//================================================================================================================
// [Ethernet.h]: 
// -. Version: 1.0.1.0
// -. Update Data: 2008/03/25
// -. Created by OYS
// -. Revision history:
//   1. <Ver 1.0.0.4>: [2007/09/29] 
//    1) UDP 통신의 sendto()에서 destination IP가 변경되면 통신단절됨(W3100 버그). 따라서 SOCKET을 초기화하는
//         루틴 삽입됨.
//    2) send()와 sendto() 함수에서 SEND command를 write한 후에 2us 지연하는 코드 삽입
//    3) send()와 sendto() 함수에서 송신 오류 발생하면 socket을 초기화하는 코드 삽입
//    4) sendto() recv(), recvfrom() 함수의 반환데이터형을 t_ui32에서 t_i32로 변경함.
//    5) WT_RegRead()/WT_RegWrite()의 지연시간을 최소화함. address쓰고 data r/w하는 사이에만 100ns 지연을하고
//        나머지 지연은 모두 제거함 
//   2. <Ver 1.0.0.5>: [2007/10/05] 
//    1) UDP 통신 sendto_in() 함수에서 len(frame size)가 176, 180 byte일 때 전송이 몇 번된고 소켓이 죽는 문제 발생
//        => WT_RegWrite(COMMAND(s), CSEND); 수행한 후 지연시간을 2us에서 5us로 수정하여 문제 해결함.
//   3. <Ver 1.0.0.6>: [2007/10/25] 
//    1) Ethernet 케이블이 빠진 상태에서 sendto() 또는 socket()(초켓초기화) 함수를 수행하면 SEND_OK/SOCK_INIT_OK 
//       상태 플래그가 SET되지 않는 W3100 버그가 있다(SOCK_INIT의 경우 pending되어 있다가 네트워크 케이블이 연결
//       되는 순간에 SET된다). 이를 개선하기 위해서 CheckSockInit() 함수를 추가하여 활용하도록 수정되었다.
//   4. <Ver 1.0.0.7>: [2007/11/22] 
//    1) UDP 포트 2개를 사용할때 알수 없는 에러 발생 버그 수정: _netISR()을 Ethernet.h에서 정의하고,
//          mk_net.c의 netISR()에서는 이를 호출하도록 수정함.
//   5. <Ver 1.0.0.8>: [2007/11/28] 
//    1) 신성이엔지 프로그램 구동 시에 Table-D, 또는 Table-W 영역을 read할 때 소켓이 죽는 문제가 발생했다.
//        =>  sendto_in() 함수에서 WT_RegWrite(COMMAND(s), CSEND); 수행한 후 지연 시간을 5us에서 10us로 수정하여
//            문제 해결함.
//    2) 1)번 항목의 문제가 완전히 해결되지 않음(롬 버전에서 동일문제 발생) WT_RegRead()/WT_RegWrite()의 지연시간을 
//       증대하여 문제해결함(각 라인에 모드 200ns 지연 적용)
//   6. <Ver 1.0.0.9>: [2008/03/25] 
//    1) while (WT_RegRead(COMMAND(s)) & CSEND){...} 구문을 WT_RegWrite(COMMAND(s), CSEND); 구문보다 
//       앞서 실행하도록 수정하였다. 이 것으로 다음과 같은 문제들이 해결되었다.
//       a) CEIP SDK를 사용할 때 통신이 죽는 문제(SEND후에 SEND완료가 되지 않는 문제) 해결
//       b) CEIP SDK에서 ping 체크가 되지 않던 문제 해결.
//   7. <Ver 1.0.1.0>: [2008/04/01]
//    1) CheckSockInit() 함수 내부에 if(nSockStat == SOCK_INIT || nSockStat == SOCK_UDP){} 구문 추가됨
//     이 것이 없으면 소켓이 초기화 되었어도 않된 것처럼 인식되는 경우가 발생한다. 
//    2) socket() 함수에서 TCP 모드일 때만 initseqnum() 함수를 호출했는데 UDP 모드에서도 호출하도록 수정하였다.
//     간혹 SEND 시에 W31000 칩의 WRITE 포인터와 READ 포인터 값의 차이가 엄청크게 나는 경우가 발생하는데 이때 READ
//     포인터를 읽어보면 0x12233### 값이고, WRITE 포인터는 작은값(예를 들어 3000 정도)다. READ/WRITE 포인터가 초기화
//     되지 않아서 생기는 문제로 추정되며, 이 조치를 취한 후에 안정적이 되었다. 
//    3) un_l2cval 구조체의 lVal 데이터형이 t_i32 에서 t_ui32로 수정되었다(W3100의 RX/TX의 WRITE_PTR/READ_PTR 연산 시에
//     오류의 소지가 있다.
//    4) W3100의 RX/TX의 WRITE_PTR/READ_PTR 연산 루틴을 모두 바구었다.
//     예전)
//     if (wr_ptr.lVal >= ack_ptr.lVal) size = SSIZE[s] - (wr_ptr.lVal - ack_ptr.lVal);
//     else size = SSIZE[s] - (0 - ack_ptr.lVal + wr_ptr.lVal);
//     수정)
//     if (wr_ptr.lVal >= ack_ptr.lVal) size = SSIZE[s] - (wr_ptr.lVal - ack_ptr.lVal);
//     else size = SSIZE[s] - ((t_ui32)((t_ui32)0xffffffff - ack_ptr.lVal + 1) + wr_ptr.lVal);
//   8. <Ver 1.0.1.0>: [2009/01/13] 
//    1) CSEND 명령을 수행한 후에 지연 시간을 30ms로 늘렸다. 
//		초중량물 로봇 컨트롤러를 개발할 때 시스템 환경설정 데이터를 연속적으로 업로드하면 죽는 문제가 발생했다.
//		여러가지 트러블슈팅을 해본 결과 다음의 send 명령 후에 지연 시간을 10us 이상으로 늘리는 것이 해결책으로 결론되어 졌다.
//      (이전에는 5us이었는데 이 것이 부족했었음). 따라서 안전하게 30us 지연으로 수정하였다.
//			WT_RegWrite(COMMAND(s), CSEND); // SEND
//			wait_1us(30);
//		이 것은 칩 버그인 것으로 판단되지만 어쨋든 반드시 CSEND 명령 후에 상당한 지연이 필요한 것은 확실해졌다.
//================================================================================================================

#ifndef _miCOMMON_ETHERNET_H_
#define _miCOMMON_ETHERNET_H_

#include "mk_common.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <math.h>

#define _DONT_USE_INTERRUPT_   // interrupt를 사용하지 않는 경우에는 이 define문을 선언한다.

//------ VC33 ONLY----------------------------------------------------------
#ifdef _DONT_USE_INTERRUPT_
#define INTLAN_EN()		
#define INTLAN_DIS()	
#else
#define INTLAN_EN()		asm("		OR		0001H,IE ")
#define INTLAN_DIS()	asm("		ANDN	0001H,IE ")
#endif
//--------------------------------------------------------------------------

typedef struct{
	t_ui32 B3:	8;
	t_ui32 B2:	8;
	t_ui32 B1:	8;
	t_ui32 B0:	8;
}TByteArray4;

/* Type for treating 4 byte variables with byte by byte */
typedef union _un_l2cval {
	TByteArray4 cVal;
	t_ui32		lVal;
}un_l2cval;


//-------------------------------------------------------------------------------------------------------
// To prevent occurrence of warning when there's unused function by KEIL compiler,
// include functions to use as using mode
//-------------------------------------------------------------------------------------------------------

#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
//#define __IP_RAW__	// To use upper layer protocol with IP Protocol 

#ifdef __IP_RAW__
	#ifndef __UDP__
		#define __UDP__
	#endif
#endif	

#define	MAX_SOCK_NUM	4			// Concurrent maxmium number of socket

#define MAX_SEGMENT_SIZE	1460		// Maximum TCP transmission packet size
#define MAX_BUF_SIZE1		0


//============================= WT3100A Address Definition ==============================================
#define	SEND_DATA_BUF		0x4000	// Internal Tx buffer address of W3100A
#define	RECV_DATA_BUF		0x6000	// Internal Rx buffer address of W3100A

#define	COMMAND(i)			(i)	// C#_CR (각 소켓의 Command 레지스터), i는 소켓 번호
#define	INT_STATUS(i)		(0x04+(i))
#define	INT_REG				0x08
#define	INTMASK				0x09
#define	RESETSOCK			0x0A

#define RX_PTR_BASE			0x10
#define RX_PTR_SIZE			0x0C
#define	RX_WR_PTR(i)		(RX_PTR_BASE + RX_PTR_SIZE*(i))
#define	RX_RD_PTR(i)   		(RX_PTR_BASE + RX_PTR_SIZE*(i) + 0x04)
#define	RX_ACK_PTR(i)		(TX_PTR_BASE + TX_PTR_SIZE*(i) + 0x08)

#define TX_PTR_BASE			0x40
#define TX_PTR_SIZE			0x0C
#define	TX_WR_PTR(i)		(TX_PTR_BASE + TX_PTR_SIZE*(i))
#define	TX_RD_PTR(i)   		(TX_PTR_BASE + TX_PTR_SIZE*(i) + 0x04)
#define	TX_ACK_PTR(i)		(RX_PTR_BASE + RX_PTR_SIZE*(i) + 0x08)

/* Shadow Register Pointer Define */
#define SHADOW_RXWR_PTR(i)	(0x1E0 + 3*i)
#define	SHADOW_RXRD_PTR(i)	(0x1E1 + 3*i)
#define	SHADOW_TXACK_PTR(i)	(0x1E2 + 3*i)
#define	SHADOW_TXWR_PTR(i)	(0x1F0 + 3*i)
#define SHADOW_TXRD_PTR(i)	(0x1F1 + 3*i)

