百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 热门文章 > 正文

串口网口数据透传程序

bigegpt 2024-09-03 11:03 3 浏览

comtcp简介

comtcp程序实现linux平台下串口网口数据转发功能,将串口与网口数据透明转发,应用该程序可以用网络TCP访问串口设备;

#include	<stdio.h>
#include	<unistd.h>
#include	<stdlib.h>
#include	<errno.h>
#include	<fcntl.h>      /*文件控制定义*/
#include	<termios.h>    /*PPSIX终端控制定义*/
#include	<string.h>
#include	<sys/ioctl.h>
#include 	<netinet/tcp.h>
#include	<sys/socket.h>
#include	<netinet/in.h>
#include	<pthread.h>
#include	<signal.h>
#include	<sys/time.h>
#include	<sys/epoll.h> 	/* epoll function */
#include	<sys/sysinfo.h>
#define		MAXEPOLLSIZE 5	//表示MAXEPOLLSIZE-1个
#define		MAXLINE 256
#define		MAXEVENTS 10

#define FALSE 0
#define TRUE  1

struct sPrivateReg
{
	int fd;
	unsigned int lastaccesstime;
}__attribute__((packed));

int connfd,fcom,comindex,tcpindex;
pthread_mutex_t rs485busdata_mut; 
unsigned char volatile rs485busyflag;

void set_speed(int fd,int speed)
{
	struct termios   Opt;
	tcgetattr(fd, &Opt);
	cfsetispeed(&Opt, speed);
	cfsetospeed(&Opt, speed);
	tcsetattr(fd, TCSANOW, &Opt);
}

int set_Parity(int fd,int databits,int stopbits,int parity)
{
	struct termios options;
	if  ( tcgetattr( fd,&options)  !=  0)
	{
		perror("SetupSerial 1");
		return(FALSE);
	}
	options.c_iflag &= ~IXOFF;
	options.c_iflag &= ~IXON;
	options.c_cflag &= ~CSIZE;
	switch (databits) /*设置数据位数*/
	{
		case 7:
			options.c_cflag |= CS7;
		break;
		case 8:
			options.c_cflag |= CS8;
		break;
		default:
			printf("Unsupported data size\n");
		return (FALSE);
	}
	switch (parity)
	{
	case 'n':
	case 'N':
		options.c_cflag &= ~PARENB;   		/* Clear parity enable */
		options.c_iflag &= ~INPCK;     		/* Enable parity checking */
	break;
	case 'o':
	case 'O':
		options.c_cflag |= (PARODD | PARENB);  	/* 设置为奇效验*/
		options.c_iflag |= INPCK;             	/* Disnable parity checking */
	break;
	case 'e':
	case 'E':
		options.c_cflag |= PARENB;     		/* Enable parity */
		options.c_cflag &= ~PARODD;   		/* 转换为偶效验*/
		options.c_iflag |= INPCK;      	 	/* Disnable parity checking */
	break;
	case 'S':
	case 's':  /*as no parity*/
		options.c_cflag &= ~PARENB;
		options.c_cflag &= ~CSTOPB;
	break;
	default:
		printf("Unsupported parity\n");
		return (FALSE);
	}
	/* 设置停止位*/
	switch (stopbits)
	{
		case 1:
			options.c_cflag &= ~CSTOPB;
		break;
		case 2:
			options.c_cflag |= CSTOPB;
		break;
		default:
			printf("Unsupported stop bits\n");
			return (FALSE);
	}
	/* Set input parity option */
	if (parity != 'n')
	options.c_iflag |= INPCK;
	tcflush(fd,TCIFLUSH); /* Update the options and do it NOW */
	options.c_cc[VTIME] = 1; //100ms
	options.c_cc[VMIN] = 255;
	options.c_iflag &= ~(IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK|ISTRIP|INLCR|IGNCR|ICRNL|IUCLC|IXON|IXOFF|IXANY);
	options.c_oflag &= ~OPOST;
	options.c_lflag &= ~(ECHO|ECHONL|ISIG|IEXTEN|ICANON);
	if (tcsetattr(fd,TCSANOW,&options) != 0)
	{
		perror("SetupSerial 3");
		return (FALSE);
	}
	return (TRUE);
}

