一个简单的串口转TCP工具

主要功能

  1. 支持串口收TCP发
  2. 支持TCP收串口发
  3. 支持断线重连
  4. 更多的细节及实现不在此做过多讨论。

代码

注:如串口收到数据时网络断开需保证数据在下次连接TCP时发出不在该实现内,如有兴趣可根据此框架自行修改。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <string.h>
#include <time.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <stdbool.h>
#include <stdint.h>

#define MAX_COMM_LEN 1024

uint8_t uartrecv_buf[MAX_COMM_LEN];	//串口收发缓冲区
uint8_t netrecv_buf[MAX_COMM_LEN];	//网络收发缓冲区

static int uart_dev;

typedef struct {
	int speed;
	int vtime;
	int vmin;
	char ipaddr[16];
	int port;
}Uart2TcpConfig;

static void set_opt(int fd, int nSpeed, int nBits, char nEvent, int nStop, int vtime, int vmin)
{
	struct termios newtio,oldtio;
    if(tcgetattr(fd,&oldtio) !=  0) { 
        printf("Failed to call tcgetattr.");
        return;
    }
    memset(&newtio, 0, sizeof(newtio));
    newtio.c_cflag  |=  CLOCAL | CREAD;

    newtio.c_cflag &= ~CSIZE;
    switch( nBits )
    {
    case 7:
        newtio.c_cflag |= CS7;
        break;
    case 8:
        newtio.c_cflag |= CS8;
        break;
    }
    switch( nEvent )
    {
    case 'O':
        newtio.c_cflag |= PARENB;
        newtio.c_cflag |= PARODD;
        newtio.c_iflag |= (INPCK | ISTRIP);
        break;
    case 'E': 
        newtio.c_iflag |= (INPCK | ISTRIP);
        newtio.c_cflag |= PARENB;
        newtio.c_cflag &= ~PARODD;
        break;
    case 'N':  
        newtio.c_cflag &= ~PARENB;
        break;
    }
    switch( nSpeed )
    {
    case 2400:
        cfsetispeed(&newtio, B2400);
        cfsetospeed(&newtio, B2400);
        break;
    case 4800:
        cfsetispeed(&newtio, B4800);
        cfsetospeed(&newtio, B4800);
        break;
    case 9600:
        cfsetispeed(&newtio, B9600);
        cfsetospeed(&newtio, B9600);
        break;
    case 115200:
        cfsetispeed(&newtio, B115200);
        cfsetospeed(&newtio, B115200);
        break;
    case 460800:
        cfsetispeed(&newtio, B460800);
        cfsetospeed(&newtio, B460800);
        break;
    default:
        cfsetispeed(&newtio, B9600);
        cfsetospeed(&newtio, B9600);
        break;
    }
    if( nStop == 1 )
        newtio.c_cflag &=  ~CSTOPB;
    else if ( nStop == 2 )
        newtio.c_cflag |=  CSTOPB;
    newtio.c_cc[VTIME]  = vtime;
    newtio.c_cc[VMIN] = vmin;
    tcflush(fd, TCIOFLUSH);
    if((tcsetattr(fd, TCSANOW, &newtio))!=0)
    {
        printf("COM set error");
        return;
    }
}

static bool uart_init(char *uart, int speed, int vtime, int vmin)
{

	if((uart_dev = open(uart, O_RDWR | O_NOCTTY | O_NDELAY)) < 0){
		printf("Failed to open %s\n", uart);
		return false;
	}

	set_opt(uart_dev, speed, 8, 'N', 1, vtime, vmin);

    fcntl(uart_dev, F_SETFL, O_NONBLOCK);

	printf("Uart init success.\n");

	return true;
}

static int set_nonblocking(int fd)
{
    int flags = fcntl(fd, F_GETFL, 0);
    if (flags == -1) {
        return -1;
    }
    flags |= O_NONBLOCK;
    return fcntl(fd, F_SETFL, flags);
}

static bool try_to_reconnect(int sockfd, struct sockaddr_in *serv_addr)
{
	printf("try to reconnect ...\n");
	close(sockfd);
	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	int ret = connect(sockfd, (struct sockaddr *)serv_addr, sizeof(struct sockaddr_in));
	if(ret == 0){
		set_nonblocking(sockfd);
		printf("Reconnect success.\n");
		return true;
	}
	
	return false;
}

