
#include "opora.h"
#include "config.h"
#include "ethfunc.h"

const uint16_t MyMAC[3]={0x3412,0x7856,0xBC9A};	//MAC-адрес контроллера
const uint16_t MyIPAddress[2]={0xA8C0,0x5801}; //IP-адрес клиента (наш IP-адрес): 192.168.1.88
const uint16_t RemoteIPAddress[2]={0xA8C0,0x4101};	//IP-адрес на который отправляется ARP-запрос

uint32_t ReplyICMPCounter=0;
uint16_t Identification, SequenceNumber;

_Rec_Frame Frame;
_Remote_Mac Remote_MAC;

void Answear_ARP(void);
void Request_ARP(void);
void PacketAnaliser(void);
uint16_t CheckSum_IP(uint16_t*);
uint16_t CheckSum_ICMP(uint16_t,uint16_t*);
void Answear_ICMP(void);
void Request_ICMP(void);
void RemoteMacInit(void);


void TIMER1_Handler()
{
	static uint32_t Time=5,Sec=0,MilliSec=0,Timeout=TIMEOUT;
	
	TIMER1->STATUS&=0xFFFD;	//сброс события прерывания	
	if(MilliSec++ ==19)
	{
		Sec++;
		MilliSec=0;
	}

	if(Sec==Time)
	{
		if(Remote_MAC.hasMAC!=1)
		{
			Request_ARP();
			Timeout=TIMEOUT;
		}
		else
		{
			Request_ICMP();
			Timeout=TIMEOUT*3;
		}
		Time=Sec+Timeout;
	}
}

int main()
{
	SysTickInit();
	ClkConfig();
	PortConfig();
	RemoteMacInit();
	EthernetConfig();
 	NVIC_EnableIRQ(ETHERNET_IRQn);
	Identification=(uint16_t)SysTick->VAL;
	SequenceNumber=(uint16_t)SysTick->VAL;
	SysTickDisable();
	Timer1Config();
	NVIC_EnableIRQ(TIMER1_IRQn);
	while(1)
	{
		if((ETHERNET->PHY_STATUS&0x02)==0x00)	PORTB->SETTX=1<<15;		//отображение сигнала LINK
		else									PORTB->CLRTX=1<<15;

		if((ETHERNET->PHY_STATUS&0x08)==0x00)	PORTB->SETTX=1<<14;		//Full Duplex Mode
		else									PORTB->CLRTX=1<<14;

		PORTD->RXTX=ReplyICMPCounter<<7;
	}
}

void ETHERNET_Handler()
{
	uint16_t Status;

	Status=ETHERNET->IFR;		
	ETHERNET->IFR=Status;
	Status&=0x101;

	if((Status&0x01)==0x01)
	{
		Frame.Counter=ReadPacket(&Frame);
		PacketAnaliser();
	}
}

//*** Функция разбора полученного пакета
void PacketAnaliser(void)
{
	switch(Frame.Data[6])  //определяем тип следующего протокола
    {
    	case 0x0008:       //протокол IP
			if(Remote_MAC.hasMAC==0) break;//этого не должно быть!
        	if((Frame.Data[15]==MyIPAddress[0])&&(Frame.Data[16]==MyIPAddress[1]))  //сравниваем IP адреса в пакете с нашим
            {                                                                                 //если они совпадают, то занимаемся разбором пакета дальше,                              
            	if(CheckSum_IP(Frame.Data)==Frame.Data[12])   //если контрольные суммы пакета и вычисленная совпадают, продолжаем
                {                                                           //иначе - отбрасываем пакет
                //--------------------ICMP-------------------
                	if((Frame.Data[11]&0xFF00)==0x0100)     //определили следующий протокол: ICMP
                    {
                    	if(Frame.Data[17]==0x0000)        //определили тип - Echo (ping) reply
						{
                        	ReplyICMPCounter++;
						}
                    }
                }
                //-------------------------------------------
            }
            break;

		case 0x0608:      //протокол ARP
			if(Frame.Data[10]!=0x0200) break;	//ARP-reply

			Remote_MAC.RmtMAC[0]=Frame.Data[3];
			Remote_MAC.RmtMAC[1]=Frame.Data[4];
			Remote_MAC.RmtMAC[2]=Frame.Data[5];
			
			Remote_MAC.RmtIP[0]=Frame.Data[14];
			Remote_MAC.RmtIP[1]=Frame.Data[15];

			Remote_MAC.hasMAC=1;
            break;
	}
}

