#ifndef _MK_ETHERNET_W5100_H_
#define _MK_ETHERNET_W5100_H_

//****************************************************************************************************************
//*
//*						EIP2_Ethernet.h
//* 버전: v1.0.0.0 [2009.01.20] by Hyun, Jong Ok
//* 내용
//*    1. v1.0.0.1 [2009.02.24]
//*      (1) sendto 함수에서 패킷 전송후 불필요하게 기다리던 부분을 패킷 전송 전에 체크 하도록 위치를 변경 하고, IR 레지스터 상태를
//           보던 기존 코드를 변경해서 Sn_CR 레지스터 상태에 따른 전송 Ready 상태인지를 체크하도록 수정했습니다.
//****************************************************************************************************************

#include "mk_common.h"

/// 인터럽트 및 기타 관련
#define	CLK_CPU			8000000		/**< 8Mhz(for serial) */

#define __DEF_IINCHIP_MAP_BASE__	(W5100)    // chip base address
#define COMMON_BASE 0x0000
#define __DEF_IINCHIP_MAP_TXBUF__ (COMMON_BASE + 0x4000) /* Internal Tx buffer address of the iinchip */
#define __DEF_IINCHIP_MAP_RXBUF__ (COMMON_BASE + 0x6000) /* Internal Rx buffer address of the iinchip */

//#define __DEF_IINCHIP_DBG__ /* involve debug code in driver (socket.c) */
#define __DEF_IINCHIP_INT__ /**< involve interrupt service routine (socket.c) */

#ifdef __DEF_IINCHIP_INT__
  // iinchip use external interrupt 4
  #define IINCHIP_ISR_DISABLE()	//(EIMSK &= ~(0x10))
  #define IINCHIP_ISR_ENABLE()	//(EIMSK |= 0x10)
  #define IINCHIP_ISR_GET(X)	//	(X = EIMSK)
  #define IINCHIP_ISR_SET(X)	//	(EIMSK = X)
#else
  #define IINCHIP_ISR_DISABLE()
  #define IINCHIP_ISR_ENABLE()	
  #define IINCHIP_ISR_GET(X)
  #define IINCHIP_ISR_SET(X)
#endif

typedef t_uchar		uint8;
//typedef unsigned char 	SOCKET;
typedef t_ui16 		Uint16;
typedef t_bool 		bool;
typedef t_i16 		int16;
typedef volatile t_char 	vint8;
typedef volatile t_i16 		vint16;
typedef volatile t_uchar 	vuint8;
typedef volatile t_ui16 	vuint16;

/** global define */
#define HW_PM_VERSION	"0.1"
#define HW_NM_VERSION	"0.1"
#define HW_MB_VERSION	"0.1"

#define TX_RX_MAX_BUF_SIZE	2048
#define TX_BUF	0x1100
#define RX_BUF	(TX_BUF+TX_RX_MAX_BUF_SIZE)

#define UART_DEVICE_CNT		1	/**< UART device number */
/* #define SUPPORT_UART_ONE */

//=============================================================================

#define MR __DEF_IINCHIP_MAP_BASE__	// 0x2000
#define IDM_OR ((__DEF_IINCHIP_MAP_BASE__ + 0x00))
#define IDM_AR0 ((__DEF_IINCHIP_MAP_BASE__ + 0x01))
#define IDM_AR1 ((__DEF_IINCHIP_MAP_BASE__ + 0x02))
#define IDM_DR ((__DEF_IINCHIP_MAP_BASE__ + 0x03))

/**
 @brief Gateway IP Register address
 */
#define GAR0				(COMMON_BASE + 0x0001)
/**
 @brief Subnet mask Register address
 */
#define SUBR0			(COMMON_BASE + 0x0005)
/**
 @brief Source MAC Register address
 */
#define SHAR0				(COMMON_BASE + 0x0009)
/**
 @brief Source IP Register address
 */
#define SIPR0				(COMMON_BASE + 0x000F)
/**
 @brief Interrupt Register
 */
#define IR					(COMMON_BASE + 0x0015)
/**
 @brief Interrupt mask register
 */
#define IMR					(COMMON_BASE + 0x0016)
/**
 @brief Timeout register address( 1 is 100us )
 */
#define RTR0				(COMMON_BASE + 0x0017)
/**
 @brief Retry count reigster
 */
#define RCR						(COMMON_BASE + 0x0019)
/**
 @brief Receive memory size reigster
 */
#define RMSR			(COMMON_BASE + 0x001A)
/**
 @brief Transmit memory size reigster
 */
#define TMSR			(COMMON_BASE + 0x001B)
/**
 @brief Authentication type register address in PPPoE mode
 */
#define PATR0					(COMMON_BASE + 0x001C)
//#define PPPALGO (COMMON_BASE + 0x001D)
#define PTIMER (COMMON_BASE + 0x0028)
#define PMAGIC (COMMON_BASE + 0x0029)

/**
 @brief Unreachable IP register address in UDP mode
 */
#define UIPR0				(COMMON_BASE + 0x002A)
/**
 @brief Unreachable Port register address in UDP mode
 */
#define UPORT0			(COMMON_BASE + 0x002E)

/**
 @brief socket register
*/
#define CH_BASE (COMMON_BASE + 0x0400)
/**
 @brief	size of each channel register map
 */
#define CH_SIZE		0x0100
/**
 @brief socket Mode register
 */
#define Sn_MR(ch)		(CH_BASE + ch * CH_SIZE + 0x0000)
/**
 @brief channel Sn_CR register
 */
#define Sn_CR(ch)				(CH_BASE + ch * CH_SIZE + 0x0001)
/**
 @brief channel interrupt register
 */
#define Sn_IR(ch)			(CH_BASE + ch * CH_SIZE + 0x0002)
/**
 @brief channel status register
 */
#define Sn_SR(ch)			(CH_BASE + ch * CH_SIZE + 0x0003)
/**
 @brief source port register
 */
#define Sn_PORT0(ch)		(CH_BASE + ch * CH_SIZE + 0x0004)
/**
 @brief Peer MAC register address
 */
#define Sn_DHAR0(ch)			(CH_BASE + ch * CH_SIZE + 0x0006)
/**
 @brief Peer IP register address
 */
#define Sn_DIPR0(ch)			(CH_BASE + ch * CH_SIZE + 0x000C)
/**
 @brief Peer port register address
 */
#define Sn_DPORT0(ch)		(CH_BASE + ch * CH_SIZE + 0x0010)
/**
 @brief Maximum Segment Size(Sn_MSSR0) register address
 */
#define Sn_MSSR0(ch)					(CH_BASE + ch * CH_SIZE + 0x0012)
/**
 @brief Protocol of IP Header field register in IP raw mode
 */
#define Sn_PROTO(ch)			(CH_BASE + ch * CH_SIZE + 0x0014)

/** 
 @brief IP Type of Service(TOS) Register 
 */
#define Sn_TOS(ch)						(CH_BASE + ch * CH_SIZE + 0x0015)
/**
 @brief IP Time to live(TTL) Register 
 */
#define Sn_TTL(ch)						(CH_BASE + ch * CH_SIZE + 0x0016)

//not support
//#define RX_CH_DMEM_SIZE			(COMMON_BASE + 0x001E)
//#define TX_CH_DMEM_SIZE			(COMMON_BASE + 0x001F)

/**
 @brief Transmit free memory size register
 */
#define Sn_TX_FSR0(ch)	(CH_BASE + ch * CH_SIZE + 0x0020)
/**
 @brief Transmit memory read pointer register address
 */
#define Sn_TX_RD0(ch)			(CH_BASE + ch * CH_SIZE + 0x0022)
/**
 @brief Transmit memory write pointer register address
 */
#define Sn_TX_WR0(ch)			(CH_BASE + ch * CH_SIZE + 0x0024)
/**
 @brief Received data size register
 */
#define Sn_RX_RSR0(ch)	(CH_BASE + ch * CH_SIZE + 0x0026)
/**
 @brief Read point of Receive memory
 */
