From b7bae7fb3e25df598fd55cf6616221374eb51f94 Mon Sep 17 00:00:00 2001 From: Lorow Date: Tue, 20 May 2025 23:09:06 +0200 Subject: [PATCH] Add Proof of concept switching between UVC and Wi-Fi streaming based on the presence of Wi-Fi creds, rewrite restart task to esp_timer TODO: Think about letting people set the mode explicitly so the board comes online faster --- .../OpenIrisTasks/OpenIrisTasks.cpp | 25 +++++--- .../SerialManager/SerialManager.cpp | 14 ++-- .../SerialManager/SerialManager.hpp | 4 +- main/openiris_main.cpp | 64 +++++++++++++++++-- 4 files changed, 79 insertions(+), 28 deletions(-) diff --git a/components/OpenIrisTasks/OpenIrisTasks/OpenIrisTasks.cpp b/components/OpenIrisTasks/OpenIrisTasks/OpenIrisTasks.cpp index 633704a..71b8a84 100644 --- a/components/OpenIrisTasks/OpenIrisTasks/OpenIrisTasks.cpp +++ b/components/OpenIrisTasks/OpenIrisTasks/OpenIrisTasks.cpp @@ -1,14 +1,19 @@ #include "OpenIrisTasks.hpp" -void OpenIrisTasks::ScheduleRestart(int milliseconds) -{ - taskYIELD(); - const auto initialTime = Helpers::getTimeInMillis(); - while (Helpers::getTimeInMillis() - initialTime <= milliseconds) - { - continue; - } - +void restart_the_board(void *arg) { esp_restart(); - taskYIELD(); +} + +void OpenIrisTasks::ScheduleRestart(const int milliseconds) +{ + esp_timer_handle_t timerHandle; + constexpr esp_timer_create_args_t args = { + .callback = &restart_the_board, + .arg = nullptr, + .name = "restartBoard"}; + + if (const auto result = esp_timer_create(&args, &timerHandle); result == ESP_OK) + { + esp_timer_start_once(timerHandle, milliseconds); + } } \ No newline at end of file diff --git a/components/SerialManager/SerialManager/SerialManager.cpp b/components/SerialManager/SerialManager/SerialManager.cpp index 0e57be6..93d6a3e 100644 --- a/components/SerialManager/SerialManager/SerialManager.cpp +++ b/components/SerialManager/SerialManager/SerialManager.cpp @@ -1,16 +1,8 @@ #include "SerialManager.hpp" -#define ECHO_TEST_TXD (4) -#define ECHO_TEST_RXD (5) -#define ECHO_TEST_RTS (UART_PIN_NO_CHANGE) -#define ECHO_TEST_CTS (UART_PIN_NO_CHANGE) - -#define ECHO_UART_PORT_NUM (1) -#define ECHO_UART_BAUD_RATE (115200) - #define BUF_SIZE (1024) -SerialManager::SerialManager(std::shared_ptr commandManager) : commandManager(commandManager) { +SerialManager::SerialManager(std::shared_ptr commandManager, esp_timer_handle_t *timerHandle) : commandManager(commandManager), timerHandle(timerHandle) { this->data = static_cast(malloc(BUF_SIZE)); this->temp_data = static_cast(malloc(256)); } @@ -28,6 +20,9 @@ void SerialManager::try_receive() int current_position = 0; int len = usb_serial_jtag_read_bytes(this->temp_data, 256, 1000 / 20); + if (len) { + esp_timer_stop(*timerHandle); + } // since we've got something on the serial port // we gotta keep reading until we've got the whole message while (len) @@ -46,6 +41,7 @@ void SerialManager::try_receive() const auto result = this->commandManager->executeFromJson(std::string_view(reinterpret_cast(this->data))); const auto resultMessage = result.getResult(); usb_serial_jtag_write_bytes(resultMessage.c_str(), resultMessage.length(), 1000 / 20); + esp_timer_start_once(*timerHandle, 30000000); // 30s } } diff --git a/components/SerialManager/SerialManager/SerialManager.hpp b/components/SerialManager/SerialManager/SerialManager.hpp index 16a4dd3..e3fca9a 100644 --- a/components/SerialManager/SerialManager/SerialManager.hpp +++ b/components/SerialManager/SerialManager/SerialManager.hpp @@ -19,13 +19,13 @@ class SerialManager { public: - explicit SerialManager(std::shared_ptr commandManager); + explicit SerialManager(std::shared_ptr commandManager, esp_timer_handle_t *timerHandle); void setup(); void try_receive(); private: - // QueueHandle_t serialQueue; std::shared_ptr commandManager; + esp_timer_handle_t *timerHandle; uint8_t *data; uint8_t *temp_data; }; diff --git a/main/openiris_main.cpp b/main/openiris_main.cpp index 3e64ed2..e2d1498 100644 --- a/main/openiris_main.cpp +++ b/main/openiris_main.cpp @@ -28,6 +28,7 @@ #define BLINK_GPIO (gpio_num_t) CONFIG_BLINK_GPIO #define CONFIG_LED_C_PIN_GPIO (gpio_num_t) CONFIG_LED_C_PIN +esp_timer_handle_t timerHandle; QueueHandle_t eventQueue = xQueueCreate(10, sizeof(SystemEvent)); QueueHandle_t ledStateQueue = xQueueCreate(10, sizeof(uint32_t)); @@ -52,7 +53,7 @@ UVCStreamManager uvcStream; #endif auto *ledManager = new LEDManager(BLINK_GPIO, CONFIG_LED_C_PIN_GPIO, ledStateQueue); -auto *serialManager = new SerialManager(commandManager); +auto *serialManager = new SerialManager(commandManager, &timerHandle); static void initNVSStorage() { @@ -71,8 +72,57 @@ int test_log(const char *format, va_list args) return vprintf(format, args); } +void disable_serial_manager_task(TaskHandle_t serialManagerHandle) +{ + vTaskDelete(serialManagerHandle); +} + +// the idea here is pretty simple. +// After setting everything up, we start a 30s timer with this as a callback +// if we get anything on the serial, we stop the timer and reset it after the commands are done +// this is done to ensure the user has enough time to configure the board if need be +// +// todo: check the initial PR by Summer and port the device mode from that, should be useful +// but we'll have to rethink it +void start_video_streaming(void *arg) +{ + if (!deviceConfig->getWifiConfigs().empty() || strcmp(CONFIG_WIFI_SSID, "") != 0) { + // make sure the server runs on a separate core + ESP_LOGI("[MAIN]", "WiFi setup detected, starting WiFi streaming."); + streamServer.startStreamServer(); + } else { +#ifdef CONFIG_WIRED_MODE + ESP_LOGI("[MAIN]", "UVC setup detected, starting UVC streaming."); + uvcStream.setup(); +#else + ESP_LOGE("[MAIN]", "The board does not support UVC, please, setup WiFi connection."); +#endif + } + + ESP_LOGI("[MAIN]", "Setup window expired, started streaming services, quitting serial manager."); + const auto serialTaskHandle = static_cast(arg); + disable_serial_manager_task(serialTaskHandle); +} + +esp_timer_handle_t createStartVideoStreamingTimer(void *pvParameter) +{ + esp_timer_handle_t handle; + const esp_timer_create_args_t args = { + .callback = &start_video_streaming, + .arg = pvParameter, + .name = "startVideoStreaming"}; + + if (const auto result = esp_timer_create(&args, &handle); result != ESP_OK) + { + ESP_LOGE("[MAIN]", "Failed to create timer: %s", esp_err_to_name(result)); + } + + return handle; +} + extern "C" void app_main(void) { + TaskHandle_t *serialManagerHandle = nullptr; dependencyRegistry->registerService(DependencyType::project_config, deviceConfig); dependencyRegistry->registerService(DependencyType::camera_manager, cameraHandler); // uvc plan @@ -153,14 +203,12 @@ extern "C" void app_main(void) 1024 * 6, serialManager, 1, // we only rely on the serial manager during provisioning, we can run it slower - nullptr); + serialManagerHandle); wifiManager.Begin(); mdnsManager.start(); restAPI->begin(); cameraHandler->setupCamera(); - // make sure the server runs on a separate core - streamServer.startStreamServer(); xTaskCreate( HandleRestAPIPollTask, @@ -170,7 +218,9 @@ extern "C" void app_main(void) 1, // it's the rest API, we only serve commands over it so we don't really need a higher priority nullptr); -#ifdef CONFIG_WIRED_MODE - uvcStream.setup(); -#endif + timerHandle = createStartVideoStreamingTimer(serialManagerHandle); + if (timerHandle != nullptr) + { + esp_timer_start_once(timerHandle, 30000000); // 30s + } }