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.
This commit is contained in:
Jef Driesen 2023-02-02 20:12:35 +01:00
parent ee78d6f65b
commit 255a2dbb9a
2 changed files with 61 additions and 16 deletions

View File

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

View File

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