mirror of
https://github.com/EyeTrackVR/OpenIris.git
synced 2025-09-26 23:29:14 +08:00
feat: Refactor commands and serial manager to support updated commands payload
Refactor commands and serial manager to support updated commands payload with initial PoC of better state logging
This commit is contained in:
commit
811a9f898a
@ -1,74 +1,81 @@
|
||||
#include "CommandManager.hpp"
|
||||
|
||||
CommandManager::CommandManager(ProjectConfig *deviceConfig) : deviceConfig(deviceConfig) {}
|
||||
CommandManager::CommandManager(ProjectConfig* deviceConfig)
|
||||
: deviceConfig(deviceConfig) {}
|
||||
|
||||
|
||||
const CommandType CommandManager::getCommandType(Command &command){
|
||||
if (!command.data.containsKey("command"))
|
||||
return CommandType::None;
|
||||
|
||||
if (auto search = commandMap.find(command.data["command"]); search != commandMap.end())
|
||||
return search->second;
|
||||
|
||||
const CommandType CommandManager::getCommandType(JsonVariant& command) {
|
||||
if (!command.containsKey("command"))
|
||||
return CommandType::None;
|
||||
|
||||
if (auto search = commandMap.find(command["command"]);
|
||||
search != commandMap.end())
|
||||
return search->second;
|
||||
|
||||
return CommandType::None;
|
||||
}
|
||||
|
||||
bool CommandManager::hasHasDataField(Command &command) {
|
||||
return command.data.containsKey("data");
|
||||
bool CommandManager::hasDataField(JsonVariant& command) {
|
||||
return command.containsKey("data");
|
||||
}
|
||||
|
||||
void CommandManager::handleCommand(Command command) {
|
||||
auto command_type = this->getCommandType(command);
|
||||
void CommandManager::handleCommands(CommandsPayload commandsPayload) {
|
||||
if (!commandsPayload.data.containsKey("commands")) {
|
||||
log_e("Json data sent not supported, lacks commands field");
|
||||
return;
|
||||
}
|
||||
|
||||
switch(command_type)
|
||||
{
|
||||
case CommandType::SET_WIFI: {
|
||||
if (!this->hasHasDataField(command))
|
||||
// malformed command, lacked data field
|
||||
break;
|
||||
for (JsonVariant commandData :
|
||||
commandsPayload.data["commands"].as<JsonArray>()) {
|
||||
this->handleCommand(commandData);
|
||||
}
|
||||
|
||||
this->deviceConfig->save();
|
||||
}
|
||||
|
||||
if(!command.data["data"].containsKey("ssid") || !command.data["data"].containsKey("password"))
|
||||
break;
|
||||
void CommandManager::handleCommand(JsonVariant command) {
|
||||
auto command_type = this->getCommandType(command);
|
||||
|
||||
std::string customNetworkName = "main";
|
||||
if (command.data["data"].containsKey("network_name"))
|
||||
customNetworkName = command.data["data"]["network_name"].as<std::string>();
|
||||
switch (command_type) {
|
||||
case CommandType::SET_WIFI: {
|
||||
if (!this->hasDataField(command))
|
||||
// malformed command, lacked data field
|
||||
break;
|
||||
|
||||
this->deviceConfig->setWifiConfig(
|
||||
customNetworkName,
|
||||
command.data["data"]["ssid"],
|
||||
command.data["data"]["password"],
|
||||
0, // channel, should this be zero?
|
||||
0, // power, should this be zero?
|
||||
false,
|
||||
false
|
||||
);
|
||||
|
||||
// we purposefully save here
|
||||
this->deviceConfig->save();
|
||||
break;
|
||||
}
|
||||
case CommandType::SET_MDNS: {
|
||||
if (!this->hasHasDataField(command))
|
||||
break;
|
||||
if (!command["data"].containsKey("ssid") ||
|
||||
!command["data"].containsKey("password"))
|
||||
break;
|
||||
|
||||
if(!command.data["data"].containsKey("hostname") || !strlen(command.data["data"]["hostname"]))
|
||||
break;
|
||||
std::string customNetworkName = "main";
|
||||
if (command["data"].containsKey("network_name"))
|
||||
customNetworkName = command["data"]["network_name"].as<std::string>();
|
||||
|
||||
this->deviceConfig->setMDNSConfig(
|
||||
command.data["data"]["hostname"],
|
||||
"openiristracker",
|
||||
false
|
||||
);
|
||||
this->deviceConfig->setWifiConfig(customNetworkName,
|
||||
command["data"]["ssid"],
|
||||
command["data"]["password"],
|
||||
0, // channel, should this be zero?
|
||||
0, // power, should this be zero?
|
||||
false, false);
|
||||
|
||||
break;
|
||||
}
|
||||
case CommandType::PING: {
|
||||
Serial.println("PONG \n\r");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
break;
|
||||
}
|
||||
case CommandType::SET_MDNS: {
|
||||
if (!this->hasDataField(command))
|
||||
break;
|
||||
|
||||
if (!command["data"].containsKey("hostname") ||
|
||||
!strlen(command["data"]["hostname"]))
|
||||
break;
|
||||
|
||||
this->deviceConfig->setMDNSConfig(command["data"]["hostname"],
|
||||
"openiristracker", false);
|
||||
|
||||
break;
|
||||
}
|
||||
case CommandType::PING: {
|
||||
Serial.println("PONG \n\r");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
@ -6,34 +6,33 @@
|
||||
#include "data/config/project_config.hpp"
|
||||
|
||||
enum CommandType {
|
||||
None,
|
||||
PING,
|
||||
SET_WIFI,
|
||||
SET_MDNS,
|
||||
None,
|
||||
PING,
|
||||
SET_WIFI,
|
||||
SET_MDNS,
|
||||
};
|
||||
|
||||
|
||||
struct Command {
|
||||
JsonDocument data;
|
||||
struct CommandsPayload {
|
||||
JsonDocument data;
|
||||
};
|
||||
|
||||
class CommandManager{
|
||||
|
||||
private:
|
||||
const std::unordered_map<std::string, CommandType> commandMap = {
|
||||
{"ping", CommandType::PING},
|
||||
{"set_wifi", CommandType::SET_WIFI},
|
||||
{"set_mdns", CommandType::SET_MDNS},
|
||||
};
|
||||
class CommandManager {
|
||||
private:
|
||||
const std::unordered_map<std::string, CommandType> commandMap = {
|
||||
{"ping", CommandType::PING},
|
||||
{"set_wifi", CommandType::SET_WIFI},
|
||||
{"set_mdns", CommandType::SET_MDNS},
|
||||
};
|
||||
|
||||
ProjectConfig* deviceConfig;
|
||||
ProjectConfig* deviceConfig;
|
||||
|
||||
bool hasHasDataField(Command &command);
|
||||
bool hasDataField(JsonVariant& command);
|
||||
void handleCommand(JsonVariant command);
|
||||
const CommandType getCommandType(JsonVariant& command);
|
||||
|
||||
public:
|
||||
CommandManager(ProjectConfig *deviceConfig);
|
||||
void handleCommand(Command command);
|
||||
const CommandType getCommandType(Command &command);
|
||||
public:
|
||||
CommandManager(ProjectConfig* deviceConfig);
|
||||
void handleCommands(CommandsPayload commandsPayload);
|
||||
};
|
||||
|
||||
#endif
|
@ -1,14 +1,12 @@
|
||||
#include "SerialManager.hpp"
|
||||
|
||||
SerialManager::SerialManager(CommandManager* commandManager)
|
||||
: commandManager(commandManager) {}
|
||||
: commandManager(commandManager) {
|
||||
this->queryManager = new QueryManager();
|
||||
}
|
||||
|
||||
#ifdef ETVR_EYE_TRACKER_USB_API
|
||||
void SerialManager::send_frame() {
|
||||
// if we failed to capture the frame, we bail, but we still want to listen to commands
|
||||
if (err != ESP_OK)
|
||||
return;
|
||||
|
||||
if (!last_frame)
|
||||
last_frame = esp_timer_get_time();
|
||||
|
||||
@ -21,14 +19,17 @@ void SerialManager::send_frame() {
|
||||
if (fb) {
|
||||
len = fb->len;
|
||||
buf = fb->buf;
|
||||
} else {
|
||||
log_e("Camera capture failed with response: %s", esp_err_to_name(err));
|
||||
} else
|
||||
err = ESP_FAIL;
|
||||
|
||||
// if we failed to capture the frame, we bail, but we still want to listen to
|
||||
// commands
|
||||
if (err != ESP_OK) {
|
||||
log_e("Camera capture failed with response: %s", esp_err_to_name(err));
|
||||
return;
|
||||
}
|
||||
|
||||
if (err == ESP_OK)
|
||||
Serial.write(ETVR_HEADER, 2);
|
||||
|
||||
Serial.write(ETVR_HEADER, 2);
|
||||
Serial.write(ETVR_HEADER_FRAME, 2);
|
||||
len_bytes[0] = len & 0xFF;
|
||||
len_bytes[1] = (len >> CHAR_BIT) & 0xFF;
|
||||
@ -54,27 +55,42 @@ void SerialManager::send_frame() {
|
||||
|
||||
void SerialManager::init() {
|
||||
Serial.begin(3000000);
|
||||
if (SERIAL_FLUSH_ENABLED){
|
||||
if (SERIAL_FLUSH_ENABLED) {
|
||||
Serial.flush();
|
||||
}
|
||||
|
||||
this->sendQuery(QueryAction::READY_TO_RECEIVE, QueryStatus::NONE, "");
|
||||
}
|
||||
|
||||
void SerialManager::(QueryAction action,
|
||||
QueryStatus status,
|
||||
std::string additional_info) {
|
||||
JsonDocument doc;
|
||||
doc["action"] = queryActionMap.at(action);
|
||||
doc["status"] = status;
|
||||
doc["additional_info"] = additional_info;
|
||||
|
||||
doc.shrinkToFit(); // optional
|
||||
serializeJson(doc, Serial);
|
||||
}
|
||||
|
||||
void SerialManager::run() {
|
||||
if (Serial.available()) {
|
||||
JsonDocument doc;
|
||||
DeserializationError deserializationError = deserializeJson(doc, Serial);
|
||||
if (Serial.available()) {
|
||||
JsonDocument doc;
|
||||
DeserializationError deserializationError = deserializeJson(doc, Serial);
|
||||
|
||||
if (deserializationError) {
|
||||
log_e("Command deserialization failed: %s",
|
||||
deserializationError.c_str());
|
||||
}
|
||||
if (deserializationError) {
|
||||
log_e("Command deserialization failed: %s", deserializationError.c_str());
|
||||
|
||||
Command command = {doc};
|
||||
this->commandManager->handleCommand(command);
|
||||
return;
|
||||
}
|
||||
|
||||
CommandsPayload commands = {doc};
|
||||
this->commandManager->handleCommands(commands);
|
||||
}
|
||||
#ifdef ETVR_EYE_TRACKER_USB_API
|
||||
else {
|
||||
this->send_frame();
|
||||
}
|
||||
else {
|
||||
this->send_frame();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -12,6 +12,24 @@
|
||||
const char* const ETVR_HEADER = "\xff\xa0";
|
||||
const char* const ETVR_HEADER_FRAME = "\xff\xa1";
|
||||
|
||||
enum QueryAction {
|
||||
READY_TO_RECEIVE,
|
||||
PARSE_COMMANDS,
|
||||
CONNECT_TO_WIFI,
|
||||
};
|
||||
|
||||
enum QueryStatus {
|
||||
NONE,
|
||||
SUCCESS,
|
||||
ERROR,
|
||||
};
|
||||
|
||||
const std::unordered_map<QueryAction, std::string> queryActionMap = {
|
||||
{QueryAction::READY_TO_RECEIVE, "ready_to_receive"},
|
||||
{QueryAction::PARSE_COMMANDS, "parse_commands"},
|
||||
{QueryAction::CONNECT_TO_WIFI, "connect_to_wifi"},
|
||||
};
|
||||
|
||||
class SerialManager {
|
||||
private:
|
||||
esp_err_t err = ESP_OK;
|
||||
@ -26,6 +44,9 @@ class SerialManager {
|
||||
|
||||
public:
|
||||
SerialManager(CommandManager* commandManager);
|
||||
void sendQuery(QueryAction action,
|
||||
QueryStatus status,
|
||||
std::string additional_info);
|
||||
void init();
|
||||
void run();
|
||||
};
|
||||
|
@ -18,6 +18,13 @@ WiFiHandler::WiFiHandler(ProjectConfig& configManager,
|
||||
WiFiHandler::~WiFiHandler() {}
|
||||
|
||||
void WiFiHandler::begin() {
|
||||
|
||||
// just to be sure, we reeset everything before we do anything, some boards were having problems otherwise
|
||||
WiFi.disconnect();
|
||||
// we purposefully set the lowest min required security level, some boards have problems connecting otherwise
|
||||
// https://github.com/espressif/arduino-esp32/issues/8770
|
||||
WiFi.setMinSecurity(WIFI_AUTH_WEP);
|
||||
|
||||
log_i("Starting WiFi Handler \n\r");
|
||||
if (this->_enable_adhoc ||
|
||||
wifiStateManager.getCurrentState() == WiFiState_e::WiFiState_ADHOC) {
|
||||
@ -40,8 +47,6 @@ void WiFiHandler::begin() {
|
||||
if (networks.empty()) {
|
||||
log_i("No networks found in config, trying the default one \n\r");
|
||||
|
||||
// since networks may not have a password, we only need to check if we have an ssid
|
||||
// bail if we don't
|
||||
if (this->iniSTA(
|
||||
this->ssid,
|
||||
this->password,
|
||||
@ -135,6 +140,8 @@ bool WiFiHandler::iniSTA(const std::string& ssid,
|
||||
uint8_t channel,
|
||||
wifi_power_t power) {
|
||||
|
||||
// since networks may not have a password, we only need to check if we have an ssid
|
||||
// bail if we don't
|
||||
if (ssid == ""){
|
||||
log_d("ssid missing, bailing");
|
||||
return false;
|
||||
@ -148,13 +155,14 @@ bool WiFiHandler::iniSTA(const std::string& ssid,
|
||||
wifiStateManager.setState(WiFiState_e::WiFiState_Connecting);
|
||||
log_i("Trying to connect to: %s \n\r", ssid.c_str());
|
||||
auto mdnsConfig = configManager.getMDNSConfig();
|
||||
|
||||
log_d("Setting hostname %s \n\r");
|
||||
WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE,
|
||||
INADDR_NONE); // need to call before setting hostname
|
||||
log_d("Setting hostname %s \n\r");
|
||||
WiFi.setHostname(mdnsConfig.hostname.c_str());
|
||||
log_i("Setting TX power to: %d \n\r", (uint8_t)power);
|
||||
WiFi.setTxPower(power); // https://github.com/espressif/arduino-esp32/issues/5698
|
||||
WiFi.begin(ssid.c_str(), password.c_str(), channel);
|
||||
WiFi.setTxPower(power);
|
||||
|
||||
log_d("Waiting for WiFi to connect... \n\r");
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
progress++;
|
||||
@ -169,7 +177,6 @@ bool WiFiHandler::iniSTA(const std::string& ssid,
|
||||
}
|
||||
wifiStateManager.setState(WiFiState_e::WiFiState_Connected);
|
||||
log_i("Successfully connected to %s \n\r", ssid.c_str());
|
||||
log_i("Setting TX power to: %d \n\r", (uint8_t)power);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -3,20 +3,18 @@
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include <data/CommandManager/CommandManager.hpp>
|
||||
#include <data/config/project_config.hpp>
|
||||
#include <io/LEDManager/LEDManager.hpp>
|
||||
#include <io/Serial/SerialManager.hpp>
|
||||
#include <io/camera/cameraHandler.hpp>
|
||||
#include <logo/logo.hpp>
|
||||
#include <io/Serial/SerialManager.hpp>
|
||||
#include <data/CommandManager/CommandManager.hpp>
|
||||
|
||||
#ifndef ETVR_EYE_TRACKER_USB_API
|
||||
#include <network/api/webserverHandler.hpp>
|
||||
#include <network/mDNS/MDNSManager.hpp>
|
||||
#include <network/stream/streamServer.hpp>
|
||||
#include <network/wifihandler/wifihandler.hpp>
|
||||
#else
|
||||
#include <usb/etvr_eye_tracker_usb.hpp>
|
||||
#endif // ETVR_EYE_TRACKER_WEB_API
|
||||
|
||||
#endif // OPENIRIS_HPP
|
||||
|
@ -1,61 +0,0 @@
|
||||
#include "etvr_eye_tracker_usb.hpp"
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <USBCDC.h>
|
||||
#include <esp_camera.h>
|
||||
|
||||
const char* const ETVR_HEADER = "\xff\xa0";
|
||||
const char* const ETVR_HEADER_FRAME = "\xff\xa1";
|
||||
|
||||
void etvr_eye_tracker_usb_init() {
|
||||
Serial.begin(3000000);
|
||||
Serial.flush();
|
||||
}
|
||||
|
||||
void etvr_eye_tracker_usb_loop() {
|
||||
int64_t last_frame = 0;
|
||||
if (!last_frame)
|
||||
last_frame = esp_timer_get_time();
|
||||
|
||||
long last_request_time = 0;
|
||||
camera_fb_t* fb = NULL;
|
||||
esp_err_t err = ESP_OK;
|
||||
|
||||
size_t len = 0;
|
||||
uint8_t* buf = NULL;
|
||||
|
||||
uint8_t len_bytes[2];
|
||||
|
||||
while (true) {
|
||||
fb = esp_camera_fb_get();
|
||||
if (fb) {
|
||||
len = fb->len;
|
||||
buf = fb->buf;
|
||||
} else {
|
||||
log_e("Camera capture failed with response: %s", esp_err_to_name(err));
|
||||
err = ESP_FAIL;
|
||||
}
|
||||
if (err == ESP_OK)
|
||||
Serial.write(ETVR_HEADER, 2);
|
||||
Serial.write(ETVR_HEADER_FRAME, 2);
|
||||
len_bytes[0] = len & 0xFF;
|
||||
len_bytes[1] = (len >> CHAR_BIT) & 0xFF;
|
||||
Serial.write(len_bytes, 2);
|
||||
Serial.write((const char*)buf, len);
|
||||
if (fb) {
|
||||
esp_camera_fb_return(fb);
|
||||
fb = NULL;
|
||||
buf = NULL;
|
||||
} else if (buf) {
|
||||
free(buf);
|
||||
buf = NULL;
|
||||
}
|
||||
if (err != ESP_OK)
|
||||
break;
|
||||
long request_end = millis();
|
||||
long latency = request_end - last_request_time;
|
||||
last_request_time = request_end;
|
||||
log_d("Size: %uKB, Time: %ums (%ifps)\n", len / 1024, latency,
|
||||
1000 / latency);
|
||||
}
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
#ifndef INCLUDED_ETVR_EYE_TRACKER_USB_HPP
|
||||
#define INCLUDED_ETVR_EYE_TRACKER_USB_HPP
|
||||
|
||||
void etvr_eye_tracker_usb_init();
|
||||
void etvr_eye_tracker_usb_loop();
|
||||
|
||||
#endif // INCLUDED_ETVR_EYE_TRACKER_USB_HPP
|
@ -20,7 +20,11 @@ CameraHandler cameraHandler(deviceConfig);
|
||||
#endif // SIM_ENABLED
|
||||
|
||||
#ifndef ETVR_EYE_TRACKER_USB_API
|
||||
WiFiHandler wifiHandler(deviceConfig, WIFI_SSID, WIFI_PASSWORD, WIFI_CHANNEL, ENABLE_ADHOC);
|
||||
WiFiHandler wifiHandler(deviceConfig,
|
||||
WIFI_SSID,
|
||||
WIFI_PASSWORD,
|
||||
WIFI_CHANNEL,
|
||||
ENABLE_ADHOC);
|
||||
MDNSHandler mdnsHandler(deviceConfig);
|
||||
#ifdef SIM_ENABLED
|
||||
APIServer apiServer(deviceConfig, wifiStateManager, "/control");
|
||||
@ -83,7 +87,7 @@ void setup() {
|
||||
#endif // SIM_ENABLED
|
||||
deviceConfig.load();
|
||||
|
||||
serialManager.init();
|
||||
serialManager.init();
|
||||
|
||||
#ifndef ETVR_EYE_TRACKER_USB_API
|
||||
etvr_eye_tracker_web_init();
|
||||
|
Loading…
Reference in New Issue
Block a user