f087f01d2b
H1/L4: one classification (AbCipRefusals.IsDeviceRefusal) of the statuses
that prove the controller answered - NotFound, OutOfBounds, NotAllowed,
TooLarge, TooSmall, TypeMismatch, Unsupported - shared by the data path, the
Test-Connect probe (IsReachableStatus widened) and the native runtime.
- A refused read/write (thrown or as a status word) is per-tag Bad with a
once-per-tag Warning, keeps the runtime (no evict, so no lease/Forward-Open
churn for a sole lease holder), writes no Degraded and, since the device
answered, advances LastSuccessfulRead without touching the state.
- A refused cold create records the backoff as reachable, so siblings are no
longer throttled for up to 30 s by one Arr[999].
- The native runtime completes InitializeAsync on any refusal (it used to on
TypeMismatch/Unsupported only) and reports it on every later read.
- A refused READ of NotAllowed reads BadNotReadable, not BadNotWritable.
- Test Connect names the refusal ("probe tag refused: OutOfBounds").
0x1C/0x20/0xFF-0x2104 still fold into BadReply inside Driver.Ab.Transport
(Lane K follow-up); they remain comms faults until mapped there.
Refs #737
Claude-Session: https://claude.ai/code/session_01Ub9hGmYLQvn9XETzw7CMsT
66 lines
3.4 KiB
C#
66 lines
3.4 KiB
C#
using ZB.MOM.WW.OtOpcUa.Driver.Ab.Transport;
|
|
|
|
namespace ZB.MOM.WW.OtOpcUa.Driver.AbCip;
|
|
|
|
/// <summary>
|
|
/// Maps transport <see cref="AbStatus"/> values to OPC UA StatusCodes through the table shared with AbLegacy
|
|
/// (<see cref="AbOpcUaStatusMap"/>): timeout, not-found, not-allowed, out-of-bounds, unsupported, type-mismatch
|
|
/// and device-state-conflict get their specific codes; the remaining transport errors fold into
|
|
/// <c>BadCommunicationError</c>. (The raw CIP general-status mapper that used to live here had no callers — the
|
|
/// transports surface an <see cref="AbStatus"/>, not the status byte — and was removed.)
|
|
/// </summary>
|
|
public static class AbCipStatusMapper
|
|
{
|
|
public const uint Good = 0u;
|
|
public const uint GoodMoreData = 0x00A60000u;
|
|
public const uint BadInternalError = 0x80020000u;
|
|
public const uint BadNodeIdUnknown = 0x80340000u;
|
|
public const uint BadNotReadable = 0x803A0000u;
|
|
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 = 0x80740000u;
|
|
public const uint BadConfigurationError = 0x80890000u;
|
|
|
|
/// <summary>
|
|
/// Map a transport status code to an OPC UA StatusCode. The integer is
|
|
/// <see cref="IAbCipTagRuntime.GetStatus"/>, i.e. the underlying value of <see cref="AbStatus"/>.
|
|
/// </summary>
|
|
/// <param name="status">The <see cref="AbStatus"/> as an integer.</param>
|
|
/// <returns>The mapped OPC UA StatusCode value.</returns>
|
|
public static uint MapStatus(int status) => MapStatus((AbStatus)status);
|
|
|
|
/// <summary>
|
|
/// Map an <see cref="AbStatus"/> to an OPC UA StatusCode. Timeout, not-found, not-allowed and
|
|
/// out-of-bounds get their specific codes; the remaining transport errors fold into
|
|
/// <see cref="BadCommunicationError"/>.
|
|
/// </summary>
|
|
/// <param name="status">The transport status.</param>
|
|
/// <returns>The mapped OPC UA StatusCode value.</returns>
|
|
public static uint MapStatus(AbStatus status) => AbOpcUaStatusMap.MapStatus(status);
|
|
|
|
/// <summary>
|
|
/// Status for an exception thrown while creating / reading a tag: a transport exception maps
|
|
/// through its <see cref="AbStatus"/> (so a tag the controller does not have reads
|
|
/// <see cref="BadNodeIdUnknown"/>, not a comms error); anything else is
|
|
/// <see cref="BadCommunicationError"/>.
|
|
/// </summary>
|
|
/// <param name="ex">The exception.</param>
|
|
/// <returns>The OPC UA status code.</returns>
|
|
public static uint MapException(Exception ex) =>
|
|
AbOpcUaStatusMap.MapException(ex);
|
|
|
|
/// <summary>
|
|
/// Status for a READ the controller refused: as <see cref="MapStatus(AbStatus)"/>, except that a
|
|
/// <see cref="AbStatus.NotAllowed"/> answer to a read is <see cref="BadNotReadable"/> (the shared table's
|
|
/// <c>BadNotWritable</c> describes a refused write).
|
|
/// </summary>
|
|
/// <param name="status">The refusal status.</param>
|
|
/// <returns>The OPC UA status code.</returns>
|
|
public static uint MapReadStatus(AbStatus status) =>
|
|
status == AbStatus.NotAllowed ? BadNotReadable : MapStatus(status);
|
|
}
|