

/*
 **********************************************************************************************************************
 * Includes
 **********************************************************************************************************************
*/

#include "NvM.h"

#include "NvM_Cfg_SchM.h"

#include "Rte_NvM.h"

#if (NVM_DEV_ERROR_DETECT == STD_ON)
# include "Det.h"    // TRACE[NVM556] NvM module shall include Det.h
// TRACE[NVM089] Check version compatibility of included header files
# if (!defined(DET_AR_RELEASE_MAJOR_VERSION) || (DET_AR_RELEASE_MAJOR_VERSION != NVM_AR_RELEASE_MAJOR_VERSION))
#  error "AUTOSAR major version undefined or mismatched"
# endif
#if (!defined(DET_AR_RELEASE_MINOR_VERSION) || ((DET_AR_RELEASE_MINOR_VERSION != 0) && (DET_AR_RELEASE_MINOR_VERSION != 2)))
#error "AUTOSAR minor version undefined or mismatched"
#endif
#endif

#include "NvM_Prv.h"

/*
 **********************************************************************************************************************
 * Code
 **********************************************************************************************************************
*/

#define NVM_START_SEC_CODE
#include "NvM_MemMap.h"

#ifdef NVM_CFG_API_RESTORE_BLOCK_DEFAULTS
    // TRACE[BSW_SWS_AR4_0_R2_NVRAMManager_Ext-2917] Declaration of the overloading function shall be done here, not in a header file
    /* MR12 RULE 8.5 VIOLATION: Not using a header file for this declaration is a customer requirement */
    extern Std_ReturnType NVM_CFG_API_RESTORE_BLOCK_DEFAULTS(NvM_BlockIdType BlockId, void *NvM_DstPtr);

    /* MR12 RULE 8.3 VIOLATION: The parameter identifiers in Rte's generated declaration of this depend on Rte vendor */
    Std_ReturnType NvM_RestoreBlockDefaults(NvM_BlockIdType BlockId, void *NvM_DstPtr)
    {
        // TRACE[BSW_SWS_AR4_0_R2_NVRAMManager_Ext-2920] Call the overloading function
        return NVM_CFG_API_RESTORE_BLOCK_DEFAULTS(BlockId, NvM_DstPtr);
    }

    Std_ReturnType NvM_Rb_RestoreBlockDefaultsBase(NvM_BlockIdType BlockId, void *NvM_DstPtr)
#else
    /* MR12 RULE 8.3 VIOLATION: The parameter identifiers in Rte's generated declaration of this depend on Rte vendor; typedef is generated by Rte instead of using void pointer (but is compatible) */
    Std_ReturnType NvM_RestoreBlockDefaults(NvM_BlockIdType BlockId, void *NvM_DstPtr)
