/**  Header Files **************************************************/
#include <p18f4520.h>
#include <stdio.h>
#include <delays.h>
#include <timers.h>
#include <portb.h>
#include "LCD Module.h"

/** Configuration Bits *********************************************/
#pragma config OSC = INTIO67
#pragma config WDT = OFF
#pragma config LVP = OFF
#pragma config BOREN = OFF
#pragma config XINST = OFF

/** Define Constants Here ******************************************/
#define PRESSED 0
#define DEBOUNCE_TIME 30
#define START_TIMER_VALUE 34286

/** Local Function Prototypes **************************************/
void updateDisplays(void);
void low_isr(void);
void high_isr(void);

/** Declare Interrupt Vector Sections ****************************/
#pragma code high_vector=0x08

void interrupt_at_high_vector(void) {
    _asm goto high_isr _endasm
}

#pragma code low_vector=0x18

void interrupt_at_low_vector(void) {
    _asm goto low_isr _endasm
}

/** Global Variables ***********************************************/
int timeRemaining = 6;
char line2[17];

/*******************************************************************
 * Function:        void main(void)
 ********************************************************************/
#pragma code

void main(void) {
    // Set the clock to 4 MHz
    OSCCONbits.IRCF2 = 1;
    OSCCONbits.IRCF1 = 1;
    OSCCONbits.IRCF0 = 0;

    // Pin IO Setup
    ADCON1 = 0x0F;
    TRISA = 0xFF; // All of PORTA input
    TRISB = 0xFF; // All of PORTB input
    TRISC = 0x00; // All of PORTC output
    TRISD = 0x00; // All of PORTD output
    PORTC = 0x00; // Turn off all 8 Port C LEDs

    XLCDInit();
    XLCDClear();

    XLCDL1home();
    XLCDPutRomString("FEED THE FISH IN");
    sprintf(line2, "%d SECONDS", timeRemaining);
    XLCDL2home();
    XLCDPutRamString(line2);

    // Interrupt setup
    RCONbits.IPEN = 1; // Put the interrupts into Priority Mode

    // Add specific interrupts here...
    OpenTimer0(TIMER_INT_ON & T0_16BIT & T0_SOURCE_INT & T0_PS_1_32);
    INTCON2bits.TMR0IP = 0;
    OpenRB2INT(PORTB_CHANGE_INT_ON & FALLING_EDGE_INT & PORTB_PULLUPS_OFF);
    INTCON3bits.INT2IP = 0;

    INTCONbits.GIEH = 1; // Turn on high priority interrupts
    INTCONbits.GIEL = 1;

    WriteTimer0(START_TIMER_VALUE);
    while (1) {
        updateDisplays(); // Many options for when you update the LCD.
    }
}

/*****************************************************************
 * Function:        void high_isr(void)
 ******************************************************************/
#pragma interrupt high_isr

void high_isr(void) {
    // Add code here for the high priority Interrupt Service Routine (ISR)
}

/******************************************************************
 * Function:        void low_isr(void)
 ********************************************************************/
#pragma interruptlow low_isr

void low_isr(void) {
    // Add code here for the low priority Interrupt Service Routine (ISR)
    if (INTCON3bits.INT2IF) { // Interrupt 2, RB2 with debounce
        INTCON3bits.INT2IF = 0;
        Delay1KTCYx(DEBOUNCE_TIME); // Assumes a 4 MHz clock
        if (PORTBbits.RB2 == PRESSED) {
            timeRemaining = 6;
            WriteTimer0(START_TIMER_VALUE);
        }
    }

    if (INTCONbits.TMR0IF) { // Timer 0 interrupt
        INTCONbits.TMR0IF = 0;
        WriteTimer0(START_TIMER_VALUE);
        timeRemaining--;
		if (timeRemaining < 0) {
			timeRemaining = 0; // Just to protect from looping after 32k seconds
		}
    }
}

#pragma code

void updateDisplays() {
    if (timeRemaining > 0) {
        XLCDL1home();
        XLCDPutRomString("FEED THE FISH IN");
        sprintf(line2, "%d SECONDS", timeRemaining);
        XLCDL2home();
        XLCDPutRamString(line2);
        PORTC = 0x00;
    } else {
        XLCDClear();
        PORTC = 0xFF;
    }
}