diff --git a/README.md b/README.md index 37c67d0..d7c8a34 100644 --- a/README.md +++ b/README.md @@ -124,8 +124,10 @@ Runtime override: If the setup CLI (or a JSON command) provides a new device nam - Fast Wi‑Fi setup: in the CLI, go to “Wi‑Fi settings” → “Automatic setup”, then check “status”. - Change name/MDNS: set the device name in the CLI, then replug USB — UVC will show the new name. - Adjust brightness/LED: set LED PWM in the CLI. - - Switch to UVC mode over commands: send JSON `{ "cmd": "switch_mode", "mode": "uvc" }` then reboot. - - Read filtered LED current (if enabled): `{ "cmd": "get_led_current" }`. + - Switch to UVC mode over commands (CDC/serial): + `{"commands":[{"command":"switch_mode","data":{"mode":"uvc"}}]}` then reboot. + - Read filtered LED current (if enabled): + `{"commands":[{"command":"get_led_current"}]}` --- @@ -143,11 +145,19 @@ When UVC support is compiled in the device enumerates as a composite USB device: - UVC interface: video streaming (JPEG frames) - CDC (virtual COM): command channel accepting newline‑terminated JSON objects -Example newline‑terminated JSON commands over CDC: +Example newline‑terminated JSON commands over CDC (one per line): ``` -{"cmd":"ping"}\n -{"cmd":"get_info"}\n -{"cmd":"switch_mode","mode":"wifi"}\n +{"commands":[{"command":"ping"}]} +{"commands":[{"command":"get_who_am_i"}]} +{"commands":[{"command":"switch_mode","data":{"mode":"wifi"}}]} +``` + +Chained commands in a single request (processed in order): +``` +{"commands":[ + {"command":"set_mdns","data":{"hostname":"tracker"}}, + {"command":"set_wifi","data":{"name":"main","ssid":"your_network","password":"password","channel":0,"power":0}} +]} ``` Responses are JSON blobs flushed immediately. diff --git a/components/LEDManager/LEDManager/LEDManager.hpp b/components/LEDManager/LEDManager/LEDManager.hpp index 0129c3b..a08ace3 100644 --- a/components/LEDManager/LEDManager/LEDManager.hpp +++ b/components/LEDManager/LEDManager/LEDManager.hpp @@ -72,8 +72,8 @@ private: bool finishedPattern = false; #if defined(CONFIG_LED_EXTERNAL_CONTROL) && defined(CONFIG_LED_EXTERNAL_AS_DEBUG) - mutable bool hasStoredExternalDuty = false; - mutable uint32_t storedExternalDuty = 0; // raw 0-255 + bool hasStoredExternalDuty = false; + uint32_t storedExternalDuty = 0; // raw 0-255 #endif }; diff --git a/components/Monitoring/Monitoring/CurrentMonitor.hpp b/components/Monitoring/Monitoring/CurrentMonitor.hpp index 3285f4e..d1163d3 100644 --- a/components/Monitoring/Monitoring/CurrentMonitor.hpp +++ b/components/Monitoring/Monitoring/CurrentMonitor.hpp @@ -1,3 +1,5 @@ +#ifndef CURRENT_MONITOR_HPP +#define CURRENT_MONITOR_HPP #pragma once #include #include @@ -43,3 +45,5 @@ private: size_t sample_idx_ = 0; size_t sample_count_ = 0; }; + +#endif diff --git a/components/Monitoring/Monitoring/MonitoringManager.hpp b/components/Monitoring/Monitoring/MonitoringManager.hpp index 6b96688..3e7a6c2 100644 --- a/components/Monitoring/Monitoring/MonitoringManager.hpp +++ b/components/Monitoring/Monitoring/MonitoringManager.hpp @@ -6,8 +6,6 @@ class MonitoringManager { public: - MonitoringManager() = default; - ~MonitoringManager() = default; void setup(); void start(); diff --git a/components/UVCStream/UVCStream/UVCStream.cpp b/components/UVCStream/UVCStream/UVCStream.cpp index 531b7e8..4f773a6 100644 --- a/components/UVCStream/UVCStream/UVCStream.cpp +++ b/components/UVCStream/UVCStream/UVCStream.cpp @@ -97,10 +97,10 @@ static uvc_fb_t *UVCStreamHelpers::camera_fb_get_cb(void *cb_ctx) // --- Frame pacing BEFORE grabbing a new camera frame --- static int64_t next_deadline_us = 0; // next permitted capture time static int rem_acc = 0; // fractional remainder accumulator - constexpr int target_fps = 60; // desired FPS - constexpr int64_t us_per_sec = 1000000; // 1e6 microseconds - constexpr int base_interval_us = us_per_sec / target_fps; // 16666 - constexpr int rem_us = us_per_sec % target_fps; // 40 (distributed) + static const int target_fps = 60; // desired FPS + static const int64_t us_per_sec = 1000000; // 1e6 microseconds + static const int base_interval_us = us_per_sec / target_fps; // 16666 + static const int rem_us = us_per_sec % target_fps; // 40 (distributed) const int64_t now_us = esp_timer_get_time(); if (next_deadline_us == 0) diff --git a/main/openiris_main.cpp b/main/openiris_main.cpp index 3f2761b..81b443e 100644 --- a/main/openiris_main.cpp +++ b/main/openiris_main.cpp @@ -5,9 +5,9 @@ #include "freertos/queue.h" #include "driver/gpio.h" #include "esp_log.h" +#include "esp_timer.h" #include "sdkconfig.h" #include "nvs_flash.h" -#include "esp_wifi.h" #include #include @@ -65,7 +65,7 @@ UVCStreamManager uvcStream; auto ledManager = std::make_shared(BLINK_GPIO, CONFIG_LED_C_PIN_GPIO, ledStateQueue, deviceConfig); auto *serialManager = new SerialManager(commandManager, &timerHandle, deviceConfig); -MonitoringManager monitoringManager; +std::shared_ptr monitoringManager = std::make_shared(); void startWiFiMode(bool shouldCloseSerialManager); void startWiredMode(bool shouldCloseSerialManager); @@ -233,11 +233,11 @@ void startSetupMode() { // If we're in SETUP mode - Device starts with a 20-second delay before deciding on what to do // during this time we await any commands - const int startup_delay_s = CONFIG_GENERAL_STARTUP_DELAY; + const uint64_t startup_delay_s = CONFIG_GENERAL_STARTUP_DELAY; ESP_LOGI("[MAIN]", "====================================="); - ESP_LOGI("[MAIN]", "STARTUP: %d-SECOND DELAY MODE ACTIVE", startup_delay_s); + ESP_LOGI("[MAIN]", "STARTUP: %llu-SECOND DELAY MODE ACTIVE", (unsigned long long)startup_delay_s); ESP_LOGI("[MAIN]", "====================================="); - ESP_LOGI("[MAIN]", "Device will wait %d seconds for commands...", startup_delay_s); + ESP_LOGI("[MAIN]", "Device will wait %llu seconds for commands...", (unsigned long long)startup_delay_s); // Create a one-shot timer for 20 seconds const esp_timer_create_args_t startup_timer_args = { @@ -248,9 +248,9 @@ void startSetupMode() .skip_unhandled_events = false}; ESP_ERROR_CHECK(esp_timer_create(&startup_timer_args, &timerHandle)); - ESP_ERROR_CHECK(esp_timer_start_once(timerHandle, (uint64_t)startup_delay_s * 1000000)); - ESP_LOGI("[MAIN]", "Started %d-second startup timer", startup_delay_s); - ESP_LOGI("[MAIN]", "Send any command within %d seconds to enter heartbeat mode", startup_delay_s); + ESP_ERROR_CHECK(esp_timer_start_once(timerHandle, startup_delay_s * 1000000)); + ESP_LOGI("[MAIN]", "Started %llu-second startup timer", (unsigned long long)startup_delay_s); + ESP_LOGI("[MAIN]", "Send any command within %llu seconds to enter heartbeat mode", (unsigned long long)startup_delay_s); } extern "C" void app_main(void) @@ -262,7 +262,7 @@ extern "C" void app_main(void) dependencyRegistry->registerService(DependencyType::wifi_manager, wifiManager); #endif dependencyRegistry->registerService(DependencyType::led_manager, ledManager); - dependencyRegistry->registerService(DependencyType::monitoring_manager, std::shared_ptr(&monitoringManager, [](MonitoringManager*){})); + dependencyRegistry->registerService(DependencyType::monitoring_manager, monitoringManager); // add endpoint to check firmware version // add firmware version somewhere @@ -275,8 +275,8 @@ extern "C" void app_main(void) initNVSStorage(); deviceConfig->load(); ledManager->setup(); - monitoringManager.setup(); - monitoringManager.start(); + monitoringManager->setup(); + monitoringManager->start(); xTaskCreate( HandleStateManagerTask, diff --git a/tools/openiris_setup.py b/tools/openiris_setup.py index b0af91f..403267c 100644 --- a/tools/openiris_setup.py +++ b/tools/openiris_setup.py @@ -1063,10 +1063,9 @@ def get_settings(device: OpenIrisDevice, args=None): print("🔑 Serial/MAC: unavailable") # Advertised Name - adv = summary.get("AdvertisedName", {}) - adv_name = adv.get("advertised_name") - if adv_name: - print(f"📛 Name: {adv_name}") + advertised_name_data = summary.get("AdvertisedName", {}) + if advertised_name := advertised_name_data.get("advertised_name"): + print(f"📛 Name: {advertised_name}") # Info info = summary.get("Info", {}) @@ -1090,12 +1089,11 @@ def get_settings(device: OpenIrisDevice, args=None): print(f"🎚️ Mode: {mode if mode else 'unknown'}") # Current - current = summary.get("Current", {}).get("led_current_ma") - if current is not None: - print(f"🔌 LED Current: {current:.3f} mA") + current_section = summary.get("Current", {}) + if (led_current_ma := current_section.get("led_current_ma")) is not None: + print(f"🔌 LED Current: {led_current_ma:.3f} mA") else: - err = summary.get("Current", {}).get("error") - if err: + if (err := current_section.get("error")): print(f"🔌 LED Current: unavailable ({err})") else: print("🔌 LED Current: unavailable") diff --git a/tools/switchBoardType.py b/tools/switchBoardType.py index 069ea6d..0ff17f6 100644 --- a/tools/switchBoardType.py +++ b/tools/switchBoardType.py @@ -1,4 +1,5 @@ import os +import difflib import argparse from typing import Dict, Optional, List @@ -70,22 +71,9 @@ def _suggest_boards(partial: str) -> List[str]: contains = [b for b in BOARD_CONFIGS if partial_low in b.lower()] if contains: return contains[:10] - # simple levenshtein distance limited (manual lightweight) - def distance(a: str, b: str) -> int: - if len(a) < len(b): - a, b = b, a - prev = list(range(len(b)+1)) - for i, ca in enumerate(a, 1): - cur = [i] - for j, cb in enumerate(b, 1): - ins = cur[j-1] + 1 - dele = prev[j] + 1 - sub = prev[j-1] + (ca != cb) - cur.append(min(ins, dele, sub)) - prev = cur - return prev[-1] - ranked = sorted(BOARD_CONFIGS, key=lambda k: distance(partial_low, k.lower())) - return ranked[:5] + # fallback to fuzzy matching using difflib + choices = list(BOARD_CONFIGS.keys()) + return difflib.get_close_matches(partial, choices, n=5, cutoff=0.4) def normalize_board_name(raw: Optional[str]) -> Optional[str]: if raw is None: