diff --git a/CLAUDE.md b/CLAUDE.md index f18f9991..6b0a85a0 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1089,11 +1089,11 @@ re-emit a concrete default. The defaults differ per driver (final review, 2026-1 through the old AdminUI, whose typed form drops unknown keys (#576). Evidence: AbCip reads proven on a real CompactLogix (Z-35162); scalar native writes (DINT/BOOL/REAL) proven on it once (2026-10-09, user-approved one-off, restored) — and native UDT member writes (DINT/BIT/REAL, #611 gate, same day); array/STRING, libplctag member and fragmented writes are `ab_server`-only. - **AbLegacy: an absent key resolves to `Libplctag` for every family; `Native` is opt-in** (no node key). On - a wire the native PCCC path is proven only for **N-file reads/writes and one F8 read**, all on `ab_server`; - `S:0` (the default probe), B/T/C/R/S/L/ST/A/O/I and the T/C/R sub-element offsets are encoded from the PCCC - table and **unverified natively**. Explicit Native on PLC-5/`LogixPccc` logs a once-per-instance Warning. - AbLegacy native refuses status-bit sub-element writes (`T4:0.DN`…, `BadNotSupported`) and its ST byte order - is unverified. + a real MicroLogix 1400 (Z-33323, idle, 2026-10-09) native read S/N/F/B/T/C/R/ST/O/I incl. `S:0`, T/C/R + sub-elements and status bits, and ST byte order, all correct, and wrote N/F8/B-bit (restored); ⚠️ **libplctag (the + default) fails `S:`/`O:`/`I:` and control status bits there** — the default probe `S:0` fails on real hardware. + L/A files, function files, SLC, PLC-5 and `logixpccc` remain unverified natively. Explicit Native on PLC-5/`LogixPccc` logs a once-per-instance Warning. + AbLegacy native refuses status-bit sub-element writes (`T4:0.DN`…, `BadNotSupported`). Refusals are not comms faults: an Unsupported refusal (`BadNotSupported`) and an AbCip native **type mismatch** (`BadTypeMismatch`, where libplctag returned Good garbage for a same-width mis-authored type) both diff --git a/docs/drivers/AbLegacy.md b/docs/drivers/AbLegacy.md index 6758ef01..3a09b0fd 100644 --- a/docs/drivers/AbLegacy.md +++ b/docs/drivers/AbLegacy.md @@ -210,18 +210,45 @@ Native routing: SLC500/MicroLogix/PLC-5 are direct; `logixpccc` uses Unconnected ### Wire evidence (native PCCC) -Everything below is against the `ab_server` simulator; no real PCCC controller has been exercised. +**Real controller (2026-10-09, user-directed):** MicroLogix 1400 **Z-33323** (`ab://10.201.44.231/`, empty path), +chosen because it was idle (`N10:150/0` cycle-in-progress and `B3:0/4` false, pump input `I:0/0` off, `O:0` = 0 +before and after). Read pass, each address on libplctag then native (raw output in +[the gate-results doc](../plans/2026-10-07-native-ab-transport-gate-results.md)): + +| Address(es) | libplctag | Native | +|---|---|---| +| `S:0` (default probe), `S:57` (= 1400), `S:4` | **BadCommunicationError** | Good (4, 1400, clock) | +| `N9:0`, `N9:4`, `N7:255` | Good | Good, equal | +| `F8:226` (2.1), `F8:214` (200.0) | Good | Good, equal | +| `B3:24`, `B3:28` (0x0905), bits `/0`, `/8`, `/9`, `B3:132/14` | Good | Good, equal | +| `T4:15/93/14/11.PRE`, `.ACC`, `.DN`; `T40:3/12.PRE` | Good | Good, equal | +| `C5:0.PRE/.ACC`, `C5:1.PRE`, `C5:8.DN` | Good | Good, equal | +| `R6:0.LEN`, `.POS` | Good | Good, equal | +| `R6:0.DN` (and `.EN`) | **BadCommunicationError** | Good | +| `ST14:10` (`"Z-33323"`), `ST14:0` | Good | Good, equal — **ST byte order correct** | +| `O:0`, `O:0/3`, `I:0`, `I:0/0` | **BadCommunicationError** | Good | + +Native writes on the same idle press, each restored to 0 and verified: `N7:23` 0→4242→0 (neighbours `N7:22/24` +unchanged), `F8:190` 0→42.5→0, `B3:200` bit RMW `/5` set → 32, `/3` set → 40, `/5` clear → 8, `/3` clear → 0 +(neighbours `B3:199/201` unchanged). Addresses vetted against the sibling Z-33756 program export (no ladder, +symbol, HMI, panel or migration reference) and Z-33323's own symbol table, and read 0 beforehand. +⚠️ **libplctag (the default) cannot read `S`, `O`, `I` or control status bits on this controller**, and the +numbered forms (`S2:0`, `O0:0`, `I1:0`) are rejected by the address parser — so the default probe `S:0` fails on a +real MicroLogix under the default transport (tracked as a follow-up issue). Not tested on hardware: L and A files +(no press has them), function files, PLC-5, SLC, `logixpccc`. + +Simulator evidence: | What | Evidence | |---|---| | N-file read (`N7:0`) | libplctag captures `slc500-read-n7`, `micrologix-read-n7`, `plc5-read-n7` (codec byte parity) + native `AbLegacyReadSmokeTests` read on all three profiles | | N-file write (`N7:5`) | capture `slc500-write-n7` + native `AbLegacyReadSmokeTests` write/read round trip (SLC 500) | | F-file read (`F8`) | one capture, `slc500-read-f8` (codec parity only; no native F write on a wire) | -| S (incl. the default probe `S:0`), B, T, C, R, L, ST, A, O, I | **none** — encoded from the PCCC file-type table | +| S (incl. `S:0`), B, T, C, R, ST, O, I | **real MicroLogix 1400 (above)**; L and A: none | | MicroLogix function files (RTC/HSC/...), PLC-5 octal I/O | **none** — parsed only; native refuses function files as Unsupported | | Bit-within-word write (`B3:0/5`) | `ab_server` SLC500 + MicroLogix, both transports (`AbLegacyBitWriteTests`): the driver RMWs the parent word, only the addressed bit changes (the parent-word read-modify-write is not atomic against ladder writes to the same word). PLC-5 native refuses it (`BadNotSupported`, #571) | | Indirect addressing (`N7:[N7:0]`) | `ab_server` N-file, both transports (#646) - resolved by the driver, the transport sees the composed address | -| T/C/R sub-elements (`.PRE`/`.ACC`/`.LEN`/`.POS`), 6-byte T/C/R element layout | **none** | +| T/C/R sub-elements (`.PRE`/`.ACC`/`.LEN`/`.POS`, status bits) | **real MicroLogix 1400 (above)** | ### Native known gaps diff --git a/docs/plans/2026-10-07-native-ab-transport-gate-results.md b/docs/plans/2026-10-07-native-ab-transport-gate-results.md index 906d3ec1..717a534d 100644 --- a/docs/plans/2026-10-07-native-ab-transport-gate-results.md +++ b/docs/plans/2026-10-07-native-ab-transport-gate-results.md @@ -576,3 +576,74 @@ restore, snapshot again. Every write and read returned Good (`0x00000000`); the final snapshot equals the pre-gate snapshot. Not covered: sibling-bit preservation inside one hidden host SINT (this UDT has a single BIT member) and the libplctag member-write path. Raw output: the session scratchpad `hw4/gate611.txt`. + +## AbLegacy on a real MicroLogix 1400 — 2026-10-09 (Z-33323, idle, user-directed) + +Press selection: Z-33470 was mid-cycle (`N10:150/0` = `B3:0/4` = true) and was left alone; Z-33323 read idle on both, with the pump input `I:0/0` off. The other North presses time out on TCP from the VPN (ICMP answers). AbLegacy CLI from master, `ab://10.201.44.231/`, `-P MicroLogix`. + +``` +=== 10.201.44.231 +ST14:10 Value: "Z-33323" Status: 0x00000000 (Good) +N10:150/0 Value: false Status: 0x00000000 (Good) +B3:0/4 Value: false Status: 0x00000000 (Good) +I:0/0 Value: Status: 0x80050000 (BadCommunicationError) +I:0/1 Value: Status: 0x80050000 (BadCommunicationError) +=== 10.201.44.249 +ST14:10 Value: "Z-33470" Status: 0x00000000 (Good) +N10:150/0 Value: true Status: 0x00000000 (Good) +B3:0/4 Value: true Status: 0x00000000 (Good) +I:0/0 Value: Status: 0x80050000 (BadCommunicationError) +I:0/1 Value: Status: 0x80050000 (BadCommunicationError) + +IDLE CHECK N10:150/0=false 0x00000000 (Good) B3:0/4=false 0x00000000 (Good) +S:0 Int | lib: 0x80050000 (BadCommunicationError) | nat: 4 0x00000000 (Good) +S:57 Int | lib: 0x80050000 (BadCommunicationError) | nat: 1400 0x00000000 (Good) +S:4 Int | lib: 0x80050000 (BadCommunicationError) | nat: 9952 0x00000000 (Good) +N9:0 Int | lib: 2331 0x00000000 (Good) | nat: 2331 0x00000000 (Good) +N9:4 Int | lib: 3867 0x00000000 (Good) | nat: 3867 0x00000000 (Good) +N7:255 Int | lib: 32000 0x00000000 (Good) | nat: 32000 0x00000000 (Good) +F8:226 Float | lib: 2.1 0x00000000 (Good) | nat: 2.1 0x00000000 (Good) +F8:214 Float | lib: 200 0x00000000 (Good) | nat: 200 0x00000000 (Good) +B3:24 Int | lib: 1 0x00000000 (Good) | nat: 1 0x00000000 (Good) +B3:24/0 Bit | lib: true 0x00000000 (Good) | nat: true 0x00000000 (Good) +B3:28 Int | lib: 2309 0x00000000 (Good) | nat: 2309 0x00000000 (Good) +B3:28/8 Bit | lib: true 0x00000000 (Good) | nat: true 0x00000000 (Good) +B3:28/9 Bit | lib: false 0x00000000 (Good) | nat: false 0x00000000 (Good) +B3:132/14 Bit | lib: true 0x00000000 (Good) | nat: true 0x00000000 (Good) +T4:15.PRE Int | lib: 6000 0x00000000 (Good) | nat: 6000 0x00000000 (Good) +T4:15.ACC Int | lib: 6000 0x00000000 (Good) | nat: 6000 0x00000000 (Good) +T4:15.DN Bit | lib: true 0x00000000 (Good) | nat: true 0x00000000 (Good) +T4:93.PRE Int | lib: 7000 0x00000000 (Good) | nat: 7000 0x00000000 (Good) +T4:93.DN Bit | lib: false 0x00000000 (Good) | nat: false 0x00000000 (Good) +T4:14.PRE Int | lib: 3600 0x00000000 (Good) | nat: 3600 0x00000000 (Good) +T4:14.ACC Int | lib: 2922 0x00000000 (Good) | nat: 2922 0x00000000 (Good) +T4:11.PRE Int | lib: 32767 0x00000000 (Good) | nat: 32767 0x00000000 (Good) +T40:3.PRE Int | lib: 500 0x00000000 (Good) | nat: 500 0x00000000 (Good) +T40:12.PRE Int | lib: 500 0x00000000 (Good) | nat: 500 0x00000000 (Good) +C5:0.PRE Int | lib: 999 0x00000000 (Good) | nat: 999 0x00000000 (Good) +C5:0.ACC Int | lib: 111 0x00000000 (Good) | nat: 111 0x00000000 (Good) +C5:8.DN Bit | lib: true 0x00000000 (Good) | nat: true 0x00000000 (Good) +C5:1.PRE Int | lib: 32767 0x00000000 (Good) | nat: 32767 0x00000000 (Good) +R6:0.LEN Int | lib: 32 0x00000000 (Good) | nat: 32 0x00000000 (Good) +R6:0.POS Int | lib: 0 0x00000000 (Good) | nat: 0 0x00000000 (Good) +R6:0.DN Bit | lib: 0x80050000 (BadCommunicationError) | nat: false 0x00000000 (Good) +ST14:10 String | lib: "Z-33323" 0x00000000 (Good) | nat: "Z-33323" 0x00000000 (Good) +ST14:0 String | lib: "EQ_TEST_LARGE_MOLD" 0x00000000 (Good) | nat: "EQ_TEST_LARGE_MOLD" 0x00000000 (Good) +O:0 Int | lib: 0x80050000 (BadCommunicationError) | nat: 0 0x00000000 (Good) +O:0/3 Bit | lib: 0x80050000 (BadCommunicationError) | nat: false 0x00000000 (Good) +I:0 Int | lib: 0x80050000 (BadCommunicationError) | nat: -29376 0x00000000 (Good) +I:0/0 Bit | lib: 0x80050000 (BadCommunicationError) | nat: false 0x00000000 (Good) +IDLE RECHECK N10:150/0=false 0x00000000 (Good) + +pre: cycle=falseG pump=falseG +-- N7:23 write 4242: 0x00000000 (Good) -> N7:22=0G N7:23=4242G N7:24=0G +-- N7:23 restore 0: 0x00000000 (Good) -> N7:23=0G +-- F8:190 write 42.5: 0x00000000 (Good) -> F8:190=42.5G +-- F8:190 restore 0: 0x00000000 (Good) -> F8:190=0G +-- B3:200/5 set: 0x00000000 (Good) -> B3:200=32G (exp 32) +-- B3:200/3 set: 0x00000000 (Good) -> B3:200=40G (exp 40) +-- B3:200/5 clear: 0x00000000 (Good) -> B3:200=8G (exp 8) +-- B3:200/3 clear: 0x00000000 (Good) -> B3:200=0G (exp 0) +-- neighbours: B3:199=0G B3:201=0G +post: cycle=falseG pump=falseG N7:23=0G F8:190=0G B3:200=0G +```