Merge pull request #10056 from jarvte/context_act_ppp_retry_logic

Cellular: retry logic for CellularContext connect
pull/10215/head
Cruz Monrreal 2019-04-01 17:03:17 -05:00 committed by GitHub
commit cf4118f4ae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 198 additions and 52 deletions

View File

@ -20,8 +20,8 @@
using namespace mbed;
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), _nw(0), _fh(0), _cp_req(cp_req), _nonip_req(nonip_req), _cp_in_use(false)
AT_CellularBase(at), _is_connected(false),
_current_op(OP_INVALID), _fh(0), _cp_req(cp_req), _nonip_req(nonip_req), _cp_in_use(false)
{
_stack = NULL;
_pdp_type = DEFAULT_PDP_TYPE;
@ -37,7 +37,12 @@ AT_CellularContext::AT_CellularContext(ATHandler &at, CellularDevice *device, co
_new_context_set = false;
_next = NULL;
_cp_netif = NULL;
memset(_retry_timeout_array, 0, CELLULAR_RETRY_ARRAY_SIZE);
_retry_array_length = 0;
_retry_count = 0;
_is_blocking = true;
_device = device;
_nw = NULL;
}
AT_CellularContext::~AT_CellularContext()
@ -251,10 +256,6 @@ 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;
@ -281,3 +282,8 @@ void AT_CellularContext::deactivate_non_ip_context()
void AT_CellularContext::set_disconnect()
{
}
void AT_CellularContext::do_connect_with_retry()
{
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) , Arm Limited and affiliates.
* Copyright (c) 2018, Arm Limited and affiliates.
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -17,7 +17,7 @@
#include "CellularContext.h"
using namespace mbed;
namespace mbed {
void CellularContext::cp_data_received()
{
@ -28,3 +28,25 @@ CellularDevice *CellularContext::get_device() const
{
return _device;
}
void CellularContext::do_connect_with_retry()
{
do_connect();
}
void CellularContext::do_connect()
{
_cb_data.error = NSAPI_ERROR_OK;
}
void CellularContext::call_network_cb(nsapi_connection_status_t status)
{
if (_connect_status != status) {
_connect_status = status;
if (_status_cb) {
_status_cb(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, _connect_status);
}
}
}
}

View File

@ -74,3 +74,8 @@ void CellularStateMachine::set_cellular_callback(mbed::Callback<void(nsapi_event
void CellularStateMachine::cellular_event_changed(nsapi_event_t ev, intptr_t ptr)
{
}
void CellularStateMachine::get_retry_timeout_array(uint16_t *timeout, int &array_len) const
{
}

View File

@ -15,7 +15,7 @@
* limitations under the License.
*/
#include "cellular/framework/API/CellularContext.h"
#include "CellularContext.h"
#include "ControlPlane_netif_stub.h"
namespace mbed {
@ -186,10 +186,6 @@ public:
{
};
void call_network_cb(nsapi_connection_status_t status)
{
};
ControlPlane_netif_stub *get_cp_netif()
{
if (!my_cp_netif) {
@ -219,6 +215,11 @@ public:
void set_disconnect()
{
};
void do_connect_with_retry()
{
};
};
}

View File

@ -314,6 +314,22 @@ protected: // Device specific implementations might need these so protected
*/
void cp_data_received();
/** Retry logic after device attached to network. Retry to find and activate pdp context or in case
* of PPP find correct pdp context and open data channel. Retry logic is the same which is used in
* CellularStateMachine.
*/
virtual void do_connect_with_retry();
/** Helper method to call callback function if it is provided
*
* @param status connection status which is parameter in callback function
*/
void call_network_cb(nsapi_connection_status_t status);
/** Find and activate pdp context or in case of PPP find correct pdp context and open data channel.
*/
virtual void do_connect();
// member variables needed in target override methods
NetworkStack *_stack; // must be pointer because of PPP
pdp_type_t _pdp_type;
@ -332,7 +348,12 @@ protected: // Device specific implementations might need these so protected
bool _active_high;
ControlPlane_netif *_cp_netif;
uint16_t _retry_timeout_array[CELLULAR_RETRY_ARRAY_SIZE];
int _retry_array_length;
int _retry_count;
CellularDevice *_device;
CellularNetwork *_nw;
bool _is_blocking;
};
/**

View File

@ -418,6 +418,16 @@ public:
protected:
friend class AT_CellularNetwork;
friend class AT_CellularContext;
friend class CellularContext;
/** Get the retry array from the CellularStateMachine. Array is used in retry logic.
* Array contains seconds and retry logic uses those second to wait before trying again.
*
* @param timeout timeout array containing seconds for retry logic. Must have space for
* CELLULAR_RETRY_ARRAY_SIZE (defined in CellularCommon.h)
* @param array_len length of the timeout array on return
*/
void get_retry_timeout_array(uint16_t *timeout, int &array_len) const;
/** Cellular callback to be attached to Network and CellularStateMachine classes.
* CellularContext calls this when in PPP mode to provide network changes.

View File

@ -48,8 +48,8 @@ using namespace mbed_cellular_util;
using namespace mbed;
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), _nw(0), _fh(0), _cp_req(cp_req), _nonip_req(nonip_req), _cp_in_use(false)
AT_CellularBase(at), _is_connected(false), _current_op(OP_INVALID), _fh(0), _cp_req(cp_req),
_nonip_req(nonip_req), _cp_in_use(false)
{
tr_info("New CellularContext %s (%p)", apn ? apn : "", this);
_stack = NULL;
@ -68,7 +68,12 @@ AT_CellularContext::AT_CellularContext(ATHandler &at, CellularDevice *device, co
_dcd_pin = NC;
_active_high = false;
_cp_netif = NULL;
memset(_retry_timeout_array, 0, CELLULAR_RETRY_ARRAY_SIZE);
_retry_array_length = 0;
_retry_count = 0;
_is_blocking = true;
_device = device;
_nw = NULL;
}
AT_CellularContext::~AT_CellularContext()
@ -119,6 +124,11 @@ AT_CellularDevice *AT_CellularContext::get_device() const
return static_cast<AT_CellularDevice *>(CellularContext::get_device());
}
void AT_CellularContext::do_connect_with_retry()
{
CellularContext::do_connect_with_retry();
}
nsapi_error_t AT_CellularContext::connect()
{
tr_info("CellularContext connect");
@ -129,15 +139,15 @@ nsapi_error_t AT_CellularContext::connect()
nsapi_error_t err = _device->attach_to_network();
_cb_data.error = check_operation(err, OP_CONNECT);
_retry_count = 0;
if (_is_blocking) {
if (_cb_data.error == NSAPI_ERROR_OK || _cb_data.error == NSAPI_ERROR_ALREADY) {
do_connect();
do_connect_with_retry();
}
} else {
if (_cb_data.error == NSAPI_ERROR_ALREADY) {
// device is already attached, to be async we must use queue to connect and give proper callbacks
int id = _device->get_queue()->call_in(0, this, &AT_CellularContext::do_connect);
int id = _device->get_queue()->call_in(0, this, &AT_CellularContext::do_connect_with_retry);
if (id == 0) {
return NSAPI_ERROR_NO_MEMORY;
}
@ -580,8 +590,6 @@ void AT_CellularContext::do_connect()
_cb_data.error = open_data_channel();
_at.unlock();
if (_cb_data.error != NSAPI_ERROR_OK) {
tr_error("Failed to open data channel!");
call_network_cb(NSAPI_STATUS_DISCONNECTED);
_is_connected = false;
} else {
_is_context_activated = true;
@ -970,7 +978,8 @@ void AT_CellularContext::cellular_callback(nsapi_event_t ev, intptr_t ptr)
if (_status_cb) {
_status_cb(ev, ptr);
}
do_connect();
_retry_count = 0;
do_connect_with_retry();
return;
}
}
@ -1000,19 +1009,6 @@ void AT_CellularContext::cellular_callback(nsapi_event_t ev, intptr_t ptr)
}
}
void AT_CellularContext::call_network_cb(nsapi_connection_status_t status)
{
if (_connect_status != status) {
_connect_status = status;
if (_status_cb) {
_status_cb(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, _connect_status);
}
if (_nw && _connect_status == NSAPI_STATUS_DISCONNECTED) {
tr_info("CellularContext disconnected");
}
}
}
ControlPlane_netif *AT_CellularContext::get_cp_netif()
{
tr_error("No control plane interface available from base context!");

View File

@ -93,12 +93,6 @@ protected:
*/
virtual uint32_t get_timeout_for_operation(ContextOperation op) const;
/** Helper method to call callback function if it is provided
*
* @param status connection status which is parameter in callback function
*/
void call_network_cb(nsapi_connection_status_t status);
virtual nsapi_error_t activate_non_ip_context();
virtual nsapi_error_t setup_control_plane_opt();
virtual void deactivate_non_ip_context();
@ -123,13 +117,11 @@ private:
nsapi_error_t check_operation(nsapi_error_t err, ContextOperation op);
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);
virtual void do_connect_with_retry();
private:
bool _is_connected;
bool _is_blocking;
ContextOperation _current_op;
char _found_apn[MAX_APN_LENGTH];
CellularNetwork *_nw;
FileHandle *_fh;
rtos::Semaphore _semaphore;
rtos::Semaphore _cp_opt_semaphore;

View File

@ -21,6 +21,8 @@
#include <stdint.h>
#include "nsapi_types.h"
const int CELLULAR_RETRY_ARRAY_SIZE = 10;
struct cell_callback_data_t {
nsapi_error_t error; /* possible error code */
int status_data; /* cellular_event_status related enum or other info in int format. Check cellular_event_status comments.*/

View File

@ -15,6 +15,8 @@
* limitations under the License.
*/
#include "CellularContext.h"
#include "CellularLog.h"
#include "ThisThread.h"
MBED_WEAK CellularInterface *CellularInterface::get_target_default_instance()
{
@ -66,4 +68,79 @@ CellularDevice *CellularContext::get_device() const
return _device;
}
void CellularContext::do_connect_with_retry()
{
do_connect();
if (_cb_data.error == NSAPI_ERROR_OK) {
return;
}
if (_retry_count == 0) {
_device->get_retry_timeout_array(_retry_timeout_array, _retry_array_length);
}
if (_is_blocking) {
while (_retry_count < _retry_array_length) {
tr_debug("SYNC do_connect failed with %d, retry after %d seconds", _cb_data.error, _retry_timeout_array[_retry_count]);
rtos::ThisThread::sleep_for(_retry_timeout_array[_retry_count] * 1000);
do_connect();
if (_cb_data.error == NSAPI_ERROR_OK) {
return;
}
_retry_count++;
}
} else {
if (_retry_count < _retry_array_length) {
if (_retry_count == _retry_array_length - 1) {
// set the flag that this is the last try for ppp connect / pdp context activate
_cb_data.final_try = true;
}
tr_debug("ASYNC do_connect failed with %d, retry after %d seconds", _cb_data.error, _retry_timeout_array[_retry_count]);
int id = _device->get_queue()->call_in(_retry_timeout_array[_retry_count] * 1000, this, &CellularContext::do_connect_with_retry);
if (id == 0) {
tr_error("Failed call via eventqueue in do_connect_with_retry()");
#if !NSAPI_PPP_AVAILABLE
_cb_data.final_try = true;
_cb_data.error = NSAPI_ERROR_NO_MEMORY;
// in PPP mode we did not activate any context, just searched the correct _cid
if (_status_cb) {
_status_cb((nsapi_event_t)CellularActivatePDPContext, (intptr_t)&_cb_data);
}
_cb_data.final_try = false;
_cb_data.error = NSAPI_ERROR_OK;
#else
call_network_cb(NSAPI_STATUS_DISCONNECTED);
#endif // !NSAPI_PPP_AVAILABLE
}
_retry_count++;
return; // don't call NSAPI_STATUS_DISCONNECTED in every failure, only the last one.
}
}
#if NSAPI_PPP_AVAILABLE
if (_cb_data.error != NSAPI_ERROR_OK) {
tr_error("Failed to open data channel!");
call_network_cb(NSAPI_STATUS_DISCONNECTED);
}
#endif // #if NSAPI_PPP_AVAILABLE
}
void CellularContext::do_connect()
{
_cb_data.error = NSAPI_ERROR_OK;
}
void CellularContext::call_network_cb(nsapi_connection_status_t status)
{
if (_connect_status != status) {
_connect_status = status;
if (_status_cb) {
_status_cb(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, _connect_status);
}
if (_nw && _connect_status == NSAPI_STATUS_DISCONNECTED) {
tr_info("CellularContext disconnected");
}
}
}
} // namespace mbed

View File

@ -34,7 +34,7 @@ MBED_WEAK CellularDevice *CellularDevice::get_target_default_instance()
}
CellularDevice::CellularDevice(FileHandle *fh) : _network_ref_count(0), _sms_ref_count(0),
_info_ref_count(0), _fh(fh), _queue(5 * EVENTS_EVENT_SIZE), _state_machine(0), _nw(0), _status_cb(0)
_info_ref_count(0), _fh(fh), _queue(8 * EVENTS_EVENT_SIZE), _state_machine(0), _nw(0), _status_cb(0)
{
MBED_ASSERT(fh);
set_sim_pin(NULL);
@ -67,6 +67,13 @@ CellularContext *CellularDevice::get_context_list() const
return NULL;
}
void CellularDevice::get_retry_timeout_array(uint16_t *timeout, int &array_len) const
{
if (_state_machine && timeout) {
_state_machine->get_retry_timeout_array(timeout, array_len);
}
}
void CellularDevice::set_sim_pin(const char *sim_pin)
{
if (sim_pin) {

View File

@ -67,7 +67,7 @@ CellularStateMachine::CellularStateMachine(CellularDevice &device, events::Event
_retry_timeout_array[7] = 128; // if around two minutes was not enough then let's wait much longer
_retry_timeout_array[8] = 600;
_retry_timeout_array[9] = TIMEOUT_NETWORK_MAX;
_retry_array_length = RETRY_ARRAY_SIZE;
_retry_array_length = CELLULAR_RETRY_ARRAY_SIZE;
}
CellularStateMachine::~CellularStateMachine()
@ -153,7 +153,7 @@ bool CellularStateMachine::open_sim()
} else {
// No sim pin provided even it's needed, stop state machine
tr_error("PIN required but no SIM pin provided.");
_retry_count = RETRY_ARRAY_SIZE;
_retry_count = CELLULAR_RETRY_ARRAY_SIZE;
return false;
}
}
@ -285,8 +285,8 @@ void CellularStateMachine::enter_to_state(CellularState state)
void CellularStateMachine::retry_state_or_fail()
{
if (++_retry_count < RETRY_ARRAY_SIZE) {
tr_debug("%s: retry %d/%d", get_state_string(_state), _retry_count, RETRY_ARRAY_SIZE);
if (++_retry_count < CELLULAR_RETRY_ARRAY_SIZE) {
tr_debug("%s: retry %d/%d", get_state_string(_state), _retry_count, CELLULAR_RETRY_ARRAY_SIZE);
_event_timeout = _retry_timeout_array[_retry_count];
_is_retry = true;
_cb_data.error = NSAPI_ERROR_OK;
@ -686,12 +686,20 @@ void CellularStateMachine::set_retry_timeout_array(const uint16_t timeout[], int
tr_warn("set_retry_timeout_array, timeout array null or invalid length");
return;
}
_retry_array_length = array_len > RETRY_ARRAY_SIZE ? RETRY_ARRAY_SIZE : array_len;
_retry_array_length = array_len > CELLULAR_RETRY_ARRAY_SIZE ? CELLULAR_RETRY_ARRAY_SIZE : array_len;
for (int i = 0; i < _retry_array_length; i++) {
_retry_timeout_array[i] = timeout[i];
}
}
void CellularStateMachine::get_retry_timeout_array(uint16_t *timeout, int &array_len) const
{
for (int i = 0; i < _retry_array_length; i++) {
timeout[i] = _retry_timeout_array[i];
}
array_len = _retry_array_length;
}
} // namespace

View File

@ -30,8 +30,6 @@ namespace mbed {
class CellularDevice;
const int RETRY_ARRAY_SIZE = 10;
/** CellularStateMachine class
*
* Finite State Machine for attaching to cellular network. Used by CellularDevice.
@ -133,6 +131,7 @@ private:
*/
void reset();
private:
void get_retry_timeout_array(uint16_t *timeout, int &array_len) const;
bool power_on();
bool open_sim();
bool get_network_registration(CellularNetwork::RegistrationType type, CellularNetwork::RegistrationStatus &status, bool &is_registered);
@ -171,7 +170,7 @@ private:
int _start_time;
int _event_timeout;
uint16_t _retry_timeout_array[RETRY_ARRAY_SIZE];
uint16_t _retry_timeout_array[CELLULAR_RETRY_ARRAY_SIZE];
int _retry_array_length;
int _event_id;
const char *_plmn;