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
UbloxPPPCellularInterface.cpp
- Committer:
- RobMeades
- Date:
- 2017-06-14
- Revision:
- 0:44dd95724bc2
- Child:
- 2:4c533665168c
File content as of revision 0:44dd95724bc2:
/* Copyright (c) 2017 ublox Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "cellular/onboard_modem_api.h" #include "nsapi_ppp.h" #include "utils/APN_db.h" #include "UbloxPPPCellularInterface.h" #ifdef FEATURE_COMMON_PAL #include "mbed_trace.h" #define TRACE_GROUP "UPCI" #else #define tr_debug(format, ...) debug_if(_debug_trace_on, format "\n", ## __VA_ARGS__) #define tr_info(format, ...) debug_if(_debug_trace_on, format "\n", ## __VA_ARGS__) #define tr_warn(format, ...) debug_if(_debug_trace_on, format "\n", ## __VA_ARGS__) #define tr_error(format, ...) debug_if(_debug_trace_on, format "\n", ## __VA_ARGS__) #endif #if NSAPI_PPP_AVAILABLE /********************************************************************** * PRIVATE METHODS **********************************************************************/ // Send the credentials to the modem. nsapi_error_t UbloxPPPCellularInterface::setup_context_and_credentials() { nsapi_error_t nsapi_error = NSAPI_ERROR_PARAMETER; const char *auth = _uname && _pwd ? "CHAP:" : ""; LOCK(); if (_apn) { // TODO: IPV6 if (_at->send("AT+CGDCONT=1,\"%s\",\"%s%s\"", "IP", auth, _apn) && _at->recv("OK")) { nsapi_error = NSAPI_ERROR_OK; // C030 needs a short delay before the connection is triggered wait_ms(100); } } UNLOCK(); return nsapi_error; } // Enter data mode. bool UbloxPPPCellularInterface::set_atd() { bool success; LOCK(); success = _at->send("ATD*99***1#") && _at->recv("CONNECT"); UNLOCK(); return success; } /********************************************************************** * PROTECTED METHODS **********************************************************************/ // Gain access to the underlying network stack. NetworkStack *UbloxPPPCellularInterface::get_stack() { return nsapi_ppp_get_stack(); } // Get the next set of credentials, based on IMSI. void UbloxPPPCellularInterface::get_next_credentials(const char * config) { if (config) { _apn = _APN_GET(config); _uname = _APN_GET(config); _pwd = _APN_GET(config); } _apn = _apn ? _apn : ""; _uname = _uname ? _uname : ""; _pwd = _pwd ? _pwd : ""; } /********************************************************************** * PUBLIC METHODS **********************************************************************/ // Constructor. UbloxPPPCellularInterface::UbloxPPPCellularInterface(PinName tx, PinName rx, int baud, bool debug_on) { _apn = NULL; _uname = NULL; _pwd = NULL; _sim_pin_check_change_pending = false; _sim_pin_check_change_pending_enabled_value = false; _sim_pin_change_pending = false; _sim_pin_change_pending_new_pin_value = NULL; _ppp_connection_up = false; _connection_status_cb = NULL; // Initialise the base class, which starts the AT parser` baseClassInit(tx, rx, baud, debug_on); } // Destructor. UbloxPPPCellularInterface::~UbloxPPPCellularInterface() { if (_ppp_connection_up) { disconnect(); } } // Set APN, user name and password. void UbloxPPPCellularInterface::set_credentials(const char *apn, const char *uname, const char *pwd) { _apn = apn; _uname = uname; _pwd = pwd; } // Set PIN. void UbloxPPPCellularInterface::set_sim_pin(const char *pin) { set_pin(pin); } // Make a cellular connection. nsapi_error_t UbloxPPPCellularInterface::connect(const char *sim_pin, const char *apn, const char *uname, const char *pwd) { nsapi_error_t nsapi_error; if (sim_pin != NULL) { set_pin(sim_pin); } if (apn != NULL) { _apn = apn; } if ((uname != NULL) && (pwd != NULL)) { _uname = uname; _pwd = pwd; } else { _uname = NULL; _pwd = NULL; } nsapi_error = connect(); return nsapi_error; } // Make a cellular connection nsapi_error_t UbloxPPPCellularInterface::connect() { nsapi_error_t nsapi_error = NSAPI_ERROR_IS_CONNECTED; const char * config = NULL; if (!_ppp_connection_up) { // Set up modem and then register with the network if (init()) { // Perform any pending SIM actions if (_sim_pin_check_change_pending) { if (!sim_pin_check_enable(_sim_pin_check_change_pending_enabled_value)) { nsapi_error = NSAPI_ERROR_AUTH_FAILURE; } _sim_pin_check_change_pending = false; } if (_sim_pin_change_pending) { if (!change_sim_pin(_sim_pin_change_pending_new_pin_value)) { nsapi_error = NSAPI_ERROR_AUTH_FAILURE; } _sim_pin_change_pending = false; } if (nsapi_error != NSAPI_ERROR_AUTH_FAILURE) { nsapi_error = NSAPI_ERROR_NO_CONNECTION; for (int retries = 0; (nsapi_error == NSAPI_ERROR_NO_CONNECTION) && (retries < 3); retries++) { if (nwk_registration()) { nsapi_error = NSAPI_ERROR_OK; } } } } else { nsapi_error = NSAPI_ERROR_DEVICE_ERROR; } if (nsapi_error == NSAPI_ERROR_OK) { // If the caller hasn't entered an APN, try to find it if (_apn == NULL) { config = apnconfig(_dev_info.imsi); } // Attempt to connect do { // Set up APN and IP protocol for external PDP context get_next_credentials(config); nsapi_error = setup_context_and_credentials(); // Attempt to enter data mode if ((nsapi_error == NSAPI_ERROR_OK) && set_atd()) { // Initialise PPP // nsapi_ppp_connect() is a blocking call, it will block until // connected, or timeout after 30 seconds nsapi_error = nsapi_ppp_connect(_fh, _connection_status_cb, _uname, _pwd); _ppp_connection_up = (nsapi_error == NSAPI_ERROR_OK); } } while (!_ppp_connection_up && config && *config); } if (!_ppp_connection_up) { tr_error("Failed to connect, check your APN/username/password"); } } return nsapi_error; } // User initiated disconnect. nsapi_error_t UbloxPPPCellularInterface::disconnect() { nsapi_error_t nsapi_error = NSAPI_ERROR_DEVICE_ERROR; if (nsapi_ppp_disconnect(_fh) == NSAPI_ERROR_OK) { _ppp_connection_up = false; // Get the "NO CARRIER" response out of the modem // so as not to confuse subsequent AT commands _at->send("AT") && _at->recv("NO CARRIER"); if (nwk_deregistration()) { nsapi_error = NSAPI_ERROR_OK; } } return nsapi_error; } // Enable or disable SIM PIN check lock. nsapi_error_t UbloxPPPCellularInterface::set_sim_pin_check(bool set, bool immediate, const char *sim_pin) { nsapi_error_t nsapi_error = NSAPI_ERROR_AUTH_FAILURE; if (sim_pin != NULL) { _pin = sim_pin; } if (immediate) { if (init()) { if (sim_pin_check_enable(set)) { nsapi_error = NSAPI_ERROR_OK; } } else { nsapi_error = NSAPI_ERROR_DEVICE_ERROR; } } else { nsapi_error = NSAPI_ERROR_OK; _sim_pin_check_change_pending = true; _sim_pin_check_change_pending_enabled_value = set; } return nsapi_error; } // Change the PIN code for the SIM card. nsapi_error_t UbloxPPPCellularInterface::set_new_sim_pin(const char *new_pin, bool immediate, const char *old_pin) { nsapi_error_t nsapi_error = NSAPI_ERROR_AUTH_FAILURE; if (old_pin != NULL) { _pin = old_pin; } if (immediate) { if (init()) { if (change_sim_pin(new_pin)) { nsapi_error = NSAPI_ERROR_OK; } } else { nsapi_error = NSAPI_ERROR_DEVICE_ERROR; } } else { nsapi_error = NSAPI_ERROR_OK; _sim_pin_change_pending = true; _sim_pin_change_pending_new_pin_value = new_pin; } return nsapi_error; } // Determine if PPP is up. bool UbloxPPPCellularInterface::is_connected() { return _ppp_connection_up; } // Get our IP address. const char *UbloxPPPCellularInterface::get_ip_address() { return nsapi_ppp_get_ip_addr(_fh); } // Get the local network mask. const char *UbloxPPPCellularInterface::get_netmask() { return nsapi_ppp_get_netmask(_fh); } // Get the local gateways. const char *UbloxPPPCellularInterface::get_gateway() { return nsapi_ppp_get_ip_addr(_fh); } // Set the callback to be called in case the connection is lost. void UbloxPPPCellularInterface::connection_status_cb(Callback<void(nsapi_error_t)> cb) { _connection_status_cb = cb; } #endif // NSAPI_PPP_AVAILABLE // End of File