#include <Mega32.h>
#include <delay.h>
#include <stdio.h>
#include "txrx.c" 

#define begin {
#define end }

//define some useful maps to bits
#define MOUSE_CLK_OUT PORTC.1
#define MOUSE_CLK_IN PINC.0
#define MOUSE_DATA_OUT PORTC.5
#define MOUSE_DATA_IN PINC.4
#define KEYBOARD_CLK_OUT PORTC.3
#define KEYBOARD_CLK_IN PINC.2
#define KEYBOARD_DATA_OUT PORTC.7
#define KEYBOARD_DATA_IN PINC.6  

//define PS/2 data line states
#define IDLE 0
#define INHIBIT 1
#define BUSY 2
#define WAIT_FOR_REQUEST 3
#define REQUEST 4
#define POWEROFF 5

// boolean defines
#define TRUE 1
#define FALSE 0 

// RX defines
#define tx_id 163
#define MAX_RX_LENGTH 32   

char k;
unsigned char my_rx_data[MAX_RX_LENGTH];

#define MOUSE 1
#define KEYBOARD 2

#define LowLetter 0
#define CapLetter 1
#define Number 2
#define Punct 3

//an ascii list of the english letters sorted by frequency (sub 32 to get upper case)
//the letters are: e t a i o n s h r d l c u m w f g y p b v k j x q z
flash char letter[26]
={101,116,97,111,105,110,115,104,114,100,108,99,117,109,119,102,103,121,112,98,118,107,106,120,113,122};
//numbers : 0 1 2 3 4 5 6 7 8 9
flash char numbers[10] =
{48,49,50,51,52,53,54,55,56,57};
//other characters (punctuation)
//sorted for frequency:  . , : ; ? ! " ' / ( ) * + - = # $ % &
flash char punct[19] = 
{46,44,58,59,63,33,34,39,47,40,41,42,43,45,61,35,36,37,38};
char userMode;  //user mode 0 = mouse; 1 = keyboard;
char charMode;  //charater mode, 0:low lett  1:cap lett  2:numb   3:punc  5:backspace
char charLen[4] = {26,26,10,19};  //number of characters available in current mode
signed char nextChar;
char newChar;

signed char stepX, stepY, btnClick;
int blinkCount;
char bsCount;

char key, prev_key;

// byte declarations
unsigned char mouse_byte_index;
unsigned char mouse_transmit_byte;
unsigned char mouse_transmit_parity;
unsigned char mouse_receive_byte;
unsigned char mouse_receive_bit;
unsigned char mouse_previous_byte;
unsigned char mouse_resend_byte;

// clock state machine declarations
unsigned char mouse_clock_state;
unsigned char mouse_next_clock_state;
unsigned char mouse_state;
unsigned char mouse_transmit;
unsigned char mouse_receive;


// mouse packet declarations
unsigned char gen_mouse_packet;
unsigned int mouse_count;
unsigned char mouse_delay;

// mouse packet
unsigned char mouse_byte;
// keyboard packet
unsigned char key_byte;

// byte declarations
unsigned char keyboard_byte_index;
unsigned char keyboard_transmit_byte;
unsigned char keyboard_transmit_parity;
unsigned char keyboard_receive_byte;
unsigned char keyboard_receive_bit;
unsigned char keyboard_previous_byte;
unsigned char keyboard_resend_byte;

// clock state machine declarations
unsigned char keyboard_clock_state;
unsigned char keyboard_next_clock_state;
unsigned char keyboard_state;
unsigned char keyboard_transmit;
unsigned char keyboard_receive;


// keyboard packet declarations
unsigned char gen_keyboard_packet;
unsigned int keyboard_count;
unsigned char keyboard_delay;

#define RISE 0
#define HIGH 1
#define FALL 2
#define LOW 3

// queue declarations
#define QUEUELEN 100
unsigned char mouse_queue[QUEUELEN]; //queue of data sent by keyboard. (first in, first out)
unsigned char mouse_queueFull;    //indicates if queue is full
unsigned char mouse_queueEmpty;//indicates if queue is empty
unsigned char mouse_queueIn;       //indicates where to put data into queue
unsigned char mouse_queueOut;    //indicates where to take data out of queue

unsigned char keyboard_queue[QUEUELEN]; //queue of data sent by keyboard. (first in, first out)
unsigned char keyboard_queueFull;    //indicates if queue is full
unsigned char keyboard_queueEmpty;//indicates if queue is empty
unsigned char keyboard_queueIn;       //indicates where to put data into queue
unsigned char keyboard_queueOut;    //indicates where to take data out of queue

// PS/2 Host Command set.
#define ERROR			              0xFC
#define RESET 			            0xFF
#define RESEND 			            0xFE
#define SET_MAKE                0xFD
#define SET_MAKE_BREAK          0xFC
#define SET_TYPE                0xFB
#define SET_ALL_TYPE_MAKE_BREAK 0xFA
#define SET_ALL_MAKE            0xF9
#define SET_ALL_MAKE_BREAK      0xF8
#define SET_ALL_TYPE            0xF7
#define SET_DEFAULT 	          0xF6
#define DIS_DATA_REPORT         0xF5
#define EN_DATA_REPORT 	        0xF4
#define SET_SAMPLE_RATE         0xF3
#define GET_DEVICE_ID 	        0xF2
#define SET_REMOTE_MODE         0xF0      // for mouse
#define SET_SCAN_CODE           0xF0      // for keyboard
#define SET_WRAP_MODE 	        0xEE      // for mouse
#define ECHO                    0xEE      // for keyboard
#define SET_LED                 0xED
#define RESET_WRAP_MODE         0xEC
#define READ_DATA 		          0xEB
#define SET_STREAM_MODE         0xEA
#define STATUS_REQ 		          0xE9
#define SET_RES 		            0xE8
#define SET_SCALING21	          0xE7
#define SET_SCALING11	          0xE6

#define ACK 			          0xFA
#define SELF_TEST_PASS	    0xAA
#define INIT			          0x00
#define SCALING21		        0x02

// mouse declarations
unsigned char mouse_deviceID;
unsigned char mouse_data_reporting;
unsigned char mouse_sample_rate;
unsigned char mouse_scaling;	// 0 = 1:1, 1 = 2:1
unsigned char mouse_resolution;
unsigned char mouse_waiting_for_sample_rate;
unsigned char mouse_waiting_for_resolution;

