Cellular: major refactoring while introducing new CellularContext class.

pull/8579/head
Teppo Järvelin 2018-09-14 13:32:10 +03:00
parent 8880538eba
commit ad2abbe887
65 changed files with 2761 additions and 2083 deletions

View File

@ -146,7 +146,7 @@ nsapi_error_t CellularConnectionFSM::init()
_state = STATE_INIT;
_next_state = STATE_INIT;
return _network->init();
return NSAPI_ERROR_OK;
}
bool CellularConnectionFSM::power_on()
@ -447,7 +447,7 @@ void CellularConnectionFSM::state_device_ready()
}
} else {
if (_retry_count == 0) {
(void)_power->set_device_ready_urc_cb(mbed::callback(this, &CellularConnectionFSM::ready_urc_cb));
_power->set_device_ready_urc_cb(mbed::callback(this, &CellularConnectionFSM::ready_urc_cb));
}
retry_state_or_fail();
}
@ -528,26 +528,26 @@ void CellularConnectionFSM::state_activating_pdp_context()
{
_cellularDevice->set_timeout(TIMEOUT_CONNECT);
tr_info("Activate PDP Context (timeout %d ms)", TIMEOUT_CONNECT);
if (_network->activate_context() == NSAPI_ERROR_OK) {
/* if (_network->activate_context() == NSAPI_ERROR_OK) {
// when using modems stack connect is synchronous
_next_state = STATE_CONNECTING_NETWORK;
} else {
retry_state_or_fail();
}
}*/
}
void CellularConnectionFSM::state_connect_to_network()
{
_cellularDevice->set_timeout(TIMEOUT_CONNECT);
tr_info("Connect to cellular network (timeout %d ms)", TIMEOUT_CONNECT);
if (_network->connect() == NSAPI_ERROR_OK) {
/*if (_network->connect() == NSAPI_ERROR_OK) {
_cellularDevice->set_timeout(TIMEOUT_NETWORK);
tr_debug("Connected to cellular network, set at timeout (timeout %d ms)", TIMEOUT_NETWORK);
// when using modems stack connect is synchronous
_next_state = STATE_CONNECTED;
} else {
retry_state_or_fail();
}
}*/
}
void CellularConnectionFSM::state_connected()
@ -719,11 +719,6 @@ CellularSIM *CellularConnectionFSM::get_sim()
return _sim;
}
NetworkStack *CellularConnectionFSM::get_stack()
{
return _cellularDevice->get_stack();
}
void CellularConnectionFSM::set_retry_timeout_array(uint16_t timeout[], int array_len)
{
_retry_array_length = array_len > MAX_RETRY_ARRAY_SIZE ? MAX_RETRY_ARRAY_SIZE : array_len;

View File

@ -178,10 +178,6 @@ private:
nsapi_error_t continue_from_state(CellularState state);
bool is_registered_to_plmn();
private:
friend class EasyCellularConnection;
NetworkStack *get_stack();
private:
void report_failure(const char *msg);
void event();

View File

@ -23,6 +23,7 @@
#endif
#include "EasyCellularConnection.h"
#include "CellularContext.h"
#include "CellularSIM.h"
#include "CellularLog.h"
#include "mbed_wait_api.h"
@ -41,10 +42,10 @@ void EasyCellularConnection::network_callback(nsapi_event_t ev, intptr_t ptr)
}
}
EasyCellularConnection::EasyCellularConnection(CellularDevice *device) : _is_initialized(false),
_serial(MDMTXD, MDMRXD, MBED_CONF_PLATFORM_DEFAULT_SERIAL_BAUD_RATE), _device(device),
EasyCellularConnection::EasyCellularConnection(CellularContext *ctx) : _is_initialized(false), _context(ctx),
_credentials_err(NSAPI_ERROR_OK), _status_cb(0)
{
_device = CellularDevice::get_default_instance();
#if USE_APN_LOOKUP
_credentials_set = false;
#endif // #if USE_APN_LOOKUP
@ -52,29 +53,17 @@ EasyCellularConnection::EasyCellularConnection(CellularDevice *device) : _is_ini
EasyCellularConnection::~EasyCellularConnection()
{
}
nsapi_error_t EasyCellularConnection::init()
{
nsapi_error_t err = NSAPI_ERROR_OK;
_stm_error = false;
if (!_is_initialized) {
#if defined (MDMRTS) && defined (MDMCTS)
_serial.set_flow_control(SerialBase::RTSCTS, MDMRTS, MDMCTS);
#endif
err = _device->init_stm(&_serial);
if (err != NSAPI_ERROR_OK) {
return NSAPI_ERROR_NO_MEMORY;
}
_context->attach(callback(this, &EasyCellularConnection::network_callback));
err = _device->start_dispatch();
if (err != NSAPI_ERROR_OK) {
return NSAPI_ERROR_NO_MEMORY;
}
_network = _device->open_network(&_serial);
_device->attach(callback(this, &EasyCellularConnection::network_callback));
_is_initialized = true;
}
@ -85,15 +74,13 @@ void EasyCellularConnection::set_credentials(const char *apn, const char *uname,
{
if (apn && strlen(apn) > 0) {
_credentials_err = init();
if (_credentials_err) {
return;
}
_credentials_err = _device->set_credentials(apn, uname, pwd);
_context->set_apn_credentials(apn, uname, pwd);
#if USE_APN_LOOKUP
if (_credentials_err == NSAPI_ERROR_OK) {
_credentials_set = true;
}
_credentials_set = true;
#endif // #if USE_APN_LOOKUP
}
}
@ -101,17 +88,13 @@ void EasyCellularConnection::set_credentials(const char *apn, const char *uname,
void EasyCellularConnection::set_sim_pin(const char *sim_pin)
{
if (sim_pin && strlen(sim_pin) > 0) {
_credentials_err = init();
if (_credentials_err) {
return;
}
_device->set_sim_pin(sim_pin);
}
}
nsapi_error_t EasyCellularConnection::connect(const char *sim_pin, const char *apn, const char *uname, const char *pwd)
{
if (_device->is_connected()) {
if (_context->is_connected()) {
return NSAPI_ERROR_IS_CONNECTED;
}
@ -129,7 +112,7 @@ nsapi_error_t EasyCellularConnection::connect(const char *sim_pin, const char *a
nsapi_error_t EasyCellularConnection::check_connect()
{
if (_device->is_connected()) {
if (_context->is_connected()) {
return NSAPI_ERROR_IS_CONNECTED;
}
@ -155,11 +138,11 @@ nsapi_error_t EasyCellularConnection::connect()
#if USE_APN_LOOKUP
if (!_credentials_set) {
err = _device->set_sim_ready();
err = _context->set_sim_ready();
if (err == NSAPI_ERROR_OK) {
char imsi[MAX_IMSI_LENGTH + 1];
wait(1); // need to wait to access SIM in some modems
CellularSIM* sim = _device->open_sim(&_serial);
CellularSIM* sim = _device->open_sim(&_device->get_filehandle());
err = sim->get_imsi(imsi);
if (err == NSAPI_ERROR_OK) {
const char *apn_config = apnconfig(imsi);
@ -168,19 +151,19 @@ nsapi_error_t EasyCellularConnection::connect()
const char *uname = _APN_GET(apn_config);
const char *pwd = _APN_GET(apn_config);
tr_info("Looked up APN %s", apn);
err = _device->set_credentials(apn, uname, pwd);
_context->set_apn_credentials(apn, uname, pwd);
}
}
_device->close_sim();
}
if (err) {
} else {
tr_error("APN lookup failed");
return err;
}
}
#endif // USE_APN_LOOKUP
err = _device->connect();
err = _context->connect();
if (err != NSAPI_ERROR_OK) {
tr_info("No cellular connection");
err = NSAPI_ERROR_NO_CONNECTION;
@ -192,41 +175,31 @@ nsapi_error_t EasyCellularConnection::disconnect()
{
_credentials_err = NSAPI_ERROR_OK;
_is_initialized = false;
_stm_error = false;
#if USE_APN_LOOKUP
_credentials_set = false;
#endif // #if USE_APN_LOOKUP
return _device->disconnect();
return _context->disconnect();
}
bool EasyCellularConnection::is_connected()
{
return _device->is_connected();
return _context->is_connected();
}
const char *EasyCellularConnection::get_ip_address()
{
if (!_network) {
return NULL;
}
return _network->get_ip_address();
return _context->get_ip_address();
}
const char *EasyCellularConnection::get_netmask()
{
if (!_network) {
return NULL;
}
return _network->get_netmask();
return NULL;
}
const char *EasyCellularConnection::get_gateway()
{
if (!_network) {
return NULL;
}
return _network->get_gateway();
return NULL;
}
void EasyCellularConnection::attach(mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb)
@ -242,19 +215,13 @@ void EasyCellularConnection::modem_debug_on(bool on)
void EasyCellularConnection::set_plmn(const char *plmn)
{
if (plmn && strlen(plmn) > 0) {
if (!_device) {
_credentials_err = init();
if (_credentials_err) {
return;
}
}
_device->set_plmn(plmn);
}
}
NetworkStack *EasyCellularConnection::get_stack()
{
return _device->get_stack();
return _context->get_stack();
}
CellularDevice *EasyCellularConnection::get_device() const
@ -264,7 +231,7 @@ CellularDevice *EasyCellularConnection::get_device() const
UARTSerial *EasyCellularConnection::get_serial()
{
return &_serial;
return (UARTSerial*)&_device->get_filehandle();
}
} // namespace

View File

@ -22,7 +22,7 @@
#if defined(CELLULAR_DEVICE) || defined(DOXYGEN_ONLY)
#include "CellularDevice.h"
#include "CellularContext.h"
#include "UARTSerial.h"
#include "CellularBase.h"
@ -30,6 +30,7 @@
namespace mbed {
class CellularDevice;
/** EasyCellularConnection class
*
* Simplified adapter for cellular connection
@ -37,7 +38,7 @@ namespace mbed {
class EasyCellularConnection: public CellularBase {
public:
EasyCellularConnection(CellularDevice *device = CellularDevice::get_default_instance());
EasyCellularConnection(CellularContext *ctx = (CellularContext *)CellularContext::get_default_instance());
virtual ~EasyCellularConnection();
public:
@ -165,14 +166,12 @@ private:
nsapi_error_t check_connect();
bool _is_initialized;
bool _stm_error;
#if USE_APN_LOOKUP
bool _credentials_set;
#endif // #if USE_APN_LOOKUP
UARTSerial _serial;
CellularDevice *_device;
CellularNetwork* _network;
CellularContext* _context;
nsapi_error_t _credentials_err;
Callback<void(nsapi_event_t, intptr_t)> _status_cb;
};

View File

@ -0,0 +1,262 @@
/*
* Copyright (c) 2018, Arm Limited and affiliates.
* SPDX-License-Identifier: Apache-2.0
*
* 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.
*/
#ifndef _CELLULARCONTEXT_H_
#define _CELLULARCONTEXT_H_
#include "NetworkInterface.h"
#include "CellularDevice.h"
namespace mbed {
class CellularContext : public NetworkInterface {
public:
// max simultaneous PDP contexts active
static const int PDP_CONTEXT_COUNT = 4;
static NetworkInterface *get_default_instance();
/* authentication type when activating or modifying the pdp context */
enum AuthenticationType {
NOAUTH = 0,
PAP,
CHAP
};
/* whether the additional exception reports are allowed to be sent when the maximum uplink rate is reached */
enum RateControlExceptionReports {
NotAllowedToBeSent = 0,
AllowedToBeSent
};
/* specifies the time unit to be used for the maximum uplink rate */
enum RateControlUplinkTimeUnit {
Unrestricted = 0,
Minute,
Hour,
Day,
Week
};
/* PDP Context information */
struct pdpcontext_params_t {
char apn[MAX_ACCESSPOINT_NAME_LENGTH + 1];
char local_addr[MAX_IPV6_ADDR_IN_IPV4LIKE_DOTTED_FORMAT + 1];
char local_subnet_mask[MAX_IPV6_ADDR_IN_IPV4LIKE_DOTTED_FORMAT + 1];
char gateway_addr[MAX_IPV6_ADDR_IN_IPV4LIKE_DOTTED_FORMAT + 1];
char dns_primary_addr[MAX_IPV6_ADDR_IN_IPV4LIKE_DOTTED_FORMAT + 1];
char dns_secondary_addr[MAX_IPV6_ADDR_IN_IPV4LIKE_DOTTED_FORMAT + 1];
char p_cscf_prim_addr[MAX_IPV6_ADDR_IN_IPV4LIKE_DOTTED_FORMAT + 1];
char p_cscf_sec_addr[MAX_IPV6_ADDR_IN_IPV4LIKE_DOTTED_FORMAT + 1];
int cid;
int bearer_id;
int im_signalling_flag;
int lipa_indication;
int ipv4_mtu;
int wlan_offload;
int local_addr_ind;
int non_ip_mtu;
int serving_plmn_rate_control_value;
pdpcontext_params_t *next;
pdpcontext_params_t()
{
apn[0] = '\0';
local_addr[0] = '\0';
local_subnet_mask[0] = '\0';
gateway_addr[0] = '\0';
dns_primary_addr[0] = '\0';
dns_secondary_addr[0] = '\0';
p_cscf_prim_addr[0] = '\0';
p_cscf_sec_addr[0] = '\0';
cid = -1;
bearer_id = -1;
im_signalling_flag = -1;
lipa_indication = -1;
ipv4_mtu = -1;
wlan_offload = -1;
local_addr_ind = -1;
non_ip_mtu = -1;
serving_plmn_rate_control_value = -1;
next = NULL;
}
};
typedef CellularList<pdpcontext_params_t> pdpContextList_t;
// pointer for next item when used as a linked list
CellularContext* _next;
protected:
// friend of CellularDevice so that it's the only way to close/delete this class.
friend class CellularDevice;
virtual ~CellularContext() {}
public: // from NetworkInterface
virtual nsapi_error_t set_blocking(bool blocking) = 0;
virtual NetworkStack *get_stack() = 0;
virtual const char *get_ip_address() = 0;
virtual void attach(mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb) = 0;
virtual nsapi_error_t connect() = 0;
virtual nsapi_error_t disconnect() = 0;
virtual bool is_connected() = 0;
public:
/** Start the interface
*
* Power on the device and does the initializations for communication with the modem..
* By default this API is synchronous. API can be set to asynchronous with method set_blocking(...).
* In synchronous and asynchronous mode application can get result in from callback which is set with
* attach(...)
*
* @return NSAPI_ERROR_OK on success
* NSAPI_ERROR_NO_MEMORY on case of memory failure
*/
virtual nsapi_error_t set_device_ready() = 0;
/** Start the interface
*
* Attempts to open the sim.
* By default this API is synchronous. API can be set to asynchronous with method set_blocking(...).
* In synchronous and asynchronous mode application can get result in from callback which is set with
* attach(...)
*
* @return NSAPI_ERROR_OK on success
* NSAPI_ERROR_NO_MEMORY on case of memory failure
*/
virtual nsapi_error_t set_sim_ready() = 0;
/** Start the interface
*
* Attempts to register the device to cellular network.
* By default this API is synchronous. API can be set to asynchronous with method set_blocking(...).
* In synchronous and asynchronous mode application can get result in from callback which is set with
* attach(...)
*
* @return NSAPI_ERROR_OK on success
* NSAPI_ERROR_NO_MEMORY on case of memory failure
*/
virtual nsapi_error_t register_to_network() = 0;
/** Start the interface
*
* Attempts to attach the device to cellular network.
* By default this API is synchronous. API can be set to asynchronous with method set_blocking(...).
* In synchronous and asynchronous mode application can get result in from callback which is set with
* attach(...)
*
* @return NSAPI_ERROR_OK on success
* NSAPI_ERROR_NO_MEMORY on case of memory failure
*/
virtual nsapi_error_t attach_to_network() = 0;
public:
/** Get APN rate control.
*
* @remark optional params are not updated if not received from network, so use good defaults
* @param reports Additional exception reports at maximum rate reached are allowed to be sent [optional]
* @param time_unit Uplink time unit with values 0=unrestricted, 1=minute, 2=hour, 3=day, 4=week [optional]
* @param uplink_rate Maximum number of messages per timeUnit [optional]
* @return NSAPI_ERROR_OK on success
* NSAPI_ERROR_DEVICE_ERROR on case of failure
*/
virtual nsapi_error_t get_rate_control(CellularContext::RateControlExceptionReports &reports,
CellularContext::RateControlUplinkTimeUnit &time_unit, int &uplink_rate) = 0;
/** Get the relevant information for an active non secondary PDP context.
*
* @remark optional params are not updated if not received from network.
* @param params_list reference to linked list, which is filled on successful call
* @return NSAPI_ERROR_OK on success
* NSAPI_ERROR_NO_MEMORY on memory failure
* NSAPI_ERROR_DEVICE_ERROR on other failures
*/
virtual nsapi_error_t get_pdpcontext_params(pdpContextList_t &params_list) = 0;
/** Get backoff timer value
*
* @param backoff_timer Backoff timer value associated with PDP APN in seconds
* @return NSAPI_ERROR_OK on success
* NSAPI_ERROR_PARAMETER if no access point is set or found when activating context
* NSAPI_ERROR_DEVICE_ERROR on failure
*/
virtual nsapi_error_t get_apn_backoff_timer(int &backoff_timer) = 0;
/** Set the cellular network APN and credentials
*
* @param apn Optional name of the network to connect to
* @param uname Optional username for the APN
* @param pwd Optional password for the APN
*/
virtual void set_apn_credentials(const char *uname = 0, const char *pwd = 0,
CellularContext::AuthenticationType type = CellularContext::CHAP) = 0;
/** Set the cellular network APN and credentials
*
* @param apn Name of the network to connect to
* @param uname Optional username for the APN
* @param pwd Optional password for the APN
* @param type Optional authentication type to use
*/
virtual void set_apn_credentials(const char* apn, const char *uname = 0, const char *pwd = 0,
CellularContext::AuthenticationType type = CellularContext::CHAP) = 0;
/** Set the file handle used to communicate with the modem. Can be used to change default file handle.
*
* @param fh file handle for communicating with the modem
*/
virtual void set_file_handle(FileHandle *fh) = 0;
protected:
enum ContextOperation {
OP_INVALID = -1,
OP_DEVICE_READY = 0,
OP_SIM_READY = 1,
OP_REGISTER = 2,
OP_ATTACH = 3 ,
OP_CONNECT = 4,
OP_MAX = 5
};
/** Status callback function will be called on status changes on the network or CellularDevice
* by the CellularDevice.
*
* @param ev event type
* @param ptr event-type dependent reason parameter
*/
virtual void cellular_callback(nsapi_event_t ev, intptr_t ptr) = 0;
// member variables needed in target override methods
NetworkStack *_stack; // must be pointer because of PPP
nsapi_ip_stack_t _ip_stack_type;
CellularContext::AuthenticationType _authentication_type;
nsapi_connection_status_t _connect_status;
cell_callback_data_t _cb_data;
Callback<void(nsapi_event_t, intptr_t)> _status_cb;
int _cid;
bool _new_context_set;
bool _is_context_active;
bool _is_context_activated; // did we activate the context
const char *_apn;
const char *_uname;
const char *_pwd;
};
} // namespace mbed
#endif /* _CELLULARCONTEXT_H_ */

View File

@ -20,8 +20,6 @@
#include "CellularStateMachine.h"
class NetworkStack;
namespace mbed {
class CellularPower;
@ -29,8 +27,12 @@ class CellularSMS;
class CellularSIM;
class CellularInformation;
class CellularNetwork;
class CellularContext;
class FileHandle;
const int MAX_PIN_SIZE = 8;
const int MAX_PLMN_SIZE = 16;
/**
* Class CellularDevice
*
@ -53,6 +55,12 @@ public:
*/
virtual events::EventQueue *get_queue() const;
/** Get filehandle
*
* @return Filehandle used in CellularDevice. With AT it's UARTSerial.
*/
FileHandle &get_filehandle() const;
/** Default constructor
*/
CellularDevice();
@ -62,40 +70,65 @@ public:
virtual ~CellularDevice();
public:
/** Creates a new CellularContext interface. There can be multiple CellularContext interfaces unlike
* open_xxx(...) methods.
*
* @param fh file handle used in communication to modem. Can be for example UART handle. If null then the default
* file handle is used.
* @param apn access point to use with context, can be null.
* @param stack stack to be used when finding suitable PDP context
*
* @return new instance of class CellularContext or NULL in case of failure
*
*/
virtual CellularContext *create_context(FileHandle *fh = NULL, const char *apn = MBED_CONF_NSAPI_DEFAULT_CELLULAR_APN, nsapi_ip_stack_t stack = DEFAULT_STACK) = 0;
/** Deletes the given CellularContext instance
*
* @param context to delete
*/
virtual void delete_context(CellularContext *context) = 0;
/** Create new CellularNetwork interface.
*
* @param fh file handle used in communication to modem. Can be for example UART handle.
* @param fh file handle used in communication to modem. Can be for example UART handle. If null then the default
* file handle is used.
* @return New instance of interface CellularNetwork.
*/
virtual CellularNetwork *open_network(FileHandle *fh) = 0;
virtual CellularNetwork *open_network(FileHandle *fh = NULL) = 0;
/** Create new CellularSMS interface.
*
* @param fh file handle used in communication to modem. Can be for example UART handle.
* @param fh file handle used in communication to modem. Can be for example UART handle. If null then the default
* file handle is used.
* @return New instance of interface CellularSMS.
*/
virtual CellularSMS *open_sms(FileHandle *fh) = 0;
virtual CellularSMS *open_sms(FileHandle *fh = NULL) = 0;
/** Create new CellularPower interface.
*
* @param fh file handle used in communication to modem. Can be for example UART handle.
* @param fh file handle used in communication to modem. Can be for example UART handle. If null then the default
* file handle is used.
* @return New instance of interface CellularPower.
*/
virtual CellularPower *open_power(FileHandle *fh) = 0;
virtual CellularPower *open_power(FileHandle *fh = NULL) = 0;
/** Create new CellularSIM interface.
*
* @param fh file handle used in communication to modem. Can be for example UART handle.
* @param fh file handle used in communication to modem. Can be for example UART handle. If null then the default
* file handle is used.
* @return New instance of interface CellularSIM.
*/
virtual CellularSIM *open_sim(FileHandle *fh) = 0;
virtual CellularSIM *open_sim(FileHandle *fh = NULL) = 0;
/** Create new CellularInformation interface.
*
* @param fh file handle used in communication to modem. Can be for example UART handle.
* @param fh file handle used in communication to modem. Can be for example UART handle. If null then the default
* file handle is used.
* @return New instance of interface CellularInformation.
*/
virtual CellularInformation *open_information(FileHandle *fh) = 0;
virtual CellularInformation *open_information(FileHandle *fh = NULL) = 0;
/** Closes the opened CellularNetwork by deleting the CellularNetwork instance.
*/
@ -129,12 +162,6 @@ public:
*/
virtual void modem_debug_on(bool on) = 0;
/** Get network stack.
*
* @return network stack
*/
virtual NetworkStack *get_stack() = 0;
/** Initialize cellular module must be called right after module is ready.
* For example, when multiple modules are supported in a single AT driver this function detects
* and adapts to an actual module at runtime.
@ -147,33 +174,6 @@ public:
public:
/** Inits the internal state machine.
*
* @remark MUST be called if internal state machine is to be used. All the following public methods place in to this
* category.
*
* @param fh file handle to be used as serial. Can be for example UARTSerial
*/
nsapi_error_t init_stm(FileHandle *fh);
/** Check if the connection is currently established or not
*
* @return true/false If the cellular module have successfully acquired a carrier and is
* connected to an external packet data network using PPP, isConnected()
* API returns true and false otherwise.
*/
bool is_connected() const;
/** Register callback for status reporting
*
* The specified status callback function will be called on status changes
* on the network and modem. The parameters on the callback are the event type and struct cell_callback_data_t
* giving more information about the event.
*
* @param status_cb The callback for status changes
*/
void attach(Callback<void(nsapi_event_t, intptr_t)> status_cb);
/** Start event queue dispatching in internal state machine by creating a new thread.
*
* @return NSAPI_ERROR_OK on success
@ -186,21 +186,6 @@ public:
*/
void stop();
/** By default operations are synchronous. This method can toggle between sync/async.
*
*/
void set_blocking(bool blocking);
/** Set the Cellular network credentials
*
* Please check documentation of connect() for default behaviour of APN settings.
*
* @param apn Access point name
* @param uname optionally, Username
* @param pwd optionally, password
*/
nsapi_error_t set_credentials(const char *apn, const char *uname = 0, const char *pwd = 0);
/** Set the pin code for SIM card
*
* @param sim_pin PIN for the SIM card
@ -215,7 +200,8 @@ public:
*/
void set_plmn(const char* plmn);
public: // Operations that can be sync/async
public: // Operations that can be sync/async, CellularContext will use these
friend class CellularContext;
/** Start the interface
*
@ -265,65 +251,35 @@ public: // Operations that can be sync/async
*/
nsapi_error_t attach_to_network();
/** Start the interface
/** Cellular callback which is called by Network class after this class attaches to it, CellularStateMachine
* and CellularContext when in PPP mode. This method will broadcast to every interested classes:
* CellularContext (might be many) and CellularStateMachine if available.
*
* Attempts to activate PDP context.
* By default this API is synchronous. API can be set to asynchronous with method set_blocking(...).
* In synchronous and asynchronous mode application can get result in from callback which is set with
* attach(...)
*
* @return NSAPI_ERROR_OK on success
* NSAPI_ERROR_NO_MEMORY on case of memory failure
*/
nsapi_error_t activate_context();
void cellular_callback(nsapi_event_t ev, intptr_t ptr);
/** Start the interface
/** Get the linked list of CellularContext instances
*
* Attempts to connect to a Cellular network.
* By default this API is synchronous. API can be set to asynchronous with method set_blocking(...).
* In synchronous and asynchronous mode application can get result in from callback which is set with
* attach(...)
*
* @param sim_pin PIN for the SIM card
* @param apn optionally, access point name
* @param uname optionally, Username
* @param pwd optionally, password
* @return NSAPI_ERROR_OK on success, or negative error code on failure
* @return Pointer to first item in linked list
*/
nsapi_error_t connect(const char *sim_pin, const char *apn = 0, const char *uname = 0, const char *pwd = 0);
virtual CellularContext *get_context_list() const;
/** Start the interface
*
* Attempts to connect to a Cellular network.
* By default this API is synchronous. API can be set to asynchronous with method set_blocking(...).
* In synchronous and asynchronous mode application can get result in from callback which is set with
* attach(...)
* If the SIM requires a PIN, and it is not set/invalid, NSAPI_ERROR_AUTH_ERROR is returned.
*
* @return NSAPI_ERROR_OK on success, or negative error code on failure
*/
nsapi_error_t connect();
/** Stop the interface
*
* @return 0 on success, or error code on failure
*/
nsapi_error_t disconnect();
private:
void network_callback(nsapi_event_t ev, intptr_t ptr);
Callback<void(nsapi_event_t, intptr_t)> _nw_status_cb;
protected:
nsapi_error_t _error;
int _network_ref_count;
int _sms_ref_count;
int _power_ref_count;
int _sim_ref_count;
int _info_ref_count;
bool _is_connected;
CellularStateMachine *_state_machine;
FileHandle *_fh;
private:
nsapi_error_t start_state_machine(CellularStateMachine::CellularState target_state);
void create_state_machine();
nsapi_error_t _error;
CellularStateMachine *_state_machine;
CellularNetwork *_nw;
char _sim_pin[MAX_PIN_SIZE + 1];
char _plmn[MAX_PLMN_SIZE +1];
PlatformMutex _mutex;
};
} // namespace mbed

View File

@ -18,8 +18,9 @@
#ifndef CELLULAR_NETWORK_H_
#define CELLULAR_NETWORK_H_
#include "NetworkInterface.h"
#include "CellularList.h"
#include "Callback.h"
#include "nsapi_types.h"
namespace mbed {
@ -35,7 +36,7 @@ const int MAX_OPERATOR_NAME_SHORT = 8;
*
* An abstract interface for connecting to a network and getting information from it.
*/
class CellularNetwork : public NetworkInterface {
class CellularNetwork {
protected:
// friend of CellularDevice so that it's the only way to close/delete this class.
friend class CellularDevice;
@ -94,28 +95,6 @@ public:
Attached,
};
/* whether the additional exception reports are allowed to be sent when the maximum uplink rate is reached */
enum RateControlExceptionReports {
NotAllowedToBeSent = 0,
AllowedToBeSent
};
/* specifies the time unit to be used for the maximum uplink rate */
enum RateControlUplinkTimeUnit {
Unrestricted = 0,
Minute,
Hour,
Day,
Week
};
/* authentication type when activating or modifying the pdp context */
enum AuthenticationType {
NOAUTH = 0,
PAP,
CHAP
};
enum RadioAccessTechnology {
RAT_GSM,
RAT_GSM_COMPACT,
@ -159,51 +138,6 @@ public:
typedef CellularList<operator_t> operList_t;
/* PDP Context information */
struct pdpcontext_params_t {
char apn[MAX_ACCESSPOINT_NAME_LENGTH + 1];
char local_addr[MAX_IPV6_ADDR_IN_IPV4LIKE_DOTTED_FORMAT + 1];
char local_subnet_mask[MAX_IPV6_ADDR_IN_IPV4LIKE_DOTTED_FORMAT + 1];
char gateway_addr[MAX_IPV6_ADDR_IN_IPV4LIKE_DOTTED_FORMAT + 1];
char dns_primary_addr[MAX_IPV6_ADDR_IN_IPV4LIKE_DOTTED_FORMAT + 1];
char dns_secondary_addr[MAX_IPV6_ADDR_IN_IPV4LIKE_DOTTED_FORMAT + 1];
char p_cscf_prim_addr[MAX_IPV6_ADDR_IN_IPV4LIKE_DOTTED_FORMAT + 1];
char p_cscf_sec_addr[MAX_IPV6_ADDR_IN_IPV4LIKE_DOTTED_FORMAT + 1];
int cid;
int bearer_id;
int im_signalling_flag;
int lipa_indication;
int ipv4_mtu;
int wlan_offload;
int local_addr_ind;
int non_ip_mtu;
int serving_plmn_rate_control_value;
pdpcontext_params_t *next;
pdpcontext_params_t()
{
apn[0] = '\0';
local_addr[0] = '\0';
local_subnet_mask[0] = '\0';
gateway_addr[0] = '\0';
dns_primary_addr[0] = '\0';
dns_secondary_addr[0] = '\0';
p_cscf_prim_addr[0] = '\0';
p_cscf_sec_addr[0] = '\0';
cid = -1;
bearer_id = -1;
im_signalling_flag = -1;
lipa_indication = -1;
ipv4_mtu = -1;
wlan_offload = -1;
local_addr_ind = -1;
non_ip_mtu = -1;
serving_plmn_rate_control_value = -1;
next = NULL;
}
};
typedef CellularList<pdpcontext_params_t> pdpContextList_t;
struct operator_names_t {
char numeric[MAX_OPERATOR_NAME_SHORT + 1];
char alpha[MAX_OPERATOR_NAME_LONG + 1];
@ -248,14 +182,6 @@ public:
}
};
/** Does all the needed initializations that can fail
*
* @remark must be called immediately after constructor.
* @return NSAPI_ERROR_OK on success
* NSAPI_ERROR_NO_MEMORY on memory failure
*/
virtual nsapi_error_t init() = 0;
/** Request registering to network.
*
* @param plmn format is in numeric format or 0 for automatic network registration
@ -286,38 +212,12 @@ public:
virtual nsapi_error_t set_registration_urc(RegistrationType type, bool on) = 0;
/** Set the cellular network APN and credentials
*
* @param apn Optional name of the network to connect to
* @param username Optional username for the APN
* @param password Optional password fot the APN
* @return NSAPI_ERROR_OK on success
* NSAPI_ERROR_NO_MEMORY on memory failure
*/
virtual nsapi_error_t set_credentials(const char *apn,
const char *username = 0, const char *password = 0) = 0;
/** Set the cellular network APN and credentials
*
* @param apn Name of the network to connect to
* @param type Authentication type to use
* @param username Optional username for the APN
* @param password Optional password fot the APN
* @return NSAPI_ERROR_OK on success
* NSAPI_ERROR_NO_MEMORY on memory failure
*/
virtual nsapi_error_t set_credentials(const char *apn, AuthenticationType type,
const char *username = 0, const char *password = 0) = 0;
/** Request attach to network.
*
* @deprecated Parameter timeout will be deprecated. Use mbed-os/features/cellular/framework/API/CellularDevice.h set_timeout instead.
* @param timeout milliseconds to wait for attach response
* @return NSAPI_ERROR_OK on success
* NSAPI_ERROR_DEVICE_ERROR on failure
*/
MBED_DEPRECATED_SINCE("mbed-os-5.9", "Parameter timeout will be deprecated. Use mbed-os/features/cellular/framework/API/CellularDevice.h set_timeout instead.")
virtual nsapi_error_t set_attach(int timeout = 10 * 1000) = 0;
virtual nsapi_error_t set_attach() = 0;
/** Request attach status from network.
*
@ -334,27 +234,6 @@ public:
*/
virtual nsapi_error_t detach() = 0;
/** Get APN rate control.
*
* @remark optional params are not updated if not received from network, so use good defaults
* @param reports Additional exception reports at maximum rate reached are allowed to be sent [optional]
* @param time_unit Uplink time unit with values 0=unrestricted, 1=minute, 2=hour, 3=day, 4=week [optional]
* @param uplink_rate Maximum number of messages per timeUnit [optional]
* @return NSAPI_ERROR_OK on success
* NSAPI_ERROR_DEVICE_ERROR on case of failure
*/
virtual nsapi_error_t get_rate_control(CellularNetwork::RateControlExceptionReports &reports,
CellularNetwork::RateControlUplinkTimeUnit &time_unit, int &uplink_rate) = 0;
/** Get backoff timer value
*
* @param backoff_timer Backoff timer value associated with PDP APN in seconds
* @return NSAPI_ERROR_OK on success
* NSAPI_ERROR_PARAMETER if no access point is set or found when activating context
* NSAPI_ERROR_DEVICE_ERROR on failure
*/
virtual nsapi_error_t get_apn_backoff_timer(int &backoff_timer) = 0;
/** Sets radio access technology.
*
* @param rat Radio access technology
@ -395,70 +274,6 @@ public:
virtual nsapi_error_t get_ciot_optimization_config(Supported_UE_Opt &supported_opt,
Preferred_UE_Opt &preferred_opt) = 0;
/** Start the interface. Attempts to connect to a cellular network.
*
* @return NSAPI_ERROR_OK on success
* NSAPI_ERROR_NO_CONNECTION if fails to find suitable context to activate or activation failed (if not already activated)
* NSAPI_ERROR_UNSUPPORTED if NetworkStack was not found or cellular device does not support authentication
* NSAPI_ERROR_AUTH_FAILURE if password and username were provided and authentication to network failed
* Also if PPP mode
* NSAPI_ERROR_DEVICE_ERROR on failure and check more error from nsapi_ppp_connect(...)
*/
virtual nsapi_error_t connect() = 0;
/** Start the interface. Attempts to connect to a cellular network.
*
* @param apn Optional name of the network to connect to
* @param username Optional username for your APN
* @param password Optional password for your APN
* @return NSAPI_ERROR_OK on success
* NSAPI_ERROR_NO_CONNECTION if fails to find suitable context to activate or activation failed (if not already activated)
* NSAPI_ERROR_UNSUPPORTED if NetworkStack was not found
* NSAPI_ERROR_AUTH_FAILURE if password and username were provided and authentication to network failed
* NSAPI_ERROR_NO_MEMORY on memory failure
* Also if PPP mode
* NSAPI_ERROR_DEVICE_ERROR on failure and check more error from nsapi_ppp_connect(...)
*/
virtual nsapi_error_t connect(const char *apn,
const char *username = 0, const char *password = 0) = 0;
/** Finds the correct PDP context and activates it. If correct PDP context is not found, one is created.
* Given APN (or not given) and stack type (IPv4/IPv6/dual) are influencing when finding the PDP context.
*
* @return NSAPI_ERROR_OK on success
* NSAPI_ERROR_NO_CONNECTION if fails to find suitable context to activate or activation failed (if not already activated)
* NSAPI_ERROR_UNSUPPORTED if NetworkStack was not found
* NSAPI_ERROR_AUTH_FAILURE if password and username were provided and authentication to network failed
*/
virtual nsapi_error_t activate_context() = 0;
/**
* Set the pdn type to be used
*
* @param stack_type the stack type to be used.
*
* @return NSAPI_ERROR_OK on success
* NSAPI_ERROR_PARAMETER if modem does not support the given stack_type
*/
virtual nsapi_error_t set_stack_type(nsapi_ip_stack_t stack_type) = 0;
/**
* Get the pdn type in use
*
* @return stack type
*/
virtual nsapi_ip_stack_t get_stack_type() = 0;
/** Get the relevant information for an active non secondary PDP context.
*
* @remark optional params are not updated if not received from network.
* @param params_list reference to linked list, which is filled on successful call
* @return NSAPI_ERROR_OK on success
* NSAPI_ERROR_NO_MEMORY on memory failure
* NSAPI_ERROR_DEVICE_ERROR on other failures
*/
virtual nsapi_error_t get_pdpcontext_params(pdpContextList_t &params_list) = 0;
/** Get extended signal quality parameters.
*
* @param rxlev signal strength level
@ -511,14 +326,6 @@ public:
*/
virtual nsapi_connection_status_t get_connection_status() const = 0;
/** Set blocking status of connect() which by default should be blocking
*
* @param blocking true if connect is blocking
* @return NSAPI_ERROR_OK
* if PPP mode check errors from nsapi_ppp_set_blocking(...)
*/
virtual nsapi_error_t set_blocking(bool blocking) = 0;
/** Read operator names
*
* @param op_names on successful return contains linked list of operator names.
@ -528,6 +335,12 @@ public:
*/
virtual nsapi_error_t get_operator_names(operator_names_list &op_names) = 0;
/** Check if there is any PDP context active
*
* @return true is any context is active, false otherwise or in case of error
*/
virtual bool is_active_context() = 0;
/** Gets current network registration parameters:
* type, status, access technology, cell_id, lac, active_time, periodic_tau.
*

View File

@ -0,0 +1,871 @@
/*
* Copyright (c) 2018, Arm Limited and affiliates.
* SPDX-License-Identifier: Apache-2.0
*
* 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 "AT_CellularContext.h"
#include "AT_CellularNetwork.h"
#include "AT_CellularStack.h"
#include "CellularLog.h"
#include "CellularUtil.h"
#include "CellularSIM.h"
#include "UARTSerial.h"
#include "nsapi_ppp.h"
#include "nsapi_dns.h"
using namespace mbed_cellular_util;
using namespace mbed;
AT_CellularContext::AT_CellularContext(ATHandler &at, CellularDevice *device, const char *apn, nsapi_ip_stack_t stack) :
AT_CellularBase(at), _ip_stack_type_requested(DEFAULT_STACK), _is_connected(false), _is_blocking(true),
_current_op(OP_INVALID), _device(device), _nw(0), _fh(0)
{
tr_debug("AT_CellularContext::AT_CellularContext(): apn: %s, stack: %d", apn, stack);
_stack = NULL;
_ip_stack_type = DEFAULT_STACK;
_authentication_type = CellularContext::CHAP;
_connect_status = NSAPI_STATUS_DISCONNECTED;
_is_context_active = false;
_is_context_activated = false;
_apn = apn;
_uname = MBED_CONF_NSAPI_DEFAULT_CELLULAR_USERNAME;
_pwd = MBED_CONF_NSAPI_DEFAULT_CELLULAR_PASSWORD;
_status_cb = NULL;
_cid = -1;
_new_context_set = false;
_next = NULL;
}
AT_CellularContext::~AT_CellularContext()
{
(void)disconnect();
if (_nw) {
_device->close_network();
}
}
void AT_CellularContext::set_file_handle(FileHandle *fh)
{
_fh = fh;
_at.set_file_handle(_fh);
}
nsapi_error_t AT_CellularContext::connect()
{
if (_is_connected) {
return NSAPI_ERROR_IS_CONNECTED;
}
nsapi_error_t err = _device->attach_to_network();
_cb_data.error = check_operation(err, OP_CONNECT);
if (_is_blocking) {
if (_cb_data.error == NSAPI_ERROR_OK || _cb_data.error == NSAPI_ERROR_ALREADY) {
do_connect();
}
} else {
if (_cb_data.error == NSAPI_ERROR_ALREADY) {
// device is already attached, to be async we must use queue to connect and give proper callbacks
int id = _device->get_queue()->call_in(0, this, &AT_CellularContext::do_connect);
if (id == 0) {
return NSAPI_ERROR_NO_MEMORY;
}
return NSAPI_ERROR_OK;
}
}
return _cb_data.error;
}
nsapi_error_t AT_CellularContext::set_device_ready()
{
nsapi_error_t err = _device->set_device_ready();
return check_operation(err, OP_DEVICE_READY);
}
nsapi_error_t AT_CellularContext::set_sim_ready()
{
nsapi_error_t err = _device->set_sim_ready();
return check_operation(err, OP_SIM_READY);
}
nsapi_error_t AT_CellularContext::register_to_network()
{
nsapi_error_t err = _device->register_to_network();
return check_operation(err, OP_REGISTER);
}
nsapi_error_t AT_CellularContext::attach_to_network()
{
nsapi_error_t err = _device->attach_to_network();
return check_operation(err, OP_ATTACH);
}
nsapi_error_t AT_CellularContext::check_operation(nsapi_error_t err, ContextOperation op)
{
_current_op = op;
if (err == NSAPI_ERROR_IN_PROGRESS || err == NSAPI_ERROR_OK) {
if (_is_blocking) {
int sema_err = _semaphore.wait(get_timeout_for_operation(op)); // cellular network searching may take several minutes
if (sema_err != 1) {
tr_warning("No cellular connection");
return NSAPI_ERROR_TIMEOUT;
}
return NSAPI_ERROR_OK;
}
}
return err;
}
uint32_t AT_CellularContext::get_timeout_for_operation(ContextOperation op) const
{
uint32_t timeout = 10 * 60 * 1000; // default timeout is 10 minutes as registration and attach may take time
if (op == OP_SIM_READY || op == OP_DEVICE_READY) {
timeout = 3 * 60 * 1000; // use 3 minutes for device ready and sim
}
return timeout;
}
bool AT_CellularContext::is_connected()
{
return _is_connected;
}
NetworkStack *AT_CellularContext::get_stack()
{
#if NSAPI_PPP_AVAILABLE
// use lwIP/PPP if modem does not have IP stack
if (!_stack) {
_stack = nsapi_ppp_get_stack();
}
#endif
return _stack;
}
const char *AT_CellularContext::get_ip_address()
{
#if NSAPI_PPP_AVAILABLE
return nsapi_ppp_get_ip_addr(_at.get_file_handle());
#else
if (!_stack) {
_stack = get_stack();
}
if (_stack) {
return _stack->get_ip_address();
}
return NULL;
#endif
}
void AT_CellularContext::attach(Callback<void(nsapi_event_t, intptr_t)> status_cb)
{
_status_cb = status_cb;
}
nsapi_error_t AT_CellularContext::set_blocking(bool blocking)
{
nsapi_error_t err = NSAPI_ERROR_OK;
#if NSAPI_PPP_AVAILABLE
err = nsapi_ppp_set_blocking(blocking);
#endif
_is_blocking = blocking;
return err;
}
void AT_CellularContext::set_apn_credentials(const char *uname, const char *pwd,
CellularContext::AuthenticationType type) {
_uname = uname;
_pwd = pwd;
_authentication_type = type;
}
void AT_CellularContext::set_apn_credentials(const char* apn, const char *uname, const char *pwd,
CellularContext::AuthenticationType type)
{
_apn = apn;
_uname = uname;
_pwd = pwd;
_authentication_type = type;
}
bool AT_CellularContext::stack_type_supported(nsapi_ip_stack_t stack_type)
{
if (stack_type == _ip_stack_type) {
return true;
} else {
return false;
}
}
nsapi_ip_stack_t AT_CellularContext::get_stack_type()
{
return _ip_stack_type;
}
nsapi_ip_stack_t AT_CellularContext::string_to_stack_type(const char *pdp_type)
{
nsapi_ip_stack_t stack = DEFAULT_STACK;
int len = strlen(pdp_type);
if (len == 6 && memcmp(pdp_type, "IPV4V6", len) == 0) {
stack = IPV4V6_STACK;
} else if (len == 4 && memcmp(pdp_type, "IPV6", len) == 0) {
stack = IPV6_STACK;
} else if (len == 2 && memcmp(pdp_type, "IP", len) == 0) {
stack = IPV4_STACK;
}
return stack;
}
// PDP Context handling
nsapi_error_t AT_CellularContext::delete_current_context()
{
tr_info("Delete context %d", _cid);
_at.clear_error();
_at.cmd_start("AT+CGDCONT=");
_at.write_int(_cid);
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
if (_at.get_last_error() == NSAPI_ERROR_OK) {
_cid = -1;
_new_context_set = false;
}
return _at.get_last_error();
}
nsapi_error_t AT_CellularContext::do_user_authentication()
{
// if user has defined user name and password we need to call CGAUTH before activating or modifying context
if (_pwd && _uname) {
_at.cmd_start("AT+CGAUTH=");
_at.write_int(_cid);
_at.write_int(_authentication_type);
_at.write_string(_uname);
_at.write_string(_pwd);
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
if (_at.get_last_error() != NSAPI_ERROR_OK) {
return NSAPI_ERROR_AUTH_FAILURE;
}
}
return NSAPI_ERROR_OK;
}
bool AT_CellularContext::get_context()
{
if (_apn) {
tr_debug("APN in use: %s", _apn);
} else {
tr_debug("NO APN");
}
_at.cmd_start("AT+CGDCONT?");
_at.cmd_stop();
_at.resp_start("+CGDCONT:");
_cid = -1;
int cid_max = 0; // needed when creating new context
char apn[MAX_ACCESSPOINT_NAME_LENGTH];
int apn_len = 0;
bool modem_supports_ipv6 = stack_type_supported(IPV6_STACK);
bool modem_supports_ipv4 = stack_type_supported(IPV4_STACK);
while (_at.info_resp()) {
int cid = _at.read_int();
if (cid > cid_max) {
cid_max = cid;
}
char pdp_type_from_context[10];
int pdp_type_len = _at.read_string(pdp_type_from_context, sizeof(pdp_type_from_context) - 1);
if (pdp_type_len > 0) {
apn_len = _at.read_string(apn, sizeof(apn) - 1);
if (apn_len >= 0) {
if (_apn && (strcmp(apn, _apn) != 0)) {
continue;
}
nsapi_ip_stack_t pdp_stack = string_to_stack_type(pdp_type_from_context);
// Accept dual PDP context for IPv4/IPv6 only modems
if (pdp_stack != DEFAULT_STACK && (stack_type_supported(pdp_stack) || pdp_stack == IPV4V6_STACK)) {
if (_ip_stack_type_requested == IPV4_STACK) {
if (pdp_stack == IPV4_STACK || pdp_stack == IPV4V6_STACK) {
_ip_stack_type = _ip_stack_type_requested;
_cid = cid;
break;
}
} else if (_ip_stack_type_requested == IPV6_STACK) {
if (pdp_stack == IPV6_STACK || pdp_stack == IPV4V6_STACK) {
_ip_stack_type = _ip_stack_type_requested;
_cid = cid;
break;
}
} else {
// requested dual stack or stack is not specified
// If dual PDP need to check for IPV4 or IPV6 modem support. Prefer IPv6.
if (pdp_stack == IPV4V6_STACK) {
if (modem_supports_ipv6) {
_ip_stack_type = IPV6_STACK;
_cid = cid;
break;
} else if (modem_supports_ipv4) {
_ip_stack_type = IPV4_STACK;
_cid = cid;
break;
}
// If PDP is IPV4 or IPV6 they are already checked if supported
} else {
_ip_stack_type = pdp_stack;
_cid = cid;
if (pdp_stack == IPV6_STACK) {
break;
}
if (pdp_stack == IPV4_STACK && !modem_supports_ipv6) {
break;
}
}
}
}
}
}
}
_at.resp_stop();
if (_cid == -1) { // no suitable context was found so create a new one
if (!set_new_context(cid_max + 1)) {
return false;
}
}
// save the apn
if (apn_len > 0 && !_apn) {
memcpy(_found_apn, apn, apn_len + 1);
}
tr_debug("Context id %d", _cid);
return true;
}
bool AT_CellularContext::set_new_context(int cid)
{
nsapi_ip_stack_t tmp_stack = _ip_stack_type_requested;
if (tmp_stack == DEFAULT_STACK) {
bool modem_supports_ipv6 = stack_type_supported(IPV6_STACK);
bool modem_supports_ipv4 = stack_type_supported(IPV4_STACK);
if (modem_supports_ipv6 && modem_supports_ipv4) {
tmp_stack = IPV4V6_STACK;
} else if (modem_supports_ipv6) {
tmp_stack = IPV6_STACK;
} else if (modem_supports_ipv4) {
tmp_stack = IPV4_STACK;
}
}
char pdp_type[8 + 1] = {0};
switch (tmp_stack) {
case IPV4_STACK:
strncpy(pdp_type, "IP", sizeof(pdp_type));
break;
case IPV6_STACK:
strncpy(pdp_type, "IPV6", sizeof(pdp_type));
break;
case IPV4V6_STACK:
strncpy(pdp_type, "IPV6", sizeof(pdp_type)); // try first IPV6 and then fall-back to IPv4
break;
default:
break;
}
//apn: "If the value is null or omitted, then the subscription value will be requested."
bool success = false;
_at.cmd_start("AT+CGDCONT=");
_at.write_int(cid);
_at.write_string(pdp_type);
_at.write_string(_apn);
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
success = (_at.get_last_error() == NSAPI_ERROR_OK);
// Fall back to ipv4
if (!success && tmp_stack == IPV4V6_STACK) {
_at.clear_error();
tmp_stack = IPV4_STACK;
_at.cmd_start("AT+FCLASS=0;+CGDCONT=");
_at.write_int(cid);
_at.write_string("IP");
_at.write_string(_apn);
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
success = (_at.get_last_error() == NSAPI_ERROR_OK);
}
if (success) {
_ip_stack_type = tmp_stack;
_cid = cid;
_new_context_set = true;
tr_info("New PDP context id %d was created", _cid);
}
return success;
}
nsapi_error_t AT_CellularContext::do_activate_context()
{
_at.lock();
nsapi_error_t err = NSAPI_ERROR_OK;
// try to find or create context with suitable stack
if (get_context()) {
#if NSAPI_PPP_AVAILABLE
// in PPP we don't activate any context but leave it to PPP stack
return err;
#endif // NSAPI_PPP_AVAILABLE
// try to authenticate user before activating or modifying context
err = do_user_authentication();
} else {
err = NSAPI_ERROR_NO_CONNECTION;
}
if (err != NSAPI_ERROR_OK) {
_at.unlock();
tr_error("Failed to activate network context! (%d)", err);
call_network_cb(NSAPI_STATUS_DISCONNECTED);
return err;
}
// do check for stack to validate that we have support for stack
if (!get_stack()) {
tr_error("No cellular stack!");
return NSAPI_ERROR_UNSUPPORTED;
}
_is_context_active = false;
_is_context_activated = false;
_at.cmd_start("AT+CGACT?");
_at.cmd_stop();
_at.resp_start("+CGACT:");
while (_at.info_resp()) {
int context_id = _at.read_int();
int context_activation_state = _at.read_int();
if (context_id == _cid && context_activation_state == 1) {
_is_context_active = true;
}
}
_at.resp_stop();
if (!_is_context_active) {
tr_info("Activate PDP context %d", _cid);
_at.cmd_start("AT+CGACT=1,");
_at.write_int(_cid);
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
if (_at.get_last_error() == NSAPI_ERROR_OK) {
_is_context_activated = true;
}
}
err = (_at.get_last_error() == NSAPI_ERROR_OK) ? NSAPI_ERROR_OK : NSAPI_ERROR_NO_CONNECTION;
// If new PDP context was created and failed to activate, delete it
if (err != NSAPI_ERROR_OK && _new_context_set) {
delete_current_context();
} else if (err == NSAPI_ERROR_OK) {
_is_context_active = true;
}
_at.unlock();
return err;
}
void AT_CellularContext::do_connect()
{
call_network_cb(NSAPI_STATUS_CONNECTING);
if (!_is_context_active) {
_cb_data.error = do_activate_context();
#if !NSAPI_PPP_AVAILABLE
// in PPP mode we did not activate any context, just searched the correct _cid
if (_status_cb) {
_status_cb((nsapi_event_t)CellularActivatePDPContext, (intptr_t )&_cb_data);
}
#endif // !NSAPI_PPP_AVAILABLE
}
if (_cb_data.error != NSAPI_ERROR_OK) {
call_network_cb(NSAPI_STATUS_DISCONNECTED);
_is_connected = false;
return;
}
#if NSAPI_PPP_AVAILABLE
if (_cb_data.error == NSAPI_ERROR_OK) {
_at.lock();
_cb_data.error = open_data_channel();
_at.unlock();
if (_cb_data.error != NSAPI_ERROR_OK) {
tr_error("Failed to open data channel!");
call_network_cb(NSAPI_STATUS_DISCONNECTED);
_is_connected = false;
}
}
#else
_is_connected = true;
call_network_cb(NSAPI_STATUS_GLOBAL_UP);
#endif
}
#if NSAPI_PPP_AVAILABLE
nsapi_error_t AT_CellularContext::open_data_channel()
{
tr_info("Open data channel in PPP mode");
if (is_supported(AT_CGDATA)) {
_at.cmd_start("AT+CGDATA=\"PPP\",");
_at.write_int(_cid);
} else {
MBED_ASSERT(_cid >= 0 && _cid <= 99);
char cmd_buf[sizeof("ATD*99***xx#")];
std::sprintf(cmd_buf, "ATD*99***%d#", _cid);
_at.cmd_start(cmd_buf);
}
_at.cmd_stop();
_at.resp_start("CONNECT", true);
if (_at.get_last_error()) {
tr_error("Failed to CONNECT");
return _at.get_last_error();
}
_at.set_is_filehandle_usable(false);
/* Initialize PPP
* If blocking: mbed_ppp_init() is a blocking call, it will block until
connected, or timeout after 30 seconds*/
return nsapi_ppp_connect(_at.get_file_handle(), callback(this, &AT_CellularContext::ppp_status_cb), _uname, _pwd, _ip_stack_type);
}
void AT_CellularContext::ppp_status_cb(nsapi_event_t ev, intptr_t ptr)
{
if (ev == NSAPI_EVENT_CONNECTION_STATUS_CHANGE && ptr == NSAPI_STATUS_GLOBAL_UP) {
_is_connected = true;
} else {
_is_connected = false;
}
_connect_status = (nsapi_connection_status_t)ptr;
// call device's callback, it will broadcast this to here (cellular_callback)
_device->cellular_callback(ev, ptr);
}
#endif //#if NSAPI_PPP_AVAILABLE
nsapi_error_t AT_CellularContext::disconnect()
{
if (!_nw) {
return NSAPI_ERROR_NO_CONNECTION;
}
#if NSAPI_PPP_AVAILABLE
nsapi_error_t err = nsapi_ppp_disconnect(_at.get_file_handle());
if (err != NSAPI_ERROR_OK) {
tr_error("Cellular disconnect failed!");
// continue even in failure due to ppp disconnect in any case releases filehandle
}
// after ppp disconnect if we wan't to use same at handler we need to set filehandle again to athandler so it
// will set the correct sigio and nonblocking
_at.lock();
_at.set_file_handle(_at.get_file_handle());
_at.set_is_filehandle_usable(true);
//_at.sync(); // consume extra characters after ppp disconnect, also it may take a while until modem listens AT commands
_at.unlock();
#endif // NSAPI_PPP_AVAILABLE
_at.lock();
// deactivate a context only if we have activated
if (_is_context_activated) {
_is_context_active = false;
size_t active_contexts_count = 0;
_at.cmd_start("AT+CGACT?");
_at.cmd_stop();
_at.resp_start("+CGACT:");
while (_at.info_resp()) {
int context_id = _at.read_int();
int context_activation_state = _at.read_int();
if (context_activation_state == 1) {
active_contexts_count++;
if (context_id == _cid) {
_is_context_active = true;
}
}
}
_at.resp_stop();
CellularNetwork::RadioAccessTechnology rat = CellularNetwork::RAT_GSM;
// always return NSAPI_ERROR_OK
CellularNetwork::registration_params_t reg_params;
_nw->get_registration_params(reg_params);
rat = reg_params._act;
// 3GPP TS 27.007:
// For EPS, if an attempt is made to disconnect the last PDN connection, then the MT responds with ERROR
if (_is_context_active && (rat < CellularNetwork::RAT_E_UTRAN || active_contexts_count > 1)) {
_at.cmd_start("AT+CGACT=0,");
_at.write_int(_cid);
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
}
}
if (!_at.get_last_error()) {
call_network_cb(NSAPI_STATUS_DISCONNECTED);
}
return _at.unlock_return_error();
}
nsapi_error_t AT_CellularContext::get_apn_backoff_timer(int &backoff_timer)
{
// If apn is set
if (_apn) {
_at.lock();
_at.cmd_start("AT+CABTRDP=");
_at.write_string(_apn);
_at.cmd_stop();
_at.resp_start("+CABTRDP:");
if (_at.info_resp()) {
_at.skip_param();
backoff_timer = _at.read_int();
}
_at.resp_stop();
return _at.unlock_return_error();
}
return NSAPI_ERROR_PARAMETER;
}
nsapi_error_t AT_CellularContext::get_rate_control(
CellularContext::RateControlExceptionReports &reports,
CellularContext::RateControlUplinkTimeUnit &timeUnit, int &uplinkRate)
{
_at.lock();
_at.cmd_start("AT+CGAPNRC=");
_at.write_int(_cid);
_at.cmd_stop();
_at.resp_start("+CGAPNRC:");
_at.read_int();
if (_at.get_last_error() == NSAPI_ERROR_OK) {
bool comma_found = true;
int next_element = _at.read_int();
if (next_element >= 0) {
reports = (RateControlExceptionReports)next_element;
tr_debug("reports %d", reports);
next_element = _at.read_int();
} else {
comma_found = false;
}
if (comma_found && next_element >= 0) {
timeUnit = (RateControlUplinkTimeUnit)next_element;
tr_debug("time %d", timeUnit);
next_element = _at.read_int();
} else {
comma_found = false;
}
if (comma_found && next_element >= 0) {
uplinkRate = next_element;
tr_debug("rate %d", uplinkRate);
}
}
_at.resp_stop();
return _at.unlock_return_error();
}
nsapi_error_t AT_CellularContext::get_pdpcontext_params(pdpContextList_t &params_list)
{
const int ipv6_subnet_size = 128;
const int max_ipv6_size = 64;
char *ipv6_and_subnetmask = (char *)malloc(ipv6_subnet_size);
if (!ipv6_and_subnetmask) {
return NSAPI_ERROR_NO_MEMORY;
}
char *temp = (char *)malloc(max_ipv6_size);
if (!temp) {
free(ipv6_and_subnetmask);
return NSAPI_ERROR_NO_MEMORY;
}
_at.lock();
_at.cmd_start("AT+CGCONTRDP=");
_at.write_int(_cid);
_at.cmd_stop();
_at.resp_start("+CGCONTRDP:");
pdpcontext_params_t *params = NULL;
while (_at.info_resp()) { // response can be zero or many +CGDCONT lines
params = params_list.add_new();
if (!params) {
tr_warn("Could not allocate new pdpcontext_params_t");
_at.resp_stop();
_at.unlock();
params_list.delete_all();
free(temp);
free(ipv6_and_subnetmask);
return NSAPI_ERROR_NO_MEMORY;
}
params->cid = _at.read_int();
params->bearer_id = _at.read_int();
_at.read_string(params->apn, sizeof(params->apn));
// rest are optional params
ipv6_and_subnetmask[0] = '\0';
temp[0] = '\0';
_at.read_string(ipv6_and_subnetmask, ipv6_subnet_size);
separate_ip_addresses(ipv6_and_subnetmask, params->local_addr, sizeof(params->local_addr), params->local_subnet_mask, sizeof(params->local_subnet_mask));
ipv6_and_subnetmask[0] = '\0';
_at.read_string(ipv6_and_subnetmask, ipv6_subnet_size);
separate_ip_addresses(ipv6_and_subnetmask, params->gateway_addr, sizeof(params->gateway_addr), temp, max_ipv6_size);
prefer_ipv6(params->gateway_addr, sizeof(params->gateway_addr), temp, max_ipv6_size);
ipv6_and_subnetmask[0] = '\0';
temp[0] = '\0';
_at.read_string(ipv6_and_subnetmask, ipv6_subnet_size);
separate_ip_addresses(ipv6_and_subnetmask, params->dns_primary_addr, sizeof(params->dns_primary_addr), temp, max_ipv6_size);
prefer_ipv6(params->dns_primary_addr, sizeof(params->dns_primary_addr), temp, max_ipv6_size);
ipv6_and_subnetmask[0] = '\0';
temp[0] = '\0';
_at.read_string(ipv6_and_subnetmask, ipv6_subnet_size);
separate_ip_addresses(ipv6_and_subnetmask, params->dns_secondary_addr, sizeof(params->dns_secondary_addr), temp, max_ipv6_size);
prefer_ipv6(params->dns_secondary_addr, sizeof(params->dns_secondary_addr), temp, max_ipv6_size);
ipv6_and_subnetmask[0] = '\0';
temp[0] = '\0';
_at.read_string(ipv6_and_subnetmask, ipv6_subnet_size);
separate_ip_addresses(ipv6_and_subnetmask, params->p_cscf_prim_addr, sizeof(params->p_cscf_prim_addr), temp, max_ipv6_size);
prefer_ipv6(params->p_cscf_prim_addr, sizeof(params->p_cscf_prim_addr), temp, max_ipv6_size);
ipv6_and_subnetmask[0] = '\0';
temp[0] = '\0';
_at.read_string(ipv6_and_subnetmask, ipv6_subnet_size);
separate_ip_addresses(ipv6_and_subnetmask, params->p_cscf_sec_addr, sizeof(params->p_cscf_sec_addr), temp, max_ipv6_size);
prefer_ipv6(params->p_cscf_sec_addr, sizeof(params->p_cscf_sec_addr), temp, max_ipv6_size);
params->im_signalling_flag = _at.read_int();
params->lipa_indication = _at.read_int();
params->ipv4_mtu = _at.read_int();
params->wlan_offload = _at.read_int();
params->local_addr_ind = _at.read_int();
params->non_ip_mtu = _at.read_int();
params->serving_plmn_rate_control_value = _at.read_int();
}
_at.resp_stop();
free(temp);
free(ipv6_and_subnetmask);
return _at.unlock_return_error();
}
// Called by CellularDevice for network and cellular device changes
void AT_CellularContext::cellular_callback(nsapi_event_t ev, intptr_t ptr)
{
if (ev >= NSAPI_EVENT_CELLULAR_STATUS_BASE && ev <= NSAPI_EVENT_CELLULAR_STATUS_END) {
cell_callback_data_t* data = (cell_callback_data_t*)ptr;
cellular_connection_status_t st = (cellular_connection_status_t)ev;
tr_debug("AT_CellularContext: network_callback called with event: %d, err: %d, data: %d", ev, data->error, data->status_data);
_cb_data.error = data->error;
if (_is_blocking) {
if (data->error != NSAPI_ERROR_OK) {
// operation failed, release semaphore
_semaphore.release();
} else {
if ((st == CellularDeviceReady && _current_op == OP_DEVICE_READY) ||
(st == CellularSIMStatusChanged && _current_op == OP_SIM_READY &&
data->status_data == CellularSIM::SimStateReady)) {
// target reached, release semaphore
_semaphore.release();
} else if (st == CellularRegistrationStatusChanged && (data->status_data == CellularNetwork::RegisteredHomeNetwork ||
data->status_data == CellularNetwork::RegisteredRoaming) && _current_op == OP_REGISTER) {
// target reached, release semaphore
_semaphore.release();
} else if (st == CellularAttachNetwork && (_current_op == OP_ATTACH || _current_op == OP_CONNECT) &&
data->status_data == CellularNetwork::Attached) {
_nw = _device->open_network(_fh);
// target reached, release semaphore
_semaphore.release();
}
}
} else {
// non blocking
if (st == CellularAttachNetwork && _current_op == OP_CONNECT && data->error == NSAPI_ERROR_OK &&
data->status_data == CellularNetwork::Attached) {
// forward to application
if (_status_cb) {
_status_cb(ev, ptr);
}
do_connect();
return;
}
}
} else {
tr_debug("AT_CellularContext: network_callback called with event: %d, ptr: %d", ev, ptr);
#if NSAPI_PPP_AVAILABLE
if (_is_blocking) {
if (ev == NSAPI_EVENT_CONNECTION_STATUS_CHANGE && ptr == NSAPI_STATUS_GLOBAL_UP) {
_cb_data.error = NSAPI_ERROR_OK;
_semaphore.release();
} else if (ev == NSAPI_EVENT_CONNECTION_STATUS_CHANGE && ptr == NSAPI_STATUS_DISCONNECTED) {
_cb_data.error = NSAPI_ERROR_NO_CONNECTION;
_semaphore.release();
}
}
#endif
}
// forward to application
if (_status_cb) {
_status_cb(ev, ptr);
}
}
void AT_CellularContext::call_network_cb(nsapi_connection_status_t status)
{
if (_connect_status != status) {
_connect_status = status;
if (_status_cb) {
_status_cb(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, _connect_status);
}
}
}

View File

@ -0,0 +1,122 @@
/*
* Copyright (c) 2018, Arm Limited and affiliates.
* SPDX-License-Identifier: Apache-2.0
*
* 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.
*/
#ifndef AT_CELLULARCONTEXT_H_
#define AT_CELLULARCONTEXT_H_
#include "CellularContext.h"
#include "AT_CellularBase.h"
#include "Semaphore.h"
const int MAX_APN_LENGTH = 63 + 1;
namespace mbed {
class AT_CellularContext : public CellularContext, public AT_CellularBase {
public:
AT_CellularContext(ATHandler &at, CellularDevice *device, const char *apn = MBED_CONF_NSAPI_DEFAULT_CELLULAR_APN,
nsapi_ip_stack_t stack = DEFAULT_STACK);
virtual ~AT_CellularContext();
public: // from NetworkInterface
virtual nsapi_error_t set_blocking(bool blocking);
virtual NetworkStack *get_stack();
virtual const char *get_ip_address();
virtual void attach(mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb);
virtual nsapi_error_t connect();
virtual nsapi_error_t disconnect();
virtual bool is_connected();
public: // from CellularContext
virtual nsapi_error_t get_pdpcontext_params(pdpContextList_t &params_list);
virtual nsapi_error_t get_rate_control(CellularContext::RateControlExceptionReports &reports,
CellularContext::RateControlUplinkTimeUnit &time_unit, int &uplink_rate);
virtual nsapi_error_t get_apn_backoff_timer(int &backoff_timer);
virtual nsapi_error_t set_device_ready();
virtual nsapi_error_t set_sim_ready();
virtual nsapi_error_t register_to_network();
virtual nsapi_error_t attach_to_network();
virtual void set_apn_credentials(const char *uname = 0, const char *pwd = 0,
CellularContext::AuthenticationType type = CellularContext::CHAP);
virtual void set_apn_credentials(const char* apn, const char *uname = 0, const char *pwd = 0,
CellularContext::AuthenticationType type = CellularContext::CHAP);
virtual void set_file_handle(FileHandle *fh);
protected:
virtual void cellular_callback(nsapi_event_t ev, intptr_t ptr);
/** Does the authentication for the PDP Context if user name and password are provided.
* Can be overridden by the modem target if 3GPP default implementation if not an option
*
* @return NSAPI_ERROR_OK if no credentials provided or authentication was successful
* NSAPI_ERROR_AUTH_FAILURE if authentication failed
* NSAPI_ERROR_DEVICE_ERROR if communication with the modemm failed
*/
virtual nsapi_error_t do_user_authentication();
/** Activates PDP context or in PPP mode opens data channel.
* Can be overridden by the modem target if 3GPP default implementation if not an option
*/
virtual void do_connect();
/** Check if modem supports the given stack type. Can be overridden by the modem.
*
* @return true if supported
*/
virtual bool stack_type_supported(nsapi_ip_stack_t stack_type);
/** Get the operation specific timeout. Used in synchronous mode when setting the maximum
* waiting time. Modem specific implementation can override this to provide different timeouts.
*
* @param op current operation
* @return timeout in milliseconds
*/
virtual uint32_t get_timeout_for_operation(ContextOperation op) const;
/** Helper method to call callback function if it is provided
*
* @param status connection status which is parameter in callback function
*/
void call_network_cb(nsapi_connection_status_t status);
private:
#if NSAPI_PPP_AVAILABLE
nsapi_error_t open_data_channel();
void ppp_status_cb(nsapi_event_t ev, intptr_t ptr);
#endif // #if NSAPI_PPP_AVAILABLE
nsapi_error_t do_activate_context();
bool set_new_context(int cid);
bool get_context();
nsapi_error_t delete_current_context();
nsapi_ip_stack_t string_to_stack_type(const char *pdp_type);
nsapi_ip_stack_t get_stack_type();
nsapi_error_t check_operation(nsapi_error_t err, ContextOperation op);
private:
nsapi_ip_stack_t _ip_stack_type_requested;
bool _is_connected;
bool _is_blocking;
ContextOperation _current_op;
char _found_apn[MAX_APN_LENGTH];
CellularDevice *_device;
CellularNetwork *_nw;
FileHandle *_fh;
rtos::Semaphore _semaphore;
};
} // namespace mbed
#endif // AT_CELLULARCONTEXT_H_

View File

@ -21,7 +21,11 @@
#include "AT_CellularPower.h"
#include "AT_CellularSIM.h"
#include "AT_CellularSMS.h"
#include "AT_CellularContext.h"
#include "AT_CellularStack.h"
#include "CellularLog.h"
#include "ATHandler.h"
#include "UARTSerial.h"
using namespace events;
using namespace mbed;
@ -29,9 +33,10 @@ using namespace mbed;
#define DEFAULT_AT_TIMEOUT 1000 // at default timeout in milliseconds
AT_CellularDevice::AT_CellularDevice(EventQueue &queue) :
_atHandlers(0), _network(0), _sms(0), _sim(0), _power(0), _information(0), _at_queue(queue),
_atHandlers(0), _network(0), _sms(0), _sim(0), _power(0), _information(0), _context_list(0), _at_queue(queue),
_default_timeout(DEFAULT_AT_TIMEOUT), _modem_debug_on(false)
{
_fh = new UARTSerial(MDMTXD, MDMRXD, MBED_CONF_PLATFORM_DEFAULT_SERIAL_BAUD_RATE);
}
AT_CellularDevice::~AT_CellularDevice()
@ -49,12 +54,22 @@ AT_CellularDevice::~AT_CellularDevice()
close_sim();
close_information();
AT_CellularContext* curr = _context_list;
AT_CellularContext* next;
while (curr) {
next = (AT_CellularContext*)curr->_next;
delete curr;
curr = next;
}
ATHandler *atHandler = _atHandlers;
while (atHandler) {
ATHandler *old = atHandler;
atHandler = atHandler->_nextATHandler;
delete old;
}
delete _fh;
}
events::EventQueue *AT_CellularDevice::get_queue() const
@ -66,7 +81,7 @@ events::EventQueue *AT_CellularDevice::get_queue() const
ATHandler *AT_CellularDevice::get_at_handler(FileHandle *fileHandle)
{
if (!fileHandle) {
return NULL;
fileHandle = _fh;
}
ATHandler *atHandler = _atHandlers;
while (atHandler) {
@ -114,6 +129,58 @@ void AT_CellularDevice::release_at_handler(ATHandler *at_handler)
}
}
CellularContext *AT_CellularDevice::get_context_list() const
{
return _context_list;
}
CellularContext *AT_CellularDevice::create_context(FileHandle *fh, const char *apn, nsapi_ip_stack_t stack)
{
ATHandler *atHandler = get_at_handler(_fh);
if (atHandler) {
AT_CellularContext *ctx = create_context_impl(*atHandler, apn, stack);
AT_CellularContext* curr = _context_list;
if (_context_list == NULL) {
_context_list = ctx;
return ctx;
}
AT_CellularContext* prev;
while (curr) {
prev = curr;
curr = (AT_CellularContext*)curr->_next;
}
prev->_next = ctx;
return ctx;
}
return NULL;
}
AT_CellularContext *AT_CellularDevice::create_context_impl(ATHandler &at, const char *apn, nsapi_ip_stack_t stack)
{
return new AT_CellularContext(at, this, apn, stack);
}
void AT_CellularDevice::delete_context(CellularContext *context)
{
AT_CellularContext* curr = _context_list;
AT_CellularContext* prev = NULL;
while (curr) {
if (curr == context) {
if (prev == NULL) {
_context_list = (AT_CellularContext*)curr->_next;
} else {
prev->_next = curr->_next;
}
}
prev = curr;
curr = (AT_CellularContext*)curr->_next;
}
delete (AT_CellularContext*)context;
}
CellularNetwork *AT_CellularDevice::open_network(FileHandle *fh)
{
if (!_network) {
@ -301,14 +368,6 @@ void AT_CellularDevice::modem_debug_on(bool on)
}
}
NetworkStack *AT_CellularDevice::get_stack()
{
if (!_network) {
return NULL;
}
return _network->get_stack();
}
nsapi_error_t AT_CellularDevice::init_module(FileHandle *fh)
{
return NSAPI_ERROR_OK;

View File

@ -28,6 +28,7 @@ class AT_CellularNetwork;
class AT_CellularPower;
class AT_CellularSIM;
class AT_CellularSMS;
class AT_CellularContext;
/**
* Class AT_CellularDevice
@ -54,15 +55,19 @@ public: // CellularDevice
virtual events::EventQueue *get_queue() const;
virtual CellularNetwork *open_network(FileHandle *fh);
virtual CellularContext *create_context(FileHandle *fh = NULL, const char *apn = MBED_CONF_NSAPI_DEFAULT_CELLULAR_APN, nsapi_ip_stack_t stack = DEFAULT_STACK);
virtual CellularSMS *open_sms(FileHandle *fh);
virtual void delete_context(CellularContext *context);
virtual CellularPower *open_power(FileHandle *fh);
virtual CellularNetwork *open_network(FileHandle *fh = NULL);
virtual CellularSIM *open_sim(FileHandle *fh);
virtual CellularSMS *open_sms(FileHandle *fh = NULL);
virtual CellularInformation *open_information(FileHandle *fh);
virtual CellularPower *open_power(FileHandle *fh = NULL);
virtual CellularSIM *open_sim(FileHandle *fh = NULL);
virtual CellularInformation *open_information(FileHandle *fh = NULL);
virtual void close_network();
@ -80,11 +85,12 @@ public: // CellularDevice
virtual void modem_debug_on(bool on);
virtual NetworkStack *get_stack();
virtual nsapi_error_t init_module(FileHandle *fh);
protected:
virtual AT_CellularContext *create_context_impl(ATHandler &at, const char *apn, nsapi_ip_stack_t stack);
/** Create new instance of AT_CellularNetwork or if overridden, modem specific implementation.
*
* @param at ATHandler reference for communication with the modem.
@ -120,12 +126,14 @@ protected:
*/
virtual AT_CellularInformation *open_information_impl(ATHandler &at);
virtual CellularContext *get_context_list() const;
AT_CellularNetwork *_network;
AT_CellularSMS *_sms;
AT_CellularSIM *_sim;
AT_CellularPower *_power;
AT_CellularInformation *_information;
AT_CellularContext *_context_list;
protected:
events::EventQueue &_at_queue;
int _default_timeout;

View File

@ -17,7 +17,6 @@
#include <stdlib.h>
#include "AT_CellularNetwork.h"
#include "nsapi_ppp.h"
#include "CellularUtil.h"
#include "CellularLog.h"
#include "CellularCommon.h"
@ -39,65 +38,47 @@ static const at_reg_t at_reg[] = {
};
AT_CellularNetwork::AT_CellularNetwork(ATHandler &atHandler) : AT_CellularBase(atHandler),
_stack(NULL), _apn(NULL), _uname(NULL), _pwd(NULL), _ip_stack_type_requested(DEFAULT_STACK),
_ip_stack_type(DEFAULT_STACK), _cid(-1), _connection_status_cb(NULL), _op_act(RAT_UNKNOWN),
_authentication_type(CHAP), _connect_status(NSAPI_STATUS_DISCONNECTED), _new_context_set(false),
_is_context_active(false)
_connection_status_cb(NULL), _op_act(RAT_UNKNOWN), _connect_status(NSAPI_STATUS_DISCONNECTED)
{
}
AT_CellularNetwork::~AT_CellularNetwork()
{
#if NSAPI_PPP_AVAILABLE
(void)disconnect();
#else
delete _stack;
#endif // NSAPI_PPP_AVAILABLE
for (int type = 0; type < CellularNetwork::C_MAX; type++) {
if (has_registration((RegistrationType)type) != RegistrationModeDisable) {
_at.remove_urc_handler(at_reg[type].urc_prefix);
}
}
_at.remove_urc_handler("NO CARRIER");
_at.remove_urc_handler("+CGEV:");
free_credentials();
}
nsapi_error_t AT_CellularNetwork::init()
{
_urc_funcs[C_EREG] = callback(this, &AT_CellularNetwork::urc_cereg);
_urc_funcs[C_GREG] = callback(this, &AT_CellularNetwork::urc_cgreg);
_urc_funcs[C_REG] = callback(this, &AT_CellularNetwork::urc_creg);
for (int type = 0; type < CellularNetwork::C_MAX; type++) {
if (has_registration((RegistrationType)type) != RegistrationModeDisable) {
if (_at.set_urc_handler(at_reg[type].urc_prefix, _urc_funcs[type]) != NSAPI_ERROR_OK) {
return NSAPI_ERROR_NO_MEMORY;
}
_at.set_urc_handler(at_reg[type].urc_prefix, _urc_funcs[type]);
}
}
return _at.set_urc_handler("NO CARRIER", callback(this, &AT_CellularNetwork::urc_no_carrier));
_at.set_urc_handler("NO CARRIER", callback(this, &AT_CellularNetwork::urc_no_carrier));
// additional urc to get better disconnect info for application. Not critical.
_at.set_urc_handler("+CGEV:", callback(this, &AT_CellularNetwork::urc_cgev));
_at.lock();
_at.cmd_start("AT+CGEREP=1");// discard unsolicited result codes when MT TE link is reserved (e.g. in on line data mode); otherwise forward them directly to the TE
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
_at.unlock();
}
void AT_CellularNetwork::free_credentials()
AT_CellularNetwork::~AT_CellularNetwork()
{
if (_uname) {
free(_uname);
_uname = NULL;
_at.lock();
_at.cmd_start("AT+CGEREP=0");// buffer unsolicited result codes in the MT; if MT result code buffer is full, the oldest ones can be discarded. No codes are forwarded to the TE
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
_at.unlock();
for (int type = 0; type < CellularNetwork::C_MAX; type++) {
if (has_registration((RegistrationType)type) != RegistrationModeDisable) {
_at.remove_urc_handler(at_reg[type].urc_prefix, _urc_funcs[type]);
}
}
if (_pwd) {
free(_pwd);
_pwd = NULL;
}
if (_apn) {
free(_apn);
_apn = NULL;
}
_at.remove_urc_handler("NO CARRIER", callback(this, &AT_CellularNetwork::urc_no_carrier));
_at.remove_urc_handler("+CGEV:", callback(this, &AT_CellularNetwork::urc_cgev));
}
void AT_CellularNetwork::urc_no_carrier()
@ -160,21 +141,21 @@ void AT_CellularNetwork::read_reg_params_and_compare(RegistrationType type)
if (_at.get_last_error() == NSAPI_ERROR_OK && _connection_status_cb) {
tr_debug("type: %d, status: %d, lac: %d, cellID: %d, act: %d", type, reg_params._status, reg_params._lac, reg_params._cell_id, reg_params._act);
_reg_params._type = type;
cell_callback_data_t data;
cell_callback_data_t data;
data.error = NSAPI_ERROR_OK;
if (reg_params._act != _reg_params._act) {
_reg_params._act = reg_params._act;
data.status_data = reg_params._act;
data.status_data = reg_params._act;
_connection_status_cb((nsapi_event_t)CellularRadioAccessTechnologyChanged, (intptr_t)&data);
}
if (reg_params._status != _reg_params._status) {
_reg_params._status = reg_params._status;
data.status_data = reg_params._status;
data.status_data = reg_params._status;
_connection_status_cb((nsapi_event_t)CellularRegistrationStatusChanged, (intptr_t)&data);
}
if (reg_params._cell_id != -1 && reg_params._cell_id != _reg_params._cell_id) {
_reg_params._cell_id = reg_params._cell_id;
data.status_data = reg_params._cell_id;
data.status_data = reg_params._cell_id;
_connection_status_cb((nsapi_event_t)CellularCellIDChanged, (intptr_t)&data);
}
}
@ -198,278 +179,6 @@ void AT_CellularNetwork::urc_cgreg()
read_reg_params_and_compare(C_GREG);
}
nsapi_error_t AT_CellularNetwork::set_credentials(const char *apn,
const char *username, const char *password)
{
free_credentials();
size_t len;
if (apn && (len = strlen(apn)) > 0) {
_apn = (char *)malloc(len * sizeof(char) + 1);
if (_apn) {
memcpy(_apn, apn, len + 1);
} else {
return NSAPI_ERROR_NO_MEMORY;
}
}
if (username && (len = strlen(username)) > 0) {
if (!is_supported(AT_CGAUTH)) { // APN authentication is needed with username/password
return NSAPI_ERROR_UNSUPPORTED;
}
_uname = (char *)malloc(len * sizeof(char) + 1);
if (_uname) {
memcpy(_uname, username, len + 1);
} else {
return NSAPI_ERROR_NO_MEMORY;
}
}
if (password && (len = strlen(password)) > 0) {
_pwd = (char *)malloc(len * sizeof(char) + 1);
if (_pwd) {
memcpy(_pwd, password, len + 1);
} else {
return NSAPI_ERROR_NO_MEMORY;
}
}
return NSAPI_ERROR_OK;
}
nsapi_error_t AT_CellularNetwork::set_credentials(const char *apn,
AuthenticationType type, const char *username, const char *password)
{
nsapi_error_t err = set_credentials(apn, username, password);
if (err) {
return err;
}
_authentication_type = type;
return NSAPI_ERROR_OK;
}
nsapi_error_t AT_CellularNetwork::connect(const char *apn,
const char *username, const char *password)
{
nsapi_error_t err = set_credentials(apn, username, password);
if (err) {
return err;
}
return connect();
}
nsapi_error_t AT_CellularNetwork::delete_current_context()
{
tr_info("Delete context %d", _cid);
_at.clear_error();
_at.cmd_start("AT+CGDCONT=");
_at.write_int(_cid);
_at.cmd_stop_read_resp();
if (_at.get_last_error() == NSAPI_ERROR_OK) {
_cid = -1;
_new_context_set = false;
}
return _at.get_last_error();
}
nsapi_error_t AT_CellularNetwork::activate_context()
{
_at.lock();
nsapi_error_t err = NSAPI_ERROR_OK;
// try to find or create context with suitable stack
if (!get_context()) {
err = NSAPI_ERROR_NO_CONNECTION;
}
if (err != NSAPI_ERROR_OK) {
_at.unlock();
tr_error("Failed to activate network context! (%d)", err);
call_network_cb(NSAPI_STATUS_DISCONNECTED);
return err;
}
// do check for stack to validate that we have support for stack
_stack = get_stack();
if (!_stack) {
tr_error("No cellular stack!");
return NSAPI_ERROR_UNSUPPORTED;
}
_is_context_active = false;
_at.cmd_start("AT+CGACT?");
_at.cmd_stop();
_at.resp_start("+CGACT:");
while (_at.info_resp()) {
int context_id = _at.read_int();
int context_activation_state = _at.read_int();
if (context_id == _cid && context_activation_state == 1) {
_is_context_active = true;
}
}
_at.resp_stop();
if (!_is_context_active) {
// authenticate before activating or modifying context
nsapi_error_t err = do_user_authentication();
if (err != NSAPI_ERROR_OK) {
tr_error("Cellular authentication failed!");
return err;
}
tr_info("Activate PDP context %d", _cid);
_at.cmd_start("AT+CGACT=1,");
_at.write_int(_cid);
_at.cmd_stop_read_resp();
}
err = (_at.get_last_error() == NSAPI_ERROR_OK) ? NSAPI_ERROR_OK : NSAPI_ERROR_NO_CONNECTION;
// If new PDP context was created and failed to activate, delete it
if (err != NSAPI_ERROR_OK && _new_context_set) {
delete_current_context();
} else if (err == NSAPI_ERROR_OK) {
_is_context_active = true;
}
_at.unlock();
return err;
}
nsapi_error_t AT_CellularNetwork::connect()
{
call_network_cb(NSAPI_STATUS_CONNECTING);
nsapi_error_t err = NSAPI_ERROR_OK;
if (!_is_context_active) {
err = activate_context();
}
if (err) {
call_network_cb(NSAPI_STATUS_DISCONNECTED);
return err;
}
#if NSAPI_PPP_AVAILABLE
_at.lock();
err = open_data_channel();
_at.unlock();
if (err != NSAPI_ERROR_OK) {
tr_error("Failed to open data channel!");
call_network_cb(NSAPI_STATUS_DISCONNECTED);
return err;
}
#else
// additional urc to get better disconnect info for application. Not critical so not returning an error in case of failure
err = _at.set_urc_handler("+CGEV:", callback(this, &AT_CellularNetwork::urc_cgev));
if (err == NSAPI_ERROR_OK) {
_at.lock();
_at.cmd_start("AT+CGEREP=1");
_at.cmd_stop_read_resp();
_at.unlock();
}
call_network_cb(NSAPI_STATUS_GLOBAL_UP);
#endif
return NSAPI_ERROR_OK;
}
nsapi_error_t AT_CellularNetwork::open_data_channel()
{
#if NSAPI_PPP_AVAILABLE
tr_info("Open data channel in PPP mode");
if (is_supported(AT_CGDATA)) {
_at.cmd_start("AT+CGDATA=\"PPP\",");
_at.write_int(_cid);
} else {
MBED_ASSERT(_cid >= 0 && _cid <= 99);
_at.cmd_start("ATD*99***");
_at.use_delimiter(false);
_at.write_int(_cid);
_at.write_string("#", false);
_at.use_delimiter(true);
}
_at.cmd_stop();
_at.resp_start("CONNECT", true);
if (_at.get_last_error()) {
tr_error("Failed to CONNECT");
return _at.get_last_error();
}
_at.set_is_filehandle_usable(false);
/* Initialize PPP
* If blocking: mbed_ppp_init() is a blocking call, it will block until
connected, or timeout after 30 seconds*/
return nsapi_ppp_connect(_at.get_file_handle(), callback(this, &AT_CellularNetwork::ppp_status_cb), NULL, NULL, _ip_stack_type);
#else
return NSAPI_ERROR_OK;
#endif // #if NSAPI_PPP_AVAILABLE
}
/**
* User initiated disconnect
*
* Disconnects from PPP connection only and brings down the underlying network
* interface
*/
nsapi_error_t AT_CellularNetwork::disconnect()
{
#if NSAPI_PPP_AVAILABLE
nsapi_error_t err = nsapi_ppp_disconnect(_at.get_file_handle());
// after ppp disconnect if we wan't to use same at handler we need to set filehandle again to athandler so it
// will set the correct sigio and nonblocking
_at.lock();
_at.set_file_handle(_at.get_file_handle());
_at.set_is_filehandle_usable(true);
_at.unlock();
return err;
#else
_at.lock();
_is_context_active = false;
size_t active_contexts_count = 0;
_at.cmd_start("AT+CGACT?");
_at.cmd_stop();
_at.resp_start("+CGACT:");
while (_at.info_resp()) {
int context_id = _at.read_int();
int context_activation_state = _at.read_int();
if (context_activation_state == 1) {
active_contexts_count++;
if (context_id == _cid) {
_is_context_active = true;
}
}
}
_at.resp_stop();
// 3GPP TS 27.007:
// For EPS, if an attempt is made to disconnect the last PDN connection, then the MT responds with ERROR
if (_is_context_active && (_reg_params._act < RAT_E_UTRAN || active_contexts_count > 1)) {
_at.cmd_start("AT+CGACT=0,");
_at.write_int(_cid);
_at.cmd_stop_read_resp();
}
_at.restore_at_timeout();
_at.remove_urc_handler("+CGEV:");
call_network_cb(NSAPI_STATUS_DISCONNECTED);
return _at.unlock_return_error();
#endif
}
void AT_CellularNetwork::call_network_cb(nsapi_connection_status_t status)
{
if (_connect_status != status) {
@ -490,224 +199,6 @@ nsapi_connection_status_t AT_CellularNetwork::get_connection_status() const
return _connect_status;
}
nsapi_error_t AT_CellularNetwork::set_blocking(bool blocking)
{
#if NSAPI_PPP_AVAILABLE
return nsapi_ppp_set_blocking(blocking);
#else
return NSAPI_ERROR_OK;
#endif
}
#if NSAPI_PPP_AVAILABLE
void AT_CellularNetwork::ppp_status_cb(nsapi_event_t event, intptr_t parameter)
{
_connect_status = (nsapi_connection_status_t)parameter;
if (_connection_status_cb) {
_connection_status_cb(event, parameter);
}
}
#endif
nsapi_error_t AT_CellularNetwork::do_user_authentication()
{
// if user has defined user name and password we need to call CGAUTH before activating or modifying context
if (_pwd && _uname) {
if (!is_supported(AT_CGAUTH)) {
return NSAPI_ERROR_UNSUPPORTED;
}
_at.cmd_start("AT+CGAUTH=");
_at.write_int(_cid);
_at.write_int(_authentication_type);
_at.write_string(_uname);
_at.write_string(_pwd);
_at.cmd_stop_read_resp();
if (_at.get_last_error() != NSAPI_ERROR_OK) {
return NSAPI_ERROR_AUTH_FAILURE;
}
}
return NSAPI_ERROR_OK;
}
bool AT_CellularNetwork::set_new_context(int cid)
{
nsapi_ip_stack_t tmp_stack = _ip_stack_type_requested;
if (tmp_stack == DEFAULT_STACK) {
bool modem_supports_ipv6 = get_modem_stack_type(IPV6_STACK);
bool modem_supports_ipv4 = get_modem_stack_type(IPV4_STACK);
if (modem_supports_ipv6 && modem_supports_ipv4) {
tmp_stack = IPV4V6_STACK;
} else if (modem_supports_ipv6) {
tmp_stack = IPV6_STACK;
} else if (modem_supports_ipv4) {
tmp_stack = IPV4_STACK;
}
}
char pdp_type[8 + 1] = {0};
switch (tmp_stack) {
case IPV4_STACK:
strncpy(pdp_type, "IP", sizeof(pdp_type));
break;
case IPV6_STACK:
strncpy(pdp_type, "IPV6", sizeof(pdp_type));
break;
case IPV4V6_STACK:
strncpy(pdp_type, "IPV6", sizeof(pdp_type)); // try first IPV6 and then fall-back to IPv4
break;
default:
break;
}
//apn: "If the value is null or omitted, then the subscription value will be requested."
bool success = false;
_at.cmd_start("AT+CGDCONT=");
_at.write_int(cid);
_at.write_string(pdp_type);
_at.write_string(_apn);
_at.cmd_stop_read_resp();
success = (_at.get_last_error() == NSAPI_ERROR_OK);
// Fall back to ipv4
if (!success && tmp_stack == IPV4V6_STACK) {
tmp_stack = IPV4_STACK;
_at.clear_error();
_at.cmd_start("AT+FCLASS=0;+CGDCONT=");
_at.write_int(cid);
_at.write_string("IP");
_at.write_string(_apn);
_at.cmd_stop_read_resp();
success = (_at.get_last_error() == NSAPI_ERROR_OK);
}
if (success) {
_ip_stack_type = tmp_stack;
_cid = cid;
_new_context_set = true;
tr_info("New PDP context id %d was created", _cid);
}
return success;
}
bool AT_CellularNetwork::get_context()
{
if (_apn) {
tr_debug("APN in use: %s", _apn);
} else {
tr_debug("NO APN");
}
_at.cmd_start("AT+CGDCONT?");
_at.cmd_stop();
_at.resp_start("+CGDCONT:");
_cid = -1;
int cid_max = 0; // needed when creating new context
char apn[MAX_ACCESSPOINT_NAME_LENGTH];
int apn_len = 0;
bool modem_supports_ipv6 = get_modem_stack_type(IPV6_STACK);
bool modem_supports_ipv4 = get_modem_stack_type(IPV4_STACK);
while (_at.info_resp()) {
int cid = _at.read_int();
if (cid > cid_max) {
cid_max = cid;
}
char pdp_type_from_context[10];
int pdp_type_len = _at.read_string(pdp_type_from_context, sizeof(pdp_type_from_context) - 1);
if (pdp_type_len > 0) {
apn_len = _at.read_string(apn, sizeof(apn) - 1);
if (apn_len >= 0) {
if (_apn && (strcmp(apn, _apn) != 0)) {
continue;
}
nsapi_ip_stack_t pdp_stack = string_to_stack_type(pdp_type_from_context);
// Accept dual PDP context for IPv4/IPv6 only modems
if (pdp_stack != DEFAULT_STACK && (get_modem_stack_type(pdp_stack) || pdp_stack == IPV4V6_STACK)) {
if (_ip_stack_type_requested == IPV4_STACK) {
if (pdp_stack == IPV4_STACK || pdp_stack == IPV4V6_STACK) {
_ip_stack_type = _ip_stack_type_requested;
_cid = cid;
break;
}
} else if (_ip_stack_type_requested == IPV6_STACK) {
if (pdp_stack == IPV6_STACK || pdp_stack == IPV4V6_STACK) {
_ip_stack_type = _ip_stack_type_requested;
_cid = cid;
break;
}
} else {
// requested dual stack or stack is not specified
// If dual PDP need to check for IPV4 or IPV6 modem support. Prefer IPv6.
if (pdp_stack == IPV4V6_STACK) {
if (modem_supports_ipv6) {
_ip_stack_type = IPV6_STACK;
_cid = cid;
break;
} else if (modem_supports_ipv4) {
_ip_stack_type = IPV4_STACK;
_cid = cid;
break;
}
// If PDP is IPV4 or IPV6 they are already checked if supported
} else {
_ip_stack_type = pdp_stack;
_cid = cid;
if (pdp_stack == IPV6_STACK) {
break;
}
if (pdp_stack == IPV4_STACK && !modem_supports_ipv6) {
break;
}
}
}
}
}
}
}
_at.resp_stop();
if (_cid == -1) { // no suitable context was found so create a new one
if (!set_new_context(cid_max + 1)) {
return false;
}
}
// save the apn
if (apn_len > 0 && !_apn) {
_apn = (char *)malloc(apn_len * sizeof(char) + 1);
if (_apn) {
memcpy(_apn, apn, apn_len + 1);
} else {
return false;
}
}
tr_debug("Context id %d", _cid);
return true;
}
nsapi_ip_stack_t AT_CellularNetwork::string_to_stack_type(const char *pdp_type)
{
nsapi_ip_stack_t stack = DEFAULT_STACK;
int len = strlen(pdp_type);
if (len == 6 && memcmp(pdp_type, "IPV4V6", len) == 0) {
stack = IPV4V6_STACK;
} else if (len == 4 && memcmp(pdp_type, "IPV6", len) == 0) {
stack = IPV6_STACK;
} else if (len == 2 && memcmp(pdp_type, "IP", len) == 0) {
stack = IPV4_STACK;
}
return stack;
}
nsapi_error_t AT_CellularNetwork::set_registration_urc(RegistrationType type, bool urc_on)
{
int index = (int)type;
@ -820,7 +311,7 @@ AT_CellularNetwork::RegistrationMode AT_CellularNetwork::has_registration(Regist
return RegistrationModeLAC;
}
nsapi_error_t AT_CellularNetwork::set_attach(int /*timeout*/)
nsapi_error_t AT_CellularNetwork::set_attach()
{
_at.lock();
@ -868,76 +359,6 @@ nsapi_error_t AT_CellularNetwork::detach()
return _at.unlock_return_error();
}
nsapi_error_t AT_CellularNetwork::get_apn_backoff_timer(int &backoff_timer)
{
// If apn is set
if (_apn) {
_at.lock();
_at.cmd_start("AT+CABTRDP=");
_at.write_string(_apn);
_at.cmd_stop();
_at.resp_start("+CABTRDP:");
if (_at.info_resp()) {
_at.skip_param();
backoff_timer = _at.read_int();
}
_at.resp_stop();
return _at.unlock_return_error();
}
return NSAPI_ERROR_PARAMETER;
}
NetworkStack *AT_CellularNetwork::get_stack()
{
#if NSAPI_PPP_AVAILABLE
// use lwIP/PPP if modem does not have IP stack
if (!_stack) {
_stack = nsapi_ppp_get_stack();
}
#endif
return _stack;
}
const char *AT_CellularNetwork::get_ip_address()
{
#if NSAPI_PPP_AVAILABLE
return nsapi_ppp_get_ip_addr(_at.get_file_handle());
#else
if (!_stack) {
_stack = get_stack();
}
if (_stack) {
return _stack->get_ip_address();
}
return NULL;
#endif
}
nsapi_error_t AT_CellularNetwork::set_stack_type(nsapi_ip_stack_t stack_type)
{
if (get_modem_stack_type(stack_type)) {
_ip_stack_type_requested = stack_type;
return NSAPI_ERROR_OK;
} else {
return NSAPI_ERROR_PARAMETER;
}
}
nsapi_ip_stack_t AT_CellularNetwork::get_stack_type()
{
return _ip_stack_type;
}
bool AT_CellularNetwork::get_modem_stack_type(nsapi_ip_stack_t requested_stack)
{
if (requested_stack == _ip_stack_type) {
return true;
} else {
return false;
}
}
nsapi_error_t AT_CellularNetwork::set_access_technology_impl(RadioAccessTechnology opsAct)
{
return NSAPI_ERROR_UNSUPPORTED;
@ -1006,10 +427,11 @@ nsapi_error_t AT_CellularNetwork::scan_plmn(operList_t &operators, int &opsCount
nsapi_error_t AT_CellularNetwork::set_ciot_optimization_config(Supported_UE_Opt supported_opt,
Preferred_UE_Opt preferred_opt)
{
_at.lock();
_at.cmd_start("AT+CCIOTOPT=");
_at.write_int(_cid);
_at.write_int(0); // disable urc
_at.write_int(supported_opt);
_at.write_int(preferred_opt);
_at.cmd_stop_read_resp();
@ -1037,138 +459,6 @@ nsapi_error_t AT_CellularNetwork::get_ciot_optimization_config(Supported_UE_Opt
return _at.unlock_return_error();
}
nsapi_error_t AT_CellularNetwork::get_rate_control(
CellularNetwork::RateControlExceptionReports &reports,
CellularNetwork::RateControlUplinkTimeUnit &timeUnit, int &uplinkRate)
{
_at.lock();
_at.cmd_start("AT+CGAPNRC=");
_at.write_int(_cid);
_at.cmd_stop();
_at.resp_start("+CGAPNRC:");
_at.read_int();
if (_at.get_last_error() == NSAPI_ERROR_OK) {
bool comma_found = true;
int next_element = _at.read_int();
if (next_element >= 0) {
reports = (RateControlExceptionReports)next_element;
tr_debug("reports %d", reports);
next_element = _at.read_int();
} else {
comma_found = false;
}
if (comma_found && next_element >= 0) {
timeUnit = (RateControlUplinkTimeUnit)next_element;
tr_debug("time %d", timeUnit);
next_element = _at.read_int();
} else {
comma_found = false;
}
if (comma_found && next_element >= 0) {
uplinkRate = next_element;
tr_debug("rate %d", uplinkRate);
}
}
_at.resp_stop();
return _at.unlock_return_error();
}
nsapi_error_t AT_CellularNetwork::get_pdpcontext_params(pdpContextList_t &params_list)
{
const int ipv6_subnet_size = 128;
const int max_ipv6_size = 64;
char *ipv6_and_subnetmask = (char *)malloc(ipv6_subnet_size);
if (!ipv6_and_subnetmask) {
return NSAPI_ERROR_NO_MEMORY;
}
char *temp = (char *)malloc(max_ipv6_size);
if (!temp) {
free(ipv6_and_subnetmask);
return NSAPI_ERROR_NO_MEMORY;
}
_at.lock();
_at.cmd_start("AT+CGCONTRDP=");
_at.write_int(_cid);
_at.cmd_stop();
_at.resp_start("+CGCONTRDP:");
pdpcontext_params_t *params = NULL;
while (_at.info_resp()) { // response can be zero or many +CGDCONT lines
params = params_list.add_new();
if (!params) {
tr_warn("Could not allocate new pdpcontext_params_t");
_at.resp_stop();
_at.unlock();
params_list.delete_all();
free(temp);
free(ipv6_and_subnetmask);
return NSAPI_ERROR_NO_MEMORY;
}
params->cid = _at.read_int();
params->bearer_id = _at.read_int();
_at.read_string(params->apn, sizeof(params->apn));
// rest are optional params
ipv6_and_subnetmask[0] = '\0';
temp[0] = '\0';
_at.read_string(ipv6_and_subnetmask, ipv6_subnet_size);
separate_ip_addresses(ipv6_and_subnetmask, params->local_addr, sizeof(params->local_addr), params->local_subnet_mask, sizeof(params->local_subnet_mask));
ipv6_and_subnetmask[0] = '\0';
_at.read_string(ipv6_and_subnetmask, ipv6_subnet_size);
separate_ip_addresses(ipv6_and_subnetmask, params->gateway_addr, sizeof(params->gateway_addr), temp, max_ipv6_size);
prefer_ipv6(params->gateway_addr, sizeof(params->gateway_addr), temp, max_ipv6_size);
ipv6_and_subnetmask[0] = '\0';
temp[0] = '\0';
_at.read_string(ipv6_and_subnetmask, ipv6_subnet_size);
separate_ip_addresses(ipv6_and_subnetmask, params->dns_primary_addr, sizeof(params->dns_primary_addr), temp, max_ipv6_size);
prefer_ipv6(params->dns_primary_addr, sizeof(params->dns_primary_addr), temp, max_ipv6_size);
ipv6_and_subnetmask[0] = '\0';
temp[0] = '\0';
_at.read_string(ipv6_and_subnetmask, ipv6_subnet_size);
separate_ip_addresses(ipv6_and_subnetmask, params->dns_secondary_addr, sizeof(params->dns_secondary_addr), temp, max_ipv6_size);
prefer_ipv6(params->dns_secondary_addr, sizeof(params->dns_secondary_addr), temp, max_ipv6_size);
ipv6_and_subnetmask[0] = '\0';
temp[0] = '\0';
_at.read_string(ipv6_and_subnetmask, ipv6_subnet_size);
separate_ip_addresses(ipv6_and_subnetmask, params->p_cscf_prim_addr, sizeof(params->p_cscf_prim_addr), temp, max_ipv6_size);
prefer_ipv6(params->p_cscf_prim_addr, sizeof(params->p_cscf_prim_addr), temp, max_ipv6_size);
ipv6_and_subnetmask[0] = '\0';
temp[0] = '\0';
_at.read_string(ipv6_and_subnetmask, ipv6_subnet_size);
separate_ip_addresses(ipv6_and_subnetmask, params->p_cscf_sec_addr, sizeof(params->p_cscf_sec_addr), temp, max_ipv6_size);
prefer_ipv6(params->p_cscf_sec_addr, sizeof(params->p_cscf_sec_addr), temp, max_ipv6_size);
params->im_signalling_flag = _at.read_int();
params->lipa_indication = _at.read_int();
params->ipv4_mtu = _at.read_int();
params->wlan_offload = _at.read_int();
params->local_addr_ind = _at.read_int();
params->non_ip_mtu = _at.read_int();
params->serving_plmn_rate_control_value = _at.read_int();
}
_at.resp_stop();
free(temp);
free(ipv6_and_subnetmask);
return _at.unlock_return_error();
}
nsapi_error_t AT_CellularNetwork::get_extended_signal_quality(int &rxlev, int &ber, int &rscp, int &ecno, int &rsrq, int &rsrp)
{
_at.lock();
@ -1276,6 +566,29 @@ nsapi_error_t AT_CellularNetwork::get_operator_names(operator_names_list &op_nam
return _at.unlock_return_error();
}
bool AT_CellularNetwork::is_active_context()
{
_at.lock();
bool active_found = false;
// read active contexts
_at.cmd_start("AT+CGACT?");
_at.cmd_stop();
_at.resp_start("+CGACT:");
while (_at.info_resp()) {
(void)_at.read_int(); // discard context id
if (_at.read_int() == 1) { // check state
tr_debug("Found active context");
active_found = true;
break;
}
}
_at.resp_stop();
_at.unlock();
return active_found;
}
nsapi_error_t AT_CellularNetwork::get_registration_params(registration_params_t &reg_params)
{
reg_params = _reg_params;

View File

@ -20,7 +20,6 @@
#include "CellularNetwork.h"
#include "AT_CellularBase.h"
#include "NetworkStack.h"
namespace mbed {
@ -33,7 +32,7 @@ namespace mbed {
/**
* Class AT_CellularNetwork
*
* Class for connecting to a network and getting information from it.
* Class for attaching to a network and getting information from it.
*/
class AT_CellularNetwork : public CellularNetwork, public AT_CellularBase {
@ -44,52 +43,22 @@ public:
// declare friend so it can access stack
friend class AT_CellularDevice;
public: // NetworkInterface
virtual nsapi_error_t set_credentials(const char *apn,
const char *username = 0, const char *password = 0);
virtual nsapi_error_t set_credentials(const char *apn, AuthenticationType type,
const char *username = 0, const char *password = 0);
virtual nsapi_error_t connect(const char *apn,
const char *username = 0, const char *password = 0);
virtual nsapi_error_t connect();
virtual nsapi_error_t disconnect();
protected:
virtual NetworkStack *get_stack();
public: // CellularNetwork
virtual nsapi_error_t init();
virtual nsapi_error_t activate_context();
virtual nsapi_error_t set_registration(const char *plmn = 0);
virtual nsapi_error_t get_network_registering_mode(NWRegisteringMode &mode);
virtual nsapi_error_t set_attach(int timeout = 10 * 1000);
virtual nsapi_error_t set_attach();
virtual nsapi_error_t get_attach(AttachStatus &status);
virtual nsapi_error_t detach();
virtual nsapi_error_t get_rate_control(CellularNetwork::RateControlExceptionReports &reports,
CellularNetwork::RateControlUplinkTimeUnit &time_unit, int &uplink_rate);
virtual nsapi_error_t get_apn_backoff_timer(int &backoff_timer);
virtual void attach(Callback<void(nsapi_event_t, intptr_t)> status_cb);
virtual nsapi_connection_status_t get_connection_status() const;
virtual nsapi_error_t set_blocking(bool blocking);
virtual const char *get_ip_address();
virtual nsapi_error_t set_access_technology(RadioAccessTechnology rat);
virtual nsapi_error_t scan_plmn(operList_t &operators, int &ops_count);
@ -100,12 +69,6 @@ public: // CellularNetwork
virtual nsapi_error_t get_ciot_optimization_config(Supported_UE_Opt &supported_opt,
Preferred_UE_Opt &preferred_opt);
virtual nsapi_error_t set_stack_type(nsapi_ip_stack_t stack_type);
virtual nsapi_ip_stack_t get_stack_type();
virtual nsapi_error_t get_pdpcontext_params(pdpContextList_t &params_list);
virtual nsapi_error_t get_extended_signal_quality(int &rxlev, int &ber, int &rscp, int &ecno, int &rsrq, int &rsrp);
virtual nsapi_error_t get_signal_quality(int &rssi, int &ber);
@ -118,17 +81,13 @@ public: // CellularNetwork
virtual nsapi_error_t get_operator_names(operator_names_list &op_names);
virtual bool is_active_context();
virtual nsapi_error_t get_registration_params(registration_params_t &reg_params);
virtual nsapi_error_t get_registration_params(RegistrationType type, registration_params_t &reg_params);
protected:
/** Check if modem supports the given stack type.
*
* @return true if supported
*/
virtual bool get_modem_stack_type(nsapi_ip_stack_t requested_stack);
/** Check if modem supports given registration type.
*
* @param reg_type enum RegistrationType
@ -149,13 +108,6 @@ protected:
*/
virtual nsapi_error_t set_access_technology_impl(RadioAccessTechnology op_rat);
/** APN user authentication
*
* @return NSAPI_ERROR_OK on success
* NSAPI_ERROR_UNSUPPORTED on authentication not supported by cellular device
* NSAPI_ERROR_AUTH_FAILURE on authentication to network failed
*/
virtual nsapi_error_t do_user_authentication();
private:
// "NO CARRIER" urc
void urc_no_carrier();
@ -164,19 +116,6 @@ private:
void urc_cgreg();
void urc_cgev();
nsapi_ip_stack_t string_to_stack_type(const char *pdp_type);
void free_credentials();
nsapi_error_t open_data_channel();
bool get_context();
bool set_new_context(int cid);
nsapi_error_t delete_current_context();
// calls network callback only if status was changed, updates local connection status
void call_network_cb(nsapi_connection_status_t status);
void read_reg_params_and_compare(RegistrationType type);
void read_reg_params(registration_params_t &reg_params);
@ -185,27 +124,15 @@ private:
// Returns periodic tau(Table 10.5.163a/3GPP TS 24.008: GPRS Timer 3 information element) in seconds
int calculate_periodic_tau(const char *periodic_tau_string, int periodic_tau_length);
#if NSAPI_PPP_AVAILABLE
void ppp_status_cb(nsapi_event_t, intptr_t);
#endif
// calls network callback only if status was changed, updates local connection status
void call_network_cb(nsapi_connection_status_t status);
protected:
NetworkStack *_stack;
char *_apn;
char *_uname;
char *_pwd;
nsapi_ip_stack_t _ip_stack_type_requested;
nsapi_ip_stack_t _ip_stack_type;
int _cid;
Callback<void(nsapi_event_t, intptr_t)> _connection_status_cb;
RadioAccessTechnology _op_act;
AuthenticationType _authentication_type;
nsapi_connection_status_t _connect_status;
bool _new_context_set;
bool _is_context_active;
registration_params_t _reg_params;
mbed::Callback<void()> _urc_funcs[C_MAX];
};

View File

@ -24,10 +24,12 @@
struct cell_callback_data_t {
nsapi_error_t error; /* possible error code */
int status_data; /* cellular_event_status related enum or other info in int format. Check cellular_event_status comments.*/
bool final_try; /* This flag is true if state machine is used and this was the last try. State machine does goes to idle. */
cell_callback_data_t() {
error = NSAPI_ERROR_OK;
status_data = -1;
final_try = false;
}
};

View File

@ -0,0 +1,34 @@
/*
* Copyright (c) 2018, Arm Limited and affiliates.
* SPDX-License-Identifier: Apache-2.0
*
* 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 "CellularContext.h"
namespace mbed {
#ifdef CELLULAR_DEVICE
MBED_WEAK NetworkInterface *CellularContext::get_default_instance()
{
// Uses default APN, uname, password from mbed_app.json
static CellularDevice *dev = CellularDevice::get_default_instance();
return dev->create_context();
}
#else
MBED_WEAK NetworkInterface *CellularContext::get_default_instance()
{
return NULL;
}
#endif // CELLULAR_DEVICE
} // namespace mbed

View File

@ -16,6 +16,8 @@
*/
#include "CellularDevice.h"
#include "CellularContext.h"
#include "CellularSIM.h"
#include "CellularUtil.h"
#include "CellularLog.h"
#include "CellularTargets.h"
@ -31,7 +33,7 @@ namespace mbed {
#ifdef CELLULAR_DEVICE
MBED_WEAK CellularDevice *CellularDevice::get_default_instance()
{
static events::EventQueue event_queue(4 * EVENTS_EVENT_SIZE);
static events::EventQueue event_queue(5 * EVENTS_EVENT_SIZE);
static CELLULAR_DEVICE device(event_queue);
return &device;
}
@ -42,10 +44,11 @@ MBED_WEAK CellularDevice *CellularDevice::get_default_instance()
}
#endif // CELLULAR_DEVICE
CellularDevice::CellularDevice() : _error(NSAPI_ERROR_OK), _network_ref_count(0), _sms_ref_count(0),
_power_ref_count(0), _sim_ref_count(0), _info_ref_count(0), _is_connected(false),
_state_machine(0), _fh(0)
CellularDevice::CellularDevice() : _network_ref_count(0), _sms_ref_count(0),_power_ref_count(0), _sim_ref_count(0),
_info_ref_count(0), _fh(0), _error(0), _state_machine(0), _nw(0)
{
set_sim_pin(MBED_CONF_NSAPI_DEFAULT_CELLULAR_SIM_PIN);
set_plmn(MBED_CONF_NSAPI_DEFAULT_CELLULAR_PLMN);
}
CellularDevice::~CellularDevice()
@ -59,138 +62,136 @@ void CellularDevice::stop()
_state_machine->stop();
}
bool CellularDevice::is_connected() const
{
return _is_connected;
}
events::EventQueue *CellularDevice::get_queue() const
{
return NULL;
}
nsapi_error_t CellularDevice::set_credentials(const char *apn, const char *uname, const char *pwd)
CellularContext *CellularDevice::get_context_list() const {
return NULL;
}
FileHandle &CellularDevice::get_filehandle() const
{
MBED_ASSERT(_state_machine);
return _state_machine->set_credentials(apn, uname, pwd);
return *_fh;
}
void CellularDevice::set_sim_pin(const char *sim_pin)
{
MBED_ASSERT(_state_machine);
_state_machine->set_sim_pin(sim_pin);
}
nsapi_error_t CellularDevice::init_stm(FileHandle *fh)
{
MBED_ASSERT(!_state_machine);
if (fh == NULL) {
return NSAPI_ERROR_PARAMETER;
if (sim_pin) {
strncpy(_sim_pin, sim_pin, sizeof(_sim_pin));
_sim_pin[sizeof(_sim_pin) - 1] = '\0';
} else {
memset(_sim_pin, 0, sizeof(_sim_pin));
}
_fh = fh;
_state_machine = new CellularStateMachine(*this, *get_queue(), open_power(_fh));
_state_machine->attach(callback(this, &CellularDevice::network_callback));
_state_machine->set_sim(open_sim(_fh));
CellularNetwork *nw = open_network(_fh);
_state_machine->set_network(nw);
nsapi_error_t err = nw->init();
if (err != NSAPI_ERROR_OK) {
delete _state_machine;
_state_machine = NULL;
}
return err;
}
nsapi_error_t CellularDevice::start_dispatch() {
MBED_ASSERT(_state_machine);
return _state_machine->start_dispatch();
}
nsapi_error_t CellularDevice::set_device_ready()
{
return _state_machine->run_to_state(CellularStateMachine::STATE_DEVICE_READY);
}
nsapi_error_t CellularDevice::set_sim_ready()
{
return _state_machine->run_to_state(CellularStateMachine::STATE_SIM_PIN);
}
nsapi_error_t CellularDevice::register_to_network()
{
return _state_machine->run_to_state(CellularStateMachine::STATE_REGISTERING_NETWORK);
}
nsapi_error_t CellularDevice::attach_to_network()
{
return _state_machine->run_to_state(CellularStateMachine::STATE_ATTACHING_NETWORK);
}
nsapi_error_t CellularDevice::activate_context()
{
return _state_machine->run_to_state(CellularStateMachine::STATE_ACTIVATING_PDP_CONTEXT);
}
nsapi_error_t CellularDevice::connect(const char *sim_pin, const char *apn,
const char *uname, const char *pwd)
{
set_sim_pin(sim_pin);
set_credentials(apn, uname, pwd);
return connect();
}
nsapi_error_t CellularDevice::connect()
{
return _state_machine->run_to_state(CellularStateMachine::STATE_CONNECTED);
}
nsapi_error_t CellularDevice::disconnect()
{
MBED_ASSERT(_state_machine);
return _state_machine->disconnect();
}
void CellularDevice::set_plmn(const char* plmn)
{
MBED_ASSERT(_state_machine);
_state_machine->set_plmn(plmn);
if (plmn) {
strncpy(_plmn, plmn, sizeof(_plmn));
_plmn[sizeof(_plmn) - 1] = '\0';
} else {
memset(_plmn, 0, sizeof(_plmn));
}
}
void CellularDevice::set_blocking(bool blocking)
{
MBED_ASSERT(_state_machine);
_state_machine->set_blocking(blocking);
nsapi_error_t CellularDevice::start_dispatch() {
_mutex.lock();
create_state_machine();
nsapi_error_t err = _state_machine->start_dispatch();
_mutex.unlock();
return err;
}
void CellularDevice::attach(mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb)
nsapi_error_t CellularDevice::set_device_ready()
{
_nw_status_cb = status_cb;
return start_state_machine(CellularStateMachine::STATE_DEVICE_READY);
}
void CellularDevice::network_callback(nsapi_event_t ev, intptr_t ptr)
nsapi_error_t CellularDevice::set_sim_ready()
{
if (ev == NSAPI_EVENT_CONNECTION_STATUS_CHANGE) {
if (ptr == NSAPI_STATUS_GLOBAL_UP) {
_is_connected = true;
} else {
_is_connected = false;
}
return start_state_machine(CellularStateMachine::STATE_SIM_PIN);
}
nsapi_error_t CellularDevice::register_to_network()
{
return start_state_machine(CellularStateMachine::STATE_REGISTERING_NETWORK);
}
nsapi_error_t CellularDevice::attach_to_network()
{
return start_state_machine(CellularStateMachine::STATE_ATTACHING_NETWORK);
}
void CellularDevice::create_state_machine()
{
if (!_state_machine) {
_state_machine = new CellularStateMachine(*this, *get_queue());
_state_machine->set_cellular_callback(callback(this, &CellularDevice::cellular_callback));
}
}
nsapi_error_t CellularDevice::start_state_machine(CellularStateMachine::CellularState target_state)
{
_mutex.lock();
create_state_machine();
CellularStateMachine::CellularState current_state, targeted_state;
bool is_running = _state_machine->get_current_status(current_state, targeted_state);
if (current_state >= target_state) { // can stm be in this state but failed?
_mutex.unlock();
return NSAPI_ERROR_ALREADY;
} else if (is_running && targeted_state >= target_state) {
_mutex.unlock();
return NSAPI_ERROR_IN_PROGRESS;
}
nsapi_error_t err = _state_machine->run_to_state(target_state);
_mutex.unlock();
return err;
}
void CellularDevice::cellular_callback(nsapi_event_t ev, intptr_t ptr)
{
if (ev >= NSAPI_EVENT_CELLULAR_STATUS_BASE && ev <= NSAPI_EVENT_CELLULAR_STATUS_END) {
tr_debug("Device: network_callback called with event: %d, err: %d, data: %d", ev, ((cell_callback_data_t*)ptr)->error, ((cell_callback_data_t*)ptr)->status_data);
cell_callback_data_t* ptr_data = (cell_callback_data_t*)ptr;
tr_debug("Device: network_callback called with event: %d, err: %d, data: %d", ev, ptr_data->error, ptr_data->status_data);
cellular_connection_status_t cell_ev = (cellular_connection_status_t)ev;
if (cell_ev == CellularRegistrationStatusChanged && _state_machine) {
// broadcast only network registration changes to state machine
_state_machine->cellular_event_changed(ev, ptr);
}
if (cell_ev == CellularDeviceReady && ptr_data->error == NSAPI_ERROR_OK) {
// Here we can create mux and give new filehandles as mux reserves the one what was in use.
// if mux we would need to set new filehandle:_state_machine->set_filehandle( get fh from mux);
_nw = open_network(_fh);
// Attach to network so we can get update status from the network
_nw->attach(callback(this, &CellularDevice::cellular_callback));
} else if (cell_ev == CellularSIMStatusChanged && ptr_data->error == NSAPI_ERROR_OK &&
ptr_data->status_data == CellularSIM::SimStatePinNeeded) {
if (strlen(_sim_pin)) {
_state_machine->set_sim_pin(_sim_pin);
}
if (strlen(_plmn)) {
_state_machine->set_plmn(_plmn);
}
}
} else {
tr_debug("Device: network_callback called with event: %d, ptr: %d", ev, ptr);
}
// forward network callback to application is it has registered with attach
if (_nw_status_cb) {
_nw_status_cb(ev, ptr);
// broadcast network and cellular changes to state machine and CellularContext.
CellularContext *curr = get_context_list();
while (curr) {
curr->cellular_callback(ev, ptr);
curr = curr->_next;
}
}
} // namespae mbed
} // namespace mbed

View File

@ -17,10 +17,9 @@
#include "CellularStateMachine.h"
#include "CellularDevice.h"
#include "CellularLog.h"
#include "CellularUtil.h"
#include "CellularPower.h"
#include "CellularSIM.h"
#include "CellularLog.h"
#include "Thread.h"
#include "UARTSerial.h"
@ -42,14 +41,13 @@
namespace mbed {
CellularStateMachine::CellularStateMachine(CellularDevice &device, events::EventQueue &queue, CellularPower *power) :
CellularStateMachine::CellularStateMachine(CellularDevice &device, events::EventQueue &queue) :
_cellularDevice(device), _state(STATE_INIT), _next_state(_state), _target_state(_state),
_event_status_cb(0), _network(0), _power(power), _sim(0), _queue(queue), _queue_thread(0), _retry_count(0),
_event_timeout(-1), _event_id(0), _plmn(0), _command_success(false), _plmn_network_found(false), _cb_data(),
_current_event(NSAPI_EVENT_CONNECTION_STATUS_CHANGE), _automatic_reconnect(true), _blocking(true),
_stm_semaphore(0)
_event_status_cb(0), _network(0), _power(0), _sim(0), _queue(queue), _queue_thread(0), _sim_pin(0),
_retry_count(0), _event_timeout(-1), _event_id(-1), _plmn(0), _command_success(false),
_plmn_network_found(false), _is_retry(false), _cb_data(), _current_event(NSAPI_EVENT_CONNECTION_STATUS_CHANGE),
_active_context(false)
{
memset(_sim_pin, 0, sizeof(_sim_pin));
#if MBED_CONF_CELLULAR_RANDOM_MAX_START_DELAY == 0
_start_time = 0;
#else
@ -92,6 +90,9 @@ void CellularStateMachine::stop()
_target_state = _state;
_cb_data.error = NSAPI_ERROR_OK;
_cb_data.status_data = -1;
_cb_data.final_try = false;
_event_id = -1;
_is_retry = false;
if (_power) {
_cellularDevice.close_power();
@ -109,52 +110,11 @@ void CellularStateMachine::stop()
}
}
void CellularStateMachine::set_blocking(bool blocking)
{
_blocking = blocking;
}
void CellularStateMachine::set_automatic_reconnect(bool do_reconnect)
{
_automatic_reconnect = do_reconnect;
}
events::EventQueue *CellularStateMachine::get_queue() const
{
return &_queue;
}
nsapi_error_t CellularStateMachine::set_credentials(const char *apn, const char *uname, const char *pwd)
{
return _network->set_credentials(apn, uname, pwd);
}
void CellularStateMachine::set_sim(CellularSIM* sim)
{
if (_sim) {
// we own this so we'll close it before accepting new one
_cellularDevice.close_sim();
}
_sim = sim;
}
void CellularStateMachine::set_network(CellularNetwork* nw)
{
if (_network) {
_cellularDevice.close_network();
}
_network = nw;
_network->attach(callback(this, &CellularStateMachine::network_callback));
}
void CellularStateMachine::set_power(CellularPower* pwr)
{
if (_power) {
_cellularDevice.close_power();
}
_power = pwr;
}
bool CellularStateMachine::power_on()
{
_cb_data.error = _power->on();
@ -171,8 +131,7 @@ bool CellularStateMachine::power_on()
void CellularStateMachine::set_sim_pin(const char *sim_pin)
{
strncpy(_sim_pin, sim_pin, sizeof(_sim_pin));
_sim_pin[sizeof(_sim_pin) - 1] = '\0';
_sim_pin = sim_pin;
}
void CellularStateMachine::set_plmn(const char *plmn)
@ -182,16 +141,17 @@ void CellularStateMachine::set_plmn(const char *plmn)
bool CellularStateMachine::open_sim()
{
if (!_sim) {
// can only fail with allocation with new and then it's critical error
_sim = _cellularDevice.open_sim();
}
CellularSIM::SimState state = CellularSIM::SimStateUnknown;
// wait until SIM is readable
// here you could add wait(secs) if you know start delay of your SIM
_cb_data.error = _sim->get_sim_state(state);
if (_cb_data.error != NSAPI_ERROR_OK) {
tr_info("Waiting for SIM (err while reading)...");
if (_event_status_cb) {
_cb_data.status_data = state;
_event_status_cb((nsapi_event_t)CellularSIMStatusChanged, (intptr_t )&_cb_data);
}
return false;
}
@ -233,7 +193,7 @@ bool CellularStateMachine::is_registered()
}
}
return is_registered;
return is_registered || _active_context;
}
bool CellularStateMachine::get_network_registration(CellularNetwork::RegistrationType type,
@ -241,28 +201,31 @@ bool CellularStateMachine::get_network_registration(CellularNetwork::Registratio
{
is_registered = false;
bool is_roaming = false;
_cb_data.error = _network->get_registration_status(type, status);
CellularNetwork::registration_params_t reg_params;
_cb_data.error = _network->get_registration_params(type, reg_params);
if (_cb_data.error != NSAPI_ERROR_OK) {
if (_cb_data.error != NSAPI_ERROR_UNSUPPORTED) {
tr_warn("Get network registration failed (type %d)!", type);
}
return false;
}
status = reg_params._status;
switch (status) {
case CellularNetwork::RegisteredRoaming:
is_roaming = true;
is_roaming = true;// @suppress("No break at end of case")
// fall-through
case CellularNetwork::RegisteredHomeNetwork:
is_registered = true;
break;
case CellularNetwork::RegisteredSMSOnlyRoaming:
is_roaming = true;
is_roaming = true;// @suppress("No break at end of case")
// fall-through
case CellularNetwork::RegisteredSMSOnlyHome:
tr_warn("SMS only network registration!");
break;
case CellularNetwork::RegisteredCSFBNotPreferredRoaming:
is_roaming = true;
is_roaming = true; // @suppress("No break at end of case")
// fall-through
case CellularNetwork::RegisteredCSFBNotPreferredHome:
tr_warn("Not preferred network registration!");
@ -289,20 +252,19 @@ void CellularStateMachine::report_failure(const char *msg)
{
tr_error("Cellular stm failed with: %s", msg);
_event_id = -1;
if (_event_status_cb) {
_cb_data.final_try = true;
_event_status_cb(_current_event, (intptr_t )&_cb_data);
}
tr_error("Target state %s was not reached. Returning from state: %s", get_state_string(_target_state), get_state_string(_state));
if (_blocking) {
_stm_semaphore.release();
}
}
const char *CellularStateMachine::get_state_string(CellularState state) const
{
#if MBED_CONF_MBED_TRACE_ENABLE
static const char *strings[STATE_MAX_FSM_STATE] = { "Init", "Power", "Device ready", "SIM pin", "Registering network", "Manual registering", "Attaching network", "Activating PDP Context", "Connecting network", "Connected", "Disconnecting"};
static const char *strings[STATE_MAX_FSM_STATE] = { "Init", "Power", "Device ready", "SIM pin", "Registering network", "Manual registering", "Attaching network"};
return strings[state];
#else
return NULL;
@ -357,46 +319,6 @@ bool CellularStateMachine::is_registered_to_plmn()
return false;
}
void CellularStateMachine::continue_from_state(CellularState state)
{
tr_info("Continue state from %s to %s", get_state_string((CellularStateMachine::CellularState)_state),
get_state_string((CellularStateMachine::CellularState)state));
_state = state;
enter_to_state(state);
_event_id = _queue.call_in(0, callback(this, &CellularStateMachine::event));
if (!_event_id) {
_cb_data.error = NSAPI_ERROR_NO_MEMORY;
report_failure("Failed to call queue.");
stop();
}
}
nsapi_error_t CellularStateMachine::run_to_state(CellularStateMachine::CellularState state)
{
// update next state so that we don't continue from previous state if state machine was paused and then started again.
_state = _next_state;
_target_state = state;
enter_to_state(_next_state);
_event_id = _queue.call_in(0, callback(this, &CellularStateMachine::event));
if (!_event_id) {
stop();
return NSAPI_ERROR_NO_MEMORY;
}
if (_blocking) {
// TODO, should we adjust semaphore wait time according to state we are trying to achieve?
int ret_wait = _stm_semaphore.wait(10 * 60 * 1000); // cellular network searching may take several minutes
if (ret_wait != 1) {
tr_info("No cellular connection");
return NSAPI_ERROR_NO_CONNECTION;
}
}
return _cb_data.error;
}
void CellularStateMachine::enter_to_state(CellularState state)
{
_next_state = state;
@ -404,6 +326,7 @@ void CellularStateMachine::enter_to_state(CellularState state)
_command_success = false;
_cb_data.error = NSAPI_ERROR_OK;
_cb_data.status_data = -1;
_cb_data.final_try = false;
}
void CellularStateMachine::retry_state_or_fail()
@ -411,6 +334,7 @@ void CellularStateMachine::retry_state_or_fail()
if (++_retry_count < RETRY_ARRAY_SIZE) {
tr_debug("Retry State %s, retry %d/%d", get_state_string(_state), _retry_count, RETRY_ARRAY_SIZE);
_event_timeout = _retry_timeout_array[_retry_count];
_is_retry = true;
} else {
report_failure(get_state_string(_state));
return;
@ -422,6 +346,9 @@ void CellularStateMachine::state_init()
// we should check that if power is already on then we can jump to device ready state
_cellularDevice.set_timeout(TIMEOUT_POWER_ON);
tr_info("Cellular state init (timeout %d ms)", TIMEOUT_POWER_ON);
if (!_power) {
_power = _cellularDevice.open_power();
}
_cb_data.error = _power->is_device_ready();
if (_cb_data.error != NSAPI_ERROR_OK) {
_event_timeout = _start_time;
@ -465,7 +392,7 @@ void CellularStateMachine::state_device_ready()
enter_to_state(STATE_SIM_PIN);
} else {
if (_retry_count == 0) {
(void)_power->set_device_ready_urc_cb(mbed::callback(this, &CellularStateMachine::ready_urc_cb));
_power->set_device_ready_urc_cb(mbed::callback(this, &CellularStateMachine::ready_urc_cb));
}
retry_state_or_fail();
}
@ -476,6 +403,10 @@ void CellularStateMachine::state_sim_pin()
_cellularDevice.set_timeout(TIMEOUT_SIM_PIN);
tr_info("Sim state (timeout %d ms)", TIMEOUT_SIM_PIN);
if (open_sim()) {
if (!_network) {
_network = _cellularDevice.open_network();
}
bool success = false;
for (int type = 0; type < CellularNetwork::C_MAX; type++) {
_cb_data.error = _network->set_registration_urc((CellularNetwork::RegistrationType)type, true);
@ -488,6 +419,9 @@ void CellularStateMachine::state_sim_pin()
retry_state_or_fail();
return;
}
_active_context = false;
_active_context = _network->is_active_context(); // check if context was already activated
if (_plmn) {
enter_to_state(STATE_MANUAL_REGISTERING_NETWORK);
} else {
@ -537,6 +471,7 @@ void CellularStateMachine::state_attaching()
{
_cellularDevice.set_timeout(TIMEOUT_CONNECT);
_cb_data.error = _network->set_attach();
tr_info("CellularStateMachine::state_attaching(): %d", _cb_data.error);
if (_cb_data.error == NSAPI_ERROR_OK) {
_cellularDevice.close_sim();
_sim = NULL;
@ -544,45 +479,86 @@ void CellularStateMachine::state_attaching()
_cb_data.status_data = CellularNetwork::Attached;
_event_status_cb(_current_event, (intptr_t )&_cb_data);
}
enter_to_state(STATE_ACTIVATING_PDP_CONTEXT);
} else {
retry_state_or_fail();
}
}
void CellularStateMachine::state_activating_pdp_context()
void CellularStateMachine::continue_from_state(CellularState state)
{
_cellularDevice.set_timeout(TIMEOUT_CONNECT);
tr_info("Activate PDP Context (timeout %d ms)", TIMEOUT_CONNECT);
_cb_data.error = _network->activate_context();
if (_cb_data.error == NSAPI_ERROR_OK) {
if (_event_status_cb) {
_event_status_cb(_current_event, (intptr_t )&_cb_data);
_mutex.lock();
tr_info("Continue state from %s to %s", get_state_string((CellularStateMachine::CellularState)_state),
get_state_string((CellularStateMachine::CellularState)state));
_state = state;
enter_to_state(state);
_event_id = _queue.call_in(0, this, &CellularStateMachine::event);
if (!_event_id) {
_event_id = -1;
_cb_data.error = NSAPI_ERROR_NO_MEMORY;
report_failure("Failed to call queue.");
stop();
}
_mutex.unlock();
}
nsapi_error_t CellularStateMachine::run_to_state(CellularStateMachine::CellularState state)
{
_mutex.lock();
// call pre_event via queue so that it's in same thread and it's safe to decisions
int id = _queue.call_in(0, this, &CellularStateMachine::pre_event, state);
if (!id) {
stop();
_mutex.unlock();
return NSAPI_ERROR_NO_MEMORY;
}
_mutex.unlock();
return NSAPI_ERROR_OK;
}
void CellularStateMachine::pre_event(CellularState state)
{
tr_debug("CellularStateMachine::pre_event, state: %s, _target_state: %s, _event_id: %d", get_state_string(state), get_state_string(_target_state), _event_id);
if (_target_state < state) {
// new wanted state will not be achieved with current _target_state so update it
_target_state = state;
} else {
// wanted state is already / will be achieved, return without launching new event
return;
}
// if _event_id is -1 it means that new event is not going to be launched so we must launch new event
if (_event_id == -1) {
if (!_cb_data.final_try) {
// update next state so that we don't continue from previous state if state machine was paused and then started again.
// but only if earlier try did not finish to failure, then we must continue from that state
_state = _next_state;
}
enter_to_state(_next_state);
_event_id = _queue.call_in(0, this, &CellularStateMachine::event);
if (!_event_id) {
_event_id = -1;
report_failure("Failed to call queue.");
stop();
}
enter_to_state(STATE_CONNECTING_NETWORK);
} else {
retry_state_or_fail();
}
}
void CellularStateMachine::state_connect_to_network()
bool CellularStateMachine::get_current_status(CellularStateMachine::CellularState &current_state, CellularStateMachine::CellularState &target_state)
{
_cellularDevice.set_timeout(TIMEOUT_CONNECT);
tr_info("Connect to cellular network (timeout %d ms)", TIMEOUT_CONNECT);
_cb_data.error = _network->connect();
if (_cb_data.error == NSAPI_ERROR_OK) {
_cellularDevice.set_timeout(TIMEOUT_NETWORK);
tr_debug("Connected to cellular network, set at timeout (timeout %d ms)", TIMEOUT_NETWORK);
// when using modems stack connect is synchronous
enter_to_state(STATE_CONNECTED);
} else {
retry_state_or_fail();
}
bool is_running;
_mutex.lock();
current_state = _state;
target_state = _target_state;
is_running = _event_id != -1;
_mutex.unlock();
return is_running;
}
void CellularStateMachine::event()
{
tr_debug("CellularStateMachine::event(): %s", get_state_string(_state));
_event_timeout = -1;
_is_retry = false;
switch (_state) {
case STATE_INIT:
_current_event = (nsapi_event_t)CellularDeviceReady;
@ -612,26 +588,14 @@ void CellularStateMachine::event()
_current_event = (nsapi_event_t)CellularAttachNetwork;
state_attaching();
break;
case STATE_ACTIVATING_PDP_CONTEXT:
_current_event = (nsapi_event_t)CellularActivatePDPContext;
state_activating_pdp_context();
break;
case STATE_CONNECTING_NETWORK:
_current_event = NSAPI_EVENT_CONNECTION_STATUS_CHANGE;
state_connect_to_network();
break;
case STATE_CONNECTED:
_current_event = NSAPI_EVENT_CONNECTION_STATUS_CHANGE;
break;
case STATE_DISCONNECTING:
default:
MBED_ASSERT(0);
break;
}
if (_blocking && _target_state == _state && _cb_data.error == NSAPI_ERROR_OK) {
if (_target_state == _state && _cb_data.error == NSAPI_ERROR_OK && !_is_retry) {
tr_info("Target state reached: %s", get_state_string(_target_state));
_stm_semaphore.release();
_event_id = -1;
return;
}
@ -660,10 +624,6 @@ nsapi_error_t CellularStateMachine::start_dispatch()
MBED_ASSERT(!_queue_thread);
_queue_thread = new rtos::Thread(osPriorityNormal, 2048);
if (!_queue_thread) {
stop();
return NSAPI_ERROR_NO_MEMORY;
}
if (_queue_thread->start(callback(&_queue, &events::EventQueue::dispatch_forever)) != osOK) {
stop();
return NSAPI_ERROR_NO_MEMORY;
@ -672,35 +632,24 @@ nsapi_error_t CellularStateMachine::start_dispatch()
return NSAPI_ERROR_OK;
}
void CellularStateMachine::attach(mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb)
void CellularStateMachine::set_cellular_callback(mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb)
{
_event_status_cb = status_cb;
}
nsapi_error_t CellularStateMachine::disconnect()
{
nsapi_error_t err = NSAPI_ERROR_OK;
if (_network) {
// set state to disconnecting
_state = STATE_DISCONNECTING;
err = _network->disconnect();
}
return err;
}
void CellularStateMachine::network_callback(nsapi_event_t ev, intptr_t ptr)
void CellularStateMachine::cellular_event_changed(nsapi_event_t ev, intptr_t ptr)
{
cell_callback_data_t *data = (cell_callback_data_t*)ptr;
if (ev >= NSAPI_EVENT_CELLULAR_STATUS_BASE && ev <= NSAPI_EVENT_CELLULAR_STATUS_END) {
tr_debug("FSM: network_callback called with event: %d, err: %d, data: %d _state: %s", ev, data->error, data->status_data, get_state_string(_state));
tr_debug("FSM: cellular_event_changed called with event: %d, err: %d, data: %d _state: %s", ev, data->error, data->status_data, get_state_string(_state));
} else {
tr_debug("FSM: network_callback called with event: %d, ptr: %d _state: %s", ev, ptr, get_state_string(_state));
tr_debug("FSM: cellular_event_changed called with event: %d, ptr: %d _state: %s", ev, ptr, get_state_string(_state));
}
if ((cellular_connection_status_t)ev == CellularRegistrationStatusChanged &&
(_state == STATE_REGISTERING_NETWORK || _state == STATE_MANUAL_REGISTERING_NETWORK)) {
// expect packet data so only these states are valid
if (data->status_data == CellularNetwork::RegisteredHomeNetwork || data->status_data == CellularNetwork::RegisteredRoaming) {
if ((data->status_data == CellularNetwork::RegisteredHomeNetwork || data->status_data == CellularNetwork::RegisteredRoaming) && data->error == NSAPI_ERROR_OK) {
if (_plmn) {
if (is_registered_to_plmn()) {
if (!_plmn_network_found) {
@ -715,30 +664,6 @@ void CellularStateMachine::network_callback(nsapi_event_t ev, intptr_t ptr)
}
}
}
if (_event_status_cb) {
_event_status_cb(ev, ptr);
}
// try to reconnect if we think that we are connected, automatic reconnection is on and we get event disconnected
if (_automatic_reconnect && ev == NSAPI_EVENT_CONNECTION_STATUS_CHANGE && ptr == NSAPI_STATUS_DISCONNECTED &&
_state == STATE_CONNECTED) {
tr_info("FSM: start automatic reconnect!");
// call disconnect to set filehandle irq back to us, don't really care about return value.
(void)_network->disconnect();
// start from registering phase as we might have been deregistered if there is no network
if (_plmn) {
continue_from_state(STATE_MANUAL_REGISTERING_NETWORK);
} else {
continue_from_state(STATE_REGISTERING_NETWORK);
}
if (_event_status_cb) {
_event_status_cb(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, NSAPI_STATUS_RECONNECTING);
}
}
}
void CellularStateMachine::ready_urc_cb()

View File

@ -20,7 +20,7 @@
#include "EventQueue.h"
#include "CellularNetwork.h"
#include "CellularCommon.h"
#include "Semaphore.h"
#include "PlatformMutex.h"
namespace rtos {
class Thread;
@ -28,33 +28,28 @@ namespace rtos {
namespace mbed {
class UARTSerial;
class CellularPower;
class CellularSIM;
class CellularDevice;
const int MAX_PIN_SIZE = 8;
const int RETRY_ARRAY_SIZE = 10;
/** CellularStateMachine class
*
* Finite State Machine for connecting to cellular network.
* By default automatic reconnecting is on. This means that when FSM gets the disconnected callback
* it will try to connect automatically. Application can toggle this behavior with method set_automatic_reconnect(...)
* Finite State Machine for attaching to cellular network. Used by CellularDevice.
*/
class CellularStateMachine {
public:
private:
// friend of CellularDevice so that it's the only way to close/delete this class.
friend class CellularDevice;
/** Constructor
*
* @param device reference to CellularDevice
* @param queue reference to queue used in state transitions
* @param power power needed in first state. Can be also given with set_power but must be given before
* calling run_to_state. Transfers ownership to this class.
*/
CellularStateMachine(CellularDevice &device, events::EventQueue &queue, CellularPower *power);
CellularStateMachine(CellularDevice &device, events::EventQueue &queue);
~CellularStateMachine();
public:
/** Cellular connection states
*/
enum CellularState {
@ -65,60 +60,17 @@ public:
STATE_REGISTERING_NETWORK,
STATE_MANUAL_REGISTERING_NETWORK,
STATE_ATTACHING_NETWORK,
STATE_ACTIVATING_PDP_CONTEXT,
STATE_CONNECTING_NETWORK,
STATE_CONNECTED,
STATE_DISCONNECTING,
STATE_MAX_FSM_STATE
};
public:
/** Set the SIM interface. Transfers ownership to this class.
/** Register cellular specific for status changes
*
* @param sim sim interface to be used to access sim services
*/
void set_sim(CellularSIM* sim);
/** Set the network interface. Transfers ownership to this class.
*
* @param nw network interface to be used for network services
*/
void set_network(CellularNetwork* nw);
/** Set the power interface. Transfers ownership to this class.
*
* @param pwr power interface for power handling
*/
void set_power(CellularPower* pwr);
/** By default run_to_state is synchronous. This method can toggle between sync/async.
*
*/
void set_blocking(bool blocking);
/** Disconnects from the cellular network.
*
* @return NSAPI_ERROR_OK on success, negative code in case of failure
*/
nsapi_error_t disconnect();
/** By default automatic reconnecting is on. This means that when FSM gets the disconnected callback
* it will try to connect automatically. By this method application can toggle this behavior.
*
* @param do_reconnect true for automatic reconnect, false to not reconnect automatically
*/
void set_automatic_reconnect(bool do_reconnect);
/** Register callback for status reporting
*
* The specified status callback function will be called on status changes
* on the network. The parameters on the callback are the event type and
* event-type dependent reason parameter.
* The specified status callback function will be called on device status changes.
* The parameters on the callback are the event type and event-type dependent reason parameter.
*
* @param status_cb The callback for status changes
*/
void attach(mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb);
void set_cellular_callback(mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb);
/** Start event queue dispatching
* @return see nsapi_error_t, 0 on success
@ -135,16 +87,6 @@ public:
*/
nsapi_error_t run_to_state(CellularState state);
/** Set the Cellular network credentials
*
* Please check documentation of connect() for default behaviour of APN settings.
*
* @param apn Access point name
* @param uname optionally, Username
* @param pwd optionally, password
*/
nsapi_error_t set_credentials(const char *apn, const char *uname = 0, const char *pwd = 0);
/** Set cellular device SIM PIN code
* @param sim_pin PIN code
*/
@ -176,6 +118,23 @@ public:
* @return event queue
*/
events::EventQueue *get_queue() const;
/** Get the current status of the state machine. Thread safe.
*
* @param current_state
* @param target_state
* @return true if state machine is running, false is not
*
*/
bool get_current_status(CellularStateMachine::CellularState &current_state, CellularStateMachine::CellularState &target_state);
/** CellularDevice updates about network events and cellular events
*
* @param ev Event type
* @param ptr Event type specific data
*/
void cellular_event_changed(nsapi_event_t ev, intptr_t ptr);
private:
bool power_on();
bool open_sim();
@ -191,18 +150,14 @@ private:
void state_registering();
void state_manual_registering_network();
void state_attaching();
void state_activating_pdp_context();
void state_connect_to_network();
void enter_to_state(CellularState state);
void retry_state_or_fail();
void network_callback(nsapi_event_t ev, intptr_t ptr);
void continue_from_state(CellularState state);
bool is_registered_to_plmn();
private:
void report_failure(const char *msg);
void event();
void ready_urc_cb();
void pre_event(CellularState state);
CellularDevice &_cellularDevice;
CellularState _state;
@ -217,7 +172,7 @@ private:
events::EventQueue &_queue;
rtos::Thread *_queue_thread;
char _sim_pin[MAX_PIN_SIZE + 1];
const char *_sim_pin;
int _retry_count;
int _start_time;
int _event_timeout;
@ -228,11 +183,11 @@ private:
const char *_plmn;
bool _command_success;
bool _plmn_network_found;
bool _is_retry;
cell_callback_data_t _cb_data;
nsapi_event_t _current_event;
bool _automatic_reconnect;
bool _blocking;
rtos::Semaphore _stm_semaphore;
bool _active_context; // Is there any active context?
PlatformMutex _mutex;
};
} // namespace

View File

@ -17,10 +17,12 @@
#include "GEMALTO_CINTERION_CellularNetwork.h"
#include "GEMALTO_CINTERION_Module.h"
#include "AT_CellularInformation.h"
#include "GEMALTO_CINTERION_CellularContext.h"
#include "GEMALTO_CINTERION.h"
#include "AT_CellularInformation.h"
#include "CellularLog.h"
using namespace mbed;
using namespace events;
@ -39,6 +41,11 @@ AT_CellularNetwork *GEMALTO_CINTERION::open_network_impl(ATHandler &at)
return new GEMALTO_CINTERION_CellularNetwork(at);
}
AT_CellularContext *GEMALTO_CINTERION::create_context_impl(ATHandler &at, const char *apn, nsapi_ip_stack_t stack)
{
return new GEMALTO_CINTERION_CellularContext(at, this, apn, stack);
}
nsapi_error_t GEMALTO_CINTERION::init_module(FileHandle *fh)
{
CellularInformation *information = open_information(fh);

View File

@ -30,8 +30,8 @@ public:
protected: // AT_CellularDevice
virtual AT_CellularNetwork *open_network_impl(ATHandler &at);
public: // CellularDevice
virtual AT_CellularContext *create_context_impl(ATHandler &at, const char *apn, nsapi_ip_stack_t stack);
public:
virtual nsapi_error_t init_module(FileHandle *fh);
virtual uint16_t get_send_delay();
};

View File

@ -0,0 +1,54 @@
/*
* Copyright (c) 2018, Arm Limited and affiliates.
* SPDX-License-Identifier: Apache-2.0
*
* 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 "GEMALTO_CINTERION_CellularContext.h"
#include "GEMALTO_CINTERION_CellularStack.h"
#include "GEMALTO_CINTERION_Module.h"
namespace mbed {
GEMALTO_CINTERION_CellularContext::GEMALTO_CINTERION_CellularContext(ATHandler &at, CellularDevice *device,
const char *apn, nsapi_ip_stack_t stack) : AT_CellularContext(at, device, apn, stack)
{
}
GEMALTO_CINTERION_CellularContext::~GEMALTO_CINTERION_CellularContext()
{
}
#if !NSAPI_PPP_AVAILABLE
NetworkStack *GEMALTO_CINTERION_CellularContext::get_stack()
{
if (!_stack) {
_stack = new GEMALTO_CINTERION_CellularStack(_at, _apn, _cid, _ip_stack_type);
}
return _stack;
}
#endif // NSAPI_PPP_AVAILABLE
bool GEMALTO_CINTERION_CellularContext::stack_type_supported(nsapi_ip_stack_t requested_stack)
{
#if NSAPI_PPP_AVAILABLE
return (requested_stack == IPV4_STACK || requested_stack == IPV6_STACK);
#else
if (GEMALTO_CINTERION_Module::get_model() == GEMALTO_CINTERION_Module::ModelBGS2) {
return (requested_stack == IPV4_STACK);
}
return (requested_stack == IPV4_STACK || requested_stack == IPV6_STACK);
#endif
}
} /* namespace mbed */

View File

@ -0,0 +1,38 @@
/*
* Copyright (c) 2018, Arm Limited and affiliates.
* SPDX-License-Identifier: Apache-2.0
*
* 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.
*/
#ifndef GEMALTO_CINTERION_CELLULARCONTEXT_H_
#define GEMALTO_CINTERION_CELLULARCONTEXT_H_
#include "AT_CellularContext.h"
namespace mbed {
class GEMALTO_CINTERION_CellularContext: public AT_CellularContext {
public:
GEMALTO_CINTERION_CellularContext(ATHandler &at, CellularDevice *device, const char *apn, nsapi_ip_stack_t stack);
virtual ~GEMALTO_CINTERION_CellularContext();
protected:
#if !NSAPI_PPP_AVAILABLE
virtual NetworkStack *get_stack();
#endif // NSAPI_PPP_AVAILABLE
virtual bool stack_type_supported(nsapi_ip_stack_t requested_stack);
};
} /* namespace mbed */
#endif // GEMALTO_CINTERION_CELLULARCONTEXT_H_

View File

@ -16,7 +16,6 @@
*/
#include "GEMALTO_CINTERION_CellularNetwork.h"
#include "GEMALTO_CINTERION_CellularStack.h"
#include "GEMALTO_CINTERION_Module.h"
using namespace mbed;
@ -29,24 +28,6 @@ GEMALTO_CINTERION_CellularNetwork::~GEMALTO_CINTERION_CellularNetwork()
{
}
#if !NSAPI_PPP_AVAILABLE
NetworkStack *GEMALTO_CINTERION_CellularNetwork::get_stack()
{
if (!_stack) {
_stack = new GEMALTO_CINTERION_CellularStack(_at, _apn, _cid, _ip_stack_type);
}
return _stack;
}
#endif // NSAPI_PPP_AVAILABLE
bool GEMALTO_CINTERION_CellularNetwork::get_modem_stack_type(nsapi_ip_stack_t requested_stack)
{
if (GEMALTO_CINTERION_Module::get_model() == GEMALTO_CINTERION_Module::ModelBGS2) {
return (requested_stack == IPV4_STACK);
}
return (requested_stack == IPV4_STACK || requested_stack == IPV6_STACK);
}
AT_CellularNetwork::RegistrationMode GEMALTO_CINTERION_CellularNetwork::has_registration(RegistrationType reg_type)
{
if (GEMALTO_CINTERION_Module::get_model() == GEMALTO_CINTERION_Module::ModelEMS31) {

View File

@ -28,14 +28,7 @@ public:
virtual ~GEMALTO_CINTERION_CellularNetwork();
protected:
#if !NSAPI_PPP_AVAILABLE
virtual NetworkStack *get_stack();
#endif // NSAPI_PPP_AVAILABLE
virtual RegistrationMode has_registration(RegistrationType reg_type);
virtual bool get_modem_stack_type(nsapi_ip_stack_t requested_stack);
virtual nsapi_error_t set_access_technology_impl(RadioAccessTechnology opsAct);
};

View File

@ -18,7 +18,7 @@
#include "QUECTEL_BC95_CellularNetwork.h"
#include "QUECTEL_BC95_CellularPower.h"
#include "QUECTEL_BC95_CellularSIM.h"
#include "QUECTEL_BC95_CellularContext.h"
#include "QUECTEL_BC95.h"
#define CONNECT_DELIM "\r\n"
@ -59,3 +59,8 @@ AT_CellularSIM *QUECTEL_BC95::open_sim_impl(ATHandler &at)
{
return new QUECTEL_BC95_CellularSIM(at);
}
AT_CellularContext *QUECTEL_BC95::create_context_impl(ATHandler &at, const char *apn, nsapi_ip_stack_t stack)
{
return new QUECTEL_BC95_CellularContext(at, this, apn, stack);
}

View File

@ -31,6 +31,7 @@ protected: // AT_CellularDevice
virtual AT_CellularNetwork *open_network_impl(ATHandler &at);
virtual AT_CellularPower *open_power_impl(ATHandler &at);
virtual AT_CellularSIM *open_sim_impl(ATHandler &at);
virtual AT_CellularContext *create_context_impl(ATHandler &at, const char *apn, nsapi_ip_stack_t stack);
public: // NetworkInterface
void handle_urc(FileHandle *fh);

View File

@ -0,0 +1,44 @@
/*
* Copyright (c) 2018, Arm Limited and affiliates.
* SPDX-License-Identifier: Apache-2.0
*
* 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 "QUECTEL_BC95_CellularContext.h"
#include "QUECTEL_BC95_CellularStack.h"
namespace mbed {
QUECTEL_BC95_CellularContext::QUECTEL_BC95_CellularContext(ATHandler &at, CellularDevice *device, const char *apn,
nsapi_ip_stack_t stack) : AT_CellularContext(at, device, apn, stack)
{
}
QUECTEL_BC95_CellularContext::~QUECTEL_BC95_CellularContext()
{
}
NetworkStack *QUECTEL_BC95_CellularContext::get_stack()
{
if (!_stack) {
_stack = new QUECTEL_BC95_CellularStack(_at, _cid, _ip_stack_type);
}
return _stack;
}
bool QUECTEL_BC95_CellularContext::get_modem_stack_type(nsapi_ip_stack_t requested_stack)
{
return requested_stack == IPV4_STACK ? true : false;
}
} /* namespace mbed */

View File

@ -0,0 +1,36 @@
/*
* Copyright (c) 2018, Arm Limited and affiliates.
* SPDX-License-Identifier: Apache-2.0
*
* 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.
*/
#ifndef QUECTEL_BC95_CELLULARCONTEXT_H_
#define QUECTEL_BC95_CELLULARCONTEXT_H_
#include "AT_CellularContext.h"
namespace mbed {
class QUECTEL_BC95_CellularContext: public AT_CellularContext {
public:
QUECTEL_BC95_CellularContext(ATHandler &at, CellularDevice *device, const char *apn, nsapi_ip_stack_t stack);
virtual ~QUECTEL_BC95_CellularContext();
protected:
virtual NetworkStack *get_stack();
virtual bool get_modem_stack_type(nsapi_ip_stack_t requested_stack);
};
} /* namespace mbed */
#endif // QUECTEL_BC95_CELLULARCONTEXT_H_

View File

@ -16,7 +16,6 @@
*/
#include "QUECTEL_BC95_CellularNetwork.h"
#include "QUECTEL_BC95_CellularStack.h"
using namespace mbed;
@ -29,19 +28,6 @@ QUECTEL_BC95_CellularNetwork::~QUECTEL_BC95_CellularNetwork()
{
}
NetworkStack *QUECTEL_BC95_CellularNetwork::get_stack()
{
if (!_stack) {
_stack = new QUECTEL_BC95_CellularStack(_at, _cid, _ip_stack_type);
}
return _stack;
}
bool QUECTEL_BC95_CellularNetwork::get_modem_stack_type(nsapi_ip_stack_t requested_stack)
{
return requested_stack == IPV4_STACK ? true : false;
}
AT_CellularNetwork::RegistrationMode QUECTEL_BC95_CellularNetwork::has_registration(RegistrationType reg_tech)
{
return (reg_tech == C_EREG) ? RegistrationModeLAC : RegistrationModeDisable;

View File

@ -28,12 +28,7 @@ public:
virtual ~QUECTEL_BC95_CellularNetwork();
protected:
virtual NetworkStack *get_stack();
virtual nsapi_error_t set_access_technology_impl(RadioAccessTechnology opRat);
virtual bool get_modem_stack_type(nsapi_ip_stack_t requested_stack);
virtual RegistrationMode has_registration(RegistrationType reg_type);
};
} // namespace mbed

View File

@ -15,9 +15,12 @@
* limitations under the License.
*/
#include "QUECTEL/BG96/QUECTEL_BG96.h"
#include "QUECTEL/BG96/QUECTEL_BG96_CellularNetwork.h"
#include "QUECTEL/BG96/QUECTEL_BG96_CellularStack.h"
#include "QUECTEL_BG96.h"
#include "QUECTEL_BG96_CellularNetwork.h"
#include "QUECTEL_BG96_CellularStack.h"
#include "QUECTEL_BG96_CellularSIM.h"
#include "QUECTEL_BG96_CellularPower.h"
#include "QUECTEL_BG96_CellularContext.h"
using namespace mbed;
using namespace events;
@ -47,3 +50,19 @@ AT_CellularNetwork *QUECTEL_BG96::open_network_impl(ATHandler &at)
{
return new QUECTEL_BG96_CellularNetwork(at);
}
AT_CellularSIM *QUECTEL_BG96::open_sim_impl(ATHandler &at)
{
return new QUECTEL_BG96_CellularSIM(at);
}
AT_CellularPower *QUECTEL_BG96::open_power_impl(ATHandler &at)
{
return new QUECTEL_BG96_CellularPower(at);
}
AT_CellularContext *QUECTEL_BG96::create_context_impl(ATHandler &at, const char *apn, nsapi_ip_stack_t stack)
{
return new QUECTEL_BG96_CellularContext(at, this, apn, stack);
}

View File

@ -29,8 +29,10 @@ public:
protected: // AT_CellularDevice
virtual AT_CellularNetwork *open_network_impl(ATHandler &at);
public: // NetworkInterface
virtual AT_CellularSIM *open_sim_impl(ATHandler &at);
virtual AT_CellularPower *open_power_impl(ATHandler &at);
virtual AT_CellularContext *create_context_impl(ATHandler &at, const char *apn, nsapi_ip_stack_t stack);
public:
void handle_urc(FileHandle *fh);
};
} // namespace mbed

View File

@ -0,0 +1,68 @@
/*
* Copyright (c) 2018, Arm Limited and affiliates.
* SPDX-License-Identifier: Apache-2.0
*
* 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 "QUECTEL_BG96_CellularContext.h"
#include "QUECTEL_BG96_CellularStack.h"
namespace mbed {
QUECTEL_BG96_CellularContext::QUECTEL_BG96_CellularContext(ATHandler &at, CellularDevice *device, const char *apn,
nsapi_ip_stack_t stack) : AT_CellularContext(at, device, apn, stack)
{
}
QUECTEL_BG96_CellularContext::~QUECTEL_BG96_CellularContext()
{
}
bool QUECTEL_BG96_CellularContext::stack_type_supported(nsapi_ip_stack_t stack_type)
{
if (stack_type == IPV4_STACK) {
return true;
}
return false;
}
NetworkStack *QUECTEL_BG96_CellularContext::get_stack()
{
if (!_stack) {
_stack = new QUECTEL_BG96_CellularStack(_at, _cid, _ip_stack_type);
}
return _stack;
}
nsapi_error_t QUECTEL_BG96_CellularContext::do_user_authentication()
{
if (_pwd && _uname) {
_at.cmd_start("AT+QICSGP=");
_at.write_int(_cid);
_at.write_int(1); // IPv4
_at.write_string(_apn);
_at.write_string(_uname);
_at.write_string(_pwd);
_at.write_int(_authentication_type);
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
if (_at.get_last_error() != NSAPI_ERROR_OK) {
return NSAPI_ERROR_AUTH_FAILURE;
}
}
return NSAPI_ERROR_OK;
}
} /* namespace mbed */

View File

@ -0,0 +1,37 @@
/*
* Copyright (c) 2018, Arm Limited and affiliates.
* SPDX-License-Identifier: Apache-2.0
*
* 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.
*/
#ifndef QUECTEL_BG96_CELLULARCONTEXT_H_
#define QUECTEL_BG96_CELLULARCONTEXT_H_
#include "AT_CellularContext.h"
namespace mbed {
class QUECTEL_BG96_CellularContext: public AT_CellularContext {
public:
QUECTEL_BG96_CellularContext(ATHandler &at, CellularDevice *device, const char *apn, nsapi_ip_stack_t stack);
virtual ~QUECTEL_BG96_CellularContext();
protected:
virtual bool stack_type_supported(nsapi_ip_stack_t stack_type);
virtual NetworkStack *get_stack();
virtual nsapi_error_t do_user_authentication();
};
} /* namespace mbed */
#endif // QUECTEL_BG96_CELLULARCONTEXT_H_

View File

@ -28,23 +28,6 @@ QUECTEL_BG96_CellularNetwork::~QUECTEL_BG96_CellularNetwork()
{
}
bool QUECTEL_BG96_CellularNetwork::get_modem_stack_type(nsapi_ip_stack_t requested_stack)
{
if (requested_stack == IPV4_STACK) {
return true;
}
return false;
}
NetworkStack *QUECTEL_BG96_CellularNetwork::get_stack()
{
if (!_stack) {
_stack = new QUECTEL_BG96_CellularStack(_at, _cid, _ip_stack_type);
}
return _stack;
}
nsapi_error_t QUECTEL_BG96_CellularNetwork::set_access_technology_impl(RadioAccessTechnology opsAct)
{
_at.lock();
@ -89,22 +72,3 @@ nsapi_error_t QUECTEL_BG96_CellularNetwork::set_access_technology_impl(RadioAcce
return _at.unlock_return_error();
}
nsapi_error_t QUECTEL_BG96_CellularNetwork::do_user_authentication()
{
if (_pwd && _uname) {
_at.cmd_start("AT+QICSGP=");
_at.write_int(_cid);
_at.write_int(1); // IPv4
_at.write_string(_apn);
_at.write_string(_uname);
_at.write_string(_pwd);
_at.write_int(_authentication_type);
_at.cmd_stop_read_resp();
if (_at.get_last_error() != NSAPI_ERROR_OK) {
return NSAPI_ERROR_AUTH_FAILURE;
}
}
return NSAPI_ERROR_OK;
}

View File

@ -28,13 +28,7 @@ public:
virtual ~QUECTEL_BG96_CellularNetwork();
protected:
virtual NetworkStack *get_stack();
virtual nsapi_error_t set_access_technology_impl(RadioAccessTechnology opRat);
virtual bool get_modem_stack_type(nsapi_ip_stack_t requested_stack);
virtual nsapi_error_t do_user_authentication();
};
} // namespace mbed

View File

@ -15,9 +15,10 @@
* limitations under the License.
*/
#include "QUECTEL/UG96/QUECTEL_UG96.h"
#include "QUECTEL/UG96/QUECTEL_UG96_CellularNetwork.h"
#include "QUECTEL/UG96/QUECTEL_UG96_CellularPower.h"
#include "QUECTEL_UG96.h"
#include "QUECTEL_UG96_CellularNetwork.h"
#include "QUECTEL_UG96_CellularPower.h"
#include "QUECTEL_UG96_CellularContext.h"
using namespace mbed;
using namespace events;
@ -46,3 +47,8 @@ AT_CellularPower *QUECTEL_UG96::open_power_impl(ATHandler &at)
{
return new QUECTEL_UG96_CellularPower(at);
}
AT_CellularContext *QUECTEL_UG96::create_context_impl(ATHandler &at, const char *apn, nsapi_ip_stack_t stack)
{
return new QUECTEL_UG96_CellularContext(at, this, apn, stack);
}

View File

@ -38,6 +38,7 @@ public:
protected: // AT_CellularDevice
virtual AT_CellularNetwork *open_network_impl(ATHandler &at);
virtual AT_CellularPower *open_power_impl(ATHandler &at);
virtual AT_CellularContext *create_context_impl(ATHandler &at, const char *apn, nsapi_ip_stack_t stack);
public: // NetworkInterface
void handle_urc(FileHandle *fh);

View File

@ -0,0 +1,56 @@
/*
* Copyright (c) 2018, Arm Limited and affiliates.
* SPDX-License-Identifier: Apache-2.0
*
* 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 "QUECTEL_UG96_CellularContext.h"
namespace mbed {
QUECTEL_UG96_CellularContext::QUECTEL_UG96_CellularContext(ATHandler &at, CellularDevice *device, const char *apn,
nsapi_ip_stack_t stack) : AT_CellularContext(at, device, apn, stack)
{
}
QUECTEL_UG96_CellularContext::~QUECTEL_UG96_CellularContext()
{
}
bool QUECTEL_UG96_CellularContext::stack_type_supported(nsapi_ip_stack_t requested_stack)
{
return requested_stack == IPV4_STACK ? true : false;
}
nsapi_error_t QUECTEL_UG96_CellularContext::do_user_authentication()
{
if (_pwd && _uname) {
_at.cmd_start("AT+QICSGP=");
_at.write_int(_cid);
_at.write_int(1); // context type 1=IPv4
_at.write_string(_apn);
_at.write_string(_uname);
_at.write_string(_pwd);
_at.write_int(_authentication_type);
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
if (_at.get_last_error() != NSAPI_ERROR_OK) {
return NSAPI_ERROR_AUTH_FAILURE;
}
}
return NSAPI_ERROR_OK;
}
} /* namespace mbed */

View File

@ -0,0 +1,36 @@
/*
* Copyright (c) 2018, Arm Limited and affiliates.
* SPDX-License-Identifier: Apache-2.0
*
* 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.
*/
#ifndef QUECTEL_UG96_CELLULARCONTEXT_H_
#define QUECTEL_UG96_CELLULARCONTEXT_H_
#include "AT_CellularContext.h"
namespace mbed {
class QUECTEL_UG96_CellularContext: public AT_CellularContext {
public:
QUECTEL_UG96_CellularContext(ATHandler &at, CellularDevice *device, const char *apn, nsapi_ip_stack_t stack);
virtual ~QUECTEL_UG96_CellularContext();
protected:
virtual bool stack_type_supported(nsapi_ip_stack_t requested_stack);
virtual nsapi_error_t do_user_authentication();
};
} /* namespace mbed */
#endif // QUECTEL_UG96_CELLULARCONTEXT_H_

View File

@ -15,7 +15,7 @@
* limitations under the License.
*/
#include "QUECTEL/UG96/QUECTEL_UG96_CellularNetwork.h"
#include "QUECTEL_UG96_CellularNetwork.h"
using namespace mbed;
@ -27,11 +27,6 @@ QUECTEL_UG96_CellularNetwork::~QUECTEL_UG96_CellularNetwork()
{
}
bool QUECTEL_UG96_CellularNetwork::get_modem_stack_type(nsapi_ip_stack_t requested_stack)
{
return requested_stack == IPV4_STACK ? true : false;
}
AT_CellularNetwork::RegistrationMode QUECTEL_UG96_CellularNetwork::has_registration(RegistrationType reg_type)
{
return (reg_type == C_REG || reg_type == C_GREG) ? RegistrationModeLAC : RegistrationModeDisable;
@ -42,24 +37,3 @@ nsapi_error_t QUECTEL_UG96_CellularNetwork::set_access_technology_impl(RadioAcce
_op_act = RAT_UNKNOWN;
return NSAPI_ERROR_UNSUPPORTED;
}
nsapi_error_t QUECTEL_UG96_CellularNetwork::do_user_authentication()
{
if (_pwd && _uname) {
_at.cmd_start("AT+QICSGP=");
_at.write_int(_cid);
_at.write_int(1); // context type 1=IPv4
_at.write_string(_apn);
_at.write_string(_uname);
_at.write_string(_pwd);
_at.write_int(_authentication_type);
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
if (_at.get_last_error() != NSAPI_ERROR_OK) {
return NSAPI_ERROR_AUTH_FAILURE;
}
}
return NSAPI_ERROR_OK;
}

View File

@ -28,13 +28,8 @@ public:
virtual ~QUECTEL_UG96_CellularNetwork();
protected:
virtual bool get_modem_stack_type(nsapi_ip_stack_t requested_stack);
virtual RegistrationMode has_registration(RegistrationType rat);
virtual nsapi_error_t set_access_technology_impl(RadioAccessTechnology opRat);
virtual nsapi_error_t do_user_authentication();
};
} // namespace mbed

View File

@ -18,6 +18,7 @@
#include "TELIT_HE910.h"
#include "TELIT_HE910_CellularPower.h"
#include "TELIT_HE910_CellularNetwork.h"
#include "TELIT_HE910_CellularContext.h"
using namespace mbed;
using namespace events;
@ -47,6 +48,11 @@ AT_CellularPower *TELIT_HE910::open_power_impl(ATHandler &at)
return new TELIT_HE910_CellularPower(at);
}
AT_CellularContext *TELIT_HE910::create_context_impl(ATHandler &at, const char *apn, nsapi_ip_stack_t stack)
{
return new TELIT_HE910_CellularContext(at, this, apn, stack);
}
uint16_t TELIT_HE910::get_send_delay() const
{
return DEFAULT_DELAY_BETWEEN_AT_COMMANDS;

View File

@ -33,6 +33,7 @@ public:
protected: // AT_CellularDevice
virtual AT_CellularNetwork *open_network_impl(ATHandler &at);
virtual AT_CellularPower *open_power_impl(ATHandler &at);
virtual AT_CellularContext *create_context_impl(ATHandler &at, const char *apn, nsapi_ip_stack_t stack);
public: // from CellularDevice
virtual uint16_t get_send_delay() const;

View File

@ -0,0 +1,35 @@
/*
* Copyright (c) 2018, Arm Limited and affiliates.
* SPDX-License-Identifier: Apache-2.0
*
* 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 "TELIT_HE910_CellularContext.h"
namespace mbed {
TELIT_HE910_CellularContext::TELIT_HE910_CellularContext(ATHandler &at, CellularDevice *device, const char *apn,
nsapi_ip_stack_t stack) : AT_CellularContext(at, device, apn, stack)
{
}
TELIT_HE910_CellularContext::~TELIT_HE910_CellularContext()
{
}
bool TELIT_HE910_CellularContext::stack_type_supported(nsapi_ip_stack_t requested_stack)
{
return requested_stack == IPV4_STACK || requested_stack == IPV6_STACK;
}
} /* namespace mbed */

View File

@ -0,0 +1,35 @@
/*
* Copyright (c) 2018, Arm Limited and affiliates.
* SPDX-License-Identifier: Apache-2.0
*
* 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.
*/
#ifndef TELIT_HE910_CELLULARCONTEXT_H_
#define TELIT_HE910_CELLULARCONTEXT_H_
#include "AT_CellularContext.h"
namespace mbed {
class TELIT_HE910_CellularContext: public AT_CellularContext {
public:
TELIT_HE910_CellularContext(ATHandler &at, CellularDevice *device, const char *apn, nsapi_ip_stack_t stack);
virtual ~TELIT_HE910_CellularContext();
protected:
virtual bool stack_type_supported(nsapi_ip_stack_t requested_stack);
};
} /* namespace mbed */
#endif // TELIT_HE910_CELLULARCONTEXT_H_

View File

@ -27,11 +27,6 @@ TELIT_HE910_CellularNetwork::~TELIT_HE910_CellularNetwork()
{
}
bool TELIT_HE910_CellularNetwork::get_modem_stack_type(nsapi_ip_stack_t requested_stack)
{
return requested_stack == IPV4_STACK ? true : false;
}
AT_CellularNetwork::RegistrationMode TELIT_HE910_CellularNetwork::has_registration(RegistrationType reg_type)
{
return (reg_type == C_REG || reg_type == C_GREG) ? RegistrationModeLAC : RegistrationModeDisable;

View File

@ -28,11 +28,7 @@ public:
virtual ~TELIT_HE910_CellularNetwork();
protected:
virtual bool get_modem_stack_type(nsapi_ip_stack_t requested_stack);
virtual RegistrationMode has_registration(RegistrationType rat);
virtual nsapi_error_t set_access_technology_impl(RadioAccessTechnology opRat);
};

View File

@ -18,6 +18,7 @@
#include "UBLOX_AT.h"
#include "UBLOX_AT_CellularNetwork.h"
#include "UBLOX_AT_CellularPower.h"
#include "UBLOX_AT_CellularContext.h"
using namespace mbed;
using namespace events;
@ -49,3 +50,8 @@ AT_CellularPower *UBLOX_AT::open_power_impl(ATHandler &at)
{
return new UBLOX_AT_CellularPower(at);
}
AT_CellularContext *UBLOX_AT::create_context_impl(ATHandler &at, const char *apn, nsapi_ip_stack_t stack)
{
return new UBLOX_AT_CellularContext(at, this, apn, stack);
}

View File

@ -30,7 +30,7 @@ public:
protected: // AT_CellularDevice
virtual AT_CellularNetwork *open_network_impl(ATHandler &at);
virtual AT_CellularPower *open_power_impl(ATHandler &at);
virtual AT_CellularContext *create_context_impl(ATHandler &at, const char *apn, nsapi_ip_stack_t stack);
public: // NetworkInterface
void handle_urc(FileHandle *fh);
};

View File

@ -0,0 +1,286 @@
/*
* Copyright (c) 2018, Arm Limited and affiliates.
* SPDX-License-Identifier: Apache-2.0
*
* 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 "UBLOX_AT_CellularContext.h"
#include "UBLOX_AT_CellularStack.h"
#include "APN_db.h"
namespace mbed {
UBLOX_AT_CellularContext::UBLOX_AT_CellularContext(ATHandler &at, CellularDevice *device, const char *apn,
nsapi_ip_stack_t stack) : AT_CellularContext(at, device, apn, stack)
{
// The authentication to use
_auth = NSAPI_SECURITY_UNKNOWN;
}
UBLOX_AT_CellularContext::~UBLOX_AT_CellularContext()
{
}
NetworkStack *UBLOX_AT_CellularContext::get_stack()
{
if (!_stack) {
_stack = new UBLOX_AT_CellularStack(_at, _cid, _ip_stack_type);
}
return _stack;
}
bool UBLOX_AT_CellularContext::stack_type_supported(nsapi_ip_stack_t requested_stack)
{
return requested_stack == IPV4_STACK ? true : false;
}
void UBLOX_AT_CellularContext::do_connect()
{
_at.lock();
_cb_data.error = NSAPI_ERROR_NO_CONNECTION;
// Attempt to establish a connection
#ifdef TARGET_UBLOX_C030_R410M
_cb_data.error = NSAPI_ERROR_OK;
#else
_cb_data.error = open_data_channel();
#endif
if (_cb_data.error != NSAPI_ERROR_OK) {
// If new PSD context was created and failed to activate, delete it
if (_new_context_set) {
disconnect_modem_stack();
}
_connect_status = NSAPI_STATUS_DISCONNECTED;
} else {
_connect_status = NSAPI_STATUS_GLOBAL_UP;
}
_at.unlock();
if (_status_cb) {
call_network_cb(_connect_status);
}
}
nsapi_error_t UBLOX_AT_CellularContext::open_data_channel()
{
bool success = false;
int active = 0;
char * config = NULL;
nsapi_error_t err = NSAPI_ERROR_NO_CONNECTION;
char imsi[MAX_IMSI_LENGTH+1];
// do check for stack to validate that we have support for stack
_stack = get_stack();
if (!_stack) {
return err;
}
_at.cmd_start("AT+UPSND=" PROFILE ",8");
_at.cmd_stop();
_at.resp_start("+UPSND:");
_at.read_int();
_at.read_int();
active = _at.read_int();
_at.resp_stop();
if (active == 0) {
// If the caller hasn't entered an APN, try to find it
if (_apn == NULL) {
err = get_imsi(imsi);
if (err == NSAPI_ERROR_OK) {
config = (char*)apnconfig(imsi);
}
}
// Attempt to connect
do {
get_next_credentials(&config);
if(_uname && _pwd) {
_auth = (*_uname && *_pwd) ? _auth : NSAPI_SECURITY_NONE;
} else {
_auth = NSAPI_SECURITY_NONE;
}
success = activate_profile(_apn, _uname, _pwd);
} while (!success && config && *config);
} else {
// If the profile is already active, we're good
success = true;
}
err = (_at.get_last_error() == NSAPI_ERROR_OK) ? NSAPI_ERROR_OK : NSAPI_ERROR_NO_CONNECTION;
return err;
}
bool UBLOX_AT_CellularContext::activate_profile(const char* apn,
const char* username,
const char* password)
{
bool activated = false;
bool success = false;
// Set up the APN
if (apn) {
success = false;
_at.cmd_start("AT+UPSD=0,1,");
_at.write_string(apn);
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
if (_at.get_last_error() == NSAPI_ERROR_OK) {
success = true;
}
}
// Set up the UserName
if (success && username) {
success = false;
_at.cmd_start("AT+UPSD=" PROFILE ",2,");
_at.write_string(username);
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
if (_at.get_last_error() == NSAPI_ERROR_OK) {
success = true;
}
}
// Set up the Password
if (success && password) {
success = false;
_at.cmd_start("AT+UPSD=" PROFILE ",3,");
_at.write_string(password);
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
if (_at.get_last_error() == NSAPI_ERROR_OK) {
success = true;
}
}
if (success) {
_at.cmd_start("AT+UPSD=" PROFILE ",7,\"0.0.0.0\"");
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
// Set up the authentication protocol
// 0 = none
// 1 = PAP (Password Authentication Protocol)
// 2 = CHAP (Challenge Handshake Authentication Protocol)
for (int protocol = nsapi_security_to_modem_security(NSAPI_SECURITY_NONE);
success && (protocol <= nsapi_security_to_modem_security(NSAPI_SECURITY_CHAP)); protocol++) {
if ((_auth == NSAPI_SECURITY_UNKNOWN) || (nsapi_security_to_modem_security(_auth) == protocol)) {
_at.cmd_start("AT+UPSD=0,6,");
_at.write_int(protocol);
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
if (_at.get_last_error() == NSAPI_ERROR_OK) {
// Activate, wait upto 30 seconds for the connection to be made
_at.set_at_timeout(30000);
_at.cmd_start("AT+UPSDA=0,3");
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
_at.restore_at_timeout();
if (_at.get_last_error() == NSAPI_ERROR_OK) {
activated = true;
}
}
}
}
}
return activated;
}
// Convert nsapi_security_t to the modem security numbers
int UBLOX_AT_CellularContext::nsapi_security_to_modem_security(nsapi_security_t nsapi_security)
{
int modem_security = 3;
switch (nsapi_security) {
case NSAPI_SECURITY_NONE:
modem_security = 0;
break;
case NSAPI_SECURITY_PAP:
modem_security = 1;
break;
case NSAPI_SECURITY_CHAP:
modem_security = 2;
break;
case NSAPI_SECURITY_UNKNOWN:
modem_security = 3;
break;
default:
modem_security = 3;
break;
}
return modem_security;
}
// Disconnect the on board IP stack of the modem.
bool UBLOX_AT_CellularContext::disconnect_modem_stack()
{
bool success = false;
if (get_ip_address() != NULL) {
_at.cmd_start("AT+UPSDA=" PROFILE ",4");
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
if (_at.get_last_error() == NSAPI_ERROR_OK) {
success = true;
}
}
return success;
}
nsapi_error_t UBLOX_AT_CellularContext::get_imsi(char* imsi)
{
_at.lock();
_at.cmd_start("AT+CIMI");
_at.cmd_stop();
_at.resp_start();
int len = _at.read_string(imsi, MAX_IMSI_LENGTH);
if (len > 0) {
imsi[len] = '\0';
}
_at.resp_stop();
return _at.unlock_return_error();
}
// Get the next set of credentials, based on IMSI.
void UBLOX_AT_CellularContext::get_next_credentials(char ** config)
{
if (*config) {
_apn = _APN_GET(*config);
_uname = _APN_GET(*config);
_pwd = _APN_GET(*config);
}
}
const char *UBLOX_AT_CellularContext::get_gateway()
{
return get_ip_address();
}
} /* namespace mbed */

View File

@ -0,0 +1,88 @@
/*
* Copyright (c) 2018, Arm Limited and affiliates.
* SPDX-License-Identifier: Apache-2.0
*
* 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.
*/
#ifndef UBLOX_AT_CELLULARCONTEXT_H_
#define UBLOX_AT_CELLULARCONTEXT_H_
#include "AT_CellularContext.h"
namespace mbed {
class UBLOX_AT_CellularContext: public AT_CellularContext {
public:
UBLOX_AT_CellularContext(ATHandler &at, CellularDevice *device, const char *apn, nsapi_ip_stack_t stack);
virtual ~UBLOX_AT_CellularContext();
virtual void do_connect();
virtual const char *get_gateway();
protected:
virtual NetworkStack *get_stack();
virtual bool stack_type_supported(nsapi_ip_stack_t requested_stack);
private:
/** Length of IMSI buffer.
*/
static const int MAX_IMSI_LENGTH = 15;
/** The type of authentication to use.
*/
nsapi_security_t _auth;
/** Connect the on board IP stack of the modem.
*
* @return True if successful, otherwise false.
*/
nsapi_error_t open_data_channel();
/** Activate one of the on-board modem's connection profiles.
*
* @param apn The APN to use.
* @param username The user name to use.
* @param password The password to use.
* @param auth The authentication method to use
* (NSAPI_SECURITY_NONE, NSAPI_SECURITY_PAP,
* NSAPI_SECURITY_CHAP or NSAPI_SECURITY_UNKNOWN).
* @return True if successful, otherwise false.
*/
bool activate_profile(const char* apn, const char* username, const char* password);
/** Convert nsapi_security_t to the modem security numbers.
*
* @param nsapi_security Security protocol.
* @return Modem security numbers.
*/
int nsapi_security_to_modem_security(nsapi_security_t nsapi_security);
/** Disconnect the on board IP stack of the modem.
*
* @return True if successful, otherwise false.
*/
bool disconnect_modem_stack();
/** Read IMSI of modem.
*/
nsapi_error_t get_imsi(char* imsi);
/** Get the next set of credentials from the database.
*/
void get_next_credentials(char ** config);
};
} /* namespace mbed */
#endif // UBLOX_AT_CELLULARCONTEXT_H_

View File

@ -16,15 +16,12 @@
*/
#include "UBLOX_AT_CellularNetwork.h"
#include "UBLOX_AT_CellularStack.h"
using namespace mbed;
UBLOX_AT_CellularNetwork::UBLOX_AT_CellularNetwork(ATHandler &atHandler) : AT_CellularNetwork(atHandler)
{
_op_act = RAT_UNKNOWN;
// The authentication to use
_auth = NSAPI_SECURITY_UNKNOWN;
}
UBLOX_AT_CellularNetwork::~UBLOX_AT_CellularNetwork()
@ -34,19 +31,6 @@ UBLOX_AT_CellularNetwork::~UBLOX_AT_CellularNetwork()
}
}
NetworkStack *UBLOX_AT_CellularNetwork::get_stack()
{
if (!_stack) {
_stack = new UBLOX_AT_CellularStack(_at, _cid, _ip_stack_type);
}
return _stack;
}
bool UBLOX_AT_CellularNetwork::get_modem_stack_type(nsapi_ip_stack_t requested_stack)
{
return requested_stack == IPV4_STACK ? true : false;
}
AT_CellularNetwork::RegistrationMode UBLOX_AT_CellularNetwork::has_registration(RegistrationType reg_type)
{
return (reg_type == C_REG || reg_type == C_GREG) ? RegistrationModeLAC : RegistrationModeDisable;
@ -85,230 +69,3 @@ nsapi_error_t UBLOX_AT_CellularNetwork::set_access_technology_impl(RadioAccessTe
return NSAPI_ERROR_OK;
}
nsapi_error_t UBLOX_AT_CellularNetwork::connect()
{
_at.lock();
nsapi_error_t err = NSAPI_ERROR_NO_CONNECTION;
// Attempt to establish a connection
#ifdef TARGET_UBLOX_C030_R410M
err = NSAPI_ERROR_OK;
#else
err = open_data_channel();
#endif
if (err != NSAPI_ERROR_OK) {
// If new PSD context was created and failed to activate, delete it
if (_new_context_set) {
disconnect_modem_stack();
}
_connect_status = NSAPI_STATUS_DISCONNECTED;
} else {
_connect_status = NSAPI_STATUS_GLOBAL_UP;
}
_at.unlock();
if (_connection_status_cb) {
_connection_status_cb(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, _connect_status);
}
return err;
}
nsapi_error_t UBLOX_AT_CellularNetwork::open_data_channel()
{
bool success = false;
int active = 0;
char *config = NULL;
nsapi_error_t err = NSAPI_ERROR_NO_CONNECTION;
char imsi[MAX_IMSI_LENGTH + 1];
// do check for stack to validate that we have support for stack
_stack = get_stack();
if (!_stack) {
return err;
}
_at.cmd_start("AT+UPSND=" PROFILE ",8");
_at.cmd_stop();
_at.resp_start("+UPSND:");
_at.read_int();
_at.read_int();
active = _at.read_int();
_at.resp_stop();
if (active == 0) {
// If the caller hasn't entered an APN, try to find it
if (_apn == NULL) {
err = get_imsi(imsi);
if (err == NSAPI_ERROR_OK) {
config = (char *)apnconfig(imsi);
}
}
// Attempt to connect
do {
get_next_credentials(&config);
if (_uname && _pwd) {
_auth = (*_uname && *_pwd) ? _auth : NSAPI_SECURITY_NONE;
} else {
_auth = NSAPI_SECURITY_NONE;
}
success = activate_profile(_apn, _uname, _pwd);
} while (!success && config && *config);
} else {
// If the profile is already active, we're good
success = true;
}
err = (_at.get_last_error() == NSAPI_ERROR_OK) ? NSAPI_ERROR_OK : NSAPI_ERROR_NO_CONNECTION;
return err;
}
bool UBLOX_AT_CellularNetwork::activate_profile(const char *apn,
const char *username,
const char *password)
{
bool activated = false;
bool success = false;
// Set up the APN
if (apn) {
success = false;
_at.cmd_start("AT+UPSD=0,1,");
_at.write_string(apn);
_at.cmd_stop_read_resp();
if (_at.get_last_error() == NSAPI_ERROR_OK) {
success = true;
}
}
// Set up the UserName
if (success && username) {
success = false;
_at.cmd_start("AT+UPSD=" PROFILE ",2,");
_at.write_string(username);
_at.cmd_stop_read_resp();
if (_at.get_last_error() == NSAPI_ERROR_OK) {
success = true;
}
}
// Set up the Password
if (success && password) {
success = false;
_at.cmd_start("AT+UPSD=" PROFILE ",3,");
_at.write_string(password);
_at.cmd_stop_read_resp();
if (_at.get_last_error() == NSAPI_ERROR_OK) {
success = true;
}
}
if (success) {
_at.cmd_start("AT+UPSD=" PROFILE ",7,\"0.0.0.0\"");
_at.cmd_stop_read_resp();
// Set up the authentication protocol
// 0 = none
// 1 = PAP (Password Authentication Protocol)
// 2 = CHAP (Challenge Handshake Authentication Protocol)
for (int protocol = nsapi_security_to_modem_security(NSAPI_SECURITY_NONE);
success && (protocol <= nsapi_security_to_modem_security(NSAPI_SECURITY_CHAP)); protocol++) {
if ((_auth == NSAPI_SECURITY_UNKNOWN) || (nsapi_security_to_modem_security(_auth) == protocol)) {
_at.cmd_start("AT+UPSD=0,6,");
_at.write_int(protocol);
_at.cmd_stop_read_resp();
if (_at.get_last_error() == NSAPI_ERROR_OK) {
// Activate, wait upto 30 seconds for the connection to be made
_at.set_at_timeout(30000);
_at.cmd_start("AT+UPSDA=0,3");
_at.cmd_stop_read_resp();
_at.restore_at_timeout();
if (_at.get_last_error() == NSAPI_ERROR_OK) {
activated = true;
}
}
}
}
}
return activated;
}
// Convert nsapi_security_t to the modem security numbers
int UBLOX_AT_CellularNetwork::nsapi_security_to_modem_security(nsapi_security_t nsapi_security)
{
int modem_security = 3;
switch (nsapi_security) {
case NSAPI_SECURITY_NONE:
modem_security = 0;
break;
case NSAPI_SECURITY_PAP:
modem_security = 1;
break;
case NSAPI_SECURITY_CHAP:
modem_security = 2;
break;
case NSAPI_SECURITY_UNKNOWN:
modem_security = 3;
break;
default:
modem_security = 3;
break;
}
return modem_security;
}
// Disconnect the on board IP stack of the modem.
bool UBLOX_AT_CellularNetwork::disconnect_modem_stack()
{
bool success = false;
if (get_ip_address() != NULL) {
_at.cmd_start("AT+UPSDA=" PROFILE ",4");
_at.cmd_stop_read_resp();
if (_at.get_last_error() == NSAPI_ERROR_OK) {
success = true;
}
}
return success;
}
nsapi_error_t UBLOX_AT_CellularNetwork::get_imsi(char *imsi)
{
_at.lock();
_at.cmd_start("AT+CIMI");
_at.cmd_stop();
_at.resp_start();
int len = _at.read_string(imsi, MAX_IMSI_LENGTH);
if (len > 0) {
imsi[len] = '\0';
}
_at.resp_stop();
return _at.unlock_return_error();
}
// Get the next set of credentials, based on IMSI.
void UBLOX_AT_CellularNetwork::get_next_credentials(char **config)
{
if (*config) {
_apn = _APN_GET(*config);
_uname = _APN_GET(*config);
_pwd = _APN_GET(*config);
}
}
const char *UBLOX_AT_CellularNetwork::get_gateway()
{
return get_ip_address();
}

View File

@ -19,7 +19,6 @@
#define UBLOX_AT_CELLULAR_NETWORK_H_
#include "AT_CellularNetwork.h"
#include "APN_db.h"
namespace mbed {
@ -28,67 +27,9 @@ public:
UBLOX_AT_CellularNetwork(ATHandler &atHandler);
virtual ~UBLOX_AT_CellularNetwork();
virtual nsapi_error_t connect();
virtual const char *get_gateway();
protected:
virtual NetworkStack *get_stack();
virtual nsapi_error_t set_access_technology_impl(RadioAccessTechnology opRat);
virtual bool get_modem_stack_type(nsapi_ip_stack_t requested_stack);
virtual RegistrationMode has_registration(RegistrationType rat);
private:
/** Length of IMSI buffer.
*/
static const int MAX_IMSI_LENGTH = 15;
/** The type of authentication to use.
*/
nsapi_security_t _auth;
/** Connect the on board IP stack of the modem.
*
* @return True if successful, otherwise false.
*/
nsapi_error_t open_data_channel();
/** Activate one of the on-board modem's connection profiles.
*
* @param apn The APN to use.
* @param username The user name to use.
* @param password The password to use.
* @param auth The authentication method to use
* (NSAPI_SECURITY_NONE, NSAPI_SECURITY_PAP,
* NSAPI_SECURITY_CHAP or NSAPI_SECURITY_UNKNOWN).
* @return True if successful, otherwise false.
*/
bool activate_profile(const char *apn, const char *username, const char *password);
/** Convert nsapi_security_t to the modem security numbers.
*
* @param nsapi_security Security protocol.
* @return Modem security numbers.
*/
int nsapi_security_to_modem_security(nsapi_security_t nsapi_security);
/** Disconnect the on board IP stack of the modem.
*
* @return True if successful, otherwise false.
*/
bool disconnect_modem_stack();
/** Read IMSI of modem.
*/
nsapi_error_t get_imsi(char *imsi);
/** Get the next set of credentials from the database.
*/
void get_next_credentials(char **config);
};
} // namespace mbed

View File

@ -193,12 +193,9 @@ nsapi_size_or_error_t UBLOX_AT_CellularStack::socket_sendto_impl(CellularSocket
const void *data, nsapi_size_t size)
{
int sent_len = 0;
uint8_t ch = 0, cont = 50;
pollfh fhs;
fhs.fh = _at.get_file_handle();
fhs.events = POLLIN;
int pollCount;
if (socket->proto == NSAPI_UDP) {
if (size > UBLOX_MAX_PACKET_SIZE) {
@ -210,7 +207,7 @@ nsapi_size_or_error_t UBLOX_AT_CellularStack::socket_sendto_impl(CellularSocket
_at.write_int(address.get_port());
_at.write_int(size);
_at.cmd_stop();
pollCount = poll(&fhs, 1, 50);
(void)poll(&fhs, 1, 50);
_at.write_bytes((uint8_t *)data, size);
_at.resp_start("+USOST:");
@ -235,7 +232,7 @@ nsapi_size_or_error_t UBLOX_AT_CellularStack::socket_sendto_impl(CellularSocket
_at.write_int(socket->id);
_at.write_int(blk);
_at.cmd_stop();
pollCount = poll(&fhs, 1, 50);
(void)poll(&fhs, 1, 50);
_at.write_bytes((uint8_t *)buf, blk);
_at.resp_start("+USOWR:");

View File

@ -18,6 +18,7 @@
#include "UBLOX_PPP.h"
#include "UBLOX_PPP_CellularNetwork.h"
#include "UBLOX_PPP_CellularPower.h"
#include "UBLOX_PPP_CellularContext.h"
using namespace mbed;
using namespace events;
@ -49,3 +50,8 @@ AT_CellularPower *UBLOX_PPP::open_power_impl(ATHandler &at)
{
return new UBLOX_PPP_CellularPower(at);
}
AT_CellularContext *UBLOX_PPP::create_context_impl(ATHandler &at, const char *apn, nsapi_ip_stack_t stack)
{
return new UBLOX_PPP_CellularContext(at, this, apn, stack);
}

View File

@ -30,10 +30,7 @@ public:
protected: // AT_CellularDevice
virtual AT_CellularNetwork *open_network_impl(ATHandler &at);
virtual AT_CellularPower *open_power_impl(ATHandler &at);
};
MBED_DEPRECATED_SINCE("mbed-os-5.9", "This API will be deprecated, Use UBLOX_PPP instead of UBLOX_LISA_U.")
class UBLOX_LISA_U : public UBLOX_PPP {
virtual AT_CellularContext *create_context_impl(ATHandler &at, const char *apn, nsapi_ip_stack_t stack);
};
} // namespace mbed

View File

@ -0,0 +1,35 @@
/*
* Copyright (c) 2018, Arm Limited and affiliates.
* SPDX-License-Identifier: Apache-2.0
*
* 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 "UBLOX_PPP_CellularContext.h"
namespace mbed {
UBLOX_PPP_CellularContext::UBLOX_PPP_CellularContext(ATHandler &at, CellularDevice *device, const char *apn,
nsapi_ip_stack_t stack) : AT_CellularContext(at, device, apn, stack)
{
}
UBLOX_PPP_CellularContext::~UBLOX_PPP_CellularContext()
{
}
bool UBLOX_PPP_CellularContext::stack_type_supported(nsapi_ip_stack_t requested_stack)
{
return requested_stack == IPV4_STACK ? true : false;
}
} /* namespace mbed */

View File

@ -0,0 +1,35 @@
/*
* Copyright (c) 2018, Arm Limited and affiliates.
* SPDX-License-Identifier: Apache-2.0
*
* 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.
*/
#ifndef UBLOX_PPP_CELLULARCONTEXT_H_
#define UBLOX_PPP_CELLULARCONTEXT_H_
#include "AT_CellularContext.h"
namespace mbed {
class UBLOX_PPP_CellularContext: public AT_CellularContext {
public:
UBLOX_PPP_CellularContext(ATHandler &at, CellularDevice *device, const char *apn, nsapi_ip_stack_t stack);
virtual ~UBLOX_PPP_CellularContext();
protected:
virtual bool stack_type_supported(nsapi_ip_stack_t requested_stack);
};
} /* namespace mbed */
#endif // UBLOX_PPP_CELLULARCONTEXT_H_

View File

@ -27,11 +27,6 @@ UBLOX_PPP_CellularNetwork::~UBLOX_PPP_CellularNetwork()
{
}
bool UBLOX_PPP_CellularNetwork::get_modem_stack_type(nsapi_ip_stack_t requested_stack)
{
return requested_stack == IPV4_STACK ? true : false;
}
AT_CellularNetwork::RegistrationMode UBLOX_PPP_CellularNetwork::has_registration(RegistrationType reg_type)
{
return (reg_type == C_REG || reg_type == C_GREG) ? RegistrationModeLAC : RegistrationModeDisable;

View File

@ -28,17 +28,10 @@ public:
virtual ~UBLOX_PPP_CellularNetwork();
protected:
virtual bool get_modem_stack_type(nsapi_ip_stack_t requested_stack);
virtual RegistrationMode has_registration(RegistrationType rat);
virtual nsapi_error_t set_access_technology_impl(RadioAccessTechnology opRat);
};
MBED_DEPRECATED_SINCE("mbed-os-5.9", "This API will be deprecated, Use UBLOX_PPP_CellularNetwork instead of UBLOX_LISA_U_CellularNetwork.")
class UBLOX_LISA_U_CellularNetwork : public UBLOX_PPP_CellularNetwork {
};
} // namespace mbed
#endif // UBLOX_PPP_CELLULAR_NETWORK_H_

View File

@ -34,10 +34,6 @@ public: //from CellularPower
virtual nsapi_error_t off();
};
MBED_DEPRECATED_SINCE("mbed-os-5.9", "This API will be deprecated, Use UBLOX_PPP_CellularPower instead of UBLOX_LISA_U_CellularPower.")
class UBLOX_LISA_U_CellularPower : public UBLOX_PPP_CellularPower {
};
} // namespace mbed
#endif // UBLOX_PPP_CELLULARPOWER_H_

View File

@ -110,27 +110,8 @@ MBED_WEAK NetworkInterface *NetworkInterface::get_target_default_instance()
#elif MBED_CONF_TARGET_NETWORK_DEFAULT_INTERFACE_TYPE == CELLULAR
MBED_WEAK NetworkInterface *NetworkInterface::get_target_default_instance()
{
CellularBase *cellular = CellularBase::get_default_instance();
if (!cellular) {
return NULL;
}
/* CellularBase is expected to attempt to work without any parameters - we
* will try, at least.
*/
#ifdef MBED_CONF_NSAPI_DEFAULT_CELLULAR_APN
#ifndef MBED_CONF_NSAPI_DEFAULT_CELLULAR_USERNAME
#define MBED_CONF_NSAPI_DEFAULT_CELLULAR_USERNAME NULL
#endif
#ifndef MBED_CONF_NSAPI_DEFAULT_CELLULAR_PASSWORD
#define MBED_CONF_NSAPI_DEFAULT_CELLULAR_PASSWORD NULL
#endif
cellular->set_credentials(MBED_CONF_NSAPI_DEFAULT_CELLULAR_APN, MBED_CONF_NSAPI_DEFAULT_CELLULAR_USERNAME, MBED_CONF_NSAPI_DEFAULT_CELLULAR_PASSWORD);
#endif
#ifdef MBED_CONF_NSAPI_DEFAULT_CELLULAR_SIM_PIN
cellular->set_sim_pin(MBED_CONF_NSAPI_DEFAULT_CELLULAR_SIM_PIN);
#endif
return CellularContext::get_default_instance();
return cellular;
}
#elif defined(MBED_CONF_TARGET_NETWORK_DEFAULT_INTERFACE_TYPE)
/* If anyone invents a new JSON value, they must have their own default weak

View File

@ -6,10 +6,11 @@
"default-wifi-ssid": null,
"default-wifi-password": null,
"default-wifi-security": "NONE",
"default-cellular-sim-pin": null,
"default-cellular-apn": null,
"default-cellular-username": null,
"default-cellular-password": null,
"default-cellular-plmn": 0,
"default-cellular-sim-pin": 0,
"default-cellular-apn": 0,
"default-cellular-username": 0,
"default-cellular-password": 0,
"default-mesh-type": {
"help": "Configuration type for MeshInterface::get_default_instance(). [LOWPAN/THREAD]",
"value": "THREAD"

View File

@ -69,7 +69,6 @@ typedef enum nsapi_connection_status {
NSAPI_STATUS_GLOBAL_UP = 1, /*!< global IP address set */
NSAPI_STATUS_DISCONNECTED = 2, /*!< no connection to network */
NSAPI_STATUS_CONNECTING = 3, /*!< connecting to network */
NSAPI_STATUS_RECONNECTING = 4, /*!< reconnecting to network */
NSAPI_STATUS_ERROR_UNSUPPORTED = NSAPI_ERROR_UNSUPPORTED
} nsapi_connection_status_t;