/***********************************************************************************************************************
 *  FILE DESCRIPTION
 *  ------------------------------------------------------------------------------------------------------------------*/
/** \file
 *  \brief        Interface layer for accessing the logical block table (LBT)
 *
 *  --------------------------------------------------------------------------------------------------------------------
 *  COPYRIGHT
 *  --------------------------------------------------------------------------------------------------------------------
 *  \par Copyright
 *  \verbatim
 *  Copyright (c) 2023 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
 *  --------------------------------------------------------------------------------------------------------------------
 *  01.00.00   2018-05-24  visci   -                Initial version
 *  01.01.00   2018-11-27  visshs  ESCAN00101459    Add Support for Secure Boot
 *  01.02.00   2019-02-26  visrie  ESCAN00102278    Added additional getter functions
 *  01.02.01   2019-09-05  visrcn  ESCAN00103604    Modified memory qualifiers
 *  01.03.00   2022-03-31  visstn  FBL-4366         Perform MISRA 2012 migration
 *  01.04.00   2022-10-17  visjns  FBL-4925         Change LBT access to use RAM
 *  01.04.01   2023-04-24  vismix  ESCAN00113819    Incorrect assertion expression in FblLbtActivateLbtBlockByAddress()
 *  01.05.00   2023-12-14  vistbe  FBL-7967         Add new filename attribute for LBT
 **********************************************************************************************************************/

#define FBL_LBT_ACCESS_SOURCE

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

#include "fbl_inc.h"

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

#if ( FBLLIB_LBT_VERSION != 0x0105u ) || \
    ( FBLLIB_LBT_RELEASE_VERSION != 0x00u )
# error "Error in fbl_lbt_access.c: Source and header file are inconsistent!"
#endif

#if ( FBLLIB_LBT_VERSION != _FBLLIB_LBT_VERSION ) || \
    ( FBLLIB_LBT_RELEASE_VERSION != _FBLLIB_LBT_RELEASE_VERSION )
# error "Error in fbl_lbt_access.c: Source and v_ver.h are inconsistent!"
#endif

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

/* Access of LBT in RAM  */
#if defined(FBL_LBT_ENABLE_RAM_BUFFER)
# define FBL_LBT_RAM_BUF_SIZE sizeof(tLogicalBlockTable)
#endif /* FBL_LBT_ENABLE_RAM_BUFFER */

/***********************************************************************************************************************
 *  TYPEDEFS
 **********************************************************************************************************************/

#if defined(FBL_LBT_ENABLE_RAM_BUFFER)
typedef const V_MEMRAM1 tLogicalBlockTable V_MEMRAM2 V_MEMRAM3 * tLogicalBlockTableConstPointer;
#endif /* FBL_LBT_ENABLE_RAM_BUFFER */

/***********************************************************************************************************************
 *  LOCAL DATA
 **********************************************************************************************************************/

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

V_MEMRAM0 static V_MEMRAM1 tFblLbtBlockNr V_MEMRAM2 fblLbtBlockIteratorNr;
V_MEMRAM0 static V_MEMRAM1 tFblLbtBlockFilter V_MEMRAM2 fblLbtBlockIteratorFilter;
V_MEMRAM0 static V_MEMRAM1 boolean V_MEMRAM2 fblLbtBlockIteratorDone;
#if defined(FBL_LBT_ENABLE_RAM_BUFFER)
V_MEMRAM0 static V_MEMRAM1 tLogicalBlockTable V_MEMRAM2 fblLbtRamBuffer;
V_MEMROM0 static tLogicalBlockTableConstPointer V_MEMROM1 V_MEMROM2 fblLbtActive = &fblLbtRamBuffer;
#else
V_MEMRAM0 static V_MEMROM1 tLogicalBlockTable V_MEMROM2 V_MEMROM3 * V_MEMRAM1 V_MEMRAM2 fblLbtActive;
#endif /* FBL_LBT_ENABLE_RAM_BUFFER */

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

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

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

static boolean FblLbtBlockFilterHit(const V_MEMRAM1 tFblLbtBlockFilter V_MEMRAM2 V_MEMRAM3 * blockFilter,
                                    const V_MEMRAM1 tBlockDescriptor V_MEMRAM2 V_MEMRAM3 * blockDescriptor);
#if defined( FBL_LBT_ENABLE_REPROGRAMMABLE_LBT )
static tFblResult FblLbtBlockCompare(const V_MEMRAM1 tBlockDescriptor V_MEMRAM2 V_MEMRAM3 * block1,
                                     const V_MEMRAM1 tBlockDescriptor V_MEMRAM2 V_MEMRAM3 * block2);
static tFblResult FblLbtCheckReferences(void);
#endif /* FBL_LBT_ENABLE_REPROGRAMMABLE_LBT */

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

/***********************************************************************************************************************
 *  FblLbtBlockFilterHit
 **********************************************************************************************************************/
/*! \brief       Check whether a certain block matches the filter settings
 *  \param[in]   blockFilter Block filter settings
 *  \param[in]   blockDescriptor Structure with block information
 *  \return      Possible return values:
 *               - TRUE if the block matches the filter criteria
 *               - FALSE otherwise
 **********************************************************************************************************************/
static boolean FblLbtBlockFilterHit(const V_MEMRAM1 tFblLbtBlockFilter V_MEMRAM2 V_MEMRAM3 * blockFilter,
                                    const V_MEMRAM1 tBlockDescriptor V_MEMRAM2 V_MEMRAM3 * blockDescriptor)
{
   /* Default setting: open filter */
   boolean result = TRUE;

   /* Check if mandatory/optional filter is enabled */
   if (blockFilter->mandatoryType.enabled == TRUE)
   {
      /* Check if this is a mandatory block */
      if (blockDescriptor->mandatoryType == TRUE)
      {
         /* Block is mandatory: compare against filter value */
         result = (blockFilter->mandatoryType.value == TRUE) ? TRUE : FALSE;
      }
      else
      {
         /* Block is optional: compare against filter value */
         result = (blockFilter->mandatoryType.value == FALSE) ? TRUE : FALSE;
      }
   }

#if defined( FBL_LBT_ENABLE_BLOCK_TYPE )
   /* Check if block type filter is enabled */
   if (blockFilter->blockType.enabled == TRUE)
   {
      /* AND logic: check if filter is still 'open' */
      if (result == TRUE)
      {
         result = (boolean)((blockDescriptor->blockType == blockFilter->blockType.value) ? TRUE : FALSE);
      }
   }
#endif /* FBL_LBT_ENABLE_BLOCK_TYPE */

   return result;
}

#if defined( FBL_LBT_ENABLE_REPROGRAMMABLE_LBT )
/***********************************************************************************************************************
 *  FblLbtBlockCompare
 **********************************************************************************************************************/
/*! \brief       Compare the parameters of two blocks (member-compare)
 *  \param[in]   block1 Structure with parameters of first block
 *  \param[in]   block2 Structure with parameters of second block
 *  \return      Possible return values:
 *               - kFblOk if the two blocks are equal
 *               - kFblFailed otherwise
 **********************************************************************************************************************/
