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