From 5614aff3ee7dd766048bb874798d4049a6b7e48a Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Sat, 26 Feb 2011 09:32:15 +0100 Subject: [PATCH] Add a libusb based implementation. --- configure.ac | 6 +++ src/Makefile.am | 5 +- src/atomics_cobalt.c | 117 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 127 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 4568890..059d76e 100644 --- a/configure.ac +++ b/configure.ac @@ -42,6 +42,12 @@ esac AC_MSG_RESULT([$os_win32]) AM_CONDITIONAL([OS_WIN32], [test "$os_win32" = "yes"]) +# Checks for USB support. +PKG_CHECK_MODULES([LIBUSB], [libusb-1.0], [have_libusb=yes], [have_libusb=no]) +if test "$have_libusb" = "yes"; then + AC_DEFINE([HAVE_LIBUSB], [1], [libusb support]) +fi + # Checks for IrDA support. AC_CHECK_HEADERS([winsock2.h af_irda.h], [irda_win32=yes], [irda_win32=no], [ #if HAVE_WINSOCK2_H diff --git a/src/Makefile.am b/src/Makefile.am index a0724ff..9a115e0 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -46,8 +46,11 @@ libdivecomputer_HEADERS = \ # Source files. # +AM_CFLAGS = $(LIBUSB_CFLAGS) + lib_LTLIBRARIES = libdivecomputer.la +libdivecomputer_la_LIBADD = $(LIBUSB_LIBS) libdivecomputer_la_LDFLAGS = \ -version-info $(DC_VERSION_LIBTOOL) \ -no-undefined \ @@ -106,7 +109,7 @@ endif if IRDA if OS_WIN32 -libdivecomputer_la_LIBADD = -lws2_32 +libdivecomputer_la_LIBADD += -lws2_32 endif libdivecomputer_la_SOURCES += irda.h irda.c else diff --git a/src/atomics_cobalt.c b/src/atomics_cobalt.c index 2af6a0c..0728d07 100644 --- a/src/atomics_cobalt.c +++ b/src/atomics_cobalt.c @@ -19,19 +19,35 @@ * MA 02110-1301 USA */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include // memcmp, memcpy #include // malloc, free +#ifdef HAVE_LIBUSB +#include +#endif + #include "device-private.h" #include "atomics_cobalt.h" #include "checksum.h" #include "utils.h" #include "array.h" +#define VID 0x0471 +#define PID 0x0888 +#define TIMEOUT 1000 + #define FP_OFFSET 20 typedef struct atomics_cobalt_device_t { device_t base; +#ifdef HAVE_LIBUSB + libusb_context *context; + libusb_device_handle *handle; +#endif unsigned char fingerprint[6]; } atomics_cobalt_device_t; @@ -66,6 +82,7 @@ atomics_cobalt_device_open (device_t **out) if (out == NULL) return DEVICE_STATUS_ERROR; +#ifdef HAVE_LIBUSB // Allocate memory. atomics_cobalt_device_t *device = (atomics_cobalt_device_t *) malloc (sizeof (atomics_cobalt_device_t)); if (device == NULL) { @@ -77,11 +94,37 @@ atomics_cobalt_device_open (device_t **out) device_init (&device->base, &atomics_cobalt_device_backend); // Set the default values. + device->context = NULL; + device->handle = NULL; memset (device->fingerprint, 0, sizeof (device->fingerprint)); + int rc = libusb_init (&device->context); + if (rc < 0) { + free (device); + return DEVICE_STATUS_IO; + } + + device->handle = libusb_open_device_with_vid_pid (device->context, VID, PID); + if (device->handle == NULL) { + libusb_exit (device->context); + free (device); + return DEVICE_STATUS_IO; + } + + rc = libusb_claim_interface (device->handle, 0); + if (rc < 0) { + libusb_close (device->handle); + libusb_exit (device->context); + free (device); + return DEVICE_STATUS_IO; + } + *out = (device_t*) device; return DEVICE_STATUS_SUCCESS; +#else + return DEVICE_STATUS_UNSUPPORTED; +#endif } @@ -93,6 +136,12 @@ atomics_cobalt_device_close (device_t *abstract) if (! device_is_atomics_cobalt (abstract)) return DEVICE_STATUS_TYPE_MISMATCH; +#ifdef HAVE_LIBUSB + libusb_release_interface(device->handle, 0); + libusb_close (device->handle); + libusb_exit (device->context); +#endif + // Free memory. free (device); @@ -123,7 +172,75 @@ atomics_cobalt_device_set_fingerprint (device_t *abstract, const unsigned char d static device_status_t atomics_cobalt_read_dive (device_t *abstract, dc_buffer_t *buffer, int init) { +#ifdef HAVE_LIBUSB + atomics_cobalt_device_t *device = (atomics_cobalt_device_t *) abstract; + + if (device_is_cancelled (abstract)) + return DEVICE_STATUS_CANCELLED; + + // Erase the current contents of the buffer. + if (!dc_buffer_clear (buffer)) { + WARNING ("Insufficient buffer space available."); + return DEVICE_STATUS_MEMORY; + } + + // Send the command to the dive computer. + uint8_t bRequest = init ? 0x09 : 0x0A; + int rc = libusb_control_transfer (device->handle, + LIBUSB_RECIPIENT_DEVICE | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT, + bRequest, 0, 0, NULL, 0, TIMEOUT); + if (rc != LIBUSB_SUCCESS) + return DEVICE_STATUS_IO; + + unsigned int nbytes = 0; + while (1) { + // Receive the answer from the dive computer. + int length = 0; + unsigned char packet[10 * 1024] = {0}; + rc = libusb_bulk_transfer (device->handle, 0x82, + packet, sizeof (packet), &length, TIMEOUT); + if (rc != LIBUSB_SUCCESS && rc != LIBUSB_ERROR_TIMEOUT) + return DEVICE_STATUS_IO; + + // Append the packet to the output buffer. + dc_buffer_append (buffer, packet, length); + nbytes += length; + + // If we received fewer bytes than requested, the transfer is finished. + if (length < sizeof (packet)) + break; + } + + // Check for a buffer error. + if (dc_buffer_get_size (buffer) != nbytes) { + WARNING ("Insufficient buffer space available."); + return DEVICE_STATUS_MEMORY; + } + + // Check for the minimum length. + if (nbytes < 2) { + WARNING ("Data packet is too short."); + return DEVICE_STATUS_ERROR; + } + +#if 0 + // Verify the checksum of the packet. + unsigned char *data = dc_buffer_get_data (buffer); + unsigned short crc = array_uint16_le (data + nbytes - 2); + unsigned short ccrc = checksum_add_uint16 (data, nbytes - 2, 0x0); + if (crc != ccrc) { + WARNING ("Unexpected answer CRC."); + return DEVICE_STATUS_PROTOCOL; + } +#endif + + // Remove the checksum bytes. + dc_buffer_slice (buffer, 0, nbytes - 2); + + return DEVICE_STATUS_SUCCESS; +#else return DEVICE_STATUS_UNSUPPORTED; +#endif }