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:
50
README.md
50
README.md
@@ -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`.
|
||||
|
||||
Reference in New Issue
Block a user