fix(twincat): #645 live gate — sum-read never worked on hardware; TC2 diagnostics fallback
Read-only live gate on Elma presses Z35474 (TC3 3.1.4024) and Z34834 (TC2 2.11): - Sum-read: every chunk came back BadCommunicationError. Beckhoff's SumRead(IList<IgIoSumReadEntity>) ctor casts to IList<SumDataEntity>, which throws InvalidCastException for a List<> (only an array survives via covariance). The fake-client tests never built a real SumRead. New AdsTwinCATClient.CreateSumRead passes an array; TwinCATSumReadConstructionTests pins it (red on the List form) plus a falsifiability control on the library. After the fix: 59 tags, status identical everywhere, values identical on every non-moving tag, ~0.35-0.66 s vs ~2.7 s per poll; TC2 CE 2.11 answers sum reads. - An unexpected sum chunk failure now logs one Warning per device (it was invisible: the health message was overwritten by the next good read). - Diagnostics: TC2 has no TwinCAT_SystemInfoVarList; fall back to .SYSTEMINFO / .SYSTEMTASKINFOARR[1] once the TC3 name answers not-found (live: all six keys). - #612 browse: Flat verified on TC3 (10,770 leaves; VirtualTree 1,459 strict subset) — comment and docs updated, no load-mode option needed. Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe
This commit is contained in:
+22
-13
@@ -189,8 +189,14 @@ to exercise Windows-1252 live — that rule is unit-tested only.
|
||||
|
||||
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`).
|
||||
and the array codec). Live-gated read-only on 2026-10-08 against Z35474 (TC3) and Z34834 (TC2 2.11) — see
|
||||
`docs/v3/twincat-backlog.md` items 6–8 for the evidence.
|
||||
|
||||
⚠️ **Beckhoff's `SumRead` must be handed an ARRAY of entities.** Its `IList<IgIoSumReadEntity>` overload casts to
|
||||
`IList<SumDataEntity>` internally, which only an array survives (covariance); a `List<>` throws
|
||||
`InvalidCastException` before anything is sent. The shipped #645 code passed a `List<>`, so on real hardware every
|
||||
sum chunk came back `BadCommunicationError` while all fake-client tests passed. `AdsTwinCATClient.CreateSumRead`
|
||||
owns the construction; an unexpected chunk failure now logs one Warning per device.
|
||||
|
||||
### Sum-read (opt-in)
|
||||
|
||||
@@ -229,8 +235,12 @@ ReadState. One device: flat keys `TwinCAT.AdsState`, `.AppName`, `.OnlineChangeC
|
||||
jitter). Several devices: one line per device, `TwinCAT.<DeviceName or host>` =
|
||||
`Run; Plc30 App; online-changes 7; cycle 10.0 ms; exec 2.5 ms; headroom 7.5 ms`, so the host's 16-entry cap
|
||||
covers 16 devices. Times round to 0.1 ms (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 a new client is installed (reconnect).
|
||||
best-effort: a runtime that does not export one keeps the others, and a symbol answering "not
|
||||
found" is not re-asked until a new client is installed (reconnect). **TwinCAT 2** has no
|
||||
`TwinCAT_SystemInfoVarList`; once a TC3 name answers "not found" the driver reads the TC2 globals instead —
|
||||
`.SYSTEMINFO.PROJECTNAME` (AppName), `.SYSTEMINFO.ONLINECHANGECOUNT` (UINT), `.SYSTEMTASKINFOARR[1].CYCLETIME` /
|
||||
`.LASTEXECTIME` (same 100 ns units). Live on TC2 2.11: 8 reads on the first tick, 4 after; a TC3 target never
|
||||
reads the TC2 names.
|
||||
|
||||
## Capability surface
|
||||
|
||||
@@ -448,16 +458,15 @@ Discovered struct/UDT/FB member **writes** are **deferred** in this release. Sca
|
||||
members can be written when pre-declared with `Writable: true`; the controller-browse expansion
|
||||
path does not yet wire the write channel.
|
||||
|
||||
### Live caveat — Flat-mode vs VirtualTree-mode browse
|
||||
### Flat-mode vs VirtualTree-mode browse — resolved, Flat stays (#612)
|
||||
|
||||
The ADS client's `BrowseSymbolsAsync` may return symbols in **Flat mode** (a flat list of all
|
||||
instance paths, with no `SubSymbols` populated) on some TC3 runtime configurations, in which
|
||||
case the recursive struct expansion produces no sub-symbols and the walk yields only top-level
|
||||
symbols. If a live TC3 browse does not populate `SubSymbols` on struct-typed symbols, the
|
||||
alternative is **VirtualTree mode** (which returns a hierarchical symbol tree with `SubSymbols`
|
||||
populated). VirtualTree-mode browse is an unverified follow-up; if Flat-mode struct expansion
|
||||
produces empty `Discovered/` sub-folders for struct symbols, switch to VirtualTree mode via the
|
||||
driver configuration.
|
||||
The driver loads symbols with `SymbolsLoadMode.Flat`. The worry was that Flat might leave `SubSymbols`
|
||||
empty on some TC3 runtimes and drop every struct member. Live on the only TC3 press, Z35474 (TwinCAT
|
||||
3.1.4024, 2026-10-08, read-only): Flat returned 3,384 roots, every one of the 573 struct roots carried its
|
||||
`SubSymbols`, and the expander produced 10,770 leaves (9,921 of them struct members; `DiscoverAsync` 10,628
|
||||
variables). VirtualTree returned 1,027 roots and 1,459 leaves — a strict subset (0 tree-only leaves) that
|
||||
misses array-of-struct element members such as `.L_Axis[10].IN._AT.DriveStatusWord`. There is no load-mode
|
||||
option and none is needed. TC2 Flat was already proven (45,083 / 42,666 variables, 2026-10-07).
|
||||
|
||||
## Further reading
|
||||
|
||||
|
||||
Reference in New Issue
Block a user