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

/******************************************************************************
 * @version: V1.0.0  demo
 ******************************************************************************/

/*!
 * @file eflash.c
 *
 * @brief This file contains the user eflash function..
 *
 */
/* ===========================================  Includes  =========================================== */
#include "ac780x_eflash.h"
#include "stdbool.h"
#include "eflash.h"
#include "gpio.h"
#include "timer.h"

/* ============================================  Define  ============================================ */
#define WRITE_LENGTH             256U                                  /*! 写入数据长度，最小写入长度为4字节， 所以WRITE_LENGTH 需要大于等于4 */
#define PFLASH_PAGE61_ADRESS     0x08007A00U                           /*! Page61 0x0800_7A00 ~ 0x0800_7CFF   size 512B */
#define PFLASH_PAGE62_ADRESS     0x08007C00U                           /*! Page62 0x0800_7C00 ~ 0x0800_7DFF   size 512B */
#define PFLASH_PAGE63_ADRESS     0x08007E00U                           /*! Page63 0x0800_7E00 ~ 0x0800_7FFF   size 512B */

#define DFLASH_PAGE0_ADRESS      0x08020000U                           /*! Dflash Page0 0x0802_0000 ~ 0x0802_0007   size 8B */
#define DFLASH_PAGE255_ADRESS    0x080207F8U                           /*! Dflash Page0 0x0802_07F8 ~ 0x0802_07FF   size 8B */

/* ===========================================  Typedef  ============================================ */

/* ==========================================  Variables  =========================================== */
FLASHJobType g_FlASHJobType = FLASH_JOB_NULL;                          /*! 操作任务标志位 */
uint8_t g_WriteBuff[WRITE_LENGTH] = {0};                               /*! 写入数据BUFF */
uint8_t g_ReadBuff[WRITE_LENGTH] = {0};                                /*! 读取数据BUFF */

/* ====================================  Functions declaration  ===================================== */

/* ======================================  Functions define  ======================================== */
/*!
 * @brief   FLASH_DataErase_Job 擦除操作
 *          Flash写入数据前，需要保证要写入的Flash为空，即写入地址处为0xFF，本操作对D-Flash全片擦除、
 *          对指定P-Flash空间进行擦除，因Code存储在P-Flash中，应谨慎使用P-Flash全片擦除
 * @param   none
 * @return  none
 */
static void FLASH_DataErase_Job(void)
{
    EFLASH_UnlockCtrl();                                                                          /*！ Flash 写入/擦除前需要先解锁 */
    EFLASH_PageErase(PFLASH_PAGE61_ADRESS);                                                       /*！ 擦除P-flash page61 0x0800_7A00 ~ 0x0800_7CFF   size 512B */
    if (EFLASH_STATUS_SUCCESS != EFLASH_PageEraseVerify(PFLASH_PAGE61_ADRESS, WRITE_LENGTH / 4U)) /*！ 验证相应位置是否擦除成功 */
    {
        printf("[LINE %d] ERROR :Erase [0x%08X] failue.\r\n", __LINE__, PFLASH_PAGE61_ADRESS);    /*！ 若擦除失败，则打印相应错误警告 */
    }
    EFLASH_DFMassErase();                                                                         /*!  D-flash  全片擦除，因为Code 存放在P-flash中， 不建议对P-flash进行全片擦除 */
    if (EFLASH_STATUS_SUCCESS != EFLASH_DFMassEraseVerify())                                      /*！ 验证相应位置是否擦除成功 */
    {
        printf("[LINE %d] ERROR :Erase Dflash  failue.\r\n", __LINE__);                           /*！ 若擦除失败，则打印相应错误警告 */
    }
    EFLASH_LockCtrl();                                                                            /*！ 完成flash操作后重新上锁， 上锁与解锁要配套使用 */
}

/*!
 * @brief   FLASH_DataInit_Job 写入数据初始化
 *          对写入数据BUFF进行赋初值
 * @param   none
 * @return  none
 */
static void FLASH_DataInit_Job(void)
{
    uint16_t i = 0;
    for (i = 0; i < WRITE_LENGTH; i++)
    {
        g_WriteBuff[i] = i;
    }
}

/*!
 * @brief   Flash_DataUpdate_Job 写入数据更新
 *          对写入数据BUFF进行数据更新
 * @param   none
 * @return  none
 */