#define SOCK_BASE			0xA0
#define SOCK_SIZE			0x18
#define SOCK_STATUS(i)		(SOCK_BASE + SOCK_SIZE*(i))
#define OPT_PROTOCOL(i)		(SOCK_BASE + SOCK_SIZE*(i) + 0x01)
#define DST_HA_PTR(i)  		(SOCK_BASE + SOCK_SIZE*(i) + 0x02)
#define DST_IP_PTR(i)		(SOCK_BASE + SOCK_SIZE*(i) + 0x08)
#define DST_PORT_PTR(i)		(SOCK_BASE + SOCK_SIZE*(i) + 0x0C)
#define SRC_PORT_PTR(i)		(SOCK_BASE + SOCK_SIZE*(i) + 0x0E)
#define IP_PROTOCOL(i)		(SOCK_BASE + SOCK_SIZE*(i) + 0x10)
#define TOS(i)				(SOCK_BASE + SOCK_SIZE*(i) + 0x11)
#define MSS(i)				(SOCK_BASE + SOCK_SIZE*(i) + 0x12)
#define P_WINDOW(i)			(SOCK_BASE + SOCK_SIZE*(i) + 0x14)
#define WINDOW(i)			(SOCK_BASE + SOCK_SIZE*(i) + 0x16)

#define GATEWAY_PTR			0x80
#define SUBNET_MASK_PTR		0x84
#define SRC_HA_PTR			0x88
#define SRC_IP_PTR			0x8E
#define TIMEOUT_PTR			0x92
#define RX_DMEM_SIZE		0x95	
#define TX_DMEM_SIZE		0x96

//============================= WT3100A Values Definition ==============================================

/* SOCKET OPTION(Settting OPT_PROTOCOL REG.) */
#define SOCKOPT_BROADCAST	0x80		// Transmission, Reception of broadcasting data
#define SOCKOPT_NDTIMEOUT	0x40		// Setting timeout
#define SOCKOPT_NDACK		0x20		// Setting No Delayed Ack(TCP)
#define SOCKOPT_SWS		0x10		// Setting Silly Window Syndrome(TCP)

/* OPTION(Setting OPT_PROTOCOL REG.) for MAC LAYER RAW MODE */
#define MACLOPT_RXERR		0x80		// Setting reception of error packet
#define MACLOPT_BROADCAST	0x40		// Setting reception of broadcast packet
#define MACLOPT_PROMISC		0x20		// Setting reception of promiscuous packet

/* Distinguish TCP / UDP / IP RAW / MAC RAW (Setting OPT_PROTOCOL REG.) */
#define	SOCK_CLOSEDM		0x00 		// unused socket
#define	SOCK_STREAM		0x01		// TCP
#define	SOCK_DGRAM		0x02		// UDP
#define	SOCK_IPL_RAW		0x03		// IP LAYER RAW SOCK
#define	SOCK_MACL_RAW		0x04		// MAC LAYER RAW SOCK

/* Setting 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              // user datagram protocol 
#define IPPROTO_IDP             22              // xns idp 
#define IPPROTO_ND              77              // UNOFFICIAL net disk proto
#define IPPROTO_RAW             255             // raw IP packet 

/* 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

/* Command variables */
#define CSYS_INIT		0x01	   	// To set up network information(mac address, gateway address, subnet mask, source ip)
#define CSOCK_INIT		0x02		// To initialize socket
#define CCONNECT		0x04		// To establish connection as tcp client mode
#define CLISTEN			0x08		// To wait for connection request as tcp server mode
#define CCLOSE			0x10		// To terminate connection
#define CSEND			0x20		// To send data
#define CRECV			0x40		// To receive data
#define CSW_RESET		0x80		// To do software reset

/* Status Variables */
#define SSYS_INIT_OK		0x01	// Completion of CSYS_INIT command
#define SSOCK_INIT_OK		0x02	// Completion of CSOCK_INIT command
#define SESTABLISHED		0x04	// Completion of connection setup
#define SCLOSED			0x08		// Completion of CCLOSED command
#define STIMEOUT		0x10		// Timout occured at send,sendto command
#define SSEND_OK		0x20		// Completion of sending data
#define SRECV_OK		0x40		// Completion of receiving data

/* Socket Status Vabiables */
#define SOCK_CLOSED		0x00		// Status of connection closed
#define SOCK_ARP		0x01		// Status of ARP
#define SOCK_LISTEN		0x02		// Status of waiting for TCP connection setup
#define SOCK_SYNSENT		0x03		// Status of setting up TCP connection
#define SOCK_SYNSENT_ACK	0x04		// Status of setting up TCP connection
#define SOCK_SYNRECV		0x05		// Status of setting up TCP connection
#define SOCK_ESTABLISHED	0x06		// Status of TCP connection established
#define SOCK_CLOSE_WAIT		0x07		// Status of closing TCP connection
#define SOCK_LAST_ACK		0x08		// Status of closing TCP connection
#define SOCK_FIN_WAIT1		0x09		// Status of closing TCP connection
#define SOCK_FIN_WAIT2		0x0A		// Status of closing TCP connection
#define SOCK_CLOSING		0x0B		// Status of closing TCP connection
#define SOCK_TIME_WAIT		0x0C		// Status of closing TCP connection
#define SOCK_RESET		0x0D		// Status of closing TCP connection
#define SOCK_INIT		0x0E		// Status of socket initialization
#define SOCK_UDP		0x0F		// Status of UDP
#define SOCK_RAW		0x10		// Status of IP RAW

t_i32 WT_RegRead(t_i32 addr);
void WT_RegWrite(t_i32 addr, t_i32 data);
void InitEthernet(t_i32 *dwEtherBaseAddr, u_char addr[]);
void InitNetConfig(u_char addr[]);
void initW3100A(void);							// Initialize W3100A
void sysinit(u_char sbufsize, u_char rbufsize);                         // Specify flexible memory and soft reset W3100A
void setsubmask(u_char * addr);						// Set subnet mask value
void setgateway(u_char * addr);                                         // Set Gateway IP address
void setMACAddr(u_char * addr);                                         // Set Mac address
void setIP(u_char * addr);                                              // Set source IP address

char socket(SOCKET s, u_char protocol, t_ui32 port, u_char flag);        // Open a channel among TCP, UDP, IP_RAW mode


#ifdef __IP_RAW__
void setIPprotocol(SOCKET s, u_char ipprotocol);			// Set upper protocol of IP 
#endif

#ifdef	__OPT__
void settimeout(u_char * val);						// Set re-transmition timeout value
void setINTMask(u_char mask);						// Set Interrupt mask value
void setTOS(SOCKET s, u_char tos);                                      // Set type of service 
void reset_sock(SOCKET s);                                              // Reset the specified channel
#endif


#ifdef	__TCP_CLIENT__
char connect(SOCKET s, u_char * addr, t_ui32 port);
#endif

#ifdef	__TCP_SERVER__
//char listen(SOCKET s, u_char * addr, t_ui32 * port);
void NBlisten(SOCKET s);
#endif

void initseqnum(SOCKET s);

#ifdef	__TCP__
t_i32 send(SOCKET s, const void* buf, t_ui32 len, BOOL bPack);
t_i32 send_in(SOCKET s, const void* buf, t_ui32 len, BOOL bPack);
t_i32 recv(SOCKET s, void* buf, t_ui32 len, BOOL bPack);
#endif	// __TCP__

#ifdef	__UDP__
t_i32 sendto(SOCKET , const u_char*, t_ui32, u_char *, t_ui32);
t_i32 sendto_in(SOCKET , const u_char*, t_ui32);
t_i32 recvfrom(SOCKET, u_char*, t_ui32, u_char *, t_ui32 *, t_i32 bPack);
#endif	// __UDP__

t_ui32 read_data_8(SOCKET s, t_i32 src_addr, u_char* dst, t_ui32 len);
t_ui32 read_data_32(SOCKET s, t_i32 src_addr, t_i32* dst, t_ui32 len);
t_ui32 write_data_8(SOCKET s, const u_char* src, t_i32 dst_addr, t_ui32 len);
t_ui32 write_data_32(SOCKET s, const t_i32* src, t_i32 dst_addr, t_ui32 len);

void close(SOCKET s);
t_ui32 select(SOCKET s, u_char func);
void _netISR(void);

//#define wait_1ms(ms)	Delay_ms(ms)
//#define wait_1us(us) 	Delay_us(us);


// ****************************************************************************************************************
// *								C SOURCE CONTENTs
// ****************************************************************************************************************

un_l2cval SEQ_NUM;               // Set initial sequence number
u_char I_STATUS[4]={0,0,0,0};              // Store Interrupt Status according to channels
t_ui32 Local_Port;                // Designate Local Port
t_ui32 SMASK[MAX_SOCK_NUM];      // Variable to store MASK of Tx in each channel, on setting dynamic memory size.
t_ui32 RMASK[MAX_SOCK_NUM];      // Variable to store MASK of Rx in each channel, on setting dynamic memory size.
t_i32 SSIZE[MAX_SOCK_NUM];         // Maximun Tx memory size by each channel
t_i32 RSIZE[MAX_SOCK_NUM];         // Maximun Rx memory size by each channel
u_char SBUFBASEADDRESS[MAX_SOCK_NUM];     // Maximun Tx memory base address by each channel
u_char RBUFBASEADDRESS[MAX_SOCK_NUM];     // Maximun Rx memory base address by each channel
t_ui32 g_adwPrvUdpDestIp[MAX_SOCK_NUM];
t_i32 g_anPrvUdpDestPort[MAX_SOCK_NUM];
t_bool g_bWizSockInited[MAX_SOCK_NUM]={false, false, false, false};

t_i32 *LAN_CS = (t_i32 *)0xF20000; // [CAUTION] 시스템에 따라서 Base address가 달라질 수 있다. 

