Public Access
M1 step 6: Wi-Fi Tools from ordinary scans
- lib/wifi (host-tested): channel occupancy (neighbour spill, signal weighting, quietest of 1/6/11) and a signal tracker (history, lost detection, click interval) - WifiService: scan results carry BSSID, channel and security; a scan can target one channel for quick tracker refreshes; endListScans() turns the radio back off when Wi-Fi is disabled - Wi-Fi Tools App: networks nearby, channel occupancy bars, signal tracker with clicks (m to mute) - M1 plan: Monitoring-mode views and captures deferred Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EhqxQ49eCju4CzKYNjZzwT
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
#include "channel_occupancy.h"
|
||||
|
||||
namespace roro {
|
||||
|
||||
namespace {
|
||||
// -90 dBm (barely there) -> 0.1, -40 dBm and stronger -> 1.
|
||||
float weight(int rssi) {
|
||||
float w = (rssi + 90) / 50.0f;
|
||||
if (w < 0.1f) w = 0.1f;
|
||||
if (w > 1.0f) w = 1.0f;
|
||||
return w;
|
||||
}
|
||||
const float kSpill[] = {1.0f, 0.5f, 0.2f}; // same channel, one away, two away
|
||||
} // namespace
|
||||
|
||||
std::array<float, 14> channelLoad(const std::vector<ChannelSighting>& sightings) {
|
||||
std::array<float, 14> load{};
|
||||
for (auto& s : sightings) {
|
||||
if (s.channel < 1 || s.channel > 13) continue;
|
||||
for (int d = -2; d <= 2; d++) {
|
||||
int ch = s.channel + d;
|
||||
if (ch >= 1 && ch <= 13) load[ch] += weight(s.rssi) * kSpill[d < 0 ? -d : d];
|
||||
}
|
||||
}
|
||||
return load;
|
||||
}
|
||||
|
||||
int quietestChannel(const std::array<float, 14>& load) {
|
||||
int best = 1;
|
||||
for (int ch : {6, 11})
|
||||
if (load[ch] < load[best]) best = ch;
|
||||
return best;
|
||||
}
|
||||
|
||||
} // namespace roro
|
||||
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <vector>
|
||||
|
||||
namespace roro {
|
||||
|
||||
struct ChannelSighting {
|
||||
int channel;
|
||||
int rssi;
|
||||
};
|
||||
|
||||
// How crowded each 2.4 GHz Wi-Fi channel (1..13) is, from the access points a scan saw. A 20 MHz
|
||||
// network spills onto the channels up to two away, less the further it is; a strong signal
|
||||
// counts more than a faint one. Index 0 is unused.
|
||||
std::array<float, 14> channelLoad(const std::vector<ChannelSighting>& sightings);
|
||||
|
||||
// The least crowded of the non-overlapping channels 1, 6 and 11 (the lowest on a tie).
|
||||
int quietestChannel(const std::array<float, 14>& load);
|
||||
|
||||
} // namespace roro
|
||||
@@ -0,0 +1,52 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <deque>
|
||||
|
||||
namespace roro {
|
||||
|
||||
// Follows one access point's signal over repeated scans, for finding where it is.
|
||||
class SignalTracker {
|
||||
public:
|
||||
static constexpr int kNoSignal = -127;
|
||||
static constexpr uint32_t kLostAfterMs = 5000;
|
||||
static constexpr uint32_t kFastestClickMs = 60;
|
||||
static constexpr uint32_t kSlowestClickMs = 1200;
|
||||
|
||||
explicit SignalTracker(size_t historySize) : size_(historySize) {}
|
||||
|
||||
void seen(int rssi, uint32_t nowMs) {
|
||||
push(rssi);
|
||||
latest_ = rssi;
|
||||
lastSeenMs_ = nowMs;
|
||||
everSeen_ = true;
|
||||
}
|
||||
void missed() { push(kNoSignal); } // a scan that didn't see it
|
||||
|
||||
bool lost(uint32_t nowMs) const { return !everSeen_ || nowMs - lastSeenMs_ >= kLostAfterMs; }
|
||||
int latest() const { return latest_; }
|
||||
const std::deque<int>& history() const { return history_; }
|
||||
|
||||
// Time between clicks: fast when the signal is strong (close), slow when faint.
|
||||
static uint32_t clickIntervalMs(int rssi) {
|
||||
if (rssi >= -35) return kFastestClickMs;
|
||||
if (rssi <= -95) return kSlowestClickMs;
|
||||
float t = (rssi + 95) / 60.0f; // 0 at -95 dBm, 1 at -35 dBm
|
||||
return static_cast<uint32_t>(kSlowestClickMs - t * (kSlowestClickMs - kFastestClickMs));
|
||||
}
|
||||
|
||||
private:
|
||||
void push(int v) {
|
||||
history_.push_back(v);
|
||||
if (history_.size() > size_) history_.pop_front();
|
||||
}
|
||||
|
||||
size_t size_;
|
||||
std::deque<int> history_;
|
||||
int latest_ = kNoSignal;
|
||||
uint32_t lastSeenMs_ = 0;
|
||||
bool everSeen_ = false;
|
||||
};
|
||||
|
||||
} // namespace roro
|
||||
Reference in New Issue
Block a user