/********************************************************************
* FileName:        Exam Rev 1.c
* Processor:       PIC18F4520
* Compiler:        MPLAB C18 v.3.06 
*
* This file performs the operations requested for the ME430 Lab Exam 
* Oct 29th, 2008
*                                                                     
*
*       Author               Date              Comment
*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
// David Fisher 			10-28-08

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

/** Configuration Bits *********************************************/     
#pragma config OSC = EC  // EC = External 4MHz Crystal for PICDEM board only
#pragma config WDT = OFF
#pragma config LVP = OFF
#pragma config BOREN = OFF

/** Define Constants Here ******************************************/
#define PRESSED 0
#define UNPRESSED 1
#define DELAY_TIME_1K_100mS 100

#define VOLUME 20
#define NO_VOLUME 0

#define TIMER_RESET_VALUE 56160
#define LIGHT_STAGE1 0b00001000
#define LIGHT_STAGE2 0b00000100
#define LIGHT_STAGE3 0b00000010
#define LIGHT_STAGE4 0b00000001

#define BUZZER_300_HZ 207
#define BUZZER_450_HZ 138
#define BUZZER_600_HZ 103
#define BUZZER_750_HZ 82
			

/** Local Function Prototypes **************************************/
void low_isr(void);
void high_isr(void);
void fireTheCannon(char fireLine);

/** 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 RA0result=0;
char line1[17];
char line2[17];
char recentState = LIGHT_STAGE1;
char recentButtonState = UNPRESSED;

/*******************************************************************
* Function:        void main(void)
********************************************************************/
#pragma code
void main (void)
{
	char cannonOnLine =1;
// -------------------------- General Pin I/O -----------------------------
// REQUIRES: #include <p18f4520.h> 
	ADCON1 = 0x0F;				// All pins digital IO
	TRISB = 0x00;				// All of PORTB is an Output
	TRISAbits.TRISA4 = 1; 		// Makes RA4 an input
	PORTB = LIGHT_STAGE1;		// Turn on RB2 and RB3

// ----------------  Displaying information to the LCD --------------------
// REQUIRES: #include "LCD Module.h"
// REQUIRES: #include <stdio.h>
	XLCDInit();   
    XLCDClear();
    XLCDDisplayOnCursorOff(); 			 	

// --------------------------- Using the ADC ------------------------------
// REQUIRES: #include <adc.h>
	OpenADC(ADC_FOSC_8 & ADC_RIGHT_JUST & ADC_12_TAD, 
			ADC_CH0 & ADC_INT_OFF & ADC_REF_VDD_VSS, 
			0x0E);		

// -------------------------- Using the PWM -------------------------------
// REQUIRES: #include <timers.h>
// REQUIRES: #include <pwm.h>
	OpenTimer2(TIMER_INT_OFF & T2_PS_1_16);	
	OpenPWM1(BUZZER_300_HZ);			
	SetDCPWM1(0);			

// ------------------------- Using Interrupts -------------------------------
// REQUIRES: #include <timers.h>
	// Put the interrupts into Priority Mode
	RCONbits.IPEN = 1;
	// Start up Timer 0 with high priority interrupts 128 prescaler
	OpenTimer0( TIMER_INT_ON & T0_16BIT & T0_SOURCE_INT & T0_PS_1_128 );
	INTCON2bits.TMR0IP = 1;
	WriteTimer0(TIMER_RESET_VALUE);
	// Turn on High Priority interrupts
	INTCONbits.GIEH = 1;
		
	while (1)
    {
		SetChanADC( ADC_CH0 );		// Select the pin
		ConvertADC(); 				// Start conversion
		while( BusyADC() ); 		// Wait for completion
		RA0result = ReadADC(); 		// Read result	
		
		if(PORTAbits.RA4 == PRESSED) 
		{
			fireTheCannon(cannonOnLine);
		}
		else
		{
			if(RA0result < 512)
			{
				cannonOnLine =1;			
				XLCDL1home();
				XLCDPutRomString("->     ");	
				XLCDL2home();
				XLCDPutRomString("       ");
			}
			else
			{
				cannonOnLine =2;
				XLCDL1home();
				XLCDPutRomString("       ");	
				XLCDL2home();
				XLCDPutRomString("->     ");
			}
		}	
    }
}

/*****************************************************************
* Additional Helper Functions
******************************************************************/

/*****************************************************************
* Function:			void sample(void)
* Input Variables:	none
* Output Return:	none
* Overview:			Use a comment block like this before functions
******************************************************************/
void fireTheCannon(char fireLine)
{
	if(fireLine == 1)
	{
		XLCDL1home();
	}
	else
	{
		XLCDL2home();
	}		
	XLCDPutRomString("-> ---");
}	

/*****************************************************************
* Function:        void high_isr(void)
* Possible sources of interrupt - none
* Overview:
******************************************************************/
#pragma interrupt high_isr
void high_isr(void)
{
	if(INTCONbits.TMR0IF)  // Check wether it was the timer 0 interrupt
	{						
		INTCONbits.TMR0IF = 0;	// Clear interrupt flag for TIMER Zero
		WriteTimer0(TIMER_RESET_VALUE);
		
		SetDCPWM1(VOLUME);  	// set the duty cycle (provides volume)
		switch (recentState) 
		{
			case LIGHT_STAGE1:
				recentState = LIGHT_STAGE2;
				OpenPWM1(BUZZER_450_HZ);				
				break;	
			case LIGHT_STAGE2:
				recentState = LIGHT_STAGE3;
				OpenPWM1(BUZZER_600_HZ);
				break;
			case LIGHT_STAGE3:
				recentState = LIGHT_STAGE4;
				OpenPWM1(BUZZER_750_HZ);
				break;							
			case LIGHT_STAGE4:
				recentState = LIGHT_STAGE1;
				OpenPWM1(BUZZER_300_HZ);
				break;
			default:
				recentState = LIGHT_STAGE1;
				OpenPWM1(BUZZER_300_HZ);
				break;			
		}
		PORTB = recentState;
		Delay1KTCYx(DELAY_TIME_1K_100mS);
		SetDCPWM1(NO_VOLUME);	// Stop the buzzer
	}
}

/******************************************************************
* Function:        void low_isr(void)
* Possible sources of interrupt - none
* Overview:
********************************************************************/
#pragma interruptlow low_isr
void low_isr(void)
{
	// Add code here for the low priority Interrupt Service Routine (ISR)
}