feat(twincat): opt-in ADS sum-read and /hosts diagnostics bag; refresh TwinCAT backlog (#645, #612)

Sum-read (#310): batches a poll's reads per device into sum commands capped at sumReadMaxItems,
per-item ADS errors mapped per tag, falls back to individual reads when the target refuses the
command. Diagnostics (#314): ADS state, app name, online-change count, task cycle/exec/jitter via
IDriverDiagnostics. Re-implemented against the current raw-byte read path (stranded auto/driver-gaps
commits predate it). Sum-write not ported. Unit tests only; live gate pending a route.

Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe
This commit is contained in:
Joseph Doherty
2026-10-08 19:18:42 -04:00
parent 8801631739
commit af19db4ed1
15 changed files with 1055 additions and 48 deletions
+39 -1
View File
@@ -185,9 +185,47 @@ notifications; `DInt` over a `STRING(80)` → `BadTypeMismatch` in both paths wi
the rest of the subscription Good. No PLC value held a genuine non-ASCII string
to exercise Windows-1252 live — that rule is unit-tested only.
## Sum-read and diagnostics (Gitea #645)
Two items ported from the stranded `auto/driver-gaps` branch (#310, #314), re-implemented against the
current raw-byte read path rather than cherry-picked (the branch predates the type guard, the string codec
and the array codec). Unit-tested against the fake client only; the live gate is read-only and pending a
route (see `docs/v3/twincat-backlog.md`).
### Sum-read (opt-in)
`useSumRead: true` (default **off**) batches a poll's reads for one device into ADS sum-read commands
(`IndexGroup 0xF080`) of at most `sumReadMaxItems` symbols (default 200) instead of one round-trip per tag.
TC2 CE 2.11 support for the sum command is unverified, hence opt-in.
- The client plans each item exactly as a single read does — symbol from the Beckhoff symbol cache, declared
type checked by `TwinCATTypeGuard` — and then reads the raw bytes at the symbol's index group / offset in
one command, decoding with the same `TwinCATArrayCodec` (a scalar is a one-element array). A type-mismatched
item gets `BadTypeMismatch` without joining the batch; a bit-indexed BOOL and a handle-addressed symbol
(`0xF005`) are read individually inside the call.
- Per-item ADS error codes map to that tag only (`MapAdsError`); the overall code is the command's.
- **Fallback.** If the target refuses the command as a whole (overall ADS 1792–1798: service / group /
offset / size not supported) the client throws `TwinCATSumReadRefusedException`; the driver logs once,
marks the device `SumReadUnsupported`, and re-reads that batch with individual reads. The flag is sticky
until the driver is re-initialised. A comms-level failure is **not** a refusal: that chunk goes
`BadCommunicationError` and the next poll tries the sum command again.
- A one-item chunk is just a single read. Sum-**write** is not implemented (writes stay per-tag).
### `/hosts` diagnostics (`IDriverDiagnostics`)
The driver implements the optional `IDriverDiagnostics` bag (the S7 `NegotiatedPduSize` precedent, #640),
so these ride the health snapshot to `/hosts` — deliberately not synthetic raw tags. Sampled once per
healthy probe tick: ADS device state (`ReadState`), and `TwinCAT_SystemInfoVarList` `_AppInfo.AppName`,
`_AppInfo.OnlineChangeCnt`, `_TaskInfo[1].CycleTime`, `_TaskInfo[1].LastExecTime` (100 ns ticks).
Keys: `TwinCAT.AdsState`, `.AppName`, `.OnlineChangeCnt`, `.CycleTimeMs`, `.LastExecTimeMs`, `.JitterMs`
(last exec − cycle; positive = the task overran). Several devices prefix `TwinCAT.<DeviceName or host>.`;
the host caps the bag at 16 entries. Times are rounded to 0.1 ms because the bag's digest is in the
publish fingerprint. Each symbol is best-effort: a runtime that does not export one (older TC2) keeps the
others, and a symbol answering "not found" is not re-asked until the client is rebuilt.
## Capability surface
`TwinCATDriver : IDriver, IReadable, IWritable, ITagDiscovery, ISubscribable, IHostConnectivityProbe, IPerCallHostResolver, IRediscoverable`
`TwinCATDriver : IDriver, IReadable, IWritable, ITagDiscovery, ISubscribable, IHostConnectivityProbe, IPerCallHostResolver, IRediscoverable, ISkippedTagReporter, IDriverDiagnostics`
(`src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/TwinCATDriver.cs`).
| Capability | Path | Notes |