From 05a39bccdade6916dece6f9f48e3a20264c03479 Mon Sep 17 00:00:00 2001 From: Mohammad Abdul Sahil <127765312+abdulsaheel@users.noreply.github.com> Date: Sat, 19 Sep 2026 13:26:07 +0530 Subject: [PATCH] cmdBuzz: take a profile like its siblings cmdBuzz was the only cmd builder in commands.dart with no BandProfile param, so it always built a gen4 frame no matter what band it was really going to. no live bug today (ble_engine branches around it with cmdBuzzGen5Maverick) but any future generic caller passing profile: gen5 would silently get a gen4 crc8 frame a real gen5 strap can't parse. same fix as cmdGetBattery/cmdAbortHistorical/etc got earlier. --- lib/src/commands.dart | 5 +++-- test/gen5_command_surface_test.dart | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/lib/src/commands.dart b/lib/src/commands.dart index f0427d8..94992b0 100644 --- a/lib/src/commands.dart +++ b/lib/src/commands.dart @@ -280,12 +280,13 @@ Uint8List cmdEnableOptical(int seq, bool on, {BandProfile profile = BandProfile. /// nothing to tell the caller. A value that does not fit a u8 is a caller bug, /// so throw. (Contrast [cmdSetAlarm], which masks because its payload is a /// pattern LIST already validated for length.) -Uint8List cmdBuzz(int seq, [int pattern = hapticShortPulse]) { +Uint8List cmdBuzz(int seq, + [int pattern = hapticShortPulse, BandProfile profile = BandProfile.gen4]) { if (pattern < 0 || pattern > 0xff) { throw ArgumentError.value( pattern, 'pattern', 'haptic waveform effect must fit in a u8 (0-255)'); } - return buildCommand(seq, Cmd.runHapticsPattern, [pattern, 0, 0, 0, 0]); + return buildCommand(seq, Cmd.runHapticsPattern, [pattern, 0, 0, 0, 0], profile); } // ── On-device haptic alarm (SET_ALARM_TIME = 0x42) ───────────────────────── diff --git a/test/gen5_command_surface_test.dart b/test/gen5_command_surface_test.dart index 87a4d45..da491f0 100644 --- a/test/gen5_command_surface_test.dart +++ b/test/gen5_command_surface_test.dart @@ -461,6 +461,24 @@ void main() { expect(f4.opcode, Cmd.abortHistoricalTransmits); }); + test('RUN_HAPTICS_PATTERN (cmdBuzz) is profile-aware', () { + // cmdBuzz was the one builder in this file missing a BandProfile + // parameter entirely, so a gen5 caller silently got a gen4 frame. + final gen5Frame = cmdBuzz(1, hapticShortPulse, gen5); + final f = parseFrame(gen5Frame, profile: gen5)!; + expect(f.valid, isTrue, reason: 'must parse as a gen5 frame'); + expect(f.opcode, Cmd.runHapticsPattern); + final asGen4 = parseFrame(gen5Frame, profile: BandProfile.gen4); + expect(asGen4 == null || !asGen4.valid, isTrue, + reason: 'a gen5 frame must not also parse as valid gen4'); + + // Default (no profile arg) stays gen4 — backward compatible. + final gen4Frame = cmdBuzz(1); + final f4 = parseFrame(gen4Frame, profile: BandProfile.gen4)!; + expect(f4.valid, isTrue); + expect(f4.opcode, Cmd.runHapticsPattern); + }); + test('GET_BATTERY_LEVEL (26) is profile-aware', () { // control.dart's decode branches on profile.isGen5 for this exact // opcode's reply (u8 percent vs u16 LE deci-percent), so the request