int OpenDev(char *Dev)
{
	int fd = open( Dev, O_RDWR );         //| O_NOCTTY | O_NDELAY
	if (-1 == fd)
	{
		/*设置数据位数*/
		perror("Can't Open Serial Port");
		return -1;
	}
	else
		return fd;
}

void Uart_set_send(int fd)	
{
	int status;
	ioctl(fd, TIOCMGET, &status);
	status &= ~TIOCM_RTS;
	ioctl(fd, TIOCMSET, &status);
}

void Uart_set_get(int fd)	
{
	int status;
	ioctl(fd, TIOCMGET, &status);
	status |= TIOCM_RTS;
	ioctl(fd, TIOCMSET, &status);
}

void Chekbusy(int fd) 	
{
	int status;
	ioctl(fd, TIOCSERGETLSR, &status);
	while(((status&0x0001)==0))
	{
		ioctl(fd, TIOCSERGETLSR, &status);
	}
	usleep(20);		
	Uart_set_get(fd); 	
}

void Uart_send(int fd,char *data ,int longer)	
{
	int nread;
	Uart_set_send(fd); 			
	nread = write(fd, data ,longer);		
	Chekbusy(fd);
}

int Uart_read(int fd,unsigned char *rcv_buf,int num,int sec,int usec)
{
	int retval;
	fd_set rfds;
	struct timeval tv;
	int ret=-1;
	tv.tv_sec = sec;//set the rcv wait time
	tv.tv_usec = usec;//100000us = 0.1s
	while(1)
	{
		FD_ZERO(&rfds);
		FD_SET(fd,&rfds);
		retval = select(fd+1,&rfds,NULL,NULL,&tv);
		if(retval ==-1)
		{
			perror("select()");
			break;
		}
		else if(retval)
		{
			ret= read(fd,rcv_buf,num);
		}
		else
		{
			break;
		}
	}
	return ret;  
}

void DoComEvent(int *index)
{
	int  rwnum;
	unsigned char RTU_RXBuf[255];
	while(1)
	{
		rwnum=Uart_read(fcom,RTU_RXBuf,255,0,500000);
		if(rwnum>0){send(connfd,RTU_RXBuf , rwnum, 0);rs485busyflag=0;}
		usleep(1000);
	}
}

int setnonblocking(int sockfd)
{
	if (fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFD, 0)|O_NONBLOCK) == -1) {
		return -1;
	}
	return 0;
}

int getavailablefd(unsigned int nowdatetime,struct sPrivateReg Private_Reg_Buf[])
{
	unsigned int oversecmax = 0;
	int ret = -1;
	int i;
	for(i = 0; i< MAXEPOLLSIZE; i++)
	{
		if(Private_Reg_Buf[i].fd == -1)
			return i;
		else if(oversecmax<nowdatetime-Private_Reg_Buf[i].lastaccesstime)
		{
			oversecmax = nowdatetime-Private_Reg_Buf[i].lastaccesstime;
			ret = i;
		}
	}
	if(oversecmax>60)
	{
		printf("close_fd(overtime): %d\n", Private_Reg_Buf[ret].fd);
		Private_Reg_Buf[ret].fd = -1;
		shutdown(Private_Reg_Buf[ret].fd, SHUT_RDWR);
		close(Private_Reg_Buf[ret].fd);
	}
	else
		ret = -1;
	return ret;
}

struct sPrivateReg * findfd(int fd,struct sPrivateReg Private_Reg_Buf[])
{
	int i;
	for(i = 0; i< MAXEPOLLSIZE; i++)
		if(Private_Reg_Buf[i].fd == fd)	return &Private_Reg_Buf[i];
	return NULL;
}

unsigned int gettickcount()
{
	struct sysinfo info;
	sysinfo(&info);
	return info.uptime;
}

void initPrivate_Reg_Buf(int index,struct sPrivateReg Private_Reg_Buf[])
{
	memset(&Private_Reg_Buf[index], 0, sizeof(struct sPrivateReg));
	Private_Reg_Buf[index].fd = -1;
}

void close_fd(int fd,struct sPrivateReg Private_Reg_Buf[])
{
	int i;
	for(i = 0; i< MAXEPOLLSIZE; i++)
	if(Private_Reg_Buf[i].fd == fd)
	{
		printf("close_fd(normal): %d\n", fd);
		Private_Reg_Buf[i].fd = -1;
		shutdown(fd, SHUT_RDWR);
		close(fd);
		return;
	}
}

