Merge branch 'aeris500ai'

This commit is contained in:
Jef Driesen 2016-07-11 21:48:58 +02:00
commit 335539f179
12 changed files with 334 additions and 109 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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