/*
 * socket.c
 *
 * Created: 14/08/2018 9:41:39
 *  Author: Ledo
 */ 

#include "socket.h"
#include "W5200.h"

uint8_t incr_windowfull_retry_cnt(uint8_t s)
{
	return windowfull_retry_cnt[s]++;
}

void init_windowfull_retry_cnt(uint8_t s)
{
	windowfull_retry_cnt[s] = 0;
}

uint8_t getISR(uint8_t s)
{
	return I_STATUS[s];
}
void putISR(uint8_t s, uint8_t val)
{
	I_STATUS[s] = val;
}

uint16_t getIINCHIP_RxMAX(uint8_t s)
{
	return RSIZE[s];
}
uint16_t getIINCHIP_TxMAX(uint8_t s)
{
	return SSIZE[s];
}
uint16_t getIINCHIP_RxMASK(uint8_t s)
{
	return RMASK[s];
}
uint16_t getIINCHIP_TxMASK(uint8_t s)
{
	return SMASK[s];
}
uint16_t getIINCHIP_RxBASE(uint8_t s)
{
	return RBUFBASEADDRESS[s];
}

uint16_t getIINCHIP_TxBASE(uint8_t s)
{
	return SBUFBASEADDRESS[s];
}


/**
@brief	This function writes into W5200 memory(Buffer)
*/
uint16_t wiz_write_buf(uint16_t addr,uint8_t* buf,uint16_t len)
{
	uint16_t idx = 0;
	
	InterruptDisable();
	
	if(len == 0)
	{
		//printf("len is '0'\r\n");
		return 0;
	}
	
	//SPI MODE I/F
	IINCHIP_CS_low();                                        // CS=0, SPI start
	
	IINCHIP_SpiSendData(((addr+idx) & 0xFF00) >> 8);        // Address byte 1
	IINCHIP_SpiSendData((addr+idx) & 0x00FF);               // Address byte 2
	IINCHIP_SpiSendData((0x80 | ((len & 0x7F00) >> 8)));    // Data write command and Write data length 1
	IINCHIP_SpiSendData((len & 0x00FF));                    // Write data length 2
	for(idx = 0; idx < len; idx++)                          // Write data in loop
	{
		IINCHIP_SpiSendData(buf[idx]);
	}
	
	IINCHIP_CS_high();                                         // CS=1, SPI end
	
	InterruptEnable();                                  // Interrupt Service Routine Enable
	return len;
}


/**
@brief	This function reads from W5200 memory(Buffer)
*/
uint16_t wiz_read_buf(uint16_t addr, uint8_t* buf,uint16_t len)
{
	uint16_t idx = 0;
	
	InterruptDisable();                                  // Interrupt Service Routine Disable
	
	IINCHIP_CS_low();                                        // CS=0, SPI start
	
	IINCHIP_SpiSendData(((addr) & 0xFF00) >> 8);        // Address byte 1
	IINCHIP_SpiSendData((addr) & 0x00FF);               // Address byte 2
	IINCHIP_SpiSendData((0x00 | ((len & 0x7F00) >> 8)));    // Data read command
	IINCHIP_SpiSendData((len & 0x00FF));

	for(idx = 0; idx < len; idx++)                          // Read data in loop
	{
		buf[idx] = IINCHIP_SpiSendData(0x00);
	}
	
	IINCHIP_CS_high();                                         // CS=0, SPI end
	
	InterruptEnable();                                 // Interrupt Service Routine Enable
	return len;
}

/**
 Retransmittion 
 **/
 
/**
@brief	This function sets up Retransmission time.
If there is no response from the peer or delay in response then retransmission 
will be there as per RTR (Retry Time-value Register)setting
*/
void setRTR(uint16_t timeout)
{
	IINCHIP_WRITE(RTR,(uint8_t)((timeout & 0xff00) >> 8));
	IINCHIP_WRITE((RTR + 1),(uint8_t)(timeout & 0x00ff));
}

/**
@brief	This function set the number of Retransmission.

If there is no response from the peer or delay in response then recorded time 
as per RTR & RCR register seeting then time out will occur.
*/
void setRCR(uint8_t retry)
{
	IINCHIP_WRITE(RCR,retry);
}


