Skip to content

Commit c6e5595

Browse files
Teppo JärvelinCruz Monrreal II
authored andcommitted
Cellular: retry logic for CellularContext connect
State machine has retry logic until device is attached to network. After this CellularContext does the context activation e.g. connect. There was no retry logic for context activation. Added logic to CellularContext level so it's available for at and (upcoming)ril layers.
1 parent 2d9c494 commit c6e5595

13 files changed

+198
-52
lines changed

UNITTESTS/stubs/AT_CellularContext_stub.cpp

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@
2020
using namespace mbed;
2121

2222
AT_CellularContext::AT_CellularContext(ATHandler &at, CellularDevice *device, const char *apn, bool cp_req, bool nonip_req) :
23-
AT_CellularBase(at), _is_blocking(true), _is_connected(false),
24-
_current_op(OP_INVALID), _nw(0), _fh(0), _cp_req(cp_req), _nonip_req(nonip_req), _cp_in_use(false)
23+
AT_CellularBase(at), _is_connected(false),
24+
_current_op(OP_INVALID), _fh(0), _cp_req(cp_req), _nonip_req(nonip_req), _cp_in_use(false)
2525
{
2626
_stack = NULL;
2727
_pdp_type = DEFAULT_PDP_TYPE;
@@ -37,7 +37,12 @@ AT_CellularContext::AT_CellularContext(ATHandler &at, CellularDevice *device, co
3737
_new_context_set = false;
3838
_next = NULL;
3939
_cp_netif = NULL;
40+
memset(_retry_timeout_array, 0, CELLULAR_RETRY_ARRAY_SIZE);
41+
_retry_array_length = 0;
42+
_retry_count = 0;
43+
_is_blocking = true;
4044
_device = device;
45+
_nw = NULL;
4146
}
4247

4348
AT_CellularContext::~AT_CellularContext()
@@ -251,10 +256,6 @@ void AT_CellularContext::cellular_callback(nsapi_event_t ev, intptr_t ptr)
251256
{
252257
}
253258

254-
void AT_CellularContext::call_network_cb(nsapi_connection_status_t status)
255-
{
256-
}
257-
258259
ControlPlane_netif *AT_CellularContext::get_cp_netif()
259260
{
260261
return NULL;
@@ -281,3 +282,8 @@ void AT_CellularContext::deactivate_non_ip_context()
281282
void AT_CellularContext::set_disconnect()
282283
{
283284
}
285+
286+
void AT_CellularContext::do_connect_with_retry()
287+
{
288+
289+
}

UNITTESTS/stubs/CellularContext_stub.cpp

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) , Arm Limited and affiliates.
2+
* Copyright (c) 2018, Arm Limited and affiliates.
33
* SPDX-License-Identifier: Apache-2.0
44
*
55
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
1717

1818
#include "CellularContext.h"
1919

20-
using namespace mbed;
20+
namespace mbed {
2121

2222
void CellularContext::cp_data_received()
2323
{
@@ -28,3 +28,25 @@ CellularDevice *CellularContext::get_device() const
2828
{
2929
return _device;
3030
}
31+
32+
void CellularContext::do_connect_with_retry()
33+
{
34+
do_connect();
35+
}
36+
37+
void CellularContext::do_connect()
38+
{
39+
_cb_data.error = NSAPI_ERROR_OK;
40+
}
41+
42+
void CellularContext::call_network_cb(nsapi_connection_status_t status)
43+
{
44+
if (_connect_status != status) {
45+
_connect_status = status;
46+
if (_status_cb) {
47+
_status_cb(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, _connect_status);
48+
}
49+
}
50+
}
51+
52+
}

UNITTESTS/stubs/CellularStateMachine_stub.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,3 +74,8 @@ void CellularStateMachine::set_cellular_callback(mbed::Callback<void(nsapi_event
7474
void CellularStateMachine::cellular_event_changed(nsapi_event_t ev, intptr_t ptr)
7575
{
7676
}
77+
78+
void CellularStateMachine::get_retry_timeout_array(uint16_t *timeout, int &array_len) const
79+
{
80+
81+
}

UNITTESTS/target_h/myCellularContext.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
* limitations under the License.
1616
*/
1717

18-
#include "cellular/framework/API/CellularContext.h"
18+
#include "CellularContext.h"
1919
#include "ControlPlane_netif_stub.h"
2020

2121
namespace mbed {
@@ -186,10 +186,6 @@ class myCellularContext : public CellularContext {
186186
{
187187
};
188188

189-
void call_network_cb(nsapi_connection_status_t status)
190-
{
191-
};
192-
193189
ControlPlane_netif_stub *get_cp_netif()
194190
{
195191
if (!my_cp_netif) {
@@ -219,6 +215,11 @@ class myCellularContext : public CellularContext {
219215
void set_disconnect()
220216
{
221217
};
218+
219+
void do_connect_with_retry()
220+
{
221+
};
222+
222223
};
223224

224225
}

features/cellular/framework/API/CellularContext.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,22 @@ class CellularContext : public CellularInterface {
314314
*/
315315
void cp_data_received();
316316

317+
/** Retry logic after device attached to network. Retry to find and activate pdp context or in case
318+
* of PPP find correct pdp context and open data channel. Retry logic is the same which is used in
319+
* CellularStateMachine.
320+
*/
321+
virtual void do_connect_with_retry();
322+
323+
/** Helper method to call callback function if it is provided
324+
*
325+
* @param status connection status which is parameter in callback function
326+
*/
327+
void call_network_cb(nsapi_connection_status_t status);
328+
329+
/** Find and activate pdp context or in case of PPP find correct pdp context and open data channel.
330+
*/
331+
virtual void do_connect();
332+
317333
// member variables needed in target override methods
318334
NetworkStack *_stack; // must be pointer because of PPP
319335
pdp_type_t _pdp_type;
@@ -332,7 +348,12 @@ class CellularContext : public CellularInterface {
332348
bool _active_high;
333349

334350
ControlPlane_netif *_cp_netif;
351+
uint16_t _retry_timeout_array[CELLULAR_RETRY_ARRAY_SIZE];
352+
int _retry_array_length;
353+
int _retry_count;
335354
CellularDevice *_device;
355+
CellularNetwork *_nw;
356+
bool _is_blocking;
336357
};
337358

338359
/**

features/cellular/framework/API/CellularDevice.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,16 @@ class CellularDevice {
418418
protected:
419419
friend class AT_CellularNetwork;
420420
friend class AT_CellularContext;
421+
friend class CellularContext;
422+
423+
/** Get the retry array from the CellularStateMachine. Array is used in retry logic.
424+
* Array contains seconds and retry logic uses those second to wait before trying again.
425+
*
426+
* @param timeout timeout array containing seconds for retry logic. Must have space for
427+
* CELLULAR_RETRY_ARRAY_SIZE (defined in CellularCommon.h)
428+
* @param array_len length of the timeout array on return
429+
*/
430+
void get_retry_timeout_array(uint16_t *timeout, int &array_len) const;
421431

422432
/** Cellular callback to be attached to Network and CellularStateMachine classes.
423433
* CellularContext calls this when in PPP mode to provide network changes.

features/cellular/framework/AT/AT_CellularContext.cpp

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ using namespace mbed_cellular_util;
4848
using namespace mbed;
4949

5050
AT_CellularContext::AT_CellularContext(ATHandler &at, CellularDevice *device, const char *apn, bool cp_req, bool nonip_req) :
51-
AT_CellularBase(at), _is_connected(false), _is_blocking(true),
52-
_current_op(OP_INVALID), _nw(0), _fh(0), _cp_req(cp_req), _nonip_req(nonip_req), _cp_in_use(false)
51+
AT_CellularBase(at), _is_connected(false), _current_op(OP_INVALID), _fh(0), _cp_req(cp_req),
52+
_nonip_req(nonip_req), _cp_in_use(false)
5353
{
5454
tr_info("New CellularContext %s (%p)", apn ? apn : "", this);
5555
_stack = NULL;
@@ -68,7 +68,12 @@ AT_CellularContext::AT_CellularContext(ATHandler &at, CellularDevice *device, co
6868
_dcd_pin = NC;
6969
_active_high = false;
7070
_cp_netif = NULL;
71+
memset(_retry_timeout_array, 0, CELLULAR_RETRY_ARRAY_SIZE);
72+
_retry_array_length = 0;
73+
_retry_count = 0;
74+
_is_blocking = true;
7175
_device = device;
76+
_nw = NULL;
7277
}
7378

7479
AT_CellularContext::~AT_CellularContext()
@@ -119,6 +124,11 @@ AT_CellularDevice *AT_CellularContext::get_device() const
119124
return static_cast<AT_CellularDevice *>(CellularContext::get_device());
120125
}
121126

127+
void AT_CellularContext::do_connect_with_retry()
128+
{
129+
CellularContext::do_connect_with_retry();
130+
}
131+
122132
nsapi_error_t AT_CellularContext::connect()
123133
{
124134
tr_info("CellularContext connect");
@@ -129,15 +139,15 @@ nsapi_error_t AT_CellularContext::connect()
129139

130140
nsapi_error_t err = _device->attach_to_network();
131141
_cb_data.error = check_operation(err, OP_CONNECT);
132-
142+
_retry_count = 0;
133143
if (_is_blocking) {
134144
if (_cb_data.error == NSAPI_ERROR_OK || _cb_data.error == NSAPI_ERROR_ALREADY) {
135-
do_connect();
145+
do_connect_with_retry();
136146
}
137147
} else {
138148
if (_cb_data.error == NSAPI_ERROR_ALREADY) {
139149
// device is already attached, to be async we must use queue to connect and give proper callbacks
140-
int id = _device->get_queue()->call_in(0, this, &AT_CellularContext::do_connect);
150+
int id = _device->get_queue()->call_in(0, this, &AT_CellularContext::do_connect_with_retry);
141151
if (id == 0) {
142152
return NSAPI_ERROR_NO_MEMORY;
143153
}
@@ -580,8 +590,6 @@ void AT_CellularContext::do_connect()
580590
_cb_data.error = open_data_channel();
581591
_at.unlock();
582592
if (_cb_data.error != NSAPI_ERROR_OK) {
583-
tr_error("Failed to open data channel!");
584-
call_network_cb(NSAPI_STATUS_DISCONNECTED);
585593
_is_connected = false;
586594
} else {
587595
_is_context_activated = true;
@@ -970,7 +978,8 @@ void AT_CellularContext::cellular_callback(nsapi_event_t ev, intptr_t ptr)
970978
if (_status_cb) {
971979
_status_cb(ev, ptr);
972980
}
973-
do_connect();
981+
_retry_count = 0;
982+
do_connect_with_retry();
974983
return;
975984
}
976985
}
@@ -1000,19 +1009,6 @@ void AT_CellularContext::cellular_callback(nsapi_event_t ev, intptr_t ptr)
10001009
}
10011010
}
10021011

1003-
void AT_CellularContext::call_network_cb(nsapi_connection_status_t status)
1004-
{
1005-
if (_connect_status != status) {
1006-
_connect_status = status;
1007-
if (_status_cb) {
1008-
_status_cb(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, _connect_status);
1009-
}
1010-
if (_nw && _connect_status == NSAPI_STATUS_DISCONNECTED) {
1011-
tr_info("CellularContext disconnected");
1012-
}
1013-
}
1014-
}
1015-
10161012
ControlPlane_netif *AT_CellularContext::get_cp_netif()
10171013
{
10181014
tr_error("No control plane interface available from base context!");

features/cellular/framework/AT/AT_CellularContext.h

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -93,12 +93,6 @@ class AT_CellularContext : public CellularContext, public AT_CellularBase {
9393
*/
9494
virtual uint32_t get_timeout_for_operation(ContextOperation op) const;
9595

96-
/** Helper method to call callback function if it is provided
97-
*
98-
* @param status connection status which is parameter in callback function
99-
*/
100-
void call_network_cb(nsapi_connection_status_t status);
101-
10296
virtual nsapi_error_t activate_non_ip_context();
10397
virtual nsapi_error_t setup_control_plane_opt();
10498
virtual void deactivate_non_ip_context();
@@ -123,13 +117,11 @@ class AT_CellularContext : public CellularContext, public AT_CellularBase {
123117
nsapi_error_t check_operation(nsapi_error_t err, ContextOperation op);
124118
AT_CellularBase::CellularProperty pdp_type_t_to_cellular_property(pdp_type_t pdp_type);
125119
void ciot_opt_cb(mbed::CellularNetwork::CIoT_Supported_Opt ciot_opt);
126-
120+
virtual void do_connect_with_retry();
127121
private:
128122
bool _is_connected;
129-
bool _is_blocking;
130123
ContextOperation _current_op;
131124
char _found_apn[MAX_APN_LENGTH];
132-
CellularNetwork *_nw;
133125
FileHandle *_fh;
134126
rtos::Semaphore _semaphore;
135127
rtos::Semaphore _cp_opt_semaphore;

features/cellular/framework/common/CellularCommon.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
#include <stdint.h>
2222
#include "nsapi_types.h"
2323

24+
const int CELLULAR_RETRY_ARRAY_SIZE = 10;
25+
2426
struct cell_callback_data_t {
2527
nsapi_error_t error; /* possible error code */
2628
int status_data; /* cellular_event_status related enum or other info in int format. Check cellular_event_status comments.*/

features/cellular/framework/device/CellularContext.cpp

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
* limitations under the License.
1616
*/
1717
#include "CellularContext.h"
18+
#include "CellularLog.h"
19+
#include "ThisThread.h"
1820

1921
MBED_WEAK CellularInterface *CellularInterface::get_target_default_instance()
2022
{
@@ -66,4 +68,79 @@ CellularDevice *CellularContext::get_device() const
6668
return _device;
6769
}
6870

71+
void CellularContext::do_connect_with_retry()
72+
{
73+
do_connect();
74+
if (_cb_data.error == NSAPI_ERROR_OK) {
75+
return;
76+
}
77+
78+
if (_retry_count == 0) {
79+
_device->get_retry_timeout_array(_retry_timeout_array, _retry_array_length);
80+
}
81+
82+
if (_is_blocking) {
83+
while (_retry_count < _retry_array_length) {
84+
tr_debug("SYNC do_connect failed with %d, retry after %d seconds", _cb_data.error, _retry_timeout_array[_retry_count]);
85+
rtos::ThisThread::sleep_for(_retry_timeout_array[_retry_count] * 1000);
86+
do_connect();
87+
if (_cb_data.error == NSAPI_ERROR_OK) {
88+
return;
89+
}
90+
_retry_count++;
91+
}
92+
} else {
93+
if (_retry_count < _retry_array_length) {
94+
if (_retry_count == _retry_array_length - 1) {
95+
// set the flag that this is the last try for ppp connect / pdp context activate
96+
_cb_data.final_try = true;
97+
}
98+
tr_debug("ASYNC do_connect failed with %d, retry after %d seconds", _cb_data.error, _retry_timeout_array[_retry_count]);
99+
int id = _device->get_queue()->call_in(_retry_timeout_array[_retry_count] * 1000, this, &CellularContext::do_connect_with_retry);
100+
if (id == 0) {
101+
tr_error("Failed call via eventqueue in do_connect_with_retry()");
102+
#if !NSAPI_PPP_AVAILABLE
103+
_cb_data.final_try = true;
104+
_cb_data.error = NSAPI_ERROR_NO_MEMORY;
105+
// in PPP mode we did not activate any context, just searched the correct _cid
106+
if (_status_cb) {
107+
_status_cb((nsapi_event_t)CellularActivatePDPContext, (intptr_t)&_cb_data);
108+
}
109+
_cb_data.final_try = false;
110+
_cb_data.error = NSAPI_ERROR_OK;
111+
#else
112+
call_network_cb(NSAPI_STATUS_DISCONNECTED);
113+
#endif // !NSAPI_PPP_AVAILABLE
114+
}
115+
_retry_count++;
116+
return; // don't call NSAPI_STATUS_DISCONNECTED in every failure, only the last one.
117+
}
118+
}
119+
120+
#if NSAPI_PPP_AVAILABLE
121+
if (_cb_data.error != NSAPI_ERROR_OK) {
122+
tr_error("Failed to open data channel!");
123+
call_network_cb(NSAPI_STATUS_DISCONNECTED);
124+
}
125+
#endif // #if NSAPI_PPP_AVAILABLE
126+
}
127+
128+
void CellularContext::do_connect()
129+
{
130+
_cb_data.error = NSAPI_ERROR_OK;
131+
}
132+
133+
void CellularContext::call_network_cb(nsapi_connection_status_t status)
134+
{
135+
if (_connect_status != status) {
136+
_connect_status = status;
137+
if (_status_cb) {
138+
_status_cb(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, _connect_status);
139+
}
140+
if (_nw && _connect_status == NSAPI_STATUS_DISCONNECTED) {
141+
tr_info("CellularContext disconnected");
142+
}
143+
}
144+
}
145+
69146
} // namespace mbed

0 commit comments

Comments
 (0)