From d516627957778427af22ce57c2d5c1294e9948d5 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 9 Nov 2025 16:37:14 -0600 Subject: [PATCH] [uart] Store static data in flash and use function pointers for lambdas (#11784) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/uart/__init__.py | 7 ++++-- esphome/components/uart/automation.h | 35 +++++++++++++++------------- 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/esphome/components/uart/__init__.py b/esphome/components/uart/__init__.py index eb911ed0073..cbc11d0db04 100644 --- a/esphome/components/uart/__init__.py +++ b/esphome/components/uart/__init__.py @@ -31,7 +31,7 @@ from esphome.const import ( PLATFORM_HOST, PlatformFramework, ) -from esphome.core import CORE +from esphome.core import CORE, ID import esphome.final_validate as fv from esphome.yaml_util import make_data_base @@ -446,7 +446,10 @@ async def uart_write_to_code(config, action_id, template_arg, args): templ = await cg.templatable(data, args, cg.std_vector.template(cg.uint8)) cg.add(var.set_data_template(templ)) else: - cg.add(var.set_data_static(cg.ArrayInitializer(*data))) + # Generate static array in flash to avoid RAM copy + arr_id = ID(f"{action_id}_data", is_declaration=True, type=cg.uint8) + arr = cg.static_const_array(arr_id, cg.ArrayInitializer(*data)) + cg.add(var.set_data_static(arr, len(data))) return var diff --git a/esphome/components/uart/automation.h b/esphome/components/uart/automation.h index ad2c4d2bf1d..c2eb308eb8d 100644 --- a/esphome/components/uart/automation.h +++ b/esphome/components/uart/automation.h @@ -10,32 +10,35 @@ namespace uart { template class UARTWriteAction : public Action, public Parented { public: - void set_data_template(std::function(Ts...)> func) { - this->data_func_ = func; - this->static_ = false; + void set_data_template(std::vector (*func)(Ts...)) { + // Stateless lambdas (generated by ESPHome) implicitly convert to function pointers + this->code_.func = func; + this->len_ = -1; // Sentinel value indicates template mode } - void set_data_static(std::vector &&data) { - this->data_static_ = std::move(data); - this->static_ = true; - } - void set_data_static(std::initializer_list data) { - this->data_static_ = std::vector(data); - this->static_ = true; + + // Store pointer to static data in flash (no RAM copy) + void set_data_static(const uint8_t *data, size_t len) { + this->code_.data = data; + this->len_ = len; // Length >= 0 indicates static mode } void play(const Ts &...x) override { - if (this->static_) { - this->parent_->write_array(this->data_static_); + if (this->len_ >= 0) { + // Static mode: use pointer and length + this->parent_->write_array(this->code_.data, static_cast(this->len_)); } else { - auto val = this->data_func_(x...); + // Template mode: call function + auto val = this->code_.func(x...); this->parent_->write_array(val); } } protected: - bool static_{false}; - std::function(Ts...)> data_func_{}; - std::vector data_static_{}; + ssize_t len_{-1}; // -1 = template mode, >=0 = static mode with length + union Code { + std::vector (*func)(Ts...); // Function pointer (stateless lambdas) + const uint8_t *data; // Pointer to static data in flash + } code_; }; } // namespace uart