t_i32 _WT_RegRead(t_i32 addr) 
{
	t_i32 Value;

#if 1
	Outp32(LAN_CS, 1, (addr&0xff));
	Delay_200ns();
	Outp32(LAN_CS, 2, (addr>>8));
	Delay_200ns();
	Value = Inp32(LAN_CS, 3) & 0xff;
	Delay_200ns();
#else
	Delay_200ns();
	Outp32(LAN_CS, 1, (addr&0xff));
	Delay_200ns();
	Outp32(LAN_CS, 2, (addr>>8));
	Delay_200ns();
	Value = Inp32(LAN_CS, 3) & 0xff;
	Delay_200ns();
#endif
	return(Value);
}

void _WT_RegWrite(t_i32 addr, t_i32 data)
{
#if 1
	Outp32(LAN_CS, 1, (addr&0xff));
	Delay_200ns();
	Outp32(LAN_CS, 2, (addr>>8));
	Delay_200ns();
	Outp32(LAN_CS, 3, data&0xff);
	Delay_200ns();
#else
	Delay_200ns();
	Outp32(LAN_CS, 1, (addr&0xff));
	Delay_200ns();
	Outp32(LAN_CS, 2, (addr>>8));
	Delay_200ns();
	Outp32(LAN_CS, 3, data&0xff);
	Delay_200ns();
#endif
}

t_i32 WT_RegRead(t_i32 addr) 
{
	t_i32 value;
	INTLAN_DIS();
	value = _WT_RegRead(addr);
	INTLAN_EN();
	return (value);
}

void WT_RegWrite(t_i32 addr, t_i32 data)
{
	INTLAN_DIS();
	_WT_RegWrite(addr, data);
	INTLAN_EN();
}


void InitEthernet(t_i32 *dwEtherBaseAddr, u_char addr[])
{
	LAN_CS = dwEtherBaseAddr;
	*(LAN_CS+0) = 0x82; /* IDM 모드 & non increases address */
	wait_1us(100);
	initW3100A();
	wait_1us(100);
	InitNetConfig(addr);
}

//-------------------------------------------------------------------------------------------------------
// Description   :  Initialize Network Information to be used by W3100
// Argument      :  
// Return Value  :  
// Note          :  
//-------------------------------------------------------------------------------------------------------
void InitNetConfig(u_char addr[])
{	
	t_i32 i, j;
	char c;
	u_char ip[6];  	       		// Variable for setting up network information
	u_char ipstr[16];
	un_l2cval tip;

	ip[0] = 0x00; ip[1] = 0x05; ip[2] = 0xEA; ip[3] = 0x50; ip[4] = 0x32; ip[5] = addr[3];     // ETC.
	setMACAddr(ip);		// Setup MAC
	wait_1ms(1);
	setIP(addr);		// Setup source IP
	wait_1ms(1);
	ip[0] = 192; ip[1] = 168; ip[2] = 1; ip[3] = 254;		// VPN Env.
	setgateway(ip);		// Setup gateway address
	//setgateway(addr);		// Setup gateway address
	wait_1ms(1);
	ip[0] = 255; ip[1] = 255; ip[2] = 255; ip[3] = 0;
	//ip[0] = 0; ip[1] = 0; ip[2] = 0; ip[3] = 0;
	setsubmask(ip);		// Setup subnet mask
	
	wait_1ms(1);
	
	sysinit(0x55, 0x55); // 각 채널별 송수신버퍼 모두를 2K, 2K, 2K, 2K
	//sysinit(0x0A, 0x0A); // 각 채널별 송수신버퍼 모두를 4K, 4K, 0K, 0K
	
	wait_1ms(1);
}

//-------------------------------------------------------------------------------------------------------
//               W3100A initialization function
//
// Description :
//   Function for S/W resetting of the W3100A.
//   Sets the initial SEQ# to be used for TCP communication.
// Arguments   : None
// Returns     : None
// Note        : API Function
//-------------------------------------------------------------------------------------------------------
void initW3100A(void)
{
    Local_Port = 3000;          // This default value will be set if you didn't designate it when you create a socket
                                // If you don't designate port number and create a socket continuously,
                                // the port number will be assigned with incremented by one to Local_Port
    SEQ_NUM.lVal = 0x12233445;  // Sets the initial SEQ# to be used for TCP communication. (It should be ramdom value)
    WT_RegWrite(COMMAND(0), CSW_RESET); // Software RESET
	wait_1ms(1);
	//setINTMask(0xff); // receive intrrupt 사용할 때
	//setINTMask(0x0f);  // receive intrrupt 사용하지 않을 때
	setINTMask(0x00);  // receive intrrupt 사용하지 않을 때
}


//-------------------------------------------------------------------------------------------------------
//               W3100A initialization function
//
// Description : 
//   Sets the Tx, Rx memory size by each channel, source MAC, source IP, gateway, and subnet mask
//   to be used by the W3100A to the designated values.
//   May be called when reflecting modified network information or Tx, Rx memory size on the W3100A
//   Include Ping Request for ARP update (In case that a device embedding W3100A is directly connected to Router)
// Arguments   : sbufsize - Tx memory size (00 - 1KByte, 01- 2KBtye, 10 - 4KByte, 11 - 8KByte)
//                          bit 1-0 : Tx memory size of channel #0 
//                          bit 3-2 : Tx memory size of channel #1 
//                          bit 5-4 : Tx memory size of channel #2
//                          bit 7-6 : Tx memory size of channel #3 
//               rbufsize - Rx memory size (00 - 1KByte, 01- 2KBtye, 10 - 4KByte, 11 - 8KByte)
//                          bit 1-0 : Rx memory size of channel #0 
//                          bit 3-2 : Rx memory size of channel #1 
//                          bit 5-4 : Rx memory size of channel #2
//                          bit 7-6 : Rx memory size of channel #3 
// Returns     : None
// Note        : API Function
//               Maximum memory size for Tx, Rx in W3100A is 8KBytes,
//               In the range of 8KBytes, the memory size could be allocated dynamically by each channel 
//               Be attentive to sum of memory size shouldn't exceed 8Kbytes
//               and to data transmission and receiption from non-allocated channel may cause some problems.
//               If 8KBytes memory already is assigned to centain channel, other 3 channels couldn't be used, for there's no available memory.
//               If two 4KBytes memory are assigned to two each channels, other 2 channels couldn't be used, for there's no available memory.
//               (Example of memory assignment)
//                sbufsize => 00000011, rbufsize => 00000011 : Assign 8KBytes for Tx and Rx to channel #0, Cannot use channel #1,#2,#3
//                sbufsize => 00001010, rbufsize => 00001010 : Assign 4KBytes for Tx and Rx to each channel #0,#1 respectively. Cannot use channel #2,#3
//                sbufsize => 01010101, rbufsize => 01010101 : Assign 2KBytes for Tx and Rx to each all channels respectively.
//                sbufsize => 00010110, rbufsize => 01010101 : Assign 4KBytes for Tx, 2KBytes for Rx to channel #0
//                                                             2KBytes for Tx, 2KBytes for Rx to channel #1
//                                                             2KBytes for Tx, 2KBytes for Rx to channel #2
//                                                             2KBytes is available exclusively for Rx in channel #3. There's no memory for Tx.
//-------------------------------------------------------------------------------------------------------

void sysinit(u_char sbufsize, u_char rbufsize)
{
	char i;
	t_i32 ssum,rsum;

	ssum = 0;
	rsum = 0;
	
	WT_RegWrite(TX_DMEM_SIZE, sbufsize);                 // Set Tx memory size for each channel
	WT_RegWrite(RX_DMEM_SIZE, rbufsize);                 // Set Rx memory size for each channel
	
	SBUFBASEADDRESS[0] = SEND_DATA_BUF;      // Set Base Address of Tx memory for channel #0
	RBUFBASEADDRESS[0] = RECV_DATA_BUF;      // Set Base Address of Rx memory for channel #0

	for(i = 0 ; i < MAX_SOCK_NUM; i++)               // Set maximum memory size for Tx and Rx, mask, base address of memory by each channel
	{
		SSIZE[i] = 0;
		RSIZE[i] = 0;
		g_adwPrvUdpDestIp[i] = 0;
		g_anPrvUdpDestPort[i] = -1;
		if(ssum < 8192)
		{
			switch((sbufsize >> i*2) & 0x03) // Set maximum Tx memory size
			{
			case 0:
				SSIZE[i] = 1024;
				SMASK[i] = 0x000003FF;
				break;
			case 1:
				SSIZE[i] = 2048;
				SMASK[i] = 0x000007FF;
				break;
			case 2:
				SSIZE[i] = 4096;
				SMASK[i] = 0x00000FFF;
				break;
			case 3:
				SSIZE[i] = 8192;
				SMASK[i] = 0x00001FFF;
				break;
			}
		}
		if( rsum < 8192)
		{
			switch((rbufsize>> i*2) & 0x03)  // Set maximum Rx memory size
			{
			case 0:
				RSIZE[i] = 1024;
				RMASK[i] = 0x000003FF;
				break;
			case 1:
				RSIZE[i] = 2048;
				RMASK[i] = 0x000007FF;
				break;
			case 2:
				RSIZE[i] = 4096;
				RMASK[i] = 0x00000FFF;
				break;
			case 3:
				RSIZE[i] = 8192;
				RMASK[i] = 0x00001FFF;
				break;
			}
		}
		ssum += SSIZE[i];
		rsum += RSIZE[i];

		if(i != 0)                               // Set 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];
		}
	}
	I_STATUS[0] = 0;
	WT_RegWrite(COMMAND(0), CSYS_INIT); 
   #ifdef _DONT_USE_INTERRUPT_
	do{
		_netISR(); // I_STATUS[] 값을 갱신 		
	}while(!(I_STATUS[0] & SSYS_INIT_OK));
   #else
	while(!(I_STATUS[0] & SSYS_INIT_OK));
   #endif
}



