fix(driver-twincat): resolve Medium code-review finding (Driver.TwinCAT-011)
Confirm AdsErrorCode values from Beckhoff.TwinCAT.Ads 7.0.172 and rewrite MapAdsError with 20 explicit cases. Fix critical bug: AdsSymbolVersionChanged was 0x0702 (DeviceInvalidGroup) but DeviceSymbolVersionInvalid is 1809 (0x0711); correct constant and all comments. Add BadOutOfService for DeviceNotReady and BadInvalidState for DeviceInvalidState/PLC-in-Config. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -58,7 +58,7 @@ internal sealed class AdsTwinCATClient : ITwinCATClient
|
||||
|
||||
public event EventHandler? OnSymbolVersionChanged;
|
||||
|
||||
/// <summary>Raise <see cref="OnSymbolVersionChanged"/> when <paramref name="adsError"/> is 0x0702.</summary>
|
||||
/// <summary>Raise <see cref="OnSymbolVersionChanged"/> when <paramref name="adsError"/> is <c>DeviceSymbolVersionInvalid</c> (1809 / 0x0711).</summary>
|
||||
private uint MapAndSignal(uint adsError)
|
||||
{
|
||||
if (TwinCATStatusMapper.IsSymbolVersionChanged(adsError))
|
||||
|
||||
@@ -21,11 +21,11 @@ public interface ITwinCATClient : IDisposable
|
||||
|
||||
/// <summary>
|
||||
/// Raised when the client observes the ADS symbol-version-changed code
|
||||
/// (<see cref="TwinCATStatusMapper.AdsSymbolVersionChanged"/>) on any read / write /
|
||||
/// notification — the signal that a PLC program re-download has invalidated every
|
||||
/// symbol + notification handle. The driver forwards this to
|
||||
/// <see cref="Core.Abstractions.IRediscoverable.OnRediscoveryNeeded"/> so Core rebuilds
|
||||
/// the address space subtree (docs/v2/driver-specs.md §6, Driver.TwinCAT-013).
|
||||
/// (<see cref="TwinCATStatusMapper.AdsSymbolVersionChanged"/> — <c>DeviceSymbolVersionInvalid</c>
|
||||
/// 1809 / 0x0711) on any read / write / notification — the signal that a PLC program
|
||||
/// re-download has invalidated every symbol + notification handle. The driver forwards
|
||||
/// this to <see cref="Core.Abstractions.IRediscoverable.OnRediscoveryNeeded"/> so Core
|
||||
/// rebuilds the address space subtree (docs/v2/driver-specs.md §6, Driver.TwinCAT-013).
|
||||
/// </summary>
|
||||
event EventHandler? OnSymbolVersionChanged;
|
||||
|
||||
|
||||
@@ -516,14 +516,16 @@ public sealed class TwinCATDriver : IDriver, IReadable, IWritable, ITagDiscovery
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Routes a wire-detected ADS symbol-version-changed (0x0702) to Core as an
|
||||
/// <see cref="IRediscoverable"/> invocation (Driver.TwinCAT-013). A PLC re-download
|
||||
/// invalidates every symbol + notification handle, so the address space must be rebuilt
|
||||
/// — this is the documented TwinCAT failure mode, not a transient connection error.
|
||||
/// Routes a wire-detected ADS symbol-version-changed (DeviceSymbolVersionInvalid 1809 /
|
||||
/// 0x0711) to Core as an <see cref="IRediscoverable"/> invocation (Driver.TwinCAT-013).
|
||||
/// A PLC re-download invalidates every symbol + notification handle, so the address
|
||||
/// space must be rebuilt — this is the documented TwinCAT failure mode, not a transient
|
||||
/// connection error.
|
||||
/// </summary>
|
||||
private void HandleSymbolVersionChanged(object? sender, EventArgs e) =>
|
||||
OnRediscoveryNeeded?.Invoke(this, new RediscoveryEventArgs(
|
||||
"TwinCAT symbol-version-changed 0x0702 — PLC program re-downloaded", ScopeHint: "TwinCAT"));
|
||||
"TwinCAT symbol-version-changed (DeviceSymbolVersionInvalid 0x0711) — PLC program re-downloaded",
|
||||
ScopeHint: "TwinCAT"));
|
||||
|
||||
public void Dispose() => DisposeAsync().AsTask().GetAwaiter().GetResult();
|
||||
public async ValueTask DisposeAsync() => await ShutdownAsync(CancellationToken.None).ConfigureAwait(false);
|
||||
|
||||
@@ -1,56 +1,82 @@
|
||||
namespace ZB.MOM.WW.OtOpcUa.Driver.TwinCAT;
|
||||
|
||||
/// <summary>
|
||||
/// Maps AMS / ADS error codes to OPC UA StatusCodes. ADS error codes are defined in
|
||||
/// <c>AdsErrorCode</c> from <c>Beckhoff.TwinCAT.Ads</c> — this mapper covers the ones a
|
||||
/// driver actually encounters during normal operation (symbol-not-found, access-denied,
|
||||
/// timeout, router-not-initialized, invalid-group/offset, etc.).
|
||||
/// 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 = 0x80550000u;
|
||||
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>ADSERR_DEVICE_SYMBOLVERSIONINVALID</c> — error <c>0x0702</c> (1794 decimal).
|
||||
/// 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 = 0x0702u;
|
||||
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;
|
||||
|
||||
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 an AMS / ADS error code (uint from AdsErrorCode enum). 0 = success; non-zero
|
||||
/// codes follow Beckhoff's AMS error table (7 = target port not found, 1792 =
|
||||
/// ADSERR_DEVICE_SRVNOTSUPP, 1793 = ADSERR_DEVICE_INVALIDGRP, 1794 =
|
||||
/// ADSERR_DEVICE_INVALIDOFFSET, 1798 = ADSERR_DEVICE_SYMBOLNOTFOUND, 1808 =
|
||||
/// ADSERR_DEVICE_ACCESSDENIED, 1861 = ADSERR_CLIENT_SYNCTIMEOUT).
|
||||
/// Map an AMS / ADS error code (uint cast from <c>AdsErrorCode</c> enum) to an OPC UA
|
||||
/// StatusCode. 0 = success. Device-layer codes (0x0700–0x073F) cover the operations a
|
||||
/// driver actually encounters during normal runtime.
|
||||
/// </summary>
|
||||
public static uint MapAdsError(uint adsError) => adsError switch
|
||||
{
|
||||
0 => Good,
|
||||
6 or 7 => BadCommunicationError, // target port unreachable
|
||||
1792 => BadNotSupported, // service not supported
|
||||
1793 => BadOutOfRange, // invalid index group
|
||||
1794 => BadOutOfRange, // invalid index offset
|
||||
1798 => BadNodeIdUnknown, // symbol not found
|
||||
1807 => BadDeviceFailure, // device in invalid state
|
||||
1808 => BadNotWritable, // access denied
|
||||
1811 or 1812 => BadOutOfRange, // size mismatch
|
||||
1861 => BadTimeout, // sync timeout
|
||||
_ => BadCommunicationError,
|
||||
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,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user