refactor(ablegacy): confine libplctag to its adapter behind AbStatus/AbTransportException
This commit is contained in:
@@ -2,7 +2,7 @@ using System.Diagnostics;
|
||||
using System.Net.Sockets;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using libplctag;
|
||||
using ZB.MOM.WW.OtOpcUa.Driver.Ab.Transport;
|
||||
using ZB.MOM.WW.OtOpcUa.Core.Abstractions;
|
||||
using ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.PlcFamilies;
|
||||
|
||||
@@ -18,23 +18,25 @@ namespace ZB.MOM.WW.OtOpcUa.Driver.AbLegacy;
|
||||
/// non-PCCC server) returns <c>Ok = false</c> with a "handshake failed" message instead of
|
||||
/// a false-positive green tick.
|
||||
/// <para>
|
||||
/// Status-code discrimination: libplctag statuses that indicate the controller answered
|
||||
/// Status-code discrimination: transport statuses that indicate the controller answered
|
||||
/// the PCCC session but could not resolve the probe tag
|
||||
/// (<see cref="Status.ErrorNotFound"/>, <see cref="Status.ErrorNoMatch"/>,
|
||||
/// <see cref="Status.ErrorBadDevice"/>) are treated as "reachable — Ok = true" because
|
||||
/// (<see cref="AbStatus.NotFound"/>) are treated as "reachable — Ok = true" because
|
||||
/// a non-existent tag name proves PCCC connectivity. Statuses that indicate a transport or
|
||||
/// session failure (<see cref="Status.ErrorTimeout"/>, <see cref="Status.ErrorBadConnection"/>,
|
||||
/// <see cref="Status.ErrorBadGateway"/>, <see cref="Status.ErrorWinsock"/>,
|
||||
/// <see cref="Status.ErrorOpen"/>, <see cref="Status.ErrorClose"/>,
|
||||
/// <see cref="Status.ErrorRead"/>, <see cref="Status.ErrorWrite"/>,
|
||||
/// <see cref="Status.ErrorBadReply"/>, <see cref="Status.ErrorRemoteErr"/>,
|
||||
/// <see cref="Status.ErrorPartial"/>, <see cref="Status.ErrorAbort"/>) are treated as
|
||||
/// session failure (<see cref="AbStatus.Timeout"/>, <see cref="AbStatus.BadConnection"/>,
|
||||
/// <see cref="AbStatus.BadReply"/>, <see cref="AbStatus.Partial"/>, <see cref="AbStatus.Abort"/>) are treated as
|
||||
/// "handshake failed — Ok = false". All other error statuses default to
|
||||
/// "handshake failed" (conservative).
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public sealed class AbLegacyDriverProbe : IDriverProbe
|
||||
{
|
||||
private readonly IAbLegacyTagFactory _tagFactory;
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="AbLegacyDriverProbe"/> class.</summary>
|
||||
/// <param name="tagFactory">The tag factory used for the PCCC handshake; defaults to the libplctag-backed one.</param>
|
||||
public AbLegacyDriverProbe(IAbLegacyTagFactory? tagFactory = null) =>
|
||||
_tagFactory = tagFactory ?? new LibplctagLegacyTagFactory();
|
||||
|
||||
private static readonly JsonSerializerOptions _opts = new()
|
||||
{
|
||||
PropertyNameCaseInsensitive = true,
|
||||
@@ -104,7 +106,7 @@ public sealed class AbLegacyDriverProbe : IDriverProbe
|
||||
TagName: tagName,
|
||||
Timeout: timeout);
|
||||
|
||||
var rt = new LibplctagLegacyTagRuntime(p);
|
||||
var rt = _tagFactory.Create(p);
|
||||
try
|
||||
{
|
||||
await rt.InitializeAsync(cts.Token);
|
||||
@@ -112,10 +114,10 @@ public sealed class AbLegacyDriverProbe : IDriverProbe
|
||||
|
||||
// InitializeAsync completed without throwing — either the tag was found (Ok) or
|
||||
// libplctag returned a non-exception status. Check via GetStatus().
|
||||
var statusCode = (Status)rt.GetStatus();
|
||||
var statusCode = (AbStatus)rt.GetStatus();
|
||||
if (IsReachableStatus(statusCode))
|
||||
{
|
||||
var msg = statusCode == Status.Ok
|
||||
var msg = statusCode == AbStatus.Ok
|
||||
? "PCCC session OK"
|
||||
: "PCCC session OK (controller reachable; probe tag not found)";
|
||||
return new(true, msg, sw.Elapsed);
|
||||
@@ -128,10 +130,10 @@ public sealed class AbLegacyDriverProbe : IDriverProbe
|
||||
{
|
||||
return new(false, $"Probe timed out after {timeout.TotalSeconds:F0}s.", null);
|
||||
}
|
||||
catch (LibPlcTagException ex)
|
||||
catch (AbTransportException ex)
|
||||
{
|
||||
// LibPlcTagException carries the Status; classify as reachable vs transport failure.
|
||||
if (IsReachableException(ex))
|
||||
// AbTransportException carries the Status; classify as reachable vs transport failure.
|
||||
if (IsReachableStatus(ex.Status))
|
||||
{
|
||||
sw.Stop();
|
||||
return new(true, "PCCC session OK (controller reachable; probe tag not found)", sw.Elapsed);
|
||||
@@ -150,30 +152,13 @@ public sealed class AbLegacyDriverProbe : IDriverProbe
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns <c>true</c> for libplctag statuses that indicate the PCCC controller answered
|
||||
/// but the probe tag name was not found or did not match — sufficient to confirm PCCC
|
||||
/// reachability. Returns <c>true</c> for <see cref="Status.Ok"/> (tag was found).
|
||||
/// Returns <c>true</c> for statuses that indicate the PCCC controller answered but the
|
||||
/// probe tag was not found — sufficient to confirm PCCC reachability. Also <c>true</c> for
|
||||
/// <see cref="AbStatus.Ok"/> (tag was found).
|
||||
/// </summary>
|
||||
private static bool IsReachableStatus(Status s) => s is
|
||||
Status.Ok or
|
||||
Status.ErrorNotFound or
|
||||
Status.ErrorNoMatch or
|
||||
Status.ErrorBadDevice;
|
||||
|
||||
/// <summary>
|
||||
/// Inspects a <see cref="LibPlcTagException"/> message to decide whether the error is a
|
||||
/// "controller answered PCCC but tag not found" condition (reachable) versus a session /
|
||||
/// transport failure (unreachable). Falls back to checking the exception message for
|
||||
/// known tag-not-found phrases used by the libplctag native library.
|
||||
/// </summary>
|
||||
private static bool IsReachableException(LibPlcTagException ex)
|
||||
{
|
||||
// libplctag wraps the Status in the message as "STATUS_NOT_FOUND", "STATUS_NO_MATCH", etc.
|
||||
var msg = ex.Message ?? string.Empty;
|
||||
return msg.Contains("NOT_FOUND", StringComparison.OrdinalIgnoreCase)
|
||||
|| msg.Contains("NO_MATCH", StringComparison.OrdinalIgnoreCase)
|
||||
|| msg.Contains("BAD_DEVICE", StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
/// <param name="s">The transport status.</param>
|
||||
/// <returns>Whether the status proves the controller answered.</returns>
|
||||
internal static bool IsReachableStatus(AbStatus s) => s is AbStatus.Ok or AbStatus.NotFound;
|
||||
|
||||
private static (AbLegacyHostAddress? parsed, AbLegacyDeviceOptions? device) ExtractTarget(AbLegacyDriverOptions opts)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user