/*
 * Nastavení_PAO_firmware.cpp
 *
 * Created: 12.9.2012 21:58:22
 *  Author: Josef Sobotka
 */ 
//#include "prog1_constants.h" //pro první verzi zařízení
#include "prog2_constants.h"   //pro druhou verzi zařízení

 
#define F_CPU 3686400
#define TIME_TO_OP_US 10 

#define SETBIT(ADDRESS,BIT) (ADDRESS |= (1<<BIT))
#define SETBITS(ADDRESS,BITs,VALUE) (ADDRESS |= (VALUE<<BITs))
#define CLEARBIT(ADDRESS,BIT) (ADDRESS &= ~(1<<BIT))
#define FLIPBIT(ADDRESS,BIT) (ADDRESS ^= (1<<BIT))
#define CHECKBIT(ADDRESS,BIT) (ADDRESS & (1<<BIT))
#define WRITEBIT(RADDRESS,RBIT,WADDRESS,WBIT) (CHECKBIT(RADDRESS,RBIT) ? SETBIT(WADDRESS,WBIT) : CLEARBIT(WADDRESS,WBIT))

#include <avr/interrupt.h>
#include <util/delay.h>
#include <avr/eeprom.h>
#include <avr/pgmspace.h>
#include <avr/wdt.h>
#include <stdint.h>
#include <stdbool.h>
#include <avr/iom88.h>

void SetDDRregs(void){
	
	SETBIT(DDRC,0);
	SETBIT(DDRC,1);
	SETBIT(DDRC,2);
	SETBIT(DDRC,3);
	SETBIT(DDRC,4);
	SETBIT(DDRC,5);
	
	SETBIT(DDRB,0);
	SETBIT(DDRB,1);
	
	SETBIT(DDRD,2);
	SETBIT(DDRD,3);
	SETBIT(DDRD,4);
	SETBIT(DDRD,5);
	SETBIT(DDRD,6);
	SETBIT(DDRD,7);
	
	SETBIT(DDRB,2);

}

//Deklarace proměnných pro USB i naše použití

enum CommandTypes{
	
CurcuitEcho = 1,
ReadByteFromEEPROM = 2,
WriteByteToEEPROM = 3,
ProgrammPAOFromRAM = 4,
WriteByteToRAM = 5,
ReadByteFromRAM = 6


};
	
enum MsgReturns
{
	msgOK = 1,
    msgErr = 2	        
};

uint8_t RecieveBuffer[5];
uint8_t TransmitBuffer[5];
uint8_t DataByteStorage[14];
int MagicCounter;
bool RecieveErr;


//Fce pro programování obvodu

void SetAdressRegistersToProgram(uint8_t adresa){
	
	CLEARBIT(ADR0P,ADR0B);
	CLEARBIT(ADR1P,ADR1B);
	CLEARBIT(ADR2P,ADR2B);
	CLEARBIT(ADR3P,ADR3B);
	
	if((adresa & 0x01) == 0x01){
	SETBIT(ADR0P,ADR0B);
	}
	
	if((adresa & 0x02) == 0x02){
	SETBIT(ADR1P,ADR1B);
	}
	
	if((adresa & 0x04) == 0x04){
	SETBIT(ADR2P,ADR2B);
	}
	
	if((adresa & 0x08) == 0x08){
	SETBIT(ADR3P,ADR3B);
	}
	
	
}




void SetDataValuesToProgramm(uint8_t obsah){
	
	CLEARBIT(DATA0P,DATA0B);
	CLEARBIT(DATA1P,DATA1B);
	CLEARBIT(DATA2P,DATA2B);
	CLEARBIT(DATA3P,DATA3B);
	CLEARBIT(DATA4P,DATA4B);
	CLEARBIT(DATA5P,DATA5B);
	CLEARBIT(DATA6P,DATA6B);
	CLEARBIT(DATA7P,DATA7B);

	
	if((obsah & 0x01) == 0x01){
	SETBIT(DATA0P,DATA0B);
	}
	
	if((obsah & 0x02) == 0x02){
	SETBIT(DATA1P,DATA1B);
	}
	
	if((obsah & 0x04) == 0x04){
	SETBIT(DATA2P,DATA2B);
	}
	
	if((obsah & 0x08) == 0x08){
	SETBIT(DATA3P,DATA3B);
	}
	
	if((obsah & 0x10) == 0x10){
	SETBIT(DATA4P,DATA4B);
	}
	
	if((obsah & 0x20) == 0x20){
	SETBIT(DATA5P,DATA5B);
	}
	
	if((obsah & 0x40) == 0x40){
	SETBIT(DATA6P,DATA6B);
	}
	
	if((obsah & 0x80) == 0x80){
	SETBIT(DATA7P,DATA7B);
	}
	
}


