본문 바로가기

Ethernet Chat Server/3.링버퍼 코드 추가

채팅 프로그램 링버퍼 코드 추가

안녕하세요.
Edward입니다.

저번 링버퍼 설명에 추가하여 링버퍼 구현 코드를 올리겠습니다.

코드는 아래와 같습니다.

[code language="c"]

/*
===============================================================================
 Name : W5500-EVB.c
 Author : $(author)
 Version :
 Copyright : $(copyright)
 Description : main definition
===============================================================================
*/

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

#include "cr_section_macros.h"
#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
#define SERIAL_BUF_SIZE 2048
uint8_t gDATABUF[DATA_BUF_SIZE];
uint8_t SERIAL_BUF[SERIAL_BUF_SIZE];
uint8_t SERIAL_SIZE = 0;

typedef struct {
	int head;
	int tail;
	char data[SERIAL_BUF_SIZE];
} t_rb;

t_rb ringbuffer = {0, 0, }; // used to t_rb struct to creation ringbuffer variable to head = 0; , tail = 0;
uint8_t AutoSend_flag=0; // global variable

int rb_put( t_rb *rb , char d ) // push -> read UART
{
	int nhead = (rb->head+1) % (SERIAL_BUF_SIZE+1); // adder tail
	if (rb->tail == nhead) {	// full
		return 0;
	}
	rb->data[rb->head] = d;
	rb->head = nhead;
	return 1; // return rb_put -> continue the function -> until the tail output
}

/*push -> serial data write , pop -> read the data to send*/
char rb_get( t_rb *rb, int *err ) // pop -> send Ethernet
{
	char d;
	int ntail = (rb->tail+1) % (SERIAL_BUF_SIZE+1);
	if (rb->tail == rb->head) {	// empty
		*err = 0;
		return 0;
	}
	d = rb->data[rb->tail];
	rb->tail = ntail;
	*err = 1;
	return d; // return d
}

int finder ( t_rb *rb, char ch )
{
	int i;
	int cnt;

	if(rb->head > rb->tail){
		for(i=rb->tail; i<rb->head; i++){
			if(rb->data[i] == ch){
				return i;
			}
		}
	}
	else{
		for(i=rb->tail; i < SERIAL_BUF_SIZE; i++){
			if(rb->data[i] == ch){
				return i;
			}
		}
		cnt = i;
		for(i=0; i < rb->tail; i++){
			if(rb->data[i] == ch){
				return (cnt +i);
			}
		}
	}
	return 0;
}

int EtherToSerial(uint8_t* buf,uint16_t size)
{
	uint8_t i;
	for(i=0 ; i < size ; i++){
		putchar(buf[i]);
	}
	return 0 ;
}

int SerialToEther(uint8_t sn)
{
	int len = finder(&ringbuffer, '\n');
	int err;
	int i;

	if(len > 0)
	{
		for(i=0; i<len; i++){
			SERIAL_BUF[i] = rb_get(&ringbuffer, &err);
		}
		send(sn, SERIAL_BUF, len);
		return len;
	}
	else if(AutoSend_flag == 1)
	{
		for(i=0; i<SERIAL_BUF_SIZE; i++){
			SERIAL_BUF[i] = rb_get(&ringbuffer, &err);
		}
		send(sn, SERIAL_BUF, SERIAL_BUF_SIZE);
		AutoSend_flag = 0;
		return SERIAL_BUF_SIZE;
		}
	return 0;
}

void UART_IRQHandler(void)
{
	if((Chip_UART_ReadLineStatus(LPC_USART) & UART_LSR_RDR) == 1){
		if(rb_put(&ringbuffer, Chip_UART_ReadByte(LPC_USART)) != 1){
			AutoSend_flag = 1;
		}

	}
}

int main(void) {

	//uint8_t ip[4]={192,168,0,45};
	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();

	Chip_UART_IntEnable(LPC_USART, (UART_IER_RBRINT | UART_IER_RLSINT)); //uart enable

	/* Enable UART 0 interrupt */
	NVIC_EnableIRQ(UART0_IRQn);



	//printf("%d:Connecting, ip[%d.%d.%d.%d] port [%d]\r\n", sn, ip[0], ip[1], ip[2], ip[3], port);

	while(1) {
		switch(getSn_SR(sn)) { // Sn_SR(sn) check if) listen state? goto ESTABLISHED
		case SOCK_CLOSED:
			if(socket(sn, Sn_MR_TCP, port, 0x00)==sn){ // socket create
				printf("%d:Socket Opened\r\n",sn);
			}
			else{
				printf("%d:Socket Error\r\n",sn);
				while(1); // end to error
			}

			break;
		case SOCK_INIT:
			//printf("%d:Connecting, ip[%d.%d.%d.%d] port [%d]\r\", sn, ip[0], ip[1], ip[2], ip[3], port);
			/*
 	 	 	 if(connect(sn,ip,port)==SOCK_OK);
 	 	 	 else {
 	 	 	 	 printf("%d:Connect Error\r\n",sn);
 	 	 	 	 while(1);
 	 	 	 	 }
			*/
			if(listen(sn) == SOCK_OK){ // listen state
				printf("%d:listen\r\n",sn);
			}
			else{
				printf("%d:listen error\r\n",sn);
				while(1);
			}

			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:
			if(disconnect(sn) == SOCK_OK){
				printf("%d:disconnect OK\r\n",sn);
			}
			else{
				printf("%d:diconnect Error\r\n",sn);
			}

			break;
		}
		//NVIC_DisableIRQ(UART0_IRQn);
		//Chip_UART_DeInit(LPC_USART);
	}
	return 0 ;
}

