Electron Freezing and Unrecoverable

Hi Everyone,

I’m using an electron as a wireless network coordinator, I have the watchdog enabled and tested.
The electron is always on at customer sites. The issue I am having is that occasionally an electron will freeze, the watchdog does not recover it and it takes a manual reset to get it going again.

Does anyone have any suggestions for this problem?

Thanks,
Peatear

It’d help if we could take a look at your code.

I guess with “the watchdog” you mean the Application Watchdog, right?
If so, you may run into the situation where the watchdog gets reset by the system without you anticipating it happening. That’s why we’d need to see at least some of your code.

e.g. delay(), Particle.process() or dropping out of loop() will reset the watchdog timer, preventing it from firing.

I’m having similar issues with my Electrons, and was wondering what you exactly mean by ‘‘freezing’’?

e.g. is it set to Automatic mode and won’t it connect anymore (in this case Deep_Sleep for a few seconds should fix it) or does it literally just stall?

#include "LoRa.h"
#include "math.h"
#include <SPI.h>
#include "Cape.h"
#include "cellular_hal.h"

SYSTEM_MODE(SEMI_AUTOMATIC);
//STARTUP(cellular_credentials_set("m2minternet.apn", "", "", NULL));  // ROGERS APN
STARTUP(cellular_credentials_set("mnet.bell.ca.ioe", "", "", NULL)); // BELL APN

ApplicationWatchdog wd(360000, watchdogCallback);  // arf, 6 mins



// Source content to be crypted
// Result buffer needs an additional byte for the initialization vector
char decrypted[70];
char encrypted[69];
char RX_DATA[20][70];
int RSSI[20];
char temp[40];
int WakeCommand = 0;
// Insert secret key and its length
Cape cape(key, 10);
//STARTUP(System.enableFeature(FEATURE_RETAINED_MEMORY)); //uses 9ua of power, but prob worth it
//retained int lastTime;
long int catchTime;
int n;
int bootTime;
int waitforfirmware = 0; // 1 millisecond
int TXint = 15;
String ACK = "";
char rxID[6];
bool LoRaSwitch = false;
char T1[6];
char T2[6];
char T3[6];
char T4[6];

char ICCID[5] = "";
char targetID[6] = "EMPTY";
char SleepID[6] = "EMPTY";
char WakeID[6] = "EMPTY";
int retries = 0;

char * Type;
char * ID;
char * Temp1;
char * Temp2;
char * Temp3;
char * Temp4;
char * Temp5;
char * Temp6;
char * Temp7;

char * Vbatt;

char * RXICCID;
char * rxIDACK;
char * deviceType;
char * timeRX;
char * checkTemp1;
char * checkTemp2;
char * checkTemp3;
char * checkTemp4;
char * checkTemp5;
char * checkTemp6;
char * checkVbatt;
bool aliveflag = false;
bool isEncrypted = false;
volatile char RX_data_flag[20];
int j;
uint32_t input1 = 0;
uint32_t input2 = 0;
const uint8_t chipSelect = D5;
#define ONE_DAY_MILLIS (24 * 60 * 60 * 1000)
unsigned long lastSync = millis();

void setup() {

  cape.set_key(key, 10);
  Serial.begin(115200);
  delay(5000);

  Particle.connect();
  // Print true or false depending on whether current time is valid
  waitFor(Time.isValid, 60000);

  Serial.println("ETC Receiver");
  getICCID();

  if (!LoRa.begin(915E6)) {
    Serial.println("Starting LoRa failed!");
    while (1);
  }
  LoRa.enableCrc();

  LoRa.onReceive(onReceive);
  // put the radio into receive mode
  LoRa.receive();

  PMIC pmic;
  pmic.setChargeVoltage(4208); // set max voltage to 4.2v (instead of default 4.112)
  pmic.setChargeCurrent(0, 0, 1, 0, 0, 0); // set charging to 1024 milliamp (instead of default 0.5 amp)

  catchTime = millis();
  // register the receive callback


  Particle.function("TX", TXinterval);

  Particle.variable("TXinterval", & TXint, INT);
  Particle.function("DataonDemand",DataonDemand);
  Particle.function("SleepSensor",Sleepsensor);
  Particle.function("WakeSensor",Wakesensor);
  Serial.println("Setup Finished");

}

