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