Automatic connection reset

boron
Tags: #<Tag:0x00007fe21b8b28b0>

#1

Hi,
After searching high and low and trying an array of code, I am unable to come up with anything that works. Basically I just want to check the connection during the loop and if the connection is not there… then reset the modem on the Boron LTE running an external sim.

if (!Particle.connected) {
    Cellular.off();
    Cellular.command("AT+CFUN=15");        
    Cellular.on();     
    Cellular.connect();
    Particle.connect;
    waitUntil(Particle.connected);
    SMSMode();
   }

#2

What SYSTEM_MODE are you using? Also, your Cellular.command(...) won’t work because you just shut off your modem!

Here is how I do this on an Electron:

if (resetModem) {
    Particle.disconnect();
#if Wiring_Cellular
    SINGLE_THREADED_BLOCK()
    {
        Cellular.command(30000, "AT+CFUN=16\r\n");
    }
    Cellular.off();
#endif
}

To restart the modem, simply run: Particle.connect();

Perhaps give this a try?

Edit:

However be careful with how you are calling this. This is pretty brute force. You may want a more nuanced check. Maybe a timeout of a minute without connection. That would be more extensible.


#3

Using system automatic currently.

Yes. How stupid of me calling the AT command after turning off the modem. Der.

Resetting the modem is not the main problem, it’s rather identifying that the connection has dropped in a timely manner rather then wait for 5 min for the connection to be automatically reset by the boron.


#4

So here’s the thing - connections will drop from time to time in a manner that doesn’t require a modem hard reset. You only really want to do that for large failures. Usually the best way to determine that is with a timeout. Here is a way you could approach this:

// global inits
bool has_connected = false;
bool just_disconnected = true;
uint32_t last_connection = 0;
const uint32_t connection_timeout_ms = 120000UL;    // 2 minutes

// in your loop somewhere
if (!has_connected && Particle.connected()) has_connected = true;
else if (has_connected && !Particle.connected()) {
    if (just_disconnected) {
        just_disconnected = false;
        last_connection = millis();
    }
    else if ((millis() - last_connection) > connection_timeout_ms) {
        resetModem = true;
    }
}
//...
if (resetModem) {
    Particle.disconnect();
#if Wiring_Cellular
    SINGLE_THREADED_BLOCK()
    {
        Cellular.command(30000, "AT+CFUN=16\r\n");
    }
    Cellular.off();
#endif
}

edit:
Oh and definitely use SYSTEM_THREAD(ENABLED); . If you don’t do so your code will get delayed up to a minute or more while the system firmware attempts to reconnect to the cloud in some cases. Read up on SYSTEM_THREAD in the docs and let us know if you have any more questions about it for your use case (and check the forums too).


#5

Thanks mate, will give that a crack. Unfortunately the way I’m using the Borons require them to be available 24/7. I’m not too worried about a drop out here or there as long as I can get them back on line within a minute or so. Not 5 to 6. Thanks for your assistance.


#6

Consider also implementing a hardware watchdog to reset the device externally if a freak device failure is something you need to recover from without human intervention. 24/7 is tough, especially on a pretty young/new hardware set. Something will go wrong eventually. The software application watchdog can also be helpful for failure recovery.

You can definitely hit consistent uptime in good cell coverage, though. I have hundreds of Electrons that are running 24/7 and the only ones that don’t have a 98%+ raw uptime are ones with atrocious cell coverage (-97dB to -112dB) or bad cell quality metrics.

Make sure to spend the time determining why it seems like the device takes time to recover. Utilize on-device logging to determine if it was a cloud connection or a cell connection issue. See if it was an issue with a single attempt or multiple faster attempts that failed. No matter how quickly you reconnect it’s very important to determine the root cause if you want true 24/7 stability. Best of luck and let us know if you have any difficulty!


#7
    SINGLE_THREADED_BLOCK()
    {
        Cellular.command(30000, "AT+CFUN=16\r\n");
    }

The system thread of Device-OS can acquire a lock around the cellular AT interface. By attempting a Cellular.command within SINGLE_THREADED_BLOCK you are running an extremely high risk of deadlocking the system. Connection outages are some of the times that Device-OS is most likely to be communicating with the modem and holding the lock. A deadlock will prevent all FreeRTOS context switching which can also prevent the software application watchdog from triggering.

SINGLE_THREADED_BLOCK is very dangerous and should not be used without careful consideration. Accessing any resource (cellular, wifi, logging, SPI/I2C/UART, dynamic memory, etc) from within such a block can result in deadlocks.

I would also be careful around manual connection management. May interfere with normal Device-OS recovery and cause degenerate connection issues.


#8

if(!Particle.connected) isn’t going to do what you want. You would need if(!Particle.connected()).

Cellular modem is kind of funny. The connection might be “down” but not recognized right away. There are mechanisms both on the cell modem and in Device-OS (background keep-alives) but those still have an interval and consume data. Default keep-alive is 23 minutes which may not be appropriate if you are on a 3rd party sim and result in the connection transparently closing periodically.