fix(lf): correct T55xx write/wakeup structs, 2-byte LF tune, fire-and-forget sampling config
lf.tune sends the 2-byte {mode,divisor} the firmware requires (was 3 -> EINVARG/0V). t55.writebl packs the 10-byte {data,pwd,blockno,flags} struct with a single bit-packed flags byte (was 12). t55.wakeup packs 5 bytes {pwd,flags}. t55.config is maintained client-side (firmware has no GET). LF_SAMPLING_SET_CONFIG uses send_ng_no_response (firmware never replies). Pre-existing, independent of the rebase.
This commit is contained in:
@@ -11,11 +11,15 @@ def make_response(cmd, status, data):
|
||||
def test_lf_tune():
|
||||
t = AsyncMock()
|
||||
lf = LFCommands(t)
|
||||
# First call: init, second call: poll returns data
|
||||
# First call: init, second call: measure returns uint32 voltage
|
||||
t.send_ng.return_value = make_response(Cmd.MEASURE_ANTENNA_TUNING_LF, 0,
|
||||
struct.pack("<I", 42000))
|
||||
result = asyncio.get_event_loop().run_until_complete(lf.tune(divisor=95))
|
||||
assert "voltage_mV" in result
|
||||
assert result["voltage_mV"] == 42000
|
||||
# Firmware requires exactly 2-byte payloads ({1,div} init, {2,div} measure)
|
||||
calls = t.send_ng.call_args_list
|
||||
assert calls[0].args[1] == struct.pack("<BB", 1, 95)
|
||||
assert calls[1].args[1] == struct.pack("<BB", 2, 95)
|
||||
|
||||
def test_lf_config_get():
|
||||
t = AsyncMock()
|
||||
@@ -25,3 +29,50 @@ def test_lf_config_get():
|
||||
result = asyncio.get_event_loop().run_until_complete(lf.config())
|
||||
assert "decimation" in result
|
||||
assert "bits_per_sample" in result
|
||||
|
||||
def test_lf_config_set_fire_and_forget():
|
||||
t = AsyncMock()
|
||||
lf = LFCommands(t)
|
||||
payload = struct.pack("<bbbhhib", 1, 8, 1, 95, 128, 0, 0)
|
||||
t.send_ng.return_value = make_response(Cmd.LF_SAMPLING_GET_CONFIG, 0, payload)
|
||||
asyncio.get_event_loop().run_until_complete(lf.config(divisor=88))
|
||||
# Firmware never replies to SET — must be fire-and-forget
|
||||
t.send_ng_no_response.assert_awaited_once()
|
||||
assert t.send_ng_no_response.call_args.args[0] == Cmd.LF_SAMPLING_SET_CONFIG
|
||||
|
||||
def test_lf_t55_writebl():
|
||||
t = AsyncMock()
|
||||
lf = LFCommands(t)
|
||||
t.send_ng.return_value = make_response(Cmd.LF_T55XX_WRITEBL, 0, b"")
|
||||
asyncio.get_event_loop().run_until_complete(
|
||||
lf.t55.writebl(block=4, data=0x12345678, page=1,
|
||||
password=0xAABBCCDD, downlink_mode=2))
|
||||
payload = t.send_ng.call_args.args[1]
|
||||
# data(4)+pwd(4)+blockno(1)+flags(1) = 10 bytes
|
||||
assert len(payload) == 10
|
||||
data, pwd, blockno, flags = struct.unpack("<IIBB", payload)
|
||||
assert data == 0x12345678
|
||||
assert pwd == 0xAABBCCDD
|
||||
assert blockno == 4
|
||||
# PwdMode(0x01) | Page(0x02) | downlink 2<<3 (0x10) = 0x13
|
||||
assert flags == 0x13
|
||||
|
||||
def test_lf_t55_wakeup():
|
||||
t = AsyncMock()
|
||||
lf = LFCommands(t)
|
||||
t.send_ng.return_value = make_response(Cmd.LF_T55XX_WAKEUP, 0, b"")
|
||||
asyncio.get_event_loop().run_until_complete(
|
||||
lf.t55.wakeup(password=0x11223344, downlink_mode=3))
|
||||
payload = t.send_ng.call_args.args[1]
|
||||
assert len(payload) == 5
|
||||
pwd, flags = struct.unpack("<IB", payload)
|
||||
assert pwd == 0x11223344
|
||||
assert flags == (3 << 3)
|
||||
|
||||
def test_lf_t55_config_client_side():
|
||||
t = AsyncMock()
|
||||
lf = LFCommands(t)
|
||||
result = asyncio.get_event_loop().run_until_complete(lf.t55.config())
|
||||
assert len(result["modes"]) == 4
|
||||
# No firmware round-trip: SET_CONFIG is write-only and never replies
|
||||
t.send_ng.assert_not_called()
|
||||
|
||||
Reference in New Issue
Block a user