#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"

FSP_CPP_HEADER
void R_BSP_WarmStart(bsp_warm_start_event_t event);
FSP_CPP_FOOTER

//正弦波数据数组变量
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);
        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("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; //打印完后旧数据清零
        
        }
	}

#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;
     }
 }
