STAB-21 ConnectionBackoff in EnsureConnectedAsync; STAB-22 write-pass accumulator with a write-side Faulted that a clean read does not erase; _health on the Volatile idiom; S7-016 contiguous array write (Bool arrays stay refused). Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe
This commit is contained in:
+27
-1
@@ -195,6 +195,21 @@ Portal under *Protection & Security* for the CPU.
|
||||
| PUT/GET denied | `BadNotSupported` | `Faulted` (config alert) |
|
||||
| CPU / hardware fault | `BadDeviceFailure` | `Degraded` |
|
||||
| Socket / timeout | `BadCommunicationError` | `Degraded` |
|
||||
| Reconnect suppressed (backoff window) | `BadCommunicationError` | `Degraded` |
|
||||
| Array write of the wrong shape / length / element type | `BadTypeMismatch` | unchanged |
|
||||
| Bool / wide-type array write | `BadNotSupported` | unchanged |
|
||||
|
||||
**Health is decided once per pass, worst state wins.** A read pass and a write batch each
|
||||
accumulate their outcomes and write health once (`Healthy < Degraded < Faulted`), so a PUT/GET-denied
|
||||
`Faulted` item is not erased by a later `Degraded` or successful sibling. The write-side `Faulted` is
|
||||
**sticky against reads**: a clean read pass (reads often work against a write-protected CPU) leaves
|
||||
`Faulted` in place and only advances `LastSuccessfulRead`; the next write that succeeds clears it. A
|
||||
transient `Degraded` write failure is still cleared by a clean read, as before.
|
||||
|
||||
**Connect backoff.** A dead PLC costs one connect attempt per backoff window (1 s doubling to a 30 s
|
||||
cap), not one per read / poll tick / probe tick: inside the window `EnsureConnectedAsync` fails fast
|
||||
(`BadCommunicationError`, `Degraded`) without a connect. A successful connect clears the window, so a
|
||||
fresh drop after a healthy period reconnects immediately; worst-case recovery lag is the 30 s cap.
|
||||
|
||||
## Testing
|
||||
|
||||
@@ -228,7 +243,18 @@ normal dev (the S7 sim is on the shared Docker host but currently offline).
|
||||
|
||||
**Live-verify** — integration-fixture-gated (not Mac-verifiable without the S7 sim up).
|
||||
|
||||
**Deferrals** — array *writes*, multi-dimensional arrays, per-element historization,
|
||||
**Array writes (S7-016)** — a writable `Byte` / `Int16` / `UInt16` / `Int32` / `UInt32` / `Float32` array
|
||||
is written as ONE contiguous `WriteBytesAsync` of `count x element-bytes` (the inverse of the read
|
||||
decode), and the value must be an array of exactly `arrayLength` elements (else `BadTypeMismatch`, no
|
||||
health impact). **Writable `Bool` arrays are refused at init** (`NotSupportedException`): the array
|
||||
read is byte-granular, so a matching write would overwrite the 7 neighbouring bits of every byte it
|
||||
touches, and a safe bit-packed write needs read-modify-write. Mark Bool arrays `writable: false`.
|
||||
Note the *server* still presents every array node read-only to OPC UA clients ([Uns.md §Array
|
||||
tags](../Uns.md#array-tags-1-d), #610 item 1) — the driver path is reachable today through the Client
|
||||
CLI / driver-level callers and is proven by the unit suite plus the snap7 fixture test
|
||||
(`S7_1500ArrayWriteTests`); the AdminUI tag editor rejects wide-type and writable-Bool arrays at author time.
|
||||
|
||||
**Deferrals** — server-side exposure of array writes, multi-dimensional arrays, per-element historization,
|
||||
wide-type array elements (`Int64`, `UInt64`, `Float64`, `String`, `DateTime`), and
|
||||
Timer/Counter array elements.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user