ESP8266串口双向透传

通过UART0实现数据透传,将UART0的RX数据通过TCP传输到指定IP,将接受到其他sta发送的TCP数据,通过URAT0的TX打印出来。

开发环境:win10+官方提供VirtualBox和OVA镜像

编辑工具:source insight3.5

一、串口数据TCP透传

上一篇中用的是任务模式,但是有一个问题就是会一直阻塞到串口那里,其他任务无法正常运行,所以这次使用串口中断实现透传。在中断中无法直接使用socket发送数据,这里实现的在中断中开辟一个新任务,任务简单执行一个write即可,代码如下:

void  socket_TCP_send( void * pvParameters )
{
	ETS_UART_INTR_DISABLE();
	//print_data(pvParameters);
	write(sock_fd, pvParameters, strlen(pvParameters));
	memset(TC_data,0,sizeof(TC_data));
	ETS_UART_INTR_ENABLE();
	vTaskDelete(NULL);
}

在SDK源码中的串口中断函数里是将接受到的数据原封不动的通过UART0的TX打印出来,接受一个打印一个,这里需要将接受到的数据装到一个全局变量里,以供发送使用,局部也可以,全局的好处在于可以控制接受任意字节的数据,进行透传。代码如下:

LOCAL void
uart0_rx_intr_handler(void *para)
{
    /* uart0 and uart1 intr combine togther, when interrupt occur, see reg 0x3ff20020, bit2, bit0 represents
    * uart1 and uart0 respectively
    */
    uint8 RcvChar;
    uint8 uart_no = UART0;//UartDev.buff_uart_no;
    uint8 fifo_len = 0;
    uint8 buf_idx = 0;


    uint32 uart_intr_status = READ_PERI_REG(UART_INT_ST(uart_no)) ;
 while (uart_intr_status != 0x0) {
        if (UART_FRM_ERR_INT_ST == (uart_intr_status & UART_FRM_ERR_INT_ST)) {
            //printf("FRM_ERR\r\n");
            WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_FRM_ERR_INT_CLR);
        } else if (UART_RXFIFO_FULL_INT_ST == (uart_intr_status & UART_RXFIFO_FULL_INT_ST)) {
            printf("full\r\n");
            fifo_len = (READ_PERI_REG(UART_STATUS(UART0)) >> UART_RXFIFO_CNT_S)&UART_RXFIFO_CNT;
            buf_idx = 0;

            while (buf_idx < fifo_len) {
                //uart_tx_one_char(UART0, READ_PERI_REG(UART_FIFO(UART0)) & 0xFF);
                TC_data[buf_idx] = READ_PERI_REG(UART_FIFO(UART0)) & 0xFF;
                buf_idx++;
            }

            WRITE_PERI_REG(UART_INT_CLR(UART0), UART_RXFIFO_FULL_INT_CLR);
        } else if (UART_RXFIFO_TOUT_INT_ST == (uart_intr_status & UART_RXFIFO_TOUT_INT_ST)) {
            printf("tout\r\n");
            fifo_len = (READ_PERI_REG(UART_STATUS(UART0)) >> UART_RXFIFO_CNT_S)&UART_RXFIFO_CNT;
            buf_idx = 0;
            
            while (buf_idx < fifo_len) {
                //uart_tx_one_char(UART0, READ_PERI_REG(UART_FIFO(UART0)) & 0xFF);
                TC_data[buf_idx] = READ_PERI_REG(UART_FIFO(UART0)) & 0xFF;
                buf_idx++;
            }

            WRITE_PERI_REG(UART_INT_CLR(UART0), UART_RXFIFO_TOUT_INT_CLR);
        } else if (UART_TXFIFO_EMPTY_INT_ST == (uart_intr_status & UART_TXFIFO_EMPTY_INT_ST)) {
            printf("empty\n\r");
            WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_TXFIFO_EMPTY_INT_CLR);
            CLEAR_PERI_REG_MASK(UART_INT_ENA(UART0), UART_TXFIFO_EMPTY_INT_ENA);
        } else {
            //skip
        }

        uart_intr_status = READ_PERI_REG(UART_INT_ST(uart_no)) ;
    }
	if(strlen(TC_data) > 0)
	{
		xTaskCreate(
	      socket_TCP_send,       /* Function that implements the task. */
	      "socket_TCP_send",          /* Text name for the task. */
	      512,      /* Stack size in words, not bytes. */
	      TC_data,    /* Parameter passed into the task. */
	      2,/* Priority at which the task is created. */
	      &xuHandle );      /* Used to pass out the created task's handle. */
	}   
}

全局变量定义如下:

char TC_data[256] = {0};
xTaskHandle xuHandle = NULL;

这样做的话就可以让串口不阻塞任务了。

二、将TCP数据透传到串口

在user_init函数中,开辟新的任务,这个任务负责创建socket实现TCPserver,然后将连接到server的client数据通过URAT0的TX输出,新任务代码如下:

 void  task_wifi_urat( void * pvParameters )
{
    int ret = 0;
    int clicoon = 0;//在server中的client连接套接字
	do
	{
		listenfd = socket(AF_INET,  SOCK_STREAM, 0);
		if (listenfd < 0) 
		{
			vTaskDelay(1000/portTICK_RATE_MS);
		}
	}while(listenfd < 0);


	struct sockaddr_in servaddr;
	memset(&servaddr, 0, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_port = htons(9000);
	servaddr.sin_addr.s_addr = INADDR_ANY;

	do
	{
		ret = bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr));
		if (ret != 0) 
		{
			vTaskDelay(1000/portTICK_RATE_MS);
		}
	}while(ret != 0);
	

	do
	{
		ret = listen(listenfd, 5);
		if (ret != 0) 
		{
			vTaskDelay(1000/portTICK_RATE_MS);
		}
	}while(ret != 0);
	
	//print_data("ready TCP\n");
	
	struct sockaddr_in peeraddr;
	socklen_t peerlen = sizeof(peeraddr);

	while(1)
	{
		
		clicoon = accept(listenfd, (struct sockaddr*)&peeraddr, &peerlen);
		if(clicoon < 0)
		{
			vTaskDelay(1000/portTICK_RATE_MS);
			continue;
		}
		//printf("accept success\n");
		while(1) 
		{
			memset(tcp_msg, 0, sizeof(tcp_msg));
			int ret = read(clicoon, tcp_msg, sizeof(tcp_msg));
			
			if(ret <= 0)
			{
				//printf("close coon\n");
				close(clicoon);
				break;
			}
			else
			{
				print_data(tcp_msg);			
			}
	}
    }
}

由于ESP8266默认打印串口日志的是URAT0,但是这里的UART0是不需要这些没用的数据的, 所以需要在串口初始化的时候指定打印数据到UART1,然后手动的将TCP数据输出到UART0输出,输出函数代码如下:

void print_data(const char *data)
{
	int i = 0;
	for(i = 0; data[i] != 0; i++)
	{
		uart0_write_char(data[i]);
	}
}

在初始化中将UART1指定为日志打印代码:

UART_SetPrintPort(UART1);
这样就可以实现双向透传了,如果有更简单的方法,希望大神们多多指教。


你可能感兴趣的:(C,ESP8266/8285)