void loop() {
  wd.checkin(); // resets the AWDT count
  if (Particle.connected()) {
      if (!aliveflag) {
          aliveflag = true;
          Particle.keepAlive(45);
      }
  }
  else {
      aliveflag = false;
  }
  for (j = 0; j < 20; j++) {

    if (RX_data_flag[j] == 1 && strstr(RX_DATA[j], "S,")) { //if data is available in the buffer

      int i;
      char * pt;
      char DATA[13][12];
      pt = strtok(RX_DATA[j], ",");
      if (pt != NULL) {
        for (i = 0; i < 13; i++) {
          strcpy(DATA[i], pt);
          pt = strtok(NULL, ",");
        }
      }

      Type = DATA[2];
      ID = DATA[3];
      Vbatt = DATA[4];
      Temp1 = DATA[5];
      timeRX = DATA[6];
      Temp2 = DATA[7];
      Temp3 = DATA[8];
      Temp4 = DATA[9];
      Temp5 = DATA[10];
      Temp6 = DATA[11];
      Temp7 = DATA[12];


      memset(RX_DATA[j], 0, sizeof RX_DATA[j]);
      RX_data_flag[j] = 0;
      retries = 0;
      RETRY_START:
        //Serial.println("Data Available");  //empty for now.

      long int startTime;

      FuelGauge fuel;
      float battLevel;
      battLevel = fuel.getVCell();
      //int sb = round(battLevel * 100);    //round to 2 decimals step 1
      //float b1 = sb / 100.00;             // round to 2 decimals step 2
      float b1 = roundf(battLevel * 100) / 100;
      String Vpart = String(b1, 2); //remove trailing zeros.

      String output = "";

      int theTime = Time.now();
      String niceTime = "";

      if (theTime > 0) {
        niceTime = String(Time.year(theTime)) + "-" + String(Time.month(theTime)) + "-" + String(Time.day(theTime)) + " " + String(Time.hour(theTime)) + ":" + String(Time.minute(theTime)) + ":" + String(Time.second(theTime));
      }
      else {
        niceTime = "not yet acquired";
      }

      // need a time out here!
      startTime = millis();

      while (!Particle.connected()) {
        delay(50);
        Serial.println("not connected");
        Serial.println(millis() - startTime);

        if ((millis() - startTime) > 120000) {
          Serial.println("did not connect for 120 seconds!");
          Serial.println("breaking out of first while loop");
          int notConnected = 1;
          break;
        }
      }

      if (Particle.connected()) {

        //Serial.println("Particle.connected() == true, so let's do this.");

        int bootSecs;
        if (bootTime > 0) {
          bootSecs = Time.now() - bootTime;
        }
        else {
          bootSecs = -1;
        }

        // get cell signal data
        CellularSignal sig = Cellular.RSSI();
        int rssi = sig.rssi;
        int qual = sig.qual;

        //recreate output, because for GSM we don't want to send values where no thermistor is hooked up, i.e. -72.6, etc. For SD card, we wanted everything.

        // output = output + "The Office Temp is:" + n + " RSSI of Signal:" + RSSI + " Vbatt:" + b1;
        output = output + Type + "," + RSSI[j] + "," + ID + "," + Vbatt + "," + rssi + "," + Vpart + "," + qual + ",0.1," + Temp1 + "," + timeRX + "," + Temp2 + "," + Temp3 + "," + Temp4 + "," + Temp5 + "," + Temp6 + "," + Temp7 + ",";
        Serial.println(output);
        // wait for it to actually publish! 8/22/17
        static uint32_t b4Publish;
        b4Publish = millis();
        bool success = false;

        //success = Particle.publish("PETER", output, PRIVATE, WITH_ACK);   //Particle.publish("readyforfirmware", "end", PRIVATE, WITH_ACK);   //Particle.publish("publish-with-ack", String(count), PRIVATE, WITH_ACK);
        success = Particle.publish("NOWIRES", output, PRIVATE, WITH_ACK);
        //success = 1;
        output = "";
        //success =   Particle.publish("googlesheets", output, PRIVATE);   //Particle.publish("readyforfirmware", "end", PRIVATE, WITH_ACK);   //Particle.publish("publish-with-ack", String(count), PRIVATE, WITH_ACK);

        if (!success) {
          Serial.printlnf("%7d(s): publish failed: %d", (millis() - b4Publish) / 1000);
          if (retries < 3) {
            Particle.disconnect();
            delay(3000);
            Particle.connect();
            Serial.print("Retry: ");
            Serial.println(retries + 1);
            retries++;
            goto RETRY_START;
          }
        }
        else {
          retries = 0;
          Serial.printlnf("%7d(s): publish passed: %d", (millis() - b4Publish) / 1000);
        }
        delay(500);
      }

    }
    else if (RX_data_flag[j] == 1 && !strstr(RX_DATA[j], "S,")) {
      Serial.println(RX_DATA[j]);
      Serial.println("Data conditions not met. ");
      memset(RX_DATA[j], 0, sizeof RX_DATA[j]);
      RX_data_flag[j] = 0;
    }

  }

  long int check = millis() - catchTime;


  if (check >= 120000) {
     Serial.println("Restart LoRa");
     if (!LoRa.begin(915E6)) {
       Serial.println("Starting LoRa failed!");
       while (1);
     }
     LoRa.enableCrc();

     LoRa.onReceive(onReceive);
     LoRa.receive();
     catchTime = millis();
 }
  if (millis() - lastSync > ONE_DAY_MILLIS) {
  // Request time synchronization from the Particle Cloud
  Particle.syncTime();
  lastSync = millis();
  }

}

void updateTime() {
  long int startTime = millis();
  while (!Time.isValid()) {
    Particle.process();
    delay(50);

    Serial.print("been waiting for the time update for this many millisecs: ");
    Serial.println(millis() - startTime);

    if ((millis() - startTime) > 5000) {
      Serial.println("forget time update, it took more than 5 secs.");
      break;
    }
  }
}

void goToSleep() {
  LoRa.sleep();
  int secsTilQtr = 0;
  if (Time.now() > 0) {
    // calculate how many seconds until the next :00 / :15 / :30 is so we can reboot at the right time
    int minsTilQtr = TXint - (Time.minute() % TXint) - 1; // subtract 1 bc the rest is secs
    secsTilQtr = (60 * minsTilQtr) + (60 - Time.second());
  }

  // if (secsTilQtr < 0 || secsTilQtr > 900 || secsTilQtr == 0){
  //     secsTilQtr = 900;  // extra safety, in case something goes weird, or if we couldn't connect to cloud to get the time...
  // }

  // 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.

  secsTilQtr = secsTilQtr - 45;
  if (secsTilQtr <= 0) secsTilQtr = 10;
  Cellular.on();
  System.sleep(SLEEP_MODE_DEEP, secsTilQtr);
}
int TXinterval(String command) {
  /* Particle.functions always take a string as an argument and return an integer.
  Since we can pass a string, it means that we can give the program commands on how the function should be used.
  In this case, telling the function "on" will turn the LED on and telling it "off" will turn the LED off.
  Then, the function returns a value to us to let us know what happened.
  In this case, it will return 1 for the LEDs turning on, 0 for the LEDs turning off,
  and -1 if we received a totally bogus command that didn't do anything to the LEDs.
  */

  if (command == "1 min") {
    Serial.println("1 min");
    TXint = 1;
    return 1;
  }
  else if (command == "15 min") {
    Serial.println("15 min");
    TXint = 15;
    return 1;
  }
  else if (command == "60 min") {
    Serial.println("60 min");
    TXint = 60;
    return 1;
  }
  else {
    return -1;
  }
}

void onReceive(int packetSize) {
  noInterrupts();

  // try to parse packet
  if (packetSize > sizeof RX_DATA[j]) packetSize = sizeof RX_DATA[j];
  for (j = 0; j < 20; j++) {
    if (RX_data_flag[j] == 0) {
      for (int i = 0; i < packetSize; i++) {
        char spi = ((char) LoRa.read());
        RX_DATA[j][i] = spi;
      }
      RSSI[j] = LoRa.packetRssi();
      if (!sendACK()) {
        // Serial.println("Received Data Bad:  ");
        // Serial.println(RX_DATA[j]);

        RX_data_flag[j] = 0;
        memset(RX_DATA[j], 0, sizeof RX_DATA[j]);
        break;
      }
      else {
        RX_data_flag[j] = 1;
        break;
      }
    }
    else if (j == 19) {
      for (int i = 0; i < packetSize; i++) {
        char spi = ((char) LoRa.read());
      }
    }

  }
  LoRa.receive(); // go back into receive mode
  interrupts();
}

