Merge remote-tracking branch 'jef/master' into Subsurface-branch

Rough merge of upstream libdivecomputer.

This is mainly about making the new iostream code upstream, although we
don't actually use it.

It abstracts out the the old serial and usbhid code, but we end up still
using our own 'custom_io' interface because the iostream code doesn't do
it right.

* jef/master:
  Correctly determine git SHA if libdivecomputer is a git submodule
  Don't accept a NULL pointer as parameter
  Add support for semi-closed circuit diving
  Detect dives with invalid profile data
  Implement the serial communication functions as no-ops
  Move the socket code to a common file
  Add support for a custom I/O implementation
  Port the USB HID code to the new I/O interface
  Port the bluetooth code to the new I/O interface
  Port the IrDA code to the new I/O interface
  Port the serial code to the new I/O interface
  Add a new abstract I/O interface
  Post release version bump to 0.7.0
This commit is contained in:
Linus Torvalds 2017-12-12 13:59:29 -08:00
commit 8a34d822ff
67 changed files with 2741 additions and 2206 deletions

View File

@ -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]))

View File

@ -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

View File

@ -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, "<divemode>%s</divemode>\n",
names[divemode]);
}

View File

@ -7,6 +7,7 @@ libdivecomputer_HEADERS = \
buffer.h \
descriptor.h \
iterator.h \
iostream.h \
device.h \
parser.h \
datetime.h \

View File

@ -1,67 +1,14 @@
#ifndef CUSTOM_IO_H
#define CUSTOM_IO_H
#include <libdivecomputer/iostream.h>
#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;

View File

@ -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 <libdivecomputer/common.h>
#include <libdivecomputer/context.h>
#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 */

View File

@ -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,

View File

@ -246,6 +246,10 @@
RelativePath="..\src\cressi_leonardo_parser.c"
>
</File>
<File
RelativePath="..\src\custom.c"
>
</File>
<File
RelativePath="..\src\datetime.c"
>
@ -294,6 +298,10 @@
RelativePath="..\src\ihex.c"
>
</File>
<File
RelativePath="..\src\iostream.c"
>
</File>
<File
RelativePath="..\src\irda.c"
>
@ -418,6 +426,10 @@
RelativePath="..\src\shearwater_predator_parser.c"
>
</File>
<File
RelativePath="..\src\socket.c"
>
</File>
<File
RelativePath="..\src\suunto_common.c"
>
@ -572,6 +584,10 @@
RelativePath="..\src\cressi_leonardo.h"
>
</File>
<File
RelativePath="..\src\custom.h"
>
</File>
<File
RelativePath="..\include\libdivecomputer\datetime.h"
>
@ -624,6 +640,14 @@
RelativePath="..\src\ihex.h"
>
</File>
<File
RelativePath="..\src\iostream-private.h"
>
</File>
<File
RelativePath="..\src\iostream.h"
>
</File>
<File
RelativePath="..\src\irda.h"
>
@ -748,6 +772,10 @@
RelativePath="..\src\shearwater_predator.h"
>
</File>
<File
RelativePath="..\src\socket.h"
>
</File>
<File
RelativePath="..\src\suunto_common.h"
>

View File

@ -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 $@; \

View File

@ -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;

View File

@ -25,22 +25,14 @@
#include <stdlib.h> // malloc, free
#include "socket.h"
#ifdef _WIN32
#define NOGDI
#include <winsock2.h>
#include <windows.h>
#ifdef HAVE_WS2BTH_H
#define BLUETOOTH
#include <ws2bth.h>
#endif
#else
#include <errno.h> // errno
#include <unistd.h> // close
#include <sys/types.h> // socket, getsockopt
#include <sys/socket.h> // socket, getsockopt
#include <sys/select.h> // select
#include <sys/ioctl.h> // ioctl
#include <sys/time.h>
#ifdef HAVE_BLUEZ
#define BLUETOOTH
#include <bluetooth/bluetooth.h>
@ -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

View File

@ -24,16 +24,12 @@
#include <libdivecomputer/common.h>
#include <libdivecomputer/context.h>
#include <libdivecomputer/iostream.h>
#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
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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
}

View File

@ -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);
}

View File

@ -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;

263
src/custom.c Normal file
View File

@ -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 <stdlib.h> // 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;
}

67
src/custom.h Normal file
View File

@ -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 <libdivecomputer/common.h>
#include <libdivecomputer/context.h>
#include <libdivecomputer/iostream.h>
#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 */

231
src/custom_io.c Normal file
View File

@ -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 <stdlib.h> // malloc, free
#include <libdivecomputer/context.h>
#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);
}

View File

@ -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);
}

View File

@ -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) {

View File

@ -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;

View File

@ -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);
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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) {

86
src/iostream-private.h Normal file
View File

@ -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 <libdivecomputer/common.h>
#include <libdivecomputer/context.h>
#include <libdivecomputer/iostream.h>
#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 */

254
src/iostream.c Normal file
View File

@ -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 <stddef.h>
#include <stdlib.h>
#include <assert.h>
#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;
}

View File

@ -25,218 +25,89 @@
#include <stdlib.h> // malloc, free
#include <stdio.h> // snprintf
#include <string.h>
#include "socket.h"
#ifdef _WIN32
#define NOGDI
#include <winsock2.h>
#include <windows.h>
#ifdef HAVE_AF_IRDA_H
#define IRDA
#include <af_irda.h>
#endif
#ifdef HAVE_AF_IRDA_H
#define IRDA
#include <af_irda.h>
#endif
#else
#include <string.h> // strerror
#include <errno.h> // errno
#include <unistd.h> // close
#include <sys/types.h> // socket, getsockopt
#include <sys/socket.h> // socket, getsockopt
#ifdef HAVE_LINUX_IRDA_H
#define IRDA
#include <linux/types.h> // irda
#include <linux/irda.h> // irda
#endif
#include <sys/select.h> // select
#include <sys/ioctl.h> // ioctl
#include <sys/time.h>
#ifdef HAVE_LINUX_IRDA_H
#define IRDA
#include <linux/types.h>
#include <linux/irda.h>
#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

View File

@ -24,16 +24,12 @@
#include <libdivecomputer/common.h>
#include <libdivecomputer/context.h>
#include <libdivecomputer/iostream.h>
#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
}

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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;

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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.

View File

@ -24,67 +24,12 @@
#include <libdivecomputer/common.h>
#include <libdivecomputer/context.h>
#include <libdivecomputer/iostream.h>
#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
}

View File

@ -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);
}
}

View File

@ -25,12 +25,29 @@
#include <windows.h>
#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;

View File

@ -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;
}

View File

@ -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

View File

@ -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.

358
src/socket.c Normal file
View File

@ -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;
}

152
src/socket.h Normal file
View File

@ -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 <winsock2.h>
#include <windows.h>
#else
#include <errno.h> // errno
#include <unistd.h> // close
#include <sys/types.h> // socket, getsockopt
#include <sys/socket.h> // socket, getsockopt
#include <sys/select.h> // select
#include <sys/ioctl.h> // ioctl
#include <sys/time.h>
#endif
#include <libdivecomputer/common.h>
#include <libdivecomputer/context.h>
#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 */

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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)

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -24,20 +24,16 @@
#include <libdivecomputer/common.h>
#include <libdivecomputer/context.h>
#include <libdivecomputer/iostream.h>
#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

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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);
}