Index: firmware/App/Modes/ModeStandby.c =================================================================== diff -u -rabb9687e52d9db5df1abe7626ba04a6d431ba823 -rc74c1d99a011dd0fb7f98f183faecda675221fce --- firmware/App/Modes/ModeStandby.c (.../ModeStandby.c) (revision abb9687e52d9db5df1abe7626ba04a6d431ba823) +++ firmware/App/Modes/ModeStandby.c (.../ModeStandby.c) (revision c74c1d99a011dd0fb7f98f183faecda675221fce) @@ -1,8 +1,232 @@ -/* - * ModeStandby.c - * - * Created on: Jul 31, 2024 - * Author: fw - */ +#include // For memcpy and memset + +#include "sys_core.h" // To disable RAM and Flash ECC +#include "sys_mpu.h" // To disable MPU + +#include "Download.h" +#include "FPGA.h" #include "ModeStandby.h" +#include "NVDataMgmt.h" +#include "OperationModes.h" +#include "Timers.h" +#include "Utilities.h" + +/** + * @addtogroup BLStandbyMode + * @{ + */ + +// ********** private definitions ********** + +#define WAIT_FOR_UPDATE_FROM_UI_MS 1000 ///< Wait for update timeout in milliseconds. + +// ********** private data ********** + +static MODE_STANDBY_STATE_T standbyCurrentState; ///< Standby current state. +static U32 waitForUpdateMsgStartTimeMS; ///< Wait for update start time in milliseconds. + +// ********** private function prototypes ********** + +static MODE_STANDBY_STATE_T handleStandbyModeCheckForUpdateState( void ); +static MODE_STANDBY_STATE_T handleStandbyModeCheckFWAndFPGAImages( void ); +static MODE_STANDBY_STATE_T handleStandbyModeIdleState( void ); + +static void jumpToApplication( void ); + +/*********************************************************************//** + * @brief + * The initStandbyMode function initializes the standby mode. + * @details \b Inputs: none + * @details \b Outputs: standbyCurrentState, waitForUpdateMsgStartTimeMS + * @return none + *************************************************************************/ +void initStandbyMode( void ) +{ + standbyCurrentState = STANDBY_CHECK_FOR_UPDATE_STATE; + waitForUpdateMsgStartTimeMS = getMSTimerCount(); +} + +/*********************************************************************//** + * @brief + * The transitionToStandbyMode function prepares for transition to Standby Mode. + * @details \b Inputs: none + * @details \b Outputs: Standby Mode unit re-initialized + * @return none + *************************************************************************/ +U32 transitionToStandbyMode( void ) +{ + initStandbyMode(); + + return 0; +} + +/*********************************************************************//** + * @brief + * The execStandbyMode function executes the Standby Mode state machine. + * @details \b Inputs: standbyCurrentState + * @details \b Outputs: standbyCurrentState + * @return current state (sub-mode) + *************************************************************************/ +U32 execStandbyMode( void ) +{ + // If the bootloader is the standby mode and and update request is received at any time, request a transition to update mode + // TODO what if we are in the check image process, should we transition to update upon the request? + if ( ( UPDATE_CMD_START == getSWUpdateCommandState() ) || ( TRUE == hasUpdateBeenRequested() ) ) + { + // TODO if we are here because of the FPGA register, clear it so it won't be called again. + requestNewOperationMode( MODE_UPDATE ); + } + + switch( standbyCurrentState ) + { + case STANDBY_CHECK_FOR_UPDATE_STATE: + standbyCurrentState = handleStandbyModeCheckForUpdateState(); + break; + + case STANDBY_CHECK_FW_AND_FPGA_IMAGES_STATE: + standbyCurrentState = handleStandbyModeCheckFWAndFPGAImages(); + break; + + case STANDBY_IDLE_STATE: + standbyCurrentState = handleStandbyModeIdleState(); + break; + + default: + // Do nothing + break; + } + + return standbyCurrentState; +} + +/*********************************************************************//** + * @brief + * The handleStandbyModeCheckForUpdateState function handles the standby + * check for update state. + * This state waits for a software update command (i.e. verify or abort) and + * then transitions accordingly. Also, if the wait for update has timed out + * it transitions to the verifying firmware and FPGA images. + * @details \b Inputs: waitForUpdateMsgStartTimeMS + * @details \b Outputs: none + * @return next state of the standby mode state machine + *************************************************************************/ +static MODE_STANDBY_STATE_T handleStandbyModeCheckForUpdateState( void ) +{ + MODE_STANDBY_STATE_T state = STANDBY_CHECK_FOR_UPDATE_STATE; + + switch ( getSWUpdateCommandState() ) + { + case UPDATE_CMD_ABORT: + state = STANDBY_IDLE_STATE; + break; + + case UPDATE_CMD_VERIFY: + state = STANDBY_CHECK_FW_AND_FPGA_IMAGES_STATE; + break; + + default: + // Do nothing + break; + } + + if ( TRUE == didTimeout( waitForUpdateMsgStartTimeMS, 3000000 /*WAIT_FOR_UPDATE_FROM_UI_MS*/ ) ) // TODO a high number if timeout for development + { + state = STANDBY_CHECK_FW_AND_FPGA_IMAGES_STATE; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleStandbyModeCheckFWAndFPGAImages function handles the standby + * check firmware and FPGA images state. + * This state checks the integrity of the firmware as well as the FPGA header + * to make sure the images are valid. + * @details \b Inputs: waitForUpdateMsgStartTimeMS + * @details \b Outputs: none + * @return next state of the standby mode state machine + *************************************************************************/ +static MODE_STANDBY_STATE_T handleStandbyModeCheckFWAndFPGAImages( void ) +{ + MODE_STANDBY_STATE_T state = STANDBY_CHECK_FW_AND_FPGA_IMAGES_STATE; + BOOL isFirmwareImageValid = FALSE; + BOOL isFPGAImageValid = FALSE; + // TODo timeout and wait for a while prior to transitioning + // TODO why a bad code passes the CRC? + _disable_IRQ(); + if ( TRUE == isFWCRCTableValid() ) + { + isFirmwareImageValid = runFWIntegrityTest(); + } + _enable_IRQ(); + + if ( TRUE == isFPGAIDValid() ) + { + isFPGAImageValid = TRUE; + } + + if ( ( TRUE == isFirmwareImageValid ) && ( TRUE == isFPGAImageValid ) ) + { + // All good, jump to application + jumpToApplication(); + } + else + { + // TODO do we need to try a few times prior to tansitioning to Idle? + + // If either of the images (firmware or FPGA) failed, go to the idle state until another update request is received + state = STANDBY_IDLE_STATE; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleStandbyModeIdleState function handles the standby idle state. + * This state waits until a new update request arrives. + * @details \b Inputs: none + * @details \b Outputs: none + * @return next state of the standby mode state machine + *************************************************************************/ +static MODE_STANDBY_STATE_T handleStandbyModeIdleState( void ) +{ + MODE_STANDBY_STATE_T state = STANDBY_IDLE_STATE; + + // This state does nothing and waits until another update request is received. This could be because the update was aborted or + // the firmware or FPGA have bad images. So we cannot jump to the application. + + return state; +} + +/*********************************************************************//** + * @brief + * The jumpToApplication function handles the jump to application commands. + * This function, disables interrupts that were used in the bootloader and + * then it jumps to the fimrware start address. + * @details \b Inputs: none + * @details \b Outputs: none + * @return none + *************************************************************************/ +static void jumpToApplication( void ) +{ + U32 jumpAddress = (U32)FIRMWARE_START_ADDRESS; + + // Disable various memory protections + _coreDisableRamEcc_(); + _coreDisableFlashEcc_(); + _mpuDisable_(); + + // Disable all interrupts + _disable_interrupt_(); + _disable_IRQ_interrupt_(); + _disable_FIQ_interrupt_(); + + ((void (*)(void))jumpAddress)(); + while(1); +} + +/**@}*/ +