diff --git a/docs/plans/2026-07-16-c-client-oracle-and-lf-demod-parity.md b/docs/plans/2026-07-16-c-client-oracle-and-lf-demod-parity.md index eb03beb..48c917a 100644 --- a/docs/plans/2026-07-16-c-client-oracle-and-lf-demod-parity.md +++ b/docs/plans/2026-07-16-c-client-oracle-and-lf-demod-parity.md @@ -68,15 +68,21 @@ write-read-back** — and there is **no read/addressing bug**: firmware sends) reads *only the addressed block*, repetitively. A clean 32-bit repeat in the capture proves block-read mode engaged (the 64-bit emulation stream can't produce one). - `T55xx_SetBits` clocks the address MSB-first; pm3py's `readbl` payload matches the firmware - struct byte-for-byte. Addressing is correct end-to-end. -- **Write-read-back (decisive):** wrote `DEADBEEF` to unused block 3 → `READ(3)` returned - `~DEADBEEF` at **rot 0**, and *only* block 3 changed. So `READ(N)` addresses block N, reads - the right bits, and the only artifact is a **consistent Manchester polarity inversion**. + struct byte-for-byte. Addressing is stock-proxmark, verified end-to-end. +- A block-3 write-read-back was **not** decisive on its own: `writebl` and `readbl` share the + same address path, so they round-trip regardless of whether addressing is correct (it only + proved the demod inverts). Proxmark, Flipper, and pm3py all write the header into block 1, so + the alternative "pm3py reads 1↔2 swapped" had to be excluded with an **addressing-free** read. +- **Decisive test (MAXBLK=1):** temporarily set the config MAXBLK field to 1 (`00148040 → + 00148020`) so regular-read streams *only physical block 1* (datasheet §5.11.1), read it off + the air (no read-command addressing), then restored `00148040`. Physical block 1 came back as + `~BDEF7BC0` — the **non-header** half — matching `READ(1)`. So `READ(1)` == physical block 1. Conclusion: this tag was simply **cloned with the two EM4100 halves in reverse order** -(block 1 = `BDEF7BC0`, block 2 = `FF801EF7`); both orders stream the same cyclic waveform and -read as `00FFFFFFFF`. pm3py reads them correctly. The "wrong" appearance was polarity (inversion) -+ rotation, i.e. the documented "best-effort — bit alignment not verified". +(block 1 = `BDEF7BC0`, block 2 = `FF801EF7`) by a non-proxmark/Flipper/pm3py tool; both orders +stream the same cyclic waveform and read as `00FFFFFFFF`. pm3py reads them correctly. The "wrong" +appearance was polarity (inversion) + rotation, i.e. the documented "best-effort — bit alignment +not verified". **Real improvement (open):** `read_t55xx_block` should *resolve* data-block polarity/rotation instead of leaving it best-effort. Polarity is determinable — read block 0 (config), resolve its