/*!
 * @file        flash_eeprom.c
 *
 * @brief       This file contains all the functions for the eeprom emulation.
 *
 * @version     V1.0.0
 *
 * @date        2026-02-25
 *
 * @attention
 *
 *  Copyright (C) 2026 Geehy Semiconductor
 *
 *  You may not use this file except in compliance with the
 *  GEEHY COPYRIGHT NOTICE (Geehy Semiconductor Software License Agreement).
 *
 *  The program is only for reference, which is distributed in the hope
 *  that it will be useful and instructional for customers to develop
 *  their software. Unless required by applicable law or agreed to in
 *  writing, the program is distributed on an "AS IS" BASIS, WITHOUT
 *  ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the Geehy Semiconductor Software License Agreement for the governing permissions
 *  and limitations under the License.
 */

/* Includes */
#include "flash_eeprom.h"

/** @addtogroup Examples
  @{
*/

/** @addtogroup FLASH_Examples
  @{
*/

/** @addtogroup FMC_Flash_EEPROM
  @{
*/

/** @defgroup FMC_Flash_EEPROM_Functions Functions
  @{
*/

/*!
* @brief       Get valid Page for write or read operation.
*
* @param       mode: Get valid pages in read and write mode.
*                    This parameter can be any combination of the flowing values:
*                    @arg GET_VALID_PAGE_READ
*                    @arg GET_VALID_PAGE_WRITE
*
* @retval      Returns valid page number. It can be one of value:
*                    @arg PAGE0_VALID
*                    @arg PAGE1_VALID
*                    @arg NO_VALID_PAGE
*
* @note
*/
static uint32_t Flash_EE_FindValidPage(uint8_t Mode)
{
    uint32_t pageStatus0 = 0U;
    uint32_t pageStatus1 = 0U;
    uint32_t tempReturn = NO_VALID_PAGE;

    /* Get Page0 status */
    pageStatus0 = (*(__IO uint32_t*)PAGE0_START_ADDRESS);

    /* Get Page1 status */
    pageStatus1 = (*(__IO uint32_t*)PAGE1_START_ADDRESS);

    if (Mode == GET_VALID_PAGE_WRITE)
    {
        if (pageStatus0 == PAGE_STATUS_TRANSFER)
        {
            /* Page0 is valid */
            tempReturn = PAGE0_VALID;
        }
        else if (pageStatus1 == PAGE_STATUS_TRANSFER)
        {
            /* Page1 is valid */
            tempReturn = PAGE1_VALID;
        }
        else if (pageStatus0 == PAGE_STATUS_VALID)
        {
            /* Page0 is valid */
            tempReturn = PAGE0_VALID;
        }
        else if (pageStatus1 == PAGE_STATUS_VALID)
        {
            /* Page1 is valid */
            tempReturn = PAGE1_VALID;
        }
        else
        {
            /* no valid page found */
            tempReturn = NO_VALID_PAGE;
        }
    }
    else if (Mode == GET_VALID_PAGE_READ)
    {
        if (pageStatus0 == PAGE_STATUS_VALID)
        {
            /* Page0 is valid */
            tempReturn = PAGE0_VALID;
        }
        else if (pageStatus1 == PAGE_STATUS_VALID)
        {
            /* Page1 is valid */
            tempReturn = PAGE1_VALID;
        }
        else
        {
            /* no valid page found */
            tempReturn = NO_VALID_PAGE;
        }
    }
    else
    {
        /* no valid page found */
        tempReturn = NO_VALID_PAGE;
    }
    
    return tempReturn;
}

/*!
* @brief       Erase flash eeprom page, can erase multiple pages.
*
* @param       PageAddr: Erase page base address. 
*                        This parameter can be any combination of the flowing values:
*                        @arg PAGE0_START_ADDRESS
*                        @arg PAGE1_START_ADDRESS
*
* @retval      Returns the fmc status. The value refer to Fmc_StateType.
*
* @note
*/
static Fmc_StateType Flash_EE_PageErase(uint32_t PageAddr)
{
    uint16_t i = 0;
    uint32_t eraseAddr = 0;
    Fmc_StateType flashStatus = FMC_STATE_COMPLETE;

    /* Erase one or more flash pages */
    for(i = 0; i < FLASH_EE_PAGE_NUM; i++)
    {
        /* Calculate the erase page address */
        eraseAddr = PageAddr + (i * G32_FLASH_PAGE_SIZE);

        flashStatus = Fmc_ErasePage(eraseAddr);

        if (flashStatus != FMC_STATE_COMPLETE)
        {
            break;
        }
        else
        {
            /* nothing */
        }
    }

    return flashStatus;
}

