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

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

#include <interface.h>

typedef struct {
	iface_t iface;
} comm_t;

comm_t  comm;
void comm_write(iface_t * iface, byte_t byte) {
	// disable interrupt (temporarily)
	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;	
}

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

	// init interface
	comm.iface.write = comm_write;
}

void comm_start() {
	// don't start without interrupt handler
	if (!comm.iface.on_read)
		return;

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

ISR(USI_OVF_vect) {
	// call interrupt handler
	comm.iface.on_read(&comm.iface, USIBR, comm.iface.callback_data);
}

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

#include "main.h"

// the public instance of the app buffer
struct app app = {};

// initalizes the application modules
void init() {
	// init button module (making the button light up on press)
	// module also updates app.buffer.button for us
	button_init();

	// init adc module
	// will sample 0x8F (CHANNEL 8 and 0-3) 
	// this module also updates app.buffer.poti and slider for us
	adc_init((adc_buffer_t){
		.ptr  = app.adc_buffer,
		.size = 5,
	}, 0x8F);

	// init communication module
	comm_init();
	
	// bind state encoder to communication module
	slave_init(&app.state, &comm.iface);
	
	// start all modules
	adc_start();
	comm_start();
	
	// activate interrupts (effectivly starting the application)
	sei();
}


// little debug helper function
// FIXME: remove when not needed
void delay(uint16_t d) {
	while(d--) {
		__asm("nop");
	}
}

int main() {
	init();

	// start relevant periphials
	adc_start();

	while(1) {
		// nothing to do here, the application is interrupt-driven
	}
}
