📄 serial.c
字号:
/* * Program: serial.c * Author: Paul Dean * Date: 2002-02-19 * Description: To provide underlying serial port function, * for high level applications. * */#include <termios.h> //* tcgetattr, tcsetattr */#include <stdio.h> //* perror, printf, puts, fprintf, fputs */#include <unistd.h> //* read, write, close */#include <fcntl.h> //* open */#include <sys/signal.h>#include <sys/types.h>#include <string.h> //* bzero, memcpy */#include <limits.h> //* CHAR_MAX */#include "types.h" //* INT32, INT16, INT8, UINT32, UINT16, UINT8 */#include "serial.h"#include "prompt.h"static INT32 fd; //* File descriptor for the port */static INT32 bOpen = 0; //* flag of whether serial opened */static struct termios termios_old, termios_new;static struct timeval tv_timeout;static void SignalHandlerIO ();static void SetBaudrate (INT32);static INT32 GetBaudrate ();static void SetDataBit (INT32 databit);static INT32 BAUDRATE (INT32 baudrate);static INT32 _BAUDRATE (INT32 baudrate);static INT32 SetPortAttr (const P_PORT_INFO pPortInfo);static void SetStopBit (const char *stopbit);static void SetParityCheck (char parity);static void SetFlowControl (INT32 fctrl);/* * Function: INT32 OpenComPort (const P_PORT_INFO pPortInfo) * Arguments: const P_PORT_INFO pPortInfo; * Description: Open serial port ComPort at baudrate baud rate. */INT32 OpenComPort (const P_PORT_INFO pPortInfo){ char *pComPort; INT32 retval; switch (pPortInfo->port) { case 0: pComPort = "/dev/ttyS0"; break; case 1: pComPort = "/dev/ttyS1"; break; case 2: pComPort = "/dev/ttyS2"; break; case 3: pComPort = "/dev/ttyS3"; break; case 4: pComPort = "/dev/ttyS4"; break; case 5: pComPort = "/dev/ttyS5"; break; case 6: pComPort = "/dev/ttyS6"; break; case 7: pComPort = "/dev/ttyS7"; break; default: pComPort = "/dev/ttyS0"; break; } fd = open (pComPort, O_RDWR | O_NOCTTY | O_NONBLOCK); if (-1 == fd) { fprintf (stderr, "cannot open port %s\n", pComPort); bOpen = 0; return (E_OPEN); } tcgetattr (fd, &termios_old); //* save old termios value */ //* 0 on success, -1 on failure */ retval = SetPortAttr (pPortInfo); if (-1 == retval) { fprintf (stderr, "\nport %s cannot set baudrate at %d\n", pComPort, pPortInfo->baudrate); return (E_SET_BAUDRATE); } bOpen = 1; return (0);}/* * Function: void CloseComPort() * Arguments: void; * Description: close serial port by use of file descriptor fd */void CloseComPort (){ //* flush output data before close and restore old attribute */ tcsetattr (fd, TCSADRAIN, &termios_old); close (fd); bOpen = 0;}/* * Function: INT32 ReadComPort (void *data, INT32 datalength) * Arguments: void *data, INT32 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. */INT32 ReadComPort (void *data, INT32 datalength){ INT32 retval = 0; fd_set fs_read; if (!bOpen) { return (E_NOTOPEN); } FD_ZERO (&fs_read); FD_SET (fd, &fs_read); tv_timeout.tv_sec = TIMEOUT_SEC (datalength, GetBaudrate ()); 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); }}/* * Write datalength bytes in buffer given by UINT8 *data, * return value: bytes written * Nonblock mode*/INT32 WriteComPort (UINT8 * data, INT32 datalength){ INT32 retval, len = 0, total_len = 0; fd_set fs_write; if (!bOpen) { return (E_NOTOPEN); } FD_ZERO (&fs_write); FD_SET (fd, &fs_write); tv_timeout.tv_sec = TIMEOUT_SEC (datalength, GetBaudrate ()); 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);}/* * Function: static INT32 GetBaudrate() * Arguments: void; * Description: get serial port baudrate */static INT32 GetBaudrate (){ return (_BAUDRATE (cfgetospeed (&termios_new)));}/* * Function: static void SetBaudrate (INT32 baudrate) * Arguments: INT32 baudrate; * Description: set serial port baudrate by use of file descriptor fd */static void SetBaudrate (INT32 baudrate){ termios_new.c_cflag = BAUDRATE (baudrate); //* set baudrate */}/* * Function: static static void SetDataBit (INT32 databit) * Arguments: INT32 databit; * Description: Set databit; */static void SetDataBit (INT32 databit){ termios_new.c_cflag &= ~CSIZE; switch (databit) { case 8: termios_new.c_cflag |= CS8; break; case 7: termios_new.c_cflag |= CS7; break; case 6: termios_new.c_cflag |= CS6; break; case 5: termios_new.c_cflag |= CS5; break; default: termios_new.c_cflag |= CS8; break; }}/* * Function: static void SetStopBit (const char *stopbit) * Arguments: const char *stopbit; * Description: Set Stop Bit */static void SetStopBit (const char *stopbit){ if (0 == strcmp (stopbit, "1")) { termios_new.c_cflag &= ~CSTOPB; //* 1 stop bit */ } else if (0 == strcmp (stopbit, "1.5")) { termios_new.c_cflag &= ~CSTOPB; //* 1.5 stop bits */ } else if (0 == strcmp (stopbit, "2")) { termios_new.c_cflag |= CSTOPB; //* 2 stop bits */ } else { termios_new.c_cflag &= ~CSTOPB; //* 1 stop bit */ }}/* * Function: static void SetParityCheck (char parity) * Arguments: char parity; * Description: Set Parity Check */static void SetParityCheck (char parity){ switch (parity) { case 'N': //* no parity check */ termios_new.c_cflag &= ~PARENB; break; case 'E': //* even */ termios_new.c_cflag |= PARENB; termios_new.c_cflag &= ~PARODD; break; case 'O': //* odd */ termios_new.c_cflag |= PARENB; termios_new.c_cflag |= ~PARODD; break; default: //* no parity check */ termios_new.c_cflag &= ~PARENB; break; }}/* * Function: static void SetFlowControl(INT32 fctrl) * Arguments: INT32 fctrl; * 0: No Flow Control; * 1: Hardware Control; * 2: Software Control; */static void SetFlowControl (INT32 fctrl){ switch (fctrl) { case 0: termios_new.c_cflag &= ~CRTSCTS; break; case 1: default: termios_new.c_cflag |= CRTSCTS; break; case 2: break; }}/* * Function: static INT32 SetPortAttr (const P_PORT_INFO) * Arguments: const P_PORT_INFO pPortInfo; * Description: Set Attribute of serial port */static INT32 SetPortAttr (const P_PORT_INFO pPortInfo){ bzero (&termios_new, sizeof (termios_new)); cfmakeraw (&termios_new); SetBaudrate (pPortInfo->baudrate); termios_new.c_cflag |= CLOCAL | CREAD; SetFlowControl (pPortInfo->fctrl); SetDataBit (pPortInfo->databit); SetParityCheck (pPortInfo->parity); SetStopBit (pPortInfo->stopbit); termios_new.c_oflag = 0; termios_new.c_lflag |= 0; 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));}/* * Function: static INT32 BAUDRATE (INT32 baudrate) * Arguments: INT32 baudrate; * Description: convert baudrate from INT32 to MACRO B** */static INT32 BAUDRATE (INT32 baudrate){ switch (baudrate) { case 0: return (B0); 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 2400: return (B2400); case 9600: return (B9600); case 19200: return (B19200); case 38400: return (B38400); case 57600: return (B57600); case 115200: return (B115200); default: return (B9600); }}/* * Function: static INT32 _BAUDRATE (INT32 baudrate) * Arguments: INT32 baudrate; * Description: convert baudrate from MACRO B** to INT32 */static INT32 _BAUDRATE (INT32 baudrate){//* reverse baudrate */ switch (baudrate) { 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); }}/* * Function: INT32 SendFile (const char *pathname, INT32 echo) * Arguments: const char *pathname, INT32 echo; */INT32 SendFile (const char *pathname, INT32 echo){ INT32 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 = WriteComPort (buf, buflen)) != buflen) { fprintf (stderr, "write %d bytes for %d bytes\n", len, buflen); fprintf (stderr, "To CloseComPort()\n"); CloseComPort (); close (fd); fprintf (stderr, "CloseComPort completed\n"); return (-1); } } //* end of while (1) */ fflush (stdout); fflush (stderr); close (fd); return (0);}/* * Function: static void SignalHandlerIO () * Arguments: void; * Read the data ready. */static void SignalHandlerIO (){ char recvbuf[CHAR_MAX + 1]; INT32 retval; fd_set fs_read; FD_ZERO (&fs_read); FD_SET (fd, &fs_read); tv_timeout.tv_sec = 0; tv_timeout.tv_usec = 200; //* 200 miliseconds */ printf ("\n"); while (1) { retval = select (fd + 1, &fs_read, NULL, NULL, &tv_timeout); if (retval) { retval = read (fd, recvbuf, sizeof (recvbuf) - 1); } else { prompt (); break; } if (DEBUG) { printf ("received %d-byte data\n", retval); fflush (stdout); } if (retval > 0) { recvbuf[retval] = '\0'; printf ("%s", recvbuf); fflush (stdout); } else { prompt (); break; } }}/* * Function: INT32 SetPortSig() * Arguments: void; * Set Signal for read; */INT32 SetPortSig (){ //* install the signal handler before making the device asynchronous */ static struct sigaction sigaction_io; //* definition of signal action */ sigaction_io.sa_handler = SignalHandlerIO; 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); if (-1 == fcntl (fd, F_SETOWN, getpid ())) return (-1); /* * Make the file descriptor asynchronous (the manual page says only * O_APPEND and O_NONBLOCK, will work with F_SETFL...) */ return (0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -