/*	Sample program for Olimex AVR-IO with AT90S2313 processor
 *	Using Hyper Terminal for input commands as follow:
 *	1) W - followed by 4 binary signes (if input less than 4 signs, adds a zeros)
 *	effect: Turn ON/OFF the relays respective the signes
 *	2) w - followed by 1 hex sign (if no input sign, adds a zero)
 *	effect: TURN ON/OFF the relays respective sign converted in binary
 *	3) R - effect: output 4 binary signs depending on respective INs
 *	4) r - effect: output 1 hex sign depending on respective INs
 *	5) O: Set all relays ON
 *	6) C: Set all relays OFF
 *	7) S: Switch states of relays depending on respective INs until next S
 *	Compile with AVRStudio+WinAVR (gcc version 3.4.6)
 */

#define __AVR_AT90S2313__	1
#define OSCSPEED	10000000	//Hz

#include "avr/io.h"

unsigned char Action = 0;

const char WText[] = "Welcome"; 
const char EText[] = "Error!";

/************************ P O R T   I N I T I A L I Z A T I O N **************************/

void PORT_Init()
{
	PORTB = 0b00000000;
	DDRB  = 0b00001111;		//set Relays(O1-O4) as output (Bit0:3 = 1)

	PORTD = 0b00000000;
	DDRD  = 0b00000010;		//set TX as output (Bit1 = 1)
}

/*************************************** U A R T *****************************************/

void UART_Init(uint32_t Baud)
{
	//calculate BaudRate (Datasheet page 44)
	unsigned char BaudRate = OSCSPEED / (16 * Baud) - 1;
	UBRR = BaudRate;		//set BaudRate into register
	UCR  = UCR | 0b00011000;//enable Transmitter (Bit3 = 1) and Receiver (Bit4 = 1)
}


void UART_Transmit(unsigned char Data)
{
	while (!(USR & 0b00100000));
	UDR = Data;
}

unsigned char UART_Receive()
{
	if (USR & 0b10000000)
		return UDR;
	else
		return 0;
}

/*************************************** P R I N T *****************************************/

//print Welcome/Error text
//Welcome message:	Temp = 1
//Error message:	Temp = 0
void Print(unsigned char Temp)
{
	unsigned char i=0, T=1;
	UART_Transmit(13);
	UART_Transmit(10);
	while (T)
	{
		if (Temp)
			T = WText[i];
		else
			T = EText[i];

		UART_Transmit(T);
		i++;
	}
	UART_Transmit(13);
	UART_Transmit(10);
}

/************************************** A C T I O N S **************************************/

void Write(unsigned char Temp)
{
	unsigned char Br, Arr[5], T = 0, Bl = 1, T1 = 48;	//T1 = '0'
	for (Br=0; Br<5; Br++) Arr[Br] = 48;	//null the elements of the array
	Br = 0;
	switch (Temp)
	{
		case 1:		//input - 'W'; follow input in binary format
			while ((T!=13) & (Br<5) & Bl)
			//while	(NO ENTER (T!=13), Length is less than 5 signs (Br<5) and no signs except '0' or '1' (Bl = 1)
			{
				T = UART_Receive();
				if ((T!=0) & (T!=13) & Bl)
				{
					if ((T!=48) & (T!=49)) Bl = 0;
					Arr[Br] = T;
					Br++;					
				}
			}

			//check for incorrect input (Length is 5 signs or there is a sign except '0' or '1')
			if ((Br == 5) | (!Bl)) Print(0);
			else
				{
					T=0;
					//calculate T depending on states of respective relays
					for (Br=0; Br<4; Br++) T = T | Arr[Br]<<(3-Br);
					PORTB = T;
				}
		break;
		case 2:		//input - 'w'; follow input in hex format
			while ((T!=13) & (Br<2) & Bl)			
			//while (NO ENTER (T!=13), length is less than 2 signs(Br<2) and no signs except 0-9 and A-F (Bl=1)
			{
				T = UART_Receive();
				if ((T!=0) & (T!=13) & Bl)
				{
					Br++;
					T1 = T;		//keeping value of T (T has dynamic value (ENTER))
					if ((T1 < 48) | ((T1>57) & (T1<65)) | (T1 > 70)) //if T1(T) isn't 0-9 or A-F
						Bl = 0;
				}
			}
			T = T1;			//T gets its value

			//check for incorrect input (Length is 2 signs or there is a sign except 0-9 or A-F)
			if ((Br == 2) | (!Bl)) Print(0);		
			else
				{
					//convert T (sign --> hex number)
					if (T<58)		//T [0..9] (48 - '0'; 57 - '9')
						T = T - 48;
					else			//T [10..15] (65 - 'A'; 70 - 'F')
						T = T - 55;

					PORTB = T;
				}
		break;
	}
}

void Read(unsigned char Temp)
{
	unsigned char T=0;
	switch (Temp)
	{
		case 1:		//Input - 'R'
			if (!(PIND & 0b00000100))
				UART_Transmit('1');
			else
				UART_Transmit('0');
			if (!(PIND & 0b00001000))
				UART_Transmit('1');
			else
				UART_Transmit('0');
			if (!(PIND & 0b00100000))
				UART_Transmit('1');
			else
				UART_Transmit('0');
			if (!(PIND & 0b01000000))
				UART_Transmit('1');
			else
				UART_Transmit('0');
		break;
		case 2:		//Input - 'r'
			if (!(PIND & 0b00000100)) T = T + 8;
			if (!(PIND & 0b00001000)) T = T + 4;
			if (!(PIND & 0b00100000)) T = T + 2;
			if (!(PIND & 0b01000000)) T = T + 1;

			//transmit T: int --> char
			if (T < 10)			//if T in [0..9] (0 - 48; 9 - 57)
				T = T + 48;
			else
				T = T + 55;		//if T in [10..15] (A - 65; F - 70)

			UART_Transmit(T);	//output value of T
		break;
	}	
}

void Control(unsigned char Temp)
{
	unsigned char T=0;
	switch (Temp)
	{
		case 1:		//Input - 'C'
			PORTB = 0b00000000;
		break;
		case 2:		//Input - 'O'
			PORTB = 0b00001111;
		break;
		case 3:		//Input - 'S' 
					//turn on/off led on relays depending on input PIN
					//until input of 'S'
			while (T != 'S')
			{
				T = UART_Receive();
				PORTB =	  (!(PIND & 0b00000100)) * 8 
						+ (!(PIND & 0b00001000)) * 4 
						+ (!(PIND & 0b00100000)) * 2 
						+ (!(PIND & 0b01000000));
			}
			PORTB = 0b00000000;		//turn off all relays
		break;
	}
}

/************************************* M A I N *******************************************/

int main()
{
	PORT_Init();
	UART_Init(9600);
	while (1)
	{
		Print(1);
		Action = 0;
		while (!(Action)) Action = UART_Receive();

		/*
		switch (Action)
		{
			case 'W':	Write(1); break;
			case 'w':	Write(2); break;
			case 'R':	Read(1); break;
			case 'r':	Read(2); break;
			case 'C':	Control(1); break;
			case 'O':	Control(2); break;
			case 'S':	Control(3); break;
		}
		*/

		if (Action == 'W') Write(1);
		if (Action == 'w') Write(2);
		if (Action == 'R') Read(1);
		if (Action == 'r') Read(2);
		if (Action == 'C') Control(1);
		if (Action == 'O') Control(2);
		if (Action == 'S') Control(3);
	}
}
