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