Commit 04726fd7 authored by Guillaume Gonnet's avatar Guillaume Gonnet
Browse files

Add OTAA replay join procedure.

parent 76c8eaf2
......@@ -11,7 +11,7 @@ APPLICATION = cubsat
BOARD ?= im880b
DRIVER ?= sx1272
# Riot submodule is in `RIOT` directory.
# RIOT submodule is in `RIOT` directory.
RIOTBASE ?= $(CURDIR)/RIOT
......@@ -37,6 +37,7 @@ USEMODULE += cubsat-app
# USEMODULE += cubsat-app-benchmark
USEMODULE += cubsat-app-cmds
USEMODULE += cubsat-app-providers
# USEMODULE += cubsat-app-drivers
USEMODULE += lorariot-ctrl
USEMODULE += lorariot-adapter
USEMODULE += lorariot-region
......
#
# Main sources module.
# Main source module.
#
# Copyright (C) 2019, ENSIMAG students
# This project is under the MIT license
......@@ -25,7 +25,7 @@ export LORARIOT_DIR := $(CURDIR)/lorariot
export LORARIOT_INC := -I$(LORARIOT_DIR)
# Include this directory for getting keys.
# Include this directory for getting LoRaWAN keys.
INCLUDES += -I$(CURDIR)
......
......@@ -18,11 +18,14 @@ This project is under the MIT license
#define PANIC(msg) core_panic(PANIC_GENERAL_ERROR, msg)
// Store information given by UART.
typedef struct {
mutex_t mutex;
mutex_t mutex_gps;
mutex_t mutex_cmd;
bool is_parsing;
uint8_t line_length;
char line[127];
} gps_isr_info_t;
char line[128];
} uart_isr_info_t;
extern gps_isr_info_t gps_isr_info;
// Unique instance of UART info structure.
extern uart_isr_info_t uart_isr_info;
#
# Cubsat driver module.
#
# Copyright (C) 2019, ENSIMAG students
# This project is under the MIT license
MODULE := cubsat-app-drivers
include $(RIOTBASE)/Makefile.base
......@@ -10,6 +10,8 @@ This project is under the MIT license
#include "providers.h"
#include "app.h"
#include <debug.h>
// Configure LoRaMAC driver with provider information.
void pvd_otaa_enable(provider_t *pvd)
......@@ -40,15 +42,22 @@ void pvd_otaa_reset(provider_t *pvd)
// If join failed, we can't continue running the application because all
// messages will be lost.
if (loraraiot_otaa(&otaa_req) != LORARIOT_JOIN_SUCCEEDED)
PANIC("Can't join Orange network.");
if (loraraiot_otaa(&otaa_req) != LORARIOT_SUCCESS) {
DEBUG("[otaa] join error for devui [%2x ..]", *otaa->deveui);
PANIC("Can't join network using OTAA");
}
uint8_t *data = loraraiot_retrieve_otaa();
// TODO: save join response.
(void)data;
// Resend the join message to port 6.
lorariot_mcps_t mcps = LORARIOT_CONFIRMED(DR_0);
// TODO: fill msg with join data.
lorariot_send(&mcps);
}
......@@ -19,22 +19,24 @@ This project is under the MIT license
#define STD_BAUDRATE 9600
//
// Unique instance of UART info structure.
uart_isr_info_t uart_isr_info;
// Handle
static void gps_isr(gps_isr_info_t *info, char c)
// Handle interruption from UART.
static void uart_isr(uart_isr_info_t *info, char c)
{
if (info->is_parsing)
return; // Ignore new GPS data while parsing an old one.
return; // Ignore new data while parsing an old one.
if ((c == '$') || (info->line_length >= 127))
if ((c == '$') || (c == '~') || (info->line_length >= 127))
info->line_length = 0;
info->line[info->line_length++] = c;
if (c == '\n') {
if (c == '\n' && (*info->line == '$' || *info->line == '~')) {
info->line[info->line_length++] = '\0';
mutex_unlock(&info->mutex);
info->is_parsing = true;
mutex_unlock((*info->line == '$') ? &info->mutex_gps : &info->mutex_cmd);
}
}
......@@ -57,5 +59,5 @@ ssize_t stdio_write(const void *buffer, size_t len)
// Initialize STDIO module.
void stdio_init(void)
{
uart_init(STD_DEV, STD_BAUDRATE, (uart_rx_cb_t)gps_isr, &gps_isr_info);
uart_init(STD_DEV, STD_BAUDRATE, (uart_rx_cb_t)uart_isr, &uart_isr_info);
}
/*!
* \file LoRaMac-extra.h
*
* \brief LoRa MAC layer implementation
*
* \copyright Revised BSD License, see section \ref LICENSE.
*
* \code
* ______ _
* / _____) _ | |
* ( (____ _____ ____ _| |_ _____ ____| |__
* \____ \| ___ | (_ _) ___ |/ ___) _ \
* _____) ) ____| | | || |_| ____( (___| | | |
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
* (C)2013-2017 Semtech
*
* ___ _____ _ ___ _ _____ ___ ___ ___ ___
* / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
* \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
* |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
* embedded.connectivity.solutions===============
*
* \endcode
*
* \author Miguel Luis ( Semtech )
*
* \author Gregory Cristian ( Semtech )
*
* \author Daniel Jaeckle ( STACKFORCE )
*/
#ifndef __LORAMAC_EXTRA_H__
#define __LORAMAC_EXTRA_H__
#include "LoRaMac.h"
#include "LoRaMac-extra.h"
#include "LoRaMacCrypto.h"
/*!
* \brief Apply join response to current LoRaMac parameters.
*
* \param [IN] data - Join response data.
* \param [IN] size - Size of join data response.
*/
void LoRaMacApplyJoin(uint8_t *data, uint8_t size)
{
LoRaMacJoinComputeSKeys(LoRaMacAppKey, data, LoRaMacDevNonce, LoRaMacNwkSKey, LoRaMacAppSKey);
// Network identifier (NetID).
LoRaMacNetID = ((uint32_t)data[3] << 0);
LoRaMacNetID |= ((uint32_t)data[4] << 8);
LoRaMacNetID |= ((uint32_t)data[5] << 16);
// End-device address (DevAddr).
LoRaMacDevAddr = ((uint32_t)data[6] << 0);
LoRaMacDevAddr |= ((uint32_t)data[7] << 8);
LoRaMacDevAddr |= ((uint32_t)data[8] << 16);
LoRaMacDevAddr |= ((uint32_t)data[9] << 24);
// Downlink settings (DLSettings).
LoRaMacParams.Rx1DrOffset = (data[10] >> 4) & 0x07;
LoRaMacParams.Rx2Channel.Datarate = (data[10] >> 0) & 0x0F;
// Reception delays.
LoRaMacParams.ReceiveDelay1 = (data[11] & 0x0F);
if (LoRaMacParams.ReceiveDelay1 == 0)
LoRaMacParams.ReceiveDelay1 = 1;
LoRaMacParams.ReceiveDelay1 *= 1000;
LoRaMacParams.ReceiveDelay2 = LoRaMacParams.ReceiveDelay1 + 1000;
// Apply CF list.
ApplyCFListParams_t applyCFList;
applyCFList.Payload = &data[12];
applyCFList.Size = size - 12; // Size of the regular payload is 12.
RegionApplyCFList(LoRaMacRegion, &applyCFList);
IsLoRaMacNetworkJoined = true;
}
#endif // __LORAMAC_EXTRA_H__
\ No newline at end of file
/*!
* \file LoRaMac-extra.h
*
* \brief LoRa MAC layer implementation
*
* \copyright Revised BSD License, see section \ref LICENSE.
*
* \code
* ______ _
* / _____) _ | |
* ( (____ _____ ____ _| |_ _____ ____| |__
* \____ \| ___ | (_ _) ___ |/ ___) _ \
* _____) ) ____| | | || |_| ____( (___| | | |
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
* (C)2013-2017 Semtech
*
* ___ _____ _ ___ _ _____ ___ ___ ___ ___
* / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
* \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
* |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
* embedded.connectivity.solutions===============
*
* \endcode
*
* \author Miguel Luis ( Semtech )
*
* \author Gregory Cristian ( Semtech )
*
* \author Daniel Jaeckle ( STACKFORCE )
*/
#ifndef __LORAMAC_INT_H__
#define __LORAMAC_INT_H__
#include "LoRaMac.h"
/*!
* Maximum PHY layer payload size
*/
#define LORAMAC_PHY_MAXPAYLOAD 255
/*!
* Buffer containing the upper layer data.
*/
extern uint8_t LoRaMacRxPayload[LORAMAC_PHY_MAXPAYLOAD];
/*!
* LoRaMac region.
*/
extern LoRaMacRegion_t LoRaMacRegion;
/*!
* Indicates if the MAC layer has already joined a network.
*/
extern bool IsLoRaMacNetworkJoined;
/*!
* Device nonce is a random value extracted by issuing a sequence of RSSI
* measurements.
*/
extern uint16_t LoRaMacDevNonce;
/*!
* Network ID (3 bytes).
*/
extern uint32_t LoRaMacNetID;
/*!
* Mote Address.
*/
extern uint32_t LoRaMacDevAddr;
/*!
* LoRaMac parameters.
*/
extern LoRaMacParams_t LoRaMacParams;
/*!
* AES encryption/decryption cipher network session key.
*/
extern uint8_t LoRaMacNwkSKey[16];
/*!
* AES encryption/decryption cipher application session key.
*/
extern uint8_t LoRaMacAppSKey[16];
/*!
* AES encryption/decryption cipher application key.
*/
extern uint8_t *LoRaMacAppKey;
/*!
* \brief Apply join response to current LoRaMac parameters.
*
* \param [IN] data - Join response data.
* \param [IN] size - Size of join data response.
*/
void LoRaMacApplyJoin(uint8_t *data, uint8_t size);
#endif // __LORAMAC_INT_H__
\ No newline at end of file
......@@ -30,15 +30,11 @@
*/
#include "utilities.h"
#include "LoRaMac.h"
#include "LoRaMac-extra.h"
#include "LoRaMacCrypto.h"
#include "LoRaMacTest.h"
#include "radio.h"
/*!
* Maximum PHY layer payload size
*/
#define LORAMAC_PHY_MAXPAYLOAD 255
/*!
* Maximum MAC commands buffer size
*/
......@@ -52,7 +48,7 @@
/*!
* LoRaMac region.
*/
static LoRaMacRegion_t LoRaMacRegion;
LoRaMacRegion_t LoRaMacRegion;
/*!
* LoRaMac duty cycle for the back-off procedure during the first hour.
......@@ -82,12 +78,12 @@ static uint8_t *LoRaMacAppEui;
/*!
* AES encryption/decryption cipher application key
*/
static uint8_t *LoRaMacAppKey;
uint8_t *LoRaMacAppKey;
/*!
* AES encryption/decryption cipher network session key
*/
static uint8_t LoRaMacNwkSKey[] =
uint8_t LoRaMacNwkSKey[16] =
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
......@@ -96,7 +92,7 @@ static uint8_t LoRaMacNwkSKey[] =
/*!
* AES encryption/decryption cipher application session key
*/
static uint8_t LoRaMacAppSKey[] =
uint8_t LoRaMacAppSKey[16] =
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
......@@ -106,17 +102,17 @@ static uint8_t LoRaMacAppSKey[] =
* Device nonce is a random value extracted by issuing a sequence of RSSI
* measurements
*/
static uint16_t LoRaMacDevNonce;
uint16_t LoRaMacDevNonce;
/*!
* Network ID ( 3 bytes )
*/
static uint32_t LoRaMacNetID;
uint32_t LoRaMacNetID;
/*!
* Mote Address
*/
static uint32_t LoRaMacDevAddr;
uint32_t LoRaMacDevAddr;
/*!
* Multicast channels linked list
......@@ -156,7 +152,7 @@ static uint8_t LoRaMacTxPayloadLen = 0;
/*!
* Buffer containing the upper layer data.
*/
static uint8_t LoRaMacRxPayload[LORAMAC_PHY_MAXPAYLOAD];
uint8_t LoRaMacRxPayload[LORAMAC_PHY_MAXPAYLOAD];
/*!
* LoRaMAC frame counter. Each time a packet is sent the counter is incremented.
......@@ -184,7 +180,7 @@ static bool IsRxWindowsEnabled = true;
/*!
* Indicates if the MAC layer has already joined a network.
*/
static bool IsLoRaMacNetworkJoined = false;
bool IsLoRaMacNetworkJoined = false;
/*!
* LoRaMac ADR control status
......@@ -735,7 +731,6 @@ static void OnRadioRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t
{
LoRaMacHeader_t macHdr;
LoRaMacFrameCtrl_t fCtrl;
ApplyCFListParams_t applyCFList;
GetPhyParams_t getPhy;
PhyParam_t phyParam;
......@@ -801,39 +796,12 @@ static void OnRadioRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t
if( micRx == mic )
{
LoRaMacJoinComputeSKeys( LoRaMacAppKey, LoRaMacRxPayload + 1, LoRaMacDevNonce, LoRaMacNwkSKey, LoRaMacAppSKey );
LoRaMacNetID = ( uint32_t )LoRaMacRxPayload[4];
LoRaMacNetID |= ( ( uint32_t )LoRaMacRxPayload[5] << 8 );
LoRaMacNetID |= ( ( uint32_t )LoRaMacRxPayload[6] << 16 );
LoRaMacDevAddr = ( uint32_t )LoRaMacRxPayload[7];
LoRaMacDevAddr |= ( ( uint32_t )LoRaMacRxPayload[8] << 8 );
LoRaMacDevAddr |= ( ( uint32_t )LoRaMacRxPayload[9] << 16 );
LoRaMacDevAddr |= ( ( uint32_t )LoRaMacRxPayload[10] << 24 );
// DLSettings
LoRaMacParams.Rx1DrOffset = ( LoRaMacRxPayload[11] >> 4 ) & 0x07;
LoRaMacParams.Rx2Channel.Datarate = LoRaMacRxPayload[11] & 0x0F;
// RxDelay
LoRaMacParams.ReceiveDelay1 = ( LoRaMacRxPayload[12] & 0x0F );
if( LoRaMacParams.ReceiveDelay1 == 0 )
{
LoRaMacParams.ReceiveDelay1 = 1;
}
LoRaMacParams.ReceiveDelay1 *= 1000;
LoRaMacParams.ReceiveDelay2 = LoRaMacParams.ReceiveDelay1 + 1000;
// Apply CF list
applyCFList.Payload = &LoRaMacRxPayload[13];
// Size of the regular payload is 12. Plus 1 byte MHDR and 4 bytes MIC
applyCFList.Size = size - 17;
RegionApplyCFList( LoRaMacRegion, &applyCFList );
// Remove from size 1 byte MHDR and 4 bytes MIC.
size = size - 5;
LoRaMacRxPayload[0] = size;
LoRaMacApplyJoin(LoRaMacRxPayload + 1, size);
MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK;
IsLoRaMacNetworkJoined = true;
}
else
{
......
......@@ -8,6 +8,7 @@ LGPLv2.1 license.
*/
#include "controller.h"
#include "LoRaMac-extra.h"
// Make OTAA join request in LoRaRIOT thread.
......@@ -25,12 +26,12 @@ static void _otaa(lorariot_otaa_t *otaa)
mlmeReq.Req.Join.AppKey = otaa->appkey;
mlmeReq.Req.Join.Datarate = otaa->dr;
uint8_t ret = LoRaMacMlmeRequest(&mlmeReq);
uint8_t status = LoRaMacMlmeRequest(&mlmeReq);
msg_t msg;
msg.type = MSG_TYPE_LORAMAC_JOIN;
msg.content.value = SEMTECH_LORAMAC_BUSY;
msg_send(&msg, semtech_loramac_pid);
msg.type = LORARIOT_TYPE_LORAMAC_JOIN;
msg.content.value = status;
msg_send(&msg, lorariot.caller_pid);
}
......@@ -38,7 +39,6 @@ static void _otaa(lorariot_otaa_t *otaa)
int loraraiot_otaa(lorariot_otaa_t *otaa)
{
// Call `LoRaMacMlmeRequest` in event loop thread.
lorariot.caller_pid = thread_getpid();
lorariot_call((lorariot_func_t)_otaa, otaa);
// Wait for join status from LoRaMAC-node.
......@@ -46,3 +46,24 @@ int loraraiot_otaa(lorariot_otaa_t *otaa)
msg_receive(&msg);
return (uint8_t)msg.content.value;
}
// Retrieve OTAA join data.
uint8_t *loraraiot_retrieve_otaa(void)
{
LoRaMacRxPayload[29] = (LoRaMacDevNonce >> 0) & 0xFF;
LoRaMacRxPayload[30] = (LoRaMacDevNonce >> 8) & 0xFF;
return LoRaMacRxPayload;
}
// Replay OTAA with previous join data.
void lorariot_replay_otaa(uint8_t *data)
{
uint8_t size = data[0];
LoRaMacDevNonce = (data[30] << 8) | (data[29]);
LoRaMacApplyJoin(data + 1, size);
}
......@@ -85,12 +85,6 @@ void *lorariot_event_loop(void *arg)
msg_reply(&msg, &msg_resp);
} break;
case LORARIOT_TYPE_LORAMAC_JOIN: {
msg_t msg_ret;
msg_ret.content.value = msg.content.value;
msg_send(&msg_ret, lorariot.caller_pid);
} break;
case LORARIOT_TYPE_LORAMAC_LINK_CHECK: {
// MlmeConfirm_t *confirm = (MlmeConfirm_t *)msg.content.ptr;
// mac->link_chk.demod_margin = confirm->DemodMargin;
......@@ -123,6 +117,7 @@ void lorariot_call(lorariot_func_t func, void *arg)
{
msg_t msg, msg_resp;
lorariot_call_t call = { func, arg };
lorariot.caller_pid = thread_getpid();
msg.type = LORARIOT_TYPE_CALL;
msg.content.ptr = &call;
......
......@@ -40,15 +40,6 @@ extern LoRaMacPrimitives_t lorariot_primitives;
extern LoRaMacCallback_t lorariot_callbacks;
// Store data of LoRaRIOT controller.
typedef struct {
uint8_t caller_pid;
} lorariot_ctrl_t;
// Unique instance of `lorariot_ctrl_t`.
extern lorariot_ctrl_t lorariot;
// Handle a NetDev event.
void lorariot_event_cb(netdev_t *dev, netdev_event_t event);
......
......@@ -31,28 +31,17 @@ void lorariot_mcps_confirm(McpsConfirm_t *confirm)
// Handle a MLME confirm notification.
void lorariot_mlme_confirm(MlmeConfirm_t *confirm)
{
DEBUG("[semtech-loramac] MLME confirm event\n");
DEBUG("[lorariot] MLME confirm event: %d\n", confirm->MlmeRequest);
switch (confirm->MlmeRequest) {
case MLME_JOIN:
if (confirm->Status == LORAMAC_EVENT_INFO_STATUS_OK) {
// Status is OK, node has joined the network.
DEBUG("[semtech-loramac] join succeeded\n");
msg_t msg;
msg.type = LORARIOT_TYPE_LORAMAC_JOIN;
msg.content.value = LORARIOT_JOIN_SUCCEEDED;
msg_send(&msg, lorariot_pid);
}
else {
DEBUG("[semtech-loramac] join not successful\n");
// Join was not successful.
msg_t msg;
msg.type = LORARIOT_TYPE_LORAMAC_JOIN;
msg.content.value = LORARIOT_JOIN_FAILED;
msg_send(&msg, lorariot_pid);
}
break;
case MLME_LINK_CHECK:
case MLME_JOIN: {
DEBUG("[lorariot] join response: %d\n", confirm->Status);
msg_t msg;
msg.type = LORARIOT_TYPE_LORAMAC_JOIN;
msg.content.value = confirm->Status;
msg_send(&msg, lorariot.caller_pid);
} break;
case MLME_LINK_CHECK: {
if (confirm->Status == LORAMAC_EVENT_INFO_STATUS_OK) {
DEBUG("[semtech-loramac] link check received\n");
msg_t msg;
......@@ -60,6 +49,7 @@ void lorariot_mlme_confirm(MlmeConfirm_t *confirm)
msg.content.ptr = confirm;
msg_send(&msg, lorariot_pid);
}
} break;
default:
break;
......@@ -108,7 +98,6 @@ static void _send_mcps(lorariot_mcps_t *mcps)
void lorariot_send(lorariot_mcps_t *mcps)
{
// Call `LoRaMacMcpsRequest` in event loop thread.
lorariot.caller_pid = thread_getpid();
lorariot_call((lorariot_func_t)_send_mcps, mcps);
// Wait for TX status information from LoRaMAC-node.
......
/*
Manage message sending.
LoRaRIOT module: interface between RIOT and LoRaMAC-node.
This file is based on "semtech-loramac" module from RIOT OS, under the
LGPLv2.1 license.
......@@ -10,6 +10,7 @@ LGPLv2.1 license.
#pragma once
#include <stdint.h>
#include <stdbool.h>