RIOT icon indicating copy to clipboard operation
RIOT copied to clipboard

gnrc/lorawan: add basic LoRaWAN 1.1 features

Open Ollrogge opened this issue 2 years ago • 31 comments

Contribution description

This PR adds basic support for LoRaWAN version 1.1. This includes joining a network and sending / receiving data. This PR also modifies the LoRaWAN 1.0 code to use the 1.1 terms. This should not change the behavior of the 1.0 code and everything should still work.

Not implemented are ReJoin-Requests and MAC commands such as RekeyInd and RekeyConf.

For testing purposes I setup a private LoRaWAN network using the Chirpstack and was able to join the network and send data.

Testing procedure

  • tests/gnrc_lorawan_11
  • examples/gnrc_lorawan if able to setup a private LoRaWAN network

Ollrogge avatar Mar 29 '22 17:03 Ollrogge

Overall the code looks nice and the changes make sense. I left some comments there and plan to run some tests when they are addressed.

jia200x avatar Apr 05 '22 10:04 jia200x

Overall the code looks nice and the changes make sense. I left some comments there and plan to run some tests when they are addressed.

I think I have addressed all comments now :)

Ollrogge avatar Apr 11 '22 16:04 Ollrogge

2. How does the user join to a LoRaWAN 1.0.x NS if using the 1.1 binary?

That is not possible at the moment. I could however add e.g. a fall_back variable to the context struct and execute 1.0 code with 1.1 firmware if this flag is set.

This however would require one more CONFIG_ flag I believe ? Since the 1.0 code is not compiled in if 1.1 is used. E.g. CONFIG_GNRC_LORAWAN_HYBRID

Ollrogge avatar Apr 12 '22 12:04 Ollrogge

That is not possible at the moment. I could however add e.g. a fall_back variable to the context struct and execute 1.0 code with 1.1 firmware if this flag is set.

Hmmm from what I read in the standard it only seems to be a matter of choosing the "right" keys in order to join an 1.0.x backend. All the rest should be retrocompatible by design. If that doesn't work, maybe there's something missing in the implementation.

jia200x avatar Apr 12 '22 12:04 jia200x

@jia200x Should I rather prioritize stack usage or coverage ? E.g. should I leave a struct member only needed in LoRaWAN 1.1 to increase coverage with if(IS_USED(... or remove it with #if if using LoRaWAN 1.0 ?

Ollrogge avatar Apr 15 '22 05:04 Ollrogge

Ideally members should be removed from the struct if they are not used. Although this rules out if(IS_USED), you can always write getters/setters that map to no op if you don't need the member. You can then use if(IS_USED) with the getter/setter and use #ifdef in the getter/setter definition.

jia200x avatar Apr 15 '22 07:04 jia200x

Ideally members should be removed from the struct if they are not used. Although this rules out if(IS_USED), you can always write getters/setters that map to no op if you don't need the member. You can then use if(IS_USED) with the getter/setter and use #ifdef in the getter/setter definition.

In order for 1.1 firmware to work with a 1.0x NS I had to add handling of the OptNeg bit. This would have removed all possibilities to use if(IS_USED). Therefore, I added a getter and setter for the optneg bit of the mac struct.

Furthermore I implemented the acknowledgement frame counter and addressed all other comments :)

Ollrogge avatar Apr 15 '22 15:04 Ollrogge

Last round of (style) comments. Otherwise, I will proceed testing it against a Chirpstack instance.

From the Kconfig side I'm also not sure how to deal with the pseudomodule, since some of the options are exposed only if GNRC_LORAWAN_1_1 is used, but GNRC LoRaWAN is still not modeled. Maybe @leandrolanzieri could provide some insights?

Addressed all your latest comments now :)

Ollrogge avatar Apr 25 '22 10:04 Ollrogge

@jia200x Do you need anything else to start testing?

Ollrogge avatar May 02 '22 13:05 Ollrogge

@jia200x Do you need anything else to start testing?

Time :smile:

I will give it a look during the week

jia200x avatar May 02 '22 15:05 jia200x

@jia200x Do you need anything else to start testing?

Time smile

I will give it a look during the week

All good :) Just wondered if there was maybe something I missed

Ollrogge avatar May 02 '22 16:05 Ollrogge

I will give it a look during the week

Uh, I couldn't make it this week :/. I will be back on Wednesday and plan to continue with testing

