From 4be0ac2d6502204568f1e5d450020a670fb594f3 Mon Sep 17 00:00:00 2001 From: NP v/d Spek Date: Tue, 3 Sep 2024 19:09:10 +0200 Subject: [PATCH] WIP --- esphome/.gitignore | 5 ++ esphome/components/espnow/espnow.cpp | 46 +++++------- esphome/components/espnow/espnow.h | 108 ++++++++++++++------------- esphome/core/bytebuffer.cpp | 23 +++++- esphome/core/bytebuffer.h | 10 +++ esphome/test.yaml | 61 +++++++++++++++ 6 files changed, 172 insertions(+), 81 deletions(-) create mode 100644 esphome/.gitignore create mode 100644 esphome/test.yaml diff --git a/esphome/.gitignore b/esphome/.gitignore new file mode 100644 index 0000000000..d8b4157aef --- /dev/null +++ b/esphome/.gitignore @@ -0,0 +1,5 @@ +# Gitignore settings for ESPHome +# This is an example and may include too much for your use-case. +# You can modify this file to suit your needs. +/.esphome/ +/secrets.yaml diff --git a/esphome/components/espnow/espnow.cpp b/esphome/components/espnow/espnow.cpp index 82db15cfca..c07c60fde1 100644 --- a/esphome/components/espnow/espnow.cpp +++ b/esphome/components/espnow/espnow.cpp @@ -55,55 +55,46 @@ struct { } __attribute__((packed)) espnow_frame_format_t; #endif -ESPNowPacket::ESPNowPacket(uint64_t peer, const uint8_t *data, uint8_t size, uint32_t app_id) - : mac64(mac64), size(size), app_id(app_id), retrys(0) { - if (this->mac64 == 0) - this->mac64 = ESPNOW_BROADCAST_ADDR; - this->is_broadcast = this->mac64 == ESPNOW_BROADCAST_ADDR; - - this->ref_id = 0; - - this->size = std::min(MAX_ESPNOW_DATA_SIZE, size); - std::memcpy(&this->data, (uint8_t *) data, this->size); +ESPNowPacket::ESPNowPacket(espnow_addr_t peer, const uint8_t *data, uint8_t size, uint32_t protocol) : ESPNowPacket() { + if (this->peer() == {0}) + this->peer(ESPNOW_BROADCAST_ADDR); + this->is_broadcast = memcpr(&this->peer(), &ESPNOW_BROADCAST_ADDR, 6); + this->protocol(protocol); + this->content_->get_data().std::memcpy(&this->data, (uint8_t *) data, this->size); this->data[this->size + 1] = 0; this->recalc(); - this->info("create"); } -inline void ESPNowPacket::info(std::string place) { +void ESPNowPacket::info(std::string place) { ESP_LOGVV(TAG, "%s: M:%s A:0x%06x R:0x%02x C:0x%04x S:%02x", place.c_str(), this->to_str().c_str(), this->app_id, this->ref_id, this->random, this->size); } bool ESPNowPacket::is_valid() { - uint16_t crc = this->crc16; - recalc(); - bool valid = (std::memcmp(&header, &TRANSPORT_HEADER, 3) == 0); - valid &= (this->app_id != 0); - valid &= (this->crc16 == crc); + uint16_t crc = this->crc(); + this->calc_crc(); + bool valid = (std::memcmp(this->header(), &TRANSPORT_HEADER, 3) == 0); + valid &= (this->protocol() != 0); + valid &= (this->crc() == crc); if (!valid) { - ESP_LOGV("Packet", "Invalid H:%02x%02x%02x A:%06x R:%02x C:%04x ipv. %04x, %d&%d&%d=%d\n", this->header[0], - this->header[1], this->header[2], this->app_id, this->ref_id, crc, this->crc16, - std::memcmp(&header, &TRANSPORT_HEADER, 3) == 0, (this->app_id != 0), (this->crc16 == crc), valid); + ESP_LOGV("Packet", "Invalid H:%02x%02x%02x A:%06x R:%02x C:%04x ipv. %04x\n", this->header()[0], this->header()[1], + this->header()[2], this->protocol(), this->packet_id(), crc, this->crc()); } - - this->crc16 = crc; + this->crc(crc); return valid; } -void ESPNowProtocol::setup() { parent_->register_protocol(this); } - bool ESPNowProtocol::write(uint64_t mac_address, const uint8_t *data, uint8_t len) { - ESPNowPacket packet(mac_address, data, len, this->get_app_id()); + ESPNowPacket packet(mac_address, data, len, this->get_protocol_id()); return this->parent_->write(packet); } bool ESPNowProtocol::write(uint64_t mac_address, std::vector &data) { - ESPNowPacket packet(mac_address, (uint8_t *) data.data(), (uint8_t) data.size(), this->get_app_id()); + ESPNowPacket packet(mac_address, (uint8_t *) data.data(), (uint8_t) data.size(), this->get_protocol_id()); return this->parent_->write(packet); } bool ESPNowProtocol::write(ESPNowPacket packet) { - packet.app_id = this->get_app_id(); + packet.protocol(this->get_protocol_id()); packet.ref_id = this->get_next_ref_id(); packet.recalc(); return this->parent_->write(packet); @@ -239,7 +230,6 @@ esp_err_t ESPNowComponent::del_peer(uint64_t addr) { ESPNowDefaultProtocol *ESPNowComponent::get_default_protocol() { if (this->protocols_[ESPNOW_DEFAULT_APP_ID] == nullptr) { ESPNowDefaultProtocol *tmp = new ESPNowDefaultProtocol(); - this->protocols_[ESPNOW_DEFAULT_APP_ID] = tmp; this->register_protocol(tmp); } return (ESPNowDefaultProtocol *) this->protocols_[ESPNOW_DEFAULT_APP_ID]; diff --git a/esphome/components/espnow/espnow.h b/esphome/components/espnow/espnow.h index 07058ed1c3..17abc9c2c0 100644 --- a/esphome/components/espnow/espnow.h +++ b/esphome/components/espnow/espnow.h @@ -22,7 +22,7 @@ namespace espnow { typedef uint8_t espnow_addr_t[6]; -static const uint64_t ESPNOW_BROADCAST_ADDR = 0xFFFFFFFFFFFF; +static const espnow_addr_t ESPNOW_BROADCAST_ADDR = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; static espnow_addr_t ESPNOW_ADDR_SELF = {0}; static const uint8_t ESPNOW_DATA_HEADER = 0x00; @@ -62,70 +62,76 @@ class ESPNowPacket { public: ESPNowPacket() ESPHOME_ALWAYS_INLINE { this->content_.put_uint24(TRANSPORT_HEADER); } // Create packet to be send. - ESPNowPacket(espnow_addr_t mac64, const uint8_t *data, uint8_t size, uint32_t app_id); + ESPNowPacket(espnow_addr_t peer, const uint8_t *data, uint8_t size, uint32_t app_id); // Load received packet's. - ESPNowPacket(espnow_addr_t mac64, const uint8_t *data, uint8_t size); + ESPNowPacket(espnow_addr_t peer, const uint8_t *data, uint8_t size); - void info(std::string place); + inline void info(std::string place); uint8_T *peer() { return this->peer_; } void peer(espnow_addr_t mac_addres) { std::memcpy(&this->peer_, &mac_addres, 6); } - uint8_T size() { return this->content_; } + uint8_T size() { + if (this->content_->get_used() <= 10) { + return 0; + } + return this->content_->get_used(); + } +} bool broadcast(){return this->is_broadcast_}; - void broadcast(bool state) { this->is_broadcast_ = state; } +void broadcast(bool state) { this->is_broadcast_ = state; } - uint32_t timestamp() { return this->timestamp_; }; - void timestamp(uint32_t timestamp) { this->timestamp_ = timestamp; }; +uint32_t timestamp() { return this->timestamp_; }; +void timestamp(uint32_t timestamp) { this->timestamp_ = timestamp; }; - uint32_t protocol() { - this->content_->set_position(ESPNOW_DATA_PROTOCOL); - return this->content_->get_uint24(); - } - void protocol(uint32_t protocol) { - this->content_->set_position(ESPNOW_DATA_PROTOCOL); - this->content_->put_uint24(protocol); - } +uint32_t protocol() { + this->content_->set_position(ESPNOW_DATA_PROTOCOL); + return this->content_->get_uint24(); +} +void protocol(uint32_t protocol) { + this->content_->set_position(ESPNOW_DATA_PROTOCOL); + this->content_->put_uint24(protocol); +} - uint8_t packet_id() { - this->content_->set_position(ESPNOW_DATA_PACKET); - return this->content_->get_uint8(); - } - void packet_id(uint8_t packet_id) { - this->content_->set_position(ESPNOW_DATA_PACKET); - this->content_->put_uint8(packet_id); - } +uint8_t packet_id() { + this->content_->set_position(ESPNOW_DATA_PACKET); + return this->content_->get_uint8(); +} +void packet_id(uint8_t packet_id) { + this->content_->set_position(ESPNOW_DATA_PACKET); + this->content_->put_uint8(packet_id); +} - uint16_t crc() { - this->content_->set_position(ESPNOW_DATA_CRC); - return this->content_->get_uint16(); - } - void crc(uint16_t crc) { - this->content_->set_position(ESPNOW_DATA_CRC); - this->content_->put_uint16(crc); - } +uint16_t crc() { + this->content_->set_position(ESPNOW_DATA_CRC); + return this->content_->get_uint16(); +} +void crc(uint16_t crc) { + this->content_->set_position(ESPNOW_DATA_CRC); + this->content_->put_uint16(crc); +} - ByteBuffer *content() { - this->content_.set_position(ESPNOW_DATA_CONTENT + this->size_); - return &this->content_; +ByteBuffer *content() { + this->content_.set_position(ESPNOW_DATA_CONTENT + this->size_); + return &this->content_; +} + +void retry() { + if (this->retrys_ < 7) { + this->retrys_ = this->retrys_ + 1; } +} - void retry() { - if (this->retrys_ < 7) { - this->retrys_ = this->retrys_ + 1; - } - } +void calc_crc() { + this->crc(0); + this->crc(esp_crc16_le(this->packet(), this->dataptr(), 10 + size())); +} - void calc_crc() { - this->crc(0); - this->crc(esp_crc16_le(this->packet(), this->dataptr(), 10 + size())); - } +bool is_valid(); - bool is_valid(); - - uint8_t *dataptr() { return this->content_->get_data()->data(); } +uint8_t *dataptr() { return this->content_->get_data()->data(); } }; class ESPNowComponent; @@ -136,13 +142,11 @@ class ESPNowProtocol : public Parented { public: ESPNowProtocol(){}; - void setup(); - virtual void on_receive(ESPNowPacket packet){}; virtual void on_sent(ESPNowPacket packet, bool status){}; virtual void on_new_peer(ESPNowPacket packet){}; - virtual uint32_t get_app_id() = 0; + virtual uint32_t get_protocol_id() = 0; uint8_t get_next_ref_id() { return next_ref_id_++; } bool write(uint64_t mac_address, const uint8_t *data, uint8_t len); @@ -159,7 +163,7 @@ class ESPNowDefaultProtocol : public ESPNowProtocol { void on_sent(ESPNowPacket packet, bool status) override { this->on_sent_.call(packet, status); }; void on_new_peer(ESPNowPacket packet) override { this->on_new_peer_.call(packet); }; - uint32_t get_app_id() override { return ESPNOW_DEFAULT_APP_ID; }; + uint32_t get_protocol_id() override { return ESPNOW_DEFAULT_APP_ID; }; void add_on_sent_callback(std::function &&callback) { this->on_sent_.add(std::move(callback)); @@ -206,7 +210,7 @@ class ESPNowComponent : public Component { void register_protocol(ESPNowProtocol *protocol) { protocol->set_parent(this); - this->protocols_[protocol->get_app_id()] = protocol; + this->protocols_[protocol->get_protocol_id()] = protocol; } esp_err_t add_peer(uint64_t addr); diff --git a/esphome/core/bytebuffer.cpp b/esphome/core/bytebuffer.cpp index 65525ecfcf..a3392d0177 100644 --- a/esphome/core/bytebuffer.cpp +++ b/esphome/core/bytebuffer.cpp @@ -80,7 +80,9 @@ void ByteBuffer::flip() { /// Getters uint8_t ByteBuffer::get_uint8() { assert(this->get_remaining() >= 1); - return this->data_[this->position_++]; + this->position_++; + this->update_used_(); + return this->data_[this->position_]; } uint64_t ByteBuffer::get_uint(size_t length) { assert(this->get_remaining() >= length); @@ -98,6 +100,7 @@ uint64_t ByteBuffer::get_uint(size_t length) { value |= this->data_[this->position_++]; } } + this->update_used_(); return value; } @@ -126,13 +129,22 @@ std::vector ByteBuffer::get_vector(size_t length) { assert(this->get_remaining() >= length); auto start = this->data_.begin() + this->position_; this->position_ += length; + this->update_used_(); return {start, start + length}; } +void ByteBuffer::get_data(const uint8_t *data, size_t length) { + assert(this->get_remaining() >= length); + auto start = this->data_.begin() + this->position_; + copy(start, start + length, data); + this->position_ += length; + this->update_used_(); +} /// Putters void ByteBuffer::put_uint8(uint8_t value) { assert(this->get_remaining() >= 1); this->data_[this->position_++] = value; + this->update_used_(); } void ByteBuffer::put_uint(uint64_t value, size_t length) { @@ -150,6 +162,7 @@ void ByteBuffer::put_uint(uint64_t value, size_t length) { value >>= 8; } } + this->update_used_(); } void ByteBuffer::put_float(float value) { static_assert(sizeof(float) == sizeof(uint32_t), "Float sizes other than 32 bit not supported"); @@ -169,5 +182,13 @@ void ByteBuffer::put_vector(const std::vector &value) { assert(this->get_remaining() >= value.size()); std::copy(value.begin(), value.end(), this->data_.begin() + this->position_); this->position_ += value.size(); + this->update_used_(); } +void ByteBuffer::put_array(const uint8_t *data, size_t size) { + assert(this->get_remaining() >= size); + std::copy(data[0], data[size], this->data_.begin() + this->position_); + this->position_ += size; + this->update_used_(); +} + } // namespace esphome diff --git a/esphome/core/bytebuffer.h b/esphome/core/bytebuffer.h index d44d01f275..02c7d1f364 100644 --- a/esphome/core/bytebuffer.h +++ b/esphome/core/bytebuffer.h @@ -92,6 +92,7 @@ class ByteBuffer { bool get_bool() { return this->get_uint8(); } // Get vector of bytes, increment by length std::vector get_vector(size_t length); + void get_data(const uint8_t *data, size_t length); // Put values into the buffer, increment the position accordingly // put any integral value, length represents the number of bytes @@ -112,11 +113,13 @@ class ByteBuffer { void put_double(double value); void put_bool(bool value) { this->put_uint8(value); } void put_vector(const std::vector &value); + void put_array(const uint8_t *data, size_t size); inline size_t get_capacity() const { return this->data_.size(); } inline size_t get_position() const { return this->position_; } inline size_t get_limit() const { return this->limit_; } inline size_t get_remaining() const { return this->get_limit() - this->get_position(); } + inline size_t get_used() const { return this->used_; } inline Endian get_endianness() const { return this->endianness_; } inline void mark() { this->mark_ = this->position_; } inline void big_endian() { this->endianness_ = BIG; } @@ -131,14 +134,21 @@ class ByteBuffer { std::vector get_data() { return this->data_; }; void rewind() { this->position_ = 0; } void reset() { this->position_ = this->mark_; } + void resize() { this->used_ = this->position_; } protected: ByteBuffer(std::vector const &data) : data_(data), limit_(data.size()) {} + void update_used_() { + if (this->used_ < this->position_) { + this->resize(); + } + } std::vector data_; Endian endianness_{LITTLE}; size_t position_{0}; size_t mark_{0}; size_t limit_{0}; + size_t used_{0}; }; } // namespace esphome diff --git a/esphome/test.yaml b/esphome/test.yaml new file mode 100644 index 0000000000..ea8e192b78 --- /dev/null +++ b/esphome/test.yaml @@ -0,0 +1,61 @@ +# These substitutions allow the end user to override certain values +substitutions: + name: "lum-iot-test" + friendly_name: "Project Template" + +#xternal_components: +# - source: github://pr#7141 +# components: [ espnow ] +# refresh: 1 sec + +esp32: + board: esp32-s3-devkitc-1 + framework: + type: esp-idf + +wifi: + +esphome: + name: "${name}" + # Friendly names are used where appropriate in Home Assistant + friendly_name: "${friendly_name}" + # Automatically add the mac address to the name + # so you can use a single firmware for all devices + name_add_mac_suffix: false + + # This will allow for (future) project identification, + # configuration and updates. + project: + name: esphome.project-template + version: "1.0" + +# To be able to get logs from the device via serial and api. +logger: + +# API is a requirement of the dashboard import. +api: + +# OTA is required for Over-the-Air updating +ota: + platform: esphome + +# Sets up Bluetooth LE (Only on ESP32) to allow the user +# to provision wifi credentials to the device. +esp32_improv: + authorizer: none + +espnow: + auto_add_peer: true + peers: + - FF:FF:FF:FF:FF:FF + on_receive: + - logger.log: + format: "Received: %s RSSI: %d" + args: [it->data().data(), it->rssi()] + +binary_sensor: + - platform: gpio + pin: GPIO39 + name: Button + on_click: + - espnow.send: "hallo everyone"