/* * ModeStandby.c * * Created on: Aug 7, 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" #define WAIT_FOR_UPDATE_FROM_UI_MS 1000 static MODE_STANDBY_STATE_T standbyCurrentState; static U32 waitForUpdateMsgStartTimeMS; 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 ); void initStandbyMode( void ) { standbyCurrentState = STANDBY_CHECK_FOR_UPDATE_STATE; waitForUpdateMsgStartTimeMS = getMSTimerCount(); } U32 transitionToStandbyMode( void ) { initStandbyMode(); return 0; } 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; } 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; } 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; } 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; } 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); }