jia200x avatar May 06 '22 12:05 jia200x

while testing, I realized the netif commands are not implemented in sc_gnrc_netif (so, you cannot e.g set the join key from the shell). This is important, since RIOTCtrl uses the shell for setting the keys. Could you implement that as well? It should be straightforward

jia200x avatar May 17 '22 13:05 jia200x

Otherwise I can join the Network Server using 1.1!

ifconfig
Iface  3  HWaddr: 26:0B:79:1B  Frequency: 868299987Hz  RSSI: -157  BW: 125kHz  SF: 12  CR: 4/5  Link: up 
           TX-Power: 14dBm  State: SLEEP  Demod margin.: 0  Num gateways.: 0 
          IQ_INVERT  
          RX_SINGLE  OTAA  L2-PDU:767  

jia200x avatar May 17 '22 13:05 jia200x

after flashing again, I get these messages from the join server:

DevNonce is too small

Any ideas?

jia200x avatar May 17 '22 13:05 jia200x

while testing, I realized the netif commands are not implemented in sc_gnrc_netif (so, you cannot e.g set the join key from the shell). This is important, since RIOTCtrl uses the shell for setting the keys. Could you implement that as well? It should be straightforward

Done. Hope I didn't mess anything up. These key names are really hard to remember.

Ollrogge avatar May 17 '22 19:05 Ollrogge

after flashing again, I get these messages from the join server:

DevNonce is too small

Any ideas?

Yes this is due to the new requirements for the DevNonce in LoRaWAN 1.1: A DevNonce value SHALL NEVER be reused for a given JoinEUI value. If the end-device can be power-cycled then DevNonce SHALL be persistent (stored in a non-volatile memory).

You get the error because after powercycling the DevNonce used by the device is 0 but the JoinServer expects a different value.

This requires the LoRaWAN code to store state in flash memory. I will implement this tomorrow.

Ollrogge avatar May 17 '22 19:05 Ollrogge

after flashing again, I get these messages from the join server:

DevNonce is too small

Any ideas?

Yes this is due to the new requirements for the DevNonce in LoRaWAN 1.1: A DevNonce value SHALL NEVER be reused for a given JoinEUI value. If the end-device can be power-cycled then DevNonce SHALL be persistent (stored in a non-volatile memory).

You get the error because after powercycling the DevNonce used by the device is 0 but the JoinServer expects a different value.

This requires the LoRaWAN code to store state in flash memory. I will implement this tomorrow.

@jia200x Added the storage of this data in flash memory. Error should be gone now

Ollrogge avatar May 18 '22 14:05 Ollrogge

hmmmm for some reason the device joins (TTN), but the NS does not receive data using the txtsnd command :(. I tried the same commands with LoRaWAN 1.0.3 (current master) and it works. Have you seen this behavior before? Are you using Chirpstack as NS?

jia200x avatar May 23 '22 15:05 jia200x

hmmmm for some reason the device joins (TTN), but the NS does not receive data using the txtsnd command :(. I tried the same commands with LoRaWAN 1.0.3 (current master) and it works. Have you seen this behavior before? Are you using Chirpstack as NS?

No, unfortunately I haven't seen this before and yes I am using Chirpstack as NS. How are you testing the implementation with TTN ? Maybe I can reproduce and debug the issue.

Ollrogge avatar May 24 '22 09:05 Ollrogge

No, unfortunately I haven't seen this before and yes I am using Chirpstack as NS. How are you testing the implementation with TTN ? Maybe I can reproduce and debug the issue.

I compile the examples/gnrc_lorawan with these settings (I X'd the keys)

diff --cc examples/gnrc_lorawan/Makefile
index d8cdb15b35,d8cdb15b35..5319cf4277
--- a/examples/gnrc_lorawan/Makefile
+++ b/examples/gnrc_lorawan/Makefile
@@@ -15,7 -15,7 +15,7 @@@ USEMODULE += auto_init_gnrc_neti
  # Add support for GNRC LoRaWAN
  USEMODULE += gnrc_lorawan
  # Add support for GNRC LoRaWAN 1.1
--# USEMODULE += gnrc_lorawan_1_1
++USEMODULE += gnrc_lorawan_1_1
  
  # Use GNRC pktdump to print downlink messages
  USEMODULE += gnrc_pktdump
@@@ -56,11 -56,11 +56,11 @@@ ifndef CONFIG_KCONFIG_USEMODULE_LORAWA
    # header. Therefore this flag will be removed after that
    CFLAGS += -DCONFIG_GNRC_NETIF_LORAWAN_NETIF_HDR
  
--  CFLAGS += -DCONFIG_LORAMAC_APP_KEY_DEFAULT=\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\"
--  CFLAGS += -DCONFIG_LORAMAC_NWK_KEY_DEFAULT=\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\"
--  CFLAGS += -DCONFIG_LORAMAC_APP_EUI_DEFAULT=\"BBBBBBBBBBBBBBBB\"
--  CFLAGS += -DCONFIG_LORAMAC_JOIN_EUI_DEFAULT=\"BBBBBBBBBBBBBBBB\"
--  CFLAGS += -DCONFIG_LORAMAC_DEV_EUI_DEFAULT=\"CCCCCCCCCCCCCCCC\"
++  CFLAGS += -DCONFIG_LORAMAC_APP_KEY_DEFAULT=\"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\"
++  CFLAGS += -DCONFIG_LORAMAC_NWK_KEY_DEFAULT=\"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
++  CFLAGS += -DCONFIG_LORAMAC_APP_EUI_DEFAULT=\"0000000000000000\"
++  CFLAGS += -DCONFIG_LORAMAC_JOIN_EUI_DEFAULT=\"0000000000000000\"
++  CFLAGS += -DCONFIG_LORAMAC_DEV_EUI_DEFAULT=\"XXXXXXXXXXXXXXXX\"
  
    # For TTN, It's necessary to set the RX2 DR to 3 in EU_868 region
    # CFLAGS += -DCONFIG_LORAMAC_DEFAULT_RX2_DR_3

The NS is configured with LoRaWAN 1.1 and "RP001 Regional Parameters 1.0.3 revision A". I simply run:

ifconfig 3 up
/* wait some seconds */
ifconfig /* <- shows link is up */
txtsnd 3 01 RIOT

The NS does not receive data.

jia200x avatar May 24 '22 09:05 jia200x

No, unfortunately I haven't seen this before and yes I am using Chirpstack as NS. How are you testing the implementation with TTN ? Maybe I can reproduce and debug the issue.

I compile the examples/gnrc_lorawan with these settings (I X'd the keys)

diff --cc examples/gnrc_lorawan/Makefile
index d8cdb15b35,d8cdb15b35..5319cf4277
--- a/examples/gnrc_lorawan/Makefile
+++ b/examples/gnrc_lorawan/Makefile
@@@ -15,7 -15,7 +15,7 @@@ USEMODULE += auto_init_gnrc_neti
  # Add support for GNRC LoRaWAN
  USEMODULE += gnrc_lorawan
  # Add support for GNRC LoRaWAN 1.1
--# USEMODULE += gnrc_lorawan_1_1
++USEMODULE += gnrc_lorawan_1_1
  
  # Use GNRC pktdump to print downlink messages
  USEMODULE += gnrc_pktdump
@@@ -56,11 -56,11 +56,11 @@@ ifndef CONFIG_KCONFIG_USEMODULE_LORAWA
    # header. Therefore this flag will be removed after that
    CFLAGS += -DCONFIG_GNRC_NETIF_LORAWAN_NETIF_HDR
  
--  CFLAGS += -DCONFIG_LORAMAC_APP_KEY_DEFAULT=\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\"
--  CFLAGS += -DCONFIG_LORAMAC_NWK_KEY_DEFAULT=\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\"
--  CFLAGS += -DCONFIG_LORAMAC_APP_EUI_DEFAULT=\"BBBBBBBBBBBBBBBB\"
--  CFLAGS += -DCONFIG_LORAMAC_JOIN_EUI_DEFAULT=\"BBBBBBBBBBBBBBBB\"
--  CFLAGS += -DCONFIG_LORAMAC_DEV_EUI_DEFAULT=\"CCCCCCCCCCCCCCCC\"
++  CFLAGS += -DCONFIG_LORAMAC_APP_KEY_DEFAULT=\"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\"
++  CFLAGS += -DCONFIG_LORAMAC_NWK_KEY_DEFAULT=\"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
++  CFLAGS += -DCONFIG_LORAMAC_APP_EUI_DEFAULT=\"0000000000000000\"
++  CFLAGS += -DCONFIG_LORAMAC_JOIN_EUI_DEFAULT=\"0000000000000000\"
++  CFLAGS += -DCONFIG_LORAMAC_DEV_EUI_DEFAULT=\"XXXXXXXXXXXXXXXX\"
  
    # For TTN, It's necessary to set the RX2 DR to 3 in EU_868 region
    # CFLAGS += -DCONFIG_LORAMAC_DEFAULT_RX2_DR_3

The NS is configured with LoRaWAN 1.1 and "RP001 Regional Parameters 1.0.3 revision A". I simply run:

ifconfig 3 up
/* wait some seconds */
ifconfig /* <- shows link is up */
txtsnd 3 01 RIOT

The NS does not receive data.

How do I access a device that is part of TTN ? I have never interacted with it

Ollrogge avatar May 24 '22 09:05 Ollrogge

How do I access a device that is part of TTN ? I have never interacted with it

You need to register to TTN. You can do it here: https://eu1.cloud.thethings.network Then, you need to add an Application and a Device (similar to Chirpstack). Since TTN works with "ready-to-use" devices, you will need to specify a devkit when selecting the device type. I usually select STM32 and any of the Nucleo-wl5x series.

Do you have a TTN gateway nearby? If so, you can just flash it to a RIOT device. Otherwise, you can use IoT-LAB to book a b-l072z-lrwan1 and work directly with the testbed. They have a TTN gateway there.

If you go with IoT-LAB, you can use the built-in iotlab Makefile logic on RIOT to interact with the remote nodes. Eg

IOTLAB_NODE=st-lrwan1-11.saclay.iot-lab.info BOARD=b-l072z-lrwan1 make clean flash term /* <--- voilà, the remote node is flashed and you get a shell */

EDIT: Please let me know if you need anything

jia200x avatar May 24 '22 09:05 jia200x

How do I access a device that is part of TTN ? I have never interacted with it

You need to register to TTN. You can do it here: https://eu1.cloud.thethings.network Then, you need to add an Application and a Device (similar to Chirpstack). Since TTN works with "ready-to-use" devices, you will need to specify a devkit when selecting the device type. I usually select STM32 and any of the Nucleo-wl5x series.

Do you have a TTN gateway nearby? If so, you can just flash it to a RIOT device. Otherwise, you can use IoT-LAB to book a b-l072z-lrwan1 and work directly with the testbed. They have a TTN gateway there.

If you go with IoT-LAB, you can use the built-in iotlab Makefile logic on RIOT to interact with the remote nodes. Eg

IOTLAB_NODE=st-lrwan1-11.saclay.iot-lab.info BOARD=b-l072z-lrwan1 make clean flash term /* <--- voilà, the remote node is flashed and you get a shell */

EDIT: Please let me know if you need anything

So after some debugging I am 99% certain that no data is received because I haven't yet implemented the RekeyInd MAC command. I found this comment on an issue which indicates that TTN will drop uplink messages if RekeyInd hasn't been sent. Will implement this.

Ollrogge avatar May 30 '22 16:05 Ollrogge

@jia200x I implement the Rekey MAC command and successfully tested it with TTN. Please test again if you can :)

image

Ollrogge avatar May 31 '22 13:05 Ollrogge

Hi. It works now! However, according to this, there should be also backward compatibility between a v1.1 device and a 1.0.3 network server. When I configure that on TTN, it throws invalid MIC. Does it work for you on Chirpstack?

jia200x avatar Jun 28 '22 09:06 jia200x

Hi. It works now! However, according to this, there should be also backward compatibility between a v1.1 device and a 1.0.3 network server. When I configure that on TTN, it throws invalid MIC. Does it work for you on Chirpstack?

Should be fixed as well now !

Ollrogge avatar Jun 29 '22 13:06 Ollrogge

I can confirm this still works as expected when compiling LoRaWAN 1.0.3. I will proceed with all tests for LoRaWAN 1.1

jia200x avatar Aug 08 '22 12:08 jia200x

ok, everything seems to work now

jia200x avatar Aug 23 '22 12:08 jia200x

@jia200x Tests for some boards fail because they don't implement they flashpage API which I need for LoRaWAN 1.1. How should I handle this ?

Ollrogge avatar Aug 29 '22 10:08 Ollrogge