#include <p18cxxx.h>
#include "main.h"

#define	ADDRESS	0x06
#define	DATA	0x12

unsigned char Buffer[26], index=0;

#pragma code INTERRUPT_VECTOR = 0x08
#pragma interrupt YourISRCode
void YourISRCode()
{
	//if (PIR1 & 0x02)
	if (PIR1bits.TMR2IF)
	{
		Infrared_Blink_State (TOGGLE);
		PR2 = Buffer[index++];
		if (index==26)
		{
			index = 0;
			Infrared_Transmit (OFF);
		}
		PIR1bits.TMR2IF = 0;
	}
}

#pragma code
void DelayMs (volatile unsigned int Ms)
{
	volatile unsigned int x;
	while (Ms--)
		for (x=900; x; x--);
	return;
}

void System_Init (void)
{
	unsigned char i;
	for (i=0; i<26; i++)
		Buffer[i] = ZERO;
	Clock_Init ();
	Digital_PIN_Init ();
	Timer2_Init ();
	GPIO_Init ();
	Infrared_Init ();
}

// Clock initialize
void Clock_Init (void)
{
	OSCTUNEbits.PLLEN = 1;  		// Enable the PLL and wait 2+ms until the PLL locks before enabling USB module
	DelayMs (50);
	return;
}

// Analog input/output --> general purpose input/output
void Digital_PIN_Init (void)
{
	// All outputs set as GPIO
    ANCON0 = 0xFF;
    ANCON1 = 0xFF;
    INTCON2bits.RBPU = 0;
    return;
}

void GPIO_Init (void)
{ 
	BUTTON_INPUT;					// Button --> Input
	
	// Infrared LED: 1 - ON; 0 - OFF
	//TRISC = TRISC & (~0x40);		// Infrared LED --> Output
	LATC = LATC & (~0x40);			// Infrared LED --> Off
	
	TRISC = TRISC | 0x80;			// receiver -> input
	
	// LED: 1 - OFF; 0 - ON
	TRISA = TRISA & (~0x01);		// LED0 --> Output
	LATA = LATA | 0x01;				// LED0 --> Off
    return;
}

// Timer4 is used for Infrared LED to blink (transmitting) with frequency ~36KHz
void Infrared_Init (void)
{
	// SDA & SCK - Input, Low State
	TRISB = TRISB | 0x30;
	PORTB = PORTB & (~0x30);

	// Configure Infrared LED - OUTPUT
	TRISC = TRISC & (~0x40);
	
	RPOR17 = 14; // ECCP1 Compare or PWM Output Channel A
		
	// start TIMER4 - prescaler: 4, count: 83 -> 36145Hz
	// ECCP1 is used in compare mode to generate freq on output
	CCPR1L = HALF_PERIOD;
	CCP1CON = 0b00001100; // PWM mode; PxA and PxC active-high; PxB and PxD active-high
	TCLKCON = 0x02;
		
	PR4 = TOGGLE_PERIOD;
	T4CON = 0b00000101;
	return;
}

// Timer2 is used to start/stop blinking with frequency 1152 Hz (period of 868 us)
void Timer2_Init (void)
{
	//int prescaler, temp;
	
    //RCON = RCON | 0x80;		// IPEN = 1;	interrupt priority enabled
    INTCON = INTCON | 0xC0;		// high and low priority interrupts enabled
    
    PIE1 = PIE1 | 0x02;		// Interrupt on Timer2 matching PR register
    IPR1 = IPR1 | 0x02;		// High priority interrupt
    T2CON = 0b01111110;		// setting of the Timer2 -> Prescaler -> 16; Postscaler -> 16
	return;
}

/*
ON - The LED is blinking.
OFF - The LED is off.
TOGGLE - Change between these states.
*/
void Infrared_Blink_State (char State)
{
	switch (State)
	{
		case ON:
    		//LATA = LATA & ~0x01;
    		RPOR17 = 14; // ECCP1 Compare or PWM Output Channel A - ON
		break;
		case OFF:
    		//LATA = LATA | 0x01;
    		RPOR17 = 0; // ECCP1 Compare or PWM Output Channel A - OFF
		break;
		case TOGGLE:
			//LATA = LATA ^ 0x01;
			if (RPOR17 == 14)
	    		RPOR17 = 0; // ECCP1 Compare or PWM Output Channel A - OFF
			else
				RPOR17 = 14; // ECCP1 Compare or PWM Output Channel A - ON
   		break;
		default:
		break;
	}
	return;
}

/*
ON - The LED is ON and transmit signals.
OFF - The LED is OFF. No signals transmitting.
TOGGLE - Change between these states.
*/
void Infrared_Transmit (char State)
{
	Infrared_Blink_State (OFF);
	switch (State)
	{
   		case ON:
			PIE1 = PIE1 | 0x02;
			//LATA = LATA & (~0x01);
   		break;
   		case OFF:
			PIE1 = PIE1 & (~0x02);
			//LATA = LATA | 0x01;
   		break;
   		case TOGGLE:
			PIE1 = PIE1 ^ 0x02;
			//LATA = LATA ^ 0x01;
   		break;
		default:
		break;
	}	
	return;
}

void Set_Command (unsigned char Address, unsigned char Data)
{
	unsigned char i;
	index = 0;
	PR2 = INITIAL;		// 2.4 ms
	for (i=1; i<=14; i=i+2)
	{
		if (Data & 0x01)
			Buffer[i] = ONE;
		else
			Buffer[i] = ZERO;
		Data = Data >> 1;
	}

	for (i=15; i<24; i=i+2)
	{
		if (Address & 0x01)
			Buffer[i] = ONE;
		else
			Buffer[i] = ZERO;
		Address = Address >> 1;
	}
	TMR2 = 0x00;
	PIR1bits.TMR2IF = 0;
	return;
}	

void main ()
{
	unsigned char Released = 1;
	System_Init ();
	Infrared_Transmit (OFF);
	while (1)
	{
		if (BUTTON_PRESSED && Released)
		{
			Infrared_Transmit (OFF);
			Set_Command (ADDRESS, DATA);
			Infrared_Transmit (ON);
			Infrared_Blink_State (TOGGLE);
			Released = 0;
			//DelayMs (1000);
		}
		
		if (!BUTTON_PRESSED)
			Released = 1;
	}	
	return;
}
