From 819bc0a0f23f94a01972750548771327a25e6e3a Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 31 Dec 2025 22:45:45 -1000 Subject: [PATCH] [abbwelcome] Use stack-based formatting to eliminate heap allocations --- .../remote_base/abbwelcome_protocol.cpp | 14 +++-- .../remote_base/abbwelcome_protocol.h | 53 +++++++++++++------ 2 files changed, 47 insertions(+), 20 deletions(-) diff --git a/esphome/components/remote_base/abbwelcome_protocol.cpp b/esphome/components/remote_base/abbwelcome_protocol.cpp index 88f928901b..352ae10ed7 100644 --- a/esphome/components/remote_base/abbwelcome_protocol.cpp +++ b/esphome/components/remote_base/abbwelcome_protocol.cpp @@ -51,7 +51,8 @@ void ABBWelcomeProtocol::encode(RemoteTransmitData *dst, const ABBWelcomeData &s dst->reserve(reserve_count); for (size_t i = 0; i < src.size(); i++) this->encode_byte_(dst, src[i]); - ESP_LOGD(TAG, "Transmitting: %s", src.to_string().c_str()); + char buf[ABBWelcomeData::FORMAT_BUFFER_SIZE]; + ESP_LOGD(TAG, "Transmitting: %s", src.format_to(buf)); } bool ABBWelcomeProtocol::decode_byte_(RemoteReceiveData &src, bool &done, uint8_t &data) { @@ -94,7 +95,8 @@ optional ABBWelcomeProtocol::decode(RemoteReceiveData src) { for (; (received_bytes < length) && !done; received_bytes++) { uint8_t data = 0; if (!this->decode_byte_(src, done, data)) { - ESP_LOGW(TAG, "Received incomplete packet: %s", out.to_string(received_bytes).c_str()); + char buf[ABBWelcomeData::FORMAT_BUFFER_SIZE]; + ESP_LOGW(TAG, "Received incomplete packet: %s", out.format_to(buf, received_bytes)); return {}; } if (received_bytes == 2) { @@ -106,17 +108,19 @@ optional ABBWelcomeProtocol::decode(RemoteReceiveData src) { ESP_LOGVV(TAG, "Received Byte: 0x%02X", data); out[received_bytes] = data; } + char buf[ABBWelcomeData::FORMAT_BUFFER_SIZE]; if (out.is_valid()) { - ESP_LOGI(TAG, "Received: %s", out.to_string().c_str()); + ESP_LOGI(TAG, "Received: %s", out.format_to(buf)); return out; } - ESP_LOGW(TAG, "Received malformed packet: %s", out.to_string(received_bytes).c_str()); + ESP_LOGW(TAG, "Received malformed packet: %s", out.format_to(buf, received_bytes)); } return {}; } void ABBWelcomeProtocol::dump(const ABBWelcomeData &data) { - ESP_LOGD(TAG, "Received ABBWelcome: %s", data.to_string().c_str()); + char buf[ABBWelcomeData::FORMAT_BUFFER_SIZE]; + ESP_LOGD(TAG, "Received ABBWelcome: %s", data.format_to(buf)); } } // namespace remote_base diff --git a/esphome/components/remote_base/abbwelcome_protocol.h b/esphome/components/remote_base/abbwelcome_protocol.h index b8d9293c11..5ac6676d19 100644 --- a/esphome/components/remote_base/abbwelcome_protocol.h +++ b/esphome/components/remote_base/abbwelcome_protocol.h @@ -136,22 +136,45 @@ class ABBWelcomeData { this->data_[1] = 0xff; this->data_[this->size() - 1] = this->calc_cs_(); } - std::string to_string(uint8_t max_print_bytes = 255) const { - std::string info; - if (this->is_valid()) { - info = str_sprintf(this->get_three_byte_address() ? "[%06" PRIX32 " %s %06" PRIX32 "] Type: %02X" - : "[%04" PRIX32 " %s %04" PRIX32 "] Type: %02X", - this->get_source_address(), this->get_retransmission() ? "»" : ">", - this->get_destination_address(), this->get_message_type()); - if (this->get_data_size()) - info += str_sprintf(", Data: %s", format_hex_pretty(this->get_data()).c_str()); - } else { - info = "[Invalid]"; - } + // Buffer size for format_to(): raw_hex(81) + space(1) + brackets/addrs/type(~35) + data(53) + null(1) + static constexpr size_t FORMAT_BUFFER_SIZE = 192; + + char *format_to(char *buffer, uint8_t max_print_bytes = 255) const { + size_t remaining = FORMAT_BUFFER_SIZE; + char *ptr = buffer; + uint8_t print_bytes = std::min(this->size(), max_print_bytes); - if (print_bytes) - info = str_sprintf("%s %s", format_hex_pretty(this->data_.data(), print_bytes).c_str(), info.c_str()); - return info; + if (print_bytes) { + char raw_hex[format_hex_pretty_size(12 + MAX_DATA_LENGTH)]; + format_hex_pretty_to(raw_hex, this->data_.data(), print_bytes, '.'); + int written = snprintf(ptr, remaining, "%s ", raw_hex); + if (written > 0 && static_cast(written) < remaining) { + ptr += written; + remaining -= written; + } + } + + if (this->is_valid()) { + int written = snprintf(ptr, remaining, + this->get_three_byte_address() ? "[%06" PRIX32 " %s %06" PRIX32 "] Type: %02X" + : "[%04" PRIX32 " %s %04" PRIX32 "] Type: %02X", + this->get_source_address(), this->get_retransmission() ? "»" : ">", + this->get_destination_address(), this->get_message_type()); + if (written > 0 && static_cast(written) < remaining) { + ptr += written; + remaining -= written; + } + if (this->get_data_size() && remaining > 1) { + char data_hex[format_hex_pretty_size(MAX_DATA_LENGTH)]; + format_hex_pretty_to(data_hex, this->data_.data() + 5 + 2 * this->get_address_length(), this->get_data_size(), + '.'); + snprintf(ptr, remaining, ", Data: %s", data_hex); + } + } else { + snprintf(ptr, remaining, "[Invalid]"); + } + + return buffer; } bool operator==(const ABBWelcomeData &rhs) const { if (std::equal(this->data_.begin(), this->data_.begin() + this->size(), rhs.data_.begin()))