Electron reconnection to cell service

I believe there is a bug, at least in 0.6.2, and possibly others, if you interrupt a Cellular.connect() by calling Cellular.disconnect() and Cellular.off(). It seems to leave things in a bad state and I can’t get it to connect again. This is easily worked around, and with the code below I can successfully disconnect and reconnect the antenna at various times without problems.

#include "Particle.h"

SYSTEM_MODE(SEMI_AUTOMATIC);
SYSTEM_THREAD(ENABLED);

SerialLogHandler logHandler;

const unsigned long STARTUP_DELAY_MS = 5000; // To allow for serial connection to be made
const unsigned long CELLULAR_CONNECT_TIMEOUT_MS = 120000;
const unsigned long CLOUD_CONNECT_TIMEOUT_MS = 30000;
const unsigned long PUBLISH_PERIOD_MS = 30000;
const unsigned long RETRY_CONNECT_DELAY_MS = 60000;

enum State {
    STARTUP_STATE,
    CELLULAR_CONNECT_STATE,
    CELLULAR_CONNECT_WAIT_STATE,
    CLOUD_CONNECT_STATE,
    CLOUD_CONNECT_WAIT_STATE,
    CLOUD_CONNECTED_STATE,
    CLOUD_DISCONNECT_STATE,
    RETRY_WAIT_STATE
};
State state = STARTUP_STATE;
unsigned long stateTime = 0;

void setup() {
    Serial.begin(9600);
}

void loop() {
    switch(state) {
    case STARTUP_STATE:
        if (millis() - stateTime >= STARTUP_DELAY_MS) {
            state = CELLULAR_CONNECT_STATE;
        }
        break;

    case CELLULAR_CONNECT_STATE:
        Log.info("turning cellular on");
        Cellular.on();

        Log.info("connecting to cellular...");
        Cellular.connect();
        state = CELLULAR_CONNECT_WAIT_STATE;
        stateTime = millis();
        break;

    case CELLULAR_CONNECT_WAIT_STATE:
        if (Cellular.ready()) {
            Log.info("connected to cellular");

            state = CLOUD_CONNECT_STATE;
        }
        else
        if (millis() - stateTime >= CELLULAR_CONNECT_TIMEOUT_MS) {
            Log.info("failed to connect to cellular");

            Log.info("disconnecting from cellular");
            Cellular.disconnect();
            delay(2000);

            Log.info("turning cellular off");
            Cellular.off();

            // There appears to be a bug in 0.6.2 where if you interrupt a cellular connect,
            // you can't connect again. Work around this by going into deep sleep for a few
            // seconds which will reset the system firmware state. You can tell this is happening
            // if you go into breathing dark blue after doing the Cellular.connect().
            // https://community.particle.io/t/particle-connection-process-modem-cancel-bug-if-modem-registration-aborted/33138/
            Log.info("going into deep sleep to reset device and modem");
            delay(2000);

            System.sleep(SLEEP_MODE_DEEP, 10);

            // Not reached, system will reset and start over with setup and loop again after waking up
        }
        break;

    case CLOUD_CONNECT_STATE:
        Log.info("connecting to cloud");
        Particle.connect();
        state = CLOUD_CONNECT_WAIT_STATE;
        stateTime = millis();
        break;

    case CLOUD_CONNECT_WAIT_STATE:
        if (Particle.connected()) {
            state = CLOUD_CONNECTED_STATE;
            stateTime = millis();
        }
        else
        if (millis() - stateTime >= CLOUD_CONNECT_TIMEOUT_MS) {
            Log.info("failed to connect to the cloud");
            state = CLOUD_DISCONNECT_STATE;
        }
        break;

    case CLOUD_CONNECTED_STATE:
        if (Particle.connected()) {
            if (millis() - stateTime >= PUBLISH_PERIOD_MS) {
                stateTime = millis();

                // We send test events otherwise the device may not realize it has disconnected
                // from the cloud
                Log.info("sending test event");
                Particle.publish("testEvent", "", PRIVATE);
            }
        }
        else {
            Log.info("lost cloud connection");
            state = CLOUD_DISCONNECT_STATE;
        }
        break;

    case CLOUD_DISCONNECT_STATE:
        Log.info("disconnecting from cloud");
        Particle.disconnect();

        Log.info("disconnecting from cellular");
        Cellular.disconnect();
        delay(2000);

        Log.info("turning cellular off");
        Cellular.off();

        state = RETRY_WAIT_STATE;
        stateTime = millis();
        break;

    case RETRY_WAIT_STATE:
        if (millis() - stateTime >= RETRY_CONNECT_DELAY_MS) {
            state = CELLULAR_CONNECT_STATE;
            break;
        }
    }

}
4 Likes