diff --git a/Devices/m5stack-tab5/device.properties b/Devices/m5stack-tab5/device.properties index 38d7e4243..c55287cea 100644 --- a/Devices/m5stack-tab5/device.properties +++ b/Devices/m5stack-tab5/device.properties @@ -32,21 +32,11 @@ sdkconfig.CONFIG_WIFI_PROV_SCAN_MAX_ENTRIES=16 sdkconfig.CONFIG_WIFI_PROV_AUTOSTOP_TIMEOUT=30 sdkconfig.CONFIG_WIFI_PROV_STA_ALL_CHANNEL_SCAN=y sdkconfig.CONFIG_SLAVE_IDF_TARGET_ESP32C6=y -sdkconfig.CONFIG_ESP_HOSTED_ENABLED=y -sdkconfig.CONFIG_ESP_HOSTED_SDIO_HOST_INTERFACE=y -sdkconfig.CONFIG_ESP_HOSTED_SDIO_SLOT_1=y -sdkconfig.CONFIG_ESP_HOSTED_PRIV_SDIO_PIN_CMD_SLOT_1=13 -sdkconfig.CONFIG_ESP_HOSTED_PRIV_SDIO_PIN_CLK_SLOT_1=12 -sdkconfig.CONFIG_ESP_HOSTED_PRIV_SDIO_PIN_D0_SLOT_1=11 -sdkconfig.CONFIG_ESP_HOSTED_PRIV_SDIO_PIN_D1_4BIT_BUS_SLOT_1=10 -sdkconfig.CONFIG_ESP_HOSTED_PRIV_SDIO_PIN_D2_4BIT_BUS_SLOT_1=9 -sdkconfig.CONFIG_ESP_HOSTED_PRIV_SDIO_PIN_D3_4BIT_BUS_SLOT_1=8 -sdkconfig.CONFIG_ESP_HOSTED_SDIO_GPIO_RESET_SLAVE=15 -# Fixes recent changes to esp_hosted -sdkconfig.CONFIG_ESP_HOSTED_USE_MEMPOOL=n +sdkconfig.CONFIG_ESP_HOSTED_HOST_TRANSPORT_BUS_SDIO=y +# esp_hosted 3.x ships a native pin/reset-GPIO preset for this exact board. +sdkconfig.CONFIG_ESP32P4_TAB5_C6_BOARD=y # ESP-NOW bridge (EspNowBackendHosted.cpp) registers 6 custom-RPC handlers (4 resp + 2 event); default cap is 3 -sdkconfig.CONFIG_ESP_HOSTED_ENABLE_PEER_DATA_TRANSFER=y -sdkconfig.CONFIG_ESP_HOSTED_MAX_CUSTOM_MSG_HANDLERS=8 +sdkconfig.CONFIG_ESP_HOSTED_HOST_FEAT_PEER_DATA_MAX_CUSTOM_MSG_HANDLERS=8 # Performance: larger L2 cache reduces PSRAM stalls for draw/DPI buffers sdkconfig.CONFIG_CACHE_L2_CACHE_256KB=y # Performance: cache-line-aligned draw buffers, required for PPA/DMA2D coherency (see lvgl-module's lvgl_display_alloc_buffer()) diff --git a/Drivers/ili9881c-module/source/ili9881c.cpp b/Drivers/ili9881c-module/source/ili9881c.cpp index 59a7e42d7..3fefe75e3 100644 --- a/Drivers/ili9881c-module/source/ili9881c.cpp +++ b/Drivers/ili9881c-module/source/ili9881c.cpp @@ -102,12 +102,10 @@ static int pin_or_unused(const GpioPinSpec& pin) { return pin.gpio_controller == nullptr ? -1 : static_cast(pin.pin); } +// RGB666 has no ESP-IDF 6.1 lcd_color_format_t equivalent (LL only implements RGB565/RGB888), +// so 18bpp is rejected in start() below rather than silently mis-driving the panel. static lcd_color_format_t color_format_from_bits_per_pixel(uint8_t bits_per_pixel) { - switch (bits_per_pixel) { - case 18: return LCD_COLOR_FMT_RGB666; - case 24: return LCD_COLOR_FMT_RGB888; - default: return LCD_COLOR_FMT_RGB565; - } + return bits_per_pixel == 24 ? LCD_COLOR_FMT_RGB888 : LCD_COLOR_FMT_RGB565; } // Unpacks the devicetree's flat [cmd, data_len, delay_ms, data_len bytes...] encoding (produced @@ -155,6 +153,10 @@ static bool parse_init_sequence(const uint8_t* bytes, uint32_t length, ili9881c_ static error_t start(Device* device) { const auto* config = GET_CONFIG(device); + if (config->bits_per_pixel == 18) { + LOG_E(TAG, "18bpp (RGB666) is unsupported on this ESP-IDF version"); + return ERROR_NOT_SUPPORTED; + } auto* internal = static_cast(malloc(sizeof(Ili9881cInternal))); if (internal == nullptr) { @@ -191,7 +193,7 @@ static error_t start(Device* device) { .bus_id = config->dsi_bus_id, .num_data_lanes = config->num_data_lanes, .phy_clk_src = MIPI_DSI_PHY_CLK_SRC_DEFAULT, - .lane_bit_rate_mbps = config->lane_bit_rate_mbps, + .lane_bit_rate_mbps = static_cast(config->lane_bit_rate_mbps), }; if (esp_lcd_new_dsi_bus(&bus_config, &internal->dsi_bus_handle) != ESP_OK) { LOG_E(TAG, "Failed to create MIPI DSI bus"); @@ -219,8 +221,7 @@ static error_t start(Device* device) { const esp_lcd_dpi_panel_config_t dpi_config = { .virtual_channel = 0, .dpi_clk_src = MIPI_DSI_DPI_CLK_SRC_DEFAULT, - .dpi_clock_freq_mhz = config->dpi_clock_freq_mhz, - .pixel_format = (lcd_color_rgb_pixel_format_t)0, // deprecated field - in/out_color_format below take precedence + .dpi_clock_freq_mhz = static_cast(config->dpi_clock_freq_mhz), .in_color_format = color_format, .out_color_format = color_format, .num_fbs = config->num_fbs, @@ -235,7 +236,6 @@ static error_t start(Device* device) { .vsync_front_porch = config->vsync_front_porch, }, .flags = { - .use_dma2d = config->use_dma2d, .disable_lp = config->disable_lp, }, }; @@ -270,6 +270,10 @@ static error_t start(Device* device) { return ERROR_RESOURCE; } + if (config->use_dma2d) { + esp_lcd_dpi_panel_enable_dma2d(internal->panel_handle); + } + // Bring-up sequence: reset() pulses (or software-resets) the panel and init() pushes // init_cmds over the DBI command interface before bringing up the underlying DPI peripheral. // swap_xy/set_gap are intentionally not called: the ILI9881C driver doesn't override them and diff --git a/Drivers/jd9165-module/source/jd9165.cpp b/Drivers/jd9165-module/source/jd9165.cpp index 268757969..416688a24 100644 --- a/Drivers/jd9165-module/source/jd9165.cpp +++ b/Drivers/jd9165-module/source/jd9165.cpp @@ -73,12 +73,10 @@ static int pin_or_unused(const GpioPinSpec& pin) { return pin.gpio_controller == nullptr ? -1 : static_cast(pin.pin); } +// RGB666 has no ESP-IDF 6.1 lcd_color_format_t equivalent (LL only implements RGB565/RGB888), +// so 18bpp is rejected in start() below rather than silently mis-driving the panel. static lcd_color_format_t color_format_from_bits_per_pixel(uint8_t bits_per_pixel) { - switch (bits_per_pixel) { - case 18: return LCD_COLOR_FMT_RGB666; - case 24: return LCD_COLOR_FMT_RGB888; - default: return LCD_COLOR_FMT_RGB565; - } + return bits_per_pixel == 24 ? LCD_COLOR_FMT_RGB888 : LCD_COLOR_FMT_RGB565; } // Unpacks the devicetree's flat [cmd, data_len, delay_ms, data_len bytes...] encoding (produced @@ -126,6 +124,10 @@ static bool parse_init_sequence(const uint8_t* bytes, uint32_t length, jd9165_lc static error_t start(Device* device) { const auto* config = GET_CONFIG(device); + if (config->bits_per_pixel == 18) { + LOG_E(TAG, "18bpp (RGB666) is unsupported on this ESP-IDF version"); + return ERROR_NOT_SUPPORTED; + } auto* internal = static_cast(malloc(sizeof(Jd9165Internal))); if (internal == nullptr) { @@ -162,7 +164,7 @@ static error_t start(Device* device) { .bus_id = config->dsi_bus_id, .num_data_lanes = config->num_data_lanes, .phy_clk_src = MIPI_DSI_PHY_CLK_SRC_DEFAULT, - .lane_bit_rate_mbps = config->lane_bit_rate_mbps, + .lane_bit_rate_mbps = static_cast(config->lane_bit_rate_mbps), }; if (esp_lcd_new_dsi_bus(&bus_config, &internal->dsi_bus_handle) != ESP_OK) { LOG_E(TAG, "Failed to create MIPI DSI bus"); @@ -190,8 +192,7 @@ static error_t start(Device* device) { const esp_lcd_dpi_panel_config_t dpi_config = { .virtual_channel = 0, .dpi_clk_src = MIPI_DSI_DPI_CLK_SRC_DEFAULT, - .dpi_clock_freq_mhz = config->dpi_clock_freq_mhz, - .pixel_format = (lcd_color_rgb_pixel_format_t)0, // deprecated field - in/out_color_format below take precedence + .dpi_clock_freq_mhz = static_cast(config->dpi_clock_freq_mhz), .in_color_format = color_format, .out_color_format = color_format, .num_fbs = config->num_fbs, @@ -206,7 +207,6 @@ static error_t start(Device* device) { .vsync_front_porch = config->vsync_front_porch, }, .flags = { - .use_dma2d = config->use_dma2d, .disable_lp = config->disable_lp, }, }; @@ -240,6 +240,10 @@ static error_t start(Device* device) { return ERROR_RESOURCE; } + if (config->use_dma2d) { + esp_lcd_dpi_panel_enable_dma2d(internal->panel_handle); + } + // Bring-up sequence: reset() pulses (or software-resets) the panel and init() pushes // init_cmds over the DBI command interface before bringing up the underlying DPI peripheral. // swap_xy/set_gap are intentionally not called: the JD9165 driver doesn't override them and diff --git a/Drivers/st7121-module/source/st7121.cpp b/Drivers/st7121-module/source/st7121.cpp index 61189a792..1ee021837 100644 --- a/Drivers/st7121-module/source/st7121.cpp +++ b/Drivers/st7121-module/source/st7121.cpp @@ -102,12 +102,10 @@ static int pin_or_unused(const GpioPinSpec& pin) { return pin.gpio_controller == nullptr ? -1 : static_cast(pin.pin); } +// RGB666 has no ESP-IDF 6.1 lcd_color_format_t equivalent (LL only implements RGB565/RGB888), +// so 18bpp is rejected in start() below rather than silently mis-driving the panel. static lcd_color_format_t color_format_from_bits_per_pixel(uint8_t bits_per_pixel) { - switch (bits_per_pixel) { - case 18: return LCD_COLOR_FMT_RGB666; - case 24: return LCD_COLOR_FMT_RGB888; - default: return LCD_COLOR_FMT_RGB565; - } + return bits_per_pixel == 24 ? LCD_COLOR_FMT_RGB888 : LCD_COLOR_FMT_RGB565; } // Unpacks the devicetree's flat [cmd, data_len, delay_ms, data_len bytes...] encoding (produced @@ -155,6 +153,10 @@ static bool parse_init_sequence(const uint8_t* bytes, uint32_t length, st7121_lc static error_t start(Device* device) { const auto* config = GET_CONFIG(device); + if (config->bits_per_pixel == 18) { + LOG_E(TAG, "18bpp (RGB666) is unsupported on this ESP-IDF version"); + return ERROR_NOT_SUPPORTED; + } auto* internal = static_cast(malloc(sizeof(St7121Internal))); if (internal == nullptr) { @@ -191,7 +193,7 @@ static error_t start(Device* device) { .bus_id = config->dsi_bus_id, .num_data_lanes = config->num_data_lanes, .phy_clk_src = MIPI_DSI_PHY_CLK_SRC_DEFAULT, - .lane_bit_rate_mbps = config->lane_bit_rate_mbps, + .lane_bit_rate_mbps = static_cast(config->lane_bit_rate_mbps), }; if (esp_lcd_new_dsi_bus(&bus_config, &internal->dsi_bus_handle) != ESP_OK) { LOG_E(TAG, "Failed to create MIPI DSI bus"); @@ -219,8 +221,7 @@ static error_t start(Device* device) { const esp_lcd_dpi_panel_config_t dpi_config = { .virtual_channel = 0, .dpi_clk_src = MIPI_DSI_DPI_CLK_SRC_DEFAULT, - .dpi_clock_freq_mhz = config->dpi_clock_freq_mhz, - .pixel_format = (lcd_color_rgb_pixel_format_t)0, // deprecated field - in/out_color_format below take precedence + .dpi_clock_freq_mhz = static_cast(config->dpi_clock_freq_mhz), .in_color_format = color_format, .out_color_format = color_format, .num_fbs = config->num_fbs, @@ -235,7 +236,6 @@ static error_t start(Device* device) { .vsync_front_porch = config->vsync_front_porch, }, .flags = { - .use_dma2d = config->use_dma2d, .disable_lp = config->disable_lp, }, }; @@ -269,6 +269,10 @@ static error_t start(Device* device) { return ERROR_RESOURCE; } + if (config->use_dma2d) { + esp_lcd_dpi_panel_enable_dma2d(internal->panel_handle); + } + // Bring-up sequence: reset() pulses (or software-resets) the panel and init() pushes // init_cmds over the DBI command interface before bringing up the underlying DPI peripheral. // swap_xy/set_gap are intentionally not called: the ST7121 driver doesn't override them and diff --git a/Drivers/st7123-module/source/st7123.cpp b/Drivers/st7123-module/source/st7123.cpp index 7e0a047ac..26a9eba2d 100644 --- a/Drivers/st7123-module/source/st7123.cpp +++ b/Drivers/st7123-module/source/st7123.cpp @@ -102,12 +102,10 @@ static int pin_or_unused(const GpioPinSpec& pin) { return pin.gpio_controller == nullptr ? -1 : static_cast(pin.pin); } +// RGB666 has no ESP-IDF 6.1 lcd_color_format_t equivalent (LL only implements RGB565/RGB888), +// so 18bpp is rejected in start() below rather than silently mis-driving the panel. static lcd_color_format_t color_format_from_bits_per_pixel(uint8_t bits_per_pixel) { - switch (bits_per_pixel) { - case 18: return LCD_COLOR_FMT_RGB666; - case 24: return LCD_COLOR_FMT_RGB888; - default: return LCD_COLOR_FMT_RGB565; - } + return bits_per_pixel == 24 ? LCD_COLOR_FMT_RGB888 : LCD_COLOR_FMT_RGB565; } // Unpacks the devicetree's flat [cmd, data_len, delay_ms, data_len bytes...] encoding (produced @@ -155,6 +153,10 @@ static bool parse_init_sequence(const uint8_t* bytes, uint32_t length, st7123_lc static error_t start(Device* device) { const auto* config = GET_CONFIG(device); + if (config->bits_per_pixel == 18) { + LOG_E(TAG, "18bpp (RGB666) is unsupported on this ESP-IDF version"); + return ERROR_NOT_SUPPORTED; + } auto* internal = static_cast(malloc(sizeof(St7123Internal))); if (internal == nullptr) { @@ -191,7 +193,7 @@ static error_t start(Device* device) { .bus_id = config->dsi_bus_id, .num_data_lanes = config->num_data_lanes, .phy_clk_src = MIPI_DSI_PHY_CLK_SRC_DEFAULT, - .lane_bit_rate_mbps = config->lane_bit_rate_mbps, + .lane_bit_rate_mbps = static_cast(config->lane_bit_rate_mbps), }; if (esp_lcd_new_dsi_bus(&bus_config, &internal->dsi_bus_handle) != ESP_OK) { LOG_E(TAG, "Failed to create MIPI DSI bus"); @@ -219,8 +221,7 @@ static error_t start(Device* device) { const esp_lcd_dpi_panel_config_t dpi_config = { .virtual_channel = 0, .dpi_clk_src = MIPI_DSI_DPI_CLK_SRC_DEFAULT, - .dpi_clock_freq_mhz = config->dpi_clock_freq_mhz, - .pixel_format = (lcd_color_rgb_pixel_format_t)0, // deprecated field - in/out_color_format below take precedence + .dpi_clock_freq_mhz = static_cast(config->dpi_clock_freq_mhz), .in_color_format = color_format, .out_color_format = color_format, .num_fbs = config->num_fbs, @@ -235,7 +236,6 @@ static error_t start(Device* device) { .vsync_front_porch = config->vsync_front_porch, }, .flags = { - .use_dma2d = config->use_dma2d, .disable_lp = config->disable_lp, }, }; @@ -269,6 +269,10 @@ static error_t start(Device* device) { return ERROR_RESOURCE; } + if (config->use_dma2d) { + esp_lcd_dpi_panel_enable_dma2d(internal->panel_handle); + } + // Bring-up sequence: reset() pulses (or software-resets) the panel and init() pushes // init_cmds over the DBI command interface before bringing up the underlying DPI peripheral. // swap_xy/set_gap are intentionally not called: the ST7123 driver doesn't override them and diff --git a/Modules/c-symbols-module/source/module.cpp b/Modules/c-symbols-module/source/module.cpp index e7b26ea0a..49f30246a 100644 --- a/Modules/c-symbols-module/source/module.cpp +++ b/Modules/c-symbols-module/source/module.cpp @@ -12,6 +12,14 @@ extern "C" { +#if CONFIG_IDF_TARGET_ESP32P4 +// Newlib doesn't provide this (only Picolibc does); a compat shim is force-linked into the +// firmware for espressif__esp_ipa's sake - see +// Platforms/platform-esp32/source/drivers/esp32p4_libc_compat.c. Side-loaded apps built against +// Newlib need it resolved the same way. +extern int __issignalingf(float); +#endif + static const ModuleSymbol SYMBOLS[] = { // stdlib.h DEFINE_MODULE_SYMBOL(malloc), @@ -61,6 +69,9 @@ static const ModuleSymbol SYMBOLS[] = { DEFINE_MODULE_SYMBOL(fmaxf), DEFINE_MODULE_SYMBOL(fminf), DEFINE_MODULE_SYMBOL(roundf), +#if CONFIG_IDF_TARGET_ESP32P4 + DEFINE_MODULE_SYMBOL(__issignalingf), +#endif // Explicit signatures: libstdc++/libc++'s float/double/long double overloads make a // bare `&acos` etc. ambiguous. esp-idf newlib's plain, unoverloaded functions match these signatures // exactly, so the cast is a no-op there - one list works for all platforms: diff --git a/Modules/cpp-symbols-module/README.md b/Modules/cpp-symbols-module/README.md index 6e1c333f4..252211a0a 100644 --- a/Modules/cpp-symbols-module/README.md +++ b/Modules/cpp-symbols-module/README.md @@ -44,8 +44,32 @@ Non-template helpers shared by every `std::map`/`std::set` instantiation: ### `std::string` -- `basic_string::_M_replace_cold` - the rarely-taken slow path of `std::string::replace`, - split out of the header-inlined fast path. +Most of the common out-of-line member set (this class ends up entirely out-of-line for any app +built at C++17 or earlier - see `extern template class basic_string` in libstdc++'s +`bits/basic_string.tcc`): + +- `_M_replace_cold`, `_M_replace`, `_M_mutate`, `_M_append`, `_M_erase`, `_M_assign`, + `_M_create`, `_M_dispose`, `_M_construct` +- `substr`, `find`, `reserve`, `append` (both overloads), `assign`, `push_back`, `pop_back`, + `operator=(basic_string&&)` +- `_S_copy`, `_S_move` (static helpers) +- Free functions returning `basic_string` by value: `__str_concat`, `operator+(basic_string + const&, const char*)` + +- `(basic_string const&, pos, len)` and `(const char*, allocator const&)` constructors - + implemented directly rather than exported by address (see below), since GCC doesn't emit a + standalone definition for either. + +**Not supported: the move constructor.** Like the two constructors above, GCC never emits a +standalone out-of-line definition for it in a C++20+ build - it's a pure header-inline forwarder +with no real function body to take the address of, even when this module's own code is made to +call it directly. If it turns out to be needed, implement it the same way as the other two: write +a small function whose body does the equivalent construction via placement-new (`new (self) +std::string(...)`), and register its address manually under the mangled name(s) in `SYMBOLS[]` +(the compiler inlines the real header logic into that function, producing a genuine addressable +symbol - the same trick used for `_M_replace_cold` and friends, except *we* supply the body +instead of pointing at one the library already provides). An app whose loaded ELF needs it will +still fail with `Can't find common ...C1.../...C2.../...C5...`. ## Adding a new symbol diff --git a/Modules/cpp-symbols-module/source/module.cpp b/Modules/cpp-symbols-module/source/module.cpp index 916f56d2a..03e9b3bd6 100644 --- a/Modules/cpp-symbols-module/source/module.cpp +++ b/Modules/cpp-symbols-module/source/module.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #if defined(__GLIBCXX__) || defined(ESP_PLATFORM) #define TT_CPP_SYMBOLS_AVAILABLE 1 @@ -42,8 +43,54 @@ extern "C" { #ifdef ESP_PLATFORM // string - same 32-bit-ABI mangling caveat as operator new/delete above. void _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE15_M_replace_coldEPcjPKcjj(void*, char*, unsigned int, char const*, unsigned int, unsigned int); + void* _ZNKSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE6substrEjj(void*, const void*, unsigned int, unsigned int); + char* _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE9_M_createERjj(void*, unsigned int*, unsigned int); + void _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE7reserveEj(void*, unsigned int); + unsigned int _ZNKSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE4findEcj(const void*, char, unsigned int); + void _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE10_M_disposeEv(void*); + void* _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE10_M_replaceEjjPKcj(void*, unsigned int, unsigned int, const char*, unsigned int); + void _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE12_M_constructIPKcEEvT_S8_St20forward_iterator_tag(void*, const char*, const char*, char); + void* _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE6appendEPKc(void*, const char*); + void* _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE6appendEPKcj(void*, const char*, unsigned int); + void* _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE6assignEPKc(void*, const char*); + void _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE7_S_copyEPcPKcj(char*, const char*, unsigned int); + void _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE7_S_moveEPcPKcj(char*, const char*, unsigned int); + void _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE8_M_eraseEjj(void*, unsigned int, unsigned int); + void _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE8pop_backEv(void*); + void* _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE9_M_appendEPKcj(void*, const char*, unsigned int); + void _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE9_M_assignERKS4_(void*, const void*); + void _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE9_M_mutateEjjPKcj(void*, unsigned int, unsigned int, const char*, unsigned int); + void _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE9push_backEc(void*, char); + void* _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEaSEOS4_(void*, void*); + // Non-members: return basic_string by value, so the first param is the hidden + // return-value pointer (Itanium ABI), same convention as substr() above. + void* _ZSt12__str_concatINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEET_PKNS6_10value_typeENS6_9size_typeES9_SA_RKNS6_14allocator_typeE(void*, const char*, unsigned int, const char*, unsigned int, const void*); + void* _ZStplIcSt11char_traitsIcESaIcEENSt7__cxx1112basic_stringIT_T0_T1_EERKS8_PKS5_(void*, const void*, const char*); #endif } + +#ifdef ESP_PLATFORM +namespace { +// basic_string(basic_string const&, pos, len) has no out-of-line definition anywhere to take the +// address of - unlike everything else above, GCC never emits one for this ctor under C++20+ (it's +// a pure header-inline forwarder around _M_construct(), confirmed by trying to force an +// instantiation and finding no resulting linkable symbol). Implemented directly instead: this +// function's placement-new triggers the compiler to inline the real construction logic here, +// producing a genuine addressable definition, registered below under the mangled name(s) the ELF +// loader actually looks up. +void construct_basic_string_from_substring(void* self, const void* str, unsigned int pos, unsigned int len) { + new (self) std::string(*static_cast(str), pos, len); +} +// Same story for basic_string(const char*, allocator const&). +void construct_basic_string_from_cstr(void* self, const char* s, const void* alloc) { + new (self) std::string(s, *static_cast*>(alloc)); +} +// Same story for the move constructor, basic_string(basic_string&&). +void construct_basic_string_move(void* self, void* other) { + new (self) std::string(std::move(*static_cast(other))); +} +} +#endif #endif static const ModuleSymbol SYMBOLS[] = { @@ -76,6 +123,37 @@ static const ModuleSymbol SYMBOLS[] = { #ifdef ESP_PLATFORM // string - Note: You have to use the mangled names here DEFINE_MODULE_SYMBOL(_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE15_M_replace_coldEPcjPKcjj), + DEFINE_MODULE_SYMBOL(_ZNKSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE6substrEjj), + DEFINE_MODULE_SYMBOL(_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE9_M_createERjj), + DEFINE_MODULE_SYMBOL(_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE7reserveEj), + DEFINE_MODULE_SYMBOL(_ZNKSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE4findEcj), + DEFINE_MODULE_SYMBOL(_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE10_M_disposeEv), + DEFINE_MODULE_SYMBOL(_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE10_M_replaceEjjPKcj), + DEFINE_MODULE_SYMBOL(_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE12_M_constructIPKcEEvT_S8_St20forward_iterator_tag), + DEFINE_MODULE_SYMBOL(_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE6appendEPKc), + DEFINE_MODULE_SYMBOL(_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE6appendEPKcj), + DEFINE_MODULE_SYMBOL(_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE6assignEPKc), + DEFINE_MODULE_SYMBOL(_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE7_S_copyEPcPKcj), + DEFINE_MODULE_SYMBOL(_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE7_S_moveEPcPKcj), + DEFINE_MODULE_SYMBOL(_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE8_M_eraseEjj), + DEFINE_MODULE_SYMBOL(_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE8pop_backEv), + DEFINE_MODULE_SYMBOL(_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE9_M_appendEPKcj), + DEFINE_MODULE_SYMBOL(_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE9_M_assignERKS4_), + DEFINE_MODULE_SYMBOL(_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE9_M_mutateEjjPKcj), + DEFINE_MODULE_SYMBOL(_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE9push_backEc), + DEFINE_MODULE_SYMBOL(_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEaSEOS4_), + // C1/C2/C5: complete-object, base-object, and comdat-folded aliases of the same constructor. + { "_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC1ERKS4_jj", (void*)&construct_basic_string_from_substring }, + { "_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC2ERKS4_jj", (void*)&construct_basic_string_from_substring }, + { "_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC5ERKS4_jj", (void*)&construct_basic_string_from_substring }, + { "_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC1IS3_EEPKcRKS3_", (void*)&construct_basic_string_from_cstr }, + { "_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC2IS3_EEPKcRKS3_", (void*)&construct_basic_string_from_cstr }, + { "_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC5IS3_EEPKcRKS3_", (void*)&construct_basic_string_from_cstr }, + { "_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC1EOS4_", (void*)&construct_basic_string_move }, + { "_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC2EOS4_", (void*)&construct_basic_string_move }, + { "_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC5EOS4_", (void*)&construct_basic_string_move }, + DEFINE_MODULE_SYMBOL(_ZSt12__str_concatINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEET_PKNS6_10value_typeENS6_9size_typeES9_SA_RKNS6_14allocator_typeE), + DEFINE_MODULE_SYMBOL(_ZStplIcSt11char_traitsIcESaIcEENSt7__cxx1112basic_stringIT_T0_T1_EERKS8_PKS5_), #endif #endif // TT_CPP_SYMBOLS_AVAILABLE MODULE_SYMBOL_TERMINATOR diff --git a/Platforms/platform-esp32/CMakeLists.txt b/Platforms/platform-esp32/CMakeLists.txt index f46a983d6..44964cc54 100644 --- a/Platforms/platform-esp32/CMakeLists.txt +++ b/Platforms/platform-esp32/CMakeLists.txt @@ -22,10 +22,17 @@ idf_component_register( if (DEFINED ENV{ESP_IDF_VERSION}) GET_PROPERTY_FILE_CONTENT("${CMAKE_CURRENT_LIST_DIR}/../../sdkconfig" sdkconfig_text) - GET_PROPERTY_VALUE(sdkconfig_text "CONFIG_ESP_HOSTED_ENABLED" esp_host_enabled "n") + GET_PROPERTY_VALUE(sdkconfig_text "CONFIG_ESP_HOSTED_HOST" esp_host_enabled "n") if (esp_host_enabled STREQUAL "y") idf_component_optional_requires(PRIVATE espressif__esp_hosted) endif () endif () idf_component_optional_requires(PRIVATE bt usb espressif__usb_host_hid espressif__usb_host_msc) + +if ("${IDF_TARGET}" STREQUAL "esp32p4") + # Force-links esp32p4_libc_compat.c's __issignalingf() shim - nothing references it until + # espressif__esp_ipa is scanned much later in link order, by which point this archive is + # already passed over. + target_link_libraries(${COMPONENT_LIB} INTERFACE "-Wl,-u,__issignalingf") +endif () diff --git a/Platforms/platform-esp32/include/tactility/drivers/esp32_esp_hosted_ota.h b/Platforms/platform-esp32/include/tactility/drivers/esp32_esp_hosted_ota.h index 69c16597b..d4f16ac87 100644 --- a/Platforms/platform-esp32/include/tactility/drivers/esp32_esp_hosted_ota.h +++ b/Platforms/platform-esp32/include/tactility/drivers/esp32_esp_hosted_ota.h @@ -3,5 +3,5 @@ struct FirmwareOps; /** @return the esp_hosted co-processor FirmwareOps implementation. Only declared/linked when - * CONFIG_ESP_HOSTED_ENABLED - callers (esp32_wifi.cpp) must guard with the same #if. */ + * CONFIG_ESP_HOSTED_HOST - callers (esp32_wifi.cpp) must guard with the same #if. */ const FirmwareOps* esp32_esp_hosted_ota_get_ops(); diff --git a/Platforms/platform-esp32/private/bluetooth/esp32_ble_internal.h b/Platforms/platform-esp32/private/bluetooth/esp32_ble_internal.h index 09520de68..bd0c3b324 100644 --- a/Platforms/platform-esp32/private/bluetooth/esp32_ble_internal.h +++ b/Platforms/platform-esp32/private/bluetooth/esp32_ble_internal.h @@ -172,18 +172,5 @@ extern size_t active_hid_rpt_map_len; // esp32_ble_hid.cpp extern uint16_t hid_appearance; // esp32_ble_hid.cpp extern BleHidProfile current_hid_profile; // esp32_ble_hid.cpp -// ---- HCI gate (ble_hci_gate.c) — P4/esp-hosted only ---- -// Controls whether hci_rx_handler forwards packets to NimBLE. -// Set true after nimble_port_init(), false before nimble_port_stop(). -#if defined(CONFIG_ESP_HOSTED_ENABLED) -#ifdef __cplusplus -extern "C" { -#endif -void ble_hci_gate_set_active(bool active); -bool ble_hci_gate_wait_idle(int max_ms); -#ifdef __cplusplus -} -#endif -#endif // CONFIG_ESP_HOSTED_ENABLED #endif // CONFIG_BT_NIMBLE_ENABLED diff --git a/Platforms/platform-esp32/source/drivers/bluetooth/ble_hci_gate.c b/Platforms/platform-esp32/source/drivers/bluetooth/ble_hci_gate.c deleted file mode 100644 index 960340f2d..000000000 --- a/Platforms/platform-esp32/source/drivers/bluetooth/ble_hci_gate.c +++ /dev/null @@ -1,142 +0,0 @@ -// ble_hci_gate.c — Strong override of the weak hci_rx_handler from vhci_drv.c. -// Gates HCI packet delivery so packets are silently dropped when NimBLE is not -// initialised, preventing null-npl_funcs crashes during radio teardown (P4 only). -// -// On ESP32-P4, sdio_process_rx_task runs independently of the NimBLE host and can -// deliver an HCI packet after nimble_port_deinit() has zeroed npl_funcs. -// dispatch_disable() calls ble_hci_gate_set_active(false) + ble_hci_gate_wait_idle() -// before touching NimBLE, ensuring no in-flight or future hci_rx_handler call can -// dereference NimBLE internals. - -#include -#if defined(CONFIG_BT_NIMBLE_ENABLED) && defined(CONFIG_ESP_HOSTED_ENABLED) - -#include -#include -#include -#include -#include -#include -#include - -// NimBLE transport + HCI -#include -#include -#include - -// H4 packet type indicators (same values used in vhci_drv.c) -#define HCI_H4_EVT 0x04 -#define HCI_H4_ACL 0x02 - -// Local defines from vhci_drv.c (not exported by any header) -#define BLE_HCI_EVENT_HDR_LEN (2) - -static const char* TAG = "ble_hci_gate"; - -// ---- Gate state (zero-init = gate closed until dispatch_enable opens it) ---- -static atomic_bool s_hci_active = ATOMIC_VAR_INIT(false); -static atomic_int s_hci_refcount = ATOMIC_VAR_INIT(0); - -void ble_hci_gate_set_active(bool active) { - atomic_store_explicit(&s_hci_active, active, memory_order_seq_cst); -} - -// Spin-wait until all in-flight hci_rx_handler calls complete (max_ms timeout). -// Returns true if drained within the timeout. -bool ble_hci_gate_wait_idle(int max_ms) { - for (int elapsed = 0; elapsed < max_ms; elapsed++) { - if (atomic_load_explicit(&s_hci_refcount, memory_order_acquire) == 0) - return true; - vTaskDelay(pdMS_TO_TICKS(1)); - } - return (atomic_load_explicit(&s_hci_refcount, memory_order_acquire) == 0); -} - -// Strong override — replaces the H_WEAK_REF hci_rx_handler in vhci_drv.c. -// All four esp-hosted transport drivers (SDIO, SPI, SPI-HD, UART) call this symbol. -int hci_rx_handler(uint8_t *buf, size_t buf_len) { - // Fast path: gate closed — NimBLE not ready, drop silently - if (!atomic_load_explicit(&s_hci_active, memory_order_acquire)) - return ESP_OK; - - // Hold a reference so dispatch_disable() waits for us to finish - atomic_fetch_add_explicit(&s_hci_refcount, 1, memory_order_acquire); - - // Double-check: gate may have closed between the first check and the increment - if (!atomic_load_explicit(&s_hci_active, memory_order_acquire)) { - atomic_fetch_sub_explicit(&s_hci_refcount, 1, memory_order_release); - return ESP_OK; - } - - // ---- Original vhci_drv.c (NimBLE branch) logic ---- - uint8_t *data = buf; - uint32_t len_total_read = buf_len; - int rc; - - if (data[0] == HCI_H4_EVT) { - uint8_t *evbuf; - int totlen = BLE_HCI_EVENT_HDR_LEN + data[2]; - - if (totlen > UINT8_MAX + BLE_HCI_EVENT_HDR_LEN) { - ESP_LOGE(TAG, "Rx: len[%d] > max INT, drop", totlen); - atomic_fetch_sub_explicit(&s_hci_refcount, 1, memory_order_release); - return ESP_FAIL; - } - if (totlen > MYNEWT_VAL(BLE_TRANSPORT_EVT_SIZE)) { - ESP_LOGE(TAG, "Rx: len[%d] > max BLE, drop", totlen); - atomic_fetch_sub_explicit(&s_hci_refcount, 1, memory_order_release); - return ESP_FAIL; - } - if (data[1] == BLE_HCI_EVCODE_HW_ERROR) { - ESP_LOGE(TAG, "Rx: HW_ERROR"); - atomic_fetch_sub_explicit(&s_hci_refcount, 1, memory_order_release); - return ESP_FAIL; - } - - if ((data[1] == BLE_HCI_EVCODE_LE_META) && - (data[3] == BLE_HCI_LE_SUBEV_ADV_RPT || - data[3] == BLE_HCI_LE_SUBEV_EXT_ADV_RPT)) { - evbuf = ble_transport_alloc_evt(1); - if (!evbuf) { - ESP_LOGW(TAG, "Rx: Drop ADV Report: OOM (not fatal)"); - atomic_fetch_sub_explicit(&s_hci_refcount, 1, memory_order_release); - return ESP_FAIL; - } - } else { - evbuf = ble_transport_alloc_evt(0); - if (!evbuf) { - ESP_LOGE(TAG, "Rx: transport_alloc_evt(0) failed"); - atomic_fetch_sub_explicit(&s_hci_refcount, 1, memory_order_release); - return ESP_FAIL; - } - } - - memset(evbuf, 0, sizeof *evbuf); - memcpy(evbuf, &data[1], totlen); - rc = ble_transport_to_hs_evt(evbuf); - if (rc) { - ESP_LOGE(TAG, "Rx: transport_to_hs_evt failed"); - atomic_fetch_sub_explicit(&s_hci_refcount, 1, memory_order_release); - return ESP_FAIL; - } - } else if (data[0] == HCI_H4_ACL) { - struct os_mbuf *m = ble_transport_alloc_acl_from_ll(); - if (!m) { - ESP_LOGE(TAG, "Rx: alloc_acl_from_ll failed"); - atomic_fetch_sub_explicit(&s_hci_refcount, 1, memory_order_release); - return ESP_FAIL; - } - if ((rc = os_mbuf_append(m, &data[1], len_total_read - 1)) != 0) { - ESP_LOGE(TAG, "Rx: os_mbuf_append failed; rc=%d", rc); - os_mbuf_free_chain(m); - atomic_fetch_sub_explicit(&s_hci_refcount, 1, memory_order_release); - return ESP_FAIL; - } - ble_transport_to_hs_acl(m); - } - - atomic_fetch_sub_explicit(&s_hci_refcount, 1, memory_order_release); - return ESP_OK; -} - -#endif // CONFIG_BT_NIMBLE_ENABLED && CONFIG_ESP_HOSTED_ENABLED diff --git a/Platforms/platform-esp32/source/drivers/bluetooth/esp32_ble.cpp b/Platforms/platform-esp32/source/drivers/bluetooth/esp32_ble.cpp index 8a30aa86a..34d81c207 100644 --- a/Platforms/platform-esp32/source/drivers/bluetooth/esp32_ble.cpp +++ b/Platforms/platform-esp32/source/drivers/bluetooth/esp32_ble.cpp @@ -29,14 +29,9 @@ constexpr auto* TAG = "esp32_ble"; #include #include -#if defined(CONFIG_ESP_HOSTED_ENABLED) +#if defined(CONFIG_ESP_HOSTED_HOST) #include -// esp_hosted_misc.h lacks its own extern "C" guard, so its declarations get C++ -// name-mangled when included from a .cpp file, causing "undefined reference" at -// link time against the library's plain-C symbols. -extern "C" { -#include -} +#include #endif // ble_store_config_init() is not declared in the public header in some IDF versions. @@ -684,28 +679,16 @@ static void dispatch_enable(BleCtx* ctx) { ble_publish_event(ctx->device, e); } -#if defined(CONFIG_ESP_HOSTED_ENABLED) - // Over esp_hosted (SDIO to a co-processor, e.g. C6), the slave's on-chip BT - // controller is never auto-started at slave boot — it only comes up in - // response to these RPCs. Without them, HCI Reset (the first command NimBLE - // ever sends) is handed to esp_vhci_host_send_packet() on the slave with no - // controller underneath to consume it, so it's silently dropped and NimBLE - // times out (BLE_HS_ETIMEOUT_HCI) forever. Must run before nimble_port_init(). - // esp_hosted_bt_controller_init/enable() both bail out immediately (no retry, - // no blocking) if the SDIO/SPI transport to the co-processor isn't marked up - // yet. On boot, BT can auto-enable before Wi-Fi has driven that bring-up, so - // explicitly (re)connect here and let it block until the slave handshake - // (the "Attempt connection with slave" / "Card init success" sequence) - // completes — esp_hosted_connect_to_slave() is a thin wrapper that's safe to - // call again if the transport is already up. +#if defined(CONFIG_ESP_HOSTED_HOST) + // Over esp_hosted, the co-processor's BT controller only comes up via + // esp_hosted_bt_host_stack_setup() below, which needs the SDIO/SPI transport already up - + // BT can auto-enable before Wi-Fi has driven that bring-up, so (re)connect here first. if (esp_hosted_connect_to_slave() != ESP_OK) { LOG_W(TAG, "esp_hosted_connect_to_slave failed"); } - if (esp_hosted_bt_controller_init() != ESP_OK) { - LOG_W(TAG, "esp_hosted_bt_controller_init failed"); - } - if (esp_hosted_bt_controller_enable() != ESP_OK) { - LOG_W(TAG, "esp_hosted_bt_controller_enable failed"); + esp_hosted_bt_host_stack_cfg_t hosted_bt_cfg = ESP_HOSTED_BT_HOST_STACK_CONFIG_DEFAULT(); + if (esp_hosted_bt_host_stack_setup(&hosted_bt_cfg) != ESP_OK) { + LOG_W(TAG, "esp_hosted_bt_host_stack_setup failed"); } #endif @@ -776,9 +759,6 @@ static void dispatch_enable(BleCtx* ctx) { ble_svc_gap_device_name_set(ctx->device_name); ble_att_set_preferred_mtu(BLE_ATT_MTU_MAX); -#if defined(CONFIG_ESP_HOSTED_ENABLED) - ble_hci_gate_set_active(true); // Open gate: NimBLE transport pool is ready -#endif // Drain any stale "done" signal left over from a previous cycle (e.g. if the // last dispatch_disable() timed out waiting on it — see xSemaphoreTake below // with pdMS_TO_TICKS(2000)) so dispatch_disable() only ever consumes the @@ -809,9 +789,9 @@ static void dispatch_disable(BleCtx* ctx) { // Blocking: waits for nimble_port_run() to exit. // Do NOT call ble_gap_adv_stop()/disc_cancel() before — if controller is // unresponsive they generate more HCI timeouts before the stop takes effect. - // The HCI gate must stay OPEN here: nimble_port_stop() → ble_hs_stop() sends + // The HCI link must stay bound here: nimble_port_stop() → ble_hs_stop() sends // HCI commands and needs to receive the command-complete events back from the - // controller. Closing the gate before this point starves NimBLE of those events, + // controller. Unbinding before this point starves NimBLE of those events, // causing HCI timeouts and a cascade of resets that crash in ble_hs_timer_sched. nimble_port_stop(); // nimble_port_stop()'s internal semaphore only confirms the stop sentinel event was @@ -826,27 +806,17 @@ static void dispatch_disable(BleCtx* ctx) { LOG_W(TAG, "host task did not signal completion in time"); } } -#if defined(CONFIG_ESP_HOSTED_ENABLED) - // Close the gate NOW — after nimble_port_stop() returns the NimBLE host task has - // exited and nimble_port_deinit() is about to zero npl_funcs. Any HCI packet - // arriving after this point must not reach ble_transport_alloc_evt(). - ble_hci_gate_set_active(false); - if (!ble_hci_gate_wait_idle(20)) { - LOG_W(TAG, "HCI gate drain timed out"); +#if defined(CONFIG_ESP_HOSTED_HOST) + // Unbind before nimble_port_deinit() zeros npl_funcs. Unlike the old ble_hci_gate.c this + // repo carried for esp_hosted 2.x, esp_hosted 3.x exposes no drain/wait-for-in-flight + // primitive here, so a packet already inside the RX callback at this exact moment is a + // small theoretical race this migration cannot close without patching esp_hosted itself. + if (esp_hosted_bt_host_stack_teardown() != ESP_OK) { + LOG_W(TAG, "esp_hosted_bt_host_stack_teardown failed"); } #endif nimble_port_deinit(); -#if defined(CONFIG_ESP_HOSTED_ENABLED) - // Symmetric with the enable-side esp_hosted_bt_controller_init/enable() calls. - if (esp_hosted_bt_controller_disable() != ESP_OK) { - LOG_W(TAG, "esp_hosted_bt_controller_disable failed"); - } - if (esp_hosted_bt_controller_deinit(true) != ESP_OK) { - LOG_W(TAG, "esp_hosted_bt_controller_deinit failed"); - } -#endif - ctx->spp_conn_handle.store(BLE_HS_CONN_HANDLE_NONE); ctx->spp_active.store(false); ctx->midi_conn_handle.store(BLE_HS_CONN_HANDLE_NONE); diff --git a/Platforms/platform-esp32/source/drivers/esp32_esp_hosted_ota.cpp b/Platforms/platform-esp32/source/drivers/esp32_esp_hosted_ota.cpp index bc0aed392..e1bc79d15 100644 --- a/Platforms/platform-esp32/source/drivers/esp32_esp_hosted_ota.cpp +++ b/Platforms/platform-esp32/source/drivers/esp32_esp_hosted_ota.cpp @@ -2,7 +2,7 @@ #include #endif -#if defined(CONFIG_ESP_HOSTED_ENABLED) +#if defined(CONFIG_ESP_HOSTED_HOST) #include #include @@ -251,4 +251,4 @@ const FirmwareOps* esp32_esp_hosted_ota_get_ops() { return &firmwareOps; } -#endif // CONFIG_ESP_HOSTED_ENABLED +#endif // CONFIG_ESP_HOSTED_HOST diff --git a/Platforms/platform-esp32/source/drivers/esp32_wifi.cpp b/Platforms/platform-esp32/source/drivers/esp32_wifi.cpp index 4ea88d9a8..7b6c387c2 100644 --- a/Platforms/platform-esp32/source/drivers/esp32_wifi.cpp +++ b/Platforms/platform-esp32/source/drivers/esp32_wifi.cpp @@ -20,7 +20,7 @@ #include -#if defined(CONFIG_ESP_HOSTED_ENABLED) +#if defined(CONFIG_ESP_HOSTED_HOST) #include #endif @@ -583,7 +583,7 @@ error_t api_get_firmware_ops(Device* /*device*/, const FirmwareOps** ops, void** if (ops == nullptr || ctx == nullptr) { return ERROR_INVALID_ARGUMENT; } -#if defined(CONFIG_ESP_HOSTED_ENABLED) +#if defined(CONFIG_ESP_HOSTED_HOST) // Only meaningful on a hosted board (P4+C6/C5 etc.) - this wifi device is backed by a real // co-processor with its own updatable firmware there. On a native (non-hosted) chip, this // device's "radio" is the chip's own built-in WiFi, nothing to update via this interface. diff --git a/Platforms/platform-esp32/source/drivers/esp32p4_libc_compat.c b/Platforms/platform-esp32/source/drivers/esp32p4_libc_compat.c new file mode 100644 index 000000000..cc3c2915f --- /dev/null +++ b/Platforms/platform-esp32/source/drivers/esp32p4_libc_compat.c @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: Apache-2.0 +// Tactility forces Newlib (see device.py) instead of ESP-IDF 6.x's Picolibc default, but +// managed_components/espressif__esp_ipa's prebuilt libesp_ipa.a (camera ISP auto-white-balance, +// linked in for boards with a camera sensor node, e.g. m5stack-tab5) was built against Picolibc +// and references its __issignalingf(), which Newlib doesn't provide. +#include +#if CONFIG_IDF_TARGET_ESP32P4 + +#include + +int __issignalingf(float x) { + union { float f; uint32_t i; } u = { .f = x }; + if (((u.i >> 23) & 0xff) != 0xff) { + return 0; // not NaN or Inf + } + // NaN with mantissa MSB clear is signaling; MSB set is quiet. + return (u.i & 0x007fffff) != 0 && (u.i & 0x00400000) == 0; +} + +#endif // CONFIG_IDF_TARGET_ESP32P4 diff --git a/Tactility/Source/service/espnow/EspNowBackendHosted.cpp b/Tactility/Source/service/espnow/EspNowBackendHosted.cpp index ca48054b2..f6d3d6ba9 100644 --- a/Tactility/Source/service/espnow/EspNowBackendHosted.cpp +++ b/Tactility/Source/service/espnow/EspNowBackendHosted.cpp @@ -2,7 +2,7 @@ #include #endif -#if defined(CONFIG_ESP_HOSTED_ENABLED) +#if defined(CONFIG_ESP_HOSTED_HOST) #include #include @@ -310,4 +310,4 @@ uint32_t getVersion() { } -#endif // CONFIG_ESP_HOSTED_ENABLED +#endif // CONFIG_ESP_HOSTED_HOST diff --git a/Tactility/Source/service/espnow/EspNowBackendNative.cpp b/Tactility/Source/service/espnow/EspNowBackendNative.cpp index 10597cdf7..887f25357 100644 --- a/Tactility/Source/service/espnow/EspNowBackendNative.cpp +++ b/Tactility/Source/service/espnow/EspNowBackendNative.cpp @@ -2,7 +2,7 @@ #include #endif -#if defined(CONFIG_SOC_WIFI_SUPPORTED) && !defined(CONFIG_ESP_HOSTED_ENABLED) +#if defined(CONFIG_SOC_WIFI_SUPPORTED) && !defined(CONFIG_ESP_HOSTED_HOST) #include #include @@ -205,4 +205,4 @@ uint32_t getVersion() { } -#endif // CONFIG_SOC_WIFI_SUPPORTED && !CONFIG_ESP_HOSTED_ENABLED +#endif // CONFIG_SOC_WIFI_SUPPORTED && !CONFIG_ESP_HOSTED_HOST diff --git a/Tactility/idf_component.yml b/Tactility/idf_component.yml index e513d89d7..3f24865ee 100644 --- a/Tactility/idf_component.yml +++ b/Tactility/idf_component.yml @@ -6,11 +6,11 @@ dependencies: rules: - if: "target in [esp32s3, esp32c6, esp32p4]" espressif/esp_hosted: - version: "2.12.11" + version: "3.0.7" rules: - if: "target == esp32p4" espressif/esp_wifi_remote: - version: "1.2.3" + version: "1.6.4" rules: - if: "target == esp32p4" espressif/esp_lcd_ili9341: diff --git a/device.py b/device.py index d3b872a5a..2f7b4ef61 100644 --- a/device.py +++ b/device.py @@ -118,6 +118,12 @@ def write_partition_table(output_file, device_properties: dict, is_dev: bool): output_file.write("CONFIG_PARTITION_TABLE_CUSTOM=y\n") output_file.write(f"CONFIG_PARTITION_TABLE_CUSTOM_FILENAME=\"{partition_filename}\"\n") output_file.write(f"CONFIG_PARTITION_TABLE_FILENAME=\"{partition_filename}\"\n") + idf_target = get_property_or_exit(device_properties, "hardware.target").lower() + if idf_target == "esp32p4": + # ESP-IDF 6.1's P4 bootloader (0x6140 bytes) no longer fits under the default + # CONFIG_PARTITION_TABLE_OFFSET=0x8000 budget (max 0x6000), regardless of device config. + # The partition CSVs leave their offsets blank so they auto-place relative to this value. + output_file.write("CONFIG_PARTITION_TABLE_OFFSET=0x10000\n") def write_tactility_variables(output_file, device_properties: dict, device_id: str): # Board and vendor @@ -176,6 +182,14 @@ def write_core_variables(output_file, device_properties: dict): output_file.write("CONFIG_ESP_WIFI_RX_IRAM_OPT=n\n") output_file.write("CONFIG_HEAP_PLACE_FUNCTION_INTO_FLASH=y\n") output_file.write("CONFIG_RINGBUF_PLACE_ISR_FUNCTIONS_INTO_FLASH=y\n") + if idf_target == "esp32p4": + # EspNowBackendHosted.cpp's esp_hosted_send_custom_data()/esp_hosted_register_custom_callback() + # need esp_hosted's peer-data feature enabled to exist at all. + output_file.write("CONFIG_ESP_HOSTED_HOST_FEAT_PEER_DATA=y\n") + # ESP-IDF 6.1 defaults to requiring chip rev >=v3.1; boards in this repo (e.g. m5stack-tab5) + # ship v1.0 silicon, which that bootloader refuses to boot. + output_file.write("CONFIG_ESP32P4_SELECTS_REV_LESS_V3=y\n") + output_file.write("CONFIG_ESP32P4_REV_MIN_100=y\n") def write_flash_variables(output_file, device_properties: dict): flash_size = get_property_or_exit(device_properties, "hardware.flashSize") if not flash_size.endswith("MB"): @@ -411,7 +425,10 @@ def write_bluetooth_variables(output_file, device_properties: dict): output_file.write("CONFIG_BT_NIMBLE_ENABLED=y\n") if idf_target == "esp32p4": output_file.write("CONFIG_BT_NIMBLE_TRANSPORT_UART=n\n") - output_file.write("CONFIG_ESP_HOSTED_ENABLE_BT_NIMBLE=y\n") + # esp_hosted 3.0 removed the legacy ESP_HOSTED_ENABLE_BT_NIMBLE knob in favor + # of a stack-agnostic feature flag; the app binds NimBLE to it explicitly via + # esp_hosted_bt_host_stack_setup() (see esp32_ble.cpp). + output_file.write("CONFIG_ESP_HOSTED_HOST_FEAT_BT=y\n") # Move NimBLE host buffers to SPIRAM when available, regardless of target. # The default (INTERNAL) mode causes heap fragmentation after a disable+deinit # cycle, preventing a subsequent nimble_port_init() from allocating its buffers diff --git a/partitions-16mb-no-sd-dev.csv b/partitions-16mb-no-sd-dev.csv index 5d69f3878..2a508da19 100644 --- a/partitions-16mb-no-sd-dev.csv +++ b/partitions-16mb-no-sd-dev.csv @@ -1,7 +1,7 @@ # Name, Type, SubType, Offset, Size, Flags -# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap -nvs, data, nvs, 0x9000, 0x6000, -phy_init, data, phy, 0xf000, 0x1000, -factory, app, factory, 0x10000, 4M, +# Offsets are left blank so the build auto-places partitions relative to CONFIG_PARTITION_TABLE_OFFSET (see device.py), including on targets where that offset is bumped to fit a larger bootloader. +nvs, data, nvs, , 0x6000, +phy_init, data, phy, , 0x1000, +factory, app, factory, , 4M, system, data, fat, , 128k, data, data, fat, , 1000k, diff --git a/partitions-16mb-no-sd.csv b/partitions-16mb-no-sd.csv index 65eeb5a8a..dd442eed9 100644 --- a/partitions-16mb-no-sd.csv +++ b/partitions-16mb-no-sd.csv @@ -1,7 +1,7 @@ # Name, Type, SubType, Offset, Size, Flags -# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap -nvs, data, nvs, 0x9000, 0x6000, -phy_init, data, phy, 0xf000, 0x1000, -factory, app, factory, 0x10000, 4M, +# Offsets are left blank so the build auto-places partitions relative to CONFIG_PARTITION_TABLE_OFFSET (see device.py), including on targets where that offset is bumped to fit a larger bootloader. +nvs, data, nvs, , 0x6000, +phy_init, data, phy, , 0x1000, +factory, app, factory, , 4M, system, data, fat, , 128k, data, data, fat, , 11800k, diff --git a/partitions-16mb-with-sd.csv b/partitions-16mb-with-sd.csv index 6e011704c..f5795298c 100644 --- a/partitions-16mb-with-sd.csv +++ b/partitions-16mb-with-sd.csv @@ -1,6 +1,6 @@ # Name, Type, SubType, Offset, Size, Flags -# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap -nvs, data, nvs, 0x9000, 0x6000, -phy_init, data, phy, 0xf000, 0x1000, -factory, app, factory, 0x10000, 4M, +# Offsets are left blank so the build auto-places partitions relative to CONFIG_PARTITION_TABLE_OFFSET (see device.py), including on targets where that offset is bumped to fit a larger bootloader. +nvs, data, nvs, , 0x6000, +phy_init, data, phy, , 0x1000, +factory, app, factory, , 4M, system, data, fat, , 128k, diff --git a/partitions-32mb-no-sd-dev.csv b/partitions-32mb-no-sd-dev.csv index 5d69f3878..2a508da19 100644 --- a/partitions-32mb-no-sd-dev.csv +++ b/partitions-32mb-no-sd-dev.csv @@ -1,7 +1,7 @@ # Name, Type, SubType, Offset, Size, Flags -# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap -nvs, data, nvs, 0x9000, 0x6000, -phy_init, data, phy, 0xf000, 0x1000, -factory, app, factory, 0x10000, 4M, +# Offsets are left blank so the build auto-places partitions relative to CONFIG_PARTITION_TABLE_OFFSET (see device.py), including on targets where that offset is bumped to fit a larger bootloader. +nvs, data, nvs, , 0x6000, +phy_init, data, phy, , 0x1000, +factory, app, factory, , 4M, system, data, fat, , 128k, data, data, fat, , 1000k, diff --git a/partitions-32mb-no-sd.csv b/partitions-32mb-no-sd.csv index 21f89df11..3c0b8b6a7 100644 --- a/partitions-32mb-no-sd.csv +++ b/partitions-32mb-no-sd.csv @@ -1,7 +1,7 @@ # Name, Type, SubType, Offset, Size, Flags -# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap -nvs, data, nvs, 0x9000, 0x6000, -phy_init, data, phy, 0xf000, 0x1000, -factory, app, factory, 0x10000, 4M, +# Offsets are left blank so the build auto-places partitions relative to CONFIG_PARTITION_TABLE_OFFSET (see device.py), including on targets where that offset is bumped to fit a larger bootloader. +nvs, data, nvs, , 0x6000, +phy_init, data, phy, , 0x1000, +factory, app, factory, , 4M, system, data, fat, , 128k, data, data, fat, , 28480k, diff --git a/partitions-4mb-with-sd.csv b/partitions-4mb-with-sd.csv index bf83015c4..5b9085582 100644 --- a/partitions-4mb-with-sd.csv +++ b/partitions-4mb-with-sd.csv @@ -1,6 +1,6 @@ # Name, Type, SubType, Offset, Size, Flags -# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap -nvs, data, nvs, 0x9000, 0x6000, -phy_init, data, phy, 0xf000, 0x1000, -factory, app, factory, 0x10000, 3800k, +# Offsets are left blank so the build auto-places partitions relative to CONFIG_PARTITION_TABLE_OFFSET (see device.py), including on targets where that offset is bumped to fit a larger bootloader. +nvs, data, nvs, , 0x6000, +phy_init, data, phy, , 0x1000, +factory, app, factory, , 3800k, system, data, fat, , 128k, diff --git a/partitions-8mb-no-sd-dev.csv b/partitions-8mb-no-sd-dev.csv index 5d69f3878..2a508da19 100644 --- a/partitions-8mb-no-sd-dev.csv +++ b/partitions-8mb-no-sd-dev.csv @@ -1,7 +1,7 @@ # Name, Type, SubType, Offset, Size, Flags -# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap -nvs, data, nvs, 0x9000, 0x6000, -phy_init, data, phy, 0xf000, 0x1000, -factory, app, factory, 0x10000, 4M, +# Offsets are left blank so the build auto-places partitions relative to CONFIG_PARTITION_TABLE_OFFSET (see device.py), including on targets where that offset is bumped to fit a larger bootloader. +nvs, data, nvs, , 0x6000, +phy_init, data, phy, , 0x1000, +factory, app, factory, , 4M, system, data, fat, , 128k, data, data, fat, , 1000k, diff --git a/partitions-8mb-no-sd.csv b/partitions-8mb-no-sd.csv index bdc40599e..87c19cf6a 100644 --- a/partitions-8mb-no-sd.csv +++ b/partitions-8mb-no-sd.csv @@ -1,7 +1,7 @@ # Name, Type, SubType, Offset, Size, Flags -# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap -nvs, data, nvs, 0x9000, 0x6000, -phy_init, data, phy, 0xf000, 0x1000, -factory, app, factory, 0x10000, 4M, +# Offsets are left blank so the build auto-places partitions relative to CONFIG_PARTITION_TABLE_OFFSET (see device.py), including on targets where that offset is bumped to fit a larger bootloader. +nvs, data, nvs, , 0x6000, +phy_init, data, phy, , 0x1000, +factory, app, factory, , 4M, system, data, fat, , 128k, data, data, fat, , 3800k, diff --git a/partitions-8mb-with-sd.csv b/partitions-8mb-with-sd.csv index 6e011704c..f5795298c 100644 --- a/partitions-8mb-with-sd.csv +++ b/partitions-8mb-with-sd.csv @@ -1,6 +1,6 @@ # Name, Type, SubType, Offset, Size, Flags -# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap -nvs, data, nvs, 0x9000, 0x6000, -phy_init, data, phy, 0xf000, 0x1000, -factory, app, factory, 0x10000, 4M, +# Offsets are left blank so the build auto-places partitions relative to CONFIG_PARTITION_TABLE_OFFSET (see device.py), including on targets where that offset is bumped to fit a larger bootloader. +nvs, data, nvs, , 0x6000, +phy_init, data, phy, , 0x1000, +factory, app, factory, , 4M, system, data, fat, , 128k,