/* =============================================================== 
 * Vlastni implementace TCP Stacku
 *
 *
 * Autor: Bc. Ondrej Satora, VUT FEEC 2011
 * Inspirace cerpana mimo jine z AN833 od Microchip a k ni
 * nalezici ukazkove knihovny pro PIC32
 ============================================================== */
/* Scheduler includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"

// Pouzivane knihovny
#include "stdint.h"
#include "tcp.h"
#include "enc28j60.h"
#include "eth.h"
#include "ip.h"
#include "net.h"
#include "net_checksum.h"
#include "My_usart.h"
#include "misc.h"
#include "www.h"
#include "server.h"

//#define DEBUG

// Globalni promene

// Externi promenne
extern uint8_t my_MAC[MAC_ADR_SIZE];			// MAC adresa HTTP serveru
extern uint8_t my_IP[IP_ADR_SIZE];				// IP adresa HTTP serveru
extern uint16_t my_HTTP_Port;					// Port HTTP serveru

// Stavove promenne
extern uint8_t TCP_Status = TCP_STATE_CLOSED;		// Stav stavoveho automatu TCP spojeni (pouze jedno spojeni soucasne)
uint32_t TCP_Timeout[TCP_TIMEOUT_COUNT];

const uint32_t TimeoutConst[TCP_TIMEOUT_COUNT] =
{	5000,										// Pocet ms od obdrzeni pozadavku na spojeni po kterem spojeni
												// automaticky prejde do rezimu LISTEN jestlize nejsou provedeny vsechny 3 casti handshakeingu
	10000,										// Pocet ms necinosti spojeni po kterem se automaticky uzavre (prejde do stavu listen) 
	1000,										// Doba v [ms] po kterou se ceka na prichod ACK - potvrzeni naposledy odeslane TCP zpravy
	700};										// Doba v [ms] po kterou zustane spojeni zablokovane (po kompletni vymene FIN+ACK mezi obemi stranami spojeni) nez se znova resetuje a otevre
// Pracovni globalni promenne TCP stacku
uint32_t TCP_ACK_Number=0;
uint32_t TCP_SEQ_Number=0;
uint16_t TCP_LastDataLen=0;
uint8_t TCP_ClientIP[IP_ADR_SIZE];				// IP adresa pripojeneho klienta
uint16_t TCP_ClientPort=0;						// Port pripojeneho klienta
uint8_t PokusOZnovuodeslani=0;					// Pocet pokusu o znovuodeslani paketu pokud neprisel vcas korektni ACK
uint32_t TimeoutPredchoziAktualniCas=0;
uint16_t PoziceVkladani=0;

extern uint8_t TCPEnableGenerateWWW;
extern uint8_t TCPGenerateStatus;
extern uint8_t Server_Freez;

volatile uint8_t Dummy3;
extern uint8_t ServerEnable;
/* --------------------------------------------------------------
 Inicializace TCP stacku
 ------------------------------------------------------------- */
void TCP_Init(void)
{
	uint8_t i;
	// Inicializace Timeoutu
	for(i=0;i<TCP_TIMEOUT_COUNT;i++)
	{
		TCP_Timeout[i] = 0xFFFFFFFF;
	}
	TCP_ResetRemoteClient();										// Inicializace Zapamatovanych udaju o klientovy
	PokusOZnovuodeslani=0;
	TCP_Status = TCP_STATE_LISTEN;
	TCPEnableGenerateWWW = 0;											// Zakaze plnit WWW server data  do TCP
	TCPGenerateStatus=GENERATE_OFF;
	#ifdef DEBUG
		USART1_WaitForMUTEX();
		USART1_SetMUTEX();
		USART1_Send("GEN > Generate=OFF",1);
		USART1_Send("GEN > Server freez=OFF",1);
		USART1_Send("GEN > Generate WWW=OFF",1);
		USART1_FreeMUTEX();
	#endif
	if(!(ServerEnable&(1<<SERVER_ENABLE_WWW)))
	{
		ServerEnable&=~(1<<SERVER_ENABLE_WWW2);						// Sekundarni spozdena deaktivace HTTP serveru (po dokonceni generovani predchozi stranky a ukonceni spojeni)
	}
}

/* --------------------------------------------------------------
 Smazani udaju o pripojenem TCP klientovy
 ------------------------------------------------------------- */
void TCP_ResetRemoteClient(void)
{
	uint8_t i;
	for(i=0;i<IP_ADR_SIZE;i++)										// Smazani IP adresy
	{
		TCP_ClientIP[i] = 0;
	}
	TCP_ClientPort=0;												// Inicializace portu
	TCP_ACK_Number=0;												// Reset ACK cisla
	TCP_SEQ_Number=0;												// Reset SEQ cisla
	TCP_LastDataLen=0;
	PoziceVkladani=0;
}

/* --------------------------------------------------------------
 Kontrolni funkce overujici jestli prijaty TCP paket odpovida 
 vzdalenemu klientovi s nimz bylo sestaveno spojeni
 ------------------------------------------------------------- */
uint8_t TCP_CheckRemoteClient(uint8_t *RX_buffer)
{
	if((RX_buffer[OFFSET_TCP_SourcePort+0] == (TCP_ClientPort & 0xFF00)>>8) &
	   (RX_buffer[OFFSET_TCP_SourcePort+1] == (TCP_ClientPort & 0x00FF)))			// Overeni cisla Portu
	{
		if((RX_buffer[OFFSET_IP_SourceIP+0] == TCP_ClientIP[0]) &
	       (RX_buffer[OFFSET_IP_SourceIP+1] == TCP_ClientIP[1]) &
		   (RX_buffer[OFFSET_IP_SourceIP+2] == TCP_ClientIP[2]) &
		   (RX_buffer[OFFSET_IP_SourceIP+3] == TCP_ClientIP[3]))					// Overeni IP adresy
		{
			return(1);
		}	
	}
	return(0);
}

/* --------------------------------------------------------------
 Hlavni funkce spracovavajici prichozi TCP pakety
 ------------------------------------------------------------- */