/*!
* @brief       Erases PAGE0 and PAGE1 and writes PAGE_STATUS_VALID header to PAGE0.
*
* @param       None
*
* @retval      Returns the fmc status. The value refer to Fmc_StateType.
*
* @note
*/
static Fmc_StateType Flash_EE_Format(void)
{
    Fmc_StateType flashStatus = FMC_STATE_COMPLETE;
    Fmc_StateType tempVal = FMC_STATE_COMPLETE;
    uint32_t data[2] = {0, 0};

    /* Erase Page0 */
    flashStatus = Flash_EE_PageErase(PAGE0_START_ADDRESS);

    if (flashStatus != FMC_STATE_COMPLETE)
    {
        tempVal = flashStatus;
    }
    else
    {
        /* Erase Page1 */
        flashStatus = Flash_EE_PageErase(PAGE1_START_ADDRESS);
        if (flashStatus != FMC_STATE_COMPLETE)
        {
            tempVal = flashStatus;
        }
        else
        {
            data[0] = PAGE_STATUS_VALID;
            data[1] = PAGE_STATUS_ERASED;

            /* Set Page0 as valid page */
            tempVal = Fmc_ProgramWord(PAGE0_START_ADDRESS, (uint32_t)FMC_LEN_64BIT, data);
        }
    }
    return tempVal;
}

/*!
* @brief       Verify Flash EEPROM page status.
*
* @param       PageStatus0: Page0 status.
*
* @param       PageStatus1: Page1 status.
*
* @retval      The returned value can be: 0 or 1.
*              @arg 0: the page status format correct.
*              @arg 1: the page status format incorrect.
*
* @note
*/
static uint16_t Flash_EE_PageStatusCheck(uint32_t PageStatus0, uint32_t PageStatus1)
{
    uint16_t tempVal = 0;

    /* the euqal status is invalid */
    if (PageStatus0 == PageStatus1)
    {
        tempVal = 1;
    }
    else
    {
        /* Page0 status is not known status */
        if ((PageStatus0 != PAGE_STATUS_ERASED) && \
            (PageStatus0 != PAGE_STATUS_TRANSFER) && \
            (PageStatus0 != PAGE_STATUS_VALID))
        {
            tempVal = 1;
        }
        else
        {
            /* Page1 status is not known status */
            if ((PageStatus1 != PAGE_STATUS_ERASED) && \
                (PageStatus1 != PAGE_STATUS_TRANSFER) && \
                (PageStatus1 != PAGE_STATUS_VALID))
            {
                tempVal = 1;
            }
            else
            {
                /* Format is correct */
                tempVal = 0;
            }
        }
    }
    return tempVal;
}

/*!
* @brief       Not verify page full, Writes variable and virtual address in Flash EEPROM.
*
* @param       VirtAddress: the variable virtual address.
*                           Virtual address value must be between 0 ~ NUMBER_OF_VARIABLES.
*
* @param       Data: the variable value.
*
* @retval      Returns the fmc status. The value refer to Fmc_StateType.
*
* @note
*/
static Fmc_StateType Flash_EE_NotVerifyPageFullWriteData(uint32_t VirtAddress, uint32_t Data)
{
    uint32_t Address = 0;
    uint32_t PageEndAddress = 0;
    uint32_t validPage = 0;
    uint32_t data[2] = {0, 0};
    Fmc_StateType flashStatus = FMC_STATE_COMPLETE;
    Fmc_StateType tempReturn = FMC_STATE_COMPLETE;

    /* Get the valid page for write operation */
    validPage = Flash_EE_FindValidPage(GET_VALID_PAGE_WRITE);

    if (validPage == NO_VALID_PAGE)
    {
        tempReturn = FMC_STATE_PG_ERR;
    }
    else
    {
        /* Calculate the valid Page start Address */
        Address = FLASH_EE_START_ADDRESS + (validPage * FLASH_EE_PAGE_SIZE);

        /* Calculate the valid Page end Address */
        PageEndAddress  = FLASH_EE_START_ADDRESS + (validPage * FLASH_EE_PAGE_SIZE) + FLASH_EE_PAGE_SIZE - 4U;

        while (Address < PageEndAddress)
        {
            /* Verify if Address and Address+4 contents are 0xFFFFFFFF */
            if ( ((*(__IO uint32_t*)Address) == 0xFFFFFFFFU) && ((*(__IO uint32_t*)(Address + 4U)) == 0xFFFFFFFFU) )
            {
                data[0] = Data;
                data[1] = VirtAddress;
                
                /* write data to flash */
                flashStatus = Fmc_ProgramWord(Address, (uint32_t)FMC_LEN_64BIT, data);

                tempReturn = flashStatus;
                break;
            }
            else
            {
                /* Next address location */
                Address += 8U;
            }
        }
    }
    return tempReturn;
}

