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.
This commit is contained in:
Jef Driesen 2017-05-15 22:14:47 +02:00
parent 2854453f26
commit 55b9307e19
2 changed files with 55 additions and 9 deletions

View File

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

View File

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