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 _connection_status_cb = NULL; 00267 _connect_status = NSAPI_STATUS_DISCONNECTED ; 00268 _connect_is_blocking = true; 00269 dev_info.reg_status_csd = CSD_NOT_REGISTERED_NOT_SEARCHING; 00270 dev_info.reg_status_psd = PSD_NOT_REGISTERED_NOT_SEARCHING; 00271 } 00272 00273 00274 PPPCellularInterface::~PPPCellularInterface() 00275 { 00276 delete _at; 00277 } 00278 00279 void PPPCellularInterface::enable_hup(bool) 00280 { 00281 //meant to be overridden 00282 } 00283 00284 void PPPCellularInterface::modem_init() 00285 { 00286 //meant to be overridden 00287 } 00288 00289 void PPPCellularInterface::modem_deinit() 00290 { 00291 //meant to be overridden 00292 } 00293 00294 void PPPCellularInterface::modem_power_up() 00295 { 00296 //meant to be overridden 00297 } 00298 00299 void PPPCellularInterface::modem_power_down() 00300 { 00301 //meant to be overridden 00302 } 00303 00304 void PPPCellularInterface::modem_debug_on(bool on) 00305 { 00306 _debug_trace_on = on; 00307 } 00308 00309 void PPPCellularInterface::ppp_status_cb(nsapi_event_t event, intptr_t parameter) 00310 { 00311 _connect_status = (nsapi_connection_status_t)parameter; 00312 00313 if (_connection_status_cb) { 00314 _connection_status_cb(event, parameter); 00315 } 00316 } 00317 00318 /** 00319 * Public API. Sets up the flag for the driver to enable or disable SIM pin check 00320 * at the next boot. 00321 */ 00322 void PPPCellularInterface::set_sim_pin_check(bool check) 00323 { 00324 set_sim_pin_check_request = check; 00325 } 00326 00327 /** 00328 * Public API. Sets up the flag for the driver to change pin code for SIM card 00329 */ 00330 void PPPCellularInterface::set_new_sim_pin(const char *new_pin) 00331 { 00332 change_pin = true; 00333 _new_pin = new_pin; 00334 } 00335 00336 bool PPPCellularInterface::nwk_registration(uint8_t nwk_type) 00337 { 00338 bool success = false; 00339 bool registered = false; 00340 00341 char str[35]; 00342 int retcode; 00343 int retry_counter = 0; 00344 unsigned int reg_status; 00345 00346 success = nwk_type == PACKET_SWITCHED ? 00347 _at->send("AT+CGREG=0") : 00348 _at->send("AT+CREG=0") && _at->recv("OK\n"); 00349 00350 success = _at->send("AT+COPS=0") //initiate auto-registration 00351 && _at->recv("OK"); 00352 if (!success) { 00353 tr_error("Modem not responding."); 00354 return false; 00355 } 00356 00357 //Network search 00358 //If not registered after 60 attempts, i.e., 30 seconds wait, give up 00359 tr_debug("Searching Network ..."); 00360 00361 while (!registered) { 00362 00363 if (retry_counter > 60) { 00364 success = false; 00365 goto give_up; 00366 } 00367 00368 success = nwk_type == PACKET_SWITCHED ? 00369 _at->send("AT+CGREG?") 00370 && _at->recv("+CGREG: %34[^\n]\n", str) 00371 && _at->recv("OK\n") : 00372 _at->send("AT+CREG?") 00373 && _at->recv("+CREG: %34[^\n]\n", str) 00374 && _at->recv("OK\n"); 00375 00376 retcode = sscanf(str, "%*u,%u", ®_status); 00377 00378 if (retcode >= 1) { 00379 if (nwk_type == PACKET_SWITCHED) { 00380 set_nwk_reg_status_psd(reg_status); 00381 if (is_registered_psd()) { 00382 registered = true; 00383 } 00384 } else if (nwk_type == CIRCUIT_SWITCHED) { 00385 set_nwk_reg_status_csd(reg_status); 00386 if (is_registered_csd()) { 00387 registered = true; 00388 } 00389 } 00390 } 00391 00392 if (registered) { 00393 break; 00394 } else { 00395 wait_ms(500); 00396 } 00397 00398 retry_counter++; 00399 } 00400 00401 give_up: 00402 return registered; 00403 } 00404 00405 bool PPPCellularInterface::is_connected() 00406 { 00407 return (_connect_status == NSAPI_STATUS_GLOBAL_UP || _connect_status == NSAPI_STATUS_LOCAL_UP ); 00408 } 00409 00410 // Get the SIM card going. 00411 nsapi_error_t PPPCellularInterface::initialize_sim_card() 00412 { 00413 nsapi_error_t nsapi_error = NSAPI_ERROR_AUTH_FAILURE ; 00414 int retry_count = 0; 00415 bool done = false; 00416 00417 /* SIM initialization may take a significant amount, so an error is 00418 * kind of expected. We should retry 10 times until we succeed or timeout. */ 00419 for (retry_count = 0; !done && (retry_count < 10); retry_count++) { 00420 char pinstr[16]; 00421 00422 if (_at->send("AT+CPIN?") && _at->recv("+CPIN: %15[^\n]\nOK\n", pinstr)) { 00423 if (strcmp(pinstr, "SIM PIN") == 0) { 00424 if (!_at->send("AT+CPIN=\"%s\"", _pin) || !_at->recv("OK")) { 00425 tr_debug("PIN correct"); 00426 nsapi_error = NSAPI_ERROR_OK ; 00427 } 00428 } else if (strcmp(pinstr, "READY") == 0) { 00429 tr_debug("SIM Ready"); 00430 nsapi_error = NSAPI_ERROR_OK ; 00431 done = true; 00432 } else { 00433 tr_debug("Unexpected response from SIM: \"%s\"", pinstr); 00434 } 00435 } 00436 00437 /* wait for a second before retry */ 00438 wait_ms(1000); 00439 } 00440 00441 if (!done) { 00442 tr_error("SIM not ready."); 00443 } 00444 00445 return nsapi_error; 00446 } 00447 00448 void PPPCellularInterface::set_sim_pin(const char *pin) { 00449 /* overwrite the default pin by user provided pin */ 00450 _pin = pin; 00451 } 00452 00453 nsapi_error_t PPPCellularInterface::setup_context_and_credentials() 00454 { 00455 bool success; 00456 00457 if (!_apn) { 00458 return NSAPI_ERROR_PARAMETER ; 00459 } 00460 00461 #if NSAPI_PPP_IPV4_AVAILABLE && NSAPI_PPP_IPV6_AVAILABLE 00462 const char ipv4v6_pdp_type[] = {"IPV4V6"}; 00463 const char ipv4_pdp_type[] = {"IP"}; 00464 const char *pdp_type = ipv4v6_pdp_type; 00465 _stack = IPV4V6_STACK; 00466 #elif NSAPI_PPP_IPV6_AVAILABLE 00467 const char pdp_type[] = {"IPV6"}; 00468 #elif NSAPI_PPP_IPV4_AVAILABLE 00469 const char pdp_type[] = {"IP"}; 00470 #endif 00471 const char *auth = _uname && _pwd ? "CHAP:" : ""; 00472 00473 #if NSAPI_PPP_IPV4_AVAILABLE && NSAPI_PPP_IPV6_AVAILABLE 00474 retry_without_dual_stack: 00475 #endif 00476 success = _at->send("AT" 00477 "+FCLASS=0;" // set to connection (ATD) to data mode 00478 "+CGDCONT=" CTX ",\"%s\",\"%s%s\"", 00479 pdp_type, auth, _apn 00480 ) 00481 && _at->recv("OK"); 00482 00483 #if NSAPI_PPP_IPV4_AVAILABLE && NSAPI_PPP_IPV6_AVAILABLE 00484 if (_stack == IPV4V6_STACK) { 00485 if (!success) { 00486 // fallback to ipv4 00487 pdp_type = ipv4_pdp_type; 00488 _stack = IPV4_STACK; 00489 goto retry_without_dual_stack; 00490 } 00491 } 00492 #endif 00493 00494 if (!success) { 00495 _at->recv("OK"); 00496 } 00497 00498 return success ? NSAPI_ERROR_OK : NSAPI_ERROR_PARAMETER ; 00499 00500 } 00501 00502 void PPPCellularInterface::set_credentials(const char *apn, const char *uname, 00503 const char *pwd) 00504 { 00505 _apn = apn; 00506 _uname = uname; 00507 _pwd = pwd; 00508 set_credentials_api_used = true; 00509 } 00510 00511 00512 00513 void PPPCellularInterface::setup_at_parser() 00514 { 00515 if (_at) { 00516 return; 00517 } 00518 00519 _at = new ATCmdParser(_fh, OUTPUT_ENTER_KEY, AT_PARSER_BUFFER_SIZE, AT_PARSER_TIMEOUT, 00520 _debug_trace_on ? true : false); 00521 00522 /* Error cases, out of band handling */ 00523 _at->oob("ERROR", callback(parser_abort, _at)); 00524 _at->oob("+CME ERROR", callback(parser_abort, _at)); 00525 _at->oob("+CMS ERROR", callback(parser_abort, _at)); 00526 _at->oob("NO CARRIER", callback(parser_abort, _at)); 00527 00528 /* URCs, handled out of band */ 00529 _at->oob("+CMT", callback(CMT_URC, _at)); 00530 _at->oob("+CMTI", callback(CMTI_URC, _at)); 00531 } 00532 00533 void PPPCellularInterface::shutdown_at_parser() 00534 { 00535 delete _at; 00536 _at = NULL; 00537 } 00538 00539 nsapi_error_t PPPCellularInterface::connect(const char *sim_pin, const char *apn, const char *uname, const char *pwd) 00540 { 00541 if (!sim_pin) { 00542 return NSAPI_ERROR_PARAMETER ; 00543 } 00544 00545 if (apn) { 00546 _apn = apn; 00547 } 00548 00549 if (uname && pwd) { 00550 _uname = uname; 00551 _pwd = pwd; 00552 } else { 00553 _uname = NULL; 00554 _pwd = NULL; 00555 } 00556 00557 _pin = sim_pin; 00558 00559 return connect(); 00560 } 00561 00562 nsapi_error_t PPPCellularInterface::connect() 00563 { 00564 nsapi_error_t retcode; 00565 bool success; 00566 bool did_init = false; 00567 const char *apn_config = NULL; 00568 00569 if (is_connected()) { 00570 return NSAPI_ERROR_IS_CONNECTED ; 00571 } else if (_connect_status == NSAPI_STATUS_CONNECTING ) { 00572 return NSAPI_ERROR_ALREADY ; 00573 } 00574 00575 _connect_status = NSAPI_STATUS_CONNECTING ; 00576 if (_connection_status_cb) { 00577 _connection_status_cb(NSAPI_EVENT_CONNECTION_STATUS_CHANGE , NSAPI_STATUS_CONNECTING ); 00578 } 00579 00580 do { 00581 retry_init: 00582 00583 00584 retcode = NSAPI_ERROR_OK ; 00585 00586 /* setup AT parser */ 00587 setup_at_parser(); 00588 00589 if (!initialized) { 00590 00591 /* If we have hangup (eg DCD) detection, we don't want it active 00592 * as long as we are using ATCmdParser. 00593 * As soon as we get into data mode, we will turn it back on. */ 00594 enable_hup(false); 00595 00596 if (!power_up()) { 00597 retcode = NSAPI_ERROR_DEVICE_ERROR ; 00598 break; 00599 } 00600 00601 retcode = initialize_sim_card(); 00602 if (retcode != NSAPI_ERROR_OK ) { 00603 break; 00604 } 00605 00606 success = nwk_registration(PACKET_SWITCHED) //perform network registration 00607 && get_CCID(_at)//get integrated circuit ID of the SIM 00608 && get_IMSI(_at)//get international mobile subscriber information 00609 && get_IMEI(_at)//get international mobile equipment identifier 00610 && get_MEID(_at)//its same as IMEI 00611 && set_CMGF(_at)//set message format for SMS 00612 && set_CNMI(_at);//set new SMS indication 00613 00614 if (!success) { 00615 retcode = NSAPI_ERROR_NO_CONNECTION ; 00616 break; 00617 } 00618 00619 #if MBED_CONF_PPP_CELL_IFACE_APN_LOOKUP 00620 if (!apn_config) { 00621 apn_config = apnconfig(dev_info.imsi); 00622 } 00623 #endif 00624 00625 /* Check if user want skip SIM pin checking on boot up */ 00626 if (set_sim_pin_check_request) { 00627 retcode = do_sim_pin_check(_at, _pin); 00628 if (retcode != NSAPI_ERROR_OK ) { 00629 break; 00630 } 00631 /* set this request to false, as it is unnecessary to repeat in case of retry */ 00632 set_sim_pin_check_request = false; 00633 } 00634 00635 /* check if the user requested a sim pin change */ 00636 if (change_pin) { 00637 retcode = do_change_sim_pin(_at, _pin, _new_pin); 00638 if (retcode != NSAPI_ERROR_OK ) { 00639 break; 00640 } 00641 /* set this request to false, as it is unnecessary to repeat in case of retry */ 00642 change_pin = false; 00643 } 00644 00645 #if MBED_CONF_PPP_CELL_IFACE_APN_LOOKUP 00646 if (apn_config) { 00647 _apn = _APN_GET(apn_config); 00648 _uname = _APN_GET(apn_config); 00649 _pwd = _APN_GET(apn_config); 00650 tr_info("Looked up APN %s.", _apn); 00651 } 00652 #endif 00653 00654 //sets up APN and IP protocol for external PDP context 00655 retcode = setup_context_and_credentials(); 00656 if (retcode != NSAPI_ERROR_OK ) { 00657 break; 00658 } 00659 00660 if (!success) { 00661 shutdown_at_parser(); 00662 retcode = NSAPI_ERROR_NO_CONNECTION ; 00663 break; 00664 } 00665 00666 initialized = true; 00667 did_init = true; 00668 } else { 00669 /* If we were already initialized, we expect to receive NO_CARRIER response 00670 * from the modem as we were kicked out of Data mode */ 00671 _at->recv("NO CARRIER"); 00672 success = _at->send("AT") && _at->recv("OK"); 00673 } 00674 00675 /* Attempt to enter data mode */ 00676 success = set_atd(_at); //enter into Data mode with the modem 00677 if (!success) { 00678 power_down(); 00679 initialized = false; 00680 00681 /* if we were previously initialized , i.e., not in this particular attempt, 00682 * we want to re-initialize */ 00683 if (!did_init) { 00684 goto retry_init; 00685 } 00686 00687 /* shutdown AT parser before notifying application of the failure */ 00688 shutdown_at_parser(); 00689 00690 retcode = NSAPI_ERROR_NO_CONNECTION ; 00691 break; 00692 } 00693 00694 /* This is the success case. 00695 * Save RAM, discard AT Parser as we have entered Data mode. */ 00696 shutdown_at_parser(); 00697 00698 /* We now want hangup (e.g., DCD) detection if available */ 00699 enable_hup(true); 00700 00701 /* Initialize PPP 00702 * mbed_ppp_init() is a blocking call, it will block until 00703 * connected, or timeout after 30 seconds*/ 00704 retcode = nsapi_ppp_connect(_fh, callback(this, &PPPCellularInterface::ppp_status_cb), _uname, _pwd, _stack); 00705 } while ((_connect_status == NSAPI_STATUS_CONNECTING && _connect_is_blocking) && 00706 apn_config && *apn_config); 00707 00708 00709 if (retcode != NSAPI_ERROR_OK ) { 00710 _connect_status = NSAPI_STATUS_DISCONNECTED ; 00711 if (_connection_status_cb) { 00712 _connection_status_cb(NSAPI_EVENT_CONNECTION_STATUS_CHANGE , NSAPI_STATUS_DISCONNECTED ); 00713 } 00714 } 00715 00716 00717 return retcode; 00718 } 00719 00720 /** 00721 * User initiated disconnect 00722 * 00723 * Disconnects from PPP connection only and brings down the underlying network 00724 * interface 00725 */ 00726 nsapi_error_t PPPCellularInterface::disconnect() 00727 { 00728 return nsapi_ppp_disconnect(_fh); 00729 } 00730 00731 const char *PPPCellularInterface::get_ip_address() 00732 { 00733 return nsapi_ppp_get_ip_addr(_fh); 00734 } 00735 00736 const char *PPPCellularInterface::get_netmask() 00737 { 00738 return nsapi_ppp_get_netmask(_fh); 00739 } 00740 00741 const char *PPPCellularInterface::get_gateway() 00742 { 00743 return nsapi_ppp_get_ip_addr(_fh); 00744 } 00745 00746 /** Power down modem 00747 * Uses AT command to do it */ 00748 void PPPCellularInterface::power_down() 00749 { 00750 modem_power_down(); 00751 modem_deinit(); 00752 } 00753 00754 /** 00755 * Powers up the modem 00756 * 00757 * Enables the GPIO lines to the modem and then wriggles the power line in short pulses. 00758 */ 00759 bool PPPCellularInterface::power_up() 00760 { 00761 /* Initialize GPIO lines */ 00762 modem_init(); 00763 /* Give modem a little time to settle down */ 00764 wait(0.25); 00765 00766 bool success = false; 00767 00768 int retry_count = 0; 00769 while (true) { 00770 modem_power_up(); 00771 /* Modem tends to spit out noise during power up - don't confuse the parser */ 00772 _at->flush(); 00773 /* It is mandatory to avoid sending data to the serial port during the first 200 ms 00774 * of the module startup. Telit_xE910 Global form factor App note. 00775 * Not necessary for all types of modems however. Let's wait just to be on the safe side */ 00776 wait_ms(200); 00777 _at->set_timeout(1000); 00778 if (_at->send("AT") && _at->recv("OK")) { 00779 tr_info("Modem Ready."); 00780 break; 00781 } 00782 00783 if (++retry_count > 10) { 00784 goto failure; 00785 } 00786 } 00787 00788 _at->set_timeout(8000); 00789 00790 /*For more details regarding DCD and DTR circuitry, please refer to Modem AT manual */ 00791 success = _at->send("AT" 00792 "E0;" //turn off modem echoing 00793 "+CMEE=2;"//turn on verbose responses 00794 "&K0"//turn off RTC/CTS handshaking 00795 "+IPR=115200;"//setup baud rate 00796 "&C1;"//set DCD circuit(109), changes in accordance with the carrier detect status 00797 "&D0")//set DTR circuit, we ignore the state change of DTR 00798 && _at->recv("OK"); 00799 00800 if (!success) { 00801 goto failure; 00802 } 00803 00804 /* If everything alright, return from here with success*/ 00805 return success; 00806 00807 failure: 00808 tr_error("Preliminary modem setup failed."); 00809 return false; 00810 } 00811 00812 /** 00813 * Get a pointer to the underlying network stack 00814 */ 00815 NetworkStack *PPPCellularInterface::get_stack() 00816 { 00817 return nsapi_ppp_get_stack(); 00818 } 00819 00820 00821 void PPPCellularInterface::attach( 00822 Callback<void(nsapi_event_t, intptr_t)> status_cb) 00823 { 00824 _connection_status_cb = status_cb; 00825 } 00826 00827 nsapi_connection_status_t PPPCellularInterface::get_connection_status() const 00828 { 00829 return _connect_status; 00830 } 00831 00832 nsapi_error_t PPPCellularInterface::set_blocking(bool blocking) 00833 { 00834 return nsapi_ppp_set_blocking(blocking); 00835 } 00836 00837 00838 00839 #endif // NSAPI_PPP_AVAILABLE
Generated on Tue Jul 12 2022 13:25:03 by
1.7.2