int sendACK() {
  //cape.encrypt(RX_DATA[j], encrypted, sizeof encrypted-1, 176);
  //Serial.print("Decrypted:  ");
  isEncrypted = false;
  if (!strstr(RX_DATA[j], "S,")){
    isEncrypted = true;
    cape.decrypt(RX_DATA[j], decrypted, strlen(RX_DATA[j]));
    memcpy(RX_DATA[j], decrypted, 69);
    memset(decrypted, 0, sizeof decrypted);
    memset(encrypted, 0, sizeof encrypted);
    Serial.println(RX_DATA[j]);
  }
  if (strstr(RX_DATA[j], "S,")) {
    int i;
    char * pt;
    char DATA[12][12];
    char buffer[80];
    memcpy(buffer, RX_DATA[j], 80);
    //Serial.println(buffer);
    pt = strtok(buffer, ",");
    if (pt != NULL) {
      for (i = 0; i < 12; i++) {
        strcpy(DATA[i], pt);

        pt = strtok(NULL, ",");
      }
    }

    float datacheck = NULL;
    char * end;
    RXICCID = DATA[1];


    deviceType = DATA[2];
    datacheck = strtol(deviceType, & end, 10);
    if (strlen(end)) {
      //Serial.println("Conversion error deviceType");
      return 0;
    }
    //else Serial.println("good data ID");
    if (1 > datacheck || datacheck > 9) return 0;

    rxIDACK = DATA[3];
    datacheck = strtol(rxIDACK, & end, 10);
    if (strlen(end)) {
      //Serial.println("Conversion error ID");
      return 0;
    }
    //else Serial.println("good data ID");
    if (10000 > datacheck || datacheck > 99999) return 0;

    checkVbatt = DATA[4];
    datacheck = strtof(checkVbatt, & end);
    if (strlen(end)) {
      //Serial.println("Conversion error Vbatt");
      return 0;
    }
    //else Serial.println("good data Vbatt");
    if (0 > datacheck || datacheck > 6) return 0;

    checkTemp1 = DATA[5];
    datacheck = strtof(checkTemp1, & end);
    if (strlen(end)) {
      Serial.println("Conversion error T1");
      return 0;
    }
    //else Serial.println("good data T1");
    if (-60 > datacheck || datacheck > 150) return 0;
    if (!strstr(DATA[7], "*")){
      checkTemp2 = DATA[7];
      datacheck = strtof(checkTemp2, & end);
      if (strlen(end)) {
        //Serial.println("Conversion error T2");
        return 0;
      }
    }
    //else Serial.println("good data T1");
    if (-60 > datacheck || datacheck > 150) return 0;

    if (!strstr(DATA[8], "*")){
      checkTemp3 = DATA[8];
      datacheck = strtof(checkTemp3, & end);
      if (strlen(end)) {
        //Serial.println("Conversion error T3");
        return 0;
      }
      //else Serial.println("good data T1");
      if (-60 > datacheck || datacheck > 150) return 0;
    }

    if (!strstr(DATA[9], "*")){
      checkTemp4 = DATA[9];
      datacheck = strtof(checkTemp4, & end);
      if (strlen(end)) {
        //Serial.println("Conversion error T4");
        return 0;
      }
      //else Serial.println("good data T1");
      if (-60 > datacheck || datacheck > 150) return 0;
    }

    if (!strstr(DATA[10], "*")){
      checkTemp5 = DATA[10];
      datacheck = strtof(checkTemp5, & end);
      if (strlen(end)) {
        //Serial.println("Conversion error T5");
        return 0;
      }
      //else Serial.println("good data T1");
      if (-60 > datacheck || datacheck > 150) return 0;
    }

    if (!strstr(DATA[11], "*")){
      checkTemp6 = DATA[11];
      datacheck = strtof(checkTemp6, & end);
      if (strlen(end)) {
        //Serial.println("Conversion error T6");
        return 0;
      }
      //else Serial.println("good data T1");
      if (-60 > datacheck || datacheck > 150) return 0;
    }


    char tempACK[3];
    sprintf(tempACK, "%02d", TXint); //maintain TX interval size ie. 01 or 15
    int datatype = strtol(deviceType, & end, 10);
    if (strstr(WakeID, rxIDACK)){
      WakeCommand = 0;
      strcpy(WakeID, "EMPTY");
      WakeCommand = 0;
    }

    if (isEncrypted == false){
      Serial.println("sending to unencrypted device");
      char sNew[3];
      char mNew[3];
      char hNew[3];
      sprintf(hNew, "%02d", Time.hour());
      sprintf(mNew, "%02d", Time.minute());
      sprintf(sNew, "%02d", Time.second());

      if (strstr(RXICCID, ICCID) || strstr(RXICCID, "OPEN")) {
        ACK = ACK + rxIDACK + "," + tempACK + "," + hNew + "," + mNew + "," + sNew + "," + ICCID;
        Serial.println(ACK);
        LoRa.beginPacket();
        LoRa.print(ACK);
        LoRa.endPacket();
        ACK = "";
        return 1;
      }
    }
    switch (datatype) {
      case 3:
        if (strstr(SleepID, rxIDACK)) {
        //sleep ACK command;
          ACK = ACK + rxIDACK + ",SLEEP";
          Serial.println(ACK);
          ACK.toCharArray(decrypted, strlen(ACK)+1);
          cape.encrypt(decrypted, encrypted, strlen(ACK)+1, 176);
          LoRa.beginPacket();
          LoRa.print(encrypted);
          LoRa.endPacket();
          // Serial.println(strlen(encrypted));
          // Serial.println(strlen(decrypted));
          // Serial.println(strlen(ACK));
          memset(decrypted, 0, sizeof decrypted);
          memset(encrypted, 0, sizeof encrypted);
          ACK = "";
          strcpy(SleepID, "EMPTY");
        }
        else if (strstr(rxIDACK,targetID)) {
            Serial.println("targetID");
            ACK = ACK + rxIDACK + "," + tempACK + "," + ICCID + "," + Time.now() + "," + input1 + "," + input2;
            Serial.println(ACK);
            ACK.toCharArray(decrypted, strlen(ACK)+1);
            cape.encrypt(decrypted, encrypted, strlen(ACK)+1, 176);
            LoRa.beginPacket();
            LoRa.print(encrypted);
            LoRa.endPacket();
            memset(decrypted, 0, sizeof decrypted);
            memset(encrypted, 0, sizeof encrypted);
            strcpy(targetID, "EMPTY");
            ACK = "";
            input1 = 0;
            input2 = 0;
        }
        else if (strstr(RXICCID, ICCID) || strstr(RXICCID, "OPEN")) {
            ACK = ACK + rxIDACK + "," + tempACK + "," + ICCID + "," + Time.now() + ",0,0";
            Serial.println(ACK);
            ACK.toCharArray(decrypted, strlen(ACK)+1);
            cape.encrypt(decrypted, encrypted, strlen(ACK)+1, 176);
            LoRa.beginPacket();
            LoRa.print(encrypted);
            LoRa.endPacket();
            memset(decrypted, 0, sizeof decrypted);
            memset(encrypted, 0, sizeof encrypted);
            ACK = "";
        }
        break;
      default:
        char sNew[3];
        char mNew[3];
        char hNew[3];
        sprintf(hNew, "%02d", Time.hour());
        sprintf(mNew, "%02d", Time.minute());
        sprintf(sNew, "%02d", Time.second());

        if (strstr(RXICCID, ICCID) || strstr(RXICCID, "OPEN")) {
          ACK = ACK + rxIDACK + "," + tempACK + "," + hNew + "," + mNew + "," + sNew + "," + ICCID;
          ACK.toCharArray(decrypted, strlen(ACK)+1);
          cape.encrypt(decrypted, encrypted, strlen(ACK)+1, 176);
          LoRa.beginPacket();
          LoRa.print(encrypted);
          LoRa.endPacket();
          memset(decrypted, 0, sizeof decrypted);
          memset(encrypted, 0, sizeof encrypted);
          ACK = "";

        }

      }
      if (WakeCommand) {
        //Wake ACK command;
        ACK = ACK + WakeID + ",WAKE";
        Serial.println(ACK);
        ACK.toCharArray(decrypted, strlen(ACK)+1);
        cape.encrypt(decrypted, encrypted, strlen(ACK)+1, 176);
        LoRa.beginPacket();
        LoRa.print(encrypted);
        LoRa.endPacket();
        memset(decrypted, 0, sizeof decrypted);
        memset(encrypted, 0, sizeof encrypted);
        ACK = "";
        WakeCommand--;
        if (WakeCommand <= 0){
          strcpy(WakeID, "EMPTY");
          WakeCommand = 0;
        }
      }
      return 1;
    }
    else return 0;
}

