1
0
mirror of https://github.com/esphome/esphome.git synced 2025-11-16 14:55:50 +00:00

Compare commits

...

12 Commits

Author SHA1 Message Date
J. Nick Koston
d60c358f48 preen 2025-11-15 18:43:39 -06:00
J. Nick Koston
26b820272a optimize esp8266 as well 2025-11-15 18:36:39 -06:00
J. Nick Koston
9557c90c20 comment 2025-11-15 18:31:07 -06:00
J. Nick Koston
d64bcf27b3 cleanup 2025-11-15 18:17:50 -06:00
J. Nick Koston
d5d61546e7 cleanup 2025-11-15 18:15:10 -06:00
J. Nick Koston
554cdbd5a4 bot is right 2025-11-15 18:03:08 -06:00
J. Nick Koston
0d147e5d10 missed one 2025-11-15 17:42:01 -06:00
J. Nick Koston
730a70ee8b missed header 2025-11-15 17:37:37 -06:00
J. Nick Koston
d096f1192d make bot happy 2025-11-15 17:35:41 -06:00
J. Nick Koston
88a23acc4b tweak 2025-11-15 17:19:37 -06:00
J. Nick Koston
950dff1a38 [logger] Reduce ESP32 UART mutex overhead by 50% 2025-11-15 16:54:18 -06:00
J. Nick Koston
61eddfdcda [logger] Reduce ESP32 UART mutex overhead by 50% 2025-11-15 16:47:35 -06:00
9 changed files with 84 additions and 37 deletions

View File

@@ -365,8 +365,10 @@ async def to_code(config):
if CORE.is_esp32:
if config[CONF_HARDWARE_UART] == USB_CDC:
add_idf_sdkconfig_option("CONFIG_ESP_CONSOLE_USB_CDC", True)
cg.add_define("USE_LOGGER_UART_SELECTION_USB_CDC")
elif config[CONF_HARDWARE_UART] == USB_SERIAL_JTAG:
add_idf_sdkconfig_option("CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG", True)
cg.add_define("USE_LOGGER_UART_SELECTION_USB_SERIAL_JTAG")
try:
uart_selection(USB_SERIAL_JTAG)
cg.add_define("USE_LOGGER_USB_SERIAL_JTAG")

View File

