/********************************************************************************
 		Remote Control State Machine
		Mauro Grassi May 2008 for Musicolour BETA ver 8.0 and above
 		based on code by Peter Smith
		Infrared receive state machine (must be called every 64us)
*********************************************************************************/
#include "h/ir.h"
#include "h/flashmem.h"
#include "h/lcd16x2.h"

__attribute__((space(psv)))
unsigned int irCodes[IRKEYS]=
{  0x0140, 0x0141, 0x0142, 0x0143, 0x0144, 0x0145, 0x0146, 0x0147, 0x0148, 0x0149, 0x0150, 0x0151, 0x0160, 0x0161, 0x017C, 0x0176, 0x0175, 0x0169, 0x0174 , 0x0172, 0x0177, 0x014F, 0x0168, 0x0167 };

char definitionString[IRKEYS][9]=
{
	"0",
	"1",
	"2",
	"3",
	"4",
	"5",
	"6",
	"7",
	"8",
	"9",
	"Vol.Up",
	"Vol.Down",
	"Ch.Up",
	"Ch.Down",
	"Menu",
	"Stop",
	"Play",
	"Pause",
	"Fast.F",
	"Rewind",
	"Record",
	"Ok",
	"Exit",
	"Line"
};

unsigned int Codes[IRKEYS];
unsigned int keyBuffer[KEY_BUFFER_SIZE];
BYTE keyFull;
BYTE keyGetPtr;
BYTE keyPtr;
unsigned int ir_timer;
BYTE ir_state, ir_bit_cnt;
unsigned int ir_cmd, ir_code;
unsigned int ir_timeout;
BYTE ir_rpt;
BYTE ir_rdy;

//*****************************************************************************
// Keys pressed FIFO functions
//*****************************************************************************
unsigned int getKey(void)
{
	unsigned int g;
	if(keyFull>0)
    	{
	    g=keyBuffer[keyGetPtr];
	    keyGetPtr++;
	    if(keyGetPtr>=KEY_BUFFER_SIZE)keyGetPtr=0;
	    keyFull--;
	    } else g=0xFFFF;
	return g;
}

void putKey(unsigned int k)
{
    if(keyFull<KEY_BUFFER_SIZE)
     {
	 keyBuffer[keyPtr]=k;
	 keyPtr++;
	 if(keyPtr>=KEY_BUFFER_SIZE)keyPtr=0;
	 keyFull++;
	 }    
}    

void readRemoteControlCodes(void)
{
	int i;
	for(i=0; i<IRKEYS; i++)
	{
	Codes[i]=(unsigned int)readFlashMemory(REMOTE_CONTROL_DEFS_ADDRESS+1+i);
	}
}

void initKeys(void)
{
	keyFull=0;
	keyGetPtr=0;
	keyPtr=0;
	defineDefaultRemoteControl();
}

void writeRemoteControlCodes(void)
{
	int i;
	for(i=0; i<IRKEYS; i++)
	{
	writeFlashMemory(REMOTE_CONTROL_DEFS_ADDRESS+1+i, Codes[i]);
	}
}

unsigned int keyCodeDefined(unsigned int key, int i)
{
	// checks if the key has already been defined!
	int j;
	unsigned int b;

	b=0;
	j=0;
	while((b==0)&&(j<i))
	{
	if((Codes[j] & 0x7FF)==(0x7FF & key))b=1;
	j++;
	}
	return b;
}


void reDefineRemoteControlCodes(void)
{
	// here the user can define the remote control codes...
	int i;
	unsigned int myKey;
	unsigned int x;

 	 writeStringLCD(0, "Press:", 16);
	 writeStringLCD(0x40, "", 16);
	 i=0;
	 while(i<IRKEYS)
	 {
	 writeStringLCD(7, definitionString[i], 16);
	 keyFull=0;
	 keyGetPtr=0;
	 keyPtr=0;
     while(keyFull==0)
	 {
	 
	 }
	 myKey=(ir_cmd & 0x7FF);
	 if((keyCodeDefined(myKey, i))==0)
		{
		 Codes[i]=myKey;			// do not allow duplicate definitions	
		 i++;
		}
	 }
 	 readFlashRow();
	 x=(3*(REMOTE_CONTROL_DEFS_ADDRESS+1));
	 for(i=0; i<IRKEYS; i++)
	 {
	 myBuffer[x+2]=0;
	 myBuffer[x+1]=(Codes[i]>>8);	
	 myBuffer[x]=Codes[i];
	 x+=3;
	 }
	 writeFlashRow();

 	 writeStringLCD(0, "Done.", 16);
	 writeStringLCD(0x40, "", 16);
	 delayMs(1500);
}

