docs: backfill XML documentation across 756 files
v2-ci / build (push) Failing after 1m43s
v2-ci / unit-tests (tests/Core/ZB.MOM.WW.OtOpcUa.Cluster.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.ControlPlane.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Security.Tests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests) (push) Has been skipped
v2-ci / build (push) Failing after 1m43s
v2-ci / unit-tests (tests/Core/ZB.MOM.WW.OtOpcUa.Cluster.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.ControlPlane.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Security.Tests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests) (push) Has been skipped
Adds <summary>, <param>, <typeparam>, and <inheritdoc/> tags to public members surfaced by commentchecker — resolves 5,847 of 5,869 issues (99.6%) across three /fixdocs passes.
This commit is contained in:
@@ -29,10 +29,18 @@ public sealed class TwinCATDriver : IDriver, IReadable, IWritable, ITagDiscovery
|
||||
new(StringComparer.OrdinalIgnoreCase);
|
||||
private DriverHealth _health = new(DriverState.Unknown, null, null);
|
||||
|
||||
/// <summary>Occurs when a subscribed tag value changes.</summary>
|
||||
public event EventHandler<DataChangeEventArgs>? OnDataChange;
|
||||
/// <summary>Occurs when a device host connectivity status changes.</summary>
|
||||
public event EventHandler<HostStatusChangedEventArgs>? OnHostStatusChanged;
|
||||
/// <summary>Occurs when the Galaxy object hierarchy or TwinCAT symbol table is rediscovered.</summary>
|
||||
public event EventHandler<RediscoveryEventArgs>? OnRediscoveryNeeded;
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="TwinCATDriver"/> class.</summary>
|
||||
/// <param name="options">Driver configuration options.</param>
|
||||
/// <param name="driverInstanceId">Unique driver instance identifier.</param>
|
||||
/// <param name="clientFactory">Optional ADS client factory; defaults to <see cref="AdsTwinCATClientFactory"/>.</param>
|
||||
/// <param name="logger">Optional logger; defaults to <see cref="NullLogger{TwinCATDriver}"/>.</param>
|
||||
public TwinCATDriver(TwinCATDriverOptions options, string driverInstanceId,
|
||||
ITwinCATClientFactory? clientFactory = null,
|
||||
ILogger<TwinCATDriver>? logger = null)
|
||||
@@ -48,9 +56,15 @@ public sealed class TwinCATDriver : IDriver, IReadable, IWritable, ITagDiscovery
|
||||
OnDataChange?.Invoke(this, new DataChangeEventArgs(handle, tagRef, snapshot)));
|
||||
}
|
||||
|
||||
/// <summary>Gets the unique driver instance identifier.</summary>
|
||||
public string DriverInstanceId => _driverInstanceId;
|
||||
/// <summary>Gets the driver type name.</summary>
|
||||
public string DriverType => "TwinCAT";
|
||||
|
||||
/// <summary>Initializes the driver with configuration and establishes device connections.</summary>
|
||||
/// <param name="driverConfigJson">JSON configuration string for the driver.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>Completion task.</returns>
|
||||
public Task InitializeAsync(string driverConfigJson, CancellationToken cancellationToken)
|
||||
{
|
||||
_health = new DriverHealth(DriverState.Initializing, null, null);
|
||||
@@ -95,12 +109,19 @@ public sealed class TwinCATDriver : IDriver, IReadable, IWritable, ITagDiscovery
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>Reinitializes the driver by shutting down and reinitializing with new configuration.</summary>
|
||||
/// <param name="driverConfigJson">JSON configuration string for the driver.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>Completion task.</returns>
|
||||
public async Task ReinitializeAsync(string driverConfigJson, CancellationToken cancellationToken)
|
||||
{
|
||||
await ShutdownAsync(cancellationToken).ConfigureAwait(false);
|
||||
await InitializeAsync(driverConfigJson, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>Shuts down the driver and releases all device connections and subscriptions.</summary>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>Completion task.</returns>
|
||||
public async Task ShutdownAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
// Native subs first — disposing the handles is cheap + lets the client close its
|
||||
@@ -133,6 +154,8 @@ public sealed class TwinCATDriver : IDriver, IReadable, IWritable, ITagDiscovery
|
||||
_health = new DriverHealth(DriverState.Unknown, _health.LastSuccessfulRead, null);
|
||||
}
|
||||
|
||||
/// <summary>Gets the current driver health status.</summary>
|
||||
/// <returns>Driver health information.</returns>
|
||||
public DriverHealth GetHealth() => _health;
|
||||
|
||||
/// <summary>
|
||||
@@ -150,14 +173,24 @@ public sealed class TwinCATDriver : IDriver, IReadable, IWritable, ITagDiscovery
|
||||
/// every <see cref="DiscoverAsync"/> call. This is a no-op but is deliberately present
|
||||
/// so Core's cache-budget enforcement sees a compliant Tier-A driver.
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>Completion task.</returns>
|
||||
public Task FlushOptionalCachesAsync(CancellationToken cancellationToken) => Task.CompletedTask;
|
||||
|
||||
/// <summary>Gets the count of configured devices.</summary>
|
||||
internal int DeviceCount => _devices.Count;
|
||||
/// <summary>Gets the device state for the specified host address.</summary>
|
||||
/// <param name="hostAddress">The ADS host address.</param>
|
||||
/// <returns>Device state or null if not found.</returns>
|
||||
internal DeviceState? GetDeviceState(string hostAddress) =>
|
||||
_devices.TryGetValue(hostAddress, out var s) ? s : null;
|
||||
|
||||
// ---- IReadable ----
|
||||
|
||||
/// <summary>Reads values for the specified tag references from ADS devices.</summary>
|
||||
/// <param name="fullReferences">The full tag references to read.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>Data value snapshots for each reference.</returns>
|
||||
public async Task<IReadOnlyList<DataValueSnapshot>> ReadAsync(
|
||||
IReadOnlyList<string> fullReferences, CancellationToken cancellationToken)
|
||||
{
|
||||
@@ -212,6 +245,10 @@ public sealed class TwinCATDriver : IDriver, IReadable, IWritable, ITagDiscovery
|
||||
|
||||
// ---- IWritable ----
|
||||
|
||||
/// <summary>Writes values to the specified tags on ADS devices.</summary>
|
||||
/// <param name="writes">The write requests to execute.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>Write results for each request.</returns>
|
||||
public async Task<IReadOnlyList<WriteResult>> WriteAsync(
|
||||
IReadOnlyList<WriteRequest> writes, CancellationToken cancellationToken)
|
||||
{
|
||||
@@ -272,6 +309,10 @@ public sealed class TwinCATDriver : IDriver, IReadable, IWritable, ITagDiscovery
|
||||
|
||||
// ---- ITagDiscovery ----
|
||||
|
||||
/// <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="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>Completion task.</returns>
|
||||
public async Task DiscoverAsync(IAddressSpaceBuilder builder, CancellationToken cancellationToken)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(builder);
|
||||
@@ -352,6 +393,10 @@ public sealed class TwinCATDriver : IDriver, IReadable, IWritable, ITagDiscovery
|
||||
/// target's PLC runtime — the PLC pushes changes on its own cycle so we skip the poll
|
||||
/// loop entirely. Unsub path disposes the handles.
|
||||
/// </summary>
|
||||
/// <param name="fullReferences">The full tag references to subscribe to.</param>
|
||||
/// <param name="publishingInterval">The publishing interval for updates.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>Subscription handle for managing the subscription.</returns>
|
||||
public async Task<ISubscriptionHandle> SubscribeAsync(
|
||||
IReadOnlyList<string> fullReferences, TimeSpan publishingInterval, CancellationToken cancellationToken)
|
||||
{
|
||||
@@ -402,6 +447,10 @@ public sealed class TwinCATDriver : IDriver, IReadable, IWritable, ITagDiscovery
|
||||
return handle;
|
||||
}
|
||||
|
||||
/// <summary>Unsubscribes from a native or poll-based subscription.</summary>
|
||||
/// <param name="handle">The subscription handle to unsubscribe.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>Completion task.</returns>
|
||||
public Task UnsubscribeAsync(ISubscriptionHandle handle, CancellationToken cancellationToken)
|
||||
{
|
||||
if (handle is NativeSubscriptionHandle native && _nativeSubs.TryRemove(native.Id, out var sub))
|
||||
@@ -415,6 +464,7 @@ public sealed class TwinCATDriver : IDriver, IReadable, IWritable, ITagDiscovery
|
||||
|
||||
private sealed record NativeSubscriptionHandle(long Id) : ISubscriptionHandle
|
||||
{
|
||||
/// <summary>Gets the diagnostic identifier for the subscription.</summary>
|
||||
public string DiagnosticId => $"twincat-native-sub-{Id}";
|
||||
}
|
||||
|
||||
@@ -424,6 +474,8 @@ public sealed class TwinCATDriver : IDriver, IReadable, IWritable, ITagDiscovery
|
||||
|
||||
// ---- IHostConnectivityProbe ----
|
||||
|
||||
/// <summary>Gets the connectivity status for all configured devices.</summary>
|
||||
/// <returns>List of host connectivity statuses.</returns>
|
||||
public IReadOnlyList<HostConnectivityStatus> GetHostStatuses() =>
|
||||
[.. _devices.Values.Select(s => new HostConnectivityStatus(s.Options.HostAddress, s.HostState, s.HostStateChangedUtc))];
|
||||
|
||||
@@ -484,6 +536,9 @@ public sealed class TwinCATDriver : IDriver, IReadable, IWritable, ITagDiscovery
|
||||
/// </summary>
|
||||
public const string UnresolvedHostSentinel = "";
|
||||
|
||||
/// <summary>Resolves the device host address for the specified tag reference.</summary>
|
||||
/// <param name="fullReference">The full tag reference.</param>
|
||||
/// <returns>The host address or <see cref="UnresolvedHostSentinel"/> if not found.</returns>
|
||||
public string ResolveHost(string fullReference)
|
||||
{
|
||||
if (_tagsByName.TryGetValue(fullReference, out var def))
|
||||
@@ -573,6 +628,7 @@ public sealed class TwinCATDriver : IDriver, IReadable, IWritable, ITagDiscovery
|
||||
/// cancel tokens, wait on task handles with a hard timeout, dispose clients — so a
|
||||
/// synchronous path does the right thing without re-entering the scheduler.
|
||||
/// </summary>
|
||||
/// <summary>Synchronously disposes driver resources without awaiting async operations.</summary>
|
||||
public void Dispose()
|
||||
{
|
||||
// Dispose native subscriptions first — handle disposal is sync.
|
||||
@@ -602,32 +658,43 @@ public sealed class TwinCATDriver : IDriver, IReadable, IWritable, ITagDiscovery
|
||||
_health = new DriverHealth(DriverState.Unknown, _health.LastSuccessfulRead, null);
|
||||
}
|
||||
|
||||
/// <summary>Asynchronously disposes driver resources.</summary>
|
||||
/// <returns>Completion task.</returns>
|
||||
public async ValueTask DisposeAsync() => await ShutdownAsync(CancellationToken.None).ConfigureAwait(false);
|
||||
|
||||
internal sealed class DeviceState(TwinCATAmsAddress parsedAddress, TwinCATDeviceOptions options)
|
||||
{
|
||||
/// <summary>Gets the parsed AMS address for the device.</summary>
|
||||
public TwinCATAmsAddress ParsedAddress { get; } = parsedAddress;
|
||||
/// <summary>Gets the device configuration options.</summary>
|
||||
public TwinCATDeviceOptions Options { get; } = options;
|
||||
/// <summary>Gets or sets the active ADS client for this device.</summary>
|
||||
public ITwinCATClient? Client { get; set; }
|
||||
|
||||
/// <summary>Serializes connect / reconnect so concurrent callers never race a client
|
||||
/// create-or-dispose for this device (Driver.TwinCAT-007).</summary>
|
||||
public SemaphoreSlim ConnectGate { get; } = new(1, 1);
|
||||
|
||||
/// <summary>Gets the lock object for synchronizing host state transitions.</summary>
|
||||
public object ProbeLock { get; } = new();
|
||||
/// <summary>Gets or sets the current host connectivity state.</summary>
|
||||
public HostState HostState { get; set; } = HostState.Unknown;
|
||||
/// <summary>Gets or sets the UTC timestamp of the last host state change.</summary>
|
||||
public DateTime HostStateChangedUtc { get; set; } = DateTime.UtcNow;
|
||||
/// <summary>Gets or sets the cancellation token source for the probe loop.</summary>
|
||||
public CancellationTokenSource? ProbeCts { get; set; }
|
||||
/// <summary>The running probe-loop task — awaited by <see cref="TwinCATDriver.ShutdownAsync"/>
|
||||
/// so the loop cannot touch a disposed client (Driver.TwinCAT-009).</summary>
|
||||
public Task? ProbeTask { get; set; }
|
||||
|
||||
/// <summary>Disposes the active ADS client if any.</summary>
|
||||
public void DisposeClient()
|
||||
{
|
||||
Client?.Dispose();
|
||||
Client = null;
|
||||
}
|
||||
|
||||
/// <summary>Disposes the connection gate semaphore.</summary>
|
||||
public void DisposeGate() => ConnectGate.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user