/* Copyright Statement:
 *
 * This software/firmware and related documentation ("AutoChips Software") are
 * protected under relevant copyright laws. The information contained herein is
 * confidential and proprietary to AutoChips Inc. and/or its licensors. Without
 * the prior written permission of AutoChips inc. and/or its licensors, any
 * reproduction, modification, use or disclosure of AutoChips Software, and
 * information contained herein, in whole or in part, shall be strictly
 * prohibited.
 *
 * AutoChips Inc. (C) 2022. All rights reserved.
 *
 * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
 * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("AUTOCHIPS SOFTWARE")
 * RECEIVED FROM AUTOCHIPS AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
 * ON AN "AS-IS" BASIS ONLY. AUTOCHIPS EXPRESSLY DISCLAIMS ANY AND ALL
 * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
 * NONINFRINGEMENT. NEITHER DOES AUTOCHIPS PROVIDE ANY WARRANTY WHATSOEVER WITH
 * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
 * INCORPORATED IN, OR SUPPLIED WITH THE AUTOCHIPS SOFTWARE, AND RECEIVER AGREES
 * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
 * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
 * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN AUTOCHIPS
 * SOFTWARE. AUTOCHIPS SHALL ALSO NOT BE RESPONSIBLE FOR ANY AUTOCHIPS SOFTWARE
 * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
 * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND AUTOCHIPS'S
 * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE AUTOCHIPS SOFTWARE
 * RELEASED HEREUNDER WILL BE, AT AUTOCHIPS'S OPTION, TO REVISE OR REPLACE THE
 * AUTOCHIPS SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
 * CHARGE PAID BY RECEIVER TO AUTOCHIPS FOR SUCH AUTOCHIPS SOFTWARE AT ISSUE.
 */

/*!
 * @file eep_drv.c
 * version: V2.2.0 EEP
 * @brief This file provides EEP integration functions.
 *
 */

/* PRQA S 3440 EOF */ /* Number of macro definitions exceeds 4095 */
/* PRQA S 3387 EOF */ /* ++,-- operator. */
/* PRQA S 0306,0303,0316 EOF */ /* Type conversion. */
/* PRQA S 2889 EOF */ /* More than one 'return'  */
/* PRQA S 1503,1505 EOF */ /* Is defined but not used. */

/* ===========================================  Includes  =========================================== */
#include "eep_drv.h"

/* ============================================  Define  ============================================ */
/* EEP group size define rule:
   1. Total EEP size (Byte) = EEP SRAM size which base address is EepRamBaseAddr
   2. The min EEP_GROUP_SIZE = EEP_SIZE (word) * 2 * EepFlashMinProByteNum
   3. EEP_FLASH_SIZE = EEP_GROUP_SIZE * Total group
*/

/* EEP operate group flag */
#define EEP_GROUP_FLAG_VALUE            (0x00000000U)

/* EEP total group number */
#define EEP_GROUPS_NUM                  (4U)

/* RAM total group number */
#define RAM_GROUPS_NUM                  (8U)

/* EEP FLASH max program unit size */
#define EEP_FLASH_MAX_UNIT_SIZE         (32U)

/* EEP FLASH max retry times */
#define EEP_FLASH_MAX_RETRY_TIMES         (3U)
/* ===========================================  Typedef  ============================================ */

/* ====================================  Functions declaration  ===================================== */
extern void Eep_Flash_LockCtrl(Eep_Hal_ConfigType *EepConfig);
extern Eep_Hal_StatusType Eep_Flash_UnlockCtrl(const Eep_Hal_ConfigType *EepConfig);
extern Eep_Hal_StatusType Eep_Flash_EraseGroup(const Eep_Hal_ConfigType *EepConfig, uint32_t Addr, uint32_t Size);
extern Eep_Hal_StatusType Eep_Flash_VerifyGroup(const Eep_Hal_ConfigType *EepConfig, uint32_t Addr, uint32_t Size);
extern Eep_Hal_StatusType Eep_Flash_Program(const Eep_Hal_ConfigType *EepConfig, uint32_t Addr, uint32_t Size, const uint8_t *Data);
extern Eep_Hal_StatusType Eep_Flash_PreInitCheck(const Eep_Hal_ConfigType *EepConfig, uint32_t RamAddr, uint32_t FlashAddr);
extern Eep_Hal_StatusType Eep_Flash_CheckBusy(const Eep_Hal_ConfigType *EepConfig);
extern uint32_t RamUintSize(const Eep_Hal_ConfigType *EepConfig);
extern Eep_Hal_StatusType CheckEepSizeAlign(const Eep_Hal_ConfigType *EepConfig);
void EepMemset(void *s, uint8_t c, uint32_t count);
void EepMemcpy(void *v_dst, const void *v_src, uint32_t c);

