#include <define.h>						
#include <ENC28J60.h>

// az #include <define.h>	tartalmazza a többi (saját) headert, pl.: SPI.h, USART.h, ADC.h


unsigned char	myIP[4] 			=	{192,	168,	0,		11};
unsigned char	myMAC[6] 			=	{0x00,	0x04,	0xA3,	0xAA,	0xBB,	0xCC};	// Microchip's first 3bytes(OUI) is 00-04-3A

unsigned char 	SourceMAC[6]		=	{0,0,0,0,0,0};
unsigned char 	SourceIP[4]			=	{0,0,0,0};

unsigned char 	DestinationMAC[6]	=	{0,0,0,0,0,0};
unsigned char 	DestinationIP[4]	=	{0,0,0,0};



unsigned int i,x, cnt, temp, tmp, ethertype, transport_layer, package_length;
unsigned char package, RX_BUF[1538]={},TX_BUF[1538]={}, Type[2]={}, Next_Packet_Pointer[2] = {}, Receive_Status_Vector[4] = {};


void ENC28J60_TX_Packet(unsigned char array[], unsigned char control) // control egy vezérlő byte az ENC-nek
{
	if(ENC28J60_RD(ECON1) & TXRTS)
	{
		USART0_TX_String("waiting for TX to complete");
	}
	else
	{
		ENC28J60_BANK_SEL(BANK0);
		ENC28J60_CS();
		ENC28J60_CMD(WCR,EWRPTL);
		SPIWR(0);
		SPIWR(16);
		ENC28J60_DS();

		ENC28J60_CS();
		SPIWR(WBM);
		SPIWR(control);
		for(i=0;i<package_length;i++)
		{
			SPIWRD(array[i]);
		}
		ENC28J60_DS();
		
		ENC28J60_CS();
		ENC28J60_CMD(WCR,ETXNDL);
		SPIWR(i);
		SPIWR(16);
		ENC28J60_DS();
		
		ENC28J60_BFS(TXRTS);
	}
}

void ENC28J60_RX_Packet(unsigned char array[])
{
	ENC28J60_CS();
	SPIWR(RBM);
	//	reading next packet pointer (NPP) and Recieve Status Vector (RSV)
	Next_Packet_Pointer[0]		=	SPIWRD(DUMMY);
	Next_Packet_Pointer[1]		=	SPIWRD(DUMMY);
	Receive_Status_Vector[0]	=	SPIWRD(DUMMY);
	Receive_Status_Vector[1]	=	SPIWRD(DUMMY);
	Receive_Status_Vector[2]	=	SPIWRD(DUMMY);
	Receive_Status_Vector[3]	=	SPIWRD(DUMMY);
	
	package_length=((Receive_Status_Vector[1]<<8)+Receive_Status_Vector[0]);					//	merging RSV byte 0 and 1 into integer (Byte Count)
	if(package_length%2 != 0)																//	if it's odd
	{
		package_length++;																	//	add +1
	}
	for(i = 0;i<package_length;i++)
	{
		array[i]	=	SPIWRD(DUMMY);
	}
	ENC28J60_DS();
	
	ENC28J60_CS();
	ENC28J60_CMD(BFS,ECON2);
	SPIWR(PKTDEC);
	ENC28J60_DS();
	
	ENC28J60_BANK_SEL(BANK0);
	ENC28J60_CS();
	ENC28J60_CMD(WCR,ERXRDPTL);
	SPIWR(Next_Packet_Pointer[0]);												//	ERXRDPTL
	SPIWR(Next_Packet_Pointer[1]);												//	ERXRDPTH
	ENC28J60_DS();
}

void MAC_Frame(unsigned char array[], unsigned int type)
{
	for(i=0;i<6;i++)
	{
		array[i] =	DestinationMAC[i];
	}
	for(i=6;i<12;i++)
	{
		array[i] =	myMAC[i-6];
	}
	array[12] = type>>8;
	array[13] = type;
	package_length = 14;
}

