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:
@@ -19,16 +19,19 @@ namespace ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.Cli.Commands;
|
||||
[Command("browse", Description = "Enumerate controller symbols via the driver's DiscoverAsync walk.")]
|
||||
public sealed class BrowseCommand : TwinCATCommandBase
|
||||
{
|
||||
/// <summary>Gets or sets the case-sensitive instance-path prefix to filter on.</summary>
|
||||
[CommandOption("prefix", Description =
|
||||
"Case-sensitive instance-path prefix to filter on (e.g. 'GVL_Fixture' or " +
|
||||
"'MAIN.'). Empty (default) prints everything.")]
|
||||
public string? Prefix { get; init; }
|
||||
|
||||
/// <summary>Gets or sets the maximum number of symbols to print.</summary>
|
||||
[CommandOption("max", Description =
|
||||
"Maximum number of symbols to print. 0 = unbounded (default 500 for large " +
|
||||
"controllers — flat-mode symbol counts easily top 10k).")]
|
||||
public int Max { get; init; } = 500;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async ValueTask ExecuteAsync(IConsole console)
|
||||
{
|
||||
Validate();
|
||||
@@ -85,6 +88,8 @@ public sealed class BrowseCommand : TwinCATCommandBase
|
||||
/// <see cref="StringComparison.Ordinal"/> — TwinCAT identifiers are case-sensitive on
|
||||
/// the wire, so a relaxed match would be misleading.
|
||||
/// </summary>
|
||||
/// <param name="source">The source collection to filter.</param>
|
||||
/// <param name="prefix">The prefix to filter on, or null to keep everything.</param>
|
||||
internal static List<(string BrowseName, DriverAttributeInfo Info)> FilterByPrefix(
|
||||
IReadOnlyList<(string BrowseName, DriverAttributeInfo Info)> source, string? prefix)
|
||||
=> source
|
||||
@@ -95,6 +100,8 @@ public sealed class BrowseCommand : TwinCATCommandBase
|
||||
/// Cap-to-max projection. <paramref name="max"/> <= 0 means unbounded, otherwise the
|
||||
/// min of <paramref name="matchedCount"/> and <paramref name="max"/>.
|
||||
/// </summary>
|
||||
/// <param name="matchedCount">The number of matched items.</param>
|
||||
/// <param name="max">The maximum number to show, or 0 for unbounded.</param>
|
||||
internal static int PrintLimit(int matchedCount, int max)
|
||||
=> max <= 0 ? matchedCount : Math.Min(max, matchedCount);
|
||||
|
||||
@@ -104,31 +111,42 @@ public sealed class BrowseCommand : TwinCATCommandBase
|
||||
/// written from at least one ACL tier, so the CLI labels it RW. The real per-tier
|
||||
/// authorization is enforced server-side.
|
||||
/// </summary>
|
||||
/// <param name="info">The attribute info to label.</param>
|
||||
internal static string AccessTag(DriverAttributeInfo info)
|
||||
=> info.SecurityClass == SecurityClassification.ViewOnly ? "RO" : "RW";
|
||||
|
||||
/// <summary>An address space builder that collects variables for enumeration.</summary>
|
||||
internal sealed class CollectingAddressSpaceBuilder : IAddressSpaceBuilder
|
||||
{
|
||||
/// <summary>Gets the collected variables.</summary>
|
||||
public List<(string BrowseName, DriverAttributeInfo Info)> Variables { get; } = [];
|
||||
|
||||
/// <inheritdoc />
|
||||
public IAddressSpaceBuilder Folder(string browseName, string displayName) => this;
|
||||
|
||||
/// <inheritdoc />
|
||||
public IVariableHandle Variable(string browseName, string displayName, DriverAttributeInfo info)
|
||||
{
|
||||
Variables.Add((browseName, info));
|
||||
return new Handle(info.FullName);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void AddProperty(string name, DriverDataType type, object? value) { }
|
||||
|
||||
/// <summary>A variable handle that stores the full reference.</summary>
|
||||
private sealed class Handle(string fullRef) : IVariableHandle
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public string FullReference => fullRef;
|
||||
/// <inheritdoc />
|
||||
public IAlarmConditionSink MarkAsAlarmCondition(AlarmConditionInfo info) => new NullSink();
|
||||
}
|
||||
|
||||
/// <summary>A null sink that ignores alarm condition transitions.</summary>
|
||||
private sealed class NullSink : IAlarmConditionSink
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public void OnTransition(AlarmEventArgs args) { }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ namespace ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.Cli.Commands;
|
||||
[Command("probe", Description = "Verify the TwinCAT runtime is reachable and a sample symbol reads.")]
|
||||
public sealed class ProbeCommand : TwinCATTagCommandBase
|
||||
{
|
||||
/// <summary>Gets the symbol path to probe in the TwinCAT runtime.</summary>
|
||||
[CommandOption("symbol", 's', Description =
|
||||
"Symbol path to probe. System-global examples: " +
|
||||
"'TwinCAT_SystemInfoVarList._AppInfo.OnlineChangeCnt', 'MAIN.bRunning'. " +
|
||||
@@ -20,11 +21,13 @@ public sealed class ProbeCommand : TwinCATTagCommandBase
|
||||
IsRequired = true)]
|
||||
public string SymbolPath { get; init; } = default!;
|
||||
|
||||
/// <summary>Gets the data type to use for reading the symbol.</summary>
|
||||
[CommandOption("type", 't', Description =
|
||||
"Bool / SInt / USInt / Int / UInt / DInt / UDInt / LInt / ULInt / Real / LReal / " +
|
||||
"String / WString / Time / Date / DateTime / TimeOfDay (default DInt).")]
|
||||
public TwinCATDataType DataType { get; init; } = TwinCATDataType.DInt;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async ValueTask ExecuteAsync(IConsole console)
|
||||
{
|
||||
Validate();
|
||||
|
||||
@@ -11,17 +11,20 @@ namespace ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.Cli.Commands;
|
||||
[Command("read", Description = "Read a single TwinCAT symbol.")]
|
||||
public sealed class ReadCommand : TwinCATTagCommandBase
|
||||
{
|
||||
/// <summary>Gets or sets the TwinCAT symbol path to read.</summary>
|
||||
[CommandOption("symbol", 's', Description =
|
||||
"Symbol path. Program scope: 'MAIN.bStart'. Global: 'GVL.Counter'. " +
|
||||
"Nested UDT member: 'Motor1.Status.Running'. Array element: 'Recipe[3]'.",
|
||||
IsRequired = true)]
|
||||
public string SymbolPath { get; init; } = default!;
|
||||
|
||||
/// <summary>Gets or sets the data type of the symbol being read.</summary>
|
||||
[CommandOption("type", 't', Description =
|
||||
"Bool / SInt / USInt / Int / UInt / DInt / UDInt / LInt / ULInt / Real / LReal / " +
|
||||
"String / WString / Time / Date / DateTime / TimeOfDay (default DInt).")]
|
||||
public TwinCATDataType DataType { get; init; } = TwinCATDataType.DInt;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async ValueTask ExecuteAsync(IConsole console)
|
||||
{
|
||||
Validate();
|
||||
@@ -50,6 +53,10 @@ public sealed class ReadCommand : TwinCATTagCommandBase
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Synthesizes an internal tag name from a symbol path and data type.</summary>
|
||||
/// <param name="symbolPath">The TwinCAT symbol path.</param>
|
||||
/// <param name="type">The data type of the symbol.</param>
|
||||
/// <returns>A synthesized tag name combining the symbol path and type.</returns>
|
||||
internal static string SynthesiseTagName(string symbolPath, TwinCATDataType type)
|
||||
=> $"{symbolPath}:{type}";
|
||||
}
|
||||
|
||||
@@ -13,17 +13,21 @@ namespace ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.Cli.Commands;
|
||||
[Command("subscribe", Description = "Watch a TwinCAT symbol via ADS notification or poll, until Ctrl+C.")]
|
||||
public sealed class SubscribeCommand : TwinCATTagCommandBase
|
||||
{
|
||||
/// <summary>Gets the TwinCAT symbol path to subscribe to.</summary>
|
||||
[CommandOption("symbol", 's', Description = "Symbol path — same format as `read`.", IsRequired = true)]
|
||||
public string SymbolPath { get; init; } = default!;
|
||||
|
||||
/// <summary>Gets the TwinCAT data type of the symbol.</summary>
|
||||
[CommandOption("type", 't', Description =
|
||||
"Bool / SInt / USInt / Int / UInt / DInt / UDInt / LInt / ULInt / Real / LReal / " +
|
||||
"String / WString / Time / Date / DateTime / TimeOfDay (default DInt).")]
|
||||
public TwinCATDataType DataType { get; init; } = TwinCATDataType.DInt;
|
||||
|
||||
/// <summary>Gets the publishing interval in milliseconds.</summary>
|
||||
[CommandOption("interval-ms", 'i', Description = "Publishing interval ms (default 1000).")]
|
||||
public int IntervalMs { get; init; } = 1000;
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Validate()
|
||||
{
|
||||
base.Validate();
|
||||
@@ -32,6 +36,7 @@ public sealed class SubscribeCommand : TwinCATTagCommandBase
|
||||
$"--interval-ms must be greater than 0 (got {IntervalMs}).");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async ValueTask ExecuteAsync(IConsole console)
|
||||
{
|
||||
Validate();
|
||||
@@ -113,6 +118,8 @@ public sealed class SubscribeCommand : TwinCATTagCommandBase
|
||||
/// different format — anything else means we landed on the poll loop. Internal so the
|
||||
/// test assembly can cover the mapping without spinning a real driver.
|
||||
/// </summary>
|
||||
/// <param name="handle">The subscription handle to describe.</param>
|
||||
/// <returns>A description of the subscription mechanism ("ADS notification" or "polling").</returns>
|
||||
internal static string DescribeMechanism(ISubscriptionHandle handle) =>
|
||||
handle.DiagnosticId.StartsWith("twincat-native-sub-", StringComparison.Ordinal)
|
||||
? "ADS notification"
|
||||
|
||||
@@ -13,20 +13,24 @@ namespace ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.Cli.Commands;
|
||||
[Command("write", Description = "Write a single TwinCAT symbol.")]
|
||||
public sealed class WriteCommand : TwinCATTagCommandBase
|
||||
{
|
||||
/// <summary>Gets the symbol path to write.</summary>
|
||||
[CommandOption("symbol", 's', Description =
|
||||
"Symbol path — same format as `read`.", IsRequired = true)]
|
||||
public string SymbolPath { get; init; } = default!;
|
||||
|
||||
/// <summary>Gets the data type of the symbol value.</summary>
|
||||
[CommandOption("type", 't', Description =
|
||||
"Bool / SInt / USInt / Int / UInt / DInt / UDInt / LInt / ULInt / Real / LReal / " +
|
||||
"String / WString / Time / Date / DateTime / TimeOfDay (default DInt).")]
|
||||
public TwinCATDataType DataType { get; init; } = TwinCATDataType.DInt;
|
||||
|
||||
/// <summary>Gets the value to write.</summary>
|
||||
[CommandOption("value", 'v', Description =
|
||||
"Value to write. Parsed per --type (booleans accept true/false/1/0).",
|
||||
IsRequired = true)]
|
||||
public string Value { get; init; } = default!;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async ValueTask ExecuteAsync(IConsole console)
|
||||
{
|
||||
Validate();
|
||||
@@ -63,6 +67,8 @@ public sealed class WriteCommand : TwinCATTagCommandBase
|
||||
}
|
||||
|
||||
/// <summary>Parse <c>--value</c> per <see cref="TwinCATDataType"/>, invariant culture.</summary>
|
||||
/// <param name="raw">The raw string value to parse.</param>
|
||||
/// <param name="type">The target TwinCAT data type.</param>
|
||||
internal static object ParseValue(string raw, TwinCATDataType type) => type switch
|
||||
{
|
||||
TwinCATDataType.Bool => ParseBool(raw),
|
||||
|
||||
@@ -13,27 +13,31 @@ namespace ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.Cli;
|
||||
/// </summary>
|
||||
public abstract class TwinCATCommandBase : DriverCommandBase
|
||||
{
|
||||
/// <summary>Gets the AMS Net ID of the target runtime.</summary>
|
||||
[CommandOption("ams-net-id", 'n', Description =
|
||||
"AMS Net ID of the target runtime (e.g. '192.168.1.40.1.1' or '127.0.0.1.1.1' for local).",
|
||||
IsRequired = true)]
|
||||
public string AmsNetId { get; init; } = default!;
|
||||
|
||||
/// <summary>Gets the AMS port number.</summary>
|
||||
[CommandOption("ams-port", 'p', Description =
|
||||
"AMS port. TwinCAT 3 PLC runtime defaults to 851; TwinCAT 2 uses 801.")]
|
||||
public int AmsPort { get; init; } = 851;
|
||||
|
||||
/// <summary>Gets the per-operation timeout in milliseconds.</summary>
|
||||
[CommandOption("timeout-ms", Description = "Per-operation timeout in ms (default 5000).")]
|
||||
public int TimeoutMs { get; init; } = 5000;
|
||||
|
||||
/// <summary>
|
||||
/// The per-operation timeout, projected from <see cref="TimeoutMs"/>. The CliFx
|
||||
/// Gets the per-operation timeout, projected from <see cref="TimeoutMs"/>. The CliFx
|
||||
/// <c>init</c> accessor required by the abstract base property is intentionally a
|
||||
/// no-op: <see cref="TimeoutMs"/> is the only source of truth, so any value an
|
||||
/// `init` initialiser supplies to <see cref="Timeout"/> directly is silently
|
||||
/// `init` initialiser supplies to this property directly is silently
|
||||
/// dropped. Do NOT add a backing field "fixing" the empty body — it would diverge
|
||||
/// from <see cref="TimeoutMs"/> and the two would drift on every refactor
|
||||
/// (Driver.TwinCAT.Cli-007).
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
public override TimeSpan Timeout
|
||||
{
|
||||
get => TimeSpan.FromMilliseconds(TimeoutMs);
|
||||
@@ -41,11 +45,12 @@ public abstract class TwinCATCommandBase : DriverCommandBase
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Canonical TwinCAT gateway string the driver's <c>TwinCATAmsAddress.TryParse</c>
|
||||
/// Gets the canonical TwinCAT gateway string the driver's <c>TwinCATAmsAddress.TryParse</c>
|
||||
/// consumes — shape <c>ads://{AmsNetId}:{AmsPort}</c>.
|
||||
/// </summary>
|
||||
protected string Gateway => $"ads://{AmsNetId}:{AmsPort}";
|
||||
|
||||
/// <summary>Gets the driver instance ID for this command.</summary>
|
||||
protected string DriverInstanceId => $"twincat-cli-{AmsNetId}:{AmsPort}";
|
||||
|
||||
/// <summary>
|
||||
@@ -68,7 +73,12 @@ public abstract class TwinCATCommandBase : DriverCommandBase
|
||||
// Protected members are exposed to the test assembly through these internal accessors so the
|
||||
// test project can cover Gateway / DriverInstanceId composition + range validation without
|
||||
// needing reflection on every assertion (Driver.TwinCAT.Cli-006).
|
||||
/// <summary>Gets the gateway string for testing.</summary>
|
||||
internal string GatewayForTest => Gateway;
|
||||
|
||||
/// <summary>Gets the driver instance ID for testing.</summary>
|
||||
internal string DriverInstanceIdForTest => DriverInstanceId;
|
||||
|
||||
/// <summary>Validates the command for testing.</summary>
|
||||
internal void ValidateForTest() => Validate();
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ namespace ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.Cli;
|
||||
/// </summary>
|
||||
public abstract class TwinCATTagCommandBase : TwinCATCommandBase
|
||||
{
|
||||
/// <summary>Gets or sets a value indicating whether to use polling instead of native ADS notifications.</summary>
|
||||
[CommandOption("poll-only", Description =
|
||||
"Disable native ADS notifications and fall through to the shared PollGroupEngine " +
|
||||
"(same as setting UseNativeNotifications=false in a real driver config).")]
|
||||
@@ -22,6 +23,7 @@ public abstract class TwinCATTagCommandBase : TwinCATCommandBase
|
||||
/// the tag list a subclass supplies. Probe disabled, controller-browse disabled,
|
||||
/// native notifications toggled by <see cref="PollOnly"/>.
|
||||
/// </summary>
|
||||
/// <param name="tags">Tag definitions for the driver.</param>
|
||||
protected TwinCATDriverOptions BuildOptions(IReadOnlyList<TwinCATTagDefinition> tags) => new()
|
||||
{
|
||||
Devices = [new TwinCATDeviceOptions(
|
||||
@@ -35,6 +37,8 @@ public abstract class TwinCATTagCommandBase : TwinCATCommandBase
|
||||
};
|
||||
|
||||
// ---- Test hook ----
|
||||
/// <summary>Test hook that exposes BuildOptions for unit testing.</summary>
|
||||
/// <param name="tags">Tag definitions for the driver.</param>
|
||||
internal TwinCATDriverOptions BuildOptionsForTest(IReadOnlyList<TwinCATTagDefinition> tags)
|
||||
=> BuildOptions(tags);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user