STM32CubeWL/Middlewares/Third_Party/LoRaWAN/LmHandler/Packages/LmhpRemoteMcastSetup.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( &current_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 */