Fork for new features
Embed:
(wiki syntax)
Show/hide line numbers
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 memset(_plmn, 0, sizeof(_plmn)); 00447 00448 _dev_info.dev = DEV_TYPE_NONE; 00449 _dev_info.reg_status_csd = CSD_NOT_REGISTERED_NOT_SEARCHING; 00450 _dev_info.reg_status_psd = PSD_NOT_REGISTERED_NOT_SEARCHING; 00451 _dev_info.reg_status_eps = EPS_NOT_REGISTERED_NOT_SEARCHING; 00452 } 00453 00454 // Destructor. 00455 UbloxCellularBase::~UbloxCellularBase() 00456 { 00457 deinit(); 00458 delete _at; 00459 delete _fh; 00460 } 00461 00462 // Initialise the portions of this class that are parameterised. 00463 void UbloxCellularBase::baseClassInit(PinName tx, PinName rx, 00464 int baud, bool debug_on) 00465 { 00466 // Only initialise ourselves if it's not already been done 00467 if (_at == NULL) { 00468 if (_debug_trace_on == false) { 00469 _debug_trace_on = debug_on; 00470 } 00471 _baud = baud; 00472 00473 // Set up File Handle for buffered serial comms with cellular module 00474 // (which will be used by the AT parser) 00475 // Note: the UART is initialised to run no faster than 115200 because 00476 // the modems cannot reliably auto-baud at faster rates. The faster 00477 // rate is adopted later with a specific AT command and the 00478 // UARTSerial rate is adjusted at that time 00479 if (baud > 115200) { 00480 baud = 115200; 00481 } 00482 _fh = new UARTSerial(tx, rx, baud); 00483 00484 // Set up the AT parser 00485 _at = new ATCmdParser(_fh, OUTPUT_ENTER_KEY, AT_PARSER_BUFFER_SIZE, 00486 _at_timeout, _debug_trace_on); 00487 00488 // Error cases, out of band handling 00489 _at->oob("ERROR", callback(this, &UbloxCellularBase::parser_abort_cb)); 00490 _at->oob("+CME ERROR", callback(this, &UbloxCellularBase::CMX_ERROR_URC)); 00491 _at->oob("+CMS ERROR", callback(this, &UbloxCellularBase::CMX_ERROR_URC)); 00492 00493 // Registration status, out of band handling 00494 _at->oob("+CREG", callback(this, &UbloxCellularBase::CREG_URC)); 00495 _at->oob("+CGREG", callback(this, &UbloxCellularBase::CGREG_URC)); 00496 _at->oob("+CEREG", callback(this, &UbloxCellularBase::CEREG_URC)); 00497 00498 // Capture the UMWI, just to stop it getting in the way 00499 _at->oob("+UMWI", callback(this, &UbloxCellularBase::UMWI_URC)); 00500 } 00501 } 00502 00503 // Set the AT parser timeout. 00504 // Note: the AT interface should be locked before this is called. 00505 void UbloxCellularBase::at_set_timeout(int timeout) { 00506 00507 MBED_ASSERT(_at != NULL); 00508 00509 _at_timeout = timeout; 00510 _at->set_timeout(timeout); 00511 } 00512 00513 // Read up to size bytes from the AT interface up to a "end". 00514 // Note: the AT interface should be locked before this is called. 00515 int UbloxCellularBase::read_at_to_char(char * buf, int size, char end) 00516 { 00517 int count = 0; 00518 int x = 0; 00519 00520 if (size > 0) { 00521 for (count = 0; (count < size) && (x >= 0) && (x != end); count++) { 00522 x = _at->getc(); 00523 *(buf + count) = (char) x; 00524 } 00525 00526 count--; 00527 *(buf + count) = 0; 00528 00529 // Convert line endings: 00530 // If end was '\n' (0x0a) and the preceding character was 0x0d, then 00531 // overwrite that with null as well. 00532 if ((count > 0) && (end == '\n') && (*(buf + count - 1) == '\x0d')) { 00533 count--; 00534 *(buf + count) = 0; 00535 } 00536 } 00537 00538 return count; 00539 } 00540 00541 // Power up the modem. 00542 // Enables the GPIO lines to the modem and then wriggles the power line in short pulses. 00543 bool UbloxCellularBase::power_up() 00544 { 00545 bool success = false; 00546 int at_timeout; 00547 LOCK(); 00548 00549 at_timeout = _at_timeout; // Has to be inside LOCK()s 00550 00551 MBED_ASSERT(_at != NULL); 00552 00553 /* Initialize GPIO lines */ 00554 tr_info("Powering up modem..."); 00555 modem_init(); 00556 /* Give modem a little time to settle down */ 00557 wait_ms(250); 00558 00559 for (int retry_count = 0; !success && (retry_count < 20); retry_count++) { 00560 //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. 00561 if ( (retry_count % 5) == 0) { 00562 modem_power_up(); 00563 } 00564 wait_ms(500); 00565 // Modem tends to spit out noise during power up - don't confuse the parser 00566 _at->flush(); 00567 at_set_timeout(1000); 00568 if (_at->send("AT")) { 00569 // C027 needs a delay here 00570 wait_ms(100); 00571 if (_at->recv("OK")) { 00572 success = true; 00573 } 00574 } 00575 at_set_timeout(at_timeout); 00576 } 00577 00578 if (success) { 00579 // Set the final baud rate 00580 if (_at->send("AT+IPR=%d", _baud) && _at->recv("OK")) { 00581 // Need to wait for things to be sorted out on the modem side 00582 wait_ms(100); 00583 ((UARTSerial *)_fh)->set_baud(_baud); 00584 } 00585 00586 // Turn off modem echoing and turn on verbose responses 00587 success = _at->send("ATE0;+CMEE=2") && _at->recv("OK") && 00588 // The following commands are best sent separately 00589 _at->send("AT&K0") && _at->recv("OK") && // Turn off RTC/CTS handshaking 00590 _at->send("AT&C1") && _at->recv("OK") && // Set DCD circuit(109), changes in accordance with the carrier detect status 00591 _at->send("AT&D0") && _at->recv("OK"); // Set DTR circuit, we ignore the state change of DTR 00592 } 00593 00594 if (!success) { 00595 tr_error("Preliminary modem setup failed."); 00596 } 00597 00598 UNLOCK(); 00599 return success; 00600 } 00601 00602 // Power down modem via AT interface. 00603 void UbloxCellularBase::power_down() 00604 { 00605 LOCK(); 00606 00607 MBED_ASSERT(_at != NULL); 00608 00609 // power-off modem 00610 modem_power_down(); 00611 modem_deinit(); 00612 00613 if (_modem_initialised && (_at != NULL)) { 00614 int at_timeout = _at_timeout; // Save previous timeout 00615 _at->set_timeout(1000); 00616 // Check modem is powered off 00617 if(_at->send("AT") && _at->recv("OK")) { 00618 _at->send("AT+CPWROFF") && _at->recv("OK"); 00619 } 00620 _at->set_timeout(at_timeout); 00621 } 00622 00623 _dev_info.reg_status_csd = CSD_NOT_REGISTERED_NOT_SEARCHING; 00624 _dev_info.reg_status_psd = PSD_NOT_REGISTERED_NOT_SEARCHING; 00625 _dev_info.reg_status_eps = EPS_NOT_REGISTERED_NOT_SEARCHING; 00626 00627 UNLOCK(); 00628 } 00629 00630 // Get the device ID. 00631 bool UbloxCellularBase::set_device_identity(DeviceType *dev) 00632 { 00633 char buf[20]; 00634 bool success; 00635 LOCK(); 00636 00637 MBED_ASSERT(_at != NULL); 00638 00639 success = _at->send("ATI") && _at->recv("%19[^\n]\nOK\n", buf); 00640 00641 if (success) { 00642 if (strstr(buf, "SARA-G35")) 00643 *dev = DEV_SARA_G35; 00644 else if (strstr(buf, "LISA-U200-03S")) 00645 *dev = DEV_LISA_U2_03S; 00646 else if (strstr(buf, "LISA-U2")) 00647 *dev = DEV_LISA_U2; 00648 else if (strstr(buf, "SARA-U2")) 00649 *dev = DEV_SARA_U2; 00650 else if (strstr(buf, "SARA-R4")) 00651 *dev = DEV_SARA_R4; 00652 else if (strstr(buf, "LEON-G2")) 00653 *dev = DEV_LEON_G2; 00654 else if (strstr(buf, "TOBY-L2")) 00655 *dev = DEV_TOBY_L2; 00656 else if (strstr(buf, "MPCI-L2")) 00657 *dev = DEV_MPCI_L2; 00658 } 00659 00660 UNLOCK(); 00661 return success; 00662 } 00663 00664 // Send initialisation AT commands that are specific to the device. 00665 bool UbloxCellularBase::device_init(DeviceType dev) 00666 { 00667 bool success = false; 00668 LOCK(); 00669 00670 MBED_ASSERT(_at != NULL); 00671 00672 if ((dev == DEV_LISA_U2) || (dev == DEV_LEON_G2) || (dev == DEV_TOBY_L2)) { 00673 success = _at->send("AT+UGPIOC=20,2") && _at->recv("OK"); 00674 } else if ((dev == DEV_SARA_U2) || (dev == DEV_SARA_G35)) { 00675 success = _at->send("AT+UGPIOC=16,2") && _at->recv("OK"); 00676 } else { 00677 success = true; 00678 } 00679 00680 UNLOCK(); 00681 return success; 00682 } 00683 00684 // Get the SIM card going. 00685 bool UbloxCellularBase::initialise_sim_card() 00686 { 00687 bool success = false; 00688 int retry_count = 0; 00689 bool done = false; 00690 LOCK(); 00691 00692 MBED_ASSERT(_at != NULL); 00693 00694 /* SIM initialisation may take a significant amount, so an error is 00695 * kind of expected. We should retry 10 times until we succeed or timeout. */ 00696 for (retry_count = 0; !done && (retry_count < 10); retry_count++) { 00697 char pinstr[16]; 00698 00699 if (_at->send("AT+CPIN?") && _at->recv("+CPIN: %15[^\n]\n", pinstr) && 00700 _at->recv("OK")) { 00701 done = true; 00702 if (strcmp(pinstr, "SIM PIN") == 0) { 00703 _sim_pin_check_enabled = true; 00704 if (_at->send("AT+CPIN=\"%s\"", _pin)) { 00705 if (_at->recv("OK")) { 00706 tr_info("PIN correct"); 00707 success = true; 00708 } else { 00709 tr_error("Incorrect PIN"); 00710 } 00711 } 00712 } else if (strcmp(pinstr, "READY") == 0) { 00713 _sim_pin_check_enabled = false; 00714 tr_info("No PIN required"); 00715 success = true; 00716 } else { 00717 tr_debug("Unexpected response from SIM: \"%s\"", pinstr); 00718 } 00719 } 00720 00721 /* wait for a second before retry */ 00722 wait_ms(1000); 00723 } 00724 00725 if (done) { 00726 tr_info("SIM Ready."); 00727 } else { 00728 tr_error("SIM not ready."); 00729 } 00730 00731 UNLOCK(); 00732 return success; 00733 } 00734 00735 /********************************************************************** 00736 * PUBLIC METHODS 00737 **********************************************************************/ 00738 00739 // Initialise the modem. 00740 bool UbloxCellularBase::init(const char *pin) 00741 { 00742 int x; 00743 MBED_ASSERT(_at != NULL); 00744 00745 if (!_modem_initialised) { 00746 if (power_up()) { 00747 tr_info("Modem Ready."); 00748 if (pin != NULL) { 00749 _pin = pin; 00750 } 00751 if (initialise_sim_card()) { 00752 if (set_device_identity(&_dev_info.dev) && // Set up device identity 00753 device_init(_dev_info.dev)) {// Initialise this device 00754 // Get the integrated circuit ID of the SIM 00755 if (get_iccid()) { 00756 // Try a few times to get the IMSI (since on some modems this can 00757 // take a while to be retrieved, especially if a SIM PIN 00758 // was set) 00759 for (x = 0; (x < 3) && !get_imsi(); x++) { 00760 wait_ms(1000); 00761 } 00762 00763 if (x < 3) { // If we got the IMSI, can get the others 00764 if (get_imei() && // Get international mobile equipment identifier 00765 get_meid() && // Probably the same as the IMEI 00766 set_sms()) { // And set up SMS 00767 // The modem is initialised. 00768 _modem_initialised = true; 00769 } 00770 } 00771 } 00772 } 00773 } 00774 } 00775 } 00776 00777 return _modem_initialised; 00778 } 00779 00780 // Perform registration. 00781 bool UbloxCellularBase::nwk_registration() 00782 { 00783 bool atSuccess = false; 00784 bool registered = false; 00785 int status; 00786 int at_timeout; 00787 LOCK(); 00788 00789 at_timeout = _at_timeout; // Has to be inside LOCK()s 00790 00791 MBED_ASSERT(_at != NULL); 00792 00793 if (!is_registered_psd() && !is_registered_csd() && !is_registered_eps()) { 00794 tr_info("Searching Network..."); 00795 // Enable the packet switched and network registration unsolicited result codes 00796 if (_at->send("AT+CREG=1") && _at->recv("OK") && 00797 _at->send("AT+CGREG=1") && _at->recv("OK")) { 00798 atSuccess = true; 00799 if (_at->send("AT+CEREG=1")) { 00800 _at->recv("OK"); 00801 // Don't check return value as this works for LTE only 00802 } 00803 00804 if (atSuccess) { 00805 // See if a PLMN is set by user 00806 if (_plmn[0] != 0) { 00807 tr_debug("Manual network registration to %s, please wait upto 3 minutes", _plmn); 00808 at_set_timeout(3*60*1000); 00809 _at->send("AT+COPS=1,2,\"%s\"", _plmn) && _at->recv("OK"); 00810 } else { 00811 tr_debug("Automatic network registration"); 00812 _at->send("AT+COPS=0") && _at->recv("OK"); 00813 } 00814 at_set_timeout(at_timeout); 00815 00816 // Query the registration status directly as well, 00817 // just in case 00818 if (_at->send("AT+CREG?") && _at->recv("OK")) { 00819 // Answer will be processed by URC 00820 } 00821 if (_at->send("AT+CGREG?") && _at->recv("OK")) { 00822 // Answer will be processed by URC 00823 } 00824 if (_at->send("AT+CEREG?")) { 00825 _at->recv("OK"); 00826 // Don't check return value as this works for LTE only 00827 } 00828 } 00829 } 00830 // Wait for registration to succeed 00831 at_set_timeout(1000); 00832 for (int waitSeconds = 0; !registered && (waitSeconds < 180); waitSeconds++) { 00833 registered = is_registered_psd() || is_registered_csd() || is_registered_eps(); 00834 _at->recv(UNNATURAL_STRING); 00835 } 00836 at_set_timeout(at_timeout); 00837 00838 if (registered) { 00839 // This should return quickly but sometimes the status field is not returned 00840 // so make the timeout short 00841 at_set_timeout(1000); 00842 if (_at->send("AT+COPS?") && _at->recv("+COPS: %*d,%*d,\"%*[^\"]\",%d\n", &status)) { 00843 set_rat(status); 00844 } 00845 at_set_timeout(at_timeout); 00846 } 00847 } else { 00848 registered = true; 00849 } 00850 00851 UNLOCK(); 00852 return registered; 00853 } 00854 00855 bool UbloxCellularBase::is_registered_csd() 00856 { 00857 return (_dev_info.reg_status_csd == CSD_REGISTERED) || 00858 (_dev_info.reg_status_csd == CSD_REGISTERED_ROAMING) || 00859 (_dev_info.reg_status_csd == CSD_CSFB_NOT_PREFERRED); 00860 } 00861 00862 bool UbloxCellularBase::is_registered_psd() 00863 { 00864 return (_dev_info.reg_status_psd == PSD_REGISTERED) || 00865 (_dev_info.reg_status_psd == PSD_REGISTERED_ROAMING); 00866 } 00867 00868 bool UbloxCellularBase::is_registered_eps() 00869 { 00870 return (_dev_info.reg_status_eps == EPS_REGISTERED) || 00871 (_dev_info.reg_status_eps == EPS_REGISTERED_ROAMING); 00872 } 00873 00874 // Perform deregistration. 00875 bool UbloxCellularBase::nwk_deregistration() 00876 { 00877 bool success = false; 00878 LOCK(); 00879 00880 MBED_ASSERT(_at != NULL); 00881 00882 if (_at->send("AT+COPS=2") && _at->recv("OK")) { 00883 _dev_info.reg_status_csd = CSD_NOT_REGISTERED_NOT_SEARCHING; 00884 _dev_info.reg_status_psd = PSD_NOT_REGISTERED_NOT_SEARCHING; 00885 _dev_info.reg_status_eps = EPS_NOT_REGISTERED_NOT_SEARCHING; 00886 success = true; 00887 } 00888 00889 UNLOCK(); 00890 return success; 00891 } 00892 00893 // Put the modem into its lowest power state. 00894 void UbloxCellularBase::deinit() 00895 { 00896 power_down(); 00897 _modem_initialised = false; 00898 } 00899 00900 // Set the PIN. 00901 void UbloxCellularBase::set_pin(const char *pin) { 00902 _pin = pin; 00903 } 00904 00905 // Enable or disable SIM pin checking. 00906 bool UbloxCellularBase::sim_pin_check_enable(bool enableNotDisable) 00907 { 00908 bool success = false;; 00909 LOCK(); 00910 00911 MBED_ASSERT(_at != NULL); 00912 00913 if (_pin != NULL) { 00914 if (_sim_pin_check_enabled && !enableNotDisable) { 00915 // Disable the SIM lock 00916 if (_at->send("AT+CLCK=\"SC\",0,\"%s\"", _pin) && _at->recv("OK")) { 00917 _sim_pin_check_enabled = false; 00918 success = true; 00919 } 00920 } else if (!_sim_pin_check_enabled && enableNotDisable) { 00921 // Enable the SIM lock 00922 if (_at->send("AT+CLCK=\"SC\",1,\"%s\"", _pin) && _at->recv("OK")) { 00923 _sim_pin_check_enabled = true; 00924 success = true; 00925 } 00926 } else { 00927 success = true; 00928 } 00929 } 00930 00931 UNLOCK(); 00932 return success; 00933 } 00934 00935 // Change the pin code for the SIM card. 00936 bool UbloxCellularBase::change_sim_pin(const char *pin) 00937 { 00938 bool success = false;; 00939 LOCK(); 00940 00941 MBED_ASSERT(_at != NULL); 00942 00943 // Change the SIM pin 00944 if ((pin != NULL) && (_pin != NULL)) { 00945 if (_at->send("AT+CPWD=\"SC\",\"%s\",\"%s\"", _pin, pin) && _at->recv("OK")) { 00946 _pin = pin; 00947 success = true; 00948 } 00949 } 00950 00951 UNLOCK(); 00952 return success; 00953 } 00954 00955 // Get the IMEI. 00956 bool UbloxCellularBase::get_imei(char *imei_to_send, int size) 00957 { 00958 bool success; 00959 LOCK(); 00960 00961 MBED_ASSERT(_at != NULL); 00962 00963 // International mobile equipment identifier 00964 // AT Command Manual UBX-13002752, section 4.7 00965 success = _at->send("AT+CGSN") && _at->recv("%15[^\n]\nOK\n", _dev_info.imei); 00966 tr_info("DevInfo: IMEI=%s", _dev_info.imei); 00967 00968 if (success) { 00969 memcpy(imei_to_send,_dev_info.imei,size); 00970 imei_to_send[size-1] = '\0'; 00971 } 00972 00973 UNLOCK(); 00974 return success; 00975 } 00976 00977 // Get the IMEI of the module. 00978 const char *UbloxCellularBase::imei() 00979 { 00980 return _dev_info.imei; 00981 } 00982 00983 // Get the Mobile Equipment ID (which may be the same as the IMEI). 00984 const char *UbloxCellularBase::meid() 00985 { 00986 return _dev_info.meid; 00987 } 00988 00989 // Get the IMSI of the SIM. 00990 const char *UbloxCellularBase::imsi() 00991 { 00992 // (try) to update the IMSI, just in case the SIM has changed 00993 get_imsi(); 00994 00995 return _dev_info.imsi; 00996 } 00997 00998 // Get the ICCID of the SIM. 00999 const char *UbloxCellularBase::iccid() 01000 { 01001 // (try) to update the ICCID, just in case the SIM has changed 01002 get_iccid(); 01003 01004 return _dev_info.iccid; 01005 } 01006 01007 // Get the RSSI in dBm. 01008 int UbloxCellularBase::rssi() 01009 { 01010 char buf[7] = {0}; 01011 int rssi = 0; 01012 int qual = 0; 01013 int rssiRet = 0; 01014 bool success; 01015 LOCK(); 01016 01017 MBED_ASSERT(_at != NULL); 01018 01019 success = _at->send("AT+CSQ") && _at->recv("+CSQ: %6[^\n]\nOK\n", buf); 01020 01021 if (success) { 01022 if (sscanf(buf, "%d,%d", &rssi, &qual) == 2) { 01023 // AT+CSQ returns a coded RSSI value and an RxQual value 01024 // For 2G an RSSI of 0 corresponds to -113 dBm or less, 01025 // an RSSI of 31 corresponds to -51 dBm or less and hence 01026 // each value is a 2 dB step. 01027 // For LTE the mapping is defined in the array rssiConvertLte[]. 01028 // For 3G the mapping to RSCP is defined in the array rscpConvert3G[] 01029 // and the RSSI value is then RSCP - the EC_NO_LEV number derived 01030 // by putting the qual number through qualConvert3G[]. 01031 if ((rssi >= 0) && (rssi <= 31)) { 01032 switch (_dev_info.rat) { 01033 case UTRAN: 01034 case HSDPA: 01035 case HSUPA: 01036 case HSDPA_HSUPA: 01037 // 3G 01038 if ((qual >= 0) && (qual <= 7)) { 01039 qual = qualConvert3G[qual]; 01040 rssiRet = rscpConvert3G[rssi]; 01041 rssiRet -= qual; 01042 } 01043 01044 break; 01045 case LTE: 01046 // LTE 01047 rssiRet = rssiConvertLte[rssi]; 01048 break; 01049 case GSM: 01050 case COMPACT_GSM: 01051 case EDGE: 01052 default: 01053 // GSM or assumed GSM if the RAT is not known 01054 rssiRet = -(113 - (rssi << 2)); 01055 break; 01056 } 01057 } 01058 } 01059 } 01060 01061 UNLOCK(); 01062 return rssiRet; 01063 } 01064 01065 //RAT should be set in a detached state (AT+COPS=2) 01066 bool UbloxCellularBase::set_modem_rat(RAT selected_rat, RAT preferred_rat, RAT second_preferred_rat) 01067 { 01068 bool success = false; 01069 char command[16] = {0x00}; 01070 01071 //check if modem is registered with network 01072 if (is_registered_csd() || is_registered_psd() || is_registered_eps()) { 01073 tr_error("RAT should only be set in detached state"); 01074 return false; 01075 } 01076 01077 if (preferred_rat != NOT_USED && second_preferred_rat != NOT_USED) { 01078 sprintf(command, "AT+URAT=%d,%d,%d", selected_rat, preferred_rat, second_preferred_rat); 01079 } else if (preferred_rat != NOT_USED) { 01080 sprintf(command, "AT+URAT=%d,%d", selected_rat, preferred_rat); 01081 } else if (second_preferred_rat != NOT_USED) { 01082 sprintf(command, "AT+URAT=%d,%d", selected_rat, second_preferred_rat); 01083 } else { 01084 sprintf(command, "AT+URAT=%d", selected_rat); 01085 } 01086 01087 LOCK(); 01088 if (_at->send(command) && _at->recv("OK")) { 01089 success = true; 01090 } else { 01091 tr_error("unable to set the specified RAT"); 01092 success = false; 01093 } 01094 UNLOCK(); 01095 01096 return success; 01097 } 01098 01099 bool UbloxCellularBase::get_modem_rat(RAT *selected_rat, RAT *preferred_rat, RAT *second_preferred_rat) 01100 { 01101 bool success = false; 01102 char buf[24] = {0x00}; 01103 01104 if (selected_rat == NULL || preferred_rat == NULL || second_preferred_rat == NULL) { 01105 tr_info("invalid pointers"); 01106 return false; 01107 } 01108 01109 MBED_ASSERT(_at != NULL); 01110 01111 *selected_rat = NOT_USED; 01112 *preferred_rat = NOT_USED; 01113 *second_preferred_rat = NOT_USED; 01114 01115 LOCK(); 01116 01117 if (_at->send("AT+URAT?") && _at->recv("%23[^\n]\nOK\n", buf)) { 01118 if (sscanf(buf, "+URAT: %d,%d,%d", (int*)selected_rat, (int*)preferred_rat, (int*)second_preferred_rat) == 3) { 01119 success = true; 01120 } else if (sscanf(buf, "+URAT: %d,%d", (int*)selected_rat, (int*)preferred_rat) == 2) { 01121 success = true; 01122 } else if (sscanf(buf, "+URAT: %d", (int*)selected_rat) == 1) { 01123 success = true; 01124 } 01125 } 01126 01127 UNLOCK(); 01128 return success; 01129 } 01130 01131 // Power down modem via AT interface. 01132 bool UbloxCellularBase::reboot_modem() 01133 { 01134 bool return_val = false; 01135 int at_timeout; 01136 LOCK(); 01137 01138 MBED_ASSERT(_at != NULL); 01139 01140 at_timeout = _at_timeout; // Has to be inside LOCK()s 01141 at_set_timeout(3*60*1000); //command has 3 minutes timeout 01142 tr_info("rebooting modem..."); 01143 01144 if (_at->send("AT+CFUN=15") && _at->recv("OK")) { 01145 tr_info("reboot successful"); 01146 return_val = true; 01147 } 01148 01149 _dev_info.reg_status_csd = CSD_NOT_REGISTERED_NOT_SEARCHING; 01150 _dev_info.reg_status_psd = PSD_NOT_REGISTERED_NOT_SEARCHING; 01151 _dev_info.reg_status_eps = EPS_NOT_REGISTERED_NOT_SEARCHING; 01152 _modem_initialised = false; 01153 at_set_timeout(at_timeout); 01154 UNLOCK(); 01155 01156 return return_val; 01157 } 01158 01159 #ifdef TARGET_UBLOX_C030_R41XM 01160 bool UbloxCellularBase::set_mno_profile(MNOProfile profile) 01161 { 01162 bool return_val = false; 01163 01164 MNOProfile mno_profile; 01165 if (get_mno_profile(&mno_profile)) { 01166 tr_info("Current MNO profile is: %d", (int)mno_profile); 01167 if (mno_profile != profile) { 01168 01169 if (is_registered_csd() || is_registered_psd() || is_registered_eps()) { 01170 tr_error("MNO profile should only be set in detached state"); 01171 return false; 01172 } 01173 01174 LOCK(); 01175 if (_at->send("AT+UMNOPROF=%d", profile) && _at->recv("OK")) { 01176 return_val = true; 01177 } else { 01178 tr_error("unable to set specified profile"); 01179 } 01180 UNLOCK(); 01181 01182 } else { 01183 return_val = true; 01184 } 01185 } else { 01186 tr_error("could not read MNO profile"); 01187 } 01188 01189 return return_val; 01190 } 01191 01192 bool UbloxCellularBase::get_mno_profile(MNOProfile *profile) 01193 { 01194 bool return_val = false; 01195 01196 if (profile == NULL) { 01197 return false; 01198 } 01199 01200 LOCK(); 01201 MBED_ASSERT(_at != NULL); 01202 01203 if ( (_at->send("AT+UMNOPROF?") && _at->recv("+UMNOPROF: %d", (int*)profile) && _at->recv("OK")) ) { 01204 return_val = true; 01205 } 01206 01207 UNLOCK(); 01208 return return_val; 01209 } 01210 #endif 01211 01212 // End of File 01213
Generated on Sun Jul 31 2022 21:56:42 by 1.7.2