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