


/**
 **********************************************************************************************************************
 * \moduledescription
 *           AUTOSAR FEE
 *           According to Document Version 3.0.0, Part of Release 4.0, Revision 2
 * \scope    INTERN
 **********************************************************************************************************************
 */


/*
 *********************************************************************
 * Includes
 *********************************************************************
 */
#include "Fee.h"
#include "rba_FeeFs1_Prv.h"
#include "Fls.h"
#include "rba_FeeFs1_SyncRead.h"

#if (!defined(FLS_AR_RELEASE_MAJOR_VERSION) || (FLS_AR_RELEASE_MAJOR_VERSION != FEE_AR_RELEASE_MAJOR_VERSION))
    #error "AUTOSAR major version undefined or mismatched"
#endif
#if (!defined(FLS_AR_RELEASE_MINOR_VERSION) || ((FLS_AR_RELEASE_MINOR_VERSION != 0) && (FLS_AR_RELEASE_MINOR_VERSION != 2)))
    #error "AUTOSAR minor version undefined or mismatched"
#endif

#include "Crc.h"
#if (!defined(CRC_AR_RELEASE_MAJOR_VERSION) || (CRC_AR_RELEASE_MAJOR_VERSION != FEE_AR_RELEASE_MAJOR_VERSION))
    #error "AUTOSAR major version undefined or mismatched"
#endif
#if (!defined(CRC_AR_RELEASE_MINOR_VERSION) || ((CRC_AR_RELEASE_MINOR_VERSION != 0) && (CRC_AR_RELEASE_MINOR_VERSION != 2)))
    #error "AUTOSAR minor version undefined or mismatched"
#endif

#if (FEE_PRV_DEBUGGING != FALSE)
#include "Mcu.h"
#include "Eep.h"
/* FEE_PRV_DEBUGGING */
#endif

#if(defined(FEE_PRV_CFG_SELECTED_FS) && (1 == FEE_PRV_CFG_SELECTED_FS))

#if (FEE_PRESENT == 1)
/**
 *********************************************************************
 * Fee_LLSearchSpecifiedBlkHeader(): Search for a specific block header
 *                                   within all sector
 *
 * This function searches for a specific block header within all
 * sectors.
 *
 * \param    FeeIdx_u16:            Fee block index to search
 * \param    LastHdrAddr_ptr:       Address pointer for the last header address
 * \param    GlobBlkHdr_ptr:        Pointer for the block header content
 *                                  that will be found
 * \param    SearchRetry_b:         Retry of search
 * \return
 * \retval   FEE_ERROR_E:           The block does not exist in the flash
 * \retval   FEE_ABORTED_E:         The cache access did not work (another block
 *                                  or no block index was referenced)
 *                                  The function needs to be called again.
 * \retval   FEE_ORDER_FINISHED_E:  Order is finished with success
 * \seealso
 * \usedresources
 *********************************************************************
 */
#define FEE_START_SEC_CODE
#include "Fee_MemMap.h"
Fee_stRetVal_ten Fee_LLSearchSpecifiedBlkHeader(uint16 FeeIdx_u16,
                                                uint32* LastHdrAddr_ptr,
                                                Fee_GlobInfoLastRdHeader_tst* GlobBlkHdr_ptr,
                                                boolean SearchRetry_b)
{
    Fee_stRetVal_ten xRetVal    = FEE_ORDER_PENDING_E;  /* Function return */
    Fee_stRetVal_ten xtmpRetVal = FEE_ORDER_PENDING_E;  /* Temp return */

    Fee_GlobInfoLastRdHeader_tst xTmpBlkHdr_st;         /* Temporary block header */
    uint8   xLogSecIdx_u8;                              /* Index of the logical sector */
    boolean xContinueSearch_b = FALSE;                  /* Seach indicator */
    uint32  xTmpAddr_u32 = FEE_CACHE_INIT_VALUE;        /* Temp variable */
    boolean xForcePageBufReload_b = FALSE;              /* Force no reload of the page buffer */

    static uint8 xPhySecIdx_u8  = FEE_NO_SEC_IDX_FOUND;                 /* Index of the active sector */
    static uint8 xSearchType_u8 = FEE_USE_MANUAL_ACCESS;                /* Search type (Cached / manual) */

    #if (FEE_PRV_DEBUGGING != FALSE)
    if(Eep_stMain == EEP_FIRSTINIT_INI)
    {
        Fee_Prv_stModuleTest_st.Fee_SearchSpecificBlockHeaderNum_u32++;
    }
    #endif


    /* Switch over state machine */
    switch (Fee_RdWrOrder_st.Fee_LLSearchBlkHdr_en)
    {
        /* Init state */
        case FEE_LL_SEARCHBLK_INIT_E:
        {
            /* Check if this is the first try to find a valid block */
            if((SearchRetry_b == FALSE) ||
               (*LastHdrAddr_ptr == FEE_MAXUINT32))
            {
                /* Detect the most current sector because this is no retry due to
                 * an invalid block checksum. */
                xPhySecIdx_u8 = Fee_GetMostCurrentSectorIdx();
            }
            else
            {
                /* Get the corresponding sector index of the current read sector
                 * (this might be a retry within the most current or an elder sector) */
                xPhySecIdx_u8 = Fee_GetPhysSectorByAddress(Fee_RdWrOrder_st.xRdAddress);
            }

            /* Cache is not available for unknown blocks during the "afterburner" run
             * which will be visible by a return of FEE_CACHE_INIT_VALUE. */
            if((Fee_Prv_stReorg_u8 != FEE_PRV_ST_REORG_AFTERB_RUNNING) &&
               (SearchRetry_b == FALSE))
            {
                /* Try to get a valid address via cache */
                xTmpAddr_u32 = Fee_LLGetAddressFromCache(FeeIdx_u16);
            }

            /* Evaluate the cache content */
            if((xTmpAddr_u32 != FEE_CACHE_INIT_VALUE) &&
               (xTmpAddr_u32 != FEE_CACHE_TMP_INVALID_VALUE))
            {
                /* Cache can be used */
                xSearchType_u8 = FEE_USE_CACHED_ACCESS;

                /* Copy cache address */
                Fee_RdWrOrder_st.xRdAddress = xTmpAddr_u32;
            }
            else
            {
                /* Start the manual search from the beginning of the sector */
                Fee_RdWrOrder_st.xRdAddress = Fee_LLGetSecStartAddress(xPhySecIdx_u8);

                /* A manual search is necessary */
                xSearchType_u8 = FEE_USE_MANUAL_ACCESS;
            }

            /* This pattern is used to detect if at least 1 time a valid header was copied */
            GlobBlkHdr_ptr->FeeIndex_u16 = FEE_MAXUINT16;

            /* Force a reload of the page buffer because the init state is only passed for
             * new block read orders */
            xForcePageBufReload_b = TRUE;

            /* Set next state */
            Fee_RdWrOrder_st.Fee_LLSearchBlkHdr_en = FEE_LL_SEARCHBLK_BLK_HEADER_E;
        }
        /* No break to save time */

        /* Search any block header beginning at Fee_RdWrOrder_st.xRdAddress (manual search without cache) */
        /* MR12 RULE 16.3 VIOLATION: Time critical position */
        case FEE_LL_SEARCHBLK_BLK_HEADER_E:
        {
            /* Search for the next block header. If cached access is used, the address for the header is already
             * in the cache. If the manual search is used, the start address for the search can be changed
             * via Fee_RdWrOrder_st.xRdAddress.
             *
             * The cache will always contain the latest version of the block. If this block is corrupt,
             * the calling function comes back with the LastHdrAddr_ptr as the upper limit of the search.
             * The area before this address has to be checked now in order to find elder versions of this
             * block inside any of the sectors.
             *
             * During the initialization (and shutdown), the most current sector has already been checked via
             * Fee_LLFindNextEmptyPage and the cache has been build up. All available blocks within the most
             * current USED sector are available via cache from this moment onwards. Therefor this sector
             * can be skipped for the subsequent read orders during the initialization if no cache entry
             * is available.
             * */

            /* Check if the current sector has to be used for the search. This is indicated by the
             * update status array for the cache. In case the respective sector has already been checked,
             * all found blocks out of the configuration are already in the cache).
             * Searches can be skipped in case there is no cache entry available and the sector has
             * been checked already and no older version is necessary to be detected. */
            /* MR12 RULE 13.5 VIOLATION: Search must be continued when any of the multiple conditions are failed. */
            if((Fee_LLGetCacheUpdateStForSect(xPhySecIdx_u8) == FEE_CACHE_UPD_COMP_FOR_SECT) &&
               (xSearchType_u8 == FEE_USE_MANUAL_ACCESS) &&
               (SearchRetry_b == FALSE) &&
               (Fee_LLGetAddressFromCache(FeeIdx_u16) != FEE_CACHE_TMP_INVALID_VALUE) &&
               (Fee_Prv_stReorg_u8 != FEE_PRV_ST_REORG_AFTERB_RUNNING))
            {
                /* Skip the search within the current sector and check if other sectors
                 * might be used for the search */
                xtmpRetVal = FEE_SEARCH_ABORTED_E;
            }
            else
            {
                /* Search the next block header */
                xtmpRetVal = Fee_LLSearchNextBlkHeader(&xTmpBlkHdr_st, xSearchType_u8, FEE_NO_CACHE_UPDATE, xForcePageBufReload_b, 0);
            }

            /* Switch function return */
            switch(xtmpRetVal)
            {
                /* Order is still pending */
                case FEE_ORDER_PENDING_E:
                {
                    /* Just wait */
                    ;
                }
                break;

                /* One valid header was found */
                case FEE_ORDER_FINISHED_E:
                {

                    /* Check if the correct block index was found */
                    if((xTmpBlkHdr_st.FeeIndex_u16 == FeeIdx_u16) &&
                       ((Fee_RdWrOrder_st.Fee_LLSecReorg_en == FEE_LL_REORG_SEARCH_BLK_E) ||
                        (Fee_RdWrOrder_st.Fee_LLSecReorg_en == FEE_LL_REORG_REDUNDANT_BLK_CHK_E)||   /* sector change is active and no entry in the Fee_OrderFifo_st exists */
                        /* Search for an unknown block without cache. */
#if(((FEE_RB_ACT_SURVIVAL_EVAL != FALSE) && (FEE_RB_ACT_UNKNOWN_BLOCK_REORG == FALSE)) || ((FEE_RB_ACT_UNKNOWN_BLOCK_REORG != FALSE) && (FEE_RB_ACT_UNKNOWN_BLOCK_CACHE_SIZE == 0)))
                        (Fee_RdWrOrder_st.Fee_LLSearchUnknBlkHdr_en == FEE_LL_SEARCHUNKNBLK_SPEC_BLK_HEADER_E) || /* sector change is active and no entry in the Fee_OrderFifo_st exists */
#endif
                        (Fee_BlockProperties_st[Fee_OrderFifo_st[Fee_idxActQueue_u8].BlockPropIdx_u16].Length_u16 == xTmpBlkHdr_st.BlkLength_u16) ||
                        (Fee_OrderFifo_st[Fee_idxActQueue_u8].Length_u16 == 0) || (xTmpBlkHdr_st.BlkLength_u16 == 0) ||
                        (Fee_BlockProperties_st[Fee_OrderFifo_st[Fee_idxActQueue_u8].BlockPropIdx_u16].Length_u16 == (xTmpBlkHdr_st.BlkLength_u16 + 4))))
                    {
                        /* Check if this is a retry due to an invalid latest copy and if the address of the
                         * newer, invalid block is already reached. There is no need to differ between a
                         * first try and a later try */
                        if(*LastHdrAddr_ptr > xTmpBlkHdr_st.AdrBlkHeader_u32)
                        {
                            /* LastHdrAddr has the init value or an older copy was found
                             * --> search for newer copies inside the same sector */

                            /* Save the block info */
                            GlobBlkHdr_ptr->AdrBlkHeader_u32 = xTmpBlkHdr_st.AdrBlkHeader_u32;
                            GlobBlkHdr_ptr->BlkLength_u16    = xTmpBlkHdr_st.BlkLength_u16;
                            GlobBlkHdr_ptr->BlkStatus_u8     = xTmpBlkHdr_st.BlkStatus_u8;
                            GlobBlkHdr_ptr->FeeIndex_u16     = xTmpBlkHdr_st.FeeIndex_u16;
                            GlobBlkHdr_ptr->BlkCrc32_u32     = xTmpBlkHdr_st.BlkCrc32_u32;
                            GlobBlkHdr_ptr->HdrCrc16_u16     = xTmpBlkHdr_st.HdrCrc16_u16;
                            GlobBlkHdr_ptr->DataBytes_au8[0u]= xTmpBlkHdr_st.DataBytes_au8[0u];
                            GlobBlkHdr_ptr->DataBytes_au8[1u]= xTmpBlkHdr_st.DataBytes_au8[1u];

                            /* Check if the search can be finished (the cache always contains the latest copy) */
                            if(xSearchType_u8 == FEE_USE_CACHED_ACCESS)
                            {
                                /* Block was found (latest copy), do not search until the sector end is reached */
                                xRetVal = FEE_ORDER_FINISHED_E;
                            }
                            else
                            {
                                /* Update the read address to the last found block header */
                                Fee_RdWrOrder_st.xRdAddress = xTmpBlkHdr_st.AdrBlkHeader_u32;

                                /* Increment the read address page wise ("safety mode") and search for the next
                                 * block header until the complete sector is checked
                                 * --> search for all copies of the block in order to find the latest one */
                                Fee_IncAddressInsideSector(&Fee_RdWrOrder_st.xRdAddress, FEE_PAGE_LEN, TRUE);
                            }
                        }
                        else
                        {
                            /* The end address (former invalid block) is reached
                             * --> Check if at least one header was found before */

                            if(GlobBlkHdr_ptr->FeeIndex_u16 != FEE_MAXUINT16)
                            {
                                /* The latest valid copy was found */
                                xRetVal = FEE_ORDER_FINISHED_E;
                            }
                            else
                            {
                                /* There was no valid header found in the address space before the last invalid block
                                 * --> Valid block is not within the current sector
                                 * --> Search within older sectors if possible */

                                /* Get the corresponding sector index of the sector that has been
                                 * used for the search */
                                xPhySecIdx_u8 = Fee_GetPhysSectorByAddress(Fee_RdWrOrder_st.xRdAddress);

                                /* Get the corresponding logical sector index */
                                xLogSecIdx_u8 = Fee_idxLLSectorOrder_au8[xPhySecIdx_u8];

                                /* Reset the search indicator */
                                xContinueSearch_b = FALSE;

                                /* Check if there are more logical sectors available (0 is the lowest possible value)
                                 * and if one of these sectors is either in the state FULL or USED */
                                if(xLogSecIdx_u8 > 0)
                                {
                                    do
                                    {
                                        /* Decrement the logical sector */
                                        xLogSecIdx_u8--;

                                        /* Check for relevant sector states */
                                        if((Fee_LLSectorOrder_st[xLogSecIdx_u8].SecState_en == FEE_SECTOR_USED_E) ||
                                           (Fee_LLSectorOrder_st[xLogSecIdx_u8].SecState_en == FEE_SECTOR_FULL_E))
                                        {
                                            /* Go on with the previous sector */
                                            xContinueSearch_b = TRUE;

                                            /* Get respective physical sector index */
                                            xPhySecIdx_u8 = Fee_LLSectorOrder_st[xLogSecIdx_u8].xPhySecIdx_u8;

                                            /* This sector has to be checked, starting at the beginning */
                                            Fee_RdWrOrder_st.xRdAddress = Fee_FlashProp_st[xPhySecIdx_u8].Fee_LogStartAddress_u32;

                                            /* Set back the LastHrAddr_ptr because the new sector might have new adress ranges */
                                            *LastHdrAddr_ptr = FEE_MAXUINT32;

                                            /* Make sure the manual search will be started in the next sector */
                                            xSearchType_u8 = FEE_USE_MANUAL_ACCESS;

                                            /* The next search will start in the previous sector and will continue until the
                                             * end of this sector is reached */
                                        }
                                    }
                                    while((xLogSecIdx_u8 > 0) && (xContinueSearch_b == FALSE));
                                }

                                /* Check if all relevant sectors have been checked already */
                                if(xContinueSearch_b == FALSE)
                                {
                                    /* All relevant sectors have been checked, block header cannot be found,
                                     * invalidate the cache */
                                    Fee_LLInvalidateAddressInCache(FeeIdx_u16);

                                    /* Set the return value */
                                    xRetVal = FEE_ERROR_E;
                                }
                            }
                        }
                    }
                    else
                    {
                        /* Another block was found */
                        /* *********************** */

                        /* Evaluate the search type */
                        if(xSearchType_u8 == FEE_USE_CACHED_ACCESS)
                        {
                            /* The address inside the cache was not correct or the data inside
                             * the header is corrupt.
                             * The manual search will be started automatically (no valid cache entry available). */

                            /* Mark the cache for the activation of the manual search instead of avoiding
                             * this during the sector reorganization */
                            Fee_LLUpdateAddressInCache(xTmpBlkHdr_st.FeeIndex_u16,
                                                       FEE_CACHE_TMP_INVALID_VALUE);

                            /* Set return value */
                            xRetVal = FEE_ABORTED_E;
                        }
                        else
                        {
                            /* Get the block address from the cache */
                            xTmpAddr_u32 = Fee_LLGetAddressFromCache(xTmpBlkHdr_st.FeeIndex_u16);

                            /* Check if a cache entry is already available and the search will be
                             * continued until the end of a sector (*LastHdrAddr_ptr == FEE_MAXUINT32).
                             * Not for retries after finding a block with a corrupted block checksum.
                             * Hint: the block checksum is not verified */
                            if(((xTmpAddr_u32 == FEE_CACHE_INIT_VALUE) ||
                                (xTmpAddr_u32 == FEE_CACHE_TMP_INVALID_VALUE)) &&
                                (*LastHdrAddr_ptr == FEE_MAXUINT32))
                            {
                                /* There is no valid entry available, update the cache */
                                Fee_LLUpdateAddressInCache(xTmpBlkHdr_st.FeeIndex_u16,
                                                           xTmpBlkHdr_st.AdrBlkHeader_u32);
                            }
                            else
                            {
                                /* A cache entry already exists, an update might be possible */

                                /* Get the corresponding sector index */
                                xPhySecIdx_u8 = Fee_GetPhysSectorByAddress(Fee_RdWrOrder_st.xRdAddress);

                                /* Check if the address is within the same sector because
                                 * later versions will always be located behind old copies and if
                                 * the search will be continued until the end of the sector
                                 * (a retry after a defect block CRC was found is indicated via
                                 *  *LastHdrAddr_ptr != FEE_MAXUINT32 := upper limit for the search)*/
                                if((xTmpAddr_u32 >= Fee_FlashProp_st[xPhySecIdx_u8].Fee_LogStartAddress_u32) &&
                                   (xTmpAddr_u32 <  Fee_FlashProp_st[xPhySecIdx_u8].Fee_LogEndAddress_u32) &&
                                   (*LastHdrAddr_ptr == FEE_MAXUINT32))
                                {
                                    /* Overwrite the cache entry with a later block version */
                                    Fee_LLUpdateAddressInCache(xTmpBlkHdr_st.FeeIndex_u16,
                                                               xTmpBlkHdr_st.AdrBlkHeader_u32);
                                }
                            }

                            /* Update the read address to the last found block header */
                            Fee_RdWrOrder_st.xRdAddress = xTmpBlkHdr_st.AdrBlkHeader_u32;

                            /* Increment the read address page wise ("safety mode") and search for the next
                             * block header until the end of the sector is reached */
                            Fee_IncAddressInsideSector(&Fee_RdWrOrder_st.xRdAddress, FEE_PAGE_LEN, TRUE);
                        }
                    }
                }
                break;

                /* The requested header was not found in the sector that was used for the search */
                case FEE_SECTORFULL_E:
                case FEE_SEARCH_ABORTED_E:
                {

                    /* Get the corresponding sector index of the sector that has been
                     * used for the search */
                    xPhySecIdx_u8 = Fee_GetPhysSectorByAddress(Fee_RdWrOrder_st.xRdAddress);

                    /* Mark the respective sector as checked for building up the cache during
                     * the initialization phase of the driver or if it is manual search
                     * (during the manual search the cache is updated on "its" way to the
                     *  end of the sector) */
                    if(xSearchType_u8 == FEE_USE_MANUAL_ACCESS)
                    {
                        /* Update the cache status array for the current sector */
                        Fee_LLUpdateCacheStForSect(xPhySecIdx_u8);
                    }

                    /* Check if at least one header was found before */
                    if(GlobBlkHdr_ptr->FeeIndex_u16 != FEE_MAXUINT16)
                    {
                        /* The end of the sector is reached and the latest copy was found */
                        xRetVal = FEE_ORDER_FINISHED_E;
                    }
                    else
                    {
                        /* Check if another sector might be used to continue with the search */

                        /* Get the corresponding logical sector index */
                        xLogSecIdx_u8 = Fee_idxLLSectorOrder_au8[xPhySecIdx_u8];
                        /* Reset the search indicator */
                        xContinueSearch_b = FALSE;

                        /* Check if there are more logical sectors available (0 is the lowest possible value)
                         * and if one of these sectors is either in the state FULL or USED */
                        if(xLogSecIdx_u8 > 0)
                        {
                            do
                            {
                                /* Decrement the logical sector */
                                xLogSecIdx_u8--;

                                /* Check for relevant sector states */
                                if((Fee_LLSectorOrder_st[xLogSecIdx_u8].SecState_en == FEE_SECTOR_USED_E) ||
                                   (Fee_LLSectorOrder_st[xLogSecIdx_u8].SecState_en == FEE_SECTOR_FULL_E))
                                {
                                    /* Go on with the previous sector */
                                    xContinueSearch_b = TRUE;

                                    /* Get respective physical sector index */
                                    xPhySecIdx_u8 = Fee_LLSectorOrder_st[xLogSecIdx_u8].xPhySecIdx_u8;

                                    /* This sector has to be checked, starting at the beginning */
                                    Fee_RdWrOrder_st.xRdAddress = Fee_FlashProp_st[xPhySecIdx_u8].Fee_LogStartAddress_u32;

                                    /* Set back the LastHrAddr_ptr because the new sector might have new address ranges */
                                    *LastHdrAddr_ptr = FEE_MAXUINT32;

                                    /* Make sure the manual search will be started in the next sector */
                                    xSearchType_u8 = FEE_USE_MANUAL_ACCESS;

                                    /* The next search will start in the previous sector and will continue until the
                                     * end of this sector is reached */
                                }
                            }
                            while((xLogSecIdx_u8 > 0) && (xContinueSearch_b == FALSE));
                        }

                        /* Check if all relevant sectors have been checked already */
                        if(xContinueSearch_b == FALSE)
                        {
                            /* All relevant sectors have been checked, block header cannot be found,
                             * invalidate the cache */
                            Fee_LLInvalidateAddressInCache(FeeIdx_u16);

                            /* Set the return value */
                            xRetVal = FEE_ERROR_E;
                        }
                    }
                }
                break;

                /* Cache access did not show any result */
                case FEE_ERROR_E:
                    /* Mark the cache for the activation of the manual search instead of avoiding
                     * this during the sector reorganization */
                    Fee_LLUpdateAddressInCache(FeeIdx_u16,
                                               FEE_CACHE_TMP_INVALID_VALUE);

                    /* Return with an error to be called again with the manual search */
                    xRetVal = FEE_ABORTED_E;
                break;

                /* Error cases */
                case FEE_ABORTED_E:
                default:
                {
                    /* States should never be reached,
                     * invalidate the cache entry */
                    Fee_LLUpdateAddressInCache(FeeIdx_u16,
                                                  FEE_CACHE_TMP_INVALID_VALUE);

                    /* Set the return value */
                    xRetVal = FEE_ERROR_E;
                }
                break;
            }
        }
        break;

        /* Default case */
        default:
        {
            /* States should never be reached,
             * mark the cache for the activation of the manual search */
            Fee_LLUpdateAddressInCache(FeeIdx_u16,
                                       FEE_CACHE_TMP_INVALID_VALUE);

            /* Set the return value */
            xRetVal = FEE_ERROR_E;
        }
        break;
    }


    /* Check for necessary resets */
    if(xRetVal != FEE_ORDER_PENDING_E)
    {
        /* Reset state machine */
        Fee_RdWrOrder_st.Fee_LLSearchBlkHdr_en = FEE_LL_SEARCHBLK_INIT_E;

        /* Reset physical sector index */
        xPhySecIdx_u8 = FEE_NO_SEC_IDX_FOUND;

        /* Reset search type */
        xSearchType_u8 = FEE_USE_MANUAL_ACCESS;
    }

    return (xRetVal);
}


