/* This program copyright 2003 Perry Harrington (pedward at dainst dot com) * * This program is covered under the GPL license. For information on the GPL * license, see http://www.gnu.org/licenses/licenses.html#GPL * * Serial initialization code was taken from public domain examples. * * The program expects 2 arguments, the serial port to access and the baud rate. * The user must have permissions to access the port. * * Compile with: gcc -Wall -o terminal terminal.c * */ #include #include #include #include #include #include #include #include #include #include #include #define ESCAPE '~' #define QUIT 'q' #define CRLF 'c' #define DELBS 'b' /* baudrate settings are defined in , which is included by */ #define BAUDRATE B57600 /* change this definition for the correct port */ /*#define MODEMDEVICE "/dev/ttyS0"*/ #define _POSIX_SOURCE 1 /* POSIX compliant source */ #define FALSE 0 #define TRUE 1 int parseBaud(char *baudrate) { int i; sscanf(baudrate, "%d",&i); switch (i) { case 460800: return B460800; case 230400: return B230400; case 115200: return B115200; case 57600: return B57600; case 38400: return B38400; case 19200: return B19200; case 9600: return B9600; case 4800: return B4800; case 2400: return B2400; case 1800: return B1800; case 1200: return B1200; case 600: return B600; case 300: return B300; case 200: return B200; case 150: return B150; case 134: return B134; case 110: return B110; case 75: return B75; case 50: return B50; default: return B0; } } void usage(void) { printf("terminal port baud\n"); printf("Ex: terminal /dev/ttyS0 57600\n"); } int main(int argc, char *argv[]) { unsigned char buf[1024]; unsigned int baudrate; int fd, res; int crlf_conv = TRUE; int del_bs = TRUE; char last,prev; struct termios oldtio,newtio; struct termios coldtio,cnewtio; fd_set fds; int STOP=FALSE; if (argc != 3) { fprintf(stderr, "You must supply a port name and baudrate!\n"); usage(); exit(1); } baudrate = parseBaud(argv[2]); if (baudrate == B0) { fprintf(stderr, "Invalid baudrate: %s\n", argv[2]); usage(); exit(1); } /* Open modem device for reading and writing and not as controlling tty because we don't want to get killed if linenoise sends CTRL-C. */ fd = open(argv[1], O_RDWR | O_NOCTTY ); if (fd <0) {perror(argv[1]); exit(-1); } tcgetattr(fd,&oldtio); /* save current serial port settings */ tcgetattr(0,&coldtio); /* save current serial port settings */ memset(&newtio, 0, sizeof(newtio)); /* clear struct for new port settings */ memcpy(&cnewtio, &coldtio, sizeof(cnewtio)); /* BAUDRATE: Set bps rate. You could also use cfsetispeed and cfsetospeed. CRTSCTS : output hardware flow control (only used if the cable has all necessary lines. See sect. 7 of Serial-HOWTO) CS8 : 8n1 (8bit,no parity,1 stopbit) CLOCAL : local connection, no modem contol CREAD : enable receiving characters */ newtio.c_cflag = baudrate | CS8 | CLOCAL | CREAD; /* IGNPAR : ignore bytes with parity errors ICRNL : map CR to NL (otherwise a CR input on the other computer will not terminate input) otherwise make device raw (no other input processing) */ //newtio.c_iflag = IGNPAR | IGNBRK; newtio.c_iflag = 0; /* Raw output. */ newtio.c_oflag = 0; /* ICANON : enable canonical input disable all echo functionality, and don't send signals to calling program */ //newtio.c_lflag = ICANON; newtio.c_lflag = 0; cfmakeraw(&newtio); /* initialize all control characters default values can be found in /usr/include/termios.h, and are given in the comments, but we don't need them here */ newtio.c_cc[VINTR] = 0; /* Ctrl-c */ newtio.c_cc[VQUIT] = 0; /* Ctrl-\ */ newtio.c_cc[VERASE] = 0; /* del */ newtio.c_cc[VKILL] = 0; /* @ */ newtio.c_cc[VEOF] = 0; /* Ctrl-d */ newtio.c_cc[VTIME] = 0; /* inter-character timer unused */ newtio.c_cc[VMIN] = 1; /* blocking read until 1 character arrives */ newtio.c_cc[VSWTC] = 0; /* '\0' */ newtio.c_cc[VSTART] = 0; /* Ctrl-q */ newtio.c_cc[VSTOP] = 0; /* Ctrl-s */ newtio.c_cc[VSUSP] = 0; /* Ctrl-z */ newtio.c_cc[VEOL] = 0; /* '\0' */ newtio.c_cc[VREPRINT] = 0; /* Ctrl-r */ newtio.c_cc[VDISCARD] = 0; /* Ctrl-u */ newtio.c_cc[VWERASE] = 0; /* Ctrl-w */ newtio.c_cc[VLNEXT] = 0; /* Ctrl-v */ newtio.c_cc[VEOL2] = 0; /* '\0' */ /* now clean the modem line and activate the settings for the port */ tcflush(fd, TCIFLUSH); tcsetattr(fd,TCSANOW,&newtio); cnewtio.c_lflag &= ~(ECHO|ICANON); tcflush(0, TCIFLUSH); tcsetattr(0,TCSANOW,&cnewtio); last = prev = '\0'; printf("Escape keys, type at beginning of line:\n\t%c%c quits\n\t%c%c toggles CRLF conversion\n\t%c%c toggles DEL to BS conversion\n\n", ESCAPE, QUIT, ESCAPE, CRLF, ESCAPE, DELBS); while (STOP==FALSE) { /* loop until we have a terminating condition */ FD_ZERO(&fds); FD_SET(fd,&fds); FD_SET(0,&fds); res = select(fd+1,&fds,NULL,NULL,NULL); if (res < 0) { perror("select"); } else if (res > 0) { if (FD_ISSET(fd, &fds)) { res = read(fd,buf,sizeof(buf)); write(1,buf,res); } if (FD_ISSET(0, &fds)) { res = read(0,buf,sizeof(buf)); if ((prev == '\n' || prev == '\r') && last == ESCAPE) { switch(buf[0]) { case QUIT: STOP = TRUE; continue; case CRLF: crlf_conv = !crlf_conv; break; case DELBS: del_bs = !del_bs; default: break; } } if (del_bs == TRUE && (buf[0] == 0x7F)) { write(fd,"\b",1); } else if (crlf_conv == TRUE && ((buf[0] == '\r' && buf[1] == '\n') || buf[0] == '\n' )) { write(fd,"\r",1); } else { write(fd,buf,res); } prev = last; last = buf[0]; } } } /* restore the old port settings */ tcsetattr(fd,TCSANOW,&oldtio); tcsetattr(0,TCSANOW,&coldtio); close(fd); printf("exit...\n"); return 0; }