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