//*** Функция формирования ответа на ARP-запрос
void Answear_ARP(void)
{
	uint16_t Buf[22];
  	Buf[0]=Frame.Data[3];         	//MAC-адрес источника
   	Buf[1]=Frame.Data[4];         	//MAC-адрес источника
   	Buf[2]=Frame.Data[5];         	//MAC-адрес источника
	Buf[3]=ETHERNET->MAC_T;     	//наш MAC-адрес
	Buf[4]=ETHERNET->MAC_M;     	//наш MAC-адрес
	Buf[5]=ETHERNET->MAC_H;     	//наш MAC-адрес
	Buf[6]=Frame.Data[6];         	//type - ARP
	Buf[7]=Frame.Data[7];         	//Hardware type - Ethernet
	Buf[8]=Frame.Data[8];         	//Protocol type - IP
	Buf[9]=Frame.Data[9];         	//Hardware size - 6; Protocol size - 4
	Buf[10]=0x0200;              	//код ответа на запрос Who has...
	Buf[11]=ETHERNET->MAC_T;    	//Sender MAC-address: 0A.1B.2C.3D.4E.5F
	Buf[12]=ETHERNET->MAC_M;    	//Sender MAC-address: 0A.1B.2C.3D.4E.5F
	Buf[13]=ETHERNET->MAC_H;    	//Sender MAC-address: 0A.1B.2C.3D.4E.5F
	Buf[14]=MyIPAddress[0]; 		//My_IP_Address[0];    //Sender IP-address: 192.168.1.87
	Buf[15]=MyIPAddress[1]; 		//My_IP_Address[1];    //Sender IP-address: 192.168.1.87
	Buf[16]=Frame.Data[3];        	//Target MAC-address
	Buf[17]=Frame.Data[4];        	//Target MAC-address
	Buf[18]=Frame.Data[5];        	//Target MAC-address
	Buf[19]=Frame.Data[14];       	//Target IP-address
  	Buf[20]=Frame.Data[15];       	//Target IP-address
	Buf[21]=0;

	SendPacket(Buf,42);
}

//*** Функция для подсчета контрольной суммы пакета IP-протокола
uint16_t CheckSum_IP(uint16_t* Data)
{
        unsigned long a, cs=0;
        for(a=0; a<10; a++)
        {
                if(a == 5) continue;
                else cs = cs + Data[7+a];
        }
        cs = (cs >> 16) + (cs & 0xFFFF);
        return (uint16_t)(~cs);
}

//*** Функция для подсчета контрольной суммы пакета ICMP-протокола
//*** size - кол-во слов, по которому необходимо посчитать контрольную сумму
uint16_t CheckSum_ICMP(uint16_t size, uint16_t* Data)
{
        unsigned long a, cs=0;
        for(a=0;a<size;a++)
        {
                if(a==1) continue;
                else cs+=Data[a+17];
        }
        cs=(cs>>16)+(cs&0xFFFF);
        return (uint16_t)(~cs);
}

//*** Функция для формирования ответа на запрос ICMP
void Answear_ICMP(void)
{
    unsigned long a;
	uint16_t buffer[288];
	uint16_t tmp;
	
	//Кол-во байт в ICMP-пакете
  	tmp=Frame.Counter-34-4;	//34 байта - заголовок Eth2 и IP пакетов, 4 байта - контрольная сумма Eth2 пакета.
	if((tmp&0x01)==1)	
	{
		tmp=(tmp+1)>>1;	//из кол-ва байт получили кол-во слов
		Frame.Data[tmp+16]=Frame.Data[tmp+16]&0x00FF;
	}
	else 				tmp=tmp>>1;		//из кол-ва байт получили кол-во слов
		
	//-------Ethernet 2 Protocol---------
    buffer[0]=Frame.Data[3];
    buffer[1]=Frame.Data[4];
    buffer[2]=Frame.Data[5];

	buffer[3]=ETHERNET->MAC_T;
	buffer[4]=ETHERNET->MAC_M;
	buffer[5]=ETHERNET->MAC_H;

	buffer[6]=Frame.Data[6];
    //-------IP Protocol---------
    for(a=7;a<12;a++)
	{
	    buffer[a]= Frame.Data[a];
    }
    //---------------------------
    buffer[12]=CheckSum_IP(Frame.Data);
	buffer[13]=Frame.Data[15];//IP->DestinAddr[0];
	buffer[14]=Frame.Data[16];//IP->DestinAddr[1];
	buffer[15]=Frame.Data[13];//IP->SourceAddr[0];
	buffer[16]=Frame.Data[14];//IP->SourceAddr[1];
	//-------ICMP Protocol---------
	buffer[17]=0x0000; //ответ
    Frame.Data[17]=0x0000;
	//-----------------------------
	buffer[18]=CheckSum_ICMP(tmp,Frame.Data);
    for(a=19;a<((tmp-2)+19);a++)
	{
    	buffer[a]=Frame.Data[a];
	}
	SendPacket(buffer,(tmp*2+34));		
}

