#include "hal_data.h"
#include <stdint.h>
#include <stdio.h>
#include "lwrb/lwrb.h"
#include "shell_port.h"
#include "multi_button.h"
#include "log.h"
#include "internal_flash.h"

FSP_CPP_HEADER
void R_BSP_WarmStart(bsp_warm_start_event_t event);
FSP_CPP_FOOTER


/* Private functions */
static fsp_err_t check_for_write_complete(void);
static fsp_err_t print_to_console(char *p_data);
static fsp_err_t usb_process(void);

#define NUM_STRING_DESCRIPTOR               (7U)

/* Global variables */
extern uint8_t g_apl_device[];
extern uint8_t g_apl_configuration[];
extern uint8_t g_apl_hs_configuration[];
extern uint8_t g_apl_qualifier_descriptor[];
extern uint8_t *g_apl_string_table[];
extern int g_curr_led_freq;

const usb_descriptor_t g_usb_descriptor =
{
 g_apl_device,                   /* Pointer to the device descriptor */
 g_apl_configuration,            /* Pointer to the configuration descriptor for Full-speed */
 g_apl_hs_configuration,         /* Pointer to the configuration descriptor for Hi-speed */
 g_apl_qualifier_descriptor,     /* Pointer to the qualifier descriptor */
 g_apl_string_table,             /* Pointer to the string descriptor table */
 NUM_STRING_DESCRIPTOR
};

usb_status_t            usb_event;
static bool  b_usb_attach = false;

//正弦波数据数组变量
const uint16_t sindata[] = {
   2048, 2460, 2856, 3218, 3532, 3786, 3969, 4072, 4093, 4031, 3887, 3668,
   3382, 3042, 2661, 2255, 1841, 1435, 1054, 714, 428, 209, 65, 3, 24, 127,
   310, 564, 878, 1240, 1636, 2048
};

extern void qe_touch_main(void);

lwrb_t buff = {0};
uint8_t buff_data[256];

volatile uint64_t SysTickms = 0;

enum Button_IDs {
	btn1_id = 0,
	btn2_id,
	btn3_id,
    btn_max,
};

struct Button btn[btn_max];

uint64_t getSystemTicks() 
{
    return SysTickms;
}

fsp_err_t SystickInit(void)
{
    /* 获取处理器时钟uwSysclk */
    uint32_t uwSysclk = R_BSP_SourceClockHzGet(FSP_PRIV_CLOCK_PLL);
    /* 计数周期为uwSysclk/1000 */
    if (SysTick_Config(uwSysclk / 1000) != 0)
    {
        return FSP_ERR_ASSERTION;
    }
    /* Return function status */
    return FSP_SUCCESS;
}

void SysTick_Handler(void)
{
    SysTickms += 1;
}

uint8_t read_button_GPIO(uint8_t button_id)
{
    // you can share the GPIO read function with multiple Buttons
    bsp_io_level_t btnState = BSP_IO_LEVEL_HIGH;
    switch(button_id)
	{
		case btn1_id:
            R_IOPORT_PinRead(&g_ioport_ctrl, BSP_IO_PORT_00_PIN_13, &btnState);
            break;
		case btn2_id:
            R_IOPORT_PinRead(&g_ioport_ctrl, BSP_IO_PORT_01_PIN_12, &btnState);
            break;
		case btn3_id:
            R_IOPORT_PinRead(&g_ioport_ctrl, BSP_IO_PORT_01_PIN_11, &btnState);
            break;
		default:
            break;
	}

    return (uint8_t)btnState;
}

void Callback_btn_Handler(void *btn_ptr)
{
    Button *_btn = (Button *)btn_ptr;

    switch (_btn->event)
    {
    case PRESS_DOWN:
        logInfo("BTN[%d] press down!",_btn->button_id+1);
        break;
    case PRESS_UP:
        logInfo("BTN[%d] press up!",_btn->button_id+1);
        break;
    case PRESS_REPEAT:
        logInfo("BTN[%d] press repeat!",_btn->button_id+1);
        break;
    case SINGLE_CLICK:
        logInfo("BTN[%d] single click!",_btn->button_id+1);
        if (_btn->button_id == btn1_id) {        
            logWarning("MCU Enter Software Standby Mode!");
            g_lpm0.p_api->lowPowerModeEnter(g_lpm0.p_ctrl);  
        }
        else if (_btn->button_id == btn2_id) {
            FLASH_HP_DataFlash_Operation();
        }
        break;
    case DOUBLE_CLICK:
        logInfo("BTN[%d] double click!",_btn->button_id+1);
        break;
    case LONG_PRESS_START:
        logInfo("BTN[%d] long press start!",_btn->button_id+1);
        break;
    case LONG_PRESS_HOLD:
        logInfo("BTN[%d] long press hold!",_btn->button_id+1);
        break;
    default:
        break;
    }
}

