Sum-read (#310): batches a poll's reads per device into sum commands capped at sumReadMaxItems, per-item ADS errors mapped per tag, falls back to individual reads when the target refuses the command. Diagnostics (#314): ADS state, app name, online-change count, task cycle/exec/jitter via IDriverDiagnostics. Re-implemented against the current raw-byte read path (stranded auto/driver-gaps commits predate it). Sum-write not ported. Unit tests only; live gate pending a route. Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe
This commit is contained in:
@@ -55,6 +55,45 @@ public interface ITwinCATClient : IDisposable
|
||||
int? arrayCount,
|
||||
CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Reads several symbols at once — the ADS sum-read path (Gitea #645 / #310). The result is a parallel
|
||||
/// list: element <c>i</c> is the outcome of <paramref name="reads"/>[<c>i</c>], each decoded and
|
||||
/// status-mapped exactly as <see cref="ReadValueAsync"/> would (an item the sum command cannot carry —
|
||||
/// a bit-indexed BOOL, a handle-addressed symbol — is read individually inside the call).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The default implementation reads one item at a time, so a client without a sum path (or a test
|
||||
/// fake) is correct if not faster. An implementation that issues a real sum command throws
|
||||
/// <see cref="TwinCATSumReadRefusedException"/> when the TARGET refuses the command as a whole
|
||||
/// (service / index group not supported); the caller then falls back to individual reads. A
|
||||
/// comms-level failure propagates as the ordinary exception.
|
||||
/// </remarks>
|
||||
/// <param name="reads">The symbols to read, at most the caller's chunk size.</param>
|
||||
/// <param name="cancellationToken">Cancellation token for the read.</param>
|
||||
/// <returns>One <c>(value, status)</c> per item, in request order.</returns>
|
||||
/// <exception cref="TwinCATSumReadRefusedException">The target refused the sum command itself.</exception>
|
||||
async Task<IReadOnlyList<(object? value, uint status)>> ReadValuesAsync(
|
||||
IReadOnlyList<TwinCATBulkReadItem> reads, CancellationToken cancellationToken)
|
||||
{
|
||||
var results = new (object? value, uint status)[reads.Count];
|
||||
for (var i = 0; i < reads.Count; i++)
|
||||
{
|
||||
var r = reads[i];
|
||||
results[i] = await ReadValueAsync(r.SymbolPath, r.Type, r.BitIndex, r.ArrayCount, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The target's ADS device state (<c>Run</c>, <c>Stop</c>, <c>Config</c>, …) as text, or <c>null</c>
|
||||
/// when it cannot be read. Feeds the driver's <c>/hosts</c> diagnostics (Gitea #645 / #314).
|
||||
/// Default <c>null</c> — a client without a state read simply reports none.
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">Cancellation token for the read.</param>
|
||||
/// <returns>The state name, or <c>null</c>.</returns>
|
||||
Task<string?> ReadAdsStateAsync(CancellationToken cancellationToken) => Task.FromResult<string?>(null);
|
||||
|
||||
/// <summary>
|
||||
/// Write a symbolic value. Returns the mapped OPC UA status for the operation
|
||||
/// (0 = Good, non-zero = error mapped via <see cref="TwinCATStatusMapper"/>).
|
||||
@@ -132,6 +171,18 @@ public interface ITwinCATClient : IDisposable
|
||||
IAsyncEnumerable<TwinCATDiscoveredSymbol> BrowseSymbolsAsync(CancellationToken cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>One element of an <see cref="ITwinCATClient.ReadValuesAsync"/> request — the same four facts
|
||||
/// <see cref="ITwinCATClient.ReadValueAsync"/> takes.</summary>
|
||||
/// <param name="SymbolPath">The ADS symbol path (a bit-indexed BOOL keeps its <c>.N</c> suffix, as for a single read).</param>
|
||||
/// <param name="Type">The declared data type.</param>
|
||||
/// <param name="BitIndex">The bit to extract for a BOOL-within-word tag; null otherwise.</param>
|
||||
/// <param name="ArrayCount">The authored array length for an array tag; null for a scalar.</param>
|
||||
public sealed record TwinCATBulkReadItem(
|
||||
string SymbolPath,
|
||||
TwinCATDataType Type,
|
||||
int? BitIndex = null,
|
||||
int? ArrayCount = null);
|
||||
|
||||
/// <summary>Opaque handle for a registered ADS notification. <see cref="IDisposable.Dispose"/> tears it down.</summary>
|
||||
public interface ITwinCATNotificationHandle : IDisposable { }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user