Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

examples/lorawan: add autonomous lorawan class A device example #8789

Merged
merged 1 commit into from
Jun 21, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions examples/lorawan/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# 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 := nucleo32-f031 nucleo32-f042 nucleo32-l031

DEVEUI ?= 0000000000000000
APPEUI ?= 0000000000000000
APPKEY ?= 00000000000000000000000000000000

# 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

CFLAGS += -DREGION_$(REGION)
CFLAGS += -DDEVEUI=\"$(DEVEUI)\" -DAPPEUI=\"$(APPEUI)\" -DAPPKEY=\"$(APPKEY)\"

# 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
38 changes: 38 additions & 0 deletions examples/lorawan/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
LoRaWAN
=======

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 devices using RIOT.

This application is using the Over-The-Air Activation 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 an mbed LoRa shield: 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 OTAA activation, edit the application
`Makefile` and set your device information:

DEVEUI ?= 0000000000000000
APPEUI ?= 0000000000000000
APPKEY ?= 00000000000000000000000000000000
136 changes: 136 additions & 0 deletions examples/lorawan/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
/*
* 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 <alexandre.abadie@inria.fr>
*
* @}
*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>

#include "msg.h"
#include "thread.h"
#include "fmt.h"

#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)

#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 deveui[LORAMAC_DEVEUI_LEN];
static uint8_t appeui[LORAMAC_APPEUI_LEN];
static uint8_t appkey[LORAMAC_APPKEY_LEN];

static void rtc_cb(void *arg)
{
(void) arg;
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);
/* The send call blocks until done */
semtech_loramac_send(&loramac, (uint8_t *)message, strlen(message));
/* Wait until the send cycle has completed */
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();
}

/* 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(deveui, DEVEUI);
fmt_hex_bytes(appeui, APPEUI);
fmt_hex_bytes(appkey, APPKEY);

/* Initialize the loramac stack */
semtech_loramac_init(&loramac);
semtech_loramac_set_deveui(&loramac, deveui);
semtech_loramac_set_appeui(&loramac, appeui);
semtech_loramac_set_appkey(&loramac, appkey);

/* Use a fast datarate, e.g. BW125/SF7 in EU868 */
semtech_loramac_set_dr(&loramac, LORAMAC_DR_5);

/* Start the Over-The-Air Activation (OTAA) procedure to retrieve the
* generated device address and to get the network and application session
* keys.
*/
puts("Starting join procedure");
if (semtech_loramac_join(&loramac, LORAMAC_JOIN_OTAA) != SEMTECH_LORAMAC_JOIN_SUCCEEDED) {
puts("Join procedure failed");
return 1;
}
puts("Join procedure succeeded");

/* start the sender thread */
sender_pid = thread_create(sender_stack, sizeof(sender_stack),
SENDER_PRIO, 0, sender, NULL, "sender");

/* trigger the first send */
msg_t msg;
msg_send(&msg, sender_pid);
return 0;
}