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