/**
* @file    Fls_Nvr.c
*==================================================================================================
*   Project              : YTMicro AUTOSAR 4.4.0 MCAL
*   Platform             : ARM
*   Peripheral           : Fls_Nvr
*   Dependencies         : none
*
*   Autosar Version      : V4.4.0
*   Autosar Revision     : ASR_REL_4_4_REV_0000
*   SW Version           : V0.8.0
*
*   (c) Copyright 2020-2023 Yuntu Microelectronics co.,ltd.
*   All Rights Reserved.
==================================================================================================*/
#include "Fls_Types.h"
#include "pSIP_Efm.h"
#ifdef __cplusplus
extern "C"
{
#endif

/*==================================================================================================
                                              INCLUDE FILES
==================================================================================================*/
#include "SchM_Fls.h"
#include "Fls_Lld_Reg.h"
#include "Fls_Cfg.h"
#include "Fls_Nvr.h"
#include "Fls.h"

/*==================================================================================================
                                      SOURCE FILE VERSION INFORMATION
==================================================================================================*/
#define FLS_NVR_VENDOR_ID_C             		(180)
#define FLS_NVR_AR_REL_MAJOR_VER_C              (4)
#define FLS_NVR_AR_REL_MINOR_VER_C              (4)
#define FLS_NVR_AR_REL_REVISION_VER_C           (0)
#define FLS_NVR_SW_MAJOR_VER_C                  (0)
#define FLS_NVR_SW_MINOR_VER_C                  (8)
#define FLS_NVR_SW_PATCH_VER_C                  (0)
/*==================================================================================================
                                            FILE VERSION CHECKS
==================================================================================================*/
/* Check if source file and FLS_NVR header file are of the same vendor */
#if (FLS_NVR_VENDOR_ID_C != FLS_NVR_VENDOR_ID)
#error "Fls_Nvr.c and Fls_Nvr.h have different vendor ids"
#endif

/* Check if source file and FLS_NVR header file are of the same Autosar version */
#if (( FLS_NVR_AR_REL_MAJOR_VER_C != FLS_NVR_AR_REL_MAJOR_VER) || \
      ( FLS_NVR_AR_REL_MINOR_VER_C != FLS_NVR_AR_REL_MINOR_VER) || \
      ( FLS_NVR_AR_REL_REVISION_VER_C != FLS_NVR_AR_REL_REVISION_VER))
#error "AutoSar Version Numbers of Fls_Nvr.c and Fls_Nvr.h are different"
#endif

/* Check if source file and FLS_NVR header file are of the same Software version */
#if (( FLS_NVR_SW_MAJOR_VER_C != FLS_NVR_SW_MAJOR_VER) || \
      ( FLS_NVR_SW_MINOR_VER_C != FLS_NVR_SW_MINOR_VER) || \
      ( FLS_NVR_SW_PATCH_VER_C != FLS_NVR_SW_PATCH_VER))
#error "Software Version Numbers of Fls_Nvr.c and Fls_Nvr.h are different"
#endif

/*==================================================================================================
                                                GLOBAL VARIABLES
==================================================================================================*/
extern Fls_JobStateType Fls_JobState;
/*==================================================================================================
                                                LOCAL VARIABLES
==================================================================================================*/

/*==================================================================================================
                                                LOCAL CONSTANTS
==================================================================================================*/

/*==================================================================================================
                                                LOCAL MACROS
==================================================================================================*/

#define FLS_EFM_CMDUNLOCK_KEY             (0xFD9573F5U)
#if defined (CPU_YTM32B1MC0)
#define FLS_ERR_FLAGS_MASK                (EFM_STS_CMD_FAIL_MASK|\
                                        EFM_STS_ACCERR_MASK|\
                                        EFM_STS_UNRECOVERR_MASK|\
                                        EFM_STS_RECOVERR_MASK)
#elif defined (CPU_YTM32B1HA0)
#define FLS_ERR_FLAGS_MASK                (EFM_STS_FAIL_MASK|\
                                        EFM_STS_ACCERR_MASK|\
                                        EFM_STS_UNRECOVERR_MASK|\
                                        EFM_STS_RECOVERR_MASK|\
                                        EFM_STS_CI_UNRECOVERR_MASK|\
                                        EFM_STS_CI_RECOVERR_MASK)
