fix(14a): raw() returns whole firmware buffer instead of received bytes
hf.iso14a.raw() returned the entire receive buffer the firmware replies with (sizeof(buf)), so a tag that didn't answer came back as a run of zeros (~40 bytes) rather than empty. The firmware puts the real received length in oldarg[0]; trim resp.data to it. No response -> empty (raw=b"", data=None); adds a `received` count. 2 regression tests. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -63,10 +63,16 @@ class HF14ACommands:
|
|||||||
payload=data,
|
payload=data,
|
||||||
timeout=5.0,
|
timeout=5.0,
|
||||||
)
|
)
|
||||||
|
# The firmware replies with its whole receive buffer; oldarg[0] is the number of bytes
|
||||||
|
# actually received (0 = the tag didn't answer). Trim to it so a no-response is empty,
|
||||||
|
# not a buffer of zeros.
|
||||||
|
received = resp.oldarg[0] if resp.oldarg else 0
|
||||||
|
payload = resp.data[:received] if resp.data else b""
|
||||||
return {
|
return {
|
||||||
"status": resp.status,
|
"status": resp.status,
|
||||||
"data": resp.data.hex() if resp.data else None,
|
"received": received,
|
||||||
"raw": resp.data,
|
"data": payload.hex() if payload else None,
|
||||||
|
"raw": payload,
|
||||||
}
|
}
|
||||||
|
|
||||||
async def sniff(self, param: int = 0) -> dict:
|
async def sniff(self, param: int = 0) -> dict:
|
||||||
|
|||||||
@@ -25,6 +25,31 @@ def test_14a_scan():
|
|||||||
assert result["sak"] == 0x08
|
assert result["sak"] == 0x08
|
||||||
|
|
||||||
|
|
||||||
|
def test_14a_raw_trims_to_received_length():
|
||||||
|
t = AsyncMock()
|
||||||
|
hf14a = HF14ACommands(t)
|
||||||
|
# firmware replies with its whole (padded) buffer; oldarg[0] = bytes actually received
|
||||||
|
version = bytes.fromhex("0004040201000f03") + b"\x80\x91" # 8-byte version + 2-byte CRC
|
||||||
|
t.send_mix.return_value = PM3Response(cmd=Cmd.ACK, status=0, reason=0, ng=False,
|
||||||
|
data=version + b"\x00" * 30, oldarg=[10, 0, 0])
|
||||||
|
result = asyncio.get_event_loop().run_until_complete(hf14a.raw(b"\x60"))
|
||||||
|
assert result["received"] == 10
|
||||||
|
assert result["raw"] == version # trimmed to the received length, not the padding
|
||||||
|
assert result["data"] == version.hex()
|
||||||
|
|
||||||
|
|
||||||
|
def test_14a_raw_no_response_is_empty():
|
||||||
|
t = AsyncMock()
|
||||||
|
hf14a = HF14ACommands(t)
|
||||||
|
# tag didn't answer: received length 0, buffer full of zeros -> must come back empty
|
||||||
|
t.send_mix.return_value = PM3Response(cmd=Cmd.ACK, status=0, reason=0, ng=False,
|
||||||
|
data=b"\x00" * 40, oldarg=[0, 0, 0])
|
||||||
|
result = asyncio.get_event_loop().run_until_complete(hf14a.raw(b"\x30\x99"))
|
||||||
|
assert result["received"] == 0
|
||||||
|
assert result["raw"] == b"" # not 40 bytes of zeros
|
||||||
|
assert result["data"] is None
|
||||||
|
|
||||||
|
|
||||||
def test_14a_sim_packs_ng_struct():
|
def test_14a_sim_packs_ng_struct():
|
||||||
t = AsyncMock()
|
t = AsyncMock()
|
||||||
hf14a = HF14ACommands(t)
|
hf14a = HF14ACommands(t)
|
||||||
|
|||||||
Reference in New Issue
Block a user