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
Diff: UbloxPPPCellularInterface.cpp
- Revision:
- 0:44dd95724bc2
- Child:
- 2:4c533665168c
diff -r 000000000000 -r 44dd95724bc2 UbloxPPPCellularInterface.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/UbloxPPPCellularInterface.cpp Wed Jun 14 09:27:55 2017 +0000 @@ -0,0 +1,345 @@ +/* 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 +