#else
#define FLS_ERR_FLAGS_MASK                (EFM_STS_FAIL_MASK|\
                                        EFM_STS_ACCERR_MASK|\
                                        EFM_STS_UNRECOVERR_MASK|\
                                        EFM_STS_RECOVERR_MASK)
#endif
#if (FLS_WEBIT_AVAILABLE==STD_ON)
#if defined (CPU_YTM32B1HA0)
#define FLS_ADDR_SELECTED_FLAG_MASK           (EFM_STS_SET_ADDR_MASK)   /* addr selected flag */
#elif defined (CPU_YTM32B1MC0)
#define FLS_ADDR_SELECTED_FLAG_MASK           (EFM_STS_ARRAY_SELECTED_MASK)   /* addr selected flag */
#else
#endif
#endif

#if (FLS_CUS_NVR_VALID==STD_ON)
#define VALID_CUS_NVR_ADDRESS(Adress)		(((Adress) >= FLS_CUS_NVR_BASE_ADDR) && ((Adress) <= (FLS_CUS_NVR_BASE_ADDR+FLS_CUS_NVR_LENGTH)))
#endif


#if (FLS_OPT_NVR_VALID==STD_ON)
#define VALID_OPT_NVR_ADDRESS(Adress)		(((Adress) >= FLS_OPT_NVR_BASE_ADDR) && ((Adress) <= (FLS_OPT_NVR_BASE_ADDR+FLS_OPT_NVR_LENGTH)))
#endif

#if (FLS_HCU_NVR_VALID==STD_ON)
#define VALID_HCU_NVR_ADDRESS(Adress)		(((Adress) >= FLS_HCU_NVR_BASE_ADDR) && ((Adress) <= (FLS_HCU_NVR_BASE_ADDR+FLS_HCU_NVR_LENGTH)))
#endif

#define FLS_DEFAULT_VALUE           (0xFFFFFFFFU)
/*==================================================================================================
                                                LOCAL FUNCTIONS
==================================================================================================*/

#define FLS_START_SEC_RAMCODE
#include "Fls_MemMap.h"
FLS_FUNC static boolean Fls_NvrCheckErrorFlag(void)
{
    boolean TempRet = FALSE;
    if (0U != (EFM->STS & FLS_ERR_FLAGS_MASK))
    {
        TempRet = TRUE;
    }
    else
    {
        /*Nothing to do*/
    }
    return TempRet;
}
FLS_FUNC static Fls_Lld_ReturnType Fls_NvrLoadCommandSync(uint8 Command,uint32 TimeoutCnt)
{
    Fls_Lld_ReturnType TempStatus = FLASH_E_OK;
    EFM->STS =  FLS_ERR_FLAGS_MASK | EFM_STS_DONE_MASK;
    EFM->CMD_UNLOCK = FLS_EFM_CMDUNLOCK_KEY;
    EFM->CMD = Command;
#if(STD_ON == FLS_TIMEOUT_SUPERVISION_ENABLED)
    uint32 Timeout = TimeoutCnt;
    while ((EFM_STS_IDLE_MASK != (EFM->STS & EFM_STS_IDLE_MASK)) && (Timeout > 0U))
    {
        Timeout -= 1U;
    }
    if ((0U == Timeout)||(TRUE == Fls_NvrCheckErrorFlag()))
    {
        TempStatus = FLASH_E_FAILED;
    }
#else
    (void)TimeoutCnt;
    while (EFM_STS_IDLE_MASK != (EFM->STS & EFM_STS_IDLE_MASK))
    {
        /* wait until command is finished */
        __asm("NOP");/*PRQA S 1006 */
    }
    if (TRUE==Fls_NvrCheckErrorFlag())
    {
        TempStatus = FLASH_E_FAILED;
    }
#endif
    return TempStatus;
}

#define FLS_STOP_SEC_RAMCODE
#include "Fls_MemMap.h"

#define FLS_START_SEC_CODE
#include "Fls_MemMap.h"