#if((FEE_RB_ACT_SURVIVAL_EVAL != FALSE) || (FEE_RB_ACT_UNKNOWN_BLOCK_REORG != FALSE))
/* Search for an unknown block without cache. */
#if (FEE_RB_ACT_UNKNOWN_BLOCK_CACHE_SIZE == 0)
/**
 *********************************************************************
 * Fee_LLSearchUnknownBlkHeader(): Search for an unknown block header
 *                                 within all sector. Search is without cache.
 *
 * This function searches for an unknown block header within all
 * sectors and returns the latest valid copy of this block.
 *
 * \param    StartHdrAddr_ptr:      Start address for the search
 * \param    LastHdrAddr_ptr:       Address pointer for the last header address
 * \param    GlobBlkHdr_ptr:        Pointer for the block header content
 *                                  that will be found
 * \param    SearchRetry_ptr:       Retry of search
 * \return
 * \return   FEE_PENDING_E:         Search is still ongoing
 * \retval   FEE_ERROR_E:           No unknown block exists in the
 *                                  eldest FULL sector
 * \retval   FEE_ORDER_FINISHED_E:  Order is finished with success
 * \seealso
 * \usedresources
 *********************************************************************
 */
Fee_stRetVal_ten Fee_LLSearchUnknownBlkHeader(uint32* StartHdrAddr_ptr,
                                              uint32* LastHdrAddr_ptr,
                                              Fee_GlobInfoLastRdHeader_tst* GlobBlkHdr_ptr,
                                              boolean* SearchRetry_ptr)
{
    Fee_stRetVal_ten xRetVal    = FEE_ORDER_PENDING_E;  /* Function return */
    Fee_stRetVal_ten xtmpRetVal = FEE_ORDER_PENDING_E;  /* Temp return */

    Fee_GlobInfoLastRdHeader_tst xTmpNxtBlkHdr_st;      /* Temporary block header */

    boolean xForcePageBufReload_b = FALSE;              /* Force no reload of the page buffer */
    uint16  xDummyCacheIdx_u16 = 0;                     /* Cache index dummy */
    uint8   xPhySecIdx_u8  = FEE_NO_SEC_IDX_FOUND;      /* Index of the active sector */
    static uint16           xFeeIdx_u16 = FEE_MAXUINT16;                /* Block index */


    /* Loop if polling mode is active and function state is pending */
    do
    {
        /* Switch over state machine */
        switch (Fee_RdWrOrder_st.Fee_LLSearchUnknBlkHdr_en)
        {
            /* Init state */
            case FEE_LL_SEARCHUNKNBLK_INIT_E:
            {
                /* Force a reload of the page buffer because the init state is only passed for
                 * new block read orders */
                xForcePageBufReload_b = TRUE;

                /* Check for a retry because of an invalid block checksum */
                if(*SearchRetry_ptr == FALSE)
                {
                    /* Reset the next block index */
                    xFeeIdx_u16 = FEE_MAXUINT16;

                    /* Copy the start address for the search */
                    Fee_RdWrOrder_st.xRdAddress = *StartHdrAddr_ptr;

                    /* Set next state */
                    Fee_RdWrOrder_st.Fee_LLSearchUnknBlkHdr_en = FEE_LL_SEARCHUNKNBLK_UNKN_BLK_HEADER_E;
                }
                else
                {
                    /* Return to the specified header search because this is a retry */
                    Fee_RdWrOrder_st.Fee_LLSearchUnknBlkHdr_en = FEE_LL_SEARCHUNKNBLK_SPEC_BLK_HEADER_E;

                    /* Get the corresponding sector index of the current read sector
                     * (this might be a retry within the most current or an elder sector) */
                    xPhySecIdx_u8 = Fee_GetPhysSectorByAddress(Fee_RdWrOrder_st.xRdAddress);

                    /* Start the manual search from the beginning of the sector */
                    Fee_RdWrOrder_st.xRdAddress = Fee_LLGetSecStartAddress(xPhySecIdx_u8);

                    break;
                }
            }
            /* No break to save time */

            /* Search any block header beginning at Fee_RdWrOrder_st.xRdAddress (manual search without cache) */
            /* MR12 RULE 16.3 VIOLATION: Time critical position */
            case FEE_LL_SEARCHUNKNBLK_UNKN_BLK_HEADER_E:
            {
                /* Search for the next block header. The start address for the search can be changed
                 * via Fee_RdWrOrder_st.xRdAddress.
                 * */

                /* Search the next block header */
                xtmpRetVal = Fee_LLSearchNextBlkHeader(&xTmpNxtBlkHdr_st, FEE_USE_MANUAL_ACCESS, FEE_NO_CACHE_UPDATE, xForcePageBufReload_b, 0);

                /* Switch function return */
                switch(xtmpRetVal)
                {
                    /* Order is still pending */
                    case FEE_ORDER_PENDING_E:
                    {
                        /* Just wait */
                        ;
                    }
                    break;

                    /* One valid unknown block header was found (within the oldest FULL sector) */
                    case FEE_ORDER_FINISHED_E:
                    {
                        /* Reset the forced reload for the initialization (init value will remain
                         * true in case the polling mode is active) */
                        xForcePageBufReload_b = FALSE;

                        /* Check if the found block index is within the configuration or not */
                        if(Fee_SrvBinarySearchInBlockProp(xTmpNxtBlkHdr_st.FeeIndex_u16, &xDummyCacheIdx_u16) == FALSE)
                        {
                            /* Check if this block has to be transfered. This is the case if:
                             * Block is not in the layout (afterburner is running) AND
                             *      - Survival flag is TRUE (config setting must be taken out of the DFlash) OR
                             *      - FEE_RB_ACT_UNKNOWN_BLOCK_REORG == TRUE (valid for all blocks) */
                            if(((xTmpNxtBlkHdr_st.BlkStatus_u8 & (uint8)FEE_FLAG_SURV_ATTR_MSK) > 0u) ||
                               (FEE_RB_ACT_UNKNOWN_BLOCK_REORG != FALSE))
                            {
                                /* The first copy of an unknown block index was found,
                                 * identify the latest valid version of this block in the next step */

                                /* Update the read address to the last found block header */
                                Fee_RdWrOrder_st.xRdAddress = xTmpNxtBlkHdr_st.AdrBlkHeader_u32;

                                /* Increment the read address page wise ("safety mode") and search for the next
                                 * block header until the complete sector is checked
                                 * --> search for all copies of the block in order to find the latest one */
                                Fee_IncAddressInsideSector(&Fee_RdWrOrder_st.xRdAddress, FEE_PAGE_LEN, TRUE);

                                /* Save the block info */
                                GlobBlkHdr_ptr->AdrBlkHeader_u32 = xTmpNxtBlkHdr_st.AdrBlkHeader_u32;
                                GlobBlkHdr_ptr->BlkLength_u16    = xTmpNxtBlkHdr_st.BlkLength_u16;
                                GlobBlkHdr_ptr->BlkStatus_u8     = xTmpNxtBlkHdr_st.BlkStatus_u8;
                                GlobBlkHdr_ptr->FeeIndex_u16     = xTmpNxtBlkHdr_st.FeeIndex_u16;
                                GlobBlkHdr_ptr->BlkCrc32_u32     = xTmpNxtBlkHdr_st.BlkCrc32_u32;
                                GlobBlkHdr_ptr->HdrCrc16_u16     = xTmpNxtBlkHdr_st.HdrCrc16_u16;
                                GlobBlkHdr_ptr->DataBytes_au8[0u]= xTmpNxtBlkHdr_st.DataBytes_au8[0u];
                                GlobBlkHdr_ptr->DataBytes_au8[1u]= xTmpNxtBlkHdr_st.DataBytes_au8[1u];

                                /* Copy the block index for the search */
                                xFeeIdx_u16 = GlobBlkHdr_ptr->FeeIndex_u16;

                                /* Set the next state to find the latest valid block version inside
                                 * all sectors */
                                Fee_RdWrOrder_st.Fee_LLSearchUnknBlkHdr_en = FEE_LL_SEARCHUNKNBLK_SPEC_BLK_HEADER_E;
                            }
                            else
                            {
                                /* The found unknown block need not be transffered
                                 * --> Go on with the search */

                                /* Update the read address to the last found block header */
                                Fee_RdWrOrder_st.xRdAddress = xTmpNxtBlkHdr_st.AdrBlkHeader_u32;

                                /* Increment the read address page wise ("safety mode") and search for the next
                                 * block header until the complete sector is checked
                                 * --> search for all copies of the block in order to find the latest one */
                                Fee_IncAddressInsideSector(&Fee_RdWrOrder_st.xRdAddress, FEE_PAGE_LEN, TRUE);
                            }
                        }
                        else
                        {
                            /* The found block is within the layout and not relevant for this search
                             * --> Go on with the search */

                            /* Update the read address to the last found block header */
                            Fee_RdWrOrder_st.xRdAddress = xTmpNxtBlkHdr_st.AdrBlkHeader_u32;

                            /* Increment the read address page wise ("safety mode") and search for the next
                             * block header until the complete sector is checked
                             * --> search for all copies of the block in order to find the latest one */
                            Fee_IncAddressInsideSector(&Fee_RdWrOrder_st.xRdAddress, FEE_PAGE_LEN, TRUE);
                        }

                        /* Save the address as start value for the next run for finding the next
                         * unknown block index */
                        *StartHdrAddr_ptr = Fee_RdWrOrder_st.xRdAddress;
                    }
                    break;

                    /* The sector end address is reached */
                    case FEE_SECTORFULL_E:
                    case FEE_SEARCH_ABORTED_E:
                    {
                        /* The end address for the search is set inside the calling function */

                        /* Function can be finished */
                        xRetVal = FEE_SECTORFULL_E;
                    }
                    break;

                    /* Error cases */
                    case FEE_ABORTED_E:
                    case FEE_ERROR_E:
                    default:
                    {
                        /* States should never be reached */
                        xRetVal = FEE_ERROR_E;
                    }
                    break;
                }
            }
            break;

            /* Search the next specific block header */
            case FEE_LL_SEARCHUNKNBLK_SPEC_BLK_HEADER_E:
                /* Search for the next block header with the given FeeIdx.
                 * The start address for the search can be set with the variable xAdrLastBlkHeader_u32. */
                xtmpRetVal = Fee_LLSearchSpecifiedBlkHeader(xFeeIdx_u16,        /* FeeIdx */
                                                            LastHdrAddr_ptr,    /* End address for the search */
                                                            GlobBlkHdr_ptr,     /* Result structure */
                                                            *SearchRetry_ptr);     /* Indicate first try or not */

                /* Evaluate the search result */
                switch(xtmpRetVal)
                {
                    /* Order not finished yet */
                    case FEE_ORDER_PENDING_E:
                    {
                        /* Just wait */
                        ;
                    }
                    break;

                    /* The latest valid block header was found (maybe the one that
                     * was found before in the oldest FULL sector) */
                    case FEE_ORDER_FINISHED_E:
                    {
                        /* Finish function */
                        xRetVal = FEE_ORDER_FINISHED_E;
                    }
                    break;

                    /* No valid header page was found within the complete flash (all sectors have been checked
                     * until the end address LastHdrAddr_ptr has been reached) */
                    case FEE_ERROR_E:
                    {
                        /* Set the read address to the end address of the search and reset the end address */
                        Fee_RdWrOrder_st.xRdAddress = *LastHdrAddr_ptr;
                        *LastHdrAddr_ptr = FEE_MAXUINT32;

                        /* Increment the read address page wise ("safety mode") and search for the next
                         * block header until the complete sector is checked
                         * --> search for all copies of the block in order to find the latest one */
                        Fee_IncAddressInsideSector(&Fee_RdWrOrder_st.xRdAddress, FEE_PAGE_LEN, TRUE);

                        /* Reset the retry indicator (normally done by calling function) */
                        *SearchRetry_ptr = FALSE;

                        /* Go on with the search */
                        Fee_RdWrOrder_st.Fee_LLSearchUnknBlkHdr_en = FEE_LL_SEARCHUNKNBLK_INIT_E;

                        /* Do not set the error return but keep on searching. Otherwise the
                         * unkown block reorganization will be finished without reaching the
                         * end of the sector. */
                    }
                    break;

                    /* These cases should never be reached (cannot be returned by Fee_LLSearchSpecifiedBlkHeader).
                     * FEE_ERROR_E and FEE_ABORTED_E cannot be reached because cache is not used and the block
                     * which is searched will be there at least once in the oldest FULL sector */
                    case FEE_BLOCK_INVALIDATED_E:
                    case FEE_ABORTED_E:
                    case FEE_NUM_RET_VAL_E:
                    case FEE_ERASE_SECTOR_E:
                    case FEE_SECTORCHANGE_E:
                    case FEE_SECTORFULL_E:
                    default:
                    {
                        /* Return an error */
                        xRetVal = FEE_ABORTED_E;
                    }
                    break;
                }
            break;

            /* Default case */
            default:
            {
                /* State should never be reached */
                xRetVal = FEE_ERROR_E;
            }
            break;
        }
    }
    while((Fee_stMain == FEE_POLLING_MODE_E) && (xRetVal == FEE_ORDER_PENDING_E));

    /* Check for necessary resets */
    if(xRetVal != FEE_ORDER_PENDING_E)
    {
        /* Reset state machine */
        Fee_RdWrOrder_st.Fee_LLSearchUnknBlkHdr_en = FEE_LL_SEARCHUNKNBLK_INIT_E;
    }

    return (xRetVal);
}
#else
/**
 *********************************************************************************************************
 * Fee_BuildUpCacheUnknownBlk(): Build up the cache for unkown blocks over the oldest sector.
 *
 * This function builds up the cache for the unknown blocks that are present in the oldest sector.
 * The block checksum and data checksum are both considered while building the cahce.
 * The function continues to scan the remaining sectors for finding the latest copy of the unknown blocks.
 * The function is designed to be called when cyclic tasks are running.
 *
 * \return
 * \retval   FEE_ORDER_PENDING_E:   Order is pending
 * \retval   FEE_ABORTED_E:         Order was aborted
 * \retval   FEE_SECTORFULL_E:      The end address of the sector
 *                                  was reached
 * \seealso
 * \usedresources
 *********************************************************************************************************
 */