uint8_t TCP_ProcessRx(uint8_t *RX_buffer, uint8_t *TX_buffer, uint16_t Rx_BufferLen)
{
	volatile uint32_t temp;

	switch(TCP_Status)
	{
		/* Mod synchronizace - 3 stavovy handshakeing */
		case TCP_STATE_LISTEN:							// Spojeni jeste nebylo navazano
		{
			#ifdef DEBUG
				USART1_WaitForMUTEX();
				USART1_SetMUTEX();
				USART1_Send("TCP STATUS: LISTEN",1);
				USART1_FreeMUTEX();
			#endif
			if (RX_buffer[OFFSET_TCP_Flags] & TCP_SYN)	// Pozadavek na synchronizaci
			{
				TCP_Status = TCP_STATE_SYN_RECEIVED;
				TCP_Timeout[TCP_TIMEOUTID_ACK] = 0xFFFFFFFF;	// Vyresetovani Timeoutu				

				TCP_Send_TCP_syn_ack(RX_buffer, TX_buffer);		// odeslani paketu se synchronizaci (SYN) a potvrzenim prijeti predchoziho (ACK)
		        TCP_Timeout[TCP_TIMEOUTID_HANDSHAKE] = xTaskGetTickCount();
				TCP_Timeout[TCP_TIMEOUTID_ACK] = xTaskGetTickCount();
				PokusOZnovuodeslani=0;
				#ifdef DEBUG
					USART1_WaitForMUTEX();
					USART1_SetMUTEX();
					USART1_Send("TCP > Send ACK+SYN",1);
					USART1_FreeMUTEX();
				#endif
				return(TCP_STATE_SYN_RECEIVED);
		    }
			break;
		}
		case TCP_STATE_SYN_RECEIVED:							// Potvrzeni prijeti SYN+ACK klientem
		{
			#ifdef DEBUG
				USART1_WaitForMUTEX();
				USART1_SetMUTEX();
				USART1_Send("TCP STATUS: SYN RECEIVED",1);
				USART1_FreeMUTEX();
			#endif
			if (TCP_CheckRemoteClient(RX_buffer))
			{
				if (RX_buffer[OFFSET_TCP_Flags] & TCP_ACK)		// Pozadavek na ack - potvrzeni prichozich dat
				{
					TCP_Status=TCP_STATE_ESTABLISHED;
					TCP_Timeout[TCP_TIMEOUTID_ACK] = 0xFFFFFFFF;	// Vyresetovani Timeoutu
					TCP_Timeout[TCP_TIMEOUTID_HANDSHAKE] = 0xFFFFFFFF;		// Vyresetovani Timeoutu navazani spojeni
					#ifdef DEBUG
						USART1_WaitForMUTEX();
						USART1_SetMUTEX();
						USART1_Send("TCP > Connection Established",1);
						USART1_FreeMUTEX();
					#endif
					TCP_Timeout[TCP_TIMEOUTID_CONNECTION] = xTaskGetTickCount();										
			        TCP_SEQ_Number++;
					return(TCP_STATE_ESTABLISHED);
			  	}
				else if(TCP_CheckRemoteClient(RX_buffer))			// Pokud nebyl prijat ACK tak odesle predchozi paket znova
				{
					#ifdef DEBUG
						USART1_WaitForMUTEX();
						USART1_SetMUTEX();
						USART1_Send(" TCP > Neprijato ACK",1);
						USART1_FreeMUTEX();
					#endif
					return(TCP_STATE_SYN_RECEIVED);
				}
			}
			else
			{
				#ifdef DEBUG
					USART1_WaitForMUTEX();
					USART1_SetMUTEX();
					USART1_Send(" TCP > Pokus o komunikaci dalsiho klienta odmitnut",1);
					USART1_FreeMUTEX();
				#endif
			}
			break;
		}
		/* Mod prenos dat */
		case TCP_STATE_ESTABLISHED:
		{
			#ifdef DEBUG
				USART1_WaitForMUTEX();
				USART1_SetMUTEX();
				USART1_Send("TCP STATUS: ESTABLISHED",1);
				USART1_FreeMUTEX();
			#endif
			// Overeni jestli neprisla zadost o ukonceni spojeni
			if(TCP_CheckRemoteClient(RX_buffer))
			{
				if (RX_buffer[OFFSET_TCP_Flags] & TCP_FIN)		// Pozadavek na ack - potvrzeni prichozich dat
				{
					TCP_Status=TCP_STATE_FIN_WAIT_1;
					TCP_Timeout[TCP_TIMEOUTID_ACK] = 0xFFFFFFFF;	// Vyresetovani Timeoutu
					#ifdef DEBUG
						USART1_WaitForMUTEX();
						USART1_SetMUTEX();
						USART1_Send("TCP > Send ACK - cekani na potvrzeni druhou stranou",1);
						USART1_FreeMUTEX();
					#endif
					TCP_LastDataLen = 0;
					TCP_SEQ_Number--;
					TCP_Send_TCP_ack(RX_buffer, TX_buffer,1);		// Odeslani potvrzeni o uzavirani spojeni a cekani na prijeti FIN+ACK					
					PokusOZnovuodeslani=0;
					TCP_Timeout[TCP_TIMEOUTID_FINWAIT2] = xTaskGetTickCount();
					TCP_Timeout[TCP_TIMEOUTID_CONNECTION] = 0xFFFFFFFF;	// Vyresetovani Timeoutu
					return(TCP_STATE_FIN_WAIT_1);
				}
				else													// Prijaty uzitecna data data
				{
					/* Zjisteni delky prijatych TCP dat */
					TCP_LastDataLen = Rx_BufferLen - (ETH_Header_len + IP_Header_len + TCP_Checksum_len_NoOpt_Data);
					#ifdef DEBUG
						USART1_WaitForMUTEX();
						USART1_SetMUTEX();
						USART1_Send("TCP > Con.Established, Prichozi data. Len: ",0);
						USART1_SendInteger(TCP_LastDataLen);
						USART1_Send_Enter();
						USART1_FreeMUTEX();
					#endif
					TCPEnableGenerateWWW = 1;
					if(TCPGenerateStatus!=GENERATE_PROGRESS) 
					{
						TCPGenerateStatus=GENERATE_START;
						#ifdef DEBUG
							USART1_WaitForMUTEX();
							USART1_SetMUTEX();
							USART1_Send("GEN > Generate=START",1);							
							USART1_FreeMUTEX();
						#endif
					}
					Server_Freez = 1;								// Zastavi tento proces dokud bude WWW server pracovat s RxTx bufferem
					#ifdef DEBUG
						USART1_WaitForMUTEX();
						USART1_SetMUTEX();
						USART1_Send("GEN > Server freez=ON",1);
						USART1_Send("GEN > Generate WWW=ON",1);
						USART1_FreeMUTEX();
					#endif
					return(TCP_DATA_ARIVED);
				}
			}
			else
			{
				#ifdef DEBUG
					USART1_WaitForMUTEX();
					USART1_SetMUTEX();
					USART1_Send(" TCP > Pokus o komunikaci dalsiho klienta odmitnut",1);
					USART1_FreeMUTEX();
				#endif
			}
			break;
		}
		/* Mod ukoncovani spojeni - 4 - stavovy handshake */
		case TCP_STATE_FIN_WAIT_1:
		{
			#ifdef DEBUG
				USART1_WaitForMUTEX();
				USART1_SetMUTEX();
				USART1_Send("TCP STATUS: FIN WAIT 1",1);
				USART1_FreeMUTEX();
			#endif
			if(TCP_CheckRemoteClient(RX_buffer))
			{
				#ifdef DEBUG
					USART1_WaitForMUTEX();
					USART1_SetMUTEX();
					USART1_Send(" TCP > FIN|ACK > klient OK",1);
					USART1_FreeMUTEX();
				#endif
				if (RX_buffer[OFFSET_TCP_Flags] & (TCP_FIN|TCP_ACK))	// Pozadavek na ack - potvrzeni prichozich dat
				{				
					#ifdef DEBUG
						USART1_WaitForMUTEX();
						USART1_SetMUTEX();
						USART1_Send(" TCP > FIN|ACK > ACK Flag OK",1);
						USART1_Send(" TCP > Set FIN wait 2 timeout",1);
						USART1_FreeMUTEX();
					#endif
					TCP_Timeout[TCP_TIMEOUTID_ACK] = 0xFFFFFFFF;		// Vyresetovani Timeoutu
					TCP_Timeout[TCP_TIMEOUTID_FINWAIT2] = xTaskGetTickCount();
					return(TCP_STATE_FIN_WAIT_2);
				}
				else if(TCP_CheckRemoteClient(RX_buffer))				// Neprijato potvrzeni ukonceni spojeni 
				{														// -> odeslat znova predchozi TCP paket					
					TCP_Timeout[TCP_TIMEOUTID_FINWAIT2] = xTaskGetTickCount();
				}
			}
			else
			{
				#ifdef DEBUG
					USART1_WaitForMUTEX();
					USART1_SetMUTEX();
					USART1_Send(" TCP > Pokus o komunikaci dalsiho klienta odmitnut",1);
					USART1_FreeMUTEX();
				#endif
			}
			break;
		}
		case TCP_STATE_FIN_WAIT_2:
		{
			#ifdef DEBUG
				USART1_WaitForMUTEX();
				USART1_SetMUTEX();
				USART1_Send("TCP STATUS: FIN WAIT 2",1);
				USART1_FreeMUTEX();
			#endif
			TCP_Init();										// Resetovani TCP spojeni
			#ifdef DEBUG
				USART1_WaitForMUTEX();
				USART1_SetMUTEX();
				USART1_Send("TCP > Closing wait complete",1);
				USART1_FreeMUTEX();
			#endif
			return(TCP_STATE_LISTEN);
		}
		case TCP_STATE_TIME_WAIT:
		{
			#ifdef DEBUG
				USART1_WaitForMUTEX();
				USART1_SetMUTEX();
				USART1_Send("TCP STATUS: TIME WAIT",1);
				USART1_FreeMUTEX();
			#endif
			if(TCP_CheckRemoteClient(RX_buffer))
			{
				#ifdef DEBUG
					USART1_WaitForMUTEX();
					USART1_SetMUTEX();
					USART1_Send(" TCP > ACK > klient OK",1);
					USART1_FreeMUTEX();
				#endif
				if (RX_buffer[OFFSET_TCP_Flags] & TCP_ACK)		// Pozadavek na ack - potvrzeni prichozich dat
				{
					temp = (RX_buffer[OFFSET_TCP_ACK+0]<<24)|
						   (RX_buffer[OFFSET_TCP_ACK+1]<<16)|
						   (RX_buffer[OFFSET_TCP_ACK+2]<<8)|
						   (RX_buffer[OFFSET_TCP_ACK+3]);
					#ifdef DEBUG
						USART1_WaitForMUTEX();
						USART1_SetMUTEX();
						USART1_Send(" TCP > ACK > ACK Flag OK",1);
						USART1_Send(" TCP > Rx ACK: ",0);
						USART1_SendInt32(temp);
						USART1_Send(" Int SEQ: ",0);
						USART1_SendInt32(TCP_SEQ_Number);
						USART1_Send_Enter();
						USART1_FreeMUTEX();
					#endif				
					if(temp == (TCP_SEQ_Number))				// Overeni jestli se prijate ACK = Naposledy odeslanemu SEQ + 1
					{
						#ifdef DEBUG
							USART1_WaitForMUTEX();
							USART1_SetMUTEX();
							USART1_Send(" TCP > ACK > ACK Num OK",1);
							USART1_FreeMUTEX();
						#endif
						TCP_LastDataLen=0;
						TCP_Status=TCP_STATE_ESTABLISHED;
						TCPEnableGenerateWWW = 1;				 // Povoli zapisovat data www serveru do bufferu
						Server_Freez=1;							// Zastavi proces serveru (zpracovani dat z ENC)
						#ifdef DEBUG
							USART1_WaitForMUTEX();
							USART1_SetMUTEX();
							USART1_Send("GEN > Server freez=ON",1);
							USART1_Send("GEN > Generate WWW=ON",1);
							USART1_FreeMUTEX();
						#endif
						return(TCP_STATE_ESTABLISHED);
					}
					else										// ACK cislo se neshoduje s ocekavanym => znovuodeslani predchoziho paketu
					{
						#ifdef DEBUG
							USART1_WaitForMUTEX();
							USART1_SetMUTEX();
							USART1_Send(" TCP > ACK > ACK Num Fail",1);
							USART1_FreeMUTEX();
						#endif
						TCP_ReSendPacket();
					}
				}
			}
			else
			{
				#ifdef DEBUG
					USART1_WaitForMUTEX();
					USART1_SetMUTEX();
					USART1_Send(" TCP > Pokus o komunikaci dalsiho klienta odmitnut",1);
					USART1_FreeMUTEX();
				#endif	
			}
			break;
		}
	}
	return(TCP_Status);
}

