#include "config.h"
#include "timer.h"

/* Setup a 16-bit timer to overflow at the specified frequency
     timer = 1-9
     freq = Hz, or 0 to disable the timer.
     interrupt = 1 to enable interrupt, 0 to disable
*/
int timer_setup_16bit(int timer, uint32_t freq, int ie)
{
        uint32_t period;
        uint16_t prescale;
        
        if (timer < 1 || timer > 9)
                return -1;

        if (freq == 0) {
                switch(timer) {
                case 1: T1CONbits.TON = 0; return 0;
                case 2: T2CONbits.TON = 0; return 0;
                case 3: T3CONbits.TON = 0; return 0;
                case 4: T4CONbits.TON = 0; return 0;
                case 5: T5CONbits.TON = 0; return 0;
                case 6: T6CONbits.TON = 0; return 0;
                case 7: T7CONbits.TON = 0; return 0;
                case 8: T8CONbits.TON = 0; return 0;
                case 9: T9CONbits.TON = 0; return 0;
                }
        }

        /* Figure out timer prescaler and period values.  Max period
           is 65535 (PRx = 65534) so we can still attain 100% duty
           cycle when using a timer for PWM. */
        if ((period = FCY / (freq * 1L)) <= 65535)
                prescale = 0;
        else if ((period = FCY / (freq * 8L)) <= 65535)
                prescale = 1;
        else if ((period = FCY / (freq * 64L)) <= 65535)
                prescale = 2;
        else if ((period = FCY / (freq * 256L)) <= 65535)
                prescale = 3;
        else
                prescale = 3, period = 65535;
        if (period > 0)
                period -= 1;

        switch (timer) {
#define __timer_setup_case(x) \
case x: \
        T##x##CONbits.TON = 0; \
        T##x##CONbits.TCKPS = prescale; \
        PR##x = period; \
        T##x##CONbits.TON = 1; \
        break
                __timer_setup_case(1);
                __timer_setup_case(2);
                __timer_setup_case(3);
                __timer_setup_case(4);
                __timer_setup_case(5);
                __timer_setup_case(6);
                __timer_setup_case(7);
                __timer_setup_case(8);
                __timer_setup_case(9);
#undef __timer_setup_case
        }
        
        /* Enable interrupt if requested */
        timer_clear_txif(timer);
        switch (timer) {
        case 1: IEC0bits.T1IE = ie; break;
        case 2: IEC0bits.T2IE = ie; break;
        case 3: IEC0bits.T3IE = ie; break;
        case 4: IEC1bits.T4IE = ie; break;
        case 5: IEC1bits.T5IE = ie; break;
        case 6: IEC2bits.T6IE = ie; break;
        case 7: IEC3bits.T7IE = ie; break;
        case 8: IEC3bits.T8IE = ie; break;
        case 9: IEC3bits.T9IE = ie; break;
        }

        return 0;
}