/*!
* @brief       Transfers valid(last updated) variables data from the full Page to an empty one.
*
* @param       None
*
* @retval      Returns the fmc status. The value refer to Fmc_StateType.
*
* @note
*/
static Fmc_StateType Fmc_TransferToNewActPage(const uint32_t (*status)[2])
{
    Fmc_StateType tempReturn = FMC_STATE_COMPLETE;
    Fmc_StateType flashStatus = FMC_STATE_COMPLETE;
    uint32_t VirtAddr = 0;

    /* Transfer process: transfer variables from old to the new active page */
    for (VirtAddr = 0; VirtAddr < NUMBER_OF_VARIABLES; VirtAddr++)
    {
        /* Find valid variables: the last updated variable */
        if (status[VirtAddr][0] == 1U)
        {
            /* Transfer the variable to the new active page */
            flashStatus = Flash_EE_NotVerifyPageFullWriteData(VirtAddr, status[VirtAddr][1]);
            if (flashStatus != FMC_STATE_COMPLETE)
            {
                tempReturn = flashStatus;
                break;
            }
            else
            {
                /* nothing */
            }
        }
        else
        {
            /* nothing */
        }
    }

    return tempReturn;
} 

/*!
* @brief       Transfers valid(last updated) variables data from the full Page to an empty one.
*
* @param       None
*
* @retval      Returns the fmc status. The value refer to Fmc_StateType.
*
* @note
*/
static Fmc_StateType Flash_EE_TransferToActivePage(void)
{
    uint32_t fullPageAddress = 0;
    uint32_t emptyPageAddress = 0;
    uint32_t readData = 0;
    uint32_t validPage = NO_VALID_PAGE;
    uint32_t data[2] = {0, 0};
    uint32_t status[FLASH_EE_PAGE_SIZE / 8U][2];
    Fmc_StateType flashStatus = FMC_STATE_COMPLETE;
    Fmc_StateType tempReturn = FMC_STATE_COMPLETE;
    
    /* This vitual address corresponds to the vitual address written by the user */
    uint32_t VirtAddr = 0;


    /* Get valid Page for read operation */
    validPage = Flash_EE_FindValidPage(GET_VALID_PAGE_READ);

    if ((validPage != PAGE0_VALID) && (validPage != PAGE1_VALID))
    {
        tempReturn = FMC_STATE_PG_ERR;
    }
    else
    {
        switch(validPage)
        {
            case PAGE0_VALID:
                /* Empty page is Page1 */
                emptyPageAddress = PAGE1_START_ADDRESS;

                /* Full page is Page0 */
                fullPageAddress = PAGE0_START_ADDRESS;
            break;
            
            case PAGE1_VALID:
                /* Empty page is Page0 */
                emptyPageAddress = PAGE0_START_ADDRESS;

                /* Full page is Page1 */
                fullPageAddress = PAGE1_START_ADDRESS;
            break;

            default:
                {
                    /* do nothing */
                }
            break;            
        }
        
        data[0] =  PAGE_STATUS_TRANSFER;
        data[1] =  PAGE_STATUS_ERASED;

        /* Set the empty Page status as transfer status */
        flashStatus = Fmc_ProgramWord(emptyPageAddress, (uint32_t)FMC_LEN_64BIT, data);
        if (flashStatus != FMC_STATE_COMPLETE)
        {
            tempReturn = flashStatus;
        }
        else
        {
            /* Transfer process: record the old variables */
            for (VirtAddr = 0; VirtAddr < NUMBER_OF_VARIABLES; VirtAddr++)
            {
                /* Find valid variables: the last updated variable */
                if (Flash_EE_ReadData(VirtAddr, &readData) == 0U)
                {
                    status[VirtAddr][0] = 1;
                    status[VirtAddr][1] = readData;
                }
                else
                {
                    status[VirtAddr][0] = 0;
                }
            
            }
            
            /* Erase the empty page */
            flashStatus = Flash_EE_PageErase(emptyPageAddress);
            if (flashStatus != FMC_STATE_COMPLETE)
            {
                tempReturn = flashStatus;
            }
            else
            {
                /* Erase the old page */
                flashStatus = Flash_EE_PageErase(fullPageAddress);
                if (flashStatus != FMC_STATE_COMPLETE)
                {
                    tempReturn = flashStatus;
                }
                else
                {
                    data[0] =  PAGE_STATUS_VALID;
                    data[1] =  PAGE_STATUS_ERASED;
                    
                    /* Mark empty page status as valid */
                    flashStatus = Fmc_ProgramWord(emptyPageAddress, (uint32_t)FMC_LEN_64BIT, data);
                    if (flashStatus != FMC_STATE_COMPLETE)
                    {
                        tempReturn = flashStatus;
                    }
                    else
                    {
                        /* Transfer process: transfer variables from old to the new active page */
                        tempReturn = Fmc_TransferToNewActPage((const uint32_t (*)[2])status);
                    }
                }
            }
        }
    }
    return tempReturn;
}