Fee_stRetVal_ten Fee_BuildUpCacheUnknownBlk(void)
{
    Fee_stRetVal_ten xRetVal    = FEE_ORDER_PENDING_E;  /* Function return value */
    Fee_stRetVal_ten xtmpRetVal = FEE_ORDER_PENDING_E;  /* To hold return values of the functions Fee_LLCalcBlkCrcInFlash and Fee_LLSearchNextBlkHeader */
    Fee_GlobInfoLastRdHeader_tst xTmpNxtBlkHdr_st;      /* To hold the details of the unkown block header */
    uint16 i;                                           /* For loop Variable */
    uint16 xDummyCacheIdx_u16 = 0;                     /* Dummy cache index for the function Fee_SrvBinarySearchInBlockProp */
    uint8 xPhySecIdx_u8;                              /* Index of the physical sector */
    uint8 xLogSecIdx_u8;                              /* Index of the logical sector */
    boolean xContinueSearch_b = FALSE;                  /* Flag to indicate if search needs to be continued in other sector or not */
    boolean xForcePageBufReload_b = FALSE;              /* Force no reload of the page buffer */
    boolean    xOldUnknonwBlk;                                /* Flag to indicate if the unknown block is new or old */

    /* Switch over state machine */
    switch (Fee_RdWrOrder_st.Fee_LLBuildUpCacheUnknownBlk_en)
    {
        /* Init state */
        case FEE_LL_BLD_UP_CACHE_UNKOWN_BLK_INIT_E:
        {
            /* Initialise cache */
            for (i=0;i<FEE_RB_ACT_UNKNOWN_BLK_CACHE_ARRAY_SIZE;i++)
            {
                Fee_UnknownBlkCache_Addr_au32[i]    = FEE_CACHE_INIT_VALUE;    /* Block header address */
                Fee_UnknownBlkCache_FeeIndex_u16[i] = 0;                      /* Fee index */
            }

            /* Clear the count of number of unknown blocks */
            Fee_RdWrOrder_st.Fee_UnknownBlkCacheIdx_u16 = 0;

            /* Set to next state to build up the cache */
            Fee_RdWrOrder_st.Fee_LLBuildUpCacheUnknownBlk_en = FEE_LL_BLD_UP_CACHE_UNKOWN_BLK_READ_E;

            /* Force a reload of the page buffer because the init state is only passed for new block read orders */
            xForcePageBufReload_b = TRUE;

            /* Copy the start address for the search, start address is from the last scanned address, if the address is within the range. */
            if ((Fee_RdWrOrder_st.Fee_UnknownBlkCacheAdd_u32 >= Fee_FlashProp_st[Fee_LLSectorOrder_st[0].xPhySecIdx_u8].Fee_LogStartAddress_u32) &&
                (Fee_RdWrOrder_st.Fee_UnknownBlkCacheAdd_u32 <=  Fee_FlashProp_st[Fee_LLSectorOrder_st[0].xPhySecIdx_u8].Fee_LogEndAddress_u32))
            {
                Fee_RdWrOrder_st.xRdAddress = Fee_RdWrOrder_st.Fee_UnknownBlkCacheAdd_u32;
            }
            else
            {
                /* The cache is not built up yet, start from the top of the oldest sector. */
                Fee_RdWrOrder_st.Fee_UnknownBlkCacheAdd_u32 = Fee_FlashProp_st[Fee_LLSectorOrder_st[0].xPhySecIdx_u8].Fee_LogStartAddress_u32;
                Fee_RdWrOrder_st.xRdAddress = Fee_RdWrOrder_st.Fee_UnknownBlkCacheAdd_u32;
            }
        }
        //break;

        /* MR12 RULE 16.3 VIOLATION: Time critical position, skip break for faster processing */
        case FEE_LL_BLD_UP_CACHE_UNKOWN_BLK_READ_E:
        {
            /* Search the next block header */
            xtmpRetVal = Fee_LLSearchNextBlkHeader(&xTmpNxtBlkHdr_st, FEE_USE_MANUAL_ACCESS, FEE_NO_CACHE_UPDATE, xForcePageBufReload_b, 0);

            /* Switch function return */
            switch(xtmpRetVal)
            {
                /* Order is still pending */
                case FEE_ORDER_PENDING_E:
                {
                    /* Just wait */
                    ;
                }
                break;

                /* One valid header was found */
                case FEE_ORDER_FINISHED_E:
                {
                    /* Reset the forced reload for the initialization (init value will remain
                     * true in case the polling mode is active) */
                    xForcePageBufReload_b = FALSE;

                    /* Check if the found block index is within the configuration or not */
                    if(Fee_SrvBinarySearchInBlockProp(xTmpNxtBlkHdr_st.FeeIndex_u16, &xDummyCacheIdx_u16) == FALSE)
                    {
                        /* The first copy of an unknown block index was found, validate if Data CRC is ok */

                        /* Update the read address to the last found block header */
                        Fee_RdWrOrder_st.xRdAddress = xTmpNxtBlkHdr_st.AdrBlkHeader_u32;

                        /* Increment the read address page wise ("safety mode") and search for the next
                         * block header until the complete sector is checked
                         * --> search for all copies of the block in order to find the latest one */
                        Fee_IncAddressInsideSector(&Fee_RdWrOrder_st.xRdAddress, FEE_PAGE_LEN, TRUE);

                        /* Update the address till where the sector is scanned till:
                         * 1. The unknown block cache is full and a new unknown block is found or
                         * 2. Till end of oldest sector is reached.
                         */
                        if ((Fee_RdWrOrder_st.Fee_UnknownBlkCacheIdx_u16 < FEE_RB_ACT_UNKNOWN_BLK_CACHE_ARRAY_SIZE) &&
                            (Fee_RdWrOrder_st.xRdAddress >= Fee_FlashProp_st[Fee_LLSectorOrder_st[0].xPhySecIdx_u8].Fee_LogStartAddress_u32) &&
                            (Fee_RdWrOrder_st.xRdAddress <= Fee_FlashProp_st[Fee_LLSectorOrder_st[0].xPhySecIdx_u8].Fee_LogEndAddress_u32))
                        {
                            Fee_RdWrOrder_st.Fee_UnknownBlkCacheAdd_u32 = Fee_RdWrOrder_st.xRdAddress;
                        }
                        else
                        {
                            /* Cache for unknown block cant be built further.
                             * Fee_RdWrOrder_st.Fee_UnknownBlkCacheAdd_u32 should hold the last address till where the cahce was built.
                             * Hence, do nothing here.  */
                        }

                        /* Save the block info */
                        Fee_GlobInfoLastRdHeader_st = xTmpNxtBlkHdr_st;

                        /* Go to next state to validate the Data CRC for this copy */
                        Fee_RdWrOrder_st.Fee_LLBuildUpCacheUnknownBlk_en = FEE_LL_BLD_UP_CACHE_UNKOWN_BLK_VALIDATEDATA_E;
                    }
                    else
                    {
                        /* The found block is a known block and not relevant for this search
                         * --> Go on with the search */

                        /* Update the read address to the last found block header */
                        Fee_RdWrOrder_st.xRdAddress = xTmpNxtBlkHdr_st.AdrBlkHeader_u32;

                        /* Increment the read address page wise ("safety mode") and search for the next
                         * block header until the complete sector is checked
                         * --> search for all copies of the block in order to find the latest one */
                        Fee_IncAddressInsideSector(&Fee_RdWrOrder_st.xRdAddress, FEE_PAGE_LEN, TRUE);

                        /* Update the address till where the sector is scanned till:
                         * 1. The unknown block cache is full and a new unknown block is found or
                         * 2. Till end of oldest sector is reached.
                         */
                        if ((Fee_RdWrOrder_st.Fee_UnknownBlkCacheIdx_u16 < FEE_RB_ACT_UNKNOWN_BLK_CACHE_ARRAY_SIZE) &&
                            (Fee_RdWrOrder_st.xRdAddress >= Fee_FlashProp_st[Fee_LLSectorOrder_st[0].xPhySecIdx_u8].Fee_LogStartAddress_u32) &&
                            (Fee_RdWrOrder_st.xRdAddress <= Fee_FlashProp_st[Fee_LLSectorOrder_st[0].xPhySecIdx_u8].Fee_LogEndAddress_u32))
                        {
                            Fee_RdWrOrder_st.Fee_UnknownBlkCacheAdd_u32 = Fee_RdWrOrder_st.xRdAddress;
                        }
                        else
                        {
                            /* Cache for unknown block cant be built further.
                             * Fee_RdWrOrder_st.Fee_UnknownBlkCacheAdd_u32 should hold the last address till where the cahce was built.
                             * Hence, do nothing here.  */
                        }
                    }
                }
                break;

                /* The sector end address is reached */
                case FEE_SECTORFULL_E:
                {
                    /* Update the address till where the sector is scanned till:
                     * 1. The unknown block cache is full and a new unknown block is found or
                     * 2. Till end of oldest sector is reached.
                     */
                    if ((Fee_RdWrOrder_st.Fee_UnknownBlkCacheIdx_u16 < FEE_RB_ACT_UNKNOWN_BLK_CACHE_ARRAY_SIZE) &&
                        (Fee_RdWrOrder_st.xRdAddress >= Fee_FlashProp_st[Fee_LLSectorOrder_st[0].xPhySecIdx_u8].Fee_LogStartAddress_u32) &&
                        (Fee_RdWrOrder_st.xRdAddress <= Fee_FlashProp_st[Fee_LLSectorOrder_st[0].xPhySecIdx_u8].Fee_LogEndAddress_u32))
                    {
                        Fee_RdWrOrder_st.Fee_UnknownBlkCacheAdd_u32 = Fee_RdWrOrder_st.xRdAddress;
                    }
                    else
                    {
                        /* Cache for unknown block cant be built further.
                         * Fee_RdWrOrder_st.Fee_UnknownBlkCacheAdd_u32 should hold the last address till where the cahce was built.
                         * Hence, do nothing here.  */
                    }

                    /* Continue scanning the other sectors as PLC must be built over all the sectors */
                    /* Get the corresponding physical sector index of the sector that has been used for the search */
                    xPhySecIdx_u8 = Fee_GetPhysSectorByAddress(Fee_RdWrOrder_st.xRdAddress);

                    /* Get the corresponding logical sector index */
                    xLogSecIdx_u8 = Fee_idxLLSectorOrder_au8[xPhySecIdx_u8];

                    /* Reset the search indicator */
                    xContinueSearch_b = FALSE;

                    /* Check if there are more logical sectors available (Fee_NumFlashBanksUsed_u8 is the biggest possible value)
                     * and if one of these sectors is either in the state FULL or USED */
                    do
                    {
                        /* Decrement the logical sector */
                        xLogSecIdx_u8++;

                        /* Check for overflow */
                        if(xLogSecIdx_u8 < Fee_NumFlashBanksUsed_u8)
                        {
                            /* Check for relevant sector states */
                            if((Fee_LLSectorOrder_st[xLogSecIdx_u8].SecState_en == FEE_SECTOR_USED_E) ||
                               (Fee_LLSectorOrder_st[xLogSecIdx_u8].SecState_en == FEE_SECTOR_FULL_E))
                            {
                                /* Go on with the next sector */
                                xContinueSearch_b = TRUE;

                                /* Get respective physical sector index */
                                xPhySecIdx_u8 = Fee_LLSectorOrder_st[xLogSecIdx_u8].xPhySecIdx_u8;

                                /* This sector has to be checked, starting at the beginning */
                                Fee_RdWrOrder_st.xRdAddress = Fee_FlashProp_st[xPhySecIdx_u8].Fee_LogStartAddress_u32;

                                /* The next search will start in the next sector and will continue until the most active sector is reached */
                           }
                        }
                        else
                        {
                            /* End of the sectors have been reached, the loop must be exited now. Do nothing. */
                        }
                    }
                    while((xLogSecIdx_u8 < Fee_NumFlashBanksUsed_u8) && (xContinueSearch_b == FALSE));

                    /* Check if all relevant sectors have been checked already */
                    if(xContinueSearch_b == FALSE)
                    {
                        /* All relevant sectors have been checked and cache building is complete. */
                        /* Set the return value */
                        xRetVal = FEE_ORDER_FINISHED_E;
                    }
                }
                break;

                /* Error cases */
                case FEE_SEARCH_ABORTED_E:
                case FEE_ABORTED_E:
                case FEE_ERROR_E:
                default:
                {
                    /* States should never be reached */
                    xRetVal = FEE_ERROR_E;
                }
                break;
            }
        }
        break;

        case FEE_LL_BLD_UP_CACHE_UNKOWN_BLK_VALIDATEDATA_E:
        {
            /* Call to validate if the data CRC is valid */
            xtmpRetVal = Fee_LLCalcBlkCrcInFlash(&Fee_GlobInfoLastRdHeader_st);

            /* Update cache if the CRC is valid */
            /* Switch function return */
            switch(xtmpRetVal)
            {
                /* Order is still pending */
                case FEE_ORDER_PENDING_E:
                {
                    /* Just wait */
                    ;
                }
                break;

                /* One valid header was found */
                case FEE_ORDER_FINISHED_E:
                {
                    /* A unknown block with valid header and valid data is found, store the contents in the cache. */
                    /* Clear the flag to check if this unknown block is already found earlier or not. */
                    xOldUnknonwBlk = FALSE;

                    /* Check if this unknown block was found earlier.
                     * It is suffient to do the check till Fee_UnknownBlkCacheIdx_u16, as this will hold the index till which the cache is filled. */
                    for(i=0; i<Fee_RdWrOrder_st.Fee_UnknownBlkCacheIdx_u16; i++)
                    {
                        if (Fee_UnknownBlkCache_FeeIndex_u16[i] == Fee_GlobInfoLastRdHeader_st.FeeIndex_u16)
                        {
                            /* Block was already found earlier, stop the search and set the flag for updating cache. */
                            xOldUnknonwBlk = TRUE;
                            /* Store the index and address, the location to store is there in variable i */
                            Fee_UnknownBlkCache_Addr_au32[i]   = Fee_GlobInfoLastRdHeader_st.AdrBlkHeader_u32;    /* Store block header address */

                            /* Update of the Fee index is not required as the Fee index is already known now and only the address is being updated now */
                            break;
                        }
                        else
                        {
                            /* Continue the search for the remaning entries in cache. */
                        }
                    }

                    /* If cache is not yet updated, then, update in next available space in cache.
                     * Also, consider only the unknown blocks of the oldest sector only. */
                    if ((xOldUnknonwBlk == FALSE) && (Fee_RdWrOrder_st.Fee_UnknownBlkCacheIdx_u16 < FEE_RB_ACT_UNKNOWN_BLK_CACHE_ARRAY_SIZE) &&
                        (Fee_GlobInfoLastRdHeader_st.AdrBlkHeader_u32 < Fee_FlashProp_st[Fee_LLSectorOrder_st[0].xPhySecIdx_u8].Fee_LogEndAddress_u32))
                    {
                        /* This is a new unknown block found, store at the next available location in the cache. */
                        Fee_UnknownBlkCache_Addr_au32[Fee_RdWrOrder_st.Fee_UnknownBlkCacheIdx_u16]   = Fee_GlobInfoLastRdHeader_st.AdrBlkHeader_u32;            /* Block header address */
                        Fee_UnknownBlkCache_FeeIndex_u16[Fee_RdWrOrder_st.Fee_UnknownBlkCacheIdx_u16]     = Fee_GlobInfoLastRdHeader_st.FeeIndex_u16;  /* Fee index */

                        /* Increment the index to next location in cache */
                        Fee_RdWrOrder_st.Fee_UnknownBlkCacheIdx_u16++;
                    }
                    else
                    {
                        /* This place is reached only when:
                         *  1. The cache for unknown block is full i.e., there are more unknown blocks and its details cant be remembered or
                         *  2. All the unknown blocks of the oldest sector are scanned.
                         * In the first case, cache must be build for the remaining area of the sector after all the current blocks are transfered.
                         * In the second case, no more cache building is required. */
                    }

                    /* Continue with the search for the next unknown block and cache build up. */
                    Fee_RdWrOrder_st.Fee_LLBuildUpCacheUnknownBlk_en = FEE_LL_BLD_UP_CACHE_UNKOWN_BLK_READ_E;

                }
                break;

                /* Found unknown block copy was invalid, skip this copy and continue the search. */
                case FEE_ERROR_E:
                {
                    Fee_RdWrOrder_st.Fee_LLBuildUpCacheUnknownBlk_en = FEE_LL_BLD_UP_CACHE_UNKOWN_BLK_READ_E;
                }
                break;

                /* Error cases */
                case FEE_SECTORFULL_E:
                case FEE_SEARCH_ABORTED_E:
                case FEE_ABORTED_E:
                default:
                {
                    /* States should never be reached */
                    xRetVal = FEE_ERROR_E;
                }
                break;
            }/* End of switch case of Fee_LLCalcBlkCrcInFlash */
        }
        break;
        default:
        {
            break;
        }
    }/*End of switch case */

    /* Check if the search was aborted or the sector is full */
    if (xRetVal != FEE_ORDER_PENDING_E)
    {
        /* No valid block header found yet, reset the state machine */
        Fee_RdWrOrder_st.Fee_LLBuildUpCacheUnknownBlk_en = FEE_LL_BLD_UP_CACHE_UNKOWN_BLK_INIT_E;
    }

    return(xRetVal);

}
#endif /* End of (FEE_RB_ACT_UNKNOWN_BLOCK_CACHE_SIZE == 0) */
#endif /* End of ((FEE_RB_ACT_SURVIVAL_EVAL != FALSE) || (FEE_RB_ACT_UNKNOWN_BLOCK_REORG != FALSE)) */

