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

/* adc driver */
void adc_init() {
	ADMUX = 0; // set channel, set reference to vdd
	ADCSRA = (1<<ADEN) | // enable adc
			(1<<ADIE); // enable adc interrupt
}
void adc_start() {}

enum {
	ADC_CHANNEL_1,
	ADC_CHANNEL_2,
	ADC_CHANNEL_3,
	ADC_CHANNEL_4,
	ADC_CHANNEL_5,
	ADC_CHANNEL_6,
	ADC_CHANNEL_7,
	ADC_CHANNEL_COUNT
};


uint16_t adc_samples[ADC_CHANNEL_COUNT];
uint8_t adc_current_sample;

ISR(ADC_vect) {
	uint16_t sample;
	adc_samples[adc_current_sample] = sample;

	adc_current_sample = (adc_current_sample+1)/ADC_CHANNEL_COUNT;
}


/* led driver */
#define LED_DDR DDRA
#define LED_REG PORTA
#define LED_PIN 1

static inline void led_toggle() {
	LED_REG ^= (1<<LED_PIN);
}

static inline void led_off() {
	LED_REG &= ~(1<<LED_PIN);
}

static inline void led_on() {
	LED_REG |= (1<<LED_PIN);
}

void led_init() {
	LED_DDR |= (1<<LED_PIN);
	led_off();
}

/* button driver */
// TODO: make interrupt driven
#define BUTTON_DDR DDRA
#define BUTTON_REG PINA
#define BUTTON_PIN 1

enum {
	BUTTON_RELEASED,
	BUTTON_PRESSED
} button_state;

void button_init() {
	led_init();
	
	BUTTON_DDR &= ~(1<<BUTTON_PIN);
}

int button_set_state(int state) {
	if (state == BUTTON_PRESSED) 
		led_on();
	else
		led_off();

	button_state = state;
	return state;
}

int button_is_pressed() {
	return BUTTON_REG&(1<<BUTTON_PIN);
}

/* Communication driver */
#define SLAVE_ENABLE_DDR DDRA
#define SLAVE_ENABLE_REG PINA
#define SLAVE_ENABLE_PIN 1

#include <interface.h>

void comm_write(iface_t * iface, byte_t byte) {
	// disable interrupt
	uint8_t temp = USICR;
	USICR &= ~(1<<USIOIE);

	// write data register
	USIDR = byte;

	// wait for buffer overflow
	while(!(USICR&(1<<USIOIE))) {}

	// restore control register
	USICR = temp;	
}

iface_t comm_iface;

void comm_init() {
	// TODO: setup pins
	// TODO: setup USART in synchronous mode
	USICR = (1<<USIWM0)|(1<<USICS1);

	comm_iface.write = comm_write;
}

void comm_start() {
	// TODO: activate USART 
	USICR |= (1<<USIOIE);
}

ISR(USI_OVF_vect) {
	byte_t byte = USIBR;
	
	// only operate when enabled
	if (SLAVE_ENABLE_REG & (1<<SLAVE_ENABLE_PIN)) {
		return;
	}
	
	if (comm_iface.on_read) {
		comm_iface.on_read(&comm_iface, byte, comm_iface.callback_data);
	}
}

/* main application code */
void init() {
	adc_init();
	button_init();
	comm_init();

	adc_start();
	comm_start();

	// activate interrupts
	sei();
}

int main() {
	init();

	while(1) {}
}
