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.
Dependencies: nRF51_Vdd TextLCD BME280
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_gw_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 15:15:56 by
