Gleb Klochkov / Mbed OS Climatcontroll_Main

Dependencies:   esp8266-driver

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