#define Sn_RX_RD0(ch)			(CH_BASE + ch * CH_SIZE + 0x0028)
/**
 @brief Write point of Receive memory
 */
#define Sn_RX_WR0(ch)			(CH_BASE + ch * CH_SIZE + 0x002A)


/* MODE register values */
#define MR_RST			0x80 /**< reset */
#define MR_PB			0x10 /**< ping block */
#define MR_PPPOE		0x08 /**< enable pppoe */
#define MR_LB  		0x04 /**< little or big endian selector in indirect mode */
#define MR_AI			0x02 /**< auto-increment in indirect mode */
#define MR_IND			0x01 /**< enable indirect mode */

/* IR register values */
#define IR_CONFLICT	0x80 /**< check ip confict */
#define IR_UNREACH	0x40 /**< get the destination unreachable message in UDP sending */
#define IR_PPPoE		0x20 /**< get the PPPoE close message */
#define IR_SOCK(ch)	(0x01 << ch) /**< check socket interrupt */

/* Sn_MR values */
#define Sn_MR_CLOSE		0x00		/**< unused socket */
#define Sn_MR_TCP		0x01		/**< TCP */
#define Sn_MR_UDP		0x02		/**< UDP */
#define Sn_MR_IPRAW	0x03		/**< IP LAYER RAW SOCK */
#define Sn_MR_MACRAW	0x04		/**< MAC LAYER RAW SOCK */
#define Sn_MR_PPPOE		0x05		/**< PPPoE */
#define Sn_MR_ND		0x20		/**< No Delayed Ack(TCP) flag */
#define Sn_MR_MULTI		0x80		/**< support multicating */


/* Sn_CR values */
#define Sn_CR_OPEN		0x01		/**< initialize or open socket */
#define Sn_CR_LISTEN		0x02		/**< wait connection request in tcp mode(Server mode) */
#define Sn_CR_CONNECT	0x04		/**< send connection request in tcp mode(Client mode) */
#define Sn_CR_DISCON		0x08		/**< send closing reqeuset in tcp mode */
#define Sn_CR_CLOSE		0x10		/**< close socket */
#define Sn_CR_SEND		0x20		/**< updata txbuf pointer, send data */
#define Sn_CR_SEND_MAC	0x21		/**< send data with MAC address, so without ARP process */
#define Sn_CR_SEND_KEEP	0x22		/**<  send keep alive message */
#define Sn_CR_RECV		0x40		/**< update rxbuf pointer, recv data */

/*
#ifdef __DEF_IINCHIP_PPP__
	#define Sn_CR_PCON				0x23		 
	#define Sn_CR_PDISCON			0x24		 
	#define Sn_CR_PCR					0x25		 
	#define Sn_CR_PCN					0x26		
	#define Sn_CR_PCJ					0x27		
#endif
*/

/* Sn_IR values */
/*
#ifdef __DEF_IINCHIP_PPP__
	#define Sn_IR_PRECV			0x80		
	#define Sn_IR_PFAIL			0x40		
	#define Sn_IR_PNEXT			0x20		
#endif
*/

#define Sn_IR_SEND_OK			0x10		/**< complete sending */
#define Sn_IR_TIMEOUT			0x08		/**< assert timeout */
#define Sn_IR_RECV				0x04		/**< receiving data */
#define Sn_IR_DISCON				0x02		/**< closed socket */
#define Sn_IR_CON					0x01		/**< established connection */

/* Sn_SR values */
#define SOCK_CLOSED				0x00		/**< closed */
#define SOCK_INIT 				0x13		/**< init state */
#define SOCK_LISTEN				0x14		/**< listen state */
#define SOCK_SYNSENT	   		0x15		/**< connection state */
#define SOCK_SYNRECV		   	0x16		/**< connection state */
#define SOCK_ESTABLISHED		0x17		/**< success to connect */
#define SOCK_FIN_WAIT			0x18		/**< closing state */
#define SOCK_CLOSING		   	0x1A		/**< closing state */
#define SOCK_TIME_WAIT			0x1B		/**< closing state */
#define SOCK_CLOSE_WAIT			0x1C		/**< closing state */
#define SOCK_LAST_ACK			0x1D		/**< closing state */
#define SOCK_UDP				   0x22		/**< udp socket */
#define SOCK_IPRAW			   0x32		/**< ip raw mode socket */
#define SOCK_MACRAW			   0x42		/**< mac raw mode socket */
#define SOCK_PPPOE				0x5F		/**< pppoe socket */

/* IP PROTOCOL */
#define IPPROTO_IP              0           /**< Dummy for IP */
#define IPPROTO_ICMP            1           /**< Control message protocol */
#define IPPROTO_IGMP            2           /**< Internet group management protocol */
#define IPPROTO_GGP             3           /**< Gateway^2 (deprecated) */
#define IPPROTO_TCP             6           /**< TCP */
#define IPPROTO_PUP             12          /**< PUP */
#define IPPROTO_UDP             17          /**< UDP */
#define IPPROTO_IDP             22          /**< XNS idp */
#define IPPROTO_ND              77          /**< UNOFFICIAL net disk protocol */
#define IPPROTO_RAW             255         /**< Raw IP packet */

Uint16 IINCHIP_READ(Uint16 addr);
void IINCHIP_WRITE(Uint16 addr, Uint16 data);
Uint16 wiz_read_buf(Uint16 addr, uint8* buf,Uint16 len);
Uint16 wiz_write_buf(Uint16 addr,uint8* buf,Uint16 len, t_bool bPack);

void iinchip_init(void); // reset iinchip
void sysinit(uint8 tx_size, uint8 rx_size); // setting tx/rx buf size
uint8 getISR(uint8 s);
void putISR(uint8 s, uint8 val);
Uint16 getIINCHIP_RxMAX(uint8 s);
Uint16 getIINCHIP_TxMAX(uint8 s);
Uint16 getIINCHIP_RxMASK(uint8 s);
Uint16 getIINCHIP_TxMASK(uint8 s);
Uint16 getIINCHIP_RxBASE(uint8 s);
Uint16 getIINCHIP_TxBASE(uint8 s);
void setGAR(Uint16 * addr); // set gateway address
void setSUBR(Uint16 * addr); // set subnet mask address
void setSHAR(Uint16 * addr); // set local MAC address
void setSIPR(Uint16 * addr); // set local IP address
void setRTR(Uint16 timeout); // set retry duration for data transmission, connection, closing ...
void setRCR(uint8 retry); // set retry count (above the value, assert timeout interrupt)
void setIMR(uint8 mask); // set interrupt mask. 
void getGAR(Uint16 * addr);
void getSUBR(Uint16 * addr);
void getSHAR(Uint16 * addr);
void getSIPR(Uint16 * addr);
uint8 getIR( void );
void setSn_MSS(SOCKET s, Uint16 Sn_MSSR0); // set maximum segment size
void setSn_PROTO(SOCKET s, uint8 proto); // set IP Protocol value using IP-Raw mode
uint8 getSn_IR(SOCKET s); // get socket interrupt status
int getSn_SR(SOCKET s); // get socket status
int getSn_TX_FSR(SOCKET s); // get socket TX free buf size
int getSn_RX_RSR(SOCKET s); // get socket RX recv buf size
void setSn_DHAR(SOCKET s, Uint16 * addr);
void setSn_DIPR(SOCKET s, Uint16 * addr);
void setSn_DPORT(SOCKET s, Uint16 * addr);
void getSn_DHAR(SOCKET s, Uint16 * addr);
void getSn_DIPR(SOCKET s, Uint16 * addr);
void getSn_DPORT(SOCKET s, Uint16 * addr);
void setSn_TTL(SOCKET s, uint8 ttl);
void setMR(uint8 val);
/*
#ifdef __DEF_IINCHIP_PPP__
uint8 pppinit(uint8 *id, uint8 idlen, uint8 *passwd, uint8 passwdlen);
uint8 pppterm(uint8 *mac,uint8 *sessionid);
#endif
*/
void send_data_processing(SOCKET s, uint8 *data, Uint16 len, t_bool bPack);
void recv_data_processing(SOCKET s, uint8 *data, Uint16 len, t_bool bPack);
void read_data(SOCKET s, vuint8 * src, vuint8 * dst, Uint16 len, t_bool bPack);
void write_data(SOCKET s, vuint8 * src, vuint8 * dst, Uint16 len, t_bool bPack);

//****************************************************************************************************************
//*
//*						socket.h
//*
//****************************************************************************************************************

#define	__TCP__		// Function for TCP
#define __TCP_SERVER__	// Function for TCP server
#define __TCP_CLIENT__	// Function for TCP client
#define	__UDP__		// Function for UDP
#define	__OPT__		// Option function

/* Select parameter to use */
#define SEL_CONTROL		0	// Confirm socket status
#define SEL_SEND		1	       	// Confirm Tx free buffer size
#define SEL_RECV		2	       	// Confirm Rx data size


#ifdef	__TCP_CLIENT__
uint8 connect(SOCKET s, uint8 * addr, Uint16 port); // Establish TCP connection (Active connection)
#endif

#ifdef	__TCP_SERVER__
uint8 listen(SOCKET s);	// Establish TCP connection (Passive connection)
#endif

uint8 socket(SOCKET s, uint8 protocol, Uint16 port, uint8 flag); // Opens a socket(TCP or UDP or IP_RAW mode)
void close2(SOCKET s); // Close socket
void disconnect(SOCKET s); // disconnect the connection
Uint16 send(SOCKET s, const uint8 * buf, Uint16 len, t_bool bPack); // Send data (TCP)
Uint16 recv(SOCKET s, uint8 * buf, Uint16 len, t_bool bPack);	// Receive data (TCP)
Uint16 sendto(SOCKET s, const uint8 * buf, Uint16 len, uint8 * addr, t_i32 port); // Send data (UDP/IP RAW)
Uint16 recvfrom(SOCKET s, uint8 * buf, Uint16 len, uint8 * addr, t_ui32  *port, t_bool bPack); // Receive data (UDP/IP RAW)
Uint16 igmpsend(SOCKET s, const uint8 * buf, Uint16 len);

//****************************************************************************************************************
//*
//*						w5100.c
//*
//****************************************************************************************************************

static uint8 I_STATUS[MAX_SOCK_NUM];
static Uint16 SMASK[MAX_SOCK_NUM]; /**< Variable for Tx buffer MASK in each channel */
static Uint16 RMASK[MAX_SOCK_NUM]; /**< Variable for Rx buffer MASK in each channel */
static Uint16 SSIZE[MAX_SOCK_NUM]; /**< Max Tx buffer size by each channel */
static Uint16 RSIZE[MAX_SOCK_NUM]; /**< Max Rx buffer size by each channel */
static Uint16 SBUFBASEADDRESS[MAX_SOCK_NUM]; /**< Tx buffer base address by each channel */
static Uint16 RBUFBASEADDRESS[MAX_SOCK_NUM]; /**< Rx buffer base address by each channel */

Uint16 val;

int *W5100 = (int *)0x2000;

int wt5100_reg_read(int address);
void wt5100_reg_write(int address, int data);

/**
@brief	This function reads into W5100 memory(Buffer)
*/ 
Uint16 wiz_read_buf(Uint16 addr, uint8* buf, Uint16 len)
{
   Uint16 idx = 0;
 
   val = *((vuint16 *)(W5100+1)) = addr >> 8;
   val = *((vuint16 *)(W5100+2)) = addr & 0xff;
   for (idx = 0; idx < len ; idx++) 
   {
		buf[idx] = *((vuint16 *)(W5100+3)) & 0x00ff;
   }

	return len;
}

int wt5100_reg_read(int address)
{
	*(W5100+1) = address>>8;		// MSB Address
	//Delay_ms(100);
	*(W5100+2) = address & 0xff;	// LSB Address
	//Delay_ms(1000);
	
	return (int) *(W5100+3) & 0x00ff;		// Data read
}

void wt5100_reg_write(int address, int data)
{
	*(W5100+1) = address>>8;		// MSB Address
	//Delay_ms(100);
	*(W5100+2) = address & 0xff;	// LSB Address
	//Delay_ms(1000);
	
	*(W5100+3) = data & 0xff;		// Data write
}

/*
void IINCHIP_WRITE(Uint16 addr, Uint16 data)
{
//	IINCHIP_ISR_DISABLE();
	*((vUint16 *)(W5100+0x01)) = (addr & 0xFF00)>>8;		// MSB Address
	delay_loop();
	*((vUint16 *)(W5100+0x02)) = addr & 0x00FF;	// LSB Address
	delay_loop();
	
	*((vUint16 *)(W5100+0x03)) = data & 0xff;		// Data write
//	IINCHIP_ISR_ENABLE();	
	
}


Uint16 IINCHIP_READ(Uint16 addr)
{
	Uint16 data;
//	IINCHIP_ISR_DISABLE();
	*((vUint16 *)(W5100+0x01)) = (addr & 0xFF00) >>8;		// MSB Address
	//delay_loop();
	*((vUint16 *)(W5100+0x02)) = addr & 0x00FF;	// LSB Address
	//delay_loop();
	
	data = *((vUint16 *)(W5100+0x03)) & 0xff;
	
//	IINCHIP_ISR_ENABLE();	
		
	return (data & 0xff);		// Data read
}
*/

uint8 getISR(uint8 s)
{
	return I_STATUS[s];
}

void putISR(uint8 s, uint8 val)
{
   I_STATUS[s] = val;
}

Uint16 getIINCHIP_RxMAX(uint8 s)
{
   return RSIZE[s];
}
Uint16 getIINCHIP_TxMAX(uint8 s)
{
   return SSIZE[s];
}
Uint16 getIINCHIP_RxMASK(uint8 s)
{
   return RMASK[s];
}
Uint16 getIINCHIP_TxMASK(uint8 s)
{
   return SMASK[s];
}
Uint16 getIINCHIP_RxBASE(uint8 s)
{
   return RBUFBASEADDRESS[s];
}
Uint16 getIINCHIP_TxBASE(uint8 s)
{
   return SBUFBASEADDRESS[s];
}


/**
@brief	This function writes into W5100 memory(Buffer)
*/ 
Uint16 wiz_write_buf(Uint16 addr,uint8* buf,Uint16 len, t_bool bPack)
{
	Uint16 idx = 0;
//   IINCHIP_ISR_DISABLE();
	*((vuint8*)IDM_AR0) = (uint8)((addr & 0xFF00) >> 8);
	*((vuint8*)IDM_AR1) = (uint8)(addr & 0x00FF);

	if(bPack){ // srouce buffer의 데이터가 16 비트로 packing되어 있는 경우...
		t_ui16 *pwSrcBuf;
		pwSrcBuf = (t_ui16 *)buf;
		for (idx = 0; idx < len ; idx++){ 
   			*((vuint8*)IDM_DR) = pwSrcBuf[idx] & 0xff;
			*((vuint8*)IDM_DR) = (pwSrcBuf[idx] >> 8) & 0xff;
		}
	}else{
		for (idx = 0; idx < len ; idx++){ 
			*((vuint8*)IDM_DR) = *buf & 0xff;
			buf++;
		}
	}

//   IINCHIP_ISR_ENABLE();

	return len;
}


/**
@brief	This function reads into W5100 memory(Buffer)
*/ 

#if (__COMPILER_VERSION__ == __WINAVR_20050214__)
static void iinchip_irq(void);

void SIG_INTERRUPT4( void ) __attribute__ ((signal));
void SIG_INTERRUPT4( void )
{
	iinchip_irq();
}


/**
@brief	Socket interrupt routine
*/ 
static void iinchip_irq(void)
{
#ifdef __DEF_IINCHIP_INT__
	uint8 int_val;
//	IINCHIP_ISR_DISABLE();
	int_val = wt5100_reg_read(IR);

	if (int_val & IR_CONFLICT)
	{
		//printf("IP conflict : %.2x\r\n", int_val);
	}
	if (int_val & IR_UNREACH)
	{
		//printf("INT Port Unreachable : %.2x\r\n", int_val);
		//printf("UIPR0 : %d.%d.%d.%d\r\n", wt5100_reg_read(UIPR0), wt5100_reg_read(UIPR0+1), wt5100_reg_read(UIPR0+2), wt5100_reg_read(UIPR0+3));
		//printf("UPORT0 : %.2x %.2x\r\n", wt5100_reg_read(UPORT0), wt5100_reg_read(UPORT0+1));
	}

	if (int_val & IR_SOCK(0))
	{
		I_STATUS[0] = wt5100_reg_read(Sn_IR(0));
   		wt5100_reg_write(Sn_IR(0), I_STATUS[0] & 0xf);
	}
	if (int_val & IR_SOCK(1))
	{
		I_STATUS[1] = wt5100_reg_read(Sn_IR(1));
   		wt5100_reg_write(Sn_IR(1), I_STATUS[1] & 0xf);
	}
	if (int_val & IR_SOCK(2))
	{
		I_STATUS[2] = wt5100_reg_read(Sn_IR(2));
   		wt5100_reg_write(Sn_IR(2), I_STATUS[2] & 0xf);
	}
	if (int_val & IR_SOCK(3))
	{
		I_STATUS[3] = wt5100_reg_read(Sn_IR(3));
   		wt5100_reg_write(Sn_IR(3), I_STATUS[3] & 0xf);
	}

	wt5100_reg_write(IR, int_val);

//	IINCHIP_ISR_ENABLE();
	
#endif
}
#else	
/**
@brief	Socket interrupt routine
*/ 
ISR(INT4_vect)
{
#ifdef __DEF_IINCHIP_INT__
	uint8 int_val;
//	IINCHIP_ISR_DISABLE();
	int_val = wt5100_reg_read(IR);

	if (int_val & IR_CONFLICT)
	{
		//printf("IP conflict : %.2x\r\n", int_val);
	}
	if (int_val & IR_UNREACH)
	{
//		printf("INT Port Unreachable : %.2x\r\n", int_val);
//		printf("UIPR0 : %d.%d.%d.%d\r\n", wt5100_reg_read(UIPR0), wt5100_reg_read(UIPR0+1), wt5100_reg_read(UIPR0+2), wt5100_reg_read(UIPR0+3));
//		printf("UPORT0 : %.2x %.2x\r\n", wt5100_reg_read(UPORT0), wt5100_reg_read(UPORT0+1));
	}

	if (int_val & IR_SOCK(0))
	{
		I_STATUS[0] = wt5100_reg_read(Sn_IR(0));
   		wt5100_reg_write(Sn_IR(0), I_STATUS[0] & 0xf);
	}
	if (int_val & IR_SOCK(1))
	{
		I_STATUS[1] = wt5100_reg_read(Sn_IR(1));
   		wt5100_reg_write(Sn_IR(1), I_STATUS[1] & 0xf);
	}
	if (int_val & IR_SOCK(2))
	{
		I_STATUS[2] = wt5100_reg_read(Sn_IR(2));
   		wt5100_reg_write(Sn_IR(2), I_STATUS[2] & 0xf);
	}
	if (int_val & IR_SOCK(3))
	{
		I_STATUS[3] = wt5100_reg_read(Sn_IR(3));
   		wt5100_reg_write(Sn_IR(3), I_STATUS[3] & 0xf);
	}

	wt5100_reg_write(IR, int_val);

//	IINCHIP_ISR_ENABLE();
	
#endif
}
#endif

/**
@brief	This function is for resetting of the iinchip. Initializes the iinchip to work in whether DIRECT or INDIRECT mode
*/ 
void iinchip_init(void)
{
	setMR(MR_RST);

#if (__DEF_IINCHIP_BUS__ == __DEF_IINCHIP_INDIRECT_MODE__)
	setMR(MR_IND | MR_AI);
#ifdef __DEF_IINCHIP_DBG__	
//	printf("MR value is %d \r\n",wt5100_reg_read(MR));
#endif	
#endif
}


/**
@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\n
Maximum memory size for Tx, Rx in the W5100 is 8K Bytes,\n
In the range of 8KBytes, 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 8KBytes 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 sysinit(
	uint8 tx_size, 	/**< tx_size Tx memory size (00 - 1KByte, 01- 2KBtye, 10 - 4KByte, 11 - 8KByte) */
	uint8 rx_size		/**< rx_size Rx memory size (00 - 1KByte, 01- 2KBtye, 10 - 4KByte, 11 - 8KByte) */
	)
{
	int16 i;
	int16 ssum,rsum;

	ssum = 0;
	rsum = 0;
	
	wt5100_reg_write(TMSR,tx_size); /* Set Tx memory size for each channel */
	wt5100_reg_write(RMSR,rx_size); /* Set Rx memory size for each channel */

	SBUFBASEADDRESS[0] = (Uint16)(__DEF_IINCHIP_MAP_TXBUF__);		/* Set base address of Tx memory for channel #0 */
	RBUFBASEADDRESS[0] = (Uint16)(__DEF_IINCHIP_MAP_RXBUF__);		/* Set base address of Rx memory for channel #0 */

   for (i = 0 ; i < MAX_SOCK_NUM; i++)       // Set the size, masking and base address of Tx & Rx memory by each channel
	{
		SSIZE[i] = (int16)(0);
		RSIZE[i] = (int16)(0);
		if (ssum < 8192)
		{
         switch((tx_size >> i*2) & 0x03)  // Set Tx memory size
			{
			case 0:
				SSIZE[i] = (int16)(1024);
				SMASK[i] = (Uint16)(0x03FF);
				break;
			case 1:
				SSIZE[i] = (int16)(2048);
				SMASK[i] = (Uint16)(0x07FF);
				break;
			case 2:
				SSIZE[i] = (int16)(4096);
				SMASK[i] = (Uint16)(0x0FFF);
				break;
			case 3:
				SSIZE[i] = (int16)(8192);
				SMASK[i] = (Uint16)(0x1FFF);
				break;
			}
		}
		if (rsum < 8192)
		{
         switch((rx_size >> i*2) & 0x03)     // Set Rx memory size
			{
			case 0:
				RSIZE[i] = (int16)(1024);
				RMASK[i] = (Uint16)(0x03FF);
				break;
			case 1:
				RSIZE[i] = (int16)(2048);
				RMASK[i] = (Uint16)(0x07FF);
				break;
			case 2:
				RSIZE[i] = (int16)(4096);
				RMASK[i] = (Uint16)(0x0FFF);
				break;
			case 3:
				RSIZE[i] = (int16)(8192);
				RMASK[i] = (Uint16)(0x1FFF);
				break;
			}
		}
		ssum += SSIZE[i];
		rsum += RSIZE[i];

      if (i != 0)             // Sets base address of Tx and Rx memory for channel #1,#2,#3
		{
			SBUFBASEADDRESS[i] = SBUFBASEADDRESS[i-1] + SSIZE[i-1];
			RBUFBASEADDRESS[i] = RBUFBASEADDRESS[i-1] + RSIZE[i-1];
		}
	}
}

void setMR(uint8 val)
{
   *(W5100+0) = val;
}


/**
@brief	This function sets up gateway IP address.
*/ 
void setGAR(
	Uint16 * addr	/**< a pointer to a 4 -byte array responsible to set the Gateway IP address. */
	)
{
	wt5100_reg_write((GAR0 + 0),addr[0]);
	wt5100_reg_write((GAR0 + 1),addr[1]);
	wt5100_reg_write((GAR0 + 2),addr[2]);
	wt5100_reg_write((GAR0 + 3),addr[3]);
}
void getGWIP(uint8 * addr)
{
	addr[0] = wt5100_reg_read((GAR0 + 0));
	addr[1] = wt5100_reg_read((GAR0 + 1));
	addr[2] = wt5100_reg_read((GAR0 + 2));
	addr[3] = wt5100_reg_read((GAR0 + 3));
}


