#include "sweep_view.h" #include namespace roro::lora { namespace { constexpr int kPeakAboveFloorDb = 10; constexpr size_t kMaxPeaks = 3; } // namespace SweepStats summarize(const int8_t* dbm, size_t steps, uint32_t fromHz, uint32_t stepHz) { SweepStats s; if (!steps) return s; std::vector sorted(dbm, dbm + steps); std::nth_element(sorted.begin(), sorted.begin() + steps / 2, sorted.end()); s.floor = sorted[steps / 2]; s.top = *std::max_element(dbm, dbm + steps); for (size_t i = 0; i < steps; ++i) { int v = dbm[i]; bool localMax = (i == 0 || v >= dbm[i - 1]) && (i + 1 == steps || v > dbm[i + 1]); if (localMax && v >= s.floor + kPeakAboveFloorDb) s.peaks.push_back({fromHz + static_cast(i) * stepHz, v}); } std::stable_sort(s.peaks.begin(), s.peaks.end(), [](const SweepPeak& a, const SweepPeak& b) { return a.dbm > b.dbm; }); if (s.peaks.size() > kMaxPeaks) s.peaks.resize(kMaxPeaks); return s; } uint8_t heatLevel(int dbm, int low, int high) { if (dbm <= low) return 0; if (dbm >= high) return 255; return static_cast((dbm - low) * 255 / (high - low) + ((dbm - low) * 255 % (high - low) ? 1 : 0)); } uint16_t heatColor(uint8_t level) { // Five segments of 51 steps each. auto rgb = [](int r, int g, int b) { return static_cast((r >> 3) << 11 | (g >> 2) << 5 | (b >> 3)); }; int seg = std::min(level / 51, 4), t = (level - seg * 51) * 255 / 51; switch (seg) { case 0: return rgb(0, 0, t); // black to blue case 1: return rgb(0, t, 255); // blue to cyan case 2: return rgb(0, 255, 255 - t); // cyan to green case 3: return rgb(t, 255, 0); // green to yellow default: return rgb(255, 255 - t, 0); // yellow to red } } } // namespace roro::lora