/**
* @brief  设置当前的电压
* @param  需要控制的电压
* @retval 无
*/
void DAC_SetVoltage(float voltage)
{
   uint16_t dac_data;
   dac_data = (uint16_t)(4095*((voltage)/3.3f));
   g_dac0.p_api->write(g_dac0.p_ctrl, dac_data);
}

/** 自定义函数：设置PWM占空比
    @param duty 占空比范围：0~100 %
*/
void GPT2_PWMA_SetDuty(uint8_t duty)
{
    timer_info_t info;
    uint32_t current_period_counts;
    uint32_t duty_cycle_counts;

    if (duty > 100)
        duty = 100; //限制占空比范围：0~100

    /* 获得GPT的信息 */
    //R_GPT_InfoGet(&g_timer_gpt2_ctrl, &info);
    g_timer0.p_api->infoGet(g_timer2.p_ctrl, &info);

    /* 获得计时器一个周期需要的计数次数 */
    current_period_counts = info.period_counts;

    /* 根据占空比和一个周期的计数次数计算GTCCR寄存器的值 */
    duty_cycle_counts = (uint32_t)(((uint64_t) current_period_counts * duty) / 100);

    /* 最后调用FSP库函数设置占空比 */
    // R_GPT_DutyCycleSet(&g_timer_gpt2_ctrl, duty_cycle_counts, GPT_IO_PIN_GTIOCA);
    g_timer0.p_api->dutyCycleSet(g_timer2.p_ctrl, duty_cycle_counts, GPT_IO_PIN_GTIOCA);
}

void dwt_timestamp_init(void)
{
    CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;  // 1. 开总开关
    DWT->CYCCNT = 0;                                 // 2. 清计数器
    DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;             // 3. 启动 CYCCNT
}

uint16_t adc_val[8];
float temperature = 0.0f;
int gi_temperature = 0;
SHELL_EXPORT_VAR(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_VAR_INT), gettemperature, &gi_temperature, test);

uint8_t gpt2_pwma_duty = 20;
SHELL_EXPORT_VAR(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_VAR_CHAR), varPwm, &gpt2_pwma_duty, test);

timer_info_t info;  //用于获取定时器参数信息
uint32_t period;    //输入捕获计数器的计数周期
/* 保存所测量的PWM信号的信息 */
uint32_t pwm_period;            //PWM周期
uint32_t pwm_high_level_time;   //PWM高电平的时间
uint32_t pwm_freq;              //PWM频率
uint32_t pwm_duty;              //PWM占空比
/*******************************************************************************************************************//**
 * main() is generated by the RA Configuration editor and is used to generate threads if an RTOS is used.  This function
 * is called by main() when no RTOS is used.
 **********************************************************************************************************************/
