RIOT
RIOT copied to clipboard
gnrc/lorawan: add basic LoRaWAN 1.1 features
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
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.
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 :)
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
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 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 ?
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.
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 :)
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 :)
@jia200x Do you need anything else to start testing?
@jia200x Do you need anything else to start testing?
Time :smile:
I will give it a look during the week
@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
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
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
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
after flashing again, I get these messages from the join server:
DevNonce is too small
Any ideas?
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.
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.
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
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?
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.
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.
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
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
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.
@jia200x I implement the Rekey MAC command and successfully tested it with TTN. Please test again if you can :)
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?
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 !
I can confirm this still works as expected when compiling LoRaWAN 1.0.3. I will proceed with all tests for LoRaWAN 1.1
ok, everything seems to work now
@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 ?