# TwinCAT driver — operator guide Beckhoff TwinCAT 2 / TwinCAT 3 ADS driver. Talks to the runtime via `Beckhoff.TwinCAT.Ads` v6 (managed); requires a reachable AMS router on the host (local TwinCAT XAR, the standalone `Beckhoff.TwinCAT.Ads.TcpRouter` NuGet, or any Windows box with TwinCAT installed and an authorised AMS route). ## Configuration surface `TwinCATDriverOptions` (one instance supports N AMS targets, each a `TwinCATDeviceOptions`). Wire format mirrors the C# class on the JSON side — every `init`-only property round-trips through `System.Text.Json` with the default options. | Option | Type | Default | Notes | | --- | --- | --- | --- | | `Devices` | `TwinCATDeviceOptions[]` | `[]` | One entry per AMS target. | | `Tags` | `TwinCATTagDefinition[]` | `[]` | Pre-declared symbol set. | | `Probe.Enabled` | `bool` | `true` | Per-tick `ReadStateAsync` against the runtime. | | `Probe.Interval` | `TimeSpan` | `5 s` | | | `Timeout` | `TimeSpan` | `2 s` | Per-operation timeout. | | `UseNativeNotifications` | `bool` | `true` | False = fall through to PollGroupEngine. | | `EnableControllerBrowse` | `bool` | `false` | Walk symbol table on `DiscoverAsync`. | | `MaxArrayExpansion` | `int` | `1024` | Per-element cutoff during nested-UDT browse. | | `EnableAlarms` (PR 5.1) | `bool` | `false` | Opt-in TC3 EventLogger bridge — see "Alarms" below. | ## Alarms (TC3 EventLogger bridge, PR 5.1 / #316) When `EnableAlarms=true`, the driver implements `IAlarmSource` by opening a second `AdsClient` against AMS port **110** (`AMSPORT_EVENTLOG`) and adding a device notification on `ADSIGRP_TCEVENTLOG_ALARMS`. Subscribers receive `OnAlarmEvent` notifications for every transition the EventLogger surfaces (raise / clear / acknowledge). ### Decode caveat Beckhoff doesn't ship a managed wrapper for `TcEventLogger` in the regular `Beckhoff.TwinCAT.Ads` v6 NuGet — only the C++ TcCOM headers exist. The driver therefore decodes the AMS-port-110 binary payload manually. The current implementation is best-effort: event class GUIDs and source names usually decode cleanly; some less-common fields may surface as `"Unknown"` until a follow-up PR lands a complete decoder. Spike output captured at [`docs/v3/twincat-eventlogger-spike.md`](../v3/twincat-eventlogger-spike.md). ### Wire path | Layer | What it does | | --- | --- | | Primary `AdsClient` | The existing per-device session against the PLC runtime port (default `851`) — handles reads / writes / native subscriptions. | | Secondary `AdsClient` (alarms) | Opens against AMS port `110` on the same target NetId. Adds one device notification on `ADSIGRP_TCEVENTLOG_ALARMS` with a `length=...` payload covering the full alarm-list shape. | | `ITwinCATAlarmGate` (driver-internal) | Decodes incoming notifications into `TwinCATAlarmEvent` records (`EventClass`, `Source`, `Severity`, `Message`, `OccurrenceUtc`, `Acked`). | | `TwinCATAlarmSource` | Projects `TwinCATAlarmEvent` onto the driver-agnostic `IAlarmSource.OnAlarmEvent`. | ### Severity mapping (TC3 → OPC UA AC) TC3 EventLogger severity is a 0–255 `USINT`. The driver maps it onto the four-bucket `AlarmSeverity` enum the OPC UA AC layer consumes: | TC3 severity | `AlarmSeverity` | | --- | --- | | 0–64 | `Low` | | 65–128 | `Medium` | | 129–192 | `High` | | 193–255 | `Critical` | ### Acknowledge `AcknowledgeAsync` round-trips through `ITwinCATAlarmGate.AcknowledgeAsync`, which writes to the EventLogger ack index group. Best-effort — the wire format isn't documented in managed code, so individual ack failures don't poison the batch and the gate returns silently when the EventLogger isn't configured. ### Disabling `EnableAlarms=false` (default) returns a sentinel handle from `SubscribeAlarmsAsync` and never opens the secondary `AdsClient`. `OnAlarmEvent` simply never fires. Capability negotiation still works, which is why the driver advertises `IAlarmSource` unconditionally. ## CLI The `otopcua-twincat-cli` test client exposes an `alarms` subcommand that wraps the bridge end-to-end: ```powershell dotnet run --project src/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.Cli -- alarms ` --ams-net-id 5.23.91.23.1.1 --ams-port 851 ` --source Conveyor1.MotorOverload ``` See [`docs/Driver.TwinCAT.Cli.md`](../Driver.TwinCAT.Cli.md) for the full CLI surface. ## Test coverage - **Unit**: `TwinCATAlarmSourceTests` covers (a) feature-gating off vs. on, (b) gate-event projection shape, (c) multi-event ordering, (d) source-filter matching, (e) acknowledge round-trip, (f) JSON DTO round-trip. - **Integration**: `TwinCATAlarmIntegrationTests.Driver_raises_alarm_event_when_PLC_logs_event` ships build-only in PR 5.1; the GVL + FB_AlarmHarness ship as XAE stubs at `tests/.../TwinCatProject/PLC/`. Once the XAR project imports them the test transitions skip → pass. ## See also - [`docs/v3/twincat-eventlogger-spike.md`](../v3/twincat-eventlogger-spike.md) — spike output for the managed-wrapper question - [`docs/drivers/TwinCAT-Test-Fixture.md`](TwinCAT-Test-Fixture.md) — coverage map + capability matrix - [`docs/Driver.TwinCAT.Cli.md`](../Driver.TwinCAT.Cli.md) — CLI guide