mirror of
https://github.com/MrUnknownDE/OpenIris-ESPIDF.git
synced 2026-04-21 23:43:44 +02:00
Merge pull request #11 from lorow/feature/add-cdc-communication
Feature/add cdc communication
This commit is contained in:
@@ -128,8 +128,20 @@ CommandResult getLEDDutyCycleCommand(std::shared_ptr<DependencyRegistry> registr
|
|||||||
|
|
||||||
CommandResult startStreamingCommand()
|
CommandResult startStreamingCommand()
|
||||||
{
|
{
|
||||||
activateStreaming(false); // Don't disable setup interfaces by default
|
// since we're trying to kill the serial handler
|
||||||
return CommandResult::getSuccessResult("Streaming started");
|
// from *inside* the serial handler, we'd deadlock.
|
||||||
|
// we can just pass nullptr to the vtaskdelete(),
|
||||||
|
// but then we won't get any response, so we schedule a timer instead
|
||||||
|
esp_timer_create_args_t args{
|
||||||
|
.callback = activateStreaming,
|
||||||
|
.arg = nullptr,
|
||||||
|
.name = "activateStreaming"};
|
||||||
|
|
||||||
|
esp_timer_handle_t activateStreamingTimer;
|
||||||
|
esp_timer_create(&args, &activateStreamingTimer);
|
||||||
|
esp_timer_start_once(activateStreamingTimer, pdMS_TO_TICKS(150));
|
||||||
|
|
||||||
|
return CommandResult::getSuccessResult("Streaming starting");
|
||||||
}
|
}
|
||||||
|
|
||||||
CommandResult switchModeCommand(std::shared_ptr<DependencyRegistry> registry, std::string_view jsonPayload)
|
CommandResult switchModeCommand(std::shared_ptr<DependencyRegistry> registry, std::string_view jsonPayload)
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
#include "main_globals.hpp"
|
#include "main_globals.hpp"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
|
|
||||||
// Forward declarations
|
// used to force starting the stream setup process via commands
|
||||||
extern void start_video_streaming(void *arg);
|
extern void force_activate_streaming();
|
||||||
|
|
||||||
static bool s_startupCommandReceived = false;
|
static bool s_startupCommandReceived = false;
|
||||||
bool getStartupCommandReceived()
|
bool getStartupCommandReceived()
|
||||||
@@ -15,17 +15,6 @@ void setStartupCommandReceived(bool startupCommandReceived)
|
|||||||
s_startupCommandReceived = startupCommandReceived;
|
s_startupCommandReceived = startupCommandReceived;
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
// Global pause state
|
||||||
static bool s_startupPaused = false;
|
static bool s_startupPaused = false;
|
||||||
bool getStartupPaused()
|
bool getStartupPaused()
|
||||||
@@ -39,14 +28,9 @@ void setStartupPaused(bool startupPaused)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Function to manually activate streaming
|
// Function to manually activate streaming
|
||||||
void activateStreaming(bool disableSetup)
|
void activateStreaming(void *arg)
|
||||||
{
|
{
|
||||||
ESP_LOGI("[MAIN_GLOBALS]", "Manually activating streaming, disableSetup=%s", disableSetup ? "true" : "false");
|
force_activate_streaming();
|
||||||
|
|
||||||
TaskHandle_t *serialHandle = disableSetup ? g_serial_manager_handle : nullptr;
|
|
||||||
void *serialTaskHandle = (serialHandle && *serialHandle) ? *serialHandle : nullptr;
|
|
||||||
|
|
||||||
start_video_streaming(serialTaskHandle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// USB handover state
|
// USB handover state
|
||||||
|
|||||||
@@ -6,14 +6,10 @@
|
|||||||
#include "freertos/FreeRTOS.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
#include "freertos/task.h"
|
#include "freertos/task.h"
|
||||||
|
|
||||||
// Functions for main to set global handles
|
|
||||||
|
|
||||||
// Functions to access global handles from components
|
|
||||||
TaskHandle_t *getSerialManagerHandle();
|
|
||||||
void setSerialManagerHandle(TaskHandle_t *serialManagerHandle);
|
|
||||||
|
|
||||||
// Function to manually activate streaming
|
// Function to manually activate streaming
|
||||||
void activateStreaming(bool disableSetup = false);
|
// designed to be scheduled as a task
|
||||||
|
// so that the serial manager has time to return the response
|
||||||
|
void activateStreaming(void *arg);
|
||||||
|
|
||||||
bool getStartupCommandReceived();
|
bool getStartupCommandReceived();
|
||||||
void setStartupCommandReceived(bool startupCommandReceived);
|
void setStartupCommandReceived(bool startupCommandReceived);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
idf_component_register(SRCS "SerialManager/SerialManager.cpp"
|
idf_component_register(SRCS "SerialManager/SerialManager.cpp"
|
||||||
INCLUDE_DIRS "SerialManager"
|
INCLUDE_DIRS "SerialManager"
|
||||||
REQUIRES esp_driver_uart CommandManager ProjectConfig
|
REQUIRES esp_driver_uart CommandManager ProjectConfig tinyusb
|
||||||
)
|
)
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "SerialManager.hpp"
|
#include "SerialManager.hpp"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
#include "main_globals.hpp"
|
#include "main_globals.hpp"
|
||||||
|
#include "tusb.h"
|
||||||
|
|
||||||
#define BUF_SIZE (1024)
|
#define BUF_SIZE (1024)
|
||||||
|
|
||||||
@@ -65,10 +66,10 @@ void SerialManager::try_receive()
|
|||||||
// Notify main that a command was received during startup
|
// Notify main that a command was received during startup
|
||||||
notify_startup_command_received();
|
notify_startup_command_received();
|
||||||
|
|
||||||
const auto result = this->commandManager->executeFromJson(std::string_view(reinterpret_cast<const char *>(this->data)));
|
const auto result = this->commandManager->executeFromJson(std::string_view(reinterpret_cast<const char *>(this->data)));
|
||||||
const auto resultMessage = result.getResult();
|
const auto resultMessage = result.getResult();
|
||||||
int written = usb_serial_jtag_write_bytes(resultMessage.c_str(), resultMessage.length(), 1000 / 20);
|
int written = usb_serial_jtag_write_bytes(resultMessage.c_str(), resultMessage.length(), 1000 / 20);
|
||||||
(void)written; // ignore errors if driver already uninstalled
|
(void)written; // ignore errors if driver already uninstalled
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,6 +128,22 @@ bool SerialManager::should_send_heartbeat()
|
|||||||
return wifiConfigs.empty();
|
return wifiConfigs.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SerialManager::shutdown()
|
||||||
|
{
|
||||||
|
// Stop heartbeats; timer will be deleted by main if needed.
|
||||||
|
// Uninstall the USB Serial JTAG driver to free the internal USB for TinyUSB.
|
||||||
|
esp_err_t err = usb_serial_jtag_driver_uninstall();
|
||||||
|
if (err == ESP_OK)
|
||||||
|
{
|
||||||
|
ESP_LOGI("[SERIAL]", "usb_serial_jtag driver uninstalled");
|
||||||
|
}
|
||||||
|
else if (err != ESP_ERR_INVALID_STATE)
|
||||||
|
{
|
||||||
|
ESP_LOGW("[SERIAL]", "usb_serial_jtag_driver_uninstall returned %s", esp_err_to_name(err));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// we can cancel this task once we're in cdc
|
||||||
void HandleSerialManagerTask(void *pvParameters)
|
void HandleSerialManagerTask(void *pvParameters)
|
||||||
{
|
{
|
||||||
auto const serialManager = static_cast<SerialManager *>(pvParameters);
|
auto const serialManager = static_cast<SerialManager *>(pvParameters);
|
||||||
@@ -150,17 +167,71 @@ void HandleSerialManagerTask(void *pvParameters)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SerialManager::shutdown()
|
void HandleCDCSerialManagerTask(void *pvParameters)
|
||||||
{
|
{
|
||||||
// Stop heartbeats; timer will be deleted by main if needed.
|
auto const commandManager = static_cast<CommandManager *>(pvParameters);
|
||||||
// Uninstall the USB Serial JTAG driver to free the internal USB for TinyUSB.
|
static char buffer[BUF_SIZE];
|
||||||
esp_err_t err = usb_serial_jtag_driver_uninstall();
|
auto idx = 0;
|
||||||
if (err == ESP_OK)
|
|
||||||
|
cdc_command_packet_t packet;
|
||||||
|
while (true)
|
||||||
{
|
{
|
||||||
ESP_LOGI("[SERIAL]", "usb_serial_jtag driver uninstalled");
|
if (xQueueReceive(cdcMessageQueue, &packet, portMAX_DELAY) == pdTRUE)
|
||||||
}
|
{
|
||||||
else if (err != ESP_ERR_INVALID_STATE)
|
for (auto i = 0; i < packet.len; i++)
|
||||||
{
|
{
|
||||||
ESP_LOGW("[SERIAL]", "usb_serial_jtag_driver_uninstall returned %s", esp_err_to_name(err));
|
buffer[idx++] = packet.data[i];
|
||||||
|
// if we're at the end of the buffer, try to process the command anyway
|
||||||
|
// if we've got a new line, we've finished sending the commands, process them
|
||||||
|
if (idx >= BUF_SIZE || buffer[idx - 1] == '\n' || buffer[idx - 1] == '\r')
|
||||||
|
{
|
||||||
|
buffer[idx - 1] = '\0';
|
||||||
|
const auto result = commandManager->executeFromJson(std::string_view(reinterpret_cast<const char *>(buffer)));
|
||||||
|
const auto resultMessage = result.getResult();
|
||||||
|
tud_cdc_write(resultMessage.c_str(), resultMessage.length());
|
||||||
|
tud_cdc_write_flush();
|
||||||
|
idx = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// tud_cdc_rx_cb is defined as TU_ATTR_WEAK so we can override it, we will be called back if we get some data
|
||||||
|
// but we don't want to do any processing here since we don't want to risk blocking
|
||||||
|
// grab the data and send it to a queue, a special task will process it and handle with the command manager
|
||||||
|
extern "C" void tud_cdc_rx_cb(uint8_t itf)
|
||||||
|
{
|
||||||
|
// we can void the interface number
|
||||||
|
(void)itf;
|
||||||
|
cdc_command_packet_t packet;
|
||||||
|
auto len = tud_cdc_available();
|
||||||
|
|
||||||
|
if (len > 0)
|
||||||
|
{
|
||||||
|
auto read = tud_cdc_read(packet.data, sizeof(packet.data));
|
||||||
|
if (read > 0)
|
||||||
|
{
|
||||||
|
// we should be safe here, given that the max buffer size is 64
|
||||||
|
packet.len = static_cast<uint8_t>(read);
|
||||||
|
xQueueSend(cdcMessageQueue, &packet, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts)
|
||||||
|
{
|
||||||
|
(void)itf;
|
||||||
|
(void)dtr;
|
||||||
|
(void)rts;
|
||||||
|
|
||||||
|
ESP_LOGI("[SERIAL]", "CDC line state changed: DTR=%d, RTS=%d", dtr, rts);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const *p_line_coding)
|
||||||
|
{
|
||||||
|
(void)itf;
|
||||||
|
ESP_LOGI("[SERIAL]", "CDC line coding: %" PRIu32 " bps, %d stop bits, %d parity, %d data bits",
|
||||||
|
p_line_coding->bit_rate, p_line_coding->stop_bits,
|
||||||
|
p_line_coding->parity, p_line_coding->data_bits);
|
||||||
|
}
|
||||||
@@ -18,6 +18,17 @@
|
|||||||
#include "esp_vfs_dev.h"
|
#include "esp_vfs_dev.h"
|
||||||
#include "esp_mac.h"
|
#include "esp_mac.h"
|
||||||
|
|
||||||
|
extern "C" void tud_cdc_rx_cb(uint8_t itf);
|
||||||
|
extern "C" void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts);
|
||||||
|
|
||||||
|
extern QueueHandle_t cdcMessageQueue;
|
||||||
|
|
||||||
|
struct cdc_command_packet_t
|
||||||
|
{
|
||||||
|
uint8_t len;
|
||||||
|
uint8_t data[64];
|
||||||
|
};
|
||||||
|
|
||||||
class SerialManager
|
class SerialManager
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -38,4 +49,5 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
void HandleSerialManagerTask(void *pvParameters);
|
void HandleSerialManagerTask(void *pvParameters);
|
||||||
|
void HandleCDCSerialManagerTask(void *pvParameters);
|
||||||
#endif
|
#endif
|
||||||
@@ -17,7 +17,8 @@ extern std::shared_ptr<CameraManager> cameraHandler;
|
|||||||
extern std::shared_ptr<ProjectConfig> deviceConfig;
|
extern std::shared_ptr<ProjectConfig> deviceConfig;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C"
|
||||||
|
{
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const char *get_uvc_device_name();
|
const char *get_uvc_device_name();
|
||||||
|
|||||||
@@ -28,17 +28,18 @@
|
|||||||
|
|
||||||
#include "uvc_frame_config.h"
|
#include "uvc_frame_config.h"
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C"
|
||||||
|
{
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
// Board Specific Configuration
|
// Board Specific Configuration
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
#ifdef CONFIG_TINYUSB_RHPORT_HS
|
#ifdef CONFIG_TINYUSB_RHPORT_HS
|
||||||
# define CFG_TUSB_RHPORT1_MODE OPT_MODE_DEVICE | OPT_MODE_HIGH_SPEED
|
#define CFG_TUSB_RHPORT1_MODE OPT_MODE_DEVICE | OPT_MODE_HIGH_SPEED
|
||||||
#else
|
#else
|
||||||
# define CFG_TUSB_RHPORT0_MODE OPT_MODE_DEVICE | OPT_MODE_FULL_SPEED
|
#define CFG_TUSB_RHPORT0_MODE OPT_MODE_DEVICE | OPT_MODE_FULL_SPEED
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
||||||
@@ -55,20 +56,20 @@ extern "C" {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef CFG_TUSB_OS
|
#ifndef CFG_TUSB_OS
|
||||||
#define CFG_TUSB_OS OPT_OS_FREERTOS
|
#define CFG_TUSB_OS OPT_OS_FREERTOS
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Espressif IDF requires "freertos/" prefix in include path
|
// Espressif IDF requires "freertos/" prefix in include path
|
||||||
#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3, OPT_MCU_ESP32P4)
|
#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3, OPT_MCU_ESP32P4)
|
||||||
#define CFG_TUSB_OS_INC_PATH freertos/
|
#define CFG_TUSB_OS_INC_PATH freertos/
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef CFG_TUSB_DEBUG
|
#ifndef CFG_TUSB_DEBUG
|
||||||
#define CFG_TUSB_DEBUG 0
|
#define CFG_TUSB_DEBUG 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Enable Device stack
|
// Enable Device stack
|
||||||
#define CFG_TUD_ENABLED 1
|
#define CFG_TUD_ENABLED 1
|
||||||
|
|
||||||
/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.
|
/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.
|
||||||
* Tinyusb use follows macros to declare transferring memory so that they can be put
|
* Tinyusb use follows macros to declare transferring memory so that they can be put
|
||||||
@@ -82,71 +83,54 @@ extern "C" {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef CFG_TUSB_MEM_ALIGN
|
#ifndef CFG_TUSB_MEM_ALIGN
|
||||||
#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4)))
|
#define CFG_TUSB_MEM_ALIGN __attribute__((aligned(4)))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
||||||
// DEVICE CONFIGURATION
|
// DEVICE CONFIGURATION
|
||||||
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
||||||
|
|
||||||
#ifndef CFG_TUD_ENDPOINT0_SIZE
|
#ifndef CFG_TUD_ENDPOINT0_SIZE
|
||||||
#define CFG_TUD_ENDPOINT0_SIZE 64
|
#define CFG_TUD_ENDPOINT0_SIZE 64
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//------------- CLASS -------------//
|
//------------- CLASS -------------//
|
||||||
|
|
||||||
// The number of video control interfaces
|
#define CFG_TUD_CDC 1
|
||||||
// The number of video streaming interfaces
|
|
||||||
#if CONFIG_UVC_SUPPORT_TWO_CAM
|
// CDC FIFO size of TX and RX
|
||||||
#define CFG_TUD_VIDEO 2
|
#define CFG_TUD_CDC_RX_BUFSIZE 256
|
||||||
#define CFG_TUD_VIDEO_STREAMING 2
|
#define CFG_TUD_CDC_TX_BUFSIZE 256
|
||||||
#else
|
|
||||||
#define CFG_TUD_VIDEO 1
|
// CDC Endpoint transfer buffer size, more is faster
|
||||||
#define CFG_TUD_VIDEO_STREAMING 1
|
#define CFG_TUD_CDC_EP_BUFSIZE 64
|
||||||
#endif
|
|
||||||
|
// The number of video control interfaces
|
||||||
|
// The number of video streaming interfaces
|
||||||
|
|
||||||
|
#define CFG_TUD_VIDEO 1
|
||||||
|
#define CFG_TUD_VIDEO_STREAMING 1
|
||||||
|
|
||||||
// video streaming endpoint size
|
// video streaming endpoint size
|
||||||
#ifdef UVC_CAM1_BULK_MODE
|
#ifdef UVC_CAM1_BULK_MODE
|
||||||
#if CONFIG_TINYUSB_RHPORT_HS
|
#if CONFIG_TINYUSB_RHPORT_HS
|
||||||
#define CFG_TUD_CAM1_VIDEO_STREAMING_EP_BUFSIZE 512
|
#define CFG_TUD_CAM1_VIDEO_STREAMING_EP_BUFSIZE 512
|
||||||
#else
|
#else
|
||||||
#define CFG_TUD_CAM1_VIDEO_STREAMING_EP_BUFSIZE 64
|
#define CFG_TUD_CAM1_VIDEO_STREAMING_EP_BUFSIZE 64
|
||||||
#endif
|
#endif
|
||||||
#define CFG_TUD_CAM1_VIDEO_STREAMING_BULK 1
|
#define CFG_TUD_CAM1_VIDEO_STREAMING_BULK 1
|
||||||
#else
|
#else
|
||||||
#define CFG_TUD_CAM1_VIDEO_STREAMING_BULK 0
|
#define CFG_TUD_CAM1_VIDEO_STREAMING_BULK 0
|
||||||
#if CONFIG_TINYUSB_RHPORT_HS
|
#if CONFIG_TINYUSB_RHPORT_HS
|
||||||
#define CFG_TUD_CAM1_VIDEO_STREAMING_EP_BUFSIZE 1023
|
#define CFG_TUD_CAM1_VIDEO_STREAMING_EP_BUFSIZE 1023
|
||||||
#else
|
#else
|
||||||
#define CFG_TUD_CAM1_VIDEO_STREAMING_EP_BUFSIZE 512
|
#define CFG_TUD_CAM1_VIDEO_STREAMING_EP_BUFSIZE 512
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define CFG_EXAMPLE_VIDEO_DISABLE_MJPEG (!FORMAT_MJPEG)
|
#define CFG_EXAMPLE_VIDEO_DISABLE_MJPEG (!FORMAT_MJPEG)
|
||||||
|
|
||||||
#if CONFIG_UVC_SUPPORT_TWO_CAM
|
|
||||||
#ifdef UVC_CAM2_BULK_MODE
|
|
||||||
#if CONFIG_TINYUSB_RHPORT_HS
|
|
||||||
#define CFG_TUD_CAM2_VIDEO_STREAMING_EP_BUFSIZE 512
|
|
||||||
#else
|
|
||||||
#define CFG_TUD_CAM2_VIDEO_STREAMING_EP_BUFSIZE 64
|
|
||||||
#endif
|
|
||||||
#define CFG_TUD_CAM2_VIDEO_STREAMING_BULK 1
|
|
||||||
#else
|
|
||||||
#define CFG_TUD_CAM2_VIDEO_STREAMING_BULK 0
|
|
||||||
#if CONFIG_TINYUSB_RHPORT_HS
|
|
||||||
#define CFG_TUD_CAM2_VIDEO_STREAMING_EP_BUFSIZE 1023
|
|
||||||
#else
|
|
||||||
#define CFG_TUD_CAM2_VIDEO_STREAMING_EP_BUFSIZE 512
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if CONFIG_UVC_SUPPORT_TWO_CAM
|
|
||||||
#define CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE (CFG_TUD_CAM1_VIDEO_STREAMING_EP_BUFSIZE > CFG_TUD_CAM2_VIDEO_STREAMING_EP_BUFSIZE?CFG_TUD_CAM1_VIDEO_STREAMING_EP_BUFSIZE:CFG_TUD_CAM2_VIDEO_STREAMING_EP_BUFSIZE)
|
|
||||||
#else
|
|
||||||
#define CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE CFG_TUD_CAM1_VIDEO_STREAMING_EP_BUFSIZE
|
#define CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE CFG_TUD_CAM1_VIDEO_STREAMING_EP_BUFSIZE
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,14 +65,18 @@ uint8_t const *tud_descriptor_device_cb(void)
|
|||||||
// Configuration Descriptor
|
// Configuration Descriptor
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
// String descriptor indices used in interface descriptors
|
// String descriptor indices used in interface descriptors
|
||||||
#define STRID_LANGID 0
|
#define STRID_LANGID 0
|
||||||
#define STRID_MANUFACTURER 1
|
#define STRID_MANUFACTURER 1
|
||||||
#define STRID_PRODUCT 2
|
#define STRID_PRODUCT 2
|
||||||
#define STRID_SERIAL 3
|
#define STRID_SERIAL 3
|
||||||
#define STRID_UVC_CAM1 4
|
#define STRID_UVC_CAM1 4
|
||||||
|
|
||||||
|
// Endpoint numbers for CDC
|
||||||
|
#define EPNUM_CDC_NOTIF 0x81
|
||||||
|
#define EPNUM_CDC_OUT 0x02
|
||||||
|
#define EPNUM_CDC_IN 0x82
|
||||||
// Endpoint numbers for UVC video IN endpoints (device -> host)
|
// Endpoint numbers for UVC video IN endpoints (device -> host)
|
||||||
#define EPNUM_CAM1_VIDEO_IN 0x81
|
#define EPNUM_CAM1_VIDEO_IN 0x83
|
||||||
|
|
||||||
#if CFG_TUD_CAM1_VIDEO_STREAMING_BULK
|
#if CFG_TUD_CAM1_VIDEO_STREAMING_BULK
|
||||||
|
|
||||||
@@ -113,7 +117,7 @@ uint8_t const *tud_descriptor_device_cb(void)
|
|||||||
#endif // CFG_TUD_CAM1_VIDEO_STREAMING_BULK
|
#endif // CFG_TUD_CAM1_VIDEO_STREAMING_BULK
|
||||||
|
|
||||||
// Total length of this configuration
|
// Total length of this configuration
|
||||||
#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CAM1_VIDEO_CAPTURE_DESC_LEN)
|
#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN + TUD_CAM1_VIDEO_CAPTURE_DESC_LEN)
|
||||||
|
|
||||||
// Full-speed configuration descriptor
|
// Full-speed configuration descriptor
|
||||||
static uint8_t const desc_fs_configuration[] = {
|
static uint8_t const desc_fs_configuration[] = {
|
||||||
@@ -121,6 +125,7 @@ static uint8_t const desc_fs_configuration[] = {
|
|||||||
// total_length, attributes, power_mA)
|
// total_length, attributes, power_mA)
|
||||||
// attributes: 0 = bus-powered (default). Add TUSB_DESC_CONFIG_ATT_SELF_POWERED or _REMOTE_WAKEUP if needed.
|
// attributes: 0 = bus-powered (default). Add TUSB_DESC_CONFIG_ATT_SELF_POWERED or _REMOTE_WAKEUP if needed.
|
||||||
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0, 500),
|
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0, 500),
|
||||||
|
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 6, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT, EPNUM_CDC_IN, 64),
|
||||||
// IAD for Video Control
|
// IAD for Video Control
|
||||||
#if CFG_TUD_CAM1_VIDEO_STREAMING_BULK
|
#if CFG_TUD_CAM1_VIDEO_STREAMING_BULK
|
||||||
#if CONFIG_UVC_CAM1_MULTI_FRAMESIZE
|
#if CONFIG_UVC_CAM1_MULTI_FRAMESIZE
|
||||||
@@ -235,16 +240,16 @@ uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid)
|
|||||||
// Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors.
|
// Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors.
|
||||||
// https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors
|
// https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors
|
||||||
|
|
||||||
if (!(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])))
|
if (!(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])))
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *str = string_desc_arr[index];
|
const char *str = string_desc_arr[index];
|
||||||
// Allow dynamic overrides for specific indices
|
// Allow dynamic overrides for specific indices
|
||||||
if (index == STRID_SERIAL)
|
if (index == STRID_SERIAL)
|
||||||
str = get_serial_number();
|
str = get_serial_number();
|
||||||
if (index == STRID_UVC_CAM1)
|
if (index == STRID_UVC_CAM1)
|
||||||
str = get_uvc_device_name();
|
str = get_uvc_device_name();
|
||||||
if (str == NULL)
|
if (str == NULL)
|
||||||
str = string_desc_arr[index];
|
str = string_desc_arr[index];
|
||||||
|
|||||||
@@ -36,13 +36,13 @@
|
|||||||
#define UVC_ENTITY_CAP_OUTPUT_TERMINAL 0x02
|
#define UVC_ENTITY_CAP_OUTPUT_TERMINAL 0x02
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
#if (CFG_TUD_CDC)
|
||||||
|
ITF_NUM_CDC,
|
||||||
|
ITF_NUM_CDC_DATA,
|
||||||
|
#endif
|
||||||
#if (CFG_TUD_VIDEO)
|
#if (CFG_TUD_VIDEO)
|
||||||
ITF_NUM_VIDEO_CONTROL,
|
ITF_NUM_VIDEO_CONTROL,
|
||||||
ITF_NUM_VIDEO_STREAMING,
|
ITF_NUM_VIDEO_STREAMING,
|
||||||
#if CONFIG_UVC_SUPPORT_TWO_CAM
|
|
||||||
ITF_NUM_VIDEO_CONTROL_2,
|
|
||||||
ITF_NUM_VIDEO_STREAMING_2,
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
ITF_NUM_TOTAL
|
ITF_NUM_TOTAL
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -29,9 +29,12 @@
|
|||||||
#define BLINK_GPIO (gpio_num_t) CONFIG_LED_BLINK_GPIO
|
#define BLINK_GPIO (gpio_num_t) CONFIG_LED_BLINK_GPIO
|
||||||
#define CONFIG_LED_C_PIN_GPIO (gpio_num_t) CONFIG_LED_EXTERNAL_GPIO
|
#define CONFIG_LED_C_PIN_GPIO (gpio_num_t) CONFIG_LED_EXTERNAL_GPIO
|
||||||
|
|
||||||
|
TaskHandle_t serialManagerHandle;
|
||||||
|
|
||||||
esp_timer_handle_t timerHandle;
|
esp_timer_handle_t timerHandle;
|
||||||
QueueHandle_t eventQueue = xQueueCreate(10, sizeof(SystemEvent));
|
QueueHandle_t eventQueue = xQueueCreate(10, sizeof(SystemEvent));
|
||||||
QueueHandle_t ledStateQueue = xQueueCreate(10, sizeof(uint32_t));
|
QueueHandle_t ledStateQueue = xQueueCreate(10, sizeof(uint32_t));
|
||||||
|
QueueHandle_t cdcMessageQueue = xQueueCreate(3, sizeof(cdc_command_packet_t));
|
||||||
|
|
||||||
auto *stateManager = new StateManager(eventQueue, ledStateQueue);
|
auto *stateManager = new StateManager(eventQueue, ledStateQueue);
|
||||||
auto dependencyRegistry = std::make_shared<DependencyRegistry>();
|
auto dependencyRegistry = std::make_shared<DependencyRegistry>();
|
||||||
@@ -56,6 +59,9 @@ UVCStreamManager uvcStream;
|
|||||||
auto ledManager = std::make_shared<LEDManager>(BLINK_GPIO, CONFIG_LED_C_PIN_GPIO, ledStateQueue, deviceConfig);
|
auto ledManager = std::make_shared<LEDManager>(BLINK_GPIO, CONFIG_LED_C_PIN_GPIO, ledStateQueue, deviceConfig);
|
||||||
auto *serialManager = new SerialManager(commandManager, &timerHandle, deviceConfig);
|
auto *serialManager = new SerialManager(commandManager, &timerHandle, deviceConfig);
|
||||||
|
|
||||||
|
void startWiFiMode(bool shouldCloseSerialManager);
|
||||||
|
void startWiredMode(bool shouldCloseSerialManager);
|
||||||
|
|
||||||
static void initNVSStorage()
|
static void initNVSStorage()
|
||||||
{
|
{
|
||||||
esp_err_t ret = nvs_flash_init();
|
esp_err_t ret = nvs_flash_init();
|
||||||
@@ -73,92 +79,34 @@ int websocket_logger(const char *format, va_list args)
|
|||||||
return vprintf(format, args);
|
return vprintf(format, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
void disable_serial_manager_task(TaskHandle_t serialManagerHandle)
|
void launch_streaming()
|
||||||
{
|
{
|
||||||
vTaskDelete(serialManagerHandle);
|
// Note, when switching and later right away activating UVC mode when we were previously in WiFi or Auto mode, the WiFi
|
||||||
}
|
// utilities will still be running since we've launched them with startAutoMode() -> startWiFiMode()
|
||||||
|
// we could add detection of this case, but it's probably not worth it since the next start of the device literally won't launch them
|
||||||
|
// and we're telling folks to just reboot the device anyway
|
||||||
|
// same case goes for when switching from UVC to WiFi
|
||||||
|
|
||||||
// New setup flow:
|
|
||||||
// 1. Device starts in setup mode (AP + Serial active)
|
|
||||||
// 2. User configures WiFi via serial commands
|
|
||||||
// 3. Device attempts WiFi connection while maintaining setup interfaces
|
|
||||||
// 4. Device reports connection status via serial
|
|
||||||
// 5. User explicitly starts streaming after verifying connectivity
|
|
||||||
void start_video_streaming(void *arg)
|
|
||||||
{
|
|
||||||
// Get the stored device mode
|
|
||||||
StreamingMode deviceMode = deviceConfig->getDeviceMode();
|
StreamingMode deviceMode = deviceConfig->getDeviceMode();
|
||||||
|
// if we've changed the mode from auto to something else, we can clean up serial manager
|
||||||
// Check if WiFi is actually connected, not just configured
|
// either the API endpoints or CDC will take care of further configuration
|
||||||
bool hasWifiCredentials = !deviceConfig->getWifiConfigs().empty() || strcmp(CONFIG_WIFI_SSID, "") != 0;
|
if (deviceMode == StreamingMode::WIFI)
|
||||||
bool wifiConnected = (wifiManager->GetCurrentWiFiState() == WiFiState_e::WiFiState_Connected);
|
|
||||||
|
|
||||||
if (deviceMode == StreamingMode::UVC)
|
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_GENERAL_DEFAULT_WIRED_MODE
|
startWiFiMode(true);
|
||||||
ESP_LOGI("[MAIN]", "Starting UVC streaming mode.");
|
|
||||||
ESP_LOGI("[MAIN]", "Initializing UVC hardware...");
|
|
||||||
// If we were given the Serial task handle, stop the task and uninstall the driver
|
|
||||||
if (arg != nullptr)
|
|
||||||
{
|
|
||||||
const auto serialTaskHandle = static_cast<TaskHandle_t>(arg);
|
|
||||||
vTaskDelete(serialTaskHandle);
|
|
||||||
ESP_LOGI("[MAIN]", "Serial task deleted before UVC init");
|
|
||||||
serialManager->shutdown();
|
|
||||||
ESP_LOGI("[MAIN]", "Serial driver uninstalled");
|
|
||||||
// Leave a small gap for the host to see COM disappear
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(200));
|
|
||||||
setUsbHandoverDone(true);
|
|
||||||
}
|
|
||||||
esp_err_t ret = uvcStream.setup();
|
|
||||||
if (ret != ESP_OK)
|
|
||||||
{
|
|
||||||
ESP_LOGE("[MAIN]", "Failed to initialize UVC: %s", esp_err_to_name(ret));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
uvcStream.start();
|
|
||||||
ESP_LOGI("[MAIN]", "UVC streaming started");
|
|
||||||
return; // UVC path complete, do not fall through to WiFi
|
|
||||||
#else
|
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
else if (deviceMode == StreamingMode::UVC)
|
||||||
if ((deviceMode == StreamingMode::WIFI || deviceMode == StreamingMode::AUTO) && hasWifiCredentials && wifiConnected)
|
|
||||||
{
|
{
|
||||||
ESP_LOGI("[MAIN]", "Starting WiFi streaming mode.");
|
startWiredMode(true);
|
||||||
streamServer.startStreamServer();
|
}
|
||||||
|
else if (deviceMode == StreamingMode::AUTO)
|
||||||
|
{
|
||||||
|
// we're still in auto, the user didn't select anything yet, let's give a bit of time for them to make a choice
|
||||||
|
ESP_LOGI("[MAIN]", "No mode was selected, staying in AUTO mode. WiFi streaming will be enabled still. \nPlease select another mode if you'd like.");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (hasWifiCredentials && !wifiConnected)
|
ESP_LOGI("[MAIN]", "Unknown device mode: %d", (int)deviceMode);
|
||||||
{
|
|
||||||
ESP_LOGE("[MAIN]", "WiFi credentials configured but not connected. Try connecting first.");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ESP_LOGE("[MAIN]", "No streaming mode available. Please configure WiFi.");
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ESP_LOGI("[MAIN]", "Streaming started successfully.");
|
|
||||||
|
|
||||||
// Optionally disable serial manager after explicit streaming start
|
|
||||||
if (arg != nullptr)
|
|
||||||
{
|
|
||||||
ESP_LOGI("[MAIN]", "Disabling setup interfaces after streaming start.");
|
|
||||||
const auto serialTaskHandle = static_cast<TaskHandle_t>(arg);
|
|
||||||
disable_serial_manager_task(serialTaskHandle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Manual streaming activation - no timer needed
|
|
||||||
void activate_streaming(TaskHandle_t serialTaskHandle = nullptr)
|
|
||||||
{
|
|
||||||
start_video_streaming(serialTaskHandle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Callback for automatic startup after delay
|
// Callback for automatic startup after delay
|
||||||
@@ -170,55 +118,7 @@ void startup_timer_callback(void *arg)
|
|||||||
|
|
||||||
if (!getStartupCommandReceived() && !getStartupPaused())
|
if (!getStartupCommandReceived() && !getStartupPaused())
|
||||||
{
|
{
|
||||||
ESP_LOGI("[MAIN]", "No command received during startup delay, proceeding with automatic mode startup");
|
launch_streaming();
|
||||||
|
|
||||||
// Get the stored device mode
|
|
||||||
StreamingMode deviceMode = deviceConfig->getDeviceMode();
|
|
||||||
ESP_LOGI("[MAIN]", "Stored device mode: %d", (int)deviceMode);
|
|
||||||
|
|
||||||
// Get the serial manager handle to disable it after streaming starts
|
|
||||||
TaskHandle_t *serialHandle = getSerialManagerHandle();
|
|
||||||
TaskHandle_t serialTaskHandle = (serialHandle && *serialHandle) ? *serialHandle : nullptr;
|
|
||||||
|
|
||||||
if (deviceMode == StreamingMode::WIFI || deviceMode == StreamingMode::AUTO)
|
|
||||||
{
|
|
||||||
// For WiFi mode, check if we have credentials and are connected
|
|
||||||
bool hasWifiCredentials = !deviceConfig->getWifiConfigs().empty() || strcmp(CONFIG_WIFI_SSID, "") != 0;
|
|
||||||
bool wifiConnected = (wifiManager->GetCurrentWiFiState() == WiFiState_e::WiFiState_Connected);
|
|
||||||
|
|
||||||
ESP_LOGI("[MAIN]", "WiFi check - hasCredentials: %s, connected: %s",
|
|
||||||
hasWifiCredentials ? "true" : "false",
|
|
||||||
wifiConnected ? "true" : "false");
|
|
||||||
|
|
||||||
if (hasWifiCredentials && wifiConnected)
|
|
||||||
{
|
|
||||||
ESP_LOGI("[MAIN]", "Starting WiFi streaming automatically");
|
|
||||||
activate_streaming(serialTaskHandle);
|
|
||||||
}
|
|
||||||
else if (hasWifiCredentials && !wifiConnected)
|
|
||||||
{
|
|
||||||
ESP_LOGI("[MAIN]", "WiFi credentials exist but not connected, waiting...");
|
|
||||||
// Could retry connection here
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ESP_LOGI("[MAIN]", "No WiFi credentials, staying in setup mode");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (deviceMode == StreamingMode::UVC)
|
|
||||||
{
|
|
||||||
#ifdef CONFIG_GENERAL_DEFAULT_WIRED_MODE
|
|
||||||
ESP_LOGI("[MAIN]", "Starting UVC streaming automatically");
|
|
||||||
activate_streaming(serialTaskHandle);
|
|
||||||
#else
|
|
||||||
ESP_LOGE("[MAIN]", "UVC mode selected but CONFIG_GENERAL_DEFAULT_WIRED_MODE not enabled in build!");
|
|
||||||
ESP_LOGI("[MAIN]", "Device will stay in setup mode. Enable CONFIG_GENERAL_DEFAULT_WIRED_MODE and rebuild.");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ESP_LOGI("[MAIN]", "Unknown device mode: %d", (int)deviceMode);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -237,97 +137,77 @@ void startup_timer_callback(void *arg)
|
|||||||
timerHandle = nullptr;
|
timerHandle = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void app_main(void)
|
// Manual streaming activation
|
||||||
|
// We'll clean up the timer and handle streaming setup if called by a command
|
||||||
|
void force_activate_streaming()
|
||||||
{
|
{
|
||||||
dependencyRegistry->registerService<ProjectConfig>(DependencyType::project_config, deviceConfig);
|
// Delete the timer before it fires
|
||||||
dependencyRegistry->registerService<CameraManager>(DependencyType::camera_manager, cameraHandler);
|
// since we've got called manually
|
||||||
dependencyRegistry->registerService<WiFiManager>(DependencyType::wifi_manager, wifiManager);
|
esp_timer_delete(timerHandle);
|
||||||
dependencyRegistry->registerService<LEDManager>(DependencyType::led_manager, ledManager);
|
timerHandle = nullptr;
|
||||||
// uvc plan
|
launch_streaming();
|
||||||
// cleanup the logs - done
|
}
|
||||||
// prepare the camera to be initialized with UVC - done?
|
|
||||||
// debug uvc performance - done
|
|
||||||
|
|
||||||
// porting plan:
|
void startWiredMode(bool shouldCloseSerialManager)
|
||||||
// port the wifi manager first. - worky!!!
|
{
|
||||||
// port the logo - done
|
#ifndef CONFIG_GENERAL_DEFAULT_WIRED_MODE
|
||||||
// port preferences lib - DONE; prolly temporary
|
ESP_LOGE("[MAIN]", "UVC mode selected but the board likely does not support it.");
|
||||||
// then port the config - done, needs todos done
|
ESP_LOGI("[MAIN]", "Falling back to WiFi mode if credentials available");
|
||||||
// State Management - done
|
deviceMode = StreamingMode::WIFI;
|
||||||
// then port the led manager as this will be fairly easy - done
|
startWiFiMode();
|
||||||
// then port the mdns stuff - done
|
#else
|
||||||
// then port the camera manager - done
|
ESP_LOGI("[MAIN]", "Starting UVC streaming mode.");
|
||||||
// then port the streaming stuff (web and uvc) - done
|
if (shouldCloseSerialManager)
|
||||||
// then add ADHOC and support for more networks in wifi manager - done
|
{
|
||||||
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
ESP_LOGI("[MAIN]", "Closing serial manager task.");
|
||||||
|
vTaskDelete(serialManagerHandle);
|
||||||
|
}
|
||||||
|
|
||||||
// simplify commands - a simple dependency injection + std::function should do it - DONE
|
ESP_LOGI("[MAIN]", "Shutting down serial manager, CDC will take over in a bit.");
|
||||||
// something like
|
serialManager->shutdown();
|
||||||
// template<typename T>
|
|
||||||
// void registerService(std::shared_pointer<T> service)
|
|
||||||
// services[std::type_index(typeid(T))] = service;
|
|
||||||
// where services is an std::unordered_map<std::type_index, std::shared_pointer<void>>;
|
|
||||||
// I can then use like std::shared_ptr<T> resolve() { return services[typeid(T)]; } to get it in the command
|
|
||||||
// which can be like a second parameter of the command, like std::function<void(DiContainer &diContainer, char* jsonPayload)>
|
|
||||||
|
|
||||||
// simplify config - DONE
|
ESP_LOGI("[MAIN]", "Serial driver uninstalled");
|
||||||
// here I can decouple the loading, initializing and saving logic from the config class and move
|
// Leaving a small gap for the host to see COM disappear
|
||||||
// that into the separate modules, and have the config class only act as a container
|
vTaskDelay(pdMS_TO_TICKS(200));
|
||||||
|
setUsbHandoverDone(true);
|
||||||
|
|
||||||
// rethink led manager - we need to move the state change sending into a queue and rethink the state lighting logic - DONE
|
ESP_LOGI("[MAIN]", "Setting up UVC Streamer");
|
||||||
// also, the entire led manager needs to be moved to a task - DONE
|
|
||||||
// with that, I couuld use vtaskdelayuntil to advance and display states - DONE
|
|
||||||
// and with that, I should rethink how state management works - DONE
|
|
||||||
|
|
||||||
// rethink state management - DONE
|
esp_err_t ret = uvcStream.setup();
|
||||||
|
if (ret != ESP_OK)
|
||||||
// port serial manager - DONE
|
{
|
||||||
// instead of the UVCCDC thing - give the board 30s for serial commands and then determine if we should reboot into UVC - DONE
|
ESP_LOGE("[MAIN]", "Failed to initialize UVC: %s", esp_err_to_name(ret));
|
||||||
|
return;
|
||||||
// add endpoint to check firmware version
|
}
|
||||||
// add firmware version somewhere
|
|
||||||
// setup CI and building for other boards
|
|
||||||
// finish todos, overhaul stuff a bit
|
|
||||||
|
|
||||||
// esp_log_set_vprintf(&websocket_logger);
|
|
||||||
Logo::printASCII();
|
|
||||||
initNVSStorage();
|
|
||||||
deviceConfig->load();
|
|
||||||
ledManager->setup();
|
|
||||||
|
|
||||||
|
ESP_LOGI("[MAIN]", "Starting CDC Serial Manager Task");
|
||||||
xTaskCreate(
|
xTaskCreate(
|
||||||
HandleStateManagerTask,
|
HandleCDCSerialManagerTask,
|
||||||
"HandleLEDDisplayTask",
|
"HandleCDCSerialManagerTask",
|
||||||
1024 * 2,
|
1024 * 6,
|
||||||
stateManager,
|
commandManager.get(),
|
||||||
3,
|
1,
|
||||||
nullptr // it's fine for us not get a handle back, we don't need it
|
|
||||||
);
|
|
||||||
|
|
||||||
xTaskCreate(
|
|
||||||
HandleLEDDisplayTask,
|
|
||||||
"HandleLEDDisplayTask",
|
|
||||||
1024 * 2,
|
|
||||||
ledManager.get(),
|
|
||||||
3,
|
|
||||||
nullptr);
|
nullptr);
|
||||||
|
|
||||||
serialManager->setup();
|
ESP_LOGI("[MAIN]", "Starting UVC streaming");
|
||||||
|
|
||||||
static TaskHandle_t serialManagerHandle = nullptr;
|
uvcStream.start();
|
||||||
// Pass address of variable so xTaskCreate() stores the actual task handle
|
ESP_LOGI("[MAIN]", "UVC streaming started");
|
||||||
xTaskCreate(
|
#endif
|
||||||
HandleSerialManagerTask,
|
}
|
||||||
"HandleSerialManagerTask",
|
|
||||||
1024 * 6,
|
void startWiFiMode(bool shouldCloseSerialManager)
|
||||||
serialManager,
|
{
|
||||||
1, // we only rely on the serial manager during provisioning, we can run it slower
|
ESP_LOGI("[MAIN]", "Starting WiFi streaming mode.");
|
||||||
&serialManagerHandle);
|
if (shouldCloseSerialManager)
|
||||||
|
{
|
||||||
|
ESP_LOGI("[MAIN]", "Closing serial manager task.");
|
||||||
|
vTaskDelete(serialManagerHandle);
|
||||||
|
}
|
||||||
|
|
||||||
wifiManager->Begin();
|
wifiManager->Begin();
|
||||||
mdnsManager.start();
|
mdnsManager.start();
|
||||||
restAPI->begin();
|
restAPI->begin();
|
||||||
cameraHandler->setupCamera();
|
|
||||||
|
|
||||||
xTaskCreate(
|
xTaskCreate(
|
||||||
HandleRestAPIPollTask,
|
HandleRestAPIPollTask,
|
||||||
@@ -336,8 +216,12 @@ extern "C" void app_main(void)
|
|||||||
restAPI,
|
restAPI,
|
||||||
1, // it's the rest API, we only serve commands over it so we don't really need a higher priority
|
1, // it's the rest API, we only serve commands over it so we don't really need a higher priority
|
||||||
nullptr);
|
nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
// New flow: Device starts with a 20-second delay before automatic mode startup
|
void startSetupMode()
|
||||||
|
{
|
||||||
|
// If we're in an auto mode - Device starts with a 20-second delay before deciding on what to do
|
||||||
|
// during this time we await any commands
|
||||||
ESP_LOGI("[MAIN]", "=====================================");
|
ESP_LOGI("[MAIN]", "=====================================");
|
||||||
ESP_LOGI("[MAIN]", "STARTUP: 20-SECOND DELAY MODE ACTIVE");
|
ESP_LOGI("[MAIN]", "STARTUP: 20-SECOND DELAY MODE ACTIVE");
|
||||||
ESP_LOGI("[MAIN]", "=====================================");
|
ESP_LOGI("[MAIN]", "=====================================");
|
||||||
@@ -355,5 +239,77 @@ extern "C" void app_main(void)
|
|||||||
ESP_ERROR_CHECK(esp_timer_start_once(timerHandle, CONFIG_GENERAL_UVC_DELAY * 1000000));
|
ESP_ERROR_CHECK(esp_timer_start_once(timerHandle, CONFIG_GENERAL_UVC_DELAY * 1000000));
|
||||||
ESP_LOGI("[MAIN]", "Started 20-second startup timer");
|
ESP_LOGI("[MAIN]", "Started 20-second startup timer");
|
||||||
ESP_LOGI("[MAIN]", "Send any command within 20 seconds to enter heartbeat mode");
|
ESP_LOGI("[MAIN]", "Send any command within 20 seconds to enter heartbeat mode");
|
||||||
setSerialManagerHandle(&serialManagerHandle);
|
}
|
||||||
|
|
||||||
|
extern "C" void app_main(void)
|
||||||
|
{
|
||||||
|
dependencyRegistry->registerService<ProjectConfig>(DependencyType::project_config, deviceConfig);
|
||||||
|
dependencyRegistry->registerService<CameraManager>(DependencyType::camera_manager, cameraHandler);
|
||||||
|
dependencyRegistry->registerService<WiFiManager>(DependencyType::wifi_manager, wifiManager);
|
||||||
|
dependencyRegistry->registerService<LEDManager>(DependencyType::led_manager, ledManager);
|
||||||
|
|
||||||
|
// add endpoint to check firmware version
|
||||||
|
// add firmware version somewhere
|
||||||
|
// setup CI and building for other boards
|
||||||
|
// finish todos, overhaul stuff a bit
|
||||||
|
|
||||||
|
// todo - do we need logs over CDC? Or just commands and their results?
|
||||||
|
// esp_log_set_vprintf(&websocket_logger);
|
||||||
|
Logo::printASCII();
|
||||||
|
initNVSStorage();
|
||||||
|
deviceConfig->load();
|
||||||
|
ledManager->setup();
|
||||||
|
|
||||||
|
xTaskCreate(
|
||||||
|
HandleStateManagerTask,
|
||||||
|
"HandleStateManagerTask",
|
||||||
|
1024 * 2,
|
||||||
|
stateManager,
|
||||||
|
3,
|
||||||
|
nullptr // it's fine for us not get a handle back, we don't need it
|
||||||
|
);
|
||||||
|
|
||||||
|
xTaskCreate(
|
||||||
|
HandleLEDDisplayTask,
|
||||||
|
"HandleLEDDisplayTask",
|
||||||
|
1024 * 2,
|
||||||
|
ledManager.get(),
|
||||||
|
3,
|
||||||
|
nullptr);
|
||||||
|
|
||||||
|
cameraHandler->setupCamera();
|
||||||
|
|
||||||
|
// let's keep the serial manager running for the duration of the setup
|
||||||
|
// we'll clean it up later if need be
|
||||||
|
serialManager->setup();
|
||||||
|
xTaskCreate(
|
||||||
|
HandleSerialManagerTask,
|
||||||
|
"HandleSerialManagerTask",
|
||||||
|
1024 * 6,
|
||||||
|
serialManager,
|
||||||
|
1,
|
||||||
|
&serialManagerHandle);
|
||||||
|
|
||||||
|
StreamingMode mode = deviceConfig->getDeviceMode();
|
||||||
|
if (mode == StreamingMode::UVC)
|
||||||
|
{
|
||||||
|
// in UVC mode we only need to start the bare essentials for UVC
|
||||||
|
// we don't need any wireless communication, we can shut it down
|
||||||
|
|
||||||
|
// todo this would be the perfect place to introduce random delays
|
||||||
|
// to workaround windows usb bug
|
||||||
|
startWiredMode(true);
|
||||||
|
}
|
||||||
|
else if (mode == StreamingMode::WIFI)
|
||||||
|
{
|
||||||
|
// in Wifi mode we only need the wireless communication stuff, nothing else got started
|
||||||
|
startWiFiMode(true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// since we're in setup mode, we have to have wireless functionality on,
|
||||||
|
// so we can do wifi scanning, test connection etc
|
||||||
|
startWiFiMode(false);
|
||||||
|
startSetupMode();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user