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