fix lorawan class A demo for RHF76_052DM board

LoRaMac-node-4.4.4 demo
This commit is contained in:
supowang
2020-06-02 16:06:58 +08:00
parent 5b51d50ade
commit 595cd6f0d2
30 changed files with 6918 additions and 933 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -403,14 +403,9 @@
<FilePath>..\apps\common\NvmCtxMgmt.c</FilePath> <FilePath>..\apps\common\NvmCtxMgmt.c</FilePath>
</File> </File>
<File> <File>
<FileName>LoRaApi.c</FileName> <FileName>LoRaDemo.c</FileName>
<FileType>1</FileType> <FileType>1</FileType>
<FilePath>..\apps\classA\LoRaApi.c</FilePath> <FilePath>..\apps\classA\LoRaDemo.c</FilePath>
</File>
<File>
<FileName>at_parser.c</FileName>
<FileType>1</FileType>
<FilePath>..\apps\classA\at_parser.c</FilePath>
</File> </File>
</Files> </Files>
</Group> </Group>
@@ -722,11 +717,6 @@
<FileType>1</FileType> <FileType>1</FileType>
<FilePath>..\Src\sysIrqHandlers.c</FilePath> <FilePath>..\Src\sysIrqHandlers.c</FilePath>
</File> </File>
<File>
<FileName>atcmd-board.c</FileName>
<FileType>1</FileType>
<FilePath>..\Src\atcmd-board.c</FilePath>
</File>
</Files> </Files>
</Group> </Group>
<Group> <Group>

View File

@@ -0,0 +1,63 @@
/*!
* \file Commissioning.h
*
* \brief End-device commissioning parameters
*
* \copyright Revised BSD License, see section \ref LICENSE.
*
* \code
* ______ _
* / _____) _ | |
* ( (____ _____ ____ _| |_ _____ ____| |__
* \____ \| ___ | (_ _) ___ |/ ___) _ \
* _____) ) ____| | | || |_| ____( (___| | | |
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
* (C)2013-2020 Semtech
*
* \endcode
*/
#ifndef __COMMISSIONING_H__
#define __COMMISSIONING_H__
/*!
******************************************************************************
********************************** WARNING ***********************************
******************************************************************************
The LoRaWAN AES128 keys are stored and provisionned on secure-elements.
This project providdes a software emulated secure-element.
The LoRaWAN AES128 keys SHALL be updated under
src/peripherals/<secure-element name>-se\se-identity.h file.
******************************************************************************
******************************************************************************
******************************************************************************
*/
#include "se-identity.h"
/*!
* When set to 1 the application uses the Over-the-Air activation procedure
* When set to 0 the application uses the Personalization activation procedure
*/
#define OVER_THE_AIR_ACTIVATION 1
/*!
* When using ABP activation the MAC layer must know in advance to which server
* version it will be connected.
*/
#define ABP_ACTIVATION_LRWAN_VERSION_V10x 0x01000300 // 1.0.3.0
#define ABP_ACTIVATION_LRWAN_VERSION ABP_ACTIVATION_LRWAN_VERSION_V10x
/*!
* Indicates if the end-device is to be connected to a private or public network
*/
#define LORAWAN_PUBLIC_NETWORK true
/*!
* Current network ID
*/
#define LORAWAN_NETWORK_ID ( uint32_t )0
#endif // __COMMISSIONING_H__

View File