int handle(int confd,int *index) 
{
	int rtcpnum;
	struct timeval tm,tm1;
	unsigned char buf[MAXLINE];
	rtcpnum=read(confd, buf, MAXLINE);
	if (rtcpnum == 0) {
		printf("client close the connection\n");
		close(confd);
		return -1;
	} 
	if (rtcpnum < 0) {
		perror("read error");
		close(confd);
		return -1;
	}	
	pthread_mutex_lock(&rs485busdata_mut);
	rs485busyflag=1;
	connfd=confd;
	Uart_send(fcom,(char *)buf,rtcpnum);	
	gettimeofday(&tm, NULL);
	while(rs485busyflag){
	gettimeofday(&tm1, NULL);
	if(((tm1.tv_sec-tm.tv_sec)*1000+(tm1.tv_usec-tm.tv_usec)/1000)>=500)
	{rs485busyflag=0;break;}
	else usleep(2000);
	}
	pthread_mutex_unlock(&rs485busdata_mut);				
	return 0;	
}

void DoTcpEvent1(int *index)
{
	int i,fd_index;
	int count=0;
	int  servPort =502+(*index);
	int listenq = 6;//监听队列
	int listenfd, connect_fd, kdpfd, nfds, n, curfds;
	struct sockaddr_in servaddr, cliaddr;
	socklen_t socklen = sizeof(struct sockaddr_in);
	struct epoll_event ev;
	struct epoll_event events[MAXEVENTS];
	struct sPrivateReg Private_Reg_Buf[MAXEPOLLSIZE];
	unsigned int datetime;

	for(i=0;i<MAXEPOLLSIZE;i++)//初始化在线列表
	Private_Reg_Buf[i].fd = -1;
	bzero(&servaddr, sizeof(servaddr));
	servaddr.sin_family = AF_INET; 
	servaddr.sin_addr.s_addr = htonl (INADDR_ANY);
	servaddr.sin_port = htons (servPort);

	listenfd = socket(AF_INET, SOCK_STREAM, 0); 
	if (listenfd == -1) {
		perror("can't create socket file");	
	}
	int opt = 1;
	setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

	if (setnonblocking(listenfd) < 0) {
		perror("setnonblock error");
	}

	if (bind(listenfd, (struct sockaddr *) &servaddr, sizeof(struct sockaddr)) == -1) 
	{
		perror("bind error");	
	} 
	if (listen(listenfd, listenq) == -1) 
	{
		perror("listen error");	
	}
	/* 创建 epoll 句柄,把监听 socket 加入到 epoll 集合里 */
	kdpfd = epoll_create(MAXEPOLLSIZE);
	ev.events = EPOLLIN | EPOLLHUP | EPOLLERR;
	ev.data.fd = listenfd;
	if (epoll_ctl(kdpfd, EPOLL_CTL_ADD, listenfd, &ev) < 0) 
	{
		fprintf(stderr, "epoll set insertion error: fd=%d\n", listenfd);	
	}
	curfds = 1;
	printf("transparent comtcp startup,port %d, max client is %d, backlog is %d\n", servPort, MAXEPOLLSIZE, listenq);
	while(1)
	{
		/* 等待有事件发生 */
		nfds = epoll_wait(kdpfd, events, MAXEVENTS, -1);
		datetime = gettickcount();
		if (nfds == -1)
		{
			perror("epoll_wait");
			continue;
		}
		/* 处理所有事件 */
		for (n = 0; n < nfds; ++n)
		{
			if (events[n].data.fd == listenfd) 
			{
				connect_fd = accept(listenfd, (struct sockaddr *)&cliaddr,&socklen);
				if (connect_fd < 0) 
				{
					perror("accept error");
					exit(1);
					continue;
				}
				else
				{
				   printf("accept success %d\n",count++);
				}

	 			fd_index = getavailablefd(datetime,Private_Reg_Buf);
				if(fd_index>=0)
				{
					initPrivate_Reg_Buf(fd_index,Private_Reg_Buf);
					Private_Reg_Buf[fd_index].fd = connect_fd;
					Private_Reg_Buf[fd_index].lastaccesstime = datetime;
					ev.events = EPOLLIN | EPOLLHUP | EPOLLERR;
					ev.data.fd = connect_fd;
					if (epoll_ctl(kdpfd, EPOLL_CTL_ADD, connect_fd, &ev) < 0)
					{
					   fprintf(stderr, "epoll set insertion error: fd=%d\n",connect_fd);
					}
				}
				else
				{
					shutdown(connect_fd, SHUT_RDWR);
					close(connect_fd);
					printf("full tcp pool!\n");
				}
			}
			else if(events[n].events&EPOLLHUP)//#
			{
				epoll_ctl(kdpfd, EPOLL_CTL_DEL, events[n].data.fd, &ev) ;
				close_fd(events[n].data.fd,Private_Reg_Buf);
				printf("EPOLLHUP fd: %d\n",events[n].data.fd);
			}
			else if(events[n].events&EPOLLERR)
			{
			   /* read data from client */
				epoll_ctl(kdpfd, EPOLL_CTL_DEL, events[n].data.fd, &ev) ;
				close_fd(events[n].data.fd,Private_Reg_Buf);
				printf("EPOLLERR fd: %d\n",events[n].data.fd);
			}
			else if(events[n].events&EPOLLIN)
			{
				//recive_form_client(events[n].data.fd);
				struct sPrivateReg *pPrivate_Reg_Buf = findfd(events[n].data.fd,Private_Reg_Buf);
				if(pPrivate_Reg_Buf)
				{
					pPrivate_Reg_Buf->lastaccesstime = gettickcount();
					if (handle(events[n].data.fd,index) < 0) 
					{
						close_fd(pPrivate_Reg_Buf->fd,Private_Reg_Buf);
					}
				}
			}
			else
			{
			   /* read data from client */
				printf("UNKNOWN POLL MESSAGE fd: %d\n",events[n].data.fd);
			}
		}
	}
	close(listenfd);	
}