#if (FLS_WEBIT_AVAILABLE==STD_ON)
FLS_FUNC LOCAL_INLINE boolean Fls_NvrAddrSelJudge(uint16 TimeOut)
{
    uint16 TimeOutCnt = TimeOut;
    boolean TempRet = FALSE;
    while (0U != TimeOutCnt)
    {
        if (0U != (EFM->STS & FLS_ADDR_SELECTED_FLAG_MASK))
        {
            TempRet = TRUE;
            break;
        }
        else
        {
            --TimeOutCnt;
        }
    }

    return TempRet;
}

FLS_FUNC LOCAL_INLINE void Fls_NvrWriteEnable(void)
{
    EFM->CTRL |= EFM_CTRL_WE_MASK;
    __asm("ISB");
    __asm("DSB");

}

FLS_FUNC LOCAL_INLINE void Fls_NvrWriteDisable(void)
{

    __asm("ISB");
    __asm("DSB");
    EFM->CTRL &= ~EFM_CTRL_WE_MASK;
}
#endif

FLS_FUNC static Fls_Lld_ReturnType Fls_EraseNvrFlash(Fls_AddressType Adress,uint32 CustomerKey)
{
    Fls_Lld_ReturnType RetVal = FLASH_E_OK;
    /*write cunstemor key*/
    EFM->CUS_KEY = CustomerKey;
    /*Clear command*/
    EFM->CMD = 0U;
    /*Clear all error flags*/
    EFM->STS =  FLS_ERR_FLAGS_MASK | EFM_STS_DONE_MASK;
#if (FLS_WEBIT_AVAILABLE==STD_ON)
    Fls_NvrWriteEnable();

#endif
#if defined (CPU_YTM32B1MC0)||defined (CPU_YTM32B1HA0)
    *((volatile uint32 *)Adress) = 0x00000000;
#elif defined (CPU_YTM32B1MD1)|| defined (CPU_YTM32B1ME0)
    EFM->NVR_ADDR = Adress;
#else
#endif
#if (FLS_WEBIT_AVAILABLE==STD_ON)
    Fls_NvrWriteDisable();
    if(TRUE==Fls_NvrAddrSelJudge(0x1000U))
    {
        RetVal = FLASH_E_OK;
    }
#endif

    if(FLASH_E_OK==RetVal)
    {
#if (FLS_SCHM_SUPPORT==STD_ON)
        SchM_Enter_Fls_FLS_EXCLUSIVE_AREA_00();
#endif
#if (FLS_TIMEOUT_SUPERVISION_ENABLED==STD_ON)
        RetVal = Fls_NvrLoadCommandSync(FLS_CUS_NVR_ERASE_CMD,FLS_SYNC_ERASE_TIMEOUT);
#else
        RetVal = Fls_NvrLoadCommandSync(FLS_CUS_NVR_ERASE_CMD,0);
#endif
#if (FLS_SCHM_SUPPORT==STD_ON)
        SchM_Exit_Fls_FLS_EXCLUSIVE_AREA_00();
#endif
    }
    return RetVal;
}


FLS_FUNC static Fls_Lld_ReturnType Fls_WriteNvrFlash(Fls_AddressType Adress, const uint8 * SourceAddressPtr,Fls_LengthType Length,uint32 CustomerKey)
{
    Fls_Lld_ReturnType RetVal = FLASH_E_OK;
    /*Clear command*/
    EFM->CMD = 0U;
    /*Clear all error flags*/
    EFM->STS =  FLS_ERR_FLAGS_MASK | EFM_STS_DONE_MASK;
    /*write cunstemor key*/
    EFM->CUS_KEY = CustomerKey;
#if (FLS_WEBIT_AVAILABLE==STD_ON)
    Fls_NvrWriteEnable();
#endif

    /*Write data and select the writing address*/
#if defined (CPU_YTM32B1MC0)||defined (CPU_YTM32B1HA0)
    for (uint8 LoopCnt = 0U; LoopCnt < (Length >> 2U); ++LoopCnt)
    {
        *((volatile uint32 *)(Adress + ((uint32)LoopCnt * 4U))) = *((const uint32 *)(&SourceAddressPtr[LoopCnt * 4U])); /* PRQA S 3305,0310 */
    }
#elif defined (CPU_YTM32B1MD1)|| defined (CPU_YTM32B1ME0)
    EFM->NVR_ADDR = Adress;
    EFM->NVR_DATA[0] = *((uint32 *)(SourceAddressPtr));
    EFM->NVR_DATA[1] = *((uint32 *)(SourceAddressPtr+4));
#else
#endif
#if (FLS_WEBIT_AVAILABLE==STD_ON)
    Fls_NvrWriteDisable();
    if(TRUE==Fls_NvrAddrSelJudge(0x1000U))
    {
        RetVal = FLASH_E_OK;
    }
#endif

    if(FLASH_E_OK==RetVal)
    {
#if (FLS_SCHM_SUPPORT==STD_ON)
        SchM_Enter_Fls_FLS_EXCLUSIVE_AREA_00();
#endif
#if (FLS_TIMEOUT_SUPERVISION_ENABLED==STD_ON)
        RetVal = Fls_NvrLoadCommandSync(FLS_CUS_NVR_WRITE_CMD,FLS_SYNC_WRITE_TIMEOUT);
#else
        RetVal = Fls_NvrLoadCommandSync(FLS_CUS_NVR_WRITE_CMD,0);
#endif
#if (FLS_SCHM_SUPPORT==STD_ON)
        SchM_Exit_Fls_FLS_EXCLUSIVE_AREA_00();
#endif
    }
    return RetVal;
}