/**
@brief	This sets the maximum segment size of TCP in Active Mode), while in Passive Mode this is set by peer
*/
void setSn_MSS(SOCKET s, uint16_t Sn_MSSR0)
{
	IINCHIP_WRITE(Sn_MSSR0(s),(uint8_t)((Sn_MSSR0 & 0xff00) >> 8));
	IINCHIP_WRITE((Sn_MSSR0(s) + 1),(uint8_t)(Sn_MSSR0 & 0x00ff));
}

void setSn_TTL(SOCKET s, uint8_t ttl)
{
   IINCHIP_WRITE(Sn_TTL(s), ttl);
}


/**
@brief	These below function is used to setup the Protocol Field of IP Header when
		executing the IP Layer RAW mode.
*/
void setSn_PROTO(SOCKET s, uint8_t proto)
{
	IINCHIP_WRITE(Sn_PROTO(s),proto);
}


/**
@brief	get socket interrupt status

These below functions are used to read the Interrupt & Soket Status register
*/
uint8_t getSn_IR(SOCKET s)
{
	return IINCHIP_READ(Sn_IR(s));
}


/**
@brief	 get socket status
*/
uint8_t getSn_SR(SOCKET s)
{
	return IINCHIP_READ(Sn_SR(s));
}


/**
@brief	get socket TX free buf size

This gives free buffer size of transmit buffer. This is the data size that user can transmit.
User shuold check this value first and control the size of transmitting data
*/
uint16_t getSn_TX_FSR(SOCKET s)
{
	uint16_t val=0,val1=0;
	do
	{
		val1 = IINCHIP_READ(Sn_TX_FSR0(s));
		val1 = (val1 << 8) + IINCHIP_READ(Sn_TX_FSR0(s) + 1);
		if (val1 != 0)
		{
			val = IINCHIP_READ(Sn_TX_FSR0(s));
			val = (val << 8) + IINCHIP_READ(Sn_TX_FSR0(s) + 1);
		}
	} while (val != val1);
	return val;
}


/**
@brief	 get socket RX recv buf size

This gives size of received data in receive buffer.
*/
uint16_t getSn_RX_RSR(SOCKET s)
{
	uint16_t val=0,val1=0;
	do
	{
		val1 = IINCHIP_READ(Sn_RX_RSR0(s));
		val1 = (val1 << 8) + IINCHIP_READ(Sn_RX_RSR0(s) + 1);
		if(val1 != 0)
		{
			val = IINCHIP_READ(Sn_RX_RSR0(s));
			val = (val << 8) + IINCHIP_READ(Sn_RX_RSR0(s) + 1);
		}
	} while (val != val1);
	return val;
}



/**
@brief	 This function is being called by send() and sendto() function also. 

This function read the Tx write pointer register and after copy the data in buffer update the Tx write pointer
register. User should read upper byte first and lower byte later to get proper value.
*/
void send_data_processing(SOCKET s, uint8_t *data, uint16_t len)
{
	
	uint16_t ptr;
	ptr = IINCHIP_READ(Sn_TX_WR0(s));
	ptr = (ptr << 8) + IINCHIP_READ(Sn_TX_WR0(s) + 1);
	write_data(s, data, (uint8_t *)(ptr), len);
	ptr += len;

	IINCHIP_WRITE(Sn_TX_WR0(s),(uint8_t)((ptr & 0xff00) >> 8));
	IINCHIP_WRITE((Sn_TX_WR0(s) + 1),(uint8_t)(ptr & 0x00ff));
	
}


/**
@brief	This function is being called by recv() also.

This function read the Rx read pointer register
and after copy the data from receive buffer update the Rx write pointer register.
User should read upper byte first and lower byte later to get proper value.
*/
void recv_data_processing(SOCKET s, uint8_t *data, uint16_t len)
{
	uint16_t ptr;
	ptr = IINCHIP_READ(Sn_RX_RD0(s));
	ptr = ((ptr & 0x00ff) << 8) + IINCHIP_READ(Sn_RX_RD0(s) + 1);
	read_data(s, (uint8_t *)ptr, data, len); // read data
	ptr += len;
	IINCHIP_WRITE(Sn_RX_RD0(s),(uint8_t)((ptr & 0xff00) >> 8));
	IINCHIP_WRITE((Sn_RX_RD0(s) + 1),(uint8_t)(ptr & 0x00ff));
}


