Files
MARTe_IO_Components/Client/NativeUI/src/source.h
T
2026-05-27 15:46:50 +02:00

109 lines
4.3 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#pragma once
#include "protocol.h"
#include "signal_buffer.h"
#include "udp_client.h"
#include <atomic>
#include <chrono>
#include <cstdint>
#include <memory>
#include <mutex>
#include <string>
#include <vector>
/** Time calibration: maps timer ticks from one time-signal → Unix wall-clock seconds.
*
* Mirrors the WebUI Go client approach exactly:
* timer_to_sec = 1e-9 for uint64 (HRT nanoseconds), 1e-6 for all others (microseconds)
* calib_offset = wallT - timerVal * timer_to_sec (set once on first packet)
* t = calib_offset + timerVal * timer_to_sec
*/
struct TimeCalib {
double calib_offset = 0.0; // wallT_unix - timerVal * timer_to_sec
double timer_to_sec = 1e-6; // 1e-9 for uint64, 1e-6 for uint32/other
bool valid = false;
};
/** Per-signal display + buffer state. */
struct SignalState {
SignalDef def;
std::shared_ptr<SignalBuffer> buffer; // high-res ring buffer (last ~1-60 s)
std::shared_ptr<SignalBuffer> archive; // low-res ~1 kHz history (last ~17 min)
double archive_last_t = -1e18; // ingest-thread only
// Render-thread state (only modified on render thread after initial setup)
bool visible = true;
uint8_t plot_mask = 0; // bitmask: bit k set → signal is shown on plot k (03)
float color[4] = {1.f, 1.f, 1.f, 1.f}; // RGBA
float line_width = 1.5f;
bool use_envelope = false; // true → PlotShaded, false → PlotLine
};
/**
* One MARTe2 UDPStreamer source.
* Owns a UDPClient (ingest thread) and a vector of SignalState objects
* populated when CONFIG arrives.
*/
class Source {
public:
Source(std::string label, std::string host, uint16_t port,
std::string multicast_group = "", uint16_t data_port = 0);
~Source();
void start();
void stop();
// ── Identification ────────────────────────────────────────────────
const std::string& label() const { return label_; }
const std::string& host() const { return host_; }
uint16_t port() const { return port_; }
bool connected() const { return connected_.load(std::memory_order_relaxed); }
// ── Signal list (protect with signals_mutex while iterating) ──────
mutable std::mutex signals_mutex;
std::vector<SignalState> signal_states; // indexed by signal_idx
std::atomic<bool> config_dirty{false}; // set by ingest, cleared by render
// ── Stats ─────────────────────────────────────────────────────────
struct Stats {
uint64_t packets_rx = 0;
uint64_t packets_lost = 0;
uint64_t bytes_rx = 0;
};
Stats stats() const;
// High-res ring buffer capacity (≈60 s @ 100 kHz, ≈1.2 s @ 5 MHz)
static constexpr size_t MAX_SIGNAL_SAMPLES = 6'000'000;
// Low-res archive capacity: ~1000 Hz effective rate → ~17 min history
static constexpr size_t MAX_ARCHIVE_SAMPLES = 1'000'000;
// Minimum time between archive writes (1 ms = 1000 Hz)
static constexpr double ARCHIVE_DT = 1.0 / 1000.0;
private:
// Called from ingest thread
void handle_config(const std::vector<SignalDef>& defs);
void handle_data(const DataPacket& dp, const std::vector<SignalDef>& defs);
std::string label_, host_;
uint16_t port_;
std::shared_ptr<UDPClient> client_;
std::atomic<bool> connected_{false};
// Time calibrations indexed by protocol signal index (size = defs.size())
std::vector<TimeCalib> time_calibs_;
// Spatial-array expansion map.
// Indexed by protocol signal index; maps to the first signal_states entry
// for that signal and how many entries it occupies (1 for scalars/temporal).
struct SigExpand {
int start_state_idx;
uint32_t num_elements; // 1 for scalar/temporal, N for spatial
};
std::vector<SigExpand> sig_expand_;
// Stats (written by ingest thread, read by render — relaxed OK for display)
std::atomic<uint64_t> stat_rx_{0};
std::atomic<uint64_t> stat_lost_{0};
std::atomic<uint64_t> stat_bytes_{0};
};