/*******************************************************************************
*                  COPYRIGHT (C) 2021 CMS Technologies Ltd.                    *
*                                                                              *
********************************************************************************
* FileName      : tim_demo.c                                                  *
* Author        :                                                              *
* Version       : 1.0                                                          *
* Date          : 2021.08.13                                                   *
* Description   :                                                              *
* Function List :                                                              *
********************************************************************************/
#include "RTE_TIM40.h"
#include "cgc.h"
#include "common.h"
#include "BAT32A279.h"
#include "gpio.h"
#include "tim.h"
#include "string.h"
#include "isr.h"


typedef struct 
{
    uint32_t u32Period[RTE_TIM40_PERIOD_FILTER_SUM];
    uint32_t u32Freq;  
    uint8_t  u8PeriodCnt;  
    uint8_t  u8PeriodBufCnt; 
    uint32_t u32CHClock; 
}TIM40CapObj_st_t;

volatile TIM40CapObj_st_t    g_stTIM40CapObj[RTE_TIM40_CH_SUM];

void RTE_TIM4_Capture_Init(uint8_t u8CapChannel);
uint32_t RTE_Frequency_Get(uint8_t u8ch);
void tim40_channel0_interrupt(void );
void tim40_channel1_interrupt(void );
void tim40_channel2_interrupt(void );
void tim40_channel3_interrupt(void );
void RTE_Calc_Freq(uint8_t u8ch);



void RTE_CAPTURE_KL30_Init(void)
{    
    memset((void*)g_stTIM40CapObj,0,sizeof(g_stTIM40CapObj));
    RTE_TIM4_Capture_Init(RTE_VSPEED_CAP_CH);
    RTE_TIM4_Capture_Init(RTE_ENGINE_CAP_CH);
}

void RTE_CAPTURE_Wakeup_Init(void)
{
    memset((void*)g_stTIM40CapObj,0,sizeof(g_stTIM40CapObj));
    RTE_TIM4_Capture_Init(RTE_VSPEED_CAP_CH);
    RTE_TIM4_Capture_Init(RTE_ENGINE_CAP_CH);
}

void RTE_CAPTURE_Sleep_Init(void)
{
    TIM_Cmd(TM40,RTE_TIM40_CH0,DISABLE);
    TIM_Cmd(TM40,RTE_TIM40_CH1,DISABLE);
    TIM_Cmd(TM40,RTE_TIM40_CH2,DISABLE);
    TIM_Cmd(TM40,RTE_TIM40_CH3,DISABLE);
    CGC_PER0PeriphClockCmd(CGC_PER0Periph_TIM40,DISABLE);
}

uint32_t RTE_VSPEED_Freq_Get(void)
{
    return RTE_Frequency_Get(RTE_VSPEED_CAP_CH);
}

uint32_t RTE_ENGINE_Freq_Get(void)
{
    return RTE_Frequency_Get(RTE_ENGINE_CAP_CH);
}

const uint32_t TIM4_Clock[16U] = {

    64000000UL,
    32000000UL,
    16000000UL,
    8000000UL,
    4000000UL,
    2000000UL,
    1000000UL,
    500000UL,
    250000UL,
    125000UL,
    62500UL,
    31250UL,
    15625UL,
    7812UL,
    3906UL,
    1953UL,
};

