fix(focas): publish LastStatus after the fixed-tree stamp; test waits on full readiness (#673)

This commit is contained in:
Joseph Doherty
2026-10-11 08:16:00 -04:00
parent db6a53036b
commit e5d12d391a
2 changed files with 15 additions and 6 deletions
@@ -1232,13 +1232,16 @@ public sealed class FocasDriver : IDriver, IReadable, IWritable, ITagDiscovery,
ProgramInfo: programInfo is not null,
Timers: timer is not null,
Status: statusProbe is not null);
state.LastStatus = statusProbe;
state.FixedTreeCache = new FocasFixedTreeCache(sys, [.. axes], [.. spindles], caps);
// The bootstrap IS an answer from the device, and Identity comes entirely from it —
// so stamp liveness here as well as per tick, or a CNC whose axis poll never
// succeeds would serve a perfectly valid sysinfo as stale.
state.LastFixedPollUtc = DateTime.UtcNow;
// Published LAST (release write): LastStatus is the field callers watch for "the first
// answer is in", and an authored FIXED:Status/* read is only servable once
// FixedTreeCache and LastFixedPollUtc are set (TryReadFixedTreeOnDevice). Publishing it
// first let a reader see a status while the read still returned BadCommunicationError (#673).
state.LastStatus = statusProbe;
}
catch (OperationCanceledException) when (ct.IsCancellationRequested) { return; }
catch (Exception ex)
@@ -1998,7 +2001,12 @@ public sealed class FocasDriver : IDriver, IReadable, IWritable, ITagDiscovery,
/// </summary>
public ConcurrentDictionary<string, byte> CoalesceRejected { get; } = new(StringComparer.Ordinal);
/// <summary>Gets or sets the last <c>cnc_statinfo</c> snapshot (#257); null until the first answer.</summary>
public FocasStatus? LastStatus { get; set; }
public FocasStatus? LastStatus
{
get => Volatile.Read(ref _lastStatus);
set => Volatile.Write(ref _lastStatus, value);
}
private FocasStatus? _lastStatus;
/// <summary>Gets or sets the last program information snapshot.</summary>
public FocasProgramInfo? LastProgramInfo { get; set; }
/// <summary>Gets or sets the cached first-axis dynamic snapshot — feeds Program/Number, /MainNumber, /Sequence.</summary>