/*
 * hellorefsend.c
 *
 * Created: 28.4.2015 12:18:48
 *  Author: janiyli
 */ 


//
//
// hello.reflect.45.c
//
// light reflection synchronous detection hello-world
//    9600 baud FTDI interface
//
// Neil Gershenfeld
// 10/25/12
//
// (c) Massachusetts Institute of Technology 2012
// Permission granted for experimental and personal use;
// license for commercial sale available from MIT.
//

#include <avr/io.h>
#define F_CPU 8000000UL
#include <util/delay.h>

#define output(directions,pin) (directions |= pin) // set port direction for output
#define set(port,pin) (port |= pin) // set port pin
#define clear(port,pin) (port &= (~pin)) // clear port pin
#define pin_test(pins,pin) (pins & pin) // test for port pin
#define bit_test(byte,bit) (byte & (1 << bit)) // test for bit set
#define bit_delay_time 102 // bit delay for 9600 with overhead
#define bit_delay() _delay_us(bit_delay_time) // RS232 bit delay
#define half_bit_delay() _delay_us(bit_delay_time/2) // RS232 half bit delay
#define char_delay() _delay_ms(10) // char delay

#define serial_port PORTB
#define serial_direction DDRB
#define serial_pin_out (1 << PB2)

#define led_port PORTB
#define led_direction DDRB
#define led_pin (1 << PB3)

#define nloop 100 // number of loops to accumulate

void put_char(volatile unsigned char *port, unsigned char pin, char txchar) {
	//
	// send character in txchar on port pin
	//    assumes line driver (inverts bits)
	//
	// start bit
	//
	clear(*port,pin);
	bit_delay();
	//
	// unrolled loop to write data bits
	//
	if bit_test(txchar,0)
	set(*port,pin);
	else
	clear(*port,pin);
	bit_delay();
	if bit_test(txchar,1)
	set(*port,pin);
	else
	clear(*port,pin);
	bit_delay();
	if bit_test(txchar,2)
	set(*port,pin);
	else
	clear(*port,pin);
	bit_delay();
	if bit_test(txchar,3)
	set(*port,pin);
	else
	clear(*port,pin);
	bit_delay();
	if bit_test(txchar,4)
	set(*port,pin);
	else
	clear(*port,pin);
	bit_delay();
	if bit_test(txchar,5)
	set(*port,pin);
	else
	clear(*port,pin);
	bit_delay();
	if bit_test(txchar,6)
	set(*port,pin);
	else
	clear(*port,pin);
	bit_delay();
	if bit_test(txchar,7)
	set(*port,pin);
	else
	clear(*port,pin);
	bit_delay();
	//
	// stop bit
	//
	set(*port,pin);
	bit_delay();
	//
	// char delay
	//
	bit_delay();
}

int main(void) {
	//
	// main
	//
	static unsigned char count;
	static uint16_t on,off;
	//
	// set clock divider to /1
	//
	CLKPR = (1 << CLKPCE);
	CLKPR = (0 << CLKPS3) | (0 << CLKPS2) | (0 << CLKPS1) | (0 << CLKPS0);
	//
	// initialize output pins
	//
	set(serial_port, serial_pin_out);
	output(serial_direction, serial_pin_out);
	set(led_port, led_pin);
	output(led_direction, led_pin);
	//
	// init A/D
	//
	ADMUX = (0 << REFS2) | (0 << REFS1) | (0 << REFS0) // Vcc ref
	| (0 << ADLAR) // right adjust
	| (0 << MUX3) | (0 << MUX2) | (1 << MUX1) | (0 << MUX0); // ADC2
	ADCSRA = (1 << ADEN) // enable
	| (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // prescaler /128
	//
	// main loop
	//
	while (1) {
		//
		// accumulate
		//
		on = 0;
		off = 0;
		for (count = 0; count < nloop; ++count) {
			//
			// LED off
			//
			set(led_port, led_pin);
			//
			// initiate conversion
			//
			ADCSRA |= (1 << ADSC);
			//
			// wait for completion
			//
			while (ADCSRA & (1 << ADSC))
			;
			//
			// save result
			//
			off += ADC;
			//
			// LED on
			//
			clear(led_port, led_pin);
			//
			// initiate conversion
			//
			ADCSRA |= (1 << ADSC);
			//
			// wait for completion
			//
			while (ADCSRA & (1 << ADSC))
			;
			//
			// save result
			//
			on += ADC;
		}
		//
		// send framing
		//
		put_char(&serial_port, serial_pin_out, 1);
		char_delay();
		put_char(&serial_port, serial_pin_out, 2);
		char_delay();
		put_char(&serial_port, serial_pin_out, 3);
		char_delay();
		put_char(&serial_port, serial_pin_out, 4);
		char_delay();
		//
		// send result
		//
		on = (on - off)/100;
		if (on > 5) put_char(&serial_port, serial_pin_out, ('a'));
			else put_char(&serial_port, serial_pin_out, ('b'));
		
	}
}
