Skip to content

Cellular: retry logic for CellularContext connect #10056

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 1, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 12 additions & 6 deletions UNITTESTS/stubs/AT_CellularContext_stub.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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()
Expand Down Expand Up @@ -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;
Expand All @@ -281,3 +282,8 @@ void AT_CellularContext::deactivate_non_ip_context()
void AT_CellularContext::set_disconnect()
{
}

void AT_CellularContext::do_connect_with_retry()
{

}
26 changes: 24 additions & 2 deletions UNITTESTS/stubs/CellularContext_stub.cpp
Original file line number Diff line number Diff line change
@@ -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");
Expand All @@ -17,7 +17,7 @@

#include "CellularContext.h"

using namespace mbed;
namespace mbed {

void CellularContext::cp_data_received()
{
Expand All @@ -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);
}
}
}

}
5 changes: 5 additions & 0 deletions UNITTESTS/stubs/CellularStateMachine_stub.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
{

}
11 changes: 6 additions & 5 deletions UNITTESTS/target_h/myCellularContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
* limitations under the License.
*/

#include "cellular/framework/API/CellularContext.h"
#include "CellularContext.h"
#include "ControlPlane_netif_stub.h"

namespace mbed {
Expand Down Expand Up @@ -186,10 +186,6 @@ class myCellularContext : public CellularContext {
{
};

void call_network_cb(nsapi_connection_status_t status)
{
};

ControlPlane_netif_stub *get_cp_netif()
{
if (!my_cp_netif) {
Expand Down Expand Up @@ -219,6 +215,11 @@ class myCellularContext : public CellularContext {
void set_disconnect()
{
};

void do_connect_with_retry()
{
};

};

}
21 changes: 21 additions & 0 deletions features/cellular/framework/API/CellularContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,22 @@ class CellularContext : public CellularInterface {
*/
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;
Expand All @@ -332,7 +348,12 @@ class CellularContext : public CellularInterface {
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;
};

/**
Expand Down
10 changes: 10 additions & 0 deletions features/cellular/framework/API/CellularDevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,16 @@ class CellularDevice {
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.
Expand Down
38 changes: 17 additions & 21 deletions features/cellular/framework/AT/AT_CellularContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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()
Expand Down Expand Up @@ -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();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you override if you just directly call the base?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's because of EventQueue. In non blocking mode we use EventQueue to call do_connect_with_retry. We can't call CellularContext::do_connect_with_retry() as it's protected so to avoid that problem we had to introduce this function.

}

nsapi_error_t AT_CellularContext::connect()
{
tr_info("CellularContext connect");
Expand All @@ -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;
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
}
Expand Down Expand Up @@ -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!");
Expand Down
10 changes: 1 addition & 9 deletions features/cellular/framework/AT/AT_CellularContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,6 @@ class AT_CellularContext : public CellularContext, public AT_CellularBase {
*/
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();
Expand All @@ -123,13 +117,11 @@ class AT_CellularContext : public CellularContext, public AT_CellularBase {
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;
Expand Down
2 changes: 2 additions & 0 deletions features/cellular/framework/common/CellularCommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.*/
Expand Down
77 changes: 77 additions & 0 deletions features/cellular/framework/device/CellularContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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()
{
Expand Down Expand Up @@ -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
Loading