/*
 * bus.node.44.sz.with2leds.pb.c
 *
 * Created: 4/27/2014 4:07:05 PM
 *  Author: Scott Zitek
 */ 
// based upon hello.bus.45.c
//
// 9600 baud serial bus hello-world
//
// Neil Gershenfeld
// 11/24/10
//
// (c) Massachusetts Institute of Technology 2010
// Permission granted for experimental and personal use;
// license for commercial sale available from MIT.
//

// sz - Modified for ATtiny44
#define F_CPU 8000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/pgmspace.h>
#include <string.h>

#define output(directions,pin) (directions |= pin) // set port direction for output
#define input(directions,pin) (directions &= (~pin)) // set port direction for input
#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 100 // 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 led_delay() _delay_ms(100) // LED flash delay

//on my board there is a pushbutton connected to PA3
#define input_port PORTA
#define input_direction DDRA
#define input_pins PINA
#define input_pin (1 << PA3)

// on my board the green LED is PB2
#define led_port_a PORTB
#define led_direction_a DDRB
#define led_pin_a (1 << PB2) //sz - different pin for first LED and renamed led_pin to led_pin_a

// on my board the red LED is PA7
#define led_port_b PORTA
#define led_direction_b DDRA
#define led_pin_b (1 << PA7)


// sz - on my board, pin PA1 is bus TX and PA0 is bus RX (on example hello.bus.44, PB3 is bus TX and PB4 is bus RX
#define serial_port PORTA
#define serial_direction DDRA
#define serial_pins PINA
#define serial_pin_in (1 << PA1)
#define serial_pin_out (1 << PA0)

#define node_id '3'

void get_char(volatile unsigned char *pins, unsigned char pin, char *rxbyte) {
	//
	// read character into rxbyte on pins pin
	//    assumes line driver (inverts bits)
	//
	*rxbyte = 0;
	while (pin_test(*pins,pin))
	//
	// wait for start bit
	//
	;
	//
	// delay to middle of first data bit
	//
	half_bit_delay();
	bit_delay();
	//
	// unrolled loop to read data bits
	//
	if pin_test(*pins,pin)
	*rxbyte |= (1 << 0);
	else
	*rxbyte |= (0 << 0);
	bit_delay();
	if pin_test(*pins,pin)
	*rxbyte |= (1 << 1);
	else
	*rxbyte |= (0 << 1);
	bit_delay();
	if pin_test(*pins,pin)
	*rxbyte |= (1 << 2);
	else
	*rxbyte |= (0 << 2);
	bit_delay();
	if pin_test(*pins,pin)
	*rxbyte |= (1 << 3);
	else
	*rxbyte |= (0 << 3);
	bit_delay();
	if pin_test(*pins,pin)
	*rxbyte |= (1 << 4);
	else
	*rxbyte |= (0 << 4);
	bit_delay();
	if pin_test(*pins,pin)
	*rxbyte |= (1 << 5);
	else
	*rxbyte |= (0 << 5);
	bit_delay();
	if pin_test(*pins,pin)
	*rxbyte |= (1 << 6);
	else
	*rxbyte |= (0 << 6);
	bit_delay();
	if pin_test(*pins,pin)
	*rxbyte |= (1 << 7);
	else
	*rxbyte |= (0 << 7);
	//
	// wait for stop bit
	//
	bit_delay();
	half_bit_delay();
}

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();
}

void put_string(volatile unsigned char *port, unsigned char pin, PGM_P str) {
	//
	// send character in txchar on port pin
	//    assumes line driver (inverts bits)
	//
	static char chr;
	static int index;
	index = 0;
	do {
		chr = pgm_read_byte(&(str[index]));
		put_char(&serial_port, serial_pin_out, chr);
		++index;
	} while (chr != 0);
}

void flash() {
	//
	// LED flash delay
	//	
	set(led_port_a, led_pin_a);
	set(led_port_b, led_pin_b);
	led_delay();
	clear(led_port_a, led_pin_a);
	clear(led_port_b, led_pin_b);
	led_delay();

}

void flash_a() {
	//
	// LED flash delay
	//
	set(led_port_a, led_pin_a);
	led_delay();
	clear(led_port_a, led_pin_a);
	led_delay();
}

void flash_b() {
	//
	// LED flash delay
	//
	set(led_port_b, led_pin_b);
	led_delay();
	clear(led_port_b, led_pin_b);
	led_delay();
}


int main(void) {
	//
	// main
	//
	static char chr;
	//
	// set clock divider to /1
	//
	CLKPR = (1 << CLKPCE);
	CLKPR = (0 << CLKPS3) | (0 << CLKPS2) | (0 << CLKPS1) | (0 << CLKPS0);
	
	//
	// initialize input pins
	//
	
	input(input_direction,input_pin); //makes PA3 (pin 10) an input to monitor my pushbutton - I don’t need pull-up resistor
	
	//
	// initialize output pins
	//
	set(serial_port, serial_pin_out);
	input(serial_direction, serial_pin_out);
	
	//set(led_port_a, led_pin_a);
	output(led_direction_a, led_pin_a);
	
	output(led_direction_b, led_pin_b);
	
	//
	// main loop
	//
	while (1)
	{ 
		
				
			get_char(&serial_pins, serial_pin_in, &chr);
			flash_a(); //flash green LED each time a character is received
			if (chr == node_id) 
				{
				output(serial_direction, serial_pin_out);
				if pin_test(input_pins, input_pin)//button is not pushed
					{
					static const char message[] PROGMEM = "button not-pressed node ";
					put_string(&serial_port, serial_pin_out, (PGM_P) message);
					put_char(&serial_port, serial_pin_out, chr);
					put_char(&serial_port, serial_pin_out, 10); // new line
					}
				else // button is pressed
					{
					static const char message[] PROGMEM = "button pressed, node ";
					put_string(&serial_port, serial_pin_out, (PGM_P) message);
					put_char(&serial_port, serial_pin_out, chr);
					put_char(&serial_port, serial_pin_out, 10); // new line
					}
				led_delay();
				flash_b();
				input(serial_direction, serial_pin_out);
				}
	}
}