FLS_FUNC static Fls_Lld_ReturnType Fls_ReadNvrFlash(Fls_AddressType Adress, uint8 * DestinationAddressPtr,Fls_LengthType Length, uint32 CustomerKey)
{
    Fls_Lld_ReturnType RetVal = FLASH_E_OK;

#if defined (CPU_YTM32B1MD1)|| defined (CPU_YTM32B1ME0)
    /*write cunstemor key*/
    EFM->CUS_KEY = CustomerKey;
    /*Clear command*/
    EFM->CMD = 0U;
    /*Clear all error flags*/
    EFM->STS =  FLS_ERR_FLAGS_MASK | EFM_STS_DONE_MASK;

    EFM->NVR_ADDR = Adress;
#if (FLS_SCHM_SUPPORT==STD_ON)
    SchM_Enter_Fls_FLS_EXCLUSIVE_AREA_00();
#endif
#if (FLS_TIMEOUT_SUPERVISION_ENABLED==STD_ON)
    RetVal = Fls_NvrLoadCommandSync(FLS_CUS_NVR_READ_CMD,FLS_SYNC_WRITE_TIMEOUT);
#else
    RetVal = Fls_NvrLoadCommandSync(FLS_CUS_NVR_READ_CMD,0);
#endif
#if (FLS_SCHM_SUPPORT==STD_ON)
    SchM_Exit_Fls_FLS_EXCLUSIVE_AREA_00();
#endif
    if(FLASH_E_OK==RetVal)
    {
        *((uint32 *)DestinationAddressPtr)= EFM->NVR_DATA[0];
        *((uint32 *)(DestinationAddressPtr+4))= EFM->NVR_DATA[1];
    }

#elif defined (CPU_YTM32B1MC0)||defined (CPU_YTM32B1HA0)
    Fls_LengthType TempCnt = 0;
    /*write cunstemor key*/
    EFM->CUS_KEY = CustomerKey;

    /*Read data*/
    while(TempCnt<Length)
    {
        DestinationAddressPtr[TempCnt] = *((volatile uint8 *)(Adress + TempCnt));
        ++TempCnt;
    }
#else

#endif
    return RetVal;
}
FLS_FUNC static Fls_Lld_ReturnType Fls_ReadOptFlash(Fls_AddressType Adress, uint8 * DestinationAddressPtr,Fls_LengthType Length)
{
    Fls_Lld_ReturnType RetVal = FLASH_E_OK;

#if defined (CPU_YTM32B1MD1)|| defined (CPU_YTM32B1ME0)
    /*Clear all error flags*/
    EFM->STS =  FLS_ERR_FLAGS_MASK | EFM_STS_DONE_MASK;
    /*Clear command*/
    EFM->CMD = 0U;
    EFM->NVR_ADDR = Adress;
#if (FLS_SCHM_SUPPORT==STD_ON)
    SchM_Enter_Fls_FLS_EXCLUSIVE_AREA_00();
#endif
#if (FLS_TIMEOUT_SUPERVISION_ENABLED==STD_ON)
    RetVal = Fls_NvrLoadCommandSync(FLS_CUS_NVR_READ_CMD,FLS_SYNC_WRITE_TIMEOUT);
#else
    RetVal = Fls_NvrLoadCommandSync(FLS_CUS_NVR_READ_CMD,0);
#endif
#if (FLS_SCHM_SUPPORT==STD_ON)
    SchM_Exit_Fls_FLS_EXCLUSIVE_AREA_00();
#endif
    if(FLASH_E_OK==RetVal)
    {
        *((uint32 *)DestinationAddressPtr)= EFM->NVR_DATA[0];
        *((uint32 *)(DestinationAddressPtr+4))= EFM->NVR_DATA[1];
    }

#elif defined (CPU_YTM32B1MC0)||defined (CPU_YTM32B1HA0)
    Fls_LengthType TempCnt = 0;
    /*Read data*/
    while(TempCnt<Length)
    {
        DestinationAddressPtr[TempCnt] = *((volatile uint8 *)(Adress + TempCnt));
        ++TempCnt;
    }
#else

#endif
    return RetVal;
}