static tFblResult FblLbtBlockCompare(const V_MEMRAM1 tBlockDescriptor V_MEMRAM2 V_MEMRAM3 * block1,
                                     const V_MEMRAM1 tBlockDescriptor V_MEMRAM2 V_MEMRAM3 * block2)
{
   tFblResult result = kFblOk;

   if (   (block1->blockNr           != block2->blockNr)
       || (block1->mandatoryType     != block2->mandatoryType)
       || (block1->blockStartAddress != block2->blockStartAddress)
       || (block1->blockLength       != block2->blockLength)
#if defined( FBL_LBT_ENABLE_BLOCK_INDEX )
       || (block1->blockIndex        != block2->blockIndex)
#endif
#if defined( FBL_LBT_ENABLE_BLOCK_TYPE )
       || (block1->blockType         != block2->blockType)
#endif
#if defined( FBL_LBT_ENABLE_HEADER_ADDRESS )
       || (block1->headerAddress     != block2->headerAddress)
#endif
#if defined( FBL_LBT_ENABLE_BM_HEADER_ADDRESS )
       || (block1->bmHeaderAddress   != block2->bmHeaderAddress)
#endif
#if defined( FBL_LBT_ENABLE_MAX_PROG_ATTEMPTS )
       || (block1->maxProgAttempts   != block2->maxProgAttempts)
#endif
#if defined( FBL_LBT_ENABLE_VERIFY_INPUT )
       || (block1->verifyInput       != block2->verifyInput)
#endif
#if defined( FBL_LBT_ENABLE_VERIFY_PROCESSED )
       || (block1->verifyProcessed   != block2->verifyProcessed)
#endif
#if defined( FBL_LBT_ENABLE_VERIFY_PIPELINED )
       || (block1->verifyPipelined   != block2->verifyPipelined)
#endif
#if defined( FBL_LBT_ENABLE_VERIFY_OUTPUT )
       || (block1->verifyOutput      != block2->verifyOutput)
#endif
      )
   {
      /* At least one of the block descriptor parameters doesn't match */
      result = kFblFailed;
   }

   return result;
}

/***********************************************************************************************************************
 *  FblLbtCheckReferences
 **********************************************************************************************************************/
/*! \brief       Check if the references which are used in the reprogrammable LBT are valid with the bootloader
 *  \return      Possible return values:
 *               - kFblOk if all references are valid
 *               - kFblFailed otherwise
 **********************************************************************************************************************/
static tFblResult FblLbtCheckReferences(void)
{
   tFblResult result = kFblOk;
   tFblLbtBlockFilter blockFilter = {0};
   tBlockDescriptor newLbtBlock = {0};
   vuint8 tableIdx = 0u;

   FblLbtBlockFilterInit(&blockFilter);

   newLbtBlock = FblLbtBlockFirst(&blockFilter);
   while ( FblLbtBlockDone() == FALSE )
   {
#if defined( FBL_LBT_ENABLE_BLOCK_TYPE )
      /* Compare actual block type against pre-defined list */
      result = kFblFailed;
      for (tableIdx = 0u; tableIdx < fblLbtBlockTypes.typeCount; tableIdx++)
      {
         if (newLbtBlock.blockType == fblLbtBlockTypes.type[tableIdx])
         {
            result = kFblOk;
            break;
         }
      }
#endif /* FBL_LBT_ENABLE_BLOCK_TYPE */

#if defined( FBL_LBT_ENABLE_VERIFY_INPUT )
      if (result == kFblOk)
      {
         /* Compare actual verification function against pre-defined list */
         result = kFblFailed;
         for (tableIdx = 0u; tableIdx < fblLbtVerificationFunc.funcCount; tableIdx++)
         {
            if (newLbtBlock.verifyInput == fblLbtVerificationFunc.func[tableIdx])
            {
               result = kFblOk;
               break;
            }
         }
      }
#endif /* FBL_LBT_ENABLE_VERIFY_INPUT */
#if defined( FBL_LBT_ENABLE_VERIFY_PROCESSED )
      if (result == kFblOk)
      {
         /* Compare actual verification function against pre-defined list */
         result = kFblFailed;
         for (tableIdx = 0u; tableIdx < fblLbtVerificationFunc.funcCount; tableIdx++)
         {
            if (newLbtBlock.verifyProcessed == fblLbtVerificationFunc.func[tableIdx])
            {
               result = kFblOk;
               break;
            }
         }
      }
#endif /* FBL_LBT_ENABLE_VERIFY_PROCESSED */
#if defined( FBL_LBT_ENABLE_VERIFY_PIPELINED )
      if (result == kFblOk)
      {
         /* Compare actual verification function against pre-defined list */
         result = kFblFailed;
         for (tableIdx = 0u; tableIdx < fblLbtVerificationFunc.funcCount; tableIdx++)
         {
            if (newLbtBlock.verifyPipelined == fblLbtVerificationFunc.func[tableIdx])
            {
               result = kFblOk;
               break;
            }
         }
      }
#endif /* FBL_LBT_ENABLE_VERIFY_PIPELINED */
#if defined( FBL_LBT_ENABLE_VERIFY_OUTPUT )
      if (result == kFblOk)
      {
         /* Compare actual verification function against pre-defined list */
         result = kFblFailed;
         for (tableIdx = 0u; tableIdx < fblLbtVerificationFunc.funcCount; tableIdx++)
         {
            if (newLbtBlock.verifyOutput == fblLbtVerificationFunc.func[tableIdx])
            {
               result = kFblOk;
               break;
            }
         }
      }
#endif /* FBL_LBT_ENABLE_VERIFY_OUTPUT */

      if (result != kFblOk)
      {
         /* Unknown reference used: abort */
         break;
      }

      newLbtBlock = FblLbtBlockNext();
   }

   return result;
}
#endif /* FBL_LBT_ENABLE_REPROGRAMMABLE_LBT */

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

/***********************************************************************************************************************
 *  FblLbtInitPowerOn
 **********************************************************************************************************************/
/*! \brief       Power-on initialization of the LBT access module
 **********************************************************************************************************************/
void FblLbtInitPowerOn(void)
{
#if defined(FBL_LBT_ENABLE_RAM_BUFFER)
   /* Initialize pointer with built-in LBT copied into RAM buffer */ /* PRQA S 0306 1 */ /* MD_FblLib_Lbt_0306 */
   (void)FblReadBlock((tFblAddress)&FblLogicalBlockTable, (vuint8*)&fblLbtRamBuffer, FBL_LBT_RAM_BUF_SIZE);
#else
   /* Initialize pointer with built-in LBT */
   fblLbtActive = &FblLogicalBlockTable;
#endif /* FBL_LBT_ENABLE_RAM_BUFFER */
}

/***********************************************************************************************************************
 *  FblLbtBlockFilterInit
 **********************************************************************************************************************/
/*! \brief       Initialize/reset the block filter structure
 *  \param[out]  blockFilter Structure with block filter parameters
 **********************************************************************************************************************/
void FblLbtBlockFilterInit(V_MEMRAM1 tFblLbtBlockFilter V_MEMRAM2 V_MEMRAM3 * blockFilter)
{
   blockFilter->mandatoryType.enabled = FALSE;
#if defined( FBL_LBT_ENABLE_BLOCK_TYPE )
   blockFilter->blockType.enabled = FALSE;
#endif
}

/***********************************************************************************************************************
 *  FblLbtBlockFilterSetMandatoryType
 **********************************************************************************************************************/
/*! \brief       Set and enable the filter for the mandatory type
 *  \param[out]  blockFilter Structure with block filter parameters
 *  \param[in]   mandatoryType The mandatory type value which shall be filtered (optional/mandatory)
 **********************************************************************************************************************/
void FblLbtBlockFilterSetMandatoryType(V_MEMRAM1 tFblLbtBlockFilter V_MEMRAM2 V_MEMRAM3 * blockFilter,
                                       tFblLbtMandatoryType mandatoryType)
{
   blockFilter->mandatoryType.value = mandatoryType;
   blockFilter->mandatoryType.enabled = TRUE;
}

#if defined( FBL_LBT_ENABLE_BLOCK_TYPE )
/***********************************************************************************************************************
 *  FblLbtBlockFilterSetBlockType
 **********************************************************************************************************************/
