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) 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 int mno_profile; 00820 00821 #ifdef TARGET_UBLOX_C030_R412M 00822 if (_psm_status == false) { //psm is not enabled by application yet so disable it at start-up 00823 set_power_saving_mode(0, 0); 00824 } 00825 #endif 00826 #ifdef TARGET_UBLOX_C030_R41XM 00827 if (_at->is_idle_mode_enabled() == false) { 00828 set_idle_mode(false); //disable idle mode at start up 00829 } 00830 if(_edrx_configured == false) { 00831 // A special form of the command can be given as +CEDRXS=3. 00832 // In this form, eDRX will be disabled and data for all parameters in the command +CEDRXS will be removed or, 00833 // if available, set to the manufacturer specific default values. 00834 set_receive_period(3,UbloxCellularBase::EDRXGSM_A_Gb_mode); 00835 set_receive_period(3,UbloxCellularBase::EDRXEUTRAN_WB_S1_mode); 00836 set_receive_period(3,UbloxCellularBase::EDRXEUTRAN_NB_S1_mode); 00837 } 00838 get_receive_period(); 00839 00840 if (get_mno_profile(&mno_profile)) 00841 tr_info("Current MNO profile is: %d", mno_profile); 00842 #endif 00843 if (set_device_identity(&_dev_info.dev) && // Set up device identity 00844 device_init(_dev_info.dev)) {// Initialise this device 00845 // Get the integrated circuit ID of the SIM 00846 if (get_iccid()) { 00847 // Try a few times to get the IMSI (since on some modems this can 00848 // take a while to be retrieved, especially if a SIM PIN 00849 // was set) 00850 for (x = 0; (x < 3) && !get_imsi(); x++) { 00851 wait_ms(1000); 00852 } 00853 00854 if (x < 3) { // If we got the IMSI, can get the others 00855 if (get_imei() && // Get international mobile equipment identifier 00856 get_meid() && // Probably the same as the IMEI 00857 set_sms()) { // And set up SMS 00858 // The modem is initialised. 00859 _modem_initialised = true; 00860 tr_info("Modem initialized"); 00861 } 00862 } 00863 } 00864 } 00865 } 00866 } 00867 } 00868 } 00869 00870 return _modem_initialised; 00871 } 00872 00873 // Perform registration. 00874 bool UbloxCellularBase::nwk_registration() 00875 { 00876 bool atSuccess = false; 00877 bool registered = false; 00878 int status; 00879 int at_timeout; 00880 LOCK(); 00881 00882 at_timeout = _at_timeout; // Has to be inside LOCK()s 00883 00884 MBED_ASSERT(_at != NULL); 00885 00886 if (!is_registered_psd() && !is_registered_csd() && !is_registered_eps()) { 00887 if (set_functionality_mode(FUNC_FULL)) { 00888 tr_info("Searching Network..."); 00889 // Enable the packet switched and network registration unsolicited result codes 00890 if (_at->send("AT+CREG=1") && _at->recv("OK") && 00891 _at->send("AT+CGREG=1") && _at->recv("OK")) { 00892 atSuccess = true; 00893 if (_at->send("AT+CEREG=1")) { 00894 _at->recv("OK"); 00895 // Don't check return value as this works for LTE only 00896 } 00897 00898 if (atSuccess) { 00899 // See if we are already in automatic mode 00900 if (_at->send("AT+COPS?") && _at->recv("+COPS: %d", &status) && 00901 _at->recv("OK")) { 00902 // If not, set it 00903 if (status != 0) { 00904 // Don't check return code here as there's not much 00905 // we can do if this fails. 00906 _at->send("AT+COPS=0") && _at->recv("OK"); 00907 } 00908 } 00909 00910 // Query the registration status directly as well, 00911 // just in case 00912 if (_at->send("AT+CREG?") && _at->recv("OK")) { 00913 // Answer will be processed by URC 00914 } 00915 if (_at->send("AT+CGREG?") && _at->recv("OK")) { 00916 // Answer will be processed by URC 00917 } 00918 if (_at->send("AT+CEREG?")) { 00919 _at->recv("OK"); 00920 // Don't check return value as this works for LTE only 00921 } 00922 } 00923 } 00924 // Wait for registration to succeed 00925 at_set_timeout(1000); 00926 for (int waitSeconds = 0; !registered && (waitSeconds < 180); waitSeconds++) { 00927 registered = is_registered_psd() || is_registered_csd() || is_registered_eps(); 00928 _at->recv(UNNATURAL_STRING); 00929 } 00930 at_set_timeout(at_timeout); 00931 00932 if (registered) { 00933 // This should return quickly but sometimes the status field is not returned 00934 // so make the timeout short 00935 at_set_timeout(1000); 00936 if (_at->send("AT+COPS?") && _at->recv("+COPS: %*d,%*d,\"%*[^\"]\",%d\n", &status)) { 00937 set_rat(status); 00938 } 00939 at_set_timeout(at_timeout); 00940 } 00941 } 00942 } else { 00943 registered = true; 00944 } 00945 00946 UNLOCK(); 00947 return registered; 00948 } 00949 00950 bool UbloxCellularBase::is_registered_csd() 00951 { 00952 return (_dev_info.reg_status_csd == CSD_REGISTERED) || 00953 (_dev_info.reg_status_csd == CSD_REGISTERED_ROAMING) || 00954 (_dev_info.reg_status_csd == CSD_CSFB_NOT_PREFERRED); 00955 } 00956 00957 bool UbloxCellularBase::is_registered_psd() 00958 { 00959 return (_dev_info.reg_status_psd == PSD_REGISTERED) || 00960 (_dev_info.reg_status_psd == PSD_REGISTERED_ROAMING); 00961 } 00962 00963 bool UbloxCellularBase::is_registered_eps() 00964 { 00965 return (_dev_info.reg_status_eps == EPS_REGISTERED) || 00966 (_dev_info.reg_status_eps == EPS_REGISTERED_ROAMING); 00967 } 00968 00969 // Perform deregistration. 00970 bool UbloxCellularBase::nwk_deregistration() 00971 { 00972 bool success = false; 00973 LOCK(); 00974 00975 MBED_ASSERT(_at != NULL); 00976 00977 at_set_timeout(3*60*1000); //command has 3 minutes timeout 00978 00979 if (_at->send("AT+COPS=2") && _at->recv("OK")) { 00980 _dev_info.reg_status_csd = CSD_NOT_REGISTERED_NOT_SEARCHING; 00981 _dev_info.reg_status_psd = PSD_NOT_REGISTERED_NOT_SEARCHING; 00982 _dev_info.reg_status_eps = EPS_NOT_REGISTERED_NOT_SEARCHING; 00983 success = true; 00984 } 00985 00986 UNLOCK(); 00987 return success; 00988 } 00989 00990 // Put the modem into its lowest power state. 00991 void UbloxCellularBase::deinit() 00992 { 00993 power_down(); 00994 _modem_initialised = false; 00995 } 00996 00997 // Set the PIN. 00998 void UbloxCellularBase::set_pin(const char *pin) { 00999 _pin = pin; 01000 } 01001 01002 // Enable or disable SIM pin checking. 01003 bool UbloxCellularBase::sim_pin_check_enable(bool enableNotDisable) 01004 { 01005 bool success = false;; 01006 LOCK(); 01007 01008 MBED_ASSERT(_at != NULL); 01009 01010 if (_pin != NULL) { 01011 if (_sim_pin_check_enabled && !enableNotDisable) { 01012 // Disable the SIM lock 01013 if (_at->send("AT+CLCK=\"SC\",0,\"%s\"", _pin) && _at->recv("OK")) { 01014 _sim_pin_check_enabled = false; 01015 success = true; 01016 } 01017 } else if (!_sim_pin_check_enabled && enableNotDisable) { 01018 // Enable the SIM lock 01019 if (_at->send("AT+CLCK=\"SC\",1,\"%s\"", _pin) && _at->recv("OK")) { 01020 _sim_pin_check_enabled = true; 01021 success = true; 01022 } 01023 } else { 01024 success = true; 01025 } 01026 } 01027 01028 UNLOCK(); 01029 return success; 01030 } 01031 01032 // Change the pin code for the SIM card. 01033 bool UbloxCellularBase::change_sim_pin(const char *pin) 01034 { 01035 bool success = false;; 01036 LOCK(); 01037 01038 MBED_ASSERT(_at != NULL); 01039 01040 // Change the SIM pin 01041 if ((pin != NULL) && (_pin != NULL)) { 01042 if (_at->send("AT+CPWD=\"SC\",\"%s\",\"%s\"", _pin, pin) && _at->recv("OK")) { 01043 _pin = pin; 01044 success = true; 01045 } 01046 } 01047 01048 UNLOCK(); 01049 return success; 01050 } 01051 01052 // Get the IMEI. 01053 bool UbloxCellularBase::get_imei(char *imei_to_send, int size) 01054 { 01055 bool success; 01056 LOCK(); 01057 01058 MBED_ASSERT(_at != NULL); 01059 01060 // International mobile equipment identifier 01061 // AT Command Manual UBX-13002752, section 4.7 01062 success = _at->send("AT+CGSN") && _at->recv("%15[^\n]\nOK\n", _dev_info.imei); 01063 tr_info("DevInfo: IMEI=%s", _dev_info.imei); 01064 01065 if (success) { 01066 memcpy(imei_to_send,_dev_info.imei,size); 01067 imei_to_send[size-1] = '\0'; 01068 } 01069 01070 UNLOCK(); 01071 return success; 01072 } 01073 01074 // Get the IMEI of the module. 01075 const char *UbloxCellularBase::imei() 01076 { 01077 return _dev_info.imei; 01078 } 01079 01080 // Get the Mobile Equipment ID (which may be the same as the IMEI). 01081 const char *UbloxCellularBase::meid() 01082 { 01083 return _dev_info.meid; 01084 } 01085 01086 // Get the IMSI of the SIM. 01087 const char *UbloxCellularBase::imsi() 01088 { 01089 // (try) to update the IMSI, just in case the SIM has changed 01090 get_imsi(); 01091 01092 return _dev_info.imsi; 01093 } 01094 01095 // Get the ICCID of the SIM. 01096 const char *UbloxCellularBase::iccid() 01097 { 01098 // (try) to update the ICCID, just in case the SIM has changed 01099 get_iccid(); 01100 01101 return _dev_info.iccid; 01102 } 01103 01104 // Get the RSSI in dBm. 01105 int UbloxCellularBase::rssi() 01106 { 01107 char buf[7] = {0}; 01108 int rssi = 0; 01109 int qual = 0; 01110 int rssiRet = 0; 01111 bool success; 01112 LOCK(); 01113 01114 MBED_ASSERT(_at != NULL); 01115 01116 success = _at->send("AT+CSQ") && _at->recv("+CSQ: %6[^\n]\nOK\n", buf); 01117 01118 if (success) { 01119 if (sscanf(buf, "%d,%d", &rssi, &qual) == 2) { 01120 // AT+CSQ returns a coded RSSI value and an RxQual value 01121 // For 2G an RSSI of 0 corresponds to -113 dBm or less, 01122 // an RSSI of 31 corresponds to -51 dBm or less and hence 01123 // each value is a 2 dB step. 01124 // For LTE the mapping is defined in the array rssiConvertLte[]. 01125 // For 3G the mapping to RSCP is defined in the array rscpConvert3G[] 01126 // and the RSSI value is then RSCP - the EC_NO_LEV number derived 01127 // by putting the qual number through qualConvert3G[]. 01128 if ((rssi >= 0) && (rssi <= 31)) { 01129 switch (_dev_info.rat) { 01130 case UTRAN: 01131 case HSDPA: 01132 case HSUPA: 01133 case HSDPA_HSUPA: 01134 // 3G 01135 if ((qual >= 0) && (qual <= 7)) { 01136 qual = qualConvert3G[qual]; 01137 rssiRet = rscpConvert3G[rssi]; 01138 rssiRet -= qual; 01139 } 01140 01141 break; 01142 case LTE: 01143 // LTE 01144 rssiRet = rssiConvertLte[rssi]; 01145 break; 01146 case GSM: 01147 case COMPACT_GSM: 01148 case EDGE: 01149 default: 01150 // GSM or assumed GSM if the RAT is not known 01151 rssiRet = -(113 - (rssi << 2)); 01152 break; 01153 } 01154 } 01155 } 01156 } 01157 01158 UNLOCK(); 01159 return rssiRet; 01160 } 01161 01162 //RAT should be set in a detached state (AT+COPS=2) 01163 bool UbloxCellularBase::set_modem_rat(RAT selected_rat, RAT preferred_rat, RAT second_preferred_rat) 01164 { 01165 bool success = false; 01166 char command[16] = {0x00}; 01167 01168 //check if modem is registered with network 01169 if (is_registered_csd() || is_registered_psd() || is_registered_eps()) { 01170 tr_error("RAT should only be set in detached state"); 01171 return false; 01172 } 01173 01174 if (preferred_rat != NOT_USED && second_preferred_rat != NOT_USED) { 01175 sprintf(command, "AT+URAT=%d,%d,%d", selected_rat, preferred_rat, second_preferred_rat); 01176 } else if (preferred_rat != NOT_USED) { 01177 sprintf(command, "AT+URAT=%d,%d", selected_rat, preferred_rat); 01178 } else if (second_preferred_rat != NOT_USED) { 01179 sprintf(command, "AT+URAT=%d,%d", selected_rat, second_preferred_rat); 01180 } else { 01181 sprintf(command, "AT+URAT=%d", selected_rat); 01182 } 01183 01184 LOCK(); 01185 if (_at->send(command) && _at->recv("OK")) { 01186 success = true; 01187 } else { 01188 tr_error("unable to set the specified RAT"); 01189 success = false; 01190 } 01191 UNLOCK(); 01192 01193 return success; 01194 } 01195 01196 bool UbloxCellularBase::get_modem_rat(int *selected_rat, int *preferred_rat, int *second_preferred_rat) 01197 { 01198 bool success = false; 01199 char buf[24] = {0x00}; 01200 01201 if (selected_rat == NULL || preferred_rat == NULL || second_preferred_rat == NULL) { 01202 tr_info("invalid pointers"); 01203 return false; 01204 } 01205 01206 MBED_ASSERT(_at != NULL); 01207 01208 *selected_rat = NOT_USED; 01209 *preferred_rat = NOT_USED; 01210 *second_preferred_rat = NOT_USED; 01211 01212 LOCK(); 01213 01214 if (_at->send("AT+URAT?") && _at->recv("%23[^\n]\nOK\n", buf)) { 01215 if (sscanf(buf, "+URAT: %d,%d,%d", selected_rat, preferred_rat, second_preferred_rat) == 3) { 01216 success = true; 01217 } else if (sscanf(buf, "+URAT: %d,%d", selected_rat, preferred_rat) == 2) { 01218 success = true; 01219 } else if (sscanf(buf, "+URAT: %d", selected_rat) == 1) { 01220 success = true; 01221 } 01222 } 01223 01224 UNLOCK(); 01225 return success; 01226 } 01227 01228 //application should call init() or connect() in order to initialize the modem 01229 bool UbloxCellularBase::reboot_modem() 01230 { 01231 return (set_functionality_mode(FUNC_RESET)); 01232 } 01233 01234 bool UbloxCellularBase::set_functionality_mode(FunctionalityMode mode) 01235 { 01236 bool return_val = false; 01237 int at_timeout; 01238 LOCK(); 01239 01240 MBED_ASSERT(_at != NULL); 01241 01242 at_timeout = _at_timeout; // Has to be inside LOCK()s 01243 at_set_timeout(3*60*1000); //command has 3 minutes timeout 01244 01245 if (_at->send("AT+CFUN=%d", mode) && _at->recv("OK")) { 01246 return_val = true; 01247 } 01248 01249 if (mode == FUNC_RESET || mode == FUNC_RESET_WITH_SIM) { 01250 _modem_initialised = false; 01251 } 01252 01253 at_set_timeout(at_timeout); 01254 UNLOCK(); 01255 01256 return return_val; 01257 } 01258 01259 bool UbloxCellularBase::get_functionality_mode(int *mode) 01260 { 01261 bool return_val = false; 01262 01263 if (mode == NULL) { 01264 return false; 01265 } 01266 01267 LOCK(); 01268 MBED_ASSERT(_at != NULL); 01269 01270 if ( (_at->send("AT+CFUN?") && _at->recv("+CFUN: %d", mode) && _at->recv("OK")) ) { 01271 return_val = true; 01272 } 01273 01274 UNLOCK(); 01275 return return_val; 01276 } 01277 01278 #ifdef TARGET_UBLOX_C030_R41XM 01279 bool UbloxCellularBase::set_mno_profile(MNOProfile profile) 01280 { 01281 bool return_val = false; 01282 01283 int mno_profile; 01284 if (get_mno_profile(&mno_profile)) { 01285 tr_info("Current MNO profile is: %d", mno_profile); 01286 if (mno_profile != profile) { 01287 01288 if (is_registered_csd() || is_registered_psd() || is_registered_eps()) { 01289 tr_error("MNO profile should only be set in detached state"); 01290 return false; 01291 } 01292 01293 LOCK(); 01294 if (_at->send("AT+UMNOPROF=%d", profile) && _at->recv("OK")) { 01295 return_val = true; 01296 } else { 01297 tr_error("unable to set specified profile"); 01298 } 01299 UNLOCK(); 01300 01301 } else { 01302 return_val = true; 01303 } 01304 } else { 01305 tr_error("could not read MNO profile"); 01306 } 01307 01308 return return_val; 01309 } 01310 01311 bool UbloxCellularBase::get_mno_profile(int *profile) 01312 { 01313 bool return_val = false; 01314 01315 if (profile == NULL) { 01316 return false; 01317 } 01318 01319 LOCK(); 01320 MBED_ASSERT(_at != NULL); 01321 01322 if ( (_at->send("AT+UMNOPROF?") && _at->recv("+UMNOPROF: %d", profile) && _at->recv("OK")) ) { 01323 return_val = true; 01324 } 01325 01326 UNLOCK(); 01327 return return_val; 01328 } 01329 // Enable or Disable the UPSV power saving mode 01330 bool UbloxCellularBase::set_idle_mode(bool enable) 01331 { 01332 #ifdef TARGET_UBLOX_C030_R412M 01333 if (_psm_status == true && enable == true) { 01334 return false; 01335 } 01336 #endif 01337 01338 bool success = false; 01339 LOCK(); 01340 01341 MBED_ASSERT(_at != NULL); 01342 01343 if (_at->send("AT+UPSV=%d", enable ? 4 : 0) && _at->recv("OK")) { 01344 if (enable == true) { 01345 _at->idle_mode_enabled(); 01346 } 01347 else { 01348 _at->idle_mode_disabled(); 01349 } 01350 success = true; 01351 } 01352 01353 UNLOCK(); 01354 return success; 01355 } 01356 01357 bool UbloxCellularBase::get_idle_mode(int *status) 01358 { 01359 bool return_val = false; 01360 01361 if (status == NULL) { 01362 return false; 01363 } 01364 01365 LOCK(); 01366 MBED_ASSERT(_at != NULL); 01367 01368 if ( (_at->send("AT+UPSV?") && _at->recv("+UPSV: %d", status) && _at->recv("OK")) ) { 01369 if (*status == 4) { 01370 *status = 1; 01371 } 01372 return_val = true; 01373 } 01374 01375 UNLOCK(); 01376 return return_val; 01377 } 01378 #endif 01379 01380 #ifdef TARGET_UBLOX_C030_R412M 01381 bool UbloxCellularBase::get_power_saving_mode(int *status, int *periodic_time, int *active_time) 01382 { 01383 char pt_encoded[8+1];// timer value encoded as 3GPP IE 01384 char at_encoded[8+1];// timer value encoded as 3GPP IE 01385 int value, multiplier; 01386 bool return_val; 01387 01388 if (status == NULL || periodic_time == NULL || active_time == NULL) { 01389 return false; 01390 } 01391 01392 LOCK(); 01393 //+UCPSMS:1,,,"01000011","01000011" 01394 if (_at->send("AT+UCPSMS?") && _at->recv("+UCPSMS:%d,,,\"%8c\",\"%8c\"\n", status, pt_encoded, at_encoded)) { 01395 if (*status == true) { 01396 //PSM is enabled, decode the timer values, periodic TAU first 01397 value = (pt_encoded[7]- '0'); 01398 value += (pt_encoded[6]- '0') << 1; 01399 value += (pt_encoded[5]- '0') << 2; 01400 value += (pt_encoded[4]- '0') << 3; 01401 value += (pt_encoded[3]- '0') << 4; 01402 01403 multiplier = (pt_encoded[2]- '0'); 01404 multiplier += (pt_encoded[1]- '0') << 1; 01405 multiplier += (pt_encoded[0]- '0') << 2; 01406 01407 switch(multiplier) { 01408 //10 minutes 01409 case 0: 01410 value = value*10*60; 01411 break; 01412 01413 //1 hour 01414 case 1: 01415 value = value*60*60; 01416 break; 01417 01418 //10 hours 01419 case 2: 01420 value = value*10*60*60; 01421 break; 01422 01423 //2 seconds 01424 case 3: 01425 value = value*2; 01426 break; 01427 01428 //30 seconds 01429 case 4: 01430 value = value*30; 01431 break; 01432 01433 //1 minute 01434 case 5: 01435 value = value*60; 01436 break; 01437 01438 //320 hours 01439 case 6: 01440 value = value*320*60*60; 01441 break; 01442 01443 default: 01444 value = 0; 01445 break; 01446 } 01447 *periodic_time = value; 01448 01449 //decode the active time 01450 value = (at_encoded[7]- '0'); 01451 value += (at_encoded[6]- '0') << 1; 01452 value += (at_encoded[5]- '0') << 2; 01453 value += (at_encoded[4]- '0') << 3; 01454 value += (at_encoded[3]- '0') << 4; 01455 01456 multiplier = (at_encoded[2]- '0'); 01457 multiplier += (at_encoded[1]- '0') << 1; 01458 multiplier += (at_encoded[0]- '0') << 2; 01459 01460 switch(multiplier) { 01461 //2 seconds 01462 case 0: 01463 value = value*2; 01464 break; 01465 01466 //1 minute 01467 case 1: 01468 value = value*60; 01469 break; 01470 01471 //decihours (6minutes) 01472 case 2: 01473 value = value*6*60; 01474 break; 01475 01476 default: 01477 value = 0; 01478 break; 01479 } 01480 *active_time = value; 01481 } 01482 return_val = true; 01483 } else { 01484 return_val = false; 01485 } 01486 UNLOCK(); 01487 return return_val; 01488 } 01489 01490 bool UbloxCellularBase::set_power_saving_mode(int periodic_time, int active_time) 01491 { 01492 if (_at->is_idle_mode_enabled() == true && periodic_time != 0 && active_time != 0 ) { 01493 return false; 01494 } 01495 bool return_val = false; 01496 01497 LOCK(); 01498 int at_timeout = _at_timeout; 01499 at_set_timeout(10000); //AT+CPSMS has response time of < 10s 01500 01501 //check if modem supports PSM URCs 01502 if (_at->send("AT+UPSMR?") && _at->recv("OK")) { 01503 if (periodic_time == 0 && active_time == 0) { 01504 // disable PSM 01505 if (_at->send("AT+CPSMS=0") && _at->recv("OK")) { 01506 if (_at->send("AT+UPSMR=0") && _at->recv("OK")) {//disable the URC 01507 //de-register the callback 01508 detach_cb_psm_going_in(); 01509 detach_cb_psm_coming_out(); 01510 _psm_status = false; 01511 return_val = true; 01512 } 01513 } 01514 } else { //PSM string encoding code borrowed from AT_CellularPower.cpp 01515 /** 01516 Table 10.5.163a/3GPP TS 24.008: GPRS Timer 3 information element 01517 01518 Bits 5 to 1 represent the binary coded timer value. 01519 01520 Bits 6 to 8 defines the timer value unit for the GPRS timer as follows: 01521 8 7 6 01522 0 0 0 value is incremented in multiples of 10 minutes 01523 0 0 1 value is incremented in multiples of 1 hour 01524 0 1 0 value is incremented in multiples of 10 hours 01525 0 1 1 value is incremented in multiples of 2 seconds 01526 1 0 0 value is incremented in multiples of 30 seconds 01527 1 0 1 value is incremented in multiples of 1 minute 01528 1 1 0 value is incremented in multiples of 320 hours (NOTE 1) 01529 1 1 1 value indicates that the timer is deactivated (NOTE 2). 01530 */ 01531 char pt[8+1];// timer value encoded as 3GPP IE 01532 const int ie_value_max = 0x1f; 01533 uint32_t periodic_timer = 0; 01534 if (periodic_time <= 2*ie_value_max) { // multiples of 2 seconds 01535 periodic_timer = periodic_time/2; 01536 strcpy(pt, "01100000"); 01537 } else { 01538 if (periodic_time <= 30*ie_value_max) { // multiples of 30 seconds 01539 periodic_timer = periodic_time/30; 01540 strcpy(pt, "10000000"); 01541 } else { 01542 if (periodic_time <= 60*ie_value_max) { // multiples of 1 minute 01543 periodic_timer = periodic_time/60; 01544 strcpy(pt, "10100000"); 01545 } else { 01546 if (periodic_time <= 10*60*ie_value_max) { // multiples of 10 minutes 01547 periodic_timer = periodic_time/(10*60); 01548 strcpy(pt, "00000000"); 01549 } else { 01550 if (periodic_time <= 60*60*ie_value_max) { // multiples of 1 hour 01551 periodic_timer = periodic_time/(60*60); 01552 strcpy(pt, "00100000"); 01553 } else { 01554 if (periodic_time <= 10*60*60*ie_value_max) { // multiples of 10 hours 01555 periodic_timer = periodic_time/(10*60*60); 01556 strcpy(pt, "01000000"); 01557 } else { // multiples of 320 hours 01558 int t = periodic_time / (320*60*60); 01559 if (t > ie_value_max) { 01560 t = ie_value_max; 01561 } 01562 periodic_timer = t; 01563 strcpy(pt, "11000000"); 01564 } 01565 } 01566 } 01567 } 01568 } 01569 } 01570 01571 uint_to_binary_str(periodic_timer, &pt[3], sizeof(pt)-3, 5); 01572 pt[8] = '\0'; 01573 01574 /** 01575 Table 10.5.172/3GPP TS 24.008: GPRS Timer information element 01576 01577 Bits 5 to 1 represent the binary coded timer value. 01578 01579 Bits 6 to 8 defines the timer value unit for the GPRS timer as follows: 01580 01581 8 7 6 01582 0 0 0 value is incremented in multiples of 2 seconds 01583 0 0 1 value is incremented in multiples of 1 minute 01584 0 1 0 value is incremented in multiples of decihours 01585 1 1 1 value indicates that the timer is deactivated. 01586 01587 Other values shall be interpreted as multiples of 1 minute in this version of the protocol. 01588 */ 01589 char at[8+1]; 01590 uint32_t active_timer; // timer value encoded as 3GPP IE 01591 if (active_time <= 2*ie_value_max) { // multiples of 2 seconds 01592 active_timer = active_time/2; 01593 strcpy(at, "00000000"); 01594 } else { 01595 if (active_time <= 60*ie_value_max) { // multiples of 1 minute 01596 active_timer = (1<<5) | (active_time/60); 01597 strcpy(at, "00100000"); 01598 } else { // multiples of decihours 01599 int t = active_time / (6*60); 01600 if (t > ie_value_max) { 01601 t = ie_value_max; 01602 } 01603 active_timer = t; 01604 strcpy(at, "01000000"); 01605 } 01606 } 01607 01608 uint_to_binary_str(active_timer, &at[3], sizeof(at)-3, 5); 01609 at[8] = '\0'; 01610 01611 if (_at->send("AT+CPSMS=1,,,\"%s\",\"%s\"", pt, at) && _at->recv("OK")) { 01612 if (_at->send("AT+UPSMR=1") && _at->recv("OK")) {//enable the PSM URC 01613 tr_info("PSM enabled successfully!"); 01614 _psm_status = true; 01615 return_val = true; 01616 } else { 01617 tr_error("PSM URCs not supported"); 01618 return_val = false; 01619 } 01620 } else { 01621 tr_error("+CPSMS command failed"); 01622 return_val = false; 01623 } 01624 } 01625 } else { 01626 tr_error("PSM URCs not supported by this version of modem"); 01627 } 01628 at_set_timeout(at_timeout); 01629 UNLOCK(); 01630 return return_val; 01631 } 01632 01633 void UbloxCellularBase::uint_to_binary_str(uint32_t num, char* str, int str_size, int bit_cnt) 01634 { 01635 if (!str || str_size < bit_cnt) { 01636 return; 01637 } 01638 int tmp, pos = 0; 01639 01640 for (int i = 31; i >= 0; i--) { 01641 tmp = num >> i; 01642 if (i < bit_cnt) { 01643 if (tmp&1) { 01644 str[pos] = 1 + '0'; 01645 } else { 01646 str[pos] = 0 + '0'; 01647 } 01648 pos++; 01649 } 01650 } 01651 } 01652 01653 uint32_t UbloxCellularBase::binary_str_to_uint(const char *binary_string, int binary_string_length) 01654 { 01655 if (!binary_string || !binary_string_length) { 01656 return 0; 01657 } 01658 01659 int integer_output = 0, base_exp = 1; 01660 01661 for (int i = binary_string_length - 1; i >= 0; i--) { 01662 if (binary_string[i] == '1') { 01663 integer_output += (base_exp << (binary_string_length - (i+1))); 01664 } 01665 } 01666 01667 return integer_output; 01668 } 01669 01670 bool UbloxCellularBase::is_modem_awake() 01671 { 01672 return (_dev_info.modem_psm_state == AWAKE); 01673 } 01674 01675 #ifdef TARGET_UBLOX_C030_R41XM 01676 int UbloxCellularBase::set_receive_period(int mode, tEDRXAccessTechnology act_type, uint8_t edrx_value) { 01677 char edrx[5]; 01678 uint_to_binary_str(edrx_value, edrx, 5, 4); 01679 edrx[4] = '\0'; 01680 int status = 1; 01681 01682 LOCK(); 01683 01684 if (_at->send("AT+CEDRXS=%d,%d,\"%s\"", mode, act_type, edrx) && _at->recv("OK")) { 01685 _edrx_configured = true; 01686 status = 0; 01687 } 01688 else { 01689 status = 1; 01690 } 01691 01692 01693 UNLOCK(); 01694 01695 return status; 01696 } 01697 01698 int UbloxCellularBase::set_receive_period(int mode, tEDRXAccessTechnology act_type) { 01699 int status = 1; 01700 01701 LOCK(); 01702 01703 if (_at->send("AT+CEDRXS=%d,%d", mode, act_type) && _at->recv("OK")) { 01704 01705 status = 0; 01706 } 01707 else { 01708 status = 1; 01709 } 01710 01711 UNLOCK(); 01712 01713 return status; 01714 } 01715 01716 int UbloxCellularBase::set_receive_period(int mode) { 01717 int status = 1; 01718 01719 LOCK(); 01720 01721 if (_at->send("AT+CEDRXS=%d", mode) && _at->recv("OK")) { 01722 01723 status = 0; 01724 } 01725 else { 01726 status = 1; 01727 } 01728 01729 UNLOCK(); 01730 01731 return status; 01732 } 01733 01734 uint32_t UbloxCellularBase::get_receive_period() { 01735 uint32_t edrx_value = 2; 01736 char buf[24] = {0x00}; 01737 char edrx_val[5]; 01738 tEDRXAccessTechnology act_type; 01739 01740 LOCK(); 01741 01742 if (_at->send("AT+CEDRXS?") && _at->recv("%23[^\n]\nOK\n", buf)) { 01743 if (sscanf(buf, "+CEDRXS: %d,\"%s\"", (int *)&act_type, edrx_val) == 2) { 01744 01745 edrx_value = binary_str_to_uint(edrx_val,4); 01746 } 01747 } 01748 01749 if (_at->send("AT+CEDRXRDP") && _at->recv("OK")) { 01750 } 01751 01752 tr_info("edrx_value. %d", edrx_value); 01753 01754 UNLOCK(); 01755 return edrx_value; 01756 } 01757 #endif //TARGET_UBLOX_C030_R41XM 01758 01759 //application should call init() or connect() in order to initialize the modem 01760 void UbloxCellularBase::wakeup_modem() 01761 { 01762 LOCK(); 01763 01764 MBED_ASSERT(_at != NULL); 01765 01766 tr_info("Waking up modem..."); 01767 01768 modem_power_up(); 01769 01770 _dev_info.reg_status_csd = CSD_NOT_REGISTERED_NOT_SEARCHING; 01771 _dev_info.reg_status_psd = PSD_NOT_REGISTERED_NOT_SEARCHING; 01772 _dev_info.reg_status_eps = EPS_NOT_REGISTERED_NOT_SEARCHING; 01773 _modem_initialised = false; 01774 01775 UNLOCK(); 01776 } 01777 #endif 01778 // End of File 01779
Generated on Sun Jul 24 2022 18:28:40 by
1.7.2