/* --------------------------------------------------------------
 Funkce pro znovu odeslani naposledy odesilaneho TCP paketu
 vraci 0 pokud byl prekrocen maximalni pocet pokusu o 
 znovuodeslani paketu
 ------------------------------------------------------------- */
uint8_t TCP_ReSendPacket(void)
{
	PokusOZnovuodeslani++;
	if(PokusOZnovuodeslani>TCP_SEND_TRY_COUNT)
	{
		TCP_Init();										// Resetovani TCP spojeni
		#ifdef DEBUG		
			USART1_WaitForMUTEX();
			USART1_SetMUTEX();
			USART1_Send(" TCP > ACK faild -> RESTART connection",1);
			USART1_FreeMUTEX();
		#endif
		return(0);
	}
	/* Znovuodeslani predchoziho TCP paketu */
	ETH_ReSendPAcket(TxBuffer_TCP);						// Znovuodeslani predchoziho paketu
	TCP_Timeout[TCP_TIMEOUTID_ACK] = xTaskGetTickCount();	// Nastaveni Timeoutu
	#ifdef DEBUG
		USART1_WaitForMUTEX();
		USART1_SetMUTEX();
		USART1_Send(" TCP > ReSend last packet",1);
		USART1_FreeMUTEX();
	#endif
	return(1);
}

/* --------------------------------------------------------------
 Funkce pro vkladani dat z FLASH do TCP paketu a jejich odesilani
 po vlozeni vsech dat nebo po naplneni maximalni delky paketu.
 ------------------------------------------------------------- */
uint8_t TCP_AddDataStringFromFLASH(const uint8_t *buffer, uint8_t *RX_buffer, uint8_t *TX_buffer)
{
	uint16_t i=0;
	uint8_t NavratovaHodnota=1;

	/* Nakopirovani dat do odesilaciho bufferu */
	while(buffer[i]!=0x00)
	{
		NavratovaHodnota=TCP_AddDataChar(buffer[i++], RX_buffer, TX_buffer, 0);
	}
	
	return(NavratovaHodnota);
}

/* --------------------------------------------------------------
 Funkce pro vkladani dat do TCP paketu a jejich odesilani
 po vlozeni vsech dat nebo po naplneni maximalni delky paketu.
 ------------------------------------------------------------- */
uint8_t TCP_AddDataString(uint8_t *buffer, uint8_t *RX_buffer, uint8_t *TX_buffer)
{
	uint16_t i=0;
	uint8_t NavratovaHodnota=1;

	/* Nakopirovani dat do odesilaciho bufferu */
	while(buffer[i]!=0x00)
	{
		NavratovaHodnota=TCP_AddDataChar(buffer[i++], RX_buffer, TX_buffer, 0);
	}
	return(NavratovaHodnota);
}

/* --------------------------------------------------------------
 Funkce pro vkladani dat do TCP paketu a jejich odesilani
 po vlozeni vsech dat nebo po naplneni maximalni delky paketu.
 ------------------------------------------------------------- */
uint8_t TCP_AddDataChar(uint8_t znak, uint8_t *RX_buffer, uint8_t *TX_buffer, uint8_t Konec)
{
	
	/* Nakopirovani dat do odesilaciho bufferu */
	if(TCPGenerateStatus!=GENERATE_PROGRESS)
	{
		return 0;
	}
	if(!Konec)													// Pozadavek na okamzite odeslani paketu bez pridavani jakychkoliv dat
	{
		TX_buffer[OFFSET_TCP_Data+PoziceVkladani] = znak;				// Zkopirovani znaku do TCP paketu
	
		PoziceVkladani++;												// Odecteni jednicky protoze predchozi while vzdy vraci delku dat o +1 vetsi
		if(PoziceVkladani<TCP_MAX_DATA_SIZE)							// Paket jeste nebyl uplne naplnen a zatim nebude odeslan
		{			
			return(1);													// Navrat k dalsimu pridavani dat bez cekani
		}																	
		#ifdef DEBUG
			USART1_WaitForMUTEX();
			USART1_SetMUTEX();
			USART1_Send("TCP > Paket plny: ",0);
			USART1_SendInteger(PoziceVkladani);
			USART1_Send_Enter();
			USART1_FreeMUTEX();
		#endif
		TCP_TxTCPPaket(RX_buffer, TX_buffer, PoziceVkladani,0);
		#ifdef DEBUG
			USART1_WaitForMUTEX();
			USART1_SetMUTEX();
			USART1_Send("TCP > odeslano",1);	
			USART1_FreeMUTEX();
		#endif
	}
	else
	{
		#ifdef DEBUG
			USART1_WaitForMUTEX();
			USART1_SetMUTEX();
			USART1_Send("TCP > Velikost dat: ",0);
			USART1_SendInteger(PoziceVkladani);
			USART1_Send_Enter();
			USART1_Send(" -> odesilam posledni",1);	
			USART1_FreeMUTEX();
		#endif
		TCP_TxTCPPaket(RX_buffer, TX_buffer, PoziceVkladani,1);
		#ifdef DEBUG
			USART1_WaitForMUTEX();
			USART1_SetMUTEX();
			USART1_Send("TCP > odeslano",1);	
			USART1_FreeMUTEX();
		#endif
	}
	TCPEnableGenerateWWW = 0;												// Zakaze WWW serveru plnit TCP dalsimi daty
	#ifdef DEBUG
		USART1_WaitForMUTEX();
		USART1_SetMUTEX();
		USART1_Send("GEN > Generate WWW=OFF",1);
		USART1_FreeMUTEX();
	#endif
	while(!TCPEnableGenerateWWW)
	{
		Dummy3++;														// Slouzi pouze k zamestnani procesu aby nedoslo k zatuhnuti tasku
		Dummy3=Dummy3;
		vTaskDelay(1*portTICK_FOR_1MS);
	}
	#ifdef DEBUG
		USART1_WaitForMUTEX();
		USART1_SetMUTEX();
		USART1_Send("GEN > Generate WWW resume",1);
		USART1_FreeMUTEX();
	#endif
	return(0);															// Navrat se zastavenym vkladanim dat dokud se 
																		// TCP_Status nezmeni z TIME_WAIT na ESTABLISHED 
}