/**
 *********************************************************************
 * Fee_LLSearchNextBlkHeader(): Search for the next block header
 *                              within one sector
 *
 * This function searches for the next block header within one sector.
 * Therefore the internal page buffer Fee_llPageBuf_au32 is used. If only the
 * erase pattern is found within the page buffer, the rest of the
 * sector is assumed to be empty. The function searches not until the
 * very end of the respective sector.
 *
 * \param    Fee_GlobInfoLastRdHeader_ptr: Pointer to headers structure
 * \param    CachedAccess_boolean:    TRUE:   Cached access
 *                                    FALSE:  "Manual search"
 * \param    FastCacheUpdate_boolean: TRUE:   Update cache if an index
 *                                            is found
 *                                    FALSE:  Do not update the cache
 * \param    xForcePageBufReload_b:   TRUE:   The page buffer will be
 *                                            reloaded
 *                                    FALSE:  The page buffer will only
 *                                            be reloaded if necessary
 *
 * \return
 * \retval   FEE_ORDER_PENDING_E:   Order is pending
 * \retval   FEE_ABORTED_E:         Order was aborted
 * \retval   FEE_SECTORFULL_E:      The end of the sector is reached
 * \retval   FEE_ERROR_E:           Cached access did not work or
 *                                  the default state was reached
 * \retval   FEE_ORDER_FINISHED_E:  Order is finished
 * \seealso
 * \usedresources
 *********************************************************************
 */
