feat(rawcli): command catalogs + hints for identified LF chips
catalog_for() returned None for LF, so after identifying a T5577/EM4100 the completer and input_hint had nothing — no command suggestions, no hex/binary opcode hints. Now LF chips get catalogs like the HF ones: - T5577 catalog: READ(block) / WRITE(block, data) / WAKE(password) / DETECT(), with the downlink opcode exposed via build() for hex+binary completion, block-role hints (0=config, 7=password, 1-6=data), and execution via a new run() path (LF isn't a raw-byte exchange — it drives lf.t55 / the demod). READ(0)/DETECT use the reliable rotation-fixed config read; data-block reads are best-effort and labelled as such. capture.read_t55xx_block added. - LF read-only credentials (native EM4100/HID/AWID/FDX-B) get a minimal catalog (INFO -> re-read). - catalog_for dispatches protocol "lf": "T5577" in the label -> T5577, else read-only. - TagCommand gains an optional run(device, *args); completer/_opcode tolerate build=None. Hardware-verified: identify -> catalog T5577, help lists the commands, DETECT()/READ(0) return config 00148040 (EM4100). Tests: LF resolver, T5577 opcodes, T5577 block-role hints. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -9,6 +9,7 @@ from __future__ import annotations
|
||||
|
||||
import inspect
|
||||
|
||||
from . import ask
|
||||
from . import protocols
|
||||
|
||||
# how many envelope samples to pull from BigBuf after a capture (a T55xx/EM frame is a few
|
||||
@@ -114,6 +115,21 @@ def read_config(device) -> dict | None:
|
||||
return protocols.decode_t55xx_config(data) if data else None
|
||||
|
||||
|
||||
def read_t55xx_block(device, block: int) -> int | None:
|
||||
"""Best-effort read of a T55xx 32-bit data block: send the block read, demod the first
|
||||
repeating 32-bit word. A bare block has no header/CRC, so the bit alignment (rotation) can't
|
||||
be verified — this is inherently best-effort. Block 0 (config) is the reliable one; read it
|
||||
via read_config, which resolves the rotation against known presets."""
|
||||
data = _capture(device, lambda: _try(lambda: device.lf.t55.readbl(int(block)), None))
|
||||
if not data:
|
||||
return None
|
||||
for bits in ask.manchester_bits(data):
|
||||
clean = [b for b in bits if b is not None]
|
||||
for word in protocols._repeating_words(clean, 32):
|
||||
return word
|
||||
return None
|
||||
|
||||
|
||||
def identify_lf(device, emit=None) -> dict | None:
|
||||
"""Full LF identify against a live device. Returns a result dict (``found``/``field``/
|
||||
``label``/``chip``/``config``/``emulating``/``emitted``) or ``None`` if the device is
|
||||
|
||||
Reference in New Issue
Block a user