[esp32_hosted][esp32_ble] Support esp_hosted 3.x alongside 2.x, keep builds on 2.12.13 for now (#19621)

This commit is contained in:
Jonathan Swoboda
2026-09-28 17:08:06 -04:00
committed by GitHub
parent 13c27429a4
commit 89cc689864
9 changed files with 259 additions and 51 deletions
+7 -2
View File
@@ -474,12 +474,17 @@ def final_validation(config: ConfigType) -> None:
# Check if hosted bluetooth is being used
if "esp32_hosted" in full_config:
from esphome.components.esp32_hosted import uses_esp_hosted_3x
add_idf_sdkconfig_option("CONFIG_BT_CLASSIC_ENABLED", False)
add_idf_sdkconfig_option("CONFIG_BT_BLE_ENABLED", True)
add_idf_sdkconfig_option("CONFIG_BT_BLUEDROID_ENABLED", True)
add_idf_sdkconfig_option("CONFIG_BT_CONTROLLER_DISABLED", True)
add_idf_sdkconfig_option("CONFIG_ESP_HOSTED_ENABLE_BT_BLUEDROID", True)
add_idf_sdkconfig_option("CONFIG_ESP_HOSTED_BLUEDROID_HCI_VHCI", True)
if uses_esp_hosted_3x():
add_idf_sdkconfig_option("CONFIG_ESP_HOSTED_HOST_FEAT_BT", True)
else:
add_idf_sdkconfig_option("CONFIG_ESP_HOSTED_ENABLE_BT_BLUEDROID", True)
add_idf_sdkconfig_option("CONFIG_ESP_HOSTED_BLUEDROID_HCI_VHCI", True)
# Check if BLE Client is needed (via esp32_ble_tracker or esp32_ble_client)
has_ble_client = (
+34 -10
View File
@@ -6,16 +6,21 @@
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
#ifndef CONFIG_ESP_HOSTED_ENABLE_BT_BLUEDROID
#ifndef CONFIG_BT_CONTROLLER_DISABLED
#include <esp_bt.h>
#else
#include "esphome/components/watchdog/watchdog.h"
#include <cinttypes>
extern "C" {
#include <esp_hosted.h>
#ifndef CONFIG_ESP_HOSTED_HOST_FEAT_BT
#include <esp_hosted_misc.h>
#include <esp_hosted_bluedroid.h>
#endif
}
#ifdef CONFIG_ESP_HOSTED_HOST_FEAT_BT
#include <esp_hosted_bt_host_stack.h>
#endif
#endif
#include <esp_bt_device.h>
#include <esp_bt_main.h>
@@ -35,7 +40,7 @@ namespace esphome::esp32_ble {
static const char *const TAG = "esp32_ble";
#ifdef CONFIG_ESP_HOSTED_ENABLE_BT_BLUEDROID
#ifdef CONFIG_BT_CONTROLLER_DISABLED
// Bringing up the remote BT controller issues synchronous RPCs to the
// co-processor with 5 second response timeouts, and the default task watchdog
// is also 5 seconds. If the co-processor firmware does not answer (for example
@@ -43,8 +48,9 @@ static const char *const TAG = "esp32_ble";
// device before the RPC could return an error, causing a boot loop. Raise the
// watchdog for the duration of the bring-up so failures surface as error
// returns instead. 60 seconds covers the worst case: transport reconnect
// (up to ~20s), version preflight (1s), controller init/enable (5s each) and
// the bluedroid host bring-up over the hosted HCI transport.
// (up to ~20s), version preflight (1s), the controller init retry window
// (5s of 5s RPCs), controller enable (5s) and the bluedroid host bring-up
// over the hosted HCI transport.
static constexpr uint32_t HOSTED_BT_WDT_TIMEOUT_MS = 60000;
#endif
@@ -202,10 +208,10 @@ void ESP32BLE::advertising_init_() {
bool ESP32BLE::ble_setup_() {
esp_err_t err;
#ifdef CONFIG_ESP_HOSTED_ENABLE_BT_BLUEDROID
#ifdef CONFIG_BT_CONTROLLER_DISABLED
watchdog::WatchdogManager wdt(HOSTED_BT_WDT_TIMEOUT_MS);
#endif
#ifndef CONFIG_ESP_HOSTED_ENABLE_BT_BLUEDROID
#ifndef CONFIG_BT_CONTROLLER_DISABLED
if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_ENABLED) {
// start bt controller
if (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_IDLE) {
@@ -239,8 +245,7 @@ bool ESP32BLE::ble_setup_() {
}
// Fast preflight (1 second RPC timeout): verifies the co-processor answers
// RPCs at all before the 5 second timeout BT controller RPCs below, and
// before hosted_hci_bluedroid_open(), which aborts if the transport is down.
// RPCs at all before the 5 second timeout BT controller RPCs below.
esp_hosted_coprocessor_fwver_t fw_ver{};
if (esp_hosted_get_coprocessor_fwversion(&fw_ver) != ESP_OK) {
ESP_LOGE(TAG, "Co-processor not responding; BLE disabled. Update its firmware with the esp32_hosted "
@@ -249,6 +254,19 @@ bool ESP32BLE::ble_setup_() {
}
ESP_LOGD(TAG, "Co-processor firmware %" PRIu32 ".%" PRIu32 ".%" PRIu32, fw_ver.major1, fw_ver.minor1, fw_ver.patch1);
#ifdef CONFIG_ESP_HOSTED_HOST_FEAT_BT
esp_hosted_bt_host_stack_cfg_t bt_cfg{};
bt_cfg.stack = ESP_HOSTED_BT_HOST_STACK_BLUEDROID;
bt_cfg.bring_up_controller = true;
bt_cfg.controller_ready_timeout_ms = EH_BT_CTRL_DEFAULT_READY_TIMEOUT_MS;
if (esp_hosted_bt_host_stack_setup(&bt_cfg) != ESP_OK) {
ESP_LOGE(TAG,
"BT controller bring-up failed; co-processor firmware %" PRIu32 ".%" PRIu32 ".%" PRIu32
" may lack BT support. Update it with the esp32_hosted update component; BLE disabled",
fw_ver.major1, fw_ver.minor1, fw_ver.patch1);
return false;
}
#else
if (esp_hosted_bt_controller_init() != ESP_OK) {
ESP_LOGE(TAG,
"BT controller init failed; co-processor firmware %" PRIu32 ".%" PRIu32 ".%" PRIu32
@@ -273,6 +291,7 @@ bool ESP32BLE::ble_setup_() {
.register_host_callback = hosted_hci_bluedroid_register_host_callback,
};
esp_bluedroid_attach_hci_driver(&operations);
#endif
#endif
err = esp_bluedroid_init();
@@ -393,7 +412,7 @@ bool ESP32BLE::ble_setup_() {
}
bool ESP32BLE::ble_dismantle_() {
#ifdef CONFIG_ESP_HOSTED_ENABLE_BT_BLUEDROID
#ifdef CONFIG_BT_CONTROLLER_DISABLED
// Same 5 second RPCs as the bring-up path; see HOSTED_BT_WDT_TIMEOUT_MS
watchdog::WatchdogManager wdt(HOSTED_BT_WDT_TIMEOUT_MS);
#endif
@@ -416,7 +435,7 @@ bool ESP32BLE::ble_dismantle_() {
ESP_LOGD(TAG, "Already deinitialized");
}
#ifndef CONFIG_ESP_HOSTED_ENABLE_BT_BLUEDROID
#ifndef CONFIG_BT_CONTROLLER_DISABLED
if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_IDLE) {
// stop bt controller
if (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_ENABLED) {
@@ -440,6 +459,11 @@ bool ESP32BLE::ble_dismantle_() {
return false;
}
}
#elif defined(CONFIG_ESP_HOSTED_HOST_FEAT_BT)
if (esp_hosted_bt_host_stack_teardown() != ESP_OK) {
ESP_LOGE(TAG, "esp_hosted_bt_host_stack_teardown failed");
return false;
}
#else
if (esp_hosted_bt_controller_disable() != ESP_OK) {
ESP_LOGE(TAG, "esp_hosted_bt_controller_disable failed");
@@ -3,7 +3,7 @@
#ifdef USE_ESP32
#ifndef CONFIG_ESP_HOSTED_ENABLE_BT_BLUEDROID
#ifndef CONFIG_BT_CONTROLLER_DISABLED
#include <esp_bt.h>
#endif
#include <esp_bt_main.h>
@@ -35,7 +35,7 @@ void ESP32BLEBeacon::dump_config() {
}
}
*bpos = '\0';
#ifndef CONFIG_ESP_HOSTED_ENABLE_BT_BLUEDROID
#ifndef CONFIG_BT_CONTROLLER_DISABLED
ESP_LOGCONFIG(TAG,
" UUID: %s, Major: %u, Minor: %u, Min Interval: %ums, Max Interval: %ums, Measured Power: %d"
", TX Power: %ddBm",
@@ -81,7 +81,7 @@ void ESP32BLEBeacon::on_advertise_() {
ibeacon_adv_data.ibeacon_vendor.measured_power = static_cast<uint8_t>(this->measured_power_);
esp_err_t err;
#ifndef CONFIG_ESP_HOSTED_ENABLE_BT_BLUEDROID
#ifndef CONFIG_BT_CONTROLLER_DISABLED
ESP_LOGD(TAG, "Setting BLE TX power");
err = esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_ADV, this->tx_power_);
if (err != ESP_OK) {
@@ -5,7 +5,7 @@
#ifdef USE_ESP32
#ifndef CONFIG_ESP_HOSTED_ENABLE_BT_BLUEDROID
#ifndef CONFIG_BT_CONTROLLER_DISABLED
#include <esp_bt.h>
#endif
#include <esp_gap_ble_api.h>
@@ -47,7 +47,7 @@ class ESP32BLEBeacon final : public Component {
void set_min_interval(uint16_t val) { this->min_interval_ = val; }
void set_max_interval(uint16_t val) { this->max_interval_ = val; }
void set_measured_power(int8_t val) { this->measured_power_ = val; }
#ifndef CONFIG_ESP_HOSTED_ENABLE_BT_BLUEDROID
#ifndef CONFIG_BT_CONTROLLER_DISABLED
void set_tx_power(esp_power_level_t val) { this->tx_power_ = val; }
#endif
void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param);
@@ -61,7 +61,7 @@ class ESP32BLEBeacon final : public Component {
uint16_t min_interval_{};
uint16_t max_interval_{};
int8_t measured_power_{};
#ifndef CONFIG_ESP_HOSTED_ENABLE_BT_BLUEDROID
#ifndef CONFIG_BT_CONTROLLER_DISABLED
esp_power_level_t tx_power_{};
#endif
esp_ble_adv_params_t ble_adv_params_;
@@ -10,7 +10,7 @@
#include <nvs_flash.h>
#include <freertos/FreeRTOSConfig.h>
#include <esp_bt_main.h>
#ifndef CONFIG_ESP_HOSTED_ENABLE_BT_BLUEDROID
#ifndef CONFIG_BT_CONTROLLER_DISABLED
#include <esp_bt.h>
#endif
#include <freertos/task.h>
@@ -7,7 +7,7 @@
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
#ifndef CONFIG_ESP_HOSTED_ENABLE_BT_BLUEDROID
#ifndef CONFIG_BT_CONTROLLER_DISABLED
#include <esp_bt.h>
#endif
#include <esp_bt_defs.h>
@@ -635,7 +635,7 @@ void ESP32BLETracker::log_unexpected_state_(const char *operation, ScannerState
#ifdef USE_ESP32_BLE_SOFTWARE_COEXISTENCE
void ESP32BLETracker::update_coex_preference_(bool force_ble) {
#ifndef CONFIG_ESP_HOSTED_ENABLE_BT_BLUEDROID
#ifndef CONFIG_BT_CONTROLLER_DISABLED
if (force_ble && !this->coex_prefer_ble_) {
ESP_LOGD(TAG, "Setting coexistence to Bluetooth to make connection.");
this->coex_prefer_ble_ = true;
@@ -645,7 +645,7 @@ void ESP32BLETracker::update_coex_preference_(bool force_ble) {
this->coex_prefer_ble_ = false;
esp_coex_preference_set(ESP_COEX_PREFER_BALANCE); // Reset to default
}
#endif // CONFIG_ESP_HOSTED_ENABLE_BT_BLUEDROID
#endif // CONFIG_BT_CONTROLLER_DISABLED
}
#endif
+195 -24
View File
@@ -1,5 +1,6 @@
import os
from pathlib import Path
import re
from esphome import pins
from esphome.components import esp32
@@ -7,15 +8,22 @@ from esphome.components.const import CONF_SLOT, CONF_USE_PSRAM
import esphome.config_validation as cv
from esphome.const import (
CONF_CLK_PIN,
CONF_COMPONENTS,
CONF_CS_PIN,
CONF_FRAMEWORK,
CONF_FREQUENCY,
CONF_MISO_PIN,
CONF_MOSI_PIN,
CONF_NAME,
CONF_REF,
CONF_RESET_PIN,
CONF_TYPE,
CONF_VARIANT,
KEY_ESP32,
)
from esphome.core import CORE
from esphome.cpp_generator import add_define
import esphome.final_validate as fv
from esphome.types import ConfigType
CODEOWNERS = ["@swoboda1337"]
@@ -23,6 +31,9 @@ DEPENDENCIES = ["esp32"]
# esp32_ble raises the task watchdog around the remote BT controller bring-up
AUTO_LOAD = ["watchdog"]
# 3.x is opt-in via a pin under esp32.framework.components (needs ESP-IDF 5.5)
ESP_HOSTED_COMPONENT = "espressif/esp_hosted"
CONF_ACTIVE_HIGH = "active_high"
CONF_BUS_WIDTH = "bus_width"
CONF_CMD_PIN = "cmd_pin"
@@ -145,6 +156,34 @@ CONFIG_SCHEMA = cv.typed_schema(
)
# Version specs that stay within one major (exact, ^, ~, ~=); other ranges are 3.x
_PINNED_MAJOR = re.compile(r"^(?:==|\^|~=|~)?(\d+)(?:\.(?:\d+|\*))*$")
def user_esp_hosted_major() -> int | None:
"""Major version of a user-pinned esp_hosted, or None without a pin."""
try:
full_config = fv.full_config.get()
except LookupError:
full_config = CORE.config
esp32_config = full_config.get(KEY_ESP32) or {}
for component in esp32_config.get(CONF_FRAMEWORK, {}).get(CONF_COMPONENTS, []):
if component.get(CONF_NAME) != ESP_HOSTED_COMPONENT:
continue
ref = component.get(CONF_REF, "").strip()
if not ref:
return 2
if match := _PINNED_MAJOR.match(ref):
return int(match.group(1))
return 3
return None
def uses_esp_hosted_3x() -> bool:
"""Whether the user pinned esp_hosted 3.x."""
return (major := user_esp_hosted_major()) is not None and major >= 3
def _final_validate(config: ConfigType) -> None:
# The esp_hosted releases compatible with older ESP-IDF versions crash at
# boot with a heap double free in the SDIO RX path (fixed in esp_hosted
@@ -155,12 +194,34 @@ def _final_validate(config: ConfigType) -> None:
"Remove the framework version from your configuration to use the "
"recommended version, or pin a version at or above 5.3."
)
if (major := user_esp_hosted_major()) is None or major < 3:
return
if idf_ver < cv.Version(5, 5, 0):
raise cv.Invalid(
f"esp_hosted 3.x requires ESP-IDF 5.5 or newer, got {idf_ver}. "
f"Remove the {ESP_HOSTED_COMPONENT} pin from esp32.framework."
"components to stay on the 2.x line, or use ESP-IDF 5.5 or newer."
)
if not config[CONF_ACTIVE_HIGH]:
raise cv.Invalid(
"esp_hosted 3.x always parks the reset line high with a low pulse, so "
"'active_high: false' cannot be expressed on it. Remove the "
f"{ESP_HOSTED_COMPONENT} pin from esp32.framework.components to stay "
"on the 2.x line."
)
if config[CONF_TYPE] == "sdio" and config[CONF_BUS_WIDTH] == 1:
raise cv.Invalid(
"esp_hosted 3.x cannot be built with a 1-bit SDIO bus "
"(espressif/esp-hosted-mcu#245). Remove the "
f"{ESP_HOSTED_COMPONENT} pin from esp32.framework.components to stay "
"on the 2.x line, or use a 4-bit bus."
)
FINAL_VALIDATE_SCHEMA = _final_validate
def _configure_sdio(config: ConfigType) -> None:
def _configure_sdio_2x(config: ConfigType) -> None:
slot = config[CONF_SLOT]
esp32.add_idf_sdkconfig_option(
f"CONFIG_ESP_HOSTED_SDIO_SLOT_{slot}",
@@ -202,7 +263,42 @@ def _configure_sdio(config: ConfigType) -> None:
)
def _configure_spi(config: ConfigType) -> None:
def _configure_sdio_3x(config: ConfigType) -> None:
esp32.add_idf_sdkconfig_option("CONFIG_ESP_HOSTED_HOST_TRANSPORT_BUS_SDIO", True)
esp32.add_idf_sdkconfig_option(
f"CONFIG_ESP_HOSTED_SDIO_SLOT_{config[CONF_SLOT]}",
True,
)
esp32.add_idf_sdkconfig_option(
f"CONFIG_ESP_HOSTED_HOST_SDIO_BUS_WIDTH_{config[CONF_BUS_WIDTH]}",
True,
)
esp32.add_idf_sdkconfig_option(
"CONFIG_ESP_HOSTED_HOST_SDIO_PIN_CLK", config[CONF_CLK_PIN]
)
esp32.add_idf_sdkconfig_option(
"CONFIG_ESP_HOSTED_HOST_SDIO_PIN_CMD", config[CONF_CMD_PIN]
)
esp32.add_idf_sdkconfig_option(
"CONFIG_ESP_HOSTED_HOST_SDIO_PIN_D0", config[CONF_D0_PIN]
)
if config[CONF_BUS_WIDTH] == 4:
esp32.add_idf_sdkconfig_option(
"CONFIG_ESP_HOSTED_HOST_SDIO_PIN_D1", config[CONF_D1_PIN]
)
esp32.add_idf_sdkconfig_option(
"CONFIG_ESP_HOSTED_HOST_SDIO_PIN_D2", config[CONF_D2_PIN]
)
esp32.add_idf_sdkconfig_option(
"CONFIG_ESP_HOSTED_HOST_SDIO_PIN_D3", config[CONF_D3_PIN]
)
esp32.add_idf_sdkconfig_option(
"CONFIG_ESP_HOSTED_HOST_SDIO_CLK_KHZ",
int(config[CONF_SDIO_FREQUENCY] // 1000),
)
def _configure_spi_2x(config: ConfigType) -> None:
esp32.add_idf_sdkconfig_option("CONFIG_ESP_HOSTED_SPI_HOST_INTERFACE", True)
# SPI mode is set via per-variant choice options
variant = config[CONF_VARIANT]
@@ -250,11 +346,53 @@ def _configure_spi(config: ConfigType) -> None:
esp32.add_idf_sdkconfig_option("CONFIG_ESP_HOSTED_DR_ACTIVE_LOW", True)
async def to_code(config: ConfigType) -> None:
add_define("USE_ESP32_HOSTED")
transport = config[CONF_TYPE]
transport_prefix = "SDIO" if transport == "sdio" else "SPI"
def _configure_spi_3x(config: ConfigType) -> None:
esp32.add_idf_sdkconfig_option("CONFIG_ESP_HOSTED_HOST_TRANSPORT_BUS_SPI", True)
esp32.add_idf_sdkconfig_option(
"CONFIG_ESP_HOSTED_HOST_SPI_MODE", config[CONF_SPI_MODE]
)
esp32.add_idf_sdkconfig_option(
"CONFIG_ESP_HOSTED_HOST_SPI_CLK_MHZ", int(config[CONF_FREQUENCY] // 1e6)
)
esp32.add_idf_sdkconfig_option(
"CONFIG_ESP_HOSTED_HOST_SPI_MOSI_GPIO", config[CONF_MOSI_PIN]
)
esp32.add_idf_sdkconfig_option(
"CONFIG_ESP_HOSTED_HOST_SPI_MISO_GPIO", config[CONF_MISO_PIN]
)
esp32.add_idf_sdkconfig_option(
"CONFIG_ESP_HOSTED_HOST_SPI_CLK_GPIO", config[CONF_CLK_PIN]
)
esp32.add_idf_sdkconfig_option(
"CONFIG_ESP_HOSTED_HOST_SPI_CS_GPIO", config[CONF_CS_PIN]
)
esp32.add_idf_sdkconfig_option(
"CONFIG_ESP_HOSTED_HOST_HANDSHAKE_GPIO", config[CONF_HANDSHAKE_PIN]
)
esp32.add_idf_sdkconfig_option(
"CONFIG_ESP_HOSTED_HOST_DATA_READY_GPIO", config[CONF_DATA_READY_PIN]
)
# Handshake and data_ready polarity
if config[CONF_HANDSHAKE_ACTIVE_HIGH]:
esp32.add_idf_sdkconfig_option(
"CONFIG_ESP_HOSTED_SPI_HANDSHAKE_ACTIVE_HIGH", True
)
else:
esp32.add_idf_sdkconfig_option(
"CONFIG_ESP_HOSTED_SPI_HANDSHAKE_ACTIVE_LOW", True
)
if config[CONF_DATA_READY_ACTIVE_HIGH]:
esp32.add_idf_sdkconfig_option(
"CONFIG_ESP_HOSTED_SPI_DATAREADY_ACTIVE_HIGH", True
)
else:
esp32.add_idf_sdkconfig_option(
"CONFIG_ESP_HOSTED_SPI_DATAREADY_ACTIVE_LOW", True
)
def _configure_2x(config: ConfigType) -> None:
transport_prefix = "SDIO" if config[CONF_TYPE] == "sdio" else "SPI"
# Reset polarity
if config[CONF_ACTIVE_HIGH]:
esp32.add_idf_sdkconfig_option(
@@ -274,24 +412,11 @@ async def to_code(config: ConfigType) -> None:
f"CONFIG_SLAVE_IDF_TARGET_{config[CONF_VARIANT]}", # NOLINT
True,
)
# Transport-specific configuration
if transport == "sdio":
_configure_sdio(config)
if config[CONF_TYPE] == "sdio":
_configure_sdio_2x(config)
else:
_configure_spi(config)
# ESP-NOW-over-hosted shim: only the radio-less ESP32-P4 host needs it (see
# the note by _MAX_CUSTOM_MSG_HANDLERS). Enabled for every P4 host, not
# gated on the `espnow` component being present: the shim is tiny and the
# esp_now_* symbols/CustomRpc calls it defines require these Kconfig options
# to link whenever esp_now_hosted.cpp compiles (which is on any P4 host), so
# coupling the two keeps the build consistent. When `espnow` is absent the
# symbols are simply unused and never register a callback at runtime.
_configure_spi_2x(config)
if esp32.get_esp32_variant() == esp32.VARIANT_ESP32P4:
add_define("USE_ESP_NOW_HOSTED")
# esp_now_hosted.cpp includes esp_now.h, which esp_wifi provides
esp32.include_builtin_idf_component("esp_wifi")
# esp-hosted's CustomRpc ("peer data transfer") path — off by default.
esp32.add_idf_sdkconfig_option(
"CONFIG_ESP_HOSTED_ENABLE_PEER_DATA_TRANSFER", True
@@ -299,18 +424,64 @@ async def to_code(config: ConfigType) -> None:
esp32.add_idf_sdkconfig_option(
"CONFIG_ESP_HOSTED_MAX_CUSTOM_MSG_HANDLERS", _MAX_CUSTOM_MSG_HANDLERS
)
# Place the transport mempool in PSRAM. Required on memory-tight host
# configurations (e.g. P4 with a large LVGL UI) where the internal-RAM
# mempool allocation fails at boot with `sdio_mempool_create` assert.
if config[CONF_USE_PSRAM]:
esp32.add_idf_sdkconfig_option("CONFIG_ESP_HOSTED_MEMPOOL_PREFER_SPIRAM", True)
def _configure_3x(config: ConfigType) -> None:
esp32.add_idf_sdkconfig_option(
"CONFIG_ESP_HOSTED_HOST_RESET_GPIO", config[CONF_RESET_PIN]
)
# Co-processor variant
esp32.add_idf_sdkconfig_option(
f"CONFIG_ESP_HOSTED_CP_TARGET_{config[CONF_VARIANT]}",
True,
)
if config[CONF_TYPE] == "sdio":
_configure_sdio_3x(config)
else:
_configure_spi_3x(config)
if esp32.get_esp32_variant() == esp32.VARIANT_ESP32P4:
esp32.add_idf_sdkconfig_option("CONFIG_ESP_HOSTED_HOST_FEAT_PEER_DATA", True)
esp32.add_idf_sdkconfig_option(
"CONFIG_ESP_HOSTED_HOST_FEAT_PEER_DATA_MAX_CUSTOM_MSG_HANDLERS",
_MAX_CUSTOM_MSG_HANDLERS,
)
if config[CONF_USE_PSRAM]:
esp32.add_idf_sdkconfig_option("CONFIG_EH_HOST_PORT_DMA_PREFER_SPIRAM", True)
esp32.add_idf_sdkconfig_option("CONFIG_ESP_HOSTED_DFLT_TASK_FROM_SPIRAM", True)
async def to_code(config: ConfigType) -> None:
add_define("USE_ESP32_HOSTED")
use_3x = uses_esp_hosted_3x()
if use_3x:
_configure_3x(config)
else:
_configure_2x(config)
# ESP-NOW-over-hosted shim: only the radio-less ESP32-P4 host needs it (see
# the note by _MAX_CUSTOM_MSG_HANDLERS). Enabled for every P4 host, not
# gated on the `espnow` component being present: the shim is tiny and the
# esp_now_* symbols/CustomRpc calls it defines require the peer-data Kconfig
# options (set above) to link whenever esp_now_hosted.cpp compiles (which is
# on any P4 host), so coupling the two keeps the build consistent. When
# `espnow` is absent the symbols are simply unused and never register a
# callback at runtime.
if esp32.get_esp32_variant() == esp32.VARIANT_ESP32P4:
add_define("USE_ESP_NOW_HOSTED")
# esp_now_hosted.cpp includes esp_now.h, which esp_wifi provides
esp32.include_builtin_idf_component("esp_wifi")
# Library versions; this component set requires ESP-IDF 5.3 or newer,
# which is enforced at validation time.
idf_ver = esp32.idf_version()
os.environ["ESP_IDF_VERSION"] = f"{idf_ver.major}.{idf_ver.minor}"
esp32.add_idf_component(name="espressif/esp_wifi_remote", ref="1.6.3")
esp32.add_idf_component(name="espressif/esp_wifi_remote", ref="1.6.5")
esp32.add_idf_component(name="espressif/wifi_remote_over_eppp", ref="0.3.3")
esp32.add_idf_component(name="espressif/eppp_link", ref="1.1.5")
esp32.add_idf_component(name="espressif/esp_hosted", ref="2.12.13")
@@ -26,6 +26,8 @@ static const char *const TAG = "esp32_hosted.update";
// Older coprocessor firmware versions have a 1500-byte limit per RPC call
constexpr size_t CHUNK_SIZE = 1500;
// OTA begin blocks while the coprocessor erases its partition
constexpr uint32_t OTA_WDT_TIMEOUT_MS = 60000;
#ifdef USE_ESP32_HOSTED_HTTP_UPDATE
// Interval/timeout IDs (uint32_t to avoid string comparison)
@@ -336,7 +338,11 @@ bool Esp32HostedUpdate::stream_firmware_to_coprocessor_() {
ESP_LOGI(TAG, "Firmware size: %zu bytes", total_size);
// Begin OTA on coprocessor
esp_err_t err = esp_hosted_slave_ota_begin(); // NOLINT
esp_err_t err;
{
watchdog::WatchdogManager wdt(OTA_WDT_TIMEOUT_MS);
err = esp_hosted_slave_ota_begin(); // NOLINT
}
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to begin OTA: %s", esp_err_to_name(err));
container->end();
@@ -425,7 +431,11 @@ bool Esp32HostedUpdate::write_embedded_firmware_to_coprocessor_() {
ESP_LOGI(TAG, "Starting OTA update (%zu bytes)", this->firmware_size_);
esp_err_t err = esp_hosted_slave_ota_begin(); // NOLINT
esp_err_t err;
{
watchdog::WatchdogManager wdt(OTA_WDT_TIMEOUT_MS);
err = esp_hosted_slave_ota_begin(); // NOLINT
}
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to begin OTA: %s", esp_err_to_name(err));
this->status_set_error(LOG_STR("Failed to begin OTA"));
@@ -472,8 +482,6 @@ void Esp32HostedUpdate::perform(bool force) {
this->update_info_.has_progress = false;
this->publish_state();
watchdog::WatchdogManager watchdog(60000);
#ifdef USE_ESP32_HOSTED_HTTP_UPDATE
if (!this->stream_firmware_to_coprocessor_())
#else
+1 -1
View File
@@ -26,7 +26,7 @@ dependencies:
espressif/mdns:
version: 1.12.0
espressif/esp_wifi_remote:
version: 1.6.3
version: 1.6.5
rules:
- if: "target in [esp32h2, esp32p4]"
espressif/wifi_remote_over_eppp: