mirror of
https://github.com/esphome/esphome.git
synced 2026-09-11 15:27:33 +00:00
[esp32] Enable ESP-IDF Log V2 on IDF 6.1+
This commit is contained in:
@@ -2214,6 +2214,18 @@ async def to_code(config):
|
||||
# This saves ~250 bytes of RAM (tag cache) and associated code
|
||||
add_idf_sdkconfig_option("CONFIG_LOG_TAG_LEVEL_IMPL_NONE", True)
|
||||
|
||||
# ESP-IDF Log V2 centralizes formatting inside esp_log(), removing the
|
||||
# per-site macro expansions of V1 (saves ~4KB flash, ~180B RAM). Only enable
|
||||
# on IDF >= 6.1, where CONFIG_LOG_API_CONSTRAINED_ENV_SAFE=n lets
|
||||
# ESP_DRAM_LOGx / ESP_EARLY_LOGx expand directly to esp_rom_printf and drops
|
||||
# the ~1.2KB esp_rom_vprintf that would otherwise sit in IRAM. Below 6.1 the
|
||||
# option does not exist, so we stay on V1 unchanged.
|
||||
if idf_version() >= cv.Version(6, 1, 0):
|
||||
add_idf_sdkconfig_option("CONFIG_LOG_VERSION_1", False)
|
||||
add_idf_sdkconfig_option("CONFIG_LOG_VERSION_2", True)
|
||||
add_idf_sdkconfig_option("CONFIG_LOG_API_CONSTRAINED_ENV_SAFE", False)
|
||||
cg.add_define("USE_ESP32_LOG_V2")
|
||||
|
||||
# Reduce PHY TX power in the event of a brownout
|
||||
add_idf_sdkconfig_option("CONFIG_ESP_PHY_REDUCE_TX_POWER", True)
|
||||
|
||||
|
||||
@@ -246,6 +246,7 @@
|
||||
#define BLUETOOTH_PROXY_MAX_CONNECTIONS 3
|
||||
#define BLUETOOTH_PROXY_ADVERTISEMENT_BATCH_SIZE 16
|
||||
#define USE_CAPTIVE_PORTAL
|
||||
#define USE_ESP32_LOG_V2
|
||||
#define USE_ESP32_BLE
|
||||
#define USE_ESP32_BLE_MAX_CONNECTIONS 3
|
||||
#define USE_ESP32_BLE_CLIENT
|
||||
|
||||
@@ -86,3 +86,79 @@ int HOT esp_idf_log_vprintf_(const char *format, va_list args) { // NOLINT
|
||||
#endif
|
||||
|
||||
} // namespace esphome
|
||||
|
||||
#if defined(USE_ESP32_LOG_V2) && !defined(BOOTLOADER_BUILD)
|
||||
// Override esp_log_format to prevent V2's 3-call vprintf fragmentation.
|
||||
// Without this, Log V2 calls the vprintf hook 3 times per message (header,
|
||||
// body, newline) which creates 3 separate log entries in ESPHome's logger.
|
||||
// This strong definition overrides the archive symbol from ESP-IDF's liblog,
|
||||
// affecting all callers including precompiled blobs (e.g. wifi).
|
||||
#include <esp_private/log_message.h>
|
||||
#include <esp_log_write.h>
|
||||
|
||||
// Format an ESP-IDF log message directly to the console, bypassing the
|
||||
// ESPHome logger hook. Used when the hook isn't installed (early boot) or
|
||||
// can't be used safely (constrained env: PHY init, efuse reads -- fwrite
|
||||
// locks crash on USB JTAG devices).
|
||||
// Formats in ESPHome style with ANSI colors into a 512-byte stack buffer,
|
||||
// then outputs atomically via esp_rom_printf.
|
||||
// This path is cold on 99.9% of builds -- it only runs during early boot
|
||||
// and at DEBUG framework log level (default is ERROR).
|
||||
static void __attribute__((noinline)) esp_log_format_direct_(esp_log_msg_t *message) {
|
||||
// ESP-IDF levels: NONE=0 ERROR=1 WARN=2 INFO=3 DEBUG=4 VERBOSE=5
|
||||
// Color digits: E=1(red) W=3(yellow) I=2(green) D=6(cyan) V=7(gray)
|
||||
static const char color_digit[] = {'\0', '1', '3', '2', '6', '7'};
|
||||
static const char lvl[] = {'\0', 'E', 'W', 'I', 'D', 'V'};
|
||||
// Format into stack buffer and output atomically via esp_rom_printf.
|
||||
// Can't use fwrite (locks crash during early boot and PHY init).
|
||||
char buf[512];
|
||||
int pos = 0;
|
||||
uint8_t level = message->config.opts.log_level;
|
||||
if (level > 0 && level < sizeof(lvl)) {
|
||||
pos = snprintf(buf, sizeof(buf), "\033[0;3%cm[%c][%s]: ", color_digit[level], lvl[level],
|
||||
message->tag ? message->tag : "idf");
|
||||
}
|
||||
if (pos >= 0 && pos < (int) sizeof(buf) - 2) {
|
||||
int body = vsnprintf(buf + pos, sizeof(buf) - pos, message->format, message->args);
|
||||
if (body > 0)
|
||||
pos += (body < (int) sizeof(buf) - pos) ? body : (int) sizeof(buf) - pos - 1;
|
||||
}
|
||||
if (level > 0 && level < sizeof(lvl) && pos < (int) sizeof(buf) - 6) {
|
||||
pos += snprintf(buf + pos, sizeof(buf) - pos, "\033[0m");
|
||||
}
|
||||
if (pos < (int) sizeof(buf) - 1) {
|
||||
buf[pos++] = '\n';
|
||||
}
|
||||
buf[pos] = '\0';
|
||||
esp_rom_printf("%s", buf);
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
// Override esp_log_format from liblog.a to prevent V2's 3-call vprintf
|
||||
// fragmentation. IRAM_ATTR to match esp_log_va's IRAM placement and avoid
|
||||
// an IRAM->flash cache miss on every ESP-IDF log call. This function is
|
||||
// tiny (~43 bytes) so the IRAM cost is negligible.
|
||||
void IRAM_ATTR esp_log_format(esp_log_msg_t *message) {
|
||||
extern vprintf_like_t esp_log_vprint_func;
|
||||
extern int vprintf(const char *, __gnuc_va_list); // NOLINT
|
||||
if (esp_log_vprint_func == &vprintf || message->config.opts.constrained_env) [[unlikely]] {
|
||||
// Early boot or constrained env (PHY init, efuse reads, scheduler not
|
||||
// running). Can't use the ESPHome hook -- fwrite locks crash during PHY
|
||||
// init on USB JTAG devices and newlib isn't initialized during early boot.
|
||||
// Format to stack buffer with vsnprintf + esp_rom_printf instead.
|
||||
//
|
||||
// Note: if called from an ISR with flash cache disabled, this will crash
|
||||
// because the format string and tag are in flash. This is the same as V1
|
||||
// where ESP_EARLY_LOGx from ISR also used flash-resident format strings
|
||||
// via esp_rom_printf. No ESP-IDF code is known to log from ISR with
|
||||
// cache disabled.
|
||||
esp_log_format_direct_(message);
|
||||
return;
|
||||
}
|
||||
// After hook installed, normal environment: skip formatting, forward body only.
|
||||
// Call esp_log_vprint_func directly to avoid pulling in esp_rom_vprintf
|
||||
// (1.2KB IRAM) through the esp_log_vprintf inline.
|
||||
esp_log_vprint_func(message->format, message->args);
|
||||
}
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user