From 755a0698b80718995ac6754bd88a4153daa9f1a3 Mon Sep 17 00:00:00 2001 From: Mohammad Abdul Sahil <127765312+abdulsaheel@users.noreply.github.com> Date: Sat, 19 Sep 2026 11:43:11 +0530 Subject: [PATCH] fix cmdAbortHistorical to take a profile like its siblings it was the one command in the labrador prepare/start sequence (20 -> 123 -> 139 -> 125 -> 124) that never got the profile param when the others did. a gen5 caller had no way to make its abort step frame as gen5, so it silently sent a gen4 frame the strap can't parse. defaults to gen4, so existing callers are unaffected. --- lib/src/commands.dart | 4 ++-- test/gen5_command_surface_test.dart | 21 +++++++++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/lib/src/commands.dart b/lib/src/commands.dart index a5ebc35..fb339db 100644 --- a/lib/src/commands.dart +++ b/lib/src/commands.dart @@ -101,8 +101,8 @@ Uint8List cmdGetHello(int seq) => buildCommand(seq, Cmd.getHelloHarvard, const [0x00]); Uint8List cmdGetHelloModern(int seq) => buildCommand(seq, Cmd.getHello, const [0x01]); -Uint8List cmdAbortHistorical(int seq) => - buildCommand(seq, Cmd.abortHistoricalTransmits, const [0x00]); +Uint8List cmdAbortHistorical(int seq, {BandProfile profile = BandProfile.gen4}) => + buildCommand(seq, Cmd.abortHistoricalTransmits, const [0x00], profile); Uint8List cmdSendHistorical(int seq) => buildCommand(seq, Cmd.sendHistoricalData, const [0x00]); /// Read the strap RTC (GET_CLOCK = 0x0B = 11) with an EMPTY body. diff --git a/test/gen5_command_surface_test.dart b/test/gen5_command_surface_test.dart index 047e730..9e2b444 100644 --- a/test/gen5_command_surface_test.dart +++ b/test/gen5_command_surface_test.dart @@ -440,6 +440,27 @@ void main() { } }); + test('ABORT_HISTORICAL_TRANSMITS (20) is profile-aware', () { + // The first step of the Labrador prepare/start sequence; must frame + // as gen5 (8-byte header, CRC16-Modbus) when the rest of that sequence + // does, not silently fall back to gen4 framing. + final gen5Frame = cmdAbortHistorical(1, profile: gen5); + final f = parseFrame(gen5Frame, profile: gen5)!; + expect(f.valid, isTrue, reason: 'must parse as a gen5 frame'); + expect(f.opcode, Cmd.abortHistoricalTransmits); + // A gen4 parse of a gen5 frame must NOT also validate (wrong header + // length / CRC scheme) — otherwise this test can't tell them apart. + 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 = cmdAbortHistorical(1); + final f4 = parseFrame(gen4Frame, profile: BandProfile.gen4)!; + expect(f4.valid, isTrue); + expect(f4.opcode, Cmd.abortHistoricalTransmits); + }); + // Filtered reading ("Labrador", R17) — the three lifecycle toggles. // Every body is [revision 01][operation]; 124's operation is // NOT a boolean.