Cellular: Change 3GPP TS 27.007 NIDD to async

Add a missing license header.
Remove semaphores and add +CRTDCP to support async operation.
Fix delete context and disconnect to execute just once.
Add support for NONIP PPD type.
Change CellularNetwork::clear() to virtual so it can be overridden.
pull/12065/head
Ari Parkkila 2019-12-09 03:05:11 -08:00
parent 972d8a6107
commit 913cbd96a6
12 changed files with 191 additions and 47 deletions

View File

@ -24,6 +24,7 @@ set(unittest-test-sources
stubs/AT_CellularDevice_stub.cpp stubs/AT_CellularDevice_stub.cpp
stubs/AT_CellularStack_stub.cpp stubs/AT_CellularStack_stub.cpp
stubs/AT_CellularNetwork_stub.cpp stubs/AT_CellularNetwork_stub.cpp
stubs/AT_ControlPlane_netif_stub.cpp
stubs/CellularDevice_stub.cpp stubs/CellularDevice_stub.cpp
stubs/CellularStateMachine_stub.cpp stubs/CellularStateMachine_stub.cpp
stubs/equeue_stub.c stubs/equeue_stub.c

View File

@ -198,6 +198,10 @@ bool AT_CellularContext::get_context()
return true; return true;
} }
const char* AT_CellularContext::get_nonip_context_type_str() {
return "Non-IP";
}
bool AT_CellularContext::set_new_context(int cid) bool AT_CellularContext::set_new_context(int cid)
{ {
return true; return true;

View File

@ -0,0 +1,57 @@
/*
* Copyright (c) 2019, 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 "CellularUtil.h"
#include "ThisThread.h"
#include "AT_ControlPlane_netif.h"
#include "CellularLog.h"
using namespace mbed_cellular_util;
namespace mbed {
AT_ControlPlane_netif::AT_ControlPlane_netif(ATHandler &at, int cid) : AT_CellularBase(at),
_cid(cid), _cb(NULL), _data(NULL)
{
}
AT_ControlPlane_netif::~AT_ControlPlane_netif()
{}
void AT_ControlPlane_netif::urc_cp_recv()
{
}
nsapi_size_or_error_t AT_ControlPlane_netif::send(const void *cpdata, nsapi_size_t cpdata_length)
{
return cpdata_length;
}
nsapi_size_or_error_t AT_ControlPlane_netif::recv(void *cpdata, nsapi_size_t cpdata_length)
{
return cpdata_length;
}
void AT_ControlPlane_netif::attach(void (*callback)(void *), void *data)
{
}
void AT_ControlPlane_netif::data_received()
{
}
} //mbed namespace

View File

@ -160,6 +160,10 @@ public:
return true; return true;
}; };
const char* get_nonip_context_type_str() {
return "Non-IP";
}
bool set_new_context(int cid) bool set_new_context(int cid)
{ {
return true; return true;

View File

@ -19,6 +19,7 @@
#include "AT_CellularContext.h" #include "AT_CellularContext.h"
#include "AT_CellularNetwork.h" #include "AT_CellularNetwork.h"
#include "AT_CellularStack.h" #include "AT_CellularStack.h"
#include "AT_ControlPlane_netif.h"
#include "AT_CellularDevice.h" #include "AT_CellularDevice.h"
#include "CellularLog.h" #include "CellularLog.h"
#if (DEVICE_SERIAL && DEVICE_INTERRUPTIN) || defined(DOXYGEN_ONLY) #if (DEVICE_SERIAL && DEVICE_INTERRUPTIN) || defined(DOXYGEN_ONLY)
@ -322,6 +323,9 @@ void AT_CellularContext::set_credentials(const char *apn, const char *uname, con
// PDP Context handling // PDP Context handling
void AT_CellularContext::delete_current_context() void AT_CellularContext::delete_current_context()
{ {
if (_cid <= 0) {
return;
}
tr_info("Delete context %d", _cid); tr_info("Delete context %d", _cid);
_at.clear_error(); _at.clear_error();
@ -426,13 +430,17 @@ bool AT_CellularContext::get_context()
return true; return true;
} }
const char* AT_CellularContext::get_nonip_context_type_str() {
return "Non-IP";
}
bool AT_CellularContext::set_new_context(int cid) bool AT_CellularContext::set_new_context(int cid)
{ {
char pdp_type_str[8 + 1] = {0}; char pdp_type_str[8 + 1] = {0};
pdp_type_t pdp_type = IPV4_PDP_TYPE; pdp_type_t pdp_type = IPV4_PDP_TYPE;
if (_nonip_req && _cp_in_use && get_device()->get_property(AT_CellularDevice::PROPERTY_NON_IP_PDP_TYPE)) { if (_nonip_req && _cp_in_use && get_device()->get_property(AT_CellularDevice::PROPERTY_NON_IP_PDP_TYPE)) {
strncpy(pdp_type_str, "Non-IP", sizeof(pdp_type_str)); strncpy(pdp_type_str, get_nonip_context_type_str(), sizeof(pdp_type_str));
pdp_type = NON_IP_PDP_TYPE; pdp_type = NON_IP_PDP_TYPE;
} else if (get_device()->get_property(AT_CellularDevice::PROPERTY_IPV4V6_PDP_TYPE) || } else if (get_device()->get_property(AT_CellularDevice::PROPERTY_IPV4V6_PDP_TYPE) ||
(get_device()->get_property(AT_CellularDevice::PROPERTY_IPV4_PDP_TYPE) && (get_device()->get_property(AT_CellularDevice::PROPERTY_IPV4_PDP_TYPE) &&
@ -556,7 +564,7 @@ nsapi_error_t AT_CellularContext::find_and_activate_context()
} }
// do check for stack to validate that we have support for stack // do check for stack to validate that we have support for stack
if (!get_stack()) { if (!(_nonip_req && _cp_in_use) && !get_stack()) {
_at.unlock(); _at.unlock();
tr_error("No cellular stack!"); tr_error("No cellular stack!");
return NSAPI_ERROR_UNSUPPORTED; return NSAPI_ERROR_UNSUPPORTED;
@ -962,6 +970,7 @@ void AT_CellularContext::cellular_callback(nsapi_event_t ev, intptr_t ptr)
_nw = _device->open_network(_fh); _nw = _device->open_network(_fh);
} }
#if MBED_CONF_CELLULAR_CONTROL_PLANE_OPT
if (_cp_req && !_cp_in_use && (_cb_data.error == NSAPI_ERROR_OK) && if (_cp_req && !_cp_in_use && (_cb_data.error == NSAPI_ERROR_OK) &&
(st == CellularSIMStatusChanged && data->status_data == CellularDevice::SimStateReady)) { (st == CellularSIMStatusChanged && data->status_data == CellularDevice::SimStateReady)) {
if (setup_control_plane_opt() != NSAPI_ERROR_OK) { if (setup_control_plane_opt() != NSAPI_ERROR_OK) {
@ -970,6 +979,7 @@ void AT_CellularContext::cellular_callback(nsapi_event_t ev, intptr_t ptr)
tr_info("Control plane SETUP success!"); tr_info("Control plane SETUP success!");
} }
} }
#endif
if (_is_blocking) { if (_is_blocking) {
if (_cb_data.error != NSAPI_ERROR_OK) { if (_cb_data.error != NSAPI_ERROR_OK) {
@ -1044,8 +1054,10 @@ void AT_CellularContext::cellular_callback(nsapi_event_t ev, intptr_t ptr)
ControlPlane_netif *AT_CellularContext::get_cp_netif() ControlPlane_netif *AT_CellularContext::get_cp_netif()
{ {
tr_error("No control plane interface available from base context!"); if (!_cp_netif) {
return NULL; _cp_netif = new AT_ControlPlane_netif(_at, _cid);
}
return _cp_netif;
} }
nsapi_error_t AT_CellularContext::setup_control_plane_opt() nsapi_error_t AT_CellularContext::setup_control_plane_opt()
@ -1068,19 +1080,11 @@ nsapi_error_t AT_CellularContext::setup_control_plane_opt()
ciot_opt_ret = _nw->set_ciot_optimization_config(mbed::CellularNetwork::CIOT_OPT_CONTROL_PLANE, ciot_opt_ret = _nw->set_ciot_optimization_config(mbed::CellularNetwork::CIOT_OPT_CONTROL_PLANE,
mbed::CellularNetwork::PREFERRED_UE_OPT_CONTROL_PLANE, mbed::CellularNetwork::PREFERRED_UE_OPT_CONTROL_PLANE,
callback(this, &AT_CellularContext::ciot_opt_cb)); callback(this, &AT_CellularContext::ciot_opt_cb));
if (ciot_opt_ret == NSAPI_ERROR_OK) {
if (ciot_opt_ret != NSAPI_ERROR_OK) { // assume network supports CIoT optimizations until ciot_opt_cb
return ciot_opt_ret; _cp_in_use = true;
} }
return ciot_opt_ret;
//wait for control plane opt call back to release semaphore
_cp_opt_semaphore.try_acquire_for(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) void AT_CellularContext::ciot_opt_cb(mbed::CellularNetwork::CIoT_Supported_Opt ciot_opt)
@ -1088,15 +1092,18 @@ void AT_CellularContext::ciot_opt_cb(mbed::CellularNetwork::CIoT_Supported_Opt
if (ciot_opt == mbed::CellularNetwork::CIOT_OPT_CONTROL_PLANE || if (ciot_opt == mbed::CellularNetwork::CIOT_OPT_CONTROL_PLANE ||
ciot_opt == mbed::CellularNetwork::CIOT_OPT_BOTH) { ciot_opt == mbed::CellularNetwork::CIOT_OPT_BOTH) {
_cp_in_use = true; _cp_in_use = true;
} else {
_cp_in_use = false;
} }
_cp_opt_semaphore.release();
} }
void AT_CellularContext::set_disconnect() void AT_CellularContext::set_disconnect()
{ {
tr_debug("AT_CellularContext::set_disconnect()"); tr_debug("AT_CellularContext::set_disconnect()");
_is_connected = false; if (_is_connected) {
_device->cellular_callback(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, NSAPI_STATUS_DISCONNECTED, this); _is_connected = false;
_device->cellular_callback(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, NSAPI_STATUS_DISCONNECTED, this);
}
} }
void AT_CellularContext::set_cid(int cid) void AT_CellularContext::set_cid(int cid)

View File

@ -108,6 +108,10 @@ protected:
virtual bool get_context(); virtual bool get_context();
AT_CellularDevice::CellularProperty pdp_type_t_to_cellular_property(pdp_type_t pdp_type); AT_CellularDevice::CellularProperty pdp_type_t_to_cellular_property(pdp_type_t pdp_type);
bool set_new_context(int cid); bool set_new_context(int cid);
/** Get string name for NIDD context type.
* @return NIDD context text, e.g. Non-IP or NONIP
*/
virtual const char* get_nonip_context_type_str();
private: private:
#if NSAPI_PPP_AVAILABLE #if NSAPI_PPP_AVAILABLE

View File

@ -375,7 +375,11 @@ nsapi_error_t AT_CellularNetwork::set_ciot_optimization_config(CIoT_Supported_Op
Callback<void(CIoT_Supported_Opt)> network_support_cb) Callback<void(CIoT_Supported_Opt)> network_support_cb)
{ {
_ciotopt_network_support_cb = network_support_cb; _ciotopt_network_support_cb = network_support_cb;
return _at.at_cmd_discard("+CCIOTOPT", "=1,", "%d%d", supported_opt, preferred_opt); nsapi_error_t err = _at.at_cmd_discard("+CRTDCP", "=", "%d", 1);
if (!err) {
err = _at.at_cmd_discard("+CCIOTOPT", "=1,", "%d%d", supported_opt, preferred_opt);
}
return err;
} }
void AT_CellularNetwork::urc_cciotopti() void AT_CellularNetwork::urc_cciotopti()
@ -690,7 +694,7 @@ nsapi_error_t AT_CellularNetwork::clear()
} }
context = context->next; context = context->next;
} }
#ifdef MBED_CONF_NSAPI_DEFAULT_CELLULAR_APN #if defined(MBED_CONF_NSAPI_DEFAULT_CELLULAR_APN) && !MBED_CONF_CELLULAR_CONTROL_PLANE_OPT
char pdp_type_str[sizeof("IPV4V6")]; char pdp_type_str[sizeof("IPV4V6")];
if (_device.get_property(AT_CellularDevice::PROPERTY_IPV4V6_PDP_TYPE) || if (_device.get_property(AT_CellularDevice::PROPERTY_IPV4V6_PDP_TYPE) ||
(_device.get_property(AT_CellularDevice::PROPERTY_IPV4_PDP_TYPE) && _device.get_property(AT_CellularDevice::PROPERTY_IPV6_PDP_TYPE))) { (_device.get_property(AT_CellularDevice::PROPERTY_IPV4_PDP_TYPE) && _device.get_property(AT_CellularDevice::PROPERTY_IPV6_PDP_TYPE))) {

View File

@ -117,7 +117,7 @@ protected:
* *
* @return NSAPI_ERROR_OK on success * @return NSAPI_ERROR_OK on success
*/ */
nsapi_error_t clear(); virtual nsapi_error_t clear();
private: private:
void urc_creg(); void urc_creg();

View File

@ -1,10 +1,31 @@
/*AT_ControlPlane_netif.cpp*/ /*
* Copyright (c) 2019, 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 "CellularUtil.h"
#include "ThisThread.h"
#include "AT_ControlPlane_netif.h" #include "AT_ControlPlane_netif.h"
#include "CellularLog.h"
using namespace mbed_cellular_util;
namespace mbed { namespace mbed {
AT_ControlPlane_netif::AT_ControlPlane_netif(ATHandler &at, int cid) : AT_ControlPlane_netif::AT_ControlPlane_netif(ATHandler &at, int cid) :
_cid(cid), _cb(NULL), _data(NULL), _recv_len(0), _at(at) _cid(cid), _cb(NULL), _data(NULL), _at(at)
{ {
_at.set_urc_handler("+CRTDCP:", mbed::Callback<void()>(this, &AT_ControlPlane_netif::urc_cp_recv)); _at.set_urc_handler("+CRTDCP:", mbed::Callback<void()>(this, &AT_ControlPlane_netif::urc_cp_recv));
} }
@ -18,44 +39,58 @@ void AT_ControlPlane_netif::urc_cp_recv()
_at.lock(); _at.lock();
int cid = _at.read_int(); int cid = _at.read_int();
int cpdata_length = _at.read_int(); int cpdata_length = _at.read_int();
int read_len = _at.read_string(_recv_buffer, sizeof(_recv_buffer)); if (cpdata_length < 0) {
return;
_at.unlock(); }
uint8_t *cpdata = new uint8_t[cpdata_length];
ssize_t read_len = _at.read_hex_string((char *)cpdata, cpdata_length);
// cid not expected to be different because: one context - one file handle // cid not expected to be different because: one context - one file handle
// so this file handle cannot get urc from different context // so this file handle cannot get urc from different context
if (read_len > 0 && read_len == cpdata_length && cid == _cid) { if (read_len > 0 && read_len == cpdata_length && cid == _cid) {
_recv_len = read_len; packet_t *packet = _packet_list.add_new();
packet->data = cpdata;
packet->data_len = cpdata_length;
data_received(); data_received();
} else {
delete[] cpdata;
} }
_at.unlock();
} }
nsapi_size_or_error_t AT_ControlPlane_netif::send(const void *cpdata, nsapi_size_t cpdata_length) nsapi_size_or_error_t AT_ControlPlane_netif::send(const void *cpdata, nsapi_size_t cpdata_length)
{ {
//CSODCP if (cpdata_length > MAX_CP_DATA_RECV_LEN) {
return NSAPI_ERROR_PARAMETER;
}
_at.lock(); _at.lock();
_at.cmd_start("AT+CSODCP=");
_at.write_int(_cid);
_at.write_int(cpdata_length);
_at.write_hex_string((char *)cpdata, cpdata_length);
_at.cmd_stop_read_resp();
nsapi_size_or_error_t err = _at.unlock_return_error();
nsapi_size_or_error_t err = _at.at_cmd_discard("+CSODCP", "=", "%d%d%b", _cid, cpdata_length, cpdata, cpdata_length); return err ? err : cpdata_length;
return (err == NSAPI_ERROR_OK) ? cpdata_length : err;
} }
nsapi_size_or_error_t AT_ControlPlane_netif::recv(void *cpdata, nsapi_size_t cpdata_length) nsapi_size_or_error_t AT_ControlPlane_netif::recv(void *cpdata, nsapi_size_t cpdata_length)
{ {
// If no data received through CRTDCP URC _at.lock();
if (!_recv_len) { if (_packet_list.count() <= 0) {
return NSAPI_ERROR_WOULD_BLOCK; (void) send("", 0); // poll for missing +CRTDCP indications
if (_packet_list.count() <= 0) {
return NSAPI_ERROR_WOULD_BLOCK;
}
} }
packet_t *packet = _packet_list.dequeue();
// If too small buffer for data int data_len = (cpdata_length >= packet->data_len) ? packet->data_len : cpdata_length;
if (_recv_len > cpdata_length) { memcpy(cpdata, packet->data, data_len);
return NSAPI_ERROR_DEVICE_ERROR; delete[] packet->data;
} delete (packet);
_at.unlock();
memcpy(cpdata, _recv_buffer, _recv_len); return data_len;
size_t recv = _recv_len;
_recv_len = 0;
return recv;
} }
void AT_ControlPlane_netif::attach(void (*callback)(void *), void *data) void AT_ControlPlane_netif::attach(void (*callback)(void *), void *data)

View File

@ -1,3 +1,21 @@
/*
* Copyright (c) 2019, 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 "CellularList.h"
#include "ControlPlane_netif.h" #include "ControlPlane_netif.h"
#include "ATHandler.h" #include "ATHandler.h"
@ -28,10 +46,14 @@ protected:
int _cid; int _cid;
private: private:
struct packet_t {
uint8_t *data;
nsapi_size_t data_len;
packet_t *next;
};
CellularList<packet_t> _packet_list;
void (*_cb)(void *); void (*_cb)(void *);
void *_data; void *_data;
char _recv_buffer[MBED_CONF_CELLULAR_MAX_CP_DATA_RECV_LEN];
size_t _recv_len;
// Called on receiving URC: +CRTDCP // Called on receiving URC: +CRTDCP
void urc_cp_recv(); void urc_cp_recv();

View File

@ -378,6 +378,8 @@ pdp_type_t string_to_pdp_type(const char *pdp_type_str)
pdp_type = IPV4_PDP_TYPE; pdp_type = IPV4_PDP_TYPE;
} else if (len == 6 && memcmp(pdp_type_str, "Non-IP", len) == 0) { } else if (len == 6 && memcmp(pdp_type_str, "Non-IP", len) == 0) {
pdp_type = NON_IP_PDP_TYPE; pdp_type = NON_IP_PDP_TYPE;
} else if (len == 5 && memcmp(pdp_type_str, "NONIP", len) == 0) {
pdp_type = NON_IP_PDP_TYPE;
} }
return pdp_type; return pdp_type;
} }

View File

@ -69,6 +69,10 @@ CellularContext::CellularContext() : _next(0), _stack(0), _pdp_type(DEFAULT_PDP_
void CellularContext::cp_data_received() void CellularContext::cp_data_received()
{ {
if (!_cp_netif) {
tr_warn("Cellular Non-IP callback missing");
return;
}
_cp_netif->data_received(); _cp_netif->data_received();
} }