diff --git a/lib/openstrap_protocol.dart b/lib/openstrap_protocol.dart index b8edb0a..d620dae 100644 --- a/lib/openstrap_protocol.dart +++ b/lib/openstrap_protocol.dart @@ -138,7 +138,6 @@ export 'src/commands.dart' cmdDisableAlarm, kDefaultAlarmHaptics, gen5ClientHello, - cmdGetDataRangeGen5, cmdSendHistoricalGen5, cmdSetClockGen5, cmdGetClockGen5, diff --git a/lib/src/commands.dart b/lib/src/commands.dart index 256ceb5..2075e1d 100644 --- a/lib/src/commands.dart +++ b/lib/src/commands.dart @@ -153,8 +153,12 @@ Uint8List cmdSetClock(int seq, return buildCommand(seq, Cmd.setClock, payload, profile); } -Uint8List cmdGetDataRange(int seq) => - buildCommand(seq, Cmd.getDataRange, const [0x00]); +/// GET_DATA_RANGE (0x22) — shared opcode, envelope + payload differ by +/// profile: gen4 takes a `[0x00]` body, gen5 expects an EMPTY payload (see +/// control.dart's dual-profile decoder for this opcode). +Uint8List cmdGetDataRange(int seq, {BandProfile profile = BandProfile.gen4}) => + buildCommand(seq, Cmd.getDataRange, + profile.isGen5 ? const [] : const [0x00], profile); Uint8List cmdReportVersionInfo(int seq) => buildCommand(seq, Cmd.reportVersionInfo, const []); @@ -602,10 +606,6 @@ Uint8List cmdDisableAlarm(int seq, Uint8List gen5ClientHello({int seq = 1}) => buildCommand(seq, Cmd.getHello, const [0x01], BandProfile.gen5); -/// gen5 GET_DATA_RANGE (0x22) with the EMPTY payload gen5 expects. -Uint8List cmdGetDataRangeGen5(int seq) => - buildCommand(seq, Cmd.getDataRange, const [], BandProfile.gen5); - /// gen5 SEND_HISTORICAL_DATA (0x16) with the EMPTY payload gen5 expects — the /// command that starts the flash drain. Uint8List cmdSendHistoricalGen5(int seq) => diff --git a/test/doc_conformance_test.dart b/test/doc_conformance_test.dart index 388c2bc..e78d67e 100644 --- a/test/doc_conformance_test.dart +++ b/test/doc_conformance_test.dart @@ -105,7 +105,8 @@ void main() { // zeros — any real body byte here would be a doc deviation. expect(c.inner.length, 4); expect(c.inner[3], 0, reason: 'alignment padding, not a body byte'); - final r = parseFrame(cmdGetDataRangeGen5(1), profile: BandProfile.gen5)!; + final r = parseFrame( + cmdGetDataRange(1, profile: BandProfile.gen5), profile: BandProfile.gen5)!; expect(r.inner[2], 34); expect(r.inner.length, 4); expect(r.inner[3], 0, reason: 'alignment padding, not a body byte'); diff --git a/test/whoop_protocol_update_test.dart b/test/whoop_protocol_update_test.dart index aafba3e..f7f0f6a 100644 --- a/test/whoop_protocol_update_test.dart +++ b/test/whoop_protocol_update_test.dart @@ -117,6 +117,15 @@ void main() { expect(frame.inner, [0x23, 0x06, 0x22, 0x00]); }); + test('cmdGetDataRange(profile: gen5) frames with the gen5 envelope', () { + final frame = parseFrame( + cmdGetDataRange(0x07, profile: BandProfile.gen5), + profile: BandProfile.gen5)!; + expect(frame.valid, isTrue); + // gen5 body is empty — inner is [type][seq][opcode] padded to /4. + expect(frame.inner, [0x23, 0x07, 0x22, 0x00]); + }); + test('cmdSetClock builds the WHOOP-exact 8-byte sec+subsec payload', () { // Fixed instant: sec = 0x12345678, millis = 500. // subsec = 500 * 32768 ~/ 1000 = 16384 = 0x4000 (u16 LE, then 2 zero pad).