/* --------------------------------------------------------------
 Funkce slouzici k odeslani TCP paketu jiz naplneneho daty
 ------------------------------------------------------------- */
void TCP_TxTCPPaket(uint8_t *RX_buffer, uint8_t *TX_buffer, uint16_t TCPDataLen, uint8_t PosledniPaket)
{
	uint16_t i;
	uint8_t destMAC[MAC_ADR_SIZE];
	
	/* Vytvoreni hlavicek paketu a jeho odeslani */	
	for(i=0;i<MAC_ADR_SIZE;i++)
	{
		destMAC[i] = RX_buffer[OFFSET_ETH_SourceMAC+i];						// Nastavi zdrojovou MAC z prichoziho paketu
	}

	ETH_Set_ETH_Header(TX_buffer, destMAC, my_MAC, ETH_Type_IPv4);			// Nastaveni ETH hlavicky pro IP odpoved	
	IP_Set_IP_Header(TX_buffer, IP_Header_len+TCP_Header_lenNoOption+TCPDataLen,		// Nastaveni IP hlavicky
					 0, 0x00, MY_TTL, IP_Protokol_TCP, my_IP, TCP_ClientIP);	
	TCP_ACK_Number = (uint32_t)RX_buffer[OFFSET_TCP_SEQ+0]<<24|
					  (uint32_t)RX_buffer[OFFSET_TCP_SEQ+1]<<16|
					  (uint32_t)RX_buffer[OFFSET_TCP_SEQ+2]<<8|
			 		  (uint32_t)RX_buffer[OFFSET_TCP_SEQ+3];				// Zjisteni prichoziho SEQ cisla (pouzije se jako ACK+1)
	TCP_ACK_Number+=TCP_LastDataLen;

	if(PosledniPaket)
	{
	   	i = TCP_PSH|TCP_ACK|TCP_FIN;
	}
	else
	{
		i = TCP_PSH|TCP_ACK;
	}
	TCP_Set_TCP_Header(TX_buffer, my_HTTP_Port, TCP_ClientPort, 
					   TCP_SEQ_Number, TCP_ACK_Number, i, 0, TCPDataLen);
	enc28j60PacketSend(ETH_Header_len+IP_Header_len+TCP_Header_lenNoOption+TCPDataLen,TX_buffer,TxBuffer_TCP);	// Odeslani paketu
	TCP_SEQ_Number += TCPDataLen;
	if(PosledniPaket)
	{
		TCP_SEQ_Number++;
	}
	else
	PoziceVkladani=0;
	TCP_Status = TCP_STATE_TIME_WAIT;										// Pockani na prijeti ACK od klienta
	TCP_Timeout[TCP_TIMEOUTID_ACK] = xTaskGetTickCount();
	Server_Freez = 0;								// Spusti tento proces serveru
	#ifdef DEBUG
		USART1_WaitForMUTEX();
		USART1_SetMUTEX();
		USART1_Send("GEN > Server freez=OFF",1);
		USART1_FreeMUTEX();
	#endif
}

/* --------------------------------------------------------------
 Funkce pro obsluhu timeoutu TCP spojeni a resetovani TCP stavu
 pokud nejaky z nich vyprsi. Je nutno ji periodicky spoustet!
 ------------------------------------------------------------- */
