using ZB.MOM.WW.OtOpcUa.Commons.OpcUa; using ZB.MOM.WW.OtOpcUa.Core.Abstractions; namespace ZB.MOM.WW.OtOpcUa.Runtime.Drivers; /// /// Derives a full Part 9 from each native /// delta, tracking per-condition-NodeId prior state. Owned by the /// single-threaded DriverHostActor (no locking). Native alarms carry only a transition /// , not a full state machine, so this is the translation the /// scripted-alarm engine does internally. /// public sealed class NativeAlarmProjector { private readonly Dictionary _prior = new(StringComparer.Ordinal); /// Project an alarm transition onto the full condition snapshot for . /// The materialised condition node's id (the projection's state key). /// The native alarm transition. /// The full Part 9 condition snapshot to write to the node. public AlarmConditionSnapshot Project(string nodeId, AlarmEventArgs e) { var prev = _prior.TryGetValue(nodeId, out var p) ? p : (Active: false, Acked: true); var sev = MapSeverity(e.Severity); var (active, acked) = e.Kind switch { AlarmTransitionKind.Raise or AlarmTransitionKind.Retrigger => (true, false), AlarmTransitionKind.Acknowledge => (prev.Active, true), AlarmTransitionKind.Clear => (false, prev.Acked), _ => (prev.Active, prev.Acked), }; _prior[nodeId] = (active, acked); return new AlarmConditionSnapshot( Active: active, Acknowledged: acked, Confirmed: true, Enabled: true, Shelving: AlarmShelvingKind.Unshelved, Severity: sev, Message: e.Message); } /// Clears all tracked per-node state (call on address-space rebuild). public void Clear() => _prior.Clear(); private static ushort MapSeverity(AlarmSeverity s) => s switch { AlarmSeverity.Low => 200, AlarmSeverity.Medium => 500, AlarmSeverity.High => 700, AlarmSeverity.Critical => 900, _ => 500, }; }