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 int at_timeout; 00607 LOCK(); 00608 00609 at_timeout = _at_timeout; // Has to be inside LOCK()s 00610 00611 MBED_ASSERT(_at != NULL); 00612 00613 /* Initialize GPIO lines */ 00614 tr_info("Powering up modem..."); 00615 modem_init(); 00616 /* Give modem a little time to settle down */ 00617 wait_ms(250); 00618 00619 for (int retry_count = 0; !success && (retry_count < 20); retry_count++) { 00620 //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. 00621 if ( (retry_count % 5) == 0) { 00622 modem_power_up(); 00623 } 00624 wait_ms(500); 00625 // Modem tends to spit out noise during power up - don't confuse the parser 00626 _at->flush(); 00627 at_set_timeout(1000); 00628 if (_at->send("AT")) { 00629 // C027 needs a delay here 00630 wait_ms(100); 00631 if (_at->recv("OK")) { 00632 success = true; 00633 } 00634 } 00635 at_set_timeout(at_timeout); 00636 } 00637 00638 if (success) { 00639 // Set the final baud rate 00640 if (_at->send("AT+IPR=%d", _baud) && _at->recv("OK")) { 00641 // Need to wait for things to be sorted out on the modem side 00642 wait_ms(100); 00643 ((UARTSerial *)_fh)->set_baud(_baud); 00644 } 00645 00646 // Turn off modem echoing and turn on verbose responses 00647 success = _at->send("ATE0;+CMEE=2") && _at->recv("OK") && 00648 // The following commands are best sent separately 00649 _at->send("AT&K0") && _at->recv("OK") && // Turn off RTC/CTS handshaking 00650 _at->send("AT&C1") && _at->recv("OK") && // Set DCD circuit(109), changes in accordance with the carrier detect status 00651 _at->send("AT&D0") && _at->recv("OK"); // Set DTR circuit, we ignore the state change of DTR 00652 } 00653 00654 if (!success) { 00655 tr_error("Preliminary modem setup failed."); 00656 } 00657 00658 UNLOCK(); 00659 return success; 00660 } 00661 00662 // Power down modem via AT interface. 00663 void UbloxCellularBase::power_down() 00664 { 00665 LOCK(); 00666 00667 MBED_ASSERT(_at != NULL); 00668 00669 // power-off modem 00670 modem_power_down(); 00671 modem_deinit(); 00672 00673 if (_modem_initialised && (_at != NULL)) { 00674 int at_timeout = _at_timeout; // Save previous timeout 00675 _at->set_timeout(1000); 00676 // Check modem is powered off 00677 if(_at->send("AT") && _at->recv("OK")) { 00678 _at->send("AT+CPWROFF") && _at->recv("OK"); 00679 } 00680 _at->set_timeout(at_timeout); 00681 } 00682 00683 _dev_info.reg_status_csd = CSD_NOT_REGISTERED_NOT_SEARCHING; 00684 _dev_info.reg_status_psd = PSD_NOT_REGISTERED_NOT_SEARCHING; 00685 _dev_info.reg_status_eps = EPS_NOT_REGISTERED_NOT_SEARCHING; 00686 00687 UNLOCK(); 00688 } 00689 00690 // Get the device ID. 00691 bool UbloxCellularBase::set_device_identity(DeviceType *dev) 00692 { 00693 char buf[20]; 00694 bool success; 00695 LOCK(); 00696 00697 MBED_ASSERT(_at != NULL); 00698 00699 success = _at->send("ATI") && _at->recv("%19[^\n]\nOK\n", buf); 00700 00701 if (success) { 00702 if (strstr(buf, "SARA-G35")) 00703 *dev = DEV_SARA_G35; 00704 else if (strstr(buf, "LISA-U200-03S")) 00705 *dev = DEV_LISA_U2_03S; 00706 else if (strstr(buf, "LISA-U2")) 00707 *dev = DEV_LISA_U2; 00708 else if (strstr(buf, "SARA-U2")) 00709 *dev = DEV_SARA_U2; 00710 else if (strstr(buf, "SARA-R4")) 00711 *dev = DEV_SARA_R4; 00712 else if (strstr(buf, "LEON-G2")) 00713 *dev = DEV_LEON_G2; 00714 else if (strstr(buf, "TOBY-L2")) 00715 *dev = DEV_TOBY_L2; 00716 else if (strstr(buf, "MPCI-L2")) 00717 *dev = DEV_MPCI_L2; 00718 } 00719 00720 UNLOCK(); 00721 return success; 00722 } 00723 00724 // Send initialisation AT commands that are specific to the device. 00725 bool UbloxCellularBase::device_init(DeviceType dev) 00726 { 00727 bool success = false; 00728 LOCK(); 00729 00730 MBED_ASSERT(_at != NULL); 00731 00732 if ((dev == DEV_LISA_U2) || (dev == DEV_LEON_G2) || (dev == DEV_TOBY_L2)) { 00733 success = _at->send("AT+UGPIOC=20,2") && _at->recv("OK"); 00734 } else if ((dev == DEV_SARA_U2) || (dev == DEV_SARA_G35)) { 00735 success = _at->send("AT+UGPIOC=16,2") && _at->recv("OK"); 00736 } else { 00737 success = true; 00738 } 00739 00740 UNLOCK(); 00741 return success; 00742 } 00743 00744 // Get the SIM card going. 00745 bool UbloxCellularBase::initialise_sim_card() 00746 { 00747 bool success = false; 00748 int retry_count = 0; 00749 bool done = false; 00750 LOCK(); 00751 00752 MBED_ASSERT(_at != NULL); 00753 00754 /* SIM initialisation may take a significant amount, so an error is 00755 * kind of expected. We should retry 10 times until we succeed or timeout. */ 00756 for (retry_count = 0; !done && (retry_count < 10); retry_count++) { 00757 char pinstr[16]; 00758 00759 if (_at->send("AT+CPIN?") && _at->recv("+CPIN: %15[^\n]\n", pinstr) && 00760 _at->recv("OK")) { 00761 done = true; 00762 if (strcmp(pinstr, "SIM PIN") == 0) { 00763 _sim_pin_check_enabled = true; 00764 if (_at->send("AT+CPIN=\"%s\"", _pin)) { 00765 if (_at->recv("OK")) { 00766 tr_info("PIN correct"); 00767 success = true; 00768 } else { 00769 tr_error("Incorrect PIN"); 00770 } 00771 } 00772 } else if (strcmp(pinstr, "READY") == 0) { 00773 _sim_pin_check_enabled = false; 00774 tr_info("No PIN required"); 00775 success = true; 00776 } else { 00777 tr_debug("Unexpected response from SIM: \"%s\"", pinstr); 00778 } 00779 } 00780 00781 /* wait for a second before retry */ 00782 wait_ms(1000); 00783 } 00784 00785 if (done) { 00786 tr_info("SIM Ready."); 00787 } else { 00788 tr_error("SIM not ready."); 00789 } 00790 00791 UNLOCK(); 00792 return success; 00793 } 00794 00795 /********************************************************************** 00796 * PUBLIC METHODS 00797 **********************************************************************/ 00798 00799 // Initialise the modem. 00800 bool UbloxCellularBase::init(const char *pin) 00801 { 00802 int x; 00803 MBED_ASSERT(_at != NULL); 00804 00805 if (!_modem_initialised) { 00806 if (power_up()) { 00807 tr_info("Modem Ready."); 00808 if (pin != NULL) { 00809 _pin = pin; 00810 } 00811 #ifdef TARGET_UBLOX_C027 00812 if (set_functionality_mode(FUNC_MIN)) { 00813 #else 00814 if (set_functionality_mode(FUNC_AIRPLANE)) { 00815 #endif 00816 if (initialise_sim_card()) { 00817 #ifdef TARGET_UBLOX_C030_R41XM 00818 int mno_profile; 00819 if (get_mno_profile(&mno_profile)) { 00820 if (mno_profile == SW_DEFAULT) { 00821 tr_critical("!!CANNOT USE PROFILE 0(SW_DEFAULT). PLEASE SET AN APPROPRIATE MNO PROFILE!!"); 00822 _default_profile_is_set = true; 00823 return false; 00824 } 00825 } 00826 #ifdef TARGET_UBLOX_C030_R412M 00827 int status = 0, periodic_time = 0, active_time = 0; 00828 if (_psm_status == UNKNOWN) { 00829 if (get_power_saving_mode(&status, &periodic_time, &active_time)) { 00830 if (status) { //PSM is already enabled either by a previous run or MNO profile 00831 tr_info("PSM is already enabled, periodic_time %d, active_time %d", periodic_time, active_time); 00832 _psm_status = ENABLED; 00833 if ( !(set_psm_urcs(true)) ) { //enable PSM URCs 00834 tr_error("Modem does not support PSM URCs, disabling PSM"); 00835 set_power_saving_mode(0, 0); 00836 } else if (!_func_psm_going_in){ 00837 tr_critical("!!PSM IS ENABLED, CALLBACK NOT ATTACHED. PLEASE REGISTER ONE!!"); 00838 } 00839 } 00840 } 00841 } else if (_psm_status == ENABLED && !_func_psm_going_in){ 00842 tr_critical("!!PSM IS ENABLED, CALLBACK NOT ATTACHED. PLEASE REGISTER ONE!!"); 00843 } 00844 #elif TARGET_UBLOX_C030_R410M 00845 disable_psm(); //PSM is currently not supported by driver for R410M due to lack of URCs 00846 #endif 00847 if (_at->is_idle_mode_enabled() == false) { 00848 set_idle_mode(false); //disable idle mode at start up 00849 } 00850 #endif 00851 if (set_device_identity(&_dev_info.dev) && // Set up device identity 00852 device_init(_dev_info.dev)) {// Initialise this device 00853 // Get the integrated circuit ID of the SIM 00854 if (get_iccid()) { 00855 // Try a few times to get the IMSI (since on some modems this can 00856 // take a while to be retrieved, especially if a SIM PIN 00857 // was set) 00858 for (x = 0; (x < 3) && !get_imsi(); x++) { 00859 wait_ms(1000); 00860 } 00861 00862 if (x < 3) { // If we got the IMSI, can get the others 00863 if (get_imei() && // Get international mobile equipment identifier 00864 get_meid() && // Probably the same as the IMEI 00865 set_sms()) { // And set up SMS 00866 // The modem is initialised. 00867 _modem_initialised = true; 00868 tr_info("Modem initialized"); 00869 } 00870 } 00871 } 00872 } 00873 } 00874 } 00875 } 00876 } 00877 00878 return _modem_initialised; 00879 } 00880 00881 // Perform registration. 00882 bool UbloxCellularBase::nwk_registration() 00883 { 00884 bool atSuccess = false; 00885 bool registered = false; 00886 int status; 00887 int at_timeout; 00888 LOCK(); 00889 00890 at_timeout = _at_timeout; // Has to be inside LOCK()s 00891 00892 MBED_ASSERT(_at != NULL); 00893 00894 if (!is_registered_psd() && !is_registered_csd() && !is_registered_eps()) { 00895 if (set_functionality_mode(FUNC_FULL)) { 00896 tr_info("Searching Network..."); 00897 // Enable the packet switched and network registration unsolicited result codes 00898 if (_at->send("AT+CREG=1") && _at->recv("OK") && 00899 _at->send("AT+CGREG=1") && _at->recv("OK")) { 00900 atSuccess = true; 00901 if (_at->send("AT+CEREG=1")) { 00902 _at->recv("OK"); 00903 // Don't check return value as this works for LTE only 00904 } 00905 00906 if (atSuccess) { 00907 // See if we are already in automatic mode 00908 if (_at->send("AT+COPS?") && _at->recv("+COPS: %d", &status) && 00909 _at->recv("OK")) { 00910 // If not, set it 00911 if (status != 0) { 00912 // Don't check return code here as there's not much 00913 // we can do if this fails. 00914 _at->send("AT+COPS=0") && _at->recv("OK"); 00915 } 00916 } 00917 00918 // Query the registration status directly as well, 00919 // just in case 00920 if (_at->send("AT+CREG?") && _at->recv("OK")) { 00921 // Answer will be processed by URC 00922 } 00923 if (_at->send("AT+CGREG?") && _at->recv("OK")) { 00924 // Answer will be processed by URC 00925 } 00926 if (_at->send("AT+CEREG?")) { 00927 _at->recv("OK"); 00928 // Don't check return value as this works for LTE only 00929 } 00930 } 00931 } 00932 // Wait for registration to succeed 00933 at_set_timeout(1000); 00934 for (int waitSeconds = 0; !registered && (waitSeconds < 180); waitSeconds++) { 00935 registered = is_registered_psd() || is_registered_csd() || is_registered_eps(); 00936 _at->recv(UNNATURAL_STRING); 00937 } 00938 at_set_timeout(at_timeout); 00939 00940 if (registered) { 00941 // This should return quickly but sometimes the status field is not returned 00942 // so make the timeout short 00943 at_set_timeout(1000); 00944 if (_at->send("AT+COPS?") && _at->recv("+COPS: %*d,%*d,\"%*[^\"]\",%d\nOK\n", &status)) { 00945 set_rat(status); 00946 } 00947 at_set_timeout(at_timeout); 00948 } 00949 } 00950 } else { 00951 registered = true; 00952 } 00953 00954 UNLOCK(); 00955 return registered; 00956 } 00957 00958 bool UbloxCellularBase::is_registered_csd() 00959 { 00960 return (_dev_info.reg_status_csd == CSD_REGISTERED) || 00961 (_dev_info.reg_status_csd == CSD_REGISTERED_ROAMING) || 00962 (_dev_info.reg_status_csd == CSD_CSFB_NOT_PREFERRED); 00963 } 00964 00965 bool UbloxCellularBase::is_registered_psd() 00966 { 00967 return (_dev_info.reg_status_psd == PSD_REGISTERED) || 00968 (_dev_info.reg_status_psd == PSD_REGISTERED_ROAMING); 00969 } 00970 00971 bool UbloxCellularBase::is_registered_eps() 00972 { 00973 return (_dev_info.reg_status_eps == EPS_REGISTERED) || 00974 (_dev_info.reg_status_eps == EPS_REGISTERED_ROAMING); 00975 } 00976 00977 // Perform deregistration. 00978 bool UbloxCellularBase::nwk_deregistration() 00979 { 00980 bool success = false; 00981 LOCK(); 00982 00983 MBED_ASSERT(_at != NULL); 00984 00985 int at_timeout = _at_timeout; // Has to be inside LOCK()s 00986 at_set_timeout(3*60*1000); //command has 3 minutes timeout 00987 00988 if (_at->send("AT+COPS=2") && _at->recv("OK")) { 00989 _dev_info.reg_status_csd = CSD_NOT_REGISTERED_NOT_SEARCHING; 00990 _dev_info.reg_status_psd = PSD_NOT_REGISTERED_NOT_SEARCHING; 00991 _dev_info.reg_status_eps = EPS_NOT_REGISTERED_NOT_SEARCHING; 00992 success = true; 00993 } 00994 00995 at_set_timeout(at_timeout); 00996 UNLOCK(); 00997 return success; 00998 } 00999 01000 // Put the modem into its lowest power state. 01001 void UbloxCellularBase::deinit() 01002 { 01003 power_down(); 01004 _modem_initialised = false; 01005 } 01006 01007 // Set the PIN. 01008 void UbloxCellularBase::set_pin(const char *pin) { 01009 _pin = pin; 01010 } 01011 01012 // Enable or disable SIM pin checking. 01013 bool UbloxCellularBase::sim_pin_check_enable(bool enableNotDisable) 01014 { 01015 bool success = false;; 01016 LOCK(); 01017 01018 MBED_ASSERT(_at != NULL); 01019 01020 if (_pin != NULL) { 01021 if (_sim_pin_check_enabled && !enableNotDisable) { 01022 // Disable the SIM lock 01023 if (_at->send("AT+CLCK=\"SC\",0,\"%s\"", _pin) && _at->recv("OK")) { 01024 _sim_pin_check_enabled = false; 01025 success = true; 01026 } 01027 } else if (!_sim_pin_check_enabled && enableNotDisable) { 01028 // Enable the SIM lock 01029 if (_at->send("AT+CLCK=\"SC\",1,\"%s\"", _pin) && _at->recv("OK")) { 01030 _sim_pin_check_enabled = true; 01031 success = true; 01032 } 01033 } else { 01034 success = true; 01035 } 01036 } 01037 01038 UNLOCK(); 01039 return success; 01040 } 01041 01042 // Change the pin code for the SIM card. 01043 bool UbloxCellularBase::change_sim_pin(const char *pin) 01044 { 01045 bool success = false;; 01046 LOCK(); 01047 01048 MBED_ASSERT(_at != NULL); 01049 01050 // Change the SIM pin 01051 if ((pin != NULL) && (_pin != NULL)) { 01052 if (_at->send("AT+CPWD=\"SC\",\"%s\",\"%s\"", _pin, pin) && _at->recv("OK")) { 01053 _pin = pin; 01054 success = true; 01055 } 01056 } 01057 01058 UNLOCK(); 01059 return success; 01060 } 01061 01062 // Get the IMEI. 01063 bool UbloxCellularBase::get_imei(char *imei_to_send, int size) 01064 { 01065 bool success; 01066 LOCK(); 01067 01068 MBED_ASSERT(_at != NULL); 01069 01070 // International mobile equipment identifier 01071 // AT Command Manual UBX-13002752, section 4.7 01072 success = _at->send("AT+CGSN") && _at->recv("%15[^\n]\nOK\n", _dev_info.imei); 01073 tr_info("DevInfo: IMEI=%s", _dev_info.imei); 01074 01075 if (success) { 01076 memcpy(imei_to_send,_dev_info.imei,size); 01077 imei_to_send[size-1] = '\0'; 01078 } 01079 01080 UNLOCK(); 01081 return success; 01082 } 01083 01084 // Get the IMEI of the module. 01085 const char *UbloxCellularBase::imei() 01086 { 01087 return _dev_info.imei; 01088 } 01089 01090 // Get the Mobile Equipment ID (which may be the same as the IMEI). 01091 const char *UbloxCellularBase::meid() 01092 { 01093 return _dev_info.meid; 01094 } 01095 01096 // Get the IMSI of the SIM. 01097 const char *UbloxCellularBase::imsi() 01098 { 01099 // (try) to update the IMSI, just in case the SIM has changed 01100 get_imsi(); 01101 01102 return _dev_info.imsi; 01103 } 01104 01105 // Get the ICCID of the SIM. 01106 const char *UbloxCellularBase::iccid() 01107 { 01108 // (try) to update the ICCID, just in case the SIM has changed 01109 get_iccid(); 01110 01111 return _dev_info.iccid; 01112 } 01113 01114 // Get the RSSI in dBm. 01115 int UbloxCellularBase::rssi() 01116 { 01117 char buf[7] = {0}; 01118 int rssi = 0; 01119 int qual = 0; 01120 int rssiRet = 0; 01121 bool success; 01122 LOCK(); 01123 01124 MBED_ASSERT(_at != NULL); 01125 01126 success = _at->send("AT+CSQ") && _at->recv("+CSQ: %6[^\n]\nOK\n", buf); 01127 01128 if (success) { 01129 if (sscanf(buf, "%d,%d", &rssi, &qual) == 2) { 01130 // AT+CSQ returns a coded RSSI value and an RxQual value 01131 // For 2G an RSSI of 0 corresponds to -113 dBm or less, 01132 // an RSSI of 31 corresponds to -51 dBm or less and hence 01133 // each value is a 2 dB step. 01134 // For LTE the mapping is defined in the array rssiConvertLte[]. 01135 // For 3G the mapping to RSCP is defined in the array rscpConvert3G[] 01136 // and the RSSI value is then RSCP - the EC_NO_LEV number derived 01137 // by putting the qual number through qualConvert3G[]. 01138 if ((rssi >= 0) && (rssi <= 31)) { 01139 switch (_dev_info.rat) { 01140 case UTRAN: 01141 case HSDPA: 01142 case HSUPA: 01143 case HSDPA_HSUPA: 01144 // 3G 01145 if ((qual >= 0) && (qual <= 7)) { 01146 qual = qualConvert3G[qual]; 01147 rssiRet = rscpConvert3G[rssi]; 01148 rssiRet -= qual; 01149 } 01150 01151 break; 01152 case LTE: 01153 // LTE 01154 rssiRet = rssiConvertLte[rssi]; 01155 break; 01156 case GSM: 01157 case COMPACT_GSM: 01158 case EDGE: 01159 default: 01160 // GSM or assumed GSM if the RAT is not known 01161 rssiRet = -(113 - (rssi << 2)); 01162 break; 01163 } 01164 } 01165 } 01166 } 01167 01168 UNLOCK(); 01169 return rssiRet; 01170 } 01171 01172 //RAT should be set in a detached state (AT+COPS=2) 01173 bool UbloxCellularBase::set_modem_rat(RAT selected_rat, RAT preferred_rat, RAT second_preferred_rat) 01174 { 01175 #ifdef TARGET_UBLOX_C030_R41XM 01176 if (_default_profile_is_set == true) { 01177 tr_critical("!!CANNOT USE PROFILE 0(SW_DEFAULT). PLEASE SET AN APPROPRIATE MNO PROFILE!!"); 01178 return false; 01179 } 01180 #endif 01181 01182 bool success = false; 01183 char command[16] = {0x00}; 01184 01185 //check if modem is registered with network 01186 if (is_registered_csd() || is_registered_psd() || is_registered_eps()) { 01187 tr_error("RAT should only be set in detached state"); 01188 return false; 01189 } 01190 01191 if (preferred_rat != NOT_USED && second_preferred_rat != NOT_USED) { 01192 sprintf(command, "AT+URAT=%d,%d,%d", selected_rat, preferred_rat, second_preferred_rat); 01193 } else if (preferred_rat != NOT_USED) { 01194 sprintf(command, "AT+URAT=%d,%d", selected_rat, preferred_rat); 01195 } else if (second_preferred_rat != NOT_USED) { 01196 sprintf(command, "AT+URAT=%d,%d", selected_rat, second_preferred_rat); 01197 } else { 01198 sprintf(command, "AT+URAT=%d", selected_rat); 01199 } 01200 01201 LOCK(); 01202 if (_at->send(command) && _at->recv("OK")) { 01203 success = true; 01204 } else { 01205 tr_error("unable to set the specified RAT"); 01206 success = false; 01207 } 01208 UNLOCK(); 01209 01210 return success; 01211 } 01212 01213 bool UbloxCellularBase::get_modem_rat(int *selected_rat, int *preferred_rat, int *second_preferred_rat) 01214 { 01215 #ifdef TARGET_UBLOX_C030_R41XM 01216 if (_default_profile_is_set == true) { 01217 tr_critical("!!CANNOT USE PROFILE 0(SW_DEFAULT). PLEASE SET AN APPROPRIATE MNO PROFILE!!"); 01218 return false; 01219 } 01220 #endif 01221 01222 bool success = false; 01223 char buf[24] = {0x00}; 01224 01225 if (selected_rat == NULL || preferred_rat == NULL || second_preferred_rat == NULL) { 01226 tr_info("invalid pointers"); 01227 return false; 01228 } 01229 01230 MBED_ASSERT(_at != NULL); 01231 01232 *selected_rat = NOT_USED; 01233 *preferred_rat = NOT_USED; 01234 *second_preferred_rat = NOT_USED; 01235 01236 LOCK(); 01237 01238 if (_at->send("AT+URAT?") && _at->recv("%23[^\n]\nOK\n", buf)) { 01239 if (sscanf(buf, "+URAT: %d,%d,%d", selected_rat, preferred_rat, second_preferred_rat) == 3) { 01240 success = true; 01241 } else if (sscanf(buf, "+URAT: %d,%d", selected_rat, preferred_rat) == 2) { 01242 success = true; 01243 } else if (sscanf(buf, "+URAT: %d", selected_rat) == 1) { 01244 success = true; 01245 } 01246 } 01247 01248 UNLOCK(); 01249 return success; 01250 } 01251 01252 //application should call init() or connect() in order to initialize the modem 01253 bool UbloxCellularBase::reboot_modem() 01254 { 01255 return (set_functionality_mode(FUNC_RESET)); 01256 } 01257 01258 bool UbloxCellularBase::set_functionality_mode(FunctionalityMode mode) 01259 { 01260 bool return_val = false; 01261 int at_timeout; 01262 LOCK(); 01263 01264 MBED_ASSERT(_at != NULL); 01265 01266 at_timeout = _at_timeout; // Has to be inside LOCK()s 01267 at_set_timeout(3*60*1000); //command has 3 minutes timeout 01268 01269 if (_at->send("AT+CFUN=%d", mode) && _at->recv("OK")) { 01270 return_val = true; 01271 } 01272 01273 if (mode == FUNC_RESET || mode == FUNC_RESET_WITH_SIM) { 01274 _modem_initialised = false; 01275 } 01276 01277 at_set_timeout(at_timeout); 01278 UNLOCK(); 01279 01280 return return_val; 01281 } 01282 01283 bool UbloxCellularBase::get_functionality_mode(int *mode) 01284 { 01285 bool return_val = false; 01286 01287 if (mode == NULL) { 01288 return false; 01289 } 01290 01291 LOCK(); 01292 MBED_ASSERT(_at != NULL); 01293 01294 if ( (_at->send("AT+CFUN?") && _at->recv("+CFUN: %d", mode) && _at->recv("OK")) ) { 01295 return_val = true; 01296 } 01297 01298 UNLOCK(); 01299 return return_val; 01300 } 01301 01302 #ifdef TARGET_UBLOX_C030_R41XM 01303 bool UbloxCellularBase::set_mno_profile(MNOProfile profile) 01304 { 01305 bool return_val = false; 01306 int current_profile; 01307 MNOProfile arr[MAX_NUM_PROFILES] = { SW_DEFAULT, SIM_ICCID, ATT, TMO, VODAFONE, DT, STANDARD_EU 01308 #ifdef TARGET_UBLOX_C030_R410M 01309 , VERIZON, TELSTRA, CT, SPRINT, TELUS 01310 #endif 01311 }; 01312 01313 if (is_registered_csd() || is_registered_psd() || is_registered_eps()) { 01314 tr_error("MNO profile should only be set in detached state"); 01315 return false; 01316 } 01317 01318 if (get_mno_profile(¤t_profile)) { 01319 if (current_profile == profile) { //Ref to UBX-18019856 7.1.7, parameters will be updated only if we switch to another profile first 01320 for (uint8_t index = 0; index < MAX_NUM_PROFILES; index++) { //get the index of current profile and use the next one 01321 if (arr[index] == current_profile) { 01322 index = ((index + 1) % MAX_NUM_PROFILES); 01323 current_profile = arr[index]; 01324 break; 01325 } 01326 } 01327 01328 LOCK(); 01329 if (_at->send("AT+UMNOPROF=%d", current_profile) && _at->recv("OK")) { 01330 tr_info("temporary MNO profile set: %d", current_profile); 01331 } 01332 UNLOCK(); 01333 } 01334 LOCK(); 01335 if (_at->send("AT+UMNOPROF=%d", profile) && _at->recv("OK")) { 01336 if (profile == SW_DEFAULT) { 01337 tr_critical("!!CANNOT USE PROFILE 0(SW_DEFAULT). PLEASE SET AN APPROPRIATE MNO PROFILE!!"); 01338 _default_profile_is_set = true; 01339 } else { 01340 _default_profile_is_set = false; 01341 } 01342 return_val = true; 01343 } else { 01344 tr_error("unable to set user specified profile"); 01345 } 01346 UNLOCK(); 01347 } else { 01348 tr_error("could not read MNO profile"); 01349 } 01350 01351 return return_val; 01352 } 01353 01354 bool UbloxCellularBase::get_mno_profile(int *profile) 01355 { 01356 bool return_val = false; 01357 char buf[4] = {0x00}; 01358 01359 if (profile == NULL) { 01360 return false; 01361 } 01362 01363 LOCK(); 01364 MBED_ASSERT(_at != NULL); 01365 01366 if (_at->send("AT+UMNOPROF?") && _at->recv("+UMNOPROF: %3[^\n]\nOK\n", buf)) { 01367 *profile = atoi(buf); 01368 return_val = true; 01369 } 01370 01371 UNLOCK(); 01372 return return_val; 01373 } 01374 // Enable or Disable the UPSV power saving mode 01375 bool UbloxCellularBase::set_idle_mode(bool enable) 01376 { 01377 #ifdef TARGET_UBLOX_C030_R412M 01378 if (_psm_status == ENABLED && enable == true) { 01379 return false; 01380 } 01381 #endif 01382 01383 bool success = false; 01384 LOCK(); 01385 01386 MBED_ASSERT(_at != NULL); 01387 01388 if (_at->send("AT+UPSV=%d", enable ? 4 : 0) && _at->recv("OK")) { 01389 if (enable == true) { 01390 _at->idle_mode_enabled(); 01391 } 01392 else { 01393 _at->idle_mode_disabled(); 01394 } 01395 success = true; 01396 } 01397 01398 UNLOCK(); 01399 return success; 01400 } 01401 01402 bool UbloxCellularBase::get_idle_mode(int *status) 01403 { 01404 bool return_val = false; 01405 01406 if (status == NULL) { 01407 return false; 01408 } 01409 01410 LOCK(); 01411 MBED_ASSERT(_at != NULL); 01412 01413 if ( (_at->send("AT+UPSV?") && _at->recv("+UPSV: %d", status) && _at->recv("OK")) ) { 01414 if (*status == 4) { 01415 *status = 1; 01416 } 01417 return_val = true; 01418 } 01419 01420 UNLOCK(); 01421 return return_val; 01422 } 01423 01424 int UbloxCellularBase::set_receive_period(int mode, tEDRXAccessTechnology act_type, uint8_t edrx_value) { 01425 char edrx[5]; 01426 uint_to_binary_str(edrx_value, edrx, 5, 4); 01427 edrx[4] = '\0'; 01428 int status = 1; 01429 01430 LOCK(); 01431 01432 if (_at->send("AT+CEDRXS=%d,%d,\"%s\"", mode, act_type, edrx) && _at->recv("OK")) { 01433 status = 0; 01434 } 01435 else { 01436 status = 1; 01437 } 01438 01439 01440 UNLOCK(); 01441 01442 return status; 01443 } 01444 01445 int UbloxCellularBase::set_receive_period(int mode, tEDRXAccessTechnology act_type) { 01446 int status = 1; 01447 01448 LOCK(); 01449 01450 if (_at->send("AT+CEDRXS=%d,%d", mode, act_type) && _at->recv("OK")) { 01451 01452 status = 0; 01453 } 01454 else { 01455 status = 1; 01456 } 01457 01458 UNLOCK(); 01459 01460 return status; 01461 } 01462 01463 int UbloxCellularBase::set_receive_period(int mode) { 01464 int status = 1; 01465 01466 LOCK(); 01467 01468 if (_at->send("AT+CEDRXS=%d", mode) && _at->recv("OK")) { 01469 01470 status = 0; 01471 } 01472 else { 01473 status = 1; 01474 } 01475 01476 UNLOCK(); 01477 01478 return status; 01479 } 01480 01481 uint32_t UbloxCellularBase::get_receive_period() { 01482 uint32_t edrx_value = 2; 01483 char buf[24] = {0x00}; 01484 char edrx_val[5]; 01485 tEDRXAccessTechnology act_type; 01486 01487 LOCK(); 01488 01489 if (_at->send("AT+CEDRXS?") && _at->recv("%23[^\n]\nOK\n", buf)) { 01490 if (sscanf(buf, "+CEDRXS: %d,\"%s\"", (int *)&act_type, edrx_val) == 2) { 01491 01492 edrx_value = binary_str_to_uint(edrx_val,4); 01493 } 01494 } 01495 01496 if (_at->send("AT+CEDRXRDP") && _at->recv("OK")) { 01497 } 01498 01499 tr_info("edrx_value. %d", edrx_value); 01500 01501 UNLOCK(); 01502 return edrx_value; 01503 } 01504 01505 void UbloxCellularBase::uint_to_binary_str(uint32_t num, char* str, int str_size, int bit_cnt) 01506 { 01507 if (!str || str_size < bit_cnt) { 01508 return; 01509 } 01510 int tmp, pos = 0; 01511 01512 for (int i = 31; i >= 0; i--) { 01513 tmp = num >> i; 01514 if (i < bit_cnt) { 01515 if (tmp&1) { 01516 str[pos] = 1 + '0'; 01517 } else { 01518 str[pos] = 0 + '0'; 01519 } 01520 pos++; 01521 } 01522 } 01523 } 01524 01525 uint32_t UbloxCellularBase::binary_str_to_uint(const char *binary_string, int binary_string_length) 01526 { 01527 if (!binary_string || !binary_string_length) { 01528 return 0; 01529 } 01530 01531 int integer_output = 0, base_exp = 1; 01532 01533 for (int i = binary_string_length - 1; i >= 0; i--) { 01534 if (binary_string[i] == '1') { 01535 integer_output += (base_exp << (binary_string_length - (i+1))); 01536 } 01537 } 01538 01539 return integer_output; 01540 } 01541 01542 bool UbloxCellularBase::set_band_bitmask(RAT rat, uint64_t bitmask) { 01543 01544 if (_default_profile_is_set == true) { 01545 tr_critical("!!CANNOT USE PROFILE 0(SW_DEFAULT). PLEASE SET AN APPROPRIATE MNO PROFILE!!"); 01546 return false; 01547 } 01548 01549 bool status = false; 01550 UBandmaskRAT eBandMastRat; 01551 01552 if(rat == LTE_CATM1) { 01553 eBandMastRat = UBANDMASK_RAT_LTE_CATM1; 01554 } 01555 else if(rat == LTE_CATNB1) { 01556 eBandMastRat = UBANDMASK_RAT_LTE_CATNB1; 01557 } 01558 else { 01559 tr_error("Invalid RAT for Band mask selection: %d", rat); 01560 01561 return false; 01562 } 01563 01564 tr_info("UBANDMASK RAT %d, bitmask : %llu", eBandMastRat, bitmask); 01565 01566 LOCK(); 01567 01568 if (_at->send("AT+UBANDMASK=%d,%llu", eBandMastRat, bitmask) && _at->recv("OK")) { 01569 01570 status = true; 01571 } 01572 UNLOCK(); 01573 01574 return status; 01575 } 01576 bool UbloxCellularBase::get_band_bitmask(uint64_t *m1_bitmask, uint64_t *nb1_bitmask) 01577 { 01578 if (_default_profile_is_set == true) { 01579 tr_critical("!!CANNOT USE PROFILE 0(SW_DEFAULT). PLEASE SET AN APPROPRIATE MNO PROFILE!!"); 01580 return false; 01581 } 01582 01583 bool status = false; 01584 int eBandMastRat0, eBandMastRat1; 01585 01586 LOCK(); 01587 01588 if(_at->send("AT+UBANDMASK?") && _at->recv("+UBANDMASK: %d,%llu,%d,%llu", &eBandMastRat0, m1_bitmask, &eBandMastRat1, nb1_bitmask) && _at->recv("OK")) { 01589 01590 status = true; 01591 } 01592 UNLOCK(); 01593 01594 return status; 01595 } 01596 01597 bool UbloxCellularBase::disable_psm() 01598 { 01599 bool return_value = false; 01600 01601 LOCK(); 01602 if (_at->send("AT+CPSMS=0") && _at->recv("OK")) { 01603 return_value = true; 01604 } 01605 UNLOCK(); 01606 01607 return return_value; 01608 } 01609 #endif //TARGET_UBLOX_C030_R41XM 01610 01611 01612 #ifdef TARGET_UBLOX_C030_R412M 01613 bool UbloxCellularBase::get_power_saving_mode(int *status, int *periodic_time, int *active_time) 01614 { 01615 char pt_encoded[8+1];// timer value encoded as 3GPP IE 01616 char at_encoded[8+1];// timer value encoded as 3GPP IE 01617 int value, multiplier; 01618 bool return_val; 01619 01620 if (status == NULL || periodic_time == NULL || active_time == NULL) { 01621 return false; 01622 } 01623 01624 LOCK(); 01625 //+UCPSMS:1,,,"01000011","01000011" 01626 if (_at->send("AT+UCPSMS?") && _at->recv("+UCPSMS:%d,,,\"%8c\",\"%8c\"\nOK\n", status, pt_encoded, at_encoded)) { 01627 if (*status == true) { 01628 //PSM is enabled, decode the timer values, periodic TAU first 01629 value = (pt_encoded[7]- '0'); 01630 value += (pt_encoded[6]- '0') << 1; 01631 value += (pt_encoded[5]- '0') << 2; 01632 value += (pt_encoded[4]- '0') << 3; 01633 value += (pt_encoded[3]- '0') << 4; 01634 01635 multiplier = (pt_encoded[2]- '0'); 01636 multiplier += (pt_encoded[1]- '0') << 1; 01637 multiplier += (pt_encoded[0]- '0') << 2; 01638 01639 switch(multiplier) { 01640 //10 minutes 01641 case 0: 01642 value = value*10*60; 01643 break; 01644 01645 //1 hour 01646 case 1: 01647 value = value*60*60; 01648 break; 01649 01650 //10 hours 01651 case 2: 01652 value = value*10*60*60; 01653 break; 01654 01655 //2 seconds 01656 case 3: 01657 value = value*2; 01658 break; 01659 01660 //30 seconds 01661 case 4: 01662 value = value*30; 01663 break; 01664 01665 //1 minute 01666 case 5: 01667 value = value*60; 01668 break; 01669 01670 //320 hours 01671 case 6: 01672 value = value*320*60*60; 01673 break; 01674 01675 default: 01676 value = 0; 01677 break; 01678 } 01679 *periodic_time = value; 01680 01681 //decode the active time 01682 value = (at_encoded[7]- '0'); 01683 value += (at_encoded[6]- '0') << 1; 01684 value += (at_encoded[5]- '0') << 2; 01685 value += (at_encoded[4]- '0') << 3; 01686 value += (at_encoded[3]- '0') << 4; 01687 01688 multiplier = (at_encoded[2]- '0'); 01689 multiplier += (at_encoded[1]- '0') << 1; 01690 multiplier += (at_encoded[0]- '0') << 2; 01691 01692 switch(multiplier) { 01693 //2 seconds 01694 case 0: 01695 value = value*2; 01696 break; 01697 01698 //1 minute 01699 case 1: 01700 value = value*60; 01701 break; 01702 01703 //decihours (6minutes) 01704 case 2: 01705 value = value*6*60; 01706 break; 01707 01708 default: 01709 value = 0; 01710 break; 01711 } 01712 *active_time = value; 01713 } 01714 return_val = true; 01715 } else { 01716 return_val = false; 01717 } 01718 UNLOCK(); 01719 return return_val; 01720 } 01721 01722 bool UbloxCellularBase::set_power_saving_mode(int periodic_time, int active_time) 01723 { 01724 01725 if (_at->is_idle_mode_enabled() == true && periodic_time != 0 && active_time != 0 ) { 01726 return false; 01727 } 01728 bool return_val = false; 01729 01730 LOCK(); 01731 int at_timeout = _at_timeout; 01732 at_set_timeout(10000); //AT+CPSMS has response time of < 10s 01733 01734 if (periodic_time == 0 && active_time == 0) { 01735 // disable PSM 01736 if (_at->send("AT+CPSMS=0") && _at->recv("OK")) { 01737 set_psm_urcs(false); //disable the URC 01738 _psm_status = DISABLED; 01739 return_val = true; 01740 } 01741 } else if (_at->send("AT+UPSMR?") && _at->recv("OK")) { //PSM string encoding code borrowed from AT_CellularPower.cpp 01742 /** 01743 Table 10.5.163a/3GPP TS 24.008: GPRS Timer 3 information element 01744 01745 Bits 5 to 1 represent the binary coded timer value. 01746 01747 Bits 6 to 8 defines the timer value unit for the GPRS timer as follows: 01748 8 7 6 01749 0 0 0 value is incremented in multiples of 10 minutes 01750 0 0 1 value is incremented in multiples of 1 hour 01751 0 1 0 value is incremented in multiples of 10 hours 01752 0 1 1 value is incremented in multiples of 2 seconds 01753 1 0 0 value is incremented in multiples of 30 seconds 01754 1 0 1 value is incremented in multiples of 1 minute 01755 1 1 0 value is incremented in multiples of 320 hours (NOTE 1) 01756 1 1 1 value indicates that the timer is deactivated (NOTE 2). 01757 */ 01758 char pt[8+1];// timer value encoded as 3GPP IE 01759 const int ie_value_max = 0x1f; 01760 uint32_t periodic_timer = 0; 01761 if (periodic_time <= 2*ie_value_max) { // multiples of 2 seconds 01762 periodic_timer = periodic_time/2; 01763 strcpy(pt, "01100000"); 01764 } else { 01765 if (periodic_time <= 30*ie_value_max) { // multiples of 30 seconds 01766 periodic_timer = periodic_time/30; 01767 strcpy(pt, "10000000"); 01768 } else { 01769 if (periodic_time <= 60*ie_value_max) { // multiples of 1 minute 01770 periodic_timer = periodic_time/60; 01771 strcpy(pt, "10100000"); 01772 } else { 01773 if (periodic_time <= 10*60*ie_value_max) { // multiples of 10 minutes 01774 periodic_timer = periodic_time/(10*60); 01775 strcpy(pt, "00000000"); 01776 } else { 01777 if (periodic_time <= 60*60*ie_value_max) { // multiples of 1 hour 01778 periodic_timer = periodic_time/(60*60); 01779 strcpy(pt, "00100000"); 01780 } else { 01781 if (periodic_time <= 10*60*60*ie_value_max) { // multiples of 10 hours 01782 periodic_timer = periodic_time/(10*60*60); 01783 strcpy(pt, "01000000"); 01784 } else { // multiples of 320 hours 01785 int t = periodic_time / (320*60*60); 01786 if (t > ie_value_max) { 01787 t = ie_value_max; 01788 } 01789 periodic_timer = t; 01790 strcpy(pt, "11000000"); 01791 } 01792 } 01793 } 01794 } 01795 } 01796 } 01797 01798 uint_to_binary_str(periodic_timer, &pt[3], sizeof(pt)-3, 5); 01799 pt[8] = '\0'; 01800 01801 /** 01802 Table 10.5.172/3GPP TS 24.008: GPRS Timer information element 01803 01804 Bits 5 to 1 represent the binary coded timer value. 01805 01806 Bits 6 to 8 defines the timer value unit for the GPRS timer as follows: 01807 01808 8 7 6 01809 0 0 0 value is incremented in multiples of 2 seconds 01810 0 0 1 value is incremented in multiples of 1 minute 01811 0 1 0 value is incremented in multiples of decihours 01812 1 1 1 value indicates that the timer is deactivated. 01813 01814 Other values shall be interpreted as multiples of 1 minute in this version of the protocol. 01815 */ 01816 char at[8+1]; 01817 uint32_t active_timer; // timer value encoded as 3GPP IE 01818 if (active_time <= 2*ie_value_max) { // multiples of 2 seconds 01819 active_timer = active_time/2; 01820 strcpy(at, "00000000"); 01821 } else { 01822 if (active_time <= 60*ie_value_max) { // multiples of 1 minute 01823 active_timer = (1<<5) | (active_time/60); 01824 strcpy(at, "00100000"); 01825 } else { // multiples of decihours 01826 int t = active_time / (6*60); 01827 if (t > ie_value_max) { 01828 t = ie_value_max; 01829 } 01830 active_timer = t; 01831 strcpy(at, "01000000"); 01832 } 01833 } 01834 01835 uint_to_binary_str(active_timer, &at[3], sizeof(at)-3, 5); 01836 at[8] = '\0'; 01837 01838 if (_at->send("AT+CPSMS=1,,,\"%s\",\"%s\"", pt, at) && _at->recv("OK")) { 01839 if (set_psm_urcs(true)) {//enable the PSM URC 01840 tr_info("PSM enabled successfully!"); 01841 _psm_status = ENABLED; 01842 return_val = true; 01843 } else { 01844 tr_error("Error enabling PSM URCs, PSM not enabled"); 01845 _at->send("AT+CPSMS=0"); 01846 _at->recv("OK"); 01847 return_val = false; 01848 } 01849 } else { 01850 tr_error("+CPSMS command failed"); 01851 return_val = false; 01852 } 01853 } else { 01854 tr_error("PSM URCs not supported by this version of modem"); 01855 } 01856 01857 at_set_timeout(at_timeout); 01858 UNLOCK(); 01859 return return_val; 01860 } 01861 01862 bool UbloxCellularBase::is_modem_awake() 01863 { 01864 return (_dev_info.modem_psm_state == AWAKE); 01865 } 01866 01867 //application should call init() or connect() in order to initialize the modem 01868 void UbloxCellularBase::wakeup_modem() 01869 { 01870 LOCK(); 01871 01872 MBED_ASSERT(_at != NULL); 01873 01874 tr_info("Waking up modem..."); 01875 01876 modem_power_up(); 01877 01878 _dev_info.reg_status_csd = CSD_NOT_REGISTERED_NOT_SEARCHING; 01879 _dev_info.reg_status_psd = PSD_NOT_REGISTERED_NOT_SEARCHING; 01880 _dev_info.reg_status_eps = EPS_NOT_REGISTERED_NOT_SEARCHING; 01881 _modem_initialised = false; 01882 01883 UNLOCK(); 01884 } 01885 01886 bool UbloxCellularBase::set_psm_urcs(bool enable) 01887 { 01888 01889 bool success = false; 01890 LOCK(); 01891 01892 MBED_ASSERT(_at != NULL); 01893 01894 if (_at->send("AT+UPSMR=%d", enable ? 1 : 0) && _at->recv("OK")) { 01895 success = true; 01896 } 01897 01898 UNLOCK(); 01899 return success; 01900 } 01901 #endif 01902 01903 // End of File 01904
Generated on Thu Jul 14 2022 11:15:18 by
1.7.2