#include "Timer.h"
#include "stm32f1xx_ll_bus.h" // Pour l'activation des horloges
#include "stm32f1xx_ll_tim.h" // Pour les timers


/****************************************************************************
  *																	INTERRUPTIONS
	***************************************************************************/


// variable pointeur de fonction permettant de mémoriser le callback à appeler depuis
// le handler d'IT
void (*it_callback_TIM1)(void); 
void (*it_callback_TIM2)(void); 
void (*it_callback_TIM3)(void); 
void (*it_callback_TIM4)(void); 


void TIM1_UP_IRQHandler(void)
{
	// rabaisser le flag d'IT
	LL_TIM_ClearFlag_UPDATE(TIM1);
	(*it_callback_TIM1)();
}	

void TIM2_IRQHandler(void)
{
	// rabaisser le flag d'IT
	LL_TIM_ClearFlag_UPDATE(TIM2);
	(*it_callback_TIM2)();
}	

void TIM3_IRQHandler(void)
{
	// rabaisser le flag d'IT
	LL_TIM_ClearFlag_UPDATE(TIM3);
	(*it_callback_TIM3)();
}	

void TIM4_IRQHandler(void)
{
	// rabaisser le flag d'IT
	LL_TIM_ClearFlag_UPDATE(TIM4);
	(*it_callback_TIM4)();
}	


/**
	* @brief  Autorise les interruptions
  * @note   
	* @param  TIM_TypeDef Timer : indique le timer à utiliser par le chronomètre, TIM1, TIM2, TIM3 ou TIM4
  * @retval None
  */
void Timer_IT_enable(TIM_TypeDef * timer)
{
	LL_TIM_EnableIT_UPDATE(timer);
}


/**
	* @brief  Interdit les interruptions
  * @note   
	* @param  TIM_TypeDef Timer : indique le timer à utiliser par le chronomètre, TIM1, TIM2, TIM3 ou TIM4
  * @retval None
  */
void Timer_IT_disable(TIM_TypeDef * timer)
{
	LL_TIM_DisableIT_UPDATE(timer); 
}

/**
	* @brief  Configure le Timer considéré en interruption sur débordement.
  * @note   A ce stade, les interruptions ne sont pas validés (voir  MyTimer_IT_Enable )
	* @param  TIM_TypeDef Timer : indique le timer à utiliser par le chronomètre, TIM1, TIM2, TIM3 ou TIM4
	* 				void (*IT_function) (void) : nom (adresse) de la fonction à lancer sur interruption
	*         int Prio : priorité associée à l'interruption
  * @retval None
  */
void Timer_IT_conf(TIM_TypeDef * timer, void (*it_callback) (void), int prio)
{
	// affectation de la fonction
	if (timer == TIM1) it_callback_TIM1 = it_callback;
	else if (timer == TIM2)	it_callback_TIM2 = it_callback;
	else if (timer == TIM3)	it_callback_TIM3 = it_callback;
	else  it_callback_TIM4 = it_callback;

	
	// Blocage IT (il faudra la débloquer voir fct suivante)
	LL_TIM_DisableIT_UPDATE(timer);
	
	// validation du canal NVIC
	IRQn_Type TIM_irq;
	
	if (timer == TIM1) TIM_irq = TIM1_UP_IRQn;
	else if (timer == TIM2)	TIM_irq = TIM2_IRQn;
	else if (timer == TIM3)	TIM_irq = TIM3_IRQn;
	else 	TIM_irq = TIM4_IRQn;
	
	NVIC_SetPriority(TIM_irq, prio);
	NVIC_EnableIRQ(TIM_irq);

	
}

/****************************************************************************
  *																	TIMER
	***************************************************************************/

/**
	* @brief  Démarre le timer considéré et active les interruptions
  * @note   
	* @param  TIM_TypeDef Timer : indique le timer à utiliser par le chronomètre, TIM1, TIM2, TIM3 ou TIM4
  * @retval None
  */
void Timer_start(TIM_TypeDef * timer)
{
	LL_TIM_EnableCounter(timer);
}

/**
	* @brief  Arrêt le timer considéré  et désactive les interruptions
  * @note   
	* @param  TIM_TypeDef Timer : indique le timer à utiliser par le chronomètre, TIM1, TIM2, TIM3 ou TIM4
  * @retval None
  */
void Timer_stop(TIM_TypeDef * timer)
{
	LL_TIM_DisableCounter(timer);
}

/**
	* @brief  Active l'horloge et règle l'ARR et le PSC du timer visé.
  * @note   Fonction à lancer avant toute autre. Le timer n'est pas encore lancé (voir Timer_start)
	* @param  TIM_TypeDef Timer : indique le timer à utiliser par le chronomètre, TIM1, TIM2, TIM3 ou TIM4
	* 				int Arr   : valeur à placer dans ARR
	*					int Psc   : valeur à placer dans PSC
  * @retval None
  */
void Timer_conf(TIM_TypeDef * timer, int arr, int psc)
{
	LL_TIM_InitTypeDef init_struct;
	
	// Validation horloge locale
	if (timer == TIM1) LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_TIM1);
	else if (timer == TIM2) LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM2);
	else if (timer == TIM3) LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM3);
	else  LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM4);
	
	// chargement structure Arr, Psc, Up Count
	init_struct.Autoreload = arr;
	init_struct.Prescaler = psc;
	init_struct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1;
	init_struct.CounterMode = LL_TIM_COUNTERMODE_UP;
	init_struct.RepetitionCounter = 0;
	
	LL_TIM_Init(timer,&init_struct);

	// Blocage interruptions
	Timer_IT_disable(timer);
	
	// Blocage Timer
	Timer_stop(timer);
}

/****************************************************************************
  *																	PWM INPUT
	***************************************************************************/


/****************************************************************************
  *																	PWM OUTPUT
	***************************************************************************/

int getArrFromFreq(float freq_khz)
{
	return (72000 / freq_khz) - 1;
}

void PWMo_conf(TIM_TypeDef * timer, int channel, float freq_khz, float dutyCycle)
{
	const int arr = getArrFromFreq(freq_khz);
	Timer_conf(timer, arr, 0);
	LL_TIM_OC_InitTypeDef init_struct;
	LL_TIM_OC_StructInit(&init_struct);
	
	init_struct.OCMode = LL_TIM_OCMODE_PWM1;
	init_struct.OCState = LL_TIM_OCSTATE_ENABLE;
	init_struct.CompareValue= dutyCycle * arr;
	
	LL_TIM_OC_Init(timer, channel, &init_struct);
}

void PWMo_setDutyCycle(TIM_TypeDef * timer, int channel, float freq_khz, float dutyCycle)
{
	int compare = dutyCycle * getArrFromFreq(freq_khz);
	if (channel == LL_TIM_CHANNEL_CH1) LL_TIM_OC_SetCompareCH1(timer, compare);
	else if (channel == LL_TIM_CHANNEL_CH2) LL_TIM_OC_SetCompareCH2(timer, compare);
	else if (channel == LL_TIM_CHANNEL_CH3) LL_TIM_OC_SetCompareCH3(timer, compare);
	else  LL_TIM_OC_SetCompareCH4(timer, compare);
}

/****************************************************************************
  *																ENCODER
	***************************************************************************/

void Timer_encoder_conf(TIM_TypeDef * timer, int arr, int psc)
{
	
}

int Timer_encoder_get(TIM_TypeDef * timer)
{
	return 0;
}
