mcci-catena / arduino-lmic

LoraWAN-MAC-in-C library, adapted to run under the Arduino environment
https://forum.mcci.io/c/device-software/arduino-lmic/
MIT License
643 stars 210 forks source link

LoRaWAN Join backoff not implemented #2

Open terrillmoore opened 7 years ago

terrillmoore commented 7 years ago

According to LoRaWAN 1.02, section 7 (page 37), lines 21 and following:

the interval between the end of the RX2 slot and the next uplink retransmission shall be random and follow a different sequence for every device (For example using a pseudo-random generator seeded with the device‘s address)

A table that follows is hard to read, but it apparently shows the following:

Period after starting JOIN attempt How long to back off Duty-cycle limit
First hour base delay + (0 to 1) seconds less than 36 seconds in first hour
Next ten hours base delay + (1 to 11) seconds less than 36 seconds in this ten-hour period
Subsequent 24-hour periods base delay + 11 + N seconds (incremented once/day) + ( 0 to 24) less than 8.7 seconds per 24h period

The base delay is called T0 in the specification and is not used expect on that page. I believe that the implementation can choose it, but it's not clear.

In any case, the LMIC implementation doesn't do anything like this. Apart from bug #1, which leads to fairly unpredictable behavior once the first JOIN cycle fails, the delay doesn't take into account any of the above considerations.

Possibly need to consider FRAM storage of the partial join state, as devices that are power-cycling still want to delay joining (if they're in the field).

cyberman54 commented 5 years ago

@terrillmoore what would be a straight forward way for a node to check if it's currently joined? Is there a API for this, or can some internal LMIC. be used for this purpose?

terrillmoore commented 5 years ago

For now, check LMIC.devaddr != 0. That's what the LMIC does. We should probably have an API that does the same thing, but ... I'm focused on compliance things so I can merge issue215 into HEAD.

terrillmoore commented 5 years ago

Root cause of the total lack of randomization: LMICbandplan_nextTx() is used by engineUpdate() to calculate the next transmit time, using now as the base time. But LMICbandplan_nextJoinState() previously set the value of LMIC.txend to the next desired join time, including randomization; and that calculated value gets discarded and overwritten by the result of LMICbandplan_nextTx(), which doesn't consider the current value of LMIC.txend.

But.. we probably need a new LMICinternal_backoffTime() that returns the next time in the backoff sequence. (This backoff time is also to be used by devices that will retry and will synchronously need attention from the network; confirmed downlinks and device-initiated MAC requests for sure, but also application layer things (an uplink that causes an application-layer downlink). This sequence would be reset whenever we get a valid downlink; and so can be shared between join and regular operations.) We have an obscure opmode OP_RNDTX bit that could be coopted to help us for this, I think.