From 35f16b7664a3d7c0f2a310fc17515a0d4f6e0466 Mon Sep 17 00:00:00 2001 From: michael Date: Sat, 4 Jul 2026 22:38:23 -0700 Subject: [PATCH] fix(hf): tune() must send START/MEASURE/STOP mode byte and parse uint16 CMD_MEASURE_ANTENNA_TUNING_HF requires a 1-byte mode arg (firmware rejects length!=1 with EINVARG) and returns the voltage as uint16, not uint32. tune() sent no arg (empty reply -> 0 mV) and parsed --- pm3py/core/hf.py | 14 +++++++++++--- tests/test_hf.py | 9 +++++++-- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/pm3py/core/hf.py b/pm3py/core/hf.py index 2d118ac..03305e5 100644 --- a/pm3py/core/hf.py +++ b/pm3py/core/hf.py @@ -16,9 +16,17 @@ class HFCommands: self.mfc = None # type: ignore async def tune(self, on_progress: ProgressCallback = None) -> dict: - """Measure HF antenna voltage.""" - resp = await self._t.send_ng(Cmd.MEASURE_ANTENNA_TUNING_HF, timeout=10.0) - voltage = struct.unpack_from("= 4 else 0 + """Measure HF antenna voltage. + + CMD_MEASURE_ANTENNA_TUNING_HF is a START/MEASURE/STOP state machine that + requires a 1-byte mode arg (firmware rejects length!=1 with EINVARG): + mode 1 = START (spins up the HF FPGA), mode 2 = MEASURE (returns uint16 mV), + mode 3 = STOP. Voltage is a uint16_t, not uint32_t. + """ + await self._t.send_ng(Cmd.MEASURE_ANTENNA_TUNING_HF, bytes([1]), timeout=10.0) # START + resp = await self._t.send_ng(Cmd.MEASURE_ANTENNA_TUNING_HF, bytes([2]), timeout=10.0) # MEASURE + voltage = struct.unpack_from("= 2 else 0 + await self._t.send_ng(Cmd.MEASURE_ANTENNA_TUNING_HF, bytes([3]), timeout=10.0) # STOP result = { "voltage_mV": voltage, "voltage_V": round(voltage / 1000.0, 3), diff --git a/tests/test_hf.py b/tests/test_hf.py index 281aa86..d700a37 100644 --- a/tests/test_hf.py +++ b/tests/test_hf.py @@ -7,7 +7,12 @@ from pm3py.core.hf import HFCommands def test_hf_tune(): t = AsyncMock() hf = HFCommands(t) + # MEASURE (mode 2) returns the voltage as a uint16 mV; 15485 mV = 0x3C7D t.send_ng.return_value = PM3Response(cmd=Cmd.MEASURE_ANTENNA_TUNING_HF, status=0, - reason=0, ng=True, data=b"\x00" * 4) + reason=0, ng=True, data=b"\x7d\x3c") result = asyncio.get_event_loop().run_until_complete(hf.tune()) - assert "voltage_mV" in result + assert result["voltage_mV"] == 15485 + assert result["voltage_V"] == 15.485 + # Firmware requires the START(1)/MEASURE(2)/STOP(3) mode-byte sequence + modes = [call.args[1] for call in t.send_ng.call_args_list] + assert modes == [bytes([1]), bytes([2]), bytes([3])]