void hal_entry(void)
{
    /* TODO: add your own code here */
    
//   qe_touch_main();
    
    fsp_err_t err;
    dwt_timestamp_init();
    SystickInit();
    err = g_uart9.p_api->open(g_uart9.p_ctrl, g_uart9.p_cfg);
    assert(FSP_SUCCESS == err);

    lwrb_init(&buff, buff_data, sizeof(buff_data));  
    
    userShellInit(); 
    logDebug("Init uart and shell end");

    logDebug("Start Open adc0");
    err = g_adc0.p_api->open(g_adc0.p_ctrl,g_adc0.p_cfg);
    assert(FSP_SUCCESS == err);
    err = g_adc0.p_api->scanCfg(g_adc0.p_ctrl,g_adc0.p_channel_cfg);
    assert(FSP_SUCCESS == err);
    logDebug("Open adc0 end");
    
    logDebug("Start Open and start dac0");
    err = g_dac0.p_api->open(g_dac0.p_ctrl,g_dac0.p_cfg);
    assert(FSP_SUCCESS == err);    
    err = g_dac0.p_api->start(g_dac0.p_ctrl);
    assert(FSP_SUCCESS == err);
    logDebug("Open dac0 end");
    
    logDebug("Start Open and start timer0");
    err = g_timer0.p_api->open(g_timer0.p_ctrl,g_timer0.p_cfg);
    assert(FSP_SUCCESS == err);    
    err = g_timer0.p_api->start(g_timer0.p_ctrl);
    assert(FSP_SUCCESS == err);
    logDebug("Open timer0 end");

    logDebug("Start Open and start timer2 pwm");
    err = g_timer2.p_api->open(g_timer2.p_ctrl,g_timer2.p_cfg);
    assert(FSP_SUCCESS == err);    
    err = g_timer2.p_api->start(g_timer2.p_ctrl);
    assert(FSP_SUCCESS == err);
    GPT2_PWMA_SetDuty(gpt2_pwma_duty);
    logDebug("Open timer2 pwm end");

    logDebug("Start Open and start timer5 cap");
    err = g_timer5.p_api->open(g_timer5.p_ctrl,g_timer5.p_cfg);
    assert(FSP_SUCCESS == err);    
    err = g_timer5.p_api->infoGet(g_timer5.p_ctrl,&info);
    assert(FSP_SUCCESS == err);    
    /* 获取计数周期：GPT的一个周期的计数次数 */
    period = info.period_counts;
    err = g_timer5.p_api->enable(g_timer5.p_ctrl);
    assert(FSP_SUCCESS == err);
    err = g_timer5.p_api->start(g_timer5.p_ctrl);
    assert(FSP_SUCCESS == err);
    logDebug("Open timer5 cap end");
    
    logDebug("Start Open IRQ4");
    err = g_external_irq4.p_api->open(g_external_irq4.p_ctrl,g_external_irq4.p_cfg);
    assert(FSP_SUCCESS == err);
    err = g_external_irq4.p_api->enable(g_external_irq4.p_ctrl);
    assert(FSP_SUCCESS == err);
    logDebug("Open IRQ4 end");
    
    logDebug("Start Open lpm");
    err = g_lpm0.p_api->open(g_lpm0.p_ctrl,g_lpm0.p_cfg);
    assert(FSP_SUCCESS == err);
    logDebug("Open lpm end");
    
    logDebug("Start Open usb");
    err = g_basic0.p_api->open(g_basic0.p_ctrl,g_basic0.p_cfg);
    assert(FSP_SUCCESS == err);
    logDebug("Open usb end");
    
    logDebug("Start Open flash");
    err = g_flash0.p_api->open(g_flash0.p_ctrl,g_flash0.p_cfg);
    assert(FSP_SUCCESS == err);

    err = g_flash0.p_api->startupAreaSelect(g_flash0.p_ctrl, FLASH_STARTUP_AREA_BLOCK0, true);
    assert(FSP_SUCCESS == err);
    logDebug("Open flash end");
    
    logDebug("Init button");
    for (uint8_t i = 0; i < btn_max; i++) 
    {
        button_init(&btn[i], read_button_GPIO, 0, i);    
        button_attach(&btn[i], PRESS_DOWN, Callback_btn_Handler);
        button_attach(&btn[i], PRESS_UP, Callback_btn_Handler);
        button_attach(&btn[i], PRESS_REPEAT, Callback_btn_Handler);
        button_attach(&btn[i], SINGLE_CLICK, Callback_btn_Handler);
        button_attach(&btn[i], DOUBLE_CLICK, Callback_btn_Handler);
        button_attach(&btn[i], LONG_PRESS_START, Callback_btn_Handler);
        button_attach(&btn[i], LONG_PRESS_HOLD, Callback_btn_Handler);

        button_start(&btn[i]);
    }

    
    uint64_t led1_tick = SysTickms + 100;
    uint64_t btn_tick = SysTickms + 5;
    
    uint64_t _ms = SysTickms;
    uint64_t _sec = SysTickms + 1000;
    uint8_t sindataindex = 0;
    

    logDebug("Start adc0 scan");
    g_adc0.p_api->scanStart(g_adc0.p_ctrl);

    logInfo("Start App!");
	while(1)
	{             
        // button
        if (btn_tick < SysTickms)
        {
            button_ticks();
            btn_tick = SysTickms + 5;
        }
        // shell
        if (lwrb_get_full(&buff))
        {
            char ch = '0';
            lwrb_read(&buff,&ch,1);
            shellHandler(&shell, ch);
        }        
        // adc & TSN
        if (get_adc_scan_status())
        {        
            g_adc0.p_api->read(g_adc0.p_ctrl,ADC_CHANNEL_0,&adc_val[0]);
            g_adc0.p_api->read(g_adc0.p_ctrl,ADC_CHANNEL_TEMPERATURE,&adc_val[1]);
            int32_t    cal127;
            adc_info_t adc_info;
            (void) R_ADC_InfoGet(&g_adc0_ctrl, &adc_info);
            cal127 = (int32_t) adc_info.calibration_data;
            float slope = 4.0f/1000.0f;
            float v1= 3.3f * (float)cal127 / 4096.0f;
            float vs = 3.3f * (float)adc_val[1] /4096.0f;
            temperature = (vs - v1) / slope + 127.0f;
            gi_temperature = (int)(temperature * 100.0f);
            reset_adc_scan_state();
        }
        // led1 100ms         
        if (led1_tick < SysTickms)
        {
            led1_tick = SysTickms + 100; 
            g_ioport.p_api->pinWrite(g_ioport.p_ctrl, BSP_IO_PORT_00_PIN_02, (adc_val[0]>2000));
        }  
        // 1ms dac-->sin
        if (_ms != SysTickms) 
        {
            if (sindataindex >= 32) {
                sindataindex = 0;
            }
            g_dac0.p_api->write(g_dac0.p_ctrl,sindata[sindataindex++]);
           // DAC_SetVoltage(vol);
        }
        
        GPT2_PWMA_SetDuty(gpt2_pwma_duty);

        if (_sec < SysTickms) 
        {
            _sec = SysTickms + 1000;
            /* 计算PWM的频率 */
            pwm_freq = info.clock_frequency / pwm_period;

            /* 计算PWM的占空比 */
            pwm_duty = pwm_high_level_time * 100 / pwm_period;

            // 打印
            // logInfo("High=%d, Period=%d, ", pwm_high_level_time, pwm_period);
            // logInfo("Friquency = %dHz, Duty_Cycle = %d%%", pwm_freq, pwm_duty);
            pwm_period = pwm_high_level_time = pwm_freq = 0; //打印完后旧数据清零
        
        }

        usb_process();
	}

#if BSP_TZ_SECURE_BUILD
    /* Enter non-secure code */
    R_BSP_NonSecureEnter();
#endif
}