/* ==========================================  Variables  =========================================== */
/* PRQA S 0686,0694 ++ */ /* Array init. */
static uint16_t EepSize = 4096U;
static uint32_t EepRamBaseAddr = 0x14000000U;
static uint32_t EepFlashBaseAddr = 0x1000000U;
static uint32_t EepGroupSize = (16U * 1024U);
static uint32_t EepFlashMinProByteNum = 8U;
static uint32_t EepFlashDateByteNum = 0U;
static uint32_t CurFlashOperatAddr[RAM_GROUPS_NUM] = {0U};
static uint16_t CurFlashGroup[RAM_GROUPS_NUM] = {0U};
static uint16_t LastFlashGroup[RAM_GROUPS_NUM] = {0U};
static uint32_t EepGroupFlag[EEP_FLASH_MAX_UNIT_SIZE / 4U] = {0U};
static uint32_t EepGroupAddr[RAM_GROUPS_NUM][EEP_GROUPS_NUM][2U] = {0U};
static uint32_t RamGroupAddr[RAM_GROUPS_NUM][2U] = {0U};
static uint32_t RamUnitSize = 512U;
static Eep_Hal_ConfigType EepConfig = {4096U, 0x14000000U, 0x1000000U, 2048U, 8U, EEP_FLASH_MAX_RETRY_TIMES, EEP_HAL_AC78406, (void *)0U};

extern uint32_t EepFlashStartAddr;
extern uint32_t EepFlashEndAddr;

/* PRQA S 0686,0694 -- */ /* Array init. */
/* ======================================  Functions define  ======================================== */
void EepMemset(void *s, uint8_t c, uint32_t count)
{
   uint8_t *xs = (uint8_t *)s;
   uint32_t len = count;

    while (0x0U != len--)
    {
        *xs++ = c;
    }
}

void EepMemcpy(void *v_dst, const void *v_src, uint32_t c)
{
    uint32_t len  = c;
    const char *src = (const char *)v_src;
    char *dst = (char *)v_dst;

    /* Simple, byte oriented memcpy. */
    while (0x0U != len--)
    {
        *dst++ = *src++;
    }
}

/* PRQA S 1338 ++ */ /* Modified parameter.  */
/*!
 * @brief write data to FLASH, the Flash low 32-bit saved EEP address
 *
 * @param[in] flashAddr: write FLASH start address
 * @param[in] eepAddr: EEP address
 * @param[in] data: data pointer
 * @param[in] size: data byte number
 * @param[in] mode: 0: not write all sram data to FLASH, 1: write all sram data to FLASH
 * @return EEP operate status
 */
static Eep_Hal_StatusType WriteDataToDflash(volatile uint32_t *FlashAddr, uint32_t EepAddr,
                                      const uint8_t *Data, uint16_t Size, uint8_t Mode)
{
    Eep_Hal_StatusType Ret = EEP_HAL_SUCCESS;
    uint8_t NewCombineData[EEP_FLASH_MAX_UNIT_SIZE] = {0};
    uint16_t i, j;
    uint16_t TempSize;

    while ((Size > 0U) && (EEP_HAL_SUCCESS == Ret))
    {
        /*Filled EEP address to array newCombineData */
        for (i = 0U; i < EepFlashDateByteNum; i++)
        {
            NewCombineData[i] = (uint8_t)((EepAddr >> (i * 8U)) & 0xFFU);
        }
        TempSize = (uint16_t)EepFlashDateByteNum;
        if (Size < EepFlashDateByteNum)
        {
            TempSize = Size;
        }
        for (i = 0U; i < TempSize; i++)
        {
            NewCombineData[i + EepFlashDateByteNum] = Data[i];
        }

        for (i = TempSize; i < EepFlashDateByteNum; i++)
        {
            if ((EepAddr + i) < (EepSize + EepRamBaseAddr))
            {
                NewCombineData[i + EepFlashDateByteNum] = *(volatile uint8_t *)(EepAddr + i);
            }
            else
            {
                NewCombineData[i + EepFlashDateByteNum] = 0xFFU;
            }
        }

        if (1U == Mode)
        {
            for (i = 0U; i < EepFlashDateByteNum; i++)
            {
                if (0xFFU != NewCombineData[i + EepFlashDateByteNum])
                {
                    break;
                }
            }
        }
        if ((i < EepFlashDateByteNum) || (0U == Mode))
        {
            Ret = Eep_Flash_Program(&EepConfig, *FlashAddr, EepFlashMinProByteNum, (uint8_t *)NewCombineData);
            *FlashAddr += EepFlashMinProByteNum;
        }

        Size -= TempSize;
        for (j = 0; j < TempSize; j++)
        {
            Data++;
            EepAddr++;
        }
    }

    return Ret;
}
/* PRQA S 1338 -- */
/*!
 * @brief look for the first data which is not 0xFFFFFFFF form end to start address
 *
 * @param[in] endAddr: end address
 * @param[in] validDataAddr: valid data start address
 * @return none
 */