/**
@brief	for copy the data form application buffer to Transmite buffer of the chip.

This function is being used for copy the data form application buffer to Transmite
buffer of the chip. It calculate the actual physical address where one has to write
the data in transmite buffer. Here also take care of the condition while it exceed
the Tx memory uper-bound of socket.
*/
void write_data(SOCKET s, volatile uint8_t * src, volatile uint8_t * dst, uint16_t len)
{
	uint16_t size;
	uint16_t dst_mask;
	uint8_t * dst_ptr;

	dst_mask = (uint32_t)dst & getIINCHIP_TxMASK(s);
	dst_ptr = (uint8_t *)(getIINCHIP_TxBASE(s) + dst_mask);
	
	if (dst_mask + len > getIINCHIP_TxMAX(s)) 
	{
		size = getIINCHIP_TxMAX(s) - dst_mask;
		wiz_write_buf((uint32_t)dst_ptr, (uint8_t*)src, size);
		src += size;
		size = len - size;
		dst_ptr = (uint8_t *)(getIINCHIP_TxBASE(s));
		wiz_write_buf((uint32_t)dst_ptr, (uint8_t*)src, size);
	} 
	else
	{
		wiz_write_buf((uint32_t)dst_ptr, (uint8_t*)src, len);
	}
}


/**
@brief	This function is being used for copy the data form Receive buffer of the chip to application buffer.

It calculate the actual physical address where one has to read
the data from Receive buffer. Here also take care of the condition while it exceed
the Rx memory uper-bound of socket.
*/
void read_data(SOCKET s, volatile uint8_t * src, volatile uint8_t * dst, uint16_t len)
{
	uint16_t size;
	uint16_t src_mask;
	uint8_t * src_ptr;

	src_mask = (uint32_t)src & getIINCHIP_RxMASK(s);
	src_ptr = (uint8_t *)(getIINCHIP_RxBASE(s) + src_mask);
	
	if( (src_mask + len) > getIINCHIP_RxMAX(s) ) 
	{
		size = getIINCHIP_RxMAX(s) - src_mask;
		wiz_read_buf((uint32_t)src_ptr, (uint8_t*)dst,size);
		dst += size;
		size = len - size;
		src_ptr = (uint8_t *)(getIINCHIP_RxBASE(s));
		wiz_read_buf((uint32_t)src_ptr, (uint8_t*) dst,size);
	} 
	else
	
	{
		wiz_read_buf((uint32_t)src_ptr, (uint8_t*) dst,len);//(uint32_t)src_ptr,
	}
}


/*Socket functions*/

/**
@brief	This Socket function initialize the channel in perticular mode, and set the port and wait for W5200 done it.
@return 	1 for sucess else 0.
*/  
uint8_t socket(SOCKET s, uint8_t protocol, uint16_t port, uint8_t flag)
{
	uint8_t ret;

	if ((protocol == Sn_MR_TCP) || (protocol == Sn_MR_UDP) || (protocol == Sn_MR_IPRAW) || (protocol == Sn_MR_MACRAW) || (protocol == Sn_MR_PPPOE))
	{
		close(s);
		IINCHIP_WRITE(Sn_MR(s),protocol | flag);
		if (port != 0) {
			IINCHIP_WRITE(Sn_PORT0(s),(uint8_t)((port & 0xff00) >> 8));
			IINCHIP_WRITE((Sn_PORT0(s) + 1),(uint8_t)(port & 0x00ff));
		} else {
			local_port++; // if don't set the source port, set local_port number.
			IINCHIP_WRITE(Sn_PORT0(s),(uint8_t)((local_port & 0xff00) >> 8));
			IINCHIP_WRITE((Sn_PORT0(s) + 1),(uint8_t)(local_port & 0x00ff));

		}
		IINCHIP_WRITE(Sn_CR(s),Sn_CR_OPEN); // run sockinit Sn_CR

		/* wait to process the command... */
		while( IINCHIP_READ(Sn_CR(s)) ) 
			;
		/* ------- */
		ret = 1;
	}
	else
	{
		ret = 0;
	}

	return ret;
}


