/*********************************************************************
 *
 *                  Tick Manager for Timekeeping
 *
 *********************************************************************
 * FileName:        Tick.c
 * Dependencies:    Timer 0 (PIC18) or Timer 1 (PIC24F, PIC24H, 
 *					dsPIC30F, dsPIC33F, PIC32)
 * Processor:       PIC18, PIC24F, PIC24H, dsPIC30F, dsPIC33F, PIC32
 * Compiler:        Microchip C32 v1.10b or higher
 *					Microchip C30 v3.12 or higher
 *					Microchip C18 v3.30 or higher
 *					HI-TECH PICC-18 PRO 9.63PL2 or higher
 * Company:         Microchip Technology, Inc.
 *
 * Software License Agreement
 *
 * Copyright (C) 2002-2010 Microchip Technology Inc.  All rights
 * reserved.
 *
 * Microchip licenses to you the right to use, modify, copy, and
 * distribute:
 * (i)  the Software when embedded on a Microchip microcontroller or
 *      digital signal controller product ("Device") which is
 *      integrated into Licensee's product; or
 * (ii) ONLY the Software driver source files ENC28J60.c, ENC28J60.h,
 *		ENCX24J600.c and ENCX24J600.h ported to a non-Microchip device
 *		used in conjunction with a Microchip ethernet controller for
 *		the sole purpose of interfacing with the ethernet controller.
 *
 * You should refer to the license agreement accompanying this
 * Software for additional information regarding your rights and
 * obligations.
 *
 * THE SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT
 * WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT
 * LIMITATION, ANY WARRANTY OF MERCHANTABILITY, FITNESS FOR A
 * PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL
 * MICROCHIP BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR
 * CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF
 * PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR SERVICES, ANY CLAIMS
 * BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE
 * THEREOF), ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION, OR OTHER
 * SIMILAR COSTS, WHETHER ASSERTED ON THE BASIS OF CONTRACT, TORT
 * (INCLUDING NEGLIGENCE), BREACH OF WARRANTY, OR OTHERWISE.
 *
 *
 * Author               Date        Comment
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 * Nilesh Rajbharti     6/28/01     Original        (Rev 1.0)
 * Nilesh Rajbharti     2/9/02      Cleanup
 * Nilesh Rajbharti     5/22/02     Rev 2.0 (See version.log for detail)
 * Howard Schlunder	6/13/07     Changed to use timer without
 *                                  writing for perfect accuracy.
 *                      6/17/13     Updated to remove compile warnings
********************************************************************/
#define __TICK_C

#include "../Include/TCPIPStack/TCPIP.h"

// Internal counter to store Ticks.  This variable is incremented in an ISR and 
// therefore must be marked volatile to prevent the compiler optimizer from 
// reordering code to use this value in the main context while interrupts are 
// disabled.
static volatile DWORD dwInternalTicks = 0;

// 6-byte value to store Ticks.  Allows for use over longer periods of time.
static volatile BYTE vTickReading[6] __attribute__ ((aligned));

static void GetTickCopy(void);

/*BYTE hours;
BYTE minutes;
BYTE seconds;*/

/*****************************************************************************
  Function:
	void TickInit(void)

  Summary:
	Initializes the Tick manager module.

  Description:
	Configures the Tick module and any necessary hardware resources.

  Precondition:
	None

  Parameters:
	None

  Returns:
  	None
  	
  Remarks:
	This function is called only one during lifetime of the application.
  ***************************************************************************/
void TickInit(void)
{
#if defined(__18CXX)
	// Use Timer0 for 8 bit processors
    // Initialize the time
    TMR0H = 0;
    TMR0L = 0;

	// Set up the timer interrupt
	INTCON2bits.TMR0IP = 0;		// Low priority
    INTCONbits.TMR0IF = 0;
    INTCONbits.TMR0IE = 1;		// Enable interrupt

    // Timer0 on, 16-bit, internal timer, 1:256 prescalar
    T0CON = 0x87;

#else
	// Use Timer 1 for 16-bit and 32-bit processors
    T1CON = 0;              // Timer reset
    dwInternalTicks = 0;
    if (TICKS_PER_SECOND == 32768ul){
        PR1 = 0xFFFF;           //0x7FFF; Timer1 period register = 32767
        T1CONbits.TCS = 1;      // Timer1 Clock= External
        T1CONbits.TCKPS = 0;
        TMR1 = 0;
    }else{
	// 1:256 prescale
	T1CONbits.TCKPS = 3;
	// Base
	PR1 = 0xFFFF;
	// Clear counter
	TMR1 = 0;
    }
	// Enable timer interrupt
	#if defined(__C30__)
		IPC0bits.T1IP = 2;	// Interrupt priority 2 (low)
		IFS0bits.T1IF = 0;
		IEC0bits.T1IE = 1;
	#else
		IPC1bits.T1IP = 2;	// Interrupt priority 2 (low)
		IFS0CLR = _IFS0_T1IF_MASK;
		IEC0SET = _IEC0_T1IE_MASK;
	#endif

	// Start timer
	T1CONbits.TON = 1;
#endif
}

/*****************************************************************************
  Function:
	static void GetTickCopy(void)

  Summary:
	Reads the tick value.

  Description:
	This function performs an interrupt-safe and synchronized read of the 
	48-bit Tick value.

  Precondition:
	None

  Parameters:
	None

  Returns:
  	None
  ***************************************************************************/
static void GetTickCopy(void)
{
	// Perform an Interrupt safe and synchronized read of the 48-bit 
	// tick value
#if defined(__18CXX)
	do
	{
		INTCONbits.TMR0IE = 1;		// Enable interrupt
		Nop();
		INTCONbits.TMR0IE = 0;		// Disable interrupt
		vTickReading[0] = TMR0L;
		vTickReading[1] = TMR0H;
		*((DWORD*)&vTickReading[2]) = dwInternalTicks;
	} while(INTCONbits.TMR0IF);
	INTCONbits.TMR0IE = 1;			// Enable interrupt
#elif defined(__C30__)
	do
	{
            DWORD dwTempTicks;
            WORD_VAL wTemp;
		
            IEC0bits.T1IE = 1;			// Enable interrupt
            Nop();
            IEC0bits.T1IE = 0;			// Disable interrupt

            // Get low 2 bytes
            wTemp.Val = TMR1;
            vTickReading[0] = wTemp.v[0];
            vTickReading[1] = wTemp.v[1];
            //((WORD*)vTickReading)[0] = TMR1;
		
            // Correct corner case where interrupt increments byte[4+] but
            // TMR1 hasn't rolled over to 0x0000 yet
            dwTempTicks = dwInternalTicks;
            //if(((WORD*)vTickReading)[0] == 0xFFFFu)
            if(wTemp.Val == 0xFFFFu)
                dwTempTicks--;
		
            // Get high 4 bytes
            vTickReading[2] = ((BYTE*)&dwTempTicks)[0];
            vTickReading[3] = ((BYTE*)&dwTempTicks)[1];
            vTickReading[4] = ((BYTE*)&dwTempTicks)[2];
            vTickReading[5] = ((BYTE*)&dwTempTicks)[3];
        } while(IFS0bits.T1IF);
	IEC0bits.T1IE = 1;				// Enable interrupt
#else	// PIC32
	do
	{
		DWORD dwTempTicks;
        WORD_VAL wTemp;
		
		IEC0SET = _IEC0_T1IE_MASK;	// Enable interrupt
		Nop();
		IEC0CLR = _IEC0_T1IE_MASK;	// Disable interrupt
		
		// Get low 2 bytes
        wTemp.Val = TMR1;
        vTickReading[0] = wTemp.v[0];
        vTickReading[1] = wTemp.v[1];
		//((volatile WORD*)vTickReading)[0] = TMR1;
		
		// Correct corner case where interrupt increments byte[4+] but 
		// TMR1 hasn't rolled over to 0x0000 yet
		dwTempTicks = dwInternalTicks;

		// PIC32MX3XX/4XX devices trigger the timer interrupt when TMR1 == PR1 
		// (TMR1 prescalar is 0x00), requiring us to undo the ISR's increment 
		// of the upper 32 bits of our 48 bit timer in the special case when 
		// TMR1 == PR1 == 0xFFFF.  For other PIC32 families, the ISR is 
		// triggered when TMR1 increments from PR1 to 0x0000, making no special 
		// corner case.
		#if __PIC32_FEATURE_SET__ <= 460
			//if(((WORD*)vTickReading)[0] == 0xFFFFu)
            if(wTemp.Val == 0xFFFFu)
				dwTempTicks--;
		#elif !defined(__PIC32_FEATURE_SET__)
			#error __PIC32_FEATURE_SET__ macro must be defined.  You need to download a newer C32 compiler version.
		#endif
		
		// Get high 4 bytes
		vTickReading[2] = ((BYTE*)&dwTempTicks)[0];
		vTickReading[3] = ((BYTE*)&dwTempTicks)[1];
		vTickReading[4] = ((BYTE*)&dwTempTicks)[2];
		vTickReading[5] = ((BYTE*)&dwTempTicks)[3];
	} while(IFS0bits.T1IF);
	IEC0SET = _IEC0_T1IE_MASK;		// Enable interrupt
#endif
}


/*****************************************************************************
  Function:
	DWORD TickGet(void)

  Summary:
	Obtains the current Tick value.

  Description:
	This function retrieves the current Tick value, allowing timing and
	measurement code to be written in a non-blocking fashion.  This function
	retrieves the least significant 32 bits of the internal tick counter, 
	and is useful for measuring time increments ranging from a few 
	microseconds to a few hours.  Use TickGetDiv256 or TickGetDiv64K for
	longer periods of time.

  Precondition:
	None

  Parameters:
	None

  Returns:
  	Lower 32 bits of the current Tick value.
  ***************************************************************************/
DWORD TickGet(void)
{
    DWORD dw;
    
	GetTickCopy();
	((BYTE*)&dw)[0] = vTickReading[0];	// Note: This copy must be done one 
	((BYTE*)&dw)[1] = vTickReading[1];	// byte at a time to prevent misaligned 
	((BYTE*)&dw)[2] = vTickReading[2];	// memory reads, which will reset the PIC.
	((BYTE*)&dw)[3] = vTickReading[3];
	return dw;
}

