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:
@@ -69,6 +69,9 @@ public static class S7AddressParser
|
||||
/// the offending input echoed in the message so operators can correlate to the tag
|
||||
/// config that produced the fault.
|
||||
/// </summary>
|
||||
/// <param name="address">The S7 address string to parse.</param>
|
||||
/// <returns>The parsed address structure.</returns>
|
||||
/// <exception cref="FormatException">Thrown if the address syntax is invalid.</exception>
|
||||
public static S7ParsedAddress Parse(string address)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(address))
|
||||
@@ -102,6 +105,9 @@ public static class S7AddressParser
|
||||
/// config validation pages in the Admin UI). Returns <c>false</c> for any input that
|
||||
/// would throw from <see cref="Parse"/>.
|
||||
/// </summary>
|
||||
/// <param name="address">The S7 address string to parse.</param>
|
||||
/// <param name="result">The parsed address structure (valid only if method returns true).</param>
|
||||
/// <returns>True if parsing succeeded; false otherwise.</returns>
|
||||
public static bool TryParse(string address, out S7ParsedAddress result)
|
||||
{
|
||||
try
|
||||
|
||||
@@ -55,7 +55,9 @@ public sealed class S7Driver(S7DriverOptions options, string driverInstanceId, I
|
||||
/// </summary>
|
||||
private static readonly TimeSpan DrainTimeout = TimeSpan.FromSeconds(5);
|
||||
|
||||
/// <summary>Occurs when a subscribed tag value or status code changes.</summary>
|
||||
public event EventHandler<DataChangeEventArgs>? OnDataChange;
|
||||
/// <summary>Occurs when host connectivity status changes.</summary>
|
||||
public event EventHandler<HostStatusChangedEventArgs>? OnHostStatusChanged;
|
||||
|
||||
/// <summary>OPC UA StatusCode used when the tag name isn't in the driver's tag map.</summary>
|
||||
@@ -101,9 +103,15 @@ public sealed class S7Driver(S7DriverOptions options, string driverInstanceId, I
|
||||
private DriverHealth _health = new(DriverState.Unknown, null, null);
|
||||
private bool _disposed;
|
||||
|
||||
/// <summary>Gets the unique driver instance identifier.</summary>
|
||||
public string DriverInstanceId => driverInstanceId;
|
||||
/// <summary>Gets the driver type name.</summary>
|
||||
public string DriverType => "S7";
|
||||
|
||||
/// <summary>Initializes the driver with the provided configuration.</summary>
|
||||
/// <param name="driverConfigJson">JSON configuration string.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>A task representing the asynchronous operation.</returns>
|
||||
public async Task InitializeAsync(string driverConfigJson, CancellationToken cancellationToken)
|
||||
{
|
||||
_health = new DriverHealth(DriverState.Initializing, null, null);
|
||||
@@ -184,6 +192,10 @@ public sealed class S7Driver(S7DriverOptions options, string driverInstanceId, I
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Reinitializes the driver with a new configuration.</summary>
|
||||
/// <param name="driverConfigJson">JSON configuration string.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>A task representing the asynchronous operation.</returns>
|
||||
public async Task ReinitializeAsync(string driverConfigJson, CancellationToken cancellationToken)
|
||||
{
|
||||
// InitializeAsync re-parses driverConfigJson, so a config change delivered here is
|
||||
@@ -192,6 +204,9 @@ public sealed class S7Driver(S7DriverOptions options, string driverInstanceId, I
|
||||
await InitializeAsync(driverConfigJson, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>Shuts down the driver and releases resources.</summary>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>A task representing the asynchronous operation.</returns>
|
||||
public async Task ShutdownAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
// Signal cancellation to the probe + poll loops first, collect their Task handles,
|
||||
@@ -236,6 +251,15 @@ public sealed class S7Driver(S7DriverOptions options, string driverInstanceId, I
|
||||
_health = new DriverHealth(DriverState.Unknown, _health.LastSuccessfulRead, null);
|
||||
}
|
||||
|
||||
/// <summary>Gets the current driver health.</summary>
|
||||
/// <returns>The current health state.</returns>
|
||||
public DriverHealth GetHealth() => _health;
|
||||
|
||||
/// <summary>Flushes optional caches to free memory.</summary>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>A task representing the asynchronous operation.</returns>
|
||||
public Task FlushOptionalCachesAsync(CancellationToken cancellationToken) => Task.CompletedTask;
|
||||
|
||||
/// <summary>
|
||||
/// True when <paramref name="driverConfigJson"/> carries a real config body. The
|
||||
/// bootstrapper always passes a populated document; some unit tests pass <c>"{}"</c> or
|
||||
@@ -309,8 +333,6 @@ public sealed class S7Driver(S7DriverOptions options, string driverInstanceId, I
|
||||
S7DataType.DateTime,
|
||||
};
|
||||
|
||||
public DriverHealth GetHealth() => _health;
|
||||
|
||||
/// <summary>
|
||||
/// Approximate memory footprint. The Plc instance + one 240-960 byte PDU buffer is
|
||||
/// under 4 KB; return 0 because the <see cref="IDriver"/> contract asks for a
|
||||
@@ -318,10 +340,12 @@ public sealed class S7Driver(S7DriverOptions options, string driverInstanceId, I
|
||||
/// </summary>
|
||||
public long GetMemoryFootprint() => 0;
|
||||
|
||||
public Task FlushOptionalCachesAsync(CancellationToken cancellationToken) => Task.CompletedTask;
|
||||
|
||||
// ---- IReadable ----
|
||||
|
||||
/// <summary>Reads values from the specified tag references.</summary>
|
||||
/// <param name="fullReferences">Tag references to read.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>A task representing the asynchronous operation returning a list of data value snapshots.</returns>
|
||||
public async Task<IReadOnlyList<DataValueSnapshot>> ReadAsync(
|
||||
IReadOnlyList<string> fullReferences, CancellationToken cancellationToken)
|
||||
{
|
||||
@@ -405,6 +429,10 @@ public sealed class S7Driver(S7DriverOptions options, string driverInstanceId, I
|
||||
/// Factored out of <see cref="ReadOneAsync"/> so it can be exercised in unit tests
|
||||
/// without a live PLC (Driver.S7-014).
|
||||
/// </summary>
|
||||
/// <param name="tag">Tag definition containing type information.</param>
|
||||
/// <param name="addr">Parsed tag address.</param>
|
||||
/// <param name="raw">Raw value from S7.Net.</param>
|
||||
/// <returns>The reinterpreted value in the target semantic type.</returns>
|
||||
internal static object ReinterpretRawValue(S7TagDefinition tag, S7ParsedAddress addr, object raw) =>
|
||||
(tag.DataType, addr.Size, raw) switch
|
||||
{
|
||||
@@ -429,6 +457,10 @@ public sealed class S7Driver(S7DriverOptions options, string driverInstanceId, I
|
||||
|
||||
// ---- IWritable ----
|
||||
|
||||
/// <summary>Writes values to the specified tags.</summary>
|
||||
/// <param name="writes">Write requests containing tag references and values.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>A task representing the asynchronous operation returning a list of write results.</returns>
|
||||
public async Task<IReadOnlyList<WriteResult>> WriteAsync(
|
||||
IReadOnlyList<WriteRequest> writes, CancellationToken cancellationToken)
|
||||
{
|
||||
@@ -517,6 +549,9 @@ public sealed class S7Driver(S7DriverOptions options, string driverInstanceId, I
|
||||
/// Factored out of <see cref="WriteOneAsync"/> so it can be exercised in unit tests
|
||||
/// without a live PLC (Driver.S7-014).
|
||||
/// </summary>
|
||||
/// <param name="dataType">Target S7 data type.</param>
|
||||
/// <param name="value">Value to box.</param>
|
||||
/// <returns>The boxed value in the wire type expected by S7.Net.</returns>
|
||||
internal static object BoxValueForWrite(S7DataType dataType, object? value) => dataType switch
|
||||
{
|
||||
S7DataType.Bool => (object)Convert.ToBoolean(value),
|
||||
@@ -562,6 +597,10 @@ public sealed class S7Driver(S7DriverOptions options, string driverInstanceId, I
|
||||
|
||||
// ---- ITagDiscovery ----
|
||||
|
||||
/// <summary>Discovers tags and builds the OPC UA address space.</summary>
|
||||
/// <param name="builder">Address space builder.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>A task representing the asynchronous operation.</returns>
|
||||
public Task DiscoverAsync(IAddressSpaceBuilder builder, CancellationToken cancellationToken)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(builder);
|
||||
@@ -599,6 +638,11 @@ public sealed class S7Driver(S7DriverOptions options, string driverInstanceId, I
|
||||
|
||||
// ---- ISubscribable (polling overlay) ----
|
||||
|
||||
/// <summary>Subscribes to changes on the specified tag references.</summary>
|
||||
/// <param name="fullReferences">Tag references to subscribe to.</param>
|
||||
/// <param name="publishingInterval">Polling interval.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>A task representing the asynchronous operation returning a subscription handle.</returns>
|
||||
public Task<ISubscriptionHandle> SubscribeAsync(
|
||||
IReadOnlyList<string> fullReferences, TimeSpan publishingInterval, CancellationToken cancellationToken)
|
||||
{
|
||||
@@ -618,6 +662,10 @@ public sealed class S7Driver(S7DriverOptions options, string driverInstanceId, I
|
||||
return Task.FromResult<ISubscriptionHandle>(handle);
|
||||
}
|
||||
|
||||
/// <summary>Unsubscribes from a subscription.</summary>
|
||||
/// <param name="handle">Subscription handle.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>A task representing the asynchronous operation.</returns>
|
||||
public Task UnsubscribeAsync(ISubscriptionHandle handle, CancellationToken cancellationToken)
|
||||
{
|
||||
if (handle is S7SubscriptionHandle h && _subscriptions.TryRemove(h.Id, out var state))
|
||||
@@ -714,6 +762,9 @@ public sealed class S7Driver(S7DriverOptions options, string driverInstanceId, I
|
||||
/// <paramref name="interval"/>; each subsequent failure doubles the wait up to
|
||||
/// <see cref="PollBackoffCap"/>. Computed in ticks to avoid overflow at large counts.
|
||||
/// </summary>
|
||||
/// <param name="interval">Base polling interval.</param>
|
||||
/// <param name="consecutiveFailures">Number of consecutive failures.</param>
|
||||
/// <returns>The computed backoff delay.</returns>
|
||||
internal static TimeSpan ComputeBackoffDelay(TimeSpan interval, int consecutiveFailures)
|
||||
{
|
||||
if (consecutiveFailures <= 0) return interval;
|
||||
@@ -748,6 +799,7 @@ public sealed class S7Driver(S7DriverOptions options, string driverInstanceId, I
|
||||
TimeSpan Interval,
|
||||
CancellationTokenSource Cts)
|
||||
{
|
||||
/// <summary>Gets the last known values for subscribed tags.</summary>
|
||||
public ConcurrentDictionary<string, DataValueSnapshot> LastValues { get; }
|
||||
= new(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
@@ -760,6 +812,7 @@ public sealed class S7Driver(S7DriverOptions options, string driverInstanceId, I
|
||||
|
||||
private sealed record S7SubscriptionHandle(long Id) : ISubscriptionHandle
|
||||
{
|
||||
/// <summary>Gets the diagnostic identifier for this subscription.</summary>
|
||||
public string DiagnosticId => $"s7-sub-{Id}";
|
||||
}
|
||||
|
||||
@@ -772,6 +825,8 @@ public sealed class S7Driver(S7DriverOptions options, string driverInstanceId, I
|
||||
/// </summary>
|
||||
public string HostName => $"{_options.Host}:{_options.Port}";
|
||||
|
||||
/// <summary>Gets the host connectivity statuses.</summary>
|
||||
/// <returns>A list containing the current host status.</returns>
|
||||
public IReadOnlyList<HostConnectivityStatus> GetHostStatuses()
|
||||
{
|
||||
lock (_probeLock)
|
||||
@@ -827,6 +882,7 @@ public sealed class S7Driver(S7DriverOptions options, string driverInstanceId, I
|
||||
OnHostStatusChanged?.Invoke(this, new HostStatusChangedEventArgs(HostName, old, newState));
|
||||
}
|
||||
|
||||
/// <summary>Disposes the driver and releases resources.</summary>
|
||||
public void Dispose()
|
||||
{
|
||||
// Driver.S7-010: avoid the sync-over-async DisposeAsync().AsTask().GetAwaiter().GetResult()
|
||||
@@ -840,6 +896,8 @@ public sealed class S7Driver(S7DriverOptions options, string driverInstanceId, I
|
||||
_gate.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>Asynchronously disposes the driver and releases resources.</summary>
|
||||
/// <returns>A task representing the asynchronous operation.</returns>
|
||||
public async ValueTask DisposeAsync()
|
||||
{
|
||||
if (_disposed) return;
|
||||
|
||||
@@ -15,12 +15,18 @@ public static class S7DriverFactoryExtensions
|
||||
{
|
||||
public const string DriverTypeName = "S7";
|
||||
|
||||
/// <summary>Registers the S7 driver factory with the registry.</summary>
|
||||
/// <param name="registry">The driver factory registry.</param>
|
||||
public static void Register(DriverFactoryRegistry registry)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(registry);
|
||||
registry.Register(DriverTypeName, CreateInstance);
|
||||
}
|
||||
|
||||
/// <summary>Creates a new S7 driver instance from configuration.</summary>
|
||||
/// <param name="driverInstanceId">The unique identifier for the driver instance.</param>
|
||||
/// <param name="driverConfigJson">The JSON configuration for the driver.</param>
|
||||
/// <returns>A newly created S7 driver instance.</returns>
|
||||
internal static S7Driver CreateInstance(string driverInstanceId, string driverConfigJson)
|
||||
{
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(driverInstanceId);
|
||||
@@ -34,6 +40,9 @@ public static class S7DriverFactoryExtensions
|
||||
/// / <see cref="S7Driver.ReinitializeAsync"/> so a config change delivered through the
|
||||
/// <c>IDriver</c> contract is actually applied — see code-review finding Driver.S7-011.
|
||||
/// </summary>
|
||||
/// <param name="driverInstanceId">The unique identifier for the driver instance.</param>
|
||||
/// <param name="driverConfigJson">The JSON configuration for the driver.</param>
|
||||
/// <returns>Parsed S7 driver options.</returns>
|
||||
internal static S7DriverOptions ParseOptions(string driverInstanceId, string driverConfigJson)
|
||||
{
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(driverInstanceId);
|
||||
@@ -104,32 +113,52 @@ public static class S7DriverFactoryExtensions
|
||||
AllowTrailingCommas = true,
|
||||
};
|
||||
|
||||
/// <summary>Data transfer object for S7 driver configuration.</summary>
|
||||
internal sealed class S7DriverConfigDto
|
||||
{
|
||||
/// <summary>Gets the PLC host address.</summary>
|
||||
public string? Host { get; init; }
|
||||
/// <summary>Gets the PLC port.</summary>
|
||||
public int? Port { get; init; }
|
||||
/// <summary>Gets the CPU type name.</summary>
|
||||
public string? CpuType { get; init; }
|
||||
/// <summary>Gets the rack number.</summary>
|
||||
public short? Rack { get; init; }
|
||||
/// <summary>Gets the slot number.</summary>
|
||||
public short? Slot { get; init; }
|
||||
/// <summary>Gets the connection timeout in milliseconds.</summary>
|
||||
public int? TimeoutMs { get; init; }
|
||||
/// <summary>Gets the list of tag definitions.</summary>
|
||||
public List<S7TagDto>? Tags { get; init; }
|
||||
/// <summary>Gets the probe configuration.</summary>
|
||||
public S7ProbeDto? Probe { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>Data transfer object for S7 tag definition.</summary>
|
||||
internal sealed class S7TagDto
|
||||
{
|
||||
/// <summary>Gets the tag name.</summary>
|
||||
public string? Name { get; init; }
|
||||
/// <summary>Gets the S7 address (e.g., DB1.DBD0).</summary>
|
||||
public string? Address { get; init; }
|
||||
/// <summary>Gets the data type name.</summary>
|
||||
public string? DataType { get; init; }
|
||||
/// <summary>Gets a value indicating whether the tag is writable.</summary>
|
||||
public bool? Writable { get; init; }
|
||||
/// <summary>Gets the string length for string types.</summary>
|
||||
public int? StringLength { get; init; }
|
||||
/// <summary>Gets a value indicating whether write is idempotent.</summary>
|
||||
public bool? WriteIdempotent { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>Data transfer object for S7 probe configuration.</summary>
|
||||
internal sealed class S7ProbeDto
|
||||
{
|
||||
/// <summary>Gets a value indicating whether probing is enabled.</summary>
|
||||
public bool? Enabled { get; init; }
|
||||
/// <summary>Gets the probe interval in milliseconds.</summary>
|
||||
public int? IntervalMs { get; init; }
|
||||
/// <summary>Gets the probe timeout in milliseconds.</summary>
|
||||
public int? TimeoutMs { get; init; }
|
||||
// Driver.S7-012: ProbeAddress removed from the configurable surface — the probe uses
|
||||
// ReadStatusAsync (CPU status), not a tag-address read. Config documents that previously
|
||||
|
||||
@@ -67,8 +67,11 @@ public sealed class S7DriverOptions
|
||||
|
||||
public sealed class S7ProbeOptions
|
||||
{
|
||||
/// <summary>Gets or sets a value indicating whether probing is enabled.</summary>
|
||||
public bool Enabled { get; init; } = true;
|
||||
/// <summary>Gets or sets the probe interval.</summary>
|
||||
public TimeSpan Interval { get; init; } = TimeSpan.FromSeconds(5);
|
||||
/// <summary>Gets or sets the probe timeout.</summary>
|
||||
public TimeSpan Timeout { get; init; } = TimeSpan.FromSeconds(2);
|
||||
|
||||
// Driver.S7-012: ProbeAddress was configured and documented but was never read by the
|
||||
|
||||
Reference in New Issue
Block a user