/* MR12 RULE 1505 VIOLATION: This function is used within the same file and has no external linkage */
Fee_stRetVal_ten Fee_LLSearchNextBlkHeader(Fee_GlobInfoLastRdHeader_tst* Fee_GlobInfoLastRdHeader_ptr,
                                           uint8 CachedAccess_u8,
                                           uint8 FastCacheUpdate_u8,
                                           boolean xForcePageBufReload_b,
                                           uint32 strAddrHdrSearch)
{
    Fee_stRetVal_ten xRetVal = FEE_ORDER_PENDING_E;     /* Function return */

    #if ((FEE_HEADER_RECHECK_ACTIVE != FALSE) || (FEE_NO_FALLBACK_ACTIVE != FALSE))
    /* In case NoFallback is activated the last block header has to be stored until the NoFallback marker is evaluated */
    static Fee_BlkHeader_tst xCurrBlkHeader_st;                         /* Block header structure */
    static uint32 xBlkHeaderAdr_u32;                                    /* Address of the last block header */
    #else
    Fee_BlkHeader_tst xCurrBlkHeader_st;                /* Block header structure */
    #endif

    uint8           xPhySecIdx_u8;                      /* Physical sector index */
    uint8           xPhyWrSecIdx_u8;                    /* Physical sector index for the next write request */
    uint16          i_u16 = 0;                          /* Loop counter */
    uint16          xCalcCrc_u16 = 0;                   /* Block header CRC */
    uint32          xLoopInRamCounter_u32 = 0;          /* Loop counter */
    static uint16                   xNumBytes2Read_u16 = 0;             /* Bytes to read via Fls_Read */
    static boolean xPageBufReloaded_b = TRUE;                           /* Reloaded page buffer */
    static uint8 xCntRetry_u8 = FEE_MAX_RD_WR_COMP_RETRIES;             /* Retries for read */
    static uint8 xLoopReduction_u8 = 0;                                 /* Loop reduction counter */
#if (FEE_NO_FALLBACK_ACTIVE != FALSE)
    static uint8 noFBPatternBfr_au8[FEE_PAGE_LEN]; /* buffer for reading the content of the noFallBack marker page */
#endif
    #if(FEE_FAST_CACHE_INIT_ACTIVE == FALSE)
    uint8 local_loop_u8;                                                /* Loop variable for checking page contents */
    uint32* Fee_PageBytePtr_pu32;                                       /* Temp pointer to read contents of page buffer. */
    #endif

    #if (FEE_PRV_DEBUGGING != FALSE)
    uint32 xTimeStart_u32 = 0;

    if(Eep_stMain == EEP_FIRSTINIT_INI)
    {
        Fee_Prv_stModuleTest_st.Fee_SearchNextBlockHeaderNum_u32++;
    }
    #endif
    if (strAddrHdrSearch != 0uL)
    {
        Fee_RdWrOrder_st.xRdAddress = strAddrHdrSearch;
    }
    /* Loop if function state is pending */
    do
    {
        /* Switch over state machine */
        switch(Fee_RdWrOrder_st.Fee_LLRdState_en)
        {
            /* Init state */
            case FEE_LL_INIT_READ_E:
            {
                /* Get index of the physical sector belonging to a read request */
                xPhySecIdx_u8   = Fee_GetPhysSectorByAddress(Fee_RdWrOrder_st.xRdAddress);

                /* Get index of the physical sector belonging to a write request */
                xPhyWrSecIdx_u8 = Fee_GetPhysSectorByAddress(Fee_RdWrOrder_st.xWrAddress);

                /* Check if the user address is outside the active (logical) sector or behind the next
                 * write address (per definition the flash is empty behind the next write address if
                 * writing and reading is done in the same sector) */
                if((Fee_RdWrOrder_st.xRdAddress >= Fee_FlashProp_st[xPhySecIdx_u8].Fee_LogEndAddress_u32 ) ||
                   ((Fee_RdWrOrder_st.xRdAddress >= Fee_RdWrOrder_st.xWrAddress) &&
                    (xPhySecIdx_u8 == xPhyWrSecIdx_u8)))
                {
                    /* Check if the read address is behind the active sector */
                    if(Fee_RdWrOrder_st.xRdAddress >= Fee_FlashProp_st[xPhySecIdx_u8].Fee_LogEndAddress_u32)
                    {
                        /* Reset the address */
                        Fee_RdWrOrder_st.xRdAddress = Fee_FlashProp_st[xPhySecIdx_u8].Fee_LogEndAddress_u32;
                    }

                    /* Sector is full */
                    xRetVal = FEE_SECTORFULL_E;

                    /* Leave loop */
                    break;
                }

                /* Check if a reload via Fls is necessary or not */
                /* MR12 RULE 13.5 VIOLATION: Reload of buffer is required only when multiple conditions are not satisifed. */
                if((xForcePageBufReload_b == FALSE) &&
                   (Fee_RdWrOrder_st.AdrHdSearchStart_u32 != FEE_MAXUINT32) &&
                   (Fee_RdWrOrder_st.xRdAddress < ((Fee_RdWrOrder_st.AdrHdSearchStart_u32 + (uint32)FEE_LL_PAGEBUFFSIZE) - (uint32)xLoopReduction_u8)) &&
                   (Fee_RdWrOrder_st.xRdAddress >= Fee_RdWrOrder_st.AdrHdSearchStart_u32) &&
                   (xPhySecIdx_u8 == Fee_GetPhysSectorByAddress(Fee_RdWrOrder_st.AdrHdSearchStart_u32)))
                {
                    /* Reload is NOT necessary, indicate a still valid page buffer */
                    xPageBufReloaded_b = FALSE;

                    /* Evaluate the rest of the page buffer content */
                    Fee_RdWrOrder_st.Fee_LLRdState_en = FEE_LL_READ_FINISHED_E;

                    /* Break in order to jump over the Fls_Read state */
                    break;
                }
                else
                {
                    /* Indicate a necessary reload */
                    xPageBufReloaded_b = TRUE;

                    /* Reset the start address for the search */
                    Fee_RdWrOrder_st.AdrHdSearchStart_u32 = Fee_RdWrOrder_st.xRdAddress;


                    /* Check for the necessity of a cached access */
                    if(CachedAccess_u8 == (uint8)FEE_USE_CACHED_ACCESS)
                    {
                        /* Cached access is possible, only read the necessary amount of data (only header pages) */
                        xNumBytes2Read_u16 = FEE_VIRTUAL_PAGE_SIZE*FEE_PAGES_USED_BY_BLK_HEADER;
                    }
                    else
                    {
                        /* Set default value for the number of bytes to read */
                        xNumBytes2Read_u16 = FEE_LL_PAGEBUFFSIZE;

                        /* 1. Check if the current sector has enough free pages left to fill the internal page buffer completely */
                        if((Fee_RdWrOrder_st.xRdAddress + (uint32)FEE_LL_PAGEBUFFSIZE) > Fee_FlashProp_st[xPhySecIdx_u8].Fee_LogEndAddress_u32)
                        {
                           /* Reduce the number of bytes to read */
                           xNumBytes2Read_u16 = (uint16)((Fee_FlashProp_st[xPhySecIdx_u8].Fee_LogEndAddress_u32 + 1u)-
                                                         Fee_RdWrOrder_st.xRdAddress);
                        }

                        /* 2. Check if reading of a complete page buffer exceeds the current write address */
                        if(((Fee_RdWrOrder_st.xRdAddress + (uint32)FEE_LL_PAGEBUFFSIZE) >= Fee_RdWrOrder_st.xWrAddress) &&
                           (xPhySecIdx_u8 == xPhyWrSecIdx_u8))
                        {
                           /* Reduce the number of bytes to read */
                           xNumBytes2Read_u16 = (uint16)(Fee_RdWrOrder_st.xWrAddress - Fee_RdWrOrder_st.xRdAddress);
                        }
                    }

                    /* Set next state in order to fill the page buffer with data from the flash */
                    Fee_RdWrOrder_st.Fee_LLRdState_en = FEE_LL_READ_PAGE_E;
                }
            }
            /* No break to save time */

            /* Read a page */
            /* MR12 RULE 16.3 VIOLATION: Time critical position */
            case FEE_LL_READ_PAGE_E:
            {
                /* Read the data from either the logical sector start address or the last known DFlash position of
                 * the requested block */
                if(Fls_Read(Fee_RdWrOrder_st.xRdAddress, (uint8*)&Fee_PageBytePtr_cpu8[0], xNumBytes2Read_u16) != E_NOT_OK)
                {
                    /* Set next state */
                    Fee_RdWrOrder_st.Fee_LLRdState_en = FEE_LL_WAIT_READ_PAGE_E;
                }
                else
                {
                    /* Fls did not accept the order due to wrong parameters or an internal busy state.
                     * Reset the state machine */
                    xRetVal = FEE_ABORTED_E;
                }
            }
            break;

            /* Wait for the read order to be finished */
            case FEE_LL_WAIT_READ_PAGE_E:
            {
                /* The next state will be set by the Fee_JobEndNotification () or
                 * Fee_JobErrorNotification() function automatically */

                /* Check whether the OS is currently running or not */
                if (Fee_stMain == FEE_POLLING_MODE_E)
                {
                    /* Call the Fls main function manually */
                    Fls_MainFunction();
                }

                #if (STD_ON == FEE_POLLING_MODE)
                /* Use the FLS polling mechanism in order to reach the next state */
                Fee_CheckFlsJobResult();
                #endif
            }
            break;

            /* Error reaction for read error */
            case FEE_LL_READ_ERROR_E:
                /* Reset the complete read buffer */
                Fee_SrvMemSet8((uint8*)&Fee_PageBytePtr_cpu8[0], (uint8)FEE_ERASE_PATTERN, (uint32)FEE_LL_PAGEBUFFSIZE);

                /* Verify retry possibility */
                if(xCntRetry_u8 > 0u)
                {
                    /* Decrement retry possibilities */
                    xCntRetry_u8--;

                    /* Try again to call the Fls and perform the read procedure */
                    Fee_RdWrOrder_st.Fee_LLRdState_en = FEE_LL_READ_PAGE_E;
                }
                else
                {
                    /* Reading failed somewhere in between the currently read flash area
                     * --> Cached access:    regular behaviour (switch over to manual read)
                     * --> Noncached access: Increment read address and repeat reading afterwards */
                    if(CachedAccess_u8 == FEE_USE_CACHED_ACCESS)
                    {
                        /* Error handling must be done by upper layer
                         * --> Current entry will be marked as temp invalid in the cache and a
                         *     manual search will be triggered starting at the beginning of the current
                         *     read sector */
                        xRetVal = FEE_ERROR_E;
                    }
                    else
                    {
                        /* Force a reload and start searching within the next area
                         * --> the formerly read flash area will not be used anymore,
                         *     data might get lost (no influence on cache and cache status) */
                        Fee_IncAddressInsideSector(&Fee_RdWrOrder_st.xRdAddress, xNumBytes2Read_u16, TRUE);

                        /* Reset state machine */
                        Fee_RdWrOrder_st.Fee_LLRdState_en = FEE_LL_INIT_READ_E;
                    }
                }
            break;

            /* Evaluate the content of the page buffer */
            case FEE_LL_READ_FINISHED_E:
            {
                /*
                 * Header overview:
                 *  +----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+
                 *  |            Preamble            |Blk Status|       FeeIndex      |     Block length    |     Header CRC16    |
                 *  +----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+
                 *  Preamble   : 0xA53C96 fix pattern
                 *  Blk Status : Contains information like security level, etc.
                 *  FeeIndex   : Block index
                 *  Block length: Block length without the header length
                 *  Header CRC16: CRC16 checksum over Preamble, Blk Status, Fee Index and Block length.
                 *                The start value is FEE_MARKER_PATTERN (0xCAFE)
                 *
                 *  Hint: A block header will always start at the beginning of a page.
                 */

                /* Check if a complete new page buffer was loaded */
                if(xPageBufReloaded_b == FALSE)
                {
                    /* Go on with the search within the same page buffer at the corresponding offset */
                    i_u16 = (uint16)((Fee_RdWrOrder_st.xRdAddress - Fee_RdWrOrder_st.AdrHdSearchStart_u32) / (uint32)FEE_PAGE_LEN);
                }
                else
                {
                    /* Reset the loop counter start value*/
                    i_u16 = 0u;

                    #if (FEE_PRV_DEBUGGING != FALSE)
                    Fee_Prv_stModuleTest_st.Fee_SearchNextBlockHeaderNumReload_u32++;
                    #endif
                }

                /* Set the loop counter end value to the temp value */
                xLoopInRamCounter_u32 = xNumBytes2Read_u16;

                /* Check for the page alignment of the loop counter */
                while((xLoopInRamCounter_u32 % (uint32)FEE_PAGE_LEN) != 0u)
                {
                    /* Increment address */
                    xLoopInRamCounter_u32++;
                }

                /* Copy the preamble out of the last 8 Bytes of the buffer */
                if(xLoopInRamCounter_u32 >= (uint32)FEE_LL_PAGEBUFFSIZE)
                {
                    /* Copy the preamble out of the last 8 Bytes of the buffer */
                    Fee_LLCopyPageBuff2HeaderStart(&xCurrBlkHeader_st, &Fee_PageBytePtr_cpu8[xLoopInRamCounter_u32 - 8uL]);

                    /* Check if the end of the buffer contains a preamble */
                    if ((xCurrBlkHeader_st.Preamble_au8[2] == (uint8)FEE_BLK_HEADER_PREAMBEL_BYTE_2) &&
                        (xCurrBlkHeader_st.Preamble_au8[1] == (uint8)FEE_BLK_HEADER_PREAMBEL_BYTE_1) &&
                        (xCurrBlkHeader_st.Preamble_au8[0] == (uint8)FEE_BLK_HEADER_PREAMBEL_BYTE_0))
                    {
                        /* Set the loop reduction counter to the smallest supported page size. Otherwise only the first
                         * half out of the block header might be available inside the page buffer. */
                        xLoopReduction_u8 = (uint8)FEE_BKL_HEADER_REDUCTION;
                    }
                }

                /* Reduce the upper limit of the loop */
                xLoopInRamCounter_u32 -= xLoopReduction_u8;
                xLoopInRamCounter_u32 /= (uint32)FEE_PAGE_LEN;

                #if (FEE_PRV_DEBUGGING != FALSE)
                xTimeStart_u32 = Mcu_Rb_GetSysTimePart(TIM0);
                #endif

                /* Loop over all pages inside the page buffer
                 * Hints:
                 * - a complete block header must be evaluated which are 14 bytes
                 *   (--> the upper limit for the search varies depending on the page size
                 *        in order to access only the buffer area)
                 * - also possible for the cached access, because the header information
                 *   will be located within the first two bytes */
                /* MR12 RULE 15.4 VIOLATION: Using 2 breaks has no side effects, as the first break is reached when valid header is found. and second when cache is pointing to incorrect location. In both cases, the scan of RAM buffer is completed and software can go to next step. */
                for(; i_u16 < xLoopInRamCounter_u32; i_u16++)
                {
                    /* Extract the preamble out of the page buffer and copy it to the block structure */
                    Fee_LLCopyPageBuff2HeaderStart(&xCurrBlkHeader_st, &Fee_PageBytePtr_cpu8[(i_u16 * (uint16)FEE_PAGE_LEN)]);

                    /* Compare the preamble of the block header byte - wise */
                    if ((xCurrBlkHeader_st.Preamble_au8[2] == (uint8)FEE_BLK_HEADER_PREAMBEL_BYTE_2) &&
                        (xCurrBlkHeader_st.Preamble_au8[1] == (uint8)FEE_BLK_HEADER_PREAMBEL_BYTE_1) &&
                        (xCurrBlkHeader_st.Preamble_au8[0] == (uint8)FEE_BLK_HEADER_PREAMBEL_BYTE_0))
                    {

                        /* For controllers with no Cache init, the last programmed page is identified here during the Next Free page identification.
                         * Set the last programmed address after the complete header. */
                        #if(FEE_FAST_CACHE_INIT_ACTIVE == FALSE)
                        if (Fee_stMain == FEE_POLLING_MODE_E)
                        {
                            Fee_RdWrOrder_st.LastProgrammedAddress_u32 = (uint32)(Fee_RdWrOrder_st.AdrHdSearchStart_u32 + (uint32)(i_u16 * (uint16)FEE_PAGE_LEN));
                        }
                        else
                        {
                            /* Software is running in Normal mode. it is not required to identify the last programmed page. */
                        }
                        #endif

                        /* Set the loop reduction counter to the smallest supported page size. Otherwise only the first
                         * half out of the block header might be available inside the page buffer. */
                        xLoopReduction_u8 = (uint8)FEE_BKL_HEADER_REDUCTION;

                        /* Extract the rest up to the Crc32 out of the page buffer and copy it to the block structure */
                        Fee_LLCopyPageBuff2HeaderMid(&xCurrBlkHeader_st, &Fee_PageBytePtr_cpu8[(i_u16 * (uint16)FEE_PAGE_LEN)]);

                        /* Read BIT7 and check if the block shall be considered or not.
                         * If this bit is set the block was written in plant and must be ignored from application. */
                        if((xCurrBlkHeader_st.BlkStatus_u8 & FEE_MASK_BIT7) == 0u)
                        {
                            /* Check the block header CRC */
                            xCalcCrc_u16 = Crc_CalculateCRC16((uint8*)&Fee_PageBytePtr_cpu8[(i_u16 * (uint16)FEE_PAGE_LEN)],
                                                              (uint32)(FEE_BLK_HEADER_SIZE - 6u),
                                                              (uint16)FEE_MARKER_PATTERN,
                                                              FALSE);

                            /* Check the header consistency */
                            if(xCalcCrc_u16 == xCurrBlkHeader_st.HdrCrc16_u16)
                            {
                                /* This is a valid header. Nevertheless it is possible that this order was not finished correct
                                 * or that the block checksum is wrong. */

                                /* Extract the rest out of the page buffer and copy it to the block structure */
                                Fee_LLCopyPageBuff2HeaderEnd(&xCurrBlkHeader_st, &Fee_PageBytePtr_cpu8[(i_u16 * (uint16)FEE_PAGE_LEN)]);

                                /* Store the block header's start address to the global info structure */
                                Fee_GlobInfoLastRdHeader_ptr->AdrBlkHeader_u32 = (uint32)(Fee_RdWrOrder_st.AdrHdSearchStart_u32 +
                                                                                          (uint32)(i_u16 * (uint16)FEE_PAGE_LEN));
                                Fee_GlobInfoLastRdHeader_ptr->FeeIndex_u16     = xCurrBlkHeader_st.FeeIndex_u16;
                                Fee_GlobInfoLastRdHeader_ptr->BlkStatus_u8     = xCurrBlkHeader_st.BlkStatus_u8;
                                Fee_GlobInfoLastRdHeader_ptr->BlkLength_u16    = xCurrBlkHeader_st.BlkLength_u16;
                                Fee_GlobInfoLastRdHeader_ptr->HdrCrc16_u16     = xCurrBlkHeader_st.HdrCrc16_u16;
                                Fee_GlobInfoLastRdHeader_ptr->BlkCrc32_u32     = xCurrBlkHeader_st.BlkCrc32_u32;
                                Fee_GlobInfoLastRdHeader_ptr->DataBytes_au8[0u]= xCurrBlkHeader_st.DataBytes_au8[0u];
                                Fee_GlobInfoLastRdHeader_ptr->DataBytes_au8[1u]= xCurrBlkHeader_st.DataBytes_au8[1u];

                                /* Check for an an init run because the special cache update without the evaluation
                                 * of the data checksum will be done in order to fasten up the system */
                                if(FastCacheUpdate_u8 == (uint8)FEE_UPDATE_CACHE_IN_INIT)
                                {
                                    /* Update the cache with the current header address */
                                    Fee_LLUpdateAddressInCache(Fee_GlobInfoLastRdHeader_ptr->FeeIndex_u16,
                                                               Fee_GlobInfoLastRdHeader_ptr->AdrBlkHeader_u32);
                                }

                                /* Finish the order */
                                xRetVal = FEE_ORDER_FINISHED_E;

                                /* Finish the loop */
                                break;
                            }
                        }
                    }
                    else
                    {
                        /* For controllers with no Cache init, the last programmed page is identified here during the Next Free page identification.
                         * Check if the page is blank or programmed by comparing against the erase pattern. */
                        #if(FEE_FAST_CACHE_INIT_ACTIVE == FALSE)
                        if (Fee_stMain == FEE_POLLING_MODE_E)
                        {
                            /* For faster operation, use 32 bytes compare. */
                            Fee_PageBytePtr_pu32 = (uint32*)Fee_PageBytePtr_cpu8;
                            local_loop_u8 = (i_u16 * (uint16)FEE_PAGE_LEN)/4u;
                            if((Fee_PageBytePtr_pu32[local_loop_u8] != FEE_ERASE_PATTERN_U32) ||
                               (Fee_PageBytePtr_pu32[(local_loop_u8 + 1u)] != FEE_ERASE_PATTERN_U32))
                            {
                                /* Page is not blank. Store the address of the page as last programmed page. */
                                Fee_RdWrOrder_st.LastProgrammedAddress_u32 = (uint32)(Fee_RdWrOrder_st.AdrHdSearchStart_u32 + (uint32)(i_u16 * (uint16)FEE_PAGE_LEN));
                            }
                            else
                            {
                                /* Page is blank. Continue to identify the last programmed page. */
                            }
                        }
                        else
                        {
                            /* Software is running in Normal mode. it is not required to identify the last programmed page. */
                        }
                        #endif

                        /* Page contains no block header (missing preamble)
                         * --> search within the next page that has already been loaded
                         *     or leave the loop in case this was a cached access */
                        if(CachedAccess_u8 == (uint8)FEE_USE_CACHED_ACCESS)
                        {
                            /* MR12 RULE 15.4 VIOLATION: Save time */
                            break;
                        }
                    }
                }


                #if (FEE_PRV_DEBUGGING != FALSE)
                Fee_Prv_stModuleTest_st.Fee_SearchNextBlockHeaderLoopRamDiff_u32 +=
                        MCU_RB_TIM0TICKS_TO_US(Mcu_Rb_GetSysTimePart(TIM0) - xTimeStart_u32);
                #endif


                /* Check whether a valid block header has been found or not */
                if (xRetVal != FEE_ORDER_FINISHED_E)
                {
                    /* A complete page buffer (or a some pages only in case of a cached access)
                     * contain(s) no valid block header. The start address
                     * for this search was either the sector beginning or a pointer out of
                     * the last valid block header (or the address out of the cache). */

                    /* No abortion, go on until the end of the sector is reached unless it
                     * was a cached access */
                    if(CachedAccess_u8 == (uint8)FEE_USE_MANUAL_ACCESS)
                    {
                        /* No valid block header was found, increment address for next search. */

                        /* Set the read address for the next page buffer reload by the Fls right
                         * behind the end of the last loaded address area -1 page
                         * (The last page of the buffer was not evaluated because only complete
                         *  block headers can be checked (14 bytes)
                         *  --> do not skip this page but force a check).
                         * Ensure page alignment and keep the address within the current sector
                         * If the end of the sector is reached, the function will restrict the
                         * read address to the sector end address which will lead to a sector
                         * full return in the init read state */

                        Fee_IncAddressInsideSector(&Fee_RdWrOrder_st.xRdAddress,
                                                   (uint16)(((Fee_RdWrOrder_st.AdrHdSearchStart_u32 +
                                                              (uint32)FEE_LL_PAGEBUFFSIZE) -
                                                             Fee_RdWrOrder_st.xRdAddress) -
                                                            (uint32)xLoopReduction_u8),
                                                   TRUE);

                        /* Reset state machine */
                        Fee_RdWrOrder_st.Fee_LLRdState_en = FEE_LL_INIT_READ_E;
                    }
                    else
                    {
                        /* Cache address is not correct */
                        xRetVal = FEE_ERROR_E;
                    }
                }
                #if (FEE_HEADER_RECHECK_ACTIVE != FALSE)
                /* The NoFallback feature can be activated only if header recheck is activated */
                else
                {
                    /* If the function is called during init additional checks are skipped */
                    if (FastCacheUpdate_u8 != (uint8)FEE_UPDATE_CACHE_IN_INIT)
                    {
                        #if (FEE_NO_FALLBACK_ACTIVE != FALSE)
                        /* A valid block header has been found
                         * --> check if the block is configured as NoFallback */
                        if ((Fee_GlobInfoLastRdHeader_ptr->BlkStatus_u8 & (uint8)FEE_FLAG_NOFALLBACK_MSK) > 0)
                        {
                            /* The block shall be considered only if the NoFallback marker is not written
                             -> perform a pattern check of the NoFallBack marker */
                            Fee_RdWrOrder_st.Fee_LLRdState_en = FEE_LL_NOFALLBACK_MARKER_PATTERN_READ_E;
                        }
                        else
                        #endif
                        {
                            Fee_RdWrOrder_st.Fee_LLRdState_en = FEE_LL_RECHECK_HEADER_E;
                        }

                        /* Store the block header's start address separately since it is not part of the local structure */
                        xBlkHeaderAdr_u32 = Fee_GlobInfoLastRdHeader_ptr->AdrBlkHeader_u32;

                        /* The order is finished only if the NoFallback marker has been checked */
                        xRetVal = FEE_ORDER_PENDING_E;
                    }
                }
                #endif
            }
            break;

            #if (FEE_HEADER_RECHECK_ACTIVE != FALSE)
            #if (FEE_NO_FALLBACK_ACTIVE != FALSE)
            /*************************************************************************************
             * only available if FEE_HEADER_RECHECK_ACTIVE && FEE_NO_FALLBACK_ACTIVE
             * NoFallback can only be activated, if blank check is meaningful (RECHECK_ACTIVE)
             * read the NoFallback marker
             *************************************************************************************/
            case FEE_LL_NOFALLBACK_MARKER_PATTERN_READ_E:
            {
                /* for safety reasons, before reading the NoFallback marker initialize the noFBPatternBfr_au8
                 * to ensure not accessing old data
                 * After read, erase pattern or NoFallback pattern is expected,
                 * so initialize the buffer with the inverse erase pattern */
                Fee_SrvMemSet8(noFBPatternBfr_au8, (uint8)~FEE_ERASE_PATTERN, (uint32)FEE_PAGE_LEN);

                /* It is ensured during write,
                 * that the noFB marker has a valid address and is not overlapping into another sector
                   -> it is not required to check if the address is valid */
                if(E_NOT_OK != Fls_Read(xBlkHeaderAdr_u32 - FEE_PAGE_LEN, noFBPatternBfr_au8, FEE_PAGE_LEN))
                {
                    /* Set next state */
                    Fee_RdWrOrder_st.Fee_LLRdState_en = FEE_LL_NOFALLBACK_MARKER_PATTERN_READ_WAIT_E;
                }
                else
                {
                    /* Fls did not accept the order due to wrong parameters or an internal busy state.
                     * Reset the state machine */
                    xRetVal = FEE_ABORTED_E;
                }
            }
            break;

            /*************************************************************************************
             * only available if FEE_HEADER_RECHECK_ACTIVE && FEE_NO_FALLBACK_ACTIVE
             * NoFallback can only be activated, if blank check is meaningful (RECHECK_ACTIVE)
             * state to check the noFallBack pattern
             *************************************************************************************/
            case FEE_LL_NOFALLBACK_MARKER_PATTERN_CHECK_E:
            {
                boolean isNoFBPattern_b;
                uint8  const * copyBfr_pcu8;
                uint8  const * noFBPatternBfr_pcu8;
                uint32 i_u32;

                /* compare content of copy bytewise with the noFallBack pattern */
                copyBfr_pcu8 = noFBPatternBfr_au8;
                noFBPatternBfr_pcu8 = Fee_NoFallbackMarkerPattern;
                isNoFBPattern_b = TRUE;

                for(i_u32 = 0uL; (i_u32 < FEE_PAGE_LEN) && (isNoFBPattern_b); i_u32++)
                {
                    if((*copyBfr_pcu8) != (*noFBPatternBfr_pcu8))
                    {
                        isNoFBPattern_b = FALSE;
                    }
                    copyBfr_pcu8++;
                    noFBPatternBfr_pcu8++;
                }

                if(isNoFBPattern_b)
                {
                    /* noFallBack marker page contains the noFallback pattern */

                    /* perform a blank check over the NoFallBack marker area
                       marker area is blank && noFallback pattern -> pattern is irrelevant, copy is valid
                       marker area is not blank && noFallback pattern -> copy is invalidated */
                    Fee_RdWrOrder_st.Fee_LLRdState_en = FEE_LL_NOFALLBACK_MARKER_BLANK_CHECK_E;
                    xRetVal = FEE_ORDER_PENDING_E;
                }
                else
                {
                    /* noFallBack marker page does not contain the noFallback pattern */
                     /* -> copy is not invalidated and could be used */

                    /* perform next step to check if the block is fully programmed */
                    Fee_RdWrOrder_st.Fee_LLRdState_en = FEE_LL_RECHECK_HEADER_E;
                    xRetVal = FEE_ORDER_PENDING_E;
                }
            }
            break;

            /*************************************************************************************
             * only available if FEE_HEADER_RECHECK_ACTIVE && FEE_NO_FALLBACK_ACTIVE
             * NoFallback can only be activated, if blank check is meaningful (RECHECK_ACTIVE)
             * blank check NoFallback page
             *************************************************************************************/
            case FEE_LL_NOFALLBACK_MARKER_BLANK_CHECK_E:
            {
                /* It is ensured during write,
                 * that the noFB marker has a valid address and is not overlapping into another sector
                   -> it is not required to check if the address is valid */
                if (Fls_BlankCheck(xBlkHeaderAdr_u32 - FEE_PAGE_LEN, FEE_PAGE_LEN) != E_NOT_OK)
                {
                    /* Set the next state */
                    Fee_RdWrOrder_st.Fee_LLRdState_en = FEE_LL_NOFALLBACK_MARKER_BLANK_CHECK_WAIT_E;

                    /* if NoFallback marker area is blank
                         -> state is switched to FEE_LL_RECHECK_HEADER_E
                       if NoFallback marker area is not blank
                         -> state is switched to FEE_LL_NOFALLBACK_MARKER_BLANK_CHECK_FAILED_E */
                }
                else
                {
                    /* Fls did not accept the order due to wrong parameters or an internal busy state.
                     * Reset the state machine */
                    xRetVal = FEE_ABORTED_E;
                }
            }
            break;

            /* FEE_NO_FALLBACK_ACTIVE != FALSE */
            #endif

            /*************************************************************************************
             * only available if FEE_HEADER_RECHECK_ACTIVE
             * header blank check
             *************************************************************************************/
            case FEE_LL_RECHECK_HEADER_E:
            {
                /* Call the blank check function */
                if (Fls_BlankCheck(xBlkHeaderAdr_u32 + ((FEE_PAGES_USED_BY_BLK_HEADER * FEE_PAGE_LEN) - FEE_PHY_PAGE_LEN),
                                      FEE_PHY_PAGE_LEN) != E_NOT_OK)
                {
                    /* Set the next state */
                    Fee_RdWrOrder_st.Fee_LLRdState_en = FEE_LL_RECHECK_HEADER_WAIT_E;
                }
                else
                {
                    /* Fls did not accept the order due to wrong parameters or an internal busy state.
                     * Reset the state machine */
                    xRetVal = FEE_ABORTED_E;
                }
            }
            break;

            /* Wait for the blank check to be finished */
            case FEE_LL_RECHECK_HEADER_WAIT_E:
            #if (FEE_NO_FALLBACK_ACTIVE != FALSE)
            case FEE_LL_NOFALLBACK_MARKER_BLANK_CHECK_WAIT_E:
            case FEE_LL_NOFALLBACK_MARKER_PATTERN_READ_WAIT_E:
            #endif
            {
                /* The next state will be set by the Fee_JobEndNotification() or Fee_JobErrorNotification() function automatically */

                /* Check whether the OS is currently running or not */
                if (Fee_stMain == FEE_POLLING_MODE_E)
                {
                    /* Call the Fls main function manually */
                    Fls_MainFunction();
                }

                #if (STD_ON == FEE_POLLING_MODE)
                /* Use the FLS polling mechanism in order to reach the next state */
                Fee_CheckFlsJobResult();
                #endif
            }
            break;

            /* Reading of the block is allowed since
             * - the NoFallback marker for NoFallback blocks is not programmed
             * - the block header is fully programmed */
            case FEE_LL_RECHECK_HEADER_FINISHED_E:
            {
                /* Store the block header information to the global info structure */
                Fee_GlobInfoLastRdHeader_ptr->AdrBlkHeader_u32 = xBlkHeaderAdr_u32;
                Fee_GlobInfoLastRdHeader_ptr->FeeIndex_u16     = xCurrBlkHeader_st.FeeIndex_u16;
                Fee_GlobInfoLastRdHeader_ptr->BlkStatus_u8     = xCurrBlkHeader_st.BlkStatus_u8;
                Fee_GlobInfoLastRdHeader_ptr->BlkLength_u16    = xCurrBlkHeader_st.BlkLength_u16;
                Fee_GlobInfoLastRdHeader_ptr->HdrCrc16_u16     = xCurrBlkHeader_st.HdrCrc16_u16;
                Fee_GlobInfoLastRdHeader_ptr->BlkCrc32_u32     = xCurrBlkHeader_st.BlkCrc32_u32;
                Fee_GlobInfoLastRdHeader_ptr->DataBytes_au8[0u]    = xCurrBlkHeader_st.DataBytes_au8[0u];
                Fee_GlobInfoLastRdHeader_ptr->DataBytes_au8[1u]    = xCurrBlkHeader_st.DataBytes_au8[1u];

                /* Finish the order */
                xRetVal = FEE_ORDER_FINISHED_E;
            }
            break;

            /* If the NoFallback marker area is not blank reading of the block is not allowed */
            case FEE_LL_RECHECK_HEADER_FAILED_E:
            #if (FEE_NO_FALLBACK_ACTIVE != FALSE)
            case FEE_LL_NOFALLBACK_MARKER_BLANK_CHECK_FAILED_E:
            #endif
            {
                if (CachedAccess_u8 == (uint8)FEE_USE_MANUAL_ACCESS)
                {
                    /* Update the read address to the last found block header */
                    Fee_RdWrOrder_st.xRdAddress = xBlkHeaderAdr_u32;

                    /* Increment the read address page wise ("safety mode") and search for the next
                     * block header until the end of the page buffer */
                    Fee_IncAddressInsideSector(&Fee_RdWrOrder_st.xRdAddress, FEE_PAGE_LEN, TRUE);

                    /* Reset the state machine and continue the search */
                    Fee_RdWrOrder_st.Fee_LLRdState_en = FEE_LL_INIT_READ_E;
                }
                else
                {
                    /* Cache address is not correct */
                    xRetVal = FEE_ERROR_E;
                }
            }
            break;
            /* FEE_HEADER_RECHECK_ACTIVE != FALSE */
            #endif

            /* Default case should never be reached */
            default:
            {
                /* Set error state */
                xRetVal = FEE_ERROR_E;

                /* No valid block header found yet, reset the state machine */
                Fee_RdWrOrder_st.Fee_LLRdState_en = FEE_LL_INIT_READ_E;
            }
            break;
        }
    }
    while((xRetVal == FEE_ORDER_PENDING_E) && (Fee_stMain == FEE_POLLING_MODE_E));

    /* Check if the search was aborted or the sector is full */
    if (xRetVal != FEE_ORDER_PENDING_E)
    {
        /* No valid block header found yet, reset the state machine */
        Fee_RdWrOrder_st.Fee_LLRdState_en = FEE_LL_INIT_READ_E;

        /* Reset the loop reduction counter */
        xLoopReduction_u8 = 0u;

        /* Reset retry counter */
        xCntRetry_u8 = (uint8)FEE_MAX_RD_WR_COMP_RETRIES;
    }

    return(xRetVal);
}


