From 4ae91bd58b5cd2cb95c172d53bfdd51a34066996 Mon Sep 17 00:00:00 2001 From: Martino Ferrari Date: Sat, 31 Oct 2026 20:02:55 +0100 Subject: [PATCH] source: normalise UDPS signal dimensions in to_info; comment tidy --- src/acquisition.cpp | 12 ++++++------ src/acquisition.hpp | 4 ++-- src/source/udps_source.cpp | 13 +++++++++++-- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/acquisition.cpp b/src/acquisition.cpp index 3fd1f9c..7d67af7 100644 --- a/src/acquisition.cpp +++ b/src/acquisition.cpp @@ -366,8 +366,8 @@ std::uint32_t Acquisition::build_stamps(const Frame& frame, int time_signal, if (time_source_ != 2 && time_signal >= 0 && time_signal < static_cast(frame.num_signals)) { const SignalInfo& ts = frame.signals[time_signal]; - // How the client indexes a signal's values depends on its shape - // (`udps_frame_value`): a scalar carries one value per batched cycle, so the + // How a frame indexes a signal's values depends on its shape + // (`Frame::value`): a scalar carries one value per batched cycle, so the // stamp of sample k is (sample=k, elem=0); a multi-element signal carries one // *sample* of `elements` values per packet, so the stamp of sample k is // (sample=0, elem=k). Passing the scalar form for both is why FULL_ARRAY time @@ -966,7 +966,7 @@ void Acquisition::on_data(const Frame& frame) { const double raw = ch.elements > 1 ? frame.value(static_cast(ch.signal), 0, - std::min(k, ch.elements - 1)) + std::min(k, ch.elements - 1)) : frame.value(static_cast(ch.signal), k, 0); // Every sample is read and accumulated even when only one in `period` is stored: // that is the whole point of the filter. Skipping the read -- which is what the @@ -1202,10 +1202,10 @@ void Acquisition::backfill_from(const Frame& frame, const Partition& part, const double raw = channels[i].elements > 1 ? frame.value(static_cast(channels[i].signal), 0, - std::min(static_cast(k), - channels[i].elements - 1)) + std::min(static_cast(k), + channels[i].elements - 1)) : frame.value(static_cast(channels[i].signal), - static_cast(k), 0); + static_cast(k), 0); acc += raw * channels[i].gain + channels[i].offset; } const f32 value = static_cast(acc / double(period)); diff --git a/src/acquisition.hpp b/src/acquisition.hpp index c9e72c2..a585c32 100644 --- a/src/acquisition.hpp +++ b/src/acquisition.hpp @@ -31,8 +31,8 @@ class Acquisition : private SourceSink { Acquisition(const Acquisition&) = delete; Acquisition& operator=(const Acquisition&) = delete; - /// Opens the client (no socket until the first poll) and starts the thread. - /// Throws std::runtime_error when the client cannot be created. + /// Opens the source (no socket until the first poll) and starts the thread. + /// Throws std::runtime_error when the source cannot be created. void start(); /// Stops the thread and destroys the client. Idempotent. void stop(); diff --git a/src/source/udps_source.cpp b/src/source/udps_source.cpp index 1ae89f8..e0a1f54 100644 --- a/src/source/udps_source.cpp +++ b/src/source/udps_source.cpp @@ -19,8 +19,17 @@ SignalInfo to_info(const udps_signal_t& s) { info.unit = s.unit; info.type_code = s.type_code; info.quant_type = s.quant_type; - info.rows = s.num_rows; - info.cols = s.num_cols; + // Store the effective dimensions `udps_signal_num_elements` uses, so `SignalInfo::elements()` + // (rows * cols) gives the same count for any CONFIG, hostile or odd ones included: a zero + // dimension means 1 on its own (rows 0, cols 5 is 5 elements), and the product is clamped to + // UDPS_MAX_ELEMENTS, which also keeps rows * cols from overflowing uint32. + std::uint64_t rows = s.num_rows == 0 ? 1u : s.num_rows; + std::uint64_t cols = s.num_cols == 0 ? 1u : s.num_cols; + if (rows > UDPS_MAX_ELEMENTS) rows = UDPS_MAX_ELEMENTS; + if (cols > UDPS_MAX_ELEMENTS) cols = UDPS_MAX_ELEMENTS; + if (rows * cols > UDPS_MAX_ELEMENTS) cols = UDPS_MAX_ELEMENTS / rows; + info.rows = static_cast(rows); + info.cols = static_cast(cols); info.range_min = s.range_min; info.range_max = s.range_max; info.time_mode = s.time_mode;