char * extract_between(const char * str,
  const char * p1,
    const char * p2) {
  char * ret;
  const char * i1 = strstr(str, p1);
  if (i1 != NULL) {
    const size_t pl1 = strlen(p1);
    const char * i2 = strstr(i1 + pl1, p2);
    if (p2 != NULL) {
      /* Found both markers, extract text. */
      const size_t mlen = i2 - (i1 + pl1);
      ret = (char * ) malloc(mlen + 1);
      if (ret != NULL) {
        memcpy(ret, i1 + pl1, mlen);
        ret[mlen] = '\0';
        return ret;
      } else {
        ret = "FAIL";
        return ret;
      }
    } else {
      ret = "FAIL";
      return ret;
    }
  } else {
    ret = "FAIL";
    return ret;
  }
}

void getICCID() {

  CellularDevice device;
  memset( & device, 0, sizeof(device));
  device.size = sizeof(device);
  cellular_device_info( & device, NULL);
  Serial.println(device.iccid);
  int N = 4;
  int sublen = strlen(device.iccid) - N;
  memcpy(ICCID, device.iccid + sublen, N);
  ICCID[N] = '\0';
  Serial.print("My ICCID is: ");
  Serial.println(ICCID);

}
int DataonDemand(String command){
  char * pt;
  char *ptr;
  char test[50];
  command.toCharArray(test, strlen(command)+1);
  Serial.println(test);
  pt = strtok(test, ",");
  input1 = strtoul(pt, &ptr, 10);
  pt = strtok(NULL, ",");
  input2 = strtoul(pt, &ptr, 10);
  pt = strtok(NULL, ",");
  strcpy(targetID, pt);
  Serial.println(targetID);
  if(input2-input1 > 259200) {
    input1 = input2 = 0;
    return -1; //period is longer than 72hrs
  }
  else return 1;
}
void watchdogCallback() {
  System.reset();
}
int Sleepsensor(String command){
  char * pt;
  char *ptr;
  char test[50];

  command.toCharArray(test, strlen(command)+1);
  Serial.println(test);
  pt = strtok(test, "Sleep:");
  strcpy(SleepID, pt);
  Serial.println(SleepID);
  return 1;
}

