/***********************************************************************************************************************
 *  FILE DESCRIPTION
 *  ------------------------------------------------------------------------------------------------------------------*/
/** \file
 *  \brief         Main module of FBL
 *
 *  --------------------------------------------------------------------------------------------------------------------
 *  COPYRIGHT
 *  --------------------------------------------------------------------------------------------------------------------
 *  \par Copyright
 *  \verbatim
 *  Copyright (c) 2025 by Vector Informatik GmbH.                                                  All rights reserved.
 *
 *                This software is copyright protected and proprietary to Vector Informatik GmbH.
 *                Vector Informatik GmbH grants to you only those rights as set out in the license conditions.
 *                All other rights remain with Vector Informatik GmbH.
 *  \endverbatim
 */
/**********************************************************************************************************************/

/***********************************************************************************************************************
 *  REVISION HISTORY
 *  --------------------------------------------------------------------------------------------------------------------
 *  Version    Date        Author       Change Id        Description
 *  --------------------------------------------------------------------------------------------------------------------
 *  05.00.00   2019-10-10  vistmo       FBL-388          Adapt main function interface for vBaseEnv
 *  05.01.00   2019-11-14  visrcn       FBL-830          Add support for VTT use case
 *  05.01.01   2020-02-27  vistbe       ESCAN00105432    [DemoAppl] No diagnostic requests can be processed
 *  06.00.00   2020-04-08  visrie       FBL-1016         Support of EcuM functions, support of new FblSb interface
 *  06.01.00   2020-04-29  vistmo       FBL-1584         Adding OTA startup support
 *  06.01.01   2020-10-28  visrcn       ESCAN00107190    Compiler error: Wrong definition for FblMain function
 *  06.01.02   2020-11-26  visrcn       ESCAN00107979    Tester connection is not shutdown after StayInBoot check
 *  06.02.00   2022-04-08  lhopfhauer   FBL-4852         Add support for new swap API
 *  06.03.00   2022-05-06  lhopfhauer   FBL-5148         Encapsulate call of FblInterruptDisable
 *  06.04.00   2022-07-06  fmenke       FBL-5235         Use Pre Timer/Wd init as standard
 *  06.05.00   2022-11-30  visrie       FBL-6065         Encapsulate FblMain declaration
 *  06.05.01   2023-04-06  lhopfhauer   ESCAN00113532    [DemoAppl only] FblCwClrCheckForStartMsg is not cleared if Stay
 *                                                        in Boot is enabled - DemoAppl is not responding
 *  06.06.00   2023-05-24  fmenke       FBL-7036         P2 timeout in tester after the programming session request
 *  06.07.00   2025-06-18  vsarcmijo    FBL-9710         Extend presence pattern to connect validity information
 *                                      ESCAN00116602    [DemoAppl only] Compiler error: FblCwClrCheckForStartMsg is not
 *                                                        defined
 *  06.08.00   2025-10-21  pharring     FBL-11469        Set a state when FblRepeat is reached
 **********************************************************************************************************************/

#define FBL_MAIN_SOURCE

/***********************************************************************************************************************
 *  INCLUDES
 **********************************************************************************************************************/

#include "fbl_inc.h"

#include "EcuM.h"

/***********************************************************************************************************************
 *  VERSION
 **********************************************************************************************************************/

#if ( FBLMAIN_VERSION != 0x0608u ) || \
    ( FBLMAIN_RELEASE_VERSION != 0x00u )
# error "Error in fbl_main.c: Source and header file are inconsistent!"
#endif

#if ( FBLMAIN_VERSION != _FBL_MAIN_VERSION ) || \
    ( FBLMAIN_RELEASE_VERSION != _FBL_MAIN_RELEASE_VERSION)
# error "Error in fbl_main.c: Source and v_ver.h are inconsistent!"
#endif

#if defined( _MICROSOFT_C_VTT_ )
# define FBL_MAIN_ENABLE_VTT_USECASE
#endif /* _MICROSOFT_C_VTT_ */

/***********************************************************************************************************************
 *  DEFINES
 **********************************************************************************************************************/

