upsv
Embed:
(wiki syntax)
Show/hide line numbers
UbloxCellularBase.cpp
00001 /* Copyright (c) 2017 ublox Limited 00002 * 00003 * Licensed under the Apache License, Version 2.0 (the "License"); 00004 * you may not use this file except in compliance with the License. 00005 * You may obtain a copy of the License at 00006 * 00007 * http://www.apache.org/licenses/LICENSE-2.0 00008 * 00009 * Unless required by applicable law or agreed to in writing, software 00010 * distributed under the License is distributed on an "AS IS" BASIS, 00011 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00012 * See the License for the specific language governing permissions and 00013 * limitations under the License. 00014 */ 00015 00016 #include "UARTSerial.h" 00017 #include "APN_db.h" 00018 #include "UbloxCellularBase.h" 00019 #include "onboard_modem_api.h" 00020 #ifdef FEATURE_COMMON_PAL 00021 #include "mbed_trace.h" 00022 #define TRACE_GROUP "UCB" 00023 #else 00024 #define tr_debug(format, ...) debug_if(_debug_trace_on, format "\n", ## __VA_ARGS__) 00025 #define tr_info(format, ...) debug_if(_debug_trace_on, format "\n", ## __VA_ARGS__) 00026 #define tr_warn(format, ...) debug_if(_debug_trace_on, format "\n", ## __VA_ARGS__) 00027 #define tr_error(format, ...) debug_if(_debug_trace_on, format "\n", ## __VA_ARGS__) 00028 #endif 00029 00030 /* Array to convert the 3G qual number into a median EC_NO_LEV number. 00031 */ 00032 /* 0 1 2 3 4 5 6 7 */ 00033 /* 44, 41, 35, 29, 23, 17, 11, 7*/ 00034 const int qualConvert3G[] = {-2, -4, -7, -10, -13, -16, -19, -21}; 00035 00036 /* Array to convert the 3G "rssi" number into a dBm RSCP value rounded up to the 00037 * nearest whole number. 00038 */ 00039 const int rscpConvert3G[] = {-108, -105, -103, -100, -98, -96, -94, -93, /* 0 - 7 */ 00040 -91, -89, -88, -85, -83, -80, -78, -76, /* 8 - 15 */ 00041 -74, -73, -70, -68, -66, -64, -63, -60, /* 16 - 23 */ 00042 -58, -56, -54, -53, -51, -49, -48, -46}; /* 24 - 31 */ 00043 00044 /* Array to convert the LTE rssi number into a dBm value rounded up to the 00045 * nearest whole number. 00046 */ 00047 const int rssiConvertLte[] = {-118, -115, -113, -110, -108, -105, -103, -100, /* 0 - 7 */ 00048 -98, -95, -93, -90, -88, -85, -83, -80, /* 8 - 15 */ 00049 -78, -76, -74, -73, -71, -69, -68, -65, /* 16 - 23 */ 00050 -63, -61, -60, -59, -58, -55, -53, -48}; /* 24 - 31 */ 00051 00052 /********************************************************************** 00053 * PRIVATE METHODS 00054 **********************************************************************/ 00055 00056 void UbloxCellularBase::set_nwk_reg_status_csd(int status) 00057 { 00058 switch (status) { 00059 case CSD_NOT_REGISTERED_NOT_SEARCHING: 00060 case CSD_NOT_REGISTERED_SEARCHING: 00061 tr_info("Not (yet) registered for circuit switched service"); 00062 break; 00063 case CSD_REGISTERED: 00064 case CSD_REGISTERED_ROAMING: 00065 tr_info("Registered for circuit switched service"); 00066 break; 00067 case CSD_REGISTRATION_DENIED: 00068 tr_info("Circuit switched service denied"); 00069 break; 00070 case CSD_UNKNOWN_COVERAGE: 00071 tr_info("Out of circuit switched service coverage"); 00072 break; 00073 case CSD_SMS_ONLY: 00074 tr_info("SMS service only"); 00075 break; 00076 case CSD_SMS_ONLY_ROAMING: 00077 tr_info("SMS service only"); 00078 break; 00079 case CSD_CSFB_NOT_PREFERRED: 00080 tr_info("Registered for circuit switched service with CSFB not preferred"); 00081 break; 00082 default: 00083 tr_info("Unknown circuit switched service registration status. %d", status); 00084 break; 00085 } 00086 00087 _dev_info.reg_status_csd = static_cast<NetworkRegistrationStatusCsd>(status); 00088 } 00089 00090 void UbloxCellularBase::set_nwk_reg_status_psd(int status) 00091 { 00092 switch (status) { 00093 case PSD_NOT_REGISTERED_NOT_SEARCHING: 00094 case PSD_NOT_REGISTERED_SEARCHING: 00095 tr_info("Not (yet) registered for packet switched service"); 00096 break; 00097 case PSD_REGISTERED: 00098 case PSD_REGISTERED_ROAMING: 00099 tr_info("Registered for packet switched service"); 00100 break; 00101 case PSD_REGISTRATION_DENIED: 00102 tr_info("Packet switched service denied"); 00103 break; 00104 case PSD_UNKNOWN_COVERAGE: 00105 tr_info("Out of packet switched service coverage"); 00106 break; 00107 case PSD_EMERGENCY_SERVICES_ONLY: 00108 tr_info("Limited access for packet switched service. Emergency use only."); 00109 break; 00110 default: 00111 tr_info("Unknown packet switched service registration status. %d", status); 00112 break; 00113 } 00114 00115 _dev_info.reg_status_psd = static_cast<NetworkRegistrationStatusPsd>(status); 00116 } 00117 00118 void UbloxCellularBase::set_nwk_reg_status_eps(int status) 00119 { 00120 switch (status) { 00121 case EPS_NOT_REGISTERED_NOT_SEARCHING: 00122 case EPS_NOT_REGISTERED_SEARCHING: 00123 tr_info("Not (yet) registered for EPS service"); 00124 break; 00125 case EPS_REGISTERED: 00126 case EPS_REGISTERED_ROAMING: 00127 tr_info("Registered for EPS service"); 00128 break; 00129 case EPS_REGISTRATION_DENIED: 00130 tr_info("EPS service denied"); 00131 break; 00132 case EPS_UNKNOWN_COVERAGE: 00133 tr_info("Out of EPS service coverage"); 00134 break; 00135 case EPS_EMERGENCY_SERVICES_ONLY: 00136 tr_info("Limited access for EPS service. Emergency use only."); 00137 break; 00138 default: 00139 tr_info("Unknown EPS service registration status. %d", status); 00140 break; 00141 } 00142 00143 _dev_info.reg_status_eps = static_cast<NetworkRegistrationStatusEps>(status); 00144 } 00145 00146 #ifdef TARGET_UBLOX_C030_R412M 00147 void UbloxCellularBase::set_modem_psm_state(int status) 00148 { 00149 switch (status) { 00150 case ASLEEP: 00151 tr_info("Modem is going in PSM sleep"); 00152 break; 00153 case AWAKE: 00154 tr_info("Modem is awake from PSM sleep"); 00155 break; 00156 default: 00157 tr_info("Unknown PSM state. %d", status); 00158 break; 00159 } 00160 00161 _dev_info.modem_psm_state = static_cast<ModemPSMState>(status); 00162 } 00163 #endif 00164 00165 void UbloxCellularBase::set_rat(int acTStatus) 00166 { 00167 switch (acTStatus) { 00168 case GSM: 00169 case COMPACT_GSM: 00170 tr_info("Connected in GSM"); 00171 break; 00172 case UTRAN: 00173 tr_info("Connected to UTRAN"); 00174 break; 00175 case EDGE: 00176 tr_info("Connected to EDGE"); 00177 break; 00178 case HSDPA: 00179 tr_info("Connected to HSDPA"); 00180 break; 00181 case HSUPA: 00182 tr_info("Connected to HSPA"); 00183 break; 00184 case HSDPA_HSUPA: 00185 tr_info("Connected to HDPA/HSPA"); 00186 break; 00187 case LTE: 00188 tr_info("Connected to LTE"); 00189 break; 00190 case EC_GSM_IoT: 00191 tr_info("Connected to EC_GSM_IoT"); 00192 break; 00193 case E_UTRAN_NB_S1: 00194 tr_info("Connected to E_UTRAN NB1"); 00195 break; 00196 default: 00197 tr_info("Unknown RAT %d", acTStatus); 00198 break; 00199 } 00200 00201 _dev_info.rat = static_cast<RadioAccessNetworkType>(acTStatus); 00202 } 00203 00204 bool UbloxCellularBase::get_iccid() 00205 { 00206 bool success; 00207 LOCK(); 00208 00209 MBED_ASSERT(_at != NULL); 00210 00211 // Returns the ICCID (Integrated Circuit Card ID) of the SIM-card. 00212 // ICCID is a serial number identifying the SIM. 00213 // AT Command Manual UBX-13002752, section 4.12 00214 success = _at->send("AT+CCID") && _at->recv("+CCID: %20[^\n]\nOK\n", _dev_info.iccid); 00215 tr_info("DevInfo: ICCID=%s", _dev_info.iccid); 00216 00217 UNLOCK(); 00218 return success; 00219 } 00220 00221 bool UbloxCellularBase::get_imsi() 00222 { 00223 bool success; 00224 LOCK(); 00225 00226 MBED_ASSERT(_at != NULL); 00227 00228 // International mobile subscriber identification 00229 // AT Command Manual UBX-13002752, section 4.11 00230 success = _at->send("AT+CIMI") && _at->recv("%15[^\n]\nOK\n", _dev_info.imsi); 00231 tr_info("DevInfo: IMSI=%s", _dev_info.imsi); 00232 00233 UNLOCK(); 00234 return success; 00235 } 00236 00237 bool UbloxCellularBase::get_imei() 00238 { 00239 bool success; 00240 LOCK(); 00241 00242 MBED_ASSERT(_at != NULL); 00243 00244 // International mobile equipment identifier 00245 // AT Command Manual UBX-13002752, section 4.7 00246 success = _at->send("AT+CGSN") && _at->recv("%15[^\n]\nOK\n", _dev_info.imei); 00247 tr_info("DevInfo: IMEI=%s", _dev_info.imei); 00248 00249 UNLOCK(); 00250 return success; 00251 } 00252 00253 bool UbloxCellularBase::get_meid() 00254 { 00255 bool success; 00256 LOCK(); 00257 00258 MBED_ASSERT(_at != NULL); 00259 00260 // Mobile equipment identifier 00261 // AT Command Manual UBX-13002752, section 4.8 00262 success = _at->send("AT+GSN") && _at->recv("%18[^\n]\nOK\n", _dev_info.meid); 00263 tr_info("DevInfo: MEID=%s", _dev_info.meid); 00264 00265 UNLOCK(); 00266 return success; 00267 } 00268 00269 bool UbloxCellularBase::set_sms() 00270 { 00271 bool success = false; 00272 char buf[32]; 00273 LOCK(); 00274 00275 MBED_ASSERT(_at != NULL); 00276 00277 // Set up SMS format and enable URC 00278 // AT Command Manual UBX-13002752, section 11 00279 if (_at->send("AT+CMGF=1") && _at->recv("OK")) { 00280 tr_debug("SMS in text mode"); 00281 if (_at->send("AT+CNMI=2,1") && _at->recv("OK")) { 00282 tr_debug("SMS URC enabled"); 00283 // Set to CS preferred since PS preferred doesn't work 00284 // on some networks 00285 if (_at->send("AT+CGSMS=1") && _at->recv("OK")) { 00286 tr_debug("SMS set to CS preferred"); 00287 success = true; 00288 memset (buf, 0, sizeof (buf)); 00289 if (_at->send("AT+CSCA?") && 00290 _at->recv("+CSCA: \"%31[^\"]\"", buf) && 00291 _at->recv("OK")) { 00292 tr_info("SMS Service Centre address is \"%s\"", buf); 00293 } 00294 } 00295 } 00296 } 00297 00298 UNLOCK(); 00299 return success; 00300 } 00301 00302 void UbloxCellularBase::parser_abort_cb() 00303 { 00304 _at->abort(); 00305 } 00306 00307 // Callback for CME ERROR and CMS ERROR. 00308 void UbloxCellularBase::CMX_ERROR_URC() 00309 { 00310 char buf[48]; 00311 00312 if (read_at_to_char(buf, sizeof (buf), '\n') > 0) { 00313 tr_debug("AT error %s", buf); 00314 } 00315 parser_abort_cb(); 00316 } 00317 00318 // Callback for circuit switched registration URC. 00319 void UbloxCellularBase::CREG_URC() 00320 { 00321 char buf[10]; 00322 int status; 00323 int acTStatus; 00324 00325 // If this is the URC it will be a single 00326 // digit followed by \n. If it is the 00327 // answer to a CREG query, it will be 00328 // a ": %d,%d\n" where the second digit 00329 // indicates the status 00330 // Note: not calling _at->recv() from here as we're 00331 // already in an _at->recv() 00332 if (read_at_to_char(buf, sizeof (buf), '\n') > 0) { 00333 if (sscanf(buf, ": %*d,%d,%*d,%*d,%d,", &status, &acTStatus) == 2) { 00334 set_nwk_reg_status_csd(status); 00335 set_rat(acTStatus); 00336 } else if (sscanf(buf, ": %*d,%d", &status) == 1) { 00337 set_nwk_reg_status_csd(status); 00338 } else if (sscanf(buf, ": %d", &status) == 1) { 00339 set_nwk_reg_status_csd(status); 00340 } 00341 } 00342 } 00343 00344 // Callback for packet switched registration URC. 00345 void UbloxCellularBase::CGREG_URC() 00346 { 00347 char buf[10]; 00348 int status; 00349 int acTStatus; 00350 00351 // If this is the URC it will be a single 00352 // digit followed by \n. If it is the 00353 // answer to a CGREG query, it will be 00354 // a ": %d,%d\n" where the second digit 00355 // indicates the status 00356 // Note: not calling _at->recv() from here as we're 00357 // already in an _at->recv() 00358 if (read_at_to_char(buf, sizeof (buf), '\n') > 0) { 00359 if (sscanf(buf, ": %*d,%d,%*d,%*d,%d,", &status, &acTStatus) == 2) { 00360 set_nwk_reg_status_csd(status); 00361 set_rat(acTStatus); 00362 } else if (sscanf(buf, ": %*d,%d", &status) == 1) { 00363 set_nwk_reg_status_psd(status); 00364 } else if (sscanf(buf, ": %d", &status) == 1) { 00365 set_nwk_reg_status_psd(status); 00366 } 00367 } 00368 } 00369 00370 // Callback for EPS registration URC. 00371 void UbloxCellularBase::CEREG_URC() 00372 { 00373 char buf[10]; 00374 int status; 00375 int acTStatus; 00376 00377 // If this is the URC it will be a single 00378 // digit followed by \n. If it is the 00379 // answer to a CEREG query, it will be 00380 // a ": %d,%d\n" where the second digit 00381 // indicates the status 00382 // Note: not calling _at->recv() from here as we're 00383 // already in an _at->recv() 00384 if (read_at_to_char(buf, sizeof (buf), '\n') > 0) { 00385 if (sscanf(buf, ": %*d,%d,%*d,%*d,%d,", &status, &acTStatus) == 2) { 00386 set_nwk_reg_status_csd(status); 00387 set_rat(acTStatus); 00388 } else if (sscanf(buf, ": %*d,%d", &status) == 1) { 00389 set_nwk_reg_status_eps(status); 00390 } else if (sscanf(buf, ": %d", &status) == 1) { 00391 set_nwk_reg_status_eps(status); 00392 } 00393 } 00394 } 00395 00396 // Callback UMWI, just filtering it out. 00397 void UbloxCellularBase::UMWI_URC() 00398 { 00399 char buf[10]; 00400 00401 // Note: not calling _at->recv() from here as we're 00402 // already in an _at->recv() 00403 read_at_to_char(buf, sizeof (buf), '\n'); 00404 } 00405 00406 #ifdef TARGET_UBLOX_C030_R412M 00407 // Callback UUPSMR, set/clear flag for modem psm state. 00408 void UbloxCellularBase::UUPSMR_URC() 00409 { 00410 int status; 00411 char buf[10]; 00412 00413 if (read_at_to_char(buf, sizeof (buf), '\n') > 0) { 00414 if (sscanf(buf, ": %d", &status) == 1) { 00415 set_modem_psm_state(status); 00416 //call application registered callbacks 00417 if (status == AWAKE) { //modem coming out of sleep 00418 if (_func_psm_coming_out) { 00419 _func_psm_coming_out(_cb_param_psm_coming_out); 00420 } 00421 } else if(status == ASLEEP) { //modem going into sleep 00422 if (_func_psm_going_in) { 00423 _func_psm_going_in(_cb_param_psm_going_in); 00424 } 00425 } 00426 } 00427 } 00428 } 00429 #endif 00430 /********************************************************************** 00431 * PROTECTED METHODS 00432 **********************************************************************/ 00433 00434 #if MODEM_ON_BOARD 00435 void UbloxCellularBase::modem_init() 00436 { 00437 ::onboard_modem_init(); 00438 } 00439 00440 void UbloxCellularBase::modem_deinit() 00441 { 00442 ::onboard_modem_deinit(); 00443 } 00444 00445 void UbloxCellularBase::modem_power_up() 00446 { 00447 ::onboard_modem_power_up(); 00448 } 00449 00450 void UbloxCellularBase::modem_power_down() 00451 { 00452 ::onboard_modem_power_down(); 00453 } 00454 #else 00455 void UbloxCellularBase::modem_init() 00456 { 00457 // Meant to be overridden 00458 } 00459 00460 void UbloxCellularBase::modem_deinit() 00461 { 00462 // Meant to be overridden 00463 } 00464 00465 void UbloxCellularBase::modem_power_up() 00466 { 00467 // Meant to be overridden 00468 } 00469 00470 void UbloxCellularBase::modem_power_down() 00471 { 00472 // Mmeant to be overridden 00473 } 00474 #endif 00475 00476 // Constructor. 00477 // Note: to allow this base class to be inherited as a virtual base class 00478 // by everyone, it takes no parameters. See also comment above classInit() 00479 // in the header file. 00480 UbloxCellularBase::UbloxCellularBase() 00481 { 00482 _pin = NULL; 00483 _at = NULL; 00484 _at_timeout = AT_PARSER_TIMEOUT; 00485 _fh = NULL; 00486 _modem_initialised = false; 00487 _sim_pin_check_enabled = false; 00488 _debug_trace_on = false; 00489 00490 _dev_info.dev = DEV_TYPE_NONE; 00491 _dev_info.reg_status_csd = CSD_NOT_REGISTERED_NOT_SEARCHING; 00492 _dev_info.reg_status_psd = PSD_NOT_REGISTERED_NOT_SEARCHING; 00493 _dev_info.reg_status_eps = EPS_NOT_REGISTERED_NOT_SEARCHING; 00494 #ifdef TARGET_UBLOX_C030_R412M 00495 _dev_info.modem_psm_state = AWAKE; 00496 _psm_status = false; 00497 _cb_param_psm_going_in = NULL; 00498 _func_psm_going_in = NULL; 00499 _cb_param_psm_coming_out = NULL; 00500 _func_psm_coming_out = NULL; 00501 #endif 00502 } 00503 00504 // Destructor. 00505 UbloxCellularBase::~UbloxCellularBase() 00506 { 00507 deinit(); 00508 delete _at; 00509 delete _fh; 00510 } 00511 00512 // Initialise the portions of this class that are parameterised. 00513 void UbloxCellularBase::baseClassInit(PinName tx, PinName rx, 00514 int baud, bool debug_on) 00515 { 00516 // Only initialise ourselves if it's not already been done 00517 if (_at == NULL) { 00518 if (_debug_trace_on == false) { 00519 _debug_trace_on = debug_on; 00520 } 00521 _baud = baud; 00522 00523 // Set up File Handle for buffered serial comms with cellular module 00524 // (which will be used by the AT parser) 00525 // Note: the UART is initialised to run no faster than 115200 because 00526 // the modems cannot reliably auto-baud at faster rates. The faster 00527 // rate is adopted later with a specific AT command and the 00528 // UARTSerial rate is adjusted at that time 00529 if (baud > 115200) { 00530 baud = 115200; 00531 } 00532 _fh = new UARTSerial(tx, rx, baud); 00533 00534 // Set up the AT parser 00535 #ifdef TARGET_UBLOX_C030_R41XM 00536 _at = new UbloxATCmdParser(_fh, OUTPUT_ENTER_KEY, AT_PARSER_BUFFER_SIZE, 00537 _at_timeout, _debug_trace_on); 00538 #else 00539 _at = new ATCmdParser(_fh, OUTPUT_ENTER_KEY, AT_PARSER_BUFFER_SIZE, 00540 _at_timeout, _debug_trace_on); 00541 #endif 00542 00543 // Error cases, out of band handling 00544 _at->oob("ERROR", callback(this, &UbloxCellularBase::parser_abort_cb)); 00545 _at->oob("+CME ERROR", callback(this, &UbloxCellularBase::CMX_ERROR_URC)); 00546 _at->oob("+CMS ERROR", callback(this, &UbloxCellularBase::CMX_ERROR_URC)); 00547 00548 // Registration status, out of band handling 00549 _at->oob("+CREG", callback(this, &UbloxCellularBase::CREG_URC)); 00550 _at->oob("+CGREG", callback(this, &UbloxCellularBase::CGREG_URC)); 00551 _at->oob("+CEREG", callback(this, &UbloxCellularBase::CEREG_URC)); 00552 00553 // Capture the UMWI, just to stop it getting in the way 00554 _at->oob("+UMWI", callback(this, &UbloxCellularBase::UMWI_URC)); 00555 #ifdef TARGET_UBLOX_C030_R412M 00556 // Handle PSM URC for going in and coming out of PSM 00557 _at->oob("+UUPSMR", callback(this, &UbloxCellularBase::UUPSMR_URC)); 00558 #endif 00559 } 00560 } 00561 00562 // Set the AT parser timeout. 00563 // Note: the AT interface should be locked before this is called. 00564 void UbloxCellularBase::at_set_timeout(int timeout) { 00565 00566 MBED_ASSERT(_at != NULL); 00567 00568 _at_timeout = timeout; 00569 _at->set_timeout(timeout); 00570 } 00571 00572 // Read up to size bytes from the AT interface up to a "end". 00573 // Note: the AT interface should be locked before this is called. 00574 int UbloxCellularBase::read_at_to_char(char * buf, int size, char end) 00575 { 00576 int count = 0; 00577 int x = 0; 00578 00579 if (size > 0) { 00580 for (count = 0; (count < size) && (x >= 0) && (x != end); count++) { 00581 x = _at->getc(); 00582 *(buf + count) = (char) x; 00583 } 00584 00585 count--; 00586 *(buf + count) = 0; 00587 00588 // Convert line endings: 00589 // If end was '\n' (0x0a) and the preceding character was 0x0d, then 00590 // overwrite that with null as well. 00591 if ((count > 0) && (end == '\n') && (*(buf + count - 1) == '\x0d')) { 00592 count--; 00593 *(buf + count) = 0; 00594 } 00595 } 00596 00597 return count; 00598 } 00599 00600 // Power up the modem. 00601 // Enables the GPIO lines to the modem and then wriggles the power line in short pulses. 00602 bool UbloxCellularBase::power_up() 00603 { 00604 bool success = false; 00605 int at_timeout; 00606 LOCK(); 00607 00608 at_timeout = _at_timeout; // Has to be inside LOCK()s 00609 00610 MBED_ASSERT(_at != NULL); 00611 00612 /* Initialize GPIO lines */ 00613 tr_info("Powering up modem..."); 00614 modem_init(); 00615 /* Give modem a little time to settle down */ 00616 wait_ms(250); 00617 00618 for (int retry_count = 0; !success && (retry_count < 20); retry_count++) { 00619 //In case of SARA-R4, modem takes a while to turn on, constantly toggling the power pin every ~2 secs causes the modem to never power up. 00620 if ( (retry_count % 5) == 0) { 00621 modem_power_up(); 00622 } 00623 wait_ms(500); 00624 // Modem tends to spit out noise during power up - don't confuse the parser 00625 _at->flush(); 00626 at_set_timeout(1000); 00627 if (_at->send("AT")) { 00628 // C027 needs a delay here 00629 wait_ms(100); 00630 if (_at->recv("OK")) { 00631 success = true; 00632 } 00633 } 00634 at_set_timeout(at_timeout); 00635 } 00636 00637 if (success) { 00638 // Set the final baud rate 00639 if (_at->send("AT+IPR=%d", _baud) && _at->recv("OK")) { 00640 // Need to wait for things to be sorted out on the modem side 00641 wait_ms(100); 00642 ((UARTSerial *)_fh)->set_baud(_baud); 00643 } 00644 00645 // Turn off modem echoing and turn on verbose responses 00646 success = _at->send("ATE0;+CMEE=2") && _at->recv("OK") && 00647 // The following commands are best sent separately 00648 _at->send("AT&K0") && _at->recv("OK") && // Turn off RTC/CTS handshaking 00649 _at->send("AT&C1") && _at->recv("OK") && // Set DCD circuit(109), changes in accordance with the carrier detect status 00650 _at->send("AT&D0") && _at->recv("OK"); // Set DTR circuit, we ignore the state change of DTR 00651 } 00652 00653 if (!success) { 00654 tr_error("Preliminary modem setup failed."); 00655 } 00656 00657 UNLOCK(); 00658 return success; 00659 } 00660 00661 // Power down modem via AT interface. 00662 void UbloxCellularBase::power_down() 00663 { 00664 LOCK(); 00665 00666 MBED_ASSERT(_at != NULL); 00667 00668 // power-off modem 00669 modem_power_down(); 00670 modem_deinit(); 00671 00672 if (_modem_initialised && (_at != NULL)) { 00673 int at_timeout = _at_timeout; // Save previous timeout 00674 _at->set_timeout(1000); 00675 // Check modem is powered off 00676 if(_at->send("AT") && _at->recv("OK")) { 00677 _at->send("AT+CPWROFF") && _at->recv("OK"); 00678 } 00679 _at->set_timeout(at_timeout); 00680 } 00681 00682 _dev_info.reg_status_csd = CSD_NOT_REGISTERED_NOT_SEARCHING; 00683 _dev_info.reg_status_psd = PSD_NOT_REGISTERED_NOT_SEARCHING; 00684 _dev_info.reg_status_eps = EPS_NOT_REGISTERED_NOT_SEARCHING; 00685 00686 UNLOCK(); 00687 } 00688 00689 // Get the device ID. 00690 bool UbloxCellularBase::set_device_identity(DeviceType *dev) 00691 { 00692 char buf[20]; 00693 bool success; 00694 LOCK(); 00695 00696 MBED_ASSERT(_at != NULL); 00697 00698 success = _at->send("ATI") && _at->recv("%19[^\n]\nOK\n", buf); 00699 00700 if (success) { 00701 if (strstr(buf, "SARA-G35")) 00702 *dev = DEV_SARA_G35; 00703 else if (strstr(buf, "LISA-U200-03S")) 00704 *dev = DEV_LISA_U2_03S; 00705 else if (strstr(buf, "LISA-U2")) 00706 *dev = DEV_LISA_U2; 00707 else if (strstr(buf, "SARA-U2")) 00708 *dev = DEV_SARA_U2; 00709 else if (strstr(buf, "SARA-R4")) 00710 *dev = DEV_SARA_R4; 00711 else if (strstr(buf, "LEON-G2")) 00712 *dev = DEV_LEON_G2; 00713 else if (strstr(buf, "TOBY-L2")) 00714 *dev = DEV_TOBY_L2; 00715 else if (strstr(buf, "MPCI-L2")) 00716 *dev = DEV_MPCI_L2; 00717 } 00718 00719 UNLOCK(); 00720 return success; 00721 } 00722 00723 // Send initialisation AT commands that are specific to the device. 00724 bool UbloxCellularBase::device_init(DeviceType dev) 00725 { 00726 bool success = false; 00727 LOCK(); 00728 00729 MBED_ASSERT(_at != NULL); 00730 00731 if ((dev == DEV_LISA_U2) || (dev == DEV_LEON_G2) || (dev == DEV_TOBY_L2)) { 00732 success = _at->send("AT+UGPIOC=20,2") && _at->recv("OK"); 00733 } else if ((dev == DEV_SARA_U2) || (dev == DEV_SARA_G35)) { 00734 success = _at->send("AT+UGPIOC=16,2") && _at->recv("OK"); 00735 } else { 00736 success = true; 00737 } 00738 00739 UNLOCK(); 00740 return success; 00741 } 00742 00743 // Get the SIM card going. 00744 bool UbloxCellularBase::initialise_sim_card() 00745 { 00746 bool success = false; 00747 int retry_count = 0; 00748 bool done = false; 00749 LOCK(); 00750 00751 MBED_ASSERT(_at != NULL); 00752 00753 /* SIM initialisation may take a significant amount, so an error is 00754 * kind of expected. We should retry 10 times until we succeed or timeout. */ 00755 for (retry_count = 0; !done && (retry_count < 10); retry_count++) { 00756 char pinstr[16]; 00757 00758 if (_at->send("AT+CPIN?") && _at->recv("+CPIN: %15[^\n]\n", pinstr) && 00759 _at->recv("OK")) { 00760 done = true; 00761 if (strcmp(pinstr, "SIM PIN") == 0) { 00762 _sim_pin_check_enabled = true; 00763 if (_at->send("AT+CPIN=\"%s\"", _pin)) { 00764 if (_at->recv("OK")) { 00765 tr_info("PIN correct"); 00766 success = true; 00767 } else { 00768 tr_error("Incorrect PIN"); 00769 } 00770 } 00771 } else if (strcmp(pinstr, "READY") == 0) { 00772 _sim_pin_check_enabled = false; 00773 tr_info("No PIN required"); 00774 success = true; 00775 } else { 00776 tr_debug("Unexpected response from SIM: \"%s\"", pinstr); 00777 } 00778 } 00779 00780 /* wait for a second before retry */ 00781 wait_ms(1000); 00782 } 00783 00784 if (done) { 00785 tr_info("SIM Ready."); 00786 } else { 00787 tr_error("SIM not ready."); 00788 } 00789 00790 UNLOCK(); 00791 return success; 00792 } 00793 00794 /********************************************************************** 00795 * PUBLIC METHODS 00796 **********************************************************************/ 00797 00798 // Initialise the modem. 00799 bool UbloxCellularBase::init(const char *pin) 00800 { 00801 int x; 00802 MBED_ASSERT(_at != NULL); 00803 00804 if (!_modem_initialised) { 00805 if (power_up()) { 00806 tr_info("Modem Ready."); 00807 if (pin != NULL) { 00808 _pin = pin; 00809 } 00810 #ifdef TARGET_UBLOX_C027 00811 if (set_functionality_mode(FUNC_MIN)) { 00812 #else 00813 if (set_functionality_mode(FUNC_AIRPLANE)) { 00814 #endif 00815 if (initialise_sim_card()) { 00816 #ifdef TARGET_UBLOX_C030_R412M 00817 if (_psm_status == false) { //psm is not enabled by application yet so disable it at start-up 00818 set_power_saving_mode(0, 0); 00819 } 00820 #endif 00821 #ifdef TARGET_UBLOX_C030_R41XM 00822 if (_at->is_idle_mode_enabled() == false) { 00823 set_idle_mode(false); //disable idle mode at start up 00824 } 00825 #endif 00826 if (set_device_identity(&_dev_info.dev) && // Set up device identity 00827 device_init(_dev_info.dev)) {// Initialise this device 00828 // Get the integrated circuit ID of the SIM 00829 if (get_iccid()) { 00830 // Try a few times to get the IMSI (since on some modems this can 00831 // take a while to be retrieved, especially if a SIM PIN 00832 // was set) 00833 for (x = 0; (x < 3) && !get_imsi(); x++) { 00834 wait_ms(1000); 00835 } 00836 00837 if (x < 3) { // If we got the IMSI, can get the others 00838 if (get_imei() && // Get international mobile equipment identifier 00839 get_meid() && // Probably the same as the IMEI 00840 set_sms()) { // And set up SMS 00841 // The modem is initialised. 00842 _modem_initialised = true; 00843 } 00844 } 00845 } 00846 } 00847 } 00848 } 00849 } 00850 } 00851 00852 return _modem_initialised; 00853 } 00854 00855 // Perform registration. 00856 bool UbloxCellularBase::nwk_registration() 00857 { 00858 bool atSuccess = false; 00859 bool registered = false; 00860 int status; 00861 int at_timeout; 00862 LOCK(); 00863 00864 at_timeout = _at_timeout; // Has to be inside LOCK()s 00865 00866 MBED_ASSERT(_at != NULL); 00867 00868 if (!is_registered_psd() && !is_registered_csd() && !is_registered_eps()) { 00869 if (set_functionality_mode(FUNC_FULL)) { 00870 tr_info("Searching Network..."); 00871 // Enable the packet switched and network registration unsolicited result codes 00872 if (_at->send("AT+CREG=1") && _at->recv("OK") && 00873 _at->send("AT+CGREG=1") && _at->recv("OK")) { 00874 atSuccess = true; 00875 if (_at->send("AT+CEREG=1")) { 00876 _at->recv("OK"); 00877 // Don't check return value as this works for LTE only 00878 } 00879 00880 if (atSuccess) { 00881 // See if we are already in automatic mode 00882 if (_at->send("AT+COPS?") && _at->recv("+COPS: %d", &status) && 00883 _at->recv("OK")) { 00884 // If not, set it 00885 if (status != 0) { 00886 // Don't check return code here as there's not much 00887 // we can do if this fails. 00888 _at->send("AT+COPS=0") && _at->recv("OK"); 00889 } 00890 } 00891 00892 // Query the registration status directly as well, 00893 // just in case 00894 if (_at->send("AT+CREG?") && _at->recv("OK")) { 00895 // Answer will be processed by URC 00896 } 00897 if (_at->send("AT+CGREG?") && _at->recv("OK")) { 00898 // Answer will be processed by URC 00899 } 00900 if (_at->send("AT+CEREG?")) { 00901 _at->recv("OK"); 00902 // Don't check return value as this works for LTE only 00903 } 00904 } 00905 } 00906 // Wait for registration to succeed 00907 at_set_timeout(1000); 00908 for (int waitSeconds = 0; !registered && (waitSeconds < 180); waitSeconds++) { 00909 registered = is_registered_psd() || is_registered_csd() || is_registered_eps(); 00910 _at->recv(UNNATURAL_STRING); 00911 } 00912 at_set_timeout(at_timeout); 00913 00914 if (registered) { 00915 // This should return quickly but sometimes the status field is not returned 00916 // so make the timeout short 00917 at_set_timeout(1000); 00918 if (_at->send("AT+COPS?") && _at->recv("+COPS: %*d,%*d,\"%*[^\"]\",%d\n", &status)) { 00919 set_rat(status); 00920 } 00921 at_set_timeout(at_timeout); 00922 } 00923 } 00924 } else { 00925 registered = true; 00926 } 00927 00928 UNLOCK(); 00929 return registered; 00930 } 00931 00932 bool UbloxCellularBase::is_registered_csd() 00933 { 00934 return (_dev_info.reg_status_csd == CSD_REGISTERED) || 00935 (_dev_info.reg_status_csd == CSD_REGISTERED_ROAMING) || 00936 (_dev_info.reg_status_csd == CSD_CSFB_NOT_PREFERRED); 00937 } 00938 00939 bool UbloxCellularBase::is_registered_psd() 00940 { 00941 return (_dev_info.reg_status_psd == PSD_REGISTERED) || 00942 (_dev_info.reg_status_psd == PSD_REGISTERED_ROAMING); 00943 } 00944 00945 bool UbloxCellularBase::is_registered_eps() 00946 { 00947 return (_dev_info.reg_status_eps == EPS_REGISTERED) || 00948 (_dev_info.reg_status_eps == EPS_REGISTERED_ROAMING); 00949 } 00950 00951 // Perform deregistration. 00952 bool UbloxCellularBase::nwk_deregistration() 00953 { 00954 bool success = false; 00955 LOCK(); 00956 00957 MBED_ASSERT(_at != NULL); 00958 00959 if (_at->send("AT+COPS=2") && _at->recv("OK")) { 00960 _dev_info.reg_status_csd = CSD_NOT_REGISTERED_NOT_SEARCHING; 00961 _dev_info.reg_status_psd = PSD_NOT_REGISTERED_NOT_SEARCHING; 00962 _dev_info.reg_status_eps = EPS_NOT_REGISTERED_NOT_SEARCHING; 00963 success = true; 00964 } 00965 00966 UNLOCK(); 00967 return success; 00968 } 00969 00970 // Put the modem into its lowest power state. 00971 void UbloxCellularBase::deinit() 00972 { 00973 power_down(); 00974 _modem_initialised = false; 00975 } 00976 00977 // Set the PIN. 00978 void UbloxCellularBase::set_pin(const char *pin) { 00979 _pin = pin; 00980 } 00981 00982 // Enable or disable SIM pin checking. 00983 bool UbloxCellularBase::sim_pin_check_enable(bool enableNotDisable) 00984 { 00985 bool success = false;; 00986 LOCK(); 00987 00988 MBED_ASSERT(_at != NULL); 00989 00990 if (_pin != NULL) { 00991 if (_sim_pin_check_enabled && !enableNotDisable) { 00992 // Disable the SIM lock 00993 if (_at->send("AT+CLCK=\"SC\",0,\"%s\"", _pin) && _at->recv("OK")) { 00994 _sim_pin_check_enabled = false; 00995 success = true; 00996 } 00997 } else if (!_sim_pin_check_enabled && enableNotDisable) { 00998 // Enable the SIM lock 00999 if (_at->send("AT+CLCK=\"SC\",1,\"%s\"", _pin) && _at->recv("OK")) { 01000 _sim_pin_check_enabled = true; 01001 success = true; 01002 } 01003 } else { 01004 success = true; 01005 } 01006 } 01007 01008 UNLOCK(); 01009 return success; 01010 } 01011 01012 // Change the pin code for the SIM card. 01013 bool UbloxCellularBase::change_sim_pin(const char *pin) 01014 { 01015 bool success = false;; 01016 LOCK(); 01017 01018 MBED_ASSERT(_at != NULL); 01019 01020 // Change the SIM pin 01021 if ((pin != NULL) && (_pin != NULL)) { 01022 if (_at->send("AT+CPWD=\"SC\",\"%s\",\"%s\"", _pin, pin) && _at->recv("OK")) { 01023 _pin = pin; 01024 success = true; 01025 } 01026 } 01027 01028 UNLOCK(); 01029 return success; 01030 } 01031 01032 // Get the IMEI. 01033 bool UbloxCellularBase::get_imei(char *imei_to_send, int size) 01034 { 01035 bool success; 01036 LOCK(); 01037 01038 MBED_ASSERT(_at != NULL); 01039 01040 // International mobile equipment identifier 01041 // AT Command Manual UBX-13002752, section 4.7 01042 success = _at->send("AT+CGSN") && _at->recv("%15[^\n]\nOK\n", _dev_info.imei); 01043 tr_info("DevInfo: IMEI=%s", _dev_info.imei); 01044 01045 if (success) { 01046 memcpy(imei_to_send,_dev_info.imei,size); 01047 imei_to_send[size-1] = '\0'; 01048 } 01049 01050 UNLOCK(); 01051 return success; 01052 } 01053 01054 // Get the IMEI of the module. 01055 const char *UbloxCellularBase::imei() 01056 { 01057 return _dev_info.imei; 01058 } 01059 01060 // Get the Mobile Equipment ID (which may be the same as the IMEI). 01061 const char *UbloxCellularBase::meid() 01062 { 01063 return _dev_info.meid; 01064 } 01065 01066 // Get the IMSI of the SIM. 01067 const char *UbloxCellularBase::imsi() 01068 { 01069 // (try) to update the IMSI, just in case the SIM has changed 01070 get_imsi(); 01071 01072 return _dev_info.imsi; 01073 } 01074 01075 // Get the ICCID of the SIM. 01076 const char *UbloxCellularBase::iccid() 01077 { 01078 // (try) to update the ICCID, just in case the SIM has changed 01079 get_iccid(); 01080 01081 return _dev_info.iccid; 01082 } 01083 01084 // Get the RSSI in dBm. 01085 int UbloxCellularBase::rssi() 01086 { 01087 char buf[7] = {0}; 01088 int rssi = 0; 01089 int qual = 0; 01090 int rssiRet = 0; 01091 bool success; 01092 LOCK(); 01093 01094 MBED_ASSERT(_at != NULL); 01095 01096 success = _at->send("AT+CSQ") && _at->recv("+CSQ: %6[^\n]\nOK\n", buf); 01097 01098 if (success) { 01099 if (sscanf(buf, "%d,%d", &rssi, &qual) == 2) { 01100 // AT+CSQ returns a coded RSSI value and an RxQual value 01101 // For 2G an RSSI of 0 corresponds to -113 dBm or less, 01102 // an RSSI of 31 corresponds to -51 dBm or less and hence 01103 // each value is a 2 dB step. 01104 // For LTE the mapping is defined in the array rssiConvertLte[]. 01105 // For 3G the mapping to RSCP is defined in the array rscpConvert3G[] 01106 // and the RSSI value is then RSCP - the EC_NO_LEV number derived 01107 // by putting the qual number through qualConvert3G[]. 01108 if ((rssi >= 0) && (rssi <= 31)) { 01109 switch (_dev_info.rat) { 01110 case UTRAN: 01111 case HSDPA: 01112 case HSUPA: 01113 case HSDPA_HSUPA: 01114 // 3G 01115 if ((qual >= 0) && (qual <= 7)) { 01116 qual = qualConvert3G[qual]; 01117 rssiRet = rscpConvert3G[rssi]; 01118 rssiRet -= qual; 01119 } 01120 01121 break; 01122 case LTE: 01123 // LTE 01124 rssiRet = rssiConvertLte[rssi]; 01125 break; 01126 case GSM: 01127 case COMPACT_GSM: 01128 case EDGE: 01129 default: 01130 // GSM or assumed GSM if the RAT is not known 01131 rssiRet = -(113 - (rssi << 2)); 01132 break; 01133 } 01134 } 01135 } 01136 } 01137 01138 UNLOCK(); 01139 return rssiRet; 01140 } 01141 01142 //RAT should be set in a detached state (AT+COPS=2) 01143 bool UbloxCellularBase::set_modem_rat(RAT selected_rat, RAT preferred_rat, RAT second_preferred_rat) 01144 { 01145 bool success = false; 01146 char command[16] = {0x00}; 01147 01148 //check if modem is registered with network 01149 if (is_registered_csd() || is_registered_psd() || is_registered_eps()) { 01150 tr_error("RAT should only be set in detached state"); 01151 return false; 01152 } 01153 01154 if (preferred_rat != NOT_USED && second_preferred_rat != NOT_USED) { 01155 sprintf(command, "AT+URAT=%d,%d,%d", selected_rat, preferred_rat, second_preferred_rat); 01156 } else if (preferred_rat != NOT_USED) { 01157 sprintf(command, "AT+URAT=%d,%d", selected_rat, preferred_rat); 01158 } else if (second_preferred_rat != NOT_USED) { 01159 sprintf(command, "AT+URAT=%d,%d", selected_rat, second_preferred_rat); 01160 } else { 01161 sprintf(command, "AT+URAT=%d", selected_rat); 01162 } 01163 01164 LOCK(); 01165 if (_at->send(command) && _at->recv("OK")) { 01166 success = true; 01167 } else { 01168 tr_error("unable to set the specified RAT"); 01169 success = false; 01170 } 01171 UNLOCK(); 01172 01173 return success; 01174 } 01175 01176 bool UbloxCellularBase::get_modem_rat(int *selected_rat, int *preferred_rat, int *second_preferred_rat) 01177 { 01178 bool success = false; 01179 char buf[24] = {0x00}; 01180 01181 if (selected_rat == NULL || preferred_rat == NULL || second_preferred_rat == NULL) { 01182 tr_info("invalid pointers"); 01183 return false; 01184 } 01185 01186 MBED_ASSERT(_at != NULL); 01187 01188 *selected_rat = NOT_USED; 01189 *preferred_rat = NOT_USED; 01190 *second_preferred_rat = NOT_USED; 01191 01192 LOCK(); 01193 01194 if (_at->send("AT+URAT?") && _at->recv("%23[^\n]\nOK\n", buf)) { 01195 if (sscanf(buf, "+URAT: %d,%d,%d", selected_rat, preferred_rat, second_preferred_rat) == 3) { 01196 success = true; 01197 } else if (sscanf(buf, "+URAT: %d,%d", selected_rat, preferred_rat) == 2) { 01198 success = true; 01199 } else if (sscanf(buf, "+URAT: %d", selected_rat) == 1) { 01200 success = true; 01201 } 01202 } 01203 01204 UNLOCK(); 01205 return success; 01206 } 01207 01208 //application should call init() or connect() in order to initialize the modem 01209 bool UbloxCellularBase::reboot_modem() 01210 { 01211 return (set_functionality_mode(FUNC_RESET)); 01212 } 01213 01214 bool UbloxCellularBase::set_functionality_mode(FunctionalityMode mode) 01215 { 01216 bool return_val = false; 01217 int at_timeout; 01218 LOCK(); 01219 01220 MBED_ASSERT(_at != NULL); 01221 01222 at_timeout = _at_timeout; // Has to be inside LOCK()s 01223 at_set_timeout(3*60*1000); //command has 3 minutes timeout 01224 01225 if (_at->send("AT+CFUN=%d", mode) && _at->recv("OK")) { 01226 return_val = true; 01227 } 01228 01229 if (mode == FUNC_RESET || mode == FUNC_RESET_WITH_SIM) { 01230 _modem_initialised = false; 01231 } 01232 01233 at_set_timeout(at_timeout); 01234 UNLOCK(); 01235 01236 return return_val; 01237 } 01238 01239 bool UbloxCellularBase::get_functionality_mode(int *mode) 01240 { 01241 bool return_val = false; 01242 01243 if (mode == NULL) { 01244 return false; 01245 } 01246 01247 LOCK(); 01248 MBED_ASSERT(_at != NULL); 01249 01250 if ( (_at->send("AT+CFUN?") && _at->recv("+CFUN: %d", mode) && _at->recv("OK")) ) { 01251 return_val = true; 01252 } 01253 01254 UNLOCK(); 01255 return return_val; 01256 } 01257 01258 #ifdef TARGET_UBLOX_C030_R41XM 01259 bool UbloxCellularBase::set_mno_profile(MNOProfile profile) 01260 { 01261 bool return_val = false; 01262 01263 int mno_profile; 01264 if (get_mno_profile(&mno_profile)) { 01265 tr_info("Current MNO profile is: %d", mno_profile); 01266 if (mno_profile != profile) { 01267 01268 if (is_registered_csd() || is_registered_psd() || is_registered_eps()) { 01269 tr_error("MNO profile should only be set in detached state"); 01270 return false; 01271 } 01272 01273 LOCK(); 01274 if (_at->send("AT+UMNOPROF=%d", profile) && _at->recv("OK")) { 01275 return_val = true; 01276 } else { 01277 tr_error("unable to set specified profile"); 01278 } 01279 UNLOCK(); 01280 01281 } else { 01282 return_val = true; 01283 } 01284 } else { 01285 tr_error("could not read MNO profile"); 01286 } 01287 01288 return return_val; 01289 } 01290 01291 bool UbloxCellularBase::get_mno_profile(int *profile) 01292 { 01293 bool return_val = false; 01294 01295 if (profile == NULL) { 01296 return false; 01297 } 01298 01299 LOCK(); 01300 MBED_ASSERT(_at != NULL); 01301 01302 if ( (_at->send("AT+UMNOPROF?") && _at->recv("+UMNOPROF: %d", profile) && _at->recv("OK")) ) { 01303 return_val = true; 01304 } 01305 01306 UNLOCK(); 01307 return return_val; 01308 } 01309 // Enable or Disable the UPSV power saving mode 01310 bool UbloxCellularBase::set_idle_mode(bool enable) 01311 { 01312 #ifdef TARGET_UBLOX_C030_R412M 01313 if (_psm_status == true && enable == true) { 01314 return false; 01315 } 01316 #endif 01317 01318 bool success = false; 01319 LOCK(); 01320 01321 MBED_ASSERT(_at != NULL); 01322 01323 if (_at->send("AT+UPSV=%d", enable ? 4 : 0) && _at->recv("OK")) { 01324 if (enable == true) { 01325 _at->idle_mode_enabled(); 01326 } 01327 else { 01328 _at->idle_mode_disabled(); 01329 } 01330 success = true; 01331 } 01332 01333 UNLOCK(); 01334 return success; 01335 } 01336 01337 bool UbloxCellularBase::get_idle_mode(int *status) 01338 { 01339 bool return_val = false; 01340 01341 if (status == NULL) { 01342 return false; 01343 } 01344 01345 LOCK(); 01346 MBED_ASSERT(_at != NULL); 01347 01348 if ( (_at->send("AT+UPSV?") && _at->recv("+UPSV: %d", status) && _at->recv("OK")) ) { 01349 if (*status == 4) { 01350 *status = 1; 01351 } 01352 return_val = true; 01353 } 01354 01355 UNLOCK(); 01356 return return_val; 01357 } 01358 #endif 01359 01360 #ifdef TARGET_UBLOX_C030_R412M 01361 bool UbloxCellularBase::get_power_saving_mode(int *status, int *periodic_time, int *active_time) 01362 { 01363 char pt_encoded[8+1];// timer value encoded as 3GPP IE 01364 char at_encoded[8+1];// timer value encoded as 3GPP IE 01365 int value, multiplier; 01366 bool return_val; 01367 01368 if (status == NULL || periodic_time == NULL || active_time == NULL) { 01369 return false; 01370 } 01371 01372 LOCK(); 01373 //+UCPSMS:1,,,"01000011","01000011" 01374 if (_at->send("AT+UCPSMS?") && _at->recv("+UCPSMS:%d,,,\"%8c\",\"%8c\"\n", status, pt_encoded, at_encoded)) { 01375 if (*status == true) { 01376 //PSM is enabled, decode the timer values, periodic TAU first 01377 value = (pt_encoded[7]- '0'); 01378 value += (pt_encoded[6]- '0') << 1; 01379 value += (pt_encoded[5]- '0') << 2; 01380 value += (pt_encoded[4]- '0') << 3; 01381 value += (pt_encoded[3]- '0') << 4; 01382 01383 multiplier = (pt_encoded[2]- '0'); 01384 multiplier += (pt_encoded[1]- '0') << 1; 01385 multiplier += (pt_encoded[0]- '0') << 2; 01386 01387 switch(multiplier) { 01388 //10 minutes 01389 case 0: 01390 value = value*10*60; 01391 break; 01392 01393 //1 hour 01394 case 1: 01395 value = value*60*60; 01396 break; 01397 01398 //10 hours 01399 case 2: 01400 value = value*10*60*60; 01401 break; 01402 01403 //2 seconds 01404 case 3: 01405 value = value*2; 01406 break; 01407 01408 //30 seconds 01409 case 4: 01410 value = value*30; 01411 break; 01412 01413 //1 minute 01414 case 5: 01415 value = value*60; 01416 break; 01417 01418 //320 hours 01419 case 6: 01420 value = value*320*60*60; 01421 break; 01422 01423 default: 01424 value = 0; 01425 break; 01426 } 01427 *periodic_time = value; 01428 01429 //decode the active time 01430 value = (at_encoded[7]- '0'); 01431 value += (at_encoded[6]- '0') << 1; 01432 value += (at_encoded[5]- '0') << 2; 01433 value += (at_encoded[4]- '0') << 3; 01434 value += (at_encoded[3]- '0') << 4; 01435 01436 multiplier = (at_encoded[2]- '0'); 01437 multiplier += (at_encoded[1]- '0') << 1; 01438 multiplier += (at_encoded[0]- '0') << 2; 01439 01440 switch(multiplier) { 01441 //2 seconds 01442 case 0: 01443 value = value*2; 01444 break; 01445 01446 //1 minute 01447 case 1: 01448 value = value*60; 01449 break; 01450 01451 //decihours (6minutes) 01452 case 2: 01453 value = value*6*60; 01454 break; 01455 01456 default: 01457 value = 0; 01458 break; 01459 } 01460 *active_time = value; 01461 } 01462 return_val = true; 01463 } else { 01464 return_val = false; 01465 } 01466 UNLOCK(); 01467 return return_val; 01468 } 01469 01470 bool UbloxCellularBase::set_power_saving_mode(int periodic_time, int active_time) 01471 { 01472 if (_at->is_idle_mode_enabled() == true && periodic_time != 0 && active_time != 0 ) { 01473 return false; 01474 } 01475 bool return_val = false; 01476 01477 LOCK(); 01478 int at_timeout = _at_timeout; 01479 at_set_timeout(10000); //AT+CPSMS has response time of < 10s 01480 01481 //check if modem supports PSM URCs 01482 if (_at->send("AT+UPSMR?") && _at->recv("OK")) { 01483 if (periodic_time == 0 && active_time == 0) { 01484 // disable PSM 01485 if (_at->send("AT+CPSMS=0") && _at->recv("OK")) { 01486 if (_at->send("AT+UPSMR=0") && _at->recv("OK")) {//disable the URC 01487 //de-register the callback 01488 detach_cb_psm_going_in(); 01489 detach_cb_psm_coming_out(); 01490 _psm_status = false; 01491 return_val = true; 01492 } 01493 } 01494 } else { //PSM string encoding code borrowed from AT_CellularPower.cpp 01495 /** 01496 Table 10.5.163a/3GPP TS 24.008: GPRS Timer 3 information element 01497 01498 Bits 5 to 1 represent the binary coded timer value. 01499 01500 Bits 6 to 8 defines the timer value unit for the GPRS timer as follows: 01501 8 7 6 01502 0 0 0 value is incremented in multiples of 10 minutes 01503 0 0 1 value is incremented in multiples of 1 hour 01504 0 1 0 value is incremented in multiples of 10 hours 01505 0 1 1 value is incremented in multiples of 2 seconds 01506 1 0 0 value is incremented in multiples of 30 seconds 01507 1 0 1 value is incremented in multiples of 1 minute 01508 1 1 0 value is incremented in multiples of 320 hours (NOTE 1) 01509 1 1 1 value indicates that the timer is deactivated (NOTE 2). 01510 */ 01511 char pt[8+1];// timer value encoded as 3GPP IE 01512 const int ie_value_max = 0x1f; 01513 uint32_t periodic_timer = 0; 01514 if (periodic_time <= 2*ie_value_max) { // multiples of 2 seconds 01515 periodic_timer = periodic_time/2; 01516 strcpy(pt, "01100000"); 01517 } else { 01518 if (periodic_time <= 30*ie_value_max) { // multiples of 30 seconds 01519 periodic_timer = periodic_time/30; 01520 strcpy(pt, "10000000"); 01521 } else { 01522 if (periodic_time <= 60*ie_value_max) { // multiples of 1 minute 01523 periodic_timer = periodic_time/60; 01524 strcpy(pt, "10100000"); 01525 } else { 01526 if (periodic_time <= 10*60*ie_value_max) { // multiples of 10 minutes 01527 periodic_timer = periodic_time/(10*60); 01528 strcpy(pt, "00000000"); 01529 } else { 01530 if (periodic_time <= 60*60*ie_value_max) { // multiples of 1 hour 01531 periodic_timer = periodic_time/(60*60); 01532 strcpy(pt, "00100000"); 01533 } else { 01534 if (periodic_time <= 10*60*60*ie_value_max) { // multiples of 10 hours 01535 periodic_timer = periodic_time/(10*60*60); 01536 strcpy(pt, "01000000"); 01537 } else { // multiples of 320 hours 01538 int t = periodic_time / (320*60*60); 01539 if (t > ie_value_max) { 01540 t = ie_value_max; 01541 } 01542 periodic_timer = t; 01543 strcpy(pt, "11000000"); 01544 } 01545 } 01546 } 01547 } 01548 } 01549 } 01550 01551 uint_to_binary_str(periodic_timer, &pt[3], sizeof(pt)-3, 5); 01552 pt[8] = '\0'; 01553 01554 /** 01555 Table 10.5.172/3GPP TS 24.008: GPRS Timer information element 01556 01557 Bits 5 to 1 represent the binary coded timer value. 01558 01559 Bits 6 to 8 defines the timer value unit for the GPRS timer as follows: 01560 01561 8 7 6 01562 0 0 0 value is incremented in multiples of 2 seconds 01563 0 0 1 value is incremented in multiples of 1 minute 01564 0 1 0 value is incremented in multiples of decihours 01565 1 1 1 value indicates that the timer is deactivated. 01566 01567 Other values shall be interpreted as multiples of 1 minute in this version of the protocol. 01568 */ 01569 char at[8+1]; 01570 uint32_t active_timer; // timer value encoded as 3GPP IE 01571 if (active_time <= 2*ie_value_max) { // multiples of 2 seconds 01572 active_timer = active_time/2; 01573 strcpy(at, "00000000"); 01574 } else { 01575 if (active_time <= 60*ie_value_max) { // multiples of 1 minute 01576 active_timer = (1<<5) | (active_time/60); 01577 strcpy(at, "00100000"); 01578 } else { // multiples of decihours 01579 int t = active_time / (6*60); 01580 if (t > ie_value_max) { 01581 t = ie_value_max; 01582 } 01583 active_timer = t; 01584 strcpy(at, "01000000"); 01585 } 01586 } 01587 01588 uint_to_binary_str(active_timer, &at[3], sizeof(at)-3, 5); 01589 at[8] = '\0'; 01590 01591 if (_at->send("AT+CPSMS=1,,,\"%s\",\"%s\"", pt, at) && _at->recv("OK")) { 01592 if (_at->send("AT+UPSMR=1") && _at->recv("OK")) {//enable the PSM URC 01593 tr_info("PSM enabled successfully!"); 01594 _psm_status = true; 01595 return_val = true; 01596 } else { 01597 tr_error("PSM URCs not supported"); 01598 return_val = false; 01599 } 01600 } else { 01601 tr_error("+CPSMS command failed"); 01602 return_val = false; 01603 } 01604 } 01605 } else { 01606 tr_error("PSM URCs not supported by this version of modem"); 01607 } 01608 at_set_timeout(at_timeout); 01609 UNLOCK(); 01610 return return_val; 01611 } 01612 01613 void UbloxCellularBase::uint_to_binary_str(uint32_t num, char* str, int str_size, int bit_cnt) 01614 { 01615 if (!str || str_size < bit_cnt) { 01616 return; 01617 } 01618 int tmp, pos = 0; 01619 01620 for (int i = 31; i >= 0; i--) { 01621 tmp = num >> i; 01622 if (i < bit_cnt) { 01623 if (tmp&1) { 01624 str[pos] = 1 + '0'; 01625 } else { 01626 str[pos] = 0 + '0'; 01627 } 01628 pos++; 01629 } 01630 } 01631 } 01632 01633 bool UbloxCellularBase::is_modem_awake() 01634 { 01635 return (_dev_info.modem_psm_state == AWAKE); 01636 } 01637 01638 //application should call init() or connect() in order to initialize the modem 01639 void UbloxCellularBase::wakeup_modem() 01640 { 01641 LOCK(); 01642 01643 MBED_ASSERT(_at != NULL); 01644 01645 tr_info("Waking up modem..."); 01646 01647 modem_power_up(); 01648 01649 _dev_info.reg_status_csd = CSD_NOT_REGISTERED_NOT_SEARCHING; 01650 _dev_info.reg_status_psd = PSD_NOT_REGISTERED_NOT_SEARCHING; 01651 _dev_info.reg_status_eps = EPS_NOT_REGISTERED_NOT_SEARCHING; 01652 _modem_initialised = false; 01653 01654 UNLOCK(); 01655 } 01656 #endif 01657 // End of File 01658
Generated on Wed Aug 3 2022 16:33:26 by 1.7.2