diff --git a/README.md b/README.md index c927593..1ec5060 100644 --- a/README.md +++ b/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`.