#if !defined( FBL_BM_HEADER_ADDRESS )
# define FBL_BM_HEADER_ADDRESS &FblBmHdrHeader
#endif /* FBL_BM_HEADER_ADDRESS */

/* FblStart feature */
#if defined( FBL_ENABLE_FBL_START )
# if !defined( FblStartReset )
#  define FblStartReset() ApplFblReset()
# endif
#endif /* FBL_ENABLE_FBL_START */

# if defined( FBL_ENABLE_STAY_IN_BOOT )
#  if !defined( kFblMainStartMessageDelay )
#   define kFblMainStartMessageDelay 20u      /**< Start message delay default value: 20ms */
#  endif
#  define kFblMainStartMessageReceived 0u     /**< Indicates that a startup message has been received */
#  define kFblMainStartMessageTimeout  1u     /**< No startup message has been received before timeout */
# endif /* FBL_ENABLE_STAY_IN_BOOT */

/* Main state handling */
#define FblMainSetStartFromReset()                 SetFblMainState( kFblMainStateStartFromReset )
#define FblMainSetStartFromAppl()                  SetFblMainState( kFblMainStateStartFromAppl )
#define FblMainSetStartFromXcp()                   SetFblMainState( kFblMainStateStartFromXcp )
#define FblMainSetStartFromOta()                   SetFblMainState( kFblMainStateStartFromOta )
#define FblMainSetApplicationValid()               SetFblMainState( kFblMainStateApplicationValid )
#define FblMainSetWaitStartMessage()   {                                               \
                                       SetFblMainState( kFblMainStateWaitStartMessage );    \
                                       startMessageDelay = kFblMainStartMessageDelay + 1u;   \
                                       }
#define FblMainSetStartMessageReceived()           SetFblMainState( kFblMainStateStartMessageReceived )

#define FblMainClrStartFromReset()                 ClrFblMainState( kFblMainStateStartFromReset )
#define FblMainClrStartFromAppl()                  ClrFblMainState( kFblMainStateStartFromAppl )
#define FblMainClrStartFromXcp()                   ClrFblMainState( kFblMainStateStartFromXcp )
#define FblMainClrStartFromOta()                   ClrFblMainState( kFblMainStateStartFromOta )
#define FblMainClrApplicationValid()               ClrFblMainState( kFblMainStateApplicationValid )
#define FblMainClrWaitStartMessage()               ClrFblMainState( kFblMainStateWaitStartMessage )
#define FblMainClrStartMessageReceived()           ClrFblMainState( kFblMainStateStartMessageReceived )

/***********************************************************************************************************************
 *  GLOBAL DATA
 **********************************************************************************************************************/

# define FBLHEADER_START_SEC_CONST
# include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */
/** FBL header data for access from application software */
V_MEMROM0 V_MEMROM1 tFblHeader V_MEMROM2 FblHeader = /* PRQA S 1514 */ /* MD_FblMain_1514_FblHeader */
{
   FBL_MAIN_HEADER_MAGIC_FLAG
# if defined( FBL_MTAB_NO_OF_BLOCKS )
   ,(tFblHeaderLogicalBlockTablePtr)(&FblLogicalBlockTable)
   ,sizeof(FblLogicalBlockTable)
# else
   ,V_NULL
   ,0u
# endif
# if defined( FBL_ENABLE_COMMON_DATA )
   ,(tFblCommonDataPtr)(&fblCommonData)
# endif
   ,FBL_BLOCK_START_ADDRESS
   ,FBL_BLOCK_LENGTH
   ,FBL_BM_HEADER_ADDRESS
};
# define FBLHEADER_STOP_SEC_CONST
# include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */

# define FBLMAIN_START_SEC_VAR
# include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */
/***********************************************************************************************************************
 *  LOCAL DATA
 **********************************************************************************************************************/
# if defined( FBL_ENABLE_STAY_IN_BOOT )
V_MEMRAM0 static V_MEMRAM1 vuint16 V_MEMRAM2 startMessageDelay;
# endif /* FBL_ENABLE_STAY_IN_BOOT */

V_MEMRAM0 V_MEMRAM1_NEAR tFblStateBitmap V_MEMRAM2_NEAR fblMainStates[FBL_STATE_INDEX(kFblMainNumberOfStates - 1u) + 1u];

