aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/devel.rst4
-rw-r--r--docs/user.rst4
-rw-r--r--docs/user/streams.rst4
-rw-r--r--include/libtio.h3
-rw-r--r--include/libtio/chrono.h33
-rw-r--r--include/libtio/endian.h108
-rw-r--r--include/libtio/error.h7
-rw-r--r--include/libtio/fs.h67
-rw-r--r--include/libtio/integers.h96
-rw-r--r--include/libtio/io/scsi.h3
-rw-r--r--include/libtio/io/serial.h28
-rw-r--r--include/libtio/io/usb.h7
-rw-r--r--include/libtio/iter.h6
-rw-r--r--include/libtio/native.h80
-rw-r--r--include/libtio/stream.h12
-rw-r--r--include/libtio/system.h101
-rw-r--r--lib/chrono/internals.h16
-rw-r--r--lib/chrono/sleep.c62
-rw-r--r--lib/chrono/timer.c101
-rw-r--r--lib/endian/endian.c167
-rw-r--r--lib/endian/internals.h6
-rw-r--r--lib/error/internals.h8
-rw-r--r--lib/error/iter.c56
-rw-r--r--lib/error/names.c (renamed from lib/error.c)5
-rw-r--r--lib/internals.h20
-rw-r--r--lib/iter.c6
-rw-r--r--lib/misc/alloc.c66
-rw-r--r--lib/misc/libusb.c40
-rw-r--r--lib/serial/builtin/unix_dev.c155
-rw-r--r--lib/serial/builtin/unix_dev_serial.c158
-rw-r--r--lib/serial/list.c24
-rw-r--r--lib/stream/builtin/bulk_only.c2
-rw-r--r--lib/stream/native/serial.c23
-rw-r--r--lib/stream/native/usb.c19
-rw-r--r--lib/stream/usb.c3
-rw-r--r--lib/system/internals.h26
-rw-r--r--lib/system/libusb/internals.h24
-rw-r--r--lib/system/libusb/list.c (renamed from lib/usb/builtin/libusb.c)17
-rw-r--r--lib/system/libusb/open.c43
-rw-r--r--lib/system/libusb/stream.c (renamed from lib/stream/builtin/libusb.c)24
-rw-r--r--lib/system/open.c66
-rw-r--r--lib/system/stdio/internals.h25
-rw-r--r--lib/system/stdio/stream.c (renamed from lib/stream/builtin/std.c)22
-rw-r--r--lib/system/unix/internals.h33
-rw-r--r--lib/system/unix/list_serial.c242
-rw-r--r--lib/system/unix/open.c35
-rw-r--r--lib/system/unix/stream.c (renamed from lib/stream/builtin/unix.c)50
-rw-r--r--lib/system/unix/timer.c57
-rw-r--r--lib/system/unix/utils.c22
-rw-r--r--lib/system/windows/internals.h30
-rw-r--r--lib/system/windows/list_serial.c (renamed from lib/serial/builtin/windows.c)31
-rw-r--r--lib/system/windows/open.c23
-rw-r--r--lib/system/windows/sleep.c13
-rw-r--r--lib/system/windows/stream.c (renamed from lib/stream/builtin/windows.c)32
-rw-r--r--lib/system/windows/utils.c22
-rw-r--r--lib/usb/list.c19
56 files changed, 1495 insertions, 861 deletions
diff --git a/docs/devel.rst b/docs/devel.rst
index 97d8e31..0781c38 100644
--- a/docs/devel.rst
+++ b/docs/devel.rst
@@ -1,5 +1,5 @@
-Developer documentation
-=======================
+Library developer documentation
+===============================
You've read :ref:`user` and want to contribute the
project? You're very welcome! This chapter regroups everything you need to
diff --git a/docs/user.rst b/docs/user.rst
index a088e52..cbc660c 100644
--- a/docs/user.rst
+++ b/docs/user.rst
@@ -1,7 +1,7 @@
.. _user:
-User documentation
-==================
+Library user documentation
+==========================
This chapter describes the library interface and concepts, which library
developers must also know in order to contribute to the project.
diff --git a/docs/user/streams.rst b/docs/user/streams.rst
index f80f4cc..2cc0254 100644
--- a/docs/user/streams.rst
+++ b/docs/user/streams.rst
@@ -141,7 +141,7 @@ Reading and writing to a stream
These functions both work for generic and serial streams.
-.. c:function:: int tio_set_timeouts(tio_stream_t *stream,
+.. c:function:: int tio_set_timeouts(tio_stream_t *stream, \
tio_timeouts_t const *read_timeouts, tio_timeouts_t const *write_timeouts)
Set the stream timeouts for read and write operations.
@@ -266,7 +266,7 @@ Using an SCSI stream
The following functions ought to be used with serial streams:
-.. c:function:: int tio_scsi_request(tio_stream_t *stream,
+.. c:function:: int tio_scsi_request(tio_stream_t *stream, \
tio_scsi_request_t *request)
Send a SCSI request and get answers.
diff --git a/include/libtio.h b/include/libtio.h
index c71c539..52071c2 100644
--- a/include/libtio.h
+++ b/include/libtio.h
@@ -2,6 +2,8 @@
# define LIBTIO_H 20180710
# include "libtio/cdefs.h"
+# include "libtio/integers.h"
+# include "libtio/endian.h"
# include "libtio/error.h"
# include "libtio/log.h"
@@ -9,6 +11,7 @@
# include "libtio/stream.h"
# include "libtio/chrono.h"
# include "libtio/mutex.h"
+# include "libtio/system.h"
/* Define what is required to use the library facilities. */
diff --git a/include/libtio/chrono.h b/include/libtio/chrono.h
index 71dd96a..19c51ba 100644
--- a/include/libtio/chrono.h
+++ b/include/libtio/chrono.h
@@ -6,20 +6,20 @@
TIO_BEGIN_NAMESPACE
TIO_STRUCT(tio_timer, tio_timer_t)
+TIO_STRUCT(tio_timer_functions, tio_timer_functions_t)
/* Callbacks for timers. */
-typedef TIO_HOOK_TYPE(int) tio_get_timer_t
- OF((tio_timer_t **tio__timer));
typedef TIO_HOOK_TYPE(void) tio_free_timer_t
- OF((tio_timer_t *tio__timer));
+ OF((void *tio__cookie));
typedef TIO_HOOK_TYPE(int) tio_get_spent_time_t
- OF((tio_timer_t *tio__timer, unsigned long *tio__spent));
+ OF((void *tio__cookie, unsigned long *tio__spent));
-/* Callback for sleep. */
+struct tio_timer_functions {
+ tio_free_timer_t *tio_timer_functions_free;
-typedef TIO_HOOK_TYPE(int) tio_sleep_t
- OF((unsigned long tio__ms));
+ tio_get_spent_time_t *tio_timer_functions_get_spent_time;
+};
/* ---
* Public functions.
@@ -27,31 +27,20 @@ typedef TIO_HOOK_TYPE(int) tio_sleep_t
TIO_BEGIN_DECLS
-/* Sleep. */
+/* Create a timer. */
-TIO_EXTERN(int) tio_sleep
- OF((unsigned long tio__ms));
-TIO_EXTERN(void) tio_set_sleep_func
- OF((tio_sleep_t *tio__func));
+TIO_EXTERN(int) tio_open_timer
+ OF((tio_timer_t **tio__timerp, void *tio__cookie,
+ tio_timer_functions_t const *tio__functions));
/* Timers are there to manage spent time on an operation to measure
* the time operations can take and identify bottlenecks. */
-TIO_EXTERN(int) tio_get_timer
- OF((tio_timer_t **tio__timer));
-
#define tio_free_timer(TIMER) tio_free(TIMER)
TIO_EXTERN(int) tio_get_spent_time
OF((tio_timer_t *tio__timer, unsigned long *tio__spent));
-/* You can change these functions too! */
-
-TIO_EXTERN(int) tio_set_timer_funcs
- OF((tio_get_timer_t *tio__get_timer,
- tio_free_timer_t *tio__free_timer,
- tio_get_spent_time_t *tio__get_spent_time));
-
TIO_END_DECLS
TIO_END_NAMESPACE
diff --git a/include/libtio/endian.h b/include/libtio/endian.h
new file mode 100644
index 0000000..a168185
--- /dev/null
+++ b/include/libtio/endian.h
@@ -0,0 +1,108 @@
+#ifndef LIBTIO_ENDIAN_H
+# define LIBTIO_ENDIAN_H 20190606
+# include "cdefs.h"
+# include "integers.h"
+
+/* These function always exist. They are the default ones, if the platform
+ * does not have any equivalent function (or has one but indicates that
+ * fact badly). */
+
+TIO_EXTERN(tio_uint16_t) tio_be16toh
+ OF((tio_uint16_t tio__x));
+TIO_EXTERN(tio_uint16_t) tio_le16toh
+ OF((tio_uint16_t tio__x));
+TIO_EXTERN(tio_uint32_t) tio_be32toh
+ OF((tio_uint32_t tio__x));
+TIO_EXTERN(tio_uint32_t) tio_le32toh
+ OF((tio_uint32_t tio__x));
+
+TIO_EXTERN(tio_uint16_t) tio_htobe16
+ OF((tio_uint16_t tio__x));
+TIO_EXTERN(tio_uint16_t) tio_htole16
+ OF((tio_uint16_t tio__x));
+TIO_EXTERN(tio_uint32_t) tio_htobe32
+ OF((tio_uint32_t tio__x));
+TIO_EXTERN(tio_uint32_t) tio_htole32
+ OF((tio_uint32_t tio__x));
+
+# if defined(__APPLE__)
+# include <libkern/OSByteOrder.h>
+
+# define tio_int_be16toh(TIO__X) OSSwapBigToHostInt16(TIO__X)
+# define tio_int_le16toh(TIO__X) OSSwapLittleToHostInt16(TIO__X)
+# define tio_int_be32toh(TIO__X) OSSwapBigToHostInt32(TIO__X)
+# define tio_int_le32toh(TIO__X) OSSwapLittleToHostInt32(TIO__X)
+
+# define tio_int_htobe16(TIO__X) OSSwapHostToBigInt16(TIO__X)
+# define tio_int_htole16(TIO__X) OSSwapHostToLittleInt16(TIO__X)
+# define tio_int_htobe32(TIO__X) OSSwapHostToBigInt32(TIO__X)
+# define tio_int_htole32(TIO__X) OSSwapHostToLittleInt32(TIO__X)
+
+# elif defined(__OpenBSD__)
+# include <sys/endian.h>
+# define LIBTIO_ENDIAN_DEFINED
+
+# elif defined(_WIN16) || defined(_WIN32) || defined(_WIN64) \
+ || defined(__WINDOWS__)
+# include <winsock2.h>
+# include <sys/param.h>
+
+# if BYTE_ORDER == LITTLE_ENDIAN
+# define tio_int_be16toh(TIO__X) ntohs(TIO__X)
+# define tio_int_le16toh(TIO__X) (TIO__X)
+# define tio_int_be32toh(TIO__X) ntohl(TIO__X)
+# define tio_int_le32toh(TIO__X) (TIO__X)
+
+# define tio_int_htobe16(TIO__X) htons(TIO__X)
+# define tio_int_htole16(TIO__X) (TIO__X)
+# define tio_int_htobe32(TIO__X) htonl(TIO__X)
+# define tio_int_htole32(TIO__X) (TIO__X)
+# else
+# define tio_int_be16toh(TIO__X) (TIO__X)
+# define tio_int_le16toh(TIO__X) ntohs(TIO__X)
+# define tio_int_be32toh(TIO__X) (TIO__X)
+# define tio_int_le32toh(TIO__X) ntohl(TIO__X)
+
+# define tio_int_htobe16(TIO__X) (TIO__X)
+# define tio_int_htole16(TIO__X) htons(TIO__X)
+# define tio_int_htobe32(TIO__X) (TIO__X)
+# define tio_int_htole32(TIO__X) htonl(TIO__X)
+# endif
+
+# elif defined(__GLIBC__) && defined(__USE_MISC)
+# include <endian.h>
+# define LIBTIO_ENDIAN_DEFINED
+
+# endif
+
+/* *e*toh, hto*e* macros are already defined, just make `tio_` aliases. */
+
+# ifdef LIBTIO_ENDIAN_DEFINED
+# define tio_int_be16toh(TIO__X) be16toh(TIO__X)
+# define tio_int_le16toh(TIO__X) le16toh(TIO__X)
+# define tio_int_be32toh(TIO__X) be32toh(TIO__X)
+# define tio_int_le32toh(TIO__X) le32toh(TIO__X)
+
+# define tio_int_htobe16(TIO__X) htobe16(TIO__X)
+# define tio_int_htole16(TIO__X) htole16(TIO__X)
+# define tio_int_htobe32(TIO__X) htobe32(TIO__X)
+# define tio_int_htole32(TIO__X) htole32(TIO__X)
+# endif
+
+/* If we aren't including this from libcasio's endian source functions,
+ * `LIBTIO_NO_ENDIAN` should not be defined. Otherwise, as we will be
+ * defining the "dynamic" symbols, do not define the functions. */
+
+# if !defined(LIBTIO_NO_ENDIAN) && defined(tio_int_be16toh)
+# define tio_be16toh(TIO__X) tio_int_be16toh(TIO__X)
+# define tio_le16toh(TIO__X) tio_int_le16toh(TIO__X)
+# define tio_be32toh(TIO__X) tio_int_be32toh(TIO__X)
+# define tio_le32toh(TIO__X) tio_int_le32toh(TIO__X)
+
+# define tio_htobe16(TIO__X) tio_int_htobe16(TIO__X)
+# define tio_htole16(TIO__X) tio_int_htole16(TIO__X)
+# define tio_htobe32(TIO__X) tio_int_htobe32(TIO__X)
+# define tio_htole32(TIO__X) tio_int_htole32(TIO__X)
+# endif
+
+#endif /* LIBTIO_ENDIAN_H */
diff --git a/include/libtio/error.h b/include/libtio/error.h
index c81f300..67856d6 100644
--- a/include/libtio/error.h
+++ b/include/libtio/error.h
@@ -1,6 +1,7 @@
#ifndef LIBTIO_ERROR_H
# define LIBTIO_ERROR_H 20180710
# include "cdefs.h"
+# include "iter.h"
TIO_BEGIN_NAMESPACE
@@ -66,6 +67,12 @@ TIO_EXTERN(char const *) tio_error_name
TIO_EXTERN(char const *) tio_error_desc
OF((int tio__code));
+TIO_EXTERN(int) tio_list_errors
+ OF((tio_iter_t **tio__iterp));
+
+# define tio_next_error(ITER, ERRNUMP) \
+ (tio_next((ITER), (void **)(int **)(ERRNUMP)))
+
TIO_END_DECLS
TIO_END_NAMESPACE
diff --git a/include/libtio/fs.h b/include/libtio/fs.h
index 2b4281e..e3c3c32 100644
--- a/include/libtio/fs.h
+++ b/include/libtio/fs.h
@@ -4,6 +4,7 @@
# include "stream.h"
TIO_BEGIN_NAMESPACE
+TIO_STRUCT(tio_fs, tio_fs_t)
TIO_STRUCT(tio_fs_functions, tio_fs_functions_t)
TIO_STRUCT(tio_fs_create_info, tio_fs_create_info_t)
TIO_STRUCT(tio_path, tio_path_t)
@@ -56,15 +57,37 @@ typedef TIO_HOOK_TYPE(int) tio_fs_move_t
tio_path_t const *tio__destpath));
typedef TIO_HOOK_TYPE(int) tio_fs_stat_t
- OF((void *tio__cookie, tio_stat_t *tio__stat, unsigned long tio__flags));
+ OF((void *tio__cookie, tio_stat_t *tio__stat,
+ unsigned long tio__flags));
typedef TIO_HOOK_TYPE(int) tio_fs_open_t
- OF((void *tio__cookie, tio_path_t *tio__path, unsigned long tio__flags));
+ OF((void *tio__cookie, tio_path_t *tio__path,
+ unsigned long tio__flags));
typedef TIO_HOOK_TYPE(int) tio_fs_list_t
- OF((void *tio__cookie, tio_iter_t **tio__iterp, tio_path_t *tio__path));
+ OF((void *tio__cookie, tio_iter_t **tio__iterp,
+ tio_path_t *tio__path));
+
+# define TIO_FSFLAG_CREATE 1
+# define TIO_FSFLAG_REMOVE 2
+# define TIO_FSFLAG_MOVE 4
+# define TIO_FSFLAG_LIST 8
+# define TIO_FSFLAG_STAT 16
+# define TIO_FSFLAG_OPEN 32
struct tio_fs_functions {
+ tio_fs_close_t *tio_fs_functions_close;
+
+ /* Directory interactions. */
+
+ tio_fs_create_t *tio_fs_functions_create;
+ tio_fs_remove_t *tio_fs_functions_remove;
+ tio_fs_move_t *tio_fs_functions_move;
+ tio_fs_list_t *tio_fs_functions_list;
+
+ /* File interactions. */
+ tio_fs_stat_t *tio_fs_functions_stat;
+ tio_fs_open_t *tio_fs_functions_open;
};
/* ---
@@ -86,13 +109,45 @@ TIO_EXTERN(int) tio_set_path_child
TIO_EXTERN(int) tio_set_path_to_parent
OF((tio_path_t **tio__pathp));
-TIO_EXTERN(int) tio_free_path
- OF((tio_path_t *tio__path));
+# define tio_free_path(PATH) tio_free(PATH)
TIO_EXTERN(int) tio_get_path_name
- OF((tio_path_t *tio__path, void **tio__namep, size_t *tio__name_sizep));
+ OF((tio_path_t *tio__path, void **tio__namep,
+ size_t *tio__name_sizep));
+
+/* Filesystem management. */
+
+TIO_EXTERN(int) tio_create
+ OF((tio_fs_t *tio__fs, tio_path_t *tio__path,
+ tio_filetype_t tio__ftyp, ...));
+TIO_EXTERN(int) tio_remove
+ OF((tio_fs_t *tio__fs, tio_path_t *tio__path));
+TIO_EXTERN(int) tio_move
+ OF((tio_fs_t *tio__fs, tio_path_t const *tio__path,
+ tio_path_t const *tio__destpath));
+
+TIO_EXTERN(int) tio_stat
+ OF((tio_fs_t *tio__fs, tio_stat_t *tio__stat,
+ unsigned long tio__flags));
+TIO_EXTERN(int) tio_open
+ OF((tio_fs_t *tio__fs, tio_stream_t **tio__streamp,
+ tio_path_t const *tio__path, unsigned long tio__flags));
+
+TIO_EXTERN(int) tio_list
+ OF((tio_fs_t *tio__fs, tio_iter_t **tio__
+
+/* Get a native filesystem. */
+# define tio_next_fs(ITER, FSNAMEP) \
+ tio_next((ITER), (void **)(char const **)(FSNAMEP))
+TIO_EXTERN(int) tio_list_fs
+ OF((tio_iter_t **tio__iterp));
+TIO_EXTERN(int) tio_get_fs
+ OF((tio_fs_t **tio__fsp, char const *tio__name));
+TIO_EXTERN(int) tio_get_fs_folder
+ OF((tio_fs_t **tio__fsp, tio_fs_t *tio__fs,
+ tio_path_t *tio__foldpath));
TIO_END_DECLS
TIO_END_NAMESPACE
diff --git a/include/libtio/integers.h b/include/libtio/integers.h
new file mode 100644
index 0000000..87bcd33
--- /dev/null
+++ b/include/libtio/integers.h
@@ -0,0 +1,96 @@
+#ifndef LIBTIO_INTEGERS_H
+# define LIBTIO_INTEGERS_H 20190606
+# include "cdefs.h"
+
+TIO_BEGIN_NAMESPACE
+
+# if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+# include <stdint.h>
+# include <inttypes.h>
+
+/* `stdint.h` and `inttypes.h` are standard C99 headers.
+ * `stdint.h` provides the `uintN_t` types, and
+ * `inttypes.h` provides the `PRI[uxX]N` macros. */
+
+typedef uint8_t tio_uint8_t;
+typedef uint16_t tio_uint16_t;
+typedef uint32_t tio_uint32_t;
+
+# define TIO_PRIu8 PRIu8
+# define TIO_PRIx8 PRIx8
+# define TIO_PRIX8 PRIX8
+# define TIO_PRIu16 PRIu16
+# define TIO_PRIx16 PRIx16
+# define TIO_PRIX16 PRIX16
+# define TIO_PRIu32 PRIu32
+# define TIO_PRIx32 PRIx32
+# define TIO_PRIX32 PRIX32
+
+# else /* C89 */
+# include <limits.h>
+
+/* Here, we ought to do some C89 hacking.
+ * We'll use the `limits.h` definitions to try and guess which one of the
+ * default types are the 8-bit, 16-bit and 32-bit integer. */
+
+# define TIO_P8 "hh"
+typedef unsigned char tio_uint8_t;
+
+/* 16-bit integer. */
+
+# if (USHRT_MAX > 0xffffUL)
+# error "No 16-bit type, exiting!"
+# endif
+# define TIO_P16 "h"
+typedef unsigned short tio_uint16_t;
+
+/* 32-bit integer. */
+
+# if (UINT_MAX == 0xffffffffUL)
+# define TIO_P32 ""
+typedef unsigned int tio_uint32_t;
+# elif (ULONG_MAX == 0xffffffffUL)
+# define TIO_P32 "l"
+typedef unsigned long tio_uint32_t;
+# else
+
+/* There is nothing between `char` and `short`, and `char` is always
+ * byte-wide;
+ *
+ * `long long` is not defined in C89, and even if it can be used as a
+ * compiler extension for C89, it is supposed to be 64-bit or more.
+ * So basically we're running out of options here. */
+
+# error "No 32-bit type, exiting!"
+# endif
+
+# define TIO_PRIu8 TIO_P8 "u"
+# define TIO_PRIx8 TIO_P8 "x"
+# define TIO_PRIX8 TIO_P8 "X"
+# define TIO_PRIu16 TIO_P16 "u"
+# define TIO_PRIx16 TIO_P16 "x"
+# define TIO_PRIX16 TIO_P16 "X"
+# define TIO_PRIu32 TIO_P32 "u"
+# define TIO_PRIx32 TIO_P32 "x"
+# define TIO_PRIX32 TIO_P32 "X"
+# endif
+
+/* printf thing for `size_t` */
+
+# if defined(_WIN64)
+# define TIO_PRIuSIZE "l64u"
+# define TIO_PRIxSIZE "l64x"
+# define TIO_PRIXSIZE "l64X"
+# elif defined(_WIN32)
+# define TIO_PRIuSIZE "u"
+# define TIO_PRIxSIZE "x"
+# define TIO_PRIXSIZE "X"
+# else
+# define TIO_PRIuSIZE "zu"
+# define TIO_PRIxSIZE "zx"
+# define TIO_PRIXSIZE "zX"
+# endif
+
+TIO_END_NAMESPACE
+
+#endif /* LIBTIO_INTEGERS_H */
diff --git a/include/libtio/io/scsi.h b/include/libtio/io/scsi.h
index fd9cd7e..a00f109 100644
--- a/include/libtio/io/scsi.h
+++ b/include/libtio/io/scsi.h
@@ -5,7 +5,8 @@
TIO_BEGIN_NAMESPACE
/* An SCSI stream serves for interacting with an SCSI-enabled device.
- * Using such a stream, you can send an SCSI request and receive the answer.
+ * Using such a stream, you can send an SCSI request and receive the
+ * answer.
*
* An SCSI request can be followed with data in two directions: to the
* device and from the device:
diff --git a/include/libtio/io/serial.h b/include/libtio/io/serial.h
index b7d4aa1..e4cf055 100644
--- a/include/libtio/io/serial.h
+++ b/include/libtio/io/serial.h
@@ -27,14 +27,18 @@ struct tio_serial_attrs {
};
/* Here are the control characters you can define:
- * `TIO_XON`: the XON character to re-enable transmission (software control);
- * `TIO_XOFF`: the XOFF charater to disable transmission (software control). */
+ *
+ * `TIO_XON`: the XON character to re-enable transmission
+ * (software control).
+ * `TIO_XOFF`: the XOFF charater to disable transmission
+ * (software control). */
# define TIO_XON 0
# define TIO_XOFF 1
-/* Among the flags, you can find various things. First of all, the stop bits
- * settings (1 or 2):
+/* Among the flags, you can find various things. First of all, the stop
+ * bits settings (1 or 2):
+ *
* `TIO_STOONE`: 1 stop bit;
* `TIO_STOTWO`: 2 stop bits.
*
@@ -91,10 +95,11 @@ struct tio_serial_attrs {
/* The XON/XOFF software control settings.
*
- * XOFF disables the transmission temporarily, usually because the device at
- * the other end can't manage so much data at once, whereas XON re-enables the
- * transmission, probably because the device at the other end has finished
- * processing the data you sent it and is ready to process some more.
+ * XOFF disables the transmission temporarily, usually because the device
+ * at the other end can't manage so much data at once, whereas XON
+ * re-enables the transmission, probably because the device at the other
+ * end has finished processing the data you sent it and is ready to process
+ * some more.
*
* XON/XOFF software flow control can be enabled on input (XIN) and
* output (XOFF). The XON and XOFF characters are common to both
@@ -159,10 +164,9 @@ TIO_EXTERN(int) tio_make_serial_attrs
unsigned long tio__flags));
/* List the available serial ports.
- * The iterator yields strings (`char const *`) representing the path. */
-
-TIO_EXTERN(int) tio_list_serial_ports
- OF((tio_iter_t **tio__iterp));
+ * The iterator yields strings (`char const *`) representing the path.
+ *
+ * Use `tio_list_serial_ports(tio_iter_t **, tio_system_t *)`. */
# define tio_next_serial_port(ITER, PTRP) \
(tio_next((ITER), (void **)(char const **)(PTRP)))
diff --git a/include/libtio/io/usb.h b/include/libtio/io/usb.h
index aed26a9..c18e612 100644
--- a/include/libtio/io/usb.h
+++ b/include/libtio/io/usb.h
@@ -38,10 +38,9 @@ struct tio_usb_device {
TIO_BEGIN_DECLS
/* List the available USB devices.
- * The iterator yields strings (`char const *`) representing the path. */
-
-TIO_EXTERN(int) tio_list_usb_devices
- OF((tio_iter_t **tio__iterp));
+ * The iterator yields strings (`char const *`) representing the path.
+ *
+ * Use `tio_list_usb_devices(tio_iter_t **iterp, tio_system_t *system)` */
# define tio_next_usb_device(ITER, PTRP) \
(tio_next((ITER), (void **)(tio_usb_device_t **)(PTRP)))
diff --git a/include/libtio/iter.h b/include/libtio/iter.h
index 31d1133..6a212ff 100644
--- a/include/libtio/iter.h
+++ b/include/libtio/iter.h
@@ -7,10 +7,8 @@ TIO_BEGIN_NAMESPACE
/* A few things in libtio work using iterators. This is the centralized
* iterator interface. */
-struct tio_iter;
-typedef struct tio_iter tio_iter_t;
-struct tio_iter_functions;
-typedef struct tio_iter_functions tio_iter_functions_t;
+TIO_STRUCT(tio_iter, tio_iter_t)
+TIO_STRUCT(tio_iter_functions, tio_iter_functions_t)
/* ---
* Define something.
diff --git a/include/libtio/native.h b/include/libtio/native.h
index 4a005ad..2faba26 100644
--- a/include/libtio/native.h
+++ b/include/libtio/native.h
@@ -39,86 +39,6 @@ TIO_BEGIN_DECLS
# define LIBTIO_DISABLED_MACOS 1
# endif
-/* ---
- * Native stream opening functions.
- * --- */
-
-/* FILE streams. */
-
-# ifndef LIBTIO_DISABLED_FILE
-# include <stdio.h>
-
-TIO_EXTERN(int) tio_open_std
- OF((tio_stream_t **tio__stream,
- FILE *tio__fl, int tio__close));
-
-TIO_EXTERN(int) tio_open_stdout
- OF((tio_stream_t **tio__stream));
-TIO_EXTERN(int) tio_open_stderr
- OF((tio_stream_t **tio__stream));
-TIO_EXTERN(int) tio_open_stdin
- OF((tio_stream_t **tio__stream));
-
-# endif
-
-/* UNIX-specific streams and listings. */
-
-# ifndef LIBTIO_DISABLED_UNIX
-
-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. */
-
-TIO_EXTERN(int) tio_list_unix_serial_ports_using_dev_serial
- OF((tio_iter_t **tio__iterp));
-TIO_EXTERN(int) tio_list_unix_serial_ports_using_cu_devices
- OF((tio_iter_t **tio__iterp));
-
-# endif
-
-/* MS-Windows specific streams and port/device listing. */
-
-# ifndef LIBTIO_DISABLED_WINDOWS
-# include <windows.h>
-
-TIO_EXTERN(int) tio_open_windows_file_handle
- OF((tio_stream_t **tio__streamp, HANDLE tio__handle,
- int tio__cl));
-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));
-
-# endif
-
-/* libusb stream. */
-
-# ifndef LIBTIO_DISABLED_LIBUSB
-# include <libusb.h>
-
-TIO_EXTERN(int) tio_open_libusb
- OF((tio_stream_t **tio__streamp, int tio__bus, int tio__addr));
-TIO_EXTERN(int) tio_open_libusb_device
- OF((tio_stream_t **tio__streamp, libusb_device *tio__device,
- int tio__deref));
-
-TIO_EXTERN(int) tio_list_libusb_devices
- OF((tio_iter_t **tio__iterp));
-
-# endif
-
TIO_END_DECLS
TIO_END_NAMESPACE
diff --git a/include/libtio/stream.h b/include/libtio/stream.h
index ffa3333..8b3357e 100644
--- a/include/libtio/stream.h
+++ b/include/libtio/stream.h
@@ -36,7 +36,8 @@ struct tio_timeouts {
* - before the first block.
* - between blocks.
*
- * All timeouts are in microseconds, and considered only if non zero. */
+ * All timeouts are in microseconds, and considered only if non
+ * zero. */
unsigned long tio_timeouts_total;
unsigned long tio_timeouts_blocks;
@@ -301,15 +302,6 @@ TIO_EXTERN(int) tio_open_limited
TIO_EXTERN(int) tio_empty_limited
OF((tio_stream_t *tio__stream));
-/* Open a native serial or USB stream. */
-
-TIO_EXTERN(int) tio_open_native_serial
- OF((tio_stream_t **tio__streamp,
- char const *tio__path));
-TIO_EXTERN(int) tio_open_native_usb
- OF((tio_stream_t **tio__streamp,
- int tio__bus, int tio__addr));
-
/* Make a generic stream over USB using bulk-only transport. */
TIO_EXTERN(int) tio_open_bulk_usb_over_stream
diff --git a/include/libtio/system.h b/include/libtio/system.h
new file mode 100644
index 0000000..ecc5a5b
--- /dev/null
+++ b/include/libtio/system.h
@@ -0,0 +1,101 @@
+#ifndef TIO_SYSTEM_H
+# define TIO_SYSTEM_H 20190907
+# include "cdefs.h"
+# include "stream.h"
+
+TIO_BEGIN_NAMESPACE
+
+/* libtio uses a system as an abstraction. */
+
+TIO_STRUCT(tio_system, tio_system_t)
+TIO_STRUCT(tio_system_functions, tio_system_functions_t)
+
+# define TIO_STDSTREAM_IN 0
+# define TIO_STDSTREAM_OUT 1
+# define TIO_STDSTREAM_ERR 2
+
+/* Callbacks.
+ * Uses `tio_close_t` from stream callbacks. */
+
+typedef TIO_HOOK_TYPE(int) tio_open_stdstream_t
+ OF((void *tio__cookie, tio_stream_t **tio__stream, int tio__type));
+
+typedef TIO_HOOK_TYPE(int) tio_open_usb_stream_t
+ OF((void *tio__cookie, tio_stream_t **tio__stream, int tio__bus,
+ int tio__addr));
+typedef TIO_HOOK_TYPE(int) tio_list_usb_devices_t
+ OF((void *tio__cookie, tio_iter_t **tio__iter));
+
+typedef TIO_HOOK_TYPE(int) tio_open_serial_stream_t
+ OF((void *tio__cookie, tio_stream_t **tio__stream,
+ char const *tio__path, tio_serial_attrs_t const *tio__attrs));
+typedef TIO_HOOK_TYPE(int) tio_list_serial_ports_t
+ OF((void *tio__cookie, tio_iter_t **tio__iterp));
+
+typedef TIO_HOOK_TYPE(int) tio_sleep_t
+ OF((void *tio__cookie, unsigned long tio__ms));
+typedef TIO_HOOK_TYPE(int) tio_get_timer_t
+ OF((void *tio__cookie, tio_timer_t **tio__timer));
+
+/* Callbacks definition. */
+
+# define TIO_OPENFLAG_SYSTEM_USB 1
+# define TIO_OPENFLAG_SYSTEM_SERIAL 2
+# define TIO_OPENFLAG_SYSTEM_CHRONO 4
+
+# define TIO_OPENFLAG_SYSTEM_ALL 7
+
+struct tio_system_functions {
+ tio_close_t *tio_system_functions_close;
+
+ tio_open_usb_stream_t *tio_system_functions_open_usb_stream;
+ tio_list_usb_devices_t *tio_system_functions_list_usb_devices;
+
+ tio_open_serial_stream_t *tio_system_functions_open_serial_stream;
+ tio_list_serial_ports_t *tio_system_functions_list_serial_ports;
+
+ tio_sleep_t *tio_system_functions_sleep;
+ tio_get_timer_t *tio_system_functions_get_timer;
+};
+
+/* ---
+ * Management functions.
+ * --- */
+
+TIO_BEGIN_DECLS
+
+/* Open a system. */
+
+TIO_EXTERN(int) tio_open_system
+ OF((tio_system_t **tio__systemp, void *tio__cookie,
+ unsigned int tio__flags,
+ tio_system_functions_t const *tio__functions));
+TIO_EXTERN(int) tio_open_local_system
+ OF((tio_system_t **tio__systemp));
+
+/* Stream interactions (USB and serial). */
+
+TIO_EXTERN(int) tio_open_usb_stream
+ OF((tio_system_t *tio__system, tio_stream_t **tio__streamp,
+ int tio__bus, int tio__addr));
+TIO_EXTERN(int) tio_list_usb_devices
+ OF((tio_system_t *tio__system, tio_iter_t **tio__iterp));
+
+TIO_EXTERN(int) tio_open_serial_stream
+ OF((tio_system_t *tio__system, tio_stream_t **tio__streamp,
+ char const *tio__path, tio_serial_attrs_t const *tio__attrs));
+TIO_EXTERN(int) tio_list_serial_ports
+ OF((tio_system_t *tio__system, tio_iter_t **tio__iterp));
+
+TIO_EXTERN(int) tio_sleep_on_system
+ OF((tio_system_t *tio__system, unsigned long tio__ms));
+TIO_EXTERN(int) tio_get_system_timer
+ OF((tio_system_t *tio__system, tio_timer_t **tio__timerp));
+
+# define tio_sleep(MS) tio_sleep_on_system(NULL, (MS))
+# define tio_get_timer(TP) tio_get_system_timer(NULL, (TP))
+
+TIO_END_DECLS
+TIO_END_NAMESPACE
+
+#endif /* TIO_NATIVE_H */
diff --git a/lib/chrono/internals.h b/lib/chrono/internals.h
new file mode 100644
index 0000000..d02427e
--- /dev/null
+++ b/lib/chrono/internals.h
@@ -0,0 +1,16 @@
+#ifndef LOCAL_TIMER_INTERNALS_H
+# define LOCAL_TIMER_INTERNALS_H 20200105
+# include "../internals.h"
+
+struct tio_timer {
+ /* Timer information. */
+
+ void *tio_timer_cookie;
+
+ /* Callbacks. */
+
+ tio_free_timer_t *tio_timer_free;
+ tio_get_spent_time_t *tio_timer_get_spent_time;
+};
+
+#endif /* LOCAL_TIMER_INTERNALS_H */
diff --git a/lib/chrono/sleep.c b/lib/chrono/sleep.c
deleted file mode 100644
index e4d9728..0000000
--- a/lib/chrono/sleep.c
+++ /dev/null
@@ -1,62 +0,0 @@
-/* ---
- * Microsoft Windows environment.
- * --- */
-
-#if defined(__WINDOWS__)
-# include "../internals.h"
-# include <windows.h>
-
-TIO_HOOK(int) default_sleep(unsigned long ms)
-{
- Sleep(ms);
- return (tio_ok);
-}
-
-/* ---
- * UNIX-like environments.
- * --- */
-
-#elif defined(__unix__) || defined(__unix)
-# define _POSIX_C_SOURCE 200112L
-# include "../internals.h"
-# include <time.h>
-
-TIO_LOCAL(int) default_sleep(unsigned long ms)
-{
- struct timespec requested_timestamp;
-
- requested_timestamp.tv_sec = ms / 1000;
- requested_timestamp.tv_nsec = (ms % 1000) * 1000000;
- nanosleep(&requested_timestamp, NULL);
- return (tio_ok);
-}
-
-/* ---
- * Default and main function.
- * --- */
-
-#else
-# include "../internals.h"
-# define default_callback NULL
-#endif
-
-TIO_LOCAL_DATA(tio_sleep_t *) tio_sleep_callback = &default_sleep;
-
-/* `tio_set_sleep_func()`: set the default sleep function. */
-
-TIO_EXTERN(void) tio_set_sleep_func(tio_sleep_t *func)
-{
- tio_sleep_callback = func;
-}
-
-/* `tio_sleep()`: sleep for a certain number of milliseconds. */
-
-TIO_EXTERN(int) tio_sleep(unsigned long ms)
-{
- if (!tio_sleep_callback)
- return (tio_error_op);
- if (!ms)
- return (tio_ok);
-
- return ((*tio_sleep_callback)(ms));
-}
diff --git a/lib/chrono/timer.c b/lib/chrono/timer.c
index 14d6c1f..44372eb 100644
--- a/lib/chrono/timer.c
+++ b/lib/chrono/timer.c
@@ -1,87 +1,38 @@
-#include "../internals.h"
+#include "internals.h"
-/* ---
- * Default functions for UNIX.
- * --- */
-
-#if _POSIX_C_SOURCE >= 199309L
-# include <time.h>
-
-struct tio_timer {
- clockid_t clk_id;
- struct timespec initial;
-};
-
-TIO_HOOK(int) default_get_timer(tio_timer_t **timerp)
+TIO_EXTERN(int) tio_get_spent_time(tio_timer_t *timer,
+ unsigned long *spentp)
{
- tio_timer_t *timer;
-
- if (!(timer = tio_alloc(1, sizeof(*timer))))
- return (tio_error_alloc);
-
-#ifdef __linux__
- timer->clk_id = CLOCK_MONOTONIC_COARSE;
-#else
- timer->clk_id = CLOCK_MONOTONIC;
-#endif
-
- if (clock_gettime(timer->clk_id, &timer->initial) < 0) {
- tio_free(timer);
- return (tio_error_unknown);
- }
-
- *timerp = timer;
- return (0);
+ if (!timer || !spentp || !timer->tio_timer_get_spent_time)
+ return (tio_error_op);
+ return ((*timer->tio_timer_get_spent_time)(timer->tio_timer_cookie,
+ spentp));
}
-TIO_HOOK(int) default_get_spent_time(tio_timer_t *timer,
- unsigned long *spent)
+TIO_HOOK(void) free_timer(tio_timer_t *timer)
{
- struct timespec ts;
-
- if (clock_gettime(timer->clk_id, &ts) < 0)
- return (tio_error_unknown);
-
- *spent = (ts.tv_sec - timer->initial.tv_sec) * 1000
- + (ts.tv_nsec - timer->initial.tv_nsec) / 1000000;
- return (tio_ok);
+ if (timer->tio_timer_free)
+ (*timer->tio_timer_free)(timer->tio_timer_cookie);
}
-#else
-# define NO_DEFAULTS 1
-#endif
+TIO_EXTERN(int) tio_open_timer(tio_timer_t **timerp,
+ void *cookie, tio_timer_functions_t const *functions)
+{
+ tio_timer_t *timer;
-#ifndef NO_DEFAULTS
-# define NO_DEFAULTS 0
-#endif
+ if (!(timer = tio_alloc_free(1, sizeof(tio_timer_t),
+ (tio_free_t *)&free_timer))) {
+ if (functions->tio_timer_functions_free)
+ (*functions->tio_timer_functions_free)(cookie);
-/* ---
- * Public API functions.
- * --- */
+ return (tio_error_alloc);
+ }
-#if NO_DEFAULTS
-TIO_LOCAL_DATA(tio_get_timer_t *)
- gettimer = 0;
-TIO_LOCAL_DATA(tio_get_spent_time_t *)
- getspenttime = 0;
-#else
-TIO_LOCAL_DATA(tio_get_timer_t *)
- gettimer = &default_get_timer;
-TIO_LOCAL_DATA(tio_get_spent_time_t *)
- getspenttime = &default_get_spent_time;
-#endif
+ timer->tio_timer_cookie = cookie;
+ timer->tio_timer_free = functions->tio_timer_functions_free;
+ timer->tio_timer_get_spent_time =
+ functions->tio_timer_functions_get_spent_time;
-TIO_EXTERN(int) tio_get_timer(tio_timer_t **timerp)
-{
- if (!gettimer)
- return (tio_error_op);
- return ((*gettimer)(timerp));
-}
-
-TIO_EXTERN(int) casio_get_spent_time(tio_timer_t *timer,
- unsigned long *spent)
-{
- if (!getspenttime)
- return (tio_error_op);
- return ((*getspenttime)(timer, spent));
+ *timerp = timer;
+ return (tio_ok);
}
diff --git a/lib/endian/endian.c b/lib/endian/endian.c
new file mode 100644
index 0000000..5e64565
--- /dev/null
+++ b/lib/endian/endian.c
@@ -0,0 +1,167 @@
+/* ****************************************************************************
+ * utils/endian.c -- internal endian things.
+ * Copyright (C) 2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
+ *
+ * This file is part of libcasio.
+ * libcasio is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 3.0 of the License,
+ * or (at your option) any later version.
+ *
+ * libcasio 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libcasio; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * These utilities are inspired by `libusb_cpu_to_le16` utility from libusb.
+ * ************************************************************************* */
+#include "internals.h"
+
+/* `tio_be16toh()`: big endian to host 16-bit conversion. */
+
+TIO_EXTERN(tio_uint16_t) tio_be16toh(tio_uint16_t x)
+{
+#ifdef tio_int_be16toh
+ return (tio_int_be16toh(x));
+#else
+ union {
+ tio_uint8_t b8[2];
+ tio_uint16_t b16;
+ } tmp;
+
+ tmp.b16 = x;
+ return ((tmp.b8[0] << 8) | tmp.b8[1]);
+#endif
+}
+
+/* `tio_le16toh()`: little endian to host 16-bit conversion. */
+
+TIO_EXTERN(tio_uint16_t) tio_le16toh(tio_uint16_t x)
+{
+#ifdef tio_le16toh
+ return (tio_int_le16toh(x));
+#else
+ union {
+ tio_uint8_t b8[2];
+ tio_uint16_t b16;
+ } tmp;
+
+ tmp.b16 = x;
+ return ((tmp.b8[1] << 8) | tmp.b8[0]);
+#endif
+}
+
+/* `tio_be32toh()`: big endian to host 32-bit conversion. */
+
+TIO_EXTERN(tio_uint32_t) tio_be32toh(tio_uint32_t x)
+{
+#ifdef tio_int_be32toh
+ return (tio_int_be32toh(x));
+#else
+ union {
+ tio_uint8_t b8[4];
+ tio_uint32_t b32;
+ } tmp;
+
+ tmp.b32 = x;
+ return ((tmp.b8[0] << 24) | (tmp.b8[1] << 16)
+ | (tmp.b8[2] << 8) | (tmp.b8[3] ));
+#endif
+}
+
+/* `tio_le32toh()`: little endian to host 32-bit conversion. */
+
+TIO_EXTERN(tio_uint32_t) tio_le32toh(tio_uint32_t x)
+{
+#ifdef tio_int_le32toh
+ return (tio_int_le32toh(x));
+#else
+ union {
+ tio_uint8_t b8[4];
+ tio_uint32_t b32;
+ } tmp;
+
+ tmp.b32 = x;
+ return ((tmp.b8[3] << 24) | (tmp.b8[2] << 16)
+ | (tmp.b8[1] << 8) | (tmp.b8[0] ));
+#endif
+}
+
+/* `tio_htobe16()`: host to big endian 16-bit conversion. */
+
+TIO_EXTERN(tio_uint16_t) tio_htobe16(tio_uint16_t x)
+{
+#ifdef tio_int_htobe16
+ return (tio_int_htobe16(x));
+#else
+ union {
+ tio_uint8_t b8[2];
+ tio_uint16_t b16;
+ } tmp;
+
+ tmp.b8[0] = x >> 8;
+ tmp.b8[1] = x & 0xFF;
+ return (tmp.b16);
+#endif
+}
+
+/* `tio_htole16()`: host to little endian 16-bit conversion. */
+
+TIO_EXTERN(tio_uint16_t) tio_htole16(tio_uint16_t x)
+{
+#ifdef tio_int_htole16
+ return (tio_int_htole16(x));
+#else
+ union {
+ tio_uint8_t b8[2];
+ tio_uint16_t b16;
+ } tmp;
+
+ tmp.b8[0] = x & 0xFF;
+ tmp.b8[1] = x >> 8;
+ return (tmp.b16);
+#endif
+}
+
+/* `tio_htobe32()`: host to big endian 32-bit conversion. */
+
+TIO_EXTERN(tio_uint32_t) tio_htobe32(tio_uint32_t x)
+{
+#ifdef tio_int_htobe32
+ return (tio_int_htobe32(x));
+#else
+ union {
+ tio_uint8_t b8[4];
+ tio_uint32_t b32;
+ } tmp;
+
+ tmp.b8[0] = (x >> 24);
+ tmp.b8[1] = (x >> 16) & 0xFF;
+ tmp.b8[2] = (x >> 8) & 0xFF;
+ tmp.b8[3] = (x ) & 0xFF;
+ return (tmp.b32);
+#endif
+}
+
+/* `tio_htole32()`: host to little endian 32-bit conversion. */
+
+TIO_EXTERN(tio_uint32_t) tio_htole32(tio_uint32_t x)
+{
+#ifdef tio_int_htole32
+ return (tio_int_htole32(x));
+#else
+ union {
+ tio_uint8_t b8[4];
+ tio_uint32_t b32;
+ } tmp;
+
+ tmp.b8[0] = (x ) & 0xFF;
+ tmp.b8[1] = (x >> 8) & 0xFF;
+ tmp.b8[2] = (x >> 16) & 0xFF;
+ tmp.b8[3] = (x >> 24);
+ return (tmp.b32);
+#endif
+}
diff --git a/lib/endian/internals.h b/lib/endian/internals.h
new file mode 100644
index 0000000..8846792
--- /dev/null
+++ b/lib/endian/internals.h
@@ -0,0 +1,6 @@
+#ifndef LOCAL_ENDIAN_H
+# define LOCAL_ENDIAN_H 1
+# define LIBTIO_NO_ENDIAN 1
+# include "../internals.h"
+
+#endif /* LOCAL_UTILS_ENDIAN_H */
diff --git a/lib/error/internals.h b/lib/error/internals.h
new file mode 100644
index 0000000..c270eda
--- /dev/null
+++ b/lib/error/internals.h
@@ -0,0 +1,8 @@
+#ifndef LOCAL_ERROR_INTERNALS_H
+# define LOCAL_ERROR_INTERNALS_H 20200105
+# include "../internals.h"
+
+# define DEFAULT_ERROR_MSG "(unknown libtio error)"
+# define ERROR_COUNT 0x18
+
+#endif
diff --git a/lib/error/iter.c b/lib/error/iter.c
new file mode 100644
index 0000000..d443f4a
--- /dev/null
+++ b/lib/error/iter.c
@@ -0,0 +1,56 @@
+#include "internals.h"
+
+TIO_STRUCT(cookie, cookie_t)
+
+struct cookie {
+ int current_number;
+};
+
+TIO_HOOK(int) next_error(cookie_t *cookie, int *numberp)
+{
+ int nextnumber;
+
+ if (cookie->current_number < 0
+ || cookie->current_number >= ERROR_COUNT)
+ return (tio_error_iter);
+
+ nextnumber = cookie->current_number;
+ *numberp = nextnumber;
+
+ for (;; nextnumber++) {
+ if (nextnumber < 0 || nextnumber >= ERROR_COUNT)
+ break ;
+ if (!strcmp(tio_error_name(nextnumber), DEFAULT_ERROR_MSG))
+ continue ;
+
+ break;
+ }
+
+ cookie->current_number = nextnumber;
+ return (tio_error_ok);
+}
+
+TIO_HOOK(void) end_iter(cookie_t *cookie)
+{
+ tio_free(cookie);
+}
+
+TIO_LOCAL(tio_iter_functions_t const) iter_functions = {
+ (tio_next_t *)next_error,
+ (tio_nextfree_t *)0,
+ (tio_end_t *)end_iter
+};
+
+/* `tio_iter_errors()`: list errors in libtio. */
+
+TIO_EXTERN(int) tio_iter_errors(tio_iter_t **iterp)
+{
+ cookie_t *cookie;
+
+ if (!(cookie = tio_alloc(1, sizeof(cookie_t))))
+ return tio_error_alloc;
+
+ cookie->current_number = 0;
+
+ /* TODO */
+}
diff --git a/lib/error.c b/lib/error/names.c
index d9c5863..9603210 100644
--- a/lib/error.c
+++ b/lib/error/names.c
@@ -2,7 +2,6 @@
/* The array. */
-#define ARR_SIZE 0x18
#define UNKNOWN NULL, NULL
TIO_LOCAL_DATA(char const *) errors[] = {
@@ -39,7 +38,7 @@ TIO_EXTERN(char const *) tio_error_name(int code)
{
char const *nm;
- if (code >= ARR_SIZE || !(nm = errors[code + code]))
+ if (code >= ERROR_COUNT || !(nm = errors[code + code]))
return ("(unknown libtio error)");
return (nm);
}
@@ -50,7 +49,7 @@ TIO_EXTERN(char const *) tio_error_desc(int code)
{
char const *ds;
- if (code >= ARR_SIZE || !(ds = errors[code + code + 1]))
+ if (code >= ERROR_COUNT || !(ds = errors[code + code + 1]))
return ("(unknown libtio error)");
return (ds);
}
diff --git a/lib/internals.h b/lib/internals.h
index 9a4f43e..2486435 100644
--- a/lib/internals.h
+++ b/lib/internals.h
@@ -10,12 +10,19 @@
typedef TIO_HOOK_TYPE(void) tio_free_t
OF((void *tio__mem));
+typedef TIO_HOOK_TYPE(void) tio_decref_t
+ OF((void *tio__mem));
TIO_EXTERN(void *) tio_alloc
OF((size_t tio__count, size_t tio__size));
TIO_EXTERN(void *) tio_alloc_free
OF((size_t tio__count, size_t tio__size,
tio_free_t *tio__free_func));
+TIO_EXTERN(void *) tio_alloc_ref
+ OF((size_t tio__count, size_t tio__size,
+ tio_free_t *tio__free_func, tio_decref_t *tio__decref_func));
+TIO_EXTERN(void) tio_incref
+ OF((void *tio__mem));
/* Exit function. */
@@ -25,16 +32,6 @@ typedef TIO_HOOK_TYPE(void) tio_exit_t
TIO_EXTERN(int) tio_add_exit
OF((tio_exit_t func, void *cookie));
-/* libusb utilities. */
-
-# ifndef LIBTIO_DISABLED_LIBUSB
-# include <libusb.h>
-
-TIO_EXTERN(int) tio_get_libusb_context
- OF((libusb_context **tio__ctx));
-
-# endif
-
/* ---
* Logging system.
* --- */
@@ -165,7 +162,8 @@ TIO_EXTERN(void) tio_log_mem();
* Function with candidates.
* --- */
-/* This set of macros are used when declaring a function with candidates. */
+/* This set of macros are used when declaring a function with
+ * candidates. */
# define CANDIDATE_FUNC_BODY(FUNC_TYPE, CANDIDATES, ARGS) \
{ \
diff --git a/lib/iter.c b/lib/iter.c
index ac32bcd..0c34a53 100644
--- a/lib/iter.c
+++ b/lib/iter.c
@@ -45,7 +45,8 @@ TIO_HOOK(void) default_end(void *cookie)
TIO_HOOK(void) free_iter(tio_iter_t *iter)
{
if (iter->tio_iter_has_last) {
- (*iter->tio_iter_nextfree)(iter->tio_iter_cookie, iter->tio_iter_last);
+ (*iter->tio_iter_nextfree)(iter->tio_iter_cookie,
+ iter->tio_iter_last);
iter->tio_iter_has_last = 0;
}
@@ -97,7 +98,8 @@ TIO_EXTERN(int) tio_next(tio_iter_t *iter, void **ptrp)
if (iter->tio_iter_stopped)
return (tio_error_iter);
if (iter->tio_iter_has_last) {
- (*iter->tio_iter_nextfree)(iter->tio_iter_cookie, iter->tio_iter_last);
+ (*iter->tio_iter_nextfree)(iter->tio_iter_cookie,
+ iter->tio_iter_last);
iter->tio_iter_has_last = 0;
}
diff --git a/lib/misc/alloc.c b/lib/misc/alloc.c
index 4f540d9..d31acd3 100644
--- a/lib/misc/alloc.c
+++ b/lib/misc/alloc.c
@@ -1,16 +1,24 @@
#include "../internals.h"
#include <stdlib.h>
#define ALLOC_CHUNK_SIZE 1024
+#define ALIGN_TO 8
/* ---
* Local data.
* --- */
-# define get_node_data(nodeptr) (void *)(nodeptr + sizeof(*nodeptr))
+# define get_node(dataptr) \
+ ((struct alloc_node *)dataptr - sizeof(struct alloc_node))
+# define get_node_data(nodeptr) \
+ (void *)(nodeptr + sizeof(*nodeptr))
struct alloc_node {
- tio_free_t *free_func;
+ tio_free_t *free_func;
+ tio_decref_t *decref_func;
+
struct alloc_node *next;
+ tio_uint16_t ref_count;
+ tio_uint16_t padding_bytes;
};
TIO_LOCAL_DATA(struct alloc_node *) alloc_node = NULL;
@@ -34,14 +42,25 @@ TIO_EXTERN(void *) tio_alloc_free(size_t count, size_t size,
{
struct alloc_node *node;
size_t total_size = count * size;
+ tio_uint16_t padding_bytes;
void *mem;
+ char *raw_alloc;
- node = malloc(sizeof(*node) + total_size);
- if (!node)
+ raw_alloc = malloc(sizeof(*node) + total_size + 7);
+ if (!raw_alloc)
return (NULL);
+ padding_bytes = (tio_uint16_t)((uintptr_t)raw_alloc & (ALIGN_TO - 1));
+ if (padding_bytes)
+ padding_bytes = ALIGN_TO - padding_bytes;
+
+ node = (struct alloc_node *)(raw_alloc + padding_bytes);
+
node->free_func = free_func;
+ node->decref_func = (tio_decref_t *)0;
+ node->ref_count = 1;
node->next = alloc_node;
+ node->padding_bytes = padding_bytes;
alloc_node = node;
mem = get_node_data(node);
@@ -50,24 +69,41 @@ TIO_EXTERN(void *) tio_alloc_free(size_t count, size_t size,
return (mem);
}
+/* `tio_alloc_ref()`: allocate memory dynamically using a custom
+ * dereference function. */
+
+TIO_EXTERN(void *) tio_alloc_ref(size_t count, size_t size,
+ tio_free_t *free_func, tio_decref_t *decref_func)
+{
+ void *ptr = tio_alloc_free(count, size, free_func);
+
+ if (!ptr)
+ return (NULL);
+
+ get_node(ptr)->decref_func = decref_func;
+ return (ptr);
+}
+
+/* `tio_incref()`: increment the reference count for an element. */
+
+TIO_EXTERN(void) tio_incref(void *ptr)
+{
+ get_node(ptr)->ref_count++;
+}
+
/* `tio_free()`: free allocated memory. */
TIO_EXTERN(void) tio_free(void *ptr)
{
struct alloc_node **nodep;
- struct alloc_node *node;
-
- for (nodep = &alloc_node; (node = *nodep); nodep = &node->next) {
- void *nodedata = get_node_data(node);
-
- if (nodedata != ptr)
- continue;
+ struct alloc_node *node = get_node(ptr);
+ if (node->decref_func)
+ (*node->decref_func)(ptr);
+ if (!--node->ref_count) {
if (node->free_func)
- (*node->free_func)(nodedata);
- *nodep = node->next;
+ (*node->free_func)(ptr);
- free(node);
- break;
+ free(((tio_uint8_t *)node) - node->padding_bytes);
}
}
diff --git a/lib/misc/libusb.c b/lib/misc/libusb.c
deleted file mode 100644
index 16a08ea..0000000
--- a/lib/misc/libusb.c
+++ /dev/null
@@ -1,40 +0,0 @@
-#include "../internals.h"
-#ifndef LIBTIO_DISABLED_LIBUSB
-# include <libusb.h>
-
-TIO_HOOK(void) free_context(void *vcontext)
-{
- libusb_exit((libusb_context *)vcontext);
-}
-
-/* `get_context()`: get the default libusb context. */
-
-TIO_LOCAL_DATA(libusb_context *) tio_libusb_context = NULL;
-
-TIO_EXTERN(int) tio_get_libusb_context(libusb_context **context)
-{
- libusb_context *ctx;
- int lerr, err;
-
- if (tio_libusb_context) {
- *context = tio_libusb_context;
- return (tio_ok);
- }
-
- if ((lerr = libusb_init(&ctx))) {
- msg((ll_fatal, "libusb_init failed with error %s: %s.",
- libusb_error_name(lerr), libusb_strerror(lerr)));
- return (tio_error_unknown);
- }
-
- if ((err = tio_add_exit(free_context, ctx))) {
- libusb_exit(ctx);
- return (err);
- }
-
- tio_libusb_context = ctx;
- *context = ctx;
- return (tio_ok);
-}
-
-#endif
diff --git a/lib/serial/builtin/unix_dev.c b/lib/serial/builtin/unix_dev.c
deleted file mode 100644
index e165e22..0000000
--- a/lib/serial/builtin/unix_dev.c
+++ /dev/null
@@ -1,155 +0,0 @@
-#include "../../internals.h"
-
-#ifndef LIBTIO_DISABLED_UNIX
-# include <errno.h>
-# include <string.h>
-# include <dirent.h>
-# include <unistd.h>
-
-/* `get_path_max()`: get the maximum path size. */
-
-TIO_LOCAL(size_t) get_path_max(void)
-{
- ssize_t path_max;
-
-#ifdef PATH_MAX
- path_max = PATH_MAX;
-#else
- path_max = pathconf("/", _PC_PATH_MAX);
- if (path_max <= 0)
- path_max = 4096;
-#endif
- ++path_max;
-
- return ((size_t)path_max);
-}
-
-/* `all_numbers()`: check if a string is entirely composed of numbers. */
-
-# define CHECK_NUM(CAR) \
- { \
- int c = (CAR); \
- \
- if (c < '0' || c > '9') \
- return (0); \
- }
-
-TIO_LOCAL(int) all_numbers(char const *s, size_t size)
-{
- if (size)
- for (; size--; s++)
- CHECK_NUM(*s)
- else
- for (; *s; s++)
- CHECK_NUM(*s)
-
- return (1);
-}
-
-/* ---
- * Cookie and callbacks.
- * --- */
-
-/* The cookie used for /dev iterating. */
-
-TIO_STRUCT(cookie, cookie_t)
-
-struct cookie {
- char *path;
- DIR *dp;
-
- char *start;
-};
-
-/* `next_serial_port()`: get the next serial port using the directory
- * listing.
- *
- * The serial lines are represented:
- * - on MacOS/OS X: "cu.*" (e.g. "cu.usbmodem621").
- * - on FreeBSD: "cuadX" (e.g. "cuad0").
- * - on Linux: "ttySX" (e.g. "ttyS0"). */
-
-# define IS_SERIAL_DEVICE(DEVNAME) \
- (!strncmp((DEVNAME), "cu.", 3) || \
- (!strncmp((DEVNAME), "cuad", 4) && all_numbers(&(DEVNAME)[4], 0)) || \
- (!strncmp((DEVNAME), "ttyS", 4) && all_numbers(&(DEVNAME)[4], 0)))
-
-TIO_HOOK(int) next_serial_port(cookie_t *cookie, char const **ptr)
-{
- struct dirent *dr;
-
- while (1) {
- /* Get the next entry. */
-
- if (!(dr = readdir(cookie->dp)))
- return (tio_error_iter);
-
- /* Check the name. */
-
- if (!IS_SERIAL_DEVICE(dr->d_name))
- continue;
-
- /* We have found a serial port!
- * Just copy it into our buffer and return it. */
-
- strcpy(cookie->start, dr->d_name);
- break;
- }
-
- *ptr = cookie->path;
- return (0);
-}
-
-/* `end_iter()`: end the iterator. */
-
-TIO_HOOK(void) end_iter(cookie_t *cookie)
-{
- closedir(cookie->dp);
- tio_free(cookie);
-}
-
-/* `dev_cu_functions`: the callbacks structure. */
-
-TIO_LOCAL_DATA(tio_iter_functions_t const) dev_cu_functions = {
- (tio_next_t *)&next_serial_port,
- NULL,
- (tio_end_t *)&end_iter
-};
-
-/* ---
- * Open the iterator.
- * --- */
-
-/* `tio_list_unix_serial_ports_using_cu_devices()`: list serial ports
- * using the `/dev` directory, by looking for `cu.*` devices. */
-
-TIO_EXTERN(int) tio_list_unix_serial_ports_using_cu_devices(tio_iter_t **iterp)
-{
- cookie_t *cookie;
- size_t path_max = get_path_max();
-
- /* Create the cookie. */
-
- if (!(cookie = tio_alloc(1, sizeof(cookie) + path_max)))
- return (tio_error_alloc);
-
- cookie->path = (char *)(void *)&cookie[1];
-
- /* Prepare the path and open the directory stream. */
-
- strcpy(cookie->path, "/dev/");
- cookie->start = strchr(cookie->path, '\0');
-
- if (!(cookie->dp = opendir(cookie->path))) {
- tio_free(cookie);
-
- msg((ll_error, "unknown error %d: %s", errno, strerror(errno)));
- return (tio_error_unknown);
- }
-
- /* Create the iterator. */
-
- return (tio_iter(iterp, cookie, &dev_cu_functions));
-}
-
-#endif
diff --git a/lib/serial/builtin/unix_dev_serial.c b/lib/serial/builtin/unix_dev_serial.c
deleted file mode 100644
index 6aee6ab..0000000
--- a/lib/serial/builtin/unix_dev_serial.c
+++ /dev/null
@@ -1,158 +0,0 @@
-#define _DEFAULT_SOURCE
-#include "../../internals.h"
-
-#ifndef LIBTIO_DISABLED_UNIX
-# include <errno.h>
-
-# include <sys/stat.h>
-# include <unistd.h>
-# include <fcntl.h>
-# include <dirent.h>
-
-/* `get_path_max()`: get the maximum path size. */
-
-TIO_LOCAL(size_t) get_path_max(void)
-{
- ssize_t path_max;
-
-#ifdef PATH_MAX
- path_max = PATH_MAX;
-#else
- path_max = pathconf("/", _PC_PATH_MAX);
- if (path_max <= 0)
- path_max = 4096;
-#endif
- ++path_max;
-
- return ((size_t)path_max);
-}
-
-/* ---
- * Cookie and callbacks.
- * --- */
-
-/* The cookie used for /dev/serial iterating. */
-
-TIO_STRUCT(cookie, cookie_t)
-
-struct cookie {
- char *path;
- char *devname;
- size_t path_max;
- DIR *dp;
- char *start;
-};
-
-/* `next_serial_port()`: get the next serial port using the
- * directory listing. */
-
-TIO_HOOK(int) next_serial_port(cookie_t *cookie, char const **ptr)
-{
- struct dirent *dr;
- struct stat st;
- ssize_t rl;
- char *res;
-
- while (1) {
- /* Get the next entry. */
-
- if (!(dr = readdir(cookie->dp)))
- return (tio_error_iter);
-
- /* Copy that into the path and check the type. */
-
- strcpy(cookie->start, dr->d_name);
- if (lstat(cookie->path, &st) || (st.st_mode & S_IFMT) != S_IFLNK)
- continue;
-
- /* Get the destination path. */
-
- rl = readlink(cookie->path, cookie->devname, get_path_max());
- if (rl < 0)
- continue;
- cookie->devname[rl] = 0;
-
- /* If the path is a relative one, adapt it. */
-
- if (cookie->devname[0] != '/') {
- strcpy(cookie->start, cookie->devname);
- if (!(res = realpath(cookie->path, cookie->devname)))
- continue;
- }
-
- break;
- }
-
- *ptr = cookie->devname;
- return (0);
-}
-
-/* `end_iter()`: end the iterator. */
-
-TIO_HOOK(void) end_iter(cookie_t *cookie)
-{
- closedir(cookie->dp);
- tio_free(cookie);
-}
-
-/* `dev_serial_functions`: the callbacks structure. */
-
-TIO_LOCAL_DATA(tio_iter_functions_t const) dev_serial_functions = {
- (tio_next_t *)&next_serial_port,
- NULL,
- (tio_end_t *)&end_iter
-};
-
-/* ---
- * Open the iterator.
- * --- */
-
-/* `tio_list_unix_serial_ports_using_dev_serial()`: list serial ports using
- * the `/dev/serial` directory.
- *
- * Links in the /dev/serial/by-id/ should resolve to relative paths, but
- * I also managed absolute paths, in case. */
-
-TIO_EXTERN(int) tio_list_unix_serial_ports_using_dev_serial(tio_iter_t **iterp)
-{
- cookie_t *cookie;
- char const *dev_serial = "/dev/serial/by-id/";
- size_t path_max;
-
- /* Get the maximum path size.
- * Snippet found in `man 3 realpath`, glibc version. */
-
- path_max = get_path_max();
-
- /* Create the cookie. */
-
- if (!(cookie = tio_alloc(1, sizeof(*cookie) + path_max + path_max)))
- return (tio_error_alloc);
-
- cookie->path = (char *)(void *)&cookie[1];
- cookie->devname = cookie->path + path_max;
-
- /* Open the directory stream. */
-
- strcpy(cookie->path, dev_serial);
- if (!(cookie->dp = opendir(cookie->path))) {
- tio_free(cookie);
-
- if (errno == ENOENT)
- return (tio_error_op);
-
- msg((ll_error, "unknown error %d: %s", errno, strerror(errno)));
- return (tio_error_unknown);
- }
-
- /* Prepare what's left to prepare in the cookie. */
-
- cookie->start = strchr(cookie->path, '\0');
- cookie->path_max = path_max;
-
- /* Create the iterator. */
-
- return (tio_iter(iterp, cookie, &dev_serial_functions));
-}
-
-# endif /* __linux__ */
diff --git a/lib/serial/list.c b/lib/serial/list.c
deleted file mode 100644
index 8933696..0000000
--- a/lib/serial/list.c
+++ /dev/null
@@ -1,24 +0,0 @@
-#include "../internals.h"
-
-typedef TIO_EXTERN_TYPE(int) spl_func
- OF((tio_iter_t **));
-
-/* `spl_candidates`: candidates to serial ports listing. */
-
-TIO_LOCAL_DATA(spl_func * 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_list_serial_ports()`: list the serial ports, in an agnostic way. */
-
-TIO_EXTERN(int) tio_list_serial_ports(tio_iter_t **iterp)
- CANDIDATE_FUNC_BODY(spl_func, spl_candidates, (iterp))
diff --git a/lib/stream/builtin/bulk_only.c b/lib/stream/builtin/bulk_only.c
index dbe89d0..44fa595 100644
--- a/lib/stream/builtin/bulk_only.c
+++ b/lib/stream/builtin/bulk_only.c
@@ -124,7 +124,7 @@ TIO_EXTERN(int) tio_open_bulk_usb(tio_stream_t **streamp,
tio_stream_t *usb_stream;
int err;
- err = tio_open_native_usb(&usb_stream, bus, addr);
+ err = tio_open_usb_stream(NULL, &usb_stream, bus, addr);
if (err)
return (err);
diff --git a/lib/stream/native/serial.c b/lib/stream/native/serial.c
deleted file mode 100644
index f088caa..0000000
--- a/lib/stream/native/serial.c
+++ /dev/null
@@ -1,23 +0,0 @@
-#include "../internals.h"
-
-typedef TIO_EXTERN_TYPE(int) spo_func
- OF((tio_stream_t **, char const *));
-
-/* `spo_candidates`: candidates to serial device opening. */
-
-TIO_LOCAL_DATA(spo_func * const) spo_candidates[] = {
-#ifndef LIBTIO_DISABLED_WINDOWS
- &tio_open_windows_serial_port,
-#endif
-
-#ifndef LIBTIO_DISABLED_UNIX
- &tio_open_unix_serial_port,
-#endif
-
- NULL
-};
-
-/* `tio_open_native_serial()`: open a serial device, in an agnostic way. */
-
-TIO_EXTERN(int) tio_open_native_serial(tio_stream_t **sp, char const *path)
- CANDIDATE_FUNC_BODY(spo_func, spo_candidates, (sp, path))
diff --git a/lib/stream/native/usb.c b/lib/stream/native/usb.c
deleted file mode 100644
index e2da4d6..0000000
--- a/lib/stream/native/usb.c
+++ /dev/null
@@ -1,19 +0,0 @@
-#include "../internals.h"
-
-typedef TIO_EXTERN_TYPE(int) uo_func
- OF((tio_stream_t **, int, int));
-
-/* `uo_candidates`: candidates to USB device opening. */
-
-TIO_LOCAL_DATA(uo_func * const) uo_candidates[] = {
-#ifndef LIBTIO_DISABLED_LIBUSB
- &tio_open_libusb,
-#endif
-
- NULL
-};
-
-/* `tio_open_native_usb()`: open a USB device, in an agnostic way. */
-
-TIO_EXTERN(int) tio_open_native_usb(tio_stream_t **streamp, int bus, int addr)
- CANDIDATE_FUNC_BODY(uo_func, uo_candidates, (streamp, bus, addr))
diff --git a/lib/stream/usb.c b/lib/stream/usb.c
index 367bb0c..94259e6 100644
--- a/lib/stream/usb.c
+++ b/lib/stream/usb.c
@@ -3,7 +3,8 @@
/* `tio_send_usb_bulk()`: send a USB bulk packet. */
TIO_EXTERN(int) tio_send_usb_bulk(tio_stream_t *stream,
- unsigned char const *data, size_t size, unsigned int timeout /* in ms */)
+ unsigned char const *data, size_t size,
+ unsigned int timeout /* in ms */)
{
int err;
tio_usb_send_bulk_t *func;
diff --git a/lib/system/internals.h b/lib/system/internals.h
new file mode 100644
index 0000000..dc832ed
--- /dev/null
+++ b/lib/system/internals.h
@@ -0,0 +1,26 @@
+#ifndef LOCAL_SYSTEM_INTERNALS_H
+# define LOCAL_SYSTEM_INTERNALS_H 20190419
+# include "../internals.h"
+
+/* Internal structure for the system. */
+
+struct tio_system {
+ /* System information. */
+
+ void *tio_system_cookie;
+
+ /* Callbacks. */
+
+ tio_close_t *tio_system_close;
+
+ tio_open_usb_stream_t *tio_system_open_usb_stream;
+ tio_list_usb_devices_t *tio_system_list_usb_devices;
+
+ tio_open_serial_stream_t *tio_system_open_serial_stream;
+ tio_list_serial_ports_t *tio_system_list_serial_ports;
+
+ tio_sleep_t *tio_system_sleep;
+ tio_get_timer_t *tio_system_get_timer;
+};
+
+#endif
diff --git a/lib/system/libusb/internals.h b/lib/system/libusb/internals.h
new file mode 100644
index 0000000..7a7d987
--- /dev/null
+++ b/lib/system/libusb/internals.h
@@ -0,0 +1,24 @@
+#ifndef LOCAL_LIBUSB_INTERNALS_H
+# define LOCAL_LIBUSB_INTERNALS_H 20190725
+# include "../../internals.h"
+
+# ifndef LIBTIO_DISABLED_LIBUSB
+# include <libusb.h>
+
+TIO_STRUCT(tio_libusb_cookie, tio_libusb_cookie_t)
+
+struct tio_libusb_cookie {
+ libusb_context *context;
+};
+
+/* Utilities. */
+
+TIO_EXTERN(int) tio_libusb_list_devices
+ OF((tio_libusb_cookie_t *tio__cookie, tio_iter_t **tio__iterp));
+
+TIO_EXTERN(int) tio_libusb_open
+ OF((tio_libusb_cookie_t *tio__cookie, tio_stream_t **tio__streamp,
+ int tio__bus, int tio__addr));
+
+# endif
+#endif
diff --git a/lib/usb/builtin/libusb.c b/lib/system/libusb/list.c
index c91cb20..219880d 100644
--- a/lib/usb/builtin/libusb.c
+++ b/lib/system/libusb/list.c
@@ -1,4 +1,4 @@
-#include "../../internals.h"
+#include "internals.h"
#ifndef LIBTIO_DISABLED_LIBUSB
# include <libusb.h>
@@ -76,9 +76,10 @@ TIO_LOCAL_DATA(tio_iter_functions_t const) libusb_dl_functions = {
* Open the iterator.
* --- */
-/* `tio_list_libusb_devices()`: list USB devices using libusb. */
+/* `tio_libusb_list_devices()`: list USB devices using libusb. */
-TIO_EXTERN(int) tio_list_libusb_devices(tio_iter_t **iterp)
+TIO_EXTERN(int) tio_libusb_list_devices(tio_libusb_cookie_t *lcookie,
+ tio_iter_t **iterp)
{
cookie_t *cookie;
libusb_context *ctx;
@@ -86,17 +87,13 @@ TIO_EXTERN(int) tio_list_libusb_devices(tio_iter_t **iterp)
int device_count;
int err;
- /* Open up the context. */
-
- if ((err = tio_get_libusb_context(&ctx)))
- return (err);
-
/* Get the device list. */
- device_count = libusb_get_device_list(ctx, &device_list);
+ device_count = libusb_get_device_list(lcookie->context, &device_list);
if (device_count < 0) {
msg((ll_fatal, "libusb_get_device_list returned %s: %s.",
- libusb_error_name(device_count), libusb_strerror(device_count)));
+ libusb_error_name(device_count),
+ libusb_strerror(device_count)));
return (tio_error_unknown);
}
diff --git a/lib/system/libusb/open.c b/lib/system/libusb/open.c
new file mode 100644
index 0000000..28aba75
--- /dev/null
+++ b/lib/system/libusb/open.c
@@ -0,0 +1,43 @@
+#include "internals.h"
+#ifndef LIBTIO_DISABLED_LIBUSB
+
+TIO_HOOK(void) tio_libusb_close(tio_libusb_cookie_t *cookie)
+{
+ libusb_exit(cookie->context);
+}
+
+TIO_LOCAL_DATA(tio_system_functions_t const) libusb_functions = {
+ (tio_close_t *)&tio_libusb_close,
+
+ (tio_open_usb_stream_t *)&tio_libusb_open,
+ (tio_list_usb_devices_t *)&tio_libusb_list_devices
+};
+
+TIO_EXTERN(int) tio_open_libusb_system(tio_system_t **systemp)
+{
+ libusb_context *ctx;
+ tio_libusb_cookie_t *cookie;
+ int lerr, err;
+
+ /* Open a libusb context and create the cookie. */
+
+ if ((lerr = libusb_init(&ctx))) {
+ msg((ll_fatal, "libusb_init failed with error %s: %s.",
+ libusb_error_name(lerr), libusb_strerror(lerr)));
+ return (tio_error_unknown);
+ }
+
+ if (!(cookie = tio_alloc(1, sizeof(tio_libusb_cookie_t)))) {
+ libusb_exit(ctx);
+ return (tio_error_alloc);
+ }
+
+ cookie->context = ctx;
+
+ /* Open the system. */
+
+ return (tio_open_system(systemp, cookie, TIO_OPENFLAG_SYSTEM_ALL,
+ &libusb_functions));
+}
+
+#endif
diff --git a/lib/stream/builtin/libusb.c b/lib/system/libusb/stream.c
index d57edd1..edd8dba 100644
--- a/lib/stream/builtin/libusb.c
+++ b/lib/system/libusb/stream.c
@@ -1,4 +1,4 @@
-#include "../internals.h"
+#include "internals.h"
#ifndef LIBTIO_DISABLED_LIBUSB
# include <libusb.h>
@@ -9,18 +9,15 @@
/* `find_device()`: find a descriptor out of bus/host number. */
-TIO_LOCAL(int) find_device(int bus, int addr, libusb_device **devicep)
+TIO_LOCAL(int) find_device(tio_libusb_cookie_t *cookie,
+ int bus, int addr, libusb_device **devicep)
{
- libusb_context *ctx = NULL;
libusb_device **device_list;
int device_count, err, id;
- if ((err = tio_get_libusb_context(&ctx)))
- return (err);
-
/* Get the device list. */
- device_count = libusb_get_device_list(ctx, &device_list);
+ device_count = libusb_get_device_list(cookie->context, &device_list);
if (device_count < 0) {
msg((ll_fatal, "libusb_get_device_list returned error %s: %s.",
libusb_error_name(device_count), libusb_strerror(device_count)));
@@ -164,9 +161,9 @@ TIO_LOCAL_DATA(tio_usb_functions_t const) usb_functions = {
* Open the stream.
* --- */
-/* `tio_open_libusb_device()`: find a USB device. */
+/* `tio_libusb_open_device()`: find a USB device. */
-TIO_EXTERN(int) tio_open_libusb_device(tio_stream_t **streamp,
+TIO_LOCAL(int) tio_libusb_open_device(tio_stream_t **streamp,
libusb_device *device, int deref)
{
int err = tio_ok, uerr;
@@ -221,16 +218,17 @@ fail:
return (err);
}
-/* `tio_open_libusb()`: open a USB device. */
+/* `tio_libusb_open()`: open a USB device. */
-TIO_EXTERN(int) tio_open_libusb(tio_stream_t **streamp, int bus, int addr)
+TIO_EXTERN(int) tio_libusb_open(tio_libusb_cookie_t *cookie,
+ tio_stream_t **streamp, int bus, int addr)
{
int err = 0;
libusb_device *device = NULL;
- if ((err = find_device(bus, addr, &device)))
+ if ((err = find_device(cookie, bus, addr, &device)))
return (err);
- return (tio_open_libusb_device(streamp, device, 1));
+ return (tio_libusb_open_device(streamp, device, 1));
}
#endif
diff --git a/lib/system/open.c b/lib/system/open.c
new file mode 100644
index 0000000..d12da95
--- /dev/null
+++ b/lib/system/open.c
@@ -0,0 +1,66 @@
+#include "internals.h"
+
+/* `free_system()`: close a system. */
+
+TIO_HOOK(void) free_system(tio_system_t *system)
+{
+ tio_close_t *cl;
+
+ if (!system)
+ return ;
+
+ /* Close the system. */
+
+ if ((cl = system->tio_system_close))
+ (*cl)(system->tio_system_cookie);
+}
+
+/* `tio_open_system()`: open a system. */
+
+TIO_EXTERN(int) tio_open_system(tio_system_t **systemp,
+ void *cookie, unsigned int flags,
+ tio_system_functions_t const *functions)
+{
+ tio_system_t *system;
+ tio_close_t *cl = functions->tio_system_functions_close;
+
+ if (!(system = (*systemp = tio_alloc_free(1, sizeof(*systemp),
+ (tio_free_t *)&free_system)))) {
+ if (cl)
+ (*cl)(cookie);
+ return (tio_error_alloc);
+ }
+
+ system->tio_system_cookie = cookie;
+
+ system->tio_system_close = cl;
+ system->tio_system_open_usb_stream = NULL;
+ system->tio_system_list_usb_devices = NULL;
+ system->tio_system_open_serial_stream = NULL;
+ system->tio_system_list_serial_ports = NULL;
+ system->tio_system_sleep = NULL;
+ system->tio_system_get_timer = NULL;
+
+ if (flags & TIO_OPENFLAG_SYSTEM_USB) {
+ system->tio_system_open_usb_stream =
+ functions->tio_system_functions_open_usb_stream;
+ system->tio_system_list_usb_devices =
+ functions->tio_system_functions_list_usb_devices;
+ }
+
+ if (flags & TIO_OPENFLAG_SYSTEM_SERIAL) {
+ system->tio_system_open_serial_stream =
+ functions->tio_system_functions_open_serial_stream;
+ system->tio_system_list_serial_ports =
+ functions->tio_system_functions_list_serial_ports;
+ }
+
+ if (flags & TIO_OPENFLAG_SYSTEM_CHRONO) {
+ system->tio_system_sleep =
+ functions->tio_system_functions_sleep;
+ system->tio_system_get_timer =
+ functions->tio_system_functions_get_timer;
+ }
+
+ return (tio_ok);
+}
diff --git a/lib/system/stdio/internals.h b/lib/system/stdio/internals.h
new file mode 100644
index 0000000..cbea520
--- /dev/null
+++ b/lib/system/stdio/internals.h
@@ -0,0 +1,25 @@
+#ifndef LOCAL_STDIO_INTERNALS_H
+# define LOCAL_STDIO_INTERNALS_H 20190725
+# include "../../internals.h"
+# ifndef LIBTIO_DISABLED_FILE
+
+# include <stdio.h>
+# if defined(__linux__)
+# include <stdio_ext.h>
+# else
+# define __freadable(F) (1)
+# define __fwritable(F) (1)
+# endif
+
+TIO_EXTERN(int) tio_stdio_open_file
+ OF((tio_stream_t **tio__streamp, FILE *tio__filep, int tio__cl));
+
+TIO_EXTERN(int) tio_stdio_open_out
+ OF((tio_stream_t **tio__streamp));
+TIO_EXTERN(int) tio_stdio_open_err
+ OF((tio_stream_t **tio__streamp));
+TIO_EXTERN(int) tio_stdio_open_in
+ OF((tio_stream_t **tio__streamp));
+
+# endif
+#endif
diff --git a/lib/stream/builtin/std.c b/lib/system/stdio/stream.c
index 12f851a..c5cbcb6 100644
--- a/lib/stream/builtin/std.c
+++ b/lib/system/stdio/stream.c
@@ -1,13 +1,6 @@
-#include "../internals.h"
+#include "internals.h"
#ifndef LIBTIO_DISABLED_FILE
-# if defined(__linux__)
-# include <stdio_ext.h>
-# else
-# define __freadable(F) (1)
-# define __fwritable(F) (1)
-# endif
-
/* Cookie structure. */
typedef struct {
@@ -89,9 +82,10 @@ TIO_LOCAL_DATA(tio_functions_t const) tio_std_functions = {
&tio_std_seek
};
-/* `tio_open_std()`: open a libtio stream from a standard stream. */
+/* `tio_stdio_open_file()`: open a libtio stream from a standard stream. */
-TIO_EXTERN(int) tio_open_std(tio_stream_t **streamp, FILE *filep, int cl)
+TIO_EXTERN(int) tio_stdio_open_file(tio_stream_t **streamp,
+ FILE *filep, int cl)
{
std_cookie_t *cookie = NULL;
unsigned int flags = 0;
@@ -152,7 +146,7 @@ TIO_EXTERN(int) NAME(tio_stream_t **streamp) \
return (tio_error_ok); \
} \
\
- err = tio_open_std(&GLOBAL, STREAM_NAME, 0); \
+ err = tio_stdio_open_file(&GLOBAL, STREAM_NAME, 0); \
if (err) \
return (err); \
\
@@ -160,8 +154,8 @@ TIO_EXTERN(int) NAME(tio_stream_t **streamp) \
return (tio_error_ok); \
}
-BUILTIN_STREAM(tio_open_stdout, stdout_stream, stdout)
-BUILTIN_STREAM(tio_open_stderr, stderr_stream, stderr)
-BUILTIN_STREAM(tio_open_stdin, stdin_stream, stdin)
+BUILTIN_STREAM(tio_stdio_open_out, stdout_stream, stdout)
+BUILTIN_STREAM(tio_stdio_open_err, stderr_stream, stderr)
+BUILTIN_STREAM(tio_stdio_open_in, stdin_stream, stdin)
#endif
diff --git a/lib/system/unix/internals.h b/lib/system/unix/internals.h
new file mode 100644
index 0000000..b9189bb
--- /dev/null
+++ b/lib/system/unix/internals.h
@@ -0,0 +1,33 @@
+#ifndef LOCAL_UNIX_INTERNALS_H
+# define LOCAL_UNIX_INTERNALS_H 20190725
+# define _GNU_SOURCE 1
+
+# include "../../internals.h"
+# ifndef LIBTIO_DISABLED_UNIX
+
+# include <string.h>
+# include <errno.h>
+# include <time.h>
+# include <dirent.h>
+# include <fcntl.h>
+# include <unistd.h>
+# include <termios.h>
+# include <sys/stat.h>
+# include <sys/ioctl.h>
+
+TIO_EXTERN(size_t) tio_unix_path_max
+ OF((void));
+
+TIO_EXTERN(int) tio_unix_list_serial_ports
+ OF((void *cookie, tio_iter_t **tio__iterp));
+
+TIO_EXTERN(int) tio_unix_open_file
+ OF((tio_stream_t **tio__streamp, int tio__fd, int tio__cl));
+TIO_EXTERN(int) tio_unix_open_serial_file
+ OF((tio_stream_t **tio__streamp, int tio__fd, int tio__cl));
+TIO_EXTERN(int) tio_unix_open_serial_port
+ OF((void *cookie, tio_stream_t **tio__streamp, char const *tio__path,
+ tio_serial_attrs_t const *tio__attrs));
+
+# endif
+#endif
diff --git a/lib/system/unix/list_serial.c b/lib/system/unix/list_serial.c
new file mode 100644
index 0000000..bb5438c
--- /dev/null
+++ b/lib/system/unix/list_serial.c
@@ -0,0 +1,242 @@
+#include "internals.h"
+#ifndef LIBTIO_DISABLED_UNIX
+
+TIO_STRUCT(dev_serial_cookie, dev_serial_cookie_t)
+TIO_STRUCT(cu_cookie, cu_cookie_t)
+
+/* We have two available methods for listing serial devices using the
+ * standard UNIX API:
+ *
+ * - (linux only) listing links in the `/dev/serial/by-id/` directory,
+ * which should be more precise.
+ * - (general) listing serial ports in the `/dev` directory, by looking
+ * for `cu.*` devices; might be imprecise.
+ *
+ * First method, the /dev/serial method. */
+
+struct dev_serial_cookie {
+ char *path;
+ char *devname;
+ size_t path_max;
+ DIR *dp;
+
+ char *start;
+};
+
+TIO_HOOK(int) next_dev_serial_device(dev_serial_cookie_t *cookie,
+ char const **ptr)
+{
+ struct dirent *dr;
+ struct stat st;
+ ssize_t rl;
+ char *res;
+
+ while (1) {
+ /* Get the next entry. */
+
+ if (!(dr = readdir(cookie->dp)))
+ return (tio_error_iter);
+
+ /* Copy that into the path and check the type. */
+
+ strcpy(cookie->start, dr->d_name);
+ if (lstat(cookie->path, &st) || (st.st_mode & S_IFMT) != S_IFLNK)
+ continue;
+
+ /* Get the destination path. */
+
+ rl = readlink(cookie->path, cookie->devname, cookie->path_max);
+ if (rl < 0)
+ continue;
+ cookie->devname[rl] = 0;
+
+ /* If the path is a relative one, adapt it. */
+
+ if (cookie->devname[0] != '/') {
+ strcpy(cookie->start, cookie->devname);
+ if (!(res = realpath(cookie->path, cookie->devname)))
+ continue;
+ }
+
+ break;
+ }
+
+ *ptr = cookie->devname;
+ return (0);
+}
+
+/* `end_dev_serial_iter()`: end the iterator. */
+
+TIO_HOOK(void) end_dev_serial_iter(dev_serial_cookie_t *cookie)
+{
+ closedir(cookie->dp);
+ tio_free(cookie);
+}
+
+TIO_LOCAL_DATA(tio_iter_functions_t const) dev_serial_functions = {
+ (tio_next_t *)&next_dev_serial_device,
+ NULL,
+ (tio_end_t *)&end_dev_serial_iter
+};
+
+/* Second method, the `/dev` listing and testing if it is a serial
+ * device. */
+
+# define CHECK_NUM(CAR) { \
+ int c = (CAR); \
+ if (c < '0' || c > '9') \
+ return (0); }
+
+TIO_LOCAL(int) all_numbers(char const *s, size_t size)
+{
+ if (size)
+ for (; size--; s++)
+ CHECK_NUM(*s)
+ else
+ for (; *s; s++)
+ CHECK_NUM(*s)
+
+ return (1);
+}
+
+struct cu_cookie {
+ char *path;
+ DIR *dp;
+
+ char *start;
+};
+
+/* `next_cu_device()`: get the next serial port using the directory
+ * listing.
+ *
+ * The serial lines are represented:
+ * - on MacOS/OS X: "cu.*" (e.g. "cu.usbmodem621").
+ * - on FreeBSD: "cuadX" (e.g. "cuad0").
+ * - on Linux: "ttySX" (e.g. "ttyS0"). */
+
+# define IS_SERIAL_DEVICE(DEVNAME) \
+ (!strncmp((DEVNAME), "cu.", 3) || \
+ (!strncmp((DEVNAME), "cuad", 4) && all_numbers(&(DEVNAME)[4], 0)) || \
+ (!strncmp((DEVNAME), "ttyS", 4) && all_numbers(&(DEVNAME)[4], 0)))
+
+TIO_HOOK(int) next_cu_device(cu_cookie_t *cookie, char const **ptr)
+{
+ struct dirent *dr;
+
+ while (1) {
+ /* Get the next entry. */
+
+ if (!(dr = readdir(cookie->dp)))
+ return (tio_error_iter);
+
+ /* Check the name. */
+
+ if (!IS_SERIAL_DEVICE(dr->d_name))
+ continue;
+
+ /* We have found a serial port!
+ * Just copy it into our buffer and return it. */
+
+ strcpy(cookie->start, dr->d_name);
+ break;
+ }
+
+ *ptr = cookie->path;
+ return (0);
+}
+
+TIO_HOOK(void) end_cu_iter(cu_cookie_t *cookie)
+{
+ closedir(cookie->dp);
+ tio_free(cookie);
+}
+
+TIO_LOCAL_DATA(tio_iter_functions_t const) dev_cu_functions = {
+ (tio_next_t *)&next_cu_device,
+ (tio_nextfree_t *)0,
+ (tio_end_t *)&end_cu_iter
+};
+
+/* Now we're done with the method-specific definitions, let's define
+ * the general method!
+ *
+ * `tio_unix_list_serial_ports()`: test the available methods and stick
+ * to one by returning the corresponding iterator. */
+
+TIO_EXTERN(int) tio_unix_list_serial_ports(void *cookie,
+ tio_iter_t **iterp)
+{
+ DIR *dr;
+
+ (void)cookie;
+
+ /* First, try the `/dev/serial` method.
+ * If the directory does not exist, then this method will not work. */
+
+ dr = opendir("/dev/serial/by-id/");
+ if (dr) {
+ dev_serial_cookie_t *cookie;
+ size_t path_max = tio_unix_path_max();
+
+ /* The directory exists and we have a pointer to it!
+ * Create the corresponding cookie and iterator. */
+
+ cookie = tio_alloc(1, sizeof(dev_serial_cookie_t)
+ + path_max + path_max);
+ if (!cookie) {
+ closedir(dr);
+ return (tio_error_alloc);
+ }
+
+ cookie->path = (char *)(void *)&cookie[1];
+ cookie->devname = cookie->path + path_max;
+ strcpy(cookie->path, "/dev/serial/by-id/");
+ cookie->start = strchr(cookie->path, '\0');
+ cookie->path_max = path_max;
+
+ return (tio_iter(iterp, cookie, &dev_serial_functions));
+ } else if (errno != ENOENT) {
+ msg((ll_error, "unknown error %d while opening /dev/serial/by-id: "
+ "%s", errno, strerror(errno)));
+ return tio_error_unknown;
+ }
+
+ /* If the first method doesn't work because the directory doesn't
+ * exist, let's try listing serial devices from `/dev` directly. */
+
+ dr = opendir("/dev/");
+ if (dr) {
+ cu_cookie_t *cookie;
+ size_t path_max = tio_unix_path_max();
+
+ /* The directory exists and we have a pointer to it!
+ * Create the corresponding cookie and iterator. */
+
+ cookie = tio_alloc(1, sizeof(cu_cookie_t) + path_max);
+ if (!cookie) {
+ closedir(dr);
+ return (tio_error_alloc);
+ }
+
+ cookie->path = (char *)(void *)&cookie[1];
+ strcpy(cookie->path, "/dev/");
+ cookie->start = strchr(cookie->path, '\0');
+
+ return (tio_iter(iterp, cookie, &dev_cu_functions));
+ } else if (errno != ENOENT) {
+ msg((ll_error, "unknown error %d while opening /dev: "
+ "%s", errno, strerror(errno)));
+ return tio_error_unknown;
+ }
+
+ /* Wow, really, the two functions have failed? Maybe the system uses
+ * another directory name for `/dev`… anyway, we don't know, so let's
+ * just say we haven't found a method that works for the current
+ * system. */
+
+ msg((ll_error, "none of the serial ports listing methods seem to "
+ "be applicable… how about contributing?"));
+ return (tio_error_op);
+}
+
+#endif
diff --git a/lib/system/unix/open.c b/lib/system/unix/open.c
new file mode 100644
index 0000000..c6c2e5d
--- /dev/null
+++ b/lib/system/unix/open.c
@@ -0,0 +1,35 @@
+#include "internals.h"
+#ifndef LIBTIO_DISABLED_UNIX
+
+TIO_HOOK(int) tio_unix_sleep(void *cookie, unsigned long ms)
+{
+ struct timespec requested_timestamp;
+
+ (void)cookie;
+
+ requested_timestamp.tv_sec = ms / 1000;
+ requested_timestamp.tv_nsec = (ms % 1000) * 1000000;
+ nanosleep(&requested_timestamp, NULL);
+ return (tio_ok);
+}
+
+TIO_LOCAL_DATA(tio_system_functions_t) unix_system_functions = {
+ (tio_close_t *)NULL,
+
+ (tio_open_usb_stream_t *)NULL,
+ (tio_list_usb_devices_t *)NULL,
+
+ (tio_open_serial_stream_t *)&tio_unix_open_serial_port,
+ (tio_list_serial_ports_t *)&tio_unix_list_serial_ports,
+
+ (tio_sleep_t *)&tio_unix_sleep,
+ (tio_get_timer_t *)NULL
+};
+
+TIO_EXTERN(int) tio_open_unix_system(tio_system_t **systemp)
+{
+ return (tio_open_system(systemp, NULL,
+ TIO_OPENFLAG_SYSTEM_ALL, &unix_system_functions));
+}
+
+#endif
diff --git a/lib/stream/builtin/unix.c b/lib/system/unix/stream.c
index e187f30..f271afc 100644
--- a/lib/stream/builtin/unix.c
+++ b/lib/system/unix/stream.c
@@ -1,13 +1,8 @@
-#include "../internals.h"
+#include "internals.h"
#ifndef LIBTIO_DISABLED_UNIX
-# include <sys/stat.h>
-# include <sys/ioctl.h>
-# include <fcntl.h>
-# include <unistd.h>
-# include <errno.h>
-# include <termios.h>
-/* `unix_get_attrs()`: get the serial attributes on a given file descriptor. */
+/* `unix_get_attrs()`: get the serial attributes on a given file
+ * descriptor. */
# define SET_MASK(MASK, VALUE) \
{ \
@@ -432,9 +427,9 @@ TIO_LOCAL_DATA(tio_serial_functions_t const) unix_serial_functions = {
* Open the stream.
* --- */
-/* `tio_open_unix_file()`: open the UNIX stream from a file descriptor. */
+/* `tio_unix_open_file()`: open the UNIX stream from a file descriptor. */
-TIO_EXTERN(int) tio_open_unix_file(tio_stream_t **streamp, int fd, int cl)
+TIO_EXTERN(int) tio_unix_open_file(tio_stream_t **streamp, int fd, int cl)
{
cookie_t *cookie = NULL;
unsigned int mode = TIO_OPENFLAG_READ | TIO_OPENFLAG_WRITE
@@ -483,10 +478,10 @@ fail:
return (err);
}
-/* `tio_open_unix_serial()`: open a serial stream using a file descriptor
- * representing a serial port. */
+/* `tio_unix_open_serial_file()`: open a serial stream using a file
+ * descriptor representing a serial port. */
-TIO_EXTERN(int) tio_open_unix_serial(tio_stream_t **streamp,
+TIO_EXTERN(int) tio_unix_open_serial_file(tio_stream_t **streamp,
int fd, int cl)
{
cookie_t *cookie = NULL;
@@ -544,10 +539,13 @@ fail:
/* `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)
+TIO_EXTERN(int) tio_open_unix_serial_port(void *cookie,
+ tio_stream_t **streamp, char const *path,
+ tio_serial_attrs_t const *attrs)
{
- int fd;
+ int fd, err;
+
+ (void)cookie;
fd = open(path, O_NOCTTY | O_RDWR);
if (fd < 0) switch (errno) {
@@ -567,7 +565,25 @@ TIO_EXTERN(int) tio_open_unix_serial_port(tio_stream_t **streamp,
return (tio_error_unknown);
}
- return (tio_open_unix_serial(streamp, fd, 1));
+ err = tio_unix_open_serial_file(streamp, fd, 1);
+ if (err)
+ return (err);
+
+ /* Okay, we'll just set the attributes up directly using the stream
+ * interface, #yolo. */
+
+ err = tio_set_serial_attrs(*streamp, attrs, TIO_SERIALFLAG_ALL);
+ if (err) {
+ tio_close(*streamp);
+ *streamp = NULL;
+
+ msg((ll_error, "set serial attrs returned error %s, "
+ "giving up stream creating operation.", tio_error_name(err)));
+
+ return (tio_error_unknown);
+ }
+
+ return (tio_ok);
}
#endif
diff --git a/lib/system/unix/timer.c b/lib/system/unix/timer.c
new file mode 100644
index 0000000..fe0979c
--- /dev/null
+++ b/lib/system/unix/timer.c
@@ -0,0 +1,57 @@
+#include "internals.h"
+#ifndef LIBTIO_DISABLED_UNIX
+
+TIO_STRUCT(cookie, cookie_t)
+
+struct cookie {
+ clockid_t clk_id;
+ struct timespec initial;
+};
+
+TIO_HOOK(void) free_timer(cookie_t *timer)
+{
+ tio_free(timer);
+}
+
+TIO_HOOK(int) get_spent_time(cookie_t *timer,
+ unsigned long *spent)
+{
+ struct timespec ts;
+
+ if (clock_gettime(timer->clk_id, &ts) < 0)
+ return (tio_error_unknown);
+
+ *spent = (ts.tv_sec - timer->initial.tv_sec) * 1000
+ + (ts.tv_nsec - timer->initial.tv_nsec) / 1000000;
+ return (tio_ok);
+}
+
+TIO_LOCAL_DATA(tio_timer_functions_t const) timer_functions = {
+ (tio_free_timer_t *)&free_timer,
+ (tio_get_spent_time_t *)&get_spent_time
+};
+
+TIO_EXTERN(int) tio_unix_open_timer(void *scookie, tio_timer_t **timerp)
+{
+ cookie_t *cookie;
+
+ (void)scookie;
+
+ if (!(cookie = tio_alloc(1, sizeof(*cookie))))
+ return (tio_error_alloc);
+
+#ifdef __linux__
+ cookie->clk_id = CLOCK_MONOTONIC_COARSE;
+#else
+ cookie->clk_id = CLOCK_MONOTONIC;
+#endif
+
+ if (clock_gettime(cookie->clk_id, &cookie->initial) < 0) {
+ tio_free(cookie);
+ return (tio_error_unknown);
+ }
+
+ return (tio_open_timer(timerp, cookie, &timer_functions));
+}
+
+#endif
diff --git a/lib/system/unix/utils.c b/lib/system/unix/utils.c
new file mode 100644
index 0000000..cf4869d
--- /dev/null
+++ b/lib/system/unix/utils.c
@@ -0,0 +1,22 @@
+#include "internals.h"
+#ifndef LIBTIO_DISABLED_UNIX
+
+/* `tio_unix_path_max()`: get the maximum path size. */
+
+TIO_EXTERN(size_t) tio_unix_path_max(void)
+{
+ ssize_t path_max;
+
+#ifdef PATH_MAX
+ path_max = PATH_MAX;
+#else
+ path_max = pathconf("/", _PC_PATH_MAX);
+ if (path_max <= 0)
+ path_max = 4096;
+#endif
+ ++path_max;
+
+ return ((size_t)path_max);
+}
+
+#endif
diff --git a/lib/system/windows/internals.h b/lib/system/windows/internals.h
new file mode 100644
index 0000000..24fdaab
--- /dev/null
+++ b/lib/system/windows/internals.h
@@ -0,0 +1,30 @@
+#ifndef LOCAL_WINDOWS_INTERNALS_H
+# define LOCAL_WINDOWS_INTERNALS_H 20190725
+# include "../../internals.h"
+# ifndef LIBTIO_DISABLED_WINDOWS
+
+/* If you need to redefine the Windows minimal version, redefine it here
+ * before the internal header inclusion. */
+
+# include <setupapi.h>
+# include <usbiodef.h>
+# include <winerror.h>
+
+TIO_EXTERN(void) tio_win_log_error
+ OF((char const *tio__func_name, DWORD tio__code));
+
+TIO_EXTERN(int) tio_win_open_file_handle
+ OF((tio_stream_t **tio__streamp, HANDLE tio__handle, int tio__cl));
+TIO_EXTERN(int) tio_win_open_serial_port
+ OF((tio_stream_t **tio__streamp, char const *tio__path));
+TIO_EXTERN(int) tio_win_open_serial_handle
+ OF((tio_stream_t **tio__streamp, HANDLE tio__handle, int tio__cl));
+
+TIO_EXTERN(int) tio_win_list_serial_ports
+ OF((tio_iter_t **tio__iterp));
+
+TIO_EXTERN(int) tio_win_sleep
+ OF((unsigned long ms));
+
+# endif
+#endif
diff --git a/lib/serial/builtin/windows.c b/lib/system/windows/list_serial.c
index 87dc22b..569ebbb 100644
--- a/lib/serial/builtin/windows.c
+++ b/lib/system/windows/list_serial.c
@@ -6,28 +6,6 @@
# define SERIAL_COMM_HKEY "HARDWARE\\DEVICEMAP\\SERIALCOMM"
/* ---
- * Utilities.
- * --- */
-
-/* `win_log_error()`: log an error with its description. */
-
-TIO_LOCAL(void) win_log_error(char const *function_name, DWORD code)
-{
- char error_buffer[1024];
- DWORD buffer_size;
-
- buffer_size = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
- NULL, code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
- error_buffer, 1023, NULL);
- error_buffer[buffer_size] = '\0';
-
- ifmsg(!buffer_size, ((ll_error, "%s returned error 0x%08lX occurred.",
- function_name, code)))
- elsemsg((ll_error, "%s: error 0x%08lX occurred: %s.",
- function_name, code, error_buffer))
-}
-
-/* ---
* Iterator callbacks.
* --- */
@@ -63,8 +41,9 @@ TIO_HOOK(int) next_serial_port(cookie_t *cookie, char const **ptr)
curval = cookie->value_size;
curdata = cookie->data_size;
- switch ((werr = RegEnumValue(cookie->hkey, cookie->i++, cookie->value,
- &curval, NULL, &type, (BYTE *)cookie->data, &curdata))) {
+ switch ((werr = RegEnumValue(cookie->hkey, cookie->i++,
+ cookie->value, &curval, NULL, &type, (BYTE *)cookie->data,
+ &curdata))) {
case 0:
/* Nothing wrong, check what's next. */
@@ -131,9 +110,9 @@ TIO_LOCAL_DATA(tio_iter_functions_t const) serial_listing_functions = {
* Open the iterator.
* --- */
-/* `tio_list_windows_serial_ports()`: list windows serial ports. */
+/* `tio_win_list_serial_ports()`: list windows serial ports. */
-TIO_EXTERN(int) tio_list_windows_serial_ports(tio_iter_t **iterp)
+TIO_EXTERN(int) tio_win_list_serial_ports(tio_iter_t **iterp)
{
cookie_t *cookie;
DWORD werr, value_size, data_size;
diff --git a/lib/system/windows/open.c b/lib/system/windows/open.c
new file mode 100644
index 0000000..0d0ed59
--- /dev/null
+++ b/lib/system/windows/open.c
@@ -0,0 +1,23 @@
+#include "internals.h"
+#ifndef LIBTIO_DISABLED_WINDOWS
+
+TIO_LOCAL_DATA(tio_system_functions_t) win_system_functions = {
+ (tio_close_t *)NULL,
+
+ (tio_open_usb_stream_t *)NULL,
+ (tio_list_usb_devices_t *)NULL,
+
+ (tio_open_serial_stream_t *)NULL,
+ (tio_list_serial_ports_t *)NULL,
+
+ (tio_sleep_t *)&tio_win_sleep,
+ (tio_get_timer_t *)NULL
+};
+
+TIO_EXTERN(int) tio_open_win_system(tio_system_t **systemp)
+{
+ return (tio_open_system(&systemp, NULL,
+ TIO_OPENFLAG_SYSTEM_ALL, &win_system_functions));
+}
+
+#endif
diff --git a/lib/system/windows/sleep.c b/lib/system/windows/sleep.c
new file mode 100644
index 0000000..f8ed0a3
--- /dev/null
+++ b/lib/system/windows/sleep.c
@@ -0,0 +1,13 @@
+/* If you need to redefine the Windows minimal version, redefine it here
+ * before the internal header inclusion. */
+
+#include "internals.h"
+#ifndef LIBTIO_DISABLED_WINDOWS
+
+TIO_EXTERN(int) tio_win_sleep(unsigned long ms)
+{
+ Sleep(ms);
+ return (tio_ok);
+}
+
+#endif
diff --git a/lib/stream/builtin/windows.c b/lib/system/windows/stream.c
index e536f57..ce69458 100644
--- a/lib/stream/builtin/windows.c
+++ b/lib/system/windows/stream.c
@@ -1,29 +1,5 @@
-/* If you need to redefine the Windows minimal version, redefine it here
- * before the internal header inclusion. */
-
-#include "../internals.h"
+#include "internals.h"
#ifndef LIBTIO_DISABLED_WINDOWS
-# include <setupapi.h>
-# include <usbiodef.h>
-# include <winerror.h>
-
-/* `win_log_error()`: log an error with its description. */
-
-TIO_LOCAL(void) win_log_error(char const *function_name, DWORD code)
-{
- char error_buffer[1024];
- DWORD buffer_size;
-
- buffer_size = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
- NULL, code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
- error_buffer, 1023, NULL);
- error_buffer[buffer_size] = '\0';
-
- ifmsg(!buffer_size, ((ll_error, "%s returned error 0x%08lX occurred.",
- function_name, code)))
- elsemsg((ll_error, "%s: error 0x%08lX occurred: %s.",
- function_name, code, error_buffer))
-}
/* `win_invalid_handle()`: check if a handle is valid. */
@@ -459,7 +435,7 @@ TIO_LOCAL_DATA(tio_serial_functions_t const) win_serial_functions = {
/* `tio_open_windows_file_handle()`: open a generic Windows stream out of a
* file handle. */
-TIO_EXTERN(int) tio_open_windows_file_handle(tio_stream_t **streamp,
+TIO_EXTERN(int) tio_win_open_file_handle(tio_stream_t **streamp,
HANDLE handle, int cl)
{
cookie_t *cookie = NULL;
@@ -520,7 +496,7 @@ fail:
/* `tio_open_windows_serial_handle()`: open a generic Windows stream out of a
* handle. */
-TIO_EXTERN(int) tio_open_windows_serial_handle(tio_stream_t **streamp,
+TIO_EXTERN(int) tio_win_open_serial_handle(tio_stream_t **streamp,
HANDLE handle, int cl)
{
cookie_t *cookie = NULL;
@@ -570,7 +546,7 @@ fail:
/* `tio_open_windows_serial_port()`: open a serial port using the path. */
-TIO_EXTERN(int) tio_open_windows_serial_port(tio_stream_t **streamp,
+TIO_EXTERN(int) tio_win_open_serial_port(tio_stream_t **streamp,
char const *path)
{
HANDLE handle = INVALID_HANDLE_VALUE;
diff --git a/lib/system/windows/utils.c b/lib/system/windows/utils.c
new file mode 100644
index 0000000..a4c009b
--- /dev/null
+++ b/lib/system/windows/utils.c
@@ -0,0 +1,22 @@
+#include "internals.h"
+#ifndef LIBTIO_DISABLED_WINDOWS
+
+/* `tio_win_log_error()`: log an error with its description. */
+
+TIO_EXTERN(void) tio_win_log_error(char const *function_name, DWORD code)
+{
+ char error_buffer[1024];
+ DWORD buffer_size;
+
+ buffer_size = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL, code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ error_buffer, 1023, NULL);
+ error_buffer[buffer_size] = '\0';
+
+ ifmsg(!buffer_size, ((ll_error, "%s returned error 0x%08lX occurred.",
+ function_name, code)))
+ elsemsg((ll_error, "%s: error 0x%08lX occurred: %s.",
+ function_name, code, error_buffer))
+}
+
+#endif
diff --git a/lib/usb/list.c b/lib/usb/list.c
deleted file mode 100644
index e03edf2..0000000
--- a/lib/usb/list.c
+++ /dev/null
@@ -1,19 +0,0 @@
-#include "../internals.h"
-
-typedef TIO_EXTERN_TYPE(int) udl_func
- OF((tio_iter_t **));
-
-/* `udl_candidates`: candidates to USB devices listing. */
-
-TIO_LOCAL_DATA(udl_func * const) udl_candidates[] = {
-#ifndef LIBTIO_DISABLED_LIBUSB
- &tio_list_libusb_devices,
-#endif
-
- NULL
-};
-
-/* `tio_list_serial_ports()`: list the serial ports, in an agnostic way. */
-
-TIO_EXTERN(int) tio_list_usb_devices(tio_iter_t **iterp)
- CANDIDATE_FUNC_BODY(udl_func, udl_candidates, (iterp))