#include "ultrasonic_analog.h"
#include "gd32e23x_usart.h"
#include "gd32e23x_rcu.h"
#include "gd32e23x_gpio.h"
#include "board_config.h"
#include "systick.h"

volatile bool g_ultrasonic_measure_done = false;
extern uint32_t g_capture_value;

void ultrasonic_tx_init(void) {

    // TODO
    rcu_periph_clock_enable(RCU_GPIOA);

    gpio_mode_set(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_0);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_0);
    gpio_bit_reset(GPIOA, GPIO_PIN_0);

    rcu_periph_clock_enable(US_TX_GPIO_RCU);

    gpio_mode_set(US_TX_GPIO_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, US_TX_GPIO_PIN);
    gpio_output_options_set(US_TX_GPIO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, US_TX_GPIO_PIN);
    gpio_af_set(US_TX_GPIO_PORT, US_TX_GPIO_AF, US_TX_GPIO_PIN);

    timer_oc_parameter_struct timer_ocinitpara;
    timer_parameter_struct timer_initpara;

    rcu_periph_clock_enable(US_TX_TIMER_RCU);

    timer_deinit(US_TX_TIMER);

    timer_struct_para_init(&timer_initpara);
    /* 配置为300kHz PWM输出 (72MHz/240) */
    timer_initpara.prescaler = 0;  // 不分频
    timer_initpara.alignedmode = TIMER_COUNTER_EDGE;
    timer_initpara.counterdirection = TIMER_COUNTER_UP;
    timer_initpara.period = 239;   // 72MHz/300kHz - 1
    timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
    timer_init(US_TX_TIMER, &timer_initpara);

    timer_channel_output_struct_para_init(&timer_ocinitpara);
    timer_ocinitpara.outputstate = TIMER_CCX_DISABLE;
    timer_ocinitpara.outputnstate = TIMER_CCXN_DISABLE;
    timer_ocinitpara.ocpolarity = TIMER_OC_POLARITY_HIGH;
    timer_ocinitpara.ocnpolarity = TIMER_OCN_POLARITY_HIGH;
    timer_ocinitpara.ocidlestate = TIMER_OC_IDLE_STATE_LOW;
    timer_ocinitpara.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;
    timer_channel_output_config(US_TX_TIMER, US_TX_TIMER_CH, &timer_ocinitpara);

    /* config timer channel output mode */
    timer_channel_output_mode_config(US_TX_TIMER, US_TX_TIMER_CH, TIMER_OC_MODE_PWM0);

    /* config channel output pluse value (50% duty) */
    timer_channel_output_pulse_value_config(US_TX_TIMER, US_TX_TIMER_CH, 120);
    
    /* auto-reload preload enable */
    timer_auto_reload_shadow_enable(US_TX_TIMER);

    timer_counter_value_config(US_TX_TIMER, 0);

    timer_interrupt_enable(US_TX_TIMER, TIMER_INT_UP);
    nvic_irq_enable(TIMER13_IRQn, 2);

}

void ultrasonic_pwm_out_cycles(void) {
    
    g_ultrasonic_measure_done = false;

    timer_disable(TIMER13);

    timer_channel_output_state_config(TIMER13, TIMER_CH_0, TIMER_CCX_ENABLE);

    timer_enable(US_TX_TIMER);
    timer_enable(TIMER15);

}

// void ultrasonic_transmit_debounce_delay(const uint16_t micro_second) {
//     rcu_periph_clock_enable(US_TX_DELAY_RCU);
//     timer_deinit(US_TX_DELAY_TIMER);

//     timer_parameter_struct timer_initpara;
//     timer_struct_para_init(&timer_initpara);
//     timer_initpara.prescaler = 71;
//     timer_initpara.alignedmode = TIMER_COUNTER_EDGE;
//     timer_initpara.counterdirection = TIMER_COUNTER_UP;
//     timer_initpara.period = micro_second - 1;
//     timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
//     timer_initpara.repetitioncounter = 0;
//     timer_init(US_TX_DELAY_TIMER, &timer_initpara);

