Updated with native ui (imgui + qt)
This commit is contained in:
@@ -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 (0–3)
|
||||
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};
|
||||
};
|
||||
Reference in New Issue
Block a user