static void GetValidDataStartAddr(uint32_t RamGroup, uint8_t Group, volatile uint32_t *GroupOperateAddr)
{
    uint32_t i, TempSize, TempAddr, TempGroupEndAddr;

    if (0U == EepFlashMinProByteNum)
    {
        return;
    }

    TempSize = (EepGroupSize / EepFlashMinProByteNum) - 1U;
    TempGroupEndAddr = EepGroupAddr[RamGroup][Group][1U] - EepFlashMinProByteNum;
    *GroupOperateAddr = EepGroupAddr[RamGroup][Group][0U];
    for (i = 0U; i < TempSize; i++)
    {
        TempAddr = TempGroupEndAddr - ((i + 1U) * EepFlashMinProByteNum);
        /* Check address is not 0xFFFFFFFF */
        if (0xFFFFFFFFU !=  *((volatile uint32_t *)(TempAddr)))
        {
            *GroupOperateAddr = TempAddr + EepFlashMinProByteNum;
            break;
        }
    }
}

/*!
 * @brief get the flag value of operate of current group
 *
 * @param[in] group: EEP group index
 * @return the flag value
 */
static uint32_t GetEepGroupFlagVal(uint32_t RamGroup, uint16_t Group)
{
    return (*(volatile uint32_t *)(EepGroupAddr[RamGroup][Group][1U] - EepFlashMinProByteNum));
}

/*!
 * @brief check the current group index and caculate the count of the group flag
 *
 * @param[out] index: group index
 * @return the count of the group flag
 */
static uint8_t CheckOperateGroup(uint32_t RamGroup, uint8_t *Index)
{
    uint8_t Cnt  = 0U;
    uint8_t i;

    for (i = 0U; i < EEP_GROUPS_NUM; i++)
    {
        if (EEP_GROUP_FLAG_VALUE == GetEepGroupFlagVal(RamGroup, i))
        {
            Cnt++;
            *Index = i;
        }
    }

    return Cnt;
}

/*!
 * @brief Load flash data to RAM
 *
 * @param[in] group: EEP group index
 * @param[in] operateAddr: EEP group operate address
 * @return EEP operate status
 */
static Eep_Hal_StatusType LoadFlashDataToSram(uint32_t RamGroup, uint8_t Group, uint32_t OperateAddr)
{
    uint32_t i, j, RamUnitStartAddr;
    uint32_t Temp;
    Eep_Hal_StatusType Ret = EEP_HAL_SUCCESS;

    RamUnitStartAddr = EepRamBaseAddr + (RamGroup * RamUnitSize);
    for (i = EepGroupAddr[RamGroup][Group][0U]; i < OperateAddr; i += EepFlashMinProByteNum)
    {
        for (j = 0U; j < EepFlashDateByteNum; j++)
        {
            Temp = *(volatile uint32_t *)(i);
            /* maybe the temp is 0xFFFFFFFF */
            if ((Temp >= RamUnitStartAddr) && (Temp < (RamUnitStartAddr + RamUnitSize)))
            {
                *(volatile uint8_t *)(Temp + j) = *(volatile uint8_t *)(i + EepFlashDateByteNum + j);
            }
        }
    }

    return Ret;
}
/*!
 * @brief Load EEP data to SRAM from EEP group
 *
 * @param[in] curGroupOperateAddr: current group flash operate address
 * @param[in] lastGroupOperateAddr: last group flash operate address
 * @return EEP operate status
 */