/*******************************************************************************************************************//**
 * This function is called at various points during the startup process.  This implementation uses the event that is
 * called right before main() to set up the pins.
 *
 * @param[in]  event    Where at in the start up process the code is currently at
 **********************************************************************************************************************/
void R_BSP_WarmStart (bsp_warm_start_event_t event)
{
    if (BSP_WARM_START_RESET == event)
    {
#if BSP_FEATURE_FLASH_LP_VERSION != 0

        /* Enable reading from data flash. */
        R_FACI_LP->DFLCTL = 1U;

        /* Would normally have to wait tDSTOP(6us) for data flash recovery. Placing the enable here, before clock and
         * C runtime initialization, should negate the need for a delay since the initialization will typically take more than 6us. */
#endif
    }

    if (BSP_WARM_START_POST_C == event)
    {
        /* C runtime environment and system clocks are setup. */

        /* Configure pins. */
        R_IOPORT_Open(&IOPORT_CFG_CTRL, &IOPORT_CFG_NAME);

#if BSP_CFG_SDRAM_ENABLED

        /* Setup SDRAM and initialize it. Must configure pins first. */
        R_BSP_SdramInit(true);
#endif
    }
}

#if BSP_TZ_SECURE_BUILD

FSP_CPP_HEADER
BSP_CMSE_NONSECURE_ENTRY void template_nonsecure_callable ();

/* Trustzone Secure Projects require at least one nonsecure callable function in order to build (Remove this if it is not required to build). */
BSP_CMSE_NONSECURE_ENTRY void template_nonsecure_callable ()
{

}
FSP_CPP_FOOTER

#endif

void user_timer0_callback(timer_callback_args_t * p_args)
{
    /* 定时器溢出事件 */
    static bsp_io_level_t level_led3 = BSP_IO_LEVEL_HIGH;  
    if (TIMER_EVENT_CYCLE_END == p_args->event)
    {        
        g_ioport.p_api->pinWrite(g_ioport.p_ctrl, BSP_IO_PORT_01_PIN_04, level_led3);
        level_led3 = !level_led3;
    }
}

