Skip to content

Commit

Permalink
[gen2, threading, sleep20] Fixes Cellular taking up to 10 minutes to …
Browse files Browse the repository at this point in the history
…shutoff modem with System.sleep(config) if there is no cell connection [ch73242]
  • Loading branch information
technobly committed Feb 20, 2021
1 parent c7b7413 commit a0955ef
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 36 deletions.
1 change: 1 addition & 0 deletions system/inc/system_sleep.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ int system_sleep(Spark_Sleep_TypeDef mode, long seconds, uint32_t param, void* r
int system_sleep_pin(uint16_t pin, uint16_t mode, long seconds, uint32_t param, void* reserved);
int system_sleep_pins(const uint16_t* pins, size_t pins_count, const InterruptMode* modes, size_t modes_count, long seconds, uint32_t param, void* reserved);
int system_sleep_ext(const hal_sleep_config_t* config, hal_wakeup_source_base_t** reason, void* reserved);
int system_sleep_ext_impl(const hal_sleep_config_t* config, hal_wakeup_source_base_t** reason, void* reserved);

#ifdef __cplusplus
}
Expand Down
11 changes: 9 additions & 2 deletions system/src/system_sleep.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,16 @@ static int system_sleep_network_resume(network_interface_index index) {
}

int system_sleep_ext(const hal_sleep_config_t* config, hal_wakeup_source_base_t** reason, void* reserved) {
SYSTEM_THREAD_CONTEXT_SYNC(system_sleep_ext(config, reason, reserved));

LOG(TRACE, "Entering system_sleep_ext()");
// Cancel current connection attempt to unblock the system thread
if (network_connecting(NETWORK_INTERFACE_ALL, 0, NULL)) {
network_connect_cancel(NETWORK_INTERFACE_ALL, 1, 0, 0);
}
return system_sleep_ext_impl(config, reason, reserved);
}

