본문 바로가기

Ethernet Chat Server/4.링버퍼 코드 수정

채팅 프로그램, 링버퍼 오류 수정

Edward입니다.

링버퍼의 Debugging을 한 결과.. finder에서 Empty상태를 안만들어줘서 안되는 것으로 판명되었습니다.

아래의 수정된 코드를 보시면 이해가 빠르실거라 생각됩니다.

[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 16
uint8_t gDATABUF[DATA_BUF_SIZE];
uint8_t SERIAL_BUF[SERIAL_BUF_SIZE];
uint8_t SERIAL_SIZE = 0;

typedef struct { // creation ring buffer
	int tail; // read data pointer
	int head; // write data pointer
	char data[SERIAL_BUF_SIZE]; // receive buffer
} t_rb;

// pointer initial to 0 set , pointer end to SERIAL_BUF_SIZE

t_rb ringbuffer = {0, 0, }; // tail = 0, head = 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);
	if(rb->tail == nhead) // Full
	{
		return 0; 
	}
	rb->data[rb->head] = d;
	rb->head = nhead;
	return 1;
}

/*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); //rest
	if(rb->head == rb->tail) // empty
	{
		*err = 0;		
		return 0; // buffer non-write -> empty
	}
	d = rb->data[rb->tail]; 
	rb->tail = ntail; 
	*err = 1; 

	return d; // buffer read
}

int finder ( t_rb *rb, char ch ) // new line finder
{
	int i;
	int cnt;
	
	if(rb->head == rb->tail) 
	{
		return 0;
	}
	else if(rb->head > rb->tail){
		for(i=rb->tail; i<rb->head; i++){
			if(rb->data[i] == ch){
				return (i+1);
			}
		}
	}
	else{
		for(i=rb->tail; i < SERIAL_BUF_SIZE; i++){
			if(rb->data[i] == ch){
				return (i+1);
			}
		}
		cnt = i;
		for(i=0; i<rb->head; i++){
			if(rb->data[i] == ch){
				return (cnt+i+1);
			}
		}
	}
	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, 0x0a);
	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; // data send to 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; // data send to max 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){
			//printf("Return1 data output%s");
		}
		else{
			AutoSend_flag = 1;
			//printf("Return0 data no output%s");
		}
	}
}

int main(void) {

	//uint8_t ip[4]={192,168,0,45};
	uint16_t port=5000;
	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"]

/*
===============================================================================
 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 16
uint8_t gDATABUF[DATA_BUF_SIZE];
uint8_t SERIAL_BUF[SERIAL_BUF_SIZE];
uint8_t SERIAL_SIZE = 0;

typedef struct { // creation ring buffer
	int tail; // read data pointer
	int head; // write data pointer
	char data[SERIAL_BUF_SIZE]; // receive buffer
} t_rb;

// pointer initial to 0 set , pointer end to SERIAL_BUF_SIZE

t_rb ringbuffer = {0, 0, }; // tail = 0, head = 0
uint8_t AutoSend_flag=0; // global variable
/*
t_rb* creating(void) // creation ring buffer
{
	t_rb *rb;
	rb->initialpoint = rb->data[0];
	rb->endpoint = rb->data[SERIAL_BUF_SIZE-1];
	rb->tail = rb->data[0];
	rb->head = rb->data[0];

	return rb;
}
*/
int rb_put( t_rb *rb , char d ) // push -> read UART
{
	int nhead = (rb->head+1) % (SERIAL_BUF_SIZE); // 전에 (rb->head+1) % (SERIAL_BUF_SIZE+1) 이었음 버퍼사이즈 15개인데 17개로 지정되어있는거 오류
	if(rb->tail == nhead) // Full
	{
		//rb->head = rb->data[0];
		return 0; // buffer non-write -> full
	}
	rb->data[rb->head] = d; // data head에 넣고
	rb->head = nhead; // 증가 *선연산 후 증가 d++
	return 1; // buffer write & return 1일 때 수신버퍼에 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); //rest
	if(rb->head == rb->tail) // empty
	{
		*err = 0;
		//rb->tail = rb->data[0];
		
		return 0; // buffer non-write -> empty
	}
	d = rb->data[rb->tail]; // 수신버퍼에 있는걸 d로 출력
	rb->tail = ntail; // d출력 후 증가 -> 나머지 만큼
	*err = 1; //same to return 1 or 1일 때 수신버퍼에서 Data 출력

	return d; // buffer read
}

