Skip to content

Suunto Nautic: device info + decode fixes (devinfo, dive mode, RBT, HR, surface temp) - #4

Merged
latishab merged 5 commits into
mainfrom
fix/nautic-tank-begin-dropout
Sep 8, 2026
Merged

Suunto Nautic: device info + decode fixes (devinfo, dive mode, RBT, HR, surface temp)#4
latishab merged 5 commits into
mainfrom
fix/nautic-tank-begin-dropout

Conversation

@latishab

@latishab latishab commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Brings the shipping branch up to date on main:

  • emit DC_EVENT_DEVINFO (firmware + serial) for the Nautic (libdc-swift #40)
  • report the dive mode (fixes every scuba dive importing as FREEDIVE)
  • gas time remaining -> DC_SAMPLE_RBT
  • heart rate (Ocean) -> DC_SAMPLE_HEARTBEAT
  • surface temperature + gas-mix sample on a switch

All verified against the real-capture corpus (libdc-swift #29).

urbamax and others added 5 commits September 8, 2026 17:29
A short fetch of GET /Info returns a device-identity record — confirmed on
a live Nautic (firmware 2.55.46): Suunto\0 Nautic\0 Vaasa\0 T\0
2604C3003306\0 ... 2.55.46 ... in one 303-byte DATA frame. Take the first
"N.N.N" token as the firmware and the first 12-char uppercase-hex token
(which precedes the firmware) as the serial, and announce them via
DC_EVENT_DEVINFO. Best-effort — every failure path is non-fatal.

dc_event_devinfo_t is unsigned-int only, so the firmware is packed
(a<<16)|(b<<8)|c and the hex serial truncated to its low 32 bits.
The parser never answered DC_FIELD_DIVEMODE, so the consumer was left
with the dc_divemode_t zero value -- FREEDIVE -- and every scuba dive
imported as an apnea dive (seen on nandodiver's captures,
deepsealabs/libdc-swift#29).

Read the CHUNK_ACTIVITY (0x08) sport id -- the app's ActivityType, e.g.
51 scuba, 61 free diving, 62 mermaiding -- and map 61/62 to
DC_DIVEMODE_FREEDIVE, everything else (and a stream with no activity
chunk, since the Nautic/Ocean are recreational OC computers) to
DC_DIVEMODE_OC.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
(cherry picked from commit 3319bab08bcc4042aaf7cd0e2d8b8a3bd45f8e86)
Each 18-byte cylinder record in the 0x16 extended-status chunk carries a
uint32 LE (seconds) at +10 -- the gas time remaining, the app's
Cylinders[].GasTime. 0xFFFFFFFF means not computed (no AI, or not enough
data yet). Emit it for the primary cylinder as RBT minutes, the same way
suunto_eonsteel does.

Byte-exact against the app export's per-sample GasTime on real pod dives
(deepsealabs/libdc-swift#29), and absent exactly on the no-transmitter
dives.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Chunk 0x0F is [timeDelta:2][hr:uint8 bpm] -- the Suunto Ocean's optical
wrist heart rate, one sample per second. The Nautic and Nautic S have no
HR sensor, so the chunk never appears on those and nothing changes for
them.

Verified byte-exact against the app export's per-sample HR on a real
Ocean dive (deepsealabs/libdc-swift#29): 2413 samples, first 30 values
identical (89, 89, 89, 90, 89, 91, ...), full range 66-113 bpm.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- DC_FIELD_TEMPERATURE_SURFACE: the first temperature reading, taken at
  the surface at dive start. Verified against the app export's first
  sample on real dives (24.3 / 20.9 / 29.7 C).

- DC_SAMPLE_GASMIX: emit the active gas-mix index on a CHUNK_GAS_SWITCH,
  the modern channel, alongside the existing SAMPLE_EVENT_GASCHANGE that
  older consumers read.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@latishab
latishab merged commit 6e7c39d into main Sep 8, 2026
6 of 18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants