From df339cf08f42a78d1cfbd4427501d2621b071936 Mon Sep 17 00:00:00 2001 From: Michael Keller Date: Sun, 13 Sep 2026 14:12:53 +1200 Subject: [PATCH 1/2] shearwater: separate calibration traversal state Share one sample traversal between the vtable callback and the private calibration pass. Keep calibration results typed and cache the ppo2 source on the parser. Signed-off-by: Michael Keller --- src/shearwater_predator_parser.c | 57 ++++++++++++++++++++------------ 1 file changed, 36 insertions(+), 21 deletions(-) diff --git a/src/shearwater_predator_parser.c b/src/shearwater_predator_parser.c index ba730d4d..b16f0985 100644 --- a/src/shearwater_predator_parser.c +++ b/src/shearwater_predator_parser.c @@ -174,6 +174,7 @@ struct shearwater_predator_parser_t { unsigned int calibrated; double calibration[3]; bool needs_divecan_calibration_estimate; + bool external_ppo2_used; unsigned int divemode; unsigned int serial; unsigned int units; @@ -185,7 +186,6 @@ struct shearwater_predator_parser_t { }; struct dc_parser_sensor_calibration_t { - bool external_ppo2_used; double sum_ppo2; double sum_calculated_ppo2; unsigned int ppo2_sample_count; @@ -197,6 +197,8 @@ static dc_status_t shearwater_predator_parser_samples_foreach (dc_parser_t *abst static dc_status_t shearwater_predator_parser_destroy (dc_parser_t *abstract); static dc_status_t shearwater_predator_parser_cache (shearwater_predator_parser_t *parser); +static dc_status_t shearwater_predator_parser_calibration_prepass (shearwater_predator_parser_t *parser, struct dc_parser_sensor_calibration_t *calibration); +static dc_status_t shearwater_predator_parser_samples_foreach_internal (shearwater_predator_parser_t *parser, dc_sample_callback_t callback, void *userdata, struct dc_parser_sensor_calibration_t *calibration); static const dc_parser_vtable_t shearwater_predator_parser_vtable = { sizeof(shearwater_predator_parser_t), @@ -327,6 +329,7 @@ shearwater_common_parser_create (dc_parser_t **out, dc_context_t *context, const parser->calibration[i] = 0.0; } parser->needs_divecan_calibration_estimate = false; + parser->external_ppo2_used = false; parser->units = METRIC; parser->density = DEF_DENSITY_SALT; parser->atmospheric = DEF_ATMOSPHERIC / (BAR / 1000); @@ -966,7 +969,7 @@ shearwater_predator_parser_cache (shearwater_predator_parser_t *parser) } struct dc_parser_sensor_calibration_t userdata = { 0 }; - dc_status_t rc = shearwater_predator_parser_samples_foreach(abstract, NULL, (void *)&userdata); + dc_status_t rc = shearwater_predator_parser_calibration_prepass(parser, &userdata); bool calibrated = false; if (parser->needs_divecan_calibration_estimate) { @@ -989,7 +992,7 @@ shearwater_predator_parser_cache (shearwater_predator_parser_t *parser) } if (!calibrated) { - add_sensor_state(parser, userdata.external_ppo2_used); + add_sensor_state(parser, parser->external_ppo2_used); } static const char *name = "Divemode"; @@ -1160,18 +1163,12 @@ shearwater_predator_parser_get_field (dc_parser_t *abstract, dc_field_type_t typ } +// AI-generated (Claude) static dc_status_t -shearwater_predator_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata) +shearwater_predator_parser_samples_foreach_internal (shearwater_predator_parser_t *parser, dc_sample_callback_t callback, void *userdata, struct dc_parser_sensor_calibration_t *calibration) { - shearwater_predator_parser_t *parser = (shearwater_predator_parser_t *) abstract; - - const unsigned char *data = abstract->data; - unsigned int size = abstract->size; - - // Cache the parser data. - dc_status_t rc = shearwater_predator_parser_cache (parser); - if (rc != DC_STATUS_SUCCESS) - return rc; + const unsigned char *data = parser->base.data; + unsigned int size = parser->base.size; // Previous gas mix. unsigned int o2_previous = UNDEFINED, he_previous = UNDEFINED, dil_previous = UNDEFINED; @@ -1244,10 +1241,8 @@ shearwater_predator_parser_samples_foreach (dc_parser_t *abstract, dc_sample_cal if ((status & PPO2_EXTERNAL) == 0) { double calculated_ppo2 = data[offset + pnf + 6] / 100.0; - if (!callback && userdata) { - struct dc_parser_sensor_calibration_t *out = (struct dc_parser_sensor_calibration_t *)userdata; - - out->external_ppo2_used = true; + if (calibration) { + parser->external_ppo2_used = true; if (parser->needs_divecan_calibration_estimate) { double ppo2_sum = 0.0; @@ -1269,9 +1264,9 @@ shearwater_predator_parser_samples_foreach (dc_parser_t *abstract, dc_sample_cal double ppo2 = ppo2_sum / ppo2_count; - out->sum_ppo2 += ppo2; - out->sum_calculated_ppo2 += calculated_ppo2; - out->ppo2_sample_count++; + calibration->sum_ppo2 += ppo2; + calibration->sum_calculated_ppo2 += calculated_ppo2; + calibration->ppo2_sample_count++; } } @@ -1327,7 +1322,7 @@ shearwater_predator_parser_samples_foreach (dc_parser_t *abstract, dc_sample_cal (o2 != 0 || he != 0)) { unsigned int idx = shearwater_predator_find_gasmix (parser, o2, he, ccr); if (idx >= parser->ngasmixes) { - ERROR (abstract->context, "Invalid gas mix."); + ERROR (parser->base.context, "Invalid gas mix."); return DC_STATUS_DATAFORMAT; } @@ -1490,3 +1485,23 @@ shearwater_predator_parser_samples_foreach (dc_parser_t *abstract, dc_sample_cal return DC_STATUS_SUCCESS; } + + +static dc_status_t +shearwater_predator_parser_calibration_prepass (shearwater_predator_parser_t *parser, struct dc_parser_sensor_calibration_t *calibration) +{ + return shearwater_predator_parser_samples_foreach_internal(parser, NULL, NULL, calibration); +} + + +static dc_status_t +shearwater_predator_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata) +{ + shearwater_predator_parser_t *parser = (shearwater_predator_parser_t *) abstract; + + dc_status_t rc = shearwater_predator_parser_cache (parser); + if (rc != DC_STATUS_SUCCESS) + return rc; + + return shearwater_predator_parser_samples_foreach_internal(parser, callback, userdata, NULL); +} From ae1faf7c3a8adbb4557493b1f044caf7b8ec3a76 Mon Sep 17 00:00:00 2001 From: Michael Keller Date: Sun, 13 Sep 2026 14:13:29 +1200 Subject: [PATCH 2/2] shearwater: skip non-CCR calibration pass The calibration pass only produces CCR and SCR state, so skip it for open-circuit, gauge, and freedive profiles. Signed-off-by: Michael Keller --- src/shearwater_predator_parser.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/shearwater_predator_parser.c b/src/shearwater_predator_parser.c index b16f0985..c39400aa 100644 --- a/src/shearwater_predator_parser.c +++ b/src/shearwater_predator_parser.c @@ -969,7 +969,9 @@ shearwater_predator_parser_cache (shearwater_predator_parser_t *parser) } struct dc_parser_sensor_calibration_t userdata = { 0 }; - dc_status_t rc = shearwater_predator_parser_calibration_prepass(parser, &userdata); + dc_status_t rc = DC_STATUS_SUCCESS; + if (shearwater_predator_is_ccr(divemode)) + rc = shearwater_predator_parser_calibration_prepass(parser, &userdata); bool calibrated = false; if (parser->needs_divecan_calibration_estimate) {