/**  Header Files **************************************************/
#include <p18f4520.h>
#include <stdio.h>
#include <adc.h>
#include <portb.h>
#include <delays.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

/** Local Function Prototypes **************************************/
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 counter = 0;

/*******************************************************************
 * 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
    OpenADC(ADC_FOSC_8 & ADC_RIGHT_JUST & ADC_12_TAD,
            ADC_CH0 & ADC_INT_OFF & ADC_REF_VDD_VSS,
            0x0B); // Four analog pins
    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

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

    // Turn on the RB1 interrupt INT1, falling edge
    OpenRB1INT(PORTB_CHANGE_INT_ON & FALLING_EDGE_INT & PORTB_PULLUPS_OFF);
    INTCON3bits.INT1IP = 1;         // Setting the prior as high here
        
    INTCONbits.GIEH = 1; // Turn on high priority interrupts

    while (1) {
        if (counter == 0) {
            PORTC = 0b00000000;
        } else if (counter == 1) {
            PORTC = 0b10000001;
        } else if (counter == 2) {
            PORTC = 0b11000011;
        } else if (counter == 3) {
            PORTC = 0b11100111;
        } else if (counter == 4) {
            PORTC = 0b11111111;
        } else {
            counter = 0;  // Should not happen checked in ISR
        }
    }
}

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

void high_isr(void) {
    if (INTCON3bits.INT1IF) { // Interrupt 1, RB1 with debounce
        INTCON3bits.INT1IF = 0;
        Delay1KTCYx(30); // Assumes a 4 MHz clock
        if (PORTBbits.RB1 == PRESSED) {
            counter++;
            if (counter > 4) {
                counter = 0;
            }
        }
    }
}

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

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