using libplctag; namespace ZB.MOM.WW.OtOpcUa.Driver.AbCip; /// /// Maps libplctag / CIP General Status codes to OPC UA StatusCodes. Mirrors the shape of /// ModbusDriver.MapModbusExceptionToStatus so Admin UI status displays stay /// uniform across drivers. /// /// /// Coverage: the CIP general-status values an AB PLC actually returns during normal /// driver operation. Full CIP Volume 1 Appendix B lists 50+ codes; the ones here are the /// ones that move the driver's status needle: /// /// 0x00 success — OPC UA Good (0). /// 0x04 path segment error / 0x05 path destination unknown — BadNodeIdUnknown /// (tag doesn't exist). /// 0x06 partial data transfer — GoodMoreData (fragmented read underway). /// 0x08 service not supported — BadNotSupported (e.g. write on a safety /// partition tag from a non-safety task). /// 0x0A / 0x13 attribute-list error / insufficient data — BadOutOfRange /// (type mismatch or truncated buffer). /// 0x0B already in requested mode — benign, treated as Good. /// 0x0E attribute not settable — BadNotWritable. /// 0x10 device state conflict — BadDeviceFailure (program-mode protected /// writes during download / test-mode transitions). /// 0x16 object does not exist — BadNodeIdUnknown. /// 0x1E embedded service error — unwrap to the extended status when possible. /// libplctag.NET errors — mapped per-member by /// : timeout, not-found, not-allowed, and /// out-of-bounds get their specific OPC UA codes; the remaining transport errors /// fold into BadCommunicationError. /// /// public static class AbCipStatusMapper { public const uint Good = 0u; public const uint GoodMoreData = 0x00A70000u; public const uint BadInternalError = 0x80020000u; public const uint BadNodeIdUnknown = 0x80340000u; public const uint BadNotWritable = 0x803B0000u; public const uint BadOutOfRange = 0x803C0000u; public const uint BadNotSupported = 0x803D0000u; public const uint BadDeviceFailure = 0x808B0000u; public const uint BadCommunicationError = 0x80050000u; public const uint BadTimeout = 0x800A0000u; public const uint BadTypeMismatch = 0x80730000u; /// Map a CIP general-status byte to an OPC UA StatusCode. /// The CIP general-status byte value. /// The corresponding OPC UA StatusCode. public static uint MapCipGeneralStatus(byte status) => status switch { 0x00 => Good, 0x04 or 0x05 => BadNodeIdUnknown, 0x06 => GoodMoreData, 0x08 => BadNotSupported, 0x0A or 0x13 => BadOutOfRange, 0x0B => Good, 0x0E => BadNotWritable, 0x10 => BadDeviceFailure, 0x16 => BadNodeIdUnknown, _ => BadInternalError, }; /// /// Map a libplctag return/status code to an OPC UA StatusCode. The integer passed here /// is (int)Tag.GetStatus() — i.e. the underlying value of the libplctag.NET /// enum, NOT a raw native PLCTAG_ERR_* constant. The wrapper /// renumbers the native codes into a contiguous enum, so this method switches on the /// members directly to stay correct if the wrapper renumbers again. /// is success; is an in-flight /// operation; every other (negative) member is an error. /// /// The libplctag status code as an integer. /// The corresponding OPC UA StatusCode. public static uint MapLibplctagStatus(int status) => MapLibplctagStatus((Status)status); /// /// Map a libplctag.NET enum value to an OPC UA StatusCode. This is /// the strongly-typed core of the mapper; the int overload exists only for the /// seam, which returns the boxed-as-int value. /// /// The libplctag Status enum value. /// The corresponding OPC UA StatusCode. public static uint MapLibplctagStatus(Status status) => status switch { Status.Ok => Good, Status.Pending => GoodMoreData, Status.ErrorTimeout => BadTimeout, Status.ErrorNotFound or Status.ErrorNoMatch or Status.ErrorBadDevice => BadNodeIdUnknown, Status.ErrorNotAllowed => BadNotWritable, Status.ErrorOutOfBounds or Status.ErrorTooLarge or Status.ErrorTooSmall => BadOutOfRange, Status.ErrorUnsupported or Status.ErrorNotImplemented => BadNotSupported, Status.ErrorBadConnection or Status.ErrorBadGateway or Status.ErrorBadReply or Status.ErrorWinsock or Status.ErrorOpen or Status.ErrorClose or Status.ErrorRead or Status.ErrorWrite or Status.ErrorRemoteErr or Status.ErrorPartial or Status.ErrorAbort => BadCommunicationError, _ => BadCommunicationError, }; }