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,
};
}