⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xcport.c

📁 支持X/YModem和cis_b+协议的串口通讯程序
💻 C
字号:
/*	xcport.c -- modem interface routines for XC	This file uses 4-character tabstops*/#include <stdio.h>#include <stdlib.h>#include <string.h>#include <ctype.h>#include <sys/types.h>#include <sys/time.h>#include <unistd.h>#include <fcntl.h>#include <signal.h>#include <errno.h>#include "xc.h"/* define this if you need to send SIGUSR1/SIGUSR2 to  handle an active getty process, or use ungetty.*//*#define GETTY_HANDLER */# if DIDO == 2			/* SCO Xenix 2.2 uses ungetty */#	define UNGETTY "/usr/lib/uucp/ungetty"#	define UG_NOTENAB	0#	define UG_ENAB		1#	define UG_FAIL		2#	define LOCKDIR "/usr/spool/uucp"#	define SIZEOFLOCKFILE sizeof(short)	static	int	code, retcode, errflag;#	ifndef GETTY_HANDLER#		define GETTY_HANDLER#	endif# endif /*DIDO==2*/# if DIDO == 3			/* SCO Xenix 2.3, SCO Unix */#	include <utmp.h>#	define LOCKDIR "/usr/spool/uucp"#	ifndef ASCII_PID#	 define ASCII_PID#	 define PIDSIZE 10#	endif	static pid_t gettypid = -1;# endif /*DIDO==3*/# if DIDO == 4			/* System V Release 4 */#	include <utmp.h>#	include <sys/stat.h>#	include <sys/mkdev.h>#	define LOCKDIR "/var/spool/locks"#	ifndef ASCII_PID#	 define ASCII_PID#	 define PIDSIZE 10#	endif	static pid_t gettypid = -1;# endif /*DIDO==4*//* see Linux FSSTND doc for discussion of lock files */# if DIDO == 9			/* Linux */#	define LOCKDIR "/var/lock"#	define ASCII_PID#	define PIDSIZE 10# endif /*DIDO==9*/#ifndef SIZEOFLOCKFILE#define SIZEOFLOCKFILE sizeof(int)#endif#if defined(DIDO) && DIDO <= 4static pid_t pid;#endifshort flowflag;			/* modem port i/o data mask */static speed_t cbaud = B2400;	/* default bps */static int mfd = -1;		/* modem port file descriptor */static struct termios pmode;	/* modem device control string */static char port[SM_BUFF];	/* modem port device file string */static char lckname[SM_BUFF];	/* lockfile string */char protocol[] = "8N1";	/* default modem protocol */extern int errno;static struct {	char *proto;	int  clear;	int  set;} prot_tbl[] = {	{"8N1",	~(CSIZE | PARENB | CSTOPB), CS8},	{"7E2",	~(CSIZE | PARODD), CS7 | PARENB | CSTOPB},	{"7O2",	~CSIZE,	CS7 | PARENB | PARODD | CSTOPB},	{NIL(char),0,0}};static struct {	char	 *bps;	unsigned rate;	speed_t cbaud;} bps_tbl[] = {	{"300",  300,  B300},	{"600",  600,  B600},	{"1200", 1200, B1200},	{"2400", 2400, B2400},	{"4800", 4800, B4800},	{"9600", 9600, B9600},#ifdef B19200	{"19200",19200,B19200},#endif#ifdef B38400	{"38400",38400,B38400},	{"57600",57600,B50},#endif	{"0", 0, B0}};#if XC_PLUS && HAVE_RS232FLOW voidset_rtscts(){	if (rtscts)		pmode.c_cflag |= CRTSCTS;	else		pmode.c_cflag &= ~CRTSCTS;   	if (mfd != -1)	   tcsetattr(mfd, TCSANOW, &pmode); }#endif /* XC_PLUS */voidxc_setflow(flow)short flow;{	if (flow)		pmode.c_iflag |= IXON | IXOFF | IXANY;	else		pmode.c_iflag &= ~(IXON | IXOFF | IXANY);	tcsetattr(mfd, TCSANOW, &pmode);}/* get/set character size and parity on the port */char *xc_setproto(p)char *p;{	register i;	if (!p)		return protocol;	for (i=0; prot_tbl[i].proto; i++){		if (!strcmp(p,prot_tbl[i].proto)){			pmode.c_cflag &= prot_tbl[i].clear;			pmode.c_cflag |= prot_tbl[i].set;			tcsetattr( mfd, TCSANOW, &pmode);			strcpy(protocol,p);			return protocol;		}	}	return NIL(char);}/* get/set port string */char *mport(s)char *s;{	if (s && mfd == -1)		if (strncmp("/dev/", s, 5))			strcpy(port, "/dev/"),			strcat(port, s);		else			strcpy(port, s);	return(port);}/*	Get/set the bps of the modem port; set the terminal rate to correspond. */unsignedmrate(s)char *s;{	register i;	if (s){		for (i=0; bps_tbl[i].cbaud; i++){			if (!strcmp(s,bps_tbl[i].bps)){				cbaud = bps_tbl[i].cbaud;				cfsetispeed(&pmode,cbaud);				cfsetospeed(&pmode,cbaud);				tcsetattr( mfd, TCSANOW, &pmode );				return (bps_tbl[i].rate);			}		}		return FAILURE;	}	for (i=0; bps_tbl[i].cbaud; i++)		if ((cfgetospeed(&pmode)) == bps_tbl[i].cbaud)			return (bps_tbl[i].rate);			return FAILURE;}/*	The following routine is used to hang up the modem. This is accomplished	by setting bps to 0. According to my documentation on termio, setting bps	to zero will result in DTR not being asserted. This hangs up some (most?)	modems. If not, the second part of the routine sends the Hayes modem	"escape" and then a hangup command.*/inthangup(){	S1("<< HANGUP >>");#if DTR_DROPS_CARRIER	cfsetospeed(&pmode,B0);		/* set cbaud 0 (drop DTR) */	tcsetattr(mfd,TCSANOW, &pmode);	sleep(1);			/* wait a second */	cfsetospeed(&pmode,cbaud);	tcsetattr(mfd,TCSANOW, &pmode);	/* reset bps */#else /* use Hayes command */	sleep(2);					/* Allow for "escape guard time" */	send_string(ATTEN);			/* Send modem escape command */	sleep(3);					/* More "escape guard time" */	send_string(HANGUP);		/* Send hangup command */#endif	return SUCCESS ;}#ifdef GETTY_HANDLER# if DIDO >= 2/*	suspend() sends signal to a running getty			 sets:	gettypid, process number of running getty, if DIDO > 2					retcode, exit value of 'ungetty', if DIDO = 2	restart(): restarts getty if it had been running before*/# if DIDO >= 3static voidsuspend(){	struct	utmp *t, *getutent();	char buf[12];	void endutent();	strcpy(buf, strrchr(port, '/') +1);	while ((t = getutent())){		if (t->ut_type == LOGIN_PROCESS && (!strcmp(buf, t->ut_line))){			gettypid = t->ut_pid;	/* get getty PID */			if (kill(gettypid, SIGUSR1) == -1 && errno != EPERM)				S1("Can't signal getty");		}	}	endutent();}static voidrestart(){	if (gettypid != -1)		kill(gettypid, SIGUSR2);}# endif /*DIDO>=3*/# if DIDO == 2static voidsuspend(){	code=errflag=pid=retcode=0;	if ((pid = fork()) == 0){		execl(UNGETTY, "ungetty", port, NIL(char));		S1("ungetty exec error");		exit(8);		}	while (((code = wait(&errflag)) != pid) && code != -1);	switch ((errflag>>8) & 0xff){	case UG_NOTENAB:	/* line acquired: not enabled */		retcode = UG_NOTENAB;		break;	case UG_ENAB:	/* line acquired: need ungetty -r when done */		retcode = UG_ENAB;		break;	case UG_FAIL:		/* could not acquire line */	case 255:		exit(8);	}}static voidrestart(){	code=errflag=pid=0;	if(retcode == UG_ENAB){		if ((pid = fork()) == 0){			execl(UNGETTY, "ungetty", "-r", port, NIL(char));			exit(8);		}	while (((code = wait(&errflag)) != pid) && code != -1)		;	}}# endif /*DIDO==2*/# endif /*DIDO>=2*/#endif /*GETTY_HANDLER*//*	Attach standard input and output to the modem port. This only gets called	after a fork by the child process, which then exec's a program that uses	standard i/o for some data transfer protocol. (To put this here is actually	a kludge, but I wanted to keep the modem-specific stuff in a black box.)*/voidmattach(){	dup2(mfd, 0);	/* close local stdin and connect to port */	dup2(mfd, 1);	/* close local stdout and connect to port */	close(mfd);		/* close the old port descriptor */}#if !HAVE_SELECTstatic voidalrm(junk)int junk;{    /* do nothing */    signal(SIGALRM, alrm);}#endif/*	Get a byte from the modem port within 'seconds' or return -1.	All data read from the modem are input through this routine.*/	static int rcount = 0; /* used by readbyte() and purge() */intreadbyte(seconds)int seconds;{#if HAVE_SELECT	struct timeval tmval = { 0L, 0L }, *tmval_p ;	fd_set refds ;	int srval ;#endif	static char *p, rxbuf[SM_BUFF];	if (rcount > 0){		rcount--;		return(*p++ & 0xff);	}#if HAVE_SELECT	FD_ZERO(&refds);	FD_SET(mfd,&refds);	if(seconds == RB_BLOCK) { /* block */	    tmval_p = NULL ;	} else {	    tmval_p = &tmval ;	    tmval.tv_sec = (long) seconds ;	}	srval = select(mfd+2, &refds, NULL, NULL, tmval_p) ;	if ( srval == 0 ) 	    return -1 ;	else if ( srval < 0 ){	    fprintf(stderr, " select() error in %s\r\n", __FILE__ );	    return -1 ;	} 	if( ! FD_ISSET(mfd, &refds) ) /* nothing to do, ergo return */	    return -1 ;		rcount = read(mfd, p = rxbuf, SM_BUFF);#else	if (seconds){	    signal(SIGALRM, alrm);	    alarm((unsigned)seconds);	}	if ((rcount = read(mfd, p = rxbuf, SM_BUFF)) < 1)	    return(-1);	if (seconds)	    alarm(0);#endif	rcount--;	return(*p++ & 0xff);}/*	Throw away all input characters until no more are sent. */void purge() {#if _POSIX_SOURCE	tcflush(mfd, TCIFLUSH);#else	while (readbyte(1) != -1)    		; /* empty loop */#endif	rcount = 0;}/*	Output a byte to the modem port.	All data sent to the modem are output through this routine.*/voidsendbyte(ch)int ch;{	char c = ch & 0xff;	if(write(mfd, &c, 1)<0){		S1("sendbyte: write error!");		fprintf(stderr,"Verify that you are trying to use a valid and operational tty port.\r\n");		sleep(1);	}}voidsend_string(s)char *s;{	while (*s){		sendbyte(*s++);		/* msecs(35);*/		/* season to taste ... */	}}/* send a modem break */intxmitbrk(){	S1("<< BREAK >>");	tcsendbreak( mfd, 0 ); 	return SUCCESS;}/*	check to see if lock file exists and is still active.	kill(pid, 0) only works on ATTSV, some BSDs and Xenix	returns: SUCCESS, or FAILURE if lock file active	added: Steve Manes 7/29/88*/static intcheckLCK(){	int rc, fd;#ifdef ASCII_PID	char alckpid[PIDSIZE+2];#endif	pid_t lckpid = -1;	if ((fd = open(lckname, O_RDONLY)) == -1){		if (errno == ENOENT)			return SUCCESS;	/* lock file doesn't exist */		goto unlock;	}#ifdef ASCII_PID	rc = read(fd, (char *)alckpid, PIDSIZE+1);	close(fd);	lckpid = atoi(alckpid);	if (rc != 11)#else	rc = read(fd, (char *)&lckpid, SIZEOFLOCKFILE);	close(fd);	if (rc != SIZEOFLOCKFILE)#endif	{		S1("Lock file has bad format");		goto unlock;	}	/* now, send a bogus 'kill' and check the results */	if (kill(lckpid, 0) == 0 || errno == EPERM){		sprintf(Msg,"Lock file process %d on %s is still active - try later",			lckpid, port);		S;		return FAILURE;	}unlock:	if (unlink(lckname) != 0){		sprintf(Msg,"Can't unlink %s file", lckname);		S;		return FAILURE;	}	return SUCCESS;}/*	lock_tty() returns FAILURE if the lock file exists (and XC will not run).	unlock_tty() deletes the lock file.	SCOXENIX 2.3 mods: Steve Manes	Check for active LCK file and try to delete it	SCOXENIX 2.2 mods: Jean-Pierre Radley	As above, using 'ungetty'	Tandy 6000 mods: Fred Buck 	SVR4 mods: Larry Rosenman*/static intlock_tty(){#if (DIDO >= 2)	int lckfd;	char *s, buf[16];#ifdef ASCII_PID	static char apid[PIDSIZE+2] = { '\0' };#else	pid = -1;#endif	strcpy(buf, strrchr(port, '/') +1);	s = buf + strlen(buf) - 1;#if DIDO == 4	struct stat stat_buf;#endif#if DIDO == 2	*s = toupper(*s);#endif#if DIDO >= 3	*s = tolower(*s);#endif#if DIDO == 4	if(stat(port,&stat_buf)==0){		sprintf(lckname,"%s/LK.%03d.%03d.%03d",LOCKDIR,			major(stat_buf.st_dev),			major(stat_buf.st_rdev),			minor(stat_buf.st_rdev));	}#else	sprintf(lckname, "%s/LCK..%s", LOCKDIR, buf);#endif /*DIDO==4*/	if (!checkLCK())	/* check LCK file */		return FAILURE;	/* can't unlock it */		if ((lckfd = creat(lckname, 0666)) < 0){		sprintf(Msg,"Can't create '%s'", lckname);		S;		return FAILURE;	}#ifdef ASCII_PID   /* HDB UUCP style file lock */	sprintf(apid, "%*d\n", PIDSIZE, getpid());	write(lckfd, apid, PIDSIZE+1);#else	pid = getpid();	write(lckfd, (char *)&pid, SIZEOFLOCKFILE);#endif	close(lckfd);#endif /* DIDO >= 2 */	return SUCCESS;}voidunlock_tty(){	static char byettyxx[50], *byeptr;	char *port_name ;	if((port_name = ttyname(mfd))!=NULL){	sprintf(byettyxx,"BYE%s", strrchr(port_name,'/')+1);	byeptr = getenv(byettyxx);	if (byeptr && *byeptr)		S1("Sending BYE string to modem"),		send_string("\r"),		send_string(byeptr),		send_string("\r");	}	pmode.c_cflag &= ~CLOCAL;	pmode.c_cflag |= B0 | HUPCL;	tcsetattr(mfd, TCSANOW, &pmode);	close(mfd);#if DIDO >= 2	setuid(geteuid());	setgid(getegid());	unlink(lckname);# ifdef GETTY_HANDLER	restart();# endif#endif	S2("Exiting XC");}/*	Opens the modem port and configures it. If the port string is	already defined it will use that as the modem port; otherwise it	gets the environment variable MODEM. Returns SUCCESS or FAILURE.*/intmopen(){	int c;	char *p;	if (port[0] == '\0'){		if (!(p = getenv("MODEM"))){			S2("Exiting: no modem port specified or present in environment");			exit(3);		}		mport(p);	}	if (!lock_tty())		exit(4);#if DIDO	p = port +strlen(port) -1;	*p = toupper(*p);# ifdef GETTY_HANDLER	suspend();# endif#endif	if ((mfd = open(port, O_RDWR | O_NDELAY)) < 0){		sprintf(Msg,"Can't open modem port %s",port);		S;		exit(5);	}	tcgetattr( mfd, &pmode);	cfsetospeed(&pmode,cbaud);	cfsetispeed(&pmode,cbaud);	pmode.c_cflag &= ~HUPCL;	pmode.c_cflag |= CLOCAL;#if DIDO >= 3 & defined(CRTSCTS)	pmode.c_cflag |= CRTSCTS ;	/* pmode.c_cflag |= CRTSFL ; */#endif	pmode.c_iflag = IGNBRK ;	pmode.c_oflag = pmode.c_lflag = 0;	pmode.c_cc[VMIN] = 1; 	/* This many chars satisfies reads */	pmode.c_cc[VTIME] = 0;	/* or in this many tenths of seconds */	xc_setflow(flowflag);	c = mfd;	if ((mfd = open(port, O_RDWR)) < 0){	/* Reopen line with CLOCAL */		sprintf(Msg,"Can't re-open modem port %s",port);		S;		return FAILURE;	}	close(c);	return SUCCESS;}/*        xc_drain()	Used in wcputsec(). Wait for output to drain before sending	checksum/crc. Clear input buffer of any noise in anticipation of	an acknowledgement after we send the checksum/crc.  Note that	there are some circumstances where we would not want to have	xc_drain call purge(). For example, under g-mode streaming	transfer, there is no ACK handshake.  This means that receipt	of any CAN byte from the other end will be asynchronous and	unpredictable. Therefore having xc_drain() call purge() might	cause us to inadvertently clobber the CAN that has arrived but	has not yet been read.*/voidxc_drain(purge_flag) int purge_flag;{#if _POSIX_SOURCE    tcdrain(mfd);    if (purge_flag)	tcflush(mfd, TCIFLUSH);	/* same as purge() */#else    if (purge_flag)	purge();#endif}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -