#include "LPC17xx.h"
#include "timer.h"

#define MR 					0x0000	
#define IR 					0x0002
#define IMR 			    0x0004
#define SHAR				0x0008
#define SHAR2				0x000A
#define SHAR4				0x000C
#define GAR					0x0010
#define GAR2				0x0012
#define SUBR				0x0014
#define SUBR2				0x0016
#define SIPR				0x0018
#define SIPR2				0x001A
#define TMS01R			0x0020		
#define TMS23R			0x0022		
#define TMS45R			0x0024		
#define TMS67R			0x0026		
#define RMS01R      0x0028
#define RMS23R      0x002A   /**< Refer to RMS01R. */
#define RMS45R      0x002C   /**< Refer to RMS01R. */
#define RMS67R      0x002E   /**< Refer to RMS01R. */
#define MTYPER      0x0030 

#define S0_MR           0x0200  
#define S1_MR 0x0240
#define S0_CR           0x0202  
#define S1_CR 0x0242
#define S0_IMR          0x0204  
#define S0_IR           0x0206  
#define S1_IR 0x0246 
#define S0_SSR          0x0208  
#define S1_SSR 0x0248 
#define S0_PORTR        0x020A  
#define S1_PORTR        0x024A
#define S0_DHAR         0x020C  
#define S0_DHAR2        0x020E
#define S0_DHAR4        0x0210
#define S0_DPORTR       0x0212  
#define S0_DIPR         0x0214  
#define S0_DIPR2        0x0216
#define S0_PROTOR       0x021A  
#define S0_TX_WRSR      0x0220  
#define S0_TX_WRSR2     0x0222
#define S0_TX_FSR       0x0224  
#define S0_TX_FSR2      0x0226
#define S0_TX_FIFOR     0x022E  
#define S0_RX_RSR       0x0228  
#define S0_RX_RSR2      0x022A
#define S0_RX_FIFOR     0x0230  

#define OPEN 0x0001
#define CLOSE 0x0010
#define RECV 0x0040

#define SOCK_CLOSED 0x0000
#define SOCK_UDP 0x0022
#define SOCK_IPRAW 0x0032
#define SOCK_MACRAW 0x0042

#define	MAX_SOCK_NUM		8

#define UDP_port 5000 //5000
#define UDP_max_size 508 //1432

#define DIR(port,offset,pins) LPC_GPIO##port->FIODIR |= (pins<<offset)
#define DIR_CLR(port,offset,pins) LPC_GPIO##port->FIODIR &= ~(pins<<offset)
#define OUT_VAL(port,offset,pins) LPC_GPIO##port->FIOPIN |= (pins<<offset)
#define CLR_VAL(port,offset,pins) LPC_GPIO##port->FIOPIN &= ~(pins<<offset)
#define IN_VAL(port,offset,pins) (LPC_GPIO##port->FIOPIN)&(pins<<offset)
#define SET_PIN(port,pin) LPC_GPIO##port->FIOSET |= (1<<pin)
#define CLR_PIN(port,pin) LPC_GPIO##port->FIOCLR |= (1<<pin)
#define RD_PIN(port,pin) (LPC_GPIO##port->FIOPIN)&(1<<pin)

#define POW(out)   (out)?(SET_PIN(4,28)):(CLR_PIN(4,28))   //POWER ON/OFF WIZNET (output)
#define WR(out)    (out)?(SET_PIN(1,18)):(CLR_PIN(1,18))   //WRITE ENABLE (output)
#define RD(out)    (out)?(SET_PIN(3,25)):(CLR_PIN(3,25))   //READ ENABLE  (output)
#define CS(out)    (out)?(SET_PIN(3,26)):(CLR_PIN(3,26))   //CHIP SELECT  (output)
#define INT        (RD_PIN(0,27))?(1):(0)                  //INTERRUPT (input) 
#define RESET(out) (out)?(SET_PIN(1,31)):(CLR_PIN(1,31))   //Hardware Reset Signal (output)
#define B16EN(out) (out)?(SET_PIN(1,29)):(CLR_PIN(1,29))   //16/8 BIT DATA BUS SELECT  (output) 
#define BRDY       (IN_VAL(0,23,0xf)>>23)                  //Buffer Ready Indicator (input)
       
#define DATA0(out)  (out&0xFF)?(OUT_VAL(0,4,out)):(CLR_VAL(0,4,0xFF))       //System low data bus [0-7]: P0.4-P0.11 (in/out)
#define DATA1(out)  (out&0xFF)?(OUT_VAL(0,15,out)):(CLR_VAL(0,15,0xFF))     //System high data bus [8-15]: P0.15-P0.22 (in/out)
#define DATA16(out) (out&0xFFFF)?(LPC_GPIO0->FIOPIN |= ((((uint32_t)out&0x00FF)<<4)|(((uint32_t)out&0xFF00)<<7))):(LPC_GPIO0->FIOPIN &= 0xFF80700F)
#define DATA        ((IN_VAL(0,4,0xFF))>>4)|((IN_VAL(0,15,0xFF))>>7)
#define ADDR(out)   (out&0x3FF)?(OUT_VAL(1,19,out)):(CLR_VAL(1,19,0x3FF))   //System address bus [1-15]: P1.19-P1.28 (output)

uint32_t TXMEM_SIZE[MAX_SOCK_NUM];
uint32_t RXMEM_SIZE[MAX_SOCK_NUM];

uint8_t udp_data[UDP_max_size];

void WriteReg (uint16_t Addr, uint16_t Data)
{ 
	ADDR(Addr);
    DATA16(Data);
	CS(0); WR(0); 	// WR+CS = 0
	__NOP();
	CS(1); WR(1);  	// WR+CS = 1
	ADDR(0);
 	LPC_GPIO0->FIOPIN &= 0xFF80700F; 
}

uint16_t ReadReg (uint16_t Addr)
{
	uint16_t data;
	DIR_CLR(0,4,0xFF);	DIR_CLR(0,15,0xFF);   
	ADDR(Addr);
	CS(0); RD(0); 	// RD+CS = 0
	__NOP();
    __NOP();
    data = DATA; 
	CS(1); RD(1);	 // RD+CS = 1
	ADDR(0);
	DIR(0,4,0xFF);	DIR(0,15,0xFF);	
	return (data);
}

void Init (void)
{
  /* SystemClockUpdate() updates the SystemFrequency variable */
  SystemClockUpdate();

  DIR(0,4,0xFF); DIR(0,15,0xFF);
  DIR(1,19,0x3FF);
  DIR_CLR(0,23,0xf);  
  DIR(1,18, 1);
  DIR(3,25, 1);
  DIR(3,26, 1);
  DIR(1,31, 1);
  DIR(1,29, 1);
  DIR(4,28, 1);
  DIR_CLR(0,27,1);

  POW(1);				
  B16EN(1);
  WR(1);
  RD(1);
  CS(1); 
  RESET(1); 
}

uint8_t    socket_udp(uint16_t port)
{
   WriteReg(S0_MR,0x02); // set Sn_MR with protocol & flag
   WriteReg(S0_PORTR, port);
   
   WriteReg(S0_CR, OPEN);         // open s-th SOCKET 
   while(ReadReg(S0_CR));
   
   return 1;   
}

void close_soc(void)
{
   ////////////////////////////////   
   WriteReg (S0_IR, 0x00FF); //setSn_IR(s ,0x00FF);          // Clear the remained interrupt bits.
   WriteReg (S0_CR, CLOSE); //setSn_CR(s ,Sn_CR_CLOSE);     // Close s-th SOCKET     
   while(ReadReg(S0_CR));    
}