void CheckSum(unsigned char array[], unsigned int type)
{
	//	http://en.wikipedia.org/wiki/IPv4#Header_Checksum
	//	http://en.wikipedia.org/wiki/IPv4_header_checksum
	
	unsigned long int checksum = 0;
	unsigned int y = 0;
	if(type == ICMPv4)
	{
		i = 34;					//	ICMPv4 frame kezdete a csomagban
		y = 74;					//	ill a frame vége
	}
	else if(type == IPv4)
	{
		i = 14;					//	IPv4 frame kezdete a csomagban
		y = 34;					//	ill a frame vége
	}
	
	//	checksum printelése	{
	USART0_TX_String("Checksum:	");
	itoa(checksum, StringA, 16);
	USART0_TX_String(StringA);
	USART0_TXD(13);
	USART0_TXD(10);
	//	checksum printelése }
	
	for(i=i;i<y;i+=2)
	{
		checksum += ((array[i]<<8) | array[i+1]);					// a for ciklusban csak ez a lényeg
		//checksum += array[i+1];
		
		// az adott 2 byte (array[i] és array[i+1]) printelése	{
		USART0_TX_String("byte:	");
		itoa(i, StringA, 10);
		USART0_TX_String(StringA);
		USART0_TXD(9);
		
		if(array[i] < 0x10)
		{
			USART0_TX_String("0");
		}
		itoa(array[i], StringA, 16);
		USART0_TX_String(StringA);
		if(array[i+1] < 0x10)
		{
			USART0_TX_String("0");
		}
		itoa(array[i+1], StringA, 16);
		USART0_TX_String(StringA);
		USART0_TXD(9);
		ltoa(checksum, StringA, 16);
		USART0_TX_String(StringA);
		USART0_TXD(13);
		USART0_TXD(10);
		// az adott 2 byte (array[i] és array[i+1]) printelése	}

	}
	
	//	checksum printelése felosztva 2db integeré	{
	USART0_TX_String("Checksum_L:	");
	itoa((checksum), StringA, 16);
	USART0_TX_String(StringA);
	USART0_TXD(13);
	USART0_TXD(10);
	USART0_TX_String("Checksum_H:	");
	itoa((checksum>>16), StringA, 16);
	USART0_TX_String(StringA);
	USART0_TXD(13);
	USART0_TXD(10);
	//	checksum printelése felosztva 2db integeré	}
	
	//	long int konvertálása sima int-é, majd az érték invertálása
	checksum = ((checksum & 0x0000FFFF) + ((checksum>>16) & 0x0000FFFF));
	checksum = ~checksum;
	
	
	USART0_TX_String("Checksum:	");
	ltoa(checksum, StringA, 16);
	USART0_TX_String(StringA);
	USART0_TXD(13);
	USART0_TXD(10);
	
	//	 a kapott checksum beilesztése
	if(type == IPv4)
	{
		checksum -=2;						//	 IPv4 esetén egy kompenzálás/foltozás
		array[24] = (checksum>>8);
		array[25] = checksum;
	}
	
	else if(type == ICMPv4)
	{
		array[36] = (checksum>>8);
		array[37] = checksum;
	}
}

void IPv4_Frame(unsigned char array[])
{
	array[14] = 0x45;						//	Version and IHL
	array[15] = 0x00;						//	DSCP and ECN
	array[16] = 0x00;						//	Total Length
	array[17] = 0x3c;						//	Total Length
	array[18] = RX_BUF[18];				//	Identification
	array[19] = RX_BUF[19];				//	Identification
	array[20] = 0x00;						//	Flags and Fragments
	array[21] = 0x00;						//	Fragments
	array[22] = 0x40;						//	Time To Live
	array[23] = 0x01;						//	Protocol
	array[24] = 0x00;						//	Header Checksum
	array[25] = 0x00;						//	Header Checksum
	
	for(i=26;i<30;i++)
	{
		array[i] = myIP[i-26];				//	Sender Hardware Address
	}
	
	for(i=30;i<34;i++)
	{
		array[i] = DestinationIP[i-30];	//	Sender Hardware Address
	}
	CheckSum(array,IPv4);					//	CheckSum rutin meghívása itt
	
	package_length = 34;
}

