Auto: focas-f4c — pmc_wrpmcrng with bit-level RMW

Closes #270
This commit is contained in:
Joseph Doherty
2026-04-26 05:15:52 -04:00
parent 0c967af645
commit 54c09d4d5d
17 changed files with 837 additions and 101 deletions

View File

@@ -232,6 +232,49 @@ public interface IFocasClient : IDisposable
int depth, CancellationToken cancellationToken)
=> Task.FromResult<IReadOnlyList<FocasAlarmHistoryEntry>>(Array.Empty<FocasAlarmHistoryEntry>());
/// <summary>
/// Write a contiguous range of PMC bytes in a single wire call (FOCAS
/// <c>pmc_wrpmcrng</c>) for the given <paramref name="letter"/> starting at
/// <paramref name="startByte"/>, copying every byte from <paramref name="bytes"/>.
/// Plan PR F4-c (issue #270). The wire call is byte-addressed; bit-level writes
/// are handled upstream by the <see cref="WritePmcBitAsync"/> read-modify-write
/// wrapper which performs <c>pmc_rdpmcrng</c> + bit mask + this method on a
/// per-byte semaphore (so two concurrent bit writes against the same byte don't
/// lose one another's update).
/// <para>Default impl returns <see cref="FocasStatusMapper.BadNotSupported"/> so
/// transport variants that haven't yet routed the write keep compiling — those
/// variants surface BadNotSupported on PMC writes until the wire client is
/// extended.</para>
/// </summary>
Task<uint> WritePmcRangeAsync(
string letter, int pathId, int startByte, byte[] bytes, CancellationToken cancellationToken)
=> Task.FromResult(FocasStatusMapper.BadNotSupported);
/// <summary>
/// Read-modify-write one bit within a PMC byte (Plan PR F4-c, issue #270). The
/// wire call <c>pmc_wrpmcrng</c> is byte-addressed, so the driver reads the
/// parent byte first, masks the target bit, then writes the byte back. Default
/// impl uses <see cref="ReadPmcRangeAsync"/> + <see cref="WritePmcRangeAsync"/>
/// so transport variants get correct RMW semantics for free; the FWLIB-backed
/// client overrides this with a per-byte semaphore so two concurrent bit writes
/// against the same byte serialise.
/// </summary>
async Task<uint> WritePmcBitAsync(
string letter, int pathId, int byteAddress, int bitIndex, bool newValue,
CancellationToken cancellationToken)
{
if (bitIndex is < 0 or > 7) return FocasStatusMapper.BadOutOfRange;
var (buf, status) = await ReadPmcRangeAsync(letter, pathId, byteAddress, 1, cancellationToken)
.ConfigureAwait(false);
if (status != FocasStatusMapper.Good || buf is null || buf.Length < 1) return status;
var current = buf[0];
var updated = newValue
? (byte)(current | (1 << bitIndex))
: (byte)(current & ~(1 << bitIndex));
return await WritePmcRangeAsync(letter, pathId, byteAddress, new[] { updated }, cancellationToken)
.ConfigureAwait(false);
}
/// <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"/>