@@ -184,6 +184,45 @@ public interface IFocasClient : IDisposable
|
||||
/// </summary>
|
||||
Task SetPathAsync(int pathId, CancellationToken cancellationToken)
|
||||
=> Task.CompletedTask;
|
||||
|
||||
/// <summary>
|
||||
/// Read a contiguous range of PMC bytes in a single wire call (FOCAS
|
||||
/// <c>pmc_rdpmcrng</c> with byte data type) for the given <paramref name="letter"/>
|
||||
/// (<c>R</c>, <c>D</c>, <c>X</c>, etc.) starting at <paramref name="startByte"/> and
|
||||
/// spanning <paramref name="byteCount"/> bytes. Returned tuple has the byte buffer
|
||||
/// (length <paramref name="byteCount"/> on success) + the OPC UA status mapped through
|
||||
/// <see cref="FocasStatusMapper"/>. Used by <see cref="FocasDriver"/> to coalesce
|
||||
/// same-letter/same-path PMC reads in a batch into one round trip per range
|
||||
/// (issue #266 — see <see cref="Wire.FocasPmcCoalescer"/>).
|
||||
/// <para>
|
||||
/// Default falls back to per-byte <see cref="ReadAsync(FocasAddress, FocasDataType, CancellationToken)"/>
|
||||
/// calls so transport variants that haven't extended their wire surface still work
|
||||
/// correctly — they just won't see the round-trip reduction. The fallback short-circuits
|
||||
/// on the first non-Good status so a partial buffer isn't returned with a Good code.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
async Task<(byte[]? buffer, uint status)> ReadPmcRangeAsync(
|
||||
string letter, int pathId, int startByte, int byteCount, CancellationToken cancellationToken)
|
||||
{
|
||||
if (byteCount <= 0) return (Array.Empty<byte>(), FocasStatusMapper.Good);
|
||||
var buf = new byte[byteCount];
|
||||
for (var i = 0; i < byteCount; i++)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
var addr = new FocasAddress(FocasAreaKind.Pmc, letter, startByte + i, BitIndex: null, PathId: pathId);
|
||||
var (value, status) = await ReadAsync(addr, FocasDataType.Byte, cancellationToken).ConfigureAwait(false);
|
||||
if (status != FocasStatusMapper.Good) return (null, status);
|
||||
buf[i] = value switch
|
||||
{
|
||||
sbyte s => unchecked((byte)s),
|
||||
byte b => b,
|
||||
int n => unchecked((byte)n),
|
||||
short s => unchecked((byte)s),
|
||||
_ => 0,
|
||||
};
|
||||
}
|
||||
return (buf, FocasStatusMapper.Good);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
Reference in New Issue
Block a user