[/code]

* 설명!

[code language="c"]

typedef struct { // Creation buffer(링버퍼)
	int head;
	int tail;
	char data[SERIAL_BUF_SIZE];
} t_rb;

t_rb ringbuffer = {0, 0, }; // head, tail 0 초기화
uint8_t AutoSend_flag=0; // 자동전송 flag & 플래그 1될 때 강제전송
/*여기서! return1일 때 Data Write하고 return0일 때는 Data Write안되요*/
int rb_put( t_rb *rb , char d ) // push -> read UART
{
	int nhead = (rb->head+1) % (SERIAL_BUF_SIZE+1); // 나머지 연산
	if (rb->tail == nhead) {	// full
		return 0;
	}
	rb->data[rb->head] = d; // 위 조건식이 아닐경우 데이터 배열로 Write
	rb->head = nhead; // Write 포인터 증가
	return 1; // return rb_put;
}

/*마찬가지로 return d일 때 read 포인터에서 data 뽑아서 출력*/
/*push -> serial data write , pop -> read the data to send*/
char rb_get( t_rb *rb, int *err ) // pop -> send Ethernet
{
	char d;
	int ntail = (rb->tail+1) % (SERIAL_BUF_SIZE+1); // 나머지 연산
	if (rb->tail == rb->head) {	// empty
		*err = 0;
		return 0;
	}
	d = rb->data[rb->tail]; // Read 포인터
	rb->tail = ntail; // Read 포인터 감소(data 뽑아냈으니깐.)
	*err = 1;
	return d; // return d
}

[/code]
[code language="c"]

int finder ( t_rb *rb, char ch ) // \n 개행문자 입력 시 Data 전송 되도록 구현
{
	int i;
	int cnt;

	if(rb->head > rb->tail){ // head가 tail보다 작으면
		for(i=rb->tail; i<rb->head; i++){ // tail부터 head범위까지
			if(rb->data[i] == ch){ // 찾기
				return i;
			}
		}
	}
	else{
		for(i=rb->tail; i < SERIAL_BUF_SIZE; i++){ //tail부터 size까지
			if(rb->data[i] == ch){ // 찾기
				return i;
			}
		}
		cnt = i;
		for(i=0; i < rb->tail; i++){ // 0부터 tail까지
			if(rb->data[i] == ch){ // 찾기
				return (cnt +i);
			}
		}
	}
	return 0;
}

int EtherToSerial(uint8_t* buf,uint16_t size) // Client로 부터 Data 받음.
{
	uint8_t i;
	for(i=0 ; i < size ; i++){
		putchar(buf[i]);
	}
	return 0 ;
}
/*수신버퍼와 SERIAL_BUF랑은 다른거에요!*/
/*저렇게 버퍼에 있는걸 버퍼로 넣어서 한번에 전송시키는게 속도가 빠른 것으로 알고있어요.*/
int SerialToEther(uint8_t sn) // Client로 data 출력
{
	int len = finder(&ringbuffer, '\n');
	int err;
	int i;

	if(len > 0)
	{
		for(i=0; i<len; i++){
			SERIAL_BUF[i] = rb_get(&ringbuffer, &err); // UART data를 Serial buffer에 담음.
		}
		send(sn, SERIAL_BUF, len); // Serial 버퍼에 있는 Data 전송
		return len; // len 범위까지
	}
	else if(AutoSend_flag == 1) // 자동전송
	{
		for(i=0; i<SERIAL_BUF_SIZE; i++){
			SERIAL_BUF[i] = rb_get(&ringbuffer, &err);
		}
		send(sn, SERIAL_BUF, SERIAL_BUF_SIZE);
		AutoSend_flag = 0;
		return SERIAL_BUF_SIZE; // 전체 전송
		}
	return 0;
}

void UART_IRQHandler(void)
{
	if((Chip_UART_ReadLineStatus(LPC_USART) & UART_LSR_RDR) == 1){
		if(rb_put(&ringbuffer, Chip_UART_ReadByte(LPC_USART)) != 1){ // UART 1byte씩 Read. 
			AutoSend_flag = 1; // if문 조건식이 1과 같지 않으면 참으로 인식 -> 자동 전송함.
		}

	}
}

[/code]

!!! 여기에서 문제점..

버그가 발견되었습니다.

UART에서 Data를 읽어와서 Ethernet으로 전송해야하는데, Firmware 적으로 뻗어버립니다.

자동전송까지는 구현이 되었는데, 개행문자를 사용해서 보내버리면 Firmware가 먹통이 되어버려서 다음시간에는 Debugging하여 포스팅 하겠습니다.