#include "config.h"

// Include all the libraries we're using, this is alredy included in heavy, 
// just remove the parts that are not needed.
#include "appled.h"
#include "digitalout.h"
#include "digitalin.h"
#include "pwmout.h"
#include "webserver.h"

/////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////// Setup Varables and Instances ////////////////////////////////////////

// You can see the prototypes of the functions and tasks.
// below that you can see the global varables that are used.

//Tasks
void Logic( void* parameters );
void Listener1( void* parameters );
void Listener2( void* parameters );
void Listener3( void* parameters );
void Listener4( void* parameters );
void *ltask;

//Functions And Struct
struct netconn* udpSocket;
void doVacation(void);
void doPetExists(void);

// Varables
void* mainQueue;
char *r1;
char *r2;
char *r3;
char *r4;
int address1 = IP_ADDRESS( 192, 168, 0, 202 );
int address2 = IP_ADDRESS( 192, 168, 0, 202 );
int address3 = IP_ADDRESS( 192, 168, 0, 202 );
int address4 = IP_ADDRESS( 192, 168, 0, 204 );
int port = 8000;

// Time trigered items...
char ttf[4] = {'1','7','0','0'}; // Time to feed
char ttw[4] = {'1','0','2','5'}; // Time to wake
char tta[4] = {'0','0','0','0'}; // Time to alarm

// The three states that needed to be tracked.
int onVacation = 0;
int petExists = 0;
int petFed = 0;

/////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////// RUN AT START ////////////////////////////////////////////////////

