fix lorawan class A demo for RHF76_052DM board
LoRaMac-node-4.4.4 demo
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -403,14 +403,9 @@
|
||||
<FilePath>..\apps\common\NvmCtxMgmt.c</FilePath>
|
||||
</File>
|
||||
<File>
|
||||
<FileName>LoRaApi.c</FileName>
|
||||
<FileName>LoRaDemo.c</FileName>
|
||||
<FileType>1</FileType>
|
||||
<FilePath>..\apps\classA\LoRaApi.c</FilePath>
|
||||
</File>
|
||||
<File>
|
||||
<FileName>at_parser.c</FileName>
|
||||
<FileType>1</FileType>
|
||||
<FilePath>..\apps\classA\at_parser.c</FilePath>
|
||||
<FilePath>..\apps\classA\LoRaDemo.c</FilePath>
|
||||
</File>
|
||||
</Files>
|
||||
</Group>
|
||||
@@ -722,11 +717,6 @@
|
||||
<FileType>1</FileType>
|
||||
<FilePath>..\Src\sysIrqHandlers.c</FilePath>
|
||||
</File>
|
||||
<File>
|
||||
<FileName>atcmd-board.c</FileName>
|
||||
<FileType>1</FileType>
|
||||
<FilePath>..\Src\atcmd-board.c</FilePath>
|
||||
</File>
|
||||
</Files>
|
||||
</Group>
|
||||
<Group>
|
||||
|
63
board/RHF76_STM32L072CBxx_Lora/apps/classA/Commissioning.h
Normal file
63
board/RHF76_STM32L072CBxx_Lora/apps/classA/Commissioning.h
Normal 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__
|
@@ -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
|
||||
}
|
@@ -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
|
1184
board/RHF76_STM32L072CBxx_Lora/apps/classA/LoRaDemo.c
Normal file
1184
board/RHF76_STM32L072CBxx_Lora/apps/classA/LoRaDemo.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
}
|
@@ -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
|
@@ -1,98 +1,35 @@
|
||||
#include "LoRaApi.h"
|
||||
#include <stdio.h>
|
||||
#include <string.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>
|
||||
#define TASK1_PRIO 3
|
||||
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ջ<EFBFBD><D5BB>С
|
||||
#define TASK1_STK_SIZE (1024 * 4)
|
||||
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ƿ<EFBFBD>
|
||||
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)
|
||||
k_task_t task1;
|
||||
k_stack_t task1_stack[4096];
|
||||
|
||||
extern int lora_main(void);
|
||||
void task1_fun(void *arg)
|
||||
{
|
||||
g_st_state =2;
|
||||
}
|
||||
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();
|
||||
}
|
||||
lora_main();
|
||||
}
|
||||
|
||||
extern uint8_t sx1276_band;
|
||||
int main(void)
|
||||
{
|
||||
k_err_t err;
|
||||
TOS_CPU_CPSR_ALLOC();
|
||||
BoardInitMcu( );
|
||||
BoardInitPeriph( );
|
||||
sx1276_band = 2;
|
||||
printf("welcome to tencent IoTOS\r\n");
|
||||
err = tos_knl_init(); //<2F><>ʼ<EFBFBD><CABC>TOS
|
||||
printf("Welcome to TencentOS Tiny! \r\n");
|
||||
tos_knl_init();
|
||||
TOS_CPU_INT_DISABLE();
|
||||
err = tos_task_create(&task1,
|
||||
"task1",
|
||||
task1_fun,
|
||||
NULL,
|
||||
3,
|
||||
task1_stack,
|
||||
4096,
|
||||
20);
|
||||
if(err != K_ERR_NONE)
|
||||
{
|
||||
printf("tos init failed\r\n");
|
||||
return err;
|
||||
}
|
||||
TOS_CPU_INT_DISABLE();//<2F><><EFBFBD><EFBFBD><EFBFBD>ٽ<EFBFBD><D9BD><EFBFBD>
|
||||
err = tos_task_create((k_task_t * )&Task1TCB, //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ƿ<EFBFBD>
|
||||
(char * )"task1", //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
(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>
|
||||
printf("TencentOS Tiny Create task1 fail! code : %d \r\n",err);
|
||||
|
||||
TOS_CPU_INT_ENABLE(); //<2F>˳<EFBFBD><CBB3>ٽ<EFBFBD><D9BD><EFBFBD>
|
||||
tos_knl_start(); //<2F><><EFBFBD><EFBFBD>TOS
|
||||
while (1)
|
||||
{
|
||||
|
||||
}
|
||||
TOS_CPU_INT_ENABLE();
|
||||
tos_knl_start();
|
||||
}
|
||||
|
||||
|
257
board/RHF76_STM32L072CBxx_Lora/apps/common/CayenneLpp.c
Normal file
257
board/RHF76_STM32L072CBxx_Lora/apps/common/CayenneLpp.c
Normal 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;
|
||||
}
|
76
board/RHF76_STM32L072CBxx_Lora/apps/common/CayenneLpp.h
Normal file
76
board/RHF76_STM32L072CBxx_Lora/apps/common/CayenneLpp.h
Normal 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__
|
1011
board/RHF76_STM32L072CBxx_Lora/apps/common/LmHandler/LmHandler.c
Normal file
1011
board/RHF76_STM32L072CBxx_Lora/apps/common/LmHandler/LmHandler.c
Normal file
File diff suppressed because it is too large
Load Diff
335
board/RHF76_STM32L072CBxx_Lora/apps/common/LmHandler/LmHandler.h
Normal file
335
board/RHF76_STM32L072CBxx_Lora/apps/common/LmHandler/LmHandler.h
Normal 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__
|
@@ -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__
|
@@ -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++;
|
||||
}
|
||||
}
|
||||
}
|
@@ -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__
|
@@ -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__
|
@@ -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 );
|
||||
}
|
@@ -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__
|
@@ -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;
|
||||
}
|
@@ -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__
|
@@ -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 );
|
||||
}
|
||||
}
|
||||
}
|
@@ -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__
|
@@ -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;
|
||||
}
|
@@ -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__
|
434
board/RHF76_STM32L072CBxx_Lora/apps/common/LmHandlerMsgDisplay.c
Normal file
434
board/RHF76_STM32L072CBxx_Lora/apps/common/LmHandlerMsgDisplay.c
Normal 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" );
|
||||
}
|
102
board/RHF76_STM32L072CBxx_Lora/apps/common/LmHandlerMsgDisplay.h
Normal file
102
board/RHF76_STM32L072CBxx_Lora/apps/common/LmHandlerMsgDisplay.h
Normal 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__
|
@@ -112,7 +112,6 @@ LoRaMacCtxUpdateStatus_t CtxUpdateStatus = { .Value = 0 };
|
||||
/*
|
||||
* Nvmm handles
|
||||
*/
|
||||
static NvmmDataBlock_t FCntHandlerNvmCtxDataBlock;
|
||||
static NvmmDataBlock_t SecureElementNvmCtxDataBlock;
|
||||
static NvmmDataBlock_t CryptoNvmCtxDataBlock;
|
||||
#if ( MAX_PERSISTENT_CTX_MGMT_ENABLED == 1 )
|
||||
@@ -164,11 +163,6 @@ void NvmCtxMgmtEvent( LoRaMacNvmCtxModule_t module )
|
||||
CtxUpdateStatus.Elements.ConfirmQueue = 1;
|
||||
break;
|
||||
}
|
||||
case LORAMAC_NVMCTXMODULE_FCNT_HANDLER:
|
||||
{
|
||||
CtxUpdateStatus.Elements.FCntHandlerNvmCtx = 1;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
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( CtxUpdateStatus.Elements.Mac == 1 )
|
||||
{
|
||||
@@ -288,7 +274,6 @@ NvmCtxMgmtStatus_t NvmCtxMgmtRestore( void )
|
||||
|
||||
uint8_t NvmCryptoCtxRestore[mibReq.Param.Contexts->CryptoNvmCtxSize];
|
||||
uint8_t NvmSecureElementCtxRestore[mibReq.Param.Contexts->SecureElementNvmCtxSize];
|
||||
uint8_t NvmFCntHandlerCtxRestore[mibReq.Param.Contexts->FCntHandlerNvmCtxSize];
|
||||
#if ( MAX_PERSISTENT_CTX_MGMT_ENABLED == 1 )
|
||||
uint8_t NvmMacCtxRestore[mibReq.Param.Contexts->MacNvmCtxSize];
|
||||
uint8_t NvmRegionCtxRestore[mibReq.Param.Contexts->RegionNvmCtxSize];
|
||||
@@ -319,17 +304,6 @@ NvmCtxMgmtStatus_t NvmCtxMgmtRestore( void )
|
||||
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( NvmmDeclare( &MacNvmCtxDataBlock, mibReq.Param.Contexts->MacNvmCtxSize ) == NVMM_SUCCESS )
|
||||
{
|
||||
|
@@ -367,13 +367,21 @@ void RegionCN470InitDefaults( InitDefaultsParams_t* params )
|
||||
}
|
||||
|
||||
// Initialize the channels default mask
|
||||
#if 1 // set your channels
|
||||
NvmCtx.ChannelsDefaultMask[0] = 0xFFFF;
|
||||
NvmCtx.ChannelsDefaultMask[1] = 0xFFFF;
|
||||
NvmCtx.ChannelsDefaultMask[2] = 0xFFFF;
|
||||
NvmCtx.ChannelsDefaultMask[3] = 0xFFFF;
|
||||
NvmCtx.ChannelsDefaultMask[4] = 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
|
||||
RegionCommonChanMaskCopy( NvmCtx.ChannelsMask, NvmCtx.ChannelsDefaultMask, 6 );
|
||||
break;
|
||||
|
@@ -66,17 +66,17 @@ extern "C" {
|
||||
* When set to 1 DevEui is LORAWAN_DEVICE_EUI
|
||||
* 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)
|
||||
*/
|
||||
#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)
|
||||
*/
|
||||
#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
|
||||
@@ -103,8 +103,8 @@ extern "C" {
|
||||
* WARNING: FOR 1.0.x DEVICES IT IS THE \ref LORAWAN_GEN_APP_KEY \
|
||||
*/ \
|
||||
.KeyID = APP_KEY, \
|
||||
.KeyValue = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, \
|
||||
0x3C }, \
|
||||
.KeyValue = { 0x8c, 0xf9, 0x57, 0x20, 0x00, 0x00, 0xf7, 0x37, 0x1e, 0x29, 0xaa, 0xaa, 0xad, 0x20, 0x4a, \
|
||||
0x72 }, \
|
||||
}, \
|
||||
{ \
|
||||
/*! \
|
||||
@@ -112,8 +112,8 @@ extern "C" {
|
||||
* WARNING: FOR 1.0.x DEVICES IT IS THE \ref LORAWAN_APP_KEY \
|
||||
*/ \
|
||||
.KeyID = NWK_KEY, \
|
||||
.KeyValue = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, \
|
||||
0x3C }, \
|
||||
.KeyValue = { 0x8c, 0xf9, 0x57, 0x20, 0x00, 0x00, 0xf7, 0x37, 0x1e, 0x29, 0xaa, 0xaa, 0xad, 0x20, 0x4a, \
|
||||
0x72 }, \
|
||||
}, \
|
||||
{ \
|
||||
/*! \
|
||||
@@ -139,8 +139,8 @@ extern "C" {
|
||||
* WARNING: NWK_S_KEY FOR 1.0.x DEVICES \
|
||||
*/ \
|
||||
.KeyID = F_NWK_S_INT_KEY, \
|
||||
.KeyValue = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, \
|
||||
0x3C }, \
|
||||
.KeyValue = { 0x8c, 0xf9, 0x57, 0x20, 0x00, 0x00, 0xf7, 0x37, 0x1e, 0x29, 0xaa, 0xaa, 0xad, 0x20, 0x4a, \
|
||||
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 \
|
||||
*/ \
|
||||
.KeyID = S_NWK_S_INT_KEY, \
|
||||
.KeyValue = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, \
|
||||
0x3C }, \
|
||||
.KeyValue = { 0x8c, 0xf9, 0x57, 0x20, 0x00, 0x00, 0xf7, 0x37, 0x1e, 0x29, 0xaa, 0xaa, 0xad, 0x20, 0x4a, \
|
||||
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 \
|
||||
*/ \
|
||||
.KeyID = NWK_S_ENC_KEY, \
|
||||
.KeyValue = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, \
|
||||
0x3C }, \
|
||||
.KeyValue = { 0x8c, 0xf9, 0x57, 0x20, 0x00, 0x00, 0xf7, 0x37, 0x1e, 0x29, 0xaa, 0xaa, 0xad, 0x20, 0x4a, \
|
||||
0x72 }, \
|
||||
}, \
|
||||
{ \
|
||||
/*! \
|
||||
* Application session key \
|
||||
*/ \
|
||||
.KeyID = APP_S_KEY, \
|
||||
.KeyValue = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, \
|
||||
0x3C }, \
|
||||
.KeyValue = { 0x8c, 0xf9, 0x57, 0x20, 0x00, 0x00, 0xf7, 0x37, 0x1e, 0x29, 0xaa, 0xaa, 0xad, 0x20, 0x4a, \
|
||||
0x72 }, \
|
||||
}, \
|
||||
{ \
|
||||
/*! \
|
||||
|
Reference in New Issue
Block a user