Merge pull request #9524 from aabadie/pr/pkg/semtech-loramac_eeprom

pkg/semtech-loramac: use internal eeprom to store lorawan config (deveui, appeui, etc)
This commit is contained in:
José Alamos 2018-10-15 14:51:04 +02:00 committed by GitHub
commit 3849c4b3b7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 266 additions and 71 deletions

View File

@ -41,6 +41,10 @@
#include "LoRaMac.h" #include "LoRaMac.h"
#include "region/Region.h" #include "region/Region.h"
#ifdef MODULE_PERIPH_EEPROM
#include "periph/eeprom.h"
#endif
#define ENABLE_DEBUG (0) #define ENABLE_DEBUG (0)
#include "debug.h" #include "debug.h"
@ -297,6 +301,119 @@ static void mlme_indication(MlmeIndication_t *indication)
} }
} }
#ifdef MODULE_PERIPH_EEPROM
static inline void _set_uplink_counter(semtech_loramac_t *mac, uint8_t *counter)
{
uint32_t counter4 = ((uint32_t)counter[0] << 24 |
(uint32_t)counter[1] << 16 |
(uint32_t)counter[2] << 8 |
counter[3]);
DEBUG("[semtech-loramac] uplink counter: %" PRIu32 " \n", counter4);
mutex_lock(&mac->lock);
MibRequestConfirm_t mibReq;
mibReq.Type = MIB_UPLINK_COUNTER;
mibReq.Param.UpLinkCounter = counter4;
LoRaMacMibSetRequestConfirm(&mibReq);
mutex_unlock(&mac->lock);
}
static inline void _read_loramac_config(semtech_loramac_t *mac)
{
DEBUG("[semtech-loramac] reading configuration from EEPROM\n");
uint8_t magic[SEMTECH_LORAMAC_EEPROM_MAGIC_LEN] = {0};
size_t pos = SEMTECH_LORAMAC_EEPROM_START;
pos += eeprom_read(pos, magic, SEMTECH_LORAMAC_EEPROM_MAGIC_LEN);
if (strncmp((char*)magic, "RIOT", SEMTECH_LORAMAC_EEPROM_MAGIC_LEN) != 0) {
DEBUG("[semtech-loramac] no configuration present on EEPROM "
"(invalid magic '%s')\n", magic);
return;
}
/* LoRaWAN EUIs, Keys and device address */
pos += eeprom_read(pos, mac->deveui, LORAMAC_DEVEUI_LEN);
pos += eeprom_read(pos, mac->appeui, LORAMAC_APPEUI_LEN);
pos += eeprom_read(pos, mac->appkey, LORAMAC_APPKEY_LEN);
pos += eeprom_read(pos, mac->appskey, LORAMAC_APPSKEY_LEN);
pos += eeprom_read(pos, mac->nwkskey, LORAMAC_NWKSKEY_LEN);
pos += eeprom_read(pos, mac->devaddr, LORAMAC_DEVADDR_LEN);
/* uplink counter, mainly used for ABP activation */
uint8_t counter[4] = { 0 };
pos += eeprom_read(pos, counter, 4);
_set_uplink_counter(mac, counter);
}
static inline void _save_uplink_counter(semtech_loramac_t *mac)
{
size_t pos = SEMTECH_LORAMAC_EEPROM_START +
SEMTECH_LORAMAC_EEPROM_MAGIC_LEN +
LORAMAC_DEVEUI_LEN + LORAMAC_APPEUI_LEN +
LORAMAC_APPKEY_LEN + LORAMAC_APPSKEY_LEN +
LORAMAC_NWKSKEY_LEN + LORAMAC_DEVADDR_LEN;
uint8_t counter[4];
mutex_lock(&mac->lock);
MibRequestConfirm_t mibReq;
mibReq.Type = MIB_UPLINK_COUNTER;
LoRaMacMibGetRequestConfirm(&mibReq);
counter[0] = (uint8_t)(mibReq.Param.UpLinkCounter >> 24);
counter[1] = (uint8_t)(mibReq.Param.UpLinkCounter >> 16);
counter[2] = (uint8_t)(mibReq.Param.UpLinkCounter >> 8);
counter[3] = (uint8_t)(mibReq.Param.UpLinkCounter);
mutex_unlock(&mac->lock);
pos += eeprom_write(pos, counter, 4);
}
void semtech_loramac_save_config(semtech_loramac_t *mac)
{
DEBUG("[semtech-loramac] saving configuration on EEPROM\n");
uint8_t magic[] = SEMTECH_LORAMAC_EEPROM_MAGIC;
size_t pos = SEMTECH_LORAMAC_EEPROM_START;
pos += eeprom_write(pos, magic, SEMTECH_LORAMAC_EEPROM_MAGIC_LEN);
/* Store EUIs, Keys and device address */
pos += eeprom_write(pos, mac->deveui, LORAMAC_DEVEUI_LEN);
pos += eeprom_write(pos, mac->appeui, LORAMAC_APPEUI_LEN);
pos += eeprom_write(pos, mac->appkey, LORAMAC_APPKEY_LEN);
pos += eeprom_write(pos, mac->appskey, LORAMAC_APPSKEY_LEN);
pos += eeprom_write(pos, mac->nwkskey, LORAMAC_NWKSKEY_LEN);
pos += eeprom_write(pos, mac->devaddr, LORAMAC_DEVADDR_LEN);
/* save uplink counter, mainly used for ABP activation */
_save_uplink_counter(mac);
}
void semtech_loramac_erase_config(void)
{
DEBUG("[semtech-loramac] erasing configuration on EEPROM\n");
uint8_t magic[SEMTECH_LORAMAC_EEPROM_MAGIC_LEN];
size_t pos = SEMTECH_LORAMAC_EEPROM_START;
eeprom_read(pos, magic, SEMTECH_LORAMAC_EEPROM_MAGIC_LEN);
if (strcmp((char*)magic, "RIOT") != 0) {
DEBUG("[semtech-loramac] no configuration present on EEPROM\n");
return;
}
MibRequestConfirm_t mibReq;
size_t uplink_counter_len = sizeof(mibReq.Param.UpLinkCounter);
size_t end = (pos + SEMTECH_LORAMAC_EEPROM_MAGIC_LEN +
LORAMAC_DEVEUI_LEN + LORAMAC_APPEUI_LEN +
LORAMAC_APPKEY_LEN + LORAMAC_APPSKEY_LEN +
LORAMAC_NWKSKEY_LEN + LORAMAC_DEVADDR_LEN +
uplink_counter_len);
for (size_t p = pos; p < end; p++) {
eeprom_write_byte(p, 0);
}
}
#endif /* MODULE_PERIPH_EEPROM */
void _init_loramac(semtech_loramac_t *mac, void _init_loramac(semtech_loramac_t *mac,
LoRaMacPrimitives_t * primitives, LoRaMacCallback_t *callbacks) LoRaMacPrimitives_t * primitives, LoRaMacCallback_t *callbacks)
{ {
@ -317,6 +434,9 @@ void _init_loramac(semtech_loramac_t *mac,
semtech_loramac_set_tx_port(mac, LORAMAC_DEFAULT_TX_PORT); semtech_loramac_set_tx_port(mac, LORAMAC_DEFAULT_TX_PORT);
semtech_loramac_set_tx_mode(mac, LORAMAC_DEFAULT_TX_MODE); semtech_loramac_set_tx_mode(mac, LORAMAC_DEFAULT_TX_MODE);
mac->link_chk.available = false; mac->link_chk.available = false;
#ifdef MODULE_PERIPH_EEPROM
_read_loramac_config(mac);
#endif
} }
static void _join_otaa(semtech_loramac_t *mac) static void _join_otaa(semtech_loramac_t *mac)
@ -434,6 +554,12 @@ static void _send(semtech_loramac_t *mac, void *arg)
msg.content.value = (uint8_t)status; msg.content.value = (uint8_t)status;
msg_send(&msg, semtech_loramac_pid); msg_send(&msg, semtech_loramac_pid);
} }
#ifdef MODULE_PERIPH_EEPROM
else {
/* save the uplink counter */
_save_uplink_counter(mac);
}
#endif
} }
static void _semtech_loramac_call(semtech_loramac_func_t func, void *arg) static void _semtech_loramac_call(semtech_loramac_func_t func, void *arg)

