/** * @file Types.h * @brief Plain data shared across UDPScope modules. No logic, no dependencies. */ #pragma once #include #include #include #include namespace udpscope { /** A time series as two parallel arrays, which is what ImPlot wants. */ struct Series { std::vector t; std::vector v; void clear() { t.clear(); v.clear(); } size_t size() const { return t.size(); } bool empty() const { return t.empty(); } }; /** RGBA in 0..1. Framework-free so PaneTree needs no ImGui. */ struct Color { float r = 1.f, g = 1.f, b = 1.f, a = 1.f; }; /** Screen rectangle in pixels. */ struct Rect { double x = 0.0, y = 0.0, w = 0.0, h = 0.0; bool contains(double px, double py) const { return px >= x && px < (x + w) && py >= y && py < (y + h); } }; /* Protocol constants, spelled out rather than included, so the framework-free * modules stay independent of udps_client.h. They mirror Common/UDP/UDPSProtocol.h. */ constexpr uint8_t kTimePacket = 0; constexpr uint8_t kTimeFullArray = 1; constexpr uint8_t kTimeFirstSample = 2; constexpr uint8_t kTimeLastSample = 3; constexpr uint32_t kNoTimeSignal = 0xFFFFFFFFu; /** Framework-free mirror of udps_signal_t, plus UI state. */ struct SignalMeta { std::string name; uint8_t typeCode = 255; uint8_t quantType = 0; uint32_t numRows = 1; uint32_t numCols = 1; double rangeMin = 0.0; double rangeMax = 0.0; uint8_t timeMode = kTimePacket; double samplingRate = 0.0; uint32_t timeSignalIdx = kNoTimeSignal; std::string unit; /** User override: treat an ambiguous PACKET array as a profile, not a burst. */ bool profileOverride = false; uint32_t numElements() const { const uint64_t n = static_cast(numRows ? numRows : 1u) * static_cast(numCols ? numCols : 1u); return n == 0u ? 1u : static_cast(n); } bool hasTimeSignal(uint32_t numSignals) const { return timeSignalIdx != kNoTimeSignal && timeSignalIdx < numSignals; } /** * @brief True when this array should be plotted against element index * rather than unrolled onto the time axis. * * Only PACKET arrays are ambiguous: the producer stamped the whole datagram * with one time, which is what a genuine vector looks like and also what a * burst carrying no time metadata looks like. Default is burst, matching * UDPSourceSession, with this flag as the user's override. */ bool isVectorProfile() const { return profileOverride && numElements() > 1u && timeMode == kTimePacket; } }; /** * @brief Non-owning mirror of udps_frame_t. * * Kept separate from the C struct so FrameDecoder can be tested with plain * arrays and no socket. Points at memory owned by the caller. */ struct FrameView { uint32_t counter = 0; uint64_t hrt = 0; double recvTime = 0.0; uint32_t numSamples = 1; uint32_t numSignals = 0; const double* const* values = nullptr; /**< values[i][0..counts[i]) */ const uint32_t* counts = nullptr; }; } /* namespace udpscope */