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 <noreply@anthropic.com>
This commit is contained in:
michael
2026-07-15 21:10:10 -07:00
parent 0f77eb9b83
commit d59a3c017b

View File

@@ -137,7 +137,7 @@ pm3.lf.tune(divisor=95)
Frequency is `12000 / (divisor + 1)` kHz — `95` = 125 kHz, `88` = 134 kHz. 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 ```python
result = pm3.lf.search() 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 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.*`:** **T55xx tags — `pm3.lf.t55.*`:**
```python ```python
@@ -510,23 +520,32 @@ NTAG213 (HF / 14a) UID 04A1B2C3
[Rdr] Tag → Reader: 01 02 03 04 … [Rdr] Tag → Reader: 01 02 03 04 …
[raw / hf / NTAG213 / 0x] 30 04 # …or send raw bytes directly [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 [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 / <transponder> / 0x|0b]` reflects the field, the identified - **Breadcrumb prompt** `[raw / hf|lf / <transponder> / 0x|0b]` reflects the field, the identified
tag, and the current numeric entry mode. tag, and the current numeric entry mode.
- **Entry modes** — type hex (`30 04`) or binary; **Ctrl-/** toggles `0x`/`0b`, digits auto-group - **Per-byte base entry** — type hex (`30 04`) or binary; **Ctrl-/** toggles `0x`/`0b` and digits
into bytes, and `0x`/`0b` prefixes can be intermixed on one line. 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`** - **`identify`** probes 14a → 15693 → LF and keeps the tag selected; **`transponder`** / **`close`**
manage the connection. manage the connection.
- **Function-style commands** `READ(4)`, `GET_VERSION()`, `WRITE(4, 0x01020304)` from the - **Function-style commands** from the identified tag's catalog: NTAG/Ultralight (`READ`,
identified tag's catalog (Type 2 / MIFARE Classic / ISO 15693 seeded). `help` lists them, `FAST_READ`, `GET_VERSION`, `WRITE`, …), **MIFARE Classic** (`CHK(block)` to find the sector
`help READ` shows one. 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. - **Live annotated trace** — every exchange prints the reader↔tag frames with decoded annotations.
- **TLV / NDEF** — `tlv <hex>` prints a structured multi-line breakdown; a multi-line editor - **TLV / NDEF** — `tlv <hex>` prints a structured multi-line breakdown; a multi-line editor
composes long TLVs. 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 ## `pm3py client` — autocompleting console for the stock Proxmark3 client