/*! \brief       Set and enable the filter for the block type
 *  \param[out]  blockFilter Structure with block filter parameters
 *  \param[in]   blockType The block type value which shall be filtered
 **********************************************************************************************************************/
void FblLbtBlockFilterSetBlockType(V_MEMRAM1 tFblLbtBlockFilter V_MEMRAM2 V_MEMRAM3 * blockFilter,
                                   tFblLbtBlockType blockType)
{
   blockFilter->blockType.value = blockType;
   blockFilter->blockType.enabled = TRUE;
}
#endif /* FBL_LBT_ENABLE_BLOCK_TYPE */

/***********************************************************************************************************************
 *  FblLbtBlockFirst
 **********************************************************************************************************************/
/*! \brief       Initialization/start function of the block iterator
 *  \param[in]   blockFilter Structure with block filter parameters
 *  \return      First block which matches the given filter settings
 **********************************************************************************************************************/
tBlockDescriptor FblLbtBlockFirst(const V_MEMRAM1 tFblLbtBlockFilter V_MEMRAM2 V_MEMRAM3 * blockFilter)
{
   fblLbtBlockIteratorNr = 0u;
   fblLbtBlockIteratorFilter = *blockFilter;
   fblLbtBlockIteratorDone = FALSE;

   return FblLbtBlockNext();
}

/***********************************************************************************************************************
 *  FblLbtBlockNext
 **********************************************************************************************************************/
/*! \brief       Continue/next function of the block iterator
 *  \return      Next block which matches the filter settings which have been passed to FblLbtBlockFirst
 **********************************************************************************************************************/
tBlockDescriptor FblLbtBlockNext(void)
{
   tBlockDescriptor blockDescriptor = {0};
   boolean filterResult = FALSE;

   /* Initialize block descriptor to avoid compiler warning (invalid descriptor will NOT be used, loop is aborted before) */
   blockDescriptor = FblLogicalBlockTable.logicalBlock[0u];

   while (fblLbtBlockIteratorNr < fblLbtActive->noOfBlocks)
   {
      /* Retrieve next block from LBT */
      blockDescriptor = fblLbtActive->logicalBlock[fblLbtBlockIteratorNr];

      /* Increment iterator */
      fblLbtBlockIteratorNr++;

      /* Test block descriptor against filter settings */
      filterResult = FblLbtBlockFilterHit(&fblLbtBlockIteratorFilter, &blockDescriptor);
      if (filterResult == TRUE)
      {
         /* Current block descriptor matches the filter settings, return to caller */
         break;
      }
   }

   if ((fblLbtBlockIteratorNr >= fblLbtActive->noOfBlocks) && (filterResult == FALSE))
   {
      /* No more blocks found, abort iteration */
      fblLbtBlockIteratorDone = TRUE;
   }

   return blockDescriptor;
}

/***********************************************************************************************************************
 *  FblLbtBlockDone
 **********************************************************************************************************************/
/*! \brief       Implementation of the exit condition of the block iterator
 *  \return      Boolean value which reflects the exit condition
 *               - FALSE: Last block not reached yet
 *               - TRUE : Last block has been reached
 **********************************************************************************************************************/
boolean FblLbtBlockDone(void)
{
   return fblLbtBlockIteratorDone;
}

/***********************************************************************************************************************
 *  FblLbtGetBlockCount
 **********************************************************************************************************************/
/*! \brief       Getter function for the actual block count of the active LBT
 *  \return      Number of blocks in the active LBT
 **********************************************************************************************************************/
tFblLbtBlockCount FblLbtGetBlockCount(void)
{
   return (tFblLbtBlockCount)fblLbtActive->noOfBlocks;
}

/***********************************************************************************************************************
 *  FblLbtGetMagicFlag
 **********************************************************************************************************************/
/*! \brief       Getter function to read the magic flag
 *  \return      Magic flag value
 **********************************************************************************************************************/
tFblLbtMagicFlag FblLbtGetMagicFlag(void)
{
   return (tFblLbtMagicFlag)fblLbtActive->magicFlag;
}

/***********************************************************************************************************************
 *  FblLbtGetBlockNrByAddressLength
 **********************************************************************************************************************/
/*! \brief       Look up and return the block number for a given memory range
 *  \param[in]   address Start address of the memory range
 *  \param[in]   length Length of the memory range
 *  \param[out]  Block number of the respective block (if found)
 *  \return      Possible return values:
 *               - kFblOk if block number could be retrieved successfully
 *               - kFblFailed otherwise
 **********************************************************************************************************************/
tFblResult FblLbtGetBlockNrByAddressLength(tFblAddress address, tFblLength length,
                                           V_MEMRAM1 tFblLbtBlockNr V_MEMRAM2 V_MEMRAM3 * blockNr)
{
   tFblResult result = kFblFailed;
   tBlockDescriptor localBlockDescriptor = {0};
   tFblLbtBlockFilter blockFilter = {0};

   /* Configure block filter (clear all filter settings) */
   FblLbtBlockFilterInit(&blockFilter);

   localBlockDescriptor = FblLbtBlockFirst(&blockFilter);
   while (FblLbtBlockDone() == FALSE)
   {
      result = FblLbtCheckRangeContained(address, length,
                                         localBlockDescriptor.blockStartAddress,
                                         localBlockDescriptor.blockLength);
      if (result == kFblOk)
      {
         *blockNr = localBlockDescriptor.blockNr;
         break;
      }

      localBlockDescriptor = FblLbtBlockNext();
   }

   return result;
}

/***********************************************************************************************************************
 *  FblLbtGetBlockDescriptorByNr
 **********************************************************************************************************************/
/*! \brief       Look up and return the block descriptor with a certain block number value
 *  \param[in]   blockNr Block number value of the block to be retrieved
 *  \param[out]  blockDescriptor Parameter structure with the information of the respective block
 *  \return      Possible return values:
 *               - kFblOk if descriptor could be retrieved successfully
 *               - kFblFailed otherwise
 **********************************************************************************************************************/
tFblResult FblLbtGetBlockDescriptorByNr(tFblLbtBlockNr blockNr,
                                        V_MEMRAM1 tBlockDescriptor V_MEMRAM2 V_MEMRAM3 * blockDescriptor)
{
   tFblResult result = kFblFailed;

   if (blockNr < fblLbtActive->noOfBlocks)
   {
     *blockDescriptor = fblLbtActive->logicalBlock[blockNr];
     result = kFblOk;
   }

   return result;
}

/***********************************************************************************************************************
 *  FblLbtGetBlockDescriptorByAddressLength
 **********************************************************************************************************************/
/*! \brief       Look up and return the block descriptor for a given memory range
 *  \param[in]   address Start address of the memory range
 *  \param[in]   length Length of the memory range
 *  \param[out]  blockDescriptor Parameter structure with the information of the respective block
 *  \return      Possible return values:
 *               - kFblOk if block descriptor could be retrieved successfully
 *               - kFblFailed otherwise
 **********************************************************************************************************************/
tFblResult FblLbtGetBlockDescriptorByAddressLength(tFblAddress address, tFblLength length,
                                                   V_MEMRAM1 tBlockDescriptor V_MEMRAM2 V_MEMRAM3 * blockDescriptor)
{
   tFblResult result = kFblFailed;
   tFblLbtBlockNr localBlockNr = 0u;

   result = FblLbtGetBlockNrByAddressLength(address, length, &localBlockNr);

   if (result == kFblOk)
   {
      result = FblLbtGetBlockDescriptorByNr(localBlockNr, blockDescriptor);
   }

   return result;
}

