#include // For memcpy and memset #include "reg_system.h" #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 "SystemComm.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. // ********** private function prototypes ********** static MODE_STANDBY_STATE_T handleStandbyModeCheckForUpdateState( void ); static MODE_STANDBY_STATE_T handleStandbyModeCheckFWAndFPGAImagesState( void ); static MODE_STANDBY_STATE_T handleStandbyModeIdleState( void ); static MODE_STANDBY_STATE_T handleStandbyModeCheckUpdatedImageStates( void ); static MODE_STANDBY_STATE_T handleStandyModeResetBootloaderState( void ); static void jumpToApplication( void ); static void resetBootloader( void ); /*********************************************************************//** * @brief * The initStandbyMode function initializes the standby mode. * @details \b Inputs: none * @details \b Outputs: standbyCurrentState * @return none *************************************************************************/ void initStandbyMode( void ) { standbyCurrentState = STANDBY_CHECK_FOR_UPDATE_STATE; } /*********************************************************************//** * @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 standbyCurrentState; } /*********************************************************************//** * @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 in standby mode and update request is received at any time, request a transition to update mode if ( UPDATE_CMD_START == getSWUpdateCommandState() ) { requestNewOperationMode( MODE_UPDATE ); } switch( standbyCurrentState ) { case STANDBY_CHECK_FOR_UPDATE_STATE: standbyCurrentState = handleStandbyModeCheckForUpdateState(); break; case STANDBY_CHECK_FW_AND_FPGA_IMAGES_STATE: standbyCurrentState = handleStandbyModeCheckFWAndFPGAImagesState(); break; case STANDBY_IDLE_STATE: standbyCurrentState = handleStandbyModeIdleState(); break; case STANDBY_CHECK_UPDATED_IMAGE_STATE: standbyCurrentState = handleStandbyModeCheckUpdatedImageStates(); break; case STANDBY_RESET_BOOTLOADER_STATE: standbyCurrentState = handleStandyModeResetBootloaderState(); 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; SW_UPDATE_CMD_T cmd = getSWUpdateCommandState(); switch ( cmd ) { case UPDATE_CMD_ABORT: state = STANDBY_IDLE_STATE; break; case UPDATE_CMD_VERIFY: state = STANDBY_CHECK_UPDATED_IMAGE_STATE; break; case UPDATE_CMD_IDLE: if ( TRUE == didTimeout( getLastBroadcastMessageTimeStampMS(), WAIT_FOR_UPDATE_FROM_UI_MS ) ) { state = STANDBY_CHECK_FW_AND_FPGA_IMAGES_STATE; } break; default: // Do nothing break; } return state; } /*********************************************************************//** * @brief * The handleStandbyModeCheckFWAndFPGAImagesState 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: none * @details \b Outputs: none * @return next state of the standby mode state machine *************************************************************************/ static MODE_STANDBY_STATE_T handleStandbyModeCheckFWAndFPGAImagesState( void ) { MODE_STANDBY_STATE_T state = STANDBY_IDLE_STATE; BOOL isFirmwareImageValid = FALSE; BOOL isFPGAImageValid = FALSE; SW_UPDATE_CMD_T cmd = getSWUpdateCommandState(); // TODO why a bad code passes the CRC? if ( TRUE == isFWCRCTableValid() ) { isFirmwareImageValid = runFWIntegrityTest(); } if ( TRUE == isFPGAIDValid() ) { isFPGAImageValid = TRUE; } // NOTE: If either of the images (firmware or FPGA) failed, go to the idle state until another update request is received // If both images are good and no update was in progress, jump to firmware address if ( ( TRUE == isFirmwareImageValid ) && ( TRUE == isFPGAImageValid ) ) { // All good, jump to application jumpToApplication(); } 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 handleStandbyModeCheckUpdatedImageStates function handles the standby * check the updated image state. * This state checks the validity of the updated image that the update * was in progress. * @details \b Inputs: none * @details \b Outputs: none * @return next state of the standby mode state machine *************************************************************************/ static MODE_STANDBY_STATE_T handleStandbyModeCheckUpdatedImageStates( void ) { SW_UPDATE_RESP_STATUS_T resp; U32 calcCRC = 0; MODE_STANDBY_STATE_T state = STANDBY_RESET_BOOTLOADER_STATE; SW_UPDATE_DESINTATION_T dest = getSWUpdateDestination(); ACK_NACK_STATUS_T ackStatus = ACK; BOOL status = FALSE; switch( dest ) { case UPDATE_FPGA: status = isFPGAFlashSuccessful(); ackStatus = ( TRUE == status ? ACK : NACK ); break; case UPDATE_FIRMWARE: status = runFWIntegrityTest(); ackStatus = ( TRUE == status ? ACK : NACK ); break; default: // Do nothing break; } // NOTE: FPGA is check in self configure resp.msgID = getCurrentCmdMessageID(); resp.msgAckNackStatus = ackStatus; resp.spareSpace = 0; resp.msgCRC = crc32( calcCRC, (U08*)&resp, sizeof( SW_UPDATE_RESP_STATUS_T ) - sizeof( U32 ) ); // If both firmware and FPGA results passed, send an ack otherwise send a nack sendAckNackStatusFromBootloader( (U08*)&resp ); return state; } /*********************************************************************//** * @brief * The handleStandyModeResetBootloaderState function handles the standby * reset bootloader state. * This state resets the bootloader and transitions to idle state. * @details \b Inputs: none * @details \b Outputs: none * @return next state of the standby mode state machine *************************************************************************/ static MODE_STANDBY_STATE_T handleStandyModeResetBootloaderState( void ) { MODE_STANDBY_STATE_T state = STANDBY_IDLE_STATE; // Reset the bootloader regardless of whether the update was successful or not resetBootloader(); 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 firmware 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); } /*********************************************************************//** * @brief * The resetBootloader function resets the bootloader by soft reseting the * processor. * @details \b Inputs: none * @details \b Outputs: none * @return none *************************************************************************/ static void resetBootloader( void ) { systemREG1->SYSECR = (0x2) << 14; // Reset processor } /**@}*/