519 lines
15 KiB
C
519 lines
15 KiB
C
/*!
|
|
* \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 )
|
|
*/
|
|
/**
|
|
******************************************************************************
|
|
*
|
|
* Portions COPYRIGHT 2020 STMicroelectronics
|
|
*
|
|
* @file LmhpCompliance.c
|
|
* @author MCD Application Team
|
|
* @brief Certification Protocol Handling definition
|
|
******************************************************************************
|
|
*/
|
|
/* Includes ------------------------------------------------------------------*/
|
|
#include "LoRaMacTest.h"
|
|
#include "LmhpCompliance.h"
|
|
|
|
/* Private typedef -----------------------------------------------------------*/
|
|
/*!
|
|
* 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;
|
|
|
|
/* Private define ------------------------------------------------------------*/
|
|
/*!
|
|
* 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
|
|
|
|
/* Private macro -------------------------------------------------------------*/
|
|
#ifndef MIN
|
|
#define MIN( a, b ) ( ( ( a ) < ( b ) ) ? ( a ) : ( b ) )
|
|
#endif
|
|
|
|
/* Private function prototypes -----------------------------------------------*/
|
|
/*!
|
|
* 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 Confirm
|
|
*
|
|
* \param [in] mcpsConfirm MCPS confirmation primitive data
|
|
*/
|
|
static void LmhpComplianceOnMcpsConfirm(McpsConfirm_t *mcpsConfirm);
|
|
|
|
/*!
|
|
* 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);
|
|
|
|
/* Private variables ---------------------------------------------------------*/
|
|
/*!
|
|
* 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,
|
|
.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;
|
|
|
|
static LmhPackage_t LmhpCompliancePackage =
|
|
{
|
|
.Port = COMPLIANCE_PORT,
|
|
.Init = LmhpComplianceInit,
|
|
.IsInitialized = LmhpComplianceIsInitialized,
|
|
.IsRunning = LmhpComplianceIsRunning,
|
|
.Process = LmhpComplianceProcess,
|
|
.OnMcpsConfirmProcess = LmhpComplianceOnMcpsConfirm,
|
|
.OnMcpsIndicationProcess = LmhpComplianceOnMcpsIndication,
|
|
.OnMlmeConfirmProcess = LmhpComplianceOnMlmeConfirm,
|
|
.OnJoinRequest = NULL, /* To be initialized by LmHandler */
|
|
.OnSendRequest = NULL, /* To be initialized by LmHandler */
|
|
.OnDeviceTimeRequest = NULL, /* To be initialized by LmHandler */
|
|
};
|
|
|
|
/* Exported functions ---------------------------------------------------------*/
|
|
LmhPackage_t *LmphCompliancePackageFactory(void)
|
|
{
|
|
return &LmhpCompliancePackage;
|
|
}
|
|
|
|
/* Private functions ---------------------------------------------------------*/
|
|
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 LmhpComplianceOnMcpsConfirm(McpsConfirm_t *mcpsConfirm)
|
|
{
|
|
if (ComplianceTestState.Initialized == false)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ((ComplianceTestState.IsRunning == true) &&
|
|
(mcpsConfirm->McpsRequest == MCPS_CONFIRMED) &&
|
|
(mcpsConfirm->AckReceived != 0))
|
|
{
|
|
/* Increment the compliance certification protocol downlink counter */
|
|
ComplianceTestState.DownLinkCounter++;
|
|
}
|
|
}
|
|
|
|
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
|
|
};
|
|
TimerTime_t nextTxIn = 0;
|
|
|
|
/* Schedule next transmission */
|
|
TimerStart(&ComplianceTxNextPacketTimer);
|
|
|
|
return LmhpCompliancePackage.OnSendRequest(&appData, (LmHandlerMsgTypes_t)ComplianceTestState.IsTxConfirmed, &nextTxIn,
|
|
true);
|
|
}
|
|
|
|
static void LmhpComplianceOnMcpsIndication(McpsIndication_t *mcpsIndication)
|
|
{
|
|
if (ComplianceTestState.Initialized == false)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (mcpsIndication->RxData == false)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ((ComplianceTestState.IsRunning == true) &&
|
|
(mcpsIndication->AckReceived == 0))
|
|
{
|
|
/* Increment the compliance certification protocol downlink counter */
|
|
ComplianceTestState.DownLinkCounter++;
|
|
}
|
|
|
|
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.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 */
|
|
LmhpComplianceTxProcess();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* 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;
|
|
|
|
LoRaMacMlmeRequest(&mlmeReq);
|
|
}
|
|
break;
|
|
case 6: /* (ix) */
|
|
{
|
|
MibRequestConfirm_t mibReq;
|
|
|
|
TimerStop(&ComplianceTxNextPacketTimer);
|
|
|
|
/* 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(ACTIVATION_TYPE_OTAA);
|
|
}
|
|
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];
|
|
}
|
|
LoRaMacMlmeRequest(&mlmeReq);
|
|
ComplianceTestState.State = 1;
|
|
}
|
|
break;
|
|
case 8: /* Send DeviceTimeReq */
|
|
{
|
|
MlmeReq_t mlmeReq;
|
|
|
|
mlmeReq.Type = MLME_DEVICE_TIME;
|
|
|
|
LoRaMacMlmeRequest(&mlmeReq);
|
|
}
|
|
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];
|
|
|
|
LoRaMacMlmeRequest(&mlmeReq);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void LmhpComplianceProcess(void)
|
|
{
|
|
/* Nothing to process */
|
|
}
|
|
|
|
static void OnComplianceTxNextPacketTimerEvent(void *context)
|
|
{
|
|
LmhpComplianceTxProcess();
|
|
}
|