/**
@brief	This function close the socket and parameter is "s" which represent the socket number
*/ 
void close(SOCKET s)
{

	
	IINCHIP_WRITE(Sn_CR(s),Sn_CR_CLOSE);

	/* wait to process the command... */
	while( IINCHIP_READ(Sn_CR(s)) ) 
		;
	/* ------- */
                /* all clear */
		IINCHIP_WRITE(Sn_IR(s), 0xFF);
}


/**
@brief	This function established  the connection for the channel in passive (server) mode. This function waits for the request from the peer.
@return	1 for success else 0.
*/ 
uint8_t listen(SOCKET s)
{
	uint8_t ret;

	if (IINCHIP_READ(Sn_SR(s)) == SOCK_INIT)
	{
		IINCHIP_WRITE(Sn_CR(s),Sn_CR_LISTEN);
		/* wait to process the command... */
		while( IINCHIP_READ(Sn_CR(s)) ) 
			;
		/* ------- */
		ret = 1;
	}
	else
	{
		ret = 0;

	}
	return ret;
}


/**
@brief	This function established  the connection for the channel in Active (client) mode. 
		This function waits for the untill the connection is established.
		
@return	1 for success else 0.
*/ 
uint8_t connect(SOCKET s, uint8_t * addr, uint16_t port)
{
	uint8_t ret;

	if 
	(
			((addr[0] == 0xFF) && (addr[1] == 0xFF) && (addr[2] == 0xFF) && (addr[3] == 0xFF)) ||
		 	((addr[0] == 0x00) && (addr[1] == 0x00) && (addr[2] == 0x00) && (addr[3] == 0x00)) ||
		 	(port == 0x00) 
	) 
	
 	{
 		ret = 0;
	}
	else
	{
		ret = 1;
		// set destination IP
		IINCHIP_WRITE(Sn_DIPR0(s),addr[0]);
		IINCHIP_WRITE((Sn_DIPR0(s) + 1),addr[1]);
		IINCHIP_WRITE((Sn_DIPR0(s) + 2),addr[2]);
		IINCHIP_WRITE((Sn_DIPR0(s) + 3),addr[3]);
		IINCHIP_WRITE(Sn_DPORT0(s),(uint8_t)((port & 0xff00) >> 8));
		IINCHIP_WRITE((Sn_DPORT0(s) + 1),(uint8_t)(port & 0x00ff));
		clearSUBR();   // clear the subnet mask again and keep it because of the ARP errata of W5100
		IINCHIP_WRITE(Sn_CR(s),Sn_CR_CONNECT);
                /* wait for completion */
		while ( IINCHIP_READ(Sn_CR(s)) ) ;
		while ( IINCHIP_READ(Sn_SR(s)) != SOCK_SYNSENT )
		{
			if(IINCHIP_READ(Sn_SR(s)) == SOCK_ESTABLISHED)
			{
				break;
			}
			if (getSn_IR(s) & Sn_IR_TIMEOUT)
			{
				IINCHIP_WRITE(Sn_IR(s), (Sn_IR_TIMEOUT));  // clear TIMEOUT Interrupt
				ret = 0;
				break;
			}
		}
		setSUBR(SubNet);	 // set the subnet mask register
	}
	
	return ret;
}






/**
@brief	This function used for disconnect the socket and parameter is "s" which represent the socket number
@return	1 for success else 0.
*/ 
void disconnect(SOCKET s)
{

	IINCHIP_WRITE(Sn_CR(s),Sn_CR_DISCON);

	/* wait to process the command... */
	while( IINCHIP_READ(Sn_CR(s)) ) 
		;
	/* ------- */
}


