Files
pm3py/pm3py/_firmware.py
michael 042f49a9ec fix(sim): bound 14a sim abort latency + detect teardown host-side
Bump firmware pin to 3b6201d97, which bounds the 14a sim button / host-stop
latency under continuous reader traffic (was multi-second, now ~10ms).

SimSession now treats an HF_MIFARE_SIMULATE (0x0610) reply as end-of-sim for
14a: the sim starts with HF_ISO14443A_SIMULATE but the firmware tears down
with HF_MIFARE_SIMULATE, so _trace_reader and _relay_loop watch for it and
flip _active off on a button-driven stop (previously the host never noticed).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 10:04:44 -07:00

40 lines
1.7 KiB
Python

"""Firmware pin — the fork firmware build this pm3py release corresponds to.
pm3py and the firmware fork share a wire contract (command IDs, the response-table
format, the WTX relay, the sim-trace path), so a given pm3py must be paired with a
specific firmware build. This module records that pairing.
The pin is stamped from the ``firmware/`` submodule commit. Until tagged firmware
releases exist it is the raw commit SHA; a release process will later set ``tag``
and asset URLs, and auto-download will resolve the matching ``fullimage.elf``
against them. Nothing here reads the submodule at runtime — a pip-installed wheel
has no submodule — so the value is baked in and bumped when the pin moves.
"""
from dataclasses import dataclass
@dataclass(frozen=True)
class FirmwarePin:
"""A pinned firmware build."""
sha: str # firmware/ submodule commit (short is fine)
tag: str | None = None # release tag, once tagged releases exist
# The firmware/ submodule commit this pm3py build was developed and tested against.
FIRMWARE_PIN = FirmwarePin(sha="3b6201d97")
def matches(version_string: str, pin: FirmwarePin = FIRMWARE_PIN) -> bool:
"""True if a device's firmware version string corresponds to ``pin``.
The firmware embeds its git revision (e.g. ``Iceman/main/303bd5873-dirty``)
in the version string, so a 7-char SHA prefix (git's default abbreviation) is
a reliable substring test. A configured ``tag`` matches too, once releases
are tagged.
"""
if not version_string:
return False
if pin.tag and pin.tag in version_string:
return True
return bool(pin.sha) and pin.sha[:7] in version_string