//-------------------------------------------------------------------------------------------------------
//               Subnet mask setup function
//
// Description : Subnet mask setup function
// Arguments   : addr - pointer having the value for setting up the Subnet Mask
// Returns     : None
// Note        : API Function
//-------------------------------------------------------------------------------------------------------
void setsubmask(u_char * addr)
{
	u_char i;

	for (i = 0; i < 4; i++){
		WT_RegWrite(SUBNET_MASK_PTR + i, addr[i]);
	}
}


//-------------------------------------------------------------------------------------------------------
//               gateway IP setup function
//
// Description : gateway IP setup function
// Arguments   : addr - pointer having the value for setting up the gateway IP
// Returns     : None
// Note        : API Function
//-------------------------------------------------------------------------------------------------------
void setgateway(u_char * addr)
{
	u_char i;

	for (i = 0; i < 4; i++){
		WT_RegWrite(GATEWAY_PTR + i, addr[i]);
	}
}


//-------------------------------------------------------------------------------------------------------
//               W3100A IP Address setup function
//
// Description : W3100A IP Address setup function
// Arguments   : addr - pointer having the value for setting up the source IP Address
// Returns     : None
// Note        : API Function
//-------------------------------------------------------------------------------------------------------
void setIP(u_char * addr)
{
	u_char i;

	for (i = 0; i < 4; i++) {
		WT_RegWrite(SRC_IP_PTR + i, addr[i]);
	}
}


//-------------------------------------------------------------------------------------------------------
//               MAC Address setup function
//
// Description : MAC Address setup function
// Arguments   : addr - pointer having the value for setting up the MAC Address
// Returns     : None
// Note        : API Function
//-------------------------------------------------------------------------------------------------------
void setMACAddr(u_char * addr)
{
	u_char i;

	for (i = 0; i < 6; i++) {
		WT_RegWrite(SRC_HA_PTR + i, addr[i]);
	}
}


#ifdef __IP_RAW__

//-------------------------------------------------------------------------------------------------------
//               Upper layer protocol setup function in IP RAW Mode
//
// Description : Upper layer protocol setup function in protocol field of IP header when
//                    developing upper layer protocol like ICMP, IGMP, EGP etc. by using IP Protocol
// Arguments   : s          - Channel number
//               ipprotocol - Upper layer protocol setting value of IP Protocol
//                            (Possible to use designated IPPROTO_ in header file)
// Returns     : None
// Note        : API Function
//                  This function should be called before calling socket() that is, before socket initialization.
//-------------------------------------------------------------------------------------------------------
void setIPprotocol(SOCKET s, u_char ipprotocol)
{
	WT_RegWrite(IP_PROTOCOL(s), ipprotocol);
}
#endif


#ifdef	__OPT__


//-------------------------------------------------------------------------------------------------------
//               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(u_char * val)
{
	u_char i;

	for (i = 0; i < 3; i++) {
		WT_RegWrite(TIMEOUT_PTR + i, val[i]);
	}
}

void gettimeout(u_char * val)
{
	u_char i;

	for (i = 0; i < 3; i++) {
		val[i] = WT_RegRead(TIMEOUT_PTR + i);
	}
}


//-------------------------------------------------------------------------------------------------------
//               interrupt mask setup function
//
// Description : Interrupt mask setup function. Enable/Disable appropriate Interrupt.
// Arguments   : mask - mask value to setup ('1' : interrupt enable)
// Returns     : None
// Note        : API Function
//-------------------------------------------------------------------------------------------------------
void setINTMask(u_char mask)
{
	WT_RegWrite(INTMASK, mask);
}


//-------------------------------------------------------------------------------------------------------
//               TOS value setup function for TOS field of IP header
//
// Description : TOS value setup function for TOS field of IP header
// Arguments   : s   - channel number
//    tos - Valuse to setup for TOS field of IP Header
// Returns     : None
// Note        : API Function
//-------------------------------------------------------------------------------------------------------
void setTOS(SOCKET s, u_char tos)
{
	WT_RegWrite(TOS(s), tos);
}
#endif // __OPT__




//-------------------------------------------------------------------------------------------------------
//               Initialization function to appropriate channel
//
// Description : Initialize designated channel and wait until W3100 has done.
// Arguments   : s - channel number
//               protocol - designate protocol for channel
//                          SOCK_STREAM(0x01) -> TCP.
//                          SOCK_DGRAM(0x02)  -> UDP.
//                          SOCK_IPL_RAW(0x03) -> IP LAYER RAW.
//                          SOCK_MACL_RAW(0x04) -> MAC LAYER RAW.
//               port     - designate source port for appropriate channel
//               flag     - designate option to be used in appropriate.
//                          SOCKOPT_BROADCAST(0x80) -> Send/receive broadcast message in UDP
//							SOCKOPT_NDTIMEOUT(0x40) -> Use register value which designated TIMEOUT value
//                          SOCKOPT_NDACK(0x20)     -> When not using no delayed ack
//                          SOCKOPT_SWS(0x10)       -> When not using silly window syndrome
// Returns     : When succeeded : Channel number, failed :1
// Note        : API Function
//-------------------------------------------------------------------------------------------------------
char socket(SOCKET s, u_char protocol, t_ui32 port, u_char flag)
{
	u_char k;
	t_ui32 start_t;

	g_adwPrvUdpDestIp[s] = 0;
	g_anPrvUdpDestPort[s] = -1;
	g_bWizSockInited[s] = false;

	WT_RegWrite(OPT_PROTOCOL(s), protocol | flag); // Designate socket protocol and option

	if (port != 0){ // setup designated port number
		k = (u_char)((port & 0xff00) >> 8);
		WT_RegWrite(SRC_PORT_PTR(s), k);
		k = (u_char)(port & 0x00ff);
		WT_RegWrite(SRC_PORT_PTR(s)+1, k);
	} 
	else{ // Designate random port number which is managed by local when you didn't designate source port
		Local_Port++;
		WT_RegWrite(SRC_PORT_PTR(s), (u_char)((Local_Port & 0xff00) >> 8));
		WT_RegWrite(SRC_PORT_PTR(s)+1, (u_char)(Local_Port & 0x00ff));
	}

	I_STATUS[s] = 0;
	WT_RegWrite(COMMAND(s), CSOCK_INIT);                          // SOCK_INIT
	Delay_us(10);

   #ifdef _DONT_USE_INTERRUPT_
	start_t = mkcTimerTick();
	do{
		_netISR(); // I_STATUS[] 값을 갱신 		
		if(mkcTimerTick() - start_t > 20){ 
			break;
		}
	}while (I_STATUS[s] == 0);                         // Waiting Interrupt to CSOCK_INIT
   #else
	while (I_STATUS[s] == 0);                         // Waiting Interrupt to CSOCK_INIT
   #endif
	Delay_us(2);

	if (protocol == SOCK_STREAM)		// if TCP
		initseqnum(s);					// Uses initial seq# with random number
	else if(protocol == SOCK_DGRAM){
		initseqnum(s);					// Uses initial seq# with random number
		g_adwPrvUdpDestIp[s] = 0;
		g_anPrvUdpDestPort[s] = -1;
	}

	if (!(I_STATUS[s] & SSOCK_INIT_OK)) return (-1);  // Error

	g_bWizSockInited[s] = true;

	Delay_ms(1);

	return	(s);
}


t_bool CheckSockInit(t_ui16 s)
{
	if(!g_bWizSockInited[s]){
		t_i16 nSockStat;
		nSockStat = _WT_RegRead(SOCK_STATUS(s)) & 0xff;
		if(nSockStat == SOCK_INIT || nSockStat == SOCK_UDP){ // [2008/04/01] 추가
			g_bWizSockInited[s] = true;
		}else if(_WT_RegRead(INT_STATUS(s)) & SSOCK_INIT_OK){
			g_bWizSockInited[s] = true;
		}
	}

	return (g_bWizSockInited[s]);
}

#ifdef	__TCP_CLIENT__

//-------------------------------------------------------------------------------------------------------
//               Connection establishing function to designated peer.
//
// Description : This function establish a connection to the peer by designated channel,
//     and wait until the connection is established successfully. (TCP client mode)
// Arguments   : s    - channel number
//               addr - destination IP Address
//               port - destination Port Number
// Returns     : when succeeded : 1, failed : -1
// Note        : API Function
//-------------------------------------------------------------------------------------------------------
char connect(SOCKET s, u_char * addr, t_ui32 port)
{
	if(!CheckSockInit(s))
		return -1;

	if (port != 0) 
	{                                                           // designate destination port
		WT_RegWrite(DST_PORT_PTR(s), (u_char)((port & 0xff00) >> 8));
		WT_RegWrite(DST_PORT_PTR(s)+1, (u_char)(port & 0x00ff));
	}
	else    return (-1);

	WT_RegWrite(DST_IP_PTR(s), addr[0]); // designate destination IP address
	WT_RegWrite((DST_IP_PTR(s) + 1), addr[1]);
	WT_RegWrite((DST_IP_PTR(s) + 2), addr[2]);
	WT_RegWrite((DST_IP_PTR(s) + 3), addr[3]);

	I_STATUS[s] = 0;
	WT_RegWrite(COMMAND(s), CCONNECT); // CONNECT
   
    return	(1);
}

BOOL is_connected(SOCKET s)
{
   #ifdef _DONT_USE_INTERRUPT_
	_netISR(); // I_STATUS[] 값을 갱신 		
   #endif	
	if (select(s, SEL_CONTROL) == SOCK_CLOSED) return false;   // When failed, appropriate channel will be closed and return an error
	else if (!(I_STATUS[s] & SESTABLISHED)) return (-1);             // Error
}

#endif



#ifdef	__TCP_SERVER__


