fix(abcip): translate decode/encode-time libplctag exceptions; doc and probe-test cleanups
This commit is contained in:
@@ -834,8 +834,8 @@ public sealed class AbCipDriver : IDriver, IReadable, IWritable, ITagDiscovery,
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Transport exception — evict so the next read creates a fresh handle. A libplctag
|
||||
// exception carries its Status, so a tag the controller does not have reads
|
||||
// Transport exception — evict so the next read creates a fresh handle. An AbTransportException
|
||||
// carries its AbStatus, so a tag the controller does not have reads
|
||||
// BadNodeIdUnknown and a decode past the buffer BadOutOfRange, not a comms error.
|
||||
EvictRuntime(device, def.Name);
|
||||
results[fb.OriginalIndex] = new DataValueSnapshot(null,
|
||||
|
||||
@@ -18,19 +18,10 @@ namespace ZB.MOM.WW.OtOpcUa.Driver.AbCip;
|
||||
/// non-CIP server) returns <c>Ok = false</c> with a "handshake failed" message instead of
|
||||
/// a false-positive green tick.
|
||||
/// <para>
|
||||
/// Status-code discrimination: transport statuses (<c>AbStatus</c>) that indicate the controller answered
|
||||
/// the CIP session but could not resolve the probe tag
|
||||
/// (<c>ErrorNotFound</c>, <c>ErrorNoMatch</c>,
|
||||
/// <c>ErrorBadDevice</c>) are treated as "reachable — Ok = true" because
|
||||
/// a non-existent tag name proves CIP connectivity. Statuses that indicate a transport or
|
||||
/// session failure (<c>ErrorTimeout</c>, <c>ErrorBadConnection</c>,
|
||||
/// <c>ErrorBadGateway</c>, <c>ErrorWinsock</c>,
|
||||
/// <c>ErrorOpen</c>, <c>ErrorClose</c>,
|
||||
/// <c>ErrorRead</c>, <c>ErrorWrite</c>,
|
||||
/// <c>ErrorBadReply</c>, <c>ErrorRemoteErr</c>,
|
||||
/// <c>ErrorPartial</c>, <c>ErrorAbort</c>) are treated as
|
||||
/// "handshake failed — Ok = false". All other error statuses default to
|
||||
/// "handshake failed" (conservative).
|
||||
/// Status-code discrimination: <c>AbStatus.Ok</c> and <c>AbStatus.NotFound</c> mean the controller
|
||||
/// answered the CIP session (a non-existent probe tag name still proves CIP connectivity) and are
|
||||
/// treated as "reachable - Ok = true". Every other status (timeout, bad connection, bad reply,
|
||||
/// partial, abort, ...) is a transport or session failure: "handshake failed - Ok = false".
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public sealed class AbCipDriverProbe : IDriverProbe
|
||||
|
||||
@@ -28,7 +28,7 @@ public interface IAbCipTagRuntime : IDisposable
|
||||
/// Raw transport status code (an <c>AbStatus</c> value) — mapped to an OPC UA StatusCode via
|
||||
/// <see cref="AbCipStatusMapper.MapStatus(int)"/>. Zero on success, negative on error.
|
||||
/// </summary>
|
||||
/// <returns>The raw libplctag status code (zero on success, negative on error).</returns>
|
||||
/// <returns>The <c>AbStatus</c> value (zero on success, negative on error).</returns>
|
||||
int GetStatus();
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -55,4 +55,22 @@ internal static class LibplctagStatusTranslation
|
||||
try { return await op().ConfigureAwait(false); }
|
||||
catch (LibPlcTagException ex) { throw new AbTransportException(ToAbStatus(ex), ex.Message, ex); }
|
||||
}
|
||||
|
||||
/// <summary>Runs a synchronous libplctag call, rethrowing <see cref="LibPlcTagException"/> as <see cref="AbTransportException"/>.</summary>
|
||||
/// <typeparam name="T">The result type.</typeparam>
|
||||
/// <param name="op">The libplctag call.</param>
|
||||
/// <returns>The call result.</returns>
|
||||
public static T WrapSync<T>(Func<T> op)
|
||||
{
|
||||
try { return op(); }
|
||||
catch (LibPlcTagException ex) { throw new AbTransportException(ToAbStatus(ex), ex.Message, ex); }
|
||||
}
|
||||
|
||||
/// <summary>Runs a synchronous libplctag call, rethrowing <see cref="LibPlcTagException"/> as <see cref="AbTransportException"/>.</summary>
|
||||
/// <param name="op">The libplctag call.</param>
|
||||
public static void WrapSync(Action op)
|
||||
{
|
||||
try { op(); }
|
||||
catch (LibPlcTagException ex) { throw new AbTransportException(ToAbStatus(ex), ex.Message, ex); }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,13 +51,16 @@ internal sealed class LibplctagTagRuntime : IAbCipTagRuntime
|
||||
public int GetStatus() => (int)LibplctagStatusTranslation.ToAbStatus(_tag.GetStatus());
|
||||
|
||||
/// <inheritdoc />
|
||||
public int GetSize() => _tag.GetSize();
|
||||
public int GetSize() => LibplctagStatusTranslation.WrapSync(() => _tag.GetSize());
|
||||
|
||||
/// <inheritdoc />
|
||||
public object? DecodeValue(AbCipDataType type, int? bitIndex) => DecodeValueAt(type, 0, bitIndex);
|
||||
|
||||
/// <inheritdoc />
|
||||
public object? DecodeValueAt(AbCipDataType type, int offset, int? bitIndex) => type switch
|
||||
public object? DecodeValueAt(AbCipDataType type, int offset, int? bitIndex) =>
|
||||
LibplctagStatusTranslation.WrapSync(() => DecodeValueAtCore(type, offset, bitIndex));
|
||||
|
||||
private object? DecodeValueAtCore(AbCipDataType type, int offset, int? bitIndex) => type switch
|
||||
{
|
||||
AbCipDataType.Bool => bitIndex is int bit
|
||||
? _tag.GetBit(bit)
|
||||
@@ -79,7 +82,10 @@ internal sealed class LibplctagTagRuntime : IAbCipTagRuntime
|
||||
};
|
||||
|
||||
/// <inheritdoc />
|
||||
public object? DecodeArray(AbCipDataType type, int count)
|
||||
public object? DecodeArray(AbCipDataType type, int count) =>
|
||||
LibplctagStatusTranslation.WrapSync(() => DecodeArrayCore(type, count));
|
||||
|
||||
private object? DecodeArrayCore(AbCipDataType type, int count)
|
||||
{
|
||||
if (count < 1) count = 1;
|
||||
// libplctag reports the per-element byte size once the tag has been read; it correctly
|
||||
@@ -160,7 +166,10 @@ internal sealed class LibplctagTagRuntime : IAbCipTagRuntime
|
||||
};
|
||||
|
||||
/// <inheritdoc />
|
||||
public void EncodeValue(AbCipDataType type, int? bitIndex, object? value)
|
||||
public void EncodeValue(AbCipDataType type, int? bitIndex, object? value) =>
|
||||
LibplctagStatusTranslation.WrapSync(() => EncodeValueCore(type, bitIndex, value));
|
||||
|
||||
private void EncodeValueCore(AbCipDataType type, int? bitIndex, object? value)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user