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

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:
Joseph Doherty
2026-05-28 08:10:17 -04:00
parent f9fc7dd2e1
commit 64e3fbe035
756 changed files with 9876 additions and 96 deletions
@@ -38,10 +38,18 @@ public sealed class FocasDriver : IDriver, IReadable, IWritable, ITagDiscovery,
// record is immutable so there is no torn-read risk on the object itself.
private DriverHealth _health = new(DriverState.Unknown, null, null);
/// <summary>Occurs when data changes on a subscribed tag.</summary>
public event EventHandler<DataChangeEventArgs>? OnDataChange;
/// <summary>Occurs when a device host connection status changes.</summary>
public event EventHandler<HostStatusChangedEventArgs>? OnHostStatusChanged;
/// <summary>Occurs when an alarm event is raised.</summary>
public event EventHandler<AlarmEventArgs>? OnAlarmEvent;
/// <summary>Initializes a new instance of the <see cref="FocasDriver"/> class with the provided options and dependencies.</summary>
/// <param name="options">The driver configuration options.</param>
/// <param name="driverInstanceId">The unique identifier for this driver instance.</param>
/// <param name="clientFactory">Optional factory for creating FOCAS client instances.</param>
/// <param name="logger">Optional logger instance.</param>
public FocasDriver(FocasDriverOptions options, string driverInstanceId,
IFocasClientFactory? clientFactory = null,
ILogger<FocasDriver>? logger = null)
@@ -57,9 +65,15 @@ public sealed class FocasDriver : IDriver, IReadable, IWritable, ITagDiscovery,
OnDataChange?.Invoke(this, new DataChangeEventArgs(handle, tagRef, snapshot)));
}
/// <summary>Gets the driver instance identifier.</summary>
public string DriverInstanceId => _driverInstanceId;
/// <summary>Gets the driver type name.</summary>
public string DriverType => "FOCAS";
/// <summary>Initializes the driver with configuration and prepares device connections and polling.</summary>
/// <param name="driverConfigJson">JSON configuration string for the driver.</param>
/// <param name="cancellationToken">Cancellation token for the operation.</param>
/// <returns>A task representing the asynchronous initialization operation.</returns>
public Task InitializeAsync(string driverConfigJson, CancellationToken cancellationToken)
{
Volatile.Write(ref _health, new DriverHealth(DriverState.Initializing, null, null));
@@ -142,12 +156,19 @@ public sealed class FocasDriver : IDriver, IReadable, IWritable, ITagDiscovery,
return Task.CompletedTask;
}
/// <summary>Reinitializes the driver by shutting down and restarting with new configuration.</summary>
/// <param name="driverConfigJson">JSON configuration string for the driver.</param>
/// <param name="cancellationToken">Cancellation token for the operation.</param>
/// <returns>A task representing the asynchronous reinitialization operation.</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, cancelling all running operations and releasing resources.</summary>
/// <param name="cancellationToken">Cancellation token for the operation.</param>
/// <returns>A task representing the asynchronous shutdown operation.</returns>
public async Task ShutdownAsync(CancellationToken cancellationToken)
{
await _poll.DisposeAsync().ConfigureAwait(false);
@@ -181,11 +202,20 @@ public sealed class FocasDriver : IDriver, IReadable, IWritable, ITagDiscovery,
Volatile.Write(ref _health, new DriverHealth(DriverState.Unknown, Volatile.Read(ref _health).LastSuccessfulRead, null));
}
/// <summary>Gets the current health status of the driver.</summary>
public DriverHealth GetHealth() => Volatile.Read(ref _health);
/// <summary>Gets the current memory footprint of the driver.</summary>
public long GetMemoryFootprint() => 0;
/// <summary>Flushes optional internal caches.</summary>
/// <param name="cancellationToken">Cancellation token for the operation.</param>
/// <returns>A task representing the asynchronous cache flush operation.</returns>
public Task FlushOptionalCachesAsync(CancellationToken cancellationToken) => Task.CompletedTask;
/// <summary>Gets the number of configured devices.</summary>
internal int DeviceCount => _devices.Count;
/// <summary>Gets the state of a device by host address.</summary>
/// <param name="hostAddress">The host address of the device.</param>
/// <returns>The device state if found; otherwise null.</returns>
internal DeviceState? GetDeviceState(string hostAddress) =>
_devices.TryGetValue(hostAddress, out var s) ? s : null;
@@ -194,6 +224,10 @@ public sealed class FocasDriver : IDriver, IReadable, IWritable, ITagDiscovery,
// ---- IReadable ----
/// <summary>Reads values from one or more tags asynchronously.</summary>
/// <param name="fullReferences">A read-only list of tag references to read.</param>
/// <param name="cancellationToken">Cancellation token for the operation.</param>
/// <returns>A task representing the asynchronous read operation.</returns>
public async Task<IReadOnlyList<DataValueSnapshot>> ReadAsync(
IReadOnlyList<string> fullReferences, CancellationToken cancellationToken)
{
@@ -260,6 +294,10 @@ public sealed class FocasDriver : IDriver, IReadable, IWritable, ITagDiscovery,
// ---- IWritable ----
/// <summary>Writes values to one or more tags asynchronously.</summary>
/// <param name="writes">A read-only list of write requests.</param>
/// <param name="cancellationToken">Cancellation token for the operation.</param>
/// <returns>A task representing the asynchronous write operation.</returns>
public async Task<IReadOnlyList<WriteResult>> WriteAsync(
IReadOnlyList<WriteRequest> writes, CancellationToken cancellationToken)
{
@@ -325,6 +363,10 @@ public sealed class FocasDriver : IDriver, IReadable, IWritable, ITagDiscovery,
// ---- ITagDiscovery ----
/// <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="cancellationToken">Cancellation token for the operation.</param>
/// <returns>A task representing the asynchronous discovery operation.</returns>
public Task DiscoverAsync(IAddressSpaceBuilder builder, CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(builder);
@@ -493,15 +535,27 @@ public sealed class FocasDriver : IDriver, IReadable, IWritable, ITagDiscovery,
/// the path inside the tree. Matches what poll-loop snapshots publish +
/// what <see cref="ReadAsync"/> looks up.
/// </summary>
/// <param name="deviceHost">The host address of the device.</param>
/// <param name="path">The path within the fixed tree.</param>
/// <returns>The canonical full reference for the node.</returns>
internal static string FixedTreeReference(string deviceHost, string path) =>
$"{deviceHost}/{path}";
// ---- ISubscribable (polling overlay via shared engine) ----
/// <summary>Subscribes to data changes on one or more tags.</summary>
/// <param name="fullReferences">A read-only list of tag references to subscribe to.</param>
/// <param name="publishingInterval">The interval at which to publish data changes.</param>
/// <param name="cancellationToken">Cancellation token for the operation.</param>
/// <returns>A task representing the asynchronous subscription operation.</returns>
public Task<ISubscriptionHandle> SubscribeAsync(
IReadOnlyList<string> fullReferences, TimeSpan publishingInterval, CancellationToken cancellationToken) =>
Task.FromResult(_poll.Subscribe(fullReferences, publishingInterval));
/// <summary>Unsubscribes from a previous subscription.</summary>
/// <param name="handle">The subscription handle to unsubscribe from.</param>
/// <param name="cancellationToken">Cancellation token for the operation.</param>
/// <returns>A task representing the asynchronous unsubscription operation.</returns>
public Task UnsubscribeAsync(ISubscriptionHandle handle, CancellationToken cancellationToken)
{
_poll.Unsubscribe(handle);
@@ -510,6 +564,7 @@ public sealed class FocasDriver : IDriver, IReadable, IWritable, ITagDiscovery,
// ---- IHostConnectivityProbe ----
/// <summary>Gets the connectivity status of all configured devices.</summary>
public IReadOnlyList<HostConnectivityStatus> GetHostStatuses() =>
[.. _devices.Values.Select(s => new HostConnectivityStatus(s.Options.HostAddress, s.HostState, s.HostStateChangedUtc))];
@@ -915,6 +970,10 @@ public sealed class FocasDriver : IDriver, IReadable, IWritable, ITagDiscovery,
// ---- IAlarmSource ----
/// <summary>Subscribes to alarm events from the driver.</summary>
/// <param name="sourceNodeIds">A read-only list of source node IDs to subscribe to.</param>
/// <param name="cancellationToken">Cancellation token for the operation.</param>
/// <returns>A task representing the asynchronous subscription operation.</returns>
public Task<IAlarmSubscriptionHandle> SubscribeAlarmsAsync(
IReadOnlyList<string> sourceNodeIds, CancellationToken cancellationToken)
{
@@ -924,13 +983,23 @@ public sealed class FocasDriver : IDriver, IReadable, IWritable, ITagDiscovery,
return _alarmProjection.SubscribeAsync(sourceNodeIds, cancellationToken);
}
/// <summary>Unsubscribes from a previous alarm subscription.</summary>
/// <param name="handle">The alarm subscription handle to unsubscribe from.</param>
/// <param name="cancellationToken">Cancellation token for the operation.</param>
/// <returns>A task representing the asynchronous unsubscription operation.</returns>
public Task UnsubscribeAlarmsAsync(IAlarmSubscriptionHandle handle, CancellationToken cancellationToken) =>
_alarmProjection is { } p ? p.UnsubscribeAsync(handle, cancellationToken) : Task.CompletedTask;
/// <summary>Acknowledges one or more alarms.</summary>
/// <param name="acknowledgements">A read-only list of alarm acknowledgement requests.</param>
/// <param name="cancellationToken">Cancellation token for the operation.</param>
/// <returns>A task representing the asynchronous acknowledgement operation.</returns>
public Task AcknowledgeAsync(
IReadOnlyList<AlarmAcknowledgeRequest> acknowledgements, CancellationToken cancellationToken) =>
_alarmProjection is { } p ? p.AcknowledgeAsync(acknowledgements, cancellationToken) : Task.CompletedTask;
/// <summary>Raises an alarm event with the provided arguments.</summary>
/// <param name="args">The alarm event arguments.</param>
internal void InvokeAlarmEvent(AlarmEventArgs args) => OnAlarmEvent?.Invoke(this, args);
/// <summary>
@@ -938,6 +1007,9 @@ public sealed class FocasDriver : IDriver, IReadable, IWritable, ITagDiscovery,
/// projection — kept <c>internal</c> rather than <c>public</c> because callers that
/// want alarm events should subscribe through <c>IAlarmSource</c> instead.
/// </summary>
/// <param name="deviceFilter">Optional set of device host addresses to filter results; null includes all devices.</param>
/// <param name="ct">Cancellation token.</param>
/// <returns>A list of tuples containing host address and active alarms for each device.</returns>
internal async Task<IReadOnlyList<(string HostAddress, IReadOnlyList<FocasActiveAlarm> Alarms)>>
ReadActiveAlarmsAcrossDevicesAsync(HashSet<string>? deviceFilter, CancellationToken ct)
{
@@ -963,6 +1035,9 @@ public sealed class FocasDriver : IDriver, IReadable, IWritable, ITagDiscovery,
// ---- IPerCallHostResolver ----
/// <summary>Resolves the host address for a given tag reference.</summary>
/// <param name="fullReference">The full reference of the tag.</param>
/// <returns>The host address for the tag reference.</returns>
public string ResolveHost(string fullReference)
{
if (_tagsByName.TryGetValue(fullReference, out var def))
@@ -999,7 +1074,9 @@ public sealed class FocasDriver : IDriver, IReadable, IWritable, ITagDiscovery,
return device.Client;
}
/// <summary>Disposes the driver and releases all resources synchronously.</summary>
public void Dispose() => DisposeAsync().AsTask().GetAwaiter().GetResult();
/// <summary>Disposes the driver and releases all resources asynchronously.</summary>
public async ValueTask DisposeAsync() => await ShutdownAsync(CancellationToken.None).ConfigureAwait(false);
/// <summary>
@@ -1031,25 +1108,41 @@ public sealed class FocasDriver : IDriver, IReadable, IWritable, ITagDiscovery,
internal sealed class DeviceState(FocasHostAddress parsedAddress, FocasDeviceOptions options)
{
/// <summary>Gets the parsed host address.</summary>
public FocasHostAddress ParsedAddress { get; } = parsedAddress;
/// <summary>Gets the device configuration options.</summary>
public FocasDeviceOptions Options { get; } = options;
/// <summary>Gets or sets the FOCAS client instance.</summary>
public IFocasClient? Client { get; set; }
/// <summary>Gets the lock object for probe synchronization.</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 timestamp when host state last changed.</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>Gets or sets the cancellation token source for the recycle loop.</summary>
public CancellationTokenSource? RecycleCts { get; set; }
/// <summary>Gets or sets the cancellation token source for the fixed-tree loop.</summary>
public CancellationTokenSource? FixedTreeCts { get; set; }
/// <summary>Gets or sets the fixed-tree cache for this device.</summary>
public FocasFixedTreeCache? FixedTreeCache { get; set; }
/// <summary>Gets the last fixed tree snapshots by field name.</summary>
public Dictionary<string, int> LastFixedSnapshots { get; } = new(StringComparer.OrdinalIgnoreCase);
/// <summary>Gets or sets the last program information snapshot.</summary>
public FocasProgramInfo? LastProgramInfo { get; set; }
/// <summary>Cached first-axis dynamic snapshot — feeds Program/Number, /MainNumber, /Sequence.</summary>
/// <summary>Gets or sets the cached first-axis dynamic snapshot — feeds Program/Number, /MainNumber, /Sequence.</summary>
public FocasDynamicSnapshot? LastProgramAxisRef { get; set; }
/// <summary>Gets the last timer values by timer kind.</summary>
public Dictionary<FocasTimerKind, FocasTimer> LastTimers { get; } = [];
/// <summary>Gets the last servo load percentages by servo name.</summary>
public Dictionary<string, double> LastServoLoads { get; } = new(StringComparer.OrdinalIgnoreCase);
/// <summary>Gets the last spindle load percentages by spindle index.</summary>
public Dictionary<int, int> LastSpindleLoads { get; } = [];
/// <summary>Disposes the FOCAS client instance.</summary>
public void DisposeClient()
{
Client?.Dispose();