int system_sleep_ext_impl(const hal_sleep_config_t* config, hal_wakeup_source_base_t** reason, void* reserved) {
SYSTEM_THREAD_CONTEXT_SYNC(system_sleep_ext(config, reason, reserved));

// Validates the sleep configuration previous to disconnecting network,
// so that the network status remains if the configuration is invalid.
Expand Down
143 changes: 109 additions & 34 deletions user/tests/wiring/cellular_no_antenna/cellular_no_antenna.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,16 @@
#include "application.h"
#include "unit-test/unit-test.h"

// Serial1LogHandler logHandler(115200, LOG_LEVEL_ALL);

namespace {

STARTUP(System.enableFeature(FEATURE_RETAINED_MEMORY));
static retained uint32_t magick = 0;
static retained uint32_t phase = 0;

} // anonymous

#if Wiring_Cellular

void disconnect_from_cloud(system_tick_t timeout) {
Expand Down Expand Up @@ -66,22 +76,27 @@ test(CELLULAR_NO_ANTENNA_01_conn_after_off) {
return;
}

// Connect to Particle cloud
Particle.connect();
delay(30000);
// Power off the cell radio
Cellular.off();
delay(60000);
// Callback handler for network_status
System.on(network_status, nwstatus_callback_handler);
// clear g_state_conn_attempt just-in-case
g_state_conn_attempt = 0;
// Check that Particle.connect() attempts to work after the delay
Particle.connect();
// Wait sometime for Particle.connect() to try
waitFor(network_is_connecting, 30000);
// Verify that a connection attempt has been made
assertEqual(g_state_conn_attempt, 1);
if (phase == 0xbeef0002) {
Serial.println(" >> Device is reset from hibernate mode.");
assertEqual(System.resetReason(), (int)RESET_REASON_PIN_RESET);
} else {
// Connect to Particle cloud
Particle.connect();
delay(30000);
// Power off the cell radio
Cellular.off();
delay(60000);
// Callback handler for network_status
System.on(network_status, nwstatus_callback_handler);
// clear g_state_conn_attempt just-in-case
g_state_conn_attempt = 0;
// Check that Particle.connect() attempts to work after the delay
Particle.connect();
// Wait sometime for Particle.connect() to try
waitFor(network_is_connecting, 30000);
// Verify that a connection attempt has been made
assertEqual(g_state_conn_attempt, 1);
}
}

// Test for ch73242
Expand All @@ -92,27 +107,87 @@ test(CELLULAR_NO_ANTENNA_02_device_will_poweroff_quickly_when_modem_cannot_conne
return;
}

const system_tick_t waitMs[9] = {2000, 4000, 5000, 7500, 10000, 12500, 15000, 25000};
// Callback handler for network_status
System.on(network_status, nwstatus_callback_handler);
// clear g_state_conn_attempt just-in-case
g_state_conn_attempt = 0;
for (int x = 0; x < 9; x++) {
if (phase == 0xbeef0002) {
Serial.println(" >> Device is reset from hibernate mode.");
assertEqual(System.resetReason(), (int)RESET_REASON_PIN_RESET);
} else {
const system_tick_t waitMs[9] = {2000, 4000, 5000, 7500, 10000, 12500, 15000, 25000};
// Callback handler for network_status
System.on(network_status, nwstatus_callback_handler);
// clear g_state_conn_attempt just-in-case
g_state_conn_attempt = 0;
for (int x = 0; x < 9; x++) {
Particle.connect();
// Log.info("delaying: %lu", waitMs[x]);
delay(waitMs[x]);
assertTrue(Particle.disconnected());
// cellular_cancel(true, false, NULL); // Workaround: call before Cellular.off() / System.sleep(config);
Cellular.off();
waitFor(Cellular.isOff, 60000);
assertTrue(Cellular.isOff());
}
// Check that Particle.connect() attempts to work after the delay
Particle.connect();
// Log.info("delaying: %lu", waitMs[x]);
delay(waitMs[x]);
// Wait sometime for Particle.connect() to try
waitFor(network_is_connecting, 30000);
// Verify that a connection attempt has been made
assertEqual(g_state_conn_attempt, 1);
}
}

// Test for ch73242
test(CELLULAR_NO_ANTENNA_03a_device_will_sleep_quickly_when_modem_cannot_connect) {
/* This test should only be run with threading enabled */
if (system_thread_get_state(nullptr) != spark::feature::ENABLED) {
skip();
return;
}

if (magick != 0xdeadbeef) {
magick = 0xdeadbeef;
phase = 0xbeef0001;
}
if (phase == 0xbeef0001) {
Serial.println(" >> Device attempts to connect to the Cloud for 25s.");
Particle.connect();
delay(25000);
assertTrue(Particle.disconnected());
// cellular_cancel(true, false, NULL); // Workaround: call before Cellular.off()
Cellular.off();
waitFor(Cellular.isOff, 60000);
assertTrue(Cellular.isOff());
Serial.println(" >> Device is still trying to connect...");
Serial.println(" >> Device enters hibernate mode.");
Serial.println(" >> Please reconnect serial and type 't' immediately after you press the reset button.");
Serial.println(" >> Press any key now - if device does not sleep within 60s, consider it a failure.");
while (Serial.available() <= 0);
while (Serial.available() > 0) {
(void)Serial.read();
}

phase = 0xbeef0002;

// cellular_cancel(true, false, NULL); // Workaround: call before Cellular.off() / System.sleep(config);
SystemSleepConfiguration config;
config.mode(SystemSleepMode::HIBERNATE);
SystemSleepResult result = System.sleep(config);
assertEqual(result.error(), SYSTEM_ERROR_NONE);
} else if (phase == 0xbeef0002) {
Serial.println(" >> Device is reset from hibernate mode.");
assertEqual(System.resetReason(), (int)RESET_REASON_PIN_RESET);
}
}

test(CELLULAR_NO_ANTENNA_03b_device_will_sleep_quickly_when_modem_cannot_connect) {
/* This test should only be run with threading enabled */
if (system_thread_get_state(nullptr) != spark::feature::ENABLED) {
skip();
return;
}

if (phase == 0xbeef0002) {
phase = 0xbeef0001;
assertEqual(System.resetReason(), (int)RESET_REASON_PIN_RESET);
} else {
Serial.println(" >> Please run Test 3a first!");
fail();
}
// Check that Particle.connect() attempts to work after the delay
Particle.connect();
// Wait sometime for Particle.connect() to try
waitFor(network_is_connecting, 30000);
// Verify that a connection attempt has been made
assertEqual(g_state_conn_attempt, 1);
}

#endif // Wiring_Cellular

0 comments on commit a0955ef

Please sign in to comment.