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) 2017 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 } 00503 00504 // Destructor. 00505 UbloxCellularBase::~UbloxCellularBase() 00506 { 00507 deinit(); 00508 delete _at; 00509 delete _fh; 00510 } 00511 00512 // Initialise the portions of this class that are parameterised. 00513 void UbloxCellularBase::baseClassInit(PinName tx, PinName rx, 00514 int baud, bool debug_on) 00515 { 00516 // Only initialise ourselves if it's not already been done 00517 if (_at == NULL) { 00518 if (_debug_trace_on == false) { 00519 _debug_trace_on = debug_on; 00520 } 00521 _baud = baud; 00522 00523 // Set up File Handle for buffered serial comms with cellular module 00524 // (which will be used by the AT parser) 00525 // Note: the UART is initialised to run no faster than 115200 because 00526 // the modems cannot reliably auto-baud at faster rates. The faster 00527 // rate is adopted later with a specific AT command and the 00528 // UARTSerial rate is adjusted at that time 00529 if (baud > 115200) { 00530 baud = 115200; 00531 } 00532 _fh = new UARTSerial(tx, rx, baud); 00533 00534 // Set up the AT parser 00535 #ifdef TARGET_UBLOX_C030_R41XM 00536 _at = new UbloxATCmdParser(_fh, OUTPUT_ENTER_KEY, AT_PARSER_BUFFER_SIZE, 00537 _at_timeout, _debug_trace_on); 00538 #else 00539 _at = new ATCmdParser(_fh, OUTPUT_ENTER_KEY, AT_PARSER_BUFFER_SIZE, 00540 _at_timeout, _debug_trace_on); 00541 #endif 00542 00543 // Error cases, out of band handling 00544 _at->oob("ERROR", callback(this, &UbloxCellularBase::parser_abort_cb)); 00545 _at->oob("+CME ERROR", callback(this, &UbloxCellularBase::CMX_ERROR_URC)); 00546 _at->oob("+CMS ERROR", callback(this, &UbloxCellularBase::CMX_ERROR_URC)); 00547 00548 // Registration status, out of band handling 00549 _at->oob("+CREG", callback(this, &UbloxCellularBase::CREG_URC)); 00550 _at->oob("+CGREG", callback(this, &UbloxCellularBase::CGREG_URC)); 00551 _at->oob("+CEREG", callback(this, &UbloxCellularBase::CEREG_URC)); 00552 00553 // Capture the UMWI, just to stop it getting in the way 00554 _at->oob("+UMWI", callback(this, &UbloxCellularBase::UMWI_URC)); 00555 #ifdef TARGET_UBLOX_C030_R412M 00556 // Handle PSM URC for going in and coming out of PSM 00557 _at->oob("+UUPSMR", callback(this, &UbloxCellularBase::UUPSMR_URC)); 00558 #endif 00559 } 00560 } 00561 00562 // Set the AT parser timeout. 00563 // Note: the AT interface should be locked before this is called. 00564 void UbloxCellularBase::at_set_timeout(int timeout) { 00565 00566 MBED_ASSERT(_at != NULL); 00567 00568 _at_timeout = timeout; 00569 _at->set_timeout(timeout); 00570 } 00571 00572 // Read up to size bytes from the AT interface up to a "end". 00573 // Note: the AT interface should be locked before this is called. 00574 int UbloxCellularBase::read_at_to_char(char * buf, int size, char end) 00575 { 00576 int count = 0; 00577 int x = 0; 00578 00579 if (size > 0) { 00580 for (count = 0; (count < size) && (x >= 0) && (x != end); count++) { 00581 x = _at->getc(); 00582 *(buf + count) = (char) x; 00583 } 00584 00585 count--; 00586 *(buf + count) = 0; 00587 00588 // Convert line endings: 00589 // If end was '\n' (0x0a) and the preceding character was 0x0d, then 00590 // overwrite that with null as well. 00591 if ((count > 0) && (end == '\n') && (*(buf + count - 1) == '\x0d')) { 00592 count--; 00593 *(buf + count) = 0; 00594 } 00595 } 00596 00597 return count; 00598 } 00599 00600 // Power up the modem. 00601 // Enables the GPIO lines to the modem and then wriggles the power line in short pulses. 00602 bool UbloxCellularBase::power_up() 00603 { 00604 bool success = false; 00605 int at_timeout; 00606 LOCK(); 00607 00608 at_timeout = _at_timeout; // Has to be inside LOCK()s 00609 00610 MBED_ASSERT(_at != NULL); 00611 00612 /* Initialize GPIO lines */ 00613 tr_info("Powering up modem..."); 00614 modem_init(); 00615 /* Give modem a little time to settle down */ 00616 wait_ms(250); 00617 00618 for (int retry_count = 0; !success && (retry_count < 20); retry_count++) { 00619 //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. 00620 if ( (retry_count % 5) == 0) { 00621 modem_power_up(); 00622 } 00623 wait_ms(500); 00624 // Modem tends to spit out noise during power up - don't confuse the parser 00625 _at->flush(); 00626 at_set_timeout(1000); 00627 if (_at->send("AT")) { 00628 // C027 needs a delay here 00629 wait_ms(100); 00630 if (_at->recv("OK")) { 00631 success = true; 00632 } 00633 } 00634 at_set_timeout(at_timeout); 00635 } 00636 00637 if (success) { 00638 // Set the final baud rate 00639 if (_at->send("AT+IPR=%d", _baud) && _at->recv("OK")) { 00640 // Need to wait for things to be sorted out on the modem side 00641 wait_ms(100); 00642 ((UARTSerial *)_fh)->set_baud(_baud); 00643 } 00644 00645 // Turn off modem echoing and turn on verbose responses 00646 success = _at->send("ATE0;+CMEE=2") && _at->recv("OK") && 00647 // The following commands are best sent separately 00648 _at->send("AT&K0") && _at->recv("OK") && // Turn off RTC/CTS handshaking 00649 _at->send("AT&C1") && _at->recv("OK") && // Set DCD circuit(109), changes in accordance with the carrier detect status 00650 _at->send("AT&D0") && _at->recv("OK"); // Set DTR circuit, we ignore the state change of DTR 00651 } 00652 00653 if (!success) { 00654 tr_error("Preliminary modem setup failed."); 00655 } 00656 00657 UNLOCK(); 00658 return success; 00659 } 00660 00661 // Power down modem via AT interface. 00662 void UbloxCellularBase::power_down() 00663 { 00664 LOCK(); 00665 00666 MBED_ASSERT(_at != NULL); 00667 00668 // power-off modem 00669 modem_power_down(); 00670 modem_deinit(); 00671 00672 if (_modem_initialised && (_at != NULL)) { 00673 int at_timeout = _at_timeout; // Save previous timeout 00674 _at->set_timeout(1000); 00675 // Check modem is powered off 00676 if(_at->send("AT") && _at->recv("OK")) { 00677 _at->send("AT+CPWROFF") && _at->recv("OK"); 00678 } 00679 _at->set_timeout(at_timeout); 00680 } 00681 00682 _dev_info.reg_status_csd = CSD_NOT_REGISTERED_NOT_SEARCHING; 00683 _dev_info.reg_status_psd = PSD_NOT_REGISTERED_NOT_SEARCHING; 00684 _dev_info.reg_status_eps = EPS_NOT_REGISTERED_NOT_SEARCHING; 00685 00686 UNLOCK(); 00687 } 00688 00689 // Get the device ID. 00690 bool UbloxCellularBase::set_device_identity(DeviceType *dev) 00691 { 00692 char buf[20]; 00693 bool success; 00694 LOCK(); 00695 00696 MBED_ASSERT(_at != NULL); 00697 00698 success = _at->send("ATI") && _at->recv("%19[^\n]\nOK\n", buf); 00699 00700 if (success) { 00701 if (strstr(buf, "SARA-G35")) 00702 *dev = DEV_SARA_G35; 00703 else if (strstr(buf, "LISA-U200-03S")) 00704 *dev = DEV_LISA_U2_03S; 00705 else if (strstr(buf, "LISA-U2")) 00706 *dev = DEV_LISA_U2; 00707 else if (strstr(buf, "SARA-U2")) 00708 *dev = DEV_SARA_U2; 00709 else if (strstr(buf, "SARA-R4")) 00710 *dev = DEV_SARA_R4; 00711 else if (strstr(buf, "LEON-G2")) 00712 *dev = DEV_LEON_G2; 00713 else if (strstr(buf, "TOBY-L2")) 00714 *dev = DEV_TOBY_L2; 00715 else if (strstr(buf, "MPCI-L2")) 00716 *dev = DEV_MPCI_L2; 00717 } 00718 00719 UNLOCK(); 00720 return success; 00721 } 00722 00723 // Send initialisation AT commands that are specific to the device. 00724 bool UbloxCellularBase::device_init(DeviceType dev) 00725 { 00726 bool success = false; 00727 LOCK(); 00728 00729 MBED_ASSERT(_at != NULL); 00730 00731 if ((dev == DEV_LISA_U2) || (dev == DEV_LEON_G2) || (dev == DEV_TOBY_L2)) { 00732 success = _at->send("AT+UGPIOC=20,2") && _at->recv("OK"); 00733 } else if ((dev == DEV_SARA_U2) || (dev == DEV_SARA_G35)) { 00734 success = _at->send("AT+UGPIOC=16,2") && _at->recv("OK"); 00735 } else { 00736 success = true; 00737 } 00738 00739 UNLOCK(); 00740 return success; 00741 } 00742 00743 // Get the SIM card going. 00744 bool UbloxCellularBase::initialise_sim_card() 00745 { 00746 bool success = false; 00747 int retry_count = 0; 00748 bool done = false; 00749 LOCK(); 00750 00751 MBED_ASSERT(_at != NULL); 00752 00753 /* SIM initialisation may take a significant amount, so an error is 00754 * kind of expected. We should retry 10 times until we succeed or timeout. */ 00755 for (retry_count = 0; !done && (retry_count < 10); retry_count++) { 00756 char pinstr[16]; 00757 00758 if (_at->send("AT+CPIN?") && _at->recv("+CPIN: %15[^\n]\n", pinstr) && 00759 _at->recv("OK")) { 00760 done = true; 00761 if (strcmp(pinstr, "SIM PIN") == 0) { 00762 _sim_pin_check_enabled = true; 00763 if (_at->send("AT+CPIN=\"%s\"", _pin)) { 00764 if (_at->recv("OK")) { 00765 tr_info("PIN correct"); 00766 success = true; 00767 } else { 00768 tr_error("Incorrect PIN"); 00769 } 00770 } 00771 } else if (strcmp(pinstr, "READY") == 0) { 00772 _sim_pin_check_enabled = false; 00773 tr_info("No PIN required"); 00774 success = true; 00775 } else { 00776 tr_debug("Unexpected response from SIM: \"%s\"", pinstr); 00777 } 00778 } 00779 00780 /* wait for a second before retry */ 00781 wait_ms(1000); 00782 } 00783 00784 if (done) { 00785 tr_info("SIM Ready."); 00786 } else { 00787 tr_error("SIM not ready."); 00788 } 00789 00790 UNLOCK(); 00791 return success; 00792 } 00793 00794 /********************************************************************** 00795 * PUBLIC METHODS 00796 **********************************************************************/ 00797 00798 // Initialise the modem. 00799 bool UbloxCellularBase::init(const char *pin) 00800 { 00801 int x; 00802 MBED_ASSERT(_at != NULL); 00803 00804 if (!_modem_initialised) { 00805 if (power_up()) { 00806 tr_info("Modem Ready."); 00807 if (pin != NULL) { 00808 _pin = pin; 00809 } 00810 #ifdef TARGET_UBLOX_C027 00811 if (set_functionality_mode(FUNC_MIN)) { 00812 #else 00813 if (set_functionality_mode(FUNC_AIRPLANE)) { 00814 #endif 00815 if (initialise_sim_card()) { 00816 #ifdef TARGET_UBLOX_C030_R412M 00817 if (_psm_status == false) { //psm is not enabled by application yet so disable it at start-up 00818 set_power_saving_mode(0, 0); 00819 } 00820 #endif 00821 #ifdef TARGET_UBLOX_C030_R41XM 00822 if (_at->is_idle_mode_enabled() == false) { 00823 set_idle_mode(false); //disable idle mode at start up 00824 } 00825 #endif 00826 if (set_device_identity(&_dev_info.dev) && // Set up device identity 00827 device_init(_dev_info.dev)) {// Initialise this device 00828 // Get the integrated circuit ID of the SIM 00829 if (get_iccid()) { 00830 // Try a few times to get the IMSI (since on some modems this can 00831 // take a while to be retrieved, especially if a SIM PIN 00832 // was set) 00833 for (x = 0; (x < 3) && !get_imsi(); x++) { 00834 wait_ms(1000); 00835 } 00836 00837 if (x < 3) { // If we got the IMSI, can get the others 00838 if (get_imei() && // Get international mobile equipment identifier 00839 get_meid() && // Probably the same as the IMEI 00840 set_sms()) { // And set up SMS 00841 // The modem is initialised. 00842 _modem_initialised = true; 00843 } 00844 } 00845 } 00846 } 00847 } 00848 } 00849 } 00850 } 00851 00852 return _modem_initialised; 00853 } 00854 00855 // Perform registration. 00856 bool UbloxCellularBase::nwk_registration() 00857 { 00858 bool atSuccess = false; 00859 bool registered = false; 00860 int status; 00861 int at_timeout; 00862 LOCK(); 00863 00864 at_timeout = _at_timeout; // Has to be inside LOCK()s 00865 00866 MBED_ASSERT(_at != NULL); 00867 00868 if (!is_registered_psd() && !is_registered_csd() && !is_registered_eps()) { 00869 if (set_functionality_mode(FUNC_FULL)) { 00870 tr_info("Searching Network..."); 00871 // Enable the packet switched and network registration unsolicited result codes 00872 if (_at->send("AT+CREG=1") && _at->recv("OK") && 00873 _at->send("AT+CGREG=1") && _at->recv("OK")) { 00874 atSuccess = true; 00875 if (_at->send("AT+CEREG=1")) { 00876 _at->recv("OK"); 00877 // Don't check return value as this works for LTE only 00878 } 00879 00880 if (atSuccess) { 00881 // See if we are already in automatic mode 00882 if (_at->send("AT+COPS?") && _at->recv("+COPS: %d", &status) && 00883 _at->recv("OK")) { 00884 // If not, set it 00885 if (status != 0) { 00886 // Don't check return code here as there's not much 00887 // we can do if this fails. 00888 _at->send("AT+COPS=0") && _at->recv("OK"); 00889 } 00890 } 00891 00892 // Query the registration status directly as well, 00893 // just in case 00894 if (_at->send("AT+CREG?") && _at->recv("OK")) { 00895 // Answer will be processed by URC 00896 } 00897 if (_at->send("AT+CGREG?") && _at->recv("OK")) { 00898 // Answer will be processed by URC 00899 } 00900 if (_at->send("AT+CEREG?")) { 00901 _at->recv("OK"); 00902 // Don't check return value as this works for LTE only 00903 } 00904 } 00905 } 00906 // Wait for registration to succeed 00907 at_set_timeout(1000); 00908 for (int waitSeconds = 0; !registered && (waitSeconds < 180); waitSeconds++) { 00909 registered = is_registered_psd() || is_registered_csd() || is_registered_eps(); 00910 _at->recv(UNNATURAL_STRING); 00911 } 00912 at_set_timeout(at_timeout); 00913 00914 if (registered) { 00915 // This should return quickly but sometimes the status field is not returned 00916 // so make the timeout short 00917 at_set_timeout(1000); 00918 if (_at->send("AT+COPS?") && _at->recv("+COPS: %*d,%*d,\"%*[^\"]\",%d\n", &status)) { 00919 set_rat(status); 00920 } 00921 at_set_timeout(at_timeout); 00922 } 00923 } 00924 } else { 00925 registered = true; 00926 } 00927 00928 UNLOCK(); 00929 return registered; 00930 } 00931 00932 bool UbloxCellularBase::is_registered_csd() 00933 { 00934 return (_dev_info.reg_status_csd == CSD_REGISTERED) || 00935 (_dev_info.reg_status_csd == CSD_REGISTERED_ROAMING) || 00936 (_dev_info.reg_status_csd == CSD_CSFB_NOT_PREFERRED); 00937 } 00938 00939 bool UbloxCellularBase::is_registered_psd() 00940 { 00941 return (_dev_info.reg_status_psd == PSD_REGISTERED) || 00942 (_dev_info.reg_status_psd == PSD_REGISTERED_ROAMING); 00943 } 00944 00945 bool UbloxCellularBase::is_registered_eps() 00946 { 00947 return (_dev_info.reg_status_eps == EPS_REGISTERED) || 00948 (_dev_info.reg_status_eps == EPS_REGISTERED_ROAMING); 00949 } 00950 00951 // Perform deregistration. 00952 bool UbloxCellularBase::nwk_deregistration() 00953 { 00954 bool success = false; 00955 LOCK(); 00956 00957 MBED_ASSERT(_at != NULL); 00958 00959 if (_at->send("AT+COPS=2") && _at->recv("OK")) { 00960 _dev_info.reg_status_csd = CSD_NOT_REGISTERED_NOT_SEARCHING; 00961 _dev_info.reg_status_psd = PSD_NOT_REGISTERED_NOT_SEARCHING; 00962 _dev_info.reg_status_eps = EPS_NOT_REGISTERED_NOT_SEARCHING; 00963 success = true; 00964 } 00965 00966 UNLOCK(); 00967 return success; 00968 } 00969 00970 // Put the modem into its lowest power state. 00971 void UbloxCellularBase::deinit() 00972 { 00973 power_down(); 00974 _modem_initialised = false; 00975 } 00976 00977 // Set the PIN. 00978 void UbloxCellularBase::set_pin(const char *pin) { 00979 _pin = pin; 00980 } 00981 00982 // Enable or disable SIM pin checking. 00983 bool UbloxCellularBase::sim_pin_check_enable(bool enableNotDisable) 00984 { 00985 bool success = false;; 00986 LOCK(); 00987 00988 MBED_ASSERT(_at != NULL); 00989 00990 if (_pin != NULL) { 00991 if (_sim_pin_check_enabled && !enableNotDisable) { 00992 // Disable the SIM lock 00993 if (_at->send("AT+CLCK=\"SC\",0,\"%s\"", _pin) && _at->recv("OK")) { 00994 _sim_pin_check_enabled = false; 00995 success = true; 00996 } 00997 } else if (!_sim_pin_check_enabled && enableNotDisable) { 00998 // Enable the SIM lock 00999 if (_at->send("AT+CLCK=\"SC\",1,\"%s\"", _pin) && _at->recv("OK")) { 01000 _sim_pin_check_enabled = true; 01001 success = true; 01002 } 01003 } else { 01004 success = true; 01005 } 01006 } 01007 01008 UNLOCK(); 01009 return success; 01010 } 01011 01012 // Change the pin code for the SIM card. 01013 bool UbloxCellularBase::change_sim_pin(const char *pin) 01014 { 01015 bool success = false;; 01016 LOCK(); 01017 01018 MBED_ASSERT(_at != NULL); 01019 01020 // Change the SIM pin 01021 if ((pin != NULL) && (_pin != NULL)) { 01022 if (_at->send("AT+CPWD=\"SC\",\"%s\",\"%s\"", _pin, pin) && _at->recv("OK")) { 01023 _pin = pin; 01024 success = true; 01025 } 01026 } 01027 01028 UNLOCK(); 01029 return success; 01030 } 01031 01032 // Get the IMEI. 01033 bool UbloxCellularBase::get_imei(char *imei_to_send, int size) 01034 { 01035 bool success; 01036 LOCK(); 01037 01038 MBED_ASSERT(_at != NULL); 01039 01040 // International mobile equipment identifier 01041 // AT Command Manual UBX-13002752, section 4.7 01042 success = _at->send("AT+CGSN") && _at->recv("%15[^\n]\nOK\n", _dev_info.imei); 01043 tr_info("DevInfo: IMEI=%s", _dev_info.imei); 01044 01045 if (success) { 01046 memcpy(imei_to_send,_dev_info.imei,size); 01047 imei_to_send[size-1] = '\0'; 01048 } 01049 01050 UNLOCK(); 01051 return success; 01052 } 01053 01054 // Get the IMEI of the module. 01055 const char *UbloxCellularBase::imei() 01056 { 01057 return _dev_info.imei; 01058 } 01059 01060 // Get the Mobile Equipment ID (which may be the same as the IMEI). 01061 const char *UbloxCellularBase::meid() 01062 { 01063 return _dev_info.meid; 01064 } 01065 01066 // Get the IMSI of the SIM. 01067 const char *UbloxCellularBase::imsi() 01068 { 01069 // (try) to update the IMSI, just in case the SIM has changed 01070 get_imsi(); 01071 01072 return _dev_info.imsi; 01073 } 01074 01075 // Get the ICCID of the SIM. 01076 const char *UbloxCellularBase::iccid() 01077 { 01078 // (try) to update the ICCID, just in case the SIM has changed 01079 get_iccid(); 01080 01081 return _dev_info.iccid; 01082 } 01083 01084 // Get the RSSI in dBm. 01085 int UbloxCellularBase::rssi() 01086 { 01087 char buf[7] = {0}; 01088 int rssi = 0; 01089 int qual = 0; 01090 int rssiRet = 0; 01091 bool success; 01092 LOCK(); 01093 01094 MBED_ASSERT(_at != NULL); 01095 01096 success = _at->send("AT+CSQ") && _at->recv("+CSQ: %6[^\n]\nOK\n", buf); 01097 01098 if (success) { 01099 if (sscanf(buf, "%d,%d", &rssi, &qual) == 2) { 01100 // AT+CSQ returns a coded RSSI value and an RxQual value 01101 // For 2G an RSSI of 0 corresponds to -113 dBm or less, 01102 // an RSSI of 31 corresponds to -51 dBm or less and hence 01103 // each value is a 2 dB step. 01104 // For LTE the mapping is defined in the array rssiConvertLte[]. 01105 // For 3G the mapping to RSCP is defined in the array rscpConvert3G[] 01106 // and the RSSI value is then RSCP - the EC_NO_LEV number derived 01107 // by putting the qual number through qualConvert3G[]. 01108 if ((rssi >= 0) && (rssi <= 31)) { 01109 switch (_dev_info.rat) { 01110 case UTRAN: 01111 case HSDPA: 01112 case HSUPA: 01113 case HSDPA_HSUPA: 01114 // 3G 01115 if ((qual >= 0) && (qual <= 7)) { 01116 qual = qualConvert3G[qual]; 01117 rssiRet = rscpConvert3G[rssi]; 01118 rssiRet -= qual; 01119 } 01120 01121 break; 01122 case LTE: 01123 // LTE 01124 rssiRet = rssiConvertLte[rssi]; 01125 break; 01126 case GSM: 01127 case COMPACT_GSM: 01128 case EDGE: 01129 default: 01130 // GSM or assumed GSM if the RAT is not known 01131 rssiRet = -(113 - (rssi << 2)); 01132 break; 01133 } 01134 } 01135 } 01136 } 01137 01138 UNLOCK(); 01139 return rssiRet; 01140 } 01141 01142 //RAT should be set in a detached state (AT+COPS=2) 01143 bool UbloxCellularBase::set_modem_rat(RAT selected_rat, RAT preferred_rat, RAT second_preferred_rat) 01144 { 01145 bool success = false; 01146 char command[16] = {0x00}; 01147 01148 //check if modem is registered with network 01149 if (is_registered_csd() || is_registered_psd() || is_registered_eps()) { 01150 tr_error("RAT should only be set in detached state"); 01151 return false; 01152 } 01153 01154 if (preferred_rat != NOT_USED && second_preferred_rat != NOT_USED) { 01155 sprintf(command, "AT+URAT=%d,%d,%d", selected_rat, preferred_rat, second_preferred_rat); 01156 } else if (preferred_rat != NOT_USED) { 01157 sprintf(command, "AT+URAT=%d,%d", selected_rat, preferred_rat); 01158 } else if (second_preferred_rat != NOT_USED) { 01159 sprintf(command, "AT+URAT=%d,%d", selected_rat, second_preferred_rat); 01160 } else { 01161 sprintf(command, "AT+URAT=%d", selected_rat); 01162 } 01163 01164 LOCK(); 01165 if (_at->send(command) && _at->recv("OK")) { 01166 success = true; 01167 } else { 01168 tr_error("unable to set the specified RAT"); 01169 success = false; 01170 } 01171 UNLOCK(); 01172 01173 return success; 01174 } 01175 01176 bool UbloxCellularBase::get_modem_rat(int *selected_rat, int *preferred_rat, int *second_preferred_rat) 01177 { 01178 bool success = false; 01179 char buf[24] = {0x00}; 01180 01181 if (selected_rat == NULL || preferred_rat == NULL || second_preferred_rat == NULL) { 01182 tr_info("invalid pointers"); 01183 return false; 01184 } 01185 01186 MBED_ASSERT(_at != NULL); 01187 01188 *selected_rat = NOT_USED; 01189 *preferred_rat = NOT_USED; 01190 *second_preferred_rat = NOT_USED; 01191 01192 LOCK(); 01193 01194 if (_at->send("AT+URAT?") && _at->recv("%23[^\n]\nOK\n", buf)) { 01195 if (sscanf(buf, "+URAT: %d,%d,%d", selected_rat, preferred_rat, second_preferred_rat) == 3) { 01196 success = true; 01197 } else if (sscanf(buf, "+URAT: %d,%d", selected_rat, preferred_rat) == 2) { 01198 success = true; 01199 } else if (sscanf(buf, "+URAT: %d", selected_rat) == 1) { 01200 success = true; 01201 } 01202 } 01203 01204 UNLOCK(); 01205 return success; 01206 } 01207 01208 //application should call init() or connect() in order to initialize the modem 01209 bool UbloxCellularBase::reboot_modem() 01210 { 01211 return (set_functionality_mode(FUNC_RESET)); 01212 } 01213 01214 bool UbloxCellularBase::set_functionality_mode(FunctionalityMode mode) 01215 { 01216 bool return_val = false; 01217 int at_timeout; 01218 LOCK(); 01219 01220 MBED_ASSERT(_at != NULL); 01221 01222 at_timeout = _at_timeout; // Has to be inside LOCK()s 01223 at_set_timeout(3*60*1000); //command has 3 minutes timeout 01224 01225 if (_at->send("AT+CFUN=%d", mode) && _at->recv("OK")) { 01226 return_val = true; 01227 } 01228 01229 if (mode == FUNC_RESET || mode == FUNC_RESET_WITH_SIM) { 01230 _modem_initialised = false; 01231 } 01232 01233 at_set_timeout(at_timeout); 01234 UNLOCK(); 01235 01236 return return_val; 01237 } 01238 01239 bool UbloxCellularBase::get_functionality_mode(int *mode) 01240 { 01241 bool return_val = false; 01242 01243 if (mode == NULL) { 01244 return false; 01245 } 01246 01247 LOCK(); 01248 MBED_ASSERT(_at != NULL); 01249 01250 if ( (_at->send("AT+CFUN?") && _at->recv("+CFUN: %d", mode) && _at->recv("OK")) ) { 01251 return_val = true; 01252 } 01253 01254 UNLOCK(); 01255 return return_val; 01256 } 01257 01258 #ifdef TARGET_UBLOX_C030_R41XM 01259 bool UbloxCellularBase::set_mno_profile(MNOProfile profile) 01260 { 01261 bool return_val = false; 01262 01263 int mno_profile; 01264 if (get_mno_profile(&mno_profile)) { 01265 tr_info("Current MNO profile is: %d", mno_profile); 01266 if (mno_profile != profile) { 01267 01268 if (is_registered_csd() || is_registered_psd() || is_registered_eps()) { 01269 tr_error("MNO profile should only be set in detached state"); 01270 return false; 01271 } 01272 01273 LOCK(); 01274 if (_at->send("AT+UMNOPROF=%d", profile) && _at->recv("OK")) { 01275 return_val = true; 01276 } else { 01277 tr_error("unable to set specified profile"); 01278 } 01279 UNLOCK(); 01280 01281 } else { 01282 return_val = true; 01283 } 01284 } else { 01285 tr_error("could not read MNO profile"); 01286 } 01287 01288 return return_val; 01289 } 01290 01291 bool UbloxCellularBase::get_mno_profile(int *profile) 01292 { 01293 bool return_val = false; 01294 01295 if (profile == NULL) { 01296 return false; 01297 } 01298 01299 LOCK(); 01300 MBED_ASSERT(_at != NULL); 01301 01302 if ( (_at->send("AT+UMNOPROF?") && _at->recv("+UMNOPROF: %d", profile) && _at->recv("OK")) ) { 01303 return_val = true; 01304 } 01305 01306 UNLOCK(); 01307 return return_val; 01308 } 01309 // Enable or Disable the UPSV power saving mode 01310 bool UbloxCellularBase::set_idle_mode(bool enable) 01311 { 01312 #ifdef TARGET_UBLOX_C030_R412M 01313 if (_psm_status == true && enable == true) { 01314 return false; 01315 } 01316 #endif 01317 01318 bool success = false; 01319 LOCK(); 01320 01321 MBED_ASSERT(_at != NULL); 01322 01323 if (_at->send("AT+UPSV=%d", enable ? 4 : 0) && _at->recv("OK")) { 01324 if (enable == true) { 01325 _at->idle_mode_enabled(); 01326 } 01327 else { 01328 _at->idle_mode_disabled(); 01329 } 01330 success = true; 01331 } 01332 01333 UNLOCK(); 01334 return success; 01335 } 01336 01337 bool UbloxCellularBase::get_idle_mode(int *status) 01338 { 01339 bool return_val = false; 01340 01341 if (status == NULL) { 01342 return false; 01343 } 01344 01345 LOCK(); 01346 MBED_ASSERT(_at != NULL); 01347 01348 if ( (_at->send("AT+UPSV?") && _at->recv("+UPSV: %d", status) && _at->recv("OK")) ) { 01349 if (*status == 4) { 01350 *status = 1; 01351 } 01352 return_val = true; 01353 } 01354 01355 UNLOCK(); 01356 return return_val; 01357 } 01358 #endif 01359 01360 #ifdef TARGET_UBLOX_C030_R412M 01361 bool UbloxCellularBase::get_power_saving_mode(int *status, int *periodic_time, int *active_time) 01362 { 01363 char pt_encoded[8+1];// timer value encoded as 3GPP IE 01364 char at_encoded[8+1];// timer value encoded as 3GPP IE 01365 int value, multiplier; 01366 bool return_val; 01367 01368 if (status == NULL || periodic_time == NULL || active_time == NULL) { 01369 return false; 01370 } 01371 01372 LOCK(); 01373 //+UCPSMS:1,,,"01000011","01000011" 01374 if (_at->send("AT+UCPSMS?") && _at->recv("+UCPSMS:%d,,,\"%8c\",\"%8c\"\n", status, pt_encoded, at_encoded)) { 01375 if (*status == true) { 01376 //PSM is enabled, decode the timer values, periodic TAU first 01377 value = (pt_encoded[7]- '0'); 01378 value += (pt_encoded[6]- '0') << 1; 01379 value += (pt_encoded[5]- '0') << 2; 01380 value += (pt_encoded[4]- '0') << 3; 01381 value += (pt_encoded[3]- '0') << 4; 01382 01383 multiplier = (pt_encoded[2]- '0'); 01384 multiplier += (pt_encoded[1]- '0') << 1; 01385 multiplier += (pt_encoded[0]- '0') << 2; 01386 01387 switch(multiplier) { 01388 //10 minutes 01389 case 0: 01390 value = value*10*60; 01391 break; 01392 01393 //1 hour 01394 case 1: 01395 value = value*60*60; 01396 break; 01397 01398 //10 hours 01399 case 2: 01400 value = value*10*60*60; 01401 break; 01402 01403 //2 seconds 01404 case 3: 01405 value = value*2; 01406 break; 01407 01408 //30 seconds 01409 case 4: 01410 value = value*30; 01411 break; 01412 01413 //1 minute 01414 case 5: 01415 value = value*60; 01416 break; 01417 01418 //320 hours 01419 case 6: 01420 value = value*320*60*60; 01421 break; 01422 01423 default: 01424 value = 0; 01425 break; 01426 } 01427 *periodic_time = value; 01428 01429 //decode the active time 01430 value = (at_encoded[7]- '0'); 01431 value += (at_encoded[6]- '0') << 1; 01432 value += (at_encoded[5]- '0') << 2; 01433 value += (at_encoded[4]- '0') << 3; 01434 value += (at_encoded[3]- '0') << 4; 01435 01436 multiplier = (at_encoded[2]- '0'); 01437 multiplier += (at_encoded[1]- '0') << 1; 01438 multiplier += (at_encoded[0]- '0') << 2; 01439 01440 switch(multiplier) { 01441 //2 seconds 01442 case 0: 01443 value = value*2; 01444 break; 01445 01446 //1 minute 01447 case 1: 01448 value = value*60; 01449 break; 01450 01451 //decihours (6minutes) 01452 case 2: 01453 value = value*6*60; 01454 break; 01455 01456 default: 01457 value = 0; 01458 break; 01459 } 01460 *active_time = value; 01461 } 01462 return_val = true; 01463 } else { 01464 return_val = false; 01465 } 01466 UNLOCK(); 01467 return return_val; 01468 } 01469 01470 bool UbloxCellularBase::set_power_saving_mode(int periodic_time, int active_time) 01471 { 01472 if (_at->is_idle_mode_enabled() == true && periodic_time != 0 && active_time != 0 ) { 01473 return false; 01474 } 01475 bool return_val = false; 01476 01477 LOCK(); 01478 int at_timeout = _at_timeout; 01479 at_set_timeout(10000); //AT+CPSMS has response time of < 10s 01480 01481 //check if modem supports PSM URCs 01482 if (_at->send("AT+UPSMR?") && _at->recv("OK")) { 01483 if (periodic_time == 0 && active_time == 0) { 01484 // disable PSM 01485 if (_at->send("AT+CPSMS=0") && _at->recv("OK")) { 01486 if (_at->send("AT+UPSMR=0") && _at->recv("OK")) {//disable the URC 01487 //de-register the callback 01488 detach_cb_psm_going_in(); 01489 detach_cb_psm_coming_out(); 01490 _psm_status = false; 01491 return_val = true; 01492 } 01493 } 01494 } else { //PSM string encoding code borrowed from AT_CellularPower.cpp 01495 /** 01496 Table 10.5.163a/3GPP TS 24.008: GPRS Timer 3 information element 01497 01498 Bits 5 to 1 represent the binary coded timer value. 01499 01500 Bits 6 to 8 defines the timer value unit for the GPRS timer as follows: 01501 8 7 6 01502 0 0 0 value is incremented in multiples of 10 minutes 01503 0 0 1 value is incremented in multiples of 1 hour 01504 0 1 0 value is incremented in multiples of 10 hours 01505 0 1 1 value is incremented in multiples of 2 seconds 01506 1 0 0 value is incremented in multiples of 30 seconds 01507 1 0 1 value is incremented in multiples of 1 minute 01508 1 1 0 value is incremented in multiples of 320 hours (NOTE 1) 01509 1 1 1 value indicates that the timer is deactivated (NOTE 2). 01510 */ 01511 char pt[8+1];// timer value encoded as 3GPP IE 01512 const int ie_value_max = 0x1f; 01513 uint32_t periodic_timer = 0; 01514 if (periodic_time <= 2*ie_value_max) { // multiples of 2 seconds 01515 periodic_timer = periodic_time/2; 01516 strcpy(pt, "01100000"); 01517 } else { 01518 if (periodic_time <= 30*ie_value_max) { // multiples of 30 seconds 01519 periodic_timer = periodic_time/30; 01520 strcpy(pt, "10000000"); 01521 } else { 01522 if (periodic_time <= 60*ie_value_max) { // multiples of 1 minute 01523 periodic_timer = periodic_time/60; 01524 strcpy(pt, "10100000"); 01525 } else { 01526 if (periodic_time <= 10*60*ie_value_max) { // multiples of 10 minutes 01527 periodic_timer = periodic_time/(10*60); 01528 strcpy(pt, "00000000"); 01529 } else { 01530 if (periodic_time <= 60*60*ie_value_max) { // multiples of 1 hour 01531 periodic_timer = periodic_time/(60*60); 01532 strcpy(pt, "00100000"); 01533 } else { 01534 if (periodic_time <= 10*60*60*ie_value_max) { // multiples of 10 hours 01535 periodic_timer = periodic_time/(10*60*60); 01536 strcpy(pt, "01000000"); 01537 } else { // multiples of 320 hours 01538 int t = periodic_time / (320*60*60); 01539 if (t > ie_value_max) { 01540 t = ie_value_max; 01541 } 01542 periodic_timer = t; 01543 strcpy(pt, "11000000"); 01544 } 01545 } 01546 } 01547 } 01548 } 01549 } 01550 01551 uint_to_binary_str(periodic_timer, &pt[3], sizeof(pt)-3, 5); 01552 pt[8] = '\0'; 01553 01554 /** 01555 Table 10.5.172/3GPP TS 24.008: GPRS Timer information element 01556 01557 Bits 5 to 1 represent the binary coded timer value. 01558 01559 Bits 6 to 8 defines the timer value unit for the GPRS timer as follows: 01560 01561 8 7 6 01562 0 0 0 value is incremented in multiples of 2 seconds 01563 0 0 1 value is incremented in multiples of 1 minute 01564 0 1 0 value is incremented in multiples of decihours 01565 1 1 1 value indicates that the timer is deactivated. 01566 01567 Other values shall be interpreted as multiples of 1 minute in this version of the protocol. 01568 */ 01569 char at[8+1]; 01570 uint32_t active_timer; // timer value encoded as 3GPP IE 01571 if (active_time <= 2*ie_value_max) { // multiples of 2 seconds 01572 active_timer = active_time/2; 01573 strcpy(at, "00000000"); 01574 } else { 01575 if (active_time <= 60*ie_value_max) { // multiples of 1 minute 01576 active_timer = (1<<5) | (active_time/60); 01577 strcpy(at, "00100000"); 01578 } else { // multiples of decihours 01579 int t = active_time / (6*60); 01580 if (t > ie_value_max) { 01581 t = ie_value_max; 01582 } 01583 active_timer = t; 01584 strcpy(at, "01000000"); 01585 } 01586 } 01587 01588 uint_to_binary_str(active_timer, &at[3], sizeof(at)-3, 5); 01589 at[8] = '\0'; 01590 01591 if (_at->send("AT+CPSMS=1,,,\"%s\",\"%s\"", pt, at) && _at->recv("OK")) { 01592 if (_at->send("AT+UPSMR=1") && _at->recv("OK")) {//enable the PSM URC 01593 tr_info("PSM enabled successfully!"); 01594 _psm_status = true; 01595 return_val = true; 01596 } else { 01597 tr_error("PSM URCs not supported"); 01598 return_val = false; 01599 } 01600 } else { 01601 tr_error("+CPSMS command failed"); 01602 return_val = false; 01603 } 01604 } 01605 } else { 01606 tr_error("PSM URCs not supported by this version of modem"); 01607 } 01608 at_set_timeout(at_timeout); 01609 UNLOCK(); 01610 return return_val; 01611 } 01612 01613 void UbloxCellularBase::uint_to_binary_str(uint32_t num, char* str, int str_size, int bit_cnt) 01614 { 01615 if (!str || str_size < bit_cnt) { 01616 return; 01617 } 01618 int tmp, pos = 0; 01619 01620 for (int i = 31; i >= 0; i--) { 01621 tmp = num >> i; 01622 if (i < bit_cnt) { 01623 if (tmp&1) { 01624 str[pos] = 1 + '0'; 01625 } else { 01626 str[pos] = 0 + '0'; 01627 } 01628 pos++; 01629 } 01630 } 01631 } 01632 01633 bool UbloxCellularBase::is_modem_awake() 01634 { 01635 return (_dev_info.modem_psm_state == AWAKE); 01636 } 01637 01638 //application should call init() or connect() in order to initialize the modem 01639 void UbloxCellularBase::wakeup_modem() 01640 { 01641 LOCK(); 01642 01643 MBED_ASSERT(_at != NULL); 01644 01645 tr_info("Waking up modem..."); 01646 01647 modem_power_up(); 01648 01649 _dev_info.reg_status_csd = CSD_NOT_REGISTERED_NOT_SEARCHING; 01650 _dev_info.reg_status_psd = PSD_NOT_REGISTERED_NOT_SEARCHING; 01651 _dev_info.reg_status_eps = EPS_NOT_REGISTERED_NOT_SEARCHING; 01652 _modem_initialised = false; 01653 01654 UNLOCK(); 01655 } 01656 #endif 01657 // End of File 01658
Generated on Wed Aug 3 2022 16:33:26 by
1.7.2