#if defined( FBL_LBT_ENABLE_BLOCK_TYPE )
/***********************************************************************************************************************
 *  FblLbtGetBlockDescriptorByType
 **********************************************************************************************************************/
/*! \brief       Look up and return the first block descriptor with a certain block type value
 *  \param[in]   blockType Type value of the block to be retrieved
 *  \param[out]  blockDescriptor Parameter structure with the information of the respective block
 *  \return      Possible return values:
 *               - kFblOk if descriptor could be retrieved successfully
 *               - kFblFailed otherwise
 **********************************************************************************************************************/
tFblResult FblLbtGetBlockDescriptorByType(tFblLbtBlockType blockType,
                                          V_MEMRAM1 tBlockDescriptor V_MEMRAM2 V_MEMRAM3 * blockDescriptor)
{
   tFblResult result = kFblFailed;
   tBlockDescriptor localBlockDescriptor = {0};
   tFblLbtBlockFilter blockFilter = {0};

   /* Configure block filter (clear all filter settings) */
   FblLbtBlockFilterInit(&blockFilter);

   localBlockDescriptor = FblLbtBlockFirst(&blockFilter);
   while ( FblLbtBlockDone() == FALSE )
   {
      if (localBlockDescriptor.blockType == blockType)
      {
         *blockDescriptor = localBlockDescriptor;
         result = kFblOk;
         break;
      }

      localBlockDescriptor = FblLbtBlockNext();
   }

   return result;
}
#endif /* FBL_LBT_ENABLE_BLOCK_TYPE */

#if defined( FBL_LBT_ENABLE_BLOCK_TYPE )
/***********************************************************************************************************************
 *  FblLbtGetBlockTypeByNr
 **********************************************************************************************************************/
/*! \brief       Look up and return the block type with a certain block index value
 *  \param[in]   blockNr Block number value of the block to be retrieved
 *  \param[out]  blockType Type of the respective block
 *  \return      Possible return values:
 *               - kFblOk if block type could be retrieved successfully
 *               - kFblFailed otherwise
 **********************************************************************************************************************/
tFblResult FblLbtGetBlockTypeByNr(tFblLbtBlockNr blockNr,
                                  V_MEMRAM1 tFblLbtBlockType V_MEMRAM2 V_MEMRAM3 * blockType)
{
   tFblResult result = kFblFailed;
   tBlockDescriptor blockDescriptor = {0};

   /* Initialize block type to resolve MISRA finding (blockDescriptor is only valid in case 'kFblOk' is returned) */
   blockDescriptor.blockType = 0uL;

   if (FblLbtGetBlockDescriptorByNr(blockNr, &blockDescriptor) == kFblOk)
   {
      *blockType = blockDescriptor.blockType;
      result = kFblOk;
   }

   return result;
}
#endif /* FBL_LBT_ENABLE_BLOCK_TYPE */

#if defined( FBL_LBT_ENABLE_BLOCK_INDEX )
/***********************************************************************************************************************
*  FblLbtGetBlockIndexByNr
**********************************************************************************************************************/
/*! \brief       Look up and return the block index with a certain block index value
*  \param[in]   blockNr Block number value of the block to be retrieved
*  \param[out]  blockIndex Index of the respective block
*  \return      Possible return values:
*               - kFblOk if block type could be retrieved successfully
*               - kFblFailed otherwise
**********************************************************************************************************************/
tFblResult FblLbtGetBlockIndexByNr(tFblLbtBlockNr blockNr, V_MEMRAM1 tFblLbtBlockIndex V_MEMRAM2 V_MEMRAM3 * blockIndex)
{
   tFblResult result = kFblFailed;
   tBlockDescriptor blockDescriptor = {0};

   /* Initialize block type to resolve MISRA finding (blockDescriptor is only valid in case 'kFblOk' is returned) */
   blockDescriptor.blockIndex = 0uL;

   if (FblLbtGetBlockDescriptorByNr(blockNr, &blockDescriptor) == kFblOk)
   {
      *blockIndex = blockDescriptor.blockIndex;
      result = kFblOk;
   }

   return result;
}
#endif /* FBL_LBT_ENABLE_BLOCK_INDEX */

#if defined( FBL_LBT_ENABLE_HEADER_ADDRESS )
/***********************************************************************************************************************
 *  FblLbtGetBlockHeaderAddressByNr
 **********************************************************************************************************************/
/*! \brief       Look up and return the block header address with a certain block index value
 *  \param[in]   blockNr Block number value of the block to be retrieved
 *  \param[out]  blockHeaderAddress Header address of the respective block
 *  \return      Possible return values:
 *               - kFblOk if header address could be retrieved successfully
 *               - kFblFailed otherwise
 **********************************************************************************************************************/
tFblResult FblLbtGetBlockHeaderAddressByNr(tFblLbtBlockNr blockNr,
                                           V_MEMRAM1 tFblAddress V_MEMRAM2 V_MEMRAM3 * blockHeaderAddress)
{
   tFblResult result = kFblFailed;
   tBlockDescriptor blockDescriptor = {0};

   /* Initialize header address to resolve MISRA finding (blockDescriptor is only valid in case 'kFblOk' is returned) */
   blockDescriptor.headerAddress = 0uL;

   if (FblLbtGetBlockDescriptorByNr(blockNr, &blockDescriptor) == kFblOk)
   {
      *blockHeaderAddress = blockDescriptor.headerAddress;
      result = kFblOk;
   }

   return result;
}
#endif /* FBL_LBT_ENABLE_BLOCK_HEADER_ADDRESS */

#if defined( FBL_LBT_ENABLE_BM_HEADER_ADDRESS )
/***********************************************************************************************************************
 *  FblLbtGetBlockBmHeaderAddressByNr
 **********************************************************************************************************************/
/*! \brief       Look up and return the bootmanager header address with a certain block index value
 *  \param[in]   blockNr Block number value of the block to be retrieved
 *  \param[out]  bmHeaderAddress BM Header address of the respective block
 *  \return      Possible return values:
 *               - kFblOk if header address could be retrieved successfully
 *               - kFblFailed otherwise
 **********************************************************************************************************************/
tFblResult FblLbtGetBlockBmHeaderAddressByNr(tFblLbtBlockNr blockNr,
                                             V_MEMRAM1 tFblAddress V_MEMRAM2 V_MEMRAM3 * bmHeaderAddress)
{
   tFblResult result = kFblFailed;
   tBlockDescriptor blockDescriptor = {0};

   /* Initialize BM header address to resolve MISRA finding (blockDescriptor is only valid in case 'kFblOk' is returned) */
   blockDescriptor.bmHeaderAddress = 0uL;

   if (FblLbtGetBlockDescriptorByNr(blockNr, &blockDescriptor) == kFblOk)
   {
      *bmHeaderAddress = blockDescriptor.bmHeaderAddress;
      result = kFblOk;
   }

   return result;
}
#endif /* FBL_LBT_ENABLE_BM_HEADER_ADDRESS */

#if defined( FBL_LBT_ENABLE_MAX_PROG_ATTEMPTS )
/***********************************************************************************************************************
 *  FblLbtGetBlockMaxProgAttemptsByNr
 **********************************************************************************************************************/
/*! \brief       Look up and return the maximum programming attempts with a certain block index value
 *  \param[in]   blockNr Block number value of the block to be retrieved
 *  \param[out]  maxProgAttempts Maxmimum programming attempts of the respective block
 *  \return      Possible return values:
 *               - kFblOk if maximum programming attempts could be retrieved successfully
 *               - kFblFailed otherwise
 **********************************************************************************************************************/
