Skip to content

Commit 4401d41

Browse files
authored
Merge pull request #10053 from AriParkkila/cellular-state-timeout
Cellular: Make CellularStateMachine timeouts configurable
2 parents b0ba3d3 + e0f8b21 commit 4401d41

File tree

8 files changed

+101
-19
lines changed

8 files changed

+101
-19
lines changed

UNITTESTS/stubs/CellularStateMachine_stub.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,3 +79,11 @@ void CellularStateMachine::get_retry_timeout_array(uint16_t *timeout, int &array
7979
{
8080

8181
}
82+
83+
void CellularStateMachine::set_retry_timeout_array(const uint16_t timeout[], int array_len)
84+
{
85+
}
86+
87+
void CellularStateMachine::set_timeout(int timeout)
88+
{
89+
}

features/cellular/framework/API/CellularDevice.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,11 +331,27 @@ class CellularDevice {
331331
virtual void close_information() = 0;
332332

333333
/** Set the default response timeout.
334+
*
335+
* @remark CellularStateMachine timeouts for all states are also changed to `timeout`.
334336
*
335337
* @param timeout milliseconds to wait response from modem
336338
*/
337339
virtual void set_timeout(int timeout) = 0;
338340

341+
/** Set an array of timeouts to wait before CellularStateMachine retries after failure.
342+
* To disable retry behavior completely use `set_retry_timeout_array(NULL, 0)`.
343+
* CellularContext callback event `cell_callback_data_t.final_try` indicates true when all retries have failed.
344+
*
345+
* @remark Use `set_retry_timeout_array` for CellularStateMachine to wait before it retries again after failure,
346+
* this is useful to send repetitive requests when don't know exactly when modem is ready to accept requests.
347+
* Use `set_timeout` for timeout how long to wait for a response from modem for each request,
348+
* this is useful if modem can accept requests but processing takes long time before sending response.
349+
*
350+
* @param timeout timeout array using seconds
351+
* @param array_len length of the array
352+
*/
353+
void set_retry_timeout_array(const uint16_t timeout[], int array_len);
354+
339355
/** Turn modem debug traces on
340356
*
341357
* @param on set true to enable debug traces

features/cellular/framework/AT/AT_CellularContext.cpp

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -903,6 +903,12 @@ void AT_CellularContext::cellular_callback(nsapi_event_t ev, intptr_t ptr)
903903
cell_callback_data_t *data = (cell_callback_data_t *)ptr;
904904
cellular_connection_status_t st = (cellular_connection_status_t)ev;
905905
_cb_data.error = data->error;
906+
_cb_data.final_try = data->final_try;
907+
if (data->final_try) {
908+
if (_current_op != OP_INVALID) {
909+
_semaphore.release();
910+
}
911+
}
906912
#if USE_APN_LOOKUP
907913
if (st == CellularSIMStatusChanged && data->status_data == CellularDevice::SimStateReady &&
908914
_cb_data.error == NSAPI_ERROR_OK) {
@@ -924,7 +930,9 @@ void AT_CellularContext::cellular_callback(nsapi_event_t ev, intptr_t ptr)
924930
_device->stop();
925931
if (_is_blocking) {
926932
// operation failed, release semaphore
927-
_semaphore.release();
933+
if (_current_op != OP_INVALID) {
934+
_semaphore.release();
935+
}
928936
}
929937
}
930938
_device->close_information();
@@ -948,8 +956,10 @@ void AT_CellularContext::cellular_callback(nsapi_event_t ev, intptr_t ptr)
948956
if (_is_blocking) {
949957
if (_cb_data.error != NSAPI_ERROR_OK) {
950958
// operation failed, release semaphore
951-
_current_op = OP_INVALID;
952-
_semaphore.release();
959+
if (_current_op != OP_INVALID) {
960+
_current_op = OP_INVALID;
961+
_semaphore.release();
962+
}
953963
} else {
954964
if ((st == CellularDeviceReady && _current_op == OP_DEVICE_READY) ||
955965
(st == CellularSIMStatusChanged && _current_op == OP_SIM_READY &&

features/cellular/framework/AT/AT_CellularDevice.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,10 @@ void AT_CellularDevice::set_timeout(int timeout)
344344
_default_timeout = timeout;
345345

346346
ATHandler::set_at_timeout_list(_default_timeout, true);
347+
348+
if (_state_machine) {
349+
_state_machine->set_timeout(_default_timeout);
350+
}
347351
}
348352

349353
uint16_t AT_CellularDevice::get_send_delay() const

features/cellular/framework/device/CellularContext.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,12 @@ CellularDevice *CellularContext::get_device() const
7070

7171
void CellularContext::do_connect_with_retry()
7272
{
73+
if (_cb_data.final_try) {
74+
_cb_data.final_try = false;
75+
_cb_data.error == NSAPI_ERROR_NO_CONNECTION;
76+
call_network_cb(NSAPI_STATUS_DISCONNECTED);
77+
return;
78+
}
7379
do_connect();
7480
if (_cb_data.error == NSAPI_ERROR_OK) {
7581
return;

features/cellular/framework/device/CellularDevice.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,4 +237,11 @@ nsapi_error_t CellularDevice::shutdown()
237237
return NSAPI_ERROR_OK;
238238
}
239239

240+
void CellularDevice::set_retry_timeout_array(const uint16_t timeout[], int array_len)
241+
{
242+
if (create_state_machine() == NSAPI_ERROR_OK) {
243+
_state_machine->set_retry_timeout_array(timeout, array_len);
244+
}
245+
}
246+
240247
} // namespace mbed

features/cellular/framework/device/CellularStateMachine.cpp

Lines changed: 38 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@
2828
#define TIMEOUT_POWER_ON (1*1000)
2929
#define TIMEOUT_SIM_PIN (1*1000)
3030
#define TIMEOUT_NETWORK (10*1000)
31+
/** CellularStateMachine does connecting up to packet service attach, and
32+
* after that it's up to CellularContext::connect() to connect to PDN.
33+
* If CellularContext or an application does not set timeout (via `CellularDevice::set_timeout`)
34+
* then TIMEOUT_CONNECT is used also for connecting to PDN and also for socket operations.
35+
*/
3136
#define TIMEOUT_CONNECT (60*1000)
3237
#define TIMEOUT_REGISTRATION (180*1000)
3338

@@ -36,6 +41,7 @@
3641

3742
#define RETRY_COUNT_DEFAULT 3
3843

44+
3945
const int STM_STOPPED = -99;
4046
const int ACTIVE_PDP_CONTEXT = 0x01;
4147
const int ATTACHED_TO_NETWORK = 0x02;
@@ -68,6 +74,12 @@ CellularStateMachine::CellularStateMachine(CellularDevice &device, events::Event
6874
_retry_timeout_array[8] = 600;
6975
_retry_timeout_array[9] = TIMEOUT_NETWORK_MAX;
7076
_retry_array_length = CELLULAR_RETRY_ARRAY_SIZE;
77+
78+
_state_timeout_power_on = TIMEOUT_POWER_ON;
79+
_state_timeout_sim_pin = TIMEOUT_SIM_PIN;
80+
_state_timeout_registration = TIMEOUT_REGISTRATION;
81+
_state_timeout_network = TIMEOUT_NETWORK;
82+
_state_timeout_connect = TIMEOUT_CONNECT;
7183
}
7284

7385
CellularStateMachine::~CellularStateMachine()
@@ -273,8 +285,8 @@ void CellularStateMachine::enter_to_state(CellularState state)
273285

274286
void CellularStateMachine::retry_state_or_fail()
275287
{
276-
if (++_retry_count < CELLULAR_RETRY_ARRAY_SIZE) {
277-
tr_debug("%s: retry %d/%d", get_state_string(_state), _retry_count, CELLULAR_RETRY_ARRAY_SIZE);
288+
if (_retry_count < _retry_array_length) {
289+
tr_debug("%s: retry %d/%d", get_state_string(_state), _retry_count, _retry_array_length);
278290
// send info to application/driver about error logic so it can implement proper error logic
279291
_cb_data.status_data = _current_event;
280292
_cb_data.data = &_retry_count;
@@ -284,15 +296,17 @@ void CellularStateMachine::retry_state_or_fail()
284296
_event_timeout = _retry_timeout_array[_retry_count];
285297
_is_retry = true;
286298
_cb_data.error = NSAPI_ERROR_OK;
299+
_retry_count++;
287300
} else {
301+
_cb_data.final_try = true;
288302
report_failure(get_state_string(_state));
289303
}
290304
}
291305

292306
void CellularStateMachine::state_init()
293307
{
294-
_cellularDevice.set_timeout(TIMEOUT_POWER_ON);
295-
tr_info("Start connecting (timeout %d s)", TIMEOUT_POWER_ON / 1000);
308+
_cellularDevice.set_timeout(_state_timeout_power_on);
309+
tr_info("Start connecting (timeout %d ms)", _state_timeout_power_on);
296310
_cb_data.error = _cellularDevice.is_ready();
297311
_status = _cb_data.error ? 0 : DEVICE_READY;
298312
if (_cb_data.error != NSAPI_ERROR_OK) {
@@ -308,8 +322,8 @@ void CellularStateMachine::state_init()
308322

309323
void CellularStateMachine::state_power_on()
310324
{
311-
_cellularDevice.set_timeout(TIMEOUT_POWER_ON);
312-
tr_info("Modem power ON (timeout %d s)", TIMEOUT_POWER_ON / 1000);
325+
_cellularDevice.set_timeout(_state_timeout_power_on);
326+
tr_info("Modem power ON (timeout %d ms)", _state_timeout_power_on);
313327
if (power_on()) {
314328
enter_to_state(STATE_DEVICE_READY);
315329
} else {
@@ -340,7 +354,7 @@ bool CellularStateMachine::device_ready()
340354

341355
void CellularStateMachine::state_device_ready()
342356
{
343-
_cellularDevice.set_timeout(TIMEOUT_POWER_ON);
357+
_cellularDevice.set_timeout(_state_timeout_power_on);
344358
if (!(_status & DEVICE_READY)) {
345359
tr_debug("Device was not ready, calling soft_power_on()");
346360
_cb_data.error = _cellularDevice.soft_power_on();
@@ -364,8 +378,8 @@ void CellularStateMachine::state_device_ready()
364378

365379
void CellularStateMachine::state_sim_pin()
366380
{
367-
_cellularDevice.set_timeout(TIMEOUT_SIM_PIN);
368-
tr_info("Setup SIM (timeout %d s)", TIMEOUT_SIM_PIN / 1000);
381+
_cellularDevice.set_timeout(_state_timeout_sim_pin);
382+
tr_info("Setup SIM (timeout %d ms)", _state_timeout_sim_pin);
369383
if (open_sim()) {
370384
bool success = false;
371385
for (int type = 0; type < CellularNetwork::C_MAX; type++) {
@@ -419,8 +433,7 @@ void CellularStateMachine::state_signal_quality()
419433

420434
void CellularStateMachine::state_registering()
421435
{
422-
_cellularDevice.set_timeout(TIMEOUT_NETWORK);
423-
tr_info("Network registration (timeout %d s)", TIMEOUT_REGISTRATION / 1000);
436+
_cellularDevice.set_timeout(_state_timeout_network);
424437
if (is_registered()) {
425438
if (_cb_data.status_data != CellularNetwork::RegisteredHomeNetwork &&
426439
_cb_data.status_data != CellularNetwork::RegisteredRoaming && _status) {
@@ -432,7 +445,8 @@ void CellularStateMachine::state_registering()
432445
// we are already registered, go to attach
433446
enter_to_state(STATE_ATTACHING_NETWORK);
434447
} else {
435-
_cellularDevice.set_timeout(TIMEOUT_REGISTRATION);
448+
tr_info("Network registration (timeout %d ms)", _state_timeout_registration);
449+
_cellularDevice.set_timeout(_state_timeout_registration);
436450
if (!_command_success && !_plmn) { // don't call set_registration twice for manual registration
437451
_cb_data.error = _network.set_registration(_plmn);
438452
_command_success = (_cb_data.error == NSAPI_ERROR_OK);
@@ -443,9 +457,9 @@ void CellularStateMachine::state_registering()
443457

444458
void CellularStateMachine::state_attaching()
445459
{
446-
_cellularDevice.set_timeout(TIMEOUT_CONNECT);
447-
tr_info("Attaching network (timeout %d s)", TIMEOUT_CONNECT / 1000);
448460
if (_status != ATTACHED_TO_NETWORK) {
461+
_cellularDevice.set_timeout(_state_timeout_connect);
462+
tr_info("Attaching network (timeout %d ms)", _state_timeout_connect);
449463
_cb_data.error = _network.set_attach();
450464
}
451465
if (_cb_data.error == NSAPI_ERROR_OK) {
@@ -695,11 +709,10 @@ void CellularStateMachine::device_ready_cb()
695709
void CellularStateMachine::set_retry_timeout_array(const uint16_t timeout[], int array_len)
696710
{
697711
if (!timeout || array_len <= 0) {
698-
tr_warn("set_retry_timeout_array, timeout array null or invalid length");
712+
_retry_array_length = 0;
699713
return;
700714
}
701715
_retry_array_length = array_len > CELLULAR_RETRY_ARRAY_SIZE ? CELLULAR_RETRY_ARRAY_SIZE : array_len;
702-
703716
for (int i = 0; i < _retry_array_length; i++) {
704717
_retry_timeout_array[i] = timeout[i];
705718
}
@@ -713,5 +726,14 @@ void CellularStateMachine::get_retry_timeout_array(uint16_t *timeout, int &array
713726
array_len = _retry_array_length;
714727
}
715728

729+
void CellularStateMachine::set_timeout(int timeout)
730+
{
731+
_state_timeout_power_on = timeout;
732+
_state_timeout_sim_pin = timeout;
733+
_state_timeout_registration = timeout;
734+
_state_timeout_network = timeout;
735+
_state_timeout_connect = timeout;
736+
}
737+
716738
} // namespace
717739

features/cellular/framework/device/CellularStateMachine.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,15 @@ class CellularStateMachine {
184184
cellular_connection_status_t _current_event;
185185
int _status;
186186
PlatformMutex _mutex;
187+
188+
// Cellular state timeouts
189+
int _state_timeout_power_on;
190+
int _state_timeout_sim_pin;
191+
int _state_timeout_registration;
192+
int _state_timeout_network;
193+
int _state_timeout_connect; // timeout for PS attach, PDN connect and socket operations
194+
// Change all cellular state timeouts to `timeout`
195+
void set_timeout(int timeout);
187196
cell_signal_quality_t _signal_quality;
188197
};
189198

0 commit comments

Comments
 (0)