Nathan Yonkee / Mbed 2 deprecated Nucleo_sinewave_output_copy

Dependencies:   mbed

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     _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", &reg_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