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