refactor: extract sniff infrastructure into pm3py/sniff/ sub-package
Phase 2 of package refactor. Extracts trace parsing, ISO 15693 decoders, NDEF annotation, and ANSI formatting from core/hf_iso15.py into dedicated sniff/ modules: - sniff/trace.py — parse_tracelog (protocol-agnostic) - sniff/ndef.py — NDEF TLV/record decode - sniff/decode_iso15.py — 15693 command/response decoders - sniff/format.py — ANSI color formatting - sniff/session.py — SniffSession with iso15() method core/hf_iso15.py re-exports sniff symbols for backward compat. Also fixes NTAG 5 placement (iso15693, not iso14443a4) in design doc. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
45
CLAUDE.md
45
CLAUDE.md
@@ -15,17 +15,38 @@ python -m pytest tests/ -v
|
||||
pip install -e .
|
||||
```
|
||||
|
||||
## Architecture
|
||||
## Package structure
|
||||
|
||||
- `protocol.py` — Wire constants, CRC-16/A, Cmd enum, PM3Status enum. Source of truth for command IDs and frame formats.
|
||||
- `transport.py` — Frame encode/decode (`encode_ng_frame`, `encode_mix_frame`, `decode_response_frame`), `PM3Transport` async serial class. USB skips CRC (uses magic `0x3361`), FPC UART uses CRC with byte-swapped wire format (`(low << 8) | high`).
|
||||
- `client.py` — `Proxmark3` class (async-first, `Proxmark3.sync()` for REPL), `_SyncProxy`, `FirmwareInfo`, port auto-detection.
|
||||
- `hw.py` — Hardware commands. LED API is platform-aware (Easy vs RDV4 have different color-to-pin mappings). PWM validation fetches capabilities on first use.
|
||||
- `lf.py` — LF commands + `T55xxCommands` + `LFSearchResult`. Full tag demod (EM410x, HID, etc.) is NOT implemented — that requires the C client's DSP stack.
|
||||
- `hf.py` — HF core (tune, search, sniff, dropfield).
|
||||
- `hf_14a.py` — ISO 14443-A (scan, raw, sniff, sim). Uses MIX frames.
|
||||
- `hf_15.py` — ISO 15693 (scan, rdbl, wrbl, sniff). Uses NG frames with ISO command payloads.
|
||||
- `hf_mf.py` — MIFARE Classic (rdbl, wrbl, rdsc, chk, sniff, sim, nested, cident). Read uses NG, write uses MIX.
|
||||
```
|
||||
pm3py/
|
||||
__init__.py # re-exports Proxmark3, PM3Error, PM3Response, Cmd, PM3Status
|
||||
core/ # wire protocol and device commands
|
||||
protocol.py # wire constants, CRC-16/A, Cmd enum, PM3Status
|
||||
transport.py # frame encode/decode, PM3Transport async serial
|
||||
client.py # Proxmark3 class, _SyncProxy, FirmwareInfo
|
||||
hw.py # hardware commands, LED API (platform-aware)
|
||||
hf.py # HF core — tune, search, sniff, dropfield
|
||||
hf_iso14a.py # ISO 14443-A — scan, raw. Uses MIX frames
|
||||
hf_iso15.py # ISO 15693 — scan, rdbl, wrbl, sniff + trace decoders
|
||||
hf_mfc.py # MIFARE Classic — rdbl, wrbl, rdsc, chk, nested, cident
|
||||
lf.py # LF commands + T55xxCommands + LFSearchResult
|
||||
sniff/ # sniff sessions, trace parsing, protocol decoders (scaffold)
|
||||
sim/ # card simulation sessions, table compiler, relay (scaffold)
|
||||
reader/ # higher-level reader modes (scaffold)
|
||||
transponders/ # tag/transponder models independent of hardware (scaffold)
|
||||
```
|
||||
|
||||
## Client API
|
||||
|
||||
```python
|
||||
pm3.hw.ping() # hardware
|
||||
pm3.hf.iso14a.scan() # ISO 14443-A
|
||||
pm3.hf.iso15.rdbl(4) # ISO 15693
|
||||
pm3.hf.mfc.rdbl(0) # MIFARE Classic
|
||||
pm3.lf.t55.readbl(0) # T55xx
|
||||
pm3.hf.tune() # HF antenna tune
|
||||
pm3.hf.dropfield() # drop field
|
||||
```
|
||||
|
||||
## Wire protocol essentials
|
||||
|
||||
@@ -37,7 +58,7 @@ pip install -e .
|
||||
|
||||
## Key patterns
|
||||
|
||||
- All command methods are `async`. The sync wrapper in `_SyncProxy` intercepts via `__getattr__` and calls `loop.run_until_complete()`.
|
||||
- All command methods are `async`. The sync wrapper in `_SyncProxy` (in `core/client.py`) intercepts via `__getattr__` and calls `loop.run_until_complete()`.
|
||||
- Command classes hold a `self._t` reference to `PM3Transport` (or mock in tests).
|
||||
- Tests use `AsyncMock` for transport. Set `hw._is_rdv4 = False` to skip capabilities fetch in LED tests.
|
||||
- `capabilities()` response parsed at known byte/bit offsets from the C struct (version=7 format).
|
||||
@@ -84,7 +105,7 @@ Firmware maintenance: atomic single-file commits for easy rebase against upstrea
|
||||
|
||||
## Adding new commands
|
||||
|
||||
1. Find the `CMD_*` constant in `include/pm3_cmd.h` and add to `Cmd` enum in `protocol.py`
|
||||
1. Find the `CMD_*` constant in `include/pm3_cmd.h` and add to `Cmd` enum in `core/protocol.py`
|
||||
2. Check if the C client uses `SendCommandNG` (→ `send_ng`) or `SendCommandMIX` (→ `send_mix`)
|
||||
3. Check the payload struct in `pm3_cmd.h` and use `struct.pack` to build it
|
||||
4. Parse the response using `struct.unpack_from` on `resp.data`
|
||||
|
||||
Reference in New Issue
Block a user