编程开源技术交流,分享技术与知识

网站首页 > 开源技术 正文

串口网口数据透传程序(串口透传实验报告)

wxchong 2024-07-29 08:11:17 开源技术 54 ℃ 0 评论

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端口,串口调试软件连接到设备串口;

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

下图为测试结果:


Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表