#define FBLMAIN_STOP_SEC_VAR
#include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */

/***********************************************************************************************************************
 *  LOCAL FUNCTION PROTOTYPES
 **********************************************************************************************************************/

#define FBLMAIN_START_SEC_CODE
#include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */

static void FblCheckProgrammingRequest(void);
#  if defined( FBL_ENABLE_STAY_IN_BOOT )
static void FblPostProcessStartMsg( vuintx startMsgResult );
static void FblRepeatCheckForStartMsg(void);
#  endif /* FBL_ENABLE_STAY_IN_BOOT */

static void FblInitPowerOn( void );
static void FblInit( vuint8 initposition );

static void FblDeinit( void );

static void FblRepeat( void );

/***********************************************************************************************************************
 *  LOCAL FUNCTIONS
 **********************************************************************************************************************/

/***********************************************************************************************************************
 *  FblCheckProgrammingRequest
 **********************************************************************************************************************/
/*! \brief       Evaluates the programming request flag and decides the next steps (e.g. stay in bootloader, check for
 *               stay-in-boot message or some SecureBoot specific operations).
 **********************************************************************************************************************/
static void FblCheckProgrammingRequest(void)
{
   /* Decide the next step of the Bootloader */
   switch (ApplFblExtProgRequest())
   {
      case kProgRequest:
      {
         FblMainSetStartFromAppl();
         break;
      }
#  if defined( FBL_ENABLE_STAY_IN_BOOT )
      case kCheckStayInBootRequest:
      {
         /* Check for stay in boot message during startup */
         FblMainSetWaitStartMessage();
         break;
      }
#  endif /* FBL_ENABLE_STAY_IN_BOOT */
# if defined( FBLBM_ENABLE_SECURE_BOOT )
#  if defined ( FBLBM_ENABLE_SECBOOT_FBL_INIT_KEY )
      case kInitKeysRequest:  /* Intentional fall through */
#  endif
#  if defined( FBLBM_ENABLE_SECBOOT_FBL_INIT_MAC )
      case kInitMacsRequest:  /* Intentional fall through */
#  endif
# endif /* FBLBM_ENABLE_SECURE_BOOT */
      case kNoProgRequest:    /* Intentional fall through */
      default:
      {
         /* Normal startup */
         FblMainSetStartFromReset();
         break;
      }
   }
}

#  if defined( FBL_ENABLE_STAY_IN_BOOT )
/***********************************************************************************************************************
 *  FblPostProcessStartMsg
 **********************************************************************************************************************/
/*! \brief       Post-process result of start message reception
 *  \details     This function post-processes the result of the startup message check - either
 *               the Bootloader is prepared or the application is started.
 *  \param[in]   startMsgResult Indicates if a start message has been received or not
 **********************************************************************************************************************/
static void FblPostProcessStartMsg(vuintx startMsgResult)
{
   switch (startMsgResult)
   {
      case kFblMainStartMessageReceived:
      {
         FblMainSetStartMessageReceived();
         break;
      }
      case kFblMainStartMessageTimeout:
      {
#   if defined( FBL_NO_JSR_APPL )
#   else /* FBL_NO_JSR_APPL */
         /* Request shutdown from Com-Wrapper */
         FblCwShutdownRequest(kFblCwResetEcuRegularCase);

         while (!FblMainGetFblShutdownRequest())
         {
            FblLookForWatchdogVoid();
         }

         FblDeinit();
         CallApplStart();
#   endif /* FBL_NO_JSR_APPL */
         break;
      }
      default:
      {
         assertFblInternal(0u, kFblSysAssertParameterOutOfRange); /* PRQA S 2741,4558 */ /* MD_FblMain_2741_4558 */
         break;
      }
   }
}
#  endif /* FBL_ENABLE_STAY_IN_BOOT */

/***********************************************************************************************************************
 *  FblInitPowerOn
 **********************************************************************************************************************/
/*! \brief       Pre-initialization of Bootloader variables
 *  \details     Initializes all variables needed to control the Bootloader
 **********************************************************************************************************************/
