Use the new USB transport for the Atomic Aquatics Cobalt
Replace the hardcoded libusb based code with the new USB I/O transport. This enables the use of a custom I/O on platforms where libusb is not available.
This commit is contained in:
parent
c84bbd93a3
commit
c72dc4aa73
@ -19,19 +19,10 @@
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <string.h> // memcmp, memcpy
|
||||
#include <stdlib.h> // malloc, free
|
||||
|
||||
#ifdef HAVE_LIBUSB
|
||||
#ifdef _WIN32
|
||||
#define NOGDI
|
||||
#endif
|
||||
#include <libusb.h>
|
||||
#endif
|
||||
#include <libdivecomputer/usb.h>
|
||||
|
||||
#include "atomics_cobalt.h"
|
||||
#include "context-private.h"
|
||||
@ -41,8 +32,6 @@
|
||||
|
||||
#define ISINSTANCE(device) dc_device_isinstance((device), &atomics_cobalt_device_vtable)
|
||||
|
||||
#define EXITCODE(rc) (rc == LIBUSB_ERROR_TIMEOUT ? DC_STATUS_TIMEOUT : DC_STATUS_IO)
|
||||
|
||||
#define COBALT1 0
|
||||
#define COBALT2 2
|
||||
|
||||
@ -58,10 +47,7 @@
|
||||
|
||||
typedef struct atomics_cobalt_device_t {
|
||||
dc_device_t base;
|
||||
#ifdef HAVE_LIBUSB
|
||||
libusb_context *context;
|
||||
libusb_device_handle *handle;
|
||||
#endif
|
||||
dc_iostream_t *iostream;
|
||||
unsigned int simulation;
|
||||
unsigned char fingerprint[6];
|
||||
unsigned char version[SZ_VERSION];
|
||||
@ -69,7 +55,6 @@ typedef struct atomics_cobalt_device_t {
|
||||
|
||||
static dc_status_t atomics_cobalt_device_set_fingerprint (dc_device_t *abstract, const unsigned char data[], unsigned int size);
|
||||
static dc_status_t atomics_cobalt_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void *userdata);
|
||||
static dc_status_t atomics_cobalt_device_close (dc_device_t *abstract);
|
||||
|
||||
static const dc_device_vtable_t atomics_cobalt_device_vtable = {
|
||||
sizeof(atomics_cobalt_device_t),
|
||||
@ -80,22 +65,19 @@ static const dc_device_vtable_t atomics_cobalt_device_vtable = {
|
||||
NULL, /* dump */
|
||||
atomics_cobalt_device_foreach, /* foreach */
|
||||
NULL, /* timesync */
|
||||
atomics_cobalt_device_close /* close */
|
||||
NULL /* close */
|
||||
};
|
||||
|
||||
|
||||
dc_status_t
|
||||
atomics_cobalt_device_open (dc_device_t **out, dc_context_t *context)
|
||||
atomics_cobalt_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_t *iostream)
|
||||
{
|
||||
#ifdef HAVE_LIBUSB
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
atomics_cobalt_device_t *device = NULL;
|
||||
#endif
|
||||
|
||||
if (out == NULL)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
#ifdef HAVE_LIBUSB
|
||||
// Allocate memory.
|
||||
device = (atomics_cobalt_device_t *) dc_device_allocate (context, &atomics_cobalt_device_vtable);
|
||||
if (device == NULL) {
|
||||
@ -104,67 +86,30 @@ atomics_cobalt_device_open (dc_device_t **out, dc_context_t *context)
|
||||
}
|
||||
|
||||
// Set the default values.
|
||||
device->context = NULL;
|
||||
device->handle = NULL;
|
||||
device->iostream = iostream;
|
||||
device->simulation = 0;
|
||||
memset (device->fingerprint, 0, sizeof (device->fingerprint));
|
||||
|
||||
int rc = libusb_init (&device->context);
|
||||
if (rc < 0) {
|
||||
ERROR (context, "Failed to initialize usb support.");
|
||||
status = DC_STATUS_IO;
|
||||
// Set the timeout for receiving data (2000 ms).
|
||||
status = dc_iostream_set_timeout (device->iostream, TIMEOUT);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (context, "Failed to set the timeout.");
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
device->handle = libusb_open_device_with_vid_pid (device->context, VID, PID);
|
||||
if (device->handle == NULL) {
|
||||
ERROR (context, "Failed to open the usb device.");
|
||||
status = DC_STATUS_IO;
|
||||
goto error_usb_exit;
|
||||
}
|
||||
|
||||
rc = libusb_claim_interface (device->handle, 0);
|
||||
if (rc < 0) {
|
||||
ERROR (context, "Failed to claim the usb interface.");
|
||||
status = DC_STATUS_IO;
|
||||
goto error_usb_close;
|
||||
}
|
||||
|
||||
status = atomics_cobalt_device_version ((dc_device_t *) device, device->version, sizeof (device->version));
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (context, "Failed to identify the dive computer.");
|
||||
goto error_usb_close;
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
*out = (dc_device_t*) device;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
|
||||
error_usb_close:
|
||||
libusb_close (device->handle);
|
||||
error_usb_exit:
|
||||
libusb_exit (device->context);
|
||||
error_free:
|
||||
dc_device_deallocate ((dc_device_t *) device);
|
||||
return status;
|
||||
#else
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
atomics_cobalt_device_close (dc_device_t *abstract)
|
||||
{
|
||||
atomics_cobalt_device_t *device = (atomics_cobalt_device_t *) abstract;
|
||||
|
||||
#ifdef HAVE_LIBUSB
|
||||
libusb_release_interface(device->handle, 0);
|
||||
libusb_close (device->handle);
|
||||
libusb_exit (device->context);
|
||||
#endif
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
@ -202,6 +147,7 @@ atomics_cobalt_device_set_simulation (dc_device_t *abstract, unsigned int simula
|
||||
dc_status_t
|
||||
atomics_cobalt_device_version (dc_device_t *abstract, unsigned char data[], unsigned int size)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
atomics_cobalt_device_t *device = (atomics_cobalt_device_t *) abstract;
|
||||
|
||||
if (!ISINSTANCE (abstract))
|
||||
@ -210,31 +156,31 @@ atomics_cobalt_device_version (dc_device_t *abstract, unsigned char data[], unsi
|
||||
if (size < SZ_VERSION)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
#ifdef HAVE_LIBUSB
|
||||
// Send the command to the dive computer.
|
||||
uint8_t bRequest = 0x01;
|
||||
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) {
|
||||
ERROR (abstract->context, "Failed to send the command.");
|
||||
return EXITCODE(rc);
|
||||
}
|
||||
unsigned char bRequest = 0x01;
|
||||
dc_usb_control_t control = {
|
||||
DC_USB_REQUEST_VENDOR | DC_USB_RECIPIENT_DEVICE | DC_USB_ENDPOINT_OUT, /* bmRequestType */
|
||||
bRequest, /* bRequest */
|
||||
0, /* wValue */
|
||||
0, /* wIndex */
|
||||
0, /* wLength */
|
||||
};
|
||||
|
||||
HEXDUMP (abstract->context, DC_LOGLEVEL_INFO, "Write", &bRequest, 1);
|
||||
status = dc_iostream_ioctl (device->iostream, DC_IOCTL_USB_CONTROL_WRITE, &control, sizeof(control));
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to send the command.");
|
||||
return status;
|
||||
}
|
||||
|
||||
// Receive the answer from the dive computer.
|
||||
int length = 0;
|
||||
size_t length = 0;
|
||||
unsigned char packet[SZ_VERSION + 2] = {0};
|
||||
rc = libusb_bulk_transfer (device->handle, 0x82,
|
||||
packet, sizeof (packet), &length, TIMEOUT);
|
||||
if (rc != LIBUSB_SUCCESS || length != sizeof (packet)) {
|
||||
status = dc_iostream_read (device->iostream, packet, sizeof(packet), &length);
|
||||
if (status != DC_STATUS_SUCCESS || length != sizeof (packet)) {
|
||||
ERROR (abstract->context, "Failed to receive the answer.");
|
||||
return EXITCODE(rc);
|
||||
return status;
|
||||
}
|
||||
|
||||
HEXDUMP (abstract->context, DC_LOGLEVEL_INFO, "Read", packet, length);
|
||||
|
||||
// Verify the checksum of the packet.
|
||||
unsigned short crc = array_uint16_le (packet + SZ_VERSION);
|
||||
unsigned short ccrc = checksum_add_uint16 (packet, SZ_VERSION, 0x0);
|
||||
@ -246,16 +192,13 @@ atomics_cobalt_device_version (dc_device_t *abstract, unsigned char data[], unsi
|
||||
memcpy (data, packet, SZ_VERSION);
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
#else
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
atomics_cobalt_read_dive (dc_device_t *abstract, dc_buffer_t *buffer, int init, dc_event_progress_t *progress)
|
||||
{
|
||||
#ifdef HAVE_LIBUSB
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
atomics_cobalt_device_t *device = (atomics_cobalt_device_t *) abstract;
|
||||
|
||||
if (device_is_cancelled (abstract))
|
||||
@ -268,35 +211,37 @@ atomics_cobalt_read_dive (dc_device_t *abstract, dc_buffer_t *buffer, int init,
|
||||
}
|
||||
|
||||
// Send the command to the dive computer.
|
||||
uint8_t bRequest = 0;
|
||||
unsigned char bRequest = 0;
|
||||
if (device->simulation)
|
||||
bRequest = init ? 0x02 : 0x03;
|
||||
else
|
||||
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) {
|
||||
ERROR (abstract->context, "Failed to send the command.");
|
||||
return EXITCODE(rc);
|
||||
}
|
||||
|
||||
HEXDUMP (abstract->context, DC_LOGLEVEL_INFO, "Write", &bRequest, 1);
|
||||
dc_usb_control_t control = {
|
||||
DC_USB_REQUEST_VENDOR | DC_USB_RECIPIENT_DEVICE | DC_USB_ENDPOINT_OUT, /* bmRequestType */
|
||||
bRequest, /* bRequest */
|
||||
0, /* wValue */
|
||||
0, /* wIndex */
|
||||
0, /* wLength */
|
||||
};
|
||||
|
||||
status = dc_iostream_ioctl (device->iostream, DC_IOCTL_USB_CONTROL_WRITE, &control, sizeof(control));
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to send the command.");
|
||||
return status;
|
||||
}
|
||||
|
||||
unsigned int nbytes = 0;
|
||||
while (1) {
|
||||
// Receive the answer from the dive computer.
|
||||
int length = 0;
|
||||
size_t length = 0;
|
||||
unsigned char packet[8 * 1024] = {0};
|
||||
rc = libusb_bulk_transfer (device->handle, 0x82,
|
||||
packet, sizeof (packet), &length, TIMEOUT);
|
||||
if (rc != LIBUSB_SUCCESS && rc != LIBUSB_ERROR_TIMEOUT) {
|
||||
status = dc_iostream_read (device->iostream, packet, sizeof(packet), &length);
|
||||
if (status != DC_STATUS_SUCCESS && status != DC_STATUS_TIMEOUT) {
|
||||
ERROR (abstract->context, "Failed to receive the answer.");
|
||||
return EXITCODE(rc);
|
||||
return status;
|
||||
}
|
||||
|
||||
HEXDUMP (abstract->context, DC_LOGLEVEL_INFO, "Read", packet, length);
|
||||
|
||||
// Update and emit a progress event.
|
||||
if (progress) {
|
||||
progress->current += length;
|
||||
@ -343,9 +288,6 @@ atomics_cobalt_read_dive (dc_device_t *abstract, dc_buffer_t *buffer, int init,
|
||||
dc_buffer_slice (buffer, 0, nbytes - 2);
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
#else
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -23,6 +23,7 @@
|
||||
#define ATOMICS_COBALT_H
|
||||
|
||||
#include <libdivecomputer/context.h>
|
||||
#include <libdivecomputer/iostream.h>
|
||||
#include <libdivecomputer/device.h>
|
||||
#include <libdivecomputer/parser.h>
|
||||
#include <libdivecomputer/atomics_cobalt.h>
|
||||
@ -32,7 +33,7 @@ extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
dc_status_t
|
||||
atomics_cobalt_device_open (dc_device_t **device, dc_context_t *context);
|
||||
atomics_cobalt_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
||||
|
||||
dc_status_t
|
||||
atomics_cobalt_parser_create (dc_parser_t **parser, dc_context_t *context);
|
||||
|
||||
@ -61,6 +61,7 @@ static int dc_filter_mares (dc_transport_t transport, const void *userdata, void
|
||||
static int dc_filter_divesystem (dc_transport_t transport, const void *userdata, void *params);
|
||||
static int dc_filter_oceanic (dc_transport_t transport, const void *userdata, void *params);
|
||||
static int dc_filter_mclean (dc_transport_t transport, const void *userdata, void *params);
|
||||
static int dc_filter_atomic (dc_transport_t transport, const void *userdata, void *params);
|
||||
|
||||
static dc_status_t dc_descriptor_iterator_next (dc_iterator_t *iterator, void *item);
|
||||
|
||||
@ -326,8 +327,8 @@ static const dc_descriptor_t g_descriptors[] = {
|
||||
{"Dive Rite", "NiTek Trio", DC_FAMILY_ZEAGLE_N2ITION3, 0, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Scubapro", "XTender 5", DC_FAMILY_ZEAGLE_N2ITION3, 0, DC_TRANSPORT_SERIAL, NULL},
|
||||
/* Atomic Aquatics Cobalt */
|
||||
{"Atomic Aquatics", "Cobalt", DC_FAMILY_ATOMICS_COBALT, 0, DC_TRANSPORT_USB, NULL},
|
||||
{"Atomic Aquatics", "Cobalt 2", DC_FAMILY_ATOMICS_COBALT, 2, DC_TRANSPORT_USB, NULL},
|
||||
{"Atomic Aquatics", "Cobalt", DC_FAMILY_ATOMICS_COBALT, 0, DC_TRANSPORT_USB, dc_filter_atomic},
|
||||
{"Atomic Aquatics", "Cobalt 2", DC_FAMILY_ATOMICS_COBALT, 2, DC_TRANSPORT_USB, dc_filter_atomic},
|
||||
/* Shearwater Predator */
|
||||
{"Shearwater", "Predator", DC_FAMILY_SHEARWATER_PREDATOR, 2, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLUETOOTH, dc_filter_shearwater},
|
||||
/* Shearwater Petrel */
|
||||
@ -669,6 +670,23 @@ static int dc_filter_mclean(dc_transport_t transport, const void *userdata, void
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dc_filter_atomic (dc_transport_t transport, const void *userdata, void *params)
|
||||
{
|
||||
static const dc_usb_desc_t usb[] = {
|
||||
{0x0471, 0x0888}, // Atomic Aquatics Cobalt
|
||||
};
|
||||
|
||||
static const dc_usb_params_t usb_params = {
|
||||
0, 0x82, 0x02
|
||||
};
|
||||
|
||||
if (transport == DC_TRANSPORT_USB) {
|
||||
return DC_FILTER_INTERNAL_WITH_PARAMS (userdata, usb, 0, dc_match_usb, params, &usb_params);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
dc_status_t
|
||||
dc_descriptor_iterator (dc_iterator_t **out)
|
||||
{
|
||||
|
||||
@ -190,7 +190,7 @@ dc_device_open (dc_device_t **out, dc_context_t *context, dc_descriptor_t *descr
|
||||
rc = zeagle_n2ition3_device_open (&device, context, iostream);
|
||||
break;
|
||||
case DC_FAMILY_ATOMICS_COBALT:
|
||||
rc = atomics_cobalt_device_open (&device, context);
|
||||
rc = atomics_cobalt_device_open (&device, context, iostream);
|
||||
break;
|
||||
case DC_FAMILY_SHEARWATER_PREDATOR:
|
||||
rc = shearwater_predator_device_open (&device, context, iostream);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user