//-------------------------------------------------------------------------------------------------------
//              Waits for connection request from a peer (Non-blocking Mode)
//
// Description : Wait for connection request from a peer through designated channel (TCP Server mode)
// Arguments   : s - channel number
// Returns     : None
// Note        : API Function
//-------------------------------------------------------------------------------------------------------
void NBlisten(SOCKET s)
{
	I_STATUS[s] = 0;
	WT_RegWrite(COMMAND(s), CLISTEN); // LISTEN
}

#endif


//-------------------------------------------------------------------------------------------------------
//               Create random value for initial Seq# when establishing TCP connection
//
// Description : In this function, you can add some source codes to create random number for initial Seq#
//     In real, TCP initial SEQ# should be random value. 
//               (Currently, we're using static value in EVB/DK.)
// Arguments   : s - channel number
// Returns     : None
// Note        : API Function
//-------------------------------------------------------------------------------------------------------

void initseqnum(SOCKET s)
{
	t_i32 i;

	i = s;

	SEQ_NUM.lVal++;     // Designate initial seq#
                        // If you have random number generation function, assign random number instead of SEQ_NUM.lVal++.

	WT_RegWrite(TX_WR_PTR(s), SEQ_NUM.cVal.B0);
	WT_RegWrite(TX_WR_PTR(s)+1, SEQ_NUM.cVal.B1);
	WT_RegWrite(TX_WR_PTR(s)+2, SEQ_NUM.cVal.B2);
	WT_RegWrite(TX_WR_PTR(s)+3, SEQ_NUM.cVal.B3);
	wait_1us(3);	    // Wait until TX_WR_PRT has been written safely. ( Must have delay(1.6us) if next action is to write 4byte-pointer register )

	WT_RegWrite(TX_RD_PTR(s), SEQ_NUM.cVal.B0);
	WT_RegWrite(TX_RD_PTR(s)+1, SEQ_NUM.cVal.B1);
	WT_RegWrite(TX_RD_PTR(s)+2, SEQ_NUM.cVal.B2);
	WT_RegWrite(TX_RD_PTR(s)+3, SEQ_NUM.cVal.B3);
	wait_1us(3);	    // Wait until TX_RD_PRT has been written safely.

	WT_RegWrite(TX_ACK_PTR(s), SEQ_NUM.cVal.B0);
	WT_RegWrite(TX_ACK_PTR(s)+1, SEQ_NUM.cVal.B1);
	WT_RegWrite(TX_ACK_PTR(s)+2, SEQ_NUM.cVal.B2);
	WT_RegWrite(TX_ACK_PTR(s)+3, SEQ_NUM.cVal.B3);
}


#ifdef	__TCP__

//-------------------------------------------------------------------------------------------------------
//               Function for sending TCP data.
//
// Description : Function for sending TCP data and Composed of the send() and send_in() functions.
//     The send() function is an application I/F function.
//     It continues to call the send_in() function to complete the sending of the data up to the size of the data to be sent
//     when the application is called.
//     The send_in() function receives the return value (the size of the data sent), calculates the size of the data to be sent,
//     and calls the send_in() function again if there is any data left to be sent.
// Arguments   : s   - channel number
//               buf - Pointer pointing data to send
//               len - data size to send
// Returns     : Succeed: sent data size, Failed:  -1;
// Note        : API Function
//-------------------------------------------------------------------------------------------------------
t_i32 send(SOCKET s, const void* buf, t_ui32 len, BOOL bPack)
{
	t_i32 ptr, size;

	if(!CheckSockInit(s))
		return -1;

	if (len <= 0) return (0);
	else 
	{
		ptr = 0;
		do {
			if(bPack) size = send_in(s, (t_ui32*)buf + (ptr/4), len, bPack);
			else size = send_in(s, (t_char*)buf + ptr, len, bPack);
			if (size == -1) return -1;	// Error
			len = len - size;
			ptr += size;
		} while ( len > 0);
	}

	return ptr;
}

//-------------------------------------------------------------------------------------------------------
//               Internal function for sending TCP data.
//
// Description : Called by the send() function for TCP transmission.
//    It first calculates the free transmit buffer size
//    and compares it with the size of the data to be transmitted to determine the transmission size.
//    After calculating the data size, it copies data from TX_WR_PTR.
//    It waits if there is a previous send command in process.
//    When the send command is cleared, it updates the TX_WR_PTR up to the size to be transmitted and performs the send command.
// Arguments   : s   - channel number
//               buf - Pointer pointing data to send
//               len - data size to send
// Returns     : Succeeded: sent data size, Failed: -1
// Note        : Internal Function
//-------------------------------------------------------------------------------------------------------
t_i32 send_in(SOCKET s, const void* buf, t_ui32 len, BOOL bPack)
{
	u_char k;
	t_i32 size;
	un_l2cval wr_ptr, ack_ptr;
	t_i32 send_ptr;
	t_ui32 start_t;

S_START:
	INTLAN_DIS(); // Disable interrupt

	k = _WT_RegRead(SHADOW_TXWR_PTR(s));	// Must read the shadow register for reading 4byte pointer registers
	wait_1us(3);                    // wait for reading 4byte pointer registers safely
	wr_ptr.cVal.B0 = _WT_RegRead(TX_WR_PTR(s));
	wr_ptr.cVal.B1 = _WT_RegRead(TX_WR_PTR(s) + 1);
	wr_ptr.cVal.B2 = _WT_RegRead(TX_WR_PTR(s) + 2);
	wr_ptr.cVal.B3 = _WT_RegRead(TX_WR_PTR(s) + 3);

	k = _WT_RegRead(SHADOW_TXACK_PTR(s));       // Must read the shadow register for reading 4byte pointer registers
	wait_1us(3);                    // wait for reading 4byte pointer registers safely
	ack_ptr.cVal.B0 = _WT_RegRead(TX_ACK_PTR(s));
	ack_ptr.cVal.B1 = _WT_RegRead(TX_ACK_PTR(s) + 1);
	ack_ptr.cVal.B2 = _WT_RegRead(TX_ACK_PTR(s) + 2);
	ack_ptr.cVal.B3 = _WT_RegRead(TX_ACK_PTR(s) + 3);
	
	INTLAN_EN(); // Enable interrupt

	// Calculate send free buffer size
	if (wr_ptr.lVal >= ack_ptr.lVal) size = SSIZE[s] - (wr_ptr.lVal - ack_ptr.lVal);
	else size = SSIZE[s] - ((t_ui32)((t_ui32)0xffffffff - ack_ptr.lVal + 1) + wr_ptr.lVal);
	
	if (size > SSIZE[s]){ // Recalulate after some delay because of error in pointer caluation
		if (select(s, SEL_CONTROL) != SOCK_ESTABLISHED) return -1;              // Error
		wait_1ms(1);
		goto S_START;
	}

	if (size == 0){ // Wait when previous sending has not finished yet and there's no free buffer
		if (select(s, SEL_CONTROL) != SOCK_ESTABLISHED) return -1; // Error
		wait_1ms(1);
		goto S_START;
	}
	else if (size < len)	len = size;

	send_ptr = SBUFBASEADDRESS[s] + (UINT)(wr_ptr.lVal & SMASK[s]);    // Calculate pointer to data copy
	if(bPack) write_data_32(s, (const t_i32*)buf, send_ptr, len);                                              // data copy
	else write_data_8(s, buf, send_ptr, len);

	//////////////////////////////////////////////////////////////////////////////////
	// [2008/03/25]: 아래의 이전 명령완료 체크하는 구문을 CSEND 명령을 내린 이후에
	// 넣으면 CEIP SDK를 사용했을 때 종종 통신이 끊기고, PING도 가끔 않되는 문제가
	// 발생한다.
#if 1
	start_t = mkcTimerTick();
	while (WT_RegRead(COMMAND(s)) & CSEND){                                         // Confirm prev. send command complete
		if (select(s, SEL_CONTROL) != SOCK_ESTABLISHED) return -1;                  // Error
		if(mkcTimerTick() - start_t > 3000) return -1; // timeout
	}
#endif

	wr_ptr.lVal = wr_ptr.lVal + len;                                                // tx_wr_ptr update
	INTLAN_DIS(); // Disable interrupt
	WT_RegWrite(TX_WR_PTR(s), wr_ptr.cVal.B0);
	WT_RegWrite((TX_WR_PTR(s) + 1), wr_ptr.cVal.B1);
	WT_RegWrite((TX_WR_PTR(s) + 2), wr_ptr.cVal.B2);
	WT_RegWrite((TX_WR_PTR(s) + 3), wr_ptr.cVal.B3);
	INTLAN_EN(); // Enable interrupt

	I_STATUS[s] = 0;
	WT_RegWrite(COMMAND(s), CSEND); // SEND
	wait_1us(30); 

#if 1
	start_t = mkcTimerTick();
	while (WT_RegRead(COMMAND(s)) & CSEND){							// Confirm previous send command
		if(mkcTimerTick() - start_t > 3000){
			Delay_us(2);
			return -1; // timeout
		}
	}
#endif

    return	(len);
}


//-------------------------------------------------------------------------------------------------------
//               TCP data receiving function.
//
// Description : This function is for receiving TCP data.
//     The recv() function is an application I/F function. It continues to wait for as much data as the application wants to receive.
// Arguments   : s   - channel number
//               buf - Pointer where the data to be received is copied
//               len - Size of the data to be received
// Returns     : Succeeded: received data size, Failed: -1
// Note        : API Fcuntion
//-------------------------------------------------------------------------------------------------------