void TCP_TimeoutProcess(void)
{
	uint32_t AktualniCas;
	
	uint32_t PorovnavanaHodnota=0;
	uint8_t i;

	AktualniCas = xTaskGetTickCount();

	for(i=0;i<TCP_TIMEOUT_COUNT;i++)
	{
		if(TCP_Timeout[i]!=0xFFFFFFFF)					// overeni jestli je mereni timeoutu vubec potreba
		{
			PorovnavanaHodnota=TCP_Timeout[i]+(TimeoutConst[i]);		// Konstanta v jednotce ms
			if(TimeoutPredchoziAktualniCas>AktualniCas)		// Kontrola jestli doslo k preteceni SysTicku
			{
				if(PorovnavanaHodnota>=0xFFFFFFFE)		// Overeni jestli nedoslo k preteceni 24-bitu (ciloveho casu)				
					PorovnavanaHodnota-=0xFFFFFFFE;		// Prepocet na zbytek po preteceni				
			}
			
			if(AktualniCas>=PorovnavanaHodnota)			// Zjisteni jestli uz Timeout vyprsel
			{
				TCP_Timeout[i]=0xFFFFFFFF;				// Vyresetovani timeoutu -> deaktivace
				#ifdef DEBUG
					USART1_WaitForMUTEX();
					USART1_SetMUTEX();
					USART1_Send("TCP > TimeOut ",0);
					USART1_SendNumber(i);
					USART1_Send(" vyresetovan",1);
					USART1_FreeMUTEX();
				#endif
				switch(i)
				{
					case TCP_TIMEOUTID_HANDSHAKE:
					{
						TCP_Init();										// Resetovani TCP spojeni
						#ifdef DEBUG
							USART1_WaitForMUTEX();
							USART1_SetMUTEX();
							USART1_Send("TCP > Handshake TimeOut",1);
							USART1_FreeMUTEX();
						#endif
						break;
					}
					case TCP_TIMEOUTID_CONNECTION:
					{
						TCP_Init();										// Resetovani TCP spojeni
						#ifdef DEBUG
							USART1_WaitForMUTEX();
							USART1_SetMUTEX();
							USART1_Send("TCP > Connection TimeOut",1);
							USART1_FreeMUTEX();
						#endif
						break;
					}
					case TCP_TIMEOUTID_ACK:
					{
						/* Znovuodeslani predchoziho paketu */
						TCP_ReSendPacket();
						break;
					}
					case TCP_TIMEOUTID_FINWAIT2:
					{
						TCP_Init();										// -> uplne ukonceni spojeni
						#ifdef DEBUG
							USART1_WaitForMUTEX();
							USART1_SetMUTEX();
							USART1_Send("TCP > FIN wait 2 TimeOut->konec spojeni",1);
							USART1_FreeMUTEX();
						#endif
						break;
					}
					default:
					{
						#ifdef DEBUG
							USART1_WaitForMUTEX();
							USART1_SetMUTEX();
							USART1_Send("TCP > Nezname TimeOut ID",1);
							USART1_FreeMUTEX();
						#endif
						break;
					}
				}
			}
		}
	}
	TimeoutPredchoziAktualniCas = AktualniCas;									// Ulozeni predesleho aktualniho casu pro potreby detekce preteceni SysTicku
}

/* --------------------------------------------------------------
 Vyplni TCP hlavicku a zapise ji do bufferu TCP paketu
 vcetne vypoctu a zapsani CRC
 ------------------------------------------------------------- */
void TCP_Set_TCP_Header(uint8_t *buffer, uint16_t SourcePort, uint16_t DestPort, uint32_t SEQ_num, uint32_t ACK_num, 
						uint8_t Flags, uint8_t OptionsByte, uint16_t len)
{
// len .... delka uzitecnych dat v TCP paketu
// OptionsByte- 0...Zadne options byty, 1...Pridane options byty
	unsigned int tmp;
	uint16_t CalcWindow = len;
	if(len==0) CalcWindow=65535; 

	// Vyplneni TCP hlavicky	
	buffer[OFFSET_TCP_SourcePort+0] = (SourcePort & 0xFF00)>>8;		// Source port
	buffer[OFFSET_TCP_SourcePort+1] = (SourcePort & 0x00FF);
	buffer[OFFSET_TCP_DestPort+0] = (DestPort & 0xFF00)>>8;			// Destination port
	buffer[OFFSET_TCP_DestPort+1] = (DestPort & 0x00FF);
	buffer[OFFSET_TCP_SEQ+0] = (SEQ_num & 0xFF000000)>>24;			// SEQ number
	buffer[OFFSET_TCP_SEQ+1] = (SEQ_num & 0x00FF0000)>>16;
	buffer[OFFSET_TCP_SEQ+2] = (SEQ_num & 0x0000FF00)>>8;
	buffer[OFFSET_TCP_SEQ+3] = (SEQ_num & 0x000000FF);
	buffer[OFFSET_TCP_ACK+0] = (ACK_num & 0xFF000000)>>24;			// ACK number
	buffer[OFFSET_TCP_ACK+1] = (ACK_num & 0x00FF0000)>>16;
	buffer[OFFSET_TCP_ACK+2] = (ACK_num & 0x0000FF00)>>8;
	buffer[OFFSET_TCP_ACK+3] = (ACK_num & 0x000000FF);
	
	if (OptionsByte==1)												// TCP Header len
	{
		buffer[OFFSET_TCP_DataOffset] = (TCP_Header_lenOption2 & 0xF0);	// Data offset (Maska 0xF0);
		len = len + TCP_Header_lenOption;  					// Paket bez Option bytu
	}
	else
	{	
		buffer[OFFSET_TCP_DataOffset] = (TCP_Header_lenNoOption2 & 0xF0);	// Data offset (Maska 0xF0);
		len = len + TCP_Header_lenNoOption; 				// Paket bez Option bytu
	}	
	buffer[OFFSET_TCP_Flags] = Flags;					  	// Flags
	buffer[OFFSET_TCP_WindowSize+0] = (CalcWindow & 0xFF00)>>8;	// Window size - nastavena fixne na maximum
	buffer[OFFSET_TCP_WindowSize+1] = (CalcWindow & 0x00FF);
	// Checksum se pocita se z Source IP, Dest. IP, TCP Source port, Dest. port, SEQ, ACK, TCP header len,
	// TCP flags, Window size, TCP checksum (vynulovaneho!), urgent pointer, TCP Options a TCP dat (pokud jsou)
	buffer[OFFSET_TCP_CheckSum+0] = 0x00;					// Vynulovani TCP Checksumu
	buffer[OFFSET_TCP_CheckSum+1] = 0x00;
	buffer[OFFSET_TCP_UrgentPointer+0] = 0x00;				// nepouzit
	buffer[OFFSET_TCP_UrgentPointer+1] = 0x00;				// nepouzit	
	if (OptionsByte==1)										// TCP Option bytes
	{
		// Budou pridany Option byty - pro prvni paket na zacatku komunikace (otevirani spojeni)
		// => pakety prenasejici SYN a ACK flagy
		// Option byty musi mit delku N-nasobek 32 bitu (=4 bytu)
		// a aby tomu tak bylo, tak se zbytek co nevychazi vyplni byty NOP (=0x01)
		// +--------+--------+---------+--------+
        // |00000010|00000100|   max seg size   |
        // +--------+--------+---------+--------+
        // Kind=2   Length=4
		buffer[OFFSET_TCP_Options+0] = 0x02;				// Kind = 2
		buffer[OFFSET_TCP_Options+1] = 0x04;				// Kind = 4
		buffer[OFFSET_TCP_Options+2] = 0x05;				// Maximum segment size 1408 (=0x0580)
		buffer[OFFSET_TCP_Options+3] = 0x80;
//		buffer[OFFSET_TCP_Options+4] = 0x01;				// NOP
//		buffer[OFFSET_TCP_Options+5] = 0x01;				// NOP
//		buffer[OFFSET_TCP_Options+6] = 0x01;				// NOP
//		buffer[OFFSET_TCP_Options+7] = 0x01;				// NOP
	}
	else
	{	
		// Option byty nebudou pridany -> odtud start dat (vlozeny funkci TCP_InsertData)
	}	
	tmp = NET_checksum(&buffer[OFFSET_IP_SourceIP], len+8, TCP_TYPE);	// Checksum se pocita i z IP adres, proto je o 8 bytu delsi nez TCP hlavicka + data
	buffer[OFFSET_TCP_CheckSum+0] = (tmp & 0xFF00)>>8;		// Checksum
	buffer[OFFSET_TCP_CheckSum+1] = (tmp & 0x00FF);
}

