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 d8c02e8..e2a5cda 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 @@ -356,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; } @@ -372,7 +383,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); @@ -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) { + // 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..473dc57 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. - if (model >= IX3M_EASY && model <= IX3M_REB) { + parser->model = model; + if (model >= IX3M_EASY) { 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) { + // 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.