docs: document scriptable trace access (on_frame, quiet, entries)

Adds a 'Structured / scriptable access' subsection under Live Sniff & Simulation covering the on_frame callback, quiet mode, the ANSI-free frame dict shape, and push vs pull (entries) usage for both SniffSession and SimSession.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
michael
2026-07-05 01:51:40 -07:00
parent 382732b881
commit fa31c3ad1a

View File

@@ -376,6 +376,56 @@ s.close() # stop (if needed) and close the por
A 14443-A sim path (`await s.start_14a(tag)`, WTX relay) also exists but is **async and experimental** — it requires the async `PM3Transport` (not the synchronous `SimSession.open()` port above) and is still under development.
### Structured / scriptable access
For scripting you usually want the frames as **data**, not printed colored text. Both
`start_15693(...)` methods take two optional kwargs (defaults preserve the console
behavior above):
- **`on_frame=callback`** — invoked per decoded frame (from the reader thread) with a
plain dict. Passing it also auto-enables trace streaming on the sim.
- **`quiet=True`** — don't print frames to the console (the callback and the `entries`
accumulator still fill).
Every frame is an ANSI-free dict:
```python
{'protocol': int, 'direction': int, # 0 = reader→tag, 1 = tag→reader
'timestamp': int|None, 'duration': int|None,
'data': bytes, 'data_hex': str,
'decoded': str|None} # e.g. 'INVENTORY', 'READ BLOCK 4'
```
*(SimSession frames also carry `'crc_fail': bool`; sniff frames carry `timestamp`/`duration`.)*
**Push model** — react to frames as they arrive, no printing:
```python
from pm3py.sniff.session import SniffSession
reads = []
s = SniffSession.open()
s.start_15693(on_frame=lambda f: reads.append(f["decoded"]), quiet=True)
# ... run a reader against a tag ...
s.stop(); s.close()
print(reads) # ['INVENTORY', 'READ BLOCK 0', ...] — pure data, no ANSI
```
**Pull model** — run quiet, then read the accumulator afterward:
```python
from pm3py.sim import SimSession, IcodeSlix2Tag
s = SimSession.open()
s.start_15693(IcodeSlix2Tag(uid=None), trace=True, quiet=True) # capture, no printing
# ... phone reads the tag ...
s.stop()
for f in s.entries: # list of frame dicts (a copy)
print(f["direction"], f["data_hex"], f["decoded"])
s.clear(); s.close()
```
`SimSession.entries` mirrors `SniffSession.entries`; both have `.clear()`.
### Card simulation
The simulation framework (`pm3py/sim/` infrastructure, `pm3py/transponders/` tag models) provides pure-Python transponder models served from the firmware response table. Import everything from `pm3py.sim`.