mirror of
https://github.com/ByteWelder/Tactility.git
synced 2026-10-17 02:45:05 +00:00
Fixes
This commit is contained in:
parent
026532b1f0
commit
15735af476
@ -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())
|
||||
|
||||
@ -102,12 +102,10 @@ static int pin_or_unused(const GpioPinSpec& pin) {
|
||||
return pin.gpio_controller == nullptr ? -1 : static_cast<int>(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<Ili9881cInternal*>(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<float>(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<float>(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
|
||||
|
||||
@ -73,12 +73,10 @@ static int pin_or_unused(const GpioPinSpec& pin) {
|
||||
return pin.gpio_controller == nullptr ? -1 : static_cast<int>(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<Jd9165Internal*>(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<float>(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<float>(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
|
||||
|
||||
@ -102,12 +102,10 @@ static int pin_or_unused(const GpioPinSpec& pin) {
|
||||
return pin.gpio_controller == nullptr ? -1 : static_cast<int>(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<St7121Internal*>(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<float>(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<float>(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
|
||||
|
||||
@ -102,12 +102,10 @@ static int pin_or_unused(const GpioPinSpec& pin) {
|
||||
return pin.gpio_controller == nullptr ? -1 : static_cast<int>(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<St7123Internal*>(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<float>(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<float>(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
|
||||
|
||||
@ -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 <cmath> 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:
|
||||
|
||||
@ -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<char>` 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<const char*>`
|
||||
- `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<char>` 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
|
||||
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
#include <cstdint>
|
||||
#include <new>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#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<char> 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<const std::string*>(str), pos, len);
|
||||
}
|
||||
// Same story for basic_string(const char*, allocator<char> const&).
|
||||
void construct_basic_string_from_cstr(void* self, const char* s, const void* alloc) {
|
||||
new (self) std::string(s, *static_cast<const std::allocator<char>*>(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<std::string*>(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
|
||||
|
||||
@ -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 ()
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 <sdkconfig.h>
|
||||
#if defined(CONFIG_BT_NIMBLE_ENABLED) && defined(CONFIG_ESP_HOSTED_ENABLED)
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdatomic.h>
|
||||
#include <string.h>
|
||||
#include <esp_log.h>
|
||||
#include <esp_err.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
|
||||
// NimBLE transport + HCI
|
||||
#include <nimble/transport.h>
|
||||
#include <nimble/hci_common.h>
|
||||
#include <os/os_mbuf.h>
|
||||
|
||||
// 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
|
||||
@ -29,14 +29,9 @@ constexpr auto* TAG = "esp32_ble";
|
||||
#include <tactility/log.h>
|
||||
#include <esp_timer.h>
|
||||
|
||||
#if defined(CONFIG_ESP_HOSTED_ENABLED)
|
||||
#if defined(CONFIG_ESP_HOSTED_HOST)
|
||||
#include <esp_hosted.h>
|
||||
// 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 <esp_hosted_misc.h>
|
||||
}
|
||||
#include <esp_hosted_bt_host_stack.h>
|
||||
#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);
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
#include <sdkconfig.h>
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_ESP_HOSTED_ENABLED)
|
||||
#if defined(CONFIG_ESP_HOSTED_HOST)
|
||||
|
||||
#include <tactility/drivers/esp32_esp_hosted_ota.h>
|
||||
#include <tactility/drivers/wifi.h>
|
||||
@ -251,4 +251,4 @@ const FirmwareOps* esp32_esp_hosted_ota_get_ops() {
|
||||
return &firmwareOps;
|
||||
}
|
||||
|
||||
#endif // CONFIG_ESP_HOSTED_ENABLED
|
||||
#endif // CONFIG_ESP_HOSTED_HOST
|
||||
|
||||
@ -20,7 +20,7 @@
|
||||
|
||||
#include <TactilityCpp/Allocator.h>
|
||||
|
||||
#if defined(CONFIG_ESP_HOSTED_ENABLED)
|
||||
#if defined(CONFIG_ESP_HOSTED_HOST)
|
||||
#include <tactility/drivers/esp32_esp_hosted_ota.h>
|
||||
#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.
|
||||
|
||||
@ -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 <sdkconfig.h>
|
||||
#if CONFIG_IDF_TARGET_ESP32P4
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
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
|
||||
@ -2,7 +2,7 @@
|
||||
#include <sdkconfig.h>
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_ESP_HOSTED_ENABLED)
|
||||
#if defined(CONFIG_ESP_HOSTED_HOST)
|
||||
|
||||
#include <Tactility/service/espnow/EspNowBackend.h>
|
||||
#include <Tactility/service/espnow/EspNowHostedTransport.h>
|
||||
@ -310,4 +310,4 @@ uint32_t getVersion() {
|
||||
|
||||
}
|
||||
|
||||
#endif // CONFIG_ESP_HOSTED_ENABLED
|
||||
#endif // CONFIG_ESP_HOSTED_HOST
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
#include <sdkconfig.h>
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SOC_WIFI_SUPPORTED) && !defined(CONFIG_ESP_HOSTED_ENABLED)
|
||||
#if defined(CONFIG_SOC_WIFI_SUPPORTED) && !defined(CONFIG_ESP_HOSTED_HOST)
|
||||
|
||||
#include <Tactility/service/espnow/EspNowBackend.h>
|
||||
#include <Tactility/service/wifi/Wifi.h>
|
||||
@ -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
|
||||
|
||||
@ -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:
|
||||
|
||||
19
device.py
19
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
|
||||
|
||||
@ -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,
|
||||
|
||||
|
@ -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,
|
||||
|
||||
|
@ -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,
|
||||
|
||||
|
@ -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,
|
||||
|
||||
|
@ -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,
|
||||
|
||||
|
@ -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,
|
||||
|
||||
|
@ -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,
|
||||
|
||||
|
@ -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,
|
||||
|
||||
|
@ -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,
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user