tFblResult FblLbtGetBlockMaxProgAttemptsByNr(tFblLbtBlockNr blockNr,
                                             V_MEMRAM1 tFblLbtMaxProgAttempts V_MEMRAM2 V_MEMRAM3 * maxProgAttempts)
{
   tFblResult result = kFblFailed;
   tBlockDescriptor blockDescriptor = {0};

   /* Initialize maximum programming attempts to resolve MISRA finding (blockDescriptor is only valid in case 'kFblOk' is returned) */
   blockDescriptor.maxProgAttempts = 0u;

   if (FblLbtGetBlockDescriptorByNr(blockNr, &blockDescriptor) == kFblOk)
   {
      *maxProgAttempts = blockDescriptor.maxProgAttempts;
      result = kFblOk;
   }

   return result;
}
#endif /* FBL_LBT_ENABLE_MAX_PROG_ATTEMPTS */

#if defined( FBL_LBT_ENABLE_VERIFY_INPUT )
/***********************************************************************************************************************
 *  FblLbtGetBlockVerifyInputFuncByNr
 **********************************************************************************************************************/
/*! \brief       Look up and return the verification function
 *  \param[in]   blockNr Block number value of the block to be retrieved
 *  \param[out]  blockVerifyFunc Address of the block specific verification function
 *  \return      Possible return values:
 *               - kFblOk if verification function could be retrieved successfully
 *               - kFblFailed otherwise
 **********************************************************************************************************************/
tFblResult FblLbtGetBlockVerifyInputFuncByNr(tFblLbtBlockNr blockNr,
                                             V_MEMRAM1 tExportFct V_MEMRAM2 V_MEMRAM3 * blockVerifyFunc)
{
   tFblResult result = kFblFailed;
   tBlockDescriptor blockDescriptor = {0};

   /* Initialize verify function to resolve MISRA finding (blockDescriptor is only valid in case 'kFblOk' is returned) */
   blockDescriptor.verifyInput = (tExportFct)0;

   if (FblLbtGetBlockDescriptorByNr(blockNr, &blockDescriptor) == kFblOk)
   {
      *blockVerifyFunc = blockDescriptor.verifyInput;
      result = kFblOk;
   }

   return result;
}
#endif /* FBL_LBT_ENABLE_VERIFY_INPUT */

#if defined( FBL_LBT_ENABLE_VERIFY_PROCESSED )
/***********************************************************************************************************************
 *  FblLbtGetBlockVerifyProcessedFuncByNr
 **********************************************************************************************************************/
/*! \brief       Look up and return the verification function
 *  \param[in]   blockNr Block number value of the block to be retrieved
 *  \param[out]  blockVerifyFunc Address of the block specific verification function
 *  \return      Possible return values:
 *               - kFblOk if verification function could be retrieved successfully
 *               - kFblFailed otherwise
 **********************************************************************************************************************/
tFblResult FblLbtGetBlockVerifyProcessedFuncByNr(tFblLbtBlockNr blockNr,
                                                 V_MEMRAM1 tExportFct V_MEMRAM2 V_MEMRAM3 * blockVerifyFunc)
{
   tFblResult result = kFblFailed;
   tBlockDescriptor blockDescriptor = {0};

   /* Initialize verify function to resolve MISRA finding (blockDescriptor is only valid in case 'kFblOk' is returned) */
   blockDescriptor.verifyProcessed = (tExportFct)0;

   if (FblLbtGetBlockDescriptorByNr(blockNr, &blockDescriptor) == kFblOk)
   {
      *blockVerifyFunc = blockDescriptor.verifyProcessed;
      result = kFblOk;
   }

   return result;
}
#endif /* FBL_LBT_ENABLE_VERIFY_PROCESSED */

#if defined( FBL_LBT_ENABLE_VERIFY_PIPELINED )
/***********************************************************************************************************************
 *  FblLbtGetBlockVerifyPipelinedFuncByNr
 **********************************************************************************************************************/
/*! \brief       Look up and return the verification function
 *  \param[in]   blockNr Block number value of the block to be retrieved
 *  \param[out]  blockVerifyFunc Address of the block specific verification function
 *  \return      Possible return values:
 *               - kFblOk if verification function could be retrieved successfully
 *               - kFblFailed otherwise
 **********************************************************************************************************************/
tFblResult FblLbtGetBlockVerifyPipelinedFuncByNr(tFblLbtBlockNr blockNr,
                                                 V_MEMRAM1 tExportFct V_MEMRAM2 V_MEMRAM3 * blockVerifyFunc)
{
   tFblResult result = kFblFailed;
   tBlockDescriptor blockDescriptor = {0};

   /* Initialize verify function to resolve MISRA finding (blockDescriptor is only valid in case 'kFblOk' is returned) */
   blockDescriptor.verifyPipelined = (tExportFct)0;

   if (FblLbtGetBlockDescriptorByNr(blockNr, &blockDescriptor) == kFblOk)
   {
      *blockVerifyFunc = blockDescriptor.verifyPipelined;
      result = kFblOk;
   }

   return result;
}
#endif /* FBL_LBT_ENABLE_VERIFY_PIPELINED */

#if defined( FBL_LBT_ENABLE_VERIFY_OUTPUT )
/***********************************************************************************************************************
 *  FblLbtGetBlockVerifyOutputFuncByNr
 **********************************************************************************************************************/
/*! \brief       Look up and return the block header address with a certain block index value
 *  \param[in]   blockNr Block number value of the block to be retrieved
 *  \param[out]  blockVerifyFunc Address of the block specific verification function
 *  \return      Possible return values:
 *               - kFblOk if verification function could be retrieved successfully
 *               - kFblFailed otherwise
 **********************************************************************************************************************/
tFblResult FblLbtGetBlockVerifyOutputFuncByNr(tFblLbtBlockNr blockNr,
                                              V_MEMRAM1 tExportFct V_MEMRAM2 V_MEMRAM3 * blockVerifyFunc)
{
   tFblResult result = kFblFailed;
   tBlockDescriptor blockDescriptor = {0};

   /* Initialize verify function to resolve MISRA finding (blockDescriptor is only valid in case 'kFblOk' is returned) */
   blockDescriptor.verifyOutput = (tExportFct)0uL;

   if (FblLbtGetBlockDescriptorByNr(blockNr, &blockDescriptor) == kFblOk)
   {
      *blockVerifyFunc = blockDescriptor.verifyOutput;
      result = kFblOk;
   }

   return result;
}
#endif /* FBL_LBT_ENABLE_VERIFY_OUTPUT */

#if defined( FBL_LBT_ENABLE_BLOCK_INDEX )
/***********************************************************************************************************************
 *  FblLbtGetBlockDescriptorByIndex
 **********************************************************************************************************************/
/*! \brief       Look up and return the block descriptor with a certain block index value
 *  \param[in]   blockIndex Index value of the block to be retrieved
 *  \param[out]  blockDescriptor Parameter structure with the information of the respective block
 *  \return      Possible return values:
 *               - kFblOk if descriptor could be retrieved successfully
 *               - kFblFailed otherwise
 **********************************************************************************************************************/
tFblResult FblLbtGetBlockDescriptorByIndex(tFblLbtBlockIndex blockIndex,
                                           V_MEMRAM1 tBlockDescriptor V_MEMRAM2 V_MEMRAM3 * blockDescriptor)
{
   tFblResult result = kFblFailed;
   tBlockDescriptor localBlockDescriptor = {0};
   tFblLbtBlockFilter blockFilter = {0};

   /* Configure block filter (clear all filter settings) */
   FblLbtBlockFilterInit(&blockFilter);

   localBlockDescriptor = FblLbtBlockFirst(&blockFilter);
   while ( FblLbtBlockDone() == FALSE )
   {
      if (localBlockDescriptor.blockIndex == blockIndex)
      {
         *blockDescriptor = localBlockDescriptor;
         result = kFblOk;
         break;
      }

      localBlockDescriptor = FblLbtBlockNext();
   }

   return result;
}