t_i32 recv(SOCKET s, void* buf, t_ui32 len, BOOL bPack)
{
	u_char k;
	t_i32 size;
	un_l2cval wr_ptr, rd_ptr;
	t_i32 recv_ptr;

	if(!CheckSockInit(s))
		return -1;

R_START:
	INTLAN_DIS(); // Disable interrupt
	k = _WT_RegRead(SHADOW_RXWR_PTR(s));	// Must read the shadow register for reading 4byte pointer registers
	wait_1us(3);                    // wait for reading 4byte pointer registers safely
	wr_ptr.cVal.B0 = _WT_RegRead(RX_WR_PTR(s));
	wr_ptr.cVal.B1 = _WT_RegRead(RX_WR_PTR(s) + 1);
	wr_ptr.cVal.B2 = _WT_RegRead(RX_WR_PTR(s) + 2);
	wr_ptr.cVal.B3 = _WT_RegRead(RX_WR_PTR(s) + 3);
	
	k = _WT_RegRead(SHADOW_RXRD_PTR(s));        // Must read the shadow register for reading 4byte pointer registers
	wait_1us(3);                    // wait for reading 4byte pointer registers safely
	rd_ptr.cVal.B0 = _WT_RegRead(RX_RD_PTR(s));
	rd_ptr.cVal.B1 = _WT_RegRead(RX_RD_PTR(s) + 1);
	rd_ptr.cVal.B2 = _WT_RegRead(RX_RD_PTR(s) + 2);
	rd_ptr.cVal.B3 = _WT_RegRead(RX_RD_PTR(s) + 3);
	
	INTLAN_EN(); // Enable interrupt

	// calculate received data size //
	if ( len <= 0 ) return (0);
	else if (wr_ptr.lVal >= rd_ptr.lVal) size = wr_ptr.lVal - rd_ptr.lVal;
	else size = ((t_ui32)((t_ui32)0xffffffff - rd_ptr.lVal + 1) + wr_ptr.lVal);
	
	if (size < len)                                                                 // Wait until receiving is done when received data size is less then len
	{
		if (select(s, SEL_CONTROL) != SOCK_ESTABLISHED) return -1;              // Error
		wait_1ms(1);  
		goto R_START;
	}

	recv_ptr = RBUFBASEADDRESS[s] + (UINT)(rd_ptr.lVal & RMASK[s]);    // Calculate pointer to be copied received data

	if(bPack) read_data_32(s, recv_ptr, (t_i32*)buf, len);                                               // Copy receibed data
	else read_data_8(s, recv_ptr, (u_char*)buf, len);                                               // Copy receibed data

	rd_ptr.lVal += len;                                                             // Update rx_rd_ptr
	WT_RegWrite(RX_RD_PTR(s), rd_ptr.cVal.B0);
	WT_RegWrite(RX_RD_PTR(s) + 1, rd_ptr.cVal.B1);
	WT_RegWrite(RX_RD_PTR(s) + 2, rd_ptr.cVal.B2);
	WT_RegWrite(RX_RD_PTR(s) + 3, rd_ptr.cVal.B3);

	WT_RegWrite(COMMAND(s), CRECV); // RECV

    return	(len);
}
#endif	// __TCP__


#ifdef	__UDP__

//-------------------------------------------------------------------------------------------------------
//               UDP data sending function.
//
// Description : Composed of the sendto()and sendto_in() functions.
//    The send() function is an application I/F function.
//    It continues to call the send_in() function to complete the sending of the data up to the size of the data to be sent
//    when the application is called.Unlike TCP transmission, it designates the destination address and the port.
// Arguments   : s    - channel port
//               buf  - Pointer pointing data to send
//               len  - data size to send
//               addr - destination IP address to send data
//               port - destination port number to send data
// Returns     : Sent data size
// Note        : API Function
//-------------------------------------------------------------------------------------------------------
t_i32 sendto(SOCKET s, const u_char* buf, t_ui32 len, u_char * addr, t_ui32 port)
{
	t_i32 ptr, size;
	t_ui32 start_t, dwCurIp;

	if(!CheckSockInit(s))
		return -1;
		
	dwCurIp = ((addr[0]&0xff) << 24) | ((addr[1]&0xff) << 16) | ((addr[2]&0xff) << 8) | (addr[3]&0xff);

	if((g_adwPrvUdpDestIp[s] != 0 && g_adwPrvUdpDestIp[s] != dwCurIp) || (g_anPrvUdpDestPort[s] != -1 && g_anPrvUdpDestPort[s] != port)){	// For UDP Multi-Destination
		g_adwPrvUdpDestIp[s] = dwCurIp;
		if(g_adwPrvUdpDestIp[s]){
			I_STATUS[s] = 0;
			WT_RegWrite(COMMAND(s), CSOCK_INIT);                          // SOCK_INIT
			Delay_us(10);
		   #ifdef _DONT_USE_INTERRUPT_
			do{
				_netISR(); // I_STATUS[] 값을 갱신 		
			}while (I_STATUS[s] == 0);                         // Waiting Interrupt to CSOCK_INIT
		   #else
			while (I_STATUS[s] == 0);                         // Waiting Interrupt to CSOCK_INIT
		   #endif
			Delay_us(2);
		}
	}

	if (port != 0)                                              // Designate destination port number
	{						
		WT_RegWrite(DST_PORT_PTR(s), (u_char)((port & 0xff00) >> 8));
		WT_RegWrite((DST_PORT_PTR(s) + 1), (u_char)(port & 0x00ff));
	}

	WT_RegWrite(DST_IP_PTR(s), addr[0]&0xff);                                   // Designate destination IP address
	WT_RegWrite((DST_IP_PTR(s) + 1), addr[1]&0xff);
	WT_RegWrite((DST_IP_PTR(s) + 2), addr[2]&0xff);
	WT_RegWrite((DST_IP_PTR(s) + 3), addr[3]&0xff);

	if (len <= 0) return (0);
	else 
	{
		ptr = 0;
		do{
			size = sendto_in(s, buf + ptr, len);
			if(size == -1) return -1;	// Error
			len = len - size;
			ptr += size;
		}while ( len > 0);
	}
	return ptr;
}

//-------------------------------------------------------------------------------------------------------
//               UDP data sending function.
//
// Description : An internal function that is the same as the send_in() function of the TCP.
// Arguments   : s   - Channel number
//               buf - Pointer indicating the data to send
//               len - data size to send
// Returns     : Sent data size
// Note        : Internal Function
//-------------------------------------------------------------------------------------------------------
t_i32 sendto_in(SOCKET s, const u_char* buf, t_ui32 len)
{
	u_char k;
	t_ui32 i, size;
	un_l2cval wr_ptr, rd_ptr;
	t_i32 send_ptr;
	t_ui32 start_t;

S2_START:
	// if(select(s,SEL_CONTROL)==SOCK_CLOSED) return -1;	// Error
	INTLAN_DIS(); // Disable interrupt
	k = _WT_RegRead(SHADOW_TXWR_PTR(s));	// Must read the shadow register for reading 4byte pointer registers
	wait_1us(3);
	wr_ptr.cVal.B0 = _WT_RegRead(TX_WR_PTR(s));
	wr_ptr.cVal.B1 = _WT_RegRead(TX_WR_PTR(s) + 1);
	wr_ptr.cVal.B2 = _WT_RegRead(TX_WR_PTR(s) + 2);
	wr_ptr.cVal.B3 = _WT_RegRead(TX_WR_PTR(s) + 3);

	k = _WT_RegRead(SHADOW_TXRD_PTR(s));
	wait_1us(3);
	rd_ptr.cVal.B0 = _WT_RegRead(TX_RD_PTR(s));
	rd_ptr.cVal.B1 = _WT_RegRead(TX_RD_PTR(s) + 1);
	rd_ptr.cVal.B2 = _WT_RegRead(TX_RD_PTR(s) + 2);
	rd_ptr.cVal.B3 = _WT_RegRead(TX_RD_PTR(s) + 3);
	INTLAN_EN(); // Enable interrupt

	// Calculate free buffer size to send
	if (wr_ptr.lVal >= rd_ptr.lVal) size = SSIZE[s] - (wr_ptr.lVal - rd_ptr.lVal);
	else size = SSIZE[s] - ((t_ui32)((t_ui32)0xffffffff - rd_ptr.lVal + 1) + wr_ptr.lVal);
	
	if (size > SSIZE[s]) // Recalculate after some delay because of error in pointer caluation
	{
		wait_1ms(10);
		goto S2_START;
	}

	if (size == 0) // Wait when previous sending has not finished yet and there's no free buffer
	{
		wait_1ms(1);
		goto S2_START;
	} 
	else if (size < len)	len = size;

	send_ptr = SBUFBASEADDRESS[s] + (UINT)(wr_ptr.lVal & SMASK[s]);     // Calculate pointer to copy data pointer
	write_data_8(s, buf, send_ptr, len); // Copy data

#if 1
	//////////////////////////////////////////////////////////////////////////////////
	// [2008/03/25]: 아래의 이전 명령완료 체크하는 구문을 CSEND 명령을 내린 이후에
	// 넣으면 CEIP SDK를 사용했을 때 종종 통신이 끊기고, PING도 가끔 않되는 문제가
	// 발생한다.
	start_t = mkcTimerTick();
	while (WT_RegRead(COMMAND(s)) & CSEND){							// Confirm previous send command
		if(mkcTimerTick() - start_t > 3000){
			Delay_us(2);
			return -1; // timeout
		}
	}
#endif

	wr_ptr.lVal = wr_ptr.lVal + len; // Update tx_wr_ptr
	INTLAN_DIS(); // Disable interrupt
	WT_RegWrite(TX_WR_PTR(s), wr_ptr.cVal.B0);
	WT_RegWrite((TX_WR_PTR(s) + 1), wr_ptr.cVal.B1);
	WT_RegWrite((TX_WR_PTR(s) + 2), wr_ptr.cVal.B2);
	WT_RegWrite((TX_WR_PTR(s) + 3), wr_ptr.cVal.B3);
	INTLAN_EN(); // Enable interrupt
	
	WT_RegWrite(COMMAND(s), CSEND); // SEND
	wait_1us(30); 

#if 1
	start_t = mkcTimerTick();
	while (WT_RegRead(COMMAND(s)) & CSEND){							// Confirm previous send command
		if(mkcTimerTick() - start_t > 3000){
			Delay_us(2);
			return -1; // timeout
		}
	}
#endif
    return	(len);
}

