


/**
 **********************************************************************************************************************
 * \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"
#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(defined(FEE_PRV_CFG_SELECTED_FS) && (1 == FEE_PRV_CFG_SELECTED_FS))

#if (FEE_PRESENT == 1)
/**
 *********************************************************************
 * Fee_LLWriteMarker(): Write a marker in the sector marker section
 *
 * This function writes one of the sector markers in the respective
 * sector header section. The marker pattern, marker ID,
 * sector change counter (if necessary) and the marker checksum are
 * written.
 * If there is not enough space in the marker section and the USED
 * marker needs to be written, the calling function should erase
 * this sector. Otherwise data might get lost.
 * If the there is enough space and the marker cannot be written
 * due to any HW issue, the function will retry the write access
 * automatically for FEE_MAX_RD_WR_COMP_RETRIES times.
 *
 * \param    PhySectIdx_u8:         Index of the physical sector
 * \param    MarkerID_u8:           Marker ID to write
 * \return   Function result
 * \retval   FEE_ORDER_PENDING_E:   Order is still pending
 * \retval   FEE_ABORTED_E:         Order was aborted due to a wrong
 *                                  FLS compare function call
 * \retval   FEE_ERROR_E:           Marker not writable/readable or
 *                                  marker section is full
 * \retval   FEE_ORDER_FINISHED_E:  Order finished successfully
 * \seealso
 * \usedresources
 *********************************************************************
 */
