
// Fab_MainB_F1.c  This code is edited by Yrjo L. for Attiny44 use 30.5.2017
// Voltage ADC + LEDs  + IO ; receive periodicly temp adc results from Node and send voltage adc results back. Sleeps if not used.
// Wake up by pin change (TX). Controls pump and blower. Test: voltage level ok, communication ?? version 6.6.2017
// ====================================
//                ATtiny44						ISP
//           VCC--+ o      +--GND				MISO---+5V
//GREEN LED PB0 --+        +--PA0 TX 			SCK ---MOSI
//  RED LED PB1 --+        +--PA1 RX  Wake		RST ---GND
//	   	  RESET --+        +--PA2 M2
// 	   INT0 PB2 --+        +--PA3 M1
//    ADC7  PA7 --+        +--SCK 
//         MOSI --+--------+--MISO
// ====================================
#define F_CPU 8000000UL // 1 MHz (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 100  // bit delay for 9600 with overhead: MainB 100, 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_delay() _delay_ms(2000) // LED flash delay

#define led_pin1 PB1			// Define the I/O port to be used for the RED LED.
#define led_pin2 PB0			// Define the I/O port to be used for the GREEN LED.
#define MOTOR1 PA3				// Define the I/O port to be used for the MOTOR 1.
#define MOTOR2 PA2				// Define the I/O port to be used for the MOTOR 2.
#define button PA1				// Wake up pin = RX 
#define serial_port PORTA	
#define serial_direction DDRA
#define serial_pins PINA	
#define serial_pin_in (1 << PA1)   // RX
#define serial_pin_out (1 << PA0)  // TX

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

ISR(PCINT0_vect) {					
	if (!(PINA & (1 << button))) {	//Checks Pin PA1 for value change 
	} }

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_INT()				// 8-bit resolution, set ADLAR to 1 to enable the Left-shift result (only bits ADC9..ADC2)
{							// then, only reading ADCH is sufficient for 8-bit results (256 values)
	ADCSRB =	(1 << ADLAR);		// left shift result
	ADCSRA =  (1 << ADEN)  |     // Enable ADC
	(1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);			// Set prescaler to 128. Eg. 8 MHz/128 = 62.5 Hz sample rate.     
	
	GIMSK |= (1 << PCIE0);  // Pin change interrupt mode
	PCMSK0 |= (1 << PCINT1); // Data from RX pin wakes up
	sei(); 
}

int main(void)			// This MainB_F1 code is very similar as Node_F1 code
{						
int Mtemp, Mvolt, Mtlim, Mvlim;
int Sleep_count;
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);
input(serial_direction, serial_pin_out);
// LED Port directions output
DDRB |= (1 << led_pin1);	// RED 
DDRB |= (1 << led_pin2);	// GREEN
// LEDs  lights
PORTB |= (1 << led_pin1);  // RED =1 
PORTB |= (1 << led_pin2);  // GREEN =1
// Motor Port direction output
DDRA |= (1 << MOTOR1);	
DDRA |= (1 << MOTOR2);	

initADC_INT();
Mtlim = 114; Mvlim = 205; Sleep_count = 1;

	_delay_ms(50);  // Short delay here ensures Node_F1 start first.

	while(1) {
	get_char(&serial_pins, serial_pin_in, &chr); //  This node gets temp or sleep info
	Mtemp = chr;

	ADMUX |=  (1 << MUX2) | (1 << MUX1) | (1 << MUX0);      // use ADC7 (PA7),  and |= this (MUX =000111b) = volt
	ADCSRA |= (1 << ADSC);      // start ADC measurement = VOLTAGE

	while (ADCSRA & (1 << ADSC) ); // wait till conversion complete
	Mvolt = ADCH;

	_delay_ms(50);
	
	if (Mtemp < Mtlim && Mvolt > Mvlim) {	// temp > 20C and voltage > 12V, then green light on
		PORTB |= (1 << led_pin2);			// GREEN =1
		PORTB &= ~(1 << led_pin1);			// RED =0 
		_delay_ms(300);						// pump and blower stop
				PORTA &= ~(1 << MOTOR1);
				PORTA &= ~(1 << MOTOR2);
		Sleep_count = 1;
	}
	if (Mvolt <= Mvlim) {					// voltage < 12V, then red light flashes
		PORTB |= (1 << led_pin1);			// RED =1
		PORTB &= ~(1 << led_pin2);			// GREEN =0
		_delay_ms(300);						// pump and blower stop
			
		PORTB &= ~(1 << led_pin1);			// RED =0 
		_delay_ms(300);
				PORTA &= ~(1 << MOTOR1);
				PORTA &= ~(1 << MOTOR2);
		Sleep_count++;

	}
	if (Mtemp > Mtlim && Mvolt > Mvlim) {	// temp < 20C and voltage > 12V, then green flashes
		PORTB &= ~(1 << led_pin1);			// RED =0  
		PORTB |= (1 << led_pin2);			// GREEN  =1
		_delay_ms(300);						// pump and blower work
		
		PORTA |= (1 << MOTOR1);
		PORTA |= (1 << MOTOR2);

		PORTB &= ~(1 << led_pin2);			// GREEN =0
		_delay_ms(300);
		Sleep_count = 1;
	}
	if (Sleep_count > 15) {		//  Node goto sleep. 
		//		PORTB &= ~(1 << led_pin2);			// GREEN =0  Why these ??
		//		PORTB &= ~(1 << led_pin1);			// RED =0
		output(serial_direction, serial_pin_out);
		put_char(&serial_port, serial_pin_out, 255);
		_delay_ms(300);  // wait, Node sleeps first
			
				sleep_enable();
				sleep_mode();
				Sleep_count = 1;
	}

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




