Fixed triggering mode change when acquiring

This commit is contained in:
Martino Ferrari committed 2026-10-01 17:54:17 +02:00
1 parent 3d4085898e
commit 0d741c401b
10 files changed
+504 -106

No files matched your search

+48 -7
View File
@@ -127,6 +127,21 @@ struct StreamStats {
std::atomic<bool> have_config{false};
};
/// What the plot is showing, which is one decision made once per frame: the bind, the
/// export and the status wording all have to agree, and the producer can latch between
/// any two of them.
///
/// `Capturing` is the live-updating capture: an edge has been accepted (so the pre
/// window was full) and the post window is still filling, and the plot follows the live
/// ring on an edge-relative axis until the snapshot lands. It is a deliberate departure
/// from SPECS:37 ("not refreshed till next event") -- see README.
enum class DisplayMode {
Live, ///< no trigger: the live ring, stream clock
Capturing, ///< an edge was accepted: the live ring, edge-relative clock
Held, ///< the frozen snapshot of the last event
Waiting, ///< armed, nothing captured yet: blank
};
/// The application's data model: the stream description, the two sample buffers,
/// the trigger configuration and the counters. Structural changes (a CONFIG
/// update, an enable/disable, a calibration) rebuild the buffers, so all mutating
@@ -191,6 +206,11 @@ class ScopeModel {
std::shared_ptr<const EventSnapshot> event() const noexcept {
return event_.load(std::memory_order_acquire);
}
/// How many snapshots `publish_event()` has produced. Not interchangeable with
/// `trigger_latches()`: a Disarm during a capture publishes what the capture got to
/// *without* an event having fired, so this counts "there is a new picture to frame"
/// while the latch count keeps answering "how many events fired".
std::uint64_t event_seq() const noexcept { return event_seq_.load(std::memory_order_acquire); }
/// Publishes the live buffer's new samples to its `ChannelBuffer`s.
void acquire_all();
@@ -211,16 +231,35 @@ class ScopeModel {
}
void set_trigger_enabled(bool on);
/// Whether the engine is mid-capture (an edge was seen and the post-trigger
/// window is still filling). Purely informational: it drives the status line's
/// wording. The plot deliberately does *not* react to it -- in trigger mode the
/// picture changes only on a latch (SPECS: "data visualisation should not be
/// refreshed till next event").
/// Whether the engine is mid-capture (an edge was seen -- so the pre window was
/// full -- and the post-trigger window is still filling). This is what puts the
/// display in `DisplayMode::Capturing`: the plot follows the live ring, on an axis
/// pinned to the coming event's window, until the snapshot replaces it.
///
/// Release/acquire, not relaxed: `capture_edge()` is written before this is set and
/// has to be visible to a consumer that sees the flag.
bool trigger_pending() const noexcept {
return trigger_pending_.load(std::memory_order_relaxed);
return trigger_pending_.load(std::memory_order_acquire);
}
void set_trigger_pending(bool on) noexcept {
trigger_pending_.store(on, std::memory_order_relaxed);
trigger_pending_.store(on, std::memory_order_release);
}
/// The stream time of the edge of the capture `trigger_pending()` refers to. Written
/// by the producer before it raises the flag, so a consumer that sees the flag sees
/// this too; stale once the flag clears.
f64 capture_edge() const noexcept { return capture_edge_.load(std::memory_order_relaxed); }
void set_capture_edge(f64 e) noexcept {
capture_edge_.store(e, std::memory_order_relaxed);
}
/// What the plot should bind to this frame. Read it *once* per frame and pass the
/// answer around: calling it twice can straddle a latch, and then the bind and the
/// axis disagree about which clock they are on.
DisplayMode display_mode() const noexcept {
if (!trigger_enabled()) return DisplayMode::Live;
if (trigger_pending()) return DisplayMode::Capturing;
return event() != nullptr ? DisplayMode::Held : DisplayMode::Waiting;
}
/// The x origin the plot uses: 0 for "seconds since the stream started", or minus
@@ -283,7 +322,9 @@ class ScopeModel {
f64 epoch_ = 0.0;
std::atomic<double> event_span_{1.0};
std::atomic<bool> trigger_pending_{false};
std::atomic<double> capture_edge_{0.0};
std::atomic<std::shared_ptr<const EventSnapshot>> event_; ///< the event on screen
std::atomic<std::uint64_t> event_seq_{0};
std::atomic<double> display_epoch_{0.0};
std::atomic<bool> trigger_armed_{false};
std::atomic<bool> trigger_enabled_{false};