/**
@brief	It sets up SubnetMask address
*/ 
void setSUBR(
	Uint16 * addr	/**< a pointer to a 4 -byte array responsible to set the SubnetMask address */
	)
{
	wt5100_reg_write((SUBR0 + 0),addr[0]);
	wt5100_reg_write((SUBR0 + 1),addr[1]);
	wt5100_reg_write((SUBR0 + 2),addr[2]);
	wt5100_reg_write((SUBR0 + 3),addr[3]);
}


/**
@brief	This function sets up MAC address.
*/ 
void setSHAR(
	Uint16 * addr	/**< a pointer to a 6 -byte array responsible to set the MAC address. */
	)
{
	wt5100_reg_write((SHAR0 + 0),addr[0]);
	wt5100_reg_write((SHAR0 + 1),addr[1]);
	wt5100_reg_write((SHAR0 + 2),addr[2]);
	wt5100_reg_write((SHAR0 + 3),addr[3]);
	wt5100_reg_write((SHAR0 + 4),addr[4]);
	wt5100_reg_write((SHAR0 + 5),addr[5]);
}


/**
@brief	This function sets up Source IP address.
*/
void setSIPR(
	Uint16 * addr	/**< a pointer to a 4 -byte array responsible to set the Source IP address. */
	)
{
	wt5100_reg_write((SIPR0 + 0),addr[0]);
	wt5100_reg_write((SIPR0 + 1),addr[1]);
	wt5100_reg_write((SIPR0 + 2),addr[2]);
	wt5100_reg_write((SIPR0 + 3),addr[3]);
}


/**
@brief	This function gets Interrupt register in common register.
 */
uint8 getIR( void )
{
   return wt5100_reg_read(IR);
}



/**
@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 timeout)
{
	wt5100_reg_write(RTR0,(uint8)((timeout & 0xff00) >> 8));
	wt5100_reg_write((RTR0 + 1),(uint8)(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 retry)
{
	wt5100_reg_write(RCR,retry);
}


/**
@brief	This function set the interrupt mask Enable/Disable appropriate Interrupt. ('1' : interrupt enable)

If any bit in IMR is set as '0' then there is not interrupt signal though the bit is
set in IR register.
*/
void setIMR(uint8 mask)
{
	wt5100_reg_write(IMR,mask); // must be setted 0x10.
}


/**
@brief	These below functions are used to get the Gateway, SubnetMask
		and Source Hardware Address (MAC Address) and Source IP address
*/
void getGAR(Uint16 * addr)
{
	addr[0] = wt5100_reg_read(GAR0);
	addr[1] = wt5100_reg_read(GAR0+1);
	addr[2] = wt5100_reg_read(GAR0+2);
	addr[3] = wt5100_reg_read(GAR0+3);
}
void getSUBR(Uint16 * addr)
{
	addr[0] = wt5100_reg_read(SUBR0);
	addr[1] = wt5100_reg_read(SUBR0+1);
	addr[2] = wt5100_reg_read(SUBR0+2);
	addr[3] = wt5100_reg_read(SUBR0+3);
}
void getSHAR(Uint16 * addr)
{
	addr[0] = wt5100_reg_read(SHAR0);
	addr[1] = wt5100_reg_read(SHAR0+1);
	addr[2] = wt5100_reg_read(SHAR0+2);
	addr[3] = wt5100_reg_read(SHAR0+3);
	addr[4] = wt5100_reg_read(SHAR0+4);
	addr[5] = wt5100_reg_read(SHAR0+5);
}
void getSIPR(Uint16 * addr)
{
	addr[0] = wt5100_reg_read(SIPR0);
	addr[1] = wt5100_reg_read(SIPR0+1);
	addr[2] = wt5100_reg_read(SIPR0+2);
	addr[3] = wt5100_reg_read(SIPR0+3);
}


/**
@brief	These below functions are used to get the Destination Hardware Address (MAC Address), Destination IP address and Destination Port.
*/
void getSn_DHAR(SOCKET s, Uint16 * addr)
{
	addr[0] = wt5100_reg_read(Sn_DHAR0(s));
	addr[1] = wt5100_reg_read(Sn_DHAR0(s)+1);
	addr[2] = wt5100_reg_read(Sn_DHAR0(s)+2);
	addr[3] = wt5100_reg_read(Sn_DHAR0(s)+3);
	addr[4] = wt5100_reg_read(Sn_DHAR0(s)+4);
	addr[5] = wt5100_reg_read(Sn_DHAR0(s)+5);
}
void setSn_DHAR(SOCKET s, Uint16 * addr)
{
	wt5100_reg_write((Sn_DHAR0(s) + 0),addr[0]);
	wt5100_reg_write((Sn_DHAR0(s) + 1),addr[1]);
	wt5100_reg_write((Sn_DHAR0(s) + 2),addr[2]);
	wt5100_reg_write((Sn_DHAR0(s) + 3),addr[3]);
	wt5100_reg_write((Sn_DHAR0(s) + 4),addr[4]);
	wt5100_reg_write((Sn_DHAR0(s) + 5),addr[5]);
}
void getSn_DIPR(SOCKET s, Uint16 * addr)
{
	addr[0] = wt5100_reg_read(Sn_DIPR0(s)) &0x00ff;
	addr[1] = wt5100_reg_read(Sn_DIPR0(s)+1) &0x00ff;
	addr[2] = wt5100_reg_read(Sn_DIPR0(s)+2) &0x00ff;
	addr[3] = wt5100_reg_read(Sn_DIPR0(s)+3) &0x00ff;
}
void setSn_DIPR(SOCKET s, Uint16 * addr)
{
//	Uint16 val;
//	val = addr[0];
//	val = addr[1];
		
	//val = (addr[0]&0xff) << 8 | (addr[1]&0xff);
	wt5100_reg_write((Sn_DIPR0(s) + 0), addr[0]);
	wt5100_reg_write((Sn_DIPR0(s) + 1), addr[1]);
	//val = (addr[2]&0xff) << 8 | (addr[3]&0xff);	
	wt5100_reg_write((Sn_DIPR0(s) + 2), addr[2]);
	wt5100_reg_write((Sn_DIPR0(s) + 3), addr[3]);
}
void getSn_DPORT(SOCKET s, Uint16 * addr)
{
	addr[0] = wt5100_reg_read(Sn_DPORT0(s));
	addr[1] = wt5100_reg_read(Sn_DPORT0(s)+1);
}
void setSn_DPORT(SOCKET s, Uint16 * addr)
{
	wt5100_reg_write((Sn_DPORT0(s) + 0),addr[0]);
	wt5100_reg_write((Sn_DPORT0(s) + 1),addr[1]);
}


