From 255a2dbb9aa804d84c36a855fa92d93d72c04578 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Thu, 2 Feb 2023 20:12:35 +0100 Subject: [PATCH] Keep open-circuit and diluent gas mixes separately The OSTC stores either the OC gas mixes or the CCR diluents depending on the dive mode. For CCR dives, there is also bailout to an OC gas possible, and those gas mixes are added dynamically to the manual gas mixes. The Shearwater dive computers store both the configured OC gas mixes and CCR diluents in the header. In both cases, the gas change events should reference the correct type of gas mix. This patch takes care of that. --- src/hw_ostc_parser.c | 47 ++++++++++++++++++++++++++++---- src/shearwater_predator_parser.c | 30 +++++++++++++------- 2 files changed, 61 insertions(+), 16 deletions(-) diff --git a/src/hw_ostc_parser.c b/src/hw_ostc_parser.c index 0210937..aff1b8c 100644 --- a/src/hw_ostc_parser.c +++ b/src/hw_ostc_parser.c @@ -112,6 +112,7 @@ typedef struct hw_ostc_gasmix_t { unsigned int helium; unsigned int type; unsigned int enabled; + unsigned int diluent; } hw_ostc_gasmix_t; typedef struct hw_ostc_parser_t { @@ -195,7 +196,7 @@ static const hw_ostc_layout_t hw_ostc_layout_ostc3 = { }; static unsigned int -hw_ostc_find_gasmix (hw_ostc_parser_t *parser, unsigned int o2, unsigned int he, unsigned int type) +hw_ostc_find_gasmix (hw_ostc_parser_t *parser, unsigned int o2, unsigned int he, unsigned int dil, unsigned int type) { unsigned int offset = 0; unsigned int count = parser->ngasmixes; @@ -207,7 +208,7 @@ hw_ostc_find_gasmix (hw_ostc_parser_t *parser, unsigned int o2, unsigned int he, unsigned int i = offset; while (i < count) { - if (o2 == parser->gasmix[i].oxygen && he == parser->gasmix[i].helium) + if (o2 == parser->gasmix[i].oxygen && he == parser->gasmix[i].helium && dil == parser->gasmix[i].diluent) break; i++; } @@ -215,6 +216,18 @@ hw_ostc_find_gasmix (hw_ostc_parser_t *parser, unsigned int o2, unsigned int he, return i; } +static unsigned int +hw_ostc_is_ccr (unsigned int divemode, unsigned int version) +{ + if (version == 0x21) { + return divemode == OSTC_ZHL16_CC || divemode == OSTC_ZHL16_CC_GF || divemode == OSTC_PSCR_GF; + } else if (version == 0x23 || version == 0x24) { + return divemode == OSTC3_CC || divemode == OSTC3_PSCR; + } else { + return 0; + } +} + static dc_status_t hw_ostc_parser_cache (hw_ostc_parser_t *parser) { @@ -263,6 +276,13 @@ hw_ostc_parser_cache (hw_ostc_parser_t *parser) return DC_STATUS_DATAFORMAT; } + // Get the dive mode. + unsigned int divemode = layout->divemode < header ? + data[layout->divemode] : UNDEFINED; + + // Get the CCR mode. + unsigned int ccr = hw_ostc_is_ccr (divemode, version); + // Get all the gas mixes, the index of the inital mix, // the initial setpoint (used in the fixed setpoint CCR mode), // and the initial CNS from the header @@ -281,6 +301,7 @@ hw_ostc_parser_cache (hw_ostc_parser_t *parser) gasmix[i].helium = 0; gasmix[i].type = 0; gasmix[i].enabled = 1; + gasmix[i].diluent = 0; } } else if (version == 0x23 || version == 0x24) { ngasmixes = 5; @@ -289,13 +310,14 @@ hw_ostc_parser_cache (hw_ostc_parser_t *parser) gasmix[i].helium = data[28 + 4 * i + 1]; gasmix[i].type = data[28 + 4 * i + 3]; gasmix[i].enabled = gasmix[i].type != 0; + gasmix[i].diluent = ccr; // Find the first gas marked as the initial gas. if (initial == UNDEFINED && data[28 + 4 * i + 3] == 1) { initial = i + 1; /* One based index! */ } } // The first fixed setpoint is the initial setpoint in CCR mode. - if (data[layout->divemode] == OSTC3_CC || data[layout->divemode] == OSTC3_PSCR) { + if (ccr) { initial_setpoint = data[60]; } // Initial CNS @@ -314,6 +336,7 @@ hw_ostc_parser_cache (hw_ostc_parser_t *parser) } else { gasmix[i].enabled = 1; } + gasmix[i].diluent = ccr; } } if (initial != UNDEFINED) { @@ -375,6 +398,7 @@ hw_ostc_parser_create_internal (dc_parser_t **out, dc_context_t *context, unsign parser->gasmix[i].helium = 0; parser->gasmix[i].type = 0; parser->gasmix[i].enabled = 0; + parser->gasmix[i].diluent = 0; } *out = (dc_parser_t *) parser; @@ -415,6 +439,7 @@ hw_ostc_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsig parser->gasmix[i].helium = 0; parser->gasmix[i].type = 0; parser->gasmix[i].enabled = 0; + parser->gasmix[i].diluent = 0; } return DC_STATUS_SUCCESS; @@ -787,6 +812,13 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call firmware = array_uint16_be (data + layout->firmware); } + // Get the dive mode. + unsigned int divemode = layout->divemode < header ? + data[layout->divemode] : UNDEFINED; + + // Get the CCR mode. + unsigned int ccr = hw_ostc_is_ccr (divemode, version); + unsigned int time = 0; unsigned int nsamples = 0; unsigned int tank = parser->initial != UNDEFINED ? parser->initial : 0; @@ -894,7 +926,7 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call } unsigned int o2 = data[offset]; unsigned int he = data[offset + 1]; - unsigned int idx = hw_ostc_find_gasmix (parser, o2, he, MANUAL); + unsigned int idx = hw_ostc_find_gasmix (parser, o2, he, ccr, MANUAL); if (idx >= parser->ngasmixes) { if (idx >= NGASMIXES) { ERROR (abstract->context, "Maximum number of gas mixes reached."); @@ -904,6 +936,7 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call parser->gasmix[idx].helium = he; parser->gasmix[idx].type = 0; parser->gasmix[idx].enabled = 1; + parser->gasmix[idx].diluent = ccr; parser->ngasmixes = idx + 1; } @@ -954,7 +987,7 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call unsigned int o2 = data[offset]; unsigned int he = data[offset + 1]; - unsigned int idx = hw_ostc_find_gasmix (parser, o2, he, MANUAL); + unsigned int idx = hw_ostc_find_gasmix (parser, o2, he, 0, MANUAL); if (idx >= parser->ngasmixes) { if (idx >= NGASMIXES) { ERROR (abstract->context, "Maximum number of gas mixes reached."); @@ -964,6 +997,7 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call parser->gasmix[idx].helium = he; parser->gasmix[idx].type = 0; parser->gasmix[idx].enabled = 1; + parser->gasmix[idx].diluent = 0; parser->ngasmixes = idx + 1; } @@ -1086,7 +1120,7 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call unsigned int o2 = data[offset]; unsigned int he = data[offset + 1]; - unsigned int idx = hw_ostc_find_gasmix (parser, o2, he, MANUAL); + unsigned int idx = hw_ostc_find_gasmix (parser, o2, he, 0, MANUAL); if (idx >= parser->ngasmixes) { if (idx >= NGASMIXES) { ERROR (abstract->context, "Maximum number of gas mixes reached."); @@ -1096,6 +1130,7 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call parser->gasmix[idx].helium = he; parser->gasmix[idx].type = 0; parser->gasmix[idx].enabled = 1; + parser->gasmix[idx].diluent = 0; parser->ngasmixes = idx + 1; } diff --git a/src/shearwater_predator_parser.c b/src/shearwater_predator_parser.c index 9432603..06a0882 100644 --- a/src/shearwater_predator_parser.c +++ b/src/shearwater_predator_parser.c @@ -106,6 +106,7 @@ typedef struct shearwater_predator_parser_t shearwater_predator_parser_t; typedef struct shearwater_predator_gasmix_t { unsigned int oxygen; unsigned int helium; + unsigned int diluent; } shearwater_predator_gasmix_t; typedef struct shearwater_predator_tank_t { @@ -182,11 +183,11 @@ static const dc_parser_vtable_t shearwater_petrel_parser_vtable = { static unsigned int -shearwater_predator_find_gasmix (shearwater_predator_parser_t *parser, unsigned int o2, unsigned int he) +shearwater_predator_find_gasmix (shearwater_predator_parser_t *parser, unsigned int o2, unsigned int he, unsigned int dil) { unsigned int i = 0; while (i < parser->ngasmixes) { - if (o2 == parser->gasmix[i].oxygen && he == parser->gasmix[i].helium) + if (o2 == parser->gasmix[i].oxygen && he == parser->gasmix[i].helium && dil == parser->gasmix[i].diluent) break; i++; } @@ -238,6 +239,7 @@ shearwater_common_parser_create (dc_parser_t **out, dc_context_t *context, unsig for (unsigned int i = 0; i < NGASMIXES; ++i) { parser->gasmix[i].oxygen = 0; parser->gasmix[i].helium = 0; + parser->gasmix[i].diluent = 0; } parser->ntanks = 0; for (unsigned int i = 0; i < NTANKS; ++i) { @@ -301,6 +303,7 @@ shearwater_predator_parser_set_data (dc_parser_t *abstract, const unsigned char for (unsigned int i = 0; i < NGASMIXES; ++i) { parser->gasmix[i].oxygen = 0; parser->gasmix[i].helium = 0; + parser->gasmix[i].diluent = 0; } parser->ntanks = 0; for (unsigned int i = 0; i < NTANKS; ++i) { @@ -425,12 +428,13 @@ shearwater_predator_parser_cache (shearwater_predator_parser_t *parser) unsigned int ngasmixes = NFIXED; shearwater_predator_gasmix_t gasmix[NGASMIXES] = {0}; shearwater_predator_tank_t tank[NTANKS] = {0}; - unsigned int o2_previous = UNDEFINED, he_previous = UNDEFINED; + unsigned int o2_previous = UNDEFINED, he_previous = UNDEFINED, dil_previous = UNDEFINED; unsigned int aimode = AI_OFF; if (!pnf) { for (unsigned int i = 0; i < NFIXED; ++i) { gasmix[i].oxygen = data[20 + i]; gasmix[i].helium = data[30 + i]; + gasmix[i].diluent = i >= 5; } } @@ -449,19 +453,20 @@ shearwater_predator_parser_cache (shearwater_predator_parser_t *parser) if (type == LOG_RECORD_DIVE_SAMPLE) { // Status flags. unsigned int status = data[offset + 11 + pnf]; - if ((status & OC) == 0) { + unsigned int ccr = (status & OC) == 0; + if (ccr) { divemode = status & SC ? M_SC : M_CC; } // Gaschange. unsigned int o2 = data[offset + 7 + pnf]; unsigned int he = data[offset + 8 + pnf]; - if ((o2 != o2_previous || he != he_previous) && + if ((o2 != o2_previous || he != he_previous || ccr != dil_previous) && (o2 != 0 || he != 0)) { // Find the gasmix in the list. unsigned int idx = 0; while (idx < ngasmixes) { - if (o2 == gasmix[idx].oxygen && he == gasmix[idx].helium) + if (o2 == gasmix[idx].oxygen && he == gasmix[idx].helium && ccr == gasmix[idx].diluent) break; idx++; } @@ -474,11 +479,13 @@ shearwater_predator_parser_cache (shearwater_predator_parser_t *parser) } gasmix[idx].oxygen = o2; gasmix[idx].helium = he; + gasmix[idx].diluent = ccr; ngasmixes = idx + 1; } o2_previous = o2; he_previous = he; + dil_previous = ccr; } // Tank pressure @@ -551,6 +558,7 @@ shearwater_predator_parser_cache (shearwater_predator_parser_t *parser) if (type == LOG_RECORD_OPENING_0) { for (unsigned int i = 0; i < NFIXED; ++i) { gasmix[i].oxygen = data[offset + 20 + i]; + gasmix[i].diluent = i >= 5; } for (unsigned int i = 0; i < 2; ++i) { gasmix[i].helium = data[offset + 30 + i]; @@ -859,7 +867,7 @@ shearwater_predator_parser_samples_foreach (dc_parser_t *abstract, dc_sample_cal return rc; // Previous gas mix. - unsigned int o2_previous = UNDEFINED, he_previous = UNDEFINED; + unsigned int o2_previous = UNDEFINED, he_previous = UNDEFINED, dil_previous = UNDEFINED; // Sample interval. unsigned int time = 0; @@ -919,8 +927,9 @@ shearwater_predator_parser_samples_foreach (dc_parser_t *abstract, dc_sample_cal // Status flags. unsigned int status = data[offset + pnf + 11]; + unsigned int ccr = (status & OC) == 0; - if ((status & OC) == 0) { + if (ccr) { // PPO2 if ((status & PPO2_EXTERNAL) == 0) { #ifdef SENSOR_AVERAGE @@ -961,9 +970,9 @@ shearwater_predator_parser_samples_foreach (dc_parser_t *abstract, dc_sample_cal // Gaschange. unsigned int o2 = data[offset + pnf + 7]; unsigned int he = data[offset + pnf + 8]; - if ((o2 != o2_previous || he != he_previous) && + if ((o2 != o2_previous || he != he_previous || ccr != dil_previous) && (o2 != 0 || he != 0)) { - unsigned int idx = shearwater_predator_find_gasmix (parser, o2, he); + unsigned int idx = shearwater_predator_find_gasmix (parser, o2, he, ccr); if (idx >= parser->ngasmixes) { ERROR (abstract->context, "Invalid gas mix."); return DC_STATUS_DATAFORMAT; @@ -973,6 +982,7 @@ shearwater_predator_parser_samples_foreach (dc_parser_t *abstract, dc_sample_cal if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata); o2_previous = o2; he_previous = he; + dil_previous = ccr; } // Deco stop / NDL.