From d59a3c017bfb248c48a28d26d0dcb1ff49bd2163 Mon Sep 17 00:00:00 2001 From: michael Date: Wed, 15 Jul 2026 21:10:10 -0700 Subject: [PATCH] docs(readme): pure-Python LF demod, rawcli memory map + per-byte base entry - LF: drop the stale "demodulation still needs the C client" note; document pm3py.lf (EM4100/HID/AWID/FDX-B + T55xx config, hardware-validated) with identify_lf/read_config. - rawcli: per-byte base intermixed entry (30 + toggle + 00000100 -> 30 00000100 -> 0x30 0x04), the completion-menu memory map (page/block roles incl. MIFARE Classic sector trailers), MFC authenticated CHK/READ/WRITE + LF T5577 commands, and the no-command/byte-mixing rule. Co-Authored-By: Claude Opus 4.8 --- README.md | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index c3b2d37..f97c795 100644 --- a/README.md +++ b/README.md @@ -137,7 +137,7 @@ pm3.lf.tune(divisor=95) Frequency is `12000 / (divisor + 1)` kHz — `95` = 125 kHz, `88` = 134 kHz. -`lf.search()` returns an `LFSearchResult` with callable next steps (it captures raw samples; full EM410x/HID/AWID demodulation still needs the C client's DSP stack): +`lf.search()` returns an `LFSearchResult` with callable next steps: ```python result = pm3.lf.search() @@ -147,6 +147,16 @@ result.tune() # check antenna voltage (tag present?) result.read_t55xx(block=0) # try reading it as a T55xx ``` +**Pure-Python LF demodulation — `pm3py.lf`.** Demod no longer needs the C client's DSP stack: +`pm3py.lf` ports the ASK/FSK/biphase pipeline and decodes the captured samples directly +(EM4100, HID, AWID, FDX-B, and the T55xx config block). Hardware-validated. + +```python +from pm3py.lf import identify_lf, read_config +identify_lf(pm3) # -> {'label': 'T5577 (EM4100 20260716FF)', 'chip': ..., 'emitted': {...}} +read_config(pm3) # decode a T55xx block-0 config (modulation, bit-rate, block count) +``` + **T55xx tags — `pm3.lf.t55.*`:** ```python @@ -510,23 +520,32 @@ NTAG213 (HF / 14a) UID 04A1B2C3 [Rdr] Tag → Reader: 01 02 03 04 … [raw / hf / NTAG213 / 0x] 30 04 # …or send raw bytes directly +[raw / hf / NTAG213 / 0b] 30 00000100 # per-byte base: hex 30 + a binary byte → sends 0x30 0x04 [raw / hf / NTAG213 / 0x] tlv 00 03 09 D1 01 05 54 02 65 6E 48 69 FE # decode a TLV / NDEF block ``` - **Breadcrumb prompt** `[raw / hf|lf / / 0x|0b]` reflects the field, the identified tag, and the current numeric entry mode. -- **Entry modes** — type hex (`30 04`) or binary; **Ctrl-/** toggles `0x`/`0b`, digits auto-group - into bytes, and `0x`/`0b` prefixes can be intermixed on one line. +- **Per-byte base entry** — type hex (`30 04`) or binary; **Ctrl-/** toggles `0x`/`0b` and digits + auto-group into bytes (a byte seals at 2 hex / 8 binary). Base is tracked **per byte**: the + toggle only changes the base of the *next* byte, so `30` then toggle then `00000100` reads as + `30 00000100` and sends `0x30 0x04`. A `0x`/`0b` prefix overrides for one token; function-call + args are base-10 (`READ(4)`, `READ(0x2B)`). Mixing a command with raw bytes on one line is an + error, not a transmit. - **`identify`** probes 14a → 15693 → LF and keeps the tag selected; **`transponder`** / **`close`** manage the connection. -- **Function-style commands** — `READ(4)`, `GET_VERSION()`, `WRITE(4, 0x01020304)` from the - identified tag's catalog (Type 2 / MIFARE Classic / ISO 15693 seeded). `help` lists them, - `help READ` shows one. +- **Function-style commands** from the identified tag's catalog: NTAG/Ultralight (`READ`, + `FAST_READ`, `GET_VERSION`, `WRITE`, …), **MIFARE Classic** (`CHK(block)` to find the sector + key, then authenticated `READ(block[, key][, A|B])` / `WRITE`), ISO 15693, and LF T5577 + (`READ`/`WRITE`/`DETECT`). `help` lists them, `help READ` shows one. +- **Completion + memory map** — command names, opcodes matched by the hex/binary value you type, + and the identified tag's **datasheet memory map** all surface in the completion menu, rendered + in whichever base you're entering. Page/block roles are named (UID, CC/OTP, user memory, + CFG0/CFG1, PWD/PACK on NTAG21x/Ultralight; manufacturer block and sector trailers — Key A / + access bits / Key B — on MIFARE Classic). - **Live annotated trace** — every exchange prints the reader↔tag frames with decoded annotations. - **TLV / NDEF** — `tlv ` prints a structured multi-line breakdown; a multi-line editor composes long TLVs. -- **ipython-style completion** — command/argument menus with each command's help as the tooltip, - plus history auto-suggestion. ## `pm3py client` — autocompleting console for the stock Proxmark3 client