Switch to ByteBuffer

This commit is contained in:
Rapsssito 2024-08-14 12:54:56 +02:00
parent 3277f3ba9e
commit 1f5f7561c2
14 changed files with 294 additions and 174 deletions

View file

@ -53,6 +53,8 @@ BLECharacteristicSetValueAction = esp32_ble_server_automations_ns.class_(
BLECharacteristicNotifyAction = esp32_ble_server_automations_ns.class_( BLECharacteristicNotifyAction = esp32_ble_server_automations_ns.class_(
"BLECharacteristicNotifyAction", automation.Action "BLECharacteristicNotifyAction", automation.Action
) )
ByteBuffer_ns = cg.esphome_ns.namespace("ByteBuffer")
ByteBuffer = cg.esphome_ns.class_("ByteBuffer")
_ble_server_config = None _ble_server_config = None
@ -167,47 +169,22 @@ def parse_uuid(uuid):
def parse_descriptor_value(value): def parse_descriptor_value(value):
# Compute the maximum length of the descriptor value # Compute the maximum length of the descriptor value
# Also parse the value for byte arrays # 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: try:
cv.boolean(value) val = val_method(value)
return value, 1 buffer = ByteBuffer_ns.wrap(val)
return buffer, buffer.get_capacity()
except cv.Invalid: except cv.Invalid:
pass pass
# Assume it's a list of bytes
try: try:
cv.float_(value) val = cv.All(cv.ensure_list(cv.hex_uint8_t), cv.Length(min=1))(value)
return value, 8 buffer = ByteBuffer_ns.wrap(cg.std_vector.template(cg.uint8)(val))
return buffer, buffer.get_capacity()
except cv.Invalid: except cv.Invalid:
pass pass
try: raise cv.Invalid(f"Could not find type for value: {value}")
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
def calculate_num_handles(service_config): def calculate_num_handles(service_config):
@ -302,30 +279,20 @@ async def parse_characteristic_value(value, args):
return await cg.templatable( return await cg.templatable(
value, value,
args, args,
cg.std_vector.template(cg.uint8), ByteBuffer,
cg.std_vector.template(cg.uint8), ByteBuffer_ns.wrap,
) )
if isinstance(value, list): for val_method in [cv.boolean, cv.float_, cv.hex_uint8_t,
return cg.std_vector.template(cg.uint8)(value) cv.hex_uint16_t, cv.hex_uint32_t, cv.int_, cv.string]:
# Transform the value into a vector of bytes
try: try:
bool_value = cv.boolean(value) val = val_method(value)
return cg.RawExpression(f"to_vector({'true' if bool_value else 'false'})") return ByteBuffer_ns.wrap(val)
except cv.Invalid: except cv.Invalid:
pass pass
# Assume it's a list of bytes
try: try:
int_ = cv.uint64_t(value) val = cv.All(cv.ensure_list(cv.hex_uint8_t), cv.Length(min=1))(value)
return cg.RawExpression(f"to_vector({int_})") return ByteBuffer_ns.wrap(cg.std_vector.template(cg.uint8)(val))
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_}")')
except cv.Invalid: except cv.Invalid:
pass pass
raise cv.Invalid(f"Could not find type for value: {value}") 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]) paren = await cg.get_variable(config[CONF_ID])
var = cg.new_Pvariable(action_id, template_arg, paren) var = cg.new_Pvariable(action_id, template_arg, paren)
value = await parse_characteristic_value(config[CONF_VALUE], args) value = await parse_characteristic_value(config[CONF_VALUE], args)
cg.add(var.set_value(value)) cg.add(var.set_buffer(value))
return var return var

View file

@ -1,5 +1,6 @@
#include "ble_2901.h" #include "ble_2901.h"
#include "esphome/components/esp32_ble/ble_uuid.h" #include "esphome/components/esp32_ble/ble_uuid.h"
#include "esphome/core/bytebuffer.h"
#ifdef USE_ESP32 #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 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)) { 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; this->permissions_ = ESP_GATT_PERM_READ;
} }

View file