static bool net_status(int sockfd)
{
	if(sockfd <= 0)
		return false;

	struct tcp_info info;
	int len = sizeof(info);
	getsockopt(sockfd, IPPROTO_TCP, TCP_INFO, &info, (socklen_t *)&len); 
	if((info.tcpi_state == TCP_ESTABLISHED))
		return true;
	else
		return false;
}

static int data_send(int fd, uint8_t *buf, int len)
{
	int size, count = 0;
	while(len > 0){
		size = write(fd, buf+count, len - count);
		if(size < 1) {
			break;
		}
		count += size;
		len -= size;
	}

	return count;
}

static int data_recv(int fd, uint8_t *buf, int len)
{
	int size = 0, count = 0;
	do {
		size = read(fd, buf+count, len - count);
		if(size < 1) {
			break;
		}
		count += size;
	} while (size > 0);

	return count;
}

int main (int argc, char *argv[])
{
    if(argc != 7) {
		printf("Params error.\n");
		printf("eg. %s /dev/ttyS2 115200 192.168.4.100 6800 1(vtime) 0(vmin)\n", argv[0]);
		return -1;
	}
	
	Uart2TcpConfig config;
	config.speed = atoi(argv[2]);
    strcpy(config.ipaddr, argv[3]);
    config.port  = atoi(argv[4]);
    config.vtime = atoi(argv[5]);
    config.vmin  = atoi(argv[6]);
    
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if(sockfd == -1) {
        perror("sockfd failed!\n");
        return -1;
    }

	if(!uart_init(argv[1], config.speed, config.vtime, config.vmin)) {
		printf("Uart init failed.\n");
		return -1;
	}
	
    struct sockaddr_in serv_addr;
    memset(&serv_addr, 0, sizeof(serv_addr));

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr =  inet_addr(config.ipaddr);
    serv_addr.sin_port = htons(config.port);
	int ret = connect(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
	if(ret != 0) {
		while(1){
			if(try_to_reconnect(sockfd, &serv_addr))
				break;
			sleep(1);
		}
	}
	printf("Connect to [%s:%d] success.\n", config.ipaddr, config.port);
    
    set_nonblocking(sockfd);
    
    fd_set fds_read, fds_tmp;
    int maxfd = -1;
    
    FD_ZERO(&fds_tmp);
    FD_ZERO(&fds_read);
    FD_SET(uart_dev, &fds_read);
	maxfd = uart_dev + 1;
	FD_SET(sockfd, &fds_read);
	if(sockfd >= maxfd) {
		maxfd = sockfd + 1;
	}

    while(1) {
    	if(!net_status(sockfd)){
			while(1){
				if(try_to_reconnect(sockfd, &serv_addr))
					break;
				sleep(1);
			}
		}
		
		fds_tmp = fds_read;
		
    	if (select(maxfd+1, &fds_tmp, NULL, NULL, NULL) == -1) {
            continue;
        }
        
        if(FD_ISSET(uart_dev, &fds_tmp)) {
        	// UART 2 TCP
        	memset(uartrecv_buf, 0, MAX_COMM_LEN);
			int uartrecv_len = data_recv(uart_dev, uartrecv_buf, MAX_COMM_LEN - 1);
			if (uartrecv_len > 0) {
				int len = data_send(sockfd, uartrecv_buf, uartrecv_len);
				if (len != uartrecv_len) {
					printf("tcp write data error \n");
					continue;
				}
			}
        }
        
        if(FD_ISSET(sockfd, &fds_tmp)) {
        	// TCP 2 UART
        	memset(netrecv_buf , 0, MAX_COMM_LEN);
        	int netrecv_len = data_recv(sockfd, netrecv_buf, MAX_COMM_LEN - 1);
			if(netrecv_len > 0) {
				int len = data_send(uart_dev, netrecv_buf, netrecv_len);
				if(len != netrecv_len) {
					printf("uart write data error \n");
					continue;
				}
			}
        }
    }
    close(sockfd);
    close(uart_dev);
    return 0;
}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值