Files
lmxopcua/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/TwinCATNotificationRefusedException.cs
T
Joseph Doherty dcc35f3481 feat(twincat): native ADS notifications for array tags, decoded from raw bytes
An array tag subscribed natively used to register only its declared scalar
(publishing element 0 at Good) and was then refused wholesale with
BadTypeMismatch. The driver now hands the authored ArrayLength to the client,
which registers the whole array as raw bytes and decodes every notification.

- TwinCATTypeGuard.CheckArray plans the layout from the RESOLVED array type:
  element checked like a scalar notification (width / float kind / string
  kind); STRING(n)/WSTRING(n) elements stride n+1 / 2(n+1); multi-dim arrays
  flattened in PLC memory order; an authored ArrayLength shorter than the PLC
  array reads the leading sub-range, a longer one is refused; struct / pointer
  / nested-array elements, non-array symbols and VAR_IN_OUT refs are refused.
- CheckNotificationSize caps a native array at 128 KiB (largest registration
  proven on a live TC 2.11 target); above it the tag is refused BadOutOfRange.
- TwinCATArrayCodec decodes the bytes into the element-typed CLR array.
- The poll read uses the same plan + codec instead of the Beckhoff typed array
  read, which failed live for most real arrays (exact CLR element type, rank-N
  for multi-dim, member arrays sliced by the under-reported TC2 symbol size).
- TwinCATNotificationRefusedException carries the refusal's status; the type
  mismatch derives from it and the driver isolates either per tag.
2026-10-07 14:45:35 -04:00

29 lines
1.4 KiB
C#

namespace ZB.MOM.WW.OtOpcUa.Driver.TwinCAT;
/// <summary>
/// Thrown by <see cref="ITwinCATClient.AddNotificationAsync"/> when the client refuses to register a
/// native notification for one tag — its declared type cannot decode the PLC symbol
/// (<see cref="TwinCATTypeMismatchException"/>), or an array is too large for a native notification.
/// The driver isolates that one tag to <see cref="StatusCode"/> (one WARN) and keeps the rest of the
/// subscription; the intent stays registered so the probe-tick retry re-checks it.
/// </summary>
internal class TwinCATNotificationRefusedException : Exception
{
/// <summary>Initializes a new instance of the <see cref="TwinCATNotificationRefusedException"/> class.</summary>
/// <param name="symbolPath">The ADS symbol the tag names.</param>
/// <param name="reason">The one-line reason.</param>
/// <param name="statusCode">The OPC UA status the refused tag publishes.</param>
public TwinCATNotificationRefusedException(string symbolPath, string reason, uint statusCode)
: base($"TwinCAT symbol '{symbolPath}': {reason}")
{
SymbolPath = symbolPath;
StatusCode = statusCode;
}
/// <summary>Gets the ADS symbol the refused tag names.</summary>
public string SymbolPath { get; }
/// <summary>Gets the OPC UA status the refused tag publishes.</summary>
public uint StatusCode { get; }
}