While doing some tests to better understand the behavior of networking function calls with
SYSTEM_THREAD(ENABLED), I encountered this unexpected behavior. If I call Cellular.disconnect() and then call Cellular.connect(), the Electron will not connect until it hits a timeout and turns the modem off and then back on. This process takes around 6 minutes. If instead I turn the modem all the way off and on before calling Cellular.connect() it connects very quickly (19 seconds). This behavior is consistent across any SYSTEM_MODE or SYSTEM_THREAD.
What is the intended purpose of Cellular.disconnect()? It doesn’t appear to have a functional use without also using Cellular.off().
Serial Output:
Connected to Particle Cloud
TESTING CELLULAR DISCONNECT INCLUDING TURNING CELLULAR OFF...
Particle.disconnect() returned after 0 millis
Disconnecting from Particle Cloud...
Took 523 millis to disconnect
Disconnected from Particle Cloud
Cellular.disconnect() returned after 0 millis
Took 1 millis to disconnect
Cellular.off() returned after 0 millis
Network powering off...
Network off
Took 6310 millis to turn off
Cellular.on() returned after 0 millis
Network powering on...
Network on
Took 3351 millis to turn on
Cellular.connect() returned after 0 millis
Connecting to network...
Took 18631 millis to connect
Connected to network
Particle.connect() returned after 0 millis
Connecting to Particle Cloud...
Connected to Particle Cloud
Took 368 millis to connect
TESTING CELLULAR DISCONNECT WITHOUT TURNING CELLULAR OFF...
Particle.disconnect() returned after 0 millis
Disconnecting from Particle Cloud...
Took 280 millis to disconnect
Disconnected from Particle Cloud
Cellular.disconnect() returned after 0 millis
Took 1 millis to disconnect
Cellular.connect() returned after 0 millis
Connecting to network...
Network powering off...
Network off
Network powering on...
Network on
Connecting to network...
Took 344730 millis to connect
Connected to network
Particle.connect() returned after 0 millis
Connecting to Particle Cloud...
Took 358 millis to connect
Connected to Particle Cloud
My test code:
#include "Particle.h"
SYSTEM_THREAD(ENABLED); // Enable system threading
SYSTEM_MODE(AUTOMATIC); // Allow Particle to manage it's own connectivity
#if Wiring_Cellular
// Set your 3rd-party SIM APN here
// https://docs.particle.io/reference/firmware/electron/#setcredentials-
STARTUP(cellular_credentials_set("hologram", "", "", NULL));
// Cell indicator Config
CellularSignal sig;
int strength;
// 60 seconds chosen since hologram UDP timeout is estimated at around 180 seconds but in practice worked best at 60
const int keepAliveInterval = 20; // keepAlive interval in seconds
#endif
// Used for both WiFi and Cell
int rssi;
String signal_strength;
bool network_status_local = false;
uint32_t time_start;
//..............................................................................
//..............................................................................
void cloud_status_handler(system_event_t event, int param)
{
if (param == cloud_status_connecting)
{
Serial.println("Connecting to Particle Cloud...");
}
else if (param == cloud_status_connected)
{
// init the keepAlive interval to maintain connection to Particle cloud
#if Wiring_Cellular
Particle.keepAlive(keepAliveInterval);
#endif
Serial.println("Connected to Particle Cloud");
}
else if (param == cloud_status_disconnecting)
{
Serial.println("Disconnecting from Particle Cloud...");
}
else if (param == cloud_status_disconnected)
{
Serial.println("Disconnected from Particle Cloud");
}
}
//..............................................................................
//..............................................................................
//..............................................................................
void network_status_handler(system_event_t event, int param)
{
if (param == network_status_connecting)
{
Serial.println("Connecting to network...");
}
else if (param == network_status_connected)
{
Serial.println("Connected to network");
}
else if (param == network_status_off)
{
Serial.println("Network off");
network_status_local = false;
}
else if (param == network_status_on)
{
Serial.println("Network on");
network_status_local = true;
}
else if (param == network_status_powering_on)
{
Serial.println("Network powering on...");
}
else if (param == network_status_powering_off)
{
Serial.println("Network powering off...");
}
}
//..............................................................................
bool waitCloudDisconnect() { return !Particle.connected(); }
bool waitCellDisconnect() { return !Cellular.ready(); }
bool waitCellOff() { return !network_status_local; }
bool waitCellOn() { return network_status_local; }
/* This function is called once at start up ----------------------------------*/
void setup()
{
Serial.begin(9600);
System.on(cloud_status, cloud_status_handler);
System.on(network_status, network_status_handler);
pinMode(A0, OUTPUT);
digitalWrite(A0, LOW);
delay(10000);
Serial.println("PERFORMING INITIAL SETUP");
// TURN ON CELLULAR
time_start = millis();
Cellular.on();
Serial.println("Cellular.on() returned after " + String(millis() - time_start) + " millis");
time_start = millis();
waitUntil(waitCellOn);
Serial.println("Took " + String(millis() - time_start) + " millis to turn on");
delay(1000);
// CONNECT TO CELLULAR NETWORK
time_start = millis();
Cellular.connect();
Serial.println("Cellular.connect() returned after " + String(millis() - time_start) + " millis");
time_start = millis();
waitUntil(Cellular.ready);
Serial.println("Took " + String(millis() - time_start) + " millis to connect");
delay(1000);
// CONNECT TO PARTICLE CLOUD
time_start = millis();
Particle.connect();
Serial.println("Particle.disconnect() returned after " + String(millis() - time_start) + " millis");
time_start = millis();
waitUntil(Particle.connected);
Serial.println("Took " + String(millis() - time_start) + " millis to connect");
delay(1000);
Serial.println("");
Serial.println("");
Serial.println("Setup Complete");
Serial.println("");
Serial.println("");
}
/* This function loops forever --------------------------------------------*/
void loop() {
// now let's kick - for a kick to be valid it must be
// at least 100ns
ATOMIC_BLOCK() // we'll consider this timing critical
{
digitalWrite(A0, HIGH); // rising edge to begin DONE signal detection on TPL5010
delayMicroseconds(10); // wait 10x minimum time of 100ns
digitalWrite(A0, LOW); // bring line back to wait for next kick
}
if (Particle.connected())
{
Serial.println("");
Serial.println("");
Serial.println("TESTING CELLULAR DISCONNECT INCLUDING TURNING CELLULAR OFF...");
// DISCONNECT FROM PARTICLE CLOUD
time_start = millis();
Particle.disconnect();
Serial.println("Particle.disconnect() returned after " + String(millis() - time_start) + " millis");
time_start = millis();
waitUntil(waitCloudDisconnect);
Serial.println("Took " + String(millis() - time_start) + " millis to disconnect");
delay(1000);
// DISCONNECT FROM CELLULAR NETWORK
time_start = millis();
Cellular.disconnect();
Serial.println("Cellular.disconnect() returned after " + String(millis() - time_start) + " millis");
time_start = millis();
waitUntil(waitCellDisconnect);
Serial.println("Took " + String(millis() - time_start) + " millis to disconnect");
delay(1000);
// TURN OFF CELLULAR
time_start = millis();
Cellular.off();
Serial.println("Cellular.off() returned after " + String(millis() - time_start) + " millis");
time_start = millis();
waitUntil(waitCellOff);
Serial.println("Took " + String(millis() - time_start) + " millis to turn off");
delay(1000);
// TURN ON CELLULAR
time_start = millis();
Cellular.on();
Serial.println("Cellular.on() returned after " + String(millis() - time_start) + " millis");
time_start = millis();
waitUntil(waitCellOn);
Serial.println("Took " + String(millis() - time_start) + " millis to turn on");
delay(1000);
// CONNECT TO CELLULAR NETWORK
time_start = millis();
Cellular.connect();
Serial.println("Cellular.connect() returned after " + String(millis() - time_start) + " millis");
time_start = millis();
waitUntil(Cellular.ready);
Serial.println("Took " + String(millis() - time_start) + " millis to connect");
delay(1000);
// CONNECT TO PARTICLE CLOUD
time_start = millis();
Particle.connect();
Serial.println("Particle.connect() returned after " + String(millis() - time_start) + " millis");
time_start = millis();
waitUntil(Particle.connected);
Serial.println("Took " + String(millis() - time_start) + " millis to connect");
delay(1000);
Serial.println("");
Serial.println("");
}
// now let's kick - for a kick to be valid it must be
// at least 100ns
ATOMIC_BLOCK() // we'll consider this timing critical
{
digitalWrite(A0, HIGH); // rising edge to begin DONE signal detection on TPL5010
delayMicroseconds(10); // wait 10x minimum time of 100ns
digitalWrite(A0, LOW); // bring line back to wait for next kick
}
if (Particle.connected())
{
Serial.println("TESTING CELLULAR DISCONNECT WITHOUT TURNING CELLULAR OFF...");
// DISCONNECT FROM PARTICLE CLOUD
time_start = millis();
Particle.disconnect();
Serial.println("Particle.disconnect() returned after " + String(millis() - time_start) + " millis");
time_start = millis();
waitUntil(waitCloudDisconnect);
Serial.println("Took " + String(millis() - time_start) + " millis to disconnect");
delay(1000);
// DISCONNECT FROM CELLULAR NETWORK
time_start = millis();
Cellular.disconnect();
Serial.println("Cellular.disconnect() returned after " + String(millis() - time_start) + " millis");
time_start = millis();
waitUntil(waitCellDisconnect);
Serial.println("Took " + String(millis() - time_start) + " millis to disconnect");
delay(1000);
// CONNECT TO CELLULAR NETWORK
time_start = millis();
Cellular.connect();
Serial.println("Cellular.connect() returned after " + String(millis() - time_start) + " millis");
time_start = millis();
waitUntil(Cellular.ready);
Serial.println("Took " + String(millis() - time_start) + " millis to connect");
delay(1000);
// CONNECT TO PARTICLE CLOUD
time_start = millis();
Particle.connect();
Serial.println("Particle.connect() returned after " + String(millis() - time_start) + " millis");
time_start = millis();
waitUntil(Particle.connected);
Serial.println("Took " + String(millis() - time_start) + " millis to connect");
delay(1000);
Serial.println("");
Serial.println("");
}
// now let's kick - for a kick to be valid it must be
// at least 100ns
ATOMIC_BLOCK() // we'll consider this timing critical
{
digitalWrite(A0, HIGH); // rising edge to begin DONE signal detection on TPL5010
delayMicroseconds(10); // wait 10x minimum time of 100ns
digitalWrite(A0, LOW); // bring line back to wait for next kick
}
delay(5000);
}