/*******************************************************************************
*                  COPYRIGHT (C) 2021 CMS Technologies Ltd.                    *
*                                                                              *
********************************************************************************
* FileName      : tim.c                                                  *
* Author        :                                                              *
* Version       : 1.0.2                                                          *
* Date          : 2024.04.07                                                   *
* Description   :                                                              *
* Function List :                                                              *
********************************************************************************/
#include "tim.h"
#include "cgc.h"

//#if defined(BAT32G1XX_80PIN) || defined(BAT32G1XX_100PIN)
#define TIM_CHAN_MAX_NUM    8u
#define TIM_MAX_NUM    		2u

static IRQn_Type TIM_IRQTable[TIM_MAX_NUM][TIM_CHAN_MAX_NUM] = 
{{TM00_IRQn, TM01_IRQn, TM02_IRQn, TM03_IRQn},
{TM10_IRQn, TM11_IRQn, TM12_IRQn, TM13_IRQn,TM14_IRQn,TM15_IRQn,TM16_IRQn,TM17_IRQn},
};
//#else
//#define TIM_CHAN_MAX_NUM    4u
//#define TIM_MAX_NUM    		1u

//static IRQn_Type TIM_IRQTable[TIM_MAX_NUM][TIM_CHAN_MAX_NUM] = 
//{{TM00_IRQn, TM01_IRQn, TM02_IRQn, TM03_IRQn}};
//#endif


/**
  * @brief  Enables the specified TIMER channel.
  * @param  TIMx: the specified tim, it can be TIM40 TIM41
  * @param  ChxIdx where ChxIdx can be 0, 1,2,3.
  *         @arg TTM_Index_Channel0
  *         @arg TTM_Index_Channel1
  *         @arg TTM_Index_Channel2
  *         @arg TTM_Index_Channel3
  *         @arg TIM_Index_Channel4
  *         @arg TIM_Index_Channel5
  *         @arg TIM_Index_Channel6
  *         @arg TIM_Index_Channel7  
  * @retval None
  */
void TIM_Start(TMx_Type* TMx, uint8_t ChxIdx)
{
	assert_param(IS_TIM(TMx));	
	assert_param(IS_TIM_CHANIDEX(ChxIdx));
	
	TMx->TS = (1 << ChxIdx);
}


/**
  * @brief  Disable the specified TIMER channel count.
  * @param  tim: the specified tim, it can be TIM40 TIM41
  * @param  ChxIdx where ChxIdx can be 0, 1,2,3.
  *         @arg TIM_Index_Channel0
  *         @arg TIM_Index_Channel1
  *         @arg TIM_Index_Channel2
  *         @arg TIM_Index_Channel3
  *         @arg TIM_Index_Channel4
  *         @arg TIM_Index_Channel5
  *         @arg TIM_Index_Channel6
  *         @arg TIM_Index_Channel7
  * @retval None
  */
void TIM_Stop(TMx_Type* TMx, uint8_t ChxIdx)
{
	assert_param(IS_TIM(TMx));	
	assert_param(IS_TIM_CHANIDEX(ChxIdx));
	
	TMx->TT = (1 << ChxIdx);
}

/**
  * @brief  Enables or disables the specified TIMER channel.
  * @param  TIMx: TMx is TM40 or TM81.
  * @param  Chx: where x can be 0, 1,2,3 select channel of  specified TIMER peripheral.
  * @param  NewState: new state of the TIEMR channel.
  *          This parameter can be: ENABLE or DISABLE.
  * @retval None
  */
void TIM_Cmd(TMx_Type* TMx, uint8_t Chx, FunctionalState NewState)
{

	if(NewState == ENABLE)
		TIM_Start(TMx,Chx);
	else
		TIM_Stop(TMx,Chx);
}

/**
  * @brief  Set the specified TIMER channel's count num.
  * @param  TIMx: where x can be 0, 1, select TIEMR peripheral.
  * @param  Chx: where x can be 0, 1,2,3 4.5.6.7
  * @param  counter: the count num of the TIEMR channel.          
  * @retval None
  */
void TIM_SetCounter(TMx_Type* TMx, uint8_t ChxIdx, uint16_t counter)
{
	assert_param(IS_TIM(TMx));	
	assert_param(IS_TIM_CHANIDEX(ChxIdx));
	
	TMx->TDR[ChxIdx] = counter;	
}

/**
  * @brief  Get the specified TIMER channel's status.
  * @param  TIMx: where x can be 0, 1, select TIEMR peripheral.
  * @param  Chx: where x can be 0, 1,2,3.4.5.6.7 select channel of  specified TIMER peripheral.        
  * @retval bool: 1 it occurs overflow 
  *               0 it does not occur overflow
  */
bool TIM_GetStatus(TMx_Type* TMx, uint8_t ChxIdx)
{	
	assert_param(IS_TIM(TMx));	
	assert_param(IS_TIM_CHANIDEX(ChxIdx));
		
	
	return (bool)(TMx->TSR[ChxIdx] & _0001_TM4_OVERFLOW_OCCURS);
}

