#pragma once #include #include #include #include #include #include #include "adc_sweep/sweep_core.hpp" namespace adc_sweep { constexpr uint32_t kShmMagic = 0x53575041; // "AWPS" constexpr uint32_t kShmVersion = 1; struct alignas(64) ShmHeader { uint32_t magic; uint32_t version; uint32_t capacity; uint32_t sweep_width; uint32_t slot_stride; uint32_t reserved0; uint64_t producer_seq; std::atomic write_seq; std::atomic latest_slot; uint32_t reserved1; uint8_t reserved2[64 - 48]; }; static_assert(sizeof(ShmHeader) == 64, "ShmHeader must stay fixed size"); struct SweepSlotHeader { std::atomic seq; uint64_t ts_mono_ns; uint32_t sweep_idx; int32_t ch_primary; uint32_t ch_mask; uint32_t reserved; float n_valid; float min; float max; float mean; float std; float dt_ms; }; class ShmSweepStackWriter { public: ShmSweepStackWriter(std::string shm_name, uint32_t capacity, uint32_t sweep_width); ~ShmSweepStackWriter(); bool open_or_create(std::string& err); void close(); bool publish(const SweepResult& result, std::string& err); uint32_t capacity() const { return capacity_; } uint32_t sweep_width() const { return sweep_width_; } private: SweepSlotHeader* slot_header(uint32_t slot_idx); float* slot_sweep_data(uint32_t slot_idx); std::string shm_name_; uint32_t capacity_; uint32_t sweep_width_; uint32_t slot_stride_; int shm_fd_ = -1; void* mapped_ = nullptr; size_t mapped_size_ = 0; ShmHeader* header_ = nullptr; uint64_t next_seq_ = 1; }; struct LatestSnapshot { uint64_t seq = 0; SweepMeta meta; std::vector sweep; }; std::optional read_latest_snapshot(void* mapped, uint32_t capacity, uint32_t sweep_width, uint32_t slot_stride); } // namespace adc_sweep