// SPDX-License-Identifier: MIT // SPDX-FileCopyrightText: 2026 Martino Ferrari #pragma once #include "model.hpp" #include namespace udpscope { /// One signal's values in a frame. `values` points into the source's own buffer and is valid /// only while the `on_data` call that received the frame is running. struct SignalValues { const double* values = nullptr; std::uint32_t count = 0; }; /// A data frame in source-neutral form; it mirrors `udps_frame_t`. A source with no packet /// counter supplies a running one and `lost = 0`: the hole, backfill and time-base logic only /// needs `counter`, `lost` and `late`. struct Frame { std::uint32_t counter = 0; std::uint32_t lost = 0; bool late = false; double recv_time = 0.0; std::uint8_t publish_mode = 0; std::uint32_t num_samples = 0; std::uint32_t num_signals = 0; const SignalInfo* signals = nullptr; const SignalValues* values = nullptr; /// Element `elem` of signal `sig` at sample `sample`. Mirrors `udps_frame_value`: a scalar /// signal carried once per sample is indexed by `sample`, a vector/matrix signal by `elem`. /// Out of range reads 0.0. double value(std::uint32_t sig, std::uint32_t sample, std::uint32_t elem) const noexcept { if (sig >= num_signals) return 0.0; const SignalValues& v = values[sig]; const std::uint32_t idx = (v.count == num_samples && signals[sig].elements() == 1u) ? sample : elem; return idx < v.count ? v.values[idx] : 0.0; } }; } // namespace udpscope