Updated with native ui (imgui + qt)

This commit is contained in:
Martino Ferrari
2026-05-27 15:46:50 +02:00
parent 3dd0d863fa
commit cf174edde8
205 changed files with 157039 additions and 0 deletions
+108
View File
@@ -0,0 +1,108 @@
#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};
};