// keyboard declarations
unsigned char keyboard_deviceID[2];
unsigned char keyboard_data_reporting;
unsigned char keyboard_waiting_for_sample_rate;
unsigned char keyboard_waiting_for_led;

// Function prototypes
void initialize(void); //all the usual mcu stuff

// function prototypes
unsigned char mouse_queuePut(unsigned char);
unsigned char mouse_queueGet(void);
void mouse_process_command(unsigned char);

unsigned char keyboard_queuePut(unsigned char);
unsigned char keyboard_queueGet(void);
void keyboard_process_command(unsigned char);

unsigned char getParity(unsigned char);

// mouse function
void mouse_init(void);
void mouse_send(signed char, signed char, unsigned char, unsigned char, unsigned char);

//keyboard function
void keyboard_init(void);
void keyboard_send(char,char);

void setMode(char);

// this interrupt should run every 20us or 1/4 period of the clock
interrupt [TIM0_COMP] void timer0_overflow(void)
begin

	if (mouse_queueEmpty == TRUE)
		mouse_count++;

	if (mouse_count >= 500)	// 100 samples a second
	begin
		gen_mouse_packet = TRUE;
		mouse_count = 0;
	end

	if (mouse_delay > 0)
	   mouse_delay--;

	// state machine for transmitting a byte to Host
	if (mouse_transmit && mouse_delay == 0)
	begin
		// update the next clock state
		mouse_clock_state = mouse_next_clock_state;

		// do the appropriate command based on the state of the clock
		switch (mouse_clock_state)
		begin
			case RISE:	// start or end a byte transmission
				switch (mouse_byte_index)
				begin
					case 0:
						// get a new byte to be xmitted
						if (mouse_queueEmpty == FALSE) // get data off the queue to be xmitted
						begin
				 			mouse_transmit_byte = mouse_queueGet();
				 			mouse_transmit_parity = getParity(mouse_transmit_byte);
				 			//delay_us(150);			// used to wait until host is ready
				 			mouse_delay = 7;
				 		end
				 		break;

				 	case 11:
				 		// finished transmission
				 		mouse_transmit = FALSE; 	// transmit finished
				 		mouse_byte_index = 0;	// reset byte index
				 		break;

				 	default:
				 		break;
				end

				if (mouse_delay == 0)
				begin
				   // set the new clock state
				   MOUSE_CLK_OUT = 1;
				   mouse_next_clock_state = HIGH;
				   break;	// end of RISE
				end

			case HIGH:	// can begin writing data to host

				// state machine ensure we transmit the correct bit from the PS/2 byte
				switch (mouse_byte_index)
				begin
					case 0:
						MOUSE_DATA_OUT = 0;
						break;
					case 1:
					case 2:
					case 3:
					case 4:
					case 5:
					case 6:
					case 7:
					case 8:
						MOUSE_DATA_OUT = mouse_transmit_byte & 0x01;
						mouse_transmit_byte = mouse_transmit_byte >> 1;
						break;
					case 9:
						MOUSE_DATA_OUT = mouse_transmit_parity;
						break;
					case 10:
						MOUSE_DATA_OUT = 1;
						break;
					default:
						break;
				end

				// update the byte index
				mouse_byte_index++;

				// update the clock state
				mouse_next_clock_state = FALL;
				break;	// end of HIGH

			case FALL:   // clock transitions to low
				MOUSE_CLK_OUT=0;				// pull the clock to 0
				mouse_next_clock_state = LOW;	// set the next clock state to low
				break;	// end of FALL

			case LOW:   // clock is low - nothing happens here
				mouse_next_clock_state = RISE;	// next clock state is rising
				break;	// end of RISE
		end
	end


	if (mouse_receive)
	begin
		// get the next clock state
		mouse_clock_state = mouse_next_clock_state;

		switch (mouse_clock_state)
		begin
			case RISE:	// all receiving done on the rising edge of the clock
				MOUSE_CLK_OUT = 1;

				// get the bit off the data line
			 	// and place into the receive_byte
				if (mouse_byte_index >=0 && mouse_byte_index < 8)
				begin
					mouse_receive_bit = MOUSE_DATA_IN;
					mouse_receive_byte = ((mouse_receive_bit & 0x01) << mouse_byte_index) | mouse_receive_byte;
				end

				// update variables for the next state
				if (mouse_byte_index < 11)
				begin
					mouse_next_clock_state = HIGH;
					mouse_byte_index++;
				end

				break;

			case HIGH:
				switch (mouse_byte_index)
				begin
					case 10:
						MOUSE_DATA_OUT = 0;
						break;

					case 11:
			        	MOUSE_DATA_OUT = 1; 	// send ACK

			        	// terminate receive operation and reset
			        	mouse_receive = FALSE;
			        	mouse_byte_index = 0;

			        	// process the received command
			        	mouse_process_command(mouse_receive_byte);

			        	mouse_receive_byte = 0;
			        	mouse_receive_bit = 0;
			        	break;
			  		default:
			  			break;
			  	end

			  	mouse_next_clock_state = FALL;
			  	break;

			case FALL:	// hosts transmits on the falling edge
				MOUSE_CLK_OUT = 0;
				mouse_next_clock_state = LOW;
				break;

			case LOW:
				mouse_next_clock_state = RISE;
				break;
		end
	end

	switch (mouse_state)
	begin
		case IDLE:
			// enter inhibt state if clock is trying to be pulled
			// low by host when device is trying to make high
			if ((mouse_clock_state == HIGH || mouse_clock_state == RISE) && MOUSE_CLK_IN == 0)	// host trying to pull CLK low!
			begin
				mouse_state = INHIBIT;  // go to the INHIBIT state
				mouse_next_clock_state = LOW;		// turn off the clock
				mouse_transmit = FALSE;			// mouse can no longer transmit
				mouse_receive = FALSE;			// mouse can no longer receive
			end
			else  // check if mouse needs to be in BUSY state -- anything on queue?
			begin
				if(mouse_queueEmpty == FALSE)
				begin
					mouse_state = BUSY;			// transition to busy state
					mouse_transmit = TRUE;				// allow mouse to transmit
					mouse_receive = FALSE;				// make sure we don't receive!
					mouse_next_clock_state = RISE;	// turn on the clock
					mouse_byte_index = 0;				// reset the byte index for transmit
				end
				else // otherwise we should just stay in IDLE
				begin
					mouse_state = IDLE;
				end
			end

			break;

		case BUSY:    
			// again check if host is trying to inhibt
			// by pulling the clock low when it should be high
			if ((mouse_clock_state == HIGH || mouse_clock_state == RISE) && MOUSE_CLK_IN == 0)
			begin
				mouse_state = INHIBIT;  // go to the INHIBIT state
				mouse_next_clock_state = LOW;		// turn off the clock
				mouse_transmit = FALSE;			// mouse can no longer transmit
				mouse_receive = FALSE;			// mouse can no longer receive
			end
			else // go back to IDLE if mouse has nothing to send or receive
			begin
				if ( !(mouse_transmit|| mouse_receive) )
					mouse_state = IDLE;
				else
					mouse_state = BUSY;		// otherwise stay BUSY
			end
			break;

	   	case INHIBIT:
			// if we enter the INHIBIT state before we finish sending
			// a byte, we should save the byte & resend!
			if(mouse_byte_index > 0 && mouse_byte_index < 10)
			begin
				mouse_resend_byte = TRUE;
			end
			// reset the byte index
			mouse_byte_index = 0;

			// check for REQUEST state
			// first, the host must release the CLK
			if (MOUSE_CLK_IN == 1)
			begin
				mouse_state = WAIT_FOR_REQUEST;	// next, we check for DATA line to go low
			end
			else // stay in INHIBIT state
			begin
				mouse_state = INHIBIT;
				mouse_transmit = FALSE;
				mouse_receive = FALSE;
				mouse_next_clock_state = LOW;
			end

			break;

		case WAIT_FOR_REQUEST:
			// check if the data line has gone low
			if(MOUSE_DATA_IN == 0)
			begin
				mouse_state = REQUEST;	// go to REQUEST state
				mouse_next_clock_state = RISE;	// turn on the clock
			end
			else
			begin
				// we must be in the IDLE state because both
				// CLK & DATA are high
				mouse_state = IDLE;
				mouse_next_clock_state = RISE;
			end

			break;

		case REQUEST: 
			// get ready to receive data from the host
			mouse_transmit = FALSE;
			mouse_receive = TRUE;
			mouse_byte_index = 0;
			mouse_next_clock_state = FALL;	// host sends data on falling edge

			// In case we get another INHIBIT state
			if ((mouse_clock_state == HIGH || mouse_clock_state == RISE) && MOUSE_CLK_IN == 0)
			begin
				mouse_state = INHIBIT;
				mouse_next_clock_state = LOW;
				mouse_transmit = FALSE;
				mouse_receive = FALSE;
			end
			else if (mouse_transmit || mouse_receive)	// go to BUSY state to process data
				mouse_state = BUSY;
			else
				mouse_state = REQUEST;			// otherwise stay in REQUEST until data comes
		break;

	end//end switch 
	
	
	if (keyboard_queueEmpty == TRUE)
		keyboard_count++;

	if (keyboard_count >= 15000)	// 5 samples a second
	begin
		gen_keyboard_packet = TRUE;
		keyboard_count = 0;
	end

	if (keyboard_delay > 0)
	   keyboard_delay--;

	// state machine for transmitting a byte to Host
	if (keyboard_transmit && keyboard_delay == 0)
	begin
		// update the next clock state
		keyboard_clock_state = keyboard_next_clock_state;

		// do the appropriate command based on the state of the clock
		switch (keyboard_clock_state)
		begin
			case RISE:	// start or end a byte transmission
				switch (keyboard_byte_index)
				begin
					case 0:
						// get a new byte to be xmitted
						if (keyboard_queueEmpty == FALSE) // get data off the queue to be xmitted
						begin
				 			keyboard_transmit_byte = keyboard_queueGet();
				 			keyboard_transmit_parity = getParity(keyboard_transmit_byte);
				 			//delay_us(150);			// used to wait until host is ready
				 			keyboard_delay = 7;
				 		end
				 		break;

				 	case 11:
				 		// finished transmission
				 		keyboard_transmit = FALSE; 	// transmit finished
				 		keyboard_byte_index = 0;	// reset byte index
				 		break;

				 	default:
				 		break;
				end

				if (keyboard_delay == 0)
				begin
				   // set the new clock state
				   KEYBOARD_CLK_OUT = 1;
				   keyboard_next_clock_state = HIGH;
				   break;	// end of RISE
				end

			case HIGH:	// can begin writing data to host

				// state machine ensure we transmit the correct bit from the PS/2 byte
				switch (keyboard_byte_index)
				begin
					case 0:
						KEYBOARD_DATA_OUT = 0;
						break;
					case 1:
					case 2:
					case 3:
					case 4:
					case 5:
					case 6:
					case 7:
					case 8:
						KEYBOARD_DATA_OUT = keyboard_transmit_byte & 0x01;
						keyboard_transmit_byte = keyboard_transmit_byte >> 1;
						break;
					case 9:
						KEYBOARD_DATA_OUT = keyboard_transmit_parity;
						break;
					case 10:
						KEYBOARD_DATA_OUT = 1;
						break;
					default:
						break;
				end

				// update the byte index
				keyboard_byte_index++;

				// update the clock state
				keyboard_next_clock_state = FALL;
				break;	// end of HIGH

			case FALL:   // clock transitions to low
				KEYBOARD_CLK_OUT=0;				// pull the clock to 0
				keyboard_next_clock_state = LOW;	// set the next clock state to low
				break;	// end of FALL

			case LOW:   // clock is low - nothing happens here
				keyboard_next_clock_state = RISE;	// next clock state is rising
				break;	// end of RISE
		end
	end


	if (keyboard_receive)
	begin
		// get the next clock state
		keyboard_clock_state = keyboard_next_clock_state;

		switch (keyboard_clock_state)
		begin
			case RISE:	// all receiving done on the rising edge of the clock
				KEYBOARD_CLK_OUT = 1;

				// get the bit off the data line
			 	// and place into the receive_byte
				if (keyboard_byte_index >=0 && keyboard_byte_index < 8)
				begin
					keyboard_receive_bit = KEYBOARD_DATA_IN;
					keyboard_receive_byte = ((keyboard_receive_bit & 0x01) << keyboard_byte_index) | keyboard_receive_byte;
				end

				// update variables for the next state
				if (keyboard_byte_index < 11)
				begin
					keyboard_next_clock_state = HIGH;
					keyboard_byte_index++;
				end

				break;

			case HIGH:
				switch (keyboard_byte_index)
				begin
					case 10:
						KEYBOARD_DATA_OUT = 0;
						break;

					case 11:
			        	KEYBOARD_DATA_OUT = 1; 	// send ACK

			        	// terminate receive operation and reset
			        	keyboard_receive = FALSE;
			        	keyboard_byte_index = 0;

			        	// process the received command
			        	keyboard_process_command(keyboard_receive_byte);

			        	keyboard_receive_byte = 0;
			        	keyboard_receive_bit = 0;
			        	break;
			  		default:
			  			break;
			  	end

			  	keyboard_next_clock_state = FALL;
			  	break;

			case FALL:	// hosts transmits on the falling edge
				KEYBOARD_CLK_OUT = 0;
				keyboard_next_clock_state = LOW;
				break;

			case LOW:
				keyboard_next_clock_state = RISE;
				break;
		end
	end

	switch (keyboard_state)
	begin
		case IDLE:
			// enter inhibt state if clock is trying to be pulled
			// low by host when device is trying to make high
			if ((keyboard_clock_state == HIGH || keyboard_clock_state == RISE) && KEYBOARD_CLK_IN == 0)	// host trying to pull CLK low!
			begin
				keyboard_state = INHIBIT;  // go to the INHIBIT state
				keyboard_next_clock_state = LOW;		// turn off the clock
				keyboard_transmit = FALSE;			// keyboard can no longer transmit
				keyboard_receive = FALSE;			// keyboard can no longer receive
			end
			else  // check if keyboard needs to be in BUSY state -- anything on queue?
			begin
				if(keyboard_queueEmpty == FALSE)
				begin
					keyboard_state = BUSY;			// transition to busy state
					keyboard_transmit = TRUE;				// allow keyboard to transmit
					keyboard_receive = FALSE;				// make sure we don't receive!
					keyboard_next_clock_state = RISE;	// turn on the clock
					keyboard_byte_index = 0;				// reset the byte index for transmit
				end
				else // otherwise we should just stay in IDLE
				begin
					keyboard_state = IDLE;
				end
			end

			break;

		case BUSY:
			// again check if host is trying to inhibt
			// by pulling the clock low when it should be high
			if ((keyboard_clock_state == HIGH || keyboard_clock_state == RISE) && KEYBOARD_CLK_IN == 0)
			begin
				keyboard_state = INHIBIT;  // go to the INHIBIT state
				keyboard_next_clock_state = LOW;		// turn off the clock
				keyboard_transmit = FALSE;			// keyboard can no longer transmit
				keyboard_receive = FALSE;			// keyboard can no longer receive
			end
			else // go back to IDLE if keyboard has nothing to send or receive
			begin
				if ( !(keyboard_transmit|| keyboard_receive) )
					keyboard_state = IDLE;
				else
					keyboard_state = BUSY;		// otherwise stay BUSY
			end
			break;

	   	case INHIBIT:
			// if we enter the INHIBIT state before we finish sending
			// a byte, we should save the byte & resend!
			if(keyboard_byte_index > 0 && keyboard_byte_index < 10)
			begin
				keyboard_resend_byte = TRUE;
			end
			// reset the byte index
			keyboard_byte_index = 0;

			// check for REQUEST state
			// first, the host must release the CLK
			if (KEYBOARD_CLK_IN == 1)
			begin
				keyboard_state = WAIT_FOR_REQUEST;	// next, we check for DATA line to go low
			end
			else // stay in INHIBIT state
			begin
				keyboard_state = INHIBIT;
				keyboard_transmit = FALSE;
				keyboard_receive = FALSE;
				keyboard_next_clock_state = LOW;
			end

			break;

		case WAIT_FOR_REQUEST:
			// check if the data line has gone low
			if(KEYBOARD_DATA_IN == 0)
			begin
			    keyboard_state = REQUEST;	// go to REQUEST state
				keyboard_next_clock_state = RISE;	// turn on the clock
			end
			else
			begin
				// we must be in the IDLE state because both
				// CLK & DATA are high
				keyboard_state = IDLE;
				keyboard_next_clock_state = RISE;
			end

			break;

		case REQUEST:
			// get ready to receive data from the host
			keyboard_transmit = FALSE;
			keyboard_receive = TRUE;
			keyboard_byte_index = 0;
			keyboard_next_clock_state = FALL;	// host sends data on falling edge

			// In case we get another INHIBIT state
			if ((keyboard_clock_state == HIGH || keyboard_clock_state == RISE) && KEYBOARD_CLK_IN == 0)
			begin
				keyboard_state = INHIBIT;
				keyboard_next_clock_state = LOW;
				keyboard_transmit = FALSE;
				keyboard_receive = FALSE;
			end
			else if (keyboard_transmit || keyboard_receive)	// go to BUSY state to process data
				keyboard_state = BUSY;
			else
				keyboard_state = REQUEST;			// otherwise stay in REQUEST until data comes
		break;

	end//end switch

