ublox-cellular-base
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, bool disable_mno_params) 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 #ifdef TARGET_UBLOX_C030_R412M 00820 if (_psm_status == false) { //PSM is not yet configured by driver or application 00821 if (disable_mno_params) { 00822 set_power_saving_mode(0, 0); 00823 } else { 00824 int status = 0, periodic_time = 0, active_time = 0; 00825 if (get_power_saving_mode(&status, &periodic_time, &active_time)) { 00826 if (status) { //PSM is already enabled either by a previous run or MNO profile 00827 tr_info("PSM is already enabled, periodic_time %d, active_time %d", periodic_time, active_time); 00828 _psm_status = true; 00829 if ( !(set_psm_urcs(1)) ) { //enable PSM URCs 00830 tr_error("Modem does not support PSM URCs, disabling PSM"); 00831 set_power_saving_mode(0, 0); 00832 } 00833 } 00834 } 00835 } 00836 } 00837 #endif 00838 #ifdef TARGET_UBLOX_C030_R41XM 00839 if (_at->is_idle_mode_enabled() == false) { 00840 set_idle_mode(false); //disable idle mode at start up 00841 } 00842 int mno_profile; 00843 if (get_mno_profile(&mno_profile)) { 00844 tr_info("Current MNO profile is: %d", mno_profile); 00845 } 00846 #endif 00847 if (set_device_identity(&_dev_info.dev) && // Set up device identity 00848 device_init(_dev_info.dev)) {// Initialise this device 00849 // Get the integrated circuit ID of the SIM 00850 if (get_iccid()) { 00851 // Try a few times to get the IMSI (since on some modems this can 00852 // take a while to be retrieved, especially if a SIM PIN 00853 // was set) 00854 for (x = 0; (x < 3) && !get_imsi(); x++) { 00855 wait_ms(1000); 00856 } 00857 00858 if (x < 3) { // If we got the IMSI, can get the others 00859 if (get_imei() && // Get international mobile equipment identifier 00860 get_meid() && // Probably the same as the IMEI 00861 set_sms()) { // And set up SMS 00862 // The modem is initialised. 00863 _modem_initialised = true; 00864 tr_info("Modem initialized"); 00865 } 00866 } 00867 } 00868 } 00869 } 00870 } 00871 } 00872 } 00873 00874 return _modem_initialised; 00875 } 00876 00877 // Perform registration. 00878 bool UbloxCellularBase::nwk_registration() 00879 { 00880 bool atSuccess = false; 00881 bool registered = false; 00882 int status; 00883 int at_timeout; 00884 LOCK(); 00885 00886 at_timeout = _at_timeout; // Has to be inside LOCK()s 00887 00888 MBED_ASSERT(_at != NULL); 00889 00890 if (!is_registered_psd() && !is_registered_csd() && !is_registered_eps()) { 00891 if (set_functionality_mode(FUNC_FULL)) { 00892 tr_info("Searching Network..."); 00893 // Enable the packet switched and network registration unsolicited result codes 00894 if (_at->send("AT+CREG=1") && _at->recv("OK") && 00895 _at->send("AT+CGREG=1") && _at->recv("OK")) { 00896 atSuccess = true; 00897 if (_at->send("AT+CEREG=1")) { 00898 _at->recv("OK"); 00899 // Don't check return value as this works for LTE only 00900 } 00901 00902 if (atSuccess) { 00903 // See if we are already in automatic mode 00904 if (_at->send("AT+COPS?") && _at->recv("+COPS: %d", &status) && 00905 _at->recv("OK")) { 00906 // If not, set it 00907 if (status != 0) { 00908 // Don't check return code here as there's not much 00909 // we can do if this fails. 00910 _at->send("AT+COPS=0") && _at->recv("OK"); 00911 } 00912 } 00913 00914 // Query the registration status directly as well, 00915 // just in case 00916 if (_at->send("AT+CREG?") && _at->recv("OK")) { 00917 // Answer will be processed by URC 00918 } 00919 if (_at->send("AT+CGREG?") && _at->recv("OK")) { 00920 // Answer will be processed by URC 00921 } 00922 if (_at->send("AT+CEREG?")) { 00923 _at->recv("OK"); 00924 // Don't check return value as this works for LTE only 00925 } 00926 } 00927 } 00928 // Wait for registration to succeed 00929 at_set_timeout(1000); 00930 for (int waitSeconds = 0; !registered && (waitSeconds < 180); waitSeconds++) { 00931 registered = is_registered_psd() || is_registered_csd() || is_registered_eps(); 00932 _at->recv(UNNATURAL_STRING); 00933 } 00934 at_set_timeout(at_timeout); 00935 00936 if (registered) { 00937 // This should return quickly but sometimes the status field is not returned 00938 // so make the timeout short 00939 at_set_timeout(1000); 00940 if (_at->send("AT+COPS?") && _at->recv("+COPS: %*d,%*d,\"%*[^\"]\",%d\n", &status)) { 00941 set_rat(status); 00942 } 00943 at_set_timeout(at_timeout); 00944 } 00945 } 00946 } else { 00947 registered = true; 00948 } 00949 00950 UNLOCK(); 00951 return registered; 00952 } 00953 00954 bool UbloxCellularBase::is_registered_csd() 00955 { 00956 return (_dev_info.reg_status_csd == CSD_REGISTERED) || 00957 (_dev_info.reg_status_csd == CSD_REGISTERED_ROAMING) || 00958 (_dev_info.reg_status_csd == CSD_CSFB_NOT_PREFERRED); 00959 } 00960 00961 bool UbloxCellularBase::is_registered_psd() 00962 { 00963 return (_dev_info.reg_status_psd == PSD_REGISTERED) || 00964 (_dev_info.reg_status_psd == PSD_REGISTERED_ROAMING); 00965 } 00966 00967 bool UbloxCellularBase::is_registered_eps() 00968 { 00969 return (_dev_info.reg_status_eps == EPS_REGISTERED) || 00970 (_dev_info.reg_status_eps == EPS_REGISTERED_ROAMING); 00971 } 00972 00973 // Perform deregistration. 00974 bool UbloxCellularBase::nwk_deregistration() 00975 { 00976 bool success = false; 00977 LOCK(); 00978 00979 MBED_ASSERT(_at != NULL); 00980 00981 int at_timeout = _at_timeout; // Has to be inside LOCK()s 00982 at_set_timeout(3*60*1000); //command has 3 minutes timeout 00983 00984 if (_at->send("AT+COPS=2") && _at->recv("OK")) { 00985 _dev_info.reg_status_csd = CSD_NOT_REGISTERED_NOT_SEARCHING; 00986 _dev_info.reg_status_psd = PSD_NOT_REGISTERED_NOT_SEARCHING; 00987 _dev_info.reg_status_eps = EPS_NOT_REGISTERED_NOT_SEARCHING; 00988 success = true; 00989 } 00990 00991 at_set_timeout(at_timeout); 00992 UNLOCK(); 00993 return success; 00994 } 00995 00996 // Put the modem into its lowest power state. 00997 void UbloxCellularBase::deinit() 00998 { 00999 power_down(); 01000 _modem_initialised = false; 01001 } 01002 01003 // Set the PIN. 01004 void UbloxCellularBase::set_pin(const char *pin) { 01005 _pin = pin; 01006 } 01007 01008 // Enable or disable SIM pin checking. 01009 bool UbloxCellularBase::sim_pin_check_enable(bool enableNotDisable) 01010 { 01011 bool success = false;; 01012 LOCK(); 01013 01014 MBED_ASSERT(_at != NULL); 01015 01016 if (_pin != NULL) { 01017 if (_sim_pin_check_enabled && !enableNotDisable) { 01018 // Disable the SIM lock 01019 if (_at->send("AT+CLCK=\"SC\",0,\"%s\"", _pin) && _at->recv("OK")) { 01020 _sim_pin_check_enabled = false; 01021 success = true; 01022 } 01023 } else if (!_sim_pin_check_enabled && enableNotDisable) { 01024 // Enable the SIM lock 01025 if (_at->send("AT+CLCK=\"SC\",1,\"%s\"", _pin) && _at->recv("OK")) { 01026 _sim_pin_check_enabled = true; 01027 success = true; 01028 } 01029 } else { 01030 success = true; 01031 } 01032 } 01033 01034 UNLOCK(); 01035 return success; 01036 } 01037 01038 // Change the pin code for the SIM card. 01039 bool UbloxCellularBase::change_sim_pin(const char *pin) 01040 { 01041 bool success = false;; 01042 LOCK(); 01043 01044 MBED_ASSERT(_at != NULL); 01045 01046 // Change the SIM pin 01047 if ((pin != NULL) && (_pin != NULL)) { 01048 if (_at->send("AT+CPWD=\"SC\",\"%s\",\"%s\"", _pin, pin) && _at->recv("OK")) { 01049 _pin = pin; 01050 success = true; 01051 } 01052 } 01053 01054 UNLOCK(); 01055 return success; 01056 } 01057 01058 // Get the IMEI. 01059 bool UbloxCellularBase::get_imei(char *imei_to_send, int size) 01060 { 01061 bool success; 01062 LOCK(); 01063 01064 MBED_ASSERT(_at != NULL); 01065 01066 // International mobile equipment identifier 01067 // AT Command Manual UBX-13002752, section 4.7 01068 success = _at->send("AT+CGSN") && _at->recv("%15[^\n]\nOK\n", _dev_info.imei); 01069 tr_info("DevInfo: IMEI=%s", _dev_info.imei); 01070 01071 if (success) { 01072 memcpy(imei_to_send,_dev_info.imei,size); 01073 imei_to_send[size-1] = '\0'; 01074 } 01075 01076 UNLOCK(); 01077 return success; 01078 } 01079 01080 // Get the IMEI of the module. 01081 const char *UbloxCellularBase::imei() 01082 { 01083 return _dev_info.imei; 01084 } 01085 01086 // Get the Mobile Equipment ID (which may be the same as the IMEI). 01087 const char *UbloxCellularBase::meid() 01088 { 01089 return _dev_info.meid; 01090 } 01091 01092 // Get the IMSI of the SIM. 01093 const char *UbloxCellularBase::imsi() 01094 { 01095 // (try) to update the IMSI, just in case the SIM has changed 01096 get_imsi(); 01097 01098 return _dev_info.imsi; 01099 } 01100 01101 // Get the ICCID of the SIM. 01102 const char *UbloxCellularBase::iccid() 01103 { 01104 // (try) to update the ICCID, just in case the SIM has changed 01105 get_iccid(); 01106 01107 return _dev_info.iccid; 01108 } 01109 01110 // Get the RSSI in dBm. 01111 int UbloxCellularBase::rssi() 01112 { 01113 char buf[7] = {0}; 01114 int rssi = 0; 01115 int qual = 0; 01116 int rssiRet = 0; 01117 bool success; 01118 LOCK(); 01119 01120 MBED_ASSERT(_at != NULL); 01121 01122 success = _at->send("AT+CSQ") && _at->recv("+CSQ: %6[^\n]\nOK\n", buf); 01123 01124 if (success) { 01125 if (sscanf(buf, "%d,%d", &rssi, &qual) == 2) { 01126 // AT+CSQ returns a coded RSSI value and an RxQual value 01127 // For 2G an RSSI of 0 corresponds to -113 dBm or less, 01128 // an RSSI of 31 corresponds to -51 dBm or less and hence 01129 // each value is a 2 dB step. 01130 // For LTE the mapping is defined in the array rssiConvertLte[]. 01131 // For 3G the mapping to RSCP is defined in the array rscpConvert3G[] 01132 // and the RSSI value is then RSCP - the EC_NO_LEV number derived 01133 // by putting the qual number through qualConvert3G[]. 01134 if ((rssi >= 0) && (rssi <= 31)) { 01135 switch (_dev_info.rat) { 01136 case UTRAN: 01137 case HSDPA: 01138 case HSUPA: 01139 case HSDPA_HSUPA: 01140 // 3G 01141 if ((qual >= 0) && (qual <= 7)) { 01142 qual = qualConvert3G[qual]; 01143 rssiRet = rscpConvert3G[rssi]; 01144 rssiRet -= qual; 01145 } 01146 01147 break; 01148 case LTE: 01149 // LTE 01150 rssiRet = rssiConvertLte[rssi]; 01151 break; 01152 case GSM: 01153 case COMPACT_GSM: 01154 case EDGE: 01155 default: 01156 // GSM or assumed GSM if the RAT is not known 01157 rssiRet = -(113 - (rssi << 2)); 01158 break; 01159 } 01160 } 01161 } 01162 } 01163 01164 UNLOCK(); 01165 return rssiRet; 01166 } 01167 01168 //RAT should be set in a detached state (AT+COPS=2) 01169 bool UbloxCellularBase::set_modem_rat(RAT selected_rat, RAT preferred_rat, RAT second_preferred_rat) 01170 { 01171 bool success = false; 01172 char command[16] = {0x00}; 01173 01174 //check if modem is registered with network 01175 if (is_registered_csd() || is_registered_psd() || is_registered_eps()) { 01176 tr_error("RAT should only be set in detached state"); 01177 return false; 01178 } 01179 01180 if (preferred_rat != NOT_USED && second_preferred_rat != NOT_USED) { 01181 sprintf(command, "AT+URAT=%d,%d,%d", selected_rat, preferred_rat, second_preferred_rat); 01182 } else if (preferred_rat != NOT_USED) { 01183 sprintf(command, "AT+URAT=%d,%d", selected_rat, preferred_rat); 01184 } else if (second_preferred_rat != NOT_USED) { 01185 sprintf(command, "AT+URAT=%d,%d", selected_rat, second_preferred_rat); 01186 } else { 01187 sprintf(command, "AT+URAT=%d", selected_rat); 01188 } 01189 01190 LOCK(); 01191 if (_at->send(command) && _at->recv("OK")) { 01192 success = true; 01193 } else { 01194 tr_error("unable to set the specified RAT"); 01195 success = false; 01196 } 01197 UNLOCK(); 01198 01199 return success; 01200 } 01201 01202 bool UbloxCellularBase::get_modem_rat(int *selected_rat, int *preferred_rat, int *second_preferred_rat) 01203 { 01204 bool success = false; 01205 char buf[24] = {0x00}; 01206 01207 if (selected_rat == NULL || preferred_rat == NULL || second_preferred_rat == NULL) { 01208 tr_info("invalid pointers"); 01209 return false; 01210 } 01211 01212 MBED_ASSERT(_at != NULL); 01213 01214 *selected_rat = NOT_USED; 01215 *preferred_rat = NOT_USED; 01216 *second_preferred_rat = NOT_USED; 01217 01218 LOCK(); 01219 01220 if (_at->send("AT+URAT?") && _at->recv("%23[^\n]\nOK\n", buf)) { 01221 if (sscanf(buf, "+URAT: %d,%d,%d", selected_rat, preferred_rat, second_preferred_rat) == 3) { 01222 success = true; 01223 } else if (sscanf(buf, "+URAT: %d,%d", selected_rat, preferred_rat) == 2) { 01224 success = true; 01225 } else if (sscanf(buf, "+URAT: %d", selected_rat) == 1) { 01226 success = true; 01227 } 01228 } 01229 01230 UNLOCK(); 01231 return success; 01232 } 01233 01234 //application should call init() or connect() in order to initialize the modem 01235 bool UbloxCellularBase::reboot_modem() 01236 { 01237 return (set_functionality_mode(FUNC_RESET)); 01238 } 01239 01240 bool UbloxCellularBase::set_functionality_mode(FunctionalityMode mode) 01241 { 01242 bool return_val = false; 01243 int at_timeout; 01244 LOCK(); 01245 01246 MBED_ASSERT(_at != NULL); 01247 01248 at_timeout = _at_timeout; // Has to be inside LOCK()s 01249 at_set_timeout(3*60*1000); //command has 3 minutes timeout 01250 01251 if (_at->send("AT+CFUN=%d", mode) && _at->recv("OK")) { 01252 return_val = true; 01253 } 01254 01255 if (mode == FUNC_RESET || mode == FUNC_RESET_WITH_SIM) { 01256 _modem_initialised = false; 01257 } 01258 01259 at_set_timeout(at_timeout); 01260 UNLOCK(); 01261 01262 return return_val; 01263 } 01264 01265 bool UbloxCellularBase::get_functionality_mode(int *mode) 01266 { 01267 bool return_val = false; 01268 01269 if (mode == NULL) { 01270 return false; 01271 } 01272 01273 LOCK(); 01274 MBED_ASSERT(_at != NULL); 01275 01276 if ( (_at->send("AT+CFUN?") && _at->recv("+CFUN: %d", mode) && _at->recv("OK")) ) { 01277 return_val = true; 01278 } 01279 01280 UNLOCK(); 01281 return return_val; 01282 } 01283 01284 #ifdef TARGET_UBLOX_C030_R41XM 01285 bool UbloxCellularBase::set_mno_profile(MNOProfile profile) 01286 { 01287 bool return_val = false; 01288 int current_profile; 01289 MNOProfile arr[MAX_NUM_PROFILES] = { SW_DEFAULT, SIM_ICCID, ATT, TMO, VODAFONE, DT, STANDARD_EU 01290 #ifdef TARGET_UBLOX_C030_R410M 01291 , VERIZON, TELSTRA, CT, SPRINT, TELUS 01292 #endif 01293 }; 01294 01295 if (is_registered_csd() || is_registered_psd() || is_registered_eps()) { 01296 tr_error("MNO profile should only be set in detached state"); 01297 return false; 01298 } 01299 01300 if (get_mno_profile(¤t_profile)) { 01301 if (current_profile == profile) { //Ref to UBX-18019856 7.1.7, parameters will be updated only if we switch to another profile first 01302 for (uint8_t index = 0; index < MAX_NUM_PROFILES; index++) { //get the index of current profile and use the next one 01303 if (arr[index] == current_profile) { 01304 index = ((index + 1) % MAX_NUM_PROFILES); 01305 current_profile = arr[index]; 01306 break; 01307 } 01308 } 01309 01310 LOCK(); 01311 if (_at->send("AT+UMNOPROF=%d", current_profile) && _at->recv("OK")) { 01312 tr_error("temporary MNO profile set: %d", current_profile); 01313 } 01314 UNLOCK(); 01315 } 01316 LOCK(); 01317 if (_at->send("AT+UMNOPROF=%d", profile) && _at->recv("OK")) { 01318 return_val = true; 01319 } else { 01320 tr_error("unable to set user specified profile"); 01321 } 01322 UNLOCK(); 01323 } else { 01324 tr_error("could not read MNO profile"); 01325 } 01326 01327 return return_val; 01328 } 01329 01330 bool UbloxCellularBase::get_mno_profile(int *profile) 01331 { 01332 bool return_val = false; 01333 char buf[4] = {0x00}; 01334 01335 if (profile == NULL) { 01336 return false; 01337 } 01338 01339 LOCK(); 01340 MBED_ASSERT(_at != NULL); 01341 01342 if (_at->send("AT+UMNOPROF?") && _at->recv("+UMNOPROF: %3[^\n]\nOK\n", buf)) { 01343 *profile = atoi(buf); 01344 return_val = true; 01345 } 01346 01347 UNLOCK(); 01348 return return_val; 01349 } 01350 // Enable or Disable the UPSV power saving mode 01351 bool UbloxCellularBase::set_idle_mode(bool enable) 01352 { 01353 #ifdef TARGET_UBLOX_C030_R412M 01354 if (_psm_status == true && enable == true) { 01355 return false; 01356 } 01357 #endif 01358 01359 bool success = false; 01360 LOCK(); 01361 01362 MBED_ASSERT(_at != NULL); 01363 01364 if (_at->send("AT+UPSV=%d", enable ? 4 : 0) && _at->recv("OK")) { 01365 if (enable == true) { 01366 _at->idle_mode_enabled(); 01367 } 01368 else { 01369 _at->idle_mode_disabled(); 01370 } 01371 success = true; 01372 } 01373 01374 UNLOCK(); 01375 return success; 01376 } 01377 01378 bool UbloxCellularBase::get_idle_mode(int *status) 01379 { 01380 bool return_val = false; 01381 01382 if (status == NULL) { 01383 return false; 01384 } 01385 01386 LOCK(); 01387 MBED_ASSERT(_at != NULL); 01388 01389 if ( (_at->send("AT+UPSV?") && _at->recv("+UPSV: %d", status) && _at->recv("OK")) ) { 01390 if (*status == 4) { 01391 *status = 1; 01392 } 01393 return_val = true; 01394 } 01395 01396 UNLOCK(); 01397 return return_val; 01398 } 01399 01400 int UbloxCellularBase::set_receive_period(int mode, tEDRXAccessTechnology act_type, uint8_t edrx_value) { 01401 char edrx[5]; 01402 uint_to_binary_str(edrx_value, edrx, 5, 4); 01403 edrx[4] = '\0'; 01404 int status = 1; 01405 01406 LOCK(); 01407 01408 if (_at->send("AT+CEDRXS=%d,%d,\"%s\"", mode, act_type, edrx) && _at->recv("OK")) { 01409 _edrx_configured = true; 01410 status = 0; 01411 } 01412 else { 01413 status = 1; 01414 } 01415 01416 01417 UNLOCK(); 01418 01419 return status; 01420 } 01421 01422 int UbloxCellularBase::set_receive_period(int mode, tEDRXAccessTechnology act_type) { 01423 int status = 1; 01424 01425 LOCK(); 01426 01427 if (_at->send("AT+CEDRXS=%d,%d", mode, act_type) && _at->recv("OK")) { 01428 01429 status = 0; 01430 } 01431 else { 01432 status = 1; 01433 } 01434 01435 UNLOCK(); 01436 01437 return status; 01438 } 01439 01440 int UbloxCellularBase::set_receive_period(int mode) { 01441 int status = 1; 01442 01443 LOCK(); 01444 01445 if (_at->send("AT+CEDRXS=%d", mode) && _at->recv("OK")) { 01446 01447 status = 0; 01448 } 01449 else { 01450 status = 1; 01451 } 01452 01453 UNLOCK(); 01454 01455 return status; 01456 } 01457 01458 uint32_t UbloxCellularBase::get_receive_period() { 01459 uint32_t edrx_value = 2; 01460 char buf[24] = {0x00}; 01461 char edrx_val[5]; 01462 tEDRXAccessTechnology act_type; 01463 01464 LOCK(); 01465 01466 if (_at->send("AT+CEDRXS?") && _at->recv("%23[^\n]\nOK\n", buf)) { 01467 if (sscanf(buf, "+CEDRXS: %d,\"%s\"", (int *)&act_type, edrx_val) == 2) { 01468 01469 edrx_value = binary_str_to_uint(edrx_val,4); 01470 } 01471 } 01472 01473 if (_at->send("AT+CEDRXRDP") && _at->recv("OK")) { 01474 } 01475 01476 tr_info("edrx_value. %d", edrx_value); 01477 01478 UNLOCK(); 01479 return edrx_value; 01480 } 01481 01482 void UbloxCellularBase::uint_to_binary_str(uint32_t num, char* str, int str_size, int bit_cnt) 01483 { 01484 if (!str || str_size < bit_cnt) { 01485 return; 01486 } 01487 int tmp, pos = 0; 01488 01489 for (int i = 31; i >= 0; i--) { 01490 tmp = num >> i; 01491 if (i < bit_cnt) { 01492 if (tmp&1) { 01493 str[pos] = 1 + '0'; 01494 } else { 01495 str[pos] = 0 + '0'; 01496 } 01497 pos++; 01498 } 01499 } 01500 } 01501 01502 uint32_t UbloxCellularBase::binary_str_to_uint(const char *binary_string, int binary_string_length) 01503 { 01504 if (!binary_string || !binary_string_length) { 01505 return 0; 01506 } 01507 01508 int integer_output = 0, base_exp = 1; 01509 01510 for (int i = binary_string_length - 1; i >= 0; i--) { 01511 if (binary_string[i] == '1') { 01512 integer_output += (base_exp << (binary_string_length - (i+1))); 01513 } 01514 } 01515 01516 return integer_output; 01517 } 01518 01519 bool UbloxCellularBase::set_band_bitmask(RAT rat, uint64_t bitmask) { 01520 01521 bool status = false; 01522 UBandmaskRAT eBandMastRat; 01523 01524 if(rat == LTE_CATM1) { 01525 eBandMastRat = UBANDMASK_RAT_LTE_CATM1; 01526 } 01527 else if(rat == LTE_CATNB1) { 01528 eBandMastRat = UBANDMASK_RAT_LTE_CATNB1; 01529 } 01530 else { 01531 tr_error("Invalid RAT for Band mask selection: %d", rat); 01532 01533 return false; 01534 } 01535 01536 tr_info("UBANDMASK RAT %d, bitmask : %llu", eBandMastRat, bitmask); 01537 01538 LOCK(); 01539 01540 if (_at->send("AT+UBANDMASK=%d,%llu", eBandMastRat, bitmask) && _at->recv("OK")) { 01541 01542 status = true; 01543 } 01544 UNLOCK(); 01545 01546 return status; 01547 } 01548 #endif //TARGET_UBLOX_C030_R41XM 01549 01550 #ifdef TARGET_UBLOX_C030_R412M 01551 bool UbloxCellularBase::get_power_saving_mode(int *status, int *periodic_time, int *active_time) 01552 { 01553 char pt_encoded[8+1];// timer value encoded as 3GPP IE 01554 char at_encoded[8+1];// timer value encoded as 3GPP IE 01555 int value, multiplier; 01556 bool return_val; 01557 01558 if (status == NULL || periodic_time == NULL || active_time == NULL) { 01559 return false; 01560 } 01561 01562 LOCK(); 01563 //+UCPSMS:1,,,"01000011","01000011" 01564 if (_at->send("AT+UCPSMS?") && _at->recv("+UCPSMS:%d,,,\"%8c\",\"%8c\"\nOK\n", status, pt_encoded, at_encoded)) { 01565 if (*status == true) { 01566 //PSM is enabled, decode the timer values, periodic TAU first 01567 value = (pt_encoded[7]- '0'); 01568 value += (pt_encoded[6]- '0') << 1; 01569 value += (pt_encoded[5]- '0') << 2; 01570 value += (pt_encoded[4]- '0') << 3; 01571 value += (pt_encoded[3]- '0') << 4; 01572 01573 multiplier = (pt_encoded[2]- '0'); 01574 multiplier += (pt_encoded[1]- '0') << 1; 01575 multiplier += (pt_encoded[0]- '0') << 2; 01576 01577 switch(multiplier) { 01578 //10 minutes 01579 case 0: 01580 value = value*10*60; 01581 break; 01582 01583 //1 hour 01584 case 1: 01585 value = value*60*60; 01586 break; 01587 01588 //10 hours 01589 case 2: 01590 value = value*10*60*60; 01591 break; 01592 01593 //2 seconds 01594 case 3: 01595 value = value*2; 01596 break; 01597 01598 //30 seconds 01599 case 4: 01600 value = value*30; 01601 break; 01602 01603 //1 minute 01604 case 5: 01605 value = value*60; 01606 break; 01607 01608 //320 hours 01609 case 6: 01610 value = value*320*60*60; 01611 break; 01612 01613 default: 01614 value = 0; 01615 break; 01616 } 01617 *periodic_time = value; 01618 01619 //decode the active time 01620 value = (at_encoded[7]- '0'); 01621 value += (at_encoded[6]- '0') << 1; 01622 value += (at_encoded[5]- '0') << 2; 01623 value += (at_encoded[4]- '0') << 3; 01624 value += (at_encoded[3]- '0') << 4; 01625 01626 multiplier = (at_encoded[2]- '0'); 01627 multiplier += (at_encoded[1]- '0') << 1; 01628 multiplier += (at_encoded[0]- '0') << 2; 01629 01630 switch(multiplier) { 01631 //2 seconds 01632 case 0: 01633 value = value*2; 01634 break; 01635 01636 //1 minute 01637 case 1: 01638 value = value*60; 01639 break; 01640 01641 //decihours (6minutes) 01642 case 2: 01643 value = value*6*60; 01644 break; 01645 01646 default: 01647 value = 0; 01648 break; 01649 } 01650 *active_time = value; 01651 } 01652 return_val = true; 01653 } else { 01654 return_val = false; 01655 } 01656 UNLOCK(); 01657 return return_val; 01658 } 01659 01660 bool UbloxCellularBase::set_power_saving_mode(int periodic_time, int active_time) 01661 { 01662 if (_at->is_idle_mode_enabled() == true && periodic_time != 0 && active_time != 0 ) { 01663 return false; 01664 } 01665 bool return_val = false; 01666 01667 LOCK(); 01668 int at_timeout = _at_timeout; 01669 at_set_timeout(10000); //AT+CPSMS has response time of < 10s 01670 01671 //check if modem supports PSM URCs 01672 if (_at->send("AT+UPSMR?") && _at->recv("OK")) { 01673 if (periodic_time == 0 && active_time == 0) { 01674 // disable PSM 01675 if (_at->send("AT+CPSMS=0") && _at->recv("OK")) { 01676 if (set_psm_urcs(0)) {//disable the URC 01677 //de-register the callback 01678 detach_cb_psm_going_in(); 01679 detach_cb_psm_coming_out(); 01680 _psm_status = false; 01681 return_val = true; 01682 } 01683 } 01684 } else { //PSM string encoding code borrowed from AT_CellularPower.cpp 01685 /** 01686 Table 10.5.163a/3GPP TS 24.008: GPRS Timer 3 information element 01687 01688 Bits 5 to 1 represent the binary coded timer value. 01689 01690 Bits 6 to 8 defines the timer value unit for the GPRS timer as follows: 01691 8 7 6 01692 0 0 0 value is incremented in multiples of 10 minutes 01693 0 0 1 value is incremented in multiples of 1 hour 01694 0 1 0 value is incremented in multiples of 10 hours 01695 0 1 1 value is incremented in multiples of 2 seconds 01696 1 0 0 value is incremented in multiples of 30 seconds 01697 1 0 1 value is incremented in multiples of 1 minute 01698 1 1 0 value is incremented in multiples of 320 hours (NOTE 1) 01699 1 1 1 value indicates that the timer is deactivated (NOTE 2). 01700 */ 01701 char pt[8+1];// timer value encoded as 3GPP IE 01702 const int ie_value_max = 0x1f; 01703 uint32_t periodic_timer = 0; 01704 if (periodic_time <= 2*ie_value_max) { // multiples of 2 seconds 01705 periodic_timer = periodic_time/2; 01706 strcpy(pt, "01100000"); 01707 } else { 01708 if (periodic_time <= 30*ie_value_max) { // multiples of 30 seconds 01709 periodic_timer = periodic_time/30; 01710 strcpy(pt, "10000000"); 01711 } else { 01712 if (periodic_time <= 60*ie_value_max) { // multiples of 1 minute 01713 periodic_timer = periodic_time/60; 01714 strcpy(pt, "10100000"); 01715 } else { 01716 if (periodic_time <= 10*60*ie_value_max) { // multiples of 10 minutes 01717 periodic_timer = periodic_time/(10*60); 01718 strcpy(pt, "00000000"); 01719 } else { 01720 if (periodic_time <= 60*60*ie_value_max) { // multiples of 1 hour 01721 periodic_timer = periodic_time/(60*60); 01722 strcpy(pt, "00100000"); 01723 } else { 01724 if (periodic_time <= 10*60*60*ie_value_max) { // multiples of 10 hours 01725 periodic_timer = periodic_time/(10*60*60); 01726 strcpy(pt, "01000000"); 01727 } else { // multiples of 320 hours 01728 int t = periodic_time / (320*60*60); 01729 if (t > ie_value_max) { 01730 t = ie_value_max; 01731 } 01732 periodic_timer = t; 01733 strcpy(pt, "11000000"); 01734 } 01735 } 01736 } 01737 } 01738 } 01739 } 01740 01741 uint_to_binary_str(periodic_timer, &pt[3], sizeof(pt)-3, 5); 01742 pt[8] = '\0'; 01743 01744 /** 01745 Table 10.5.172/3GPP TS 24.008: GPRS Timer information element 01746 01747 Bits 5 to 1 represent the binary coded timer value. 01748 01749 Bits 6 to 8 defines the timer value unit for the GPRS timer as follows: 01750 01751 8 7 6 01752 0 0 0 value is incremented in multiples of 2 seconds 01753 0 0 1 value is incremented in multiples of 1 minute 01754 0 1 0 value is incremented in multiples of decihours 01755 1 1 1 value indicates that the timer is deactivated. 01756 01757 Other values shall be interpreted as multiples of 1 minute in this version of the protocol. 01758 */ 01759 char at[8+1]; 01760 uint32_t active_timer; // timer value encoded as 3GPP IE 01761 if (active_time <= 2*ie_value_max) { // multiples of 2 seconds 01762 active_timer = active_time/2; 01763 strcpy(at, "00000000"); 01764 } else { 01765 if (active_time <= 60*ie_value_max) { // multiples of 1 minute 01766 active_timer = (1<<5) | (active_time/60); 01767 strcpy(at, "00100000"); 01768 } else { // multiples of decihours 01769 int t = active_time / (6*60); 01770 if (t > ie_value_max) { 01771 t = ie_value_max; 01772 } 01773 active_timer = t; 01774 strcpy(at, "01000000"); 01775 } 01776 } 01777 01778 uint_to_binary_str(active_timer, &at[3], sizeof(at)-3, 5); 01779 at[8] = '\0'; 01780 01781 if (_at->send("AT+CPSMS=1,,,\"%s\",\"%s\"", pt, at) && _at->recv("OK")) { 01782 if (set_psm_urcs(1)) {//enable the PSM URC 01783 tr_info("PSM enabled successfully!"); 01784 _psm_status = true; 01785 return_val = true; 01786 } else { 01787 tr_error("PSM URCs not supported"); 01788 return_val = false; 01789 } 01790 } else { 01791 tr_error("+CPSMS command failed"); 01792 return_val = false; 01793 } 01794 } 01795 } else { 01796 tr_error("PSM URCs not supported by this version of modem"); 01797 } 01798 at_set_timeout(at_timeout); 01799 UNLOCK(); 01800 return return_val; 01801 } 01802 01803 bool UbloxCellularBase::is_modem_awake() 01804 { 01805 return (_dev_info.modem_psm_state == AWAKE); 01806 } 01807 01808 //application should call init() or connect() in order to initialize the modem 01809 void UbloxCellularBase::wakeup_modem() 01810 { 01811 LOCK(); 01812 01813 MBED_ASSERT(_at != NULL); 01814 01815 tr_info("Waking up modem..."); 01816 01817 modem_power_up(); 01818 01819 _dev_info.reg_status_csd = CSD_NOT_REGISTERED_NOT_SEARCHING; 01820 _dev_info.reg_status_psd = PSD_NOT_REGISTERED_NOT_SEARCHING; 01821 _dev_info.reg_status_eps = EPS_NOT_REGISTERED_NOT_SEARCHING; 01822 _modem_initialised = false; 01823 01824 UNLOCK(); 01825 } 01826 01827 bool UbloxCellularBase::set_psm_urcs(bool enable) 01828 { 01829 01830 bool success = false; 01831 LOCK(); 01832 01833 MBED_ASSERT(_at != NULL); 01834 01835 if (_at->send("AT+UPSMR=%d", enable ? 1 : 0) && _at->recv("OK")) { 01836 success = true; 01837 } 01838 01839 UNLOCK(); 01840 return success; 01841 } 01842 #endif 01843 01844 // End of File 01845
Generated on Mon Aug 1 2022 10:51:08 by
![doxygen](doxygen.png)