Files
desklock/firmware/components/esp_hosted/docs/migration_guide.md
T
jpmschweitzerandClaude Fable 5 cb5826e02b
Test, Build and Push / test-gateway (push) Successful in 12s
Test, Build and Push / release (push) Skipped
Test, Build and Push / build-gateway (push) Skipped
Fork fix: the SDIO wedge is FIXED (esp-hosted-mcu #167)
Root cause (verified against our exact IDF tree, not the community guess):
the "258" in "sdio_write_task: Failed to send data: 258" is NOT a timeout
(that is 263). 258 = 0x102 = ESP_ERR_INVALID_ARG. On the ESP32-P4, block-
mode CMD53 writes require the SOURCE buffer to be 64-byte (cache-line)
aligned; the IDF sdmmc driver rejects a misaligned source with INVALID_ARG
BEFORE any bus activity. esp_hosts write loop then declares "Unrecoverable
host sdio state" and reboots the whole P4. The audio TX payload is not
64-aligned, so streaming mic audio wedged on the very FIRST frame (which is
exactly what we saw: listening -> instant Failed to send -> reboot).

This also explains why buffer/queue/clock/retry tuning all did nothing: the
write never reached the bus. And why our symptom was instant, not after
~100 writes (the community block-mode-desync theory) — it is the first
misaligned buffer, every time.

Fix: vendored esp_hosted 2.12.11 as an editable local component (overrides
the registry copy) and bounce a misaligned TX payload through one aligned
DMA scratch buffer in hosted_sdio_write_block (port_esp_hosted_host_sdio.c).
TX is serialized by the bus lock so a single static bounce buffer is safe;
freed in hosted_sdio_deinit. Host-only change — no C6 reflash.

VERIFIED ON HARDWARE (autonomous self-test): 40s of continuous mic-audio
upstream streaming — the traffic that previously wedged on the first frame
— ran clean, zero timeouts, zero reboots. A guarded SDIO_TX_SELFTEST harness
is kept (compiled out) for future SDIO stress testing.

Credit: root cause + patch designed via multi-agent investigation; the
precise 258=INVALID_ARG decode (correcting the upstream community timeout
assumption) came from checking our actual esp_err.h.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-15 09:50:27 +02:00

9.2 KiB
Raw Blame History

This migration guide documents key changes in ESP-Hosted that users must be aware of when migrating from older versions.

Index

  1. 2.5.2 - Bluetooth Controller on Co-Processor Disabled by Default
  2. 2.6.0 - ESP-Hosted Slave OTA
  3. 2.11.0 - ESP-Hosted Host Driver
  4. 2.12.4 - Custom Msg Callback - User Ptr

{\color{yellow} \text{2.12.4 - Custom Msg Callback - User Ptr}}

Migration needed from versions

Firmware Version Migration required
Host < 2.12.4
Slave < 2.12.4

Reason for change

  1. esp_hosted_register_custom_callback() now supports a user-provided pointer to be passed back on every callback invocation.
  2. This allows external code to maintain per-callback context without global variables.

Old API

esp_err_t esp_hosted_register_custom_callback(
    uint32_t msg_id,
    void (*callback)(uint32_t msg_id, const uint8_t *data, size_t data_len));

esp_err_t esp_hosted_send_custom_data(uint32_t msg_id, const uint8_t *data, size_t data_len);

New API

esp_err_t esp_hosted_register_custom_callback(uint32_t msg_id_exp,
    void (*callback)(uint32_t msg_id_recvd, const uint8_t *data_recvd, size_t data_len_recvd, void *local_context), // <-- Changed
    void *local_context); // <-- Extra argument

esp_err_t esp_hosted_send_custom_data(uint32_t msg_id_to_send, const uint8_t *data_to_send, size_t data_len_to_send); // no logical change

Arguments:

  • msg_id message ID to register
  • callback function pointer to handle the message (adds void* as last arg)
  • user user-provided pointer returned on every callback invocation

Returns: ESP_OK on success, or an error code on failure.

{\color{yellow} \text{2.11.0 - ESP-Hosted Host Driver}}

Migration needed from versions

Host version wifi-remote version
< 2.11.0 < 1.3.1
  1. A double-free memory error can occur in some situations when ESP-Hosted Host receives network data and passes it to the netif rx() function (registered by netif via the wifi-remote component) for processing.

  2. This error is resolved in ESP-Hosted v2.11.1. It must be used with wifi-remote v1.3.1 or greater to prevent a memory leak condition during netif initialization.

{\color{yellow} \text{2.6.0 - ESP-Hosted Slave OTA}}

Migration needed from versions

Slave version Host version
> 2.5.X > 2.5.X

Reason for change

  1. The existing esp_hosted_slave_ota() API was restrictive, supporting only HTTP-based OTA updates. The OTA APIs are now exposed so developers can implement their own OTA mechanisms.
  2. The port layer previously contained OTA logic, which forced inclusion of the HTTP client in the host codebase even when not required.

Changes required on host

If you are migrating from the old esp_hosted_slave_ota() function, update your code as follows.

Old API (deprecated)

#include "esp_hosted.h"

const char *image_url = "http://example.com/network_adapter.bin";
esp_err_t ret = esp_hosted_slave_ota(image_url);
if (ret == ESP_OK) {
    printf("OTA update failed[%d]\n", ret);
}

New APIs

The slave OTA process is now performed using the following APIs.

esp_hosted_slave_ota_begin()

esp_err_t esp_hosted_slave_ota_begin(void);

Initializes the OTA process on the slave.

  • Arguments: None

  • Returns: ESP_OK on success, or an error code on failure

  • What it does:

    • Prepares the slave for firmware reception
    • Allocates OTA buffers
    • Sets up the OTA partition on the slave

esp_hosted_slave_ota_write()

esp_err_t esp_hosted_slave_ota_write(const void *data, size_t size);

Sends firmware data chunks to the slave.

  • Arguments:

    • data: Pointer to firmware data chunk
    • size: Size of the data chunk (typically 14001500 bytes)
  • Returns: ESP_OK on success, or an error code on failure

  • What it does:

    • Transmits firmware data over ESP-Hosted transport (SDIO/SPI/UART)
    • The slave writes data to its OTA partition
    • Can be called multiple times for large firmware images

esp_hosted_slave_ota_end()

esp_err_t esp_hosted_slave_ota_end(void);

Finalizes the OTA process.

  • Arguments: None

  • Returns: ESP_OK on success, or an error code on failure

  • What it does:

    • Validates the complete firmware image on the slave
    • Calculates and verifies checksums
    • Marks the new firmware as valid but not yet active

esp_hosted_slave_ota_activate()

esp_err_t esp_hosted_slave_ota_activate(void);

Activates the newly flashed firmware.

  • Arguments: None

  • Returns: ESP_OK on success, or an error code on failure

  • What it does:

    • Switches the slaves boot partition to the new firmware
    • Triggers slave reboot with the new firmware
    • Note: After this call, the slave restarts with the new firmware

How to use the new APIs

A dedicated example demonstrates the usage of the new OTA APIs: Slave OTA using ESP-Hosted transport

Tip

The example uses the new ESP-Hosted-MCU Slave OTA APIs. You can reuse or customize it for your own OTA workflow.

Example methods supported:

Method Description
Partition method Slave firmware binary stored in Hosts partition table (slave_fw partition). Requires an extra host partition, but no Wi-Fi connectivity.
LittleFS method Host partition formatted as LittleFS and stores the slave firmware. Requires an extra host partition, but no Wi-Fi connectivity.
HTTPS method Slave firmware binary hosted on an HTTPS server. No extra host partition needed, but requires Wi-Fi connectivity.

{\color{yellow} \text{2.5.2 - Bluetooth Controller on Co-Processor Disabled by Default}}

Migration needed from versions

Slave version Host version
> 2.5.1 > 2.5.1

Before v2.5.2, the Bluetooth controller on the co-processor was initialized and enabled by default. From v2.5.2 onwards, it starts in a disabled state.

Reason for change

This allows users to modify the Bluetooth MAC address before the controller is initialized, as it can only be changed prior to enabling the controller.

New APIs

esp_hosted_bt_controller_init()

esp_err_t esp_hosted_bt_controller_init(void);

Initializes the Bluetooth controller on the co-processor.

  • Arguments: None

  • Returns: ESP_OK on success, or an error code on failure

  • What it does:

    • Allocates and initializes controller resources
    • Prepares the controller for activation

esp_hosted_bt_controller_deinit()

esp_err_t esp_hosted_bt_controller_deinit(bool mem_release);

Deinitializes the Bluetooth controller on the co-processor.

  • Arguments:

    • mem_release: If true, releases controller memory (cannot be reused)
  • Returns: ESP_OK on success, or an error code on failure

  • What it does:

    • Stops the Bluetooth controller
    • Optionally releases memory used by the controller
    • Once released, the controller cannot be reinitialized without reboot

esp_hosted_bt_controller_enable()

esp_err_t esp_hosted_bt_controller_enable(void);

Enables the Bluetooth controller on the co-processor.

  • Arguments: None

  • Returns: ESP_OK on success, or an error code on failure

  • What it does:

    • Starts the Bluetooth controller task
    • Enables radio and HCI interfaces for Bluetooth operation

esp_hosted_bt_controller_disable()

esp_err_t esp_hosted_bt_controller_disable(void);

Disables the Bluetooth controller on the co-processor.

  • Arguments: None

  • Returns: ESP_OK on success, or an error code on failure

  • What it does:

    • Gracefully stops the controller
    • Disables the Bluetooth radio
    • Must be called before deinitializing the controller

Changes required on host

Before starting the Bluetooth stack on the host:

  1. Call esp_hosted_connect_to_slave() to establish a connection with the slave.
  2. (Optional) Set the Bluetooth MAC address using esp_hosted_iface_mac_addr_set().
  3. Initialize the Bluetooth controller using esp_hosted_bt_controller_init().
  4. Enable the Bluetooth controller using esp_hosted_bt_controller_enable().

See Initializing the Bluetooth Controller for more details.

How to use the new APIs

You can now start the host Bluetooth stack and use Bluetooth as usual. All ESP-Hosted Bluetooth host examples (NimBLE and BlueDroid) have been updated accordingly.

For an example showing how to change the BT MAC address before starting the controller, refer to: BT Controller Example