mcci-catena/arduino-lmic

Frequency selection is incremental upwards in MHz in cycles, not pseudo random as required by Lorawan Spec

Cloolalang opened this issue · 6 comments

Describe your question or issue
Compared to other end-devices LMIC appears to just increment channels after each uplink, not pseudo random channels selection as shown in LoraWan 1.0.3 line 244

Environment

This information is all important; it's hard to help without a complete set of answers.

  • Version of LMIC being used: Latest Oct 20
  • Version of Arduino IDE being used: Platformio
  • Network provider (The Things Network, Swisscom, ChirpStack, etc.) Rak loraserver
  • Region (EU868, US915, etc.) EU 868
  • Board (MCCI Catena, Adafruit Feather M0, Heltec Wi-Fi LoRa 32 v2, etc.) TTGO V1
  • Radio (HopeRF, SX1276, etc.) SX1276

Add some debug output to the operation of the random number generator at

https://github.com/mcci-catena/arduino-lmic/blob/master/src/lmic/radio.c#L1124

and

https://github.com/mcci-catena/arduino-lmic/blob/master/src/lmic/radio.c#L1162

and see if you are actually getting any randomness

lmic_eu_like.c
lmic_us_like.c

in lmic_us_like.c I found this:

tatic void setNextChannel(uint start, uint end, uint count) {
ASSERT(count>0);
ASSERT(start<end);
ASSERT(count <= (end - start));
// We used to pick a random channel once and then just increment. That is not per spec.
// Now we use a new random number each time, because they are not very expensive.
// Regarding the algo below, we cannot pick a number and scan until we hit an enabled channel.
// That would result in the first enabled channel following a set of disabled ones
// being used more frequently than the other enabled channels.

Thanks for bringing this up. At present, for EU-like plans, the channel number choice is sequential, and has been so from the beginning of the LMIC. The channel selection was randomized for US-like plans to comply with US regulations but we (being in the US) didn't realize that the LoRaWAN spec also required this generally.

The US randomization scheme is known to have problems and should not be copied. Not because it's non-random, but because it chooses channels with replacement (rolls the dice each time, rather than shuffling the deck of channels). There is a planned change to shuffle, because the compliance tests implicitly check for shuffling, as they require that all channels be touched within a small number of total uplinks. I did the math, and we are expected to fail most of the time with a dice-roll. This has practical consequences; if one channel is good, you might not transmit on that channel for much longer than 1/n transmissions. On the other hand, using a shuffle, you can be sure worst case gap between reuses is 2n-2 uplinks.

For what it's worth, the compliance tests don't check this, except in the US where it's required for FCC compliance.

Now that I'm aware of the general requirement, I'll put the shuffle algorithm in the common code rather than in the US code.

Thanks Terry, for taking a look at this,
This library is really a great project, I am very appreciative of your work!
(Im working on a lab-test system (chirpstack) for design verification and per-compliance of end-devices)
P.

@Cloolalang -- this turns out to be an interesting problem.

In US915/AU915 plans, there are 64 125 kHz channels, all basically the same. It turns out that the compliance specs really want you to select without replacement - like shuffling a deck of cards and dealing off the deck until you run out. Dealing without replacement is either RAM intensive or code intensive. I have a routine that is code intensive, and tests nicely; but it's 750 bytes of code on the avr32u4. The code size is worrisome. We may get some back due to the resulting overall simplification. (To my surprise, the same routine is only 468 bytes on CM0+ systems.)

(The code-intensive approach routine only takes ten bytes of RAM for US; and only two bytes for EU, so that's nice.)

However, In EU868, there are three categories of channel ("bands"):

  • channels in a group allowing 10% duty cycle,
  • channels in a group allowing 1% duty cycle and
  • channels in a group allowing 0.1% duty cycle.

What if the next randomly-chosen channel is a 0.1% duty-cycle channel with no bandwidth available; but one of the 1% or 0.1% channels has bandwidth? Shuffling without replacement across all channels will effectively throttle the device in unexpected ways.

At present, the code chooses the first available band (starting with the highest duty cycle, i.e., the 10% band), checks whether there are any enabled and feasible channels, and finally selects one. It would probably be better to construct a mask of all possible channels (across bands and so forth) and then select from that. The shuffle mask could be maintained (although it would not work as nicely as on US bands).

I'm sort of unwilling to break AVR use cases, but we definitely need to improve randomness for the US, and we are supposed to be more random in the EU. Thoughts, anyone?

I have pushed a branch (https://github.com/mcci-catena/arduino-lmic/tree/issue515) that has proposed changes; it intends to implement the "it would be best to..." handwaving outlined above. The branch will run through CI tests and we'll find out whether the code growth breaks AVR.