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