#include "packet.h"
#include "mybool.h"
#include <stdio.h>				// sprintf

/* FreeRTOS includes */
#include "FreeRTOS.h"
#include "timers.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
#include "priorities.h"

// vsetko pre pracu s displejom
#include "grlib/grlib.h"
#include "grlib/widget.h"

#include "MainTask.h"
#include "com_RS485.h"

#include "displayScreens/LEDscreen.h"
#include "displayScreens/SMscreen.h"
#include "displayScreens/MenuScreen.h"		// conzola
#include "displayScreens/MesageWindow.h"	// Mesage window

// definicia hlaviciek 
	xTaskHandle 	xHMainTask;		// handle tasku
	xQueueHandle	xQueueMainTask;	// handle fronty

// globalne premenne
	volatile unsigned char s_SPModulOnline;			// ak je nula alebo male cislo tak je asi online
	volatile unsigned char s_LEDModulOnline;		// ak je nula alebo male cislo tak je asi online
	volatile unsigned char NumScanConnectedDevice;	// pocet skenovani pripojenych zariadeni ak je 0 tak sa vypisuje na conzolu

// slucka tasku
void	MainTask( void *pvParameters )
{
	NumScanConnectedDevice= 0xff;
	s_SPModulOnline= 255;
	s_LEDModulOnline= 255;
	
	xTimerHandle xTimerScanConnectDevice;
	xTimerScanConnectDevice= xTimerCreate( "ScanConnectedDevice",  ( 1000 / portTICK_RATE_MS ), pdTRUE, 0, vTimerScanConnectDevice );	
	xTimerStart( xTimerScanConnectDevice, 100 );

	t_MainQueueStruct	Mesage;
	t_packet			*s_packet;
	s_packet= (t_packet *)Mesage.Data;

	for(;;)
	{
		if( xQueueReceive( xQueueMainTask, &Mesage, portMAX_DELAY ) )	// bol bola priata niaka sprava/packet treba ho spracovat	
		{

				// Sprava uloz nastavenia do spinacieho modulu mozem bit aktual alebo eeprom pre SPINACI MODUL
			if( Mesage.Mesage_ID == C_QUEUE_SM_CONFIG )			
			{													// pre Mesage.Data[0] == 0 je to nastavenie aktual
				SendMesageToRS485( C_QUEUE_TX_SEND_RQS, SPINACI_MODUL_ID, MY_ID, C_SET_OUTPUTS_PACKET, Mesage.Data[0], 3, (Mesage.Data + 1) );
				NewMasageToConsole("Sending request to SPm", 0);
			}
				// Sprava uloz nastavenia do LED modulu mozem bit aktual alebo eeprom PRE LED MODUL
			if( Mesage.Mesage_ID == C_QUEUE_LEDM_CONFIG )		
			{													// pre Mesage.Data[0] == 0 je to nastavenie aktual
				SendMesageToRS485( C_QUEUE_TX_SEND_RQS, LED_MODUL_ID, MY_ID, C_SET_OUTPUTS_PACKET, Mesage.Data[0], 8, (Mesage.Data + 1) );
				NewMasageToConsole("Sending request to LEDm", 0);
			}
				// nastav vystupy podla zvolenych settings alebo nastav demo	PRE LED MODUL
			if( Mesage.Mesage_ID == C_QUEUE_LEDM_SET )			
			{
				SendMesageToRS485( C_QUEUE_TX_SEND_RQS, LED_MODUL_ID, MY_ID, C_SEL_SETTINGS_PACKET, Mesage.Data[0], 0, 0 );
				NewMasageToConsole("Sending request to LEDm", 0);				
			}
				// nastav vystupy podla zvolenych settings pre SPINACI MODUL
			if( Mesage.Mesage_ID == C_QUEUE_SM_SET )			// nastav vystupy podla zvolenych settings
			{
				SendMesageToRS485( C_QUEUE_TX_SEND_RQS, SPINACI_MODUL_ID, MY_ID, C_SEL_SETTINGS_PACKET, Mesage.Data[0], 0, 0 );
				NewMasageToConsole("Sending request to SPm", 0);				
			}
				// ziadost o aktualne nastavenia zariadeniapre SPINACI MODUL
			if( Mesage.Mesage_ID == C_QUEUE_READ_ACT_SETT_SM )		
			{
				SendMesageToRS485( C_QUEUE_TX_SEND, SPINACI_MODUL_ID, MY_ID, C_SEND_DEVICE_SETTINGS, 0, 0, 0 );
				NewMasageToConsole("Check SP modul settings", 0);
			}
				// ziadost o aktualne nastavenia zariadeniapre LED MODUL
			if( Mesage.Mesage_ID == C_QUEUE_READ_ACT_SETT_LEDM)		
			{
				SendMesageToRS485( C_QUEUE_TX_SEND, LED_MODUL_ID, MY_ID, C_SEND_DEVICE_SETTINGS, 0, 0, 0 );
				NewMasageToConsole("Check LED modul settings", 0);
			}
				// sprava s com_RS485 tasku
			if( Mesage.Mesage_ID == C_QUEUE_NEW_PACKET )		// bol priaty packet z comRS485 taku s novym packetom
			{
				if( (s_packet->sign == C_WISO_PACKET) && (s_packet->comand == C_OK_PACKET) )// ak je to odpoved na kto je online 
				{
					if( s_packet->sorce_ID == SPINACI_MODUL_ID )
					{
						s_SPModulOnline= 0;		// je online
						OnlineStavChanged();
						if( NumScanConnectedDevice == 0 ) NewMasageToConsole((char*)s_packet->data, 1);		// poslem na conzolu
					}
					else if( s_packet->sorce_ID == LED_MODUL_ID )
					{
						s_LEDModulOnline= 0;		// je online
						OnlineStavChanged();	
					if( NumScanConnectedDevice == 0 ) NewMasageToConsole((char*)s_packet->data, 1);		// poslem na conzolu
					}
					else NewMasageToConsole("Modul has wrong ID", 2);		// poslem na conzolu
				}
				if( s_packet->comand == C_MY_SETTINGS )		// odpoved na ziadost o aktualne nastavenia zariadenia
				{
					if( IsMenuScreenSet() )		// ak je anstaveny menu screan tak nastavi zistene nastavenia
					{
						if( s_packet->sorce_ID == SPINACI_MODUL_ID ) SetSMCheckBoxStatus( s_packet->data );	
						if( s_packet->sorce_ID == LED_MODUL_ID ) SetLEDMSlidersStatus( s_packet->data );	
					}
					if( s_packet->sorce_ID == SPINACI_MODUL_ID ) NewMasageToConsole("SPm settings accepted", 1);
					if( s_packet->sorce_ID == LED_MODUL_ID ) NewMasageToConsole("LEDm settings accepted", 1);
				}
				if( s_packet->comand == C_NACK_ERR_PACKET )		// niaka ina chyba
				{
					NewMasageToConsole((char*)s_packet->data, 2);
				}
			} 
					// sprava s com_RS485 tasku
			if( Mesage.Mesage_ID == C_QUEUE_ANSWER_PACKET )		// packet je odpoved na niaky moj dotaz
			{
				if( s_packet->comand == C_OK_PACKET )			// prisla niaka odpoved
				{
					NewMasageToConsole((char*)s_packet->data, 1);
				}
				if( s_packet->comand == C_ERR_PACKET )		// odpoved neprisla
				{
					if( (IsMenuScreenSet()) && (s_packet->sign != C_SEND_DEVICE_SETTINGS)  ) ShowMesageWindow( (char*)s_packet->data, 0 );
					NewMasageToConsole((char*)s_packet->data, 2);
				}
			}
		}
	}

}

void vTimerScanConnectDevice( xTimerHandle pxTimer )
{
	NumScanConnectedDevice++;
	if( s_SPModulOnline < 255 ) s_SPModulOnline++;
	if( s_LEDModulOnline < 255 ) s_LEDModulOnline++;
	if( (s_SPModulOnline > 1) || (s_LEDModulOnline > 1) ) OnlineStavChanged();
	t_com_queue_struct	s_mesage;
	s_mesage.Mesage_ID= C_QUEUE_TX_SEND;
	
	t_packet	*s_packet;	
	s_packet= (t_packet *)s_mesage.Data;
	
	s_packet->start_of_packet= START_OF_PACKET;
	s_packet->dest_ID= BROADCAST_ID;
	s_packet->sorce_ID= MY_ID;
	s_packet->comand= C_WISO_PACKET;
	s_packet->sign= 0;
	s_packet->packet_number= 0;
	s_packet->lenght= PACKET_LENGHT_NO_DATA;
	sendToComRS485Queue( &s_mesage, 0 );
	
	if( NumScanConnectedDevice == 0 )NewMasageToConsole("Scan Connected Modules", 0);	
}

unsigned long	MainTaskInit( void )
{
	// vytvorim frontu pre posielanie dat Do tohto tasku
	xQueueMainTask= xQueueCreate( LENGHTQUEUEMAINTASK, sizeof( t_MainQueueStruct ) );
	// vytvorenie tasku	
	if(xTaskCreate( MainTask, "MainTask", STACK_SIZE_MAIN_TASK, 0, PRIORITY_MAIN_TASK,  xHMainTask ) != pdPASS)
	{
		return(1);
	}
	
	return (0);	// vsetko OK
	
}

unsigned long IsSPModulonline(void)
{
	if( s_SPModulOnline > 2 ) return 0;	// nieje online
	else return 1;		// je online
}

unsigned long IsLEDModulonline(void)
{
	if( s_LEDModulOnline > 2 ) return 0;	// nieje online
	else return 1;		// je online
}

void	SendMesageToRS485( unsigned char MesageTyp, unsigned char DestID, unsigned char SourceID, unsigned char Comand, unsigned char Sign, unsigned char DataLenght, char *Data )
{
	t_com_queue_struct	PacketMesage;
	PacketMesage.Mesage_ID= MesageTyp;
	t_packet	*s_Spacket;
	s_Spacket= (t_packet *)PacketMesage.Data;
	
	s_Spacket->start_of_packet= START_OF_PACKET;
	s_Spacket->dest_ID= DestID;
	s_Spacket->sorce_ID= SourceID;
	s_Spacket->comand= Comand;
	s_Spacket->sign= Sign;
	s_Spacket->lenght= PACKET_LENGHT_NO_DATA + DataLenght;
	
	if( DataLenght > 0)	memcpy( s_Spacket->data, Data, DataLenght );
	sendToComRS485Queue( &PacketMesage, 0 );	
}

// odosle spravu do fronty pre ComRS485 task
unsigned long	sendToMainQueue( const t_MainQueueStruct *mesage, unsigned long xTicksToWait )
{
	if( xQueueSendToBack( xQueueMainTask, mesage, xTicksToWait ) == pdPASS) return 0;		// odoslalo do fronty
	
	else return 1;		// neodoslalo
}