/* ------------------------------------------------------------------
 Odeslani paketu se synchronizaci (SYN  a ACK)
 ----------------------------------------------------------------- */
void TCP_Send_TCP_syn_ack(uint8_t *RX_buffer, uint8_t *TX_buffer)
{
	uint8_t sourceMAC[MAC_ADR_SIZE];
	uint8_t destMAC[MAC_ADR_SIZE];
	uint8_t sourceIP[IP_ADR_SIZE];
	uint8_t destIP[IP_ADR_SIZE];
	uint16_t DestPort;
	uint32_t SEQNumber;
	uint32_t ACKNumber;
	uint8_t i;	

	// Vytvoreni ETH a IP hlavicky
	for(i=0;i<MAC_ADR_SIZE;i++)
	{
		destMAC[i] = RX_buffer[OFFSET_ETH_SourceMAC+i];			// Nastavi zdrojovou MAC z prichoziho paketu
		sourceMAC[i] = my_MAC[i];								// Jako zdrojovou MAC adresu nastavi lokalni adresu
	}
	for(i=0;i<IP_ADR_SIZE;i++)
	{
		destIP[i] = RX_buffer[OFFSET_IP_SourceIP+i];			// Jako cilovou IP adresu nastavi Zdrojovou IP adresu prijatou v ARP paketu
		sourceIP[i] = my_IP[i];
		TCP_ClientIP[i] = destIP[i];							// Ulozeni IP adresy klienta pro dalsi komunikaci a overovani
	}

	ETH_Set_ETH_Header(TX_buffer, destMAC, sourceMAC, ETH_Type_IPv4);		// Nastaveni ETH hlavicky pro IP odpoved	
	IP_Set_IP_Header(TX_buffer, IP_Header_len+TCP_Header_lenOption,		// Nastaveni IP hlavicky
					 0, 0x00, MY_TTL, IP_Protokol_TCP, sourceIP, destIP);
	DestPort=(uint16_t)RX_buffer[OFFSET_TCP_SourcePort+0]<<8|
			 (uint16_t)RX_buffer[OFFSET_TCP_SourcePort+1];					// Nastaveni ciloveho portu na zdrojovy port v prichozim paketu
	SEQNumber = 0;															// Inicializace SEQ nejakou pocatecni hodnotou = 0 (podle standardu nahodne cislo)
	ACKNumber = (uint32_t)RX_buffer[OFFSET_TCP_SEQ+0]<<24|
				(uint32_t)RX_buffer[OFFSET_TCP_SEQ+1]<<16|
				(uint32_t)RX_buffer[OFFSET_TCP_SEQ+2]<<8|
			 	(uint32_t)RX_buffer[OFFSET_TCP_SEQ+3];						// Zjisteni prichoziho SEQ cisla (pouzije se jako ACK+1)
	ACKNumber++;															// Naviseni ACK o jednicku (potvrzeni potvrzeni prijeti SYN)
	TCP_ClientPort = DestPort;												// Ulozeni vzdaleneho portu klienta pro dalsi komunikaci a overovani
	TCP_Set_TCP_Header(TX_buffer, my_HTTP_Port, DestPort, SEQNumber, ACKNumber, TCP_SYN|TCP_ACK, 1, 0);
	enc28j60PacketSend(ETH_Header_len+IP_Header_len+TCP_Header_lenOption,TX_buffer,1);	// Odeslani ACK a SYNC paketu					   
}

/* ------------------------------------------------------------------
 Odeslani paketu o potvrzeni ukoncovani spojeni (FIN  a ACK)
 ----------------------------------------------------------------- */
