Is there a built-in cellular back-off scheme?

I could not find anything about this in the docs or the forum:

When a cellular device turns on for the first time, and does not get online in e.g. 3-5 minutes, how can the reason be detected (to indicate it to the user)?

Is there a retry strategy maybe with cellular back-off already built in with Cellular.connect()?

It will retry continuously until you stop it. Every 10 minutes the modem will be power cycled to see if that helps.

There isn’t much propagated up that the user can see, other than being able to tell if the problem is connecting to cellular (blinking green), where Cellular.ready() is false. Or failure to connect to the cloud (blinking cyan) where Cellular.ready() is true and Particle.connected() is false.

There are a number of reasons you could be stuck in blinking green, but Device OS can’t always tell the reason, and even when it can, it’s currently not available to user firmware. It’s not a bad idea for a feature request.

Thanks. Yes, a product must be able to answer why it is not connecting.

Minimum to know is if the device is denied (blocked) or without supported operators available. So a AT+CREG status would be good.

During a cellular disconnected period, would it be ok to do a cellular command periodically every [10]s, like this, but with CREG instead?

SYSTEM_THREAD(ENABLED);
SYSTEM_MODE(SEMI_AUTOMATIC);

SerialLogHandler logHandler;

int callbackICCID(int type, const char* buf, int len, char* iccid)
{
 if ((type == TYPE_PLUS) && iccid) {
   if (sscanf(buf, "\r\n+CCID: %[^\r]\r\n", iccid) == 1)
     /*nothing*/;
 }
 return WAIT;
}

void setup()
{
 char iccid[32] = "";
 WITH_LOCK(Cellular) {
   if ((RESP_OK == Cellular.command(callbackICCID, iccid, 10000, "AT+CCID\r\n"))
     && (strcmp(iccid,"") != 0))
   {
     Log.info("SIM ICCID = %s\r\n", iccid);
   }
   else
   {
     Log.info("SIM ICCID NOT FOUND!");
   }
 }
}

void loop()
{
 // your loop code
}

I found the cellularhelper library, and wait 4s from startup, but I can not get information out of calling the getCREG function (B523, OS 1.5.0):

        CellularHelperCREGResponse CREGinfo;
        CellularHelper.getCREG(CREGinfo);
        Log.info("CREG info: %s", CREGinfo.toString());

I get:

0000040345 [app] INFO: CREG info: �� 

(It is not a great way to know if the Cellular device has been blocked or is finding no supported operator, but it seems to be the only way.)

AT+CREG can’t be used on Gen 3 devices including the B523. The reason is that AT+CREG returns a URC (unsolicited result code) and on Gen 3 devices, URCs are not returned on the callback to Celluar.command so the cellular helper function won’t work.

However, the results from the AT+CREG URC are stored in device diagnostics, so you don’t need to issue that command. The only caveat is that I’m not sure when the data is saved, so it may or may not be helpful for what you are looking to do. But it’s worth a try to see.

Here’s how to read the cellular global identity, which is the information from AT+CREG:

Unfortunately I did not find the CREG parameter that would indicate the needed registration denied …

I have not found this in docs or the community posts, but can user firmware snoop through the loghandler logs?

You’re right, the CREG response is only saved in internal structures, not the diagnostics.

Yes, the user firmware can install a log handler that monitors the system output. I would have recommended that, except I’m not sure that non-debug Device OS builds will have the output you need. If you are seeing the result in your USB serial log, then yes you can intercept it.

The other method I would probably lean toward is having two modes: normal connecting and troubleshooting. If normal connecting mode fails, then your firmware goes into troubleshooting mode where it can take over the modem and do things like tower scans and other intrusive debugging activities. This makes more sense if you have some sort of display to show the results, which is why this sort of thing is not built-in.

Non debug Device OS (1.5.2 B523) does indeed log UPREG via USB serial observed with:

SerialLogHandler logHandler(LOG_LEVEL_TRACE);

0000070114 [ncp.at] TRACE: > AT+CGREG?
0000070161 [ncp.at] TRACE: < +CGREG: 2,2
0000070163 [ncp.at] TRACE: < OK
0000070164 [ncp.at] TRACE: > AT+CEREG?
0000070211 [ncp.at] TRACE: < +CEREG: 2,2
0000070213 [ncp.at] TRACE: < OK
0000079414 [ncp.at] TRACE: < +CREG: 5,"36BB","27CC216",7
0000079515 [ncp.at] TRACE: < +CGREG: 5,"36BB","27CC216",7
0000079518 [hal] TRACE: NCP connection state changed: 2

But so far I have only found examples of generating user firmwarelogs and piping them somewhere like Papertrail etc.

How do you snoop through the log above from user firmware?

What you do is subclass StreamLogHandler and implement the

size_t write(uint8_t c) 

method. Buffer the data from write until you get a \n and that will be the full entry.

Use LogManager::instance()->addHandler() to add the handler to the system log handler.

This is an example of logging to SD card, but it shows how to subclass the log handler and add it.

It’s possible to hook in at a different layer and get the message before being generated as text, but you might not get all of the data that way.

Good point. I plan to indicate “denied” and “no coverage” via LED. Also plan to have an offline device log in FRAM. From experience a single carrier per country is a significant problem for installers in the field.