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:
@@ -57,12 +57,14 @@ public enum FocasOperationMode : short
|
||||
public static class FocasOperationModeExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Canonical operator-facing label for an operation mode (e.g. <c>"AUTO"</c>,
|
||||
/// Gets the canonical operator-facing label for an operation mode (e.g. <c>"AUTO"</c>,
|
||||
/// <c>"EDIT"</c>). Delegates to <see cref="FocasOpMode.ToText"/> so the wire layer
|
||||
/// and the fixed-tree projection render identical labels — historically these two
|
||||
/// surfaces diverged ("TJOG" vs "T-JOG", "TEACH_IN_HANDLE" vs "TEACH-IN-HANDLE",
|
||||
/// and different unknown-code fallbacks). Resolved by Driver.FOCAS-010.
|
||||
/// </summary>
|
||||
/// <param name="mode">The operation mode.</param>
|
||||
/// <returns>The operator-facing label.</returns>
|
||||
public static string ToText(this FocasOperationMode mode) =>
|
||||
FocasOpMode.ToText((short)mode);
|
||||
}
|
||||
@@ -74,6 +76,9 @@ public static class FocasOperationModeExtensions
|
||||
/// </summary>
|
||||
internal static class FocasPmcAreaLookup
|
||||
{
|
||||
/// <summary>Looks up a PMC area code by letter.</summary>
|
||||
/// <param name="letter">The PMC area letter (case-insensitive).</param>
|
||||
/// <returns>The corresponding FocasPmcArea, or null if not recognized.</returns>
|
||||
public static FocasPmcArea? FromLetter(string letter) => letter.ToUpperInvariant() switch
|
||||
{
|
||||
"G" => FocasPmcArea.G,
|
||||
@@ -98,6 +103,9 @@ internal static class FocasPmcAreaLookup
|
||||
/// </summary>
|
||||
internal static class FocasPmcDataTypeLookup
|
||||
{
|
||||
/// <summary>Maps a FocasDataType to the corresponding PMC wire data type.</summary>
|
||||
/// <param name="t">The FOCAS data type.</param>
|
||||
/// <returns>The PMC data type for wire communication.</returns>
|
||||
public static FocasPmcDataType FromFocasDataType(FocasDataType t) => t switch
|
||||
{
|
||||
FocasDataType.Bit or FocasDataType.Byte => FocasPmcDataType.Byte,
|
||||
|
||||
@@ -46,6 +46,7 @@ public sealed class FocasWireClient : IAsyncDisposable, IDisposable
|
||||
/// Construct a disconnected client. Optional <paramref name="logger"/> receives
|
||||
/// <c>Debug</c>-level entries per response block (command ID, RC, payload length).
|
||||
/// </summary>
|
||||
/// <param name="logger">Optional logger for debug-level wire protocol entries.</param>
|
||||
public FocasWireClient(ILogger<FocasWireClient>? logger = null)
|
||||
{
|
||||
_logger = logger;
|
||||
@@ -65,6 +66,10 @@ public sealed class FocasWireClient : IAsyncDisposable, IDisposable
|
||||
/// call while already connected is a no-op. Sub-second timeouts require the
|
||||
/// <see cref="ConnectAsync(string, int, TimeSpan, CancellationToken)"/> overload.
|
||||
/// </summary>
|
||||
/// <param name="host">The CNC hostname or IP address.</param>
|
||||
/// <param name="port">The FOCAS/2 TCP port (typically 8193).</param>
|
||||
/// <param name="timeoutSeconds">Connection timeout in seconds; zero or negative disables the timeout.</param>
|
||||
/// <param name="cancellationToken">Cancellation token for the connect operation.</param>
|
||||
public Task ConnectAsync(
|
||||
string host,
|
||||
int port,
|
||||
@@ -81,6 +86,10 @@ public sealed class FocasWireClient : IAsyncDisposable, IDisposable
|
||||
/// <see cref="TimeSpan.Zero"/> to disable the timeout entirely (rely on the caller's
|
||||
/// <paramref name="cancellationToken"/> instead). Idempotent.
|
||||
/// </summary>
|
||||
/// <param name="host">The CNC hostname or IP address.</param>
|
||||
/// <param name="port">The FOCAS/2 TCP port (typically 8193).</param>
|
||||
/// <param name="timeout">Connection timeout duration; <see cref="TimeSpan.Zero"/> disables the timeout.</param>
|
||||
/// <param name="cancellationToken">Cancellation token for the connect operation.</param>
|
||||
public Task ConnectAsync(
|
||||
string host,
|
||||
int port,
|
||||
@@ -206,6 +215,9 @@ public sealed class FocasWireClient : IAsyncDisposable, IDisposable
|
||||
/// Read CNC identity via <c>cnc_sysinfo</c>. Cached from the connect-time exchange
|
||||
/// unless a per-call <paramref name="pathId"/> override is supplied.
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">Cancellation token for the read operation.</param>
|
||||
/// <param name="timeout">Optional per-call timeout override.</param>
|
||||
/// <param name="pathId">Optional path ID override; defaults to <see cref="PathId"/>.</param>
|
||||
public async Task<FocasResult<WireSysInfo>> ReadSysInfoAsync(
|
||||
CancellationToken cancellationToken = default,
|
||||
TimeSpan? timeout = null,
|
||||
@@ -218,6 +230,9 @@ public sealed class FocasWireClient : IAsyncDisposable, IDisposable
|
||||
}
|
||||
|
||||
/// <summary>Read CNC status bits via <c>cnc_statinfo</c> (3 command blocks aggregated into one <see cref="WireStatus"/>).</summary>
|
||||
/// <param name="cancellationToken">Cancellation token for the read operation.</param>
|
||||
/// <param name="timeout">Optional per-call timeout override.</param>
|
||||
/// <param name="pathId">Optional path ID override; defaults to <see cref="PathId"/>.</param>
|
||||
public async Task<FocasResult<WireStatus>> ReadStatusAsync(
|
||||
CancellationToken cancellationToken = default,
|
||||
TimeSpan? timeout = null,
|
||||
@@ -253,6 +268,10 @@ public sealed class FocasWireClient : IAsyncDisposable, IDisposable
|
||||
}
|
||||
|
||||
/// <summary>Read configured axis names via <c>cnc_rdaxisname</c> (command <c>0x0089</c>).</summary>
|
||||
/// <param name="maxCount">Maximum number of axis records to return.</param>
|
||||
/// <param name="cancellationToken">Cancellation token for the read operation.</param>
|
||||
/// <param name="timeout">Optional per-call timeout override.</param>
|
||||
/// <param name="pathId">Optional path ID override; defaults to <see cref="PathId"/>.</param>
|
||||
public async Task<FocasResult<IReadOnlyList<WireAxisRecord>>> ReadAxisNamesAsync(
|
||||
short maxCount = 32,
|
||||
CancellationToken cancellationToken = default,
|
||||
@@ -265,6 +284,10 @@ public sealed class FocasWireClient : IAsyncDisposable, IDisposable
|
||||
}
|
||||
|
||||
/// <summary>Read configured spindle names via <c>cnc_rdspdlname</c> (command <c>0x008a</c>).</summary>
|
||||
/// <param name="maxCount">Maximum number of spindle records to return.</param>
|
||||
/// <param name="cancellationToken">Cancellation token for the read operation.</param>
|
||||
/// <param name="timeout">Optional per-call timeout override.</param>
|
||||
/// <param name="pathId">Optional path ID override; defaults to <see cref="PathId"/>.</param>
|
||||
public async Task<FocasResult<IReadOnlyList<WireSpindleRecord>>> ReadSpindleNamesAsync(
|
||||
short maxCount = 8,
|
||||
CancellationToken cancellationToken = default,
|
||||
@@ -281,6 +304,10 @@ public sealed class FocasWireClient : IAsyncDisposable, IDisposable
|
||||
/// one PDU and aggregates the replies — alarm flags, program/sequence numbers, feed
|
||||
/// and spindle actuals, plus the four-slot position quadruple.
|
||||
/// </summary>
|
||||
/// <param name="axis">The axis number to read from.</param>
|
||||
/// <param name="cancellationToken">Cancellation token for the read operation.</param>
|
||||
/// <param name="timeout">Optional per-call timeout override.</param>
|
||||
/// <param name="pathId">Optional path ID override; defaults to <see cref="PathId"/>.</param>
|
||||
public async Task<FocasResult<WireDynamic>> ReadDynamic2Async(
|
||||
short axis = 1,
|
||||
CancellationToken cancellationToken = default,
|
||||
@@ -322,6 +349,10 @@ public sealed class FocasWireClient : IAsyncDisposable, IDisposable
|
||||
}
|
||||
|
||||
/// <summary>Read servo-meter load percentages via <c>cnc_rdsvmeter</c> (command <c>0x0056</c>).</summary>
|
||||
/// <param name="maxCount">Maximum number of servo meter records to return.</param>
|
||||
/// <param name="cancellationToken">Cancellation token for the read operation.</param>
|
||||
/// <param name="timeout">Optional per-call timeout override.</param>
|
||||
/// <param name="pathId">Optional path ID override; defaults to <see cref="PathId"/>.</param>
|
||||
public async Task<FocasResult<IReadOnlyList<WireServoMeter>>> ReadServoMeterAsync(
|
||||
short maxCount = 32,
|
||||
CancellationToken cancellationToken = default,
|
||||
@@ -355,6 +386,10 @@ public sealed class FocasWireClient : IAsyncDisposable, IDisposable
|
||||
}
|
||||
|
||||
/// <summary>Read per-spindle load percentages via <c>cnc_rdspload</c> (command <c>0x0040</c> with arg1=0).</summary>
|
||||
/// <param name="spindleSelector">Spindle selector; -1 selects all spindles.</param>
|
||||
/// <param name="cancellationToken">Cancellation token for the read operation.</param>
|
||||
/// <param name="timeout">Optional per-call timeout override.</param>
|
||||
/// <param name="pathId">Optional path ID override; defaults to <see cref="PathId"/>.</param>
|
||||
public Task<FocasResult<IReadOnlyList<WireSpindleMetric>>> ReadSpindleLoadAsync(
|
||||
short spindleSelector = -1,
|
||||
CancellationToken cancellationToken = default,
|
||||
@@ -363,6 +398,10 @@ public sealed class FocasWireClient : IAsyncDisposable, IDisposable
|
||||
=> ReadSpindleMetricAsync(0, spindleSelector, cancellationToken, timeout, pathId);
|
||||
|
||||
/// <summary>Read per-spindle maximum RPMs via <c>cnc_rdspmaxrpm</c> (command <c>0x0040</c> with arg1=1).</summary>
|
||||
/// <param name="spindleSelector">Spindle selector; -1 selects all spindles.</param>
|
||||
/// <param name="cancellationToken">Cancellation token for the read operation.</param>
|
||||
/// <param name="timeout">Optional per-call timeout override.</param>
|
||||
/// <param name="pathId">Optional path ID override; defaults to <see cref="PathId"/>.</param>
|
||||
public Task<FocasResult<IReadOnlyList<WireSpindleMetric>>> ReadSpindleMaxRpmAsync(
|
||||
short spindleSelector = -1,
|
||||
CancellationToken cancellationToken = default,
|
||||
@@ -375,6 +414,11 @@ public sealed class FocasWireClient : IAsyncDisposable, IDisposable
|
||||
/// payload to the type declared in the per-series parameter catalog. <paramref name="axis"/>
|
||||
/// selects an axis-scoped parameter; <c>0</c> means global.
|
||||
/// </summary>
|
||||
/// <param name="dataNumber">The parameter data number.</param>
|
||||
/// <param name="axis">Axis selector; zero means a global parameter.</param>
|
||||
/// <param name="cancellationToken">Cancellation token for the read operation.</param>
|
||||
/// <param name="timeout">Optional per-call timeout override.</param>
|
||||
/// <param name="pathId">Optional path ID override; defaults to <see cref="PathId"/>.</param>
|
||||
public async Task<FocasResult<byte[]>> ReadParameterBytesAsync(
|
||||
short dataNumber,
|
||||
short axis = 0,
|
||||
@@ -389,6 +433,11 @@ public sealed class FocasWireClient : IAsyncDisposable, IDisposable
|
||||
}
|
||||
|
||||
/// <summary>Typed Int32 parameter read — convenience over <see cref="ReadParameterBytesAsync"/>.</summary>
|
||||
/// <param name="dataNumber">The parameter data number.</param>
|
||||
/// <param name="type">The FOCAS parameter type code.</param>
|
||||
/// <param name="cancellationToken">Cancellation token for the read operation.</param>
|
||||
/// <param name="timeout">Optional per-call timeout override.</param>
|
||||
/// <param name="pathId">Optional path ID override; defaults to <see cref="PathId"/>.</param>
|
||||
public async Task<FocasResult<WireParameter>> ReadParameterAsync(
|
||||
short dataNumber,
|
||||
short type = 0,
|
||||
@@ -404,6 +453,11 @@ public sealed class FocasWireClient : IAsyncDisposable, IDisposable
|
||||
}
|
||||
|
||||
/// <summary>Typed 8-bit parameter read.</summary>
|
||||
/// <param name="dataNumber">The parameter data number.</param>
|
||||
/// <param name="axis">Axis selector; zero means a global parameter.</param>
|
||||
/// <param name="cancellationToken">Cancellation token for the read operation.</param>
|
||||
/// <param name="timeout">Optional per-call timeout override.</param>
|
||||
/// <param name="pathId">Optional path ID override; defaults to <see cref="PathId"/>.</param>
|
||||
public async Task<FocasResult<byte>> ReadParameterByteAsync(short dataNumber, short axis = 0, CancellationToken cancellationToken = default, TimeSpan? timeout = null, ushort? pathId = null)
|
||||
{
|
||||
var result = await ReadParameterBytesAsync(dataNumber, axis, cancellationToken, timeout, pathId).ConfigureAwait(false);
|
||||
@@ -413,6 +467,11 @@ public sealed class FocasWireClient : IAsyncDisposable, IDisposable
|
||||
}
|
||||
|
||||
/// <summary>Typed 16-bit parameter read.</summary>
|
||||
/// <param name="dataNumber">The parameter data number.</param>
|
||||
/// <param name="axis">Axis selector; zero means a global parameter.</param>
|
||||
/// <param name="cancellationToken">Cancellation token for the read operation.</param>
|
||||
/// <param name="timeout">Optional per-call timeout override.</param>
|
||||
/// <param name="pathId">Optional path ID override; defaults to <see cref="PathId"/>.</param>
|
||||
public async Task<FocasResult<short>> ReadParameterInt16Async(short dataNumber, short axis = 0, CancellationToken cancellationToken = default, TimeSpan? timeout = null, ushort? pathId = null)
|
||||
{
|
||||
var result = await ReadParameterBytesAsync(dataNumber, axis, cancellationToken, timeout, pathId).ConfigureAwait(false);
|
||||
@@ -422,6 +481,11 @@ public sealed class FocasWireClient : IAsyncDisposable, IDisposable
|
||||
}
|
||||
|
||||
/// <summary>Typed 32-bit parameter read.</summary>
|
||||
/// <param name="dataNumber">The parameter data number.</param>
|
||||
/// <param name="axis">Axis selector; zero means a global parameter.</param>
|
||||
/// <param name="cancellationToken">Cancellation token for the read operation.</param>
|
||||
/// <param name="timeout">Optional per-call timeout override.</param>
|
||||
/// <param name="pathId">Optional path ID override; defaults to <see cref="PathId"/>.</param>
|
||||
public async Task<FocasResult<int>> ReadParameterInt32Async(short dataNumber, short axis = 0, CancellationToken cancellationToken = default, TimeSpan? timeout = null, ushort? pathId = null)
|
||||
{
|
||||
var result = await ReadParameterBytesAsync(dataNumber, axis, cancellationToken, timeout, pathId).ConfigureAwait(false);
|
||||
@@ -431,6 +495,11 @@ public sealed class FocasWireClient : IAsyncDisposable, IDisposable
|
||||
}
|
||||
|
||||
/// <summary>Typed IEEE-754 single-precision parameter read.</summary>
|
||||
/// <param name="dataNumber">The parameter data number.</param>
|
||||
/// <param name="axis">Axis selector; zero means a global parameter.</param>
|
||||
/// <param name="cancellationToken">Cancellation token for the read operation.</param>
|
||||
/// <param name="timeout">Optional per-call timeout override.</param>
|
||||
/// <param name="pathId">Optional path ID override; defaults to <see cref="PathId"/>.</param>
|
||||
public async Task<FocasResult<float>> ReadParameterFloat32Async(short dataNumber, short axis = 0, CancellationToken cancellationToken = default, TimeSpan? timeout = null, ushort? pathId = null)
|
||||
{
|
||||
var result = await ReadParameterBytesAsync(dataNumber, axis, cancellationToken, timeout, pathId).ConfigureAwait(false);
|
||||
@@ -440,6 +509,11 @@ public sealed class FocasWireClient : IAsyncDisposable, IDisposable
|
||||
}
|
||||
|
||||
/// <summary>Typed IEEE-754 double-precision parameter read.</summary>
|
||||
/// <param name="dataNumber">The parameter data number.</param>
|
||||
/// <param name="axis">Axis selector; zero means a global parameter.</param>
|
||||
/// <param name="cancellationToken">Cancellation token for the read operation.</param>
|
||||
/// <param name="timeout">Optional per-call timeout override.</param>
|
||||
/// <param name="pathId">Optional path ID override; defaults to <see cref="PathId"/>.</param>
|
||||
public async Task<FocasResult<double>> ReadParameterFloat64Async(short dataNumber, short axis = 0, CancellationToken cancellationToken = default, TimeSpan? timeout = null, ushort? pathId = null)
|
||||
{
|
||||
var result = await ReadParameterBytesAsync(dataNumber, axis, cancellationToken, timeout, pathId).ConfigureAwait(false);
|
||||
@@ -449,6 +523,10 @@ public sealed class FocasWireClient : IAsyncDisposable, IDisposable
|
||||
}
|
||||
|
||||
/// <summary>Read a single macro variable via <c>cnc_rdmacro</c> (command <c>0x0015</c>).</summary>
|
||||
/// <param name="number">The macro variable number.</param>
|
||||
/// <param name="cancellationToken">Cancellation token for the read operation.</param>
|
||||
/// <param name="timeout">Optional per-call timeout override.</param>
|
||||
/// <param name="pathId">Optional path ID override; defaults to <see cref="PathId"/>.</param>
|
||||
public Task<FocasResult<WireMacro>> ReadMacroAsync(
|
||||
short number,
|
||||
CancellationToken cancellationToken = default,
|
||||
@@ -465,6 +543,13 @@ public sealed class FocasWireClient : IAsyncDisposable, IDisposable
|
||||
/// is the width code (see <see cref="FocasPmcDataType"/>). Payload is decoded into
|
||||
/// <see cref="WirePmcRange.Values"/> — one entry per slot of the requested width.
|
||||
/// </summary>
|
||||
/// <param name="area">The PMC address-letter code numeric value.</param>
|
||||
/// <param name="dataType">The PMC data width code numeric value.</param>
|
||||
/// <param name="start">The starting address.</param>
|
||||
/// <param name="end">The ending address; must be greater than or equal to start.</param>
|
||||
/// <param name="cancellationToken">Cancellation token for the read operation.</param>
|
||||
/// <param name="timeout">Optional per-call timeout override.</param>
|
||||
/// <param name="pathId">Optional path ID override; defaults to <see cref="PathId"/>.</param>
|
||||
public async Task<FocasResult<WirePmcRange>> ReadPmcRangeAsync(
|
||||
short area,
|
||||
short dataType,
|
||||
@@ -510,6 +595,13 @@ public sealed class FocasWireClient : IAsyncDisposable, IDisposable
|
||||
}
|
||||
|
||||
/// <summary>Typed overload for <see cref="ReadPmcRangeAsync(short, short, ushort, ushort, CancellationToken, TimeSpan?, ushort?)"/>.</summary>
|
||||
/// <param name="area">The PMC address-letter code.</param>
|
||||
/// <param name="dataType">The PMC data width code.</param>
|
||||
/// <param name="start">The starting address.</param>
|
||||
/// <param name="end">The ending address; must be greater than or equal to start.</param>
|
||||
/// <param name="cancellationToken">Cancellation token for the read operation.</param>
|
||||
/// <param name="timeout">Optional per-call timeout override.</param>
|
||||
/// <param name="pathId">Optional path ID override; defaults to <see cref="PathId"/>.</param>
|
||||
public Task<FocasResult<WirePmcRange>> ReadPmcRangeAsync(
|
||||
FocasPmcArea area,
|
||||
FocasPmcDataType dataType,
|
||||
@@ -525,6 +617,11 @@ public sealed class FocasWireClient : IAsyncDisposable, IDisposable
|
||||
/// the 76-byte vendor <c>ODBALMMSG2_data</c> layout and the 80-byte legacy wire
|
||||
/// shape so the same managed surface works across firmware revisions.
|
||||
/// </summary>
|
||||
/// <param name="type">Alarm type filter; -1 reads all active alarms.</param>
|
||||
/// <param name="count">Maximum number of alarms to return.</param>
|
||||
/// <param name="cancellationToken">Cancellation token for the read operation.</param>
|
||||
/// <param name="timeout">Optional per-call timeout override.</param>
|
||||
/// <param name="pathId">Optional path ID override; defaults to <see cref="PathId"/>.</param>
|
||||
public async Task<FocasResult<IReadOnlyList<WireAlarm>>> ReadAlarmsAsync(
|
||||
short type = -1,
|
||||
short count = 32,
|
||||
@@ -541,6 +638,9 @@ public sealed class FocasWireClient : IAsyncDisposable, IDisposable
|
||||
}
|
||||
|
||||
/// <summary>Read operation mode via <c>cnc_rdopmode</c>, returned as the typed <see cref="FocasOperationMode"/>.</summary>
|
||||
/// <param name="cancellationToken">Cancellation token for the read operation.</param>
|
||||
/// <param name="timeout">Optional per-call timeout override.</param>
|
||||
/// <param name="pathId">Optional path ID override; defaults to <see cref="PathId"/>.</param>
|
||||
public Task<FocasResult<FocasOperationMode>> ReadOperationModeAsync(
|
||||
CancellationToken cancellationToken = default,
|
||||
TimeSpan? timeout = null,
|
||||
@@ -555,6 +655,9 @@ public sealed class FocasWireClient : IAsyncDisposable, IDisposable
|
||||
/// FOCAS <c>short</c> so callers storing the raw mode code (e.g. OtOpcUa's
|
||||
/// <c>FocasProgramInfo.Mode</c> int field) don't have to cast the enum.
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">Cancellation token for the read operation.</param>
|
||||
/// <param name="timeout">Optional per-call timeout override.</param>
|
||||
/// <param name="pathId">Optional path ID override; defaults to <see cref="PathId"/>.</param>
|
||||
public Task<FocasResult<short>> ReadOperationModeCodeAsync(
|
||||
CancellationToken cancellationToken = default,
|
||||
TimeSpan? timeout = null,
|
||||
@@ -565,6 +668,9 @@ public sealed class FocasWireClient : IAsyncDisposable, IDisposable
|
||||
cancellationToken, timeout, EffectivePathId(pathId));
|
||||
|
||||
/// <summary>Read the currently-executing program name + O-number via <c>cnc_exeprgname2</c> (command <c>0x00fc</c>).</summary>
|
||||
/// <param name="cancellationToken">Cancellation token for the read operation.</param>
|
||||
/// <param name="timeout">Optional per-call timeout override.</param>
|
||||
/// <param name="pathId">Optional path ID override; defaults to <see cref="PathId"/>.</param>
|
||||
public Task<FocasResult<WireProgramName>> ReadExecutingProgramNameAsync(
|
||||
CancellationToken cancellationToken = default,
|
||||
TimeSpan? timeout = null,
|
||||
@@ -572,6 +678,9 @@ public sealed class FocasWireClient : IAsyncDisposable, IDisposable
|
||||
=> ReadSingleWithTimeoutAsync(0x00fc, ParseProgramName, cancellationToken, timeout, EffectivePathId(pathId));
|
||||
|
||||
/// <summary>Read the executed block count via <c>cnc_rdblkcount</c>.</summary>
|
||||
/// <param name="cancellationToken">Cancellation token for the read operation.</param>
|
||||
/// <param name="timeout">Optional per-call timeout override.</param>
|
||||
/// <param name="pathId">Optional path ID override; defaults to <see cref="PathId"/>.</param>
|
||||
public Task<FocasResult<int>> ReadBlockCountAsync(
|
||||
CancellationToken cancellationToken = default,
|
||||
TimeSpan? timeout = null,
|
||||
@@ -585,6 +694,10 @@ public sealed class FocasWireClient : IAsyncDisposable, IDisposable
|
||||
/// Read one cumulative timer via <c>cnc_rdtimer</c>. <paramref name="type"/> selects
|
||||
/// PowerOn / Operating / Cutting / Cycle per the FOCAS spec (0..3).
|
||||
/// </summary>
|
||||
/// <param name="type">Timer type selector (0=PowerOn, 1=Operating, 2=Cutting, 3=Cycle).</param>
|
||||
/// <param name="cancellationToken">Cancellation token for the read operation.</param>
|
||||
/// <param name="timeout">Optional per-call timeout override.</param>
|
||||
/// <param name="pathId">Optional path ID override; defaults to <see cref="PathId"/>.</param>
|
||||
public Task<FocasResult<WireTimer>> ReadTimerAsync(
|
||||
short type,
|
||||
CancellationToken cancellationToken = default,
|
||||
|
||||
@@ -26,11 +26,17 @@ public class FocasWireException : Exception
|
||||
/// </summary>
|
||||
public bool IsTransient { get; }
|
||||
|
||||
/// <summary>Initializes a new FOCAS wire exception with a message.</summary>
|
||||
/// <param name="message">The exception message.</param>
|
||||
public FocasWireException(string message)
|
||||
: base(message)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>Initializes a new FOCAS wire exception with message, return code, and transient flag.</summary>
|
||||
/// <param name="message">The exception message.</param>
|
||||
/// <param name="rc">The FOCAS return code, if available.</param>
|
||||
/// <param name="isTransient">Whether the transport was closed.</param>
|
||||
public FocasWireException(string message, short? rc, bool isTransient = false)
|
||||
: base(message)
|
||||
{
|
||||
@@ -38,11 +44,18 @@ public class FocasWireException : Exception
|
||||
IsTransient = isTransient;
|
||||
}
|
||||
|
||||
/// <summary>Initializes a new FOCAS wire exception with a message and inner exception.</summary>
|
||||
/// <param name="message">The exception message.</param>
|
||||
/// <param name="innerException">The inner exception.</param>
|
||||
public FocasWireException(string message, Exception innerException)
|
||||
: base(message, innerException)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>Initializes a new FOCAS wire exception with message, inner exception, and transient flag.</summary>
|
||||
/// <param name="message">The exception message.</param>
|
||||
/// <param name="innerException">The inner exception.</param>
|
||||
/// <param name="isTransient">Whether the transport was closed.</param>
|
||||
public FocasWireException(string message, Exception innerException, bool isTransient)
|
||||
: base(message, innerException)
|
||||
{
|
||||
|
||||
@@ -29,6 +29,10 @@ internal static class FocasWireProtocol
|
||||
private static readonly byte[] Magic = [0xa0, 0xa0, 0xa0, 0xa0];
|
||||
|
||||
/// <summary>Assemble a full PDU (10-byte header + body) for transmission.</summary>
|
||||
/// <param name="type">The PDU type byte.</param>
|
||||
/// <param name="direction">The direction byte (request or response).</param>
|
||||
/// <param name="body">The PDU body bytes.</param>
|
||||
/// <returns>The complete PDU bytes including header and body.</returns>
|
||||
public static byte[] BuildPdu(byte type, byte direction, ReadOnlySpan<byte> body)
|
||||
{
|
||||
if (body.Length > ushort.MaxValue)
|
||||
@@ -49,6 +53,8 @@ internal static class FocasWireProtocol
|
||||
/// opens two TCP sockets in sequence and each sends its own initiate PDU carrying its
|
||||
/// index.
|
||||
/// </summary>
|
||||
/// <param name="socketIndex">The socket index (1 or 2).</param>
|
||||
/// <returns>The initiate body bytes.</returns>
|
||||
public static byte[] BuildInitiateBody(ushort socketIndex)
|
||||
{
|
||||
var body = new byte[2];
|
||||
@@ -57,6 +63,8 @@ internal static class FocasWireProtocol
|
||||
}
|
||||
|
||||
/// <summary>Assemble a type-<c>0x21</c> body carrying one or more request blocks.</summary>
|
||||
/// <param name="blocks">The request blocks to assemble.</param>
|
||||
/// <returns>The assembled body bytes.</returns>
|
||||
public static byte[] BuildRequestBody(IReadOnlyList<RequestBlock> blocks)
|
||||
{
|
||||
if (blocks.Count > ushort.MaxValue)
|
||||
@@ -79,6 +87,9 @@ internal static class FocasWireProtocol
|
||||
}
|
||||
|
||||
/// <summary>Async read of one full PDU off a stream. Throws <see cref="FocasWireException"/> on invalid magic / version / truncation.</summary>
|
||||
/// <param name="stream">The network stream to read from.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>The read PDU.</returns>
|
||||
public static async Task<Pdu> ReadPduAsync(NetworkStream stream, CancellationToken cancellationToken)
|
||||
{
|
||||
var header = new byte[10];
|
||||
@@ -100,6 +111,8 @@ internal static class FocasWireProtocol
|
||||
}
|
||||
|
||||
/// <summary>Synchronous counterpart to <see cref="ReadPduAsync"/> — used by <see cref="FocasWireClient"/>'s sync dispose.</summary>
|
||||
/// <param name="stream">The network stream to read from.</param>
|
||||
/// <returns>The read PDU.</returns>
|
||||
public static Pdu ReadPdu(NetworkStream stream)
|
||||
{
|
||||
var header = new byte[10];
|
||||
@@ -149,6 +162,8 @@ internal static class FocasWireProtocol
|
||||
/// block carries the command ID, the FOCAS <c>EW_*</c> return code, and the payload
|
||||
/// bytes.
|
||||
/// </summary>
|
||||
/// <param name="body">The response body bytes.</param>
|
||||
/// <returns>The parsed response blocks.</returns>
|
||||
public static IReadOnlyList<ResponseBlock> ParseResponseBlocks(ReadOnlySpan<byte> body)
|
||||
{
|
||||
if (body.Length < 2)
|
||||
@@ -181,6 +196,8 @@ internal static class FocasWireProtocol
|
||||
}
|
||||
|
||||
/// <summary>Read an ASCII string out of a payload span, stopping at the first NUL and trimming trailing spaces.</summary>
|
||||
/// <param name="bytes">The bytes to decode.</param>
|
||||
/// <returns>The decoded ASCII string.</returns>
|
||||
public static string ReadAscii(ReadOnlySpan<byte> bytes)
|
||||
{
|
||||
var end = bytes.IndexOf((byte)0);
|
||||
@@ -193,6 +210,8 @@ internal static class FocasWireProtocol
|
||||
/// (spindle) slot. Trailing spaces and NULs are stripped so <c>"X "</c> becomes
|
||||
/// <c>"X"</c>.
|
||||
/// </summary>
|
||||
/// <param name="bytes">The bytes to decode.</param>
|
||||
/// <returns>The decoded name record.</returns>
|
||||
public static string ReadNameRecord(ReadOnlySpan<byte> bytes)
|
||||
{
|
||||
if (bytes.Length < 2) return string.Empty;
|
||||
|
||||
@@ -30,13 +30,19 @@ public sealed class WireFocasClient : IFocasClient
|
||||
/// <see cref="FocasWireClient"/> so the per-response Debug entries actually reach
|
||||
/// the host's logging pipeline (Driver.FOCAS-007).
|
||||
/// </summary>
|
||||
/// <param name="logger">Optional logger for debug output from wire client responses.</param>
|
||||
public WireFocasClient(ILogger<FocasWireClient>? logger)
|
||||
{
|
||||
_wire = new FocasWireClient(logger);
|
||||
}
|
||||
|
||||
/// <summary>Gets a value indicating whether the wire client is connected to the FOCAS host.</summary>
|
||||
public bool IsConnected => _wire.IsConnected;
|
||||
|
||||
/// <summary>Connects to a FOCAS host at the specified address.</summary>
|
||||
/// <param name="address">The host address containing the machine name and port.</param>
|
||||
/// <param name="timeout">The connection timeout; values less than or equal to zero are clamped to 1 second.</param>
|
||||
/// <param name="cancellationToken">Cancellation token for the operation.</param>
|
||||
public async Task ConnectAsync(FocasHostAddress address, TimeSpan timeout, CancellationToken cancellationToken)
|
||||
{
|
||||
if (_wire.IsConnected) return;
|
||||
@@ -48,6 +54,11 @@ public sealed class WireFocasClient : IFocasClient
|
||||
await _wire.ConnectAsync(address.Host, address.Port, effective, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>Reads a value from the specified FOCAS address.</summary>
|
||||
/// <param name="address">The FOCAS address to read from.</param>
|
||||
/// <param name="type">The FOCAS data type of the value.</param>
|
||||
/// <param name="cancellationToken">Cancellation token for the operation.</param>
|
||||
/// <returns>A tuple containing the read value and FOCAS status code.</returns>
|
||||
public async Task<(object? value, uint status)> ReadAsync(
|
||||
FocasAddress address, FocasDataType type, CancellationToken cancellationToken)
|
||||
{
|
||||
@@ -63,10 +74,19 @@ public sealed class WireFocasClient : IFocasClient
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>Writes a value to a FOCAS address (always returns BadNotWritable as OtOpcUa is read-only).</summary>
|
||||
/// <param name="address">The FOCAS address to write to.</param>
|
||||
/// <param name="type">The FOCAS data type of the value.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
/// <param name="cancellationToken">Cancellation token for the operation.</param>
|
||||
/// <returns>A task that returns the BadNotWritable status code.</returns>
|
||||
public Task<uint> WriteAsync(
|
||||
FocasAddress address, FocasDataType type, object? value, CancellationToken cancellationToken)
|
||||
=> Task.FromResult(FocasStatusMapper.BadNotWritable);
|
||||
|
||||
/// <summary>Probes the FOCAS host to verify connectivity.</summary>
|
||||
/// <param name="cancellationToken">Cancellation token for the operation.</param>
|
||||
/// <returns>True if the probe succeeds; otherwise false.</returns>
|
||||
public async Task<bool> ProbeAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
if (!_wire.IsConnected) return false;
|
||||
@@ -81,6 +101,9 @@ public sealed class WireFocasClient : IFocasClient
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Reads all active alarms from the FOCAS host.</summary>
|
||||
/// <param name="cancellationToken">Cancellation token for the operation.</param>
|
||||
/// <returns>A list of active alarms; empty if read fails or not connected.</returns>
|
||||
public async Task<IReadOnlyList<FocasActiveAlarm>> ReadAlarmsAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
if (!_wire.IsConnected) return [];
|
||||
@@ -102,6 +125,9 @@ public sealed class WireFocasClient : IFocasClient
|
||||
Message: a.Message ?? string.Empty);
|
||||
}
|
||||
|
||||
/// <summary>Gets system information from the FOCAS host.</summary>
|
||||
/// <param name="cancellationToken">Cancellation token for the operation.</param>
|
||||
/// <returns>The FOCAS system information.</returns>
|
||||
public async Task<FocasSysInfo> GetSysInfoAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
RequireConnected();
|
||||
@@ -121,6 +147,9 @@ public sealed class WireFocasClient : IFocasClient
|
||||
AxesCount: axesCount);
|
||||
}
|
||||
|
||||
/// <summary>Gets the names of all axes on the FOCAS host.</summary>
|
||||
/// <param name="cancellationToken">Cancellation token for the operation.</param>
|
||||
/// <returns>A list of axis names; empty if read fails or not connected.</returns>
|
||||
public async Task<IReadOnlyList<FocasAxisName>> GetAxisNamesAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
if (!_wire.IsConnected) return [];
|
||||
@@ -140,6 +169,9 @@ public sealed class WireFocasClient : IFocasClient
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Gets the names of all spindles on the FOCAS host.</summary>
|
||||
/// <param name="cancellationToken">Cancellation token for the operation.</param>
|
||||
/// <returns>A list of spindle names; empty if read fails or not connected.</returns>
|
||||
public async Task<IReadOnlyList<FocasSpindleName>> GetSpindleNamesAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
if (!_wire.IsConnected) return [];
|
||||
@@ -158,6 +190,10 @@ public sealed class WireFocasClient : IFocasClient
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Reads the dynamic state of a specified axis.</summary>
|
||||
/// <param name="axisIndex">The index of the axis to read.</param>
|
||||
/// <param name="cancellationToken">Cancellation token for the operation.</param>
|
||||
/// <returns>The dynamic snapshot of the axis.</returns>
|
||||
public async Task<FocasDynamicSnapshot> ReadDynamicAsync(int axisIndex, CancellationToken cancellationToken)
|
||||
{
|
||||
RequireConnected();
|
||||
@@ -179,6 +215,9 @@ public sealed class WireFocasClient : IFocasClient
|
||||
DistanceToGo: pos.Distance);
|
||||
}
|
||||
|
||||
/// <summary>Gets information about the currently executing program.</summary>
|
||||
/// <param name="cancellationToken">Cancellation token for the operation.</param>
|
||||
/// <returns>The current program information.</returns>
|
||||
public async Task<FocasProgramInfo> GetProgramInfoAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
RequireConnected();
|
||||
@@ -206,6 +245,10 @@ public sealed class WireFocasClient : IFocasClient
|
||||
Mode: modeResult.IsOk ? modeResult.Value : 0);
|
||||
}
|
||||
|
||||
/// <summary>Gets a timer value from the FOCAS host.</summary>
|
||||
/// <param name="kind">The kind of timer to read (run time, cutting time, etc.).</param>
|
||||
/// <param name="cancellationToken">Cancellation token for the operation.</param>
|
||||
/// <returns>The timer value.</returns>
|
||||
public async Task<FocasTimer> GetTimerAsync(FocasTimerKind kind, CancellationToken cancellationToken)
|
||||
{
|
||||
RequireConnected();
|
||||
@@ -215,6 +258,9 @@ public sealed class WireFocasClient : IFocasClient
|
||||
return new FocasTimer(kind, t.Minutes, t.Milliseconds);
|
||||
}
|
||||
|
||||
/// <summary>Gets servo load information for all axes.</summary>
|
||||
/// <param name="cancellationToken">Cancellation token for the operation.</param>
|
||||
/// <returns>A list of servo load values for each axis; empty if read fails or not connected.</returns>
|
||||
public async Task<IReadOnlyList<FocasServoLoad>> GetServoLoadsAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
if (!_wire.IsConnected) return [];
|
||||
@@ -226,9 +272,15 @@ public sealed class WireFocasClient : IFocasClient
|
||||
.ToList();
|
||||
}
|
||||
|
||||
/// <summary>Gets spindle load information for all spindles.</summary>
|
||||
/// <param name="cancellationToken">Cancellation token for the operation.</param>
|
||||
/// <returns>A list of spindle load percentages; empty if read fails or not connected.</returns>
|
||||
public Task<IReadOnlyList<int>> GetSpindleLoadsAsync(CancellationToken cancellationToken) =>
|
||||
ReadSpindleMetricAsync((sel, ct) => _wire.ReadSpindleLoadAsync(sel, ct), cancellationToken);
|
||||
|
||||
/// <summary>Gets maximum RPM information for all spindles.</summary>
|
||||
/// <param name="cancellationToken">Cancellation token for the operation.</param>
|
||||
/// <returns>A list of maximum RPM values for each spindle; empty if read fails or not connected.</returns>
|
||||
public Task<IReadOnlyList<int>> GetSpindleMaxRpmsAsync(CancellationToken cancellationToken) =>
|
||||
ReadSpindleMetricAsync((sel, ct) => _wire.ReadSpindleMaxRpmAsync(sel, ct), cancellationToken);
|
||||
|
||||
@@ -249,6 +301,7 @@ public sealed class WireFocasClient : IFocasClient
|
||||
return list;
|
||||
}
|
||||
|
||||
/// <summary>Disposes the wire client and releases all resources.</summary>
|
||||
public void Dispose() => _wire.Dispose();
|
||||
|
||||
// ---- PMC / Parameter / Macro read paths ------------------------------------------
|
||||
@@ -359,6 +412,7 @@ public sealed class WireFocasClientFactory : IFocasClientFactory
|
||||
{
|
||||
private readonly ILogger<FocasWireClient>? _logger;
|
||||
|
||||
/// <summary>Initializes a new instance of the WireFocasClientFactory without a logger.</summary>
|
||||
public WireFocasClientFactory() : this(logger: null) { }
|
||||
|
||||
/// <summary>
|
||||
@@ -367,10 +421,13 @@ public sealed class WireFocasClientFactory : IFocasClientFactory
|
||||
/// client already emits Debug entries per FOCAS response, but the previous no-arg
|
||||
/// factory path discarded them.
|
||||
/// </summary>
|
||||
/// <param name="logger">Optional logger for debug output from wire client responses.</param>
|
||||
public WireFocasClientFactory(ILogger<FocasWireClient>? logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
/// <summary>Creates a new WireFocasClient instance.</summary>
|
||||
/// <returns>A new IFocasClient implementation.</returns>
|
||||
public IFocasClient Create() => new WireFocasClient(_logger);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user