Captures uncommitted work that lived in the working tree on
v2-mxgw-integration but was orthogonal to the migration. Stashed
during the v2-mxgw merge to master (2026-04-30) and replanted here on
a feature branch off master so it's git-visible rather than living in
the stash list.
Two distinct buckets:
1. Tracked fixture/config refinements (10 files, ~36 lines):
- scripts/e2e/test-opcuaclient.ps1
- src/ZB.MOM.WW.OtOpcUa.Admin/appsettings.json
- 5 docker-compose.yml under tests/.../IntegrationTests/Docker/
(AbCip, Modbus, OpcUaClient, S7)
- 4 fixture .cs files (AbServerFixture, ModbusSimulatorFixture,
OpcPlcFixture, Snap7ServerFixture)
2. Untracked driver-gaps queue artifacts (~8000 lines):
- docs/plans/{abcip,ablegacy,focas,opcuaclient,s7,twincat}-plan.md
— per-driver gap plans
- docs/featuregaps.md — cross-cutting analysis
- docs/v2/focas-deployment.md, docs/v2/implementation/focas-simulator-plan.md
- followup.md — auto/driver-gaps queue follow-ups
- scripts/queue/ — PR-queue automation tooling (12 files including
pr-manifest.yaml at 1473 lines)
This commit is a snapshot for recoverability — review and split into
focused PRs (or discard) before merging anywhere downstream.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
321 lines
13 KiB
YAML
321 lines
13 KiB
YAML
- id: twincat-1.1
|
|
driver: twincat
|
|
phase: 1
|
|
plan_pr_id: "1.1"
|
|
title: "TwinCAT — Int64 fidelity for LINT/ULINT"
|
|
plan_anchor: "docs/plans/twincat-plan.md"
|
|
summary: |
|
|
Map LInt/ULInt to DriverDataType.Int64 instead of silently truncating to Int32.
|
|
The TwinCATDataType.cs:40 truncation comment "matches Int64 gap" is removed and
|
|
MapToClrType already returns long/ulong, so the wire-level read returns the
|
|
correct boxed types. May add Int64 to Core.Abstractions DriverDataType enum if
|
|
missing. Closes a long-standing fixture caveat noted in the test suite.
|
|
files:
|
|
- "src/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/TwinCATDataType.cs"
|
|
- "src/ZB.MOM.WW.OtOpcUa.Core.Abstractions/DriverDataType.cs"
|
|
docs:
|
|
- "docs/Driver.TwinCAT.Cli.md"
|
|
- "docs/drivers/TwinCAT-Test-Fixture.md"
|
|
fixture:
|
|
- "tests/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.IntegrationTests/TwinCatProject/PLC/GVLs/GVL_Primitives.TcGVL"
|
|
- "tests/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.IntegrationTests/TwinCatProject/README.md"
|
|
e2e: []
|
|
effort: S
|
|
deps: []
|
|
cross_driver: false
|
|
notes: "Hardware-gated via TWINCAT_TARGET_NETID; no e2e change to test-twincat.ps1."
|
|
|
|
- id: twincat-1.2
|
|
driver: twincat
|
|
phase: 1
|
|
plan_pr_id: "1.2"
|
|
title: "TwinCAT — TIME/DATE/DT/TOD as native UA types"
|
|
plan_anchor: "docs/plans/twincat-plan.md"
|
|
summary: |
|
|
Stop marshalling IEC TIME/DATE/DT/TOD as raw UDINT and convert to native UA
|
|
Duration/DateTime types via post-processing in ReadValueAsync, ConvertForWrite,
|
|
and OnAdsNotificationEx. May expose missing Duration in DriverDataType. CLI
|
|
syntax updates so users write ISO-8601 / IEC literals instead of numeric raw
|
|
values.
|
|
files:
|
|
- "src/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/TwinCATDataType.cs"
|
|
- "src/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/AdsTwinCATClient.cs"
|
|
docs:
|
|
- "docs/Driver.TwinCAT.Cli.md"
|
|
fixture:
|
|
- "tests/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.IntegrationTests/TwinCatProject/PLC/GVLs/GVL_Primitives.TcGVL"
|
|
- "tests/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.IntegrationTests/TwinCatProject/README.md"
|
|
e2e: []
|
|
effort: M
|
|
deps: []
|
|
cross_driver: false
|
|
notes: "Hardware-gated via TWINCAT_TARGET_NETID. May add Duration to DriverDataType enum."
|
|
|
|
- id: twincat-1.3
|
|
driver: twincat
|
|
phase: 1
|
|
plan_pr_id: "1.3"
|
|
title: "TwinCAT — Bit-indexed BOOL writes (read-modify-write)"
|
|
plan_anchor: "docs/plans/twincat-plan.md"
|
|
summary: |
|
|
Replace the NotSupportedException at AdsTwinCATClient.cs:99 with read-modify-write
|
|
on the parent word, serializing concurrent bit writes to the same parent via a
|
|
keyed SemaphoreSlim. Closes referenced task #181. CLI gains an example and the
|
|
fixture caveat in the bugs-caught list updates to note writes now work.
|
|
files:
|
|
- "src/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/AdsTwinCATClient.cs"
|
|
docs:
|
|
- "docs/Driver.TwinCAT.Cli.md"
|
|
- "docs/drivers/TwinCAT-Test-Fixture.md"
|
|
fixture: []
|
|
e2e: []
|
|
effort: S
|
|
deps: []
|
|
cross_driver: false
|
|
notes: "Reuses GVL_Primitives.vWord (0xBEEF) — no fixture schema change."
|
|
|
|
- id: twincat-1.4
|
|
driver: twincat
|
|
phase: 1
|
|
plan_pr_id: "1.4"
|
|
title: "TwinCAT — Multi-dim and whole-array reads"
|
|
plan_anchor: "docs/plans/twincat-plan.md"
|
|
summary: |
|
|
Expand ReadValueAsync/WriteValueAsync to handle whole-array reads in a single
|
|
AdsClient call rather than element-by-element. Surface IsArray + ArrayDimensions
|
|
on TwinCATTagDefinition and through DriverAttributeInfo from DiscoverAsync. Sets
|
|
up the array-shape plumbing the rest of the driver needs.
|
|
files:
|
|
- "src/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/AdsTwinCATClient.cs"
|
|
- "src/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/TwinCATDriver.cs"
|
|
- "src/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/TwinCATDriverOptions.cs"
|
|
docs:
|
|
- "docs/Driver.TwinCAT.Cli.md"
|
|
- "docs/drivers/TwinCAT-Test-Fixture.md"
|
|
fixture:
|
|
- "tests/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.IntegrationTests/TwinCatProject/PLC/GVLs/GVL_Arrays.TcGVL"
|
|
- "tests/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.IntegrationTests/TwinCatProject/README.md"
|
|
e2e: []
|
|
effort: M
|
|
deps: []
|
|
cross_driver: false
|
|
notes: "Hardware-gated via TWINCAT_TARGET_NETID. New 5x5 aReal2D seed with deterministic pattern."
|
|
|
|
- id: twincat-1.5
|
|
driver: twincat
|
|
phase: 1
|
|
plan_pr_id: "1.5"
|
|
title: "TwinCAT — ENUM and ALIAS at discovery"
|
|
plan_anchor: "docs/plans/twincat-plan.md"
|
|
summary: |
|
|
MapSymbolTypeName currently returns null for non-atomic types, dropping ENUM and
|
|
ALIAS symbols silently. Switch to inspecting symbol.DataType + Category from
|
|
TwinCAT.TypeSystem so DataTypeCategory.Enum walks EnumValues and Alias resolves
|
|
to base atomic recursively. Surface enum members for later EnumStrings rendering.
|
|
POINTER/REFERENCE/INTERFACE/UNION explicitly out of scope.
|
|
files:
|
|
- "src/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/AdsTwinCATClient.cs"
|
|
docs:
|
|
- "docs/Driver.TwinCAT.Cli.md"
|
|
- "docs/drivers/TwinCAT-Test-Fixture.md"
|
|
fixture:
|
|
- "tests/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.IntegrationTests/TwinCatProject/README.md"
|
|
e2e: []
|
|
effort: M
|
|
deps: []
|
|
cross_driver: false
|
|
notes: "Reuses existing GVL_Enums + DUTs; only README integration-test contract entry added."
|
|
|
|
- id: twincat-2.1
|
|
driver: twincat
|
|
phase: 2
|
|
plan_pr_id: "2.1"
|
|
title: "TwinCAT — ADS Sum-read / Sum-write"
|
|
plan_anchor: "docs/plans/twincat-plan.md"
|
|
summary: |
|
|
Replace per-tag ReadValueAsync loops with Beckhoff's ADS Sum commands
|
|
(IndexGroup 0xF080-0xF084) via SumSymbolRead/SumSymbolWrite to batch N
|
|
reads/writes per AMS request. Bucket fullReferences by DeviceHostAddress and
|
|
expose a new ReadValuesAsync surface on ITwinCATClient. Targets ~10x throughput
|
|
on multi-thousand-tag scans; perf-tier test gated behind TWINCAT_PERF=1.
|
|
files:
|
|
- "src/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/AdsTwinCATClient.cs"
|
|
- "src/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/TwinCATDriver.cs"
|
|
- "src/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/ITwinCATClient.cs"
|
|
docs:
|
|
- "docs/v3/twincat-backlog.md"
|
|
- "docs/drivers/TwinCAT-Test-Fixture.md"
|
|
fixture:
|
|
- "tests/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.IntegrationTests/TwinCatProject/PLC/GVLs/GVL_Perf.TcGVL"
|
|
- "tests/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.IntegrationTests/TwinCatProject/README.md"
|
|
e2e: []
|
|
effort: L
|
|
deps: []
|
|
cross_driver: false
|
|
notes: "Perf test gated behind TWINCAT_PERF=1 plus TWINCAT_TARGET_NETID; new FB_PerfChurn POU."
|
|
|
|
- id: twincat-2.2
|
|
driver: twincat
|
|
phase: 2
|
|
plan_pr_id: "2.2"
|
|
title: "TwinCAT — Handle-based access with caching"
|
|
plan_anchor: "docs/plans/twincat-plan.md"
|
|
summary: |
|
|
Cache CreateVariableHandleAsync results so per-read overhead drops to
|
|
read-by-handle (4-byte index vs N-byte symbol path). On
|
|
DeviceSymbolVersionInvalid (0x710) evict and retry once. Clear cache on
|
|
AdsClient reconnect until the symbol-version listener (PR 2.3) ships. Dispose
|
|
path calls DeleteVariableHandleAsync for cached handles.
|
|
files:
|
|
- "src/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/AdsTwinCATClient.cs"
|
|
docs:
|
|
- "docs/Driver.TwinCAT.Cli.md"
|
|
- "docs/drivers/TwinCAT-Test-Fixture.md"
|
|
fixture: []
|
|
e2e: []
|
|
effort: M
|
|
deps: []
|
|
cross_driver: false
|
|
notes: "Combines with PR 2.1 for sum-read-by-handle. Reuses GVL_Perf.aTags."
|
|
|
|
- id: twincat-2.3
|
|
driver: twincat
|
|
phase: 2
|
|
plan_pr_id: "2.3"
|
|
title: "TwinCAT — Symbol-version invalidation listener"
|
|
plan_anchor: "docs/plans/twincat-plan.md"
|
|
summary: |
|
|
Register an AddDeviceNotificationAsync on the symbol-version index group
|
|
(AdsReservedIndexGroup.SymbolVersion 0xF008) so the handle cache from PR 2.2
|
|
is wiped on online-change bumps. Initial integration test gated as
|
|
requires-manual-online-change until automation lands. Resolves open question
|
|
(c) confirming the v6 enum constant.
|
|
files:
|
|
- "src/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/AdsTwinCATClient.cs"
|
|
docs:
|
|
- "docs/drivers/TwinCAT-Test-Fixture.md"
|
|
fixture:
|
|
- "tests/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.IntegrationTests/TwinCatProject/README.md"
|
|
e2e: []
|
|
effort: M
|
|
deps: ["twincat-2.2"]
|
|
cross_driver: false
|
|
notes: "Hardware-gated via TWINCAT_TARGET_NETID; manual online-change drill documented in README."
|
|
|
|
- id: twincat-3.1
|
|
driver: twincat
|
|
phase: 3
|
|
plan_pr_id: "3.1"
|
|
title: "TwinCAT — Per-tag MaxDelay tuning"
|
|
plan_anchor: "docs/plans/twincat-plan.md"
|
|
summary: |
|
|
Surface NotificationSettings MaxDelay as a per-tag option (default 0 to
|
|
preserve current behavior). Plumb int? MaxDelayMs through TwinCATTagDefinition,
|
|
SubscribeAsync, and AddNotificationAsync. Coalesces high-frequency PLC signals
|
|
so the OPC UA subscription queue stops flooding under bursty change rates.
|
|
files:
|
|
- "src/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/TwinCATDriverOptions.cs"
|
|
- "src/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/TwinCATDriver.cs"
|
|
- "src/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/AdsTwinCATClient.cs"
|
|
docs:
|
|
- "docs/Driver.TwinCAT.Cli.md"
|
|
- "docs/drivers/TwinCAT-Test-Fixture.md"
|
|
fixture:
|
|
- "tests/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.IntegrationTests/TwinCatProject/README.md"
|
|
e2e: []
|
|
effort: S
|
|
deps: []
|
|
cross_driver: false
|
|
notes: "Reuses GVL_Fixture.nCounter as 100 Hz driver. Hardware-gated via TWINCAT_TARGET_NETID."
|
|
|
|
- id: twincat-3.2
|
|
driver: twincat
|
|
phase: 3
|
|
plan_pr_id: "3.2"
|
|
title: "TwinCAT — Cycle-time / jitter / PLC-state diagnostics"
|
|
plan_anchor: "docs/plans/twincat-plan.md"
|
|
summary: |
|
|
Augment the probe loop to read _AppInfo.OnlineChangeCnt/AppName and
|
|
_TaskInfo[1].CycleTime/LastExecTime, surface as TwinCATDeviceDiagnostics on
|
|
DeviceState, and emit through IDriverDiagnostics (cross-driver surface from
|
|
Modbus task #154). Read system symbols directly without going through the user
|
|
browse filter.
|
|
files:
|
|
- "src/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/TwinCATDriver.cs"
|
|
- "src/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/TwinCATSystemSymbolFilter.cs"
|
|
docs:
|
|
- "docs/drivers/TwinCAT-Test-Fixture.md"
|
|
- "docs/Driver.TwinCAT.Cli.md"
|
|
- "docs/v3/twincat-backlog.md"
|
|
fixture:
|
|
- "tests/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.IntegrationTests/TwinCatProject/README.md"
|
|
e2e: []
|
|
effort: M
|
|
deps: []
|
|
cross_driver: true
|
|
notes: "Reuses IDriverDiagnostics from Modbus task #154. Hardware-gated via TWINCAT_TARGET_NETID."
|
|
|
|
- id: twincat-4.1
|
|
driver: twincat
|
|
phase: 4
|
|
plan_pr_id: "4.1"
|
|
title: "TwinCAT — Nested UDT browse via online type walker"
|
|
plan_anchor: "docs/plans/twincat-plan.md"
|
|
summary: |
|
|
Largest single piece of work. Recurse BrowseSymbolsAsync into IStructType.SubItems
|
|
yielding one TwinCATDiscoveredSymbol per leaf with dotted instance paths. Expand
|
|
arrays-of-structs up to a configurable bound (default 1024). Add a pure
|
|
TwinCATTypeWalker helper. Folds recursed structure into Discovered/ folder tree.
|
|
Online runtime path only — TMC offline parsing deferred per open question (a).
|
|
files:
|
|
- "src/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/AdsTwinCATClient.cs"
|
|
- "src/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/TwinCATDriver.cs"
|
|
- "src/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/TwinCATTypeWalker.cs"
|
|
docs:
|
|
- "docs/Driver.TwinCAT.Cli.md"
|
|
- "docs/drivers/TwinCAT-Test-Fixture.md"
|
|
- "docs/v3/twincat-backlog.md"
|
|
fixture:
|
|
- "tests/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.IntegrationTests/TwinCatProject/PLC/DUTs/ST_NestedFlags.TcDUT"
|
|
- "tests/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.IntegrationTests/TwinCatProject/PLC/DUTs/ST_RecursiveCap.TcDUT"
|
|
- "tests/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.IntegrationTests/TwinCatProject/PLC/DUTs/ST_AlarmRecord.TcDUT"
|
|
- "tests/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.IntegrationTests/TwinCatProject/README.md"
|
|
e2e: []
|
|
effort: L
|
|
deps: ["twincat-1.5"]
|
|
cross_driver: false
|
|
notes: "Hardware-gated via TWINCAT_TARGET_NETID. PR 1.4 helpful but not blocking."
|
|
|
|
- id: twincat-5.1
|
|
driver: twincat
|
|
phase: 5
|
|
plan_pr_id: "5.1"
|
|
title: "TwinCAT — IAlarmSource via TC3 EventLogger"
|
|
plan_anchor: "docs/plans/twincat-plan.md"
|
|
summary: |
|
|
Implement IAlarmSource over TcEventLogger on AMS port 110 so PLC alarms
|
|
surface as OPC UA AC events. Begins with a one-day spike (open question (b))
|
|
documented in docs/v3/twincat-eventlogger-spike.md to determine if a managed
|
|
wrapper exists or if we hit AMS port 110 directly via a secondary AdsClient
|
|
+ AddDeviceNotificationAsync on the alarm-list index group. Gated by new
|
|
EnableAlarms option (default false).
|
|
files:
|
|
- "src/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/TwinCATAlarmSource.cs"
|
|
- "src/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/TwinCATDriver.cs"
|
|
- "src/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/TwinCATDriverOptions.cs"
|
|
docs:
|
|
- "docs/drivers/TwinCAT.md"
|
|
- "docs/v3/twincat-eventlogger-spike.md"
|
|
- "docs/Driver.TwinCAT.Cli.md"
|
|
- "docs/drivers/TwinCAT-Test-Fixture.md"
|
|
fixture:
|
|
- "tests/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.IntegrationTests/TwinCatProject/PLC/POUs/FB_AlarmHarness.TcPOU"
|
|
- "tests/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.IntegrationTests/TwinCatProject/PLC/GVLs/GVL_Alarms.TcGVL"
|
|
- "tests/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.IntegrationTests/TwinCatProject/README.md"
|
|
e2e:
|
|
- "scripts/e2e/test-twincat.ps1"
|
|
effort: L
|
|
deps: []
|
|
cross_driver: false
|
|
notes: "Hardware-gated via TWINCAT_TARGET_NETID. Spike-first; e2e Test-AlarmRoundTrip likely deferred to follow-up."
|