@ -32,14 +32,13 @@ BLECharacteristic::BLECharacteristic(const ESPBTUUID uuid, uint32_t properties)
this->set_write_no_response_property((properties & PROPERTY_WRITE_NR) != 0); this->set_write_no_response_property((properties & PROPERTY_WRITE_NR) != 0);
} }
void BLECharacteristic::set_value(std::vector<uint8_t> value) { void BLECharacteristic::set_value(ByteBuffer buffer) {
size_t length = buffer.get_capacity();
uint8_t *data = buffer.array();
xSemaphoreTake(this->set_value_lock_, 0L); xSemaphoreTake(this->set_value_lock_, 0L);
this->value_ = std::move(value); this->value_ = std::vector<uint8_t>(data, data + length);
xSemaphoreGive(this->set_value_lock_); xSemaphoreGive(this->set_value_lock_);
} }
void BLECharacteristic::set_value(const uint8_t *data, size_t length) {
this->set_value(std::vector<uint8_t>(data, data + length));
}
void BLECharacteristic::notify(bool require_ack) { void BLECharacteristic::notify(bool require_ack) {
if (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->value_.insert(this->value_.end(), param->write.value, param->write.value + param->write.len);
this->write_event_ = true; this->write_event_ = true;
} else { } 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) { if (param->write.need_rsp) {

View file

@ -3,7 +3,7 @@
#include "ble_descriptor.h" #include "ble_descriptor.h"
#include "esphome/components/esp32_ble/ble_uuid.h" #include "esphome/components/esp32_ble/ble_uuid.h"
#include "esphome/core/event_emitter.h" #include "esphome/core/event_emitter.h"
#include "esphome/core/helpers.h" #include "esphome/core/bytebuffer.h"
#include <vector> #include <vector>
@ -40,16 +40,7 @@ class BLECharacteristic : public EventEmitter<BLECharacteristicEvt::VectorEvt, s
BLECharacteristic(ESPBTUUID uuid, uint32_t properties); BLECharacteristic(ESPBTUUID uuid, uint32_t properties);
~BLECharacteristic(); ~BLECharacteristic();
void set_value(const uint8_t *data, size_t length); void set_value(ByteBuffer buffer);
void set_value(std::vector<uint8_t> 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_broadcast_property(bool value); void set_broadcast_property(bool value);
void set_indicate_property(bool value); void set_indicate_property(bool value);

View file

@ -38,9 +38,10 @@ void BLEDescriptor::do_create(BLECharacteristic *characteristic) {
this->state_ = CREATING; this->state_ = CREATING;
} }
void BLEDescriptor::set_value(std::vector<uint8_t> 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) { 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); ESP_LOGE(TAG, "Size %d too large, must be no bigger than %d", length, this->value_.attr_max_len);
return; return;

View file

@ -1,7 +1,7 @@
#pragma once #pragma once
#include "esphome/components/esp32_ble/ble_uuid.h" #include "esphome/components/esp32_ble/ble_uuid.h"
#include "esphome/core/helpers.h" #include "esphome/core/bytebuffer.h"
#ifdef USE_ESP32 #ifdef USE_ESP32
@ -21,16 +21,7 @@ class BLEDescriptor {
virtual ~BLEDescriptor(); virtual ~BLEDescriptor();
void do_create(BLECharacteristic *characteristic); void do_create(BLECharacteristic *characteristic);
void set_value(const uint8_t *data, size_t length); void set_value(ByteBuffer buffer);
void set_value(std::vector<uint8_t> 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 gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param); void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param);

View file

@ -4,6 +4,7 @@
#include "esphome/core/log.h" #include "esphome/core/log.h"
#include "esphome/core/application.h" #include "esphome/core/application.h"
#include "esphome/core/version.h" #include "esphome/core/version.h"
#include "esphome/core/bytebuffer.h"
#ifdef USE_ESP32 #ifdef USE_ESP32
@ -111,20 +112,20 @@ bool BLEServer::create_device_characteristics_() {
if (this->model_.has_value()) { if (this->model_.has_value()) {
BLECharacteristic *model = BLECharacteristic *model =
this->device_information_service_->create_characteristic(MODEL_UUID, BLECharacteristic::PROPERTY_READ); 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 { } else {
BLECharacteristic *model = BLECharacteristic *model =
this->device_information_service_->create_characteristic(MODEL_UUID, BLECharacteristic::PROPERTY_READ); 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 = BLECharacteristic *version =
this->device_information_service_->create_characteristic(VERSION_UUID, BLECharacteristic::PROPERTY_READ); 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 = BLECharacteristic *manufacturer =
this->device_information_service_->create_characteristic(MANUFACTURER_UUID, BLECharacteristic::PROPERTY_READ); 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; return true;
} }

View file

@ -4,6 +4,7 @@
#include "esphome/core/event_emitter.h" #include "esphome/core/event_emitter.h"
#include "esphome/core/automation.h" #include "esphome/core/automation.h"
#include "esphome/core/bytebuffer.h"
#include <vector> #include <vector>
#include <unordered_map> #include <unordered_map>
@ -27,7 +28,7 @@ enum BLECharacteristicSetValueActionEvt {
PRE_NOTIFY, 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 class BLECharacteristicSetValueActionManager
: public EventEmitter<BLECharacteristicSetValueActionEvt, BLECharacteristic *> { : public EventEmitter<BLECharacteristicSetValueActionEvt, BLECharacteristic *> {
public: public:
@ -52,22 +53,22 @@ class BLECharacteristicSetValueActionManager
template<typename... Ts> class BLECharacteristicSetValueAction : public Action<Ts...> { template<typename... Ts> class BLECharacteristicSetValueAction : public Action<Ts...> {
public: public:
BLECharacteristicSetValueAction(BLECharacteristic *characteristic) : parent_(characteristic) {} BLECharacteristicSetValueAction(BLECharacteristic *characteristic) : parent_(characteristic) {}
TEMPLATABLE_VALUE(std::vector<uint8_t>, value) TEMPLATABLE_VALUE(ByteBuffer, buffer)
void play(Ts... x) override { void play(Ts... x) override {
// If the listener is already set, do nothing // If the listener is already set, do nothing
if (BLECharacteristicSetValueActionManager::get_instance()->get_listener(this->parent_) == this->listener_id_) if (BLECharacteristicSetValueActionManager::get_instance()->get_listener(this->parent_) == this->listener_id_)
return; return;
// Set initial value // 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 // Set the listener for read events
this->listener_id_ = this->parent_->EventEmitter<BLECharacteristicEvt::EmptyEvt>::on( this->listener_id_ = this->parent_->EventEmitter<BLECharacteristicEvt::EmptyEvt>::on(
BLECharacteristicEvt::EmptyEvt::ON_READ, [this, x...]() { BLECharacteristicEvt::EmptyEvt::ON_READ, [this, x...]() {
// Set the value of the characteristic every time it is read // 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 // Set the listener in the global manager so only one BLECharacteristicSetValueAction is set for each characteristic
BLECharacteristicSetValueActionManager::get_instance()->set_listener( 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: protected:

View file

@ -4,6 +4,7 @@
#include "esphome/components/esp32_ble_server/ble_2902.h" #include "esphome/components/esp32_ble_server/ble_2902.h"
#include "esphome/core/application.h" #include "esphome/core/application.h"
#include "esphome/core/log.h" #include "esphome/core/log.h"
#include "esphome/core/bytebuffer.h"
#ifdef USE_ESP32 #ifdef USE_ESP32
@ -63,7 +64,7 @@ void ESP32ImprovComponent::setup_characteristics() {
if (this->status_indicator_ != nullptr) if (this->status_indicator_ != nullptr)
capabilities |= improv::CAPABILITY_IDENTIFY; capabilities |= improv::CAPABILITY_IDENTIFY;
#endif #endif
this->capabilities_->set_value(capabilities); this->capabilities_->set_value(ByteBuffer::wrap(capabilities));
this->setup_complete_ = true; this->setup_complete_ = true;
} }
@ -196,7 +197,7 @@ void ESP32ImprovComponent::set_state_(improv::State state) {
this->state_ = state; this->state_ = state;
if (this->status_->get_value().empty() || this->status_->get_value()[0] != state) { if (this->status_->get_value().empty() || this->status_->get_value()[0] != state) {
uint8_t data[1]{state}; uint8_t data[1]{state};
this->status_->set_value(data, 1); this->status_->set_value(ByteBuffer::wrap(data));
if (state != improv::STATE_STOPPED) if (state != improv::STATE_STOPPED)
this->status_->notify(); 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) { if (this->error_->get_value().empty() || this->error_->get_value()[0] != error) {
uint8_t data[1]{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) if (this->state_ != improv::STATE_STOPPED)
this->error_->notify(); this->error_->notify();
} }
} }
void ESP32ImprovComponent::send_response_(std::vector<uint8_t> &response) { void ESP32ImprovComponent::send_response_(std::vector<uint8_t> &response) {
this->rpc_response_->set_value(response); this->rpc_response_->set_value(ByteBuffer::wrap(response));
if (this->state_ != improv::STATE_STOPPED) if (this->state_ != improv::STATE_STOPPED)
this->rpc_response_->notify(); this->rpc_response_->notify();
} }

View file

@ -1,5 +1,6 @@
#include "bytebuffer.h" #include "bytebuffer.h"
#include <cassert> #include <cassert>
#include <cstring>
namespace esphome { namespace esphome {
@ -8,13 +9,59 @@ ByteBuffer ByteBuffer::create(size_t capacity) {
return {data}; return {data};
} }
ByteBuffer ByteBuffer::wrap(uint8_t *ptr, size_t len) { ByteBuffer ByteBuffer::wrap(const uint8_t *ptr, size_t len) {
std::vector<uint8_t> data(ptr, ptr + len); std::vector<uint8_t> data(ptr, ptr + len);
return {data}; return {data};
} }
ByteBuffer ByteBuffer::wrap(std::vector<uint8_t> data) { return {std::move(data)}; } ByteBuffer ByteBuffer::wrap(std::vector<uint8_t> 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<uint8_t> buffer(data.begin(), data.end());
return {buffer};
}
ByteBuffer ByteBuffer::wrap(std::initializer_list<uint8_t> values) {
std::vector<uint8_t> buffer(values);
return {buffer};
}
void ByteBuffer::set_limit(size_t limit) { void ByteBuffer::set_limit(size_t limit) {
assert(limit <= this->get_capacity()); assert(limit <= this->get_capacity());
this->limit_ = limit; this->limit_ = limit;
@ -27,6 +74,16 @@ void ByteBuffer::clear() {
this->limit_ = this->get_capacity(); this->limit_ = this->get_capacity();
this->position_ = 0; 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() { uint16_t ByteBuffer::get_uint16() {
assert(this->get_remaining() >= 2); assert(this->get_remaining() >= 2);
uint16_t value; uint16_t value;
@ -39,23 +96,6 @@ uint16_t ByteBuffer::get_uint16() {
} }
return value; 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() { uint32_t ByteBuffer::get_uint24() {
assert(this->get_remaining() >= 3); assert(this->get_remaining() >= 3);
uint32_t value; uint32_t value;
@ -77,14 +117,89 @@ uint32_t ByteBuffer::get_int24() {
value |= mask; value |= mask;
return value; return value;
} }
uint8_t ByteBuffer::get_uint8() { uint32_t ByteBuffer::get_uint32() {
assert(this->get_remaining() >= 1); assert(this->get_remaining() >= 4);
return this->data_[this->position_++]; 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() { float ByteBuffer::get_float() {
auto value = this->get_uint32(); assert(this->get_remaining() >= sizeof(float));
return *(float *) &value; 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) { void ByteBuffer::put_uint8(uint8_t value) {
assert(this->get_remaining() >= 1); assert(this->get_remaining() >= 1);
this->data_[this->position_++] = value; this->data_[this->position_++] = value;
@ -126,9 +241,60 @@ void ByteBuffer::put_uint32(uint32_t value) {
this->data_[this->position_++] = (uint8_t) value; this->data_[this->position_++] = (uint8_t) value;
} }
} }
void ByteBuffer::put_float(float value) { this->put_uint32(*(uint32_t *) &value); } void ByteBuffer::put_uint64(uint64_t value) {
void ByteBuffer::flip() { assert(this->get_remaining() >= 8);
this->limit_ = this->position_; if (this->endianness_ == LITTLE) {
this->position_ = 0; 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 } // namespace esphome

View file

@ -4,6 +4,7 @@
#include <vector> #include <vector>
#include <cinttypes> #include <cinttypes>
#include <cstddef> #include <cstddef>
#include <string>
namespace esphome { namespace esphome {
@ -29,18 +30,34 @@ enum Endian { LITTLE, BIG };
*/ */
class ByteBuffer { class ByteBuffer {
public: public:
// Default constructor (compatibility with TEMPLATABLE_VALUE)
ByteBuffer() = default;
/** /**
* Create a new Bytebuffer with the given capacity * Create a new Bytebuffer with the given capacity
*/ */
static ByteBuffer create(size_t 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<uint8_t> data); static ByteBuffer wrap(std::vector<uint8_t> 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<uint8_t> values);
// Get one byte from the buffer, increment position by 1 // Get one byte from the buffer, increment position by 1
uint8_t get_uint8(); uint8_t get_uint8();
@ -50,20 +67,39 @@ class ByteBuffer {
uint32_t get_uint24(); uint32_t get_uint24();
// Get a 32 bit unsigned value, increment by 4 // Get a 32 bit unsigned value, increment by 4
uint32_t get_uint32(); 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(); }; uint8_t get_int8() { return (int8_t) this->get_uint8(); };
int16_t get_int16() { return (int16_t) this->get_uint16(); } int16_t get_int16() { return (int16_t) this->get_uint16(); }
uint32_t get_int24(); uint32_t get_int24();
int32_t get_int32() { return (int32_t) this->get_uint32(); } 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 // Get a float value, increment by 4
float get_float(); 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_uint8(uint8_t value);
void put_uint16(uint16_t value); void put_uint16(uint16_t value);
void put_uint24(uint32_t value); void put_uint24(uint32_t value);
void put_uint32(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_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_capacity() const { return this->data_.size(); }
inline size_t get_position() const { return this->position_; } inline size_t get_position() const { return this->position_; }

View file

@ -534,30 +534,6 @@ std::vector<uint8_t> base64_decode(const std::string &encoded_string) {
return ret; return ret;
} }
std::vector<uint8_t> to_vector(bool value) { return {value ? (uint8_t) 1 : (uint8_t) 0}; }
std::vector<uint8_t> to_vector(uint8_t value) { return {value}; }
std::vector<uint8_t> to_vector(uint16_t value) { return {uint8_t(value >> 8), uint8_t(value & 0xFF)}; }
std::vector<uint8_t> 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<uint8_t> 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<uint8_t> to_vector(int value) { return to_vector(static_cast<uint32_t>(value)); }
std::vector<uint8_t> to_vector(float value) {
uint32_t val;
memcpy(&val, &value, sizeof(val));
return to_vector(val);
}
std::vector<uint8_t> to_vector(double value) {
uint64_t val;
memcpy(&val, &value, sizeof(val));
return to_vector(val);
}
std::vector<uint8_t> to_vector(const std::string &value) { return std::vector<uint8_t>(value.begin(), value.end()); }
// Colors // Colors
float gamma_correct(float value, float gamma) { float gamma_correct(float value, float gamma) {

View file

@ -441,17 +441,6 @@ std::string base64_encode(const std::vector<uint8_t> &buf);
std::vector<uint8_t> base64_decode(const std::string &encoded_string); std::vector<uint8_t> base64_decode(const std::string &encoded_string);
size_t base64_decode(std::string const &encoded_string, uint8_t *buf, size_t buf_len); 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<uint8_t> to_vector(bool value);
std::vector<uint8_t> to_vector(uint8_t value);
std::vector<uint8_t> to_vector(uint16_t value);
std::vector<uint8_t> to_vector(uint32_t value);
std::vector<uint8_t> to_vector(uint64_t value);
std::vector<uint8_t> to_vector(int value);
std::vector<uint8_t> to_vector(float value);
std::vector<uint8_t> to_vector(double value);
std::vector<uint8_t> to_vector(const std::string &value);
///@} ///@}
/// @name Colors /// @name Colors

View file

@ -31,6 +31,6 @@ esp32_ble_server:
ESP_LOGD("BLE", "Received: %s", std::string(x.begin(), x.end()).c_str()); ESP_LOGD("BLE", "Received: %s", std::string(x.begin(), x.end()).c_str());
- ble_server.characteristic.set_value: - ble_server.characteristic.set_value:
id: test_change_characteristic id: test_change_characteristic
value: !lambda 'return {0x00, 0x01, 0x02};' value: !lambda 'return ByteBuffer::wrap({0x00, 0x01, 0x02});'
- ble_server.characteristic.notify: - ble_server.characteristic.notify:
id: test_notify_characteristic id: test_notify_characteristic