diff --git a/configure.ac b/configure.ac
index 927d8e5..21a95f7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -166,6 +166,7 @@ AC_CHECK_HEADERS([IOKit/serial/ioss.h])
AC_CHECK_HEADERS([getopt.h])
AC_CHECK_HEADERS([sys/param.h])
AC_CHECK_HEADERS([pthread.h])
+AC_CHECK_HEADERS([mach/mach_time.h])
# Checks for global variable declarations.
AC_CHECK_DECLS([optreset])
@@ -178,6 +179,7 @@ AC_CHECK_MEMBERS([struct tm.tm_gmtoff],,,[
# Checks for library functions.
AC_FUNC_STRERROR_R
AC_CHECK_FUNCS([localtime_r gmtime_r timegm _mkgmtime])
+AC_CHECK_FUNCS([clock_gettime mach_absolute_time])
AC_CHECK_FUNCS([getopt_long])
# Checks for supported compiler options.
diff --git a/include/libdivecomputer/custom_io.h b/include/libdivecomputer/custom_io.h
index 1e310b9..0e0ab7c 100644
--- a/include/libdivecomputer/custom_io.h
+++ b/include/libdivecomputer/custom_io.h
@@ -49,7 +49,6 @@ typedef struct dc_custom_io_t
dc_status_t (*serial_configure) (struct dc_custom_io_t *io, unsigned int baudrate, unsigned int databits, dc_parity_t parity, dc_stopbits_t stopbits, dc_flowcontrol_t flowcontrol);
dc_status_t (*serial_set_dtr) (struct dc_custom_io_t *io, int level);
dc_status_t (*serial_set_rts) (struct dc_custom_io_t *io, int level);
- dc_status_t (*serial_set_halfduplex) (struct dc_custom_io_t *io, unsigned int value);
dc_status_t (*serial_set_break) (struct dc_custom_io_t *io, unsigned int level);
//dc_serial_set_latency (dc_serial_t *device, unsigned int milliseconds) - Unused
//dc_serial_get_lines (dc_serial_t *device, unsigned int *value) - Unused
diff --git a/include/libdivecomputer/iostream.h b/include/libdivecomputer/iostream.h
index dab5daf..832680d 100644
--- a/include/libdivecomputer/iostream.h
+++ b/include/libdivecomputer/iostream.h
@@ -129,17 +129,6 @@ dc_iostream_set_timeout (dc_iostream_t *iostream, int timeout);
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.
*
diff --git a/msvc/libdivecomputer.vcproj b/msvc/libdivecomputer.vcproj
index c54c3d7..1b1cd96 100644
--- a/msvc/libdivecomputer.vcproj
+++ b/msvc/libdivecomputer.vcproj
@@ -482,6 +482,10 @@
RelativePath="..\src\suunto_vyper_parser.c"
>
+
+
@@ -820,6 +824,10 @@
RelativePath="..\src\suunto_vyper2.h"
>
+
+
diff --git a/src/Makefile.am b/src/Makefile.am
index 49ae4e7..f72f38d 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -16,7 +16,7 @@ endif
libdivecomputer_la_SOURCES = \
version.c \
- descriptor.c \
+ descriptor-private.h descriptor.c \
iostream-private.h iostream.c \
iterator-private.h iterator.c \
common-private.h common.c \
@@ -24,6 +24,7 @@ libdivecomputer_la_SOURCES = \
device-private.h device.c \
parser-private.h parser.c \
datetime.c \
+ timer.h timer.c \
suunto_common.h suunto_common.c \
suunto_common2.h suunto_common2.c \
suunto_solution.h suunto_solution.c suunto_solution_parser.c \
diff --git a/src/bluetooth.c b/src/bluetooth.c
index 1c3211e..772101f 100644
--- a/src/bluetooth.c
+++ b/src/bluetooth.c
@@ -24,6 +24,7 @@
#endif
#include // malloc, free
+#include
#include "socket.h"
@@ -50,6 +51,8 @@
#include "common-private.h"
#include "context-private.h"
#include "iostream-private.h"
+#include "iterator-private.h"
+#include "descriptor-private.h"
#ifdef _WIN32
#define DC_ADDRESS_FORMAT "%012I64X"
@@ -64,12 +67,38 @@
#define ISINSTANCE(device) dc_iostream_isinstance((device), &dc_bluetooth_vtable)
+struct dc_bluetooth_device_t {
+ dc_bluetooth_address_t address;
+ char name[248];
+};
+
#ifdef BLUETOOTH
+static dc_status_t dc_bluetooth_iterator_next (dc_iterator_t *iterator, void *item);
+static dc_status_t dc_bluetooth_iterator_free (dc_iterator_t *iterator);
+
+typedef struct dc_bluetooth_iterator_t {
+ dc_iterator_t base;
+ dc_filter_t filter;
+#ifdef _WIN32
+ HANDLE hLookup;
+#else
+ int fd;
+ inquiry_info *devices;
+ size_t count;
+ size_t current;
+#endif
+} dc_bluetooth_iterator_t;
+
+static const dc_iterator_vtable_t dc_bluetooth_iterator_vtable = {
+ sizeof(dc_bluetooth_iterator_t),
+ dc_bluetooth_iterator_next,
+ dc_bluetooth_iterator_free,
+};
+
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 */
@@ -194,8 +223,275 @@ error:
#endif
#endif
+char *
+dc_bluetooth_addr2str(dc_bluetooth_address_t address, char *str, size_t size)
+{
+ if (str == NULL || size < DC_BLUETOOTH_SIZE)
+ return NULL;
+
+ int n = snprintf(str, size, "%02X:%02X:%02X:%02X:%02X:%02X",
+ (unsigned char)((address >> 40) & 0xFF),
+ (unsigned char)((address >> 32) & 0xFF),
+ (unsigned char)((address >> 24) & 0xFF),
+ (unsigned char)((address >> 16) & 0xFF),
+ (unsigned char)((address >> 8) & 0xFF),
+ (unsigned char)((address >> 0) & 0xFF));
+ if (n < 0 || (size_t) n >= size)
+ return NULL;
+
+ return str;
+}
+
+dc_bluetooth_address_t
+dc_bluetooth_str2addr(const char *str)
+{
+ dc_bluetooth_address_t address = 0;
+
+ if (str == NULL)
+ return 0;
+
+ unsigned char c = 0;
+ while ((c = *str++) != '\0') {
+ if (c == ':') {
+ continue;
+ } else if (c >= '0' && c <= '9') {
+ c -= '0';
+ } else if (c >= 'A' && c <= 'F') {
+ c -= 'A' - 10;
+ } else if (c >= 'a' && c <= 'f') {
+ c -= 'a' - 10;
+ } else {
+ return 0; /* Invalid character! */
+ }
+
+ address <<= 4;
+ address |= c;
+ }
+
+ return address;
+}
+
+dc_bluetooth_address_t
+dc_bluetooth_device_get_address (dc_bluetooth_device_t *device)
+{
+ if (device == NULL)
+ return 0;
+
+ return device->address;
+}
+
+const char *
+dc_bluetooth_device_get_name (dc_bluetooth_device_t *device)
+{
+ if (device == NULL || device->name[0] == '\0')
+ return NULL;
+
+ return device->name;
+}
+
+void
+dc_bluetooth_device_free (dc_bluetooth_device_t *device)
+{
+ free (device);
+}
+
dc_status_t
-dc_bluetooth_open (dc_iostream_t **out, dc_context_t *context)
+dc_bluetooth_iterator_new (dc_iterator_t **out, dc_context_t *context, dc_descriptor_t *descriptor)
+{
+#ifdef BLUETOOTH
+ dc_status_t status = DC_STATUS_SUCCESS;
+ dc_bluetooth_iterator_t *iterator = NULL;
+
+ if (out == NULL)
+ return DC_STATUS_INVALIDARGS;
+
+ iterator = (dc_bluetooth_iterator_t *) dc_iterator_allocate (context, &dc_bluetooth_iterator_vtable);
+ if (iterator == NULL) {
+ SYSERROR (context, S_ENOMEM);
+ return DC_STATUS_NOMEMORY;
+ }
+
+#ifdef _WIN32
+ WSAQUERYSET wsaq;
+ memset(&wsaq, 0, sizeof (wsaq));
+ wsaq.dwSize = sizeof (wsaq);
+ wsaq.dwNameSpace = NS_BTH;
+ wsaq.lpcsaBuffer = NULL;
+
+ HANDLE hLookup = NULL;
+ if (WSALookupServiceBegin(&wsaq, LUP_CONTAINERS | LUP_FLUSHCACHE, &hLookup) != 0) {
+ s_errcode_t errcode = S_ERRNO;
+ if (errcode == WSASERVICE_NOT_FOUND) {
+ // No remote bluetooth devices found.
+ hLookup = NULL;
+ } else {
+ SYSERROR (context, errcode);
+ status = dc_socket_syserror(errcode);
+ goto error_free;
+ }
+ }
+
+ iterator->hLookup = hLookup;
+#else
+ // Get the resource number for the first available bluetooth adapter.
+ int dev = hci_get_route (NULL);
+ if (dev < 0) {
+ s_errcode_t errcode = S_ERRNO;
+ SYSERROR (context, errcode);
+ status = dc_socket_syserror(errcode);
+ goto error_free;
+ }
+
+ // Open a socket to the bluetooth adapter.
+ int fd = hci_open_dev (dev);
+ if (fd < 0) {
+ s_errcode_t errcode = S_ERRNO;
+ SYSERROR (context, errcode);
+ status = dc_socket_syserror(errcode);
+ goto error_free;
+ }
+
+ // Perform the bluetooth device discovery. The inquiry lasts for at
+ // most MAX_PERIODS * 1.28 seconds, and at most MAX_DEVICES devices
+ // will be returned.
+ inquiry_info *devices = NULL;
+ int ndevices = hci_inquiry (dev, MAX_PERIODS, MAX_DEVICES, NULL, &devices, IREQ_CACHE_FLUSH);
+ if (ndevices < 0) {
+ s_errcode_t errcode = S_ERRNO;
+ SYSERROR (context, errcode);
+ status = dc_socket_syserror(errcode);
+ goto error_close;
+ }
+
+ iterator->fd = fd;
+ iterator->devices = devices;
+ iterator->count = ndevices;
+ iterator->current = 0;
+#endif
+ iterator->filter = dc_descriptor_get_filter (descriptor);
+
+ *out = (dc_iterator_t *) iterator;
+
+ return DC_STATUS_SUCCESS;
+
+#ifndef _WIN32
+error_close:
+ hci_close_dev(fd);
+#endif
+error_free:
+ dc_iterator_deallocate ((dc_iterator_t *) iterator);
+ return status;
+#else
+ return DC_STATUS_UNSUPPORTED;
+#endif
+}
+
+#ifdef BLUETOOTH
+static dc_status_t
+dc_bluetooth_iterator_next (dc_iterator_t *abstract, void *out)
+{
+ dc_bluetooth_iterator_t *iterator = (dc_bluetooth_iterator_t *) abstract;
+ dc_bluetooth_device_t *device = NULL;
+
+#ifdef _WIN32
+ if (iterator->hLookup == NULL) {
+ return DC_STATUS_DONE;
+ }
+
+ unsigned char buf[4096];
+ LPWSAQUERYSET pwsaResults = (LPWSAQUERYSET) buf;
+ memset(pwsaResults, 0, sizeof(WSAQUERYSET));
+ pwsaResults->dwSize = sizeof(WSAQUERYSET);
+ pwsaResults->dwNameSpace = NS_BTH;
+ pwsaResults->lpBlob = NULL;
+
+ while (1) {
+ DWORD dwSize = sizeof(buf);
+ if (WSALookupServiceNext (iterator->hLookup, LUP_RETURN_NAME | LUP_RETURN_ADDR, &dwSize, pwsaResults) != 0) {
+ s_errcode_t errcode = S_ERRNO;
+ if (errcode == WSA_E_NO_MORE || errcode == WSAENOMORE) {
+ break; // No more results.
+ }
+ SYSERROR (abstract->context, errcode);
+ return dc_socket_syserror(errcode);
+ }
+
+ if (pwsaResults->dwNumberOfCsAddrs == 0 ||
+ pwsaResults->lpcsaBuffer == NULL ||
+ pwsaResults->lpcsaBuffer->RemoteAddr.lpSockaddr == NULL) {
+ ERROR (abstract->context, "Invalid results returned");
+ return DC_STATUS_IO;
+ }
+
+ SOCKADDR_BTH *sa = (SOCKADDR_BTH *) pwsaResults->lpcsaBuffer->RemoteAddr.lpSockaddr;
+ dc_bluetooth_address_t address = sa->btAddr;
+ const char *name = (char *) pwsaResults->lpszServiceInstanceName;
+#else
+ while (iterator->current < iterator->count) {
+ inquiry_info *dev = &iterator->devices[iterator->current++];
+
+ dc_bluetooth_address_t address = dc_address_get (&dev->bdaddr);
+
+ // Get the user friendly name.
+ char buf[HCI_MAX_NAME_LENGTH], *name = buf;
+ int rc = hci_read_remote_name (iterator->fd, &dev->bdaddr, sizeof(buf), buf, 0);
+ if (rc < 0) {
+ name = NULL;
+ }
+
+ // Null terminate the string.
+ buf[sizeof(buf) - 1] = '\0';
+#endif
+
+ INFO (abstract->context, "Discover: address=" DC_ADDRESS_FORMAT ", name=%s",
+ address, name ? name : "");
+
+ if (iterator->filter && !iterator->filter (DC_TRANSPORT_BLUETOOTH, name)) {
+ continue;
+ }
+
+ device = (dc_bluetooth_device_t *) malloc (sizeof(dc_bluetooth_device_t));
+ if (device == NULL) {
+ SYSERROR (abstract->context, S_ENOMEM);
+ return DC_STATUS_NOMEMORY;
+ }
+
+ device->address = address;
+ if (name) {
+ strncpy(device->name, name, sizeof(device->name) - 1);
+ device->name[sizeof(device->name) - 1] = '\0';
+ } else {
+ memset(device->name, 0, sizeof(device->name));
+ }
+
+ *(dc_bluetooth_device_t **) out = device;
+
+ return DC_STATUS_SUCCESS;
+ }
+
+ return DC_STATUS_DONE;
+}
+
+static dc_status_t
+dc_bluetooth_iterator_free (dc_iterator_t *abstract)
+{
+ dc_bluetooth_iterator_t *iterator = (dc_bluetooth_iterator_t *) abstract;
+
+#ifdef _WIN32
+ if (iterator->hLookup) {
+ WSALookupServiceEnd (iterator->hLookup);
+ }
+#else
+ bt_free(iterator->devices);
+ hci_close_dev(iterator->fd);
+#endif
+
+ return DC_STATUS_SUCCESS;
+}
+#endif
+
+dc_status_t
+dc_bluetooth_open (dc_iostream_t **out, dc_context_t *context, dc_bluetooth_address_t address, unsigned int port)
{
#ifdef BLUETOOTH
dc_status_t status = DC_STATUS_SUCCESS;
@@ -204,6 +500,8 @@ dc_bluetooth_open (dc_iostream_t **out, dc_context_t *context)
if (out == NULL)
return DC_STATUS_INVALIDARGS;
+ INFO (context, "Open: address=" DC_ADDRESS_FORMAT ", port=%u", address, port);
+
// Allocate memory.
device = (dc_socket_t *) dc_iostream_allocate (context, &dc_bluetooth_vtable);
if (device == NULL) {
@@ -221,164 +519,6 @@ dc_bluetooth_open (dc_iostream_t **out, dc_context_t *context)
goto error_free;
}
- *out = (dc_iostream_t *) device;
-
- return DC_STATUS_SUCCESS;
-
-error_free:
- dc_iostream_deallocate ((dc_iostream_t *) device);
- return status;
-#else
- return DC_STATUS_UNSUPPORTED;
-#endif
-}
-
-dc_status_t
-dc_bluetooth_discover (dc_iostream_t *abstract, dc_bluetooth_callback_t callback, void *userdata)
-{
-#ifdef BLUETOOTH
- dc_status_t status = DC_STATUS_SUCCESS;
-
- if (!ISINSTANCE (abstract))
- return DC_STATUS_INVALIDARGS;
-
-#ifdef _WIN32
- WSAQUERYSET wsaq;
- memset(&wsaq, 0, sizeof (wsaq));
- wsaq.dwSize = sizeof (wsaq);
- wsaq.dwNameSpace = NS_BTH;
- wsaq.lpcsaBuffer = NULL;
-
- HANDLE hLookup;
- if (WSALookupServiceBegin(&wsaq, LUP_CONTAINERS | LUP_FLUSHCACHE, &hLookup) != 0) {
- s_errcode_t errcode = S_ERRNO;
- if (errcode == WSASERVICE_NOT_FOUND) {
- // No remote bluetooth devices found.
- status = DC_STATUS_SUCCESS;
- } else {
- SYSERROR (abstract->context, errcode);
- status = dc_socket_syserror(errcode);
- }
- goto error_exit;
- }
-
- unsigned char buf[4096];
- LPWSAQUERYSET pwsaResults = (LPWSAQUERYSET) buf;
- memset(pwsaResults, 0, sizeof(WSAQUERYSET));
- pwsaResults->dwSize = sizeof(WSAQUERYSET);
- pwsaResults->dwNameSpace = NS_BTH;
- pwsaResults->lpBlob = NULL;
-
- while (1) {
- DWORD dwSize = sizeof(buf);
- if (WSALookupServiceNext (hLookup, LUP_RETURN_NAME | LUP_RETURN_ADDR, &dwSize, pwsaResults) != 0) {
- s_errcode_t errcode = S_ERRNO;
- if (errcode == WSA_E_NO_MORE || errcode == WSAENOMORE) {
- break; // No more results.
- }
- 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 (abstract->context, "Invalid results returned");
- status = DC_STATUS_IO;
- goto error_close;
- }
-
- SOCKADDR_BTH *sa = (SOCKADDR_BTH *) pwsaResults->lpcsaBuffer->RemoteAddr.lpSockaddr;
- dc_bluetooth_address_t address = sa->btAddr;
- const char *name = (char *) pwsaResults->lpszServiceInstanceName;
-
- INFO (abstract->context, "Discover: address=" DC_ADDRESS_FORMAT ", name=%s", address, name);
-
- if (callback) callback (address, name, userdata);
-
- }
-
-error_close:
- WSALookupServiceEnd (hLookup);
-#else
- // Get the resource number for the first available bluetooth adapter.
- int dev = hci_get_route (NULL);
- if (dev < 0) {
- s_errcode_t errcode = S_ERRNO;
- SYSERROR (abstract->context, errcode);
- status = dc_socket_syserror(errcode);
- goto error_exit;
- }
-
- // Open a socket to the bluetooth adapter.
- int fd = hci_open_dev (dev);
- if (fd < 0) {
- s_errcode_t errcode = S_ERRNO;
- SYSERROR (abstract->context, errcode);
- status = dc_socket_syserror(errcode);
- goto error_exit;
- }
-
- // Allocate a buffer to store the results of the discovery.
- inquiry_info *devices = (inquiry_info *) malloc (MAX_DEVICES * sizeof(inquiry_info));
- if (devices == NULL) {
- s_errcode_t errcode = S_ERRNO;
- SYSERROR (abstract->context, errcode);
- status = dc_socket_syserror(errcode);
- goto error_close;
- }
-
- // Perform the bluetooth device discovery. The inquiry lasts for at
- // most MAX_PERIODS * 1.28 seconds, and at most MAX_DEVICES devices
- // will be returned.
- int ndevices = hci_inquiry (dev, MAX_PERIODS, MAX_DEVICES, NULL, &devices, IREQ_CACHE_FLUSH);
- if (ndevices < 0) {
- s_errcode_t errcode = S_ERRNO;
- SYSERROR (abstract->context, errcode);
- status = dc_socket_syserror(errcode);
- goto error_free;
- }
-
- for (unsigned int i = 0; i < ndevices; ++i) {
- dc_bluetooth_address_t address = dc_address_get (&devices[i].bdaddr);
-
- // Get the user friendly name.
- char buf[HCI_MAX_NAME_LENGTH], *name = buf;
- int rc = hci_read_remote_name (fd, &devices[i].bdaddr, sizeof(buf), buf, 0);
- if (rc < 0) {
- name = NULL;
- }
-
- INFO (abstract->context, "Discover: address=" DC_ADDRESS_FORMAT ", name=%s", address, name);
-
- if (callback) callback (address, name, userdata);
- }
-
-error_free:
- free(devices);
-error_close:
- hci_close_dev(fd);
-#endif
-
-error_exit:
- return status;
-#else
- return DC_STATUS_UNSUPPORTED;
-#endif
-}
-
-dc_status_t
-dc_bluetooth_connect (dc_iostream_t *abstract, dc_bluetooth_address_t address, unsigned int port)
-{
-#ifdef BLUETOOTH
- dc_socket_t *device = (dc_socket_t *) abstract;
-
- if (!ISINSTANCE (abstract))
- return DC_STATUS_INVALIDARGS;
-
- INFO (abstract->context, "Connect: address=" DC_ADDRESS_FORMAT ", port=%d", address, port);
-
#ifdef _WIN32
SOCKADDR_BTH sa;
sa.addressFamily = AF_BTH;
@@ -394,16 +534,29 @@ dc_bluetooth_connect (dc_iostream_t *abstract, dc_bluetooth_address_t address, u
sa.rc_family = AF_BLUETOOTH;
dc_address_set (&sa.rc_bdaddr, address);
if (port == 0) {
- dc_status_t rc = dc_bluetooth_sdp (&sa.rc_channel, abstract->context, &sa.rc_bdaddr);
- if (rc != DC_STATUS_SUCCESS) {
- return rc;
+ status = dc_bluetooth_sdp (&sa.rc_channel, context, &sa.rc_bdaddr);
+ if (status != DC_STATUS_SUCCESS) {
+ goto error_close;
}
} else {
sa.rc_channel = port;
}
#endif
- return dc_socket_connect (&device->base, (struct sockaddr *) &sa, sizeof (sa));
+ status = dc_socket_connect (&device->base, (struct sockaddr *) &sa, sizeof (sa));
+ if (status != DC_STATUS_SUCCESS) {
+ goto error_close;
+ }
+
+ *out = (dc_iostream_t *) device;
+
+ return DC_STATUS_SUCCESS;
+
+error_close:
+ dc_socket_close (&device->base);
+error_free:
+ dc_iostream_deallocate ((dc_iostream_t *) device);
+ return status;
#else
return DC_STATUS_UNSUPPORTED;
#endif
diff --git a/src/bluetooth.h b/src/bluetooth.h
index 1a8e947..5b443a4 100644
--- a/src/bluetooth.h
+++ b/src/bluetooth.h
@@ -25,11 +25,19 @@
#include
#include
#include
+#include
+#include
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
+/**
+ * The minimum number of bytes (including the terminating null byte) for
+ * formatting a bluetooth address as a string.
+ */
+#define DC_BLUETOOTH_SIZE 18
+
/**
* Bluetooth address (48 bits).
*/
@@ -40,48 +48,86 @@ typedef unsigned long long dc_bluetooth_address_t;
#endif
/**
- * Bluetooth enumeration callback.
+ * Convert a bluetooth address to a string.
*
- * @param[in] address The bluetooth device address.
- * @param[in] name The bluetooth device name.
- * @param[in] userdata The user data pointer.
+ * The bluetooth address is formatted as XX:XX:XX:XX:XX:XX, where each
+ * XX is a hexadecimal number specifying an octet of the 48-bit address.
+ * The minimum size for the buffer is #DC_BLUETOOTH_SIZE bytes.
+ *
+ * @param[in] address A bluetooth address.
+ * @param[in] str The memory buffer to store the result.
+ * @param[in] size The size of the memory buffer.
+ * @returns The null-terminated string on success, or NULL on failure.
*/
-typedef void (*dc_bluetooth_callback_t) (dc_bluetooth_address_t address, const char *name, void *userdata);
+char *
+dc_bluetooth_addr2str(dc_bluetooth_address_t address, char *str, size_t size);
+
+/**
+ * Convert a string to a bluetooth address.
+ *
+ * The string is expected to be in the format XX:XX:XX:XX:XX:XX, where
+ * each XX is a hexadecimal number specifying an octet of the 48-bit
+ * address.
+ *
+ * @param[in] address A null-terminated string.
+ * @returns The bluetooth address on success, or zero on failure.
+ */
+dc_bluetooth_address_t
+dc_bluetooth_str2addr(const char *address);
+
+/**
+ * Opaque object representing a bluetooth device.
+ */
+typedef struct dc_bluetooth_device_t dc_bluetooth_device_t;
+
+/**
+ * Get the address of the bluetooth device.
+ *
+ * @param[in] device A valid bluetooth device.
+ */
+dc_bluetooth_address_t
+dc_bluetooth_device_get_address (dc_bluetooth_device_t *device);
+
+/**
+ * Get the name of the bluetooth device.
+ *
+ * @param[in] device A valid bluetooth device.
+ */
+const char *
+dc_bluetooth_device_get_name (dc_bluetooth_device_t *device);
+
+/**
+ * Destroy the bluetooth device and free all resources.
+ *
+ * @param[in] device A valid bluetooth device.
+ */
+void
+dc_bluetooth_device_free (dc_bluetooth_device_t *device);
+
+/**
+ * Create an iterator to enumerate the bluetooth devices.
+ *
+ * @param[out] iterator A location to store the iterator.
+ * @param[in] context A valid context object.
+ * @param[in] descriptor A valid device descriptor or NULL.
+ * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code
+ * on failure.
+ */
+dc_status_t
+dc_bluetooth_iterator_new (dc_iterator_t **iterator, dc_context_t *context, dc_descriptor_t *descriptor);
/**
* Open an 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_iostream_t **iostream, dc_context_t *context);
-
-/**
- * Enumerate the bluetooth devices.
- *
- * @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_iostream_t *iostream, dc_bluetooth_callback_t callback, void *userdata);
-
-/**
- * Connect to an bluetooth device.
- *
- * @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_iostream_t *iostream, dc_bluetooth_address_t address, unsigned int port);
+dc_bluetooth_open (dc_iostream_t **iostream, dc_context_t *context, dc_bluetooth_address_t address, unsigned int port);
#ifdef __cplusplus
}
diff --git a/src/context.c b/src/context.c
index f731184..d662cd9 100644
--- a/src/context.c
+++ b/src/context.c
@@ -27,11 +27,11 @@
#ifdef _WIN32
#define NOGDI
#include
-#else
-#include
#endif
#include "context-private.h"
+#include "timer.h"
+
#include
struct dc_context_t {
@@ -40,11 +40,7 @@ struct dc_context_t {
void *userdata;
#ifdef ENABLE_LOGGING
char msg[8192 + 32];
-#ifdef _WIN32
- LARGE_INTEGER timestamp, frequency;
-#else
- struct timeval timestamp;
-#endif
+ dc_timer_t *timer;
#endif
dc_custom_io_t *custom_io;
dc_user_device_t *user_device;
@@ -137,23 +133,11 @@ logfunc (dc_context_t *context, dc_loglevel_t loglevel, const char *file, unsign
{
const char *loglevels[] = {"NONE", "ERROR", "WARNING", "INFO", "DEBUG", "ALL"};
- unsigned long seconds = 0, microseconds = 0;
+ dc_usecs_t now = 0;
+ dc_timer_now (context->timer, &now);
-#ifdef _WIN32
- LARGE_INTEGER now, delta;
- QueryPerformanceCounter(&now);
- delta.QuadPart = now.QuadPart - context->timestamp.QuadPart;
- delta.QuadPart *= 1000000;
- delta.QuadPart /= context->frequency.QuadPart;
- seconds = delta.QuadPart / 1000000;
- microseconds = delta.QuadPart % 1000000;
-#else
- struct timeval now, delta;
- gettimeofday (&now, NULL);
- timersub (&now, &context->timestamp, &delta);
- seconds = delta.tv_sec;
- microseconds = delta.tv_usec;
-#endif
+ unsigned long seconds = now / 1000000;
+ unsigned long microseconds = now % 1000000;
if (loglevel == DC_LOGLEVEL_ERROR || loglevel == DC_LOGLEVEL_WARNING) {
fprintf (stderr, "[%li.%06li] %s: %s [in %s:%d (%s)]\n",
@@ -190,12 +174,8 @@ dc_context_new (dc_context_t **out)
#ifdef ENABLE_LOGGING
memset (context->msg, 0, sizeof (context->msg));
-#ifdef _WIN32
- QueryPerformanceFrequency(&context->frequency);
- QueryPerformanceCounter(&context->timestamp);
-#else
- gettimeofday (&context->timestamp, NULL);
-#endif
+ context->timer = NULL;
+ dc_timer_new (&context->timer);
#endif
context->custom_io = NULL;
@@ -208,6 +188,10 @@ dc_context_new (dc_context_t **out)
dc_status_t
dc_context_free (dc_context_t *context)
{
+ if (context == NULL)
+ return DC_STATUS_SUCCESS;
+
+ dc_timer_free (context->timer);
free (context);
return DC_STATUS_SUCCESS;
diff --git a/src/custom.c b/src/custom.c
index e96ba5f..519a39e 100644
--- a/src/custom.c
+++ b/src/custom.c
@@ -29,7 +29,6 @@
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);
@@ -55,7 +54,6 @@ 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 */
@@ -117,17 +115,6 @@ dc_custom_set_latency (dc_iostream_t *abstract, unsigned int value)
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)
{
diff --git a/src/custom.h b/src/custom.h
index f062cd3..f1ab5da 100644
--- a/src/custom.h
+++ b/src/custom.h
@@ -33,7 +33,6 @@ extern "C" {
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);
diff --git a/src/custom_io.c b/src/custom_io.c
index dd1adfa..7b47c7c 100644
--- a/src/custom_io.c
+++ b/src/custom_io.c
@@ -56,18 +56,6 @@ 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)
{
@@ -198,7 +186,6 @@ 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 */
diff --git a/src/descriptor-private.h b/src/descriptor-private.h
new file mode 100644
index 0000000..5023f7f
--- /dev/null
+++ b/src/descriptor-private.h
@@ -0,0 +1,44 @@
+/*
+ * 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_DESCRIPTOR_PRIVATE_H
+#define DC_DESCRIPTOR_PRIVATE_H
+
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+typedef struct dc_usb_desc_t {
+ unsigned short vid;
+ unsigned short pid;
+} dc_usb_desc_t;
+
+typedef int (*dc_filter_t) (dc_transport_t transport, const void *userdata);
+
+dc_filter_t
+dc_descriptor_get_filter (dc_descriptor_t *descriptor);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* DC_DESCRIPTOR_PRIVATE_H */
diff --git a/src/descriptor.c b/src/descriptor.c
index 21e3a81..c562317 100644
--- a/src/descriptor.c
+++ b/src/descriptor.c
@@ -41,18 +41,38 @@
#include
#include
+#include
-#include
-
+#include "descriptor-private.h"
#include "iterator-private.h"
+#include "platform.h"
#define C_ARRAY_SIZE(array) (sizeof (array) / sizeof *(array))
+static int dc_filter_uwatec (dc_transport_t transport, const void *userdata);
+static int dc_filter_suunto (dc_transport_t transport, const void *userdata);
+static int dc_filter_shearwater (dc_transport_t transport, const void *userdata);
+static int dc_filter_hw (dc_transport_t transport, const void *userdata);
+
+static dc_status_t dc_descriptor_iterator_next (dc_iterator_t *iterator, void *item);
+
struct dc_descriptor_t {
const char *vendor;
const char *product;
dc_family_t type;
unsigned int model;
+ dc_filter_t filter;
+};
+
+typedef struct dc_descriptor_iterator_t {
+ dc_iterator_t base;
+ size_t current;
+} dc_descriptor_iterator_t;
+
+static const dc_iterator_vtable_t dc_descriptor_iterator_vtable = {
+ sizeof(dc_descriptor_iterator_t),
+ dc_descriptor_iterator_next,
+ NULL,
};
/*
@@ -64,285 +84,369 @@ struct dc_descriptor_t {
static const dc_descriptor_t g_descriptors[] = {
/* Suunto Solution */
- {"Suunto", "Solution", DC_FAMILY_SUUNTO_SOLUTION, 0},
+ {"Suunto", "Solution", DC_FAMILY_SUUNTO_SOLUTION, 0, NULL},
/* Suunto Eon */
- {"Suunto", "Eon", DC_FAMILY_SUUNTO_EON, 0},
- {"Suunto", "Solution Alpha", DC_FAMILY_SUUNTO_EON, 0},
- {"Suunto", "Solution Nitrox", DC_FAMILY_SUUNTO_EON, 0},
+ {"Suunto", "Eon", DC_FAMILY_SUUNTO_EON, 0, NULL},
+ {"Suunto", "Solution Alpha", DC_FAMILY_SUUNTO_EON, 0, NULL},
+ {"Suunto", "Solution Nitrox", DC_FAMILY_SUUNTO_EON, 0, NULL},
/* Suunto Vyper */
- {"Suunto", "Spyder", DC_FAMILY_SUUNTO_VYPER, 0x01},
- {"Suunto", "Stinger", DC_FAMILY_SUUNTO_VYPER, 0x03},
- {"Suunto", "Mosquito", DC_FAMILY_SUUNTO_VYPER, 0x04},
- {"Suunto", "D3", DC_FAMILY_SUUNTO_VYPER, 0x05},
- {"Suunto", "Vyper", DC_FAMILY_SUUNTO_VYPER, 0x0A},
- {"Suunto", "Vytec", DC_FAMILY_SUUNTO_VYPER, 0X0B},
- {"Suunto", "Cobra", DC_FAMILY_SUUNTO_VYPER, 0X0C},
- {"Suunto", "Gekko", DC_FAMILY_SUUNTO_VYPER, 0X0D},
- {"Suunto", "Zoop", DC_FAMILY_SUUNTO_VYPER, 0x16},
+ {"Suunto", "Spyder", DC_FAMILY_SUUNTO_VYPER, 0x01, NULL},
+ {"Suunto", "Stinger", DC_FAMILY_SUUNTO_VYPER, 0x03, NULL},
+ {"Suunto", "Mosquito", DC_FAMILY_SUUNTO_VYPER, 0x04, NULL},
+ {"Suunto", "D3", DC_FAMILY_SUUNTO_VYPER, 0x05, NULL},
+ {"Suunto", "Vyper", DC_FAMILY_SUUNTO_VYPER, 0x0A, NULL},
+ {"Suunto", "Vytec", DC_FAMILY_SUUNTO_VYPER, 0X0B, NULL},
+ {"Suunto", "Cobra", DC_FAMILY_SUUNTO_VYPER, 0X0C, NULL},
+ {"Suunto", "Gekko", DC_FAMILY_SUUNTO_VYPER, 0X0D, NULL},
+ {"Suunto", "Zoop", DC_FAMILY_SUUNTO_VYPER, 0x16, NULL},
/* Suunto Vyper 2 */
- {"Suunto", "Vyper 2", DC_FAMILY_SUUNTO_VYPER2, 0x10},
- {"Suunto", "Cobra 2", DC_FAMILY_SUUNTO_VYPER2, 0x11},
- {"Suunto", "Vyper Air", DC_FAMILY_SUUNTO_VYPER2, 0x13},
- {"Suunto", "Cobra 3", DC_FAMILY_SUUNTO_VYPER2, 0x14},
- {"Suunto", "HelO2", DC_FAMILY_SUUNTO_VYPER2, 0x15},
+ {"Suunto", "Vyper 2", DC_FAMILY_SUUNTO_VYPER2, 0x10, NULL},
+ {"Suunto", "Cobra 2", DC_FAMILY_SUUNTO_VYPER2, 0x11, NULL},
+ {"Suunto", "Vyper Air", DC_FAMILY_SUUNTO_VYPER2, 0x13, NULL},
+ {"Suunto", "Cobra 3", DC_FAMILY_SUUNTO_VYPER2, 0x14, NULL},
+ {"Suunto", "HelO2", DC_FAMILY_SUUNTO_VYPER2, 0x15, NULL},
/* Suunto D9 */
- {"Suunto", "D9", DC_FAMILY_SUUNTO_D9, 0x0E},
- {"Suunto", "D6", DC_FAMILY_SUUNTO_D9, 0x0F},
- {"Suunto", "D4", DC_FAMILY_SUUNTO_D9, 0x12},
- {"Suunto", "D4i", DC_FAMILY_SUUNTO_D9, 0x19},
- {"Suunto", "D6i", DC_FAMILY_SUUNTO_D9, 0x1A},
- {"Suunto", "D9tx", DC_FAMILY_SUUNTO_D9, 0x1B},
- {"Suunto", "DX", DC_FAMILY_SUUNTO_D9, 0x1C},
- {"Suunto", "Vyper Novo", DC_FAMILY_SUUNTO_D9, 0x1D},
- {"Suunto", "Zoop Novo", DC_FAMILY_SUUNTO_D9, 0x1E},
- {"Suunto", "D4f", DC_FAMILY_SUUNTO_D9, 0x20},
+ {"Suunto", "D9", DC_FAMILY_SUUNTO_D9, 0x0E, NULL},
+ {"Suunto", "D6", DC_FAMILY_SUUNTO_D9, 0x0F, NULL},
+ {"Suunto", "D4", DC_FAMILY_SUUNTO_D9, 0x12, NULL},
+ {"Suunto", "D4i", DC_FAMILY_SUUNTO_D9, 0x19, NULL},
+ {"Suunto", "D6i", DC_FAMILY_SUUNTO_D9, 0x1A, NULL},
+ {"Suunto", "D9tx", DC_FAMILY_SUUNTO_D9, 0x1B, NULL},
+ {"Suunto", "DX", DC_FAMILY_SUUNTO_D9, 0x1C, NULL},
+ {"Suunto", "Vyper Novo", DC_FAMILY_SUUNTO_D9, 0x1D, NULL},
+ {"Suunto", "Zoop Novo", DC_FAMILY_SUUNTO_D9, 0x1E, NULL},
+ {"Suunto", "D4f", DC_FAMILY_SUUNTO_D9, 0x20, NULL},
/* Suunto EON Steel */
#if defined(USBHID) || defined(ENABLE_BLE)
- {"Suunto", "EON Steel", DC_FAMILY_SUUNTO_EONSTEEL, 0},
- {"Suunto", "EON Core", DC_FAMILY_SUUNTO_EONSTEEL, 1},
+ {"Suunto", "EON Steel", DC_FAMILY_SUUNTO_EONSTEEL, 0, dc_filter_suunto},
+ {"Suunto", "EON Core", DC_FAMILY_SUUNTO_EONSTEEL, 1, dc_filter_suunto},
#endif
/* Uwatec Aladin */
- {"Uwatec", "Aladin Air Twin", DC_FAMILY_UWATEC_ALADIN, 0x1C},
- {"Uwatec", "Aladin Sport Plus", DC_FAMILY_UWATEC_ALADIN, 0x3E},
- {"Uwatec", "Aladin Pro", DC_FAMILY_UWATEC_ALADIN, 0x3F},
- {"Uwatec", "Aladin Air Z", DC_FAMILY_UWATEC_ALADIN, 0x44},
- {"Uwatec", "Aladin Air Z O2", DC_FAMILY_UWATEC_ALADIN, 0xA4},
- {"Uwatec", "Aladin Air Z Nitrox", DC_FAMILY_UWATEC_ALADIN, 0xF4},
- {"Uwatec", "Aladin Pro Ultra", DC_FAMILY_UWATEC_ALADIN, 0xFF},
+ {"Uwatec", "Aladin Air Twin", DC_FAMILY_UWATEC_ALADIN, 0x1C, NULL},
+ {"Uwatec", "Aladin Sport Plus", DC_FAMILY_UWATEC_ALADIN, 0x3E, NULL},
+ {"Uwatec", "Aladin Pro", DC_FAMILY_UWATEC_ALADIN, 0x3F, NULL},
+ {"Uwatec", "Aladin Air Z", DC_FAMILY_UWATEC_ALADIN, 0x44, NULL},
+ {"Uwatec", "Aladin Air Z O2", DC_FAMILY_UWATEC_ALADIN, 0xA4, NULL},
+ {"Uwatec", "Aladin Air Z Nitrox", DC_FAMILY_UWATEC_ALADIN, 0xF4, NULL},
+ {"Uwatec", "Aladin Pro Ultra", DC_FAMILY_UWATEC_ALADIN, 0xFF, NULL},
/* Uwatec Memomouse */
- {"Uwatec", "Memomouse", DC_FAMILY_UWATEC_MEMOMOUSE, 0},
+ {"Uwatec", "Memomouse", DC_FAMILY_UWATEC_MEMOMOUSE, 0, NULL},
/* Uwatec Smart */
#ifdef IRDA
- {"Uwatec", "Smart Pro", DC_FAMILY_UWATEC_SMART, 0x10},
- {"Uwatec", "Galileo Sol", DC_FAMILY_UWATEC_SMART, 0x11},
- {"Uwatec", "Galileo Luna", DC_FAMILY_UWATEC_SMART, 0x11},
- {"Uwatec", "Galileo Terra", DC_FAMILY_UWATEC_SMART, 0x11},
- {"Uwatec", "Aladin Tec", DC_FAMILY_UWATEC_SMART, 0x12},
- {"Uwatec", "Aladin Prime", DC_FAMILY_UWATEC_SMART, 0x12},
- {"Uwatec", "Aladin Tec 2G", DC_FAMILY_UWATEC_SMART, 0x13},
- {"Uwatec", "Aladin 2G", DC_FAMILY_UWATEC_SMART, 0x13},
- {"Subgear","XP-10", DC_FAMILY_UWATEC_SMART, 0x13},
- {"Uwatec", "Smart Com", DC_FAMILY_UWATEC_SMART, 0x14},
- {"Uwatec", "Aladin 2G", DC_FAMILY_UWATEC_SMART, 0x15},
- {"Uwatec", "Aladin Tec 3G", DC_FAMILY_UWATEC_SMART, 0x15},
- {"Uwatec", "Aladin Sport", DC_FAMILY_UWATEC_SMART, 0x15},
- {"Subgear","XP-3G", DC_FAMILY_UWATEC_SMART, 0x15},
- {"Uwatec", "Smart Tec", DC_FAMILY_UWATEC_SMART, 0x18},
- {"Uwatec", "Galileo Trimix",DC_FAMILY_UWATEC_SMART, 0x19},
- {"Uwatec", "Smart Z", DC_FAMILY_UWATEC_SMART, 0x1C},
- {"Subgear","XP Air", DC_FAMILY_UWATEC_SMART, 0x1C},
+ {"Uwatec", "Smart Pro", DC_FAMILY_UWATEC_SMART, 0x10, dc_filter_uwatec},
+ {"Uwatec", "Galileo Sol", DC_FAMILY_UWATEC_SMART, 0x11, dc_filter_uwatec},
+ {"Uwatec", "Galileo Luna", DC_FAMILY_UWATEC_SMART, 0x11, dc_filter_uwatec},
+ {"Uwatec", "Galileo Terra", DC_FAMILY_UWATEC_SMART, 0x11, dc_filter_uwatec},
+ {"Uwatec", "Aladin Tec", DC_FAMILY_UWATEC_SMART, 0x12, dc_filter_uwatec},
+ {"Uwatec", "Aladin Prime", DC_FAMILY_UWATEC_SMART, 0x12, dc_filter_uwatec},
+ {"Uwatec", "Aladin Tec 2G", DC_FAMILY_UWATEC_SMART, 0x13, dc_filter_uwatec},
+ {"Uwatec", "Aladin 2G", DC_FAMILY_UWATEC_SMART, 0x13, dc_filter_uwatec},
+ {"Subgear","XP-10", DC_FAMILY_UWATEC_SMART, 0x13, dc_filter_uwatec},
+ {"Uwatec", "Smart Com", DC_FAMILY_UWATEC_SMART, 0x14, dc_filter_uwatec},
+ {"Uwatec", "Aladin 2G", DC_FAMILY_UWATEC_SMART, 0x15, dc_filter_uwatec},
+ {"Uwatec", "Aladin Tec 3G", DC_FAMILY_UWATEC_SMART, 0x15, dc_filter_uwatec},
+ {"Uwatec", "Aladin Sport", DC_FAMILY_UWATEC_SMART, 0x15, dc_filter_uwatec},
+ {"Subgear","XP-3G", DC_FAMILY_UWATEC_SMART, 0x15, dc_filter_uwatec},
+ {"Uwatec", "Smart Tec", DC_FAMILY_UWATEC_SMART, 0x18, dc_filter_uwatec},
+ {"Uwatec", "Galileo Trimix",DC_FAMILY_UWATEC_SMART, 0x19, dc_filter_uwatec},
+ {"Uwatec", "Smart Z", DC_FAMILY_UWATEC_SMART, 0x1C, dc_filter_uwatec},
+ {"Subgear","XP Air", DC_FAMILY_UWATEC_SMART, 0x1C, dc_filter_uwatec},
#endif
/* Scubapro/Uwatec Meridian */
- {"Scubapro", "Meridian", DC_FAMILY_UWATEC_MERIDIAN, 0x20},
- {"Scubapro", "Mantis", DC_FAMILY_UWATEC_MERIDIAN, 0x20},
- {"Scubapro", "Chromis", DC_FAMILY_UWATEC_MERIDIAN, 0x24},
- {"Scubapro", "Mantis 2", DC_FAMILY_UWATEC_MERIDIAN, 0x26},
+ {"Scubapro", "Meridian", DC_FAMILY_UWATEC_MERIDIAN, 0x20, NULL},
+ {"Scubapro", "Mantis", DC_FAMILY_UWATEC_MERIDIAN, 0x20, NULL},
+ {"Scubapro", "Chromis", DC_FAMILY_UWATEC_MERIDIAN, 0x24, NULL},
+ {"Scubapro", "Mantis 2", DC_FAMILY_UWATEC_MERIDIAN, 0x26, NULL},
/* Scubapro G2 */
#if defined(USBHID) || defined(ENABLE_BLE)
- {"Scubapro", "Aladin Sport Matrix", DC_FAMILY_UWATEC_G2, 0x17},
- {"Scubapro", "Aladin Square", DC_FAMILY_UWATEC_G2, 0x22},
- {"Scubapro", "G2", DC_FAMILY_UWATEC_G2, 0x32},
+ {"Scubapro", "Aladin Sport Matrix", DC_FAMILY_UWATEC_G2, 0x17, dc_filter_uwatec},
+ {"Scubapro", "Aladin Square", DC_FAMILY_UWATEC_G2, 0x22, dc_filter_uwatec},
+ {"Scubapro", "G2", DC_FAMILY_UWATEC_G2, 0x32, dc_filter_uwatec},
#endif
/* Reefnet */
- {"Reefnet", "Sensus", DC_FAMILY_REEFNET_SENSUS, 1},
- {"Reefnet", "Sensus Pro", DC_FAMILY_REEFNET_SENSUSPRO, 2},
- {"Reefnet", "Sensus Ultra", DC_FAMILY_REEFNET_SENSUSULTRA, 3},
+ {"Reefnet", "Sensus", DC_FAMILY_REEFNET_SENSUS, 1, NULL},
+ {"Reefnet", "Sensus Pro", DC_FAMILY_REEFNET_SENSUSPRO, 2, NULL},
+ {"Reefnet", "Sensus Ultra", DC_FAMILY_REEFNET_SENSUSULTRA, 3, NULL},
/* Oceanic VT Pro */
- {"Aeris", "500 AI", DC_FAMILY_OCEANIC_VTPRO, 0x4151},
- {"Oceanic", "Versa Pro", DC_FAMILY_OCEANIC_VTPRO, 0x4155},
- {"Aeris", "Atmos 2", DC_FAMILY_OCEANIC_VTPRO, 0x4158},
- {"Oceanic", "Pro Plus 2", DC_FAMILY_OCEANIC_VTPRO, 0x4159},
- {"Aeris", "Atmos AI", DC_FAMILY_OCEANIC_VTPRO, 0x4244},
- {"Oceanic", "VT Pro", DC_FAMILY_OCEANIC_VTPRO, 0x4245},
- {"Sherwood", "Wisdom", DC_FAMILY_OCEANIC_VTPRO, 0x4246},
- {"Aeris", "Elite", DC_FAMILY_OCEANIC_VTPRO, 0x424F},
+ {"Aeris", "500 AI", DC_FAMILY_OCEANIC_VTPRO, 0x4151, NULL},
+ {"Oceanic", "Versa Pro", DC_FAMILY_OCEANIC_VTPRO, 0x4155, NULL},
+ {"Aeris", "Atmos 2", DC_FAMILY_OCEANIC_VTPRO, 0x4158, NULL},
+ {"Oceanic", "Pro Plus 2", DC_FAMILY_OCEANIC_VTPRO, 0x4159, NULL},
+ {"Aeris", "Atmos AI", DC_FAMILY_OCEANIC_VTPRO, 0x4244, NULL},
+ {"Oceanic", "VT Pro", DC_FAMILY_OCEANIC_VTPRO, 0x4245, NULL},
+ {"Sherwood", "Wisdom", DC_FAMILY_OCEANIC_VTPRO, 0x4246, NULL},
+ {"Aeris", "Elite", DC_FAMILY_OCEANIC_VTPRO, 0x424F, NULL},
/* Oceanic Veo 250 */
- {"Genesis", "React Pro", DC_FAMILY_OCEANIC_VEO250, 0x4247},
- {"Oceanic", "Veo 200", DC_FAMILY_OCEANIC_VEO250, 0x424B},
- {"Oceanic", "Veo 250", DC_FAMILY_OCEANIC_VEO250, 0x424C},
- {"Seemann", "XP5", DC_FAMILY_OCEANIC_VEO250, 0x4251},
- {"Oceanic", "Veo 180", DC_FAMILY_OCEANIC_VEO250, 0x4252},
- {"Aeris", "XR-2", DC_FAMILY_OCEANIC_VEO250, 0x4255},
- {"Sherwood", "Insight", DC_FAMILY_OCEANIC_VEO250, 0x425A},
- {"Hollis", "DG02", DC_FAMILY_OCEANIC_VEO250, 0x4352},
+ {"Genesis", "React Pro", DC_FAMILY_OCEANIC_VEO250, 0x4247, NULL},
+ {"Oceanic", "Veo 200", DC_FAMILY_OCEANIC_VEO250, 0x424B, NULL},
+ {"Oceanic", "Veo 250", DC_FAMILY_OCEANIC_VEO250, 0x424C, NULL},
+ {"Seemann", "XP5", DC_FAMILY_OCEANIC_VEO250, 0x4251, NULL},
+ {"Oceanic", "Veo 180", DC_FAMILY_OCEANIC_VEO250, 0x4252, NULL},
+ {"Aeris", "XR-2", DC_FAMILY_OCEANIC_VEO250, 0x4255, NULL},
+ {"Sherwood", "Insight", DC_FAMILY_OCEANIC_VEO250, 0x425A, NULL},
+ {"Hollis", "DG02", DC_FAMILY_OCEANIC_VEO250, 0x4352, NULL},
/* Oceanic Atom 2.0 */
- {"Oceanic", "Atom 1.0", DC_FAMILY_OCEANIC_ATOM2, 0x4250},
- {"Aeris", "Epic", DC_FAMILY_OCEANIC_ATOM2, 0x4257},
- {"Oceanic", "VT3", DC_FAMILY_OCEANIC_ATOM2, 0x4258},
- {"Aeris", "Elite T3", DC_FAMILY_OCEANIC_ATOM2, 0x4259},
- {"Oceanic", "Atom 2.0", DC_FAMILY_OCEANIC_ATOM2, 0x4342},
- {"Oceanic", "Geo", DC_FAMILY_OCEANIC_ATOM2, 0x4344},
- {"Aeris", "Manta", DC_FAMILY_OCEANIC_ATOM2, 0x4345},
- {"Aeris", "XR-1 NX", DC_FAMILY_OCEANIC_ATOM2, 0x4346},
- {"Oceanic", "Datamask", DC_FAMILY_OCEANIC_ATOM2, 0x4347},
- {"Aeris", "Compumask", DC_FAMILY_OCEANIC_ATOM2, 0x4348},
- {"Aeris", "F10", DC_FAMILY_OCEANIC_ATOM2, 0x434D},
- {"Oceanic", "OC1", DC_FAMILY_OCEANIC_ATOM2, 0x434E},
- {"Sherwood", "Wisdom 2", DC_FAMILY_OCEANIC_ATOM2, 0x4350},
- {"Sherwood", "Insight 2", DC_FAMILY_OCEANIC_ATOM2, 0x4353},
- {"Genesis", "React Pro White", DC_FAMILY_OCEANIC_ATOM2, 0x4354},
- {"Tusa", "Element II (IQ-750)", DC_FAMILY_OCEANIC_ATOM2, 0x4357},
- {"Oceanic", "Veo 1.0", DC_FAMILY_OCEANIC_ATOM2, 0x4358},
- {"Oceanic", "Veo 2.0", DC_FAMILY_OCEANIC_ATOM2, 0x4359},
- {"Oceanic", "Veo 3.0", DC_FAMILY_OCEANIC_ATOM2, 0x435A},
- {"Tusa", "Zen (IQ-900)", DC_FAMILY_OCEANIC_ATOM2, 0x4441},
- {"Tusa", "Zen Air (IQ-950)", DC_FAMILY_OCEANIC_ATOM2, 0x4442},
- {"Aeris", "Atmos AI 2", DC_FAMILY_OCEANIC_ATOM2, 0x4443},
- {"Oceanic", "Pro Plus 2.1", DC_FAMILY_OCEANIC_ATOM2, 0x4444},
- {"Oceanic", "Geo 2.0", DC_FAMILY_OCEANIC_ATOM2, 0x4446},
- {"Oceanic", "VT4", DC_FAMILY_OCEANIC_ATOM2, 0x4447},
- {"Oceanic", "OC1", DC_FAMILY_OCEANIC_ATOM2, 0x4449},
- {"Beuchat", "Voyager 2G", DC_FAMILY_OCEANIC_ATOM2, 0x444B},
- {"Oceanic", "Atom 3.0", DC_FAMILY_OCEANIC_ATOM2, 0x444C},
- {"Hollis", "DG03", DC_FAMILY_OCEANIC_ATOM2, 0x444D},
- {"Oceanic", "OCS", DC_FAMILY_OCEANIC_ATOM2, 0x4450},
- {"Oceanic", "OC1", DC_FAMILY_OCEANIC_ATOM2, 0x4451},
- {"Oceanic", "VT 4.1", DC_FAMILY_OCEANIC_ATOM2, 0x4452},
- {"Aeris", "Epic", DC_FAMILY_OCEANIC_ATOM2, 0x4453},
- {"Aeris", "Elite T3", DC_FAMILY_OCEANIC_ATOM2, 0x4455},
- {"Oceanic", "Atom 3.1", DC_FAMILY_OCEANIC_ATOM2, 0x4456},
- {"Aeris", "A300 AI", DC_FAMILY_OCEANIC_ATOM2, 0x4457},
- {"Sherwood", "Wisdom 3", DC_FAMILY_OCEANIC_ATOM2, 0x4458},
- {"Aeris", "A300", DC_FAMILY_OCEANIC_ATOM2, 0x445A},
- {"Hollis", "TX1", DC_FAMILY_OCEANIC_ATOM2, 0x4542},
- {"Beuchat", "Mundial 2", DC_FAMILY_OCEANIC_ATOM2, 0x4543},
- {"Sherwood", "Amphos", DC_FAMILY_OCEANIC_ATOM2, 0x4545},
- {"Sherwood", "Amphos Air", DC_FAMILY_OCEANIC_ATOM2, 0x4546},
- {"Oceanic", "Pro Plus 3", DC_FAMILY_OCEANIC_ATOM2, 0x4548},
- {"Aeris", "F11", DC_FAMILY_OCEANIC_ATOM2, 0x4549},
- {"Oceanic", "OCi", DC_FAMILY_OCEANIC_ATOM2, 0x454B},
- {"Aeris", "A300CS", DC_FAMILY_OCEANIC_ATOM2, 0x454C},
- {"Beuchat", "Mundial 3", DC_FAMILY_OCEANIC_ATOM2, 0x4550},
- {"Oceanic", "F10", DC_FAMILY_OCEANIC_ATOM2, 0x4553},
- {"Oceanic", "F11", DC_FAMILY_OCEANIC_ATOM2, 0x4554},
- {"Subgear", "XP-Air", DC_FAMILY_OCEANIC_ATOM2, 0x4555},
- {"Sherwood", "Vision", DC_FAMILY_OCEANIC_ATOM2, 0x4556},
- {"Oceanic", "VTX", DC_FAMILY_OCEANIC_ATOM2, 0x4557},
- {"Aqualung", "i300", DC_FAMILY_OCEANIC_ATOM2, 0x4559},
- {"Aqualung", "i750TC", DC_FAMILY_OCEANIC_ATOM2, 0x455A},
- {"Aqualung", "i450T", DC_FAMILY_OCEANIC_ATOM2, 0x4641},
- {"Aqualung", "i550", DC_FAMILY_OCEANIC_ATOM2, 0x4642},
- {"Aqualung", "i200", DC_FAMILY_OCEANIC_ATOM2, 0x4646},
+ {"Oceanic", "Atom 1.0", DC_FAMILY_OCEANIC_ATOM2, 0x4250, NULL},
+ {"Aeris", "Epic", DC_FAMILY_OCEANIC_ATOM2, 0x4257, NULL},
+ {"Oceanic", "VT3", DC_FAMILY_OCEANIC_ATOM2, 0x4258, NULL},
+ {"Aeris", "Elite T3", DC_FAMILY_OCEANIC_ATOM2, 0x4259, NULL},
+ {"Oceanic", "Atom 2.0", DC_FAMILY_OCEANIC_ATOM2, 0x4342, NULL},
+ {"Oceanic", "Geo", DC_FAMILY_OCEANIC_ATOM2, 0x4344, NULL},
+ {"Aeris", "Manta", DC_FAMILY_OCEANIC_ATOM2, 0x4345, NULL},
+ {"Aeris", "XR-1 NX", DC_FAMILY_OCEANIC_ATOM2, 0x4346, NULL},
+ {"Oceanic", "Datamask", DC_FAMILY_OCEANIC_ATOM2, 0x4347, NULL},
+ {"Aeris", "Compumask", DC_FAMILY_OCEANIC_ATOM2, 0x4348, NULL},
+ {"Aeris", "F10", DC_FAMILY_OCEANIC_ATOM2, 0x434D, NULL},
+ {"Oceanic", "OC1", DC_FAMILY_OCEANIC_ATOM2, 0x434E, NULL},
+ {"Sherwood", "Wisdom 2", DC_FAMILY_OCEANIC_ATOM2, 0x4350, NULL},
+ {"Sherwood", "Insight 2", DC_FAMILY_OCEANIC_ATOM2, 0x4353, NULL},
+ {"Genesis", "React Pro White", DC_FAMILY_OCEANIC_ATOM2, 0x4354, NULL},
+ {"Tusa", "Element II (IQ-750)", DC_FAMILY_OCEANIC_ATOM2, 0x4357, NULL},
+ {"Oceanic", "Veo 1.0", DC_FAMILY_OCEANIC_ATOM2, 0x4358, NULL},
+ {"Oceanic", "Veo 2.0", DC_FAMILY_OCEANIC_ATOM2, 0x4359, NULL},
+ {"Oceanic", "Veo 3.0", DC_FAMILY_OCEANIC_ATOM2, 0x435A, NULL},
+ {"Tusa", "Zen (IQ-900)", DC_FAMILY_OCEANIC_ATOM2, 0x4441, NULL},
+ {"Tusa", "Zen Air (IQ-950)", DC_FAMILY_OCEANIC_ATOM2, 0x4442, NULL},
+ {"Aeris", "Atmos AI 2", DC_FAMILY_OCEANIC_ATOM2, 0x4443, NULL},
+ {"Oceanic", "Pro Plus 2.1", DC_FAMILY_OCEANIC_ATOM2, 0x4444, NULL},
+ {"Oceanic", "Geo 2.0", DC_FAMILY_OCEANIC_ATOM2, 0x4446, NULL},
+ {"Oceanic", "VT4", DC_FAMILY_OCEANIC_ATOM2, 0x4447, NULL},
+ {"Oceanic", "OC1", DC_FAMILY_OCEANIC_ATOM2, 0x4449, NULL},
+ {"Beuchat", "Voyager 2G", DC_FAMILY_OCEANIC_ATOM2, 0x444B, NULL},
+ {"Oceanic", "Atom 3.0", DC_FAMILY_OCEANIC_ATOM2, 0x444C, NULL},
+ {"Hollis", "DG03", DC_FAMILY_OCEANIC_ATOM2, 0x444D, NULL},
+ {"Oceanic", "OCS", DC_FAMILY_OCEANIC_ATOM2, 0x4450, NULL},
+ {"Oceanic", "OC1", DC_FAMILY_OCEANIC_ATOM2, 0x4451, NULL},
+ {"Oceanic", "VT 4.1", DC_FAMILY_OCEANIC_ATOM2, 0x4452, NULL},
+ {"Aeris", "Epic", DC_FAMILY_OCEANIC_ATOM2, 0x4453, NULL},
+ {"Aeris", "Elite T3", DC_FAMILY_OCEANIC_ATOM2, 0x4455, NULL},
+ {"Oceanic", "Atom 3.1", DC_FAMILY_OCEANIC_ATOM2, 0x4456, NULL},
+ {"Aeris", "A300 AI", DC_FAMILY_OCEANIC_ATOM2, 0x4457, NULL},
+ {"Sherwood", "Wisdom 3", DC_FAMILY_OCEANIC_ATOM2, 0x4458, NULL},
+ {"Aeris", "A300", DC_FAMILY_OCEANIC_ATOM2, 0x445A, NULL},
+ {"Hollis", "TX1", DC_FAMILY_OCEANIC_ATOM2, 0x4542, NULL},
+ {"Beuchat", "Mundial 2", DC_FAMILY_OCEANIC_ATOM2, 0x4543, NULL},
+ {"Sherwood", "Amphos", DC_FAMILY_OCEANIC_ATOM2, 0x4545, NULL},
+ {"Sherwood", "Amphos Air", DC_FAMILY_OCEANIC_ATOM2, 0x4546, NULL},
+ {"Oceanic", "Pro Plus 3", DC_FAMILY_OCEANIC_ATOM2, 0x4548, NULL},
+ {"Aeris", "F11", DC_FAMILY_OCEANIC_ATOM2, 0x4549, NULL},
+ {"Oceanic", "OCi", DC_FAMILY_OCEANIC_ATOM2, 0x454B, NULL},
+ {"Aeris", "A300CS", DC_FAMILY_OCEANIC_ATOM2, 0x454C, NULL},
+ {"Beuchat", "Mundial 3", DC_FAMILY_OCEANIC_ATOM2, 0x4550, NULL},
+ {"Oceanic", "F10", DC_FAMILY_OCEANIC_ATOM2, 0x4553, NULL},
+ {"Oceanic", "F11", DC_FAMILY_OCEANIC_ATOM2, 0x4554, NULL},
+ {"Subgear", "XP-Air", DC_FAMILY_OCEANIC_ATOM2, 0x4555, NULL},
+ {"Sherwood", "Vision", DC_FAMILY_OCEANIC_ATOM2, 0x4556, NULL},
+ {"Oceanic", "VTX", DC_FAMILY_OCEANIC_ATOM2, 0x4557, NULL},
+ {"Aqualung", "i300", DC_FAMILY_OCEANIC_ATOM2, 0x4559, NULL},
+ {"Aqualung", "i750TC", DC_FAMILY_OCEANIC_ATOM2, 0x455A, NULL},
+ {"Aqualung", "i450T", DC_FAMILY_OCEANIC_ATOM2, 0x4641, NULL},
+ {"Aqualung", "i550", DC_FAMILY_OCEANIC_ATOM2, 0x4642, NULL},
+ {"Aqualung", "i200", DC_FAMILY_OCEANIC_ATOM2, 0x4646, NULL},
/* Mares Nemo */
- {"Mares", "Nemo", DC_FAMILY_MARES_NEMO, 0},
- {"Mares", "Nemo Steel", DC_FAMILY_MARES_NEMO, 0},
- {"Mares", "Nemo Titanium",DC_FAMILY_MARES_NEMO, 0},
- {"Mares", "Nemo Excel", DC_FAMILY_MARES_NEMO, 17},
- {"Mares", "Nemo Apneist", DC_FAMILY_MARES_NEMO, 18},
+ {"Mares", "Nemo", DC_FAMILY_MARES_NEMO, 0, NULL},
+ {"Mares", "Nemo Steel", DC_FAMILY_MARES_NEMO, 0, NULL},
+ {"Mares", "Nemo Titanium",DC_FAMILY_MARES_NEMO, 0, NULL},
+ {"Mares", "Nemo Excel", DC_FAMILY_MARES_NEMO, 17, NULL},
+ {"Mares", "Nemo Apneist", DC_FAMILY_MARES_NEMO, 18, NULL},
/* Mares Puck */
- {"Mares", "Puck", DC_FAMILY_MARES_PUCK, 7},
- {"Mares", "Puck Air", DC_FAMILY_MARES_PUCK, 19},
- {"Mares", "Nemo Air", DC_FAMILY_MARES_PUCK, 4},
- {"Mares", "Nemo Wide", DC_FAMILY_MARES_PUCK, 1},
+ {"Mares", "Puck", DC_FAMILY_MARES_PUCK, 7, NULL},
+ {"Mares", "Puck Air", DC_FAMILY_MARES_PUCK, 19, NULL},
+ {"Mares", "Nemo Air", DC_FAMILY_MARES_PUCK, 4, NULL},
+ {"Mares", "Nemo Wide", DC_FAMILY_MARES_PUCK, 1, NULL},
/* Mares Darwin */
- {"Mares", "Darwin", DC_FAMILY_MARES_DARWIN , 0},
- {"Mares", "M1", DC_FAMILY_MARES_DARWIN , 0},
- {"Mares", "M2", DC_FAMILY_MARES_DARWIN , 0},
- {"Mares", "Darwin Air", DC_FAMILY_MARES_DARWIN , 1},
- {"Mares", "Airlab", DC_FAMILY_MARES_DARWIN , 1},
+ {"Mares", "Darwin", DC_FAMILY_MARES_DARWIN , 0, NULL},
+ {"Mares", "M1", DC_FAMILY_MARES_DARWIN , 0, NULL},
+ {"Mares", "M2", DC_FAMILY_MARES_DARWIN , 0, NULL},
+ {"Mares", "Darwin Air", DC_FAMILY_MARES_DARWIN , 1, NULL},
+ {"Mares", "Airlab", DC_FAMILY_MARES_DARWIN , 1, NULL},
/* Mares Icon HD */
- {"Mares", "Matrix", DC_FAMILY_MARES_ICONHD , 0x0F},
- {"Mares", "Smart", DC_FAMILY_MARES_ICONHD , 0x000010},
- {"Mares", "Smart Apnea", DC_FAMILY_MARES_ICONHD , 0x010010},
- {"Mares", "Icon HD", DC_FAMILY_MARES_ICONHD , 0x14},
- {"Mares", "Icon HD Net Ready", DC_FAMILY_MARES_ICONHD , 0x15},
- {"Mares", "Puck Pro", DC_FAMILY_MARES_ICONHD , 0x18},
- {"Mares", "Nemo Wide 2", DC_FAMILY_MARES_ICONHD , 0x19},
- {"Mares", "Puck 2", DC_FAMILY_MARES_ICONHD , 0x1F},
- {"Mares", "Quad Air", DC_FAMILY_MARES_ICONHD , 0x23},
- {"Mares", "Quad", DC_FAMILY_MARES_ICONHD , 0x29},
+ {"Mares", "Matrix", DC_FAMILY_MARES_ICONHD , 0x0F, NULL},
+ {"Mares", "Smart", DC_FAMILY_MARES_ICONHD , 0x000010, NULL},
+ {"Mares", "Smart Apnea", DC_FAMILY_MARES_ICONHD , 0x010010, NULL},
+ {"Mares", "Icon HD", DC_FAMILY_MARES_ICONHD , 0x14, NULL},
+ {"Mares", "Icon HD Net Ready", DC_FAMILY_MARES_ICONHD , 0x15, NULL},
+ {"Mares", "Puck Pro", DC_FAMILY_MARES_ICONHD , 0x18, NULL},
+ {"Mares", "Nemo Wide 2", DC_FAMILY_MARES_ICONHD , 0x19, NULL},
+ {"Mares", "Puck 2", DC_FAMILY_MARES_ICONHD , 0x1F, NULL},
+ {"Mares", "Quad Air", DC_FAMILY_MARES_ICONHD , 0x23, NULL},
+ {"Mares", "Quad", DC_FAMILY_MARES_ICONHD , 0x29, NULL},
/* Heinrichs Weikamp */
- {"Heinrichs Weikamp", "OSTC", DC_FAMILY_HW_OSTC, 0},
- {"Heinrichs Weikamp", "OSTC Mk2", DC_FAMILY_HW_OSTC, 1},
- {"Heinrichs Weikamp", "OSTC 2N", DC_FAMILY_HW_OSTC, 2},
- {"Heinrichs Weikamp", "OSTC 2C", DC_FAMILY_HW_OSTC, 3},
- {"Heinrichs Weikamp", "Frog", DC_FAMILY_HW_FROG, 0},
- {"Heinrichs Weikamp", "OSTC 2", DC_FAMILY_HW_OSTC3, 0x11},
- {"Heinrichs Weikamp", "OSTC 2", DC_FAMILY_HW_OSTC3, 0x13},
- {"Heinrichs Weikamp", "OSTC 2", DC_FAMILY_HW_OSTC3, 0x1B},
- {"Heinrichs Weikamp", "OSTC 3", DC_FAMILY_HW_OSTC3, 0x0A},
- {"Heinrichs Weikamp", "OSTC Plus", DC_FAMILY_HW_OSTC3, 0x13},
- {"Heinrichs Weikamp", "OSTC Plus", DC_FAMILY_HW_OSTC3, 0x1A},
- {"Heinrichs Weikamp", "OSTC 4", DC_FAMILY_HW_OSTC3, 0x3B},
- {"Heinrichs Weikamp", "OSTC cR", DC_FAMILY_HW_OSTC3, 0x05},
- {"Heinrichs Weikamp", "OSTC cR", DC_FAMILY_HW_OSTC3, 0x07},
- {"Heinrichs Weikamp", "OSTC Sport", DC_FAMILY_HW_OSTC3, 0x12},
- {"Heinrichs Weikamp", "OSTC Sport", DC_FAMILY_HW_OSTC3, 0x13},
+ {"Heinrichs Weikamp", "OSTC", DC_FAMILY_HW_OSTC, 0, NULL},
+ {"Heinrichs Weikamp", "OSTC Mk2", DC_FAMILY_HW_OSTC, 1, NULL},
+ {"Heinrichs Weikamp", "OSTC 2N", DC_FAMILY_HW_OSTC, 2, NULL},
+ {"Heinrichs Weikamp", "OSTC 2C", DC_FAMILY_HW_OSTC, 3, NULL},
+ {"Heinrichs Weikamp", "Frog", DC_FAMILY_HW_FROG, 0, dc_filter_hw},
+ {"Heinrichs Weikamp", "OSTC 2", DC_FAMILY_HW_OSTC3, 0x11, dc_filter_hw},
+ {"Heinrichs Weikamp", "OSTC 2", DC_FAMILY_HW_OSTC3, 0x13, dc_filter_hw},
+ {"Heinrichs Weikamp", "OSTC 2", DC_FAMILY_HW_OSTC3, 0x1B, dc_filter_hw},
+ {"Heinrichs Weikamp", "OSTC 3", DC_FAMILY_HW_OSTC3, 0x0A, dc_filter_hw},
+ {"Heinrichs Weikamp", "OSTC Plus", DC_FAMILY_HW_OSTC3, 0x13, dc_filter_hw},
+ {"Heinrichs Weikamp", "OSTC Plus", DC_FAMILY_HW_OSTC3, 0x1A, dc_filter_hw},
+ {"Heinrichs Weikamp", "OSTC 4", DC_FAMILY_HW_OSTC3, 0x3B, dc_filter_hw},
+ {"Heinrichs Weikamp", "OSTC cR", DC_FAMILY_HW_OSTC3, 0x05, dc_filter_hw},
+ {"Heinrichs Weikamp", "OSTC cR", DC_FAMILY_HW_OSTC3, 0x07, dc_filter_hw},
+ {"Heinrichs Weikamp", "OSTC Sport", DC_FAMILY_HW_OSTC3, 0x12, dc_filter_hw},
+ {"Heinrichs Weikamp", "OSTC Sport", DC_FAMILY_HW_OSTC3, 0x13, dc_filter_hw},
+ {"Heinrichs Weikamp", "OSTC 2 TR", DC_FAMILY_HW_OSTC3, 0x33, dc_filter_hw},
/* Cressi Edy */
- {"Tusa", "IQ-700", DC_FAMILY_CRESSI_EDY, 0x05},
- {"Cressi", "Edy", DC_FAMILY_CRESSI_EDY, 0x08},
+ {"Tusa", "IQ-700", DC_FAMILY_CRESSI_EDY, 0x05, NULL},
+ {"Cressi", "Edy", DC_FAMILY_CRESSI_EDY, 0x08, NULL},
/* Cressi Leonardo */
- {"Cressi", "Leonardo", DC_FAMILY_CRESSI_LEONARDO, 1},
- {"Cressi", "Giotto", DC_FAMILY_CRESSI_LEONARDO, 4},
- {"Cressi", "Newton", DC_FAMILY_CRESSI_LEONARDO, 5},
- {"Cressi", "Drake", DC_FAMILY_CRESSI_LEONARDO, 6},
+ {"Cressi", "Leonardo", DC_FAMILY_CRESSI_LEONARDO, 1, NULL},
+ {"Cressi", "Giotto", DC_FAMILY_CRESSI_LEONARDO, 4, NULL},
+ {"Cressi", "Newton", DC_FAMILY_CRESSI_LEONARDO, 5, NULL},
+ {"Cressi", "Drake", DC_FAMILY_CRESSI_LEONARDO, 6, NULL},
/* Zeagle N2iTiON3 */
- {"Zeagle", "N2iTiON3", DC_FAMILY_ZEAGLE_N2ITION3, 0},
- {"Apeks", "Quantum X", DC_FAMILY_ZEAGLE_N2ITION3, 0},
- {"Dive Rite", "NiTek Trio", DC_FAMILY_ZEAGLE_N2ITION3, 0},
- {"Scubapro", "XTender 5", DC_FAMILY_ZEAGLE_N2ITION3, 0},
+ {"Zeagle", "N2iTiON3", DC_FAMILY_ZEAGLE_N2ITION3, 0, NULL},
+ {"Apeks", "Quantum X", DC_FAMILY_ZEAGLE_N2ITION3, 0, NULL},
+ {"Dive Rite", "NiTek Trio", DC_FAMILY_ZEAGLE_N2ITION3, 0, NULL},
+ {"Scubapro", "XTender 5", DC_FAMILY_ZEAGLE_N2ITION3, 0, NULL},
/* Atomic Aquatics Cobalt */
#ifdef HAVE_LIBUSB
- {"Atomic Aquatics", "Cobalt", DC_FAMILY_ATOMICS_COBALT, 0},
- {"Atomic Aquatics", "Cobalt 2", DC_FAMILY_ATOMICS_COBALT, 2},
+ {"Atomic Aquatics", "Cobalt", DC_FAMILY_ATOMICS_COBALT, 0, NULL},
+ {"Atomic Aquatics", "Cobalt 2", DC_FAMILY_ATOMICS_COBALT, 2, NULL},
#endif
/* Shearwater Predator */
- {"Shearwater", "Predator", DC_FAMILY_SHEARWATER_PREDATOR, 2},
- /* Shearwater Petrel family */
- {"Shearwater", "Petrel", DC_FAMILY_SHEARWATER_PETREL, 3},
- {"Shearwater", "Petrel 2", DC_FAMILY_SHEARWATER_PETREL, 3},
- {"Shearwater", "Nerd", DC_FAMILY_SHEARWATER_PETREL, 4},
- {"Shearwater", "Perdix", DC_FAMILY_SHEARWATER_PETREL, 5},
- {"Shearwater", "Perdix AI", DC_FAMILY_SHEARWATER_PETREL, 6},
- {"Shearwater", "Nerd 2", DC_FAMILY_SHEARWATER_PETREL, 7},
+ {"Shearwater", "Predator", DC_FAMILY_SHEARWATER_PREDATOR, 2, dc_filter_shearwater},
+ /* Shearwater Petrel */
+ {"Shearwater", "Petrel", DC_FAMILY_SHEARWATER_PETREL, 3, dc_filter_shearwater},
+ {"Shearwater", "Petrel 2", DC_FAMILY_SHEARWATER_PETREL, 3, dc_filter_shearwater},
+ {"Shearwater", "Nerd", DC_FAMILY_SHEARWATER_PETREL, 4, dc_filter_shearwater},
+ {"Shearwater", "Perdix", DC_FAMILY_SHEARWATER_PETREL, 5, dc_filter_shearwater},
+ {"Shearwater", "Perdix AI", DC_FAMILY_SHEARWATER_PETREL, 6, dc_filter_shearwater},
+ {"Shearwater", "Nerd 2", DC_FAMILY_SHEARWATER_PETREL, 7, dc_filter_shearwater},
/* Dive Rite NiTek Q */
- {"Dive Rite", "NiTek Q", DC_FAMILY_DIVERITE_NITEKQ, 0},
+ {"Dive Rite", "NiTek Q", DC_FAMILY_DIVERITE_NITEKQ, 0, NULL},
/* Citizen Hyper Aqualand */
- {"Citizen", "Hyper Aqualand", DC_FAMILY_CITIZEN_AQUALAND, 0},
+ {"Citizen", "Hyper Aqualand", DC_FAMILY_CITIZEN_AQUALAND, 0, NULL},
/* DiveSystem/Ratio iDive */
- {"DiveSystem", "Orca", DC_FAMILY_DIVESYSTEM_IDIVE, 0x02},
- {"DiveSystem", "iDive Pro", DC_FAMILY_DIVESYSTEM_IDIVE, 0x03},
- {"DiveSystem", "iDive DAN", DC_FAMILY_DIVESYSTEM_IDIVE, 0x04},
- {"DiveSystem", "iDive Tech", DC_FAMILY_DIVESYSTEM_IDIVE, 0x05},
- {"DiveSystem", "iDive Reb", DC_FAMILY_DIVESYSTEM_IDIVE, 0x06},
- {"DiveSystem", "iDive Stealth", DC_FAMILY_DIVESYSTEM_IDIVE, 0x07},
- {"DiveSystem", "iDive Free", DC_FAMILY_DIVESYSTEM_IDIVE, 0x08},
- {"DiveSystem", "iDive Easy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x09},
- {"DiveSystem", "iDive X3M", DC_FAMILY_DIVESYSTEM_IDIVE, 0x0A},
- {"DiveSystem", "iDive Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x0B},
- {"Ratio", "iX3M Easy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x22},
- {"Ratio", "iX3M Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x23},
- {"Ratio", "iX3M Tech+", DC_FAMILY_DIVESYSTEM_IDIVE, 0x24},
- {"Ratio", "iX3M Reb", DC_FAMILY_DIVESYSTEM_IDIVE, 0x25},
- {"Ratio", "iX3M Pro Easy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x32},
- {"Ratio", "iX3M Pro Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x34},
- {"Ratio", "iX3M Pro Tech+",DC_FAMILY_DIVESYSTEM_IDIVE, 0x35},
- {"Ratio", "iDive Free", DC_FAMILY_DIVESYSTEM_IDIVE, 0x40},
- {"Ratio", "iDive Easy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x42},
- {"Ratio", "iDive Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x44},
- {"Ratio", "iDive Tech+", DC_FAMILY_DIVESYSTEM_IDIVE, 0x45},
- {"Seac", "Jack", DC_FAMILY_DIVESYSTEM_IDIVE, 0x1000},
+ {"DiveSystem", "Orca", DC_FAMILY_DIVESYSTEM_IDIVE, 0x02, NULL},
+ {"DiveSystem", "iDive Pro", DC_FAMILY_DIVESYSTEM_IDIVE, 0x03, NULL},
+ {"DiveSystem", "iDive DAN", DC_FAMILY_DIVESYSTEM_IDIVE, 0x04, NULL},
+ {"DiveSystem", "iDive Tech", DC_FAMILY_DIVESYSTEM_IDIVE, 0x05, NULL},
+ {"DiveSystem", "iDive Reb", DC_FAMILY_DIVESYSTEM_IDIVE, 0x06, NULL},
+ {"DiveSystem", "iDive Stealth", DC_FAMILY_DIVESYSTEM_IDIVE, 0x07, NULL},
+ {"DiveSystem", "iDive Free", DC_FAMILY_DIVESYSTEM_IDIVE, 0x08, NULL},
+ {"DiveSystem", "iDive Easy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x09, NULL},
+ {"DiveSystem", "iDive X3M", DC_FAMILY_DIVESYSTEM_IDIVE, 0x0A, NULL},
+ {"DiveSystem", "iDive Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x0B, NULL},
+ {"Ratio", "iX3M Easy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x22, NULL},
+ {"Ratio", "iX3M Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x23, NULL},
+ {"Ratio", "iX3M Tech+", DC_FAMILY_DIVESYSTEM_IDIVE, 0x24, NULL},
+ {"Ratio", "iX3M Reb", DC_FAMILY_DIVESYSTEM_IDIVE, 0x25, NULL},
+ {"Ratio", "iX3M Pro Easy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x32, NULL},
+ {"Ratio", "iX3M Pro Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x34, NULL},
+ {"Ratio", "iX3M Pro Tech+",DC_FAMILY_DIVESYSTEM_IDIVE, 0x35, NULL},
+ {"Ratio", "iDive Free", DC_FAMILY_DIVESYSTEM_IDIVE, 0x40, NULL},
+ {"Ratio", "iDive Easy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x42, NULL},
+ {"Ratio", "iDive Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x44, NULL},
+ {"Ratio", "iDive Tech+", DC_FAMILY_DIVESYSTEM_IDIVE, 0x45, NULL},
+ {"Seac", "Jack", DC_FAMILY_DIVESYSTEM_IDIVE, 0x1000, NULL},
/* Cochran Commander */
- {"Cochran", "Commander TM", DC_FAMILY_COCHRAN_COMMANDER, 0},
- {"Cochran", "Commander I", DC_FAMILY_COCHRAN_COMMANDER, 1},
- {"Cochran", "Commander II", DC_FAMILY_COCHRAN_COMMANDER, 2},
- {"Cochran", "EMC-14", DC_FAMILY_COCHRAN_COMMANDER, 3},
- {"Cochran", "EMC-16", DC_FAMILY_COCHRAN_COMMANDER, 4},
- {"Cochran", "EMC-20H", DC_FAMILY_COCHRAN_COMMANDER, 5},
+ {"Cochran", "Commander TM", DC_FAMILY_COCHRAN_COMMANDER, 0, NULL},
+ {"Cochran", "Commander I", DC_FAMILY_COCHRAN_COMMANDER, 1, NULL},
+ {"Cochran", "Commander II", DC_FAMILY_COCHRAN_COMMANDER, 2, NULL},
+ {"Cochran", "EMC-14", DC_FAMILY_COCHRAN_COMMANDER, 3, NULL},
+ {"Cochran", "EMC-16", DC_FAMILY_COCHRAN_COMMANDER, 4, NULL},
+ {"Cochran", "EMC-20H", DC_FAMILY_COCHRAN_COMMANDER, 5, NULL},
};
-typedef struct dc_descriptor_iterator_t {
- dc_iterator_t base;
- size_t current;
-} dc_descriptor_iterator_t;
+static int
+dc_filter_internal_name (const char *name, const char *values[], size_t count)
+{
+ if (name == NULL)
+ return 0;
-static dc_status_t dc_descriptor_iterator_next (dc_iterator_t *iterator, void *item);
-static dc_status_t dc_descriptor_iterator_free (dc_iterator_t *iterator);
+ for (size_t i = 0; i < count; ++i) {
+ if (strcasecmp (name, values[i]) == 0) {
+ return 1;
+ }
+ }
-static const dc_iterator_vtable_t dc_descriptor_iterator_vtable = {
- dc_descriptor_iterator_free,
- dc_descriptor_iterator_next
-};
+ return 0;
+}
+
+static int
+dc_filter_internal_usb (const dc_usb_desc_t *desc, const dc_usb_desc_t values[], size_t count)
+{
+ if (desc == NULL)
+ return 0;
+
+ for (size_t i = 0; i < count; ++i) {
+ if (desc->vid == values[i].vid &&
+ desc->pid == values[i].pid) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int dc_filter_uwatec (dc_transport_t transport, const void *userdata)
+{
+ static const char *irda[] = {
+ "Aladin Smart Com",
+ "Aladin Smart Pro",
+ "Aladin Smart Tec",
+ "Aladin Smart Z",
+ "Uwatec Aladin",
+ "UWATEC Galileo",
+ "UWATEC Galileo Sol",
+ };
+ static const dc_usb_desc_t usbhid[] = {
+ {0x2e6c, 0x3201}, // G2
+ {0xc251, 0x2006}, // Aladin Square
+ };
+
+ if (transport == DC_TRANSPORT_IRDA) {
+ return dc_filter_internal_name ((const char *) userdata, irda, C_ARRAY_SIZE(irda));
+ } else if (transport == DC_TRANSPORT_USBHID) {
+ return dc_filter_internal_usb ((const dc_usb_desc_t *) userdata, usbhid, C_ARRAY_SIZE(usbhid));
+ }
+
+ return 1;
+}
+
+static int dc_filter_suunto (dc_transport_t transport, const void *userdata)
+{
+ static const dc_usb_desc_t usbhid[] = {
+ {0x1493, 0x0030}, // Eon Steel
+ {0x1493, 0x0033}, // Eon Core
+ };
+
+ if (transport == DC_TRANSPORT_USBHID) {
+ return dc_filter_internal_usb ((const dc_usb_desc_t *) userdata, usbhid, C_ARRAY_SIZE(usbhid));
+ }
+
+ return 1;
+}
+
+static int dc_filter_hw (dc_transport_t transport, const void *userdata)
+{
+ if (transport == DC_TRANSPORT_BLUETOOTH) {
+ return strncasecmp ((const char *) userdata, "OSTC", 4) == 0 ||
+ strncasecmp ((const char *) userdata, "FROG", 4) == 0;
+ }
+
+ return 1;
+}
+
+static int dc_filter_shearwater (dc_transport_t transport, const void *userdata)
+{
+ static const char *bluetooth[] = {
+ "Predator",
+ "Petrel",
+ "Nerd",
+ "Perdix",
+ };
+
+ if (transport == DC_TRANSPORT_BLUETOOTH) {
+ return dc_filter_internal_name ((const char *) userdata, bluetooth, C_ARRAY_SIZE(bluetooth));
+ }
+
+ return 1;
+}
dc_status_t
dc_descriptor_iterator (dc_iterator_t **out)
@@ -352,11 +456,10 @@ dc_descriptor_iterator (dc_iterator_t **out)
if (out == NULL)
return DC_STATUS_INVALIDARGS;
- iterator = (dc_descriptor_iterator_t *) malloc (sizeof (dc_descriptor_iterator_t));
+ iterator = (dc_descriptor_iterator_t *) dc_iterator_allocate (NULL, &dc_descriptor_iterator_vtable);
if (iterator == NULL)
return DC_STATUS_NOMEMORY;
- iterator->base.vtable = &dc_descriptor_iterator_vtable;
iterator->current = 0;
*out = (dc_iterator_t *) iterator;
@@ -364,14 +467,6 @@ dc_descriptor_iterator (dc_iterator_t **out)
return DC_STATUS_SUCCESS;
}
-static dc_status_t
-dc_descriptor_iterator_free (dc_iterator_t *iterator)
-{
- free (iterator);
-
- return DC_STATUS_SUCCESS;
-}
-
static dc_status_t
dc_descriptor_iterator_next (dc_iterator_t *abstract, void *out)
{
@@ -452,3 +547,12 @@ dc_descriptor_get_transport (dc_descriptor_t *descriptor)
else
return DC_TRANSPORT_SERIAL;
}
+
+dc_filter_t
+dc_descriptor_get_filter (dc_descriptor_t *descriptor)
+{
+ if (descriptor == NULL)
+ return NULL;
+
+ return descriptor->filter;
+}
diff --git a/src/hw_ostc_parser.c b/src/hw_ostc_parser.c
index 6b065a9..f053a21 100644
--- a/src/hw_ostc_parser.c
+++ b/src/hw_ostc_parser.c
@@ -757,6 +757,7 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
switch (info[i].type) {
case 0: // Temperature
case 1: // Deco / NDL
+ case 6: // Tank pressure
if (info[i].size != 2) {
ERROR(abstract->context, "Unexpected sample size.");
return DC_STATUS_DATAFORMAT;
@@ -790,6 +791,7 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
unsigned int time = 0;
unsigned int nsamples = 0;
+ unsigned int tank = parser->initial != UNDEFINED ? parser->initial : 0;
unsigned int offset = header;
if (version == 0x23 || version == 0x24)
@@ -925,6 +927,7 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
idx--; /* Convert to a zero based index. */
sample.gasmix = idx;
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
+ tank = idx;
offset++;
length--;
}
@@ -1025,6 +1028,12 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
sample.cns = data[offset] / 100.0;
if (callback) callback (DC_SAMPLE_CNS, sample, userdata);
break;
+ case 6: // Tank pressure
+ value = array_uint16_le (data + offset);
+ sample.pressure.tank = tank;
+ sample.pressure.value = value / 10.0;
+ if (callback) callback (DC_SAMPLE_PRESSURE, sample, userdata);
+ break;
default: // Not yet used.
break;
}
diff --git a/src/iostream-private.h b/src/iostream-private.h
index 7f7be84..b9bd4f1 100644
--- a/src/iostream-private.h
+++ b/src/iostream-private.h
@@ -44,8 +44,6 @@ struct dc_iostream_vtable_t {
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);
diff --git a/src/iostream.c b/src/iostream.c
index e6c40ea..c1e3017 100644
--- a/src/iostream.c
+++ b/src/iostream.c
@@ -85,17 +85,6 @@ dc_iostream_set_latency (dc_iostream_t *iostream, unsigned int 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)
{
diff --git a/src/irda.c b/src/irda.c
index b38a502..d1aecfb 100644
--- a/src/irda.c
+++ b/src/irda.c
@@ -47,17 +47,51 @@
#include "common-private.h"
#include "context-private.h"
#include "iostream-private.h"
+#include "iterator-private.h"
+#include "descriptor-private.h"
#include "array.h"
#include "platform.h"
#define ISINSTANCE(device) dc_iostream_isinstance((device), &dc_irda_vtable)
+#define DISCOVER_MAX_DEVICES 16 // Maximum number of devices.
+#define DISCOVER_MAX_RETRIES 4 // Maximum number of retries.
+
+#ifdef _WIN32
+#define DISCOVER_BUFSIZE sizeof (DEVICELIST) + \
+ sizeof (IRDA_DEVICE_INFO) * (DISCOVER_MAX_DEVICES - 1)
+#else
+#define DISCOVER_BUFSIZE sizeof (struct irda_device_list) + \
+ sizeof (struct irda_device_info) * (DISCOVER_MAX_DEVICES - 1)
+#endif
+
+struct dc_irda_device_t {
+ unsigned int address;
+ unsigned int charset;
+ unsigned int hints;
+ char name[22];
+};
+
#ifdef IRDA
+static dc_status_t dc_irda_iterator_next (dc_iterator_t *iterator, void *item);
+
+typedef struct dc_irda_iterator_t {
+ dc_iterator_t base;
+ dc_irda_device_t items[DISCOVER_MAX_DEVICES];
+ size_t count;
+ size_t current;
+} dc_irda_iterator_t;
+
+static const dc_iterator_vtable_t dc_irda_iterator_vtable = {
+ sizeof(dc_irda_iterator_t),
+ dc_irda_iterator_next,
+ NULL,
+};
+
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 */
@@ -73,73 +107,72 @@ static const dc_iostream_vtable_t dc_irda_vtable = {
};
#endif
+unsigned int
+dc_irda_device_get_address (dc_irda_device_t *device)
+{
+ if (device == NULL)
+ return 0;
+
+ return device->address;
+}
+
+const char *
+dc_irda_device_get_name (dc_irda_device_t *device)
+{
+ if (device == NULL || device->name[0] == '\0')
+ return NULL;
+
+ return device->name;
+}
+
+void
+dc_irda_device_free (dc_irda_device_t *device)
+{
+ free (device);
+}
+
dc_status_t
-dc_irda_open (dc_iostream_t **out, dc_context_t *context)
+dc_irda_iterator_new (dc_iterator_t **out, dc_context_t *context, dc_descriptor_t *descriptor)
{
#ifdef IRDA
dc_status_t status = DC_STATUS_SUCCESS;
- dc_socket_t *device = NULL;
+ dc_irda_iterator_t *iterator = NULL;
if (out == NULL)
return DC_STATUS_INVALIDARGS;
- // Allocate memory.
- device = (dc_socket_t *) dc_iostream_allocate (context, &dc_irda_vtable);
- if (device == NULL) {
+ iterator = (dc_irda_iterator_t *) dc_iterator_allocate (context, &dc_irda_iterator_vtable);
+ if (iterator == NULL) {
SYSERROR (context, S_ENOMEM);
return DC_STATUS_NOMEMORY;
}
- // Open the socket.
- status = dc_socket_open (&device->base, AF_IRDA, SOCK_STREAM, 0);
+ // Initialize the socket library.
+ status = dc_socket_init (context);
if (status != DC_STATUS_SUCCESS) {
goto error_free;
}
- *out = (dc_iostream_t *) device;
-
- return DC_STATUS_SUCCESS;
-
-error_free:
- dc_iostream_deallocate ((dc_iostream_t *) device);
- return status;
-#else
- return DC_STATUS_UNSUPPORTED;
-#endif
-}
-
-#define DISCOVER_MAX_DEVICES 16 // Maximum number of devices.
-#define DISCOVER_MAX_RETRIES 4 // Maximum number of retries.
-
-#ifdef _WIN32
-#define DISCOVER_BUFSIZE sizeof (DEVICELIST) + \
- sizeof (IRDA_DEVICE_INFO) * (DISCOVER_MAX_DEVICES - 1)
-#else
-#define DISCOVER_BUFSIZE sizeof (struct irda_device_list) + \
- sizeof (struct irda_device_info) * (DISCOVER_MAX_DEVICES - 1)
-#endif
-
-dc_status_t
-dc_irda_discover (dc_iostream_t *abstract, dc_irda_callback_t callback, void *userdata)
-{
-#ifdef IRDA
- dc_socket_t *device = (dc_socket_t *) abstract;
-
- if (!ISINSTANCE (abstract))
- return DC_STATUS_INVALIDARGS;
+ // Open the socket.
+ int fd = socket (AF_IRDA, SOCK_STREAM, 0);
+ if (fd == S_INVALID) {
+ s_errcode_t errcode = S_ERRNO;
+ SYSERROR (context, errcode);
+ status = dc_socket_syserror(errcode);
+ goto error_socket_exit;
+ }
unsigned char data[DISCOVER_BUFSIZE] = {0};
#ifdef _WIN32
DEVICELIST *list = (DEVICELIST *) data;
- int size = sizeof (data);
#else
struct irda_device_list *list = (struct irda_device_list *) data;
- socklen_t size = sizeof (data);
#endif
+ s_socklen_t size = sizeof (data);
int rc = 0;
unsigned int nretries = 0;
- while ((rc = getsockopt (device->fd, SOL_IRLMP, IRLMP_ENUMDEVICES, (char*) data, &size)) != 0 ||
+ while ((rc = getsockopt (fd, SOL_IRLMP, IRLMP_ENUMDEVICES, (char *) data, &size)) != 0 ||
#ifdef _WIN32
list->numDevice == 0)
#else
@@ -153,14 +186,16 @@ dc_irda_discover (dc_iostream_t *abstract, dc_irda_callback_t callback, void *us
if (rc != 0) {
s_errcode_t errcode = S_ERRNO;
if (errcode != S_EAGAIN) {
- SYSERROR (abstract->context, errcode);
- return dc_socket_syserror(errcode);
+ SYSERROR (context, errcode);
+ status = dc_socket_syserror(errcode);
+ goto error_socket_close;
}
}
// Abort if the maximum number of retries is reached.
- if (nretries++ >= DISCOVER_MAX_RETRIES)
- return DC_STATUS_SUCCESS;
+ if (nretries++ >= DISCOVER_MAX_RETRIES) {
+ break;
+ }
// Restore the size parameter in case it was
// modified by the previous getsockopt call.
@@ -173,88 +208,109 @@ dc_irda_discover (dc_iostream_t *abstract, dc_irda_callback_t callback, void *us
#endif
}
- if (callback) {
+ S_CLOSE (fd);
+ dc_socket_exit (context);
+
+ dc_filter_t filter = dc_descriptor_get_filter (descriptor);
+
+ unsigned int count = 0;
#ifdef _WIN32
- for (unsigned int i = 0; i < list->numDevice; ++i) {
- const char *name = list->Device[i].irdaDeviceName;
- unsigned int address = array_uint32_le (list->Device[i].irdaDeviceID);
- unsigned int charset = list->Device[i].irdaCharSet;
- unsigned int hints = (list->Device[i].irdaDeviceHints1 << 8) +
- list->Device[i].irdaDeviceHints2;
+ for (size_t i = 0; i < list->numDevice; ++i) {
+ const char *name = list->Device[i].irdaDeviceName;
+ unsigned int address = array_uint32_le (list->Device[i].irdaDeviceID);
+ unsigned int charset = list->Device[i].irdaCharSet;
+ unsigned int hints = (list->Device[i].irdaDeviceHints1 << 8) +
+ list->Device[i].irdaDeviceHints2;
#else
- for (unsigned int i = 0; i < list->len; ++i) {
- const char *name = list->dev[i].info;
- unsigned int address = list->dev[i].daddr;
- unsigned int charset = list->dev[i].charset;
- unsigned int hints = array_uint16_be (list->dev[i].hints);
+ for (size_t i = 0; i < list->len; ++i) {
+ const char *name = list->dev[i].info;
+ unsigned int address = list->dev[i].daddr;
+ unsigned int charset = list->dev[i].charset;
+ unsigned int hints = array_uint16_be (list->dev[i].hints);
#endif
- INFO (abstract->context,
- "Discover: address=%08x, name=%s, charset=%02x, hints=%04x",
- address, name, charset, hints);
+ INFO (context, "Discover: address=%08x, name=%s, charset=%02x, hints=%04x",
+ address, name, charset, hints);
- callback (address, name, charset, hints, userdata);
+ if (filter && !filter (DC_TRANSPORT_IRDA, name)) {
+ continue;
}
+
+ strncpy(iterator->items[count].name, name, sizeof(iterator->items[count].name) - 1);
+ iterator->items[count].name[sizeof(iterator->items[count].name) - 1] = '\0';
+ iterator->items[count].address = address;
+ iterator->items[count].charset = charset;
+ iterator->items[count].hints = hints;
+ count++;
}
+ iterator->current = 0;
+ iterator->count = count;
+
+ *out = (dc_iterator_t *) iterator;
+
return DC_STATUS_SUCCESS;
+
+error_socket_close:
+ S_CLOSE (fd);
+error_socket_exit:
+ dc_socket_exit (context);
+error_free:
+ dc_iterator_deallocate ((dc_iterator_t *) iterator);
+ return status;
#else
return DC_STATUS_UNSUPPORTED;
#endif
}
-dc_status_t
-dc_irda_connect_name (dc_iostream_t *abstract, unsigned int address, const char *name)
-{
#ifdef IRDA
- dc_socket_t *device = (dc_socket_t *) abstract;
+static dc_status_t
+dc_irda_iterator_next (dc_iterator_t *abstract, void *out)
+{
+ dc_irda_iterator_t *iterator = (dc_irda_iterator_t *) abstract;
+ dc_irda_device_t *device = NULL;
- if (!ISINSTANCE (abstract))
- return DC_STATUS_INVALIDARGS;
+ if (iterator->current >= iterator->count)
+ return DC_STATUS_DONE;
- INFO (abstract->context, "Connect: address=%08x, name=%s", address, name ? name : "");
-
-#ifdef _WIN32
- SOCKADDR_IRDA peer;
- peer.irdaAddressFamily = AF_IRDA;
- peer.irdaDeviceID[0] = (address ) & 0xFF;
- peer.irdaDeviceID[1] = (address >> 8) & 0xFF;
- peer.irdaDeviceID[2] = (address >> 16) & 0xFF;
- peer.irdaDeviceID[3] = (address >> 24) & 0xFF;
- if (name) {
- strncpy (peer.irdaServiceName, name, sizeof(peer.irdaServiceName) - 1);
- peer.irdaServiceName[sizeof(peer.irdaServiceName) - 1] = '\0';
- } else {
- memset (peer.irdaServiceName, 0x00, sizeof(peer.irdaServiceName));
+ device = (dc_irda_device_t *) malloc (sizeof(dc_irda_device_t));
+ if (device == NULL) {
+ SYSERROR (abstract->context, S_ENOMEM);
+ return DC_STATUS_NOMEMORY;
}
-#else
- struct sockaddr_irda peer;
- peer.sir_family = AF_IRDA;
- peer.sir_addr = address;
- if (name) {
- strncpy (peer.sir_name, name, sizeof(peer.sir_name) - 1);
- peer.sir_name[sizeof(peer.sir_name) - 1] = '\0';
- } else {
- memset (peer.sir_name, 0x00, sizeof(peer.sir_name));
- }
-#endif
- return dc_socket_connect (&device->base, (struct sockaddr *) &peer, sizeof (peer));
-#else
- return DC_STATUS_UNSUPPORTED;
-#endif
+ *device = iterator->items[iterator->current++];
+
+ *(dc_irda_device_t **) out = device;
+
+ return DC_STATUS_SUCCESS;
}
+#endif
dc_status_t
-dc_irda_connect_lsap (dc_iostream_t *abstract, unsigned int address, unsigned int lsap)
+dc_irda_open (dc_iostream_t **out, dc_context_t *context, unsigned int address, unsigned int lsap)
{
#ifdef IRDA
- dc_socket_t *device = (dc_socket_t *) abstract;
+ dc_status_t status = DC_STATUS_SUCCESS;
+ dc_socket_t *device = NULL;
- if (!ISINSTANCE (abstract))
+ if (out == NULL)
return DC_STATUS_INVALIDARGS;
- INFO (abstract->context, "Connect: address=%08x, lsap=%u", address, lsap);
+ INFO (context, "Open: address=%08x, lsap=%u", address, lsap);
+
+ // Allocate memory.
+ device = (dc_socket_t *) dc_iostream_allocate (context, &dc_irda_vtable);
+ if (device == NULL) {
+ SYSERROR (context, S_ENOMEM);
+ return DC_STATUS_NOMEMORY;
+ }
+
+ // Open the socket.
+ status = dc_socket_open (&device->base, AF_IRDA, SOCK_STREAM, 0);
+ if (status != DC_STATUS_SUCCESS) {
+ goto error_free;
+ }
#ifdef _WIN32
SOCKADDR_IRDA peer;
@@ -272,7 +328,20 @@ dc_irda_connect_lsap (dc_iostream_t *abstract, unsigned int address, unsigned in
memset (peer.sir_name, 0x00, sizeof(peer.sir_name));
#endif
- return dc_socket_connect (&device->base, (struct sockaddr *) &peer, sizeof (peer));
+ status = dc_socket_connect (&device->base, (struct sockaddr *) &peer, sizeof (peer));
+ if (status != DC_STATUS_SUCCESS) {
+ goto error_close;
+ }
+
+ *out = (dc_iostream_t *) device;
+
+ return DC_STATUS_SUCCESS;
+
+error_close:
+ dc_socket_close (&device->base);
+error_free:
+ dc_iostream_deallocate ((dc_iostream_t *) device);
+ return status;
#else
return DC_STATUS_UNSUPPORTED;
#endif
diff --git a/src/irda.h b/src/irda.h
index c413963..92e9557 100644
--- a/src/irda.h
+++ b/src/irda.h
@@ -25,68 +25,66 @@
#include
#include
#include
+#include
+#include
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/**
- * IrDA enumeration callback.
- *
- * @param[in] address The IrDA device address.
- * @param[in] name The IrDA device name.
- * @param[in] charset The IrDA device character set.
- * @param[in] hints The IrDA device hints.
- * @param[in] userdata The user data pointer.
+ * Opaque object representing an IrDA device.
*/
-typedef void (*dc_irda_callback_t) (unsigned int address, const char *name, unsigned int charset, unsigned int hints, void *userdata);
+typedef struct dc_irda_device_t dc_irda_device_t;
+
+/**
+ * Get the address of the IrDA device.
+ *
+ * @param[in] device A valid IrDA device.
+ */
+unsigned int
+dc_irda_device_get_address (dc_irda_device_t *device);
+
+/**
+ * Get the name of the IrDA device.
+ *
+ * @param[in] device A valid IrDA device.
+ */
+const char *
+dc_irda_device_get_name (dc_irda_device_t *device);
+
+/**
+ * Destroy the IrDA device and free all resources.
+ *
+ * @param[in] device A valid IrDA device.
+ */
+void
+dc_irda_device_free (dc_irda_device_t *device);
+
+/**
+ * Create an iterator to enumerate the IrDA devices.
+ *
+ * @param[out] iterator A location to store the iterator.
+ * @param[in] context A valid context object.
+ * @param[in] descriptor A valid device descriptor or NULL.
+ * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code
+ * on failure.
+ */
+dc_status_t
+dc_irda_iterator_new (dc_iterator_t **iterator, dc_context_t *context, dc_descriptor_t *descriptor);
/**
* Open an 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_iostream_t **iostream, dc_context_t *context);
-
-/**
- * Enumerate the IrDA devices.
- *
- * @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_iostream_t *iostream, dc_irda_callback_t callback, void *userdata);
-
-/**
- * Connect to an IrDA device.
- *
- * @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_iostream_t *iostream, unsigned int address, const char *name);
-
-/**
- * Connect to an IrDA device.
- *
- * @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_iostream_t *iostream, unsigned int address, unsigned int lsap);
+dc_irda_open (dc_iostream_t **iostream, dc_context_t *context, unsigned int address, unsigned int lsap);
#ifdef __cplusplus
}
diff --git a/src/iterator-private.h b/src/iterator-private.h
index 105d40f..0cc1bfe 100644
--- a/src/iterator-private.h
+++ b/src/iterator-private.h
@@ -22,6 +22,7 @@
#ifndef DC_ITERATOR_PRIVATE_H
#define DC_ITERATOR_PRIVATE_H
+#include
#include
#ifdef __cplusplus
@@ -32,13 +33,24 @@ typedef struct dc_iterator_vtable_t dc_iterator_vtable_t;
struct dc_iterator_t {
const dc_iterator_vtable_t *vtable;
+ dc_context_t *context;
};
struct dc_iterator_vtable_t {
- dc_status_t (*free) (dc_iterator_t *iterator);
+ size_t size;
dc_status_t (*next) (dc_iterator_t *iterator, void *item);
+ dc_status_t (*free) (dc_iterator_t *iterator);
};
+dc_iterator_t *
+dc_iterator_allocate (dc_context_t *context, const dc_iterator_vtable_t *vtable);
+
+void
+dc_iterator_deallocate (dc_iterator_t *iterator);
+
+int
+dc_iterator_isinstance (dc_iterator_t *iterator, const dc_iterator_vtable_t *vtable);
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
diff --git a/src/iterator.c b/src/iterator.c
index 100f85a..83ad070 100644
--- a/src/iterator.c
+++ b/src/iterator.c
@@ -21,16 +21,51 @@
#include
#include
+#include
+#include "context-private.h"
#include "iterator-private.h"
+dc_iterator_t *
+dc_iterator_allocate (dc_context_t *context, const dc_iterator_vtable_t *vtable)
+{
+ dc_iterator_t *iterator = NULL;
+
+ assert(vtable != NULL);
+ assert(vtable->size >= sizeof(dc_iterator_t));
+
+ // Allocate memory.
+ iterator = (dc_iterator_t *) malloc (vtable->size);
+ if (iterator == NULL) {
+ ERROR (context, "Failed to allocate memory.");
+ return iterator;
+ }
+
+ iterator->vtable = vtable;
+ iterator->context = context;
+
+ return iterator;
+}
+
+void
+dc_iterator_deallocate (dc_iterator_t *iterator)
+{
+ free (iterator);
+}
+
+int
+dc_iterator_isinstance (dc_iterator_t *iterator, const dc_iterator_vtable_t *vtable)
+{
+ if (iterator == NULL)
+ return 0;
+
+ return iterator->vtable == vtable;
+}
+
dc_status_t
dc_iterator_next (dc_iterator_t *iterator, void *item)
{
- if (iterator == NULL)
- return DC_STATUS_UNSUPPORTED;
-
- if (iterator->vtable->next == NULL)
+ if (iterator == NULL || iterator->vtable->next == NULL)
return DC_STATUS_UNSUPPORTED;
if (item == NULL)
@@ -42,11 +77,16 @@ dc_iterator_next (dc_iterator_t *iterator, void *item)
dc_status_t
dc_iterator_free (dc_iterator_t *iterator)
{
+ dc_status_t status = DC_STATUS_SUCCESS;
+
if (iterator == NULL)
return DC_STATUS_SUCCESS;
- if (iterator->vtable->free == NULL)
- return DC_STATUS_UNSUPPORTED;
+ if (iterator->vtable->free) {
+ status = iterator->vtable->free (iterator);
+ }
- return iterator->vtable->free (iterator);
+ dc_iterator_deallocate (iterator);
+
+ return status;
}
diff --git a/src/libdivecomputer.symbols b/src/libdivecomputer.symbols
index f272bd6..3f0760d 100644
--- a/src/libdivecomputer.symbols
+++ b/src/libdivecomputer.symbols
@@ -35,7 +35,6 @@ 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
diff --git a/src/oceanic_common.c b/src/oceanic_common.c
index 1ab491d..9f7341a 100644
--- a/src/oceanic_common.c
+++ b/src/oceanic_common.c
@@ -32,7 +32,7 @@
#define VTABLE(abstract) ((const oceanic_common_device_vtable_t *) abstract->vtable)
-#define RB_LOGBOOK_DISTANCE(a,b,l) ringbuffer_distance (a, b, 0, l->rb_logbook_begin, l->rb_logbook_end)
+#define RB_LOGBOOK_DISTANCE(a,b,l) ringbuffer_distance (a, b, 1, l->rb_logbook_begin, l->rb_logbook_end)
#define RB_LOGBOOK_INCR(a,b,l) ringbuffer_increment (a, b, l->rb_logbook_begin, l->rb_logbook_end)
#define RB_PROFILE_DISTANCE(a,b,l) ringbuffer_distance (a, b, 0, l->rb_profile_begin, l->rb_profile_end)
@@ -208,31 +208,37 @@ oceanic_common_device_logbook (dc_device_t *abstract, dc_event_progress_t *progr
// Get the logbook pointers.
unsigned int rb_logbook_first = array_uint16_le (pointers + 4);
unsigned int rb_logbook_last = array_uint16_le (pointers + 6);
- if (rb_logbook_first < layout->rb_logbook_begin ||
- rb_logbook_first >= layout->rb_logbook_end ||
- rb_logbook_last < layout->rb_logbook_begin ||
+ if (rb_logbook_last < layout->rb_logbook_begin ||
rb_logbook_last >= layout->rb_logbook_end)
{
- ERROR (abstract->context, "Invalid logbook pointer detected (0x%04x 0x%04x).",
- rb_logbook_first, rb_logbook_last);
+ ERROR (abstract->context, "Invalid logbook end pointer detected (0x%04x).", rb_logbook_last);
return DC_STATUS_DATAFORMAT;
}
- // Calculate the end pointer and the number of bytes.
- unsigned int rb_logbook_end, rb_logbook_size;
+ // Calculate the end pointer.
+ unsigned int rb_logbook_end = 0;
if (layout->pt_mode_global == 0) {
rb_logbook_end = RB_LOGBOOK_INCR (rb_logbook_last, layout->rb_logbook_entry_size, layout);
- rb_logbook_size = RB_LOGBOOK_DISTANCE (rb_logbook_first, rb_logbook_last, layout) + layout->rb_logbook_entry_size;
} else {
rb_logbook_end = rb_logbook_last;
- rb_logbook_size = RB_LOGBOOK_DISTANCE (rb_logbook_first, rb_logbook_last, layout);
- // In a typical ringbuffer implementation with only two begin/end
- // pointers, there is no distinction possible between an empty and
- // a full ringbuffer. We always consider the ringbuffer full in
- // that case, because an empty ringbuffer can be detected by
- // inspecting the logbook entries once they are downloaded.
- if (rb_logbook_first == rb_logbook_last)
- rb_logbook_size = layout->rb_logbook_end - layout->rb_logbook_begin;
+ }
+
+ // Calculate the number of bytes.
+ // In a typical ringbuffer implementation with only two begin/end
+ // pointers, there is no distinction possible between an empty and a
+ // full ringbuffer. We always consider the ringbuffer full in that
+ // case, because an empty ringbuffer can be detected by inspecting
+ // the logbook entries once they are downloaded.
+ unsigned int rb_logbook_size = 0;
+ if (rb_logbook_first < layout->rb_logbook_begin ||
+ rb_logbook_first >= layout->rb_logbook_end)
+ {
+ // Fall back to downloading the entire logbook ringbuffer as
+ // workaround for an invalid logbook begin pointer!
+ ERROR (abstract->context, "Invalid logbook begin pointer detected (0x%04x).", rb_logbook_first);
+ rb_logbook_size = layout->rb_logbook_end - layout->rb_logbook_begin;
+ } else {
+ rb_logbook_size = RB_LOGBOOK_DISTANCE (rb_logbook_first, rb_logbook_end, layout);
}
// Update and emit a progress event.
diff --git a/src/platform.h b/src/platform.h
index 877e320..ab82fb7 100644
--- a/src/platform.h
+++ b/src/platform.h
@@ -35,6 +35,7 @@ extern "C" {
#ifdef _MSC_VER
#define snprintf _snprintf
#define strcasecmp _stricmp
+#define strncasecmp _strnicmp
#if _MSC_VER < 1800
// The rint() function is only available in MSVC 2013 and later
// versions. Our replacement macro isn't entirely correct, because the
diff --git a/src/serial.h b/src/serial.h
index d6620e0..844c5b2 100644
--- a/src/serial.h
+++ b/src/serial.h
@@ -25,29 +25,45 @@
#include
#include
#include
+#include
+#include
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/**
- * Serial enumeration callback.
- *
- * @param[in] name The name of the device node.
- * @param[in] userdata The user data pointer.
+ * Opaque object representing a serial device.
*/
-typedef void (*dc_serial_callback_t) (const char *name, void *userdata);
+typedef struct dc_serial_device_t dc_serial_device_t;
/**
- * Enumerate the serial ports.
+ * Get the device node of the serial device.
*
- * @param[in] callback The callback function to call.
- * @param[in] userdata User data to pass to the callback function.
+ * @param[in] device A valid serial device.
+ */
+const char *
+dc_serial_device_get_name (dc_serial_device_t *device);
+
+/**
+ * Destroy the serial device and free all resources.
+ *
+ * @param[in] device A valid serial device.
+ */
+void
+dc_serial_device_free (dc_serial_device_t *device);
+
+/**
+ * Create an iterator to enumerate the serial devices.
+ *
+ * @param[out] iterator A location to store the iterator.
+ * @param[in] context A valid context object.
+ * @param[in] descriptor A valid device descriptor or NULL.
* @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code
* on failure.
*/
dc_status_t
-dc_serial_enumerate (dc_serial_callback_t callback, void *userdata);
+dc_serial_iterator_new (dc_iterator_t **iterator, dc_context_t *context, dc_descriptor_t *descriptor);
/**
* Open a serial connection.
diff --git a/src/serial_posix.c b/src/serial_posix.c
index 9a9373e..03af81d 100644
--- a/src/serial_posix.c
+++ b/src/serial_posix.c
@@ -30,7 +30,6 @@
#include // fcntl
#include // tcgetattr, tcsetattr, cfsetispeed, cfsetospeed, tcflush, tcsendbreak
#include // ioctl
-#include // gettimeofday
#include // nanosleep
#ifdef HAVE_LINUX_SERIAL_H
#include
@@ -58,10 +57,17 @@
#include "common-private.h"
#include "context-private.h"
#include "iostream-private.h"
+#include "iterator-private.h"
+#include "descriptor-private.h"
+#include "timer.h"
+
+#define DIRNAME "/dev"
+
+static dc_status_t dc_serial_iterator_next (dc_iterator_t *iterator, void *item);
+static dc_status_t dc_serial_iterator_free (dc_iterator_t *iterator);
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);
@@ -75,6 +81,16 @@ static dc_status_t dc_serial_purge (dc_iostream_t *iostream, dc_direction_t dire
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);
+struct dc_serial_device_t {
+ char name[256];
+};
+
+typedef struct dc_serial_iterator_t {
+ dc_iterator_t base;
+ dc_filter_t filter;
+ DIR *dp;
+} dc_serial_iterator_t;
+
typedef struct dc_serial_t {
dc_iostream_t base;
/*
@@ -82,23 +98,25 @@ typedef struct dc_serial_t {
*/
int fd;
int timeout;
+ dc_timer_t *timer;
/*
* Serial port settings are saved into this variable immediately
* after the port is opened. These settings are restored when the
* serial port is closed.
*/
struct termios tty;
- /* Half-duplex settings */
- int halfduplex;
- unsigned int baudrate;
- unsigned int nbits;
} dc_serial_t;
+static const dc_iterator_vtable_t dc_serial_iterator_vtable = {
+ sizeof(dc_serial_iterator_t),
+ dc_serial_iterator_next,
+ dc_serial_iterator_free,
+};
+
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 */
@@ -131,12 +149,62 @@ syserror(int errcode)
}
}
-dc_status_t
-dc_serial_enumerate (dc_serial_callback_t callback, void *userdata)
+const char *
+dc_serial_device_get_name (dc_serial_device_t *device)
{
- DIR *dp = NULL;
+ if (device == NULL || device->name[0] == '\0')
+ return NULL;
+
+ return device->name;
+}
+
+void
+dc_serial_device_free (dc_serial_device_t *device)
+{
+ free (device);
+}
+
+dc_status_t
+dc_serial_iterator_new (dc_iterator_t **out, dc_context_t *context, dc_descriptor_t *descriptor)
+{
+ dc_status_t status = DC_STATUS_SUCCESS;
+ dc_serial_iterator_t *iterator = NULL;
+
+ if (out == NULL)
+ return DC_STATUS_INVALIDARGS;
+
+ iterator = (dc_serial_iterator_t *) dc_iterator_allocate (context, &dc_serial_iterator_vtable);
+ if (iterator == NULL) {
+ SYSERROR (context, ENOMEM);
+ return DC_STATUS_NOMEMORY;
+ }
+
+ iterator->dp = opendir (DIRNAME);
+ if (iterator->dp == NULL) {
+ int errcode = errno;
+ SYSERROR (context, errcode);
+ status = syserror (errcode);
+ goto error_free;
+ }
+
+ iterator->filter = dc_descriptor_get_filter (descriptor);
+
+ *out = (dc_iterator_t *) iterator;
+
+ return DC_STATUS_SUCCESS;
+
+error_free:
+ dc_iterator_deallocate ((dc_iterator_t *) iterator);
+ return status;
+}
+
+static dc_status_t
+dc_serial_iterator_next (dc_iterator_t *abstract, void *out)
+{
+ dc_serial_iterator_t *iterator = (dc_serial_iterator_t *) abstract;
+ dc_serial_device_t *device = NULL;
+
struct dirent *ep = NULL;
- const char *dirname = "/dev";
const char *patterns[] = {
#if defined (__APPLE__)
"tty.*",
@@ -149,28 +217,44 @@ dc_serial_enumerate (dc_serial_callback_t callback, void *userdata)
NULL
};
- dp = opendir (dirname);
- if (dp == NULL) {
- return DC_STATUS_IO;
- }
-
- while ((ep = readdir (dp)) != NULL) {
+ while ((ep = readdir (iterator->dp)) != NULL) {
for (size_t i = 0; patterns[i] != NULL; ++i) {
- if (fnmatch (patterns[i], ep->d_name, 0) == 0) {
- char filename[1024];
- int n = snprintf (filename, sizeof (filename), "%s/%s", dirname, ep->d_name);
- if (n >= sizeof (filename)) {
- closedir (dp);
- return DC_STATUS_NOMEMORY;
- }
+ if (fnmatch (patterns[i], ep->d_name, 0) != 0)
+ continue;
- callback (filename, userdata);
- break;
+ char filename[sizeof(device->name)];
+ int n = snprintf (filename, sizeof (filename), "%s/%s", DIRNAME, ep->d_name);
+ if (n < 0 || (size_t) n >= sizeof (filename)) {
+ return DC_STATUS_NOMEMORY;
}
+
+ if (iterator->filter && !iterator->filter (DC_TRANSPORT_SERIAL, filename)) {
+ continue;
+ }
+
+ device = (dc_serial_device_t *) malloc (sizeof(dc_serial_device_t));
+ if (device == NULL) {
+ SYSERROR (abstract->context, ENOMEM);
+ return DC_STATUS_NOMEMORY;
+ }
+
+ strncpy(device->name, filename, sizeof(device->name));
+
+ *(dc_serial_device_t **) out = device;
+
+ return DC_STATUS_SUCCESS;
}
}
- closedir (dp);
+ return DC_STATUS_DONE;
+}
+
+static dc_status_t
+dc_serial_iterator_free (dc_iterator_t *abstract)
+{
+ dc_serial_iterator_t *iterator = (dc_serial_iterator_t *) abstract;
+
+ closedir (iterator->dp);
return DC_STATUS_SUCCESS;
}
@@ -200,10 +284,12 @@ dc_serial_open (dc_iostream_t **out, dc_context_t *context, const char *name)
// Default to blocking reads.
device->timeout = -1;
- // Default to full-duplex.
- device->halfduplex = 0;
- device->baudrate = 0;
- device->nbits = 0;
+ // Create a high resolution timer.
+ status = dc_timer_new (&device->timer);
+ if (status != DC_STATUS_SUCCESS) {
+ ERROR (context, "Failed to create a high resolution timer.");
+ goto error_free;
+ }
// Open the device in non-blocking mode, to return immediately
// without waiting for the modem connection to complete.
@@ -212,7 +298,7 @@ dc_serial_open (dc_iostream_t **out, dc_context_t *context, const char *name)
int errcode = errno;
SYSERROR (context, errcode);
status = syserror (errcode);
- goto error_free;
+ goto error_timer_free;
}
#ifndef ENABLE_PTY
@@ -242,6 +328,8 @@ dc_serial_open (dc_iostream_t **out, dc_context_t *context, const char *name)
error_close:
close (device->fd);
+error_timer_free:
+ dc_timer_free (device->timer);
error_free:
dc_iostream_deallocate ((dc_iostream_t *) device);
return status;
@@ -276,6 +364,8 @@ dc_serial_close (dc_iostream_t *abstract)
dc_status_set_error(&status, syserror (errcode));
}
+ dc_timer_free (device->timer);
+
return status;
}
@@ -522,9 +612,6 @@ dc_serial_configure (dc_iostream_t *abstract, unsigned int baudrate, unsigned in
#endif
}
- device->baudrate = baudrate;
- device->nbits = 1 + databits + stopbits + (parity ? 1 : 0);
-
return DC_STATUS_SUCCESS;
}
@@ -538,16 +625,6 @@ dc_serial_set_timeout (dc_iostream_t *abstract, int timeout)
return DC_STATUS_SUCCESS;
}
-static dc_status_t
-dc_serial_set_halfduplex (dc_iostream_t *abstract, unsigned int value)
-{
- dc_serial_t *device = (dc_serial_t *) abstract;
-
- device->halfduplex = value;
-
- return DC_STATUS_SUCCESS;
-}
-
static dc_status_t
dc_serial_set_latency (dc_iostream_t *abstract, unsigned int milliseconds)
{
@@ -597,11 +674,8 @@ dc_serial_read (dc_iostream_t *abstract, void *data, size_t size, size_t *actual
dc_serial_t *device = (dc_serial_t *) abstract;
size_t nbytes = 0;
- // The total timeout.
- int timeout = device->timeout;
-
// The absolute target time.
- struct timeval tve;
+ dc_usecs_t target = 0;
int init = 1;
while (nbytes < size) {
@@ -609,35 +683,40 @@ dc_serial_read (dc_iostream_t *abstract, void *data, size_t size, size_t *actual
FD_ZERO (&fds);
FD_SET (device->fd, &fds);
- struct timeval tvt;
- if (timeout > 0) {
- struct timeval now;
- if (gettimeofday (&now, NULL) != 0) {
- int errcode = errno;
- SYSERROR (abstract->context, errcode);
- status = syserror (errcode);
+ struct timeval tv, *ptv = NULL;
+ if (device->timeout > 0) {
+ dc_usecs_t timeout = 0;
+
+ dc_usecs_t now = 0;
+ status = dc_timer_now (device->timer, &now);
+ if (status != DC_STATUS_SUCCESS) {
goto out;
}
if (init) {
// Calculate the initial timeout.
- tvt.tv_sec = (timeout / 1000);
- tvt.tv_usec = (timeout % 1000) * 1000;
+ timeout = device->timeout * 1000;
// Calculate the target time.
- timeradd (&now, &tvt, &tve);
+ target = now + timeout;
+ init = 0;
} else {
// Calculate the remaining timeout.
- if (timercmp (&now, &tve, <))
- timersub (&tve, &now, &tvt);
- else
- timerclear (&tvt);
+ if (now < target) {
+ timeout = target - now;
+ } else {
+ timeout = 0;
+ }
}
- init = 0;
- } else if (timeout == 0) {
- timerclear (&tvt);
+ tv.tv_sec = timeout / 1000000;
+ tv.tv_usec = timeout % 1000000;
+ ptv = &tv;
+ } else if (device->timeout == 0) {
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ ptv = &tv;
}
- int rc = select (device->fd + 1, &fds, NULL, NULL, timeout >= 0 ? &tvt : NULL);
+ int rc = select (device->fd + 1, &fds, NULL, NULL, ptv);
if (rc < 0) {
int errcode = errno;
if (errcode == EINTR)
@@ -682,17 +761,6 @@ dc_serial_write (dc_iostream_t *abstract, const void *data, size_t size, size_t
dc_serial_t *device = (dc_serial_t *) abstract;
size_t nbytes = 0;
- struct timeval tve, tvb;
- if (device->halfduplex) {
- // Get the current time.
- if (gettimeofday (&tvb, NULL) != 0) {
- int errcode = errno;
- SYSERROR (abstract->context, errcode);
- status = syserror (errcode);
- goto out;
- }
- }
-
while (nbytes < size) {
fd_set fds;
FD_ZERO (&fds);
@@ -740,35 +808,6 @@ dc_serial_write (dc_iostream_t *abstract, const void *data, size_t size, size_t
}
}
- if (device->halfduplex) {
- // Get the current time.
- if (gettimeofday (&tve, NULL) != 0) {
- int errcode = errno;
- SYSERROR (abstract->context, errcode);
- status = syserror (errcode);
- goto out;
- }
-
- // Calculate the elapsed time (microseconds).
- struct timeval tvt;
- timersub (&tve, &tvb, &tvt);
- unsigned long elapsed = tvt.tv_sec * 1000000 + tvt.tv_usec;
-
- // Calculate the expected duration (microseconds). A 2 millisecond fudge
- // factor is added because it improves the success rate significantly.
- unsigned long expected = 1000000.0 * device->nbits / device->baudrate * size + 0.5 + 2000;
-
- // Wait for the remaining time.
- if (elapsed < expected) {
- unsigned long remaining = expected - elapsed;
-
- // 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 (abstract, (remaining + 999) / 1000);
- }
- }
-
out:
if (actual)
*actual = nbytes;
diff --git a/src/serial_win32.c b/src/serial_win32.c
index b530c9b..1b3f0a8 100644
--- a/src/serial_win32.c
+++ b/src/serial_win32.c
@@ -29,10 +29,14 @@
#include "common-private.h"
#include "context-private.h"
#include "iostream-private.h"
+#include "iterator-private.h"
+#include "descriptor-private.h"
+
+static dc_status_t dc_serial_iterator_next (dc_iterator_t *iterator, void *item);
+static dc_status_t dc_serial_iterator_free (dc_iterator_t *iterator);
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);
@@ -46,6 +50,18 @@ static dc_status_t dc_serial_purge (dc_iostream_t *iostream, dc_direction_t dire
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);
+struct dc_serial_device_t {
+ char name[256];
+};
+
+typedef struct dc_serial_iterator_t {
+ dc_iterator_t base;
+ dc_filter_t filter;
+ HKEY hKey;
+ DWORD count;
+ DWORD current;
+} dc_serial_iterator_t;
+
typedef struct dc_serial_t {
dc_iostream_t base;
/*
@@ -59,17 +75,18 @@ typedef struct dc_serial_t {
*/
DCB dcb;
COMMTIMEOUTS timeouts;
- /* Half-duplex settings */
- int halfduplex;
- unsigned int baudrate;
- unsigned int nbits;
} dc_serial_t;
+static const dc_iterator_vtable_t dc_serial_iterator_vtable = {
+ sizeof(dc_serial_iterator_t),
+ dc_serial_iterator_next,
+ dc_serial_iterator_free,
+};
+
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 */
@@ -101,37 +118,93 @@ syserror(DWORD errcode)
}
}
-dc_status_t
-dc_serial_enumerate (dc_serial_callback_t callback, void *userdata)
+const char *
+dc_serial_device_get_name (dc_serial_device_t *device)
{
+ if (device == NULL || device->name[0] == '\0')
+ return NULL;
+
+ return device->name;
+}
+
+void
+dc_serial_device_free (dc_serial_device_t *device)
+{
+ free (device);
+}
+
+dc_status_t
+dc_serial_iterator_new (dc_iterator_t **out, dc_context_t *context, dc_descriptor_t *descriptor)
+{
+ dc_status_t status = DC_STATUS_SUCCESS;
+ dc_serial_iterator_t *iterator = NULL;
+ HKEY hKey = NULL;
+ DWORD count = 0;
+ LONG rc = 0;
+
+ if (out == NULL)
+ return DC_STATUS_INVALIDARGS;
+
+ iterator = (dc_serial_iterator_t *) dc_iterator_allocate (context, &dc_serial_iterator_vtable);
+ if (iterator == NULL) {
+ SYSERROR (context, ERROR_OUTOFMEMORY);
+ return DC_STATUS_NOMEMORY;
+ }
+
// Open the registry key.
- HKEY hKey;
- LONG rc = RegOpenKeyExA (HKEY_LOCAL_MACHINE, "HARDWARE\\DEVICEMAP\\SERIALCOMM", 0, KEY_QUERY_VALUE, &hKey);
+ rc = RegOpenKeyExA (HKEY_LOCAL_MACHINE, "HARDWARE\\DEVICEMAP\\SERIALCOMM", 0, KEY_QUERY_VALUE, &hKey);
if (rc != ERROR_SUCCESS) {
- if (rc == ERROR_FILE_NOT_FOUND)
- return DC_STATUS_SUCCESS;
- else
- return DC_STATUS_IO;
+ if (rc == ERROR_FILE_NOT_FOUND) {
+ hKey = NULL;
+ } else {
+ SYSERROR (context, rc);
+ status = syserror (rc);
+ goto error_free;
+ }
}
// Get the number of values.
- DWORD count = 0;
- rc = RegQueryInfoKey (hKey, NULL, NULL, NULL, NULL, NULL, NULL, &count, NULL, NULL, NULL, NULL);
- if (rc != ERROR_SUCCESS) {
- RegCloseKey(hKey);
- return DC_STATUS_IO;
+ if (hKey) {
+ rc = RegQueryInfoKey (hKey, NULL, NULL, NULL, NULL, NULL, NULL, &count, NULL, NULL, NULL, NULL);
+ if (rc != ERROR_SUCCESS) {
+ SYSERROR (context, rc);
+ status = syserror (rc);
+ goto error_close;
+ }
}
- for (DWORD i = 0; i < count; ++i) {
+ iterator->filter = dc_descriptor_get_filter (descriptor);
+ iterator->hKey = hKey;
+ iterator->count = count;
+ iterator->current = 0;
+
+ *out = (dc_iterator_t *) iterator;
+
+ return DC_STATUS_SUCCESS;
+
+error_close:
+ RegCloseKey (hKey);
+error_free:
+ dc_iterator_deallocate ((dc_iterator_t *) iterator);
+ return status;
+}
+
+static dc_status_t
+dc_serial_iterator_next (dc_iterator_t *abstract, void *out)
+{
+ dc_serial_iterator_t *iterator = (dc_serial_iterator_t *) abstract;
+ dc_serial_device_t *device = NULL;
+
+ while (iterator->current < iterator->count) {
// Get the value name, data and type.
- char name[512], data[512];
+ char name[256], data[sizeof(device->name)];
DWORD name_len = sizeof (name);
DWORD data_len = sizeof (data);
DWORD type = 0;
- rc = RegEnumValueA (hKey, i, name, &name_len, NULL, &type, (LPBYTE) data, &data_len);
+ LONG rc = RegEnumValueA (iterator->hKey, iterator->current++, name, &name_len, NULL, &type, (LPBYTE) data, &data_len);
if (rc != ERROR_SUCCESS) {
- RegCloseKey(hKey);
- return DC_STATUS_IO;
+ SYSERROR (abstract->context, rc);
+ return syserror (rc);
}
// Ignore non-string values.
@@ -140,17 +213,40 @@ dc_serial_enumerate (dc_serial_callback_t callback, void *userdata)
// Prevent a possible buffer overflow.
if (data_len >= sizeof (data)) {
- RegCloseKey(hKey);
return DC_STATUS_NOMEMORY;
}
// Null terminate the string.
data[data_len] = 0;
- callback (data, userdata);
+ if (iterator->filter && !iterator->filter (DC_TRANSPORT_SERIAL, data)) {
+ continue;
+ }
+
+ device = (dc_serial_device_t *) malloc (sizeof(dc_serial_device_t));
+ if (device == NULL) {
+ SYSERROR (abstract->context, ERROR_OUTOFMEMORY);
+ return DC_STATUS_NOMEMORY;
+ }
+
+ strncpy(device->name, data, sizeof(device->name));
+
+ *(dc_serial_device_t **) out = device;
+
+ return DC_STATUS_SUCCESS;
}
- RegCloseKey(hKey);
+ return DC_STATUS_DONE;
+}
+
+static dc_status_t
+dc_serial_iterator_free (dc_iterator_t *abstract)
+{
+ dc_serial_iterator_t *iterator = (dc_serial_iterator_t *) abstract;
+
+ if (iterator->hKey) {
+ RegCloseKey (iterator->hKey);
+ }
return DC_STATUS_SUCCESS;
}
@@ -190,11 +286,6 @@ dc_serial_open (dc_iostream_t **out, dc_context_t *context, const char *name)
return DC_STATUS_NOMEMORY;
}
- // Default to full-duplex.
- device->halfduplex = 0;
- device->baudrate = 0;
- device->nbits = 0;
-
// Open the device.
device->hFile = CreateFileA (devname,
GENERIC_READ | GENERIC_WRITE, 0,
@@ -359,9 +450,6 @@ dc_serial_configure (dc_iostream_t *abstract, unsigned int baudrate, unsigned in
return syserror (errcode);
}
- device->baudrate = baudrate;
- device->nbits = 1 + databits + stopbits + (parity ? 1 : 0);
-
return DC_STATUS_SUCCESS;
}
@@ -412,16 +500,6 @@ dc_serial_set_timeout (dc_iostream_t *abstract, int timeout)
return DC_STATUS_SUCCESS;
}
-static dc_status_t
-dc_serial_set_halfduplex (dc_iostream_t *abstract, unsigned int value)
-{
- dc_serial_t *device = (dc_serial_t *) abstract;
-
- device->halfduplex = value;
-
- return DC_STATUS_SUCCESS;
-}
-
static dc_status_t
dc_serial_set_latency (dc_iostream_t *abstract, unsigned int value)
{
@@ -460,18 +538,6 @@ dc_serial_write (dc_iostream_t *abstract, const void *data, size_t size, size_t
dc_serial_t *device = (dc_serial_t *) abstract;
DWORD dwWritten = 0;
- LARGE_INTEGER begin, end, freq;
- if (device->halfduplex) {
- // Get the current time.
- if (!QueryPerformanceFrequency(&freq) ||
- !QueryPerformanceCounter(&begin)) {
- DWORD errcode = GetLastError ();
- SYSERROR (abstract->context, errcode);
- status = syserror (errcode);
- goto out;
- }
- }
-
if (!WriteFile (device->hFile, data, size, &dwWritten, NULL)) {
DWORD errcode = GetLastError ();
SYSERROR (abstract->context, errcode);
@@ -479,33 +545,6 @@ dc_serial_write (dc_iostream_t *abstract, const void *data, size_t size, size_t
goto out;
}
- if (device->halfduplex) {
- // Get the current time.
- if (!QueryPerformanceCounter(&end)) {
- DWORD errcode = GetLastError ();
- SYSERROR (abstract->context, errcode);
- status = syserror (errcode);
- goto out;
- }
-
- // Calculate the elapsed time (microseconds).
- unsigned long elapsed = 1000000.0 * (end.QuadPart - begin.QuadPart) / freq.QuadPart + 0.5;
-
- // Calculate the expected duration (microseconds). A 2 millisecond fudge
- // factor is added because it improves the success rate significantly.
- unsigned long expected = 1000000.0 * device->nbits / device->baudrate * size + 0.5 + 2000;
-
- // Wait for the remaining time.
- if (elapsed < expected) {
- unsigned long remaining = expected - elapsed;
-
- // The remaining time is rounded up to the nearest millisecond
- // because the Windows Sleep() function doesn't have a higher
- // resolution.
- dc_serial_sleep (abstract, (remaining + 999) / 1000);
- }
- }
-
if (dwWritten != size) {
status = DC_STATUS_TIMEOUT;
}
diff --git a/src/shearwater_predator_parser.c b/src/shearwater_predator_parser.c
index 8c760f0..dda042c 100644
--- a/src/shearwater_predator_parser.c
+++ b/src/shearwater_predator_parser.c
@@ -494,7 +494,7 @@ shearwater_predator_parser_cache (shearwater_predator_parser_t *parser)
nsensors++;
}
}
- if (nsensors == ndefaults) {
+ if (nsensors && nsensors == ndefaults) {
// If all (calibrated) sensors still have their factory default
// calibration values (2100), they are probably not calibrated
// properly. To avoid returning incorrect ppO2 values to the
diff --git a/src/socket.c b/src/socket.c
index 5ce392f..1842a75 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -169,12 +169,6 @@ 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)
{
diff --git a/src/socket.h b/src/socket.h
index d612603..626003c 100644
--- a/src/socket.h
+++ b/src/socket.h
@@ -107,9 +107,6 @@ 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);
diff --git a/src/suunto_vyper2.c b/src/suunto_vyper2.c
index 2591878..596b06e 100644
--- a/src/suunto_vyper2.c
+++ b/src/suunto_vyper2.c
@@ -28,6 +28,7 @@
#include "serial.h"
#include "checksum.h"
#include "array.h"
+#include "timer.h"
#define ISINSTANCE(device) dc_device_isinstance((device), (const dc_device_vtable_t *) &suunto_vyper2_device_vtable)
@@ -36,6 +37,7 @@
typedef struct suunto_vyper2_device_t {
suunto_common2_device_t base;
dc_iostream_t *iostream;
+ dc_timer_t *timer;
} 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);
@@ -95,11 +97,18 @@ suunto_vyper2_device_open (dc_device_t **out, dc_context_t *context, const char
// Set the default values.
device->iostream = NULL;
+ // Create a high resolution timer.
+ status = dc_timer_new (&device->timer);
+ if (status != DC_STATUS_SUCCESS) {
+ ERROR (context, "Failed to create a high resolution timer.");
+ goto error_free;
+ }
+
// Open the device.
status = dc_serial_open (&device->iostream, context, name);
if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to open the serial port.");
- goto error_free;
+ goto error_timer_free;
}
// Set the serial communication protocol (9600 8N1).
@@ -133,13 +142,6 @@ suunto_vyper2_device_open (dc_device_t **out, dc_context_t *context, const char
goto error_close;
}
- // Enable half-duplex emulation.
- status = dc_iostream_set_halfduplex (device->iostream, 1);
- if (status != DC_STATUS_SUCCESS) {
- ERROR (context, "Failed to set half duplex.");
- goto error_close;
- }
-
// Read the version info.
status = suunto_common2_device_version ((dc_device_t *) device, device->base.version, sizeof (device->base.version));
if (status != DC_STATUS_SUCCESS) {
@@ -160,6 +162,8 @@ suunto_vyper2_device_open (dc_device_t **out, dc_context_t *context, const char
error_close:
dc_iostream_close (device->iostream);
+error_timer_free:
+ dc_timer_free (device->timer);
error_free:
dc_device_deallocate ((dc_device_t *) device);
return status;
@@ -173,6 +177,8 @@ suunto_vyper2_device_close (dc_device_t *abstract)
suunto_vyper2_device_t *device = (suunto_vyper2_device_t*) abstract;
dc_status_t rc = DC_STATUS_SUCCESS;
+ dc_timer_free (device->timer);
+
// Close the device.
rc = dc_iostream_close (device->iostream);
if (rc != DC_STATUS_SUCCESS) {
@@ -201,6 +207,13 @@ suunto_vyper2_device_packet (dc_device_t *abstract, const unsigned char command[
return status;
}
+ // Get the current timestamp.
+ dc_usecs_t begin = 0;
+ status = dc_timer_now (device->timer, &begin);
+ if (status != DC_STATUS_SUCCESS) {
+ return status;
+ }
+
// Send the command to the dive computer.
status = dc_iostream_write (device->iostream, command, csize, NULL);
if (status != DC_STATUS_SUCCESS) {
@@ -208,6 +221,34 @@ suunto_vyper2_device_packet (dc_device_t *abstract, const unsigned char command[
return status;
}
+ // Get the current timestamp.
+ dc_usecs_t end = 0;
+ status = dc_timer_now (device->timer, &end);
+ if (status != DC_STATUS_SUCCESS) {
+ return status;
+ }
+
+ // Calculate the elapsed time.
+ dc_usecs_t elapsed = end - begin;
+
+ // Calculate the expected duration. A 2 millisecond fudge factor is added
+ // because it improves the success rate significantly.
+ unsigned int baudrate = 9600;
+ unsigned int nbits = 1 + 8 /* databits */ + 1 /* stopbits */ + 0 /* parity */;
+ dc_usecs_t expected = (dc_usecs_t) csize * 1000000 * nbits / baudrate + 2000;
+
+ // Wait for the remaining time.
+ if (elapsed < expected) {
+ dc_usecs_t remaining = expected - elapsed;
+
+ // The remaining time is rounded up to the nearest millisecond
+ // because the sleep function doesn't support a higher
+ // resolution on all platforms. The higher resolution is
+ // pointless anyway, since we already added a fudge factor
+ // above.
+ dc_iostream_sleep (device->iostream, (remaining + 999) / 1000);
+ }
+
// Clear RTS to receive the reply.
status = dc_iostream_set_rts (device->iostream, 0);
if (status != DC_STATUS_SUCCESS) {
diff --git a/src/timer.c b/src/timer.c
new file mode 100644
index 0000000..36d1f8f
--- /dev/null
+++ b/src/timer.c
@@ -0,0 +1,161 @@
+/*
+ * libdivecomputer
+ *
+ * Copyright (C) 2018 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
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include
+
+#ifdef _WIN32
+#define NOGDI
+#include
+#else
+#include
+#include
+#ifdef HAVE_MACH_MACH_TIME_H
+#include
+#endif
+#endif
+
+#include "timer.h"
+
+struct dc_timer_t {
+#if defined (_WIN32)
+ LARGE_INTEGER timestamp;
+ LARGE_INTEGER frequency;
+#elif defined (HAVE_CLOCK_GETTIME)
+ struct timespec timestamp;
+#elif defined (HAVE_MACH_ABSOLUTE_TIME)
+ uint64_t timestamp;
+ mach_timebase_info_data_t info;
+#else
+ struct timeval timestamp;
+#endif
+};
+
+dc_status_t
+dc_timer_new (dc_timer_t **out)
+{
+ dc_timer_t *timer = NULL;
+
+ if (out == NULL)
+ return DC_STATUS_INVALIDARGS;
+
+ timer = (dc_timer_t *) malloc (sizeof (dc_timer_t));
+ if (timer == NULL) {
+ return DC_STATUS_NOMEMORY;
+ }
+
+#if defined (_WIN32)
+ if (!QueryPerformanceFrequency(&timer->frequency) ||
+ !QueryPerformanceCounter(&timer->timestamp)) {
+ free(timer);
+ return DC_STATUS_IO;
+ }
+#elif defined (HAVE_CLOCK_GETTIME)
+ if (clock_gettime(CLOCK_MONOTONIC, &timer->timestamp) != 0) {
+ free(timer);
+ return DC_STATUS_IO;
+ }
+#elif defined (HAVE_MACH_ABSOLUTE_TIME)
+ if (mach_timebase_info(&timer->info) != KERN_SUCCESS) {
+ free(timer);
+ return DC_STATUS_IO;
+ }
+
+ timer->timestamp = mach_absolute_time();
+#else
+ if (gettimeofday (&timer->timestamp, NULL) != 0) {
+ free(timer);
+ return DC_STATUS_IO;
+ }
+#endif
+
+ *out = timer;
+
+ return DC_STATUS_SUCCESS;
+}
+
+dc_status_t
+dc_timer_now (dc_timer_t *timer, dc_usecs_t *usecs)
+{
+ dc_status_t status = DC_STATUS_SUCCESS;
+ dc_usecs_t value = 0;
+
+ if (timer == NULL) {
+ status = DC_STATUS_INVALIDARGS;
+ goto out;
+ }
+
+#if defined (_WIN32)
+ LARGE_INTEGER now;
+ if (!QueryPerformanceCounter(&now)) {
+ status = DC_STATUS_IO;
+ goto out;
+ }
+
+ value = (now.QuadPart - timer->timestamp.QuadPart) * 1000000 / timer->frequency.QuadPart;
+#elif defined (HAVE_CLOCK_GETTIME)
+ struct timespec now, delta;
+ if (clock_gettime(CLOCK_MONOTONIC, &now) != 0) {
+ status = DC_STATUS_IO;
+ goto out;
+ }
+
+ if (now.tv_nsec < timer->timestamp.tv_nsec) {
+ delta.tv_nsec = 1000000000 + now.tv_nsec - timer->timestamp.tv_nsec;
+ delta.tv_sec = now.tv_sec - timer->timestamp.tv_sec - 1;
+ } else {
+ delta.tv_nsec = now.tv_nsec - timer->timestamp.tv_nsec;
+ delta.tv_sec = now.tv_sec - timer->timestamp.tv_sec;
+ }
+
+ value = (dc_usecs_t) delta.tv_sec * 1000000 + delta.tv_nsec / 1000;
+#elif defined (HAVE_MACH_ABSOLUTE_TIME)
+ uint64_t now = mach_absolute_time();
+ value = (now - timer->timestamp) * timer->info.numer / timer->info.denom;
+#else
+ struct timeval now, delta;
+ if (gettimeofday (&now, NULL) != 0) {
+ status = DC_STATUS_IO;
+ goto out;
+ }
+
+ timersub (&now, &timer->timestamp, &delta);
+
+ value = (dc_usecs_t) delta.tv_sec * 1000000 + delta.tv_usec;
+#endif
+
+out:
+ if (usecs)
+ *usecs = value;
+
+ return status;
+}
+
+dc_status_t
+dc_timer_free (dc_timer_t *timer)
+{
+ free (timer);
+
+ return DC_STATUS_SUCCESS;
+}
diff --git a/src/timer.h b/src/timer.h
new file mode 100644
index 0000000..651991f
--- /dev/null
+++ b/src/timer.h
@@ -0,0 +1,51 @@
+/*
+ * libdivecomputer
+ *
+ * Copyright (C) 2018 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_TIMER_H
+#define DC_TIMER_H
+
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#if defined (_WIN32) && !defined (__GNUC__)
+typedef unsigned __int64 dc_usecs_t;
+#else
+typedef unsigned long long dc_usecs_t;
+#endif
+
+typedef struct dc_timer_t dc_timer_t;
+
+dc_status_t
+dc_timer_new (dc_timer_t **timer);
+
+dc_status_t
+dc_timer_now (dc_timer_t *timer, dc_usecs_t *usecs);
+
+dc_status_t
+dc_timer_free (dc_timer_t *timer);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* DC_TIMER_H */
diff --git a/src/usbhid.c b/src/usbhid.c
index 468c1ab..52adf1f 100644
--- a/src/usbhid.c
+++ b/src/usbhid.c
@@ -54,6 +54,8 @@
#include "common-private.h"
#include "context-private.h"
#include "iostream-private.h"
+#include "descriptor-private.h"
+#include "iterator-private.h"
#include "platform.h"
#ifdef _WIN32
@@ -66,12 +68,31 @@ typedef pthread_mutex_t dc_mutex_t;
#define ISINSTANCE(device) dc_iostream_isinstance((device), &dc_usbhid_vtable)
+struct dc_usbhid_device_t {
+ unsigned short vid, pid;
+};
+
#ifdef USBHID
+static dc_status_t dc_usbhid_iterator_next (dc_iterator_t *iterator, void *item);
+static dc_status_t dc_usbhid_iterator_free (dc_iterator_t *iterator);
+
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_iterator_t {
+ dc_iterator_t base;
+ dc_filter_t filter;
+#if defined(USE_LIBUSB)
+ struct libusb_device **devices;
+ size_t count;
+ size_t current;
+#elif defined(USE_HIDAPI)
+ struct hid_device_info *devices, *current;
+#endif
+} dc_usbhid_iterator_t;
+
typedef struct dc_usbhid_t {
/* Base class. */
dc_iostream_t base;
@@ -88,11 +109,16 @@ typedef struct dc_usbhid_t {
#endif
} dc_usbhid_t;
+static const dc_iterator_vtable_t dc_usbhid_iterator_vtable = {
+ sizeof(dc_usbhid_iterator_t),
+ dc_usbhid_iterator_next,
+ dc_usbhid_iterator_free,
+};
+
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 */
@@ -286,6 +312,229 @@ dc_usbhid_exit (void)
}
#endif
+unsigned int
+dc_usbhid_device_get_vid (dc_usbhid_device_t *device)
+{
+ if (device == NULL)
+ return 0;
+
+ return device->vid;
+}
+
+unsigned int
+dc_usbhid_device_get_pid (dc_usbhid_device_t *device)
+{
+ if (device == NULL)
+ return 0;
+
+ return device->pid;
+}
+
+void
+dc_usbhid_device_free(dc_usbhid_device_t *device)
+{
+ free (device);
+}
+
+dc_status_t
+dc_usbhid_iterator_new (dc_iterator_t **out, dc_context_t *context, dc_descriptor_t *descriptor)
+{
+#ifdef USBHID
+ dc_status_t status = DC_STATUS_SUCCESS;
+ dc_usbhid_iterator_t *iterator = NULL;
+
+ if (out == NULL)
+ return DC_STATUS_INVALIDARGS;
+
+ iterator = (dc_usbhid_iterator_t *) dc_iterator_allocate (context, &dc_usbhid_iterator_vtable);
+ if (iterator == NULL) {
+ ERROR (context, "Failed to allocate memory.");
+ return DC_STATUS_NOMEMORY;
+ }
+
+ // Initialize the usb library.
+ status = dc_usbhid_init (context);
+ if (status != DC_STATUS_SUCCESS) {
+ goto error_free;
+ }
+
+#if defined(USE_LIBUSB)
+ // Enumerate the USB devices.
+ struct libusb_device **devices = NULL;
+ ssize_t ndevices = libusb_get_device_list (g_usbhid_ctx, &devices);
+ if (ndevices < 0) {
+ ERROR (context, "Failed to enumerate the usb devices (%s).",
+ libusb_error_name (ndevices));
+ status = syserror (ndevices);
+ goto error_usb_exit;
+ }
+
+ iterator->devices = devices;
+ iterator->count = ndevices;
+ iterator->current = 0;
+#elif defined(USE_HIDAPI)
+ struct hid_device_info *devices = hid_enumerate(0x0, 0x0);
+ if (devices == NULL) {
+ status = DC_STATUS_IO;
+ goto error_usb_exit;
+ }
+
+ iterator->devices = devices;
+ iterator->current = devices;
+#endif
+ iterator->filter = dc_descriptor_get_filter (descriptor);
+
+ *out = (dc_iterator_t *) iterator;
+
+ return DC_STATUS_SUCCESS;
+
+error_usb_exit:
+ dc_usbhid_exit ();
+error_free:
+ dc_iterator_deallocate ((dc_iterator_t *) iterator);
+ return status;
+#else
+ return DC_STATUS_UNSUPPORTED;
+#endif
+}
+
+#ifdef USBHID
+static dc_status_t
+dc_usbhid_iterator_next (dc_iterator_t *abstract, void *out)
+{
+ dc_usbhid_iterator_t *iterator = (dc_usbhid_iterator_t *) abstract;
+ dc_usbhid_device_t *device = NULL;
+
+#if defined(USE_LIBUSB)
+ while (iterator->current < iterator->count) {
+ struct libusb_device *current = iterator->devices[iterator->current++];
+
+ // Get the device descriptor.
+ struct libusb_device_descriptor dev;
+ int rc = libusb_get_device_descriptor (current, &dev);
+ if (rc < 0) {
+ ERROR (abstract->context, "Failed to get the device descriptor (%s).",
+ libusb_error_name (rc));
+ return syserror (rc);
+ }
+
+ dc_usb_desc_t usb = {dev.idVendor, dev.idProduct};
+ if (iterator->filter && !iterator->filter (DC_TRANSPORT_USBHID, &usb)) {
+ continue;
+ }
+
+ // Get the active configuration descriptor.
+ struct libusb_config_descriptor *config = NULL;
+ rc = libusb_get_active_config_descriptor (current, &config);
+ if (rc != LIBUSB_SUCCESS) {
+ ERROR (abstract->context, "Failed to get the configuration descriptor (%s).",
+ libusb_error_name (rc));
+ return syserror (rc);
+ }
+
+ // Find the first HID interface.
+ const struct libusb_interface_descriptor *interface = NULL;
+ for (unsigned int i = 0; i < config->bNumInterfaces; i++) {
+ const struct libusb_interface *iface = &config->interface[i];
+ for (int j = 0; j < iface->num_altsetting; j++) {
+ const struct libusb_interface_descriptor *desc = &iface->altsetting[j];
+ if (desc->bInterfaceClass == LIBUSB_CLASS_HID && interface == NULL) {
+ interface = desc;
+ }
+ }
+ }
+
+ if (interface == NULL) {
+ libusb_free_config_descriptor (config);
+ continue;
+ }
+
+ // Find the first input and output interrupt endpoints.
+ const struct libusb_endpoint_descriptor *ep_in = NULL, *ep_out = NULL;
+ for (unsigned int i = 0; i < interface->bNumEndpoints; i++) {
+ const struct libusb_endpoint_descriptor *desc = &interface->endpoint[i];
+
+ unsigned int type = desc->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK;
+ unsigned int direction = desc->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK;
+
+ if (type != LIBUSB_TRANSFER_TYPE_INTERRUPT) {
+ continue;
+ }
+
+ if (direction == LIBUSB_ENDPOINT_IN && ep_in == NULL) {
+ ep_in = desc;
+ }
+
+ if (direction == LIBUSB_ENDPOINT_OUT && ep_out == NULL) {
+ ep_out = desc;
+ }
+ }
+
+ if (ep_in == NULL || ep_out == NULL) {
+ libusb_free_config_descriptor (config);
+ continue;
+ }
+
+ device = (dc_usbhid_device_t *) malloc (sizeof(dc_usbhid_device_t));
+ if (device == NULL) {
+ ERROR (abstract->context, "Failed to allocate memory.");
+ libusb_free_config_descriptor (config);
+ return DC_STATUS_NOMEMORY;
+ }
+
+ device->vid = dev.idVendor;
+ device->pid = dev.idProduct;
+
+ *(dc_usbhid_device_t **) out = device;
+
+ libusb_free_config_descriptor (config);
+
+ return DC_STATUS_SUCCESS;
+ }
+#elif defined(USE_HIDAPI)
+ while (iterator->current) {
+ struct hid_device_info *current = iterator->current;
+ iterator->current = current->next;
+
+ dc_usb_desc_t usb = {current->vendor_id, current->product_id};
+ if (iterator->filter && !iterator->filter (DC_TRANSPORT_USBHID, &usb)) {
+ continue;
+ }
+
+ device = (dc_usbhid_device_t *) malloc (sizeof(dc_usbhid_device_t));
+ if (device == NULL) {
+ ERROR (abstract->context, "Failed to allocate memory.");
+ return DC_STATUS_NOMEMORY;
+ }
+
+ device->vid = current->vendor_id;
+ device->pid = current->product_id;
+
+ *(dc_usbhid_device_t **) out = device;
+
+ return DC_STATUS_SUCCESS;
+ }
+#endif
+
+ return DC_STATUS_DONE;
+}
+
+static dc_status_t
+dc_usbhid_iterator_free (dc_iterator_t *abstract)
+{
+ dc_usbhid_iterator_t *iterator = (dc_usbhid_iterator_t *) abstract;
+
+#if defined(USE_LIBUSB)
+ libusb_free_device_list (iterator->devices, 1);
+#elif defined(USE_HIDAPI)
+ hid_free_enumeration (iterator->devices);
+#endif
+ dc_usbhid_exit ();
+
+ return DC_STATUS_SUCCESS;
+}
+#endif
+
dc_status_t
dc_usbhid_open (dc_iostream_t **out, dc_context_t *context, unsigned int vid, unsigned int pid)
{
diff --git a/src/usbhid.h b/src/usbhid.h
index 0b381da..6ff43d1 100644
--- a/src/usbhid.h
+++ b/src/usbhid.h
@@ -25,11 +25,54 @@
#include
#include
#include
+#include
+#include
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
+/**
+ * Opaque object representing a USB HID device.
+ */
+typedef struct dc_usbhid_device_t dc_usbhid_device_t;
+
+/**
+ * Get the vendor id (VID) of the USB HID device.
+ *
+ * @param[in] device A valid USB HID device.
+ */
+unsigned int
+dc_usbhid_device_get_vid (dc_usbhid_device_t *device);
+
+/**
+ * Get the product id (PID) of the USB HID device.
+ *
+ * @param[in] device A valid USB HID device.
+ */
+unsigned int
+dc_usbhid_device_get_pid (dc_usbhid_device_t *device);
+
+/**
+ * Destroy the USB HID device and free all resources.
+ *
+ * @param[in] device A valid USB HID device.
+ */
+void
+dc_usbhid_device_free(dc_usbhid_device_t *device);
+
+/**
+ * Create an iterator to enumerate the USB HID devices.
+ *
+ * @param[out] iterator A location to store the iterator.
+ * @param[in] context A valid context object.
+ * @param[in] descriptor A valid device descriptor or NULL.
+ * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code
+ * on failure.
+ */
+dc_status_t
+dc_usbhid_iterator_new (dc_iterator_t **iterator, dc_context_t *context, dc_descriptor_t *descriptor);
+
/**
* Open a USB HID connection.
*
diff --git a/src/uwatec_smart.c b/src/uwatec_smart.c
index 4581881..a3be17d 100644
--- a/src/uwatec_smart.c
+++ b/src/uwatec_smart.c
@@ -36,7 +36,6 @@
typedef struct uwatec_smart_device_t {
dc_device_t base;
dc_iostream_t *iostream;
- unsigned int address;
unsigned int timestamp;
unsigned int devtime;
dc_ticks_t systime;
@@ -62,8 +61,8 @@ static const dc_device_vtable_t uwatec_smart_device_vtable = {
static dc_status_t
uwatec_smart_extract_dives (dc_device_t *device, const unsigned char data[], unsigned int size, dc_dive_callback_t callback, void *userdata);
-static void
-uwatec_smart_discovery (unsigned int address, const char *name, unsigned int charset, unsigned int hints, void *userdata)
+static int
+uwatec_smart_filter (const char *name)
{
static const char *names[] = {
"Aladin Smart Com",
@@ -75,16 +74,16 @@ uwatec_smart_discovery (unsigned int address, const char *name, unsigned int cha
"UWATEC Galileo Sol",
};
- uwatec_smart_device_t *device = (uwatec_smart_device_t*) userdata;
- if (device == NULL || name == NULL)
- return;
+ if (name == NULL)
+ return 0;
for (size_t i = 0; i < C_ARRAY_SIZE(names); ++i) {
if (strcasecmp(name, names[i]) == 0) {
- device->address = address;
- return;
+ return 1;
}
}
+
+ return 0;
}
@@ -152,6 +151,8 @@ uwatec_smart_device_open (dc_device_t **out, dc_context_t *context)
{
dc_status_t status = DC_STATUS_SUCCESS;
uwatec_smart_device_t *device = NULL;
+ dc_iterator_t *iterator = NULL;
+ dc_irda_device_t *dev = NULL;
if (out == NULL)
return DC_STATUS_INVALIDARGS;
@@ -165,36 +166,44 @@ uwatec_smart_device_open (dc_device_t **out, dc_context_t *context)
// Set the default values.
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->iostream, context);
+ // Create the irda device iterator.
+ status = dc_irda_iterator_new (&iterator, context, NULL);
if (status != DC_STATUS_SUCCESS) {
- ERROR (context, "Failed to open the irda socket.");
+ ERROR (context, "Failed to create the irda iterator.");
goto error_free;
}
- // Discover the 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;
+ // Enumerate the irda devices.
+ while (1) {
+ dc_irda_device_t *current = NULL;
+ status = dc_iterator_next (iterator, ¤t);
+ if (status != DC_STATUS_SUCCESS) {
+ if (status == DC_STATUS_DONE) {
+ ERROR (context, "No dive computer found.");
+ status = DC_STATUS_NODEVICE;
+ } else {
+ ERROR (context, "Failed to enumerate the irda devices.");
+ }
+ goto error_iterator_free;
+ }
+
+ if (uwatec_smart_filter (dc_irda_device_get_name (current))) {
+ dev = current;
+ break;
+ }
+
+ dc_irda_device_free (current);
}
- if (device->address == 0) {
- ERROR (context, "No dive computer found.");
- status = DC_STATUS_IO;
- goto error_close;
- }
-
- // Connect the device.
- status = dc_irda_connect_lsap (device->iostream, device->address, 1);
+ // Open the irda socket.
+ status = dc_irda_open (&device->iostream, context, dc_irda_device_get_address (dev), 1);
if (status != DC_STATUS_SUCCESS) {
- ERROR (context, "Failed to connect the device.");
- goto error_close;
+ ERROR (context, "Failed to open the irda socket.");
+ goto error_device_free;
}
// Perform the handshaking.
@@ -210,6 +219,10 @@ uwatec_smart_device_open (dc_device_t **out, dc_context_t *context)
error_close:
dc_iostream_close (device->iostream);
+error_device_free:
+ dc_irda_device_free (dev);
+error_iterator_free:
+ dc_iterator_free (iterator);
error_free:
dc_device_deallocate ((dc_device_t *) device);
return status;