Rtos API example

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers PPPCellularInterface.cpp Source File

PPPCellularInterface.cpp

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