Files
lmxopcua/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/TwinCATStatusMapper.cs
T
Joseph Doherty a6ae4e22d1 fix(status-codes): correct BadDeviceFailure from 0x80550000 to 0x808B0000
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>
2026-05-23 17:14:28 -04:00

83 lines
4.8 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
namespace ZB.MOM.WW.OtOpcUa.Driver.TwinCAT;
/// <summary>
/// Maps AMS / ADS error codes to OPC UA StatusCodes. ADS error codes are taken from the
/// <c>AdsErrorCode</c> enum in <c>Beckhoff.TwinCAT.Ads</c> 7.x — numeric values are the
/// authoritative source (not the hex shorthand in older Beckhoff InfoSys pages, which has
/// known transcription errors). Key device-layer codes start at 0x0700 (1792 decimal).
/// </summary>
public static class TwinCATStatusMapper
{
public const uint Good = 0u;
// ---- OPC UA StatusCode constants ----
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;
public const uint BadOutOfService = 0x80BE0000u;
public const uint BadInvalidState = 0x80350000u;
// ---- AdsErrorCode numeric values (confirmed from Beckhoff.TwinCAT.Ads 7.0.172) ----
/// <summary>
/// ADS <c>DeviceSymbolVersionInvalid</c> — error code 1809 (0x0711 decimal).
/// Raised by the runtime after a PLC program re-download: every symbol handle and
/// notification handle the driver holds is now stale. The driver treats this as an
/// <see cref="Core.Abstractions.IRediscoverable"/> trigger, not a connection error
/// (docs/v2/driver-specs.md §6, Driver.TwinCAT-013).
/// <para>
/// Note: legacy Beckhoff InfoSys documentation sometimes cites this as "0x0702"; that
/// is a transcription error — 0x0702 is <c>DeviceInvalidGroup</c> (1794). The SDK enum
/// value 1809 (0x0711) is authoritative (Driver.TwinCAT-011).
/// </para>
/// </summary>
public const uint AdsSymbolVersionChanged = 1809u; // DeviceSymbolVersionInvalid = 0x0711
/// <summary>True when <paramref name="adsError"/> is the symbol-version-changed code.</summary>
public static bool IsSymbolVersionChanged(uint adsError) => adsError == AdsSymbolVersionChanged;
/// <summary>
/// Map an AMS / ADS error code (uint cast from <c>AdsErrorCode</c> enum) to an OPC UA
/// StatusCode. 0 = success. Device-layer codes (0x07000x073F) cover the operations a
/// driver actually encounters during normal runtime.
/// </summary>
public static uint MapAdsError(uint adsError) => adsError switch
{
0 => Good,
// AMS router / transport errors
6 or 7 => BadCommunicationError, // TargetPortNotFound / TargetMachineNotFound
1285 or 1290 => BadCommunicationError, // RouterNotInitialized / RouterNotActive
// Device-layer codes (Beckhoff.TwinCAT.Ads AdsErrorCode enum, confirmed 7.0.172)
1792 => BadDeviceFailure, // DeviceError (generic device error)
1793 => BadNotSupported, // DeviceServiceNotSupported
1794 => BadOutOfRange, // DeviceInvalidGroup (ADS index-group error)
1795 => BadOutOfRange, // DeviceInvalidOffset (ADS index-offset error)
1796 => BadNotWritable, // DeviceInvalidAccess (write-access denied)
1797 => BadOutOfRange, // DeviceInvalidSize (size mismatch)
1798 => BadTypeMismatch, // DeviceInvalidData (data format mismatch)
1799 => BadOutOfService, // DeviceNotReady (PLC not running / in config)
1804 => BadNodeIdUnknown, // DeviceNotFound
1807 => BadDeviceFailure, // DeviceIncompatible (0x070E)
1808 => BadNodeIdUnknown, // DeviceSymbolNotFound (0x0710)
1809 => BadInvalidState, // DeviceSymbolVersionInvalid — rediscovery trigger
1810 => BadInvalidState, // DeviceInvalidState (PLC in Config mode, 0x0712)
1811 => BadNotSupported, // DeviceTransModeNotSupported (0x0713)
1812 => BadNodeIdUnknown, // DeviceNotifyHandleInvalid (stale handle, 0x0714)
1827 => BadNotWritable, // DeviceAccessDenied (0x0723)
1844 => BadOutOfRange, // DeviceOutOfRange (0x0734)
// Client-layer timeout
1861 => BadTimeout, // ClientSyncTimeOut (0x0745)
_ => BadCommunicationError,
};
}