void PinToDiodeSignalization(bool value){
	
	if(value == true){
		SETBIT(DIODEP,DIODEB);
	}
	else{
		CLEARBIT(DIODEP,DIODEB);
	}
	
}


void PinToWriteSettigs(bool value){
	
	if(value == true){
	CLEARBIT(WNPP,WNPB);
	}
	else{
	SETBIT(WNPP,WNPB);
	}
	
}

void PinToReset(bool value){
	
	if(value == false){
		CLEARBIT(RESETP,RESETB);
	}
	else{
		SETBIT(RESETP,RESETB);
	}
	
}

//Fce pro naše použití s komunikací přes usb

uint8_t FCurcuitEcho(uint8_t ValueToBeCopyed){
	
	return ValueToBeCopyed;
	
}

uint8_t FWriteByteToRAM(uint8_t index, uint8_t data){
	
	DataByteStorage[index-1] = data;
	return DataByteStorage[index-1];
	
}

uint8_t FWriteByteToEEPROM(uint8_t hodnota_adresy, uint8_t data){

eeprom_write_byte(hodnota_adresy-1,data);
return (eeprom_read_byte(hodnota_adresy-1));
	
}

uint8_t FReadByteFromEEPROM(uint8_t hodnota_adresy){

	return (eeprom_read_byte(hodnota_adresy-1));
}

uint8_t FReadByteFromRAM(uint8_t index){

	return DataByteStorage[index-1];
}


bool FProgrammPAO(){
	
		PinToReset(true);
		_delay_ms(TIME_TO_OP_US);
		PinToReset(false);
		_delay_ms(TIME_TO_OP_US);
		_delay_ms(TIME_TO_OP_US);
	
	
	for(uint8_t i=1; i<=14; i++){
		
		if((i==5)||(i==6)||(i==8)||(i==9)||(i==10)||(i==14)){
		
		SetAdressRegistersToProgram(i-1);
		_delay_ms(TIME_TO_OP_US);
		SetDataValuesToProgramm(DataByteStorage[i-1]);
		_delay_ms(TIME_TO_OP_US);
		PinToWriteSettigs(true);
		_delay_ms(TIME_TO_OP_US);
		PinToWriteSettigs(false);
		_delay_ms(TIME_TO_OP_US);
		
		}
	}
	
		SetDataValuesToProgramm(0x00);
		SetAdressRegistersToProgram(0x00);
	
	return true;
}

void InitAfterStartuC(void){
	
	cekej(); //1 sekundu pro ustálení napájení kolem 12V
	//Nebudem nic zapisovat
	SETBIT(WNPP,WNPB);
	//A dostaň se z možného resetu
	CLEARBIT(RESETP,RESETB);
	
	PinToReset(true);
	_delay_ms(TIME_TO_OP_US);
	PinToReset(false);
	
	//Nakopíruj Data z EEPROMky do pracovního pole
	
	for(uint8_t i=0; i<14; i++){
		DataByteStorage[i] = eeprom_read_byte(i);
		
	}
	
	
	FProgrammPAO();

		
}


void USART_Init( unsigned char ubrrl, unsigned char ubrrh)
{
	UBRR0H = ubrrh;
	UBRR0L = ubrrl;
	/* Enable receiver and transmitter */
	UCSR0B = (1<<RXEN0)|(1<<TXEN0);
	/* Set frame format: 8data, 2stop bit */
	UCSR0C = (1<<USBS0)|(3<<UCSZ00)|(1<<UPM01);
	
}

void USART_Transmit( unsigned char data )
{
	/* Wait for empty transmit buffer */
	while ( !CHECKBIT(UCSR0A,UDRE0) )
	;
	/* Put data into buffer, sends the data */
	UDR0 = data;
}

unsigned char USART_Receive( void )
{
	/* Wait for data to be received */
	while ( !(UCSR0A & (1<<RXC0)) )
	;
	/* Get and return received data from buffer */
	return UDR0;
}

