diff --git a/esphome/components/esp32_ble_server/__init__.py b/esphome/components/esp32_ble_server/__init__.py index 8631d53a23..d18b079997 100644 --- a/esphome/components/esp32_ble_server/__init__.py +++ b/esphome/components/esp32_ble_server/__init__.py @@ -53,6 +53,8 @@ BLECharacteristicSetValueAction = esp32_ble_server_automations_ns.class_( BLECharacteristicNotifyAction = esp32_ble_server_automations_ns.class_( "BLECharacteristicNotifyAction", automation.Action ) +ByteBuffer_ns = cg.esphome_ns.namespace("ByteBuffer") +ByteBuffer = cg.esphome_ns.class_("ByteBuffer") _ble_server_config = None @@ -167,47 +169,22 @@ def parse_uuid(uuid): def parse_descriptor_value(value): # Compute the maximum length of the descriptor value # Also parse the value for byte arrays + for val_method in [cv.boolean, cv.float_, cv.hex_uint8_t, + cv.hex_uint16_t, cv.hex_uint32_t, cv.int_, cv.string]: + try: + val = val_method(value) + buffer = ByteBuffer_ns.wrap(val) + return buffer, buffer.get_capacity() + except cv.Invalid: + pass + # Assume it's a list of bytes try: - cv.boolean(value) - return value, 1 + val = cv.All(cv.ensure_list(cv.hex_uint8_t), cv.Length(min=1))(value) + buffer = ByteBuffer_ns.wrap(cg.std_vector.template(cg.uint8)(val)) + return buffer, buffer.get_capacity() except cv.Invalid: pass - try: - cv.float_(value) - return value, 8 - except cv.Invalid: - pass - try: - cv.hex_uint8_t(value) - return value, 1 - except cv.Invalid: - pass - try: - cv.hex_uint16_t(value) - return value, 2 - except cv.Invalid: - pass - try: - cv.hex_uint32_t(value) - return value, 4 - except cv.Invalid: - pass - try: - cv.int_(value) - return value, 4 - except cv.Invalid: - pass - try: - cv.string(value) - # Count the bytes in the string - value_len = len(value.encode("utf-8")) - return value, value_len - except cv.Invalid: - pass - return ( - cg.std_vector.template(cg.uint8)(value), - len(value), - ) # Assume it's a list of bytes + raise cv.Invalid(f"Could not find type for value: {value}") def calculate_num_handles(service_config): @@ -302,30 +279,20 @@ async def parse_characteristic_value(value, args): return await cg.templatable( value, args, - cg.std_vector.template(cg.uint8), - cg.std_vector.template(cg.uint8), - ) - if isinstance(value, list): - return cg.std_vector.template(cg.uint8)(value) - # Transform the value into a vector of bytes + ByteBuffer, + ByteBuffer_ns.wrap, + ) + for val_method in [cv.boolean, cv.float_, cv.hex_uint8_t, + cv.hex_uint16_t, cv.hex_uint32_t, cv.int_, cv.string]: + try: + val = val_method(value) + return ByteBuffer_ns.wrap(val) + except cv.Invalid: + pass + # Assume it's a list of bytes try: - bool_value = cv.boolean(value) - return cg.RawExpression(f"to_vector({'true' if bool_value else 'false'})") - except cv.Invalid: - pass - try: - int_ = cv.uint64_t(value) - return cg.RawExpression(f"to_vector({int_})") - except cv.Invalid: - pass - try: - float_ = cv.float_(value) - return cg.RawExpression(f"to_vector({float_})") - except cv.Invalid: - pass - try: - string_ = cv.string(value) - return cg.RawExpression(f'to_vector("{string_}")') + val = cv.All(cv.ensure_list(cv.hex_uint8_t), cv.Length(min=1))(value) + return ByteBuffer_ns.wrap(cg.std_vector.template(cg.uint8)(val)) except cv.Invalid: pass raise cv.Invalid(f"Could not find type for value: {value}") @@ -345,7 +312,7 @@ async def ble_server_characteristic_set_value(config, action_id, template_arg, a paren = await cg.get_variable(config[CONF_ID]) var = cg.new_Pvariable(action_id, template_arg, paren) value = await parse_characteristic_value(config[CONF_VALUE], args) - cg.add(var.set_value(value)) + cg.add(var.set_buffer(value)) return var diff --git a/esphome/components/esp32_ble_server/ble_2901.cpp b/esphome/components/esp32_ble_server/ble_2901.cpp index ee0808d2c4..7c27a62c31 100644 --- a/esphome/components/esp32_ble_server/ble_2901.cpp +++ b/esphome/components/esp32_ble_server/ble_2901.cpp @@ -1,5 +1,6 @@ #include "ble_2901.h" #include "esphome/components/esp32_ble/ble_uuid.h" +#include "esphome/core/bytebuffer.h" #ifdef USE_ESP32 @@ -8,7 +9,7 @@ namespace esp32_ble_server { BLE2901::BLE2901(const std::string &value) : BLE2901((uint8_t *) value.data(), value.length()) {} BLE2901::BLE2901(const uint8_t *data, size_t length) : BLEDescriptor(esp32_ble::ESPBTUUID::from_uint16(0x2901)) { - this->set_value(data, length); + this->set_value(ByteBuffer::wrap(data, length)); this->permissions_ = ESP_GATT_PERM_READ; } diff --git a/esphome/components/esp32_ble_server/ble_characteristic.cpp b/esphome/components/esp32_ble_server/ble_characteristic.cpp index 867aad4126..3d0f615618 100644 --- a/esphome/components/esp32_ble_server/ble_characteristic.cpp +++ b/esphome/components/esp32_ble_server/ble_characteristic.cpp @@ -32,14 +32,13 @@ BLECharacteristic::BLECharacteristic(const ESPBTUUID uuid, uint32_t properties) this->set_write_no_response_property((properties & PROPERTY_WRITE_NR) != 0); } -void BLECharacteristic::set_value(std::vector value) { +void BLECharacteristic::set_value(ByteBuffer buffer) { + size_t length = buffer.get_capacity(); + uint8_t *data = buffer.array(); xSemaphoreTake(this->set_value_lock_, 0L); - this->value_ = std::move(value); + this->value_ = std::vector(data, data + length); xSemaphoreGive(this->set_value_lock_); } -void BLECharacteristic::set_value(const uint8_t *data, size_t length) { - this->set_value(std::vector(data, data + length)); -} void BLECharacteristic::notify(bool require_ack) { if (require_ack) { @@ -227,7 +226,7 @@ void BLECharacteristic::gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt this->value_.insert(this->value_.end(), param->write.value, param->write.value + param->write.len); this->write_event_ = true; } else { - this->set_value(param->write.value, param->write.len); + this->set_value(ByteBuffer::wrap(param->write.value, param->write.len)); } if (param->write.need_rsp) { diff --git a/esphome/components/esp32_ble_server/ble_characteristic.h b/esphome/components/esp32_ble_server/ble_characteristic.h index 220d89d0a7..4eb8673f74 100644 --- a/esphome/components/esp32_ble_server/ble_characteristic.h +++ b/esphome/components/esp32_ble_server/ble_characteristic.h @@ -3,7 +3,7 @@ #include "ble_descriptor.h" #include "esphome/components/esp32_ble/ble_uuid.h" #include "esphome/core/event_emitter.h" -#include "esphome/core/helpers.h" +#include "esphome/core/bytebuffer.h" #include @@ -40,16 +40,7 @@ class BLECharacteristic : public EventEmitter value); - void set_value(const std::string &value) { this->set_value(to_vector(value)); } - void set_value(uint8_t data) { this->set_value(to_vector(data)); } - void set_value(uint16_t data) { this->set_value(to_vector(data)); } - void set_value(uint32_t data) { this->set_value(to_vector(data)); } - void set_value(int data) { this->set_value(to_vector(data)); } - void set_value(float data) { this->set_value(to_vector(data)); } - void set_value(double data) { this->set_value(to_vector(data)); } - void set_value(bool data) { this->set_value(to_vector(data)); } + void set_value(ByteBuffer buffer); void set_broadcast_property(bool value); void set_indicate_property(bool value); diff --git a/esphome/components/esp32_ble_server/ble_descriptor.cpp b/esphome/components/esp32_ble_server/ble_descriptor.cpp index a82464130c..d760718ae1 100644 --- a/esphome/components/esp32_ble_server/ble_descriptor.cpp +++ b/esphome/components/esp32_ble_server/ble_descriptor.cpp @@ -38,9 +38,10 @@ void BLEDescriptor::do_create(BLECharacteristic *characteristic) { this->state_ = CREATING; } -void BLEDescriptor::set_value(std::vector value) { this->set_value(value.data(), value.size()); } +void BLEDescriptor::set_value(ByteBuffer buffer) { + size_t length = buffer.get_capacity(); + uint8_t *data = buffer.array(); -void BLEDescriptor::set_value(const uint8_t *data, size_t length) { if (length > this->value_.attr_max_len) { ESP_LOGE(TAG, "Size %d too large, must be no bigger than %d", length, this->value_.attr_max_len); return; diff --git a/esphome/components/esp32_ble_server/ble_descriptor.h b/esphome/components/esp32_ble_server/ble_descriptor.h index f294eeaa3c..33458f51f2 100644 --- a/esphome/components/esp32_ble_server/ble_descriptor.h +++ b/esphome/components/esp32_ble_server/ble_descriptor.h @@ -1,7 +1,7 @@ #pragma once #include "esphome/components/esp32_ble/ble_uuid.h" -#include "esphome/core/helpers.h" +#include "esphome/core/bytebuffer.h" #ifdef USE_ESP32 @@ -21,16 +21,7 @@ class BLEDescriptor { virtual ~BLEDescriptor(); void do_create(BLECharacteristic *characteristic); - void set_value(const uint8_t *data, size_t length); - void set_value(std::vector value); - void set_value(const std::string &value) { this->set_value(to_vector(value)); } - void set_value(uint8_t data) { this->set_value(to_vector(data)); } - void set_value(uint16_t data) { this->set_value(to_vector(data)); } - void set_value(uint32_t data) { this->set_value(to_vector(data)); } - void set_value(int data) { this->set_value(to_vector(data)); } - void set_value(float data) { this->set_value(to_vector(data)); } - void set_value(double data) { this->set_value(to_vector(data)); } - void set_value(bool data) { this->set_value(to_vector(data)); } + void set_value(ByteBuffer buffer); void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param); diff --git a/esphome/components/esp32_ble_server/ble_server.cpp b/esphome/components/esp32_ble_server/ble_server.cpp index 5c227abc25..198c13596e 100644 --- a/esphome/components/esp32_ble_server/ble_server.cpp +++ b/esphome/components/esp32_ble_server/ble_server.cpp @@ -4,6 +4,7 @@ #include "esphome/core/log.h" #include "esphome/core/application.h" #include "esphome/core/version.h" +#include "esphome/core/bytebuffer.h" #ifdef USE_ESP32 @@ -111,20 +112,20 @@ bool BLEServer::create_device_characteristics_() { if (this->model_.has_value()) { BLECharacteristic *model = this->device_information_service_->create_characteristic(MODEL_UUID, BLECharacteristic::PROPERTY_READ); - model->set_value(this->model_.value()); + model->set_value(ByteBuffer::wrap(this->model_.value())); } else { BLECharacteristic *model = this->device_information_service_->create_characteristic(MODEL_UUID, BLECharacteristic::PROPERTY_READ); - model->set_value(ESPHOME_BOARD); + model->set_value(ByteBuffer::wrap(ESPHOME_BOARD)); } BLECharacteristic *version = this->device_information_service_->create_characteristic(VERSION_UUID, BLECharacteristic::PROPERTY_READ); - version->set_value("ESPHome " ESPHOME_VERSION); + version->set_value(ByteBuffer::wrap("ESPHome " ESPHOME_VERSION)); BLECharacteristic *manufacturer = this->device_information_service_->create_characteristic(MANUFACTURER_UUID, BLECharacteristic::PROPERTY_READ); - manufacturer->set_value(this->manufacturer_); + manufacturer->set_value(ByteBuffer::wrap(this->manufacturer_)); return true; } diff --git a/esphome/components/esp32_ble_server/ble_server_automations.h b/esphome/components/esp32_ble_server/ble_server_automations.h index df289af9f2..7ce621dc5d 100644 --- a/esphome/components/esp32_ble_server/ble_server_automations.h +++ b/esphome/components/esp32_ble_server/ble_server_automations.h @@ -4,6 +4,7 @@ #include "esphome/core/event_emitter.h" #include "esphome/core/automation.h" +#include "esphome/core/bytebuffer.h" #include #include @@ -27,7 +28,7 @@ enum BLECharacteristicSetValueActionEvt { PRE_NOTIFY, }; -// Class to make sure only one BLECharacteristicSetValueAction is active at a time +// Class to make sure only one BLECharacteristicSetValueAction is active at a time for each characteristic class BLECharacteristicSetValueActionManager : public EventEmitter { public: @@ -52,22 +53,22 @@ class BLECharacteristicSetValueActionManager template class BLECharacteristicSetValueAction : public Action { public: BLECharacteristicSetValueAction(BLECharacteristic *characteristic) : parent_(characteristic) {} - TEMPLATABLE_VALUE(std::vector, value) + TEMPLATABLE_VALUE(ByteBuffer, buffer) void play(Ts... x) override { // If the listener is already set, do nothing if (BLECharacteristicSetValueActionManager::get_instance()->get_listener(this->parent_) == this->listener_id_) return; // Set initial value - this->parent_->set_value(this->value_.value(x...)); + this->parent_->set_value(this->buffer_.value(x...)); // Set the listener for read events this->listener_id_ = this->parent_->EventEmitter::on( BLECharacteristicEvt::EmptyEvt::ON_READ, [this, x...]() { // Set the value of the characteristic every time it is read - this->parent_->set_value(this->value_.value(x...)); + this->parent_->set_value(this->buffer_.value(x...)); }); // Set the listener in the global manager so only one BLECharacteristicSetValueAction is set for each characteristic BLECharacteristicSetValueActionManager::get_instance()->set_listener( - this->parent_, this->listener_id_, [this, x...]() { this->parent_->set_value(this->value_.value(x...)); }); + this->parent_, this->listener_id_, [this, x...]() { this->parent_->set_value(this->buffer_.value(x...)); }); } protected: diff --git a/esphome/components/esp32_improv/esp32_improv_component.cpp b/esphome/components/esp32_improv/esp32_improv_component.cpp index d0239916d8..8e3e965422 100644 --- a/esphome/components/esp32_improv/esp32_improv_component.cpp +++ b/esphome/components/esp32_improv/esp32_improv_component.cpp @@ -4,6 +4,7 @@ #include "esphome/components/esp32_ble_server/ble_2902.h" #include "esphome/core/application.h" #include "esphome/core/log.h" +#include "esphome/core/bytebuffer.h" #ifdef USE_ESP32 @@ -63,7 +64,7 @@ void ESP32ImprovComponent::setup_characteristics() { if (this->status_indicator_ != nullptr) capabilities |= improv::CAPABILITY_IDENTIFY; #endif - this->capabilities_->set_value(capabilities); + this->capabilities_->set_value(ByteBuffer::wrap(capabilities)); this->setup_complete_ = true; } @@ -196,7 +197,7 @@ void ESP32ImprovComponent::set_state_(improv::State state) { this->state_ = state; if (this->status_->get_value().empty() || this->status_->get_value()[0] != state) { uint8_t data[1]{state}; - this->status_->set_value(data, 1); + this->status_->set_value(ByteBuffer::wrap(data)); if (state != improv::STATE_STOPPED) this->status_->notify(); } @@ -226,14 +227,14 @@ void ESP32ImprovComponent::set_error_(improv::Error error) { } if (this->error_->get_value().empty() || this->error_->get_value()[0] != error) { uint8_t data[1]{error}; - this->error_->set_value(data, 1); + this->error_->set_value(ByteBuffer::wrap(data)); if (this->state_ != improv::STATE_STOPPED) this->error_->notify(); } } void ESP32ImprovComponent::send_response_(std::vector &response) { - this->rpc_response_->set_value(response); + this->rpc_response_->set_value(ByteBuffer::wrap(response)); if (this->state_ != improv::STATE_STOPPED) this->rpc_response_->notify(); } diff --git a/esphome/core/bytebuffer.cpp b/esphome/core/bytebuffer.cpp index fb2ade3166..9b454cc2ad 100644 --- a/esphome/core/bytebuffer.cpp +++ b/esphome/core/bytebuffer.cpp @@ -1,5 +1,6 @@ #include "bytebuffer.h" #include +#include namespace esphome { @@ -8,13 +9,59 @@ ByteBuffer ByteBuffer::create(size_t capacity) { return {data}; } -ByteBuffer ByteBuffer::wrap(uint8_t *ptr, size_t len) { +ByteBuffer ByteBuffer::wrap(const uint8_t *ptr, size_t len) { std::vector data(ptr, ptr + len); return {data}; } ByteBuffer ByteBuffer::wrap(std::vector data) { return {std::move(data)}; } +ByteBuffer ByteBuffer::wrap(uint8_t value) { + ByteBuffer buffer = ByteBuffer::create(1); + buffer.put_uint8(value); + return buffer; +} + +ByteBuffer ByteBuffer::wrap(uint16_t value) { + ByteBuffer buffer = ByteBuffer::create(2); + buffer.put_uint16(value); + return buffer; +} + +ByteBuffer ByteBuffer::wrap(uint32_t value) { + ByteBuffer buffer = ByteBuffer::create(4); + buffer.put_uint32(value); + return buffer; +} + +ByteBuffer ByteBuffer::wrap(uint64_t value) { + ByteBuffer buffer = ByteBuffer::create(8); + buffer.put_uint64(value); + return buffer; +} + +ByteBuffer ByteBuffer::wrap(float value) { + ByteBuffer buffer = ByteBuffer::create(4); + buffer.put_float(value); + return buffer; +} + +ByteBuffer ByteBuffer::wrap(double value) { + ByteBuffer buffer = ByteBuffer::create(8); + buffer.put_double(value); + return buffer; +} + +ByteBuffer ByteBuffer::wrap(const std::string &data) { + std::vector buffer(data.begin(), data.end()); + return {buffer}; +} + +ByteBuffer ByteBuffer::wrap(std::initializer_list values) { + std::vector buffer(values); + return {buffer}; +} + void ByteBuffer::set_limit(size_t limit) { assert(limit <= this->get_capacity()); this->limit_ = limit; @@ -27,6 +74,16 @@ void ByteBuffer::clear() { this->limit_ = this->get_capacity(); this->position_ = 0; } +void ByteBuffer::flip() { + this->limit_ = this->position_; + this->position_ = 0; +} + +/// Getters +uint8_t ByteBuffer::get_uint8() { + assert(this->get_remaining() >= 1); + return this->data_[this->position_++]; +} uint16_t ByteBuffer::get_uint16() { assert(this->get_remaining() >= 2); uint16_t value; @@ -39,23 +96,6 @@ uint16_t ByteBuffer::get_uint16() { } return value; } - -uint32_t ByteBuffer::get_uint32() { - assert(this->get_remaining() >= 4); - uint32_t value; - if (endianness_ == LITTLE) { - value = this->data_[this->position_++]; - value |= this->data_[this->position_++] << 8; - value |= this->data_[this->position_++] << 16; - value |= this->data_[this->position_++] << 24; - } else { - value = this->data_[this->position_++] << 24; - value |= this->data_[this->position_++] << 16; - value |= this->data_[this->position_++] << 8; - value |= this->data_[this->position_++]; - } - return value; -} uint32_t ByteBuffer::get_uint24() { assert(this->get_remaining() >= 3); uint32_t value; @@ -77,14 +117,89 @@ uint32_t ByteBuffer::get_int24() { value |= mask; return value; } -uint8_t ByteBuffer::get_uint8() { - assert(this->get_remaining() >= 1); - return this->data_[this->position_++]; +uint32_t ByteBuffer::get_uint32() { + assert(this->get_remaining() >= 4); + uint32_t value; + if (endianness_ == LITTLE) { + value = this->data_[this->position_++]; + value |= this->data_[this->position_++] << 8; + value |= this->data_[this->position_++] << 16; + value |= this->data_[this->position_++] << 24; + } else { + value = this->data_[this->position_++] << 24; + value |= this->data_[this->position_++] << 16; + value |= this->data_[this->position_++] << 8; + value |= this->data_[this->position_++]; + } + return value; +} +uint64_t ByteBuffer::get_uint64() { + assert(this->get_remaining() >= 8); + uint64_t value; + if (endianness_ == LITTLE) { + value = this->data_[this->position_++]; + value |= (uint64_t) this->data_[this->position_++] << 8; + value |= (uint64_t) this->data_[this->position_++] << 16; + value |= (uint64_t) this->data_[this->position_++] << 24; + value |= (uint64_t) this->data_[this->position_++] << 32; + value |= (uint64_t) this->data_[this->position_++] << 40; + value |= (uint64_t) this->data_[this->position_++] << 48; + value |= (uint64_t) this->data_[this->position_++] << 56; + } else { + value = (uint64_t) this->data_[this->position_++] << 56; + value |= (uint64_t) this->data_[this->position_++] << 48; + value |= (uint64_t) this->data_[this->position_++] << 40; + value |= (uint64_t) this->data_[this->position_++] << 32; + value |= (uint64_t) this->data_[this->position_++] << 24; + value |= (uint64_t) this->data_[this->position_++] << 16; + value |= (uint64_t) this->data_[this->position_++] << 8; + value |= this->data_[this->position_++]; + } + return value; } float ByteBuffer::get_float() { - auto value = this->get_uint32(); - return *(float *) &value; + assert(this->get_remaining() >= sizeof(float)); + unsigned char byteArray[sizeof(float)]; + if (this->endianness_ == LITTLE) { + for (size_t i = 0; i < sizeof(float); i++) { + byteArray[i] = this->data_[this->position_++]; + } + } else { + for (size_t i = sizeof(float); i > 0; i--) { + byteArray[i - 1] = this->data_[this->position_++]; + } + } + float value; + std::memcpy(&value, byteArray, sizeof(float)); + return value; } +double ByteBuffer::get_double() { + assert(this->get_remaining() >= sizeof(double)); + unsigned char byteArray[sizeof(double)]; + if (this->endianness_ == LITTLE) { + for (size_t i = 0; i < sizeof(double); i++) { + byteArray[i] = this->data_[this->position_++]; + } + } else { + for (size_t i = sizeof(double); i > 0; i--) { + byteArray[i - 1] = this->data_[this->position_++]; + } + } + double value; + std::memcpy(&value, byteArray, sizeof(double)); + return value; +} +std::string ByteBuffer::get_string(size_t length) { + assert(this->get_remaining() >= length); + std::string value; + value.reserve(length); + for (size_t i = 0; i < length; i++) { + value.push_back(this->data_[this->position_++]); + } + return value; +} + +/// Putters void ByteBuffer::put_uint8(uint8_t value) { assert(this->get_remaining() >= 1); this->data_[this->position_++] = value; @@ -126,9 +241,60 @@ void ByteBuffer::put_uint32(uint32_t value) { this->data_[this->position_++] = (uint8_t) value; } } -void ByteBuffer::put_float(float value) { this->put_uint32(*(uint32_t *) &value); } -void ByteBuffer::flip() { - this->limit_ = this->position_; - this->position_ = 0; +void ByteBuffer::put_uint64(uint64_t value) { + assert(this->get_remaining() >= 8); + if (this->endianness_ == LITTLE) { + this->data_[this->position_++] = (uint8_t) value; + this->data_[this->position_++] = (uint8_t) (value >> 8); + this->data_[this->position_++] = (uint8_t) (value >> 16); + this->data_[this->position_++] = (uint8_t) (value >> 24); + this->data_[this->position_++] = (uint8_t) (value >> 32); + this->data_[this->position_++] = (uint8_t) (value >> 40); + this->data_[this->position_++] = (uint8_t) (value >> 48); + this->data_[this->position_++] = (uint8_t) (value >> 56); + } else { + this->data_[this->position_++] = (uint8_t) (value >> 56); + this->data_[this->position_++] = (uint8_t) (value >> 48); + this->data_[this->position_++] = (uint8_t) (value >> 40); + this->data_[this->position_++] = (uint8_t) (value >> 32); + this->data_[this->position_++] = (uint8_t) (value >> 24); + this->data_[this->position_++] = (uint8_t) (value >> 16); + this->data_[this->position_++] = (uint8_t) (value >> 8); + this->data_[this->position_++] = (uint8_t) value; + } +} +void ByteBuffer::put_float(float value) { + assert(this->get_remaining() >= sizeof(float)); + unsigned char byteArray[sizeof(float)]; + std::memcpy(byteArray, &value, sizeof(float)); + if (this->endianness_ == LITTLE) { + for (size_t i = 0; i < sizeof(float); i++) { + this->data_[this->position_++] = byteArray[i]; + } + } else { + for (size_t i = sizeof(float); i > 0; i--) { + this->data_[this->position_++] = byteArray[i - 1]; + } + } +} +void ByteBuffer::put_double(double value) { + assert(this->get_remaining() >= sizeof(double)); + unsigned char byteArray[sizeof(double)]; + std::memcpy(byteArray, &value, sizeof(double)); + if (this->endianness_ == LITTLE) { + for (size_t i = 0; i < sizeof(double); i++) { + this->data_[this->position_++] = byteArray[i]; + } + } else { + for (size_t i = sizeof(double); i > 0; i--) { + this->data_[this->position_++] = byteArray[i - 1]; + } + } +} +void ByteBuffer::put_string(const std::string &value) { + assert(this->get_remaining() >= value.size()); + for (char c : value) { + this->data_[this->position_++] = c; + } } } // namespace esphome diff --git a/esphome/core/bytebuffer.h b/esphome/core/bytebuffer.h index f242e5e333..549b2431be 100644 --- a/esphome/core/bytebuffer.h +++ b/esphome/core/bytebuffer.h @@ -4,6 +4,7 @@ #include #include #include +#include namespace esphome { @@ -29,18 +30,34 @@ enum Endian { LITTLE, BIG }; */ class ByteBuffer { public: + // Default constructor (compatibility with TEMPLATABLE_VALUE) + ByteBuffer() = default; /** * Create a new Bytebuffer with the given capacity */ static ByteBuffer create(size_t capacity); /** - * Wrap an existing vector in a Bytebufffer + * Wrap an existing vector in a ByteBufffer */ static ByteBuffer wrap(std::vector data); /** - * Wrap an existing array in a Bytebufffer + * Wrap an existing array in a ByteBufffer */ - static ByteBuffer wrap(uint8_t *ptr, size_t len); + static ByteBuffer wrap(const uint8_t *ptr, size_t len); + // Convenience functions to create a ByteBuffer from a value + static ByteBuffer wrap(const uint8_t value); + static ByteBuffer wrap(const uint16_t value); + static ByteBuffer wrap(const uint32_t value); + static ByteBuffer wrap(const uint64_t value); + static ByteBuffer wrap(const int8_t value) { return wrap((uint8_t) value); } + static ByteBuffer wrap(const int16_t value) { return wrap((uint16_t) value); } + static ByteBuffer wrap(const int32_t value) { return wrap((uint32_t) value); } + static ByteBuffer wrap(const int64_t value) { return wrap((uint64_t) value); } + static ByteBuffer wrap(const float value); + static ByteBuffer wrap(const double value); + static ByteBuffer wrap(const bool value) { return wrap(value ? (uint8_t) 1 : (uint8_t) 0); } + static ByteBuffer wrap(const std::string &value); + static ByteBuffer wrap(const std::initializer_list values); // Get one byte from the buffer, increment position by 1 uint8_t get_uint8(); @@ -50,20 +67,39 @@ class ByteBuffer { uint32_t get_uint24(); // Get a 32 bit unsigned value, increment by 4 uint32_t get_uint32(); - // signed versions of the get functions + // Get a 64 bit unsigned value, increment by 8 + uint64_t get_uint64(); + // Signed versions of the get functions uint8_t get_int8() { return (int8_t) this->get_uint8(); }; int16_t get_int16() { return (int16_t) this->get_uint16(); } uint32_t get_int24(); int32_t get_int32() { return (int32_t) this->get_uint32(); } + int64_t get_int64() { return (int64_t) this->get_uint64(); } // Get a float value, increment by 4 float get_float(); + // Get a double value, increment by 8 + double get_double(); + // Get a bool value, increment by 1 + bool get_bool() { return this->get_uint8() != 0; } + // Get a string value, increment by the length of the string + std::string get_string(size_t length); - // put values into the buffer, increment the position accordingly + // Put values into the buffer, increment the position accordingly void put_uint8(uint8_t value); void put_uint16(uint16_t value); void put_uint24(uint32_t value); void put_uint32(uint32_t value); + void put_uint64(uint64_t value); + // Signed versions of the put functions + void put_int8(int8_t value) { this->put_uint8(value); } + void put_int24(int32_t value) { this->put_uint24(value); } + void put_int32(int32_t value) { this->put_uint32(value); } + void put_int64(int64_t value) { this->put_uint64(value); } + // Extra put functions void put_float(float value); + void put_double(double value); + void put_bool(bool value) { this->put_uint8(value ? 1 : 0); } + void put_string(const std::string &value); inline size_t get_capacity() const { return this->data_.size(); } inline size_t get_position() const { return this->position_; } diff --git a/esphome/core/helpers.cpp b/esphome/core/helpers.cpp index 2efddcdd9b..e75b06ccd3 100644 --- a/esphome/core/helpers.cpp +++ b/esphome/core/helpers.cpp @@ -534,30 +534,6 @@ std::vector base64_decode(const std::string &encoded_string) { return ret; } -std::vector to_vector(bool value) { return {value ? (uint8_t) 1 : (uint8_t) 0}; } -std::vector to_vector(uint8_t value) { return {value}; } -std::vector to_vector(uint16_t value) { return {uint8_t(value >> 8), uint8_t(value & 0xFF)}; } -std::vector to_vector(uint32_t value) { - return {uint8_t(value >> 24), uint8_t((value >> 16) & 0xFF), uint8_t((value >> 8) & 0xFF), uint8_t(value & 0xFF)}; -} -std::vector to_vector(uint64_t value) { - return {uint8_t(value >> 56), uint8_t((value >> 48) & 0xFF), uint8_t((value >> 40) & 0xFF), - uint8_t((value >> 32) & 0xFF), uint8_t((value >> 24) & 0xFF), uint8_t((value >> 16) & 0xFF), - uint8_t((value >> 8) & 0xFF), uint8_t(value & 0xFF)}; -} -std::vector to_vector(int value) { return to_vector(static_cast(value)); } -std::vector to_vector(float value) { - uint32_t val; - memcpy(&val, &value, sizeof(val)); - return to_vector(val); -} -std::vector to_vector(double value) { - uint64_t val; - memcpy(&val, &value, sizeof(val)); - return to_vector(val); -} -std::vector to_vector(const std::string &value) { return std::vector(value.begin(), value.end()); } - // Colors float gamma_correct(float value, float gamma) { diff --git a/esphome/core/helpers.h b/esphome/core/helpers.h index 69f306a67b..3e6fe9433e 100644 --- a/esphome/core/helpers.h +++ b/esphome/core/helpers.h @@ -441,17 +441,6 @@ std::string base64_encode(const std::vector &buf); std::vector base64_decode(const std::string &encoded_string); size_t base64_decode(std::string const &encoded_string, uint8_t *buf, size_t buf_len); -/// Create a byte vector from multiple types of values. -std::vector to_vector(bool value); -std::vector to_vector(uint8_t value); -std::vector to_vector(uint16_t value); -std::vector to_vector(uint32_t value); -std::vector to_vector(uint64_t value); -std::vector to_vector(int value); -std::vector to_vector(float value); -std::vector to_vector(double value); -std::vector to_vector(const std::string &value); - ///@} /// @name Colors diff --git a/tests/components/esp32_ble_server/common.yaml b/tests/components/esp32_ble_server/common.yaml index 3615546056..c8239dc094 100644 --- a/tests/components/esp32_ble_server/common.yaml +++ b/tests/components/esp32_ble_server/common.yaml @@ -31,6 +31,6 @@ esp32_ble_server: ESP_LOGD("BLE", "Received: %s", std::string(x.begin(), x.end()).c_str()); - ble_server.characteristic.set_value: id: test_change_characteristic - value: !lambda 'return {0x00, 0x01, 0x02};' + value: !lambda 'return ByteBuffer::wrap({0x00, 0x01, 0x02});' - ble_server.characteristic.notify: id: test_notify_characteristic