feat(otopcua): add ITagDiscovery.RediscoverPolicy + per-driver assignments (follow-up B)
This commit is contained in:
@@ -1,5 +1,17 @@
|
|||||||
namespace ZB.MOM.WW.OtOpcUa.Core.Abstractions;
|
namespace ZB.MOM.WW.OtOpcUa.Core.Abstractions;
|
||||||
|
|
||||||
|
/// <summary>How aggressively the host re-runs post-connect discovery for this driver.</summary>
|
||||||
|
public enum DiscoveryRediscoverPolicy
|
||||||
|
{
|
||||||
|
/// <summary>Retry every interval up to the cap or until the captured set is non-empty and stable
|
||||||
|
/// (for drivers whose discovered shape fills in asynchronously after connect, e.g. the FOCAS FixedTree).</summary>
|
||||||
|
UntilStable,
|
||||||
|
/// <summary>Run exactly one discovery pass on connect (drivers that discover synchronously in DiscoverAsync).</summary>
|
||||||
|
Once,
|
||||||
|
/// <summary>Never run post-connect discovery.</summary>
|
||||||
|
Never,
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Driver capability for discovering tags and hierarchy from the backend.
|
/// Driver capability for discovering tags and hierarchy from the backend.
|
||||||
/// Streams discovered nodes into <see cref="IAddressSpaceBuilder"/> rather than
|
/// Streams discovered nodes into <see cref="IAddressSpaceBuilder"/> rather than
|
||||||
@@ -14,4 +26,7 @@ public interface ITagDiscovery
|
|||||||
/// <param name="builder">The address space builder to stream discovered nodes into.</param>
|
/// <param name="builder">The address space builder to stream discovered nodes into.</param>
|
||||||
/// <param name="cancellationToken">A cancellation token for the discovery operation.</param>
|
/// <param name="cancellationToken">A cancellation token for the discovery operation.</param>
|
||||||
Task DiscoverAsync(IAddressSpaceBuilder builder, CancellationToken cancellationToken);
|
Task DiscoverAsync(IAddressSpaceBuilder builder, CancellationToken cancellationToken);
|
||||||
|
|
||||||
|
/// <summary>Post-connect re-discovery policy. Default preserves the original retry-until-stable behavior.</summary>
|
||||||
|
DiscoveryRediscoverPolicy RediscoverPolicy => DiscoveryRediscoverPolicy.UntilStable;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -998,6 +998,14 @@ public sealed class AbCipDriver : IDriver, IReadable, IWritable, ITagDiscovery,
|
|||||||
|
|
||||||
// ---- ITagDiscovery ----
|
// ---- ITagDiscovery ----
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Run-once: <see cref="DiscoverAsync"/> emits pre-declared tags and (when
|
||||||
|
/// EnableControllerBrowse is set) fully awaits the @tags symbol-table walk + UDT-shape
|
||||||
|
/// resolution within the single call, streaming the complete node set in one pass —
|
||||||
|
/// nothing fills in asynchronously after connect, so a single discovery pass is sufficient.
|
||||||
|
/// </summary>
|
||||||
|
public DiscoveryRediscoverPolicy RediscoverPolicy => DiscoveryRediscoverPolicy.Once;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Stream the driver's tag set into the builder. Pre-declared tags from
|
/// Stream the driver's tag set into the builder. Pre-declared tags from
|
||||||
/// <see cref="AbCipDriverOptions.Tags"/> emit first; optionally, the
|
/// <see cref="AbCipDriverOptions.Tags"/> emit first; optionally, the
|
||||||
|
|||||||
@@ -422,6 +422,13 @@ public sealed class AbLegacyDriver : IDriver, IReadable, IWritable, ITagDiscover
|
|||||||
|
|
||||||
// ---- ITagDiscovery ----
|
// ---- ITagDiscovery ----
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Run-once: <see cref="DiscoverAsync"/> emits the complete node set synchronously from
|
||||||
|
/// the configured device/tag tables within a single pass — there is no shape that fills
|
||||||
|
/// in asynchronously after connect, so a single discovery pass is sufficient.
|
||||||
|
/// </summary>
|
||||||
|
public DiscoveryRediscoverPolicy RediscoverPolicy => DiscoveryRediscoverPolicy.Once;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Discovers tags and populates the address space asynchronously.
|
/// Discovers tags and populates the address space asynchronously.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -401,6 +401,14 @@ public sealed class FocasDriver : IDriver, IReadable, IWritable, ITagDiscovery,
|
|||||||
|
|
||||||
// ---- ITagDiscovery ----
|
// ---- ITagDiscovery ----
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retry-until-stable: the FixedTree subtree is filled in asynchronously by
|
||||||
|
/// <see cref="FixedTreeLoopAsync"/> a couple of seconds AFTER connect, so the first
|
||||||
|
/// post-connect <see cref="DiscoverAsync"/> pass would miss it — the host must re-run
|
||||||
|
/// discovery until the captured node set is non-empty and stable.
|
||||||
|
/// </summary>
|
||||||
|
public DiscoveryRediscoverPolicy RediscoverPolicy => DiscoveryRediscoverPolicy.UntilStable;
|
||||||
|
|
||||||
/// <summary>Discovers tags and builds the OPC UA address space asynchronously.</summary>
|
/// <summary>Discovers tags and builds the OPC UA address space asynchronously.</summary>
|
||||||
/// <param name="builder">The address space builder for constructing the OPC UA namespace.</param>
|
/// <param name="builder">The address space builder for constructing the OPC UA namespace.</param>
|
||||||
/// <param name="cancellationToken">Cancellation token for the operation.</param>
|
/// <param name="cancellationToken">Cancellation token for the operation.</param>
|
||||||
|
|||||||
@@ -826,6 +826,14 @@ public sealed class OpcUaClientDriver : IDriver, ITagDiscovery, IReadable, IWrit
|
|||||||
|
|
||||||
// ---- ITagDiscovery ----
|
// ---- ITagDiscovery ----
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Run-once: <see cref="DiscoverAsync"/> recursively browses the remote server's address
|
||||||
|
/// space and registers every variable within the single call (browse + enrich passes are
|
||||||
|
/// fully awaited) — nothing fills in asynchronously after connect, so a single discovery
|
||||||
|
/// pass is sufficient.
|
||||||
|
/// </summary>
|
||||||
|
public DiscoveryRediscoverPolicy RediscoverPolicy => DiscoveryRediscoverPolicy.Once;
|
||||||
|
|
||||||
/// <summary>Discovers the remote OPC UA server's address space and materializes it through the supplied builder.</summary>
|
/// <summary>Discovers the remote OPC UA server's address space and materializes it through the supplied builder.</summary>
|
||||||
/// <param name="builder">Address space builder for materializing discovered nodes.</param>
|
/// <param name="builder">Address space builder for materializing discovered nodes.</param>
|
||||||
/// <param name="cancellationToken">Cancellation token for the operation.</param>
|
/// <param name="cancellationToken">Cancellation token for the operation.</param>
|
||||||
|
|||||||
@@ -377,6 +377,14 @@ public sealed class TwinCATDriver : IDriver, IReadable, IWritable, ITagDiscovery
|
|||||||
|
|
||||||
// ---- ITagDiscovery ----
|
// ---- ITagDiscovery ----
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Run-once: <see cref="DiscoverAsync"/> emits pre-declared tags and (when
|
||||||
|
/// EnableControllerBrowse is set) fully awaits the controller symbol browse within the
|
||||||
|
/// single call, streaming the complete node set in one pass — nothing fills in
|
||||||
|
/// asynchronously after connect, so a single discovery pass is sufficient.
|
||||||
|
/// </summary>
|
||||||
|
public DiscoveryRediscoverPolicy RediscoverPolicy => DiscoveryRediscoverPolicy.Once;
|
||||||
|
|
||||||
/// <summary>Discovers devices and tags from ADS configuration and optionally controller symbols.</summary>
|
/// <summary>Discovers devices and tags from ADS configuration and optionally controller symbols.</summary>
|
||||||
/// <param name="builder">Address space builder for adding discovered nodes.</param>
|
/// <param name="builder">Address space builder for adding discovered nodes.</param>
|
||||||
/// <param name="cancellationToken">Cancellation token.</param>
|
/// <param name="cancellationToken">Cancellation token.</param>
|
||||||
|
|||||||
@@ -203,6 +203,18 @@ public sealed class FocasScaffoldingTests
|
|||||||
drv.DriverInstanceId.ShouldBe("drv-1");
|
drv.DriverInstanceId.ShouldBe("drv-1");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Verifies FOCAS opts into retry-until-stable post-connect re-discovery — its
|
||||||
|
/// FixedTree subtree is populated asynchronously by a background loop a couple of
|
||||||
|
/// seconds after connect, so a single DiscoverAsync pass would miss it.
|
||||||
|
/// </summary>
|
||||||
|
[Fact]
|
||||||
|
public void RediscoverPolicy_is_UntilStable()
|
||||||
|
{
|
||||||
|
var drv = new FocasDriver(new FocasDriverOptions(), "drv-1");
|
||||||
|
drv.RediscoverPolicy.ShouldBe(DiscoveryRediscoverPolicy.UntilStable);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>Verifies InitializeAsync parses device addresses correctly.</summary>
|
/// <summary>Verifies InitializeAsync parses device addresses correctly.</summary>
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task InitializeAsync_parses_device_addresses()
|
public async Task InitializeAsync_parses_device_addresses()
|
||||||
|
|||||||
Reference in New Issue
Block a user