/***********************************************************************************************************************
 *  FblLbtGetBlockNrByIndex
 **********************************************************************************************************************/
/*! \brief       Look up and return the block number with a certain block index value
 *  \param[in]   blockIndex Index value of the block to be retrieved
 *  \param[out]  blockNr Number of the respective block
 *  \return      Possible return values:
 *               - kFblOk if block number could be retrieved successfully
 *               - kFblFailed otherwise
 **********************************************************************************************************************/
tFblResult FblLbtGetBlockNrByIndex(tFblLbtBlockIndex blockIndex,
   V_MEMRAM1 tFblLbtBlockNr V_MEMRAM2 V_MEMRAM3 * blockNr)
{
   tFblResult result = kFblFailed;
   tBlockDescriptor blockDescriptor = {0};

   /* Initialize block number to resolve MISRA finding (blockDescriptor is only valid in case 'kFblOk' is returned) */
   blockDescriptor.blockNr = 0u;

   if (FblLbtGetBlockDescriptorByIndex(blockIndex, &blockDescriptor) == kFblOk)
   {
      *blockNr = blockDescriptor.blockNr;
      result = kFblOk;
   }

   return result;
}

# if defined( FBL_LBT_ENABLE_BLOCK_TYPE )
/***********************************************************************************************************************
 *  FblLbtGetBlockTypeByIndex
 **********************************************************************************************************************/
/*! \brief       Look up and return the block type with a certain block index value
 *  \param[in]   blockIndex Index value of the block to be retrieved
 *  \param[out]  blockType Type of the respective block
 *  \return      Possible return values:
 *               - kFblOk if block type could be retrieved successfully
 *               - kFblFailed otherwise
 **********************************************************************************************************************/
tFblResult FblLbtGetBlockTypeByIndex(tFblLbtBlockIndex blockIndex,
                                     V_MEMRAM1 tFblLbtBlockType V_MEMRAM2 V_MEMRAM3 * blockType)
{
   tFblResult result = kFblFailed;
   tBlockDescriptor blockDescriptor = {0};

   /* Initialize block type to resolve MISRA finding (blockDescriptor is only valid in case 'kFblOk' is returned) */
   blockDescriptor.blockType = 0uL;

   if (FblLbtGetBlockDescriptorByIndex(blockIndex, &blockDescriptor) == kFblOk)
   {
      *blockType = blockDescriptor.blockType;
      result = kFblOk;
   }

   return result;
}
# endif /* FBL_LBT_ENABLE_BLOCK_TYPE */

# if defined( FBL_LBT_ENABLE_HEADER_ADDRESS )
/***********************************************************************************************************************
 *  FblLbtGetBlockHeaderAddressByIndex
 **********************************************************************************************************************/
/*! \brief       Look up and return the block header address with a certain block index value
 *  \param[in]   blockIndex Index value of the block to be retrieved
 *  \param[out]  blockHeaderAddress Header address of the respective block
 *  \return      Possible return values:
 *               - kFblOk if header address could be retrieved successfully
 *               - kFblFailed otherwise
 **********************************************************************************************************************/
tFblResult FblLbtGetBlockHeaderAddressByIndex(tFblLbtBlockIndex blockIndex,
                                              V_MEMRAM1 tFblAddress V_MEMRAM2 V_MEMRAM3 * blockHeaderAddress)
{
   tFblResult result = kFblFailed;
   tBlockDescriptor blockDescriptor = {0};

   /* Initialize header address to resolve MISRA finding (blockDescriptor is only valid in case 'kFblOk' is returned) */
   blockDescriptor.headerAddress = 0uL;

   if (FblLbtGetBlockDescriptorByIndex(blockIndex, &blockDescriptor) == kFblOk)
   {
      *blockHeaderAddress = blockDescriptor.headerAddress;
      result = kFblOk;
   }

   return result;
}
# endif /* FBL_LBT_ENABLE_BLOCK_HEADER_ADDRESS */

# if defined( FBL_LBT_ENABLE_BM_HEADER_ADDRESS )
/***********************************************************************************************************************
 *  FblLbtGetBlockBmHeaderAddressByIndex
 **********************************************************************************************************************/
/*! \brief       Look up and return the bootmanager header address with a certain block index value
 *  \param[in]   blockIndex Index value of the block to be retrieved
 *  \param[out]  bmHeaderAddress BM Header address of the respective block
 *  \return      Possible return values:
 *               - kFblOk if header address could be retrieved successfully
 *               - kFblFailed otherwise
 **********************************************************************************************************************/
tFblResult FblLbtGetBlockBmHeaderAddressByIndex(tFblLbtBlockIndex blockIndex,
                                                V_MEMRAM1 tFblAddress V_MEMRAM2 V_MEMRAM3 * bmHeaderAddress)
{
   tFblResult result = kFblFailed;
   tBlockDescriptor blockDescriptor = {0};

   /* Initialize BM header address to resolve MISRA finding (blockDescriptor is only valid in case 'kFblOk' is returned) */
   blockDescriptor.bmHeaderAddress = 0uL;

   if (FblLbtGetBlockDescriptorByIndex(blockIndex, &blockDescriptor) == kFblOk)
   {
      *bmHeaderAddress = blockDescriptor.bmHeaderAddress;
      result = kFblOk;
   }

   return result;
}
# endif /* FBL_LBT_ENABLE_BM_HEADER_ADDRESS */

# if defined( FBL_LBT_ENABLE_MAX_PROG_ATTEMPTS )
/***********************************************************************************************************************
 *  FblLbtGetBlockMaxProgAttemptsByIndex
 **********************************************************************************************************************/
/*! \brief       Look up and return the maximum programming attempts with a certain block index value
 *  \param[in]   blockIndex Index value of the block to be retrieved
 *  \param[out]  maxProgAttempts Maxmimum programming attempts of the respective block
 *  \return      Possible return values:
 *               - kFblOk if maximum programming attempts could be retrieved successfully
 *               - kFblFailed otherwise
 **********************************************************************************************************************/
tFblResult FblLbtGetBlockMaxProgAttemptsByIndex(tFblLbtBlockIndex blockIndex,
                                                V_MEMRAM1 tFblLbtMaxProgAttempts V_MEMRAM2 V_MEMRAM3 * maxProgAttempts)
{
   tFblResult result = kFblFailed;
   tBlockDescriptor blockDescriptor = {0};

   /* Initialize maximum programming attempts to resolve MISRA finding (blockDescriptor is only valid in case 'kFblOk' is returned) */
   blockDescriptor.maxProgAttempts = 0u;

   if (FblLbtGetBlockDescriptorByIndex(blockIndex, &blockDescriptor) == kFblOk)
   {
      *maxProgAttempts = blockDescriptor.maxProgAttempts;
      result = kFblOk;
   }

   return result;
}
# endif /* FBL_LBT_ENABLE_MAX_PROG_ATTEMPTS */

# if defined( FBL_LBT_ENABLE_VERIFY_INPUT )
/***********************************************************************************************************************
 *  FblLbtGetBlockVerifyInputFuncByIndex
 **********************************************************************************************************************/
/*! \brief       Look up and return the verification function
 *  \param[in]   blockIndex Index value of the block to be retrieved
 *  \param[out]  blockVerifyFunc Address of the block specific verification function
 *  \return      Possible return values:
 *               - kFblOk if verification function could be retrieved successfully
 *               - kFblFailed otherwise
 **********************************************************************************************************************/
