779 lines
33 KiB
C
779 lines
33 KiB
C
/*!
|
|
* \file LmhpRemoteMcastSetup.c
|
|
*
|
|
* \brief Implements the LoRa-Alliance remote multicast setup package
|
|
* Specification V1.0.0: https://resources.lora-alliance.org/technical-specifications/lorawan-remote-multicast-setup-specification-v1-0-0
|
|
* Specification V2.0.0: https://resources.lora-alliance.org/technical-specifications/ts005-2-0-0-remote-multicast-setup
|
|
*
|
|
* \copyright Revised BSD License, see section \ref LICENSE.
|
|
*
|
|
* \code
|
|
* ______ _
|
|
* / _____) _ | |
|
|
* ( (____ _____ ____ _| |_ _____ ____| |__
|
|
* \____ \| ___ | (_ _) ___ |/ ___) _ \
|
|
* _____) ) ____| | | || |_| ____( (___| | | |
|
|
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
|
|
* (C)2013-2018 Semtech
|
|
*
|
|
* \endcode
|
|
*
|
|
* \author Miguel Luis ( Semtech )
|
|
*/
|
|
/**
|
|
******************************************************************************
|
|
*
|
|
* Portions COPYRIGHT 2020 STMicroelectronics
|
|
*
|
|
* @file LmhpRemoteMcastSetup.c
|
|
* @author MCD Application Team
|
|
* @brief Remote Multicast Package definition
|
|
******************************************************************************
|
|
*/
|
|
/* Includes ------------------------------------------------------------------*/
|
|
#include "LoRaMac.h"
|
|
#include "LmHandler.h"
|
|
#include "LmhpRemoteMcastSetup.h"
|
|
#include "mw_log_conf.h" /* needed for MW_LOG */
|
|
|
|
/*!
|
|
* LoRaWAN Application Layer Remote multicast setup Specification
|
|
*/
|
|
#define REMOTE_MCAST_SETUP_PORT 200
|
|
|
|
#define REMOTE_MCAST_SETUP_ID 2
|
|
|
|
#if (LORAWAN_PACKAGES_VERSION == 1)
|
|
#define REMOTE_MCAST_SETUP_VERSION 1
|
|
#elif (LORAWAN_PACKAGES_VERSION == 2)
|
|
#define REMOTE_MCAST_SETUP_VERSION 2
|
|
#endif /* LORAWAN_PACKAGES_VERSION */
|
|
|
|
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 IsTxPending;
|
|
LmhpRemoteMcastSetupSessionStates_t SessionState;
|
|
uint8_t ID;
|
|
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 if a package transmission is pending or not.
|
|
*
|
|
* \retval status Package transmission status
|
|
* [true: pending, false: Not pending]
|
|
*/
|
|
static bool LmhpRemoteMcastSetupIsTxPending( 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 );
|
|
|
|
#if ( LORAMAC_MAX_MC_CTX > 0 )
|
|
static void OnSessionStartTimer0( void *context );
|
|
static void OnSessionStopTimer0( void *context );
|
|
#endif /* LORAMAC_MAX_MC_CTX > 0 */
|
|
#if ( LORAMAC_MAX_MC_CTX > 1 )
|
|
static void OnSessionStartTimer1( void *context );
|
|
static void OnSessionStopTimer1( void *context );
|
|
#endif /* LORAMAC_MAX_MC_CTX > 1 */
|
|
#if ( LORAMAC_MAX_MC_CTX > 2 )
|
|
static void OnSessionStartTimer2( void *context );
|
|
static void OnSessionStopTimer2( void *context );
|
|
#endif /* LORAMAC_MAX_MC_CTX > 2 */
|
|
#if ( LORAMAC_MAX_MC_CTX > 3 )
|
|
static void OnSessionStartTimer3( void *context );
|
|
static void OnSessionStopTimer3( void *context );
|
|
#endif /* LORAMAC_MAX_MC_CTX > 3 */
|
|
|
|
static LmhpRemoteMcastSetupState_t LmhpRemoteMcastSetupState =
|
|
{
|
|
.Initialized = false,
|
|
.IsTxPending = false,
|
|
.SessionState = REMOTE_MCAST_SETUP_SESSION_STATE_IDLE,
|
|
.ID = 0xFF,
|
|
};
|
|
|
|
typedef struct McGroupData_s
|
|
{
|
|
uint8_t McGroupEnabled;
|
|
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_STOPPED,
|
|
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;
|
|
|
|
static McSessionData_t McSessionData[LORAMAC_MAX_MC_CTX];
|
|
|
|
/*!
|
|
* Session start timer
|
|
*/
|
|
static TimerEvent_t SessionStartTimer[LORAMAC_MAX_MC_CTX];
|
|
|
|
/*!
|
|
* Session start timer
|
|
*/
|
|
static TimerEvent_t SessionStopTimer[LORAMAC_MAX_MC_CTX];
|
|
|
|
static LmhPackage_t LmhpRemoteMcastSetupPackage =
|
|
{
|
|
.Port = REMOTE_MCAST_SETUP_PORT,
|
|
.Init = LmhpRemoteMcastSetupInit,
|
|
.IsInitialized = LmhpRemoteMcastSetupIsInitialized,
|
|
.IsTxPending = LmhpRemoteMcastSetupIsTxPending,
|
|
.Process = LmhpRemoteMcastSetupProcess,
|
|
.OnPackageProcessEvent = NULL, /* To be initialized by LmHandler */
|
|
.OnMcpsConfirmProcess = NULL, /* Not used in this package */
|
|
.OnMcpsIndicationProcess = LmhpRemoteMcastSetupOnMcpsIndication,
|
|
.OnMlmeConfirmProcess = NULL, /* Not used in this package */
|
|
.OnMlmeIndicationProcess = NULL, /* Not used in this package */
|
|
.OnJoinRequest = NULL, /* To be initialized by LmHandler */
|
|
.OnDeviceTimeRequest = NULL, /* To be initialized by LmHandler */
|
|
.OnSysTimeUpdate = NULL, /* To be initialized by LmHandler */
|
|
#if (defined( LORAMAC_VERSION ) && (( LORAMAC_VERSION == 0x01000400 ) || ( LORAMAC_VERSION == 0x01010100 )))
|
|
.OnSystemReset = NULL, /* To be initialized by LmHandler */
|
|
#endif /* LORAMAC_VERSION */
|
|
};
|
|
|
|
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;
|
|
#if ( LORAMAC_MAX_MC_CTX > 0 )
|
|
TimerInit( &SessionStartTimer[0], OnSessionStartTimer0 );
|
|
TimerInit( &SessionStopTimer[0], OnSessionStopTimer0 );
|
|
#endif /* LORAMAC_MAX_MC_CTX > 0 */
|
|
#if ( LORAMAC_MAX_MC_CTX > 1 )
|
|
TimerInit( &SessionStartTimer[1], OnSessionStartTimer1 );
|
|
TimerInit( &SessionStopTimer[1], OnSessionStopTimer1 );
|
|
#endif /* LORAMAC_MAX_MC_CTX > 1 */
|
|
#if ( LORAMAC_MAX_MC_CTX > 2 )
|
|
TimerInit( &SessionStartTimer[2], OnSessionStartTimer2 );
|
|
TimerInit( &SessionStopTimer[2], OnSessionStopTimer2 );
|
|
#endif /* LORAMAC_MAX_MC_CTX > 2 */
|
|
#if ( LORAMAC_MAX_MC_CTX > 3 )
|
|
TimerInit( &SessionStartTimer[3], OnSessionStartTimer3 );
|
|
TimerInit( &SessionStopTimer[3], OnSessionStopTimer3 );
|
|
#endif /* LORAMAC_MAX_MC_CTX > 3 */
|
|
}
|
|
else
|
|
{
|
|
LmhpRemoteMcastSetupState.Initialized = false;
|
|
}
|
|
LmhpRemoteMcastSetupState.IsTxPending = false;
|
|
|
|
for( uint8_t id = 0; id < LORAMAC_MAX_MC_CTX; id++ )
|
|
{
|
|
McSessionData[id].McGroupData.McGroupEnabled = false;
|
|
}
|
|
}
|
|
|
|
static bool LmhpRemoteMcastSetupIsInitialized( void )
|
|
{
|
|
return LmhpRemoteMcastSetupState.Initialized;
|
|
}
|
|
|
|
static bool LmhpRemoteMcastSetupIsTxPending( void )
|
|
{
|
|
return LmhpRemoteMcastSetupState.IsTxPending;
|
|
}
|
|
|
|
static void LmhpRemoteMcastSetupProcess( void )
|
|
{
|
|
LmhpRemoteMcastSetupSessionStates_t state;
|
|
uint8_t id;
|
|
bool active_session = false;
|
|
DeviceClass_t deviceClass = CLASS_A;
|
|
|
|
CRITICAL_SECTION_BEGIN( );
|
|
state = LmhpRemoteMcastSetupState.SessionState;
|
|
id = LmhpRemoteMcastSetupState.ID;
|
|
CRITICAL_SECTION_END( );
|
|
|
|
switch( state )
|
|
{
|
|
case REMOTE_MCAST_SETUP_SESSION_STATE_START:
|
|
|
|
LmHandlerGetCurrentClass( &deviceClass );
|
|
if( ( ( McSessionData[id].RxParams.Class == CLASS_B ) && ( deviceClass == CLASS_C ) ) ||
|
|
( ( McSessionData[id].RxParams.Class == CLASS_C ) && ( deviceClass == CLASS_B ) ) )
|
|
{
|
|
LmhpRemoteMcastSetupState.SessionState = REMOTE_MCAST_SETUP_SESSION_STATE_IDLE;
|
|
}
|
|
else
|
|
{
|
|
/* Switch to Class B or C */
|
|
if( LmHandlerRequestClass( McSessionData[id].RxParams.Class ) == LORAMAC_HANDLER_SUCCESS )
|
|
{
|
|
LmhpRemoteMcastSetupState.SessionState = REMOTE_MCAST_SETUP_SESSION_STATE_IDLE;
|
|
|
|
if( McSessionData[id].RxParams.Class == CLASS_B )
|
|
{
|
|
TimerSetValue( &SessionStopTimer[id], ( 1 << McSessionData[id].SessionTimeout ) * 1000 * 128 );
|
|
}
|
|
else /* CLASS_C */
|
|
{
|
|
TimerSetValue( &SessionStopTimer[id], ( 1 << McSessionData[id].SessionTimeout ) * 1000 );
|
|
}
|
|
TimerStart( &SessionStopTimer[id] );
|
|
}
|
|
else
|
|
{
|
|
TimerSetValue( &SessionStartTimer[id], 1000 );
|
|
TimerStart( &SessionStartTimer[id] );
|
|
}
|
|
}
|
|
break;
|
|
case REMOTE_MCAST_SETUP_SESSION_STATE_STOP:
|
|
for( uint8_t id_index = 0; id_index < LORAMAC_MAX_MC_CTX; id_index++ )
|
|
{
|
|
if( McSessionData[id_index].SessionState == SESSION_STARTED )
|
|
{
|
|
active_session = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( active_session == false )
|
|
{
|
|
/* Switch back to Class A */
|
|
if( LmHandlerRequestClass( CLASS_A ) == LORAMAC_HANDLER_SUCCESS )
|
|
{
|
|
LmhpRemoteMcastSetupState.SessionState = REMOTE_MCAST_SETUP_SESSION_STATE_IDLE;
|
|
}
|
|
else
|
|
{
|
|
TimerSetValue( &SessionStopTimer[id], 1000 );
|
|
TimerStart( &SessionStopTimer[id] );
|
|
}
|
|
}
|
|
break;
|
|
case REMOTE_MCAST_SETUP_SESSION_STATE_IDLE:
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void LmhpRemoteMcastSetupOnMcpsIndication( McpsIndication_t *mcpsIndication )
|
|
{
|
|
uint8_t cmdIndex = 0;
|
|
uint8_t dataBufferIndex = 0;
|
|
uint8_t id = 0xFF;
|
|
|
|
if( mcpsIndication->Port != REMOTE_MCAST_SETUP_PORT )
|
|
{
|
|
return;
|
|
}
|
|
|
|
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:
|
|
{
|
|
uint8_t nbAvailableGroups = 0;
|
|
uint8_t reqGroupMask = mcpsIndication->Buffer[cmdIndex++] & 0x0F;
|
|
uint8_t AnsGroupMask = 0x00;
|
|
|
|
LmhpRemoteMcastSetupState.DataBuffer[dataBufferIndex++] = REMOTE_MCAST_SETUP_MC_GROUP_STATUS_ANS;
|
|
|
|
/* move index to the next first optional list */
|
|
dataBufferIndex++;
|
|
for( id = 0; id < LORAMAC_MAX_MC_CTX; id++ )
|
|
{
|
|
if( McSessionData[id].McGroupData.McGroupEnabled )
|
|
{
|
|
nbAvailableGroups++;
|
|
|
|
/* If multicast group defined in the input bit mask */
|
|
if( ( reqGroupMask & ( 1 << id ) ) != 0 )
|
|
{
|
|
AnsGroupMask |= ( 1 << id );
|
|
LmhpRemoteMcastSetupState.DataBuffer[dataBufferIndex++] = id;
|
|
LmhpRemoteMcastSetupState.DataBuffer[dataBufferIndex++] = ( McSessionData[id].McGroupData.McAddr >> 0 ) & 0xFF;
|
|
LmhpRemoteMcastSetupState.DataBuffer[dataBufferIndex++] = ( McSessionData[id].McGroupData.McAddr >> 8 ) & 0xFF;
|
|
LmhpRemoteMcastSetupState.DataBuffer[dataBufferIndex++] = ( McSessionData[id].McGroupData.McAddr >> 16 ) & 0xFF;
|
|
LmhpRemoteMcastSetupState.DataBuffer[dataBufferIndex++] = ( McSessionData[id].McGroupData.McAddr >> 24 ) & 0xFF;
|
|
}
|
|
}
|
|
}
|
|
/* set the status bit */
|
|
LmhpRemoteMcastSetupState.DataBuffer[1] = ( nbAvailableGroups & 0x07 ) << 4 | ( AnsGroupMask & 0x0F );
|
|
|
|
break;
|
|
}
|
|
case REMOTE_MCAST_SETUP_MC_GROUP_SETUP_REQ:
|
|
{
|
|
uint8_t idError = 0x01; /* One bit value */
|
|
id = mcpsIndication->Buffer[cmdIndex++] & 0x03;
|
|
|
|
McSessionData[id].McGroupData.IdHeader.Value = id;
|
|
|
|
if( id < LORAMAC_MAX_MC_CTX )
|
|
{
|
|
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,
|
|
.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.Params.ClassC = /* Field not used for multicast channel setup. Must be initialized to something */
|
|
{
|
|
.Frequency = 0,
|
|
.Datarate = 0
|
|
}
|
|
};
|
|
|
|
if( LoRaMacMcChannelSetup( &channel ) == LORAMAC_STATUS_OK )
|
|
{
|
|
idError = 0x00;
|
|
McSessionData[id].McGroupData.McGroupEnabled = true;
|
|
}
|
|
}
|
|
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;
|
|
id = mcpsIndication->Buffer[cmdIndex++] & 0x03;
|
|
|
|
status = id;
|
|
McSessionData[id].McGroupData.IdHeader.Value = 0;
|
|
McSessionData[id].McGroupData.McAddr = 0;
|
|
memset1( McSessionData[id].McGroupData.McKeyEncrypted, 0x00, 16 );
|
|
McSessionData[id].McGroupData.McFCountMin = 0;
|
|
McSessionData[id].McGroupData.McFCountMax = 0;
|
|
|
|
LmhpRemoteMcastSetupState.DataBuffer[dataBufferIndex++] = REMOTE_MCAST_SETUP_MC_GROUP_DELETE_ANS;
|
|
|
|
if( LoRaMacMcChannelDelete( ( AddressIdentifier_t )id ) != LORAMAC_STATUS_OK )
|
|
{
|
|
status |= 0x04; /* McGroupUndefined bit set */
|
|
}
|
|
else
|
|
{
|
|
McSessionData[id].McGroupData.McGroupEnabled = false;
|
|
}
|
|
LmhpRemoteMcastSetupState.DataBuffer[dataBufferIndex++] = status;
|
|
break;
|
|
}
|
|
case REMOTE_MCAST_SETUP_MC_GROUP_CLASS_C_SESSION_REQ:
|
|
{
|
|
bool isTimerSet = false;
|
|
int32_t timeToSessionStart = 0;
|
|
uint8_t status = 0x00;
|
|
id = mcpsIndication->Buffer[cmdIndex++] & 0x03;
|
|
|
|
if( id < LORAMAC_MAX_MC_CTX )
|
|
{
|
|
McSessionData[id].RxParams.Class = CLASS_C;
|
|
|
|
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 epoch 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.Params.ClassC.Frequency = ( mcpsIndication->Buffer[cmdIndex++] << 0 ) & 0x000000FF;
|
|
McSessionData[id].RxParams.Params.ClassC.Frequency |= ( mcpsIndication->Buffer[cmdIndex++] << 8 ) & 0x0000FF00;
|
|
McSessionData[id].RxParams.Params.ClassC.Frequency |= ( mcpsIndication->Buffer[cmdIndex++] << 16 ) & 0x00FF0000;
|
|
McSessionData[id].RxParams.Params.ClassC.Frequency *= 100;
|
|
McSessionData[id].RxParams.Params.ClassC.Datarate = mcpsIndication->Buffer[cmdIndex++];
|
|
|
|
if( LoRaMacMcChannelSetupRxParams( ( AddressIdentifier_t )id, &McSessionData[id].RxParams,
|
|
&status ) == LORAMAC_STATUS_OK )
|
|
{
|
|
SysTime_t curTime = { .Seconds = 0, .SubSeconds = 0 };
|
|
curTime = SysTimeGet( );
|
|
|
|
timeToSessionStart = McSessionData[id].SessionTime - curTime.Seconds;
|
|
if( timeToSessionStart > 0 )
|
|
{
|
|
/* Start session start timer */
|
|
TimerSetValue( &SessionStartTimer[id], timeToSessionStart * 1000 );
|
|
TimerStart( &SessionStartTimer[id] );
|
|
|
|
isTimerSet = true;
|
|
|
|
MW_LOG( TS_OFF, VLEVEL_M, "Time2SessionStart: %d ms\r\n", timeToSessionStart * 1000 );
|
|
}
|
|
else
|
|
{
|
|
/* Session start time before current device time */
|
|
status |= 0x10; /* McGroupUndefined bit set */
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
status |= 0x10; /* McGroupUndefined bit set */
|
|
}
|
|
|
|
LmhpRemoteMcastSetupState.DataBuffer[dataBufferIndex++] = REMOTE_MCAST_SETUP_MC_GROUP_CLASS_C_SESSION_ANS;
|
|
LmhpRemoteMcastSetupState.DataBuffer[dataBufferIndex++] = status;
|
|
if( isTimerSet == true )
|
|
{
|
|
LmhpRemoteMcastSetupState.DataBuffer[dataBufferIndex++] = ( timeToSessionStart >> 0 ) & 0xFF;
|
|
LmhpRemoteMcastSetupState.DataBuffer[dataBufferIndex++] = ( timeToSessionStart >> 8 ) & 0xFF;
|
|
LmhpRemoteMcastSetupState.DataBuffer[dataBufferIndex++] = ( timeToSessionStart >> 16 ) & 0xFF;
|
|
}
|
|
break;
|
|
}
|
|
case REMOTE_MCAST_SETUP_MC_GROUP_CLASS_B_SESSION_REQ:
|
|
{
|
|
bool isTimerSet = false;
|
|
int32_t timeToSessionStart = 0;
|
|
uint8_t status = 0x00;
|
|
id = mcpsIndication->Buffer[cmdIndex++] & 0x03;
|
|
|
|
if( id < LORAMAC_MAX_MC_CTX )
|
|
{
|
|
McSessionData[id].RxParams.Class = CLASS_B;
|
|
|
|
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 epoch offset. The system time is based on Unix time. */
|
|
McSessionData[id].SessionTime += UNIX_GPS_EPOCH_OFFSET;
|
|
|
|
McSessionData[id].RxParams.Params.ClassB.Periodicity = ( mcpsIndication->Buffer[cmdIndex] >> 4 ) & 0x07;
|
|
McSessionData[id].SessionTimeout = mcpsIndication->Buffer[cmdIndex++] & 0x0F;
|
|
|
|
McSessionData[id].RxParams.Params.ClassB.Frequency = ( mcpsIndication->Buffer[cmdIndex++] << 0 ) & 0x000000FF;
|
|
McSessionData[id].RxParams.Params.ClassB.Frequency |= ( mcpsIndication->Buffer[cmdIndex++] << 8 ) & 0x0000FF00;
|
|
McSessionData[id].RxParams.Params.ClassB.Frequency |= ( mcpsIndication->Buffer[cmdIndex++] << 16 ) & 0x00FF0000;
|
|
McSessionData[id].RxParams.Params.ClassB.Frequency *= 100;
|
|
McSessionData[id].RxParams.Params.ClassB.Datarate = mcpsIndication->Buffer[cmdIndex++];
|
|
|
|
if( LoRaMacMcChannelSetupRxParams( ( AddressIdentifier_t )id, &McSessionData[id].RxParams,
|
|
&status ) == LORAMAC_STATUS_OK )
|
|
{
|
|
SysTime_t curTime = { .Seconds = 0, .SubSeconds = 0 };
|
|
curTime = SysTimeGet( );
|
|
|
|
timeToSessionStart = McSessionData[id].SessionTime - curTime.Seconds;
|
|
if( timeToSessionStart > 0 )
|
|
{
|
|
/* Start session start timer */
|
|
TimerSetValue( &SessionStartTimer[id], timeToSessionStart * 1000 );
|
|
TimerStart( &SessionStartTimer[id] );
|
|
|
|
isTimerSet = true;
|
|
|
|
MW_LOG( TS_OFF, VLEVEL_M, "Time2SessionStart: %d ms\r\n", timeToSessionStart * 1000 );
|
|
}
|
|
else
|
|
{
|
|
/* Session start time before current device time */
|
|
status |= 0x10; /* McGroupUndefined bit set */
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
status |= 0x10; /* McGroupUndefined bit set */
|
|
}
|
|
|
|
LmhpRemoteMcastSetupState.DataBuffer[dataBufferIndex++] = REMOTE_MCAST_SETUP_MC_GROUP_CLASS_B_SESSION_ANS;
|
|
LmhpRemoteMcastSetupState.DataBuffer[dataBufferIndex++] = status;
|
|
if( isTimerSet == true )
|
|
{
|
|
LmhpRemoteMcastSetupState.DataBuffer[dataBufferIndex++] = ( timeToSessionStart >> 0 ) & 0xFF;
|
|
LmhpRemoteMcastSetupState.DataBuffer[dataBufferIndex++] = ( timeToSessionStart >> 8 ) & 0xFF;
|
|
LmhpRemoteMcastSetupState.DataBuffer[dataBufferIndex++] = ( timeToSessionStart >> 16 ) & 0xFF;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( dataBufferIndex != 0 )
|
|
{
|
|
/* Answer commands */
|
|
LmHandlerAppData_t appData =
|
|
{
|
|
.Buffer = LmhpRemoteMcastSetupState.DataBuffer,
|
|
.BufferSize = dataBufferIndex,
|
|
.Port = REMOTE_MCAST_SETUP_PORT
|
|
};
|
|
|
|
bool current_dutycycle;
|
|
LmHandlerGetDutyCycleEnable( ¤t_dutycycle );
|
|
|
|
/* force Duty Cycle OFF to this Send */
|
|
LmHandlerSetDutyCycleEnable( false );
|
|
LmHandlerSend( &appData, LORAMAC_HANDLER_UNCONFIRMED_MSG, true );
|
|
|
|
/* restore initial Duty Cycle */
|
|
LmHandlerSetDutyCycleEnable( current_dutycycle );
|
|
|
|
if( id != 0xFF && id < LORAMAC_MAX_MC_CTX )
|
|
{
|
|
MW_LOG( TS_OFF, VLEVEL_M, "ID : %d\r\n", McSessionData[id].McGroupData.IdHeader.Fields.McGroupId );
|
|
MW_LOG( TS_OFF, VLEVEL_M, "McAddr : %08X\r\n", McSessionData[id].McGroupData.McAddr );
|
|
MW_LOG( TS_OFF, VLEVEL_M, "McKey : %02X", McSessionData[id].McGroupData.McKeyEncrypted[0] );
|
|
for( int32_t i = 1; i < 16; i++ )
|
|
{
|
|
MW_LOG( TS_OFF, VLEVEL_M, "-%02X", McSessionData[id].McGroupData.McKeyEncrypted[i] );
|
|
}
|
|
MW_LOG( TS_OFF, VLEVEL_M, "\r\n" );
|
|
MW_LOG( TS_OFF, VLEVEL_M, "McFCountMin : %u\r\n", McSessionData[id].McGroupData.McFCountMin );
|
|
MW_LOG( TS_OFF, VLEVEL_M, "McFCountMax : %u\r\n", McSessionData[id].McGroupData.McFCountMax );
|
|
MW_LOG( TS_OFF, VLEVEL_M, "SessionTime : %u\r\n", McSessionData[id].SessionTime );
|
|
MW_LOG( TS_OFF, VLEVEL_M, "SessionTimeT: %d s\r\n", ( 1 << McSessionData[id].SessionTimeout ) );
|
|
if( McSessionData[id].RxParams.Class == CLASS_B )
|
|
{
|
|
MW_LOG( TS_OFF, VLEVEL_M, "Rx Freq : %u\r\n", McSessionData[id].RxParams.Params.ClassB.Frequency );
|
|
MW_LOG( TS_OFF, VLEVEL_M, "Rx DR : DR_%d\r\n", McSessionData[id].RxParams.Params.ClassB.Datarate );
|
|
MW_LOG( TS_OFF, VLEVEL_M, "Periodicity : %u\r\n", McSessionData[id].RxParams.Params.ClassB.Periodicity );
|
|
}
|
|
else
|
|
{
|
|
MW_LOG( TS_OFF, VLEVEL_M, "Rx Freq : %u\r\n", McSessionData[id].RxParams.Params.ClassC.Frequency );
|
|
MW_LOG( TS_OFF, VLEVEL_M, "Rx DR : DR_%d\r\n", McSessionData[id].RxParams.Params.ClassC.Datarate );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#if ( LORAMAC_MAX_MC_CTX > 0 )
|
|
static void OnSessionStartTimer0( void *context )
|
|
{
|
|
TimerStop( &SessionStartTimer[0] );
|
|
|
|
McSessionData[0].SessionState = SESSION_STARTED;
|
|
LmhpRemoteMcastSetupState.ID = 0;
|
|
LmhpRemoteMcastSetupState.SessionState = REMOTE_MCAST_SETUP_SESSION_STATE_START;
|
|
if( LmhpRemoteMcastSetupPackage.OnPackageProcessEvent != NULL )
|
|
{
|
|
LmhpRemoteMcastSetupPackage.OnPackageProcessEvent();
|
|
}
|
|
}
|
|
|
|
static void OnSessionStopTimer0( void *context )
|
|
{
|
|
TimerStop( &SessionStopTimer[0] );
|
|
|
|
McSessionData[0].SessionState = SESSION_STOPPED;
|
|
LmhpRemoteMcastSetupState.ID = 0;
|
|
LmhpRemoteMcastSetupState.SessionState = REMOTE_MCAST_SETUP_SESSION_STATE_STOP;
|
|
if( LmhpRemoteMcastSetupPackage.OnPackageProcessEvent != NULL )
|
|
{
|
|
LmhpRemoteMcastSetupPackage.OnPackageProcessEvent();
|
|
}
|
|
}
|
|
#endif /* LORAMAC_MAX_MC_CTX > 0 */
|
|
#if ( LORAMAC_MAX_MC_CTX > 1 )
|
|
static void OnSessionStartTimer1( void *context )
|
|
{
|
|
TimerStop( &SessionStartTimer[1] );
|
|
|
|
McSessionData[1].SessionState = SESSION_STARTED;
|
|
LmhpRemoteMcastSetupState.ID = 1;
|
|
LmhpRemoteMcastSetupState.SessionState = REMOTE_MCAST_SETUP_SESSION_STATE_START;
|
|
if( LmhpRemoteMcastSetupPackage.OnPackageProcessEvent != NULL )
|
|
{
|
|
LmhpRemoteMcastSetupPackage.OnPackageProcessEvent();
|
|
}
|
|
}
|
|
|
|
static void OnSessionStopTimer1( void *context )
|
|
{
|
|
TimerStop( &SessionStopTimer[1] );
|
|
|
|
McSessionData[1].SessionState = SESSION_STOPPED;
|
|
LmhpRemoteMcastSetupState.ID = 1;
|
|
LmhpRemoteMcastSetupState.SessionState = REMOTE_MCAST_SETUP_SESSION_STATE_STOP;
|
|
if( LmhpRemoteMcastSetupPackage.OnPackageProcessEvent != NULL )
|
|
{
|
|
LmhpRemoteMcastSetupPackage.OnPackageProcessEvent();
|
|
}
|
|
}
|
|
#endif /* LORAMAC_MAX_MC_CTX > 1 */
|
|
#if ( LORAMAC_MAX_MC_CTX > 2 )
|
|
static void OnSessionStartTimer2( void *context )
|
|
{
|
|
TimerStop( &SessionStartTimer[2] );
|
|
|
|
McSessionData[2].SessionState = SESSION_STARTED;
|
|
LmhpRemoteMcastSetupState.ID = 2;
|
|
LmhpRemoteMcastSetupState.SessionState = REMOTE_MCAST_SETUP_SESSION_STATE_START;
|
|
if( LmhpRemoteMcastSetupPackage.OnPackageProcessEvent != NULL )
|
|
{
|
|
LmhpRemoteMcastSetupPackage.OnPackageProcessEvent();
|
|
}
|
|
}
|
|
|
|
static void OnSessionStopTimer2( void *context )
|
|
{
|
|
TimerStop( &SessionStopTimer[2] );
|
|
|
|
McSessionData[2].SessionState = SESSION_STOPPED;
|
|
LmhpRemoteMcastSetupState.ID = 2;
|
|
LmhpRemoteMcastSetupState.SessionState = REMOTE_MCAST_SETUP_SESSION_STATE_STOP;
|
|
if( LmhpRemoteMcastSetupPackage.OnPackageProcessEvent != NULL )
|
|
{
|
|
LmhpRemoteMcastSetupPackage.OnPackageProcessEvent();
|
|
}
|
|
}
|
|
#endif /* LORAMAC_MAX_MC_CTX > 2 */
|
|
#if ( LORAMAC_MAX_MC_CTX > 3 )
|
|
static void OnSessionStartTimer3( void *context )
|
|
{
|
|
TimerStop( &SessionStartTimer[3] );
|
|
|
|
McSessionData[3].SessionState = SESSION_STARTED;
|
|
LmhpRemoteMcastSetupState.ID = 3;
|
|
LmhpRemoteMcastSetupState.SessionState = REMOTE_MCAST_SETUP_SESSION_STATE_START;
|
|
if( LmhpRemoteMcastSetupPackage.OnPackageProcessEvent != NULL )
|
|
{
|
|
LmhpRemoteMcastSetupPackage.OnPackageProcessEvent();
|
|
}
|
|
}
|
|
|
|
static void OnSessionStopTimer3( void *context )
|
|
{
|
|
TimerStop( &SessionStopTimer[3] );
|
|
|
|
McSessionData[3].SessionState = SESSION_STOPPED;
|
|
LmhpRemoteMcastSetupState.ID = 3;
|
|
LmhpRemoteMcastSetupState.SessionState = REMOTE_MCAST_SETUP_SESSION_STATE_STOP;
|
|
if( LmhpRemoteMcastSetupPackage.OnPackageProcessEvent != NULL )
|
|
{
|
|
LmhpRemoteMcastSetupPackage.OnPackageProcessEvent();
|
|
}
|
|
}
|
|
#endif /* LORAMAC_MAX_MC_CTX > 3 */
|