/* Ethernet server */

/* Scheduler includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"

// Include pouzivanych knihoven
#include "stdint.h"
#include "server.h"
#include "net.h"
#include "tcp.h"
#include "ip.h"
#include "arp.h"
#include "eth.h"
#include "icmp.h"
#include "udp.h"
#include "UDP_komunikace.h"
#include "enc28j60.h"
#include "www.h"
//#include "usart.h"

// Nastaveni serveru - nastavit stejne take v "tcp_ip.c" !!!
extern uint8_t my_MAC[MAC_ADR_SIZE] = {0x04,0x02,0x35,0x00,0x00,0x01};		// MAC adresa HTTP serveru
extern uint8_t my_IP[IP_ADR_SIZE] = {192,168,0,2};							// IP adresa HTTP serveru
extern uint8_t my_MASK[IP_ADR_SIZE] = {255,255,255,0};						// Maska podsite serveru
extern uint8_t my_GATE[IP_ADR_SIZE] = {192,168,0,1};						// Vychozi brana serveru
extern uint16_t my_HTTP_Port = 80;											// Port HTTP serveru
extern uint16_t my_UDP_Port = 1234;											// Port UDP serveru
extern uint16_t my_Telnet_Port = 23;										// Port Telnet serveru

// Globalni promenne
uint8_t RxTx_buffer[TCP_BUFFER_SIZE+1];	// buffer do ktereho se nahraje prichozi paket
//static unsigned char TX_buffer[800+1];	// buffer do ktereho se sestavuje paket pro odeslani
static uint16_t PaketLen = 0;
volatile unsigned char TCP_State = TCP_State_Idle;

extern uint8_t Server_Freez = 0;
volatile uint8_t Dummy2;
extern uint8_t ServerEnable = ((1<<SERVER_ENABLE_WWW2)|(1<<SERVER_ENABLE_WWW)|(1<<SERVER_ENABLE_UDP)|(1<<SERVER_ENABLE_TELNET)|(1<<SERVER_ENABLE_PING));
/* ----------------------------------------------------
 Inicializace Ethernetoveho serveru
 --------------------------------------------------- */
void ServerInit(void)
{
	enc28j60Init(my_MAC);					  		// Inicializace enc28j60 radice
	ARP_InitCahce();								// Smazani lokalni ARP cache
}

/* ----------------------------------------------------
 Start HTTP serveru v nekonecne smycce
 --------------------------------------------------- */
void ServerStart(void)
{	
	volatile uint8_t Vysledek_TCP;
	
	TCP_TimeoutProcess();									// Provede prepocitani timeoutu TCP spojeni

	PaketLen = enc28j60PacketReceive(MAX_PACKET_SIZE, RxTx_buffer);	// Ulozi prijaty paket do RX_bufferu
	if(PaketLen==0)											// Pokud je delka prichozich dat PaketLen = 0 znamena to, 
    {														// ze nebyl prijat zadny validni paket a neni co zpracovavat
		return;
    }
	// Test prichoziho APR paketu
	if(Check_ETH_type_ARP_myIP(RxTx_buffer,PaketLen))		// Kontrola jestli je prijaty paket ARP paket a jestli IP adresa v jeho dotazu odpovida me
    {
		ARP_Send_ARP_Reply(RxTx_buffer,RxTx_buffer);
		ARP_InsertCacheEntryFromRX(RxTx_buffer);			// Vlozi zaznam IP->MAC (z prichoziho paketu) do lokalni ARP cache
		return;
    }
    // check if ip packets are for us:
    if(Check_ETH_type_IP_myIP(RxTx_buffer,PaketLen)==0) 	// Kontrola jestli je prijaty paket IP paket a jestli IP adresa v jeho dotazu odpovida me
    {
		return;
    }
	// check if paket is PING request
	if(ICMP_Check_PingRequest(RxTx_buffer))
	{
		if(PaketLen<sizeof(RxTx_buffer))					// Odpovi pouze na paket ktery  se vleze do vysilaciho bufferu
		{
			if(ServerEnable&(1<<SERVER_ENABLE_PING))
			{
				ICMP_Send_EchoReply(RxTx_buffer,RxTx_buffer,PaketLen);
			}
		}
		return;
	}
	// check if paket is TCP and Dest. port is WWWPort
	if (TCP_Check_TCP_WWWPort(RxTx_buffer, my_HTTP_Port))
	{
		if(ServerEnable&(1<<SERVER_ENABLE_WWW2))
		{
			Vysledek_TCP = TCP_ProcessRx(RxTx_buffer, RxTx_buffer, PaketLen);
			
			/* zastavit se a pockat dokud nenaplni WWW server cely buffer */
			while(Server_Freez)
			{
				Dummy2++;
				Dummy2=Dummy2;
				vTaskDelay(1*portTICK_FOR_1MS);
			}
		}
	}
	// Kontrola jestli jsou prichozi data UDP datagram
	if (UDP_Check_UDP_Port(RxTx_buffer, my_UDP_Port))
	{
		if(ServerEnable&(1<<SERVER_ENABLE_UDP))
		{
			if(UDPKom_CheckIdent(RxTx_buffer))
			{
				if(UDPKom_ProcessData(RxTx_buffer)==UDPKom_Zadost)		// Pokud prisla zadost o data, tak je odeslat. Jinak se prichozi aplikuji parametry 
				{
					// Odeslani dat
					UDPKom_SendDataFromRX(RxTx_buffer, RxTx_buffer);
				}
				else													// Prochozi datagram byl nastavenim parametru
				{					
				}	
			}						
		}
	}											 	
}

