/**
 ******************************************************************************
 *
 * @file       stopwatch.c
 * @author     The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
 * @brief      Stop watch function
 * @see        The GNU Public License (GPL) Version 3
 *
 *****************************************************************************/
/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
 * for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

#include "stopwatch.h"
#include "main.h"

// *****************************************************************************

uint32_t	resolution_us = 0;

// *****************************************************************************
// initialise the stopwatch

void STOPWATCH_init(uint32_t resolution)
{
	resolution_us = resolution;

	if (resolution_us == 0)
		return;

	// enable timer clock
	switch ((uint32_t)STOPWATCH_TIMER)
	{
		case (uint32_t)TIM1: RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE); break;
		case (uint32_t)TIM2: RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); break;
		case (uint32_t)TIM3: RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); break;
		case (uint32_t)TIM4: RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); break;
		#ifdef STM32F10X_HD
			case (uint32_t)TIM5: RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE); break;
			case (uint32_t)TIM6: RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE); break;
			case (uint32_t)TIM7: RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7, ENABLE); break;
			case (uint32_t)TIM8: RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM8, ENABLE); break;
		#endif
	}

	// time base configuration
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
	TIM_TimeBaseStructure.TIM_Period = 0xffff;													// max period
	TIM_TimeBaseStructure.TIM_Prescaler = ((PIOS_MASTER_CLOCK / 1000000) * resolution_us) - 1;	// <resolution> uS accuracy @ 72 MHz
	TIM_TimeBaseStructure.TIM_ClockDivision = 0;
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInit(STOPWATCH_TIMER, &TIM_TimeBaseStructure);

	// enable interrupt request
	TIM_ITConfig(STOPWATCH_TIMER, TIM_IT_Update, ENABLE);

	// start counter
	TIM_Cmd(STOPWATCH_TIMER, ENABLE);
}

// *****************************************************************************
// timer interrupt
/*
#ifdef STM32F10X_MD
	#if (STOPWATCH_TIMER == TIM1)
		void TIM1_IRQHandler(void)
	#if (STOPWATCH_TIMER == TIM2)
		void TIM2_IRQHandler(void)
	#elif (STOPWATCH_TIMER == TIM3)
		void TIM3_IRQHandler(void)
	#elif (STOPWATCH_TIMER == TIM4)
		void TIM4_IRQHandler(void)
	#endif
#endif
#ifdef STM32F10X_HD
	#if (STOPWATCH_TIMER == TIM1)
		void TIM1_IRQHandler(void)
	#if (STOPWATCH_TIMER == TIM2)
		void TIM2_IRQHandler(void)
	#elif (STOPWATCH_TIMER == TIM3)
		void TIM3_IRQHandler(void)
	#elif (STOPWATCH_TIMER == TIM4)
		void TIM4_IRQHandler(void)
	#elif (STOPWATCH_TIMER == TIM5)
		void TIM5_IRQHandler(void)
	#elif (STOPWATCH_TIMER == TIM6)
		void TIM6_IRQHandler(void)
	#elif (STOPWATCH_TIMER == TIM7)
		void TIM7_IRQHandler(void)
	#elif (STOPWATCH_TIMER == TIM8)
		void TIM8_IRQHandler(void)
	#endif
#endif
{

}
*/
// *****************************************************************************
// resets the stopwatch

void STOPWATCH_reset(void)
{
	if (resolution_us > 0)
	{	// reset the counter
		STOPWATCH_TIMER->CNT = 1;				// set to 1 instead of 0 to avoid new IRQ request
		TIM_ClearITPendingBit(STOPWATCH_TIMER, TIM_IT_Update);
	}
}

// *****************************************************************************
// returns the timer count since the last STOPWATCH_reset() call
// return 0xffffffff if counter overrun or not initialised

uint32_t STOPWATCH_get_count(void)
{
	uint32_t value = STOPWATCH_TIMER->CNT;				// get counter value ASAP

	if (resolution_us == 0)
		return 0xffffffff;								// not initialized

	if (TIM_GetITStatus(STOPWATCH_TIMER, TIM_IT_Update) != RESET)
		return 0xffffffff;								// timer overfloaw

	return value;										// return the timer count
}

// *****************************************************************************
// returns number of us since the last STOPWATCH_reset() call
// return 0xffffffff if counter overrun or not initialised

uint32_t STOPWATCH_get_us(void)
{
	uint32_t value = STOPWATCH_TIMER->CNT;				// get counter value ASAP

	if (resolution_us == 0)
		return 0xffffffff;								// not initialized

	if (TIM_GetITStatus(STOPWATCH_TIMER, TIM_IT_Update) != RESET)
		return 0xffffffff;								// timer overfloaw

	return (value * resolution_us);						// return number of micro seconds
}

// *****************************************************************************