FLS_FUNC static Fls_Lld_ReturnType Fls_WriteOptFlash(Fls_AddressType Adress, const uint8 * SourceAddressPtr,Fls_LengthType Length)
{
    Fls_Lld_ReturnType RetVal = FLASH_E_OK;
    /*Clear command*/
    EFM->CMD = 0U;
    /*Clear all error flags*/
    EFM->STS =  FLS_ERR_FLAGS_MASK | EFM_STS_DONE_MASK;
#if (FLS_WEBIT_AVAILABLE==STD_ON)
    Fls_NvrWriteEnable();
#endif

    /*Write data and select the writing address*/
#if defined (CPU_YTM32B1MC0)||defined (CPU_YTM32B1HA0)
    for (uint8 LoopCnt = 0U; LoopCnt < (Length >> 2U); ++LoopCnt)
    {
        *((volatile uint32 *)(Adress + ((uint32)LoopCnt * 4U))) = *((const uint32 *)(&SourceAddressPtr[LoopCnt * 4U])); /* PRQA S 3305,0310 */
    }
#elif defined (CPU_YTM32B1MD1)|| defined (CPU_YTM32B1ME0)
    EFM->NVR_ADDR = Adress;
    EFM->NVR_DATA[0] = *((uint32 *)(SourceAddressPtr));
    EFM->NVR_DATA[1] = *((uint32 *)(SourceAddressPtr+4));
#else
#endif
#if (FLS_WEBIT_AVAILABLE==STD_ON)
    Fls_NvrWriteDisable();
    if(TRUE==Fls_NvrAddrSelJudge(0x1000U))
    {
        RetVal = FLASH_E_OK;
    }
#endif

    if(FLASH_E_OK==RetVal)
    {
#if (FLS_SCHM_SUPPORT==STD_ON)
        SchM_Enter_Fls_FLS_EXCLUSIVE_AREA_00();
#endif
#if (FLS_TIMEOUT_SUPERVISION_ENABLED==STD_ON)
        RetVal = Fls_NvrLoadCommandSync(FLS_CUS_NVR_WRITE_CMD,FLS_SYNC_WRITE_TIMEOUT);
#else
        RetVal = Fls_NvrLoadCommandSync(FLS_CUS_NVR_WRITE_CMD,0);
#endif
#if (FLS_SCHM_SUPPORT==STD_ON)
        SchM_Exit_Fls_FLS_EXCLUSIVE_AREA_00();
#endif
    }
    return RetVal;
}
/*==================================================================================================
                                                GLOBAL FUNCTIONS
==================================================================================================*/
#if (FLS_CUS_NVR_VALID == STD_ON)
FLS_FUNC Fls_Lld_ReturnType Fls_WriteCusNvr(Fls_AddressType Adress, const uint8 * SourceAddressPtr,Fls_LengthType Length,uint32 CustomerKey)
{
    Fls_Lld_ReturnType RetVal = FLASH_E_OK;

    /*Check fls module state and input parameters are valid*/
    if((MEMIF_JOB_PENDING != Fls_JobState.JobResult)&&
            (TRUE==VALID_CUS_NVR_ADDRESS(Adress))&&
            (TRUE==VALID_CUS_NVR_ADDRESS(Adress+Length))&&
            (Length!=0U)&&(0U==(Length%FLS_CUS_NVR_PAGE_SIZE))&&
            (SourceAddressPtr!=NULL_PTR))
    {
        Fls_LengthType RemainLength = Length;
        Fls_LengthType WriteLength = 0;
        Fls_AddressType WriteAddress = Adress;
        const uint8 *  DataPtr = SourceAddressPtr;

        while((RemainLength!=0U)&&(FLASH_E_OK==RetVal))
        {
            WriteLength = (RemainLength>FLS_CUS_NVR_PAGE_SIZE)?FLS_CUS_NVR_PAGE_SIZE:RemainLength;

            RetVal = Fls_WriteNvrFlash(WriteAddress,DataPtr,WriteLength,CustomerKey);
            if(FLASH_E_OK == RetVal)
            {
                RemainLength -= WriteLength;
                WriteAddress += WriteLength;
                DataPtr += WriteLength;
            }
        }
    }
    else
    {
        RetVal = FLASH_E_FAILED;
    }

    return RetVal;
}
FLS_FUNC Fls_Lld_ReturnType Fls_EraseCusNvr(uint32 CustomerKey)
{
    Fls_Lld_ReturnType RetVal = FLASH_E_FAILED;
    if(Fls_JobState.JobResult != MEMIF_JOB_PENDING)
    {
        RetVal = Fls_EraseNvrFlash(FLS_CUS_NVR_BASE_ADDR,CustomerKey);
    }
    return RetVal;
}