void defineDefaultRemoteControl(void)
{
	unsigned int i, x;
	//
	i=(unsigned int)readFlashMemory(REMOTE_CONTROL_DEFS_ADDRESS);
	//
	if(i!=MAGIC_REMOTE_CONTROL_VALUE)
	{
	readFlashRow();
	x=(3*(REMOTE_CONTROL_DEFS_ADDRESS+1));
	for(i=0; i<IRKEYS; i++)
	{
	myBuffer[x+2]=0;
	myBuffer[x+1]=(irCodes[i]>>8);	
	myBuffer[x]=irCodes[i];
	x+=3;
	}
	x=3*REMOTE_CONTROL_DEFS_ADDRESS;
	myBuffer[x]=MAGIC_REMOTE_CONTROL_VALUE;
	myBuffer[x+1]=0;
	myBuffer[x+2]=0;
	x=3*JAYCARLCD_ADDR;
	if(USE_JAYCAR_LCD)
	{
	myBuffer[x]=0xFF;
	myBuffer[x+1]=0xFF;
	myBuffer[x+2]=0xFF;
	} else
	{
	myBuffer[x]=0;
	myBuffer[x+1]=0;
	myBuffer[x+2]=0;
	}
	writeFlashRow();
	}
	readRemoteControlCodes();
}

void initRC5(void)
{
	ir_state=0;
	ir_timer=0;
	ir_rdy=0;
	ir_code=0;
	ir_cmd=0;
	ir_rpt=0;
	T2CONbits.T32=0;			// individual 16 bit timer Timer 2
	T2CONbits.TCKPS=0b10;		// 1:64 division ratio
	T2CONbits.TCS=0;			// FCY= 40 MIPS clock
	T2CONbits.TGATE=0;
	PR2=40;						// 40Mhz / 64 / 40 = 64us period
	IFS0bits.T2IF=0;
	IEC0bits.T2IE=1;			// enable interrupt
	T2CONbits.TON=1;
}

void ir_is_finished(void)
{
		ir_bit_cnt--;
		if(ir_bit_cnt!=0)
		{
			ir_state=5;
			ir_timer=0;
		} else 
		{
			if(ir_cmd==ir_code)ir_rpt++; else ir_rpt=0;
			ir_code=ir_cmd;
			ir_rdy|=1;
			ir_state=0;
		}	
}
/***************************************************************************
 RC5 State 6
 Bit was a low, so wait for rising edge to syncronize timing
***************************************************************************/
/*
void rc5_s6(void)
{
	if(IR_RXD==1)ir_is_finished();
	else if(ir_timer>THIRTY_FIVE)ir_state=0;
}
*/
/***************************************************************************
 RC5 State 7
 Bit was a high, so wait for falling edge to syncronize timing
**************************************************************************/
/*
void rc5_s7(void)
{
	if(IR_RXD==0)ir_is_finished();
	else if(ir_timer>THIRTY_FIVE)ir_state=0;
}
*/

int ir_receive(void)
{
	// this needs to be called approximately every 64us!
	ir_timer++;
	ir_state&=7;
	switch(ir_state)
	{
		default:
		case 0:
			//rc5_s0();
			if(IR_RXD==1)
			{ 
					ir_timer=0; 
					ir_state++; 
			}
			break;
		case 1:
			//rc5_s1();
			if(IR_RXD==0){ ir_state=0; } 
			else if(ir_timer>=SEVENTY_EIGHT)ir_state++;
			break;
		case 2:
			//rc5_s2();
			if(IR_RXD==0)
			{
			ir_timer=0;
			ir_state++;
			}
			break;
		case 3:
			//rc5_s3();
			if(IR_RXD==1){
			ir_timer=0;
			ir_state++;
			} else	if(ir_timer>=THIRTY_ONE)ir_state=0;		//  more than 2ms?
			break;
		case 4:
			//rc5_s4();
			if(IR_RXD==0){
				ir_bit_cnt=12;			// initialize bit count (12 bits)
				ir_cmd=0;				// zero the command
				ir_timer=0;				// reset timer
				ir_state++;
 				} else if(ir_timer>=THIRTY_ONE)ir_state=0;
			break;
		case 5:	
			//rc5_s5();
			if(ir_timer>=TWENTY_ONE)
			{
			ir_state++;
			ir_cmd=ir_cmd<<1;
			if(IR_RXD==1)
			{
			ir_cmd|=1;
			ir_state++;
			} 
			ir_timer=0;
			}
			break;
		case 6:
			//rc5_s6();
			if(IR_RXD==1)ir_is_finished();
			else if(ir_timer>THIRTY_FIVE)ir_state=0;
			break;
		case 7:
			//rc5_s7();
			if(IR_RXD==0)ir_is_finished();
			else if(ir_timer>THIRTY_FIVE)ir_state=0;
			break;
	}
	return 0;
}

unsigned int translateIRCode(unsigned int xx)
{
	BYTE i;
	unsigned int k;
	
	k=0xFFFF;
	for(i=0; i<IRKEYS; i++)	
	{
	if((0x07FF & xx)==(0x07FF & Codes[i]))k=i;
	}
    if(k!=0xFFFF)return k; else return 0xFFFF;
}

void __attribute__((interrupt, no_auto_psv))_T2Interrupt(void)
{
	
	if(ir_rdy==0)
	{
		ir_receive();
	} else
	if(ir_rdy==1)
	{
		putKey(translateIRCode(ir_cmd));
		IR_LED=0;
		ir_timeout=0;
		ir_rdy=2;
	} else
	{
		ir_timeout++;
		if(ir_timeout>=2000)
		{
			IR_LED=1;
			ir_rdy=0;
		}
	}
	IFS0bits.T2IF=0;
}
