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