/**
@brief	This function used to send the data in TCP mode
@return	1 for success else 0.
*/ 
uint16_t send(SOCKET s, const uint8_t * buf, uint16_t len, bool retry)
{
	uint8_t status=0;
	uint16_t ret=0;
	uint16_t freesize=0;
	uint16_t txrd, txrd_before_send;

        
	if(retry) ;
	else {     
		if (len > getIINCHIP_TxMAX(s)) ret = getIINCHIP_TxMAX(s); // check size not to exceed MAX size.
		else ret = len;

		// if freebuf is available, start.
		do 
		{
			freesize = getSn_TX_FSR(s);
			status = IINCHIP_READ(Sn_SR(s));
			if ((status != SOCK_ESTABLISHED) && (status != SOCK_CLOSE_WAIT))
			{
				ret = 0; 
				break;
			}

		} while (freesize < ret);

		// copy data
		send_data_processing(s, (uint8_t *)buf, ret);
	}


//	if(ret != 0) // error code
// 2013-07-30 wiznet fix the code to add condition "retry"
	if(retry || ret != 0)
	{
		txrd_before_send = IINCHIP_READ(Sn_TX_RD0(s));
		txrd_before_send = (txrd_before_send << 8) + IINCHIP_READ(Sn_TX_RD0(s) + 1);
  
		IINCHIP_WRITE(Sn_CR(s),Sn_CR_SEND);
	
		/* wait to process the command... */
		while( IINCHIP_READ(Sn_CR(s)) );

		while ( (IINCHIP_READ(Sn_IR(s)) & Sn_IR_SEND_OK) != Sn_IR_SEND_OK )
                {
			//if(IINCHIP_READ(Sn_IR(s)) == SOCK_CLOSED)
			//2014-08-12 changed by Tony
			if(IINCHIP_READ(Sn_SR(s)) == SOCK_CLOSED)
			{

				close(s);
				return 0;
			}
		}
		IINCHIP_WRITE(Sn_IR(s), Sn_IR_SEND_OK);

		txrd = IINCHIP_READ(Sn_TX_RD0(s));
		txrd = (txrd << 8) + IINCHIP_READ(Sn_TX_RD0(s) + 1);

		if(txrd > txrd_before_send) {
			ret = txrd - txrd_before_send;
		} else {
			ret = (0xffff - txrd_before_send) + txrd + 1;
		}
	}
                
	return ret;
}


/**
@brief	This function is an application I/F function which is used to receive the data in TCP mode.
		It continues to wait for data as much as the application wants to receive.
		
@return	received data size for success else -1.
*/ 
uint16_t recv(SOCKET s, uint8_t * buf, uint16_t len)
{
	uint16_t ret=0;


	if ( len > 0 )
	{
		recv_data_processing(s, buf, len);
		IINCHIP_WRITE(Sn_CR(s),Sn_CR_RECV);

		/* wait to process the command... */
		while( IINCHIP_READ(Sn_CR(s)));
		/* ------- */
	
		ret = len;
	}
	return ret;
}


/**
@brief	This function is an application I/F function which is used to send the data for other then TCP mode. 
		Unlike TCP transmission, The peer's destination address and the port is needed.
		
@return	This function return send data size for success else -1.
*/ 
uint16_t sendto(SOCKET s, const uint8_t * buf, uint16_t len, uint8_t * addr, uint16_t port)
{
	uint16_t ret=0;
	

   if (len > getIINCHIP_TxMAX(s)) ret = getIINCHIP_TxMAX(s); // check size not to exceed MAX size.
   else ret = len;

	if
		(
		 	((addr[0] == 0x00) && (addr[1] == 0x00) && (addr[2] == 0x00) && (addr[3] == 0x00)) ||
		 	((port == 0x00)) ||(ret == 0)
		) 
 	{
 	   /* added return value */
 	   ret = 0;

	}
	else
	{
		IINCHIP_WRITE(Sn_DIPR0(s),addr[0]);
		IINCHIP_WRITE((Sn_DIPR0(s) + 1),addr[1]);
		IINCHIP_WRITE((Sn_DIPR0(s) + 2),addr[2]);
		IINCHIP_WRITE((Sn_DIPR0(s) + 3),addr[3]);
		IINCHIP_WRITE(Sn_DPORT0(s),(uint8_t)((port & 0xff00) >> 8));
		IINCHIP_WRITE((Sn_DPORT0(s) + 1),(uint8_t)(port & 0x00ff));     			
  		// copy data
 		send_data_processing(s, (uint8_t *)buf, ret);
		clearSUBR();	   // clear the subnet mask again and keep it because of the ARP errata of W5100
		IINCHIP_WRITE(Sn_CR(s),Sn_CR_SEND);
		/* wait to process the command... */
		while( IINCHIP_READ(Sn_CR(s)) ) 
			;
		/* ------- */

	   while ( (IINCHIP_READ(Sn_IR(s)) & Sn_IR_SEND_OK) != Sn_IR_SEND_OK ) 
	   {
    	        if (IINCHIP_READ(Sn_IR(s)) & Sn_IR_TIMEOUT)
		{

                /* clear interrupt */
           	IINCHIP_WRITE(Sn_IR(s), (Sn_IR_SEND_OK | Sn_IR_TIMEOUT)); /* clear SEND_OK & TIMEOUT */
		return 0;
		}
	   }

	   IINCHIP_WRITE(Sn_IR(s), Sn_IR_SEND_OK);
	   setSUBR(SubNet);    // set the subnet mask register
}
	return ret;
}


/**
@brief	This function is an application I/F function which is used to receive the data in other then
	TCP mode. This function is used to receive UDP, IP_RAW and MAC_RAW mode, and handle the header as well. 
	
@return	This function return received data size for success else -1.
*/ 
uint16_t recvfrom(SOCKET s, uint8_t * buf, uint16_t len, uint8_t * addr, uint16_t *port)
{
	uint8_t head[8];
	uint16_t data_len=0;
	uint16_t ptr=0;


	if ( len > 0 )
	{
   	ptr = IINCHIP_READ(Sn_RX_RD0(s));
   	ptr = ((ptr & 0x00ff) << 8) + IINCHIP_READ(Sn_RX_RD0(s) + 1);

   	switch (IINCHIP_READ(Sn_MR(s)) & 0x07)
   	{
   	case Sn_MR_UDP :
   			read_data(s, (uint8_t *)ptr, head, 0x08);
   			ptr += 8;
   			// read peer's IP address, port number.
    			addr[0] = head[0];
   			addr[1] = head[1];
   			addr[2] = head[2];
   			addr[3] = head[3];
   			*port = head[4];
   			*port = (*port << 8) + head[5];
   			data_len = head[6];
   			data_len = (data_len << 8) + head[7];
   			


			read_data(s, (uint8_t *)ptr, buf, data_len); // data copy.
			ptr += data_len;

			IINCHIP_WRITE(Sn_RX_RD0(s),(uint8_t)((ptr & 0xff00) >> 8));
			IINCHIP_WRITE((Sn_RX_RD0(s) + 1),(uint8_t)(ptr & 0x00ff));
   			break;
   
   	case Sn_MR_IPRAW :
   			read_data(s, (uint8_t *)ptr, head, 0x06);
   			ptr += 6;
   
   			addr[0] = head[0];
   			addr[1] = head[1];
   			addr[2] = head[2];
   			addr[3] = head[3];
   			data_len = head[4];
   			data_len = (data_len << 8) + head[5];
   	

			read_data(s, (uint8_t *)ptr, buf, data_len); // data copy.
			ptr += data_len;

			IINCHIP_WRITE(Sn_RX_RD0(s),(uint8_t)((ptr & 0xff00) >> 8));
			IINCHIP_WRITE((Sn_RX_RD0(s) + 1),(uint8_t)(ptr & 0x00ff));
   			break;
   	case Sn_MR_MACRAW :
   			read_data(s,(uint8_t*)ptr,head,2);
   			ptr+=2;
   			data_len = head[0];
   			data_len = (data_len<<8) + head[1] - 2;
   			if(data_len > 1514) 
   			{
   				while(1);
   			}

   			read_data(s,(uint8_t*) ptr,buf,data_len);
   			ptr += data_len;
   			IINCHIP_WRITE(Sn_RX_RD0(s),(uint8_t)((ptr & 0xff00) >> 8));
   			IINCHIP_WRITE((Sn_RX_RD0(s) + 1),(uint8_t)(ptr & 0x00ff));
   			
		
			break;

   	default :
   			break;
   	}
		IINCHIP_WRITE(Sn_CR(s),Sn_CR_RECV);

		/* wait to process the command... */
		while( IINCHIP_READ(Sn_CR(s)) ) ;
		/* ------- */
	}

 	return data_len;
}

/**
@brief	This function set the transmit & receive buffer size as per the channels is used
Note for TMSR and RMSR bits are as follows\n
bit 1-0 : memory size of channel #0 \n
bit 3-2 : memory size of channel #1 \n
bit 5-4 : memory size of channel #2 \n
bit 7-6 : memory size of channel #3 \n
bit 9-8 : memory size of channel #4 \n
bit 11-10 : memory size of channel #5 \n
bit 12-12 : memory size of channel #6 \n
bit 15-14 : memory size of channel #7 \n
Maximum memory size for Tx, Rx in the W5200 is 16K Bytes,\n
In the range of 16KBytes, the memory size could be allocated dynamically by each channel.\n
Be attentive to sum of memory size shouldn't exceed 8Kbytes\n
and to data transmission and receiption from non-allocated channel may cause some problems.\n
If the 16KBytes memory is already  assigned to centain channel, \n
other 3 channels couldn't be used, for there's no available memory.\n
If two 4KBytes memory are assigned to two each channels, \n
other 2 channels couldn't be used, for there's no available memory.\n
*/
void initialize( void )
{
	const uint8_t rx_size = 2;
	const uint8_t tx_size = 2;

	Set_network(Mac,Ip,SubNet,GateWay);

	for (uint8_t i = 0 ; i < MAX_SOCK_NUM; i++)       // Set the size, masking and base address of Tx & Rx memory by each channel
	{
		
		IINCHIP_WRITE((Sn_TXMEM_SIZE(i)),tx_size);
		IINCHIP_WRITE((Sn_RXMEM_SIZE(i)),rx_size);
		
		RMASK[i] = 0x7FF;//2K-1
		SMASK[i] = 0x7FF;//2K-1
		RBUFBASEADDRESS[i] = 0xC000 + i * 1024 * rx_size;
		SBUFBASEADDRESS[i] = 0x8000 + i * 1024 * tx_size;
		SSIZE[i] = 1024 * tx_size;
		RSIZE[i] = 1024 * rx_size;
	}
	
	setRTR(3000);//1000
	setRCR(3);
	
}





void ListenServer(SOCKET s, uint16_t port)
{
	uint16_t RSR_len;
	uint16_t received_len;
	uint16_t sent_data_len = 0;
	uint8_t * data_buf = rxBufferB;
	switch  (getSn_SR(s))        // based on current status of socket...
    {
        case  SOCK_CLOSED:                        // if socket is closed...
        if (socket(s,Sn_MR_TCP,port,0x00) == 1)        // if successful opening a socket...
        {
            listen(s);
            delay_ms(1);
        }
        break;

        case  SOCK_ESTABLISHED:                   // if socket connection is established...
	    if ((RSR_len = getSn_RX_RSR(s)) > 0) 			/* check Rx data */
	    {
			if (RSR_len > TX_RX_MAX_BUF_SIZE) RSR_len = TX_RX_MAX_BUF_SIZE;	/* if Rx data size is lager than TX_RX_MAX_BUF_SIZE */
			/* the data size to read is MAX_BUF_SIZE. */
			received_len = recv(s, data_buf, RSR_len);   	/* read the received data */
		
            //disconnect(s);
        }
        else                                            // no data yet...
        {
            delay_us(10);
        }
        break;

        case  SOCK_CLOSE_WAIT:                           	/* If the client request to close */
        disconnect(s);
        break;
			
	    default:
	    break;
    }
		
    
}


void ListenPc(SOCKET s, uint16_t port)
{
	uint16_t RSR_len;
	uint16_t received_len;
	uint16_t sent_data_len = 0;
	uint8_t * data_buf = rxBuffer;
	switch  (getSn_SR(s))        // based on current status of socket...
	{
		case  SOCK_CLOSED:                        // if socket is closed...
		if (socket(s,Sn_MR_TCP,port,0x00) == 1)        // if successful opening a socket...
		{
			listen(s);
			delay_ms(1);
		}
		break;

		case  SOCK_ESTABLISHED:                   // if socket connection is established...
		if ((RSR_len = getSn_RX_RSR(s)) > 0) 			/* check Rx data */
		{
			if (RSR_len > TX_RX_MAX_BUF_SIZE) RSR_len = TX_RX_MAX_BUF_SIZE;	/* if Rx data size is lager than TX_RX_MAX_BUF_SIZE */
			/* the data size to read is MAX_BUF_SIZE. */
			received_len = recv(s, data_buf, RSR_len);   	/* read the received data */
			
			//disconnect(s);
		}
		else                                            // no data yet...
		{
			delay_us(10);
		}
		break;

		case  SOCK_CLOSE_WAIT:                           	/* If the client request to close */
		disconnect(s);
		break;
		
		default:
		break;
	}
	
	
}