end

//insert data into queue.  Return 1 if queue full, or 0 if inserted data sucessfully
unsigned char mouse_queuePut(unsigned char d)
begin
	if (mouse_queueFull==TRUE)		//check if queue is full
		return(TRUE);

	mouse_queue[mouse_queueIn]=d;			//insert d into queue
	mouse_queueIn++;					//increment where to stick in the next d value
	mouse_queueEmpty=FALSE;			//indicate queue isnt' empty anymore

	if (mouse_queueIn==QUEUELEN)		//if reached the end of the queue
		mouse_queueIn=0;				//wrap around to the beginning

	if (mouse_queueIn==mouse_queueOut)		//if queueIn caught up to queueOut
		mouse_queueFull=TRUE;			//indicate queue is full

	return(0);
end

//get data out of queue.  Return 0 if queue empty or the actual data if not empty
unsigned char mouse_queueGet(void)
begin
	char d;

	if(mouse_resend_byte == TRUE)	// in case we need to resend data due to an INHIBIT
	begin
		mouse_resend_byte = FALSE;
		return mouse_previous_byte;
	end

	if (mouse_queueEmpty==TRUE)	//check if queue is empty
		return(0);

	d=mouse_queue[mouse_queueOut];		//get data out of queue
	mouse_queueOut++;				//increment location where to get next d value
	mouse_queueFull=FALSE;		//indicate queue isn't full anymore

	if (mouse_queueOut==QUEUELEN)	//if reached the end of the queue
		mouse_queueOut=0;			//wrap around to the beginning

	if (mouse_queueOut==mouse_queueIn)	//if queueOut caught up to queueIn
		mouse_queueEmpty=TRUE;	//indicate queue is empty

	mouse_previous_byte = d;		// save the byte we just popped
							// in case we need to resend it.
	return(d);				//return the data from queue
