diff --git a/boards/seed_studio/xiao_esp32s3 b/boards/seed_studio/xiao_esp32s3 index c3a29cb..c58e7d0 100644 --- a/boards/seed_studio/xiao_esp32s3 +++ b/boards/seed_studio/xiao_esp32s3 @@ -2,7 +2,16 @@ CONFIG_IDF_TARGET="esp32s3" CONFIG_IDF_TARGET_ESP32S3=y CONFIG_LED_DEBUG_GPIO=21 CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y -CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240=y +# CPU at 160MHz instead of the 240MHz in sdkconfig.base_defaults, to cut heat. +# ESP_DEFAULT_CPU_FREQ_MHZ* are the authoritative symbols; the ESP32S3_* names are legacy +# aliases. switchBoardType.py merges base and board configs by exact key, so the 240 entries +# have to be turned off explicitly here - omitting them just leaves the base values in place. +CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=n +CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_160=y +CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ=160 +CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240=n +CONFIG_ESP32S3_DEFAULT_CPU_FREQ_160=y +CONFIG_ESP32S3_DEFAULT_CPU_FREQ_MHZ=160 CONFIG_ESP32S3_SPIRAM_SUPPORT=y CONFIG_SPIRAM_MODE_OCT=y # CONFIG_ESPTOOLPY_FLASHSIZE_1MB is not set diff --git a/components/CameraManager/CameraManager/CameraManager.cpp b/components/CameraManager/CameraManager/CameraManager.cpp index 835a97a..326db64 100644 --- a/components/CameraManager/CameraManager/CameraManager.cpp +++ b/components/CameraManager/CameraManager/CameraManager.cpp @@ -48,9 +48,19 @@ void CameraManager::setupCameraPinout() ESP_LOGI(CAMERA_MANAGER_TAG, "CAM_BOARD"); #endif #if CONFIG_GENERAL_INCLUDE_UVC_MODE - xclk_freq_hz = CONFIG_CAMERA_USB_XCLK_FREQ; + // Pick the clock from the mode the device will actually run in, not from whether UVC + // support happens to be compiled in. Choosing at compile time meant every build with + // UVC enabled ran the sensor at the USB clock even in WiFi mode, which left + // CAMERA_WIFI_XCLK_FREQ dead. Mode is loaded before streaming starts, and switching + // modes already requires a reboot, so this is settled by the time the camera comes up. + if (projectConfig->getDeviceMode() == StreamingMode::UVC) + { + xclk_freq_hz = CONFIG_CAMERA_USB_XCLK_FREQ; + } #endif + ESP_LOGI(CAMERA_MANAGER_TAG, "[Camera]: XCLK set to %d Hz", xclk_freq_hz); + config = { .pin_pwdn = CONFIG_PWDN_GPIO_NUM, // CAM_PIN_PWDN, .pin_reset = CONFIG_RESET_GPIO_NUM, // CAM_PIN_RESET, diff --git a/components/wifiManager/wifiManager/wifiManager.cpp b/components/wifiManager/wifiManager/wifiManager.cpp index a63670a..b7dcb1a 100644 --- a/components/wifiManager/wifiManager/wifiManager.cpp +++ b/components/wifiManager/wifiManager/wifiManager.cpp @@ -26,9 +26,10 @@ void WiFiManagerHelpers::event_handler(void* arg, esp_event_base_t event_base, i if (s_retry_num < EXAMPLE_ESP_MAXIMUM_RETRY) { + vTaskDelay(pdMS_TO_TICKS(WIFI_RETRY_BACKOFF_MS)); esp_wifi_connect(); s_retry_num++; - ESP_LOGI(WIFI_MANAGER_TAG, "retry to connect to the AP"); + ESP_LOGI(WIFI_MANAGER_TAG, "retry %d/%d to connect to the AP", s_retry_num, EXAMPLE_ESP_MAXIMUM_RETRY); } else { @@ -51,6 +52,27 @@ WiFiManager::WiFiManager(std::shared_ptr deviceConfig, QueueHandl { } +void WiFiManager::ApplyTxPower() +{ + // esp_wifi_set_max_tx_power only takes effect once the driver is started - calling it + // before esp_wifi_start() is silently ignored. Units are 0.25dBm, valid range 8-84. + uint8_t configured = this->deviceConfig->getWiFiTxPowerConfig().power; + if (configured < 8) + configured = 8; + if (configured > 84) + configured = 84; + + if (const auto err = esp_wifi_set_max_tx_power(static_cast(configured)); err != ESP_OK) + { + ESP_LOGW(WIFI_MANAGER_TAG, "Failed to set TX power to %u: %s", configured, esp_err_to_name(err)); + return; + } + + int8_t applied = 0; + esp_wifi_get_max_tx_power(&applied); + ESP_LOGI(WIFI_MANAGER_TAG, "TX power set to %d (%d.%02d dBm)", applied, applied / 4, (applied % 4) * 25); +} + std::vector WiFiManager::ParseBSSID(std::string_view bssid_string) { return bssid_string @@ -108,8 +130,10 @@ void WiFiManager::SetCredentials(const char* ssid, const std::vector bs _wifi_cfg.sta.pmf_cfg.capable = false; _wifi_cfg.sta.pmf_cfg.required = false; - // OPTIMIZATION: Use fast scan instead of all channel scan for quicker connection - _wifi_cfg.sta.scan_method = WIFI_FAST_SCAN; + // IMPORTANT: Must be ALL_CHANNEL_SCAN for sort_method below to take effect. WIFI_FAST_SCAN + // stops at the first SSID match, so on a mesh/repeater network it latches onto whichever + // node answers the probe first - often a distant one - and association becomes a coin flip. + _wifi_cfg.sta.scan_method = WIFI_ALL_CHANNEL_SCAN; _wifi_cfg.sta.bssid_set = use_bssid; // Don't use specific BSSID _wifi_cfg.sta.channel = 0; // Auto channel detection @@ -144,12 +168,14 @@ void WiFiManager::ConnectWithHardcodedCredentials() xQueueSend(this->eventQueue, &event, 10); esp_wifi_start(); + this->ApplyTxPower(); event.value = WiFiState_e::WiFiState_Connecting; xQueueSend(this->eventQueue, &event, 10); - // Use shorter timeout for faster startup - 8 seconds should be enough for most networks - EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group, WIFI_CONNECTED_BIT | WIFI_FAIL_BIT, pdFALSE, pdFALSE, pdMS_TO_TICKS(8000)); + // Budget must cover EXAMPLE_ESP_MAXIMUM_RETRY attempts: an all-channel scan costs ~2-3s per + // attempt, so timing out earlier than that abandons retries that were about to succeed. + EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group, WIFI_CONNECTED_BIT | WIFI_FAIL_BIT, pdFALSE, pdFALSE, pdMS_TO_TICKS(18000)); /* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually * happened. */ @@ -216,12 +242,13 @@ void WiFiManager::ConnectWithStoredCredentials() ESP_LOGE(WIFI_MANAGER_TAG, "Failed to start WiFi: %s", esp_err_to_name(start_err)); continue; } + this->ApplyTxPower(); event.value = WiFiState_e::WiFiState_Connecting; xQueueSend(this->eventQueue, &event, 10); EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group, WIFI_CONNECTED_BIT | WIFI_FAIL_BIT, pdFALSE, pdFALSE, - pdMS_TO_TICKS(10000)); // 10 second timeout for faster failover + pdMS_TO_TICKS(18000)); // must cover all retries, see ConnectWithHardcodedCredentials if (bits & WIFI_CONNECTED_BIT) { ESP_LOGI(WIFI_MANAGER_TAG, "connected to ap SSID:%s", network.ssid.c_str()); diff --git a/components/wifiManager/wifiManager/wifiManager.hpp b/components/wifiManager/wifiManager/wifiManager.hpp index eab5a93..9ee11fa 100644 --- a/components/wifiManager/wifiManager/wifiManager.hpp +++ b/components/wifiManager/wifiManager/wifiManager.hpp @@ -16,7 +16,10 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" -#define EXAMPLE_ESP_MAXIMUM_RETRY 3 +#define EXAMPLE_ESP_MAXIMUM_RETRY 5 +// Spacing between reconnect attempts. Retrying with no gap burns the whole retry budget in +// under a second, which is not enough time for a busy or distant AP to answer. +#define WIFI_RETRY_BACKOFF_MS 300 #define WIFI_CONNECTED_BIT BIT0 #define WIFI_FAIL_BIT BIT1 @@ -41,6 +44,7 @@ class WiFiManager int8_t power; + void ApplyTxPower(); void SetCredentials(const char* ssid, const std::vector bssid, const char* password, bool use_bssid); void ConnectWithHardcodedCredentials(); void ConnectWithStoredCredentials();