From f818a5a92a08e147be5252864f6f8a1868e0fbcc Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Mon, 10 Jul 2023 17:52:23 +0200 Subject: [PATCH 1/4] Add a function for detecting CCR dives --- src/shearwater_predator_parser.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/shearwater_predator_parser.c b/src/shearwater_predator_parser.c index b6aa7e2..534d8e0 100644 --- a/src/shearwater_predator_parser.c +++ b/src/shearwater_predator_parser.c @@ -179,6 +179,12 @@ static const dc_parser_vtable_t shearwater_petrel_parser_vtable = { }; +static unsigned int +shearwater_predator_is_ccr (unsigned int divemode) +{ + return divemode == M_CC || divemode == M_CC2 || divemode == M_SC; +} + static unsigned int shearwater_predator_find_gasmix (shearwater_predator_parser_t *parser, unsigned int o2, unsigned int he, unsigned int dil) { @@ -659,8 +665,7 @@ shearwater_predator_parser_cache (shearwater_predator_parser_t *parser) for (unsigned int i = 0; i < ngasmixes; ++i) { if (gasmix[i].oxygen == 0 && gasmix[i].helium == 0) continue; - if (gasmix[i].diluent && - (divemode != M_CC && divemode != M_CC2 && divemode != M_SC)) + if (gasmix[i].diluent && !shearwater_predator_is_ccr (divemode)) continue; parser->gasmix[parser->ngasmixes] = gasmix[i]; parser->ngasmixes++; From f77e9c03fc1e46f4c6e7e4172ae9507faea8fb40 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Mon, 10 Jul 2023 17:53:13 +0200 Subject: [PATCH 2/4] Restrict the oxygen/diluent usage to CCR dives For open-circuit dives, the oxygen and diluent usage doesn't make any sense at all. But when an open-circuit diver uses the letter 'D' to indicate a tank for decompression use, it will get incorrectly labeled as a diluent tank. Fixed by restricting the oxygen/diluent usage to CCR dives only. --- src/shearwater_predator_parser.c | 33 +++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/src/shearwater_predator_parser.c b/src/shearwater_predator_parser.c index 534d8e0..d1a1cd6 100644 --- a/src/shearwater_predator_parser.c +++ b/src/shearwater_predator_parser.c @@ -746,21 +746,24 @@ shearwater_predator_parser_get_field (dc_parser_t *abstract, dc_field_type_t typ tank->beginpressure = parser->tank[flags].beginpressure * 2 * PSI / BAR; tank->endpressure = parser->tank[flags].endpressure * 2 * PSI / BAR; tank->gasmix = DC_GASMIX_UNKNOWN; - switch (parser->tank[flags].name[0]) { - case 'S': - tank->usage = DC_USAGE_SIDEMOUNT; - break; - case 'O': - tank->usage = DC_USAGE_OXYGEN; - break; - case 'D': - tank->usage = DC_USAGE_DILUENT; - break; - case 'T': - case 'B': - default: - tank->usage = DC_USAGE_NONE; - break; + if (shearwater_predator_is_ccr (parser->divemode)) { + switch (parser->tank[flags].name[0]) { + case 'O': + tank->usage = DC_USAGE_OXYGEN; + break; + case 'D': + tank->usage = DC_USAGE_DILUENT; + break; + default: + tank->usage = DC_USAGE_NONE; + break; + } + } else { + if (parser->tank[flags].name[0] == 'S') { + tank->usage = DC_USAGE_SIDEMOUNT; + } else { + tank->usage = DC_USAGE_NONE; + } } break; case DC_FIELD_SALINITY: From a4cd21b811bf2cf025bdfc79bd877bedbae1578d Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Thu, 6 Jul 2023 22:27:05 +0200 Subject: [PATCH 3/4] Use the GTR mode to detect sidemount tanks Firmware v84 introduced support for sidemount diving. Users can now configure the two sidemount tanks as the source for the GTR (Gas Time Remaining) estimations. We can take advantage of this feature to detect the sidemount tanks. This is more reliable than using the tank name. --- src/array.c | 11 +++++++++++ src/array.h | 3 +++ src/shearwater_predator_parser.c | 16 +++++++++++----- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/array.c b/src/array.c index 29f5faf..f47c3eb 100644 --- a/src/array.c +++ b/src/array.c @@ -404,3 +404,14 @@ signextend (unsigned int value, unsigned int nbits) else return value & mask; } + +unsigned int +popcount (unsigned int value) +{ + unsigned int count = 0; + while (value) { + value &= value - 1; + count++; + } + return count; +} diff --git a/src/array.h b/src/array.h index a6ef21e..fab1475 100644 --- a/src/array.h +++ b/src/array.h @@ -126,6 +126,9 @@ dec2bcd (unsigned char value); unsigned int signextend (unsigned int value, unsigned int nbits); +unsigned int +popcount (unsigned int value); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/src/shearwater_predator_parser.c b/src/shearwater_predator_parser.c index d1a1cd6..2bf4e3a 100644 --- a/src/shearwater_predator_parser.c +++ b/src/shearwater_predator_parser.c @@ -118,6 +118,7 @@ typedef struct shearwater_predator_tank_t { unsigned int pressure_reserve; unsigned int serial; char name[2]; + dc_usage_t usage; } shearwater_predator_tank_t; struct shearwater_predator_parser_t { @@ -254,6 +255,7 @@ shearwater_common_parser_create (dc_parser_t **out, dc_context_t *context, const parser->tank[i].pressure_reserve = 0; parser->tank[i].serial = 0; memset (parser->tank[i].name, 0, sizeof (parser->tank[i].name)); + parser->tank[i].usage = DC_USAGE_NONE; parser->tankidx[i] = i; } parser->aimode = AI_OFF; @@ -547,6 +549,14 @@ shearwater_predator_parser_cache (shearwater_predator_parser_t *parser) } } } + unsigned int gtrmode = data[offset + 29]; + if (popcount(gtrmode) >= 2) { + for (unsigned int i = 0; i < 4; ++i) { + if (gtrmode & (1 << i)) { + tank[i].usage = DC_USAGE_SIDEMOUNT; + } + } + } } else if (type == LOG_RECORD_OPENING_5) { if (logversion >= 9) { tank[0].serial = array_convert_bcd2dec (data + offset + 1, 3); @@ -759,11 +769,7 @@ shearwater_predator_parser_get_field (dc_parser_t *abstract, dc_field_type_t typ break; } } else { - if (parser->tank[flags].name[0] == 'S') { - tank->usage = DC_USAGE_SIDEMOUNT; - } else { - tank->usage = DC_USAGE_NONE; - } + tank->usage = parser->tank[flags].usage; } break; case DC_FIELD_SALINITY: From 9bc742d3acdb456f6d3aad9669cdf8896e8e9793 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Sun, 16 Jul 2023 23:59:15 +0200 Subject: [PATCH 4/4] Use the HP CCR data for the oxygen/diluent usage For dives in HP CCR mode, the oxygen and diluent tanks are stored at a fixed index. This information is more reliable than using the tank name, and also prevents the incorrect labeling of one of the other tanks as an oxygen or diluent tank. --- src/shearwater_predator_parser.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/shearwater_predator_parser.c b/src/shearwater_predator_parser.c index 2bf4e3a..fc06b66 100644 --- a/src/shearwater_predator_parser.c +++ b/src/shearwater_predator_parser.c @@ -141,6 +141,7 @@ struct shearwater_predator_parser_t { shearwater_predator_tank_t tank[NTANKS]; unsigned int tankidx[NTANKS]; unsigned int aimode; + unsigned int hpccr; unsigned int calibrated; double calibration[3]; unsigned int divemode; @@ -259,6 +260,7 @@ shearwater_common_parser_create (dc_parser_t **out, dc_context_t *context, const parser->tankidx[i] = i; } parser->aimode = AI_OFF; + parser->hpccr = 0; parser->calibrated = 0; for (unsigned int i = 0; i < 3; ++i) { parser->calibration[i] = 0.0; @@ -387,6 +389,7 @@ shearwater_predator_parser_cache (shearwater_predator_parser_t *parser) shearwater_predator_tank_t tank[NTANKS] = {0}; unsigned int o2_previous = UNDEFINED, he_previous = UNDEFINED, dil_previous = UNDEFINED; unsigned int aimode = AI_OFF; + unsigned int hpccr = 0; if (!pnf) { for (unsigned int i = 0; i < NFIXED; ++i) { gasmix[i].oxygen = data[20 + i]; @@ -498,8 +501,8 @@ shearwater_predator_parser_cache (shearwater_predator_parser_t *parser) tank[id].enabled = 1; tank[id].beginpressure = pressure; tank[id].endpressure = pressure; - tank[id].name[0] = i == 0 ? 'D': 'O'; - tank[id].name[1] = 0; + tank[id].usage = i == 0 ? DC_USAGE_DILUENT : DC_USAGE_OXYGEN; + hpccr = 1; } tank[id].endpressure = pressure; } @@ -543,9 +546,9 @@ shearwater_predator_parser_cache (shearwater_predator_parser_t *parser) if (aimode == AI_HPCCR) { for (unsigned int i = 0; i < 2; ++i) { tank[4 + i].enabled = 1; - tank[4 + i].name[0] = i == 0 ? 'D': 'O'; - tank[4 + i].name[1] = 0; + tank[4 + i].usage = i == 0 ? DC_USAGE_DILUENT : DC_USAGE_OXYGEN; } + hpccr = 1; } } } @@ -692,6 +695,7 @@ shearwater_predator_parser_cache (shearwater_predator_parser_t *parser) } } parser->aimode = aimode; + parser->hpccr = hpccr; parser->divemode = divemode; parser->units = data[parser->opening[0] + 8]; parser->atmospheric = array_uint16_be (data + parser->opening[1] + (parser->pnf ? 16 : 47)); @@ -756,7 +760,7 @@ shearwater_predator_parser_get_field (dc_parser_t *abstract, dc_field_type_t typ tank->beginpressure = parser->tank[flags].beginpressure * 2 * PSI / BAR; tank->endpressure = parser->tank[flags].endpressure * 2 * PSI / BAR; tank->gasmix = DC_GASMIX_UNKNOWN; - if (shearwater_predator_is_ccr (parser->divemode)) { + if (shearwater_predator_is_ccr (parser->divemode) && !parser->hpccr) { switch (parser->tank[flags].name[0]) { case 'O': tank->usage = DC_USAGE_OXYGEN;