end


//insert data into queue.  Return 1 if queue full, or 0 if inserted data sucessfully
unsigned char keyboard_queuePut(unsigned char d)
begin
	if (keyboard_queueFull==TRUE)		//check if queue is full
		return(TRUE);

	keyboard_queue[keyboard_queueIn]=d;			//insert d into queue
	keyboard_queueIn++;					//increment where to stick in the next d value
	keyboard_queueEmpty=FALSE;			//indicate queue isnt' empty anymore

	if (keyboard_queueIn==QUEUELEN)		//if reached the end of the queue
		keyboard_queueIn=0;				//wrap around to the beginning

	if (keyboard_queueIn==keyboard_queueOut)		//if queueIn caught up to queueOut
		keyboard_queueFull=TRUE;			//indicate queue is full

	return(0);
end

//get data out of queue.  Return 0 if queue empty or the actual data if not empty
unsigned char keyboard_queueGet(void)
begin
	char d;

	if(keyboard_resend_byte == TRUE)	// in case we need to resend data due to an INHIBIT
	begin
		keyboard_resend_byte = FALSE;
		return keyboard_previous_byte;
	end

	if (keyboard_queueEmpty==TRUE)	//check if queue is empty
		return(0);

	d=keyboard_queue[keyboard_queueOut];		//get data out of queue
	keyboard_queueOut++;				//increment location where to get next d value
	keyboard_queueFull=FALSE;		//indicate queue isn't full anymore

	if (keyboard_queueOut==QUEUELEN)	//if reached the end of the queue
		keyboard_queueOut=0;			//wrap around to the beginning

	if (keyboard_queueOut==keyboard_queueIn)	//if queueOut caught up to queueIn
		keyboard_queueEmpty=TRUE;	//indicate queue is empty

	keyboard_previous_byte = d;		// save the byte we just popped
							// in case we need to resend it.
	return(d);				//return the data from queue