@@ -65,7 +65,9 @@ void HOT Logger::log_vprintf_(uint8_t level, const char *tag, int line, const ch
uint16_t buffer_at = 0; // Initialize buffer position
this->format_log_to_buffer_with_terminator_(level, tag, line, format, args, console_buffer, &buffer_at,
MAX_CONSOLE_LOG_MSG_SIZE);
this->write_msg_(console_buffer);
// Add newline if platform needs it (ESP32 doesn't add via write_msg_)
this->add_newline_to_buffer_if_needed_(console_buffer, &buffer_at, MAX_CONSOLE_LOG_MSG_SIZE);
this->write_msg_(console_buffer, buffer_at);
}
// Reset the recursion guard for this task
@@ -131,18 +133,19 @@ void Logger::log_vprintf_(uint8_t level, const char *tag, int line, const __Flas
// Save the offset before calling format_log_to_buffer_with_terminator_
// since it will increment tx_buffer_at_ to the end of the formatted string
uint32_t msg_start = this->tx_buffer_at_;
uint16_t msg_start = this->tx_buffer_at_;
this->format_log_to_buffer_with_terminator_(level, tag, line, this->tx_buffer_, args, this->tx_buffer_,
&this->tx_buffer_at_, this->tx_buffer_size_);
// Write to console and send callback starting at the msg_start
if (this->baud_rate_ > 0) {
this->write_msg_(this->tx_buffer_ + msg_start);
}
size_t msg_length =
uint16_t msg_length =
this->tx_buffer_at_ - msg_start; // Don't subtract 1 - tx_buffer_at_ is already at the null terminator position
// Callbacks get message first (before console write)
this->log_callback_.call(level, tag, this->tx_buffer_ + msg_start, msg_length);
// Write to console starting at the msg_start
this->write_tx_buffer_to_console_(msg_start, &msg_length);
global_recursion_guard_ = false;
}
#endif // USE_STORE_LOG_STR_IN_FLASH
@@ -209,9 +212,7 @@ void Logger::process_messages_() {
// This ensures all log messages appear on the console in a clean, serialized manner
// Note: Messages may appear slightly out of order due to async processing, but
// this is preferred over corrupted/interleaved console output
if (this->baud_rate_ > 0) {
this->write_msg_(this->tx_buffer_);
}
this->write_tx_buffer_to_console_();
}
} else {
// No messages to process, disable loop if appropriate

View File

@@ -71,6 +71,17 @@ static constexpr uint16_t MAX_HEADER_SIZE = 128;
// "0x" + 2 hex digits per byte + '\0'
static constexpr size_t MAX_POINTER_REPRESENTATION = 2 + sizeof(void *) * 2 + 1;
// Platform-specific: does write_msg_ add its own newline?
// false: Caller must add newline to buffer before calling write_msg_ (ESP32, ESP8266)
// Allows single write call with newline included for efficiency
// true: write_msg_ adds newline itself via puts()/println() (other platforms)
// Newline should NOT be added to buffer
#if defined(USE_ESP32) || defined(USE_ESP8266)
static constexpr bool WRITE_MSG_ADDS_NEWLINE = false;
#else
static constexpr bool WRITE_MSG_ADDS_NEWLINE = true;
#endif
#if defined(USE_ESP32) || defined(USE_ESP8266) || defined(USE_RP2040) || defined(USE_LIBRETINY) || defined(USE_ZEPHYR)
/** Enum for logging UART selection
*
@@ -173,7 +184,7 @@ class Logger : public Component {
protected:
void process_messages_();
void write_msg_(const char *msg);
void write_msg_(const char *msg, size_t len);
// Format a log message with printf-style arguments and write it to a buffer with header, footer, and null terminator
// It's the caller's responsibility to initialize buffer_at (typically to 0)
@@ -200,6 +211,35 @@ class Logger : public Component {
}
}
// Helper to add newline to buffer for platforms that need it
// Modifies buffer_at to include the newline
inline void HOT add_newline_to_buffer_if_needed_(char *buffer, uint16_t *buffer_at, uint16_t buffer_size) {
if constexpr (!WRITE_MSG_ADDS_NEWLINE) {
// Add newline - don't need to maintain null termination
// write_msg_ now always receives explicit length, so we can safely overwrite the null terminator
// This is safe because:
// 1. Callbacks already received the message (before we add newline)
// 2. write_msg_ receives the length explicitly (doesn't need null terminator)
if (*buffer_at < buffer_size) {
buffer[(*buffer_at)++] = '\n';
} else if (buffer_size > 0) {
// Buffer was full - replace last char with newline to ensure it's visible
buffer[buffer_size - 1] = '\n';
*buffer_at = buffer_size;
}
}
}
// Helper to write tx_buffer_ to console if logging is enabled
// INTERNAL USE ONLY - offset > 0 requires length parameter to be non-null
inline void HOT write_tx_buffer_to_console_(uint16_t offset = 0, uint16_t *length = nullptr) {
if (this->baud_rate_ > 0) {
uint16_t *len_ptr = length ? length : &this->tx_buffer_at_;
this->add_newline_to_buffer_if_needed_(this->tx_buffer_ + offset, len_ptr, this->tx_buffer_size_ - offset);
this->write_msg_(this->tx_buffer_ + offset, *len_ptr);
}
}
// Helper to format and send a log message to both console and callbacks
inline void HOT log_message_to_buffer_and_send_(uint8_t level, const char *tag, int line, const char *format,
va_list args) {
@@ -208,10 +248,11 @@ class Logger : public Component {
this->format_log_to_buffer_with_terminator_(level, tag, line, format, args, this->tx_buffer_, &this->tx_buffer_at_,
this->tx_buffer_size_);
if (this->baud_rate_ > 0) {
this->write_msg_(this->tx_buffer_); // If logging is enabled, write to console
}
// Callbacks get message WITHOUT newline (for API/MQTT/syslog)
this->log_callback_.call(level, tag, this->tx_buffer_, this->tx_buffer_at_);
// Console gets message WITH newline (if platform needs it)
this->write_tx_buffer_to_console_();
}
// Write the body of the log message to the buffer
@@ -425,7 +466,9 @@ class Logger : public Component {
}
// Update buffer_at with the formatted length (handle truncation)
uint16_t formatted_len = (ret >= remaining) ? remaining : ret;
// When vsnprintf truncates (ret >= remaining), it writes (remaining - 1) chars + null terminator
// When it doesn't truncate (ret < remaining), it writes ret chars + null terminator
uint16_t formatted_len = (ret >= remaining) ? (remaining - 1) : ret;
*buffer_at += formatted_len;
// Remove all trailing newlines right after formatting

View File

@@ -121,25 +121,23 @@ void Logger::pre_setup() {
ESP_LOGI(TAG, "Log initialized");
}
void HOT Logger::write_msg_(const char *msg) {
if (
#if defined(USE_LOGGER_USB_CDC) && !defined(USE_LOGGER_USB_SERIAL_JTAG)
this->uart_ == UART_SELECTION_USB_CDC
#elif defined(USE_LOGGER_USB_SERIAL_JTAG) && !defined(USE_LOGGER_USB_CDC)
this->uart_ == UART_SELECTION_USB_SERIAL_JTAG
#elif defined(USE_LOGGER_USB_CDC) && defined(USE_LOGGER_USB_SERIAL_JTAG)
this->uart_ == UART_SELECTION_USB_CDC || this->uart_ == UART_SELECTION_USB_SERIAL_JTAG
void HOT Logger::write_msg_(const char *msg, size_t len) {
// Length is now always passed explicitly - no strlen() fallback needed
#if defined(USE_LOGGER_UART_SELECTION_USB_CDC) || defined(USE_LOGGER_UART_SELECTION_USB_SERIAL_JTAG)
// USB CDC/JTAG - single write including newline (already in buffer)
// Use fwrite to stdout which goes through VFS to USB console
//
// Note: These defines indicate the user's YAML configuration choice (hardware_uart: USB_CDC/USB_SERIAL_JTAG).
// They are ONLY defined when the user explicitly selects USB as the logger output in their config.
// This is compile-time selection, not runtime detection - if USB is configured, it's always used.
// There is no fallback to regular UART if "USB isn't connected" - that's the user's responsibility
// to configure correctly for their hardware. This approach eliminates runtime overhead.
fwrite(msg, 1, len, stdout);
#else
/* DISABLES CODE */ (false) // NOLINT
// Regular UART - single write including newline (already in buffer)
uart_write_bytes(this->uart_num_, msg, len);
#endif
) {
puts(msg);
} else {
// Use tx_buffer_at_ if msg points to tx_buffer_, otherwise fall back to strlen
size_t len = (msg == this->tx_buffer_) ? this->tx_buffer_at_ : strlen(msg);
uart_write_bytes(this->uart_num_, msg, len);
uart_write_bytes(this->uart_num_, "\n", 1);
}
}
const LogString *Logger::get_uart_selection_() {

View File

@@ -33,7 +33,10 @@ void Logger::pre_setup() {
ESP_LOGI(TAG, "Log initialized");
}
void HOT Logger::write_msg_(const char *msg) { this->hw_serial_->println(msg); }
void HOT Logger::write_msg_(const char *msg, size_t len) {
// Single write with newline already in buffer (added by caller)
this->hw_serial_->write(msg, len);
}
const LogString *Logger::get_uart_selection_() {
switch (this->uart_) {

View File

@@ -3,7 +3,7 @@
namespace esphome::logger {
void HOT Logger::write_msg_(const char *msg) {
void HOT Logger::write_msg_(const char *msg, size_t) {
time_t rawtime;
struct tm *timeinfo;
char buffer[80];

View File

@@ -49,7 +49,7 @@ void Logger::pre_setup() {
ESP_LOGI(TAG, "Log initialized");
}
void HOT Logger::write_msg_(const char *msg) { this->hw_serial_->println(msg); }
void HOT Logger::write_msg_(const char *msg, size_t) { this->hw_serial_->println(msg); }
const LogString *Logger::get_uart_selection_() {
switch (this->uart_) {

View File

@@ -27,7 +27,7 @@ void Logger::pre_setup() {
ESP_LOGI(TAG, "Log initialized");
}
void HOT Logger::write_msg_(const char *msg) { this->hw_serial_->println(msg); }
void HOT Logger::write_msg_(const char *msg, size_t) { this->hw_serial_->println(msg); }
const LogString *Logger::get_uart_selection_() {
switch (this->uart_) {

View File

@@ -62,7 +62,7 @@ void Logger::pre_setup() {
ESP_LOGI(TAG, "Log initialized");
}
void HOT Logger::write_msg_(const char *msg) {
void HOT Logger::write_msg_(const char *msg, size_t) {
#ifdef CONFIG_PRINTK
printk("%s\n", msg);
#endif