void RTE_TIM4_Capture_Init(uint8_t u8CapChannel)
{
    TIM_InitTypeDef TIM_InitStructure;
    GPIO_InitTypeDef GPIO_InitStruct;
    uint8_t u8IndexCh;

    
    u8IndexCh = 1 << u8CapChannel;
    
    switch (u8IndexCh)
    {
        case TIM_Channel_0:            

            GPIO_PinAFConfig(GPIO_PORT0, GPIO_Pin_0, GPIO_P00, GROUP_AF_ODEFAULT); //P00 used as TI00 input

            GPIO_InitStruct.GPIO_Pin    = GPIO_Pin_0;
            GPIO_InitStruct.GPIO_Mode   = GPIO_Mode_IN;
            GPIO_InitStruct.GPIO_Ctrl   = GPIO_Control_DIG;
            GPIO_Init(GPIO_PORT0, &GPIO_InitStruct);

			
            TIM_InitStructure.TIM_Channel     = TIM_Channel_0;
            TIM_InitStructure.TIM_ClkDivision = TIM_CLK0_Div128;   //specify the operation clk of tim
            TIM_InitStructure.TIM_Trigger     = TIM_Trigger_IputEdge; //IputEdge is used to start trigger and capture trigger
            TIM_InitStructure.TIM_Pulse_Edge  = TIM_Pulse_Rising;  // Measure the high or low level pulse width of P00/TI00  /TIM_Pulse_Both/TIM_Pulse_Rising

            TIM_InitStructure.TIM_Mode        = TIM_Mode_PluseInterval;  // pulse interval measure: use capture function
            TIM_InitStructure.TIM_StartInt    = TIM_StartInt_Disable;
            TIM_InitStructure.TIM4_Input      = TIM4_CH0_Input_TI00;  // specify the input of TI

            g_stTIM40CapObj[u8CapChannel].u32CHClock = TIM4_Clock[TIM_InitStructure.TIM_ClkDivision];
            TIM_Init(TM40,&TIM_InitStructure);
                    
            ISR_Register(TM00_IRQn, tim40_channel0_interrupt);  
            break;
        case TIM_Channel_1:            

            GPIO_PinAFConfig(GPIO_PORT1, GPIO_Pin_6, GPIO_P16, GROUP_AF_ODEFAULT); //P16 used as TI01 input转速GPIO

            GPIO_InitStruct.GPIO_Pin    = GPIO_Pin_6;
            GPIO_InitStruct.GPIO_Mode   = GPIO_Mode_IN;
            GPIO_InitStruct.GPIO_Ctrl   = GPIO_Control_DIG;
            GPIO_Init(GPIO_PORT0, &GPIO_InitStruct);
          
            TIM_InitStructure.TIM_Channel     = TIM_Channel_1;
            TIM_InitStructure.TIM_ClkDivision = TIM_CLK0_Div128;   //specify the operation clk of tim
            TIM_InitStructure.TIM_Trigger     = TIM_Trigger_IputEdge; //IputEdge is used to start trigger and capture trigger
            TIM_InitStructure.TIM_Pulse_Edge  = TIM_Pulse_Both;  // Measure the high or low level pulse width of P00/TI00  /TIM_Pulse_Both/TIM_Pulse_Rising

            TIM_InitStructure.TIM_Mode        = TIM_Mode_PluseInterval;  // pulse interval measure: use capture function
            TIM_InitStructure.TIM_StartInt    = TIM_StartInt_Disable;
            TIM_InitStructure.TIM4_Input      = TIM4_CH1_Input_TI01;  // specify the input of TI
            TIM_Init(TM40,&TIM_InitStructure);

            g_stTIM40CapObj[u8CapChannel].u32CHClock = TIM4_Clock[TIM_InitStructure.TIM_ClkDivision];        
            ISR_Register(TM01_IRQn, tim40_channel1_interrupt);  
            break;
        case TIM_Channel_2:            

            GPIO_PinAFConfig(GPIO_PORT1, GPIO_Pin_7, GPIO_P17, GROUP_AF_ODEFAULT); //P17 used as TI02 input车速
            GPIO_InitStruct.GPIO_Pin    = GPIO_Pin_7;
            GPIO_InitStruct.GPIO_Mode   = GPIO_Mode_IN;
            GPIO_InitStruct.GPIO_Ctrl   = GPIO_Control_DIG;
            GPIO_Init(GPIO_PORT0, &GPIO_InitStruct);

         
            TIM_InitStructure.TIM_Channel     = TIM_Channel_2;
            TIM_InitStructure.TIM_ClkDivision = TIM_CLK0_Div128;   //specify the operation clk of tim
            TIM_InitStructure.TIM_Trigger     = TIM_Trigger_IputEdge; //IputEdge is used to start trigger and capture trigger
            TIM_InitStructure.TIM_Pulse_Edge  = TIM_Pulse_Both;  // Measure the high or low level pulse width of P00/TI00  /TIM_Pulse_Both/TIM_Pulse_Rising

            TIM_InitStructure.TIM_Mode        = TIM_Mode_PluseInterval;  // pulse interval measure: use capture function
            TIM_InitStructure.TIM_StartInt    = TIM_StartInt_Disable;
            TIM_InitStructure.TIM4_Input      = TIM4_CH0_Input_TI00;  // specify the input of TI

            g_stTIM40CapObj[u8CapChannel].u32CHClock = TIM4_Clock[TIM_InitStructure.TIM_ClkDivision];

            TIM_Init(TM40,&TIM_InitStructure);
                    
            ISR_Register(TM02_IRQn, tim40_channel2_interrupt);  
            break;
        case TIM_Channel_3:            

            GPIO_PinAFConfig(GPIO_PORT3, GPIO_Pin_1, GPIO_P31, GROUP_AF_ODEFAULT); //P31 used as TI03 input

            GPIO_InitStruct.GPIO_Pin    = GPIO_Pin_1;
            GPIO_InitStruct.GPIO_Mode   = GPIO_Mode_IN;
            GPIO_InitStruct.GPIO_Ctrl   = GPIO_Control_DIG;
            GPIO_Init(GPIO_PORT0, &GPIO_InitStruct);

           
            TIM_InitStructure.TIM_Channel     = TIM_Channel_3;
            TIM_InitStructure.TIM_ClkDivision = TIM_CLK0_Div32;   //specify the operation clk of tim
            TIM_InitStructure.TIM_Trigger     = TIM_Trigger_IputEdge; //IputEdge is used to start trigger and capture trigger
            TIM_InitStructure.TIM_Pulse_Edge  = TIM_Pulse_Rising;  // Measure the high or low level pulse width of P00/TI00  /TIM_Pulse_Both/TIM_Pulse_Rising

            TIM_InitStructure.TIM_Mode        = TIM_Mode_PluseInterval;  // pulse interval measure: use capture function
            TIM_InitStructure.TIM_StartInt    = TIM_StartInt_Disable;
            TIM_InitStructure.TIM4_Input      = TIM4_CH0_Input_TI00;  // specify the input of TI

            g_stTIM40CapObj[u8CapChannel].u32CHClock = TIM4_Clock[TIM_InitStructure.TIM_ClkDivision];

            TIM_Init(TM40,&TIM_InitStructure);
                    
            ISR_Register(TM03_IRQn, tim40_channel3_interrupt);  
            break;    
        default:
            break;
    }
    TIM_Start(TM40,u8CapChannel);
}




