From 51d13a09cb6b0e715316f1431a031c13c21ed7f5 Mon Sep 17 00:00:00 2001 From: Martino Ferrari Date: Fri, 9 Oct 2026 06:52:04 +0200 Subject: [PATCH] fix: the warn-once latches reset on a CONFIG, so a reconnect is diagnosed too Four latches were process-lifetime -- two of them function-local statics, so process-wide rather than per-object -- and a condition that warned once stayed silent about every later occurrence in a long-lived session. A diagnostic that goes quiet after the first occurrence is the failure mode worth fixing in a feature whose job is diagnosis. Co-Authored-By: Claude Opus 4.6 --- src/acquisition.cpp | 17 +++++++++++------ src/acquisition.hpp | 5 +++++ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/acquisition.cpp b/src/acquisition.cpp index 4414940..5da82b8 100644 --- a/src/acquisition.cpp +++ b/src/acquisition.cpp @@ -122,6 +122,13 @@ void Acquisition::on_config(const udps_signal_t* signals, std::uint32_t count, sig.time_signal_idx, sig.unit.c_str()); } std::fflush(stderr); + // The warn-once latches are per *connection*, not per process. A reconnect re-enters here, and + // a diagnostic that goes quiet after the first occurrence of a condition that recurs on the + // next session is the failure mode worth avoiding in a feature whose whole job is diagnosis. + warned_batch_ = false; + warned_outage_ = false; + warned_bridge_ = false; + warned_time_source_ = false; model_.stats().have_config.store(true, std::memory_order_relaxed); model_.set_signals(std::move(info)); } @@ -349,9 +356,8 @@ std::uint32_t Acquisition::build_stamps(const udps_frame_t* frame, int time_sign const double from = last_stream_anchor_; for (std::uint32_t k = 0; k < n; ++k) stamps_[k] = from + double(k + 1) * step; last_stream_anchor_ = stamps_[n - 1]; - static bool bridged = false; - if (!bridged) { - bridged = true; + if (!warned_bridge_) { + warned_bridge_ = true; std::fprintf(stderr, "[udpscope] warning: the stream's time signal %s (%g..%g against a " "previous %g); bridging that packet at the declared cadence and " @@ -360,9 +366,8 @@ std::uint32_t Acquisition::build_stamps(const udps_frame_t* frame, int time_sign } } else { used_stream_time = false; // not a time base; fall back to arrival - static bool warned = false; - if (!warned) { - warned = true; + if (!warned_time_source_) { + warned_time_source_ = true; std::fprintf(stderr, "[udpscope] warning: the stream's time signal %s (%g..%g); timing " "samples by arrival instead. Check the time signal's mode and index " diff --git a/src/acquisition.hpp b/src/acquisition.hpp index 2ebc460..19ae0f8 100644 --- a/src/acquisition.hpp +++ b/src/acquisition.hpp @@ -127,6 +127,11 @@ class Acquisition { /// Warn-once latch for a loss past the reservation cap. A member, not a function-local /// `static`, matching the latch Task 2 added for the same reason. bool warned_outage_ = false; + /// Warn-once latch for the one bridged packet whose time signal glitched. + bool warned_bridge_ = false; + /// Warn-once latch for the declared time signal failing for good, so the arrival clock is + /// taken instead. + bool warned_time_source_ = false; /// The re-plan generation this object last reacted to. The buffer is re-planned whenever the /// model rebuilds it, and the state tied to the old store (`tick_` and the accumulators) is /// reset when this falls behind `ScopeModel::plan_generation()`.