/*****************************************************************************
  Function:
	DWORD TickGetDiv256(void)

  Summary:
	Obtains the current Tick value divided by 256.

  Description:
	This function retrieves the current Tick value, allowing timing and
	measurement code to be written in a non-blocking fashion.  This function
	retrieves the middle 32 bits of the internal tick counter, 
	and is useful for measuring time increments ranging from a few 
	minutes to a few weeks.  Use TickGet for shorter periods or TickGetDiv64K
	for longer ones.

  Precondition:
	None

  Parameters:
	None

  Returns:
  	Middle 32 bits of the current Tick value.
  ***************************************************************************/
DWORD TickGetDiv256(void)
{
	DWORD dw;

	GetTickCopy();
	((BYTE*)&dw)[0] = vTickReading[1];	// Note: This copy must be done one 
	((BYTE*)&dw)[1] = vTickReading[2];	// byte at a time to prevent misaligned 
	((BYTE*)&dw)[2] = vTickReading[3];	// memory reads, which will reset the PIC.
	((BYTE*)&dw)[3] = vTickReading[4];
	
	return dw;
}

/*****************************************************************************
  Function:
	DWORD TickGetDiv64K(void)

  Summary:
	Obtains the current Tick value divided by 64K.

  Description:
	This function retrieves the current Tick value, allowing timing and
	measurement code to be written in a non-blocking fashion.  This function
	retrieves the most significant 32 bits of the internal tick counter, 
	and is useful for measuring time increments ranging from a few 
	days to a few years, or for absolute time measurements.  Use TickGet or
	TickGetDiv256 for shorter periods of time.

  Precondition:
	None

  Parameters:
	None

  Returns:
  	Upper 32 bits of the current Tick value.
  ***************************************************************************/
DWORD TickGetDiv64K(void)
{
	DWORD dw;

	GetTickCopy();
	((BYTE*)&dw)[0] = vTickReading[2];	// Note: This copy must be done one 
	((BYTE*)&dw)[1] = vTickReading[3];	// byte at a time to prevent misaligned 
	((BYTE*)&dw)[2] = vTickReading[4];	// memory reads, which will reset the PIC.
	((BYTE*)&dw)[3] = vTickReading[5];
	
	return dw;
}


/*****************************************************************************
  Function:
	DWORD TickConvertToMilliseconds(DWORD dwTickValue)

  Summary:
	Converts a Tick value or difference to milliseconds.

  Description:
	This function converts a Tick value or difference to milliseconds.  For
	example, TickConvertToMilliseconds(32768) returns 1000 when a 32.768kHz 
	clock with no prescaler drives the Tick module interrupt.

  Precondition:
	None

  Parameters:
	dwTickValue	- Value to convert to milliseconds

  Returns:
  	Input value expressed in milliseconds.

  Remarks:
	This function performs division on DWORDs, which is slow.  Avoid using
	it unless you absolutely must (such as displaying data to a user).  For
	timeout comparisons, compare the current value to a multiple or fraction 
	of TICK_SECOND, which will be calculated only once at compile time.
  ***************************************************************************/
DWORD TickConvertToMilliseconds(DWORD dwTickValue)
{
	return (dwTickValue+(TICKS_PER_SECOND/2000ul))/((DWORD)(TICKS_PER_SECOND/1000ul));
}


/*****************************************************************************
  Function:
	void TickUpdate(void)

  Description:
	Updates the tick value when an interrupt occurs.

  Precondition:
	None

  Parameters:
	None

  Returns:
  	None
  ***************************************************************************/
#if defined(__18CXX)
void TickUpdate(void)
{
    if(INTCONbits.TMR0IF)
    {
		// Increment internal high tick counter
		dwInternalTicks++;

		// Reset interrupt flag
        INTCONbits.TMR0IF = 0;
    }
}

/*****************************************************************************
  Function:
	void _ISR _T1Interrupt(void)

  Description:
	Updates the tick value when an interrupt occurs.

  Precondition:
	None

  Parameters:
	None

  Returns:
  	None
  ***************************************************************************/
#else
void __attribute__ ( (interrupt, no_auto_psv) ) _T1Interrupt( void )
#endif
{
/*    if( seconds < 59 )          // is cummulative seconds < 59?
    {
        seconds+=2;              // yes, so increment seconds
    }
    else                        // else seconds => 59
    {
        seconds = 0x00;         // reset seconds
        if( minutes < 59 )      // is cummulative minutes < 59?
        {
            minutes++;          // yes, so updates minutes
        }
        else                    // else minutes => 59
        {
            minutes = 0x00;     // reset minutes
            if( hours < 23 )    // is cummulative hours < 23
            {
                hours++;        // yes, so update hours
            }
            else
            {
                hours = 0x00;   // reset time
            }
        }
    }*/
	// Increment internal high tick counter
	dwInternalTicks++;
	// Reset interrupt flag
	IFS0bits.T1IF = 0;
}

