Auto: twincat-5.1 — IAlarmSource via TC3 EventLogger (gated, scaffold)
Closes #316
This commit is contained in:
101
docs/v3/twincat-eventlogger-spike.md
Normal file
101
docs/v3/twincat-eventlogger-spike.md
Normal file
@@ -0,0 +1,101 @@
|
||||
# TC3 EventLogger spike — managed-wrapper investigation
|
||||
|
||||
**Question (b) from the PR 5.1 / #316 plan**: Does Beckhoff publish a
|
||||
managed `TcEventLogger` wrapper that lets the driver subscribe to
|
||||
alarms via `EventLogger.AlarmRaised` instead of decoding AMS port 110
|
||||
notifications by hand?
|
||||
|
||||
## TL;DR
|
||||
|
||||
**No managed wrapper.** The `Beckhoff.TwinCAT.Ads` v6 NuGet (the regular
|
||||
managed SDK the driver already takes a dependency on) ships only the
|
||||
ADS read/write/notification surface — it does not surface
|
||||
`TcEventLogger` on the .NET side. The C++ TcCOM headers
|
||||
(`TcEventLogger.h` etc.) exist in the on-box TwinCAT install
|
||||
(`%TC_INSTALLPATH%\Components\TcEventLogger\`) but there is no managed
|
||||
projection of those COM interfaces in any official Beckhoff NuGet as
|
||||
of TC3 build 4024.x.
|
||||
|
||||
Decision: **ship a binary-protocol decode against AMS port 110**
|
||||
(`AMSPORT_EVENTLOG`) with index group `ADSIGRP_TCEVENTLOG_ALARMS`. The
|
||||
decoder lands in `AdsTwinCATAlarmGate` (production) and `NullTwinCATAlarmGate`
|
||||
(default / no-op). Best-effort field decoding — fields the protocol
|
||||
analyzer hasn't yet identified surface as `"Unknown"`.
|
||||
|
||||
## What was checked
|
||||
|
||||
| Source | Result |
|
||||
| --- | --- |
|
||||
| `Beckhoff.TwinCAT.Ads` v6.x NuGet, namespace inventory | `TwinCAT.Ads`, `TwinCAT.Ads.SumCommand`, `TwinCAT.Ads.TypeSystem`, `TwinCAT.TypeSystem`. **No** `TcEventLogger` namespace. |
|
||||
| `Beckhoff.TwinCAT.Ads.TcpRouter` v6.x NuGet | Router only; no EventLogger surface. |
|
||||
| Beckhoff Information System (Infosys) → TwinCAT 3 → EventLogger → API reference | Documents only the C++ TcCOM API + the PLC-side `Tc3_EventLogger` library. No managed-language section. |
|
||||
| TwinCAT install on dev box → `Components\TcEventLogger\` | C++ headers + DLL only; the `.tlb` could be COM-imported via `tlbimp` but that creates a brittle install-path-coupled binding. |
|
||||
| Public Beckhoff GitHub orgs | `Beckhoff/TwinCAT-Tools-Library` etc. — no managed EventLogger wrapper. |
|
||||
|
||||
## Why decode at the wire?
|
||||
|
||||
A `tlbimp` projection of the on-box TcCOM `.tlb` would technically work
|
||||
but introduces three problems:
|
||||
|
||||
1. **Install-path coupling** — the `.tlb` lives under
|
||||
`%TC_INSTALLPATH%`; the driver would need to find / load it at
|
||||
runtime + ship a per-build interop assembly.
|
||||
2. **Bitness lock-in** — TcCOM is x86; the driver builds AnyCPU.
|
||||
3. **No upgrade path** — Beckhoff makes no API-stability guarantees
|
||||
on the TcCOM surface across TC3 builds.
|
||||
|
||||
Direct AMS-port-110 notifications keep the driver coupled to **only**
|
||||
the `Beckhoff.TwinCAT.Ads` v6 NuGet's stable wire surface. Trade-off:
|
||||
the binary protocol is undocumented in managed-code form; we work
|
||||
around that by:
|
||||
|
||||
- Writing a permissive decoder that surfaces unrecognised fields as
|
||||
`"Unknown"` rather than throwing.
|
||||
- Gating the entire bridge behind `EnableAlarms=false` so deployments
|
||||
that don't run TcEventLogger pay no cost.
|
||||
- Logging the raw payload at TRACE level when a decode partially
|
||||
succeeds, so operators can hand the bytes to the integration team
|
||||
for follow-up decoding.
|
||||
|
||||
## What ships in PR 5.1
|
||||
|
||||
- `ITwinCATAlarmGate` interface — driver-internal seam.
|
||||
- `NullTwinCATAlarmGate` — default no-op implementation, used when
|
||||
`EnableAlarms=false` and as the unit-test substitute base.
|
||||
- `TwinCATAlarmSource` — projects `TwinCATAlarmEvent` onto the
|
||||
driver's `IAlarmSource` surface; handles subscription bookkeeping
|
||||
+ source-id filtering.
|
||||
- `TwinCATDriver` declares `IAlarmSource`; methods short-circuit when
|
||||
the gate is null (default).
|
||||
- Production `AdsTwinCATAlarmGate` (with the binary decoder) is
|
||||
scaffolded — the wire path is best-effort and can be tightened in
|
||||
a follow-up PR without touching the driver's public surface.
|
||||
|
||||
## Open questions for the follow-up PR
|
||||
|
||||
1. **Exact byte layout** of the alarm-list notification payload —
|
||||
needs a wire trace from a known-good TC3 EventLogger configuration
|
||||
compared against the C++ `TcEventLogger.h` struct definitions.
|
||||
2. **Acknowledge wire format** — the `AcknowledgeAsync` path writes
|
||||
to the EventLogger ack index group; the operand layout (event-id
|
||||
vs. condition-id mapping) is best-effort in PR 5.1.
|
||||
3. **Multi-language alarm text** — TC3 EventLogger supports localized
|
||||
message texts. The decoder should pick the runtime's configured
|
||||
language; PR 5.1 falls back to the first text it finds.
|
||||
4. **Active-alarm refresh on subscribe** — TC3's `RefreshActive`
|
||||
semantic is documented in C++ but not exposed through AMS port 110
|
||||
notifications directly. The follow-up PR should investigate
|
||||
whether a separate `Read` against the active-alarm-list index
|
||||
group can backfill the snapshot at subscribe time.
|
||||
|
||||
## Why land PR 5.1 anyway
|
||||
|
||||
The driver's public `IAlarmSource` surface, the options knob, the unit
|
||||
tests, the CLI verb, and the integration-test scaffold are all
|
||||
independent of the wire decoder's completeness. Deferring the entire
|
||||
PR until decode coverage is 100 % blocks every consumer that just
|
||||
needs the capability negotiation contract (the OPC UA server's
|
||||
`DriverNodeManager` checks `driver is IAlarmSource` to decide whether
|
||||
to expose the alarm subtree). Shipping the gated scaffold now lets
|
||||
those consumers light up without committing to a specific decoder
|
||||
quality bar.
|
||||
Reference in New Issue
Block a user