W5500-EVB를 이용해 Chat Client를 구현하는 과정을 포스팅 하려고 한다.

W5500-EVB는 NXP社의 Coretex M0 MCU인 LPC11E36FHN33이 Main MCU로 포함되어 있고 W5500을 제어할수 있게 제작되었다.

W5500-EVB의 자세한 내용은 아래 URL을 참고해보길 바란다.

http://wizwiki.net/wiki/doku.php?id=products:w5500:w5500_evb


Chat Client 란?

간단하게 말하면 TCP Client로 구동되며, TCP Server로 접속해서, TCP로 수신된 데이터를 Serial로 송신하고, Serial로 수신된 데이터를 TCP로 송신을 하는 것이다. 간단하게 아래 사진으로 표현을 할수 있다.


W5500-EVB를 사용해서 구현을 해야 하기 때문에 W5500-EVB의 사용법에 대해 학습했다. 아래 URL을 참고해서 학습했다.

개발환경 구축하기

http://jindabang.net/2015/01/01/1-w5500%EC%9C%BC%EB%A1%9C-%EC%9E%84%EB%B2%A0%EB%94%94%EB%93%9C-%EC%9D%B4%EB%8D%94%EB%84%B7-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0%EA%B0%9C%EB%B0%9C-%ED%99%98%EA%B2%BD-%EA%B5%AC%EC%B6%95/

드라이버 포팅하기

http://jindabang.net/2015/01/02/2-w5500%EC%9C%BC%EB%A1%9C-%EC%9E%84%EB%B2%A0%EB%94%94%EB%93%9C-%EC%9D%B4%EB%8D%94%EB%84%B7-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0%EB%93%9C%EB%9D%BC%EC%9D%B4%EB%B2%84-%ED%8F%AC%ED%8C%85/

개발환경을 구축하고 W5500 드라이버를 포팅이 완료 되면 준비완료이다.


Chat Client 구현하기

W5500 드라이버를 사용하여 이더넷 통신을 하기 위해서는 “Socket Status Register”의 상태에 따라 동작을 정의 하는 방식으로 구현하게 된다. Socket Status Register 상태는 다음과 같이 정의 된다.

 SOCKET STATUS

 DESCRIPTION

 USE API

 SOCK_CLOSED

 Socket이 Close 된 상태

 socket

 SOCK_INIT

 Socket이 TCP Mode로 Open 된 상태

 connect / listen

 SOCK_LISTEN

 Socket이 TCP Server Mode로 Open 된 상태

 close

 SOCK_ESTABLISHED

 TCP 연결이 성립된 상태

 recv / send / close

 SOCK_CLOSE_WAIT

 Peer로부터 disconnect-request를 수신한 상태

 close

 SOCK_UDP

 Socket이 UDP Mode로 Open 된 상태

 recvfrom / sendto


아래 사진은 TCP를 사용할 때의 State Diagram이다.

141029_echo_server1

“Socket Status Register”의 상태에 따라 동작이 정의 되기 때문에 아래와 같은 골격을 참고해서 구현했다.

{
    ...
    switch(getSn_SR(sn)) {
    case SOCK_CLOSED:
        /* Socket Closed State */

        break;
    case SOCK_INIT:
        /* TCP Socket Creatation */

        break;
    case SOCK_LISTEN:
        /* TCP Server Mode */

        break;
    case SOCK_ESTABILSHED:
        /* TCP ESTABLISHED */

        break;
    case SOCK_CLOSE_WAIT:
        /* Disconnect request */

        break;
    }
    ...
}

구현한 코드는 아래와 같다. 아직 부족한 점이 많지만, 공부를 계속하면서 코드를 수정해가는 과정을 포스팅 하겠다.

#if defined (__USE_LPCOPEN)
#if defined(NO_BOARD_LIB)
#include "chip.h"
#else
#include "board.h"
#endif
#endif

#include 
#include "socket.h"
#include "spi_handler.h"
#include "w5500_init.h"

// TODO: insert other include files here

// TODO: insert other definitions and declarations here
#define SOCK_TCPS0       0
#define DATA_BUF_SIZE   2048
uint8_t gDATABUF[DATA_BUF_SIZE];

// Ethernet => Serial
int EtherToSerial(uint8_t* buf,uint16_t size)
{
	uint8_t i;
	for(i=0 ; i < size ; i++){
		putchar(buf[i]);
	}
	//Chip_UART_Send(LPC_USART, buf, size);
	return 0 ;
}
// Serial => Ethernet
int SerialToEther(uint8_t sn)
{
	uint8_t serial_rx_data;

	if((Chip_UART_ReadLineStatus(LPC_USART) & UART_LSR_RDR) == 1){
		Chip_UART_Read(LPC_USART, &serial_rx_data, 1);
	    send(sn, &serial_rx_data, 1);
	    //Chip_UART_SendBlocking(LPC_USART, &sr_rx_data, 1);
	}
	return 0 ;
}

int main(void) {

	uint8_t ip[4]={192,168,0,142};
	uint16_t port=23;
	uint8_t sn=SOCK_TCPS0;
	uint16_t size=0;

#if defined (__USE_LPCOPEN)
#if !defined(NO_BOARD_LIB)
	// Read clock settings and update SystemCoreClock variable
	SystemCoreClockUpdate();
	// Set up and initialize all required blocks and
	// functions related to the board hardware
	Board_Init();
	// Set the LED to the state of "On"
	Board_LED_Set(0, true);
#endif
#endif
	SPI_Init();
	W5500_Init();
	Net_Conf();

	//Socket Creation
	if(socket(sn, Sn_MR_TCP, port, 0x00)==sn){
		printf("%d:Socket Opened\r\n",sn);
	}
	else{
		printf("%d:Socket Error\r\n",sn);
		while(1);
	}

	printf("%d:Connecting, ip[%d.%d.%d.%d] port [%d]\r\n", sn, ip[0], ip[1], ip[2], ip[3], port);
	//Connent TCP Server
	if(connect(sn,ip,port)==SOCK_OK);
	else {
		printf("%d:Connect Error\r\n",sn);
		while(1);
	}

	while(1) {
		switch(getSn_SR(sn)) {
			case SOCK_CLOSED:
		        /* Socket Closed State */

		        break;
		    case SOCK_INIT:
		        /* TCP Socket Creatation */

		        break;
		    case SOCK_LISTEN:
		        /* TCP Server Mode */

		        break;
		    case SOCK_ESTABLISHED:
		        /* TCP ESTABLISHED */
		    	//Connect Interrupt Check
		    	if(getSn_IR(sn) & Sn_IR_CON) {
		    		printf("%d:Connected\r\n",sn);
		    		setSn_IR(sn,Sn_IR_CON);
		    	    Board_LED_Set(0, false);
		    	    Board_LED_Set(1, true);
		    	}
		    	//Receive Data Check
		    	if((size = getSn_RX_RSR(sn)) > 0) {
		    		if(size > DATA_BUF_SIZE) size = DATA_BUF_SIZE;
		    	    recv(sn,gDATABUF,size);
		    	    EtherToSerial(gDATABUF, size);
		    	}
		    	SerialToEther(sn);
		        break;

		    case SOCK_CLOSE_WAIT:
		        /* Disconnect request */

		        break;
		}
    }
    return 0 ;
}

코드를 자세히 보면 “Socket Status Register”의 상태에 따라 처리하는 것은 'SOCK_ESTABLISHED' 상태 일때 밖에 없는 것을 볼수 있다. 동작하는 순서를 익히기 위해 소켓생성하는 부분과 서버에 접속하는 부분은 밖으로 빼서 구현을 했다.

그리고 Serial 로 받은 데이터를 TCP로 전송하는 부분을 보완할 예정이다. (데이터를 모아 한꺼번에 보내는 기능)


+ Recent posts