Merge branch 'aeris500ai'
This commit is contained in:
commit
335539f179
@ -106,7 +106,7 @@ parse (dc_buffer_t *buffer, dc_context_t *context, dc_descriptor_t *descriptor,
|
||||
rc = reefnet_sensusultra_parser_create (&parser, context, devtime, systime);
|
||||
break;
|
||||
case DC_FAMILY_OCEANIC_VTPRO:
|
||||
rc = oceanic_vtpro_parser_create (&parser, context);
|
||||
rc = oceanic_vtpro_parser_create2 (&parser, context, model);
|
||||
break;
|
||||
case DC_FAMILY_OCEANIC_VEO250:
|
||||
rc = oceanic_veo250_parser_create (&parser, context, model);
|
||||
|
||||
@ -33,6 +33,9 @@ extern "C" {
|
||||
dc_status_t
|
||||
oceanic_vtpro_device_open (dc_device_t **device, dc_context_t *context, const char *name);
|
||||
|
||||
dc_status_t
|
||||
oceanic_vtpro_device_open2 (dc_device_t **device, dc_context_t *context, const char *name, unsigned int model);
|
||||
|
||||
dc_status_t
|
||||
oceanic_vtpro_device_version (dc_device_t *device, unsigned char data[], unsigned int size);
|
||||
|
||||
@ -42,6 +45,9 @@ oceanic_vtpro_device_keepalive (dc_device_t *device);
|
||||
dc_status_t
|
||||
oceanic_vtpro_parser_create (dc_parser_t **parser, dc_context_t *context);
|
||||
|
||||
dc_status_t
|
||||
oceanic_vtpro_parser_create2 (dc_parser_t **parser, dc_context_t *context, unsigned int model);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
@ -121,6 +121,7 @@ static const dc_descriptor_t g_descriptors[] = {
|
||||
{"Reefnet", "Sensus Pro", DC_FAMILY_REEFNET_SENSUSPRO, 2},
|
||||
{"Reefnet", "Sensus Ultra", DC_FAMILY_REEFNET_SENSUSULTRA, 3},
|
||||
/* 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},
|
||||
|
||||
@ -129,7 +129,7 @@ dc_device_open (dc_device_t **out, dc_context_t *context, dc_descriptor_t *descr
|
||||
rc = reefnet_sensusultra_device_open (&device, context, name);
|
||||
break;
|
||||
case DC_FAMILY_OCEANIC_VTPRO:
|
||||
rc = oceanic_vtpro_device_open (&device, context, name);
|
||||
rc = oceanic_vtpro_device_open2 (&device, context, name, dc_descriptor_get_model (descriptor));
|
||||
break;
|
||||
case DC_FAMILY_OCEANIC_VEO250:
|
||||
rc = oceanic_veo250_device_open (&device, context, name);
|
||||
|
||||
@ -58,6 +58,7 @@ mares_nemo_parser_create
|
||||
mares_darwin_parser_create
|
||||
mares_iconhd_parser_create
|
||||
oceanic_vtpro_parser_create
|
||||
oceanic_vtpro_parser_create2
|
||||
oceanic_veo250_parser_create
|
||||
oceanic_atom2_parser_create
|
||||
hw_ostc_parser_create
|
||||
@ -102,6 +103,7 @@ oceanic_veo250_device_open
|
||||
oceanic_veo250_device_version
|
||||
oceanic_veo250_device_keepalive
|
||||
oceanic_vtpro_device_open
|
||||
oceanic_vtpro_device_open2
|
||||
oceanic_vtpro_device_version
|
||||
oceanic_vtpro_device_keepalive
|
||||
reefnet_sensus_device_open
|
||||
|
||||
@ -32,7 +32,7 @@
|
||||
#include "ringbuffer.h"
|
||||
#include "checksum.h"
|
||||
|
||||
#define ISINSTANCE(device) dc_device_isinstance((device), &oceanic_atom2_device_vtable)
|
||||
#define ISINSTANCE(device) dc_device_isinstance((device), &oceanic_atom2_device_vtable.base)
|
||||
|
||||
#define VTX 0x4557
|
||||
|
||||
@ -65,15 +65,19 @@ static dc_status_t oceanic_atom2_device_read (dc_device_t *abstract, unsigned in
|
||||
static dc_status_t oceanic_atom2_device_write (dc_device_t *abstract, unsigned int address, const unsigned char data[], unsigned int size);
|
||||
static dc_status_t oceanic_atom2_device_close (dc_device_t *abstract);
|
||||
|
||||
static const dc_device_vtable_t oceanic_atom2_device_vtable = {
|
||||
sizeof(oceanic_atom2_device_t),
|
||||
DC_FAMILY_OCEANIC_ATOM2,
|
||||
oceanic_common_device_set_fingerprint, /* set_fingerprint */
|
||||
oceanic_atom2_device_read, /* read */
|
||||
oceanic_atom2_device_write, /* write */
|
||||
oceanic_common_device_dump, /* dump */
|
||||
oceanic_common_device_foreach, /* foreach */
|
||||
oceanic_atom2_device_close /* close */
|
||||
static const oceanic_common_device_vtable_t oceanic_atom2_device_vtable = {
|
||||
{
|
||||
sizeof(oceanic_atom2_device_t),
|
||||
DC_FAMILY_OCEANIC_ATOM2,
|
||||
oceanic_common_device_set_fingerprint, /* set_fingerprint */
|
||||
oceanic_atom2_device_read, /* read */
|
||||
oceanic_atom2_device_write, /* write */
|
||||
oceanic_common_device_dump, /* dump */
|
||||
oceanic_common_device_foreach, /* foreach */
|
||||
oceanic_atom2_device_close /* close */
|
||||
},
|
||||
oceanic_common_device_logbook,
|
||||
oceanic_common_device_profile,
|
||||
};
|
||||
|
||||
static const oceanic_common_version_t aeris_f10_version[] = {
|
||||
@ -544,7 +548,7 @@ oceanic_atom2_device_open2 (dc_device_t **out, dc_context_t *context, const char
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
device = (oceanic_atom2_device_t *) dc_device_allocate (context, &oceanic_atom2_device_vtable);
|
||||
device = (oceanic_atom2_device_t *) dc_device_allocate (context, &oceanic_atom2_device_vtable.base);
|
||||
if (device == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
|
||||
@ -29,6 +29,8 @@
|
||||
#include "ringbuffer.h"
|
||||
#include "array.h"
|
||||
|
||||
#define VTABLE(abstract) ((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_INCR(a,b,l) ringbuffer_increment (a, b, l->rb_logbook_begin, l->rb_logbook_end)
|
||||
|
||||
@ -187,7 +189,7 @@ oceanic_common_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
dc_status_t
|
||||
oceanic_common_device_logbook (dc_device_t *abstract, dc_event_progress_t *progress, dc_buffer_t *logbook)
|
||||
{
|
||||
oceanic_common_device_t *device = (oceanic_common_device_t *) abstract;
|
||||
@ -408,7 +410,7 @@ oceanic_common_device_logbook (dc_device_t *abstract, dc_event_progress_t *progr
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
dc_status_t
|
||||
oceanic_common_device_profile (dc_device_t *abstract, dc_event_progress_t *progress, dc_buffer_t *logbook, dc_dive_callback_t callback, void *userdata)
|
||||
{
|
||||
oceanic_common_device_t *device = (oceanic_common_device_t *) abstract;
|
||||
@ -655,7 +657,7 @@ oceanic_common_device_foreach (dc_device_t *abstract, dc_dive_callback_t callbac
|
||||
}
|
||||
|
||||
// Download the logbook ringbuffer.
|
||||
rc = oceanic_common_device_logbook (abstract, &progress, logbook);
|
||||
rc = VTABLE(abstract)->logbook (abstract, &progress, logbook);
|
||||
if (rc != DC_STATUS_SUCCESS) {
|
||||
dc_buffer_free (logbook);
|
||||
return rc;
|
||||
@ -668,7 +670,7 @@ oceanic_common_device_foreach (dc_device_t *abstract, dc_dive_callback_t callbac
|
||||
}
|
||||
|
||||
// Download the profile ringbuffer.
|
||||
rc = oceanic_common_device_profile (abstract, &progress, logbook, callback, userdata);
|
||||
rc = VTABLE(abstract)->profile (abstract, &progress, logbook, callback, userdata);
|
||||
if (rc != DC_STATUS_SUCCESS) {
|
||||
dc_buffer_free (logbook);
|
||||
return rc;
|
||||
|
||||
@ -65,6 +65,12 @@ typedef struct oceanic_common_device_t {
|
||||
unsigned int multipage;
|
||||
} oceanic_common_device_t;
|
||||
|
||||
typedef struct oceanic_common_device_vtable_t {
|
||||
dc_device_vtable_t base;
|
||||
dc_status_t (*logbook) (dc_device_t *device, dc_event_progress_t *progress, dc_buffer_t *logbook);
|
||||
dc_status_t (*profile) (dc_device_t *device, dc_event_progress_t *progress, dc_buffer_t *logbook, dc_dive_callback_t callback, void *userdata);
|
||||
} oceanic_common_device_vtable_t;
|
||||
|
||||
typedef unsigned char oceanic_common_version_t[PAGESIZE + 1];
|
||||
|
||||
int
|
||||
@ -73,6 +79,12 @@ oceanic_common_match (const unsigned char *version, const oceanic_common_version
|
||||
void
|
||||
oceanic_common_device_init (oceanic_common_device_t *device);
|
||||
|
||||
dc_status_t
|
||||
oceanic_common_device_logbook (dc_device_t *device, dc_event_progress_t *progress, dc_buffer_t *logbook);
|
||||
|
||||
dc_status_t
|
||||
oceanic_common_device_profile (dc_device_t *device, dc_event_progress_t *progress, dc_buffer_t *logbook, dc_dive_callback_t callback, void *userdata);
|
||||
|
||||
dc_status_t
|
||||
oceanic_common_device_set_fingerprint (dc_device_t *device, const unsigned char data[], unsigned int size);
|
||||
|
||||
|
||||
@ -31,7 +31,7 @@
|
||||
#include "ringbuffer.h"
|
||||
#include "checksum.h"
|
||||
|
||||
#define ISINSTANCE(device) dc_device_isinstance((device), &oceanic_veo250_device_vtable)
|
||||
#define ISINSTANCE(device) dc_device_isinstance((device), &oceanic_veo250_device_vtable.base)
|
||||
|
||||
#define MAXRETRIES 2
|
||||
#define MULTIPAGE 4
|
||||
@ -48,15 +48,19 @@ typedef struct oceanic_veo250_device_t {
|
||||
static dc_status_t oceanic_veo250_device_read (dc_device_t *abstract, unsigned int address, unsigned char data[], unsigned int size);
|
||||
static dc_status_t oceanic_veo250_device_close (dc_device_t *abstract);
|
||||
|
||||
static const dc_device_vtable_t oceanic_veo250_device_vtable = {
|
||||
sizeof(oceanic_veo250_device_t),
|
||||
DC_FAMILY_OCEANIC_VEO250,
|
||||
oceanic_common_device_set_fingerprint, /* set_fingerprint */
|
||||
oceanic_veo250_device_read, /* read */
|
||||
NULL, /* write */
|
||||
oceanic_common_device_dump, /* dump */
|
||||
oceanic_common_device_foreach, /* foreach */
|
||||
oceanic_veo250_device_close /* close */
|
||||
static const oceanic_common_device_vtable_t oceanic_veo250_device_vtable = {
|
||||
{
|
||||
sizeof(oceanic_veo250_device_t),
|
||||
DC_FAMILY_OCEANIC_VEO250,
|
||||
oceanic_common_device_set_fingerprint, /* set_fingerprint */
|
||||
oceanic_veo250_device_read, /* read */
|
||||
NULL, /* write */
|
||||
oceanic_common_device_dump, /* dump */
|
||||
oceanic_common_device_foreach, /* foreach */
|
||||
oceanic_veo250_device_close /* close */
|
||||
},
|
||||
oceanic_common_device_logbook,
|
||||
oceanic_common_device_profile,
|
||||
};
|
||||
|
||||
static const oceanic_common_version_t oceanic_vtpro_version[] = {
|
||||
@ -229,7 +233,7 @@ oceanic_veo250_device_open (dc_device_t **out, dc_context_t *context, const char
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
device = (oceanic_veo250_device_t *) dc_device_allocate (context, &oceanic_veo250_device_vtable);
|
||||
device = (oceanic_veo250_device_t *) dc_device_allocate (context, &oceanic_veo250_device_vtable.base);
|
||||
if (device == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
|
||||
@ -21,6 +21,7 @@
|
||||
|
||||
#include <string.h> // memcpy
|
||||
#include <stdlib.h> // malloc, free
|
||||
#include <assert.h>
|
||||
|
||||
#include <libdivecomputer/oceanic_vtpro.h>
|
||||
|
||||
@ -30,8 +31,9 @@
|
||||
#include "serial.h"
|
||||
#include "ringbuffer.h"
|
||||
#include "checksum.h"
|
||||
#include "array.h"
|
||||
|
||||
#define ISINSTANCE(device) dc_device_isinstance((device), &oceanic_vtpro_device_vtable)
|
||||
#define ISINSTANCE(device) dc_device_isinstance((device), &oceanic_vtpro_device_vtable.base)
|
||||
|
||||
#define MAXRETRIES 2
|
||||
#define MULTIPAGE 4
|
||||
@ -40,23 +42,37 @@
|
||||
#define NAK 0xA5
|
||||
#define END 0x51
|
||||
|
||||
#define AERIS500AI 0x4151
|
||||
|
||||
typedef enum oceanic_vtpro_protocol_t {
|
||||
MOD,
|
||||
INTR,
|
||||
} oceanic_vtpro_protocol_t;
|
||||
|
||||
typedef struct oceanic_vtpro_device_t {
|
||||
oceanic_common_device_t base;
|
||||
dc_serial_t *port;
|
||||
unsigned int model;
|
||||
oceanic_vtpro_protocol_t protocol;
|
||||
} oceanic_vtpro_device_t;
|
||||
|
||||
static dc_status_t oceanic_vtpro_device_logbook (dc_device_t *abstract, dc_event_progress_t *progress, dc_buffer_t *logbook);
|
||||
static dc_status_t oceanic_vtpro_device_read (dc_device_t *abstract, unsigned int address, unsigned char data[], unsigned int size);
|
||||
static dc_status_t oceanic_vtpro_device_close (dc_device_t *abstract);
|
||||
|
||||
static const dc_device_vtable_t oceanic_vtpro_device_vtable = {
|
||||
sizeof(oceanic_vtpro_device_t),
|
||||
DC_FAMILY_OCEANIC_VTPRO,
|
||||
oceanic_common_device_set_fingerprint, /* set_fingerprint */
|
||||
oceanic_vtpro_device_read, /* read */
|
||||
NULL, /* write */
|
||||
oceanic_common_device_dump, /* dump */
|
||||
oceanic_common_device_foreach, /* foreach */
|
||||
oceanic_vtpro_device_close /* close */
|
||||
static const oceanic_common_device_vtable_t oceanic_vtpro_device_vtable = {
|
||||
{
|
||||
sizeof(oceanic_vtpro_device_t),
|
||||
DC_FAMILY_OCEANIC_VTPRO,
|
||||
oceanic_common_device_set_fingerprint, /* set_fingerprint */
|
||||
oceanic_vtpro_device_read, /* read */
|
||||
NULL, /* write */
|
||||
oceanic_common_device_dump, /* dump */
|
||||
oceanic_common_device_foreach, /* foreach */
|
||||
oceanic_vtpro_device_close /* close */
|
||||
},
|
||||
oceanic_vtpro_device_logbook,
|
||||
oceanic_common_device_profile,
|
||||
};
|
||||
|
||||
static const oceanic_common_version_t oceanic_vtpro_version[] = {
|
||||
@ -98,6 +114,18 @@ static const oceanic_common_layout_t oceanic_wisdom_layout = {
|
||||
0 /* pt_mode_logbook */
|
||||
};
|
||||
|
||||
static const oceanic_common_layout_t aeris_500ai_layout = {
|
||||
0x20000, /* memsize */
|
||||
0x0000, /* cf_devinfo */
|
||||
0x0110, /* cf_pointers */
|
||||
0x0200, /* rb_logbook_begin */
|
||||
0x0200, /* rb_logbook_end */
|
||||
8, /* rb_logbook_entry_size */
|
||||
0x00200, /* rb_profile_begin */
|
||||
0x20000, /* rb_profile_end */
|
||||
0, /* pt_mode_global */
|
||||
1 /* pt_mode_logbook */
|
||||
};
|
||||
|
||||
static dc_status_t
|
||||
oceanic_vtpro_send (oceanic_vtpro_device_t *device, const unsigned char command[], unsigned int csize)
|
||||
@ -156,11 +184,13 @@ oceanic_vtpro_transfer (oceanic_vtpro_device_t *device, const unsigned char comm
|
||||
return rc;
|
||||
}
|
||||
|
||||
// Receive the answer of the dive computer.
|
||||
status = dc_serial_read (device->port, answer, asize, NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to receive the answer.");
|
||||
return status;
|
||||
if (asize) {
|
||||
// Receive the answer of the dive computer.
|
||||
status = dc_serial_read (device->port, answer, asize, NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to receive the answer.");
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
@ -174,8 +204,10 @@ oceanic_vtpro_init (oceanic_vtpro_device_t *device)
|
||||
dc_device_t *abstract = (dc_device_t *) device;
|
||||
|
||||
// Send the command to the dive computer.
|
||||
unsigned char command[2] = {0xAA, 0x00};
|
||||
status = dc_serial_write (device->port, command, sizeof (command), NULL);
|
||||
unsigned char command[2][2] = {
|
||||
{0xAA, 0x00},
|
||||
{0x20, 0x00}};
|
||||
status = dc_serial_write (device->port, command[device->protocol], sizeof (command[device->protocol]), NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to send the command.");
|
||||
return status;
|
||||
@ -190,10 +222,10 @@ oceanic_vtpro_init (oceanic_vtpro_device_t *device)
|
||||
}
|
||||
|
||||
// Verify the answer.
|
||||
const unsigned char response[13] = {
|
||||
0x4D, 0x4F, 0x44, 0x2D, 0x2D, 0x4F, 0x4B,
|
||||
0x5F, 0x56, 0x32, 0x2E, 0x30, 0x30};
|
||||
if (memcmp (answer, response, sizeof (response)) != 0) {
|
||||
const unsigned char response[2][13] = {
|
||||
{0x4D, 0x4F, 0x44, 0x2D, 0x2D, 0x4F, 0x4B, 0x5F, 0x56, 0x32, 0x2E, 0x30, 0x30},
|
||||
{0x49, 0x4E, 0x54, 0x52, 0x2D, 0x4F, 0x4B, 0x5F, 0x56, 0x31, 0x2E, 0x31, 0x31}};
|
||||
if (memcmp (answer, response[device->protocol], sizeof (response[device->protocol])) != 0) {
|
||||
ERROR (abstract->context, "Unexpected answer byte(s).");
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
@ -249,9 +281,115 @@ oceanic_vtpro_calibrate (oceanic_vtpro_device_t *device)
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
oceanic_aeris500ai_device_logbook (dc_device_t *abstract, dc_event_progress_t *progress, dc_buffer_t *logbook)
|
||||
{
|
||||
dc_status_t rc = DC_STATUS_SUCCESS;
|
||||
oceanic_vtpro_device_t *device = (oceanic_vtpro_device_t *) abstract;
|
||||
|
||||
assert (device != NULL);
|
||||
assert (device->base.layout != NULL);
|
||||
assert (device->base.layout->rb_logbook_entry_size == PAGESIZE / 2);
|
||||
assert (device->base.layout->rb_logbook_begin == device->base.layout->rb_logbook_end);
|
||||
assert (progress != NULL);
|
||||
|
||||
const oceanic_common_layout_t *layout = device->base.layout;
|
||||
|
||||
// Erase the buffer.
|
||||
if (!dc_buffer_clear (logbook))
|
||||
return DC_STATUS_NOMEMORY;
|
||||
|
||||
// Read the pointer data.
|
||||
unsigned char pointers[PAGESIZE] = {0};
|
||||
rc = oceanic_vtpro_device_read (abstract, layout->cf_pointers, pointers, sizeof (pointers));
|
||||
if (rc != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to read the memory page.");
|
||||
return rc;
|
||||
}
|
||||
|
||||
// Get the logbook pointers.
|
||||
unsigned int last = pointers[0x03];
|
||||
|
||||
// Update and emit a progress event.
|
||||
progress->current += PAGESIZE;
|
||||
progress->maximum += PAGESIZE + (last + 1) * PAGESIZE / 2;
|
||||
device_event_emit (abstract, DC_EVENT_PROGRESS, progress);
|
||||
|
||||
// Allocate memory for the logbook entries.
|
||||
if (!dc_buffer_reserve (logbook, (last + 1) * PAGESIZE / 2))
|
||||
return DC_STATUS_NOMEMORY;
|
||||
|
||||
// Send the logbook index command.
|
||||
unsigned char command[] = {0x52,
|
||||
(last >> 8) & 0xFF, // high
|
||||
(last ) & 0xFF, // low
|
||||
0x00};
|
||||
rc = oceanic_vtpro_transfer (device, command, sizeof (command), NULL, 0);
|
||||
if (rc != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to send the logbook index command.");
|
||||
return rc;
|
||||
}
|
||||
|
||||
// Read the logbook index.
|
||||
for (unsigned int i = 0; i < last + 1; ++i) {
|
||||
// Receive the answer of the dive computer.
|
||||
unsigned char answer[PAGESIZE / 2 + 1] = {0};
|
||||
rc = dc_serial_read (device->port, answer, sizeof(answer), NULL);
|
||||
if (rc != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to receive the answer.");
|
||||
return rc;
|
||||
}
|
||||
|
||||
// Verify the checksum of the answer.
|
||||
unsigned char crc = answer[PAGESIZE / 2];
|
||||
unsigned char ccrc = checksum_add_uint4 (answer, PAGESIZE / 2, 0x00);
|
||||
if (crc != ccrc) {
|
||||
ERROR (abstract->context, "Unexpected answer checksum.");
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
// Update and emit a progress event.
|
||||
progress->current += PAGESIZE / 2;
|
||||
device_event_emit (abstract, DC_EVENT_PROGRESS, progress);
|
||||
|
||||
// Ignore uninitialized entries.
|
||||
if (array_isequal (answer, PAGESIZE / 2, 0xFF)) {
|
||||
WARNING (abstract->context, "Uninitialized logbook entries detected!");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Compare the fingerprint to identify previously downloaded entries.
|
||||
if (memcmp (answer, device->base.fingerprint, PAGESIZE / 2) == 0) {
|
||||
dc_buffer_clear (logbook);
|
||||
} else {
|
||||
dc_buffer_append (logbook, answer, PAGESIZE / 2);
|
||||
}
|
||||
}
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
oceanic_vtpro_device_logbook (dc_device_t *abstract, dc_event_progress_t *progress, dc_buffer_t *logbook)
|
||||
{
|
||||
oceanic_vtpro_device_t *device = (oceanic_vtpro_device_t *) abstract;
|
||||
|
||||
if (device->model == AERIS500AI) {
|
||||
return oceanic_aeris500ai_device_logbook (abstract, progress, logbook);
|
||||
} else {
|
||||
return oceanic_common_device_logbook (abstract, progress, logbook);
|
||||
}
|
||||
}
|
||||
|
||||
dc_status_t
|
||||
oceanic_vtpro_device_open (dc_device_t **out, dc_context_t *context, const char *name)
|
||||
{
|
||||
return oceanic_vtpro_device_open2 (out, context, name, 0);
|
||||
}
|
||||
|
||||
|
||||
dc_status_t
|
||||
oceanic_vtpro_device_open2 (dc_device_t **out, dc_context_t *context, const char *name, unsigned int model)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
oceanic_vtpro_device_t *device = NULL;
|
||||
@ -260,7 +398,7 @@ oceanic_vtpro_device_open (dc_device_t **out, dc_context_t *context, const char
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
device = (oceanic_vtpro_device_t *) dc_device_allocate (context, &oceanic_vtpro_device_vtable);
|
||||
device = (oceanic_vtpro_device_t *) dc_device_allocate (context, &oceanic_vtpro_device_vtable.base);
|
||||
if (device == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
@ -274,6 +412,12 @@ oceanic_vtpro_device_open (dc_device_t **out, dc_context_t *context, const char
|
||||
|
||||
// Set the default values.
|
||||
device->port = NULL;
|
||||
device->model = model;
|
||||
if (model == AERIS500AI) {
|
||||
device->protocol = INTR;
|
||||
} else {
|
||||
device->protocol = MOD;
|
||||
}
|
||||
|
||||
// Open the device.
|
||||
status = dc_serial_open (&device->port, context, name);
|
||||
@ -311,7 +455,7 @@ oceanic_vtpro_device_open (dc_device_t **out, dc_context_t *context, const char
|
||||
}
|
||||
|
||||
// Give the interface 100 ms to settle and draw power up.
|
||||
dc_serial_sleep (device->port, 100);
|
||||
dc_serial_sleep (device->port, device->protocol == MOD ? 100 : 1000);
|
||||
|
||||
// Make sure everything is in a sane state.
|
||||
dc_serial_purge (device->port, DC_DIRECTION_ALL);
|
||||
@ -339,7 +483,9 @@ oceanic_vtpro_device_open (dc_device_t **out, dc_context_t *context, const char
|
||||
}
|
||||
|
||||
// Override the base class values.
|
||||
if (OCEANIC_COMMON_MATCH (device->base.version, oceanic_wisdom_version)) {
|
||||
if (model == AERIS500AI) {
|
||||
device->base.layout = &aeris_500ai_layout;
|
||||
} else if (OCEANIC_COMMON_MATCH (device->base.version, oceanic_wisdom_version)) {
|
||||
device->base.layout = &oceanic_wisdom_layout;
|
||||
} else {
|
||||
device->base.layout = &oceanic_vtpro_layout;
|
||||
@ -431,32 +577,36 @@ oceanic_vtpro_device_version (dc_device_t *abstract, unsigned char data[], unsig
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
// Obtain the device identification string. This string is
|
||||
// split over two packets, but we join both parts again.
|
||||
if (device->protocol == MOD) {
|
||||
// Obtain the device identification string. This string is
|
||||
// split over two packets, but we join both parts again.
|
||||
for (unsigned int i = 0; i < 2; ++i) {
|
||||
unsigned char command[4] = {0x72, 0x03, i * 0x10, 0x00};
|
||||
unsigned char answer[PAGESIZE / 2 + 2] = {0};
|
||||
rc = oceanic_vtpro_transfer (device, command, sizeof (command), answer, sizeof (answer));
|
||||
if (rc != DC_STATUS_SUCCESS)
|
||||
return rc;
|
||||
|
||||
for (unsigned int i = 0; i < 2; ++i) {
|
||||
unsigned char command[4] = {0x72, 0x03, i * 0x10, 0x00};
|
||||
unsigned char answer[PAGESIZE / 2 + 2] = {0};
|
||||
rc = oceanic_vtpro_transfer (device, command, sizeof (command), answer, sizeof (answer));
|
||||
if (rc != DC_STATUS_SUCCESS)
|
||||
return rc;
|
||||
// Verify the checksum of the answer.
|
||||
unsigned char crc = answer[PAGESIZE / 2];
|
||||
unsigned char ccrc = checksum_add_uint4 (answer, PAGESIZE / 2, 0x00);
|
||||
if (crc != ccrc) {
|
||||
ERROR (abstract->context, "Unexpected answer checksum.");
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
// Verify the checksum of the answer.
|
||||
unsigned char crc = answer[PAGESIZE / 2];
|
||||
unsigned char ccrc = checksum_add_uint4 (answer, PAGESIZE / 2, 0x00);
|
||||
if (crc != ccrc) {
|
||||
ERROR (abstract->context, "Unexpected answer checksum.");
|
||||
return DC_STATUS_PROTOCOL;
|
||||
// Verify the last byte of the answer.
|
||||
if (answer[PAGESIZE / 2 + 1] != END) {
|
||||
ERROR (abstract->context, "Unexpected answer byte.");
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
// Append the answer to the output buffer.
|
||||
memcpy (data + i * PAGESIZE / 2, answer, PAGESIZE / 2);
|
||||
}
|
||||
|
||||
// Verify the last byte of the answer.
|
||||
if (answer[PAGESIZE / 2 + 1] != END) {
|
||||
ERROR (abstract->context, "Unexpected answer byte.");
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
// Append the answer to the output buffer.
|
||||
memcpy (data + i * PAGESIZE / 2, answer, PAGESIZE / 2);
|
||||
} else {
|
||||
// Return an empty device identification string.
|
||||
memset (data, 0x00, PAGESIZE);
|
||||
}
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
|
||||
@ -31,10 +31,13 @@
|
||||
|
||||
#define ISINSTANCE(parser) dc_parser_isinstance((parser), &oceanic_vtpro_parser_vtable)
|
||||
|
||||
#define AERIS500AI 0x4151
|
||||
|
||||
typedef struct oceanic_vtpro_parser_t oceanic_vtpro_parser_t;
|
||||
|
||||
struct oceanic_vtpro_parser_t {
|
||||
dc_parser_t base;
|
||||
unsigned int model;
|
||||
// Cached fields.
|
||||
unsigned int cached;
|
||||
unsigned int divetime;
|
||||
@ -59,6 +62,13 @@ static const dc_parser_vtable_t oceanic_vtpro_parser_vtable = {
|
||||
|
||||
dc_status_t
|
||||
oceanic_vtpro_parser_create (dc_parser_t **out, dc_context_t *context)
|
||||
{
|
||||
return oceanic_vtpro_parser_create2 (out, context, 0);
|
||||
}
|
||||
|
||||
|
||||
dc_status_t
|
||||
oceanic_vtpro_parser_create2 (dc_parser_t **out, dc_context_t *context, unsigned int model)
|
||||
{
|
||||
oceanic_vtpro_parser_t *parser = NULL;
|
||||
|
||||
@ -73,6 +83,7 @@ oceanic_vtpro_parser_create (dc_parser_t **out, dc_context_t *context)
|
||||
}
|
||||
|
||||
// Set the default values.
|
||||
parser->model = model;
|
||||
parser->cached = 0;
|
||||
parser->divetime = 0;
|
||||
parser->maxdepth = 0.0;
|
||||
@ -100,27 +111,41 @@ oceanic_vtpro_parser_set_data (dc_parser_t *abstract, const unsigned char *data,
|
||||
static dc_status_t
|
||||
oceanic_vtpro_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||
{
|
||||
oceanic_vtpro_parser_t *parser = (oceanic_vtpro_parser_t *) abstract;
|
||||
|
||||
if (abstract->size < 8)
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
|
||||
const unsigned char *p = abstract->data;
|
||||
|
||||
if (datetime) {
|
||||
// The logbook entry can only store the last digit of the year field,
|
||||
// but the full year is also available in the dive header.
|
||||
if (abstract->size < 40)
|
||||
datetime->year = bcd2dec (p[4] & 0x0F) + 2000;
|
||||
else
|
||||
datetime->year = bcd2dec (((p[32 + 3] & 0xC0) >> 2) + ((p[32 + 2] & 0xF0) >> 4)) + 2000;
|
||||
datetime->month = (p[4] & 0xF0) >> 4;
|
||||
datetime->day = bcd2dec (p[3]);
|
||||
datetime->hour = bcd2dec (p[1] & 0x7F);
|
||||
// AM/PM bit of the 12-hour clock.
|
||||
unsigned int pm = 0;
|
||||
|
||||
if (parser->model == AERIS500AI) {
|
||||
datetime->year = (p[2] & 0x0F) + 1999;
|
||||
datetime->month = (p[3] & 0xF0) >> 4;
|
||||
datetime->day = ((p[2] & 0xF0) >> 4) | ((p[3] & 0x02) << 3);
|
||||
datetime->hour = bcd2dec (p[1] & 0x0F) + 10 * (p[3] & 0x01);
|
||||
pm = p[3] & 0x08;
|
||||
} else {
|
||||
// The logbook entry can only store the last digit of the year field,
|
||||
// but the full year is also available in the dive header.
|
||||
if (abstract->size < 40)
|
||||
datetime->year = bcd2dec (p[4] & 0x0F) + 2000;
|
||||
else
|
||||
datetime->year = bcd2dec (((p[32 + 3] & 0xC0) >> 2) + ((p[32 + 2] & 0xF0) >> 4)) + 2000;
|
||||
datetime->month = (p[4] & 0xF0) >> 4;
|
||||
datetime->day = bcd2dec (p[3]);
|
||||
datetime->hour = bcd2dec (p[1] & 0x7F);
|
||||
pm = p[1] & 0x80;
|
||||
}
|
||||
datetime->minute = bcd2dec (p[0]);
|
||||
datetime->second = 0;
|
||||
|
||||
// Convert to a 24-hour clock.
|
||||
datetime->hour %= 12;
|
||||
if (p[1] & 0x80)
|
||||
if (pm)
|
||||
datetime->hour += 12;
|
||||
}
|
||||
|
||||
@ -153,8 +178,17 @@ oceanic_vtpro_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, uns
|
||||
|
||||
unsigned int footer = size - PAGESIZE;
|
||||
|
||||
unsigned int oxygen = 0;
|
||||
unsigned int maxdepth = 0;
|
||||
unsigned int beginpressure = array_uint16_le(data + 0x26) & 0x0FFF;
|
||||
unsigned int endpressure = array_uint16_le(data + footer + 0x05) & 0x0FFF;
|
||||
if (parser->model == AERIS500AI) {
|
||||
oxygen = (array_uint16_le(data + footer + 2) & 0x0FF0) >> 4;
|
||||
maxdepth = data[footer + 1];
|
||||
} else {
|
||||
oxygen = data[footer + 3];
|
||||
maxdepth = array_uint16_le(data + footer + 0) & 0x0FFF;
|
||||
}
|
||||
|
||||
dc_gasmix_t *gasmix = (dc_gasmix_t *) value;
|
||||
dc_tank_t *tank = (dc_tank_t *) value;
|
||||
@ -165,15 +199,15 @@ oceanic_vtpro_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, uns
|
||||
*((unsigned int *) value) = parser->divetime;
|
||||
break;
|
||||
case DC_FIELD_MAXDEPTH:
|
||||
*((double *) value) = (data[footer + 0] + ((data[footer + 1] & 0x0F) << 8)) * FEET;
|
||||
*((double *) value) = maxdepth * FEET;
|
||||
break;
|
||||
case DC_FIELD_GASMIX_COUNT:
|
||||
*((unsigned int *) value) = 1;
|
||||
break;
|
||||
case DC_FIELD_GASMIX:
|
||||
gasmix->helium = 0.0;
|
||||
if (data[footer + 3])
|
||||
gasmix->oxygen = data[footer + 3] / 100.0;
|
||||
if (oxygen)
|
||||
gasmix->oxygen = oxygen / 100.0;
|
||||
else
|
||||
gasmix->oxygen = 0.21;
|
||||
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
|
||||
@ -204,6 +238,8 @@ oceanic_vtpro_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, uns
|
||||
static dc_status_t
|
||||
oceanic_vtpro_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata)
|
||||
{
|
||||
oceanic_vtpro_parser_t *parser = (oceanic_vtpro_parser_t *) abstract;
|
||||
|
||||
const unsigned char *data = abstract->data;
|
||||
unsigned int size = abstract->size;
|
||||
|
||||
@ -212,22 +248,18 @@ oceanic_vtpro_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
|
||||
|
||||
unsigned int time = 0;
|
||||
unsigned int interval = 0;
|
||||
switch ((data[0x27] >> 4) & 0x07) {
|
||||
case 0:
|
||||
interval = 2;
|
||||
break;
|
||||
case 1:
|
||||
interval = 15;
|
||||
break;
|
||||
case 2:
|
||||
interval = 30;
|
||||
break;
|
||||
case 3:
|
||||
interval = 60;
|
||||
break;
|
||||
default:
|
||||
interval = 0;
|
||||
break;
|
||||
if (parser->model == AERIS500AI) {
|
||||
const unsigned int intervals[] = {2, 5, 10, 15, 20, 25, 30};
|
||||
unsigned int samplerate = (data[0x27] >> 4);
|
||||
if (samplerate >= 3 && samplerate <= 9) {
|
||||
interval = intervals[samplerate - 3];
|
||||
}
|
||||
} else {
|
||||
const unsigned int intervals[] = {2, 15, 30, 60};
|
||||
unsigned int samplerate = (data[0x27] >> 4) & 0x07;
|
||||
if (samplerate <= 3) {
|
||||
interval = intervals[samplerate];
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize the state for the timestamp processing.
|
||||
@ -238,7 +270,8 @@ oceanic_vtpro_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
|
||||
dc_sample_value_t sample = {0};
|
||||
|
||||
// Ignore empty samples.
|
||||
if (array_isequal (data + offset, PAGESIZE / 2, 0x00)) {
|
||||
if (array_isequal (data + offset, PAGESIZE / 2, 0x00) ||
|
||||
array_isequal (data + offset, PAGESIZE / 2, 0xFF)) {
|
||||
offset += PAGESIZE / 2;
|
||||
continue;
|
||||
}
|
||||
@ -264,7 +297,8 @@ oceanic_vtpro_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
|
||||
unsigned int idx = offset + PAGESIZE / 2 ;
|
||||
while (idx + PAGESIZE / 2 <= size - PAGESIZE) {
|
||||
// Ignore empty samples.
|
||||
if (array_isequal (data + idx, PAGESIZE / 2, 0x00)) {
|
||||
if (array_isequal (data + idx, PAGESIZE / 2, 0x00) ||
|
||||
array_isequal (data + idx, PAGESIZE / 2, 0xFF)) {
|
||||
idx += PAGESIZE / 2;
|
||||
continue;
|
||||
}
|
||||
@ -312,12 +346,22 @@ oceanic_vtpro_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
|
||||
if (callback) callback (DC_SAMPLE_VENDOR, sample, userdata);
|
||||
|
||||
// Depth (ft)
|
||||
unsigned int depth = data[offset + 3];
|
||||
unsigned int depth = 0;
|
||||
if (parser->model == AERIS500AI) {
|
||||
depth = (array_uint16_le(data + offset + 2) & 0x0FF0) >> 4;
|
||||
} else {
|
||||
depth = data[offset + 3];
|
||||
}
|
||||
sample.depth = depth * FEET;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
|
||||
// Temperature (°F)
|
||||
unsigned int temperature = data[offset + 6];
|
||||
unsigned int temperature = 0;
|
||||
if (parser->model == AERIS500AI) {
|
||||
temperature = (array_uint16_le(data + offset + 6) & 0x0FF0) >> 4;
|
||||
} else {
|
||||
temperature = data[offset + 6];
|
||||
}
|
||||
sample.temperature = (temperature - 32.0) * (5.0 / 9.0);
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
|
||||
|
||||
|
||||
@ -92,7 +92,7 @@ dc_parser_new (dc_parser_t **out, dc_device_t *device)
|
||||
rc = reefnet_sensusultra_parser_create (&parser, context, device->clock.devtime, device->clock.systime);
|
||||
break;
|
||||
case DC_FAMILY_OCEANIC_VTPRO:
|
||||
rc = oceanic_vtpro_parser_create (&parser, context);
|
||||
rc = oceanic_vtpro_parser_create2 (&parser, context, device->devinfo.model);
|
||||
break;
|
||||
case DC_FAMILY_OCEANIC_VEO250:
|
||||
rc = oceanic_veo250_parser_create (&parser, context, device->devinfo.model);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user