//-------------------------------------------------------------------------------------------------------
//               UDP or IP data receiving function.
//
// Description : Function for receiving UDP and IP layer RAW mode data, and handling the data header.
// Arguments   : s    - channel number
//               buf  - Pointer where the data to be received is copied
//               len  - any number greater than zero.
//               addr - Peer IP address for receiving
//               port - Peer port number for receiving
// Returns     : Data size of received packet 
// Note        : API Function
//-------------------------------------------------------------------------------------------------------

t_i32 recvfrom(SOCKET s, u_char* buf, t_ui32 len, u_char * addr, t_ui32 * port, t_i32 bPack)
{
	struct _UDPHeader{  // When receiving UDP data, header added by W3100A
		union{
			struct { 
				t_i32 size1:	8;
				t_i32 size0:	8;
				t_i32 addr0:	8;
				t_i32 addr1:	8;
				t_i32 addr2:	8;
				t_i32 addr3:	8;
				t_i32 port1:	8;
				t_i32 port0:	8;
			}header;
			t_i32 stream[2];
		}u;
	}UDPHeader;

	t_i32 ret;
	t_i32 recv_ptr;
	un_l2cval wr_ptr, rd_ptr;
	t_ui32 size;
	u_char k;

	if(!CheckSockInit(s))
		return -1;

	if(select(s,SEL_CONTROL)==SOCK_CLOSED) return -1;
	INTLAN_DIS(); // Disable interrupt
	k = _WT_RegRead(SHADOW_RXWR_PTR(s));
	wait_1us(3);
	wr_ptr.cVal.B0 = _WT_RegRead(RX_WR_PTR(s));
	wr_ptr.cVal.B1 = _WT_RegRead(RX_WR_PTR(s) + 1);
	wr_ptr.cVal.B2 = _WT_RegRead(RX_WR_PTR(s) + 2);
	wr_ptr.cVal.B3 = _WT_RegRead(RX_WR_PTR(s) + 3);

	k = _WT_RegRead(SHADOW_RXRD_PTR(s));
	wait_1us(3);
	rd_ptr.cVal.B0 = _WT_RegRead(RX_RD_PTR(s));
	rd_ptr.cVal.B1 = _WT_RegRead(RX_RD_PTR(s) + 1);
	rd_ptr.cVal.B2 = _WT_RegRead(RX_RD_PTR(s) + 2);
	rd_ptr.cVal.B3 = _WT_RegRead(RX_RD_PTR(s) + 3);
	
	INTLAN_EN(); // Enable interrupt

	// Calculate received data size
	if(len <=0) return 0;
	else if (wr_ptr.lVal >= rd_ptr.lVal) size = wr_ptr.lVal - rd_ptr.lVal;
	else size = ((t_ui32)((t_ui32)0xffffffff - rd_ptr.lVal + 1) + wr_ptr.lVal);

	if(size == 0) return 0;
	
	recv_ptr = (RBUFBASEADDRESS[s] + (UINT)(rd_ptr.lVal & RMASK[s]));     // Calulate received data pointer

	if ((WT_RegRead(OPT_PROTOCOL(s)) & 0x07) == SOCK_DGRAM)                                     // Handle UDP data
	{
		read_data_32(s, recv_ptr, (t_i32*)UDPHeader.u.stream, 8);                             // W3100A UDP header copy
  		addr[0] = UDPHeader.u.header.addr0 & 0xff;                                   // Read IP address of the peer
		addr[1] = UDPHeader.u.header.addr1 & 0xff;
		addr[2] = UDPHeader.u.header.addr2 & 0xff;
		addr[3] = UDPHeader.u.header.addr3 & 0xff;                                   // Read Port number of the peer
		/* *port = UDPHeader.u.stream[6];
		*port = (*port << 8) + UDPHeader.u.stream[7];*/
		*port = UDPHeader.u.header.port1 & 0xff;
		*port = (*port)<<8;
		*port = *port | (UDPHeader.u.header.port0 & 0xff);

		size = UDPHeader.u.header.size1 & 0xff;
		size = size<<8;
		size = size | (UDPHeader.u.header.size0 & 0xff);
		size = size - 8;
		rd_ptr.lVal += 8;		
		recv_ptr = (RBUFBASEADDRESS[s] + (UINT)(rd_ptr.lVal & RMASK[s]));
		if(bPack) ret = read_data_32(s, recv_ptr, (t_i32*)buf, size);
		else ret = read_data_8(s, recv_ptr, buf, size);
		rd_ptr.lVal += ret;
	}
/*#ifdef __IP_RAW__	
	else if ((WT_RegRead(OPT_PROTOCOL(s)) & 0x07) == SOCK_IPL_RAW)                                  // When received IP layer RAW mode data
	{
//		for(i = 0; i < 4; i++) addr[i] = recv_ptr[2+i];                             // IP layer header copy
		read_data_8(s,recv_ptr,UDPHeader.u.stream,6);
		addr[0] = UDPHeader.u.header.addr0;
		addr[1] = UDPHeader.u.header.addr1;
		addr[2] = UDPHeader.u.header.addr2;
		addr[3] = UDPHeader.u.header.addr3;
		rd_ptr.lVal += 6;                                                           // Increment read pointer by 6, because already read as IP RAW header size
		recv_ptr = (u_char *)(RBUFBASEADDRESS[s] + (UINT)(rd_ptr.lVal & RMASK[s])); // Calculate IP layer raw mode data pointer
		if(bPack) ret = read_data_32(s, recv_ptr, (t_i32*)buf, size);
		else ret = read_data_8(s, recv_ptr, buf, UDPHeader.u.header.size);                                     // data copy.
		rd_ptr.lVal += (ret-4);
	} 
#endif	// end __IP_RAW__
*/
	WT_RegWrite(RX_RD_PTR(s), rd_ptr.cVal.B0); // Update rx_rd_ptr
	WT_RegWrite((RX_RD_PTR(s) + 1), rd_ptr.cVal.B1);
	WT_RegWrite((RX_RD_PTR(s) + 2), rd_ptr.cVal.B2);
	WT_RegWrite((RX_RD_PTR(s) + 3), rd_ptr.cVal.B3);

	WT_RegWrite(COMMAND(s), CRECV); // RECV
    return	(ret);	// Real received size return
}
#endif	// __UDP__

//-------------------------------------------------------------------------------------------------------
//               Channel closing function.
//
// Description : Function for closing the connection of the designated channel.
// Arguments   : s - channel number
// Returns     : None
// Note        : API Function	       
//-------------------------------------------------------------------------------------------------------
void close(SOCKET s)
{
	t_ui32 len;

	if(!CheckSockInit(s))
		return;

	if (select(s, SEL_CONTROL) == SOCK_CLOSED) return;	   // Already closed

	// When closing, if there's data which have not processed, Insert some source codes to handle this
	// Or before application call close(), handle those data first and call close() later.

	len = select(s, SEL_SEND);
	if (len == SSIZE[s])
	{
		I_STATUS[s] =0;
		WT_RegWrite(COMMAND(s), CCLOSE); // CLOSE
	   #ifdef _DONT_USE_INTERRUPT_
		do{
			WT_RegWrite(COMMAND(s), CCLOSE); // CLOSE
			_netISR(); // I_STATUS[] 값을 갱신 		
		}while(!(I_STATUS[s] & SCLOSED));
	   #else
		while(!(I_STATUS[s] & SCLOSED));
	   #endif
	}
}


//-------------------------------------------------------------------------------------------------------
//               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_ui32 select(SOCKET s, u_char func)
{
	t_ui32 val;
	un_l2cval rd_ptr, wr_ptr, ack_ptr;
	u_char k;

	if(!CheckSockInit(s))
		return -1;

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

	case SEL_SEND :                                        // Calculate send free buffer size
		INTLAN_DIS(); // Disable interrupt
		k = _WT_RegRead(SHADOW_TXWR_PTR(s));
		wait_1us(3);
		wr_ptr.cVal.B0 = _WT_RegRead(TX_WR_PTR(s));
		wr_ptr.cVal.B1 = _WT_RegRead(TX_WR_PTR(s) + 1);
		wr_ptr.cVal.B2 = _WT_RegRead(TX_WR_PTR(s) + 2);
		wr_ptr.cVal.B3 = _WT_RegRead(TX_WR_PTR(s) + 3);

		if( (_WT_RegRead(OPT_PROTOCOL(s))& 0x07) != SOCK_STREAM)
		{
			k = _WT_RegRead(SHADOW_TXRD_PTR(s));
			wait_1us(3);
			ack_ptr.cVal.B0 = _WT_RegRead(TX_RD_PTR(s));
			ack_ptr.cVal.B1 = _WT_RegRead(TX_RD_PTR(s) + 1);
			ack_ptr.cVal.B2 = _WT_RegRead(TX_RD_PTR(s) + 2);
			ack_ptr.cVal.B3 = _WT_RegRead(TX_RD_PTR(s) + 3);
		}
		else
		{
			k = _WT_RegRead(SHADOW_TXACK_PTR(s));
			wait_1us(3);
			ack_ptr.cVal.B0 = _WT_RegRead(TX_ACK_PTR(s));
			ack_ptr.cVal.B1 = _WT_RegRead(TX_ACK_PTR(s) + 1);
			ack_ptr.cVal.B2 = _WT_RegRead(TX_ACK_PTR(s) + 2);
			ack_ptr.cVal.B3 = _WT_RegRead(TX_ACK_PTR(s) + 3);
		}
		INTLAN_EN(); // Enable interrupt

		if (wr_ptr.lVal >= ack_ptr.lVal) val = SSIZE[s] - (wr_ptr.lVal - ack_ptr.lVal);
		else val = SSIZE[s] - ((t_ui32)((t_ui32)0xffffffff - ack_ptr.lVal + 1) + wr_ptr.lVal);
		break;
	case SEL_RECV :                                        // Calculate received data size	
		INTLAN_DIS(); // Disable interrupt
		k = _WT_RegRead(SHADOW_RXWR_PTR(s));
		wait_1us(3);
		wr_ptr.cVal.B0 = _WT_RegRead(RX_WR_PTR(s));
		wr_ptr.cVal.B1 = _WT_RegRead(RX_WR_PTR(s) + 1);
		wr_ptr.cVal.B2 = _WT_RegRead(RX_WR_PTR(s) + 2);
		wr_ptr.cVal.B3 = _WT_RegRead(RX_WR_PTR(s) + 3);

		k = _WT_RegRead(SHADOW_RXRD_PTR(s));
		wait_1us(3);
		rd_ptr.cVal.B0 = _WT_RegRead(RX_RD_PTR(s));
		rd_ptr.cVal.B1 = _WT_RegRead(RX_RD_PTR(s) + 1);
		rd_ptr.cVal.B2 = _WT_RegRead(RX_RD_PTR(s) + 2);
		rd_ptr.cVal.B3 = _WT_RegRead(RX_RD_PTR(s) + 3);
		INTLAN_EN(); // Enable interrupt

		if (wr_ptr.lVal == rd_ptr.lVal){ val = 0;}
		else if (wr_ptr.lVal > rd_ptr.lVal) val = wr_ptr.lVal - rd_ptr.lVal;
		else val = ((t_ui32)((t_ui32)0xffffffff - rd_ptr.lVal + 1) + wr_ptr.lVal);
		break;
	default :
		val = -1;
		break;
	}

    return	( val );
}



