diff --git a/examples/lorawan_abp/Makefile b/examples/lorawan_abp/Makefile new file mode 100644 index 000000000000..624c06172c25 --- /dev/null +++ b/examples/lorawan_abp/Makefile @@ -0,0 +1,45 @@ +# name of your application +APPLICATION = lorawan + +# Use the ST B-L072Z-LRWAN1 board by default: +BOARD ?= b-l072z-lrwan1 + +# This has to be the absolute path to the RIOT base directory: +RIOTBASE ?= $(CURDIR)/../.. + +BOARD_INSUFFICIENT_MEMORY := nucleo-f031k6 nucleo-f042k6 nucleo-l031k6 + +DEVADDR ?= 00000000 +NWKSKEY ?= 00000000000000000000000000000000 +APPSKEY ?= 00000000000000000000000000000000 +RX2_FREQ ?= 869525000 +RX2_DR ?= 3 + +# Default radio driver is Semtech SX1276 (used by the B-L072Z-LRWAN1 board) +DRIVER ?= sx1276 + +# Default region is Europe and default band is 868MHz +REGION ?= EU868 + +# Include the Semtech-loramac package +USEPKG += semtech-loramac + +USEMODULE += $(DRIVER) +USEMODULE += fmt +FEATURES_REQUIRED += periph_rtc +FEATURES_REQUIRED += periph_eeprom + +CFLAGS += -DREGION_$(REGION) +CFLAGS += -DDEVADDR=\"$(DEVADDR)\" -DNWKSKEY=\"$(NWKSKEY)\" -DAPPSKEY=\"$(APPSKEY)\" +CFLAGS += -DRX2_FREQ=$(RX2_FREQ) -DRX2_DR=$(RX2_DR) +CFLAGS += -DLORAMAC_ACTIVE_REGION=LORAMAC_REGION_$(REGION) + +# Comment this out to disable code in RIOT that does safety checking +# which is not needed in a production environment but helps in the +# development process: +DEVELHELP ?= 1 + +# Change this to 0 show compiler invocation lines by default: +QUIET ?= 1 + +include $(RIOTBASE)/Makefile.include diff --git a/examples/lorawan_abp/README.md b/examples/lorawan_abp/README.md new file mode 100644 index 000000000000..13ca69c87274 --- /dev/null +++ b/examples/lorawan_abp/README.md @@ -0,0 +1,38 @@ +LoRaWAN - ABP +============= + +Description +----------- + +This application shows a simple use case of LoRaWAN with RIOT. + +By using the real time clock and low-power capabilities of a board, this +application shows how to program a LoRaWAN Class A device using RIOT. + +This application is using the Activation-By-Personalization (ABP) procedure. + +Usage +----- + +Simply build and flash the application for a ST B-L072Z-LRWAN1 board: + + make flash term + +Use the `BOARD`, `DRIVER` and `REGION` make variables to adapt the application +to your hardware setup and region of use: + +- `BOARD` can be one of the nucleo-64 boards +- `DRIVER` can be either `sx1276` or `sx1272` +- `REGION` can be `EU868`, `US915`, etc (see LoRaWAN regional parameters for + details). + +ST Nucleo-64 can be used with mbed LoRa shields: there's one based on +[the sx1276 radio](https://os.mbed.com/components/SX1276MB1xAS/) and one based +on the [the sx1272 radio](https://os.mbed.com/components/SX1272MB2xAS/). + +Finally, to join a LoRaWAN network using ABP activation, edit the application +`Makefile` and set your device and LoRaWAN application information: + + DEVADDR ?= 00000000 + NWKSKEY ?= 00000000000000000000000000000000 + APPSKEY ?= 00000000000000000000000000000000 diff --git a/examples/lorawan_abp/main.c b/examples/lorawan_abp/main.c new file mode 100644 index 000000000000..0254e1a436fb --- /dev/null +++ b/examples/lorawan_abp/main.c @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2018 Inria + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup examples + * @{ + * + * @file + * @brief Example demonstrating the use of LoRaWAN with RIOT + * + * @author Alexandre Abadie + * + * @} + */ + +#include +#include +#include +#include + +#include "msg.h" +#include "thread.h" +#include "fmt.h" +#ifdef MODULE_PM_LAYERED +#include "pm_layered.h" +#endif + +#include "periph/rtc.h" + +#include "net/loramac.h" +#include "semtech_loramac.h" + +/* Messages are sent every 20s to respect the duty cycle on each channel */ +#define PERIOD (20U) + +/* Low-power mode lock level */ +#define PM_LOCK_LEVEL (1) + +#define SENDER_PRIO (THREAD_PRIORITY_MAIN - 1) +static kernel_pid_t sender_pid; +static char sender_stack[THREAD_STACKSIZE_MAIN / 2]; + +semtech_loramac_t loramac; + +static const char *message = "This is RIOT!"; + +static uint8_t devaddr[LORAMAC_DEVADDR_LEN]; +static uint8_t nwkskey[LORAMAC_NWKSKEY_LEN]; +static uint8_t appskey[LORAMAC_APPSKEY_LEN]; + +static void rtc_cb(void *arg) +{ + (void) arg; + +#ifdef MODULE_PM_LAYERED + /* block sleep level mode until the next sending cycle has completed */ + pm_block(PM_LOCK_LEVEL); +#endif + + msg_t msg; + msg_send(&msg, sender_pid); +} + +static void _prepare_next_alarm(void) +{ + struct tm time; + rtc_get_time(&time); + /* set initial alarm */ + time.tm_sec += PERIOD; + mktime(&time); + rtc_set_alarm(&time, rtc_cb, NULL); +} + +static void _send_message(void) +{ + printf("Sending: %s\n", message); + /* Try to send a message */ + uint8_t ret = semtech_loramac_send(&loramac, + (uint8_t *)message, strlen(message)); + if (ret != SEMTECH_LORAMAC_TX_OK) { + printf("Cannot send message '%s', ret code: %d\n", message, ret); + return; + } + /* The send was successfully scheduled, now wait until the send cycle has + completed and a reply is received from the MAC */ + semtech_loramac_recv(&loramac); +} + +static void *sender(void *arg) +{ + (void)arg; + + msg_t msg; + msg_t msg_queue[8]; + msg_init_queue(msg_queue, 8); + + while (1) { + msg_receive(&msg); + + /* Trigger the message send */ + _send_message(); + + /* Schedule the next wake-up alarm */ + _prepare_next_alarm(); + +#ifdef MODULE_PM_LAYERED + /* go back to sleep */ + pm_unblock(PM_LOCK_LEVEL); +#endif + } + + /* this should never be reached */ + return NULL; +} + +int main(void) +{ + puts("LoRaWAN Class A low-power application"); + puts("====================================="); + + /* Convert identifiers and application key */ + fmt_hex_bytes(devaddr, DEVADDR); + fmt_hex_bytes(nwkskey, NWKSKEY); + fmt_hex_bytes(appskey, APPSKEY); + + /* Initialize the loramac stack */ + semtech_loramac_init(&loramac); + semtech_loramac_set_devaddr(&loramac, devaddr); + semtech_loramac_set_nwkskey(&loramac, nwkskey); + semtech_loramac_set_appskey(&loramac, appskey); + + /* Configure RX2 parameters */ + semtech_loramac_set_rx2_freq(&loramac, RX2_FREQ); + semtech_loramac_set_rx2_dr(&loramac, RX2_DR); + + /* Store ABP parameters to EEPROM */ + semtech_loramac_save_config(&loramac); + + /* Use a fast datarate, e.g. BW125/SF7 in EU868 */ + semtech_loramac_set_dr(&loramac, LORAMAC_DR_5); + + /* ABP join procedure always succeeds */ + semtech_loramac_join(&loramac, LORAMAC_JOIN_ABP); + + /* start the sender thread */ + sender_pid = thread_create(sender_stack, sizeof(sender_stack), + SENDER_PRIO, 0, sender, NULL, "sender"); + + /* unlock the lowest possible low-power mode */ + pm_unblock(0); + + /* trigger the first send */ + msg_t msg; + msg_send(&msg, sender_pid); + return 0; +}