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

#define F_CPU 4000000UL

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

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

#define SYNC 0xAA
#define RADDR 0x80

#define BUTTON1 0 // PB0

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

#define TXPWR	3
#define LED		5

// Around 10 seconds at 1024 prescaler
#define SLEEP	160

uint8_t buttonState_now;
uint8_t buttonState_last;
int sleepCounter = 0;
uint8_t sleepMode = 0;

void USART_Init(void)
{
	UBRRL = (uint8_t)UBRRVAL;	// Low byte
	UBRRH = (UBRRVAL>>8);		// High byte
	
	UCSRA = 0x00;
	UCSRB |= (1 << 3);	// TXEN ON, TX ON,        xxxx 1xxx
	UCSRC = 0x86;		// 8 Data, 1 Stop, No Parity   1xxx x11x
}

void USART_vSendByte(uint8_t u8Data)
{
    // Wait if a byte is being transmitted
    while((UCSRA&(1<<UDRE)) == 0);

    UDR = u8Data; 
}

void Send_Packet(uint8_t addr, uint8_t cmd)
{
	USART_vSendByte(SYNC); // Sync
	USART_vSendByte(addr); // Receiver address
	USART_vSendByte(cmd); // Button status
	USART_vSendByte((addr+cmd)); // Checksum
}

void transmitButtons(uint8_t buttonState)
{
	cli();
	_delay_ms(6);
	PORTB |= _BV(LED);
	Send_Packet(RADDR, buttonState);
	_delay_ms(2);
	PORTB &= ~(_BV(LED));
	sei();
}

ISR(SIG_TIMER0_OVF)
{
	cli();
	if(sleepCounter == SLEEP)
	{
		transmitButtons(0x00);
		_delay_ms(4);
		PORTB &= ~(_BV(TXPWR)); // TX PWR OFF
		PORTB &= ~(_BV(LED));
		sleepMode = 1;
	}
	else
	{
		sleepCounter++;
		sei();
	}
}

int main(void)
{
	// PB5 = LED, PB3 = TXPWR
	DDRB = 0b00101000;
	PORTB = 0x01;
	
	DDRD = 0x02;
	PORTD = 0xFF;

	cli();

	// Initialize UART
	USART_Init();

	// Initialize timers
	TCCR0B = 0x00;
	TCNT0 = 0x00;
	TCCR0B = 0b00000101;
	TIMSK |= _BV(TOIE0);

	sei();

	// Hello World
	PORTB |= _BV(LED);
	_delay_ms(500);
	PORTB &= ~(_BV(LED));
	
	buttonState_now = 0x00;
	buttonState_last = 0x00;

	PORTB |= _BV(TXPWR); // TX PWR ON
	transmitButtons(buttonState_now);
	
	while(1)
	{
		buttonState_now = 0x00;

		if(bit_is_clear(PIND, BUTTON2))
			buttonState_now |= _BV(BUTTON2-1);
		else buttonState_now &= ~(_BV(BUTTON2-1));

		if(bit_is_clear(PIND, RIGHT))
			buttonState_now |= _BV(RIGHT-1);
		else buttonState_now &= ~(_BV(RIGHT-1));

		if(bit_is_clear(PIND, LEFT))
			buttonState_now |= _BV(LEFT-1);
		else buttonState_now &= ~(_BV(LEFT-1));

		if(bit_is_clear(PIND, DOWN))
			buttonState_now |= _BV(DOWN-1);
		else buttonState_now &= ~(_BV(DOWN-1));

		if(bit_is_clear(PIND, UP))
			buttonState_now |= _BV(UP-1);
		else buttonState_now &= ~(_BV(UP-1));

		if(bit_is_clear(PINB, BUTTON1))
			buttonState_now |= _BV(BUTTON1);
		else buttonState_now &= ~(_BV(BUTTON1));
		
		if(sleepMode == 0)
			transmitButtons(buttonState_now);
		
		if(buttonState_now != buttonState_last)
		{
			sleepCounter = 0;
			PORTB |= _BV(TXPWR); // TX PWR ON

			if(sleepMode == 1)
				transmitButtons(buttonState_now);
			
			sleepMode = 0;

			sei();
		}

		buttonState_last = buttonState_now;
	}

	return 0;
}