/**
 *********************************************************************
 * Fee_LLGetSecStartAddress(): Return sector start address
 *
 * This function returns the start address of the requested sector.
 *
 * Hint: It might be necessary to return the address of the first
 *       block header within the requested sector in the future.
 *       In this case this address might be read out of a new sector
 *       header.
 *
 * \param    xPhySectorIdx_u8:  Active sector index
 * \return
 * \retval   0...4294967295:    Start address of the first page
 *                              of the active sector
 * \seealso
 * \usedresources
 *********************************************************************
 */
uint32 Fee_LLGetSecStartAddress(uint8 xPhySectorIdx_u8)
{
    /* Access flash property table */
    return(Fee_FlashProp_st[xPhySectorIdx_u8].Fee_LogStartAddress_u32);
}


/**
 *********************************************************************
 * Fee_LLGetSecEndAddress(): Return sector end address
 *
 * This function returns the end address of the requested sector.
 *
 *
 * \param    xPhySectorIdx_u8:  Active sector index
 * \return
 * \retval   0...4294967295:    End address of the sector
 * \seealso
 * \usedresources
 *********************************************************************
 */
uint32 Fee_LLGetSecEndAddress(uint8 xPhySectorIdx_u8)
{
    /* Access flash property table */
    return(Fee_FlashProp_st[xPhySectorIdx_u8].Fee_LogEndAddress_u32);
}


/**
 *********************************************************************
 * Fee_LLGetAddressFromCache(): Find address in flash
 *
 * This functions returns the address of the corresponding block
 * header.
 *
 * \param    FeeIdx_u16:    Fee index (block persistent ID)
 * \return
 * \retval   addr_u32:      Address in flash if persistent ID is
 *                          configured
 * \retval   FEE_CACHE_INIT_VALUE: block is not configured
 * \retval   FEE_CACHE_TMP_INVALID_VALUE: block is configured but
 *                          address within cache is not valid
 * \seealso
 * \usedresources
 *********************************************************************
 */
uint32 Fee_LLGetAddressFromCache(uint16 FeeIdx_u16)
{
    uint16 xCacheIdx_u16;                   /* Cache index */
    uint32 addr_u32 = FEE_CACHE_INIT_VALUE; /* Return value */

    /* Check if the index can be found */
    if(Fee_SrvBinarySearchInBlockProp(FeeIdx_u16, &xCacheIdx_u16) != FALSE)
    {
        /* Set return value */
        addr_u32 = Fee_Cache_au32[xCacheIdx_u16];
    }

    /* Check if the cache entry is within any of the configured sectors */
    if(Fee_LLCheckAddressInCache(addr_u32) == FALSE)
    {
        /* Return the temp init value */
        addr_u32 = FEE_CACHE_TMP_INVALID_VALUE;
    }

    /* Return the block address */
    return (addr_u32);
}


/**
 *********************************************************************
 * Fee_LLCheckHdAddressInCache(): Validate the cache address
 *
 * This functions checks if a header address is within any of the
 * configured flash sectors.
 *
 * \param    AdrInSector_u32:   Address to check
 * \return
 * \retval   TRUE:              Address is valid
 * \retval   FALSE:             Address is invalid
 * \seealso
 * \usedresources
 *********************************************************************
 */
/* MR12 RULE 1505 VIOLATION: This function is used within the same file and has no external linkage */
boolean Fee_LLCheckAddressInCache(uint32 AdrInSector_u32)
{
    boolean xRetVal_b = FALSE;      /* Default return value */
    uint8   xPhySecIdx_u8;          /* Loop counter */
    uint8   xLogSecIdx_u8;          /* Logical sector index */

    /* Check for the cache init value or the temp init value first */
    if((AdrInSector_u32 != FEE_CACHE_INIT_VALUE) &&
       (AdrInSector_u32 != FEE_CACHE_TMP_INVALID_VALUE))
    {
        /* Loop over all configured flash banks */
        for(xPhySecIdx_u8=0; xPhySecIdx_u8<FEE_NUM_FLASH_BANKS; xPhySecIdx_u8++)
        {
            uint32 secStartAddr_u32 , secEndAddr_u32;
            /* Check if the address is within one of the configured sectors.
             * Low check:   logical sector start address
             * Upper check: logical sector end address - block header size */

            secStartAddr_u32 = Fee_LLGetSecStartAddress(xPhySecIdx_u8);
            secEndAddr_u32   = Fee_LLGetSecEndAddress(xPhySecIdx_u8);

            /* MR12 RULE 13.5 VIOLATION: Both upper and lower boundary checks are required. */
            if((secStartAddr_u32 <= AdrInSector_u32) &&
               (((secEndAddr_u32 + 1uL) - (FEE_PAGES_USED_BY_BLK_HEADER * FEE_PAGE_LEN)) >= AdrInSector_u32))
            {
                    /* Get the respective logical sector index */
                    xLogSecIdx_u8 = Fee_idxLLSectorOrder_au8[xPhySecIdx_u8];

                    /* Cross check the sector state */
                    if((Fee_LLSectorOrder_st[xLogSecIdx_u8].SecState_en == FEE_SECTOR_USED_E) ||
                       (Fee_LLSectorOrder_st[xLogSecIdx_u8].SecState_en == FEE_SECTOR_FULL_E))
                    {
                        /* Address successfully verified */
                        xRetVal_b = TRUE;
                    }

                    /* Exit loop */
                    break;
               }
        }
    }
    else
    {
        /* Defined values are allowed */
        xRetVal_b = TRUE;
    }

    /* Function return */
    return (xRetVal_b);
}


/**
 *********************************************************************
 * Fee_LLUpdateCacheStForSect(): Indicate a physical sector as
 *                                checked (cache update complete)
 *
 * This function updates the respective physical sector as completed
 * with respect to the cache entries.
 *
 * \param    PhySecIdx_u8:  Physical sector index
 * \return
 * \retval   none
 * \seealso
 * \usedresources
 *********************************************************************
 */
void Fee_LLUpdateCacheStForSect(uint8 PhySecIdx_u8)
{
    /* Update the array indicator for a completed cache update for one sector */
    Fee_CacheUpdCompForSect_au8[PhySecIdx_u8] = FEE_CACHE_UPD_COMP_FOR_SECT;
}

/**
 *********************************************************************
 * Fee_LLEraseCacheStForSect():  Erase checked indication for the
 *                               cache status
 *
 * This function erases the checked indication of the respective
 * physical sector.
 *
 * \param    PhySecIdx_u8:  Physical sector index
 * \return
 * \retval   none
 * \seealso
 * \usedresources
 *********************************************************************
 */
void Fee_LLEraseCacheStForSect(uint8 PhySecIdx_u8)
{
    /* Update the array indicator for a completed cache update for one sector */
    Fee_CacheUpdCompForSect_au8[PhySecIdx_u8] = FEE_CACHE_UPD_NOT_COMP_FOR_SECT;
}


/**
 *********************************************************************
 * Fee_LLGetCacheUpdateStForAllSect(): Get the status summary of the
 *                                     cache updates of all sectors
 *
 * This function returns whether a all relevant sectors have been
 * used for updating the cache or not. Currently relevant are only
 * USED or FULL sectors.
 *
 * \param    none
 * \return   Cache update status
 * \retval   FEE_CACHE_UPD_COMP_FOR_ALL_SECT: All sectors have been
 *                                            checked
 * \retval   FEE_CACHE_UPD_NOT_COMP_FOR_SECT: At least one sector was
 *                                            not checked
 *
 * \seealso
 * \usedresources
 *********************************************************************
 */
uint8 Fee_LLGetCacheUpdateStForAllSect(void)
{
    uint8  xFuncRet_u8 = FEE_CACHE_UPD_COMP_FOR_ALL_SECT;
    uint8  xLogSecIdx_u8;               /* Logical sector index */
    uint8  xPhySecIdx_u8;               /* Physical sector index */

    /* Loop over all sectors */
    for(xPhySecIdx_u8=0; xPhySecIdx_u8<FEE_NUM_FLASH_BANKS; xPhySecIdx_u8++)
    {
        /* Get the corresponding logical sector index */
        xLogSecIdx_u8 = Fee_idxLLSectorOrder_au8[xPhySecIdx_u8];

        /* Check if all relevant sectors have been checked so far */
        /* MR12 RULE 13.5 VIOLATION: Checking state of cache for the sector required only for sectors that are in USED or FULL state. */
        if(((Fee_LLSectorOrder_st[xLogSecIdx_u8].SecState_en == FEE_SECTOR_USED_E) ||
            (Fee_LLSectorOrder_st[xLogSecIdx_u8].SecState_en == FEE_SECTOR_FULL_E)) &&
           (Fee_LLGetCacheUpdateStForSect(xPhySecIdx_u8) != FEE_CACHE_UPD_COMP_FOR_SECT))
        {
            xFuncRet_u8 = FEE_CACHE_UPD_NOT_COMP_FOR_SECT;
        }
    }

    return xFuncRet_u8;
}


/**
 *********************************************************************
 * Fee_LLUpdateAddressInCache(): Update the address within the cache
 *
 * This functions updates the address of the corresponding block
 * in the cache.
 *
 * \param    FeeIdx_u16:    Fee index (block persistent ID)
 * \param    Addr_u32:      Address in flash
 * \return
 * \retval   none
 * \seealso
 * \usedresources
 *********************************************************************
 */
void Fee_LLUpdateAddressInCache(uint16 FeeIdx_u16,
                                                uint32 Addr_u32)
{
    uint16 xCacheIdx_u16;   /* Cache index */

    /* Check if the index can be found */
    if(Fee_SrvBinarySearchInBlockProp(FeeIdx_u16, &xCacheIdx_u16) != FALSE)
    {
        /* Update the address within the cache */
        Fee_Cache_au32[xCacheIdx_u16] = Addr_u32;
    }
}


/**
 *********************************************************************
 * Fee_LLGetCacheUpdateStForSect(): Get the status of the cache update
 *                                  of the respective sector
 *
 * This function returns whether a complete search through the
 * respective sector in combination with a cache update has already
 * been performed or not.
 *
 * \param    PhySecIdx_u8:  Physical sector index
 * \return   Cache update status for the physical sector
 * \retval   FEE_CACHE_UPD_COMP_FOR_SECT:     The respective sector was
 *                                            checked completely
 * \retval   FEE_CACHE_UPD_NOT_COMP_FOR_SECT: The respective sector was
 *                                            not completely checked
 * \seealso
 * \usedresources
 *********************************************************************
 */
/* MR12 RULE 1505 VIOLATION: This function is used within the same file and has no external linkage */
uint8 Fee_LLGetCacheUpdateStForSect(uint8 PhySecIdx_u8)
{
    /* Return the status of the physical sector */
    return Fee_CacheUpdCompForSect_au8[PhySecIdx_u8];
}


