mirror of
https://github.com/esphome/esphome.git
synced 2025-11-15 14:25:45 +00:00
[ble_client] Optimize ble_write memory usage - store static data in flash
This commit is contained in:
@@ -15,6 +15,7 @@ from esphome.const import (
|
|||||||
CONF_TRIGGER_ID,
|
CONF_TRIGGER_ID,
|
||||||
CONF_VALUE,
|
CONF_VALUE,
|
||||||
)
|
)
|
||||||
|
from esphome.core import ID
|
||||||
|
|
||||||
AUTO_LOAD = ["esp32_ble_client"]
|
AUTO_LOAD = ["esp32_ble_client"]
|
||||||
CODEOWNERS = ["@buxtronix", "@clydebarrow"]
|
CODEOWNERS = ["@buxtronix", "@clydebarrow"]
|
||||||
@@ -198,7 +199,12 @@ async def ble_write_to_code(config, action_id, template_arg, args):
|
|||||||
templ = await cg.templatable(value, args, cg.std_vector.template(cg.uint8))
|
templ = await cg.templatable(value, args, cg.std_vector.template(cg.uint8))
|
||||||
cg.add(var.set_value_template(templ))
|
cg.add(var.set_value_template(templ))
|
||||||
else:
|
else:
|
||||||
cg.add(var.set_value_simple(value))
|
# Generate static array in flash to avoid RAM copy
|
||||||
|
if isinstance(value, bytes):
|
||||||
|
value = list(value)
|
||||||
|
arr_id = ID(f"{action_id}_data", is_declaration=True, type=cg.uint8)
|
||||||
|
arr = cg.static_const_array(arr_id, cg.ArrayInitializer(*value))
|
||||||
|
cg.add(var.set_value_simple(arr, len(value)))
|
||||||
|
|
||||||
if len(config[CONF_SERVICE_UUID]) == len(esp32_ble_tracker.bt_uuid16_format):
|
if len(config[CONF_SERVICE_UUID]) == len(esp32_ble_tracker.bt_uuid16_format):
|
||||||
cg.add(
|
cg.add(
|
||||||
|
|||||||
@@ -96,11 +96,8 @@ template<typename... Ts> class BLEClientWriteAction : public Action<Ts...>, publ
|
|||||||
BLEClientWriteAction(BLEClient *ble_client) {
|
BLEClientWriteAction(BLEClient *ble_client) {
|
||||||
ble_client->register_ble_node(this);
|
ble_client->register_ble_node(this);
|
||||||
ble_client_ = ble_client;
|
ble_client_ = ble_client;
|
||||||
this->construct_simple_value_();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~BLEClientWriteAction() { this->destroy_simple_value_(); }
|
|
||||||
|
|
||||||
void set_service_uuid16(uint16_t uuid) { this->service_uuid_ = espbt::ESPBTUUID::from_uint16(uuid); }
|
void set_service_uuid16(uint16_t uuid) { this->service_uuid_ = espbt::ESPBTUUID::from_uint16(uuid); }
|
||||||
void set_service_uuid32(uint32_t uuid) { this->service_uuid_ = espbt::ESPBTUUID::from_uint32(uuid); }
|
void set_service_uuid32(uint32_t uuid) { this->service_uuid_ = espbt::ESPBTUUID::from_uint32(uuid); }
|
||||||
void set_service_uuid128(uint8_t *uuid) { this->service_uuid_ = espbt::ESPBTUUID::from_raw(uuid); }
|
void set_service_uuid128(uint8_t *uuid) { this->service_uuid_ = espbt::ESPBTUUID::from_raw(uuid); }
|
||||||
@@ -110,16 +107,14 @@ template<typename... Ts> class BLEClientWriteAction : public Action<Ts...>, publ
|
|||||||
void set_char_uuid128(uint8_t *uuid) { this->char_uuid_ = espbt::ESPBTUUID::from_raw(uuid); }
|
void set_char_uuid128(uint8_t *uuid) { this->char_uuid_ = espbt::ESPBTUUID::from_raw(uuid); }
|
||||||
|
|
||||||
void set_value_template(std::vector<uint8_t> (*func)(Ts...)) {
|
void set_value_template(std::vector<uint8_t> (*func)(Ts...)) {
|
||||||
this->destroy_simple_value_();
|
|
||||||
this->value_.template_func = func;
|
this->value_.template_func = func;
|
||||||
this->has_simple_value_ = false;
|
this->has_simple_value_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_value_simple(const std::vector<uint8_t> &value) {
|
// Store pointer to static data in flash (no RAM copy)
|
||||||
if (!this->has_simple_value_) {
|
void set_value_simple(const uint8_t *data, size_t len) {
|
||||||
this->construct_simple_value_();
|
this->value_.simple_data.ptr = data;
|
||||||
}
|
this->value_.simple_data.len = len;
|
||||||
this->value_.simple = value;
|
|
||||||
this->has_simple_value_ = true;
|
this->has_simple_value_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,7 +123,12 @@ template<typename... Ts> class BLEClientWriteAction : public Action<Ts...>, publ
|
|||||||
void play_complex(const Ts &...x) override {
|
void play_complex(const Ts &...x) override {
|
||||||
this->num_running_++;
|
this->num_running_++;
|
||||||
this->var_ = std::make_tuple(x...);
|
this->var_ = std::make_tuple(x...);
|
||||||
auto value = this->has_simple_value_ ? this->value_.simple : this->value_.template_func(x...);
|
std::vector<uint8_t> value;
|
||||||
|
if (this->has_simple_value_) {
|
||||||
|
value.assign(this->value_.simple_data.ptr, this->value_.simple_data.ptr + this->value_.simple_data.len);
|
||||||
|
} else {
|
||||||
|
value = this->value_.template_func(x...);
|
||||||
|
}
|
||||||
// on write failure, continue the automation chain rather than stopping so that e.g. disconnect can work.
|
// on write failure, continue the automation chain rather than stopping so that e.g. disconnect can work.
|
||||||
if (!write(value))
|
if (!write(value))
|
||||||
this->play_next_(x...);
|
this->play_next_(x...);
|
||||||
@@ -201,21 +201,14 @@ template<typename... Ts> class BLEClientWriteAction : public Action<Ts...>, publ
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void construct_simple_value_() { new (&this->value_.simple) std::vector<uint8_t>(); }
|
|
||||||
|
|
||||||
void destroy_simple_value_() {
|
|
||||||
if (this->has_simple_value_) {
|
|
||||||
this->value_.simple.~vector();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BLEClient *ble_client_;
|
BLEClient *ble_client_;
|
||||||
bool has_simple_value_ = true;
|
bool has_simple_value_{true};
|
||||||
union Value {
|
union Value {
|
||||||
std::vector<uint8_t> simple;
|
|
||||||
std::vector<uint8_t> (*template_func)(Ts...);
|
std::vector<uint8_t> (*template_func)(Ts...);
|
||||||
Value() {} // trivial constructor
|
struct {
|
||||||
~Value() {} // trivial destructor - we manage lifetime via discriminator
|
const uint8_t *ptr;
|
||||||
|
size_t len;
|
||||||
|
} simple_data;
|
||||||
} value_;
|
} value_;
|
||||||
espbt::ESPBTUUID service_uuid_;
|
espbt::ESPBTUUID service_uuid_;
|
||||||
espbt::ESPBTUUID char_uuid_;
|
espbt::ESPBTUUID char_uuid_;
|
||||||
|
|||||||
Reference in New Issue
Block a user