Add methods to return IMEI, MEID, IMSI, ICCID and RSSI.
Fork of ublox-cellular-base by
UbloxCellularBase.cpp
00001 /* Copyright (c) 2017 ublox Limited 00002 * 00003 * Licensed under the Apache License, Version 2.0 (the "License"); 00004 * you may not use this file except in compliance with the License. 00005 * You may obtain a copy of the License at 00006 * 00007 * http://www.apache.org/licenses/LICENSE-2.0 00008 * 00009 * Unless required by applicable law or agreed to in writing, software 00010 * distributed under the License is distributed on an "AS IS" BASIS, 00011 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00012 * See the License for the specific language governing permissions and 00013 * limitations under the License. 00014 */ 00015 00016 #include "UARTSerial.h" 00017 #include "APN_db.h" 00018 #include "UbloxCellularBase.h" 00019 #include "onboard_modem_api.h" 00020 #ifdef FEATURE_COMMON_PAL 00021 #include "mbed_trace.h" 00022 #define TRACE_GROUP "UCB" 00023 #else 00024 #define tr_debug(format, ...) debug_if(_debug_trace_on, format "\n", ## __VA_ARGS__) 00025 #define tr_info(format, ...) debug_if(_debug_trace_on, format "\n", ## __VA_ARGS__) 00026 #define tr_warn(format, ...) debug_if(_debug_trace_on, format "\n", ## __VA_ARGS__) 00027 #define tr_error(format, ...) debug_if(_debug_trace_on, format "\n", ## __VA_ARGS__) 00028 #endif 00029 00030 /* Array to convert the 3G qual number into a median EC_NO_LEV number. 00031 */ 00032 /* 0 1 2 3 4 5 6 7 */ 00033 const int qualConvert3G[] = {44, 41, 35, 29, 23, 17, 11, 7}; 00034 00035 /* Array to convert the 3G "rssi" number into a dBm RSCP value rounded up to the 00036 * nearest whole number. 00037 */ 00038 const int rscpConvert3G[] = {-108, -105, -103, -100, -98, -96, -94, -93, /* 0 - 7 */ 00039 -91, -89, -88, -85, -83, -80, -78, -76, /* 8 - 15 */ 00040 -74, -73, -70, -68, -66, -64, -63, -60, /* 16 - 23 */ 00041 -58, -56, -54, -53, -51, -49, -48, -46}; /* 24 - 31 */ 00042 00043 /* Array to convert the LTE rssi number into a dBm value rounded up to the 00044 * nearest whole number. 00045 */ 00046 const int rssiConvertLte[] = {-118, -115, -113, -110, -108, -105, -103, -100, /* 0 - 7 */ 00047 -98, -95, -93, -90, -88, -85, -83, -80, /* 8 - 15 */ 00048 -78, -76, -74, -73, -71, -69, -68, -65, /* 16 - 23 */ 00049 -63, -61, -60, -59, -58, -55, -53, -48}; /* 24 - 31 */ 00050 00051 /********************************************************************** 00052 * PRIVATE METHODS 00053 **********************************************************************/ 00054 00055 void UbloxCellularBase::set_nwk_reg_status_csd(int status) 00056 { 00057 switch (status) { 00058 case CSD_NOT_REGISTERED_NOT_SEARCHING: 00059 case CSD_NOT_REGISTERED_SEARCHING: 00060 tr_info("Not (yet) registered for circuit switched service"); 00061 break; 00062 case CSD_REGISTERED: 00063 case CSD_REGISTERED_ROAMING: 00064 tr_info("Registered for circuit switched service"); 00065 break; 00066 case CSD_REGISTRATION_DENIED: 00067 tr_info("Circuit switched service denied"); 00068 break; 00069 case CSD_UNKNOWN_COVERAGE: 00070 tr_info("Out of circuit switched service coverage"); 00071 break; 00072 case CSD_SMS_ONLY: 00073 tr_info("SMS service only"); 00074 break; 00075 case CSD_SMS_ONLY_ROAMING: 00076 tr_info("SMS service only"); 00077 break; 00078 case CSD_CSFB_NOT_PREFERRED: 00079 tr_info("Registered for circuit switched service with CSFB not preferred"); 00080 break; 00081 default: 00082 tr_info("Unknown circuit switched service registration status. %d", status); 00083 break; 00084 } 00085 00086 _dev_info.reg_status_csd = static_cast<NetworkRegistrationStatusCsd>(status); 00087 } 00088 00089 void UbloxCellularBase::set_nwk_reg_status_psd(int status) 00090 { 00091 switch (status) { 00092 case PSD_NOT_REGISTERED_NOT_SEARCHING: 00093 case PSD_NOT_REGISTERED_SEARCHING: 00094 tr_info("Not (yet) registered for packet switched service"); 00095 break; 00096 case PSD_REGISTERED: 00097 case PSD_REGISTERED_ROAMING: 00098 tr_info("Registered for packet switched service"); 00099 break; 00100 case PSD_REGISTRATION_DENIED: 00101 tr_info("Packet switched service denied"); 00102 break; 00103 case PSD_UNKNOWN_COVERAGE: 00104 tr_info("Out of packet switched service coverage"); 00105 break; 00106 case PSD_EMERGENCY_SERVICES_ONLY: 00107 tr_info("Limited access for packet switched service. Emergency use only."); 00108 break; 00109 default: 00110 tr_info("Unknown packet switched service registration status. %d", status); 00111 break; 00112 } 00113 00114 _dev_info.reg_status_psd = static_cast<NetworkRegistrationStatusPsd>(status); 00115 } 00116 00117 void UbloxCellularBase::set_nwk_reg_status_eps(int status) 00118 { 00119 switch (status) { 00120 case EPS_NOT_REGISTERED_NOT_SEARCHING: 00121 case EPS_NOT_REGISTERED_SEARCHING: 00122 tr_info("Not (yet) registered for EPS service"); 00123 break; 00124 case EPS_REGISTERED: 00125 case EPS_REGISTERED_ROAMING: 00126 tr_info("Registered for EPS service"); 00127 break; 00128 case EPS_REGISTRATION_DENIED: 00129 tr_info("EPS service denied"); 00130 break; 00131 case EPS_UNKNOWN_COVERAGE: 00132 tr_info("Out of EPS service coverage"); 00133 break; 00134 case EPS_EMERGENCY_SERVICES_ONLY: 00135 tr_info("Limited access for EPS service. Emergency use only."); 00136 break; 00137 default: 00138 tr_info("Unknown EPS service registration status. %d", status); 00139 break; 00140 } 00141 00142 _dev_info.reg_status_eps = static_cast<NetworkRegistrationStatusEps>(status); 00143 } 00144 00145 void UbloxCellularBase::set_rat(int acTStatus) 00146 { 00147 switch (acTStatus) { 00148 case GSM: 00149 case COMPACT_GSM: 00150 tr_info("Connected in GSM"); 00151 break; 00152 case UTRAN: 00153 tr_info("Connected to UTRAN"); 00154 break; 00155 case EDGE: 00156 tr_info("Connected to EDGE"); 00157 break; 00158 case HSDPA: 00159 tr_info("Connected to HSDPA"); 00160 break; 00161 case HSUPA: 00162 tr_info("Connected to HSPA"); 00163 break; 00164 case HSDPA_HSUPA: 00165 tr_info("Connected to HDPA/HSPA"); 00166 break; 00167 case LTE: 00168 tr_info("Connected to LTE"); 00169 break; 00170 case EC_GSM_IoT: 00171 tr_info("Connected to EC_GSM_IoT"); 00172 break; 00173 case E_UTRAN_NB_S1: 00174 tr_info("Connected to E_UTRAN NB1"); 00175 break; 00176 default: 00177 tr_info("Unknown RAT %d", acTStatus); 00178 break; 00179 } 00180 00181 _dev_info.rat = static_cast<RadioAccessNetworkType>(acTStatus); 00182 } 00183 00184 bool UbloxCellularBase::get_iccid() 00185 { 00186 bool success; 00187 LOCK(); 00188 00189 MBED_ASSERT(_at != NULL); 00190 00191 // Returns the ICCID (Integrated Circuit Card ID) of the SIM-card. 00192 // ICCID is a serial number identifying the SIM. 00193 // AT Command Manual UBX-13002752, section 4.12 00194 success = _at->send("AT+CCID") && _at->recv("+CCID: %20[^\n]\nOK\n", _dev_info.iccid); 00195 tr_info("DevInfo: ICCID=%s", _dev_info.iccid); 00196 00197 UNLOCK(); 00198 return success; 00199 } 00200 00201 bool UbloxCellularBase::get_imsi() 00202 { 00203 bool success; 00204 LOCK(); 00205 00206 MBED_ASSERT(_at != NULL); 00207 00208 // International mobile subscriber identification 00209 // AT Command Manual UBX-13002752, section 4.11 00210 success = _at->send("AT+CIMI") && _at->recv("%15[^\n]\nOK\n", _dev_info.imsi); 00211 tr_info("DevInfo: IMSI=%s", _dev_info.imsi); 00212 00213 UNLOCK(); 00214 return success; 00215 } 00216 00217 bool UbloxCellularBase::get_imei() 00218 { 00219 bool success; 00220 LOCK(); 00221 00222 MBED_ASSERT(_at != NULL); 00223 00224 // International mobile equipment identifier 00225 // AT Command Manual UBX-13002752, section 4.7 00226 success = _at->send("AT+CGSN") && _at->recv("%15[^\n]\nOK\n", _dev_info.imei); 00227 tr_info("DevInfo: IMEI=%s", _dev_info.imei); 00228 00229 UNLOCK(); 00230 return success; 00231 } 00232 00233 bool UbloxCellularBase::get_meid() 00234 { 00235 bool success; 00236 LOCK(); 00237 00238 MBED_ASSERT(_at != NULL); 00239 00240 // Mobile equipment identifier 00241 // AT Command Manual UBX-13002752, section 4.8 00242 success = _at->send("AT+GSN") && _at->recv("%18[^\n]\nOK\n", _dev_info.meid); 00243 tr_info("DevInfo: MEID=%s", _dev_info.meid); 00244 00245 UNLOCK(); 00246 return success; 00247 } 00248 00249 bool UbloxCellularBase::set_sms() 00250 { 00251 bool success = false; 00252 char buf[32]; 00253 LOCK(); 00254 00255 MBED_ASSERT(_at != NULL); 00256 00257 // Set up SMS format and enable URC 00258 // AT Command Manual UBX-13002752, section 11 00259 if (_at->send("AT+CMGF=1") && _at->recv("OK")) { 00260 tr_debug("SMS in text mode"); 00261 if (_at->send("AT+CNMI=2,1") && _at->recv("OK")) { 00262 tr_debug("SMS URC enabled"); 00263 // Set to CS preferred since PS preferred doesn't work 00264 // on some networks 00265 if (_at->send("AT+CGSMS=1") && _at->recv("OK")) { 00266 tr_debug("SMS set to CS preferred"); 00267 success = true; 00268 memset (buf, 0, sizeof (buf)); 00269 if (_at->send("AT+CSCA?") && 00270 _at->recv("+CSCA: \"%31[^\"]\"", buf) && 00271 _at->recv("OK")) { 00272 tr_info("SMS Service Centre address is \"%s\"", buf); 00273 } 00274 } 00275 } 00276 } 00277 00278 UNLOCK(); 00279 return success; 00280 } 00281 00282 void UbloxCellularBase::parser_abort_cb() 00283 { 00284 _at->abort(); 00285 } 00286 00287 // Callback for CME ERROR and CMS ERROR. 00288 void UbloxCellularBase::CMX_ERROR_URC() 00289 { 00290 char buf[48]; 00291 00292 if (read_at_to_char(buf, sizeof (buf), '\n') > 0) { 00293 tr_debug("AT error %s", buf); 00294 } 00295 parser_abort_cb(); 00296 } 00297 00298 // Callback for circuit switched registration URC. 00299 void UbloxCellularBase::CREG_URC() 00300 { 00301 char buf[10]; 00302 int status; 00303 int acTStatus; 00304 00305 // If this is the URC it will be a single 00306 // digit followed by \n. If it is the 00307 // answer to a CREG query, it will be 00308 // a ": %d,%d\n" where the second digit 00309 // indicates the status 00310 // Note: not calling _at->recv() from here as we're 00311 // already in an _at->recv() 00312 if (read_at_to_char(buf, sizeof (buf), '\n') > 0) { 00313 if (sscanf(buf, ": %*d,%d,%*d,%*d,%d,", &status, &acTStatus) == 2) { 00314 set_nwk_reg_status_csd(status); 00315 set_rat(acTStatus); 00316 } else if (sscanf(buf, ": %*d,%d", &status) == 1) { 00317 set_nwk_reg_status_csd(status); 00318 } else if (sscanf(buf, ": %d", &status) == 1) { 00319 set_nwk_reg_status_csd(status); 00320 } 00321 } 00322 } 00323 00324 // Callback for packet switched registration URC. 00325 void UbloxCellularBase::CGREG_URC() 00326 { 00327 char buf[10]; 00328 int status; 00329 int acTStatus; 00330 00331 // If this is the URC it will be a single 00332 // digit followed by \n. If it is the 00333 // answer to a CGREG query, it will be 00334 // a ": %d,%d\n" where the second digit 00335 // indicates the status 00336 // Note: not calling _at->recv() from here as we're 00337 // already in an _at->recv() 00338 if (read_at_to_char(buf, sizeof (buf), '\n') > 0) { 00339 if (sscanf(buf, ": %*d,%d,%*d,%*d,%d,", &status, &acTStatus) == 2) { 00340 set_nwk_reg_status_csd(status); 00341 set_rat(acTStatus); 00342 } else if (sscanf(buf, ": %*d,%d", &status) == 1) { 00343 set_nwk_reg_status_psd(status); 00344 } else if (sscanf(buf, ": %d", &status) == 1) { 00345 set_nwk_reg_status_psd(status); 00346 } 00347 } 00348 } 00349 00350 // Callback for EPS registration URC. 00351 void UbloxCellularBase::CEREG_URC() 00352 { 00353 char buf[10]; 00354 int status; 00355 int acTStatus; 00356 00357 // If this is the URC it will be a single 00358 // digit followed by \n. If it is the 00359 // answer to a CEREG query, it will be 00360 // a ": %d,%d\n" where the second digit 00361 // indicates the status 00362 // Note: not calling _at->recv() from here as we're 00363 // already in an _at->recv() 00364 if (read_at_to_char(buf, sizeof (buf), '\n') > 0) { 00365 if (sscanf(buf, ": %*d,%d,%*d,%*d,%d,", &status, &acTStatus) == 2) { 00366 set_nwk_reg_status_csd(status); 00367 set_rat(acTStatus); 00368 } else if (sscanf(buf, ": %*d,%d", &status) == 1) { 00369 set_nwk_reg_status_eps(status); 00370 } else if (sscanf(buf, ": %d", &status) == 1) { 00371 set_nwk_reg_status_eps(status); 00372 } 00373 } 00374 } 00375 00376 // Callback UMWI, just filtering it out. 00377 void UbloxCellularBase::UMWI_URC() 00378 { 00379 char buf[10]; 00380 00381 // Note: not calling _at->recv() from here as we're 00382 // already in an _at->recv() 00383 read_at_to_char(buf, sizeof (buf), '\n'); 00384 } 00385 00386 /********************************************************************** 00387 * PROTECTED METHODS 00388 **********************************************************************/ 00389 00390 #if MODEM_ON_BOARD 00391 void UbloxCellularBase::modem_init() 00392 { 00393 ::onboard_modem_init(); 00394 } 00395 00396 void UbloxCellularBase::modem_deinit() 00397 { 00398 ::onboard_modem_deinit(); 00399 } 00400 00401 void UbloxCellularBase::modem_power_up() 00402 { 00403 ::onboard_modem_power_up(); 00404 } 00405 00406 void UbloxCellularBase::modem_power_down() 00407 { 00408 ::onboard_modem_power_down(); 00409 } 00410 #else 00411 void UbloxCellularBase::modem_init() 00412 { 00413 // Meant to be overridden 00414 } 00415 00416 void UbloxCellularBase::modem_deinit() 00417 { 00418 // Meant to be overridden 00419 } 00420 00421 void UbloxCellularBase::modem_power_up() 00422 { 00423 // Meant to be overridden 00424 } 00425 00426 void UbloxCellularBase::modem_power_down() 00427 { 00428 // Mmeant to be overridden 00429 } 00430 #endif 00431 00432 // Constructor. 00433 // Note: to allow this base class to be inherited as a virtual base class 00434 // by everyone, it takes no parameters. See also comment above classInit() 00435 // in the header file. 00436 UbloxCellularBase::UbloxCellularBase() 00437 { 00438 _pin = NULL; 00439 _at = NULL; 00440 _at_timeout = AT_PARSER_TIMEOUT; 00441 _fh = NULL; 00442 _modem_initialised = false; 00443 _sim_pin_check_enabled = false; 00444 _debug_trace_on = false; 00445 00446 _dev_info.dev = DEV_TYPE_NONE; 00447 _dev_info.reg_status_csd = CSD_NOT_REGISTERED_NOT_SEARCHING; 00448 _dev_info.reg_status_psd = PSD_NOT_REGISTERED_NOT_SEARCHING; 00449 _dev_info.reg_status_eps = EPS_NOT_REGISTERED_NOT_SEARCHING; 00450 } 00451 00452 // Destructor. 00453 UbloxCellularBase::~UbloxCellularBase() 00454 { 00455 deinit(); 00456 delete _at; 00457 delete _fh; 00458 } 00459 00460 // Initialise the portions of this class that are parameterised. 00461 void UbloxCellularBase::baseClassInit(PinName tx, PinName rx, 00462 int baud, bool debug_on) 00463 { 00464 // Only initialise ourselves if it's not already been done 00465 if (_at == NULL) { 00466 if (_debug_trace_on == false) { 00467 _debug_trace_on = debug_on; 00468 } 00469 _baud = baud; 00470 00471 // Set up File Handle for buffered serial comms with cellular module 00472 // (which will be used by the AT parser) 00473 // Note: the UART is initialised to run no faster than 115200 because 00474 // the modems cannot reliably auto-baud at faster rates. The faster 00475 // rate is adopted later with a specific AT command and the 00476 // UARTSerial rate is adjusted at that time 00477 if (baud > 115200) { 00478 baud = 115200; 00479 } 00480 _fh = new UARTSerial(tx, rx, baud); 00481 00482 // Set up the AT parser 00483 _at = new ATCmdParser(_fh, OUTPUT_ENTER_KEY, AT_PARSER_BUFFER_SIZE, 00484 _at_timeout, _debug_trace_on); 00485 00486 // Error cases, out of band handling 00487 _at->oob("ERROR", callback(this, &UbloxCellularBase::parser_abort_cb)); 00488 _at->oob("+CME ERROR", callback(this, &UbloxCellularBase::CMX_ERROR_URC)); 00489 _at->oob("+CMS ERROR", callback(this, &UbloxCellularBase::CMX_ERROR_URC)); 00490 00491 // Registration status, out of band handling 00492 _at->oob("+CREG", callback(this, &UbloxCellularBase::CREG_URC)); 00493 _at->oob("+CGREG", callback(this, &UbloxCellularBase::CGREG_URC)); 00494 _at->oob("+CEREG", callback(this, &UbloxCellularBase::CEREG_URC)); 00495 00496 // Capture the UMWI, just to stop it getting in the way 00497 _at->oob("+UMWI", callback(this, &UbloxCellularBase::UMWI_URC)); 00498 } 00499 } 00500 00501 // Set the AT parser timeout. 00502 // Note: the AT interface should be locked before this is called. 00503 void UbloxCellularBase::at_set_timeout(int timeout) { 00504 00505 MBED_ASSERT(_at != NULL); 00506 00507 _at_timeout = timeout; 00508 _at->set_timeout(timeout); 00509 } 00510 00511 // Read up to size bytes from the AT interface up to a "end". 00512 // Note: the AT interface should be locked before this is called. 00513 int UbloxCellularBase::read_at_to_char(char * buf, int size, char end) 00514 { 00515 int count = 0; 00516 int x = 0; 00517 00518 if (size > 0) { 00519 for (count = 0; (count < size) && (x >= 0) && (x != end); count++) { 00520 x = _at->getc(); 00521 *(buf + count) = (char) x; 00522 } 00523 00524 count--; 00525 *(buf + count) = 0; 00526 00527 // Convert line endings: 00528 // If end was '\n' (0x0a) and the preceding character was 0x0d, then 00529 // overwrite that with null as well. 00530 if ((count > 0) && (end == '\n') && (*(buf + count - 1) == '\x0d')) { 00531 count--; 00532 *(buf + count) = 0; 00533 } 00534 } 00535 00536 return count; 00537 } 00538 00539 // Power up the modem. 00540 // Enables the GPIO lines to the modem and then wriggles the power line in short pulses. 00541 bool UbloxCellularBase::power_up() 00542 { 00543 bool success = false; 00544 int at_timeout; 00545 LOCK(); 00546 00547 at_timeout = _at_timeout; // Has to be inside LOCK()s 00548 00549 MBED_ASSERT(_at != NULL); 00550 00551 /* Initialize GPIO lines */ 00552 tr_info("Powering up modem..."); 00553 modem_init(); 00554 /* Give modem a little time to settle down */ 00555 wait_ms(250); 00556 00557 for (int retry_count = 0; !success && (retry_count < 20); retry_count++) { 00558 modem_power_up(); 00559 wait_ms(500); 00560 // Modem tends to spit out noise during power up - don't confuse the parser 00561 _at->flush(); 00562 at_set_timeout(1000); 00563 if (_at->send("AT")) { 00564 // C027 needs a delay here 00565 wait_ms(100); 00566 if (_at->recv("OK")) { 00567 success = true; 00568 } 00569 } 00570 at_set_timeout(at_timeout); 00571 } 00572 00573 if (success) { 00574 // Set the final baud rate 00575 if (_at->send("AT+IPR=%d", _baud) && _at->recv("OK")) { 00576 // Need to wait for things to be sorted out on the modem side 00577 wait_ms(100); 00578 ((UARTSerial *)_fh)->set_baud(_baud); 00579 } 00580 00581 // Turn off modem echoing and turn on verbose responses 00582 success = _at->send("ATE0;+CMEE=2") && _at->recv("OK") && 00583 // The following commands are best sent separately 00584 _at->send("AT&K0") && _at->recv("OK") && // Turn off RTC/CTS handshaking 00585 _at->send("AT&C1") && _at->recv("OK") && // Set DCD circuit(109), changes in accordance with the carrier detect status 00586 _at->send("AT&D0") && _at->recv("OK"); // Set DTR circuit, we ignore the state change of DTR 00587 } 00588 00589 if (!success) { 00590 tr_error("Preliminary modem setup failed."); 00591 } 00592 00593 UNLOCK(); 00594 return success; 00595 } 00596 00597 // Power down modem via AT interface. 00598 void UbloxCellularBase::power_down() 00599 { 00600 LOCK(); 00601 00602 MBED_ASSERT(_at != NULL); 00603 00604 // If we have been running, do a soft power-off first 00605 if (_modem_initialised && (_at != NULL)) { 00606 _at->send("AT+CPWROFF") && _at->recv("OK"); 00607 } 00608 00609 // Now do a hard power-off 00610 modem_power_down(); 00611 modem_deinit(); 00612 00613 _dev_info.reg_status_csd = CSD_NOT_REGISTERED_NOT_SEARCHING; 00614 _dev_info.reg_status_psd = PSD_NOT_REGISTERED_NOT_SEARCHING; 00615 _dev_info.reg_status_eps = EPS_NOT_REGISTERED_NOT_SEARCHING; 00616 00617 UNLOCK(); 00618 } 00619 00620 // Get the device ID. 00621 bool UbloxCellularBase::set_device_identity(DeviceType *dev) 00622 { 00623 char buf[20]; 00624 bool success; 00625 LOCK(); 00626 00627 MBED_ASSERT(_at != NULL); 00628 00629 success = _at->send("ATI") && _at->recv("%19[^\n]\nOK\n", buf); 00630 00631 if (success) { 00632 if (strstr(buf, "SARA-G35")) 00633 *dev = DEV_SARA_G35; 00634 else if (strstr(buf, "LISA-U200-03S")) 00635 *dev = DEV_LISA_U2_03S; 00636 else if (strstr(buf, "LISA-U2")) 00637 *dev = DEV_LISA_U2; 00638 else if (strstr(buf, "SARA-U2")) 00639 *dev = DEV_SARA_U2; 00640 else if (strstr(buf, "SARA-R4")) 00641 *dev = DEV_SARA_R4; 00642 else if (strstr(buf, "LEON-G2")) 00643 *dev = DEV_LEON_G2; 00644 else if (strstr(buf, "TOBY-L2")) 00645 *dev = DEV_TOBY_L2; 00646 else if (strstr(buf, "MPCI-L2")) 00647 *dev = DEV_MPCI_L2; 00648 } 00649 00650 UNLOCK(); 00651 return success; 00652 } 00653 00654 // Send initialisation AT commands that are specific to the device. 00655 bool UbloxCellularBase::device_init(DeviceType dev) 00656 { 00657 bool success = false; 00658 LOCK(); 00659 00660 MBED_ASSERT(_at != NULL); 00661 00662 if ((dev == DEV_LISA_U2) || (dev == DEV_LEON_G2) || (dev == DEV_TOBY_L2)) { 00663 success = _at->send("AT+UGPIOC=20,2") && _at->recv("OK"); 00664 } else if ((dev == DEV_SARA_U2) || (dev == DEV_SARA_G35)) { 00665 success = _at->send("AT+UGPIOC=16,2") && _at->recv("OK"); 00666 } else { 00667 success = true; 00668 } 00669 00670 UNLOCK(); 00671 return success; 00672 } 00673 00674 // Get the SIM card going. 00675 bool UbloxCellularBase::initialise_sim_card() 00676 { 00677 bool success = false; 00678 int retry_count = 0; 00679 bool done = false; 00680 LOCK(); 00681 00682 MBED_ASSERT(_at != NULL); 00683 00684 /* SIM initialisation may take a significant amount, so an error is 00685 * kind of expected. We should retry 10 times until we succeed or timeout. */ 00686 for (retry_count = 0; !done && (retry_count < 10); retry_count++) { 00687 char pinstr[16]; 00688 00689 if (_at->send("AT+CPIN?") && _at->recv("+CPIN: %15[^\n]\n", pinstr) && 00690 _at->recv("OK")) { 00691 done = true; 00692 if (strcmp(pinstr, "SIM PIN") == 0) { 00693 _sim_pin_check_enabled = true; 00694 if (_at->send("AT+CPIN=\"%s\"", _pin)) { 00695 if (_at->recv("OK")) { 00696 tr_info("PIN correct"); 00697 success = true; 00698 } else { 00699 tr_error("Incorrect PIN"); 00700 } 00701 } 00702 } else if (strcmp(pinstr, "READY") == 0) { 00703 _sim_pin_check_enabled = false; 00704 tr_info("No PIN required"); 00705 success = true; 00706 } else { 00707 tr_debug("Unexpected response from SIM: \"%s\"", pinstr); 00708 } 00709 } 00710 00711 /* wait for a second before retry */ 00712 wait_ms(1000); 00713 } 00714 00715 if (done) { 00716 tr_info("SIM Ready."); 00717 } else { 00718 tr_error("SIM not ready."); 00719 } 00720 00721 UNLOCK(); 00722 return success; 00723 } 00724 00725 /********************************************************************** 00726 * PUBLIC METHODS 00727 **********************************************************************/ 00728 00729 // Initialise the modem. 00730 bool UbloxCellularBase::init(const char *pin) 00731 { 00732 int x; 00733 MBED_ASSERT(_at != NULL); 00734 00735 if (!_modem_initialised) { 00736 if (power_up()) { 00737 tr_info("Modem Ready."); 00738 if (pin != NULL) { 00739 _pin = pin; 00740 } 00741 if (initialise_sim_card()) { 00742 if (set_device_identity(&_dev_info.dev) && // Set up device identity 00743 device_init(_dev_info.dev)) {// Initialise this device 00744 // Get the integrated circuit ID of the SIM 00745 if (get_iccid()) { 00746 // Try a few times to get the IMSI (since on some modems this can 00747 // take a while to be retrieved, especially if a SIM PIN 00748 // was set) 00749 for (x = 0; (x < 3) && !get_imsi(); x++) { 00750 wait_ms(1000); 00751 } 00752 00753 if (x < 3) { // If we got the IMSI, can get the others 00754 if (get_imei() && // Get international mobile equipment identifier 00755 get_meid() && // Probably the same as the IMEI 00756 set_sms()) { // And set up SMS 00757 // The modem is initialised. 00758 _modem_initialised = true; 00759 } 00760 } 00761 } 00762 } 00763 } 00764 } 00765 } 00766 00767 return _modem_initialised; 00768 } 00769 00770 // Perform registration. 00771 bool UbloxCellularBase::nwk_registration() 00772 { 00773 bool atSuccess = false; 00774 bool registered = false; 00775 int status; 00776 int at_timeout; 00777 LOCK(); 00778 00779 at_timeout = _at_timeout; // Has to be inside LOCK()s 00780 00781 MBED_ASSERT(_at != NULL); 00782 00783 if (!is_registered_psd() && !is_registered_csd() && !is_registered_eps()) { 00784 tr_info("Searching Network..."); 00785 // Enable the packet switched and network registration unsolicited result codes 00786 if (_at->send("AT+CREG=1") && _at->recv("OK") && 00787 _at->send("AT+CGREG=1") && _at->recv("OK")) { 00788 atSuccess = true; 00789 if (_at->send("AT+CEREG=1")) { 00790 _at->recv("OK"); 00791 // Don't check return value as this works for LTE only 00792 } 00793 00794 if (atSuccess) { 00795 // See if we are already in automatic mode 00796 if (_at->send("AT+COPS?") && _at->recv("+COPS: %d", &status) && 00797 _at->recv("OK")) { 00798 // If not, set it 00799 if (status != 0) { 00800 // Don't check return code here as there's not much 00801 // we can do if this fails. 00802 _at->send("AT+COPS=0") && _at->recv("OK"); 00803 } 00804 } 00805 00806 // Query the registration status directly as well, 00807 // just in case 00808 if (_at->send("AT+CREG?") && _at->recv("OK")) { 00809 // Answer will be processed by URC 00810 } 00811 if (_at->send("AT+CGREG?") && _at->recv("OK")) { 00812 // Answer will be processed by URC 00813 } 00814 if (_at->send("AT+CEREG?")) { 00815 _at->recv("OK"); 00816 // Don't check return value as this works for LTE only 00817 } 00818 } 00819 } 00820 // Wait for registration to succeed 00821 at_set_timeout(1000); 00822 for (int waitSeconds = 0; !registered && (waitSeconds < 180); waitSeconds++) { 00823 registered = is_registered_psd() || is_registered_csd() || is_registered_eps(); 00824 _at->recv(UNNATURAL_STRING); 00825 } 00826 at_set_timeout(at_timeout); 00827 00828 if (registered) { 00829 // This should return quickly but sometimes the status field is not returned 00830 // so make the timeout short 00831 at_set_timeout(1000); 00832 if (_at->send("AT+COPS?") && _at->recv("+COPS: %*d,%*d,\"%*[^\"]\",%d\n", &status)) { 00833 set_rat(status); 00834 } 00835 at_set_timeout(at_timeout); 00836 } 00837 } else { 00838 registered = true; 00839 } 00840 00841 UNLOCK(); 00842 return registered; 00843 } 00844 00845 bool UbloxCellularBase::is_registered_csd() 00846 { 00847 return (_dev_info.reg_status_csd == CSD_REGISTERED) || 00848 (_dev_info.reg_status_csd == CSD_REGISTERED_ROAMING) || 00849 (_dev_info.reg_status_csd == CSD_CSFB_NOT_PREFERRED); 00850 } 00851 00852 bool UbloxCellularBase::is_registered_psd() 00853 { 00854 return (_dev_info.reg_status_psd == PSD_REGISTERED) || 00855 (_dev_info.reg_status_psd == PSD_REGISTERED_ROAMING); 00856 } 00857 00858 bool UbloxCellularBase::is_registered_eps() 00859 { 00860 return (_dev_info.reg_status_eps == EPS_REGISTERED) || 00861 (_dev_info.reg_status_eps == EPS_REGISTERED_ROAMING); 00862 } 00863 00864 // Perform deregistration. 00865 bool UbloxCellularBase::nwk_deregistration() 00866 { 00867 bool success = false; 00868 LOCK(); 00869 00870 MBED_ASSERT(_at != NULL); 00871 00872 if (_at->send("AT+COPS=2") && _at->recv("OK")) { 00873 _dev_info.reg_status_csd = CSD_NOT_REGISTERED_NOT_SEARCHING; 00874 _dev_info.reg_status_psd = PSD_NOT_REGISTERED_NOT_SEARCHING; 00875 _dev_info.reg_status_eps = EPS_NOT_REGISTERED_NOT_SEARCHING; 00876 success = true; 00877 } 00878 00879 UNLOCK(); 00880 return success; 00881 } 00882 00883 // Put the modem into its lowest power state. 00884 void UbloxCellularBase::deinit() 00885 { 00886 power_down(); 00887 _modem_initialised = false; 00888 } 00889 00890 // Set the PIN. 00891 void UbloxCellularBase::set_pin(const char *pin) { 00892 _pin = pin; 00893 } 00894 00895 // Enable or disable SIM pin checking. 00896 bool UbloxCellularBase::sim_pin_check_enable(bool enableNotDisable) 00897 { 00898 bool success = false;; 00899 LOCK(); 00900 00901 MBED_ASSERT(_at != NULL); 00902 00903 if (_pin != NULL) { 00904 if (_sim_pin_check_enabled && !enableNotDisable) { 00905 // Disable the SIM lock 00906 if (_at->send("AT+CLCK=\"SC\",0,\"%s\"", _pin) && _at->recv("OK")) { 00907 _sim_pin_check_enabled = false; 00908 success = true; 00909 } 00910 } else if (!_sim_pin_check_enabled && enableNotDisable) { 00911 // Enable the SIM lock 00912 if (_at->send("AT+CLCK=\"SC\",1,\"%s\"", _pin) && _at->recv("OK")) { 00913 _sim_pin_check_enabled = true; 00914 success = true; 00915 } 00916 } else { 00917 success = true; 00918 } 00919 } 00920 00921 UNLOCK(); 00922 return success; 00923 } 00924 00925 // Change the pin code for the SIM card. 00926 bool UbloxCellularBase::change_sim_pin(const char *pin) 00927 { 00928 bool success = false;; 00929 LOCK(); 00930 00931 MBED_ASSERT(_at != NULL); 00932 00933 // Change the SIM pin 00934 if ((pin != NULL) && (_pin != NULL)) { 00935 if (_at->send("AT+CPWD=\"SC\",\"%s\",\"%s\"", _pin, pin) && _at->recv("OK")) { 00936 _pin = pin; 00937 success = true; 00938 } 00939 } 00940 00941 UNLOCK(); 00942 return success; 00943 } 00944 00945 // Get the IMEI. 00946 bool UbloxCellularBase::get_imei(char *imei_to_send, int size) 00947 { 00948 bool success; 00949 LOCK(); 00950 00951 MBED_ASSERT(_at != NULL); 00952 00953 // International mobile equipment identifier 00954 // AT Command Manual UBX-13002752, section 4.7 00955 success = _at->send("AT+CGSN") && _at->recv("%15[^\n]\nOK\n", _dev_info.imei); 00956 tr_info("DevInfo: IMEI=%s", _dev_info.imei); 00957 00958 if (success) { 00959 memcpy(imei_to_send,_dev_info.imei,size); 00960 imei_to_send[size-1] = '\0'; 00961 } 00962 00963 UNLOCK(); 00964 return success; 00965 } 00966 00967 // Get the IMEI of the module. 00968 const char *UbloxCellularBase::imei() 00969 { 00970 return _dev_info.imei; 00971 } 00972 00973 // Get the Mobile Equipment ID (which may be the same as the IMEI). 00974 const char *UbloxCellularBase::meid() 00975 { 00976 return _dev_info.meid; 00977 } 00978 00979 // Get the IMSI of the SIM. 00980 const char *UbloxCellularBase::imsi() 00981 { 00982 // (try) to update the IMSI, just in case the SIM has changed 00983 get_imsi(); 00984 00985 return _dev_info.imsi; 00986 } 00987 00988 // Get the ICCID of the SIM. 00989 const char *UbloxCellularBase::iccid() 00990 { 00991 // (try) to update the ICCID, just in case the SIM has changed 00992 get_iccid(); 00993 00994 return _dev_info.iccid; 00995 } 00996 00997 // Get the RSSI in dBm. 00998 int UbloxCellularBase::rssi() 00999 { 01000 char buf[7] = {0}; 01001 int rssi = 0; 01002 int qual = 0; 01003 int rssiRet = 0; 01004 bool success; 01005 LOCK(); 01006 01007 MBED_ASSERT(_at != NULL); 01008 01009 success = _at->send("AT+CSQ") && _at->recv("+CSQ: %6[^\n]\nOK\n", buf); 01010 01011 if (success) { 01012 if (sscanf(buf, "%d,%d", &rssi, &qual) == 2) { 01013 // AT+CSQ returns a coded RSSI value and an RxQual value 01014 // For 2G an RSSI of 0 corresponds to -113 dBm or less, 01015 // an RSSI of 31 corresponds to -51 dBm or less and hence 01016 // each value is a 2 dB step. 01017 // For LTE the mapping is defined in the array rssiConvertLte[]. 01018 // For 3G the mapping to RSCP is defined in the array rscpConvert3G[] 01019 // and the RSSI value is then RSCP - the EC_NO_LEV number derived 01020 // by putting the qual number through qualConvert3G[]. 01021 if ((rssi >= 0) && (rssi <= 31)) { 01022 switch (_dev_info.rat) { 01023 case UTRAN: 01024 case HSDPA: 01025 case HSUPA: 01026 case HSDPA_HSUPA: 01027 // 3G 01028 if ((qual >= 0) && (qual <= 7)) { 01029 qual = qualConvert3G[qual]; 01030 } 01031 rssiRet = rscpConvert3G[rssi]; 01032 rssiRet -= qual; 01033 break; 01034 case LTE: 01035 // LTE 01036 rssiRet = rssiConvertLte[rssi]; 01037 break; 01038 case GSM: 01039 case COMPACT_GSM: 01040 case EDGE: 01041 default: 01042 // GSM or assumed GSM if the RAT is not known 01043 rssiRet = -(113 - (rssi << 2)); 01044 break; 01045 } 01046 } 01047 } 01048 } 01049 01050 UNLOCK(); 01051 return rssiRet; 01052 } 01053 01054 // End of File 01055
Generated on Fri Jul 15 2022 20:36:24 by 1.7.2