static Eep_Hal_StatusType SortEepDataToSram(uint32_t RamGroup, uint32_t CurGroupOperateAddr, uint32_t LastGroupOperateAddr)
{
    Eep_Hal_StatusType Ret;
    /*
        1. Flash min width 64, 32-bit address + 32-bit data(AC784x)
        2. Flash min width 32, 32-bit address + 32-bit data(AC70x or AC781x)
        3. Flash min width 128, 32-bit address + 96-bit data(AC787x)
    */
    EepMemset((char *)((RamGroup * RamUnitSize) + EepRamBaseAddr), 0xff, RamUnitSize);

    Ret = LoadFlashDataToSram(RamGroup, (uint8_t)LastFlashGroup[RamGroup], LastGroupOperateAddr);

    if (EEP_HAL_SUCCESS == Ret)
    {
        Ret = LoadFlashDataToSram(RamGroup, (uint8_t)CurFlashGroup[RamGroup], CurGroupOperateAddr);
    }

    return Ret;
}

/*!
 * @brief update EEP group index and complete data copy
 *
 * @param[in] none
 * @return EEP operate status
 */
static Eep_Hal_StatusType UpdateOperateAddr(uint32_t RamGroup)
{
    Eep_Hal_StatusType Ret = EEP_HAL_SUCCESS;
    uint8_t Index = 0U;
    uint8_t Cnt;
    uint32_t LastGroupOperateAddr = 0U;
    uint32_t TmpCurFlashOperatAddr, CurFlashGroupIndex, LastFlashGroupIndex, TmpEepStartAddr, TmpEepEndAddr, TempAddr;

    Cnt = CheckOperateGroup(RamGroup, &Index);
    switch (Cnt)
    {
    case 0U:/* First used eep write operate flag in the first group */
        Ret = Eep_Flash_Program(&EepConfig, EepGroupAddr[RamGroup][0U][1U] - EepFlashMinProByteNum,
                                EepFlashMinProByteNum, (uint8_t *)EepGroupFlag);
        CurFlashGroup[RamGroup] = 0U;
        LastFlashGroup[RamGroup] = EEP_GROUPS_NUM - 1U;
        break;

    case 1U:
        if (0U == Index)
        {
            CurFlashGroup[RamGroup] = 0U;
            LastFlashGroup[RamGroup] = EEP_GROUPS_NUM - 1U;
        }
        else
        {
            CurFlashGroup[RamGroup] = Index;
            LastFlashGroup[RamGroup] = (uint16_t)Index - 1U;
        }
        break;

    case 2U:
        /* PRQA S 3415 ++ */
        /* indicate copy fail last time from the previous group to the next group
          then it should copy again and erase the previous group, cnt=2 so index never = 1 at least
        */
        if ((EEP_GROUP_FLAG_VALUE == GetEepGroupFlagVal(RamGroup, (uint16_t)Index - 1U)) &&
                (EEP_GROUP_FLAG_VALUE == GetEepGroupFlagVal(RamGroup, Index)))
        {
            CurFlashGroup[RamGroup] = Index;
            LastFlashGroup[RamGroup] = (uint16_t)Index - 1U;

        }/*indicate copy fail last time from the lasst group to the first group
               then it should copy again and erase the last group, index = the last group
            */
        else if
        ((EEP_GROUP_FLAG_VALUE == GetEepGroupFlagVal(RamGroup, 0U)) &&
                (EEP_GROUP_FLAG_VALUE  == GetEepGroupFlagVal(RamGroup, Index)))
        {
            CurFlashGroup[RamGroup] = 0U;
            LastFlashGroup[RamGroup] = Index;
        }
        else
        {
            Ret = EEP_HAL_OTHER_ERROR;
        }
        /* PRQA S 3415 -- */
        break;
    default:
        Ret = EEP_HAL_OTHER_ERROR;
        break;
    }
    if (EEP_HAL_SUCCESS != Ret)
    {
        return Ret;
    }

    GetValidDataStartAddr(RamGroup, (uint8_t)CurFlashGroup[RamGroup], &CurFlashOperatAddr[RamGroup]);
    GetValidDataStartAddr(RamGroup, (uint8_t)LastFlashGroup[RamGroup], &LastGroupOperateAddr);

    Ret = SortEepDataToSram(RamGroup, CurFlashOperatAddr[RamGroup], LastGroupOperateAddr);

    if ((EEP_HAL_SUCCESS == Ret) && (2U == Cnt))
    {
        CurFlashGroupIndex = CurFlashGroup[RamGroup];
        LastFlashGroupIndex = LastFlashGroup[RamGroup];
        TmpCurFlashOperatAddr = CurFlashOperatAddr[RamGroup];
        TmpEepStartAddr = EepRamBaseAddr + RamGroup * RamUnitSize;
        TmpEepEndAddr = EepRamBaseAddr + RamGroup * RamUnitSize + RamUnitSize;
        TempAddr = TmpEepStartAddr;

        /* Add protection: the last address maybe invalid, search forward.*/
        while (TmpCurFlashOperatAddr > EepGroupAddr[RamGroup][CurFlashGroupIndex][0U])
        {
            TempAddr = *(volatile uint32_t *)(TmpCurFlashOperatAddr - EepFlashMinProByteNum) + EepFlashDateByteNum;
            if ((TempAddr >= TmpEepStartAddr) && (TempAddr < TmpEepEndAddr)) /* Address Valid.*/
            {
                break;
            }
            else  /* Address InValid.*/
            {
                TmpCurFlashOperatAddr -= EepFlashMinProByteNum;  /* Search forward util to the group start address.*/
                if (EepGroupAddr[RamGroup][CurFlashGroupIndex][0U] == TmpCurFlashOperatAddr)
                {
                    TempAddr = TmpEepStartAddr;
                }
            }
        }

        Ret = WriteDataToDflash(&CurFlashOperatAddr[RamGroup], TempAddr, (uint8_t *)TempAddr,
                                (uint16_t)(TmpEepEndAddr - TempAddr), 1U);
        if (EEP_HAL_SUCCESS == Ret)
        {
            /* erase last group */
            Ret = Eep_Flash_EraseGroup(&EepConfig, EepGroupAddr[RamGroup][LastFlashGroupIndex][0U], EepGroupSize);
        }
    }

    return Ret;
}

