mirror of
https://github.com/MrUnknownDE/OpenIris-ESPIDF.git
synced 2026-04-16 04:53:45 +02:00
Improvements and refactors after CR, add option to modify mdns name and simplify setup tool
This commit is contained in:
@@ -25,66 +25,70 @@ std::unordered_map<std::string, CommandType> commandTypeMap = {
|
||||
{"get_device_mode", CommandType::GET_DEVICE_MODE},
|
||||
};
|
||||
|
||||
std::function<CommandResult()> CommandManager::createCommand(const CommandType type, std::string_view json) const {
|
||||
std::function<CommandResult()> CommandManager::createCommand(const CommandType type, std::string_view json) const
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case CommandType::PING:
|
||||
return { PingCommand };
|
||||
return {PingCommand};
|
||||
case CommandType::PAUSE:
|
||||
return [json] {
|
||||
PausePayload payload;
|
||||
cJSON* root = cJSON_Parse(std::string(json).c_str());
|
||||
if (root) {
|
||||
cJSON* pauseItem = cJSON_GetObjectItem(root, "pause");
|
||||
if (pauseItem && cJSON_IsBool(pauseItem)) {
|
||||
payload.pause = cJSON_IsTrue(pauseItem);
|
||||
} else {
|
||||
payload.pause = true; // Default to pause if not specified
|
||||
}
|
||||
cJSON_Delete(root);
|
||||
} else {
|
||||
payload.pause = true; // Default to pause if parsing fails
|
||||
}
|
||||
return PauseCommand(payload);
|
||||
};
|
||||
return [json]
|
||||
{ return PauseCommand(json); };
|
||||
case CommandType::SET_STREAMING_MODE:
|
||||
return [this, json] {return setDeviceModeCommand(this->registry, json); };
|
||||
return [this, json]
|
||||
{ return setDeviceModeCommand(this->registry, json); };
|
||||
case CommandType::UPDATE_OTA_CREDENTIALS:
|
||||
return [this, json] { return updateOTACredentialsCommand(this->registry, json); };
|
||||
return [this, json]
|
||||
{ return updateOTACredentialsCommand(this->registry, json); };
|
||||
case CommandType::SET_WIFI:
|
||||
return [this, json] { return setWiFiCommand(this->registry, json); };
|
||||
return [this, json]
|
||||
{ return setWiFiCommand(this->registry, json); };
|
||||
case CommandType::UPDATE_WIFI:
|
||||
return [this, json] { return updateWiFiCommand(this->registry, json); };
|
||||
return [this, json]
|
||||
{ return updateWiFiCommand(this->registry, json); };
|
||||
case CommandType::UPDATE_AP_WIFI:
|
||||
return [this, json] { return updateAPWiFiCommand(this->registry, json); };
|
||||
return [this, json]
|
||||
{ return updateAPWiFiCommand(this->registry, json); };
|
||||
case CommandType::DELETE_NETWORK:
|
||||
return [this, json] { return deleteWiFiCommand(this->registry, json); };
|
||||
return [this, json]
|
||||
{ return deleteWiFiCommand(this->registry, json); };
|
||||
case CommandType::SET_MDNS:
|
||||
return [this, json] { return setMDNSCommand(this->registry, json); };
|
||||
return [this, json]
|
||||
{ return setMDNSCommand(this->registry, json); };
|
||||
case CommandType::UPDATE_CAMERA:
|
||||
return [this, json] { return updateCameraCommand(this->registry, json); };
|
||||
return [this, json]
|
||||
{ return updateCameraCommand(this->registry, json); };
|
||||
case CommandType::RESTART_CAMERA:
|
||||
return [this, json] { return restartCameraCommand(this->registry, json); };
|
||||
return [this, json]
|
||||
{ return restartCameraCommand(this->registry, json); };
|
||||
case CommandType::GET_CONFIG:
|
||||
return [this] { return getConfigCommand(this->registry); };
|
||||
return [this]
|
||||
{ return getConfigCommand(this->registry); };
|
||||
case CommandType::SAVE_CONFIG:
|
||||
return [this] { return saveConfigCommand(this->registry); };
|
||||
return [this]
|
||||
{ return saveConfigCommand(this->registry); };
|
||||
case CommandType::RESET_CONFIG:
|
||||
return [this, json] { return resetConfigCommand(this->registry, json); };
|
||||
return [this, json]
|
||||
{ return resetConfigCommand(this->registry, json); };
|
||||
case CommandType::RESTART_DEVICE:
|
||||
return restartDeviceCommand;
|
||||
case CommandType::SCAN_NETWORKS:
|
||||
return [this] { return scanNetworksCommand(this->registry); };
|
||||
return [this]
|
||||
{ return scanNetworksCommand(this->registry); };
|
||||
case CommandType::START_STREAMING:
|
||||
return startStreamingCommand;
|
||||
case CommandType::GET_WIFI_STATUS:
|
||||
return [this] { return getWiFiStatusCommand(this->registry); };
|
||||
return [this]
|
||||
{ return getWiFiStatusCommand(this->registry); };
|
||||
case CommandType::CONNECT_WIFI:
|
||||
return [this] { return connectWiFiCommand(this->registry); };
|
||||
return [this]
|
||||
{ return connectWiFiCommand(this->registry); };
|
||||
case CommandType::SWITCH_MODE:
|
||||
return [this, json] { return switchModeCommand(this->registry, json); };
|
||||
return [this, json]
|
||||
{ return switchModeCommand(this->registry, json); };
|
||||
case CommandType::GET_DEVICE_MODE:
|
||||
return [this] { return getDeviceModeCommand(this->registry); };
|
||||
return [this]
|
||||
{ return getDeviceModeCommand(this->registry); };
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
@@ -135,7 +139,7 @@ CommandResult CommandManager::executeFromJson(const std::string_view json) const
|
||||
cJSON_AddItemToArray(responses, response);
|
||||
}
|
||||
|
||||
char* jsonString = cJSON_Print(responseDocument);
|
||||
char *jsonString = cJSON_Print(responseDocument);
|
||||
cJSON_Delete(responseDocument);
|
||||
cJSON_Delete(parsedJson);
|
||||
|
||||
|
||||
@@ -22,30 +22,30 @@ public:
|
||||
CommandResult(std::string message, const Status status)
|
||||
{
|
||||
this->status = status;
|
||||
|
||||
// Escape quotes and backslashes in the message for JSON
|
||||
std::string escapedMessage = message;
|
||||
size_t pos = 0;
|
||||
// First escape backslashes
|
||||
while ((pos = escapedMessage.find('\\', pos)) != std::string::npos) {
|
||||
while ((pos = escapedMessage.find('\\', pos)) != std::string::npos)
|
||||
{
|
||||
escapedMessage.replace(pos, 1, "\\\\");
|
||||
pos += 2;
|
||||
}
|
||||
// Then escape quotes
|
||||
pos = 0;
|
||||
while ((pos = escapedMessage.find('"', pos)) != std::string::npos) {
|
||||
while ((pos = escapedMessage.find('"', pos)) != std::string::npos)
|
||||
{
|
||||
escapedMessage.replace(pos, 1, "\\\"");
|
||||
pos += 2;
|
||||
}
|
||||
|
||||
|
||||
if (status == Status::SUCCESS)
|
||||
{
|
||||
// we gotta do it this way, because if we define it as { "result": " {} " } it crashes the compiler, lol
|
||||
this->message = std::format("{}\"result\":\"{}\"{}", "{", escapedMessage, "}");
|
||||
this->message = std::format("{{\"result\":\"{}\"}}", escapedMessage);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->message = std::format("{}\"error\":\"{}\"{}", "{", escapedMessage, "}");
|
||||
this->message = std::format("{{\"error\":\"{}\"}}", escapedMessage);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ public:
|
||||
{
|
||||
return CommandResult(message, Status::FAILURE);
|
||||
}
|
||||
|
||||
|
||||
// Create a result that returns raw JSON without wrapper
|
||||
static CommandResult getRawJsonResult(const std::string &jsonMessage)
|
||||
{
|
||||
@@ -70,7 +70,6 @@ public:
|
||||
}
|
||||
|
||||
std::string getResult() const { return this->message; }
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,25 +1,24 @@
|
||||
#include "device_commands.hpp"
|
||||
|
||||
#include <cJSON.h>
|
||||
#include <ProjectConfig.hpp>
|
||||
#include "esp_timer.h"
|
||||
#include <main_globals.hpp>
|
||||
|
||||
// Implementation inspired by SummerSigh work, initial PR opened in openiris repo, adapted to this rewrite
|
||||
CommandResult setDeviceModeCommand(std::shared_ptr<DependencyRegistry> registry, std::string_view jsonPayload) {
|
||||
CommandResult setDeviceModeCommand(std::shared_ptr<DependencyRegistry> registry, std::string_view jsonPayload)
|
||||
{
|
||||
const auto parsedJson = cJSON_Parse(jsonPayload.data());
|
||||
if (parsedJson == nullptr) {
|
||||
if (parsedJson == nullptr)
|
||||
{
|
||||
return CommandResult::getErrorResult("Invalid payload");
|
||||
}
|
||||
|
||||
const auto modeObject = cJSON_GetObjectItem(parsedJson, "mode");
|
||||
if (modeObject == nullptr) {
|
||||
if (modeObject == nullptr)
|
||||
{
|
||||
return CommandResult::getErrorResult("Invalid payload - missing mode");
|
||||
}
|
||||
|
||||
const auto mode = modeObject->valueint;
|
||||
|
||||
if (mode < 0 || mode > 2) {
|
||||
if (mode < 0 || mode > 2)
|
||||
{
|
||||
return CommandResult::getErrorResult("Invalid payload - unsupported mode");
|
||||
}
|
||||
|
||||
@@ -29,10 +28,12 @@ CommandResult setDeviceModeCommand(std::shared_ptr<DependencyRegistry> registry,
|
||||
return CommandResult::getSuccessResult("Device mode set");
|
||||
}
|
||||
|
||||
CommandResult updateOTACredentialsCommand(std::shared_ptr<DependencyRegistry> registry, std::string_view jsonPayload) {
|
||||
CommandResult updateOTACredentialsCommand(std::shared_ptr<DependencyRegistry> registry, std::string_view jsonPayload)
|
||||
{
|
||||
const auto parsedJson = cJSON_Parse(jsonPayload.data());
|
||||
|
||||
if (parsedJson == nullptr) {
|
||||
if (parsedJson == nullptr)
|
||||
{
|
||||
return CommandResult::getErrorResult("Invalid payload");
|
||||
}
|
||||
|
||||
@@ -42,18 +43,23 @@ CommandResult updateOTACredentialsCommand(std::shared_ptr<DependencyRegistry> re
|
||||
auto OTAPassword = oldDeviceConfig.OTAPassword;
|
||||
auto OTAPort = oldDeviceConfig.OTAPort;
|
||||
|
||||
if (const auto OTALoginObject = cJSON_GetObjectItem(parsedJson, "login"); OTALoginObject != nullptr) {
|
||||
if (const auto newLogin = OTALoginObject->valuestring; strcmp(newLogin, "") != 0) {
|
||||
if (const auto OTALoginObject = cJSON_GetObjectItem(parsedJson, "login"); OTALoginObject != nullptr)
|
||||
{
|
||||
if (const auto newLogin = OTALoginObject->valuestring; strcmp(newLogin, "") != 0)
|
||||
{
|
||||
OTALogin = newLogin;
|
||||
}
|
||||
}
|
||||
|
||||
if (const auto OTAPasswordObject = cJSON_GetObjectItem(parsedJson, "password"); OTAPasswordObject != nullptr) {
|
||||
if (const auto OTAPasswordObject = cJSON_GetObjectItem(parsedJson, "password"); OTAPasswordObject != nullptr)
|
||||
{
|
||||
OTAPassword = OTAPasswordObject->valuestring;
|
||||
}
|
||||
|
||||
if (const auto OTAPortObject = cJSON_GetObjectItem(parsedJson, "port"); OTAPortObject != nullptr) {
|
||||
if (const auto newPort = OTAPortObject->valueint; newPort >= 82) {
|
||||
if (const auto OTAPortObject = cJSON_GetObjectItem(parsedJson, "port"); OTAPortObject != nullptr)
|
||||
{
|
||||
if (const auto newPort = OTAPortObject->valueint; newPort >= 82)
|
||||
{
|
||||
OTAPort = newPort;
|
||||
}
|
||||
}
|
||||
@@ -62,70 +68,82 @@ CommandResult updateOTACredentialsCommand(std::shared_ptr<DependencyRegistry> re
|
||||
return CommandResult::getSuccessResult("OTA Config set");
|
||||
}
|
||||
|
||||
CommandResult restartDeviceCommand() {
|
||||
CommandResult restartDeviceCommand()
|
||||
{
|
||||
OpenIrisTasks::ScheduleRestart(2000);
|
||||
return CommandResult::getSuccessResult("Device restarted");
|
||||
}
|
||||
|
||||
CommandResult startStreamingCommand() {
|
||||
CommandResult startStreamingCommand()
|
||||
{
|
||||
activateStreaming(false); // Don't disable setup interfaces by default
|
||||
return CommandResult::getSuccessResult("Streaming started");
|
||||
}
|
||||
|
||||
CommandResult switchModeCommand(std::shared_ptr<DependencyRegistry> registry, std::string_view jsonPayload) {
|
||||
CommandResult switchModeCommand(std::shared_ptr<DependencyRegistry> registry, std::string_view jsonPayload)
|
||||
{
|
||||
const auto parsedJson = cJSON_Parse(jsonPayload.data());
|
||||
if (parsedJson == nullptr) {
|
||||
if (parsedJson == nullptr)
|
||||
{
|
||||
return CommandResult::getErrorResult("Invalid payload");
|
||||
}
|
||||
|
||||
const auto modeObject = cJSON_GetObjectItem(parsedJson, "mode");
|
||||
if (modeObject == nullptr) {
|
||||
if (modeObject == nullptr)
|
||||
{
|
||||
return CommandResult::getErrorResult("Invalid payload - missing mode");
|
||||
}
|
||||
|
||||
const char* modeStr = modeObject->valuestring;
|
||||
const char *modeStr = modeObject->valuestring;
|
||||
StreamingMode newMode;
|
||||
|
||||
|
||||
ESP_LOGI("[DEVICE_COMMANDS]", "Switch mode command received with mode: %s", modeStr);
|
||||
|
||||
if (strcmp(modeStr, "uvc") == 0 || strcmp(modeStr, "UVC") == 0) {
|
||||
|
||||
if (strcmp(modeStr, "uvc") == 0)
|
||||
{
|
||||
newMode = StreamingMode::UVC;
|
||||
} else if (strcmp(modeStr, "wifi") == 0 || strcmp(modeStr, "WiFi") == 0 || strcmp(modeStr, "WIFI") == 0) {
|
||||
}
|
||||
else if (strcmp(modeStr, "wifi") == 0)
|
||||
{
|
||||
newMode = StreamingMode::WIFI;
|
||||
} else if (strcmp(modeStr, "auto") == 0 || strcmp(modeStr, "AUTO") == 0) {
|
||||
}
|
||||
else if (strcmp(modeStr, "auto") == 0)
|
||||
{
|
||||
newMode = StreamingMode::AUTO;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
return CommandResult::getErrorResult("Invalid mode - use 'uvc', 'wifi', or 'auto'");
|
||||
}
|
||||
|
||||
const auto projectConfig = registry->resolve<ProjectConfig>(DependencyType::project_config);
|
||||
ESP_LOGI("[DEVICE_COMMANDS]", "Setting device mode to: %d", (int)newMode);
|
||||
projectConfig->setDeviceMode(newMode);
|
||||
|
||||
|
||||
cJSON_Delete(parsedJson);
|
||||
|
||||
return CommandResult::getSuccessResult("Device mode switched, restart to apply");
|
||||
}
|
||||
|
||||
CommandResult getDeviceModeCommand(std::shared_ptr<DependencyRegistry> registry) {
|
||||
CommandResult getDeviceModeCommand(std::shared_ptr<DependencyRegistry> registry)
|
||||
{
|
||||
const auto projectConfig = registry->resolve<ProjectConfig>(DependencyType::project_config);
|
||||
StreamingMode currentMode = projectConfig->getDeviceMode();
|
||||
|
||||
const char* modeStr = "unknown";
|
||||
switch (currentMode) {
|
||||
case StreamingMode::UVC:
|
||||
modeStr = "UVC";
|
||||
break;
|
||||
case StreamingMode::WIFI:
|
||||
modeStr = "WiFi";
|
||||
break;
|
||||
case StreamingMode::AUTO:
|
||||
modeStr = "Auto";
|
||||
break;
|
||||
|
||||
const char *modeStr = "unknown";
|
||||
switch (currentMode)
|
||||
{
|
||||
case StreamingMode::UVC:
|
||||
modeStr = "UVC";
|
||||
break;
|
||||
case StreamingMode::WIFI:
|
||||
modeStr = "WiFi";
|
||||
break;
|
||||
case StreamingMode::AUTO:
|
||||
modeStr = "Auto";
|
||||
break;
|
||||
}
|
||||
|
||||
char result[100];
|
||||
sprintf(result, "{\"mode\":\"%s\",\"value\":%d}", modeStr, (int)currentMode);
|
||||
|
||||
|
||||
auto result = std::format("{{ \"mode\": \"{}\", \"value\": {} }}", modeStr, static_cast<int>(currentMode));
|
||||
return CommandResult::getSuccessResult(result);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
#include "CommandResult.hpp"
|
||||
#include "ProjectConfig.hpp"
|
||||
#include "OpenIrisTasks.hpp"
|
||||
#include "DependencyRegistry.hpp"
|
||||
#include "esp_timer.h"
|
||||
#include "cJSON.h"
|
||||
#include "main_globals.hpp"
|
||||
|
||||
#include <format>
|
||||
#include <string>
|
||||
|
||||
CommandResult setDeviceModeCommand(std::shared_ptr<DependencyRegistry> registry, std::string_view jsonPayload);
|
||||
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#include "scan_commands.hpp"
|
||||
#include "cJSON.h"
|
||||
#include "esp_log.h"
|
||||
#include <string>
|
||||
|
||||
CommandResult scanNetworksCommand(std::shared_ptr<DependencyRegistry> registry) {
|
||||
CommandResult scanNetworksCommand(std::shared_ptr<DependencyRegistry> registry)
|
||||
{
|
||||
auto wifiManager = registry->resolve<WiFiManager>(DependencyType::wifi_manager);
|
||||
if (!wifiManager) {
|
||||
if (!wifiManager)
|
||||
{
|
||||
return CommandResult::getErrorResult("WiFiManager not available");
|
||||
}
|
||||
|
||||
@@ -15,7 +14,8 @@ CommandResult scanNetworksCommand(std::shared_ptr<DependencyRegistry> registry)
|
||||
cJSON *networksArray = cJSON_CreateArray();
|
||||
cJSON_AddItemToObject(root, "networks", networksArray);
|
||||
|
||||
for (const auto& network : networks) {
|
||||
for (const auto &network : networks)
|
||||
{
|
||||
cJSON *networkObject = cJSON_CreateObject();
|
||||
cJSON_AddStringToObject(networkObject, "ssid", network.ssid.c_str());
|
||||
cJSON_AddNumberToObject(networkObject, "channel", network.channel);
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
#ifndef SCAN_COMMANDS_HPP
|
||||
#define SCAN_COMMANDS_HPP
|
||||
|
||||
#include "../CommandResult.hpp"
|
||||
#include "../DependencyRegistry.hpp"
|
||||
#include "CommandResult.hpp"
|
||||
#include "DependencyRegistry.hpp"
|
||||
#include "esp_log.h"
|
||||
#include <cJSON.h>
|
||||
#include <wifiManager.hpp>
|
||||
#include <string>
|
||||
|
||||
CommandResult scanNetworksCommand(std::shared_ptr<DependencyRegistry> registry);
|
||||
|
||||
|
||||
@@ -1,24 +1,39 @@
|
||||
#include "simple_commands.hpp"
|
||||
#include "main_globals.hpp"
|
||||
#include "esp_log.h"
|
||||
|
||||
static const char* TAG = "SimpleCommands";
|
||||
static const char *TAG = "SimpleCommands";
|
||||
|
||||
CommandResult PingCommand()
|
||||
{
|
||||
return CommandResult::getSuccessResult("pong");
|
||||
};
|
||||
|
||||
CommandResult PauseCommand(const PausePayload& payload)
|
||||
CommandResult PauseCommand(std::string_view jsonPayload)
|
||||
{
|
||||
PausePayload payload;
|
||||
// pause by default if this command gets executed, even if the payload was invalid
|
||||
payload.pause = true;
|
||||
|
||||
cJSON *root = cJSON_Parse(std::string(jsonPayload).c_str());
|
||||
if (root)
|
||||
{
|
||||
cJSON *pauseItem = cJSON_GetObjectItem(root, "pause");
|
||||
if (pauseItem && cJSON_IsBool(pauseItem))
|
||||
{
|
||||
payload.pause = cJSON_IsTrue(pauseItem);
|
||||
}
|
||||
cJSON_Delete(root);
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Pause command received: %s", payload.pause ? "true" : "false");
|
||||
|
||||
startupPaused = payload.pause;
|
||||
|
||||
if (payload.pause) {
|
||||
|
||||
setStartupPaused(payload.pause);
|
||||
if (payload.pause)
|
||||
{
|
||||
ESP_LOGI(TAG, "Startup paused - device will remain in configuration mode");
|
||||
return CommandResult::getSuccessResult("Startup paused");
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGI(TAG, "Startup resumed");
|
||||
return CommandResult::getSuccessResult("Startup resumed");
|
||||
}
|
||||
|
||||
@@ -4,8 +4,11 @@
|
||||
#include <string>
|
||||
#include "CommandResult.hpp"
|
||||
#include "CommandSchema.hpp"
|
||||
#include "main_globals.hpp"
|
||||
#include "esp_log.h"
|
||||
#include <cJSON.h>
|
||||
|
||||
CommandResult PingCommand();
|
||||
CommandResult PauseCommand(const PausePayload& payload);
|
||||
CommandResult PauseCommand(std::string_view jsonPayload);
|
||||
|
||||
#endif
|
||||
@@ -4,37 +4,47 @@
|
||||
// Forward declarations
|
||||
extern void start_video_streaming(void *arg);
|
||||
|
||||
// Global variables to be set by main
|
||||
static esp_timer_handle_t* g_streaming_timer_handle = nullptr;
|
||||
static TaskHandle_t* g_serial_manager_handle = nullptr;
|
||||
|
||||
// Functions for main to set the global handles
|
||||
void setStreamingTimerHandle(esp_timer_handle_t* handle) {
|
||||
g_streaming_timer_handle = handle;
|
||||
bool startupCommandReceived = false;
|
||||
bool getStartupCommandReceived()
|
||||
{
|
||||
return startupCommandReceived;
|
||||
}
|
||||
|
||||
void setSerialManagerHandle(TaskHandle_t* handle) {
|
||||
g_serial_manager_handle = handle;
|
||||
void setStartupCommandReceived(bool startupCommandReceived)
|
||||
{
|
||||
startupCommandReceived = startupCommandReceived;
|
||||
}
|
||||
|
||||
// Functions for components to access the handles
|
||||
esp_timer_handle_t* getStreamingTimerHandle() {
|
||||
return g_streaming_timer_handle;
|
||||
}
|
||||
|
||||
TaskHandle_t* getSerialManagerHandle() {
|
||||
static TaskHandle_t *g_serial_manager_handle = nullptr;
|
||||
TaskHandle_t *getSerialManagerHandle()
|
||||
{
|
||||
return g_serial_manager_handle;
|
||||
}
|
||||
|
||||
void setSerialManagerHandle(TaskHandle_t *serialManagerHandle)
|
||||
{
|
||||
g_serial_manager_handle = serialManagerHandle;
|
||||
}
|
||||
|
||||
// Global pause state
|
||||
bool startupPaused = false;
|
||||
bool getStartupPaused()
|
||||
{
|
||||
return startupPaused;
|
||||
}
|
||||
|
||||
void setStartupPaused(bool startupPaused)
|
||||
{
|
||||
startupPaused = startupPaused;
|
||||
}
|
||||
|
||||
// Function to manually activate streaming
|
||||
void activateStreaming(bool disableSetup) {
|
||||
void activateStreaming(bool disableSetup)
|
||||
{
|
||||
ESP_LOGI("[MAIN_GLOBALS]", "Manually activating streaming, disableSetup=%s", disableSetup ? "true" : "false");
|
||||
|
||||
TaskHandle_t* serialHandle = disableSetup ? g_serial_manager_handle : nullptr;
|
||||
void* serialTaskHandle = (serialHandle && *serialHandle) ? *serialHandle : nullptr;
|
||||
|
||||
|
||||
TaskHandle_t *serialHandle = disableSetup ? g_serial_manager_handle : nullptr;
|
||||
void *serialTaskHandle = (serialHandle && *serialHandle) ? *serialHandle : nullptr;
|
||||
|
||||
start_video_streaming(serialTaskHandle);
|
||||
}
|
||||
@@ -7,22 +7,18 @@
|
||||
#include "freertos/task.h"
|
||||
|
||||
// Functions for main to set global handles
|
||||
void setStreamingTimerHandle(esp_timer_handle_t* handle);
|
||||
void setSerialManagerHandle(TaskHandle_t* handle);
|
||||
|
||||
// Functions to access global handles from components
|
||||
esp_timer_handle_t* getStreamingTimerHandle();
|
||||
TaskHandle_t* getSerialManagerHandle();
|
||||
TaskHandle_t *getSerialManagerHandle();
|
||||
void setSerialManagerHandle(TaskHandle_t *serialManagerHandle);
|
||||
|
||||
// Function to manually activate streaming
|
||||
void activateStreaming(bool disableSetup = false);
|
||||
|
||||
// Function to notify that a command was received during startup
|
||||
extern void notify_startup_command_received();
|
||||
bool getStartupCommandReceived();
|
||||
void setStartupCommandReceived(bool startupCommandReceived);
|
||||
|
||||
// Global variables for startup state
|
||||
extern bool startupCommandReceived;
|
||||
extern esp_timer_handle_t startupTimerHandle;
|
||||
extern bool startupPaused;
|
||||
bool getStartupPaused();
|
||||
void setStartupPaused(bool startupPaused);
|
||||
|
||||
#endif
|
||||
@@ -9,7 +9,6 @@
|
||||
#include "Models.hpp"
|
||||
#include <Preferences.hpp>
|
||||
|
||||
|
||||
int getNetworkCount(Preferences *pref);
|
||||
|
||||
void saveNetworkCount(Preferences *pref, int count);
|
||||
@@ -60,7 +59,7 @@ public:
|
||||
const std::string &password,
|
||||
uint8_t channel);
|
||||
void setWiFiTxPower(uint8_t power);
|
||||
void setDeviceMode(StreamingMode deviceMode);
|
||||
void setDeviceMode(StreamingMode deviceMode);
|
||||
StreamingMode getDeviceMode();
|
||||
|
||||
private:
|
||||
|
||||
@@ -4,8 +4,9 @@
|
||||
|
||||
#define BUF_SIZE (1024)
|
||||
|
||||
SerialManager::SerialManager(std::shared_ptr<CommandManager> commandManager, esp_timer_handle_t *timerHandle, std::shared_ptr<ProjectConfig> deviceConfig)
|
||||
: commandManager(commandManager), timerHandle(timerHandle), deviceConfig(deviceConfig) {
|
||||
SerialManager::SerialManager(std::shared_ptr<CommandManager> commandManager, esp_timer_handle_t *timerHandle, std::shared_ptr<ProjectConfig> deviceConfig)
|
||||
: commandManager(commandManager), timerHandle(timerHandle), deviceConfig(deviceConfig)
|
||||
{
|
||||
this->data = static_cast<uint8_t *>(malloc(BUF_SIZE));
|
||||
this->temp_data = static_cast<uint8_t *>(malloc(256));
|
||||
}
|
||||
@@ -40,47 +41,62 @@ void SerialManager::try_receive()
|
||||
|
||||
// Notify main that a command was received during startup
|
||||
notify_startup_command_received();
|
||||
|
||||
|
||||
const auto result = this->commandManager->executeFromJson(std::string_view(reinterpret_cast<const char *>(this->data)));
|
||||
const auto resultMessage = result.getResult();
|
||||
usb_serial_jtag_write_bytes(resultMessage.c_str(), resultMessage.length(), 1000 / 20);
|
||||
}
|
||||
}
|
||||
|
||||
// Function to notify that a command was received during startup
|
||||
void SerialManager::notify_startup_command_received()
|
||||
{
|
||||
setStartupCommandReceived(true);
|
||||
|
||||
// Cancel the startup timer if it's still running
|
||||
if (timerHandle != nullptr)
|
||||
{
|
||||
esp_timer_stop(*timerHandle);
|
||||
esp_timer_delete(*timerHandle);
|
||||
timerHandle = nullptr;
|
||||
ESP_LOGI("[MAIN]", "Startup timer cancelled, staying in heartbeat mode");
|
||||
}
|
||||
}
|
||||
|
||||
void SerialManager::send_heartbeat()
|
||||
{
|
||||
// Get the MAC address as unique identifier
|
||||
uint8_t mac[6];
|
||||
esp_read_mac(mac, ESP_MAC_WIFI_STA);
|
||||
|
||||
|
||||
// Format as serial number string
|
||||
char serial_number[18];
|
||||
sprintf(serial_number, "%02X%02X%02X%02X%02X%02X",
|
||||
sprintf(serial_number, "%02X%02X%02X%02X%02X%02X",
|
||||
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||||
|
||||
|
||||
// Create heartbeat JSON with serial number
|
||||
char heartbeat[128];
|
||||
sprintf(heartbeat, "{\"heartbeat\":\"openiris_setup_mode\",\"serial\":\"%s\"}\n", serial_number);
|
||||
|
||||
|
||||
usb_serial_jtag_write_bytes(heartbeat, strlen(heartbeat), 1000 / 20);
|
||||
}
|
||||
|
||||
bool SerialManager::should_send_heartbeat()
|
||||
{
|
||||
// Always send heartbeat during startup delay or if no WiFi configured
|
||||
extern bool startupCommandReceived;
|
||||
extern esp_timer_handle_t startupTimerHandle;
|
||||
|
||||
|
||||
// If startup timer is still running, always send heartbeat
|
||||
if (startupTimerHandle != nullptr) {
|
||||
if (timerHandle != nullptr)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// If in heartbeat mode after startup, continue sending
|
||||
if (startupCommandReceived) {
|
||||
if (getStartupCommandReceived())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Otherwise, only send if no WiFi credentials configured
|
||||
const auto wifiConfigs = deviceConfig->getWifiConfigs();
|
||||
return wifiConfigs.empty();
|
||||
@@ -95,16 +111,16 @@ void HandleSerialManagerTask(void *pvParameters)
|
||||
while (true)
|
||||
{
|
||||
serialManager->try_receive();
|
||||
|
||||
|
||||
// Send heartbeat every 2 seconds, but only if no WiFi credentials are set
|
||||
TickType_t currentTime = xTaskGetTickCount();
|
||||
if ((currentTime - lastHeartbeat) >= heartbeatInterval) {
|
||||
if (serialManager->should_send_heartbeat()) {
|
||||
if ((currentTime - lastHeartbeat) >= heartbeatInterval)
|
||||
{
|
||||
if (serialManager->should_send_heartbeat())
|
||||
{
|
||||
serialManager->send_heartbeat();
|
||||
}
|
||||
lastHeartbeat = currentTime;
|
||||
}
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(50)); // Small delay to prevent busy waiting
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@ public:
|
||||
void try_receive();
|
||||
void send_heartbeat();
|
||||
bool should_send_heartbeat();
|
||||
void notify_startup_command_received();
|
||||
|
||||
private:
|
||||
std::shared_ptr<CommandManager> commandManager;
|
||||
|
||||
@@ -3,25 +3,29 @@ constexpr int UVC_MAX_FRAMESIZE_SIZE(75 * 1024);
|
||||
|
||||
static const char *UVC_STREAM_TAG = "[UVC DEVICE]";
|
||||
|
||||
extern "C" {
|
||||
extern "C"
|
||||
{
|
||||
static char serial_number_str[13];
|
||||
|
||||
const char *get_uvc_device_name() {
|
||||
const char *get_uvc_device_name()
|
||||
{
|
||||
return deviceConfig->getMDNSConfig().hostname.c_str();
|
||||
}
|
||||
|
||||
const char *get_serial_number(void) {
|
||||
if (serial_number_str[0] == '\0') {
|
||||
const char *get_serial_number(void)
|
||||
{
|
||||
if (serial_number_str[0] == '\0')
|
||||
{
|
||||
uint8_t mac_address[6];
|
||||
esp_err_t result = esp_efuse_mac_get_default(mac_address);
|
||||
if (result != ESP_OK) {
|
||||
if (result != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(UVC_STREAM_TAG, "Failed to get MAC address of the board, returning default serial number");
|
||||
return CONFIG_TUSB_SERIAL_NUM;
|
||||
}
|
||||
|
||||
sniprintf(serial_number_str, sizeof(serial_number_str), "%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
mac_address[0], mac_address[1], mac_address[2], mac_address[3], mac_address[4], mac_address[5]
|
||||
);
|
||||
mac_address[0], mac_address[1], mac_address[2], mac_address[3], mac_address[4], mac_address[5]);
|
||||
}
|
||||
return serial_number_str;
|
||||
}
|
||||
|
||||
@@ -1,32 +1,38 @@
|
||||
#include "WiFiScanner.hpp"
|
||||
#include <cstring>
|
||||
|
||||
static const char *TAG = "WiFiScanner";
|
||||
|
||||
WiFiScanner::WiFiScanner() {}
|
||||
|
||||
void WiFiScanner::scanResultCallback(void* arg, esp_event_base_t event_base,
|
||||
int32_t event_id, void* event_data) {
|
||||
auto* scanner = static_cast<WiFiScanner*>(arg);
|
||||
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_SCAN_DONE) {
|
||||
void WiFiScanner::scanResultCallback(void *arg, esp_event_base_t event_base,
|
||||
int32_t event_id, void *event_data)
|
||||
{
|
||||
auto *scanner = static_cast<WiFiScanner *>(arg);
|
||||
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_SCAN_DONE)
|
||||
{
|
||||
uint16_t ap_count = 0;
|
||||
esp_wifi_scan_get_ap_num(&ap_count);
|
||||
|
||||
if (ap_count == 0) {
|
||||
|
||||
if (ap_count == 0)
|
||||
{
|
||||
ESP_LOGI(TAG, "No access points found");
|
||||
return;
|
||||
}
|
||||
|
||||
wifi_ap_record_t* ap_records = new wifi_ap_record_t[ap_count];
|
||||
wifi_ap_record_t *ap_records = new wifi_ap_record_t[ap_count];
|
||||
ESP_ERROR_CHECK(esp_wifi_scan_get_ap_records(&ap_count, ap_records));
|
||||
|
||||
scanner->networks.clear();
|
||||
for (uint16_t i = 0; i < ap_count; i++) {
|
||||
for (uint16_t i = 0; i < ap_count; i++)
|
||||
{
|
||||
WiFiNetwork network;
|
||||
network.ssid = std::string(reinterpret_cast<char*>(ap_records[i].ssid));
|
||||
network.ssid = std::string(reinterpret_cast<char *>(ap_records[i].ssid));
|
||||
network.channel = ap_records[i].primary;
|
||||
network.rssi = ap_records[i].rssi;
|
||||
memcpy(network.mac, ap_records[i].bssid, 6);
|
||||
network.auth_mode = ap_records[i].authmode;
|
||||
|
||||
|
||||
scanner->networks.push_back(network);
|
||||
}
|
||||
|
||||
@@ -35,81 +41,88 @@ void WiFiScanner::scanResultCallback(void* arg, esp_event_base_t event_base,
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<WiFiNetwork> WiFiScanner::scanNetworks() {
|
||||
// todo this is garbage
|
||||
std::vector<WiFiNetwork> WiFiScanner::scanNetworks()
|
||||
{
|
||||
std::vector<WiFiNetwork> scan_results;
|
||||
|
||||
|
||||
// Check if WiFi is initialized
|
||||
wifi_mode_t mode;
|
||||
esp_err_t err = esp_wifi_get_mode(&mode);
|
||||
if (err == ESP_ERR_WIFI_NOT_INIT) {
|
||||
if (err == ESP_ERR_WIFI_NOT_INIT)
|
||||
{
|
||||
ESP_LOGE(TAG, "WiFi not initialized");
|
||||
return scan_results;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Give WiFi more time to be ready
|
||||
vTaskDelay(pdMS_TO_TICKS(500));
|
||||
|
||||
|
||||
// Stop any ongoing scan
|
||||
esp_wifi_scan_stop();
|
||||
|
||||
|
||||
// Try sequential channel scanning as a workaround
|
||||
bool try_sequential_scan = true; // Enable sequential scan
|
||||
|
||||
if (!try_sequential_scan) {
|
||||
bool try_sequential_scan = true; // Enable sequential scan
|
||||
|
||||
if (!try_sequential_scan)
|
||||
{
|
||||
// Normal all-channel scan
|
||||
wifi_scan_config_t scan_config = {
|
||||
.ssid = nullptr,
|
||||
.bssid = nullptr,
|
||||
.channel = 0, // 0 means scan all channels
|
||||
.channel = 0, // 0 means scan all channels
|
||||
.show_hidden = true,
|
||||
.scan_type = WIFI_SCAN_TYPE_ACTIVE, // Active scan
|
||||
.scan_type = WIFI_SCAN_TYPE_ACTIVE, // Active scan
|
||||
.scan_time = {
|
||||
.active = {
|
||||
.min = 120, // Min per channel
|
||||
.max = 300 // Max per channel
|
||||
.min = 120, // Min per channel
|
||||
.max = 300 // Max per channel
|
||||
},
|
||||
.passive = 360
|
||||
},
|
||||
.home_chan_dwell_time = 0, // 0 for default
|
||||
.channel_bitmap = 0 // 0 for all channels
|
||||
.passive = 360},
|
||||
.home_chan_dwell_time = 0, // 0 for default
|
||||
.channel_bitmap = 0 // 0 for all channels
|
||||
};
|
||||
|
||||
err = esp_wifi_scan_start(&scan_config, false);
|
||||
if (err != ESP_OK) {
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "Failed to start scan: %s", esp_err_to_name(err));
|
||||
return scan_results;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
// Sequential channel scan - scan each channel individually
|
||||
std::vector<wifi_ap_record_t> all_records;
|
||||
|
||||
for (uint8_t ch = 1; ch <= 13; ch++) {
|
||||
|
||||
for (uint8_t ch = 1; ch <= 13; ch++)
|
||||
{
|
||||
wifi_scan_config_t scan_config = {
|
||||
.ssid = nullptr,
|
||||
.bssid = nullptr,
|
||||
.channel = ch, // Specific channel
|
||||
.channel = ch,
|
||||
.show_hidden = true,
|
||||
.scan_type = WIFI_SCAN_TYPE_ACTIVE,
|
||||
.scan_time = {
|
||||
.active = {
|
||||
.min = 100,
|
||||
.max = 200
|
||||
},
|
||||
.passive = 300
|
||||
},
|
||||
.max = 200},
|
||||
.passive = 300},
|
||||
.home_chan_dwell_time = 0,
|
||||
.channel_bitmap = 0
|
||||
};
|
||||
|
||||
.channel_bitmap = 0};
|
||||
|
||||
err = esp_wifi_scan_start(&scan_config, true); // Blocking scan
|
||||
if (err == ESP_OK) {
|
||||
if (err == ESP_OK)
|
||||
{
|
||||
uint16_t ch_count = 0;
|
||||
esp_wifi_scan_get_ap_num(&ch_count);
|
||||
if (ch_count > 0) {
|
||||
wifi_ap_record_t* ch_records = new wifi_ap_record_t[ch_count];
|
||||
if (esp_wifi_scan_get_ap_records(&ch_count, ch_records) == ESP_OK) {
|
||||
for (uint16_t i = 0; i < ch_count; i++) {
|
||||
if (ch_count > 0)
|
||||
{
|
||||
wifi_ap_record_t *ch_records = new wifi_ap_record_t[ch_count];
|
||||
if (esp_wifi_scan_get_ap_records(&ch_count, ch_records) == ESP_OK)
|
||||
{
|
||||
for (uint16_t i = 0; i < ch_count; i++)
|
||||
{
|
||||
all_records.push_back(ch_records[i]);
|
||||
}
|
||||
}
|
||||
@@ -118,59 +131,66 @@ std::vector<WiFiNetwork> WiFiScanner::scanNetworks() {
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(50));
|
||||
}
|
||||
|
||||
|
||||
// Process all collected records
|
||||
for (const auto& record : all_records) {
|
||||
for (const auto &record : all_records)
|
||||
{
|
||||
WiFiNetwork network;
|
||||
network.ssid = std::string(reinterpret_cast<const char*>(record.ssid));
|
||||
network.ssid = std::string(reinterpret_cast<const char *>(record.ssid));
|
||||
network.channel = record.primary;
|
||||
network.rssi = record.rssi;
|
||||
memcpy(network.mac, record.bssid, 6);
|
||||
network.auth_mode = record.authmode;
|
||||
scan_results.push_back(network);
|
||||
}
|
||||
|
||||
|
||||
// Skip the normal result processing
|
||||
return scan_results;
|
||||
}
|
||||
|
||||
|
||||
// Wait for scan completion with timeout
|
||||
int timeout_ms = 15000; // 15 second timeout
|
||||
int elapsed_ms = 0;
|
||||
|
||||
while (elapsed_ms < timeout_ms) {
|
||||
|
||||
while (elapsed_ms < timeout_ms)
|
||||
{
|
||||
uint16_t temp_count = 0;
|
||||
esp_err_t count_err = esp_wifi_scan_get_ap_num(&temp_count);
|
||||
|
||||
if (count_err == ESP_OK) {
|
||||
|
||||
if (count_err == ESP_OK)
|
||||
{
|
||||
// Wait a bit longer after finding networks to ensure scan is complete
|
||||
if (temp_count > 0 && elapsed_ms > 5000) {
|
||||
if (temp_count > 0 && elapsed_ms > 5000)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(200));
|
||||
elapsed_ms += 200;
|
||||
}
|
||||
|
||||
if (elapsed_ms >= timeout_ms) {
|
||||
|
||||
if (elapsed_ms >= timeout_ms)
|
||||
{
|
||||
ESP_LOGE(TAG, "Scan timeout after %d ms", timeout_ms);
|
||||
esp_wifi_scan_stop();
|
||||
return scan_results;
|
||||
}
|
||||
|
||||
|
||||
// Get scan results
|
||||
uint16_t ap_count = 0;
|
||||
esp_wifi_scan_get_ap_num(&ap_count);
|
||||
|
||||
if (ap_count == 0) {
|
||||
|
||||
if (ap_count == 0)
|
||||
{
|
||||
ESP_LOGI(TAG, "No access points found");
|
||||
return scan_results;
|
||||
}
|
||||
|
||||
wifi_ap_record_t* ap_records = new wifi_ap_record_t[ap_count];
|
||||
wifi_ap_record_t *ap_records = new wifi_ap_record_t[ap_count];
|
||||
err = esp_wifi_scan_get_ap_records(&ap_count, ap_records);
|
||||
if (err != ESP_OK) {
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "Failed to get scan records: %s", esp_err_to_name(err));
|
||||
delete[] ap_records;
|
||||
return scan_results;
|
||||
@@ -178,28 +198,26 @@ std::vector<WiFiNetwork> WiFiScanner::scanNetworks() {
|
||||
|
||||
// Build the results vector and track channels found
|
||||
bool channels_found[15] = {false}; // Track channels 0-14
|
||||
|
||||
for (uint16_t i = 0; i < ap_count; i++) {
|
||||
|
||||
for (uint16_t i = 0; i < ap_count; i++)
|
||||
{
|
||||
WiFiNetwork network;
|
||||
network.ssid = std::string(reinterpret_cast<char*>(ap_records[i].ssid));
|
||||
network.ssid = std::string(reinterpret_cast<char *>(ap_records[i].ssid));
|
||||
network.channel = ap_records[i].primary;
|
||||
network.rssi = ap_records[i].rssi;
|
||||
memcpy(network.mac, ap_records[i].bssid, 6);
|
||||
network.auth_mode = ap_records[i].authmode;
|
||||
|
||||
if (network.channel <= 14) {
|
||||
|
||||
if (network.channel <= 14)
|
||||
{
|
||||
channels_found[network.channel] = true;
|
||||
}
|
||||
|
||||
|
||||
scan_results.push_back(network);
|
||||
}
|
||||
|
||||
|
||||
delete[] ap_records;
|
||||
ESP_LOGI(TAG, "Found %d access points", ap_count);
|
||||
|
||||
// Also update the member variable for compatibility
|
||||
networks = scan_results;
|
||||
|
||||
|
||||
return scan_results;
|
||||
}
|
||||
@@ -7,7 +7,8 @@
|
||||
#include "esp_wifi.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
struct WiFiNetwork {
|
||||
struct WiFiNetwork
|
||||
{
|
||||
std::string ssid;
|
||||
uint8_t channel;
|
||||
int8_t rssi;
|
||||
@@ -15,14 +16,14 @@ struct WiFiNetwork {
|
||||
wifi_auth_mode_t auth_mode;
|
||||
};
|
||||
|
||||
class WiFiScanner {
|
||||
class WiFiScanner
|
||||
{
|
||||
public:
|
||||
WiFiScanner();
|
||||
std::vector<WiFiNetwork> scanNetworks();
|
||||
static void scanResultCallback(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data);
|
||||
static void scanResultCallback(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data);
|
||||
|
||||
private:
|
||||
static constexpr char const* TAG = "WiFiScanner";
|
||||
std::vector<WiFiNetwork> networks;
|
||||
};
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
static auto WIFI_MANAGER_TAG = "[WIFI_MANAGER]";
|
||||
|
||||
// Define the global variables declared as extern in the header
|
||||
int s_retry_num = 0;
|
||||
EventGroupHandle_t s_wifi_event_group;
|
||||
|
||||
@@ -19,9 +18,9 @@ void WiFiManagerHelpers::event_handler(void *arg, esp_event_base_t event_base,
|
||||
}
|
||||
else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED)
|
||||
{
|
||||
wifi_event_sta_disconnected_t* disconnected = (wifi_event_sta_disconnected_t*) event_data;
|
||||
const auto *disconnected = static_cast<wifi_event_sta_disconnected_t *>(event_data);
|
||||
ESP_LOGI(WIFI_MANAGER_TAG, "Disconnect reason: %d", disconnected->reason);
|
||||
|
||||
|
||||
if (s_retry_num < EXAMPLE_ESP_MAXIMUM_RETRY)
|
||||
{
|
||||
esp_wifi_connect();
|
||||
@@ -51,55 +50,52 @@ void WiFiManager::SetCredentials(const char *ssid, const char *password)
|
||||
{
|
||||
// Clear the config first
|
||||
memset(&_wifi_cfg, 0, sizeof(_wifi_cfg));
|
||||
|
||||
|
||||
// Copy SSID with null termination
|
||||
size_t ssid_len = std::min(strlen(ssid), sizeof(_wifi_cfg.sta.ssid) - 1);
|
||||
memcpy(_wifi_cfg.sta.ssid, ssid, ssid_len);
|
||||
_wifi_cfg.sta.ssid[ssid_len] = '\0';
|
||||
|
||||
|
||||
// Copy password with null termination
|
||||
size_t pass_len = std::min(strlen(password), sizeof(_wifi_cfg.sta.password) - 1);
|
||||
memcpy(_wifi_cfg.sta.password, password, pass_len);
|
||||
_wifi_cfg.sta.password[pass_len] = '\0';
|
||||
|
||||
|
||||
// Set other required fields
|
||||
// Use open auth if no password, otherwise allow any WPA variant
|
||||
if (strlen(password) == 0) {
|
||||
if (strlen(password) == 0)
|
||||
{
|
||||
_wifi_cfg.sta.threshold.authmode = WIFI_AUTH_OPEN;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
// IMPORTANT: Set threshold to WEP to accept ANY security mode >= WEP
|
||||
// This allows WPA, WPA2, WPA3, etc. The driver will negotiate the highest common mode
|
||||
_wifi_cfg.sta.threshold.authmode = WIFI_AUTH_WEP;
|
||||
}
|
||||
|
||||
|
||||
// CRITICAL: Disable PMF completely - this often causes handshake timeouts
|
||||
_wifi_cfg.sta.pmf_cfg.capable = false;
|
||||
_wifi_cfg.sta.pmf_cfg.required = false;
|
||||
|
||||
|
||||
// IMPORTANT: Set scan method to ALL channels
|
||||
_wifi_cfg.sta.scan_method = WIFI_ALL_CHANNEL_SCAN;
|
||||
_wifi_cfg.sta.bssid_set = 0; // Don't use specific BSSID
|
||||
_wifi_cfg.sta.channel = 0; // Scan all channels
|
||||
|
||||
_wifi_cfg.sta.bssid_set = 0; // Don't use specific BSSID
|
||||
_wifi_cfg.sta.channel = 0; // Scan all channels
|
||||
|
||||
// Additional settings that might help with compatibility
|
||||
_wifi_cfg.sta.listen_interval = 0; // Default listen interval
|
||||
_wifi_cfg.sta.sort_method = WIFI_CONNECT_AP_BY_SIGNAL; // Connect to strongest signal
|
||||
|
||||
_wifi_cfg.sta.listen_interval = 0; // Default listen interval
|
||||
_wifi_cfg.sta.sort_method = WIFI_CONNECT_AP_BY_SIGNAL; // Connect to strongest signal
|
||||
|
||||
// IMPORTANT: For WPA/WPA2 Personal networks
|
||||
_wifi_cfg.sta.threshold.rssi = -127; // Accept any signal strength
|
||||
_wifi_cfg.sta.sae_pwe_h2e = WPA3_SAE_PWE_UNSPECIFIED; // Let driver decide SAE mode
|
||||
|
||||
_wifi_cfg.sta.threshold.rssi = -127; // Accept any signal strength
|
||||
_wifi_cfg.sta.sae_pwe_h2e = WPA3_SAE_PWE_UNSPECIFIED; // Let driver decide SAE mode
|
||||
|
||||
// Log what we're trying to connect to with detailed debugging
|
||||
ESP_LOGI(WIFI_MANAGER_TAG, "Setting credentials for SSID: '%s' (length: %d)", ssid, (int)strlen(ssid));
|
||||
ESP_LOGI(WIFI_MANAGER_TAG, "Password: '%s' (length: %d)", password, (int)strlen(password));
|
||||
ESP_LOGI(WIFI_MANAGER_TAG, "Auth mode: %d, PMF capable: %d",
|
||||
ESP_LOGI(WIFI_MANAGER_TAG, "Auth mode: %d, PMF capable: %d",
|
||||
_wifi_cfg.sta.threshold.authmode, _wifi_cfg.sta.pmf_cfg.capable);
|
||||
|
||||
// Print hex dump of SSID to catch any hidden characters
|
||||
ESP_LOG_BUFFER_HEX_LEVEL(WIFI_MANAGER_TAG, _wifi_cfg.sta.ssid, strlen((char*)_wifi_cfg.sta.ssid), ESP_LOG_INFO);
|
||||
|
||||
// Print hex dump of password to catch any hidden characters
|
||||
ESP_LOG_BUFFER_HEX_LEVEL(WIFI_MANAGER_TAG, _wifi_cfg.sta.password, strlen((char*)_wifi_cfg.sta.password), ESP_LOG_INFO);
|
||||
}
|
||||
|
||||
void WiFiManager::ConnectWithHardcodedCredentials()
|
||||
@@ -164,11 +160,11 @@ void WiFiManager::ConnectWithStoredCredentials()
|
||||
// Stop WiFi once before the loop
|
||||
esp_wifi_stop();
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
|
||||
|
||||
// Ensure we're in STA mode
|
||||
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
|
||||
|
||||
for (const auto& network : networks)
|
||||
for (const auto &network : networks)
|
||||
{
|
||||
// Reset retry counter for each network attempt
|
||||
s_retry_num = 0;
|
||||
@@ -177,19 +173,14 @@ void WiFiManager::ConnectWithStoredCredentials()
|
||||
|
||||
// Update config without stopping WiFi again
|
||||
ESP_LOGI(WIFI_MANAGER_TAG, "Attempting to connect to SSID: '%s'", network.ssid.c_str());
|
||||
|
||||
// Double-check the actual config being sent to WiFi driver
|
||||
ESP_LOGI(WIFI_MANAGER_TAG, "Final SSID in config: '%s' (len: %d)",
|
||||
(char*)_wifi_cfg.sta.ssid, (int)strlen((char*)_wifi_cfg.sta.ssid));
|
||||
ESP_LOGI(WIFI_MANAGER_TAG, "Final password in config: '%s' (len: %d)",
|
||||
(char*)_wifi_cfg.sta.password, (int)strlen((char*)_wifi_cfg.sta.password));
|
||||
|
||||
|
||||
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &_wifi_cfg));
|
||||
xQueueSend(this->eventQueue, &event, 10);
|
||||
|
||||
// Start WiFi if not already started
|
||||
esp_err_t start_err = esp_wifi_start();
|
||||
if (start_err != ESP_OK && start_err != ESP_ERR_WIFI_STATE) {
|
||||
if (start_err != ESP_OK && start_err != ESP_ERR_WIFI_STATE)
|
||||
{
|
||||
ESP_LOGE(WIFI_MANAGER_TAG, "Failed to start WiFi: %s", esp_err_to_name(start_err));
|
||||
continue;
|
||||
}
|
||||
@@ -214,7 +205,7 @@ void WiFiManager::ConnectWithStoredCredentials()
|
||||
}
|
||||
ESP_LOGE(WIFI_MANAGER_TAG, "Failed to connect to SSID:%s, trying next stored network",
|
||||
network.ssid.c_str());
|
||||
|
||||
|
||||
// Disconnect before trying next network
|
||||
esp_wifi_disconnect();
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
@@ -249,107 +240,117 @@ void WiFiManager::SetupAccessPoint()
|
||||
ESP_LOGI(WIFI_MANAGER_TAG, "AP started.");
|
||||
}
|
||||
|
||||
std::vector<WiFiNetwork> WiFiManager::ScanNetworks() {
|
||||
wifi_mode_t current_mode;
|
||||
esp_err_t err = esp_wifi_get_mode(¤t_mode);
|
||||
|
||||
if (err == ESP_ERR_WIFI_NOT_INIT) {
|
||||
ESP_LOGE(WIFI_MANAGER_TAG, "WiFi not initialized for scanning");
|
||||
return std::vector<WiFiNetwork>();
|
||||
std::vector<WiFiNetwork> WiFiManager::ScanNetworks()
|
||||
{
|
||||
wifi_mode_t current_mode;
|
||||
esp_err_t err = esp_wifi_get_mode(¤t_mode);
|
||||
|
||||
if (err == ESP_ERR_WIFI_NOT_INIT)
|
||||
{
|
||||
ESP_LOGE(WIFI_MANAGER_TAG, "WiFi not initialized for scanning");
|
||||
return std::vector<WiFiNetwork>();
|
||||
}
|
||||
|
||||
// If we're in AP-only mode, we need STA interface for scanning
|
||||
if (current_mode == WIFI_MODE_AP)
|
||||
{
|
||||
ESP_LOGI(WIFI_MANAGER_TAG, "AP mode detected, checking for STA interface");
|
||||
|
||||
// Check if STA netif already exists
|
||||
esp_netif_t *sta_netif = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF");
|
||||
bool sta_netif_exists = (sta_netif != nullptr);
|
||||
|
||||
if (!sta_netif_exists)
|
||||
{
|
||||
ESP_LOGI(WIFI_MANAGER_TAG, "Creating STA interface for scanning");
|
||||
sta_netif = esp_netif_create_default_wifi_sta();
|
||||
}
|
||||
|
||||
// If we're in AP-only mode, we need STA interface for scanning
|
||||
if (current_mode == WIFI_MODE_AP) {
|
||||
ESP_LOGI(WIFI_MANAGER_TAG, "AP mode detected, checking for STA interface");
|
||||
|
||||
// Check if STA netif already exists
|
||||
esp_netif_t* sta_netif = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF");
|
||||
bool sta_netif_exists = (sta_netif != nullptr);
|
||||
|
||||
if (!sta_netif_exists) {
|
||||
ESP_LOGI(WIFI_MANAGER_TAG, "Creating STA interface for scanning");
|
||||
sta_netif = esp_netif_create_default_wifi_sta();
|
||||
}
|
||||
|
||||
ESP_LOGI(WIFI_MANAGER_TAG, "Switching to APSTA mode for scanning");
|
||||
err = esp_wifi_set_mode(WIFI_MODE_APSTA);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(WIFI_MANAGER_TAG, "Failed to set APSTA mode: %s", esp_err_to_name(err));
|
||||
if (!sta_netif_exists && sta_netif) {
|
||||
esp_netif_destroy(sta_netif);
|
||||
}
|
||||
return std::vector<WiFiNetwork>();
|
||||
}
|
||||
|
||||
// Configure STA with empty config to prevent auto-connect
|
||||
wifi_config_t empty_config = {};
|
||||
esp_wifi_set_config(WIFI_IF_STA, &empty_config);
|
||||
|
||||
// Ensure STA is disconnected and not trying to connect
|
||||
esp_wifi_disconnect();
|
||||
vTaskDelay(pdMS_TO_TICKS(500));
|
||||
|
||||
// Longer delay for mode to stabilize and enable all channels
|
||||
vTaskDelay(pdMS_TO_TICKS(1500));
|
||||
|
||||
// Perform scan
|
||||
auto networks = wifiScanner->scanNetworks();
|
||||
|
||||
// Restore AP-only mode
|
||||
ESP_LOGI(WIFI_MANAGER_TAG, "Restoring AP-only mode");
|
||||
esp_wifi_set_mode(WIFI_MODE_AP);
|
||||
|
||||
// Clean up STA interface if we created it
|
||||
if (!sta_netif_exists && sta_netif) {
|
||||
esp_netif_destroy(sta_netif);
|
||||
}
|
||||
|
||||
return networks;
|
||||
|
||||
ESP_LOGI(WIFI_MANAGER_TAG, "Switching to APSTA mode for scanning");
|
||||
err = esp_wifi_set_mode(WIFI_MODE_APSTA);
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(WIFI_MANAGER_TAG, "Failed to set APSTA mode: %s", esp_err_to_name(err));
|
||||
if (!sta_netif_exists && sta_netif)
|
||||
{
|
||||
esp_netif_destroy(sta_netif);
|
||||
}
|
||||
return std::vector<WiFiNetwork>();
|
||||
}
|
||||
|
||||
// If already in STA or APSTA mode, scan directly
|
||||
return wifiScanner->scanNetworks();
|
||||
|
||||
// Configure STA with empty config to prevent auto-connect
|
||||
wifi_config_t empty_config = {};
|
||||
esp_wifi_set_config(WIFI_IF_STA, &empty_config);
|
||||
|
||||
// Ensure STA is disconnected and not trying to connect
|
||||
esp_wifi_disconnect();
|
||||
// Longer delay for mode to stabilize and enable all channels
|
||||
vTaskDelay(pdMS_TO_TICKS(2000));
|
||||
|
||||
// Perform scan
|
||||
auto networks = wifiScanner->scanNetworks();
|
||||
|
||||
// Restore AP-only mode
|
||||
ESP_LOGI(WIFI_MANAGER_TAG, "Restoring AP-only mode");
|
||||
esp_wifi_set_mode(WIFI_MODE_AP);
|
||||
|
||||
// Clean up STA interface if we created it
|
||||
if (!sta_netif_exists && sta_netif)
|
||||
{
|
||||
esp_netif_destroy(sta_netif);
|
||||
}
|
||||
|
||||
return networks;
|
||||
}
|
||||
|
||||
// If already in STA or APSTA mode, scan directly
|
||||
return wifiScanner->scanNetworks();
|
||||
}
|
||||
|
||||
WiFiState_e WiFiManager::GetCurrentWiFiState() {
|
||||
return this->stateManager->GetWifiState();
|
||||
WiFiState_e WiFiManager::GetCurrentWiFiState()
|
||||
{
|
||||
return this->stateManager->GetWifiState();
|
||||
}
|
||||
|
||||
void WiFiManager::TryConnectToStoredNetworks() {
|
||||
ESP_LOGI(WIFI_MANAGER_TAG, "Manual WiFi connection attempt requested");
|
||||
|
||||
// Check current WiFi mode
|
||||
wifi_mode_t current_mode;
|
||||
esp_err_t err = esp_wifi_get_mode(¤t_mode);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(WIFI_MANAGER_TAG, "Failed to get WiFi mode: %s", esp_err_to_name(err));
|
||||
return;
|
||||
void WiFiManager::TryConnectToStoredNetworks()
|
||||
{
|
||||
ESP_LOGI(WIFI_MANAGER_TAG, "Manual WiFi connection attempt requested");
|
||||
|
||||
// Check current WiFi mode
|
||||
wifi_mode_t current_mode;
|
||||
esp_err_t err = esp_wifi_get_mode(¤t_mode);
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(WIFI_MANAGER_TAG, "Failed to get WiFi mode: %s", esp_err_to_name(err));
|
||||
return;
|
||||
}
|
||||
|
||||
// If in AP mode, we need to properly transition to STA mode
|
||||
if (current_mode == WIFI_MODE_AP || current_mode == WIFI_MODE_APSTA)
|
||||
{
|
||||
ESP_LOGI(WIFI_MANAGER_TAG, "Currently in AP mode, transitioning to STA mode");
|
||||
|
||||
// Stop WiFi first
|
||||
esp_wifi_stop();
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
|
||||
// Check if STA interface exists, create if needed
|
||||
esp_netif_t *sta_netif = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF");
|
||||
if (sta_netif == nullptr)
|
||||
{
|
||||
ESP_LOGI(WIFI_MANAGER_TAG, "Creating STA interface");
|
||||
sta_netif = esp_netif_create_default_wifi_sta();
|
||||
}
|
||||
|
||||
// If in AP mode, we need to properly transition to STA mode
|
||||
if (current_mode == WIFI_MODE_AP || current_mode == WIFI_MODE_APSTA) {
|
||||
ESP_LOGI(WIFI_MANAGER_TAG, "Currently in AP mode, transitioning to STA mode");
|
||||
|
||||
// Stop WiFi first
|
||||
esp_wifi_stop();
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
|
||||
// Check if STA interface exists, create if needed
|
||||
esp_netif_t* sta_netif = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF");
|
||||
if (sta_netif == nullptr) {
|
||||
ESP_LOGI(WIFI_MANAGER_TAG, "Creating STA interface");
|
||||
sta_netif = esp_netif_create_default_wifi_sta();
|
||||
}
|
||||
|
||||
// Set to STA mode
|
||||
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
}
|
||||
|
||||
// Reset retry counter and clear all event bits
|
||||
s_retry_num = 0;
|
||||
xEventGroupClearBits(s_wifi_event_group, WIFI_FAIL_BIT | WIFI_CONNECTED_BIT);
|
||||
this->ConnectWithStoredCredentials();
|
||||
|
||||
// Set to STA mode
|
||||
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
}
|
||||
|
||||
// Reset retry counter and clear all event bits
|
||||
s_retry_num = 0;
|
||||
xEventGroupClearBits(s_wifi_event_group, WIFI_FAIL_BIT | WIFI_CONNECTED_BIT);
|
||||
this->ConnectWithStoredCredentials();
|
||||
}
|
||||
|
||||
void WiFiManager::Begin()
|
||||
@@ -363,18 +364,6 @@ void WiFiManager::Begin()
|
||||
wifi_init_config_t esp_wifi_init_config = WIFI_INIT_CONFIG_DEFAULT();
|
||||
ESP_ERROR_CHECK(esp_wifi_init(&esp_wifi_init_config));
|
||||
|
||||
// Set WiFi country to enable all channels (1-14)
|
||||
wifi_country_t country_config = {
|
||||
.cc = "JP", // Japan allows channels 1-14 (most permissive)
|
||||
.schan = 1,
|
||||
.nchan = 14,
|
||||
.max_tx_power = 20,
|
||||
.policy = WIFI_COUNTRY_POLICY_AUTO
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_wifi_set_country(&country_config));
|
||||
|
||||
|
||||
|
||||
ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
|
||||
ESP_EVENT_ANY_ID,
|
||||
&WiFiManagerHelpers::event_handler,
|
||||
@@ -387,8 +376,8 @@ void WiFiManager::Begin()
|
||||
&instance_got_ip));
|
||||
|
||||
_wifi_cfg = {};
|
||||
_wifi_cfg.sta.threshold.authmode = WIFI_AUTH_OPEN; // Start with open, will be set properly by SetCredentials
|
||||
_wifi_cfg.sta.pmf_cfg.capable = false; // Disable PMF by default
|
||||
_wifi_cfg.sta.threshold.authmode = WIFI_AUTH_OPEN; // Start with open, will be set properly by SetCredentials
|
||||
_wifi_cfg.sta.pmf_cfg.capable = false; // Disable PMF by default
|
||||
_wifi_cfg.sta.pmf_cfg.required = false;
|
||||
|
||||
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
|
||||
|
||||
@@ -19,9 +19,6 @@
|
||||
#define WIFI_CONNECTED_BIT BIT0
|
||||
#define WIFI_FAIL_BIT BIT1
|
||||
|
||||
extern int s_retry_num;
|
||||
extern EventGroupHandle_t s_wifi_event_group;
|
||||
|
||||
namespace WiFiManagerHelpers
|
||||
{
|
||||
void event_handler(void *arg, esp_event_base_t event_base,
|
||||
|
||||
@@ -30,10 +30,8 @@
|
||||
#define CONFIG_LED_C_PIN_GPIO (gpio_num_t) CONFIG_LED_C_PIN
|
||||
|
||||
esp_timer_handle_t timerHandle;
|
||||
esp_timer_handle_t startupTimerHandle;
|
||||
QueueHandle_t eventQueue = xQueueCreate(10, sizeof(SystemEvent));
|
||||
QueueHandle_t ledStateQueue = xQueueCreate(10, sizeof(uint32_t));
|
||||
bool startupCommandReceived = false;
|
||||
|
||||
auto *stateManager = new StateManager(eventQueue, ledStateQueue);
|
||||
auto dependencyRegistry = std::make_shared<DependencyRegistry>();
|
||||
@@ -99,22 +97,16 @@ void start_video_streaming(void *arg)
|
||||
{
|
||||
#ifdef CONFIG_WIRED_MODE
|
||||
ESP_LOGI("[MAIN]", "Starting UVC streaming mode.");
|
||||
// Initialize UVC if not already done
|
||||
static bool uvcInitialized = false;
|
||||
if (!uvcInitialized)
|
||||
ESP_LOGI("[MAIN]", "Initializing UVC hardware...");
|
||||
esp_err_t ret = uvcStream.setup();
|
||||
if (ret != ESP_OK)
|
||||
{
|
||||
ESP_LOGI("[MAIN]", "Initializing UVC hardware...");
|
||||
esp_err_t ret = uvcStream.setup();
|
||||
if (ret != ESP_OK)
|
||||
{
|
||||
ESP_LOGE("[MAIN]", "Failed to initialize UVC: %s", esp_err_to_name(ret));
|
||||
return;
|
||||
}
|
||||
uvcInitialized = true;
|
||||
ESP_LOGE("[MAIN]", "Failed to initialize UVC: %s", esp_err_to_name(ret));
|
||||
return;
|
||||
}
|
||||
uvcStream.start();
|
||||
#else
|
||||
ESP_LOGE("[MAIN]", "UVC mode selected but CONFIG_WIRED_MODE not enabled in build!");
|
||||
ESP_LOGE("[MAIN]", "UVC mode selected but the board likely does not support it.");
|
||||
ESP_LOGI("[MAIN]", "Falling back to WiFi mode if credentials available");
|
||||
deviceMode = StreamingMode::WIFI;
|
||||
#endif
|
||||
@@ -159,10 +151,10 @@ void activate_streaming(TaskHandle_t serialTaskHandle = nullptr)
|
||||
void startup_timer_callback(void *arg)
|
||||
{
|
||||
ESP_LOGI("[MAIN]", "Startup timer fired, startupCommandReceived=%s, startupPaused=%s",
|
||||
startupCommandReceived ? "true" : "false",
|
||||
startupPaused ? "true" : "false");
|
||||
getStartupCommandReceived() ? "true" : "false",
|
||||
getStartupPaused() ? "true" : "false");
|
||||
|
||||
if (!startupCommandReceived && !startupPaused)
|
||||
if (!getStartupCommandReceived() && !getStartupPaused())
|
||||
{
|
||||
ESP_LOGI("[MAIN]", "No command received during startup delay, proceeding with automatic mode startup");
|
||||
|
||||
@@ -216,7 +208,7 @@ void startup_timer_callback(void *arg)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (startupPaused)
|
||||
if (getStartupPaused())
|
||||
{
|
||||
ESP_LOGI("[MAIN]", "Startup paused, staying in heartbeat mode");
|
||||
}
|
||||
@@ -227,23 +219,8 @@ void startup_timer_callback(void *arg)
|
||||
}
|
||||
|
||||
// Delete the timer after it fires
|
||||
esp_timer_delete(startupTimerHandle);
|
||||
startupTimerHandle = nullptr;
|
||||
}
|
||||
|
||||
// Function to notify that a command was received during startup
|
||||
void notify_startup_command_received()
|
||||
{
|
||||
startupCommandReceived = true;
|
||||
|
||||
// Cancel the startup timer if it's still running
|
||||
if (startupTimerHandle != nullptr)
|
||||
{
|
||||
esp_timer_stop(startupTimerHandle);
|
||||
esp_timer_delete(startupTimerHandle);
|
||||
startupTimerHandle = nullptr;
|
||||
ESP_LOGI("[MAIN]", "Startup timer cancelled, staying in heartbeat mode");
|
||||
}
|
||||
esp_timer_delete(timerHandle);
|
||||
timerHandle = nullptr;
|
||||
}
|
||||
|
||||
extern "C" void app_main(void)
|
||||
@@ -337,9 +314,6 @@ extern "C" void app_main(void)
|
||||
restAPI->begin();
|
||||
cameraHandler->setupCamera();
|
||||
|
||||
// Don't initialize UVC here - wait for the timer to decide
|
||||
// UVC will be initialized when streaming actually starts
|
||||
|
||||
xTaskCreate(
|
||||
HandleRestAPIPollTask,
|
||||
"HandleRestAPIPollTask",
|
||||
@@ -354,23 +328,6 @@ extern "C" void app_main(void)
|
||||
ESP_LOGI("[MAIN]", "=====================================");
|
||||
ESP_LOGI("[MAIN]", "Device will wait 20 seconds for commands...");
|
||||
|
||||
// Get the stored device mode
|
||||
StreamingMode deviceMode = deviceConfig->getDeviceMode();
|
||||
ESP_LOGI("[MAIN]", "Stored device mode: %s (value: %d)",
|
||||
deviceMode == StreamingMode::UVC ? "UVC" : deviceMode == StreamingMode::WIFI ? "WiFi"
|
||||
: "Auto",
|
||||
(int)deviceMode);
|
||||
|
||||
// If WiFi credentials exist, attempt connection but stay in setup mode
|
||||
if (!deviceConfig->getWifiConfigs().empty())
|
||||
{
|
||||
ESP_LOGI("[MAIN]", "WiFi credentials found, attempting connection in background");
|
||||
// WiFi connection happens in wifiManager->Begin() above
|
||||
}
|
||||
|
||||
// Reset startup state
|
||||
startupCommandReceived = false;
|
||||
|
||||
// Create a one-shot timer for 20 seconds
|
||||
const esp_timer_create_args_t startup_timer_args = {
|
||||
.callback = &startup_timer_callback,
|
||||
@@ -379,13 +336,10 @@ extern "C" void app_main(void)
|
||||
.name = "startup_timer",
|
||||
.skip_unhandled_events = false};
|
||||
|
||||
ESP_ERROR_CHECK(esp_timer_create(&startup_timer_args, &startupTimerHandle));
|
||||
ESP_ERROR_CHECK(esp_timer_start_once(startupTimerHandle, 20000000)); // 20 seconds in microseconds
|
||||
ESP_ERROR_CHECK(esp_timer_create(&startup_timer_args, &timerHandle));
|
||||
ESP_ERROR_CHECK(esp_timer_start_once(timerHandle, 20000000)); // 20 seconds in microseconds
|
||||
|
||||
ESP_LOGI("[MAIN]", "Started 20-second startup timer");
|
||||
ESP_LOGI("[MAIN]", "Send any command within 20 seconds to enter heartbeat mode");
|
||||
|
||||
// Set global handles for component access
|
||||
setStreamingTimerHandle(&timerHandle);
|
||||
setSerialManagerHandle(&serialManagerHandle);
|
||||
}
|
||||
|
||||
@@ -6,11 +6,13 @@ This tool automatically discovers OpenIris devices via heartbeat,
|
||||
allows WiFi configuration, and monitors the device logs.
|
||||
"""
|
||||
|
||||
import re
|
||||
import json
|
||||
import time
|
||||
import threading
|
||||
import argparse
|
||||
import sys
|
||||
import string
|
||||
from typing import Dict, List, Optional, Tuple
|
||||
import serial
|
||||
import serial.tools.list_ports
|
||||
@@ -98,7 +100,6 @@ class OpenIrisDevice:
|
||||
cmd_obj["commands"][0]["data"] = params
|
||||
|
||||
cmd_json = json.dumps(cmd_obj) + '\n'
|
||||
|
||||
try:
|
||||
# Clear any pending data
|
||||
self.connection.reset_input_buffer()
|
||||
@@ -130,9 +131,6 @@ class OpenIrisDevice:
|
||||
print(f"📡 Raw: {repr(data)}")
|
||||
print(f"📝 Buffer: {repr(response_buffer[-200:])}")
|
||||
|
||||
# Clean buffer and look for JSON
|
||||
import re
|
||||
|
||||
# Remove ANSI escape sequences
|
||||
clean_buffer = re.sub(r'\x1b\[[0-9;]*m', '', response_buffer)
|
||||
clean_buffer = clean_buffer.replace('\r', '')
|
||||
@@ -303,6 +301,26 @@ class OpenIrisDevice:
|
||||
print("✅ WiFi credentials set successfully")
|
||||
return True
|
||||
|
||||
def set_mdns_name(self, name: str) -> bool:
|
||||
"""Configure the MDNS hostname"""
|
||||
|
||||
print(f"🔧 Setting MDNS name to '{name}'...")
|
||||
print(" The device should be accessible under")
|
||||
print(f"http://{name}.local/")
|
||||
print("\n Note, this will also modify the name of the UVC device")
|
||||
|
||||
params = {
|
||||
"hostname": name
|
||||
}
|
||||
|
||||
response = self.send_command("set_mdns", params)
|
||||
if "error" in response:
|
||||
print(f"❌ MDNS name setup failed: {response['error']}")
|
||||
return False
|
||||
|
||||
print("✅ MDNS name set successfully")
|
||||
return True
|
||||
|
||||
def get_wifi_status(self) -> Dict:
|
||||
"""Get current WiFi connection status"""
|
||||
response = self.send_command("get_wifi_status")
|
||||
@@ -561,8 +579,89 @@ class OpenIrisDiscovery:
|
||||
pass
|
||||
|
||||
|
||||
def display_networks(networks: List[WiFiNetwork]):
|
||||
def scan_networks(device: OpenIrisDevice, args = None):
|
||||
should_use_custom_timeout = input("Use custom scan timeout? (y/N): ").strip().lower()
|
||||
if should_use_custom_timeout == 'y':
|
||||
try:
|
||||
timeout = int(input("Enter timeout in seconds (5-120): "))
|
||||
if 5 <= timeout <= 120:
|
||||
device.scan_networks(timeout)
|
||||
else:
|
||||
print("❌ Timeout must be between 5 and 120 seconds")
|
||||
device.scan_networks(args.scan_timeout)
|
||||
except ValueError:
|
||||
print("❌ Invalid timeout, using default")
|
||||
device.scan_networks(args.scan_timeout)
|
||||
else:
|
||||
device.scan_networks(args.scan_timeout)
|
||||
|
||||
|
||||
def configure_wifi(device: OpenIrisDevice, args = None):
|
||||
if not device.networks:
|
||||
print("❌ No networks available. Please scan first.")
|
||||
return
|
||||
|
||||
display_networks(device)
|
||||
|
||||
while True:
|
||||
net_choice = input("\nEnter network number (or 'back'): ").strip()
|
||||
if net_choice.lower() == 'back':
|
||||
break
|
||||
|
||||
try:
|
||||
net_idx = int(net_choice) - 1
|
||||
except ValueError:
|
||||
print("❌ Please enter a number or 'back'")
|
||||
continue
|
||||
|
||||
sorted_networks = sorted(device.networks, key=lambda x: x.rssi, reverse=True)
|
||||
|
||||
if 0 <= net_idx < len(sorted_networks):
|
||||
selected_network = sorted_networks[net_idx]
|
||||
|
||||
print(f"\n🔐 Selected: {selected_network.ssid}")
|
||||
print(f"Security: {selected_network.security_type}")
|
||||
|
||||
if selected_network.auth_mode == 0: # Open network
|
||||
password = ""
|
||||
print("🔓 Open network - no password required")
|
||||
else:
|
||||
password = input("Enter WiFi password: ")
|
||||
|
||||
if device.set_wifi(selected_network.ssid, password):
|
||||
print("✅ WiFi configured successfully!")
|
||||
print("💡 Next steps:")
|
||||
print(" 4. Check WiFi status")
|
||||
print(" 5. Connect to WiFi (if needed)")
|
||||
print(" 6. Start streaming when connected")
|
||||
break
|
||||
else:
|
||||
print("❌ Invalid network number")
|
||||
|
||||
|
||||
def configure_mdns(device: OpenIrisDevice, args = None):
|
||||
print("💡 Please enter your preferred device name, your board will be accessible under http://<name>.local/")
|
||||
print("💡 Please avoid spaces and special characters")
|
||||
print(" To back out, enter `back`")
|
||||
print("\n Note, this will also modify the name of the UVC device")
|
||||
while True:
|
||||
name_choice = input("\nDevice name: ").strip()
|
||||
if any(space in name_choice for space in string.whitespace):
|
||||
print("❌ Please avoid spaces and special characters")
|
||||
else:
|
||||
break
|
||||
|
||||
if name_choice.lower() == "back":
|
||||
return
|
||||
|
||||
if device.set_mdns_name(name_choice):
|
||||
print("✅ MDNS configured successfully!")
|
||||
|
||||
|
||||
def display_networks(device: OpenIrisDevice, args = None):
|
||||
"""Display available WiFi networks in a formatted table"""
|
||||
networks = device.networks
|
||||
|
||||
if not networks:
|
||||
print("❌ No networks available")
|
||||
return
|
||||
@@ -596,6 +695,65 @@ def display_networks(networks: List[WiFiNetwork]):
|
||||
print()
|
||||
|
||||
|
||||
def check_wifi_status(device: OpenIrisDevice, args = None):
|
||||
status = device.get_wifi_status()
|
||||
if status:
|
||||
print(f"📶 WiFi Status: {status.get('status', 'unknown')}")
|
||||
print(f"📡 Networks configured: {status.get('networks_configured', 0)}")
|
||||
if status.get('ip_address'):
|
||||
print(f"🌐 IP Address: {status['ip_address']}")
|
||||
else:
|
||||
print("❌ Unable to get WiFi status")
|
||||
|
||||
|
||||
def attempt_wifi_connection(device: OpenIrisDevice, args = None):
|
||||
device.connect_wifi()
|
||||
print("🕰️ Wait a few seconds then check status (option 4)")
|
||||
|
||||
|
||||
def start_streaming(device: OpenIrisDevice, args = None):
|
||||
device.start_streaming()
|
||||
print("🚀 Streaming started! Use option 8 to monitor logs.")
|
||||
|
||||
|
||||
def switch_device_mode(device: OpenIrisDevice, args = None):
|
||||
current_mode = device.get_device_mode()
|
||||
print(f"\n📍 Current device mode: {current_mode}")
|
||||
print("\n🔄 Select new device mode:")
|
||||
print("1. WiFi - Stream over WiFi connection")
|
||||
print("2. UVC - Stream as USB webcam")
|
||||
print("3. Auto - Automatic mode selection")
|
||||
|
||||
mode_choice = input("\nSelect mode (1-3): ").strip()
|
||||
|
||||
if mode_choice == "1":
|
||||
device.switch_mode("wifi")
|
||||
elif mode_choice == "2":
|
||||
device.switch_mode("uvc")
|
||||
elif mode_choice == "3":
|
||||
device.switch_mode("auto")
|
||||
else:
|
||||
print("❌ Invalid mode selection")
|
||||
|
||||
|
||||
def monitor_logs(device: OpenIrisDevice, args = None):
|
||||
device.monitor_logs()
|
||||
|
||||
|
||||
COMMANDS_MAP = {
|
||||
"1": scan_networks,
|
||||
"2": display_networks,
|
||||
"3": configure_wifi,
|
||||
"4": configure_mdns,
|
||||
"5": configure_mdns,
|
||||
"6": check_wifi_status,
|
||||
"7": attempt_wifi_connection,
|
||||
"8": start_streaming,
|
||||
"9": switch_device_mode,
|
||||
"10": monitor_logs,
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="OpenIris Setup CLI Tool")
|
||||
parser.add_argument("--timeout", type=int, default=3,
|
||||
@@ -684,123 +842,25 @@ def main():
|
||||
print("1. 🔍 Scan for WiFi networks")
|
||||
print("2. 📡 Show available networks")
|
||||
print("3. 🔐 Configure WiFi")
|
||||
print("4. 📶 Check WiFi status")
|
||||
print("5. 🔗 Connect to WiFi")
|
||||
print("6. 🚀 Start streaming mode")
|
||||
print("7. 🔄 Switch device mode (WiFi/UVC/Auto)")
|
||||
print("8. 📋 Monitor logs")
|
||||
print("9. 🚪 Exit")
|
||||
print("4. 🌐 Configure MDNS")
|
||||
print("5. 💻 Configure UVC Name")
|
||||
print("6. 📶 Check WiFi status")
|
||||
print("7. 🔗 Connect to WiFi")
|
||||
print("8. 🚀 Start streaming mode")
|
||||
print("9. 🔄 Switch device mode (WiFi/UVC/Auto)")
|
||||
print("10. 📋 Monitor logs")
|
||||
print("exit. 🚪 Exit")
|
||||
choice = input("\nSelect option (1-10): ").strip()
|
||||
|
||||
choice = input("\nSelect option (1-9): ").strip()
|
||||
|
||||
if choice == "1":
|
||||
# Ask if user wants custom timeout
|
||||
custom = input("Use custom scan timeout? (y/N): ").strip().lower()
|
||||
if custom == 'y':
|
||||
try:
|
||||
timeout = int(input("Enter timeout in seconds (5-120): "))
|
||||
if 5 <= timeout <= 120:
|
||||
device.scan_networks(timeout)
|
||||
else:
|
||||
print("❌ Timeout must be between 5 and 120 seconds")
|
||||
device.scan_networks(args.scan_timeout)
|
||||
except ValueError:
|
||||
print("❌ Invalid timeout, using default")
|
||||
device.scan_networks(args.scan_timeout)
|
||||
else:
|
||||
device.scan_networks(args.scan_timeout)
|
||||
|
||||
elif choice == "2":
|
||||
display_networks(device.networks)
|
||||
|
||||
elif choice == "3":
|
||||
if not device.networks:
|
||||
print("❌ No networks available. Please scan first.")
|
||||
continue
|
||||
|
||||
display_networks(device.networks)
|
||||
|
||||
while True:
|
||||
try:
|
||||
net_choice = input("\nEnter network number (or 'back'): ").strip()
|
||||
if net_choice.lower() == 'back':
|
||||
break
|
||||
|
||||
net_idx = int(net_choice) - 1
|
||||
sorted_networks = sorted(device.networks, key=lambda x: x.rssi, reverse=True)
|
||||
|
||||
if 0 <= net_idx < len(sorted_networks):
|
||||
selected_network = sorted_networks[net_idx]
|
||||
|
||||
print(f"\n🔐 Selected: {selected_network.ssid}")
|
||||
print(f"Security: {selected_network.security_type}")
|
||||
|
||||
if selected_network.auth_mode == 0: # Open network
|
||||
password = ""
|
||||
print("🔓 Open network - no password required")
|
||||
else:
|
||||
password = input("Enter WiFi password: ")
|
||||
|
||||
if device.set_wifi(selected_network.ssid, password):
|
||||
print("✅ WiFi configured successfully!")
|
||||
print("💡 Next steps:")
|
||||
print(" 4. Check WiFi status")
|
||||
print(" 5. Connect to WiFi (if needed)")
|
||||
print(" 6. Start streaming when connected")
|
||||
break
|
||||
else:
|
||||
print("❌ Invalid network number")
|
||||
except ValueError:
|
||||
print("❌ Please enter a number or 'back'")
|
||||
|
||||
elif choice == "4":
|
||||
# Check WiFi status
|
||||
status = device.get_wifi_status()
|
||||
if status:
|
||||
print(f"📶 WiFi Status: {status.get('status', 'unknown')}")
|
||||
print(f"📡 Networks configured: {status.get('networks_configured', 0)}")
|
||||
if status.get('ip_address'):
|
||||
print(f"🌐 IP Address: {status['ip_address']}")
|
||||
else:
|
||||
print("❌ Unable to get WiFi status")
|
||||
|
||||
elif choice == "5":
|
||||
# Attempt WiFi connection
|
||||
device.connect_wifi()
|
||||
print("🕰️ Wait a few seconds then check status (option 4)")
|
||||
|
||||
elif choice == "6":
|
||||
device.start_streaming()
|
||||
print("🚀 Streaming started! Use option 8 to monitor logs.")
|
||||
|
||||
elif choice == "7":
|
||||
# Switch device mode
|
||||
current_mode = device.get_device_mode()
|
||||
print(f"\n📍 Current device mode: {current_mode}")
|
||||
print("\n🔄 Select new device mode:")
|
||||
print("1. WiFi - Stream over WiFi connection")
|
||||
print("2. UVC - Stream as USB webcam")
|
||||
print("3. Auto - Automatic mode selection")
|
||||
|
||||
mode_choice = input("\nSelect mode (1-3): ").strip()
|
||||
|
||||
if mode_choice == "1":
|
||||
device.switch_mode("wifi")
|
||||
elif mode_choice == "2":
|
||||
device.switch_mode("uvc")
|
||||
elif mode_choice == "3":
|
||||
device.switch_mode("auto")
|
||||
else:
|
||||
print("❌ Invalid mode selection")
|
||||
|
||||
elif choice == "8":
|
||||
device.monitor_logs()
|
||||
|
||||
elif choice == "9":
|
||||
if choice == "exit":
|
||||
break
|
||||
|
||||
else:
|
||||
|
||||
command_to_run = COMMANDS_MAP.get(choice, None)
|
||||
if not command_to_run:
|
||||
print("❌ Invalid option")
|
||||
continue
|
||||
|
||||
command_to_run(device, args)
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print("\n🛑 Setup interrupted")
|
||||
|
||||
@@ -28,7 +28,7 @@ class ESPWiFiScanner:
|
||||
|
||||
self.serial.reset_input_buffer()
|
||||
|
||||
command = '{"commands":[{"command":"scan_networks","data":{}}]}\n'
|
||||
command = '{"commands":[{"command":"scan_networks"}]}\n'
|
||||
self.serial.write(command.encode())
|
||||
|
||||
timeout_start = time.time()
|
||||
@@ -92,7 +92,7 @@ def main():
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(description='ESP32 WiFi Scanner')
|
||||
parser.add_argument('port', nargs='?', default='COM15', help='Serial port (default: COM9)')
|
||||
parser.add_argument('port', nargs='?', help='Serial port - COM1, /dev/ttyUSB0, etc.')
|
||||
parser.add_argument('-t', '--timeout', type=int, default=30,
|
||||
help='Scan timeout in seconds (default: 30)')
|
||||
args = parser.parse_args()
|
||||
|
||||
Reference in New Issue
Block a user