Electron v1.0.1 firmware lockup on calling SLEEP_MODE_DEEP

The following code is a snippet from our larger code base for our application. Its been used extensively with 0.6.1 - 0.6.4 firmware on 500+ Electrons. When on 0.6.X, this code results in a deep sleep that will restore connectivity if there is some sort of cellular issue.

On 1.0.1 the code results in a lockup on the call for SLEEP_MODE_DEEP. I’m wondering if anyone can help me parse the issue

#include "application.h"

SYSTEM_MODE(MANUAL);
SYSTEM_THREAD(ENABLED);
STARTUP(System.enableFeature(FEATURE_RETAINED_MEMORY));

SerialLogHandler logHandler(LOG_LEVEL_ALL);

void watchDogOS() {
  // It's necessary to turn on the cellular modem in MANUAL or SEMI_AUTOMATIC mode
  // before going to sleep. This happens because the modem is put to sleep using AT
  // commands, and they don't work when the modem is not on.
  Cellular.on();

  Log.error("WDRS");
  System.sleep(SLEEP_MODE_DEEP, 10);
}
ApplicationWatchdog wd(60000, watchDogOS, 2304);

void cellularOffActuator(uint16_t sleepLength) {
  Cellular.off();
  Log.error("MODRS%u", sleepLength);
  // settings.save();
  delay(1000);
  if(sleepLength > 0) {
    System.sleep(SLEEP_MODE_DEEP, sleepLength);
  } else {
    System.reset();
  }
}

int cellularOff(int type, const char* buf, int len, char* param) {
  if(type == TYPE_OK) { cellularOffActuator(1); }
  return WAIT;
}

void setup() {
  Serial.begin(9600);
  while(!Serial.available()) {}

  Cellular.on();
  delay(500);
  if (!Cellular.ready()) {
    Cellular.connect();
    delay(500);
    Particle.process();
    waitFor(Cellular.ready, 240000);
    if (Cellular.ready()) {
      Log.info("Cellular connected");
    } else {
      Log.error("Cellular could not connect");
    }
  }

  Particle.connect();
  waitFor(Particle.connected, 90000);
  Log.info("Particle connected");

  Log.info("Press any key to continue");
  while(!Serial.available()) {}
  Log.info("OK starting up");
  delay(1000);
}


void loop() {
  uint32_t disconnectTimer = millis();
  if(Particle.connected()) {
    Particle.disconnect();
    delay(5000);
    while(Particle.connected() && millis() - disconnectTimer < 60000) {}
  }

  Log.info("Disconnected from Particle");

  char response[32] = "";
  Cellular.on();
  if (RESP_OK == Cellular.command(cellularOff, response, 60000, "AT+CFUN=16\r\n")) {
    Log.error("RESSHRT");
  } else {
    Log.error("ERRMODRES");
    cellularOffActuator(1);
  }
}

Logs are here: https://www.dropbox.com/s/e53jvg5c6uaqs56/Electron%20Lockup%20Logs%202019-04-04%20-%20All%20Sleep.txt?dl=0

If I replace System.sleep(SLEEP_MODE_DEEP, 10); with System.reset() in the Watchdog, the program will reset itself when the watchdog timer expires.

It seems like System.sleep doesn’t work as a reset-type function in v1.0.1 like it did previously?

Why can’t I call System.sleep in this scenario? Do I need to be checking for something before calling System.sleep?

Also, in the logs, the watchdog takes 120 seconds to expire instead of my expected 60 seconds. Why is this? I’ve had this problem for a long time, avoiding trying to get to root cause.

One update to this – if you remove this line SYSTEM_THREAD(ENABLED); the device will recover after 3 minutes. The watchdog using System.sleep(SLEEP_MODE_DEEP, 10); does not recover the device.

I don’t recommend making any calls other than System.reset() from the application watchdog. When the application watchdog triggers, the device is already in an unstable state. In particular, making any cellular calls will be a problem because if the system thread is hung, you’ll probably go into deadlock. Even entering SLEEP_MODE_DEEP is a potentially a problem because it will try to shut down networking.

Instead, you should just reset the device then do recovery after the system restarts. You could go back to sleep immediately, for example, or reset the modem after reset, not from the watchdog callback.

1 Like

OK, changing the Watchdog is an easy change that I will make ASAP.

I still have the other issue, though, which is that somehow I am putting the device into a state where calling System.sleep(SLEEP_MODE_DEEP, 10); is unsafe and locks the device. The watchdog is only part of the example because it too was failing to reset with SLEEP_MODE_DEEP.

Are there some new rules with firmware v1.0.1+ that need to be observed when calling System.sleep(SLEEP_MODE_DEEP, 10);? Or is this a bug that needs to be fixed as part of v1.0.2+?

Not sure if this will lockup the device, but you have System Thread enabled and are trying to go into SLEEP_MODE_DEEP before waiting for Cellular.on() to finish.

See specifically MANUAL, system thread (failure example)

Try disabling System Thread, or, putting a delay(2000) after the Cellular.on().