tFblResult FblLbtGetBlockVerifyInputFuncByIndex(tFblLbtBlockIndex blockIndex,
                                                V_MEMRAM1 tExportFct V_MEMRAM2 V_MEMRAM3 * blockVerifyFunc)
{
   tFblResult result = kFblFailed;
   tBlockDescriptor blockDescriptor = {0};

   /* Initialize verify function to resolve MISRA finding (blockDescriptor is only valid in case 'kFblOk' is returned) */
   blockDescriptor.verifyInput = (tExportFct)0;

   if (FblLbtGetBlockDescriptorByIndex(blockIndex, &blockDescriptor) == kFblOk)
   {
      *blockVerifyFunc = blockDescriptor.verifyInput;
      result = kFblOk;
   }

   return result;
}
# endif /* FBL_LBT_ENABLE_VERIFY_INPUT */

# if defined( FBL_LBT_ENABLE_VERIFY_PROCESSED )
/***********************************************************************************************************************
 *  FblLbtGetBlockVerifyProcessedFuncByIndex
 **********************************************************************************************************************/
/*! \brief       Look up and return the verification function
 *  \param[in]   blockIndex Index value of the block to be retrieved
 *  \param[out]  blockVerifyFunc Address of the block specific verification function
 *  \return      Possible return values:
 *               - kFblOk if verification function could be retrieved successfully
 *               - kFblFailed otherwise
 **********************************************************************************************************************/
tFblResult FblLbtGetBlockVerifyProcessedFuncByIndex(tFblLbtBlockIndex blockIndex,
                                                    V_MEMRAM1 tExportFct V_MEMRAM2 V_MEMRAM3 * blockVerifyFunc)
{
   tFblResult result = kFblFailed;
   tBlockDescriptor blockDescriptor = {0};

   /* Initialize verify function to resolve MISRA finding (blockDescriptor is only valid in case 'kFblOk' is returned) */
   blockDescriptor.verifyProcessed = (tExportFct)0;

   if (FblLbtGetBlockDescriptorByIndex(blockIndex, &blockDescriptor) == kFblOk)
   {
      *blockVerifyFunc = blockDescriptor.verifyProcessed;
      result = kFblOk;
   }

   return result;
}
# endif /* FBL_LBT_ENABLE_VERIFY_PROCESSED */

# if defined( FBL_LBT_ENABLE_VERIFY_PIPELINED )
/***********************************************************************************************************************
 *  FblLbtGetBlockVerifyPipelinedFuncByIndex
 **********************************************************************************************************************/
/*! \brief       Look up and return the verification function
 *  \param[in]   blockIndex Index value of the block to be retrieved
 *  \param[out]  blockVerifyFunc Address of the block specific verification function
 *  \return      Possible return values:
 *               - kFblOk if verification function could be retrieved successfully
 *               - kFblFailed otherwise
 **********************************************************************************************************************/
tFblResult FblLbtGetBlockVerifyPipelinedFuncByIndex(tFblLbtBlockIndex blockIndex,
                                                    V_MEMRAM1 tExportFct V_MEMRAM2 V_MEMRAM3 * blockVerifyFunc)
{
   tFblResult result = kFblFailed;
   tBlockDescriptor blockDescriptor = {0};

   /* Initialize verify function to resolve MISRA finding (blockDescriptor is only valid in case 'kFblOk' is returned) */
   blockDescriptor.verifyPipelined = (tExportFct)0;

   if (FblLbtGetBlockDescriptorByIndex(blockIndex, &blockDescriptor) == kFblOk)
   {
      *blockVerifyFunc = blockDescriptor.verifyPipelined;
      result = kFblOk;
   }

   return result;
}
# endif /* FBL_LBT_ENABLE_VERIFY_PIPELINED */

# if defined( FBL_LBT_ENABLE_VERIFY_OUTPUT )
/***********************************************************************************************************************
 *  FblLbtGetBlockVerifyOutputFuncByIndex
 **********************************************************************************************************************/
/*! \brief       Look up and return the block header address with a certain block index value
 *  \param[in]   blockIndex Index value of the block to be retrieved
 *  \param[out]  blockVerifyFunc Address of the block specific verification function
 *  \return      Possible return values:
 *               - kFblOk if verification function could be retrieved successfully
 *               - kFblFailed otherwise
 **********************************************************************************************************************/
tFblResult FblLbtGetBlockVerifyOutputFuncByIndex(tFblLbtBlockIndex blockIndex,
                                                 V_MEMRAM1 tExportFct V_MEMRAM2 V_MEMRAM3 * blockVerifyFunc)
{
   tFblResult result = kFblFailed;
   tBlockDescriptor blockDescriptor = {0};

   /* Initialize verify function to resolve MISRA finding (blockDescriptor is only valid in case 'kFblOk' is returned) */
   blockDescriptor.verifyOutput = (tExportFct)0;

   if (FblLbtGetBlockDescriptorByIndex(blockIndex, &blockDescriptor) == kFblOk)
   {
      *blockVerifyFunc = blockDescriptor.verifyOutput;
      result = kFblOk;
   }

   return result;
}
# endif /* FBL_LBT_ENABLE_VERIFY_OUTPUT */
#endif /* FBL_LBT_ENABLE_BLOCK_INDEX */

#if defined( FBL_LBT_ENABLE_FILE_NAME )
/***********************************************************************************************************************
 *  FblLbtGetBlockDescriptorByFilenameLength
 **********************************************************************************************************************/
/*! \brief       Look up and return the block descriptor for a file name and length
 *  \param[in]   fileName Name of the file
 *  \param[in]   fileNameSize Size of the give file name
*   \param[in]   fileLength Length of the file to be downloaded
 *  \param[out]  blockDescriptor Parameter structure with the information of the respective block
 *  \return      Possible return values:
 *               - kFblOk if block descriptor could be retrieved successfully
 *               - kFblFailed otherwise
 **********************************************************************************************************************/
tFblResult FblLbtGetBlockDescriptorByFilenameLength(const V_MEMRAM1 tFblLbtFileName V_MEMRAM2 V_MEMRAM3 * fileName,
   tFblLbtFileNameSize fileNameSize, tFblLength fileLength, V_MEMRAM1 tBlockDescriptor V_MEMRAM2 V_MEMRAM3 * blockDescriptor)
{
   tFblResult result = kFblFailed;
   tBlockDescriptor localBlockDescriptor = {0};
   tFblLbtBlockFilter blockFilter = {0};

   /* Configure block filter (clear all filter settings) */
   FblLbtBlockFilterInit(&blockFilter);

   localBlockDescriptor = FblLbtBlockFirst(&blockFilter);
   while ( FblLbtBlockDone() == FALSE )
   {
      /* Check if file name exists for checked block and if file name size matches.
         Also allow a length with one byte less to support strings without zero termination */
      if ((localBlockDescriptor.fileName != V_NULL) &&
         (localBlockDescriptor.fileNameSize > 0u) &&
         ((localBlockDescriptor.fileNameSize == fileNameSize) ||
          ((localBlockDescriptor.fileNameSize - 1u) == fileNameSize )) &&
         (localBlockDescriptor.blockLength >= fileLength))
      {
         vuintx i;

         /* Compare file name */
         for (i = 0u; i < fileNameSize; i++)
         {
            if (fileName[i] != localBlockDescriptor.fileName[i])
            {
               /* Missmatch detected -> File name is not equal */
               break;
            }
         }

         if (i == fileNameSize)
         {
            *blockDescriptor = localBlockDescriptor;
            result = kFblOk;
            break;
         }
      }

      localBlockDescriptor = FblLbtBlockNext();
   }

   return result;
}
#endif /* FBL_LBT_ENABLE_FILE_NAME */

