#include <avr/io.h>
#include <avr/interrupt.h>
#include "adc.h"
#include "led.h"


/* button driver */
// TODO: make interrupt driven
#define BUTTON_DDR DDRB
#define BUTTON_PORT PORTB
#define BUTTON_REG PINB
#define BUTTON_PIN 1

enum {
	BUTTON_RELEASED,
	BUTTON_PRESSED
} button_state;

void button_init() {
	led_init();

	BUTTON_DDR &= ~(1<<BUTTON_PIN);
	BUTTON_PORT |= (1<<BUTTON_PIN);
	// activate pin change interrupt
	// PCINT9
	PCMSK1 |= (1<<PCINT9);
	GIMSK  |= (1<<PCIE1); // enable PCINT1
}



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() {
	if (!comm_iface.on_read)
		return;

	// 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);
	}
}

#include <communication.h>

void on_read(iface_t * sender, byte_t b) {
	if (!IS_EOM(b)) {
		sender->write(sender, b);
		return;
	}

	// strip EOM message
	sender->write(sender, b&0x7F);
}

struct {
	volatile message_t buffer;
	adc_sample_t adc_buffer[5];
} app = {};


ISR(PCINT1_vect) {
	if(BUTTON_REG&(1<<BUTTON_PIN)) {
		app.buffer.button = !app.buffer.button;
		led_toggle();
	}
}

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

	adc_init((adc_buffer_t){
		.ptr  = app.adc_buffer,
		.size = 5,
	}, 0x8F);

	// activate interrupts
	sei();
}

void delay(uint16_t d) {
	while(d--) {
		__asm("nop");
	}
}

void adc_int(volatile adc_buffer_t * buf)
{
	app.buffer.slider  = buf->ptr[4];

	app.buffer.poti[0] = buf->ptr[3];
	app.buffer.poti[1] = buf->ptr[2];
	app.buffer.poti[2] = buf->ptr[0];
	app.buffer.poti[3] = buf->ptr[1];
}

int main() {
	init();
	adc_on_done(adc_int);

	// start relevant perephials
	adc_start();

	while(1) {
		delay(app.buffer.poti[0]>>4);
	}
}
