aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Touhey <thomas@touhey.fr>2019-04-29 12:23:01 +0200
committerThomas Touhey <thomas@touhey.fr>2019-04-29 12:23:01 +0200
commit751f742fc8b8be0746b54d45822b9351f8079a64 (patch)
tree09ba321b956b27aef6a18a232154fba5cd38f824
parentec1f2954f478f0c0efa2fb614a05d3899ba3a835 (diff)
There seems to be a problem with UNIX-related utilities and their enabling macro…
-rw-r--r--include/libtio/cdefs.h6
-rw-r--r--include/libtio/error.h6
-rw-r--r--include/libtio/io/serial.h12
-rw-r--r--include/libtio/native.h10
-rw-r--r--lib/error.c33
-rw-r--r--lib/serial/builtin/unix_dev.c2
-rw-r--r--lib/serial/builtin/unix_dev_serial.c5
-rw-r--r--lib/serial/list.c51
-rw-r--r--lib/stream/builtin/unix.c194
-rw-r--r--lib/stream/builtin/windows.c27
10 files changed, 303 insertions, 43 deletions
diff --git a/include/libtio/cdefs.h b/include/libtio/cdefs.h
index bcd4509..b896fa7 100644
--- a/include/libtio/cdefs.h
+++ b/include/libtio/cdefs.h
@@ -16,6 +16,9 @@
#ifndef LIBTIO_CDEFS_H
# define LIBTIO_CDEFS_H 20180710
# include "config.h"
+
+# define _POSIX_C_SOURCE 200809L
+
# include <stddef.h>
# include <time.h>
@@ -71,6 +74,9 @@
static TYPE
# define TIO_HOOK(TYPE) \
static TYPE
+
+# define TIO_EXTERN_TYPE(TYPE) \
+ TYPE
# define TIO_HOOK_TYPE(TYPE) \
TYPE
diff --git a/include/libtio/error.h b/include/libtio/error.h
index 6d6a63d..f2a7b9e 100644
--- a/include/libtio/error.h
+++ b/include/libtio/error.h
@@ -20,13 +20,17 @@ typedef int tio_error_t;
* `alloc`: a memory allocation has failed.
* `op`: unsupported operation.
* `arg`: an argument was invalid.
- * `iter`: no more elements in the iterator. */
+ * `iter`: no more elements in the iterator.
+ * `notfound`: error not found.
+ * `access`: access denied. */
# define tio_error_unknown 0x01
# define tio_error_alloc 0x02
# define tio_error_op 0x03
# define tio_error_arg 0x04
# define tio_error_iter 0x05
+# define tio_error_notfound 0x06
+# define tio_error_access 0x07
/* Stream errors.
* `stream`: invalid stream or stream in erroneous state (parent, …).
diff --git a/include/libtio/io/serial.h b/include/libtio/io/serial.h
index d04a7a7..12242f2 100644
--- a/include/libtio/io/serial.h
+++ b/include/libtio/io/serial.h
@@ -101,13 +101,11 @@ struct tio_serial_attrs {
# define TIO_DTRDIS 0x0000
# define TIO_DTRENB 0x0008
-# define TIO_DTRNOHAND 0x0000
-# define TIO_DTRHAND 0x0010
+# define TIO_DTRHAND 0x0018
# define TIO_RTSDIS 0x0000
# define TIO_RTSENB 0x0020
-# define TIO_RTSNOHAND 0x0000
-# define TIO_RTSHAND 0x0040
+# define TIO_RTSHAND 0x0060
/* The XON/XOFF software control settings.
*
@@ -182,8 +180,10 @@ TIO_EXTERN(int) tio_make_serial_speed_in_bauds
OF((unsigned long *tio__bauds, unsigned long tio__speed));
/* List the available serial ports.
- * TODO: platform-agnostic serial port listing function.
- * the iterator yields strings (`char const *`). */
+ * The iterator yields strings (`char const *`) representing the path. */
+
+TIO_EXTERN(int) tio_list_serial_ports
+ OF((tio_iter_t **tio__iterp));
# define tio_next_serial_port(ITER, PTRP) \
(tio_next((ITER), (void **)(char const **)(PTRP)))
diff --git a/include/libtio/native.h b/include/libtio/native.h
index 083a36a..f5600bc 100644
--- a/include/libtio/native.h
+++ b/include/libtio/native.h
@@ -63,8 +63,13 @@ TIO_EXTERN(int) tio_open_stdin
# ifndef LIBTIO_DISABLED_UNIX
-TIO_EXTERN(int) tio_open_unix_fd
+TIO_EXTERN(int) tio_open_unix_file
OF((tio_stream_t **tio__streamp, int tio__fd, int tio__close));
+TIO_EXTERN(int) tio_open_unix_serial
+ OF((tio_stream_t **tio__streamp, int tio__fd, int tio__close));
+
+TIO_EXTERN(int) tio_open_unix_serial_port
+ OF((tio_stream_t **tio__streamp, char const *tio__path));
/* These might not work, but we can try them on UNIX variants as they
* require the unistd.h functions at compile time. */
@@ -88,6 +93,9 @@ TIO_EXTERN(int) tio_open_windows_serial_handle
OF((tio_stream_t **tio__streamp, HANDLE tio__handle,
int tio__cl));
+TIO_EXTERN(int) tio_open_windows_serial_port
+ OF((tio_stream_t **tio__streamp, char const *tio__path));
+
TIO_EXTERN(int) tio_list_windows_serial_ports
OF((tio_iter_t **tio__iterp));
diff --git a/lib/error.c b/lib/error.c
index bad0620..4a37144 100644
--- a/lib/error.c
+++ b/lib/error.c
@@ -6,25 +6,26 @@
#define UNKNOWN NULL, NULL
TIO_LOCAL_DATA(char const *) errors[] = {
- "tio_error_none", "everything is okay",
- "tio_error_unknown", "an unknown error has occurred",
- "tio_error_alloc", "a memory allocation has failed",
- "tio_error_op", "unsupported operation",
- "tio_error_arg", "an argument was invalid",
- "tio_error_iter", "no more elements in an iterator",
+ "tio_error_none", "everything is okay",
+ "tio_error_unknown", "an unknown error has occurred",
+ "tio_error_alloc", "a memory allocation has failed",
+ "tio_error_op", "unsupported operation",
+ "tio_error_arg", "an argument was invalid",
+ "tio_error_iter", "no more elements in an iterator",
+ "tio_error_notfound", "an element wasn't found",
+ "tio_error_access", "not enough privileges to operate",
UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,
UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,
- UNKNOWN, UNKNOWN,
-
- "tio_error_stream", "invalid/erroneous stream",
- "tio_error_read", "a read operation has failed",
- "tio_error_write", "a write operation has failed",
- "tio_error_seek", "a seek operation has failed",
- "tio_error_end", "an end of stream has been reached",
- "tio_error_timeout", "a timeout has occurred",
- "tio_error_scsi", "an SCSI operation has failed",
- "tio_error_usb", "a USB operation has failed"
+
+ "tio_error_stream", "invalid/erroneous stream",
+ "tio_error_read", "a read operation has failed",
+ "tio_error_write", "a write operation has failed",
+ "tio_error_seek", "a seek operation has failed",
+ "tio_error_end", "an end of stream has been reached",
+ "tio_error_timeout", "a timeout has occurred",
+ "tio_error_scsi", "an SCSI operation has failed",
+ "tio_error_usb", "a USB operation has failed"
};
/* ---
diff --git a/lib/serial/builtin/unix_dev.c b/lib/serial/builtin/unix_dev.c
index cd84829..037f425 100644
--- a/lib/serial/builtin/unix_dev.c
+++ b/lib/serial/builtin/unix_dev.c
@@ -142,7 +142,7 @@ TIO_EXTERN(int) tio_list_unix_serial_ports_using_cu_devices(tio_iter_t **iterp)
if (!(cookie->dp = opendir(cookie->path))) {
tio_free(cookie);
- /* TODO: check errno */
+ msg((ll_error, "unknown error %d: %s", errno, strerror(errno)));
return (tio_error_unknown);
}
diff --git a/lib/serial/builtin/unix_dev_serial.c b/lib/serial/builtin/unix_dev_serial.c
index beb4912..c49916d 100644
--- a/lib/serial/builtin/unix_dev_serial.c
+++ b/lib/serial/builtin/unix_dev_serial.c
@@ -139,7 +139,10 @@ TIO_EXTERN(int) tio_list_unix_serial_ports_using_dev_serial(tio_iter_t **iterp)
if (!(cookie->dp = opendir(cookie->path))) {
tio_free(cookie);
- /* TODO: check errno */
+ if (errno == ENOENT)
+ return (tio_error_op);
+
+ msg((ll_error, "unknown error %d: %s", errno, strerror(errno)));
return (tio_error_unknown);
}
diff --git a/lib/serial/list.c b/lib/serial/list.c
new file mode 100644
index 0000000..8b94114
--- /dev/null
+++ b/lib/serial/list.c
@@ -0,0 +1,51 @@
+#include "../internals.h"
+
+/* `spl_candidates`: candidates to serial ports listing.
+ * `spl_last_successful_candidate`: last candidate which returned
+ * a valid iterator. */
+
+typedef TIO_EXTERN_TYPE(int) (*spl_func)
+ OF((tio_iter_t **));
+
+TIO_LOCAL_DATA(spl_func const * const) spl_candidates[] = {
+#ifndef LIBTIO_DISABLED_WINDOWS
+ &tio_list_windows_serial_ports,
+#endif
+
+#ifndef LIBTIO_DISABLED_UNIX
+ &tio_list_unix_serial_ports_using_dev_serial,
+ &tio_list_unix_serial_ports_using_cu_devices,
+#endif
+
+ NULL
+};
+
+TIO_LOCAL_DATA(spl_func const *) spl_last_successful_candidate = 0;
+
+/* `tio_list_serial_ports()`: list the serial ports, in an agnostic way. */
+
+TIO_EXTERN(int) tio_list_serial_ports(tio_iter_t **iterp)
+{
+ int err;
+
+ if (spl_last_successful_candidate) {
+ err = (*spl_last_successful_candidate)(iterp);
+ if (err != tio_error_op)
+ return (err);
+ }
+
+ {
+ spl_func const * const *func;
+
+ for (func = spl_candidates; func; func++) {
+ err = (**func)(iterp);
+ if (err == tio_error_op)
+ continue ;
+
+ spl_last_successful_candidate = *func;
+ return (err);
+ }
+ }
+
+ return (tio_error_op);
+}
diff --git a/lib/stream/builtin/unix.c b/lib/stream/builtin/unix.c
index 1843292..6ea5309 100644
--- a/lib/stream/builtin/unix.c
+++ b/lib/stream/builtin/unix.c
@@ -7,10 +7,73 @@
# include <errno.h>
# include <termios.h>
+/* `unix_get_attrs()`: get the serial attributes on a given file descriptor. */
+
+# define SET_MASK(MASK, VALUE) \
+ { \
+ attrs->tio_serial_attrs_flags &= ~(MASK); \
+ attrs->tio_serial_attrs_flags |= (VALUE); \
+ }
+
+TIO_LOCAL(int) unix_get_attrs(tio_serial_attrs_t *attrs, int fd)
+{
+ struct termios term;
+ unsigned int status;
+ speed_t speed;
+
+ if (tcgetattr(fd, &term) < 0) {
+ msg((ll_error, "could not get termios attributes on fd %d", fd));
+ return (tio_error_arg);
+ }
+
+ /* Decode the speed. */
+
+# define SPEED_UX(BR, TIO) \
+ case BR: attrs->tio_serial_attrs_speed = TIO; break;
+
+ switch ((speed = cfgetispeed(&term))) {
+ SPEED_UX(B1200, TIO_B1200)
+ SPEED_UX(B2400, TIO_B2400)
+ SPEED_UX(B4800, TIO_B4800)
+ SPEED_UX(B9600, TIO_B9600)
+ SPEED_UX(B19200, TIO_B19200)
+ SPEED_UX(B38400, TIO_B38400)
+ SPEED_UX(B57600, TIO_B57600)
+ SPEED_UX(B115200, TIO_B115200)
+
+ default:
+ msg((ll_error, "Unknown speed constant: %lX", (long)speed));
+ return (tio_error_unknown);
+ }
+
+ /* Flags. */
+
+ SET_MASK(TIO_STOMASK, term.c_cflag & CSTOPB ? TIO_STOTWO : TIO_STOONE)
+ SET_MASK(TIO_PARMASK, (term.c_cflag & PARENB ? TIO_PARENB : TIO_PARDIS)
+ ? (TIO_PARENB | (term.c_cflag & PARODD ? TIO_PARODD : TIO_PAREVEN))
+ : TIO_PARDIS)
+ SET_MASK(TIO_XINMASK, term.c_iflag & IXON ? TIO_XINENB : TIO_XINDIS)
+ SET_MASK(TIO_XOUTMASK, term.c_iflag & IXOFF ? TIO_XOUTENB : TIO_XOUTDIS)
+
+ /* Get DTR/RTS status. */
+
+ if (ioctl(fd, TIOCMGET, &status) >= 0)
+ status = 0;
+ SET_MASK(TIO_DTRMASK, (status & TIOCM_DTR)
+ ? (TIO_DTRENB | TIO_DTRHAND) : TIO_DTRDIS)
+ SET_MASK(TIO_RTSMASK, (status & TIOCM_RTS)
+ ? (TIO_RTSENB | TIO_RTSHAND) : TIO_RTSDIS)
+
+ return (tio_ok);
+}
+
/* ---
- * The cookie.
+ * Cookie and callbacks.
* --- */
+/* The cookie definition, containing the file descriptor and
+ * an internal buffer. */
+
# define BUFSIZE 2048
TIO_STRUCT(cookie, cookie_t)
@@ -28,10 +91,6 @@ struct cookie {
unsigned char _buf[BUFSIZE];
};
-/* ---
- * Callbacks.
- * --- */
-
/* `unix_read()`: read from a UNIX stream. */
TIO_HOOK(int) unix_read(cookie_t *cookie, unsigned char *dest,
@@ -204,7 +263,7 @@ TIO_HOOK(int) unix_set_attrs(cookie_t *cookie,
SPEED(TIO_B115200, B115200)
default:
- msg((ll_info, "Speed was unsupported by termios: %u",
+ msg((ll_error, "Speed was unsupported by termios: %u",
settings->tio_serial_attrs_speed));
return (tio_error_op);
}
@@ -260,9 +319,9 @@ TIO_HOOK(int) unix_set_attrs(cookie_t *cookie,
dtrflags = settings->tio_serial_attrs_flags & TIO_DTRMASK;
rtsflags = settings->tio_serial_attrs_flags & TIO_RTSMASK;
- if (dtrflags == TIO_DTRCTL_ENABLE || dtrflags == TIO_DTRCTL_HANDSHAKE)
+ if (dtrflags & TIO_DTRENB)
status |= TIOCM_DTR;
- if (rtsflags == TIO_RTSCTL_ENABLE || rtsflags == TIO_RTSCTL_HANDSHAKE)
+ if (rtsflags & TIO_RTSENB)
status |= TIOCM_RTS;
if (ioctl(fd, TIOCMSET, &status) < 0)
return (tio_error_unknown);
@@ -286,22 +345,37 @@ TIO_HOOK(void) unix_close(cookie_t *cookie)
tio_free(cookie);
}
-/* ---
- * Open the stream.
- * --- */
-
-/* The callbacks. */
+/* Callbacks for a generic stream. */
-TIO_LOCAL_DATA(tio_functions_t const) unix_callbacks = {
+TIO_LOCAL_DATA(tio_functions_t const) unix_functions = {
(tio_close_t *)unix_close,
+
(tio_read_t *)unix_read,
(tio_write_t *)unix_write,
(tio_seek_t *)unix_seek
};
-/* `tio_open_unix_fd()`: open the UNIX stream from a file descriptor. */
+/* Callbacks for a serial stream. */
+
+TIO_LOCAL_DATA(tio_serial_functions_t const) unix_serial_functions = {
+ (tio_close_t *)unix_close,
+
+ (tio_read_t *)unix_read,
+ (tio_write_t *)unix_write,
+ (tio_setattrs_t *)unix_set_attrs,
-TIO_EXTERN(int) tio_open_unix_fd(tio_stream_t **streamp, int fd, int cl)
+ NULL,
+ NULL,
+ NULL
+};
+
+/* ---
+ * Open the stream.
+ * --- */
+
+/* `tio_open_unix_file()`: open the UNIX stream from a file descriptor. */
+
+TIO_EXTERN(int) tio_open_unix_file(tio_stream_t **streamp, int fd, int cl)
{
cookie_t *cookie = NULL;
unsigned int mode = TIO_OPENFLAG_READ | TIO_OPENFLAG_WRITE
@@ -352,11 +426,97 @@ TIO_EXTERN(int) tio_open_unix_fd(tio_stream_t **streamp, int fd, int cl)
/* Final call. */
- return (tio_open(streamp, mode, cookie, &unix_callbacks, 0));
+ return (tio_open(streamp, mode, cookie, &unix_functions, 0));
fail:
if (fd >= 0 && cl)
close(fd);
return (err);
}
+/* `tio_open_unix_serial()`: open a serial stream using a file descriptor
+ * representing a serial port. */
+
+TIO_EXTERN(int) tio_open_unix_serial(tio_stream_t **streamp,
+ int fd, int cl)
+{
+ cookie_t *cookie = NULL;
+ int err;
+
+ /* Check if the device is valid. */
+
+ if (fd < 0) {
+ err = tio_error_arg;
+ goto fail;
+ }
+ if (read(fd, NULL, 0) < 0) {
+ err = tio_error_read;
+ goto fail;
+ }
+ if (write(fd, NULL, 0) < 0) {
+ err = tio_error_write;
+ goto fail;
+ }
+
+ /* Get the initial serial attributes. */
+
+ if ((err = unix_get_attrs(&attrs, fd)))
+ goto fail;
+
+ /* Allocate cookie. */
+
+ if (!(cookie = tio_alloc(1, sizeof(cookie_t)))) {
+ err = tio_error_alloc;
+ goto fail;
+ }
+
+ cookie->_fd = fd;
+ cookie->_cl = cl;
+ cookie->_to = -1;
+ cookie->_str = 0;
+ cookie->_end = -1;
+
+ /* Initialize for real. */
+
+ msg((ll_info, "Initializing UNIX stream with fd %d", fd));
+
+ /* Final call. */
+
+ return (tio_open(streamp, TIO_OPENFLAG_SERIAL_READ
+ | TIO_OPENFLAG_SERIAL_WRITE | TIO_OPENFLAG_SERIAL_SETATTRS,
+ cookie, &unix_serial_functions, 0));
+fail:
+ if (fd >= 0 && cl)
+ close(fd);
+ return (err);
+}
+
+/* `tio_open_unix_serial_port()`: open a serial port using
+ * a serial port path. */
+
+TIO_EXTERN(int) tio_open_unix_serial_port(tio_stream_t **streamp,
+ char const *path)
+{
+ int fd;
+
+ fd = open(path, O_NOCTTY | O_RDWR);
+ if (fd < 0) switch (errno) {
+ case ENODEV: case ENOENT: case ENXIO:
+ case EPIPE: case ESPIPE:
+ msg((ll_error, "couldn't open serial device: %s",
+ strerror(errno)));
+ return (tio_error_notfound);
+
+ case EACCES:
+ msg((ll_error, "permission denied"));
+ return (tio_error_notfound);
+
+ default:
+ msg((ll_error, "unknown error: %s (0x%02X)",
+ strerror(errno), errno));
+ return (tio_error_unknown);
+ }
+
+ return (tio_open_unix_serial(streamp, fd));
+}
+
#endif
diff --git a/lib/stream/builtin/windows.c b/lib/stream/builtin/windows.c
index f142adc..b0f3cb4 100644
--- a/lib/stream/builtin/windows.c
+++ b/lib/stream/builtin/windows.c
@@ -568,4 +568,31 @@ fail:
return (err);
}
+/* `tio_open_windows_serial_port()`: open a serial port using the path. */
+
+TIO_EXTERN(int) tio_open_windows_serial_port(tio_stream_t **streamp,
+ char const *path)
+{
+ HANDLE handle = INVALID_HANDLE_VALUE;
+
+ /* Open the file handle - my god, this function is so complex. */
+
+ handle = CreateFile(path, GENERIC_READ | GENERIC_WRITE, 0, NULL,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (handle == INVALID_HANDLE_VALUE) switch ((werr = GetLastError())) {
+ case ERROR_FILE_NOT_FOUND:
+ case ERROR_DEV_NOT_EXIST:
+ return (tio_error_notfound);
+
+ case ERROR_ACCESS_DENIED:
+ return (tio_error_access);
+
+ default:
+ win_log_error("CreateFile", werr);
+ return (tio_error_unknown);
+ }
+
+ return (tio_open_windows_serial_handle(streamp, handle, 1));
+}
+
#endif