// The run function is started by default when the make controler turns on.
void Run( )
{
  // Do this right quick after booting up - otherwise we won't be recognised
  Usb_SetActive( 1 );

  // Fire up the OSC system and register the subsystems you want to use
  Osc_SetActive( true, true, true, true );
  Osc_RegisterSubsystem( AppLedOsc_GetName(), AppLedOsc_ReceiveMessage, NULL );
  Osc_RegisterSubsystem( DigitalOutOsc_GetName(), DigitalOutOsc_ReceiveMessage, NULL );
  Osc_RegisterSubsystem( PwmOutOsc_GetName(), PwmOutOsc_ReceiveMessage, NULL );
  Osc_RegisterSubsystem( LedOsc_GetName(), LedOsc_ReceiveMessage, NULL );
  Osc_RegisterSubsystem( DebugOsc_GetName(), DebugOsc_ReceiveMessage, NULL );
  Osc_RegisterSubsystem( SystemOsc_GetName(), SystemOsc_ReceiveMessage, NULL );
  Osc_RegisterSubsystem( NetworkOsc_GetName(), NetworkOsc_ReceiveMessage, NULL );
  Osc_RegisterSubsystem( IoOsc_GetName(), IoOsc_ReceiveMessage, NULL );
  Osc_RegisterSubsystem( WebServerOsc_GetName(), WebServerOsc_ReceiveMessage, NULL );

  // Starts the network up.  Will not return until a network is found...
  Network_SetActive( true );
  Network_SetDhcpEnabled(0); // Disable DHCP
  Network_SetAddress( 192, 168, 0, 200 ); // Set static IP
  
  // create a queue that can hold 10 recieves
  mainQueue = QueueCreate( 10, 9 );
  if( mainQueue == 0 )
  {
	// then the queue can't be used, blink fast.
	Led_SetState( 0 ); Sleep( 200 ); Led_SetState( 1 );Sleep( 200 );
	Led_SetState( 0 ); Sleep( 200 ); Led_SetState( 1 );Sleep( 200 );
  }
  
  // Setup network socket
  udpSocket = DatagramSocket( port );
  
  // Read last stored memory values
  Eeprom_Read( EEPROM_SYSTEM_BASE - 4, (uchar*)&onVacation, 4 );
  if(onVacation != 0 || onVacation != 1){onVacation = 0;}
  Eeprom_Read( EEPROM_SYSTEM_BASE - 8, (uchar*)&petExists, 4 );
  if(petExists != 0 || petExists != 1){petExists = 0;}
  Eeprom_Read( EEPROM_SYSTEM_BASE - 12, (uchar*)&petFed, 4 );
  if(petFed != 0 || petFed != 1){petFed = 0;}

  // Setup tasks
  ltask = TaskCreate( Logic, "Logic", 2000, 0, 2 );
  TaskCreate( Listener1, "Listener1", 1000, 0, 2 );
  TaskCreate( Listener2, "Listener2", 1000, 0, 2 );
  TaskCreate( Listener3, "Listener3", 1000, 0, 2 );
  TaskCreate( Listener4, "Listener4", 1000, 0, 2 );
  
  // Led turns on and stays on when the manager is ready
  Led_SetState( 0 ); Sleep( 1000 ); Led_SetState( 1 );Sleep( 1000 );
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////// Tasks ///////////////////////////////////////////////////////

// The logic task is what checks requests and forwards or returns a reply.
// Also runs some hardware checks for vacation and pet exists when nothing is being processed.
void Logic(void* p)
{
	(void)p;
	
	while(true)
	{
		//TaskEnterCritical();
		char data[9]; // Data buffer 9 char
		if(QueueReceive( mainQueue, &data, 10 )) // Check if there is something to do...
		{
			if(data[1] == '1')
			{DatagramSocketSend( udpSocket, address1, port, &data, 9 );}
			else if(data[1] == '2')
			{DatagramSocketSend( udpSocket, address2, port, &data, 9 );}
			else if(data[1] == '3')
			{DatagramSocketSend( udpSocket, address3, port, &data, 9 );}
			else if(data[1] == '4')
			{DatagramSocketSend( udpSocket, address4, port, &data, 9 );}
			else if(data[1] == '0')
			{
				// These are commands that effect the manager
				if(data[2] == '0' && data[3] == '1') // Time Recieved
				{
					//Send time of day to Enviro
					char outt[9] = {'0','2','0','1','0',data[5],data[6],data[7],data[8]};
					DatagramSocketSend( udpSocket, address2, port, &outt, 9 );
					Sleep(1);
					
					// Check time to feed
					if(data[5] == ttf[0] && data[6] == ttf[1] && data[7] == ttf[2] && data[8] == ttf[3])
					{ 
						char out[9] = {'0','3','1','1','0','0','0','0','1'};
						DatagramSocketSend( udpSocket, address3, port, &out, 9 ); 
						Sleep(1);
					}
					
					// Check time to wake
					if(data[5] == ttw[0] && data[6] == ttw[1] && data[7] == ttw[2] && data[8] == ttw[3])
					{ 
						char out[9] = {'0','4','0','3','0','0','0','0','1'};
						DatagramSocketSend( udpSocket, address4, port, &out, 9 ); 
						Sleep(1);
					}
					
					// Check time to alarm
					if(data[5] == tta[0] && data[6] == tta[1] && data[7] == tta[2] && data[8] == tta[3])
					{ 
						char out[9] = {'0','1','1','0','0','0','0','0','1'};
						DatagramSocketSend( udpSocket, address1, port, &out, 9 ); 
						Sleep(1);
					}

				}
				else if(data[2] == '0' && data[3] == '9') // Pet Ate?
				{
					if(data[8] == '1')
					{
						petFed = 1;
						Eeprom_Write( EEPROM_SYSTEM_BASE - 12, (uchar*)&petFed, 4 );
						// Turn digital out 2 on
						DigitalOut_SetValue( 2, 1 );
					}
					else
					{
						petFed = 0;
						Eeprom_Write( EEPROM_SYSTEM_BASE - 12, (uchar*)&petFed, 4 );
						// Turn digital out 2 off
						DigitalOut_SetValue( 2, 0 );
					}
					Sleep(1);
				}
			}
		}
		else // If nothing to do, run other check functions...
		{
			doPetExists();
			Sleep(1);
			doVacation();
		}
		//TaskExitCritical();
		
		TaskSetPriority(ltask,2);
		Sleep(1);
	}
}

///////////////////////////////// Network Listeners /////////////////////////////////////////

// They listen on the 4 IP and send anything recieved to the queue to be processed.
// Ths allows for the fastest responce time to each request, without locking tasks.

// Security Listener
void Listener1(void* p)
{
	(void)p;
	while(true)
	{
		DatagramSocketReceive( udpSocket, port, &address1, &port, &r1, 9 );
		QueueSendToBack( mainQueue, &r1, 10 );
		TaskSetPriority(ltask,3);
		Sleep(1);
	}
}

// Environment Listener
void Listener2(void* p)
{
	(void)p;
	while(true)
	{
		DatagramSocketReceive( udpSocket, port, &address2, &port, &r2, 9 );
		QueueSendToBack( mainQueue, &r2, 10 );
		TaskSetPriority(ltask,3);
		Sleep(1);
	}
}

// Pet Listener
void Listener3(void* p)
{
	(void)p;
	while(true)
	{
		DatagramSocketReceive( udpSocket, port, &address3, &port, &r3, 9 );
		QueueSendToBack( mainQueue, &r3, 10 );
		TaskSetPriority(ltask,3);
		Sleep(1);
	}
}

// Clock Listener
void Listener4(void* p)
{
	(void)p;
	while(true)
	{
		DatagramSocketReceive( udpSocket, port, &address4, &port, &r4, 9 );
		QueueSendToBack( mainQueue, &r4, 10 );
		TaskSetPriority(ltask,3);
		Sleep(1);
	}
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////// Functions ///////////////////////////////////////////////////////

// Below are the two hardware check functions that are run if the make has free cycles.

void doVacation(void)
{
	if( DigitalIn_GetValue(0) == 0 && onVacation == 1) // Vacation off
	{
		onVacation = 0;
		Eeprom_Write( EEPROM_SYSTEM_BASE - 4, (uchar*)&onVacation, 4 );
		char out[9] = {'0','1','0','4','0','0','0','0','0'};
		DatagramSocketSend( udpSocket, address1, port, &out, 9 ); 
		out[1] = '2';
		DatagramSocketSend( udpSocket, address2, port, &out, 9 ); 
		out[1] = '4';
		DatagramSocketSend( udpSocket, address4, port, &out, 9 ); 
		// Turn digital out 0 off
		DigitalOut_SetValue( 0, 0 );
	}
	else if (DigitalIn_GetValue(0) != 0  && onVacation == 0) // Vacation On
	{
		onVacation =1;
		Eeprom_Write( EEPROM_SYSTEM_BASE - 4, (uchar*)&onVacation, 4 );
		char out[9] = {'0','1','0','4','0','0','0','0','1'};
		DatagramSocketSend( udpSocket, address1, port, &out, 9 ); 
		out[1] = '2';
		DatagramSocketSend( udpSocket, address2, port, &out, 9 ); 
		out[1] = '4';
		DatagramSocketSend( udpSocket, address4, port, &out, 9 ); 
		// Turn digital out 0 on
		DigitalOut_SetValue( 0, 1 );
	}	
}

void doPetExists(void)
{
	if( DigitalIn_GetValue(1) == 0 && petExists == 1) // Vacation off
	{
		petExists = 0;
		Eeprom_Write( EEPROM_SYSTEM_BASE - 8, (uchar*)&petExists, 4 );
		char out[9] = {'0','3','0','6','0','0','0','0','0'};
		DatagramSocketSend( udpSocket, address3, port, &out, 9 ); 
		// Turn digital out 1 off
		DigitalOut_SetValue( 1, 0 );
	}
	else if (DigitalIn_GetValue(1) != 0  && petExists == 0) // Vacation On
	{
		petExists = 1;
		Eeprom_Write( EEPROM_SYSTEM_BASE - 8, (uchar*)&petExists, 4 );
		char out[9] = {'0','3','0','6','0','0','0','0','1'};
		DatagramSocketSend( udpSocket, address3, port, &out, 9 ); 
		// Turn digital out 1 on
		DigitalOut_SetValue( 1, 1 );
	}	
}


