/****************************************************************************/
/* Copyright 2009 - 2015 MBARI                                              */
/****************************************************************************/
/* Summary  : System timer/ticker module for OASIS5 on PIC32MX470F512L      */
/* Filename : sys_timer.c                                                   */
/* Author   : Mike Risi (mrisi), Robert Herlien (rah)                       */
/* Project  : OASIS Mooring Replacement (OASIS5)                            */
/* Revision: 1.0                                                            */
/* Created  : 2009 by Mike Risi, Adapted for Oasis5 10/29/2015 by Bob Herlien*/
/*                                                                          */
/* MBARI provides this documentation and code "as is", with no warranty,    */
/* express or implied, of its quality or consistency. It is provided without*/
/* support and without obligation on the part of the Monterey Bay Aquarium  */
/* Research Institute to assist in its use, correction, modification, or    */
/* enhancement. This information should not be published or distributed to  */
/* third parties without specific written permission from MBARI.            */
/*                                                                          */
/****************************************************************************/
/* Modification History:                                                    */
/* 29oct2015 rah - adapted from Respirometer chamber controller             */
/****************************************************************************/

#include "GenericTypeDefs.h"
#include <xc.h>
#include "sys_timer.h"
#include "dig_io.h"

extern void disk_timerproc(void);       /* SD card driver               */


/************************************************************************/
/* Note that if you change PBCLK, you'll need to manually change some   */
/* of the constants here!!!                                             */
/************************************************************************/

static volatile UINT32 tickCount = 0;

/* intialize the timer */
void tmrInit()
{
    T2CON = 0x0030;                     /* Prescale divide by 8 */
    PR2 = (PBCLK/(8*TICKS_PER_SEC))-1;  /* set timer period    */
    TMR2 = 0x0000;                      /* clear timer count */
    
    /* set timer interrupt priority to 5 */
    IPC2bits.T2IP = 5;
    IPC2bits.T2IS = 0;

    /* setup timer interrupts */
    IFS0bits.T2IF = 0;
    IEC0bits.T2IE = 1;

    T2CONbits.TON = 1;                  /* start timer          */
    
    return;
}

/* 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 */

}

#define T3PRD(ms)       ((UINT16)((PBCLK*ms)/256000L))
/* delay for a specified number of milliseconds */
void tmrDelayMs(unsigned int ms)
{
    if (ms >= 690)                      /* 16 bit cntr saturates at 698 ms*/
        tmrDelayTicks((ms+(MS_PER_TICK-1))/MS_PER_TICK);
    else if (ms > 0)
    {
        T3CON = 0x0070;                 /* Set timer3 control to divide by 256*/
        TMR3 = 0x0000;                  /* clear timer count            */
        PR3 = T3PRD(ms) - 1;            /* set timer period             */
        IEC0bits.T3IE = 0;              /* Don't actually interrupt     */
        IFS0bits.T3IF = 0;              /* clear interrupt flag         */
        T3CONbits.TON = 1;              /* start timer                  */

        while (IFS0bits.T3IF == 0)      /* Wait for the timer to expire */
            Nop();
    }
}

/* delay for a specified number of microseconds         */
/* Note that this only works well for delays >= 5us     */
/* For shorter delays, use Nop()'s                      */
/* For us <= 4, gives fixed delay of approx 2 us        */
/* For us > 4, gives (approximately) proper delay in us */
/* If us > 21845, this will overflow, so use tmrDelayMs */
void tmrDelayUs(unsigned int us)
{
    if (us >= 21000)                    /* 16 bit cntr saturates at 21845 us */
        tmrDelayMs((us+900)/1000);
    else if (us > 4)
    {
        T3CON = 0x30;                   /* Set timer3 control to divide by 8*/
        TMR3 = 0;                       /* clear timer count                */
        PR3 = (UINT16)((PBCLK*(us-4))/8000000L);
                                        /* Subtract 3us for function o'head */
        IEC0bits.T3IE = 0;              /* Don't actually interrupt         */
        IFS0bits.T3IF = 0;              /* setup timer interrupts           */
        T3CONbits.TON = 1;              /* start timer                      */

        while (IFS0bits.T3IF == 0)      /* Wait for the timer to expire     */
            Nop();
    }
}

/* get internal tick counts */
unsigned long tmrGetTicks()
{
    return tickCount;
}

/* Timer2 ISR */
void __attribute__( (interrupt(IPL5SOFT), vector(_TIMER_2_VECTOR)) ) _T2Interrupt(void)
{
    tickPinOn();
    tickCount++;                        /* increment the counter                */
    disk_timerproc();                   /* Call the SD card timer routine       */
    IFS0bits.T2IF = 0;                  /* clear the interrupt flag             */
    tickPinOff();
}