/*!
* @brief       Check if the page is full. If the page is full, Transfers valid variables data to empty page.
*
* @param       None
*
* @retval      Returns the fmc status. The value refer to Fmc_StateType.
*
* @note
*/
static Fmc_StateType Flash_EE_FullCheck(void)
{
    uint16_t validPage = 0U;
    uint32_t pageEndAddress = 0U;
    Fmc_StateType flashStatus = FMC_STATE_COMPLETE;
    Fmc_StateType tempReturn = FMC_STATE_COMPLETE;

    /* Get valid Page for read operation */
    validPage = (uint16_t)Flash_EE_FindValidPage(GET_VALID_PAGE_READ);

    if (validPage == NO_VALID_PAGE)
    {
        tempReturn = FMC_STATE_PG_ERR;
    }
    else
    {
        /* Calculate the valid Page end Address */
        pageEndAddress  = FLASH_EE_START_ADDRESS + (validPage * FLASH_EE_PAGE_SIZE) + FLASH_EE_PAGE_SIZE - 4U;

        /* Check if the page is full: g32a1085 series Flash is erased, the data is 0xFFFFFFFF */
        if ((*(__IO uint32_t*)(pageEndAddress - 4U)) != 0xFFFFFFFFU)
        {
            /* If the page is full, transfer the data to new active page */
            flashStatus = Flash_EE_TransferToActivePage();
            if (flashStatus != FMC_STATE_COMPLETE)
            {
                tempReturn = flashStatus;
            }
            else
            {
                /* nothing */
            }
        }
        else
        {
            tempReturn = FMC_STATE_COMPLETE;
        }
    }
    return tempReturn;
}

/*!
* @brief       Transition state processing, one page state is valid, one page state is transfer, 
*              and the data is transferred to the transfer state page.
*
* @param       PageStatus0: Page0 status.
*
* @param       PageStatus1: Page1 status.
*
* @retval      Returns the fmc status. The value refer to Fmc_StateType.
*
* @note
*/
static Fmc_StateType Flash_EE_ValidTransfer(uint32_t PageStatus0, uint32_t PageStatus1)
{
    uint32_t pageEraseAddress = 0;
    Fmc_StateType flashStatus = FMC_STATE_COMPLETE;
    Fmc_StateType tempReturn = FMC_STATE_COMPLETE;

    /* Get the transfer page */
    if (PageStatus0 == PAGE_STATUS_TRANSFER)
    {
        pageEraseAddress = PAGE0_START_ADDRESS;
    }
    else
    {
        pageEraseAddress = PAGE1_START_ADDRESS;
    }

    /* Erase the transfer state page */
    flashStatus = Flash_EE_PageErase(pageEraseAddress);
    if (flashStatus != FMC_STATE_COMPLETE)
    {
        tempReturn = flashStatus;
    }
    else
    {
        tempReturn = Flash_EE_TransferToActivePage();
    }

    (void)PageStatus1;
    /* Retransmit data */
    return tempReturn;
}

