aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Eversberg <jolly@eversberg.eu>2020-04-26 09:21:18 +0200
committerAndreas Eversberg <jolly@eversberg.eu>2020-05-23 14:25:34 +0200
commitdd95a49fc9077ac219494f866de7ce385c539210 (patch)
tree05fa37e6f441459123d8ac064c742a1c323d9231
parent5d5e2e99c1ebae8bc560639432f1579c1ad37c57 (diff)
Added local library for serial port access
-rw-r--r--.gitignore1
-rw-r--r--configure.ac1
-rw-r--r--src/Makefile.am3
-rw-r--r--src/libserial/Makefile.am6
-rwxr-xr-xsrc/libserial/serial.c460
-rwxr-xr-xsrc/libserial/serial.h38
6 files changed, 508 insertions, 1 deletions
diff --git a/.gitignore b/.gitignore
index 76a9190..eff76be 100644
--- a/.gitignore
+++ b/.gitignore
@@ -47,6 +47,7 @@ src/libsdr/libsdr.a
src/libsample/libsample.a
src/libam/libam.a
src/libclipper/libclipper.a
+src/libserial/libserial.a
src/anetz/libgermanton.a
src/anetz/anetz
src/bnetz/bnetz
diff --git a/configure.ac b/configure.ac
index 5c37545..542a91e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -84,6 +84,7 @@ AC_OUTPUT(
src/libsdr/Makefile
src/libsample/Makefile
src/libclipper/Makefile
+ src/libserial/Makefile
src/anetz/Makefile
src/bnetz/Makefile
src/cnetz/Makefile
diff --git a/src/Makefile.am b/src/Makefile.am
index d07bc39..94c3f6c 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -25,7 +25,8 @@ SUBDIRS = \
libwave \
libfft \
libmncc \
- libclipper
+ libclipper \
+ libserial
if HAVE_ALSA
SUBDIRS += \
diff --git a/src/libserial/Makefile.am b/src/libserial/Makefile.am
new file mode 100644
index 0000000..04fe1e9
--- /dev/null
+++ b/src/libserial/Makefile.am
@@ -0,0 +1,6 @@
+AM_CPPFLAGS = -Wall -Wextra -g $(all_includes)
+
+noinst_LIBRARIES = libserial.a
+
+libserial_a_SOURCES = \
+ serial.c
diff --git a/src/libserial/serial.c b/src/libserial/serial.c
new file mode 100755
index 0000000..076686a
--- /dev/null
+++ b/src/libserial/serial.c
@@ -0,0 +1,460 @@
+/* serial port access
+ *
+ * (C) 2001-2018 by Andreas Eversberg <jolly@eversberg.eu>
+ * All Rights Reserved
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include "serial.h"
+
+/*
+serial = serial_open("/dev/ttyS0",9600,8,n,1,'d','e',1,2);
+
+the return value will be a "serial handle" (!NOT THE FILE HANDLE) for all routines. on failure, a NULL will be returned.
+
+the parameters are as followed:
+
+char *device; tty name
+int baud; baud rate (bits/s)
+int databits; 5-7
+char parity; n=no,e=even,o=odd
+int stopbits; 1-2
+char xonxoff; e=disable,e=enable
+char rtscts; e=disable,e=enable
+float txtimeout; seconds timeout for transmit
+float rxtimeout; seconds timeout for receive
+
+to access the real tty handle use:
+
+serial->handle
+
+NOTE: the device is in non-blocking mode.
+*/
+serial_t *serial_open(const char *serial_device, int serial_baud, int serial_databits, char serial_parity, int serial_stopbits, char serial_xonxoff, char serial_rtscts, int serial_getbreak, float serial_txtimeout, float serial_rxtimeout)
+{
+ int baud;
+ int flags;
+ int handshake_lines;
+ serial_t *serial;
+
+ if (serial_databits < 5 || serial_databits > 8) {
+ serial_errno = -EINVAL;
+ serial_errnostr = "Only 5 trough 8 stopbits supported.";
+ return NULL;
+ }
+ if (serial_stopbits < 1 || serial_stopbits > 2) {
+ serial_errno = -EINVAL;
+ serial_errnostr = "Only 1 trough 2 stopbits supported.";
+ return NULL;
+ }
+ if (serial_xonxoff !='e' && serial_xonxoff != 'd') {
+ serial_errno = -EINVAL;
+ serial_errnostr = "Enable or disable Xon/Xoff?";
+ return NULL;
+ }
+ if (serial_rtscts !='e' && serial_rtscts != 'd') {
+ serial_errno = -EINVAL;
+ serial_errnostr = "Enable or disable RTS/CTS?";
+ return NULL;
+ }
+ if (serial_parity != 'n' && serial_parity != 'e' && serial_parity != 'o') {
+ serial_errno = -EINVAL;
+ serial_errnostr = "Unsopported parity.";
+ return NULL;
+ }
+ switch (serial_baud) {
+ case 50: baud = B50; break;
+ case 75: baud = B75; break;
+ case 110: baud = B110; break;
+ case 134: baud = B134; break;
+ case 150: baud = B150; break;
+ case 200: baud = B200; break;
+ case 300: baud = B300; break;
+ case 600: baud = B600; break;
+ case 1200: baud = B1200; break;
+ case 2400: baud = B2400; break;
+ case 4800: baud = B4800; break;
+ case 9600: baud = B9600; break;
+ case 19200: baud = B19200; break;
+ case 38400: baud = B38400; break;
+ case 57600: baud = B57600; break;
+ case 115200: baud = B115200; break;
+ case 230400: baud = B230400; break;
+ default:
+ serial_errno = -EINVAL;
+ serial_errnostr = "Baudrate not supported.";
+ return NULL;
+ }
+
+ /* allocate handle */
+ if ((serial = calloc(1, sizeof(*serial)))) {
+
+ /* set parameters */
+ serial->device = serial_device;
+ serial->baud = serial_baud;
+ serial->databits = serial_databits;
+ serial->parity = serial_parity;
+ serial->stopbits = serial_stopbits;
+ serial->xonxoff = serial_xonxoff;
+ serial->rtscts = serial_rtscts;
+ serial->txtimeout = serial_txtimeout;
+ serial->rxtimeout = serial_rxtimeout;
+
+
+ if ((serial->handle = open(serial->device, O_RDWR | O_NONBLOCK)) >= 0) {
+ if (isatty(serial->handle)) {
+ /* get termios */
+ tcgetattr(serial->handle, &serial->old_termios);
+ tcgetattr(serial->handle, &serial->com_termios);
+ /* set flags */
+ serial->com_termios.c_iflag =
+ ((serial->databits == 7) ? ISTRIP : 0) |
+ ((serial->xonxoff == 'e') ? (IXON | IXOFF) : 0) ;
+ if (serial_getbreak)
+ serial->com_termios.c_iflag |= (PARMRK | INPCK);
+ else
+ serial->com_termios.c_iflag |= (IGNBRK | IGNPAR);
+ serial->com_termios.c_oflag = 0;
+ serial->com_termios.c_cflag =
+ CREAD |
+ HUPCL |
+ ((serial->databits == 5) ? CS5 : 0) |
+ ((serial->databits == 6) ? CS6 : 0) |
+ ((serial->databits == 7) ? CS7 : 0) |
+ ((serial->databits == 8) ? CS8 : 0) |
+ ((serial->parity == 'e') ? PARENB : 0) |
+ ((serial->parity == 'o') ? (PARENB | PARODD) : 0) |
+ ((serial->stopbits == 2) ? CSTOPB : 0) |
+ ((serial->rtscts =='e' ) ? CRTSCTS : 0) |
+ ((serial->rtscts =='d' ) ? CLOCAL : 0) ;
+ serial->com_termios.c_lflag = 0;
+ serial->com_termios.c_cc[VSTART] = 0x11;
+ serial->com_termios.c_cc[VSTOP] = 0x13;
+
+ /* set baud */
+ serial->com_termios.c_cflag |= baud;
+ cfsetispeed(&serial->com_termios, baud);
+ cfsetospeed(&serial->com_termios, baud);
+
+ serial->com_termios.c_cc[VMIN] = 0;
+ serial->com_termios.c_cc[VTIME] = (int)(serial->rxtimeout / 0.1 + 0.5);
+
+ if (tcsetattr(serial->handle, TCSANOW, &serial->com_termios) >= 0) {
+ handshake_lines = TIOCM_DTR;
+ if (serial->rtscts == 'd') {
+ handshake_lines |= TIOCM_RTS;
+ }
+ if (ioctl(serial->handle, TIOCMBIS, &handshake_lines) >= 0) {
+ if ((flags = fcntl(serial->handle, F_GETFL, 0)) >= 0) {
+ flags &= ~O_NONBLOCK;
+ if (fcntl(serial->handle, F_SETFL, flags) >= 0) {
+ serial_errno = 0;
+ serial_errnostr = "ok";
+ return serial;
+ } else {
+ serial_errno = -EIO;
+ serial_errnostr = "Cannot set fcntl.";
+ }
+ } else {
+ serial_errno = -EIO;
+ serial_errnostr = "Cannot read fnctl.";
+ }
+ } else {
+ serial_errno = -EIO;
+ serial_errnostr = "Cannot set handshake lines.";
+ }
+ } else {
+ serial_errno = -EIO;
+ serial_errnostr = "TTY refuses settings.";
+ }
+ } else {
+ serial_errno = -EIO;
+ serial_errnostr = "Device is not a tty!";
+ }
+ tcsetattr(serial->handle, TCSANOW, &serial->old_termios);
+ close(serial->handle);
+ } else {
+ serial_errno = -EIO;
+ serial_errnostr = "Error opening serial interface.";
+ }
+ free(serial);
+ } else {
+ serial_errno = -ENOMEM;
+ serial_errnostr = "not enougth memory for handle";
+ }
+
+ return NULL;
+}
+
+
+/*
+serial_close(serial);
+
+closes the com port and frees all memory used by "serial"
+*/
+void serial_close(serial_t *serial)
+{
+ serial_errno = 0;
+ if (serial == 0)
+ return;
+
+ tcsetattr(serial->handle,TCSANOW,&serial->old_termios);
+ close(serial->handle);
+ free(serial);
+}
+
+/*
+read = serial_read(serial, &buffer, size);
+
+reads until buffer "size" has reached or until timeout has occured.
+"read" gives the number of bytes read.
+*/
+
+int serial_read(serial_t *serial, uint8_t *buffer, int size)
+{
+ int n;
+
+ serial_errno = 0;
+ if (!serial)
+ return 0;
+
+ n = read(serial->handle, buffer, size);
+ if (n < 0) {
+ serial_errno = n;
+ n = 0;
+ }
+
+ return n;
+}
+
+/*
+wrote = serial_write(serial, &buffer, size);
+
+writes until buffer "size" has reached or until timeout has occured.
+"wrote" gives the number of bytes written.
+*/
+
+int serial_write(serial_t *serial, uint8_t *buffer, int size)
+{
+ int n;
+ fd_set Desc;
+ struct timeval Timeout;
+
+ serial_errno = 0;
+ if (!serial)
+ return 0;
+
+ Timeout.tv_usec = (int)(serial->txtimeout * 1000000) % 1000000;
+ Timeout.tv_sec = serial->txtimeout;
+
+
+ FD_ZERO (&Desc);
+ FD_SET (serial->handle, &Desc);
+
+ // Use select to check if write is possible
+
+ if (select(serial->handle + 1, NULL, &Desc, NULL, &Timeout)) {
+ // Descriptor is ready for writing
+ n = write(serial->handle, buffer, size);
+ if (n < 0) {
+ serial_errno = n;
+ n = 0;
+ }
+ return n;
+ } else {
+ // Timeout or signal. Return an timeout error code when a signal
+ // occurs
+ return 0;
+ }
+}
+
+/*
+ok = serial_timeout(serial, transmit, receive);
+
+will set the transmit and receive timeout. note that the receive timeout
+will only use the nearest 1/10s. to disable timeout, use 0 for any value.
+*/
+int serial_timeout(serial_t *serial, double serial_txtimeout, double serial_rxtimeout)
+{
+ serial_errno = 0;
+ if (!serial)
+ return 0;
+
+ serial->rxtimeout = serial_rxtimeout;
+ serial->txtimeout = serial_txtimeout;
+
+ serial->com_termios.c_cc[VMIN] = 0;
+ serial->com_termios.c_cc[VTIME] = (int)(serial->rxtimeout / 0.1 + 0.5);
+ if (tcsetattr(serial->handle, TCSANOW, &serial->com_termios) < 0) {
+ serial_errno = - EIO;
+ serial_errnostr = "TTY refuses settings.";
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+serial_errno
+serial_errnostr
+
+the last call will give an errno while opening, which is described below:
+
+0: ok
+also use serial_errnostr for description
+*/
+int serial_errno = 0;
+char *serial_errnostr = "";
+
+int serial_cts(serial_t *serial)
+{
+ int status = 0;
+
+ serial_errno = 0;
+ if (!serial)
+ return 0;
+
+ if(ioctl(serial->handle, TIOCMGET, &status) < 0) {
+ serial_errno = -EIO;
+ serial_errnostr = "Cannot get ioctl.";
+ return -1;
+ }
+ return (status & TIOCM_CTS) != 0;
+}
+
+int serial_dsr(serial_t *serial)
+{
+ int status = 0;
+
+ serial_errno = 0;
+ if (!serial)
+ return 0;
+
+ if(ioctl(serial->handle, TIOCMGET, &status) < 0) {
+ serial_errno = -EIO;
+ serial_errnostr = "Cannot get ioctl.";
+ return -1;
+ }
+ return (status & TIOCM_DSR) != 0;
+}
+
+/*
+ok = serial_dtron(serial);
+ok = serial_rtson(serial);
+ok = serial_dtroff(serial);
+ok = serial_rtsoff(serial);
+
+turn on or off: rts, dtr
+*/
+
+int serial_dtron(serial_t *serial)
+{
+ int status = TIOCM_DTR;
+
+ serial_errno = 0;
+ if (!serial)
+ return 0;
+
+ if(ioctl(serial->handle, TIOCMBIS, &status) < 0) {
+ serial_errno = -EIO;
+ serial_errnostr = "Cannot set ioctl.";
+ return -1;
+ }
+ return 0;
+}
+int serial_dtroff(serial_t *serial)
+{
+ int status = TIOCM_DTR;
+
+ serial_errno = 0;
+ if (!serial)
+ return 0;
+
+ if(ioctl(serial->handle, TIOCMBIC, &status) < 0) {
+ serial_errno = -EIO;
+ serial_errnostr = "Cannot set ioctl.";
+ return -1;
+ }
+ return 0;
+}
+int serial_rtson(serial_t *serial)
+{
+ int status = TIOCM_RTS;
+
+ serial_errno = 0;
+ if (!serial)
+ return 0;
+
+ if(ioctl(serial->handle, TIOCMBIS, &status) < 0) {
+ serial_errno = -EIO;
+ serial_errnostr = "Cannot set ioctl.";
+ return -1;
+ }
+ return 0;
+}
+int serial_rtsoff(serial_t *serial)
+{
+ int status = TIOCM_RTS;
+
+ serial_errno = 0;
+ if (!serial)
+ return 0;
+
+ if(ioctl(serial->handle, TIOCMBIC, &status) < 0) {
+ serial_errno = -EIO;
+ serial_errnostr = "Cannot set ioctl.";
+ return -1;
+ }
+ return 0;
+}
+
+int serial_break(serial_t *serial, int on)
+{
+ serial_errno = 0;
+ if (!serial)
+ return 0;
+
+ if (ioctl(serial->handle, on ? TIOCSBRK : TIOCCBRK, 0) < 0) {
+ serial_errno = -EIO;
+ serial_errnostr = "Cannot set ioctl.";
+ return -1;
+ }
+ return 0;
+}
+
+
+/*
+handle = serial_handle(serial);
+
+get real file handle by giving the serial handle
+*/
+
+int serial_handle(serial_t *serial)
+{
+ if (!serial)
+ return 0;
+
+ return serial->handle;
+}
+
diff --git a/src/libserial/serial.h b/src/libserial/serial.h
new file mode 100755
index 0000000..17300dc
--- /dev/null
+++ b/src/libserial/serial.h
@@ -0,0 +1,38 @@
+
+#include <termios.h>
+
+extern int serial_errno;
+extern char *serial_errnostr;
+
+typedef struct _serial {
+ /* parameters */
+ const char *device;
+ int baud;
+ int databits;
+ char parity;
+ int stopbits;
+ char xonxoff;
+ char rtscts;
+ float txtimeout;
+ float rxtimeout;
+
+ /* internal variables */
+ int handle;
+ struct termios com_termios;
+ struct termios old_termios;
+} serial_t;
+
+serial_t *serial_open(const char *serial_device, int serial_baud, int serial_databits, char serial_parity, int serial_stopbits, char serial_xonxoff, char serial_rtscts, int serial_getbreak, float serial_txtimeout, float serial_rxtimeout);
+void serial_close(serial_t *serial);
+int serial_read(serial_t *serial, uint8_t *buffer, int size);
+int serial_write(serial_t *serial, uint8_t *buffer, int size);
+int serial_timeout(serial_t *serial, double serial_txtimeout, double serial_rxtimeout);
+int serial_cts(serial_t *serial);
+int serial_dsr(serial_t *serial);
+int serial_dtron(serial_t *serial);
+int serial_dtroff(serial_t *serial);
+int serial_rtson(serial_t *serial);
+int serial_rtsoff(serial_t *serial);
+int serial_break(serial_t *serial, int on);
+int serial_handle(serial_t *serial);
+