diff --git a/pm3py/core/lf.py b/pm3py/core/lf.py index 6fd25c6..2ba289f 100644 --- a/pm3py/core/lf.py +++ b/pm3py/core/lf.py @@ -111,23 +111,32 @@ class LFCommands: return result - async def read(self, samples: int = 12288, verbose: bool = False, - on_progress: ProgressCallback = None) -> dict: - """Read LF ADC samples into device buffer.""" - val = (samples & 0x3FFFFFFF) + async def _acquire(self, cmd: int, samples: int, verbose: bool = False) -> dict: + """Capture LF ADC samples into BigBuf. Shared by read (reader field ON) and sniff + (field OFF). Payload is lf_sample_payload_t — a PACKED bitfield: samples:30, realtime:1, + verbose:1, cotag:1 (5 bytes).""" + word = (samples & 0x3FFFFFFF) if verbose: - val |= (1 << 31) - payload = struct.pack("= 4 else 0, } + async def read(self, samples: int = 12288, verbose: bool = False, + on_progress: ProgressCallback = None) -> dict: + """Reader-mode LF acquisition: turn the reader field ON and sample the tag's load + modulation (this is ``lf read`` — CMD_LF_ACQ_RAW_ADC). Use this before download_samples + to read an EM4100/T5577/HID. (SNIFF, field-off, captures nothing from a tag.)""" + return await self._acquire(Cmd.LF_ACQ_RAW_ADC, samples, verbose) + async def sniff(self, samples: int = 12288, on_progress: ProgressCallback = None) -> dict: - """Sniff LF signal.""" - return await self.read(samples=samples, on_progress=on_progress) + """Sniff LF: reader field OFF, capture an external reader<->tag exchange + (CMD_LF_SNIFF_RAW_ADC).""" + return await self._acquire(Cmd.LF_SNIFF_RAW_ADC, samples) async def sim(self, gap: int = 0, data: bytes = b"", on_progress: ProgressCallback = None) -> dict: diff --git a/tests/test_lf.py b/tests/test_lf.py index bddd9ae..1687f01 100644 --- a/tests/test_lf.py +++ b/tests/test_lf.py @@ -76,3 +76,27 @@ def test_lf_t55_config_client_side(): assert len(result["modes"]) == 4 # No firmware round-trip: SET_CONFIG is write-only and never replies t.send_ng.assert_not_called() + + +def test_lf_read_uses_reader_field_acq(): + # read() must turn the reader field ON (LF_ACQ_RAW_ADC) — SNIFF is field-off and reads nothing + t = AsyncMock() + lf = LFCommands(t) + t.send_ng.return_value = make_response(Cmd.LF_ACQ_RAW_ADC, 0, struct.pack(" 1 else kwargs["payload"] + assert len(payload) == 5 # lf_sample_payload_t: 30+1+1 bits + cotag byte + word = struct.unpack_from("> 30) & 1 == 0 # realtime = 0 + + +def test_lf_sniff_uses_field_off(): + t = AsyncMock() + lf = LFCommands(t) + t.send_ng.return_value = make_response(Cmd.LF_SNIFF_RAW_ADC, 0, struct.pack("