end

//calculate the parity of a character
unsigned char getParity(unsigned char x)
begin
	unsigned char temp, i;
	temp=1;
	for(i=0;i<8;i++)
	begin
		temp=temp^(x&1);
		x>>=1;
	end
	return temp;
end

void mouse_process_command(unsigned char host_command)
begin   

	//delay_us(50);	// do this stuff at rising edge of CLK

	if (host_command == RESET)
	begin
		mouse_queueIn = 0;
		mouse_queueOut = 0;
		mouse_queueEmpty = TRUE;
		mouse_queueFull = FALSE;
		delay_us(500);
	end

	// Acknowledge the incoming request
	mouse_queuePut(ACK);

	// we received a byte w/ the new resolution
	if(mouse_waiting_for_resolution)
	begin
		// check for valid resolution
		if(host_command >= 0 && host_command <= 3)
			mouse_resolution = host_command;
		else
			mouse_queuePut(ERROR);

		mouse_waiting_for_resolution = FALSE;
		return;
	end

	// we received a byte w/ the new sample rate
	if(mouse_waiting_for_sample_rate)
	begin
		// check for valid sample rate
		if(host_command >= 10 && host_command <= 200)
			mouse_sample_rate = host_command;
		else // bad sample rate
			mouse_queuePut(ERROR);

		mouse_waiting_for_sample_rate = FALSE;
		return;
	end

	switch (host_command)
	begin
		case RESET:  	// RESET
			mouse_deviceID = 0x03;			// create a device ID
			mouse_queuePut(SELF_TEST_PASS);	// respond w/ self-test passed (0xAA)
			mouse_queuePut(mouse_deviceID);			// send host device ID
			mouse_data_reporting = 0;			// disable data reporting
			mouse_sample_rate = 100;			// set the sampling rate to 100
			mouse_scaling = 0;                // set scaling to 1:1
			mouse_resolution = 0x02;			// set resolution to 4
			break;

		case RESEND:	// Host requests for resending of data
			mouse_resend_byte = TRUE;
			break;

		case EN_DATA_REPORT:	// Enabling of data reporting
			PORTB.7 = 0;		// indicates mouse was detected
			mouse_data_reporting = TRUE;
			break;

		case SET_SCALING11: 	// set scaling 1:1
			mouse_scaling = 0;
			break;

		case SET_SCALING21:  	// set scaling 2:1
			mouse_scaling = 1;
			break;

		case GET_DEVICE_ID: 	// host requests device ID
			mouse_queuePut(mouse_deviceID);
			break;

		case SET_RES:  	// host requests to set resolution
			// host sends next byte with valid resolution
			// set a flag to get this byte
			mouse_waiting_for_resolution = TRUE;
			break;

		case STATUS_REQ: //status request respond 0xFA, 0x00, 0x02, 0x64
			mouse_queuePut(0x00);		// <FIX> have to create the right byte here ...
			mouse_queuePut(mouse_resolution);
			mouse_queuePut(mouse_sample_rate);
			break;

		case SET_SAMPLE_RATE: 	// host requests setting of sample rate
			// host sends next byte with valid sample rate
			// set a flag to get this byte
			mouse_waiting_for_sample_rate = TRUE;
			break;

		case DIS_DATA_REPORT: 	// disable data reporting
			mouse_data_reporting = FALSE;
			break;

		case SET_DEFAULT: 		// set default values
			mouse_data_reporting = FALSE;
			mouse_sample_rate = 100;
			mouse_resolution = 4;
			break;

		default:
			break;
	end
end