#endif
{
    // TRACE[NVM456] Service to restore the default data to its corresponding RAM block
    void *adrRamBlock_pv = NvM_DstPtr;
    Std_ReturnType stReturn_u8 = E_NOT_OK;

#if (NVM_DEV_ERROR_DETECT == STD_ON)
    // Variables used to report DET errors
    boolean flgDetError_b = FALSE;
    uint8 idDetError_u8 = NVM_PRV_NO_DET_ERROR;
#endif

    if (NvM_Prv_Main_st.isInitialized_rAM_b != TRUE)
    {
#if (NVM_DEV_ERROR_DETECT == STD_ON)
        // TRACE[NVM625] Report the DET error NVM_E_NOT_INITIALIZED when the NVM is not yet initialized
        flgDetError_b = TRUE;
        idDetError_u8 = NVM_E_NOT_INITIALIZED;
#endif
    }
    else if (!NvM_Prv_IsBlockIdValid(NVM_SERVICE_ID_RESTORE_BLOCK_DEFAULTS, BlockId, BlockId))
    {
        // block ID is invalid so this service does not start and returns E_NOT_OK
        // TRACE[NVM630] Report the DET error NVM_E_PARAM_BLOCK_ID when the passed BlockID is out of range
    }
    else if (!(NvM_Prv_BlockDescriptors_acst[BlockId].adrRomBlock_pcv) &&
             !(NvM_Prv_BlockDescriptors_acst[BlockId].InitBlockCallback_pfct))
    {
#if (NVM_DEV_ERROR_DETECT == STD_ON)
        // TRACE[NVM628] Report the DET error NVM_E_BLOCK_CONFIG when default data is not available/configured for the referenced NVRAM block
        flgDetError_b = TRUE;
        idDetError_u8 = NVM_E_BLOCK_CONFIG;
#endif
    }

    else if (!NvM_Prv_IsSanitizedByReadAll(NvM_Prv_BlockDescriptors_acst[BlockId].stFlags_u16))
    {
        //TRACE[BSW_SWS_AR4_0_R2_NVRAMManager_Ext-2999] the potentially incompatible blocks after layout changes
        //     should be sanitized by ReadAll at first, then the current single block request
        //     is allowed to be accepted and executed
    }

	// TRACE[BSW_SWS_AR4_0_R2_NVRAMManager_Ext-3032] Ignore blocks with length null
    else if (*NvM_Prv_BlockDescriptors_acst[BlockId].nrBlockBytes_pu16 == 0)
    {
        // Block length is Null
        // Block is pre-defined but not used
        // Job shall never start
        // return E_NOT_OK
    }
    else
    {
        // Parameters are valid and a source for block defaults is available
        // TRACE[NVM012] Trigger a read of default data to RAM
        // TRACE[NVM224] The actual restore operation is not done here, just the request for doing it is queued

        SchM_Enter_NvM_Main();

        // TRACE[NVM385] Only queue this request if no operation on this block is requested or in progress
        // TRACE[NVM139] Block defaults are optional, regardless of the block management type
        // TRACE[BSW_SWS_AR4_0_R2_NVRAMManager_Ext-2866] Exception to NVM385: NvM_RestoreBlockDefaults can be queued for a block whose the only pending operation is a a maintenance operation.
        if (((NvM_Prv_stRequests_rAMwAM_au16[BlockId] == 0) && (NvM_Prv_Main_st.idActiveBlockAdmin_rAMwM_u16 != BlockId))
#if (NVM_PRV_MAINTAIN_REDUNDANT_BLOCKS)
            || (NvM_Prv_stRequests_rAMwAM_au16[BlockId] == NVM_PRV_BLOCK_REQ_MAINTAIN)
            || (
                (NvM_Prv_Main_st.idActiveService_rAMwM_u8 == NVM_PRV_SERVICE_ID_MAINTAIN_BLOCK) &&
                (NvM_Prv_stRequests_rAMwAM_au16[BlockId] == 0) &&
                (NvM_Prv_Main_st.idActiveBlockAdmin_rAMwM_u16 == BlockId)
               )
#endif
           )
        {
            // No operation pending
            // TRACE[NVM435] Only take the permanent RAM block if no temporary RAM block has been specified
            if (!adrRamBlock_pv)
            {
                adrRamBlock_pv = *NvM_Prv_BlockDescriptors_acst[BlockId].adrRamBlock_ppv;
            }

            // Now queue the read request and additionally set the read request flag of this block if we have
            // a RAM block to read to
            if (adrRamBlock_pv != NULL_PTR)
            {
                // TRACE[NVM266] NvM allows the queuing of a NvM_RestoreBlockDefaults request to restore a user block which has only an InitBlockCallback (i.e. no ROM block).
                if ((NVM_BLOCK_DATASET == NvM_Prv_BlockDescriptors_acst[BlockId].BlockManagementType_en) &&
                    NvM_Prv_BlockDescriptors_acst[BlockId].adrRomBlock_pcv &&
                    (NvM_Prv_idxDataSet_rAMwA_au8[BlockId] < NvM_Prv_BlockDescriptors_acst[BlockId].nrNvBlocks_u8))
                {
                    // In case of DATASET blocks with at least one ROM block, recovery is potentially amgiguous because it is not clear which
                    // ROM block instance to take (the case of exactly one ROM block is not specially treated here for simplicity reasons)
                    // -> reject this request
                }
                else
                {
                    // Read block contents to the given destination
                    // TRACE[NVM181] Queue this request to allow multiple concurrent single block requests
                    // In case of explicit sync the reference to NvM mirror is passed implicitly as parameter to the queueing function
                    /* MR12 RULE 11.5 VIOLATION: The actual type of the RAM block varies from block to block (not under control of NvM) */
                    if (NvM_Prv_QueueBlockRequest(NVM_SERVICE_ID_RESTORE_BLOCK_DEFAULTS, BlockId, (uint8 *) adrRamBlock_pv) == NVM_PRV_QUEUE_OP_OK)
                    {
                        // TRACE[NVM185] Set single block request result to NVM_REQ_PENDING on successful enqueuing
                        NvM_Prv_stRequestResult_rAwAM_au8[BlockId] = NVM_REQ_PENDING;

                        // TRACE[NVM227] Set the status of the permanent RAM block to INVALID before processing starts
                        if (adrRamBlock_pv == *NvM_Prv_BlockDescriptors_acst[BlockId].adrRamBlock_ppv)
                        {
                            NvM_Prv_stBlock_rAwAM_au8[BlockId] &= (uint8) ~(NVM_BLOCK_STATE_RAM_VALID);
                        }

                        // Internally signal that this block has been requested to be restored
                        NvM_Prv_stRequests_rAMwAM_au16[BlockId] |= (uint16) NVM_PRV_BLOCK_REQ_RESTORE;

                        stReturn_u8 = E_OK;
                    }
                    // TRACE[NVM184] In case of a queue overflow, the return value is E_NOT_OK
                }

                // TRACE[NVM353] E_NOT_OK is returned if the block is of type DATASET, has at least 1 ROM block and the dataset-index is pointing to an NV block
                // If a DATASET block has at least one ROM block, the restore request is accepted only if the dataset-index points to a ROM block regardless whether the block has an InitBlockCallback or not.
            }

            else
            {
#if (NVM_DEV_ERROR_DETECT == STD_ON)
                // TRACE[NVM629] Report the DET error NVM_E_PARAM_ADDRESS when no permanent RAM block is configured and a NULL pointer is passed via the parameter NvM_DstPtr
                // TRACE[NVM435] Same as NVM629. It includes the case where explicit synchronization is configured for this block and no NvM mirror exists
                flgDetError_b = TRUE;
                idDetError_u8 = NVM_E_PARAM_ADDRESS;
#endif
            }
        }

        else
        {
#if (NVM_DEV_ERROR_DETECT == STD_ON)
            // TRACE[NVM626] Report the DET error NVM_E_BLOCK_PENDING when NVRAM block identifier is already queued or currently in progress
            flgDetError_b = TRUE;
            idDetError_u8 = NVM_E_BLOCK_PENDING;
#endif
        }

        SchM_Exit_NvM_Main();
    }

#if (NVM_DEV_ERROR_DETECT == STD_ON)
    // Calling foreign DET function is done out of the Schm lock
    if (flgDetError_b != FALSE)
    {
        // TRACE[BSW_SWS_AR4_0_R2_NVRAMManager_Ext-3113] Set block ID used in NvM service causing last DET error
        NvM_Prv_SetBlockIdCausingLastDetError(BlockId);
        NVM_PRV_REPORT_DET_ERROR(NVM_SERVICE_ID_RESTORE_BLOCK_DEFAULTS, idDetError_u8);
    }
#endif

    // Return whether this operation was successful
    return stReturn_u8;
}

#define NVM_STOP_SEC_CODE
#include "NvM_MemMap.h"
