From 9f5643f75e17e223adbc83f5e53825aa8c5a881c Mon Sep 17 00:00:00 2001 From: NP v/d Spek Date: Mon, 23 Sep 2024 15:33:45 +0200 Subject: [PATCH] make use of std::shared_ptr for the packet struct --- esphome/components/espnow/__init__.py | 10 ++-- esphome/components/espnow/espnow.cpp | 61 ++++++++++----------- esphome/components/espnow/espnow.h | 78 +++++++++++++++------------ 3 files changed, 80 insertions(+), 69 deletions(-) diff --git a/esphome/components/espnow/__init__.py b/esphome/components/espnow/__init__.py index ec924fdf65..cba098d24e 100644 --- a/esphome/components/espnow/__init__.py +++ b/esphome/components/espnow/__init__.py @@ -11,7 +11,7 @@ ESPNowComponent = espnow_ns.class_("ESPNowComponent", cg.Component) ESPNowListener = espnow_ns.class_("ESPNowListener") ESPNowPacket = espnow_ns.class_("ESPNowPacket") -ESPNowPacketPtrConst = ESPNowPacket.operator("ptr") # .operator("const") + ESPNowInterface = espnow_ns.class_( "ESPNowInterface", cg.Component, cg.Parented.template(ESPNowComponent) @@ -92,19 +92,21 @@ async def to_code(config): for conf in config.get(CONF_ON_SENT, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) await automation.build_automation( - trigger, [(ESPNowPacketPtrConst, "packet"), (bool, "status")], conf + trigger, + [(cg.std_shared_ptr.template(ESPNowPacket), "packet"), (bool, "status")], + conf, ) for conf in config.get(CONF_ON_RECEIVE, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) await automation.build_automation( - trigger, [(ESPNowPacketPtrConst, "packet")], conf + trigger, [(cg.std_shared_ptr.template(ESPNowPacket), "packet")], conf ) for conf in config.get(CONF_ON_NEW_PEER, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) await automation.build_automation( - trigger, [(ESPNowPacketPtrConst, "packet")], conf + trigger, [(cg.std_shared_ptr.template(ESPNowPacket), "packet")], conf ) for conf in config.get(CONF_PEERS, []): diff --git a/esphome/components/espnow/espnow.cpp b/esphome/components/espnow/espnow.cpp index 25313e3c46..00a82c1371 100644 --- a/esphome/components/espnow/espnow.cpp +++ b/esphome/components/espnow/espnow.cpp @@ -39,7 +39,7 @@ std::string format_mac_addr(const uint8_t *mac) { sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); return buf; } -void show_packet(std::string title, ESPNowPacket *packet) { +void show_packet(std::string title, ESPNowPacketPtr packet) { ESP_LOGVV(TAG, "%s packet: M:%s H:%cx%cx%c P:%c%c%c 0x%02x S:%02x C:ox%02x~0x%02x S:%02d V:%s", "test", format_mac_addr(packet->peer_as_bytes()).c_str(), packet->content_at(0), packet->content_at(1), packet->content_at(2), packet->content_at(3), packet->content_at(4), packet->content_at(5), @@ -50,22 +50,20 @@ void show_packet(std::string title, ESPNowPacket *packet) { /* ESPNowPacket ********************************************************************** */ ESPNowPacket::ESPNowPacket(uint64_t peer, const uint8_t *data, uint8_t size, uint32_t protocol) : ESPNowPacket() { + assert(size <= MAX_ESPNOW_DATA_SIZE); this->set_peer(peer); this->is_broadcast = (std::memcmp((const void *) this->peer_as_bytes(), (const void *) &ESPNOW_BROADCAST_ADDR, 6) == 0); this->set_protocol(protocol); - this->payload()->put_bytes(data, size); - this->update_payload_(); + std::memcpy((uint8_t *) &this->content.payload, data, size); + this->update_payload(); } ESPNowPacket::ESPNowPacket(uint64_t peer, const uint8_t *data, uint8_t size) : ESPNowPacket() { this->set_peer(peer); - std::memcpy(&(this->content), data, this->prefix_size()); - size -= this->prefix_size(); - this->payload()->put_bytes(data + this->prefix_size(), size - 1); - this->update_payload_(); - this->content.payload[this->size] = *(data + size); + std::memcpy((uint8_t *) &this->content, data, size); + this->size = size - 1; } bool ESPNowPacket::is_valid() { @@ -80,7 +78,7 @@ bool ESPNowPacket::is_valid() { /* ESPNowProtocol ********************************************************************** */ bool ESPNowProtocol::write(uint64_t peer, const uint8_t *data, uint8_t len) { - ESPNowPacket *packet = new ESPNowPacket(peer, data, len, this->get_protocol_id()); + ESPNowPacketPtr packet = std::make_shared(peer, data, len, this->get_protocol_id()); packet->set_sequents(this->get_next_sequents()); return this->parent_->write(packet); } @@ -217,21 +215,21 @@ ESPNowProtocol *ESPNowComponent::get_protocol_(uint32_t protocol) { return this->protocols_[protocol]; } -void ESPNowComponent::on_receive_(ESPNowPacket *packet) { +void ESPNowComponent::on_receive_(ESPNowPacketPtr packet) { ESPNowProtocol *protocol = this->get_protocol_(packet->get_protocol()); if (protocol != nullptr) { protocol->on_receive(packet); } } -void ESPNowComponent::on_sent_(ESPNowPacket *packet, bool status) { +void ESPNowComponent::on_sent_(ESPNowPacketPtr packet, bool status) { ESPNowProtocol *protocol = this->get_protocol_(packet->get_protocol()); if (protocol != nullptr) { protocol->on_sent(packet, status); } } -void ESPNowComponent::on_new_peer_(ESPNowPacket *packet) { +void ESPNowComponent::on_new_peer_(ESPNowPacketPtr packet) { ESPNowProtocol *protocol = this->get_protocol_(packet->get_protocol()); if (protocol != nullptr) { protocol->on_new_peer(packet); @@ -257,7 +255,7 @@ void ESPNowComponent::on_data_received(const uint8_t *addr, const uint8_t *data, (wifi_promiscuous_pkt_t *) (data - sizeof(wifi_pkt_rx_ctrl_t) - 39); // = sizeof (espnow_frame_format_t) rx_ctrl = &promiscuous_pkt->rx_ctrl; #endif - ESPNowPacket *packet = new ESPNowPacket((uint64_t) *addr, data, (uint8_t) size); + ESPNowPacketPtr packet = std::make_shared((uint64_t) *addr, data, (uint8_t) size); packet->is_broadcast = broadcast; if (rx_ctrl != nullptr) { packet->rssi = rx_ctrl->rssi; @@ -268,13 +266,13 @@ void ESPNowComponent::on_data_received(const uint8_t *addr, const uint8_t *data, show_packet("Receive", packet); if (packet->is_valid()) { - xQueueSendToBack(global_esp_now->receive_queue_, packet, 10); + xQueueSendToBack(global_esp_now->receive_queue_, packet.get(), 10); } else { ESP_LOGE(TAG, "Invalid ESP-NOW packet received (CRC)"); } } -bool ESPNowComponent::write(ESPNowPacket *packet) { +bool ESPNowComponent::write(ESPNowPacketPtr packet) { uint8_t *mac = packet->peer_as_bytes(); show_packet("Write", packet); if (this->is_failed()) { @@ -286,7 +284,7 @@ bool ESPNowComponent::write(ESPNowPacket *packet) { } else if (!packet->is_valid()) { ESP_LOGW(TAG, "Packet is invalid. maybe you need to ::calc_crc(). the packat before writing."); } else if (this->use_sent_check_) { - xQueueSendToBack(this->send_queue_, packet, 10); + xQueueSendToBack(this->send_queue_, packet.get(), 10); ESP_LOGVV(TAG, "Send to 0x%12llx (%d.%d): Buffer Used: %d", packet->peer, packet->get_sequents(), packet->attempts, this->send_queue_used()); @@ -303,12 +301,11 @@ bool ESPNowComponent::write(ESPNowPacket *packet) { } void ESPNowComponent::runner() { - ESPNowPacket *packet{nullptr}; + ESPNowPacketPtr packet{nullptr}; for (;;) { - delete packet; - packet = new ESPNowPacket(); - if (xQueueReceive(this->receive_queue_, packet, (TickType_t) 1) == pdTRUE) { + packet = std::make_shared(); + if (xQueueReceive(this->receive_queue_, packet.get(), (TickType_t) 1) == pdTRUE) { uint8_t *mac = packet->peer_as_bytes(); if (!esp_now_is_peer_exist(mac)) { @@ -321,9 +318,8 @@ void ESPNowComponent::runner() { } this->defer([this, packet]() { this->on_receive_(packet); }); } - delete packet; - packet = new ESPNowPacket(); - if (xQueueReceive(this->send_queue_, packet, (TickType_t) 1) == pdTRUE) { + packet = std::make_shared(); + if (xQueueReceive(this->send_queue_, packet.get(), (TickType_t) 1) == pdTRUE) { if (packet->attempts > MAX_NUMBER_OF_RETRYS) { ESP_LOGW(TAG, "To many send retries. Packet dropped. 0x%04x", packet->get_sequents()); this->unlock(); @@ -349,18 +345,18 @@ void ESPNowComponent::runner() { this->unlock(); } } - xQueueSendToFront(this->send_queue_, packet, 10 / portTICK_PERIOD_MS); + xQueueSendToFront(this->send_queue_, packet.get(), 10 / portTICK_PERIOD_MS); } } } void ESPNowComponent::on_data_sent(const uint8_t *mac_addr, esp_now_send_status_t status) { - ESPNowPacket *packet = new ESPNowPacket(); + ESPNowPacketPtr packet = std::make_shared(); if (!global_esp_now->use_sent_check_) { return; } uint64_t mac64 = (uint64_t) *mac_addr; - if (xQueuePeek(global_esp_now->send_queue_, packet, 10 / portTICK_PERIOD_MS) == pdTRUE) { + if (xQueuePeek(global_esp_now->send_queue_, packet.get(), 10 / portTICK_PERIOD_MS) == pdTRUE) { if (status != ESP_OK) { ESP_LOGE(TAG, "sent packet failed (0x%04x.%d)", packet->get_sequents(), packet->attempts); } else if (packet->peer != mac64) { @@ -369,10 +365,11 @@ void ESPNowComponent::on_data_sent(const uint8_t *mac_addr, esp_now_send_status_ } else { ESP_LOGV(TAG, "Confirm sent (0x%04x.%d)", packet->get_sequents(), packet->attempts); global_esp_now->defer([packet]() { + packet->reload(); global_esp_now->on_sent_(packet, true); - delete packet; - ESPNowPacket tmp; - xQueueReceive(global_esp_now->send_queue_, &tmp, 10 / portTICK_PERIOD_MS); + auto tmp = std::make_shared(); + + xQueueReceive(global_esp_now->send_queue_, tmp.get(), 10 / portTICK_PERIOD_MS); global_esp_now->unlock(); }); @@ -380,9 +377,9 @@ void ESPNowComponent::on_data_sent(const uint8_t *mac_addr, esp_now_send_status_ } global_esp_now->defer([packet]() { global_esp_now->on_sent_(packet, false); - ESPNowPacket tmp; - xQueueReceive(global_esp_now->send_queue_, &tmp, 10 / portTICK_PERIOD_MS); - xQueueSendToFront(global_esp_now->send_queue_, &tmp, 10 / portTICK_PERIOD_MS); + auto tmp = std::make_shared(); + xQueueReceive(global_esp_now->send_queue_, tmp.get(), 10 / portTICK_PERIOD_MS); + xQueueSendToFront(global_esp_now->send_queue_, tmp.get(), 10 / portTICK_PERIOD_MS); global_esp_now->unlock(); }); diff --git a/esphome/components/espnow/espnow.h b/esphome/components/espnow/espnow.h index 70f462e0ab..c49e629578 100644 --- a/esphome/components/espnow/espnow.h +++ b/esphome/components/espnow/espnow.h @@ -58,7 +58,7 @@ struct ESPNowPacket { // Load received packet's. ESPNowPacket(uint64_t peer, const uint8_t *data, uint8_t size); - ~ESPNowPacket() {} // this->payload_buffer_ = nullptr; + ~ESPNowPacket() { this->payload_buffer_.reset(); } // this->payload_buffer_ = nullptr; uint8_t *peer_as_bytes() { return (uint8_t *) &(this->peer); } void set_peer(uint64_t peer) { @@ -72,35 +72,35 @@ struct ESPNowPacket { inline uint8_t prefix_size() { return sizeof(this->content) - sizeof(this->content.payload); } uint8_t get_size() { - this->update_payload_(); + this->update_payload(); return this->size; }; inline uint32_t get_protocol() { return this->content.protocol; } void set_protocol(uint32_t protocol) { this->content.protocol = protocol; - this->update_payload_(); + this->update_payload(); } inline uint8_t get_sequents() { return this->content.sequents; } void set_sequents(uint8_t sequents) { this->content.sequents = sequents; - this->update_payload_(); + this->update_payload(); } uint8_t content_at(uint8_t pos) { - this->update_payload_(); + this->update_payload(); assert(pos < this->size); return *(((uint8_t *) &this->content) + pos); } uint8_t *content_bytes() { - this->update_payload_(); + this->update_payload(); return (uint8_t *) &(this->content); } uint8_t crc() { - // this->update_payload_(); + // this->update_payload(); return this->content.payload[this->size]; } uint8_t calc_crc() { @@ -113,32 +113,43 @@ struct ESPNowPacket { bool is_valid(); std::shared_ptr payload() { + if (!this->payload_buffer_) { + this->reload(); + } this->payload_buffer_->set_position(this->payload_buffer_->get_used_space()); return this->payload_buffer_; } - private: - std::shared_ptr payload_buffer_; + void reload() { + this->payload_buffer_ = std::make_shared(MAX_ESPNOW_DATA_SIZE); + this->payload_buffer_->put_bytes((const uint8_t *) &this->content.payload, this->size - (this->prefix_size() + 1)); + this->payload_buffer_->is_changed(); + } - void update_payload_() { - if (this->payload_buffer_->is_changed()) { + void update_payload() { + if (this->payload_buffer_ && this->payload_buffer_->is_changed()) { this->payload_buffer_->flip(); this->payload_buffer_->get_bytes((uint8_t *) &(this->content.payload), this->payload_buffer_->get_used_space()); this->size = this->payload_buffer_->get_used_space() + this->prefix_size(); } this->content.payload[this->size] = this->calc_crc(); } + + protected: + std::shared_ptr payload_buffer_; }; +using ESPNowPacketPtr = std::shared_ptr; + class ESPNowComponent; class ESPNowProtocol : public Parented { public: ESPNowProtocol(){}; - virtual void on_receive(ESPNowPacket *packet){}; - virtual void on_sent(ESPNowPacket *packet, bool status){}; - virtual void on_new_peer(ESPNowPacket *packet){}; + virtual void on_receive(ESPNowPacketPtr packet){}; + virtual void on_sent(ESPNowPacketPtr packet, bool status){}; + virtual void on_new_peer(ESPNowPacketPtr packet){}; virtual uint32_t get_protocol_id() = 0; uint8_t get_next_sequents() { @@ -165,29 +176,30 @@ class ESPNowProtocol : public Parented { protected: uint8_t next_sequents_{255}; }; + class ESPNowDefaultProtocol : public ESPNowProtocol { public: uint32_t get_protocol_id() override { return ESPNOW_MAIN_PROTOCOL_ID; }; - void add_on_receive_callback(std::function &&callback) { + void add_on_receive_callback(std::function &&callback) { this->on_receive_.add(std::move(callback)); } - void on_receive(ESPNowPacket *packet) override { this->on_receive_.call(packet); }; + void on_receive(ESPNowPacketPtr packet) override { this->on_receive_.call(packet); }; - void add_on_sent_callback(std::function &&callback) { + void add_on_sent_callback(std::function &&callback) { this->on_sent_.add(std::move(callback)); } - void on_sent(ESPNowPacket *packet, bool status) override { this->on_sent_.call(packet, status); }; + void on_sent(ESPNowPacketPtr packet, bool status) override { this->on_sent_.call(packet, status); }; - void add_on_peer_callback(std::function &&callback) { + void add_on_peer_callback(std::function &&callback) { this->on_new_peer_.add(std::move(callback)); } - void on_new_peer(ESPNowPacket *packet) override { this->on_new_peer_.call(packet); }; + void on_new_peer(ESPNowPacketPtr packet) override { this->on_new_peer_.call(packet); }; protected: - CallbackManager on_sent_; - CallbackManager on_receive_; - CallbackManager on_new_peer_; + CallbackManager on_sent_; + CallbackManager on_receive_; + CallbackManager on_new_peer_; }; class ESPNowComponent : public Component { @@ -214,7 +226,7 @@ class ESPNowComponent : public Component { void runner(); - bool write(ESPNowPacket *packet); + bool write(ESPNowPacketPtr packet); void register_protocol(ESPNowProtocol *protocol) { protocol->set_parent(this); @@ -245,9 +257,9 @@ class ESPNowComponent : public Component { bool use_sent_check_{true}; bool lock_{false}; - void on_receive_(ESPNowPacket *packet); - void on_sent_(ESPNowPacket *packet, bool status); - void on_new_peer_(ESPNowPacket *packet); + void on_receive_(ESPNowPacketPtr packet); + void on_sent_(ESPNowPacketPtr packet, bool status); + void on_new_peer_(ESPNowPacketPtr packet); QueueHandle_t receive_queue_{}; QueueHandle_t send_queue_{}; @@ -312,25 +324,25 @@ template class DelPeerAction : public Action, public Pare TemplatableValue mac_{}; }; -class ESPNowSentTrigger : public Trigger { +class ESPNowSentTrigger : public Trigger { public: explicit ESPNowSentTrigger(ESPNowComponent *parent) { parent->get_default_protocol()->add_on_sent_callback( - [this](ESPNowPacket *packet, bool status) { this->trigger(packet, status); }); + [this](ESPNowPacketPtr packet, bool status) { this->trigger(packet, status); }); } }; -class ESPNowReceiveTrigger : public Trigger { +class ESPNowReceiveTrigger : public Trigger { public: explicit ESPNowReceiveTrigger(ESPNowComponent *parent) { - parent->get_default_protocol()->add_on_receive_callback([this](ESPNowPacket *packet) { this->trigger(packet); }); + parent->get_default_protocol()->add_on_receive_callback([this](ESPNowPacketPtr packet) { this->trigger(packet); }); } }; -class ESPNowNewPeerTrigger : public Trigger { +class ESPNowNewPeerTrigger : public Trigger { public: explicit ESPNowNewPeerTrigger(ESPNowComponent *parent) { - parent->get_default_protocol()->add_on_peer_callback([this](ESPNowPacket *packet) { this->trigger(packet); }); + parent->get_default_protocol()->add_on_peer_callback([this](ESPNowPacketPtr packet) { this->trigger(packet); }); } };