/**
  * @brief  Initializes the TIEMR peripheral according to the specified
  *         parameters in the TIM_InitStruct .
  * @param  TIM_InitStruct: pointer to a TIM_InitTypeDef structure that contains
  *         the configuration information for the specified TIEMR peripheral.
  * @retval initial result
  */
int TIM_Init(TMx_Type* TMx,TIM_InitTypeDef *TIM_InitStruct)
{
	int ret = TIM_SUCC;
	uint16_t clkselect = TM_CLOCK_SELECT_CKM0;
	uint8_t chanPos =0,chanNum=0,pos=0;
	uint8_t masterPos =0,masterNum=0,posm=0;
	
	assert_param(IS_TIM(TMx));	
	assert_param(IS_TIM_CHANNEL(TIM_InitStruct->TIM_Channel));
	
	if(TMx == TM40)
	{
		CGC_PER0PeriphClockCmd(CGC_PER0Periph_TIM40,ENABLE);
	}
#if defined(BAT32G1XX_80PIN) || defined(BAT32G1XX_100PIN)
	if(TMx == TM81)
	{
		CGC_PER2PeriphClockCmd(CGC_PER2Periph_TM81,ENABLE);
	}
#endif
	
	if(IS_TIM_CLK0(TIM_InitStruct->TIM_ClkDivision)){
		TMx->TPS &= ~TIM_CLK0_MASK;
		TMx->TPS |= TIM_InitStruct->TIM_ClkDivision;
		clkselect = TM_CLOCK_SELECT_CKM0;
	}else if(IS_TIM_CLK1(TIM_InitStruct->TIM_ClkDivision)){
		TMx->TPS &= ~TIM_CLK1_MASK;
		TMx->TPS |= TIM_InitStruct->TIM_ClkDivision;
		clkselect = TM_CLOCK_SELECT_CKM1;
	}else if(IS_TIM_CLK2(TIM_InitStruct->TIM_ClkDivision)){
		TMx->TPS &= ~TIM_CLK2_MASK;
		TMx->TPS |= TIM_InitStruct->TIM_ClkDivision;
		clkselect = TM_CLOCK_SELECT_CKM2;	
	}else if(IS_TIM_CLK3(TIM_InitStruct->TIM_ClkDivision)){
		TMx->TPS &= ~TIM_CLK3_MASK;
		TMx->TPS |= TIM_InitStruct->TIM_ClkDivision;
		clkselect = TM_CLOCK_SELECT_CKM3;		
	}else{
		return TIM_ERR;
	}
	
	if(IS_TTM_Master_Chan(TIM_InitStruct->TIM_Selection_Master))//multi-tim combination
	{
		for(masterPos = 0; masterPos < TIM_CHAN_MAX_NUM; masterPos++)
		{
			posm = ((char)0x01) << masterPos;
			masterNum = TIM_InitStruct->TIM_Selection_Master & posm;
			if(masterNum == posm)
			{	
				if(masterPos == TIM_Index_Channel0)
				{
					TMx->TMR[masterPos] = clkselect | TIM_InitStruct->TIM_Trigger | TIM_InitStruct->TIM_Pulse_Edge | TIM_Mode_PWM_Master | TIM_InitStruct->TIM_StartInt;								
				}
				else
				{
					TMx->TMR[masterPos] = clkselect | 0x0800 |TIM_InitStruct->TIM_Trigger | TIM_InitStruct->TIM_Pulse_Edge | TIM_Mode_PWM_Master | TIM_InitStruct->TIM_StartInt;								
				}
				TMx->TDR[masterPos] = TIM_InitStruct->TIM_Period[masterPos] -1;				 
				
				TMx->TOE &= ~(1 << masterPos);
				TMx->TO &= ~(1 << masterPos);				
				MISC->NFEN1 |=  (1<<masterPos);	 //???			
			}			
		}
		for(chanPos = 0; chanPos < TIM_CHAN_MAX_NUM; chanPos++)   //???????????
		{
			pos = ((uint8_t)0x01) << chanPos;
			chanNum = TIM_InitStruct->TIM_Channel & pos;
			if(chanNum == pos)
			{
			    TMx->TMR[chanPos] = clkselect | TIM_Trigger_UseMaster_Int | TIM_Mode_SinglePulse |TIM_InitStruct->TIM_StartInt;
				TMx->TDR[chanPos] = TIM_InitStruct->TIM_Period[chanPos];
				TMx->TO &= ~(1 << chanPos);
				TMx->TOE |= (1 << chanPos);
				TMx->TOM |= (1 << chanPos);
			}
		}
		TMx->TOL|= TIM_InitStruct->TIM_Slave_Polarity;

	}
	else
	{
		for(chanPos = 0; chanPos < TIM_CHAN_MAX_NUM; chanPos++)
		{
			pos = ((uint8_t)0x01) << chanPos;
			chanNum = TIM_InitStruct->TIM_Channel & pos;
			if(chanNum == pos)
			{
				TMx->TDR[chanPos] = TIM_InitStruct->TIM_Period[chanPos] -1;				
				TMx->TT |=  TIM_InitStruct->TIM_Channel;   //TIM stop
				TMx->TMR[chanPos] = clkselect | TIM_InitStruct->TIM_Trigger | TIM_InitStruct->TIM_Pulse_Edge  | TIM_InitStruct->TIM_StartInt;
				TMx->TO &= ~ TIM_InitStruct->TIM_Channel;
				/*g??TIM_Mode_Interval/TIM_Mode_Square/TIM_Mode_DivFreq TMR?J???g??????0x0000*/
				if(TIM_InitStruct->TIM_Mode == TIM_Mode_Interval)    //?????g??????TO???????
				{
					TMx->TOE &= ~TIM_InitStruct->TIM_Channel;
				}
				else if(TIM_InitStruct->TIM_Mode == TIM_Mode_Square)
				{
					TMx->TOE |= TIM_InitStruct->TIM_Channel;				
				}
				else if(TIM_InitStruct->TIM_Mode == TIM_Mode_DivFreq) //???g?h???????channel0 ???
				{
					assert_param(IS_TIM_CHANNEL0(TIM_InitStruct->TIM_Channel));
					if(IS_TIM_CHANNEL0(TIM_InitStruct->TIM_Channel))
					{
						TMx->TOE |= TIM_InitStruct->TIM_Channel;
					}						
				}
				else   //input event for tim 
				{
					TMx->TOE &= ~ TIM_InitStruct->TIM_Channel;
					TMx->TMR[chanPos] |= TIM_InitStruct->TIM_Mode;
					if(TIM_InitStruct->TIM_Mode == TIM_Mode_EventCount)
					{
						TMx->TMR[chanPos] |= 0x1000;	//????????w????	
					}
					if(TMx == TM40)
					{
						 MISC->NFEN1 |=  TIM_InitStruct->TIM_Channel;
					}
#if defined(BAT32G1XX_80PIN) || defined(BAT32G1XX_100PIN)
					if(TMx == TM81)
					{
						 MISC->NFEN2 |=  TIM_InitStruct->TIM_Channel;
					}	
#endif								
					if((TIM_InitStruct->TIM_Channel == TIM_Channel_0 || TIM_InitStruct->TIM_Channel == TIM_Channel_1) && (TMx == TM40))
					{
						MISC->TIOS0 |=  TIM_InitStruct->TIM4_Input;
						if(TIM_InitStruct->TIM4_Input)
						{
							MISC->NFEN1 &=  ~(TIM_InitStruct->TIM_Channel);					
						}	
					}		
				}					
			}
		}
	}
	
	return ret;
}