uint8_t    sysinit(uint8_t* tx_size, uint8_t* rx_size)
{
   uint16_t i;
   uint16_t ssum=0,rsum=0;
   unsigned int mem_cfg = 0;
   
   for(i=0; i < MAX_SOCK_NUM; i++)
   {
      if(tx_size[i] > 64)
      {
         return 0;
      }
      if(rx_size[i] > 64)
      {
         return 0;
      }
      ssum += (uint16_t)tx_size[i];
      rsum += (uint16_t)rx_size[i];
      TXMEM_SIZE[i] = ((uint32_t)tx_size[i]) << 10;
      RXMEM_SIZE[i] = ((uint32_t)rx_size[i]) << 10;
   }
   if( (ssum % 8) || ((ssum + rsum) != 128) )
   {
      return 0;
   }
   
   WriteReg(TMS01R,((uint16_t)tx_size[0] << 8) + (uint16_t)tx_size[1]);
   WriteReg(TMS23R,((uint16_t)tx_size[2] << 8) + (uint16_t)tx_size[3]);
   WriteReg(TMS45R,((uint16_t)tx_size[4] << 8) + (uint16_t)tx_size[5]);
   WriteReg(TMS67R,((uint16_t)tx_size[6] << 8) + (uint16_t)tx_size[7]);
   
   WriteReg(RMS01R,((uint16_t)rx_size[0] << 8) + (uint16_t)rx_size[1]);
   WriteReg(RMS23R,((uint16_t)rx_size[2] << 8) + (uint16_t)rx_size[3]);
   WriteReg(RMS45R,((uint16_t)rx_size[4] << 8) + (uint16_t)rx_size[5]);
   WriteReg(RMS67R,((uint16_t)rx_size[6] << 8) + (uint16_t)rx_size[7]);
   
   for(i=0; i <ssum/8 ; i++)
   {
      mem_cfg <<= 1;
      mem_cfg |= 1;
   }
   
   WriteReg(MTYPER,mem_cfg);
    
   return 1;
}

void Resive_UDP_pocket (void)
{
uint16_t dest_port, pack_size, idx, temp, i,j;
uint8_t dest_ip[4];//, udp_data[UDP_max_size];

temp = ReadReg(S0_RX_FIFOR); /* extract destination IP address from internal RX memory */
dest_ip[0] = ((temp & 0xFF00) >> 8);
dest_ip[1] = (temp & 0x00FF);
temp = ReadReg(S0_RX_FIFOR);
dest_ip[2] = ((temp & 0xFF00) >> 8);
dest_ip[3] = (temp & 0x00FF);
dest_port = S0_RX_FIFOR; /* extract destination port number from internal RX memory */
pack_size = S0_RX_FIFOR; /* extract length of DAT packet from internal RX memory */
/* calculate the read count of Sn_RX_FIFOR */

while (pack_size)
{
  temp = ReadReg(S0_RX_FIFOR);
  udp_data[i] = ((temp & 0xFF00) >> 8);
  udp_data[i+1] = (temp & 0x00FF);       /* data_buf is array of 16bit */
  pack_size-=2;
  i+=2;
}
/* set RECV command */
WriteReg (S0_CR, RECV);
}

void UDP_session(uint16_t SSreg)
{
 switch(SSreg&0xff)
   {
                                                         // -------------------------------
      case SOCK_UDP:                                     // 
         Resive_UDP_pocket();
         break;
                                                         // -----------------
      case SOCK_CLOSED:                                  // CLOSED
         close_soc();                                       // close the SOCKET
         //delay_us(10);
         socket_udp(UDP_port);                  // open the SOCKET with UDP mode
         break;
      default:
         break;
   }
}

int main(void)
{
   uint8_t tx_mem_conf[8] = {8,8,8,8,8,8,8,8};          // for setting TMSR regsiter
   uint8_t rx_mem_conf[8] = {8,8,8,8,8,8,8,8};          // for setting RMSR regsiter
 
	Init();
   
	RESET(0);
	delay_us(0,10);		
	RESET(1);
	delay_us (0,5000);	

  if(!sysinit(tx_mem_conf,rx_mem_conf))           
   {
      while(1);
   }

#if 1
	//МАС-addr W5300:  00.08.220.17.02.03
	WriteReg (SHAR, 0x0008);
	WriteReg (SHAR2, 0xDC11);
	WriteReg (SHAR4, 0x0203);
	//IP-addr GW: 10.10.20.1
	WriteReg (GAR, 0x0A0A);  
	WriteReg (GAR2, 0x1401); 
	//Mask:     255.255.255.0
	WriteReg (SUBR, 0xFFFF);
	WriteReg (SUBR2, 0xFF00);
	// IP-addr W5300: 10.10.20.80
	WriteReg (SIPR, 0x0A0A);  
	WriteReg (SIPR2, 0x1450); 
#endif

#if 0
  do{
    WriteReg(S0_MR, 0x0004); /* sets MACRAW mode */
    WriteReg(S0_CR, 0x0001); /* sets OPEN command */
    temp1 = ReadReg(S0_SSR);
  } while(temp1 != 0x0042);

	while (1) {}	
#else    
  
  while (1)
  {
   UDP_session(ReadReg (S0_SSR));
   delay_us(10);
  }
#endif
}