/* GPT 输入捕获中断回调函数 */
 void user_timer5_callback(timer_callback_args_t * p_args)
 {
     static uint32_t a_time; // A 上升沿捕获的时间
     static uint32_t b_time; // B 下降沿捕获的时间
     static uint32_t c_time; // C 上升沿捕获的时间（其实也就是 A 可以用A'表示）
     static uint32_t overflow_times;     //计数器溢出次数
     static uint8_t  one_period_flag=0;  //用于表示是否完成对一个完整周期的测量


     switch(p_args->event)
     {
         /* 捕获到上升沿 -- 有可能是 A 或者 C (A') 位置 */
         case TIMER_EVENT_CAPTURE_A:
             /* A 开始对某个周期进行测量 */
             if (0 == one_period_flag)
             {
                 a_time = p_args->capture;   //记录捕获的时间 A
                 overflow_times = 0;         //初始化计数器溢出次数
                 one_period_flag ++;         //表示即将完成对某个周期的测量
             }
             /* C (A') 如果测量完了一个周期，则计算PWM信号周期和高电平的时间 */
             else if (1 == one_period_flag)
             {
                 c_time = p_args->capture + overflow_times * period; //记录捕获的时间 C

                 //计算 PWM 周期
                 pwm_period = c_time - a_time;

                 //清零所有标志位
                 overflow_times = 0;
                 one_period_flag = 0;         //标志位清0,重新进入下一轮的测量
             }
             break;

         /* 捕获到下降沿 -- 是 B 位置 */
         case TIMER_EVENT_CAPTURE_B:
             //如果是在测量周期内检测到下降沿
             if (1 == one_period_flag)
             {
                 b_time = p_args->capture + overflow_times * period; //记录捕获的时间 B

                 pwm_high_level_time = b_time - a_time;  //计算高电平时间
             }
             break;

         /* 定时器计数溢出事件 */
         case TIMER_EVENT_CYCLE_END:
             /* 输入捕获期间计数器溢出，则记录溢出次数+1 */
             overflow_times++;
             break;

         default:
             break;
     }
 }

 void user_irq4_callback(external_irq_callback_args_t * p_args)
 {
    FSP_PARAMETER_NOT_USED(p_args);
 }


 /*****************************************************************************************************************
 *  @brief      Prints the message to console
 *  @param[in]  p_msg contains address of buffer to be printed
 *  @retval     FSP_SUCCESS     Upon success
 *  @retval     any other error code apart from FSP_SUCCESS, Write is unsuccessful
 ****************************************************************************************************************/
static fsp_err_t print_to_console(char *p_data)
{
    fsp_err_t err = FSP_SUCCESS;
    uint32_t len = ((uint32_t)strlen(p_data));

    err = R_USB_Write (&g_basic0_ctrl, (uint8_t*)p_data, len, USB_CLASS_PCDC);
    /* Handle error */
    if (FSP_SUCCESS != err)
    {
        return err;
    }

    err = check_for_write_complete();
    if (FSP_SUCCESS != err)
    {
        /* Did not get the event hence returning error */
        return FSP_ERR_USB_FAILED;
    }
    return err;
}

/*****************************************************************************************************************
 *  @brief      Check for write completion
 *  @param[in]  None
 *  @retval     FSP_SUCCESS     Upon success
 *  @retval     any other error code apart from FSP_SUCCESS
 ****************************************************************************************************************/
static fsp_err_t check_for_write_complete(void)
{
    usb_status_t usb_write_event = USB_STATUS_NONE;
    int32_t timeout_count = UINT16_MAX;
    fsp_err_t err = FSP_SUCCESS;
    usb_event_info_t    event_info = {0};

    do
    {
        err = R_USB_EventGet (&event_info, &usb_write_event);
        if (FSP_SUCCESS != err)
        {
            return err;
        }

        --timeout_count;

        if (0 > timeout_count)
        {
            timeout_count = 0;
            err = (fsp_err_t)USB_STATUS_NONE;
            break;
        }
    }while(USB_STATUS_WRITE_COMPLETE != usb_write_event);

    return err;
}

#define KIT_INFO              ('1')
#define NEXT_STEPS            ('2')
#define CARRIAGE_RETURN       ('\r')
#define LINE_CODING_LENGTH          (0x07U)
#define READ_BUF_SIZE               (256U)
usb_event_info_t    event_info          = {0};
uint8_t g_buf[READ_BUF_SIZE]            = {0};
static usb_pcdc_linecoding_t g_line_coding;