int main(int argc, char **argv)
{
	pthread_t com,tcp;
	int baud;
	char dev[10],comdev[20];
	comdev[0]=0;
	//串口初始化
	if(argc!=3)
	{
		fprintf(stderr,"Usage:comtcp baud dev\nexample:comtcp 9600 ttySAC0\n");
		exit(1);
	}
	sscanf(argv[1],"%d",&baud);
	sscanf(argv[2],"%s",dev);
	strcat(comdev,"/dev/");
	strcat(comdev,dev);
	fcom= OpenDev(comdev);
	if(fcom)
	{
		switch(baud)
		{
			case 2400:set_speed(fcom,B2400);break;
			case 4800:set_speed(fcom,B4800);break;
			case 9600:set_speed(fcom,B9600);break;
			case 19200:set_speed(fcom,B19200);break;
			case 38400:set_speed(fcom,B38400);break;
			case 57600:set_speed(fcom,B57600);break;
			case 115200:set_speed(fcom,B115200);break;
			default:set_speed(fcom,B9600);printf("daufalt baud:B9600\n");break;
		}
	}		
	else
	{
		printf("Can not open COM %s!\n",dev);
		exit(1);
	}
	if (set_Parity(fcom,8,1,'N')== FALSE)
	{
    		printf("Set Parity Error\n");
    		exit(1);
	}
	comindex=0;
	tcpindex=0;
	pthread_create(&com,NULL,(void*)&DoComEvent,(void *)&comindex);
	pthread_create(&tcp,NULL,(void*)&DoTcpEvent1,(void *)&tcpindex);
	while (1)
	{
		sleep(1);	
	}
	close(connfd);//关闭设备
	close(fcom);
	return 0;
}

使用说明

配置系统

编译源码将comtcp复制到系统某个路径下;

运行程序,执行命令

测试结果

准备下面两个调试软件:

打开软件,用网络调试软件以TCP客户端连接设备IP(例如192.168.1.15),502端口,串口调试软件连接到设备串口;

网络调试软件发送数据会在串口调试软件中收到,串口调试软件发送数据会在网络调试软件中收到;实现了串口与网口的数据互相转发;

下图为测试结果:


相关推荐

当Frida来“敲”门(frida是什么)

