398 lines
16 KiB
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( ¤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 );
|
|
}
|
|
}
|
|
|
|
static void OnRebootTimer(void *context)
|
|
{
|
|
NVIC_SystemReset();
|
|
}
|