int Wakesensor(String command){
  char * pt;
  char *ptr;
  char test[50];
  command.toCharArray(test, strlen(command)+1);
  Serial.println(test);
  pt = strtok(test, "Wake:");
  strcpy(WakeID, pt);
  Serial.println(WakeID);
  WakeCommand = 5;

  ACK = ACK + WakeID + ",WAKE";
  Serial.println(ACK);
  ACK.toCharArray(decrypted, strlen(ACK)+1);
  cape.encrypt(decrypted, encrypted, strlen(ACK)+1, 176);
  LoRa.beginPacket();
  LoRa.print(encrypted);
  LoRa.endPacket();
  memset(decrypted, 0, sizeof decrypted);
  memset(encrypted, 0, sizeof encrypted);
  ACK = "";
  LoRa.receive(); // go back into receive mode
  return 1;
}

void changeLoRaNet(){
  if((Time.minute() - 1)%15 == 0 && LoRaSwitch == false){
    Serial.println("Long distance operation..");
    LoRaSwitch = true;
    if (!LoRa.begin(915E6)) {
      Serial.println("Starting LoRa failed!");
      while (1);
    }
    LoRa.setSpreadingFactor(8);
    LoRa.setSignalBandwidth(62500);
    LoRa.enableCrc();
    LoRa.onReceive(onReceive);
    LoRa.receive();
    catchTime = millis();
  }
  else if ((Time.minute() - 2)%15 == 0 && LoRaSwitch == true){
    Serial.println("Regular operation..");
    LoRaSwitch = false;
    if (!LoRa.begin(915E6)) {
      Serial.println("Starting LoRa failed!");
      while (1);
    }
    LoRa.setSpreadingFactor(8);
    LoRa.setSignalBandwidth(62500);
    LoRa.enableCrc();
    LoRa.onReceive(onReceive);
    LoRa.receive();
    catchTime = millis();
  }
}

This is the code I’m running, essentially takes a pile of wireless readings and uploads them to the network…

