fix(dive-computer): resolve CCR transmitter cylinders from every transmitter reading - #2319
Conversation
…smitter reading A sample's pressureBar/tankIndex pair holds only the last transmitter it reported, which on a Shearwater CCR is always the oxygen transmitter. Read every transmitter from tankPressuresBar instead, resolve oxygen and diluent cylinders by their usage tag before the breathed-gas rule, and give gases without a transmitter the sensorless roles. Refs submersion-app#2318
Crediting every reporting transmitter with the breathed gas overrode a computer's own tank->gas link. The CCR fix does not need it: oxygen and diluent cylinders resolve by usage. Per-transmitter readings stay for the surfacing trim. Put the breathed diluent first among the unclaimed gases so the dive-level diluent is the one used, not the first programmed one. Refs submersion-app#2318
A bailout cylinder on its own transmitter is claimed before the unclaimed gases are ranked, so the leanest remaining gas was promoted to Bailout. Rank against every gas with no reported usage and assign only the unclaimed ones. Refs submersion-app#2318
|
📦 Build artifacts for this PR · commit
Artifacts expire in 7 days. Downloading requires being signed in to GitHub. macOS needs two extractions: unzip the downloaded artifact, then unzip the Updated automatically on each push. |
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Preserve legacy single-transmitter readings when applying surfacing trim.
Get a fresh assessment by requesting another Copilot review.
Review effort: Lite
Findings: 1
Open (1)
What changed in this PR
Fixes CCR transmitter cylinder resolution, gas assignment, sensorless roles, and surfacing pressure trimming.
Changes:
- Resolves oxygen and diluent gases across transmitter readings.
- Corrects bailout/deco role inference and index allocation.
- Adds comprehensive CCR regression tests.
| File | Summary |
|---|---|
test/features/dive_computer/data/services/parsed_tank_resolver_ccr_transmitters_test.dart |
Adds CCR multi-transmitter regression coverage. |
lib/features/dive_computer/data/services/parsed_tank_resolver.dart |
Updates cylinder, gas, role, pressure, and index resolution. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Match groupPressuresByTank, which stores such a reading on tank 0, so the surfacing trim does not drop it. Also covers the first-diluent fallback. Refs submersion-app#2318
|
@ericgriffin This is complete and ready for testing and review. All CI checks are green, the Copilot finding is fixed with a regression test and resolved, and the branch merges cleanly. The quickest check is "Re-parse all dives" on a Shearwater with CCR dives that use two transmitters (see How to Test in the description). |
|
out of interest, how does the petrel know which transmitter is oxygen? it just gets a pressure, not a gas mix..so i don't think that assumption is safe, but I may be wrong ofc. I happen to dive o2 as my 3rd sensor (first two dil/bailout), but I could easily put the o2 pressure sensor as the first one. |
|
Good question. It doesn't rely on the transmitter's position. On a CCR dive, libdivecomputer's Shearwater parser tags each transmitter from the name the diver gives it on the Petrel: a name starting with "O" becomes oxygen, one starting with "D" becomes diluent ( If the transmitters keep their default names (T1..T4), no usage is reported and this PR changes nothing for them: the gas falls back to the previous rules and the role comes from the transmitter registry. libdivecomputer already reported this correctly. The bug was on the Submersion side:
This PR fixes all three: oxygen and diluent cylinders resolve by their usage before the breathed-gas rule, the surfacing trim reads every transmitter, and gases without a transmitter get the same roles as on a sensorless dive. |
|
ah, cool. i'd forgotten about the prefixes. thanks for explaining |

Related Issue
Closes #2318
Summary
On a Shearwater CCR dive with a diluent and an oxygen transmitter, both transmitters report in the same sample, but
ProfileSample.pressureBar/tankIndexonly hold the last reading, which on the Petrel 3 is always the oxygen transmitter. The resolver relied on that pair, so:All four were confirmed against the raw downloads of eight real dives and Shearwater Cloud (details in #2318).
Changes
All in
parsed_tank_resolver.dart:usageoxygen): the computer's own link, else an oxygen-tagged gas mix, else the 100/0 default. The breathed-gas rule no longer applies to it.usagediluent): the computer's own link, else the most-breathed diluent-tagged gas, else the first diluent-tagged gas. Without any diluent-tagged gas the previous rules still apply (keeps the fix(dive-log): auto-assign 100% O2 when a cylinder's role is set to oxygen supply #1972 test behavior).tankPressuresBar(same fallback rule asgroupPressuresByTank), so each cylinder is trimmed at surfacing, not only the last one reported._firstFreeIndexalso accounts fortankPressuresBar, so synthesized cylinders never collide with a transmitter index.Deliberately unchanged: the breathed-gas rule for untagged tanks still keys on the sample's own
tankIndex. Crediting every reporting transmitter would hand each tank the dive's main gas and override a computer's own tank-to-gas link on open circuit dives. Attributing gas per transmitter properly (e.g. by pressure drop) is left as a possible follow-up.How to Test
Needs a Shearwater CCR dive downloaded with two AI transmitters named
D1/O2(or an HP CCR setup).Test Plan
parsed_tank_resolver_ccr_transmitters_test.dartmodels the real download (gas list OC1 99/0, OC5 15/55, DIL 15/55; both transmitters in every sample, O2 reported last) and failed before the fix with exactly the values seen in the field (O2 15/55, diluent 99/0, diluent end 13.4 bar)flutter test test/features/dive_computerpasses (606 tests)flutter analyzeclean on the changed areas,dart formatcleanNote: three tests under
test/features/dive_log(dive_header_map_bottom_edge_test,deco_filter_providers_test,equipment_attr_filter_providers_test) fail locally on Windows. They do not import anything fromdive_computerand are unrelated to this change.