From e1f939c131abe81e8e63281250a0c0a84679223d Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Sun, 3 May 2015 20:06:27 +0200 Subject: [PATCH 1/4] Move all caching code to a common function. --- src/suunto_eon_parser.c | 143 +++++++++++++++++++++------------------- 1 file changed, 76 insertions(+), 67 deletions(-) diff --git a/src/suunto_eon_parser.c b/src/suunto_eon_parser.c index 534b847..2ebe800 100644 --- a/src/suunto_eon_parser.c +++ b/src/suunto_eon_parser.c @@ -39,6 +39,8 @@ struct suunto_eon_parser_t { unsigned int cached; unsigned int divetime; unsigned int maxdepth; + unsigned int marker; + unsigned int nitrox; }; static dc_status_t suunto_eon_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size); @@ -56,6 +58,55 @@ static const dc_parser_vtable_t suunto_eon_parser_vtable = { suunto_eon_parser_destroy /* destroy */ }; +static dc_status_t +suunto_eon_parser_cache (suunto_eon_parser_t *parser) +{ + dc_parser_t *abstract = (dc_parser_t *) parser; + const unsigned char *data = parser->base.data; + unsigned int size = parser->base.size; + + if (parser->cached) { + return DC_STATUS_SUCCESS; + } + + if (size < 13) { + return DC_STATUS_DATAFORMAT; + } + + // The Solution Nitrox/Vario stores nitrox data, not tank pressure. + unsigned int nitrox = !parser->spyder && (data[4] & 0x80); + + // Parse the samples. + unsigned int interval = data[3]; + unsigned int nsamples = 0; + unsigned int depth = 0, maxdepth = 0; + unsigned int offset = 11; + while (offset < size && data[offset] != 0x80) { + unsigned char value = data[offset++]; + if (value < 0x7d || value > 0x82) { + depth += (signed char) value; + if (depth > maxdepth) + maxdepth = depth; + nsamples++; + } + } + + // Check the end marker. + unsigned int marker = offset; + if (marker + 2 >= size || data[marker] != 0x80) { + ERROR (abstract->context, "No valid end marker found!"); + return DC_STATUS_DATAFORMAT; + } + + // Cache the data for later use. + parser->divetime = nsamples * interval; + parser->maxdepth = maxdepth; + parser->marker = marker; + parser->nitrox = nitrox; + parser->cached = 1; + + return DC_STATUS_SUCCESS; +} dc_status_t suunto_eon_parser_create (dc_parser_t **out, dc_context_t *context, int spyder) @@ -78,6 +129,8 @@ suunto_eon_parser_create (dc_parser_t **out, dc_context_t *context, int spyder) parser->cached = 0; parser->divetime = 0; parser->maxdepth = 0; + parser->marker = 0; + parser->nitrox = 0; *out = (dc_parser_t*) parser; @@ -104,6 +157,8 @@ suunto_eon_parser_set_data (dc_parser_t *abstract, const unsigned char *data, un parser->cached = 0; parser->divetime = 0; parser->maxdepth = 0; + parser->marker = 0; + parser->nitrox = 0; return DC_STATUS_SUCCESS; } @@ -146,35 +201,11 @@ suunto_eon_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsign suunto_eon_parser_t *parser = (suunto_eon_parser_t *) abstract; const unsigned char *data = abstract->data; - unsigned int size = abstract->size; - if (size < 13) - return DC_STATUS_DATAFORMAT; - - if (!parser->cached) { - unsigned int interval = data[3]; - unsigned int nsamples = 0; - unsigned int depth = 0, maxdepth = 0; - unsigned int offset = 11; - while (offset < size && data[offset] != 0x80) { - unsigned char value = data[offset++]; - if (value < 0x7d || value > 0x82) { - depth += (signed char) value; - if (depth > maxdepth) - maxdepth = depth; - nsamples++; - } - } - - // Store the offset to the end marker. - unsigned int marker = offset; - if (marker + 2 >= size || data[marker] != 0x80) - return DC_STATUS_DATAFORMAT; - - parser->cached = 1; - parser->divetime = nsamples * interval; - parser->maxdepth = maxdepth; - } + // Cache the data. + dc_status_t rc = suunto_eon_parser_cache (parser); + if (rc != DC_STATUS_SUCCESS) + return rc; dc_gasmix_t *gasmix = (dc_gasmix_t *) value; @@ -191,7 +222,7 @@ suunto_eon_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsign break; case DC_FIELD_GASMIX: gasmix->helium = 0.0; - if ((data[4] & 0x80) && !parser->spyder) + if (parser->nitrox) gasmix->oxygen = data[0x05] / 100.0; else gasmix->oxygen = 0.21; @@ -210,45 +241,21 @@ static dc_status_t suunto_eon_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata) { suunto_eon_parser_t *parser = (suunto_eon_parser_t *) abstract; - const unsigned char *data = abstract->data; unsigned int size = abstract->size; - - if (size < 13) - return DC_STATUS_DATAFORMAT; - - // Find the maximum depth. - unsigned int depth = 0, maxdepth = 0; - unsigned int offset = 11; - while (offset < size && data[offset] != 0x80) { - unsigned char value = data[offset++]; - if (value < 0x7d || value > 0x82) { - depth += (signed char) value; - if (depth > maxdepth) - maxdepth = depth; - } - } - - // Store the offset to the end marker. - unsigned int marker = offset; - if (marker + 2 >= size || data[marker] != 0x80) - return DC_STATUS_DATAFORMAT; - - // The Solution Nitrox/Vario stores nitrox data, not tank pressure. - unsigned int nitrox = !parser->spyder && (data[4] & 0x80); - - unsigned int time = 0; - unsigned int interval = data[3]; - unsigned int complete = 1; - dc_sample_value_t sample = {0}; + // Cache the data. + dc_status_t rc = suunto_eon_parser_cache (parser); + if (rc != DC_STATUS_SUCCESS) + return rc; + // Time - sample.time = time; + sample.time = 0; if (callback) callback (DC_SAMPLE_TIME, sample, userdata); // Tank Pressure (2 bar) - if (!nitrox) { + if (!parser->nitrox) { sample.pressure.tank = 0; sample.pressure.value = data[5] * 2; if (callback) callback (DC_SAMPLE_PRESSURE, sample, userdata); @@ -258,10 +265,12 @@ suunto_eon_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c sample.depth = 0; if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata); - depth = 0; - offset = 11; + unsigned int depth = 0; + unsigned int time = 0; + unsigned int interval = data[3]; + unsigned int complete = 1; + unsigned int offset = 11; while (offset < size && data[offset] != 0x80) { - dc_sample_value_t sample = {0}; unsigned char value = data[offset++]; if (complete) { @@ -277,11 +286,11 @@ suunto_eon_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c depth += (signed char) value; // Temperature at maximum depth (°C) - if (depth == maxdepth) { + if (depth == parser->maxdepth) { if (parser->spyder) - sample.temperature = (signed char) data[marker + 1]; + sample.temperature = (signed char) data[parser->marker + 1]; else - sample.temperature = data[marker + 1] - 40; + sample.temperature = data[parser->marker + 1] - 40; if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata); } @@ -328,7 +337,7 @@ suunto_eon_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c } // Tank Pressure (2 bar) - if (!nitrox) { + if (!parser->nitrox) { sample.pressure.tank = 0; sample.pressure.value = data[offset + 2] * 2; if (callback) callback (DC_SAMPLE_PRESSURE, sample, userdata); From 5a61ffcc2f3e2f520be526f7ff1c368bcfa2a8a1 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Sun, 3 May 2015 20:09:43 +0200 Subject: [PATCH 2/4] Use a variable for gauge mode. This makes the code a little bit more readable, without needing any comments. --- src/suunto_vyper_parser.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/suunto_vyper_parser.c b/src/suunto_vyper_parser.c index 910670f..69f0b90 100644 --- a/src/suunto_vyper_parser.c +++ b/src/suunto_vyper_parser.c @@ -243,6 +243,8 @@ suunto_vyper_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsi if (rc != DC_STATUS_SUCCESS) return rc; + unsigned int gauge = data[4] & 0x40; + if (value) { switch (type) { case DC_FIELD_DIVETIME: @@ -252,8 +254,8 @@ suunto_vyper_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsi *((double *) value) = parser->maxdepth * FEET; break; case DC_FIELD_GASMIX_COUNT: - if (data[4] & 0x40) - *((unsigned int *) value) = 0; // Gauge mode + if (gauge) + *((unsigned int *) value) = 0; else *((unsigned int *) value) = parser->ngasmixes; break; @@ -269,7 +271,7 @@ suunto_vyper_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsi *((double *) value) = (signed char) data[parser->marker + 1]; break; case DC_FIELD_DIVEMODE: - if (data[4] & 0x40) { + if (gauge) { *((dc_divemode_t *) value) = DC_DIVEMODE_GAUGE; } else { *((dc_divemode_t *) value) = DC_DIVEMODE_OC; From 7278a70afe8e61ad3beaebeb179b1c9966f0e991 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Sun, 3 May 2015 20:13:04 +0200 Subject: [PATCH 3/4] Implement the tank and temperature fields. --- src/suunto_eon_parser.c | 36 ++++++++++++++++++++++++++++++++---- src/suunto_vyper_parser.c | 20 ++++++++++++++++++++ 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/src/suunto_eon_parser.c b/src/suunto_eon_parser.c index 2ebe800..ad21b94 100644 --- a/src/suunto_eon_parser.c +++ b/src/suunto_eon_parser.c @@ -208,6 +208,17 @@ suunto_eon_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsign return rc; dc_gasmix_t *gasmix = (dc_gasmix_t *) value; + dc_tank_t *tank = (dc_tank_t *) value; + + unsigned int oxygen = 21; + unsigned int beginpressure = 0; + unsigned int endpressure = 0; + if (parser->nitrox) { + oxygen = data[0x05]; + } else { + beginpressure = data[5] * 2; + endpressure = data[parser->marker + 2] * 2; + } if (value) { switch (type) { @@ -222,12 +233,29 @@ suunto_eon_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsign break; case DC_FIELD_GASMIX: gasmix->helium = 0.0; - if (parser->nitrox) - gasmix->oxygen = data[0x05] / 100.0; - else - gasmix->oxygen = 0.21; + gasmix->oxygen = oxygen / 100.0; gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium; break; + case DC_FIELD_TANK_COUNT: + if (beginpressure == 0 && endpressure == 0) + *((unsigned int *) value) = 0; + else + *((unsigned int *) value) = 1; + break; + case DC_FIELD_TANK: + tank->type = DC_TANKVOLUME_NONE; + tank->volume = 0.0; + tank->workpressure = 0.0; + tank->gasmix = 0; + tank->beginpressure = beginpressure; + tank->endpressure = endpressure; + break; + case DC_FIELD_TEMPERATURE_MINIMUM: + if (parser->spyder) + *((double *) value) = (signed char) data[parser->marker + 1]; + else + *((double *) value) = data[parser->marker + 1] - 40; + break; default: return DC_STATUS_UNSUPPORTED; } diff --git a/src/suunto_vyper_parser.c b/src/suunto_vyper_parser.c index 69f0b90..dafcf16 100644 --- a/src/suunto_vyper_parser.c +++ b/src/suunto_vyper_parser.c @@ -237,6 +237,7 @@ suunto_vyper_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsi unsigned int size = abstract->size; dc_gasmix_t *gas = (dc_gasmix_t *) value; + dc_tank_t *tank = (dc_tank_t *) value; // Cache the data. dc_status_t rc = suunto_vyper_parser_cache (parser); @@ -244,6 +245,8 @@ suunto_vyper_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsi return rc; unsigned int gauge = data[4] & 0x40; + unsigned int beginpressure = data[5] * 2; + unsigned int endpressure = data[parser->marker + 3] * 2; if (value) { switch (type) { @@ -264,6 +267,23 @@ suunto_vyper_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsi gas->oxygen = parser->oxygen[flags] / 100.0; gas->nitrogen = 1.0 - gas->oxygen - gas->helium; break; + case DC_FIELD_TANK_COUNT: + if (beginpressure == 0 && endpressure == 0) + *((unsigned int *) value) = 0; + else + *((unsigned int *) value) = 1; + break; + case DC_FIELD_TANK: + tank->type = DC_TANKVOLUME_NONE; + tank->volume = 0.0; + tank->workpressure = 0.0; + if (gauge) + tank->gasmix = DC_GASMIX_UNKNOWN; + else + tank->gasmix = 0; + tank->beginpressure = beginpressure; + tank->endpressure = endpressure; + break; case DC_FIELD_TEMPERATURE_SURFACE: *((double *) value) = (signed char) data[8]; break; From 106abe2dba7d5050fa97d16afc14cfec607a95a4 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Sun, 3 May 2015 20:35:48 +0200 Subject: [PATCH 4/4] Remove the temperature and pressure samples. With the new temperature and pressure field, artificially injecting the temperature and pressure info from the header into the samples is no longer necessary. Applications will typically expect a real temperature or pressure profile, and not a few discrete points. The two surface samples (with zero depth) at the begin and end of the dive are kept for now, to support events that occur at the surface. --- src/suunto_eon_parser.c | 23 ----------------------- src/suunto_vyper_parser.c | 24 ------------------------ 2 files changed, 47 deletions(-) diff --git a/src/suunto_eon_parser.c b/src/suunto_eon_parser.c index ad21b94..a803801 100644 --- a/src/suunto_eon_parser.c +++ b/src/suunto_eon_parser.c @@ -282,13 +282,6 @@ suunto_eon_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c sample.time = 0; if (callback) callback (DC_SAMPLE_TIME, sample, userdata); - // Tank Pressure (2 bar) - if (!parser->nitrox) { - sample.pressure.tank = 0; - sample.pressure.value = data[5] * 2; - if (callback) callback (DC_SAMPLE_PRESSURE, sample, userdata); - } - // Depth (0 ft) sample.depth = 0; if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata); @@ -313,15 +306,6 @@ suunto_eon_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c // Delta depth. depth += (signed char) value; - // Temperature at maximum depth (°C) - if (depth == parser->maxdepth) { - if (parser->spyder) - sample.temperature = (signed char) data[parser->marker + 1]; - else - sample.temperature = data[parser->marker + 1] - 40; - if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata); - } - // Depth (ft). sample.depth = depth * FEET; if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata); @@ -364,13 +348,6 @@ suunto_eon_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c if (callback) callback (DC_SAMPLE_TIME, sample, userdata); } - // Tank Pressure (2 bar) - if (!parser->nitrox) { - sample.pressure.tank = 0; - sample.pressure.value = data[offset + 2] * 2; - if (callback) callback (DC_SAMPLE_PRESSURE, sample, userdata); - } - // Depth (0 ft) sample.depth = 0; if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata); diff --git a/src/suunto_vyper_parser.c b/src/suunto_vyper_parser.c index dafcf16..946dcaf 100644 --- a/src/suunto_vyper_parser.c +++ b/src/suunto_vyper_parser.c @@ -322,15 +322,6 @@ suunto_vyper_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t sample.time = 0; if (callback) callback (DC_SAMPLE_TIME, sample, userdata); - // Temperature (°C) - sample.temperature = (signed char) data[8]; - if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata); - - // Tank Pressure (2 bar) - sample.pressure.tank = 0; - sample.pressure.value = data[5] * 2; - if (callback) callback (DC_SAMPLE_PRESSURE, sample, userdata); - // Depth (0 ft) sample.depth = 0; if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata); @@ -355,12 +346,6 @@ suunto_vyper_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t // Delta depth. depth += (signed char) value; - // Temperature at maximum depth (°C) - if (depth == parser->maxdepth) { - sample.temperature = (signed char) data[parser->marker + 1]; - if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata); - } - // Depth (ft). sample.depth = depth * FEET; if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata); @@ -418,15 +403,6 @@ suunto_vyper_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t if (callback) callback (DC_SAMPLE_TIME, sample, userdata); } - // Temperature (°C) - sample.temperature = (signed char) data[offset + 2]; - if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata); - - // Tank Pressure (2 bar) - sample.pressure.tank = 0; - sample.pressure.value = data[offset + 3] * 2; - if (callback) callback (DC_SAMPLE_PRESSURE, sample, userdata); - // Depth (0 ft) sample.depth = 0; if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);