/*
 * Spinaci_modul_v2.c
 *
 * Created: 1.3.2012 16:25:54
 *  Author: JIRKO
 */ 

#include <avr/io.h>
#include <avr/interrupt.h>		// Prerusenia
#include <string.h>				// praca so stringom
#include <avr/eeprom.h>			// pracas s eeprom
#include <stdio.h>				// sprintf
#include <util/delay.h>	

#include "deff_eeprom_lib.h"	// Definicia premennych a makier pre pracu s EEProm
#include "deff_packet_lib.h"	// Definicia konstant a makier, struktur pre pracu s packetom 
#include "deff_spinaci_modul_lib.h"		// Definicia vseobecnych konstant a makier pouzitich v projekte
#include "RS485_lib.h"			// kniznica pre riadenie zbernice RS485
#include "Spinaci_modul_IO.h"	// Kniznica pre pracu s vystupmy/vstupmy zariadenia (posuvnymi reg. 4094)


//***************************************************************************************************
//****************   Definicia globalnych premennych   ***********************************************

//--------------------------------------------------------------------------------------------------


//***************************************************************************************************
//************************************   Prerusenia   ***********************************************
// prerusenie od Timer 0 200us
ISR(TIMER0_OVF_vect)				// prerusenie kazdich 200us
{									// prerusenie pri preteceni
	SET_TCNT0;					// prerusenie T0 za 200us
	I_TIMER0_RS485();				// funkcia sa vola pri viprsani casovaca TIMER 0 zabespeceuje detkciu konca packetu a prori kolizni cas 
}

// prerusenie od Timer 2 10ms
ISR(TIMER2_OVF_vect)
{
	I_Timer2_tResetButton();			// funkcia v casovaci TIMER2 pre casovanie resetu tlacitiek
	I_Timer2_tCheckOutputs();			// funkcia v casovaci TIMER2 pre casovanie kontroly vystupov ci sa spravne nastavili
}
	
// prerusenie pri vyprazneni registru UDR
ISR(USART_UDRE_vect)
{					
	I_USART_UDRE_vect();				// funkcia sa vola pri vyprazdneni UDR a zabespecuje odosielanie dat
}	

	// prerusenie pri dokonceni vysielania
ISR(USART_TXC_vect)
{
	I_USART_TXC_vect();
}

// prerusenie ked USART prime byte
ISR(USART_RXC_vect)
{	
	I_USART_RXC_vect();				// funkcia sa vola pri priati byte a zabespecuje priem dat
}	

//--------------------------------------------------------------------------------------------------