void keyboard_process_command(unsigned char host_command)
begin

	//delay_us(50);	// do this stuff at rising edge of CLK

	if (host_command == RESET)
	begin
		keyboard_queueIn = 0;
		keyboard_queueOut = 0;
		keyboard_queueEmpty = TRUE;
		keyboard_queueFull = FALSE;
		delay_us(500);
	end

	// Acknowledge the incoming request
	keyboard_queuePut(ACK);

	// we received a byte w/ the new sample rate
	if(keyboard_waiting_for_sample_rate)
	begin
		keyboard_waiting_for_sample_rate = FALSE;
		return;
	end

	// we received a byte w/ the LED status
	if(keyboard_waiting_for_led)
	begin
		// acknowledge
		keyboard_queuePut(ACK);
		//Running
		keyboard_data_reporting = TRUE;
		PORTB.6 = 0;
		keyboard_waiting_for_led = FALSE;
		return;
	end

	switch (host_command)
	begin
		case RESET:  	// RESET
			keyboard_deviceID[0] = 0xAB;			// create a device ID
			keyboard_deviceID[1] = 0x83;
			keyboard_queuePut(SELF_TEST_PASS);	// respond w/ self-test passed (0xAA)
			keyboard_queuePut(keyboard_deviceID[0]);			// send host device ID
			keyboard_queuePut(keyboard_deviceID[1]);
			PORTB.6 = 1;
			keyboard_data_reporting = FALSE;			// disable data reporting
			break;

		case RESEND:	// Host requests for resending of data
			keyboard_resend_byte = TRUE;
			break;

		case SET_MAKE:
    case SET_MAKE_BREAK:
    case SET_TYPE:
    case SET_ALL_TYPE_MAKE_BREAK:
    case SET_ALL_MAKE:
    case SET_ALL_MAKE_BREAK:
    case SET_ALL_TYPE:
      keyboard_queuePut(ACK);
      break;

		case EN_DATA_REPORT:	// Enabling of data reporting
			PORTB.6 = 0;		// indicates keyboard was detected
			keyboard_data_reporting = TRUE;
			break;

		case GET_DEVICE_ID: 	// host requests device ID
			keyboard_queuePut(keyboard_deviceID[0]);			// send host device ID
			keyboard_queuePut(keyboard_deviceID[1]);
			break;

		case SET_SAMPLE_RATE: 	// host requests setting of sample rate
			// host sends next byte with valid sample rate
			// set a flag to get this byte
			keyboard_waiting_for_sample_rate = TRUE;
			break;

		case DIS_DATA_REPORT: 	// disable data reporting
			keyboard_data_reporting = FALSE;
			break;

		case SET_DEFAULT: 		// set default values
			keyboard_data_reporting = FALSE;
			break;

		case SET_LED:
		  keyboard_queuePut(ACK);
		  keyboard_waiting_for_led = TRUE;
		  break;

		default:
			break;
	end
end

void initialize(void)
begin

	ADMUX = 0b01000000; //ADLAR is not set
	ADCSRA = 0b11000111; //Enable & Start ADC w/ division factor of 128
	OCR0=5;	   				//20 uSec
	TIMSK=2;	   			//turn on timer 0 cmp-match ISR
	TCCR0=0b00001011;		//prescalar to 64  and Clr-on-match

	// setup Port C for PS/2 communication
	DDRC = 0b10101010;
	PORTC = 0b10101010;

	// setup LEDs for debugging
	DDRB = 0xFF;
	PORTB = 0xFF;

	DDRD.2 = 1;
	PORTD.2 = 0;

	// counter to be used in ISR
	mouse_count = 0;
	mouse_delay = 0;
	keyboard_count = 0;
	keyboard_delay = 0;

	// initialize our outputs
	MOUSE_CLK_OUT = 1;
	MOUSE_DATA_OUT = 1;
	KEYBOARD_CLK_OUT = 1;
	KEYBOARD_DATA_OUT = 1;

	//crank up the ISRs
	#asm
		sei
	#endasm
end

void mouse_init()
begin

	// initialize the queue
	mouse_queueEmpty = TRUE;
	mouse_queueFull = FALSE;
	mouse_queueIn = 0;
	mouse_queueOut =0;

	// initialize the states
	mouse_byte_index = 0;				// where we are in byte
	mouse_state = IDLE;			// state of the mouse
	mouse_clock_state = HIGH;			// state of the clock
	mouse_next_clock_state = HIGH;	// what clock will be changing to
	mouse_transmit = mouse_receive = 0;

	// init byte vars
	mouse_transmit_byte = 0xFA;
	mouse_receive_byte = 0x00;
	mouse_previous_byte = 0x00;
	mouse_resend_byte = FALSE;

	gen_mouse_packet = FALSE;

	// init mouse vars
	mouse_deviceID = 0x03;
	mouse_data_reporting = FALSE;
	mouse_sample_rate = 0;
	mouse_scaling = 0;
	mouse_resolution = 0;
	mouse_waiting_for_sample_rate = FALSE;
	mouse_waiting_for_resolution = FALSE;

	// let the host know the mouse is connected
	mouse_queuePut(SELF_TEST_PASS);
	mouse_queuePut(INIT);

end

void keyboard_init()
begin

	// initialize the queue
	keyboard_queueEmpty = TRUE;
	keyboard_queueFull = FALSE;
	keyboard_queueIn = 0;
	keyboard_queueOut =0;

	// initialize the states
	keyboard_byte_index = 0;				// where we are in byte
	keyboard_state = IDLE;			// state of the keyboard
	keyboard_clock_state = HIGH;			// state of the clock
	keyboard_next_clock_state = HIGH;	// what clock will be changing to
	keyboard_transmit = keyboard_receive = 0;

	// init byte vars
	keyboard_transmit_byte = 0xFA;
	keyboard_receive_byte = 0x00;
	keyboard_previous_byte = 0x00;
	keyboard_resend_byte = FALSE;

	gen_keyboard_packet = FALSE;

	// init keyboard vars
	keyboard_deviceID[0] = 0xAB;
	keyboard_deviceID[1] = 0x83;
	keyboard_data_reporting = FALSE;
	keyboard_waiting_for_sample_rate = FALSE;
	keyboard_waiting_for_led = FALSE;

	// let the host know the keyboard is connected
	keyboard_queuePut(SELF_TEST_PASS);
	keyboard_queuePut(INIT);