#define FEE_START_SEC_CODE
#include "Fee_MemMap.h"
Fee_stRetVal_ten Fee_LLWriteMarker(uint8 PhySectIdx_u8, uint8 MarkerID_u8)
{
    Fee_MarkerProp_t xWrMarker_st;                      /* Marker structure */
    Fee_stRetVal_ten xRetVal_en = FEE_ORDER_PENDING_E;  /* Function return value */
    uint32 xSecChngCntTmp_u32 = 0;                      /* Temporary sector change counter */
    uint8 xLogSectIdx_u8 = 0;                           /* Logical sector index */
    static uint32 xRdWr_Address_u32 = FEE_MAXUINT32;                    /* Read address for the blank check */

    #if (FEE_PRV_DEBUG_MONITOR != FALSE)
    uint16             xCacheIdx_u16;
    uint32             stDBM_u32 = 0;
    #endif

    /* Get the logical sector index */
    xLogSectIdx_u8 = Fee_idxLLSectorOrder_au8[PhySectIdx_u8];


    /* Switch over function state machine */
    switch (Fee_RdWrOrder_st.Fee_LLWrMarker_en)
    {
        /* Init state */
        case FEE_LL_MARKER_INIT_E:
        {
            #if (FEE_PRV_DEBUG_MONITOR != FALSE)
            /* For ERASE_REQUEST marker, check the cache if block is still in this sector */
            if (MarkerID_u8 == FEE_ERASE_REQUEST_ID_E)
            {
                /* Check if any cache entry points to the sector which should be erased */
                for (xCacheIdx_u16 = 0; xCacheIdx_u16 < FEE_NUM_BLOCKS; xCacheIdx_u16++)
                {
                    if ((Fee_Cache_au32[xCacheIdx_u16] >= Fee_FlashProp_st[PhySectIdx_u8].Fee_PhysStartAddress_u32) &&
                         (Fee_Cache_au32[xCacheIdx_u16] <= Fee_FlashProp_st[PhySectIdx_u8].Fee_PhysEndAddress_u32))
                    {
                        /* Set status for debug monitor */
                        stDBM_u32 = 0x1;
                        xRetVal_en = FEE_ERROR_E;
                    }
                }
            }
            #endif

            /* Set next state */
            Fee_RdWrOrder_st.Fee_LLWrMarker_en = FEE_LL_MARKER_BLK_CHK_E;

            /* Reset buffer */
            Fee_SrvMemSet8((uint8*)&Fee_MarkerBufBytePtr_cpu8[0], (uint8)FEE_ERASE_PATTERN, FEE_SEC_HEADER_SIZE);

            /* Set the start read address */
            xRdWr_Address_u32 = Fee_FlashProp_st[PhySectIdx_u8].Fee_PhysStartAddress_u32;
        }
        /* No break to save time */

        /* Perform a blank check over one page */
        /* MR12 RULE 16.3 VIOLATION: Time critical position */
        case FEE_LL_MARKER_BLK_CHK_E:
        {
            /* Perform a blank check over the respective marker */
            if(Fls_BlankCheck(xRdWr_Address_u32, FEE_PAGE_LEN) != E_NOT_OK)
            {
                /* Set the next state for finishing the blank check */
                Fee_RdWrOrder_st.Fee_LLWrMarker_en = FEE_LL_MARKER_BLK_CHK_WAIT_E;
            }
            else
            {
                /* Return an error due to invalid parameters or a busy / not intialized Fls */
                xRetVal_en = FEE_ABORTED_E;
            }
        }
        break;

        /* Wait for the blank check order to be finished */
        case FEE_LL_MARKER_BLK_CHK_WAIT_E:
        {
            /* The next state (FEE_LL_MARKER_BLK_CHK_FINISHED_E or FEE_LL_MARKER_BLK_CHK_ERROR_E)
             * 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;

        /* Differences detected */
        case FEE_LL_MARKER_BLK_CHK_ERROR_E:
        {
            /* Check the next page / marker, increment the write address for the blank check */
            xRdWr_Address_u32 += FEE_PAGE_LEN;

            /* Ensure page alignment for blank check and write operation (following) */
            while((xRdWr_Address_u32 % FEE_PAGE_LEN) != 0u)
            {
                /* Increment address */
                xRdWr_Address_u32++;
            }

            /* Check for an overflow (at least enough space for one more marker must be available) */
            if(xRdWr_Address_u32 >
               (Fee_FlashProp_st[PhySectIdx_u8].Fee_PhysStartAddress_u32 + (uint32)(((uint8)FEE_NUM_MARKER_IN_HEADER - 1u) * FEE_PAGE_LEN)))
            {
                /* Return with an error */
                xRetVal_en = FEE_ERROR_E;
            }
            else
            {
                /* Reset buffer */
                Fee_SrvMemSet8((uint8*)&Fee_MarkerBufBytePtr_cpu8[0], (uint8)FEE_ERASE_PATTERN, FEE_SEC_HEADER_SIZE);

                /* Restart the state machine starting with a blank check */
                Fee_RdWrOrder_st.Fee_LLWrMarker_en = FEE_LL_MARKER_BLK_CHK_E;
            }
        }
        break;

        /* Start write order of the marker */
        case FEE_LL_MARKER_BLK_CHK_FINISHED_E:
        {
            /* Prepare the marker to be written */
            xWrMarker_st.xPattern = FEE_MARKER_PATTERN;
            xWrMarker_st.xIdent   = MarkerID_u8;

            /* Check if the sector which will be used to store the marker has a valid
             * sector change counter. If not, the highest available counter has to be
             * searched and incremented within the other sectors.
             *
             * If the ERASED marker needs to be written, this search is also necessary,
             * because this is the first marker to be written inside this sectors
             * --> no other sector change counter is available inside this sector yet
             */

            /* Check for an available sector change counter inside the requested sector */
            if((Fee_LLSectorOrder_st[xLogSectIdx_u8].SecChngCnt_u32 != FEE_SEC_CHANGE_CNT_UNDEF) &&
               (MarkerID_u8 != FEE_ERASED_MARKER_ID_E) )
            {
                /* Save the available counter value */
                xSecChngCntTmp_u32 = Fee_LLSectorOrder_st[xLogSectIdx_u8].SecChngCnt_u32;
            }
            else
            {
                /* Increment the counter because every sector has to use different sector
                 * change counter values */
                if (Fee_RdWrRetries_u8 == FEE_MAX_RD_WR_COMP_RETRIES)
                {
                    /* Increment sector change counter (highest one is detected during the sector detection) */
                    Fee_SecChngCnt_u32++;
                }
                xSecChngCntTmp_u32 = Fee_SecChngCnt_u32;
                /* Save the new sector change counter value */
                Fee_LLSectorOrder_st[xLogSectIdx_u8].SecChngCnt_u32 = xSecChngCntTmp_u32;
            }

            if (MarkerID_u8 == FEE_START_MARKER_ID_E)
            {
                xSecChngCntTmp_u32 = Fee_RdWrOrder_st.xStartAddrNextSector_u32;
            }

            #if(FEE_ROBUST_PROG_ACTIVE != FALSE)
            if (MarkerID_u8 == FEE_CLONE_START_MARKER_ID_E)
            {
                xSecChngCntTmp_u32 = Fee_IfxRobustProgramming_s.xStartAddress;
            }
            #endif

            /* Save the counter value to the content structure of the marker content. For the
             * USED, FULL and ERASED marker it contains the sector change counter. The ERASE
             * marker content is not used and will therefore be zero.
             * Result of the shift operation: [2]CC, [1]BB, [0]AA: 0xAABBCC*/
            xWrMarker_st.xContent[0] = (uint8)(xSecChngCntTmp_u32 >> 16u);
            xWrMarker_st.xContent[1] = (uint8)(xSecChngCntTmp_u32 >> 8u);
            xWrMarker_st.xContent[2] = (uint8)(xSecChngCntTmp_u32);

            /* Calculate the new marker CRC and save it to the marker structure */
            /* MR12 RULE 11.3 VIOLATION: Variable must be changeable */
            xWrMarker_st.xChecksum  = Crc_CalculateCRC16((const uint8*)&xWrMarker_st,
                                                         (uint32)(FEE_MARKER_SIZE-FEE_MARKER_CS_SIZE),
                                                         (uint16)FEE_MARKER_PATTERN,
                                                          FALSE);

            /* Prepare marker buffer */
            Fee_LLPrepMarkerBufWithMarkerData(&xWrMarker_st, &Fee_MarkerBufBytePtr_cpu8[0]);

            /* Write the new marker into the flash */
            if(Fls_Write(xRdWr_Address_u32, (uint8*)&Fee_MarkerBufBytePtr_cpu8[0], FEE_MARKER_SIZE) != E_NOT_OK)
            {
                /* Set the next state to wait for the write order to be finished */
                Fee_RdWrOrder_st.Fee_LLWrMarker_en = FEE_LL_MARKER_WRITE_WAIT_E;
            }
            else
            {
                /* Abort due to wrong parameters or the Fls being busy / not initialized */
                xRetVal_en = FEE_ABORTED_E;
            }
        }
        break;

        /* Wait for the write order to be finished */
        case FEE_LL_MARKER_WRITE_WAIT_E:
        {
            /* The next state (FEE_LL_MARKER_WRITE_FINISHED_E) will be set by the Fee_JobEndNotification() or
             * Fee_JobErrorNotification() function automatically (the verification of the data will be done
             * in one step after the data was written) */

            /* 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;

        /* Read or write error */
        case FEE_LL_MARKER_WRITE_ERROR_E:
        {
            /* Verify retry possibility */
            if(Fee_RdWrRetries_u8 > 0)
            {
                /* Decrement retry possibilities */
                Fee_RdWrRetries_u8--;

                /* Increment the write address */
                xRdWr_Address_u32 += FEE_PAGE_LEN;

                /* Ensure page alignment */
                while((xRdWr_Address_u32 % FEE_PAGE_LEN) != 0u)
                {
                    /* Increment address */
                    xRdWr_Address_u32++;
                }

                /* Reset buffer */
                Fee_SrvMemSet8((uint8*)&Fee_MarkerBufBytePtr_cpu8[0], (uint8)FEE_ERASE_PATTERN, FEE_SEC_HEADER_SIZE);

                /* Restart the state machine starting with a blank check */
                Fee_RdWrOrder_st.Fee_LLWrMarker_en = FEE_LL_MARKER_BLK_CHK_E;
            }
            else
            {
                /* Return error, because maximum amount of retries is reached */
                xRetVal_en = FEE_ERROR_E;
            }
        }
        break;

        /* Verify the written marker  */
        case FEE_LL_MARKER_VERIFY_E:
        {
            if(Fls_Compare(xRdWr_Address_u32, (uint8*)&Fee_MarkerBufBytePtr_cpu8[0], FEE_MARKER_SIZE) != E_NOT_OK)
            {
                /* Set the next state to wait for the write order to be finished */
                Fee_RdWrOrder_st.Fee_LLWrMarker_en = FEE_LL_MARKER_VERIFY_WAIT_E;
            }
            else
            {
                /* Abort due to wrong parameters or the Fls being busy / not initialized */
                xRetVal_en = FEE_ABORTED_E;
            }
        }
        break;

        /* Verify the written marker  */
        case FEE_LL_MARKER_VERIFY_WAIT_E:
        {
            /* The next state (FEE_LL_MARKER_WRITE_FINISHED_E) will be set by the Fee_JobEndNotification() or
             * Fee_JobErrorNotification() function automatically (the verification of the data will be done
             * in one step after the data was written) */

            /* 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;

        /* Marker was written with success */
        case FEE_LL_MARKER_VERIFY_FINISHED_E:
        {
            /* Return with success */
            xRetVal_en = FEE_ORDER_FINISHED_E;
        }
        break;

        /* Default state */
        default:
        {
            /* Return aborted */
            xRetVal_en = FEE_ABORTED_E;
        }
        break;
    }


    /* Verify a necessary reset of the state machine */
    if(xRetVal_en != FEE_ORDER_PENDING_E)
    {
        #if (FEE_PRV_DEBUG_MONITOR != FALSE)
        /* Report Debug monitor */
        if (stDBM_u32 > 0)
        {
            Fee_DBM_RepError(PhySectIdx_u8, FEE_DBM_ERROR_LLMARKER_FCT_E, stDBM_u32);
            stDBM_u32 = 0;
        }
        #endif

        /* Update the new sector state (if necessary the sector change counter has been updated already before) */
        if ((MarkerID_u8 != FEE_START_MARKER_ID_E) && (MarkerID_u8 != FEE_CLONE_START_MARKER_ID_E))
        {
            /* if a START-Marker was written, the sector is still in the STATE USED. It is not allowed to write the
             * START-Marker-ID on the sector state, because the sector didn't get a new STATE by writing START-Marker */
            /* MR12 RULE 10.5 VIOLATION: Sector states are defined as enum for modular design and easy to read. */
            Fee_LLSectorOrder_st[xLogSectIdx_u8].SecState_en = (Fee_SectorState_ten)MarkerID_u8;
        }
        else
        {
            /* Start- and Clonse-Marker is nearly the same as the USED-Marker */
            Fee_LLSectorOrder_st[xLogSectIdx_u8].SecState_en = FEE_SECTOR_USED_E;
        }

        /* Init state machine */
        Fee_RdWrOrder_st.Fee_LLWrMarker_en = FEE_LL_MARKER_INIT_E;

        /* Retries for write */
        Fee_RdWrRetries_u8 = FEE_MAX_RD_WR_COMP_RETRIES;

        /* Reset start address for the blank check */
        xRdWr_Address_u32 = FEE_MAXUINT32;
    }

    return (xRetVal_en);
}
#define FEE_STOP_SEC_CODE
#include "Fee_MemMap.h"
#endif
/* 1 == FEE_PRV_CFG_SELECTED_FS */
#endif

