#include "timer.h"


#define BASE ((TIM_TypeDef *)timerBase_Addr_List[timer])

void timerReset(timerNo_t timer)
{
	if(timerBus_No[timer]==1)
	{
		RCC->APB1RSTR |= (1<<timerBus_Rst_bitPos[timer]); 	
		RCC->APB1RSTR &=~ (1<<timerBus_Rst_bitPos[timer]); 	
		return; 
	}
	RCC->APB2RSTR |= (1<<timerBus_Rst_bitPos[timer]); 	
	RCC->APB2RSTR &=~ (1<<timerBus_Rst_bitPos[timer]); 	
}

void timerActivateBus(timerNo_t timer)
{
	if(timerBus_No[timer]==1)
	{
		RCC->APB1ENR |= (1<<timerBus_En_bitPos[timer]); 	
		return; 
	}
	RCC->APB2ENR |= (1<<timerBus_En_bitPos[timer]); 	
}
 
void timerEnable(timerNo_t timer)
{
	BASE->CR1 |= TIM_CR1_CEN; //all the timers have the same CEN bit in CR1 register pos 0	
}

void timerDisable(timerNo_t timer)
{
	BASE->CR1 &=~ TIM_CR1_CEN; //all the timers have the same CEN bit in CR1 register pos 0	
}
 
void timerSetMode(timerNo_t timer, timerMode_t mode)
{
	// Propably not needed	
}
 
void timerSetCountDirection(timerNo_t timer, timerCountDirection_t direction)
{
	if(direction == upCounting)
	{

		BASE->CR1 &=~ TIM_CR1_DIR;	
		return; 
	}	 

	BASE->CR1 |= TIM_CR1_DIR;	
}
 
void timerSetPrescaler(timerNo_t timer, uint32_t prescaler)
{
	if(prescaler > timerRes_Prescaler[timer])
	{
		timerThrowError(prescalerOutOfRange);
		return; // To prevent writing wrong value in to the Register
	}
	BASE->PSC = prescaler;
}
 
void timerSetPostscaler(timerNo_t timer, uint32_t postscaler)
{
	timerThrowError(functionNotSupported);
}
 
void timerSetAutoReload(timerNo_t timer, uint32_t reload)
{
	// TODO: implement error wen reload value exceeds the hardware register size (e.g. value > 16bit)
	BASE->ARR = reload; 	
}
 
void timerClearCounter(timerNo_t timer)
{
	BASE->CNT = 0; 	
}
 
uint8_t timerGetUpdateInterrupt(timerNo_t timer)
{
	return (BASE->SR & 1);
}	

void timerClearUpdateInterrupt(timerNo_t timer)
{
	BASE->SR &= ~1;
}	

/* Second stage configuration */
void timerInitCounter (	timerNo_t timer, 
						uint32_t prescaler,
						uint32_t autoReload, 
						timerCountDirection_t direction)
{
	timerActivateBus(timer);
	timerSetMode(timer, counter);
	timerSetCountDirection(timer,direction);
	timerSetPrescaler(timer, prescaler);
	timerSetAutoReload(timer, autoReload);
}

void timerInitOutputCompare( timerNo_t timer, 
						timerOutputCompareMode_t mode,
						uint8_t timerIoChannel, 
						pinNo_t pinNo, 
						uint16_t altFunction,
						uint8_t polarity,
						uint32_t ccValue)
{
	timerStop(timer); 
	pinSetMode(pinNo,alternate); 
	pinSetAlternate(pinNo,altFunction); 
	
	// TODO: check for value existing register size
	//if(ccValue)
	//  timerThrowError(timerError_t error)
	switch(timerIoChannel)
	{
		case 1: 
			BASE->CCMR1 &= ~TIM_CCMR1_OC1M; 
			BASE->CCMR1 |= mode << TIM_CCMR1_OC1M_Pos; 
			BASE->CCER	|= TIM_CCER_CC1E;
			BASE->CCER	|= (1&&polarity) << TIM_CCER_CC1P_Pos;
			BASE->CCER	&= ~TIM_CCER_CC1NP;
			BASE->CCR1 = (uint16_t)ccValue; 
			break;
		case 2: 
			BASE->CCMR1 &= ~TIM_CCMR1_OC2M; 
			BASE->CCMR1 |= mode << TIM_CCMR1_OC2M_Pos; 
			BASE->CCER	|= TIM_CCER_CC2E;
			BASE->CCER	|= (1&&polarity) << TIM_CCER_CC2P_Pos;
			BASE->CCER	&= ~TIM_CCER_CC2NP;
			BASE->CCR2 = (uint16_t)ccValue;
			break;
		case 3: 
			BASE->CCMR2 &= ~TIM_CCMR2_OC3M; 
			BASE->CCMR2 |= mode << TIM_CCMR2_OC3M_Pos; 
			BASE->CCER	|= TIM_CCER_CC3E;
			BASE->CCER	|= (1&&polarity) << TIM_CCER_CC3P_Pos;
			BASE->CCER	&= ~TIM_CCER_CC3NP;
			BASE->CCR3 = (uint16_t)ccValue; 
			break;
		case 4: 
			BASE->CCMR2 &= ~TIM_CCMR2_OC4M; 
			BASE->CCMR2 |= mode << TIM_CCMR2_OC4M_Pos; 
			BASE->CCER	|= TIM_CCER_CC4E;
			BASE->CCER	|= (1&&polarity) << TIM_CCER_CC4P_Pos;
			BASE->CCER	&= ~TIM_CCER_CC4NP;
			BASE->CCR4 = (uint16_t)ccValue; 
			break;
		default: 
			timerThrowError(ccChannelNoOutOfRange);
			break;
	};	
}

void timerSetCounterCompareValue(timerNo_t timer,
								 uint8_t timerIoChannel,
								 uint32_t ccValue)
{
	switch(timerIoChannel) {
		case 1: 
			BASE->CCR1 = (uint16_t)ccValue; 
			break;
		case 2: 
			BASE->CCR2 = (uint16_t)ccValue;
			break;
		case 3: 
			BASE->CCR3 = (uint16_t)ccValue; 
			break;
		case 4: 
			BASE->CCR4 = (uint16_t)ccValue; 
			break;
		default: 
			timerThrowError(ccChannelNoOutOfRange);
			break;
	};	
}	
  

/*			Bus Clock
 * ------------------------------ = Duty (Hz)
 *  (Prescaler-1) * (Period-1)
 */
void timerSetHz(timerNo_t timer, uint16_t hz)
{
	uint32_t prescaler = 8000000;
	uint32_t period = 0;
	uint32_t temp = 0; 	
	
	do{
		prescaler = prescaler / 10; 
	}while(prescaler > 0xffff);
	
	
	do{
		period = period + 1; 
		temp = 8000000/(prescaler*(period)); 
	}while(temp >= hz);

	timerSetPrescaler(timer, prescaler-1);
	timerSetAutoReload(timer, period-1);
	timerClearCounter(timer);
}
 
void timerSetMs(timerNo_t timer, uint16_t ms)
{
	
}
 
void timerSetNs(timerNo_t timer, uint16_t ns)
{
	
}
 
void timerSetPs(timerNo_t timer, uint16_t ps)
{
	
}
 
void timerSart(timerNo_t timer)
{
	timerEnable(timer);
}

void timerHalt(timerNo_t timer)
{
	timerDisable(timer);
}

void timerStop(timerNo_t timer)
{
	timerDisable(timer);
	timerClearCounter(timer);
}


uint32_t timerGetCount(timerNo_t timer)
{
	return BASE->CNT;	
}


void timerThrowError(timerError_t error)
{
	while(1);	
}