void cekej(void)
{
	
	//1 sekundu čekáme pro ustálení napájení kolem 12V
		
		_delay_ms(100);
		_delay_ms(100);
		_delay_ms(100);
		_delay_ms(100);
		_delay_ms(100);
		_delay_ms(100);
		_delay_ms(100);
		_delay_ms(100);
		_delay_ms(100);
		_delay_ms(100);
		
			
}


void SerialCommunication(void){
	
	RecieveBuffer[0] = 0;
	RecieveBuffer[1] = 0;
	RecieveBuffer[2] = 0;
	RecieveBuffer[3] = 0;
	RecieveBuffer[4] = 0;

	RecieveErr = false;
	
	TransmitBuffer[0] = 0;
	TransmitBuffer[1] = 0;
	TransmitBuffer[2] = 0;
	TransmitBuffer[3] = 0;
	TransmitBuffer[4] = 0;
	
	
	for(MagicCounter=0; MagicCounter<5; MagicCounter++)
	{
		
		RecieveBuffer[MagicCounter] = USART_Receive();

		if(CHECKBIT(UCSR0A,FE0)||CHECKBIT(UCSR0A,UPE0)){
			
			RecieveErr=true;
			
		}
		
	}
	
	PinToDiodeSignalization(true);
	
	//SetAdressRegistersToProgram(0xFF);
	
	TransmitBuffer[0] = 0xFF;
	TransmitBuffer[4] = 0xFF;
	
	
	if(RecieveErr == true){
	
	TransmitBuffer[1] = (uint8_t)msgErr;
	RecieveErr=false;
	
	}
	else{
		
		TransmitBuffer[1] = (uint8_t)msgOK;
		
	}
	
	//provedeni akci podle obdrzeneho requestu
	
	if(RecieveBuffer[1] == (uint8_t)CurcuitEcho){
		
		TransmitBuffer[2] = FCurcuitEcho(RecieveBuffer[3]);
		
	}
	
	if(RecieveBuffer[1] == (uint8_t)ProgrammPAOFromRAM){
		
		FProgrammPAO();
		TransmitBuffer[2] = 0xEE;
		
	}
	
	if(RecieveBuffer[1] == (uint8_t)ReadByteFromEEPROM){
		
		// buffer[0]=MSGOK, buffer[1]=DATA,buffer[2] = ~buffer[1];
		//if ((buffer[2] == ~buffer[1]) && (buffer[3] == (buffer[1] ^ buffer[2])))
		TransmitBuffer[2] = FReadByteFromEEPROM(RecieveBuffer[2]);
		TransmitBuffer[3] = ~TransmitBuffer[2];
		
	}
	
	if(RecieveBuffer[1] == (uint8_t)ReadByteFromRAM){
		

		// buffer[0]=MSGOK, buffer[1]=DATA,buffer[2] = ~buffer[1];
		// if ((buffer[2] == ~buffer[1])&&(buffer[3] == (buffer[1]^buffer[2])))
		TransmitBuffer[2] = FReadByteFromRAM(RecieveBuffer[2]);
		TransmitBuffer[3] = ~TransmitBuffer[2];
	}
	
	if(RecieveBuffer[1] == (uint8_t)WriteByteToEEPROM){
		
		// buffer[2] = ADRESA, buffer[1]=DATA

		TransmitBuffer[2] = FWriteByteToEEPROM(RecieveBuffer[2],RecieveBuffer[3]);
		TransmitBuffer[3] = RecieveBuffer[2];
	}
	
	if(RecieveBuffer[1] == (uint8_t)WriteByteToRAM){
		
		
		// buffer[2] = INDEX, buffer[1]=DATA

		TransmitBuffer[2] = FWriteByteToRAM(RecieveBuffer[2],RecieveBuffer[3]);
		TransmitBuffer[3] = RecieveBuffer[2];
	}

	for(MagicCounter=0; MagicCounter<5;MagicCounter++){
		USART_Transmit(TransmitBuffer[MagicCounter]);
	}
				
	//SetAdressRegistersToProgram(0xFF);
	PinToDiodeSignalization(false);
}


int main(void){
	
	
	//USART_Init(225,4); //200bps
	//USART_Init(243,1); //500bps
	USART_Init(230,0); //1000bps
	
	SetDDRregs();
	InitAfterStartuC();
	
	while (1){
		
	SerialCommunication();
	
	}
	return 0;
}