From 7c0f8f9b9d92c1e0e7b1c6a5fe77eeca2b1d97f1 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Tue, 10 Jan 2017 21:30:17 +0100 Subject: [PATCH 1/3] Output samples only once all raw data is available Originally, the time and vendor sample values are emitted immediately after the previous sample is complete. This is now postponed until all raw samples are available. This will be required for the Aqualung i450t. That model appears to ignore the fixed sample rate and instead store a timestamp in each sample. That means the timestamp is only available once the last raw sample data has been reached. --- src/oceanic_atom2_parser.c | 40 ++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/src/oceanic_atom2_parser.c b/src/oceanic_atom2_parser.c index 3e67bdb..3c63a5d 100644 --- a/src/oceanic_atom2_parser.c +++ b/src/oceanic_atom2_parser.c @@ -673,6 +673,7 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ unsigned int count = 0; unsigned int complete = 1; + unsigned int previous = 0; unsigned int offset = parser->headersize; while (offset + samplesize <= size - parser->footersize) { dc_sample_value_t sample = {0}; @@ -685,12 +686,8 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ continue; } - // Time. if (complete) { - time += interval; - sample.time = time; - if (callback) callback (DC_SAMPLE_TIME, sample, userdata); - + previous = offset; complete = 0; } @@ -710,12 +707,6 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ } } - // Vendor specific data - sample.vendor.type = SAMPLE_VENDOR_OCEANIC_ATOM2; - sample.vendor.size = length; - sample.vendor.data = data + offset; - if (callback) callback (DC_SAMPLE_VENDOR, sample, userdata); - // Check for a tank switch sample. if (sampletype == 0xAA) { if (parser->model == DATAMASK || parser->model == COMPUMASK) { @@ -743,12 +734,20 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ unsigned int nsamples = surftime / interval; for (unsigned int i = 0; i < nsamples; ++i) { - if (complete) { - time += interval; - sample.time = time; - if (callback) callback (DC_SAMPLE_TIME, sample, userdata); + // Time + time += interval; + sample.time = time; + if (callback) callback (DC_SAMPLE_TIME, sample, userdata); + + // Vendor specific data + if (i == 0) { + sample.vendor.type = SAMPLE_VENDOR_OCEANIC_ATOM2; + sample.vendor.size = (offset - previous) + length; + sample.vendor.data = data + previous; + if (callback) callback (DC_SAMPLE_VENDOR, sample, userdata); } + // Depth sample.depth = 0.0; if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata); complete = 1; @@ -761,6 +760,17 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ continue; } + // Time. + time += interval; + sample.time = time; + if (callback) callback (DC_SAMPLE_TIME, sample, userdata); + + // Vendor specific data + sample.vendor.type = SAMPLE_VENDOR_OCEANIC_ATOM2; + sample.vendor.size = (offset - previous) + length; + sample.vendor.data = data + previous; + if (callback) callback (DC_SAMPLE_VENDOR, sample, userdata); + // Temperature (°F) if (have_temperature) { if (parser->model == GEO || parser->model == ATOM1 || From 8a4c1f1ef7f1a5b5371aa4b3f3974e57bd2994e5 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Thu, 12 Jan 2017 13:36:00 +0100 Subject: [PATCH 2/3] Split the raw data into multiple vendor samples After the previous commit, the raw data is now reported with one large vendor sample. Because that makes the data more difficult to interpret (for example during debugging), a small helper function is added to split the data again in multiple vendor samples. --- src/oceanic_atom2_parser.c | 51 ++++++++++++++++++++++++++++++++------ 1 file changed, 43 insertions(+), 8 deletions(-) diff --git a/src/oceanic_atom2_parser.c b/src/oceanic_atom2_parser.c index 3c63a5d..98923c7 100644 --- a/src/oceanic_atom2_parser.c +++ b/src/oceanic_atom2_parser.c @@ -557,6 +557,41 @@ oceanic_atom2_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, uns return DC_STATUS_SUCCESS; } +static void +oceanic_atom2_parser_vendor (oceanic_atom2_parser_t *parser, const unsigned char *data, unsigned int size, unsigned int samplesize, dc_sample_callback_t callback, void *userdata) +{ + unsigned int offset = 0; + while (offset + samplesize <= size) { + dc_sample_value_t sample = {0}; + + // Ignore empty samples. + if ((parser->mode != FREEDIVE && + array_isequal (data + offset, samplesize, 0x00)) || + array_isequal (data + offset, samplesize, 0xFF)) { + offset += samplesize; + continue; + } + + // Get the sample type. + unsigned int sampletype = data[offset + 0]; + if (parser->mode == FREEDIVE) + sampletype = 0; + + // Get the sample size. + unsigned int length = samplesize; + if (sampletype == 0xBB) { + length = PAGESIZE; + } + + // Vendor specific data + sample.vendor.type = SAMPLE_VENDOR_OCEANIC_ATOM2; + sample.vendor.size = length; + sample.vendor.data = data + offset; + if (callback) callback (DC_SAMPLE_VENDOR, sample, userdata); + + offset += length; + } +} static dc_status_t oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata) @@ -741,10 +776,10 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ // Vendor specific data if (i == 0) { - sample.vendor.type = SAMPLE_VENDOR_OCEANIC_ATOM2; - sample.vendor.size = (offset - previous) + length; - sample.vendor.data = data + previous; - if (callback) callback (DC_SAMPLE_VENDOR, sample, userdata); + oceanic_atom2_parser_vendor (parser, + data + previous, + (offset - previous) + length, + samplesize, callback, userdata); } // Depth @@ -766,10 +801,10 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ if (callback) callback (DC_SAMPLE_TIME, sample, userdata); // Vendor specific data - sample.vendor.type = SAMPLE_VENDOR_OCEANIC_ATOM2; - sample.vendor.size = (offset - previous) + length; - sample.vendor.data = data + previous; - if (callback) callback (DC_SAMPLE_VENDOR, sample, userdata); + oceanic_atom2_parser_vendor (parser, + data + previous, + (offset - previous) + length, + samplesize, callback, userdata); // Temperature (°F) if (have_temperature) { From e5805f3f7d9130812fadff51aaf87f092f4d25ab Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Fri, 13 Jan 2017 10:42:55 +0100 Subject: [PATCH 3/3] Fix the Aqualung i450T time samples The Aqualung i450T appears to ignore the fixed sample rate and instead store a timestamp in each sample. The presence of the surface samples in combination with this timestamp based format is odd. Even the official Diverlog software is confused: the Windows versions seems to ignore them, but the Mac version takes them into account. --- src/oceanic_atom2_parser.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/oceanic_atom2_parser.c b/src/oceanic_atom2_parser.c index 98923c7..08a2981 100644 --- a/src/oceanic_atom2_parser.c +++ b/src/oceanic_atom2_parser.c @@ -607,6 +607,7 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ if (status != DC_STATUS_SUCCESS) return status; + unsigned int extratime = 0; unsigned int time = 0; unsigned int interval = 1; unsigned int samplerate = 1; @@ -787,6 +788,8 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata); complete = 1; } + + extratime += surftime; } else { // Skip the extra samples. if ((count % samplerate) != 0) { @@ -796,7 +799,23 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ } // Time. - time += interval; + if (parser->model == I450T) { + unsigned int minute = bcd2dec(data[offset + 0]); + unsigned int hour = bcd2dec(data[offset + 1] & 0x0F); + unsigned int second = bcd2dec(data[offset + 2]); + unsigned int timestamp = (hour * 3600) + (minute * 60 ) + second + extratime; + if (timestamp < time) { + ERROR (abstract->context, "Timestamp moved backwards."); + return DC_STATUS_DATAFORMAT; + } else if (timestamp == time) { + WARNING (abstract->context, "Unexpected sample with the same timestamp ignored."); + offset += length; + continue; + } + time = timestamp; + } else { + time += interval; + } sample.time = time; if (callback) callback (DC_SAMPLE_TIME, sample, userdata);