0x1渗透测试瓶颈目前,碰到越来越多的大客户都会将核心资产业务集中在统一的APP上,或者对自己比较重要的APP,如自己的主业务,办公APP进行加壳,流量加密,投入了很多精力在移动端的防护上。而现在挖...

服务端性能测试实战3-性能测试脚本开发

前言在前面的两篇文章中,我们分别介绍了性能测试的理论知识以及性能测试计划制定,本篇文章将重点介绍性能测试脚本开发。脚本开发将分为两个阶段:阶段一:了解各个接口的入参、出参,使用Python代码模拟前端...

Springboot整合Apache Ftpserver拓展功能及业务讲解(三)

今日分享每天分享技术实战干货,技术在于积累和收藏,希望可以帮助到您,同时也希望获得您的支持和关注。架构开源地址:https://gitee.com/msxyspringboot整合Ftpserver参...

Linux和Windows下:Python Crypto模块安装方式区别

一、Linux环境下:fromCrypto.SignatureimportPKCS1_v1_5如果导包报错:ImportError:Nomodulenamed'Crypt...

Python 3 加密简介(python des加密解密)

Python3的标准库中是没多少用来解决加密的,不过却有用于处理哈希的库。在这里我们会对其进行一个简单的介绍,但重点会放在两个第三方的软件包:PyCrypto和cryptography上,我...

怎样从零开始编译一个魔兽世界开源服务端Windows

第二章:编译和安装我是艾西,上期我们讲述到编译一个魔兽世界开源服务端环境准备,那么今天跟大家聊聊怎么编译和安装我们直接进入正题(上一章没有看到的小伙伴可以点我主页查看)编译服务端:在D盘新建一个文件夹...

附1-Conda部署安装及基本使用(conda安装教程)

Windows环境安装安装介质下载下载地址:https://www.anaconda.com/products/individual安装Anaconda安装时,选择自定义安装,选择自定义安装路径:配置...

如何配置全世界最小的 MySQL 服务器

配置全世界最小的MySQL服务器——如何在一块IntelEdison为控制板上安装一个MySQL服务器。介绍在我最近的一篇博文中,物联网,消息以及MySQL,我展示了如果Partic...

如何使用Github Action来自动化编译PolarDB-PG数据库

随着PolarDB在国产数据库领域荣膺桂冠并持续获得广泛认可,越来越多的学生和技术爱好者开始关注并涉足这款由阿里巴巴集团倾力打造且性能卓越的关系型云原生数据库。有很多同学想要上手尝试,却卡在了编译数据...

面向NDK开发者的Android 7.0变更(ndk android.mk)

订阅Google官方微信公众号:谷歌开发者。与谷歌一起创造未来!受Android平台其他改进的影响,为了方便加载本机代码,AndroidM和N中的动态链接器对编写整洁且跨平台兼容的本机...

信创改造--人大金仓(Kingbase)数据库安装、备份恢复的问题纪要

问题一:在安装KingbaseES时,安装用户对于安装路径需有“读”、“写”、“执行”的权限。在Linux系统中,需要以非root用户执行安装程序,且该用户要有标准的home目录,您可...

OpenSSH 安全漏洞,修补操作一手掌握

1.漏洞概述近日,国家信息安全漏洞库(CNNVD)收到关于OpenSSH安全漏洞(CNNVD-202407-017、CVE-2024-6387)情况的报送。攻击者可以利用该漏洞在无需认证的情况下,通...

Linux:lsof命令详解(linux lsof命令详解)

介绍欢迎来到这篇博客。在这篇博客中,我们将学习Unix/Linux系统上的lsof命令行工具。命令行工具是您使用CLI(命令行界面)而不是GUI(图形用户界面)运行的程序或工具。lsoflsof代表&...

幻隐说固态第一期:固态硬盘接口类别

前排声明所有信息来源于网络收集,如有错误请评论区指出更正。废话不多说,目前固态硬盘接口按速度由慢到快分有这几类:SATA、mSATA、SATAExpress、PCI-E、m.2、u.2。下面我们来...

新品轰炸 影驰SSD多款产品登Computex

分享泡泡网SSD固态硬盘频道6月6日台北电脑展作为全球第二、亚洲最大的3C/IT产业链专业展,吸引了众多IT厂商和全球各地媒体的热烈关注,全球存储新势力—影驰,也积极参与其中,为广大玩家朋友带来了...