Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
PPPCellularInterface.cpp
00001 /* Copyright (c) 2017 ARM 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 #include "PPPCellularInterface.h" 00016 00017 #if NSAPI_PPP_AVAILABLE 00018 00019 #include <string.h> 00020 #include "nsapi_ppp.h" 00021 #if MBED_CONF_PPP_CELL_IFACE_APN_LOOKUP 00022 #include "utils/APN_db.h" 00023 #endif //MBED_CONF_PPP_CELL_IFACE_APN_LOOKUP 00024 #if defined(FEATURE_COMMON_PAL) 00025 #include "mbed_trace.h" 00026 #define TRACE_GROUP "UCID" 00027 #else 00028 #define tr_debug(...) (void(0)) //dummies if feature common pal is not added 00029 #define tr_info(...) (void(0)) //dummies if feature common pal is not added 00030 #define tr_error(...) (void(0)) //dummies if feature common pal is not added 00031 #endif //defined(FEATURE_COMMON_PAL) 00032 00033 /** 00034 * PDP (packet data profile) Context 00035 */ 00036 #define CTX "1" 00037 00038 /** 00039 * Output Enter sequence for the modem , default CR 00040 */ 00041 #define OUTPUT_ENTER_KEY "\r" 00042 00043 #if MBED_CONF_PPP_CELL_IFACE_AT_PARSER_BUFFER_SIZE 00044 #define AT_PARSER_BUFFER_SIZE MBED_CONF_PPP_CELL_IFACE_AT_PARSER_BUFFER_SIZE //bytes 00045 #else 00046 #define AT_PARSER_BUFFER_SIZE 256 //bytes 00047 #endif //MBED_CONF_PPP_CELL_IFACE_AT_PARSER_BUFFER_SIZE 00048 00049 #if MBED_CONF_PPP_CELL_IFACE_AT_PARSER_TIMEOUT 00050 #define AT_PARSER_TIMEOUT MBED_CONF_PPP_CELL_IFACE_AT_PARSER_TIMEOUT 00051 #else 00052 #define AT_PARSER_TIMEOUT 8*1000 //miliseconds 00053 #endif //MBED_CONF_PPP_CELL_IFACE_AT_PARSER_TIMEOUT 00054 00055 static bool initialized; 00056 static bool set_credentials_api_used; 00057 static bool set_sim_pin_check_request; 00058 static bool change_pin; 00059 static device_info dev_info; 00060 00061 static void parser_abort(ATCmdParser *at) 00062 { 00063 at->abort(); 00064 } 00065 00066 static bool get_CCID(ATCmdParser *at) 00067 { 00068 // Returns the ICCID (Integrated Circuit Card ID) of the SIM-card. 00069 // ICCID is a serial number identifying the SIM. 00070 bool success = at->send("AT+CCID") && at->recv("+CCID: %20[^\n]\nOK\n", dev_info.ccid); 00071 tr_debug("DevInfo: CCID=%s", dev_info.ccid); 00072 return success; 00073 } 00074 00075 static bool get_IMSI(ATCmdParser *at) 00076 { 00077 // International mobile subscriber identification 00078 bool success = at->send("AT+CIMI") && at->recv("%15[^\n]\nOK\n", dev_info.imsi); 00079 tr_debug("DevInfo: IMSI=%s", dev_info.imsi); 00080 return success; 00081 } 00082 00083 static bool get_IMEI(ATCmdParser *at) 00084 { 00085 // International mobile equipment identifier 00086 bool success = at->send("AT+CGSN") && at->recv("%15[^\n]\nOK\n", dev_info.imei); 00087 tr_debug("DevInfo: IMEI=%s", dev_info.imei); 00088 return success; 00089 } 00090 00091 static bool get_MEID(ATCmdParser *at) 00092 { 00093 // Mobile equipment identifier 00094 bool success = at->send("AT+GSN") 00095 && at->recv("%18[^\n]\nOK\n", dev_info.meid); 00096 tr_debug("DevInfo: MEID=%s", dev_info.meid); 00097 return success; 00098 } 00099 00100 static bool set_CMGF(ATCmdParser *at) 00101 { 00102 // Preferred message format 00103 // set AT+CMGF=[mode] , 0 PDU mode, 1 text mode 00104 bool success = at->send("AT+CMGF=1") && at->recv("OK"); 00105 return success; 00106 } 00107 00108 static bool set_CNMI(ATCmdParser *at) 00109 { 00110 // New SMS indication configuration 00111 // set AT+CMTI=[mode, index] , 0 PDU mode, 1 text mode 00112 // Multiple URCs for SMS, i.e., CMT, CMTI, UCMT, CBMI, CDSI as DTE could be following any of these SMS formats 00113 bool success = at->send("AT+CNMI=2," CTX) && at->recv("OK"); 00114 return success; 00115 } 00116 00117 static void CMTI_URC(ATCmdParser *at) 00118 { 00119 // our CMGF = 1, i.e., text mode. So we expect response in this format: 00120 //+CMTI: <mem>,<index>, 00121 at->recv(": %*u,%*u"); 00122 tr_info("New SMS received"); 00123 00124 } 00125 00126 static void CMT_URC(ATCmdParser *at) 00127 { 00128 // our CMGF = 1, i.e., text mode. So we expect response in this format: 00129 //+CMT: <oa>,[<alpha>],<scts>[,<tooa>, 00130 //<fo>,<pid>,<dcs>,<sca>,<tosca>, 00131 //<length>]<CR><LF><data> 00132 // By default detailed SMS header CSDH=0 , so we are not expecting [,<tooa>, 00133 //<fo>,<pid>,<dcs>,<sca>,<tosca> 00134 char sms[50]; 00135 char service_timestamp[15]; 00136 at->recv(": %49[^\"]\",,%14[^\"]\"\n", sms, service_timestamp); 00137 00138 tr_info("SMS:%s, %s", service_timestamp, sms); 00139 00140 } 00141 00142 static bool set_atd(ATCmdParser *at) 00143 { 00144 bool success = at->send("ATD*99***" CTX "#") && at->recv("CONNECT"); 00145 00146 return success; 00147 } 00148 00149 /** 00150 * Enables or disables SIM pin check lock 00151 */ 00152 static nsapi_error_t do_sim_pin_check(ATCmdParser *at, const char *pin) 00153 { 00154 bool success; 00155 if (set_sim_pin_check_request) { 00156 /* use the SIM locked */ 00157 success = at->send("AT+CLCK=\"SC\",1,\"%s\"", pin) && at->recv("OK"); 00158 } else { 00159 /* use the SIM unlocked */ 00160 success = at->send("AT+CLCK=\"SC\",0,\"%s\"",pin) && at->recv("OK"); 00161 } 00162 00163 if (success) return NSAPI_ERROR_OK ; 00164 00165 return NSAPI_ERROR_AUTH_FAILURE ; 00166 } 00167 00168 /** 00169 * Change the pin code for the SIM card 00170 */ 00171 static nsapi_error_t do_change_sim_pin(ATCmdParser *at, const char *old_pin, const char *new_pin) 00172 { 00173 /* changes the SIM pin */ 00174 bool success = at->send("AT+CPWD=\"SC\",\"%s\",\"%s\"", old_pin, new_pin) && at->recv("OK"); 00175 if (success) { 00176 return NSAPI_ERROR_OK ; 00177 } 00178 00179 return NSAPI_ERROR_AUTH_FAILURE ; 00180 } 00181 00182 static void set_nwk_reg_status_csd(unsigned int status) 00183 { 00184 switch (status) { 00185 case CSD_NOT_REGISTERED_NOT_SEARCHING: 00186 case CSD_NOT_REGISTERED_SEARCHING: 00187 break; 00188 case CSD_REGISTERED: 00189 case CSD_REGISTERED_ROAMING: 00190 tr_debug("Registered for circuit switched service"); 00191 break; 00192 case CSD_REGISTRATION_DENIED: 00193 tr_debug("Circuit switched service denied"); 00194 break; 00195 case CSD_UNKNOWN_COVERAGE: 00196 tr_debug("Out of circuit switched service coverage"); 00197 break; 00198 case CSD_SMS_ONLY: 00199 tr_debug("SMS service only"); 00200 break; 00201 case CSD_SMS_ONLY_ROAMING: 00202 tr_debug("SMS service only"); 00203 break; 00204 case CSD_CSFB_NOT_PREFERRED: 00205 tr_debug("Registered for circuit switched service with CSFB not preferred"); 00206 break; 00207 default: 00208 tr_debug("Unknown circuit switched service registration status. %u", status); 00209 break; 00210 } 00211 00212 dev_info.reg_status_csd = static_cast<nwk_registration_status_csd>(status); 00213 } 00214 00215 static void set_nwk_reg_status_psd(unsigned int status) 00216 { 00217 switch (status) { 00218 case PSD_NOT_REGISTERED_NOT_SEARCHING: 00219 case PSD_NOT_REGISTERED_SEARCHING: 00220 break; 00221 case PSD_REGISTERED: 00222 case PSD_REGISTERED_ROAMING: 00223 tr_debug("Registered for packet switched service"); 00224 break; 00225 case PSD_REGISTRATION_DENIED: 00226 tr_debug("Packet switched service denied"); 00227 break; 00228 case PSD_UNKNOWN_COVERAGE: 00229 tr_debug("Out of packet switched service coverage"); 00230 break; 00231 case PSD_EMERGENCY_SERVICES_ONLY: 00232 tr_debug("Limited access for packet switched service. Emergency use only."); 00233 break; 00234 default: 00235 tr_debug("Unknown packet switched service registration status. %u", status); 00236 break; 00237 } 00238 00239 dev_info.reg_status_psd = static_cast<nwk_registration_status_psd>(status); 00240 } 00241 00242 static bool is_registered_csd() 00243 { 00244 return (dev_info.reg_status_csd == CSD_REGISTERED) || 00245 (dev_info.reg_status_csd == CSD_REGISTERED_ROAMING) || 00246 (dev_info.reg_status_csd == CSD_CSFB_NOT_PREFERRED); 00247 } 00248 00249 static bool is_registered_psd() 00250 { 00251 return (dev_info.reg_status_psd == PSD_REGISTERED) || 00252 (dev_info.reg_status_psd == PSD_REGISTERED_ROAMING); 00253 } 00254 00255 PPPCellularInterface::PPPCellularInterface(FileHandle *fh, bool debug) 00256 { 00257 _new_pin = NULL; 00258 _pin = NULL; 00259 _at = NULL; 00260 _apn = "internet"; 00261 _uname = NULL; 00262 _pwd = NULL; 00263 _fh = fh; 00264 _debug_trace_on = debug; 00265 _stack = DEFAULT_STACK; 00266 dev_info.reg_status_csd = CSD_NOT_REGISTERED_NOT_SEARCHING; 00267 dev_info.reg_status_psd = PSD_NOT_REGISTERED_NOT_SEARCHING; 00268 dev_info.ppp_connection_up = false; 00269 } 00270 00271 00272 PPPCellularInterface::~PPPCellularInterface() 00273 { 00274 delete _at; 00275 } 00276 00277 void PPPCellularInterface::enable_hup(bool) 00278 { 00279 //meant to be overridden 00280 } 00281 00282 void PPPCellularInterface::modem_init() 00283 { 00284 //meant to be overridden 00285 } 00286 00287 void PPPCellularInterface::modem_deinit() 00288 { 00289 //meant to be overridden 00290 } 00291 00292 void PPPCellularInterface::modem_power_up() 00293 { 00294 //meant to be overridden 00295 } 00296 00297 void PPPCellularInterface::modem_power_down() 00298 { 00299 //meant to be overridden 00300 } 00301 00302 void PPPCellularInterface::modem_debug_on(bool on) 00303 { 00304 _debug_trace_on = on; 00305 } 00306 00307 void PPPCellularInterface::connection_status_cb(Callback<void(nsapi_error_t)> cb) 00308 { 00309 _connection_status_cb = cb; 00310 } 00311 00312 /** 00313 * Public API. Sets up the flag for the driver to enable or disable SIM pin check 00314 * at the next boot. 00315 */ 00316 void PPPCellularInterface::set_sim_pin_check(bool check) 00317 { 00318 set_sim_pin_check_request = check; 00319 } 00320 00321 /** 00322 * Public API. Sets up the flag for the driver to change pin code for SIM card 00323 */ 00324 void PPPCellularInterface::set_new_sim_pin(const char *new_pin) 00325 { 00326 change_pin = true; 00327 _new_pin = new_pin; 00328 } 00329 00330 bool PPPCellularInterface::nwk_registration(uint8_t nwk_type) 00331 { 00332 bool success = false; 00333 bool registered = false; 00334 00335 char str[35]; 00336 int retcode; 00337 int retry_counter = 0; 00338 unsigned int reg_status; 00339 00340 success = nwk_type == PACKET_SWITCHED ? 00341 _at->send("AT+CGREG=0") : 00342 _at->send("AT+CREG=0") && _at->recv("OK\n"); 00343 00344 success = _at->send("AT+COPS=0") //initiate auto-registration 00345 && _at->recv("OK"); 00346 if (!success) { 00347 tr_error("Modem not responding."); 00348 return false; 00349 } 00350 00351 //Network search 00352 //If not registered after 60 attempts, i.e., 30 seconds wait, give up 00353 tr_debug("Searching Network ..."); 00354 00355 while (!registered) { 00356 00357 if (retry_counter > 60) { 00358 success = false; 00359 goto give_up; 00360 } 00361 00362 success = nwk_type == PACKET_SWITCHED ? 00363 _at->send("AT+CGREG?") 00364 && _at->recv("+CGREG: %34[^\n]\n", str) 00365 && _at->recv("OK\n") : 00366 _at->send("AT+CREG?") 00367 && _at->recv("+CREG: %34[^\n]\n", str) 00368 && _at->recv("OK\n"); 00369 00370 retcode = sscanf(str, "%*u,%u", ®_status); 00371 00372 if (retcode >= 1) { 00373 if (nwk_type == PACKET_SWITCHED) { 00374 set_nwk_reg_status_psd(reg_status); 00375 if (is_registered_psd()) { 00376 registered = true; 00377 } 00378 } else if (nwk_type == CIRCUIT_SWITCHED) { 00379 set_nwk_reg_status_csd(reg_status); 00380 if (is_registered_csd()) { 00381 registered = true; 00382 } 00383 } 00384 } 00385 00386 if (registered) { 00387 break; 00388 } else { 00389 wait_ms(500); 00390 } 00391 00392 retry_counter++; 00393 } 00394 00395 give_up: 00396 return registered; 00397 } 00398 00399 bool PPPCellularInterface::is_connected() 00400 { 00401 return dev_info.ppp_connection_up; 00402 } 00403 00404 // Get the SIM card going. 00405 nsapi_error_t PPPCellularInterface::initialize_sim_card() 00406 { 00407 nsapi_error_t nsapi_error = NSAPI_ERROR_AUTH_FAILURE ; 00408 int retry_count = 0; 00409 bool done = false; 00410 00411 /* SIM initialization may take a significant amount, so an error is 00412 * kind of expected. We should retry 10 times until we succeed or timeout. */ 00413 for (retry_count = 0; !done && (retry_count < 10); retry_count++) { 00414 char pinstr[16]; 00415 00416 if (_at->send("AT+CPIN?") && _at->recv("+CPIN: %15[^\n]\nOK\n", pinstr)) { 00417 if (strcmp(pinstr, "SIM PIN") == 0) { 00418 if (!_at->send("AT+CPIN=\"%s\"", _pin) || !_at->recv("OK")) { 00419 tr_debug("PIN correct"); 00420 nsapi_error = NSAPI_ERROR_OK ; 00421 } 00422 } else if (strcmp(pinstr, "READY") == 0) { 00423 tr_debug("SIM Ready"); 00424 nsapi_error = NSAPI_ERROR_OK ; 00425 done = true; 00426 } else { 00427 tr_debug("Unexpected response from SIM: \"%s\"", pinstr); 00428 } 00429 } 00430 00431 /* wait for a second before retry */ 00432 wait_ms(1000); 00433 } 00434 00435 if (!done) { 00436 tr_error("SIM not ready."); 00437 } 00438 00439 return nsapi_error; 00440 } 00441 00442 void PPPCellularInterface::set_sim_pin(const char *pin) { 00443 /* overwrite the default pin by user provided pin */ 00444 _pin = pin; 00445 } 00446 00447 nsapi_error_t PPPCellularInterface::setup_context_and_credentials() 00448 { 00449 bool success; 00450 00451 if (!_apn) { 00452 return NSAPI_ERROR_PARAMETER ; 00453 } 00454 00455 #if NSAPI_PPP_IPV4_AVAILABLE && NSAPI_PPP_IPV6_AVAILABLE 00456 const char ipv4v6_pdp_type[] = {"IPV4V6"}; 00457 const char ipv4_pdp_type[] = {"IP"}; 00458 const char *pdp_type = ipv4v6_pdp_type; 00459 _stack = IPV4V6_STACK; 00460 #elif NSAPI_PPP_IPV6_AVAILABLE 00461 const char pdp_type[] = {"IPV6"}; 00462 #elif NSAPI_PPP_IPV4_AVAILABLE 00463 const char pdp_type[] = {"IP"}; 00464 #endif 00465 const char *auth = _uname && _pwd ? "CHAP:" : ""; 00466 00467 #if NSAPI_PPP_IPV4_AVAILABLE && NSAPI_PPP_IPV6_AVAILABLE 00468 retry_without_dual_stack: 00469 #endif 00470 success = _at->send("AT" 00471 "+FCLASS=0;" // set to connection (ATD) to data mode 00472 "+CGDCONT=" CTX ",\"%s\",\"%s%s\"", 00473 pdp_type, auth, _apn 00474 ) 00475 && _at->recv("OK"); 00476 00477 #if NSAPI_PPP_IPV4_AVAILABLE && NSAPI_PPP_IPV6_AVAILABLE 00478 if (_stack == IPV4V6_STACK) { 00479 if (!success) { 00480 // fallback to ipv4 00481 pdp_type = ipv4_pdp_type; 00482 _stack = IPV4_STACK; 00483 goto retry_without_dual_stack; 00484 } 00485 } 00486 #endif 00487 00488 if (!success) { 00489 _at->recv("OK"); 00490 } 00491 00492 return success ? NSAPI_ERROR_OK : NSAPI_ERROR_PARAMETER ; 00493 00494 } 00495 00496 void PPPCellularInterface::set_credentials(const char *apn, const char *uname, 00497 const char *pwd) 00498 { 00499 _apn = apn; 00500 _uname = uname; 00501 _pwd = pwd; 00502 set_credentials_api_used = true; 00503 } 00504 00505 00506 00507 void PPPCellularInterface::setup_at_parser() 00508 { 00509 if (_at) { 00510 return; 00511 } 00512 00513 _at = new ATCmdParser(_fh, OUTPUT_ENTER_KEY, AT_PARSER_BUFFER_SIZE, AT_PARSER_TIMEOUT, 00514 _debug_trace_on ? true : false); 00515 00516 /* Error cases, out of band handling */ 00517 _at->oob("ERROR", callback(parser_abort, _at)); 00518 _at->oob("+CME ERROR", callback(parser_abort, _at)); 00519 _at->oob("+CMS ERROR", callback(parser_abort, _at)); 00520 _at->oob("NO CARRIER", callback(parser_abort, _at)); 00521 00522 /* URCs, handled out of band */ 00523 _at->oob("+CMT", callback(CMT_URC, _at)); 00524 _at->oob("+CMTI", callback(CMTI_URC, _at)); 00525 } 00526 00527 void PPPCellularInterface::shutdown_at_parser() 00528 { 00529 delete _at; 00530 _at = NULL; 00531 } 00532 00533 nsapi_error_t PPPCellularInterface::connect(const char *sim_pin, const char *apn, const char *uname, const char *pwd) 00534 { 00535 if (!sim_pin) { 00536 return NSAPI_ERROR_PARAMETER ; 00537 } 00538 00539 if (apn) { 00540 _apn = apn; 00541 } 00542 00543 if (uname && pwd) { 00544 _uname = uname; 00545 _pwd = pwd; 00546 } else { 00547 _uname = NULL; 00548 _pwd = NULL; 00549 } 00550 00551 _pin = sim_pin; 00552 00553 return connect(); 00554 } 00555 00556 nsapi_error_t PPPCellularInterface::connect() 00557 { 00558 nsapi_error_t retcode; 00559 bool success; 00560 bool did_init = false; 00561 const char *apn_config = NULL; 00562 00563 if (dev_info.ppp_connection_up) { 00564 return NSAPI_ERROR_IS_CONNECTED ; 00565 } 00566 00567 do { 00568 retry_init: 00569 00570 /* setup AT parser */ 00571 setup_at_parser(); 00572 00573 if (!initialized) { 00574 00575 /* If we have hangup (eg DCD) detection, we don't want it active 00576 * as long as we are using ATCmdParser. 00577 * As soon as we get into data mode, we will turn it back on. */ 00578 enable_hup(false); 00579 00580 if (!power_up()) { 00581 return NSAPI_ERROR_DEVICE_ERROR ; 00582 } 00583 00584 retcode = initialize_sim_card(); 00585 if (retcode != NSAPI_ERROR_OK ) { 00586 return retcode; 00587 } 00588 00589 success = nwk_registration(PACKET_SWITCHED) //perform network registration 00590 && get_CCID(_at)//get integrated circuit ID of the SIM 00591 && get_IMSI(_at)//get international mobile subscriber information 00592 && get_IMEI(_at)//get international mobile equipment identifier 00593 && get_MEID(_at)//its same as IMEI 00594 && set_CMGF(_at)//set message format for SMS 00595 && set_CNMI(_at);//set new SMS indication 00596 00597 if (!success) { 00598 return NSAPI_ERROR_NO_CONNECTION ; 00599 } 00600 00601 #if MBED_CONF_PPP_CELL_IFACE_APN_LOOKUP 00602 if (!apn_config) { 00603 apn_config = apnconfig(dev_info.imsi); 00604 } 00605 #endif 00606 00607 /* Check if user want skip SIM pin checking on boot up */ 00608 if (set_sim_pin_check_request) { 00609 retcode = do_sim_pin_check(_at, _pin); 00610 if (retcode != NSAPI_ERROR_OK ) { 00611 return retcode; 00612 } 00613 /* set this request to false, as it is unnecessary to repeat in case of retry */ 00614 set_sim_pin_check_request = false; 00615 } 00616 00617 /* check if the user requested a sim pin change */ 00618 if (change_pin) { 00619 retcode = do_change_sim_pin(_at, _pin, _new_pin); 00620 if (retcode != NSAPI_ERROR_OK ) { 00621 return retcode; 00622 } 00623 /* set this request to false, as it is unnecessary to repeat in case of retry */ 00624 change_pin = false; 00625 } 00626 00627 #if MBED_CONF_PPP_CELL_IFACE_APN_LOOKUP 00628 if (apn_config) { 00629 _apn = _APN_GET(apn_config); 00630 _uname = _APN_GET(apn_config); 00631 _pwd = _APN_GET(apn_config); 00632 tr_info("Looked up APN %s.", _apn); 00633 } 00634 #endif 00635 00636 //sets up APN and IP protocol for external PDP context 00637 retcode = setup_context_and_credentials(); 00638 if (retcode != NSAPI_ERROR_OK ) { 00639 return retcode; 00640 } 00641 00642 if (!success) { 00643 shutdown_at_parser(); 00644 return NSAPI_ERROR_NO_CONNECTION ; 00645 } 00646 00647 initialized = true; 00648 did_init = true; 00649 } else { 00650 /* If we were already initialized, we expect to receive NO_CARRIER response 00651 * from the modem as we were kicked out of Data mode */ 00652 _at->recv("NO CARRIER"); 00653 success = _at->send("AT") && _at->recv("OK"); 00654 } 00655 00656 /* Attempt to enter data mode */ 00657 success = set_atd(_at); //enter into Data mode with the modem 00658 if (!success) { 00659 power_down(); 00660 initialized = false; 00661 00662 /* if we were previously initialized , i.e., not in this particular attempt, 00663 * we want to re-initialize */ 00664 if (!did_init) { 00665 goto retry_init; 00666 } 00667 00668 /* shutdown AT parser before notifying application of the failure */ 00669 shutdown_at_parser(); 00670 00671 return NSAPI_ERROR_NO_CONNECTION ; 00672 } 00673 00674 /* This is the success case. 00675 * Save RAM, discard AT Parser as we have entered Data mode. */ 00676 shutdown_at_parser(); 00677 00678 /* We now want hangup (e.g., DCD) detection if available */ 00679 enable_hup(true); 00680 00681 /* Initialize PPP 00682 * mbed_ppp_init() is a blocking call, it will block until 00683 * connected, or timeout after 30 seconds*/ 00684 retcode = nsapi_ppp_connect(_fh, _connection_status_cb, _uname, _pwd, _stack); 00685 if (retcode == NSAPI_ERROR_OK ) { 00686 dev_info.ppp_connection_up = true; 00687 } 00688 00689 }while(!dev_info.ppp_connection_up && apn_config && *apn_config); 00690 00691 return retcode; 00692 } 00693 00694 /** 00695 * User initiated disconnect 00696 * 00697 * Disconnects from PPP connection only and brings down the underlying network 00698 * interface 00699 */ 00700 nsapi_error_t PPPCellularInterface::disconnect() 00701 { 00702 nsapi_error_t ret = nsapi_ppp_disconnect(_fh); 00703 if (ret == NSAPI_ERROR_OK ) { 00704 dev_info.ppp_connection_up = false; 00705 return NSAPI_ERROR_OK ; 00706 } 00707 00708 return ret; 00709 } 00710 00711 const char *PPPCellularInterface::get_ip_address() 00712 { 00713 return nsapi_ppp_get_ip_addr(_fh); 00714 } 00715 00716 const char *PPPCellularInterface::get_netmask() 00717 { 00718 return nsapi_ppp_get_netmask(_fh); 00719 } 00720 00721 const char *PPPCellularInterface::get_gateway() 00722 { 00723 return nsapi_ppp_get_ip_addr(_fh); 00724 } 00725 00726 /** Power down modem 00727 * Uses AT command to do it */ 00728 void PPPCellularInterface::power_down() 00729 { 00730 modem_power_down(); 00731 modem_deinit(); 00732 } 00733 00734 /** 00735 * Powers up the modem 00736 * 00737 * Enables the GPIO lines to the modem and then wriggles the power line in short pulses. 00738 */ 00739 bool PPPCellularInterface::power_up() 00740 { 00741 /* Initialize GPIO lines */ 00742 modem_init(); 00743 /* Give modem a little time to settle down */ 00744 wait(0.25); 00745 00746 bool success = false; 00747 00748 int retry_count = 0; 00749 while (true) { 00750 modem_power_up(); 00751 /* Modem tends to spit out noise during power up - don't confuse the parser */ 00752 _at->flush(); 00753 /* It is mandatory to avoid sending data to the serial port during the first 200 ms 00754 * of the module startup. Telit_xE910 Global form factor App note. 00755 * Not necessary for all types of modems however. Let's wait just to be on the safe side */ 00756 wait_ms(200); 00757 _at->set_timeout(1000); 00758 if (_at->send("AT") && _at->recv("OK")) { 00759 tr_info("Modem Ready."); 00760 break; 00761 } 00762 00763 if (++retry_count > 10) { 00764 goto failure; 00765 } 00766 } 00767 00768 _at->set_timeout(8000); 00769 00770 /*For more details regarding DCD and DTR circuitry, please refer to Modem AT manual */ 00771 success = _at->send("AT" 00772 "E0;" //turn off modem echoing 00773 "+CMEE=2;"//turn on verbose responses 00774 "&K0"//turn off RTC/CTS handshaking 00775 "+IPR=115200;"//setup baud rate 00776 "&C1;"//set DCD circuit(109), changes in accordance with the carrier detect status 00777 "&D0")//set DTR circuit, we ignore the state change of DTR 00778 && _at->recv("OK"); 00779 00780 if (!success) { 00781 goto failure; 00782 } 00783 00784 /* If everything alright, return from here with success*/ 00785 return success; 00786 00787 failure: 00788 tr_error("Preliminary modem setup failed."); 00789 return false; 00790 } 00791 00792 /** 00793 * Get a pointer to the underlying network stack 00794 */ 00795 NetworkStack *PPPCellularInterface::get_stack() 00796 { 00797 return nsapi_ppp_get_stack(); 00798 } 00799 00800 #endif // NSAPI_PPP_AVAILABLE
Generated on Thu Jul 14 2022 14:36:21 by
