feat(iso15): add inventory() with 1/16-slot parsing + AFI/DSFID filtering
inventory() parses both response formats: slots=1 -> single tag dict (or None); slots=16 -> list of tags from the iso15_inventory_response_t anti-collision struct, each CRC15-validated. Optional request-level AFI filter and client-side DSFID filter. One 16-slot round drops colliding slots (full tree-walk resolution is a follow-up); scan() stays the single-tag convenience. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -286,3 +286,43 @@ class TestSniffLineAnnotationOverflow:
|
||||
"timestamp": 0, "duration": 0, "parity": b""}
|
||||
line = format_sniff_line(entry, width=120, is_tty=False)
|
||||
assert "CC" in line
|
||||
|
||||
|
||||
def _inv_record(uid_display_hex, dsfid=0, flags=0):
|
||||
from pm3py.core.protocol import crc15_bytes
|
||||
body = bytes([flags, dsfid]) + bytes.fromhex(uid_display_hex)[::-1]
|
||||
return body + crc15_bytes(body)
|
||||
|
||||
|
||||
def test_15_inventory_single_slot():
|
||||
t = AsyncMock()
|
||||
iso = HF15Commands(t)
|
||||
t.send_ng.return_value = PM3Response(cmd=Cmd.HF_ISO15693_COMMAND, status=0,
|
||||
reason=0, ng=True, data=_inv_record("e004a2110b37c433"))
|
||||
tag = asyncio.get_event_loop().run_until_complete(iso.inventory(slots=1))
|
||||
assert tag == {"uid": "e004a2110b37c433", "dsfid": 0, "flags": 0}
|
||||
# SLOT1 flag set in the request (raw[0] bit 0x20)
|
||||
payload = t.send_ng.call_args.args[1]
|
||||
assert payload[3] & 0x20 # raw[0] after 3-byte flags+len header
|
||||
|
||||
|
||||
def test_15_inventory_16_slot_list_and_dsfid_filter():
|
||||
t = AsyncMock()
|
||||
iso = HF15Commands(t)
|
||||
r0 = _inv_record("e004a2110b37c433")
|
||||
r3 = _inv_record("e004a2110b3746e0", dsfid=5)
|
||||
meta = bytearray(16 * 2)
|
||||
meta[0:2] = bytes([1, len(r0)]) # slot 0 valid
|
||||
meta[6:8] = bytes([1, len(r3)]) # slot 3 valid
|
||||
meta[10:12] = bytes([2, 0]) # slot 5 collision
|
||||
data = bytes([16]) + bytes(meta) + r0 + r3
|
||||
t.send_ng.return_value = PM3Response(cmd=Cmd.HF_ISO15693_COMMAND, status=0,
|
||||
reason=0, ng=True, data=data)
|
||||
tags = asyncio.get_event_loop().run_until_complete(iso.inventory(slots=16))
|
||||
assert [x["uid"] for x in tags] == ["e004a2110b37c433", "e004a2110b3746e0"]
|
||||
assert tags[0]["slot"] == 0 and tags[1]["slot"] == 3
|
||||
# client-side DSFID filter
|
||||
t.send_ng.return_value = PM3Response(cmd=Cmd.HF_ISO15693_COMMAND, status=0,
|
||||
reason=0, ng=True, data=data)
|
||||
only5 = asyncio.get_event_loop().run_until_complete(iso.inventory(slots=16, dsfid=5))
|
||||
assert [x["uid"] for x in only5] == ["e004a2110b3746e0"]
|
||||
|
||||
Reference in New Issue
Block a user