void ARP_Frame(unsigned char array[])
{
	array[14] = 0;							//	Hardware Type
	array[15] = 1;							//	Hardware Type
	array[16] = 8;							//	Protocol Type
	array[17] = 0;							//	Protocol Type
	array[18] = 6;							//	Hardware Address Length
	array[19] = 4;							//	Protocol Address Length
	array[20] = 0;							//	Operation
	array[21] = 2;							//	Operation
	
	for(i=22;i<29;i++)
	{
		array[i] = myMAC[i-22];			//	Sender Hardware Address
	}
	
	for(i=28;i<32;i++)
	{
		array[i] = myIP[i-28];				//	Sender Protocol Address
	}
	
	for(i=32;i<38;i++)
	{
		array[i] = DestinationMAC[i-32];	//	Target Hardware Address
	}
	
	for(i=38;i<42;i++)
	{
		array[i] = DestinationIP[i-38]; 	//	Target Protocol Address
	}
	package_length = 42;
}

void ICMP_Frame(unsigned char array[])
{
	array[34] = 0;				//	Type
	array[35] = 0;				//	Code
	array[36] = 0;				//	Checksum
	array[37] = 0;				//	Checksum
	array[38] = RX_BUF[38];	//	ID
	array[39] = RX_BUF[39];	//	ID
	array[40] = RX_BUF[40];	//	Seq
	array[41] = RX_BUF[41];	//	Seq
	
	for(i=42;i<74;i++)
	{
		array[i] = RX_BUF[i];
	}
	
	CheckSum(array,ICMPv4);		//	CheckSum rutin meghívása itt
	package_length = 74;
}

void Process_Package(unsigned char array[])					// array[] ez itt a RX_BUF[]
{
	ethertype = ((array[12]<<8)+array[13]);
	if(ethertype == ARP)
	{
		for(unsigned char a = 0;a<4;a++)
		{
			DestinationIP[a] = array[a+38];
		}
		if(DestinationIP[0] == myIP[0] && DestinationIP[1] == myIP[1] && DestinationIP[2] == myIP[2] && DestinationIP[3] == myIP[3])
		{
			for(unsigned char a = 0;a<6;a++)
			{
				DestinationMAC[a]	= array[a+6];
			}
			for(unsigned char a = 0;a<4;a++)
			{
				DestinationIP[a] = array[a+28];
			}
			MAC_Frame(TX_BUF,ARP);
			ARP_Frame(TX_BUF);
			ENC28J60_TX_Packet(TX_BUF,0);				//	csoamg küldése
		}
	}
	
	else if(ethertype == IPv4)
	{
		for(unsigned char a = 0;a<4;a++)
		{
			DestinationIP[a] = array[a+30];
		}
		if(DestinationIP[0] == myIP[0] && DestinationIP[1] == myIP[1] && DestinationIP[2] == myIP[2] && DestinationIP[3] == myIP[3])
		{
			for(unsigned char a = 0;a<4;a++)
			{
				DestinationIP[a] = array[a+26];
			}
			for(unsigned char a = 0;a<6;a++)
			{
				DestinationMAC[a] = array[a+6];
			}
			
			MAC_Frame(TX_BUF,IPv4);
			IPv4_Frame(TX_BUF);						//	CheckSum rutin használata itt (itt nem jó)
			
			transport_layer = array[23];
			if(transport_layer == TCP)
			{
				
			}
			
			else if(transport_layer == UDP)
			{
				
			}
			
			else if(transport_layer == ICMPv4)
			{
				ICMP_Frame(TX_BUF);					//	CheckSum rutin és itt (itt ok)
				ENC28J60_TX_Packet(TX_BUF,0);		//	csoamg küldése
			}
		}
	}
	
	else if(ethertype == IPv6)
	{
		if(transport_layer == ICMPv6)
		{
			
		}
	}
	
}

int main (void)
{
/*
AVR clock Prescaler,UART, SPI, ENC28J60 Inicializálások (ezek jók)
*/
	
	while(1)
	{

		ENC28J60_BANK_SEL(BANK1);					//	BANK1 oszlop kiválasztása az ENC-n
		package = ENC28J60_RD(EPKTCNT);				//	olvasatlan csomagok száma
		if(package!=0)								//	van-e olvasatlan csomag
		{
			ENC28J60_RX_Packet(RX_BUF);				//	csomag beolvasása
			Process_Package(RX_BUF);				//	csomag feldolgozása
		}
	}
}
