Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Protocol parity with the JRing app fixes - #77

Merged
saksham2001 merged 7 commits into
mainfrom
jring-protocol-parity
Jul 10, 2026
Merged

saksham2001 merged 7 commits into
mainfrom
jring-protocol-parity

Conversation

@saksham2001

@saksham2001 saksham2001 commented Jul 10, 2026

Copy link
Copy Markdown
Owner

Summary

PulseLoop's 56ff driver was reverse-engineered from partial knowledge. Decompiling the vendor JRing Android app (SDK com.sxr.sdk.ble.keepfit, app com.jaga.ibraceletplus.jyring) let us diff our driver against ground truth. Three long-standing user reports all trace to verified divergences, and the diff surfaced two outright bugs.

What changed

  • JringClock (new): latches the UTC offset when we send 0x01, subtracts it at exactly the four ring-stamped decode sites (0x01 ack, 0x03 activity, 0x11 sleep, 0x16/0xA0 history HR). Deliberately not applied to 0x24/0x14/0x27/0x28/0x3f, which are stamped on arrival: a blanket post-decode shift would corrupt live samples.
  • makeTimeSyncCommand now sends local wall-clock seconds. Byte [5] keeps the DST-aware hour (vendor sends the raw one); half-hour zones truncate there exactly as the vendor's do, harmlessly, since bytes [1..4] carry the full offset.
  • resyncTime() on RingSyncEngine (default no-op) + a coordinator observer for NSSystemTimeZoneDidChange / significantTimeChange. The vendor has no such listener; this is strictly better.
  • runStartup() now emits 0x19 (background monitoring) and 0x20 (capability bitmask): 48 → 02 → [33] → 0c → 01 → 21 → 19 → 20 → 10 → 16.
  • Measurement frequency for 56ff: .measurementInterval on JringCoordinator — the only UI change needed, since SettingsView/MeasurementSettingsView already gate on it — plus set/applyMeasurementSettings on JringSyncEngine mapping hrIntervalMinutes → 0x19[6]. stopHeartRate() now restores the user's cadence instead of a hardcoded 30.
  • History dedup: persistMeasurement upserts source == .history on (kind, timestamp), two-tier (in-process guard + one indexed fetch for cross-launch). Live samples keep append semantics.

Related issues

This should fix #8 and #14

Type of change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✨ New feature (non-breaking change that adds functionality)
  • 📟 New / improved wearable support (BLE driver layer)
  • 🤖 Coach / LLM change (tools, prompts, orchestration)
  • 🎨 UI / DesignSystem change
  • 🧹 Refactor / chore (no behavior change)
  • 📝 Docs only
  • ⚠️ Breaking change (existing data, settings, or APIs change)

How was this tested?

Need testing with 56ff ring.

  • Added / updated unit tests (PulseLoopTests)
  • Ran the test suite locally (⌘U in Xcode)
  • Tested on a physical device with a real ring 56ff.
  • Tested with demo data (-seedDemo YES, no hardware)
  • N/A (docs / non-code change)

Privacy & data

  • This change does not send health data off-device without explicit user action.
  • No secrets, API keys, or personal data are committed.
  • N/A

Checklist

  • My code follows the project's style (SwiftLint passes).
  • I ran the tests and they pass.
  • I updated docs / README where relevant.
  • I read the Contributing guide.

@saksham2001 saksham2001 linked an issue Jul 10, 2026 that may be closed by this pull request
2 tasks
Adds 0x23 mode 1 (BP) as an explicit spot measurement, a .manualBloodPressure capability, a Measure BP action, and a calibration flow that takes a fresh ring reading before deriving the display offset. SpO2's move to 0x23 mode 2 had otherwise left nothing sending the BP mode.
@saksham2001
saksham2001 merged commit 4241d54 into main Jul 10, 2026
2 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.

[Bug]: Steps not syncing App/Ring Usage

1 participant