Skip to content

Decode GET_DATA_RANGE pagesBehind for sync diagnostics (#689) - #694

Merged
ryanbr merged 1 commit into
mainfrom
feat/datarange-pagesbehind-689
Jul 21, 2026
Merged

Decode GET_DATA_RANGE pagesBehind for sync diagnostics (#689)#694
ryanbr merged 1 commit into
mainfrom
feat/datarange-pagesbehind-689

Conversation

@ryanbr

@ryanbr ryanbr commented Jul 21, 2026

Copy link
Copy Markdown
Owner

Fixes #689. Adds tigercraft4's ring-buffer page-backlog diagnostic, extending the existing DataRange helpers.

What it does

DataRange.pagesBehind (Swift + Kotlin byte-parity twins) decodes the backlog the WHOOP app computes from three u32s in the GET_DATA_RANGE command-response inner payload: write page W=V(2), read pointer U=V(3), ring capacity T=V(5) (V(i) = u32 @ inner i·4+1 = frame cmdOff+10/14/22), backlog W<U ? W+(T−U) : W−U. Logged as Strap backlog pages behind: N at the existing GET_DATA_RANGE response site (both platforms) — no new BLE command; the reply is already received + dumped (#451).

Scope / safety

Diagnostic only. The layout is RE'd from the app and not yet confirmed against real 4.0/5-MG captures, so it never gates sync or backfill — existing oldest/newest timestamp behavior and backfill policy are untouched. Guarded on frame length + a capacity sanity ceiling; returns null on a short/garbage frame so it can't log a nonsense number.

One unconfirmed assumption, flagged: u32 read little-endian (matching the frame's own unix words; the app's ByteBuffer default is big-endian). A fixture will settle it — a flip is one line. This is exactly why it stays log-only.

Provenance

Facts (offsets, formula) RE'd from the WHOOP app and reimplemented in NOOP's own code — facts, not copied expression (ATTRIBUTION.md). Documented in docs/PROTOCOL.md.

Verification

  • swift test (WhoopProtocol, 307 pass incl. 5 new pagesBehind) + Kotlin DataRangeScanTest green — cases: normal (W>U), wraparound (W<U), 5/MG cmdOff=10, too-short→nil, implausible→nil (capacity 0 / timestamp / U≥T).
  • compileFullDebugKotlin ✓. iOS log-site (BLEManager, app-target) via app-build — dispatched.

Reported-by: tigercraft4

Log-site scope (honest note)

The pagesBehind decode is full byte-parity on both platforms. The log emission rides the existing GET_DATA_RANGE response handler, whose family scope already differs: Android detects the reply via a computed cmdOff (6 on 4.0, 10 on 5/MG) so it logs on both families; Swift keys on frame[6] (the 4.0 offset) so its whole GET_DATA_RANGE block — newest/oldest/span/clock-drift and now pagesBehind — runs on 4.0 only. So on a 5/MG strap Android logs pagesBehind and iOS/macOS does not. This is a pre-existing Swift limitation this PR inherits, not one it introduces; closing it (a Swift 5/MG GET_DATA_RANGE handler) also moves the newest-record sync path and needs 5/MG hardware to validate, so it is tracked separately (#695).

Adds DataRange.pagesBehind (Swift + Kotlin byte-parity twins) — the ring-buffer
page backlog the WHOOP app computes from three u32s in the GET_DATA_RANGE
command-response inner payload: write page W=V(2), read pointer U=V(3), ring
capacity T=V(5) at frame offsets cmdOff+10/14/22, backlog W<U ? W+(T-U) : W-U.
Read u32 LE (matching the frame's other words); guarded on length + a capacity
sanity ceiling so a short/garbage frame returns null. Logged as 'Strap backlog
pages behind: N' at the existing GET_DATA_RANGE response site — DIAGNOSTIC ONLY:
the layout is RE'd from the app and NOT yet confirmed against real 4.0/5-MG
captures, so it never gates sync or backfill (existing oldest/newest + backfill
policy untouched). No new BLE command.

Unit tests both platforms: normal, wraparound, too-short, implausible. Facts
RE'd, reimplemented in NOOP's own code (ATTRIBUTION.md); documented in PROTOCOL.md.

Reported-by: tigercraft4 (#689). Verified: swift test (WhoopProtocol 307) +
compileFullDebugKotlin + DataRangeScanTest. iOS log-site via app-build.

Author: ryanbr <mp3geek@gmail.com>
@ryanbr
ryanbr merged commit ab6c1bb into main Jul 21, 2026
12 checks passed
@ryanbr
ryanbr deleted the feat/datarange-pagesbehind-689 branch July 21, 2026 06:33
DX23876 pushed a commit to DX23876/noop that referenced this pull request Jul 22, 2026
…yanbr#694)

DataRange.pagesBehind (Swift+Kotlin byte-parity twins) decodes the ring-buffer page backlog from three u32s in the GET_DATA_RANGE response (W=V(2)/U=V(3)/T=V(5) at cmdOff+10/14/22; W<U?W+(T-U):W-U), logged as 'Strap backlog pages behind: N' at the existing response site. Diagnostic ONLY — RE'd/unconfirmed layout (LE + offset assumptions flagged), guarded on length + a capacity ceiling, never gates sync/backfill; no new BLE command. Unit-tested both platforms (normal/wraparound/too-short/implausible). Log emission follows each platform's existing GET_DATA_RANGE handler scope (Swift 4.0-only, Android both) — 5/MG-on-Swift gap tracked as ryanbr#695. Facts reimplemented in NOOP's own code (ATTRIBUTION.md). Reported-by: tigercraft4.
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.

Decode GET_DATA_RANGE pagesBehind for sync diagnostics

1 participant