/******************************************************************************
 *
 * Freescale Semiconductor Inc.
 * (c) Copyright 2004-2013 Freescale Semiconductor, Inc.
 * ALL RIGHTS RESERVED.
 *
 ******************************************************************************
 *
 * THIS SOFTWARE IS PROVIDED BY FREESCALE "AS IS" AND ANY EXPRESSED OR 
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  
 * IN NO EVENT SHALL FREESCALE OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 
 * THE POSSIBILITY OF SUCH DAMAGE.
 *
 **************************************************************************//*!
 *
 * @file SwTimer.c
 *
 * @author Samuel Quiroz  
 *
 * @version 1.0
 *
 * @date SEP-11-2009
 *
 * @brief This file handles an array of software timers and trigger the timer event when
 * 		  the timer has elapsed.
 *****************************************************************************/

/********************************************************************************************
 * Header files
 *******************************************************************************************/
#include "SwTimer.h"
#include "fsl_types.h"

/********************************************************************************************
 * Definitions
 *******************************************************************************************/
#define INACTIVE_TIMER          0xFFFF		/**< Thism number is used to tell that the timer is inactive */
#define INVALID_TIMER_ID		0xFF		/**< This Id is returned when the timer was not created */

/********************************************************************************************
 * Locals
 *******************************************************************************************/
SwCounter_t  SwCounterObjArray[MAX_COUNTER_OBJECTS];	/**< Stores the counter objects */
SwTimerObj_t SwTimerObjArray[MAX_TIMER_OBJECTS];		/**< Stores the timer objects */
uint8_t AssignedTimersIndex = 0;		/**< Will count the timers that are created on the application */
uint8_t AssignedCountersIndex = 0;	/**< Will count the counters that are created on the application */

/********************************************************************************************
 * Functions
 *******************************************************************************************/
void SwTimer_Init(void)
{
	uint8_t i;
	for (i=0; i<MAX_TIMER_OBJECTS; i++)
	{
		SwTimerObjArray[i].timerCount = INACTIVE_TIMER;	/* Set all timers inactive */
	}	
	
	for (i=0; i<MAX_COUNTER_OBJECTS; i++)
	{
		SwCounterObjArray[i].timerCount = INACTIVE_TIMER;	/* Set all timers inactive */
	}
	
	AssignedTimersIndex = 0;
	AssignedCountersIndex = 0;
	
	HW_TIMER_INIT;
}


void SwTimer_PeriodicTask(void)
{
	uint8_t i;

	//Check for HW Timer interrupt
	if(HW_TIMER_IRQ)
	{
		//HW timer interrupt occured, clear IRQ and decrement values;
		HW_TIMER_IRQ_CLEAR;

		for (i=0; i<AssignedTimersIndex; i++)
		{
			if (SwTimerObjArray[i].timerCount != INACTIVE_TIMER)	/* only decrement active timers */
			{				
				if(SwTimerObjArray[i].timerCount >= HW_TIMER_DECREMENT_VALUE_MS)
				{
					SwTimerObjArray[i].timerCount -= HW_TIMER_DECREMENT_VALUE_MS;
				}
				else
				{
					SwTimerObjArray[i].timerCount = 0;
				}				
				
				if(SwTimerObjArray[i].timerCount == 0)	/* if timer has elapsed */
				{
					SwTimerObjArray[i].timerCount = INACTIVE_TIMER;	/* disable timer */
					
					if (SwTimerObjArray[i].timerEvent != NULL)
					{
						SwTimerObjArray[i].timerEvent();		/* execute timer callback function */	
					}					
				}
			}
		}
		
		
		for (i=0; i<AssignedCountersIndex; i++)
		{
			if (SwCounterObjArray[i].timerCount != INACTIVE_TIMER)
			{
				SwCounterObjArray[i].timerCount += HW_TIMER_DECREMENT_VALUE_MS;
			}
		}
	}
}




uint8_t SwTimer_CreateTimer(pFunc_t callBackFunc)
{
	uint8_t timerId;
	
	if (AssignedTimersIndex < MAX_TIMER_OBJECTS)
	{
		SwTimerObjArray[AssignedTimersIndex].timerEvent = callBackFunc;	
		timerId = AssignedTimersIndex++;
	}
	else
	{
		timerId = INVALID_TIMER_ID;
	}
	
	return timerId;
}


void SwTimer_StartTimer(uint8_t timerId, uint16_t tickPeriod_ms)
{
	SwTimerObjArray[timerId].timerCount = tickPeriod_ms;
}


void SwTimer_StopTimer(uint8_t timerId)
{
	SwTimerObjArray[timerId].timerCount = INACTIVE_TIMER;
}



uint8_t SwTimer_CreateCounter(void)
{
	uint8_t counterId;
	
	if (AssignedCountersIndex < MAX_COUNTER_OBJECTS)
	{
		counterId = AssignedCountersIndex++;
	}
	else
	{
		counterId = INVALID_TIMER_ID;
	}
	
	return counterId;
}


void SwTimer_StartCounter(uint8_t counterId)
{
	SwCounterObjArray[counterId].timerCount = 0;
}

void SwTimer_StopCounter(uint8_t counterId)
{
	SwCounterObjArray[counterId].timerCount = INACTIVE_TIMER;
}

uint16_t SwTimer_ReadCounter(uint8_t counterId)
{
	return (SwCounterObjArray[counterId].timerCount);
}

