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