void TCP_Send_TCP_fin_ack(uint8_t *RX_buffer, uint8_t *TX_buffer)
{
	uint8_t sourceMAC[MAC_ADR_SIZE];
	uint8_t destMAC[MAC_ADR_SIZE];
	uint8_t sourceIP[IP_ADR_SIZE];
	uint8_t destIP[IP_ADR_SIZE];
	uint16_t DestPort;
	uint32_t SEQNumber;
	uint32_t ACKNumber;
	uint8_t i;	

	// Vytvoreni ETH a IP hlavicky
	for(i=0;i<MAC_ADR_SIZE;i++)
	{
		destMAC[i] = RX_buffer[OFFSET_ETH_SourceMAC+i];			// Nastavi zdrojovou MAC z prichoziho paketu
		sourceMAC[i] = my_MAC[i];								// Jako zdrojovou MAC adresu nastavi lokalni adresu
	}
	for(i=0;i<IP_ADR_SIZE;i++)
	{
		destIP[i] = RX_buffer[OFFSET_IP_SourceIP+i];			// Jako cilovou IP adresu nastavi Zdrojovou IP adresu prijatou v ARP paketu
		sourceIP[i] = my_IP[i];
		TCP_ClientIP[i] = destIP[i];							// Ulozeni IP adresy klienta pro dalsi komunikaci a overovani
	}

	ETH_Set_ETH_Header(TX_buffer, destMAC, sourceMAC, ETH_Type_IPv4);		// Nastaveni ETH hlavicky pro IP odpoved	
	IP_Set_IP_Header(TX_buffer, IP_Header_len+TCP_Header_lenNoOption,		// Nastaveni IP hlavicky
					 0, 0x00, MY_TTL, IP_Protokol_TCP, sourceIP, destIP);
	DestPort=(uint16_t)RX_buffer[OFFSET_TCP_SourcePort+0]<<8|
			 (uint16_t)RX_buffer[OFFSET_TCP_SourcePort+1];					// Nastaveni ciloveho portu na zdrojovy port v prichozim paketu
	SEQNumber = TCP_SEQ_Number+1;												// pouziti soucasne hodnoty SEQ cisla
	ACKNumber = (uint32_t)RX_buffer[OFFSET_TCP_SEQ+0]<<24|
				(uint32_t)RX_buffer[OFFSET_TCP_SEQ+1]<<16|
				(uint32_t)RX_buffer[OFFSET_TCP_SEQ+2]<<8|
			 	(uint32_t)RX_buffer[OFFSET_TCP_SEQ+3];						// Zjisteni prichoziho SEQ cisla (pouzije se jako ACK+1)
	ACKNumber+=TCP_LastDataLen;	
	TCP_Set_TCP_Header(TX_buffer, my_HTTP_Port, DestPort, SEQNumber, ACKNumber, TCP_FIN|TCP_ACK, 0, 0);
	enc28j60PacketSend(ETH_Header_len+IP_Header_len+TCP_Header_lenNoOption,TX_buffer,1);	// Odeslani ACK a SYNC paketu					   
}

/* ------------------------------------------------------------------
 Odesle ACK pro naposledy prijaty byte
 ----------------------------------------------------------------- */
void TCP_Send_TCP_ack(uint8_t *RX_buffer, uint8_t *TX_buffer, uint8_t IncrementAck)
{
	uint8_t sourceMAC[MAC_ADR_SIZE];
	uint8_t destMAC[MAC_ADR_SIZE];
	uint8_t sourceIP[IP_ADR_SIZE];
	uint8_t destIP[IP_ADR_SIZE];
	uint16_t DestPort;
	uint32_t SEQNumber;
	uint32_t ACKNumber;
	uint8_t i;	

	// Vytvoreni ETH a IP hlavicky
	for(i=0;i<MAC_ADR_SIZE;i++)
	{
		destMAC[i] = RX_buffer[OFFSET_ETH_SourceMAC+i];			// Nastavi zdrojovou MAC z prichoziho paketu
		sourceMAC[i] = my_MAC[i];								// Jako zdrojovou MAC adresu nastavi lokalni adresu
	}
	for(i=0;i<IP_ADR_SIZE;i++)
	{
		destIP[i] = RX_buffer[OFFSET_IP_SourceIP+i];			// Jako cilovou IP adresu nastavi Zdrojovou IP adresu prijatou v ARP paketu
		sourceIP[i] = my_IP[i];
		TCP_ClientIP[i] = destIP[i];							// Ulozeni IP adresy klienta pro dalsi komunikaci a overovani
	}

	ETH_Set_ETH_Header(TX_buffer, destMAC, sourceMAC, ETH_Type_IPv4);		// Nastaveni ETH hlavicky pro IP odpoved	
	IP_Set_IP_Header(TX_buffer, IP_Header_len+TCP_Header_lenNoOption,		// Nastaveni IP hlavicky
					 0, 0x00, MY_TTL, IP_Protokol_TCP, sourceIP, destIP);
	DestPort=(uint16_t)RX_buffer[OFFSET_TCP_SourcePort+0]<<8|
			 (uint16_t)RX_buffer[OFFSET_TCP_SourcePort+1];					// Nastaveni ciloveho portu na zdrojovy port v prichozim paketu
	SEQNumber = TCP_SEQ_Number+1;												// pouziti soucasne hodnoty SEQ cisla
	ACKNumber = (uint32_t)RX_buffer[OFFSET_TCP_SEQ+0]<<24|
				(uint32_t)RX_buffer[OFFSET_TCP_SEQ+1]<<16|
				(uint32_t)RX_buffer[OFFSET_TCP_SEQ+2]<<8|
			 	(uint32_t)RX_buffer[OFFSET_TCP_SEQ+3];						// Zjisteni prichoziho SEQ cisla (pouzije se jako ACK+1)
	ACKNumber+=TCP_LastDataLen;
	if(IncrementAck)
		ACKNumber++;															// Naviseni ACK o jednicku (potvrzeni potvrzeni prijeti SYN)	
	TCP_Set_TCP_Header(TX_buffer, my_HTTP_Port, DestPort, SEQNumber, ACKNumber, TCP_ACK, 0, 0);
	enc28j60PacketSend(ETH_Header_len+IP_Header_len+TCP_Header_lenNoOption,TX_buffer,1);	// Odeslani ACK a SYNC paketu
}

/* ------------------------------------------------------------------
 Overeni jestli je prichozi paket typu TCP a jestli se shoduje cislo
 portu s nastavenym portem www serveru
 ----------------------------------------------------------------- */
uint8_t TCP_Check_TCP_WWWPort(uint8_t *buffer, uint16_t WWWPort)
{
	if (buffer[OFFSET_IP_Protokol]==IP_Protokol_TCP && 
		buffer[OFFSET_TCP_DestPort+0]==(0xFF00&WWWPort)>>8 && buffer[OFFSET_TCP_DestPort+1]==(0x00FF&WWWPort))
	{
		return(1);
	}
	return(0);
}

/* Konec souboru */
