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_CellularStack_stub.cpp
stubs/AT_CellularNetwork_stub.cpp
stubs/AT_ControlPlane_netif_stub.cpp
stubs/CellularDevice_stub.cpp
stubs/CellularStateMachine_stub.cpp
stubs/equeue_stub.c

View File

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

View File

@ -19,6 +19,7 @@
#include "AT_CellularContext.h"
#include "AT_CellularNetwork.h"
#include "AT_CellularStack.h"
#include "AT_ControlPlane_netif.h"
#include "AT_CellularDevice.h"
#include "CellularLog.h"
#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
void AT_CellularContext::delete_current_context()
{
if (_cid <= 0) {
return;
}
tr_info("Delete context %d", _cid);
_at.clear_error();
@ -426,13 +430,17 @@ bool AT_CellularContext::get_context()
return true;
}
const char* AT_CellularContext::get_nonip_context_type_str() {
return "Non-IP";
}
bool AT_CellularContext::set_new_context(int cid)
{
char pdp_type_str[8 + 1] = {0};
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)) {
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;
} else if (get_device()->get_property(AT_CellularDevice::PROPERTY_IPV4V6_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
if (!get_stack()) {
if (!(_nonip_req && _cp_in_use) && !get_stack()) {
_at.unlock();
tr_error("No cellular stack!");
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);
}
#if MBED_CONF_CELLULAR_CONTROL_PLANE_OPT
if (_cp_req && !_cp_in_use && (_cb_data.error == NSAPI_ERROR_OK) &&
(st == CellularSIMStatusChanged && data->status_data == CellularDevice::SimStateReady)) {
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!");
}
}
#endif
if (_is_blocking) {
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()
{
tr_error("No control plane interface available from base context!");
return NULL;
if (!_cp_netif) {
_cp_netif = new AT_ControlPlane_netif(_at, _cid);
}
return _cp_netif;
}
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,
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;
if (ciot_opt_ret == NSAPI_ERROR_OK) {
// assume network supports CIoT optimizations until ciot_opt_cb
_cp_in_use = true;
}
//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;
return ciot_opt_ret;
}
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 ||
ciot_opt == mbed::CellularNetwork::CIOT_OPT_BOTH) {
_cp_in_use = true;
} else {
_cp_in_use = false;
}
_cp_opt_semaphore.release();
}
void AT_CellularContext::set_disconnect()
{
tr_debug("AT_CellularContext::set_disconnect()");
_is_connected = false;
_device->cellular_callback(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, NSAPI_STATUS_DISCONNECTED, this);
if (_is_connected) {
_is_connected = false;
_device->cellular_callback(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, NSAPI_STATUS_DISCONNECTED, this);
}
}
void AT_CellularContext::set_cid(int cid)

View File

@ -108,6 +108,10 @@ protected:
virtual bool get_context();
AT_CellularDevice::CellularProperty pdp_type_t_to_cellular_property(pdp_type_t pdp_type);
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:
#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)
{
_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()
@ -690,7 +694,7 @@ nsapi_error_t AT_CellularNetwork::clear()
}
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")];
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))) {

View File

@ -117,7 +117,7 @@ protected:
*
* @return NSAPI_ERROR_OK on success
*/
nsapi_error_t clear();
virtual nsapi_error_t clear();
private:
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 "CellularLog.h"
using namespace mbed_cellular_util;
namespace mbed {
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));
}
@ -18,44 +39,58 @@ void AT_ControlPlane_netif::urc_cp_recv()
_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();
if (cpdata_length < 0) {
return;
}
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
// so this file handle cannot get urc from different context
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();
} else {
delete[] cpdata;
}
_at.unlock();
}
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.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 == NSAPI_ERROR_OK) ? cpdata_length : err;
return err ? err : 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
if (!_recv_len) {
return NSAPI_ERROR_WOULD_BLOCK;
_at.lock();
if (_packet_list.count() <= 0) {
(void) send("", 0); // poll for missing +CRTDCP indications
if (_packet_list.count() <= 0) {
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);
size_t recv = _recv_len;
_recv_len = 0;
return recv;
packet_t *packet = _packet_list.dequeue();
int data_len = (cpdata_length >= packet->data_len) ? packet->data_len : cpdata_length;
memcpy(cpdata, packet->data, data_len);
delete[] packet->data;
delete (packet);
_at.unlock();
return data_len;
}
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 "ATHandler.h"
@ -28,10 +46,14 @@ protected:
int _cid;
private:
struct packet_t {
uint8_t *data;
nsapi_size_t data_len;
packet_t *next;
};
CellularList<packet_t> _packet_list;
void (*_cb)(void *);
void *_data;
char _recv_buffer[MBED_CONF_CELLULAR_MAX_CP_DATA_RECV_LEN];
size_t _recv_len;
// Called on receiving URC: +CRTDCP
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;
} else if (len == 6 && memcmp(pdp_type_str, "Non-IP", len) == 0) {
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;
}

View File

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