feat: wifiscan

This commit is contained in:
2025-09-12 22:08:47 +02:00
parent 5bf2283063
commit fe3943b48a
10 changed files with 502 additions and 2 deletions

View File

@@ -1,8 +1,29 @@
#include "NetworkManager.h"
#include "TaskManager.h"
// SSID and password are now configured via Config class
NetworkManager::NetworkManager(NodeContext& ctx) : ctx(ctx) {}
const char* const NetworkManager::WIFI_SCAN_MONITOR_TASK = "wifi_scan_monitor";
NetworkManager::NetworkManager(NodeContext& ctx) : ctx(ctx), wifiScanInProgress(false), wifiScanStartTime(0) {
// Register scan process callback
ctx.on("wifi/scan/process", [this](void* data) {
int networksFound = reinterpret_cast<intptr_t>(data);
this->processScanResults(networksFound);
});
}
void NetworkManager::initTasks() {
if (!ctx.taskManager) {
Serial.println("[WiFi] Error: TaskManager not initialized");
return;
}
// Register task to check scan status every 100ms (initially disabled)
ctx.taskManager->registerTask(WIFI_SCAN_MONITOR_TASK, 100, [this]() {
this->updateWiFiScan();
}, false); // false = disabled by default
}
void NetworkManager::setHostnameFromMac() {
uint8_t mac[6];
@@ -65,3 +86,133 @@ void NetworkManager::setupWiFi() {
// Notify listeners that the node is (re)discovered
ctx.fire("node_discovered", &ctx.self);
}
void NetworkManager::startWiFiScan() {
if (wifiScanInProgress) {
Serial.println("[WiFi] Scan already in progress");
return;
}
// Check if we're in AP mode only
if (WiFi.getMode() == WIFI_AP) {
// Enable STA mode while keeping AP mode
WiFi.mode(WIFI_AP_STA);
delay(100); // Give some time for mode change
}
// Ensure we have STA mode enabled
if (WiFi.getMode() != WIFI_STA && WiFi.getMode() != WIFI_AP_STA) {
Serial.println("[WiFi] Error: Cannot scan without STA mode enabled");
ctx.fire("wifi/scan/error", nullptr);
return;
}
Serial.println("[WiFi] Starting WiFi scan...");
wifiScanInProgress = true;
wifiScanStartTime = millis();
// Enable the monitoring task if TaskManager is available
if (ctx.taskManager) {
ctx.taskManager->enableTask(WIFI_SCAN_MONITOR_TASK);
}
// Clear previous results safely
if (ctx.wifiAccessPoints) {
ctx.wifiAccessPoints->clear();
}
// Disable interrupts briefly during scan start
noInterrupts();
// Start the scan
WiFi.scanNetworksAsync([this](int networksFound) {
// Schedule callback in main loop
ctx.fire("wifi/scan/process", reinterpret_cast<void*>(networksFound));
}, true); // Show hidden networks
interrupts();
}
void NetworkManager::updateWiFiScan() {
if (!wifiScanInProgress) {
return;
}
// Check for timeout
if (millis() - wifiScanStartTime > WIFI_SCAN_TIMEOUT_MS) {
Serial.println("[WiFi] WiFi scan timeout");
wifiScanInProgress = false;
if (ctx.taskManager) {
ctx.taskManager->disableTask(WIFI_SCAN_MONITOR_TASK);
}
ctx.fire("wifi/scan/timeout", nullptr);
}
}
void NetworkManager::processScanResults(int networksFound) {
// This is called from the main loop context via the event system
if (!wifiScanInProgress) {
return; // Ignore if we're not expecting results
}
wifiScanInProgress = false;
// Disable the monitoring task if TaskManager is available
if (ctx.taskManager) {
ctx.taskManager->disableTask(WIFI_SCAN_MONITOR_TASK);
}
Serial.printf("[WiFi] Processing scan results, found %d networks\n", networksFound);
// Create a temporary vector to hold new results
std::vector<WiFiAccessPoint> newAccessPoints;
if (networksFound > 0) {
newAccessPoints.reserve(networksFound); // Pre-allocate space
// Process each found network
for (int i = 0; i < networksFound; i++) {
WiFiAccessPoint ap;
ap.ssid = WiFi.SSID(i);
ap.rssi = WiFi.RSSI(i);
ap.encryption = WiFi.encryptionType(i);
ap.channel = WiFi.channel(i);
ap.isHidden = WiFi.isHidden(i);
// Copy BSSID - with null check and bounds protection
uint8_t* bssid = WiFi.BSSID(i);
ap.bssid = nullptr; // Initialize to null first
if (bssid != nullptr) {
ap.bssid = new (std::nothrow) uint8_t[6]; // Use nothrow to prevent exceptions
if (ap.bssid != nullptr) {
memcpy(ap.bssid, bssid, 6);
}
}
newAccessPoints.push_back(ap);
Serial.printf("[WiFi] %d: %s (RSSI: %d, Ch: %d, Enc: %d)\n",
i, ap.ssid.c_str(), ap.rssi, ap.channel, ap.encryption);
}
}
// Free the scan results from WiFi to prevent memory leaks
WiFi.scanDelete();
// Safely swap the new results with the stored results
if (ctx.wifiAccessPoints) {
ctx.wifiAccessPoints->swap(newAccessPoints);
// Fire the scan complete event with a copy of the pointer
auto accessPoints = ctx.wifiAccessPoints;
ctx.fire("wifi/scan/complete", accessPoints);
} else {
Serial.println("[WiFi] Error: wifiAccessPoints is null");
ctx.fire("wifi/scan/error", nullptr);
}
}
void NetworkManager::onWiFiScanComplete(int networksFound) {
// Internal callback that schedules processing in the main loop
ctx.fire("wifi/scan/process", reinterpret_cast<void*>(networksFound));
}
bool NetworkManager::isWiFiScanning() const {
return wifiScanInProgress;
}

View File

@@ -1,8 +1,11 @@
#include "NodeContext.h"
#include "TaskManager.h"
NodeContext::NodeContext() {
udp = new WiFiUDP();
memberList = new std::map<String, NodeInfo>();
wifiAccessPoints = new std::vector<WiFiAccessPoint>();
taskManager = nullptr; // Will be set by TaskManager constructor
hostname = "";
self.hostname = "";
self.ip = IPAddress();
@@ -19,6 +22,7 @@ NodeContext::NodeContext(std::initializer_list<std::pair<String, String>> initia
NodeContext::~NodeContext() {
delete udp;
delete memberList;
delete wifiAccessPoints;
}
void NodeContext::on(const std::string& event, EventCallback cb) {