Library that implements the CellularInterface using PPP and LWIP on the mbed MCU. May be used on the C027 and C030 (non-N2xx flavour) boards from mbed 5.5 onwards.

Dependents:   example-ublox-cellular-interface HelloMQTT example-ublox-cellular-interface_r410M example-ublox-mbed-client

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers UbloxPPPCellularInterface.cpp Source File

UbloxPPPCellularInterface.cpp

00001 /* Copyright (c) 2017 ublox 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 
00016 #include "cellular/onboard_modem_api.h"
00017 #include "nsapi_ppp.h"
00018 #include "utils/APN_db.h"
00019 #include "UbloxPPPCellularInterface.h"
00020 #ifdef FEATURE_COMMON_PAL
00021 #include "mbed_trace.h"
00022 #define TRACE_GROUP "UPCI"
00023 #else
00024 #define tr_debug(format, ...) debug_if(_debug_trace_on, format "\n", ## __VA_ARGS__)
00025 #define tr_info(format, ...)  debug_if(_debug_trace_on, format "\n", ## __VA_ARGS__)
00026 #define tr_warn(format, ...)  debug_if(_debug_trace_on, format "\n", ## __VA_ARGS__)
00027 #define tr_error(format, ...) debug_if(_debug_trace_on, format "\n", ## __VA_ARGS__)
00028 #endif
00029 
00030 #if NSAPI_PPP_AVAILABLE
00031 
00032 /**********************************************************************
00033  * PRIVATE METHODS
00034  **********************************************************************/
00035 
00036 // Send the credentials to the modem.
00037 nsapi_error_t UbloxPPPCellularInterface::setup_context_and_credentials()
00038 {
00039     nsapi_error_t nsapi_error = NSAPI_ERROR_PARAMETER;
00040     const char *auth = _uname && _pwd ? "CHAP:" : "";
00041     LOCK();
00042 
00043     if (_apn) {
00044         // TODO: IPV6
00045         if (_at->send("AT+CGDCONT=1,\"%s\",\"%s%s\"", "IP", auth, _apn) &&
00046             _at->recv("OK")) {
00047             nsapi_error = NSAPI_ERROR_OK;
00048             // C030 needs a short delay before the connection is triggered
00049             wait_ms(100);
00050         }
00051     }
00052 
00053     UNLOCK();
00054     return nsapi_error;
00055 
00056 }
00057 
00058 // Enter data mode.
00059 bool UbloxPPPCellularInterface::set_atd()
00060 {
00061     bool success;
00062     LOCK();
00063 
00064     success = _at->send("ATD*99***1#") && _at->recv("CONNECT");
00065 
00066     UNLOCK();
00067     return success;
00068 }
00069 
00070 /**********************************************************************
00071  * PROTECTED METHODS
00072  **********************************************************************/
00073 
00074 // Gain access to the underlying network stack.
00075 NetworkStack *UbloxPPPCellularInterface::get_stack()
00076 {
00077     return nsapi_ppp_get_stack();
00078 }
00079 
00080 // Get the next set of credentials, based on IMSI.
00081 void UbloxPPPCellularInterface::get_next_credentials(const char ** config)
00082 {
00083     if (*config) {
00084         _apn    = _APN_GET(*config);
00085         _uname  = _APN_GET(*config);
00086         _pwd    = _APN_GET(*config);
00087     }
00088 
00089     _apn    = _apn     ?  _apn    : "";
00090     _uname  = _uname   ?  _uname  : "";
00091     _pwd    = _pwd     ?  _pwd    : "";
00092 }
00093 
00094 /**********************************************************************
00095  * PUBLIC METHODS
00096  **********************************************************************/
00097 
00098 // Constructor.
00099 UbloxPPPCellularInterface::UbloxPPPCellularInterface(PinName tx,
00100                                                      PinName rx,
00101                                                      int baud,
00102                                                      bool debug_on)
00103 {
00104     _apn = NULL;
00105     _uname = NULL;
00106     _pwd = NULL;
00107     _sim_pin_check_change_pending = false;
00108     _sim_pin_check_change_pending_enabled_value = false;
00109     _sim_pin_change_pending = false;
00110     _sim_pin_change_pending_new_pin_value = NULL;
00111     _ppp_connection_up = false;
00112     _connection_status_cb = NULL;
00113 
00114     // Initialise the base class, which starts the AT parser`
00115     baseClassInit(tx, rx, baud, debug_on);
00116 }
00117 
00118 // Destructor.
00119 UbloxPPPCellularInterface::~UbloxPPPCellularInterface()
00120 {
00121     if (_ppp_connection_up) {
00122         disconnect();
00123     }
00124 }
00125 
00126 // Set APN, user name and password.
00127 void  UbloxPPPCellularInterface::set_credentials(const char *apn,
00128                                                  const char *uname,
00129                                                  const char *pwd)
00130 {
00131     _apn = apn;
00132     _uname = uname;
00133     _pwd = pwd;
00134 }
00135 
00136 // Set PIN.
00137 void UbloxPPPCellularInterface::set_sim_pin(const char *pin) {
00138     set_pin(pin);
00139 }
00140 
00141 // Make a cellular connection.
00142 nsapi_error_t UbloxPPPCellularInterface::connect(const char *sim_pin,
00143                                                  const char *apn,
00144                                                  const char *uname,
00145                                                  const char *pwd)
00146 {
00147     nsapi_error_t nsapi_error;
00148 
00149     if (sim_pin != NULL) {
00150         set_pin(sim_pin);
00151     }
00152 
00153     if (apn != NULL) {
00154         _apn = apn;
00155     }
00156 
00157     if ((uname != NULL) && (pwd != NULL)) {
00158         _uname = uname;
00159         _pwd = pwd;
00160     } else {
00161         _uname = NULL;
00162         _pwd = NULL;
00163     }
00164 
00165     nsapi_error = connect();
00166 
00167     return nsapi_error;
00168 }
00169 
00170 // Make a cellular connection
00171 nsapi_error_t UbloxPPPCellularInterface::connect()
00172 {
00173     nsapi_error_t nsapi_error = NSAPI_ERROR_IS_CONNECTED;
00174     const char * config = NULL;
00175 
00176     if (!_ppp_connection_up) {
00177 
00178         // Set up modem and then register with the network
00179         if (init()) {
00180             // Perform any pending SIM actions
00181             if (_sim_pin_check_change_pending) {
00182                 if (!sim_pin_check_enable(_sim_pin_check_change_pending_enabled_value)) {
00183                     nsapi_error = NSAPI_ERROR_AUTH_FAILURE;
00184                 }
00185                 _sim_pin_check_change_pending = false;
00186             }
00187             if (_sim_pin_change_pending) {
00188                 if (!change_sim_pin(_sim_pin_change_pending_new_pin_value)) {
00189                     nsapi_error = NSAPI_ERROR_AUTH_FAILURE;
00190                 }
00191                 _sim_pin_change_pending = false;
00192             }
00193 
00194             if (nsapi_error != NSAPI_ERROR_AUTH_FAILURE) {
00195                 nsapi_error = NSAPI_ERROR_NO_CONNECTION;
00196                 for (int retries = 0; (nsapi_error == NSAPI_ERROR_NO_CONNECTION) && (retries < 3); retries++) {
00197                     if (nwk_registration()) {
00198                         nsapi_error = NSAPI_ERROR_OK;
00199                     }
00200                 }
00201             }
00202         } else {
00203             nsapi_error = NSAPI_ERROR_DEVICE_ERROR;
00204         }
00205 
00206         if (nsapi_error == NSAPI_ERROR_OK) {
00207             // If the caller hasn't entered an APN, try to find it
00208             if (_apn == NULL) {
00209                 config = apnconfig(_dev_info.imsi);
00210             }
00211 
00212             // Attempt to connect
00213             do {
00214                 // Set up APN and IP protocol for external PDP context
00215                 get_next_credentials(&config);
00216                 nsapi_error = setup_context_and_credentials();
00217 
00218                 // Attempt to enter data mode
00219                 if ((nsapi_error == NSAPI_ERROR_OK) && set_atd()) {
00220                     wait_ms(1000);
00221                     // Initialise PPP
00222                     // nsapi_ppp_connect() is a blocking call, it will block until
00223                     // connected, or timeout after 30 seconds
00224                     nsapi_error = nsapi_ppp_connect(_fh, _connection_status_cb, _uname, _pwd);
00225                     _ppp_connection_up = (nsapi_error == NSAPI_ERROR_OK);
00226                     if (!_ppp_connection_up) {
00227                         // If the connection has failed we may or may not still be
00228                         // in data mode, depending on the nature of the failure,
00229                         // so it's safest to force us back to command mode here
00230                         // (if we're already in command mode the recv() call will
00231                         // just time out)
00232                         _at->send("~+++");
00233                         _at->recv("NO CARRIER");
00234                     }
00235                 }
00236             } while (!_ppp_connection_up && config && *config);
00237         }
00238 
00239         if (!_ppp_connection_up) {
00240             tr_error("Failed to connect, check your APN/username/password");
00241         }
00242     }
00243 
00244     return nsapi_error;
00245 }
00246 
00247 // User initiated disconnect.
00248 nsapi_error_t UbloxPPPCellularInterface::disconnect()
00249 {
00250     nsapi_error_t nsapi_error = NSAPI_ERROR_DEVICE_ERROR;
00251 
00252     if (nsapi_ppp_disconnect(_fh) == NSAPI_ERROR_OK) {
00253         _ppp_connection_up = false;
00254         // Get the "NO CARRIER" response out of the modem
00255         // so as not to confuse subsequent AT commands
00256         _at->send("AT") && _at->recv("NO CARRIER");
00257 
00258         if (nwk_deregistration()) {
00259             nsapi_error = NSAPI_ERROR_OK;
00260         }
00261     }
00262 
00263     return nsapi_error;
00264 }
00265 
00266 // Enable or disable SIM PIN check lock.
00267 nsapi_error_t UbloxPPPCellularInterface::set_sim_pin_check(bool set,
00268                                                            bool immediate,
00269                                                            const char *sim_pin)
00270 {
00271     nsapi_error_t nsapi_error = NSAPI_ERROR_AUTH_FAILURE;
00272 
00273     if (sim_pin != NULL) {
00274         _pin = sim_pin;
00275     }
00276 
00277     if (immediate) {
00278         if (init()) {
00279             if (sim_pin_check_enable(set)) {
00280                 nsapi_error = NSAPI_ERROR_OK;
00281             }
00282         } else {
00283             nsapi_error = NSAPI_ERROR_DEVICE_ERROR;
00284         }
00285     } else {
00286         nsapi_error = NSAPI_ERROR_OK;
00287         _sim_pin_check_change_pending = true;
00288         _sim_pin_check_change_pending_enabled_value = set;
00289     }
00290 
00291     return nsapi_error;
00292 }
00293 
00294 // Change the PIN code for the SIM card.
00295 nsapi_error_t UbloxPPPCellularInterface::set_new_sim_pin(const char *new_pin,
00296                                                          bool immediate,
00297                                                          const char *old_pin)
00298 {
00299     nsapi_error_t nsapi_error = NSAPI_ERROR_AUTH_FAILURE;
00300 
00301     if (old_pin != NULL) {
00302         _pin = old_pin;
00303     }
00304 
00305     if (immediate) {
00306         if (init()) {
00307             if (change_sim_pin(new_pin)) {
00308                 nsapi_error = NSAPI_ERROR_OK;
00309             }
00310         } else {
00311             nsapi_error = NSAPI_ERROR_DEVICE_ERROR;
00312         }
00313     } else {
00314         nsapi_error = NSAPI_ERROR_OK;
00315         _sim_pin_change_pending = true;
00316         _sim_pin_change_pending_new_pin_value = new_pin;
00317     }
00318 
00319     return nsapi_error;
00320 }
00321 
00322 // Determine if PPP is up.
00323 bool UbloxPPPCellularInterface::is_connected()
00324 {
00325     return _ppp_connection_up;
00326 }
00327 
00328 // Get our IP address.
00329 const char *UbloxPPPCellularInterface::get_ip_address()
00330 {
00331     return nsapi_ppp_get_ip_addr(_fh);
00332 }
00333 
00334 // Get the local network mask.
00335 const char *UbloxPPPCellularInterface::get_netmask()
00336 {
00337     return nsapi_ppp_get_netmask(_fh);
00338 }
00339 
00340 // Get the local gateways.
00341 const char *UbloxPPPCellularInterface::get_gateway()
00342 {
00343     return nsapi_ppp_get_ip_addr(_fh);
00344 }
00345 
00346 // Set the callback to be called in case the connection is lost.
00347 void UbloxPPPCellularInterface::connection_status_cb(Callback<void(nsapi_event_t, intptr_t)> cb)
00348 {
00349     _connection_status_cb = cb;
00350 }
00351 
00352 #endif // NSAPI_PPP_AVAILABLE
00353 
00354 // End of File
00355