FLS_FUNC Fls_Lld_ReturnType Fls_ReadCusNvr(Fls_AddressType Adress, uint8 * TargetAddressPtr,Fls_LengthType Length,uint32 CustomerKey)
{
    Fls_Lld_ReturnType RetVal = FLASH_E_OK;

    /*Check the fls status and adress valid*/
    if((Fls_JobState.JobResult != MEMIF_JOB_PENDING)&&
            (TRUE==VALID_CUS_NVR_ADDRESS(Adress))&&
            (TRUE==VALID_CUS_NVR_ADDRESS(Adress+Length))&&
#if defined (CPU_YTM32B1MD1)|| defined (CPU_YTM32B1ME0)
            (Length!=0U)&&(0U==(Length%FLS_CUS_NVR_PAGE_SIZE))&&
#elif defined (CPU_YTM32B1MC0)||defined (CPU_YTM32B1HA0)
            (Length!=0U)&&
#endif
            (TargetAddressPtr!=NULL_PTR))
    {
        Fls_LengthType RemainLength = Length;
        Fls_LengthType ReadLength = 0;
        Fls_AddressType ReadAddress = Adress;
        uint8 *  DataPtr = TargetAddressPtr;
        while((RemainLength!=0U)&&(FLASH_E_OK==RetVal))
        {
#if defined (CPU_YTM32B1MD1)|| defined (CPU_YTM32B1ME0)
            ReadLength = (RemainLength>FLS_CUS_NVR_PAGE_SIZE)?FLS_CUS_NVR_PAGE_SIZE:RemainLength;
#elif defined (CPU_YTM32B1MC0)||defined (CPU_YTM32B1HA0)
            ReadLength = RemainLength;
#endif
            RetVal = Fls_ReadNvrFlash(ReadAddress,DataPtr,ReadLength,CustomerKey);
            if(FLASH_E_OK == RetVal)
            {
                RemainLength -= ReadLength;
                ReadAddress += ReadLength;
                DataPtr += ReadLength;
            }
        }

    }
    else
    {
        RetVal = FLASH_E_FAILED;
    }
    return RetVal;
}
#endif