/*!
* @brief       Transition state processing, a page state is erase, a page state is transfer,
*              and the transfer state is changed to valid.
*
* @param       PageStatus0: Page0 status.
*
* @param       PageStatus1: Page1 status.
*
* @retval      Returns the fmc status. The value refer to Fmc_StateType.
*
* @note
*/
static Fmc_StateType Flash_EE_EraseTransfer(uint32_t PageStatus0, uint32_t PageStatus1)
{
    uint32_t pageStartAddress = 0;
    uint32_t data[2] = {0, 0};
    
    /* Get the transfer page */
    if (PageStatus0 == PAGE_STATUS_TRANSFER)
    {
        pageStartAddress = PAGE0_START_ADDRESS;
    }
    else
    {
        pageStartAddress = PAGE1_START_ADDRESS;
    }
    
    data[0] = PAGE_STATUS_VALID;
    data[1] = PAGE_STATUS_ERASED;

    (void)PageStatus1;    

    /* Mark the page status as valid */
    return Fmc_ProgramWord(pageStartAddress, (uint32_t)FMC_LEN_64BIT, data);
}

/*!
* @brief       Flash EEPROM Init. Restore the pages to a known good state in case of pages'
*              status corruption after a power loss.
*
* @param       None
*
* @retval      Returns the fmc status. The value refer to Fmc_StateType.
*
* @note
*/
Fmc_StateType Flash_EE_Init(void)
{
    uint32_t pageStatus0 = 0;
    uint32_t pageStatus1 = 0;
    Fmc_StateType flashStatus = FMC_STATE_COMPLETE;
    Fmc_StateType tempReturn = FMC_STATE_COMPLETE;

    (void)tempReturn;

    /* Flash unlock */
    Fmc_Unlock();

    /* Get Page0 status */
    pageStatus0 = (*(__IO uint32_t*)PAGE0_START_ADDRESS);

    /* Get Page1 status */
    pageStatus1 = (*(__IO uint32_t*)PAGE1_START_ADDRESS);

    /* Ensure that the page data is completely erased */
    if (pageStatus0 == PAGE_STATUS_ERASED)
    {
        /* Erase Page0 */
        flashStatus = Flash_EE_PageErase(PAGE0_START_ADDRESS);
        if (flashStatus != FMC_STATE_COMPLETE)
        {
            Fmc_Lock();
            tempReturn = flashStatus;
        }
        else
        {
            /* nothing */
        }
    }
    else
    {
        /* nothing */
    }
    /* Ensure that the page data is completely erased */
    if ((pageStatus1 == PAGE_STATUS_ERASED) && (FMC_STATE_COMPLETE == tempReturn))
    {
        /* Erase Page1 */
        flashStatus = Flash_EE_PageErase(PAGE1_START_ADDRESS);
        if (flashStatus != FMC_STATE_COMPLETE)
        {
            Fmc_Lock();
            tempReturn = flashStatus;
        }
        else
        {
            /* nothing */
        }
    }
    else
    {
        /* nothing */
    } 
    /* Page0 Page1 status validity check */
    if ((Flash_EE_PageStatusCheck(pageStatus0, pageStatus1) != 0U)  && (FMC_STATE_COMPLETE == tempReturn))
    {
        /* If the page status is invalid, reformat */
        flashStatus = Flash_EE_Format();
        if (flashStatus != FMC_STATE_COMPLETE)
        {
            Fmc_Lock();
            tempReturn = flashStatus;
        }
        else
        {
            /* nothing */
        }
    }
    else
    {
        /* nothing */
    }
    /* Transition state processing, one page state is valid, one page state is transfer,
    and the data is transferred to the transfer state page */
    if ((FMC_STATE_COMPLETE == tempReturn) && 
        (((pageStatus0 == PAGE_STATUS_VALID) && (pageStatus1 == PAGE_STATUS_TRANSFER)) ||
        ((pageStatus0 == PAGE_STATUS_TRANSFER) && (pageStatus1 == PAGE_STATUS_VALID))))
    {
        flashStatus = Flash_EE_ValidTransfer(pageStatus0, pageStatus1);
        if (flashStatus != FMC_STATE_COMPLETE)
        {
            Fmc_Lock();
            tempReturn = flashStatus;
        }
        else
        {
            /* nothing */
        }
    }
    else
    {
        /* nothing */
    }
    /* Transition state processing, a page state is erase, a page state is transfer,
    and the transfer state is changed to valid */
    if ((FMC_STATE_COMPLETE == tempReturn) && 
        (((pageStatus0 == PAGE_STATUS_ERASED) && (pageStatus1 == PAGE_STATUS_TRANSFER)) ||
        ((pageStatus0 == PAGE_STATUS_TRANSFER) && (pageStatus1 == PAGE_STATUS_ERASED))))
    {
        flashStatus = Flash_EE_EraseTransfer(pageStatus0, pageStatus1);
        if (flashStatus != FMC_STATE_COMPLETE)
        {
            Fmc_Lock();
            tempReturn = flashStatus;
        }
        else
        {
            /* nothing */
        }
    }
    else
    {
        /* nothing */
    }

    if((FMC_STATE_COMPLETE == tempReturn))
    {
        /* Check if the page is full, when the page is full, transfer the data to erase page */
        flashStatus = Flash_EE_FullCheck();
        if ((flashStatus != FMC_STATE_COMPLETE))
        {
            Fmc_Lock();
            tempReturn = flashStatus;
        }
        else
        {
            /* Flash lock */
            Fmc_Lock();
        
            tempReturn = FMC_STATE_COMPLETE;
        }
    }
    else
    {
        /* do nothing */
    }

    return tempReturn;
}

