feat(abcip): Transport option selects native or libplctag across driver, probe and CLI
This commit is contained in:
@@ -26,6 +26,11 @@ public abstract class AbCipCommandBase : DriverCommandBase
|
||||
"ControlLogix / CompactLogix / Micro800 / GuardLogix (default ControlLogix).")]
|
||||
public AbCipPlcFamily Family { get; init; } = AbCipPlcFamily.ControlLogix;
|
||||
|
||||
/// <summary>Gets the transport stack used to reach the PLC.</summary>
|
||||
[CommandOption("transport", Description =
|
||||
"Transport stack: libplctag (default) or native (managed EtherNet/IP + CIP).")]
|
||||
public AbCipTransport Transport { get; init; } = AbCipTransport.Libplctag;
|
||||
|
||||
/// <summary>Gets the per-operation timeout in milliseconds.</summary>
|
||||
[CommandOption("timeout-ms", Description = "Per-operation timeout in ms (default 5000).")]
|
||||
public int TimeoutMs { get; init; } = 5000;
|
||||
@@ -68,6 +73,7 @@ public abstract class AbCipCommandBase : DriverCommandBase
|
||||
WriteIdempotent: t.WriteIdempotent,
|
||||
DeviceName: t.DeviceHostAddress))],
|
||||
Timeout = Timeout,
|
||||
Transport = Transport,
|
||||
Probe = new AbCipProbeOptions { Enabled = false },
|
||||
EnableControllerBrowse = false,
|
||||
EnableAlarmProjection = false,
|
||||
|
||||
@@ -6,6 +6,6 @@ return await new CliApplicationBuilder()
|
||||
.SetDescription(
|
||||
"OtOpcUa AB CIP test-client — ad-hoc probe + Logix symbolic reads/writes + polled " +
|
||||
"subscriptions against ControlLogix / CompactLogix / Micro800 / GuardLogix families " +
|
||||
"via libplctag. Second of six driver CLIs; mirrors otopcua-modbus-cli's shape.")
|
||||
"via libplctag or the native transport. Second of six driver CLIs; mirrors otopcua-modbus-cli's shape.")
|
||||
.Build()
|
||||
.RunAsync(args);
|
||||
|
||||
@@ -32,6 +32,16 @@ public sealed class AbCipDriverOptions
|
||||
/// </summary>
|
||||
public IReadOnlyList<RawTagEntry> RawTags { get; init; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Which transport stack the driver, its Test Connect probe and the CLI use. Defaults to
|
||||
/// <see cref="AbCipTransport.Libplctag"/>.
|
||||
/// <para>Changing this takes effect when the driver instance is RECREATED, not on
|
||||
/// <c>ReinitializeAsync</c>: the factories are chosen once in the constructor and held across
|
||||
/// Shutdown+Initialize. A deploy that changes the driver config stops and respawns the instance
|
||||
/// (<c>DriverSpawnPlanner</c>, #516), so an operator edit does recreate it.</para>
|
||||
/// </summary>
|
||||
public AbCipTransport Transport { get; init; } = AbCipTransport.Libplctag;
|
||||
|
||||
/// <summary>Per-device probe settings. Falls back to defaults when omitted.</summary>
|
||||
public AbCipProbeOptions Probe { get; init; } = new();
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
namespace ZB.MOM.WW.OtOpcUa.Driver.AbCip;
|
||||
|
||||
/// <summary>
|
||||
/// Which CIP transport stack an AbCip driver instance (and its Test Connect probe / CLI run)
|
||||
/// talks to the controller through. Serialises as a STRING in driver config JSON.
|
||||
/// </summary>
|
||||
public enum AbCipTransport
|
||||
{
|
||||
/// <summary>The libplctag-backed transport. The default.</summary>
|
||||
Libplctag,
|
||||
|
||||
/// <summary>The native managed EtherNet/IP + CIP transport (shared Driver.Ab.Transport stack).</summary>
|
||||
Native,
|
||||
}
|
||||
@@ -150,9 +150,12 @@ public sealed class AbCipDriver : IDriver, IReadable, IWritable, ITagDiscovery,
|
||||
ArgumentNullException.ThrowIfNull(options);
|
||||
_options = options;
|
||||
_driverInstanceId = driverInstanceId;
|
||||
_tagFactory = tagFactory ?? new LibplctagTagFactory();
|
||||
_enumeratorFactory = enumeratorFactory ?? new LibplctagTagEnumeratorFactory();
|
||||
_templateReaderFactory = templateReaderFactory ?? new LibplctagTemplateReaderFactory();
|
||||
// Chosen once here and held across ReinitializeAsync (Shutdown+Initialize): a changed
|
||||
// Transport in a reinit config is inert; a deploy recreates the instance instead.
|
||||
var defaults = AbCipTransportFactories.For(options.Transport);
|
||||
_tagFactory = tagFactory ?? defaults.Tags;
|
||||
_enumeratorFactory = enumeratorFactory ?? defaults.Enumerators;
|
||||
_templateReaderFactory = templateReaderFactory ?? defaults.Templates;
|
||||
_logger = logger ?? NullLogger<AbCipDriver>.Instance;
|
||||
_resolver = new EquipmentTagRefResolver<AbCipTagDefinition>(
|
||||
r => _tagsByRawPath.TryGetValue(r, out var t) ? t : null);
|
||||
@@ -172,6 +175,9 @@ public sealed class AbCipDriver : IDriver, IReadable, IWritable, ITagDiscovery,
|
||||
_alarmProjection = new AbCipAlarmProjection(this, _options.AlarmPollInterval, _logger);
|
||||
}
|
||||
|
||||
/// <summary>The tag factory chosen at construction; exposed so tests can pin transport selection.</summary>
|
||||
internal IAbCipTagFactory TagFactory => _tagFactory;
|
||||
|
||||
/// <summary>Upper bound on the poll-loop failure backoff — adopts the S7-proven 30 s cap fleet-wide (05/STAB-8).</summary>
|
||||
private static readonly TimeSpan PollBackoffCap = TimeSpan.FromSeconds(30);
|
||||
|
||||
|
||||
@@ -81,6 +81,8 @@ public static class AbCipDriverFactoryExtensions
|
||||
ProbeTagPath = dto.Probe?.ProbeTagPath,
|
||||
},
|
||||
Timeout = PositiveTimeoutOrDefault(dto.TimeoutMs, 2_000),
|
||||
Transport = ParseEnum<AbCipTransport>(dto.Transport, "driver", driverInstanceId, "Transport",
|
||||
fallback: AbCipTransport.Libplctag),
|
||||
EnableControllerBrowse = dto.EnableControllerBrowse ?? false,
|
||||
EnableAlarmProjection = dto.EnableAlarmProjection ?? false,
|
||||
AlarmPollInterval = TimeSpan.FromMilliseconds(dto.AlarmPollIntervalMs ?? 1_000),
|
||||
@@ -128,6 +130,11 @@ public static class AbCipDriverFactoryExtensions
|
||||
|
||||
internal sealed class AbCipDriverConfigDto
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the transport (<c>Libplctag</c> or <c>Native</c>, case-insensitive); absent means Libplctag.
|
||||
/// </summary>
|
||||
public string? Transport { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the timeout in milliseconds for operations.
|
||||
/// </summary>
|
||||
|
||||
@@ -33,11 +33,12 @@ public sealed class AbCipDriverProbe : IDriverProbe
|
||||
Converters = { new JsonStringEnumConverter() },
|
||||
};
|
||||
|
||||
private readonly IAbCipTagFactory _tagFactory;
|
||||
private readonly IAbCipTagFactory? _tagFactory;
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="AbCipDriverProbe"/> class.</summary>
|
||||
/// <param name="tagFactory">Factory for the probe's tag runtime; defaults to the libplctag-backed one.</param>
|
||||
public AbCipDriverProbe(IAbCipTagFactory? tagFactory = null) => _tagFactory = tagFactory ?? new LibplctagTagFactory();
|
||||
/// <param name="tagFactory">Factory for the probe's tag runtime; when null the config's
|
||||
/// <c>Transport</c> selects the native or libplctag-backed one.</param>
|
||||
public AbCipDriverProbe(IAbCipTagFactory? tagFactory = null) => _tagFactory = tagFactory;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string DriverType => "AbCip";
|
||||
@@ -122,7 +123,7 @@ public sealed class AbCipDriverProbe : IDriverProbe
|
||||
ConnectionSize: firstDevice?.ConnectionSize ?? profile.DefaultConnectionSize,
|
||||
UseConnectedMessaging: profile.SupportsConnectedMessaging);
|
||||
|
||||
var rt = _tagFactory.Create(p);
|
||||
var rt = (_tagFactory ?? AbCipTransportFactories.For(opts.Transport).Tags).Create(p);
|
||||
try
|
||||
{
|
||||
await rt.InitializeAsync(cts.Token);
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
namespace ZB.MOM.WW.OtOpcUa.Driver.AbCip;
|
||||
|
||||
/// <summary>Maps an <see cref="AbCipTransport"/> to the matching trio of runtime factories.</summary>
|
||||
internal static class AbCipTransportFactories
|
||||
{
|
||||
/// <summary>Returns the tag, enumerator and template-reader factories for <paramref name="transport"/>.</summary>
|
||||
public static (IAbCipTagFactory Tags, IAbCipTagEnumeratorFactory Enumerators, IAbCipTemplateReaderFactory Templates)
|
||||
For(AbCipTransport transport) => transport switch
|
||||
{
|
||||
AbCipTransport.Native => (new NativeAbCipTagFactory(), new NativeAbCipTagEnumeratorFactory(),
|
||||
new NativeAbCipTemplateReaderFactory()),
|
||||
_ => (new LibplctagTagFactory(), new LibplctagTagEnumeratorFactory(), new LibplctagTemplateReaderFactory()),
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user