#if defined (CPU_YTM32B1ME0)
FLS_FUNC Fls_Lld_ReturnType Fls_WriteSwap(void)
{
    Fls_Lld_ReturnType RetVal = FLASH_E_OK;
    /*Clear command*/
    EFM->CMD = 0U;
    /*Clear all error flags*/
    EFM->STS =  FLS_ERR_FLAGS_MASK | EFM_STS_DONE_MASK;
#if (FLS_WEBIT_AVAILABLE==STD_ON)
    Fls_NvrWriteEnable();
#endif

#if (FLS_WEBIT_AVAILABLE==STD_ON)
    Fls_NvrWriteDisable();
    if(TRUE==Fls_NvrAddrSelJudge(0x1000U))
    {
        RetVal = FLASH_E_OK;
    }
#endif
    if(FLASH_E_OK==RetVal)
    {
#if (FLS_SCHM_SUPPORT==STD_ON)
        SchM_Enter_Fls_FLS_EXCLUSIVE_AREA_00();
#endif
#if (FLS_TIMEOUT_SUPERVISION_ENABLED==STD_ON)
        RetVal = Fls_NvrLoadCommandSync(FLS_BOOT_SWAP_CMD,FLS_SYNC_WRITE_TIMEOUT);
#else
        RetVal = Fls_NvrLoadCommandSync(FLS_BOOT_SWAP_CMD,0);
#endif
#if (FLS_SCHM_SUPPORT==STD_ON)
        SchM_Exit_Fls_FLS_EXCLUSIVE_AREA_00();
#endif
    }
    return RetVal;
}

FLS_FUNC Fls_Lld_ReturnType Fls_ReadSwap(uint8 * DestinationAddressPtr)
{
    Fls_Lld_ReturnType RetVal = FLASH_E_OK;
    DestinationAddressPtr[0] = (EFM->STS & EFM_STS_BOOT_INFO_MASK) >> EFM_STS_BOOT_INFO_SHIFT;
    return RetVal;
}
#endif



#if (FLS_OPT_NVR_VALID==STD_ON)
FLS_FUNC Fls_Lld_ReturnType Fls_WriteOptNvr(Fls_AddressType Adress, const uint8 * SourceAddressPtr,Fls_LengthType Length)
{
    Fls_Lld_ReturnType RetVal = FLASH_E_OK;

    /*Check fls module state and input parameters are valid*/
    if((MEMIF_JOB_PENDING != Fls_JobState.JobResult)&&
            (TRUE==VALID_OPT_NVR_ADDRESS(Adress))&&
            (TRUE==VALID_OPT_NVR_ADDRESS(Adress+Length))&&
            (Length!=0U)&&(0U==(Length%FLS_OPT_NVR_PAGE_SIZE))&&
            (SourceAddressPtr!=NULL_PTR))
    {
        Fls_LengthType RemainLength = Length;
        Fls_LengthType WriteLength = 0;
        Fls_AddressType WriteAddress = Adress;
        const uint8 *  DataPtr = SourceAddressPtr;

        while((RemainLength!=0U)&&(FLASH_E_OK==RetVal))
        {
            WriteLength = (RemainLength>FLS_OPT_NVR_PAGE_SIZE)?FLS_OPT_NVR_PAGE_SIZE:RemainLength;

            RetVal = Fls_WriteOptFlash(WriteAddress,DataPtr,WriteLength);
            if(FLASH_E_OK == RetVal)
            {
                RemainLength -= WriteLength;
                WriteAddress += WriteLength;
                DataPtr += WriteLength;
            }
        }
    }
    else
    {
        RetVal = FLASH_E_FAILED;
    }

    return RetVal;
}