int main(void)
{
	//****************   definicia premennych  ***********************************************

		uint8_t		actual_settings[4];		// aktualne nastavenie vysotupov
		
	//--------------------------------------------------------------------------------------------------
	
	//****************   Inicializacia globalnych premenych  ***********************************************
	//save_master_ID(1);
	//save_my_ID(2);			// prvotne ulozenie ID	
	init_packet_lib();					// inicializacia kniznice packet_lib
	init_spinaci_modul_IO();			// inicializacia kniznice
	
	//****************   Nastavenia portov   ***********************************************

	DDRB=	0x00;		// Port B je cely ako vstup 
	sbi(DDRB,0);			// okrem PB0 Vystup OE
	PORTB=	0xff;		// Port B ma vsade Pullup 
	
	DDRC=	0x00;		// Port C je cely ako vstup 
	PORTC=	0xff;		// Port C ma vsade Pullup 
	
	PORTD=	0b00000011;
	//PORTD=	0b00000001;
	DDRD=	0b11111110;

	OE_1;				// zapnem vystupy obvodov 4094
	

	//--------------------------------------------------------------------------------------------------
	
	//****************   Nastavenia USARTU   ***********************************************
				
	RS485_init();
	
	//--------------------------------------------------------------------------------------------------
	
	////****************   Nastavenia Casovaca2 na 10ms  ***********************************************
	//
	//nastavenie C2			pre kristal 7.3728MHz
	TCCR2= 0b00000101;			//rezim normalny s preddelickou /1024
	TIMSK= TIMSK|(1<<TOIE2);			//povolene prerusenie pri preteceni
	TCNT2= 0xb8;				//prerusenie kazdich 10ms
	
	//--------------------------------------------------------------------------------------------------

	actual_settings[0]= 0x00;
	actual_settings[1]= 0x00;
	actual_settings[2]= 0x00;
	set_ouputs(actual_settings);							// nastavim defaltne vystupi
	
	LED_OFF;	
	sei();						//Vsetky prerusenia povolene
	uint8_t temp;  
	
	uint8_t		temp_buff_in_packet[MAX_PACKET_LENGHT];		// sem sa uklada priaty paket aby sa uvolnil rx buffer
	uint8_t		temp_buff_out_packet[MAX_PACKET_LENGHT];	// tu sa vytvara TX packet 
	
	t_packet	*temp_in_packet;				// vsobecna definicia packetu 
	t_packet	*temp_out_packet;
			
	temp_in_packet= (t_packet *)temp_buff_in_packet;
	temp_out_packet= (t_packet *)temp_buff_out_packet;

    while(1)
    {
		if( isPacketAccepted( temp_buff_in_packet ) == 0 )		// bol priaty packet 
		{
			if ( temp_in_packet->dest_ID == BROCAST_PACKET )	// spracovanie brocastoveho packetu
			{
				LED_NEG;
				switch(temp_in_packet->comand)
				{
					case  C_WISO_PACKET:			// who is online vo verzii ci som online						
						temp= snprintf((char *)temp_out_packet->data, PACKET_DATA_MAX_LENGHT, "Spinaci modul Online");					
						fill_out_packet( temp_out_packet, temp_in_packet->sorce_ID, my_ID(), (PACKET_LENGHT_WITHAUT_DATA + temp + 1), temp_in_packet->packet_number, C_OK_PACKET, temp_in_packet->comand );
						send_packet(temp_out_packet);			//odosielam packet ako odpoved packet _ok_packet
						break;
						
					case C_SET_ID_PACKET:			// nastav nove ID zariadenia id je v data
						temp= snprintf((char *)temp_out_packet->data, PACKET_DATA_MAX_LENGHT, "Zmena ID z %d na %d", temp_in_packet->dest_ID, temp_in_packet->data[0]);	// generujem spravu do data					
						save_my_ID(temp_in_packet->data[0]);					// menim ID
						fill_out_packet( temp_out_packet, temp_in_packet->sorce_ID, my_ID(), (PACKET_LENGHT_WITHAUT_DATA + temp), temp_in_packet->packet_number, C_OK_PACKET, temp_in_packet->comand);		// odpovedam uz s novym ID
						send_packet(temp_out_packet);			//odosielam packet ako odpoved packet _ok_packet	
						break;
						
					//default:						// neznamy packet
					/////! neznami packet ignorujem 	
						//break;
				}			
			}
			if ( temp_in_packet->dest_ID == my_ID() )	// spracovenie normalneho packetu
			{
				LED_NEG;
				switch(temp_in_packet->comand)
				{
					case C_SET_OUTPUTS_PACKET:			// nastav vystupy na pozadovanu hodnotu	
						temp= snprintf((char *)temp_out_packet->data, PACKET_DATA_MAX_LENGHT, "SP modul Request accepted");										
						fill_out_packet( temp_out_packet, temp_in_packet->sorce_ID, my_ID(), (PACKET_LENGHT_WITHAUT_DATA + temp + 1), temp_in_packet->packet_number, C_OK_PACKET, temp_in_packet->comand);
						if ( temp_in_packet->sign == 0 )		// je to pre zmenu aktualneho nastavenia 
						{
							memcpy(actual_settings, temp_in_packet->data, LENGHT_OUTPUTS_DATA);		// kopirujem pozadovane stavi do actual_settings
							set_ouputs(actual_settings);//send_data_4094(actual_settings);
				// nulujem lebo nefunguje spatna vazba
				actual_settings[0]= 0;
						} 
						else
						{
							eeprom_update_block((void*)temp_in_packet->data, (void*)(((temp_in_packet->sign - 1)*3)+EEADR_SET_OUTPUTS), LENGHT_OUTPUTS_DATA); // zapisem do eeprom EEADR_SEL_OUTPUTS(temp_in_packet->sign - 1)
						}
						send_packet(temp_out_packet);			//odosielam packet ako odpoved packet t_ok_packet
						break;
						
					case C_SEL_SETTINGS_PACKET:			// nastav vystupy na pozadovanu hodnotu	
						temp= snprintf((char *)temp_out_packet->data, PACKET_DATA_MAX_LENGHT, "SP modul set accepted");										
						fill_out_packet( temp_out_packet, temp_in_packet->sorce_ID, my_ID(), (PACKET_LENGHT_WITHAUT_DATA + temp + 1), temp_in_packet->packet_number, C_OK_PACKET, temp_in_packet->comand);
						eeprom_read_block((void*)actual_settings, (const void*)(((temp_in_packet->sign - 1)*3)+EEADR_SET_OUTPUTS), LENGHT_OUTPUTS_DATA);
							set_ouputs(actual_settings);//send_data_4094(actual_settings);
				// nulujem lebo nefunguje spatna vazba
				actual_settings[0]= 0;
						send_packet(temp_out_packet);			//odosielam packet ako odpoved packet t_ok_packet	
						break;
						
					case C_SEND_DEVICE_SETTINGS:		// dotaz na aktualny stav 
						fill_out_packet( temp_out_packet, temp_in_packet->sorce_ID, my_ID(), (PACKET_LENGHT_WITHAUT_DATA + (4*LENGHT_OUTPUTS_DATA)), temp_in_packet->packet_number, C_MY_SETTINGS, temp_in_packet->comand);

						memcpy(temp_out_packet->data, actual_settings, LENGHT_OUTPUTS_DATA);
						eeprom_read_block((temp_out_packet->data + LENGHT_OUTPUTS_DATA), (uint8_t*)EEADR_SEL_OUTPUTS(0), LENGHT_OUTPUTS_DATA);
						eeprom_read_block((temp_out_packet->data + (LENGHT_OUTPUTS_DATA*2)), (uint8_t*)EEADR_SEL_OUTPUTS(1), LENGHT_OUTPUTS_DATA);
						eeprom_read_block((temp_out_packet->data + (LENGHT_OUTPUTS_DATA*3)), (uint8_t*)EEADR_SEL_OUTPUTS(2), LENGHT_OUTPUTS_DATA);
					///!temp_out_packet->data[0]= read_inputs();		// kopirujem ozajstny stav na vstupoch
				// pri log jedna sa vytvori impulz a log 1 sa nuluje 
				//	temp_out_packet->data[0]= 0;
						send_packet(temp_out_packet);			//odosielam packet ako odpoved packet _my_stat_packet
						break;
						
					case C_SET_ID_PACKET:			// nastav nove ID zariadenia id je v data
						temp= snprintf((char *)temp_out_packet->data, PACKET_DATA_MAX_LENGHT, "Zmena ID z %d na %d", temp_in_packet->dest_ID, temp_in_packet->data[0]);	// generujem spravu do data					
						save_my_ID(temp_in_packet->data[0]);					// menim ID
						fill_out_packet( temp_out_packet, temp_in_packet->sorce_ID, my_ID(), (PACKET_LENGHT_WITHAUT_DATA + temp), temp_in_packet->packet_number, C_OK_PACKET, temp_in_packet->comand);		// odpovedam uz s novym ID
						send_packet(temp_out_packet);			//odosielam packet ako odpoved packet _ok_packet	
						break;
					
					case C_SET_MASTER_ID_PACKET:		// nastav masterID pre dane zariadenie
						temp= snprintf((char *)temp_out_packet->data, PACKET_DATA_MAX_LENGHT, "Zmena master ID prebehla uspesne");					
						save_master_ID(temp_in_packet->data[0]);					// menim ID
						fill_out_packet( temp_out_packet, temp_in_packet->sorce_ID, my_ID(), (PACKET_LENGHT_WITHAUT_DATA + temp), temp_in_packet->packet_number, C_OK_PACKET, temp_in_packet->comand);					// odpovedam uz s novym ID
						send_packet(temp_out_packet);			//odosielam packet ako odpoved packet 	_ok_packet
						break;
						
					case  C_WISO_PACKET:			// who is online vo verzii ci som online						
						temp= snprintf((char *)temp_out_packet->data, PACKET_DATA_MAX_LENGHT, "Spinaci modul Online");					
						fill_out_packet( temp_out_packet, temp_in_packet->sorce_ID, my_ID(), (PACKET_LENGHT_WITHAUT_DATA + temp + 1), temp_in_packet->packet_number, C_OK_PACKET, my_ID());
						send_packet(temp_out_packet);			//odosielam packet ako odpoved packet _ok_packet
						break;
						
					default:						// ine packety
													// neznamy packet odoslem err packet					
							temp= snprintf((char *)temp_out_packet->data, PACKET_DATA_MAX_LENGHT, "Neznamy packet\n\r");					
							fill_out_packet( temp_out_packet, temp_in_packet->sorce_ID, my_ID(), (PACKET_LENGHT_WITHAUT_DATA + temp + 1), temp_in_packet->packet_number, C_NACK_ERR_PACKET, my_ID());
							send_packet(temp_out_packet);			//odosielam packet ako odpoved packet _nack_err_packet
						break;
				}				
			}
		}	
		
		// *************************************************************************************************
		// ********** Pre kniznicu "Spinnaci_modul_IO.h" pre pracu s vystupmy spinacieho modulu ************	
		
		///! spravit niake opakovanie pokusov zapnut	
		I_check_Spininaci_modul(actual_settings);	// kontrola ci treba resetovat tlacitka alebo skontrolovat vystupy
		
		//--------------------------------------------------------------------------------------------------
		
		// *************************************************************************************************
		// ************* Sparava odosielania RS485 *********************************************************
		
		I_check_TX_RS485();
		//--------------------------------------------------------------------------------------------------
		
    }
}