📄 tty.c
字号:
/* * File : tty.c * Author : yfy001 * Date : 2002-04-20 * Description : To provide underlying serial port function, * for high level applications. * Copyright (C) 2001, 2002 yfy001 */#include <stdio.h> // perror, printf, puts, fprintf, fputs#include <unistd.h> // read, write, close#include <termios.h> // tcgetattr, tcsetattr#include <fcntl.h> // open#include <sys/signal.h> // sigaction#include <sys/types.h> // pid_t#include <string.h> // bzero, memcpy#include <limits.h> // CHAR_MAX#include <sys/ioctl.h> // ioctl#include "types.h" // int32, int16, int8, uint32, uint16, uint8#include "tty.h" // tty_open, tty_close, tty_read, tty_write#include "prompt.h" // promptstatic INT8 firstrecv = 1; // whether data receivedstatic int fd = -1; // File descriptor for the port static struct termios termios_old, termios_new;static struct timeval tv_timeout;static void tty_sig_handler();static void tty_set_baudrate(int);static int tty_get_baudrate();static void tty_set_databit(INT8 databit);static int tty_set_attr(const portinfo_t * p_portinfo);static void tty_set_stopbit(INT8 stopbit);static void tty_set_parity_check(INT8 parity);static void tty_set_flow_control(INT8 fctrl);static INT8 tty_is_open();/* * Arguments : const portinfo_t* p_portinfo; * Return value : 0 on success, ERROR on failure. * Description : Open serial port ComPort at baudrate baud rate. */int tty_open(const portinfo_t * p_portinfo){ char *p_tty; int retval; if (tty_is_open()) { return (0); } if (0 == p_portinfo->tty) { p_tty = "/dev/ttyS0"; } else if (1 == p_portinfo->tty) { p_tty = "/dev/ttyS1"; } else if (2 == p_portinfo->tty) { p_tty = "/dev/ttyS2"; } else if (3 == p_portinfo->tty) { p_tty = "/dev/ttyS3"; } else if (4 == p_portinfo->tty) { p_tty = "/dev/ttyS4"; } else if (5 == p_portinfo->tty) { p_tty = "/dev/ttyS5"; } else if (6 == p_portinfo->tty) { p_tty = "/dev/ttyS6"; } else if (7 == p_portinfo->tty) { p_tty = "/dev/ttyS7"; } else { p_tty = "/dev/ttyS0"; } fd = open(p_tty, O_RDWR | O_NOCTTY | O_NONBLOCK); if (-1 == fd) { fprintf(stderr, "cannot open port %s\n", p_tty); return (E_OPEN); } tcgetattr(fd, &termios_old); // save old termios value // 0 on success, -1 on failure retval = tty_set_attr(p_portinfo); if (-1 == retval) { fprintf(stderr, "\nport %s cannot set baudrate at %d\n", p_tty, p_portinfo->baudrate); return (E_SET_BAUDRATE); } return (0);}/* * Arguments : none * Return value : none * Description : close serial port by use of file descriptor fd */void tty_close(){ if (!tty_is_open()) { return; } tcsetattr(fd, TCSAFLUSH, &termios_old); close(fd); fd = -1;}/* * Arguments : void *data, int datalength; * Description : Read data ready from serial port * Return value : * E_NOTOPEN : port isn't open. * E_NODATA : no data has arrived before time is out. */int tty_read(void *data, int datalength){ int retval = 0; fd_set fs_read; if (!tty_is_open()) { return (E_NOTOPEN); } FD_ZERO(&fs_read); FD_SET(fd, &fs_read); tv_timeout.tv_sec = TIMEOUT_SEC(datalength, tty_get_baudrate()); tv_timeout.tv_usec = TIMEOUT_USEC; retval = select(fd + 1, &fs_read, NULL, NULL, &tv_timeout); if (retval) { return (read(fd, data, datalength)); } else { return (E_NODATA); }}/* * Arguments : uint8 *data, int datalength; * Return value : bytes written * Description : Write datalength bytes in buffer given by uint8 *data, */int tty_write(uint8 * data, int datalength){ int retval, len = 0, total_len = 0; fd_set fs_write; if (!tty_is_open()) { return (E_NOTOPEN); } FD_ZERO(&fs_write); FD_SET(fd, &fs_write); tv_timeout.tv_sec = TIMEOUT_SEC(datalength, tty_get_baudrate()); tv_timeout.tv_usec = TIMEOUT_USEC; for (total_len = 0, len = 0; total_len < datalength;) { retval = select(fd + 1, NULL, &fs_write, NULL, &tv_timeout); if (retval) { len = write(fd, &data[total_len], datalength - total_len); if (len > 0) { total_len += len; } } else { tcflush(fd, TCOFLUSH); // flush all output data break; } } return (total_len);}/* * Arguments : INT8 databit; * Description : Set databit; */static void tty_set_databit(INT8 databit){ termios_new.c_cflag &= ~CSIZE; if (7 == databit) { termios_new.c_cflag |= CS7; } else if (6 == databit) { termios_new.c_cflag |= CS6; } else if (5 == databit) { termios_new.c_cflag |= CS5; } else { termios_new.c_cflag |= CS8; }}/* * Arguments : int stopbit; * Description : Set Stop Bit */static void tty_set_stopbit(INT8 stopbit){ if (2 == stopbit) { termios_new.c_cflag |= CSTOPB; // 2 stop bits } else { termios_new.c_cflag &= ~CSTOPB; // 1 stop bit }}/* * Arguments : INT8 parity; * Description : Set Parity Check */static void tty_set_parity_check(INT8 parity){ parity = parity % 3; if (2 == parity) { // even termios_new.c_cflag |= PARENB; termios_new.c_cflag &= ~PARODD; } else if (1 == parity) { // odd termios_new.c_cflag |= PARENB; termios_new.c_cflag |= ~PARODD; } else { // no parity check termios_new.c_cflag &= ~PARENB; }}/* * Arguments : int fctrl; * 0: No Flow Control; * 1: Hardware Control; * 2: Software Control; * Return value : none * Description : set flow control of fd wth fctrl */static void tty_set_flow_control(INT8 fctrl){ if (0 == fctrl) { // no flow control termios_new.c_cflag &= ~CRTSCTS; } else if (1 == fctrl) { // hardware flow control termios_new.c_cflag |= CRTSCTS; } else if (2 == fctrl) { // software flow control termios_new.c_iflag |= IXON | IXOFF | IXANY; }}/* * Arguments : const portinfo_t* p_portinfo; * Description : Set Attribute of serial port */static int tty_set_attr(const portinfo_t * p_portinfo){ bzero(&termios_new, sizeof(termios_new)); cfmakeraw(&termios_new); tty_set_baudrate(p_portinfo->baudrate); termios_new.c_cflag |= CLOCAL | CREAD; tty_set_flow_control(p_portinfo->fctrl); tty_set_databit(p_portinfo->databit); tty_set_parity_check(p_portinfo->parity); tty_set_stopbit(p_portinfo->stopbit); termios_new.c_oflag &= ~OPOST; termios_new.c_cc[VTIME] = 1; // unit: (1/10) second. termios_new.c_cc[VMIN] = 1; // minimal characters for reading tcflush(fd, TCIFLUSH); return (tcsetattr(fd, TCSANOW, &termios_new));}/* * Arguments : int baudrate; * Description : set serial port baudrate by use of file descriptor fd */static void tty_set_baudrate(int baudrate){ if (0 == baudrate) { } else if (50 == baudrate) { termios_new.c_cflag = B50; } else if (75 == baudrate) { termios_new.c_cflag = B75; } else if (110 == baudrate) { termios_new.c_cflag = B110; } else if (134 == baudrate) { termios_new.c_cflag = B134; } else if (150 == baudrate) { termios_new.c_cflag = B150; } else if (200 == baudrate) { termios_new.c_cflag = B200; } else if (300 == baudrate) { termios_new.c_cflag = B300; } else if (600 == baudrate) { termios_new.c_cflag = B600; } else if (1200 == baudrate) { termios_new.c_cflag = B1200; } else if (2400 == baudrate) { termios_new.c_cflag = B2400; } else if (9600 == baudrate) { termios_new.c_cflag = B9600; } else if (19200 == baudrate) { termios_new.c_cflag = B19200; } else if (38400 == baudrate) { termios_new.c_cflag = B38400; } else if (57600 == baudrate) { termios_new.c_cflag = B57600; } else if (115200 == baudrate) { termios_new.c_cflag = B115200; } else { termios_new.c_cflag = B38400; }}/* * Arguments : void; * Description : get serial port baudrate */static int tty_get_baudrate(){ switch (cfgetospeed(&termios_new)) { case B0: return (0); 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 B2400: return (2400); case B9600: return (9600); case B19200: return (19200); case B38400: return (38400); case B57600: return (57600); case B115200: return (115200); default: return (9600); }}/* * Arguments : const char *pathname, int echo; * Return value : none * Description : send a file */int tty_send_file(const char *pathname, INT8 echo){ int fd, buflen, len; // fd for file char buf[BUFFER_LEN + 1]; fd = open(pathname, O_RDONLY); if (fd < 0) { perror(pathname); return (E_NOTOPEN); } while (1) { bzero(buf, sizeof(buf)); buflen = read(fd, buf, BUFFER_LEN); if (0 == buflen) break; buf[buflen] = 0; echo ? printf("%s", buf) : 0; if ((len = tty_write(buf, buflen)) != buflen) { fprintf(stderr, "write %d bytes for %d bytes\n", len, buflen); fprintf(stderr, "to tty_close()\n"); tty_close(); close(fd); fprintf(stderr, "tty_close() completed\n"); return (-1); } } fflush(stdout); fflush(stderr); close(fd); return (0);}/* * Arguments : none * Return value : none * Description : Read the data ready. */static void tty_sig_handler(){ char recvbuf[CHAR_MAX + 1]; int retval; fd_set fs_read; int byte_recv = 0; FD_ZERO(&fs_read); FD_SET(fd, &fs_read); tv_timeout.tv_sec = 0; tv_timeout.tv_usec = 500; while (1) { retval = select(fd + 1, &fs_read, NULL, NULL, &tv_timeout); if (retval) { byte_recv = read(fd, recvbuf, sizeof(recvbuf) - 1); if (firstrecv) { // first recieve printf("\n"); firstrecv = 0; } } else { if (byte_recv && p_args->p_portinfo->prompt) { prompt(); } break; } if (byte_recv > 0) { recvbuf[byte_recv] = '\0'; fprintf(stderr, "%s", recvbuf); if (DEBUG) fprintf(stderr, "%d-byte\n", byte_recv); fflush(stderr); } if (byte_recv > 80) { tv_timeout.tv_sec = 0; tv_timeout.tv_usec = 500; } else { tv_timeout.tv_sec = 0; tv_timeout.tv_usec = 200; } }}/* * Arguments : none * Return value : none * Description : Set Signal for read; */int tty_set_sig_on(){ // install the signal handler before making the device asynchronous static struct sigaction sigaction_io; sigaction_io.sa_handler = tty_sig_handler; sigemptyset(&(sigaction_io.sa_mask)); sigaction_io.sa_flags = 0; sigaction_io.sa_restorer = NULL; sigaction(SIGIO, &sigaction_io, NULL); // allow the process to receive SIGIO if (-1 == fcntl(fd, F_SETFL, O_ASYNC)) { return (-1); } else if (-1 == fcntl(fd, F_SETOWN, getpid())) { return (-1); } return (0);}/* * Arguments : none * Return value : INT8, 0: closed, 1: open * Description : return whether /dev/ttyS[tty] is open */static INT8 tty_is_open(){ return -1 == fd ? 0 : 1; // fd == -1, return 0 }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -