#define F_CPU 8000000UL
#define UART_BAUD 9600

#include <avr/io.h>
#include <avr/interrupt.h>
#include "uart.h"
#include "util.h"

static volatile uint16_t data;
static volatile uint8_t clocks = 0;
static volatile uint8_t communication_inhibited = 0;

static inline void update_data(uint8_t b) {
    if (b) {
	DDRB &= ~_BV(PB1); /* in */
	PORTB |= _BV(PB1); /* up */
    } else {
	DDRB |= _BV(PB1); /* out */
	PORTB &= ~_BV(PB1); /* 0 */
    }
}

static inline void update_clock(uint8_t b) {
    if (b) {
	DDRD &= ~_BV(PD2); /* in */
	PORTD |= _BV(PD2); /* up */
    } else {
	DDRD |= _BV(PD2); /* out */
	PORTD &= ~_BV(PD2); /* 0 */
    }
}

static inline void handle_timer(void) {
    TCNT0 = 128;
    if (clocks == 0) {
	return;
    }
    if ((clocks & 3) == 1) {
	if ((PIND & _BV(PD2)) == 0) {
	    data = 1;
	    clocks = 1;
	    communication_inhibited = 1;
	}
	update_data(data & 1);
	data = data >> 1;
    }
    if ((clocks & 1) == 0) {
	update_clock(clocks & 2);
    }
    clocks--;
}

ISR(TIMER0_OVF0_vect) {
    handle_timer();
}

int main(void) {
    uart_init();
    uart_putchar('i');
    update_data(1);
    update_clock(1);
    TCCR0 = _BV(CS00); /* CLK */
    TIMSK = _BV(TOIE0); /* OVF */
    uart_putchar('I');
    sei();

    for (;;) {
 	uint8_t ch = uart_getchar();
	// (echo s00011100001; sleep 0.1; echo s00000111111s00011100001) > /dev/ttyS1
	if (ch == 's') {
	    uint8_t i;
	    cli();
	    communication_inhibited = 0;
	    data = _BV(11) /*extra*/;
	    clocks = 11 * 4 + 1;
	    for (i = 0; i < 11; i++) {
		if (uart_getchar() == '1') {
		    data |= _BV(i);
		}
	    }
	    sei();
	    while (clocks) {
	    }
	    uart_putchar(communication_inhibited ? 'E' : 'O');
	}
    }
}
