안녕하세요.
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하여 포스팅 하겠습니다.