diff --git a/bootloader_components/boot_hooks.c b/bootloader_components/boot_hooks.c index b13d3f8..c0d7cc2 100644 --- a/bootloader_components/boot_hooks.c +++ b/bootloader_components/boot_hooks.c @@ -1,6 +1,6 @@ // source: https://github.com/espressif/esp-iot-solution/blob/4730d91db70df7e6e0a3191d725ab1c5f98ff9ce/examples/usb/device/usb_webcam/bootloader_components/boot_hooks/boot_hooks.c -#ifdef CONFIG_GENERAL_WIRED_MODE +#ifdef CONFIG_GENERAL_DEFAULT_WIRED_MODE #include "esp_log.h" #include "soc/rtc_cntl_struct.h" #include "soc/usb_serial_jtag_reg.h" diff --git a/components/CameraManager/CameraManager/CameraManager.cpp b/components/CameraManager/CameraManager/CameraManager.cpp index a274965..8abb9ed 100644 --- a/components/CameraManager/CameraManager/CameraManager.cpp +++ b/components/CameraManager/CameraManager/CameraManager.cpp @@ -48,7 +48,7 @@ void CameraManager::setupCameraPinout() ESP_LOGI(CAMERA_MANAGER_TAG, "CAM_BOARD"); #endif -#if CONFIG_GENERAL_WIRED_MODE +#if CONFIG_GENERAL_DEFAULT_WIRED_MODE xclk_freq_hz = CONFIG_CAMERA_USB_XCLK_FREQ; #endif @@ -82,7 +82,7 @@ void CameraManager::setupCameraPinout() .jpeg_quality = 7, // 0-63, for OV series camera sensors, lower number means higher quality // Below 6 stability problems .fb_count = 2, // When jpeg mode is used, if fb_count more than one, the driver will work in continuous mode. .fb_location = CAMERA_FB_IN_DRAM, - .grab_mode = CAMERA_GRAB_WHEN_EMPTY, + .grab_mode = CAMERA_GRAB_LATEST, //CAMERA_GRAB_WHEN_EMPTY }; } @@ -196,7 +196,7 @@ bool CameraManager::setupCamera() return false; } -#if CONFIG_GENERAL_WIRED_MODE +#if CONFIG_GENERAL_DEFAULT_WIRED_MODE const auto temp_sensor = esp_camera_sensor_get(); // Thanks to lick_it, we discovered that OV5640 likes to overheat when diff --git a/components/ProjectConfig/ProjectConfig/Models.hpp b/components/ProjectConfig/ProjectConfig/Models.hpp index 4326344..8fb0d84 100644 --- a/components/ProjectConfig/ProjectConfig/Models.hpp +++ b/components/ProjectConfig/ProjectConfig/Models.hpp @@ -35,7 +35,17 @@ struct DeviceMode_t : BaseConfigModel void load() { - int stored_mode = this->pref->getInt("mode", 0); + // Default mode can be controlled via sdkconfig: + // - If CONFIG_GENERAL_DEFAULT_WIRED_MODE is enabled, default to UVC + // - Otherwise default to AUTO + int default_mode = +#if CONFIG_GENERAL_DEFAULT_WIRED_MODE + static_cast(StreamingMode::UVC); +#else + static_cast(StreamingMode::AUTO); +#endif + + int stored_mode = this->pref->getInt("mode", default_mode); this->mode = static_cast(stored_mode); ESP_LOGI("DeviceMode", "Loaded device mode: %d", stored_mode); } diff --git a/components/UVCStream/UVCStream/UVCStream.cpp b/components/UVCStream/UVCStream/UVCStream.cpp index 7b9cc61..96b2618 100644 --- a/components/UVCStream/UVCStream/UVCStream.cpp +++ b/components/UVCStream/UVCStream/UVCStream.cpp @@ -91,6 +91,31 @@ static uvc_fb_t *UVCStreamHelpers::camera_fb_get_cb(void *cb_ctx) return nullptr; } +//-------------------------------------------------------------------------------------------------------------- + // Pace frames to exactly 60 fps (drop extras). Uses fixed-point accumulator + // to achieve an exact average of 60.000 fps without drifting. + static int64_t next_deadline_us = 0; + static int rem_acc = 0; // remainder accumulator for 1e6 % fps distribution + constexpr int target_fps = 60; + constexpr int64_t us_per_sec = 1000000LL; + constexpr int base_interval_us = us_per_sec / target_fps; // 16666 + constexpr int rem_us = us_per_sec % target_fps; // 40 + + const int64_t now_us = esp_timer_get_time(); + if (next_deadline_us == 0) + { + // First frame: allow immediately and schedule next slot from now + next_deadline_us = now_us; + } + if (now_us < next_deadline_us) + { + // Too early for next frame: drop this camera buffer + esp_camera_fb_return(s_fb.cam_fb_p); + s_fb.cam_fb_p = nullptr; + return nullptr; + } +//-------------------------------------------------------------------------------------------------------------- + s_fb.uvc_fb.buf = s_fb.cam_fb_p->buf; s_fb.uvc_fb.len = s_fb.cam_fb_p->len; s_fb.uvc_fb.width = s_fb.cam_fb_p->width; @@ -105,6 +130,20 @@ static uvc_fb_t *UVCStreamHelpers::camera_fb_get_cb(void *cb_ctx) esp_camera_fb_return(s_fb.cam_fb_p); return nullptr; } + +//-------------------------------------------------------------------------------------------------------------- + // Schedule the next allowed frame time: base interval plus distributed remainder + rem_acc += rem_us; + int extra_us = 0; + if (rem_acc >= target_fps) + { + rem_acc -= target_fps; + extra_us = 1; + } + // Accumulate from the previous deadline to avoid drift; if we are badly late, catch up from now + const int64_t base_next = next_deadline_us + base_interval_us + extra_us; + next_deadline_us = (base_next < now_us) ? now_us : base_next; +//-------------------------------------------------------------------------------------------------------------- return &s_fb.uvc_fb; } @@ -119,7 +158,7 @@ static void UVCStreamHelpers::camera_fb_return_cb(uvc_fb_t *fb, void *cb_ctx) esp_err_t UVCStreamManager::setup() { -#ifndef CONFIG_GENERAL_WIRED_MODE +#ifndef CONFIG_GENERAL_DEFAULT_WIRED_MODE ESP_LOGE(UVC_STREAM_TAG, "The board does not support UVC, please, setup WiFi connection."); return ESP_FAIL; #endif diff --git a/main/Kconfig.projbuild b/main/Kconfig.projbuild index 10b4d05..f447246 100644 --- a/main/Kconfig.projbuild +++ b/main/Kconfig.projbuild @@ -6,9 +6,13 @@ endmenu menu "OpenIris: General Configuration" - config GENERAL_WIRED_MODE + config GENERAL_DEFAULT_WIRED_MODE bool "Wired mode" default false + help + Enables UVC (wired) support in the firmware. When enabled, the + default device streaming mode will be UVC unless overridden by a + saved preference. When disabled, the default mode is AUTO. config GENERAL_UVC_DELAY int "UVC delay (s)" diff --git a/main/openiris_main.cpp b/main/openiris_main.cpp index 4fbfa4a..fc9900b 100644 --- a/main/openiris_main.cpp +++ b/main/openiris_main.cpp @@ -22,7 +22,7 @@ #include #include -#ifdef CONFIG_GENERAL_WIRED_MODE +#ifdef CONFIG_GENERAL_DEFAULT_WIRED_MODE #include #endif @@ -49,7 +49,7 @@ StreamServer streamServer(80, stateManager); auto *restAPI = new RestAPI("http://0.0.0.0:81", commandManager); -#ifdef CONFIG_GENERAL_WIRED_MODE +#ifdef CONFIG_GENERAL_DEFAULT_WIRED_MODE UVCStreamManager uvcStream; #endif @@ -95,7 +95,7 @@ void start_video_streaming(void *arg) if (deviceMode == StreamingMode::UVC) { -#ifdef CONFIG_GENERAL_WIRED_MODE +#ifdef CONFIG_GENERAL_DEFAULT_WIRED_MODE 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 @@ -120,7 +120,7 @@ void start_video_streaming(void *arg) 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_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 @@ -207,12 +207,12 @@ void startup_timer_callback(void *arg) } else if (deviceMode == StreamingMode::UVC) { -#ifdef CONFIG_GENERAL_WIRED_MODE +#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_WIRED_MODE not enabled in build!"); - ESP_LOGI("[MAIN]", "Device will stay in setup mode. Enable CONFIG_GENERAL_WIRED_MODE and rebuild."); + 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 diff --git a/sdkconfig b/sdkconfig index 49a8791..1d6d4cf 100644 --- a/sdkconfig +++ b/sdkconfig @@ -514,9 +514,9 @@ CONFIG_BOOT_ROM_LOG_ALWAYS_ON=y # CONFIG_ESPTOOLPY_NO_STUB is not set # CONFIG_ESPTOOLPY_OCT_FLASH is not set CONFIG_ESPTOOLPY_FLASH_MODE_AUTO_DETECT=y -CONFIG_ESPTOOLPY_FLASHMODE_QIO=y +# CONFIG_ESPTOOLPY_FLASHMODE_QIO is not set # CONFIG_ESPTOOLPY_FLASHMODE_QOUT is not set -# CONFIG_ESPTOOLPY_FLASHMODE_DIO is not set +CONFIG_ESPTOOLPY_FLASHMODE_DIO=y # CONFIG_ESPTOOLPY_FLASHMODE_DOUT is not set CONFIG_ESPTOOLPY_FLASH_SAMPLE_MODE_STR=y CONFIG_ESPTOOLPY_FLASHMODE="dio" @@ -527,13 +527,13 @@ CONFIG_ESPTOOLPY_FLASHFREQ_80M=y CONFIG_ESPTOOLPY_FLASHFREQ="80m" # CONFIG_ESPTOOLPY_FLASHSIZE_1MB is not set # CONFIG_ESPTOOLPY_FLASHSIZE_2MB is not set -CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y -# CONFIG_ESPTOOLPY_FLASHSIZE_8MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_4MB is not set +CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y # CONFIG_ESPTOOLPY_FLASHSIZE_16MB is not set # CONFIG_ESPTOOLPY_FLASHSIZE_32MB is not set # CONFIG_ESPTOOLPY_FLASHSIZE_64MB is not set # CONFIG_ESPTOOLPY_FLASHSIZE_128MB is not set -CONFIG_ESPTOOLPY_FLASHSIZE="4MB" +CONFIG_ESPTOOLPY_FLASHSIZE="8MB" # CONFIG_ESPTOOLPY_HEADER_FLASHSIZE_UPDATE is not set CONFIG_ESPTOOLPY_BEFORE_RESET=y # CONFIG_ESPTOOLPY_BEFORE_NORESET is not set @@ -570,7 +570,7 @@ CONFIG_ENV_GPIO_OUT_RANGE_MAX=48 # # OpenIris: General Configuration # -CONFIG_GENERAL_WIRED_MODE=y +# CONFIG_GENERAL_DEFAULT_WIRED_MODE is not set CONFIG_GENERAL_UVC_DELAY=30 # end of OpenIris: General Configuration @@ -595,32 +595,32 @@ CONFIG_WIFI_AP_PASSWORD="12345678" # OpenIris: LED Configuration # CONFIG_LED_BLINK_GPIO=8 -CONFIG_LED_EXTERNAL_GPIO=1 +CONFIG_LED_EXTERNAL_GPIO=9 CONFIG_LED_EXTERNAL_CONTROL=y -CONFIG_LED_EXTERNAL_PWM_FREQ=5000 +CONFIG_LED_EXTERNAL_PWM_FREQ=20000 CONFIG_LED_EXTERNAL_PWM_DUTY_CYCLE=100 # end of OpenIris: LED Configuration # # Camera sensor pinout configuration # -CONFIG_CAMERA_MODULE_NAME="SWROOM_BABBLE_S3" +CONFIG_CAMERA_MODULE_NAME="FaceFocusVR_Face" CONFIG_PWDN_GPIO_NUM=-1 CONFIG_RESET_GPIO_NUM=-1 -CONFIG_XCLK_GPIO_NUM=4 -CONFIG_SIOD_GPIO_NUM=48 -CONFIG_SIOC_GPIO_NUM=47 -CONFIG_Y9_GPIO_NUM=13 -CONFIG_Y8_GPIO_NUM=5 -CONFIG_Y7_GPIO_NUM=6 -CONFIG_Y6_GPIO_NUM=15 -CONFIG_Y5_GPIO_NUM=17 -CONFIG_Y4_GPIO_NUM=8 -CONFIG_Y3_GPIO_NUM=18 -CONFIG_Y2_GPIO_NUM=16 -CONFIG_VSYNC_GPIO_NUM=21 -CONFIG_HREF_GPIO_NUM=14 -CONFIG_PCLK_GPIO_NUM=7 +CONFIG_XCLK_GPIO_NUM=10 +CONFIG_SIOD_GPIO_NUM=40 +CONFIG_SIOC_GPIO_NUM=39 +CONFIG_Y9_GPIO_NUM=48 +CONFIG_Y8_GPIO_NUM=11 +CONFIG_Y7_GPIO_NUM=12 +CONFIG_Y6_GPIO_NUM=14 +CONFIG_Y5_GPIO_NUM=16 +CONFIG_Y4_GPIO_NUM=18 +CONFIG_Y3_GPIO_NUM=17 +CONFIG_Y2_GPIO_NUM=15 +CONFIG_VSYNC_GPIO_NUM=38 +CONFIG_HREF_GPIO_NUM=47 +CONFIG_PCLK_GPIO_NUM=13 # end of Camera sensor pinout configuration # @@ -1155,21 +1155,19 @@ CONFIG_SPIRAM=y # # SPI RAM config # -CONFIG_SPIRAM_MODE_QUAD=y -# CONFIG_SPIRAM_MODE_OCT is not set +# CONFIG_SPIRAM_MODE_QUAD is not set +CONFIG_SPIRAM_MODE_OCT=y CONFIG_SPIRAM_TYPE_AUTO=y -# CONFIG_SPIRAM_TYPE_ESPPSRAM16 is not set -# CONFIG_SPIRAM_TYPE_ESPPSRAM32 is not set # CONFIG_SPIRAM_TYPE_ESPPSRAM64 is not set CONFIG_SPIRAM_CLK_IO=30 CONFIG_SPIRAM_CS_IO=26 # CONFIG_SPIRAM_XIP_FROM_PSRAM is not set # CONFIG_SPIRAM_FETCH_INSTRUCTIONS is not set # CONFIG_SPIRAM_RODATA is not set -# CONFIG_SPIRAM_SPEED_120M is not set CONFIG_SPIRAM_SPEED_80M=y # CONFIG_SPIRAM_SPEED_40M is not set CONFIG_SPIRAM_SPEED=80 +# CONFIG_SPIRAM_ECC_ENABLE is not set CONFIG_SPIRAM_BOOT_INIT=y CONFIG_SPIRAM_PRE_CONFIGURE_MEMORY_PROTECTION=y # CONFIG_SPIRAM_IGNORE_NOTFOUND is not set @@ -2242,7 +2240,7 @@ CONFIG_FRAMESIZE_QVGA=y # CONFIG_FRAMESIZE_SVGA is not set # CONFIG_FRAMESIZE_HD is not set # CONFIG_FRAMESIZE_FHD is not set -CONFIG_UVC_CAM1_FRAMERATE=90 +CONFIG_UVC_CAM1_FRAMERATE=60 CONFIG_UVC_CAM1_FRAMESIZE_WIDTH=240 CONFIG_UVC_CAM1_FRAMESIZE_HEIGT=240 CONFIG_UVC_CAM1_MULTI_FRAMESIZE=y @@ -2257,7 +2255,7 @@ CONFIG_UVC_CAM1_MULTI_FRAMESIZE=y # CONFIG_UVC_MULTI_FRAME_WIDTH_1=240 CONFIG_UVC_MULTI_FRAME_HEIGHT_1=240 -CONFIG_UVC_MULTI_FRAME_FPS_1=90 +CONFIG_UVC_MULTI_FRAME_FPS_1=60 # end of FRAME_SIZE_1 # @@ -2265,7 +2263,7 @@ CONFIG_UVC_MULTI_FRAME_FPS_1=90 # CONFIG_UVC_MULTI_FRAME_WIDTH_2=240 CONFIG_UVC_MULTI_FRAME_HEIGHT_2=240 -CONFIG_UVC_MULTI_FRAME_FPS_2=90 +CONFIG_UVC_MULTI_FRAME_FPS_2=60 # end of FRAME_SIZE_2 # @@ -2273,7 +2271,7 @@ CONFIG_UVC_MULTI_FRAME_FPS_2=90 # CONFIG_UVC_MULTI_FRAME_WIDTH_3=240 CONFIG_UVC_MULTI_FRAME_HEIGHT_3=240 -CONFIG_UVC_MULTI_FRAME_FPS_3=90 +CONFIG_UVC_MULTI_FRAME_FPS_3=60 # end of FRAME_SIZE_3 # end of UVC_MULTI_FRAME_CONFIG @@ -2386,9 +2384,9 @@ CONFIG_LOG_BOOTLOADER_LEVEL_INFO=y CONFIG_LOG_BOOTLOADER_LEVEL=3 # CONFIG_APP_ROLLBACK_ENABLE is not set # CONFIG_FLASH_ENCRYPTION_ENABLED is not set -CONFIG_FLASHMODE_QIO=y +# CONFIG_FLASHMODE_QIO is not set # CONFIG_FLASHMODE_QOUT is not set -# CONFIG_FLASHMODE_DIO is not set +CONFIG_FLASHMODE_DIO=y # CONFIG_FLASHMODE_DOUT is not set CONFIG_MONITOR_BAUD=115200 # CONFIG_OPTIMIZATION_LEVEL_DEBUG is not set diff --git a/sdkconfig.base_defaults b/sdkconfig.base_defaults index 98f6833..d624357 100644 --- a/sdkconfig.base_defaults +++ b/sdkconfig.base_defaults @@ -570,7 +570,7 @@ CONFIG_ENV_GPIO_OUT_RANGE_MAX=48 # # OpenIris: General Configuration # -# CONFIG_GENERAL_WIRED_MODE is not set +# CONFIG_GENERAL_DEFAULT_WIRED_MODE is not set # CONFIG_GENERAL_UVC_DELAY is not set # end of OpenIris: General Configuration @@ -2242,7 +2242,7 @@ CONFIG_FRAMESIZE_QVGA=y # CONFIG_FRAMESIZE_SVGA is not set # CONFIG_FRAMESIZE_HD is not set # CONFIG_FRAMESIZE_FHD is not set -CONFIG_UVC_CAM1_FRAMERATE=90 +CONFIG_UVC_CAM1_FRAMERATE=60 CONFIG_UVC_CAM1_FRAMESIZE_WIDTH=240 CONFIG_UVC_CAM1_FRAMESIZE_HEIGT=240 CONFIG_UVC_CAM1_MULTI_FRAMESIZE=y @@ -2257,7 +2257,7 @@ CONFIG_UVC_CAM1_MULTI_FRAMESIZE=y # CONFIG_UVC_MULTI_FRAME_WIDTH_1=240 CONFIG_UVC_MULTI_FRAME_HEIGHT_1=240 -CONFIG_UVC_MULTI_FRAME_FPS_1=90 +CONFIG_UVC_MULTI_FRAME_FPS_1=60 # end of FRAME_SIZE_1 # @@ -2265,7 +2265,7 @@ CONFIG_UVC_MULTI_FRAME_FPS_1=90 # CONFIG_UVC_MULTI_FRAME_WIDTH_2=240 CONFIG_UVC_MULTI_FRAME_HEIGHT_2=240 -CONFIG_UVC_MULTI_FRAME_FPS_2=90 +CONFIG_UVC_MULTI_FRAME_FPS_2=60 # end of FRAME_SIZE_2 # @@ -2273,7 +2273,7 @@ CONFIG_UVC_MULTI_FRAME_FPS_2=90 # CONFIG_UVC_MULTI_FRAME_WIDTH_3=240 CONFIG_UVC_MULTI_FRAME_HEIGHT_3=240 -CONFIG_UVC_MULTI_FRAME_FPS_3=90 +CONFIG_UVC_MULTI_FRAME_FPS_3=60 # end of FRAME_SIZE_3 # end of UVC_MULTI_FRAME_CONFIG diff --git a/sdkconfig.board.facefocusvr_eye b/sdkconfig.board.facefocusvr_eye index 0ee0a7e..0812a00 100644 --- a/sdkconfig.board.facefocusvr_eye +++ b/sdkconfig.board.facefocusvr_eye @@ -59,4 +59,4 @@ CONFIG_LED_EXTERNAL_GPIO=9 CONFIG_LED_EXTERNAL_PWM_FREQ=20000 CONFIG_LED_EXTERNAL_PWM_DUTY_CYCLE=50 CONFIG_CAMERA_USB_XCLK_FREQ=23000000 -CONFIG_GENERAL_WIRED_MODE=y \ No newline at end of file +CONFIG_GENERAL_DEFAULT_WIRED_MODE=y \ No newline at end of file diff --git a/sdkconfig.board.facefocusvr_face b/sdkconfig.board.facefocusvr_face index 5006bae..54a80b2 100644 --- a/sdkconfig.board.facefocusvr_face +++ b/sdkconfig.board.facefocusvr_face @@ -59,4 +59,4 @@ CONFIG_LED_EXTERNAL_GPIO=9 CONFIG_LED_EXTERNAL_PWM_FREQ=20000 CONFIG_LED_EXTERNAL_PWM_DUTY_CYCLE=100 CONFIG_CAMERA_USB_XCLK_FREQ=23000000 -CONFIG_GENERAL_WIRED_MODE=y \ No newline at end of file +CONFIG_GENERAL_DEFAULT_WIRED_MODE=y \ No newline at end of file diff --git a/sdkconfig.board.project_babble b/sdkconfig.board.project_babble index 1ef150a..a598200 100644 --- a/sdkconfig.board.project_babble +++ b/sdkconfig.board.project_babble @@ -51,4 +51,4 @@ CONFIG_LED_EXTERNAL_PWM_FREQ=5000 CONFIG_LED_EXTERNAL_PWM_DUTY_CYCLE=100 CONFIG_LED_EXTERNAL_GPIO=1 CONFIG_CAMERA_USB_XCLK_FREQ=23000000 -CONFIG_GENERAL_WIRED_MODE=y \ No newline at end of file +# CONFIG_GENERAL_DEFAULT_WIRED_MODE is not set \ No newline at end of file diff --git a/sdkconfig.board.xiao-esp32s3 b/sdkconfig.board.xiao-esp32s3 index 8c11ad3..cec4efd 100644 --- a/sdkconfig.board.xiao-esp32s3 +++ b/sdkconfig.board.xiao-esp32s3 @@ -56,4 +56,4 @@ CONFIG_SPIRAM_SPEED=80 CONFIG_SPIRAM_SPEED_80M=y # CONFIG_LED_EXTERNAL_CONTROL is not set CONFIG_CAMERA_USB_XCLK_FREQ=23000000 -CONFIG_GENERAL_WIRED_MODE=y \ No newline at end of file +# CONFIG_GENERAL_DEFAULT_WIRED_MODE is not set \ No newline at end of file