FLS_FUNC Fls_Lld_ReturnType Fls_ReadOptNvr(Fls_AddressType Adress, uint8 * TargetAddressPtr,Fls_LengthType Length)
{
    Fls_Lld_ReturnType RetVal = FLASH_E_OK;

    /*Check the fls status and adress valid*/
    if((Fls_JobState.JobResult != MEMIF_JOB_PENDING)&&
            (TRUE==VALID_OPT_NVR_ADDRESS(Adress))&&
            (TRUE==VALID_OPT_NVR_ADDRESS(Adress+Length))&&
#if defined (CPU_YTM32B1MD1)|| defined (CPU_YTM32B1ME0)
            (Length!=0U)&&(0U==(Length%FLS_OPT_NVR_PAGE_SIZE))&&
#elif defined (CPU_YTM32B1MC0)||defined (CPU_YTM32B1HA0)
            (Length!=0U)&&
#endif
            (TargetAddressPtr!=NULL_PTR))
    {
        Fls_LengthType RemainLength = Length;
        Fls_LengthType ReadLength = 0;
        Fls_AddressType ReadAddress = Adress;
        uint8 *  DataPtr = TargetAddressPtr;
        while((RemainLength!=0U)&&(FLASH_E_OK==RetVal))
        {
#if defined (CPU_YTM32B1MD1)|| defined (CPU_YTM32B1ME0)
            ReadLength = (RemainLength>FLS_OPT_NVR_PAGE_SIZE)?FLS_OPT_NVR_PAGE_SIZE:RemainLength;
#elif defined (CPU_YTM32B1MC0)||defined (CPU_YTM32B1HA0)
            ReadLength = RemainLength;
#endif
            RetVal = Fls_ReadOptFlash(ReadAddress,DataPtr,ReadLength);
            if(FLASH_E_OK == RetVal)
            {
                RemainLength -= ReadLength;
                ReadAddress += ReadLength;
                DataPtr += ReadLength;
            }
        }

    }
    else
    {
        RetVal = FLASH_E_FAILED;
    }
    return RetVal;
}
#endif

#if (FLS_HCU_NVR_VALID == STD_ON)
FLS_FUNC Fls_Lld_ReturnType Fls_WriteHcuNvr(Fls_AddressType Adress, const uint8 * SourceAddressPtr,Fls_LengthType Length)
{
    Fls_Lld_ReturnType RetVal = FLASH_E_OK;

    /*Check fls module state and input parameters are valid*/
    if((MEMIF_JOB_PENDING != Fls_JobState.JobResult)&&
            (TRUE==VALID_HCU_NVR_ADDRESS(Adress))&&
            (TRUE==VALID_HCU_NVR_ADDRESS(Adress+Length))&&
            (Length!=0U)&&(0U==(Length%FLS_HCU_NVR_PAGE_SIZE))&&
            (SourceAddressPtr!=NULL_PTR))
    {
        Fls_LengthType RemainLength = Length;
        Fls_LengthType WriteLength = 0;
        Fls_AddressType WriteAddress = Adress;
        const uint8 *  DataPtr = SourceAddressPtr;

        while((RemainLength!=0U)&&(FLASH_E_OK==RetVal))
        {
            WriteLength = (RemainLength>FLS_HCU_NVR_PAGE_SIZE)?FLS_HCU_NVR_PAGE_SIZE:RemainLength;

            RetVal = Fls_WriteOptFlash(WriteAddress,DataPtr,WriteLength);
            if(FLASH_E_OK == RetVal)
            {
                RemainLength -= WriteLength;
                WriteAddress += WriteLength;
                DataPtr += WriteLength;
            }
        }
    }
    else
    {
        RetVal = FLASH_E_FAILED;
    }

    return RetVal;
}

FLS_FUNC Fls_Lld_ReturnType Fls_EraseHcuNvr(Fls_AddressType Adress,Fls_LengthType Length,uint32 CustomerKey)
{
    Fls_Lld_ReturnType RetVal = FLASH_E_OK;
    if((Fls_JobState.JobResult != MEMIF_JOB_PENDING)&&
            (TRUE==VALID_HCU_NVR_ADDRESS(Adress))&&
            (TRUE==VALID_HCU_NVR_ADDRESS(Adress+Length))&&
            (Length!=0U)&&(0U==(Length%FLS_HCU_NVR_SECTOR_SIZE)))
    {
        Fls_LengthType RemainLength = Length;
        Fls_AddressType EraseAddress = Adress;
        while((RemainLength!=0U)&&(FLASH_E_OK==RetVal))
        {
            RetVal = Fls_EraseNvrFlash(EraseAddress,CustomerKey);
            if(FLASH_E_OK == RetVal)
            {
                RemainLength -= FLS_HCU_NVR_SECTOR_SIZE;
                EraseAddress += FLS_HCU_NVR_SECTOR_SIZE;
            }
        }
    }
    else {
        RetVal = FLASH_E_FAILED;
    }
    return RetVal;
}
#endif


#define FLS_STOP_SEC_CODE
#include "Fls_MemMap.h"
#ifdef __cplusplus
}
#endif

/* End of file Fls_Nvr.c */
