Driver.Cli.Common-007 + Driver.Cli.Common-008 resolution.
Driver.Cli.Common-007 (High, Correctness):
0x80550000 is the canonical OPC UA spec value for BadSecurityPolicyRejected,
not BadDeviceFailure. The correct spec value for BadDeviceFailure is
0x808B0000 (verified against OPC Foundation Opc.Ua.StatusCodes;
corroborated locally by Driver.Galaxy.Runtime.StatusCodeMap and both
Wonderware historian quality mappers which all hand-pin the correct
value).
The bug was duplicated across six driver modules:
- FocasStatusMapper.BadDeviceFailure
- AbCipStatusMapper.BadDeviceFailure
- AbLegacyStatusMapper.BadDeviceFailure
- TwinCATStatusMapper.BadDeviceFailure
- ModbusDriver.StatusBadDeviceFailure
- S7Driver.StatusBadDeviceFailure
Plus the SnapshotFormatter shortlist that named 0x80550000 as
BadDeviceFailure, and three downstream Modbus tests that asserted
against the wrong value (so CI was blind).
This commit fixes all six native-mapper constants, the formatter
shortlist, and the three Modbus tests in one pass. Added a regression
guard to FormatStatus_does_not_apply_pre_fix_wrong_names that pins
0x80550000 never renders as BadDeviceFailure (mirroring the existing
-001 wrong-name guards).
Behavior change: OPC UA clients consuming the native drivers now see
the canonical BadDeviceFailure (0x808B0000) on device-fault paths
instead of the misnamed BadSecurityPolicyRejected (0x80550000). Wire-
level status semantics now match operator-facing CLI labels.
Driver.Cli.Common-008 (Low, Testing):
Deleted the redundant FormatStatus_names_native_driver_emitted_codes
Theory — its five InlineData rows were already covered by the
well-known Theory in the same commit (5a9c459), and used a weaker
ShouldContain vs the well-known Theory's ShouldBe (exact match).
Verification:
- Driver.Cli.Common.Tests: 43/43 pass (was 48 after the -008 deletion).
- Driver.Modbus.Tests: 263/263 pass.
- Driver.AbCip.Tests: 262/262.
- Driver.AbLegacy.Tests: 157/157.
- Driver.FOCAS.Tests: 178/178.
- Driver.S7.Tests: 112/112.
- Driver.TwinCAT.Tests: 131/131.
Total: 1146 tests across the affected modules, all green.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
74 lines
3.5 KiB
C#
74 lines
3.5 KiB
C#
using libplctag;
|
|
|
|
namespace ZB.MOM.WW.OtOpcUa.Driver.AbLegacy;
|
|
|
|
/// <summary>
|
|
/// Maps libplctag status codes + PCCC STS/EXT_STS bytes to OPC UA StatusCodes. Mirrors the
|
|
/// AbCip mapper — PCCC errors roughly align with CIP general-status in shape but with a
|
|
/// different byte vocabulary (PCCC STS nibble-low + EXT_STS on code 0x0F).
|
|
/// </summary>
|
|
public static class AbLegacyStatusMapper
|
|
{
|
|
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;
|
|
|
|
/// <summary>
|
|
/// Map a libplctag return/status code to an OPC UA StatusCode. The integer passed here
|
|
/// is <c>(int)Tag.GetStatus()</c> — the underlying value of the libplctag.NET
|
|
/// <see cref="Status"/> enum. Delegates to the strongly-typed overload so the mapping
|
|
/// stays correct regardless of how the wrapper renumbers native PLCTAG_ERR_* constants
|
|
/// in future releases.
|
|
/// </summary>
|
|
public static uint MapLibplctagStatus(int status) => MapLibplctagStatus((Status)status);
|
|
|
|
/// <summary>
|
|
/// Map a libplctag.NET <see cref="Status"/> enum value to an OPC UA StatusCode. This is
|
|
/// the canonical core; the <c>int</c> overload exists only for the
|
|
/// <see cref="IAbLegacyTagRuntime.GetStatus"/> seam which boxes the enum as an int.
|
|
/// </summary>
|
|
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,
|
|
};
|
|
|
|
/// <summary>
|
|
/// Map a PCCC STS (status) byte. Common codes per AB PCCC reference:
|
|
/// 0x00 = success, 0x10 = illegal command, 0x20 = bad address, 0x30 = protected,
|
|
/// 0x40 = programmer busy, 0x50 = file locked, 0xF0 = extended status follows.
|
|
/// libplctag surfaces only its own <see cref="Status"/> enum rather than exposing
|
|
/// the raw STS byte, so this method is not wired into the current read/write path.
|
|
/// It is retained as the reference mapping for future PCCC-STS inspection.
|
|
/// </summary>
|
|
public static uint MapPcccStatus(byte sts) => sts switch
|
|
{
|
|
0x00 => Good,
|
|
0x10 => BadNotSupported,
|
|
0x20 => BadNodeIdUnknown,
|
|
0x30 => BadNotWritable,
|
|
0x40 => BadDeviceFailure,
|
|
0x50 => BadDeviceFailure,
|
|
0xF0 => BadInternalError, // extended status not inspected at this layer
|
|
_ => BadCommunicationError,
|
|
};
|
|
}
|