//     timer_auto_reload_shadow_enable(US_TX_DELAY_TIMER);
//     timer_interrupt_enable(US_TX_DELAY_TIMER, TIMER_INT_UP);
//     nvic_irq_enable(TIMER15_IRQn, 1U);
// }

void ultrasonic_receive_exti_config(void) {
    rcu_periph_clock_enable(US_RX_GPIO_RCU);
    rcu_periph_clock_enable(US_RX_EXTI_RCU);

    gpio_mode_set(US_RX_GPIO_PORT, GPIO_MODE_INPUT, GPIO_PUPD_NONE, US_RX_GPIO_PIN);
    nvic_irq_enable(US_RX_EXTI_IRQ, 0U);
    syscfg_exti_line_config(EXTI_SOURCE_GPIOA, US_RX_EXTI_LINE);

    exti_init(US_RX_GPIO_EXTI, EXTI_INTERRUPT, EXTI_TRIG_FALLING);
    exti_flag_clear(US_RX_GPIO_EXTI);

    // exti_interrupt_enable(EXTI_0);
}

void ultrasonic_echo_timer_config(void) {
    rcu_periph_clock_enable(US_ECHO_RCU);
    timer_deinit(US_ECHO_TIMER);

    timer_parameter_struct timer_initpara;
    timer_struct_para_init(&timer_initpara);
    timer_initpara.prescaler = 71;
    timer_initpara.alignedmode = TIMER_COUNTER_EDGE;
    timer_initpara.counterdirection = TIMER_COUNTER_UP;
    timer_initpara.period = ULTRASONIC_MAX_TOF_RELOAD - 1;
    timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
    timer_init(TIMER15, &timer_initpara);

    timer_oc_parameter_struct timer_oc_initpara;
    timer_channel_output_struct_para_init(&timer_oc_initpara);
    timer_oc_initpara.outputstate = TIMER_CCX_ENABLE;
    timer_oc_initpara.ocpolarity = TIMER_OC_POLARITY_HIGH;
    timer_channel_output_config(TIMER15, TIMER_CH_1,&timer_oc_initpara);

    timer_interrupt_enable(TIMER15, TIMER_INT_CH1 | TIMER_INT_UP);
    nvic_irq_enable(TIMER15_IRQn, 0);


    // timer_parameter_struct timer_initpara;
    // timer_struct_para_init(&timer_initpara);
    // timer_initpara.prescaler = 71;
    // timer_initpara.alignedmode = TIMER_COUNTER_EDGE;
    // timer_initpara.counterdirection = TIMER_COUNTER_UP;
    // timer_initpara.period = ULTRASONIC_MAX_TOF_RELOAD;
    // timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
    // timer_initpara.repetitioncounter = 0;
    // timer_init(US_ECHO_TIMER, &timer_initpara);

    // timer_ic_parameter_struct timer_icinitpara;
    // timer_channel_input_struct_para_init(&timer_icinitpara);
    // timer_icinitpara.icpolarity = TIMER_IC_POLARITY_BOTH_EDGE;
    // timer_icinitpara.icselection = TIMER_IC_SELECTION_INDIRECTTI;
    // timer_icinitpara.icprescaler = TIMER_IC_PSC_DIV1;
    // timer_icinitpara.icfilter = 0x03;
    // timer_input_capture_config(US_ECHO_TIMER, US_ECHO_CH, &timer_icinitpara);


}

void ultrasonic_config(void) {
    ultrasonic_tx_init();
    // ultrasonic_transmit_debounce_delay(TIME_CORRECTION_US);
    // ultrasonic_receive_exti_config();
    ultrasonic_echo_timer_config();
}

// uint16_t ultrasonic_calc_distance(void) {
//     // while (!ultrasonicMeasurementDone);
//     // uint32_t us_value = timer_channel_capture_value_register_read(US_ECHO_TIMER, US_ECHO_CH);
//     uint16_t distance = (TIME_CORRECTION_US + g_capture_value) * 17;
//     /*
//      *  (TIME_CORRECTION_US + us_value) * 340 m/s
//      *  -----------------------------------------
//      *                  1000 000
//      *  ----------------------------------------------
//      *                          2
//      */
//     return distance;
// }
