#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define VERSION "2.6.0" /* values for parity */ #define SERIAL_NO_PARITY 1 #define SERIAL_EVEN_PARITY 2 #define SERIAL_ODD_PARITY 4 /* values for data bits */ #define SERIAL_8_DATA_BITS 8 #define SERIAL_7_DATA_BITS 7 /* values for stop bits */ #define SERIAL_1_STOP_BITS 1 #define SERIAL_2_STOP_BITS 2 /* flow control */ #define FLOW_CONTROL_NONE 1 #define FLOW_CONTROL_HARDWARE 2 #define FLOW_CONTROL_SOFTWARE 3 #define FALSE 0 #define TRUE 1 #define DEFAULT_BAUD_RATE B9600 //#define BAUD_RATE B19200 //#define BAUD_RATE B38400 #define NON_BLOCKING_SERIAL char serial_port[FILENAME_MAX+1]; char logfile_name[FILENAME_MAX+1]; /* log output to file */ int opt_log_output = FALSE; /* dump output as hex */ int opt_hex_output = TRUE; /* strip high bit from all chars sent to stdout */ int opt_strip_high_bit = FALSE; /* default is to transmit CRLF on CR from stdin; when true, only the CR is * transmitted to remote */ int opt_bare_cr = FALSE; speed_t baudrate = DEFAULT_BAUD_RATE; /* at some point, could make these command line configurable */ int parity = SERIAL_NO_PARITY; //int databits = SERIAL_7_DATA_BITS; int databits = SERIAL_8_DATA_BITS; int stopbits = SERIAL_1_STOP_BITS; //int flow_control = FLOW_CONTROL_SOFTWARE; //int flow_control = FLOW_CONTROL_HARDWARE; int flow_control = FLOW_CONTROL_NONE; int main_quit = 0; typedef struct { const char *str; int len; /* string length of str */ speed_t speed; } BaudRate; BaudRate baudrates[] = { { "110", 3, B110 }, { "150", 3, B150 }, { "300", 3, B300 }, { "600", 3, B600 }, { "1200", 4, B1200 }, { "2400", 4, B2400 }, { "4800", 4, B4800 }, { "9600", 4, B9600 }, { "19200", 5, B19200 }, { "38400", 5, B38400 }, { "57600", 5, B57600 }, { "115200", 6, B115200}, { "230400", 6, B230400}, }; const unsigned char CR = '\r'; const unsigned char LF = '\n'; #if defined linux || defined unix || defined __GNUC__ void signal_term( int signum ) { fprintf( stderr, "signal!\n" ); main_quit = 1; } void init_signals( void ) { int uerr; struct sigaction sigterm; struct sigaction sigint; memset( &sigterm, 0, sizeof(sigterm) ); sigterm.sa_handler = signal_term; uerr = sigaction( SIGTERM, &sigterm, NULL ); if( uerr != 0 ) { perror( "sigaction(SIGTERM)" ); exit(1); } memset( &sigint, 0, sizeof(sigint) ); sigint.sa_handler = signal_term; uerr = sigaction( SIGINT, &sigint, NULL ); if( uerr != 0 ) { perror( "sigaction(SIGINT)" ); exit(1); } } #endif int serial_open_port( void ) { struct termios oldtio, newtio; int fd; /* stupid human check -- I've been running this thing * as root (very very dumb) so I don't want to accidently * write DNP to /dev/hda1 or something equally tragic. */ // if( strncmp( path, "/dev/ttyS", 9 ) != 0 ) { // LOG_MESSAGE1( LOG_ERR, "\"%s\" not a serial port.", path ); // return ERR_FAIL; // } /* davep 29-Apr-2009 ; temp debug */ fprintf( stderr, "%s opening %s\n", __FUNCTION__, serial_port ); /* open serial port */ #ifdef NON_BLOCKING_SERIAL fd = open( serial_port, O_RDWR|O_NOCTTY|O_NONBLOCK ); #else fd = open( serial_port, O_RDWR|O_NOCTTY ); #endif if( fd < 0 ) { fprintf( stderr, "open() of %s failed : %s", serial_port, strerror(errno) ); return -1; } /* davep 29-Apr-2009 ; temp debug */ fprintf( stderr, "%s opened %s successfully\n", __FUNCTION__, serial_port ); tcgetattr( fd, &oldtio ); memset( &newtio, 0, sizeof(newtio) ); newtio.c_cflag = CLOCAL | CREAD ; /* parity */ switch( parity ) { case SERIAL_NO_PARITY : /* nothing -- default is no parity */ break; case SERIAL_EVEN_PARITY : newtio.c_cflag |= PARENB; break; case SERIAL_ODD_PARITY : newtio.c_cflag |= PARENB | PARODD; break; default : assert( 0 ); } /* data bits */ if( databits == SERIAL_8_DATA_BITS ) { newtio.c_cflag |= CS8; } else if( databits == SERIAL_7_DATA_BITS ) { newtio.c_cflag |= CS7; } else { assert( 0 ); } /* stop bits */ if( stopbits == SERIAL_1_STOP_BITS ) { /* nothing -- default is 1 stop bit */ } else if( stopbits == SERIAL_2_STOP_BITS ) { newtio.c_cflag |= CSTOPB; } else { assert( 0 ); } /* hardware flow control? */ if( flow_control==FLOW_CONTROL_HARDWARE ) { newtio.c_cflag |= CRTSCTS; } newtio.c_lflag = 0; /* no additional lflags */ newtio.c_iflag = 0; // | IXON | IXANY | IXOFF | IMAXBEL; /* software flow control? */ if( flow_control==FLOW_CONTROL_SOFTWARE ) { newtio.c_iflag |= (IXON | IXOFF | IXANY); } newtio.c_oflag = 0; /* no additional oflags */ cfsetospeed( &newtio, baudrate ); cfsetispeed( &newtio, baudrate ); #ifndef NON_BLOCKING_SERIAL newtio.c_cc[VMIN] = 1; /* block until this many chars recvd */ newtio.c_cc[VTIME] = 0; /* inter character timer unused */ #endif tcflush( fd, TCIFLUSH ); tcsetattr( fd, TCSANOW, &newtio ); return fd; } int baud_string_to_baud( char *baudstring, speed_t *baudrate ) { int i; for( i=0 ; i max_fd ) { max_fd = fd; } err = select( max_fd+1, &read_fds, NULL, NULL, NULL ); if( err<0 ) { fprintf( stderr, "select err=%d errno=%d (%s)\r\n", err, errno, strerror(errno) ); continue; } if( FD_ISSET( stdin_fileno, &read_fds ) ) { err = read( stdin_fileno, &databyte, 1 ); if( err <= 0 ) { fprintf( stderr, "read stdin err=%d errno=%d (%s)\r\n", err, errno, strerror(errno) ); break; } if( databyte == 0x03 ) { /* Ctrl-C? */ break; } write( fd, &databyte, 1 ); if( databyte==CR && !opt_bare_cr ) { write( fd, &LF, 1 ); } } if( FD_ISSET( fd, &read_fds ) ) { err = read( fd, &databyte, 1 ); if( err <= 0 ) { fprintf( stderr, "read fd err=%d errno=%d (%s)\r\n", err, errno, strerror(errno) ); break; } if( opt_hex_output ) { /* There is something weird in printf(). I want to see 0x00 and it * prints "0" instead. Messes up my pretty screen alignment. */ if( databyte ) { #ifdef PRINT_0X printf( "%#04x ", databyte ); } else { printf( "0x00 " ); } #else printf( "%02x ", databyte ); } else { printf( "00 " ); } #endif } else { /* buyer beware -- just print whatever we get */ /* added some simple "filtering"; TODO add regex filtering so * really annoying stuff never hits human eyeballs */ int printit = 1; /* davep 10-May-2012 ; bell pissing me off */ if( databyte==0x07 ) { printit = 0; } /* davep 19-aug-2011 ; found a platform that uses \n\r not \r\n * (buh?) so filter out the 0x0d */ if( databyte==0x0a ) { printf( "%c", 0x0d ); } if( databyte==0x0d ) { printit = 0; } /* davep 27-Oct-2011 ; quiet down people doing obnoxious stuff like: * * ******** color_pipe_set_config ENTRY config: 0x5fae64 * */ // if( databyte == '*' ) { // printit = 0; // } /* davep 01-Aug-2010 ; I did the 0x7f a while ago (strips the * 8th bit) because our newer hardware has issues and the 8th * bit flips up and down randomly. */ if( printit ) { if( opt_strip_high_bit ) { printf( "%c", databyte&0x7f ); } else { printf( "%c", databyte ); } } } if( opt_log_output ) { fwrite( &databyte, 1, 1, binfile ); fflush( binfile ); } } count++; } close( fd ); if( opt_log_output ) { fclose( binfile ); } /* set stdin back to starting point */ fprintf( stderr, "restoring stdin to previous state\r\n" ); err = tcsetattr( stdin_fileno, TCSANOW, &stdin_tios ); if( err < 0 ) { fprintf( stderr, "tcsetattr() failed to set stdin term attributes: %d %s\n", errno, strerror(errno)); /* keep going and hope for the best */ } printf( "\nbye!\n" ); return 0; }