feat(abcip): Transport option selects native or libplctag across driver, probe and CLI

This commit is contained in:
Joseph Doherty
2026-10-07 17:13:37 -04:00
parent 1211cd9a83
commit 45f6e1793f
10 changed files with 252 additions and 8 deletions
@@ -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()),
};
}