/**
@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 Sn_MSSR0)
{
	wt5100_reg_write(Sn_MSSR0(s),(uint8)((Sn_MSSR0 & 0xff00) >> 8));
	wt5100_reg_write((Sn_MSSR0(s) + 1),(uint8)(Sn_MSSR0 & 0x00ff));
}

void setSn_TTL(SOCKET s, uint8 ttl)
{
   wt5100_reg_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 proto)
{
	wt5100_reg_write(Sn_PROTO(s),proto);
}


/**
@brief	get socket interrupt status

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


/**
@brief	 get socket status
*/
int getSn_SR(SOCKET s)
{
   return wt5100_reg_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
*/
int getSn_TX_FSR(SOCKET s)
{
	int val=0,val1=0;
	do
	{
		val1 = wt5100_reg_read(Sn_TX_FSR0(s));
		val1 = (val1 << 8) + wt5100_reg_read(Sn_TX_FSR0(s) + 1);
      if (val1 != 0)
		{
   			val = wt5100_reg_read(Sn_TX_FSR0(s));
   			val = (val << 8) + wt5100_reg_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. 
*/
int getSn_RX_RSR(SOCKET s)
{
	int val=0,val1=0;
	do
	{
		val1 = wt5100_reg_read(Sn_RX_RSR0(s));
		val1 = (val1 << 8) + wt5100_reg_read(Sn_RX_RSR0(s) + 1);
      if(val1 != 0)
		{
   			val = wt5100_reg_read(Sn_RX_RSR0(s));
   			val = (val << 8) + wt5100_reg_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 *data, Uint16 len, t_bool bPack)
{
	Uint16 ptr;
	ptr = wt5100_reg_read(Sn_TX_WR0(s));
	ptr = ((ptr & 0x00ff) << 8) + wt5100_reg_read(Sn_TX_WR0(s) + 1);
	write_data(s, data, (uint8 *)(ptr), len, bPack);
	ptr += len;
	wt5100_reg_write(Sn_TX_WR0(s),(uint8)((ptr & 0xff00) >> 8));
	wt5100_reg_write((Sn_TX_WR0(s) + 1),(uint8)(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 *data, Uint16 len, t_bool bPack)
{
	Uint16 ptr;
	ptr = wt5100_reg_read(Sn_RX_RD0(s));
	ptr = ((ptr & 0x00ff) << 8) + wt5100_reg_read(Sn_RX_RD0(s) + 1);

	read_data(s, (uint8 *)ptr, data, len, bPack); // read data
	ptr += len;
	wt5100_reg_write(Sn_RX_RD0(s),(uint8)((ptr & 0xff00) >> 8));
	wt5100_reg_write((Sn_RX_RD0(s) + 1),(uint8)(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, vuint8 * src, vuint8 * dst, Uint16 len, t_bool bPack)
{
	Uint16 size;
	Uint16 dst_mask;
	uint8 * dst_ptr;

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


/**
@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, vuint8 * src, vuint8 * dst, Uint16 len, t_bool bPack)
{
	Uint16 size;
	Uint16 src_mask;
	uint8* src_ptr;
	t_ui16 byData;
	t_ui32 cnt=0, idx=0, is_next_high=0, size_tmp;
	t_ui16 *pwDstPtr;

	src_mask = (Uint16)src & getIINCHIP_RxMASK(s);
	src_ptr = (uint8 *)(getIINCHIP_RxBASE(s) + src_mask);
	
	if(bPack){
		
		
		// F2812(16bit메모리)와 C6711(8bit메모리)을 모두 호환되게 하기 위해서는 dest buffer를 16비트 포인터로 사용해야 한다.
		pwDstPtr = (t_ui16 *)dst; 
		if( (src_mask + len) > getIINCHIP_RxMAX(s) ) 
		{
			size = getIINCHIP_RxMAX(s) - src_mask;
			size_tmp = size;
			//wiz_read_buf((Uint16)src_ptr, (uint8*)dst,size);
			*((vuint16 *)(W5100+1)) = (Uint16)src_ptr >> 8;
			*((vuint16 *)(W5100+2)) = (Uint16)src_ptr & 0xff;
			while(size_tmp > 0){
				byData = *((vuint16 *)(W5100+3)) & 0xff;
				if(is_next_high){ // high-byte must be set
					pwDstPtr[idx] = pwDstPtr[idx] | (byData << 8);
					is_next_high = 0;
					idx++;
				}else{ // low-byte must be set
					pwDstPtr[idx] = byData;				
					is_next_high = 1;
				}
				size_tmp--;
			} 
			
			size = len - size;
			src_ptr = (uint8 *)(getIINCHIP_RxBASE(s));
			*((vuint16 *)(W5100+1)) = (Uint16)src_ptr >> 8;
			*((vuint16 *)(W5100+2)) = (Uint16)src_ptr & 0xff;
			size_tmp = size;
			while(size_tmp > 0){
				byData = *((vuint16 *)(W5100+3)) & 0xff;
				if(is_next_high){ // high-byte must be set
					pwDstPtr[idx] = pwDstPtr[idx] | (byData << 8);
					is_next_high = 0;
					idx++;
				}else{ // low-byte must be set
					pwDstPtr[idx] = byData;				
					is_next_high = 1;
				}
				size_tmp--;
			} 
		} 
		else
		{
			size_tmp = len;
			*((vuint16 *)(W5100+1)) = (Uint16)src_ptr >> 8;
			*((vuint16 *)(W5100+2)) = (Uint16)src_ptr & 0xff;
			while(size_tmp > 0){
				byData = *((vuint16 *)(W5100+3)) & 0xff;
				if(is_next_high){ // high-byte must be set
					pwDstPtr[idx] = pwDstPtr[idx] | (byData << 8);
					is_next_high = 0;
					idx++;
				}else{ // low-byte must be set
					pwDstPtr[idx] = byData;				
					is_next_high = 1;
				}
				size_tmp--;
			} 
		}
	}else{
		if( (src_mask + len) > getIINCHIP_RxMAX(s) ) 
		{
			size = getIINCHIP_RxMAX(s) - src_mask;
			wiz_read_buf((Uint16)src_ptr, (uint8*)dst,size);
			dst += size;
			size = len - size;
			src_ptr = (uint8 *)(getIINCHIP_RxBASE(s));
			wiz_read_buf((Uint16)src_ptr, (uint8*)dst,size);
		} 
		else
		{
			wiz_read_buf((Uint16)src_ptr, (uint8*)dst,len);
		}
	}
}

//****************************************************************************************************************
//*
//*						socket.c
//*
//****************************************************************************************************************

bool w5100_IsTxReady(SOCKET s)
{
	return (wt5100_reg_read(Sn_CR(s)) == 0x0); // Sn_CR 값이 0x0 이면 Ready 상태임.
}


static t_i32 local_port;

/**
@brief	This Socket function initialize the channel in perticular mode, and set the port and wait for W5100 done it.
@return 	1 for sucess else 0.
*/  
uint8 socket(
	SOCKET s, 		/**< for socket number */
	uint8 protocol, 	/**< for socket protocol */
	Uint16 port, 		/**< the source port for the socket */
	uint8 flag		/**< the option for the socket */
	)
{
	uint8 ret;
	if ((protocol == Sn_MR_TCP) || (protocol == Sn_MR_UDP) || (protocol == Sn_MR_IPRAW) || (protocol == Sn_MR_MACRAW) || (protocol == Sn_MR_PPPOE))
	{
		close2(s);
		wt5100_reg_write(Sn_MR(s),protocol | flag);
		if (port != 0) {
			wt5100_reg_write(Sn_PORT0(s),(uint8)((port & 0xff00) >> 8));
			wt5100_reg_write((Sn_PORT0(s) + 1),(uint8)(port & 0x00ff));
		} else {
			local_port++; // if don't set the source port, set local_port number.
			wt5100_reg_write(Sn_PORT0(s),(uint8)((local_port & 0xff00) >> 8));
			wt5100_reg_write((Sn_PORT0(s) + 1),(uint8)(local_port & 0x00ff));
		}
		wt5100_reg_write(Sn_CR(s),Sn_CR_OPEN); // run sockinit Sn_CR
		ret = 1;
	}
	else
	{
		ret = 0;
	}
	return ret;
}


/**
@brief	This function close the socket and parameter is "s" which represent the socket number
*/ 
void close2(SOCKET s)
{
	wt5100_reg_write(Sn_CR(s),Sn_CR_CLOSE);
}


/**
@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 listen(
	SOCKET s	/**< the socket number */
	)
{
	uint8 ret;
	if (wt5100_reg_read(Sn_SR(s)) == SOCK_INIT)
	{
		wt5100_reg_write(Sn_CR(s),Sn_CR_LISTEN);
		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 connect(SOCKET s, uint8 * addr, Uint16 port)
{
	uint8 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
		wt5100_reg_write(Sn_DIPR0(s),addr[0]);
		wt5100_reg_write((Sn_DIPR0(s) + 1),addr[1]);
		wt5100_reg_write((Sn_DIPR0(s) + 2),addr[2]);
		wt5100_reg_write((Sn_DIPR0(s) + 3),addr[3]);
		wt5100_reg_write(Sn_DPORT0(s),(uint8)((port & 0xff00) >> 8));
		wt5100_reg_write((Sn_DPORT0(s) + 1),(uint8)(port & 0x00ff));
		wt5100_reg_write(Sn_CR(s),Sn_CR_CONNECT);
		// wait for completion
		while (wt5100_reg_read(Sn_CR(s)))
		{
			if (wt5100_reg_read(Sn_SR(s)) == SOCK_CLOSED)
			{
				ret = 0; break;
			}
		}
	}

	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)
{
	wt5100_reg_write(Sn_CR(s),Sn_CR_DISCON);
}


/**
@brief	This function used to send the data in TCP mode
@return	1 for success else 0.
*/ 

Uint16 send(
	SOCKET s, 		/**< the socket index */
	const uint8 * buf, 	/**< a pointer to data */
	Uint16 len,		/**< the data size to be send */
	t_bool bPack
	)
{
	uint8 status=0;
	Uint16 ret=0;
	t_ui32 freesize=0;

   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 = wt5100_reg_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 *)buf, ret, bPack);
	wt5100_reg_write(Sn_CR(s),Sn_CR_SEND);

	// wait for completion
	while ( (wt5100_reg_read(Sn_IR(s)) & Sn_IR_SEND_OK) != Sn_IR_SEND_OK )
	{
		status = wt5100_reg_read(Sn_SR(s));
		if (status == SOCK_CLOSED)
		{
			putISR(s, getISR(s) & (Sn_IR_RECV | Sn_IR_DISCON | Sn_IR_CON));
			wt5100_reg_write(Sn_IR(s), (Sn_IR_SEND_OK | Sn_IR_TIMEOUT));
			return 0;
		}
     }
    putISR(s, getISR(s) & (~Sn_IR_SEND_OK));
	wt5100_reg_write(Sn_IR(s), Sn_IR_SEND_OK);
  	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 recv(
	SOCKET s, 	/**< socket index */
	uint8 * buf, 	/**< a pointer to copy the data to be received */
	Uint16 len,	/**< the data size to be read */
	t_bool bPack
	)
{
	t_i32 ret=0;

	if ( len > 0 )
	{
		recv_data_processing(s, buf, len, bPack);
		wt5100_reg_write(Sn_CR(s),Sn_CR_RECV);
		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 sendto(
	SOCKET s, 		/**< socket index */
	const uint8 * buf, 	/**< a pointer to the data */
	Uint16 len, 		/**< the data size to send */
	uint8 * addr, 		/**< the peer's Destination IP address */
	t_i32 port		/**< the peer's destination port number */
	)
{
	Uint16 val=0;
	uint8 status=0;
	uint8 isr=0;
	Uint16 ret=0;
		
	val = getIINCHIP_TxMAX(s);
	
   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) ) 
 	{
 	   return 0;
	}
	else
	{
		// 먼저 이전 명령이 완료되었는지 체크 한다.
		while ( !w5100_IsTxReady(s) ) // Sn_CR 이 0 이면 SEND 또는 RECV 작업이 완료된 상태임=>IDLE 상태.
		{
		#ifndef __DEF_IINCHIP_INT__
			isr = wt5100_reg_read(Sn_IR(s));
		#endif
			if ((isr & Sn_IR_TIMEOUT) || (getISR(s) & Sn_IR_TIMEOUT))
			{
				putISR(s, getISR(s) & (Sn_IR_RECV | Sn_IR_DISCON | Sn_IR_CON));  // clear SEND_OK & TIMEOUT in I_STATUS[s]
				wt5100_reg_write(Sn_IR(s), (Sn_IR_SEND_OK | Sn_IR_TIMEOUT));						// clear SEND_OK & TIMEOUT in Sn_IR(s)
			}
		}
		putISR(s, getISR(s) & (~Sn_IR_SEND_OK)); // FIXME: 이부분이 필요한지?
	   	wt5100_reg_write(Sn_IR(s), Sn_IR_SEND_OK); // FIXME: 이부분이 필요한지?

		// 위에서 먼저 이전 SEND 확인 후 SEND 작업 개시.
		wt5100_reg_write(Sn_DIPR0(s),addr[0]);
		wt5100_reg_write((Sn_DIPR0(s) + 1),addr[1]);
		wt5100_reg_write((Sn_DIPR0(s) + 2),addr[2]);
		wt5100_reg_write((Sn_DIPR0(s) + 3),addr[3]);
#if 0 // 기존 잘못된 코드, 
		val = (port & 0xff00) >> 8;
		wt5100_reg_write(0x410, val);	// 0B
		
		val = port & 0x00ff;
		wt5100_reg_write(0x411, val);	// B8
#else		// 2008.0905 소장님 수정하심. 기존에는 하나의 채널에 대해서만 dest port 를 설정했었다.
		wt5100_reg_write(Sn_DPORT0(s),(uint8)((port & 0xff00) >> 8));
		wt5100_reg_write((Sn_DPORT0(s) + 1),(uint8)(port & 0x00ff));
#endif

      	// copy data
      	send_data_processing(s, (uint8 *)buf, ret, false);
      	
		wt5100_reg_write(Sn_CR(s),Sn_CR_SEND);
		// 전송 명령을 내보낸 뒤 다음 작업을 계속 할 수 있다.(비동기 전송 개념)
	}
	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.
*/ 


extern Uint16 recvfrom(SOCKET s, uint8 * buf, Uint16 len, uint8 * addr, t_ui32  *port, t_bool bPack); // Receive data (UDP/IP RAW)

Uint16 recvfrom(
	SOCKET s, 	/**< the socket number */
	uint8 * buf, 	/**< a pointer to copy the data to be received */
	Uint16 len, 	/**< the data size to read */
	uint8 * addr, 	/**< a pointer to store the peer's IP address */
	t_ui32 *port,	/**< a pointer to store the peer's port number. */
	t_bool bPack
	)
{
	uint8 head[8];
	t_i32 data_len=0;
	Uint16 ptr=0;
	
	if ( len > 0 )
	{
	   	ptr = wt5100_reg_read(Sn_RX_RD0(s));
	   	ptr = ((ptr & 0x00ff) << 8) + wt5100_reg_read(Sn_RX_RD0(s) + 1);
		//printf("ISR_RX: rd_ptr : %.4x\r\n", ptr);
	   	switch (wt5100_reg_read(Sn_MR(s)) & 0x07)
	   	{
	   	case Sn_MR_UDP :
			read_data(s, (uint8 *)ptr, head, 8, false);
			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];

			// 지정한 버퍼를 초과하지 못한다. => 이 부분은 여러번 나누어 수신 버퍼를 처리하려 했으나 버퍼 수신 처리 특성상 한번에 처리해야 함. 나머지 짤리는 패킷은 소멸됨.
			if(data_len > len){
				read_data(s, (uint8 *)ptr, buf, len, bPack); // data copy.
				data_len = len;
			}else{
				read_data(s, (uint8 *)ptr, buf, data_len, bPack); // data copy.
			}
			ptr += data_len; // len 크기로 읽었든지 data_len 크기로 읽었든지 헤더에서 읽어들인 data_len 으로 UDP 패킷 read 처리를 완료해야 함.
		
			wt5100_reg_write(Sn_RX_RD0(s),(uint8)((ptr & 0xff00) >> 8));
			wt5100_reg_write((Sn_RX_RD0(s) + 1),(uint8)(ptr & 0x00ff));
			break;
	
	   	default :
	   		break;
	   	}

		wt5100_reg_write(Sn_CR(s),Sn_CR_RECV);
	}

 	return data_len;
}


Uint16 igmpsend(SOCKET s, const uint8 * buf, Uint16 len)
{
	//uint8 status=0;
	uint8 isr=0;
	t_i32 ret=0;
	
#ifdef __DEF_IINCHIP_DBG__
//	printf("igmpsend()\r\n");
#endif
   if (len > getIINCHIP_TxMAX(s)) ret = getIINCHIP_TxMAX(s); // check size not to exceed MAX size.
   else ret = len;

	if	(ret == 0) 
 	{
 	   
#ifdef __DEF_IINCHIP_DBG__
//	printf("%d Fail[%d]\r\n",len);
#endif
	}
	else
	{
		// copy data
		send_data_processing(s, (uint8 *)buf, ret, false);
		wt5100_reg_write(Sn_CR(s),Sn_CR_SEND);
      
      		while (wt5100_reg_read(Sn_CR(s)))
		{
			// status = wt5100_reg_read(Sn_SR(s));
#ifndef __DEF_IINCHIP_INT__			
			isr = wt5100_reg_read(Sn_IR(s));
#endif
			if ((getISR(s) & Sn_IR_TIMEOUT) || (isr & Sn_IR_TIMEOUT))
			{
#ifdef __DEF_IINCHIP_DBG__
//				printf("igmpsend fail.\r\n");
#endif
				putISR(s, getISR(s) & (Sn_IR_RECV | Sn_IR_DISCON | Sn_IR_CON));
				wt5100_reg_write(Sn_IR(s), (Sn_IR_SEND_OK | Sn_IR_TIMEOUT));
				return 0;
			}
		}
		putISR(s, getISR(s) & (~Sn_IR_SEND_OK));
	   	wt5100_reg_write(Sn_IR(s), Sn_IR_SEND_OK);
	}
	return ret;
}


//****************************************************************************************************************
//*
//*						EIP_Ethernet.c
//*
//****************************************************************************************************************

Uint16 gSn_RX_BASE[4];
Uint16 gSn_RX_MASK[4];

Uint16 gSn_TX_BASE[4];
Uint16 gSn_TX_MASK[4];

//CHIP_BASE_ADDR + RX_BASE_ADDR
t_char	bchannel_start[MAX_SOCK_NUM] = {0, 0, 0, 0};	// 0:close, 1:ready, 2:connect

//int *LAN_CS = (int *)0x2000;
extern int *W5100;
enum SOCK_TYPE { UDP, TCP1, TCP2, UDP_B };

void loopback_udp(t_ui32 ch);	//< channel(socket) index
void loopback_tcps(t_ui32 ch); 	//< channel(socket) index 

//bool OpenSocket();
//bool SetSocket_B();
void SendTest();
void SendTest2();

void setsubmask(t_char * addr)					// Set subnet mask value
{
	wt5100_reg_write(0x0005, addr[0]);
	wt5100_reg_write(0x0006, addr[1]);
	wt5100_reg_write(0x0007, addr[2]);
	wt5100_reg_write(0x0008, addr[3]);
}

void setgateway(t_char * addr)                                         // Set Gateway IP address
{
	wt5100_reg_write(0x0001, addr[0]);
	wt5100_reg_write(0x0002, addr[1]);
	wt5100_reg_write(0x0003, addr[2]);
	wt5100_reg_write(0x0004, addr[3]);
}

void setMACAddr(t_char * addr)                                         // Set Mac address
{
	wt5100_reg_write(0x0009, addr[0]);
	wt5100_reg_write(0x000A, addr[1]);
	wt5100_reg_write(0x000B, addr[2]);
	wt5100_reg_write(0x000C, addr[3]);
	wt5100_reg_write(0x000D, addr[4]);
	wt5100_reg_write(0x000E, addr[5]);
}

void setIP(t_char * addr)                                              // Set source IP address
{
	wt5100_reg_write(0x000F, addr[0]);
	wt5100_reg_write(0x0010, addr[1]);
	wt5100_reg_write(0x0011, addr[2]);
	wt5100_reg_write(0x0012, addr[3]);
}


void InitNetConfig(t_char addr[])
{
	t_char ip[6];
	
	// set IP, subnet, gateway address
	// ip address
	/*
	wt5100_reg_write(0x000F, addr[0]);
	wt5100_reg_write(0x0010, addr[1]);
	wt5100_reg_write(0x0011, addr[2]);
	wt5100_reg_write(0x0012, addr[3]);
	*/
	
	Delay_ms(1);
	
	//00-05-ea-50-32-(00~ff)
	// MAC address
	ip[0] = 0x00; ip[1] = 0x05; ip[2] = 0xea; ip[3] = 0x50; ip[4] = 0x32; ip[5] = addr[3];
	setMACAddr(ip);
	Delay_ms(1);	
	
	setIP(addr);	
	
	// subnet mask
	ip[0] = 255; ip[1] = 255; ip[2] = 255; ip[3] = 0;
	setsubmask(ip);
	Delay_ms(1);		
	
	// gateway address
	//ip[0] = 192; ip[1] = 168; ip[2] = 1; ip[3] = 254;
	//setgateway(ip);
}


//-------------------------------------------------------------------------------------------------------
//               TCP timeout setup function
//
// Description : TCP retransmission time setup function.
//     Timeout Interrupt occurs if the number of retransmission exceed the limit when establishing connection and data transmission. 
// Arguments   : val - Pointer having the value to setup timeout
//     Lower 2byte is for initial timeout, Upper 1byte is for the number of retransmission by timeout
//	   val[0]: low-byte of initial time-value
//     val[1]: high-byte of initial time-value
//     val[2]: retry count
// Returns     : None
// Note        : API Function
//-------------------------------------------------------------------------------------------------------
void settimeout(t_char * val)
{
	wt5100_reg_write(0x0017, val[0]&0x00ff);
	wt5100_reg_write(0x0018, val[1]&0x00ff);
	wt5100_reg_write(0x0019, val[2]&0x00ff);	
	
	/*
	// set RTR 예:
	wt5100_reg_write(0x0017, 0x13);
	wt5100_reg_write(0x0018, 0x88);	// timeout: 5000 (0x1388) => 500ms (1 means 100us)

	// set RCR	
	wt5100_reg_write(0x0019, 0x03);	// retry count : 여기에 설정된 카운트값보다 넘게 retry 되면
									// timeout interrupt (Sn_IR : 1) 이 발생함.
	*/
}

void gettimeout(t_char * val)
{
	val[0] = wt5100_reg_read(0x0017);
	val[1] = wt5100_reg_read(0x0018);
	val[2] = wt5100_reg_read(0x0019);
}


void InitEthernet(t_i32 *wEtherBaseAddr, t_char addr[])
{
	t_char time_out[3];
	
	W5100 = wEtherBaseAddr;	// 0x2000 for W5100
	// 1. Init W5100 chip
	// set MR
	*((Uint16 *)W5100) = 0x80;	// Mode Register Reset
	Delay_ms(5);
	
	*((Uint16 *)W5100) = 0x01 | 0x02;	// indirect addressing | auto increased address mode
	Delay_ms(5);

#ifdef __DEF_IINCHIP_INT__		// if interrupt service involved
	// set IMR
	wt5100_reg_write(0x0016, 0xEF);
#else
	//wt5100_reg_write(0x0016, 0x00);
#endif

	// set RTR & RCR		
	time_out[0] = 0x13;
	time_out[1] = 0x88;
	time_out[2] = 0x03;
	settimeout(time_out);
										
	//Delay_ms(1);
	// 2. Setting network information	
	InitNetConfig(addr);

	//Delay_ms(1);	
	
	// 3. sysinit // RMSR, TMSR
	sysinit(0x55, 0x55);
}


//-------------------------------------------------------------------------------------------------------
//               Function handling the channel socket information.
//
// Description : Return socket information of designated channel
// Arguments   : s    - channel number
//               func - SEL_CONTROL(0x00) -> return socket status 
//                      SEL_SEND(0x01)    -> return free transmit buffer size
//                      SEL_RECV(0x02)    -> return received data size
// Returns     : socket status or free transmit buffer size or received data size
// Note        : API Function
//-------------------------------------------------------------------------------------------------------
t_ui16 select(SOCKET s, t_char func)
{
	t_ui16 val;

	switch (func) {
	case SEL_CONTROL :                                     // socket status information
		val = getSn_SR(s);
		break;

	case SEL_SEND :                                        // Calculate send free buffer size
		// DINT; // Disable interrupt

		// EINT; // Enable interrupt

		break;

	case SEL_RECV :                                        // Calculate received data size	
		// DINT;
		val = getSn_RX_RSR(s); // check Rx data
		// EINT; // Enable interrupt
		break;

	default :
		val = -1;
		break;
	}

    return	( val );
}

#endif // #ifndef _MK_ETHERNET_W5100_H_
