Add support for the DiveSystem iX3M series.
The protocol of the iX3M series is almost identical to the protocol of the iDive series. The main difference is that the command bytes and the size of the response packets have been changed. In order to be able to communicate with the correct set of commands, the user needs to supply the correct number now. To maintain backwards compatibility, a new variant of the open function is added.
This commit is contained in:
parent
d516376ce7
commit
5c6c4cccc7
@ -33,9 +33,15 @@ extern "C" {
|
||||
dc_status_t
|
||||
divesystem_idive_device_open (dc_device_t **device, dc_context_t *context, const char *name);
|
||||
|
||||
dc_status_t
|
||||
divesystem_idive_device_open2 (dc_device_t **device, dc_context_t *context, const char *name, unsigned int model);
|
||||
|
||||
dc_status_t
|
||||
divesystem_idive_parser_create (dc_parser_t **parser, dc_context_t *context);
|
||||
|
||||
dc_status_t
|
||||
divesystem_idive_parser_create2 (dc_parser_t **parser, dc_context_t *context, unsigned int model);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
@ -254,6 +254,10 @@ static const dc_descriptor_t g_descriptors[] = {
|
||||
{"DiveSystem", "iDive Easy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x09},
|
||||
{"DiveSystem", "iDive X3M", DC_FAMILY_DIVESYSTEM_IDIVE, 0x0A},
|
||||
{"DiveSystem", "iDive Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x0B},
|
||||
{"DiveSystem", "iX3M Easy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x22},
|
||||
{"DiveSystem", "iX3M Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x23},
|
||||
{"DiveSystem", "iX3M Tec", DC_FAMILY_DIVESYSTEM_IDIVE, 0x24},
|
||||
{"DiveSystem", "iX3M Reb", DC_FAMILY_DIVESYSTEM_IDIVE, 0x25},
|
||||
};
|
||||
|
||||
typedef struct dc_descriptor_iterator_t {
|
||||
|
||||
@ -163,7 +163,7 @@ dc_device_open (dc_device_t **out, dc_context_t *context, dc_descriptor_t *descr
|
||||
rc = citizen_aqualand_device_open (&device, context, name);
|
||||
break;
|
||||
case DC_FAMILY_DIVESYSTEM_IDIVE:
|
||||
rc = divesystem_idive_device_open (&device, context, name);
|
||||
rc = divesystem_idive_device_open2 (&device, context, name, dc_descriptor_get_model (descriptor));
|
||||
break;
|
||||
default:
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
@ -37,6 +37,11 @@
|
||||
rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \
|
||||
)
|
||||
|
||||
#define IX3M_EASY 0x22
|
||||
#define IX3M_DEEP 0x23
|
||||
#define IX3M_TEC 0x24
|
||||
#define IX3M_REB 0x25
|
||||
|
||||
#define MAXRETRIES 9
|
||||
|
||||
#define MAXPACKET 0xFF
|
||||
@ -45,23 +50,26 @@
|
||||
#define NAK 0x15
|
||||
#define BUSY 0x60
|
||||
|
||||
#define CMD_ID 0x10
|
||||
#define CMD_RANGE 0x98
|
||||
#define CMD_HEADER 0xA0
|
||||
#define CMD_SAMPLE 0xA8
|
||||
|
||||
#define SZ_ID 0x0A
|
||||
#define SZ_RANGE 0x04
|
||||
#define SZ_HEADER 0x32
|
||||
#define SZ_SAMPLE 0x2A
|
||||
|
||||
#define NSTEPS 1000
|
||||
#define STEP(i,n) (NSTEPS * (i) / (n))
|
||||
|
||||
typedef struct divesystem_idive_command_t {
|
||||
unsigned char cmd;
|
||||
unsigned int size;
|
||||
} divesystem_idive_command_t;
|
||||
|
||||
typedef struct divesystem_idive_commands_t {
|
||||
divesystem_idive_command_t id;
|
||||
divesystem_idive_command_t range;
|
||||
divesystem_idive_command_t header;
|
||||
divesystem_idive_command_t sample;
|
||||
} divesystem_idive_commands_t;
|
||||
|
||||
typedef struct divesystem_idive_device_t {
|
||||
dc_device_t base;
|
||||
serial_t *port;
|
||||
unsigned char fingerprint[4];
|
||||
unsigned int model;
|
||||
} divesystem_idive_device_t;
|
||||
|
||||
static dc_status_t divesystem_idive_device_set_fingerprint (dc_device_t *abstract, const unsigned char data[], unsigned int size);
|
||||
@ -78,9 +86,29 @@ static const dc_device_vtable_t divesystem_idive_device_vtable = {
|
||||
divesystem_idive_device_close /* close */
|
||||
};
|
||||
|
||||
static const divesystem_idive_commands_t idive = {
|
||||
{0x10, 0x0A},
|
||||
{0x98, 0x04},
|
||||
{0xA0, 0x32},
|
||||
{0xA8, 0x2A},
|
||||
};
|
||||
|
||||
static const divesystem_idive_commands_t ix3m = {
|
||||
{0x11, 0x1A},
|
||||
{0x78, 0x04},
|
||||
{0x79, 0x36},
|
||||
{0x7A, 0x36},
|
||||
};
|
||||
|
||||
dc_status_t
|
||||
divesystem_idive_device_open (dc_device_t **out, dc_context_t *context, const char *name)
|
||||
{
|
||||
return divesystem_idive_device_open2 (out, context, name, 0);
|
||||
}
|
||||
|
||||
|
||||
dc_status_t
|
||||
divesystem_idive_device_open2 (dc_device_t **out, dc_context_t *context, const char *name, unsigned int model)
|
||||
{
|
||||
if (out == NULL)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
@ -98,6 +126,7 @@ divesystem_idive_device_open (dc_device_t **out, dc_context_t *context, const ch
|
||||
// Set the default values.
|
||||
device->port = NULL;
|
||||
memset (device->fingerprint, 0, sizeof (device->fingerprint));
|
||||
device->model = model;
|
||||
|
||||
// Open the device.
|
||||
int rc = serial_open (&device->port, context, name);
|
||||
@ -334,39 +363,43 @@ divesystem_idive_device_foreach (dc_device_t *abstract, dc_dive_callback_t callb
|
||||
{
|
||||
dc_status_t rc = DC_STATUS_SUCCESS;
|
||||
divesystem_idive_device_t *device = (divesystem_idive_device_t *) abstract;
|
||||
unsigned char packet[MAXPACKET - 2];
|
||||
|
||||
const divesystem_idive_commands_t *commands = &idive;
|
||||
if (device->model >= IX3M_EASY && device->model <= IX3M_REB) {
|
||||
commands = &ix3m;
|
||||
}
|
||||
|
||||
// Enable progress notifications.
|
||||
dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER;
|
||||
device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
|
||||
|
||||
unsigned char cmd_id[] = {CMD_ID, 0xED};
|
||||
unsigned char id[SZ_ID];
|
||||
rc = divesystem_idive_transfer (device, cmd_id, sizeof(cmd_id), id, sizeof(id));
|
||||
unsigned char cmd_id[] = {commands->id.cmd, 0xED};
|
||||
rc = divesystem_idive_transfer (device, cmd_id, sizeof(cmd_id), packet, commands->id.size);
|
||||
if (rc != DC_STATUS_SUCCESS)
|
||||
return rc;
|
||||
|
||||
// Emit a device info event.
|
||||
dc_event_devinfo_t devinfo;
|
||||
devinfo.model = array_uint16_le (id);
|
||||
devinfo.model = array_uint16_le (packet);
|
||||
devinfo.firmware = 0;
|
||||
devinfo.serial = array_uint32_le (id + 6);
|
||||
devinfo.serial = array_uint32_le (packet + 6);
|
||||
device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo);
|
||||
|
||||
// Emit a vendor event.
|
||||
dc_event_vendor_t vendor;
|
||||
vendor.data = id;
|
||||
vendor.size = sizeof (id);
|
||||
vendor.data = packet;
|
||||
vendor.size = commands->id.size;
|
||||
device_event_emit (abstract, DC_EVENT_VENDOR, &vendor);
|
||||
|
||||
unsigned char cmd_range[] = {CMD_RANGE, 0x8D};
|
||||
unsigned char range[4];
|
||||
rc = divesystem_idive_transfer (device, cmd_range, sizeof(cmd_range), range, sizeof(range));
|
||||
unsigned char cmd_range[] = {commands->range.cmd, 0x8D};
|
||||
rc = divesystem_idive_transfer (device, cmd_range, sizeof(cmd_range), packet, commands->range.size);
|
||||
if (rc != DC_STATUS_SUCCESS)
|
||||
return rc;
|
||||
|
||||
// Get the range of the available dive numbers.
|
||||
unsigned int first = array_uint16_le (range + 0);
|
||||
unsigned int last = array_uint16_le (range + 2);
|
||||
unsigned int first = array_uint16_le (packet + 0);
|
||||
unsigned int last = array_uint16_le (packet + 2);
|
||||
if (first > last) {
|
||||
ERROR(abstract->context, "Invalid dive numbers.");
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
@ -386,34 +419,32 @@ divesystem_idive_device_foreach (dc_device_t *abstract, dc_dive_callback_t callb
|
||||
|
||||
for (unsigned int i = 0; i < ndives; ++i) {
|
||||
unsigned int number = last - i;
|
||||
unsigned char cmd_header[] = {CMD_HEADER,
|
||||
unsigned char cmd_header[] = {commands->header.cmd,
|
||||
(number ) & 0xFF,
|
||||
(number >> 8) & 0xFF};
|
||||
unsigned char header[SZ_HEADER];
|
||||
rc = divesystem_idive_transfer (device, cmd_header, sizeof(cmd_header), header, sizeof(header));
|
||||
rc = divesystem_idive_transfer (device, cmd_header, sizeof(cmd_header), packet, commands->header.size);
|
||||
if (rc != DC_STATUS_SUCCESS)
|
||||
return rc;
|
||||
|
||||
if (memcmp(header + 7, device->fingerprint, sizeof(device->fingerprint)) == 0)
|
||||
if (memcmp(packet + 7, device->fingerprint, sizeof(device->fingerprint)) == 0)
|
||||
break;
|
||||
|
||||
unsigned int nsamples = array_uint16_le (header + 1);
|
||||
unsigned int nsamples = array_uint16_le (packet + 1);
|
||||
|
||||
// Update and emit a progress event.
|
||||
progress.current = i * NSTEPS + STEP(1, nsamples + 1);
|
||||
device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
|
||||
|
||||
dc_buffer_clear(buffer);
|
||||
dc_buffer_reserve(buffer, SZ_HEADER + SZ_SAMPLE * nsamples);
|
||||
dc_buffer_append(buffer, header, sizeof(header));
|
||||
dc_buffer_reserve(buffer, commands->header.size + commands->sample.size * nsamples);
|
||||
dc_buffer_append(buffer, packet, commands->header.size);
|
||||
|
||||
for (unsigned int j = 0; j < nsamples; ++j) {
|
||||
unsigned int idx = j + 1;
|
||||
unsigned char cmd_sample[] = {CMD_SAMPLE,
|
||||
unsigned char cmd_sample[] = {commands->sample.cmd,
|
||||
(idx ) & 0xFF,
|
||||
(idx >> 8) & 0xFF};
|
||||
unsigned char sample[SZ_SAMPLE];
|
||||
rc = divesystem_idive_transfer (device, cmd_sample, sizeof(cmd_sample), sample, sizeof(sample));
|
||||
rc = divesystem_idive_transfer (device, cmd_sample, sizeof(cmd_sample), packet, commands->sample.size);
|
||||
if (rc != DC_STATUS_SUCCESS)
|
||||
return rc;
|
||||
|
||||
@ -421,7 +452,7 @@ divesystem_idive_device_foreach (dc_device_t *abstract, dc_dive_callback_t callb
|
||||
progress.current = i * NSTEPS + STEP(j + 2, nsamples + 1);
|
||||
device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
|
||||
|
||||
dc_buffer_append(buffer, sample, sizeof(sample));
|
||||
dc_buffer_append(buffer, packet, commands->sample.size);
|
||||
}
|
||||
|
||||
unsigned char *data = dc_buffer_get_data(buffer);
|
||||
|
||||
@ -29,8 +29,15 @@
|
||||
|
||||
#define ISINSTANCE(parser) dc_device_isinstance((parser), &divesystem_idive_parser_vtable)
|
||||
|
||||
#define SZ_HEADER 0x32
|
||||
#define SZ_SAMPLE 0x2A
|
||||
#define IX3M_EASY 0x22
|
||||
#define IX3M_DEEP 0x23
|
||||
#define IX3M_TEC 0x24
|
||||
#define IX3M_REB 0x25
|
||||
|
||||
#define SZ_HEADER_IDIVE 0x32
|
||||
#define SZ_SAMPLE_IDIVE 0x2A
|
||||
#define SZ_HEADER_IX3M 0x36
|
||||
#define SZ_SAMPLE_IX3M 0x36
|
||||
|
||||
#define NGASMIXES 8
|
||||
|
||||
@ -40,6 +47,8 @@ typedef struct divesystem_idive_parser_t divesystem_idive_parser_t;
|
||||
|
||||
struct divesystem_idive_parser_t {
|
||||
dc_parser_t base;
|
||||
unsigned int headersize;
|
||||
unsigned int samplesize;
|
||||
// Cached fields.
|
||||
unsigned int cached;
|
||||
unsigned int divetime;
|
||||
@ -67,6 +76,13 @@ static const dc_parser_vtable_t divesystem_idive_parser_vtable = {
|
||||
|
||||
dc_status_t
|
||||
divesystem_idive_parser_create (dc_parser_t **out, dc_context_t *context)
|
||||
{
|
||||
return divesystem_idive_parser_create2 (out, context, 0);
|
||||
}
|
||||
|
||||
|
||||
dc_status_t
|
||||
divesystem_idive_parser_create2 (dc_parser_t **out, dc_context_t *context, unsigned int model)
|
||||
{
|
||||
if (out == NULL)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
@ -82,6 +98,13 @@ divesystem_idive_parser_create (dc_parser_t **out, dc_context_t *context)
|
||||
parser_init (&parser->base, context, &divesystem_idive_parser_vtable);
|
||||
|
||||
// Set the default values.
|
||||
if (model >= IX3M_EASY && model <= IX3M_REB) {
|
||||
parser->headersize = SZ_HEADER_IX3M;
|
||||
parser->samplesize = SZ_SAMPLE_IX3M;
|
||||
} else {
|
||||
parser->headersize = SZ_HEADER_IDIVE;
|
||||
parser->samplesize = SZ_SAMPLE_IDIVE;
|
||||
}
|
||||
parser->cached = 0;
|
||||
parser->divetime = 0;
|
||||
parser->maxdepth = 0;
|
||||
@ -129,7 +152,9 @@ divesystem_idive_parser_set_data (dc_parser_t *abstract, const unsigned char *da
|
||||
static dc_status_t
|
||||
divesystem_idive_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||
{
|
||||
if (abstract->size < SZ_HEADER)
|
||||
divesystem_idive_parser_t *parser = (divesystem_idive_parser_t *) abstract;
|
||||
|
||||
if (abstract->size < parser->headersize)
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
|
||||
dc_ticks_t ticks = array_uint32_le(abstract->data + 7) + EPOCH;
|
||||
@ -147,7 +172,7 @@ divesystem_idive_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
|
||||
divesystem_idive_parser_t *parser = (divesystem_idive_parser_t *) abstract;
|
||||
const unsigned char *data = abstract->data;
|
||||
|
||||
if (abstract->size < SZ_HEADER)
|
||||
if (abstract->size < parser->headersize)
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
|
||||
if (!parser->cached) {
|
||||
@ -201,8 +226,8 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
|
||||
unsigned int o2_previous = 0xFFFFFFFF;
|
||||
unsigned int he_previous = 0xFFFFFFFF;
|
||||
|
||||
unsigned int offset = SZ_HEADER;
|
||||
while (offset + SZ_SAMPLE <= size) {
|
||||
unsigned int offset = parser->headersize;
|
||||
while (offset + parser->samplesize <= size) {
|
||||
dc_sample_value_t sample = {0};
|
||||
|
||||
// Time (seconds).
|
||||
@ -279,7 +304,7 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
|
||||
sample.cns = cns / 100.0;
|
||||
if (callback) callback (DC_SAMPLE_CNS, sample, userdata);
|
||||
|
||||
offset += SZ_SAMPLE;
|
||||
offset += parser->samplesize;
|
||||
}
|
||||
|
||||
// Cache the data for later use.
|
||||
|
||||
@ -70,6 +70,7 @@ shearwater_petrel_parser_create
|
||||
diverite_nitekq_parser_create
|
||||
citizen_aqualand_parser_create
|
||||
divesystem_idive_parser_create
|
||||
divesystem_idive_parser_create2
|
||||
|
||||
dc_device_open
|
||||
dc_device_close
|
||||
@ -175,3 +176,4 @@ diverite_nitekq_device_open
|
||||
diverite_nitekq_extract_dives
|
||||
citizen_aqualand_device_open
|
||||
divesystem_idive_device_open
|
||||
divesystem_idive_device_open2
|
||||
|
||||
@ -140,7 +140,7 @@ dc_parser_new (dc_parser_t **out, dc_device_t *device)
|
||||
rc = citizen_aqualand_parser_create (&parser, context);
|
||||
break;
|
||||
case DC_FAMILY_DIVESYSTEM_IDIVE:
|
||||
rc = divesystem_idive_parser_create (&parser, context);
|
||||
rc = divesystem_idive_parser_create2 (&parser, context, device->devinfo.model);
|
||||
break;
|
||||
default:
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user