ublox-cellular-base

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers UbloxCellularBase.cpp Source File

UbloxCellularBase.cpp

00001 /* Copyright (c) 2019 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 "UARTSerial.h"
00017 #include "APN_db.h"
00018 #include "UbloxCellularBase.h"
00019 #include "onboard_modem_api.h"
00020 #ifdef FEATURE_COMMON_PAL
00021 #include "mbed_trace.h"
00022 #define TRACE_GROUP "UCB"
00023 #else
00024 #define tr_debug(format, ...) debug_if(_debug_trace_on, format "\n", ## __VA_ARGS__)
00025 #define tr_info(format, ...)  debug_if(_debug_trace_on, format "\n", ## __VA_ARGS__)
00026 #define tr_warn(format, ...)  debug_if(_debug_trace_on, format "\n", ## __VA_ARGS__)
00027 #define tr_error(format, ...) debug_if(_debug_trace_on, format "\n", ## __VA_ARGS__)
00028 #endif
00029 
00030 /* Array to convert the 3G qual number into a median EC_NO_LEV number.
00031  */
00032                             /* 0   1   2   3   4   5   6  7 */
00033                             /* 44, 41, 35, 29, 23, 17, 11, 7*/
00034 const int qualConvert3G[] = {-2, -4, -7, -10, -13, -16, -19, -21};
00035 
00036 /* Array to convert the 3G "rssi" number into a dBm RSCP value rounded up to the
00037  * nearest whole number.
00038  */
00039 const int rscpConvert3G[] = {-108, -105, -103, -100,  -98,  -96,  -94,  -93,   /* 0 - 7 */
00040                               -91,  -89,  -88,  -85,  -83,  -80,  -78,  -76,   /* 8 - 15 */
00041                               -74,  -73,  -70,  -68,  -66,  -64,  -63,  -60,   /* 16 - 23 */
00042                               -58,  -56,  -54,  -53,  -51,  -49,  -48,  -46};  /* 24 - 31 */
00043 
00044 /* Array to convert the LTE rssi number into a dBm value rounded up to the
00045  * nearest whole number.
00046  */
00047 const int rssiConvertLte[] = {-118, -115, -113, -110, -108, -105, -103, -100,   /* 0 - 7 */
00048                                -98,  -95,  -93,  -90,  -88,  -85,  -83,  -80,   /* 8 - 15 */
00049                                -78,  -76,  -74,  -73,  -71,  -69,  -68,  -65,   /* 16 - 23 */
00050                                -63,  -61,  -60,  -59,  -58,  -55,  -53,  -48};  /* 24 - 31 */
00051 
00052 /**********************************************************************
00053  * PRIVATE METHODS
00054  **********************************************************************/
00055 
00056 void UbloxCellularBase::set_nwk_reg_status_csd(int status)
00057 {
00058     switch (status) {
00059         case CSD_NOT_REGISTERED_NOT_SEARCHING:
00060         case CSD_NOT_REGISTERED_SEARCHING:
00061             tr_info("Not (yet) registered for circuit switched service");
00062             break;
00063         case CSD_REGISTERED:
00064         case CSD_REGISTERED_ROAMING:
00065             tr_info("Registered for circuit switched service");
00066             break;
00067         case CSD_REGISTRATION_DENIED:
00068             tr_info("Circuit switched service denied");
00069             break;
00070         case CSD_UNKNOWN_COVERAGE:
00071             tr_info("Out of circuit switched service coverage");
00072             break;
00073         case CSD_SMS_ONLY:
00074             tr_info("SMS service only");
00075             break;
00076         case CSD_SMS_ONLY_ROAMING:
00077             tr_info("SMS service only");
00078             break;
00079         case CSD_CSFB_NOT_PREFERRED:
00080             tr_info("Registered for circuit switched service with CSFB not preferred");
00081             break;
00082         default:
00083             tr_info("Unknown circuit switched service registration status. %d", status);
00084             break;
00085     }
00086 
00087     _dev_info.reg_status_csd = static_cast<NetworkRegistrationStatusCsd>(status);
00088 }
00089 
00090 void UbloxCellularBase::set_nwk_reg_status_psd(int status)
00091 {
00092     switch (status) {
00093         case PSD_NOT_REGISTERED_NOT_SEARCHING:
00094         case PSD_NOT_REGISTERED_SEARCHING:
00095             tr_info("Not (yet) registered for packet switched service");
00096             break;
00097         case PSD_REGISTERED:
00098         case PSD_REGISTERED_ROAMING:
00099             tr_info("Registered for packet switched service");
00100             break;
00101         case PSD_REGISTRATION_DENIED:
00102             tr_info("Packet switched service denied");
00103             break;
00104         case PSD_UNKNOWN_COVERAGE:
00105             tr_info("Out of packet switched service coverage");
00106             break;
00107         case PSD_EMERGENCY_SERVICES_ONLY:
00108             tr_info("Limited access for packet switched service. Emergency use only.");
00109             break;
00110         default:
00111             tr_info("Unknown packet switched service registration status. %d", status);
00112             break;
00113     }
00114 
00115     _dev_info.reg_status_psd = static_cast<NetworkRegistrationStatusPsd>(status);
00116 }
00117 
00118 void UbloxCellularBase::set_nwk_reg_status_eps(int status)
00119 {
00120     switch (status) {
00121         case EPS_NOT_REGISTERED_NOT_SEARCHING:
00122         case EPS_NOT_REGISTERED_SEARCHING:
00123             tr_info("Not (yet) registered for EPS service");
00124             break;
00125         case EPS_REGISTERED:
00126         case EPS_REGISTERED_ROAMING:
00127             tr_info("Registered for EPS service");
00128             break;
00129         case EPS_REGISTRATION_DENIED:
00130             tr_info("EPS service denied");
00131             break;
00132         case EPS_UNKNOWN_COVERAGE:
00133             tr_info("Out of EPS service coverage");
00134             break;
00135         case EPS_EMERGENCY_SERVICES_ONLY:
00136             tr_info("Limited access for EPS service. Emergency use only.");
00137             break;
00138         default:
00139             tr_info("Unknown EPS service registration status. %d", status);
00140             break;
00141     }
00142 
00143     _dev_info.reg_status_eps = static_cast<NetworkRegistrationStatusEps>(status);
00144 }
00145 
00146 #ifdef TARGET_UBLOX_C030_R412M
00147 void UbloxCellularBase::set_modem_psm_state(int status)
00148 {
00149     switch (status) {
00150         case ASLEEP:
00151             tr_info("Modem is going in PSM sleep");
00152             break;
00153         case AWAKE:
00154             tr_info("Modem is awake from PSM sleep");
00155             break;
00156         default:
00157             tr_info("Unknown PSM state. %d", status);
00158             break;
00159     }
00160 
00161     _dev_info.modem_psm_state = static_cast<ModemPSMState>(status);
00162 }
00163 #endif
00164 
00165 void UbloxCellularBase::set_rat(int acTStatus)
00166 {
00167     switch (acTStatus) {
00168         case GSM:
00169         case COMPACT_GSM:
00170             tr_info("Connected in GSM");
00171             break;
00172         case UTRAN:
00173             tr_info("Connected to UTRAN");
00174             break;
00175         case EDGE:
00176             tr_info("Connected to EDGE");
00177             break;
00178         case HSDPA:
00179             tr_info("Connected to HSDPA");
00180             break;
00181         case HSUPA:
00182             tr_info("Connected to HSPA");
00183             break;
00184         case HSDPA_HSUPA:
00185             tr_info("Connected to HDPA/HSPA");
00186             break;
00187         case LTE:
00188             tr_info("Connected to LTE");
00189             break;
00190         case EC_GSM_IoT:
00191             tr_info("Connected to EC_GSM_IoT");
00192             break;
00193         case E_UTRAN_NB_S1:
00194             tr_info("Connected to E_UTRAN NB1");
00195             break;
00196         default:
00197             tr_info("Unknown RAT %d", acTStatus);
00198             break;
00199     }
00200 
00201     _dev_info.rat = static_cast<RadioAccessNetworkType>(acTStatus);
00202 }
00203 
00204 bool UbloxCellularBase::get_iccid()
00205 {
00206     bool success;
00207     LOCK();
00208 
00209     MBED_ASSERT(_at != NULL);
00210 
00211     // Returns the ICCID (Integrated Circuit Card ID) of the SIM-card.
00212     // ICCID is a serial number identifying the SIM.
00213     // AT Command Manual UBX-13002752, section 4.12
00214     success = _at->send("AT+CCID") && _at->recv("+CCID: %20[^\n]\nOK\n", _dev_info.iccid);
00215     tr_info("DevInfo: ICCID=%s", _dev_info.iccid);
00216 
00217     UNLOCK();
00218     return success;
00219 }
00220 
00221 bool UbloxCellularBase::get_imsi()
00222 {
00223     bool success;
00224     LOCK();
00225 
00226     MBED_ASSERT(_at != NULL);
00227 
00228     // International mobile subscriber identification
00229     // AT Command Manual UBX-13002752, section 4.11
00230     success = _at->send("AT+CIMI") && _at->recv("%15[^\n]\nOK\n", _dev_info.imsi);
00231     tr_info("DevInfo: IMSI=%s", _dev_info.imsi);
00232 
00233     UNLOCK();
00234     return success;
00235 }
00236 
00237 bool UbloxCellularBase::get_imei()
00238 {
00239     bool success;
00240     LOCK();
00241 
00242     MBED_ASSERT(_at != NULL);
00243 
00244     // International mobile equipment identifier
00245     // AT Command Manual UBX-13002752, section 4.7
00246     success = _at->send("AT+CGSN") && _at->recv("%15[^\n]\nOK\n", _dev_info.imei);
00247     tr_info("DevInfo: IMEI=%s", _dev_info.imei);
00248 
00249     UNLOCK();
00250     return success;
00251 }
00252 
00253 bool UbloxCellularBase::get_meid()
00254 {
00255     bool success;
00256     LOCK();
00257 
00258     MBED_ASSERT(_at != NULL);
00259 
00260     // Mobile equipment identifier
00261     // AT Command Manual UBX-13002752, section 4.8
00262     success = _at->send("AT+GSN") && _at->recv("%18[^\n]\nOK\n", _dev_info.meid);
00263     tr_info("DevInfo: MEID=%s", _dev_info.meid);
00264 
00265     UNLOCK();
00266     return success;
00267 }
00268 
00269 bool UbloxCellularBase::set_sms()
00270 {
00271     bool success = false;
00272     char buf[32];
00273     LOCK();
00274 
00275     MBED_ASSERT(_at != NULL);
00276 
00277     // Set up SMS format and enable URC
00278     // AT Command Manual UBX-13002752, section 11
00279     if (_at->send("AT+CMGF=1") && _at->recv("OK")) {
00280         tr_debug("SMS in text mode");
00281         if (_at->send("AT+CNMI=2,1") && _at->recv("OK")) {
00282             tr_debug("SMS URC enabled");
00283             // Set to CS preferred since PS preferred doesn't work
00284             // on some networks
00285             if (_at->send("AT+CGSMS=1") && _at->recv("OK")) {
00286                 tr_debug("SMS set to CS preferred");
00287                 success = true;
00288                 memset (buf, 0, sizeof (buf));
00289                 if (_at->send("AT+CSCA?") &&
00290                     _at->recv("+CSCA: \"%31[^\"]\"", buf) &&
00291                     _at->recv("OK")) {
00292                     tr_info("SMS Service Centre address is \"%s\"", buf);
00293                 }
00294             }
00295         }
00296     }
00297 
00298     UNLOCK();
00299     return success;
00300 }
00301 
00302 void UbloxCellularBase::parser_abort_cb()
00303 {
00304     _at->abort();
00305 }
00306 
00307 // Callback for CME ERROR and CMS ERROR.
00308 void UbloxCellularBase::CMX_ERROR_URC()
00309 {
00310     char buf[48];
00311 
00312     if (read_at_to_char(buf, sizeof (buf), '\n') > 0) {
00313         tr_debug("AT error %s", buf);
00314     }
00315     parser_abort_cb();
00316 }
00317 
00318 // Callback for circuit switched registration URC.
00319 void UbloxCellularBase::CREG_URC()
00320 {
00321     char buf[10];
00322     int status;
00323     int acTStatus;
00324 
00325     // If this is the URC it will be a single
00326     // digit followed by \n.  If it is the
00327     // answer to a CREG query, it will be
00328     // a ": %d,%d\n" where the second digit
00329     // indicates the status
00330     // Note: not calling _at->recv() from here as we're
00331     // already in an _at->recv()
00332     if (read_at_to_char(buf, sizeof (buf), '\n') > 0) {
00333         if (sscanf(buf, ": %*d,%d,%*d,%*d,%d,", &status, &acTStatus) == 2) {
00334             set_nwk_reg_status_csd(status);
00335             set_rat(acTStatus);
00336         } else if (sscanf(buf, ": %*d,%d", &status) == 1) {
00337             set_nwk_reg_status_csd(status);
00338         } else if (sscanf(buf, ": %d", &status) == 1) {
00339             set_nwk_reg_status_csd(status);
00340         }
00341     }
00342 }
00343 
00344 // Callback for packet switched registration URC.
00345 void UbloxCellularBase::CGREG_URC()
00346 {
00347     char buf[10];
00348     int status;
00349     int acTStatus;
00350 
00351     // If this is the URC it will be a single
00352     // digit followed by \n.  If it is the
00353     // answer to a CGREG query, it will be
00354     // a ": %d,%d\n" where the second digit
00355     // indicates the status
00356     // Note: not calling _at->recv() from here as we're
00357     // already in an _at->recv()
00358     if (read_at_to_char(buf, sizeof (buf), '\n') > 0) {
00359         if (sscanf(buf, ": %*d,%d,%*d,%*d,%d,", &status, &acTStatus) == 2) {
00360             set_nwk_reg_status_csd(status);
00361             set_rat(acTStatus);
00362         } else if (sscanf(buf, ": %*d,%d", &status) == 1) {
00363             set_nwk_reg_status_psd(status);
00364         } else if (sscanf(buf, ": %d", &status) == 1) {
00365             set_nwk_reg_status_psd(status);
00366         }
00367     }
00368 }
00369 
00370 // Callback for EPS registration URC.
00371 void UbloxCellularBase::CEREG_URC()
00372 {
00373     char buf[10];
00374     int status;
00375     int acTStatus;
00376 
00377     // If this is the URC it will be a single
00378     // digit followed by \n.  If it is the
00379     // answer to a CEREG query, it will be
00380     // a ": %d,%d\n" where the second digit
00381     // indicates the status
00382     // Note: not calling _at->recv() from here as we're
00383     // already in an _at->recv()
00384     if (read_at_to_char(buf, sizeof (buf), '\n') > 0) {
00385         if (sscanf(buf, ": %*d,%d,%*d,%*d,%d,", &status, &acTStatus) == 2) {
00386             set_nwk_reg_status_csd(status);
00387             set_rat(acTStatus);
00388         } else if (sscanf(buf, ": %*d,%d", &status) == 1) {
00389             set_nwk_reg_status_eps(status);
00390         } else if (sscanf(buf, ": %d", &status) == 1) {
00391             set_nwk_reg_status_eps(status);
00392         }
00393     }
00394 }
00395 
00396 // Callback UMWI, just filtering it out.
00397 void UbloxCellularBase::UMWI_URC()
00398 {
00399     char buf[10];
00400 
00401     // Note: not calling _at->recv() from here as we're
00402     // already in an _at->recv()
00403     read_at_to_char(buf, sizeof (buf), '\n');
00404 }
00405 
00406 #ifdef TARGET_UBLOX_C030_R412M
00407 // Callback UUPSMR, set/clear flag for modem psm state.
00408 void UbloxCellularBase::UUPSMR_URC()
00409 {
00410     int status;
00411     char buf[10];
00412 
00413     if (read_at_to_char(buf, sizeof (buf), '\n') > 0) {
00414         if (sscanf(buf, ": %d", &status) == 1) {
00415             set_modem_psm_state(status);
00416             //call application registered callbacks
00417             if (status == AWAKE) { //modem coming out of sleep
00418                 if (_func_psm_coming_out) {
00419                     _func_psm_coming_out(_cb_param_psm_coming_out);
00420                 }
00421             } else if(status == ASLEEP) { //modem going into sleep
00422                 if (_func_psm_going_in) {
00423                     _func_psm_going_in(_cb_param_psm_going_in);
00424                 }
00425             }
00426         }
00427     }
00428 }
00429 #endif
00430 /**********************************************************************
00431  * PROTECTED METHODS
00432  **********************************************************************/
00433 
00434 #if MODEM_ON_BOARD
00435 void UbloxCellularBase::modem_init()
00436 {
00437     ::onboard_modem_init();
00438 }
00439 
00440 void UbloxCellularBase::modem_deinit()
00441 {
00442     ::onboard_modem_deinit();
00443 }
00444 
00445 void UbloxCellularBase::modem_power_up()
00446 {
00447     ::onboard_modem_power_up();
00448 }
00449 
00450 void UbloxCellularBase::modem_power_down()
00451 {
00452     ::onboard_modem_power_down();
00453 }
00454 #else
00455 void UbloxCellularBase::modem_init()
00456 {
00457     // Meant to be overridden
00458 }
00459 
00460 void UbloxCellularBase::modem_deinit()
00461 {
00462     // Meant to be overridden
00463 }
00464 
00465 void UbloxCellularBase::modem_power_up()
00466 {
00467     // Meant to be overridden
00468 }
00469 
00470 void UbloxCellularBase::modem_power_down()
00471 {
00472     // Mmeant to be overridden
00473 }
00474 #endif
00475 
00476 // Constructor.
00477 // Note: to allow this base class to be inherited as a virtual base class
00478 // by everyone, it takes no parameters.  See also comment above classInit()
00479 // in the header file.
00480 UbloxCellularBase::UbloxCellularBase()
00481 {
00482     _pin = NULL;
00483     _at = NULL;
00484     _at_timeout = AT_PARSER_TIMEOUT;
00485     _fh = NULL;
00486     _modem_initialised = false;
00487     _sim_pin_check_enabled = false;
00488     _debug_trace_on = false;
00489 
00490     _dev_info.dev = DEV_TYPE_NONE;
00491     _dev_info.reg_status_csd = CSD_NOT_REGISTERED_NOT_SEARCHING;
00492     _dev_info.reg_status_psd = PSD_NOT_REGISTERED_NOT_SEARCHING;
00493     _dev_info.reg_status_eps = EPS_NOT_REGISTERED_NOT_SEARCHING;
00494 #ifdef TARGET_UBLOX_C030_R412M
00495     _dev_info.modem_psm_state = AWAKE;
00496     _psm_status = false;
00497     _cb_param_psm_going_in = NULL;
00498     _func_psm_going_in = NULL;
00499     _cb_param_psm_coming_out = NULL;
00500     _func_psm_coming_out = NULL;
00501 #endif
00502 #ifdef TARGET_UBLOX_C030_R41XM
00503     _edrx_configured = false;
00504 #endif
00505 }
00506 
00507 // Destructor.
00508 UbloxCellularBase::~UbloxCellularBase()
00509 {
00510     deinit();
00511     delete _at;
00512     delete _fh;
00513 }
00514 
00515 // Initialise the portions of this class that are parameterised.
00516 void UbloxCellularBase::baseClassInit(PinName tx, PinName rx,
00517                                       int baud, bool debug_on)
00518 {
00519     // Only initialise ourselves if it's not already been done
00520     if (_at == NULL) {
00521         if (_debug_trace_on == false) {
00522             _debug_trace_on = debug_on;
00523         }
00524         _baud = baud;
00525 
00526         // Set up File Handle for buffered serial comms with cellular module
00527         // (which will be used by the AT parser)
00528         // Note: the UART is initialised to run no faster than 115200 because
00529         // the modems cannot reliably auto-baud at faster rates.  The faster
00530         // rate is adopted later with a specific AT command and the
00531         // UARTSerial rate is adjusted at that time
00532         if (baud > 115200) {
00533             baud = 115200;
00534         }
00535         _fh = new UARTSerial(tx, rx, baud);
00536 
00537         // Set up the AT parser
00538 #ifdef TARGET_UBLOX_C030_R41XM
00539         _at = new UbloxATCmdParser(_fh, OUTPUT_ENTER_KEY, AT_PARSER_BUFFER_SIZE,
00540                               _at_timeout, _debug_trace_on);
00541 #else
00542         _at = new ATCmdParser(_fh, OUTPUT_ENTER_KEY, AT_PARSER_BUFFER_SIZE,
00543                               _at_timeout, _debug_trace_on);
00544 #endif
00545 
00546         // Error cases, out of band handling
00547         _at->oob("ERROR", callback(this, &UbloxCellularBase::parser_abort_cb));
00548         _at->oob("+CME ERROR", callback(this, &UbloxCellularBase::CMX_ERROR_URC));
00549         _at->oob("+CMS ERROR", callback(this, &UbloxCellularBase::CMX_ERROR_URC));
00550 
00551         // Registration status, out of band handling
00552         _at->oob("+CREG", callback(this, &UbloxCellularBase::CREG_URC));
00553         _at->oob("+CGREG", callback(this, &UbloxCellularBase::CGREG_URC));
00554         _at->oob("+CEREG", callback(this, &UbloxCellularBase::CEREG_URC));
00555 
00556         // Capture the UMWI, just to stop it getting in the way
00557         _at->oob("+UMWI", callback(this, &UbloxCellularBase::UMWI_URC));
00558 #ifdef TARGET_UBLOX_C030_R412M
00559         // Handle PSM URC for going in and coming out of PSM
00560         _at->oob("+UUPSMR", callback(this, &UbloxCellularBase::UUPSMR_URC));
00561 #endif
00562     }
00563 }
00564 
00565 // Set the AT parser timeout.
00566 // Note: the AT interface should be locked before this is called.
00567 void UbloxCellularBase::at_set_timeout(int timeout) {
00568 
00569     MBED_ASSERT(_at != NULL);
00570 
00571     _at_timeout = timeout;
00572     _at->set_timeout(timeout);
00573 }
00574 
00575 // Read up to size bytes from the AT interface up to a "end".
00576 // Note: the AT interface should be locked before this is called.
00577 int UbloxCellularBase::read_at_to_char(char * buf, int size, char end)
00578 {
00579     int count = 0;
00580     int x = 0;
00581 
00582     if (size > 0) {
00583         for (count = 0; (count < size) && (x >= 0) && (x != end); count++) {
00584             x = _at->getc();
00585             *(buf + count) = (char) x;
00586         }
00587 
00588         count--;
00589         *(buf + count) = 0;
00590 
00591         // Convert line endings:
00592         // If end was '\n' (0x0a) and the preceding character was 0x0d, then
00593         // overwrite that with null as well.
00594         if ((count > 0) && (end == '\n') && (*(buf + count - 1) == '\x0d')) {
00595             count--;
00596             *(buf + count) = 0;
00597         }
00598     }
00599 
00600     return count;
00601 }
00602 
00603 // Power up the modem.
00604 // Enables the GPIO lines to the modem and then wriggles the power line in short pulses.
00605 bool UbloxCellularBase::power_up()
00606 {
00607     bool success = false;
00608     int at_timeout;
00609     LOCK();
00610 
00611     at_timeout = _at_timeout; // Has to be inside LOCK()s
00612 
00613     MBED_ASSERT(_at != NULL);
00614 
00615     /* Initialize GPIO lines */
00616     tr_info("Powering up modem...");
00617     modem_init();
00618     /* Give modem a little time to settle down */
00619     wait_ms(250);
00620 
00621     for (int retry_count = 0; !success && (retry_count < 20); retry_count++) {
00622         //In case of SARA-R4, modem takes a while to turn on, constantly toggling the power pin every ~2 secs causes the modem to never power up.
00623         if ( (retry_count % 5) == 0) { 
00624             modem_power_up();
00625         }
00626         wait_ms(500);
00627         // Modem tends to spit out noise during power up - don't confuse the parser
00628         _at->flush();
00629         at_set_timeout(1000);
00630         if (_at->send("AT")) {
00631             // C027 needs a delay here
00632             wait_ms(100);
00633             if (_at->recv("OK")) {
00634                 success = true;
00635             }
00636         }
00637         at_set_timeout(at_timeout);
00638     }
00639 
00640     if (success) {
00641         // Set the final baud rate
00642         if (_at->send("AT+IPR=%d", _baud) && _at->recv("OK")) {
00643             // Need to wait for things to be sorted out on the modem side
00644             wait_ms(100);
00645             ((UARTSerial *)_fh)->set_baud(_baud);
00646         }
00647         
00648         // Turn off modem echoing and turn on verbose responses
00649         success = _at->send("ATE0;+CMEE=2") && _at->recv("OK") &&
00650                   // The following commands are best sent separately
00651                   _at->send("AT&K0") && _at->recv("OK") && // Turn off RTC/CTS handshaking
00652                   _at->send("AT&C1") && _at->recv("OK") && // Set DCD circuit(109), changes in accordance with the carrier detect status
00653                   _at->send("AT&D0") && _at->recv("OK"); // Set DTR circuit, we ignore the state change of DTR
00654     }
00655 
00656     if (!success) {
00657         tr_error("Preliminary modem setup failed.");
00658     }
00659 
00660     UNLOCK();
00661     return success;
00662 }
00663 
00664 // Power down modem via AT interface.
00665 void UbloxCellularBase::power_down()
00666 {
00667     LOCK();
00668 
00669     MBED_ASSERT(_at != NULL);
00670 
00671     // power-off modem
00672     modem_power_down();
00673     modem_deinit();
00674 
00675     if (_modem_initialised && (_at != NULL)) {
00676         int at_timeout = _at_timeout; // Save previous timeout
00677         _at->set_timeout(1000);
00678         // Check modem is powered off
00679         if(_at->send("AT") && _at->recv("OK")) {
00680             _at->send("AT+CPWROFF") && _at->recv("OK");
00681         }
00682         _at->set_timeout(at_timeout);
00683     }
00684 
00685     _dev_info.reg_status_csd = CSD_NOT_REGISTERED_NOT_SEARCHING;
00686     _dev_info.reg_status_psd = PSD_NOT_REGISTERED_NOT_SEARCHING;
00687     _dev_info.reg_status_eps = EPS_NOT_REGISTERED_NOT_SEARCHING;
00688 
00689    UNLOCK();
00690 }
00691 
00692 // Get the device ID.
00693 bool UbloxCellularBase::set_device_identity(DeviceType *dev)
00694 {
00695     char buf[20];
00696     bool success;
00697     LOCK();
00698 
00699     MBED_ASSERT(_at != NULL);
00700 
00701     success = _at->send("ATI") && _at->recv("%19[^\n]\nOK\n", buf);
00702 
00703     if (success) {
00704         if (strstr(buf, "SARA-G35"))
00705             *dev = DEV_SARA_G35;
00706         else if (strstr(buf, "LISA-U200-03S"))
00707             *dev = DEV_LISA_U2_03S;
00708         else if (strstr(buf, "LISA-U2"))
00709             *dev = DEV_LISA_U2;
00710         else if (strstr(buf, "SARA-U2"))
00711             *dev = DEV_SARA_U2;
00712         else if (strstr(buf, "SARA-R4"))
00713             *dev = DEV_SARA_R4;
00714         else if (strstr(buf, "LEON-G2"))
00715             *dev = DEV_LEON_G2;
00716         else if (strstr(buf, "TOBY-L2"))
00717             *dev = DEV_TOBY_L2;
00718         else if (strstr(buf, "MPCI-L2"))
00719             *dev = DEV_MPCI_L2;
00720     }
00721 
00722     UNLOCK();
00723     return success;
00724 }
00725 
00726 // Send initialisation AT commands that are specific to the device.
00727 bool UbloxCellularBase::device_init(DeviceType dev)
00728 {
00729     bool success = false;
00730     LOCK();
00731 
00732     MBED_ASSERT(_at != NULL);
00733 
00734     if ((dev == DEV_LISA_U2) || (dev == DEV_LEON_G2) || (dev == DEV_TOBY_L2)) {
00735         success = _at->send("AT+UGPIOC=20,2") && _at->recv("OK");
00736     } else if ((dev == DEV_SARA_U2) || (dev == DEV_SARA_G35)) {
00737         success = _at->send("AT+UGPIOC=16,2") && _at->recv("OK");
00738     } else {
00739         success = true;
00740     }
00741 
00742     UNLOCK();
00743     return success;
00744 }
00745 
00746 // Get the SIM card going.
00747 bool UbloxCellularBase::initialise_sim_card()
00748 {
00749     bool success = false;
00750     int retry_count = 0;
00751     bool done = false;
00752     LOCK();
00753 
00754     MBED_ASSERT(_at != NULL);
00755 
00756     /* SIM initialisation may take a significant amount, so an error is
00757      * kind of expected. We should retry 10 times until we succeed or timeout. */
00758     for (retry_count = 0; !done && (retry_count < 10); retry_count++) {
00759         char pinstr[16];
00760 
00761         if (_at->send("AT+CPIN?") && _at->recv("+CPIN: %15[^\n]\n", pinstr) &&
00762             _at->recv("OK")) {
00763             done = true;
00764             if (strcmp(pinstr, "SIM PIN") == 0) {
00765                 _sim_pin_check_enabled = true;
00766                 if (_at->send("AT+CPIN=\"%s\"", _pin)) {
00767                     if (_at->recv("OK")) {
00768                         tr_info("PIN correct");
00769                         success = true;
00770                     } else {
00771                         tr_error("Incorrect PIN");
00772                     }
00773                 }
00774             } else if (strcmp(pinstr, "READY") == 0) {
00775                 _sim_pin_check_enabled = false;
00776                 tr_info("No PIN required");
00777                 success = true;
00778             } else {
00779                 tr_debug("Unexpected response from SIM: \"%s\"", pinstr);
00780             }
00781         }
00782 
00783         /* wait for a second before retry */
00784         wait_ms(1000);
00785     }
00786 
00787     if (done) {
00788         tr_info("SIM Ready.");
00789     } else {
00790         tr_error("SIM not ready.");
00791     }
00792 
00793     UNLOCK();
00794     return success;
00795 }
00796 
00797 /**********************************************************************
00798  * PUBLIC METHODS
00799  **********************************************************************/
00800 
00801 // Initialise the modem.
00802 bool UbloxCellularBase::init(const char *pin, bool disable_mno_params)
00803 {
00804     int x;
00805     MBED_ASSERT(_at != NULL);
00806 
00807     if (!_modem_initialised) {
00808         if (power_up()) {
00809             tr_info("Modem Ready.");
00810             if (pin != NULL) {
00811                 _pin = pin;
00812             }
00813 #ifdef TARGET_UBLOX_C027
00814             if (set_functionality_mode(FUNC_MIN)) {
00815 #else
00816             if (set_functionality_mode(FUNC_AIRPLANE)) {
00817 #endif
00818                 if (initialise_sim_card()) {
00819 #ifdef TARGET_UBLOX_C030_R412M
00820                     if (_psm_status == false) { //PSM is not yet configured by driver or application
00821                         if (disable_mno_params) {
00822                             set_power_saving_mode(0, 0);
00823                         } else {
00824                             int status = 0, periodic_time = 0, active_time = 0;
00825                             if (get_power_saving_mode(&status, &periodic_time, &active_time)) {
00826                                 if (status) { //PSM is already enabled either by a previous run or MNO profile
00827                                     tr_info("PSM is already enabled, periodic_time %d, active_time %d", periodic_time, active_time);
00828                                     _psm_status = true;
00829                                     if ( !(set_psm_urcs(1)) ) { //enable PSM URCs
00830                                         tr_error("Modem does not support PSM URCs, disabling PSM");
00831                                         set_power_saving_mode(0, 0);
00832                                     }
00833                                 }
00834                             }
00835                         }
00836                     }
00837 #endif
00838 #ifdef TARGET_UBLOX_C030_R41XM
00839                     if (_at->is_idle_mode_enabled() == false) {
00840                         set_idle_mode(false); //disable idle mode at start up
00841                     }
00842                     int mno_profile;
00843                     if (get_mno_profile(&mno_profile)) {
00844                         tr_info("Current MNO profile is: %d", mno_profile);
00845                     }
00846 #endif
00847                     if (set_device_identity(&_dev_info.dev) && // Set up device identity
00848                         device_init(_dev_info.dev)) {// Initialise this device
00849                         // Get the integrated circuit ID of the SIM
00850                         if (get_iccid()) {
00851                             // Try a few times to get the IMSI (since on some modems this can
00852                             // take a while to be retrieved, especially if a SIM PIN
00853                             // was set)
00854                             for (x = 0; (x < 3) && !get_imsi(); x++) {
00855                                 wait_ms(1000);
00856                             }
00857 
00858                             if (x < 3) { // If we got the IMSI, can get the others
00859                                 if (get_imei() && // Get international mobile equipment identifier
00860                                     get_meid() && // Probably the same as the IMEI
00861                                     set_sms()) { // And set up SMS
00862                                     // The modem is initialised.
00863                                     _modem_initialised = true;
00864                                     tr_info("Modem initialized");
00865                                 }
00866                             }
00867                         }
00868                     }
00869                 }
00870             }
00871         }
00872     }
00873 
00874     return _modem_initialised;
00875 }
00876 
00877 // Perform registration.
00878 bool UbloxCellularBase::nwk_registration()
00879 {
00880     bool atSuccess = false;
00881     bool registered = false;
00882     int status;
00883     int at_timeout;
00884     LOCK();
00885 
00886     at_timeout = _at_timeout; // Has to be inside LOCK()s
00887 
00888     MBED_ASSERT(_at != NULL);
00889 
00890     if (!is_registered_psd() && !is_registered_csd() && !is_registered_eps()) {
00891         if (set_functionality_mode(FUNC_FULL)) {
00892             tr_info("Searching Network...");
00893             // Enable the packet switched and network registration unsolicited result codes
00894             if (_at->send("AT+CREG=1") && _at->recv("OK") &&
00895                 _at->send("AT+CGREG=1") && _at->recv("OK")) {
00896                 atSuccess = true;
00897                 if (_at->send("AT+CEREG=1")) {
00898                     _at->recv("OK");
00899                     // Don't check return value as this works for LTE only
00900                 }
00901 
00902                 if (atSuccess) {
00903                     // See if we are already in automatic mode
00904                     if (_at->send("AT+COPS?") && _at->recv("+COPS: %d", &status) &&
00905                         _at->recv("OK")) {
00906                         // If not, set it
00907                         if (status != 0) {
00908                             // Don't check return code here as there's not much
00909                             // we can do if this fails.
00910                             _at->send("AT+COPS=0") && _at->recv("OK");
00911                         }
00912                     }
00913 
00914                     // Query the registration status directly as well,
00915                     // just in case
00916                     if (_at->send("AT+CREG?") && _at->recv("OK")) {
00917                         // Answer will be processed by URC
00918                     }
00919                     if (_at->send("AT+CGREG?") && _at->recv("OK")) {
00920                         // Answer will be processed by URC
00921                     }
00922                     if (_at->send("AT+CEREG?")) {
00923                         _at->recv("OK");
00924                         // Don't check return value as this works for LTE only
00925                     }
00926                 }
00927             }
00928             // Wait for registration to succeed
00929             at_set_timeout(1000);
00930             for (int waitSeconds = 0; !registered && (waitSeconds < 180); waitSeconds++) {
00931                 registered = is_registered_psd() || is_registered_csd() || is_registered_eps();
00932                 _at->recv(UNNATURAL_STRING);
00933             }
00934             at_set_timeout(at_timeout);
00935 
00936             if (registered) {
00937                 // This should return quickly but sometimes the status field is not returned
00938                 // so make the timeout short
00939                 at_set_timeout(1000);
00940                 if (_at->send("AT+COPS?") && _at->recv("+COPS: %*d,%*d,\"%*[^\"]\",%d\n", &status)) {
00941                     set_rat(status);
00942                 }
00943                 at_set_timeout(at_timeout);
00944             }
00945         }
00946     } else {
00947         registered = true;
00948     }
00949     
00950     UNLOCK();
00951     return registered;
00952 }
00953 
00954 bool UbloxCellularBase::is_registered_csd()
00955 {
00956   return (_dev_info.reg_status_csd == CSD_REGISTERED) ||
00957           (_dev_info.reg_status_csd == CSD_REGISTERED_ROAMING) ||
00958           (_dev_info.reg_status_csd == CSD_CSFB_NOT_PREFERRED);
00959 }
00960 
00961 bool UbloxCellularBase::is_registered_psd()
00962 {
00963     return (_dev_info.reg_status_psd == PSD_REGISTERED) ||
00964             (_dev_info.reg_status_psd == PSD_REGISTERED_ROAMING);
00965 }
00966 
00967 bool UbloxCellularBase::is_registered_eps()
00968 {
00969     return (_dev_info.reg_status_eps == EPS_REGISTERED) ||
00970             (_dev_info.reg_status_eps == EPS_REGISTERED_ROAMING);
00971 }
00972 
00973 // Perform deregistration.
00974 bool UbloxCellularBase::nwk_deregistration()
00975 {
00976     bool success = false;
00977     LOCK();
00978 
00979     MBED_ASSERT(_at != NULL);
00980 
00981     int at_timeout = _at_timeout;  // Has to be inside LOCK()s
00982     at_set_timeout(3*60*1000); //command has 3 minutes timeout
00983 
00984     if (_at->send("AT+COPS=2") && _at->recv("OK")) {
00985         _dev_info.reg_status_csd = CSD_NOT_REGISTERED_NOT_SEARCHING;
00986         _dev_info.reg_status_psd = PSD_NOT_REGISTERED_NOT_SEARCHING;
00987         _dev_info.reg_status_eps = EPS_NOT_REGISTERED_NOT_SEARCHING;
00988         success = true;
00989     }
00990 
00991     at_set_timeout(at_timeout);
00992     UNLOCK();
00993     return success;
00994 }
00995 
00996 // Put the modem into its lowest power state.
00997 void UbloxCellularBase::deinit()
00998 {
00999     power_down();
01000     _modem_initialised = false;
01001 }
01002 
01003 // Set the PIN.
01004 void UbloxCellularBase::set_pin(const char *pin) {
01005     _pin = pin;
01006 }
01007 
01008 // Enable or disable SIM pin checking.
01009 bool UbloxCellularBase::sim_pin_check_enable(bool enableNotDisable)
01010 {
01011     bool success = false;;
01012     LOCK();
01013 
01014     MBED_ASSERT(_at != NULL);
01015 
01016     if (_pin != NULL) {
01017         if (_sim_pin_check_enabled && !enableNotDisable) {
01018             // Disable the SIM lock
01019             if (_at->send("AT+CLCK=\"SC\",0,\"%s\"", _pin) && _at->recv("OK")) {
01020                 _sim_pin_check_enabled = false;
01021                 success = true;
01022             }
01023         } else if (!_sim_pin_check_enabled && enableNotDisable) {
01024             // Enable the SIM lock
01025             if (_at->send("AT+CLCK=\"SC\",1,\"%s\"", _pin) && _at->recv("OK")) {
01026                 _sim_pin_check_enabled = true;
01027                 success = true;
01028             }
01029         } else {
01030             success = true;
01031         }
01032     }
01033 
01034     UNLOCK();
01035     return success;
01036 }
01037 
01038 // Change the pin code for the SIM card.
01039 bool UbloxCellularBase::change_sim_pin(const char *pin)
01040 {
01041     bool success = false;;
01042     LOCK();
01043 
01044     MBED_ASSERT(_at != NULL);
01045 
01046     // Change the SIM pin
01047     if ((pin != NULL) && (_pin != NULL)) {
01048         if (_at->send("AT+CPWD=\"SC\",\"%s\",\"%s\"", _pin, pin) && _at->recv("OK")) {
01049             _pin = pin;
01050             success = true;
01051         }
01052     }
01053 
01054     UNLOCK();
01055     return success;
01056 }
01057 
01058 // Get the IMEI.
01059 bool UbloxCellularBase::get_imei(char *imei_to_send, int size)
01060 {
01061     bool success;
01062     LOCK();
01063 
01064     MBED_ASSERT(_at != NULL);
01065 
01066     // International mobile equipment identifier
01067     // AT Command Manual UBX-13002752, section 4.7
01068     success = _at->send("AT+CGSN") && _at->recv("%15[^\n]\nOK\n", _dev_info.imei);
01069     tr_info("DevInfo: IMEI=%s", _dev_info.imei);
01070 
01071     if (success)    {
01072         memcpy(imei_to_send,_dev_info.imei,size);
01073         imei_to_send[size-1] = '\0';
01074     }
01075 
01076     UNLOCK();
01077     return success;
01078 }
01079 
01080 // Get the IMEI of the module.
01081 const char *UbloxCellularBase::imei()
01082 {
01083     return _dev_info.imei;
01084 }
01085 
01086 // Get the Mobile Equipment ID (which may be the same as the IMEI).
01087 const char *UbloxCellularBase::meid()
01088 {
01089     return _dev_info.meid;
01090 }
01091 
01092 // Get the IMSI of the SIM.
01093 const char *UbloxCellularBase::imsi()
01094 {
01095     // (try) to update the IMSI, just in case the SIM has changed
01096     get_imsi();
01097     
01098     return _dev_info.imsi;
01099 }
01100 
01101 // Get the ICCID of the SIM.
01102 const char *UbloxCellularBase::iccid()
01103 {
01104     // (try) to update the ICCID, just in case the SIM has changed
01105     get_iccid();
01106     
01107     return _dev_info.iccid;
01108 }
01109 
01110 // Get the RSSI in dBm.
01111 int UbloxCellularBase::rssi()
01112 {
01113     char buf[7] = {0};
01114     int rssi = 0;
01115     int qual = 0;
01116     int rssiRet = 0;
01117     bool success;
01118     LOCK();
01119 
01120     MBED_ASSERT(_at != NULL);
01121 
01122     success = _at->send("AT+CSQ") && _at->recv("+CSQ: %6[^\n]\nOK\n", buf);
01123 
01124     if (success) {
01125         if (sscanf(buf, "%d,%d", &rssi, &qual) == 2) {
01126             // AT+CSQ returns a coded RSSI value and an RxQual value
01127             // For 2G an RSSI of 0 corresponds to -113 dBm or less, 
01128             // an RSSI of 31 corresponds to -51 dBm or less and hence
01129             // each value is a 2 dB step.
01130             // For LTE the mapping is defined in the array rssiConvertLte[].
01131             // For 3G the mapping to RSCP is defined in the array rscpConvert3G[]
01132             // and the RSSI value is then RSCP - the EC_NO_LEV number derived
01133             // by putting the qual number through qualConvert3G[].
01134             if ((rssi >= 0) && (rssi <= 31)) {
01135                 switch (_dev_info.rat) {
01136                     case UTRAN:
01137                     case HSDPA:
01138                     case HSUPA:
01139                     case HSDPA_HSUPA:
01140                         // 3G
01141                         if ((qual >= 0) && (qual <= 7)) {
01142                             qual = qualConvert3G[qual];
01143                             rssiRet = rscpConvert3G[rssi];
01144                             rssiRet -= qual;
01145                         }
01146 
01147                         break;
01148                     case LTE:
01149                         // LTE
01150                         rssiRet = rssiConvertLte[rssi];
01151                         break;
01152                     case GSM:
01153                     case COMPACT_GSM:
01154                     case EDGE:
01155                     default:
01156                         // GSM or assumed GSM if the RAT is not known
01157                         rssiRet = -(113 - (rssi << 2));
01158                         break;
01159                 }
01160             }
01161         }
01162     }
01163 
01164     UNLOCK();
01165     return rssiRet;
01166 }
01167 
01168 //RAT should be set in a detached state (AT+COPS=2)
01169 bool UbloxCellularBase::set_modem_rat(RAT selected_rat, RAT preferred_rat, RAT second_preferred_rat)
01170 {
01171     bool success = false;
01172     char command[16] = {0x00};
01173 
01174     //check if modem is registered with network
01175     if (is_registered_csd() || is_registered_psd() || is_registered_eps()) {
01176         tr_error("RAT should only be set in detached state");
01177         return false;
01178     }
01179 
01180     if (preferred_rat != NOT_USED && second_preferred_rat != NOT_USED) {
01181         sprintf(command, "AT+URAT=%d,%d,%d", selected_rat, preferred_rat, second_preferred_rat);
01182     } else if (preferred_rat != NOT_USED) {
01183         sprintf(command, "AT+URAT=%d,%d", selected_rat, preferred_rat);
01184     } else if (second_preferred_rat != NOT_USED) {
01185         sprintf(command, "AT+URAT=%d,%d", selected_rat, second_preferred_rat);
01186     } else {
01187         sprintf(command, "AT+URAT=%d", selected_rat);
01188     }
01189 
01190     LOCK();
01191     if (_at->send(command) && _at->recv("OK"))  {
01192         success = true;
01193     } else {
01194         tr_error("unable to set the specified RAT");
01195         success = false;
01196     }
01197     UNLOCK();
01198 
01199     return success;
01200 }
01201 
01202 bool UbloxCellularBase::get_modem_rat(int *selected_rat, int *preferred_rat, int *second_preferred_rat)
01203 {
01204     bool success = false;
01205     char buf[24] = {0x00};
01206 
01207     if (selected_rat == NULL || preferred_rat == NULL || second_preferred_rat == NULL) {
01208         tr_info("invalid pointers");
01209         return false;
01210     }
01211 
01212     MBED_ASSERT(_at != NULL);
01213 
01214     *selected_rat = NOT_USED;
01215     *preferred_rat = NOT_USED;
01216     *second_preferred_rat = NOT_USED;
01217 
01218     LOCK();
01219 
01220     if (_at->send("AT+URAT?") && _at->recv("%23[^\n]\nOK\n", buf)) {
01221         if (sscanf(buf, "+URAT: %d,%d,%d", selected_rat, preferred_rat, second_preferred_rat) == 3) {
01222             success = true;
01223         } else if (sscanf(buf, "+URAT: %d,%d", selected_rat, preferred_rat) == 2) {
01224             success = true;
01225         } else if (sscanf(buf, "+URAT: %d", selected_rat) == 1) {
01226             success = true;
01227         }
01228     }
01229 
01230     UNLOCK();
01231     return success;
01232 }
01233 
01234 //application should call init() or connect() in order to initialize the modem
01235 bool UbloxCellularBase::reboot_modem()
01236 {
01237     return (set_functionality_mode(FUNC_RESET));
01238 }
01239 
01240 bool UbloxCellularBase::set_functionality_mode(FunctionalityMode mode)
01241 {
01242     bool return_val = false;
01243     int at_timeout;
01244     LOCK();
01245 
01246     MBED_ASSERT(_at != NULL);
01247 
01248     at_timeout = _at_timeout; // Has to be inside LOCK()s
01249     at_set_timeout(3*60*1000); //command has 3 minutes timeout
01250 
01251     if (_at->send("AT+CFUN=%d", mode) && _at->recv("OK")) {
01252         return_val = true;
01253     }
01254 
01255     if (mode == FUNC_RESET || mode == FUNC_RESET_WITH_SIM) {
01256         _modem_initialised = false;
01257     }
01258 
01259     at_set_timeout(at_timeout);
01260     UNLOCK();
01261 
01262     return return_val;
01263 }
01264 
01265 bool UbloxCellularBase::get_functionality_mode(int *mode)
01266 {
01267     bool return_val = false;
01268 
01269     if (mode == NULL) {
01270         return false;
01271     }
01272 
01273     LOCK();
01274     MBED_ASSERT(_at != NULL);
01275 
01276     if ( (_at->send("AT+CFUN?") && _at->recv("+CFUN: %d", mode) && _at->recv("OK")) )  {
01277         return_val = true;
01278     }
01279 
01280     UNLOCK();
01281     return return_val;
01282 }
01283 
01284 #ifdef TARGET_UBLOX_C030_R41XM
01285 bool UbloxCellularBase::set_mno_profile(MNOProfile profile)
01286 {
01287     bool return_val = false;
01288     int current_profile;
01289     MNOProfile arr[MAX_NUM_PROFILES] = { SW_DEFAULT, SIM_ICCID, ATT, TMO, VODAFONE, DT, STANDARD_EU
01290 #ifdef  TARGET_UBLOX_C030_R410M
01291                                          , VERIZON, TELSTRA, CT, SPRINT, TELUS
01292 #endif
01293                                        };
01294 
01295     if (is_registered_csd() || is_registered_psd() || is_registered_eps()) {
01296         tr_error("MNO profile should only be set in detached state");
01297         return false;
01298     }
01299 
01300     if (get_mno_profile(&current_profile)) {
01301         if (current_profile == profile) { //Ref to UBX-18019856 7.1.7, parameters will be updated only if we switch to another profile first
01302             for (uint8_t index = 0; index < MAX_NUM_PROFILES; index++) { //get the index of current profile and use the next one
01303                 if (arr[index] == current_profile) {
01304                     index = ((index + 1) % MAX_NUM_PROFILES);
01305                     current_profile = arr[index];
01306                     break;
01307                 }
01308             }
01309 
01310             LOCK();
01311             if (_at->send("AT+UMNOPROF=%d", current_profile) && _at->recv("OK")) {
01312                 tr_error("temporary MNO profile set: %d", current_profile);
01313             }
01314             UNLOCK();
01315         }
01316         LOCK();
01317         if (_at->send("AT+UMNOPROF=%d", profile) && _at->recv("OK")) {
01318             return_val = true;
01319         } else {
01320             tr_error("unable to set user specified profile");
01321         }
01322         UNLOCK();
01323     } else {
01324         tr_error("could not read MNO profile");
01325     }
01326 
01327     return return_val;
01328 }
01329 
01330 bool UbloxCellularBase::get_mno_profile(int *profile)
01331 {
01332     bool return_val = false;
01333     char buf[4] = {0x00};
01334 
01335     if (profile == NULL) {
01336         return false;
01337     }
01338 
01339     LOCK();
01340     MBED_ASSERT(_at != NULL);
01341 
01342     if (_at->send("AT+UMNOPROF?") && _at->recv("+UMNOPROF: %3[^\n]\nOK\n", buf))  {
01343         *profile = atoi(buf);
01344         return_val = true;
01345     }
01346 
01347     UNLOCK();
01348     return return_val;
01349 }
01350 // Enable or Disable the UPSV power saving mode
01351 bool UbloxCellularBase::set_idle_mode(bool enable)
01352 {
01353 #ifdef TARGET_UBLOX_C030_R412M
01354     if (_psm_status == true && enable == true) {
01355         return false;
01356     }
01357 #endif
01358 
01359     bool success = false;
01360     LOCK();
01361 
01362     MBED_ASSERT(_at != NULL);
01363 
01364     if (_at->send("AT+UPSV=%d", enable ? 4 : 0) && _at->recv("OK")) {
01365         if (enable == true) {
01366             _at->idle_mode_enabled();
01367         }
01368         else {
01369             _at->idle_mode_disabled();
01370         }
01371         success = true;
01372     }
01373 
01374     UNLOCK();
01375     return success;
01376 }
01377 
01378 bool UbloxCellularBase::get_idle_mode(int *status)
01379 {
01380     bool return_val = false;
01381 
01382     if (status == NULL) {
01383         return false;
01384     }
01385 
01386     LOCK();
01387     MBED_ASSERT(_at != NULL);
01388 
01389     if ( (_at->send("AT+UPSV?") && _at->recv("+UPSV: %d", status) && _at->recv("OK")) )  {
01390         if (*status == 4) {
01391             *status = 1;
01392         }
01393         return_val = true;
01394     }
01395 
01396     UNLOCK();
01397     return return_val;
01398 }
01399 
01400 int UbloxCellularBase::set_receive_period(int mode, tEDRXAccessTechnology act_type, uint8_t edrx_value) {
01401     char edrx[5];
01402     uint_to_binary_str(edrx_value, edrx, 5, 4);
01403     edrx[4] = '\0';
01404     int status = 1;
01405 
01406     LOCK();
01407 
01408     if (_at->send("AT+CEDRXS=%d,%d,\"%s\"", mode, act_type, edrx) && _at->recv("OK")) {
01409         _edrx_configured = true;
01410         status = 0;
01411     }
01412     else {
01413         status = 1;
01414     }
01415 
01416 
01417     UNLOCK();
01418 
01419     return status;
01420 }
01421 
01422 int UbloxCellularBase::set_receive_period(int mode, tEDRXAccessTechnology act_type) {
01423     int status = 1;
01424 
01425     LOCK();
01426 
01427     if (_at->send("AT+CEDRXS=%d,%d", mode, act_type) && _at->recv("OK")) {
01428 
01429         status = 0;
01430     }
01431     else {
01432         status = 1;
01433     }
01434 
01435     UNLOCK();
01436 
01437     return status;
01438 }
01439 
01440 int UbloxCellularBase::set_receive_period(int mode) {
01441     int status = 1;
01442 
01443     LOCK();
01444 
01445     if (_at->send("AT+CEDRXS=%d", mode) && _at->recv("OK")) {
01446 
01447         status = 0;
01448     }
01449     else {
01450         status = 1;
01451     }
01452 
01453     UNLOCK();
01454 
01455     return status;
01456 }
01457 
01458 uint32_t UbloxCellularBase::get_receive_period() {
01459     uint32_t edrx_value = 2;
01460     char buf[24] = {0x00};
01461     char edrx_val[5];
01462     tEDRXAccessTechnology act_type;
01463 
01464     LOCK();
01465 
01466     if (_at->send("AT+CEDRXS?") && _at->recv("%23[^\n]\nOK\n", buf)) {
01467         if (sscanf(buf, "+CEDRXS: %d,\"%s\"", (int *)&act_type, edrx_val) == 2) {
01468 
01469             edrx_value = binary_str_to_uint(edrx_val,4);
01470         }
01471     }
01472 
01473     if (_at->send("AT+CEDRXRDP") && _at->recv("OK")) {
01474     }
01475 
01476     tr_info("edrx_value. %d", edrx_value);
01477 
01478     UNLOCK();
01479     return edrx_value;
01480 }
01481 
01482 void UbloxCellularBase::uint_to_binary_str(uint32_t num, char* str, int str_size, int bit_cnt)
01483 {
01484     if (!str || str_size < bit_cnt) {
01485         return;
01486     }
01487     int tmp, pos = 0;
01488 
01489     for (int i = 31; i >= 0; i--) {
01490         tmp = num >> i;
01491         if (i < bit_cnt) {
01492             if (tmp&1) {
01493                 str[pos] = 1 + '0';
01494             } else {
01495                 str[pos] = 0 + '0';
01496             }
01497             pos++;
01498         }
01499     }
01500 }
01501 
01502 uint32_t UbloxCellularBase::binary_str_to_uint(const char *binary_string, int binary_string_length)
01503 {
01504     if (!binary_string || !binary_string_length) {
01505         return 0;
01506     }
01507 
01508     int integer_output = 0, base_exp = 1;
01509 
01510     for (int i = binary_string_length - 1; i >= 0; i--) {
01511         if (binary_string[i] == '1') {
01512             integer_output += (base_exp << (binary_string_length - (i+1)));
01513         }
01514     }
01515 
01516     return integer_output;
01517 }
01518 
01519 bool UbloxCellularBase::set_band_bitmask(RAT rat, uint64_t bitmask) {
01520 
01521     bool status = false;
01522     UBandmaskRAT eBandMastRat;
01523 
01524     if(rat == LTE_CATM1) {
01525         eBandMastRat = UBANDMASK_RAT_LTE_CATM1;
01526     }
01527     else if(rat == LTE_CATNB1) {
01528         eBandMastRat = UBANDMASK_RAT_LTE_CATNB1;
01529     }
01530     else {
01531         tr_error("Invalid RAT for Band mask selection: %d", rat);
01532 
01533         return false;
01534     }
01535 
01536     tr_info("UBANDMASK RAT %d, bitmask : %llu", eBandMastRat, bitmask);
01537 
01538     LOCK();
01539 
01540     if (_at->send("AT+UBANDMASK=%d,%llu", eBandMastRat, bitmask) && _at->recv("OK")) {
01541 
01542         status = true;
01543     }
01544     UNLOCK();
01545 
01546     return status;
01547 }
01548 #endif //TARGET_UBLOX_C030_R41XM
01549 
01550 #ifdef TARGET_UBLOX_C030_R412M
01551 bool UbloxCellularBase::get_power_saving_mode(int *status, int *periodic_time, int *active_time)
01552 {
01553     char pt_encoded[8+1];// timer value encoded as 3GPP IE
01554     char at_encoded[8+1];// timer value encoded as 3GPP IE
01555     int value, multiplier;
01556     bool return_val;
01557 
01558     if (status == NULL || periodic_time == NULL || active_time == NULL) {
01559         return false;
01560     }
01561 
01562     LOCK();
01563     //+UCPSMS:1,,,"01000011","01000011"
01564     if (_at->send("AT+UCPSMS?") && _at->recv("+UCPSMS:%d,,,\"%8c\",\"%8c\"\nOK\n", status, pt_encoded, at_encoded)) {
01565         if (*status == true) {
01566             //PSM is enabled, decode the timer values, periodic TAU first
01567             value =  (pt_encoded[7]- '0');
01568             value += (pt_encoded[6]- '0') << 1;
01569             value += (pt_encoded[5]- '0') << 2;
01570             value += (pt_encoded[4]- '0') << 3;
01571             value += (pt_encoded[3]- '0') << 4;
01572 
01573             multiplier =  (pt_encoded[2]- '0');
01574             multiplier += (pt_encoded[1]- '0') << 1;
01575             multiplier += (pt_encoded[0]- '0') << 2;
01576 
01577             switch(multiplier) {
01578                 //10 minutes
01579                 case 0:
01580                     value = value*10*60;
01581                 break;
01582 
01583                 //1 hour
01584                 case 1:
01585                     value = value*60*60;
01586                 break;
01587 
01588                 //10 hours
01589                 case 2:
01590                     value = value*10*60*60;
01591                 break;
01592 
01593                 //2 seconds
01594                 case 3:
01595                     value = value*2;
01596                 break;
01597 
01598                 //30 seconds
01599                 case 4:
01600                     value = value*30;
01601                 break;
01602 
01603                 //1 minute
01604                 case 5:
01605                     value = value*60;
01606                 break;
01607 
01608                 //320 hours
01609                 case 6:
01610                     value = value*320*60*60;
01611                 break;
01612 
01613                 default:
01614                     value = 0;
01615                 break;
01616             }
01617             *periodic_time = value;
01618 
01619             //decode the active time
01620             value =  (at_encoded[7]- '0');
01621             value += (at_encoded[6]- '0') << 1;
01622             value += (at_encoded[5]- '0') << 2;
01623             value += (at_encoded[4]- '0') << 3;
01624             value += (at_encoded[3]- '0') << 4;
01625 
01626             multiplier =  (at_encoded[2]- '0');
01627             multiplier += (at_encoded[1]- '0') << 1;
01628             multiplier += (at_encoded[0]- '0') << 2;
01629 
01630             switch(multiplier) {
01631                 //2 seconds
01632                 case 0:
01633                     value = value*2;
01634                 break;
01635 
01636                 //1 minute
01637                 case 1:
01638                     value = value*60;
01639                 break;
01640 
01641                 //decihours (6minutes)
01642                 case 2:
01643                     value = value*6*60;
01644                 break;
01645 
01646                 default:
01647                     value = 0;
01648                 break;
01649             }
01650             *active_time = value;
01651         }
01652         return_val = true;
01653     } else {
01654         return_val = false;
01655     }
01656     UNLOCK();
01657     return return_val;
01658 }
01659 
01660 bool UbloxCellularBase::set_power_saving_mode(int periodic_time, int active_time)
01661 {
01662     if (_at->is_idle_mode_enabled() == true && periodic_time != 0 && active_time != 0 ) {
01663         return false;
01664     }
01665     bool return_val = false;
01666 
01667     LOCK();
01668     int at_timeout = _at_timeout;
01669     at_set_timeout(10000); //AT+CPSMS has response time of < 10s
01670 
01671     //check if modem supports PSM URCs
01672     if (_at->send("AT+UPSMR?") && _at->recv("OK")) {
01673         if (periodic_time == 0 && active_time == 0) {
01674             // disable PSM
01675             if (_at->send("AT+CPSMS=0") && _at->recv("OK")) {
01676                 if (set_psm_urcs(0)) {//disable the URC
01677                     //de-register the callback
01678                     detach_cb_psm_going_in();
01679                     detach_cb_psm_coming_out();
01680                     _psm_status = false;
01681                     return_val = true;
01682                 }
01683             }
01684         } else { //PSM string encoding code borrowed from AT_CellularPower.cpp
01685             /**
01686                 Table 10.5.163a/3GPP TS 24.008: GPRS Timer 3 information element
01687 
01688                 Bits 5 to 1 represent the binary coded timer value.
01689 
01690                 Bits 6 to 8 defines the timer value unit for the GPRS timer as follows:
01691                 8 7 6
01692                 0 0 0 value is incremented in multiples of 10 minutes
01693                 0 0 1 value is incremented in multiples of 1 hour
01694                 0 1 0 value is incremented in multiples of 10 hours
01695                 0 1 1 value is incremented in multiples of 2 seconds
01696                 1 0 0 value is incremented in multiples of 30 seconds
01697                 1 0 1 value is incremented in multiples of 1 minute
01698                 1 1 0 value is incremented in multiples of 320 hours (NOTE 1)
01699                 1 1 1 value indicates that the timer is deactivated (NOTE 2).
01700              */
01701             char pt[8+1];// timer value encoded as 3GPP IE
01702             const int ie_value_max = 0x1f;
01703             uint32_t periodic_timer = 0;
01704             if (periodic_time <= 2*ie_value_max) { // multiples of 2 seconds
01705                 periodic_timer = periodic_time/2;
01706                 strcpy(pt, "01100000");
01707             } else {
01708                 if (periodic_time <= 30*ie_value_max) { // multiples of 30 seconds
01709                     periodic_timer = periodic_time/30;
01710                     strcpy(pt, "10000000");
01711                 } else {
01712                     if (periodic_time <= 60*ie_value_max) { // multiples of 1 minute
01713                         periodic_timer = periodic_time/60;
01714                         strcpy(pt, "10100000");
01715                     } else {
01716                         if (periodic_time <= 10*60*ie_value_max) { // multiples of 10 minutes
01717                             periodic_timer = periodic_time/(10*60);
01718                             strcpy(pt, "00000000");
01719                         } else {
01720                             if (periodic_time <= 60*60*ie_value_max) { // multiples of 1 hour
01721                                 periodic_timer = periodic_time/(60*60);
01722                                 strcpy(pt, "00100000");
01723                             } else {
01724                                 if (periodic_time <= 10*60*60*ie_value_max) { // multiples of 10 hours
01725                                     periodic_timer = periodic_time/(10*60*60);
01726                                     strcpy(pt, "01000000");
01727                                 } else { // multiples of 320 hours
01728                                     int t = periodic_time / (320*60*60);
01729                                     if (t > ie_value_max) {
01730                                         t = ie_value_max;
01731                                     }
01732                                     periodic_timer = t;
01733                                     strcpy(pt, "11000000");
01734                                 }
01735                             }
01736                         }
01737                     }
01738                 }
01739             }
01740 
01741             uint_to_binary_str(periodic_timer, &pt[3], sizeof(pt)-3, 5);
01742             pt[8] = '\0';
01743 
01744             /**
01745                 Table 10.5.172/3GPP TS 24.008: GPRS Timer information element
01746 
01747                 Bits 5 to 1 represent the binary coded timer value.
01748 
01749                 Bits 6 to 8 defines the timer value unit for the GPRS timer as follows:
01750 
01751                 8 7 6
01752                 0 0 0  value is incremented in multiples of 2 seconds
01753                 0 0 1  value is incremented in multiples of 1 minute
01754                 0 1 0  value is incremented in multiples of decihours
01755                 1 1 1  value indicates that the timer is deactivated.
01756 
01757                 Other values shall be interpreted as multiples of 1 minute in this version of the protocol.
01758             */
01759             char at[8+1];
01760             uint32_t active_timer; // timer value encoded as 3GPP IE
01761             if (active_time <= 2*ie_value_max) { // multiples of 2 seconds
01762                 active_timer = active_time/2;
01763                 strcpy(at, "00000000");
01764             } else {
01765                 if (active_time <= 60*ie_value_max) { // multiples of 1 minute
01766                     active_timer = (1<<5) | (active_time/60);
01767                     strcpy(at, "00100000");
01768                 } else { // multiples of decihours
01769                     int t = active_time / (6*60);
01770                     if (t > ie_value_max) {
01771                         t = ie_value_max;
01772                     }
01773                     active_timer = t;
01774                     strcpy(at, "01000000");
01775                 }
01776             }
01777 
01778             uint_to_binary_str(active_timer, &at[3], sizeof(at)-3, 5);
01779             at[8] = '\0';
01780 
01781             if (_at->send("AT+CPSMS=1,,,\"%s\",\"%s\"", pt, at) && _at->recv("OK")) {
01782                 if (set_psm_urcs(1)) {//enable the PSM URC
01783                     tr_info("PSM enabled successfully!");
01784                     _psm_status = true;
01785                     return_val = true;
01786                 } else {
01787                     tr_error("PSM URCs not supported");
01788                     return_val = false;
01789                 }
01790             } else {
01791                 tr_error("+CPSMS command failed");
01792                 return_val = false;
01793             }
01794         }
01795     } else {
01796         tr_error("PSM URCs not supported by this version of modem");
01797     }
01798     at_set_timeout(at_timeout);
01799     UNLOCK();
01800     return return_val;
01801 }
01802 
01803 bool UbloxCellularBase::is_modem_awake()
01804 {
01805   return (_dev_info.modem_psm_state == AWAKE);
01806 }
01807 
01808 //application should call init() or connect() in order to initialize the modem
01809 void UbloxCellularBase::wakeup_modem()
01810 {
01811     LOCK();
01812 
01813     MBED_ASSERT(_at != NULL);
01814 
01815     tr_info("Waking up modem...");
01816 
01817     modem_power_up();
01818 
01819     _dev_info.reg_status_csd = CSD_NOT_REGISTERED_NOT_SEARCHING;
01820     _dev_info.reg_status_psd = PSD_NOT_REGISTERED_NOT_SEARCHING;
01821     _dev_info.reg_status_eps = EPS_NOT_REGISTERED_NOT_SEARCHING;
01822     _modem_initialised = false;
01823 
01824     UNLOCK();
01825 }
01826 
01827 bool UbloxCellularBase::set_psm_urcs(bool enable)
01828 {
01829 
01830     bool success = false;
01831     LOCK();
01832 
01833     MBED_ASSERT(_at != NULL);
01834 
01835     if (_at->send("AT+UPSMR=%d", enable ? 1 : 0) && _at->recv("OK")) {
01836         success = true;
01837     }
01838 
01839     UNLOCK();
01840     return success;
01841 }
01842 #endif
01843 
01844 // End of File
01845