mirror of
https://github.com/esphome/esphome.git
synced 2025-11-18 07:45:56 +00:00
[canbus] Optimize canbus.send memory usage - store static data in flash
This commit is contained in:
@@ -4,7 +4,7 @@ from esphome import automation
|
|||||||
import esphome.codegen as cg
|
import esphome.codegen as cg
|
||||||
import esphome.config_validation as cv
|
import esphome.config_validation as cv
|
||||||
from esphome.const import CONF_DATA, CONF_ID, CONF_TRIGGER_ID
|
from esphome.const import CONF_DATA, CONF_ID, CONF_TRIGGER_ID
|
||||||
from esphome.core import CORE
|
from esphome.core import CORE, ID
|
||||||
|
|
||||||
CODEOWNERS = ["@mvturnho", "@danielschramm"]
|
CODEOWNERS = ["@mvturnho", "@danielschramm"]
|
||||||
IS_PLATFORM_COMPONENT = True
|
IS_PLATFORM_COMPONENT = True
|
||||||
@@ -176,5 +176,8 @@ async def canbus_action_to_code(config, action_id, template_arg, args):
|
|||||||
else:
|
else:
|
||||||
if isinstance(data, bytes):
|
if isinstance(data, bytes):
|
||||||
data = [int(x) for x in data]
|
data = [int(x) for x in data]
|
||||||
cg.add(var.set_data_static(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
|
return var
|
||||||
|
|||||||
@@ -112,12 +112,16 @@ class Canbus : public Component {
|
|||||||
|
|
||||||
template<typename... Ts> class CanbusSendAction : public Action<Ts...>, public Parented<Canbus> {
|
template<typename... Ts> class CanbusSendAction : public Action<Ts...>, public Parented<Canbus> {
|
||||||
public:
|
public:
|
||||||
void set_data_template(const std::function<std::vector<uint8_t>(Ts...)> func) {
|
void set_data_template(std::vector<uint8_t> (*func)(Ts...)) {
|
||||||
this->data_func_ = func;
|
// Stateless lambdas (generated by ESPHome) implicitly convert to function pointers
|
||||||
|
this->data_.func = func;
|
||||||
this->static_ = false;
|
this->static_ = false;
|
||||||
}
|
}
|
||||||
void set_data_static(const std::vector<uint8_t> &data) {
|
|
||||||
this->data_static_ = data;
|
// Store pointer to static data in flash (no RAM copy)
|
||||||
|
void set_data_static(const uint8_t *data, size_t len) {
|
||||||
|
this->data_.static_data.ptr = data;
|
||||||
|
this->data_.static_data.len = len;
|
||||||
this->static_ = true;
|
this->static_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,21 +137,27 @@ template<typename... Ts> class CanbusSendAction : public Action<Ts...>, public P
|
|||||||
auto can_id = this->can_id_.has_value() ? *this->can_id_ : this->parent_->can_id_;
|
auto can_id = this->can_id_.has_value() ? *this->can_id_ : this->parent_->can_id_;
|
||||||
auto use_extended_id =
|
auto use_extended_id =
|
||||||
this->use_extended_id_.has_value() ? *this->use_extended_id_ : this->parent_->use_extended_id_;
|
this->use_extended_id_.has_value() ? *this->use_extended_id_ : this->parent_->use_extended_id_;
|
||||||
|
std::vector<uint8_t> data;
|
||||||
if (this->static_) {
|
if (this->static_) {
|
||||||
this->parent_->send_data(can_id, use_extended_id, this->remote_transmission_request_, this->data_static_);
|
data.assign(this->data_.static_data.ptr, this->data_.static_data.ptr + this->data_.static_data.len);
|
||||||
} else {
|
} else {
|
||||||
auto val = this->data_func_(x...);
|
data = this->data_.func(x...);
|
||||||
this->parent_->send_data(can_id, use_extended_id, this->remote_transmission_request_, val);
|
|
||||||
}
|
}
|
||||||
|
this->parent_->send_data(can_id, use_extended_id, this->remote_transmission_request_, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
optional<uint32_t> can_id_{};
|
optional<uint32_t> can_id_{};
|
||||||
optional<bool> use_extended_id_{};
|
optional<bool> use_extended_id_{};
|
||||||
bool remote_transmission_request_{false};
|
bool remote_transmission_request_{false};
|
||||||
bool static_{false};
|
bool static_{true}; // Default to static mode (most common case)
|
||||||
std::function<std::vector<uint8_t>(Ts...)> data_func_{};
|
union Data {
|
||||||
std::vector<uint8_t> data_static_{};
|
std::vector<uint8_t> (*func)(Ts...); // 4 bytes on 32-bit
|
||||||
|
struct {
|
||||||
|
const uint8_t *ptr; // 4 bytes on 32-bit
|
||||||
|
size_t len; // 4 bytes on 32-bit
|
||||||
|
} static_data; // 8 bytes total on 32-bit
|
||||||
|
} data_; // Union size = 8 bytes (max of 4 and 8)
|
||||||
};
|
};
|
||||||
|
|
||||||
class CanbusTrigger : public Trigger<std::vector<uint8_t>, uint32_t, bool>, public Component {
|
class CanbusTrigger : public Trigger<std::vector<uint8_t>, uint32_t, bool>, public Component {
|
||||||
|
|||||||
@@ -37,6 +37,15 @@ canbus:
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
number:
|
||||||
|
- platform: template
|
||||||
|
name: "Test Number"
|
||||||
|
id: test_number
|
||||||
|
optimistic: true
|
||||||
|
min_value: 0
|
||||||
|
max_value: 255
|
||||||
|
step: 1
|
||||||
|
|
||||||
button:
|
button:
|
||||||
- platform: template
|
- platform: template
|
||||||
name: Canbus Actions
|
name: Canbus Actions
|
||||||
@@ -44,3 +53,7 @@ button:
|
|||||||
- canbus.send: "abc"
|
- canbus.send: "abc"
|
||||||
- canbus.send: [0, 1, 2]
|
- canbus.send: [0, 1, 2]
|
||||||
- canbus.send: !lambda return {0, 1, 2};
|
- canbus.send: !lambda return {0, 1, 2};
|
||||||
|
# Test canbus.send with lambda that references a component (function pointer)
|
||||||
|
- canbus.send: !lambda |-
|
||||||
|
uint8_t val = (uint8_t)id(test_number).state;
|
||||||
|
return std::vector<uint8_t>{0xAA, val, 0xBB};
|
||||||
|
|||||||
Reference in New Issue
Block a user