feat: services #2
2
.cursor/rules
Normal file
2
.cursor/rules
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
## Build
|
||||||
|
- use ./ctl build target <platformio env>
|
||||||
4
ctl.sh
4
ctl.sh
@@ -51,4 +51,8 @@ function cluster {
|
|||||||
${@:-info}
|
${@:-info}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function monitor {
|
||||||
|
pio run -t monitor
|
||||||
|
}
|
||||||
|
|
||||||
${@:-info}
|
${@:-info}
|
||||||
|
|||||||
88
examples/wifiscan/README.md
Normal file
88
examples/wifiscan/README.md
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
# WiFi Scanner Example
|
||||||
|
|
||||||
|
This example demonstrates how to use the async WiFi scanning functionality in SPORE with periodic scanning via tasks.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- **Async WiFi Scanning**: Non-blocking WiFi network discovery via NetworkManager
|
||||||
|
- **Task-based Periodic Scanning**: Automatically scans for networks every minute using TaskManager
|
||||||
|
- **Event-driven**: Uses the event system to handle scan events
|
||||||
|
- **REST API**: HTTP endpoints to manually trigger scans and view results
|
||||||
|
- **Detailed Results**: Shows SSID, RSSI, channel, and encryption type for each network
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
1. Upload this example to your ESP8266 device
|
||||||
|
2. Open the Serial Monitor at 115200 baud
|
||||||
|
3. The device will automatically start scanning for WiFi networks every minute
|
||||||
|
4. Results will be displayed in the Serial Monitor
|
||||||
|
5. Use the REST API to manually trigger scans or view current results
|
||||||
|
|
||||||
|
## Event System
|
||||||
|
|
||||||
|
The WiFi scanner uses the following events:
|
||||||
|
|
||||||
|
- `wifi/scan/start`: Fired when scan starts (both manual and periodic)
|
||||||
|
- `wifi/scan/complete`: Fired when scan completes successfully
|
||||||
|
- `wifi/scan/error`: Fired when scan fails to start
|
||||||
|
- `wifi/scan/timeout`: Fired when scan times out (10 seconds)
|
||||||
|
|
||||||
|
## Task Management
|
||||||
|
|
||||||
|
The example registers a periodic task:
|
||||||
|
- **Task Name**: `wifi_scan_periodic`
|
||||||
|
- **Interval**: 60 seconds (60000ms)
|
||||||
|
- **Function**: Fires `wifi/scan/start` event and starts WiFi scan
|
||||||
|
|
||||||
|
## REST API
|
||||||
|
|
||||||
|
### Manual Scan Control
|
||||||
|
- **Start Scan**: `POST /api/wifi/scan`
|
||||||
|
- **Get Status**: `GET /api/wifi/status`
|
||||||
|
|
||||||
|
### Example API Usage
|
||||||
|
```bash
|
||||||
|
# Start a manual scan
|
||||||
|
curl -X POST http://192.168.1.50/api/wifi/scan
|
||||||
|
|
||||||
|
# Get current scan status and results
|
||||||
|
curl http://192.168.1.50/api/wifi/status
|
||||||
|
|
||||||
|
# Check task status
|
||||||
|
curl http://192.168.1.50/api/tasks/status
|
||||||
|
|
||||||
|
# Disable periodic scanning
|
||||||
|
curl -X POST http://192.168.1.50/api/tasks/control \
|
||||||
|
-d task=wifi_scan_periodic -d action=disable
|
||||||
|
```
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
- **WiFiScannerService**: Manages periodic scanning and API endpoints
|
||||||
|
- **NetworkManager**: Handles WiFi scanning operations and callbacks
|
||||||
|
- **NodeContext**: Stores the WiFi access points data
|
||||||
|
- **TaskManager**: Schedules periodic scan tasks
|
||||||
|
- **Event System**: Provides communication between components
|
||||||
|
|
||||||
|
## WiFiAccessPoint Structure
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
struct WiFiAccessPoint {
|
||||||
|
String ssid; // Network name
|
||||||
|
int32_t rssi; // Signal strength
|
||||||
|
uint8_t encryption; // Encryption type
|
||||||
|
uint8_t* bssid; // MAC address
|
||||||
|
int32_t channel; // WiFi channel
|
||||||
|
bool isHidden; // Hidden network flag
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## Task Configuration
|
||||||
|
|
||||||
|
The periodic scanning task can be controlled via the standard TaskManager API:
|
||||||
|
- Enable/disable the task
|
||||||
|
- Change the scan interval
|
||||||
|
- Monitor task status
|
||||||
|
- Start/stop the task
|
||||||
|
|
||||||
|
This provides flexibility to adjust scanning behavior based on application needs.
|
||||||
183
examples/wifiscan/main.cpp
Normal file
183
examples/wifiscan/main.cpp
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
#include <Arduino.h>
|
||||||
|
#include <functional>
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "NodeContext.h"
|
||||||
|
#include "NetworkManager.h"
|
||||||
|
#include "ClusterManager.h"
|
||||||
|
#include "ApiServer.h"
|
||||||
|
#include "TaskManager.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
class WiFiScannerService {
|
||||||
|
public:
|
||||||
|
WiFiScannerService(NodeContext& ctx, TaskManager& taskMgr, NetworkManager& networkMgr)
|
||||||
|
: ctx(ctx), taskManager(taskMgr), network(networkMgr) {
|
||||||
|
registerTasks();
|
||||||
|
}
|
||||||
|
|
||||||
|
void registerApi(ApiServer& api) {
|
||||||
|
api.addEndpoint("/api/wifi/scan", HTTP_POST, [this](AsyncWebServerRequest* request) {
|
||||||
|
if (network.isWiFiScanning()) {
|
||||||
|
JsonDocument resp;
|
||||||
|
resp["success"] = false;
|
||||||
|
resp["message"] = "WiFi scan already in progress";
|
||||||
|
String json;
|
||||||
|
serializeJson(resp, json);
|
||||||
|
request->send(409, "application/json", json);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
network.startWiFiScan();
|
||||||
|
|
||||||
|
JsonDocument resp;
|
||||||
|
resp["success"] = true;
|
||||||
|
resp["message"] = "WiFi scan started";
|
||||||
|
String json;
|
||||||
|
serializeJson(resp, json);
|
||||||
|
request->send(200, "application/json", json);
|
||||||
|
});
|
||||||
|
|
||||||
|
api.addEndpoint("/api/wifi/status", HTTP_GET, [this](AsyncWebServerRequest* request) {
|
||||||
|
JsonDocument doc;
|
||||||
|
doc["scanning"] = network.isWiFiScanning();
|
||||||
|
doc["networks_found"] = ctx.wifiAccessPoints->size();
|
||||||
|
|
||||||
|
JsonArray networks = doc["networks"].to<JsonArray>();
|
||||||
|
for (const auto& ap : *ctx.wifiAccessPoints) {
|
||||||
|
JsonObject network = networks.add<JsonObject>();
|
||||||
|
network["ssid"] = ap.ssid;
|
||||||
|
network["rssi"] = ap.rssi;
|
||||||
|
network["channel"] = ap.channel;
|
||||||
|
network["encryption"] = ap.encryption;
|
||||||
|
network["hidden"] = ap.isHidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
String json;
|
||||||
|
serializeJson(doc, json);
|
||||||
|
request->send(200, "application/json", json);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void registerTasks() {
|
||||||
|
// Register task to start WiFi scan every minute (60000ms)
|
||||||
|
taskManager.registerTask("wifi_scan_periodic", 60000, [this]() {
|
||||||
|
if (!network.isWiFiScanning()) {
|
||||||
|
Serial.println("[WiFiScannerService] Starting periodic WiFi scan...");
|
||||||
|
ctx.fire("wifi/scan/start", nullptr);
|
||||||
|
network.startWiFiScan();
|
||||||
|
} else {
|
||||||
|
Serial.println("[WiFiScannerService] Skipping scan - already in progress");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
NodeContext& ctx;
|
||||||
|
TaskManager& taskManager;
|
||||||
|
NetworkManager& network;
|
||||||
|
};
|
||||||
|
|
||||||
|
NodeContext ctx({
|
||||||
|
{"app", "wifiscan"},
|
||||||
|
{"role", "demo"}
|
||||||
|
});
|
||||||
|
NetworkManager network(ctx);
|
||||||
|
TaskManager taskManager(ctx);
|
||||||
|
ClusterManager cluster(ctx, taskManager);
|
||||||
|
ApiServer apiServer(ctx, taskManager, ctx.config.api_server_port);
|
||||||
|
WiFiScannerService wifiScanner(ctx, taskManager, network);
|
||||||
|
|
||||||
|
// WiFi scan start callback
|
||||||
|
void onWiFiScanStart(void* data) {
|
||||||
|
Serial.println("[WiFi] Scan started...");
|
||||||
|
}
|
||||||
|
|
||||||
|
// WiFi scan complete callback
|
||||||
|
void onWiFiScanComplete(void* data) {
|
||||||
|
Serial.println("\n=== WiFi Scan Results ===");
|
||||||
|
|
||||||
|
std::vector<WiFiAccessPoint>* accessPoints = static_cast<std::vector<WiFiAccessPoint>*>(data);
|
||||||
|
|
||||||
|
if (accessPoints->empty()) {
|
||||||
|
Serial.println("No networks found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.printf("Found %d networks:\n", accessPoints->size());
|
||||||
|
Serial.println("SSID\t\t\tRSSI\tChannel\tEncryption");
|
||||||
|
Serial.println("----------------------------------------");
|
||||||
|
|
||||||
|
for (const auto& ap : *accessPoints) {
|
||||||
|
String encryptionStr = "Unknown";
|
||||||
|
switch (ap.encryption) {
|
||||||
|
case ENC_TYPE_NONE:
|
||||||
|
encryptionStr = "Open";
|
||||||
|
break;
|
||||||
|
case ENC_TYPE_WEP:
|
||||||
|
encryptionStr = "WEP";
|
||||||
|
break;
|
||||||
|
case ENC_TYPE_TKIP:
|
||||||
|
encryptionStr = "WPA";
|
||||||
|
break;
|
||||||
|
case ENC_TYPE_CCMP:
|
||||||
|
encryptionStr = "WPA2";
|
||||||
|
break;
|
||||||
|
case ENC_TYPE_AUTO:
|
||||||
|
encryptionStr = "Auto";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.printf("%-20s\t%d\t%d\t%s\n",
|
||||||
|
ap.ssid.c_str(), ap.rssi, ap.channel, encryptionStr.c_str());
|
||||||
|
}
|
||||||
|
Serial.println("========================\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// WiFi scan error callback
|
||||||
|
void onWiFiScanError(void* data) {
|
||||||
|
Serial.println("[WiFi] Scan failed - error occurred");
|
||||||
|
}
|
||||||
|
|
||||||
|
// WiFi scan timeout callback
|
||||||
|
void onWiFiScanTimeout(void* data) {
|
||||||
|
Serial.println("[WiFi] Scan failed - timeout");
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
Serial.println("\n=== WiFi Scanner Example ===");
|
||||||
|
|
||||||
|
// Initialize task manager first
|
||||||
|
taskManager.initialize();
|
||||||
|
ctx.taskManager = &taskManager;
|
||||||
|
|
||||||
|
// Initialize network tasks
|
||||||
|
network.initTasks();
|
||||||
|
|
||||||
|
// Setup WiFi
|
||||||
|
network.setupWiFi();
|
||||||
|
|
||||||
|
// Start the API server
|
||||||
|
apiServer.begin();
|
||||||
|
wifiScanner.registerApi(apiServer);
|
||||||
|
|
||||||
|
// Register WiFi scan event callbacks
|
||||||
|
ctx.on("wifi/scan/start", onWiFiScanStart);
|
||||||
|
ctx.on("wifi/scan/complete", onWiFiScanComplete);
|
||||||
|
ctx.on("wifi/scan/error", onWiFiScanError);
|
||||||
|
ctx.on("wifi/scan/timeout", onWiFiScanTimeout);
|
||||||
|
|
||||||
|
// Start an initial WiFi scan
|
||||||
|
Serial.println("Starting initial WiFi scan...");
|
||||||
|
ctx.fire("wifi/scan/start", nullptr);
|
||||||
|
network.startWiFiScan();
|
||||||
|
|
||||||
|
// Print initial task status
|
||||||
|
taskManager.printTaskStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
taskManager.execute();
|
||||||
|
yield();
|
||||||
|
}
|
||||||
@@ -7,6 +7,18 @@ public:
|
|||||||
NetworkManager(NodeContext& ctx);
|
NetworkManager(NodeContext& ctx);
|
||||||
void setupWiFi();
|
void setupWiFi();
|
||||||
void setHostnameFromMac();
|
void setHostnameFromMac();
|
||||||
|
void startWiFiScan();
|
||||||
|
void updateWiFiScan();
|
||||||
|
bool isWiFiScanning() const;
|
||||||
|
void processScanResults(int networksFound);
|
||||||
|
void initTasks(); // Initialize tasks after TaskManager is ready // Public method to process scan results
|
||||||
|
|
||||||
private:
|
private:
|
||||||
NodeContext& ctx;
|
NodeContext& ctx;
|
||||||
|
bool wifiScanInProgress;
|
||||||
|
unsigned long wifiScanStartTime;
|
||||||
|
static const unsigned long WIFI_SCAN_TIMEOUT_MS = 10000; // 10 seconds timeout
|
||||||
|
static const char* const WIFI_SCAN_MONITOR_TASK; // Task name for WiFi scan monitoring
|
||||||
|
|
||||||
|
void onWiFiScanComplete(int networksFound); // Keep private for internal use
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,12 +2,33 @@
|
|||||||
|
|
||||||
#include <WiFiUdp.h>
|
#include <WiFiUdp.h>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
#include "NodeInfo.h"
|
#include "NodeInfo.h"
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <initializer_list>
|
#include <initializer_list>
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
|
||||||
|
// Forward declaration
|
||||||
|
class TaskManager;
|
||||||
|
|
||||||
|
// WiFi access point structure
|
||||||
|
struct WiFiAccessPoint {
|
||||||
|
String ssid;
|
||||||
|
int32_t rssi;
|
||||||
|
uint8_t encryption;
|
||||||
|
uint8_t* bssid;
|
||||||
|
int32_t channel;
|
||||||
|
bool isHidden;
|
||||||
|
|
||||||
|
WiFiAccessPoint() : rssi(0), encryption(0), bssid(nullptr), channel(0), isHidden(false) {}
|
||||||
|
~WiFiAccessPoint() {
|
||||||
|
if (bssid) {
|
||||||
|
delete[] bssid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class NodeContext {
|
class NodeContext {
|
||||||
public:
|
public:
|
||||||
NodeContext();
|
NodeContext();
|
||||||
@@ -19,10 +40,14 @@ public:
|
|||||||
NodeInfo self;
|
NodeInfo self;
|
||||||
std::map<String, NodeInfo>* memberList;
|
std::map<String, NodeInfo>* memberList;
|
||||||
Config config;
|
Config config;
|
||||||
|
TaskManager* taskManager;
|
||||||
|
|
||||||
using EventCallback = std::function<void(void*)>;
|
using EventCallback = std::function<void(void*)>;
|
||||||
std::map<std::string, std::vector<EventCallback>> eventRegistry;
|
std::map<std::string, std::vector<EventCallback>> eventRegistry;
|
||||||
|
|
||||||
void on(const std::string& event, EventCallback cb);
|
void on(const std::string& event, EventCallback cb);
|
||||||
void fire(const std::string& event, void* data);
|
void fire(const std::string& event, void* data);
|
||||||
|
|
||||||
|
// WiFi access points storage
|
||||||
|
std::vector<WiFiAccessPoint>* wifiAccessPoints;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,9 +4,11 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include "NodeContext.h"
|
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
|
|
||||||
|
// Forward declaration
|
||||||
|
class NodeContext;
|
||||||
|
|
||||||
// Define our own callback type to avoid conflict with TaskScheduler
|
// Define our own callback type to avoid conflict with TaskScheduler
|
||||||
using TaskFunction = std::function<void()>;
|
using TaskFunction = std::function<void()>;
|
||||||
|
|
||||||
|
|||||||
@@ -124,3 +124,32 @@ build_src_filter =
|
|||||||
+<examples/neopattern/main.cpp>
|
+<examples/neopattern/main.cpp>
|
||||||
+<src/*.c>
|
+<src/*.c>
|
||||||
+<src/*.cpp>
|
+<src/*.cpp>
|
||||||
|
|
||||||
|
[env:esp01_1m_wifiscan]
|
||||||
|
platform = platformio/espressif8266@^4.2.1
|
||||||
|
board = esp01_1m
|
||||||
|
framework = arduino
|
||||||
|
upload_speed = 115200
|
||||||
|
monitor_speed = 115200
|
||||||
|
board_build.partitions = partitions_ota_1M.csv
|
||||||
|
board_build.flash_mode = dout
|
||||||
|
board_build.flash_size = 1M
|
||||||
|
lib_deps = ${common.lib_deps}
|
||||||
|
build_src_filter =
|
||||||
|
+<examples/wifiscan/*.cpp>
|
||||||
|
+<src/*.c>
|
||||||
|
+<src/*.cpp>
|
||||||
|
|
||||||
|
[env:d1_mini_wifiscan]
|
||||||
|
platform = platformio/espressif8266@^4.2.1
|
||||||
|
board = d1_mini
|
||||||
|
framework = arduino
|
||||||
|
upload_speed = 115200
|
||||||
|
monitor_speed = 115200
|
||||||
|
board_build.flash_mode = dio
|
||||||
|
board_build.flash_size = 4M
|
||||||
|
lib_deps = ${common.lib_deps}
|
||||||
|
build_src_filter =
|
||||||
|
+<examples/wifiscan/*.cpp>
|
||||||
|
+<src/*.c>
|
||||||
|
+<src/*.cpp>
|
||||||
|
|||||||
@@ -1,8 +1,29 @@
|
|||||||
#include "NetworkManager.h"
|
#include "NetworkManager.h"
|
||||||
|
#include "TaskManager.h"
|
||||||
|
|
||||||
// SSID and password are now configured via Config class
|
// 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() {
|
void NetworkManager::setHostnameFromMac() {
|
||||||
uint8_t mac[6];
|
uint8_t mac[6];
|
||||||
@@ -65,3 +86,133 @@ void NetworkManager::setupWiFi() {
|
|||||||
// Notify listeners that the node is (re)discovered
|
// Notify listeners that the node is (re)discovered
|
||||||
ctx.fire("node_discovered", &ctx.self);
|
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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
#include "NodeContext.h"
|
#include "NodeContext.h"
|
||||||
|
#include "TaskManager.h"
|
||||||
|
|
||||||
NodeContext::NodeContext() {
|
NodeContext::NodeContext() {
|
||||||
udp = new WiFiUDP();
|
udp = new WiFiUDP();
|
||||||
memberList = new std::map<String, NodeInfo>();
|
memberList = new std::map<String, NodeInfo>();
|
||||||
|
wifiAccessPoints = new std::vector<WiFiAccessPoint>();
|
||||||
|
taskManager = nullptr; // Will be set by TaskManager constructor
|
||||||
hostname = "";
|
hostname = "";
|
||||||
self.hostname = "";
|
self.hostname = "";
|
||||||
self.ip = IPAddress();
|
self.ip = IPAddress();
|
||||||
@@ -19,6 +22,7 @@ NodeContext::NodeContext(std::initializer_list<std::pair<String, String>> initia
|
|||||||
NodeContext::~NodeContext() {
|
NodeContext::~NodeContext() {
|
||||||
delete udp;
|
delete udp;
|
||||||
delete memberList;
|
delete memberList;
|
||||||
|
delete wifiAccessPoints;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeContext::on(const std::string& event, EventCallback cb) {
|
void NodeContext::on(const std::string& event, EventCallback cb) {
|
||||||
|
|||||||
Reference in New Issue
Block a user