/*!
* @brief       Read the variable data corresponding to the last stored virtual address.
*
* @param       VirtAddress: the variable virtual address.
*                           Virtual address value must be between 0 ~ NUMBER_OF_VARIABLES.
*
* @param       pData: data pointer.
*
* @retval      The returned value can be: 0 or 1.
*              @arg 0: Read successful.
*              @arg 1: Read fail.
*
* @note
*/
uint32_t Flash_EE_ReadData(uint32_t VirtAddress, uint32_t *PData)
{
    uint32_t validPage = 0U;
    uint32_t data_address;
    uint32_t address = 0U;
    uint32_t pageStartAddress = 0U;
    uint32_t tempReturn = 1U;

    /* Get the valid page for read operation */
    validPage = Flash_EE_FindValidPage(GET_VALID_PAGE_READ);

    if (validPage == NO_VALID_PAGE)
    {
        tempReturn = NO_VALID_PAGE;
    }
    else
    {
        /* Calculate the valid Page start address */
        pageStartAddress = FLASH_EE_START_ADDRESS + (validPage * FLASH_EE_PAGE_SIZE) + 4U;

        /* Calculate the valid Page end address */
        address  = FLASH_EE_START_ADDRESS + (validPage * FLASH_EE_PAGE_SIZE) + FLASH_EE_PAGE_SIZE - 4U;

        /* Search from page end address */
        while (address > pageStartAddress)
        {
            /* Get the virtual address of the current location */
            data_address = (*(__IO uint32_t*)address);

            /* The read address is compared with the virtual address */
            if (VirtAddress == data_address)
            {
                /* Get variable value */
                *PData = (*(__IO uint32_t*)(address - 4U));

                /* Read variable data successful, return 0 */
                tempReturn = 0;
                break;
            }
            else
            {
                /* nothing */
            }

            /* Next address location */
            address -= 8U;
        }
    }
    /* Read variable data fail, return 1 */
    return tempReturn;
}

/*!
* @brief       Writes/upadtes variable data in Flash EEPROM.
*
* @param       VirtAddress: the variable virtual address.
*                           Virtual address value must be between 0 ~ NUMBER_OF_VARIABLES.
*
* @param       Data: The data to be written.
*
* @retval      Returns the fmc status. The value refer to Fmc_StateType.
*
* @note
*/
Fmc_StateType Flash_EE_WriteData(uint32_t VirtAddress, uint32_t Data)
{
    Fmc_StateType flashStatus = FMC_STATE_COMPLETE;
    Fmc_StateType tempReturn = FMC_STATE_COMPLETE;

    /* Flash unlock */
    Fmc_Unlock();

    /* Check if the page is full, when the page is full, transfer the data to erase page */
    flashStatus = Flash_EE_FullCheck();
    if (flashStatus != FMC_STATE_COMPLETE)
    {
        Fmc_Lock();
        tempReturn = flashStatus;
    }
    else
    {
        /* Write the data virtual address and value to flash */
        flashStatus = Flash_EE_NotVerifyPageFullWriteData(VirtAddress, Data);
        if (flashStatus != FMC_STATE_COMPLETE)
        {
            Fmc_Lock();
            tempReturn = flashStatus;
        }
        else
        {
            /* Check if the page is full, when the page is full, transfer the data to erase page */
            flashStatus = Flash_EE_FullCheck();
            if (flashStatus != FMC_STATE_COMPLETE)
            {
                Fmc_Lock();
                tempReturn = flashStatus;
            }
            else
            {
                /* Flash lock */
                Fmc_Lock();

                tempReturn = FMC_STATE_COMPLETE;
            }
        }
    }

    return tempReturn;
}

/**@} end of group FMC_Flash_EEPROM_Functions */
/**@} end of group FMC_Flash_EEPROM */
/**@} end of group FLASH_Examples */
/**@} end of group Examples */