Generally I’ve also been having similar issues, and I’ve been working on replicating it (I’m using Automatic mode).

One thing, this block of code seems like it doesn’t serve a purpose because a delay of under 1000 won’t allow the System Firmware to be called. I would recommend either explicitly calling Particle.process() instead of delay(50) or maybe just delaying 1000 if you’re expecting any state change in that loop. Otherwise it’s just a guaranteed delay of 120 seconds if you aren’t connected.

while (!Particle.connected()) {
        delay(50);
        Serial.println("not connected");
        Serial.println(millis() - startTime);

        if ((millis() - startTime) > 120000) {
          Serial.println("did not connect for 120 seconds!");
          Serial.println("breaking out of first while loop");
          int notConnected = 1;
          break;
        }
      }

Also, this code seems like something to look closer into. I know I’ve recently experienced issues with calling Particle.disconnect() causing the Particle.connected() to still return true, and also issues with calling Particle.connected() sometimes causing the device to infinitely attempt to reconnect. This is my post EDIT: that post is no longer relevant, though I have experienced some similar issues from some other, unknown reasons

if (!success) {
          Serial.printlnf("%7d(s): publish failed: %d", (millis() - b4Publish) / 1000);
          if (retries < 3) {
            Particle.disconnect();
            delay(3000);
            Particle.connect();
            Serial.print("Retry: ");
            Serial.println(retries + 1);
            retries++;
            goto RETRY_START;
          }

Also, to address more specifically your original question, it seems very likely that the issue you are seeing is getting locked into an irrecoverable state where one of the two following items is true - either:
A) The device doesn’t realize it is not connected and thus doesn’t attempt to reconnect
or
B) The device is attempting to reconnect but something is preventing that process from successfully completing

Also, if there was an issue on the modem side of things, a watchdog reset wouldn’t reset the modem unless you added special code to manually do so in the watchdog callback function. Which by the way you should really use a stack size higher than the default when using ApplicationWatchdog - have you tested it? I’d recommend using at least 1536 (triple the default of 512).

AFAIK, that's not quite so. After any accumulated 1000ms of delay time (whether a single or multiple calls to delay()) Particle.process() will be called.


BTW, nice copy/paste :see_no_evil:

1 Like

AFAIK, that’s not quite so. After any accumulated 1000ms of delay time (whether a single or multiple calls to delay()) Particle.process() will be called.

Interesting, I'm assuming that's accumulated within the context of that particular call to loop()? That seems a little strange to me, since I had assumed that the need for the >1000ms was that because Particle.process() takes some time to complete, the System Firmware couldn't guarantee that it would return in time for a delay smaller than that to be accurate. But perhaps that is not the case (after all, 1000ms is a really long time for a process, though perhaps it's waiting up to a timeout to detect disconnections?)

I can't think of any reason that would be a meaningful difference, except I could see that unintentionally resetting the watchdog timer when someone might not intuitively expect it.

BTW, nice copy/paste :see_no_evil:

Haha I've been using 4096 but I figured the value you provided in the other post was safe enough to recommend :smiley:

The electron seems to becoming unresponsive during particle.publish… trying to get more debug info…

You can have a browse in the implementation

1 Like

I think the issue is that particle.publish some times does not return…

@PeaTearDial, that might be if the Electron loses connectivity. You may want to look at the NO_ACK flag in the Particle.publish() documentation. :wink:

1 Like

is there any other way to check if the electron is connected than if (Particle.connected())?

OK, I’ve added a check to make sure it has been 1 second since the last publish…

I also removed the WITH_ACK…

Seems to be working so far…

1 Like

Hate to resurrect this thread…

Anyone have any ideas why the electron is going into the particle.publish command and not returning?

Just wondering why I would need a larger than default stack size for the app watchdog?

Since the application watchdog was first implemented, the system reset code and a few other things have grown in memory usage, such that the default value can trigger a stack overflow. Don’t remember all the specifics, but that’s roughly the gist iirc

3 Likes

OK cool, I’ll increase it and see if it helps… running out of ideas… I have spaced out my publishes to 5second intervals… but unfortunately it still freezes during publish eventually…

How did you narrow it down to the Particle.publish() command in particular? Were you monitoring a device via Serial? Have you been able to observe the onboard RGB LED behavior in the frozen/error state?

Issues that cause things to freeze are no fun, thats for sure!