Auto: focas-f2d — PMC range coalescing

Closes #266
This commit is contained in:
Joseph Doherty
2026-04-25 20:02:10 -04:00
parent 9ebe5bd523
commit 4d3ee47235
7 changed files with 836 additions and 0 deletions

View File

@@ -445,6 +445,42 @@ internal sealed class FwlibFocasClient : IFocasClient
return (value, FocasStatusMapper.Good);
}
/// <summary>
/// Range read for the PMC coalescer (issue #266). FWLIB's <c>pmc_rdpmcrng</c>
/// payload is capped at 40 bytes (the IODBPMC.Data union width), so requested
/// ranges larger than that are chunked into 32-byte sub-calls internally —
/// callers still see one logical range, which matches the
/// <see cref="Wire.FocasPmcCoalescer"/>'s "one wire call per group" semantics.
/// </summary>
public Task<(byte[]? buffer, uint status)> ReadPmcRangeAsync(
string letter, int pathId, int startByte, int byteCount, CancellationToken cancellationToken)
{
if (!_connected) return Task.FromResult<(byte[]?, uint)>((null, FocasStatusMapper.BadCommunicationError));
cancellationToken.ThrowIfCancellationRequested();
if (byteCount <= 0) return Task.FromResult<(byte[]?, uint)>((Array.Empty<byte>(), FocasStatusMapper.Good));
var addrType = FocasPmcAddrType.FromLetter(letter)
?? throw new InvalidOperationException($"Unknown PMC letter '{letter}'.");
var result = new byte[byteCount];
const int chunkBytes = 32;
var offset = 0;
while (offset < byteCount)
{
cancellationToken.ThrowIfCancellationRequested();
var thisChunk = Math.Min(chunkBytes, byteCount - offset);
var buf = new FwlibNative.IODBPMC { Data = new byte[40] };
var ret = FwlibNative.PmcRdPmcRng(
_handle, addrType, FocasPmcDataType.Byte,
(ushort)(startByte + offset),
(ushort)(startByte + offset + thisChunk - 1),
(ushort)(8 + thisChunk), ref buf);
if (ret != 0) return Task.FromResult<(byte[]?, uint)>((null, FocasStatusMapper.MapFocasReturn(ret)));
Array.Copy(buf.Data, 0, result, offset, thisChunk);
offset += thisChunk;
}
return Task.FromResult<(byte[]?, uint)>((result, FocasStatusMapper.Good));
}
private uint WritePmc(FocasAddress address, FocasDataType type, object? value)
{
var addrType = FocasPmcAddrType.FromLetter(address.PmcLetter ?? "") ?? (short)0;