end

void mouse_send(signed char Xmove, signed char Ymove, unsigned char Leftbutton, unsigned char Middlebutton, unsigned char Rightbutton)
begin
	if (gen_mouse_packet == TRUE)
	begin

		gen_mouse_packet = FALSE;
      
		mouse_byte = 0x08;
		mouse_byte = mouse_byte | (((Ymove >> 7)&0x1)<<5) | (((Xmove >> 7)&0x1)<<4) | ((Middlebutton&0x1) <<2) | ((Rightbutton&0x1)<<1) | (Leftbutton & 0x1);

    mouse_queuePut(mouse_byte);
	  mouse_queuePut(Xmove);
		mouse_queuePut(Ymove);

	end
end

void keyboard_send(char key, char breakCode)
begin

	   char shift = FALSE;
		if (charMode == LowLetter)
		begin   
		   switch (key)
		   begin
		      case 8: key_byte = 0x66; break;
		      case 'a': key_byte = 0x1C; break;
		      case 'b': key_byte = 0x32; break;
		      case 'c': key_byte = 0x21; break;
		      case 'd': key_byte = 0x23; break;
		      case 'e': key_byte = 0x24; break;
		      case 'f': key_byte = 0x2B; break;
		      case 'g': key_byte = 0x34; break;
		      case 'h': key_byte = 0x33; break;
		      case 'i': key_byte = 0x43; break;
		      case 'j': key_byte = 0x3B; break;
		      case 'k': key_byte = 0x42; break;
		      case 'l': key_byte = 0x4B; break;
		      case 'm': key_byte = 0x3A; break;
		      case 'n': key_byte = 0x31; break;
		      case 'o': key_byte = 0x44; break;
		      case 'p': key_byte = 0x4D; break;
		      case 'q': key_byte = 0x15; break;
		      case 'r': key_byte = 0x2D; break;
		      case 's': key_byte = 0x1B; break;
		      case 't': key_byte = 0x2C; break;
		      case 'u': key_byte = 0x3C; break;
		      case 'v': key_byte = 0x2A; break;
		      case 'w': key_byte = 0x1D; break;
		      case 'x': key_byte = 0x22; break;
		      case 'y': key_byte = 0x35; break;
		      case 'z': key_byte = 0x1A; break;
		   end
		end
		else if (charMode == CapLetter)
		begin 
		   shift = TRUE;  
		   switch (key)
		   begin
		      case 8: key_byte = 0x66; break;
		      case 'A': key_byte = 0x1C; break;
		      case 'B': key_byte = 0x32; break;
		      case 'C': key_byte = 0x21; break;
		      case 'D': key_byte = 0x23; break;
		      case 'E': key_byte = 0x24; break;
		      case 'F': key_byte = 0x2B; break;
		      case 'G': key_byte = 0x34; break;
		      case 'H': key_byte = 0x33; break;
		      case 'I': key_byte = 0x43; break;
		      case 'J': key_byte = 0x3B; break;
		      case 'K': key_byte = 0x42; break;
		      case 'L': key_byte = 0x4B; break;
		      case 'M': key_byte = 0x3A; break;
		      case 'N': key_byte = 0x31; break;
		      case 'O': key_byte = 0x44; break;
		      case 'P': key_byte = 0x4D; break;
		      case 'Q': key_byte = 0x15; break;
		      case 'R': key_byte = 0x2D; break;
		      case 'S': key_byte = 0x1B; break;
		      case 'T': key_byte = 0x2C; break;
		      case 'U': key_byte = 0x3C; break;
		      case 'V': key_byte = 0x2A; break;
		      case 'W': key_byte = 0x1D; break;
		      case 'X': key_byte = 0x22; break;
		      case 'Y': key_byte = 0x35; break;
		      case 'Z': key_byte = 0x1A; break;
		   end
		end
		else if (charMode == Number)
		begin
		   switch (key)
		   begin 
		      case 8: key_byte = 0x66; break;
		      case '0': key_byte = 0x45; break;
		      case '1': key_byte = 0x16; break;
		      case '2': key_byte = 0x1E; break;
		      case '3': key_byte = 0x26; break;
		      case '4': key_byte = 0x25; break;
		      case '5': key_byte = 0x2E; break;
		      case '6': key_byte = 0x36; break;
		      case '7': key_byte = 0x3D; break;
		      case '8': key_byte = 0x3E; break;
		      case '9': key_byte = 0x46; break;
		   end
		end
		else
		begin
		   switch (key)
		   begin 
		      case 8: key_byte = 0x66; break;
		      case '.': key_byte = 0x49; break;
		      case ',': key_byte = 0x41; break;
		      case ':': key_byte = 0x4C; shift = TRUE; break;
		      case ';': key_byte = 0x4C; break;
		      case '?': key_byte = 0x4A; shift = TRUE; break;
		      case '!': key_byte = 0x16; shift = TRUE; break;
		      case '\"': key_byte = 0x52; shift = TRUE; break;
		      case '\'': key_byte = 0x52; break;
		      case '/': key_byte = 0x4A; break;
		      case '(': key_byte = 0x46; break;
		      case ')': key_byte = 0x45; break;
		      case '*': key_byte = 0x3E; break;
		      case '+': key_byte = 0x55; shift = TRUE; break;
		      case '-': key_byte = 0x4E; shift = TRUE; break;
		      case '=': key_byte = 0x55; break;
		      case '#': key_byte = 0x26; shift = TRUE; break;
		      case '$': key_byte = 0x25; shift = TRUE; break;
		      case '%': key_byte = 0x2E; shift = TRUE; break;
		      case '&': key_byte = 0x3D; shift = TRUE; break;
		   end
		end
    
		if (breakCode == FALSE)
		  if (shift == TRUE)
		  begin
		    keyboard_queuePut(0x12);     // shift
		    keyboard_queuePut(key_byte);
		  end
		  else
		  begin
		    keyboard_queuePut(key_byte); 
		  end 
		else
		  if (shift == TRUE)
		  begin
		    keyboard_queuePut(0xF0);
		    keyboard_queuePut(key_byte);
		    keyboard_queuePut(0xF0);
		    keyboard_queuePut(0x12);     // shift	    
		  end
		  else
		  begin
		    keyboard_queuePut(0xF0);
		    keyboard_queuePut(key_byte);
		  end 

