/**
*  Wireless TAC-2
*  
*  >> Receiver
*  
*  (c) Aki Korhonen
*  http://akikorhonen.org/
*  2009-02-03
*/

#define F_CPU 6000000UL

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <stdio.h>
#include <inttypes.h>

#define BAUDRATE 1200
#define UBRRVAL ((F_CPU/(BAUDRATE*16UL))-1)

#define SYNC 0xAA
#define RADDR 0x80

#define BUTTON	6
#define RIGHT	5
#define LEFT	4
#define DOWN	3
#define UP		2

#define LED		7

void USART_Init(void)
{
	UBRRL = (uint8_t)UBRRVAL;	// Low byte
	UBRRH = (UBRRVAL>>8);		// High byte
	
	UCSRA = 0x00;
	UCSRB |= (1 << 4);	// RXEN, RX ON,           xxx1 1xxx
	UCSRB |= (1 << 7);	// RXIE, RX interrupt ON, 1xx1 1xxx
	UCSRC = 0x86;		// 8 Data, 1 Stop, No Parity   1xxx x11x
}

uint8_t USART_vReceiveByte(void)
{
    // Wait until a byte has been received
    while((UCSRA&(1<<RXC)) == 0);

    // Return received data
    return UDR;
}

ISR(USART_RX_vect)
{
	// Define variables
	uint8_t raddress, data, chk;

	// Receive destination address
	raddress = USART_vReceiveByte();

	// Receive data
	data = USART_vReceiveByte();

	// Receive checksum
	chk = USART_vReceiveByte();

	// Compare received checksum with calculated
	if(chk == (raddress+data))
	{
		if(raddress == RADDR)
		{
			if(bit_is_set(data, BUTTON-1) || bit_is_set(data, 0))
				PORTD &= ~(_BV(BUTTON));
			else PORTD |= _BV(BUTTON);

			if(bit_is_set(data, RIGHT-1))
				PORTD &= ~(_BV(RIGHT));
			else PORTD |= _BV(RIGHT);

			if(bit_is_set(data, LEFT-1))
				PORTD &= ~(_BV(LEFT));
			else PORTD |= _BV(LEFT);

			if(bit_is_set(data, DOWN-1))
				PORTD &= ~(_BV(DOWN));
			else PORTD |= _BV(DOWN);

			if(bit_is_set(data, UP-1))
				PORTD &= ~(_BV(UP));
			else PORTD |= _BV(UP);
			
			PORTB |= _BV(LED);
			_delay_ms(10);
			PORTB &= ~(_BV(LED));
		}
	}
}

int main(void)
{
	// Status LED on PB7
	DDRB = 0x80;
	PORTB = 0x00;
	
	// PD2-PD6 output
	DDRD = 0x7C;
	PORTD = 0x7C;
	
	// Hello World
	PORTB |= _BV(LED);
	_delay_ms(1000);
	PORTB &= ~(_BV(LED));
	
	// Initialize UART
	USART_Init();
	
	// Enable global interrupts
	sei();
	
	while(1)
	{
		//
	}
	
	return 0;
}