//solo para debug. Borrar luego
void readDatos(void)
{
	uint8_t * data_buf = txBuffer;

	
    IINCHIP_CS_low();                                        // CS=0, SPI start

    IINCHIP_SpiSendData(((0xc000) & 0xFF00) >> 8);        // Address byte 1
    IINCHIP_SpiSendData((0xc000) & 0x00FF);               // Address byte 2
    IINCHIP_SpiSendData((0x00 | ((20 & 0x7F00) >> 8)));    // Data read command
    IINCHIP_SpiSendData((20 & 0x00FF));

    for(int idx = 0; idx < 20; idx++)                          // Read data in loop
    {
	   data_buf[idx] = IINCHIP_SpiSendData(0x00);
	
    }

    IINCHIP_CS_high();	
}


/*
void Set_defaults(void)
{
	eeprom_write_byte(&Tcp_Config.MAC[0],0x00);
	eeprom_write_byte(&Tcp_Config.MAC[1],0x08);
	eeprom_write_byte(&Tcp_Config.MAC[2],0xDC);
	eeprom_write_byte(&Tcp_Config.MAC[3],0x01);
	eeprom_write_byte(&Tcp_Config.MAC[4],0x02);
	eeprom_write_byte(&Tcp_Config.MAC[5],0x04);

	eeprom_write_byte(&Tcp_Config.LOCAL_IP[0],89);
	eeprom_write_byte(&Tcp_Config.LOCAL_IP[1],20);
	eeprom_write_byte(&Tcp_Config.LOCAL_IP[2],4);
	eeprom_write_byte(&Tcp_Config.LOCAL_IP[3],11);
	
	eeprom_write_byte(&Tcp_Config.GATEWAY[0],0);
	eeprom_write_byte(&Tcp_Config.GATEWAY[1],0);
	eeprom_write_byte(&Tcp_Config.GATEWAY[2],0);
	eeprom_write_byte(&Tcp_Config.GATEWAY[3],0);
	
	eeprom_write_byte(&Tcp_Config.DEST_IP[0],89);
	eeprom_write_byte(&Tcp_Config.DEST_IP[1],20);
	eeprom_write_byte(&Tcp_Config.DEST_IP[2],4);
	eeprom_write_byte(&Tcp_Config.DEST_IP[3],2);

	eeprom_write_byte(&Tcp_Config.SUBNET[0],255);
	eeprom_write_byte(&Tcp_Config.SUBNET[1],255);
	eeprom_write_byte(&Tcp_Config.SUBNET[2],255);
	eeprom_write_byte(&Tcp_Config.SUBNET[3],0);

	eeprom_write_word(&Tcp_Config.LOCAL_PORT,3000);


}


void Read_eeprom_params(void)
{
	uint8_t i;
    for(i=0;i<6;i++)
	{
		Mac[i] = eeprom_read_byte(&Tcp_Config.MAC[i]);
	}
	
    for(i=0;i<4;i++)
    {
	    Ip[i] = eeprom_read_byte(&Tcp_Config.LOCAL_IP[i]);
    }

    for(i=0;i<4;i++)
    {
	    GateWay[i] = eeprom_read_byte(&Tcp_Config.GATEWAY[i]);
    }

    for(i=0;i<4;i++)
    {
	    SubNet[i] = eeprom_read_byte(&Tcp_Config.SUBNET[i]);
    }

    for(i=0;i<4;i++)
    {
	   Dest_IP[i] = eeprom_read_byte(&Tcp_Config.DEST_IP[i]);
    }
	
	local_port = eeprom_read_word(&Tcp_Config.LOCAL_PORT);
	
}
*/
