Files
pm3py/pm3py/cli/rawcli/trace_view.py
michael 1370526883 fix(rawcli): raw response crash + hex/binary opcode completion
- Crash on raw hex: reader raw() returns `data` as a hex STRING; the raw
  path fed that to bytes() -> "string argument without an encoding".
  _raw_exchange now returns the bytes (`raw` field, or converts `data`);
  render_exchange accepts bytes or a hex string.
- Completion for numeric entry, transponder-dependent: typing hex ("60")
  or binary ("01100000") now matches the identified tag's command opcodes
  and surfaces the named command (GET_VERSION) with its help. Honours a
  0x/0b prefix and the current entry mode.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 13:00:31 -07:00

32 lines
1.3 KiB
Python

"""Render a raw reader↔tag exchange as annotated, Proxmark-style trace lines, reusing the
existing :class:`pm3py.trace.TraceFormatter` and the per-protocol decoders."""
from __future__ import annotations
from pm3py.trace import TraceFormatter, decode_14443a, decode_15693
#: protocol key -> (annotation decoder, CRC byte length)
_PROTOCOLS = {
"hf14a": (decode_14443a, 2),
"hf15": (decode_15693, 2),
"lf": (None, 0),
}
def _as_bytes(value) -> bytes:
"""Accept bytes or a hex string (which is what the reader `raw()` returns as `data`)."""
if isinstance(value, str):
return bytes.fromhex(value.replace(" ", ""))
return bytes(value)
def render_exchange(command, response, *, protocol: str = "hf14a", is_tty: bool | None = None) -> str:
"""Return the annotated trace for one exchange: a ``Reader → Tag`` line for ``command`` and,
if present, a ``Tag → Reader`` line for ``response``. Both accept bytes or a hex string.
``is_tty`` forces/suppresses ANSI."""
decoder, crc_len = _PROTOCOLS.get(protocol, (None, 0))
fmt = TraceFormatter(mode="reader", decoder=decoder, crc_len=crc_len, is_tty=is_tty)
lines = [fmt.format(0, _as_bytes(command)).strip("\n")]
if response:
lines.append(fmt.format(1, _as_bytes(response)).strip("\n"))
return "\n".join(lines)