static fsp_err_t usb_process(void)
{    
    fsp_err_t err = FSP_SUCCESS;

    /* Obtain USB related events */
    err = R_USB_EventGet (&event_info, &usb_event);

    /* Handle error */
    assert(FSP_SUCCESS == err);

    /* USB event received by R_USB_EventGet */
    switch (usb_event)
    {
        case USB_STATUS_CONFIGURED:
        {
            err = R_USB_Read (&g_basic0_ctrl, g_buf, READ_BUF_SIZE, USB_CLASS_PCDC);
            /* Handle error */
            assert(FSP_SUCCESS == err);              
            logDebug("USB configured completed!");
            break;
        }
        case USB_STATUS_READ_COMPLETE:
        {
            if(b_usb_attach)
            {
                err = R_USB_Read (&g_basic0_ctrl, g_buf, READ_BUF_SIZE, USB_CLASS_PCDC);
            }
            /* Handle error */
            assert(FSP_SUCCESS == err);            
            logInfo("USB Read data completed!");
            print_to_console((char *)g_buf);
            memset (g_buf, 0, sizeof(g_buf));
            break;
        }
        case USB_STATUS_REQUEST : /* Receive Class Request */
        {
            /* Check for the specific CDC class request IDs */
            if (USB_PCDC_SET_LINE_CODING == (event_info.setup.request_type & USB_BREQUEST))
            {
                err =  R_USB_PeriControlDataGet (&g_basic0_ctrl, (uint8_t *) &g_line_coding, LINE_CODING_LENGTH );
                /* Handle error */
                assert(FSP_SUCCESS == err);
                logDebug("USB USB_PCDC_SET_LINE_CODING!");
            }
            else if (USB_PCDC_GET_LINE_CODING == (event_info.setup.request_type & USB_BREQUEST))
            {
                err =  R_USB_PeriControlDataSet (&g_basic0_ctrl, (uint8_t *) &g_line_coding, LINE_CODING_LENGTH );
                /* Handle error */
                assert(FSP_SUCCESS == err);
                logDebug("USB USB_PCDC_GET_LINE_CODING!");
            }
            else if (USB_PCDC_SET_CONTROL_LINE_STATE == (event_info.setup.request_type & USB_BREQUEST))
            {
                err = R_USB_PeriControlStatusSet (&g_basic0_ctrl, USB_SETUP_STATUS_ACK);
                /* Handle error */
                assert(FSP_SUCCESS == err);
                logDebug("USB USB_PCDC_SET_CONTROL_LINE_STATE!");
            }
            else
            {
                /* none */
            }

            break;
        }
        case USB_STATUS_DETACH:
        case USB_STATUS_SUSPEND:
        {
            b_usb_attach = false;
            memset (g_buf, 0, sizeof(g_buf));
            logDebug("USB detach or suspend!");
            break;
        }
        case USB_STATUS_RESUME:
        {
            logDebug("USB resume!");
            b_usb_attach = true;
            break;
        }
        default:
        {
            break;
        }
    }
	return err;
}


volatile bool flash_erase_complete_flag = false;
volatile bool flash_write_complete_flag = false;
volatile bool flash_event_not_blank = false;
volatile bool flash_event_blank = false;
volatile bool flash_event_error = false;
volatile flash_event_t flash_event_error_type;


 /* DATA FLASH 操作完成中断回调 */
 void user_flash_callback(flash_callback_args_t *p_args)
 {
     flash_event_t flash_event = p_args->event;

     if (FLASH_EVENT_ERASE_COMPLETE == flash_event)
     {
         flash_erase_complete_flag = true;
     }
     else if (FLASH_EVENT_WRITE_COMPLETE == flash_event)
     {
         flash_write_complete_flag = true;
     }
     else if (FLASH_EVENT_BLANK == flash_event)
     {
         flash_event_blank = true;
     }
     else if (FLASH_EVENT_NOT_BLANK == flash_event)
     {
         flash_event_not_blank = true;
     }
     else
     {
         flash_event_error = true;
         flash_event_error_type = flash_event;
     }
 }

 /* Data Flash 操作函数 */