/*!
 * @brief EEP Write
 *
 * @param[in] addr: EEP address
 * @param[in] data: data buffer pointer
 * @param[in] size: write byte number
 * @return EEP operate status
 */
static Eep_Hal_StatusType Eep_WriteExt(uint32_t RamGroup, uint32_t Addr, const uint8_t *Data, uint16_t Size)
{
    Eep_Hal_StatusType Ret;
    uint32_t LeftSize;
    uint16_t TempSize;
    uint32_t TmpCurFlashOperatAddr, CurFlashGroupIndex, RamUnitStartAddr;

    if ((0U == EepFlashMinProByteNum) || (0U == EepFlashDateByteNum))
    {
        return EEP_HAL_PARAM_ERROR;
    }

    TmpCurFlashOperatAddr = CurFlashOperatAddr[RamGroup];
    CurFlashGroupIndex = CurFlashGroup[RamGroup];
    LeftSize = (EepGroupAddr[RamGroup][CurFlashGroupIndex][1U] - EepFlashMinProByteNum - TmpCurFlashOperatAddr) / EepFlashMinProByteNum;

    /*
        check write data not enough one FLASH min write unit size - 4(EEP addr)
        According to the code, size is never more than EepFlashDateByteNum
    */
    TempSize = (uint16_t)(Size / EepFlashDateByteNum);
    if (TempSize == 0U)
    {
        TempSize = 1U;
    }

    /* check space is enough, every word combine with write address will use 8 FLASH address */
    if (LeftSize >= TempSize)
    {
        /* has enough space */
        Ret = WriteDataToDflash(&CurFlashOperatAddr[RamGroup], Addr, Data, Size, 0U);
    }
    else
    {
        /* PRQA S 3004 ++ */ /* pointer with int 0U.  */
        if (0U != EepConfig.CallbackType)
        {
            EepConfig.CallbackType();
        }
        /* PRQA S 3004 -- */
        /* verify whether next eep group is eraseed, normally
           the following erase step will not need to be executed
        */
        Ret = Eep_Flash_VerifyGroup(&EepConfig, EepGroupAddr[RamGroup][(CurFlashGroupIndex + 1U) % EEP_GROUPS_NUM][0U], EepGroupSize);
        if (EEP_HAL_SUCCESS != Ret)
        {
            Ret = Eep_Flash_EraseGroup(&EepConfig, EepGroupAddr[RamGroup][(CurFlashGroupIndex + 1U) % EEP_GROUPS_NUM][0U], EepGroupSize);
        }
        if (EEP_HAL_SUCCESS != Ret)
        {
            return Ret;
        }
        /* write group operate flag (64-bit 0) to the next group*/
        Ret = Eep_Flash_Program(&EepConfig, EepGroupAddr[RamGroup][(CurFlashGroupIndex + 1U) % EEP_GROUPS_NUM][1U] - EepFlashMinProByteNum,
                                EepFlashMinProByteNum, (uint8_t *)EepGroupFlag);
        /* write all the SRAM data to next group */
        if (EEP_HAL_SUCCESS == Ret)
        {
            CurFlashOperatAddr[RamGroup] = EepGroupAddr[RamGroup][(CurFlashGroupIndex + 1U) % EEP_GROUPS_NUM][0U];
            /* write data to the next group */
            RamUnitStartAddr = EepRamBaseAddr + (RamGroup * RamUnitSize);
            Ret = WriteDataToDflash(&CurFlashOperatAddr[RamGroup], RamUnitStartAddr, (uint8_t *)RamUnitStartAddr, (uint16_t)RamUnitSize, 1U);
        }
        /* copy current group data to next group */
        if (EEP_HAL_SUCCESS == Ret)
        {
            LastFlashGroup[RamGroup] = (uint16_t)CurFlashGroupIndex;
            CurFlashGroup[RamGroup] = (uint16_t)((CurFlashGroupIndex + 1U) % EEP_GROUPS_NUM);
            Ret = Eep_Flash_EraseGroup(&EepConfig, EepGroupAddr[RamGroup][CurFlashGroupIndex][0U], EepGroupSize);
        }
    }

    return Ret;
}

