5.1 KiB
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:
- Install-path coupling — the
.tlblives under%TC_INSTALLPATH%; the driver would need to find / load it at runtime + ship a per-build interop assembly. - Bitness lock-in — TcCOM is x86; the driver builds AnyCPU.
- 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=falseso 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
ITwinCATAlarmGateinterface — driver-internal seam.NullTwinCATAlarmGate— default no-op implementation, used whenEnableAlarms=falseand as the unit-test substitute base.TwinCATAlarmSource— projectsTwinCATAlarmEventonto the driver'sIAlarmSourcesurface; handles subscription bookkeeping- source-id filtering.
TwinCATDriverdeclaresIAlarmSource; 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
- 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.hstruct definitions. - Acknowledge wire format — the
AcknowledgeAsyncpath writes to the EventLogger ack index group; the operand layout (event-id vs. condition-id mapping) is best-effort in PR 5.1. - 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.
- Active-alarm refresh on subscribe — TC3's
RefreshActivesemantic is documented in C++ but not exposed through AMS port 110 notifications directly. The follow-up PR should investigate whether a separateReadagainst 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.