Auto: twincat-3.2 — cycle-time / jitter / PLC-state diagnostics

Closes #314
This commit is contained in:
Joseph Doherty
2026-04-26 01:59:56 -04:00
parent 30e39a752a
commit 24a3cda56a
8 changed files with 642 additions and 1 deletions

View File

@@ -198,6 +198,41 @@ on symbolic paths in PR 2.2 (the bulk path's per-call symbol resolution
is already amortised across N tags; the perf delta vs. handle-batched
bulk is marginal — tracked as a follow-up for the Phase-2 perf sweep).
## Diagnostics
PR 3.2 (#314) augments the probe loop. On every successful tick (post `ReadStateAsync`)
the driver also reads four well-known system symbols off the AMS target and stashes
them on `DeviceState.LastDiagnostics` as a `TwinCATDeviceDiagnostics` record. The same
snapshot is folded into `DriverHealth.Diagnostics` so the cross-driver
`driver-diagnostics` RPC (added for Modbus, task #154) renders TwinCAT cycle-time /
jitter / online-change counters next to its peers without a per-driver special-case.
| Symbol | Type | Diagnostic key | Notes |
| --- | --- | --- | --- |
| `TwinCAT_SystemInfoVarList._AppInfo.AppName` | `STRING(80)` | (record only) | Running PLC project name, e.g. `"Plc1"` |
| `TwinCAT_SystemInfoVarList._AppInfo.OnlineChangeCnt` | `UDINT` | `TwinCAT.OnlineChangeCnt` | Increments on every accepted online change; informational |
| `TwinCAT_SystemInfoVarList._TaskInfo[1].CycleTime` | `UDINT` (100 ns ticks) | `TwinCAT.CycleTimeMs` | Configured task period after `÷10000` ms conversion |
| `TwinCAT_SystemInfoVarList._TaskInfo[1].LastExecTime` | `UDINT` (100 ns ticks) | `TwinCAT.LastExecTimeMs` | Wall-clock duration of the last task tick |
| (computed) | `double` | `TwinCAT.JitterMs` | `LastExecTimeMs - CycleTimeMs`; positive = overrun |
| (computed) | `long` | `TwinCAT.OnlineChangeIncrements` | Cumulative deltas observed since the driver started; only emitted once non-zero |
Each individual read is wrapped in best-effort try/catch. A runtime that doesn't
expose `_TaskInfo[1]` (older TwinCAT 2 builds, some soft-PLC implementations) still
produces a partial snapshot; the missing fields fall back to the previous tick's value
or the type default for the first probe tick. Wholesale failure of all four reads
leaves the previous snapshot in place and the next tick retries.
Single-device deployments produce flat keys (`TwinCAT.CycleTimeMs`); multi-device
deployments prefix with the AMS host address (`TwinCAT.<hostAddress>.CycleTimeMs`)
so the readout is unambiguous when one driver instance owns multiple AMS targets.
Wire-level coverage lives in
`TwinCATDiagnosticsIntegrationTests.Probe_loop_surfaces_cycle_time_and_online_change_count`
(asserts `CycleTimeMs > 0` + `OnlineChangeCnt >= 0` within one probe interval against a
reachable XAR runtime). Unit-level coverage of the dictionary shape, the per-symbol
try/catch, and the multi-device prefixing lives in `TwinCATDeviceDiagnosticsTests`
the `FakeTwinCATClient.SetSystemSymbolValue` helper drives the surface deterministically.
## Follow-up candidates
1. **XAR VM live-population** — scaffolding is in place (this PR); the