📄 serial.c
字号:
#ifndef lintstatic const char rcsid[] = "$Id: serial.c,v 1.1.1.1 2001/03/08 00:01:47 efalk Exp $" ;#endif#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <errno.h>#include <fcntl.h>#include <signal.h>#include <string.h>#include <ctype.h>#include <sys/ioctl.h>#include <sys/termios.h>#include <sys/types.h>#include <sys/uio.h>#include <sys/time.h>#include "gcomm.h"#include "params.h"#include "pattern.h"#include "dialog.h"#include "buffers.h"#include "winutils.h"static struct termios old_settings ;static int tryOpen(const char *name, int mode) ;static void modemBreak() ;static int modemDialFirst(), modemDialNext() ;static void modemDialDone() ;static void SerialDialog() ; void SetHardwareFlow() ;static int get_baud() ;static int get_baudi() ; int hangingUp = 0 ; /* Open serial port. Set non-blocking. Get undefined baud rate, * character size, stop bits, etc. parameters from hardware. * Call SerialSettings() to set hardware from parameters. */intSerialOpen(const char *serialname){ int i,j ; struct termios new_settings ; /* first, open the serial port. Name may be a single * device, or a list seperated by commas */ if( (ifd = tryOpen(serialname, O_RDWR)) == -1 ) { WindowStatus("Cannot open serial port, %s", strerror(errno)) ; return -1 ; } ofd = ifd ; i = fcntl(ifd, F_GETFL, 0) ; j = fcntl(ifd, F_SETFL, i|O_NDELAY) ; if( tcgetattr(ifd,&old_settings) < 0 ) { perror("SerialOpen: tcgetattr:") ; return -1 ; } /* set any undefined variables to their true value */ if( baudRate == -1 ) { baudRate = get_baudi(cfgetospeed(&old_settings)) ; } if( byteSize == -1 ) { switch( old_settings.c_cflag & CSIZE ) { case CS5: byteSize = 5 ; break ; case CS6: byteSize = 6 ; break ; case CS7: byteSize = 7 ; break ; case CS8: byteSize = 8 ; break ; } } if( stopBits == -1 ) stopBits = (old_settings.c_cflag & CSTOPB) ? 2 : 1 ; if( inputStrip == -1 ) inputStrip = (old_settings.c_iflag & ISTRIP) != 0 ; if( parityType == -1 ) { switch( old_settings.c_cflag & (PARENB|PARODD) ) { case 0: case PARODD: parityType = ParityNone ; break ; case PARENB: parityType = ParityEven ; break ; case PARENB|PARODD: parityType = ParityOdd ; break ; } } if( flowControl == -1 ) { if( old_settings.c_cflag | CRTSCTS ) flowControl = FlowRtsCts ; else if( old_settings.c_iflag & (IXON|IXOFF) ) flowControl = FlowXonXoff ; else flowControl = FlowNone ; } WindowGetSerial() ; /* update window display */ /* put serial line into as transparent a mode as possible */ new_settings = old_settings ; new_settings.c_iflag = 0 ; new_settings.c_oflag &= ~OPOST ; new_settings.c_lflag = 0 ; new_settings.c_cc[VMIN] = 16 ; new_settings.c_cc[VTIME] = 1 ; if( tcsetattr(ifd,TCSADRAIN, &new_settings) < 0 ) { perror("SerialOpen: tcsetattr") ; return -1 ; } SerialSettings() ; return 0 ;} /* utility: attempt to open a list of devices, seperated by commas */static inttryOpen(const char *name, int type){ char devname[1024] ; char *ptr, *ptr2 ; int fd ; strncpy(devname, name, sizeof(devname)) ; for(ptr = devname; ptr != NULL; ptr = ptr2 ) { if( (ptr2 = strchr(ptr, ',')) != NULL ) *ptr2++ = '\0' ; if( (fd = open(ptr, type)) != -1 ) return fd ; } return -1 ;} /* close serial port, restore settings to original values. */intSerialClose(){ if( tcsetattr(ifd,TCSADRAIN, &old_settings) < 0 ) perror("SerialClose: tcsetattr") ; close(ifd) ; ifd = ofd = -1 ; connectionActive = False ; modemFlags = 0 ; WindowModem() ; return 0 ;} /* Set hardware flow control from parameters and modem "CD" flag */voidSetHardwareFlow(){ struct termios settings ; if( ifd == -1 ) return ; if( tcgetattr(ifd,&settings) < 0 ) { perror("SetHardwareFlow: tcgetattr") ; return ; } /* TODO: posix-compatible way to do this? */ if( ioctl(ifd, TIOCMGET, &modemFlags) < 0 ) { perror("SetHardwareFlow: TIOCMGET") ; modemFlags = 0 ; } /* Hardware bug: Some serial ports will not read if * hardware flow control is enabled and there is no carrier * detect. Therefore, we only turn on hardware flow control * when carrier detect is on */ if( flowControl != -1 ) { switch( flowControl ) { case FlowNone: hardwareFlow = 0 ; settings.c_iflag &= ~(IXON|IXOFF) ; settings.c_cflag &= ~CRTSCTS ; break ; case FlowXonXoff: hardwareFlow = 0 ; settings.c_iflag |= IXON|IXOFF ; settings.c_cflag &= ~CRTSCTS ; break ; case FlowRtsCts: settings.c_iflag &= ~(IXON|IXOFF) ; hardwareFlow = !hangingUp && (modemFlags & TIOCM_CAR) != 0 ; if( hardwareFlow ) settings.c_cflag |= CRTSCTS ; else settings.c_cflag &= ~CRTSCTS ; break ; } } if( tcsetattr(ifd,TCSADRAIN, &settings) < 0 ) perror("SetHardwareFlow: tcsetattr") ;} /* utility: set serial port */voidSerialPortControl(int baud, int cs, int parity, int stop, bool istrip){ struct termios settings ; int i ; if( ifd == -1 ) return ; if( tcgetattr(ifd,&settings) < 0 ) { perror("SerialSettings: tcgetattr") ; return ; } if( baud != -1 ) { i = get_baud(baud) ; if( i != 0 ) { cfsetospeed(&settings, i) ; cfsetispeed(&settings, i) ; } } if( cs >= 5 && cs <= 8 ) { static int csizes[] = {CS5,CS6,CS7,CS8} ; settings.c_cflag &= ~CSIZE ; settings.c_cflag |= csizes[cs-5] ; } if( stop >= 1 && stop <= 2 ) { if( stop == 2 ) settings.c_cflag |= CSTOPB ; else settings.c_cflag &= ~CSTOPB ; } if( istrip != -1 ) { if( istrip ) settings.c_iflag |= ISTRIP ; else settings.c_iflag &= ~ISTRIP ; } if( parity != -1 ) { switch( parity ) { case ParityNone: settings.c_cflag &= ~(PARENB|PARODD) ; break ; case ParityEven: settings.c_cflag &= ~PARODD ; settings.c_cflag |= PARENB ; break ; case ParityOdd: settings.c_cflag |= PARENB|PARODD ; break ; case ParityZero: case ParityOne: /* fake zero/one parity by setting byte size one higher */ i = settings.c_cflag & CSIZE ; if( i < CS8 ) { i += CS6 ; settings.c_cflag &= ~CSIZE ; settings.c_cflag |= i ; } break ; } } if( tcsetattr(ifd,TCSADRAIN, &settings) < 0 ) perror("SerialSettings: tcsetattr") ;} /* update serial port settings from parameters */voidSerialSettings(){ SerialPortControl(baudRate, byteSize, parityType, stopBits, inputStrip); SetHardwareFlow() ;} /* examine and display serial port modem lines */ /* BUG: the Zilog serial ports used by SUN shut down the receiver * if Carrier Detect is zero. Thus, we need to only enable hardware * flow control when CD is nonzero. */voidSerialModemLines(){ int oldflags = modemFlags ; if( ofd >= 0 ) { ioctl(ofd, TIOCMGET, &modemFlags) ; if( oldflags != modemFlags ) { /* if hardware flow control requested, see if CD changed */ if( flowControl == FlowRtsCts && ((oldflags ^ modemFlags) & TIOCM_CD) ) SetHardwareFlow() ; WindowModem() ; } }}voidSerialFlush(int which){ if( ofd >= 0 ) { ioctl(ofd, TCFLSH, which) ; }}voidSerialBreak(){ if( ofd >= 0 ) { ioctl(ofd, TCSBRK, 0) ; }} /* convert integer baud rate to termios # */static intget_baud(int b){ switch(b) { case 50: return B50 ; case 75: return B75 ; case 110: return B110 ; case 134: return B134 ; case 150: return B150 ; case 200: return B200 ; case 300: return B300 ; case 600: return B600 ; case 1200: return B1200 ; case 1800: return B1800 ; case 2400: return B2400 ; case 4800: return B4800 ; case 9600: return B9600 ; case 19200: return B19200 ; case 38400: return B38400 ; default: return 0 ; }} /* convert termios baud rate to integer */static intget_baudi(int b){ switch(b) { case B50: return 50 ; case B75: return 75 ; case B110: return 110 ; case B134: return 134 ; case B150: return 150 ; case B200: return 200 ; case B300: return 300 ; case B600: return 600 ; case B1200: return 1200 ; case B1800: return 1800 ; case B2400: return 2400 ; case B4800: return 4800 ; case B9600: return 9600 ; case B19200: return 19200 ; case B38400: return 38400 ; default: return 0 ; }} /* CONNECT/DISCONNECT dialog functions */ /* Establish a connection according to modem control strings * and phone number */static Pattern ModemPats[] = { {"OK\r\n",NULL,0}, {"CONNECT",NULL,0}, {"NO CARRIER\r\n",NULL,0}, {"BUSY\r\n",NULL,0}, {"ERROR\r\n",NULL,0}, {"NO DIALTONE\r\n",NULL,0} } ;#define NModemPats (sizeof(ModemPats)/sizeof(ModemPats[0]))typedef enum {dSModemConnect, dSModemInit, dSModemSetup, dSModemDialing, dSModemDisConnect, dSModemBreak, dSModemHangup, dSModemReset } DialogState ;static DialogState dState ;static char stdResetStr[] = "ATQ0V1" ;static voiddialogInit(DialogState state, int time){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -