namespace ZB.MOM.WW.OtOpcUa.Commons.OpcUa; /// /// The handful of OPC UA status codes the engine layer needs to spell, plus the Part 4 severity /// classification helpers that replaced the retired OpcUaQuality 3-state enum (Gitea #519). /// /// Why these are bare uint literals. Commons and Runtime deliberately do not /// reference the OPC UA SDK — exists precisely so the Runtime /// project can publish values without dragging in Opc.Ua.Server. That is the same layering /// decision the driver assemblies make, and it carries the same single failure mode: nothing checks /// the literal against the name. StatusCodeParityTests closes it by reflection, and it can /// only see a named constant — so add codes here rather than writing a literal at a call /// site, exactly as Gitea #497 concluded for the drivers. /// /// Severity, not equality, is what callers should branch on. A status code's top two /// bits carry its Part 4 severity (00 = Good, 01 = Uncertain, 10/11 = Bad); everything below is the /// sub-code. Before #519 the engine collapsed every value onto a 3-state enum here and the node /// manager re-expanded Bad to a bare 0x80000000, so no driver's sub-code ever reached /// a client. The sub-code now rides through to the SDK verbatim, and any code that only needs the /// bucket uses / / rather than /// comparing against or . /// public static class OpcUaStatus { /// The value is good. Part 4 severity 00; the whole code is zero. public const uint Good = 0x00000000; /// Generic uncertain. Prefer a specific Uncertain* sub-code where one applies. public const uint Uncertain = 0x40000000; /// Generic bad, carrying no diagnostic beyond the severity. This is the value the retired /// 3-state projection produced for every bad status; a caller that has something more /// specific should say so instead. public const uint Bad = 0x80000000; /// No value has been received from the device yet. Written at materialisation and on every /// address-space reset, so a freshly-deployed or just-rebuilt node reads as "not yet polled" rather /// than as a device fault. public const uint BadWaitingForInitialData = 0x80320000; /// Communication with the source has been lost. The driver-connectivity annotation for a /// native alarm condition, and the sentinel several drivers map an explicit "unavailable" reading to. public const uint BadNoCommunication = 0x80310000; /// An internal failure produced no usable value — the virtual-tag path's code for a script /// that threw or timed out. public const uint BadInternalError = 0x80020000; /// Part 4 severity bucket of : the top two bits. /// The status code to classify. /// 0 for Good, 1 for Uncertain, 2 or 3 for Bad. public static uint Severity(uint statusCode) => statusCode >> 30; /// True when is in the Good severity bucket. /// The status code to classify. /// when the value is usable. public static bool IsGood(uint statusCode) => Severity(statusCode) == 0; /// True when is in the Uncertain severity bucket. /// The status code to classify. /// when the value is questionable but present. public static bool IsUncertain(uint statusCode) => Severity(statusCode) == 1; /// True when is in the Bad severity bucket. /// The status code to classify. /// when the value must not be trusted. public static bool IsBad(uint statusCode) => Severity(statusCode) >= 2; }