/****************************************************************************
	Knihovna je soucasti operacniho systemu vytvoreneho pro Diplomovou praci.

	Jeji hlavnim ukolem je zajistit spravu casovacu a jejich jednoduche 

	nastavovani a bezproblemovy chod.

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

#include "stdafx.h"
#include "OS.h"
#include "stdlib.h"

TIMER *TimerTable[MAX_TIMERS];
#ifdef PCSIM
	// V OS Windows neni mozne nastavit casovac na kratsi interval nez 10ms. Aby byl zajisten spravny beh 
	// na obou platformach, je nezbytne prizpusobit tomu toto makro. 
	#define TimerTick(index) TimerTable[index]->remaining-=(TimerTable[index]->state==INACTIVE?0:10);
#else
	#define TimerTick(index) TimerTable[index]->remaining-=(TimerTable[index]->state==INACTIVE?0:1);
#endif
unsigned char TimerCount = 0;


static unsigned long timeStamp = 0;

/****************************************************************************
	Inicializace tabulky casovacu

	Vstup: 
		neni

	Výstup:
		neni

*****************************************************************************/
void initTimers(void)
{
	int i = 0;
	for (i = 0; i < MAX_TIMERS; i++)
		TimerTable[i] = 0;
	TimerCount = 0;
}

/****************************************************************************
	Vytvori instanci casovace a ulozi jej do tabulky

	Vstup: 
		ptr:		ukazatel na ulohu casovace
		Name:		ID casovace
		period:		perioda v ms
		typ:		typ casovace
		stat:		stav casovace

	Výstup:
		RESULT:		Uspesnost operace

*****************************************************************************/
RESULT TimerCreate(void(*ptr)(void),TIMER_NAME Name, int period,TIMER_TYPE typ, TIMER_STATE stat)
{
	TIMER* tmp_timer = 0;
	if (TimerCount  >= MAX_TIMERS)
		return FAILED;
	//alokace struktury casovace
	tmp_timer = (TIMER*)calloc(1,sizeof(TIMER));

	if (tmp_timer == 0)
		return FAILED;
	//inicializace instance casovace
	tmp_timer->interval = period;
	tmp_timer->timer = ptr;
	tmp_timer->remaining = period;
	tmp_timer->state = stat;
	tmp_timer->type = typ;
	tmp_timer->name = Name;
	TimerTable[TimerCount++] = tmp_timer;
	return PASSED;
}


/****************************************************************************
	Nastavi typ casovace

	Vstup: 
		Name:		ID ulohy
		state:		stav ulohy

	Výstup:
		RESULT:		Uspesnost operace

*****************************************************************************/
RESULT TimerChangeState(TIMER_NAME Name, TIMER_STATE state)
{
	int timerNum = 0;
	char found = 0;
	//vyhledani casovace dle ID
	for (timerNum = 0; timerNum < TimerCount; timerNum++)
	{
		if (TimerTable[timerNum]->name == Name)
		{
			found = 1;
			break;
		}
	}
	if (found == 0)
		return FAILED;
	//Nastaveni stavu casovace
	TimerTable[timerNum]->state = state;
	return PASSED;
}

/****************************************************************************
	Vymaze casovace z tabulky casovacu

	Vstup: 
		Name:		ID ulohy

	Výstup:
		RESULT:		Uspesnost operace

*****************************************************************************/
RESULT TimerDelete(TIMER_NAME Name)
{
	int timerNum = 0;
	char found = 0;
	for (timerNum = 0; timerNum < TimerCount; timerNum++)
	{
		if (TimerTable[timerNum]->name == Name)
		{
			found = 1;
			break;
		}
	}
	if (found == 0)
		return FAILED;
	
	//Uvolneni mista po strukture
	free(TimerTable[timerNum]);

	//Prerovnani casovacu v tabulce
	for (timerNum; timerNum < TimerCount-1; timerNum++)
	{
		TimerTable[timerNum] = TimerTable[1+timerNum];
	}
	TimerTable[timerNum] = 0;
	TimerCount--;
	
	return PASSED;
}

/****************************************************************************
	Spusteni ulohy s casovacem

	Vstup: 
		index		index casovace v tabulce

	Výstup:
		neni

*****************************************************************************/
void TimerRun(unsigned char index)
{
	TIMER* timer = TimerTable[index];
	if (timer->state == INACTIVE)
		return;
	//Pokud nastala vhodna chvile, provest akci casovace
	if (timer->remaining <= 0)
	{
		//spustit akci
		timer->timer();
		if (timer->type == ONCE)
		{
			//Odstranit casovac z tabulky
			TimerDelete(timer->name);
			return;
		}
		//reset casovace
		timer->remaining = timer->interval;
	}
	return;
}

/****************************************************************************
	Ridici smycka casovacu

	Vstup: 
		neni

	Výstup:
		neni

*****************************************************************************/
void Scheduler(void)
{
	int currentTimer = 0;
#ifdef PCSIM
	timeStamp += 100;
#else
	timeStamp++;
#endif
	
	for (currentTimer = 0; currentTimer < TimerCount; currentTimer++)
	{
		TimerTick(currentTimer);
	}
}


/****************************************************************************
	vraci aktualni casovou znamku

	Vstup: 
		neni

	Výstup:
		TIME_STAMP:	Casove razitko

*****************************************************************************/
TIME_STAMP GetTimeStamp(void)
{
	return timeStamp;
}

/****************************************************************************
	Vraci cas od zadaneho casoveho razitka

	Vstup: 
		Start:			casove razitko

	Výstup:
		unsigned long:	uplynuly cas

*****************************************************************************/
unsigned long GetElapsedTime(TIME_STAMP Start)
{
	return timeStamp - Start;
}