feat(focas): CNC alarms reach Part 9 conditions via ALARM: tags (#647)
An ALARM: address (*, <Type>, <Type>/<n>, <Type>/<lo>-<hi>, T<code>, OTHER) on a raw tag that
also carries the cross-driver alarm object is ONE condition with ConditionId == RawPath and a
Kind (Raise / Retrigger / Clear), so DriverHostActor.ForwardNativeAlarm routes it and
NativeAlarmProjector activates it. Fixes all seven triage defects:
1. SubscribeAlarmsAsync treated the host's RawPaths as device hosts -> nothing polled.
2. Decorated "{host}#{Type}:{Number}" ConditionId -> every event dropped.
3. No Kind -> projector kept prior state.
4. WireFocasClient.ReadAlarmsAsync answered [] on failure -> mass clear + un-acked re-raise.
It now throws; a failed device read keeps every condition's state.
5. Acks lost on reconnect -> told-record dedup (MTConnect #626 pattern) held for the driver's
lifetime; same-set re-subscribe / re-init re-raise nothing; changed set prunes leavers only.
6. Subscribe threw while AlarmProjection.Enabled=false -> the tag is the opt-in; flag is a no-op.
7. Alarm tags could not be authored -> ALARM: grammar (FocasAlarmSelector, Contracts) backs the
editor, the address picker, the deploy-time inspector and driver init.
Severity: authored alarm.severity -> exact OpcUaSeverity; else the 16i-era type bucket. The type
table stays the only one (moved to Contracts, documented 16i-era; 30i codes not invented; raw
T<code> selector + raw code in every message). Read-only: ack is server-side. Also clears the
value table on a re-initialise (#630 gap that let a removed/moved tag keep reading).
E2E: Runtime.Tests FocasNativeAlarmEndToEndTests drives the real driver through the real
DriverHostActor and asserts the condition goes Active then inactive.
Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe
This commit is contained in:
@@ -1117,6 +1117,12 @@ host logger factory (wired in `DriverFactoryBootstrap`; the FOCAS and TwinCAT fa
|
||||
- **FOCAS (#257/#266):** `cnc_statinfo` flags are a `Status/` fixed-tree subtree (`FIXED:Status/Run`…, capability-probed);
|
||||
adjacent PMC tags in one poll batch coalesce into one `pmc_rdpmcrng` (`PmcCoalesce` config, default on) — a refused range
|
||||
falls back to per-tag reads, a transport failure fails all members without retry. Parts count stays `PARAM:6711` (docs only).
|
||||
- **FOCAS alarms (#647):** an `ALARM:` address (`*`, `<Type>`, `<Type>/<n>`, `<Type>/<lo>-<hi>`, `T<code>`, `OTHER`) +
|
||||
the `alarm` object = ONE condition at the RawPath (either alone is skipped + reported). Overlapping selectors all
|
||||
fire; `OTHER` = what no type selector claims. ⚠️ A failed `cnc_rdalmmsg2` THROWS (it used to return `[]` ⇒ mass
|
||||
clear + un-acked re-raise); the told record lives on the driver, so reconnect/re-init re-raise nothing. Type names
|
||||
are the 16i-era table only (30i codes unconfirmed, not invented — use `T<code>` there). Read-only; ack server-side.
|
||||
`AlarmProjection.Enabled` is a no-op. E2E: `Runtime.Tests/FocasNativeAlarmEndToEndTests`. `docs/drivers/FOCAS.md`.
|
||||
- **Re-Initialize without teardown (#630):** FOCAS, AbLegacy, AbCip, TwinCAT, S7 and OpcUaClient `InitializeAsync`
|
||||
first release the prior device/session state (cancel, ≤ 5 s join, dispose — incl. the AbCip/FOCAS alarm
|
||||
projections) — the device-state half of `ShutdownAsync` only; the poll engine is kept and the actor re-subscribes
|
||||
@@ -1158,7 +1164,7 @@ host logger factory (wired in `DriverFactoryBootstrap`; the FOCAS and TwinCAT fa
|
||||
live node state (client acks included), the same-apply re-materialise restores it, and `CompleteAddressSpaceApply`
|
||||
(called by `OpcUaPublishActor` at the end of every apply) reports ONE event per restored off-normal condition and
|
||||
discards unclaimed captures. `NativeAlarmProjector` is pruned per apply, not cleared. Native routing is an exact
|
||||
`ConditionId == RawPath` match — AbCip's `#active` suffix was fixed; FOCAS is still unroutable (`docs/drivers/FOCAS.md`).
|
||||
`ConditionId == RawPath` match — AbCip's `#active` suffix was fixed; FOCAS routes since #647 (below).
|
||||
- **Driver removal (#609):** removing a driver releases its capability-invoker pipelines and resilience
|
||||
tracker, *then* evicts its telemetry snapshots. ⚠️ Both are **tombstoned**, not just cleared: the removed
|
||||
child stops asynchronously and its in-flight subscribe/connect still completes through the invoker (and
|
||||
|
||||
Reference in New Issue
Block a user