/* PRQA S 1338 ++ */ /* Modified paramter.  */
static Eep_Hal_StatusType EepWriteUnit(uint32_t RamGroup, uint32_t Addr, const uint8_t *Data, uint16_t Size)
{
    Eep_Hal_StatusType Ret;
    uint32_t i, j;
    uint32_t TempAddr ;
    uint32_t DateUnitSize;
    uint32_t RealLen;

    if ((Addr + Size) > (RamUnitSize * (RamGroup + 1U)))
    {
        return EEP_HAL_STATUS_ERROR;
    }

    Ret = Eep_Flash_UnlockCtrl(&EepConfig);

    if (0U == EepFlashDateByteNum)
    {
        return EEP_HAL_PARAM_ERROR;
    }

    while ((Size > 0U) && (EEP_HAL_SUCCESS == Ret))
    {
        DateUnitSize = EepFlashDateByteNum;
        TempAddr = Addr - (Addr % EepFlashDateByteNum);
        RealLen = EepFlashDateByteNum - (Addr % EepFlashDateByteNum);
        if (Size <  RealLen)
        {
            DateUnitSize = Size;
            RealLen = Size;
        }

        /* if current write data with EEP data is the same (the lenght is the min FLASH write uint),
            if no ,will write data, else, will write data
        */
        for (i = 0; i < RealLen; i++)
        {
            if (Data[i] != *(volatile uint8_t *)(Addr + EepRamBaseAddr + i))
            {
                break;
            }
        }

        if (i < DateUnitSize)
        {
            for (i = 0; i < RealLen; i++)
            {
                *(volatile uint8_t *)(Addr + EepRamBaseAddr + i) = Data[i];
            }
            Ret = Eep_WriteExt(RamGroup, (TempAddr + EepRamBaseAddr),
                               (uint8_t *)(TempAddr + EepRamBaseAddr), (uint16_t)DateUnitSize);
        }
        /* Update destination address */
        Addr += RealLen;
        /* Update size */
        Size -= (uint16_t)RealLen;
        /* Update data */
        for (j = 0; j < RealLen; j++)
        {
            Data++;
        }
    }
    Eep_Flash_LockCtrl(&EepConfig);

    return Ret;
}

/*!
 * @brief EEP Write
 *
 * @param[in] addr: EEP address
 * @param[in] data: data buffer pointer
 * @param[in] size: the size of write data(uint is byte)
 * @return EEP operate status
 *  0U: Successfully
 *  1U: FLASH status error, can Check error by register 0x40002000U
 *  2U: Input parameter error
 *  3U: timeout
 *  4U: other error
 */
Eep_Hal_StatusType Eep_Hal_Write(uint32_t Addr, const uint8_t *Data, uint16_t Size)
{
    Eep_Hal_StatusType Ret = EEP_HAL_SUCCESS;
    uint32_t CurAddr = Addr;
    uint32_t CurSize = Size;
    uint32_t i, j;

    if (((void *)0U == Data) || (EepSize <= Addr) || (EepSize < (Addr + Size)) || (0U == RamUnitSize))
    {
        return EEP_HAL_PARAM_ERROR;
    }

    /* PRQA S 0771 ++ */ /* More than one 'break'.  */
    for (i = (Addr / RamUnitSize); i < (EepSize / RamUnitSize); i++)
    {
        if (((CurAddr + CurSize) > RamGroupAddr[i][0]) && ((CurAddr + CurSize) <= RamGroupAddr[i][1]))
        {
            Ret = EepWriteUnit(i, CurAddr, Data, (uint16_t)CurSize);
            break;
        }
        else
        {
            CurSize = RamGroupAddr[i][1] - CurAddr;
            Ret = EepWriteUnit(i, CurAddr, Data, (uint16_t)CurSize);
            if (Ret != EEP_HAL_SUCCESS)
            {
                return Ret;
            }
            CurAddr += CurSize;
            for (j = 0; j < CurSize; j++)
            {
                Data++;
            }
            CurSize = Size - CurSize;
            if (CurSize >= Size)
            {
                break;
            }
        }
    }
    /* PRQA S 0771 -- */
    return Ret;
}
/* PRQA S 1338 -- */

/*!
 * @brief EEP read
 *
 * @param[in] addr: EEP read address
 * @param[in] data: Point to the buffer ready to read the data from EEP
 * @param[in] size: the number of read data(uint is byte)
 * @return EEP operate status
 */
Eep_Hal_StatusType Eep_Hal_Read(uint32_t Addr, uint8_t *Data, uint16_t Size)
{
    uint32_t i;

    if (((void *)0U == Data) || (EepSize <= Addr) || (EepSize < (Addr + Size)))
    {
        return EEP_HAL_STATUS_ERROR;
    }

    for (i = 0U; i < Size; i++)
    {
        /* check data effective */
        Data[i] = *(volatile uint8_t *)(EepRamBaseAddr + Addr + i);
    }

    return EEP_HAL_SUCCESS;
}

/*!
 * @brief erase all EEP space
 *
 * @param[in] none
 * @return EEP operate status
 */
Eep_Hal_StatusType Eep_Hal_Erase(void)
{
    Eep_Hal_StatusType Ret;
    uint32_t TotalSize;

    if (0x0U == RamUnitSize)
    {
        return EEP_HAL_PARAM_ERROR;
    }

    Ret = Eep_Flash_UnlockCtrl(&EepConfig);
    if (EEP_HAL_SUCCESS == Ret)
    {
        TotalSize = EepGroupSize * EEP_GROUPS_NUM * (EepSize / RamUnitSize);

        /* erase eep space */
        Ret = Eep_Flash_VerifyGroup(&EepConfig, EepFlashBaseAddr, TotalSize);
        if (EEP_HAL_SUCCESS != Ret)
        {
            Ret = Eep_Flash_EraseGroup(&EepConfig, EepFlashBaseAddr, TotalSize);
        }
    }
    if (EEP_HAL_SUCCESS == Ret)
    {
        EepMemset((char *)EepRamBaseAddr, 0xFFU, EepSize);
    }

    Eep_Flash_LockCtrl(&EepConfig);

    return Ret;
}

/*!
 * @brief EEP initialize
 *
 * @param[in] config: EEP parameter struct
 * @return EEP operate status
 */
