fix(twincat): size strings by the resolved type and refuse VAR_IN_OUT references (live TC2 gate)
Found by the read-only live gate against the TwinCAT 2.11 Elma cleaners Z33856 / Z33733: - The Beckhoff library reports a TC2 dotted MEMBER symbol's ByteSize as if the PLC's byte count were a bit count (STRING(80) -> 11, INT -> 1, UDINT -> 1) while DataType.ByteSize is right (81/2/4, raw SYM_INFOBYNAMEEX says 81). The previous commit's typeof(byte[]) read sliced by the symbol size, so .OPC_MACHINEDATA.PROCESSSTATUS read "ready for o" at Good; the notification width check would also have refused every numeric member. The shape now takes the resolved type's size, and string reads go by index group/offset (or a fresh handle for 0xF005) at that width. - P_INITINPUT_ACTION.SLOTID is "STRING(20) (VAR_IN_OUT)" - a 4-byte reference - but resolves to a plain STRING(20); a String tag read 21 bytes at the pointer as text at Good. The symbol's own VAR_IN_OUT marker now classifies it NonScalar -> BadTypeMismatch.
This commit is contained in:
@@ -135,6 +135,32 @@ found against a real TwinCAT 2 PLC:
|
||||
registers, and the probe-tick retry re-checks it after a PLC program change.
|
||||
Reads go through the Beckhoff symbol cache, which converts numeric values by
|
||||
the PLC's own type, so only the string-kind rule applies there.
|
||||
- **Sizes come from the resolved data type, not the symbol.** On a TwinCAT 2
|
||||
target the Beckhoff library reports a dotted *member* symbol's `ByteSize` as if
|
||||
the PLC's byte count were a bit count (`.OPC_MACHINEDATA.PROCESSSTATUS`
|
||||
`STRING(80)` → 11 B, an `INT` member → 1, a `UDINT` → 1) while its resolved
|
||||
`DataType.ByteSize` is correct (81 / 2 / 4, matching raw `SYM_INFOBYNAMEEX`).
|
||||
String reads therefore address the symbol's index group/offset explicitly at
|
||||
the type's width — sizing them by the symbol truncated `"ready for operation"`
|
||||
to `"ready for o"` at Good.
|
||||
- **A `VAR_IN_OUT` member is a reference, not a value.** TC2 names it
|
||||
`STRING(20) (VAR_IN_OUT)` (4 bytes) but the library resolves its type to the
|
||||
plain `STRING(20)`; the symbol's own name wins and such a tag is refused
|
||||
(`BadTypeMismatch`) instead of publishing the memory at the pointer as text.
|
||||
|
||||
### Live validation (2026-10-07, TwinCAT 2.11 Elma cleaners)
|
||||
|
||||
Read-only, against Z33856 (`10.201.45.236.1.1:801`) and Z33733
|
||||
(`5.25.53.46.1.1:801`) over the VPN, through an in-process
|
||||
`Beckhoff.TwinCAT.Ads.TcpRouter` in a scratch harness: ReadState RUN; browse
|
||||
discovered 45,083 / 42,666 variables incl. the `INT16`/`UINT16` globals
|
||||
(`.ACTUALOPERATIONMODE`, `.ADSSTATE_RUN`) and 3,663 / 3,564 leading-dot names, no
|
||||
empty names; `.ADSSTATE_RUN` = 5 with bits `.0`/`.1`/`.2` = true/false/true;
|
||||
work-order and part-number strings whose PLC buffers carry a stale tail after
|
||||
the NUL (`68261005\0` + `01`) read as `68261005` through both poll and native
|
||||
notifications; `DInt` over a `STRING(80)` → `BadTypeMismatch` in both paths with
|
||||
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.
|
||||
|
||||
## Capability surface
|
||||
|
||||
|
||||
Reference in New Issue
Block a user