diff --git a/configure.ac b/configure.ac index a48b734..d2f86b8 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,6 @@ # Versioning. m4_define([dc_version_major],[0]) -m4_define([dc_version_minor],[6]) +m4_define([dc_version_minor],[7]) m4_define([dc_version_micro],[0]) m4_define([dc_version_suffix],[devel-Subsurface-branch]) m4_define([dc_version],dc_version_major.dc_version_minor.dc_version_micro[]m4_ifset([dc_version_suffix],-[dc_version_suffix])) diff --git a/doc/man/dc_parser_get_field.3 b/doc/man/dc_parser_get_field.3 index 7d9e54e..2b276a1 100644 --- a/doc/man/dc_parser_get_field.3 +++ b/doc/man/dc_parser_get_field.3 @@ -172,8 +172,10 @@ for gauge (i.e., running as a record and not computing, say, decompression events), .Dv DC_DIVEMODE_OC for standard open-circuit diving, and -.Dv DC_DIVEMODE_CC -for closed-circuit +.Dv DC_DIVEMODE_CCR +and +.Dv DC_DIVEMODE_SCR +for respectively closed circuit and semi closed circuit .Dq rebreather diving. .El diff --git a/examples/output_xml.c b/examples/output_xml.c index 5153fc8..1e9c569 100644 --- a/examples/output_xml.c +++ b/examples/output_xml.c @@ -367,7 +367,7 @@ dctool_xml_output_write (dctool_output_t *abstract, dc_parser_t *parser, const u } if (status != DC_STATUS_UNSUPPORTED) { - const char *names[] = {"freedive", "gauge", "oc", "cc"}; + const char *names[] = {"freedive", "gauge", "oc", "ccr", "scr"}; fprintf (output->ostream, "%s\n", names[divemode]); } diff --git a/include/libdivecomputer/Makefile.am b/include/libdivecomputer/Makefile.am index e666f61..00926d0 100644 --- a/include/libdivecomputer/Makefile.am +++ b/include/libdivecomputer/Makefile.am @@ -7,6 +7,7 @@ libdivecomputer_HEADERS = \ buffer.h \ descriptor.h \ iterator.h \ + iostream.h \ device.h \ parser.h \ datetime.h \ diff --git a/include/libdivecomputer/custom_io.h b/include/libdivecomputer/custom_io.h index 14a66ca..1e310b9 100644 --- a/include/libdivecomputer/custom_io.h +++ b/include/libdivecomputer/custom_io.h @@ -1,67 +1,14 @@ #ifndef CUSTOM_IO_H #define CUSTOM_IO_H +#include + #include "common.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ -// Verbatim copy from src/serial.h - -#ifndef __SERIAL_TYPES__ -#define __SERIAL_TYPES__ -// Don't re-declare when we're internal -/** - * The parity checking scheme. - */ -typedef enum dc_parity_t { - DC_PARITY_NONE, /**< No parity */ - DC_PARITY_ODD, /**< Odd parity */ - DC_PARITY_EVEN, /**< Even parity */ - DC_PARITY_MARK, /**< Mark parity (always 1) */ - DC_PARITY_SPACE /**< Space parity (alwasy 0) */ -} dc_parity_t; - -/** - * The number of stop bits. - */ -typedef enum dc_stopbits_t { - DC_STOPBITS_ONE, /**< 1 stop bit */ - DC_STOPBITS_ONEPOINTFIVE, /**< 1.5 stop bits*/ - DC_STOPBITS_TWO /**< 2 stop bits */ -} dc_stopbits_t; - -/** - * The flow control. - */ -typedef enum dc_flowcontrol_t { - DC_FLOWCONTROL_NONE, /**< No flow control */ - DC_FLOWCONTROL_HARDWARE, /**< Hardware (RTS/CTS) flow control */ - DC_FLOWCONTROL_SOFTWARE /**< Software (XON/XOFF) flow control */ -} dc_flowcontrol_t; - -/** - * The direction of the data transmission. - */ -typedef enum dc_direction_t { - DC_DIRECTION_INPUT = 0x01, /**< Input direction */ - DC_DIRECTION_OUTPUT = 0x02, /**< Output direction */ - DC_DIRECTION_ALL = DC_DIRECTION_INPUT | DC_DIRECTION_OUTPUT /**< All directions */ -} dc_direction_t; - -/** - * The serial line signals. - */ -typedef enum dc_line_t { - DC_LINE_DCD = 0x01, /**< Data carrier detect */ - DC_LINE_CTS = 0x02, /**< Clear to send */ - DC_LINE_DSR = 0x04, /**< Data set ready */ - DC_LINE_RNG = 0x08, /**< Ring indicator */ -} dc_line_t; - -#endif /* __SERIAL_TYPES__ */ - struct dc_context_t; struct dc_user_device_t; diff --git a/include/libdivecomputer/iostream.h b/include/libdivecomputer/iostream.h new file mode 100644 index 0000000..dab5daf --- /dev/null +++ b/include/libdivecomputer/iostream.h @@ -0,0 +1,290 @@ +/* + * libdivecomputer + * + * Copyright (C) 2016 Jef Driesen + * + * This library 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 2.1 of the License, or (at your option) any later version. + * + * This library 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 this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#ifndef DC_IOSTREAM_H +#define DC_IOSTREAM_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * Opaque object representing a I/O stream. + */ +typedef struct dc_iostream_t dc_iostream_t; + +/** + * The parity checking scheme. + */ +typedef enum dc_parity_t { + DC_PARITY_NONE, /**< No parity */ + DC_PARITY_ODD, /**< Odd parity */ + DC_PARITY_EVEN, /**< Even parity */ + DC_PARITY_MARK, /**< Mark parity (always 1) */ + DC_PARITY_SPACE /**< Space parity (alwasy 0) */ +} dc_parity_t; + +/** + * The number of stop bits. + */ +typedef enum dc_stopbits_t { + DC_STOPBITS_ONE, /**< 1 stop bit */ + DC_STOPBITS_ONEPOINTFIVE, /**< 1.5 stop bits*/ + DC_STOPBITS_TWO /**< 2 stop bits */ +} dc_stopbits_t; + +/** + * The flow control. + */ +typedef enum dc_flowcontrol_t { + DC_FLOWCONTROL_NONE, /**< No flow control */ + DC_FLOWCONTROL_HARDWARE, /**< Hardware (RTS/CTS) flow control */ + DC_FLOWCONTROL_SOFTWARE /**< Software (XON/XOFF) flow control */ +} dc_flowcontrol_t; + +/** + * The direction of the data transmission. + */ +typedef enum dc_direction_t { + DC_DIRECTION_INPUT = 0x01, /**< Input direction */ + DC_DIRECTION_OUTPUT = 0x02, /**< Output direction */ + DC_DIRECTION_ALL = DC_DIRECTION_INPUT | DC_DIRECTION_OUTPUT /**< All directions */ +} dc_direction_t; + +/** + * The line signals. + */ +typedef enum dc_line_t { + DC_LINE_DCD = 0x01, /**< Data carrier detect */ + DC_LINE_CTS = 0x02, /**< Clear to send */ + DC_LINE_DSR = 0x04, /**< Data set ready */ + DC_LINE_RNG = 0x08, /**< Ring indicator */ +} dc_line_t; + +/** + * Set the read timeout. + * + * There are three distinct modes available: + * + * 1. Blocking (timeout < 0): + * + * The read operation is blocked until all the requested bytes have + * been received. If the requested number of bytes does not arrive, + * the operation will block forever. + * + * 2. Non-blocking (timeout == 0): + * + * The read operation returns immediately with the bytes that have + * already been received, even if no bytes have been received. + * + * 3. Timeout (timeout > 0): + * + * The read operation is blocked until all the requested bytes have + * been received. If the requested number of bytes does not arrive + * within the specified amount of time, the operation will return + * with the bytes that have already been received. + * + * @param[in] iostream A valid I/O stream. + * @param[in] timeout The timeout in milliseconds. + * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code + * on failure. + */ +dc_status_t +dc_iostream_set_timeout (dc_iostream_t *iostream, int timeout); + +/** + * Set the receive latency. + * + * The effect of this setting is highly platform and driver specific. On + * Windows it does nothing at all, on Linux it controls the low latency + * flag (e.g. only zero vs non-zero latency), and on Mac OS X it sets + * the receive latency as requested. + * + * @param[in] iostream A valid I/O stream. + * @param[in] value The latency in milliseconds. + * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code + * on failure. + */ +dc_status_t +dc_iostream_set_latency (dc_iostream_t *iostream, unsigned int value); + +/** + * Set the state of the half duplex emulation. + * + * @param[in] iostream A valid I/O stream. + * @param[in] value The half duplex state. + * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code + * on failure. + */ +dc_status_t +dc_iostream_set_halfduplex (dc_iostream_t *iostream, unsigned int value); + +/** + * Set the state of the break condition. + * + * @param[in] iostream A valid I/O stream. + * @param[in] value The break condition state. + * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code + * on failure. + */ +dc_status_t +dc_iostream_set_break (dc_iostream_t *iostream, unsigned int value); + +/** + * Set the state of the DTR line. + * + * @param[in] iostream A valid I/O stream. + * @param[in] value The DTR line state. + * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code + * on failure. + */ +dc_status_t +dc_iostream_set_dtr (dc_iostream_t *iostream, unsigned int value); + +/** + * Set the state of the RTS line. + * + * @param[in] iostream A valid I/O stream. + * @param[in] value The RTS line state. + * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code + * on failure. + */ +dc_status_t +dc_iostream_set_rts (dc_iostream_t *iostream, unsigned int value); + +/** + * Query the state of the line signals. + * + * @param[in] iostream A valid I/O stream. + * @param[out] value A location to store the bitmap with the state + * of the line signals. + * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code + * on failure. + */ +dc_status_t +dc_iostream_get_lines (dc_iostream_t *iostream, unsigned int *value); + +/** + * Query the number of available bytes in the input buffer. + * + * @param[in] iostream A valid I/O stream. + * @param[out] value A location to store the number of bytes in the + * input buffer. + * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code + * on failure. + */ +dc_status_t +dc_iostream_get_available (dc_iostream_t *iostream, size_t *value); + +/** + * Configure the line settings. + * + * @param[in] iostream A valid I/O stream. + * @param[in] baudrate The baud rate setting. + * @param[in] databits The number of data bits. + * @param[in] parity The parity setting. + * @param[in] stopbits The number of stop bits. + * @param[in] flowcontrol The flow control setting. + * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code + * on failure. + */ +dc_status_t +dc_iostream_configure (dc_iostream_t *iostream, unsigned int baudrate, unsigned int databits, dc_parity_t parity, dc_stopbits_t stopbits, dc_flowcontrol_t flowcontrol); + +/** + * Read data from the I/O stream. + * + * @param[in] iostream A valid I/O stream. + * @param[out] data The memory buffer to read the data into. + * @param[in] size The number of bytes to read. + * @param[out] actual An (optional) location to store the actual + * number of bytes transferred. + * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code + * on failure. + */ +dc_status_t +dc_iostream_read (dc_iostream_t *iostream, void *data, size_t size, size_t *actual); + +/** + * Write data to the I/O stream. + * + * @param[in] iostream A valid I/O stream. + * @param[in] data The memory buffer to write the data from. + * @param[in] size The number of bytes to write. + * @param[out] actual An (optional) location to store the actual + * number of bytes transferred. + * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code + * on failure. + */ +dc_status_t +dc_iostream_write (dc_iostream_t *iostream, const void *data, size_t size, size_t *actual); + +/** + * Flush the internal output buffer and wait until the data has been + * transmitted. + * + * @param[in] iostream A valid I/O stream. + * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code + * on failure. + */ +dc_status_t +dc_iostream_flush (dc_iostream_t *iostream); + +/** + * Discards all data from the internal buffers. + * + * @param[in] iostream A valid I/O stream. + * @param[in] direction The direction of the buffer(s). + * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code + * on failure. + */ +dc_status_t +dc_iostream_purge (dc_iostream_t *iostream, dc_direction_t direction); + +/** + * Suspend execution of the current thread for the specified amount of + * time. + * + * @param[in] iostream A valid I/O stream. + * @param[in] milliseconds The number of milliseconds to sleep. + * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code + * on failure. + */ +dc_status_t +dc_iostream_sleep (dc_iostream_t *iostream, unsigned int milliseconds); + +/** + * Close the I/O stream and free all resources. + * + * @param[in] iostream A valid I/O stream. + * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code + * on failure. + */ +dc_status_t +dc_iostream_close (dc_iostream_t *iostream); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* DC_IOSTREAM_H */ diff --git a/include/libdivecomputer/parser.h b/include/libdivecomputer/parser.h index 305a136..db38da8 100644 --- a/include/libdivecomputer/parser.h +++ b/include/libdivecomputer/parser.h @@ -132,9 +132,13 @@ typedef enum dc_divemode_t { DC_DIVEMODE_FREEDIVE, DC_DIVEMODE_GAUGE, DC_DIVEMODE_OC, /* Open circuit */ - DC_DIVEMODE_CC /* Closed circuit */ + DC_DIVEMODE_CCR, /* Closed circuit rebreather */ + DC_DIVEMODE_SCR /* Semi-closed circuit rebreather */ } dc_divemode_t; +/* For backwards compatibility */ +#define DC_DIVEMODE_CC DC_DIVEMODE_CCR + typedef enum dc_deco_type_t { DC_DECO_NDL, DC_DECO_SAFETYSTOP, diff --git a/msvc/libdivecomputer.vcproj b/msvc/libdivecomputer.vcproj index 242276a..c54c3d7 100644 --- a/msvc/libdivecomputer.vcproj +++ b/msvc/libdivecomputer.vcproj @@ -246,6 +246,10 @@ RelativePath="..\src\cressi_leonardo_parser.c" > + + @@ -294,6 +298,10 @@ RelativePath="..\src\ihex.c" > + + @@ -418,6 +426,10 @@ RelativePath="..\src\shearwater_predator_parser.c" > + + @@ -572,6 +584,10 @@ RelativePath="..\src\cressi_leonardo.h" > + + @@ -624,6 +640,14 @@ RelativePath="..\src\ihex.h" > + + + + @@ -748,6 +772,10 @@ RelativePath="..\src\shearwater_predator.h" > + + diff --git a/src/Makefile.am b/src/Makefile.am index 1545bc7..49ae4e7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -17,6 +17,7 @@ endif libdivecomputer_la_SOURCES = \ version.c \ descriptor.c \ + iostream-private.h iostream.c \ iterator-private.h iterator.c \ common-private.h common.c \ context-private.h context.c \ @@ -77,9 +78,12 @@ else libdivecomputer_la_SOURCES += serial.h serial_posix.c endif +libdivecomputer_la_SOURCES += socket.h socket.c libdivecomputer_la_SOURCES += irda.h irda.c libdivecomputer_la_SOURCES += usbhid.h usbhid.c libdivecomputer_la_SOURCES += bluetooth.h bluetooth.c +libdivecomputer_la_SOURCES += custom.h custom.c +libdivecomputer_la_SOURCES += custom_io.c if OS_WIN32 libdivecomputer_la_SOURCES += libdivecomputer.rc @@ -97,7 +101,7 @@ libdivecomputer.lo: revision.h FORCE: $(top_srcdir)/revision: FORCE - @if (test -d $(top_srcdir)/.git && cd $(top_srcdir) \ + @if (test -e $(top_srcdir)/.git && cd $(top_srcdir) \ && git rev-parse --verify HEAD) > revision-t 2>/dev/null \ && ! cmp -s revision-t $@; then \ mv -f revision-t $@; \ diff --git a/src/atomics_cobalt_parser.c b/src/atomics_cobalt_parser.c index a55e672..7d30ca3 100644 --- a/src/atomics_cobalt_parser.c +++ b/src/atomics_cobalt_parser.c @@ -214,7 +214,7 @@ atomics_cobalt_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, un *((dc_divemode_t *) value) = DC_DIVEMODE_OC; break; case 1: // Closed Circuit - *((dc_divemode_t *) value) = DC_DIVEMODE_CC; + *((dc_divemode_t *) value) = DC_DIVEMODE_CCR; break; default: return DC_STATUS_DATAFORMAT; diff --git a/src/bluetooth.c b/src/bluetooth.c index 01a3e96..b139892 100644 --- a/src/bluetooth.c +++ b/src/bluetooth.c @@ -25,22 +25,14 @@ #include // malloc, free +#include "socket.h" + #ifdef _WIN32 -#define NOGDI -#include -#include #ifdef HAVE_WS2BTH_H #define BLUETOOTH #include #endif #else -#include // errno -#include // close -#include // socket, getsockopt -#include // socket, getsockopt -#include // select -#include // ioctl -#include #ifdef HAVE_BLUEZ #define BLUETOOTH #include @@ -51,36 +43,10 @@ #endif #include "bluetooth.h" + #include "common-private.h" #include "context-private.h" - -#ifdef _WIN32 -typedef int s_ssize_t; -typedef DWORD s_errcode_t; -#define S_ERRNO WSAGetLastError () -#define S_EINTR WSAEINTR -#define S_EAGAIN WSAEWOULDBLOCK -#define S_ENOMEM WSA_NOT_ENOUGH_MEMORY -#define S_EINVAL WSAEINVAL -#define S_EACCES WSAEACCES -#define S_EAFNOSUPPORT WSAEAFNOSUPPORT -#define S_INVALID INVALID_SOCKET -#define S_IOCTL ioctlsocket -#define S_CLOSE closesocket -#else -typedef ssize_t s_ssize_t; -typedef int s_errcode_t; -#define S_ERRNO errno -#define S_EINTR EINTR -#define S_EAGAIN EAGAIN -#define S_ENOMEM ENOMEM -#define S_EINVAL EINVAL -#define S_EACCES EACCES -#define S_EAFNOSUPPORT EAFNOSUPPORT -#define S_INVALID -1 -#define S_IOCTL ioctl -#define S_CLOSE close -#endif +#include "iostream-private.h" #ifdef _WIN32 #define DC_ADDRESS_FORMAT "%012I64X" @@ -93,34 +59,27 @@ typedef int s_errcode_t; #define MAX_DEVICES 255 #define MAX_PERIODS 8 -struct dc_bluetooth_t { - dc_context_t *context; -#ifdef _WIN32 - SOCKET fd; -#else - int fd; -#endif - int timeout; -}; +#define ISINSTANCE(device) dc_iostream_isinstance((device), &dc_bluetooth_vtable) #ifdef BLUETOOTH -static dc_status_t -syserror(s_errcode_t errcode) -{ - switch (errcode) { - case S_EINVAL: - return DC_STATUS_INVALIDARGS; - case S_ENOMEM: - return DC_STATUS_NOMEMORY; - case S_EACCES: - return DC_STATUS_NOACCESS; - case S_EAFNOSUPPORT: - return DC_STATUS_UNSUPPORTED; - default: - return DC_STATUS_IO; - } -} -#endif +static const dc_iostream_vtable_t dc_bluetooth_vtable = { + sizeof(dc_socket_t), + dc_socket_set_timeout, /* set_timeout */ + dc_socket_set_latency, /* set_latency */ + dc_socket_set_halfduplex, /* set_halfduplex */ + dc_socket_set_break, /* set_break */ + dc_socket_set_dtr, /* set_dtr */ + dc_socket_set_rts, /* set_rts */ + dc_socket_get_lines, /* get_lines */ + dc_socket_get_available, /* get_received */ + dc_socket_configure, /* configure */ + dc_socket_read, /* read */ + dc_socket_write, /* write */ + dc_socket_flush, /* flush */ + dc_socket_purge, /* purge */ + dc_socket_sleep, /* sleep */ + dc_socket_close, /* close */ +}; #ifdef HAVE_BLUEZ static dc_bluetooth_address_t @@ -147,75 +106,41 @@ dc_address_set (bdaddr_t *ba, dc_bluetooth_address_t address) } } #endif +#endif dc_status_t -dc_bluetooth_open (dc_bluetooth_t **out, dc_context_t *context) +dc_bluetooth_open (dc_iostream_t **out, dc_context_t *context) { #ifdef BLUETOOTH dc_status_t status = DC_STATUS_SUCCESS; - dc_bluetooth_t *device = NULL; + dc_socket_t *device = NULL; if (out == NULL) return DC_STATUS_INVALIDARGS; // Allocate memory. - device = (dc_bluetooth_t *) malloc (sizeof (dc_bluetooth_t)); + device = (dc_socket_t *) dc_iostream_allocate (context, &dc_bluetooth_vtable); if (device == NULL) { SYSERROR (context, S_ENOMEM); return DC_STATUS_NOMEMORY; } - // Library context. - device->context = context; - - // Default to blocking reads. - device->timeout = -1; - + // Open the socket. #ifdef _WIN32 - // Initialize the winsock dll. - WSADATA wsaData; - WORD wVersionRequested = MAKEWORD (2, 2); - int rc = WSAStartup (wVersionRequested, &wsaData); - if (rc != 0) { - SYSERROR (context, rc); - status = DC_STATUS_UNSUPPORTED; + status = dc_socket_open (&device->base, AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM); +#else + status = dc_socket_open (&device->base, AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); +#endif + if (status != DC_STATUS_SUCCESS) { goto error_free; } - // Confirm that the winsock dll supports version 2.2. - // Note that if the dll supports versions greater than 2.2 in addition to - // 2.2, it will still return 2.2 since that is the version we requested. - if (LOBYTE (wsaData.wVersion) != 2 || - HIBYTE (wsaData.wVersion) != 2) { - ERROR (context, "Incorrect winsock version."); - status = DC_STATUS_UNSUPPORTED; - goto error_wsacleanup; - } -#endif - - // Open the socket. -#ifdef _WIN32 - device->fd = socket (AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM); -#else - device->fd = socket (AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); -#endif - if (device->fd == S_INVALID) { - s_errcode_t errcode = S_ERRNO; - SYSERROR (context, errcode); - status = syserror(errcode); - goto error_wsacleanup; - } - - *out = device; + *out = (dc_iostream_t *) device; return DC_STATUS_SUCCESS; -error_wsacleanup: -#ifdef _WIN32 - WSACleanup (); error_free: -#endif - free (device); + dc_iostream_deallocate ((dc_iostream_t *) device); return status; #else return DC_STATUS_UNSUPPORTED; @@ -223,66 +148,12 @@ error_free: } dc_status_t -dc_bluetooth_close (dc_bluetooth_t *device) +dc_bluetooth_discover (dc_iostream_t *abstract, dc_bluetooth_callback_t callback, void *userdata) { #ifdef BLUETOOTH dc_status_t status = DC_STATUS_SUCCESS; - if (device == NULL) - return DC_STATUS_SUCCESS; - - // Terminate all send and receive operations. - shutdown (device->fd, 0); - - // Close the socket. - if (S_CLOSE (device->fd) != 0) { - s_errcode_t errcode = S_ERRNO; - SYSERROR (device->context, errcode); - dc_status_set_error(&status, syserror(errcode)); - } - -#ifdef _WIN32 - // Terminate the winsock dll. - if (WSACleanup () != 0) { - s_errcode_t errcode = S_ERRNO; - SYSERROR (device->context, errcode); - dc_status_set_error(&status, syserror(errcode)); - } -#endif - - // Free memory. - free (device); - - return status; -#else - return DC_STATUS_UNSUPPORTED; -#endif -} - -dc_status_t -dc_bluetooth_set_timeout (dc_bluetooth_t *device, int timeout) -{ -#ifdef BLUETOOTH - if (device == NULL) - return DC_STATUS_INVALIDARGS; - - INFO (device->context, "Timeout: value=%i", timeout); - - device->timeout = timeout; - - return DC_STATUS_SUCCESS; -#else - return DC_STATUS_UNSUPPORTED; -#endif -} - -dc_status_t -dc_bluetooth_discover (dc_bluetooth_t *device, dc_bluetooth_callback_t callback, void *userdata) -{ -#ifdef BLUETOOTH - dc_status_t status = DC_STATUS_SUCCESS; - - if (device == NULL) + if (!ISINSTANCE (abstract)) return DC_STATUS_INVALIDARGS; #ifdef _WIN32 @@ -299,8 +170,8 @@ dc_bluetooth_discover (dc_bluetooth_t *device, dc_bluetooth_callback_t callback, // No remote bluetooth devices found. status = DC_STATUS_SUCCESS; } else { - SYSERROR (device->context, errcode); - status = syserror(errcode); + SYSERROR (abstract->context, errcode); + status = dc_socket_syserror(errcode); } goto error_exit; } @@ -319,15 +190,15 @@ dc_bluetooth_discover (dc_bluetooth_t *device, dc_bluetooth_callback_t callback, if (errcode == WSA_E_NO_MORE || errcode == WSAENOMORE) { break; // No more results. } - SYSERROR (device->context, errcode); - status = syserror(errcode); + SYSERROR (abstract->context, errcode); + status = dc_socket_syserror(errcode); goto error_close; } if (pwsaResults->dwNumberOfCsAddrs == 0 || pwsaResults->lpcsaBuffer == NULL || pwsaResults->lpcsaBuffer->RemoteAddr.lpSockaddr == NULL) { - ERROR (device->context, "Invalid results returned"); + ERROR (abstract->context, "Invalid results returned"); status = DC_STATUS_IO; goto error_close; } @@ -336,7 +207,7 @@ dc_bluetooth_discover (dc_bluetooth_t *device, dc_bluetooth_callback_t callback, dc_bluetooth_address_t address = sa->btAddr; const char *name = (char *) pwsaResults->lpszServiceInstanceName; - INFO (device->context, "Discover: address=" DC_ADDRESS_FORMAT ", name=%s", address, name); + INFO (abstract->context, "Discover: address=" DC_ADDRESS_FORMAT ", name=%s", address, name); if (callback) callback (address, name, userdata); @@ -349,8 +220,8 @@ error_close: int dev = hci_get_route (NULL); if (dev < 0) { s_errcode_t errcode = S_ERRNO; - SYSERROR (device->context, errcode); - status = syserror(errcode); + SYSERROR (abstract->context, errcode); + status = dc_socket_syserror(errcode); goto error_exit; } @@ -358,8 +229,8 @@ error_close: int fd = hci_open_dev (dev); if (fd < 0) { s_errcode_t errcode = S_ERRNO; - SYSERROR (device->context, errcode); - status = syserror(errcode); + SYSERROR (abstract->context, errcode); + status = dc_socket_syserror(errcode); goto error_exit; } @@ -367,8 +238,8 @@ error_close: inquiry_info *devices = (inquiry_info *) malloc (MAX_DEVICES * sizeof(inquiry_info)); if (devices == NULL) { s_errcode_t errcode = S_ERRNO; - SYSERROR (device->context, errcode); - status = syserror(errcode); + SYSERROR (abstract->context, errcode); + status = dc_socket_syserror(errcode); goto error_close; } @@ -378,8 +249,8 @@ error_close: int ndevices = hci_inquiry (dev, MAX_PERIODS, MAX_DEVICES, NULL, &devices, IREQ_CACHE_FLUSH); if (ndevices < 0) { s_errcode_t errcode = S_ERRNO; - SYSERROR (device->context, errcode); - status = syserror(errcode); + SYSERROR (abstract->context, errcode); + status = dc_socket_syserror(errcode); goto error_free; } @@ -393,7 +264,7 @@ error_close: name = NULL; } - INFO (device->context, "Discover: address=" DC_ADDRESS_FORMAT ", name=%s", address, name); + INFO (abstract->context, "Discover: address=" DC_ADDRESS_FORMAT ", name=%s", address, name); if (callback) callback (address, name, userdata); } @@ -412,13 +283,15 @@ error_exit: } dc_status_t -dc_bluetooth_connect (dc_bluetooth_t *device, dc_bluetooth_address_t address, unsigned int port) +dc_bluetooth_connect (dc_iostream_t *abstract, dc_bluetooth_address_t address, unsigned int port) { #ifdef BLUETOOTH - if (device == NULL) + dc_socket_t *device = (dc_socket_t *) abstract; + + if (!ISINSTANCE (abstract)) return DC_STATUS_INVALIDARGS; - INFO (device->context, "Connect: address=" DC_ADDRESS_FORMAT ", port=%d", address, port); + INFO (abstract->context, "Connect: address=" DC_ADDRESS_FORMAT ", port=%d", address, port); #ifdef _WIN32 SOCKADDR_BTH sa; @@ -433,171 +306,7 @@ dc_bluetooth_connect (dc_bluetooth_t *device, dc_bluetooth_address_t address, un dc_address_set (&sa.rc_bdaddr, address); #endif - if (connect (device->fd, (struct sockaddr *) &sa, sizeof (sa)) != 0) { - s_errcode_t errcode = S_ERRNO; - SYSERROR (device->context, errcode); - return syserror(errcode); - } - - return DC_STATUS_SUCCESS; -#else - return DC_STATUS_UNSUPPORTED; -#endif -} - -dc_status_t -dc_bluetooth_get_available (dc_bluetooth_t *device, size_t *value) -{ -#ifdef BLUETOOTH - if (device == NULL) - return DC_STATUS_INVALIDARGS; - -#ifdef _WIN32 - unsigned long bytes = 0; -#else - int bytes = 0; -#endif - - if (S_IOCTL (device->fd, FIONREAD, &bytes) != 0) { - s_errcode_t errcode = S_ERRNO; - SYSERROR (device->context, errcode); - return syserror(errcode); - } - - if (value) - *value = bytes; - - return DC_STATUS_SUCCESS; -#else - return DC_STATUS_UNSUPPORTED; -#endif -} - -dc_status_t -dc_bluetooth_read (dc_bluetooth_t *device, void *data, size_t size, size_t *actual) -{ -#ifdef BLUETOOTH - dc_status_t status = DC_STATUS_SUCCESS; - size_t nbytes = 0; - - if (device == NULL) { - status = DC_STATUS_INVALIDARGS; - goto out_invalidargs; - } - - while (nbytes < size) { - fd_set fds; - FD_ZERO (&fds); - FD_SET (device->fd, &fds); - - struct timeval tvt; - if (device->timeout > 0) { - tvt.tv_sec = (device->timeout / 1000); - tvt.tv_usec = (device->timeout % 1000) * 1000; - } else if (device->timeout == 0) { - timerclear (&tvt); - } - - int rc = select (device->fd + 1, &fds, NULL, NULL, device->timeout >= 0 ? &tvt : NULL); - if (rc < 0) { - s_errcode_t errcode = S_ERRNO; - if (errcode == S_EINTR) - continue; // Retry. - SYSERROR (device->context, errcode); - status = syserror(errcode); - goto out; - } else if (rc == 0) { - break; // Timeout. - } - - s_ssize_t n = recv (device->fd, (char*) data + nbytes, size - nbytes, 0); - if (n < 0) { - s_errcode_t errcode = S_ERRNO; - if (errcode == S_EINTR || errcode == S_EAGAIN) - continue; // Retry. - SYSERROR (device->context, errcode); - status = syserror(errcode); - goto out; - } else if (n == 0) { - break; // EOF reached. - } - - nbytes += n; - } - - if (nbytes != size) { - status = DC_STATUS_TIMEOUT; - } - -out: - HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Read", (unsigned char *) data, nbytes); - -out_invalidargs: - if (actual) - *actual = nbytes; - - return status; -#else - return DC_STATUS_UNSUPPORTED; -#endif -} - -dc_status_t -dc_bluetooth_write (dc_bluetooth_t *device, const void *data, size_t size, size_t *actual) -{ -#ifdef BLUETOOTH - dc_status_t status = DC_STATUS_SUCCESS; - size_t nbytes = 0; - - if (device == NULL) { - status = DC_STATUS_INVALIDARGS; - goto out_invalidargs; - } - - while (nbytes < size) { - fd_set fds; - FD_ZERO (&fds); - FD_SET (device->fd, &fds); - - int rc = select (device->fd + 1, NULL, &fds, NULL, NULL); - if (rc < 0) { - s_errcode_t errcode = S_ERRNO; - if (errcode == S_EINTR) - continue; // Retry. - SYSERROR (device->context, errcode); - status = syserror(errcode); - goto out; - } else if (rc == 0) { - break; // Timeout. - } - - s_ssize_t n = send (device->fd, (const char *) data + nbytes, size - nbytes, 0); - if (n < 0) { - s_errcode_t errcode = S_ERRNO; - if (errcode == S_EINTR || errcode == S_EAGAIN) - continue; // Retry. - SYSERROR (device->context, errcode); - status = syserror(errcode); - goto out; - } else if (n == 0) { - break; // EOF. - } - - nbytes += n; - } - - if (nbytes != size) { - status = DC_STATUS_TIMEOUT; - } - -out: - HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Write", (const unsigned char *) data, nbytes); - -out_invalidargs: - if (actual) - *actual = nbytes; - - return status; + return dc_socket_connect (&device->base, (struct sockaddr *) &sa, sizeof (sa)); #else return DC_STATUS_UNSUPPORTED; #endif diff --git a/src/bluetooth.h b/src/bluetooth.h index d2e3868..1a8e947 100644 --- a/src/bluetooth.h +++ b/src/bluetooth.h @@ -24,16 +24,12 @@ #include #include +#include #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ -/** - * Opaque object representing a bluetooth connection. - */ -typedef struct dc_bluetooth_t dc_bluetooth_t; - /** * Bluetooth address (48 bits). */ @@ -55,118 +51,37 @@ typedef void (*dc_bluetooth_callback_t) (dc_bluetooth_address_t address, const c /** * Open an bluetooth connection. * - * @param[out] bluetooth A location to store the bluetooth connection. + * @param[out] iostream A location to store the bluetooth connection. * @param[in] context A valid context object. * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code * on failure. */ dc_status_t -dc_bluetooth_open (dc_bluetooth_t **bluetooth, dc_context_t *context); - -/** - * Close the bluetooth connection and free all resources. - * - * @param[in] bluetooth A valid bluetooth connection. - * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code - * on failure. - */ -dc_status_t -dc_bluetooth_close (dc_bluetooth_t *bluetooth); - -/** - * Set the read timeout. - * - * There are three distinct modes available: - * - * 1. Blocking (timeout < 0): - * - * The read operation is blocked until all the requested bytes have - * been received. If the requested number of bytes does not arrive, - * the operation will block forever. - * - * 2. Non-blocking (timeout == 0): - * - * The read operation returns immediately with the bytes that have - * already been received, even if no bytes have been received. - * - * 3. Timeout (timeout > 0): - * - * The read operation is blocked until all the requested bytes have - * been received. If the requested number of bytes does not arrive - * within the specified amount of time, the operation will return - * with the bytes that have already been received. - * - * @param[in] bluetooth A valid bluetooth connection. - * @param[in] timeout The timeout in milliseconds. - * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code - * on failure. - */ -dc_status_t -dc_bluetooth_set_timeout (dc_bluetooth_t *bluetooth, int timeout); +dc_bluetooth_open (dc_iostream_t **iostream, dc_context_t *context); /** * Enumerate the bluetooth devices. * - * @param[in] bluetooth A valid bluetooth connection. + * @param[in] iostream A valid bluetooth connection. * @param[in] callback The callback function to call. * @param[in] userdata User data to pass to the callback function. * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code * on failure. */ dc_status_t -dc_bluetooth_discover (dc_bluetooth_t *bluetooth, dc_bluetooth_callback_t callback, void *userdata); +dc_bluetooth_discover (dc_iostream_t *iostream, dc_bluetooth_callback_t callback, void *userdata); /** * Connect to an bluetooth device. * - * @param[in] bluetooth A valid bluetooth connection. + * @param[in] iostream A valid bluetooth connection. * @param[in] address The bluetooth device address. * @param[in] port The bluetooth port number. * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code * on failure. */ dc_status_t -dc_bluetooth_connect (dc_bluetooth_t *bluetooth, dc_bluetooth_address_t address, unsigned int port); - -/** - * Query the number of available bytes in the input buffer. - * - * @param[in] bluetooth A valid bluetooth connection. - * @param[out] value A location to store the number of bytes in - * the input buffer. - * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code - * on failure. - */ -dc_status_t -dc_bluetooth_get_available (dc_bluetooth_t *bluetooth, size_t *value); - -/** - * Read data from the bluetooth connection. - * - * @param[in] bluetooth A valid bluetooth connection. - * @param[out] data The memory buffer to read the data into. - * @param[in] size The number of bytes to read. - * @param[out] actual An (optional) location to store the actual - * number of bytes transferred. - * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code - * on failure. - */ -dc_status_t -dc_bluetooth_read (dc_bluetooth_t *bluetooth, void *data, size_t size, size_t *actual); - -/** - * Write data to the bluetooth connection. - * - * @param[in] bluetooth A valid bluetooth connection. - * @param[in] data The memory buffer to write the data from. - * @param[in] size The number of bytes to write. - * @param[out] actual An (optional) location to store the actual - * number of bytes transferred. - * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code - * on failure. - */ -dc_status_t -dc_bluetooth_write (dc_bluetooth_t *bluetooth, const void *data, size_t size, size_t *actual); +dc_bluetooth_connect (dc_iostream_t *iostream, dc_bluetooth_address_t address, unsigned int port); #ifdef __cplusplus } diff --git a/src/citizen_aqualand.c b/src/citizen_aqualand.c index 47ba87f..3af5d52 100644 --- a/src/citizen_aqualand.c +++ b/src/citizen_aqualand.c @@ -34,7 +34,7 @@ typedef struct citizen_aqualand_device_t { dc_device_t base; - dc_serial_t *port; + dc_iostream_t *iostream; unsigned char fingerprint[8]; } citizen_aqualand_device_t; @@ -73,40 +73,40 @@ citizen_aqualand_device_open (dc_device_t **out, dc_context_t *context, const ch } // Set the default values. - device->port = NULL; + device->iostream = NULL; memset (device->fingerprint, 0, sizeof (device->fingerprint)); // Open the device. - status = dc_serial_open (&device->port, context, name); + status = dc_serial_open (&device->iostream, context, name); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the serial port."); goto error_free; } // Set the serial communication protocol (4800 8N1). - status = dc_serial_configure (device->port, 4800, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); + status = dc_iostream_configure (device->iostream, 4800, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); goto error_close; } // Set the timeout for receiving data (1000ms). - status = dc_serial_set_timeout (device->port, 1000); + status = dc_iostream_set_timeout (device->iostream, 1000); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the timeout."); goto error_close; } // Make sure everything is in a sane state. - dc_serial_sleep (device->port, 300); - dc_serial_purge (device->port, DC_DIRECTION_ALL); + dc_iostream_sleep (device->iostream, 300); + dc_iostream_purge (device->iostream, DC_DIRECTION_ALL); *out = (dc_device_t *) device; return DC_STATUS_SUCCESS; error_close: - dc_serial_close (device->port); + dc_iostream_close (device->iostream); error_free: dc_device_deallocate ((dc_device_t *) device); return status; @@ -121,7 +121,7 @@ citizen_aqualand_device_close (dc_device_t *abstract) dc_status_t rc = DC_STATUS_SUCCESS; // Close the device. - rc = dc_serial_close (device->port); + rc = dc_iostream_close (device->iostream); if (rc != DC_STATUS_SUCCESS) { dc_status_set_error(&status, rc); } @@ -159,21 +159,21 @@ citizen_aqualand_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) return DC_STATUS_NOMEMORY; } - dc_serial_set_dtr (device->port, 1); + dc_iostream_set_dtr (device->iostream, 1); // Send the init byte. const unsigned char init[] = {0x7F}; - status = dc_serial_write (device->port, init, sizeof (init), NULL); + status = dc_iostream_write (device->iostream, init, sizeof (init), NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); return status; } - dc_serial_sleep(device->port, 1200); + dc_iostream_sleep(device->iostream, 1200); // Send the command. const unsigned char command[] = {0xFF}; - status = dc_serial_write (device->port, command, sizeof (command), NULL); + status = dc_iostream_write (device->iostream, command, sizeof (command), NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); return status; @@ -182,7 +182,7 @@ citizen_aqualand_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) while (1) { // Receive the response packet. unsigned char answer[32] = {0}; - status = dc_serial_read (device->port, answer, sizeof (answer), NULL); + status = dc_iostream_read (device->iostream, answer, sizeof (answer), NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); return status; @@ -191,7 +191,7 @@ citizen_aqualand_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) dc_buffer_append(buffer, answer, sizeof (answer)); // Send the command. - status = dc_serial_write (device->port, command, sizeof (command), NULL); + status = dc_iostream_write (device->iostream, command, sizeof (command), NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); return status; @@ -201,7 +201,7 @@ citizen_aqualand_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) break; } - dc_serial_set_dtr (device->port, 0); + dc_iostream_set_dtr (device->iostream, 0); return DC_STATUS_SUCCESS; } diff --git a/src/cochran_commander.c b/src/cochran_commander.c index 688c019..e21ec7e 100644 --- a/src/cochran_commander.c +++ b/src/cochran_commander.c @@ -94,7 +94,7 @@ typedef struct cochran_device_layout_t { typedef struct cochran_commander_device_t { dc_device_t base; - dc_serial_t *port; + dc_iostream_t *iostream; const cochran_device_layout_t *layout; unsigned char id[67]; unsigned char fingerprint[6]; @@ -305,30 +305,30 @@ cochran_commander_serial_setup (cochran_commander_device_t *device) dc_status_t status = DC_STATUS_SUCCESS; // Set the serial communication protocol (9600 8N2, no FC). - status = dc_serial_configure (device->port, 9600, 8, DC_PARITY_NONE, DC_STOPBITS_TWO, DC_FLOWCONTROL_NONE); + status = dc_iostream_configure (device->iostream, 9600, 8, DC_PARITY_NONE, DC_STOPBITS_TWO, DC_FLOWCONTROL_NONE); if (status != DC_STATUS_SUCCESS) { ERROR (device->base.context, "Failed to set the terminal attributes."); return status; } // Set the timeout for receiving data (5000 ms). - status = dc_serial_set_timeout (device->port, 5000); + status = dc_iostream_set_timeout (device->iostream, 5000); if (status != DC_STATUS_SUCCESS) { ERROR (device->base.context, "Failed to set the timeout."); return status; } // Wake up DC and trigger heartbeat - dc_serial_set_break(device->port, 1); - dc_serial_sleep(device->port, 16); - dc_serial_set_break(device->port, 0); + dc_iostream_set_break(device->iostream, 1); + dc_iostream_sleep(device->iostream, 16); + dc_iostream_set_break(device->iostream, 0); // Clear old heartbeats - dc_serial_purge (device->port, DC_DIRECTION_ALL); + dc_iostream_purge (device->iostream, DC_DIRECTION_ALL); // Wait for heartbeat byte before send unsigned char answer = 0; - status = dc_serial_read(device->port, &answer, 1, NULL); + status = dc_iostream_read(device->iostream, &answer, 1, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (device->base.context, "Failed to receive device heartbeat."); return status; @@ -359,9 +359,9 @@ cochran_commander_packet (cochran_commander_device_t *device, dc_event_progress_ // has no buffering. for (unsigned int i = 0; i < csize; i++) { // Give the DC time to read the character. - if (i) dc_serial_sleep(device->port, 16); // 16 ms + if (i) dc_iostream_sleep(device->iostream, 16); // 16 ms - status = dc_serial_write(device->port, command + i, 1, NULL); + status = dc_iostream_write(device->iostream, command + i, 1, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); return status; @@ -370,10 +370,10 @@ cochran_commander_packet (cochran_commander_device_t *device, dc_event_progress_ if (high_speed && device->layout->baudrate != 9600) { // Give the DC time to process the command. - dc_serial_sleep(device->port, 45); + dc_iostream_sleep(device->iostream, 45); // Rates are odd, like 850400 for the EMC, 115200 for commander - status = dc_serial_configure(device->port, device->layout->baudrate, 8, DC_PARITY_NONE, DC_STOPBITS_TWO, DC_FLOWCONTROL_NONE); + status = dc_iostream_configure(device->iostream, device->layout->baudrate, 8, DC_PARITY_NONE, DC_STOPBITS_TWO, DC_FLOWCONTROL_NONE); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to set the high baud rate."); return status; @@ -388,7 +388,7 @@ cochran_commander_packet (cochran_commander_device_t *device, dc_event_progress_ if (len > 1024) len = 1024; - status = dc_serial_read (device->port, answer + nbytes, len, NULL); + status = dc_iostream_read (device->iostream, answer + nbytes, len, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive data."); return status; @@ -523,7 +523,7 @@ cochran_commander_read (cochran_commander_device_t *device, dc_event_progress_t return DC_STATUS_UNSUPPORTED; } - dc_serial_sleep(device->port, 550); + dc_iostream_sleep(device->iostream, 550); // set back to 9600 baud rc = cochran_commander_serial_setup(device); @@ -732,11 +732,11 @@ cochran_commander_device_open (dc_device_t **out, dc_context_t *context, const c } // Set the default values. - device->port = NULL; + device->iostream = NULL; cochran_commander_device_set_fingerprint((dc_device_t *) device, NULL, 0); // Open the device. - status = dc_serial_open (&device->port, device->base.context, name); + status = dc_serial_open (&device->iostream, device->base.context, name); if (status != DC_STATUS_SUCCESS) { ERROR (device->base.context, "Failed to open the serial port."); goto error_free; @@ -785,7 +785,7 @@ cochran_commander_device_open (dc_device_t **out, dc_context_t *context, const c return DC_STATUS_SUCCESS; error_close: - dc_serial_close (device->port); + dc_iostream_close (device->iostream); error_free: dc_device_deallocate ((dc_device_t *) device); return status; @@ -799,7 +799,7 @@ cochran_commander_device_close (dc_device_t *abstract) dc_status_t rc = DC_STATUS_SUCCESS; // Close the device. - rc = dc_serial_close (device->port); + rc = dc_iostream_close (device->iostream); if (rc != DC_STATUS_SUCCESS) { dc_status_set_error(&status, rc); } diff --git a/src/context-private.h b/src/context-private.h index 800ef24..793abc3 100644 --- a/src/context-private.h +++ b/src/context-private.h @@ -75,19 +75,8 @@ dc_context_hexdump (dc_context_t *context, dc_loglevel_t loglevel, const char *f dc_custom_io_t* _dc_context_custom_io (dc_context_t *context); -#define RETURN_IF_CUSTOM_SERIAL(context, block, function, ...) \ - do { \ - dc_custom_io_t *c = _dc_context_custom_io(context); \ - dc_status_t _rc; \ - if (c) { \ - if (c->serial_##function) \ - _rc = c->serial_##function(c, ##__VA_ARGS__); \ - else \ - _rc = DC_STATUS_SUCCESS; \ - block ;\ - return _rc; \ - } \ - } while (0) +dc_status_t +dc_custom_io_serial_open(dc_iostream_t **out, dc_context_t *context, const char *name); #ifdef __cplusplus } diff --git a/src/cressi_edy.c b/src/cressi_edy.c index 68e13fc..80e4fac 100644 --- a/src/cressi_edy.c +++ b/src/cressi_edy.c @@ -55,7 +55,7 @@ typedef struct cressi_edy_layout_t { typedef struct cressi_edy_device_t { dc_device_t base; - dc_serial_t *port; + dc_iostream_t *iostream; const cressi_edy_layout_t *layout; unsigned char fingerprint[SZ_PAGE / 2]; unsigned int model; @@ -112,7 +112,7 @@ cressi_edy_packet (cressi_edy_device_t *device, const unsigned char command[], u for (unsigned int i = 0; i < csize; ++i) { // Send the command to the device. - status = dc_serial_write (device->port, command + i, 1, NULL); + status = dc_iostream_write (device->iostream, command + i, 1, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); return status; @@ -120,7 +120,7 @@ cressi_edy_packet (cressi_edy_device_t *device, const unsigned char command[], u // Receive the echo. unsigned char echo = 0; - status = dc_serial_read (device->port, &echo, 1, NULL); + status = dc_iostream_read (device->iostream, &echo, 1, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the echo."); return status; @@ -135,7 +135,7 @@ cressi_edy_packet (cressi_edy_device_t *device, const unsigned char command[], u if (asize) { // Receive the answer of the device. - status = dc_serial_read (device->port, answer, asize, NULL); + status = dc_iostream_read (device->iostream, answer, asize, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); return status; @@ -165,8 +165,8 @@ cressi_edy_transfer (cressi_edy_device_t *device, const unsigned char command[], return rc; // Delay the next attempt. - dc_serial_sleep (device->port, 300); - dc_serial_purge (device->port, DC_DIRECTION_INPUT); + dc_iostream_sleep (device->iostream, 300); + dc_iostream_purge (device->iostream, DC_DIRECTION_INPUT); } return DC_STATUS_SUCCESS; @@ -234,49 +234,49 @@ cressi_edy_device_open (dc_device_t **out, dc_context_t *context, const char *na } // Set the default values. - device->port = NULL; + device->iostream = NULL; device->layout = NULL; device->model = 0; memset (device->fingerprint, 0, sizeof (device->fingerprint)); // Open the device. - status = dc_serial_open (&device->port, context, name); + status = dc_serial_open (&device->iostream, context, name); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the serial port."); goto error_free; } // Set the serial communication protocol (1200 8N1). - status = dc_serial_configure (device->port, 1200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); + status = dc_iostream_configure (device->iostream, 1200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); goto error_close; } // Set the timeout for receiving data (1000 ms). - status = dc_serial_set_timeout (device->port, 1000); + status = dc_iostream_set_timeout (device->iostream, 1000); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the timeout."); goto error_close; } // Set the DTR line. - status = dc_serial_set_dtr (device->port, 1); + status = dc_iostream_set_dtr (device->iostream, 1); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the DTR line."); goto error_close; } // Clear the RTS line. - status = dc_serial_set_rts (device->port, 0); + status = dc_iostream_set_rts (device->iostream, 0); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to clear the RTS line."); goto error_close; } // Make sure everything is in a sane state. - dc_serial_sleep(device->port, 300); - dc_serial_purge(device->port, DC_DIRECTION_ALL); + dc_iostream_sleep(device->iostream, 300); + dc_iostream_purge(device->iostream, DC_DIRECTION_ALL); // Send the init commands. cressi_edy_init1 (device); @@ -290,22 +290,22 @@ cressi_edy_device_open (dc_device_t **out, dc_context_t *context, const char *na } // Set the serial communication protocol (4800 8N1). - status = dc_serial_configure (device->port, 4800, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); + status = dc_iostream_configure (device->iostream, 4800, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); goto error_close; } // Make sure everything is in a sane state. - dc_serial_sleep(device->port, 300); - dc_serial_purge(device->port, DC_DIRECTION_ALL); + dc_iostream_sleep(device->iostream, 300); + dc_iostream_purge(device->iostream, DC_DIRECTION_ALL); *out = (dc_device_t*) device; return DC_STATUS_SUCCESS; error_close: - dc_serial_close (device->port); + dc_iostream_close (device->iostream); error_free: dc_device_deallocate ((dc_device_t *) device); return status; @@ -326,7 +326,7 @@ cressi_edy_device_close (dc_device_t *abstract) } // Close the device. - rc = dc_serial_close (device->port); + rc = dc_iostream_close (device->iostream); if (rc != DC_STATUS_SUCCESS) { dc_status_set_error(&status, rc); } diff --git a/src/cressi_leonardo.c b/src/cressi_leonardo.c index f21a223..4021288 100644 --- a/src/cressi_leonardo.c +++ b/src/cressi_leonardo.c @@ -49,7 +49,7 @@ typedef struct cressi_leonardo_device_t { dc_device_t base; - dc_serial_t *port; + dc_iostream_t *iostream; unsigned char fingerprint[5]; } cressi_leonardo_device_t; @@ -106,14 +106,14 @@ cressi_leonardo_packet (cressi_leonardo_device_t *device, const unsigned char co return DC_STATUS_CANCELLED; // Send the command to the device. - status = dc_serial_write (device->port, command, csize, NULL); + status = dc_iostream_write (device->iostream, command, csize, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); return status; } // Receive the answer of the device. - status = dc_serial_read (device->port, answer, asize, NULL); + status = dc_iostream_read (device->iostream, answer, asize, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); return status; @@ -156,8 +156,8 @@ cressi_leonardo_transfer (cressi_leonardo_device_t *device, const unsigned char return rc; // Discard any garbage bytes. - dc_serial_sleep (device->port, 100); - dc_serial_purge (device->port, DC_DIRECTION_INPUT); + dc_iostream_sleep (device->iostream, 100); + dc_iostream_purge (device->iostream, DC_DIRECTION_INPUT); } return rc; @@ -180,62 +180,62 @@ cressi_leonardo_device_open (dc_device_t **out, dc_context_t *context, const cha } // Set the default values. - device->port = NULL; + device->iostream = NULL; memset (device->fingerprint, 0, sizeof (device->fingerprint)); // Open the device. - status = dc_serial_open (&device->port, context, name); + status = dc_serial_open (&device->iostream, context, name); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the serial port."); goto error_free; } // Set the serial communication protocol (115200 8N1). - status = dc_serial_configure (device->port, 115200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); + status = dc_iostream_configure (device->iostream, 115200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); goto error_close; } // Set the timeout for receiving data (1000 ms). - status = dc_serial_set_timeout (device->port, 1000); + status = dc_iostream_set_timeout (device->iostream, 1000); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the timeout."); goto error_close; } // Set the RTS line. - status = dc_serial_set_rts (device->port, 1); + status = dc_iostream_set_rts (device->iostream, 1); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the RTS line."); goto error_close; } // Set the DTR line. - status = dc_serial_set_dtr (device->port, 1); + status = dc_iostream_set_dtr (device->iostream, 1); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the DTR line."); goto error_close; } - dc_serial_sleep (device->port, 200); + dc_iostream_sleep (device->iostream, 200); // Clear the DTR line. - status = dc_serial_set_dtr (device->port, 0); + status = dc_iostream_set_dtr (device->iostream, 0); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to clear the DTR line."); goto error_close; } - dc_serial_sleep (device->port, 100); - dc_serial_purge (device->port, DC_DIRECTION_ALL); + dc_iostream_sleep (device->iostream, 100); + dc_iostream_purge (device->iostream, DC_DIRECTION_ALL); *out = (dc_device_t *) device; return DC_STATUS_SUCCESS; error_close: - dc_serial_close (device->port); + dc_iostream_close (device->iostream); error_free: dc_device_deallocate ((dc_device_t *) device); return status; @@ -249,7 +249,7 @@ cressi_leonardo_device_close (dc_device_t *abstract) dc_status_t rc = DC_STATUS_SUCCESS; // Close the device. - rc = dc_serial_close (device->port); + rc = dc_iostream_close (device->iostream); if (rc != DC_STATUS_SUCCESS) { dc_status_set_error(&status, rc); } @@ -334,7 +334,7 @@ cressi_leonardo_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) // Send the command header to the dive computer. const unsigned char command[] = {0x7B, 0x31, 0x32, 0x33, 0x44, 0x42, 0x41, 0x7d}; - status = dc_serial_write (device->port, command, sizeof (command), NULL); + status = dc_iostream_write (device->iostream, command, sizeof (command), NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); return status; @@ -342,7 +342,7 @@ cressi_leonardo_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) // Receive the header packet. unsigned char header[7] = {0}; - status = dc_serial_read (device->port, header, sizeof (header), NULL); + status = dc_iostream_read (device->iostream, header, sizeof (header), NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); return status; @@ -364,7 +364,7 @@ cressi_leonardo_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) // Increase the packet size if more data is immediately available. size_t available = 0; - status = dc_serial_get_available (device->port, &available); + status = dc_iostream_get_available (device->iostream, &available); if (status == DC_STATUS_SUCCESS && available > len) len = available; @@ -373,7 +373,7 @@ cressi_leonardo_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) len = SZ_MEMORY - nbytes; // Read the packet. - status = dc_serial_read (device->port, data + nbytes, len, NULL); + status = dc_iostream_read (device->iostream, data + nbytes, len, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); return status; @@ -388,7 +388,7 @@ cressi_leonardo_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) // Receive the trailer packet. unsigned char trailer[4] = {0}; - status = dc_serial_read (device->port, trailer, sizeof (trailer), NULL); + status = dc_iostream_read (device->iostream, trailer, sizeof (trailer), NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); return status; diff --git a/src/custom.c b/src/custom.c new file mode 100644 index 0000000..e96ba5f --- /dev/null +++ b/src/custom.c @@ -0,0 +1,263 @@ +/* + * libdivecomputer + * + * Copyright (C) 2017 Jef Driesen + * + * This library 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 2.1 of the License, or (at your option) any later version. + * + * This library 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 this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include // malloc, free + +#include "custom.h" + +#include "iostream-private.h" +#include "common-private.h" +#include "context-private.h" + +static dc_status_t dc_custom_set_timeout (dc_iostream_t *abstract, int timeout); +static dc_status_t dc_custom_set_latency (dc_iostream_t *abstract, unsigned int value); +static dc_status_t dc_custom_set_halfduplex (dc_iostream_t *abstract, unsigned int value); +static dc_status_t dc_custom_set_break (dc_iostream_t *abstract, unsigned int value); +static dc_status_t dc_custom_set_dtr (dc_iostream_t *abstract, unsigned int value); +static dc_status_t dc_custom_set_rts (dc_iostream_t *abstract, unsigned int value); +static dc_status_t dc_custom_get_lines (dc_iostream_t *abstract, unsigned int *value); +static dc_status_t dc_custom_get_available (dc_iostream_t *abstract, size_t *value); +static dc_status_t dc_custom_configure (dc_iostream_t *abstract, unsigned int baudrate, unsigned int databits, dc_parity_t parity, dc_stopbits_t stopbits, dc_flowcontrol_t flowcontrol); +static dc_status_t dc_custom_read (dc_iostream_t *abstract, void *data, size_t size, size_t *actual); +static dc_status_t dc_custom_write (dc_iostream_t *abstract, const void *data, size_t size, size_t *actual); +static dc_status_t dc_custom_flush (dc_iostream_t *abstract); +static dc_status_t dc_custom_purge (dc_iostream_t *abstract, dc_direction_t direction); +static dc_status_t dc_custom_sleep (dc_iostream_t *abstract, unsigned int milliseconds); +static dc_status_t dc_custom_close (dc_iostream_t *abstract); + +typedef struct dc_custom_t { + /* Base class. */ + dc_iostream_t base; + /* Internal state. */ + dc_custom_cbs_t callbacks; + void *userdata; +} dc_custom_t; + +static const dc_iostream_vtable_t dc_custom_vtable = { + sizeof(dc_custom_t), + dc_custom_set_timeout, /* set_timeout */ + dc_custom_set_latency, /* set_latency */ + dc_custom_set_halfduplex, /* set_halfduplex */ + dc_custom_set_break, /* set_break */ + dc_custom_set_dtr, /* set_dtr */ + dc_custom_set_rts, /* set_rts */ + dc_custom_get_lines, /* get_lines */ + dc_custom_get_available, /* get_received */ + dc_custom_configure, /* configure */ + dc_custom_read, /* read */ + dc_custom_write, /* write */ + dc_custom_flush, /* flush */ + dc_custom_purge, /* purge */ + dc_custom_sleep, /* sleep */ + dc_custom_close, /* close */ +}; + +dc_status_t +dc_custom_open (dc_iostream_t **out, dc_context_t *context, const dc_custom_cbs_t *callbacks, void *userdata) +{ + dc_custom_t *custom = NULL; + + if (out == NULL || callbacks == NULL) + return DC_STATUS_INVALIDARGS; + + INFO (context, "Open: custom"); + + // Allocate memory. + custom = (dc_custom_t *) dc_iostream_allocate (context, &dc_custom_vtable); + if (custom == NULL) { + ERROR (context, "Failed to allocate memory."); + return DC_STATUS_NOMEMORY; + } + + custom->callbacks = *callbacks; + custom->userdata = userdata; + + *out = (dc_iostream_t *) custom; + + return DC_STATUS_SUCCESS; +} + +static dc_status_t +dc_custom_set_timeout (dc_iostream_t *abstract, int timeout) +{ + dc_custom_t *custom = (dc_custom_t *) abstract; + + if (custom->callbacks.set_timeout == NULL) + return DC_STATUS_UNSUPPORTED; + + return custom->callbacks.set_timeout (custom->userdata, timeout); +} + +static dc_status_t +dc_custom_set_latency (dc_iostream_t *abstract, unsigned int value) +{ + dc_custom_t *custom = (dc_custom_t *) abstract; + + if (custom->callbacks.set_latency == NULL) + return DC_STATUS_UNSUPPORTED; + + return custom->callbacks.set_latency (custom->userdata, value); +} + +static dc_status_t +dc_custom_set_halfduplex (dc_iostream_t *abstract, unsigned int value) +{ + dc_custom_t *custom = (dc_custom_t *) abstract; + + if (custom->callbacks.set_halfduplex == NULL) + return DC_STATUS_UNSUPPORTED; + + return custom->callbacks.set_halfduplex (custom->userdata, value); +} + +static dc_status_t +dc_custom_set_break (dc_iostream_t *abstract, unsigned int value) +{ + dc_custom_t *custom = (dc_custom_t *) abstract; + + if (custom->callbacks.set_break == NULL) + return DC_STATUS_UNSUPPORTED; + + return custom->callbacks.set_break (custom->userdata, value); +} + +static dc_status_t +dc_custom_set_dtr (dc_iostream_t *abstract, unsigned int value) +{ + dc_custom_t *custom = (dc_custom_t *) abstract; + + if (custom->callbacks.set_dtr == NULL) + return DC_STATUS_UNSUPPORTED; + + return custom->callbacks.set_dtr (custom->userdata, value); +} + +static dc_status_t +dc_custom_set_rts (dc_iostream_t *abstract, unsigned int value) +{ + dc_custom_t *custom = (dc_custom_t *) abstract; + + if (custom->callbacks.set_rts == NULL) + return DC_STATUS_UNSUPPORTED; + + return custom->callbacks.set_rts (custom->userdata, value); +} + +static dc_status_t +dc_custom_get_lines (dc_iostream_t *abstract, unsigned int *value) +{ + dc_custom_t *custom = (dc_custom_t *) abstract; + + if (custom->callbacks.get_lines == NULL) + return DC_STATUS_UNSUPPORTED; + + return custom->callbacks.get_lines (custom->userdata, value); +} + +static dc_status_t +dc_custom_get_available (dc_iostream_t *abstract, size_t *value) +{ + dc_custom_t *custom = (dc_custom_t *) abstract; + + if (custom->callbacks.get_available == NULL) + return DC_STATUS_UNSUPPORTED; + + return custom->callbacks.get_available (custom->userdata, value); +} + +static dc_status_t +dc_custom_configure (dc_iostream_t *abstract, unsigned int baudrate, unsigned int databits, dc_parity_t parity, dc_stopbits_t stopbits, dc_flowcontrol_t flowcontrol) +{ + dc_custom_t *custom = (dc_custom_t *) abstract; + + if (custom->callbacks.configure == NULL) + return DC_STATUS_UNSUPPORTED; + + return custom->callbacks.configure (custom->userdata, baudrate, databits, parity, stopbits, flowcontrol); +} + +static dc_status_t +dc_custom_read (dc_iostream_t *abstract, void *data, size_t size, size_t *actual) +{ + dc_custom_t *custom = (dc_custom_t *) abstract; + + if (custom->callbacks.read == NULL) + return DC_STATUS_UNSUPPORTED; + + return custom->callbacks.read (custom->userdata, data, size, actual); +} + +static dc_status_t +dc_custom_write (dc_iostream_t *abstract, const void *data, size_t size, size_t *actual) +{ + dc_custom_t *custom = (dc_custom_t *) abstract; + + if (custom->callbacks.write == NULL) + return DC_STATUS_UNSUPPORTED; + + return custom->callbacks.write (custom->userdata, data, size, actual); +} + +static dc_status_t +dc_custom_flush (dc_iostream_t *abstract) +{ + dc_custom_t *custom = (dc_custom_t *) abstract; + + if (custom->callbacks.flush == NULL) + return DC_STATUS_UNSUPPORTED; + + return custom->callbacks.flush (custom->userdata); +} + +static dc_status_t +dc_custom_purge (dc_iostream_t *abstract, dc_direction_t direction) +{ + dc_custom_t *custom = (dc_custom_t *) abstract; + + if (custom->callbacks.purge == NULL) + return DC_STATUS_UNSUPPORTED; + + return custom->callbacks.purge (custom->userdata, direction); +} + +static dc_status_t +dc_custom_sleep (dc_iostream_t *abstract, unsigned int milliseconds) +{ + dc_custom_t *custom = (dc_custom_t *) abstract; + + if (custom->callbacks.sleep == NULL) + return DC_STATUS_UNSUPPORTED; + + return custom->callbacks.sleep (custom->userdata, milliseconds); +} + +static dc_status_t +dc_custom_close (dc_iostream_t *abstract) +{ + dc_status_t status = DC_STATUS_SUCCESS; + dc_custom_t *custom = (dc_custom_t *) abstract; + + if (custom->callbacks.close) { + status = custom->callbacks.close (custom->userdata); + } + + return status; +} diff --git a/src/custom.h b/src/custom.h new file mode 100644 index 0000000..f062cd3 --- /dev/null +++ b/src/custom.h @@ -0,0 +1,67 @@ +/* + * libdivecomputer + * + * Copyright (C) 2017 Jef Driesen + * + * This library 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 2.1 of the License, or (at your option) any later version. + * + * This library 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 this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#ifndef DC_CUSTOM_H +#define DC_CUSTOM_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef struct dc_custom_cbs_t { + dc_status_t (*set_timeout) (void *userdata, int timeout); + dc_status_t (*set_latency) (void *userdata, unsigned int value); + dc_status_t (*set_halfduplex) (void *userdata, unsigned int value); + dc_status_t (*set_break) (void *userdata, unsigned int value); + dc_status_t (*set_dtr) (void *userdata, unsigned int value); + dc_status_t (*set_rts) (void *userdata, unsigned int value); + dc_status_t (*get_lines) (void *userdata, unsigned int *value); + dc_status_t (*get_available) (void *userdata, size_t *value); + dc_status_t (*configure) (void *userdata, unsigned int baudrate, unsigned int databits, dc_parity_t parity, dc_stopbits_t stopbits, dc_flowcontrol_t flowcontrol); + dc_status_t (*read) (void *userdata, void *data, size_t size, size_t *actual); + dc_status_t (*write) (void *userdata, const void *data, size_t size, size_t *actual); + dc_status_t (*flush) (void *userdata); + dc_status_t (*purge) (void *userdata, dc_direction_t direction); + dc_status_t (*sleep) (void *userdata, unsigned int milliseconds); + dc_status_t (*close) (void *userdata); +} dc_custom_cbs_t; + +/** + * Create a custom I/O stream. + * + * @param[out] iostream A location to store the custom I/O stream. + * @param[in] context A valid context object. + * @param[in] callbacks The callback functions to call. + * @param[in] userdata User data to pass to the callback functions. + * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code + * on failure. + */ +dc_status_t +dc_custom_open (dc_iostream_t **iostream, dc_context_t *context, const dc_custom_cbs_t *callbacks, void *userdata); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* DC_CUSTOM_H */ diff --git a/src/custom_io.c b/src/custom_io.c new file mode 100644 index 0000000..dd1adfa --- /dev/null +++ b/src/custom_io.c @@ -0,0 +1,231 @@ +/* + * libdivecomputer + * + * Copyright (C) 2017 Jef Driesen + * + * This library 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 2.1 of the License, or (at your option) any later version. + * + * This library 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 this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include // malloc, free + +#include + +#include "iostream-private.h" +#include "common-private.h" +#include "context-private.h" + +/* + * This is shamelessly stolen from src/custom.c, to make it + * work with the subsurface custom_io model. + */ +typedef struct dc_custom_t { + /* Base class. */ + dc_iostream_t base; + /* Internal state. */ + dc_context_t *context; +} dc_custom_t; + +static dc_status_t +dc_custom_set_timeout (dc_iostream_t *abstract, int timeout) +{ + dc_custom_t *custom = (dc_custom_t *) abstract; + dc_custom_io_t *io = _dc_context_custom_io(custom->context); + + if (!io->serial_set_timeout) + return DC_STATUS_SUCCESS; + + return io->serial_set_timeout(io, timeout); +} + +static dc_status_t +dc_custom_set_latency (dc_iostream_t *abstract, unsigned int value) +{ + return DC_STATUS_SUCCESS; +} + +static dc_status_t +dc_custom_set_halfduplex (dc_iostream_t *abstract, unsigned int value) +{ + dc_custom_t *custom = (dc_custom_t *) abstract; + dc_custom_io_t *io = _dc_context_custom_io(custom->context); + + if (!io->serial_set_halfduplex) + return DC_STATUS_SUCCESS; + + return io->serial_set_halfduplex(io, value); +} + +static dc_status_t +dc_custom_set_break (dc_iostream_t *abstract, unsigned int value) +{ + dc_custom_t *custom = (dc_custom_t *) abstract; + dc_custom_io_t *io = _dc_context_custom_io(custom->context); + + if (!io->serial_set_break) + return DC_STATUS_SUCCESS; + + return io->serial_set_break(io, value); +} + +static dc_status_t +dc_custom_set_dtr (dc_iostream_t *abstract, unsigned int value) +{ + dc_custom_t *custom = (dc_custom_t *) abstract; + dc_custom_io_t *io = _dc_context_custom_io(custom->context); + + if (!io->serial_set_dtr) + return DC_STATUS_SUCCESS; + + return io->serial_set_dtr(io, value); +} + +static dc_status_t +dc_custom_set_rts (dc_iostream_t *abstract, unsigned int value) +{ + dc_custom_t *custom = (dc_custom_t *) abstract; + dc_custom_io_t *io = _dc_context_custom_io(custom->context); + + if (!io->serial_set_rts) + return DC_STATUS_SUCCESS; + + return io->serial_set_rts(io, value); +} + +static dc_status_t +dc_custom_get_lines (dc_iostream_t *abstract, unsigned int *value) +{ + return DC_STATUS_SUCCESS; +} + +static dc_status_t +dc_custom_get_available (dc_iostream_t *abstract, size_t *value) +{ + dc_custom_t *custom = (dc_custom_t *) abstract; + dc_custom_io_t *io = _dc_context_custom_io(custom->context); + + if (!io->serial_get_available) + return DC_STATUS_SUCCESS; + + return io->serial_get_available(io, value); +} + +static dc_status_t +dc_custom_configure (dc_iostream_t *abstract, unsigned int baudrate, unsigned int databits, dc_parity_t parity, dc_stopbits_t stopbits, dc_flowcontrol_t flowcontrol) +{ + dc_custom_t *custom = (dc_custom_t *) abstract; + dc_custom_io_t *io = _dc_context_custom_io(custom->context); + + if (!io->serial_configure) + return DC_STATUS_SUCCESS; + + return io->serial_configure(io, baudrate, databits, parity, stopbits, flowcontrol); +} + +static dc_status_t +dc_custom_read (dc_iostream_t *abstract, void *data, size_t size, size_t *actual) +{ + dc_custom_t *custom = (dc_custom_t *) abstract; + dc_custom_io_t *io = _dc_context_custom_io(custom->context); + + if (!io->serial_read) + return DC_STATUS_SUCCESS; + + return io->serial_read(io, data, size, actual); +} + +static dc_status_t +dc_custom_write (dc_iostream_t *abstract, const void *data, size_t size, size_t *actual) +{ + dc_custom_t *custom = (dc_custom_t *) abstract; + dc_custom_io_t *io = _dc_context_custom_io(custom->context); + + if (!io->serial_write) + return DC_STATUS_SUCCESS; + + return io->serial_write(io, data, size, actual); +} + +static dc_status_t +dc_custom_flush (dc_iostream_t *abstract) +{ + return DC_STATUS_SUCCESS; +} + +static dc_status_t +dc_custom_purge (dc_iostream_t *abstract, dc_direction_t direction) +{ + dc_custom_t *custom = (dc_custom_t *) abstract; + dc_custom_io_t *io = _dc_context_custom_io(custom->context); + + if (!io->serial_purge) + return DC_STATUS_SUCCESS; + + return io->serial_purge(io, direction); +} + +static dc_status_t +dc_custom_sleep (dc_iostream_t *abstract, unsigned int milliseconds) +{ + return DC_STATUS_SUCCESS; +} + +static dc_status_t +dc_custom_close (dc_iostream_t *abstract) +{ + dc_custom_t *custom = (dc_custom_t *) abstract; + dc_custom_io_t *io = _dc_context_custom_io(custom->context); + + if (!io->serial_close) + return DC_STATUS_SUCCESS; + + return io->serial_close(io); +} + +static const dc_iostream_vtable_t dc_custom_vtable = { + sizeof(dc_custom_t), + dc_custom_set_timeout, /* set_timeout */ + dc_custom_set_latency, /* set_latency */ + dc_custom_set_halfduplex, /* set_halfduplex */ + dc_custom_set_break, /* set_break */ + dc_custom_set_dtr, /* set_dtr */ + dc_custom_set_rts, /* set_rts */ + dc_custom_get_lines, /* get_lines */ + dc_custom_get_available, /* get_received */ + dc_custom_configure, /* configure */ + dc_custom_read, /* read */ + dc_custom_write, /* write */ + dc_custom_flush, /* flush */ + dc_custom_purge, /* purge */ + dc_custom_sleep, /* sleep */ + dc_custom_close, /* close */ +}; + +dc_status_t +dc_custom_io_serial_open(dc_iostream_t **out, dc_context_t *context, const char *name) +{ + dc_custom_io_t *io = _dc_context_custom_io(context); + dc_custom_t *custom; + + custom = (dc_custom_t *) dc_iostream_allocate (context, &dc_custom_vtable); + if (!custom) { + ERROR (context, "Failed to allocate memory."); + return DC_STATUS_NOMEMORY; + } + + custom->context = context; + *out = (dc_iostream_t *) custom; + return io->serial_open(io, context, name); +} diff --git a/src/diverite_nitekq.c b/src/diverite_nitekq.c index 8c8c442..8524b56 100644 --- a/src/diverite_nitekq.c +++ b/src/diverite_nitekq.c @@ -51,7 +51,7 @@ typedef struct diverite_nitekq_device_t { dc_device_t base; - dc_serial_t *port; + dc_iostream_t *iostream; unsigned char version[32]; unsigned char fingerprint[SZ_LOGBOOK]; } diverite_nitekq_device_t; @@ -87,7 +87,7 @@ diverite_nitekq_send (diverite_nitekq_device_t *device, unsigned char cmd) // Send the command. unsigned char command[] = {cmd}; - status = dc_serial_write (device->port, command, sizeof (command), NULL); + status = dc_iostream_write (device->iostream, command, sizeof (command), NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); return status; @@ -104,7 +104,7 @@ diverite_nitekq_receive (diverite_nitekq_device_t *device, unsigned char data[], dc_device_t *abstract = (dc_device_t *) device; // Read the answer. - status = dc_serial_read (device->port, data, size, NULL); + status = dc_iostream_read (device->iostream, data, size, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); return status; @@ -112,7 +112,7 @@ diverite_nitekq_receive (diverite_nitekq_device_t *device, unsigned char data[], // Read the checksum. unsigned char checksum[2] = {0}; - status = dc_serial_read (device->port, checksum, sizeof (checksum), NULL); + status = dc_iostream_read (device->iostream, checksum, sizeof (checksum), NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the checksum."); return status; @@ -130,14 +130,14 @@ diverite_nitekq_handshake (diverite_nitekq_device_t *device) // Send the command. unsigned char command[] = {HANDSHAKE}; - status = dc_serial_write (device->port, command, sizeof (command), NULL); + status = dc_iostream_write (device->iostream, command, sizeof (command), NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); return status; } // Read the answer. - status = dc_serial_read (device->port, device->version, sizeof (device->version), NULL); + status = dc_iostream_read (device->iostream, device->version, sizeof (device->version), NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); return status; @@ -164,33 +164,33 @@ diverite_nitekq_device_open (dc_device_t **out, dc_context_t *context, const cha } // Set the default values. - device->port = NULL; + device->iostream = NULL; memset (device->fingerprint, 0, sizeof (device->fingerprint)); // Open the device. - status = dc_serial_open (&device->port, context, name); + status = dc_serial_open (&device->iostream, context, name); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the serial port."); goto error_free; } // Set the serial communication protocol (9600 8N1). - status = dc_serial_configure (device->port, 9600, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); + status = dc_iostream_configure (device->iostream, 9600, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); goto error_close; } // Set the timeout for receiving data (1000ms). - status = dc_serial_set_timeout (device->port, 1000); + status = dc_iostream_set_timeout (device->iostream, 1000); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the timeout."); goto error_close; } // Make sure everything is in a sane state. - dc_serial_sleep (device->port, 100); - dc_serial_purge (device->port, DC_DIRECTION_ALL); + dc_iostream_sleep (device->iostream, 100); + dc_iostream_purge (device->iostream, DC_DIRECTION_ALL); // Perform the handshaking. status = diverite_nitekq_handshake (device); @@ -204,7 +204,7 @@ diverite_nitekq_device_open (dc_device_t **out, dc_context_t *context, const cha return DC_STATUS_SUCCESS; error_close: - dc_serial_close (device->port); + dc_iostream_close (device->iostream); error_free: dc_device_deallocate ((dc_device_t *) device); return status; @@ -225,7 +225,7 @@ diverite_nitekq_device_close (dc_device_t *abstract) } // Close the device. - rc = dc_serial_close (device->port); + rc = dc_iostream_close (device->iostream); if (rc != DC_STATUS_SUCCESS) { dc_status_set_error(&status, rc); } diff --git a/src/divesystem_idive.c b/src/divesystem_idive.c index 8a8f1ae..46ecb34 100644 --- a/src/divesystem_idive.c +++ b/src/divesystem_idive.c @@ -69,7 +69,7 @@ typedef struct divesystem_idive_commands_t { typedef struct divesystem_idive_device_t { dc_device_t base; - dc_serial_t *port; + dc_iostream_t *iostream; unsigned char fingerprint[4]; unsigned int model; } divesystem_idive_device_t; @@ -131,41 +131,41 @@ divesystem_idive_device_open (dc_device_t **out, dc_context_t *context, const ch } // Set the default values. - device->port = NULL; + device->iostream = NULL; memset (device->fingerprint, 0, sizeof (device->fingerprint)); device->model = model; // Open the device. - status = dc_serial_open (&device->port, context, name); + status = dc_serial_open (&device->iostream, context, name); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the serial port."); goto error_free; } // Set the serial communication protocol (115200 8N1). - status = dc_serial_configure (device->port, 115200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); + status = dc_iostream_configure (device->iostream, 115200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); goto error_close; } // Set the timeout for receiving data (1000ms). - status = dc_serial_set_timeout (device->port, 1000); + status = dc_iostream_set_timeout (device->iostream, 1000); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the timeout."); goto error_close; } // Make sure everything is in a sane state. - dc_serial_sleep (device->port, 300); - dc_serial_purge (device->port, DC_DIRECTION_ALL); + dc_iostream_sleep (device->iostream, 300); + dc_iostream_purge (device->iostream, DC_DIRECTION_ALL); *out = (dc_device_t *) device; return DC_STATUS_SUCCESS; error_close: - dc_serial_close (device->port); + dc_iostream_close (device->iostream); error_free: dc_device_deallocate ((dc_device_t *) device); return status; @@ -180,7 +180,7 @@ divesystem_idive_device_close (dc_device_t *abstract) dc_status_t rc = DC_STATUS_SUCCESS; // Close the device. - rc = dc_serial_close (device->port); + rc = dc_iostream_close (device->iostream); if (rc != DC_STATUS_SUCCESS) { dc_status_set_error(&status, rc); } @@ -229,7 +229,7 @@ divesystem_idive_send (divesystem_idive_device_t *device, const unsigned char co packet[csize + 3] = (crc ) & 0xFF; // Send the data packet. - status = dc_serial_write (device->port, packet, csize + 4, NULL); + status = dc_iostream_write (device->iostream, packet, csize + 4, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); return status; @@ -253,7 +253,7 @@ divesystem_idive_receive (divesystem_idive_device_t *device, unsigned char answe // Read the packet start byte. while (1) { - status = dc_serial_read (device->port, packet + 0, 1, NULL); + status = dc_iostream_read (device->iostream, packet + 0, 1, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the packet start byte."); return status; @@ -264,7 +264,7 @@ divesystem_idive_receive (divesystem_idive_device_t *device, unsigned char answe } // Read the packet length. - status = dc_serial_read (device->port, packet + 1, 1, NULL); + status = dc_iostream_read (device->iostream, packet + 1, 1, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the packet length."); return status; @@ -277,7 +277,7 @@ divesystem_idive_receive (divesystem_idive_device_t *device, unsigned char answe } // Read the packet payload and checksum. - status = dc_serial_read (device->port, packet + 2, len + 2, NULL); + status = dc_iostream_read (device->iostream, packet + 2, len + 2, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the packet payload and checksum."); return status; @@ -383,7 +383,7 @@ divesystem_idive_transfer (divesystem_idive_device_t *device, const unsigned cha break; // Delay the next attempt. - dc_serial_sleep (device->port, 100); + dc_iostream_sleep (device->iostream, 100); } if (errorcode) { diff --git a/src/divesystem_idive_parser.c b/src/divesystem_idive_parser.c index 24f7e53..413d7c4 100644 --- a/src/divesystem_idive_parser.c +++ b/src/divesystem_idive_parser.c @@ -230,8 +230,10 @@ divesystem_idive_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, *((dc_divemode_t *) value) = DC_DIVEMODE_OC; break; case SCR: + *((dc_divemode_t *) value) = DC_DIVEMODE_SCR; + break; case CCR: - *((dc_divemode_t *) value) = DC_DIVEMODE_CC; + *((dc_divemode_t *) value) = DC_DIVEMODE_CCR; break; case GAUGE: *((dc_divemode_t *) value) = DC_DIVEMODE_GAUGE; diff --git a/src/hw_frog.c b/src/hw_frog.c index 83ee998..e2bec3b 100644 --- a/src/hw_frog.c +++ b/src/hw_frog.c @@ -55,7 +55,7 @@ typedef struct hw_frog_device_t { dc_device_t base; - dc_serial_t *port; + dc_iostream_t *iostream; unsigned char fingerprint[5]; } hw_frog_device_t; @@ -114,7 +114,7 @@ hw_frog_transfer (hw_frog_device_t *device, // Send the command. unsigned char command[1] = {cmd}; - status = dc_serial_write (device->port, command, sizeof (command), NULL); + status = dc_iostream_write (device->iostream, command, sizeof (command), NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); return status; @@ -123,7 +123,7 @@ hw_frog_transfer (hw_frog_device_t *device, if (cmd != INIT && cmd != HEADER) { // Read the echo. unsigned char answer[1] = {0}; - status = dc_serial_read (device->port, answer, sizeof (answer), NULL); + status = dc_iostream_read (device->iostream, answer, sizeof (answer), NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the echo."); return status; @@ -138,7 +138,7 @@ hw_frog_transfer (hw_frog_device_t *device, if (input) { // Send the input data packet. - status = dc_serial_write (device->port, input, isize, NULL); + status = dc_iostream_write (device->iostream, input, isize, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the data packet."); return status; @@ -153,7 +153,7 @@ hw_frog_transfer (hw_frog_device_t *device, // Increase the packet size if more data is immediately available. size_t available = 0; - status = dc_serial_get_available (device->port, &available); + status = dc_iostream_get_available (device->iostream, &available); if (status == DC_STATUS_SUCCESS && available > len) len = available; @@ -162,7 +162,7 @@ hw_frog_transfer (hw_frog_device_t *device, len = osize - nbytes; // Read the packet. - status = dc_serial_read (device->port, output + nbytes, len, NULL); + status = dc_iostream_read (device->iostream, output + nbytes, len, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); return status; @@ -181,7 +181,7 @@ hw_frog_transfer (hw_frog_device_t *device, if (cmd != EXIT) { // Read the ready byte. unsigned char answer[1] = {0}; - status = dc_serial_read (device->port, answer, sizeof (answer), NULL); + status = dc_iostream_read (device->iostream, answer, sizeof (answer), NULL); if (status != sizeof (answer)) { ERROR (abstract->context, "Failed to receive the ready byte."); return status; @@ -215,33 +215,33 @@ hw_frog_device_open (dc_device_t **out, dc_context_t *context, const char *name) } // Set the default values. - device->port = NULL; + device->iostream = NULL; memset (device->fingerprint, 0, sizeof (device->fingerprint)); // Open the device. - status = dc_serial_open (&device->port, context, name); + status = dc_serial_open (&device->iostream, context, name); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the serial port."); goto error_free; } // Set the serial communication protocol (115200 8N1). - status = dc_serial_configure (device->port, 115200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); + status = dc_iostream_configure (device->iostream, 115200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); goto error_close; } // Set the timeout for receiving data (3000ms). - status = dc_serial_set_timeout (device->port, 3000); + status = dc_iostream_set_timeout (device->iostream, 3000); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the timeout."); goto error_close; } // Make sure everything is in a sane state. - dc_serial_sleep (device->port, 300); - dc_serial_purge (device->port, DC_DIRECTION_ALL); + dc_iostream_sleep (device->iostream, 300); + dc_iostream_purge (device->iostream, DC_DIRECTION_ALL); // Send the init command. status = hw_frog_transfer (device, NULL, INIT, NULL, 0, NULL, 0); @@ -255,7 +255,7 @@ hw_frog_device_open (dc_device_t **out, dc_context_t *context, const char *name) return DC_STATUS_SUCCESS; error_close: - dc_serial_close (device->port); + dc_iostream_close (device->iostream); error_free: dc_device_deallocate ((dc_device_t *) device); return status; @@ -277,7 +277,7 @@ hw_frog_device_close (dc_device_t *abstract) } // Close the device. - rc = dc_serial_close (device->port); + rc = dc_iostream_close (device->iostream); if (rc != DC_STATUS_SUCCESS) { dc_status_set_error(&status, rc); } diff --git a/src/hw_ostc.c b/src/hw_ostc.c index 87c2b1d..36d6080 100644 --- a/src/hw_ostc.c +++ b/src/hw_ostc.c @@ -58,7 +58,7 @@ typedef struct hw_ostc_device_t { dc_device_t base; - dc_serial_t *port; + dc_iostream_t *iostream; unsigned char fingerprint[5]; } hw_ostc_device_t; @@ -96,7 +96,7 @@ hw_ostc_send (hw_ostc_device_t *device, unsigned char cmd, unsigned int echo) // Send the command. unsigned char command[1] = {cmd}; - status = dc_serial_write (device->port, command, sizeof (command), NULL); + status = dc_iostream_write (device->iostream, command, sizeof (command), NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); return status; @@ -105,7 +105,7 @@ hw_ostc_send (hw_ostc_device_t *device, unsigned char cmd, unsigned int echo) if (echo) { // Read the echo. unsigned char answer[1] = {0}; - status = dc_serial_read (device->port, answer, sizeof (answer), NULL); + status = dc_iostream_read (device->iostream, answer, sizeof (answer), NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the echo."); return status; @@ -139,40 +139,40 @@ hw_ostc_device_open (dc_device_t **out, dc_context_t *context, const char *name) } // Set the default values. - device->port = NULL; + device->iostream = NULL; memset (device->fingerprint, 0, sizeof (device->fingerprint)); // Open the device. - status = dc_serial_open (&device->port, context, name); + status = dc_serial_open (&device->iostream, context, name); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the serial port."); goto error_free; } // Set the serial communication protocol (115200 8N1). - status = dc_serial_configure (device->port, 115200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); + status = dc_iostream_configure (device->iostream, 115200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); goto error_close; } // Set the timeout for receiving data. - status = dc_serial_set_timeout (device->port, 4000); + status = dc_iostream_set_timeout (device->iostream, 4000); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the timeout."); goto error_close; } // Make sure everything is in a sane state. - dc_serial_sleep (device->port, 100); - dc_serial_purge (device->port, DC_DIRECTION_ALL); + dc_iostream_sleep (device->iostream, 100); + dc_iostream_purge (device->iostream, DC_DIRECTION_ALL); *out = (dc_device_t*) device; return DC_STATUS_SUCCESS; error_close: - dc_serial_close (device->port); + dc_iostream_close (device->iostream); error_free: dc_device_deallocate ((dc_device_t *) device); return status; @@ -187,7 +187,7 @@ hw_ostc_device_close (dc_device_t *abstract) dc_status_t rc = DC_STATUS_SUCCESS; // Close the device. - rc = dc_serial_close (device->port); + rc = dc_iostream_close (device->iostream); if (rc != DC_STATUS_SUCCESS) { dc_status_set_error(&status, rc); } @@ -232,7 +232,7 @@ hw_ostc_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) // Send the command. unsigned char command[1] = {'a'}; - status = dc_serial_write (device->port, command, sizeof (command), NULL); + status = dc_iostream_write (device->iostream, command, sizeof (command), NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); return status; @@ -240,7 +240,7 @@ hw_ostc_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) // Read the header. unsigned char header[SZ_HEADER] = {0}; - status = dc_serial_read (device->port, header, sizeof (header), NULL); + status = dc_iostream_read (device->iostream, header, sizeof (header), NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the header."); return status; @@ -286,7 +286,7 @@ hw_ostc_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) // Increase the packet size if more data is immediately available. size_t available = 0; - status = dc_serial_get_available (device->port, &available); + status = dc_iostream_get_available (device->iostream, &available); if (status == DC_STATUS_SUCCESS && available > len) len = available; @@ -295,7 +295,7 @@ hw_ostc_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) len = size - nbytes; // Read the packet. - status = dc_serial_read (device->port, data + nbytes, len, NULL); + status = dc_iostream_read (device->iostream, data + nbytes, len, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); return status; @@ -369,7 +369,7 @@ hw_ostc_device_md2hash (dc_device_t *abstract, unsigned char data[], unsigned in return rc; // Read the answer. - status = dc_serial_read (device->port, data, SZ_MD2HASH, NULL); + status = dc_iostream_read (device->iostream, data, SZ_MD2HASH, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); return status; @@ -399,7 +399,7 @@ hw_ostc_device_timesync (dc_device_t *abstract, const dc_datetime_t *datetime) unsigned char packet[6] = { datetime->hour, datetime->minute, datetime->second, datetime->month, datetime->day, datetime->year - 2000}; - status = dc_serial_write (device->port, packet, sizeof (packet), NULL); + status = dc_iostream_write (device->iostream, packet, sizeof (packet), NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the data packet."); return status; @@ -435,7 +435,7 @@ hw_ostc_device_eeprom_read (dc_device_t *abstract, unsigned int bank, unsigned c return rc; // Read the answer. - status = dc_serial_read (device->port, data, SZ_EEPROM, NULL); + status = dc_iostream_read (device->iostream, data, SZ_EEPROM, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); return status; @@ -556,7 +556,7 @@ hw_ostc_device_screenshot (dc_device_t *abstract, dc_buffer_t *buffer, hw_ostc_f unsigned int npixels = 0; while (npixels < WIDTH * HEIGHT) { unsigned char raw[3] = {0}; - status = dc_serial_read (device->port, raw, 1, NULL); + status = dc_iostream_read (device->iostream, raw, 1, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the packet."); return status; @@ -574,7 +574,7 @@ hw_ostc_device_screenshot (dc_device_t *abstract, dc_buffer_t *buffer, hw_ostc_f count &= 0x3F; } else { // Color pixel. - status = dc_serial_read (device->port, raw + 1, 2, NULL); + status = dc_iostream_read (device->iostream, raw + 1, 2, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the packet."); return status; @@ -774,7 +774,7 @@ hw_ostc_firmware_setup_internal (hw_ostc_device_t *device) // Send the command. unsigned char command[1] = {0xC1}; - status = dc_serial_write (device->port, command, sizeof (command), NULL); + status = dc_iostream_write (device->iostream, command, sizeof (command), NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); return status; @@ -782,7 +782,7 @@ hw_ostc_firmware_setup_internal (hw_ostc_device_t *device) // Read the response. unsigned char answer[2] = {0}; - status = dc_serial_read (device->port, answer, sizeof (answer), NULL); + status = dc_iostream_read (device->iostream, answer, sizeof (answer), NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the response."); return status; @@ -825,7 +825,7 @@ hw_ostc_firmware_write_internal (hw_ostc_device_t *device, unsigned char *data, dc_device_t *abstract = (dc_device_t *) device; // Send the packet. - status = dc_serial_write (device->port, data, size, NULL); + status = dc_iostream_write (device->iostream, data, size, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the packet."); return status; @@ -833,7 +833,7 @@ hw_ostc_firmware_write_internal (hw_ostc_device_t *device, unsigned char *data, // Read the response. unsigned char answer[1] = {0}; - status = dc_serial_read (device->port, answer, sizeof (answer), NULL); + status = dc_iostream_read (device->iostream, answer, sizeof (answer), NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the response."); return status; @@ -905,13 +905,13 @@ hw_ostc_device_fwupdate (dc_device_t *abstract, const char *filename) // bootloader needs to be send repeatedly, until the response packet is // received. Thus the time between each two attempts is directly controlled // by the timeout value. - dc_serial_set_timeout (device->port, 300); + dc_iostream_set_timeout (device->iostream, 300); // Setup the bootloader. const unsigned int baudrates[] = {19200, 115200}; for (unsigned int i = 0; i < C_ARRAY_SIZE(baudrates); ++i) { // Adjust the baudrate. - rc = dc_serial_configure (device->port, baudrates[i], 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); + rc = dc_iostream_configure (device->iostream, baudrates[i], 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); if (rc != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to set the terminal attributes."); free (firmware); @@ -931,7 +931,7 @@ hw_ostc_device_fwupdate (dc_device_t *abstract, const char *filename) } // Increase the timeout again. - dc_serial_set_timeout (device->port, 1000); + dc_iostream_set_timeout (device->iostream, 1000); // Enable progress notifications. dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER; diff --git a/src/hw_ostc3.c b/src/hw_ostc3.c index 7ce7fd5..e240342 100644 --- a/src/hw_ostc3.c +++ b/src/hw_ostc3.c @@ -91,7 +91,7 @@ typedef enum hw_ostc3_state_t { typedef struct hw_ostc3_device_t { dc_device_t base; - dc_serial_t *port; + dc_iostream_t *iostream; unsigned int hardware; unsigned int feature; unsigned int model; @@ -197,7 +197,7 @@ hw_ostc3_transfer (hw_ostc3_device_t *device, // Send the command. unsigned char command[1] = {cmd}; - status = dc_serial_write (device->port, command, sizeof (command), NULL); + status = dc_iostream_write (device->iostream, command, sizeof (command), NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); return status; @@ -205,7 +205,7 @@ hw_ostc3_transfer (hw_ostc3_device_t *device, // Read the echo. unsigned char echo[1] = {0}; - status = dc_serial_read (device->port, echo, sizeof (echo), NULL); + status = dc_iostream_read (device->iostream, echo, sizeof (echo), NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the echo."); return status; @@ -234,7 +234,7 @@ hw_ostc3_transfer (hw_ostc3_device_t *device, len = isize - nbytes; // Write the packet. - status = dc_serial_write (device->port, input + nbytes, len, NULL); + status = dc_iostream_write (device->iostream, input + nbytes, len, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the data packet."); return status; @@ -258,7 +258,7 @@ hw_ostc3_transfer (hw_ostc3_device_t *device, // Increase the packet size if more data is immediately available. size_t available = 0; - status = dc_serial_get_available (device->port, &available); + status = dc_iostream_get_available (device->iostream, &available); if (status == DC_STATUS_SUCCESS && available > len) len = available; @@ -267,7 +267,7 @@ hw_ostc3_transfer (hw_ostc3_device_t *device, len = osize - nbytes; // Read the packet. - status = dc_serial_read (device->port, output + nbytes, len, NULL); + status = dc_iostream_read (device->iostream, output + nbytes, len, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); return status; @@ -287,18 +287,18 @@ hw_ostc3_transfer (hw_ostc3_device_t *device, unsigned int count = delay / 100; for (unsigned int i = 0; i < count; ++i) { size_t available = 0; - status = dc_serial_get_available (device->port, &available); + status = dc_iostream_get_available (device->iostream, &available); if (status == DC_STATUS_SUCCESS && available > 0) break; - dc_serial_sleep (device->port, 100); + dc_iostream_sleep (device->iostream, 100); } } if (cmd != EXIT) { // Read the ready byte. unsigned char answer[1] = {0}; - status = dc_serial_read (device->port, answer, sizeof (answer), NULL); + status = dc_iostream_read (device->iostream, answer, sizeof (answer), NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the ready byte."); return status; @@ -332,36 +332,36 @@ hw_ostc3_device_open (dc_device_t **out, dc_context_t *context, const char *name } // Set the default values. - device->port = NULL; + device->iostream = NULL; device->hardware = INVALID; device->feature = 0; device->model = 0; memset (device->fingerprint, 0, sizeof (device->fingerprint)); // Open the device. - status = dc_serial_open (&device->port, context, name); + status = dc_serial_open (&device->iostream, context, name); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the serial port."); goto error_free; } // Set the serial communication protocol (115200 8N1). - status = dc_serial_configure (device->port, 115200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); + status = dc_iostream_configure (device->iostream, 115200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); goto error_close; } // Set the timeout for receiving data (3000ms). - status = dc_serial_set_timeout (device->port, 3000); + status = dc_iostream_set_timeout (device->iostream, 3000); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the timeout."); goto error_close; } // Make sure everything is in a sane state. - dc_serial_sleep (device->port, 300); - dc_serial_purge (device->port, DC_DIRECTION_ALL); + dc_iostream_sleep (device->iostream, 300); + dc_iostream_purge (device->iostream, DC_DIRECTION_ALL); device->state = OPEN; @@ -370,7 +370,7 @@ hw_ostc3_device_open (dc_device_t **out, dc_context_t *context, const char *name return DC_STATUS_SUCCESS; error_close: - dc_serial_close (device->port); + dc_iostream_close (device->iostream); error_free: dc_device_deallocate ((dc_device_t *) device); return status; @@ -434,17 +434,17 @@ hw_ostc3_device_init_service (hw_ostc3_device_t *device) unsigned char output[5]; // We cant use hw_ostc3_transfer here, due to the different echos - status = dc_serial_write (device->port, command, sizeof (command), NULL); + status = dc_iostream_write (device->iostream, command, sizeof (command), NULL); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to send the command."); return status; } // Give the device some time to enter service mode - dc_serial_sleep (device->port, 100); + dc_iostream_sleep (device->iostream, 100); // Read the response - status = dc_serial_read (device->port, output, sizeof (output), NULL); + status = dc_iostream_read (device->iostream, output, sizeof (output), NULL); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to receive the echo."); return status; @@ -532,7 +532,7 @@ hw_ostc3_device_close (dc_device_t *abstract) } // Close the device. - rc = dc_serial_close (device->port); + rc = dc_iostream_close (device->iostream); if (rc != DC_STATUS_SUCCESS) { dc_status_set_error(&status, rc); } @@ -727,6 +727,11 @@ hw_ostc3_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, voi if (firmware < 93) length -= 3; } + if (length < RB_LOGBOOK_SIZE_FULL) { + ERROR (abstract->context, "Invalid profile length (%u bytes).", length); + free (header); + return DC_STATUS_DATAFORMAT; + } // Check the fingerprint data. if (memcmp (header + offset + logbook->fingerprint, device->fingerprint, sizeof (device->fingerprint)) == 0) @@ -789,6 +794,26 @@ hw_ostc3_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, voi return rc; } + // Detect invalid profile data. + unsigned int delta = device->hardware == OSTC4 ? 3 : 0; + if (length < RB_LOGBOOK_SIZE_FULL + 2 || + profile[length - 2] != 0xFD || profile[length - 1] != 0xFD) { + // A valid profile should have at least a correct 2 byte + // end-of-profile marker. + WARNING (abstract->context, "Invalid profile end marker detected!"); + length = RB_LOGBOOK_SIZE_FULL; + } else if (length == RB_LOGBOOK_SIZE_FULL + 2) { + // A profile containing only the 2 byte end-of-profile + // marker is considered a valid empty profile. + } else if (length < RB_LOGBOOK_SIZE_FULL + 5 + 2 || + array_uint24_le (profile + RB_LOGBOOK_SIZE_FULL) + delta != array_uint24_le (profile + 9)) { + // If there is more data available, then there should be a + // valid profile header containing a length matching the + // length in the dive header. + WARNING (abstract->context, "Invalid profile header detected."); + length = RB_LOGBOOK_SIZE_FULL; + } + if (callback && !callback (profile, length, profile + 12, sizeof (device->fingerprint), userdata)) break; } diff --git a/src/hw_ostc_parser.c b/src/hw_ostc_parser.c index ed5c824..6b065a9 100644 --- a/src/hw_ostc_parser.c +++ b/src/hw_ostc_parser.c @@ -65,6 +65,7 @@ #define OSTC3_CC 1 #define OSTC3_GAUGE 2 #define OSTC3_APNEA 3 +#define OSTC3_PSCR 4 #define OSTC3_ZHL16 0 #define OSTC3_ZHL16_GF 1 @@ -548,8 +549,10 @@ hw_ostc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned break; case OSTC_ZHL16_CC: case OSTC_ZHL16_CC_GF: + *((dc_divemode_t *) value) = DC_DIVEMODE_CCR; + break; case OSTC_PSCR_GF: - *((dc_divemode_t *) value) = DC_DIVEMODE_CC; + *((dc_divemode_t *) value) = DC_DIVEMODE_SCR; break; default: return DC_STATUS_DATAFORMAT; @@ -572,7 +575,7 @@ hw_ostc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned *((dc_divemode_t *) value) = DC_DIVEMODE_OC; break; case OSTC3_CC: - *((dc_divemode_t *) value) = DC_DIVEMODE_CC; + *((dc_divemode_t *) value) = DC_DIVEMODE_CCR; break; case OSTC3_GAUGE: *((dc_divemode_t *) value) = DC_DIVEMODE_GAUGE; @@ -580,6 +583,9 @@ hw_ostc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned case OSTC3_APNEA: *((dc_divemode_t *) value) = DC_DIVEMODE_FREEDIVE; break; + case OSTC3_PSCR: + *((dc_divemode_t *) value) = DC_DIVEMODE_SCR; + break; default: return DC_STATUS_DATAFORMAT; } @@ -685,6 +691,13 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call unsigned int header = parser->header; const hw_ostc_layout_t *layout = parser->layout; + // Exit if no profile data available. + if (size == header || (size == header + 2 && + data[header] == 0xFD && data[header + 1] == 0xFD)) { + parser->cached = PROFILE; + return DC_STATUS_SUCCESS; + } + // Check the header length. if (version == 0x23 || version == 0x24) { if (size < header + 5) { diff --git a/src/iostream-private.h b/src/iostream-private.h new file mode 100644 index 0000000..7f7be84 --- /dev/null +++ b/src/iostream-private.h @@ -0,0 +1,86 @@ +/* + * libdivecomputer + * + * Copyright (C) 2016 Jef Driesen + * + * This library 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 2.1 of the License, or (at your option) any later version. + * + * This library 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 this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#ifndef DC_IOSTREAM_PRIVATE_H +#define DC_IOSTREAM_PRIVATE_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef struct dc_iostream_vtable_t dc_iostream_vtable_t; + +struct dc_iostream_t { + const dc_iostream_vtable_t *vtable; + dc_context_t *context; +}; + +struct dc_iostream_vtable_t { + size_t size; + + dc_status_t (*set_timeout) (dc_iostream_t *iostream, int timeout); + + dc_status_t (*set_latency) (dc_iostream_t *iostream, unsigned int value); + + dc_status_t (*set_halfduplex) (dc_iostream_t *iostream, unsigned int value); + + dc_status_t (*set_break) (dc_iostream_t *iostream, unsigned int value); + + dc_status_t (*set_dtr) (dc_iostream_t *iostream, unsigned int value); + + dc_status_t (*set_rts) (dc_iostream_t *iostream, unsigned int value); + + dc_status_t (*get_lines) (dc_iostream_t *iostream, unsigned int *value); + + dc_status_t (*get_available) (dc_iostream_t *iostream, size_t *value); + + dc_status_t (*configure) (dc_iostream_t *iostream, unsigned int baudrate, unsigned int databits, dc_parity_t parity, dc_stopbits_t stopbits, dc_flowcontrol_t flowcontrol); + + dc_status_t (*read) (dc_iostream_t *iostream, void *data, size_t size, size_t *actual); + + dc_status_t (*write) (dc_iostream_t *iostream, const void *data, size_t size, size_t *actual); + + dc_status_t (*flush) (dc_iostream_t *iostream); + + dc_status_t (*purge) (dc_iostream_t *iostream, dc_direction_t direction); + + dc_status_t (*sleep) (dc_iostream_t *iostream, unsigned int milliseconds); + + dc_status_t (*close) (dc_iostream_t *iostream); +}; + +dc_iostream_t * +dc_iostream_allocate (dc_context_t *context, const dc_iostream_vtable_t *vtable); + +void +dc_iostream_deallocate (dc_iostream_t *iostream); + +int +dc_iostream_isinstance (dc_iostream_t *iostream, const dc_iostream_vtable_t *vtable); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* DC_IOSTREAM_PRIVATE_H */ diff --git a/src/iostream.c b/src/iostream.c new file mode 100644 index 0000000..e6c40ea --- /dev/null +++ b/src/iostream.c @@ -0,0 +1,254 @@ +/* + * libdivecomputer + * + * Copyright (C) 2016 Jef Driesen + * + * This library 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 2.1 of the License, or (at your option) any later version. + * + * This library 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 this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include +#include +#include + +#include "iostream-private.h" +#include "context-private.h" + +dc_iostream_t * +dc_iostream_allocate (dc_context_t *context, const dc_iostream_vtable_t *vtable) +{ + dc_iostream_t *iostream = NULL; + + assert(vtable != NULL); + assert(vtable->size >= sizeof(dc_iostream_t)); + + // Allocate memory. + iostream = (dc_iostream_t *) malloc (vtable->size); + if (iostream == NULL) { + ERROR (context, "Failed to allocate memory."); + return iostream; + } + + // Initialize the base class. + iostream->vtable = vtable; + iostream->context = context; + + return iostream; +} + +void +dc_iostream_deallocate (dc_iostream_t *iostream) +{ + free (iostream); +} + +int +dc_iostream_isinstance (dc_iostream_t *iostream, const dc_iostream_vtable_t *vtable) +{ + if (iostream == NULL) + return 0; + + return iostream->vtable == vtable; +} + +dc_status_t +dc_iostream_set_timeout (dc_iostream_t *iostream, int timeout) +{ + if (iostream == NULL || iostream->vtable->set_timeout == NULL) + return DC_STATUS_UNSUPPORTED; + + INFO (iostream->context, "Timeout: value=%i", timeout); + + return iostream->vtable->set_timeout (iostream, timeout); +} + +dc_status_t +dc_iostream_set_latency (dc_iostream_t *iostream, unsigned int value) +{ + if (iostream == NULL || iostream->vtable->set_latency == NULL) + return DC_STATUS_UNSUPPORTED; + + INFO (iostream->context, "Latency: value=%i", value); + + return iostream->vtable->set_latency (iostream, value); +} + +dc_status_t +dc_iostream_set_halfduplex (dc_iostream_t *iostream, unsigned int value) +{ + if (iostream == NULL || iostream->vtable->set_halfduplex == NULL) + return DC_STATUS_UNSUPPORTED; + + INFO (iostream->context, "Halfduplex: value=%i", value); + + return iostream->vtable->set_halfduplex (iostream, value); +} + +dc_status_t +dc_iostream_set_break (dc_iostream_t *iostream, unsigned int value) +{ + if (iostream == NULL || iostream->vtable->set_break == NULL) + return DC_STATUS_UNSUPPORTED; + + INFO (iostream->context, "Break: value=%i", value); + + return iostream->vtable->set_break (iostream, value); +} + +dc_status_t +dc_iostream_set_dtr (dc_iostream_t *iostream, unsigned int value) +{ + if (iostream == NULL || iostream->vtable->set_dtr == NULL) + return DC_STATUS_UNSUPPORTED; + + INFO (iostream->context, "DTR: value=%i", value); + + return iostream->vtable->set_dtr (iostream, value); +} + +dc_status_t +dc_iostream_set_rts (dc_iostream_t *iostream, unsigned int value) +{ + if (iostream == NULL || iostream->vtable->set_rts == NULL) + return DC_STATUS_UNSUPPORTED; + + INFO (iostream->context, "RTS: value=%i", value); + + return iostream->vtable->set_rts (iostream, value); +} + +dc_status_t +dc_iostream_get_lines (dc_iostream_t *iostream, unsigned int *value) +{ + if (iostream == NULL || iostream->vtable->get_lines == NULL) + return DC_STATUS_UNSUPPORTED; + + return iostream->vtable->get_lines (iostream, value); +} + +dc_status_t +dc_iostream_get_available (dc_iostream_t *iostream, size_t *value) +{ + if (iostream == NULL || iostream->vtable->get_available == NULL) + return DC_STATUS_UNSUPPORTED; + + return iostream->vtable->get_available (iostream, value); +} + +dc_status_t +dc_iostream_configure (dc_iostream_t *iostream, unsigned int baudrate, unsigned int databits, dc_parity_t parity, dc_stopbits_t stopbits, dc_flowcontrol_t flowcontrol) +{ + if (iostream == NULL || iostream->vtable->configure == NULL) + return DC_STATUS_UNSUPPORTED; + + INFO (iostream->context, "Configure: baudrate=%i, databits=%i, parity=%i, stopbits=%i, flowcontrol=%i", + baudrate, databits, parity, stopbits, flowcontrol); + + return iostream->vtable->configure (iostream, baudrate, databits, parity, stopbits, flowcontrol); +} + +dc_status_t +dc_iostream_read (dc_iostream_t *iostream, void *data, size_t size, size_t *actual) +{ + dc_status_t status = DC_STATUS_SUCCESS; + size_t nbytes = 0; + + if (iostream == NULL || iostream->vtable->read == NULL) { + status = DC_STATUS_UNSUPPORTED; + goto out; + } + + status = iostream->vtable->read (iostream, data, size, &nbytes); + + HEXDUMP (iostream->context, DC_LOGLEVEL_INFO, "Read", (unsigned char *) data, nbytes); + +out: + if (actual) + *actual = nbytes; + + return status; +} + +dc_status_t +dc_iostream_write (dc_iostream_t *iostream, const void *data, size_t size, size_t *actual) +{ + dc_status_t status = DC_STATUS_SUCCESS; + size_t nbytes = 0; + + if (iostream == NULL || iostream->vtable->read == NULL) { + status = DC_STATUS_UNSUPPORTED; + goto out; + } + + status = iostream->vtable->write (iostream, data, size, &nbytes); + + HEXDUMP (iostream->context, DC_LOGLEVEL_INFO, "Write", (const unsigned char *) data, nbytes); + +out: + if (actual) + *actual = nbytes; + + return status; +} + +dc_status_t +dc_iostream_flush (dc_iostream_t *iostream) +{ + if (iostream == NULL || iostream->vtable->flush == NULL) + return DC_STATUS_UNSUPPORTED; + + INFO (iostream->context, "Flush: none"); + + return iostream->vtable->flush (iostream); +} + +dc_status_t +dc_iostream_purge (dc_iostream_t *iostream, dc_direction_t direction) +{ + if (iostream == NULL || iostream->vtable->purge == NULL) + return DC_STATUS_UNSUPPORTED; + + INFO (iostream->context, "Purge: direction=%u", direction); + + return iostream->vtable->purge (iostream, direction); +} + +dc_status_t +dc_iostream_sleep (dc_iostream_t *iostream, unsigned int milliseconds) +{ + if (iostream == NULL || iostream->vtable->sleep == NULL) + return DC_STATUS_UNSUPPORTED; + + INFO (iostream->context, "Sleep: value=%u", milliseconds); + + return iostream->vtable->sleep (iostream, milliseconds); +} + +dc_status_t +dc_iostream_close (dc_iostream_t *iostream) +{ + dc_status_t status = DC_STATUS_SUCCESS; + + if (iostream == NULL) + return DC_STATUS_SUCCESS; + + if (iostream->vtable->close) { + status = iostream->vtable->close (iostream); + } + + dc_iostream_deallocate (iostream); + + return status; +} diff --git a/src/irda.c b/src/irda.c index 1a2c38c..149808a 100644 --- a/src/irda.c +++ b/src/irda.c @@ -25,218 +25,89 @@ #include // malloc, free #include // snprintf +#include + +#include "socket.h" + #ifdef _WIN32 - #define NOGDI - #include - #include - #ifdef HAVE_AF_IRDA_H - #define IRDA - #include - #endif +#ifdef HAVE_AF_IRDA_H +#define IRDA +#include +#endif #else - #include // strerror - #include // errno - #include // close - #include // socket, getsockopt - #include // socket, getsockopt - #ifdef HAVE_LINUX_IRDA_H - #define IRDA - #include // irda - #include // irda - #endif - #include // select - #include // ioctl - #include +#ifdef HAVE_LINUX_IRDA_H +#define IRDA +#include +#include +#endif #endif #include "irda.h" + #include "common-private.h" #include "context-private.h" +#include "iostream-private.h" #include "array.h" #include "platform.h" -#ifdef _WIN32 -typedef int s_ssize_t; -typedef DWORD s_errcode_t; -#define S_ERRNO WSAGetLastError () -#define S_EINTR WSAEINTR -#define S_EAGAIN WSAEWOULDBLOCK -#define S_ENOMEM WSA_NOT_ENOUGH_MEMORY -#define S_EINVAL WSAEINVAL -#define S_EACCES WSAEACCES -#define S_EAFNOSUPPORT WSAEAFNOSUPPORT -#define S_INVALID INVALID_SOCKET -#define S_IOCTL ioctlsocket -#define S_CLOSE closesocket -#else -typedef ssize_t s_ssize_t; -typedef int s_errcode_t; -#define S_ERRNO errno -#define S_EINTR EINTR -#define S_EAGAIN EAGAIN -#define S_ENOMEM ENOMEM -#define S_EINVAL EINVAL -#define S_EACCES EACCES -#define S_EAFNOSUPPORT EAFNOSUPPORT -#define S_INVALID -1 -#define S_IOCTL ioctl -#define S_CLOSE close -#endif - -struct dc_irda_t { - dc_context_t *context; -#ifdef _WIN32 - SOCKET fd; -#else - int fd; -#endif - int timeout; -}; +#define ISINSTANCE(device) dc_iostream_isinstance((device), &dc_irda_vtable) #ifdef IRDA -static dc_status_t -syserror(s_errcode_t errcode) -{ - switch (errcode) { - case S_EINVAL: - return DC_STATUS_INVALIDARGS; - case S_ENOMEM: - return DC_STATUS_NOMEMORY; - case S_EACCES: - return DC_STATUS_NOACCESS; - case S_EAFNOSUPPORT: - return DC_STATUS_UNSUPPORTED; - default: - return DC_STATUS_IO; - } -} +static const dc_iostream_vtable_t dc_irda_vtable = { + sizeof(dc_socket_t), + dc_socket_set_timeout, /* set_timeout */ + dc_socket_set_latency, /* set_latency */ + dc_socket_set_halfduplex, /* set_halfduplex */ + dc_socket_set_break, /* set_break */ + dc_socket_set_dtr, /* set_dtr */ + dc_socket_set_rts, /* set_rts */ + dc_socket_get_lines, /* get_lines */ + dc_socket_get_available, /* get_received */ + dc_socket_configure, /* configure */ + dc_socket_read, /* read */ + dc_socket_write, /* write */ + dc_socket_flush, /* flush */ + dc_socket_purge, /* purge */ + dc_socket_sleep, /* sleep */ + dc_socket_close, /* close */ +}; #endif dc_status_t -dc_irda_open (dc_irda_t **out, dc_context_t *context) +dc_irda_open (dc_iostream_t **out, dc_context_t *context) { #ifdef IRDA dc_status_t status = DC_STATUS_SUCCESS; - dc_irda_t *device = NULL; + dc_socket_t *device = NULL; if (out == NULL) return DC_STATUS_INVALIDARGS; // Allocate memory. - device = (dc_irda_t *) malloc (sizeof (dc_irda_t)); + device = (dc_socket_t *) dc_iostream_allocate (context, &dc_irda_vtable); if (device == NULL) { SYSERROR (context, S_ENOMEM); return DC_STATUS_NOMEMORY; } - // Library context. - device->context = context; - - // Default to blocking reads. - device->timeout = -1; - -#ifdef _WIN32 - // Initialize the winsock dll. - WSADATA wsaData; - WORD wVersionRequested = MAKEWORD (2, 2); - int rc = WSAStartup (wVersionRequested, &wsaData); - if (rc != 0) { - SYSERROR (context, rc); - status = DC_STATUS_UNSUPPORTED; + // Open the socket. + status = dc_socket_open (&device->base, AF_IRDA, SOCK_STREAM, 0); + if (status != DC_STATUS_SUCCESS) { goto error_free; } - // Confirm that the winsock dll supports version 2.2. - // Note that if the dll supports versions greater than 2.2 in addition to - // 2.2, it will still return 2.2 since that is the version we requested. - if (LOBYTE (wsaData.wVersion) != 2 || - HIBYTE (wsaData.wVersion) != 2) { - ERROR (context, "Incorrect winsock version."); - status = DC_STATUS_UNSUPPORTED; - goto error_wsacleanup; - } -#endif - - // Open the socket. - device->fd = socket (AF_IRDA, SOCK_STREAM, 0); - if (device->fd == S_INVALID) { - s_errcode_t errcode = S_ERRNO; - SYSERROR (context, errcode); - status = syserror(errcode); - goto error_wsacleanup; - } - - *out = device; + *out = (dc_iostream_t *) device; return DC_STATUS_SUCCESS; -error_wsacleanup: -#ifdef _WIN32 - WSACleanup (); error_free: -#endif - free (device); + dc_iostream_deallocate ((dc_iostream_t *) device); return status; #else return DC_STATUS_UNSUPPORTED; #endif } -dc_status_t -dc_irda_close (dc_irda_t *device) -{ -#ifdef IRDA - dc_status_t status = DC_STATUS_SUCCESS; - - if (device == NULL) - return DC_STATUS_SUCCESS; - - // Terminate all send and receive operations. - shutdown (device->fd, 0); - - // Close the socket. - if (S_CLOSE (device->fd) != 0) { - s_errcode_t errcode = S_ERRNO; - SYSERROR (device->context, errcode); - dc_status_set_error(&status, syserror(errcode)); - } - -#ifdef _WIN32 - // Terminate the winsock dll. - if (WSACleanup () != 0) { - s_errcode_t errcode = S_ERRNO; - SYSERROR (device->context, errcode); - dc_status_set_error(&status, syserror(errcode)); - } -#endif - - // Free memory. - free (device); - - return status; -#else - return DC_STATUS_UNSUPPORTED; -#endif -} - -dc_status_t -dc_irda_set_timeout (dc_irda_t *device, int timeout) -{ -#ifdef IRDA - if (device == NULL) - return DC_STATUS_INVALIDARGS; - - INFO (device->context, "Timeout: value=%i", timeout); - - device->timeout = timeout; - - return DC_STATUS_SUCCESS; -#else - return DC_STATUS_UNSUPPORTED; -#endif -} - - #define DISCOVER_MAX_DEVICES 16 // Maximum number of devices. #define DISCOVER_MAX_RETRIES 4 // Maximum number of retries. @@ -249,10 +120,12 @@ dc_irda_set_timeout (dc_irda_t *device, int timeout) #endif dc_status_t -dc_irda_discover (dc_irda_t *device, dc_irda_callback_t callback, void *userdata) +dc_irda_discover (dc_iostream_t *abstract, dc_irda_callback_t callback, void *userdata) { #ifdef IRDA - if (device == NULL) + dc_socket_t *device = (dc_socket_t *) abstract; + + if (!ISINSTANCE (abstract)) return DC_STATUS_INVALIDARGS; unsigned char data[DISCOVER_BUFSIZE] = {0}; @@ -280,8 +153,8 @@ dc_irda_discover (dc_irda_t *device, dc_irda_callback_t callback, void *userdata if (rc != 0) { s_errcode_t errcode = S_ERRNO; if (errcode != S_EAGAIN) { - SYSERROR (device->context, errcode); - return syserror(errcode); + SYSERROR (abstract->context, errcode); + return dc_socket_syserror(errcode); } } @@ -316,7 +189,7 @@ dc_irda_discover (dc_irda_t *device, dc_irda_callback_t callback, void *userdata unsigned int hints = array_uint16_be (list->dev[i].hints); #endif - INFO (device->context, + INFO (abstract->context, "Discover: address=%08x, name=%s, charset=%02x, hints=%04x", address, name, charset, hints); @@ -331,13 +204,15 @@ dc_irda_discover (dc_irda_t *device, dc_irda_callback_t callback, void *userdata } dc_status_t -dc_irda_connect_name (dc_irda_t *device, unsigned int address, const char *name) +dc_irda_connect_name (dc_iostream_t *abstract, unsigned int address, const char *name) { #ifdef IRDA - if (device == NULL) + dc_socket_t *device = (dc_socket_t *) abstract; + + if (!ISINSTANCE (abstract)) return DC_STATUS_INVALIDARGS; - INFO (device->context, "Connect: address=%08x, name=%s", address, name ? name : ""); + INFO (abstract->context, "Connect: address=%08x, name=%s", address, name ? name : ""); #ifdef _WIN32 SOCKADDR_IRDA peer; @@ -360,26 +235,22 @@ dc_irda_connect_name (dc_irda_t *device, unsigned int address, const char *name) memset (peer.sir_name, 0x00, 25); #endif - if (connect (device->fd, (struct sockaddr *) &peer, sizeof (peer)) != 0) { - s_errcode_t errcode = S_ERRNO; - SYSERROR (device->context, errcode); - return syserror(errcode); - } - - return DC_STATUS_SUCCESS; + return dc_socket_connect (&device->base, (struct sockaddr *) &peer, sizeof (peer)); #else return DC_STATUS_UNSUPPORTED; #endif } dc_status_t -dc_irda_connect_lsap (dc_irda_t *device, unsigned int address, unsigned int lsap) +dc_irda_connect_lsap (dc_iostream_t *abstract, unsigned int address, unsigned int lsap) { #ifdef IRDA - if (device == NULL) + dc_socket_t *device = (dc_socket_t *) abstract; + + if (!ISINSTANCE (abstract)) return DC_STATUS_INVALIDARGS; - INFO (device->context, "Connect: address=%08x, lsap=%u", address, lsap); + INFO (abstract->context, "Connect: address=%08x, lsap=%u", address, lsap); #ifdef _WIN32 SOCKADDR_IRDA peer; @@ -397,171 +268,7 @@ dc_irda_connect_lsap (dc_irda_t *device, unsigned int address, unsigned int lsap memset (peer.sir_name, 0x00, 25); #endif - if (connect (device->fd, (struct sockaddr *) &peer, sizeof (peer)) != 0) { - s_errcode_t errcode = S_ERRNO; - SYSERROR (device->context, errcode); - return syserror(errcode); - } - - return DC_STATUS_SUCCESS; -#else - return DC_STATUS_UNSUPPORTED; -#endif -} - -dc_status_t -dc_irda_get_available (dc_irda_t *device, size_t *value) -{ -#ifdef IRDA - if (device == NULL) - return DC_STATUS_INVALIDARGS; - -#ifdef _WIN32 - unsigned long bytes = 0; -#else - int bytes = 0; -#endif - - if (S_IOCTL (device->fd, FIONREAD, &bytes) != 0) { - s_errcode_t errcode = S_ERRNO; - SYSERROR (device->context, errcode); - return syserror(errcode); - } - - if (value) - *value = bytes; - - return DC_STATUS_SUCCESS; -#else - return DC_STATUS_UNSUPPORTED; -#endif -} - -dc_status_t -dc_irda_read (dc_irda_t *device, void *data, size_t size, size_t *actual) -{ -#ifdef IRDA - dc_status_t status = DC_STATUS_SUCCESS; - size_t nbytes = 0; - - if (device == NULL) { - status = DC_STATUS_INVALIDARGS; - goto out_invalidargs; - } - - while (nbytes < size) { - fd_set fds; - FD_ZERO (&fds); - FD_SET (device->fd, &fds); - - struct timeval tvt; - if (device->timeout > 0) { - tvt.tv_sec = (device->timeout / 1000); - tvt.tv_usec = (device->timeout % 1000) * 1000; - } else if (device->timeout == 0) { - timerclear (&tvt); - } - - int rc = select (device->fd + 1, &fds, NULL, NULL, device->timeout >= 0 ? &tvt : NULL); - if (rc < 0) { - s_errcode_t errcode = S_ERRNO; - if (errcode == S_EINTR) - continue; // Retry. - SYSERROR (device->context, errcode); - status = syserror(errcode); - goto out; - } else if (rc == 0) { - break; // Timeout. - } - - s_ssize_t n = recv (device->fd, (char*) data + nbytes, size - nbytes, 0); - if (n < 0) { - s_errcode_t errcode = S_ERRNO; - if (errcode == S_EINTR || errcode == S_EAGAIN) - continue; // Retry. - SYSERROR (device->context, errcode); - status = syserror(errcode); - goto out; - } else if (n == 0) { - break; // EOF reached. - } - - nbytes += n; - } - - if (nbytes != size) { - status = DC_STATUS_TIMEOUT; - } - -out: - HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Read", (unsigned char *) data, nbytes); - -out_invalidargs: - if (actual) - *actual = nbytes; - - return status; -#else - return DC_STATUS_UNSUPPORTED; -#endif -} - -dc_status_t -dc_irda_write (dc_irda_t *device, const void *data, size_t size, size_t *actual) -{ -#ifdef IRDA - dc_status_t status = DC_STATUS_SUCCESS; - size_t nbytes = 0; - - if (device == NULL) { - status = DC_STATUS_INVALIDARGS; - goto out_invalidargs; - } - - while (nbytes < size) { - fd_set fds; - FD_ZERO (&fds); - FD_SET (device->fd, &fds); - - int rc = select (device->fd + 1, NULL, &fds, NULL, NULL); - if (rc < 0) { - s_errcode_t errcode = S_ERRNO; - if (errcode == S_EINTR) - continue; // Retry. - SYSERROR (device->context, errcode); - status = syserror(errcode); - goto out; - } else if (rc == 0) { - break; // Timeout. - } - - s_ssize_t n = send (device->fd, (const char *) data + nbytes, size - nbytes, 0); - if (n < 0) { - s_errcode_t errcode = S_ERRNO; - if (errcode == S_EINTR || errcode == S_EAGAIN) - continue; // Retry. - SYSERROR (device->context, errcode); - status = syserror(errcode); - goto out; - } else if (n == 0) { - break; // EOF. - } - - nbytes += n; - } - - if (nbytes != size) { - status = DC_STATUS_TIMEOUT; - } - -out: - HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Write", (const unsigned char *) data, nbytes); - -out_invalidargs: - if (actual) - *actual = nbytes; - - return status; + return dc_socket_connect (&device->base, (struct sockaddr *) &peer, sizeof (peer)); #else return DC_STATUS_UNSUPPORTED; #endif diff --git a/src/irda.h b/src/irda.h index 84d2f4d..c413963 100644 --- a/src/irda.h +++ b/src/irda.h @@ -24,16 +24,12 @@ #include #include +#include #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ -/** - * Opaque object representing an IrDA connection. - */ -typedef struct dc_irda_t dc_irda_t; - /** * IrDA enumeration callback. * @@ -48,130 +44,49 @@ typedef void (*dc_irda_callback_t) (unsigned int address, const char *name, unsi /** * Open an IrDA connection. * - * @param[out] irda A location to store the IrDA connection. + * @param[out] iostream A location to store the IrDA connection. * @param[in] context A valid context object. * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code * on failure. */ dc_status_t -dc_irda_open (dc_irda_t **irda, dc_context_t *context); - -/** - * Close the IrDA connection and free all resources. - * - * @param[in] irda A valid IrDA connection. - * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code - * on failure. - */ -dc_status_t -dc_irda_close (dc_irda_t *irda); - -/** - * Set the read timeout. - * - * There are three distinct modes available: - * - * 1. Blocking (timeout < 0): - * - * The read operation is blocked until all the requested bytes have - * been received. If the requested number of bytes does not arrive, - * the operation will block forever. - * - * 2. Non-blocking (timeout == 0): - * - * The read operation returns immediately with the bytes that have - * already been received, even if no bytes have been received. - * - * 3. Timeout (timeout > 0): - * - * The read operation is blocked until all the requested bytes have - * been received. If the requested number of bytes does not arrive - * within the specified amount of time, the operation will return - * with the bytes that have already been received. - * - * @param[in] irda A valid IrDA connection. - * @param[in] timeout The timeout in milliseconds. - * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code - * on failure. - */ -dc_status_t -dc_irda_set_timeout (dc_irda_t *irda, int timeout); +dc_irda_open (dc_iostream_t **iostream, dc_context_t *context); /** * Enumerate the IrDA devices. * - * @param[in] irda A valid IrDA connection. + * @param[in] iostream A valid IrDA connection. * @param[in] callback The callback function to call. * @param[in] userdata User data to pass to the callback function. * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code * on failure. */ dc_status_t -dc_irda_discover (dc_irda_t *irda, dc_irda_callback_t callback, void *userdata); +dc_irda_discover (dc_iostream_t *iostream, dc_irda_callback_t callback, void *userdata); /** * Connect to an IrDA device. * - * @param[in] irda A valid IrDA connection. + * @param[in] iostream A valid IrDA connection. * @param[in] address The IrDA device address. * @param[in] name The IrDA service name. * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code * on failure. */ dc_status_t -dc_irda_connect_name (dc_irda_t *irda, unsigned int address, const char *name); +dc_irda_connect_name (dc_iostream_t *iostream, unsigned int address, const char *name); /** * Connect to an IrDA device. * - * @param[in] irda A valid IrDA connection. + * @param[in] iostream A valid IrDA connection. * @param[in] address The IrDA device address. * @param[in] lsap The IrDA LSAP number. * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code * on failure. */ dc_status_t -dc_irda_connect_lsap (dc_irda_t *irda, unsigned int address, unsigned int lsap); - -/** - * Query the number of available bytes in the input buffer. - * - * @param[in] irda A valid IrDA connection. - * @param[out] value A location to store the number of bytes in the - * input buffer. - * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code - * on failure. - */ -dc_status_t -dc_irda_get_available (dc_irda_t *irda, size_t *value); - -/** - * Read data from the IrDA connection. - * - * @param[in] irda A valid IrDA connection. - * @param[out] data The memory buffer to read the data into. - * @param[in] size The number of bytes to read. - * @param[out] actual An (optional) location to store the actual - * number of bytes transferred. - * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code - * on failure. - */ -dc_status_t -dc_irda_read (dc_irda_t *irda, void *data, size_t size, size_t *actual); - -/** - * Write data to the IrDA connection. - * - * @param[in] irda A valid IrDA connection. - * @param[in] data The memory buffer to write the data from. - * @param[in] size The number of bytes to write. - * @param[out] actual An (optional) location to store the actual - * number of bytes transferred. - * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code - * on failure. - */ -dc_status_t -dc_irda_write (dc_irda_t *irda, const void *data, size_t size, size_t *actual); +dc_irda_connect_lsap (dc_iostream_t *iostream, unsigned int address, unsigned int lsap); #ifdef __cplusplus } diff --git a/src/libdivecomputer.symbols b/src/libdivecomputer.symbols index 62f13c3..f272bd6 100644 --- a/src/libdivecomputer.symbols +++ b/src/libdivecomputer.symbols @@ -34,6 +34,22 @@ dc_descriptor_get_type dc_descriptor_get_model dc_descriptor_get_transport +dc_iostream_set_timeout +dc_iostream_set_halfduplex +dc_iostream_set_latency +dc_iostream_set_break +dc_iostream_set_dtr +dc_iostream_set_rts +dc_iostream_get_available +dc_iostream_get_lines +dc_iostream_configure +dc_iostream_read +dc_iostream_write +dc_iostream_flush +dc_iostream_purge +dc_iostream_sleep +dc_iostream_close + dc_parser_new dc_parser_new2 dc_parser_get_type diff --git a/src/mares_common.c b/src/mares_common.c index b157dc2..f476d8d 100644 --- a/src/mares_common.c +++ b/src/mares_common.c @@ -52,7 +52,7 @@ mares_common_device_init (mares_common_device_t *device) assert (device != NULL); // Set the default values. - device->port = NULL; + device->iostream = NULL; device->echo = 0; device->delay = 0; } @@ -88,11 +88,11 @@ mares_common_packet (mares_common_device_t *device, const unsigned char command[ return DC_STATUS_CANCELLED; if (device->delay) { - dc_serial_sleep (device->port, device->delay); + dc_iostream_sleep (device->iostream, device->delay); } // Send the command to the device. - status = dc_serial_write (device->port, command, csize, NULL); + status = dc_iostream_write (device->iostream, command, csize, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); return status; @@ -101,7 +101,7 @@ mares_common_packet (mares_common_device_t *device, const unsigned char command[ if (device->echo) { // Receive the echo of the command. unsigned char echo[PACKETSIZE] = {0}; - status = dc_serial_read (device->port, echo, csize, NULL); + status = dc_iostream_read (device->iostream, echo, csize, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the echo."); return status; @@ -114,7 +114,7 @@ mares_common_packet (mares_common_device_t *device, const unsigned char command[ } // Receive the answer of the device. - status = dc_serial_read (device->port, answer, asize, NULL); + status = dc_iostream_read (device->iostream, answer, asize, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); return status; @@ -155,8 +155,8 @@ mares_common_transfer (mares_common_device_t *device, const unsigned char comman return rc; // Discard any garbage bytes. - dc_serial_sleep (device->port, 100); - dc_serial_purge (device->port, DC_DIRECTION_INPUT); + dc_iostream_sleep (device->iostream, 100); + dc_iostream_purge (device->iostream, DC_DIRECTION_INPUT); } return rc; diff --git a/src/mares_common.h b/src/mares_common.h index 4652d06..8cb58ca 100644 --- a/src/mares_common.h +++ b/src/mares_common.h @@ -41,7 +41,7 @@ typedef struct mares_common_layout_t { typedef struct mares_common_device_t { dc_device_t base; - dc_serial_t *port; + dc_iostream_t *iostream; unsigned int echo; unsigned int delay; } mares_common_device_t; diff --git a/src/mares_darwin.c b/src/mares_darwin.c index 4b1bc24..4f87f6f 100644 --- a/src/mares_darwin.c +++ b/src/mares_darwin.c @@ -125,43 +125,43 @@ mares_darwin_device_open (dc_device_t **out, dc_context_t *context, const char * device->layout = &mares_darwin_layout; // Open the device. - status = dc_serial_open (&device->base.port, context, name); + status = dc_serial_open (&device->base.iostream, context, name); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the serial port."); goto error_free; } // Set the serial communication protocol (9600 8N1). - status = dc_serial_configure (device->base.port, 9600, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); + status = dc_iostream_configure (device->base.iostream, 9600, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); goto error_close; } // Set the timeout for receiving data (1000 ms). - status = dc_serial_set_timeout (device->base.port, 1000); + status = dc_iostream_set_timeout (device->base.iostream, 1000); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the timeout."); goto error_close; } // Set the DTR line. - status = dc_serial_set_dtr (device->base.port, 1); + status = dc_iostream_set_dtr (device->base.iostream, 1); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the DTR line."); goto error_close; } // Set the RTS line. - status = dc_serial_set_rts (device->base.port, 1); + status = dc_iostream_set_rts (device->base.iostream, 1); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the RTS line."); goto error_close; } // Make sure everything is in a sane state. - dc_serial_sleep (device->base.port, 100); - dc_serial_purge (device->base.port, DC_DIRECTION_ALL); + dc_iostream_sleep (device->base.iostream, 100); + dc_iostream_purge (device->base.iostream, DC_DIRECTION_ALL); // Override the base class values. device->base.echo = 1; @@ -172,7 +172,7 @@ mares_darwin_device_open (dc_device_t **out, dc_context_t *context, const char * return DC_STATUS_SUCCESS; error_close: - dc_serial_close (device->base.port); + dc_iostream_close (device->base.iostream); error_free: dc_device_deallocate ((dc_device_t *) device); return status; @@ -186,7 +186,7 @@ mares_darwin_device_close (dc_device_t *abstract) dc_status_t rc = DC_STATUS_SUCCESS; // Close the device. - rc = dc_serial_close (device->base.port); + rc = dc_iostream_close (device->base.iostream); if (rc != DC_STATUS_SUCCESS) { dc_status_set_error(&status, rc); } diff --git a/src/mares_iconhd.c b/src/mares_iconhd.c index e945e9f..990f466 100644 --- a/src/mares_iconhd.c +++ b/src/mares_iconhd.c @@ -65,7 +65,7 @@ typedef struct mares_iconhd_model_t { typedef struct mares_iconhd_device_t { dc_device_t base; - dc_serial_t *port; + dc_iostream_t *iostream; const mares_iconhd_layout_t *layout; unsigned char fingerprint[10]; unsigned char version[140]; @@ -157,7 +157,7 @@ mares_iconhd_transfer (mares_iconhd_device_t *device, return DC_STATUS_CANCELLED; // Send the command header to the dive computer. - status = dc_serial_write (device->port, command, 2, NULL); + status = dc_iostream_write (device->iostream, command, 2, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); return status; @@ -165,7 +165,7 @@ mares_iconhd_transfer (mares_iconhd_device_t *device, // Receive the header byte. unsigned char header[1] = {0}; - status = dc_serial_read (device->port, header, sizeof (header), NULL); + status = dc_iostream_read (device->iostream, header, sizeof (header), NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); return status; @@ -179,7 +179,7 @@ mares_iconhd_transfer (mares_iconhd_device_t *device, // Send the command payload to the dive computer. if (csize > 2) { - status = dc_serial_write (device->port, command + 2, csize - 2, NULL); + status = dc_iostream_write (device->iostream, command + 2, csize - 2, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); return status; @@ -187,7 +187,7 @@ mares_iconhd_transfer (mares_iconhd_device_t *device, } // Read the packet. - status = dc_serial_read (device->port, answer, asize, NULL); + status = dc_iostream_read (device->iostream, answer, asize, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); return status; @@ -195,7 +195,7 @@ mares_iconhd_transfer (mares_iconhd_device_t *device, // Receive the trailer byte. unsigned char trailer[1] = {0}; - status = dc_serial_read (device->port, trailer, sizeof (trailer), NULL); + status = dc_iostream_read (device->iostream, trailer, sizeof (trailer), NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); return status; @@ -228,7 +228,7 @@ mares_iconhd_device_open (dc_device_t **out, dc_context_t *context, const char * } // Set the default values. - device->port = NULL; + device->iostream = NULL; device->layout = NULL; memset (device->fingerprint, 0, sizeof (device->fingerprint)); memset (device->version, 0, sizeof (device->version)); @@ -236,42 +236,42 @@ mares_iconhd_device_open (dc_device_t **out, dc_context_t *context, const char * device->packetsize = 0; // Open the device. - status = dc_serial_open (&device->port, context, name); + status = dc_serial_open (&device->iostream, context, name); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the serial port."); goto error_free; } // Set the serial communication protocol (115200 8E1). - status = dc_serial_configure (device->port, 115200, 8, DC_PARITY_EVEN, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); + status = dc_iostream_configure (device->iostream, 115200, 8, DC_PARITY_EVEN, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); goto error_close; } // Set the timeout for receiving data (1000 ms). - status = dc_serial_set_timeout (device->port, 1000); + status = dc_iostream_set_timeout (device->iostream, 1000); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the timeout."); goto error_close; } // Clear the DTR line. - status = dc_serial_set_dtr (device->port, 0); + status = dc_iostream_set_dtr (device->iostream, 0); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to clear the DTR line."); goto error_close; } // Clear the RTS line. - status = dc_serial_set_rts (device->port, 0); + status = dc_iostream_set_rts (device->iostream, 0); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to clear the RTS line."); goto error_close; } // Make sure everything is in a sane state. - dc_serial_purge (device->port, DC_DIRECTION_ALL); + dc_iostream_purge (device->iostream, DC_DIRECTION_ALL); // Send the version command. unsigned char command[] = {0xC2, 0x67}; @@ -315,7 +315,7 @@ mares_iconhd_device_open (dc_device_t **out, dc_context_t *context, const char * return DC_STATUS_SUCCESS; error_close: - dc_serial_close (device->port); + dc_iostream_close (device->iostream); error_free: dc_device_deallocate ((dc_device_t *) device); return status; @@ -330,7 +330,7 @@ mares_iconhd_device_close (dc_device_t *abstract) dc_status_t rc = DC_STATUS_SUCCESS; // Close the device. - rc = dc_serial_close (device->port); + rc = dc_iostream_close (device->iostream); if (rc != DC_STATUS_SUCCESS) { dc_status_set_error(&status, rc); } diff --git a/src/mares_nemo.c b/src/mares_nemo.c index c73c24b..d6d4e01 100644 --- a/src/mares_nemo.c +++ b/src/mares_nemo.c @@ -45,7 +45,7 @@ typedef struct mares_nemo_device_t { dc_device_t base; - dc_serial_t *port; + dc_iostream_t *iostream; unsigned char fingerprint[5]; } mares_nemo_device_t; @@ -100,53 +100,53 @@ mares_nemo_device_open (dc_device_t **out, dc_context_t *context, const char *na } // Set the default values. - device->port = NULL; + device->iostream = NULL; memset (device->fingerprint, 0, sizeof (device->fingerprint)); // Open the device. - status = dc_serial_open (&device->port, context, name); + status = dc_serial_open (&device->iostream, context, name); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the serial port."); goto error_free; } // Set the serial communication protocol (9600 8N1). - status = dc_serial_configure (device->port, 9600, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); + status = dc_iostream_configure (device->iostream, 9600, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); goto error_close; } // Set the timeout for receiving data (1000 ms). - status = dc_serial_set_timeout (device->port, 1000); + status = dc_iostream_set_timeout (device->iostream, 1000); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the timeout."); goto error_close; } // Set the DTR line. - status = dc_serial_set_dtr (device->port, 1); + status = dc_iostream_set_dtr (device->iostream, 1); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the DTR line."); goto error_close; } // Set the RTS line. - status = dc_serial_set_rts (device->port, 1); + status = dc_iostream_set_rts (device->iostream, 1); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the RTS line."); goto error_close; } // Make sure everything is in a sane state. - dc_serial_purge (device->port, DC_DIRECTION_ALL); + dc_iostream_purge (device->iostream, DC_DIRECTION_ALL); *out = (dc_device_t*) device; return DC_STATUS_SUCCESS; error_close: - dc_serial_close (device->port); + dc_iostream_close (device->iostream); error_free: dc_device_deallocate ((dc_device_t *) device); return status; @@ -161,7 +161,7 @@ mares_nemo_device_close (dc_device_t *abstract) dc_status_t rc = DC_STATUS_SUCCESS; // Close the device. - rc = dc_serial_close (device->port); + rc = dc_iostream_close (device->iostream); if (rc != DC_STATUS_SUCCESS) { dc_status_set_error(&status, rc); } @@ -207,18 +207,18 @@ mares_nemo_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) // Wait until some data arrives. size_t available = 0; - while (dc_serial_get_available (device->port, &available) == DC_STATUS_SUCCESS && available == 0) { + while (dc_iostream_get_available (device->iostream, &available) == DC_STATUS_SUCCESS && available == 0) { if (device_is_cancelled (abstract)) return DC_STATUS_CANCELLED; device_event_emit (abstract, DC_EVENT_WAITING, NULL); - dc_serial_sleep (device->port, 100); + dc_iostream_sleep (device->iostream, 100); } // Receive the header of the package. unsigned char header = 0x00; for (unsigned int i = 0; i < 20;) { - status = dc_serial_read (device->port, &header, 1, NULL); + status = dc_iostream_read (device->iostream, &header, 1, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the header."); return status; @@ -238,7 +238,7 @@ mares_nemo_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) while (nbytes < MEMORYSIZE) { // Read the packet. unsigned char packet[(PACKETSIZE + 1) * 2] = {0}; - status = dc_serial_read (device->port, packet, sizeof (packet), NULL); + status = dc_iostream_read (device->iostream, packet, sizeof (packet), NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); return status; diff --git a/src/mares_puck.c b/src/mares_puck.c index b220f54..5006b43 100644 --- a/src/mares_puck.c +++ b/src/mares_puck.c @@ -110,42 +110,42 @@ mares_puck_device_open (dc_device_t **out, dc_context_t *context, const char *na memset (device->fingerprint, 0, sizeof (device->fingerprint)); // Open the device. - status = dc_serial_open (&device->base.port, context, name); + status = dc_serial_open (&device->base.iostream, context, name); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the serial port."); goto error_free; } // Set the serial communication protocol (38400 8N1). - status = dc_serial_configure (device->base.port, 38400, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); + status = dc_iostream_configure (device->base.iostream, 38400, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); goto error_close; } // Set the timeout for receiving data (1000 ms). - status = dc_serial_set_timeout (device->base.port, 1000); + status = dc_iostream_set_timeout (device->base.iostream, 1000); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the timeout."); goto error_close; } // Clear the DTR line. - status = dc_serial_set_dtr (device->base.port, 0); + status = dc_iostream_set_dtr (device->base.iostream, 0); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to clear the DTR line."); goto error_close; } // Clear the RTS line. - status = dc_serial_set_rts (device->base.port, 0); + status = dc_iostream_set_rts (device->base.iostream, 0); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to clear the RTS line."); goto error_close; } // Make sure everything is in a sane state. - dc_serial_purge (device->base.port, DC_DIRECTION_ALL); + dc_iostream_purge (device->base.iostream, DC_DIRECTION_ALL); // Identify the model number. unsigned char header[PACKETSIZE] = {0}; @@ -176,7 +176,7 @@ mares_puck_device_open (dc_device_t **out, dc_context_t *context, const char *na return DC_STATUS_SUCCESS; error_close: - dc_serial_close (device->base.port); + dc_iostream_close (device->base.iostream); error_free: dc_device_deallocate ((dc_device_t *) device); return status; @@ -191,7 +191,7 @@ mares_puck_device_close (dc_device_t *abstract) dc_status_t rc = DC_STATUS_SUCCESS; // Close the device. - rc = dc_serial_close (device->base.port); + rc = dc_iostream_close (device->base.iostream); if (rc != DC_STATUS_SUCCESS) { dc_status_set_error(&status, rc); } diff --git a/src/oceanic_atom2.c b/src/oceanic_atom2.c index bae6537..77c8e9d 100644 --- a/src/oceanic_atom2.c +++ b/src/oceanic_atom2.c @@ -54,7 +54,7 @@ typedef struct oceanic_atom2_device_t { oceanic_common_device_t base; - dc_serial_t *port; + dc_iostream_t *iostream; unsigned int delay; unsigned int bigpage; unsigned char cache[256]; @@ -471,11 +471,11 @@ oceanic_atom2_packet (oceanic_atom2_device_t *device, const unsigned char comman return DC_STATUS_CANCELLED; if (device->delay) { - dc_serial_sleep (device->port, device->delay); + dc_iostream_sleep (device->iostream, device->delay); } // Send the command to the dive computer. - status = dc_serial_write (device->port, command, csize, NULL); + status = dc_iostream_write (device->iostream, command, csize, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); return status; @@ -489,7 +489,7 @@ oceanic_atom2_packet (oceanic_atom2_device_t *device, const unsigned char comman // Receive the response (ACK/NAK) of the dive computer. unsigned char response = 0; - status = dc_serial_read (device->port, &response, 1, NULL); + status = dc_iostream_read (device->iostream, &response, 1, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); return status; @@ -503,7 +503,7 @@ oceanic_atom2_packet (oceanic_atom2_device_t *device, const unsigned char comman if (asize) { // Receive the answer of the dive computer. - status = dc_serial_read (device->port, answer, asize, NULL); + status = dc_iostream_read (device->iostream, answer, asize, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); return status; @@ -552,8 +552,8 @@ oceanic_atom2_transfer (oceanic_atom2_device_t *device, const unsigned char comm device->delay++; // Delay the next attempt. - dc_serial_sleep (device->port, 100); - dc_serial_purge (device->port, DC_DIRECTION_INPUT); + dc_iostream_sleep (device->iostream, 100); + dc_iostream_purge (device->iostream, DC_DIRECTION_INPUT); } return DC_STATUS_SUCCESS; @@ -593,14 +593,14 @@ oceanic_atom2_device_open (dc_device_t **out, dc_context_t *context, const char oceanic_common_device_init (&device->base); // Set the default values. - device->port = NULL; + device->iostream = NULL; device->delay = 0; device->bigpage = 1; // no big pages device->cached = INVALID; memset(device->cache, 0, sizeof(device->cache)); // Open the device. - status = dc_serial_open (&device->port, context, name); + status = dc_serial_open (&device->iostream, context, name); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the serial port."); goto error_free; @@ -613,28 +613,28 @@ oceanic_atom2_device_open (dc_device_t **out, dc_context_t *context, const char } // Set the serial communication protocol (38400 8N1). - status = dc_serial_configure (device->port, baudrate, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); + status = dc_iostream_configure (device->iostream, baudrate, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); goto error_close; } // Set the timeout for receiving data (1000 ms). - status = dc_serial_set_timeout (device->port, 1000); + status = dc_iostream_set_timeout (device->iostream, 1000); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the timeout."); goto error_close; } // Give the interface 100 ms to settle and draw power up. - dc_serial_sleep (device->port, 100); + dc_iostream_sleep (device->iostream, 100); // Set the DTR/RTS lines. - dc_serial_set_dtr(device->port, 1); - dc_serial_set_rts(device->port, 1); + dc_iostream_set_dtr(device->iostream, 1); + dc_iostream_set_rts(device->iostream, 1); // Make sure everything is in a sane state. - dc_serial_purge (device->port, DC_DIRECTION_ALL); + dc_iostream_purge (device->iostream, DC_DIRECTION_ALL); // Switch the device from surface mode into download mode. Before sending // this command, the device needs to be in PC mode (automatically activated @@ -712,7 +712,7 @@ oceanic_atom2_device_open (dc_device_t **out, dc_context_t *context, const char return DC_STATUS_SUCCESS; error_close: - dc_serial_close (device->port); + dc_iostream_close (device->iostream); error_free: dc_device_deallocate ((dc_device_t *) device); return status; @@ -733,7 +733,7 @@ oceanic_atom2_device_close (dc_device_t *abstract) } // Close the device. - rc = dc_serial_close (device->port); + rc = dc_iostream_close (device->iostream); if (rc != DC_STATUS_SUCCESS) { dc_status_set_error(&status, rc); } diff --git a/src/oceanic_veo250.c b/src/oceanic_veo250.c index b6021dd..ffb1c05 100644 --- a/src/oceanic_veo250.c +++ b/src/oceanic_veo250.c @@ -40,7 +40,7 @@ typedef struct oceanic_veo250_device_t { oceanic_common_device_t base; - dc_serial_t *port; + dc_iostream_t *iostream; unsigned int last; } oceanic_veo250_device_t; @@ -99,10 +99,10 @@ oceanic_veo250_send (oceanic_veo250_device_t *device, const unsigned char comman return DC_STATUS_CANCELLED; // Discard garbage bytes. - dc_serial_purge (device->port, DC_DIRECTION_INPUT); + dc_iostream_purge (device->iostream, DC_DIRECTION_INPUT); // Send the command to the dive computer. - status = dc_serial_write (device->port, command, csize, NULL); + status = dc_iostream_write (device->iostream, command, csize, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); return status; @@ -110,7 +110,7 @@ oceanic_veo250_send (oceanic_veo250_device_t *device, const unsigned char comman // Receive the response (ACK/NAK) of the dive computer. unsigned char response = NAK; - status = dc_serial_read (device->port, &response, 1, NULL); + status = dc_iostream_read (device->iostream, &response, 1, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); return status; @@ -149,11 +149,11 @@ oceanic_veo250_transfer (oceanic_veo250_device_t *device, const unsigned char co return rc; // Delay the next attempt. - dc_serial_sleep (device->port, 100); + dc_iostream_sleep (device->iostream, 100); } // Receive the answer of the dive computer. - status = dc_serial_read (device->port, answer, asize, NULL); + status = dc_iostream_read (device->iostream, answer, asize, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); return status; @@ -177,7 +177,7 @@ oceanic_veo250_init (oceanic_veo250_device_t *device) // Send the command to the dive computer. unsigned char command[2] = {0x55, 0x00}; - status = dc_serial_write (device->port, command, sizeof (command), NULL); + status = dc_iostream_write (device->iostream, command, sizeof (command), NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); return status; @@ -186,7 +186,7 @@ oceanic_veo250_init (oceanic_veo250_device_t *device) // Receive the answer of the dive computer. size_t n = 0; unsigned char answer[13] = {0}; - status = dc_serial_read (device->port, answer, sizeof (answer), &n); + status = dc_iostream_read (device->iostream, answer, sizeof (answer), &n); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); if (n == 0) @@ -215,7 +215,7 @@ oceanic_veo250_quit (oceanic_veo250_device_t *device) // Send the command to the dive computer. unsigned char command[2] = {0x98, 0x00}; - status = dc_serial_write (device->port, command, sizeof (command), NULL); + status = dc_iostream_write (device->iostream, command, sizeof (command), NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); return status; @@ -248,49 +248,49 @@ oceanic_veo250_device_open (dc_device_t **out, dc_context_t *context, const char device->base.multipage = MULTIPAGE; // Set the default values. - device->port = NULL; + device->iostream = NULL; device->last = 0; // Open the device. - status = dc_serial_open (&device->port, context, name); + status = dc_serial_open (&device->iostream, context, name); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the serial port."); goto error_free; } // Set the serial communication protocol (9600 8N1). - status = dc_serial_configure (device->port, 9600, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); + status = dc_iostream_configure (device->iostream, 9600, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); goto error_close; } // Set the timeout for receiving data (3000 ms). - status = dc_serial_set_timeout (device->port, 3000); + status = dc_iostream_set_timeout (device->iostream, 3000); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the timeout."); goto error_close; } // Set the DTR line. - status = dc_serial_set_dtr (device->port, 1); + status = dc_iostream_set_dtr (device->iostream, 1); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the DTR line."); goto error_close; } // Set the RTS line. - status = dc_serial_set_rts (device->port, 1); + status = dc_iostream_set_rts (device->iostream, 1); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the RTS line."); goto error_close; } // Give the interface 100 ms to settle and draw power up. - dc_serial_sleep (device->port, 100); + dc_iostream_sleep (device->iostream, 100); // Make sure everything is in a sane state. - dc_serial_purge (device->port, DC_DIRECTION_ALL); + dc_iostream_purge (device->iostream, DC_DIRECTION_ALL); // Initialize the data cable (PPS mode). status = oceanic_veo250_init (device); @@ -299,7 +299,7 @@ oceanic_veo250_device_open (dc_device_t **out, dc_context_t *context, const char } // Delay the sending of the version command. - dc_serial_sleep (device->port, 100); + dc_iostream_sleep (device->iostream, 100); // Switch the device from surface mode into download mode. Before sending // this command, the device needs to be in PC mode (manually activated by @@ -322,7 +322,7 @@ oceanic_veo250_device_open (dc_device_t **out, dc_context_t *context, const char return DC_STATUS_SUCCESS; error_close: - dc_serial_close (device->port); + dc_iostream_close (device->iostream); error_free: dc_device_deallocate ((dc_device_t *) device); return status; @@ -343,7 +343,7 @@ oceanic_veo250_device_close (dc_device_t *abstract) } // Close the device. - rc = dc_serial_close (device->port); + rc = dc_iostream_close (device->iostream); if (rc != DC_STATUS_SUCCESS) { dc_status_set_error(&status, rc); } diff --git a/src/oceanic_vtpro.c b/src/oceanic_vtpro.c index cc09892..e1ba31c 100644 --- a/src/oceanic_vtpro.c +++ b/src/oceanic_vtpro.c @@ -50,7 +50,7 @@ typedef enum oceanic_vtpro_protocol_t { typedef struct oceanic_vtpro_device_t { oceanic_common_device_t base; - dc_serial_t *port; + dc_iostream_t *iostream; unsigned int model; oceanic_vtpro_protocol_t protocol; } oceanic_vtpro_device_t; @@ -140,7 +140,7 @@ oceanic_vtpro_send (oceanic_vtpro_device_t *device, const unsigned char command[ return DC_STATUS_CANCELLED; // Send the command to the dive computer. - status = dc_serial_write (device->port, command, csize, NULL); + status = dc_iostream_write (device->iostream, command, csize, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); return status; @@ -148,7 +148,7 @@ oceanic_vtpro_send (oceanic_vtpro_device_t *device, const unsigned char command[ // Receive the response (ACK/NAK) of the dive computer. unsigned char response = NAK; - status = dc_serial_read (device->port, &response, 1, NULL); + status = dc_iostream_read (device->iostream, &response, 1, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); return status; @@ -189,7 +189,7 @@ oceanic_vtpro_transfer (oceanic_vtpro_device_t *device, const unsigned char comm if (asize) { // Receive the answer of the dive computer. - status = dc_serial_read (device->port, answer, asize, NULL); + status = dc_iostream_read (device->iostream, answer, asize, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); return status; @@ -210,7 +210,7 @@ oceanic_vtpro_init (oceanic_vtpro_device_t *device) unsigned char command[2][2] = { {0xAA, 0x00}, {0x20, 0x00}}; - status = dc_serial_write (device->port, command[device->protocol], sizeof (command[device->protocol]), NULL); + status = dc_iostream_write (device->iostream, command[device->protocol], sizeof (command[device->protocol]), NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); return status; @@ -218,7 +218,7 @@ oceanic_vtpro_init (oceanic_vtpro_device_t *device) // Receive the answer of the dive computer. unsigned char answer[13] = {0}; - status = dc_serial_read (device->port, answer, sizeof (answer), NULL); + status = dc_iostream_read (device->iostream, answer, sizeof (answer), NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); return status; @@ -269,9 +269,9 @@ oceanic_vtpro_calibrate (oceanic_vtpro_device_t *device) // device needs approximately 6 seconds to respond. unsigned char answer[2] = {0}; unsigned char command[2] = {0x18, 0x00}; - dc_serial_set_timeout (device->port, 9000); + dc_iostream_set_timeout (device->iostream, 9000); dc_status_t rc = oceanic_vtpro_transfer (device, command, sizeof (command), answer, sizeof (answer)); - dc_serial_set_timeout (device->port, 3000); + dc_iostream_set_timeout (device->iostream, 3000); if (rc != DC_STATUS_SUCCESS) return rc; @@ -337,7 +337,7 @@ oceanic_aeris500ai_device_logbook (dc_device_t *abstract, dc_event_progress_t *p for (unsigned int i = 0; i < last + 1; ++i) { // Receive the answer of the dive computer. unsigned char answer[PAGESIZE / 2 + 1] = {0}; - rc = dc_serial_read (device->port, answer, sizeof(answer), NULL); + rc = dc_iostream_read (device->iostream, answer, sizeof(answer), NULL); if (rc != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); return rc; @@ -407,7 +407,7 @@ oceanic_vtpro_device_open (dc_device_t **out, dc_context_t *context, const char device->base.multipage = MULTIPAGE; // Set the default values. - device->port = NULL; + device->iostream = NULL; device->model = model; if (model == AERIS500AI) { device->protocol = INTR; @@ -416,45 +416,45 @@ oceanic_vtpro_device_open (dc_device_t **out, dc_context_t *context, const char } // Open the device. - status = dc_serial_open (&device->port, context, name); + status = dc_serial_open (&device->iostream, context, name); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the serial port."); goto error_free; } // Set the serial communication protocol (9600 8N1). - status = dc_serial_configure (device->port, 9600, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); + status = dc_iostream_configure (device->iostream, 9600, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); goto error_close; } // Set the timeout for receiving data (3000 ms). - status = dc_serial_set_timeout (device->port, 3000); + status = dc_iostream_set_timeout (device->iostream, 3000); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the timeout."); goto error_close; } // Set the DTR line. - status = dc_serial_set_dtr (device->port, 1); + status = dc_iostream_set_dtr (device->iostream, 1); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the DTR line."); goto error_close; } // Set the RTS line. - status = dc_serial_set_rts (device->port, 1); + status = dc_iostream_set_rts (device->iostream, 1); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the RTS line."); goto error_close; } // Give the interface 100 ms to settle and draw power up. - dc_serial_sleep (device->port, device->protocol == MOD ? 100 : 1000); + dc_iostream_sleep (device->iostream, device->protocol == MOD ? 100 : 1000); // Make sure everything is in a sane state. - dc_serial_purge (device->port, DC_DIRECTION_ALL); + dc_iostream_purge (device->iostream, DC_DIRECTION_ALL); // Initialize the data cable (MOD mode). status = oceanic_vtpro_init (device); @@ -495,7 +495,7 @@ oceanic_vtpro_device_open (dc_device_t **out, dc_context_t *context, const char return DC_STATUS_SUCCESS; error_close: - dc_serial_close (device->port); + dc_iostream_close (device->iostream); error_free: dc_device_deallocate ((dc_device_t *) device); return status; @@ -516,7 +516,7 @@ oceanic_vtpro_device_close (dc_device_t *abstract) } // Close the device. - rc = dc_serial_close (device->port); + rc = dc_iostream_close (device->iostream); if (rc != DC_STATUS_SUCCESS) { dc_status_set_error(&status, rc); } diff --git a/src/reefnet_sensus.c b/src/reefnet_sensus.c index 37c343a..0fc6e52 100644 --- a/src/reefnet_sensus.c +++ b/src/reefnet_sensus.c @@ -36,7 +36,7 @@ typedef struct reefnet_sensus_device_t { dc_device_t base; - dc_serial_t *port; + dc_iostream_t *iostream; unsigned char handshake[SZ_HANDSHAKE]; unsigned int waiting; unsigned int timestamp; @@ -72,7 +72,7 @@ reefnet_sensus_cancel (reefnet_sensus_device_t *device) // Send the command to the device. unsigned char command = 0x00; - status = dc_serial_write (device->port, &command, 1, NULL); + status = dc_iostream_write (device->iostream, &command, 1, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); return status; @@ -102,7 +102,7 @@ reefnet_sensus_device_open (dc_device_t **out, dc_context_t *context, const char } // Set the default values. - device->port = NULL; + device->iostream = NULL; device->waiting = 0; device->timestamp = 0; device->systime = (dc_ticks_t) -1; @@ -110,35 +110,35 @@ reefnet_sensus_device_open (dc_device_t **out, dc_context_t *context, const char memset (device->handshake, 0, sizeof (device->handshake)); // Open the device. - status = dc_serial_open (&device->port, context, name); + status = dc_serial_open (&device->iostream, context, name); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the serial port."); goto error_free; } // Set the serial communication protocol (19200 8N1). - status = dc_serial_configure (device->port, 19200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); + status = dc_iostream_configure (device->iostream, 19200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); goto error_close; } // Set the timeout for receiving data (3000 ms). - status = dc_serial_set_timeout (device->port, 3000); + status = dc_iostream_set_timeout (device->iostream, 3000); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the timeout."); goto error_close; } // Make sure everything is in a sane state. - dc_serial_purge (device->port, DC_DIRECTION_ALL); + dc_iostream_purge (device->iostream, DC_DIRECTION_ALL); *out = (dc_device_t*) device; return DC_STATUS_SUCCESS; error_close: - dc_serial_close (device->port); + dc_iostream_close (device->iostream); error_free: dc_device_deallocate ((dc_device_t *) device); return status; @@ -162,7 +162,7 @@ reefnet_sensus_device_close (dc_device_t *abstract) } // Close the device. - rc = dc_serial_close (device->port); + rc = dc_iostream_close (device->iostream); if (rc != DC_STATUS_SUCCESS) { dc_status_set_error(&status, rc); } @@ -215,7 +215,7 @@ reefnet_sensus_handshake (reefnet_sensus_device_t *device) // Send the command to the device. unsigned char command = 0x0A; - status = dc_serial_write (device->port, &command, 1, NULL); + status = dc_iostream_write (device->iostream, &command, 1, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); return status; @@ -223,7 +223,7 @@ reefnet_sensus_handshake (reefnet_sensus_device_t *device) // Receive the answer from the device. unsigned char handshake[SZ_HANDSHAKE + 2] = {0}; - status = dc_serial_read (device->port, handshake, sizeof (handshake), NULL); + status = dc_iostream_read (device->iostream, handshake, sizeof (handshake), NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the handshake."); return status; @@ -267,7 +267,7 @@ reefnet_sensus_handshake (reefnet_sensus_device_t *device) // Wait at least 10 ms to ensures the data line is // clear before transmission from the host begins. - dc_serial_sleep (device->port, 10); + dc_iostream_sleep (device->iostream, 10); return DC_STATUS_SUCCESS; } @@ -298,7 +298,7 @@ reefnet_sensus_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) // Send the command to the device. unsigned char command = 0x40; - status = dc_serial_write (device->port, &command, 1, NULL); + status = dc_iostream_write (device->iostream, &command, 1, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); return status; @@ -315,7 +315,7 @@ reefnet_sensus_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) if (len > 128) len = 128; - status = dc_serial_read (device->port, answer + nbytes, len, NULL); + status = dc_iostream_read (device->iostream, answer + nbytes, len, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); return status; diff --git a/src/reefnet_sensuspro.c b/src/reefnet_sensuspro.c index 4df3c07..e50cb44 100644 --- a/src/reefnet_sensuspro.c +++ b/src/reefnet_sensuspro.c @@ -36,7 +36,7 @@ typedef struct reefnet_sensuspro_device_t { dc_device_t base; - dc_serial_t *port; + dc_iostream_t *iostream; unsigned char handshake[SZ_HANDSHAKE]; unsigned int timestamp; unsigned int devtime; @@ -80,42 +80,42 @@ reefnet_sensuspro_device_open (dc_device_t **out, dc_context_t *context, const c } // Set the default values. - device->port = NULL; + device->iostream = NULL; device->timestamp = 0; device->systime = (dc_ticks_t) -1; device->devtime = 0; memset (device->handshake, 0, sizeof (device->handshake)); // Open the device. - status = dc_serial_open (&device->port, context, name); + status = dc_serial_open (&device->iostream, context, name); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the serial port."); goto error_free; } // Set the serial communication protocol (19200 8N1). - status = dc_serial_configure (device->port, 19200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); + status = dc_iostream_configure (device->iostream, 19200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); goto error_close; } // Set the timeout for receiving data (3000ms). - status = dc_serial_set_timeout (device->port, 3000); + status = dc_iostream_set_timeout (device->iostream, 3000); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the timeout."); goto error_close; } // Make sure everything is in a sane state. - dc_serial_purge (device->port, DC_DIRECTION_ALL); + dc_iostream_purge (device->iostream, DC_DIRECTION_ALL); *out = (dc_device_t*) device; return DC_STATUS_SUCCESS; error_close: - dc_serial_close (device->port); + dc_iostream_close (device->iostream); error_free: dc_device_deallocate ((dc_device_t *) device); return status; @@ -130,7 +130,7 @@ reefnet_sensuspro_device_close (dc_device_t *abstract) dc_status_t rc = DC_STATUS_SUCCESS; // Close the device. - rc = dc_serial_close (device->port); + rc = dc_iostream_close (device->iostream); if (rc != DC_STATUS_SUCCESS) { dc_status_set_error(&status, rc); } @@ -182,18 +182,18 @@ reefnet_sensuspro_handshake (reefnet_sensuspro_device_t *device) dc_device_t *abstract = (dc_device_t *) device; // Assert a break condition. - dc_serial_set_break (device->port, 1); + dc_iostream_set_break (device->iostream, 1); // Receive the handshake from the dive computer. unsigned char handshake[SZ_HANDSHAKE + 2] = {0}; - status = dc_serial_read (device->port, handshake, sizeof (handshake), NULL); + status = dc_iostream_read (device->iostream, handshake, sizeof (handshake), NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the handshake."); return status; } // Clear the break condition again. - dc_serial_set_break (device->port, 0); + dc_iostream_set_break (device->iostream, 0); // Verify the checksum of the handshake packet. unsigned short crc = array_uint16_le (handshake + SZ_HANDSHAKE); @@ -229,7 +229,7 @@ reefnet_sensuspro_handshake (reefnet_sensuspro_device_t *device) vendor.size = sizeof (device->handshake); device_event_emit (abstract, DC_EVENT_VENDOR, &vendor); - dc_serial_sleep (device->port, 10); + dc_iostream_sleep (device->iostream, 10); return DC_STATUS_SUCCESS; } @@ -247,7 +247,7 @@ reefnet_sensuspro_send (reefnet_sensuspro_device_t *device, unsigned char comman return rc; // Send the instruction code to the device. - status = dc_serial_write (device->port, &command, 1, NULL); + status = dc_iostream_write (device->iostream, &command, 1, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); return status; @@ -287,7 +287,7 @@ reefnet_sensuspro_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) if (len > 256) len = 256; - status = dc_serial_read (device->port, answer + nbytes, len, NULL); + status = dc_iostream_read (device->iostream, answer + nbytes, len, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); return status; @@ -352,9 +352,9 @@ reefnet_sensuspro_device_write_interval (dc_device_t *abstract, unsigned char in if (rc != DC_STATUS_SUCCESS) return rc; - dc_serial_sleep (device->port, 10); + dc_iostream_sleep (device->iostream, 10); - status = dc_serial_write (device->port, &interval, 1, NULL); + status = dc_iostream_write (device->iostream, &interval, 1, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the data packet."); return status; diff --git a/src/reefnet_sensusultra.c b/src/reefnet_sensusultra.c index fba7511..fd3d399 100644 --- a/src/reefnet_sensusultra.c +++ b/src/reefnet_sensusultra.c @@ -45,7 +45,7 @@ typedef struct reefnet_sensusultra_device_t { dc_device_t base; - dc_serial_t *port; + dc_iostream_t *iostream; unsigned char handshake[SZ_HANDSHAKE]; unsigned int timestamp; unsigned int devtime; @@ -87,42 +87,42 @@ reefnet_sensusultra_device_open (dc_device_t **out, dc_context_t *context, const } // Set the default values. - device->port = NULL; + device->iostream = NULL; device->timestamp = 0; device->systime = (dc_ticks_t) -1; device->devtime = 0; memset (device->handshake, 0, sizeof (device->handshake)); // Open the device. - status = dc_serial_open (&device->port, context, name); + status = dc_serial_open (&device->iostream, context, name); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the serial port."); goto error_free; } // Set the serial communication protocol (115200 8N1). - status = dc_serial_configure (device->port, 115200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); + status = dc_iostream_configure (device->iostream, 115200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); goto error_close; } // Set the timeout for receiving data (3000ms). - status = dc_serial_set_timeout (device->port, 3000); + status = dc_iostream_set_timeout (device->iostream, 3000); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the timeout."); goto error_close; } // Make sure everything is in a sane state. - dc_serial_purge (device->port, DC_DIRECTION_ALL); + dc_iostream_purge (device->iostream, DC_DIRECTION_ALL); *out = (dc_device_t*) device; return DC_STATUS_SUCCESS; error_close: - dc_serial_close (device->port); + dc_iostream_close (device->iostream); error_free: dc_device_deallocate ((dc_device_t *) device); return status; @@ -137,7 +137,7 @@ reefnet_sensusultra_device_close (dc_device_t *abstract) dc_status_t rc = DC_STATUS_SUCCESS; // Close the device. - rc = dc_serial_close (device->port); + rc = dc_iostream_close (device->iostream); if (rc != DC_STATUS_SUCCESS) { dc_status_set_error(&status, rc); } @@ -190,7 +190,7 @@ reefnet_sensusultra_send_uchar (reefnet_sensusultra_device_t *device, unsigned c // Wait for the prompt byte. unsigned char prompt = 0; - status = dc_serial_read (device->port, &prompt, 1, NULL); + status = dc_iostream_read (device->iostream, &prompt, 1, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the prompt byte"); return status; @@ -203,7 +203,7 @@ reefnet_sensusultra_send_uchar (reefnet_sensusultra_device_t *device, unsigned c } // Send the value to the device. - status = dc_serial_write (device->port, &value, 1, NULL); + status = dc_iostream_write (device->iostream, &value, 1, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the value."); return status; @@ -244,7 +244,7 @@ reefnet_sensusultra_packet (reefnet_sensusultra_device_t *device, unsigned char return DC_STATUS_CANCELLED; // Receive the data packet. - status = dc_serial_read (device->port, data, size, NULL); + status = dc_iostream_read (device->iostream, data, size, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the packet."); return status; @@ -346,7 +346,7 @@ static dc_status_t reefnet_sensusultra_send (reefnet_sensusultra_device_t *device, unsigned short command) { // Flush the input and output buffers. - dc_serial_purge (device->port, DC_DIRECTION_ALL); + dc_iostream_purge (device->iostream, DC_DIRECTION_ALL); // Wake-up the device and send the instruction code. unsigned int nretries = 0; @@ -366,8 +366,8 @@ reefnet_sensusultra_send (reefnet_sensusultra_device_t *device, unsigned short c // not accidentally buffered by the host and (mis)interpreted as part // of the next packet. - dc_serial_sleep (device->port, 250); - dc_serial_purge (device->port, DC_DIRECTION_ALL); + dc_iostream_sleep (device->iostream, 250); + dc_iostream_purge (device->iostream, DC_DIRECTION_ALL); } return DC_STATUS_SUCCESS; diff --git a/src/scubapro_g2.c b/src/scubapro_g2.c index a01619c..dcef627 100644 --- a/src/scubapro_g2.c +++ b/src/scubapro_g2.c @@ -383,7 +383,7 @@ scubapro_g2_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) progress.current += 4; device_event_emit (&device->base, DC_EVENT_PROGRESS, &progress); - if (length == 0) + if (length == 0) return DC_STATUS_SUCCESS; // Allocate the required amount of memory. diff --git a/src/serial.h b/src/serial.h index 10da402..d6620e0 100644 --- a/src/serial.h +++ b/src/serial.h @@ -24,67 +24,12 @@ #include #include +#include #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ -/** - * Opaque object representing a serial connection. - */ -typedef struct dc_serial_t dc_serial_t; - -#ifndef __SERIAL_TYPES__ -#define __SERIAL_TYPES__ -/** - * The parity checking scheme. - */ -typedef enum dc_parity_t { - DC_PARITY_NONE, /**< No parity */ - DC_PARITY_ODD, /**< Odd parity */ - DC_PARITY_EVEN, /**< Even parity */ - DC_PARITY_MARK, /**< Mark parity (always 1) */ - DC_PARITY_SPACE /**< Space parity (alwasy 0) */ -} dc_parity_t; - -/** - * The number of stop bits. - */ -typedef enum dc_stopbits_t { - DC_STOPBITS_ONE, /**< 1 stop bit */ - DC_STOPBITS_ONEPOINTFIVE, /**< 1.5 stop bits*/ - DC_STOPBITS_TWO /**< 2 stop bits */ -} dc_stopbits_t; - -/** - * The flow control. - */ -typedef enum dc_flowcontrol_t { - DC_FLOWCONTROL_NONE, /**< No flow control */ - DC_FLOWCONTROL_HARDWARE, /**< Hardware (RTS/CTS) flow control */ - DC_FLOWCONTROL_SOFTWARE /**< Software (XON/XOFF) flow control */ -} dc_flowcontrol_t; - -/** - * The direction of the data transmission. - */ -typedef enum dc_direction_t { - DC_DIRECTION_INPUT = 0x01, /**< Input direction */ - DC_DIRECTION_OUTPUT = 0x02, /**< Output direction */ - DC_DIRECTION_ALL = DC_DIRECTION_INPUT | DC_DIRECTION_OUTPUT /**< All directions */ -} dc_direction_t; - -/** - * The serial line signals. - */ -typedef enum dc_line_t { - DC_LINE_DCD = 0x01, /**< Data carrier detect */ - DC_LINE_CTS = 0x02, /**< Clear to send */ - DC_LINE_DSR = 0x04, /**< Data set ready */ - DC_LINE_RNG = 0x08, /**< Ring indicator */ -} dc_line_t; -#endif /* __SERIAL_TYPES__ */ - /** * Serial enumeration callback. * @@ -107,216 +52,14 @@ dc_serial_enumerate (dc_serial_callback_t callback, void *userdata); /** * Open a serial connection. * - * @param[out] serial A location to store the serial connection. + * @param[out] iostream A location to store the serial connection. * @param[in] context A valid context object. * @param[in] name The name of the device node. * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code * on failure. */ dc_status_t -dc_serial_open (dc_serial_t **serial, dc_context_t *context, const char *name); - -/** - * Close the serial connection and free all resources. - * - * @param[in] serial A valid serial connection. - * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code - * on failure. - */ -dc_status_t -dc_serial_close (dc_serial_t *serial); - -/** - * Configure the serial line settings of the connection. - * - * @param[in] serial A valid serial connection. - * @param[in] baudrate The baud rate setting. - * @param[in] databits The number of data bits. - * @param[in] parity The parity setting. - * @param[in] stopbits The number of stop bits. - * @param[in] flowcontrol The flow control setting. - * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code - * on failure. - */ -dc_status_t -dc_serial_configure (dc_serial_t *serial, unsigned int baudrate, unsigned int databits, dc_parity_t parity, dc_stopbits_t stopbits, dc_flowcontrol_t flowcontrol); - -/** - * Set the read timeout. - * - * There are three distinct modes available: - * - * 1. Blocking (timeout < 0): - * - * The read operation is blocked until all the requested bytes have - * been received. If the requested number of bytes does not arrive, - * the operation will block forever. - * - * 2. Non-blocking (timeout == 0): - * - * The read operation returns immediately with the bytes that have - * already been received, even if no bytes have been received. - * - * 3. Timeout (timeout > 0): - * - * The read operation is blocked until all the requested bytes have - * been received. If the requested number of bytes does not arrive - * within the specified amount of time, the operation will return - * with the bytes that have already been received. - * - * @param[in] serial A valid serial connection. - * @param[in] timeout The timeout in milliseconds. - * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code - * on failure. - */ -dc_status_t -dc_serial_set_timeout (dc_serial_t *serial, int timeout); - -/** - * Set the state of the half duplex emulation. - * - * @param[in] serial A valid serial connection. - * @param[in] value The half duplex state. - * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code - * on failure. - */ -dc_status_t -dc_serial_set_halfduplex (dc_serial_t *serial, unsigned int value); - -/** - * Set the receive latency. - * - * The effect of this setting is highly platform and driver specific. On - * Windows it does nothing at all, on Linux it controls the low latency - * flag (e.g. only zero vs non-zero latency), and on Mac OS X it sets - * the receive latency as requested. - * - * @param[in] serial A valid serial connection. - * @param[in] value The latency in milliseconds. - * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code - * on failure. - */ -dc_status_t -dc_serial_set_latency (dc_serial_t *serial, unsigned int value); - -/** - * Read data from the serial connection. - * - * @param[in] serial A valid serial connection. - * @param[out] data The memory buffer to read the data into. - * @param[in] size The number of bytes to read. - * @param[out] actual An (optional) location to store the actual - * number of bytes transferred. - * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code - * on failure. - */ -dc_status_t -dc_serial_read (dc_serial_t *serial, void *data, size_t size, size_t *actual); - -/** - * Write data to the serial connection. - * - * @param[in] serial A valid serial connection. - * @param[in] data The memory buffer to write the data from. - * @param[in] size The number of bytes to write. - * @param[out] actual An (optional) location to store the actual - * number of bytes transferred. - * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code - * on failure. - */ -dc_status_t -dc_serial_write (dc_serial_t *serial, const void *data, size_t size, size_t *actual); - -/** - * Flush the internal output buffer and wait until the data has been - * transmitted. - * - * @param[in] serial A valid serial connection. - * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code - * on failure. - */ -dc_status_t -dc_serial_flush (dc_serial_t *serial); - -/** - * Discards all data from the internal buffers. - * - * @param[in] serial A valid serial connection. - * @param[in] direction The direction of the buffer(s). - * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code - * on failure. - */ -dc_status_t -dc_serial_purge (dc_serial_t *serial, dc_direction_t direction); - -/** - * Set the state of the break condition. - * - * @param[in] serial A valid serial connection. - * @param[in] value The break condition state. - * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code - * on failure. - */ -dc_status_t -dc_serial_set_break (dc_serial_t *serial, unsigned int value); - -/** - * Set the state of the DTR line. - * - * @param[in] serial A valid serial connection. - * @param[in] value The DTR line state. - * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code - * on failure. - */ -dc_status_t -dc_serial_set_dtr (dc_serial_t *serial, unsigned int value); - -/** - * Set the state of the RTS line. - * - * @param[in] serial A valid serial connection. - * @param[in] value The RTS line state. - * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code - * on failure. - */ -dc_status_t -dc_serial_set_rts (dc_serial_t *serial, unsigned int value); - -/** - * Query the number of available bytes in the input buffer. - * - * @param[in] serial A valid serial connection. - * @param[out] value A location to store the number of bytes in the - * input buffer. - * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code - * on failure. - */ -dc_status_t -dc_serial_get_available (dc_serial_t *serial, size_t *value); - -/** - * Query the state of the line signals. - * - * @param[in] serial A valid serial connection. - * @param[out] value A location to store the bitmap with the state of - * the line signals. - * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code - * on failure. - */ -dc_status_t -dc_serial_get_lines (dc_serial_t *serial, unsigned int *value); - -/** - * Suspend execution of the current thread for the specified amount of - * time. - * - * @param[in] serial A valid serial connection. - * @param[in] milliseconds The number of milliseconds to sleep. - * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code - * on failure. - */ -dc_status_t -dc_serial_sleep (dc_serial_t *serial, unsigned int milliseconds); +dc_serial_open (dc_iostream_t **iostream, dc_context_t *context, const char *name); #ifdef __cplusplus } diff --git a/src/serial_posix.c b/src/serial_posix.c index 7f07206..1698df8 100644 --- a/src/serial_posix.c +++ b/src/serial_posix.c @@ -54,12 +54,29 @@ #endif #include "serial.h" + #include "common-private.h" #include "context-private.h" +#include "iostream-private.h" -struct dc_serial_t { - /* Library context. */ - dc_context_t *context; +static dc_status_t dc_serial_set_timeout (dc_iostream_t *iostream, int timeout); +static dc_status_t dc_serial_set_latency (dc_iostream_t *iostream, unsigned int value); +static dc_status_t dc_serial_set_halfduplex (dc_iostream_t *iostream, unsigned int value); +static dc_status_t dc_serial_set_break (dc_iostream_t *iostream, unsigned int value); +static dc_status_t dc_serial_set_dtr (dc_iostream_t *iostream, unsigned int value); +static dc_status_t dc_serial_set_rts (dc_iostream_t *iostream, unsigned int value); +static dc_status_t dc_serial_get_lines (dc_iostream_t *iostream, unsigned int *value); +static dc_status_t dc_serial_get_available (dc_iostream_t *iostream, size_t *value); +static dc_status_t dc_serial_configure (dc_iostream_t *iostream, unsigned int baudrate, unsigned int databits, dc_parity_t parity, dc_stopbits_t stopbits, dc_flowcontrol_t flowcontrol); +static dc_status_t dc_serial_read (dc_iostream_t *iostream, void *data, size_t size, size_t *actual); +static dc_status_t dc_serial_write (dc_iostream_t *iostream, const void *data, size_t size, size_t *actual); +static dc_status_t dc_serial_flush (dc_iostream_t *iostream); +static dc_status_t dc_serial_purge (dc_iostream_t *iostream, dc_direction_t direction); +static dc_status_t dc_serial_sleep (dc_iostream_t *iostream, unsigned int milliseconds); +static dc_status_t dc_serial_close (dc_iostream_t *iostream); + +typedef struct dc_serial_t { + dc_iostream_t base; /* * The file descriptor corresponding to the serial port. */ @@ -75,6 +92,25 @@ struct dc_serial_t { int halfduplex; unsigned int baudrate; unsigned int nbits; +} dc_serial_t; + +static const dc_iostream_vtable_t dc_serial_vtable = { + sizeof(dc_serial_t), + dc_serial_set_timeout, /* set_timeout */ + dc_serial_set_latency, /* set_latency */ + dc_serial_set_halfduplex, /* set_halfduplex */ + dc_serial_set_break, /* set_break */ + dc_serial_set_dtr, /* set_dtr */ + dc_serial_set_rts, /* set_rts */ + dc_serial_get_lines, /* get_lines */ + dc_serial_get_available, /* get_received */ + dc_serial_configure, /* configure */ + dc_serial_read, /* read */ + dc_serial_write, /* write */ + dc_serial_flush, /* flush */ + dc_serial_purge, /* purge */ + dc_serial_sleep, /* sleep */ + dc_serial_close, /* close */ }; static dc_status_t @@ -140,25 +176,27 @@ dc_serial_enumerate (dc_serial_callback_t callback, void *userdata) } dc_status_t -dc_serial_open (dc_serial_t **out, dc_context_t *context, const char *name) +dc_serial_open (dc_iostream_t **out, dc_context_t *context, const char *name) { dc_status_t status = DC_STATUS_SUCCESS; + dc_serial_t *device = NULL; - if (out == NULL) + if (out == NULL || name == NULL) return DC_STATUS_INVALIDARGS; - INFO (context, "Open: name=%s", name ? name : ""); + // Are we using custom IO? + if (_dc_context_custom_io(context)) + return dc_custom_io_serial_open(out, context, name); + + INFO (context, "Open: name=%s", name); // Allocate memory. - dc_serial_t *device = (dc_serial_t *) malloc (sizeof (dc_serial_t)); + device = (dc_serial_t *) dc_iostream_allocate (context, &dc_serial_vtable); if (device == NULL) { SYSERROR (context, ENOMEM); return DC_STATUS_NOMEMORY; } - // Library context. - device->context = context; - // Default to blocking reads. device->timeout = -1; @@ -167,8 +205,6 @@ dc_serial_open (dc_serial_t **out, dc_context_t *context, const char *name) device->baudrate = 0; device->nbits = 0; - RETURN_IF_CUSTOM_SERIAL(context, *out = device, open, context, name); - // Open the device in non-blocking mode, to return immediately // without waiting for the modem connection to complete. device->fd = open (name, O_RDWR | O_NOCTTY | O_NONBLOCK); @@ -200,31 +236,27 @@ dc_serial_open (dc_serial_t **out, dc_context_t *context, const char *name) goto error_close; } - *out = device; + *out = (dc_iostream_t *) device; return DC_STATUS_SUCCESS; error_close: close (device->fd); error_free: - free (device); + dc_iostream_deallocate ((dc_iostream_t *) device); return status; } -dc_status_t -dc_serial_close (dc_serial_t *device) +static dc_status_t +dc_serial_close (dc_iostream_t *abstract) { dc_status_t status = DC_STATUS_SUCCESS; - - if (device == NULL) - return DC_STATUS_SUCCESS; - - RETURN_IF_CUSTOM_SERIAL(device->context, free(device), close); + dc_serial_t *device = (dc_serial_t *) abstract; // Restore the initial terminal attributes. if (tcsetattr (device->fd, TCSANOW, &device->tty) != 0) { int errcode = errno; - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); dc_status_set_error(&status, syserror (errcode)); } @@ -236,33 +268,24 @@ dc_serial_close (dc_serial_t *device) // Close the device. if (close (device->fd) != 0) { int errcode = errno; - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); dc_status_set_error(&status, syserror (errcode)); } - // Free memory. - free (device); - return status; } -dc_status_t -dc_serial_configure (dc_serial_t *device, unsigned int baudrate, unsigned int databits, dc_parity_t parity, dc_stopbits_t stopbits, dc_flowcontrol_t flowcontrol) +static dc_status_t +dc_serial_configure (dc_iostream_t *abstract, unsigned int baudrate, unsigned int databits, dc_parity_t parity, dc_stopbits_t stopbits, dc_flowcontrol_t flowcontrol) { - if (device == NULL) - return DC_STATUS_INVALIDARGS; - - INFO (device->context, "Configure: baudrate=%i, databits=%i, parity=%i, stopbits=%i, flowcontrol=%i", - baudrate, databits, parity, stopbits, flowcontrol); - - RETURN_IF_CUSTOM_SERIAL(device->context, , configure, baudrate, databits, parity, stopbits, flowcontrol); + dc_serial_t *device = (dc_serial_t *) abstract; // Retrieve the current settings. struct termios tty; memset (&tty, 0, sizeof (tty)); if (tcgetattr (device->fd, &tty) != 0) { int errcode = errno; - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); return syserror (errcode); } @@ -359,7 +382,7 @@ dc_serial_configure (dc_serial_t *device, unsigned int baudrate, unsigned int da if (cfsetispeed (&tty, baud) != 0 || cfsetospeed (&tty, baud) != 0) { int errcode = errno; - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); return syserror (errcode); } @@ -455,11 +478,9 @@ dc_serial_configure (dc_serial_t *device, unsigned int baudrate, unsigned int da // Apply the new settings. if (tcsetattr (device->fd, TCSANOW, &tty) != 0 && NOPTY) { -#if 0 // who cares int errcode = errno; - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); return syserror (errcode); -#endif } // Configure a custom baudrate if necessary. @@ -469,7 +490,7 @@ dc_serial_configure (dc_serial_t *device, unsigned int baudrate, unsigned int da struct serial_struct ss; if (ioctl (device->fd, TIOCGSERIAL, &ss) != 0 && NOPTY) { int errcode = errno; - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); return syserror (errcode); } @@ -481,14 +502,14 @@ dc_serial_configure (dc_serial_t *device, unsigned int baudrate, unsigned int da // Apply the new settings. if (ioctl (device->fd, TIOCSSERIAL, &ss) != 0 && NOPTY) { int errcode = errno; - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); return syserror (errcode); } #elif defined(IOSSIOSPEED) speed_t speed = baudrate; if (ioctl (device->fd, IOSSIOSPEED, &speed) != 0 && NOPTY) { int errcode = errno; - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); return syserror (errcode); } #else @@ -503,46 +524,37 @@ dc_serial_configure (dc_serial_t *device, unsigned int baudrate, unsigned int da return DC_STATUS_SUCCESS; } -dc_status_t -dc_serial_set_timeout (dc_serial_t *device, int timeout) +static dc_status_t +dc_serial_set_timeout (dc_iostream_t *abstract, int timeout) { - if (device == NULL) - return DC_STATUS_INVALIDARGS; - - INFO (device->context, "Timeout: value=%i", timeout); - - RETURN_IF_CUSTOM_SERIAL(device->context, , set_timeout, timeout); + dc_serial_t *device = (dc_serial_t *) abstract; device->timeout = timeout; return DC_STATUS_SUCCESS; } -dc_status_t -dc_serial_set_halfduplex (dc_serial_t *device, unsigned int value) +static dc_status_t +dc_serial_set_halfduplex (dc_iostream_t *abstract, unsigned int value) { - if (device == NULL) - return DC_STATUS_INVALIDARGS; - - RETURN_IF_CUSTOM_SERIAL(device->context, , set_halfduplex, value); + dc_serial_t *device = (dc_serial_t *) abstract; device->halfduplex = value; return DC_STATUS_SUCCESS; } -dc_status_t -dc_serial_set_latency (dc_serial_t *device, unsigned int milliseconds) +static dc_status_t +dc_serial_set_latency (dc_iostream_t *abstract, unsigned int milliseconds) { - if (device == NULL) - return DC_STATUS_INVALIDARGS; + dc_serial_t *device = (dc_serial_t *) abstract; #if defined(TIOCGSERIAL) && defined(TIOCSSERIAL) && !defined(__ANDROID__) // Get the current settings. struct serial_struct ss; if (ioctl (device->fd, TIOCGSERIAL, &ss) != 0 && NOPTY) { int errcode = errno; - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); return syserror (errcode); } @@ -556,7 +568,7 @@ dc_serial_set_latency (dc_serial_t *device, unsigned int milliseconds) // Apply the new settings. if (ioctl (device->fd, TIOCSSERIAL, &ss) != 0 && NOPTY) { int errcode = errno; - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); return syserror (errcode); } #elif defined(IOSSDATALAT) @@ -566,7 +578,7 @@ dc_serial_set_latency (dc_serial_t *device, unsigned int milliseconds) unsigned long usec = (milliseconds == 0 ? 1 : milliseconds * 1000); if (ioctl (device->fd, IOSSDATALAT, &usec) != 0 && NOPTY) { int errcode = errno; - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); return syserror (errcode); } #endif @@ -574,25 +586,13 @@ dc_serial_set_latency (dc_serial_t *device, unsigned int milliseconds) return DC_STATUS_SUCCESS; } -dc_status_t -dc_serial_read (dc_serial_t *device, void *data, size_t size, size_t *actual) +static dc_status_t +dc_serial_read (dc_iostream_t *abstract, void *data, size_t size, size_t *actual) { dc_status_t status = DC_STATUS_SUCCESS; + dc_serial_t *device = (dc_serial_t *) abstract; size_t nbytes = 0; - if (device == NULL) { - status = DC_STATUS_INVALIDARGS; - goto out_invalidargs; - } - - RETURN_IF_CUSTOM_SERIAL(device->context, - { - HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Custom Read", (unsigned char *) data, nbytes); - if (actual) - *actual = nbytes; - }, - read, data, size, &nbytes); - // The total timeout. int timeout = device->timeout; @@ -610,7 +610,7 @@ dc_serial_read (dc_serial_t *device, void *data, size_t size, size_t *actual) struct timeval now; if (gettimeofday (&now, NULL) != 0) { int errcode = errno; - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); status = syserror (errcode); goto out; } @@ -638,7 +638,7 @@ dc_serial_read (dc_serial_t *device, void *data, size_t size, size_t *actual) int errcode = errno; if (errcode == EINTR) continue; // Retry. - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); status = syserror (errcode); goto out; } else if (rc == 0) { @@ -650,7 +650,7 @@ dc_serial_read (dc_serial_t *device, void *data, size_t size, size_t *actual) int errcode = errno; if (errcode == EINTR || errcode == EAGAIN) continue; // Retry. - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); status = syserror (errcode); goto out; } else if (n == 0) { @@ -665,40 +665,25 @@ dc_serial_read (dc_serial_t *device, void *data, size_t size, size_t *actual) } out: - HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Read", (unsigned char *) data, nbytes); - -out_invalidargs: if (actual) *actual = nbytes; return status; } -dc_status_t -dc_serial_write (dc_serial_t *device, const void *data, size_t size, size_t *actual) +static dc_status_t +dc_serial_write (dc_iostream_t *abstract, const void *data, size_t size, size_t *actual) { dc_status_t status = DC_STATUS_SUCCESS; + dc_serial_t *device = (dc_serial_t *) abstract; size_t nbytes = 0; - if (device == NULL) { - status = DC_STATUS_INVALIDARGS; - goto out_invalidargs; - } - - RETURN_IF_CUSTOM_SERIAL(device->context, - { - HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Custom Write", (unsigned char *) data, nbytes); - if (actual) - *actual = nbytes; - }, - write, data, size, &nbytes); - struct timeval tve, tvb; if (device->halfduplex) { // Get the current time. if (gettimeofday (&tvb, NULL) != 0) { int errcode = errno; - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); status = syserror (errcode); goto out; } @@ -714,7 +699,7 @@ dc_serial_write (dc_serial_t *device, const void *data, size_t size, size_t *act int errcode = errno; if (errcode == EINTR) continue; // Retry. - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); status = syserror (errcode); goto out; } else if (rc == 0) { @@ -726,7 +711,7 @@ dc_serial_write (dc_serial_t *device, const void *data, size_t size, size_t *act int errcode = errno; if (errcode == EINTR || errcode == EAGAIN) continue; // Retry. - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); status = syserror (errcode); goto out; } else if (n == 0) { @@ -745,7 +730,7 @@ dc_serial_write (dc_serial_t *device, const void *data, size_t size, size_t *act #endif int errcode = errno; if (errcode != EINTR ) { - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); status = syserror (errcode); goto out; } @@ -755,7 +740,7 @@ dc_serial_write (dc_serial_t *device, const void *data, size_t size, size_t *act // Get the current time. if (gettimeofday (&tve, NULL) != 0) { int errcode = errno; - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); status = syserror (errcode); goto out; } @@ -776,29 +761,21 @@ dc_serial_write (dc_serial_t *device, const void *data, size_t size, size_t *act // The remaining time is rounded up to the nearest millisecond to // match the Windows implementation. The higher resolution is // pointless anyway, since we already added a fudge factor above. - dc_serial_sleep (device, (remaining + 999) / 1000); + dc_serial_sleep (abstract, (remaining + 999) / 1000); } } out: - HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Write", (const unsigned char *) data, nbytes); - -out_invalidargs: if (actual) *actual = nbytes; return status; } -dc_status_t -dc_serial_purge (dc_serial_t *device, dc_direction_t direction) +static dc_status_t +dc_serial_purge (dc_iostream_t *abstract, dc_direction_t direction) { - if (device == NULL) - return DC_STATUS_INVALIDARGS; - - INFO (device->context, "Purge: direction=%u", direction); - - RETURN_IF_CUSTOM_SERIAL(device->context, , purge, direction); + dc_serial_t *device = (dc_serial_t *) abstract; int flags = 0; @@ -818,101 +795,78 @@ dc_serial_purge (dc_serial_t *device, dc_direction_t direction) if (tcflush (device->fd, flags) != 0) { int errcode = errno; - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); return syserror (errcode); } return DC_STATUS_SUCCESS; } -dc_status_t -dc_serial_flush (dc_serial_t *device) +static dc_status_t +dc_serial_flush (dc_iostream_t *abstract) { - if (device == NULL) - return DC_STATUS_INVALIDARGS; - - INFO (device->context, "Flush: none"); - return DC_STATUS_SUCCESS; } -dc_status_t -dc_serial_set_break (dc_serial_t *device, unsigned int level) +static dc_status_t +dc_serial_set_break (dc_iostream_t *abstract, unsigned int level) { - if (device == NULL) - return DC_STATUS_INVALIDARGS; - - INFO (device->context, "Break: value=%i", level); - - RETURN_IF_CUSTOM_SERIAL(device->context, , set_break, level); + dc_serial_t *device = (dc_serial_t *) abstract; unsigned long action = (level ? TIOCSBRK : TIOCCBRK); if (ioctl (device->fd, action, NULL) != 0 && NOPTY) { int errcode = errno; - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); return syserror (errcode); } return DC_STATUS_SUCCESS; } -dc_status_t -dc_serial_set_dtr (dc_serial_t *device, unsigned int level) +static dc_status_t +dc_serial_set_dtr (dc_iostream_t *abstract, unsigned int level) { - if (device == NULL) - return DC_STATUS_INVALIDARGS; - - INFO (device->context, "DTR: value=%i", level); - - RETURN_IF_CUSTOM_SERIAL(device->context, , set_dtr, level); + dc_serial_t *device = (dc_serial_t *) abstract; unsigned long action = (level ? TIOCMBIS : TIOCMBIC); int value = TIOCM_DTR; if (ioctl (device->fd, action, &value) != 0 && NOPTY) { int errcode = errno; - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); return syserror (errcode); } return DC_STATUS_SUCCESS; } -dc_status_t -dc_serial_set_rts (dc_serial_t *device, unsigned int level) +static dc_status_t +dc_serial_set_rts (dc_iostream_t *abstract, unsigned int level) { - if (device == NULL) - return DC_STATUS_INVALIDARGS; - - INFO (device->context, "RTS: value=%i", level); - - RETURN_IF_CUSTOM_SERIAL(device->context, , set_rts, level); + dc_serial_t *device = (dc_serial_t *) abstract; unsigned long action = (level ? TIOCMBIS : TIOCMBIC); int value = TIOCM_RTS; if (ioctl (device->fd, action, &value) != 0 && NOPTY) { int errcode = errno; - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); return syserror (errcode); } return DC_STATUS_SUCCESS; } -dc_status_t -dc_serial_get_available (dc_serial_t *device, size_t *value) +static dc_status_t +dc_serial_get_available (dc_iostream_t *abstract, size_t *value) { - if (device == NULL) - return DC_STATUS_INVALIDARGS; - - RETURN_IF_CUSTOM_SERIAL(device->context, , get_available, value); + dc_serial_t *device = (dc_serial_t *) abstract; int bytes = 0; if (ioctl (device->fd, TIOCINQ, &bytes) != 0) { int errcode = errno; - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); return syserror (errcode); } @@ -922,18 +876,16 @@ dc_serial_get_available (dc_serial_t *device, size_t *value) return DC_STATUS_SUCCESS; } -dc_status_t -dc_serial_get_lines (dc_serial_t *device, unsigned int *value) +static dc_status_t +dc_serial_get_lines (dc_iostream_t *abstract, unsigned int *value) { + dc_serial_t *device = (dc_serial_t *) abstract; unsigned int lines = 0; - if (device == NULL) - return DC_STATUS_INVALIDARGS; - int status = 0; if (ioctl (device->fd, TIOCMGET, &status) != 0) { int errcode = errno; - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); return syserror (errcode); } @@ -952,14 +904,9 @@ dc_serial_get_lines (dc_serial_t *device, unsigned int *value) return DC_STATUS_SUCCESS; } -dc_status_t -dc_serial_sleep (dc_serial_t *device, unsigned int timeout) +static dc_status_t +dc_serial_sleep (dc_iostream_t *abstract, unsigned int timeout) { - if (device == NULL) - return DC_STATUS_INVALIDARGS; - - INFO (device->context, "Sleep: value=%u", timeout); - struct timespec ts; ts.tv_sec = (timeout / 1000); ts.tv_nsec = (timeout % 1000) * 1000000; @@ -967,7 +914,7 @@ dc_serial_sleep (dc_serial_t *device, unsigned int timeout) while (nanosleep (&ts, &ts) != 0) { int errcode = errno; if (errcode != EINTR ) { - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); return syserror (errcode); } } diff --git a/src/serial_win32.c b/src/serial_win32.c index 540ec11..b530c9b 100644 --- a/src/serial_win32.c +++ b/src/serial_win32.c @@ -25,12 +25,29 @@ #include #include "serial.h" + #include "common-private.h" #include "context-private.h" +#include "iostream-private.h" -struct dc_serial_t { - /* Library context. */ - dc_context_t *context; +static dc_status_t dc_serial_set_timeout (dc_iostream_t *iostream, int timeout); +static dc_status_t dc_serial_set_latency (dc_iostream_t *iostream, unsigned int value); +static dc_status_t dc_serial_set_halfduplex (dc_iostream_t *iostream, unsigned int value); +static dc_status_t dc_serial_set_break (dc_iostream_t *iostream, unsigned int value); +static dc_status_t dc_serial_set_dtr (dc_iostream_t *iostream, unsigned int value); +static dc_status_t dc_serial_set_rts (dc_iostream_t *iostream, unsigned int value); +static dc_status_t dc_serial_get_lines (dc_iostream_t *iostream, unsigned int *value); +static dc_status_t dc_serial_get_available (dc_iostream_t *iostream, size_t *value); +static dc_status_t dc_serial_configure (dc_iostream_t *iostream, unsigned int baudrate, unsigned int databits, dc_parity_t parity, dc_stopbits_t stopbits, dc_flowcontrol_t flowcontrol); +static dc_status_t dc_serial_read (dc_iostream_t *iostream, void *data, size_t size, size_t *actual); +static dc_status_t dc_serial_write (dc_iostream_t *iostream, const void *data, size_t size, size_t *actual); +static dc_status_t dc_serial_flush (dc_iostream_t *iostream); +static dc_status_t dc_serial_purge (dc_iostream_t *iostream, dc_direction_t direction); +static dc_status_t dc_serial_sleep (dc_iostream_t *iostream, unsigned int milliseconds); +static dc_status_t dc_serial_close (dc_iostream_t *iostream); + +typedef struct dc_serial_t { + dc_iostream_t base; /* * The file descriptor corresponding to the serial port. */ @@ -46,6 +63,25 @@ struct dc_serial_t { int halfduplex; unsigned int baudrate; unsigned int nbits; +} dc_serial_t; + +static const dc_iostream_vtable_t dc_serial_vtable = { + sizeof(dc_serial_t), + dc_serial_set_timeout, /* set_timeout */ + dc_serial_set_latency, /* set_latency */ + dc_serial_set_halfduplex, /* set_halfduplex */ + dc_serial_set_break, /* set_break */ + dc_serial_set_dtr, /* set_dtr */ + dc_serial_set_rts, /* set_rts */ + dc_serial_get_lines, /* get_lines */ + dc_serial_get_available, /* get_received */ + dc_serial_configure, /* configure */ + dc_serial_read, /* read */ + dc_serial_write, /* write */ + dc_serial_flush, /* flush */ + dc_serial_purge, /* purge */ + dc_serial_sleep, /* sleep */ + dc_serial_close, /* close */ }; static dc_status_t @@ -120,19 +156,24 @@ dc_serial_enumerate (dc_serial_callback_t callback, void *userdata) } dc_status_t -dc_serial_open (dc_serial_t **out, dc_context_t *context, const char *name) +dc_serial_open (dc_iostream_t **out, dc_context_t *context, const char *name) { dc_status_t status = DC_STATUS_SUCCESS; + dc_serial_t *device = NULL; - if (out == NULL) + if (out == NULL || name == NULL) return DC_STATUS_INVALIDARGS; - INFO (context, "Open: name=%s", name ? name : ""); + // Are we using custom IO? + if (_dc_context_custom_io(context)) + return dc_custom_io_serial_open(out, context, name); + + INFO (context, "Open: name=%s", name); // Build the device name. const char *devname = NULL; char buffer[MAX_PATH] = "\\\\.\\"; - if (name && strncmp (name, buffer, 4) != 0) { + if (strncmp (name, buffer, 4) != 0) { size_t length = strlen (name) + 1; if (length + 4 > sizeof (buffer)) return DC_STATUS_NOMEMORY; @@ -143,22 +184,17 @@ dc_serial_open (dc_serial_t **out, dc_context_t *context, const char *name) } // Allocate memory. - dc_serial_t *device = (dc_serial_t *) malloc (sizeof (dc_serial_t)); + device = (dc_serial_t *) dc_iostream_allocate (context, &dc_serial_vtable); if (device == NULL) { SYSERROR (context, ERROR_OUTOFMEMORY); return DC_STATUS_NOMEMORY; } - // Library context. - device->context = context; - // Default to full-duplex. device->halfduplex = 0; device->baudrate = 0; device->nbits = 0; - RETURN_IF_CUSTOM_SERIAL(context, *out = device, open, context, name); - // Open the device. device->hFile = CreateFileA (devname, GENERIC_READ | GENERIC_WRITE, 0, @@ -185,64 +221,51 @@ dc_serial_open (dc_serial_t **out, dc_context_t *context, const char *name) goto error_close; } - *out = device; + *out = (dc_iostream_t *) device; return DC_STATUS_SUCCESS; error_close: CloseHandle (device->hFile); error_free: - free (device); + dc_iostream_deallocate ((dc_iostream_t *) device); return status; } -dc_status_t -dc_serial_close (dc_serial_t *device) +static dc_status_t +dc_serial_close (dc_iostream_t *abstract) { dc_status_t status = DC_STATUS_SUCCESS; - - if (device == NULL) - return DC_STATUS_SUCCESS; - - RETURN_IF_CUSTOM_SERIAL(device->context, free(device), close); + dc_serial_t *device = (dc_serial_t *) abstract; // Restore the initial communication settings and timeouts. if (!SetCommState (device->hFile, &device->dcb) || !SetCommTimeouts (device->hFile, &device->timeouts)) { DWORD errcode = GetLastError (); - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); dc_status_set_error(&status, syserror (errcode)); } // Close the device. if (!CloseHandle (device->hFile)) { DWORD errcode = GetLastError (); - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); dc_status_set_error(&status, syserror (errcode)); } - // Free memory. - free (device); - return status; } -dc_status_t -dc_serial_configure (dc_serial_t *device, unsigned int baudrate, unsigned int databits, dc_parity_t parity, dc_stopbits_t stopbits, dc_flowcontrol_t flowcontrol) +static dc_status_t +dc_serial_configure (dc_iostream_t *abstract, unsigned int baudrate, unsigned int databits, dc_parity_t parity, dc_stopbits_t stopbits, dc_flowcontrol_t flowcontrol) { - if (device == NULL) - return DC_STATUS_INVALIDARGS; - - INFO (device->context, "Configure: baudrate=%i, databits=%i, parity=%i, stopbits=%i, flowcontrol=%i", - baudrate, databits, parity, stopbits, flowcontrol); - - RETURN_IF_CUSTOM_SERIAL(device->context, , configure, baudrate, databits, parity, stopbits, flowcontrol); + dc_serial_t *device = (dc_serial_t *) abstract; // Retrieve the current settings. DCB dcb; if (!GetCommState (device->hFile, &dcb)) { DWORD errcode = GetLastError (); - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); return syserror (errcode); } @@ -332,7 +355,7 @@ dc_serial_configure (dc_serial_t *device, unsigned int baudrate, unsigned int da // Apply the new settings. if (!SetCommState (device->hFile, &dcb)) { DWORD errcode = GetLastError (); - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); return syserror (errcode); } @@ -342,21 +365,16 @@ dc_serial_configure (dc_serial_t *device, unsigned int baudrate, unsigned int da return DC_STATUS_SUCCESS; } -dc_status_t -dc_serial_set_timeout (dc_serial_t *device, int timeout) +static dc_status_t +dc_serial_set_timeout (dc_iostream_t *abstract, int timeout) { - if (device == NULL) - return DC_STATUS_INVALIDARGS; - - INFO (device->context, "Timeout: value=%i", timeout); - - RETURN_IF_CUSTOM_SERIAL(device->context, , set_timeout, timeout); + dc_serial_t *device = (dc_serial_t *) abstract; // Retrieve the current timeouts. COMMTIMEOUTS timeouts; if (!GetCommTimeouts (device->hFile, &timeouts)) { DWORD errcode = GetLastError (); - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); return syserror (errcode); } @@ -387,58 +405,39 @@ dc_serial_set_timeout (dc_serial_t *device, int timeout) // Activate the new timeouts. if (!SetCommTimeouts (device->hFile, &timeouts)) { DWORD errcode = GetLastError (); - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); return syserror (errcode); } return DC_STATUS_SUCCESS; } -dc_status_t -dc_serial_set_halfduplex (dc_serial_t *device, unsigned int value) +static dc_status_t +dc_serial_set_halfduplex (dc_iostream_t *abstract, unsigned int value) { - if (device == NULL) - return DC_STATUS_INVALIDARGS; - - RETURN_IF_CUSTOM_SERIAL(device->context, , set_halfduplex, value); + dc_serial_t *device = (dc_serial_t *) abstract; device->halfduplex = value; return DC_STATUS_SUCCESS; } -dc_status_t -dc_serial_set_latency (dc_serial_t *device, unsigned int value) +static dc_status_t +dc_serial_set_latency (dc_iostream_t *abstract, unsigned int value) { - if (device == NULL) - return DC_STATUS_INVALIDARGS; - return DC_STATUS_SUCCESS; } -dc_status_t -dc_serial_read (dc_serial_t *device, void *data, size_t size, size_t *actual) +static dc_status_t +dc_serial_read (dc_iostream_t *abstract, void *data, size_t size, size_t *actual) { - size_t nbytes = 0; dc_status_t status = DC_STATUS_SUCCESS; + dc_serial_t *device = (dc_serial_t *) abstract; DWORD dwRead = 0; - if (device == NULL) { - status = DC_STATUS_INVALIDARGS; - goto out_invalidargs; - } - - RETURN_IF_CUSTOM_SERIAL(device->context, - { - HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Custom Read", (unsigned char *) data, nbytes); - if (actual) - *actual = nbytes; - }, - read, data, size, &nbytes); - if (!ReadFile (device->hFile, data, size, &dwRead, NULL)) { DWORD errcode = GetLastError (); - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); status = syserror (errcode); goto out; } @@ -448,42 +447,26 @@ dc_serial_read (dc_serial_t *device, void *data, size_t size, size_t *actual) } out: - HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Read", (unsigned char *) data, dwRead); - -out_invalidargs: if (actual) *actual = dwRead; return status; } -dc_status_t -dc_serial_write (dc_serial_t *device, const void *data, size_t size, size_t *actual) +static dc_status_t +dc_serial_write (dc_iostream_t *abstract, const void *data, size_t size, size_t *actual) { - size_t nbytes = 0; dc_status_t status = DC_STATUS_SUCCESS; + dc_serial_t *device = (dc_serial_t *) abstract; DWORD dwWritten = 0; - if (device == NULL) { - status = DC_STATUS_INVALIDARGS; - goto out_invalidargs; - } - - RETURN_IF_CUSTOM_SERIAL(device->context, - { - HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Custom Write", (unsigned char *) data, nbytes); - if (actual) - *actual = nbytes; - }, - write, data, size, &nbytes); - LARGE_INTEGER begin, end, freq; if (device->halfduplex) { // Get the current time. if (!QueryPerformanceFrequency(&freq) || !QueryPerformanceCounter(&begin)) { DWORD errcode = GetLastError (); - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); status = syserror (errcode); goto out; } @@ -491,7 +474,7 @@ dc_serial_write (dc_serial_t *device, const void *data, size_t size, size_t *act if (!WriteFile (device->hFile, data, size, &dwWritten, NULL)) { DWORD errcode = GetLastError (); - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); status = syserror (errcode); goto out; } @@ -500,7 +483,7 @@ dc_serial_write (dc_serial_t *device, const void *data, size_t size, size_t *act // Get the current time. if (!QueryPerformanceCounter(&end)) { DWORD errcode = GetLastError (); - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); status = syserror (errcode); goto out; } @@ -519,7 +502,7 @@ dc_serial_write (dc_serial_t *device, const void *data, size_t size, size_t *act // The remaining time is rounded up to the nearest millisecond // because the Windows Sleep() function doesn't have a higher // resolution. - dc_serial_sleep (device, (remaining + 999) / 1000); + dc_serial_sleep (abstract, (remaining + 999) / 1000); } } @@ -528,24 +511,16 @@ dc_serial_write (dc_serial_t *device, const void *data, size_t size, size_t *act } out: - HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Write", (const unsigned char *) data, dwWritten); - -out_invalidargs: if (actual) *actual = dwWritten; return status; } -dc_status_t -dc_serial_purge (dc_serial_t *device, dc_direction_t direction) +static dc_status_t +dc_serial_purge (dc_iostream_t *abstract, dc_direction_t direction) { - if (device == NULL) - return DC_STATUS_INVALIDARGS; - - INFO (device->context, "Purge: direction=%u", direction); - - RETURN_IF_CUSTOM_SERIAL(device->context, , purge, direction); + dc_serial_t *device = (dc_serial_t *) abstract; DWORD flags = 0; @@ -565,50 +540,42 @@ dc_serial_purge (dc_serial_t *device, dc_direction_t direction) if (!PurgeComm (device->hFile, flags)) { DWORD errcode = GetLastError (); - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); return syserror (errcode); } return DC_STATUS_SUCCESS; } -dc_status_t -dc_serial_flush (dc_serial_t *device) +static dc_status_t +dc_serial_flush (dc_iostream_t *abstract) { - if (device == NULL) - return DC_STATUS_INVALIDARGS; - - INFO (device->context, "Flush: none"); + dc_serial_t *device = (dc_serial_t *) abstract; if (!FlushFileBuffers (device->hFile)) { DWORD errcode = GetLastError (); - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); return syserror (errcode); } return DC_STATUS_SUCCESS; } -dc_status_t -dc_serial_set_break (dc_serial_t *device, unsigned int level) +static dc_status_t +dc_serial_set_break (dc_iostream_t *abstract, unsigned int level) { - if (device == NULL) - return DC_STATUS_INVALIDARGS; - - INFO (device->context, "Break: value=%i", level); - - RETURN_IF_CUSTOM_SERIAL(device->context, , set_break, level); + dc_serial_t *device = (dc_serial_t *) abstract; if (level) { if (!SetCommBreak (device->hFile)) { DWORD errcode = GetLastError (); - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); return syserror (errcode); } } else { if (!ClearCommBreak (device->hFile)) { DWORD errcode = GetLastError (); - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); return syserror (errcode); } } @@ -616,61 +583,48 @@ dc_serial_set_break (dc_serial_t *device, unsigned int level) return DC_STATUS_SUCCESS; } -dc_status_t -dc_serial_set_dtr (dc_serial_t *device, unsigned int level) +static dc_status_t +dc_serial_set_dtr (dc_iostream_t *abstract, unsigned int level) { - if (device == NULL) - return DC_STATUS_INVALIDARGS; - - INFO (device->context, "DTR: value=%i", level); - - RETURN_IF_CUSTOM_SERIAL(device->context, , set_dtr, level); + dc_serial_t *device = (dc_serial_t *) abstract; int status = (level ? SETDTR : CLRDTR); if (!EscapeCommFunction (device->hFile, status)) { DWORD errcode = GetLastError (); - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); return syserror (errcode); } return DC_STATUS_SUCCESS; } -dc_status_t -dc_serial_set_rts (dc_serial_t *device, unsigned int level) +static dc_status_t +dc_serial_set_rts (dc_iostream_t *abstract, unsigned int level) { - if (device == NULL) - return DC_STATUS_INVALIDARGS; - - INFO (device->context, "RTS: value=%i", level); - - RETURN_IF_CUSTOM_SERIAL(device->context, , set_rts, level); + dc_serial_t *device = (dc_serial_t *) abstract; int status = (level ? SETRTS : CLRRTS); if (!EscapeCommFunction (device->hFile, status)) { DWORD errcode = GetLastError (); - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); return syserror (errcode); } return DC_STATUS_SUCCESS; } -dc_status_t -dc_serial_get_available (dc_serial_t *device, size_t *value) +static dc_status_t +dc_serial_get_available (dc_iostream_t *abstract, size_t *value) { - if (device == NULL) - return DC_STATUS_INVALIDARGS; - - RETURN_IF_CUSTOM_SERIAL(device->context, , get_available, value); + dc_serial_t *device = (dc_serial_t *) abstract; COMSTAT stats; if (!ClearCommError (device->hFile, NULL, &stats)) { DWORD errcode = GetLastError (); - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); return syserror (errcode); } @@ -680,18 +634,16 @@ dc_serial_get_available (dc_serial_t *device, size_t *value) return DC_STATUS_SUCCESS; } -dc_status_t -dc_serial_get_lines (dc_serial_t *device, unsigned int *value) +static dc_status_t +dc_serial_get_lines (dc_iostream_t *abstract, unsigned int *value) { + dc_serial_t *device = (dc_serial_t *) abstract; unsigned int lines = 0; - if (device == NULL) - return DC_STATUS_INVALIDARGS; - DWORD stats = 0; if (!GetCommModemStatus (device->hFile, &stats)) { DWORD errcode = GetLastError (); - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); return syserror (errcode); } @@ -710,14 +662,9 @@ dc_serial_get_lines (dc_serial_t *device, unsigned int *value) return DC_STATUS_SUCCESS; } -dc_status_t -dc_serial_sleep (dc_serial_t *device, unsigned int timeout) +static dc_status_t +dc_serial_sleep (dc_iostream_t *abstract, unsigned int timeout) { - if (device == NULL) - return DC_STATUS_INVALIDARGS; - - INFO (device->context, "Sleep: value=%u", timeout); - Sleep (timeout); return DC_STATUS_SUCCESS; diff --git a/src/shearwater_common.c b/src/shearwater_common.c index 58fd3a3..bad14c8 100644 --- a/src/shearwater_common.c +++ b/src/shearwater_common.c @@ -41,21 +41,21 @@ shearwater_common_open (shearwater_common_device_t *device, dc_context_t *contex dc_status_t status = DC_STATUS_SUCCESS; // Open the device. - status = dc_serial_open (&device->port, context, name); + status = dc_serial_open (&device->iostream, context, name); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the serial port."); return status; } // Set the serial communication protocol (115200 8N1). - status = dc_serial_configure (device->port, 115200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); + status = dc_iostream_configure (device->iostream, 115200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); goto error_close; } // Set the timeout for receiving data (3000ms). - status = dc_serial_set_timeout (device->port, 3000); + status = dc_iostream_set_timeout (device->iostream, 3000); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the timeout."); status = DC_STATUS_IO; @@ -63,13 +63,13 @@ shearwater_common_open (shearwater_common_device_t *device, dc_context_t *contex } // Make sure everything is in a sane state. - dc_serial_sleep (device->port, 300); - dc_serial_purge (device->port, DC_DIRECTION_ALL); + dc_iostream_sleep (device->iostream, 300); + dc_iostream_purge (device->iostream, DC_DIRECTION_ALL); return DC_STATUS_SUCCESS; error_close: - dc_serial_close (device->port); + dc_iostream_close (device->iostream); return status; } @@ -78,7 +78,7 @@ dc_status_t shearwater_common_close (shearwater_common_device_t *device) { // Close the device. - return dc_serial_close (device->port); + return dc_iostream_close (device->iostream); } @@ -154,7 +154,7 @@ shearwater_common_slip_write (shearwater_common_device_t *device, const unsigned #if 0 // Send an initial END character to flush out any data that may have // accumulated in the receiver due to line noise. - status = dc_serial_write (device->port, end, sizeof (end), NULL); + status = dc_iostream_write (device->iostream, end, sizeof (end), NULL); if (status != DC_STATUS_SUCCESS) { return status; } @@ -183,7 +183,7 @@ shearwater_common_slip_write (shearwater_common_device_t *device, const unsigned // Flush the buffer if necessary. if (nbytes + len + sizeof(end) > sizeof(buffer)) { - status = dc_serial_write (device->port, buffer, nbytes, NULL); + status = dc_iostream_write (device->iostream, buffer, nbytes, NULL); if (status != DC_STATUS_SUCCESS) { return status; } @@ -201,7 +201,7 @@ shearwater_common_slip_write (shearwater_common_device_t *device, const unsigned nbytes += sizeof(end); // Flush the buffer. - status = dc_serial_write (device->port, buffer, nbytes, NULL); + status = dc_iostream_write (device->iostream, buffer, nbytes, NULL); if (status != DC_STATUS_SUCCESS) { return status; } @@ -224,7 +224,7 @@ shearwater_common_slip_read (shearwater_common_device_t *device, unsigned char d unsigned char c = 0; // Get a single character to process. - status = dc_serial_read (device->port, &c, 1, NULL); + status = dc_iostream_read (device->iostream, &c, 1, NULL); if (status != DC_STATUS_SUCCESS) { return status; } @@ -243,7 +243,7 @@ shearwater_common_slip_read (shearwater_common_device_t *device, unsigned char d case ESC: // If it's an ESC character, get another character and then // figure out what to store in the packet based on that. - status = dc_serial_read (device->port, &c, 1, NULL); + status = dc_iostream_read (device->iostream, &c, 1, NULL); if (status != DC_STATUS_SUCCESS) { return status; } diff --git a/src/shearwater_common.h b/src/shearwater_common.h index 4253a00..4e3a561 100644 --- a/src/shearwater_common.h +++ b/src/shearwater_common.h @@ -44,7 +44,7 @@ extern "C" { typedef struct shearwater_common_device_t { dc_device_t base; - dc_serial_t *port; + dc_iostream_t *iostream; } shearwater_common_device_t; dc_status_t diff --git a/src/shearwater_predator_parser.c b/src/shearwater_predator_parser.c index 6e81083..16b458a 100644 --- a/src/shearwater_predator_parser.c +++ b/src/shearwater_predator_parser.c @@ -408,7 +408,7 @@ shearwater_predator_parser_cache (shearwater_predator_parser_t *parser) // Status flags. unsigned int status = data[offset + 11]; if ((status & OC) == 0) { - mode = DC_DIVEMODE_CC; + mode = DC_DIVEMODE_CCR; } // Gaschange. diff --git a/src/socket.c b/src/socket.c new file mode 100644 index 0000000..5ce392f --- /dev/null +++ b/src/socket.c @@ -0,0 +1,358 @@ +/* + * libdivecomputer + * + * Copyright (C) 2017 Jef Driesen + * + * This library 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 2.1 of the License, or (at your option) any later version. + * + * This library 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 this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include "socket.h" + +#include "common-private.h" +#include "context-private.h" + +dc_status_t +dc_socket_syserror (s_errcode_t errcode) +{ + switch (errcode) { + case S_EINVAL: + return DC_STATUS_INVALIDARGS; + case S_ENOMEM: + return DC_STATUS_NOMEMORY; + case S_EACCES: + return DC_STATUS_NOACCESS; + case S_EAFNOSUPPORT: + return DC_STATUS_UNSUPPORTED; + default: + return DC_STATUS_IO; + } +} + +dc_status_t +dc_socket_init (dc_context_t *context) +{ +#ifdef _WIN32 + // Initialize the winsock dll. + WSADATA wsaData; + WORD wVersionRequested = MAKEWORD (2, 2); + int rc = WSAStartup (wVersionRequested, &wsaData); + if (rc != 0) { + SYSERROR (context, rc); + return DC_STATUS_UNSUPPORTED; + } + + // Confirm that the winsock dll supports version 2.2. + // Note that if the dll supports versions greater than 2.2 in addition to + // 2.2, it will still return 2.2 since that is the version we requested. + if (LOBYTE (wsaData.wVersion) != 2 || + HIBYTE (wsaData.wVersion) != 2) { + ERROR (context, "Incorrect winsock version."); + return DC_STATUS_UNSUPPORTED; + } +#endif + + return DC_STATUS_SUCCESS; +} + +dc_status_t +dc_socket_exit (dc_context_t *context) +{ +#ifdef _WIN32 + // Terminate the winsock dll. + if (WSACleanup () != 0) { + s_errcode_t errcode = S_ERRNO; + SYSERROR (context, errcode); + return dc_socket_syserror(errcode); + } +#endif + + return DC_STATUS_SUCCESS; +} + +dc_status_t +dc_socket_open (dc_iostream_t *abstract, int family, int type, int protocol) +{ + dc_status_t status = DC_STATUS_SUCCESS; + dc_socket_t *device = (dc_socket_t *) abstract; + + // Default to blocking reads. + device->timeout = -1; + + // Initialize the socket library. + status = dc_socket_init (abstract->context); + if (status != DC_STATUS_SUCCESS) { + return status; + } + + // Open the socket. + device->fd = socket (family, type, protocol); + if (device->fd == S_INVALID) { + s_errcode_t errcode = S_ERRNO; + SYSERROR (abstract->context, errcode); + status = dc_socket_syserror(errcode); + goto error; + } + + return DC_STATUS_SUCCESS; + +error: + dc_socket_exit (abstract->context); + return status; +} + +dc_status_t +dc_socket_close (dc_iostream_t *abstract) +{ + dc_status_t status = DC_STATUS_SUCCESS; + dc_socket_t *socket = (dc_socket_t *) abstract; + dc_status_t rc = DC_STATUS_SUCCESS; + + // Terminate all send and receive operations. + shutdown (socket->fd, 0); + + // Close the socket. + if (S_CLOSE (socket->fd) != 0) { + s_errcode_t errcode = S_ERRNO; + SYSERROR (abstract->context, errcode); + dc_status_set_error(&status, dc_socket_syserror(errcode)); + } + + // Terminate the socket library. + rc = dc_socket_exit (abstract->context); + if (rc != DC_STATUS_SUCCESS) { + dc_status_set_error(&status, rc); + } + + return status; +} + +dc_status_t +dc_socket_connect (dc_iostream_t *abstract, const struct sockaddr *addr, s_socklen_t addrlen) +{ + dc_socket_t *socket = (dc_socket_t *) abstract; + + if (connect (socket->fd, addr, addrlen) != 0) { + s_errcode_t errcode = S_ERRNO; + SYSERROR (abstract->context, errcode); + return dc_socket_syserror(errcode); + } + + return DC_STATUS_SUCCESS; +} + +dc_status_t +dc_socket_set_timeout (dc_iostream_t *abstract, int timeout) +{ + dc_socket_t *socket = (dc_socket_t *) abstract; + + socket->timeout = timeout; + + return DC_STATUS_SUCCESS; +} + +dc_status_t +dc_socket_set_latency (dc_iostream_t *iostream, unsigned int value) +{ + return DC_STATUS_SUCCESS; +} + +dc_status_t +dc_socket_set_halfduplex (dc_iostream_t *iostream, unsigned int value) +{ + return DC_STATUS_SUCCESS; +} + +dc_status_t +dc_socket_set_break (dc_iostream_t *iostream, unsigned int value) +{ + return DC_STATUS_SUCCESS; +} + +dc_status_t +dc_socket_set_dtr (dc_iostream_t *iostream, unsigned int value) +{ + return DC_STATUS_SUCCESS; +} + +dc_status_t +dc_socket_set_rts (dc_iostream_t *iostream, unsigned int value) +{ + return DC_STATUS_SUCCESS; +} + +dc_status_t +dc_socket_get_lines (dc_iostream_t *iostream, unsigned int *value) +{ + if (value) + *value = 0; + + return DC_STATUS_SUCCESS; +} + +dc_status_t +dc_socket_get_available (dc_iostream_t *abstract, size_t *value) +{ + dc_socket_t *socket = (dc_socket_t *) abstract; + +#ifdef _WIN32 + unsigned long bytes = 0; +#else + int bytes = 0; +#endif + + if (S_IOCTL (socket->fd, FIONREAD, &bytes) != 0) { + s_errcode_t errcode = S_ERRNO; + SYSERROR (abstract->context, errcode); + return dc_socket_syserror(errcode); + } + + if (value) + *value = bytes; + + return DC_STATUS_SUCCESS; +} + +dc_status_t +dc_socket_configure (dc_iostream_t *abstract, unsigned int baudrate, unsigned int databits, dc_parity_t parity, dc_stopbits_t stopbits, dc_flowcontrol_t flowcontrol) +{ + return DC_STATUS_SUCCESS; +} + +dc_status_t +dc_socket_read (dc_iostream_t *abstract, void *data, size_t size, size_t *actual) +{ + dc_status_t status = DC_STATUS_SUCCESS; + dc_socket_t *socket = (dc_socket_t *) abstract; + size_t nbytes = 0; + + while (nbytes < size) { + fd_set fds; + FD_ZERO (&fds); + FD_SET (socket->fd, &fds); + + struct timeval tvt; + if (socket->timeout > 0) { + tvt.tv_sec = (socket->timeout / 1000); + tvt.tv_usec = (socket->timeout % 1000) * 1000; + } else if (socket->timeout == 0) { + timerclear (&tvt); + } + + int rc = select (socket->fd + 1, &fds, NULL, NULL, socket->timeout >= 0 ? &tvt : NULL); + if (rc < 0) { + s_errcode_t errcode = S_ERRNO; + if (errcode == S_EINTR) + continue; // Retry. + SYSERROR (abstract->context, errcode); + status = dc_socket_syserror(errcode); + goto out; + } else if (rc == 0) { + break; // Timeout. + } + + s_ssize_t n = recv (socket->fd, (char *) data + nbytes, size - nbytes, 0); + if (n < 0) { + s_errcode_t errcode = S_ERRNO; + if (errcode == S_EINTR || errcode == S_EAGAIN) + continue; // Retry. + SYSERROR (abstract->context, errcode); + status = dc_socket_syserror(errcode); + goto out; + } else if (n == 0) { + break; // EOF reached. + } + + nbytes += n; + } + + if (nbytes != size) { + status = DC_STATUS_TIMEOUT; + } + +out: + if (actual) + *actual = nbytes; + + return status; +} + +dc_status_t +dc_socket_write (dc_iostream_t *abstract, const void *data, size_t size, size_t *actual) +{ + dc_status_t status = DC_STATUS_SUCCESS; + dc_socket_t *socket = (dc_socket_t *) abstract; + size_t nbytes = 0; + + while (nbytes < size) { + fd_set fds; + FD_ZERO (&fds); + FD_SET (socket->fd, &fds); + + int rc = select (socket->fd + 1, NULL, &fds, NULL, NULL); + if (rc < 0) { + s_errcode_t errcode = S_ERRNO; + if (errcode == S_EINTR) + continue; // Retry. + SYSERROR (abstract->context, errcode); + status = dc_socket_syserror(errcode); + goto out; + } else if (rc == 0) { + break; // Timeout. + } + + s_ssize_t n = send (socket->fd, (const char *) data + nbytes, size - nbytes, 0); + if (n < 0) { + s_errcode_t errcode = S_ERRNO; + if (errcode == S_EINTR || errcode == S_EAGAIN) + continue; // Retry. + SYSERROR (abstract->context, errcode); + status = dc_socket_syserror(errcode); + goto out; + } else if (n == 0) { + break; // EOF. + } + + nbytes += n; + } + + if (nbytes != size) { + status = DC_STATUS_TIMEOUT; + } + +out: + if (actual) + *actual = nbytes; + + return status; +} + +dc_status_t +dc_socket_flush (dc_iostream_t *abstract) +{ + return DC_STATUS_SUCCESS; +} + +dc_status_t +dc_socket_purge (dc_iostream_t *abstract, dc_direction_t direction) +{ + return DC_STATUS_SUCCESS; +} + +dc_status_t +dc_socket_sleep (dc_iostream_t *abstract, unsigned int timeout) +{ + return DC_STATUS_SUCCESS; +} diff --git a/src/socket.h b/src/socket.h new file mode 100644 index 0000000..d612603 --- /dev/null +++ b/src/socket.h @@ -0,0 +1,152 @@ +/* + * libdivecomputer + * + * Copyright (C) 2017 Jef Driesen + * + * This library 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 2.1 of the License, or (at your option) any later version. + * + * This library 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 this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#ifndef DC_SOCKET_H +#define DC_SOCKET_H + +#ifdef _WIN32 +#define NOGDI +#include +#include +#else +#include // errno +#include // close +#include // socket, getsockopt +#include // socket, getsockopt +#include // select +#include // ioctl +#include +#endif + +#include +#include + +#include "iostream-private.h" + +#ifdef _WIN32 +typedef SOCKET s_socket_t; +typedef int s_ssize_t; +typedef DWORD s_errcode_t; +typedef int s_socklen_t; +#define S_ERRNO WSAGetLastError () +#define S_EINTR WSAEINTR +#define S_EAGAIN WSAEWOULDBLOCK +#define S_ENOMEM WSA_NOT_ENOUGH_MEMORY +#define S_EINVAL WSAEINVAL +#define S_EACCES WSAEACCES +#define S_EAFNOSUPPORT WSAEAFNOSUPPORT +#define S_INVALID INVALID_SOCKET +#define S_IOCTL ioctlsocket +#define S_CLOSE closesocket +#else +typedef int s_socket_t; +typedef ssize_t s_ssize_t; +typedef int s_errcode_t; +typedef socklen_t s_socklen_t; +#define S_ERRNO errno +#define S_EINTR EINTR +#define S_EAGAIN EAGAIN +#define S_ENOMEM ENOMEM +#define S_EINVAL EINVAL +#define S_EACCES EACCES +#define S_EAFNOSUPPORT EAFNOSUPPORT +#define S_INVALID -1 +#define S_IOCTL ioctl +#define S_CLOSE close +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef struct dc_socket_t { + dc_iostream_t base; + s_socket_t fd; + int timeout; +} dc_socket_t; + +dc_status_t +dc_socket_syserror (s_errcode_t errcode); + +dc_status_t +dc_socket_init (dc_context_t *context); + +dc_status_t +dc_socket_exit (dc_context_t *context); + +dc_status_t +dc_socket_open (dc_iostream_t *iostream, int family, int type, int protocol); + +dc_status_t +dc_socket_close (dc_iostream_t *iostream); + +dc_status_t +dc_socket_connect (dc_iostream_t *iostream, const struct sockaddr *addr, s_socklen_t addrlen); + +dc_status_t +dc_socket_set_timeout (dc_iostream_t *iostream, int timeout); + +dc_status_t +dc_socket_set_latency (dc_iostream_t *iostream, unsigned int value); + +dc_status_t +dc_socket_set_halfduplex (dc_iostream_t *iostream, unsigned int value); + +dc_status_t +dc_socket_set_break (dc_iostream_t *iostream, unsigned int value); + +dc_status_t +dc_socket_set_dtr (dc_iostream_t *iostream, unsigned int value); + +dc_status_t +dc_socket_set_rts (dc_iostream_t *iostream, unsigned int value); + +dc_status_t +dc_socket_get_lines (dc_iostream_t *iostream, unsigned int *value); + +dc_status_t +dc_socket_get_available (dc_iostream_t *iostream, size_t *value); + +dc_status_t +dc_socket_configure (dc_iostream_t *iostream, unsigned int baudrate, unsigned int databits, dc_parity_t parity, dc_stopbits_t stopbits, dc_flowcontrol_t flowcontrol); + +dc_status_t +dc_socket_read (dc_iostream_t *iostream, void *data, size_t size, size_t *actual); + +dc_status_t +dc_socket_write (dc_iostream_t *iostream, const void *data, size_t size, size_t *actual); + +dc_status_t +dc_socket_flush (dc_iostream_t *iostream); + +dc_status_t +dc_socket_purge (dc_iostream_t *iostream, dc_direction_t direction); + +dc_status_t +dc_socket_sleep (dc_iostream_t *iostream, unsigned int milliseconds); + +dc_status_t +dc_socket_close (dc_iostream_t *iostream); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* DC_SOCKET_H */ diff --git a/src/suunto_d9.c b/src/suunto_d9.c index 6f5b81c..2c92a49 100644 --- a/src/suunto_d9.c +++ b/src/suunto_d9.c @@ -44,7 +44,7 @@ typedef struct suunto_d9_device_t { suunto_common2_device_t base; - dc_serial_t *port; + dc_iostream_t *iostream; } suunto_d9_device_t; static dc_status_t suunto_d9_device_packet (dc_device_t *abstract, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize, unsigned int size); @@ -111,7 +111,7 @@ suunto_d9_device_autodetect (suunto_d9_device_t *device, unsigned int model) unsigned int idx = (hint + i) % C_ARRAY_SIZE(baudrates); // Adjust the baudrate. - status = dc_serial_configure (device->port, baudrates[idx], 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); + status = dc_iostream_configure (device->iostream, baudrates[idx], 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to set the terminal attributes."); return status; @@ -147,41 +147,41 @@ suunto_d9_device_open (dc_device_t **out, dc_context_t *context, const char *nam suunto_common2_device_init (&device->base); // Set the default values. - device->port = NULL; + device->iostream = NULL; // Open the device. - status = dc_serial_open (&device->port, context, name); + status = dc_serial_open (&device->iostream, context, name); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the serial port."); goto error_free; } // Set the serial communication protocol (9600 8N1). - status = dc_serial_configure (device->port, 9600, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); + status = dc_iostream_configure (device->iostream, 9600, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); goto error_close; } // Set the timeout for receiving data (3000 ms). - status = dc_serial_set_timeout (device->port, 3000); + status = dc_iostream_set_timeout (device->iostream, 3000); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the timeout."); goto error_close; } // Set the DTR line (power supply for the interface). - status = dc_serial_set_dtr (device->port, 1); + status = dc_iostream_set_dtr (device->iostream, 1); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the DTR line."); goto error_close; } // Give the interface 100 ms to settle and draw power up. - dc_serial_sleep (device->port, 100); + dc_iostream_sleep (device->iostream, 100); // Make sure everything is in a sane state. - dc_serial_purge (device->port, DC_DIRECTION_ALL); + dc_iostream_purge (device->iostream, DC_DIRECTION_ALL); // Try to autodetect the protocol variant. status = suunto_d9_device_autodetect (device, model); @@ -206,7 +206,7 @@ suunto_d9_device_open (dc_device_t **out, dc_context_t *context, const char *nam return DC_STATUS_SUCCESS; error_close: - dc_serial_close (device->port); + dc_iostream_close (device->iostream); error_free: dc_device_deallocate ((dc_device_t *) device); return status; @@ -221,7 +221,7 @@ suunto_d9_device_close (dc_device_t *abstract) dc_status_t rc = DC_STATUS_SUCCESS; // Close the device. - rc = dc_serial_close (device->port); + rc = dc_iostream_close (device->iostream); if (rc != DC_STATUS_SUCCESS) { dc_status_set_error(&status, rc); } @@ -240,10 +240,10 @@ suunto_d9_device_packet (dc_device_t *abstract, const unsigned char command[], u return DC_STATUS_CANCELLED; // Clear RTS to send the command. - dc_serial_set_rts (device->port, 0); + dc_iostream_set_rts (device->iostream, 0); // Send the command to the dive computer. - status = dc_serial_write (device->port, command, csize, NULL); + status = dc_iostream_write (device->iostream, command, csize, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); return status; @@ -252,7 +252,7 @@ suunto_d9_device_packet (dc_device_t *abstract, const unsigned char command[], u // Receive the echo. unsigned char echo[128] = {0}; assert (sizeof (echo) >= csize); - status = dc_serial_read (device->port, echo, csize, NULL); + status = dc_iostream_read (device->iostream, echo, csize, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the echo."); return status; @@ -265,10 +265,10 @@ suunto_d9_device_packet (dc_device_t *abstract, const unsigned char command[], u } // Set RTS to receive the reply. - dc_serial_set_rts (device->port, 1); + dc_iostream_set_rts (device->iostream, 1); // Receive the answer of the dive computer. - status = dc_serial_read (device->port, answer, asize, NULL); + status = dc_iostream_read (device->iostream, answer, asize, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); return status; diff --git a/src/suunto_d9_parser.c b/src/suunto_d9_parser.c index e8908c5..6566bc9 100644 --- a/src/suunto_d9_parser.c +++ b/src/suunto_d9_parser.c @@ -389,7 +389,7 @@ suunto_d9_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigne *((dc_divemode_t *) value) = DC_DIVEMODE_FREEDIVE; break; case CCR: - *((dc_divemode_t *) value) = DC_DIVEMODE_CC; + *((dc_divemode_t *) value) = DC_DIVEMODE_CCR; break; default: return DC_STATUS_DATAFORMAT; diff --git a/src/suunto_eon.c b/src/suunto_eon.c index 2875654..f41fae6 100644 --- a/src/suunto_eon.c +++ b/src/suunto_eon.c @@ -36,7 +36,7 @@ typedef struct suunto_eon_device_t { suunto_common_device_t base; - dc_serial_t *port; + dc_iostream_t *iostream; } suunto_eon_device_t; static dc_status_t suunto_eon_device_dump (dc_device_t *abstract, dc_buffer_t *buffer); @@ -84,31 +84,31 @@ suunto_eon_device_open (dc_device_t **out, dc_context_t *context, const char *na suunto_common_device_init (&device->base); // Set the default values. - device->port = NULL; + device->iostream = NULL; // Open the device. - status = dc_serial_open (&device->port, context, name); + status = dc_serial_open (&device->iostream, context, name); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the serial port."); goto error_free; } // Set the serial communication protocol (1200 8N2). - status = dc_serial_configure (device->port, 1200, 8, DC_PARITY_NONE, DC_STOPBITS_TWO, DC_FLOWCONTROL_NONE); + status = dc_iostream_configure (device->iostream, 1200, 8, DC_PARITY_NONE, DC_STOPBITS_TWO, DC_FLOWCONTROL_NONE); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); goto error_close; } // Set the timeout for receiving data (1000ms). - status = dc_serial_set_timeout (device->port, 1000); + status = dc_iostream_set_timeout (device->iostream, 1000); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the timeout."); goto error_close; } // Clear the RTS line. - status = dc_serial_set_rts (device->port, 0); + status = dc_iostream_set_rts (device->iostream, 0); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the DTR/RTS line."); goto error_close; @@ -119,7 +119,7 @@ suunto_eon_device_open (dc_device_t **out, dc_context_t *context, const char *na return DC_STATUS_SUCCESS; error_close: - dc_serial_close (device->port); + dc_iostream_close (device->iostream); error_free: dc_device_deallocate ((dc_device_t *) device); return status; @@ -134,7 +134,7 @@ suunto_eon_device_close (dc_device_t *abstract) dc_status_t rc = DC_STATUS_SUCCESS; // Close the device. - rc = dc_serial_close (device->port); + rc = dc_iostream_close (device->iostream); if (rc != DC_STATUS_SUCCESS) { dc_status_set_error(&status, rc); } @@ -163,7 +163,7 @@ suunto_eon_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) // Send the command. unsigned char command[1] = {'P'}; - status = dc_serial_write (device->port, command, sizeof (command), NULL); + status = dc_iostream_write (device->iostream, command, sizeof (command), NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); return status; @@ -178,7 +178,7 @@ suunto_eon_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) // Increase the packet size if more data is immediately available. size_t available = 0; - status = dc_serial_get_available (device->port, &available); + status = dc_iostream_get_available (device->iostream, &available); if (status == DC_STATUS_SUCCESS && available > len) len = available; @@ -187,7 +187,7 @@ suunto_eon_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) len = sizeof(answer) - nbytes; // Read the packet. - status = dc_serial_read (device->port, answer + nbytes, len, NULL); + status = dc_iostream_read (device->iostream, answer + nbytes, len, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); return status; @@ -264,7 +264,7 @@ suunto_eon_device_write_name (dc_device_t *abstract, unsigned char data[], unsig // Send the command. unsigned char command[21] = {'N'}; memcpy (command + 1, data, size); - status = dc_serial_write (device->port, command, sizeof (command), NULL); + status = dc_iostream_write (device->iostream, command, sizeof (command), NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); return status; @@ -285,7 +285,7 @@ suunto_eon_device_write_interval (dc_device_t *abstract, unsigned char interval) // Send the command. unsigned char command[2] = {'T', interval}; - status = dc_serial_write (device->port, command, sizeof (command), NULL); + status = dc_iostream_write (device->iostream, command, sizeof (command), NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); return status; diff --git a/src/suunto_eonsteel_parser.c b/src/suunto_eonsteel_parser.c index 30dd9a4..429e862 100644 --- a/src/suunto_eonsteel_parser.c +++ b/src/suunto_eonsteel_parser.c @@ -1351,7 +1351,7 @@ static int traverse_diving_fields(suunto_eonsteel_parser_t *eon, const struct ty if (!strcmp(name, "DiveMode")) { if (!strncmp((const char *)data, "CCR", 3)) { - eon->cache.divemode = DC_DIVEMODE_CC; + eon->cache.divemode = DC_DIVEMODE_CCR; eon->cache.initialized |= 1 << DC_FIELD_DIVEMODE; } return add_string(eon, "Dive Mode", data); diff --git a/src/suunto_solution.c b/src/suunto_solution.c index cb2481d..2e9e14e 100644 --- a/src/suunto_solution.c +++ b/src/suunto_solution.c @@ -39,7 +39,7 @@ typedef struct suunto_solution_device_t { dc_device_t base; - dc_serial_t *port; + dc_iostream_t *iostream; } suunto_solution_device_t; static dc_status_t suunto_solution_device_dump (dc_device_t *abstract, dc_buffer_t *buffer); @@ -78,31 +78,31 @@ suunto_solution_device_open (dc_device_t **out, dc_context_t *context, const cha } // Set the default values. - device->port = NULL; + device->iostream = NULL; // Open the device. - status = dc_serial_open (&device->port, context, name); + status = dc_serial_open (&device->iostream, context, name); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the serial port."); goto error_free; } // Set the serial communication protocol (1200 8N2). - status = dc_serial_configure (device->port, 1200, 8, DC_PARITY_NONE, DC_STOPBITS_TWO, DC_FLOWCONTROL_NONE); + status = dc_iostream_configure (device->iostream, 1200, 8, DC_PARITY_NONE, DC_STOPBITS_TWO, DC_FLOWCONTROL_NONE); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); goto error_close; } // Set the timeout for receiving data (1000ms). - status = dc_serial_set_timeout (device->port, 1000); + status = dc_iostream_set_timeout (device->iostream, 1000); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the timeout."); goto error_close; } // Clear the RTS line. - status = dc_serial_set_rts (device->port, 0); + status = dc_iostream_set_rts (device->iostream, 0); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the DTR/RTS line."); goto error_close; @@ -113,7 +113,7 @@ suunto_solution_device_open (dc_device_t **out, dc_context_t *context, const cha return DC_STATUS_SUCCESS; error_close: - dc_serial_close (device->port); + dc_iostream_close (device->iostream); error_free: dc_device_deallocate ((dc_device_t *) device); return status; @@ -128,7 +128,7 @@ suunto_solution_device_close (dc_device_t *abstract) dc_status_t rc = DC_STATUS_SUCCESS; // Close the device. - rc = dc_serial_close (device->port); + rc = dc_iostream_close (device->iostream); if (rc != DC_STATUS_SUCCESS) { dc_status_set_error(&status, rc); } @@ -161,14 +161,14 @@ suunto_solution_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) unsigned char answer[3] = {0}; // Assert DTR - dc_serial_set_dtr (device->port, 1); + dc_iostream_set_dtr (device->iostream, 1); // Send: 0xFF command[0] = 0xFF; - dc_serial_write (device->port, command, 1, NULL); + dc_iostream_write (device->iostream, command, 1, NULL); // Receive: 0x3F - status = dc_serial_read (device->port, answer, 1, NULL); + status = dc_iostream_read (device->iostream, answer, 1, NULL); if (status != DC_STATUS_SUCCESS) return status; if (answer[0] != 0x3F) @@ -178,7 +178,7 @@ suunto_solution_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) command[0] = 0x4D; command[1] = 0x01; command[2] = 0x01; - dc_serial_write (device->port, command, 3, NULL); + dc_iostream_write (device->iostream, command, 3, NULL); // Update and emit a progress event. progress.current += 1; @@ -187,7 +187,7 @@ suunto_solution_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) data[0] = 0x00; for (unsigned int i = 1; i < SZ_MEMORY; ++i) { // Receive: 0x01, i, data[i] - status = dc_serial_read (device->port, answer, 3, NULL); + status = dc_iostream_read (device->iostream, answer, 3, NULL); if (status != DC_STATUS_SUCCESS) return status; if (answer[0] != 0x01 || answer[1] != i) @@ -195,10 +195,10 @@ suunto_solution_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) // Send: i command[0] = i; - dc_serial_write (device->port, command, 1, NULL); + dc_iostream_write (device->iostream, command, 1, NULL); // Receive: data[i] - status = dc_serial_read (device->port, data + i, 1, NULL); + status = dc_iostream_read (device->iostream, data + i, 1, NULL); if (status != DC_STATUS_SUCCESS) return status; if (data[i] != answer[2]) @@ -206,7 +206,7 @@ suunto_solution_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) // Send: 0x0D command[0] = 0x0D; - dc_serial_write (device->port, command, 1, NULL); + dc_iostream_write (device->iostream, command, 1, NULL); // Update and emit a progress event. progress.current += 1; @@ -214,7 +214,7 @@ suunto_solution_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) } // Receive: 0x02, 0x00, 0x80 - status = dc_serial_read (device->port, answer, 3, NULL); + status = dc_iostream_read (device->iostream, answer, 3, NULL); if (status != DC_STATUS_SUCCESS) return status; if (answer[0] != 0x02 || answer[1] != 0x00 || answer[2] != 0x80) @@ -222,10 +222,10 @@ suunto_solution_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) // Send: 0x80 command[0] = 0x80; - dc_serial_write (device->port, command, 1, NULL); + dc_iostream_write (device->iostream, command, 1, NULL); // Receive: 0x80 - status = dc_serial_read (device->port, answer, 1, NULL); + status = dc_iostream_read (device->iostream, answer, 1, NULL); if (status != DC_STATUS_SUCCESS) return status; if (answer[0] != 0x80) @@ -233,10 +233,10 @@ suunto_solution_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) // Send: 0x20 command[0] = 0x20; - dc_serial_write (device->port, command, 1, NULL); + dc_iostream_write (device->iostream, command, 1, NULL); // Receive: 0x3F - status = dc_serial_read (device->port, answer, 1, NULL); + status = dc_iostream_read (device->iostream, answer, 1, NULL); if (status != DC_STATUS_SUCCESS) return status; if (answer[0] != 0x3F) diff --git a/src/suunto_vyper.c b/src/suunto_vyper.c index 33657dc..ba5ad20 100644 --- a/src/suunto_vyper.c +++ b/src/suunto_vyper.c @@ -46,7 +46,7 @@ typedef struct suunto_vyper_device_t { suunto_common_device_t base; - dc_serial_t *port; + dc_iostream_t *iostream; } suunto_vyper_device_t; static dc_status_t suunto_vyper_device_read (dc_device_t *abstract, unsigned int address, unsigned char data[], unsigned int size); @@ -104,48 +104,48 @@ suunto_vyper_device_open (dc_device_t **out, dc_context_t *context, const char * suunto_common_device_init (&device->base); // Set the default values. - device->port = NULL; + device->iostream = NULL; // Open the device. - status = dc_serial_open (&device->port, context, name); + status = dc_serial_open (&device->iostream, context, name); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the serial port."); goto error_free; } // Set the serial communication protocol (2400 8O1). - status = dc_serial_configure (device->port, 2400, 8, DC_PARITY_ODD, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); + status = dc_iostream_configure (device->iostream, 2400, 8, DC_PARITY_ODD, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); goto error_close; } // Set the timeout for receiving data (1000 ms). - status = dc_serial_set_timeout (device->port, 1000); + status = dc_iostream_set_timeout (device->iostream, 1000); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the timeout."); goto error_close; } // Set the DTR line (power supply for the interface). - status = dc_serial_set_dtr (device->port, 1); + status = dc_iostream_set_dtr (device->iostream, 1); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the DTR line."); goto error_close; } // Give the interface 100 ms to settle and draw power up. - dc_serial_sleep (device->port, 100); + dc_iostream_sleep (device->iostream, 100); // Make sure everything is in a sane state. - dc_serial_purge (device->port, DC_DIRECTION_ALL); + dc_iostream_purge (device->iostream, DC_DIRECTION_ALL); *out = (dc_device_t*) device; return DC_STATUS_SUCCESS; error_close: - dc_serial_close (device->port); + dc_iostream_close (device->iostream); error_free: dc_device_deallocate ((dc_device_t *) device); return status; @@ -160,7 +160,7 @@ suunto_vyper_device_close (dc_device_t *abstract) dc_status_t rc = DC_STATUS_SUCCESS; // Close the device. - rc = dc_serial_close (device->port); + rc = dc_iostream_close (device->iostream); if (rc != DC_STATUS_SUCCESS) { dc_status_set_error(&status, rc); } @@ -175,13 +175,13 @@ suunto_vyper_send (suunto_vyper_device_t *device, const unsigned char command[], dc_status_t status = DC_STATUS_SUCCESS; dc_device_t *abstract = (dc_device_t *) device; - dc_serial_sleep (device->port, 500); + dc_iostream_sleep (device->iostream, 500); // Set RTS to send the command. - dc_serial_set_rts (device->port, 1); + dc_iostream_set_rts (device->iostream, 1); // Send the command to the dive computer. - status = dc_serial_write (device->port, command, csize, NULL); + status = dc_iostream_write (device->iostream, command, csize, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); return status; @@ -198,11 +198,11 @@ suunto_vyper_send (suunto_vyper_device_t *device, const unsigned char command[], // receive the reply before RTS is cleared. We have to wait some time // before clearing RTS (around 30ms). But if we wait too long (> 500ms), // the reply disappears again. - dc_serial_sleep (device->port, 200); - dc_serial_purge (device->port, DC_DIRECTION_INPUT); + dc_iostream_sleep (device->iostream, 200); + dc_iostream_purge (device->iostream, DC_DIRECTION_INPUT); // Clear RTS to receive the reply. - dc_serial_set_rts (device->port, 0); + dc_iostream_set_rts (device->iostream, 0); return DC_STATUS_SUCCESS; } @@ -227,7 +227,7 @@ suunto_vyper_transfer (suunto_vyper_device_t *device, const unsigned char comman } // Receive the answer of the dive computer. - status = dc_serial_read (device->port, answer, asize, NULL); + status = dc_iostream_read (device->iostream, answer, asize, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); return status; @@ -352,7 +352,7 @@ suunto_vyper_read_dive (dc_device_t *abstract, dc_buffer_t *buffer, int init, dc // Receive the header of the package. size_t n = 0; unsigned char answer[SZ_PACKET + 3] = {0}; - status = dc_serial_read (device->port, answer, 2, &n); + status = dc_iostream_read (device->iostream, answer, 2, &n); if (status != DC_STATUS_SUCCESS) { // If no data is received because a timeout occured, we assume // the last package was already received and the transmission @@ -377,7 +377,7 @@ suunto_vyper_read_dive (dc_device_t *abstract, dc_buffer_t *buffer, int init, dc // Receive the remaining part of the package. unsigned char len = answer[1]; - status = dc_serial_read (device->port, answer + 2, len + 1, NULL); + status = dc_iostream_read (device->iostream, answer + 2, len + 1, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); return status; diff --git a/src/suunto_vyper2.c b/src/suunto_vyper2.c index 618ee4a..6ddd3d7 100644 --- a/src/suunto_vyper2.c +++ b/src/suunto_vyper2.c @@ -35,7 +35,7 @@ typedef struct suunto_vyper2_device_t { suunto_common2_device_t base; - dc_serial_t *port; + dc_iostream_t *iostream; } suunto_vyper2_device_t; static dc_status_t suunto_vyper2_device_packet (dc_device_t *abstract, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize, unsigned int size); @@ -93,44 +93,44 @@ suunto_vyper2_device_open (dc_device_t **out, dc_context_t *context, const char suunto_common2_device_init (&device->base); // Set the default values. - device->port = NULL; + device->iostream = NULL; // Open the device. - status = dc_serial_open (&device->port, context, name); + status = dc_serial_open (&device->iostream, context, name); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the serial port."); goto error_free; } // Set the serial communication protocol (9600 8N1). - status = dc_serial_configure (device->port, 9600, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); + status = dc_iostream_configure (device->iostream, 9600, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); goto error_close; } // Set the timeout for receiving data (3000 ms). - status = dc_serial_set_timeout (device->port, 3000); + status = dc_iostream_set_timeout (device->iostream, 3000); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the timeout."); goto error_close; } // Set the DTR line (power supply for the interface). - status = dc_serial_set_dtr (device->port, 1); + status = dc_iostream_set_dtr (device->iostream, 1); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the DTR line."); goto error_close; } // Give the interface 100 ms to settle and draw power up. - dc_serial_sleep (device->port, 100); + dc_iostream_sleep (device->iostream, 100); // Make sure everything is in a sane state. - dc_serial_purge (device->port, DC_DIRECTION_ALL); + dc_iostream_purge (device->iostream, DC_DIRECTION_ALL); // Enable half-duplex emulation. - dc_serial_set_halfduplex (device->port, 1); + dc_iostream_set_halfduplex (device->iostream, 1); // Read the version info. status = suunto_common2_device_version ((dc_device_t *) device, device->base.version, sizeof (device->base.version)); @@ -151,7 +151,7 @@ suunto_vyper2_device_open (dc_device_t **out, dc_context_t *context, const char return DC_STATUS_SUCCESS; error_close: - dc_serial_close (device->port); + dc_iostream_close (device->iostream); error_free: dc_device_deallocate ((dc_device_t *) device); return status; @@ -166,7 +166,7 @@ suunto_vyper2_device_close (dc_device_t *abstract) dc_status_t rc = DC_STATUS_SUCCESS; // Close the device. - rc = dc_serial_close (device->port); + rc = dc_iostream_close (device->iostream); if (rc != DC_STATUS_SUCCESS) { dc_status_set_error(&status, rc); } @@ -184,23 +184,23 @@ suunto_vyper2_device_packet (dc_device_t *abstract, const unsigned char command[ if (device_is_cancelled (abstract)) return DC_STATUS_CANCELLED; - dc_serial_sleep (device->port, 600); + dc_iostream_sleep (device->iostream, 600); // Set RTS to send the command. - dc_serial_set_rts (device->port, 1); + dc_iostream_set_rts (device->iostream, 1); // Send the command to the dive computer. - status = dc_serial_write (device->port, command, csize, NULL); + status = dc_iostream_write (device->iostream, command, csize, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); return status; } // Clear RTS to receive the reply. - dc_serial_set_rts (device->port, 0); + dc_iostream_set_rts (device->iostream, 0); // Receive the answer of the dive computer. - status = dc_serial_read (device->port, answer, asize, NULL); + status = dc_iostream_read (device->iostream, answer, asize, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); return status; diff --git a/src/usbhid.c b/src/usbhid.c index 1b0931f..f3eb4bc 100644 --- a/src/usbhid.c +++ b/src/usbhid.c @@ -50,8 +50,10 @@ #endif #include "usbhid.h" + #include "common-private.h" #include "context-private.h" +#include "iostream-private.h" #include "platform.h" #ifdef _WIN32 @@ -62,9 +64,17 @@ typedef pthread_mutex_t dc_mutex_t; #define DC_MUTEX_INIT PTHREAD_MUTEX_INITIALIZER #endif -struct dc_usbhid_t { - /* Library context. */ - dc_context_t *context; +#define ISINSTANCE(device) dc_iostream_isinstance((device), &dc_usbhid_vtable) + +#ifdef USBHID +static dc_status_t dc_usbhid_set_timeout (dc_iostream_t *iostream, int timeout); +static dc_status_t dc_usbhid_read (dc_iostream_t *iostream, void *data, size_t size, size_t *actual); +static dc_status_t dc_usbhid_write (dc_iostream_t *iostream, const void *data, size_t size, size_t *actual); +static dc_status_t dc_usbhid_close (dc_iostream_t *iostream); + +typedef struct dc_usbhid_t { + /* Base class. */ + dc_iostream_t base; /* Internal state. */ #if defined(USE_LIBUSB) libusb_device_handle *handle; @@ -76,6 +86,25 @@ struct dc_usbhid_t { hid_device *handle; int timeout; #endif +} dc_usbhid_t; + +static const dc_iostream_vtable_t dc_usbhid_vtable = { + sizeof(dc_usbhid_t), + dc_usbhid_set_timeout, /* set_timeout */ + NULL, /* set_latency */ + NULL, /* set_halfduplex */ + NULL, /* set_break */ + NULL, /* set_dtr */ + NULL, /* set_rts */ + NULL, /* get_lines */ + NULL, /* get_received */ + NULL, /* configure */ + dc_usbhid_read, /* read */ + dc_usbhid_write, /* write */ + NULL, /* flush */ + NULL, /* purge */ + NULL, /* sleep */ + dc_usbhid_close, /* close */ }; #if defined(USE_LIBUSB) @@ -100,18 +129,19 @@ syserror(int errcode) } } #endif +#endif static dc_status_t usbhid_packet_close(dc_custom_io_t *io) { - dc_usbhid_t *usbhid = (dc_usbhid_t *)io->userdata; + dc_iostream_t *usbhid = (dc_iostream_t *)io->userdata; return dc_usbhid_close(usbhid); } static dc_status_t usbhid_packet_read(dc_custom_io_t *io, void* data, size_t size, size_t *actual) { - dc_usbhid_t *usbhid = (dc_usbhid_t *)io->userdata; + dc_iostream_t *usbhid = (dc_iostream_t *)io->userdata; return dc_usbhid_read(usbhid, data, size, actual); } @@ -132,14 +162,14 @@ usbhid_packet_read(dc_custom_io_t *io, void* data, size_t size, size_t *actual) static dc_status_t usbhid_packet_write(dc_custom_io_t *io, const void* data, size_t size, size_t *actual) { - dc_usbhid_t *usbhid = (dc_usbhid_t *)io->userdata; + dc_iostream_t *usbhid = (dc_iostream_t *)io->userdata; return dc_usbhid_write(usbhid, data, size, actual); } dc_status_t dc_usbhid_custom_io (dc_context_t *context, unsigned int vid, unsigned int pid) { - dc_usbhid_t *usbhid; + dc_iostream_t *usbhid; dc_status_t status; static dc_custom_io_t custom = { @@ -259,7 +289,7 @@ dc_usbhid_exit (void) #endif dc_status_t -dc_usbhid_open (dc_usbhid_t **out, dc_context_t *context, unsigned int vid, unsigned int pid) +dc_usbhid_open (dc_iostream_t **out, dc_context_t *context, unsigned int vid, unsigned int pid) { #ifdef USBHID dc_status_t status = DC_STATUS_SUCCESS; @@ -271,15 +301,12 @@ dc_usbhid_open (dc_usbhid_t **out, dc_context_t *context, unsigned int vid, unsi INFO (context, "Open: vid=%04x, pid=%04x", vid, pid); // Allocate memory. - usbhid = (dc_usbhid_t *) malloc (sizeof (dc_usbhid_t)); + usbhid = (dc_usbhid_t *) dc_iostream_allocate (context, &dc_usbhid_vtable); if (usbhid == NULL) { ERROR (context, "Out of memory."); return DC_STATUS_NOMEMORY; } - // Library context. - usbhid->context = context; - // Initialize the usb library. status = dc_usbhid_init (context); if (status != DC_STATUS_SUCCESS) { @@ -422,7 +449,7 @@ dc_usbhid_open (dc_usbhid_t **out, dc_context_t *context, unsigned int vid, unsi usbhid->timeout = -1; #endif - *out = usbhid; + *out = (dc_iostream_t *) usbhid; return DC_STATUS_SUCCESS; @@ -437,21 +464,19 @@ error_usb_free_list: error_usb_exit: dc_usbhid_exit (); error_free: - free (usbhid); + dc_iostream_deallocate ((dc_iostream_t *) usbhid); return status; #else return DC_STATUS_UNSUPPORTED; #endif } -dc_status_t -dc_usbhid_close (dc_usbhid_t *usbhid) -{ #ifdef USBHID +static dc_status_t +dc_usbhid_close (dc_iostream_t *abstract) +{ dc_status_t status = DC_STATUS_SUCCESS; - - if (usbhid == NULL) - return DC_STATUS_SUCCESS; + dc_usbhid_t *usbhid = (dc_usbhid_t *) abstract; #if defined(USE_LIBUSB) libusb_release_interface (usbhid->handle, usbhid->interface); @@ -460,22 +485,14 @@ dc_usbhid_close (dc_usbhid_t *usbhid) hid_close(usbhid->handle); #endif dc_usbhid_exit(); - free (usbhid); return status; -#else - return DC_STATUS_UNSUPPORTED; -#endif } -dc_status_t -dc_usbhid_set_timeout (dc_usbhid_t *usbhid, int timeout) +static dc_status_t +dc_usbhid_set_timeout (dc_iostream_t *abstract, int timeout) { -#ifdef USBHID - if (usbhid == NULL) - return DC_STATUS_INVALIDARGS; - - INFO (usbhid->context, "Timeout: value=%i", timeout); + dc_usbhid_t *usbhid = (dc_usbhid_t *) abstract; #if defined(USE_LIBUSB) if (timeout < 0) { @@ -494,27 +511,19 @@ dc_usbhid_set_timeout (dc_usbhid_t *usbhid, int timeout) #endif return DC_STATUS_SUCCESS; -#else - return DC_STATUS_UNSUPPORTED; -#endif } -dc_status_t -dc_usbhid_read (dc_usbhid_t *usbhid, void *data, size_t size, size_t *actual) +static dc_status_t +dc_usbhid_read (dc_iostream_t *abstract, void *data, size_t size, size_t *actual) { -#ifdef USBHID dc_status_t status = DC_STATUS_SUCCESS; + dc_usbhid_t *usbhid = (dc_usbhid_t *) abstract; int nbytes = 0; - if (usbhid == NULL) { - status = DC_STATUS_INVALIDARGS; - goto out_invalidargs; - } - #if defined(USE_LIBUSB) int rc = libusb_interrupt_transfer (usbhid->handle, usbhid->endpoint_in, data, size, &nbytes, usbhid->timeout); if (rc != LIBUSB_SUCCESS) { - ERROR (usbhid->context, "Usb read interrupt transfer failed (%s).", + ERROR (abstract->context, "Usb read interrupt transfer failed (%s).", libusb_error_name (rc)); status = syserror (rc); goto out; @@ -522,7 +531,7 @@ dc_usbhid_read (dc_usbhid_t *usbhid, void *data, size_t size, size_t *actual) #elif defined(USE_HIDAPI) nbytes = hid_read_timeout(usbhid->handle, data, size, usbhid->timeout); if (nbytes < 0) { - ERROR (usbhid->context, "Usb read interrupt transfer failed."); + ERROR (abstract->context, "Usb read interrupt transfer failed."); status = DC_STATUS_IO; nbytes = 0; goto out; @@ -530,30 +539,19 @@ dc_usbhid_read (dc_usbhid_t *usbhid, void *data, size_t size, size_t *actual) #endif out: - HEXDUMP (usbhid->context, DC_LOGLEVEL_INFO, "Read", (unsigned char *) data, nbytes); - -out_invalidargs: if (actual) *actual = nbytes; return status; -#else - return DC_STATUS_UNSUPPORTED; -#endif } -dc_status_t -dc_usbhid_write (dc_usbhid_t *usbhid, const void *data, size_t size, size_t *actual) +static dc_status_t +dc_usbhid_write (dc_iostream_t *abstract, const void *data, size_t size, size_t *actual) { -#ifdef USBHID dc_status_t status = DC_STATUS_SUCCESS; + dc_usbhid_t *usbhid = (dc_usbhid_t *) abstract; int nbytes = 0; - if (usbhid == NULL) { - status = DC_STATUS_INVALIDARGS; - goto out_invalidargs; - } - if (size == 0) { goto out; } @@ -571,7 +569,7 @@ dc_usbhid_write (dc_usbhid_t *usbhid, const void *data, size_t size, size_t *act int rc = libusb_interrupt_transfer (usbhid->handle, usbhid->endpoint_out, (void *) buffer, length, &nbytes, 0); if (rc != LIBUSB_SUCCESS) { - ERROR (usbhid->context, "Usb write interrupt transfer failed (%s).", + ERROR (abstract->context, "Usb write interrupt transfer failed (%s).", libusb_error_name (rc)); status = syserror (rc); goto out; @@ -583,7 +581,7 @@ dc_usbhid_write (dc_usbhid_t *usbhid, const void *data, size_t size, size_t *act #elif defined(USE_HIDAPI) nbytes = hid_write(usbhid->handle, data, size); if (nbytes < 0) { - ERROR (usbhid->context, "Usb write interrupt transfer failed."); + ERROR (abstract->context, "Usb write interrupt transfer failed."); status = DC_STATUS_IO; nbytes = 0; goto out; @@ -593,19 +591,14 @@ dc_usbhid_write (dc_usbhid_t *usbhid, const void *data, size_t size, size_t *act out: #ifdef _WIN32 if (nbytes > size) { - WARNING (usbhid->context, "Number of bytes exceeds the buffer size (" DC_PRINTF_SIZE " > " DC_PRINTF_SIZE ")!", nbytes, size); + WARNING (abstract->context, "Number of bytes exceeds the buffer size (" DC_PRINTF_SIZE " > " DC_PRINTF_SIZE ")!", nbytes, size); nbytes = size; } #endif - HEXDUMP (usbhid->context, DC_LOGLEVEL_INFO, "Write", (const unsigned char *) data, nbytes); - -out_invalidargs: if (actual) *actual = nbytes; return status; -#else - return DC_STATUS_UNSUPPORTED; -#endif } +#endif diff --git a/src/usbhid.h b/src/usbhid.h index bb95a98..0b381da 100644 --- a/src/usbhid.h +++ b/src/usbhid.h @@ -24,20 +24,16 @@ #include #include +#include #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ -/** - * Opaque object representing a USB HID connection. - */ -typedef struct dc_usbhid_t dc_usbhid_t; - /** * Open a USB HID connection. * - * @param[out] usbhid A location to store the USB HID connection. + * @param[out] iostream A location to store the USB HID connection. * @param[in] context A valid context object. * @param[in] vid The USB Vendor ID of the device. * @param[in] pid The USB Product ID of the device. @@ -45,76 +41,7 @@ typedef struct dc_usbhid_t dc_usbhid_t; * on failure. */ dc_status_t -dc_usbhid_open (dc_usbhid_t **usbhid, dc_context_t *context, unsigned int vid, unsigned int pid); - -/** - * Close the connection and free all resources. - * - * @param[in] usbhid A valid USB HID connection. - * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code - * on failure. - */ -dc_status_t -dc_usbhid_close (dc_usbhid_t *usbhid); - -/** - * Set the read timeout. - * - * There are three distinct modes available: - * - * 1. Blocking (timeout < 0): - * - * The read operation is blocked until all the requested bytes have - * been received. If the requested number of bytes does not arrive, - * the operation will block forever. - * - * 2. Non-blocking (timeout == 0): - * - * The read operation returns immediately with the bytes that have - * already been received, even if no bytes have been received. - * - * 3. Timeout (timeout > 0): - * - * The read operation is blocked until all the requested bytes have - * been received. If the requested number of bytes does not arrive - * within the specified amount of time, the operation will return - * with the bytes that have already been received. - * - * @param[in] usbhid A valid USB HID connection. - * @param[in] timeout The timeout in milliseconds. - * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code - * on failure. - */ -dc_status_t -dc_usbhid_set_timeout (dc_usbhid_t *usbhid, int timeout); - -/** - * Read data from the USB HID connection. - * - * @param[in] usbhid A valid USB HID connection. - * @param[out] data The memory buffer to read the data into. - * @param[in] size The number of bytes to read. - * @param[out] actual An (optional) location to store the actual - * number of bytes transferred. - * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code - * on failure. - */ -dc_status_t -dc_usbhid_read (dc_usbhid_t *usbhid, void *data, size_t size, size_t *actual); - -/** - * Write data to the USB HID connection. - * - * @param[in] usbhid A valid USB HID connection. - * @param[in] data The memory buffer to write the data from. - * @param[in] size The number of bytes to write. - * @param[out] actual An (optional) location to store the actual - * number of bytes transferred. - * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code - * on failure. - */ -dc_status_t -dc_usbhid_write (dc_usbhid_t *usbhid, const void *data, size_t size, size_t *actual); +dc_usbhid_open (dc_iostream_t **iostream, dc_context_t *context, unsigned int vid, unsigned int pid); /* Create a dc_custom_io_t that uses usbhid for packet transfer */ dc_status_t diff --git a/src/uwatec_aladin.c b/src/uwatec_aladin.c index 25c9208..dc697c2 100644 --- a/src/uwatec_aladin.c +++ b/src/uwatec_aladin.c @@ -43,7 +43,7 @@ typedef struct uwatec_aladin_device_t { dc_device_t base; - dc_serial_t *port; + dc_iostream_t *iostream; unsigned int timestamp; unsigned int devtime; dc_ticks_t systime; @@ -86,41 +86,41 @@ uwatec_aladin_device_open (dc_device_t **out, dc_context_t *context, const char } // Set the default values. - device->port = NULL; + device->iostream = NULL; device->timestamp = 0; device->systime = (dc_ticks_t) -1; device->devtime = 0; // Open the device. - status = dc_serial_open (&device->port, context, name); + status = dc_serial_open (&device->iostream, context, name); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the serial port."); goto error_free; } // Set the serial communication protocol (19200 8N1). - status = dc_serial_configure (device->port, 19200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); + status = dc_iostream_configure (device->iostream, 19200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); goto error_close; } // Set the timeout for receiving data (INFINITE). - status = dc_serial_set_timeout (device->port, -1); + status = dc_iostream_set_timeout (device->iostream, -1); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the timeout."); goto error_close; } // Set the DTR line. - status = dc_serial_set_dtr (device->port, 1); + status = dc_iostream_set_dtr (device->iostream, 1); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the DTR line."); goto error_close; } // Clear the RTS line. - status = dc_serial_set_rts (device->port, 0); + status = dc_iostream_set_rts (device->iostream, 0); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to clear the RTS line."); goto error_close; @@ -131,7 +131,7 @@ uwatec_aladin_device_open (dc_device_t **out, dc_context_t *context, const char return DC_STATUS_SUCCESS; error_close: - dc_serial_close (device->port); + dc_iostream_close (device->iostream); error_free: dc_device_deallocate ((dc_device_t *) device); return status; @@ -146,7 +146,7 @@ uwatec_aladin_device_close (dc_device_t *abstract) dc_status_t rc = DC_STATUS_SUCCESS; // Close the device. - rc = dc_serial_close (device->port); + rc = dc_iostream_close (device->iostream); if (rc != DC_STATUS_SUCCESS) { dc_status_set_error(&status, rc); } @@ -197,7 +197,7 @@ uwatec_aladin_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) if (device_is_cancelled (abstract)) return DC_STATUS_CANCELLED; - status = dc_serial_read (device->port, answer + i, 1, NULL); + status = dc_iostream_read (device->iostream, answer + i, 1, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); return status; @@ -218,7 +218,7 @@ uwatec_aladin_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) device_event_emit (abstract, DC_EVENT_PROGRESS, &progress); // Receive the remaining part of the package. - status = dc_serial_read (device->port, answer + 4, sizeof (answer) - 4, NULL); + status = dc_iostream_read (device->iostream, answer + 4, sizeof (answer) - 4, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Unexpected EOF in answer."); return status; diff --git a/src/uwatec_memomouse.c b/src/uwatec_memomouse.c index 2f93067..90466a0 100644 --- a/src/uwatec_memomouse.c +++ b/src/uwatec_memomouse.c @@ -39,7 +39,7 @@ typedef struct uwatec_memomouse_device_t { dc_device_t base; - dc_serial_t *port; + dc_iostream_t *iostream; unsigned int timestamp; unsigned int devtime; dc_ticks_t systime; @@ -82,55 +82,55 @@ uwatec_memomouse_device_open (dc_device_t **out, dc_context_t *context, const ch } // Set the default values. - device->port = NULL; + device->iostream = NULL; device->timestamp = 0; device->systime = (dc_ticks_t) -1; device->devtime = 0; // Open the device. - status = dc_serial_open (&device->port, context, name); + status = dc_serial_open (&device->iostream, context, name); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the serial port."); goto error_free; } // Set the serial communication protocol (9600 8N1). - status = dc_serial_configure (device->port, 9600, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); + status = dc_iostream_configure (device->iostream, 9600, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); goto error_close; } // Set the timeout for receiving data (1000 ms). - status = dc_serial_set_timeout (device->port, 1000); + status = dc_iostream_set_timeout (device->iostream, 1000); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the timeout."); goto error_close; } // Clear the DTR line. - status = dc_serial_set_dtr (device->port, 0); + status = dc_iostream_set_dtr (device->iostream, 0); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to clear the DTR line."); goto error_close; } // Clear the RTS line. - status = dc_serial_set_rts (device->port, 0); + status = dc_iostream_set_rts (device->iostream, 0); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to clear the RTS line."); goto error_close; } // Make sure everything is in a sane state. - dc_serial_purge (device->port, DC_DIRECTION_ALL); + dc_iostream_purge (device->iostream, DC_DIRECTION_ALL); *out = (dc_device_t*) device; return DC_STATUS_SUCCESS; error_close: - dc_serial_close (device->port); + dc_iostream_close (device->iostream); error_free: dc_device_deallocate ((dc_device_t *) device); return status; @@ -145,7 +145,7 @@ uwatec_memomouse_device_close (dc_device_t *abstract) dc_status_t rc = DC_STATUS_SUCCESS; // Close the device. - rc = dc_serial_close (device->port); + rc = dc_iostream_close (device->iostream); if (rc != DC_STATUS_SUCCESS) { dc_status_set_error(&status, rc); } @@ -180,7 +180,7 @@ uwatec_memomouse_read_packet (uwatec_memomouse_device_t *device, unsigned char d assert (result != NULL); // Receive the header of the package. - status = dc_serial_read (device->port, data, 1, NULL); + status = dc_iostream_read (device->iostream, data, 1, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); return status; @@ -197,7 +197,7 @@ uwatec_memomouse_read_packet (uwatec_memomouse_device_t *device, unsigned char d } // Receive the remaining part of the package. - status = dc_serial_read (device->port, data + 1, len + 1, NULL); + status = dc_iostream_read (device->iostream, data + 1, len + 1, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); return status; @@ -234,11 +234,11 @@ uwatec_memomouse_read_packet_outer (uwatec_memomouse_device_t *device, unsigned return rc; // Flush the input buffer. - dc_serial_purge (device->port, DC_DIRECTION_INPUT); + dc_iostream_purge (device->iostream, DC_DIRECTION_INPUT); // Reject the packet. unsigned char value = NAK; - status = dc_serial_write (device->port, &value, 1, NULL); + status = dc_iostream_write (device->iostream, &value, 1, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to reject the packet."); return status; @@ -277,7 +277,7 @@ uwatec_memomouse_read_packet_inner (uwatec_memomouse_device_t *device, dc_buffer // Accept the packet. unsigned char value = ACK; - status = dc_serial_write (device->port, &value, 1, NULL); + status = dc_iostream_write (device->iostream, &value, 1, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to accept the packet."); return status; @@ -344,22 +344,22 @@ uwatec_memomouse_dump_internal (uwatec_memomouse_device_t *device, dc_buffer_t * device_event_emit (&device->base, DC_EVENT_PROGRESS, &progress); // Waiting for greeting message. - while (dc_serial_get_available (device->port, &available) == DC_STATUS_SUCCESS && available == 0) { + while (dc_iostream_get_available (device->iostream, &available) == DC_STATUS_SUCCESS && available == 0) { if (device_is_cancelled (abstract)) return DC_STATUS_CANCELLED; // Flush the input buffer. - dc_serial_purge (device->port, DC_DIRECTION_INPUT); + dc_iostream_purge (device->iostream, DC_DIRECTION_INPUT); // Reject the packet. unsigned char value = NAK; - status = dc_serial_write (device->port, &value, 1, NULL); + status = dc_iostream_write (device->iostream, &value, 1, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to reject the packet."); return status; } - dc_serial_sleep (device->port, 300); + dc_iostream_sleep (device->iostream, 300); } // Read the ID string. @@ -382,24 +382,24 @@ uwatec_memomouse_dump_internal (uwatec_memomouse_device_t *device, dc_buffer_t * // Wait a small amount of time before sending the command. // Without this delay, the transfer will fail most of the time. - dc_serial_sleep (device->port, 50); + dc_iostream_sleep (device->iostream, 50); // Keep send the command to the device, // until the ACK answer is received. unsigned char answer = NAK; while (answer == NAK) { // Flush the input buffer. - dc_serial_purge (device->port, DC_DIRECTION_INPUT); + dc_iostream_purge (device->iostream, DC_DIRECTION_INPUT); // Send the command to the device. - status = dc_serial_write (device->port, command, sizeof (command), NULL); + status = dc_iostream_write (device->iostream, command, sizeof (command), NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); return status; } // Wait for the answer (ACK). - status = dc_serial_read (device->port, &answer, 1, NULL); + status = dc_iostream_read (device->iostream, &answer, 1, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); return status; @@ -413,12 +413,12 @@ uwatec_memomouse_dump_internal (uwatec_memomouse_device_t *device, dc_buffer_t * } // Wait for the data packet. - while (dc_serial_get_available (device->port, &available) == DC_STATUS_SUCCESS && available == 0) { + while (dc_iostream_get_available (device->iostream, &available) == DC_STATUS_SUCCESS && available == 0) { if (device_is_cancelled (abstract)) return DC_STATUS_CANCELLED; device_event_emit (&device->base, DC_EVENT_WAITING, NULL); - dc_serial_sleep (device->port, 100); + dc_iostream_sleep (device->iostream, 100); } // Fetch the current system time. @@ -458,10 +458,10 @@ uwatec_memomouse_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) // Give the interface some time to notice the DTR // line change from a previous transfer (if any). - dc_serial_sleep (device->port, 500); + dc_iostream_sleep (device->iostream, 500); // Set the DTR line. - rc = dc_serial_set_dtr (device->port, 1); + rc = dc_iostream_set_dtr (device->iostream, 1); if (rc != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to set the RTS line."); return rc; @@ -471,7 +471,7 @@ uwatec_memomouse_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) status = uwatec_memomouse_dump_internal (device, buffer); // Clear the DTR line again. - rc = dc_serial_set_dtr (device->port, 0); + rc = dc_iostream_set_dtr (device->iostream, 0); if (rc != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to set the RTS line."); return rc; diff --git a/src/uwatec_meridian.c b/src/uwatec_meridian.c index c32f3bc..5844c29 100644 --- a/src/uwatec_meridian.c +++ b/src/uwatec_meridian.c @@ -37,7 +37,7 @@ typedef struct uwatec_meridian_device_t { dc_device_t base; - dc_serial_t *port; + dc_iostream_t *iostream; unsigned int timestamp; unsigned int devtime; dc_ticks_t systime; @@ -83,7 +83,7 @@ uwatec_meridian_transfer (uwatec_meridian_device_t *device, const unsigned char packet[11 + csize] = checksum_xor_uint8 (packet + 7, csize + 4, 0x00); // Send the packet. - status = dc_serial_write (device->port, packet, csize + 12, NULL); + status = dc_iostream_write (device->iostream, packet, csize + 12, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); return status; @@ -91,7 +91,7 @@ uwatec_meridian_transfer (uwatec_meridian_device_t *device, const unsigned char // Read the echo. unsigned char echo[sizeof(packet)]; - status = dc_serial_read (device->port, echo, csize + 12, NULL); + status = dc_iostream_read (device->iostream, echo, csize + 12, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the echo."); return status; @@ -105,7 +105,7 @@ uwatec_meridian_transfer (uwatec_meridian_device_t *device, const unsigned char // Read the header. unsigned char header[6]; - status = dc_serial_read (device->port, header, sizeof (header), NULL); + status = dc_iostream_read (device->iostream, header, sizeof (header), NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the header."); return status; @@ -118,7 +118,7 @@ uwatec_meridian_transfer (uwatec_meridian_device_t *device, const unsigned char } // Read the packet. - status = dc_serial_read (device->port, answer, asize, NULL); + status = dc_iostream_read (device->iostream, answer, asize, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the packet."); return status; @@ -126,7 +126,7 @@ uwatec_meridian_transfer (uwatec_meridian_device_t *device, const unsigned char // Read the checksum. unsigned char csum = 0x00; - status = dc_serial_read (device->port, &csum, sizeof (csum), NULL); + status = dc_iostream_read (device->iostream, &csum, sizeof (csum), NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the checksum."); return status; @@ -199,34 +199,34 @@ uwatec_meridian_device_open (dc_device_t **out, dc_context_t *context, const cha } // Set the default values. - device->port = NULL; + device->iostream = NULL; device->timestamp = 0; device->systime = (dc_ticks_t) -1; device->devtime = 0; // Open the device. - status = dc_serial_open (&device->port, context, name); + status = dc_serial_open (&device->iostream, context, name); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the serial port."); goto error_free; } // Set the serial communication protocol (57600 8N1). - status = dc_serial_configure (device->port, 57600, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); + status = dc_iostream_configure (device->iostream, 57600, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); goto error_close; } // Set the timeout for receiving data (3000ms). - status = dc_serial_set_timeout (device->port, 3000); + status = dc_iostream_set_timeout (device->iostream, 3000); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the timeout."); goto error_close; } // Make sure everything is in a sane state. - dc_serial_purge (device->port, DC_DIRECTION_ALL); + dc_iostream_purge (device->iostream, DC_DIRECTION_ALL); // Perform the handshaking. status = uwatec_meridian_handshake (device); @@ -240,7 +240,7 @@ uwatec_meridian_device_open (dc_device_t **out, dc_context_t *context, const cha return DC_STATUS_SUCCESS; error_close: - dc_serial_close (device->port); + dc_iostream_close (device->iostream); error_free: dc_device_deallocate ((dc_device_t *) device); return status; @@ -255,7 +255,7 @@ uwatec_meridian_device_close (dc_device_t *abstract) dc_status_t rc = DC_STATUS_SUCCESS; // Close the device. - rc = dc_serial_close (device->port); + rc = dc_iostream_close (device->iostream); if (rc != DC_STATUS_SUCCESS) { dc_status_set_error(&status, rc); } @@ -398,7 +398,7 @@ uwatec_meridian_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) // Read the header. unsigned char header[5]; - status = dc_serial_read (device->port, header, sizeof (header), NULL); + status = dc_iostream_read (device->iostream, header, sizeof (header), NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the header."); return status; @@ -412,7 +412,7 @@ uwatec_meridian_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) } // Read the packet data. - status = dc_serial_read (device->port, data + nbytes, packetsize - 1, NULL); + status = dc_iostream_read (device->iostream, data + nbytes, packetsize - 1, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the packet."); return status; @@ -420,7 +420,7 @@ uwatec_meridian_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) // Read the checksum. unsigned char csum = 0x00; - status = dc_serial_read (device->port, &csum, sizeof (csum), NULL); + status = dc_iostream_read (device->iostream, &csum, sizeof (csum), NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the checksum."); return status; diff --git a/src/uwatec_smart.c b/src/uwatec_smart.c index 4fd2e2d..bb67131 100644 --- a/src/uwatec_smart.c +++ b/src/uwatec_smart.c @@ -32,7 +32,7 @@ typedef struct uwatec_smart_device_t { dc_device_t base; - dc_irda_t *socket; + dc_iostream_t *iostream; unsigned int address; unsigned int timestamp; unsigned int devtime; @@ -88,13 +88,13 @@ uwatec_smart_transfer (uwatec_smart_device_t *device, const unsigned char comman dc_status_t status = DC_STATUS_SUCCESS; dc_device_t *abstract = (dc_device_t *) device; - status = dc_irda_write (device->socket, command, csize, NULL); + status = dc_iostream_write (device->iostream, command, csize, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); return status; } - status = dc_irda_read (device->socket, answer, asize, NULL); + status = dc_iostream_read (device->iostream, answer, asize, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); return status; @@ -158,21 +158,21 @@ uwatec_smart_device_open (dc_device_t **out, dc_context_t *context) } // Set the default values. - device->socket = NULL; + device->iostream = NULL; device->address = 0; device->timestamp = 0; device->systime = (dc_ticks_t) -1; device->devtime = 0; // Open the irda socket. - status = dc_irda_open (&device->socket, context); + status = dc_irda_open (&device->iostream, context); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the irda socket."); goto error_free; } // Discover the device. - status = dc_irda_discover (device->socket, uwatec_smart_discovery, device); + status = dc_irda_discover (device->iostream, uwatec_smart_discovery, device); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to discover the device."); goto error_close; @@ -185,7 +185,7 @@ uwatec_smart_device_open (dc_device_t **out, dc_context_t *context) } // Connect the device. - status = dc_irda_connect_lsap (device->socket, device->address, 1); + status = dc_irda_connect_lsap (device->iostream, device->address, 1); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to connect the device."); goto error_close; @@ -203,7 +203,7 @@ uwatec_smart_device_open (dc_device_t **out, dc_context_t *context) return DC_STATUS_SUCCESS; error_close: - dc_irda_close (device->socket); + dc_iostream_close (device->iostream); error_free: dc_device_deallocate ((dc_device_t *) device); return status; @@ -218,7 +218,7 @@ uwatec_smart_device_close (dc_device_t *abstract) dc_status_t rc = DC_STATUS_SUCCESS; // Close the device. - rc = dc_irda_close (device->socket); + rc = dc_iostream_close (device->iostream); if (status != DC_STATUS_SUCCESS) { dc_status_set_error(&status, rc); } @@ -362,7 +362,7 @@ uwatec_smart_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) // Increase the packet size if more data is immediately available. size_t available = 0; - rc = dc_irda_get_available (device->socket, &available); + rc = dc_iostream_get_available (device->iostream, &available); if (rc == DC_STATUS_SUCCESS && available > len) len = available; @@ -370,7 +370,7 @@ uwatec_smart_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) if (nbytes + len > length) len = length - nbytes; - rc = dc_irda_read (device->socket, data + nbytes, len, NULL); + rc = dc_iostream_read (device->iostream, data + nbytes, len, NULL); if (rc != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); return rc; diff --git a/src/zeagle_n2ition3.c b/src/zeagle_n2ition3.c index 3d2bb24..01b9d5e 100644 --- a/src/zeagle_n2ition3.c +++ b/src/zeagle_n2ition3.c @@ -46,7 +46,7 @@ typedef struct zeagle_n2ition3_device_t { dc_device_t base; - dc_serial_t *port; + dc_iostream_t *iostream; unsigned char fingerprint[16]; } zeagle_n2ition3_device_t; @@ -81,14 +81,14 @@ zeagle_n2ition3_packet (zeagle_n2ition3_device_t *device, const unsigned char co return DC_STATUS_CANCELLED; // Send the command to the device. - status = dc_serial_write (device->port, command, csize, NULL); + status = dc_iostream_write (device->iostream, command, csize, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); return status; } // Receive the answer of the device. - status = dc_serial_read (device->port, answer, asize, NULL); + status = dc_iostream_read (device->iostream, answer, asize, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); return status; @@ -149,32 +149,32 @@ zeagle_n2ition3_device_open (dc_device_t **out, dc_context_t *context, const cha } // Set the default values. - device->port = NULL; + device->iostream = NULL; memset (device->fingerprint, 0, sizeof (device->fingerprint)); // Open the device. - status = dc_serial_open (&device->port, context, name); + status = dc_serial_open (&device->iostream, context, name); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the serial port."); goto error_free; } // Set the serial communication protocol (4800 8N1). - status = dc_serial_configure (device->port, 4800, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); + status = dc_iostream_configure (device->iostream, 4800, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); goto error_close; } // Set the timeout for receiving data (1000 ms). - status = dc_serial_set_timeout (device->port, 1000); + status = dc_iostream_set_timeout (device->iostream, 1000); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the timeout."); goto error_close; } // Make sure everything is in a sane state. - dc_serial_purge (device->port, DC_DIRECTION_ALL); + dc_iostream_purge (device->iostream, DC_DIRECTION_ALL); // Send the init commands. zeagle_n2ition3_init (device); @@ -184,7 +184,7 @@ zeagle_n2ition3_device_open (dc_device_t **out, dc_context_t *context, const cha return DC_STATUS_SUCCESS; error_close: - dc_serial_close (device->port); + dc_iostream_close (device->iostream); error_free: dc_device_deallocate ((dc_device_t *) device); return status; @@ -199,7 +199,7 @@ zeagle_n2ition3_device_close (dc_device_t *abstract) dc_status_t rc = DC_STATUS_SUCCESS; // Close the device. - rc = dc_serial_close (device->port); + rc = dc_iostream_close (device->iostream); if (rc != DC_STATUS_SUCCESS) { dc_status_set_error(&status, rc); }