static void FblInitPowerOn(void) /* PRQA S 3006 */ /* MD_FblMain_3006 */
{
   vuintx i;

#if defined( FBL_ENABLE_INTERRUPT_DISABLE_AT_POWER_ON )
   /* Disable global interrupt handling */
   FblInterruptDisable();  /* PRQA S 1006 */ /* MD_FblMain_1006 */
#endif /* FBL_ENABLE_INTERRUPT_DISABLE_AT_POWER_ON */

#if defined( FBL_MAIN_ENABLE_VTT_USECASE )
#else
   /* Check if bootloader header address is correctly configured in generation tool */
   /* PRQA S 0306 1 */ /* MD_FblMain_FblHeader */
   assertFblGen(FblHeaderLocal == FblHeaderTable, kFblSysAssertParameterOutOfRange);
#endif /* FBL_ENABLE_DEMOAPPL || FBL_MAIN_ENABLE_VTT_USECASE */

   /* Initialization of main variables */
   for (i = 0u; i < (sizeof(fblMainStates) / sizeof(fblMainStates[0])); i++)
   {
      fblMainStates[i] = (tFblStateBitmap)0x00u;
   }
# if defined( FBL_ENABLE_STAY_IN_BOOT )
   startMessageDelay = 0u;
# endif /* FBL_ENABLE_STAY_IN_BOOT */

   /* Power on initialization of core modules */
   ClrWDInit();

   FblDiagInitPowerOn();

   MemDriver_InitPowerOn();
   /* Initialize intermediate access layer for LBT */
   FblLbtInitPowerOn();

#if defined( FBL_ENABLE_HARDWARE_SWAP )
   /* Initialize hardware swap module */
   FblSwapInitPowerOn();
#endif

# if defined( FBL_ENABLE_SECMOD_VECTOR )
   (void)SecM_InitPowerOn(V_NULL);
# endif /* FBL_ENABLE_SECMOD_VECTOR */

}

/***********************************************************************************************************************
 *  FblInit
 **********************************************************************************************************************/
/*! \brief       Do initializations after reset or start out of application
 **********************************************************************************************************************/
/* PRQA S 6050 1 */ /* MD_MSR_STCAL */
static void FblInit( vuint8 initposition )
{
   /* User initialization before core initializations */
   ApplFblStartup(kFblInitPreCallback | initposition); /* PRQA S 2986 */ /* MD_FblMain_2986 */

   switch (initposition)
   {
      /* Initialization steps the application validity is checked */
      case kFblInitBaseInitialization:
      {
         /* Initialize watchdog handling */
         FblInitWatchdog();
         /* Initialize Timer */
         FblTimerInit();
         break;
      }

      /* Initialization steps after the application validity is checked */
      case kFblInitFblCommunication:
      {

         EcuM_StartupTwo();

         /* Initialize diagnostic module */
         FblDiagInit();

#if defined( FBLBM_ENABLE_SECURE_BOOT )
         /* Initialize SecureBoot functionality */
         FblSb_Init();
#endif /* FBLBM_ENABLE_SECURE_BOOT */

#if defined( FBLNVPATTERN_ENABLE_SIGN_PRESENCE_PATTERN )
         /* Initialize extended presence pattern once */
         FblNvPatternSignedPresencePatternInit();
#endif /* FBLNVPATTERN_ENABLE_SIGN_PRESENCE_PATTERN */
         break;
      }

      /* Initialization steps executed after the Bootloader is invoked */
      case kFblInitFblFinalize:
      {

         /* Diagnostic layer - init steps after NV-memory init */
         FblDiagPostInit();
         break;
      }

      default:
      {
         assertFblInternal(0u, kFblSysAssertParameterOutOfRange); /* PRQA S 2741,4558 */ /* MD_FblMain_2741_4558 */
         break;
      }
   }

   /* User initialization after core initialization */
   ApplFblStartup(kFblInitPostCallback | initposition);
}

/***********************************************************************************************************************
 *  FblDeinit
 **********************************************************************************************************************/
/*! \brief       Do necessary deinitializations
 **********************************************************************************************************************/
static void FblDeinit( void )
{
   /* Deinitialize communication wrapper */
# if( FBL_CW_API_REFERENCE_VERSION_MAJOR == 0x02u )
   FblCw_Deinit();
# else
   FblCwDeinit();
# endif /* FBL_CW_API_REFERENCE_VERSION_MAJOR == 0x02u */

#if defined( FBL_WATCHDOG_ON )
   /* Synchronize watchdog before reset */
   ApplFblWDLong();
#endif /* FBL_WATCHDOG_ON */
   FblTimerStopp();  /* PRQA S 0303 */ /* MD_FBL_0303_MemoryMappedRegAccess */
}

# if defined( FBL_ENABLE_STAY_IN_BOOT )
/***********************************************************************************************************************
 *  FblRepeatCheckForStartMsg
 **********************************************************************************************************************/
/*! \brief       This function waits during the acceptance window if the start message is received.
 *  \pre         Hardware has to be initialized.
 **********************************************************************************************************************/
static void FblRepeatCheckForStartMsg( void )
{
   /* Set COM wrapper flag for start message window */
   FblCwSetCheckForStartMsg();
   while (FblMainGetWaitStartMessage())
   {
      /* Check if 1ms hardware timer expired */
      if ((FblLookForWatchdog() & FBL_TM_TRIGGERED) == FBL_TM_TRIGGERED)
      {
         /* Handle timer each millisecond */
         startMessageDelay--;
         if (startMessageDelay == 0u)
         {
            /* Start message wait time expired */
            FblMainClrWaitStartMessage();
            FblPostProcessStartMsg(kFblMainStartMessageTimeout);
         }
      }

      if (FblCwCheckStartMessage() == kFblOk)
      {
         /* Startup message has been received */
         FblMainClrWaitStartMessage();
         FblPostProcessStartMsg(kFblMainStartMessageReceived);
      }
   }
   /* Start message window is closed now */
   FblCwClrCheckForStartMsg();
}
# endif /* FBL_ENABLE_STAY_IN_BOOT */

/***********************************************************************************************************************
 *  FblRepeat
 **********************************************************************************************************************/
/*! \brief       This function contains the main loop of the FBL.
 *  \details     In this loop, the Bus is polled and the watchdog is triggered.
 *               This function is used by the boot procedure for the start delay and for the real operation.
 *  \pre         Hardware has to be initialized before.
 *  \return      The return value is used by the boot procedure to determine whether to stay in FBL or start the appl.
 **********************************************************************************************************************/
static void FblRepeat( void )
{
#if defined( FBL_DIAG_ENABLE_CORE_ASYNC_ROUTINE )
   FblMainSetFblRepeatStarted();
#endif /* FBL_DIAG_ENABLE_CORE_ASYNC_ROUTINE */

   /* This loop will be left only for reset */
   while (!FblMainGetFblShutdownRequest())
   {
      /* Check if 1ms hardware timer expired */
      if ((FblLookForWatchdog() & FBL_TM_TRIGGERED) == FBL_TM_TRIGGERED)
      {
         /* Run 1ms based tasks */
         FblDiagTimerTask();

#if defined( FBL_ENABLE_APPL_TIMER_TASK )
         /* Call cyclic function of fbl application module (if configured) */
         ApplFblTask();
#endif /* FBL_ENABLE_APPL_TIMER_TASK */
      }
      /* Run non-timer relevant operations */
      FblDiagStateTask();
      FblCwIdleTask();

# if defined( FBL_MEM_ENABLE_PIPELINING )
      if (FblMemTaskIsPending())
      {
         FblMemTask();
      }
# endif /* FBL_MEM_ENABLE_PIPELINING */

#if defined( FBL_ENABLE_APPL_STATE_TASK )
      /* Call background function of fbl application module (if configured) */
      ApplFblStateTask();
#endif /* FBL_ENABLE_APPL_STATE_TASK */

   }
#if defined( FBL_DIAG_ENABLE_CORE_ASYNC_ROUTINE )
   FblMainClrFblRepeatStarted();
#endif /* FBL_DIAG_ENABLE_CORE_ASYNC_ROUTINE */
}

/***********************************************************************************************************************
 *  GLOBAL FUNCTIONS
 **********************************************************************************************************************/

/***********************************************************************************************************************
 *  FblMain
 **********************************************************************************************************************/
/*! \brief       Wrapper function to call the actual FblMainInternal function
 **********************************************************************************************************************/
#if !defined( FBLBM_INSTANCE_BOOTMANAGER )
void V_API_NEAR FblMain( void ) /* PRQA S 5209 */ /* MD_FblMain_5209 */
{
  FblMainInternal();
}
#endif /* !FBLBM_INSTANCE_BOOTMANAGER */

/***********************************************************************************************************************
 *  FblMainInternal
 **********************************************************************************************************************/
/*! \brief       Main function of the Bootloader.
 *  \details     The FBL initializes the hardware and waits for a download request.
 **********************************************************************************************************************/
void V_API_NEAR FblMainInternal( void ) /* PRQA S 5209 */ /* MD_FblMain_5209 */
{
   /* Initialize variables */
   FblInitPowerOn();

   /* Base initialization step - valid for both application and Bootloader */
   FblInit(kFblInitBaseInitialization);

   /* Evaluate programming request flag and decide next bootloader step */
   FblCheckProgrammingRequest();

   /* Bootloader initialization step 1 - hardware and basic communication */
   FblInit(kFblInitFblCommunication);
# if defined( FBL_ENABLE_STAY_IN_BOOT )
   /* Check for start message */
   FblRepeatCheckForStartMsg();
# endif /* FBL_ENABLE_STAY_IN_BOOT */


   /* Bootloader initialization step 2 - full diagnostics initialization */
   FblInit(kFblInitFblFinalize);

   /* Bootloader execution */
   FblRepeat();

   /* Deinitialize and reset bootloader */
   FblDeinit();
   ApplFblReset();
}

#define FBLMAIN_STOP_SEC_CODE
#include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */

/***********************************************************************************************************************
 *  MISRA DEVIATIONS
 **********************************************************************************************************************/

/* Justification for module-specific MISRA deviations:

   MD_FBL_0303_MemoryMappedRegAccess:
      Reason:     Addressing memory mapped registers or other hardware specific feature requires casting a pointer type to
                  an integral type. This is a usual pattern for MCAL (Micro Controller Abstraction Layer) software.
      Risk:       Unintended read or write access into memory location.
      Prevention: Code inspection focus on correct access to expected memory location.

   MD_FblMain_1006:
      Reason:     Assembler code is used to deactivate interrupts and set context information.
      Risk:       The code is not portable for different compilers.
      Prevention: The assembler code provided by each FblHw module has to be tested.

   MD_FblMain_1514_FblHeader
      Reason:     MISRA: The object FblBmHeader is only referenced by function ..., in the translation unit where it is defined
                  This object is exported globally to other translation units
      Risk:       Name space pollution
      Prevention: No Prevention necessary

   MD_FblMain_2741_4558:
      Reason:     Assertion macros have to be disabled in production code and are used only for development.
      Risk:       Assertion code may be enabled in production code unintentionally. If a assertion condition is unexpectedly
                  false, the code is active. A problem may occur if the Macro is additionally changed from single statement
                  to multiple statement.
      Prevention: Macro is not allowed to be changed without review. Development code is automatically disabled via
                  configuration of project state "Production".

   MD_FblMain_2986:
      Reason:     This code is redundant but kept for clarity.
      Risk:       No risk.
      Prevention: No prevention necessary.

   MD_FblMain_3006:
      Reason:     Assembler code is used to deactivate interrupts and set context information.
      Risk:       The code is not portable for different compilers.
      Prevention: The assembler code provided by each FblHw module has to be tested.

   MD_FblMain_5209:
      Reason:     The Vector standard API for main function follows ANSI C typical definition of main function returning int.
      Risk:       No identifiable risk.
      Prevention: No prevention required.

   MD_FblMain_FblHeader:
      Reason:     A memory address is compared to a configured value. The configured value is interpreted as an integer.
      Risk:       The comparison may fail due to different data types.
      Prevention: If this check fails, the configuration checks done by assertions have to verified manually.

*/

/***********************************************************************************************************************
 *  END OF FILE: FBL_MAIN.C
 **********************************************************************************************************************/
