/* Fab_node_F1.c  ATTINY45 see ADC difference to ATTINY44
 * Created: 29.5.2017 Author : ylouhisa  version: 15.6.2017 
   Temp ADC + LEDs  + IO ; send periodicly adc results to MainB. Sleeps by command 255. Wake up by reset.  */ 

#define F_CPU 8000000UL // 8 MHz internal clock (UL Unsigned Long)
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <util/delay.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 105 // bit delay for 9600 with overhead: Node1 100 and Node2 105.
#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_pin1 PB3	//  LED RED (+ADC -) 
#define led_pin2 PB0	//  LED GREEN  

#define serial_port PORTB
#define serial_direction DDRB
#define serial_pins PINB
#define serial_pin_in (1 << PB2	)   // RX
#define serial_pin_out (1 << PB1)   // TX

#define node_id '2'		// Here is defined the NODE (0, 1, 2)

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 initADC()	{					// 8-bit ADC, set ADLAR to 1 to enable the Left-shift result (only bits ADC9..ADC2).
	ADMUX |=	(1 << ADLAR);		// Reading ADCH is sufficient for 8-bit results (256 values). See difference to A44.
	ADCSRA =	(1 << ADEN)  |      // Enable ADC
	(1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);			// Set prescaler to 128. Eg. 8 MHz/128 = 62.5 Hz sample rate.
}

int main(void) {					// Node 2 code !!
	int Mtemp, Mvolt, Mtlim, Mvlim;
	static char chr;

	set_sleep_mode(SLEEP_MODE_PWR_DOWN);
	
	// set clock divider to /1
	CLKPR = (1 << CLKPCE);
	CLKPR = (0 << CLKPS3) | (0 << CLKPS2) | (0 << CLKPS1) | (0 << CLKPS0);
	// initialize serial pins
	set(serial_port, serial_pin_out);

		// LED Port directions output
	DDRB |= (1 << led_pin1);	// RED (+ADC -)
	DDRB |= (1 << led_pin2);	// GREEN
		// LED  lights 
	PORTB |= (0 << led_pin2);	// ~GREEN =1 
	PORTB &= ~(1 << led_pin1);  // RED =0 : ADC STARTS
	
	initADC();

	Mtlim = 114; Mvlim = 205;  // Limits are same as MainB_F1
		output(serial_direction, serial_pin_out); // Starts MainB
		
		put_char(&serial_port, serial_pin_out, 100); // by value 100
		put_char(&serial_port, serial_pin_out, 100); // by value 100

	while(1) {
			input(serial_direction, serial_pin_out);
			get_char(&serial_pins, serial_pin_in, &chr); //  This node gets voltage or sleep info.
			Mvolt = chr;

			if (chr == 255) {		// If ascii 255 then goto sleep.
			sleep_enable();
			sleep_mode();
			}

			PORTB &= ~(1 << led_pin1);  // RED =0 : ADC STARTS		
			ADMUX |=  (1 << MUX1);      // use ADC2 (PB4),  and |= this (MUX =000010b) = TEMP
			ADCSRA |= (1 << ADSC);      // start ADC measurement = TEMP

			while (ADCSRA & (1 << ADSC) ); // wait till conversion complete
			Mtemp = ADCH;
			_delay_ms(50);
			
			if (Mtemp < Mtlim && Mvolt > Mvlim) {	// temp > 20C and voltage > 12V, then green light on
				PORTB &= ~(1 << led_pin2);			// ~GREEN =1
				_delay_ms(300);
			}
			if (Mvolt <= Mvlim) {	// temp < 20C and voltage < 12V, then red flashes
				PORTB |= (1 << led_pin1);			// RED =1
				PORTB |= (1 << led_pin2);			// ~GREEN =0
				_delay_ms(300);
				
				PORTB &= ~(1 << led_pin1);			// RED =0 : ADC STARTS
				_delay_ms(300);
			}
			 if (Mtemp > Mtlim && Mvolt > Mvlim) {	// temp < 20C and voltage > 12V, then green flashes
					PORTB &= ~(1 << led_pin2);		// ~GREEN  =1
					PORTB &= ~(1 << led_pin1);		// RED =0 : ADC STARTS
					_delay_ms(300);
					
					PORTB |= (1 << led_pin2);		// ~GREEN =0
					_delay_ms(300);
			} 

			output(serial_direction, serial_pin_out);
			put_char(&serial_port, serial_pin_out, Mtemp);	// ADC result sent to MainB as certain periods
						
			input(serial_direction, serial_pin_out);		// Reads MainB commands
		}
	return (0);
}