/* ------------------------------------------------------------------
 Overeni jestli je paket v bufferu ARP paketem a jestli je pro me
 ----------------------------------------------------------------- */
uint8_t Check_ETH_type_ARP_myIP(uint8_t *buffer, uint16_t len)
{
	unsigned char i=0;
	//  Kontrola jestli je spravna delka paketu ((ETH)14+(ARP)28 = 42 bytu)
	if (len<41)
	{
		return(0);
	}
	// Overeni jestli typ paketu v ETH hlavicce je ARP paket
	if(buffer[OFFSET_ETH_TypeLen+0] != (0xFF00&ETH_Type_ARP)>>8 || buffer[OFFSET_ETH_TypeLen+1] != (0x00FF&ETH_Type_ARP))
	{
		return(0);
	}
	// Overeni jestli cilova IP adresa je shodna s moji IP adresou 
	while(i<4)
	{
	    if(buffer[OFFSET_ARP_DestIP+i] != my_IP[i])
		{
			return(0);
    	}
	    i++;
	}
	return(1);
}

/* ------------------------------------------------------------------
 Overeni jestli je paket v bufferu ARP paketem a jestli je pro me
 ----------------------------------------------------------------- */
uint8_t Check_ETH_type_IP_myIP(uint8_t *buffer, uint16_t len)
{
	uint8_t i=0;

	if (len<42)														//eth+ip+udp => delka hlavicky je 42
	{
	    return(0);
	}
	if(buffer[OFFSET_ETH_TypeLen+0]!=(0xFF00&ETH_Type_IPv4)>>8 || 
	   buffer[OFFSET_ETH_TypeLen+1]!=(0x00FF&ETH_Type_IPv4))		// Overeni jestli se jedna o IPv4 paket
	{
	    return(0);
	}
	if (buffer[OFFSET_IP_Header_Length]!=0x45)						// Overeni jestli je delka IP hlavcky 20 bytu
	{	    
	    return(0);
	}
	while(i<4)														// Overeni jestli je cilova adresa shodna s "mou" adresou
	{
	    if(buffer[OFFSET_IP_DestIP+i]!=my_IP[i])
		{
	        return(0);
    	}
	    i++;
	}
	return(1);
}

/* ---------------------------------------------
 Nastaveni portu UDP serveru
 -------------------------------------------- */
void Server_SetPortUDP(uint8_t port)
{
	my_UDP_Port = port;
}

/* ---------------------------------------------
 Vycteni portu UDP serveru
 -------------------------------------------- */
uint8_t Server_GetPortUDP(void)
{
	return(my_UDP_Port);
}

/* ---------------------------------------------
 Nastaveni portu UDP serveru
 -------------------------------------------- */
void Server_SetPortWWW(uint8_t port)
{
	my_HTTP_Port = port;
}

/* ---------------------------------------------
 Vycteni portu UDP serveru
 -------------------------------------------- */
uint8_t Server_GetPortWWW(void)
{
	return(my_HTTP_Port);
}

/* ---------------------------------------------
 Nastaveni portu IP adresy serveru
 -------------------------------------------- */
void Server_SetIP(uint8_t *IP)
{
	uint8_t i;
	for(i=0;i<IP_ADR_SIZE;i++)
	{
		my_IP[i] = IP[i];
	}
}

/* ---------------------------------------------
 Vycteni portu IP adresy serveru
 -------------------------------------------- */
void Server_GetIP(uint8_t *IP)
{
	uint8_t i;
	for(i=0;i<IP_ADR_SIZE;i++)
	{
		IP[i] = my_IP[i];
	}
}
/* Konec souboru */
