STM32CubeWL/Middlewares/Third_Party/LoRaWAN/LmHandler/Packages/LmhpFragmentation.c

642 lines
27 KiB
C

/*!
* \file LmhpFragmentation.c
*
* \brief Implements the LoRa-Alliance fragmented data block transport package
* Specification V1.0.0: https://resources.lora-alliance.org/technical-specifications/lorawan-fragmented-data-block-transport-specification-v1-0-0
* Specification V2.0.0: https://resources.lora-alliance.org/technical-specifications/ts004-2-0-0-fragmented-data-block-transport
*
* \copyright Revised BSD License, see section \ref LICENSE.
*
* \code
* ______ _
* / _____) _ | |
* ( (____ _____ ____ _| |_ _____ ____| |__
* \____ \| ___ | (_ _) ___ |/ ___) _ \
* _____) ) ____| | | || |_| ____( (___| | | |
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
* (C)2013-2018 Semtech
*
* \endcode
*
* \author Miguel Luis ( Semtech )
*/
/**
******************************************************************************
*
* Portions COPYRIGHT 2020 STMicroelectronics
*
* @file LmhpFragmentation.c
* @author MCD Application Team
* @brief Implements the LoRa-Alliance fragmented data block transport package
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "LoRaMac.h"
#include "LmHandler.h"
#include "LmhpFragmentation.h"
#include "frag_decoder_if.h"
#include "utilities.h"
#include "mw_log_conf.h" /* needed for MW_LOG */
/*!
* LoRaWAN Application Layer Fragmented Data Block Transport Specification
*/
#define FRAGMENTATION_PORT 201
#define FRAGMENTATION_ID 3
#if (LORAWAN_PACKAGES_VERSION == 1)
#define FRAGMENTATION_VERSION 1
#elif (LORAWAN_PACKAGES_VERSION == 2)
#define FRAGMENTATION_VERSION 2
#endif /* LORAWAN_PACKAGES_VERSION */
#define FRAGMENTATION_MAX_SESSIONS 4
/*!
* Package current context
*/
typedef struct LmhpFragmentationState_s
{
bool Initialized;
bool IsTxPending;
#if ( FRAGMENTATION_VERSION == 2 )
bool FragDataBlockAnsRequired;
#endif /* FRAGMENTATION_VERSION */
uint8_t DataBufferMaxSize;
uint8_t DataBufferSize;
uint8_t *DataBuffer;
} 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,
#if ( FRAGMENTATION_VERSION == 2 )
FRAGMENTATION_FRAG_DATA_BLOCK_RECEIVED_REQ = 0x04,
#endif /* FRAGMENTATION_VERSION */
} 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,
#if ( FRAGMENTATION_VERSION == 2 )
FRAGMENTATION_FRAG_DATA_BLOCK_RECEIVED_ANS = 0x04,
#endif /* FRAGMENTATION_VERSION */
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 if a package transmission is pending or not.
*
* \retval status Package transmission status
* [true: pending, false: Not pending]
*/
static bool LmhpFragmentationIsTxPending( 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 );
/*!
* \brief Callback function for Fragment delay timer.
*/
static void OnFragmentProcessTimer( void *context );
static LmhpFragmentationState_t LmhpFragmentationState =
{
.Initialized = false,
.IsTxPending = false,
#if ( FRAGMENTATION_VERSION == 2 )
.FragDataBlockAnsRequired = false,
#endif /* FRAGMENTATION_VERSION */
.DataBufferMaxSize = 0,
.DataBufferSize = 0,
.DataBuffer = NULL,
};
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;
#if ( FRAGMENTATION_VERSION == 1 )
uint8_t RFU: 2;
#elif ( FRAGMENTATION_VERSION == 2 )
uint8_t AckReception: 1;
uint8_t RFU: 1;
#endif /* FRAGMENTATION_VERSION */
} Fields;
} Control;
uint8_t Padding;
uint32_t Descriptor;
#if ( FRAGMENTATION_VERSION == 2 )
uint16_t SessionCnt;
uint32_t Mic;
#endif /* FRAGMENTATION_VERSION */
} FragGroupData_t;
typedef struct FragSessionData_s
{
FragGroupData_t FragGroupData;
FragDecoderStatus_t FragDecoderStatus;
int32_t FragDecoderProcessStatus;
} FragSessionData_t;
static FragSessionData_t FragSessionData[FRAGMENTATION_MAX_SESSIONS];
static LmhPackage_t LmhpFragmentationPackage =
{
.Port = FRAGMENTATION_PORT,
.Init = LmhpFragmentationInit,
.IsInitialized = LmhpFragmentationIsInitialized,
.IsTxPending = LmhpFragmentationIsTxPending,
.Process = LmhpFragmentationProcess,
.OnPackageProcessEvent = NULL, /* To be initialized by LmHandler */
.OnMcpsConfirmProcess = NULL, /* Not used in this package */
.OnMcpsIndicationProcess = LmhpFragmentationOnMcpsIndication,
.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 */
};
/* Delay value. */
static uint32_t TxDelayTime;
/* Fragment Delay Timer struct */
static TimerEvent_t FragmentProcessTimer;
/* Co-efficient used to calculate delay. */
static uint8_t BlockAckDelay = 0;
#if ( FRAGMENTATION_VERSION == 2 )
/* fragmentation counter session */
static int32_t SessionCntPrev[FRAGMENTATION_MAX_SESSIONS] = {-1, -1, -1, -1};
#endif /* FRAGMENTATION_VERSION */
/*!
* \brief Callback function for Fragment delay timer.
*/
static void OnFragmentProcessTimer( void *context )
{
if( LmhpFragmentationState.DataBufferSize != 0 )
{
LmhpFragmentationState.IsTxPending = true;
}
if( LmhpFragmentationPackage.OnPackageProcessEvent != NULL )
{
LmhpFragmentationPackage.OnPackageProcessEvent();
}
}
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;
/* Initialize Fragmentation delay time. */
TxDelayTime = 0;
/* Initialize Fragmentation delay timer. */
TimerInit( &FragmentProcessTimer, OnFragmentProcessTimer );
}
else
{
LmhpFragmentationParams = NULL;
LmhpFragmentationState.Initialized = false;
}
LmhpFragmentationState.IsTxPending = false;
/* initialize the global fragmentation session buffer */
memset1( ( uint8_t * )FragSessionData, 0, sizeof( FragSessionData ) );
}
static bool LmhpFragmentationIsInitialized( void )
{
return LmhpFragmentationState.Initialized;
}
static bool LmhpFragmentationIsTxPending( void )
{
return LmhpFragmentationState.IsTxPending;
}
static void LmhpFragmentationProcess( void )
{
if( LmhpFragmentationState.IsTxPending == true )
{
/* Send the reply. */
LmHandlerAppData_t appData =
{
.Buffer = LmhpFragmentationState.DataBuffer,
.BufferSize = LmhpFragmentationState.DataBufferSize,
.Port = FRAGMENTATION_PORT,
};
LmHandlerErrorStatus_t lmhStatus = LORAMAC_HANDLER_ERROR;
lmhStatus = LmHandlerSend( &appData, LORAMAC_HANDLER_UNCONFIRMED_MSG, true );
#if ( FRAGMENTATION_VERSION == 2 )
if( ( lmhStatus != LORAMAC_HANDLER_SUCCESS ) || ( LmhpFragmentationState.FragDataBlockAnsRequired == true ) )
#else
if( lmhStatus != LORAMAC_HANDLER_SUCCESS )
#endif /* FRAGMENTATION_VERSION */
{
/* try to send the message again */
TimerSetValue( &FragmentProcessTimer, 1500 );
TimerStart( &FragmentProcessTimer );
}
else
{
LmhpFragmentationState.IsTxPending = false;
LmhpFragmentationState.DataBufferSize = 0;
}
}
}
static void LmhpFragmentationOnMcpsIndication( McpsIndication_t *mcpsIndication )
{
uint8_t cmdIndex = 0;
uint8_t dataBufferIndex = 0;
bool isAnswerDelayed = false;
if( mcpsIndication->Port != FRAGMENTATION_PORT )
{
return;
}
LmhpFragmentationState.DataBufferSize = 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 = ( fragIndex >> 1 ) & 0x03;
FragSessionData[fragIndex].FragDecoderStatus = FragDecoderGetStatus( );
if( ( participants == 1 ) ||
( ( participants == 0 ) && ( FragSessionData[fragIndex].FragDecoderStatus.FragNbLost > 0 ) ) )
{
LmhpFragmentationState.DataBuffer[dataBufferIndex++] = FRAGMENTATION_FRAG_STATUS_ANS;
LmhpFragmentationState.DataBuffer[dataBufferIndex++] = FragSessionData[fragIndex].FragDecoderStatus.FragNbRx & 0xFF;
LmhpFragmentationState.DataBuffer[dataBufferIndex++] = ( fragIndex << 6 ) |
( ( FragSessionData[fragIndex].FragDecoderStatus.FragNbRx >> 8 ) & 0x3F );
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 ( FRAGMENTATION_VERSION == 2 )
/* SessionCnt and MIC filed added for V2*/
fragSessionData.FragGroupData.SessionCnt = ( mcpsIndication->Buffer[cmdIndex++] << 0 ) & 0x00FF;
fragSessionData.FragGroupData.SessionCnt += ( mcpsIndication->Buffer[cmdIndex++] << 8 ) & 0xFF00;
fragSessionData.FragGroupData.Mic = ( mcpsIndication->Buffer[cmdIndex++] << 0 ) & 0x000000FF;
fragSessionData.FragGroupData.Mic += ( mcpsIndication->Buffer[cmdIndex++] << 8 ) & 0x0000FF00;
fragSessionData.FragGroupData.Mic += ( mcpsIndication->Buffer[cmdIndex++] << 16 ) & 0x00FF0000;
fragSessionData.FragGroupData.Mic += ( mcpsIndication->Buffer[cmdIndex++] << 24 ) & 0xFF000000;
#endif /* FRAGMENTATION_VERSION */
if( fragSessionData.FragGroupData.Control.Fields.FragAlgo > 0 )
{
status |= 0x01; /* Encoding unsupported */
}
if( ( fragSessionData.FragGroupData.FragNb > FRAG_MAX_NB ) ||
( fragSessionData.FragGroupData.FragSize > FRAG_MAX_SIZE ) ||
( fragSessionData.FragGroupData.FragSize < FRAG_MIN_SIZE ) ||
( ( fragSessionData.FragGroupData.FragNb * fragSessionData.FragGroupData.FragSize ) > FRAG_DECODER_DWL_REGION_SIZE ) )
{
status |= 0x02; /* Not enough Memory */
}
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 ( FRAGMENTATION_VERSION == 1 )
if( ( status & 0x0F ) == 0 )
{
#elif ( FRAGMENTATION_VERSION == 2 )
if( SessionCntPrev[fragSessionData.FragGroupData.FragSession.Fields.FragIndex] >=
fragSessionData.FragGroupData.SessionCnt )
{
status |= 0x10; /* SessionCnt Replay */
}
if( ( status & 0x1F ) == 0 )
{
#endif /* FRAGMENTATION_VERSION */
/* The FragSessionSetup is accepted */
fragSessionData.FragGroupData.IsActive = true;
fragSessionData.FragDecoderProcessStatus = FRAG_SESSION_ONGOING;
FragSessionData[fragSessionData.FragGroupData.FragSession.Fields.FragIndex] = fragSessionData;
FragDecoderInit( fragSessionData.FragGroupData.FragNb,
fragSessionData.FragGroupData.FragSize,
&LmhpFragmentationParams->DecoderCallbacks,
FRAGMENTATION_VERSION );
}
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;
}
#if ( FRAGMENTATION_VERSION == 2 )
case FRAGMENTATION_FRAG_DATA_BLOCK_RECEIVED_ANS:
{
if( mcpsIndication->Multicast == 1 )
{
/* Multicast channel. Don't process command. */
break;
}
uint8_t fragIndex = mcpsIndication->Buffer[cmdIndex++] & 0x03;
if( ( FragSessionData[fragIndex].FragGroupData.FragSession.Fields.FragIndex == fragIndex )
&& ( LmhpFragmentationState.FragDataBlockAnsRequired == true ) )
{
TimerStop( &FragmentProcessTimer );
LmhpFragmentationState.IsTxPending = false;
LmhpFragmentationState.DataBufferSize = 0;
LmhpFragmentationState.FragDataBlockAnsRequired = false;
}
break;
}
#endif /* FRAGMENTATION_VERSION */
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( FragSessionData[fragIndex].FragGroupData.IsActive == false )
{
cmdIndex = mcpsIndication->BufferSize;
break;
}
if( mcpsIndication->Multicast == 1 )
{
/* Message received on a multicast address */
/* Check McGroupBitMask */
uint8_t groupId = LoRaMacMcChannelGetGroupId( mcpsIndication->DevAddress );
if( ( groupId == 0xFF ) ||
( ( FragSessionData[fragIndex].FragGroupData.FragSession.Fields.McGroupBitMask & ( 1 << groupId ) ) == 0 ) )
{
/* Ignore message */
cmdIndex = mcpsIndication->BufferSize;
break;
}
}
if( FragSessionData[fragIndex].FragDecoderProcessStatus == FRAG_SESSION_ONGOING )
{
FragSessionData[fragIndex].FragDecoderProcessStatus = 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 );
}
if( FragSessionData[fragIndex].FragDecoderProcessStatus >= 0 )
{
uint32_t UnfragmentedBufferAddr;
/* Fragmentation successfully done */
if( LmhpFragmentationParams->OnDone != NULL )
{
LmhpFragmentationParams->OnDone( FragSessionData[fragIndex].FragDecoderProcessStatus,
( FragSessionData[fragIndex].FragGroupData.FragNb * FragSessionData[fragIndex].FragGroupData.FragSize ) -
FragSessionData[fragIndex].FragGroupData.Padding,
&UnfragmentedBufferAddr );
}
#if ( FRAGMENTATION_VERSION == 2 )
/*If AckReception = 0, the end-device SHALL do nothing */
if( FragSessionData[fragIndex].FragGroupData.Control.Fields.AckReception == 1 )
{
uint8_t status = 0x00;
uint32_t micComputed = 0;
status = fragIndex;
/* Compute MIC */
LoRaMacProcessMicForDatablock( ( uint8_t * )UnfragmentedBufferAddr,
( FragSessionData[fragIndex].FragGroupData.FragNb * FragSessionData[fragIndex].FragGroupData.FragSize ) -
FragSessionData[fragIndex].FragGroupData.Padding,
FragSessionData[fragIndex].FragGroupData.SessionCnt,
fragIndex,
FragSessionData[fragIndex].FragGroupData.Descriptor,
&micComputed );
MW_LOG( TS_OFF, VLEVEL_M, "MIC : %08X\r\n", micComputed );
/* check if the MIC computed is equal to the MIC received */
if( micComputed != FragSessionData[fragIndex].FragGroupData.Mic )
{
status |= 0x04;
}
LmhpFragmentationState.DataBuffer[dataBufferIndex++] = FRAGMENTATION_FRAG_DATA_BLOCK_RECEIVED_REQ;
LmhpFragmentationState.DataBuffer[dataBufferIndex++] = status;
BlockAckDelay = FragSessionData[fragIndex].FragGroupData.Control.Fields.BlockAckDelay;
isAnswerDelayed = true;
LmhpFragmentationState.FragDataBlockAnsRequired = true;
}
#endif /* FRAGMENTATION_VERSION */
FragSessionData[fragIndex].FragDecoderProcessStatus = FRAG_SESSION_NOT_STARTED;
}
}
cmdIndex += FragSessionData[fragIndex].FragGroupData.FragSize;
#if ( FRAGMENTATION_VERSION == 2 )
/* Store the previous session counter*/
SessionCntPrev[fragIndex] = FragSessionData[fragIndex].FragGroupData.SessionCnt;
#endif /* FRAGMENTATION_VERSION */
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 */
LmhpFragmentationState.DataBufferSize = dataBufferIndex;
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
* To prevent too early execution, a minimum delay of 3s is added
*/
TxDelayTime = 3000 + ( randr( 0, 1000 ) * ( 1 << ( BlockAckDelay + 4 ) ) );
}
else
{
TxDelayTime = 3000;
}
TimerSetValue( &FragmentProcessTimer, TxDelayTime );
TimerStart( &FragmentProcessTimer );
}
}