/****************************************************************************/
/* Copyright 2009 MBARI.                                                    */
/* MBARI Proprietary Information. All rights reserved.                      */
/****************************************************************************/
#include "p24Fxxxx.h"
#include "sys_timer.h"
#include "sys_defs.h"

/* Timer setup  */
#define FOSC    3686400
#define FCY     (FOSC/2)
#define FS      100 /* frequency of timer */

#define TMR2PRD (FCY/FS)-1

/* milliseconds per tick */
#define MS_PER_TICK (1000 / FS)

static volatile unsigned int timerTick = 0;
static unsigned long tickCount = 0;

static void updateTickCount();

/* intialize the timer */
void tmrInit()
{
    /* clear out the timer2 control reg */
    T2CON = 0x0000;
    /* clear timer count */
    TMR2 = 0x0000;           
    /* set timer period */
    PR2 = TMR2PRD;
    
	/* setup timer interrupts */
	IFS0bits.T2IF = 0; // clear timer2 interrupt flag
    IEC0bits.T2IE = 1; // enable timer2 interrupt

    /* start timer */
    T2CONbits.TON = 1;
    
    return;
}

/* perform any timer tasks in main loop */
void tmrTask()
{
    /* update 32 bit tick count */
    updateTickCount();

    /* update doze vector for one shot outputs */
}

/* see if the timer is running */
int tmrIsRunning(Timer* timer)
{
    return timer->active;
}

/* Create the timer */
void tmrCreate(Timer* timer)
{
    tmrStop(timer);
    tmrClear(timer);
}

/* Clear the timer */
void tmrClear(Timer* timer)
{
    timer->totalTicks = 0;
    timer->startTicks = tmrGetTicks();
}

/* Read the total amount of elapsed time the timer has running */
unsigned long tmrRead(Timer* timer)
{
    unsigned long ticks = tmrGetTicks();

    if ( timer->active )
    {
        /* check for rollover */
        if ( timer->startTicks > ticks )
            timer->totalTicks += (ticks + timer->startTicks);
        else
            timer->totalTicks += (ticks - timer->startTicks);
    }

    timer->startTicks = ticks;

    return (timer->totalTicks * MS_PER_TICK);
}

/* Start the timer */
unsigned long tmrStart(Timer* timer)
{
    tmrRead(timer);
    timer->active = TRUE;
    
    return (timer->totalTicks * MS_PER_TICK);
}

/* Stop the timer */
unsigned long tmrStop(Timer* timer)
{
    tmrRead(timer);
    timer->active = FALSE;
    
    return (timer->totalTicks * MS_PER_TICK);
}

/* delay for a specified number of timer ticks */
void tmrDelayTicks(unsigned int ticks)
{
    unsigned long wait_ticks = tmrGetTicks() + ticks;

    while ( wait_ticks > tmrGetTicks() )
        ;/* wait for wait ticks to expire */
}

/* delay for a specified number of milliseconds */
void tmrDelayMs(unsigned int ms)
{
    unsigned long wait_ticks = tmrGetTicks();
     
    if ( (ms / MS_PER_TICK) > 0 )
        wait_ticks += (unsigned long)(ms / MS_PER_TICK);
    else
        wait_ticks += 1;

    while ( wait_ticks > tmrGetTicks() )
        ;/* wait for wait ticks to expire */
}

/* get internal tick counts */
unsigned long tmrGetTicks()
{
    /* update 32 bit tick count */
    updateTickCount();
    
    return tickCount;
}

void updateTickCount()
{
    unsigned int tickDelta;

    /* calculate tick delta */
    tickDelta = timerTick - (tickCount & 0x0000FFFF);
    /* add delta to tick count */
    tickCount += tickDelta;
}

/* Timer2 ISR */
void __attribute__ ((interrupt,no_auto_psv))_T2Interrupt(void)
{
    /* clear timer count */
    TMR2 = 0;

    /* increment the counter */
    ++timerTick;

    /* clear the interrupt flag */
    IFS0bits.T2IF = 0;
}