/* Macro implementation for an invalidation of the cache can be found in Fee_Prv.h:
 * #define Fee_LLInvalidateAddressInCache(FEEIDX)   Fee_LLUpdateAddressInCache(FEEIDX, FEE_CACHE_INIT_VALUE) */


#if(FEE_FAST_CACHE_INIT_ACTIVE != FALSE)
/**
 *********************************************************************
 * Fee_BuildUpCache(): Build up the cache for the passed address area
 *
 * This function builds up the cache for the address area passed
 * by the user. The block checksum can be regarded if necessary.
 * The function can execute one sector without returning in case
 * this is necessary (e.g. during the ECU init).
 *
 * \param    StartAdr_u32:      Start address for the search
 * \param    EndAdr_u32:        End address for the search
 *
 * \return
 * \retval   FEE_ORDER_PENDING_E:   Order is pending
 * \retval   FEE_ABORTED_E:         Order was aborted
 * \retval   FEE_SECTORFULL_E:      The end address of the sector
 *                                  was reached
 * \seealso
 * \usedresources
 *********************************************************************
 */
/* MR12 RULE 1505 VIOLATION: This function is used within the same file and has no external linkage */
Fee_stRetVal_ten Fee_BuildUpCache(uint32 StartAdr_u32,
                                                  uint32 EndAdr_u32)
{
    uint8 xLogSecIdx_u8;                        /* Index of logical sector */
    uint8 xPhySecIdx_u8;                        /* Index of physical sector */
    uint16 xCalcCrc_u16;                        /* Header checksum */
    Fee_BlkHeader_tst xCurrBlkHeader_st;        /* Block header structure */
    uint32 xRdAdr_u32;                          /* Address for reading */
    uint32 xRdAdrEnd_u32;                       /* End address for reading */
    uint16 xBlockPropIdx_u16;                   /* Block index */
    uint16 xCacheIdx_u16 = 0;                       /* Cache index */
    uint32 xAdrBlkHeaderTmp_u32;                /* Temporary block header address */
    uint32 xDataBuf_au32[(FEE_PAGES_USED_BY_BLK_HEADER*FEE_PAGE_LEN)/4u];    /* Data buffer */
    Fee_stRetVal_ten xRetVal = FEE_ORDER_PENDING_E;  /* Function return */
   #if (FALSE == FEE_HEADER_RECHECK_ACTIVE)  /* Local varaibles are used to save computation time. */
   uint8 xActivateLastPgmSearch_u8 = 0;            /* Flag to indicate if searching of last programmed page must be done for the sector or not. */
   uint32 xLastProgrammedAddress_u32 = FEE_NULL;     /* Local variable to store the address of the last programmeed page. */
   uint32 xLastValidHeader_u32 = FEE_NULL;         /* Local variable to store the address of the last valid header. */
   #else
    uint32 const xHdrCutOff_cu32 = (FEE_PAGE_LEN * (FEE_PAGES_USED_BY_BLK_HEADER - 1u)); /* Possible cutoff before write address where no valid header can be located */
   #endif

    static uint32 xRdAdrContinue_u32;           /* Address to continue the reading */
    static uint32 xRdAdrEndContinue_u32;        /* End address for the search */

    /* Loop if polling mode is active and function state is pending */
    do
    {
        /* Switch over state machine */
        switch (Fee_RdWrOrder_st.Fee_LLBuildUpCache_en)
        {
            /* Init state */
            case FEE_LL_BLD_UP_CACHE_INIT_E:
            {
                /* Get the corresponding sector indexes */
                xPhySecIdx_u8 = Fee_GetPhysSectorByAddress(StartAdr_u32);
                xLogSecIdx_u8 = Fee_idxLLSectorOrder_au8[xPhySecIdx_u8];

                /* Loop over all configured blocks */
                for(xBlockPropIdx_u16=0; xBlockPropIdx_u16<FEE_NUM_BLOCKS; xBlockPropIdx_u16++)
                {
                    /* Check the address range */
                    if((Fee_Cache_au32[xBlockPropIdx_u16] >= Fee_FlashProp_st[xPhySecIdx_u8].Fee_LogStartAddress_u32) &&
                       (Fee_Cache_au32[xBlockPropIdx_u16] <= Fee_FlashProp_st[xPhySecIdx_u8].Fee_LogEndAddress_u32))
                    {
                        /* Clean all cache entries referring to this sector */
                        Fee_LLInvalidateAddressInCache(xBlockPropIdx_u16);
                    }
                }

                /* Check if building up the cache is necessary */
                if((Fee_LLSectorOrder_st[xLogSecIdx_u8].SecState_en == FEE_SECTOR_USED_E) ||
                   (Fee_LLSectorOrder_st[xLogSecIdx_u8].SecState_en == FEE_SECTOR_FULL_E))
                {
                    /* Read out the data */
                    Fee_RdWrOrder_st.Fee_LLBuildUpCache_en = FEE_LL_BLD_UP_CACHE_READ_E;

                    /* Copy the user's start and end addresses */
                    xRdAdrContinue_u32      = StartAdr_u32;
                    xRdAdrEnd_u32           = xRdAdrContinue_u32;
                    xRdAdrEndContinue_u32   = xRdAdrEnd_u32;

                    /* Update the cache status for the current sector  */
                    Fee_LLUpdateCacheStForSect(xPhySecIdx_u8);

                    #if (FEE_PRV_DEBUGGING != FALSE)
                    Fee_Prv_stModuleTest_st.Fee_CacheCntSect_u8++;
                    Fee_Prv_stModuleTest_st.BuildUpCacheStart_u32 = Mcu_Rb_GetSysTimePart(TIM0);
                    #endif

                    #if (FALSE == FEE_HEADER_RECHECK_ACTIVE)
                    /* Initialise the flag and address variables. */
                    xActivateLastPgmSearch_u8 = 0;
                    xLastProgrammedAddress_u32 = FEE_NULL;
                    xLastValidHeader_u32 = FEE_NULL;

                    /* Check for last programmed page only for most active sector i.e., sector state = FEE_SECTOR_USED_E. */
                    if (Fee_LLSectorOrder_st[xLogSecIdx_u8].SecState_en == FEE_SECTOR_USED_E)
                    {
                        /* Set the flag to activate the check of last programmed page. */
                        xActivateLastPgmSearch_u8 = 1;
                    }
                    else
                    {
                        /* Identification of last programmed header and page is required only for the lastest valid sector i.e., sector with USED state.
                         * Do nothing for all other sectors. */
                    }
                    #endif
                }
                else
                {
                    /* Set return value */
                    xRetVal = FEE_ABORTED_E;

                    break;
                }
            }
            /* No break to save time */

            /* Read out data */
            /* MR12 RULE 16.3 VIOLATION: Time critical position */
            case FEE_LL_BLD_UP_CACHE_READ_E:
            {
                /* Get the addresses for reading the data
                 * (use locals for faster access) */
                xRdAdr_u32      = xRdAdrContinue_u32;
                xRdAdrEnd_u32   = xRdAdrEndContinue_u32;

                /* Check if the end address for the search is already reached
                 * because of jumps after the checksum verification */
                if(xRdAdr_u32 >= Fee_LLGetSecEndAddress(Fee_GetPhysSectorByAddress(xRdAdr_u32)))
                {
                    /* Finish the order */
                    xRetVal = FEE_SECTORFULL_E;

                    break;
                }

                /* Set the end address for the search depending on the mode
                 * --> Use the fast mode during the init phase */
                if(Fee_Prv_stInit_u8 != FEE_PRV_ST_INIT_DONE)
                {
                    #if  (TRUE == FEE_HEADER_RECHECK_ACTIVE)
                    uint8 endAddrSector_u8 , wrAddrSector_u8;

                    endAddrSector_u8 = Fee_GetPhysSectorByAddress(EndAdr_u32);
                    wrAddrSector_u8  = Fee_GetPhysSectorByAddress(Fee_RdWrOrder_st.xWrAddress);

                    /* Check if the users end address exceeds the current write address */
                    if((EndAdr_u32 >= Fee_RdWrOrder_st.xWrAddress) &&
                       (endAddrSector_u8 == wrAddrSector_u8))
                    {
                        if(Fee_RdWrOrder_st.xWrAddress <= (Fee_LLGetSecStartAddress(Fee_GetPhysSectorByAddress(Fee_RdWrOrder_st.xWrAddress)) + xHdrCutOff_cu32))
                        {
                            /*
                             * Two cases are possible:
                             * 1. Only the USED marker is available but no data!
                             * 2. Only a partial programmed header page is available
                             * In both the cases it cannot be a valid block which shall be put into the cache.
                             */
                            xRetVal = FEE_SECTORFULL_E;
                            break;
                        }
                        else
                        {
                            /*
                             * Write address before or equal to sector end - limit scan to write address
                             * Even if the last page before the write address contains a valid preamble it cannot be a valid header.
                             * At the very last part before the write address (xHdrCutOff) there can be no valid header anymore.
                             * Do not check this in order to avoid reading of erased area (see below do while abort condition).
                             */
                            xRdAdrEnd_u32 = (Fee_RdWrOrder_st.xWrAddress - xHdrCutOff_cu32);
                        }
                    }
                    else
                    #endif
                    {
                        /* Take over the users end address */
                        xRdAdrEnd_u32 = EndAdr_u32;
                    }
                }
                else
                {
                    /* Do the read out DataBuf size wise */

                    /* Check if an increase of the end address is necessary again */
                    if(xRdAdr_u32 == xRdAdrEnd_u32)
                    {
                        /* Reset the current loop end */
                        Fee_IncAddressInsideSector(&xRdAdrEnd_u32, FEE_LL_DATABUFFSIZE, TRUE);

                        /* Check if the user's end address is exceeded */
                        if(xRdAdrEnd_u32 > EndAdr_u32)
                        {
                            /* Restrict the end address */
                            xRdAdrEnd_u32 = EndAdr_u32;
                        }
                    }
                }

                /* Loop until the end address is reached */
                do
                {
                    /* Read out the preamble and the block status directly */

#if defined(RBA_FLSVECU_FLASH)
                    xDataBuf_au32[0] = rba_FlsVecu_MemRead32_Macro(xRdAdr_u32);
#else
                    /* MISRA RULE 11.3 VIOLATION: Cast is necessary and not critical */
                    (void)Fee_Fls_SyncRead(xRdAdr_u32, (uint8*)&xDataBuf_au32[0], (Fls_LengthType)4U);
#endif

                    /*
                     * Header overview:
                     *  +----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+
                     *  |            Preamble            |Blk Status|       FeeIndex      |     Block length    |     Header CRC16    |
                     *  +----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+
                     *  Preamble   : 0xA53C96 fix pattern
                     *  Blk Status : Contains information like security level, etc.
                     *  FeeIndex   : Block index
                     *  Block length: Block length without the header length
                     *  Header CRC16: CRC16 checksum over Preamble, Blk Status, Fee Index and Block length.
                     *                The start value is FEE_MARKER_PATTERN (0xCAFE)
                     *
                     *  Hint: A block header will always start at the beginning of a page.
                     */

                    /* Compare the preamble of the block header byte - wise */
                    /* MR12 RULE 11.3 VIOLATION: Cast is necessary and not critical */
                    if ((((Fee_BlkHeader_tst*)(&xDataBuf_au32[0]))->Preamble_au8[2] == (uint8)FEE_BLK_HEADER_PREAMBEL_BYTE_2) &&
                        /* MR12 RULE 11.3 VIOLATION: Cast is necessary and not critical */
                        (((Fee_BlkHeader_tst*)(&xDataBuf_au32[0]))->Preamble_au8[1] == (uint8)FEE_BLK_HEADER_PREAMBEL_BYTE_1) &&
                        /* MR12 RULE 11.3 VIOLATION: Cast is necessary and not critical */
                        (((Fee_BlkHeader_tst*)(&xDataBuf_au32[0]))->Preamble_au8[0] == (uint8)FEE_BLK_HEADER_PREAMBEL_BYTE_0) &&
                        /* Fix for Defect 133411 Possible trap when data matches to preamble value */
                        (xRdAdr_u32 <= ((EndAdr_u32 + 1u) - (FEE_PAGES_USED_BY_BLK_HEADER * FEE_PAGE_LEN))))
                    {

                        /* Load the last programmed page for controllers other then R1x, P1x and RH850xx. */
                        #if (FALSE == FEE_HEADER_RECHECK_ACTIVE)
                        if (xActivateLastPgmSearch_u8 == 1)
                        {
                            xLastProgrammedAddress_u32 = xRdAdr_u32;
                        }
                        else
                        {
                            /* Identification of last programmed header and page is required only for the lastest valid sector i.e., sector with USED state.
                             * Do nothing for all other sectors. */
                        }
                        #endif

                        /* Save the start address for updating the cache */
                        xAdrBlkHeaderTmp_u32 = xRdAdr_u32;

                        /* Read out the block index and the block length */
                        Fee_IncAddressInsideSector(&xRdAdr_u32 , 4u , FALSE);

#if defined(RBA_FLSVECU_FLASH)
                        xDataBuf_au32[1] = rba_FlsVecu_MemRead32_Macro(xRdAdr_u32);
#else
                        /* MISRA RULE 11.3 VIOLATION: Cast is necessary and not critical */
                        (void)Fee_Fls_SyncRead(xRdAdr_u32, (uint8*)&xDataBuf_au32[1], (Fls_LengthType)4U);
#endif

                        /* Read out the header CRC and parts of the block CRC */
                        Fee_IncAddressInsideSector(&xRdAdr_u32 , 4u , FALSE);



#if defined(RBA_FLSVECU_FLASH)
                        xDataBuf_au32[2] = rba_FlsVecu_MemRead32_Macro(xRdAdr_u32);
#else
                        /* MISRA RULE 11.3 VIOLATION: Cast is necessary and not critical */
                        (void)Fee_Fls_SyncRead(xRdAdr_u32, (uint8*)&xDataBuf_au32[2], (Fls_LengthType)4U);
#endif

                        /* Read BIT7 and check if the block shall be considered or not.
                        * If this bit is set the block was written in plant and must be ignored from application. */

                        /* MR12 RULE 11.3 VIOLATION: Cast is necessary and not critical */
                        if((((Fee_BlkHeader_tst*)(&xDataBuf_au32[0]))->BlkStatus_u8 & FEE_MASK_BIT7) == 0u)
                        {
                            /* Check the block header CRC */
                            /* MR12 RULE 11.3 VIOLATION: Cast is necessary and not critical */
                            xCalcCrc_u16 = Crc_CalculateCRC16((uint8*)&xDataBuf_au32[0],
                                                              (uint32)(FEE_BLK_HEADER_SIZE - 6u),
                                                              (uint16)FEE_MARKER_PATTERN,
                                                              FALSE);

                            /* Extract the header checksum out of the page buffer and copy it to the block structure */
                            /* MR12 RULE 11.3 VIOLATION: Cast is necessary and not critical */
                            Fee_LLCopyPageBuff2HeaderIdxAndCrc(&xCurrBlkHeader_st, (const uint8*) &xDataBuf_au32[0]);

                            /* Check the header consistency */
                            if (xCalcCrc_u16 == xCurrBlkHeader_st.HdrCrc16_u16)
                            {
                                /* Load the last valid header address (known or unknown block). */
                                #if (FALSE == FEE_HEADER_RECHECK_ACTIVE)
                                if (xActivateLastPgmSearch_u8 == 1)
                                {
                                    xLastValidHeader_u32 = xAdrBlkHeaderTmp_u32;
                                }
                                else
                                {
                                    /* Identification of last programmed header and page is required only for the lastest valid sector i.e., sector with USED state.
                                     * Do nothing for all sectors. */
                                }
                                #endif

                                /* Check if the index can be found */
                                if (Fee_SrvBinarySearchInBlockPropFast(xCurrBlkHeader_st.FeeIndex_u16,
                                        &xCacheIdx_u16) != FALSE)
                                {
                                    /* Update the address within the cache */
                                    Fee_Cache_au32[xCacheIdx_u16] = xAdrBlkHeaderTmp_u32;
                                }
                            }
                        }
                    }
                    else
                    {
                        /* Load the last programmed page for controllers other then R1x, P1x and RH850xx. */
                        #if (FALSE == FEE_HEADER_RECHECK_ACTIVE)
                        if (xActivateLastPgmSearch_u8 == 1)
                        {
                            /* Direct read from memory is time consuming. Hence, reuse the first 4 bytes information that was already read earlier. */
                            if (xDataBuf_au32[0] != FEE_ERASE_PATTERN_U32)
                            {
                                /* Copy the address to a local variable for faster execution. */
                                xLastProgrammedAddress_u32 = xRdAdr_u32;
                            }
                            else
                            {
                                /* Extract the next 4 bytes of the page. */
#if defined(RBA_FLSVECU_FLASH)
                                xDataBuf_au32[1] = rba_FlsVecu_MemRead32_Macro((uint32)(xRdAdr_u32 + 4u))
#else
                                /* MISRA RULE 11.3 VIOLATION: Cast is necessary and not critical */
                                (void)Fee_Fls_SyncRead(xRdAdr_u32 + 4, (uint8*)&xDataBuf_au32[1], (Fls_LengthType)4U);
#endif


                                if (xDataBuf_au32[1] != FEE_ERASE_PATTERN_U32)
                                {
                                    /* Copy the address to a local variable for faster execution. */
                                    xLastProgrammedAddress_u32 = xRdAdr_u32;
                                }
                                else
                                {
                                    /* The page is blank. do nothing. */
                                }
                            }
                        }
                        else
                        {
                            /* Identification of last programmed header and page is required only for the lastest valid sector i.e., sector with USED state.
                             * Do nothing for all sectors. */
                        }
                        #endif

                        /* Just go on until the end address is reached,
                         * the next header can only start at the next page */
                        Fee_IncAddressInsideSector(&xRdAdr_u32 , FEE_PAGE_LEN , FALSE);

                    }
                } while (xRdAdr_u32 < xRdAdrEnd_u32);



                #if (FALSE == FEE_HEADER_RECHECK_ACTIVE)
                if (xActivateLastPgmSearch_u8 == 1)
                {
                    Fee_RdWrOrder_st.LastProgrammedAddress_u32 = xLastProgrammedAddress_u32;
                    Fee_RdWrOrder_st.LastValidHdrAddress_u32 = xLastValidHeader_u32;
                }
                else
                {
                    /* Identification of last programmed header and page is required only for the lastest valid sector i.e., sector with USED state.
                     * Do nothing for all sectors. */
                }
                #endif

                /* Save addresses for next call */
                xRdAdrContinue_u32      = xRdAdr_u32;
                xRdAdrEndContinue_u32   = xRdAdrEnd_u32;

                /* Check if the end address for the search is already reached */
                #if  (TRUE == FEE_HEADER_RECHECK_ACTIVE)
                if(xRdAdr_u32 >= xRdAdrEnd_u32)
                #else
                if(xRdAdrEnd_u32 >= EndAdr_u32)
                #endif
                {
                    /* Finish the order */
                    xRetVal = FEE_SECTORFULL_E;
                }
            }
            break;

            /* These states should never be reached */
            default:
            {
                /* Set error state */
                xRetVal = FEE_ERROR_E;
            }
            break;
        }
    }
    while((Fee_stMain == FEE_POLLING_MODE_E) && (xRetVal == FEE_ORDER_PENDING_E) && (xRdAdrContinue_u32 < xRdAdrEndContinue_u32));

    #if (FEE_PRV_DEBUGGING != FALSE)
    Fee_Prv_stModuleTest_st.BuildUpCacheDiffRemainInside_u32 =
                        MCU_RB_TIM0TICKS_TO_US(Mcu_Rb_GetSysTimePart(TIM0) -
                                               Fee_Prv_stModuleTest_st.BuildUpCacheStart_u32);

    /* Check for the maximum outside of the ECU init phase */
    if((Fee_Prv_stModuleTest_st.BuildUpCacheDiffRemainInside_u32 > Fee_Prv_stModuleTest_st.BuildUpCacheRemainInsideMax_u32) &&
       (Fee_stMain != FEE_POLLING_MODE_E))
    {
        Fee_Prv_stModuleTest_st.BuildUpCacheRemainInsideMax_u32 = Fee_Prv_stModuleTest_st.BuildUpCacheDiffRemainInside_u32;
    }
    #endif

    /* Check for necessary resets */
    if(xRetVal != FEE_ORDER_PENDING_E)
    {
        /* Reset state machine */
        Fee_RdWrOrder_st.Fee_LLBuildUpCache_en = FEE_LL_BLD_UP_CACHE_INIT_E;

        #if (FEE_PRV_DEBUGGING != FALSE)
        Fee_Prv_stModuleTest_st.BuildUpCacheDiff_u32 =
                            MCU_RB_TIM0TICKS_TO_US(Mcu_Rb_GetSysTimePart(TIM0) -
                                                   Fee_Prv_stModuleTest_st.BuildUpCacheStart_u32);

        /* Check for the maximum outside of the ECU init phase */
        if((Fee_Prv_stModuleTest_st.BuildUpCacheDiff_u32 > Fee_Prv_stModuleTest_st.BuildUpCacheMax_u32) &&
           (Fee_stMain != FEE_POLLING_MODE_E))
        {
            Fee_Prv_stModuleTest_st.BuildUpCacheMax_u32 = Fee_Prv_stModuleTest_st.BuildUpCacheDiff_u32;
        }
        #endif
    }

    return xRetVal;
}