/*finder -> head가 tail보다 크면 tail<->head(tail부터 head)만큼의 \n을 찾음*/
/*그리고 <-tail head-> 의 바깥부분을 찾아야하기 때문에 head부터 size까지  */
/*0부터 tail까지를 추가하였는데, 이렇게 하면 만약, tail이 head보다 위에 있을 경우*/
/*못찾을 확률이 있음. 그래서 0부터 head까지, 그리고 tail부터 size까지 찾음.*/

/*if(rb->head == rb->tail)를 넣은 이유는 조건식을 보면 크거나 같은 조건만 있는데*/
/*'같다'는 조건이 없으니 else에서 계속 돌고있다. 그래서 firmware가 다운이 되어버림 */
/*그래서 '같다'라는 조건이 되면 return 0;이니깐 0byte를 보냄*/
int finder ( t_rb *rb, char ch ) // new line finder
{
	int i;
	int cnt;
/*
	int nhead, ntail;

	//nhead = (rb->head==0?SERIAL_BUF_SIZE-1:rb->head); // 조건문 - head가 0이면 head 아니면 SERIAL_BUF(15개)
	nhead = (rb->head);
	ntail = (rb->tail);
*/
	if(rb->head == rb->tail) // \n보내면 firmware퍼지는 현상 제거 empty 추가
	{
		return 0; // head와 tail이 같아지면 return 0; data 전송 안함.
	}
	else if(rb->head > rb->tail){
		for(i=rb->tail; i<rb->head; i++){
			if(rb->data[i] == ch){
				//printf("A %d\r\n",i); i -> data 들어온 갯수 확인.
				//printf("E%d,%d\r\n",rb->tail,rb->head); -> data들어왔다면 head몇개인지, tail 몇개인지 확인
				return (i+1);
			}
		}
	}
	else{
		for(i=rb->tail; i < SERIAL_BUF_SIZE; i++){
			if(rb->data[i] == ch){
				//printf("B %d\r\n",i);
				//printf("F%d,%d\r\n",rb->tail,rb->head);
				return (i+1);
			}
		}
		cnt = i;
		for(i=0; i<rb->head; i++){
			if(rb->data[i] == ch){
				//printf("C %d\r\n",(cnt+i));
				//printf("G%d,%d\r\n",rb->tail,rb->head);
				return (cnt+i+1);
			}
		}
	}
	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, 0x0a);
	int err;
	int i;

	//printf("%d", len); finder를 통해 보내지는 Data 확인
	if(len > 0)
	{
		for(i=0; i<len; i++){
			SERIAL_BUF[i] = rb_get(&ringbuffer, &err);
		}
		//printf("%d,%s\r\n",i,SERIAL_BUF); // 캐리지 리턴 오류 -> 그래서 i+1 함. // Len이랑 head랑 갯수 맞춰주어야하기 때문에.
		send(sn, SERIAL_BUF, len);
		return len; // data send to len
	}
	else if(AutoSend_flag == 1) // Data size만큼 증가하면 자동으로 전송
	{
		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; // 0이면 다시 len만큼의 data를 전송
		return SERIAL_BUF_SIZE; // data send to max size
		}

	return 0;
}


void UART_IRQHandler(void)
{
	if((Chip_UART_ReadLineStatus(LPC_USART) & UART_LSR_RDR) == 1){
		 /*아래의 구문은 비교연산을 0으로 할 시, else로 들어가서 autosend_flag가 1이 되서 data그냥 보내버림*/
		if(rb_put(&ringbuffer, Chip_UART_ReadByte(LPC_USART)) == 1){ // return 1이 되야 data 출력
			//printf("Return1 data output%s");
		}
		else{
			AutoSend_flag = 1;
			//printf("Return0 data no output%s");
		}
	}
}

int main(void) {

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

여기까지가 채팅프로그램입니다.

최종 검사 결과.

;제목 없음

현재 저장 배열 갯수는 16byte (0~15)이며,

1. Wiznet 한 번보내고 $0a(0x0a) 보내고.
2. Wiznet 두 번보내고 $0a(0x0a) 보내고.
3. Wiznet 세 번 보내면 18개이므로 2byte over가 되서 16개까지만 자동전송 그리고 남아있는 2byte는 수신버퍼에 저장되어있음. 그리고 $0a(0x0a)보내니깐 나머지 2byte도 전송됨.