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