/**
  * @brief  The Timer operates as pulse width measure.
  * @param  tim - choose timer unit it can choose TIM40 TIM41
  * @param  chxIdx - choose 0~7   
  * @retval period - return the pulse period at specified edge
  */
uint32_t TIM_GetPulsePeriod(TMx_Type* TMx, uint8_t ChxIdx)
{	
	uint8_t tindex = 0;
	uint32_t width = 0;
	
	assert_param(IS_TIM_CHANIDEX(ChxIdx));
	assert_param(IS_TIM(TMx));
	
	if(TMx == TM40)
	{
		tindex = 0;
	}
	else
	{
		tindex = 1;
	}
	
	if(INTC_GetPendingIRQ(TIM_IRQTable[tindex][ChxIdx]))
	{
		INTC_ClearPendingIRQ(TIM_IRQTable[tindex][ChxIdx]); /* clear INTTMA interrupt flag */
	}

	if (1U == (TMx->TSR[ChxIdx] & _0001_TM4_OVERFLOW_OCCURS))
	{
		width= (uint32_t)(TMx->TDR[ChxIdx] + 1UL) + 0x10000UL;
	}
	else
	{
		width= (uint32_t)(TMx->TDR[ChxIdx] + 1UL);
	}

    return (width);
}

/**
  * @brief  The Timer operates as pulse width measure.
  * @param  tim - choose timer unit it can choose TIM40 TIM41
  * @param  chxIdx - choose 0~7   
  * @retval pulse width - return the width of pulse
  */
uint32_t TIM_GetPulseWidth(TMx_Type* TMx, uint8_t ChxIdx)
{
	uint8_t tindex = 0;
	uint32_t width = 0;
	
	assert_param(IS_TIM_CHANIDEX(ChxIdx));
	assert_param(IS_TIM(TMx));
	
	
	if(TMx == TM40)
	{
		tindex = 0;
	}
	else
	{
		tindex = 1;
	}
	if(INTC_GetPendingIRQ((TIM_IRQTable[tindex][ChxIdx])))
	{
		INTC_ClearPendingIRQ(TIM_IRQTable[tindex][ChxIdx]); /* clear INTTM interrupt flag */
	}
	else
	{
		return (width);
	}


	if (1U == (TMx->TSR[ChxIdx] & _0001_TM4_OVERFLOW_OCCURS))
	{
		width= (uint32_t)(TMx->TDR[ChxIdx] + 1UL) + 0x10000UL;
	}
	else
	{
		width= (uint32_t)(TMx->TDR[ChxIdx] + 1UL);
	}


    return (width);
}