This class provides SMS, USSD and modem file system support for u-blox modules on the C027 and C030 boards (excepting the C030 N2xx flavour) from mbed 5.5 onwards.

Dependents:   example-ublox-at-cellular-interface-ext example-ublox-cellular-driver-gen HelloMQTT ublox_new_driver_test ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers UbloxCellularDriverGen.cpp Source File

UbloxCellularDriverGen.cpp

00001 /* Copyright (c) 2017 ublox Limited
00002  *
00003  * Licensed under the Apache License, Version 2.0 (the "License");
00004  * you may not use this file except in compliance with the License.
00005  * You may obtain a copy of the License at
00006  *
00007  *     http://www.apache.org/licenses/LICENSE-2.0
00008  *
00009  * Unless required by applicable law or agreed to in writing, software
00010  * distributed under the License is distributed on an "AS IS" BASIS,
00011  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00012  * See the License for the specific language governing permissions and
00013  * limitations under the License.
00014  */
00015 
00016 #include "UbloxCellularDriverGen.h"
00017 #include "string.h"
00018 #if defined(FEATURE_COMMON_PAL)
00019 #include "mbed_trace.h"
00020 #define TRACE_GROUP "UCID"
00021 #else
00022 #define tr_debug(format, ...) debug_if(_debug_trace_on, format "\n", ## __VA_ARGS__)
00023 #define tr_info(format, ...)  debug_if(_debug_trace_on, format "\n", ## __VA_ARGS__)
00024 #define tr_warn(format, ...)  debug_if(_debug_trace_on, format "\n", ## __VA_ARGS__)
00025 #define tr_error(format, ...) debug_if(_debug_trace_on, format "\n", ## __VA_ARGS__)
00026 #endif
00027 
00028 /**********************************************************************
00029  * PROTECTED METHODS: Short Message Service
00030  **********************************************************************/
00031 
00032 // URC for Short Message listing.
00033 void UbloxCellularDriverGen::CMGL_URC()
00034 {
00035     char buf[64];
00036     int index;
00037 
00038     // Note: not calling _at->recv() from here as we're
00039     // already in an _at->recv()
00040     // +CMGL: <ix>,...
00041     *buf = 0;
00042     if (read_at_to_char(buf, sizeof(buf), '\n') > 0) {
00043         // Now also read out the text message, so that we don't
00044         // accidentally trigger URCs or the like on any of
00045         // its contents
00046         *_smsBuf = 0;
00047         read_at_to_char(_smsBuf, sizeof(_smsBuf), '\n');
00048         // Note: don't put any debug in here, this URC is being
00049         // called multiple times and debug may cause it to
00050         // miss characters
00051         if (sscanf(buf, ": %d,", &index) == 1) {
00052             _smsCount++;
00053             if ((_userSmsIndex != NULL) && (_userSmsNum > 0)) {
00054                 *_userSmsIndex = index;
00055                 _userSmsIndex++;
00056                 _userSmsNum--;
00057             }
00058         }
00059     }
00060 }
00061 
00062 // URC for new SMS messages.
00063 void UbloxCellularDriverGen::CMTI_URC()
00064 {
00065     char buf[32];
00066 
00067     // Note: not calling _at->recv() from here as we're
00068     // already in an _at->recv()
00069     *buf = 0;
00070     if (read_at_to_char(buf, sizeof (buf), '\n') > 0) {
00071         // No need to parse, any content is good
00072         tr_info("New SMS received");
00073     }
00074 }
00075 
00076 /**********************************************************************
00077  * PROTECTED METHODS: Unstructured Supplementary Service Data
00078  **********************************************************************/
00079 
00080 // URC for call waiting.
00081 void UbloxCellularDriverGen::CCWA_URC()
00082 {
00083     char buf[32];
00084     int numChars;
00085     int a;
00086     int b = 0;
00087 
00088     // Note: not calling _at->recv() from here as we're
00089     // already in an _at->recv()
00090     // +CCWA: <status>[, <class>]
00091     numChars = read_at_to_char(buf, sizeof (buf), '\n');
00092     if (numChars > 0) {
00093         if (sscanf(buf, ": %d,%d", &a, &b) > 0) {
00094             if (_ssUrcBuf == NULL) {
00095                 _ssUrcBuf = (char *) malloc(numChars + 5 + 1);
00096                 if (_ssUrcBuf != NULL) {
00097                     memcpy (_ssUrcBuf, "+CCWA", 5);
00098                     memcpy (_ssUrcBuf + 5, buf, numChars);
00099                     *(_ssUrcBuf + numChars + 5) = 0;
00100                     if (a > 0) {
00101                         debug_if(_debug_trace_on, "Calling Waiting is active");
00102                     } else {
00103                         debug_if(_debug_trace_on, "Calling Waiting is not active");
00104                     }
00105                     if (b > 0) {
00106                         if (b & 0x01) {
00107                             debug_if(_debug_trace_on, " for voice\n");
00108                         }
00109                         if (b & 0x02) {
00110                             debug_if(_debug_trace_on, " for data\n");
00111                         }
00112                         if (b & 0x04) {
00113                             debug_if(_debug_trace_on, " for fax\n");
00114                         }
00115                         if (b & 0x08) {
00116                             debug_if(_debug_trace_on, " for SMS\n");
00117                         }
00118                         if (b & 0x10) {
00119                             debug_if(_debug_trace_on, " for data circuit sync\n");
00120                         }
00121                         if (b & 0x20) {
00122                             debug_if(_debug_trace_on, " for data circuit async\n");
00123                         }
00124                         if (b & 0x40) {
00125                             debug_if(_debug_trace_on, " for dedicated packet access\n");
00126                         }
00127                         if (b & 0x80) {
00128                             debug_if(_debug_trace_on, " for dedicated PAD access\n");
00129                         }
00130                     }
00131                 }
00132             }
00133         }
00134     }
00135 }
00136 
00137 // URC for call forwarding.
00138 void UbloxCellularDriverGen::CCFC_URC()
00139 {
00140     char buf[32];
00141     int numChars;
00142     char num[32];
00143     int a, b;
00144     int numValues;
00145 
00146     // Note: not calling _at->recv() from here as we're
00147     // already in an _at->recv()
00148     // +CCFC: <status>[, <class>]
00149     numChars = read_at_to_char(buf, sizeof (buf), '\n');
00150     if (numChars > 0) {
00151         memset (num, 0, sizeof (num));
00152         numValues = sscanf(buf, ": %d,%d,\"%32[^\"][\"]", &a, &b, num);
00153         if (numValues > 0) {
00154             if (_ssUrcBuf == NULL) {
00155                 _ssUrcBuf = (char *) malloc(numChars + 5 + 1);
00156                 if (_ssUrcBuf != NULL) {
00157                     memcpy (_ssUrcBuf, "+CCFC", 5);
00158                     memcpy (_ssUrcBuf + 5, buf, numChars);
00159                     *(_ssUrcBuf + numChars + 5) = 0;
00160                     if (a > 0) {
00161                         debug_if(_debug_trace_on, "Calling Forwarding is active ");
00162                     } else {
00163                         debug_if(_debug_trace_on, "Calling Forwarding is not active ");
00164                     }
00165                     if (numValues > 1) {
00166                         if (b > 0) {
00167                             if (b & 0x01) {
00168                                 debug_if(_debug_trace_on, " for voice");
00169                             }
00170                             if (b & 0x02) {
00171                                 debug_if(_debug_trace_on, " for data");
00172                             }
00173                             if (b & 0x04) {
00174                                 debug_if(_debug_trace_on, " for fax");
00175                             }
00176                             if (b & 0x08) {
00177                                 debug_if(_debug_trace_on, " for SMS");
00178                             }
00179                             if (b & 0x10) {
00180                                 debug_if(_debug_trace_on, " for data circuit sync");
00181                             }
00182                             if (b & 0x20) {
00183                                 debug_if(_debug_trace_on, " for data circuit async");
00184                             }
00185                             if (b & 0x40) {
00186                                 debug_if(_debug_trace_on, " for dedicated packet access");
00187                             }
00188                             if (b & 0x80) {
00189                                 debug_if(_debug_trace_on, " for dedicated PAD access");
00190                             }
00191                         }
00192                     }
00193                     if (numValues > 2) {
00194                         debug_if(_debug_trace_on, " for %s\n", num);
00195                     } else {
00196                         debug_if(_debug_trace_on, "\n");
00197                     }
00198                 }
00199             }
00200         }
00201     }
00202 }
00203 
00204 
00205 // URC for calling line ID restriction.
00206 void UbloxCellularDriverGen::CLIR_URC()
00207 {
00208     char buf[32];
00209     int numChars;
00210     int a, b;
00211     int numValues;
00212 
00213     // Note: not calling _at->recv() from here as we're
00214     // already in an _at->recv()
00215     // +CLIR: <n>[, <m>]
00216     numChars = read_at_to_char(buf, sizeof (buf), '\n');
00217     if (numChars > 0) {
00218         numValues = sscanf(buf, ": %d,%d", &a, &b);
00219         if (numValues > 0) {
00220             if (_ssUrcBuf == NULL) {
00221                 _ssUrcBuf = (char *) malloc(numChars + 5 + 1);
00222                 if (_ssUrcBuf != NULL) {
00223                     memcpy (_ssUrcBuf, "+CLIR", 5);
00224                     memcpy (_ssUrcBuf + 5, buf, numChars);
00225                     *(_ssUrcBuf + numChars + 5) = 0;
00226                     switch (a) {
00227                         case 0:
00228                             debug_if(_debug_trace_on, "Calling Line ID restriction is as subscribed\n");
00229                             break;
00230                         case 1:
00231                             debug_if(_debug_trace_on, "Calling Line ID invocation ");
00232                             break;
00233                         case 2:
00234                             debug_if(_debug_trace_on, "Calling Line ID suppression ");
00235                             break;
00236                     }
00237                     if (numValues > 2) {
00238                         switch (b) {
00239                             case 0:
00240                                 debug_if(_debug_trace_on, " is not provisioned\n");
00241                                 break;
00242                             case 1:
00243                                 debug_if(_debug_trace_on, " is provisioned permanently\n");
00244                                 break;
00245                             case 2:
00246                                 debug_if(_debug_trace_on, " is unknown\n");
00247                                 break;
00248                             case 3:
00249                                 debug_if(_debug_trace_on, " is in temporary mode, presentation restricted\n");
00250                                 break;
00251                             case 4:
00252                                 debug_if(_debug_trace_on, " is in temporary mode, presentation allowed\n");
00253                                 break;
00254                         }
00255                     }
00256                 }
00257             }
00258         }
00259     }
00260 }
00261 
00262 // URC for calling line ID presentation.
00263 void UbloxCellularDriverGen::CLIP_URC()
00264 {
00265     char buf[32];
00266     int numChars;
00267     int a, b;
00268     int numValues;
00269 
00270     // Note: not calling _at->recv() from here as we're
00271     // already in an _at->recv()
00272     // +CLIP: <n>[, <m>]
00273     numChars = read_at_to_char(buf, sizeof (buf), '\n');
00274     if (numChars > 0) {
00275         numValues = sscanf(buf, ": %d,%d", &a, &b);
00276         if (numValues > 0) {
00277             if (_ssUrcBuf == NULL) {
00278                 _ssUrcBuf = (char *) malloc(numChars + 5 + 1);
00279                 if (_ssUrcBuf != NULL) {
00280                     memcpy (_ssUrcBuf, "+CLIP", 5);
00281                     memcpy (_ssUrcBuf + 5, buf, numChars);
00282                     *(_ssUrcBuf + numChars + 5) = 0;
00283                     switch (a) {
00284                         case 0:
00285                             debug_if(_debug_trace_on, "Calling Line ID disable ");
00286                             break;
00287                         case 1:
00288                             debug_if(_debug_trace_on, "Calling Line ID enable ");
00289                             break;
00290                     }
00291                     if (numValues > 1) {
00292                         switch (b) {
00293                             case 0:
00294                                 debug_if(_debug_trace_on, " is not provisioned\n");
00295                                 break;
00296                             case 1:
00297                                 debug_if(_debug_trace_on, " is provisioned\n");
00298                                 break;
00299                             case 2:
00300                                 debug_if(_debug_trace_on, " is unknown\n");
00301                                 break;
00302                         }
00303                     }
00304                 }
00305             }
00306         }
00307     }
00308 }
00309 
00310 // URC for connected line ID presentation.
00311 void UbloxCellularDriverGen::COLP_URC()
00312 {
00313     char buf[32];
00314     int numChars;
00315     int a, b;
00316     int numValues;
00317 
00318     // Note: not calling _at->recv() from here as we're
00319     // already in an _at->recv()
00320     // +COLP: <n>[, <m>]
00321     numChars = read_at_to_char(buf, sizeof (buf), '\n');
00322     if (numChars > 0) {
00323         numValues = sscanf(buf, ": %d,%d", &a, &b);
00324         if (numValues > 0) {
00325             if (_ssUrcBuf == NULL) {
00326                 _ssUrcBuf = (char *) malloc(numChars + 5 + 1);
00327                 if (_ssUrcBuf != NULL) {
00328                     memcpy (_ssUrcBuf, "+COLP", 5);
00329                     memcpy (_ssUrcBuf + 5, buf, numChars);
00330                     *(_ssUrcBuf + numChars + 5) = 0;
00331                     switch (a) {
00332                         case 0:
00333                             debug_if(_debug_trace_on, "Connected Line ID disable ");
00334                             break;
00335                         case 1:
00336                             debug_if(_debug_trace_on, "Connected Line ID enable ");
00337                             break;
00338                     }
00339                     if (numValues > 1) {
00340                         switch (b) {
00341                             case 0:
00342                                 debug_if(_debug_trace_on, " is not provisioned\n");
00343                                 break;
00344                             case 1:
00345                                 debug_if(_debug_trace_on, " is provisioned\n");
00346                                 break;
00347                             case 2:
00348                                 debug_if(_debug_trace_on, " is unknown\n");
00349                                 break;
00350                         }
00351                     }
00352                 }
00353             }
00354         }
00355     }
00356 }
00357 
00358 // URC for connected line ID restriction.
00359 void UbloxCellularDriverGen::COLR_URC()
00360 {
00361     char buf[32];
00362     int numChars;
00363     int a;
00364 
00365     // Note: not calling _at->recv() from here as we're
00366     // already in an _at->recv()
00367     // +COLR: <status>
00368     numChars = read_at_to_char(buf, sizeof (buf), '\n');
00369     if (numChars > 0) {
00370         if (sscanf(buf, ": %d", &a) > 0) {
00371             if (_ssUrcBuf == NULL) {
00372                 _ssUrcBuf = (char *) malloc(numChars + 5 + 1);
00373                 if (_ssUrcBuf != NULL) {
00374                     memcpy (_ssUrcBuf, "+COLR", 5);
00375                     memcpy (_ssUrcBuf + 5, buf, numChars);
00376                     *(_ssUrcBuf + numChars + 5) = 0;
00377                     switch (a) {
00378                         case 0:
00379                             debug_if(_debug_trace_on, "Connected Line ID restriction is not provisioned\n");
00380                             break;
00381                         case 1:
00382                             debug_if(_debug_trace_on, "Connected Line ID restriction is provisioned\n");
00383                             break;
00384                         case 2:
00385                             debug_if(_debug_trace_on, "Connected Line ID restriction is unknown\n");
00386                             break;
00387                     }
00388                 }
00389             }
00390         }
00391     }
00392 }
00393 
00394 /**********************************************************************
00395  * PUBLIC METHODS: Generic
00396  **********************************************************************/
00397 
00398 // Constructor.
00399 UbloxCellularDriverGen::UbloxCellularDriverGen(PinName tx, PinName rx,
00400                                                int baud, bool debug_on)
00401 {
00402     _userSmsIndex = NULL;
00403     _userSmsNum = 0;
00404     _smsCount = 0;
00405     _ssUrcBuf = NULL;
00406 
00407     // Initialise the base class, which starts the AT parser
00408     baseClassInit(tx, rx, baud, debug_on);
00409 
00410     // URCs related to SMS
00411     _at->oob("+CMGL", callback(this, &UbloxCellularDriverGen::CMGL_URC));
00412     // Include the colon with this one as otherwise it could be found
00413     // by +CMT, should it ever occur
00414     _at->oob("+CMTI:", callback(this, &UbloxCellularDriverGen::CMTI_URC));
00415 
00416     // URCs related to supplementary services
00417     _at->oob("+CCWA", callback(this, &UbloxCellularDriverGen::CCWA_URC));
00418     _at->oob("+CCFC", callback(this, &UbloxCellularDriverGen::CCFC_URC));
00419     _at->oob("+CLIR", callback(this, &UbloxCellularDriverGen::CLIR_URC));
00420     _at->oob("+CLIP", callback(this, &UbloxCellularDriverGen::CLIP_URC));
00421     _at->oob("+COLP", callback(this, &UbloxCellularDriverGen::COLP_URC));
00422     _at->oob("+COLR", callback(this, &UbloxCellularDriverGen::COLR_URC));
00423 }
00424 
00425 // Destructor.
00426 UbloxCellularDriverGen::~UbloxCellularDriverGen()
00427 {
00428 }
00429 
00430 /**********************************************************************
00431  * PUBLIC METHODS: Short Message Service
00432  **********************************************************************/
00433 
00434 // Count the number of messages on the module.
00435 int UbloxCellularDriverGen::smsList(const char* stat, int* index, int num)
00436 {
00437     int numMessages = -1;
00438     LOCK();
00439 
00440     _userSmsIndex = index;
00441     _userSmsNum = num;
00442     _smsCount = 0;
00443     // There is a callback to capture the result
00444     // +CMGL: <ix>,...
00445     _at->debug_on(false); // No time for AT interface debug
00446                           // as the list comes out in one long
00447                           // stream and we can lose characters if we
00448                           // pause to do printfs
00449     if (_at->send("AT+CMGL=\"%s\"", stat) && _at->recv("OK\n")) {
00450         numMessages = _smsCount;
00451     }
00452     _at->debug_on(_debug_trace_on);
00453 
00454     // Set this back to null so that the URC won't trample
00455     _userSmsIndex = NULL;
00456 
00457     UNLOCK();
00458     return numMessages;
00459 }
00460 
00461 // Send an SMS message.
00462 bool UbloxCellularDriverGen::smsSend(const char* num, const char* buf)
00463 {
00464     bool success = false;
00465     char typeOfAddress = TYPE_OF_ADDRESS_NATIONAL;
00466     LOCK();
00467 
00468     if ((strlen (num) > 0) && (*(num) == '+')) {
00469         typeOfAddress = TYPE_OF_ADDRESS_INTERNATIONAL;
00470     }
00471     if (_at->send("AT+CMGS=\"%s\",%d", num, typeOfAddress) && _at->recv(">")) {
00472         if ((_at->write(buf, (int) strlen(buf)) >= (int) strlen(buf)) &&
00473             (_at->putc(0x1A) == 0) &&  // CTRL-Z
00474             _at->recv("OK")) {
00475             success = true;
00476         }
00477     }
00478 
00479     UNLOCK();
00480     return success;
00481 }
00482 
00483 bool UbloxCellularDriverGen::smsDelete(int index)
00484 {
00485     bool success;
00486     LOCK();
00487 
00488     success = _at->send("AT+CMGD=%d", index) && _at->recv("OK");
00489 
00490     UNLOCK();
00491     return success;
00492 }
00493 
00494 bool UbloxCellularDriverGen::smsRead(int index, char* num, char* buf, int len)
00495 {
00496     bool success = false;
00497     char * endOfString;
00498     int smsReadLength = 0;
00499     LOCK();
00500 
00501     if (len > 0) {
00502         //+CMGR: "REC READ", "+393488535999",,"07/04/05,18:02:28+08",145,4,0,0,"+393492000466",145,93
00503         // The text of the message.
00504         // OK
00505         memset (_smsBuf, 0, sizeof (SMS_BUFFER_SIZE)); // Ensure terminator
00506         if (_at->send("AT+CMGR=%d", index) &&
00507             _at->recv("+CMGR: \"%*[^\"]\",\"%15[^\"]\"%*[^\n]\n", num) &&
00508             _at->recv("%" stringify(SMS_BUFFER_SIZE) "[^\n]\n", _smsBuf) &&
00509             _at->recv("OK")) {
00510             endOfString = strchr(_smsBuf, 0);
00511             if (endOfString != NULL) {
00512                 smsReadLength = endOfString - _smsBuf;
00513                 if (smsReadLength + 1 > len) { // +1 for terminator
00514                     smsReadLength = len - 1;
00515                 }
00516                 memcpy(buf, _smsBuf, smsReadLength);
00517                 *(buf + smsReadLength) = 0; // Add terminator
00518                 success = true;
00519             }
00520         }
00521     }
00522 
00523     UNLOCK();
00524     return success;
00525 }
00526 
00527 /**********************************************************************
00528  * PUBLIC  METHODS: Unstructured Supplementary Service Data
00529  **********************************************************************/
00530 
00531 // Perform a USSD command.
00532 bool UbloxCellularDriverGen::ussdCommand(const char* cmd, char* buf, int len)
00533 {
00534     bool success = false;
00535     char * tmpBuf;
00536     int atTimeout;
00537     int x;
00538     Timer timer;
00539     LOCK();
00540     atTimeout = _at_timeout; // Has to be inside LOCK()s
00541 
00542     if (len > 0) {
00543         *buf = 0;
00544         if (len > USSD_STRING_LENGTH + 1) {
00545             len = USSD_STRING_LENGTH + 1;
00546         }
00547 
00548         tmpBuf = (char *) malloc(USSD_STRING_LENGTH + 1);
00549 
00550         if (tmpBuf != NULL) {
00551             memset (tmpBuf, 0, USSD_STRING_LENGTH + 1);
00552             // +CUSD: \"%*d, \"%128[^\"]\",%*d"
00553             if (_at->send("AT+CUSD=1,\"%s\"", cmd)) {
00554                 // Wait for either +CUSD to come back or
00555                 // one of the other SS related URCs to trigger
00556                 if (_ssUrcBuf != NULL) {
00557                     free(_ssUrcBuf);
00558                     _ssUrcBuf = NULL;
00559                 }
00560                 timer.start();
00561                 _at->set_timeout(1000);
00562                 while (!success && (timer.read_ms() < 30000)) {
00563                     if (_at->recv("+CUSD: %*d,\"")) {
00564                         // Note: don't wait for "OK" here as the +CUSD response may come
00565                         // before or after the OK
00566                         // Also, the return string may include newlines so can't just use
00567                         // recv() to capture it as recv() will stop capturing at a newline.
00568                         if (read_at_to_char(tmpBuf, USSD_STRING_LENGTH, '\"') > 0) {
00569                             success = true;
00570                             memcpy (buf, tmpBuf, len);
00571                             *(buf + len - 1) = 0;
00572                         }
00573                     } else {
00574                         // Some of the return values do not appear as +CUSD but
00575                         // instead as the relevant URC for call waiting, call forwarding,
00576                         // etc.  Test those here.
00577                         if (_ssUrcBuf != NULL) {
00578                             success = true;
00579                             x = strlen (_ssUrcBuf);
00580                             if (x > len - 1 ) {
00581                                 x = len - 1;
00582                             }
00583                             memcpy (buf, _ssUrcBuf, x);
00584                             *(buf + x) = 0;
00585                             free (_ssUrcBuf);
00586                             _ssUrcBuf = NULL;
00587                         }
00588                     }
00589                 }
00590                 at_set_timeout(atTimeout);
00591                 timer.stop();
00592             }
00593         }
00594     }
00595 
00596     UNLOCK();
00597     return success;
00598 }
00599 
00600 /**********************************************************************
00601  * PUBLIC: Module File System
00602  **********************************************************************/
00603 
00604 // Delete a file from the module's file system.
00605 bool UbloxCellularDriverGen::delFile(const char* filename)
00606 {
00607     bool success;
00608     LOCK();
00609 
00610     success = _at->send("AT+UDELFILE=\"%s\"", filename) && _at->recv("OK");
00611 
00612     UNLOCK();
00613     return success;
00614 }
00615 
00616 // Write a buffer of data to a file in the module's file system.
00617 int UbloxCellularDriverGen::writeFile(const char* filename, const char* buf, int len)
00618 {
00619     int bytesWritten = -1;
00620     LOCK();
00621 
00622     if (_at->send("AT+UDWNFILE=\"%s\",%d", filename, len) && _at->recv(">")) {
00623         if ((_at->write(buf, len) >= len) && _at->recv("OK")) {
00624             bytesWritten = len;
00625         }
00626     }
00627 
00628     UNLOCK();
00629     return bytesWritten;
00630 }
00631 
00632 // Read a file from the module's file system
00633 // Note: this is implemented with block reads since UARTSerial
00634 // does not currently allow flow control and there is a danger
00635 // of character loss with large whole-file reads
00636 int UbloxCellularDriverGen::readFile(const char* filename, char* buf, int len)
00637 {
00638     int countBytes = -1;  // Counter for file reading (default value)
00639     int bytesToRead = fileSize(filename);  // Retrieve the size of the file
00640     int offset = 0;
00641     int blockSize = FILE_BUFFER_SIZE;
00642     char respFilename[48 + 1];
00643     int sz, sz_read;
00644     bool success = true;
00645     int ch = 0;
00646     int timeLimit;
00647     Timer timer;
00648 
00649     debug_if(_debug_trace_on, "readFile: filename is %s; size is %d\n", filename, bytesToRead);
00650 
00651     memset(respFilename, 0, sizeof (respFilename));  // Ensure terminator
00652     if (bytesToRead > 0)
00653     {
00654         if (bytesToRead > len) {
00655             bytesToRead = len;
00656         }
00657 
00658         while (success && (bytesToRead > 0)) {
00659 
00660             if (bytesToRead < blockSize) {
00661                 blockSize = bytesToRead;
00662             }
00663             LOCK();
00664 
00665             if (blockSize > 0) {
00666                 if (_at->send("AT+URDBLOCK=\"%s\",%d,%d\r\n", filename, offset, blockSize) &&
00667                     _at->recv("+URDBLOCK:%48[^,],%d,\"", respFilename, &sz)) {
00668                     // Note: not checking respFilename as some modules (e.g. Sara-G350 00S-00)
00669                     // doesn't always include it.
00670                     // Would use _at->read() here, but if it runs ahead of the
00671                     // serial stream it returns -1 instead of the number of characters
00672                     // read so far, which is not very helpful so instead use _at->getc() and
00673                     // a time limit. The time limit is four times the amount of time it
00674                     // should take to read the block at the working baud rate with a minimum
00675                     // of 100 ms (for short files)
00676                     timer.reset();
00677                     timer.start();
00678 
00679                     // Add startup delay
00680                     timeLimit = 200+ FILE_BUFFER_SIZE * 4 / ((MBED_CONF_UBLOX_CELL_BAUD_RATE / 8) / 1000);
00681 
00682                     sz_read = 0;
00683 
00684                     while ((sz_read < blockSize) && (timer.read_ms() < timeLimit)) {
00685                         ch = _at->getc();
00686                         if (ch >= 0) {
00687                             *buf = ch;
00688                             buf++;
00689                             sz_read++;
00690                         }
00691                     }
00692                     timer.stop();
00693 
00694                     if (sz_read == blockSize) {
00695                         bytesToRead -= sz_read;
00696                         offset += sz_read;
00697                         _at->recv("OK");
00698                     } else {
00699                     debug_if(_debug_trace_on, "blockSize %d but only received %d bytes, configured retry\n", blockSize, sz_read);
00700                         //success = false;
00701                     }
00702                } else {
00703                    success = false;
00704                }
00705             }
00706 
00707             UNLOCK();
00708         }
00709 
00710         if (success) {
00711             countBytes = offset;
00712         }
00713     }
00714 
00715     return countBytes;
00716 }
00717 
00718 // Return the size of a file.
00719 int UbloxCellularDriverGen::fileSize(const char* filename)
00720 {
00721     int returnValue = -1;
00722     int fileSize;
00723     LOCK();
00724 
00725     if (_at->send("AT+ULSTFILE=2,\"%s\"", filename) &&
00726         _at->recv("+ULSTFILE: %d\n", &fileSize) &&
00727         _at->recv("OK")) {
00728         returnValue = fileSize;
00729     }
00730 
00731     UNLOCK();
00732     return returnValue;
00733 }
00734 
00735 // End of file
00736