init
Embed:
(wiki syntax)
Show/hide line numbers
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