end 

//set user mode to mosue or keyboard
void setMode(char mode)
begin
	userMode = mode;
	charMode = LowLetter;
	nextChar = 0;
	newChar = TRUE;  
	blinkCount = 0;
	bsCount = 0;
	prev_key = 0;
	key = 0;
end 

void main(void)
begin           

	initialize();  
   while (keyboard_data_reporting == FALSE)
   begin
      keyboard_init();
      delay_ms(200);
   end
   while (mouse_data_reporting == FALSE)
   begin
	   mouse_init();
	   delay_ms(200);
   end
	
   //TXRX init
 	txrx_init(0,1,249,1);//RX only - 4000 baud - led on
  rx_reset(MAX_RX_LENGTH);
  
  setMode(MOUSE); 
   
	// begin real work
	while (TRUE)
	begin
		// if receive data
      if(rxdone()==1)
	   begin            
         k=0;
         init_getrx();
         while(rx_empty()!=1)
         begin
            my_rx_data[k] = get_next_rx_data();
            k++;
         end
         // 0 - 170
         // 1 - start_char
         // 2 - ID
         // 3 - length
         // 4 to x - payload
         rx_reset(MAX_RX_LENGTH);                                   
        
         if (userMode == MOUSE)
         begin        
            if (my_rx_data[2] == tx_id)
            begin
               stepX = 0;
               stepY = 0;
               btnClick = 0;

			   // mouse Y movement
               if (my_rx_data[5] == 0)
                  stepY = 9;
               else if (my_rx_data[5] == 42)
                  stepY = 6;
               else if (my_rx_data[5] == 84)
                  stepY = 3;
               else if (my_rx_data[5] == 168)
                  stepY = -3;     
               else if (my_rx_data[5] == 210)
                  stepY = -6;                  
               else if (my_rx_data[5] == 255)
                  stepY = -9;
               
			   // mouse X movement
               if (my_rx_data[4] == 0)
                  stepX = -9;
               else if (my_rx_data[4] == 42)
                  stepX = -6;
               else if (my_rx_data[4] == 84)
                  stepX = -3;
               else if (my_rx_data[4] == 168)
                  stepX = 3;
               else if (my_rx_data[4] == 210)
                  stepX = 6;   
               else if (my_rx_data[4] == 255)
                  stepX = 9;

               if (my_rx_data[6] == 255)
               begin
                  blinkCount++;
               end
               else
               begin
                  
                   //long blink to switch to keyboard mode
                  if (blinkCount >= 80)
                  begin
                     setMode(KEYBOARD);
                     btnClick = 1; 
                  end 
                  //short blink to click 
                  else if (blinkCount >= 10)
                  begin
                     btnClick = 1;
                  end
				 
                  blinkCount = 0; 
               end
			   // send mouse signal to pc
               mouse_send(stepX,stepY,btnClick,0,0);
            end
         end
         else if (userMode == KEYBOARD)
         begin 

            if (my_rx_data[2] == tx_id && gen_keyboard_packet == TRUE)
            begin
               gen_keyboard_packet = FALSE;
			  // send break code of previous character
               if (prev_key != 0)         
               begin
                  keyboard_send(prev_key,TRUE);
               end                  
			   // send actual character
               if (prev_key != key && newChar == FALSE)
               begin
                  keyboard_send(key,FALSE);
                  prev_key = key;
               end 
               else
               begin
                  if (my_rx_data[4] > 168)
                  begin
					// scroll down character
                     switch (charMode)
                     begin
                        case LowLetter:
                           key = letter[nextChar++];
                           break;
                        case CapLetter:
                           key = letter[nextChar++]-32;
                           break;
                        case Number:
                           key = numbers[nextChar++];
                           break;
                        case Punct:
                           key = punct[nextChar++];
                           break;
                     end
                     if (nextChar == charLen[charMode])
                        nextChar = 0;
                     if (newChar == FALSE)
                     begin
                        keyboard_send(8,FALSE);
                        prev_key = 8;
                     end
                     else
                        newChar = FALSE;
                  end
                  else if (my_rx_data[4] < 84)
                  begin  
					// scroll down character
                    nextChar--;
                    if (nextChar == -1)
                    nextChar = charLen[charMode]-1;
                    switch (charMode)
                    begin
                      case LowLetter:
                        key = letter[nextChar];
                        break;
                      case CapLetter:
                        key = letter[nextChar]-32;
                        break;
                      case Number:
                        key = numbers[nextChar];
                        break;
                      case Punct:
                        key = punct[nextChar];
                        break;
                    end
                    if (newChar == FALSE)
                     begin
                        keyboard_send(8,FALSE);
                        prev_key = 8;
                     end
                     else
                        newChar = FALSE;
                  end
                  else if (my_rx_data[5] < 84)
                  begin
					// change character mode
                    nextChar = 0;
                    if (charMode == 3)
                       charMode = 0; 
                    else charMode++;
                    switch (charMode)
                     begin
                        case LowLetter:
                           key = letter[nextChar++];
                           break;
                        case CapLetter:
                           key = letter[nextChar++]-32;
                           break;
                        case Number:
                           key = numbers[nextChar++];
                           break;
                        case Punct:
                           key = punct[nextChar++];
                           break;
                     end
                     if (newChar == FALSE)
                     begin
                        keyboard_send(8,FALSE);
                        prev_key = 8;
                     end
                     else
                        newChar = FALSE;
                  end
                  else if (my_rx_data[5] > 168)
                  begin
					// backspace
                    bsCount++;
                    if (bsCount == 3)
                    begin
                      keyboard_send(8,FALSE);
                      prev_key = key = 8;
                      bsCount = 0;
                    end
                  end
                  if (my_rx_data[6] == 255) 
                  begin            
                    blinkCount++;
                  end  
                  else
                  begin
                    
                    // long blink to switch to mouse mode 
                    if (blinkCount >= 10)
                    begin
                      setMode(MOUSE); 
                    end
                    //short blink to start new character 
                    else if (blinkCount >= 2)
                    begin
                      newChar = TRUE;
                      nextChar = 0;
                    end
                    blinkCount = 0;
                  end
               end 
            end 
            
         end  
             
      end

 	end
end