@@ -1,430 +0,0 @@
#include "LoRaApi.h"
#if( OVER_THE_AIR_ACTIVATION == 0 )
uint8_t DevEui[] = { 0x38, 0x37, 0x37, 0x37, 0x71, 0x37, 0x68, 0x07 };
uint8_t JoinEui[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
uint8_t AppKey[] = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C };
uint8_t NwkKey[] = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C };
uint32_t DevAddr = 0x008B6CCB;
uint8_t FNwkSIntKey[] = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C };
uint8_t SNwkSIntKey[] = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C };
uint8_t NwkSEncKey[] = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C };
uint8_t AppSKey[] = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C };
#else
uint8_t DevEui[] = { 0x47, 0x9B, 0x41, 0xF2, 0x00, 0x45, 0x00, 0x28 };
uint8_t JoinEui[] = { 0x52, 0x69, 0x73, 0x69, 0x6E, 0x67, 0x48, 0x46 };
uint8_t AppKey[] = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C };
uint8_t NwkKey[] = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C };
uint32_t DevAddr = 0x00ADE921;
uint8_t FNwkSIntKey[] = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C };
uint8_t SNwkSIntKey[] = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C };
uint8_t NwkSEncKey[] = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C };
uint8_t AppSKey[] = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C };
#endif
bool NextTx = true;
uint8_t IsTxConfirmed = false;
TimerEvent_t TxNextPacketTimer;
uint8_t AppPort = 2;
uint8_t AppDataSize = 13;
uint8_t AppDataBuffer[LORAWAN_APP_DATA_MAX_SIZE];
LoRaMacPrimitives_t LoRaMacPrimitives;
LoRaMacCallback_t LoRaMacCallbacks;
MibRequestConfirm_t mibReq;
LoRaMacStatus_t status;
LoRaMacStatus_t SendFrame( void )
{
McpsReq_t mcpsReq;
LoRaMacTxInfo_t txInfo;
if( LoRaMacQueryTxPossible( AppDataSize, &txInfo ) != LORAMAC_STATUS_OK )
{
// Send empty frame in order to flush MAC commands
mcpsReq.Type = MCPS_UNCONFIRMED;
mcpsReq.Req.Unconfirmed.fBuffer = NULL;
mcpsReq.Req.Unconfirmed.fBufferSize = 0;
mcpsReq.Req.Unconfirmed.Datarate = LORAWAN_DEFAULT_DATARATE;
}
else
{
if( IsTxConfirmed == false )
{
mcpsReq.Type = MCPS_UNCONFIRMED;
mcpsReq.Req.Unconfirmed.fPort = AppPort;
mcpsReq.Req.Unconfirmed.fBuffer = AppDataBuffer;
mcpsReq.Req.Unconfirmed.fBufferSize = AppDataSize;
mcpsReq.Req.Unconfirmed.Datarate = LORAWAN_DEFAULT_DATARATE;
}
else
{
mcpsReq.Type = MCPS_CONFIRMED;
mcpsReq.Req.Confirmed.fPort = AppPort;
mcpsReq.Req.Confirmed.fBuffer = AppDataBuffer;
mcpsReq.Req.Confirmed.fBufferSize = AppDataSize;
mcpsReq.Req.Confirmed.NbTrials = 8;
mcpsReq.Req.Confirmed.Datarate = LORAWAN_DEFAULT_DATARATE;
}
}
/*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
return LoRaMacMcpsRequest( &mcpsReq);
}
static void McpsConfirm( McpsConfirm_t *mcpsConfirm )
{
if( mcpsConfirm->Status == LORAMAC_EVENT_INFO_STATUS_OK )
{
switch( mcpsConfirm->McpsRequest )
{
case MCPS_UNCONFIRMED:
{
break;
}
case MCPS_CONFIRMED:
{
break;
}
case MCPS_PROPRIETARY:
{
break;
}
default:
break;
}
}
}
static void OnTxNextPacketTimerEvent( void* context)
{
MibRequestConfirm_t mibReq;
LoRaMacStatus_t status;
TimerStop( &TxNextPacketTimer );
mibReq.Type = MIB_NETWORK_ACTIVATION;
status = LoRaMacMibGetRequestConfirm( &mibReq );
if( status == LORAMAC_STATUS_OK )
{
if( mibReq.Param.NetworkActivation == ACTIVATION_TYPE_NONE )
{
// Network not joined yet. Try to join again
LoRa_JoinNetwork(1);
}
else
{
NextTx = true;
}
}
NextTx = true;
}
static void McpsIndication( McpsIndication_t *mcpsIndication )
{
if( mcpsIndication->Status != LORAMAC_EVENT_INFO_STATUS_OK )
{
return;
}
switch( mcpsIndication->McpsIndication )
{
case MCPS_UNCONFIRMED:
{
break;
}
case MCPS_CONFIRMED:
{
break;
}
case MCPS_PROPRIETARY:
{
break;
}
case MCPS_MULTICAST:
{
break;
}
default:
break;
}
if( mcpsIndication->FramePending == true )
{
// The server signals that it has pending data to be sent.
// We schedule an uplink as soon as possible to flush the server.
OnTxNextPacketTimerEvent( NULL );
}
if( mcpsIndication->RxData == true )
{
}
}
static void MlmeConfirm( MlmeConfirm_t *mlmeConfirm )
{
switch( mlmeConfirm->MlmeRequest )
{
case MLME_JOIN:
{
if( mlmeConfirm->Status == LORAMAC_EVENT_INFO_STATUS_OK )
{
MibRequestConfirm_t mibGet;
printf( "###### ===== JOINED ==== ######\r\n" );
printf( "\r\nOTAA\r\n\r\n" );
mibGet.Type = MIB_DEV_ADDR;
LoRaMacMibGetRequestConfirm( &mibGet );
printf( "DevAddr : %08X\r\n", mibGet.Param.DevAddr );
printf( "\n\r\n" );
mibGet.Type = MIB_CHANNELS_DATARATE;
LoRaMacMibGetRequestConfirm( &mibGet );
printf( "DATA RATE : DR_%d\r\n", mibGet.Param.ChannelsDatarate );
printf( "\r\n" );
// Status is OK, node has joined the network
NextTx = true;
}
else
{
// Join was not successful. Try to join again
LoRa_JoinNetwork(1);
}
break;
}
case MLME_LINK_CHECK:
{
break;
}
default:
break;
}
}
/*!
* \brief MLME-Indication event function
*
* \param [IN] mlmeIndication - Pointer to the indication structure.
*/
static void MlmeIndication( MlmeIndication_t *mlmeIndication )
{
if( mlmeIndication->Status != LORAMAC_EVENT_INFO_STATUS_BEACON_LOCKED )
{
printf( "\r\n###### ===== MLME-Indication ==== ######\r\n" );
}
if( mlmeIndication->Status != LORAMAC_EVENT_INFO_STATUS_OK )
{
}
switch( mlmeIndication->MlmeIndication )
{
case MLME_SCHEDULE_UPLINK:
{// The MAC signals that we shall provide an uplink as soon as possible
OnTxNextPacketTimerEvent( NULL );
break;
}
default:
break;
}
}
void OnMacProcessNotify( void )
{
}
void LoRa_Init(void)
{
LoRaMacPrimitives.MacMcpsConfirm = McpsConfirm;
LoRaMacPrimitives.MacMcpsIndication = McpsIndication;
LoRaMacPrimitives.MacMlmeConfirm = MlmeConfirm;
LoRaMacPrimitives.MacMlmeIndication = MlmeIndication;
LoRaMacCallbacks.GetBatteryLevel = BoardGetBatteryLevel;
LoRaMacCallbacks.GetTemperatureLevel = NULL;
LoRaMacCallbacks.NvmContextChange = NvmCtxMgmtEvent;
LoRaMacCallbacks.MacProcessNotify = OnMacProcessNotify;
LoRaMacInitialization( &LoRaMacPrimitives, &LoRaMacCallbacks, ACTIVE_REGION );
mibReq.Type = MIB_APP_KEY;
mibReq.Param.AppKey = AppKey;
LoRaMacMibSetRequestConfirm( &mibReq );
mibReq.Type = MIB_NWK_KEY;
mibReq.Param.NwkKey = NwkKey;
LoRaMacMibSetRequestConfirm( &mibReq );
#if( OVER_THE_AIR_ACTIVATION == 0 )
mibReq.Type = MIB_NET_ID;
mibReq.Param.NetID = LORAWAN_NETWORK_ID;
LoRaMacMibSetRequestConfirm( &mibReq );
mibReq.Type = MIB_DEV_ADDR;
mibReq.Param.DevAddr = DevAddr;
LoRaMacMibSetRequestConfirm( &mibReq );
mibReq.Type = MIB_F_NWK_S_INT_KEY;
mibReq.Param.FNwkSIntKey = FNwkSIntKey;
LoRaMacMibSetRequestConfirm( &mibReq );
mibReq.Type = MIB_S_NWK_S_INT_KEY;
mibReq.Param.SNwkSIntKey = SNwkSIntKey;
LoRaMacMibSetRequestConfirm( &mibReq );
mibReq.Type = MIB_NWK_S_ENC_KEY;
mibReq.Param.NwkSEncKey = NwkSEncKey;
LoRaMacMibSetRequestConfirm( &mibReq );
mibReq.Type = MIB_APP_S_KEY;
mibReq.Param.AppSKey = AppSKey;
LoRaMacMibSetRequestConfirm( &mibReq );
#endif
LoRaMacStart( );
mibReq.Type = MIB_NETWORK_ACTIVATION;
status = LoRaMacMibGetRequestConfirm( &mibReq );
if( status == LORAMAC_STATUS_OK )
{
if( mibReq.Param.NetworkActivation != ACTIVATION_TYPE_NONE )
{
NextTx = true;
}
}
#if 0
#if( OVER_THE_AIR_ACTIVATION == 0 )
LoRa_JoinNetwork(0);
#else
LoRa_JoinNetwork(1);
#endif
TimerInit( &TxNextPacketTimer, OnTxNextPacketTimerEvent );
printf_device_info();
while( 1 )
{
char *data = "Welcome to Tos Tiny!";
LoRaMacProcess( );
Lora_Send(0,2,(uint8_t *)data,strlen(data));
//PrepareTxFrame();
//SendFrame();
NextTx = false;
TimerSetValue( &TxNextPacketTimer, 15000 );
TimerStart( &TxNextPacketTimer );
while(!NextTx);
//tos_sleep_hmsm(0,0,1,400); //<2F><>ʱ1.4s
}
#endif
}
/*lorawan<61><6E><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
void LoRa_JoinNetwork(uint8_t jointype)
{
/*OTAAģʽ*/
if(jointype > 0)
{
MlmeReq_t mlmeReq;
mlmeReq.Type = MLME_JOIN;
mlmeReq.Req.Join.Datarate = LORAWAN_DEFAULT_DATARATE;
LoRaMacMlmeRequest( &mlmeReq );
}
else
{
/*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>״̬*/
MibRequestConfirm_t mibReq;
mibReq.Type = MIB_ABP_LORAWAN_VERSION;
mibReq.Param.AbpLrWanVersion.Value = ABP_ACTIVATION_LRWAN_VERSION;
LoRaMacMibSetRequestConfirm( &mibReq );
mibReq.Type = MIB_NETWORK_ACTIVATION;
mibReq.Param.NetworkActivation = ACTIVATION_TYPE_ABP;
LoRaMacMibSetRequestConfirm( &mibReq );
}
}
/*lorawan<61><6E><EFBFBD><EFBFBD>*/
uint8_t Lora_Send(uint8_t type,uint8_t port, uint8_t * psrc, uint16_t len)
{
/*<2A><>ȡ<EFBFBD><C8A1><EFBFBD>ͱ<EFBFBD><CDB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
if(type == 1)
{
IsTxConfirmed = true;
}
else
{
IsTxConfirmed = false;
}
/*<2A><>ȡ<EFBFBD>˿<EFBFBD>*/
if(port <1 && port > 233)
{
return 1;
}
else
{
/*<2A><><EFBFBD>¶˿<C2B6>*/
AppPort = port;
}
/*<2A><>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD>*/
if(len > LORAWAN_APP_DATA_MAX_SIZE)
{
return 1;
}
memcpy1(AppDataBuffer, psrc, len);
AppDataSize = len;
/*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
//printf("begin to send data\r\n");
LoRaMacStatus_t res = SendFrame( );
if(res == LORAMAC_STATUS_OK)
{
printf("SEND OK\r\n");
return 0;
}
else if(res == LORAMAC_STATUS_NO_NETWORK_JOINED)
{
printf("NO NETWORK JOINED\r\n");
return 2;
}
else if(res == LORAMAC_STATUS_BUSY)
{
printf("LORAMAC STATUS BUSY\r\n");
return 3;
}
else
{
return 1;
}
}
void printf_device_info(void)
{
printf( "DevEui : %02X", DevEui[0] );
for( int i = 1; i < 8; i++ )
{
printf( "-%02X", DevEui[i] );
}
printf( "\r\n" );
printf( "AppEui : %02X", JoinEui[0] );
for( int i = 1; i < 8; i++ )
{
printf( "-%02X", JoinEui[i] );
}
printf( "\r\n" );
printf( "AppKey : %02X", NwkKey[0] );
for( int i = 1; i < 16; i++ )
{
printf( " %02X", NwkKey[i] );
}
printf( "\n\r\n" );
#if( OVER_THE_AIR_ACTIVATION == 0 )
printf( "###### ===== JOINED ==== ######\r\n" );
printf( "\r\nABP\r\n\r\n" );
printf( "DevAddr : %08X\r\n", DevAddr );
printf( "NwkSKey : %02X", FNwkSIntKey[0] );
for( int i = 1; i < 16; i++ )
{
printf( " %02X", FNwkSIntKey[i] );
}
printf( "\r\n" );
printf( "AppSKey : %02X", AppSKey[0] );
for( int i = 1; i < 16; i++ )
{
printf( " %02X", AppSKey[i] );
}
printf( "\n\r\n" );
#endif
}

View File

@@ -1,80 +0,0 @@
#ifndef __LORAAPI_H__
#define __LORAAPI_H__
#include "stdio.h"
#include "string.h"
#include "utilities.h"
#include "board.h"
#include "gpio.h"
#include "LoRaMac.h"
#include "NvmCtxMgmt.h"
#define ACTIVE_REGION LORAMAC_REGION_CN470
#ifndef ACTIVE_REGION
#warning "No active region defined, LORAMAC_REGION_EU868 will be used as default."
#define ACTIVE_REGION LORAMAC_REGION_EU868
#endif
/*!
* Defines the application data transmission duty cycle. 5s, value in [ms].
*/
#define APP_TX_DUTYCYCLE 5000
/*!
* Defines a random delay for application data transmission duty cycle. 1s,
* value in [ms].
*/
#define APP_TX_DUTYCYCLE_RND 1000
/*!
* Default datarate
*/
#define LORAWAN_DEFAULT_DATARATE DR_0
/*!
* LoRaWAN confirmed messages
*/
#define LORAWAN_CONFIRMED_MSG_ON false
/*!
* LoRaWAN Adaptive Data Rate
*
* \remark Please note that when ADR is enabled the end-device should be static
*/
#define LORAWAN_ADR_ON 1
#define LORAWAN_DUTYCYCLE_ON false
#define OVER_THE_AIR_ACTIVATION 0
#define ABP_ACTIVATION_LRWAN_VERSION_V10x 0x01000300 // 1.0.3.0
#define ABP_ACTIVATION_LRWAN_VERSION ABP_ACTIVATION_LRWAN_VERSION_V10x
#define LORAWAN_PUBLIC_NETWORK true
#define LORAWAN_NETWORK_ID ( uint32_t )0
#define LORAWAN_APP_DATA_MAX_SIZE 64
extern bool NextTx;
extern TimerEvent_t TxNextPacketTimer;
void LoRa_Init(void);
void LoRa_JoinNetwork(uint8_t jointype);
uint8_t Lora_Send(uint8_t type,uint8_t port, uint8_t * psrc, uint16_t len);
void printf_device_info(void);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,77 +0,0 @@
#include "at_parser.h"
#include "uart-board.h"
#ifndef AT_CMD_BUF_LEN
#define AT_CMD_BUF_LEN 512
#endif
#ifndef UART_RECV_TIMEOUT
#define UART_RECV_TIMEOUT 15000
#endif
static at_uart_ops_t *uart_ops;
static at_table_t *cmd_table;
int at_parser_init(at_uart_ops_t *ops, at_table_t *table)
{
if (ops && table)
{
uart_ops = ops;
cmd_table = table;
if(ops->init)
return ops->init();
else
return 0;
}
else
return -1;
}
int at_cmd_handle(void)
{
uint8_t tmp_buf[AT_CMD_BUF_LEN];
uint16_t len = 0, i;
uint32_t n = 0;
uint16_t cmd_len = 0;
if(!uart_ops || !cmd_table)
return -1;
/*<2A>յ<EFBFBD>\r\n<><6E><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
while(n++ < UART_RECV_TIMEOUT)
{
if(uart_ops->recv(tmp_buf+len, 1) == 1)
{
len++;
n = 0;
}
}
/*ָ<><D6B8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>־*/
if(tmp_buf[len-2] == 0x0D/*'\r'*/ && tmp_buf[len-1] == 0x0A/*'\n'*/)
{
/*<2A><><EFBFBD>Ȳ<EFBFBD><C8B2><EFBFBD><EFBFBD><EFBFBD>\r\n*/
len -= 2;
}
/*<2A><>ѯATָ<54><EFBFBD><EEA3AC>ִ<EFBFBD><D6B4>*/
for(i = 0; cmd_table[i].cmd; i++)
{
cmd_len = strlen(cmd_table[i].cmd);
if(len >= cmd_len)
{
#ifdef AT_IGNORE_CASE
if(strncasecmp((const char*)cmd_table[i].cmd, (const char*)tmp_buf, cmd_len) == 0)
#else
if(memcmp((const char*)cmd_table[i].cmd, (const char*)tmp_buf, cmd_len) == 0)
#endif
{
/*<2A><>=<3D><><EFBFBD>IJ<EFBFBD><C4B2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
return cmd_table[i].func(tmp_buf + cmd_len, len - cmd_len);
}
}
}
return -1;
}

View File

@@ -1,56 +0,0 @@
#ifndef __AT_PARSER_H__
#define __AT_PARSER_H__
#include <stdint.h>
#include <string.h>
#define AT_CMD_END NULL
//#define AT_IGNORE_CASE
/*
* Please declare and register command table as follow before call
* at_cmd_handle.
* NOTE. Add AT_CMD_END as last member to mark the end of command.
* All receive text behind command text would be treated as data text
* pass to func.
*
* at_table_t cmd_table[] = {
* {"AT+VERSION=", ver_handle},
* {"AT+RESET", reset_handle},
* ...
* {AT_CMD_END, NULL},
* };
*/
typedef struct
{
const char *cmd; /* <20><><EFBFBD><EFBFBD><EFBFBD>ı<EFBFBD> */
uint8_t (*func)(uint8_t *, uint16_t size); /* <20><><EFBFBD><EFBFBD><EEB4A6><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
} at_table_t;
/*
* Please declare and register uart operations so that AT parser is
* able to receive text from uart.
*
* at_uart_ops_t uart_ops = {
* .init = NULL,
* .deinit = NULL,
* .send = NULL,
* .recv = UartReceive,
* .recv_timeout = UartReceive,
* };
*/
typedef struct
{
uint8_t (*init)(void);
uint8_t (*deinit)(void);
uint16_t (*send)(uint8_t *buf, uint16_t size);
uint16_t (*recv)(uint8_t *buf, uint16_t buf_len);
uint16_t (*recv_timeout)(uint8_t *buf, uint16_t buf_len);
}at_uart_ops_t;
int at_parser_init(at_uart_ops_t *uart_ops, at_table_t *cmd_table);
int at_cmd_handle(void);
#endif

View File

@@ -1,98 +1,35 @@
#include "LoRaApi.h"
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include "tos_k.h" #include "tos_k.h"
#include "atcmd-board.h"
/*LORA<52><41><EFBFBD><EFBFBD>״̬*/
uint8_t g_join_state = 0;
uint8_t g_st_state = 0;
/*<2A><><EFBFBD>ļ<EFBFBD><C4BC><EFBFBD>*/
uint32_t g_rx_num = 0;
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȼ<EFBFBD> k_task_t task1;
#define TASK1_PRIO 3 k_stack_t task1_stack[4096];
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ջ<EFBFBD><D5BB>С
#define TASK1_STK_SIZE (1024 * 4) extern int lora_main(void);
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ƿ<EFBFBD> void task1_fun(void *arg)
k_task_t Task1TCB;
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ջ
k_stack_t TASK1_STK[TASK1_STK_SIZE];
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
void task1(void *arg);
void lora_send_timer(void* context)
{ {
g_st_state =2; lora_main();
}
void task1(void *arg)
{
at_cmd_init();
LoRa_Init();
printf_device_info();
TimerInit( &TxNextPacketTimer, lora_send_timer );
while(1)
{
LoRaMacProcess();
if(g_join_state == 0)
{
printf("start join...\r\n");
/*<2A><><EFBFBD><EFBFBD>*/
LoRa_JoinNetwork(1);
g_join_state = 1;
}
if(g_join_state == 2)
{
/*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
if(g_st_state == 0)
{
g_st_state = 1;
TimerSetValue( &TxNextPacketTimer, 60000 );
TimerStart( &TxNextPacketTimer);
printf("\r\ntime to ");
}
else if(g_st_state == 2)
{
g_st_state = 3;
printf("send!\r\n");
/*<2A><><EFBFBD><EFBFBD>lora<72><61><EFBFBD><EFBFBD>*/
uint8_t tmpbuf[] = "tos tiny!";
Lora_Send(0, 2, tmpbuf, sizeof(tmpbuf));
g_rx_num++;
}
}
at_cmd_handle();
}
} }
extern uint8_t sx1276_band;
int main(void) int main(void)
{ {
k_err_t err; k_err_t err;
TOS_CPU_CPSR_ALLOC(); TOS_CPU_CPSR_ALLOC();
BoardInitMcu( ); printf("Welcome to TencentOS Tiny! \r\n");
BoardInitPeriph( ); tos_knl_init();
sx1276_band = 2; TOS_CPU_INT_DISABLE();
printf("welcome to tencent IoTOS\r\n"); err = tos_task_create(&task1,
err = tos_knl_init(); //<2F><>ʼ<EFBFBD><CABC>TOS "task1",
if (err != K_ERR_NONE) task1_fun,
{ NULL,
printf("tos init failed\r\n"); 3,
return err; task1_stack,
} 4096,
TOS_CPU_INT_DISABLE();//<2F><><EFBFBD><EFBFBD><EFBFBD>ٽ<EFBFBD><D9BD><EFBFBD> 20);
err = tos_task_create((k_task_t * )&Task1TCB, //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ƿ<EFBFBD> if(err != K_ERR_NONE)
(char * )"task1", //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> printf("TencentOS Tiny Create task1 fail! code : %d \r\n",err);
(k_task_entry_t )task1, //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
(void * )0, //<2F><><EFBFBD>ݸ<EFBFBD><DDB8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>IJ<EFBFBD><C4B2><EFBFBD>
(k_prio_t )TASK1_PRIO, //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȼ<EFBFBD>
TASK1_STK, //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ջ<EFBFBD><D5BB><EFBFBD><EFBFBD>ַ
(size_t)TASK1_STK_SIZE, //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ջ<EFBFBD><D5BB>С
(size_t )0); //<2F><>ʹ<EFBFBD><CAB9>ʱ<EFBFBD><CAB1>Ƭ<EFBFBD><C6AC>תʱ<D7AA><CAB1>ʱ<EFBFBD><CAB1>Ƭ<EFBFBD><C6AC><EFBFBD>ȣ<EFBFBD>Ϊ0ʱΪĬ<CEAA>ϳ<EFBFBD><CFB3>ȣ<EFBFBD>
TOS_CPU_INT_ENABLE(); //<2F>˳<EFBFBD><CBB3>ٽ<EFBFBD><D9BD><EFBFBD> TOS_CPU_INT_ENABLE();
tos_knl_start(); //<2F><><EFBFBD><EFBFBD>TOS tos_knl_start();
while (1)
{
}
} }

View File

@@ -0,0 +1,257 @@
/*!
* \file CayenneLpp.c
*
* \brief Implements the Cayenne Low Power Protocol
*
* \copyright Revised BSD License, see section \ref LICENSE.
*
* \code
* ______ _
* / _____) _ | |
* ( (____ _____ ____ _| |_ _____ ____| |__
* \____ \| ___ | (_ _) ___ |/ ___) _ \
* _____) ) ____| | | || |_| ____( (___| | | |
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
* (C)2013-2018 Semtech
*
* \endcode
*
* \author Miguel Luis ( Semtech )
*/
#include <stdint.h>
#include "utilities.h"
#include "CayenneLpp.h"
#define CAYENNE_LPP_MAXBUFFER_SIZE 242
static uint8_t CayenneLppBuffer[CAYENNE_LPP_MAXBUFFER_SIZE];
static uint8_t CayenneLppCursor = 0;
void CayenneLppInit( void )
{
CayenneLppCursor = 0;
}
void CayenneLppReset( void )
{
CayenneLppCursor = 0;
}
uint8_t CayenneLppGetSize( void )
{
return CayenneLppCursor;
}
uint8_t* CayenneLppGetBuffer( void )
{
return CayenneLppBuffer;
}
uint8_t CayenneLppCopy( uint8_t* dst )
{
memcpy1( dst, CayenneLppBuffer, CayenneLppCursor );
return CayenneLppCursor;
}
uint8_t CayenneLppAddDigitalInput( uint8_t channel, uint8_t value )
{
if( ( CayenneLppCursor + LPP_DIGITAL_INPUT_SIZE ) > CAYENNE_LPP_MAXBUFFER_SIZE )
{
return 0;
}
CayenneLppBuffer[CayenneLppCursor++] = channel;
CayenneLppBuffer[CayenneLppCursor++] = LPP_DIGITAL_INPUT;
CayenneLppBuffer[CayenneLppCursor++] = value;
return CayenneLppCursor;
}
uint8_t CayenneLppAddDigitalOutput( uint8_t channel, uint8_t value )
{
if( ( CayenneLppCursor + LPP_DIGITAL_OUTPUT_SIZE ) > CAYENNE_LPP_MAXBUFFER_SIZE )
{
return 0;
}
CayenneLppBuffer[CayenneLppCursor++] = channel;
CayenneLppBuffer[CayenneLppCursor++] = LPP_DIGITAL_OUTPUT;
CayenneLppBuffer[CayenneLppCursor++] = value;
return CayenneLppCursor;
}
uint8_t CayenneLppAddAnalogInput( uint8_t channel, float value )
{
if( ( CayenneLppCursor + LPP_ANALOG_INPUT_SIZE ) > CAYENNE_LPP_MAXBUFFER_SIZE )
{
return 0;
}
int16_t val = value * 100;
CayenneLppBuffer[CayenneLppCursor++] = channel;
CayenneLppBuffer[CayenneLppCursor++] = LPP_ANALOG_INPUT;
CayenneLppBuffer[CayenneLppCursor++] = val >> 8;
CayenneLppBuffer[CayenneLppCursor++] = val;
return CayenneLppCursor;
}
uint8_t CayenneLppAddAnalogOutput( uint8_t channel, float value )
{
if( ( CayenneLppCursor + LPP_ANALOG_OUTPUT_SIZE ) > CAYENNE_LPP_MAXBUFFER_SIZE )
{
return 0;
}
int16_t val = value * 100;
CayenneLppBuffer[CayenneLppCursor++] = channel;
CayenneLppBuffer[CayenneLppCursor++] = LPP_ANALOG_OUTPUT;
CayenneLppBuffer[CayenneLppCursor++] = val >> 8;
CayenneLppBuffer[CayenneLppCursor++] = val;
return CayenneLppCursor;
}
uint8_t CayenneLppAddLuminosity( uint8_t channel, uint16_t lux )
{
if( ( CayenneLppCursor + LPP_LUMINOSITY_SIZE ) > CAYENNE_LPP_MAXBUFFER_SIZE )
{
return 0;
}
CayenneLppBuffer[CayenneLppCursor++] = channel;
CayenneLppBuffer[CayenneLppCursor++] = LPP_LUMINOSITY;
CayenneLppBuffer[CayenneLppCursor++] = lux >> 8;
CayenneLppBuffer[CayenneLppCursor++] = lux;
return CayenneLppCursor;
}
uint8_t CayenneLppAddPresence( uint8_t channel, uint8_t value )
{
if( ( CayenneLppCursor + LPP_PRESENCE_SIZE ) > CAYENNE_LPP_MAXBUFFER_SIZE )
{
return 0;
}
CayenneLppBuffer[CayenneLppCursor++] = channel;
CayenneLppBuffer[CayenneLppCursor++] = LPP_PRESENCE;
CayenneLppBuffer[CayenneLppCursor++] = value;
return CayenneLppCursor;
}
uint8_t CayenneLppAddTemperature( uint8_t channel, float celsius )
{
if( ( CayenneLppCursor + LPP_TEMPERATURE_SIZE ) > CAYENNE_LPP_MAXBUFFER_SIZE )
{
return 0;
}
int16_t val = celsius * 10;
CayenneLppBuffer[CayenneLppCursor++] = channel;
CayenneLppBuffer[CayenneLppCursor++] = LPP_TEMPERATURE;
CayenneLppBuffer[CayenneLppCursor++] = val >> 8;
CayenneLppBuffer[CayenneLppCursor++] = val;
return CayenneLppCursor;
}
uint8_t CayenneLppAddRelativeHumidity( uint8_t channel, float rh )
{
if( ( CayenneLppCursor + LPP_RELATIVE_HUMIDITY_SIZE ) > CAYENNE_LPP_MAXBUFFER_SIZE )
{
return 0;
}
CayenneLppBuffer[CayenneLppCursor++] = channel;
CayenneLppBuffer[CayenneLppCursor++] = LPP_RELATIVE_HUMIDITY;
CayenneLppBuffer[CayenneLppCursor++] = rh * 2;
return CayenneLppCursor;
}
uint8_t CayenneLppAddAccelerometer( uint8_t channel, float x, float y, float z )
{
if( ( CayenneLppCursor + LPP_ACCELEROMETER_SIZE ) > CAYENNE_LPP_MAXBUFFER_SIZE )
{
return 0;
}
int16_t vx = x * 1000;
int16_t vy = y * 1000;
int16_t vz = z * 1000;
CayenneLppBuffer[CayenneLppCursor++] = channel;
CayenneLppBuffer[CayenneLppCursor++] = LPP_ACCELEROMETER;
CayenneLppBuffer[CayenneLppCursor++] = vx >> 8;
CayenneLppBuffer[CayenneLppCursor++] = vx;
CayenneLppBuffer[CayenneLppCursor++] = vy >> 8;
CayenneLppBuffer[CayenneLppCursor++] = vy;
CayenneLppBuffer[CayenneLppCursor++] = vz >> 8;
CayenneLppBuffer[CayenneLppCursor++] = vz;
return CayenneLppCursor;
}
uint8_t CayenneLppAddBarometricPressure( uint8_t channel, float hpa )
{
if( ( CayenneLppCursor + LPP_BAROMETRIC_PRESSURE_SIZE ) > CAYENNE_LPP_MAXBUFFER_SIZE )
{
return 0;
}
int16_t val = hpa * 10;
CayenneLppBuffer[CayenneLppCursor++] = channel;
CayenneLppBuffer[CayenneLppCursor++] = LPP_BAROMETRIC_PRESSURE;
CayenneLppBuffer[CayenneLppCursor++] = val >> 8;
CayenneLppBuffer[CayenneLppCursor++] = val;
return CayenneLppCursor;
}
uint8_t CayenneLppAddGyrometer( uint8_t channel, float x, float y, float z )
{
if( ( CayenneLppCursor + LPP_GYROMETER_SIZE ) > CAYENNE_LPP_MAXBUFFER_SIZE )
{
return 0;
}
int16_t vx = x * 100;
int16_t vy = y * 100;
int16_t vz = z * 100;
CayenneLppBuffer[CayenneLppCursor++] = channel;
CayenneLppBuffer[CayenneLppCursor++] = LPP_GYROMETER;
CayenneLppBuffer[CayenneLppCursor++] = vx >> 8;
CayenneLppBuffer[CayenneLppCursor++] = vx;
CayenneLppBuffer[CayenneLppCursor++] = vy >> 8;
CayenneLppBuffer[CayenneLppCursor++] = vy;
CayenneLppBuffer[CayenneLppCursor++] = vz >> 8;
CayenneLppBuffer[CayenneLppCursor++] = vz;
return CayenneLppCursor;
}
uint8_t CayenneLppAddGps( uint8_t channel, float latitude, float longitude, float meters )
{
if( ( CayenneLppCursor + LPP_GPS_SIZE ) > CAYENNE_LPP_MAXBUFFER_SIZE )
{
return 0;
}
int32_t lat = latitude * 10000;
int32_t lon = longitude * 10000;
int32_t alt = meters * 100;
CayenneLppBuffer[CayenneLppCursor++] = channel;
CayenneLppBuffer[CayenneLppCursor++] = LPP_GPS;
CayenneLppBuffer[CayenneLppCursor++] = lat >> 16;
CayenneLppBuffer[CayenneLppCursor++] = lat >> 8;
CayenneLppBuffer[CayenneLppCursor++] = lat;
CayenneLppBuffer[CayenneLppCursor++] = lon >> 16;
CayenneLppBuffer[CayenneLppCursor++] = lon >> 8;
CayenneLppBuffer[CayenneLppCursor++] = lon;
CayenneLppBuffer[CayenneLppCursor++] = alt >> 16;
CayenneLppBuffer[CayenneLppCursor++] = alt >> 8;
CayenneLppBuffer[CayenneLppCursor++] = alt;
return CayenneLppCursor;
}

View File

@@ -0,0 +1,76 @@
/*!
* \file CayenneLpp.h
*
* \brief Implements the Cayenne Low Power Protocol
*
* \copyright Revised BSD License, see section \ref LICENSE.
*
* \code
* ______ _
* / _____) _ | |
* ( (____ _____ ____ _| |_ _____ ____| |__
* \____ \| ___ | (_ _) ___ |/ ___) _ \
* _____) ) ____| | | || |_| ____( (___| | | |
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
* (C)2013-2018 Semtech
*
* \endcode
*
* \author Miguel Luis ( Semtech )
*/
#ifndef __CAYENNE_LPP_H__
#define __CAYENNE_LPP_H__
#include <stdint.h>
#define LPP_DIGITAL_INPUT 0 // 1 byte
#define LPP_DIGITAL_OUTPUT 1 // 1 byte
#define LPP_ANALOG_INPUT 2 // 2 bytes, 0.01 signed
#define LPP_ANALOG_OUTPUT 3 // 2 bytes, 0.01 signed
#define LPP_LUMINOSITY 101 // 2 bytes, 1 lux unsigned
#define LPP_PRESENCE 102 // 1 byte, 1
#define LPP_TEMPERATURE 103 // 2 bytes, 0.1°C signed
#define LPP_RELATIVE_HUMIDITY 104 // 1 byte, 0.5% unsigned
#define LPP_ACCELEROMETER 113 // 2 bytes per axis, 0.001G
#define LPP_BAROMETRIC_PRESSURE 115 // 2 bytes 0.1 hPa Unsigned
#define LPP_GYROMETER 134 // 2 bytes per axis, 0.01 °/s
#define LPP_GPS 136 // 3 byte lon/lat 0.0001 °, 3 bytes alt 0.01m
// Data ID + Data Type + Data Size
#define LPP_DIGITAL_INPUT_SIZE 3
#define LPP_DIGITAL_OUTPUT_SIZE 3
#define LPP_ANALOG_INPUT_SIZE 4
#define LPP_ANALOG_OUTPUT_SIZE 4
#define LPP_LUMINOSITY_SIZE 4
#define LPP_PRESENCE_SIZE 3
#define LPP_TEMPERATURE_SIZE 4
#define LPP_RELATIVE_HUMIDITY_SIZE 3
#define LPP_ACCELEROMETER_SIZE 8
#define LPP_BAROMETRIC_PRESSURE_SIZE 4
#define LPP_GYROMETER_SIZE 8
#define LPP_GPS_SIZE 11
void CayenneLppInit( void );
void CayenneLppReset( void );
uint8_t CayenneLppGetSize( void );
uint8_t* CayenneLppGetBuffer( void );
uint8_t CayenneLppCopy( uint8_t* buffer );
uint8_t CayenneLppAddDigitalInput( uint8_t channel, uint8_t value );
uint8_t CayenneLppAddDigitalOutput( uint8_t channel, uint8_t value );
uint8_t CayenneLppAddAnalogInput( uint8_t channel, float value );
uint8_t CayenneLppAddAnalogOutput( uint8_t channel, float value );
uint8_t CayenneLppAddLuminosity( uint8_t channel, uint16_t lux );
uint8_t CayenneLppAddPresence( uint8_t channel, uint8_t value );
uint8_t CayenneLppAddTemperature( uint8_t channel, float celsius );
uint8_t CayenneLppAddRelativeHumidity( uint8_t channel, float rh );
uint8_t CayenneLppAddAccelerometer( uint8_t channel, float x, float y, float z );
uint8_t CayenneLppAddBarometricPressure( uint8_t channel, float hpa );
uint8_t CayenneLppAddGyrometer( uint8_t channel, float x, float y, float z );
uint8_t CayenneLppAddGps( uint8_t channel, float latitude, float longitude, float meters );
#endif // __CAYENNE_LPP_H__

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,335 @@
/*!
* \file LmHandler.h
*
* \brief Implements the LoRaMac layer handling.
* Provides the possibility to register applicative packages.
*
* \remark Inspired by the examples provided on the en.i-cube_lrwan fork.
* MCD Application Team ( STMicroelectronics International )
*
* \copyright Revised BSD License, see section \ref LICENSE.
*
* \code
* ______ _
* / _____) _ | |
* ( (____ _____ ____ _| |_ _____ ____| |__
* \____ \| ___ | (_ _) ___ |/ ___) _ \
* _____) ) ____| | | || |_| ____( (___| | | |
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
* (C)2013-2018 Semtech
*
* \endcode
*
* \author Miguel Luis ( Semtech )
*/
#ifndef __LORAMAC_HANDLER_H__
#define __LORAMAC_HANDLER_H__
#ifdef __cplusplus
extern "C"
{
#endif
#include "LmHandlerTypes.h"
#include "LmhpCompliance.h"
typedef struct LmHandlerJoinParams_s
{
CommissioningParams_t *CommissioningParams;
int8_t Datarate;
LmHandlerErrorStatus_t Status;
}LmHandlerJoinParams_t;
typedef struct LmHandlerTxParams_s
{
uint8_t IsMcpsConfirm;
LoRaMacEventInfoStatus_t Status;
CommissioningParams_t *CommissioningParams;
LmHandlerMsgTypes_t MsgType;
uint8_t AckReceived;
int8_t Datarate;
uint32_t UplinkCounter;
LmHandlerAppData_t AppData;
int8_t TxPower;
uint8_t Channel;
}LmHandlerTxParams_t;
typedef struct LmHandlerRxParams_s
{
uint8_t IsMcpsIndication;
LoRaMacEventInfoStatus_t Status;
CommissioningParams_t *CommissioningParams;
int8_t Datarate;
int8_t Rssi;
int8_t Snr;
uint32_t DownlinkCounter;
int8_t RxSlot;
}LmHandlerRxParams_t;
typedef struct LoRaMAcHandlerBeaconParams_s
{
LoRaMacEventInfoStatus_t Status;
LmHandlerBeaconState_t State;
BeaconInfo_t Info;
}LoRaMAcHandlerBeaconParams_t;
typedef struct LmHandlerParams_s
{
/*!
* Region
*/
LoRaMacRegion_t Region;
/*!
* Holds the ADR state
*/
bool AdrEnable;
/*!
* Uplink datarate, when \ref AdrEnable is OFF
*/
int8_t TxDatarate;
/*!
* Enables/Disables a public network usage
*/
bool PublicNetworkEnable;
/*!
* LoRaWAN ETSI duty cycle control enable/disable
*
* \remark Please note that ETSI mandates duty cycled transmissions. Use only for test purposes
*/
bool DutyCycleEnabled;
/*!
* Application data buffer maximum size
*/
uint8_t DataBufferMaxSize;
/*!
* Application data buffer pointer
*/
uint8_t *DataBuffer;
}LmHandlerParams_t;
typedef struct LmHandlerCallbacks_s
{
/*!
* Get the current battery level
*
* \retval value Battery level ( 0: very low, 254: fully charged )
*/
uint8_t ( *GetBatteryLevel )( void );
/*!
* Get the current temperature
*
* \retval value Temperature in degree Celsius
*/
float ( *GetTemperature )( void );
/*!
* Returns a pseudo random seed generated using the MCU Unique ID
*
* \retval seed Generated pseudo random seed
*/
uint32_t ( *GetRandomSeed )( void );
/*!
*\brief Will be called each time a Radio IRQ is handled by the MAC
* layer.
*
*\warning Runs in a IRQ context. Should only change variables state.
*/
void ( *OnMacProcess )( void );
/*!
* Notifies the upper layer that the NVM context has changed
*
* \param [IN] stored Indicates if we are storing (true) or
* restoring (false) the NVM context
*/
void ( *OnNvmContextChange )( LmHandlerNvmContextStates_t state );
/*!
* Notifies the upper layer that a network parameters have been set
*
* \param [IN] params notification parameters
*/
void ( *OnNetworkParametersChange )( CommissioningParams_t *params );
/*!
* Notifies the upper layer that a MCPS request has been made to the MAC layer
*
* \param [IN] status - Request returned status
* \param [IN] mcpsRequest - Performed MCPS-Request. Refer to \ref McpsReq_t.
* \param [IN] nextTxDelay - Time to wait until another TX is possible.
*/
void ( *OnMacMcpsRequest )( LoRaMacStatus_t status, McpsReq_t *mcpsReq, TimerTime_t nextTxDelay );
/*!
* Notifies the upper layer that a MLME request has been made to the MAC layer
*
* \param [IN] status - Request returned status
* \param [IN] mlmeRequest - Performed MLME-Request. Refer to \ref MlmeReq_t.
* \param [IN] nextTxDelay - Time to wait until another TX is possible.
*/
void ( *OnMacMlmeRequest )( LoRaMacStatus_t status, MlmeReq_t *mlmeReq, TimerTime_t nextTxDelay );
/*!
* Notifies the upper layer that a network has been joined
*
* \param [IN] params notification parameters
*/
void ( *OnJoinRequest )( LmHandlerJoinParams_t *params );
/*!
* Notifies upper layer that a frame has been transmitted
*
* \param [IN] params notification parameters
*/
void ( *OnTxData )( LmHandlerTxParams_t *params );
/*!
* Notifies the upper layer that an applicative frame has been received
*
* \param [IN] appData Received applicative data
* \param [IN] params notification parameters
*/
void ( *OnRxData )( LmHandlerAppData_t *appData, LmHandlerRxParams_t *params );
/*!
* Confirms the LoRaWAN device class change
*
* \param [IN] deviceClass New end-device class
*/
void ( *OnClassChange )( DeviceClass_t deviceClass );
/*!
* Notifies the upper layer that the beacon status has changed
*
* \param [IN] params notification parameters
*/
void ( *OnBeaconStatusChange )( LoRaMAcHandlerBeaconParams_t *params );
#if( LMH_SYS_TIME_UPDATE_NEW_API == 1 )
/*!
* Notifies the upper layer that the system time has been updated.
*
* \param [in] isSynchronized Indicates if the system time is synchronized in the range +/-1 second
* \param [in] timeCorrection Received time correction value
*/
void ( *OnSysTimeUpdate )( bool isSynchronized, int32_t timeCorrection );
#else
/*!
* Notifies the upper layer that the system time has been updated.
*/
void ( *OnSysTimeUpdate )( void );
#endif
}LmHandlerCallbacks_t;
/*!
* LoRaMac handler initialisation
*
* \param [IN] callbacks LoRaMac handler callbacks
* \param [IN] handlerParams LoRaMac handler parameters
*
* \retval none
*/
LmHandlerErrorStatus_t LmHandlerInit( LmHandlerCallbacks_t *callbacks,
LmHandlerParams_t *handlerParams );
/*!
* Indicates if the LoRaMacHandler is busy
*
* \retval status [true] Busy, [false] free
*/
bool LmHandlerIsBusy( void );
/*!
* Processes the LoRaMac and Radio events.
* When no pendig operation asks to go in low power mode.
*
* \remark This function must be called in the main loop.
*/
void LmHandlerProcess( void );
/*!
* Instructs the MAC layer to send a ClassA uplink
*
* \param [IN] appData Data to be sent
* \param [IN] isTxConfirmed Indicates if the uplink requires an acknowledgement
*
* \retval status Returns \ref LORAMAC_HANDLER_SUCCESS if request has been
* processed else \ref LORAMAC_HANDLER_ERROR
*/
LmHandlerErrorStatus_t LmHandlerSend( LmHandlerAppData_t *appData, LmHandlerMsgTypes_t isTxConfirmed );
/*!
* Join a LoRa Network in classA
*
* \Note if the device is ABP, this is a pass through function
*/
void LmHandlerJoin( void );
/*!
* Check whether the Device is joined to the network
*
* \param [IN] none
*
* \retval status Returns \ref LORAMAC_HANDLER_SET if joined else \ref LORAMAC_HANDLER_RESET
*/
LmHandlerFlagStatus_t LmHandlerJoinStatus( void );
/*!
* Informs the server on the ping-slot periodicity to use
*
* \param [IN] periodicity Is equal to 2^periodicity seconds.
* Example: 2^3 = 8 seconds. The end-device will open an Rx slot every 8 seconds.
*
* \retval status Returns \ref LORAMAC_HANDLER_SUCCESS if request has been
* processed else \ref LORAMAC_HANDLER_ERROR
*/
LmHandlerErrorStatus_t LmHandlerPingSlotReq( uint8_t periodicity );
/*!
* Request the MAC layer to change LoRaWAN class
*
* \Note Callback \ref LmHandlerConfirmClass informs upper layer that the change has occurred
* \Note Only switch from class A to class B/C OR from class B/C to class A is allowed
*
* \param [IN] newClass New class to be requested
*
* \retval status Returns \ref LORAMAC_HANDLER_SUCCESS if request has been
* processed else \ref LORAMAC_HANDLER_ERROR
*/
LmHandlerErrorStatus_t LmHandlerRequestClass( DeviceClass_t newClass );
/*!
* Gets the current LoRaWAN class
*
* \retval currentClass Current LoRaWAN class
*/
DeviceClass_t LmHandlerGetCurrentClass( void );
/*!
* Gets the current datarate
*
* \retval currentDatarate Current datarate
*/
int8_t LmHandlerGetCurrentDatarate( void );
/*!
* Gets the current active region
*
* \retval currentRegion Current active region
*/
LoRaMacRegion_t LmHandlerGetActiveRegion( void );
/*!
* Set system maximum tolerated rx error in milliseconds
*
* \param [IN] maxErrorInMs Maximum tolerated error in milliseconds
*
* \retval status Returns \ref LORAMAC_HANDLER_SUCCESS if request has been
* processed else \ref LORAMAC_HANDLER_ERROR
*/
LmHandlerErrorStatus_t LmHandlerSetSystemMaxRxError( uint32_t maxErrorInMs );
/*
*=============================================================================
* PACKAGES HANDLING
*=============================================================================
*/
LmHandlerErrorStatus_t LmHandlerPackageRegister( uint8_t id, void *params );
bool LmHandlerPackageIsInitialized( uint8_t id );
bool LmHandlerPackageIsRunning( uint8_t id );
#ifdef __cplusplus
}
#endif
#endif // __LORAMAC_HANDLER_H__

View File

@@ -0,0 +1,124 @@
/*!
* \file LmHandlerTypes.h
*
* \brief Defines the types used by LmHandler
*
* \copyright Revised BSD License, see section \ref LICENSE.
*
* \code
* ______ _
* / _____) _ | |
* ( (____ _____ ____ _| |_ _____ ____| |__
* \____ \| ___ | (_ _) ___ |/ ___) _ \
* _____) ) ____| | | || |_| ____( (___| | | |
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
* (C)2013-2018 Semtech
*
* \endcode
*
* \author Miguel Luis ( Semtech )
*/
#ifndef __LORAMAC_HANDLER_TYPES_H__
#define __LORAMAC_HANDLER_TYPES_H__
#include "LoRaMac.h"
/*!
* If set to 1 the new API defining \ref OnSysTimeUpdate callback is used.
*/
#define LMH_SYS_TIME_UPDATE_NEW_API 1
/*!
*
*/
typedef enum
{
LORAMAC_HANDLER_ADR_OFF = 0,
LORAMAC_HANDLER_ADR_ON = !LORAMAC_HANDLER_ADR_OFF
}LmHandlerAdrStates_t;
/*!
*
*/
typedef enum
{
LORAMAC_HANDLER_RESET = 0,
LORAMAC_HANDLER_SET = !LORAMAC_HANDLER_RESET
}LmHandlerFlagStatus_t;
/*!
*
*/
typedef enum
{
LORAMAC_HANDLER_ERROR = -1,
LORAMAC_HANDLER_SUCCESS = 0
}LmHandlerErrorStatus_t;
/*!
*
*/
typedef enum
{
LORAMAC_HANDLER_UNCONFIRMED_MSG = 0,
LORAMAC_HANDLER_CONFIRMED_MSG = !LORAMAC_HANDLER_UNCONFIRMED_MSG
}LmHandlerMsgTypes_t;
/*!
*
*/
typedef enum
{
LORAMAC_HANDLER_FALSE = 0,
LORAMAC_HANDLER_TRUE = !LORAMAC_HANDLER_FALSE
}LmHandlerBoolean_t;
typedef enum
{
LORAMAC_HANDLER_BEACON_ACQUIRING,
LORAMAC_HANDLER_BEACON_LOST,
LORAMAC_HANDLER_BEACON_RX,
LORAMAC_HANDLER_BEACON_NRX
}LmHandlerBeaconState_t;
typedef enum
{
LORAMAC_HANDLER_NVM_RESTORE,
LORAMAC_HANDLER_NVM_STORE,
}LmHandlerNvmContextStates_t;
/*!
* Commissioning parameters
*/
typedef struct CommissioningParams_s
{
bool IsOtaaActivation;
uint8_t DevEui[8];
uint8_t JoinEui[8];
uint8_t SePin[4];
uint32_t NetworkId;
uint32_t DevAddr;
}CommissioningParams_t;
/*!
* Application data structure
*/
typedef struct LmHandlerAppData_s
{
uint8_t Port;
uint8_t BufferSize;
uint8_t *Buffer;
}LmHandlerAppData_t;
typedef struct LmHandlerRequestParams_s
{
uint8_t IsMcpsRequest;
LoRaMacStatus_t Status;
union
{
Mcps_t Mcps;
Mlme_t Mlme;
}RequestType;
}LmHandlerRequestParams_t;
#endif // __LORAMAC_HANDLER_TYPES_H__

View File

@@ -0,0 +1,750 @@
/*!
* \file FragDecoder.c
*
* \brief Implements the LoRa-Alliance fragmentation decoder
* Specification: https://lora-alliance.org/sites/default/files/2018-09/fragmented_data_block_transport_v1.0.0.pdf
*
* \copyright Revised BSD License, see section \ref LICENSE.
*
* \code
* ______ _
* / _____) _ | |
* ( (____ _____ ____ _| |_ _____ ____| |__
* \____ \| ___ | (_ _) ___ |/ ___) _ \
* _____) ) ____| | | || |_| ____( (___| | | |
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
* (C)2013-2018 Semtech
*
* \endcode
*
* \author Fabien Holin ( Semtech )
* \author Miguel Luis ( Semtech )
*/
#include <stddef.h>
#include <stdbool.h>
#include "utilities.h"
#include "FragDecoder.h"
#define DBG_TRACE 0
#if DBG_TRACE == 1
#include <stdio.h>
/*!
* Works in the same way as the printf function does.
*/
#define DBG( ... ) \
do \
{ \
printf( __VA_ARGS__ ); \
}while( 0 )
#else
#define DBG( fmt, ... )
#endif
/*
*=============================================================================
* Fragmentation decoder algorithm utilities
*=============================================================================
*/
typedef struct
{
#if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 )
FragDecoderCallbacks_t *Callbacks;
#else
uint8_t *File;
uint32_t FileSize;
#endif
uint16_t FragNb;
uint8_t FragSize;
uint32_t M2BLine;
uint8_t MatrixM2B[( ( FRAG_MAX_REDUNDANCY >> 3 ) + 1 ) * FRAG_MAX_REDUNDANCY];
uint16_t FragNbMissingIndex[FRAG_MAX_NB];
uint8_t S[( FRAG_MAX_REDUNDANCY >> 3 ) + 1];
FragDecoderStatus_t Status;
}FragDecoder_t;
#if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 )
/*!
* \brief Sets a row from source into file destination
*
* \param [IN] src Source buffer pointer
* \param [IN] row Destination index of the row to be copied
* \param [IN] size Source number of bytes to be copied
*/
static void SetRow( uint8_t *src, uint16_t row, uint16_t size );
#else
/*!
* \brief Sets a row from source into destination
*
* \param [IN] dst Destination buffer pointer
* \param [IN] src Source buffer pointer
* \param [IN] row Destination index of the row to be copied
* \param [IN] size Source number of bytes to be copied
*/
static void SetRow( uint8_t *dst, uint8_t *src, uint16_t row, uint16_t size );
#endif
#if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 )
/*!
* \brief Gets a row from source and stores it into file destination
*
* \param [IN] src Source buffer pointer
* \param [IN] row Source index of the row to be copied
* \param [IN] size Source number of bytes to be copied
*/
static void GetRow( uint8_t *src, uint16_t row, uint16_t size );
#else
/*!
* \brief Gets a row from source and stores it into destination
*
* \param [IN] dst Destination buffer pointer
* \param [IN] src Source buffer pointer
* \param [IN] row Source index of the row to be copied
* \param [IN] size Source number of bytes to be copied
*/
static void GetRow( uint8_t *dst, uint8_t *src, uint16_t row, uint16_t size );
#endif
/*!
* \brief Gets the parity value from a given row of the parity matrix
*
* \param [IN] index The index of the row to be computed
* \param [IN] matrixRow Pointer to the parity matrix (parity bit array)
*
* \retval parity Parity value at the given index
*/
static uint8_t GetParity( uint16_t index, uint8_t *matrixRow );
/*!
* \brief Sets the parity value on the given row of the parity matrix
*
* \param [IN] index The index of the row to be computed
* \param [IN/OUT] matrixRow Pointer to the parity matrix.
* \param [IN] parity The parity value to be set in the parity matrix
*/
static void SetParity( uint16_t index, uint8_t *matrixRow, uint8_t parity );
/*!
* \brief Check if the provided value is a power of 2
*
* \param [IN] x Value to be tested
*
* \retval status Return true if frame is a power of two
*/
static bool IsPowerOfTwo( uint32_t x );
/*!
* \brief XOrs two data lines
*
* \param [IN] line1 1st Data line to be XORed
* \param [IN] line2 2nd Data line to be XORed
* \param [IN] size Number of elements in line1
*
* \param [OUT] result XOR( line1, line2 ) result stored in line1
*/
static void XorDataLine( uint8_t *line1, uint8_t *line2, int32_t size );
/*!
* \brief XORs two parity lines
*
* \param [IN] line1 1st Parity line to be XORed
* \param [IN] line2 2nd Parity line to be XORed
* \param [IN] size Number of elements in line1
*
* \param [OUT] result XOR( line1, line2 ) result stored in line1
*/
static void XorParityLine( uint8_t* line1, uint8_t* line2, int32_t size );
/*!
* \brief Generates a pseudo random number : PRBS23
*
* \param [IN] value The input of the PRBS23 generator
*
* \retval nextValue Returns the next pseudo random number
*/
static int32_t FragPrbs23( int32_t value );
/*!
* \brief Gets and fills the parity matrix
*
* \param [IN] n Fragment N
* \param [IN] m Fragment number
* \param [OUT] matrixRow Parity matrix
*/
static void FragGetParityMatrixRow( int32_t n, int32_t m, uint8_t *matrixRow );
/*!
* \brief Finds the index of the first one in a bit array
*
* \param [IN] bitArray Pointer to the bit array
* \param [IN] size Bit array size
* \retval index The index of the first 1 in the bit array
*/
static uint16_t BitArrayFindFirstOne( uint8_t *bitArray, uint16_t size );
/*!
* \brief Checks if the provided bit array only contains zeros
*
* \param [IN] bitArray Pointer to the bit array
* \param [IN] size Bit array size
* \retval isAllZeros [0: Contains ones, 1: Contains all zeros]
*/
static uint8_t BitArrayIsAllZeros( uint8_t *bitArray, uint16_t size );
/*!
* \brief Finds & marks missing fragments
*
* \param [IN] counter Current fragment counter
* \param [OUT] FragDecoder.FragNbMissingIndex[] array is updated in place
*/
static void FragFindMissingFrags( uint16_t counter );
/*!
* \brief Finds the index (frag counter) of the x th missing frag
*
* \param [IN] x x th missing frag
*
* \retval counter The counter value associated to the x th missing frag
*/
static uint16_t FragFindMissingIndex( uint16_t x );
/*!
* \brief Extacts a row from the binary matrix and expands it to a bitArray
*
* \param [IN] bitArray Pointer to the bit array
* \param [IN] rowIndex Matrix row index
* \param [IN] bitsInRow Number of bits in one row
*/
static void FragExtractLineFromBinaryMatrix( uint8_t* bitArray, uint16_t rowIndex, uint16_t bitsInRow );
/*!
* \brief Collapses and Pushs a row of a bit array to the matrix
*
* \param [IN] bitArray Pointer to the bit array
* \param [IN] rowIndex Matrix row index
* \param [IN] bitsInRow Number of bits in one row
*/
static void FragPushLineToBinaryMatrix( uint8_t *bitArray, uint16_t rowIndex, uint16_t bitsInRow );
/*
*=============================================================================
* Fragmentation decoder algorithm
*=============================================================================
*/
static FragDecoder_t FragDecoder;
#if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 )
void FragDecoderInit( uint16_t fragNb, uint8_t fragSize, FragDecoderCallbacks_t *callbacks )
#else
void FragDecoderInit( uint16_t fragNb, uint8_t fragSize, uint8_t *file, uint32_t fileSize )
#endif
{
#if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 )
FragDecoder.Callbacks = callbacks;
#else
FragDecoder.File = file;
FragDecoder.FileSize = fileSize;
#endif
FragDecoder.FragNb = fragNb; // FragNb = FRAG_MAX_SIZE
FragDecoder.FragSize = fragSize; // number of byte on a row
FragDecoder.Status.FragNbLastRx = 0;
FragDecoder.Status.FragNbLost = 0;
FragDecoder.M2BLine = 0;
// Initialize missing fragments index array
for( uint16_t i = 0; i < FRAG_MAX_NB; i++ )
{
FragDecoder.FragNbMissingIndex[i] = 1;
}
// Initialize parity matrix
for( uint32_t i = 0; i < ( ( FRAG_MAX_REDUNDANCY >> 3 ) + 1 ); i++ )
{
FragDecoder.S[i] = 0;
}
for( uint32_t i = 0; i < ( ( ( FRAG_MAX_REDUNDANCY >> 3 ) + 1 ) * FRAG_MAX_REDUNDANCY ); i++ )
{
FragDecoder.MatrixM2B[i] = 0xFF;
}
// Initialize final uncoded data buffer ( FRAG_MAX_NB * FRAG_MAX_SIZE )
for( uint32_t i = 0; i < ( fragNb * fragSize ); i++ )
{
#if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 )
if( ( FragDecoder.Callbacks != NULL ) && ( FragDecoder.Callbacks->FragDecoderWrite != NULL ) )
{
FragDecoder.Callbacks->FragDecoderWrite( i, ( uint8_t[] ){ 0xFF }, 1 );
}
#else
FragDecoder.File[i] = 0xFF;
#endif
}
FragDecoder.Status.FragNbLost = 0;
FragDecoder.Status.FragNbLastRx = 0;
}
#if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 )
uint32_t FragDecoderGetMaxFileSize( void )
{
return FRAG_MAX_NB * FRAG_MAX_SIZE;
}
#endif
int32_t FragDecoderProcess( uint16_t fragCounter, uint8_t *rawData )
{
uint16_t firstOneInRow = 0;
int32_t first = 0;
int32_t noInfo = 0;
uint8_t matrixRow[(FRAG_MAX_NB >> 3 ) + 1];
uint8_t matrixDataTemp[FRAG_MAX_SIZE];
uint8_t dataTempVector[( FRAG_MAX_REDUNDANCY >> 3 ) + 1];
uint8_t dataTempVector2[( FRAG_MAX_REDUNDANCY >> 3 ) + 1];
memset1( matrixRow, 0, ( FRAG_MAX_NB >> 3 ) + 1 );
memset1( matrixDataTemp, 0, FRAG_MAX_SIZE );
memset1( dataTempVector, 0, ( FRAG_MAX_REDUNDANCY >> 3 ) + 1 );
memset1( dataTempVector2, 0, ( FRAG_MAX_REDUNDANCY >> 3 ) + 1 );
FragDecoder.Status.FragNbRx = fragCounter;
if( fragCounter < FragDecoder.Status.FragNbLastRx )
{
return FRAG_SESSION_ONGOING; // Drop frame out of order
}
// The M (FragNb) first packets aren't encoded or in other words they are
// encoded with the unitary matrix
if( fragCounter < ( FragDecoder.FragNb + 1 ) )
{
// The M first frame are not encoded store them
#if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 )
SetRow( rawData, fragCounter - 1, FragDecoder.FragSize );
#else
SetRow( FragDecoder.File, rawData, fragCounter - 1, FragDecoder.FragSize );
#endif
FragDecoder.FragNbMissingIndex[fragCounter - 1] = 0;
// Update the FragDecoder.FragNbMissingIndex with the loosing frame
FragFindMissingFrags( fragCounter );
}
else
{
if( FragDecoder.Status.FragNbLost > FRAG_MAX_REDUNDANCY )
{
FragDecoder.Status.MatrixError = 1;
return FRAG_SESSION_FINISHED;
}
// At this point we receive encoded frames and the number of loosing frames
// is well known: FragDecoder.FragNbLost - 1;
// In case of the end of true data is missing
FragFindMissingFrags( fragCounter );
if( FragDecoder.Status.FragNbLost == 0 )
{
// the case : all the M(FragNb) first rows have been transmitted with no error
return FragDecoder.Status.FragNbLost;
}
// fragCounter - FragDecoder.FragNb
FragGetParityMatrixRow( fragCounter - FragDecoder.FragNb, FragDecoder.FragNb, matrixRow );
for( int32_t i = 0; i < FragDecoder.FragNb; i++ )
{
if( GetParity( i , matrixRow ) == 1 )
{
if( FragDecoder.FragNbMissingIndex[i] == 0 )
{
// XOR with already receive frag
SetParity( i, matrixRow, 0 );
#if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 )
GetRow( matrixDataTemp, i, FragDecoder.FragSize );
#else
GetRow( matrixDataTemp, FragDecoder.File, i, FragDecoder.FragSize );
#endif
XorDataLine( rawData, matrixDataTemp, FragDecoder.FragSize );
}
else
{
// Fill the "little" boolean matrix m2b
SetParity( FragDecoder.FragNbMissingIndex[i] - 1, dataTempVector, 1 );
if( first == 0 )
{
first = 1;
}
}
}
}
firstOneInRow = BitArrayFindFirstOne( dataTempVector, FragDecoder.Status.FragNbLost );
if( first > 0 )
{
int32_t li;
int32_t lj;
// Manage a new line in MatrixM2B
while( GetParity( firstOneInRow, FragDecoder.S ) == 1 )
{
// Row already diagonalized exist & ( FragDecoder.MatrixM2B[firstOneInRow][0] )
FragExtractLineFromBinaryMatrix( dataTempVector2, firstOneInRow, FragDecoder.Status.FragNbLost );
XorParityLine( dataTempVector, dataTempVector2, FragDecoder.Status.FragNbLost );
// Have to store it in the mi th position of the missing frag
li = FragFindMissingIndex( firstOneInRow );
#if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 )
GetRow( matrixDataTemp, li, FragDecoder.FragSize );
#else
GetRow( matrixDataTemp, FragDecoder.File, li, FragDecoder.FragSize );
#endif
XorDataLine( rawData, matrixDataTemp, FragDecoder.FragSize );
if( BitArrayIsAllZeros( dataTempVector, FragDecoder.Status.FragNbLost ) )
{
noInfo = 1;
break;
}
firstOneInRow = BitArrayFindFirstOne( dataTempVector, FragDecoder.Status.FragNbLost );
}
if( noInfo == 0 )
{
FragPushLineToBinaryMatrix( dataTempVector, firstOneInRow, FragDecoder.Status.FragNbLost );
li = FragFindMissingIndex( firstOneInRow );
#if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 )
SetRow( rawData, li, FragDecoder.FragSize );
#else
SetRow( FragDecoder.File, rawData, li, FragDecoder.FragSize );
#endif
SetParity( firstOneInRow, FragDecoder.S, 1 );
FragDecoder.M2BLine++;
}
if( FragDecoder.M2BLine == FragDecoder.Status.FragNbLost )
{
// Then last step diagonalized
if( FragDecoder.Status.FragNbLost > 1 )
{
int32_t i, j;
for( i = ( FragDecoder.Status.FragNbLost - 2 ); i >= 0 ; i-- )
{
li = FragFindMissingIndex( i );
#if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 )
GetRow( matrixDataTemp, li, FragDecoder.FragSize );
#else
GetRow( matrixDataTemp, FragDecoder.File, li, FragDecoder.FragSize );
#endif
for( j = ( FragDecoder.Status.FragNbLost - 1 ); j > i; j--)
{
FragExtractLineFromBinaryMatrix( dataTempVector2, i, FragDecoder.Status.FragNbLost );
FragExtractLineFromBinaryMatrix( dataTempVector, j, FragDecoder.Status.FragNbLost );
if( GetParity( j, dataTempVector2 ) == 1 )
{
XorParityLine( dataTempVector2, dataTempVector, FragDecoder.Status.FragNbLost );
lj = FragFindMissingIndex( j );
#if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 )
GetRow( rawData, lj, FragDecoder.FragSize );
#else
GetRow( rawData, FragDecoder.File, lj, FragDecoder.FragSize );
#endif
XorDataLine( matrixDataTemp , rawData , FragDecoder.FragSize );
}
}
#if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 )
SetRow( matrixDataTemp, li, FragDecoder.FragSize );
#else
SetRow( FragDecoder.File, matrixDataTemp, li, FragDecoder.FragSize );
#endif
}
return FragDecoder.Status.FragNbLost;
}
else
{
//If not ( FragDecoder.FragNbLost > 1 )
return FragDecoder.Status.FragNbLost;
}
}
}
}
return FRAG_SESSION_ONGOING;
}
FragDecoderStatus_t FragDecoderGetStatus( void )
{
return FragDecoder.Status;
}
/*
*=============================================================================
* Fragmentation decoder algorithm utilities
*=============================================================================
*/
#if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 )
static void SetRow( uint8_t *src, uint16_t row, uint16_t size )
{
if( ( FragDecoder.Callbacks != NULL ) && ( FragDecoder.Callbacks->FragDecoderWrite != NULL ) )
{
FragDecoder.Callbacks->FragDecoderWrite( row * size, src, size );
}
}
static void GetRow( uint8_t *dst, uint16_t row, uint16_t size )
{
if( ( FragDecoder.Callbacks != NULL ) && ( FragDecoder.Callbacks->FragDecoderRead != NULL ) )
{
FragDecoder.Callbacks->FragDecoderRead( row * size, dst, size );
}
}
#else
static void SetRow( uint8_t *dst, uint8_t *src, uint16_t row, uint16_t size )
{
memcpy1( &dst[row * size], src, size );
}
static void GetRow( uint8_t *dst, uint8_t *src, uint16_t row, uint16_t size )
{
memcpy1( dst, &src[row * size], size );
}
#endif
static uint8_t GetParity( uint16_t index, uint8_t *matrixRow )
{
uint8_t parity;
parity = matrixRow[index >> 3];
parity = ( parity >> ( 7 - ( index % 8 ) ) ) & 0x01;
return parity;
}
static void SetParity( uint16_t index, uint8_t *matrixRow, uint8_t parity )
{
uint8_t mask = 0xFF - ( 1 << ( 7 - ( index % 8 ) ) );
parity = parity << ( 7 - ( index % 8 ) );
matrixRow[index >> 3] = ( matrixRow[index >> 3] & mask ) + parity;
}
static bool IsPowerOfTwo( uint32_t x )
{
uint8_t sumBit = 0;
for( uint8_t i = 0; i < 32; i++ )
{
sumBit += ( x & ( 1 << i ) ) >> i;
}
if( sumBit == 1 )
{
return true;
}
return false;
}
static void XorDataLine( uint8_t *line1, uint8_t *line2, int32_t size )
{
for( int32_t i = 0; i < size; i++ )
{
line1[i] = line1[i] ^ line2[i];
}
}
static void XorParityLine( uint8_t* line1, uint8_t* line2, int32_t size )
{
for( int32_t i = 0; i < size; i++ )
{
SetParity( i, line1, ( GetParity( i, line1 ) ^ GetParity( i, line2 ) ) );
}
}
static int32_t FragPrbs23( int32_t value )
{
int32_t b0 = value & 0x01;
int32_t b1 = ( value & 0x20 ) >> 5;
return ( value >> 1 ) + ( ( b0 ^ b1 ) << 22 );;
}
static void FragGetParityMatrixRow( int32_t n, int32_t m, uint8_t *matrixRow )
{
int32_t mTemp;
int32_t x;
int32_t nbCoeff = 0;
int32_t r;
if( IsPowerOfTwo( m ) != false )
{
mTemp = 1;
}
else
{
mTemp = 0;
}
x = 1 + ( 1001 * n );
for( uint8_t i = 0; i < ( ( m >> 3 ) + 1 ); i++ )
{
matrixRow[i] = 0;
}
while( nbCoeff < ( m >> 1 ) )
{
r = 1 << 16;
while( r >= m )
{
x = FragPrbs23( x );
r = x % ( m + mTemp );
}
SetParity( r, matrixRow, 1 );
nbCoeff += 1;
}
}
static uint16_t BitArrayFindFirstOne( uint8_t *bitArray, uint16_t size )
{
for( uint16_t i = 0; i < size; i++)
{
if ( GetParity( i, bitArray ) == 1 )
{
return i;
}
}
return 0;
}
static uint8_t BitArrayIsAllZeros( uint8_t *bitArray, uint16_t size )
{
for( uint16_t i = 0; i < size; i++ )
{
if( GetParity( i, bitArray ) == 1 )
{
return 0;
}
}
return 1;
}
/*!
* \brief Finds & marks missing fragments
*
* \param [IN] counter Current fragment counter
* \param [OUT] FragDecoder.FragNbMissingIndex[] array is updated in place
*/
static void FragFindMissingFrags( uint16_t counter )
{
int32_t i;
for( i = FragDecoder.Status.FragNbLastRx; i < ( counter - 1 ); i++ )
{
if( i < FragDecoder.FragNb )
{
FragDecoder.Status.FragNbLost++;
FragDecoder.FragNbMissingIndex[i] = FragDecoder.Status.FragNbLost;
}
}
if( i < FragDecoder.FragNb )
{
FragDecoder.Status.FragNbLastRx = counter;
}
else
{
FragDecoder.Status.FragNbLastRx = FragDecoder.FragNb + 1;
}
DBG( "RECEIVED : %5d / %5d Fragments\n", FragDecoder.Status.FragNbRx, FragDecoder.FragNb );
DBG( " %5d / %5d Bytes\n", FragDecoder.Status.FragNbRx * FragDecoder.FragSize, FragDecoder.FragNb * FragDecoder.FragSize );
DBG( "LOST : %7d Fragments\n\n", FragDecoder.Status.FragNbLost );
}
/*!
* \brief Finds the index (frag counter) of the x th missing frag
*
* \param [IN] x x th missing frag
*
* \retval counter The counter value associated to the x th missing frag
*/
static uint16_t FragFindMissingIndex( uint16_t x )
{
for( uint16_t i = 0; i < FragDecoder.FragNb; i++ )
{
if( FragDecoder.FragNbMissingIndex[i] == ( x + 1 ) )
{
return i;
}
}
return 0;
}
/*!
* \brief Extacts a row from the binary matrix and expands it to a bitArray
*
* \param [IN] bitArray Pointer to the bit array
* \param [IN] rowIndex Matrix row index
* \param [IN] bitsInRow Number of bits in one row
*/
static void FragExtractLineFromBinaryMatrix( uint8_t* bitArray, uint16_t rowIndex, uint16_t bitsInRow )
{
uint32_t findByte = 0;
uint32_t findBitInByte = 0;
if( rowIndex > 0 )
{
findByte = ( rowIndex * bitsInRow - ( ( rowIndex * ( rowIndex - 1 ) ) >> 1 ) ) >> 3;
findBitInByte = ( rowIndex * bitsInRow - ( ( rowIndex * ( rowIndex - 1 ) ) >> 1 ) ) % 8;
}
if( rowIndex > 0 )
{
for( uint16_t i = 0; i < rowIndex; i++ )
{
SetParity( i, bitArray, 0 );
}
}
for( uint16_t i = rowIndex; i < bitsInRow; i++ )
{
SetParity( i,
bitArray,
( FragDecoder.MatrixM2B[findByte] >> ( 7 - findBitInByte ) ) & 0x01 );
findBitInByte++;
if( findBitInByte == 8 )
{
findBitInByte = 0;
findByte++;
}
}
}
/*!
* \brief Collapses and Pushs a row of a bit array to the matrix
*
* \param [IN] bitArray Pointer to the bit array
* \param [IN] rowIndex Matrix row index
* \param [IN] bitsInRow Number of bits in one row
*/
static void FragPushLineToBinaryMatrix( uint8_t *bitArray, uint16_t rowIndex, uint16_t bitsInRow )
{
uint32_t findByte = 0;
uint32_t findBitInByte = 0;
if ( rowIndex > 0) {
findByte = ( rowIndex * bitsInRow - ( ( rowIndex * ( rowIndex - 1 ) ) >> 1 ) ) >> 3;
findBitInByte = ( rowIndex * bitsInRow - ( ( rowIndex * ( rowIndex - 1 ) ) >> 1 ) ) % 8;
}
for( uint16_t i = rowIndex; i < bitsInRow; i++ )
{
if( GetParity( i, bitArray ) == 0 )
{
FragDecoder.MatrixM2B[findByte] = FragDecoder.MatrixM2B[findByte] & ( 0xFF - ( 1 << ( 7 - findBitInByte ) ) );
}
findBitInByte++;
if( findBitInByte == 8 )
{
findBitInByte = 0;
findByte++;
}
}
}

View File

@@ -0,0 +1,143 @@
/*!
* \file FragDecoder.h
*
* \brief Implements the LoRa-Alliance fragmentation decoder
* Specification: https://lora-alliance.org/sites/default/files/2018-09/fragmented_data_block_transport_v1.0.0.pdf
*
* \copyright Revised BSD License, see section \ref LICENSE.
*
* \code
* ______ _
* / _____) _ | |
* ( (____ _____ ____ _| |_ _____ ____| |__
* \____ \| ___ | (_ _) ___ |/ ___) _ \
* _____) ) ____| | | || |_| ____( (___| | | |
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
* (C)2013-2018 Semtech
*
* \endcode
*
* \author Fabien Holin ( Semtech )
* \author Miguel Luis ( Semtech )
*/
#ifndef __FRAG_DECODER_H__
#define __FRAG_DECODER_H__
#include <stdint.h>
/*!
* If set to 1 the new API defining \ref FragDecoderWrite and
* \ref FragDecoderReadfunction callbacks is used.
*/
#define FRAG_DECODER_FILE_HANDLING_NEW_API 1
/*!
* Maximum number of fragment that can be handled.
*
* \remark This parameter has an impact on the memory footprint.
*/
#define FRAG_MAX_NB 21
/*!
* Maximum fragment size that can be handled.
*
* \remark This parameter has an impact on the memory footprint.
*/
#define FRAG_MAX_SIZE 50
/*!
* Maximum number of extra frames that can be handled.
*
* \remark This parameter has an impact on the memory footprint.
*/
#define FRAG_MAX_REDUNDANCY 5
#define FRAG_SESSION_FINISHED ( int32_t )0
#define FRAG_SESSION_NOT_STARTED ( int32_t )-2
#define FRAG_SESSION_ONGOING ( int32_t )-1
typedef struct sFragDecoderStatus
{
uint16_t FragNbRx;
uint16_t FragNbLost;
uint16_t FragNbLastRx;
uint8_t MatrixError;
}FragDecoderStatus_t;
#if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 )
typedef struct sFragDecoderCallbacks
{
/*!
* Writes `data` buffer of `size` starting at address `addr`
*
* \param [IN] addr Address start index to write to.
* \param [IN] data Data buffer to be written.
* \param [IN] size Size of data buffer to be written.
*
* \retval status Write operation status [0: Success, -1 Fail]
*/
uint8_t ( *FragDecoderWrite )( uint32_t addr, uint8_t *data, uint32_t size );
/*!
* Reads `data` buffer of `size` starting at address `addr`
*
* \param [IN] addr Address start index to read from.
* \param [IN] data Data buffer to be read.
* \param [IN] size Size of data buffer to be read.
*
* \retval status Read operation status [0: Success, -1 Fail]
*/
uint8_t ( *FragDecoderRead )( uint32_t addr, uint8_t *data, uint32_t size );
}FragDecoderCallbacks_t;
#endif
#if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 )
/*!
* \brief Initializes the fragmentation decoder
*
* \param [IN] fragNb Number of expected fragments (without redundancy packets)
* \param [IN] fragSize Size of a fragment
* \param [IN] callbacks Pointer to the Write/Read functions.
*/
void FragDecoderInit( uint16_t fragNb, uint8_t fragSize, FragDecoderCallbacks_t *callbacks );
#else
/*!
* \brief Initializes the fragmentation decoder
*
* \param [IN] fragNb Number of expected fragments (without redundancy packets)
* \param [IN] fragSize Size of a fragment
* \param [IN] file Pointer to file buffer size
* \param [IN] fileSize File buffer size
*/
void FragDecoderInit( uint16_t fragNb, uint8_t fragSize, uint8_t *file, uint32_t fileSize );
#endif
#if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 )
/*!
* \brief Gets the maximum file size that can be received
*
* \retval size FileSize
*/
uint32_t FragDecoderGetMaxFileSize( void );
#endif
/*!
* \brief Function to decode and reconstruct the binary file
* Called for each receive frame
*
* \param [IN] fragCounter Fragment counter [1..(FragDecoder.FragNb + FragDecoder.Redundancy)]
* \param [IN] rawData Pointer to the fragment to be processed (length = FragDecoder.FragSize)
*
* \retval status Process status. [FRAG_SESSION_ONGOING,
* FRAG_SESSION_FINISHED or
* FragDecoder.Status.FragNbLost]
*/
int32_t FragDecoderProcess( uint16_t fragCounter, uint8_t *rawData );
/*!
* \brief Gets the current fragmentation status
*
* \retval status Fragmentation decoder status
*/
FragDecoderStatus_t FragDecoderGetStatus( void );
#endif // __FRAG_DECODER_H__

View File

@@ -0,0 +1,156 @@
/*!
* \file LmPackage.h
*
* \brief Defines the packages API
*
* \copyright Revised BSD License, see section \ref LICENSE.
*
* \code
* ______ _
* / _____) _ | |
* ( (____ _____ ____ _| |_ _____ ____| |__
* \____ \| ___ | (_ _) ___ |/ ___) _ \
* _____) ) ____| | | || |_| ____( (___| | | |
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
* (C)2013-2018 Semtech
*
* \endcode
*
* \author Miguel Luis ( Semtech )
*/
#ifndef __LMH_PACKAGE_H__
#define __LMH_PACKAGE_H__
#include <stdint.h>
#include <stdbool.h>
#include "LmHandlerTypes.h"
/*!
* Maximum number of packages
*/
#define PKG_MAX_NUMBER 4
typedef struct LmhPackage_s
{
uint8_t Port;
/*
*=========================================================================
* Below callbacks must be initialized in package variable declaration
*=========================================================================
*/
/*!
* Initializes the package with provided parameters
*
* \param [IN] params Pointer to the package parameters
* \param [IN] dataBuffer Pointer to main application buffer
* \param [IN] dataBufferMaxSize Main application buffer maximum size
*/
void ( *Init )( void *params, uint8_t *dataBuffer, uint8_t dataBufferMaxSize );
/*!
* Returns the current package initialization status.
*
* \retval status Package initialization status
* [true: Initialized, false: Not initialized]
*/
bool ( *IsInitialized )( void );
/*!
* Returns the package operation status.
*
* \retval status Package operation status
* [true: Running, false: Not running]
*/
bool ( *IsRunning )( void );
/*!
* Processes the internal package events.
*/
void ( *Process )( void );
/*!
* Processes the MCSP Confirm
*
* \param [IN] mcpsConfirm MCPS confirmation primitive data
*/
void ( *OnMcpsConfirmProcess )( McpsConfirm_t *mcpsConfirm );
/*!
* Processes the MCPS Indication
*
* \param [IN] mcpsIndication MCPS indication primitive data
*/
void ( *OnMcpsIndicationProcess )( McpsIndication_t *mcpsIndication );
/*!
* Processes the MLME Confirm
*
* \param [IN] mlmeConfirm MLME confirmation primitive data
*/
void ( *OnMlmeConfirmProcess )( MlmeConfirm_t *mlmeConfirm );
/*!
* Processes the MLME Indication
*
* \param [IN] mlmeIndication MLME indication primitive data
*/
void ( *OnMlmeIndicationProcess )( MlmeIndication_t *mlmeIndication );
/*
*=========================================================================
* Below callbacks must be initialized in LmHandler initialization with
* provideded LmHandlerSend and OnMacRequest functions
*=========================================================================
*/
/*!
* Notifies the upper layer that a MCPS request has been made to the MAC layer
*
* \param [IN] status - Request returned status
* \param [IN] mcpsRequest - Performed MCPS-Request. Refer to \ref McpsReq_t.
* \param [IN] nextTxDelay - Time to wait until another TX is possible.
*/
void ( *OnMacMcpsRequest )( LoRaMacStatus_t status, McpsReq_t *mcpsReq, TimerTime_t nextTxDelay );
/*!
* Notifies the upper layer that a MLME request has been made to the MAC layer
*
* \param [IN] status - Request returned status
* \param [IN] mlmeRequest - Performed MLME-Request. Refer to \ref MlmeReq_t.
* \param [IN] nextTxDelay - Time to wait until another TX is possible.
*/
void ( *OnMacMlmeRequest )( LoRaMacStatus_t status, MlmeReq_t *mlmeReq, TimerTime_t nextTxDelay );
/*!
* Join a LoRa Network in classA
*
* \Note if the device is ABP, this is a pass through function
*
* \param [IN] isOtaa Indicates which activation mode must be used
*/
void ( *OnJoinRequest )( bool isOtaa );
/*!
* Instructs the MAC layer to send a ClassA uplink
*
* \param [IN] appData Data to be sent
* \param [IN] isTxConfirmed Indicates if the uplink requires an acknowledgement
*
* \retval status Returns \ref LORAMAC_HANDLER_SUCCESS if request has been
* processed else \ref LORAMAC_HANDLER_ERROR
*/
LmHandlerErrorStatus_t ( *OnSendRequest )( LmHandlerAppData_t *appData, LmHandlerMsgTypes_t isTxConfirmed );
/*!
* Requests network server time update
*
* \retval status Returns \ref LORAMAC_HANDLER_SET if joined else \ref LORAMAC_HANDLER_RESET
*/
LmHandlerErrorStatus_t ( *OnDeviceTimeRequest )( void );
#if( LMH_SYS_TIME_UPDATE_NEW_API == 1 )
/*!
* Notifies the upper layer that the system time has been updated.
*
* \param [in] isSynchronized Indicates if the system time is synchronized in the range +/-1 second
* \param [in] timeCorrection Received time correction value
*/
void ( *OnSysTimeUpdate )( bool isSynchronized, int32_t timeCorrection );
#else
/*!
* Notifies the upper layer that the system time has been updated.
*/
void ( *OnSysTimeUpdate )( void );
#endif
}LmhPackage_t;
#endif // __LMH_PACKAGE_H__

View File

@@ -0,0 +1,375 @@
/*!
* \file LmhpClockSync.c
*
* \brief Implements the LoRa-Alliance clock synchronization package
* Specification: https://lora-alliance.org/sites/default/files/2018-09/application_layer_clock_synchronization_v1.0.0.pdf
*
* \copyright Revised BSD License, see section \ref LICENSE.
*
* \code
* ______ _
* / _____) _ | |
* ( (____ _____ ____ _| |_ _____ ____| |__
* \____ \| ___ | (_ _) ___ |/ ___) _ \
* _____) ) ____| | | || |_| ____( (___| | | |
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
* (C)2013-2018 Semtech
*
* \endcode
*
* \author Miguel Luis ( Semtech )
*/
#include "systime.h"
#include "LmHandler.h"
#include "LmhpClockSync.h"
/*!
* LoRaWAN Application Layer Clock Synchronization Specification
*/
#define CLOCK_SYNC_PORT 202
#define CLOCK_SYNC_ID 1
#define CLOCK_SYNC_VERSION 1
/*!
* Package current context
*/
typedef struct LmhpClockSyncState_s
{
bool Initialized;
bool IsRunning;
uint8_t DataBufferMaxSize;
uint8_t *DataBuffer;
union
{
uint8_t Value;
struct
{
uint8_t TokenReq: 4;
uint8_t AnsRequired: 1;
uint8_t RFU: 3;
}Fields;
}TimeReqParam;
bool AppTimeReqPending;
bool AdrEnabledPrev;
uint8_t NbTransPrev;
uint8_t DataratePrev;
uint8_t NbTransmissions;
}LmhpClockSyncState_t;
typedef enum LmhpClockSyncMoteCmd_e
{
CLOCK_SYNC_PKG_VERSION_ANS = 0x00,
CLOCK_SYNC_APP_TIME_REQ = 0x01,
CLOCK_SYNC_APP_TIME_PERIOD_ANS = 0x02,
CLOCK_SYNC_FORCE_RESYNC_ANS = 0x03,
}LmhpClockSyncMoteCmd_t;
typedef enum LmhpClockSyncSrvCmd_e
{
CLOCK_SYNC_PKG_VERSION_REQ = 0x00,
CLOCK_SYNC_APP_TIME_ANS = 0x01,
CLOCK_SYNC_APP_TIME_PERIOD_REQ = 0x02,
CLOCK_SYNC_FORCE_RESYNC_REQ = 0x03,
}LmhpClockSyncSrvCmd_t;
/*!
* Initializes the package with provided parameters
*
* \param [IN] params Pointer to the package parameters
* \param [IN] dataBuffer Pointer to main application buffer
* \param [IN] dataBufferMaxSize Main application buffer maximum size
*/
static void LmhpClockSyncInit( void *params, uint8_t *dataBuffer, uint8_t dataBufferMaxSize );
/*!
* Returns the current package initialization status.
*
* \retval status Package initialization status
* [true: Initialized, false: Not initialized]
*/
static bool LmhpClockSyncIsInitialized( void );
/*!
* Returns the package operation status.
*
* \retval status Package operation status
* [true: Running, false: Not running]
*/
static bool LmhpClockSyncIsRunning( void );
/*!
* Processes the internal package events.
*/
static void LmhpClockSyncProcess( void );
/*!
* Processes the MCSP Confirm
*
* \param [IN] mcpsConfirm MCPS confirmation primitive data
*/
static void LmhpClockSyncOnMcpsConfirm( McpsConfirm_t *mcpsConfirm );
/*!
* Processes the MCPS Indication
*
* \param [IN] mcpsIndication MCPS indication primitive data
*/
static void LmhpClockSyncOnMcpsIndication( McpsIndication_t *mcpsIndication );
static LmhpClockSyncState_t LmhpClockSyncState =
{
.Initialized = false,
.IsRunning = false,
.TimeReqParam.Value = 0,
.AppTimeReqPending = false,
.AdrEnabledPrev = false,
.NbTransPrev = 0,
.NbTransmissions = 0,
};
static LmhPackage_t LmhpClockSyncPackage =
{
.Port = CLOCK_SYNC_PORT,
.Init = LmhpClockSyncInit,
.IsInitialized = LmhpClockSyncIsInitialized,
.IsRunning = LmhpClockSyncIsRunning,
.Process = LmhpClockSyncProcess,
.OnMcpsConfirmProcess = LmhpClockSyncOnMcpsConfirm,
.OnMcpsIndicationProcess = LmhpClockSyncOnMcpsIndication,
.OnMlmeConfirmProcess = NULL, // Not used in this package
.OnMlmeIndicationProcess = NULL, // Not used in this package
.OnMacMcpsRequest = NULL, // To be initialized by LmHandler
.OnMacMlmeRequest = NULL, // To be initialized by LmHandler
.OnJoinRequest = NULL, // To be initialized by LmHandler
.OnSendRequest = NULL, // To be initialized by LmHandler
.OnDeviceTimeRequest = NULL, // To be initialized by LmHandler
.OnSysTimeUpdate = NULL, // To be initialized by LmHandler
};
LmhPackage_t *LmphClockSyncPackageFactory( void )
{
return &LmhpClockSyncPackage;
}
static void LmhpClockSyncInit( void * params, uint8_t *dataBuffer, uint8_t dataBufferMaxSize )
{
if( dataBuffer != NULL )
{
LmhpClockSyncState.DataBuffer = dataBuffer;
LmhpClockSyncState.DataBufferMaxSize = dataBufferMaxSize;
LmhpClockSyncState.Initialized = true;
LmhpClockSyncState.IsRunning = true;
}
else
{
LmhpClockSyncState.IsRunning = false;
LmhpClockSyncState.Initialized = false;
}
}
static bool LmhpClockSyncIsInitialized( void )
{
return LmhpClockSyncState.Initialized;
}
static bool LmhpClockSyncIsRunning( void )
{
if( LmhpClockSyncState.Initialized == false )
{
return false;
}
return LmhpClockSyncState.IsRunning;
}
static void LmhpClockSyncProcess( void )
{
if( LmhpClockSyncState.NbTransmissions > 0 )
{
if( LmhpClockSyncAppTimeReq( ) == LORAMAC_HANDLER_SUCCESS )
{
LmhpClockSyncState.NbTransmissions--;
}
}
}
static void LmhpClockSyncOnMcpsConfirm( McpsConfirm_t *mcpsConfirm )
{
MibRequestConfirm_t mibReq;
if( LmhpClockSyncState.AppTimeReqPending == true )
{
// Revert ADR setting
mibReq.Type = MIB_ADR;
mibReq.Param.AdrEnable = LmhpClockSyncState.AdrEnabledPrev;
LoRaMacMibSetRequestConfirm( &mibReq );
// Revert NbTrans setting
mibReq.Type = MIB_CHANNELS_NB_TRANS;
mibReq.Param.ChannelsNbTrans = LmhpClockSyncState.NbTransPrev;
LoRaMacMibSetRequestConfirm( &mibReq );
// Revert data rate setting
mibReq.Type = MIB_CHANNELS_DATARATE;
mibReq.Param.ChannelsDatarate = LmhpClockSyncState.DataratePrev;
LoRaMacMibSetRequestConfirm( &mibReq );
LmhpClockSyncState.AppTimeReqPending = false;
}
}
static void LmhpClockSyncOnMcpsIndication( McpsIndication_t *mcpsIndication )
{
uint8_t cmdIndex = 0;
uint8_t dataBufferIndex = 0;
while( cmdIndex < mcpsIndication->BufferSize )
{
switch( mcpsIndication->Buffer[cmdIndex++] )
{
case CLOCK_SYNC_PKG_VERSION_REQ:
{
LmhpClockSyncState.DataBuffer[dataBufferIndex++] = CLOCK_SYNC_PKG_VERSION_ANS;
LmhpClockSyncState.DataBuffer[dataBufferIndex++] = CLOCK_SYNC_ID;
LmhpClockSyncState.DataBuffer[dataBufferIndex++] = CLOCK_SYNC_VERSION;
break;
}
case CLOCK_SYNC_APP_TIME_ANS:
{
LmhpClockSyncState.NbTransmissions = 0;
// Check if a more precise time correction has been received.
// If yes then don't process and ignore this answer.
if( mcpsIndication->DeviceTimeAnsReceived == true )
{
cmdIndex += 5;
break;
}
int32_t timeCorrection = 0;
timeCorrection = ( mcpsIndication->Buffer[cmdIndex++] << 0 ) & 0x000000FF;
timeCorrection += ( mcpsIndication->Buffer[cmdIndex++] << 8 ) & 0x0000FF00;
timeCorrection += ( mcpsIndication->Buffer[cmdIndex++] << 16 ) & 0x00FF0000;
timeCorrection += ( mcpsIndication->Buffer[cmdIndex++] << 24 ) & 0xFF000000;
if( ( mcpsIndication->Buffer[cmdIndex++] & 0x0F ) == LmhpClockSyncState.TimeReqParam.Fields.TokenReq )
{
SysTime_t curTime = { .Seconds = 0, .SubSeconds = 0 };
curTime = SysTimeGet( );
curTime.Seconds += timeCorrection;
SysTimeSet( curTime );
LmhpClockSyncState.TimeReqParam.Fields.TokenReq = ( LmhpClockSyncState.TimeReqParam.Fields.TokenReq + 1 ) & 0x0F;
if( LmhpClockSyncPackage.OnSysTimeUpdate != NULL )
{
#if( LMH_SYS_TIME_UPDATE_NEW_API == 1 )
LmhpClockSyncPackage.OnSysTimeUpdate(
( timeCorrection >= -1 ) && ( timeCorrection <= 1 ),
timeCorrection );
#else
if( ( timeCorrection >= -1 ) && ( timeCorrection <= 1 ) )
{
LmhpClockSyncPackage.OnSysTimeUpdate( );
}
#endif
}
}
break;
}
case CLOCK_SYNC_APP_TIME_PERIOD_REQ:
{
// Increment index
cmdIndex++;
// TODO implement command prosessing and handling
LmhpClockSyncState.DataBuffer[dataBufferIndex++] = CLOCK_SYNC_APP_TIME_PERIOD_ANS;
// Answer status not supported.
LmhpClockSyncState.DataBuffer[dataBufferIndex++] = 0x01;
SysTime_t curTime = SysTimeGet( );
// Substract Unix to Gps epcoh offset. The system time is based on Unix time.
curTime.Seconds -= UNIX_GPS_EPOCH_OFFSET;
LmhpClockSyncState.DataBuffer[dataBufferIndex++] = ( curTime.Seconds >> 0 ) & 0xFF;
LmhpClockSyncState.DataBuffer[dataBufferIndex++] = ( curTime.Seconds >> 8 ) & 0xFF;
LmhpClockSyncState.DataBuffer[dataBufferIndex++] = ( curTime.Seconds >> 16 ) & 0xFF;
LmhpClockSyncState.DataBuffer[dataBufferIndex++] = ( curTime.Seconds >> 24 ) & 0xFF;
break;
}
case CLOCK_SYNC_FORCE_RESYNC_REQ:
{
LmhpClockSyncState.NbTransmissions = mcpsIndication->Buffer[cmdIndex++] & 0X07;
break;
}
}
}
if( dataBufferIndex != 0 )
{
// Answer commands
LmHandlerAppData_t appData =
{
.Buffer = LmhpClockSyncState.DataBuffer,
.BufferSize = dataBufferIndex,
.Port = CLOCK_SYNC_PORT
};
LmhpClockSyncPackage.OnSendRequest( &appData, LORAMAC_HANDLER_UNCONFIRMED_MSG );
}
}
LmHandlerErrorStatus_t LmhpClockSyncAppTimeReq( void )
{
if( LmHandlerIsBusy( ) == true )
{
return LORAMAC_HANDLER_ERROR;
}
if( LmhpClockSyncState.AppTimeReqPending == false )
{
MibRequestConfirm_t mibReq;
// Disable ADR
mibReq.Type = MIB_ADR;
LoRaMacMibGetRequestConfirm( &mibReq );
LmhpClockSyncState.AdrEnabledPrev = mibReq.Param.AdrEnable;
mibReq.Param.AdrEnable = false;
LoRaMacMibSetRequestConfirm( &mibReq );
// Set NbTrans = 1
mibReq.Type = MIB_CHANNELS_NB_TRANS;
LoRaMacMibGetRequestConfirm( &mibReq );
LmhpClockSyncState.NbTransPrev = mibReq.Param.ChannelsNbTrans;
mibReq.Param.ChannelsNbTrans = 1;
LoRaMacMibSetRequestConfirm( &mibReq );
// Store data rate
mibReq.Type = MIB_CHANNELS_DATARATE;
LoRaMacMibGetRequestConfirm( &mibReq );
LmhpClockSyncState.DataratePrev = mibReq.Param.ChannelsDatarate;
// Add DeviceTimeReq MAC command.
// In case the network server supports this more precise command
// this package will use DeviceTimeAns answer as clock synchronization
// mechanism.
LmhpClockSyncPackage.OnDeviceTimeRequest( );
}
SysTime_t curTime = SysTimeGet( );
uint8_t dataBufferIndex = 0;
// Substract Unix to Gps epcoh offset. The system time is based on Unix time.
curTime.Seconds -= UNIX_GPS_EPOCH_OFFSET;
LmhpClockSyncState.DataBuffer[dataBufferIndex++] = CLOCK_SYNC_APP_TIME_REQ;
LmhpClockSyncState.DataBuffer[dataBufferIndex++] = ( curTime.Seconds >> 0 ) & 0xFF;
LmhpClockSyncState.DataBuffer[dataBufferIndex++] = ( curTime.Seconds >> 8 ) & 0xFF;
LmhpClockSyncState.DataBuffer[dataBufferIndex++] = ( curTime.Seconds >> 16 ) & 0xFF;
LmhpClockSyncState.DataBuffer[dataBufferIndex++] = ( curTime.Seconds >> 24 ) & 0xFF;
LmhpClockSyncState.TimeReqParam.Fields.AnsRequired = 0;
LmhpClockSyncState.DataBuffer[dataBufferIndex++] = LmhpClockSyncState.TimeReqParam.Value;
LmHandlerAppData_t appData =
{
.Buffer = LmhpClockSyncState.DataBuffer,
.BufferSize = dataBufferIndex,
.Port = CLOCK_SYNC_PORT
};
LmhpClockSyncState.AppTimeReqPending = true;
return LmhpClockSyncPackage.OnSendRequest( &appData, LORAMAC_HANDLER_UNCONFIRMED_MSG );
}

View File

@@ -0,0 +1,49 @@
/*!
* \file LmhpClockSync.h
*
* \brief Implements the LoRa-Alliance clock synchronization package
* Specification: https://lora-alliance.org/sites/default/files/2018-09/application_layer_clock_synchronization_v1.0.0.pdf
*
* \copyright Revised BSD License, see section \ref LICENSE.
*
* \code
* ______ _
* / _____) _ | |
* ( (____ _____ ____ _| |_ _____ ____| |__
* \____ \| ___ | (_ _) ___ |/ ___) _ \
* _____) ) ____| | | || |_| ____( (___| | | |
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
* (C)2013-2018 Semtech
*
* \endcode
*
* \author Miguel Luis ( Semtech )
*/
#ifndef __LMHP_CLOCK_SYNC_H__
#define __LMHP_CLOCK_SYNC_H__
#include "LoRaMac.h"
#include "LmHandlerTypes.h"
#include "LmhPackage.h"
/*!
* Clock sync package identifier.
*
* \remark This value must be unique amongst the packages
*/
#define PACKAGE_ID_CLOCK_SYNC 1
/*!
* Clock sync package parameters
*
* This package doesn't require parameters
*/
//typedef struct LmphClockSyncParams_s
//{
//}LmphClockSyncParams_t;
LmhPackage_t *LmphClockSyncPackageFactory( void );
LmHandlerErrorStatus_t LmhpClockSyncAppTimeReq( void );
#endif // __LMHP_CLOCK_SYNC_H__

View File

@@ -0,0 +1,491 @@
/*!
* \file LmhpCompliance.c
*
* \brief Implements the LoRa-Alliance certification protocol handling
*
* \copyright Revised BSD License, see section \ref LICENSE.
*
* \code
* ______ _
* / _____) _ | |
* ( (____ _____ ____ _| |_ _____ ____| |__
* \____ \| ___ | (_ _) ___ |/ ___) _ \
* _____) ) ____| | | || |_| ____( (___| | | |
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
* (C)2013-2018 Semtech
*
* \endcode
*
* \author Miguel Luis ( Semtech )
*/
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include "utilities.h"
#include "timer.h"
#include "LoRaMac.h"
#include "LoRaMacTest.h"
#include "Region.h"
#include "LmhPackage.h"
#include "LmhpCompliance.h"
/*!
* LoRaWAN compliance certification protocol port number.
*
* LoRaWAN Specification V1.0.2, chapter 4.3.2
*/
#define COMPLIANCE_PORT 224
/*!
* Defines the compliance mode data transmission duty cycle.
* An uplink will be transmitted ever \ref COMPLIANCE_TX_DUTYCYCLE [ms].
*/
#define COMPLIANCE_TX_DUTYCYCLE 5000
/*!
* LoRaWAN compliance tests support data
*/
typedef struct ComplianceTestState_s
{
bool Initialized;
bool IsRunning;
uint8_t State;
bool TxPending;
bool IsTxConfirmed;
uint8_t Port;
uint8_t DataBufferMaxSize;
uint8_t DataBufferSize;
uint8_t *DataBuffer;
uint16_t DownLinkCounter;
bool LinkCheck;
uint8_t DemodMargin;
uint8_t NbGateways;
}ComplianceTestState_t;
/*!
* Timer to handle the application data transmission duty cycle
*/
static TimerEvent_t ComplianceTxNextPacketTimer;
/*!
* Holds the compliance test current context
*/
static ComplianceTestState_t ComplianceTestState =
{
.Initialized = false,
.IsRunning = false,
.State = 0,
.TxPending = false,
.IsTxConfirmed = false,
.Port = 0,
.DataBufferMaxSize = 0,
.DataBufferSize = 0,
.DataBuffer = NULL,
.DownLinkCounter = 0,
.LinkCheck = false,
.DemodMargin = 0,
.NbGateways = 0
};
/*!
* LoRaWAN compliance tests protocol handler parameters
*/
static LmhpComplianceParams_t* LmhpComplianceParams;
/*!
* Initializes the compliance tests with provided parameters
*
* \param [IN] params Structure containing the initial compliance
* tests parameters.
* \param [IN] dataBuffer Pointer to main application buffer
* \param [IN] dataBufferMaxSize Application buffer maximum size
*/
static void LmhpComplianceInit( void *params, uint8_t *dataBuffer, uint8_t dataBufferMaxSize );
/*!
* Returns the current compliance certification protocol initialization status.
*
* \retval status Compliance certification protocol initialization status
* [true: Initialized, false: Not initialized]
*/
static bool LmhpComplianceIsInitialized( void );
/*!
* Returns the current compliance certification protocol handling status.
*
* \retval status Compliance certification protocol handling status
* [true: Running, false: Not running]
*/
static bool LmhpComplianceIsRunning( void );
/*!
* Processes the LoRaMac Compliance events.
*/
static void LmhpComplianceProcess( void );
/*!
* Processes the MCPS Indication
*
* \param [IN] mcpsIndication MCPS indication primitive data
*/
static void LmhpComplianceOnMcpsIndication( McpsIndication_t *mcpsIndication );
/*!
* Processes the MLME Confirm
*
* \param [IN] mlmeConfirm MLME confirmation primitive data
*/
static void LmhpComplianceOnMlmeConfirm( MlmeConfirm_t *mlmeConfirm );
/*!
* Function executed on TxNextPacket Timeout event
*/
static void OnComplianceTxNextPacketTimerEvent( void *context );
/*!
* Processes the data to transmit on port \ref COMPLIANCE_PORT
* Handles the compliance certification protocol data transmission
*
* \retval status Returns \ref LORAMAC_HANDLER_SUCCESS if request has been
* processed else \ref LORAMAC_HANDLER_ERROR
*/
static LmHandlerErrorStatus_t LmhpComplianceTxProcess( void );
LmhPackage_t LmhpCompliancePackage =
{
.Port = COMPLIANCE_PORT,
.Init = LmhpComplianceInit,
.IsInitialized = LmhpComplianceIsInitialized,
.IsRunning = LmhpComplianceIsRunning,
.Process = LmhpComplianceProcess,
.OnMcpsConfirmProcess = NULL, // Not used in this package
.OnMcpsIndicationProcess = LmhpComplianceOnMcpsIndication,
.OnMlmeConfirmProcess = LmhpComplianceOnMlmeConfirm,
.OnMlmeIndicationProcess = NULL, // Not used in this package
.OnMacMcpsRequest = NULL, // To be initialized by LmHandler
.OnMacMlmeRequest = NULL, // To be initialized by LmHandler
.OnJoinRequest = NULL, // To be initialized by LmHandler
.OnSendRequest = NULL, // To be initialized by LmHandler
.OnDeviceTimeRequest = NULL, // To be initialized by LmHandler
.OnSysTimeUpdate = NULL, // To be initialized by LmHandler
};
LmhPackage_t *LmphCompliancePackageFactory( void )
{
return &LmhpCompliancePackage;
}
static void LmhpComplianceInit( void *params, uint8_t *dataBuffer, uint8_t dataBufferMaxSize )
{
if( ( params != NULL ) && ( dataBuffer != NULL ) )
{
LmhpComplianceParams = ( LmhpComplianceParams_t* )params;
ComplianceTestState.DataBuffer = dataBuffer;
ComplianceTestState.DataBufferMaxSize = dataBufferMaxSize;
ComplianceTestState.Initialized = true;
}
else
{
LmhpComplianceParams = NULL;
ComplianceTestState.Initialized = false;
}
}
static bool LmhpComplianceIsInitialized( void )
{
return ComplianceTestState.Initialized;
}
static bool LmhpComplianceIsRunning( void )
{
if( ComplianceTestState.Initialized == false )
{
return false;
}
return ComplianceTestState.IsRunning;
}
static void LmhpComplianceOnMlmeConfirm( MlmeConfirm_t *mlmeConfirm )
{
if( ComplianceTestState.Initialized == false )
{
return;
}
if( mlmeConfirm->MlmeRequest == MLME_LINK_CHECK )
{
ComplianceTestState.LinkCheck = true;
ComplianceTestState.DemodMargin = mlmeConfirm->DemodMargin;
ComplianceTestState.NbGateways = mlmeConfirm->NbGateways;
}
}
static LmHandlerErrorStatus_t LmhpComplianceTxProcess( void )
{
if( ComplianceTestState.Initialized == false )
{
return LORAMAC_HANDLER_ERROR;
}
if( ComplianceTestState.LinkCheck == true )
{
ComplianceTestState.LinkCheck = false;
ComplianceTestState.DataBufferSize = 3;
ComplianceTestState.DataBuffer[0] = 5;
ComplianceTestState.DataBuffer[1] = ComplianceTestState.DemodMargin;
ComplianceTestState.DataBuffer[2] = ComplianceTestState.NbGateways;
ComplianceTestState.State = 1;
}
else
{
switch( ComplianceTestState.State )
{
case 4:
ComplianceTestState.State = 1;
break;
case 1:
ComplianceTestState.DataBufferSize = 2;
ComplianceTestState.DataBuffer[0] = ComplianceTestState.DownLinkCounter >> 8;
ComplianceTestState.DataBuffer[1] = ComplianceTestState.DownLinkCounter;
break;
}
}
LmHandlerAppData_t appData =
{
.Buffer = ComplianceTestState.DataBuffer,
.BufferSize = ComplianceTestState.DataBufferSize,
.Port = COMPLIANCE_PORT
};
// Schedule next transmission
TimerStart( &ComplianceTxNextPacketTimer );
return LmhpCompliancePackage.OnSendRequest( &appData, ( LmHandlerMsgTypes_t )ComplianceTestState.IsTxConfirmed );
}
static void LmhpComplianceOnMcpsIndication( McpsIndication_t* mcpsIndication )
{
if( ComplianceTestState.Initialized == false )
{
return;
}
if( mcpsIndication->RxData == false )
{
return;
}
if( mcpsIndication->Port != COMPLIANCE_PORT )
{
return;
}
if( ComplianceTestState.IsRunning == false )
{
// Check compliance test enable command (i)
if( ( mcpsIndication->BufferSize == 4 ) &&
( mcpsIndication->Buffer[0] == 0x01 ) &&
( mcpsIndication->Buffer[1] == 0x01 ) &&
( mcpsIndication->Buffer[2] == 0x01 ) &&
( mcpsIndication->Buffer[3] == 0x01 ) )
{
MibRequestConfirm_t mibReq;
// Initialize compliance test mode context
ComplianceTestState.IsTxConfirmed = false;
ComplianceTestState.TxPending = false;
ComplianceTestState.Port = 224;
ComplianceTestState.DataBufferSize = 2;
ComplianceTestState.DownLinkCounter = 0;
ComplianceTestState.LinkCheck = false;
ComplianceTestState.DemodMargin = 0;
ComplianceTestState.NbGateways = 0;
ComplianceTestState.IsRunning = true;
ComplianceTestState.State = 1;
// Enable ADR while in compliance test mode
mibReq.Type = MIB_ADR;
mibReq.Param.AdrEnable = true;
LoRaMacMibSetRequestConfirm( &mibReq );
// Disable duty cycle enforcement while in compliance test mode
LoRaMacTestSetDutyCycleOn( false );
// Stop peripherals
if( LmhpComplianceParams->StopPeripherals != NULL )
{
LmhpComplianceParams->StopPeripherals( );
}
// Initialize compliance protocol transmission timer
TimerInit( &ComplianceTxNextPacketTimer, OnComplianceTxNextPacketTimerEvent );
TimerSetValue( &ComplianceTxNextPacketTimer, COMPLIANCE_TX_DUTYCYCLE );
// Confirm compliance test protocol activation
CRITICAL_SECTION_BEGIN( );
ComplianceTestState.TxPending = true; //LmhpComplianceTxProcess( );
CRITICAL_SECTION_END( );
}
}
else
{
// Increment the compliance certification protocol downlink counter
ComplianceTestState.DownLinkCounter++;
// Parse compliance test protocol
ComplianceTestState.State = mcpsIndication->Buffer[0];
switch( ComplianceTestState.State )
{
case 0: // Check compliance test disable command (ii)
{
MibRequestConfirm_t mibReq;
TimerStop( &ComplianceTxNextPacketTimer );
// Disable compliance test mode and reset the downlink counter.
ComplianceTestState.DownLinkCounter = 0;
ComplianceTestState.IsRunning = false;
// Restore previous ADR seeting
mibReq.Type = MIB_ADR;
mibReq.Param.AdrEnable = LmhpComplianceParams->AdrEnabled;
LoRaMacMibSetRequestConfirm( &mibReq );
// Enable duty cycle enforcement
LoRaMacTestSetDutyCycleOn( LmhpComplianceParams->DutyCycleEnabled );
// Restart peripherals
if( LmhpComplianceParams->StartPeripherals != NULL )
{
LmhpComplianceParams->StartPeripherals( );
}
}
break;
case 1: // (iii, iv)
ComplianceTestState.DataBufferSize = 2;
break;
case 2: // Enable confirmed messages (v)
ComplianceTestState.IsTxConfirmed = true;
ComplianceTestState.State = 1;
break;
case 3: // Disable confirmed messages (vi)
ComplianceTestState.IsTxConfirmed = false;
ComplianceTestState.State = 1;
break;
case 4: // (vii)
ComplianceTestState.DataBufferSize = mcpsIndication->BufferSize;
ComplianceTestState.DataBuffer[0] = 4;
for( uint8_t i = 1; i < MIN( ComplianceTestState.DataBufferSize, ComplianceTestState.DataBufferMaxSize ); i++ )
{
ComplianceTestState.DataBuffer[i] = mcpsIndication->Buffer[i] + 1;
}
break;
case 5: // (viii)
{
MlmeReq_t mlmeReq;
mlmeReq.Type = MLME_LINK_CHECK;
LmhpCompliancePackage.OnMacMlmeRequest( LoRaMacMlmeRequest( &mlmeReq ), &mlmeReq, 0 );
}
break;
case 6: // (ix)
{
MibRequestConfirm_t mibReq;
// Disable TestMode and revert back to normal operation
// Disable compliance test mode and reset the downlink counter.
ComplianceTestState.DownLinkCounter = 0;
ComplianceTestState.IsRunning = false;
// Restore previous ADR seeting
mibReq.Type = MIB_ADR;
mibReq.Param.AdrEnable = LmhpComplianceParams->AdrEnabled;
LoRaMacMibSetRequestConfirm( &mibReq );
// Enable duty cycle enforcement
LoRaMacTestSetDutyCycleOn( LmhpComplianceParams->DutyCycleEnabled );
// Restart peripherals
if( LmhpComplianceParams->StartPeripherals != NULL )
{
LmhpComplianceParams->StartPeripherals( );
}
LmhpCompliancePackage.OnJoinRequest( true );
}
break;
case 7: // (x)
{
MlmeReq_t mlmeReq;
if( mcpsIndication->BufferSize == 3 )
{
mlmeReq.Type = MLME_TXCW;
mlmeReq.Req.TxCw.Timeout = ( uint16_t )( ( mcpsIndication->Buffer[1] << 8 ) | mcpsIndication->Buffer[2] );
}
else if( mcpsIndication->BufferSize == 7 )
{
mlmeReq.Type = MLME_TXCW_1;
mlmeReq.Req.TxCw.Timeout = ( uint16_t )( ( mcpsIndication->Buffer[1] << 8 ) | mcpsIndication->Buffer[2] );
mlmeReq.Req.TxCw.Frequency = ( uint32_t )( ( mcpsIndication->Buffer[3] << 16 ) | ( mcpsIndication->Buffer[4] << 8 ) | mcpsIndication->Buffer[5] ) * 100;
mlmeReq.Req.TxCw.Power = mcpsIndication->Buffer[6];
}
LmhpCompliancePackage.OnMacMlmeRequest( LoRaMacMlmeRequest( &mlmeReq ), &mlmeReq, 0 );
ComplianceTestState.State = 1;
}
break;
case 8: // Send DeviceTimeReq
{
MlmeReq_t mlmeReq;
mlmeReq.Type = MLME_DEVICE_TIME;
LmhpCompliancePackage.OnMacMlmeRequest( LoRaMacMlmeRequest( &mlmeReq ), &mlmeReq, 0 );
}
break;
case 9: // Switch end device Class
{
MibRequestConfirm_t mibReq;
mibReq.Type = MIB_DEVICE_CLASS;
// CLASS_A = 0, CLASS_B = 1, CLASS_C = 2
mibReq.Param.Class = ( DeviceClass_t )mcpsIndication->Buffer[1];;
LoRaMacMibSetRequestConfirm( &mibReq );
}
break;
case 10: // Send PingSlotInfoReq
{
MlmeReq_t mlmeReq;
mlmeReq.Type = MLME_PING_SLOT_INFO;
mlmeReq.Req.PingSlotInfo.PingSlot.Value = mcpsIndication->Buffer[1];
LmhpCompliancePackage.OnMacMlmeRequest( LoRaMacMlmeRequest( &mlmeReq ), &mlmeReq, 0 );
}
break;
default:
break;
}
}
}
static void LmhpComplianceProcess( void )
{
bool isPending;
CRITICAL_SECTION_BEGIN( );
isPending = ComplianceTestState.TxPending;
ComplianceTestState.TxPending = false;
CRITICAL_SECTION_END( );
if( isPending == true )
{
LmhpComplianceTxProcess( );
}
}
static void OnComplianceTxNextPacketTimerEvent( void* context )
{
ComplianceTestState.TxPending = true;
}

View File

@@ -0,0 +1,68 @@
/*!
* \file LmhpCompliance.h
*
* \brief Implements the LoRa-Alliance certification protocol handling
*
* \copyright Revised BSD License, see section \ref LICENSE.
*
* \code
* ______ _
* / _____) _ | |
* ( (____ _____ ____ _| |_ _____ ____| |__
* \____ \| ___ | (_ _) ___ |/ ___) _ \
* _____) ) ____| | | || |_| ____( (___| | | |
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
* (C)2013-2018 Semtech
*
* \endcode
*
* \author Miguel Luis ( Semtech )
*/
#ifndef __LMHP_COMPLIANCE__
#define __LMHP_COMPLIANCE__
#include "LoRaMac.h"
#include "LmHandlerTypes.h"
#include "LmhPackage.h"
/*!
* Compliance package identifier.
*
* \remark This value must be unique amongst the packages
*/
#define PACKAGE_ID_COMPLIANCE 0
/*!
* Compliance test protocol handler parameters
*/
typedef struct LmhpComplianceParams_s
{
/*!
* Holds the ADR state
*/
bool AdrEnabled;
/*!
* LoRaWAN ETSI duty cycle control enable/disable
*
* \remark Please note that ETSI mandates duty cycled transmissions. Use only for test purposes
*/
bool DutyCycleEnabled;
/*!
* Stops unnecessary peripherals.
*
* \remark Use for the compliance tests protocol handling in order to
* reduce the power consumption.
*/
void ( *StopPeripherals )( void );
/*!
* Starts previously stopped peripherals.
*
* \remark Use for the compliance tests protocol handling in order to
* reduce the power consumption.
*/
void ( *StartPeripherals )( void );
}LmhpComplianceParams_t;
LmhPackage_t *LmphCompliancePackageFactory( void );
#endif // __LMHP_COMPLIANCE__

View File

@@ -0,0 +1,527 @@
/*!
* \file LmhpFragmentation.c
*
* \brief Implements the LoRa-Alliance fragmented data block transport package
* Specification: https://lora-alliance.org/sites/default/files/2018-09/fragmented_data_block_transport_v1.0.0.pdf
*
* \copyright Revised BSD License, see section \ref LICENSE.
*
* \code
* ______ _
* / _____) _ | |
* ( (____ _____ ____ _| |_ _____ ____| |__
* \____ \| ___ | (_ _) ___ |/ ___) _ \
* _____) ) ____| | | || |_| ____( (___| | | |
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
* (C)2013-2018 Semtech
*
* \endcode
*
* \author Miguel Luis ( Semtech )
*/
#include "LmHandler.h"
#include "LmhpFragmentation.h"
#include "FragDecoder.h"
/*!
* LoRaWAN Application Layer Fragmented Data Block Transport Specification
*/
#define FRAGMENTATION_PORT 201
#define FRAGMENTATION_ID 3
#define FRAGMENTATION_VERSION 1
#define FRAGMENTATION_MAX_SESSIONS 4
// Fragmentation Tx delay state
typedef enum LmhpFragmentationTxDelayStates_e
{
// Tx delay in idle state.
FRAGMENTATION_TX_DELAY_STATE_IDLE,
// Tx delay to be started.
FRAGMENTATION_TX_DELAY_STATE_START,
// Tx delay to be stopped.
FRAGMENTATION_TX_DELAY_STATE_STOP,
}LmhpFragmentationTxDelayStates_t;
/*!
* Package current context
*/
typedef struct LmhpFragmentationState_s
{
bool Initialized;
bool IsRunning;
LmhpFragmentationTxDelayStates_t TxDelayState;
uint8_t DataBufferMaxSize;
uint8_t *DataBuffer;
uint8_t *file;
}LmhpFragmentationState_t;
typedef enum LmhpFragmentationMoteCmd_e
{
FRAGMENTATION_PKG_VERSION_ANS = 0x00,
FRAGMENTATION_FRAG_STATUS_ANS = 0x01,
FRAGMENTATION_FRAG_SESSION_SETUP_ANS = 0x02,
FRAGMENTATION_FRAG_SESSION_DELETE_ANS = 0x03,
}LmhpFragmentationMoteCmd_t;
typedef enum LmhpFragmentationSrvCmd_e
{
FRAGMENTATION_PKG_VERSION_REQ = 0x00,
FRAGMENTATION_FRAG_STATUS_REQ = 0x01,
FRAGMENTATION_FRAG_SESSION_SETUP_REQ = 0x02,
FRAGMENTATION_FRAG_SESSION_DELETE_REQ = 0x03,
FRAGMENTATION_DATA_FRAGMENT = 0x08,
}LmhpFragmentationSrvCmd_t;
/*!
* LoRaWAN fragmented data block transport handler parameters
*/
static LmhpFragmentationParams_t* LmhpFragmentationParams;
/*!
* Initializes the package with provided parameters
*
* \param [IN] params Pointer to the package parameters
* \param [IN] dataBuffer Pointer to main application buffer
* \param [IN] dataBufferMaxSize Main application buffer maximum size
*/
static void LmhpFragmentationInit( void *params, uint8_t *dataBuffer, uint8_t dataBufferMaxSize );
/*!
* Returns the current package initialization status.
*
* \retval status Package initialization status
* [true: Initialized, false: Not initialized]
*/
static bool LmhpFragmentationIsInitialized( void );
/*!
* Returns the package operation status.
*
* \retval status Package operation status
* [true: Running, false: Not running]
*/
static bool LmhpFragmentationIsRunning( void );
/*!
* Processes the internal package events.
*/
static void LmhpFragmentationProcess( void );
/*!
* Processes the MCPS Indication
*
* \param [IN] mcpsIndication MCPS indication primitive data
*/
static void LmhpFragmentationOnMcpsIndication( McpsIndication_t *mcpsIndication );
static LmhpFragmentationState_t LmhpFragmentationState =
{
.Initialized = false,
.IsRunning = false,
.TxDelayState = FRAGMENTATION_TX_DELAY_STATE_IDLE,
};
typedef struct FragGroupData_s
{
bool IsActive;
union
{
uint8_t Value;
struct
{
uint8_t McGroupBitMask: 4;
uint8_t FragIndex: 2;
uint8_t RFU: 2;
}Fields;
}FragSession;
uint16_t FragNb;
uint8_t FragSize;
union
{
uint8_t Value;
struct
{
uint8_t BlockAckDelay: 3;
uint8_t FragAlgo: 3;
uint8_t RFU: 2;
}Fields;
}Control;
uint8_t Padding;
uint32_t Descriptor;
}FragGroupData_t;
typedef struct FragSessionData_s
{
FragGroupData_t FragGroupData;
FragDecoderStatus_t FragDecoderStatus;
int32_t FragDecoderPorcessStatus;
}FragSessionData_t;
FragSessionData_t FragSessionData[FRAGMENTATION_MAX_SESSIONS];
// Answer struct for the commands.
LmHandlerAppData_t DelayedReplyAppData;
static LmhPackage_t LmhpFragmentationPackage =
{
.Port = FRAGMENTATION_PORT,
.Init = LmhpFragmentationInit,
.IsInitialized = LmhpFragmentationIsInitialized,
.IsRunning = LmhpFragmentationIsRunning,
.Process = LmhpFragmentationProcess,
.OnMcpsConfirmProcess = NULL, // Not used in this package
.OnMcpsIndicationProcess = LmhpFragmentationOnMcpsIndication,
.OnMlmeConfirmProcess = NULL, // Not used in this package
.OnMlmeIndicationProcess = NULL, // Not used in this package
.OnMacMcpsRequest = NULL, // To be initialized by LmHandler
.OnMacMlmeRequest = NULL, // To be initialized by LmHandler
.OnJoinRequest = NULL, // To be initialized by LmHandler
.OnSendRequest = NULL, // To be initialized by LmHandler
.OnDeviceTimeRequest = NULL, // To be initialized by LmHandler
.OnSysTimeUpdate = NULL, // To be initialized by LmHandler
};
// Delay value.
static uint32_t TxDelayTime;
// Fragment Delay Timer struct
static TimerEvent_t FragmentTxDelayTimer;
/*!
* \brief Callback function for Fragment delay timer.
*/
static void OnFragmentTxDelay( void* context )
{
// Stop the timer.
TimerStop( &FragmentTxDelayTimer );
// Set the state.
LmhpFragmentationState.TxDelayState = FRAGMENTATION_TX_DELAY_STATE_STOP;
}
LmhPackage_t *LmhpFragmentationPackageFactory( void )
{
return &LmhpFragmentationPackage;
}
static void LmhpFragmentationInit( void *params, uint8_t *dataBuffer, uint8_t dataBufferMaxSize )
{
if( ( params != NULL ) && ( dataBuffer != NULL ) )
{
LmhpFragmentationParams = ( LmhpFragmentationParams_t* )params;
LmhpFragmentationState.DataBuffer = dataBuffer;
LmhpFragmentationState.DataBufferMaxSize = dataBufferMaxSize;
LmhpFragmentationState.Initialized = true;
LmhpFragmentationState.IsRunning = true;
// Initialize Fragmentation delay time.
TxDelayTime = 0;
// Initialize Fragmentation delay timer.
TimerInit( &FragmentTxDelayTimer, OnFragmentTxDelay );
}
else
{
LmhpFragmentationParams = NULL;
LmhpFragmentationState.IsRunning = false;
LmhpFragmentationState.Initialized = false;
}
}
static bool LmhpFragmentationIsInitialized( void )
{
return LmhpFragmentationState.Initialized;
}
static bool LmhpFragmentationIsRunning( void )
{
if( LmhpFragmentationState.Initialized == false )
{
return false;
}
return LmhpFragmentationState.IsRunning;
}
static void LmhpFragmentationProcess( void )
{
LmhpFragmentationTxDelayStates_t delayTimerState;
CRITICAL_SECTION_BEGIN( );
delayTimerState = LmhpFragmentationState.TxDelayState;
// Set the state to idle so that the other states are executed only when they are set
// in the appropriate functions.
LmhpFragmentationState.TxDelayState = FRAGMENTATION_TX_DELAY_STATE_IDLE;
CRITICAL_SECTION_END( );
switch( delayTimerState )
{
case FRAGMENTATION_TX_DELAY_STATE_START:
// Set the timer with the initially calculated Delay value.
TimerSetValue( &FragmentTxDelayTimer, TxDelayTime );
// Start the timer.
TimerStart( &FragmentTxDelayTimer );
break;
case FRAGMENTATION_TX_DELAY_STATE_STOP:
// Send the reply.
LmHandlerSend( &DelayedReplyAppData, LORAMAC_HANDLER_UNCONFIRMED_MSG );
break;
case FRAGMENTATION_TX_DELAY_STATE_IDLE:
// Intentional fall through
default:
// Nothing to do.
break;
}
}
static void LmhpFragmentationOnMcpsIndication( McpsIndication_t *mcpsIndication )
{
uint8_t cmdIndex = 0;
uint8_t dataBufferIndex = 0;
bool isAnswerDelayed = false;
// Answer struct for the commands.
LmHandlerAppData_t cmdReplyAppData;
// Co-efficient used to calculate delay.
uint8_t blockAckDelay = 0;
while( cmdIndex < mcpsIndication->BufferSize )
{
switch( mcpsIndication->Buffer[cmdIndex++] )
{
case FRAGMENTATION_PKG_VERSION_REQ:
{
if( mcpsIndication->Multicast == 1 )
{
// Multicast channel. Don't process command.
break;
}
LmhpFragmentationState.DataBuffer[dataBufferIndex++] = FRAGMENTATION_PKG_VERSION_ANS;
LmhpFragmentationState.DataBuffer[dataBufferIndex++] = FRAGMENTATION_ID;
LmhpFragmentationState.DataBuffer[dataBufferIndex++] = FRAGMENTATION_VERSION;
break;
}
case FRAGMENTATION_FRAG_STATUS_REQ:
{
uint8_t fragIndex = mcpsIndication->Buffer[cmdIndex++];
uint8_t participants = fragIndex & 0x01;
fragIndex >>= 1;
FragSessionData[fragIndex].FragDecoderStatus = FragDecoderGetStatus( );
if( ( participants == 1 ) ||
( ( participants == 0 ) && ( FragSessionData[fragIndex].FragDecoderStatus.FragNbLost > 0 ) ) )
{
LmhpFragmentationState.DataBuffer[dataBufferIndex++] = FRAGMENTATION_FRAG_STATUS_ANS;
LmhpFragmentationState.DataBuffer[dataBufferIndex++] = ( fragIndex << 14 ) |
( ( FragSessionData[fragIndex].FragDecoderStatus.FragNbRx >> 8 ) & 0x3F );
LmhpFragmentationState.DataBuffer[dataBufferIndex++] = FragSessionData[fragIndex].FragDecoderStatus.FragNbRx & 0xFF;
LmhpFragmentationState.DataBuffer[dataBufferIndex++] = FragSessionData[fragIndex].FragDecoderStatus.FragNbLost;
LmhpFragmentationState.DataBuffer[dataBufferIndex++] = FragSessionData[fragIndex].FragDecoderStatus.MatrixError & 0x01;
// Fetch the co-efficient value required to calculate delay of that respective session.
blockAckDelay = FragSessionData[fragIndex].FragGroupData.Control.Fields.BlockAckDelay;
isAnswerDelayed = true;
}
break;
}
case FRAGMENTATION_FRAG_SESSION_SETUP_REQ:
{
if( mcpsIndication->Multicast == 1 )
{
// Multicast channel. Don't process command.
break;
}
FragSessionData_t fragSessionData;
uint8_t status = 0x00;
fragSessionData.FragGroupData.FragSession.Value = mcpsIndication->Buffer[cmdIndex++];
fragSessionData.FragGroupData.FragNb = ( mcpsIndication->Buffer[cmdIndex++] << 0 ) & 0x00FF;
fragSessionData.FragGroupData.FragNb |= ( mcpsIndication->Buffer[cmdIndex++] << 8 ) & 0xFF00;
fragSessionData.FragGroupData.FragSize = mcpsIndication->Buffer[cmdIndex++];
fragSessionData.FragGroupData.Control.Value = mcpsIndication->Buffer[cmdIndex++];
fragSessionData.FragGroupData.Padding = mcpsIndication->Buffer[cmdIndex++];
fragSessionData.FragGroupData.Descriptor = ( mcpsIndication->Buffer[cmdIndex++] << 0 ) & 0x000000FF;
fragSessionData.FragGroupData.Descriptor += ( mcpsIndication->Buffer[cmdIndex++] << 8 ) & 0x0000FF00;
fragSessionData.FragGroupData.Descriptor += ( mcpsIndication->Buffer[cmdIndex++] << 16 ) & 0x00FF0000;
fragSessionData.FragGroupData.Descriptor += ( mcpsIndication->Buffer[cmdIndex++] << 24 ) & 0xFF000000;
if( fragSessionData.FragGroupData.Control.Fields.FragAlgo > 0 )
{
status |= 0x01; // Encoding unsupported
}
#if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 )
if( ( fragSessionData.FragGroupData.FragNb * fragSessionData.FragGroupData.FragSize ) > FragDecoderGetMaxFileSize( ) )
{
status |= 0x02; // Not enough Memory
}
#else
if( ( fragSessionData.FragGroupData.FragNb * fragSessionData.FragGroupData.FragSize ) > LmhpFragmentationParams->BufferSize )
{
status |= 0x02; // Not enough Memory
}
#endif
status |= ( fragSessionData.FragGroupData.FragSession.Fields.FragIndex << 6 ) & 0xC0;
if( fragSessionData.FragGroupData.FragSession.Fields.FragIndex >= FRAGMENTATION_MAX_SESSIONS )
{
status |= 0x04; // FragSession index not supported
}
// Descriptor is not really defined in the specification
// Not clear how to handle this.
// Currently the descriptor is always correct
if( fragSessionData.FragGroupData.Descriptor != 0x01020304 )
{
//status |= 0x08; // Wrong Descriptor
}
if( ( status & 0x0F ) == 0 )
{
// The FragSessionSetup is accepted
fragSessionData.FragGroupData.IsActive = true;
fragSessionData.FragDecoderPorcessStatus = FRAG_SESSION_ONGOING;
FragSessionData[fragSessionData.FragGroupData.FragSession.Fields.FragIndex] = fragSessionData;
#if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 )
FragDecoderInit( fragSessionData.FragGroupData.FragNb,
fragSessionData.FragGroupData.FragSize,
&LmhpFragmentationParams->DecoderCallbacks );
#else
FragDecoderInit( fragSessionData.FragGroupData.FragNb,
fragSessionData.FragGroupData.FragSize,
LmhpFragmentationParams->Buffer,
LmhpFragmentationParams->BufferSize );
#endif
}
LmhpFragmentationState.DataBuffer[dataBufferIndex++] = FRAGMENTATION_FRAG_SESSION_SETUP_ANS;
LmhpFragmentationState.DataBuffer[dataBufferIndex++] = status;
isAnswerDelayed = false;
break;
}
case FRAGMENTATION_FRAG_SESSION_DELETE_REQ:
{
if( mcpsIndication->Multicast == 1 )
{
// Multicast channel. Don't process command.
break;
}
uint8_t status = 0x00;
uint8_t id = mcpsIndication->Buffer[cmdIndex++] & 0x03;
status |= id;
if( ( id >= FRAGMENTATION_MAX_SESSIONS ) || ( FragSessionData[id].FragGroupData.IsActive == false ) )
{
status |= 0x04; // Session does not exist
}
else
{
// Delete session
FragSessionData[id].FragGroupData.IsActive = false;
}
LmhpFragmentationState.DataBuffer[dataBufferIndex++] = FRAGMENTATION_FRAG_SESSION_DELETE_ANS;
LmhpFragmentationState.DataBuffer[dataBufferIndex++] = status;
isAnswerDelayed = false;
break;
}
case FRAGMENTATION_DATA_FRAGMENT:
{
uint8_t fragIndex = 0;
uint16_t fragCounter = 0;
fragCounter = ( mcpsIndication->Buffer[cmdIndex++] << 0 ) & 0x00FF;
fragCounter |= ( mcpsIndication->Buffer[cmdIndex++] << 8 ) & 0xFF00;
fragIndex = ( fragCounter >> 14 ) & 0x03;
fragCounter &= 0x3FFF;
if( mcpsIndication->Multicast == 1 )
{
// Message received on a multicast address
//
// TODO: Not working yet
//
// Check McGroupBitMask
//uint8_t groupId = LoRaMacMcChannelGetGroupId( mcpsIndication->DevAddress );
//if( ( groupId == 0xFF ) ||
// ( ( FragSessionData[fragIndex].FragGroupData.FragSession.Fields.McGroupBitMask & ( 1 << groupId ) ) == 0 ) )
//{
// // Ignore message
// break;
//}
}
if( FragSessionData[fragIndex].FragDecoderPorcessStatus == FRAG_SESSION_ONGOING )
{
FragSessionData[fragIndex].FragDecoderPorcessStatus = FragDecoderProcess( fragCounter, &mcpsIndication->Buffer[cmdIndex] );
FragSessionData[fragIndex].FragDecoderStatus = FragDecoderGetStatus( );
if( LmhpFragmentationParams->OnProgress != NULL )
{
LmhpFragmentationParams->OnProgress( FragSessionData[fragIndex].FragDecoderStatus.FragNbRx,
FragSessionData[fragIndex].FragGroupData.FragNb,
FragSessionData[fragIndex].FragGroupData.FragSize,
FragSessionData[fragIndex].FragDecoderStatus.FragNbLost );
}
}
else
{
if( FragSessionData[fragIndex].FragDecoderPorcessStatus >= 0 )
{
// Fragmentation successfully done
FragSessionData[fragIndex].FragDecoderPorcessStatus = FRAG_SESSION_NOT_STARTED;
if( LmhpFragmentationParams->OnDone != NULL )
{
#if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 )
LmhpFragmentationParams->OnDone( FragSessionData[fragIndex].FragDecoderPorcessStatus,
( FragSessionData[fragIndex].FragGroupData.FragNb * FragSessionData[fragIndex].FragGroupData.FragSize ) - FragSessionData[fragIndex].FragGroupData.Padding );
#else
LmhpFragmentationParams->OnDone( FragSessionData[fragIndex].FragDecoderPorcessStatus,
LmhpFragmentationParams->Buffer,
( FragSessionData[fragIndex].FragGroupData.FragNb * FragSessionData[fragIndex].FragGroupData.FragSize ) - FragSessionData[fragIndex].FragGroupData.Padding );
#endif
}
}
}
cmdIndex += FragSessionData[fragIndex].FragGroupData.FragSize;
break;
}
default:
{
break;
}
}
}
// After processing the commands, if the end-node has to reply back then a flag is checked if the
// reply is to be sent immediately or with a delay.
// In some scenarios it is not desired that multiple end-notes send uplinks at the same time to
// the same server. (Example: Fragment status during a multicast FUOTA)
if( dataBufferIndex != 0 )
{
// Prepare Answer that is to be transmitted
cmdReplyAppData.Buffer = LmhpFragmentationState.DataBuffer;
cmdReplyAppData.BufferSize = dataBufferIndex;
cmdReplyAppData.Port = FRAGMENTATION_PORT;
if( isAnswerDelayed == true )
{
// Delay value is calculated using BlockAckDelay which is communicated by server during the FragSessionSetupReq
// Pseudo Random Delay = rand(0:1) * 2^(blockAckDelay + 4) Seconds.
// Delay = Pseudo Random Delay * 1000 milli seconds.
// Eg: blockAckDelay = 7
// Pseudo Random Delay = rand(0:1) * 2^11
// rand(0:1) seconds = rand(0:1000) milliseconds
// Delay = rand(0:1000) * 2048 => 2048000ms = 34 minutes
TxDelayTime = randr( 0, 1000 ) * ( 1 << ( blockAckDelay + 4 ) );
DelayedReplyAppData = cmdReplyAppData;
LmhpFragmentationState.TxDelayState = FRAGMENTATION_TX_DELAY_STATE_START;
}
else
{
// Send the prepared answer
LmhpFragmentationPackage.OnSendRequest( &cmdReplyAppData, LORAMAC_HANDLER_UNCONFIRMED_MSG );
}
}
}

View File

@@ -0,0 +1,92 @@
/*!
* \file LmhpFragmentation.h
*
* \brief Implements the LoRa-Alliance fragmented data block transport package
* Specification: https://lora-alliance.org/sites/default/files/2018-09/fragmented_data_block_transport_v1.0.0.pdf
*
* \copyright Revised BSD License, see section \ref LICENSE.
*
* \code
* ______ _
* / _____) _ | |
* ( (____ _____ ____ _| |_ _____ ____| |__
* \____ \| ___ | (_ _) ___ |/ ___) _ \
* _____) ) ____| | | || |_| ____( (___| | | |
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
* (C)2013-2018 Semtech
*
* \endcode
*
* \author Miguel Luis ( Semtech )
*/
#ifndef __LMHP_FRAGMENTATION_H__
#define __LMHP_FRAGMENTATION_H__
#include "LoRaMac.h"
#include "LmHandlerTypes.h"
#include "LmhPackage.h"
#include "FragDecoder.h"
/*!
* Fragmentation data block transport package identifier.
*
* \remark This value must be unique amongst the packages
*/
#define PACKAGE_ID_FRAGMENTATION 3
/*!
* Fragmentation package parameters
*/
typedef struct LmhpFragmentationParams_s
{
#if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 )
/*!
* FragDecoder Write/Read function callbacks
*/
FragDecoderCallbacks_t DecoderCallbacks;
#else
/*!
* Pointer to the un-fragmented received buffer.
*/
uint8_t *Buffer;
/*!
* Size of the un-fragmented received buffer.
*/
uint32_t BufferSize;
#endif
/*!
* Notifies the progress of the current fragmentation session
*
* \param [IN] fragCounter Fragment counter
* \param [IN] fragNb Number of fragments
* \param [IN] fragSize Size of fragments
* \param [IN] fragNbLost Number of lost fragments
*/
void ( *OnProgress )( uint16_t fragCounter, uint16_t fragNb, uint8_t fragSize, uint16_t fragNbLost );
#if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 )
/*!
* Notifies that the fragmentation session is finished
*
* \param [IN] status Fragmentation session status [FRAG_SESSION_ONGOING,
* FRAG_SESSION_FINISHED or
* FragDecoder.Status.FragNbLost]
* \param [IN] size Received file size
*/
void ( *OnDone )( int32_t status, uint32_t size );
#else
/*!
* Notifies that the fragmentation session is finished
*
* \param [IN] status Fragmentation session status [FRAG_SESSION_ONGOING,
* FRAG_SESSION_FINISHED or
* FragDecoder.Status.FragNbLost]
* \param [IN] file Pointer to the reception file buffer
* \param [IN] size Received file size
*/
void ( *OnDone )( int32_t status, uint8_t *file, uint32_t size );
#endif
}LmhpFragmentationParams_t;
LmhPackage_t *LmhpFragmentationPackageFactory( void );
#endif // __LMHP_FRAGMENTATION_H__

View File

@@ -0,0 +1,459 @@
/*!
* \file LmhpRemoteMcastSetup.c
*
* \brief Implements the LoRa-Alliance remote multicast setup package
* Specification: https://lora-alliance.org/sites/default/files/2018-09/remote_multicast_setup_v1.0.0.pdf
*
* \copyright Revised BSD License, see section \ref LICENSE.
*
* \code
* ______ _
* / _____) _ | |
* ( (____ _____ ____ _| |_ _____ ____| |__
* \____ \| ___ | (_ _) ___ |/ ___) _ \
* _____) ) ____| | | || |_| ____( (___| | | |
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
* (C)2013-2018 Semtech
*
* \endcode
*
* \author Miguel Luis ( Semtech )
*/
#include "LmHandler.h"
#include "LmhpRemoteMcastSetup.h"
#define DBG_TRACE 1
#if DBG_TRACE == 1
#include <stdio.h>
/*!
* Works in the same way as the printf function does.
*/
#define DBG( ... ) \
do \
{ \
printf( __VA_ARGS__ ); \
}while( 0 )
#else
#define DBG( ... )
#endif
/*!
* LoRaWAN Application Layer Remote multicast setup Specification
*/
#define REMOTE_MCAST_SETUP_PORT 200
#define REMOTE_MCAST_SETUP_ID 2
#define REMOTE_MCAST_SETUP_VERSION 1
typedef enum LmhpRemoteMcastSetupSessionStates_e
{
REMOTE_MCAST_SETUP_SESSION_STATE_IDLE,
REMOTE_MCAST_SETUP_SESSION_STATE_START,
REMOTE_MCAST_SETUP_SESSION_STATE_STOP,
}LmhpRemoteMcastSetupSessionStates_t;
/*!
* Package current context
*/
typedef struct LmhpRemoteMcastSetupState_s
{
bool Initialized;
bool IsRunning;
LmhpRemoteMcastSetupSessionStates_t SessionState;
uint8_t DataBufferMaxSize;
uint8_t *DataBuffer;
}LmhpRemoteMcastSetupState_t;
typedef enum LmhpRemoteMcastSetupMoteCmd_e
{
REMOTE_MCAST_SETUP_PKG_VERSION_ANS = 0x00,
REMOTE_MCAST_SETUP_MC_GROUP_STATUS_ANS = 0x01,
REMOTE_MCAST_SETUP_MC_GROUP_SETUP_ANS = 0x02,
REMOTE_MCAST_SETUP_MC_GROUP_DELETE_ANS = 0x03,
REMOTE_MCAST_SETUP_MC_GROUP_CLASS_C_SESSION_ANS = 0x04,
REMOTE_MCAST_SETUP_MC_GROUP_CLASS_B_SESSION_ANS = 0x05,
}LmhpRemoteMcastSetupMoteCmd_t;
typedef enum LmhpRemoteMcastSetupSrvCmd_e
{
REMOTE_MCAST_SETUP_PKG_VERSION_REQ = 0x00,
REMOTE_MCAST_SETUP_MC_GROUP_STATUS_REQ = 0x01,
REMOTE_MCAST_SETUP_MC_GROUP_SETUP_REQ = 0x02,
REMOTE_MCAST_SETUP_MC_GROUP_DELETE_REQ = 0x03,
REMOTE_MCAST_SETUP_MC_GROUP_CLASS_C_SESSION_REQ = 0x04,
REMOTE_MCAST_SETUP_MC_GROUP_CLASS_B_SESSION_REQ = 0x05,
}LmhpRemoteMcastSetupSrvCmd_t;
/*!
* Initializes the package with provided parameters
*
* \param [IN] params Pointer to the package parameters
* \param [IN] dataBuffer Pointer to main application buffer
* \param [IN] dataBufferMaxSize Main application buffer maximum size
*/
static void LmhpRemoteMcastSetupInit( void *params, uint8_t *dataBuffer, uint8_t dataBufferMaxSize );
/*!
* Returns the current package initialization status.
*
* \retval status Package initialization status
* [true: Initialized, false: Not initialized]
*/
static bool LmhpRemoteMcastSetupIsInitialized( void );
/*!
* Returns the package operation status.
*
* \retval status Package operation status
* [true: Running, false: Not running]
*/
static bool LmhpRemoteMcastSetupIsRunning( void );
/*!
* Processes the internal package events.
*/
static void LmhpRemoteMcastSetupProcess( void );
/*!
* Processes the MCPS Indication
*
* \param [IN] mcpsIndication MCPS indication primitive data
*/
static void LmhpRemoteMcastSetupOnMcpsIndication( McpsIndication_t *mcpsIndication );
static void OnSessionStartTimer( void *context );
static void OnSessionStopTimer( void *context );
static LmhpRemoteMcastSetupState_t LmhpRemoteMcastSetupState =
{
.Initialized = false,
.IsRunning = false,
.SessionState = REMOTE_MCAST_SETUP_SESSION_STATE_IDLE,
};
typedef struct McGroupData_s
{
union
{
uint8_t Value;
struct
{
uint8_t McGroupId: 2;
uint8_t RFU: 6;
}Fields;
}IdHeader;
uint32_t McAddr;
uint8_t McKeyEncrypted[16];
uint32_t McFCountMin;
uint32_t McFCountMax;
}McGroupData_t;
typedef enum eSessionState
{
SESSION_STOPED,
SESSION_STARTED
}SessionState_t;
typedef struct McSessionData_s
{
McGroupData_t McGroupData;
SessionState_t SessionState;
uint32_t SessionTime;
uint8_t SessionTimeout;
McRxParams_t RxParams;
}McSessionData_t;
McSessionData_t McSessionData[LORAMAC_MAX_MC_CTX];
/*!
* Session start timer
*/
static TimerEvent_t SessionStartTimer;
/*!
* Session start timer
*/
static TimerEvent_t SessionStopTimer;
static LmhPackage_t LmhpRemoteMcastSetupPackage =
{
.Port = REMOTE_MCAST_SETUP_PORT,
.Init = LmhpRemoteMcastSetupInit,
.IsInitialized = LmhpRemoteMcastSetupIsInitialized,
.IsRunning = LmhpRemoteMcastSetupIsRunning,
.Process = LmhpRemoteMcastSetupProcess,
.OnMcpsConfirmProcess = NULL, // Not used in this package
.OnMcpsIndicationProcess = LmhpRemoteMcastSetupOnMcpsIndication,
.OnMlmeConfirmProcess = NULL, // Not used in this package
.OnMlmeIndicationProcess = NULL, // Not used in this package
.OnMacMcpsRequest = NULL, // To be initialized by LmHandler
.OnMacMlmeRequest = NULL, // To be initialized by LmHandler
.OnJoinRequest = NULL, // To be initialized by LmHandler
.OnSendRequest = NULL, // To be initialized by LmHandler
.OnDeviceTimeRequest = NULL, // To be initialized by LmHandler
.OnSysTimeUpdate = NULL, // To be initialized by LmHandler
};
LmhPackage_t *LmhpRemoteMcastSetupPackageFactory( void )
{
return &LmhpRemoteMcastSetupPackage;
}
static void LmhpRemoteMcastSetupInit( void * params, uint8_t *dataBuffer, uint8_t dataBufferMaxSize )
{
if( dataBuffer != NULL )
{
LmhpRemoteMcastSetupState.DataBuffer = dataBuffer;
LmhpRemoteMcastSetupState.DataBufferMaxSize = dataBufferMaxSize;
LmhpRemoteMcastSetupState.Initialized = true;
LmhpRemoteMcastSetupState.IsRunning = true;
TimerInit( &SessionStartTimer, OnSessionStartTimer );
TimerInit( &SessionStopTimer, OnSessionStopTimer );
}
else
{
LmhpRemoteMcastSetupState.IsRunning = false;
LmhpRemoteMcastSetupState.Initialized = false;
}
}
static bool LmhpRemoteMcastSetupIsInitialized( void )
{
return LmhpRemoteMcastSetupState.Initialized;
}
static bool LmhpRemoteMcastSetupIsRunning( void )
{
if( LmhpRemoteMcastSetupState.Initialized == false )
{
return false;
}
return LmhpRemoteMcastSetupState.IsRunning;
}
static void LmhpRemoteMcastSetupProcess( void )
{
LmhpRemoteMcastSetupSessionStates_t state;
CRITICAL_SECTION_BEGIN( );
state = LmhpRemoteMcastSetupState.SessionState;
LmhpRemoteMcastSetupState.SessionState = REMOTE_MCAST_SETUP_SESSION_STATE_IDLE;
CRITICAL_SECTION_END( );
switch( state )
{
case REMOTE_MCAST_SETUP_SESSION_STATE_START:
// Switch to Class C
LmHandlerRequestClass( CLASS_C );
TimerSetValue( &SessionStopTimer, ( 1 << McSessionData[0].SessionTimeout ) * 1000 );
TimerStart( &SessionStopTimer );
break;
case REMOTE_MCAST_SETUP_SESSION_STATE_STOP:
// Switch back to Class A
LmHandlerRequestClass( CLASS_A );
break;
case REMOTE_MCAST_SETUP_SESSION_STATE_IDLE:
// Intentional fall through
default:
// Nothing to do.
break;
}
}
static void LmhpRemoteMcastSetupOnMcpsIndication( McpsIndication_t *mcpsIndication )
{
uint8_t cmdIndex = 0;
uint8_t dataBufferIndex = 0;
while( cmdIndex < mcpsIndication->BufferSize )
{
switch( mcpsIndication->Buffer[cmdIndex++] )
{
case REMOTE_MCAST_SETUP_PKG_VERSION_REQ:
{
LmhpRemoteMcastSetupState.DataBuffer[dataBufferIndex++] = REMOTE_MCAST_SETUP_PKG_VERSION_ANS;
LmhpRemoteMcastSetupState.DataBuffer[dataBufferIndex++] = REMOTE_MCAST_SETUP_ID;
LmhpRemoteMcastSetupState.DataBuffer[dataBufferIndex++] = REMOTE_MCAST_SETUP_VERSION;
break;
}
case REMOTE_MCAST_SETUP_MC_GROUP_STATUS_REQ:
{
// TODO implement command prosessing and handling
break;
}
case REMOTE_MCAST_SETUP_MC_GROUP_SETUP_REQ:
{
uint8_t id = mcpsIndication->Buffer[cmdIndex++];
McSessionData[id].McGroupData.IdHeader.Value = id;
McSessionData[id].McGroupData.McAddr = ( mcpsIndication->Buffer[cmdIndex++] << 0 ) & 0x000000FF;
McSessionData[id].McGroupData.McAddr += ( mcpsIndication->Buffer[cmdIndex++] << 8 ) & 0x0000FF00;
McSessionData[id].McGroupData.McAddr += ( mcpsIndication->Buffer[cmdIndex++] << 16 ) & 0x00FF0000;
McSessionData[id].McGroupData.McAddr += ( mcpsIndication->Buffer[cmdIndex++] << 24 ) & 0xFF000000;
for( int8_t i = 0; i < 16; i++ )
{
McSessionData[id].McGroupData.McKeyEncrypted[i] = mcpsIndication->Buffer[cmdIndex++];
}
McSessionData[id].McGroupData.McFCountMin = ( mcpsIndication->Buffer[cmdIndex++] << 0 ) & 0x000000FF;
McSessionData[id].McGroupData.McFCountMin += ( mcpsIndication->Buffer[cmdIndex++] << 8 ) & 0x0000FF00;
McSessionData[id].McGroupData.McFCountMin += ( mcpsIndication->Buffer[cmdIndex++] << 16 ) & 0x00FF0000;
McSessionData[id].McGroupData.McFCountMin += ( mcpsIndication->Buffer[cmdIndex++] << 24 ) & 0xFF000000;
McSessionData[id].McGroupData.McFCountMax = ( mcpsIndication->Buffer[cmdIndex++] << 0 ) & 0x000000FF;
McSessionData[id].McGroupData.McFCountMax += ( mcpsIndication->Buffer[cmdIndex++] << 8 ) & 0x0000FF00;
McSessionData[id].McGroupData.McFCountMax += ( mcpsIndication->Buffer[cmdIndex++] << 16 ) & 0x00FF0000;
McSessionData[id].McGroupData.McFCountMax += ( mcpsIndication->Buffer[cmdIndex++] << 24 ) & 0xFF000000;
McChannelParams_t channel =
{
.IsRemotelySetup = true,
.Class = CLASS_C, // Field not used for multicast channel setup. Must be initialized to something
.IsEnabled = true,
.GroupID = ( AddressIdentifier_t )McSessionData[id].McGroupData.IdHeader.Fields.McGroupId,
.Address = McSessionData[id].McGroupData.McAddr,
.McKeys.McKeyE = McSessionData[id].McGroupData.McKeyEncrypted,
.FCountMin = McSessionData[id].McGroupData.McFCountMin,
.FCountMax = McSessionData[id].McGroupData.McFCountMax,
.RxParams.ClassC = // Field not used for multicast channel setup. Must be initialized to something
{
.Frequency = 0,
.Datarate = 0
}
};
uint8_t idError = 0x01; // One bit value
if( LoRaMacMcChannelSetup( &channel ) == LORAMAC_STATUS_OK )
{
idError = 0x00;
}
LmhpRemoteMcastSetupState.DataBuffer[dataBufferIndex++] = REMOTE_MCAST_SETUP_MC_GROUP_SETUP_ANS;
LmhpRemoteMcastSetupState.DataBuffer[dataBufferIndex++] = ( idError << 2 ) | McSessionData[id].McGroupData.IdHeader.Fields.McGroupId;
break;
}
case REMOTE_MCAST_SETUP_MC_GROUP_DELETE_REQ:
{
uint8_t status = 0x00;
uint8_t id = mcpsIndication->Buffer[cmdIndex++] & 0x03;
status = id;
LmhpRemoteMcastSetupState.DataBuffer[dataBufferIndex++] = REMOTE_MCAST_SETUP_MC_GROUP_DELETE_ANS;
if( LoRaMacMcChannelDelete( ( AddressIdentifier_t )id ) != LORAMAC_STATUS_OK )
{
status |= 0x04; // McGroupUndefined bit set
}
LmhpRemoteMcastSetupState.DataBuffer[dataBufferIndex++] = status;
break;
}
case REMOTE_MCAST_SETUP_MC_GROUP_CLASS_C_SESSION_REQ:
{
uint8_t status = 0x00;
uint8_t id = mcpsIndication->Buffer[cmdIndex++] & 0x03;
McSessionData[id].SessionTime = ( mcpsIndication->Buffer[cmdIndex++] << 0 ) & 0x000000FF;
McSessionData[id].SessionTime += ( mcpsIndication->Buffer[cmdIndex++] << 8 ) & 0x0000FF00;
McSessionData[id].SessionTime += ( mcpsIndication->Buffer[cmdIndex++] << 16 ) & 0x00FF0000;
McSessionData[id].SessionTime += ( mcpsIndication->Buffer[cmdIndex++] << 24 ) & 0xFF000000;
// Add Unix to Gps epcoh offset. The system time is based on Unix time.
McSessionData[id].SessionTime += UNIX_GPS_EPOCH_OFFSET;
McSessionData[id].SessionTimeout = mcpsIndication->Buffer[cmdIndex++] & 0x0F;
McSessionData[id].RxParams.ClassC.Frequency = ( mcpsIndication->Buffer[cmdIndex++] << 0 ) & 0x000000FF;
McSessionData[id].RxParams.ClassC.Frequency |= ( mcpsIndication->Buffer[cmdIndex++] << 8 ) & 0x0000FF00;
McSessionData[id].RxParams.ClassC.Frequency |= ( mcpsIndication->Buffer[cmdIndex++] << 16 ) & 0x00FF0000;
McSessionData[id].RxParams.ClassC.Frequency *= 100;
McSessionData[id].RxParams.ClassC.Datarate = mcpsIndication->Buffer[cmdIndex++];
LmhpRemoteMcastSetupState.DataBuffer[dataBufferIndex++] = REMOTE_MCAST_SETUP_MC_GROUP_CLASS_C_SESSION_ANS;
if( LoRaMacMcChannelSetupRxParams( ( AddressIdentifier_t )id, &McSessionData[id].RxParams, &status ) == LORAMAC_STATUS_OK )
{
SysTime_t curTime = { .Seconds = 0, .SubSeconds = 0 };
curTime = SysTimeGet( );
int32_t timeToSessionStart = McSessionData[id].SessionTime - curTime.Seconds;
if( timeToSessionStart > 0 )
{
// Start session start timer
TimerSetValue( &SessionStartTimer, timeToSessionStart * 1000 );
TimerStart( &SessionStartTimer );
DBG( "Time2SessionStart: %ld ms\n", timeToSessionStart * 1000 );
LmhpRemoteMcastSetupState.DataBuffer[dataBufferIndex++] = status;
LmhpRemoteMcastSetupState.DataBuffer[dataBufferIndex++] = ( timeToSessionStart >> 0 ) & 0xFF;
LmhpRemoteMcastSetupState.DataBuffer[dataBufferIndex++] = ( timeToSessionStart >> 8 ) & 0xFF;
LmhpRemoteMcastSetupState.DataBuffer[dataBufferIndex++] = ( timeToSessionStart >> 16 ) & 0xFF;
break;
}
else
{
// Session start time before current device time
status |= 0x10;
}
}
LmhpRemoteMcastSetupState.DataBuffer[dataBufferIndex++] = status;
break;
}
case REMOTE_MCAST_SETUP_MC_GROUP_CLASS_B_SESSION_REQ:
{
// TODO implement command prosessing and handling
break;
}
default:
{
break;
}
}
}
if( dataBufferIndex != 0 )
{
// Answer commands
LmHandlerAppData_t appData =
{
.Buffer = LmhpRemoteMcastSetupState.DataBuffer,
.BufferSize = dataBufferIndex,
.Port = REMOTE_MCAST_SETUP_PORT
};
LmhpRemoteMcastSetupPackage.OnSendRequest( &appData, LORAMAC_HANDLER_UNCONFIRMED_MSG );
DBG( "ID : %d\n", McSessionData[0].McGroupData.IdHeader.Fields.McGroupId );
DBG( "McAddr : %08lX\n", McSessionData[0].McGroupData.McAddr );
DBG( "McKey : %02X", McSessionData[0].McGroupData.McKeyEncrypted[0] );
for( int i = 1; i < 16; i++ )
{
DBG( "-%02X", McSessionData[0].McGroupData.McKeyEncrypted[i] );
}
DBG( "\n" );
DBG( "McFCountMin : %lu\n", McSessionData[0].McGroupData.McFCountMin );
DBG( "McFCountMax : %lu\n", McSessionData[0].McGroupData.McFCountMax );
DBG( "SessionTime : %lu\n", McSessionData[0].SessionTime );
DBG( "SessionTimeT: %d\n", McSessionData[0].SessionTimeout );
DBG( "Rx Freq : %lu\n", McSessionData[0].RxParams.ClassC.Frequency );
DBG( "Rx DR : DR_%d\n", McSessionData[0].RxParams.ClassC.Datarate );
}
}
static void OnSessionStartTimer( void *context )
{
TimerStop( &SessionStartTimer );
LmhpRemoteMcastSetupState.SessionState = REMOTE_MCAST_SETUP_SESSION_STATE_START;
}
static void OnSessionStopTimer( void *context )
{
TimerStop( &SessionStopTimer );
LmhpRemoteMcastSetupState.SessionState = REMOTE_MCAST_SETUP_SESSION_STATE_STOP;
}

View File

@@ -0,0 +1,47 @@
/*!
* \file LmhpRemoteMcastSetup.h
*
* \brief Implements the LoRa-Alliance remote multicast setup package
* Specification: https://lora-alliance.org/sites/default/files/2018-09/remote_multicast_setup_v1.0.0.pdf
*
* \copyright Revised BSD License, see section \ref LICENSE.
*
* \code
* ______ _
* / _____) _ | |
* ( (____ _____ ____ _| |_ _____ ____| |__
* \____ \| ___ | (_ _) ___ |/ ___) _ \
* _____) ) ____| | | || |_| ____( (___| | | |
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
* (C)2013-2018 Semtech
*
* \endcode
*
* \author Miguel Luis ( Semtech )
*/
#ifndef __LMHP_REMOTE_MCAST_SETUP_H__
#define __LMHP_REMOTE_MCAST_SETUP_H__
#include "LoRaMac.h"
#include "LmHandlerTypes.h"
#include "LmhPackage.h"
/*!
* Remote multicast setup package identifier.
*
* \remark This value must be unique amongst the packages
*/
#define PACKAGE_ID_REMOTE_MCAST_SETUP 2
/*!
* Remote multicast setup package parameters
*
* This package doesn't require parameters
*/
//typedef struct LmhpRemoteMcastSetupParams_s
//{
//}LmhpRemoteMcastSetupParams_t;
LmhPackage_t *LmhpRemoteMcastSetupPackageFactory( void );
#endif // __LMHP_REMOTE_MCAST_SETUP_H__

View File

@@ -0,0 +1,434 @@
/*!
* \file LmHandlerMsgDisplay.h
*
* \brief Common set of functions to display default messages from
* LoRaMacHandler.
*
* \copyright Revised BSD License, see section \ref LICENSE.
*
* \code
* ______ _
* / _____) _ | |
* ( (____ _____ ____ _| |_ _____ ____| |__
* \____ \| ___ | (_ _) ___ |/ ___) _ \
* _____) ) ____| | | || |_| ____( (___| | | |
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
* (C)2013-2019 Semtech
*
* \endcode
*
* \author Miguel Luis ( Semtech )
*/
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include "utilities.h"
#include "timer.h"
#include "LmHandlerMsgDisplay.h"
/*!
* MAC status strings
*/
const char* MacStatusStrings[] =
{
"OK", // LORAMAC_STATUS_OK
"Busy", // LORAMAC_STATUS_BUSY
"Service unknown", // LORAMAC_STATUS_SERVICE_UNKNOWN
"Parameter invalid", // LORAMAC_STATUS_PARAMETER_INVALID
"Frequency invalid", // LORAMAC_STATUS_FREQUENCY_INVALID
"Datarate invalid", // LORAMAC_STATUS_DATARATE_INVALID
"Frequency or datarate invalid", // LORAMAC_STATUS_FREQ_AND_DR_INVALID
"No network joined", // LORAMAC_STATUS_NO_NETWORK_JOINED
"Length error", // LORAMAC_STATUS_LENGTH_ERROR
"Region not supported", // LORAMAC_STATUS_REGION_NOT_SUPPORTED
"Skipped APP data", // LORAMAC_STATUS_SKIPPED_APP_DATA
"Duty-cycle restricted", // LORAMAC_STATUS_DUTYCYCLE_RESTRICTED
"No channel found", // LORAMAC_STATUS_NO_CHANNEL_FOUND
"No free channel found", // LORAMAC_STATUS_NO_FREE_CHANNEL_FOUND
"Busy beacon reserved time", // LORAMAC_STATUS_BUSY_BEACON_RESERVED_TIME
"Busy ping-slot window time", // LORAMAC_STATUS_BUSY_PING_SLOT_WINDOW_TIME
"Busy uplink collision", // LORAMAC_STATUS_BUSY_UPLINK_COLLISION
"Crypto error", // LORAMAC_STATUS_CRYPTO_ERROR
"FCnt handler error", // LORAMAC_STATUS_FCNT_HANDLER_ERROR
"MAC command error", // LORAMAC_STATUS_MAC_COMMAD_ERROR
"ClassB error", // LORAMAC_STATUS_CLASS_B_ERROR
"Confirm queue error", // LORAMAC_STATUS_CONFIRM_QUEUE_ERROR
"Multicast group undefined", // LORAMAC_STATUS_MC_GROUP_UNDEFINED
"Unknown error", // LORAMAC_STATUS_ERROR
};
/*!
* MAC event info status strings.
*/
const char* EventInfoStatusStrings[] =
{
"OK", // LORAMAC_EVENT_INFO_STATUS_OK
"Error", // LORAMAC_EVENT_INFO_STATUS_ERROR
"Tx timeout", // LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT
"Rx 1 timeout", // LORAMAC_EVENT_INFO_STATUS_RX1_TIMEOUT
"Rx 2 timeout", // LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT
"Rx1 error", // LORAMAC_EVENT_INFO_STATUS_RX1_ERROR
"Rx2 error", // LORAMAC_EVENT_INFO_STATUS_RX2_ERROR
"Join failed", // LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL
"Downlink repeated", // LORAMAC_EVENT_INFO_STATUS_DOWNLINK_REPEATED
"Tx DR payload size error", // LORAMAC_EVENT_INFO_STATUS_TX_DR_PAYLOAD_SIZE_ERROR
"Downlink too many frames loss", // LORAMAC_EVENT_INFO_STATUS_DOWNLINK_TOO_MANY_FRAMES_LOSS
"Address fail", // LORAMAC_EVENT_INFO_STATUS_ADDRESS_FAIL
"MIC fail", // LORAMAC_EVENT_INFO_STATUS_MIC_FAIL
"Multicast fail", // LORAMAC_EVENT_INFO_STATUS_MULTICAST_FAIL
"Beacon locked", // LORAMAC_EVENT_INFO_STATUS_BEACON_LOCKED
"Beacon lost", // LORAMAC_EVENT_INFO_STATUS_BEACON_LOST
"Beacon not found" // LORAMAC_EVENT_INFO_STATUS_BEACON_NOT_FOUND
};
/*!
* Prints the provided buffer in HEX
*
* \param buffer Buffer to be printed
* \param size Buffer size to be printed
*/
void PrintHexBuffer( uint8_t *buffer, uint8_t size )
{
uint8_t newline = 0;
for( uint8_t i = 0; i < size; i++ )
{
if( newline != 0 )
{
printf( "\n" );
newline = 0;
}
printf( "%02X ", buffer[i] );
if( ( ( i + 1 ) % 16 ) == 0 )
{
newline = 1;
}
}
printf( "\n" );
}
void DisplayNvmContextChange( LmHandlerNvmContextStates_t state )
{
if( state == LORAMAC_HANDLER_NVM_STORE )
{
printf( "\n###### ============ CTXS STORED ============ ######\n\n" );
}
else
{
printf( "\n###### =========== CTXS RESTORED =========== ######\n\n" );
}
}
void DisplayNetworkParametersUpdate( CommissioningParams_t *commissioningParams )
{
printf( "DevEui : %02X", commissioningParams->DevEui[0] );
for( int i = 1; i < 8; i++ )
{
printf( "-%02X", commissioningParams->DevEui[i] );
}
printf( "\n" );
printf( "JoinEui : %02X", commissioningParams->JoinEui[0] );
for( int i = 1; i < 8; i++ )
{
printf( "-%02X", commissioningParams->JoinEui[i] );
}
printf( "\n" );
printf( "Pin : %02X", commissioningParams->SePin[0] );
for( int i = 1; i < 4; i++ )
{
printf( "-%02X", commissioningParams->SePin[i] );
}
printf( "\n\n" );
}
void DisplayMacMcpsRequestUpdate( LoRaMacStatus_t status, McpsReq_t *mcpsReq, TimerTime_t nextTxIn )
{
switch( mcpsReq->Type )
{
case MCPS_CONFIRMED:
{
printf( "\n###### =========== MCPS-Request ============ ######\n" );
printf( "###### MCPS_CONFIRMED ######\n");
printf( "###### ===================================== ######\n");
break;
}
case MCPS_UNCONFIRMED:
{
printf( "\n###### =========== MCPS-Request ============ ######\n" );
printf( "###### MCPS_UNCONFIRMED ######\n");
printf( "###### ===================================== ######\n");
break;
}
case MCPS_PROPRIETARY:
{
printf( "\n###### =========== MCPS-Request ============ ######\n" );
printf( "###### MCPS_PROPRIETARY ######\n");
printf( "###### ===================================== ######\n");
break;
}
default:
{
printf( "\n###### =========== MCPS-Request ============ ######\n" );
printf( "###### MCPS_ERROR ######\n");
printf( "###### ===================================== ######\n");
break;
}
}
printf( "STATUS : %s\n", MacStatusStrings[status] );
if( status == LORAMAC_STATUS_DUTYCYCLE_RESTRICTED )
{
printf( "Next Tx in : %lu [ms]\n", nextTxIn );
}
}
void DisplayMacMlmeRequestUpdate( LoRaMacStatus_t status, MlmeReq_t *mlmeReq, TimerTime_t nextTxIn )
{
switch( mlmeReq->Type )
{
case MLME_JOIN:
{
printf( "\n###### =========== MLME-Request ============ ######\n" );
printf( "###### MLME_JOIN ######\n");
printf( "###### ===================================== ######\n");
break;
}
case MLME_LINK_CHECK:
{
printf( "\n###### =========== MLME-Request ============ ######\n" );
printf( "###### MLME_LINK_CHECK ######\n");
printf( "###### ===================================== ######\n");
break;
}
case MLME_DEVICE_TIME:
{
printf( "\n###### =========== MLME-Request ============ ######\n" );
printf( "###### MLME_DEVICE_TIME ######\n");
printf( "###### ===================================== ######\n");
break;
}
case MLME_TXCW:
{
printf( "\n###### =========== MLME-Request ============ ######\n" );
printf( "###### MLME_TXCW ######\n");
printf( "###### ===================================== ######\n");
break;
}
case MLME_TXCW_1:
{
printf( "\n###### =========== MLME-Request ============ ######\n" );
printf( "###### MLME_TXCW_1 ######\n");
printf( "###### ===================================== ######\n");
break;
}
default:
{
printf( "\n###### =========== MLME-Request ============ ######\n" );
printf( "###### MLME_UNKNOWN ######\n");
printf( "###### ===================================== ######\n");
break;
}
}
printf( "STATUS : %s\n", MacStatusStrings[status] );
if( status == LORAMAC_STATUS_DUTYCYCLE_RESTRICTED )
{
printf( "Next Tx in : %lu [ms]\n", nextTxIn );
}
}
void DisplayJoinRequestUpdate( LmHandlerJoinParams_t *params )
{
if( params->CommissioningParams->IsOtaaActivation == true )
{
if( params->Status == LORAMAC_HANDLER_SUCCESS )
{
printf( "###### =========== JOINED ============ ######\n" );
printf( "\nOTAA\n\n" );
printf( "DevAddr : %08lX\n", params->CommissioningParams->DevAddr );
printf( "\n\n" );
printf( "DATA RATE : DR_%d\n\n", params->Datarate );
}
}
#if ( OVER_THE_AIR_ACTIVATION == 0 )
else
{
printf( "###### =========== JOINED ============ ######\n" );
printf( "\nABP\n\n" );
printf( "DevAddr : %08lX\n", params->CommissioningParams->DevAddr );
printf( "\n\n" );
}
#endif
}
void DisplayTxUpdate( LmHandlerTxParams_t *params )
{
MibRequestConfirm_t mibGet;
if( params->IsMcpsConfirm == 0 )
{
printf( "\n###### =========== MLME-Confirm ============ ######\n" );
printf( "STATUS : %s\n", EventInfoStatusStrings[params->Status] );
return;
}
printf( "\n###### =========== MCPS-Confirm ============ ######\n" );
printf( "STATUS : %s\n", EventInfoStatusStrings[params->Status] );
printf( "\n###### ===== UPLINK FRAME %8lu ===== ######\n", params->UplinkCounter );
printf( "\n" );
printf( "CLASS : %c\n", "ABC"[LmHandlerGetCurrentClass( )] );
printf( "\n" );
printf( "TX PORT : %d\n", params->AppData.Port );
if( params->AppData.BufferSize != 0 )
{
printf( "TX DATA : " );
if( params->MsgType == LORAMAC_HANDLER_CONFIRMED_MSG )
{
printf( "CONFIRMED - %s\n", ( params->AckReceived != 0 ) ? "ACK" : "NACK" );
}
else
{
printf( "UNCONFIRMED\n" );
}
PrintHexBuffer( params->AppData.Buffer, params->AppData.BufferSize );
}
printf( "\n" );
printf( "DATA RATE : DR_%d\n", params->Datarate );
mibGet.Type = MIB_CHANNELS;
if( LoRaMacMibGetRequestConfirm( &mibGet ) == LORAMAC_STATUS_OK )
{
printf( "U/L FREQ : %lu\n", mibGet.Param.ChannelList[params->Channel].Frequency );
}
printf( "TX POWER : %d\n", params->TxPower );
mibGet.Type = MIB_CHANNELS_MASK;
if( LoRaMacMibGetRequestConfirm( &mibGet ) == LORAMAC_STATUS_OK )
{
printf("CHANNEL MASK: ");
switch( LmHandlerGetActiveRegion( ) )
{
case LORAMAC_REGION_AS923:
case LORAMAC_REGION_CN779:
case LORAMAC_REGION_EU868:
case LORAMAC_REGION_IN865:
case LORAMAC_REGION_KR920:
case LORAMAC_REGION_EU433:
case LORAMAC_REGION_RU864:
{
printf( "%04X ", mibGet.Param.ChannelsMask[0] );
break;
}
case LORAMAC_REGION_AU915:
case LORAMAC_REGION_CN470:
case LORAMAC_REGION_US915:
{
for( uint8_t i = 0; i < 5; i++)
{
printf( "%04X ", mibGet.Param.ChannelsMask[i] );
}
break;
}
default:
{
printf( "\n###### ========= Unknown Region ============ ######" );
break;
}
}
printf("\n");
}
printf( "\n" );
}
void DisplayRxUpdate( LmHandlerAppData_t *appData, LmHandlerRxParams_t *params )
{
const char *slotStrings[] = { "1", "2", "C", "C Multicast", "B Ping-Slot", "B Multicast Ping-Slot" };
if( params->IsMcpsIndication == 0 )
{
printf( "\n###### ========== MLME-Indication ========== ######\n" );
printf( "STATUS : %s\n", EventInfoStatusStrings[params->Status] );
return;
}
printf( "\n###### ========== MCPS-Indication ========== ######\n" );
printf( "STATUS : %s\n", EventInfoStatusStrings[params->Status] );
printf( "\n###### ===== DOWNLINK FRAME %8lu ===== ######\n", params->DownlinkCounter );
printf( "RX WINDOW : %s\n", slotStrings[params->RxSlot] );
printf( "RX PORT : %d\n", appData->Port );
if( appData->BufferSize != 0 )
{
printf( "RX DATA : \n" );
PrintHexBuffer( appData->Buffer, appData->BufferSize );
}
printf( "\n" );
printf( "DATA RATE : DR_%d\n", params->Datarate );
printf( "RX RSSI : %d\n", params->Rssi );
printf( "RX SNR : %d\n", params->Snr );
printf( "\n" );
}
void DisplayBeaconUpdate( LoRaMAcHandlerBeaconParams_t *params )
{
switch( params->State )
{
default:
case LORAMAC_HANDLER_BEACON_ACQUIRING:
{
printf( "\n###### ========= BEACON ACQUIRING ========== ######\n" );
break;
}
case LORAMAC_HANDLER_BEACON_LOST:
{
printf( "\n###### ============ BEACON LOST ============ ######\n" );
break;
}
case LORAMAC_HANDLER_BEACON_RX:
{
printf( "\n###### ===== BEACON %8lu ==== ######\n", params->Info.Time.Seconds );
printf( "GW DESC : %d\n", params->Info.GwSpecific.InfoDesc );
printf( "GW INFO : " );
PrintHexBuffer( params->Info.GwSpecific.Info, 6 );
printf( "\n" );
printf( "FREQ : %lu\n", params->Info.Frequency );
printf( "DATA RATE : DR_%d\n", params->Info.Datarate );
printf( "RX RSSI : %d\n", params->Info.Rssi );
printf( "RX SNR : %d\n", params->Info.Snr );
printf( "\n" );
break;
}
case LORAMAC_HANDLER_BEACON_NRX:
{
printf( "\n###### ======== BEACON NOT RECEIVED ======== ######\n" );
break;
}
}
}
void DisplayClassUpdate( DeviceClass_t deviceClass )
{
printf( "\n\n###### ===== Switch to Class %c done. ===== ######\n\n", "ABC"[deviceClass] );
}
void DisplayAppInfo( const char* appName, const Version_t* appVersion, const Version_t* gitHubVersion )
{
printf( "\n###### ===================================== ######\n\n" );
printf( "Application name : %s\n", appName );
printf( "Application version: %d.%d.%d\n", appVersion->Fields.Major, appVersion->Fields.Minor, appVersion->Fields.Patch );
printf( "GitHub base version: %d.%d.%d\n", gitHubVersion->Fields.Major, gitHubVersion->Fields.Minor, gitHubVersion->Fields.Patch );
printf( "\n###### ===================================== ######\n\n" );
}

View File

@@ -0,0 +1,102 @@
/*!
* \file LmHandlerMsgDisplay.h
*
* \brief Common set of functions to display default messages from
* LoRaMacHandler.
*
* \copyright Revised BSD License, see section \ref LICENSE.
*
* \code
* ______ _
* / _____) _ | |
* ( (____ _____ ____ _| |_ _____ ____| |__
* \____ \| ___ | (_ _) ___ |/ ___) _ \
* _____) ) ____| | | || |_| ____( (___| | | |
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
* (C)2013-2019 Semtech
*
* \endcode
*
* \author Miguel Luis ( Semtech )
*/
#ifndef __LMHANDLER_MSG_DISPLAY_H__
#define __LMHANDLER_MSG_DISPLAY_H__
#include "utilities.h"
#include "LmHandler.h"
/*!
* \brief Displays NVM context operation state
*
* \param [IN] state Indicates if we are storing (true) or
* restoring (false) the NVM context
*/
void DisplayNvmContextChange( LmHandlerNvmContextStates_t state );
/*!
* \brief Displays updated network parameters
*
* \param [IN] commissioningParams Commissioning provided parameters
*/
void DisplayNetworkParametersUpdate( CommissioningParams_t* commissioningParams );
/*!
* \brief Displays updated McpsRequest
*
* \param [IN] status McpsRequest execution status
* \param [IN] mcpsReq McpsRequest command executed
* \param [IN] nextTxIn Time to wait for the next uplink transmission
*/
void DisplayMacMcpsRequestUpdate( LoRaMacStatus_t status, McpsReq_t *mcpsReq, TimerTime_t nextTxIn );
/*!
* \brief Displays updated MlmeRequest
*
* \param [IN] status MlmeRequest execution status
* \param [IN] mlmeReq MlmeRequest command executed
* \param [IN] nextTxIn Time to wait for the next uplink transmission
*/
void DisplayMacMlmeRequestUpdate( LoRaMacStatus_t status, MlmeReq_t *mlmeReq, TimerTime_t nextTxIn );
/*!
* \brief Displays updated JoinRequest
*
* \param [IN] params Executed JoinRequest parameters
*/
void DisplayJoinRequestUpdate( LmHandlerJoinParams_t* params );
/*!
* \brief Displays Tx params
*
* \param [IN] params Tx parameters
*/
void DisplayTxUpdate( LmHandlerTxParams_t* params );
/*!
* \brief Displays Rx params
*
* \param [IN] appData Receive data payload and port number
* \param [IN] params Rx parameters
*/
void DisplayRxUpdate( LmHandlerAppData_t* appData, LmHandlerRxParams_t* params );
/*!
* \brief Displays beacon status update
*
* \param [IN] params Beacon parameters
*/
void DisplayBeaconUpdate( LoRaMAcHandlerBeaconParams_t* params );
/*!
* \brief Displays end-device class update
*
* \param [IN] deviceClass Current end-device class
*/
void DisplayClassUpdate( DeviceClass_t deviceClass );
/*!
* \brief Displays application information
*/
void DisplayAppInfo( const char* appName, const Version_t* appVersion, const Version_t* gitHubVersion );
#endif // __LMHANDLER_MSG_DISPLAY_H__

View File

@@ -112,7 +112,6 @@ LoRaMacCtxUpdateStatus_t CtxUpdateStatus = { .Value = 0 };
/* /*
* Nvmm handles * Nvmm handles
*/ */
static NvmmDataBlock_t FCntHandlerNvmCtxDataBlock;
static NvmmDataBlock_t SecureElementNvmCtxDataBlock; static NvmmDataBlock_t SecureElementNvmCtxDataBlock;
static NvmmDataBlock_t CryptoNvmCtxDataBlock; static NvmmDataBlock_t CryptoNvmCtxDataBlock;
#if ( MAX_PERSISTENT_CTX_MGMT_ENABLED == 1 ) #if ( MAX_PERSISTENT_CTX_MGMT_ENABLED == 1 )
@@ -164,11 +163,6 @@ void NvmCtxMgmtEvent( LoRaMacNvmCtxModule_t module )
CtxUpdateStatus.Elements.ConfirmQueue = 1; CtxUpdateStatus.Elements.ConfirmQueue = 1;
break; break;
} }
case LORAMAC_NVMCTXMODULE_FCNT_HANDLER:
{
CtxUpdateStatus.Elements.FCntHandlerNvmCtx = 1;
break;
}
default: default:
{ {
break; break;
@@ -213,14 +207,6 @@ NvmCtxMgmtStatus_t NvmCtxMgmtStore( void )
} }
} }
if( CtxUpdateStatus.Elements.FCntHandlerNvmCtx == 1 )
{
if( NvmmWrite( &FCntHandlerNvmCtxDataBlock, MacContexts->FCntHandlerNvmCtx, MacContexts->FCntHandlerNvmCtxSize ) != NVMM_SUCCESS )
{
return NVMCTXMGMT_STATUS_FAIL;
}
}
#if ( MAX_PERSISTENT_CTX_MGMT_ENABLED == 1 ) #if ( MAX_PERSISTENT_CTX_MGMT_ENABLED == 1 )
if( CtxUpdateStatus.Elements.Mac == 1 ) if( CtxUpdateStatus.Elements.Mac == 1 )
{ {
@@ -288,7 +274,6 @@ NvmCtxMgmtStatus_t NvmCtxMgmtRestore( void )
uint8_t NvmCryptoCtxRestore[mibReq.Param.Contexts->CryptoNvmCtxSize]; uint8_t NvmCryptoCtxRestore[mibReq.Param.Contexts->CryptoNvmCtxSize];
uint8_t NvmSecureElementCtxRestore[mibReq.Param.Contexts->SecureElementNvmCtxSize]; uint8_t NvmSecureElementCtxRestore[mibReq.Param.Contexts->SecureElementNvmCtxSize];
uint8_t NvmFCntHandlerCtxRestore[mibReq.Param.Contexts->FCntHandlerNvmCtxSize];
#if ( MAX_PERSISTENT_CTX_MGMT_ENABLED == 1 ) #if ( MAX_PERSISTENT_CTX_MGMT_ENABLED == 1 )
uint8_t NvmMacCtxRestore[mibReq.Param.Contexts->MacNvmCtxSize]; uint8_t NvmMacCtxRestore[mibReq.Param.Contexts->MacNvmCtxSize];
uint8_t NvmRegionCtxRestore[mibReq.Param.Contexts->RegionNvmCtxSize]; uint8_t NvmRegionCtxRestore[mibReq.Param.Contexts->RegionNvmCtxSize];
@@ -319,17 +304,6 @@ NvmCtxMgmtStatus_t NvmCtxMgmtRestore( void )
status = NVMCTXMGMT_STATUS_FAIL; status = NVMCTXMGMT_STATUS_FAIL;
} }
if ( NvmmDeclare( &FCntHandlerNvmCtxDataBlock, mibReq.Param.Contexts->FCntHandlerNvmCtxSize ) == NVMM_SUCCESS )
{
NvmmRead( &FCntHandlerNvmCtxDataBlock, NvmFCntHandlerCtxRestore, mibReq.Param.Contexts->FCntHandlerNvmCtxSize );
contexts.FCntHandlerNvmCtx = &NvmFCntHandlerCtxRestore;
contexts.FCntHandlerNvmCtxSize = mibReq.Param.Contexts->FCntHandlerNvmCtxSize;
}
else
{
status = NVMCTXMGMT_STATUS_FAIL;
}
#if ( MAX_PERSISTENT_CTX_MGMT_ENABLED == 1 ) #if ( MAX_PERSISTENT_CTX_MGMT_ENABLED == 1 )
if( NvmmDeclare( &MacNvmCtxDataBlock, mibReq.Param.Contexts->MacNvmCtxSize ) == NVMM_SUCCESS ) if( NvmmDeclare( &MacNvmCtxDataBlock, mibReq.Param.Contexts->MacNvmCtxSize ) == NVMM_SUCCESS )
{ {

View File

@@ -367,13 +367,21 @@ void RegionCN470InitDefaults( InitDefaultsParams_t* params )
} }
// Initialize the channels default mask // Initialize the channels default mask
#if 1 // set your channels
NvmCtx.ChannelsDefaultMask[0] = 0xFFFF; NvmCtx.ChannelsDefaultMask[0] = 0xFFFF;
NvmCtx.ChannelsDefaultMask[1] = 0xFFFF; NvmCtx.ChannelsDefaultMask[1] = 0xFFFF;
NvmCtx.ChannelsDefaultMask[2] = 0xFFFF; NvmCtx.ChannelsDefaultMask[2] = 0xFFFF;
NvmCtx.ChannelsDefaultMask[3] = 0xFFFF; NvmCtx.ChannelsDefaultMask[3] = 0xFFFF;
NvmCtx.ChannelsDefaultMask[4] = 0xFFFF; NvmCtx.ChannelsDefaultMask[4] = 0xFFFF;
NvmCtx.ChannelsDefaultMask[5] = 0xFFFF; NvmCtx.ChannelsDefaultMask[5] = 0xFFFF;
#else
NvmCtx.ChannelsDefaultMask[0] = 0x0000;
NvmCtx.ChannelsDefaultMask[1] = 0x0000;
NvmCtx.ChannelsDefaultMask[2] = 0x0000;
NvmCtx.ChannelsDefaultMask[3] = 0x0000;
NvmCtx.ChannelsDefaultMask[4] = 0x0000;
NvmCtx.ChannelsDefaultMask[5] = 0x00FF;
#endif
// Update the channels mask // Update the channels mask
RegionCommonChanMaskCopy( NvmCtx.ChannelsMask, NvmCtx.ChannelsDefaultMask, 6 ); RegionCommonChanMaskCopy( NvmCtx.ChannelsMask, NvmCtx.ChannelsDefaultMask, 6 );
break; break;

View File

@@ -66,17 +66,17 @@ extern "C" {
* When set to 1 DevEui is LORAWAN_DEVICE_EUI * When set to 1 DevEui is LORAWAN_DEVICE_EUI
* When set to 0 DevEui is automatically set with a value provided by MCU platform * When set to 0 DevEui is automatically set with a value provided by MCU platform
*/ */
#define STATIC_DEVICE_EUI 0 #define STATIC_DEVICE_EUI 1
/*! /*!
* end-device IEEE EUI (big endian) * end-device IEEE EUI (big endian)
*/ */
#define LORAWAN_DEVICE_EUI { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } #define LORAWAN_DEVICE_EUI { 0x8c, 0xf9, 0x57, 0x20, 0x00, 0x00, 0xf7, 0x37}
/*! /*!
* App/Join server IEEE EUI (big endian) * App/Join server IEEE EUI (big endian)
*/ */
#define LORAWAN_JOIN_EUI { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } #define LORAWAN_JOIN_EUI { 0x8c, 0xf9, 0x57, 0x20, 0x00, 0x00, 0xf7, 0x37}
/*! /*!
* Secure-element pin * Secure-element pin
@@ -103,8 +103,8 @@ extern "C" {
* WARNING: FOR 1.0.x DEVICES IT IS THE \ref LORAWAN_GEN_APP_KEY \ * WARNING: FOR 1.0.x DEVICES IT IS THE \ref LORAWAN_GEN_APP_KEY \
*/ \ */ \
.KeyID = APP_KEY, \ .KeyID = APP_KEY, \
.KeyValue = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, \ .KeyValue = { 0x8c, 0xf9, 0x57, 0x20, 0x00, 0x00, 0xf7, 0x37, 0x1e, 0x29, 0xaa, 0xaa, 0xad, 0x20, 0x4a, \
0x3C }, \ 0x72 }, \
}, \ }, \
{ \ { \
/*! \ /*! \
@@ -112,8 +112,8 @@ extern "C" {
* WARNING: FOR 1.0.x DEVICES IT IS THE \ref LORAWAN_APP_KEY \ * WARNING: FOR 1.0.x DEVICES IT IS THE \ref LORAWAN_APP_KEY \
*/ \ */ \
.KeyID = NWK_KEY, \ .KeyID = NWK_KEY, \
.KeyValue = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, \ .KeyValue = { 0x8c, 0xf9, 0x57, 0x20, 0x00, 0x00, 0xf7, 0x37, 0x1e, 0x29, 0xaa, 0xaa, 0xad, 0x20, 0x4a, \
0x3C }, \ 0x72 }, \
}, \ }, \
{ \ { \
/*! \ /*! \
@@ -139,8 +139,8 @@ extern "C" {
* WARNING: NWK_S_KEY FOR 1.0.x DEVICES \ * WARNING: NWK_S_KEY FOR 1.0.x DEVICES \
*/ \ */ \
.KeyID = F_NWK_S_INT_KEY, \ .KeyID = F_NWK_S_INT_KEY, \
.KeyValue = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, \ .KeyValue = { 0x8c, 0xf9, 0x57, 0x20, 0x00, 0x00, 0xf7, 0x37, 0x1e, 0x29, 0xaa, 0xaa, 0xad, 0x20, 0x4a, \
0x3C }, \ 0x72 }, \
}, \ }, \
{ \ { \
/*! \ /*! \
@@ -148,8 +148,8 @@ extern "C" {
* WARNING: NOT USED FOR 1.0.x DEVICES. MUST BE THE SAME AS \ref LORAWAN_F_NWK_S_INT_KEY \ * WARNING: NOT USED FOR 1.0.x DEVICES. MUST BE THE SAME AS \ref LORAWAN_F_NWK_S_INT_KEY \
*/ \ */ \
.KeyID = S_NWK_S_INT_KEY, \ .KeyID = S_NWK_S_INT_KEY, \
.KeyValue = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, \ .KeyValue = { 0x8c, 0xf9, 0x57, 0x20, 0x00, 0x00, 0xf7, 0x37, 0x1e, 0x29, 0xaa, 0xaa, 0xad, 0x20, 0x4a, \
0x3C }, \ 0x72 }, \
}, \ }, \
{ \ { \
/*! \ /*! \
@@ -157,16 +157,16 @@ extern "C" {
* WARNING: NOT USED FOR 1.0.x DEVICES. MUST BE THE SAME AS \ref LORAWAN_F_NWK_S_INT_KEY \ * WARNING: NOT USED FOR 1.0.x DEVICES. MUST BE THE SAME AS \ref LORAWAN_F_NWK_S_INT_KEY \
*/ \ */ \
.KeyID = NWK_S_ENC_KEY, \ .KeyID = NWK_S_ENC_KEY, \
.KeyValue = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, \ .KeyValue = { 0x8c, 0xf9, 0x57, 0x20, 0x00, 0x00, 0xf7, 0x37, 0x1e, 0x29, 0xaa, 0xaa, 0xad, 0x20, 0x4a, \
0x3C }, \ 0x72 }, \
}, \ }, \
{ \ { \
/*! \ /*! \
* Application session key \ * Application session key \
*/ \ */ \
.KeyID = APP_S_KEY, \ .KeyID = APP_S_KEY, \
.KeyValue = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, \ .KeyValue = { 0x8c, 0xf9, 0x57, 0x20, 0x00, 0x00, 0xf7, 0x37, 0x1e, 0x29, 0xaa, 0xaa, 0xad, 0x20, 0x4a, \
0x3C }, \ 0x72 }, \
}, \ }, \
{ \ { \
/*! \ /*! \