Public Access
Tab in the LoRa Scanner sweeps 863-870 MHz in 100 kHz steps (the strongest of three RSSI readings at each, at 125 kHz), shown as bars with peak hold over a waterfall, the Sniffer's frequency marked (Q98). The Sweep pauses the Sniffer and keeps its packets; Tab resumes it (Q99). Status Bar: SW. The floor, top and peaks are host-tested; `lora sweep on|off|dump` prints them on the console. At the desk: about 607 ms a pass, a flat floor at -100 to -102 dBm (15 dB above the chip's own) and a steady carrier at 863.2 MHz. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EhqxQ49eCju4CzKYNjZzwT
49 lines
1.8 KiB
C++
49 lines
1.8 KiB
C++
#include "sweep_view.h"
|
|
|
|
#include <algorithm>
|
|
|
|
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<int8_t> 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<uint32_t>(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<uint8_t>((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<uint16_t>((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
|