void FLASH_HP_DataFlash_Operation(void)
{
    fsp_err_t err;
    flash_result_t blank_check_result = FLASH_RESULT_BLANK;
    uint8_t write_buffer[DATA_FLASH_TEST_DATA_SIZE] = {0};
    uint8_t read_buffer[DATA_FLASH_TEST_DATA_SIZE] = {0};
    uint8_t index;

    /* 写入测试数据到 write_buffer */
    for (index = 0; index < DATA_FLASH_TEST_DATA_SIZE; index++)
    {
        write_buffer[index] = (uint8_t) ('A' + (index % 26));
    }

    /* 擦除 Data Flash */
    logInfo("擦除 Data Flash");
    
    err = g_flash0.p_api->erase(g_flash0.p_ctrl, DATA_FLASH_TEST_BLOCK, BLOCK_NUM);
    /* Error Handle */
    if (FSP_SUCCESS != err)
    {
        logError("Erase API failed");
        logError("Returned Error Code: %d", err);
        while(1);
    }
    logInfo("Erase successful");


    /* 如果使能了BGO功能，等待擦除完成事件标志位 */
    if (true == g_flash0.p_cfg->data_flash_bgo)
    {        
        logInfo("BGO has enabled");
        while (!flash_erase_complete_flag);
        flash_erase_complete_flag = false;
    }
    logInfo("Erase successful");

    /* 空白检查：擦除 Data Flash 完成后，进行空白检查 */
    err = g_flash0.p_api->blankCheck(g_flash0.p_ctrl, DATA_FLASH_TEST_BLOCK, FLASH_HP_DF_BLOCK_SIZE, &blank_check_result);
    /* Error Handle */
    if (FSP_SUCCESS != err)
    {
        logError("BlankCheck API failed");
        logError("Returned Error Code: %d", err);
        while(1);
    }

    /* 验证空白检查的结果 */
    if (FLASH_RESULT_BLANK == blank_check_result)
    {
        logInfo("Flash块是空白的");
    }
    else if (FLASH_RESULT_NOT_BLANK == blank_check_result)
    {
        logError("Flash块不是空白的，不要向其中写入数据");
        while(1);
    }
    else if (FLASH_RESULT_BGO_ACTIVE == blank_check_result)
    {
        /* Wait for callback function to set flag */
        while (!(flash_event_not_blank || flash_event_blank));

        logInfo("BGO has enabled");
        if (flash_event_not_blank)
        {
            logError("Flash块不是空白的，不要向其中写入数据");
            /* Reset Flag */
            flash_event_not_blank = false;
            while(1);
        }
        else
        {
            logInfo("Flash块是空白的");
            /* Reset Flag */
            flash_event_blank = false;
        }
    }

    /* 写入测试数据到 Data Flash */
    logInfo("写入 Data Flash: ");
    err = g_flash0.p_api->write(g_flash0.p_ctrl, (uint32_t)write_buffer, DATA_FLASH_TEST_BLOCK, DATA_FLASH_TEST_DATA_SIZE);
    /* Error Handle */
    if (FSP_SUCCESS != err)
    {
        logError("Write API failed");
        logError("Returned Error Code: %d", err);
        while(1);
    }

    /* 如果使能了BGO功能，等待写入完成事件标志位 */
    if (true == g_flash0_cfg.data_flash_bgo)
    {
        logInfo("BGO has enabled");
        while (!flash_write_complete_flag);     /* Note：如果写入没被擦除的块，会触发错误中断，会在这里卡死 */
        flash_write_complete_flag = false;
    }
    logInfo("Write successful");

    /* 读取 Data Flash 数据 */
    memcpy(read_buffer, (uint8_t *) DATA_FLASH_TEST_BLOCK, DATA_FLASH_TEST_DATA_SIZE);
    logInfo("打印 read_buffer 里的%d字节测试数据: ", DATA_FLASH_TEST_DATA_SIZE);
    for (index = 0; index < DATA_FLASH_TEST_DATA_SIZE; index++)
    {
        shellPrint(&shell,"%c ", read_buffer[index]);
    }
    shellPrint(&shell,"\r\nEnd.\r\n");


    /* 对比 write_buffer 和 read_buffer 数据 */
    if (0 == memcmp(read_buffer, write_buffer, DATA_FLASH_TEST_DATA_SIZE))
    {
        logInfo("数据对比一致，Data Flash 测试成功\r\n");
    }
    else
    {
        logError("数据对比不一致，Data Flash 测试失败\r\n");
        while(1);
    }
}