View File

@ -444,6 +444,41 @@ void semtech_loramac_set_rx2_dr(semtech_loramac_t *mac, uint8_t dr);
*/ */
uint8_t semtech_loramac_get_rx2_dr(semtech_loramac_t *mac); uint8_t semtech_loramac_get_rx2_dr(semtech_loramac_t *mac);
#ifdef MODULE_PERIPH_EEPROM
/**
* @brief The magic number used to identify the LoRaWAN configuration
*/
#ifndef SEMTECH_LORAMAC_EEPROM_MAGIC
#define SEMTECH_LORAMAC_EEPROM_MAGIC {0x52, 0x49, 0x4F, 0x54} /* RIOT */
#endif
/**
* @brief The magic number length used to identify the LoRaWAN configuration
*/
#ifndef SEMTECH_LORAMAC_EEPROM_MAGIC_LEN
#define SEMTECH_LORAMAC_EEPROM_MAGIC_LEN 4
#endif
/**
* @brief Start position of LoRaWAN configuration stored in eeprom
*/
#ifndef SEMTECH_LORAMAC_EEPROM_START
#define SEMTECH_LORAMAC_EEPROM_START (0)
#endif
/**
* @brief Saves the current LoRaWAN configuration to the internal EEPROM
*
* @param[in] mac Pointer to the mac
*/
void semtech_loramac_save_config(semtech_loramac_t *mac);
/**
* @brief Erases any stored LoRaWAN configuration from the internal EEPROM
*/
void semtech_loramac_erase_config(void);
#endif
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -18,6 +18,8 @@ USEMODULE += shell
USEMODULE += shell_commands USEMODULE += shell_commands
USEMODULE += fmt USEMODULE += fmt
FEATURES_OPTIONAL += periph_eeprom
CFLAGS += -DREGION_$(LORA_REGION) CFLAGS += -DREGION_$(LORA_REGION)
CFLAGS += -DLORAMAC_ACTIVE_REGION=LORAMAC_REGION_$(LORA_REGION) CFLAGS += -DLORAMAC_ACTIVE_REGION=LORAMAC_REGION_$(LORA_REGION)

