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

398 lines
16 KiB
C

/**
******************************************************************************
* @file LmhpFirmwareManagement.c
* @author MCD Application Team
* @brief Implements the LoRa-Alliance Firmware Management package
******************************************************************************
* @attention
*
* Copyright (c) 2020(-2021) STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "platform.h"
#include "LoRaMac.h"
#include "LmHandler.h"
#include "LmhpFirmwareManagement.h"
#include "mw_log_conf.h" /* needed for MW_LOG */
/* Private typedef -----------------------------------------------------------*/
/*!
* Package current context
*/
typedef struct LmhpFirmwareManagementState_s
{
bool Initialized;
#if (defined( LORAMAC_VERSION ) && ( LORAMAC_VERSION == 0x01000300 ))
bool IsRunning;
#elif (defined( LORAMAC_VERSION ) && ( LORAMAC_VERSION == 0x01000400 ))
bool IsTxPending;
#endif /* LORAMAC_VERSION */
uint8_t DataBufferMaxSize;
uint8_t *DataBuffer;
} LmhpFirmwareManagementState_t;
typedef enum LmhpFirmwareManagementMoteCmd_e
{
FW_MANAGEMENT_PKG_VERSION_ANS = 0x00,
FW_MANAGEMENT_DEV_VERSION_ANS = 0x01,
FW_MANAGEMENT_DEV_REBOOT_TIME_ANS = 0x02,
FW_MANAGEMENT_DEV_REBOOT_COUNTDOWN_ANS = 0x03,
FW_MANAGEMENT_DEV_UPGRADE_IMAGE_ANS = 0x04,
FW_MANAGEMENT_DEV_DELETE_IMAGE_ANS = 0x05,
} LmhpFirmwareManagementMoteCmd_t;
typedef enum LmhpFirmwareManagementSrvCmd_e
{
FW_MANAGEMENT_PKG_VERSION_REQ = 0x00,
FW_MANAGEMENT_DEV_VERSION_REQ = 0x01,
FW_MANAGEMENT_DEV_REBOOT_TIME_REQ = 0x02,
FW_MANAGEMENT_DEV_REBOOT_COUNTDOWN_REQ = 0x03,
FW_MANAGEMENT_DEV_UPGRADE_IMAGE_REQ = 0x04,
FW_MANAGEMENT_DEV_DELETE_IMAGE_REQ = 0x05,
} LmhpFirmwareManagementSrvCmd_t;
typedef enum LmhpFirmwareManagementUpImageStatus_e
{
FW_MANAGEMENT_NO_PRESENT_IMAGE = 0x00,
FW_MANAGEMENT_CORRUPTED_IMAGE = 0x01,
FW_MANAGEMENT_INCOMPATIBLE_IMAGE = 0x02,
FW_MANAGEMENT_VALID_IMAGE = 0x03,
} LmhpFirmwareManagementUpImageStatus_t;
/* Private define ------------------------------------------------------------*/
/*!
* LoRaWAN Application Layer Remote multicast setup Specification
*/
#define FW_MANAGEMENT_PORT 203
#define FW_MANAGEMENT_ID 4
#define FW_MANAGEMENT_VERSION 1
#define FW_VERSION 0x00000000 /* Not yet managed */
#define HW_VERSION 0x00000000 /* Not yet managed */
/* Private macro -------------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/*!
* 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 LmhpFirmwareManagementInit(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 LmhpFirmwareManagementIsInitialized(void);
#if (defined( LORAMAC_VERSION ) && ( LORAMAC_VERSION == 0x01000300 ))
/*!
* Returns the package operation status.
*
* \retval status Package operation status
* [true: Running, false: Not running]
*/
static bool LmhpFirmwareManagementIsRunning(void);
#elif (defined( LORAMAC_VERSION ) && ( LORAMAC_VERSION == 0x01000400 ))
/*!
* Returns if a package transmission is pending or not.
*
* \retval status Package transmission status
* [true: pending, false: Not pending]
*/
static bool LmhpFirmwareManagementIsTxPending(void);
#endif /* LORAMAC_VERSION */
/*!
* Processes the internal package events.
*/
static void LmhpFirmwareManagementProcess(void);
/*!
* Processes the MCPS Indication
*
* \param [in] mcpsIndication MCPS indication primitive data
*/
static void LmhpFirmwareManagementOnMcpsIndication(McpsIndication_t *mcpsIndication);
static void OnRebootTimer(void *context);
/* Private variables ---------------------------------------------------------*/
static LmhpFirmwareManagementState_t LmhpFirmwareManagementState =
{
.Initialized = false,
#if (defined( LORAMAC_VERSION ) && ( LORAMAC_VERSION == 0x01000300 ))
.IsRunning = false,
#elif (defined( LORAMAC_VERSION ) && ( LORAMAC_VERSION == 0x01000400 ))
.IsTxPending = false,
#endif /* LORAMAC_VERSION */
};
static LmhPackage_t LmhpFirmwareManagementPackage =
{
.Port = FW_MANAGEMENT_PORT,
.Init = LmhpFirmwareManagementInit,
.IsInitialized = LmhpFirmwareManagementIsInitialized,
#if (defined( LORAMAC_VERSION ) && ( LORAMAC_VERSION == 0x01000300 ))
.IsRunning = LmhpFirmwareManagementIsRunning,
#elif (defined( LORAMAC_VERSION ) && ( LORAMAC_VERSION == 0x01000400 ))
.IsTxPending = LmhpFirmwareManagementIsTxPending,
#endif /* LORAMAC_VERSION */
.Process = LmhpFirmwareManagementProcess,
.OnPackageProcessEvent = NULL, // To be initialized by LmHandler
.OnMcpsConfirmProcess = NULL, // Not used in this package
.OnMcpsIndicationProcess = LmhpFirmwareManagementOnMcpsIndication,
.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 ))
.OnSystemReset = NULL, // To be initialized by LmHandler
#endif /* LORAMAC_VERSION */
};
/*!
* Reboot timer
*/
static TimerEvent_t RebootTimer;
/* Exported functions ---------------------------------------------------------*/
LmhPackage_t *LmhpFirmwareManagementPackageFactory(void)
{
return &LmhpFirmwareManagementPackage;
}
/* Private functions ---------------------------------------------------------*/
static void LmhpFirmwareManagementInit(void *params, uint8_t *dataBuffer, uint8_t dataBufferMaxSize)
{
if( dataBuffer != NULL )
{
LmhpFirmwareManagementState.DataBuffer = dataBuffer;
LmhpFirmwareManagementState.DataBufferMaxSize = dataBufferMaxSize;
LmhpFirmwareManagementState.Initialized = true;
#if (defined( LORAMAC_VERSION ) && ( LORAMAC_VERSION == 0x01000300 ))
LmhpFirmwareManagementState.IsRunning = true;
#endif /* LORAMAC_VERSION */
TimerInit(&RebootTimer, OnRebootTimer);
}
else
{
#if (defined( LORAMAC_VERSION ) && ( LORAMAC_VERSION == 0x01000300 ))
LmhpFirmwareManagementState.IsRunning = true;
#endif /* LORAMAC_VERSION */
LmhpFirmwareManagementState.Initialized = false;
}
#if (defined( LORAMAC_VERSION ) && ( LORAMAC_VERSION == 0x01000400 ))
LmhpFirmwareManagementState.IsTxPending = false;
#endif /* LORAMAC_VERSION */
}
static bool LmhpFirmwareManagementIsInitialized(void)
{
return LmhpFirmwareManagementState.Initialized;
}
#if (defined( LORAMAC_VERSION ) && ( LORAMAC_VERSION == 0x01000300 ))
static bool LmhpFirmwareManagementIsRunning(void)
{
if (LmhpFirmwareManagementState.Initialized == false)
{
return false;
}
return LmhpFirmwareManagementState.IsRunning;
}
#elif (defined( LORAMAC_VERSION ) && ( LORAMAC_VERSION == 0x01000400 ))
static bool LmhpFirmwareManagementIsTxPending( void )
{
return LmhpFirmwareManagementState.IsTxPending;
}
#endif /* LORAMAC_VERSION */
static void LmhpFirmwareManagementProcess(void)
{
/* Not yet implemented */
}
static void LmhpFirmwareManagementOnMcpsIndication(McpsIndication_t *mcpsIndication)
{
uint8_t cmdIndex = 0;
uint8_t dataBufferIndex = 0;
if( mcpsIndication->Port != FW_MANAGEMENT_PORT )
{
return;
}
while( cmdIndex < mcpsIndication->BufferSize )
{
switch( mcpsIndication->Buffer[cmdIndex++] )
{
case FW_MANAGEMENT_PKG_VERSION_REQ:
{
LmhpFirmwareManagementState.DataBuffer[dataBufferIndex++] = FW_MANAGEMENT_PKG_VERSION_ANS;
LmhpFirmwareManagementState.DataBuffer[dataBufferIndex++] = FW_MANAGEMENT_ID;
LmhpFirmwareManagementState.DataBuffer[dataBufferIndex++] = FW_MANAGEMENT_VERSION;
break;
}
case FW_MANAGEMENT_DEV_VERSION_REQ:
{
LmhpFirmwareManagementState.DataBuffer[dataBufferIndex++] = FW_MANAGEMENT_DEV_VERSION_ANS;
/* FW Version */
LmhpFirmwareManagementState.DataBuffer[dataBufferIndex++] = (FW_VERSION >> 0) & 0xFF;
LmhpFirmwareManagementState.DataBuffer[dataBufferIndex++] = (FW_VERSION >> 8) & 0xFF;
LmhpFirmwareManagementState.DataBuffer[dataBufferIndex++] = (FW_VERSION >> 16) & 0xFF;
LmhpFirmwareManagementState.DataBuffer[dataBufferIndex++] = (FW_VERSION >> 24) & 0xFF;
/* HW Version */
LmhpFirmwareManagementState.DataBuffer[dataBufferIndex++] = (HW_VERSION >> 0) & 0xFF;
LmhpFirmwareManagementState.DataBuffer[dataBufferIndex++] = (HW_VERSION >> 8) & 0xFF;
LmhpFirmwareManagementState.DataBuffer[dataBufferIndex++] = (HW_VERSION >> 16) & 0xFF;
LmhpFirmwareManagementState.DataBuffer[dataBufferIndex++] = (HW_VERSION >> 24) & 0xFF;
break;
}
case FW_MANAGEMENT_DEV_REBOOT_TIME_REQ:
{
uint32_t rebootTimeReq = 0;
uint32_t rebootTimeAns = 0;
rebootTimeReq = (mcpsIndication->Buffer[cmdIndex++] << 0) & 0x000000FF;
rebootTimeReq += (mcpsIndication->Buffer[cmdIndex++] << 8) & 0x0000FF00;
rebootTimeReq += (mcpsIndication->Buffer[cmdIndex++] << 16) & 0x00FF0000;
rebootTimeReq += (mcpsIndication->Buffer[cmdIndex++] << 24) & 0xFF000000;
if (rebootTimeReq == 0)
{
NVIC_SystemReset();
}
else if (rebootTimeReq == 0xFFFFFFFF)
{
rebootTimeAns = rebootTimeReq;
TimerStop(&RebootTimer);
}
else
{
SysTime_t curTime = { .Seconds = 0, .SubSeconds = 0 };
curTime = SysTimeGet();
rebootTimeAns = rebootTimeReq - curTime.Seconds;
if (rebootTimeAns > 0)
{
/* Start session start timer */
TimerSetValue(&RebootTimer, rebootTimeAns * 1000);
TimerStart(&RebootTimer);
}
}
LmhpFirmwareManagementState.DataBuffer[dataBufferIndex++] = FW_MANAGEMENT_DEV_REBOOT_TIME_ANS;
/* FW Version */
LmhpFirmwareManagementState.DataBuffer[dataBufferIndex++] = (rebootTimeAns >> 0) & 0xFF;
LmhpFirmwareManagementState.DataBuffer[dataBufferIndex++] = (rebootTimeAns >> 8) & 0xFF;
LmhpFirmwareManagementState.DataBuffer[dataBufferIndex++] = (rebootTimeAns >> 16) & 0xFF;
LmhpFirmwareManagementState.DataBuffer[dataBufferIndex++] = (rebootTimeAns >> 24) & 0xFF;
break;
}
case FW_MANAGEMENT_DEV_REBOOT_COUNTDOWN_REQ:
{
uint32_t rebootCountdown = 0;
rebootCountdown = (mcpsIndication->Buffer[cmdIndex++] << 0) & 0x000000FF;
rebootCountdown += (mcpsIndication->Buffer[cmdIndex++] << 8) & 0x0000FF00;
rebootCountdown += (mcpsIndication->Buffer[cmdIndex++] << 16) & 0x00FF0000;
if (rebootCountdown == 0)
{
NVIC_SystemReset();
}
else if (rebootCountdown == 0xFFFFFF)
{
TimerStop(&RebootTimer);
}
else
{
if (rebootCountdown > 0)
{
/* Start session start timer */
TimerSetValue(&RebootTimer, rebootCountdown * 1000);
TimerStart(&RebootTimer);
}
}
LmhpFirmwareManagementState.DataBuffer[dataBufferIndex++] = FW_MANAGEMENT_DEV_REBOOT_COUNTDOWN_ANS;
/* FW Version */
LmhpFirmwareManagementState.DataBuffer[dataBufferIndex++] = (rebootCountdown >> 0) & 0xFF;
LmhpFirmwareManagementState.DataBuffer[dataBufferIndex++] = (rebootCountdown >> 8) & 0xFF;
LmhpFirmwareManagementState.DataBuffer[dataBufferIndex++] = (rebootCountdown >> 16) & 0xFF;
break;
}
case FW_MANAGEMENT_DEV_UPGRADE_IMAGE_REQ:
{
uint32_t imageVersion = 0;
uint8_t imageStatus = FW_MANAGEMENT_NO_PRESENT_IMAGE;
LmhpFirmwareManagementState.DataBuffer[dataBufferIndex++] = FW_MANAGEMENT_DEV_UPGRADE_IMAGE_ANS;
/* No FW present */
LmhpFirmwareManagementState.DataBuffer[dataBufferIndex++] = imageStatus & 0x03;
if (imageStatus == FW_MANAGEMENT_VALID_IMAGE)
{
/* Next FW version (opt) */
LmhpFirmwareManagementState.DataBuffer[dataBufferIndex++] = (imageVersion >> 0) & 0xFF;
LmhpFirmwareManagementState.DataBuffer[dataBufferIndex++] = (imageVersion >> 8) & 0xFF;
LmhpFirmwareManagementState.DataBuffer[dataBufferIndex++] = (imageVersion >> 16) & 0xFF;
LmhpFirmwareManagementState.DataBuffer[dataBufferIndex++] = (imageVersion >> 24) & 0xFF;
}
break;
}
case FW_MANAGEMENT_DEV_DELETE_IMAGE_REQ:
{
uint32_t firmwareVersion = 0;
firmwareVersion = (mcpsIndication->Buffer[cmdIndex++] << 0) & 0x000000FF;
firmwareVersion += (mcpsIndication->Buffer[cmdIndex++] << 8) & 0x0000FF00;
firmwareVersion += (mcpsIndication->Buffer[cmdIndex++] << 16) & 0x00FF0000;
firmwareVersion += (mcpsIndication->Buffer[cmdIndex++] << 24) & 0xFF000000;
LmhpFirmwareManagementState.DataBuffer[dataBufferIndex++] = FW_MANAGEMENT_DEV_DELETE_IMAGE_ANS;
/* No valid image present */
LmhpFirmwareManagementState.DataBuffer[dataBufferIndex++] = 0x01;
break;
}
default:
{
break;
}
}
}
if( dataBufferIndex != 0 )
{
// Answer commands
LmHandlerAppData_t appData =
{
.Buffer = LmhpFirmwareManagementState.DataBuffer,
.BufferSize = dataBufferIndex,
.Port = FW_MANAGEMENT_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 );
}
}
static void OnRebootTimer(void *context)
{
NVIC_SystemReset();
}