//-------------------------------------------------------------------------------------------------------
//               Copies the receive buffer data of the W3100A to the system buffer.
//
// Description : Copies the receive buffer data of the W3100A to the system buffer.
//    It is called from the recv()or recvfrom() function.
// Arguments   : s   - channel number
//               src - receive buffer pointer of W3100A
//               dst - system buffer pointer
//               len - data size to copy
// Returns     : copied data size
// Note        : Internal Function
//-------------------------------------------------------------------------------------------------------
t_ui32 read_data_8(SOCKET s, t_i32 src_addr, u_char* dst, t_ui32 len)
{
	t_ui32 i, size, size1;

	if (len == 0) return 0;

	if( ((src_addr & RMASK[s]) + len)  > RSIZE[s] ) 
	{
		size = RSIZE[s] - (src_addr & RMASK[s]);
		for (i = 0; i < size; i++) *dst++ = WT_RegRead(src_addr++);
		size1 = len - size;
		src_addr =  RBUFBASEADDRESS[s];
		for (i = 0; i < size1; i++) *dst++ = WT_RegRead(src_addr++);
	}
	else
        for (i = 0; i < len; i++) *dst++ = WT_RegRead(src_addr++);
	return len;
}


//-------------------------------------------------------------------------------------------------------
//               Copies the receive buffer data of the W3100A to the system buffer.
//
// Description : Copies the receive buffer data of the W3100A to the system buffer.
//    It is called from the recv()or recvfrom() function.
// Arguments   : s   - channel number
//               src - receive buffer pointer of W3100A
//               dst - system buffer pointer
//               len - data size to copy
// Returns     : copied data size
// Note        : Internal Function
//-------------------------------------------------------------------------------------------------------
t_ui32 read_data_32(SOCKET s, t_i32 src_addr, t_i32* dst, t_ui32 len)
{
	t_ui32 i, size, size1;
	UCHAR byte_data;
	t_i32 cnt=0, idx, sidx;

	if (len == 0) return 0;

	if( ((src_addr & RMASK[s]) + len)  > RSIZE[s] ) 
	{
		size = RSIZE[s] - (src_addr & RMASK[s]);
		for (i = 0; i < size; i++){
			byte_data = WT_RegRead(src_addr++);
			idx = cnt/4;
			sidx = (cnt%4)*8; // 바이트 위치 계산 
			dst[idx] = (dst[idx] & (~(0xff<<sidx))) | (byte_data<<sidx);
			cnt++;
		}
		size1 = len - size;
		src_addr =  RBUFBASEADDRESS[s];
		for (i = 0; i < size1; i++){
			byte_data = WT_RegRead(src_addr++);
			idx = cnt/4;
			sidx = (cnt%4)*8; // 바이트 위치 계산 
			dst[idx] = (dst[idx] & (~(0xff<<sidx))) | (byte_data<<sidx);
			cnt++;
		}
	}
	else{
        for (i = 0; i < len; i++){
			byte_data = WT_RegRead(src_addr++);
			idx = cnt/4;
			sidx = (cnt%4)*8; // 바이트 위치 계산 
			dst[idx] = (dst[idx] & (~(0xff<<sidx))) | (byte_data<<sidx);
			cnt++;
		}
	}
	return len;
}


//-------------------------------------------------------------------------------------------------------
//               Copies the system buffer data to the transmit buffer of the W3100A.
//
// Description : Copies the system buffer data to the transmit buffer of the W3100A.
//               It is called from the send_in()or sendto_in() function.
// Arguments   : s   - channel number
//               src - system buffer pointer
//               dst - send buffer pointer of W3100A
//               len - data size to copy
// Returns     : copied data size
// Note        : Internal Function
//-------------------------------------------------------------------------------------------------------
t_ui32 write_data_8(SOCKET s, const u_char* src, t_i32 dst_addr, t_ui32 len)
{
	t_ui32 i, size, size1;

	if (len == 0) return 0;

	if ( (((t_ui32)dst_addr & SMASK[s]) + len) > SSIZE[s] ) 
	{
		size = SSIZE[s] - (dst_addr & SMASK[s]);

		for (i = 0; i < size; i++) WT_RegWrite(dst_addr++, *src++);
		size1 = len - size;
		dst_addr = (SBUFBASEADDRESS[s]);
		for (i = 0; i < size1; i++) WT_RegWrite(dst_addr++, *src++);
	} 
	else
		for (i = 0; i < len; i++) WT_RegWrite(dst_addr++, *src++);

	return len;
}

//-------------------------------------------------------------------------------------------------------
//
//-------------------------------------------------------------------------------------------------------
t_ui32 write_data_32(SOCKET s, const t_i32* src_32, t_i32 dst_addr, t_ui32 len_8)
{
	t_ui32 i, size, size1;
	UCHAR byte_data;
	t_i32 cnt=0, idx, sidx;

	if (len_8 == 0) return 0;

	if ( (((t_ui32)dst_addr & SMASK[s]) + len_8) > SSIZE[s] ) 
	{
		size = SSIZE[s] - (dst_addr & SMASK[s]);

		for (i = 0; i < size; i++){ 
			idx = cnt/4;
			sidx = (cnt%4)*8; // 바이트 위치 계산 
			byte_data = (src_32[idx]>>sidx) & 0xff;
			WT_RegWrite(dst_addr++, byte_data);
			cnt++;
		}
		size1 = len_8 - size;
		dst_addr = (SBUFBASEADDRESS[s]);
		for (i = 0; i < size1; i++){
			idx = cnt/4;
			sidx = (cnt%4)*8; // 바이트 위치 계산 
			byte_data = (src_32[idx]>>sidx) & 0xff;
			WT_RegWrite(dst_addr++, byte_data);
			cnt++;
		}
	} 
	else{
		for (i = 0; i < len_8; i++){
			idx = cnt/4;
			sidx = (cnt%4)*8; // 바이트 위치 계산 
			byte_data = (src_32[idx]>>sidx) & 0xff;
			WT_RegWrite(dst_addr++, byte_data);
			cnt++;
		}
	}

	return len_8;
}

//-------------------------------------------------------------------------------------------------------
// _netISR(): Ethernet comm. interrupt service routine. this function must be called in the proper real 
// ISR.
//-------------------------------------------------------------------------------------------------------
void _netISR(void)
{
	t_uchar status;
	status = _WT_RegRead(INT_REG);
    if(status == 0x00)
    	_WT_RegWrite(INT_REG, 0xFF);
    	
	while (status) {
		if (status & 0x01) {      // channel 0 interrupt(sysinit, sockinit, established, closed, timeout, send_ok, recv_ok)
			I_STATUS[0] = _WT_RegRead(INT_STATUS(0));
			_WT_RegWrite(INT_REG, 0x01); // Interrupt clear
		}

		if (status & 0x02) {      // channel 1 interrupt(sysinit, sockinit, established, closed, timeout, send_ok, recv_ok)
			I_STATUS[1] = _WT_RegRead(INT_STATUS(1));
			_WT_RegWrite(INT_REG, 0x02); // Interrupt clear
		}

		if (status & 0x04) {      // channel 2 interrupt(sysinit, sockinit, established, closed, timeout, send_ok, recv_ok)
			I_STATUS[2] = _WT_RegRead(INT_STATUS(2));
			_WT_RegWrite(INT_REG, 0x04); // Interrupt clear
		}

		if (status & 0x08) {      // channel 3 interrupt(sysinit, sockinit, established, closed, timeout, send_ok, recv_ok)
			I_STATUS[3] = _WT_RegRead(INT_STATUS(3));
			_WT_RegWrite(INT_REG, 0x08); // Interrupt clear
		}

		if (status & 0x10) {      // channel 0 receive interrupt
			_WT_RegWrite(INT_REG, 0x10); // Clear interrupt
		}

		if (status & 0x20) {      // channel 1 receive interrupt
			_WT_RegWrite(INT_REG, 0x20);
		}

		if (status & 0x40) {      // channel 2 receive interrupt
			_WT_RegWrite(INT_REG, 0x40);
		}

		if (status & 0x80) {      // channel 3 receive interrupt
			_WT_RegWrite(INT_REG, 0x80);
		}

		status = _WT_RegRead(INT_REG);
	}
}


#endif // #ifdef _ETHERNET_H_