/**
 *********************************************************************
 * Fee_BuildUpCacheForAllSect(): Build up the cache for all
 *                               available sectors
 *
 * This function builds up the cache for all sectors that are
 * configured.
 * The function can execute one sector without returning in case
 * this is necessary (e.g. during the ECU init) or verify
 * the block checksum.
 *
 * \param    none
 *
 * \return
 * \retval   FEE_ORDER_PENDING_E:   Order is pending
 * \retval   FEE_ORDER_FINISHED_E:  Order is finished
 * \seealso
 * \usedresources
 *********************************************************************
 */
Fee_stRetVal_ten Fee_BuildUpCacheForAllSect(void)
{
    Fee_stRetVal_ten xtmpRetVal;                        /* Function return */
    Fee_stRetVal_ten xRetVal = FEE_ORDER_PENDING_E;     /* Function return */
    static uint8 xLogSecIdxForCache_u8;                 /* Index of logical sector */

    /* Loop if polling mode is active and function state is pending */
    do
    {
        /* Switch over state machine */
        switch (Fee_RdWrOrder_st.Fee_LLBuildUpCacheAllSect_en)
        {
            /* Init case */
            case FEE_LL_BLD_UP_CACHE_ALL_SECT_INIT_E:
            {
                /* Init the sector index */
                xLogSecIdxForCache_u8 = 0;

                /* Set next state */
                Fee_RdWrOrder_st.Fee_LLBuildUpCacheAllSect_en = FEE_LL_BLD_UP_CACHE_ALL_SECT_DO_E;
            }
            /* No break to save time */

            /* Build up the cache */
            /* MR12 RULE 16.3 VIOLATION: Time critical position */
            case FEE_LL_BLD_UP_CACHE_ALL_SECT_DO_E:
            {
                /* Build up the cache */
                xtmpRetVal = Fee_BuildUpCache(Fee_FlashProp_st[Fee_LLSectorOrder_st[xLogSecIdxForCache_u8].xPhySecIdx_u8].Fee_LogStartAddress_u32,
                                              Fee_FlashProp_st[Fee_LLSectorOrder_st[xLogSecIdxForCache_u8].xPhySecIdx_u8].Fee_LogEndAddress_u32);

                   /* Check the function return */
                if(xtmpRetVal != FEE_ORDER_PENDING_E)
                {
                    /* Check if all relevant sectors have been checked so far */
                    xLogSecIdxForCache_u8++;
                    if(xLogSecIdxForCache_u8 >= (Fee_NumFlashBanksUsed_u8))
                    {
                        /* Finish the function */
                        xRetVal = FEE_ORDER_FINISHED_E;
                    }
                }
            }
            break;

            /* This case should never be reached */
            default:
                /* Finish the function, the return type is currently not
                 * evaluated (only called in Ini) */
                xRetVal = FEE_ORDER_FINISHED_E;
            break;
        }
    }
    while((Fee_stMain == FEE_POLLING_MODE_E) && (xRetVal == FEE_ORDER_PENDING_E));

    /* Check the function state */
    if(xRetVal != FEE_ORDER_PENDING_E)
    {
        /* Reset the state machine */
        Fee_RdWrOrder_st.Fee_LLBuildUpCacheAllSect_en = FEE_LL_BLD_UP_CACHE_ALL_SECT_INIT_E;
    }

    return xRetVal;
}

#if (FALSE == FEE_HEADER_RECHECK_ACTIVE)
/**
 *********************************************************************
 * Fee_SearchLastBlkHeader(): Return the latest valid block
 *                            header address within one sector
 *
 * This function returns the latest valid block header address out of
 * the Fee_RdWrOrder_st.xRdAddress sector which can be found in the cache.
 * This read address can point somewhere into a sector.
 *
 * \param    none
 * \return
 * \retval   FEE_ORDER_PENDING_E:   Function is still pending
 * \retval   FEE_ERROR_E:           An error occurred
 * \retval   FEE_ABORTED_E:         Order was aborted
 * \retval   FEE_ORDER_FINISHED_E:  Function is finished
  * \seealso
 * \usedresources
 *********************************************************************
 */
Fee_stRetVal_ten Fee_SearchLastBlkHeader(Fee_GlobInfoLastRdHeader_tst* Fee_GlobInfoLastRdHeader_ptr)
{
    Fee_BlkHeader_tst xCurrBlkHeader_st;                            /* Block header structure */
    Fee_stRetVal_ten xRetVal_en  = FEE_ORDER_PENDING_E;             /* Function return */

    /* Loop if polling mode is active and function state is pending */
    do
    {
        /* Switch over the state machine */
        switch (Fee_RdWrOrder_st.Fee_LLRdState_en)
        {
            /* Init state */
            case FEE_LL_INIT_READ_E:
            {
                /* Init the user parameter */
                Fee_GlobInfoLastRdHeader_ptr->FeeIndex_u16      = FEE_MAXUINT16;
                Fee_GlobInfoLastRdHeader_ptr->BlkCrc32_u32      = 0;
                Fee_GlobInfoLastRdHeader_ptr->HdrCrc16_u16      = 0;
                Fee_GlobInfoLastRdHeader_ptr->BlkStatus_u8      = 0;
                Fee_GlobInfoLastRdHeader_ptr->BlkLength_u16     = 0;
                Fee_GlobInfoLastRdHeader_ptr->DataBytes_au8[0u] = 0;
                Fee_GlobInfoLastRdHeader_ptr->DataBytes_au8[1u] = 0;

                /* Retries for read */
                Fee_RdWrRetries_u8 = FEE_MAX_RD_WR_COMP_RETRIES;

                /* Pick the last address information from the variable which was updated during Cache init. this is required to handle unknown blocks.
                 * There is no details of unknown blocks in cache. */
                Fee_GlobInfoLastRdHeader_ptr->AdrBlkHeader_u32 = Fee_RdWrOrder_st.LastValidHdrAddress_u32;

                /* Check if a block header was found */
                if(Fee_GlobInfoLastRdHeader_ptr->AdrBlkHeader_u32 != FEE_NULL)
                {
                    /* Copy the header address */
                    Fee_RdWrOrder_st.xRdAddress = Fee_GlobInfoLastRdHeader_ptr->AdrBlkHeader_u32;

                    /* Read out the length of the corresponding block */
                    Fee_RdWrOrder_st.Fee_LLRdState_en = FEE_LL_READ_PAGE_E;
                }
                else
                {
                    /* No block header was found, return finished immediately */
                    xRetVal_en = FEE_ORDER_FINISHED_E;
                    break;
                }
            }
            /* No break to save time */
            /* Read out the header */
            /* MR12 RULE 16.3 VIOLATION: Time critical position */
            case FEE_LL_READ_PAGE_E:
            {
                /* Read out the header only */
                if(Fls_Read(Fee_RdWrOrder_st.xRdAddress, (uint8*)&Fee_PageBytePtr_cpu8[0], FEE_BLK_HEADER_SIZE) != E_NOT_OK)
                {
                    /* Set the next states:
                     * The block checksum has to be checked since the cache might have been build up during without a checksum
                     * verification (e.g. during the init) */
                    Fee_RdWrOrder_st.Fee_LLRdState_en = FEE_LL_WAIT_READ_PAGE_E;
                }
                else
                {
                    /* Fls did not accept the order due to wrong parameters or an internal busy state.
                     * Reset the state machine */
                    xRetVal_en = FEE_ABORTED_E;
                }
            }
            break;

            /* Wait for the read order to be finished */
            case FEE_LL_WAIT_READ_PAGE_E:
            {
                /* The next state will be set by the Fee_JobEndNotification () or
                 * Fee_JobErrorNotification() function automatically */

                /* Check whether the OS is currently running or not */
                if (Fee_stMain == FEE_POLLING_MODE_E)
                {
                    /* Call the Fls main function manually */
                    Fls_MainFunction();
                }

                #if (STD_ON == FEE_POLLING_MODE)
                /* Use the FLS polling mechanism in order to reach the next state */
                Fee_CheckFlsJobResult();
                #endif
            }
            break;

            /* Error reaction for read error */
            case FEE_LL_READ_ERROR_E:
            {
                /* Reset the complete read buffer */
                Fee_SrvMemSet8((uint8*)&Fee_PageBytePtr_cpu8[0], (uint8)FEE_ERASE_PATTERN, FEE_LL_PAGEBUFFSIZE);

                /* Verify retry possibility */
                if(Fee_RdWrRetries_u8 > 0)
                {
                    /* Decrement retry possibilities */
                    Fee_RdWrRetries_u8--;

                    /* Try again to call the Fls and perform the read procedure */
                    Fee_RdWrOrder_st.Fee_LLRdState_en = FEE_LL_READ_PAGE_E;
                }
                else
                {
                    /* Return error */
                    xRetVal_en = FEE_ERROR_E;
                }
            }
            break;

            /* Evaluate the block header */
            case FEE_LL_READ_FINISHED_E:
            {
                /* Extract the block length and the block index out of the flash
                 *
                 * Hint: This function is used in the init phase of the Fee and therefore
                 *       the block checksum is not relevant. Only valid headers are
                 *       added to the cache and therefore it can be regarded as valid */
                Fee_LLCopyPageBuff2HeaderMid(&xCurrBlkHeader_st, &Fee_PageBytePtr_cpu8[0]);

                /* Copy the relevant info to the global structure */
                Fee_GlobInfoLastRdHeader_ptr->FeeIndex_u16  = xCurrBlkHeader_st.FeeIndex_u16;
                Fee_GlobInfoLastRdHeader_ptr->BlkLength_u16 = xCurrBlkHeader_st.BlkLength_u16;

                /* Set return value */
                xRetVal_en = FEE_ORDER_FINISHED_E;
            }
            break;

            /* Default state should never be reached */
            default:
            {
                /* Set error state */
                xRetVal_en = FEE_ERROR_E;

                /* Reset the state machine */
                Fee_RdWrOrder_st.Fee_LLRdState_en = FEE_LL_INIT_READ_E;
            }
            break;
        }
    }
    while((Fee_stMain == FEE_POLLING_MODE_E) && (xRetVal_en == FEE_ORDER_PENDING_E));

    /* Check if the search was aborted or the sector is full */
    if (xRetVal_en != FEE_ORDER_PENDING_E)
    {
        /* Init the state machine */
        Fee_RdWrOrder_st.Fee_LLRdState_en = FEE_LL_INIT_READ_E;
    }

    /* Return function state */
    return xRetVal_en;
}
/* (FALSE == FEE_HEADER_RECHECK_ACTIVE)*/
#endif
/* FEE_FAST_CACHE_INIT_ACTIVE != FALSE */
#endif


/**
 *********************************************************************
 * Fee_SearchHighestCacheEntry(): Return the highest cache address
 *                                for the corresponding sector within
 *                                a certain boundary.
 *
 * This function returns the highest cache address for a certain
 * sector within given boundaries.
 *
 * \param    UpperBoundary_u32:        Upper boundary
 * \param     SectIdx_u8:            Corresponding sector index
 * \return
 * \retval   xAddress_u32:            Corresponding address
 * \seealso
 * \usedresources
 *********************************************************************
 */
uint32 Fee_SearchHighestCacheEntry(uint32 UpperBoundary_u32, uint8 SectIdx_u8)
{
    uint32 xAddress_u32         = FEE_NULL;                /* Function return */
    uint32 i_u32 = 0;                                    /* Loop counter */
    uint32 xSectStartAdr_u32     = Fee_FlashProp_st[SectIdx_u8].Fee_LogStartAddress_u32;
    uint32 xSectEndAdr_u32         = Fee_FlashProp_st[SectIdx_u8].Fee_LogEndAddress_u32;

    /* Get the highest value out of the cache */
    for(i_u32=0; i_u32<FEE_NUM_BLOCKS;i_u32++)
    {
        /* Check if the current cache entry to be regarded for the search*/
        if((Fee_Cache_au32[i_u32] >= xSectStartAdr_u32) &&
           (Fee_Cache_au32[i_u32]  < xSectEndAdr_u32) &&
           (Fee_Cache_au32[i_u32] != FEE_CACHE_INIT_VALUE) &&
           (Fee_Cache_au32[i_u32] != FEE_CACHE_TMP_INVALID_VALUE) &&
           (Fee_Cache_au32[i_u32] > xAddress_u32) &&
           (Fee_Cache_au32[i_u32] < UpperBoundary_u32))
        {
            /* Save the current address */
            xAddress_u32 = Fee_Cache_au32[i_u32];
        }
    }

    /* Check for the init value */
    if(xAddress_u32 == FEE_NULL)
    {
        /* Reset the return to the upper boundary */
        xAddress_u32 = UpperBoundary_u32;
    }

    return xAddress_u32;
}

void Fee_InvalidateCacheByAddress(uint32 xAddress_u32)
{
    uint32 i_u32 = 0;                                    /* Loop counter */

    /* Get the highest value out of the cache */
    for(i_u32=0; i_u32<FEE_NUM_BLOCKS;i_u32++)
    {
        /* Check if the current cache entry to be regarded for the search*/
        if(Fee_Cache_au32[i_u32] == xAddress_u32)
        {
            Fee_Cache_au32[i_u32] = FEE_CACHE_TMP_INVALID_VALUE;
        }
    }
}
#define FEE_STOP_SEC_CODE
#include "Fee_MemMap.h"
/* FEE_PRESENT == 1 */
#endif
/* 1 == FEE_PRV_CFG_SELECTED_FS */
#endif

