#include "timer_capture.h"

//---------- capture status definition: TMR3_CAP_STA ----------//
//bit[31:16]:   reserve.
//Bit [15]: A successful capture flag
//Bit [14]: rising edge mark
//Bit [13]: falling edge mark
//Bit [12]: measurement length exceeds the maximum value exception flag
//Bit [11:6]: overflow times of high-level counter
//Bit [5:0]: overflow times of low-level counter
#define TMR3_CAP_FINISH_MASK        0x8000
#define TMR3_CAP_RISE_MASK          0x4000
#define TMR3_CAP_FALL_MASK          0x2000
#define TMR3_CAP_ERROR_MASK         0x1000
#define CAP_HIGH_OVERFLOW()         ((TMR3_CAP_STA & 0x00000fc0) >> 6)
#define CAP_LOW_OVERFLOW()          (TMR3_CAP_STA & 0x0000003f)
#define CAP_HIGH_OVERFLOW_ADD()     (TMR3_CAP_STA += 0x40)
#define CAP_LOW_OVERFLOW_ADD()      (TMR3_CAP_STA++)
volatile u32 TMR3_CAP_STA = 0;
volatile u32 TMR3_CAP_VAL_H = 0;
volatile u32 TMR3_CAP_VAL_L = 0;

AT(.com_text.isr)
void timer3_cap_handle(void)
{
    if ((TMR3_CAP_STA & TMR3_CAP_FINISH_MASK) == RESET) {
        //Capture interrupt
        if (tmr_get_flag(TMR3, TMR_FLAG_CAP) != RESET) {
            tmr_clear_flag(TMR3, TMR_FLAG_CAP);
            if ((TMR3_CAP_STA & TMR3_CAP_RISE_MASK) != RESET) {     //Whether the rising edge has been captured
                if ((TMR3_CAP_STA & TMR3_CAP_FALL_MASK) != RESET) { //Whether the falling edge has been captured
                    TMR3_CAP_VAL_L = tmr_get_capture(TMR3);
                    TMR3_CAP_STA |= TMR3_CAP_FINISH_MASK;
                    TMR3_CAP_STA &= ~(TMR3_CAP_RISE_MASK | TMR3_CAP_FALL_MASK);
                } else {                                            //The falling edge has not been captured. Record the high level time value
                    TMR3_CAP_VAL_H = tmr_get_capture(TMR3);
                    TMR3_CAP_STA |= TMR3_CAP_FALL_MASK;
                    tmr_cmd(TMR3, DISABLE);
                    tmr_set_counter(TMR3, 0);
                    tmr_capture_config(TMR3, TMR_CAP_RISING, ENABLE);
                    tmr_cmd(TMR3, ENABLE);
                }
            } else {                                                //The rising edge has not been captured yet. Start capturing
                TMR3_CAP_STA = 0;
                TMR3_CAP_VAL_L = 0;
                TMR3_CAP_VAL_H = 0;
                TMR3_CAP_STA |= TMR3_CAP_RISE_MASK;
                tmr_cmd(TMR3, DISABLE);
                tmr_set_counter(TMR3, 0);
                tmr_capture_config(TMR3, TMR_CAP_FALLING, ENABLE);
                tmr_cmd(TMR3, ENABLE);

            }
        }
        //Overflow interrupt
        if (tmr_get_flag(TMR3, TMR_FLAG_UPDATE2) != RESET) {
            tmr_clear_flag(TMR3, TMR_FLAG_UPDATE2);
            if ((TMR3_CAP_STA & TMR3_CAP_RISE_MASK) != RESET) {
                if ((TMR3_CAP_STA & TMR3_CAP_FALL_MASK) != RESET) {     //Low level count overflow
                    if (CAP_LOW_OVERFLOW() == 0x0000003f) {
                        TMR3_CAP_STA = 0;
                        TMR3_CAP_STA |= TMR3_CAP_ERROR_MASK;
                    } else {
                        CAP_LOW_OVERFLOW_ADD();
                    }
                } else {       //High level count overflow
                    if (CAP_HIGH_OVERFLOW() == 0x00000fc0) {
                        TMR3_CAP_STA = 0;
                        TMR3_CAP_STA |= TMR3_CAP_ERROR_MASK;
                    } else {
                        CAP_HIGH_OVERFLOW_ADD();
                    }
                }
            }
        }
    }
}

void timer3_cap_init(u32 period)
{
    gpio_init_typedef gpio_init_structure;
    tmr_base_init_typedef tmr_base_init_struct;

    clock_gate1_cmd(CLOCK_GATE1_TMR3, ENABLE);

    gpio_init_structure.gpio_pin = GPIO_PIN_1;
    gpio_init_structure.gpio_dir = GPIO_DIR_INPUT;
    gpio_init_structure.gpio_fen = GPIO_FEN_PER;
    gpio_init_structure.gpio_mode = GPIO_MODE_DIGITAL;
    gpio_init_structure.gpio_pupd = GPIO_PUPD_PD;
    gpio_init(GPIOB_REG, &gpio_init_structure);

    gpio_func_mapping(TMR3CPTMAP_PB1);      // T3_CAP <- PB1

    tmr_base_init_struct.clock_source = TMR_INC_SOURCE;
    tmr_base_init_struct.increase_clock = TMR_COUNTER_RISING;
    tmr_base_init_struct.period = period;       // Maximun level time: = (period+1) * 63 + period, the 63 is max register count.
    tmr_base_init(TMR3, &tmr_base_init_struct);

    tmr_capture_config(TMR3, TMR_CAP_RISING, ENABLE);
    tmr_pic_config(TMR3, timer3_cap_handle, 0, TMR_IT_CAP | TMR_IT_UPDATE2, ENABLE);

    tmr_cmd(TMR3, ENABLE);
}


void timer3_capture_example(void)
{
    static u32 high_overflow, low_overflow;
    static u32 high_time, low_time;

    if (TMR3_CAP_STA & TMR3_CAP_FINISH_MASK) {
        high_overflow = CAP_HIGH_OVERFLOW();
        low_overflow = CAP_LOW_OVERFLOW();
        high_time = (high_overflow * (tmr_get_period(TMR3) + 1) + TMR3_CAP_VAL_H) ;
        low_time = (low_overflow * (tmr_get_period(TMR3) + 1) + TMR3_CAP_VAL_L) ;
        printf("period=%dus  high=%dus  low=%dus\n", high_time + low_time, high_time, low_time);
        TMR3_CAP_STA = 0;
    } else if (TMR3_CAP_STA & TMR3_CAP_ERROR_MASK) {
        TMR3_CAP_STA = 0;
        printf("---> ERROR: measure time long <---\n");
    }

}
