/*******************************************************************************
 *                                                                              *
 * Copyright 2010 Rheinmetall Canada Inc.                                  	   *
 *                                                                              *
 * No part of this document may be reproduced, stored in                        *
 * a retrieval system, or transmitted, in any form or by any means,             *
 * electronic, mechanical, photocopying, recording, or otherwise,               *
 * without the prior written permission of Rheinmetall Canada Inc.              *
 *                                                                              *
 *******************************************************************************/

#include "timer.h"
#include "define.h"
#include <string.h>
//#include <plib.h>
//#include "./FatFS/diskio.h"

//unsigned int MillisecCounter[TIMER_MAX_ID];
//unsigned int SecondCounter;
//int CalcPeriod;
stTimer astTimer[TIMER_MAX_ID];

//-------------------------------------------------------
void TimerInit(void)
{
#ifdef GP_TIMER_USE_TIMER_1
    
	T1CON = 0;
	
	T1CONbits.TCKPS = 0b01;	//1:8 prescaler
	TMR1 = 0;
	PR1 = 10000;			//77.824MHz clock with 1:8 prescaler = timer period of 102.8ns. 1ms period --> 9728 * 102.8ns = 1ms
	
	IPC1bits.T1IP = 2;		//timer interrupt priority = 2;
	IPC1bits.T1IS = 3;		//timer interrupt sub-priority = 2;
	IFS0bits.T1IF = 0;
	IEC0bits.T1IE = 1;		//start timer
	
	T1CONbits.ON = 1;
    
#endif
#ifdef GP_TIMER_USE_TIMER_2
    T2CON = 0;
    
    T2CONbits.TCKPS = 0b011; //1:8 prescaler
    TMR2 = 0;
    PR2 = 10000; //77.824MHz clock with 1:8 prescaler = timer period of 102.8ns. 1ms period --> 9728 * 102.8ns = 1ms
    
    IPC2bits.T2IP = 2; //timer interrupt priority = 2;
    IPC2bits.T2IS = 3; //timer interrupt sub-priority = 2;
    IFS0bits.T2IF = 0;
    IEC0bits.T2IE = 1; //start timer
    
    T2CONbits.ON = 1;
#endif
	
	memset(&astTimer[0], 0, sizeof(astTimer));
}

//-------------------------------------------------------
/*unsigned int GetActualTimerMilliSec(void)
 {
 return MillisecCounter;
 }*/

//-------------------------------------------------------
/*unsigned int GetActualTimerSec(void)
 {
 return SecondCounter;
 }*/	


//-------------------------------------------------------
int IsMilliSecTimerExpired(eTimerID p_eTimerID)
{
	int CalcPeriod = 0;
    
	if ((astTimer+p_eTimerID)->bRunning)
	{
		CalcPeriod = (astTimer+p_eTimerID)->uiMillisecCounter - (astTimer+p_eTimerID)->uiStart;
		//if(CalcPeriod > 0 && CalcPeriod >= (astTimer+p_eTimerID)->uiPeriodMillisec)
		if(CalcPeriod >= (astTimer+p_eTimerID)->uiPeriodMillisec)
		{
			//TimerReset(p_eTimerID);
			(astTimer+p_eTimerID)->uiMillisecCounter = 0;
			return 1;
		}
		else if(CalcPeriod < 0)
		{
			if((1000 + CalcPeriod) >= (astTimer+p_eTimerID)->uiPeriodMillisec)
			{
				//TimerReset(p_eTimerID);
				(astTimer+p_eTimerID)->uiMillisecCounter = 0;
				return 1;
			}		
		}	
	}
    
	return 0;
}

//-------------------------------------------------------
int IsSecTimerExpired(eTimerID p_eTimerID)
{
	int iCalcPeriod = 0;
    
	if ((astTimer+p_eTimerID)->bRunning)
	{
		iCalcPeriod = (astTimer+p_eTimerID)->uiSecondCounter - (astTimer+p_eTimerID)->uiStart;
		//if(iCalcPeriod > 0 && iCalcPeriod >= (astTimer+p_eTimerID)->uiPeriodSecond)
		if(iCalcPeriod >= (astTimer+p_eTimerID)->uiPeriodSecond)
		{
			//TimerReset(p_eTimerID);
			(astTimer+p_eTimerID)->uiSecondCounter = 0;
			return 1;
		}
		else if(iCalcPeriod < 0)
		{
			if(((unsigned)0xFFFFFFFF + iCalcPeriod) >= (astTimer+p_eTimerID)->uiPeriodSecond)
			{
				//TimerReset(p_eTimerID);
				(astTimer+p_eTimerID)->uiSecondCounter = 0;
				return 1;		
			}
		}
	}
    
	return 0;
}