/***********************************************************************************************************************
 *  FblLbtCheckAddressRange
 **********************************************************************************************************************/
/*! \brief       Check whether an address lies within a specified address range
 *  \param[in]   address Address to be checked
 *  \param[in]   rangeStart Start of range
 *  \param[in]   rangeLength Length of range
 *  \return      Possible return values:
 *               - kFblOk if address lies within range
 *               - kFblFailed otherwise
 **********************************************************************************************************************/
tFblResult FblLbtCheckAddressRange(tFblAddress address, tFblAddress rangeStart, tFblLength rangeLength)
{
   tFblResult result = kFblFailed;

   if (    (address >= rangeStart)
       && ((address - rangeStart) < rangeLength) )
   {
      result = kFblOk;
   }

   return result;
}

/***********************************************************************************************************************
 *  FblLbtCheckRangeContained
 **********************************************************************************************************************/
/*! \brief       Check whether an address range lies within another specified address range
 *  \param[in]   address Start address of range to be checked
 *  \param[in]   length Length of range to be checked
 *  \param[in]   rangeStart Start of range
 *  \param[in]   rangeLength Length of range
 *  \return      Possible return values:
 *               - kFblOk if range lies within range
 *               - kFblFailed otherwise
 **********************************************************************************************************************/
tFblResult FblLbtCheckRangeContained(tFblAddress address, tFblLength length, tFblAddress rangeStart, tFblLength rangeLength)
{
   tFblResult result = kFblFailed;

   if ((FblLbtCheckAddressRange(address, rangeStart, rangeLength) == kFblOk)
       && (length <= rangeLength)
       && ((address - rangeStart) <= (rangeLength - length)) )
   {
      result = kFblOk;
   }

   return result;
}

#if defined( FBL_LBT_ENABLE_REPROGRAMMABLE_LBT )
/***********************************************************************************************************************
 *  FblLbtCheckConsistency
 **********************************************************************************************************************/
/*! \brief       Check consistency between the LBT which resides in the LBT block and the bootloader
 *  \return      Possible return values:
 *               - kFblOk if the information in the new LBT is consistent with the bootloader
 *               - kFblFailed otherwise
 **********************************************************************************************************************/
tFblResult FblLbtCheckConsistency(void)
{
   tFblResult result = kFblOk;
   tFblLbtBlockNr localBlockNr = 0u;
   tBlockDescriptor baseBlock = {0};
   tBlockDescriptor newBlock = {0};

   /* Additional consistency checks should be performed by the generator which might be OEM/configuration specific, e.g.:
    * - SBL and LBT block are unique and of type 'mandatory'
    * - At least one logical block besides SBL/LBT is of type 'mandatory'
    * - Block index of all blocks is unique
    * - The configured logical blocks cover all blocks defined in the FBT
    * - Block header address of all blocks lies inside the respective block area
    * - Block header address has a reasonable distance from the presence pattern area
    */

   /* Temporarily switch to new LBT for consistency checks */
   FblLbtActivateLbtBlock();

   /* Check if block count exceeds built-in maximum value */
   if (fblLbtActive->noOfBlocks > (tFblLbtBlockCount)FBL_LBT_BLOCK_COUNT)
   {
      result = kFblFailed;
   }

   /* Check LBT against built-in FBT */
   if ((result == kFblOk) && (fblLbtActive->magicFlag != FblLogicalBlockTable.magicFlag))
   {
      result = kFblFailed;
   }

   /* Compare fixed blocks in built-in LBT against new LBT */
   if (result == kFblOk)
   {
      for (localBlockNr = 0u; localBlockNr < FblLogicalBlockTable.noOfBlocks; localBlockNr++)
      {
         baseBlock = FblLogicalBlockTable.logicalBlock[localBlockNr];
         result = FblLbtGetBlockDescriptorByNr(localBlockNr, &newBlock);
         if (result == kFblOk)
         {
            result = FblLbtBlockCompare(&baseBlock, &newBlock);
         }
         if (result != kFblOk)
         {
            break;
         }
      }
   }

   /* Check block type and verify functions against built-in values */
   if (result == kFblOk)
   {
      result = FblLbtCheckReferences();
   }

   /* Revert LBT pointer to built-in table */
   FblLbtInitPowerOn();

   return result;
}

/***********************************************************************************************************************
 *  FblLbtActivateLbtBlock
 **********************************************************************************************************************/
/*! \brief       Activate usage of the reprogrammable LBT
 *  \pre         FblLbtCheckConsistency() has been executed with positive result
 **********************************************************************************************************************/
void FblLbtActivateLbtBlock(void)
{
   /* Switch to logical block table in LBT block */
# if defined( FBL_LBT_ENABLE_RAM_BUFFER )
   FblLbtActivateLbtBlockByAddress(FblLogicalBlockTable.logicalBlock[FBL_MTAB_LBT_BLOCK_NUMBER].blockStartAddress);
# else
   /* PRQA S 0306 1 */ /* MD_FblLib_Lbt_0306 */
   fblLbtActive = (V_MEMROM1 tLogicalBlockTable V_MEMROM2 V_MEMROM3 *)FblLogicalBlockTable.logicalBlock[FBL_MTAB_LBT_BLOCK_NUMBER].blockStartAddress;
# endif /* FBL_LBT_ENABLE_RAM_BUFFER */
}
#endif /* FBL_LBT_ENABLE_REPROGRAMMABLE_LBT */

/***********************************************************************************************************************
 *  FblLbtActivateLbtBlockByAddress
 **********************************************************************************************************************/
/*! \brief       Activate usage of the reprogrammable LBT
 *  \details     CAUTION: The function will set the internal LBT pointer without further consistency checks. It's in
 *               the responsibility of the caller to check the LBT consistency before accessing the contained
 *               information!
 *  \param[in]   address Address of the logical block table, which should now be used
 **********************************************************************************************************************/
void FblLbtActivateLbtBlockByAddress(tFblAddress address)
{
   /* Switch to logical block table in LBT block */
#if defined(FBL_LBT_ENABLE_RAM_BUFFER)
   tFblLength readCount = FblReadProm(address, (vuint8*)&fblLbtRamBuffer, FBL_LBT_RAM_BUF_SIZE);
   /* PRQA S 3205 1 */ /* MD_FblLib_Lbt_3205 */
   assertFbl(readCount == FBL_LBT_RAM_BUF_SIZE, kFblSysAssertParameterOutOfRange);
#else
   /* PRQA S 0306 1 */ /* MD_FblLib_Lbt_0306 */
   fblLbtActive = (V_MEMROM1 tLogicalBlockTable V_MEMROM2 V_MEMROM3 *)address;
#endif /* FBL_LBT_ENABLE_RAM_BUFFER */
}
#define FBLLBT_STOP_SEC_CODE
#include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */

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

/* module specific MISRA deviations:

   MD_FblLib_Lbt_0306:
     Reason:     Address conversion between integer values and pointers is required to allow for hardware independent
                  configuration and address range checks.
     Risk:       The size of integer required to hold the result of a pointer cast is implementation-defined.
     Prevention: The size of the respective integer data type which holds the address value is adapted on a hardware
                  specific basis. The correctness of the respective implementation is verified by runtime tests.

   MD_FblLib_Lbt_3205:
     Reason:     Depending on the configuration some variables are not referenced by the code. For simplicity the
                  variables are kept.
     Risk:       No identifiable risk.
     Prevention: No prevention required.

*/

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