Eep_Hal_StatusType Eep_Hal_Init(const Eep_Hal_ConfigType *Config)
{
    Eep_Hal_StatusType Ret;
    uint32_t i, j, k = 0;

    EepSize = Config->EepSize;
    EepMemcpy(&EepConfig, Config, sizeof(Eep_Hal_ConfigType));
    Ret = CheckEepSizeAlign(&EepConfig);
    if (Ret != EEP_HAL_SUCCESS)
    {
        return Ret;
    }

    EepFlashMinProByteNum = Config->FlashMinProByte;
    EepFlashDateByteNum = EepFlashMinProByteNum / 2U;
    EepFlashBaseAddr = Config->EepFlashBaseAddr;
    if ((Config->Retry > EEP_FLASH_MAX_RETRY_TIMES) || (0U == Config->Retry))
    {
        EepConfig.Retry = EEP_FLASH_MAX_RETRY_TIMES;
    }
    RamUnitSize = RamUintSize(&EepConfig);

    EepGroupSize = Config->FlashPageSize;
    EepRamBaseAddr = Config->EepRamBaseAddr;

    /* EepFlashStartAddr & EepFlashEndAddr must be initialized before UpdateOperateAddr */
    EepFlashStartAddr = EepFlashBaseAddr;
    EepFlashEndAddr = EepFlashBaseAddr + EepGroupSize * EEP_GROUPS_NUM * (EepSize / RamUnitSize);

    for (i = 0; i < (EepSize / RamUnitSize); i++)
    {
        for (j = 0U; j < EEP_GROUPS_NUM; j++)
        {
            EepGroupAddr[i][j][0U] = EepFlashBaseAddr + (k * EepGroupSize);
            EepGroupAddr[i][j][1U] = EepFlashBaseAddr + ((k + 1U) * EepGroupSize);
            k++;
        }
        RamGroupAddr[i][0U] = i * RamUnitSize;
        RamGroupAddr[i][1U] = (i + 1U) * RamUnitSize;
    }

    for (i = 0U; i < (EepFlashMinProByteNum >> 2U); i++)
    {
        EepGroupFlag[i] = EEP_GROUP_FLAG_VALUE;
    }

    Ret = Eep_Flash_PreInitCheck(&EepConfig, EepRamBaseAddr, EepFlashBaseAddr);
    if (Ret != EEP_HAL_SUCCESS)
    {
        return EEP_HAL_STATUS_ERROR;
    }

    Ret = Eep_Flash_UnlockCtrl(&EepConfig);
    if (EEP_HAL_SUCCESS == Ret)
    {
        for (i = 0; i < (EepSize / RamUnitSize); i++)
        {
            Ret = UpdateOperateAddr(i);
            if (EEP_HAL_SUCCESS != Ret)
            {
                return Ret;
            }
        }
    }

    Eep_Flash_LockCtrl(&EepConfig);

    return Ret;
}

/*!
 * @brief Get EEP lib version
 *
 * @param[in] EEP version struct
 * @return EEP operate status
 */
Eep_Hal_StatusType Eep_Hal_GetVersion(Eep_Hal_VersionType *Version)
{
    Eep_Hal_StatusType Ret = EEP_HAL_SUCCESS;

    if ((void *)0U != Version)
    {
        Version->Main = EEP_HAL_SW_MAJOR_VERSION;
        Version->Sub = EEP_HAL_SW_MINOR_VERSION;
        Version->Rev = EEP_HAL_SW_PATCH_VERSION;
        Version->Year = 2024U;
        Version->Month = 10U;
        Version->Day = 29U;
    }
    else
    {
        Ret = EEP_HAL_STATUS_ERROR;
    }

    return Ret;
}

/*!
 * @brief Reload flash data to eeprom
 *
 * @param[in] none
 * @return EEP operate status
 */
Eep_Hal_StatusType Eep_Hal_Refresh(void)
{
    Eep_Hal_StatusType Ret = EEP_HAL_SUCCESS;
    uint32_t i, LastGroupOperateAddr;

    if (0x0U == RamUnitSize)
    {
        return EEP_HAL_PARAM_ERROR;
    }

    EepMemset((char *)EepRamBaseAddr, 0xff, EepSize);

    for (i = 0; i < (EepSize / RamUnitSize); i++)
    {
        GetValidDataStartAddr(i, (uint8_t)CurFlashGroup[i], &CurFlashOperatAddr[i]);
        GetValidDataStartAddr(i, (uint8_t)LastFlashGroup[i], &LastGroupOperateAddr);

        Ret = SortEepDataToSram(i, CurFlashOperatAddr[i], LastGroupOperateAddr);
    }

    return Ret;
}

/*!
 * @brief Check EEPROM current busy status
 *
 * @param[in] none
 * @return EEP current status busy or idle
 */
Eep_Hal_StatusType Eep_Hal_CheckBusy(void)
{
    Eep_Hal_StatusType Ret;

    Ret = Eep_Flash_CheckBusy(&EepConfig);

    return Ret;
}
/* =============================================  EOF  ============================================== */
