docs(xmldoc): fill missing XML docs + strip tracking-ID comments across src
v2-ci / build (push) Failing after 41s
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 41s
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>/<returns>/<inheritdoc> where missing and removes project bookkeeping IDs (task/tracking refs) from shipped code comments, so the docs read cleanly and CommentChecker is quiet except for known false positives (PLC/protocol terms, event/IEqualityComparer inheritdoc). Doc/comment-only; no logic changed; solution builds clean.
This commit is contained in:
@@ -68,22 +68,13 @@ public sealed class AbLegacyDriver : IDriver, IReadable, IWritable, ITagDiscover
|
||||
OnDataChange?.Invoke(this, new DataChangeEventArgs(handle, tagRef, snapshot)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the driver instance identifier.
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
public string DriverInstanceId => _driverInstanceId;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the driver type.
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
public string DriverType => "AbLegacy";
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the driver asynchronously.
|
||||
/// </summary>
|
||||
/// <param name="driverConfigJson">The driver configuration JSON.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>A task representing the asynchronous operation.</returns>
|
||||
/// <inheritdoc />
|
||||
public Task InitializeAsync(string driverConfigJson, CancellationToken cancellationToken)
|
||||
{
|
||||
_health = new DriverHealth(DriverState.Initializing, null, null);
|
||||
@@ -132,9 +123,6 @@ public sealed class AbLegacyDriver : IDriver, IReadable, IWritable, ITagDiscover
|
||||
catch (Exception ex)
|
||||
{
|
||||
_health = new DriverHealth(DriverState.Faulted, null, ex.Message);
|
||||
// Driver.AbLegacy-005 — structured log of the init failure so a field operator sees
|
||||
// the exception in the rolling Serilog file rather than only as a transient Detail
|
||||
// string on DriverHealth.
|
||||
_logger.LogError(ex,
|
||||
"AbLegacy driver initialise failed. Driver={DriverInstanceId}", _driverInstanceId);
|
||||
// Tear down any probe loops and cached state that were created before the failure so
|
||||
@@ -157,23 +145,14 @@ public sealed class AbLegacyDriver : IDriver, IReadable, IWritable, ITagDiscover
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reinitializes the driver asynchronously.
|
||||
/// </summary>
|
||||
/// <param name="driverConfigJson">The driver configuration JSON.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>A task representing the asynchronous operation.</returns>
|
||||
/// <inheritdoc />
|
||||
public async Task ReinitializeAsync(string driverConfigJson, CancellationToken cancellationToken)
|
||||
{
|
||||
await ShutdownAsync(cancellationToken).ConfigureAwait(false);
|
||||
await InitializeAsync(driverConfigJson, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shuts down the driver asynchronously.
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>A task representing the asynchronous operation.</returns>
|
||||
/// <inheritdoc />
|
||||
public async Task ShutdownAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
await _poll.DisposeAsync().ConfigureAwait(false);
|
||||
@@ -190,23 +169,13 @@ public sealed class AbLegacyDriver : IDriver, IReadable, IWritable, ITagDiscover
|
||||
_health = new DriverHealth(DriverState.Unknown, _health.LastSuccessfulRead, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the driver health status.
|
||||
/// </summary>
|
||||
/// <returns>The driver health status.</returns>
|
||||
/// <inheritdoc />
|
||||
public DriverHealth GetHealth() => _health;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the memory footprint of the driver.
|
||||
/// </summary>
|
||||
/// <returns>The memory footprint in bytes.</returns>
|
||||
/// <inheritdoc />
|
||||
public long GetMemoryFootprint() => 0;
|
||||
|
||||
/// <summary>
|
||||
/// Flushes optional caches asynchronously.
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>A task representing the asynchronous operation.</returns>
|
||||
/// <inheritdoc />
|
||||
public Task FlushOptionalCachesAsync(CancellationToken cancellationToken) => Task.CompletedTask;
|
||||
|
||||
/// <summary>
|
||||
@@ -224,12 +193,7 @@ public sealed class AbLegacyDriver : IDriver, IReadable, IWritable, ITagDiscover
|
||||
|
||||
// ---- IReadable ----
|
||||
|
||||
/// <summary>
|
||||
/// Reads data values asynchronously.
|
||||
/// </summary>
|
||||
/// <param name="fullReferences">The full references to read.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>A list of data value snapshots.</returns>
|
||||
/// <inheritdoc />
|
||||
public async Task<IReadOnlyList<DataValueSnapshot>> ReadAsync(
|
||||
IReadOnlyList<string> fullReferences, CancellationToken cancellationToken)
|
||||
{
|
||||
@@ -267,11 +231,6 @@ public sealed class AbLegacyDriver : IDriver, IReadable, IWritable, ITagDiscover
|
||||
await runtime.ReadAsync(cancellationToken).ConfigureAwait(false);
|
||||
status = runtime.GetStatus();
|
||||
var parsed = AbLegacyAddress.TryParse(def.Address);
|
||||
// Phase 4c #137 — an ARRAY tag (non-null ArrayLength, ≥1) decodes the whole
|
||||
// contiguous read into a typed CLR array of that count, INCLUDING a 1-element
|
||||
// array (review I-3); a SCALAR tag (null ArrayLength) decodes a single value.
|
||||
// The runtime was created with a matching ElementCount in EnsureTagRuntimeAsync
|
||||
// so its buffer holds all the elements.
|
||||
if (status != 0)
|
||||
value = null;
|
||||
else if (IsArrayTag(def))
|
||||
@@ -290,11 +249,6 @@ public sealed class AbLegacyDriver : IDriver, IReadable, IWritable, ITagDiscover
|
||||
AbLegacyStatusMapper.MapLibplctagStatus(status), null, now);
|
||||
_health = new DriverHealth(DriverState.Degraded, _health.LastSuccessfulRead,
|
||||
$"libplctag status {status} reading {reference}");
|
||||
// Driver.AbLegacy-005 — log the FIRST non-zero libplctag status per device so
|
||||
// a field operator can correlate a comms problem with a structured log
|
||||
// entry. Detail on DriverHealth is overwritten by the very next read; the
|
||||
// log entry persists. Subsequent occurrences on the same device stay quiet so
|
||||
// a permanently-bad PLC doesn't flood the rolling file.
|
||||
if (!device.FirstNonZeroStatusLogged)
|
||||
{
|
||||
device.FirstNonZeroStatusLogged = true;
|
||||
@@ -325,12 +279,7 @@ public sealed class AbLegacyDriver : IDriver, IReadable, IWritable, ITagDiscover
|
||||
|
||||
// ---- IWritable ----
|
||||
|
||||
/// <summary>
|
||||
/// Writes data values asynchronously.
|
||||
/// </summary>
|
||||
/// <param name="writes">The write requests.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>A list of write results.</returns>
|
||||
/// <inheritdoc />
|
||||
public async Task<IReadOnlyList<WriteResult>> WriteAsync(
|
||||
IReadOnlyList<WriteRequest> writes, CancellationToken cancellationToken)
|
||||
{
|
||||
@@ -422,19 +371,10 @@ public sealed class AbLegacyDriver : IDriver, IReadable, IWritable, ITagDiscover
|
||||
|
||||
// ---- 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>
|
||||
/// <inheritdoc />
|
||||
public DiscoveryRediscoverPolicy RediscoverPolicy => DiscoveryRediscoverPolicy.Once;
|
||||
|
||||
/// <summary>
|
||||
/// Discovers tags and populates the address space asynchronously.
|
||||
/// </summary>
|
||||
/// <param name="builder">The address space builder.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>A task representing the asynchronous operation.</returns>
|
||||
/// <inheritdoc />
|
||||
public Task DiscoverAsync(IAddressSpaceBuilder builder, CancellationToken cancellationToken)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(builder);
|
||||
@@ -447,14 +387,6 @@ public sealed class AbLegacyDriver : IDriver, IReadable, IWritable, ITagDiscover
|
||||
string.Equals(t.DeviceHostAddress, device.HostAddress, StringComparison.OrdinalIgnoreCase));
|
||||
foreach (var tag in tagsForDevice)
|
||||
{
|
||||
// Phase 4c #137 — PCCC data files are inherently arrays of elements (a single N7
|
||||
// file is up to 256 words). The canonical contract: a tag is an ARRAY ⟺ its
|
||||
// ArrayLength is non-null (≥1, set by the parser only when isArray:true). A tag
|
||||
// with a non-null ArrayLength materialises a 1-D array OPC UA node, INCLUDING a
|
||||
// 1-element array (ArrayLength:1 → a [1] node — review I-3). ArrayDim is clamped
|
||||
// to the PCCC file maximum (AbLegacyArray.MaxElements = 256) so the declared
|
||||
// dimension can never exceed what a single data file holds; ArrayLength == null
|
||||
// (scalar) stays scalar.
|
||||
var isArray = tag.ArrayLength is int len && len >= 1;
|
||||
var arrayDim = isArray
|
||||
? (uint)Math.Min(tag.ArrayLength!.Value, AbLegacyArray.MaxElements)
|
||||
@@ -477,23 +409,12 @@ public sealed class AbLegacyDriver : IDriver, IReadable, IWritable, ITagDiscover
|
||||
|
||||
// ---- ISubscribable (polling overlay via shared engine) ----
|
||||
|
||||
/// <summary>
|
||||
/// Subscribes to data changes asynchronously.
|
||||
/// </summary>
|
||||
/// <param name="fullReferences">The full references to subscribe to.</param>
|
||||
/// <param name="publishingInterval">The publishing interval.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>A subscription handle.</returns>
|
||||
/// <inheritdoc />
|
||||
public Task<ISubscriptionHandle> SubscribeAsync(
|
||||
IReadOnlyList<string> fullReferences, TimeSpan publishingInterval, CancellationToken cancellationToken) =>
|
||||
Task.FromResult(_poll.Subscribe(fullReferences, publishingInterval));
|
||||
|
||||
/// <summary>
|
||||
/// Unsubscribes from data changes asynchronously.
|
||||
/// </summary>
|
||||
/// <param name="handle">The subscription handle.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>A task representing the asynchronous operation.</returns>
|
||||
/// <inheritdoc />
|
||||
public Task UnsubscribeAsync(ISubscriptionHandle handle, CancellationToken cancellationToken)
|
||||
{
|
||||
_poll.Unsubscribe(handle);
|
||||
@@ -502,10 +423,7 @@ public sealed class AbLegacyDriver : IDriver, IReadable, IWritable, ITagDiscover
|
||||
|
||||
// ---- IHostConnectivityProbe ----
|
||||
|
||||
/// <summary>
|
||||
/// Gets the host connectivity statuses.
|
||||
/// </summary>
|
||||
/// <returns>A list of host connectivity statuses.</returns>
|
||||
/// <inheritdoc />
|
||||
public IReadOnlyList<HostConnectivityStatus> GetHostStatuses() =>
|
||||
[.. _devices.Values.Select(s => new HostConnectivityStatus(s.Options.HostAddress, s.HostState, s.HostStateChangedUtc))];
|
||||
|
||||
@@ -560,9 +478,6 @@ public sealed class AbLegacyDriver : IDriver, IReadable, IWritable, ITagDiscover
|
||||
state.HostState = newState;
|
||||
state.HostStateChangedUtc = DateTime.UtcNow;
|
||||
}
|
||||
// Driver.AbLegacy-005 — structured log of every probe-driven transition. Operators can
|
||||
// grep the rolling Serilog file for the device address to see when a PLC was last
|
||||
// reachable. Downgrades to Stopped log as Warning; recoveries log as Information.
|
||||
if (newState == HostState.Stopped)
|
||||
_logger.LogWarning(
|
||||
"AbLegacy probe transition. Driver={DriverInstanceId} Device={DeviceHostAddress} From={Old} To={New}",
|
||||
@@ -577,23 +492,7 @@ public sealed class AbLegacyDriver : IDriver, IReadable, IWritable, ITagDiscover
|
||||
|
||||
// ---- IPerCallHostResolver ----
|
||||
|
||||
/// <summary>
|
||||
/// Map a full reference to the host string used as the resilience-pipeline breaker key.
|
||||
/// Driver.AbLegacy-013 — the contract on <see cref="IPerCallHostResolver"/> requires that
|
||||
/// implementations never throw on an unknown reference. The fallback chain is therefore:
|
||||
/// <list type="number">
|
||||
/// <item>Known tag → its <c>DeviceHostAddress</c>.</item>
|
||||
/// <item>Unknown reference but devices configured → the first device's host address
|
||||
/// (multi-device drivers degrade to single-host behaviour rather than failing).</item>
|
||||
/// <item>Unknown reference and no devices configured → the driver instance id, which
|
||||
/// the dispatch layer treats as the single-host key per the interface
|
||||
/// documentation. Reaching this branch indicates a misconfigured driver (no
|
||||
/// devices) so callers that want to surface that should validate
|
||||
/// <see cref="DeviceCount"/> before relying on per-tag routing.</item>
|
||||
/// </list>
|
||||
/// </summary>
|
||||
/// <param name="fullReference">The full reference to resolve.</param>
|
||||
/// <returns>The host address for the reference.</returns>
|
||||
/// <inheritdoc />
|
||||
public string ResolveHost(string fullReference)
|
||||
{
|
||||
if (_tagsByName.TryGetValue(fullReference, out var def))
|
||||
@@ -698,7 +597,7 @@ public sealed class AbLegacyDriver : IDriver, IReadable, IWritable, ITagDiscover
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Phase 4c #137 — whether a tag definition is an ARRAY. The canonical contract: a tag is
|
||||
/// Whether a tag definition is an ARRAY. The canonical contract: a tag is
|
||||
/// an array ⟺ its <see cref="AbLegacyTagDefinition.ArrayLength"/> is non-null (the parser
|
||||
/// sets it ≥1 only when isArray:true), so a 1-element array (ArrayLength:1) IS an array
|
||||
/// (review I-3). <c>null</c> ArrayLength ⇒ scalar.
|
||||
@@ -706,7 +605,7 @@ public sealed class AbLegacyDriver : IDriver, IReadable, IWritable, ITagDiscover
|
||||
private static bool IsArrayTag(AbLegacyTagDefinition def) => def.ArrayLength is int len && len >= 1;
|
||||
|
||||
/// <summary>
|
||||
/// Phase 4c #137 — the effective libplctag element count for a tag definition: the tag's
|
||||
/// The effective libplctag element count for a tag definition: the tag's
|
||||
/// <see cref="AbLegacyTagDefinition.ArrayLength"/> clamped to the PCCC file maximum
|
||||
/// (<see cref="AbLegacyArray.MaxElements"/> = 256) when it is an array (≥1, INCLUDING 1),
|
||||
/// or <c>1</c> when the tag is scalar (null ArrayLength). Used both to size the runtime at
|
||||
@@ -740,9 +639,6 @@ public sealed class AbLegacyDriver : IDriver, IReadable, IWritable, ITagDiscover
|
||||
LibplctagPlcAttribute: device.Profile.LibplctagPlcAttribute,
|
||||
TagName: parsed.ToLibplctagName(),
|
||||
Timeout: _options.Timeout,
|
||||
// Phase 4c #137 — multi-element PCCC file read. A multi-element span (ArrayLength
|
||||
// > 1) creates the libplctag tag with that element count so a single read fetches
|
||||
// the whole array from the base address; scalar tags pass 1 and read unchanged.
|
||||
ElementCount: EffectiveArrayLength(def)));
|
||||
try
|
||||
{
|
||||
@@ -763,7 +659,7 @@ public sealed class AbLegacyDriver : IDriver, IReadable, IWritable, ITagDiscover
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Driver.AbLegacy-011 — synchronous teardown. Mirrors the body of
|
||||
/// Synchronous teardown. Mirrors the body of
|
||||
/// <see cref="ShutdownAsync"/> but never wraps the async path in
|
||||
/// <c>.AsTask().GetAwaiter().GetResult()</c>. The poll engine's <c>DisposeAsync</c> is
|
||||
/// drained with a <c>ConfigureAwait(false)</c> awaiter so a captured single-threaded
|
||||
@@ -841,7 +737,7 @@ public sealed class AbLegacyDriver : IDriver, IReadable, IWritable, ITagDiscover
|
||||
new(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
/// <summary>
|
||||
/// Parent-word runtimes for bit-within-word RMW writes (task #181). Keyed by the
|
||||
/// Parent-word runtimes for bit-within-word RMW writes. Keyed by the
|
||||
/// parent address (bit suffix stripped) — e.g. writes to N7:0/3 + N7:0/5 share a
|
||||
/// single parent runtime for N7:0.
|
||||
/// </summary>
|
||||
@@ -916,7 +812,7 @@ public sealed class AbLegacyDriver : IDriver, IReadable, IWritable, ITagDiscover
|
||||
public bool ProbeInitialized { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Driver.AbLegacy-005 — per-device latch for the structured "first non-zero
|
||||
/// Per-device latch for the structured "first non-zero
|
||||
/// libplctag status" log. Reset to <see langword="false"/> on a successful read so a
|
||||
/// future outage re-fires the warning rather than being suppressed by a stale flag.
|
||||
/// Concurrent readers on the same device may race the unlatched check + set, but the
|
||||
|
||||
Reference in New Issue
Block a user