//-------------------------------------------------------
int IsTimerExpired(eTimerID p_eTimerID)
{
	int iCalcPeriod = 0;
    
	if ((astTimer+p_eTimerID)->bRunning)
	{
		/*if (IsSecTimerExpired(p_eTimerID) && IsMilliSecTimerExpired(p_eTimerID))
         return 1;*/
        
		iCalcPeriod = (astTimer+p_eTimerID)->uiSecondCounter - (astTimer+p_eTimerID)->uiStart;
        
		if(iCalcPeriod >= (astTimer+p_eTimerID)->uiPeriodSecond)
		{
			iCalcPeriod = (astTimer+p_eTimerID)->uiMillisecCounter - (astTimer+p_eTimerID)->uiStart;
			if(iCalcPeriod >= (astTimer+p_eTimerID)->uiPeriodMillisec)
			{
				(astTimer+p_eTimerID)->uiSecondCounter = 0;
				(astTimer+p_eTimerID)->uiMillisecCounter = 0;
				return 1;
			}
			else if(iCalcPeriod < 0)
			{
				if((1000 + iCalcPeriod) >= (astTimer+p_eTimerID)->uiPeriodMillisec)
				{
					(astTimer+p_eTimerID)->uiSecondCounter = 0;
					(astTimer+p_eTimerID)->uiMillisecCounter = 0;
					return 1;
				}		
			}
		}
		else if(iCalcPeriod < 0)
		{
			if(((unsigned)0xFFFFFFFF + iCalcPeriod) >= (astTimer+p_eTimerID)->uiPeriodSecond)
			{
				iCalcPeriod = (astTimer+p_eTimerID)->uiMillisecCounter - (astTimer+p_eTimerID)->uiStart;
				if(iCalcPeriod >= (astTimer+p_eTimerID)->uiPeriodMillisec)
				{
					(astTimer+p_eTimerID)->uiSecondCounter = 0;
					(astTimer+p_eTimerID)->uiMillisecCounter = 0;
					return 1;
				}
				else if(iCalcPeriod < 0)
				{
					if((1000 + iCalcPeriod) >= (astTimer+p_eTimerID)->uiPeriodMillisec)
					{
						(astTimer+p_eTimerID)->uiSecondCounter = 0;
						(astTimer+p_eTimerID)->uiMillisecCounter = 0;
						return 1;
					}		
				}		
			}
		}
	}
    
	return 0;
}

//-------------------------------------------------------
void TimerStart(eTimerID p_eTimerID, unsigned int p_uiPeriod)
{
	(astTimer+p_eTimerID)->bRunning = true;
	if (p_uiPeriod >= 1000)
	{
		(astTimer+p_eTimerID)->uiPeriodSecond = p_uiPeriod / 1000;
		(astTimer+p_eTimerID)->uiPeriodMillisec = p_uiPeriod % 1000;
	}
	else
	{
		(astTimer+p_eTimerID)->uiPeriodSecond = 0;
		(astTimer+p_eTimerID)->uiPeriodMillisec = p_uiPeriod;
	}
	TimerReset(p_eTimerID);
}
void TimerStartSeconds(eTimerID p_eTimerID, unsigned int p_uiPeriod)
{
    (astTimer+p_eTimerID)->bRunning = true;
    (astTimer+p_eTimerID)->uiPeriodSecond = p_uiPeriod;
    (astTimer+p_eTimerID)->uiPeriodMillisec = 0;
	TimerReset(p_eTimerID);
}
//-------------------------------------------------------
void TimerReset(eTimerID p_eTimerID)
{
	(astTimer+p_eTimerID)->uiStart = 0; 
	(astTimer+p_eTimerID)->uiMillisecCounter = 0;
	(astTimer+p_eTimerID)->uiSecondCounter = 0;
}

//-------------------------------------------------------
bool IsTimerRunning(eTimerID p_eTimerID)
{
    return (astTimer+p_eTimerID)->bRunning;
}


//-------------------------------------------------------
void TimerStop(eTimerID p_eTimerID)
{
	(astTimer+p_eTimerID)->bRunning = false;
}

//-------------------------------------------------------
void Sleep(unsigned int timeout)
{
    TimerStart(SLEEP_FCN_TIMER,timeout);
    
    while(!IsTimerExpired(SLEEP_FCN_TIMER))
    {
        Nop();
    }
    TimerStop(SLEEP_FCN_TIMER);
}


#ifdef GP_TIMER_USE_TIMER_1

void __ISR(_TIMER_1_VECTOR, ipl2) Timer1MilliSecInterrupt(void)
{
	unsigned int i;
	stTimer* pstPtr = &astTimer[0];
    
    //    disk_timerproc();
    
	// Update all timers
	for (i=0; i<TIMER_MAX_ID; i++)
	{
		// update timer only if timer is running
		if (pstPtr->bRunning)
		{
			if(pstPtr->uiMillisecCounter++ == 1000)
			{
				pstPtr->uiMillisecCounter = 0;
				pstPtr->uiSecondCounter++;
			}
		}
		pstPtr++;
	}
	
	IFS0bits.T1IF = 0;	//Clear interrupt flag	
}
#endif

#ifdef GP_TIMER_USE_TIMER_2

void __ISR(_TIMER_2_VECTOR, ipl2) Timer2MilliSecInterrupt(void) {
    unsigned int i;
    stTimer* pstPtr = &astTimer[0];
    
    //disk_timerproc();
    
    // Update all timers
    for (i = 0; i < TIMER_MAX_ID; i++) {
        // update timer only if timer is running
        if (pstPtr->bRunning) {
            if (pstPtr->uiMillisecCounter++ == 1000) {
                pstPtr->uiMillisecCounter = 0;
                pstPtr->uiSecondCounter++;
            }
        }
        pstPtr++;
    }
    
    IFS0bits.T2IF = 0; //Clear interrupt flag	
}
#endif

//EOF


