From 47655129e12aa1d2232a14153ce9654bcae828f8 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 8 Oct 2026 21:44:06 -1000 Subject: [PATCH] Share the outlined PROGMEM append for the progmem string dump --- esphome/components/api/api_pb2_dump.cpp | 11 +++++------ esphome/components/api/proto.h | 11 +++++++++++ script/api_protobuf/api_protobuf.py | 11 +++++------ 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/esphome/components/api/api_pb2_dump.cpp b/esphome/components/api/api_pb2_dump.cpp index f74aa72741e..a50c12bd552 100644 --- a/esphome/components/api/api_pb2_dump.cpp +++ b/esphome/components/api/api_pb2_dump.cpp @@ -12,8 +12,9 @@ namespace esphome::api { #ifdef USE_ESP8266 // Out-of-line to avoid inlining strlen_P/memcpy_P at every call site -void DumpBuffer::append_p_esp8266(const char *str) { - size_t len = strlen_P(str); +void DumpBuffer::append_p_esp8266(const char *str) { this->append_p_esp8266(str, strlen_P(str)); } + +void DumpBuffer::append_p_esp8266(const char *str, size_t len) { size_t space = CAPACITY - 1 - pos_; if (len > space) len = space; @@ -135,13 +136,11 @@ static void dump_progmem_bytes_field(DumpBuffer &out, const char *field_name, co dump_bytes_field(out, field_name, data_buf, len, indent); } -// Helper for string fields in flash: copies straight into the dump buffer, which bounds the length +// Helper for string fields in flash static void dump_progmem_string_field(DumpBuffer &out, const char *field_name, const ProgmemStringRef &value, int indent = 2) { append_field_prefix(out, field_name, indent); - out.append("'"); - out.set_pos(out.pos() + value.write_to(out.data() + out.pos(), DumpBuffer::CAPACITY - out.pos())); - out.append("'\n"); + out.append("'").append_p(value.progmem_ptr(), value.size()).append("'\n"); } #pragma GCC diagnostic pop diff --git a/esphome/components/api/proto.h b/esphome/components/api/proto.h index 55021186a62..245032f83dc 100644 --- a/esphome/components/api/proto.h +++ b/esphome/components/api/proto.h @@ -708,9 +708,20 @@ class DumpBuffer { return *this; } + /// Append len bytes of a PROGMEM string + DumpBuffer &append_p(const char *str, size_t len) { +#ifdef USE_ESP8266 + append_p_esp8266(str, len); +#else + append_impl_(str, len); +#endif + return *this; + } + #ifdef USE_ESP8266 /// Out-of-line ESP8266 PROGMEM append to avoid inlining strlen_P/memcpy_P at every call site void append_p_esp8266(const char *str); + void append_p_esp8266(const char *str, size_t len); #endif const char *c_str() const { return buf_; } diff --git a/script/api_protobuf/api_protobuf.py b/script/api_protobuf/api_protobuf.py index c0eb46c2777..4760890aab6 100755 --- a/script/api_protobuf/api_protobuf.py +++ b/script/api_protobuf/api_protobuf.py @@ -3268,8 +3268,9 @@ namespace esphome::api { #ifdef USE_ESP8266 // Out-of-line to avoid inlining strlen_P/memcpy_P at every call site -void DumpBuffer::append_p_esp8266(const char *str) { - size_t len = strlen_P(str); +void DumpBuffer::append_p_esp8266(const char *str) { this->append_p_esp8266(str, strlen_P(str)); } + +void DumpBuffer::append_p_esp8266(const char *str, size_t len) { size_t space = CAPACITY - 1 - pos_; if (len > space) len = space; @@ -3391,13 +3392,11 @@ static void dump_progmem_bytes_field(DumpBuffer &out, const char *field_name, co dump_bytes_field(out, field_name, data_buf, len, indent); } -// Helper for string fields in flash: copies straight into the dump buffer, which bounds the length +// Helper for string fields in flash static void dump_progmem_string_field(DumpBuffer &out, const char *field_name, const ProgmemStringRef &value, int indent = 2) { append_field_prefix(out, field_name, indent); - out.append("'"); - out.set_pos(out.pos() + value.write_to(out.data() + out.pos(), DumpBuffer::CAPACITY - out.pos())); - out.append("'\\n"); + out.append("'").append_p(value.progmem_ptr(), value.size()).append("'\\n"); } #pragma GCC diagnostic pop