80 lines
3.8 KiB
C#
80 lines
3.8 KiB
C#
namespace ZB.MOM.WW.OtOpcUa.Driver.AbCip;
|
|
|
|
/// <summary>
|
|
/// Maps libplctag / CIP General Status codes to OPC UA StatusCodes. Mirrors the shape of
|
|
/// <c>ModbusDriver.MapModbusExceptionToStatus</c> so Admin UI status displays stay
|
|
/// uniform across drivers.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>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:</para>
|
|
/// <list type="bullet">
|
|
/// <item>0x00 success — OPC UA <c>Good (0)</c>.</item>
|
|
/// <item>0x04 path segment error / 0x05 path destination unknown — <c>BadNodeIdUnknown</c>
|
|
/// (tag doesn't exist).</item>
|
|
/// <item>0x06 partial data transfer — <c>GoodMoreData</c> (fragmented read underway).</item>
|
|
/// <item>0x08 service not supported — <c>BadNotSupported</c> (e.g. write on a safety
|
|
/// partition tag from a non-safety task).</item>
|
|
/// <item>0x0A / 0x13 attribute-list error / insufficient data — <c>BadOutOfRange</c>
|
|
/// (type mismatch or truncated buffer).</item>
|
|
/// <item>0x0B already in requested mode — benign, treated as <c>Good</c>.</item>
|
|
/// <item>0x0E attribute not settable — <c>BadNotWritable</c>.</item>
|
|
/// <item>0x10 device state conflict — <c>BadDeviceFailure</c> (program-mode protected
|
|
/// writes during download / test-mode transitions).</item>
|
|
/// <item>0x16 object does not exist — <c>BadNodeIdUnknown</c>.</item>
|
|
/// <item>0x1E embedded service error — unwrap to the extended status when possible.</item>
|
|
/// <item>any libplctag <c>PLCTAG_STATUS_*</c> below zero — wrapped as
|
|
/// <c>BadCommunicationError</c> until fine-grained mapping lands (PR 3).</item>
|
|
/// </list>
|
|
/// </remarks>
|
|
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 = 0x80550000u;
|
|
public const uint BadCommunicationError = 0x80050000u;
|
|
public const uint BadTimeout = 0x800A0000u;
|
|
public const uint BadTypeMismatch = 0x80730000u;
|
|
|
|
/// <summary>Map a CIP general-status byte to an OPC UA StatusCode.</summary>
|
|
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,
|
|
};
|
|
|
|
/// <summary>
|
|
/// Map a libplctag return/status code (<c>PLCTAG_STATUS_*</c>) to an OPC UA StatusCode.
|
|
/// libplctag uses <c>0 = PLCTAG_STATUS_OK</c>, positive values for pending, negative
|
|
/// values for errors.
|
|
/// </summary>
|
|
public static uint MapLibplctagStatus(int status)
|
|
{
|
|
if (status == 0) return Good;
|
|
if (status > 0) return GoodMoreData; // PLCTAG_STATUS_PENDING
|
|
return status switch
|
|
{
|
|
-5 => BadTimeout, // PLCTAG_ERR_TIMEOUT
|
|
-7 => BadCommunicationError, // PLCTAG_ERR_BAD_CONNECTION
|
|
-14 => BadNodeIdUnknown, // PLCTAG_ERR_NOT_FOUND
|
|
-16 => BadNotWritable, // PLCTAG_ERR_NOT_ALLOWED / read-only tag
|
|
-17 => BadOutOfRange, // PLCTAG_ERR_OUT_OF_BOUNDS
|
|
_ => BadCommunicationError,
|
|
};
|
|
}
|
|
}
|