diff --git a/esphome/components/api/proto.h b/esphome/components/api/proto.h index 189cee9e0e..e01deccbc2 100644 --- a/esphome/components/api/proto.h +++ b/esphome/components/api/proto.h @@ -409,10 +409,6 @@ class ProtoEncode { /// Tag must be a single-byte varint (< 128). Always encodes (no zero check). [[nodiscard]] static inline uint8_t *encode_short_string_force(uint8_t *__restrict__ pos PROTO_ENCODE_DEBUG_PARAM, uint8_t tag, const StringRef &ref) { -#ifdef USE_ESP8266 - // memcpy_P reads RAM too, so RAM strings share the progmem copy - return encode_short_progmem_string_force(pos PROTO_ENCODE_DEBUG_ARG, tag, ProgmemStringRef(ref)); -#else #ifdef ESPHOME_DEBUG_API assert(ref.size() < 128 && "encode_short_string_force: string exceeds max_data_length < 128"); #endif @@ -421,10 +417,8 @@ class ProtoEncode { pos[1] = static_cast(ref.size()); std::memcpy(pos + 2, ref.c_str(), ref.size()); return pos + 2 + ref.size(); -#endif } /// encode_short_string_force for a string that may be in flash (PROGMEM). -#ifdef USE_ESP8266 [[nodiscard]] static inline uint8_t *encode_short_progmem_string_force( uint8_t *__restrict__ pos PROTO_ENCODE_DEBUG_PARAM, uint8_t tag, const ProgmemStringRef &ref) { #ifdef ESPHOME_DEBUG_API @@ -436,12 +430,6 @@ class ProtoEncode { progmem_memcpy(pos + 2, ref.progmem_ptr(), ref.size()); return pos + 2 + ref.size(); } -#else - [[nodiscard]] static inline uint8_t *encode_short_progmem_string_force( - uint8_t *__restrict__ pos PROTO_ENCODE_DEBUG_PARAM, uint8_t tag, const ProgmemStringRef &ref) { - return encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, tag, ref.ram_ref()); - } -#endif /// Write a precomputed tag byte + 32-bit value. Outlined on embedded: one copy beats inline stores per field. [[nodiscard]] static PROTO_OUTLINE_FOR_SIZE uint8_t *write_tag_and_fixed32( uint8_t *__restrict__ pos PROTO_ENCODE_DEBUG_PARAM, uint8_t tag, uint32_t value) { diff --git a/esphome/core/string_ref.h b/esphome/core/string_ref.h index d8c68d7e7f..b5b4a0bdd4 100644 --- a/esphome/core/string_ref.h +++ b/esphome/core/string_ref.h @@ -226,7 +226,7 @@ inline std::string operator+(const std::string &lhs, const StringRef &rhs) { } /// A string that may live in flash (on ESP8266): pointer and length, with no byte-reading operations. -/// progmem_ptr() is safe as a "%s" log argument; read the contents with write_to() or equals(). +/// progmem_ptr() is safe as a "%s" log argument; compare the contents with equals(). class ProgmemStringRef { public: constexpr ProgmemStringRef() = default; @@ -237,20 +237,6 @@ class ProgmemStringRef { constexpr size_t size() const { return this->ref_.size(); } constexpr bool empty() const { return this->ref_.empty(); } - /// Copy into buf (null terminated, truncated to fit), returns the length copied. - size_t write_to(char *buf, size_t buf_size) const { - if (buf_size == 0) - return 0; - size_t len = std::min(this->ref_.size(), buf_size - 1); -#ifdef USE_ESP8266 - memcpy_P(buf, this->ref_.c_str(), len); -#else - std::memcpy(buf, this->ref_.c_str(), len); -#endif - buf[len] = '\0'; - return len; - } - bool equals(const StringRef &other) const { #ifdef USE_ESP8266 // A StringRef may be {nullptr, 0}, and memcmp_P with a null pointer is undefined even for 0 bytes @@ -261,11 +247,6 @@ class ProgmemStringRef { #endif } -#ifndef USE_ESP8266 - /// The string is in RAM here, so it can be viewed directly. - constexpr const StringRef &ram_ref() const { return this->ref_; } -#endif - // Remove before 2027.5.0 [[deprecated( "May point to flash; use progmem_ptr() or the owner's accessors. Removed in 2027.5.0")]] constexpr const char * diff --git a/script/api_protobuf/api_protobuf.py b/script/api_protobuf/api_protobuf.py index 4760890aab..2f601f5c94 100755 --- a/script/api_protobuf/api_protobuf.py +++ b/script/api_protobuf/api_protobuf.py @@ -1158,6 +1158,11 @@ class PointerToBufferTypeBase(TypeInfo): """Get the wire type for this field.""" return WireType.LENGTH_DELIMITED # Uses wire type 2 + @property + def progmem(self) -> bool: + """Whether the data is in flash, so encode and dump copy it with progmem_memcpy.""" + return get_field_opt(self._field, pb.progmem, False) + def get_estimated_size(self) -> int: # field ID + length varint + typical data (assume small for pointer fields) return self.calculate_field_id_size() + 2 + 16 @@ -1171,11 +1176,6 @@ class PointerToBytesBufferType(PointerToBufferTypeBase): reference_type = "const uint8_t*" const_reference_type = "const uint8_t*" - @property - def progmem(self) -> bool: - """Whether the data is in flash, so encode and dump copy it with progmem_memcpy.""" - return get_field_opt(self._field, pb.progmem, False) - @property def public_content(self) -> list[str]: # Use uint16_t for length - max packet size is well below 65535 @@ -1253,11 +1253,6 @@ class PointerToStringBufferType(PointerToBufferTypeBase): one zero fill. Any encode path that copies unconditionally must check this.""" return not self._needs_decode and not self.force - @property - def progmem(self) -> bool: - """Whether the string is in flash, so encode and dump copy it with progmem_memcpy.""" - return get_field_opt(self._field, pb.progmem, False) - @property def public_content(self) -> list[str]: if self.progmem: diff --git a/tests/component_tests/api/test_action_metadata.py b/tests/component_tests/api/test_action_metadata.py index 46896d26f6..2b7662b665 100644 --- a/tests/component_tests/api/test_action_metadata.py +++ b/tests/component_tests/api/test_action_metadata.py @@ -15,7 +15,6 @@ from esphome.config_validation import Invalid from esphome.core import CORE from esphome.cpp_generator import safe_exp from esphome.helpers import fnv1_hash -from tests.component_tests.helpers import get_define_value CONFIG = "tests/component_tests/api/test_action_metadata.yaml" CONFIG_ESP8266 = "tests/component_tests/api/test_action_metadata_esp8266.yaml" @@ -67,11 +66,10 @@ def test_esp8266_strings_are_shared_progmem_arrays( def test_esp8266_encodes_action_strings_from_flash( generate_main: Callable[[str | Path], str], ) -> None: - """ESP8266 uses the same flash string table, with no scratch buffer to size.""" + """ESP8266 uses the same flash string table.""" main_cpp = generate_main(CONFIG_ESP8266) assert "api_action0_strings[] PROGMEM" in main_cpp - assert get_define_value("API_USER_ACTION_STRINGS_SCRATCH_SIZE") is None def test_shorthand_variables_emit_no_metadata( diff --git a/tests/components/core/test_progmem_string_ref.cpp b/tests/components/core/test_progmem_string_ref.cpp index fe6dd0e24a..ec6e77b1e4 100644 --- a/tests/components/core/test_progmem_string_ref.cpp +++ b/tests/components/core/test_progmem_string_ref.cpp @@ -2,35 +2,8 @@ #include "esphome/core/string_ref.h" -#include -#include - namespace esphome::core::testing { -// ram_ref() must return a reference so callers can hand it out as `const StringRef &` -static_assert(std::is_same_v().ram_ref()), const StringRef &>); - -TEST(ProgmemStringRef, WriteToCopiesAndTerminates) { - ProgmemStringRef ref("Kitchen", 7); - char buf[16]; - EXPECT_EQ(ref.write_to(buf, sizeof(buf)), 7u); - EXPECT_STREQ(buf, "Kitchen"); -} - -TEST(ProgmemStringRef, WriteToTruncatesToFit) { - ProgmemStringRef ref("Kitchen", 7); - char buf[4]; - EXPECT_EQ(ref.write_to(buf, sizeof(buf)), 3u); - EXPECT_STREQ(buf, "Kit"); -} - -TEST(ProgmemStringRef, WriteToZeroSizeWritesNothing) { - ProgmemStringRef ref("Kitchen", 7); - char buf[1] = {'x'}; - EXPECT_EQ(ref.write_to(buf, 0), 0u); - EXPECT_EQ(buf[0], 'x'); -} - TEST(ProgmemStringRef, EqualsComparesLengthAndContent) { ProgmemStringRef ref("Kitchen", 7); EXPECT_TRUE(ref.equals(StringRef("Kitchen")));