From 2854453f264d6414f50f897a9f37b3a60907aa8f Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Tue, 9 May 2017 21:16:39 +0200 Subject: [PATCH 1/3] Add the firmware version to the devinfo event --- src/divesystem_idive.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/divesystem_idive.c b/src/divesystem_idive.c index d8c02e8..b1913e6 100644 --- a/src/divesystem_idive.c +++ b/src/divesystem_idive.c @@ -372,7 +372,7 @@ divesystem_idive_device_foreach (dc_device_t *abstract, dc_dive_callback_t callb // Emit a device info event. dc_event_devinfo_t devinfo; devinfo.model = array_uint16_le (packet); - devinfo.firmware = 0; + devinfo.firmware = array_uint32_le (packet + 2); devinfo.serial = array_uint32_le (packet + 6); device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo); From 55b9307e193d989facad7383d989ec475b5a258e Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Mon, 15 May 2017 22:14:47 +0200 Subject: [PATCH 2/3] Add support for the new iX3M APOS4 firmware The new APOS4 firmware changed the data format and communication protocol. The size of the samples changed from 54 to 64 bytes, and in order to speedup the download, a single data packet contains 3 samples at once. If the number of samples is not an exact multiple of three, the last packet appears to contain garbage data. For parsing, the firmware version is available in the dive header. Unfortunately it can't be used for dives that are downloaded from a device with the new firmware, but which have been recorded with an older firmware. Such dives store the old firmware version in the dive header, but they also use the new sample format. As a workaround, we inspect the size of the dive. --- src/divesystem_idive.c | 35 +++++++++++++++++++++++++++++++---- src/divesystem_idive_parser.c | 29 ++++++++++++++++++++++++----- 2 files changed, 55 insertions(+), 9 deletions(-) diff --git a/src/divesystem_idive.c b/src/divesystem_idive.c index b1913e6..d5bf2e5 100644 --- a/src/divesystem_idive.c +++ b/src/divesystem_idive.c @@ -57,6 +57,7 @@ typedef struct divesystem_idive_commands_t { divesystem_idive_command_t range; divesystem_idive_command_t header; divesystem_idive_command_t sample; + unsigned int nsamples; } divesystem_idive_commands_t; typedef struct divesystem_idive_device_t { @@ -86,6 +87,7 @@ static const divesystem_idive_commands_t idive = { {0x98, 0x04}, {0xA0, 0x32}, {0xA8, 0x2A}, + 1, }; static const divesystem_idive_commands_t ix3m = { @@ -93,6 +95,15 @@ static const divesystem_idive_commands_t ix3m = { {0x78, 0x04}, {0x79, 0x36}, {0x7A, 0x36}, + 1, +}; + +static const divesystem_idive_commands_t ix3m_apos4 = { + {0x11, 0x1A}, + {0x78, 0x04}, + {0x79, 0x36}, + {0x7A, 0x40}, + 3, }; dc_status_t @@ -382,6 +393,14 @@ divesystem_idive_device_foreach (dc_device_t *abstract, dc_dive_callback_t callb vendor.size = commands->id.size; device_event_emit (abstract, DC_EVENT_VENDOR, &vendor); + if (device->model >= IX3M_EASY && device->model <= IX3M_REB) { + // Detect the APOS4 firmware. + unsigned int apos4 = (devinfo.firmware / 10000000) >= 4; + if (apos4) { + commands = &ix3m_apos4; + } + } + 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) @@ -429,20 +448,28 @@ divesystem_idive_device_foreach (dc_device_t *abstract, dc_dive_callback_t callb 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) { + for (unsigned int j = 0; j < nsamples; j += commands->nsamples) { unsigned int idx = j + 1; unsigned char cmd_sample[] = {commands->sample.cmd, (idx ) & 0xFF, (idx >> 8) & 0xFF}; - rc = divesystem_idive_transfer (device, cmd_sample, sizeof(cmd_sample), packet, commands->sample.size); + rc = divesystem_idive_transfer (device, cmd_sample, sizeof(cmd_sample), packet, commands->sample.size * commands->nsamples); if (rc != DC_STATUS_SUCCESS) return rc; + // If the number of samples is not an exact multiple of the + // number of samples per packet, then the last packet + // appears to contain garbage data. Ignore those samples. + unsigned int n = commands->nsamples; + if (j + n > nsamples) { + n = nsamples - j; + } + // Update and emit a progress event. - progress.current = i * NSTEPS + STEP(j + 2, nsamples + 1); + progress.current = i * NSTEPS + STEP(j + n + 1, nsamples + 1); device_event_emit (abstract, DC_EVENT_PROGRESS, &progress); - dc_buffer_append(buffer, packet, commands->sample.size); + dc_buffer_append(buffer, packet, commands->sample.size * n); } unsigned char *data = dc_buffer_get_data(buffer); diff --git a/src/divesystem_idive_parser.c b/src/divesystem_idive_parser.c index 968765c..3ff21b6 100644 --- a/src/divesystem_idive_parser.c +++ b/src/divesystem_idive_parser.c @@ -37,6 +37,7 @@ #define SZ_SAMPLE_IDIVE 0x2A #define SZ_HEADER_IX3M 0x36 #define SZ_SAMPLE_IX3M 0x36 +#define SZ_SAMPLE_IX3M_APOS4 0x40 #define NGASMIXES 8 @@ -53,8 +54,8 @@ typedef struct divesystem_idive_parser_t divesystem_idive_parser_t; struct divesystem_idive_parser_t { dc_parser_t base; + unsigned int model; unsigned int headersize; - unsigned int samplesize; // Cached fields. unsigned int cached; unsigned int divemode; @@ -97,12 +98,11 @@ divesystem_idive_parser_create (dc_parser_t **out, dc_context_t *context, unsign } // Set the default values. + parser->model = model; 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->divemode = INVALID; @@ -241,8 +241,27 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba unsigned int mode_previous = INVALID; unsigned int divemode = INVALID; + unsigned int nsamples = array_uint16_le (data + 1); + unsigned int samplesize = SZ_SAMPLE_IDIVE; + if (parser->model >= IX3M_EASY && parser->model <= IX3M_REB) { + // Detect the APOS4 firmware. + unsigned int firmware = array_uint32_le(data + 0x2A); + unsigned int apos4 = (firmware / 10000000) >= 4; + if (apos4) { + // Dive downloaded and recorded with the APOS4 firmware. + samplesize = SZ_SAMPLE_IX3M_APOS4; + } else if (size == parser->headersize + nsamples * SZ_SAMPLE_IX3M_APOS4) { + // Dive downloaded with the APOS4 firmware, but recorded + // with an older firmware. + samplesize = SZ_SAMPLE_IX3M_APOS4; + } else { + // Dive downloaded and recorded with an older firmware. + samplesize = SZ_SAMPLE_IX3M; + } + } + unsigned int offset = parser->headersize; - while (offset + parser->samplesize <= size) { + while (offset + samplesize <= size) { dc_sample_value_t sample = {0}; // Time (seconds). @@ -328,7 +347,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 += parser->samplesize; + offset += samplesize; } // Cache the data for later use. From 28947876a2bd0d30ccea0d35a9264c5fe2fb0ac3 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Fri, 19 May 2017 20:02:33 +0200 Subject: [PATCH 3/3] Add support for the new models --- src/descriptor.c | 9 ++++++++- src/divesystem_idive.c | 4 ++-- src/divesystem_idive_parser.c | 4 ++-- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/descriptor.c b/src/descriptor.c index 53e862c..70b51d4 100644 --- a/src/descriptor.c +++ b/src/descriptor.c @@ -290,8 +290,15 @@ static const dc_descriptor_t g_descriptors[] = { {"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 Tech+", DC_FAMILY_DIVESYSTEM_IDIVE, 0x24}, {"DiveSystem", "iX3M Reb", DC_FAMILY_DIVESYSTEM_IDIVE, 0x25}, + {"DiveSystem", "iX3M Pro Easy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x32}, + {"DiveSystem", "iX3M Pro Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x34}, + {"DiveSystem", "iX3M Pro Tech+", DC_FAMILY_DIVESYSTEM_IDIVE, 0x35}, + {"DiveSystem", "iDive2 Free", DC_FAMILY_DIVESYSTEM_IDIVE, 0x40}, + {"DiveSystem", "iDive2 Easy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x42}, + {"DiveSystem", "iDive2 Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x44}, + {"DiveSystem", "iDive2 Tech+", DC_FAMILY_DIVESYSTEM_IDIVE, 0x45}, {"Cochran", "Commander", DC_FAMILY_COCHRAN_COMMANDER, 0}, {"Cochran", "EMC-14", DC_FAMILY_COCHRAN_COMMANDER, 1}, {"Cochran", "EMC-16", DC_FAMILY_COCHRAN_COMMANDER, 2}, diff --git a/src/divesystem_idive.c b/src/divesystem_idive.c index d5bf2e5..e2a5cda 100644 --- a/src/divesystem_idive.c +++ b/src/divesystem_idive.c @@ -367,7 +367,7 @@ divesystem_idive_device_foreach (dc_device_t *abstract, dc_dive_callback_t callb unsigned char packet[MAXPACKET - 2]; const divesystem_idive_commands_t *commands = &idive; - if (device->model >= IX3M_EASY && device->model <= IX3M_REB) { + if (device->model >= IX3M_EASY) { commands = &ix3m; } @@ -393,7 +393,7 @@ divesystem_idive_device_foreach (dc_device_t *abstract, dc_dive_callback_t callb vendor.size = commands->id.size; device_event_emit (abstract, DC_EVENT_VENDOR, &vendor); - if (device->model >= IX3M_EASY && device->model <= IX3M_REB) { + if (device->model >= IX3M_EASY) { // Detect the APOS4 firmware. unsigned int apos4 = (devinfo.firmware / 10000000) >= 4; if (apos4) { diff --git a/src/divesystem_idive_parser.c b/src/divesystem_idive_parser.c index 3ff21b6..473dc57 100644 --- a/src/divesystem_idive_parser.c +++ b/src/divesystem_idive_parser.c @@ -99,7 +99,7 @@ divesystem_idive_parser_create (dc_parser_t **out, dc_context_t *context, unsign // Set the default values. parser->model = model; - if (model >= IX3M_EASY && model <= IX3M_REB) { + if (model >= IX3M_EASY) { parser->headersize = SZ_HEADER_IX3M; } else { parser->headersize = SZ_HEADER_IDIVE; @@ -243,7 +243,7 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba unsigned int nsamples = array_uint16_le (data + 1); unsigned int samplesize = SZ_SAMPLE_IDIVE; - if (parser->model >= IX3M_EASY && parser->model <= IX3M_REB) { + if (parser->model >= IX3M_EASY) { // Detect the APOS4 firmware. unsigned int firmware = array_uint32_le(data + 0x2A); unsigned int apos4 = (firmware / 10000000) >= 4;