uint32_t RTE_Frequency_Get(uint8_t u8ch)
{ /* unit : 0.1HZ */
    return g_stTIM40CapObj[u8ch].u32Freq;
}


void RTE_Calc_Freq(uint8_t u8ch)
{
    uint32_t u32Temp = 0U;
    uint8_t i = 0U;
    uint16_t u16TDR;
    uint16_t u16TSR;
    uint8_t u8RollingCh = 0;
     
    switch (u8ch)
    {
        case RTE_TIM40_CH0:
            u16TDR = TM40->TDR[0U];
            u16TSR = TM40->TSR[0U];         
            break;
        case RTE_TIM40_CH1:
            u16TDR = TM40->TDR[1U];
            u16TSR = TM40->TSR[1U];   
            u8RollingCh = 0U;
            break;
        case RTE_TIM40_CH2:
            u16TDR = TM40->TDR[2U];
            u16TSR = TM40->TSR[2U];  
            break;
        case RTE_TIM40_CH3:
            u16TDR = TM40->TDR[3U];
            u16TSR = TM40->TSR[3U];   
            break;        
        default:
            u16TDR = TM40->TDR[0U];
            u16TSR = TM40->TSR[0U];  
            break;
    }
    if (1U == (u16TSR & _0001_TM4_OVERFLOW_OCCURS))
    {
        g_stTIM40CapObj[u8ch].u32Period[g_stTIM40CapObj[u8ch].u8PeriodBufCnt] = (uint32_t)(u16TDR + 1UL) + 0x10000UL;                
    }
    else
    {
        g_stTIM40CapObj[u8ch].u32Period[g_stTIM40CapObj[u8ch].u8PeriodBufCnt] = (uint32_t)(u16TDR + 1UL);  
//        Fre_In_Channel_Capture_ISR_Reset_Count(FRE_ENGINE,g_stTIM40CapObj[u8ch].u32Period[g_stTIM40CapObj[u8ch].u8PeriodBufCnt]);
    }
    g_stTIM40CapObj[u8ch].u8PeriodBufCnt++;
    if (g_stTIM40CapObj[u8ch].u8PeriodBufCnt >= RTE_TIM40_PERIOD_FILTER_SUM)
    {
        g_stTIM40CapObj[u8ch].u8PeriodBufCnt = 0U;
    }
    
    if (g_stTIM40CapObj[u8ch].u8PeriodCnt < RTE_TIM40_PERIOD_FILTER_SUM)
    {
        g_stTIM40CapObj[u8ch].u8PeriodCnt++;            
    }

    for( i = 0U;i < g_stTIM40CapObj[u8ch].u8PeriodCnt;i++)
    {
        u32Temp += g_stTIM40CapObj[u8ch].u32Period[i];
    }
    u32Temp = u32Temp / g_stTIM40CapObj[u8ch].u8PeriodCnt;
      
    g_stTIM40CapObj[u8ch].u32Freq = (g_stTIM40CapObj[u8ch].u32CHClock * 10U) / u32Temp;
}