View File

@ -25,8 +25,9 @@ you use this one.
Once your application and device are created and registered, you'll have Once your application and device are created and registered, you'll have
several information (provided by the LoRaWAN provider): several information (provided by the LoRaWAN provider):
* The type of join procedure: ABP (Activation by personnalization) or OTAA (Over
The Air Activation) * The type of join procedure: ABP (Activation by personnalization) or OTAA (
Over The Air Activation)
* The device EUI: an 8 bytes array * The device EUI: an 8 bytes array
* The application EUI: an 8 bytes array * The application EUI: an 8 bytes array
* The application key: a 16 bytes array * The application key: a 16 bytes array
@ -48,9 +49,9 @@ board.
Depending on the type of radio device, set the `LORA_DRIVER` variable accordingly: Depending on the type of radio device, set the `LORA_DRIVER` variable accordingly:
For example: For example:
```
LORA_DRIVER=sx1272 make BOARD=nucleo-f411re -C pkg/semtech-loramac flash term LORA_DRIVER=sx1272 make BOARD=nucleo-f411re -C pkg/semtech-loramac flash term
```
will build the application for a nucleo-f411re with an SX1272 based mbed LoRa shield. will build the application for a nucleo-f411re with an SX1272 based mbed LoRa shield.
The SX1276 is the default value. The SX1276 is the default value.
@ -58,16 +59,15 @@ The SX1276 is the default value.
The other parameter that has to be set at build time is the geographic region: The other parameter that has to be set at build time is the geographic region:
`EU868`, `US915`, etc. See LoRaWAN regional parameters for more information. `EU868`, `US915`, etc. See LoRaWAN regional parameters for more information.
```
LORA_REGION=US915 LORA_DRIVER=sx1272 make BOARD=nucleo-f411re -C pkg/semtech-loramac flash term LORA_REGION=US915 LORA_DRIVER=sx1272 make BOARD=nucleo-f411re -C pkg/semtech-loramac flash term
```
will build the application for a nucleo-f411re with an SX1272 based mbed LoRa shield will build the application for a nucleo-f411re with an SX1272 based mbed LoRa shield
for US915 region. for US915 region.
The default region is `EU868`. The default region is `EU868`.
## Using the shell ## Using the shell
This application provides the `loramac` command for configuring the MAC, This application provides the `loramac` command for configuring the MAC,
joining a network and sending/receiving data to/from a LoRaWAN network. joining a network and sending/receiving data to/from a LoRaWAN network.
`join` and `tx` subcommands are blocking until the MAC is done. Class A `join` and `tx` subcommands are blocking until the MAC is done. Class A
@ -76,32 +76,32 @@ is activated by default.
### Joining with Over The Air Activation ### Joining with Over The Air Activation
* Set your device EUI, application EUI, application key: * Set your device EUI, application EUI, application key:
```
> loramac set deveui AAAAAAAAAAAAAAAA > loramac set deveui AAAAAAAAAAAAAAAA
> loramac set appeui BBBBBBBBBBBBBBBB > loramac set appeui BBBBBBBBBBBBBBBB
> loramac set appkey CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC > loramac set appkey CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
```
* Join a network using the OTAA procedure: * Join a network using the OTAA procedure:
```
> loramac join otaa > loramac join otaa
Join procedure succeeded! Join procedure succeeded!
```
### Joining with Activation By Personalization ### Joining with Activation By Personalization
OTAA is always prefered in real world scenarios. OTAA is always prefered in real world scenarios.
However, ABP can be practical for testing or workshops. However, ABP can be practical for testing or workshops.
* Set your Device Address, Network Session Key , Application Session Key: * Set your Device Address, Network Session Key , Application Session Key:
```
> loramac set devaddr AAAAAAAA > loramac set devaddr AAAAAAAA
> loramac set nwkskey BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB > loramac set nwkskey BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
> loramac set appskey CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC > loramac set appskey CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
```
* Join a network using the ABP procedure: * Join a network using the ABP procedure:
```
> loramac join abp > loramac join abp
Join procedure succeeded! Join procedure succeeded!
```
Saving frame counters in flash memory is not (yet) supported. Saving frame counters in flash memory is not (yet) supported.
Before sending data, it's necessary to clear frame counters in Before sending data, it's necessary to clear frame counters in
Network Server! Otherwise uplink messages won't work. Network Server! Otherwise uplink messages won't work.
@ -111,49 +111,61 @@ If using TTN with ABP make sure to set the correct datarate for RX2.
Otherwise confirmed and downlink messages won't work. Otherwise confirmed and downlink messages won't work.
The datarate for RX2 should be DR3 (SF9BW125) as seen in The datarate for RX2 should be DR3 (SF9BW125) as seen in
[TTN LoRaWAN Frequencies Overview](https://www.thethingsnetwork.org/docs/lorawan/frequency-plans.html): [TTN LoRaWAN Frequencies Overview](https://www.thethingsnetwork.org/docs/lorawan/frequency-plans.html):
```
> loramac set rx2_dr 3 > loramac set rx2_dr 3
```
### Sending and receiving data ### Sending and receiving data
* Send confirmable data on port 2 (cnf and port are optional): * Send confirmable data on port 2 (cnf and port are optional):
```
> loramac tx This\ is\ RIOT! cnf 2 > loramac tx This\ is\ RIOT! cnf 2
```
* Send unconfirmable data on port 10: * Send unconfirmable data on port 10:
```
> loramac tx This\ is\ RIOT! uncnf 10 > loramac tx This\ is\ RIOT! uncnf 10
```
When using Class A (default mode) downlink messages will be received in When using Class A (default mode) downlink messages will be received in
the next uplink: the next uplink:
```
> loramac tx hello > loramac tx hello
Data received: RIOT, port: 1 Data received: RIOT, port: 1
```
### Other shell commands ### Other shell commands
* Save the device LoRaWAN configuration (EUIs and keys) in EEPROM (if provided
by the microcontroller):
> loramac save
On the next device reboot, these parameters will be automatically re-read
from the EEPROM non-volatile storage and thus you can join directly the
network without entering them again from the command line.
* Remove previously stored LoRaWAN configuration:
> loramac erase
* Switch the default datarate index (from 0 to 16). 5 is for SF7, BW125: * Switch the default datarate index (from 0 to 16). 5 is for SF7, BW125:
```
> loramac set dr 5 > loramac set dr 5
```
* Switch to adaptive data rate: * Switch to adaptive data rate:
```
> loramac set adr on > loramac set adr on
```
* Perform a Link Check command (will be triggered in the next transmission): * Perform a Link Check command (will be triggered in the next transmission):
```
> loramac link_check > loramac link_check
```
The list of available commands: The list of available commands:
```
> help > help
help help
Command Description Command Description
--------------------------------------- ---------------------------------------
loramac control the loramac stack loramac control the loramac stack
reboot Reboot the node reboot Reboot the node
```
On the TTN web console, you can follow the activation and the data On the TTN web console, you can follow the activation and the data
sent/received to/from a node. sent/received to/from a node.
@ -167,27 +179,25 @@ for more information.
* Let's use [mosquitto](https://mosquitto.org/) clients. They can be installed * Let's use [mosquitto](https://mosquitto.org/) clients. They can be installed
on Ubuntu using: on Ubuntu using:
```
sudo apt install mosquitto-clients sudo apt install mosquitto-clients
```
* Subscribe to data raised by any node from any application: * Subscribe to data raised by any node from any application:
```
mosquitto_sub -h eu.thethings.network -p 1883 -u <your username> -P <your password> -t '+/devices/+/up' mosquitto_sub -h eu.thethings.network -p 1883 -u <your username> -P <your password> -t '+/devices/+/up'
```
* Publish some data to one of the node: * Publish some data to one of the node:
```
mosquitto_pub -h eu.thethings.network -p 1883 -u <your username> -P <your password> -t '<application name>/devices/<device name>/down' -m '{"port":2, "payload_raw":"VGhpcyBpcyBSSU9UIQ=="}' mosquitto_pub -h eu.thethings.network -p 1883 -u <your username> -P <your password> -t '<application name>/devices/<device name>/down' -m '{"port":2, "payload_raw":"VGhpcyBpcyBSSU9UIQ=="}'
```
After sending some data from the node, the subscribed MQTT client will display: After sending some data from the node, the subscribed MQTT client will display:
```
{"app_id":"<your application>","dev_id":"<your node>","hardware_serial":"XXXXXXXXXXXX","port":2,"counter":7,"confirmed":true,"payload_raw":"dGVzdA==","metadata": {"time":"2017-12-14T09:47:24.84548586Z","frequency":868.1,"modulation":"LORA","data_rate":"SF12BW125","coding_rate":"4/5","gateways":[{"gtw_id":"eui-xxxxxxxx","timestamp":3910359076, "time":"2017-12-14T09:47:24.85112Z","channel":0,"rssi":-10,"snr":12.2,"rf_chain":1,"latitude":48.715027,"longitude":2.2059395,"altitude":157,"location_source":"registry"}]}} {"app_id":"<your application>","dev_id":"<your node>","hardware_serial":"XXXXXXXXXXXX","port":2,"counter":7,"confirmed":true,"payload_raw":"dGVzdA==","metadata": {"time":"2017-12-14T09:47:24.84548586Z","frequency":868.1,"modulation":"LORA","data_rate":"SF12BW125","coding_rate":"4/5","gateways":[{"gtw_id":"eui-xxxxxxxx","timestamp":3910359076, "time":"2017-12-14T09:47:24.85112Z","channel":0,"rssi":-10,"snr":12.2,"rf_chain":1,"latitude":48.715027,"longitude":2.2059395,"altitude":157,"location_source":"registry"}]}}
```
The payload sent is in the `payload_raw` json field and is formated in base64 The payload sent is in the `payload_raw` json field and is formated in base64
(`dGVzdA==` in this example). (`dGVzdA==` in this example).
The node will also print the data received: The node will also print the data received:
```
> loramac tx test > loramac tx test
Data received: This is RIOT! Data received: This is RIOT!
```

View File

@ -35,7 +35,11 @@ static char print_buf[LORAMAC_APPKEY_LEN * 2 + 1];
static void _loramac_usage(void) static void _loramac_usage(void)
{ {
puts("Usage: loramac <get|set|join|tx|link_check>"); puts("Usage: loramac <get|set|join|tx|link_check"
#ifdef MODULE_PERIPH_EEPROM
"|save|erase"
#endif
">");
} }
static void _loramac_join_usage(void) static void _loramac_join_usage(void)
@ -462,6 +466,24 @@ static int _cmd_loramac(int argc, char **argv)
semtech_loramac_request_link_check(&loramac); semtech_loramac_request_link_check(&loramac);
puts("Link check request scheduled"); puts("Link check request scheduled");
} }
#ifdef MODULE_PERIPH_EEPROM
else if (strcmp(argv[1], "save") == 0) {
if (argc > 2) {
_loramac_usage();
return 1;
}
semtech_loramac_save_config(&loramac);
}
else if (strcmp(argv[1], "erase") == 0) {
if (argc > 2) {
_loramac_usage();
return 1;
}
semtech_loramac_erase_config();
}
#endif
else { else {
_loramac_usage(); _loramac_usage();
return 1; return 1;