fix(ablegacy): refuse native status-bit and PLC-5 writes before creating the runtime (#593)
A first-touch native write to a T/C/R status-bit sub-element (T4:0.DN) created and initialised the tag's runtime before the runtime's write refusal could fire; the init is one READ, so against a device lacking the file (the ab_server fixture has no T/C/R) it surfaced as BadCommunicationError + Degraded health instead of BadNotSupported. The bit-RMW path was not involved: AbLegacyAddress rejects sub-element + /N, so a status bit's BitIndex is always null. NativeAbLegacyTagRuntime.WriteRefusal is now the single predicate (status bit by address whatever the authored type; any PLC-5 write), asked by the driver via IAbLegacyTagFactory.WriteRefusal (default null, so libplctag is unchanged) before EnsureTagRuntimeAsync and ahead of the bit-RMW branch. Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe
This commit is contained in:
@@ -142,9 +142,17 @@ Native routing: SLC500/MicroLogix/PLC-5 are direct; `logixpccc` uses Unconnected
|
||||
No real SLC, MicroLogix or PLC-5 has been exercised. Opt in per driver after checking it against the real
|
||||
controller.
|
||||
- ⚠️ **Status-bit writes are refused** — `T4:0.DN`, `T4:0.TT`, `T4:0.EN`, `C5:0.CU`, `C5:0.DN`, `R6:0.EN`
|
||||
and the rest return **`BadNotSupported`**; nothing is written to the PLC; the handle is kept and health is
|
||||
unchanged. libplctag performs a masked bit write here; a native read-modify-write of the control word would
|
||||
race the PLC updating TT/DN. Reads of status bits are unaffected.
|
||||
and the rest return **`BadNotSupported`** whatever the tag's authored data type (the refusal keys on the
|
||||
address); nothing is written to the PLC; health is unchanged. The driver answers the refusal **before it
|
||||
creates the tag's runtime**, so a first-touch write sends nothing at all — not even the init read, which
|
||||
against a controller without that file used to surface as `BadCommunicationError` + Degraded health (#593
|
||||
follow-up). PLC-5 writes are refused the same way. libplctag performs a masked bit write here; a native
|
||||
read-modify-write of the control word would race the PLC updating TT/DN. Reads of status bits are unaffected.
|
||||
- ⚠️ **On libplctag (the default) a status-bit write is NOT refused** — it goes to the controller as a write to the
|
||||
timer/counter/control element (libplctag's bit-tag write; not exercised on a wire — `ab_server` has no T/C/R
|
||||
files). Nothing in authoring prevents it: the address is free text,
|
||||
any `dataType` may be chosen (a status bit is naturally authored `Bit`), and `writable` defaults to `true`.
|
||||
Author status-bit tags with `"writable": false` unless writing them is genuinely intended.
|
||||
- **PLC-5 native is N-file reads only**; every other PLC-5 operation is refused with `BadNotSupported`.
|
||||
`LogixPccc` framing is unverified. Explicit Native on either logs a Warning at init.
|
||||
- **ST (string) byte order is unverified** (no capture); string values may be byte-swapped.
|
||||
@@ -175,7 +183,10 @@ Everything below is against the `ab_server` simulator; no real PCCC controller h
|
||||
wire and reach the client as `BadNotSupported` (handle kept, health unchanged; #571 closed). Native is opt-in
|
||||
for every family; an explicit Native on PLC-5 / `logixpccc` logs a Warning at init.
|
||||
- Status-bit sub-element writes (e.g. `T4:0.DN`, `C5:0.DN`) are Unsupported natively (they would clobber the
|
||||
control word); nothing goes on the wire. Sub-element arrays are Unsupported natively. L-file bit indexes
|
||||
control word); nothing goes on the wire — the driver refuses before creating the tag's runtime, so not even an
|
||||
init read is sent (`NativeAbLegacyTagRuntime.WriteRefusal` is the single predicate, asked through
|
||||
`IAbLegacyTagFactory.WriteRefusal`). Pinned offline by `NativeAbLegacyRefusedWriteTests` and on `ab_server` by
|
||||
`AbLegacyUnsupportedPathTests` (whose SLC500 fixture has no T/C/R files, which is what makes it discriminating). Sub-element arrays are Unsupported natively. L-file bit indexes
|
||||
above 15 are allowed.
|
||||
- **ST (string) file layout is uncaptured**, so the string byte order is unverified natively.
|
||||
- Capture recipe for golden frames: `scripts/ab-capture/capture.sh` (see
|
||||
|
||||
Reference in New Issue
Block a user