/***********************************************************************************************************************
* Function Name: tim40_channel0_interrupt
* @brief  TIM4 Channel interrupt service routine
* @param  msg
* @return None
***********************************************************************************************************************/
void tim40_channel0_interrupt(void)
{
    INTC_ClearPendingIRQ(TM00_IRQn);    // clear INTTM00 interrupt flag
    RTE_Calc_Freq(RTE_TIM40_CH0);    
}

/***********************************************************************************************************************
* Function Name: tim40_channel1_interrupt
* @brief  TIM4 Channel interrupt service routine
* @param  msg
* @return None
***********************************************************************************************************************/
void tim40_channel1_interrupt(void)
{
    INTC_ClearPendingIRQ(TM01_IRQn);    // clear INTTM01 interrupt flag
    RTE_Calc_Freq(RTE_TIM40_CH1);
}

/***********************************************************************************************************************
* Function Name: tim40_channel2_interrupt
* @brief  TIM4 Channel interrupt service routine
* @param  msg
* @return None
***********************************************************************************************************************/
void tim40_channel2_interrupt(void)
{
    INTC_ClearPendingIRQ(TM02_IRQn);    // clear INTTM02 interrupt flag
    RTE_Calc_Freq(RTE_TIM40_CH2);
}

/***********************************************************************************************************************
* Function Name: tim40_channel3_interrupt
* @brief  TIM4 Channel interrupt service routine
* @param  msg
* @return None
***********************************************************************************************************************/
void tim40_channel3_interrupt(void)
{
    INTC_ClearPendingIRQ(TM03_IRQn);    // clear INTTM03 interrupt flag
    RTE_Calc_Freq(RTE_TIM40_CH3);
}