static void Flash_DataUpdate_Job(void)
{
    uint16_t i = 0;
    for (i = 0; i < WRITE_LENGTH; i++)
    {
        g_WriteBuff[i] += 1;
    }
    printf("Update data, g_WriteBuff[WRITE_LENGTH] = g_WriteBuff[WRITE_LENGTH] + 1 ... \r\n");
}


/*!
 * @brief   FLASH_DataWrite_Job 写入数据
 *          写入数据前需要保证要写入Flash 的地址处无数据，即为0xFF
 *          向P-flash、D-flash中写入数据并打印
 * @param   none
 * @return  none
 */
static void FLASH_DataWrite_Job(void)
{
    uint16_t i = 0;

    EFLASH_UnlockCtrl();                                                                 /*！ Flash 写入/擦除前需要先解锁 */
    EFLASH_PageProgram(PFLASH_PAGE61_ADRESS, (uint32_t*)g_WriteBuff, WRITE_LENGTH / 4);  /*!  将数据写入P-Flash, 最小写入单位为4字节 */
    printf("Write g_WriteBuff[WRITE_LENGTH] to P-Flash ...\r\n");
    EFLASH_Read(PFLASH_PAGE61_ADRESS, (uint32_t*)g_ReadBuff, WRITE_LENGTH / 4);          /*！ 读取P-Flash指定页数据 */
    printf("Read P-Flash [0x%X] : ", PFLASH_PAGE61_ADRESS);                              /*!  打印相关信息 */
    for (i = 0; i < WRITE_LENGTH; i++)
    {
          printf("%02X  ", g_ReadBuff[i]);
    }
    printf("\r\n");

    EFLASH_PageProgram(DFLASH_PAGE0_ADRESS, (uint32_t*)g_WriteBuff, WRITE_LENGTH / 4);   /*!  将数据写入D-Flash, 最小写入单位为4字节  */
    printf("\r\nWrite g_WriteBuff[WRITE_LENGTH] to D-Flash ...\r\n");
    EFLASH_Read(DFLASH_PAGE0_ADRESS, (uint32_t*)g_ReadBuff, WRITE_LENGTH / 4);           /*！ 读取D-Flash数据 */
    printf("Read D-Flash [0x%X] : ", DFLASH_PAGE0_ADRESS);                               /*!  打印相关信息 */
    for (i = 0; i < WRITE_LENGTH; i++)
    {
          printf("%02X  ", g_ReadBuff[i]);
    }
    printf("\r\n");
    EFLASH_LockCtrl();                                                                   /*！ 完成flash操作后重新上锁， 上锁与解锁要配套使用 */
}

/*!
 * @brief   eflash_Test
 *          按下KEY1 进行写入测试， 按下KEYNMI 更新数据
 *          栈空间较小，进行相关测试时需注意栈是否溢出
 * @param   none
 * @return  none
 */
void eflash_Test(void)
{
    GPIO_LedInit();                                     /*！ LED 初始化 */
    GPIO_KeyInit();                                     /*！ KEY 初始化 */
    TIMER_PrdInit();                                    /*！ TIMER 初始化 */
    FLASH_DataInit_Job();                               /*！ 写入数据初始化*/

    while (1)
    {
        GPIO_ScanKeyInput();                            /*！按键扫描 */
        switch (g_FlASHJobType)                         /*！任务查询 */
        {
            case FLASH_JOB_WRITE:                       /*！写入任务 */
                FLASH_DataErase_Job();                  /*！擦除数据 */
                FLASH_DataWrite_Job();                  /*！写入数据 */
                g_FlASHJobType = FLASH_JOB_NULL;        /*！标志转换 */
            break;

            case FLASH_JOB_DATAPEOCESS:                 /*！更新数据任务 */
                Flash_DataUpdate_Job();                 /*！更新写入数据 */
                g_FlASHJobType = FLASH_JOB_NULL;        /*！标志转换 */
            break;

            case FLASH_JOB_NULL:                        /*！空闲状态 */
                GPIO_ToggleLedPrd();                    /*！LED闪烁 */
            break;

            default:
                g_FlASHJobType = FLASH_JOB_NULL;
            break;
        }

    }
}
/* =============================================  EOF  ============================================== */
