#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); } /**@}*/