mirror of https://github.com/ARMmbed/mbed-os.git
Cellular: Non-IP socket and PDP context for EPS control plane data delivery
parent
84e5013a2d
commit
d301e13610
|
@ -9,6 +9,7 @@ set(unittest-includes ${unittest-includes}
|
|||
../features/cellular/framework/common
|
||||
../features/cellular/framework/AT
|
||||
../features/cellular/framework/device
|
||||
../features/netsocket/cellular
|
||||
)
|
||||
|
||||
# Source files
|
||||
|
|
|
@ -12,6 +12,7 @@ set(unittest-includes ${unittest-includes}
|
|||
../features/frameworks/mbed-client-randlib/mbed-client-randlib
|
||||
../drivers
|
||||
../hal
|
||||
../features/netsocket/cellular
|
||||
)
|
||||
|
||||
# Source files
|
||||
|
|
|
@ -8,6 +8,7 @@ set(unittest-includes ${unittest-includes}
|
|||
/features/cellular/framework/device/cellulardevice
|
||||
../features/cellular/framework/device
|
||||
../features/cellular/framework/common
|
||||
../features/netsocket/cellular
|
||||
)
|
||||
|
||||
# Source files
|
||||
|
|
|
@ -8,6 +8,7 @@ set(unittest-includes ${unittest-includes}
|
|||
/features/cellular/framework/device/cellularstatemachine
|
||||
../features/cellular/framework/device
|
||||
../features/cellular/framework/common
|
||||
../features/netsocket/cellular
|
||||
)
|
||||
|
||||
# Source files
|
||||
|
|
|
@ -49,6 +49,8 @@ intptr_t AT_CellularBase::get_property(CellularProperty key)
|
|||
return AT_CellularNetwork::RegistrationModeEnable;
|
||||
} else if (key == PROPERTY_AT_CGAUTH) {
|
||||
return true;
|
||||
} else if (key == PROPERTY_IPV4_PDP_TYPE) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return AT_CellularBase_stub::supported_bool;
|
||||
|
|
|
@ -19,12 +19,12 @@
|
|||
|
||||
using namespace mbed;
|
||||
|
||||
AT_CellularContext::AT_CellularContext(ATHandler &at, CellularDevice *device, const char *apn) :
|
||||
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)
|
||||
AT_CellularContext::AT_CellularContext(ATHandler &at, CellularDevice *device, const char *apn, bool cp_req, bool nonip_req) :
|
||||
AT_CellularBase(at), _is_blocking(true), _is_connected(false),
|
||||
_current_op(OP_INVALID), _device(device), _nw(0), _fh(0), _cp_req(cp_req), _nonip_req(nonip_req), _cp_in_use(false), _cp_netif(NULL)
|
||||
{
|
||||
_stack = NULL;
|
||||
_ip_stack_type = DEFAULT_STACK;
|
||||
_pdp_type = DEFAULT_PDP_TYPE;
|
||||
_authentication_type = CellularContext::CHAP;
|
||||
_connect_status = NSAPI_STATUS_DISCONNECTED;
|
||||
_is_context_active = false;
|
||||
|
@ -143,25 +143,23 @@ const char *AT_CellularContext::get_gateway()
|
|||
return NULL;
|
||||
}
|
||||
|
||||
AT_CellularBase::CellularProperty AT_CellularContext::nsapi_ip_stack_t_to_cellular_property(nsapi_ip_stack_t stack)
|
||||
AT_CellularBase::CellularProperty AT_CellularContext::pdp_type_t_to_cellular_property(pdp_type_t pdp_type)
|
||||
{
|
||||
AT_CellularBase::CellularProperty prop = PROPERTY_IPV4_STACK;
|
||||
if (stack == IPV6_STACK) {
|
||||
prop = PROPERTY_IPV6_STACK;
|
||||
} else if (stack == IPV4V6_STACK) {
|
||||
prop = PROPERTY_IPV4V6_STACK;
|
||||
AT_CellularBase::CellularProperty prop = PROPERTY_IPV4_PDP_TYPE;
|
||||
if (pdp_type == IPV6_PDP_TYPE) {
|
||||
prop = PROPERTY_IPV6_PDP_TYPE;
|
||||
} else if (pdp_type == IPV4V6_PDP_TYPE) {
|
||||
prop = PROPERTY_IPV4V6_PDP_TYPE;
|
||||
} else if (pdp_type == NON_IP_PDP_TYPE) {
|
||||
prop = PROPERTY_NON_IP_PDP_TYPE;
|
||||
}
|
||||
|
||||
return prop;
|
||||
}
|
||||
|
||||
nsapi_ip_stack_t AT_CellularContext::get_stack_type()
|
||||
pdp_type_t AT_CellularContext::string_to_pdp_type(const char *pdp_type)
|
||||
{
|
||||
return IPV4V6_STACK;
|
||||
}
|
||||
|
||||
nsapi_ip_stack_t AT_CellularContext::string_to_stack_type(const char *pdp_type)
|
||||
{
|
||||
return IPV4V6_STACK;
|
||||
return IPV4V6_PDP_TYPE;
|
||||
}
|
||||
|
||||
// PDP Context handling
|
||||
|
@ -236,3 +234,30 @@ void AT_CellularContext::cellular_callback(nsapi_event_t ev, intptr_t ptr)
|
|||
void AT_CellularContext::call_network_cb(nsapi_connection_status_t status)
|
||||
{
|
||||
}
|
||||
|
||||
ControlPlane_netif *AT_CellularContext::get_cp_netif()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
nsapi_error_t AT_CellularContext::activate_non_ip_context()
|
||||
{
|
||||
return NSAPI_ERROR_OK;
|
||||
}
|
||||
|
||||
nsapi_error_t AT_CellularContext::setup_control_plane_opt()
|
||||
{
|
||||
return NSAPI_ERROR_OK;
|
||||
}
|
||||
|
||||
void AT_CellularContext::deactivate_ip_context()
|
||||
{
|
||||
}
|
||||
|
||||
void AT_CellularContext::deactivate_non_ip_context()
|
||||
{
|
||||
}
|
||||
|
||||
void AT_CellularContext::set_disconnect()
|
||||
{
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ nsapi_error_t AT_CellularDevice::release_at_handler(ATHandler *at_handler)
|
|||
}
|
||||
|
||||
CellularContext *AT_CellularDevice::create_context(UARTSerial *serial, const char *const apn, PinName dcd_pin,
|
||||
bool active_high)
|
||||
bool active_high, bool cp_req, bool nonip_req)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -118,12 +118,12 @@ CellularContext *AT_CellularDevice::get_context_list() const
|
|||
return NULL;
|
||||
}
|
||||
|
||||
CellularContext *AT_CellularDevice::create_context(FileHandle *fh, const char *apn)
|
||||
CellularContext *AT_CellularDevice::create_context(FileHandle *fh, const char *apn, bool cp_req, bool nonip_req)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
AT_CellularContext *AT_CellularDevice::create_context_impl(ATHandler &at, const char *apn)
|
||||
AT_CellularContext *AT_CellularDevice::create_context_impl(ATHandler &at, const char *apn, bool cp_req, bool nonip_req)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -103,3 +103,6 @@ nsapi_error_t CellularDevice::shutdown()
|
|||
return NSAPI_ERROR_OK;
|
||||
}
|
||||
|
||||
void CellularDevice::cellular_callback(nsapi_event_t ev, intptr_t ptr)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -53,12 +53,12 @@ public:
|
|||
}
|
||||
|
||||
virtual CellularContext *create_context(UARTSerial *serial, const char *const apn, PinName dcd_pin,
|
||||
bool active_high)
|
||||
bool active_high, bool cp_req = false, bool nonip_req = false)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
virtual CellularContext *create_context(FileHandle *fh = NULL, const char *apn = NULL)
|
||||
virtual CellularContext *create_context(FileHandle *fh = NULL, const char *apn = NULL, bool cp_req = false, bool nonip_req = false)
|
||||
{
|
||||
EventQueue que;
|
||||
FileHandle_stub fh1;
|
||||
|
|
|
@ -19,9 +19,18 @@
|
|||
|
||||
#include "CellularBase.h"
|
||||
#include "CellularDevice.h"
|
||||
#include "ControlPlane_netif.h"
|
||||
|
||||
namespace mbed {
|
||||
|
||||
typedef enum pdp_type {
|
||||
DEFAULT_PDP_TYPE = DEFAULT_STACK,
|
||||
IPV4_PDP_TYPE = IPV4_STACK,
|
||||
IPV6_PDP_TYPE = IPV6_STACK,
|
||||
IPV4V6_PDP_TYPE = IPV4V6_STACK,
|
||||
NON_IP_PDP_TYPE
|
||||
} pdp_type_t;
|
||||
|
||||
/**
|
||||
* @addtogroup cellular
|
||||
* @{
|
||||
|
@ -31,6 +40,7 @@ namespace mbed {
|
|||
class CellularContext : public CellularBase {
|
||||
|
||||
public:
|
||||
|
||||
// max simultaneous PDP contexts active
|
||||
static const int PDP_CONTEXT_COUNT = 4;
|
||||
|
||||
|
@ -235,6 +245,10 @@ public: // from NetworkInterface
|
|||
*/
|
||||
virtual void set_file_handle(UARTSerial *serial, PinName dcd_pin = NC, bool active_high = false) = 0;
|
||||
|
||||
/** Returns the control plane AT command interface
|
||||
*/
|
||||
virtual ControlPlane_netif *get_cp_netif() = 0;
|
||||
|
||||
protected: // Device specific implementations might need these so protected
|
||||
enum ContextOperation {
|
||||
OP_INVALID = -1,
|
||||
|
@ -264,7 +278,7 @@ protected: // Device specific implementations might need these so protected
|
|||
|
||||
// member variables needed in target override methods
|
||||
NetworkStack *_stack; // must be pointer because of PPP
|
||||
nsapi_ip_stack_t _ip_stack_type;
|
||||
pdp_type_t _pdp_type;
|
||||
CellularContext::AuthenticationType _authentication_type;
|
||||
nsapi_connection_status_t _connect_status;
|
||||
cell_callback_data_t _cb_data;
|
||||
|
|
|
@ -97,11 +97,13 @@ public:
|
|||
* @param fh file handle used in communication to modem. This 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 cp_req flag indicating if EPS control plane optimisation is required
|
||||
* @param nonip_req flag indicating if this context is required to be Non-IP
|
||||
*
|
||||
* @return new instance of class CellularContext or NULL in case of failure
|
||||
*
|
||||
*/
|
||||
virtual CellularContext *create_context(FileHandle *fh = NULL, const char *apn = NULL) = 0;
|
||||
virtual CellularContext *create_context(FileHandle *fh = NULL, const char *apn = NULL, bool cp_req = false, bool nonip_req = false) = 0;
|
||||
|
||||
/** Creates a new CellularContext interface. This API should be used if serial is UART and PPP mode used.
|
||||
* CellularContext created will use data carrier detect to be able to detect disconnection much faster in PPP mode.
|
||||
|
@ -111,12 +113,14 @@ public:
|
|||
* @param apn access point to use with context, can be null.
|
||||
* @param dcd_pin Pin used to set data carrier detect on/off for the given UART
|
||||
* @param active_high a boolean set to true if DCD polarity is active low
|
||||
* @param cp_req Flag indicating if EPS control plane optimisation is required
|
||||
* @param nonip_req Flag indicating if this context is required to be Non-IP
|
||||
*
|
||||
* @return new instance of class CellularContext or NULL in case of failure
|
||||
*
|
||||
*/
|
||||
virtual CellularContext *create_context(UARTSerial *serial, const char *apn, PinName dcd_pin = NC,
|
||||
bool active_high = false) = 0;
|
||||
bool active_high = false, bool cp_req = false, bool nonip_req = false) = 0;
|
||||
|
||||
/** Deletes the given CellularContext instance
|
||||
*
|
||||
|
|
|
@ -49,9 +49,10 @@ public:
|
|||
PROPERTY_AT_CGSN_WITH_TYPE, // 0 = not supported, 1 = supported. AT+CGSN without type is likely always supported similar to AT+GSN.
|
||||
PROPERTY_AT_CGDATA, // 0 = not supported, 1 = supported. Alternative is to support only ATD*99***<cid>#
|
||||
PROPERTY_AT_CGAUTH, // 0 = not supported, 1 = supported. APN authentication AT commands supported
|
||||
PROPERTY_IPV4_STACK, // 0 = not supported, 1 = supported. Does modem support IPV4?
|
||||
PROPERTY_IPV6_STACK, // 0 = not supported, 1 = supported. Does modem support IPV6?
|
||||
PROPERTY_IPV4V6_STACK, // 0 = not supported, 1 = supported. Does modem support dual stack IPV4V6?
|
||||
PROPERTY_IPV4_PDP_TYPE, // 0 = not supported, 1 = supported. Does modem support IPV4?
|
||||
PROPERTY_IPV6_PDP_TYPE, // 0 = not supported, 1 = supported. Does modem support IPV6?
|
||||
PROPERTY_IPV4V6_PDP_TYPE, // 0 = not supported, 1 = supported. Does modem support dual stack IPV4V6?
|
||||
PROPERTY_NON_IP_PDP_TYPE, // 0 = not supported, 1 = supported. Does modem support Non-IP?
|
||||
PROPERTY_MAX
|
||||
};
|
||||
|
||||
|
|
|
@ -25,6 +25,9 @@
|
|||
|
||||
#define NETWORK_TIMEOUT 30 * 60 * 1000 // 30 minutes
|
||||
#define DEVICE_TIMEOUT 5 * 60 * 1000 // 5 minutes
|
||||
// Timeout to wait for URC indicating ciot optimization support from network
|
||||
#define CP_OPT_NW_REPLY_TIMEOUT 3000 // 3 seconds
|
||||
|
||||
|
||||
#if NSAPI_PPP_AVAILABLE
|
||||
#define AT_SYNC_TIMEOUT 1000 // 1 second timeout
|
||||
|
@ -41,13 +44,13 @@
|
|||
using namespace mbed_cellular_util;
|
||||
using namespace mbed;
|
||||
|
||||
AT_CellularContext::AT_CellularContext(ATHandler &at, CellularDevice *device, const char *apn) :
|
||||
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)
|
||||
AT_CellularContext::AT_CellularContext(ATHandler &at, CellularDevice *device, const char *apn, bool cp_req, bool nonip_req) :
|
||||
AT_CellularBase(at), _is_connected(false), _is_blocking(true),
|
||||
_current_op(OP_INVALID), _device(device), _nw(0), _fh(0), _cp_req(cp_req), _nonip_req(nonip_req), _cp_in_use(false), _cp_netif(NULL)
|
||||
{
|
||||
tr_info("New CellularContext %s (%p)", apn ? apn : "", this);
|
||||
_stack = NULL;
|
||||
_ip_stack_type = DEFAULT_STACK;
|
||||
_pdp_type = DEFAULT_PDP_TYPE;
|
||||
_authentication_type = CellularContext::CHAP;
|
||||
_connect_status = NSAPI_STATUS_DISCONNECTED;
|
||||
_is_context_active = false;
|
||||
|
@ -258,24 +261,21 @@ void AT_CellularContext::set_credentials(const char *apn, const char *uname, con
|
|||
_pwd = pwd;
|
||||
}
|
||||
|
||||
nsapi_ip_stack_t AT_CellularContext::get_stack_type()
|
||||
pdp_type_t AT_CellularContext::string_to_pdp_type(const char *pdp_type_str)
|
||||
{
|
||||
return _ip_stack_type;
|
||||
}
|
||||
pdp_type_t pdp_type = DEFAULT_PDP_TYPE;
|
||||
int len = strlen(pdp_type_str);
|
||||
|
||||
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;
|
||||
if (len == 6 && memcmp(pdp_type_str, "IPV4V6", len) == 0) {
|
||||
pdp_type = IPV4V6_PDP_TYPE;
|
||||
} else if (len == 4 && memcmp(pdp_type_str, "IPV6", len) == 0) {
|
||||
pdp_type = IPV6_PDP_TYPE;
|
||||
} else if (len == 2 && memcmp(pdp_type_str, "IP", len) == 0) {
|
||||
pdp_type = IPV4_PDP_TYPE;
|
||||
} else if (len == 6 && memcmp(pdp_type_str, "Non-IP", len) == 0) {
|
||||
pdp_type = NON_IP_PDP_TYPE;
|
||||
}
|
||||
return stack;
|
||||
return pdp_type;
|
||||
}
|
||||
|
||||
// PDP Context handling
|
||||
|
@ -316,19 +316,24 @@ nsapi_error_t AT_CellularContext::do_user_authentication()
|
|||
return NSAPI_ERROR_OK;
|
||||
}
|
||||
|
||||
AT_CellularBase::CellularProperty AT_CellularContext::nsapi_ip_stack_t_to_cellular_property(nsapi_ip_stack_t stack)
|
||||
AT_CellularBase::CellularProperty AT_CellularContext::pdp_type_t_to_cellular_property(pdp_type_t pdp_type)
|
||||
{
|
||||
AT_CellularBase::CellularProperty prop = PROPERTY_IPV4_STACK;
|
||||
if (stack == IPV6_STACK) {
|
||||
prop = PROPERTY_IPV6_STACK;
|
||||
} else if (stack == IPV4V6_STACK) {
|
||||
prop = PROPERTY_IPV4V6_STACK;
|
||||
AT_CellularBase::CellularProperty prop = PROPERTY_IPV4_PDP_TYPE;
|
||||
if (pdp_type == IPV6_PDP_TYPE) {
|
||||
prop = PROPERTY_IPV6_PDP_TYPE;
|
||||
} else if (pdp_type == IPV4V6_PDP_TYPE) {
|
||||
prop = PROPERTY_IPV4V6_PDP_TYPE;
|
||||
} else if (pdp_type == NON_IP_PDP_TYPE) {
|
||||
prop = PROPERTY_NON_IP_PDP_TYPE;
|
||||
}
|
||||
|
||||
return prop;
|
||||
}
|
||||
|
||||
bool AT_CellularContext::get_context()
|
||||
{
|
||||
bool modem_supports_ipv6 = get_property(PROPERTY_IPV6_PDP_TYPE);
|
||||
bool modem_supports_ipv4 = get_property(PROPERTY_IPV4_PDP_TYPE);
|
||||
_at.cmd_start("AT+CGDCONT?");
|
||||
_at.cmd_stop();
|
||||
_at.resp_start("+CGDCONT:");
|
||||
|
@ -337,9 +342,6 @@ bool AT_CellularContext::get_context()
|
|||
char apn[MAX_ACCESSPOINT_NAME_LENGTH];
|
||||
int apn_len = 0;
|
||||
|
||||
bool modem_supports_ipv6 = get_property(PROPERTY_IPV6_STACK);
|
||||
bool modem_supports_ipv4 = get_property(PROPERTY_IPV4_STACK);
|
||||
|
||||
while (_at.info_resp()) {
|
||||
int cid = _at.read_int();
|
||||
if (cid > cid_max) {
|
||||
|
@ -353,52 +355,20 @@ bool AT_CellularContext::get_context()
|
|||
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_property(nsapi_ip_stack_t_to_cellular_property(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;
|
||||
}
|
||||
// APN matched -> Check PDP type
|
||||
pdp_type_t pdp_type = string_to_pdp_type(pdp_type_from_context);
|
||||
|
||||
// Accept exact matching PDP context type or dual PDP context for IPv4/IPv6 only modems
|
||||
if (get_property(pdp_type_t_to_cellular_property(pdp_type)) ||
|
||||
((pdp_type == IPV4V6_PDP_TYPE && (modem_supports_ipv4 || modem_supports_ipv6)) && !_nonip_req)) {
|
||||
_pdp_type = pdp_type;
|
||||
_cid = cid;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_at.resp_stop();
|
||||
if (_cid == -1) { // no suitable context was found so create a new one
|
||||
if (!set_new_context(cid_max + 1)) {
|
||||
|
@ -418,75 +388,77 @@ bool AT_CellularContext::get_context()
|
|||
|
||||
bool AT_CellularContext::set_new_context(int cid)
|
||||
{
|
||||
nsapi_ip_stack_t tmp_stack = _ip_stack_type_requested;
|
||||
bool modem_supports_ipv6 = get_property(PROPERTY_IPV6_PDP_TYPE);
|
||||
bool modem_supports_ipv4 = get_property(PROPERTY_IPV4_PDP_TYPE);
|
||||
bool modem_supports_nonip = get_property(PROPERTY_NON_IP_PDP_TYPE);
|
||||
|
||||
if (tmp_stack == DEFAULT_STACK) {
|
||||
bool modem_supports_ipv6 = get_property(PROPERTY_IPV6_STACK);
|
||||
bool modem_supports_ipv4 = get_property(PROPERTY_IPV4_STACK);
|
||||
char pdp_type_str[8 + 1] = {0};
|
||||
pdp_type_t pdp_type = IPV4_PDP_TYPE;
|
||||
|
||||
if (modem_supports_ipv6 && modem_supports_ipv4) {
|
||||
tmp_stack = IPV4V6_STACK;
|
||||
if (_nonip_req && _cp_in_use && modem_supports_nonip) {
|
||||
strncpy(pdp_type_str, "Non-IP", sizeof(pdp_type_str));
|
||||
pdp_type = NON_IP_PDP_TYPE;
|
||||
} else if (modem_supports_ipv6 && modem_supports_ipv4) {
|
||||
strncpy(pdp_type_str, "IPV4V6", sizeof(pdp_type_str));
|
||||
pdp_type = IPV4V6_PDP_TYPE;
|
||||
} else if (modem_supports_ipv6) {
|
||||
tmp_stack = IPV6_STACK;
|
||||
strncpy(pdp_type_str, "IPV6", sizeof(pdp_type_str));
|
||||
pdp_type = IPV6_PDP_TYPE;
|
||||
} else if (modem_supports_ipv4) {
|
||||
tmp_stack = IPV4_STACK;
|
||||
strncpy(pdp_type_str, "IP", sizeof(pdp_type));
|
||||
pdp_type = IPV4_PDP_TYPE;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
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(pdp_type_str);
|
||||
_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) {
|
||||
_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_read_resp();
|
||||
success = (_at.get_last_error() == NSAPI_ERROR_OK);
|
||||
}
|
||||
|
||||
if (success) {
|
||||
_ip_stack_type = tmp_stack;
|
||||
_pdp_type = pdp_type;
|
||||
_cid = cid;
|
||||
_new_context_set = true;
|
||||
tr_info("New PDP context %d, stack %s", _cid, pdp_type);
|
||||
tr_info("New PDP context %d, type %s", _cid, pdp_type);
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
nsapi_error_t AT_CellularContext::do_activate_context()
|
||||
{
|
||||
if (_nonip_req && _cp_in_use) {
|
||||
return activate_non_ip_context();
|
||||
}
|
||||
|
||||
// In IP case but also when Non-IP is requested and
|
||||
// control plane optimisation is not established -> activate ip context
|
||||
_nonip_req = false;
|
||||
return activate_ip_context();
|
||||
}
|
||||
|
||||
nsapi_error_t AT_CellularContext::activate_ip_context()
|
||||
{
|
||||
return activate_context();
|
||||
}
|
||||
|
||||
nsapi_error_t AT_CellularContext::activate_non_ip_context()
|
||||
{
|
||||
return activate_context();
|
||||
}
|
||||
|
||||
nsapi_error_t AT_CellularContext::activate_context()
|
||||
{
|
||||
_at.lock();
|
||||
|
||||
nsapi_error_t err = NSAPI_ERROR_OK;
|
||||
|
||||
// try to find or create context with suitable stack
|
||||
// try to find or create context of suitable type
|
||||
if (get_context()) {
|
||||
#if NSAPI_PPP_AVAILABLE
|
||||
_at.unlock();
|
||||
|
@ -593,6 +565,12 @@ void AT_CellularContext::do_connect()
|
|||
#if NSAPI_PPP_AVAILABLE
|
||||
nsapi_error_t AT_CellularContext::open_data_channel()
|
||||
{
|
||||
// If Non-IP in use fail
|
||||
if (_pdp_type == NON_IP_PDP_TYPE) {
|
||||
tr_error("Attempt of PPP connect over NON-IP: failed to CONNECT");
|
||||
return NSAPI_ERROR_PARAMETER;
|
||||
}
|
||||
|
||||
tr_info("CellularContext PPP connect");
|
||||
if (get_property(PROPERTY_AT_CGDATA)) {
|
||||
_at.cmd_start("AT+CGDATA=\"PPP\",");
|
||||
|
@ -618,7 +596,7 @@ nsapi_error_t AT_CellularContext::open_data_channel()
|
|||
/* Initialize PPP
|
||||
* If blocking: mbed_ppp_init() is a blocking call, it will block until
|
||||
connected, or timeout after 30 seconds*/
|
||||
nsapi_error_t err = nsapi_ppp_connect(_at.get_file_handle(), callback(this, &AT_CellularContext::ppp_status_cb), _uname, _pwd, _ip_stack_type);
|
||||
nsapi_error_t err = nsapi_ppp_connect(_at.get_file_handle(), callback(this, &AT_CellularContext::ppp_status_cb), _uname, _pwd, (nsapi_ip_stack_t)_pdp_type);
|
||||
if (err) {
|
||||
ppp_disconnected();
|
||||
}
|
||||
|
@ -677,6 +655,31 @@ nsapi_error_t AT_CellularContext::disconnect()
|
|||
|
||||
// deactivate a context only if we have activated
|
||||
if (_is_context_activated) {
|
||||
if (_nonip_req && _cp_in_use) {
|
||||
deactivate_non_ip_context();
|
||||
} else {
|
||||
deactivate_ip_context();
|
||||
}
|
||||
}
|
||||
|
||||
_is_connected = false;
|
||||
call_network_cb(NSAPI_STATUS_DISCONNECTED);
|
||||
|
||||
return _at.unlock_return_error();
|
||||
}
|
||||
|
||||
void AT_CellularContext::deactivate_ip_context()
|
||||
{
|
||||
deactivate_context();
|
||||
}
|
||||
|
||||
void AT_CellularContext::deactivate_non_ip_context()
|
||||
{
|
||||
deactivate_context();
|
||||
}
|
||||
|
||||
void AT_CellularContext::deactivate_context()
|
||||
{
|
||||
// CGACT and CGATT commands might take up to 3 minutes to respond.
|
||||
_at.set_at_timeout(180 * 1000);
|
||||
_is_context_active = false;
|
||||
|
@ -716,16 +719,11 @@ nsapi_error_t AT_CellularContext::disconnect()
|
|||
_at.write_int(_cid);
|
||||
_at.cmd_stop_read_resp();
|
||||
}
|
||||
|
||||
_at.clear_error();
|
||||
_at.cmd_start("AT+CGATT=0");
|
||||
_at.cmd_stop_read_resp();
|
||||
_at.restore_at_timeout();
|
||||
}
|
||||
|
||||
_is_connected = false;
|
||||
call_network_cb(NSAPI_STATUS_DISCONNECTED);
|
||||
|
||||
return _at.unlock_return_error();
|
||||
}
|
||||
|
||||
nsapi_error_t AT_CellularContext::get_apn_backoff_timer(int &backoff_timer)
|
||||
|
@ -900,6 +898,16 @@ void AT_CellularContext::cellular_callback(nsapi_event_t ev, intptr_t ptr)
|
|||
|
||||
if (!_nw && st == CellularDeviceReady && data->error == NSAPI_ERROR_OK) {
|
||||
_nw = _device->open_network(_fh);
|
||||
tr_error("OPEN NETWORK");
|
||||
}
|
||||
|
||||
if (_cp_req && !_cp_in_use && (data->error == NSAPI_ERROR_OK) &&
|
||||
(st == CellularSIMStatusChanged && data->status_data == CellularDevice::SimStateReady)) {
|
||||
if (setup_control_plane_opt() != NSAPI_ERROR_OK) {
|
||||
tr_error("Control plane SETUP failed!");
|
||||
} else {
|
||||
tr_info("Control plane SETUP success!");
|
||||
}
|
||||
}
|
||||
|
||||
if (_is_blocking) {
|
||||
|
@ -969,3 +977,61 @@ void AT_CellularContext::call_network_cb(nsapi_connection_status_t status)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
ControlPlane_netif *AT_CellularContext::get_cp_netif()
|
||||
{
|
||||
tr_error("No control plane interface available from base context!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
nsapi_error_t AT_CellularContext::setup_control_plane_opt()
|
||||
{
|
||||
// check if control plane optimization already set
|
||||
mbed::CellularNetwork::CIoT_Supported_Opt supported_network_opt;
|
||||
|
||||
if (_nw->get_ciot_network_optimization_config(supported_network_opt)) {
|
||||
return NSAPI_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
if (supported_network_opt == mbed::CellularNetwork::CIOT_OPT_CONTROL_PLANE ||
|
||||
supported_network_opt == mbed::CellularNetwork::CIOT_OPT_BOTH) {
|
||||
_cp_in_use = true;
|
||||
return NSAPI_ERROR_OK;
|
||||
}
|
||||
|
||||
// ciot optimization not set by app so need to set it now
|
||||
nsapi_error_t ciot_opt_ret;
|
||||
ciot_opt_ret = _nw->set_ciot_optimization_config(mbed::CellularNetwork::CIOT_OPT_CONTROL_PLANE,
|
||||
mbed::CellularNetwork::PREFERRED_UE_OPT_CONTROL_PLANE,
|
||||
callback(this, &AT_CellularContext::ciot_opt_cb));
|
||||
|
||||
if (ciot_opt_ret != NSAPI_ERROR_OK) {
|
||||
return ciot_opt_ret;
|
||||
}
|
||||
|
||||
//wait for control plane opt call back to release semaphore
|
||||
_cp_opt_semaphore.wait(CP_OPT_NW_REPLY_TIMEOUT);
|
||||
|
||||
if (_cp_in_use) {
|
||||
return NSAPI_ERROR_OK;
|
||||
}
|
||||
|
||||
return NSAPI_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
void AT_CellularContext::ciot_opt_cb(mbed::CellularNetwork::CIoT_Supported_Opt ciot_opt)
|
||||
{
|
||||
if (ciot_opt == mbed::CellularNetwork::CIOT_OPT_CONTROL_PLANE ||
|
||||
ciot_opt == mbed::CellularNetwork::CIOT_OPT_BOTH) {
|
||||
_cp_in_use = true;
|
||||
}
|
||||
_cp_opt_semaphore.release();
|
||||
}
|
||||
|
||||
void AT_CellularContext::set_disconnect()
|
||||
{
|
||||
_is_connected = false;
|
||||
cell_callback_data_t data;
|
||||
data.error = NSAPI_STATUS_DISCONNECTED;
|
||||
_device->cellular_callback(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, (intptr_t)&data);
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ namespace mbed {
|
|||
|
||||
class AT_CellularContext : public CellularContext, public AT_CellularBase {
|
||||
public:
|
||||
AT_CellularContext(ATHandler &at, CellularDevice *device, const char *apn = 0);
|
||||
AT_CellularContext(ATHandler &at, CellularDevice *device, const char *apn = 0, bool cp_req = false, bool nonip_req = false);
|
||||
virtual ~AT_CellularContext();
|
||||
|
||||
// from CellularBase/NetworkInterface
|
||||
|
@ -60,6 +60,8 @@ public:
|
|||
virtual void set_file_handle(UARTSerial *serial, PinName dcd_pin = NC, bool active_high = false);
|
||||
virtual void enable_hup(bool enable);
|
||||
|
||||
virtual ControlPlane_netif *get_cp_netif();
|
||||
|
||||
protected:
|
||||
virtual void cellular_callback(nsapi_event_t ev, intptr_t ptr);
|
||||
|
||||
|
@ -91,6 +93,11 @@ protected:
|
|||
*/
|
||||
void call_network_cb(nsapi_connection_status_t status);
|
||||
|
||||
virtual nsapi_error_t activate_non_ip_context();
|
||||
virtual nsapi_error_t setup_control_plane_opt();
|
||||
virtual void deactivate_non_ip_context();
|
||||
virtual void set_disconnect();
|
||||
|
||||
private:
|
||||
#if NSAPI_PPP_AVAILABLE
|
||||
nsapi_error_t open_data_channel();
|
||||
|
@ -98,16 +105,19 @@ private:
|
|||
void ppp_disconnected();
|
||||
#endif // #if NSAPI_PPP_AVAILABLE
|
||||
nsapi_error_t do_activate_context();
|
||||
nsapi_error_t activate_context();
|
||||
nsapi_error_t activate_ip_context();
|
||||
void deactivate_context();
|
||||
void deactivate_ip_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();
|
||||
pdp_type_t string_to_pdp_type(const char *pdp_type);
|
||||
nsapi_error_t check_operation(nsapi_error_t err, ContextOperation op);
|
||||
AT_CellularBase::CellularProperty nsapi_ip_stack_t_to_cellular_property(nsapi_ip_stack_t stack);
|
||||
AT_CellularBase::CellularProperty pdp_type_t_to_cellular_property(pdp_type_t pdp_type);
|
||||
void ciot_opt_cb(mbed::CellularNetwork::CIoT_Supported_Opt ciot_opt);
|
||||
|
||||
private:
|
||||
nsapi_ip_stack_t _ip_stack_type_requested;
|
||||
bool _is_connected;
|
||||
bool _is_blocking;
|
||||
ContextOperation _current_op;
|
||||
|
@ -116,6 +126,18 @@ private:
|
|||
CellularNetwork *_nw;
|
||||
FileHandle *_fh;
|
||||
rtos::Semaphore _semaphore;
|
||||
rtos::Semaphore _cp_opt_semaphore;
|
||||
|
||||
protected:
|
||||
// flag indicating if CP was requested to be setup
|
||||
bool _cp_req;
|
||||
// flag indicating if Non-IP context was requested to be setup
|
||||
bool _nonip_req;
|
||||
|
||||
// tells if CCIOTOPTI received green from network for CP optimisation use
|
||||
bool _cp_in_use;
|
||||
|
||||
ControlPlane_netif *_cp_netif;
|
||||
};
|
||||
|
||||
} // namespace mbed
|
||||
|
|
|
@ -168,19 +168,19 @@ CellularContext *AT_CellularDevice::get_context_list() const
|
|||
}
|
||||
|
||||
CellularContext *AT_CellularDevice::create_context(UARTSerial *serial, const char *const apn, PinName dcd_pin,
|
||||
bool active_high)
|
||||
bool active_high, bool cp_req, bool nonip_req)
|
||||
{
|
||||
// Call FileHandle base version - explict upcast to avoid recursing into ourselves
|
||||
CellularContext *ctx = create_context(static_cast<FileHandle *>(serial), apn);
|
||||
CellularContext *ctx = create_context(static_cast<FileHandle *>(serial), apn, cp_req, nonip_req);
|
||||
if (serial) {
|
||||
ctx->set_file_handle(serial, dcd_pin, active_high);
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
CellularContext *AT_CellularDevice::create_context(FileHandle *fh, const char *apn)
|
||||
CellularContext *AT_CellularDevice::create_context(FileHandle *fh, const char *apn, bool cp_req, bool nonip_req)
|
||||
{
|
||||
AT_CellularContext *ctx = create_context_impl(*get_at_handler(fh), apn);
|
||||
AT_CellularContext *ctx = create_context_impl(*get_at_handler(fh), apn, cp_req, nonip_req);
|
||||
AT_CellularContext *curr = _context_list;
|
||||
|
||||
if (_context_list == NULL) {
|
||||
|
@ -198,9 +198,12 @@ CellularContext *AT_CellularDevice::create_context(FileHandle *fh, const char *a
|
|||
return ctx;
|
||||
}
|
||||
|
||||
AT_CellularContext *AT_CellularDevice::create_context_impl(ATHandler &at, const char *apn)
|
||||
AT_CellularContext *AT_CellularDevice::create_context_impl(ATHandler &at, const char *apn, bool cp_req, bool nonip_req)
|
||||
{
|
||||
return new AT_CellularContext(at, this, apn);
|
||||
if (cp_req) {
|
||||
|
||||
}
|
||||
return new AT_CellularContext(at, this, apn, cp_req, nonip_req);
|
||||
}
|
||||
|
||||
void AT_CellularDevice::delete_context(CellularContext *context)
|
||||
|
|
|
@ -44,9 +44,9 @@ public:
|
|||
|
||||
virtual nsapi_error_t get_sim_state(SimState &state);
|
||||
|
||||
virtual CellularContext *create_context(FileHandle *fh = NULL, const char *apn = NULL);
|
||||
virtual CellularContext *create_context(FileHandle *fh = NULL, const char *apn = NULL, bool cp_req = false, bool nonip_req = false);
|
||||
|
||||
virtual CellularContext *create_context(UARTSerial *serial, const char *const apn, PinName dcd_pin = NC, bool active_high = false);
|
||||
virtual CellularContext *create_context(UARTSerial *serial, const char *const apn, PinName dcd_pin = NC, bool active_high = false, bool cp_req = false, bool nonip_req = false);
|
||||
|
||||
virtual void delete_context(CellularContext *context);
|
||||
|
||||
|
@ -103,7 +103,7 @@ public:
|
|||
* @return new instance of class AT_CellularContext
|
||||
*
|
||||
*/
|
||||
virtual AT_CellularContext *create_context_impl(ATHandler &at, const char *apn);
|
||||
virtual AT_CellularContext *create_context_impl(ATHandler &at, const char *apn, bool cp_req = false, bool nonip_req = false);
|
||||
|
||||
/** Create new instance of AT_CellularNetwork or if overridden, modem specific implementation.
|
||||
*
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
/*AT_ControlPlane_netif.cpp*/
|
||||
#include "AT_ControlPlane_netif.h"
|
||||
|
||||
namespace mbed {
|
||||
|
||||
AT_ControlPlane_netif::AT_ControlPlane_netif(ATHandler &at, int cid) : AT_CellularBase(at),
|
||||
_cid(cid), _cb(NULL), _data(NULL), _recv_len(0)
|
||||
{
|
||||
_at.set_urc_handler("+CRTDCP:", mbed::Callback<void()>(this, &AT_ControlPlane_netif::urc_cp_recv));
|
||||
}
|
||||
|
||||
AT_ControlPlane_netif::~AT_ControlPlane_netif()
|
||||
{}
|
||||
|
||||
void AT_ControlPlane_netif::urc_cp_recv()
|
||||
{
|
||||
//+CRTDCP: <cid>,<cpdata_length>,<cpdata>
|
||||
_at.lock();
|
||||
int cid = _at.read_int();
|
||||
int cpdata_length = _at.read_int();
|
||||
int read_len = _at.read_string(_recv_buffer, sizeof(_recv_buffer));
|
||||
|
||||
_at.unlock();
|
||||
|
||||
// cid not expected to be different because: one context - one file handle
|
||||
// so this file handle cannot get urc from different context
|
||||
if (read_len > 0 && read_len == cpdata_length && cid == _cid) {
|
||||
_recv_len = read_len;
|
||||
data_received();
|
||||
}
|
||||
}
|
||||
|
||||
nsapi_size_or_error_t AT_ControlPlane_netif::send(const void *cpdata, nsapi_size_t cpdata_length)
|
||||
{
|
||||
//CSODCP
|
||||
_at.lock();
|
||||
_at.cmd_start("AT+CSODCP=");
|
||||
_at.write_int(_cid);
|
||||
_at.write_int(cpdata_length);
|
||||
_at.write_bytes((uint8_t *)cpdata, cpdata_length);
|
||||
|
||||
return _at.unlock_return_error();
|
||||
}
|
||||
|
||||
nsapi_size_or_error_t AT_ControlPlane_netif::recv(void *cpdata, nsapi_size_t cpdata_length)
|
||||
{
|
||||
// If no data received through CRTDCP URC
|
||||
if (!_recv_len) {
|
||||
return NSAPI_ERROR_WOULD_BLOCK;
|
||||
}
|
||||
|
||||
// If too small buffer for data
|
||||
if (_recv_len > cpdata_length) {
|
||||
return NSAPI_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
memcpy(cpdata, _recv_buffer, _recv_len);
|
||||
|
||||
return _recv_len = 0;
|
||||
}
|
||||
|
||||
void AT_ControlPlane_netif::attach(void (*callback)(void *), void *data)
|
||||
{
|
||||
_cb = callback;
|
||||
_data = data;
|
||||
}
|
||||
|
||||
void AT_ControlPlane_netif::data_received()
|
||||
{
|
||||
// call socket event
|
||||
if (!_cb) {
|
||||
return;
|
||||
}
|
||||
_cb(_data);
|
||||
}
|
||||
|
||||
} //mbed namespace
|
|
@ -0,0 +1,32 @@
|
|||
#include "ControlPlane_netif.h"
|
||||
#include "ATHandler.h"
|
||||
#include "AT_CellularBase.h"
|
||||
|
||||
namespace mbed {
|
||||
|
||||
class AT_ControlPlane_netif: public ControlPlane_netif, public AT_CellularBase {
|
||||
public:
|
||||
AT_ControlPlane_netif(ATHandler &at, int cid);
|
||||
virtual ~AT_ControlPlane_netif();
|
||||
|
||||
// ControlPlane_netif
|
||||
// +CSODCP: 3GPP 27007 10.1.43
|
||||
virtual nsapi_size_or_error_t send(const void *cpdata, nsapi_size_t cpdata_length);
|
||||
// +CRTDCP: 3GPP 27007 10.1.44
|
||||
virtual nsapi_size_or_error_t recv(void *cpdata, nsapi_size_t cpdata_length);
|
||||
virtual void attach(void (*callback)(void *), void *data);
|
||||
virtual void data_received();
|
||||
|
||||
protected:
|
||||
// Id of the PDP context that enables the control plane data connection
|
||||
int _cid;
|
||||
|
||||
private:
|
||||
void (*_cb)(void *);
|
||||
void *_data;
|
||||
char _recv_buffer[MAX_CP_DATA_RECV_LEN];
|
||||
size_t _recv_len;
|
||||
void urc_cp_recv();
|
||||
};
|
||||
|
||||
} //mbed namespace
|
|
@ -36,9 +36,9 @@ GEMALTO_CINTERION::~GEMALTO_CINTERION()
|
|||
{
|
||||
}
|
||||
|
||||
AT_CellularContext *GEMALTO_CINTERION::create_context_impl(ATHandler &at, const char *apn)
|
||||
AT_CellularContext *GEMALTO_CINTERION::create_context_impl(ATHandler &at, const char *apn, bool cp_req, bool nonip_req)
|
||||
{
|
||||
return new GEMALTO_CINTERION_CellularContext(at, this, apn);
|
||||
return new GEMALTO_CINTERION_CellularContext(at, this, apn, cp_req, nonip_req);
|
||||
}
|
||||
|
||||
nsapi_error_t GEMALTO_CINTERION::init()
|
||||
|
|
|
@ -40,7 +40,7 @@ public:
|
|||
static Module get_module();
|
||||
|
||||
protected: // AT_CellularDevice
|
||||
virtual AT_CellularContext *create_context_impl(ATHandler &at, const char *apn);
|
||||
virtual AT_CellularContext *create_context_impl(ATHandler &at, const char *apn, bool cp_req = false, bool nonip_req = false);
|
||||
protected:
|
||||
virtual uint16_t get_send_delay() const;
|
||||
virtual nsapi_error_t init();
|
||||
|
|
|
@ -16,11 +16,12 @@
|
|||
*/
|
||||
#include "GEMALTO_CINTERION_CellularContext.h"
|
||||
#include "GEMALTO_CINTERION_CellularStack.h"
|
||||
#include "CellularLog.h"
|
||||
|
||||
namespace mbed {
|
||||
|
||||
GEMALTO_CINTERION_CellularContext::GEMALTO_CINTERION_CellularContext(ATHandler &at, CellularDevice *device,
|
||||
const char *apn) : AT_CellularContext(at, device, apn)
|
||||
const char *apn, bool cp_req, bool nonip_req) : AT_CellularContext(at, device, apn, cp_req, nonip_req)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -31,8 +32,13 @@ GEMALTO_CINTERION_CellularContext::~GEMALTO_CINTERION_CellularContext()
|
|||
#if !NSAPI_PPP_AVAILABLE
|
||||
NetworkStack *GEMALTO_CINTERION_CellularContext::get_stack()
|
||||
{
|
||||
if (_pdp_type == NON_IP_PDP_TYPE || _cp_in_use) {
|
||||
tr_error("Requesting stack for NON-IP context! Should request control plane netif: get_cp_netif()");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!_stack) {
|
||||
_stack = new GEMALTO_CINTERION_CellularStack(_at, _apn, _cid, _ip_stack_type);
|
||||
_stack = new GEMALTO_CINTERION_CellularStack(_at, _apn, _cid, (nsapi_ip_stack_t)_pdp_type);
|
||||
}
|
||||
return _stack;
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ namespace mbed {
|
|||
|
||||
class GEMALTO_CINTERION_CellularContext: public AT_CellularContext {
|
||||
public:
|
||||
GEMALTO_CINTERION_CellularContext(ATHandler &at, CellularDevice *device, const char *apn);
|
||||
GEMALTO_CINTERION_CellularContext(ATHandler &at, CellularDevice *device, const char *apn, bool cp_req = false, bool nonip_req = false);
|
||||
virtual ~GEMALTO_CINTERION_CellularContext();
|
||||
|
||||
protected:
|
||||
|
|
|
@ -71,9 +71,9 @@ AT_CellularNetwork *QUECTEL_BC95::open_network_impl(ATHandler &at)
|
|||
return new QUECTEL_BC95_CellularNetwork(at);
|
||||
}
|
||||
|
||||
AT_CellularContext *QUECTEL_BC95::create_context_impl(ATHandler &at, const char *apn)
|
||||
AT_CellularContext *QUECTEL_BC95::create_context_impl(ATHandler &at, const char *apn, bool cp_req, bool nonip_req)
|
||||
{
|
||||
return new QUECTEL_BC95_CellularContext(at, this, apn);
|
||||
return new QUECTEL_BC95_CellularContext(at, this, apn, cp_req, nonip_req);
|
||||
}
|
||||
|
||||
AT_CellularInformation *QUECTEL_BC95::open_information_impl(ATHandler &at)
|
||||
|
|
|
@ -32,7 +32,7 @@ public: // AT_CellularDevice
|
|||
|
||||
protected: // AT_CellularDevice
|
||||
virtual AT_CellularNetwork *open_network_impl(ATHandler &at);
|
||||
virtual AT_CellularContext *create_context_impl(ATHandler &at, const char *apn);
|
||||
virtual AT_CellularContext *create_context_impl(ATHandler &at, const char *apn, bool cp_req = false, bool nonip_req = false);
|
||||
virtual AT_CellularInformation *open_information_impl(ATHandler &at);
|
||||
virtual nsapi_error_t init();
|
||||
virtual nsapi_error_t reset();
|
||||
|
|
|
@ -16,11 +16,12 @@
|
|||
*/
|
||||
#include "QUECTEL_BC95_CellularContext.h"
|
||||
#include "QUECTEL_BC95_CellularStack.h"
|
||||
#include "CellularLog.h"
|
||||
|
||||
namespace mbed {
|
||||
|
||||
QUECTEL_BC95_CellularContext::QUECTEL_BC95_CellularContext(ATHandler &at, CellularDevice *device, const char *apn) :
|
||||
AT_CellularContext(at, device, apn)
|
||||
QUECTEL_BC95_CellularContext::QUECTEL_BC95_CellularContext(ATHandler &at, CellularDevice *device, const char *apn, bool cp_req, bool nonip_req) :
|
||||
AT_CellularContext(at, device, apn, cp_req, nonip_req)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -31,8 +32,13 @@ QUECTEL_BC95_CellularContext::~QUECTEL_BC95_CellularContext()
|
|||
#if !NSAPI_PPP_AVAILABLE
|
||||
NetworkStack *QUECTEL_BC95_CellularContext::get_stack()
|
||||
{
|
||||
if (_pdp_type == NON_IP_PDP_TYPE || _cp_in_use) {
|
||||
tr_error("Requesting stack for NON-IP context! Should request control plane netif: get_cp_netif()");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!_stack) {
|
||||
_stack = new QUECTEL_BC95_CellularStack(_at, _cid, _ip_stack_type);
|
||||
_stack = new QUECTEL_BC95_CellularStack(_at, _cid, (nsapi_ip_stack_t)_pdp_type);
|
||||
}
|
||||
return _stack;
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ namespace mbed {
|
|||
|
||||
class QUECTEL_BC95_CellularContext: public AT_CellularContext {
|
||||
public:
|
||||
QUECTEL_BC95_CellularContext(ATHandler &at, CellularDevice *device, const char *apn);
|
||||
QUECTEL_BC95_CellularContext(ATHandler &at, CellularDevice *device, const char *apn, bool cp_req = false, bool nonip_req = false);
|
||||
virtual ~QUECTEL_BC95_CellularContext();
|
||||
|
||||
protected:
|
||||
|
|
|
@ -40,6 +40,7 @@ static const intptr_t cellular_properties[AT_CellularBase::PROPERTY_MAX] = {
|
|||
1, // PROPERTY_IPV4_STACK
|
||||
0, // PROPERTY_IPV6_STACK
|
||||
0, // PROPERTY_IPV4V6_STACK
|
||||
1, // PROPERTY_NON_IP_PDP_TYPE
|
||||
};
|
||||
|
||||
QUECTEL_BG96::QUECTEL_BG96(FileHandle *fh) : AT_CellularDevice(fh)
|
||||
|
@ -56,9 +57,9 @@ AT_CellularNetwork *QUECTEL_BG96::open_network_impl(ATHandler &at)
|
|||
return new QUECTEL_BG96_CellularNetwork(at);
|
||||
}
|
||||
|
||||
AT_CellularContext *QUECTEL_BG96::create_context_impl(ATHandler &at, const char *apn)
|
||||
AT_CellularContext *QUECTEL_BG96::create_context_impl(ATHandler &at, const char *apn, bool cp_req, bool nonip_req)
|
||||
{
|
||||
return new QUECTEL_BG96_CellularContext(at, this, apn);
|
||||
return new QUECTEL_BG96_CellularContext(at, this, apn, cp_req, nonip_req);
|
||||
}
|
||||
|
||||
AT_CellularInformation *QUECTEL_BG96::open_information_impl(ATHandler &at)
|
||||
|
|
|
@ -29,7 +29,7 @@ public:
|
|||
|
||||
protected: // AT_CellularDevice
|
||||
virtual AT_CellularNetwork *open_network_impl(ATHandler &at);
|
||||
virtual AT_CellularContext *create_context_impl(ATHandler &at, const char *apn);
|
||||
virtual AT_CellularContext *create_context_impl(ATHandler &at, const char *apn, bool cp_req = false, bool nonip_req = false);
|
||||
virtual AT_CellularInformation *open_information_impl(ATHandler &at);
|
||||
virtual void set_ready_cb(Callback<void()> callback);
|
||||
|
||||
|
|
|
@ -16,28 +16,57 @@
|
|||
*/
|
||||
#include "QUECTEL_BG96_CellularContext.h"
|
||||
#include "QUECTEL_BG96_CellularStack.h"
|
||||
#include "QUECTEL_BG96_ControlPlane_netif.h"
|
||||
#include "CellularLog.h"
|
||||
|
||||
#include "Semaphore.h"
|
||||
|
||||
namespace mbed {
|
||||
|
||||
QUECTEL_BG96_CellularContext::QUECTEL_BG96_CellularContext(ATHandler &at, CellularDevice *device, const char *apn) :
|
||||
AT_CellularContext(at, device, apn)
|
||||
// Non-IP context supported only for context id 1
|
||||
#define NIDD_PDP_CONTEXT_ID 1
|
||||
// Timeout to wait for URC indicating NIDD connection opening
|
||||
#define NIDD_OPEN_URC_TIMEOUT 3000
|
||||
|
||||
QUECTEL_BG96_CellularContext::QUECTEL_BG96_CellularContext(ATHandler &at, CellularDevice *device, const char *apn, bool cp_req, bool nonip_req) :
|
||||
AT_CellularContext(at, device, apn, cp_req, nonip_req)
|
||||
{
|
||||
if (_nonip_req) {
|
||||
_at.set_urc_handler("+QIND:", mbed::Callback<void()>(this, &QUECTEL_BG96_CellularContext::urc_nidd));
|
||||
}
|
||||
}
|
||||
|
||||
QUECTEL_BG96_CellularContext::~QUECTEL_BG96_CellularContext()
|
||||
{
|
||||
if (_nonip_req) {
|
||||
_at.set_urc_handler("+QIND:", 0);
|
||||
}
|
||||
}
|
||||
|
||||
#if !NSAPI_PPP_AVAILABLE
|
||||
NetworkStack *QUECTEL_BG96_CellularContext::get_stack()
|
||||
{
|
||||
if (!_stack) {
|
||||
_stack = new QUECTEL_BG96_CellularStack(_at, _cid, _ip_stack_type);
|
||||
if (_pdp_type == NON_IP_PDP_TYPE || (_nonip_req && _pdp_type != DEFAULT_PDP_TYPE)) {
|
||||
tr_error("Requesting stack for NON-IP context! Should request control plane netif: get_cp_netif()");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!_stack) {
|
||||
_stack = new QUECTEL_BG96_CellularStack(_at, _cid, (nsapi_ip_stack_t)_pdp_type);
|
||||
}
|
||||
|
||||
return _stack;
|
||||
}
|
||||
#endif // #if !NSAPI_PPP_AVAILABLE
|
||||
|
||||
ControlPlane_netif *QUECTEL_BG96_CellularContext::get_cp_netif()
|
||||
{
|
||||
if (!_cp_netif) {
|
||||
_cp_netif = new QUECTEL_BG96_ControlPlane_netif(_at, _cid);
|
||||
}
|
||||
return _cp_netif;
|
||||
}
|
||||
|
||||
nsapi_error_t QUECTEL_BG96_CellularContext::do_user_authentication()
|
||||
{
|
||||
if (_pwd && _uname) {
|
||||
|
@ -59,4 +88,110 @@ nsapi_error_t QUECTEL_BG96_CellularContext::do_user_authentication()
|
|||
return NSAPI_ERROR_OK;
|
||||
}
|
||||
|
||||
nsapi_error_t QUECTEL_BG96_CellularContext::activate_non_ip_context()
|
||||
{
|
||||
_at.lock();
|
||||
|
||||
// Open the NIDD connection
|
||||
_at.cmd_start("AT+QCFGEXT=\"nipd\",1");
|
||||
_at.cmd_stop();
|
||||
_at.resp_start();
|
||||
_at.resp_stop();
|
||||
|
||||
nsapi_size_or_error_t ret = _at.get_last_error();
|
||||
|
||||
_at.unlock();
|
||||
|
||||
if (ret == NSAPI_ERROR_OK) {
|
||||
_semaphore.wait(NIDD_OPEN_URC_TIMEOUT);
|
||||
if (_cid == -1) {
|
||||
return NSAPI_ERROR_NO_CONNECTION;
|
||||
}
|
||||
}
|
||||
|
||||
return (ret == NSAPI_ERROR_OK) ? NSAPI_ERROR_OK : NSAPI_ERROR_NO_CONNECTION;
|
||||
}
|
||||
|
||||
void QUECTEL_BG96_CellularContext::deactivate_non_ip_context()
|
||||
{
|
||||
// Close the NIDD connection
|
||||
_at.cmd_start("AT+QCFGEXT=\"nipd\",0");
|
||||
_at.cmd_stop();
|
||||
_at.resp_start();
|
||||
_at.resp_stop();
|
||||
|
||||
}
|
||||
|
||||
void QUECTEL_BG96_CellularContext::urc_nidd()
|
||||
{
|
||||
char nipd_string[6];
|
||||
|
||||
// skip "nipd"
|
||||
_at.skip_param();
|
||||
_at.read_string(nipd_string, sizeof(nipd_string));
|
||||
|
||||
if (!strcmp(nipd_string, "recv")) {
|
||||
_cp_netif->data_received();
|
||||
} else if (!strcmp(nipd_string, "open")) {
|
||||
urc_nidd_open();
|
||||
} else if (!strcmp(nipd_string, "close")) {
|
||||
urc_nidd_close();
|
||||
}
|
||||
}
|
||||
|
||||
void QUECTEL_BG96_CellularContext::urc_nidd_open()
|
||||
{
|
||||
int err = _at.read_int();
|
||||
if (!err) {
|
||||
_is_context_active = true;
|
||||
_is_context_activated = true;
|
||||
_cid = NIDD_PDP_CONTEXT_ID;
|
||||
} else {
|
||||
tr_error("NIDD connection open failed with error: %d", err);
|
||||
}
|
||||
_semaphore.release();
|
||||
}
|
||||
|
||||
void QUECTEL_BG96_CellularContext::urc_nidd_close()
|
||||
{
|
||||
set_disconnect();
|
||||
}
|
||||
|
||||
nsapi_error_t QUECTEL_BG96_CellularContext::setup_control_plane_opt()
|
||||
{
|
||||
_at.lock();
|
||||
|
||||
_at.cmd_start("AT+QCFGEXT=\"pdp_type\",");
|
||||
_at.write_int(NIDD_PDP_CONTEXT_ID);
|
||||
_at.write_string("Non-IP");
|
||||
_at.write_string(_apn);
|
||||
_at.cmd_stop();
|
||||
_at.resp_start();
|
||||
_at.resp_stop();
|
||||
_at.cmd_start("AT+CFUN=0");
|
||||
_at.cmd_stop();
|
||||
_at.resp_start();
|
||||
_at.resp_stop();
|
||||
_at.cmd_start("AT+CFUN=1");
|
||||
_at.cmd_stop();
|
||||
_at.resp_start();
|
||||
_at.resp_stop();
|
||||
|
||||
// Configure Non-IP outgoing data type - 0 for no exception data
|
||||
_at.cmd_start("AT+QCFGEXT=\"nipdcfg\",0,");
|
||||
_at.write_string(_apn);
|
||||
_at.cmd_stop();
|
||||
_at.resp_start();
|
||||
_at.resp_stop();
|
||||
|
||||
if (_at.get_last_error() == NSAPI_ERROR_OK) {
|
||||
_cp_in_use = true;
|
||||
if (_nonip_req) {
|
||||
_pdp_type = NON_IP_PDP_TYPE;
|
||||
}
|
||||
}
|
||||
|
||||
return _at.unlock_return_error();
|
||||
}
|
||||
|
||||
} /* namespace mbed */
|
||||
|
|
|
@ -23,14 +23,24 @@ namespace mbed {
|
|||
|
||||
class QUECTEL_BG96_CellularContext: public AT_CellularContext {
|
||||
public:
|
||||
QUECTEL_BG96_CellularContext(ATHandler &at, CellularDevice *device, const char *apn);
|
||||
QUECTEL_BG96_CellularContext(ATHandler &at, CellularDevice *device, const char *apn, bool cp_req = false, bool nonip_req = false);
|
||||
virtual ~QUECTEL_BG96_CellularContext();
|
||||
|
||||
protected:
|
||||
#if !NSAPI_PPP_AVAILABLE
|
||||
virtual NetworkStack *get_stack();
|
||||
#endif // #if !NSAPI_PPP_AVAILABLE
|
||||
virtual ControlPlane_netif *get_cp_netif();
|
||||
virtual nsapi_error_t do_user_authentication();
|
||||
virtual nsapi_error_t activate_non_ip_context();
|
||||
virtual nsapi_error_t setup_control_plane_opt();
|
||||
virtual void deactivate_non_ip_context();
|
||||
rtos::Semaphore _semaphore;
|
||||
|
||||
private:
|
||||
void urc_nidd();
|
||||
void urc_nidd_open();
|
||||
void urc_nidd_close();
|
||||
};
|
||||
|
||||
} /* namespace mbed */
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
#include "QUECTEL_BG96_ControlPlane_netif.h"
|
||||
|
||||
namespace mbed {
|
||||
|
||||
QUECTEL_BG96_ControlPlane_netif::QUECTEL_BG96_ControlPlane_netif(ATHandler &at, int cid) : AT_ControlPlane_netif(at, cid)
|
||||
{}
|
||||
|
||||
nsapi_size_or_error_t QUECTEL_BG96_ControlPlane_netif::send(const void *data, nsapi_size_t size)
|
||||
{
|
||||
_at.lock();
|
||||
|
||||
_at.cmd_start("AT+QCFGEXT=\"nipds\",0,");
|
||||
_at.write_string((char *)data);
|
||||
_at.write_int(size);
|
||||
_at.cmd_stop();
|
||||
_at.resp_start();
|
||||
_at.resp_stop();
|
||||
|
||||
nsapi_error_t err = _at.get_last_error();
|
||||
|
||||
_at.unlock();
|
||||
|
||||
if (err == NSAPI_ERROR_OK) {
|
||||
return size;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
nsapi_size_or_error_t QUECTEL_BG96_ControlPlane_netif::recv(void *buffer, nsapi_size_t size)
|
||||
{
|
||||
_at.lock();
|
||||
|
||||
_at.cmd_start("AT+QCFGEXT=\"nipdr\",0");
|
||||
_at.cmd_stop();
|
||||
_at.resp_start("+QCFGEXT: ");
|
||||
// skip 3 params: "nipdr",<total_receive_length>,<have_read_length>
|
||||
_at.skip_param(3);
|
||||
// get to <unread_length>
|
||||
int unread_length = _at.read_int();
|
||||
_at.resp_stop();
|
||||
|
||||
if (!unread_length || unread_length == -1) {
|
||||
_at.unlock();
|
||||
return NSAPI_ERROR_WOULD_BLOCK;
|
||||
}
|
||||
|
||||
_at.cmd_start("AT+QCFGEXT=\"nipdr\",");
|
||||
_at.write_int(unread_length);
|
||||
_at.cmd_stop();
|
||||
|
||||
_at.resp_start("+QCFGEXT:");
|
||||
// skip "nipdr"
|
||||
_at.skip_param();
|
||||
int read_length = _at.read_int();
|
||||
_at.read_string((char *)buffer, read_length);
|
||||
_at.resp_stop();
|
||||
nsapi_error_t err = _at.get_last_error();
|
||||
_at.unlock();
|
||||
|
||||
if (err == NSAPI_ERROR_OK && read_length) {
|
||||
return read_length;
|
||||
}
|
||||
|
||||
return NSAPI_ERROR_WOULD_BLOCK;
|
||||
}
|
||||
|
||||
} // mbed namespace
|
|
@ -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_BG96_CONTROLPLANE_NETIF_H_
|
||||
#define QUECTEL_BG96_CONTROLPLANE_NETIF_H_
|
||||
|
||||
#include "AT_ControlPlane_netif.h"
|
||||
|
||||
namespace mbed {
|
||||
|
||||
class QUECTEL_BG96_ControlPlane_netif: public AT_ControlPlane_netif {
|
||||
public:
|
||||
QUECTEL_BG96_ControlPlane_netif(ATHandler &at, int cid);
|
||||
virtual ~QUECTEL_BG96_ControlPlane_netif() {};
|
||||
|
||||
// ControlPlane_netif
|
||||
nsapi_size_or_error_t send(const void *data, nsapi_size_t size);
|
||||
nsapi_size_or_error_t recv(void *buffer, nsapi_size_t size);
|
||||
};
|
||||
|
||||
} /* namespace mbed */
|
||||
|
||||
#endif // QUECTEL_BG96_CONTROLPLANE_NETIF_H_
|
|
@ -53,7 +53,7 @@ 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)
|
||||
AT_CellularContext *QUECTEL_UG96::create_context_impl(ATHandler &at, const char *apn, bool cp_req, bool nonip_req)
|
||||
{
|
||||
return new QUECTEL_UG96_CellularContext(at, this, apn);
|
||||
return new QUECTEL_UG96_CellularContext(at, this, apn, cp_req, nonip_req);
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ public:
|
|||
|
||||
protected: // AT_CellularDevice
|
||||
virtual AT_CellularPower *open_power_impl(ATHandler &at);
|
||||
virtual AT_CellularContext *create_context_impl(ATHandler &at, const char *apn);
|
||||
virtual AT_CellularContext *create_context_impl(ATHandler &at, const char *apn, bool cp_req = false, bool nonip_req = false);
|
||||
|
||||
public: // NetworkInterface
|
||||
void handle_urc(FileHandle *fh);
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
|
||||
namespace mbed {
|
||||
|
||||
QUECTEL_UG96_CellularContext::QUECTEL_UG96_CellularContext(ATHandler &at, CellularDevice *device, const char *apn) :
|
||||
AT_CellularContext(at, device, apn)
|
||||
QUECTEL_UG96_CellularContext::QUECTEL_UG96_CellularContext(ATHandler &at, CellularDevice *device, const char *apn, bool cp_req, bool nonip_req) :
|
||||
AT_CellularContext(at, device, apn, cp_req, nonip_req)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ namespace mbed {
|
|||
|
||||
class QUECTEL_UG96_CellularContext: public AT_CellularContext {
|
||||
public:
|
||||
QUECTEL_UG96_CellularContext(ATHandler &at, CellularDevice *device, const char *apn);
|
||||
QUECTEL_UG96_CellularContext(ATHandler &at, CellularDevice *device, const char *apn, bool cp_req = false, bool nonip_req = false);
|
||||
virtual ~QUECTEL_UG96_CellularContext();
|
||||
|
||||
protected:
|
||||
|
|
|
@ -69,7 +69,7 @@ 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)
|
||||
AT_CellularContext *UBLOX_AT::create_context_impl(ATHandler &at, const char *apn, bool cp_req, bool nonip_req)
|
||||
{
|
||||
return new UBLOX_AT_CellularContext(at, this, apn);
|
||||
return new UBLOX_AT_CellularContext(at, this, apn, cp_req, nonip_req);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
virtual AT_CellularContext *create_context_impl(ATHandler &at, const char *apn, bool cp_req = false, bool nonip_req = false);
|
||||
public: // NetworkInterface
|
||||
void handle_urc(FileHandle *fh);
|
||||
};
|
||||
|
|
|
@ -17,11 +17,12 @@
|
|||
#include "UBLOX_AT_CellularContext.h"
|
||||
#include "UBLOX_AT_CellularStack.h"
|
||||
#include "APN_db.h"
|
||||
#include "CellularLog.h"
|
||||
|
||||
namespace mbed {
|
||||
|
||||
UBLOX_AT_CellularContext::UBLOX_AT_CellularContext(ATHandler &at, CellularDevice *device, const char *apn) :
|
||||
AT_CellularContext(at, device, apn)
|
||||
UBLOX_AT_CellularContext::UBLOX_AT_CellularContext(ATHandler &at, CellularDevice *device, const char *apn, bool cp_req, bool nonip_req) :
|
||||
AT_CellularContext(at, device, apn, cp_req, nonip_req)
|
||||
{
|
||||
// The authentication to use
|
||||
_auth = NSAPI_SECURITY_UNKNOWN;
|
||||
|
@ -33,9 +34,14 @@ UBLOX_AT_CellularContext::~UBLOX_AT_CellularContext()
|
|||
|
||||
NetworkStack *UBLOX_AT_CellularContext::get_stack()
|
||||
{
|
||||
if (!_stack) {
|
||||
_stack = new UBLOX_AT_CellularStack(_at, _cid, _ip_stack_type);
|
||||
if (_pdp_type == NON_IP_PDP_TYPE || _cp_in_use) {
|
||||
tr_error("Requesting stack for NON-IP context! Should request control plane netif: get_cp_netif()");
|
||||
return NULL;
|
||||
}
|
||||
if (!_stack) {
|
||||
_stack = new UBLOX_AT_CellularStack(_at, _cid, (nsapi_ip_stack_t)_pdp_type);
|
||||
}
|
||||
|
||||
return _stack;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ namespace mbed {
|
|||
|
||||
class UBLOX_AT_CellularContext: public AT_CellularContext {
|
||||
public:
|
||||
UBLOX_AT_CellularContext(ATHandler &at, CellularDevice *device, const char *apn);
|
||||
UBLOX_AT_CellularContext(ATHandler &at, CellularDevice *device, const char *apn, bool cp_req = false, bool nonip_req = false);
|
||||
virtual ~UBLOX_AT_CellularContext();
|
||||
|
||||
virtual void do_connect();
|
||||
|
|
|
@ -0,0 +1,267 @@
|
|||
/* CellularNonIPSocket
|
||||
#include <CellularNonIPSocket.h>
|
||||
* Copyright (c) 2015 ARM Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "platform/Callback.h"
|
||||
#include "CellularNonIPSocket.h"
|
||||
#include <stdio.h>
|
||||
|
||||
using namespace mbed;
|
||||
|
||||
CellularNonIPSocket::CellularNonIPSocket(CellularContext *cellular_context)
|
||||
: _timeout(osWaitForever),
|
||||
_readers(0), _writers(0), _pending(0),
|
||||
_cp_netif(NULL),
|
||||
_opened(false)
|
||||
{
|
||||
open(cellular_context);
|
||||
}
|
||||
|
||||
nsapi_error_t CellularNonIPSocket::open(CellularContext *cellular_context)
|
||||
{
|
||||
return open(cellular_context->get_cp_netif());
|
||||
}
|
||||
|
||||
CellularNonIPSocket::~CellularNonIPSocket()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
nsapi_error_t CellularNonIPSocket::open(ControlPlane_netif *cp_netif)
|
||||
{
|
||||
if (_opened) {
|
||||
return NSAPI_ERROR_OK;
|
||||
}
|
||||
|
||||
_lock.lock();
|
||||
|
||||
if (_cp_netif != NULL || cp_netif == NULL) {
|
||||
_lock.unlock();
|
||||
return NSAPI_ERROR_PARAMETER;
|
||||
}
|
||||
_cp_netif = cp_netif;
|
||||
|
||||
_event = callback(this, &CellularNonIPSocket::event);
|
||||
_cp_netif->attach(Callback<void()>::thunk, &_event);
|
||||
_opened = true;
|
||||
|
||||
_lock.unlock();
|
||||
return NSAPI_ERROR_OK;
|
||||
}
|
||||
|
||||
nsapi_error_t CellularNonIPSocket::close()
|
||||
{
|
||||
_lock.lock();
|
||||
|
||||
nsapi_error_t ret = NSAPI_ERROR_OK;
|
||||
if (!_opened) {
|
||||
return NSAPI_ERROR_NO_SOCKET;
|
||||
}
|
||||
|
||||
// Just in case - tell the stack not to callback any more, then remove this socket.
|
||||
_cp_netif->attach(0, 0);
|
||||
_opened = false;
|
||||
_cp_netif = 0; // Invalidate the cp_netif pointer - otherwise open() fails.
|
||||
|
||||
// Wakeup anything in a blocking operation
|
||||
// on this socket
|
||||
event();
|
||||
|
||||
// Wait until all readers and writers are gone
|
||||
while (_readers || _writers) {
|
||||
_lock.unlock();
|
||||
_event_flag.wait_any(FINISHED_FLAG, osWaitForever);
|
||||
_lock.lock();
|
||||
}
|
||||
|
||||
_lock.unlock();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
nsapi_size_or_error_t CellularNonIPSocket::send(const void *data, nsapi_size_t size)
|
||||
{
|
||||
_lock.lock();
|
||||
nsapi_size_or_error_t ret;
|
||||
|
||||
_writers++;
|
||||
|
||||
while (true) {
|
||||
if (!_opened) {
|
||||
ret = NSAPI_ERROR_NO_SOCKET;
|
||||
break;
|
||||
}
|
||||
|
||||
_pending = 0;
|
||||
nsapi_size_or_error_t sent = _cp_netif->send(data, size);
|
||||
if ((0 == _timeout) || (NSAPI_ERROR_WOULD_BLOCK != sent)) {
|
||||
ret = sent;
|
||||
break;
|
||||
} else {
|
||||
uint32_t flag;
|
||||
|
||||
// Release lock before blocking so other threads
|
||||
// accessing this object aren't blocked
|
||||
_lock.unlock();
|
||||
flag = _event_flag.wait_any(WRITE_FLAG, _timeout);
|
||||
_lock.lock();
|
||||
|
||||
if (flag & osFlagsError) {
|
||||
// Timeout break
|
||||
ret = NSAPI_ERROR_WOULD_BLOCK;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_writers--;
|
||||
if (!_opened || !_writers) {
|
||||
_event_flag.set(FINISHED_FLAG);
|
||||
}
|
||||
_lock.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
nsapi_size_or_error_t CellularNonIPSocket::recv(void *buffer, nsapi_size_t size)
|
||||
{
|
||||
_lock.lock();
|
||||
nsapi_size_or_error_t ret;
|
||||
|
||||
_readers++;
|
||||
|
||||
while (true) {
|
||||
if (!_opened) {
|
||||
ret = NSAPI_ERROR_NO_SOCKET;
|
||||
break;
|
||||
}
|
||||
|
||||
_pending = 0;
|
||||
nsapi_size_or_error_t recv = _cp_netif->recv(buffer, size);
|
||||
|
||||
// Non-blocking sockets always return. Blocking only returns when success or errors other than WOULD_BLOCK
|
||||
if ((0 == _timeout) || (NSAPI_ERROR_WOULD_BLOCK != recv)) {
|
||||
ret = recv;
|
||||
break;
|
||||
} else {
|
||||
uint32_t flag;
|
||||
|
||||
// Release lock before blocking so other threads
|
||||
// accessing this object aren't blocked
|
||||
_lock.unlock();
|
||||
printf("\nWAITWAITWAIT\n");
|
||||
flag = _event_flag.wait_any(READ_FLAG, _timeout);
|
||||
_lock.lock();
|
||||
|
||||
if (flag & osFlagsError) {
|
||||
// Timeout break
|
||||
ret = NSAPI_ERROR_WOULD_BLOCK;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_readers--;
|
||||
if (!_opened || !_readers) {
|
||||
_event_flag.set(FINISHED_FLAG);
|
||||
}
|
||||
|
||||
_lock.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void CellularNonIPSocket::set_blocking(bool blocking)
|
||||
{
|
||||
set_timeout(blocking ? -1 : 0);
|
||||
}
|
||||
|
||||
void CellularNonIPSocket::set_timeout(int timeout)
|
||||
{
|
||||
_lock.lock();
|
||||
|
||||
if (timeout >= 0) {
|
||||
_timeout = (uint32_t)timeout;
|
||||
} else {
|
||||
_timeout = osWaitForever;
|
||||
}
|
||||
|
||||
_lock.unlock();
|
||||
}
|
||||
|
||||
void CellularNonIPSocket::event()
|
||||
{
|
||||
_event_flag.set(READ_FLAG | WRITE_FLAG);
|
||||
|
||||
_pending += 1;
|
||||
if (_callback && _pending == 1) {
|
||||
_callback();
|
||||
}
|
||||
}
|
||||
|
||||
void CellularNonIPSocket::sigio(Callback<void()> callback)
|
||||
{
|
||||
_lock.lock();
|
||||
_callback = callback;
|
||||
_lock.unlock();
|
||||
}
|
||||
|
||||
nsapi_error_t CellularNonIPSocket::connect(const SocketAddress &address)
|
||||
{
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
Socket *CellularNonIPSocket::accept(nsapi_error_t *error)
|
||||
{
|
||||
if (error) {
|
||||
*error = NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
nsapi_error_t CellularNonIPSocket::listen(int backlog)
|
||||
{
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
nsapi_size_or_error_t CellularNonIPSocket::sendto(const SocketAddress &address,
|
||||
const void *data, nsapi_size_t size)
|
||||
{
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
nsapi_size_or_error_t CellularNonIPSocket::recvfrom(SocketAddress *address,
|
||||
void *data, nsapi_size_t size)
|
||||
{
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
nsapi_error_t CellularNonIPSocket::setsockopt(int level, int optname, const void *optval, unsigned optlen)
|
||||
{
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
nsapi_error_t CellularNonIPSocket::getsockopt(int level, int optname, void *optval, unsigned *optlen)
|
||||
{
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
nsapi_error_t CellularNonIPSocket::getpeername(SocketAddress *address)
|
||||
{
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
nsapi_error_t CellularNonIPSocket::bind(const SocketAddress &address)
|
||||
{
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
|
@ -0,0 +1,150 @@
|
|||
|
||||
/** \addtogroup netsocket */
|
||||
/** @{*/
|
||||
/* Socket
|
||||
* Copyright (c) 2015 ARM Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef CELLULARNONIPSOCKET_H
|
||||
#define CELLULARNONIPSOCKET_H
|
||||
|
||||
#include "netsocket/Socket.h"
|
||||
#include "rtos/Mutex.h"
|
||||
#include "rtos/EventFlags.h"
|
||||
#include "Callback.h"
|
||||
#include "mbed_toolchain.h"
|
||||
#include "ControlPlane_netif.h"
|
||||
#include "CellularContext.h"
|
||||
|
||||
//Socket implementation for non ip datagrams over cellular control plane
|
||||
class CellularNonIPSocket : public Socket {
|
||||
public:
|
||||
/** Destroy the socket.
|
||||
*
|
||||
* @note Closes socket if it's still open.
|
||||
*/
|
||||
virtual ~CellularNonIPSocket();
|
||||
|
||||
/** Creates and opens a socket on the given cellular context.
|
||||
*
|
||||
* @param cellular_context Cellular PDP context over which this socket
|
||||
* is sending and receiving data.
|
||||
*/
|
||||
CellularNonIPSocket(mbed::CellularContext *cellular_context);
|
||||
|
||||
/** Opens a socket on the given cellular context.
|
||||
*
|
||||
* @param cellular_context Cellular PDP context over which this socket is sending and
|
||||
* receiving data. The context has support for providing
|
||||
* a control plane interface for data delivery.
|
||||
* @return NSAPI_ERROR_OK on success
|
||||
* NSAPI_ERROR_PARAMETER otherwise
|
||||
*/
|
||||
nsapi_error_t open(mbed::CellularContext *cellular_context);
|
||||
|
||||
/** Opens a socket that will use the given control plane interface for data delivery.
|
||||
* Attaches the event as callback to the control plane interface.
|
||||
*
|
||||
* @param cp_netif Control plane interface for data delivery.
|
||||
* @return NSAPI_ERROR_OK on success
|
||||
* NSAPI_ERROR_PARAMETER otherwise
|
||||
*
|
||||
*/
|
||||
nsapi_error_t open(mbed::ControlPlane_netif *cp_netif);
|
||||
|
||||
/** Closes socket
|
||||
*
|
||||
* @return NSAPI_ERROR_OK on success
|
||||
* NSAPI_ERROR_NO_SOCKET otherwise
|
||||
*/
|
||||
|
||||
virtual nsapi_error_t close();
|
||||
|
||||
/** Send data over a control plane cellular context.
|
||||
*
|
||||
* By default, send blocks until all data is sent. If socket is set to
|
||||
* nonblocking or times out, a partial amount can be written.
|
||||
* NSAPI_ERROR_WOULD_BLOCK is returned if no data was written.
|
||||
*
|
||||
* @param data Buffer of data to be sent.
|
||||
* @param size Size of the buffer in bytes.
|
||||
* @return Number of sent bytes on success, negative error
|
||||
* code on failure.
|
||||
*/
|
||||
virtual nsapi_size_or_error_t send(const void *data, nsapi_size_t size);
|
||||
|
||||
/** Receive data from a socket.
|
||||
*
|
||||
* By default, recv blocks until some data is received. If socket is set to
|
||||
* nonblocking or times out, NSAPI_ERROR_WOULD_BLOCK can be returned to
|
||||
* indicate no data.
|
||||
*
|
||||
* @param data Pointer to buffer for received data.
|
||||
* @param size Size of the buffer in bytes.
|
||||
* @return Number of received bytes on success, negative error
|
||||
* code on failure.
|
||||
*/
|
||||
virtual nsapi_size_or_error_t recv(void *data, nsapi_size_t size);
|
||||
|
||||
/** @copydoc Socket::set_blocking
|
||||
*/
|
||||
virtual void set_blocking(bool blocking);
|
||||
|
||||
/** @copydoc Socket::set_blocking
|
||||
*/
|
||||
virtual void set_timeout(int timeout);
|
||||
|
||||
/** @copydoc Socket::sigio
|
||||
*/
|
||||
virtual void sigio(mbed::Callback<void()> func);
|
||||
|
||||
// NOT SUPPORTED
|
||||
virtual nsapi_error_t connect(const SocketAddress &address);
|
||||
virtual Socket *accept(nsapi_error_t *error = NULL);
|
||||
virtual nsapi_error_t listen(int backlog = 1);
|
||||
virtual nsapi_error_t setsockopt(int level, int optname, const void *optval, unsigned optlen);
|
||||
virtual nsapi_error_t getsockopt(int level, int optname, void *optval, unsigned *optlen);
|
||||
virtual nsapi_error_t getpeername(SocketAddress *address);
|
||||
virtual nsapi_size_or_error_t sendto(const SocketAddress &address,
|
||||
const void *data, nsapi_size_t size);
|
||||
virtual nsapi_size_or_error_t recvfrom(SocketAddress *address,
|
||||
void *data, nsapi_size_t size);
|
||||
virtual nsapi_error_t bind(const SocketAddress &address);
|
||||
|
||||
protected:
|
||||
CellularNonIPSocket();
|
||||
virtual void event();
|
||||
|
||||
uint32_t _timeout;
|
||||
mbed::Callback<void()> _event;
|
||||
mbed::Callback<void()> _callback;
|
||||
rtos::EventFlags _event_flag;
|
||||
rtos::Mutex _lock;
|
||||
uint8_t _readers;
|
||||
uint8_t _writers;
|
||||
volatile unsigned _pending;
|
||||
|
||||
// Event flags
|
||||
static const int READ_FLAG = 0x1u;
|
||||
static const int WRITE_FLAG = 0x2u;
|
||||
static const int FINISHED_FLAG = 0x3u;
|
||||
|
||||
mbed::ControlPlane_netif *_cp_netif;
|
||||
bool _opened;
|
||||
};
|
||||
|
||||
#endif // CELLULARNONIPSOCKET_H
|
||||
|
||||
/** @}*/
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* 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 CONTROLPLANE_NETIF_H_
|
||||
#define CONTROLPLANE_NETIF_H_
|
||||
|
||||
#include "nsapi_types.h"
|
||||
|
||||
namespace mbed {
|
||||
|
||||
/* Length of the buffer storing data received over control plane */
|
||||
#define MAX_CP_DATA_RECV_LEN 2048
|
||||
|
||||
// TODO: need to make this l3ip compatible
|
||||
class ControlPlane_netif {
|
||||
public:
|
||||
ControlPlane_netif() {}
|
||||
virtual ~ControlPlane_netif() {}
|
||||
|
||||
/** Send data over cellular control plane
|
||||
*
|
||||
* @param cpdata Buffer of data to be sent over control plane connection
|
||||
* @param cpdata_length Length of data in bytes
|
||||
* @return Number of sent bytes on success, negative error
|
||||
* code on failure.
|
||||
*/
|
||||
virtual nsapi_size_or_error_t send(const void *cpdata, nsapi_size_t cpdata_length) = 0;
|
||||
|
||||
/** Receive data over cellular control plane
|
||||
*
|
||||
* @param cpdata Destination buffer for data received from control plane connection
|
||||
* @param cpdata_length Length of data in bytes
|
||||
* @return Number of received bytes on success, negative error
|
||||
* code on failure.
|
||||
*/
|
||||
virtual nsapi_size_or_error_t recv(void *cpdata, nsapi_size_t cpdata_length) = 0;
|
||||
|
||||
/** Register a callback on state change of the socket
|
||||
*
|
||||
* The specified callback will be called on state changes such as when
|
||||
* the socket can recv/send successfully and on when an error
|
||||
* occurs. The callback may also be called spuriously without reason.
|
||||
*
|
||||
* The callback may be called in an interrupt context and should not
|
||||
* perform expensive operations such as recv/send calls.
|
||||
*
|
||||
* @param callback Function to call on state change
|
||||
* @param data Argument to pass to callback
|
||||
*/
|
||||
virtual void attach(void (*callback)(void *), void *data) = 0;
|
||||
|
||||
/** Receives data from the control plane PDP context
|
||||
*
|
||||
* This function is called by cellular PDP context when data
|
||||
* is received from network. It will invoke the callback set
|
||||
* by the above attach.
|
||||
*
|
||||
* @param buffer Buffer containing received data
|
||||
* @param size Size of data in bytes
|
||||
*/
|
||||
virtual void data_received() = 0;
|
||||
};
|
||||
|
||||
} // mbed namespace
|
||||
#endif
|
Loading…
Reference in New Issue