void Request_ARP(void)
{
	uint16_t Buf[22];
  	Buf[0]=0xFFFF;         			//MAC-адрес источника
   	Buf[1]=0xFFFF;         			//MAC-адрес источника
   	Buf[2]=0xFFFF;         			//MAC-адрес источника
	Buf[3]=ETHERNET->MAC_T;     	//наш MAC-адрес
	Buf[4]=ETHERNET->MAC_M;     	//наш MAC-адрес
	Buf[5]=ETHERNET->MAC_H;     	//наш MAC-адрес
	Buf[6]=0x0608;         			//type - ARP
	Buf[7]=0x0100;         			//Hardware type - Ethernet
	Buf[8]=0x0008;         			//Protocol type - IP
	Buf[9]=0x0406;         			//Hardware size - 6; Protocol size - 4
	Buf[10]=0x0100;              	//код запроса ARP
	Buf[11]=ETHERNET->MAC_T;    	//Sender MAC-address
	Buf[12]=ETHERNET->MAC_M;    	//Sender MAC-address
	Buf[13]=ETHERNET->MAC_H;    	//Sender MAC-address
	Buf[14]=MyIPAddress[0]; 		//My_IP_Address[0];
	Buf[15]=MyIPAddress[1]; 		//My_IP_Address[1];
	Buf[16]=0x0000;        			//Target MAC-address
	Buf[17]=0x0000;        			//Target MAC-address
	Buf[18]=0x0000;        			//Target MAC-address
	Buf[19]=RemoteIPAddress[0];		//Target IP-address
  	Buf[20]=RemoteIPAddress[1];		//Target IP-address
	Buf[21]=0;

	SendPacket(Buf,42);
}

void Request_ICMP(void)
{
	uint16_t Buf[37];
	uint8_t tmp[2];
	uint32_t i,j;

//---- Eth2 ----
  	Buf[0]=Remote_MAC.RmtMAC[0];    //MAC-адрес источника
   	Buf[1]=Remote_MAC.RmtMAC[1];    //MAC-адрес источника
   	Buf[2]=Remote_MAC.RmtMAC[2];    //MAC-адрес источника
	Buf[3]=ETHERNET->MAC_T;     	//наш MAC-адрес
	Buf[4]=ETHERNET->MAC_M;     	//наш MAC-адрес
	Buf[5]=ETHERNET->MAC_H;     	//наш MAC-адрес
	Buf[6]=0x0008;         			//type - IP
//---- IP ----
	Buf[7]=0x0045;         			//Version 4, length 20 bytes, Differentiated Services Field 0x00
	Buf[8]=0x3C00;         			//Total length 60 bytes
	Buf[9]=Identification; 			//Identification
	Buf[10]=0x0000;              	//Flag = 0x00, Fragment offset = 0x00
	Buf[11]=0x0180;			    	//Time To Live = 0x80, Protocol = 0x01 - ICMP
	Buf[12]=0x0000;    				//Checksum IP
	Buf[13]=MyIPAddress[0];    		//Source IP-address[0]
	Buf[14]=MyIPAddress[1]; 		//Source IP-address[1]
	Buf[15]=Remote_MAC.RmtIP[0];	//Destination IP-address[0]
	Buf[16]=Remote_MAC.RmtIP[1];   	//Destination IP-address[1]
	Buf[12]=CheckSum_IP(Buf);
//---- ICMP ----
	Buf[17]=0x0008;        			//Type 0x08 (Echo (ping) request), Code 0x00
	Buf[18]=0x0000;		        	//Checksum ICMP
	Buf[19]=0x0002;       			//Identifier
  	Buf[20]=SequenceNumber;       			//Sequence Number

	for(i=0,j=0;i<32;i+=2,j++)
	{
		tmp[0]=0x61+i;
		tmp[1]=0x62+i;

		Buf[j+21]=(tmp[1]<<8)|(tmp[0]);
	}
	Buf[18]=CheckSum_ICMP(20,Buf);
	SendPacket(Buf,74);

	
	tmp[0]=(Identification>>8);
	tmp[1]=Identification;
	if(++tmp[0]==0)	tmp[1]++;
	Identification=(tmp[0]<<8)|tmp[1];

	tmp[0]=(SequenceNumber>>8);
	tmp[1]=SequenceNumber;
	if(++tmp[0]==0)	tmp[1]++;
	SequenceNumber=(tmp[0]<<8)|tmp[1];
}

void RemoteMacInit(void)
{
	Remote_MAC.RmtMAC[0]=0;
	Remote_MAC.RmtMAC[1]=0;
	Remote_MAC.RmtMAC[2]=0;

	Remote_MAC.RmtIP[0]=0;
	Remote_MAC.RmtIP[1]=0;

	Remote_MAC.hasMAC=0;
}
