Auto: twincat-5.1 — IAlarmSource via TC3 EventLogger (gated, scaffold)

Closes #316
This commit is contained in:
Joseph Doherty
2026-04-26 11:13:24 -04:00
parent 3babfb8a99
commit c88e0b6bed
13 changed files with 1238 additions and 7 deletions

View File

@@ -278,6 +278,88 @@ dotnet test tests\ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.IntegrationTests `
--filter "FullyQualifiedName~TwinCATSymbolVersionTests"
```
## Alarm scenarios
PR 5.1 (#316) ships an opt-in TC3 EventLogger bridge. The driver's
`IAlarmSource` implementation surfaces alarms by opening a second
`AdsClient` against AMS port `110` (`AMSPORT_EVENTLOG`) and adding a
device notification on `ADSIGRP_TCEVENTLOG_ALARMS`. The decode is
best-effort because Beckhoff doesn't ship a managed `TcEventLogger`
wrapper (only C++ TcCOM headers); some fields surface as `Unknown`
until a follow-up PR lands a binary-protocol decoder. Spike output
captured at `docs/v3/twincat-eventlogger-spike.md`.
The integration test
(`TwinCATAlarmIntegrationTests.Driver_raises_alarm_event_when_PLC_logs_event`)
ships build-only in PR 5.1 — once the XAR project imports the GVL +
FB_AlarmHarness below, swap the `Assert.Skip` in the test body for the
live flow:
1. Init the driver with `EnableAlarms=true`.
2. `SubscribeAlarmsAsync([], ct)`.
3. `WriteAsync` to flip `GVL_Alarms.bTriggerEvent` from `FALSE` to
`TRUE``FB_AlarmHarness` sees the rising edge and calls
`FB_TcLogEvent` on the PLC side.
4. Assert `OnAlarmEvent` fires within `~5 s` with non-empty
`Source` + `Message`.
### Global Variable List: `GVL_Alarms`
```st
VAR_GLOBAL
bTriggerEvent : BOOL := FALSE;
bAcked : BOOL := FALSE;
nLastEventClass : DINT := 0;
nLastSeverity : USINT := 0;
fbAlarmHarness : FB_AlarmHarness;
END_VAR
```
The XAE-form GVL ships at `PLC/GVLs/GVL_Alarms.TcGVL`; import it
alongside the other fixture GVLs.
### POU: `FB_AlarmHarness`
```st
FUNCTION_BLOCK FB_AlarmHarness
VAR
fbTrigger : R_TRIG;
fbLogEvent : FB_TcLogEvent; // declared in Tc3_EventLogger
sMessage : STRING(255) := 'Integration-fixture EventLogger trigger';
END_VAR
fbTrigger(CLK := GVL_Alarms.bTriggerEvent);
IF fbTrigger.Q THEN
fbLogEvent.eSeverity := TcEventSeverity.Warning;
fbLogEvent.bConfirmable := TRUE;
fbLogEvent.Execute(bExecute := TRUE);
GVL_Alarms.nLastEventClass := 1;
GVL_Alarms.nLastSeverity := 100;
END_IF
fbLogEvent.Execute(bExecute := FALSE);
```
The XAE-form POU ships at `PLC/POUs/FB_AlarmHarness.TcPOU`. Wire it
into `MAIN`:
```st
GVL_Alarms.fbAlarmHarness();
```
### Event class IDs / severity buckets / cleared-on transitions
| Symbol | Value | Notes |
| --- | --- | --- |
| `nLastEventClass` | `DINT`, fixture-side echo (`1` after a rising edge) | Watch-window aid; the actual EventLogger event class is configured in the TC3 GUI per project. |
| `nLastSeverity` | `USINT`, fixed `100` after a rising edge | Maps to `AlarmSeverity.Medium` via `TwinCATAlarmSource.MapSeverity` (≤128 = Medium). |
| `bTriggerEvent` | `BOOL`, operator/test writes | Rising edge only — flip back to `FALSE` then `TRUE` to re-fire. |
| `bAcked` | `BOOL`, driver writes when `AcknowledgeAsync` runs | Cleared by next event raise. |
The TC3 EventLogger surfaces the cleared transition automatically when
`fbLogEvent.bConfirmable=TRUE` and an operator confirms; the driver
projects the clear as a second `OnAlarmEvent` with the same condition
id.
## How to run the TwinCAT-tier tests
On the dev box: