1
0
mirror of https://github.com/esphome/esphome.git synced 2025-03-04 09:48:16 +00:00

- move the automations to there own header file

- split the structural data from the ESPNowPacket component
- implement getters and setters for the data structure
This commit is contained in:
NP v/d Spek 2024-09-19 15:40:13 +02:00
parent 252dca528f
commit a9f3ae9ead
3 changed files with 255 additions and 219 deletions

View File

@ -0,0 +1,57 @@
#pragma once
#include "esphome/components/esphome/esphome.h"
#include "esphome/core/automation.h"
#include "esphome/core/component.h"
namespace esphome {
namespace espnow {
template<typename... Ts> class NewPeerAction : public Action<Ts...>, public Parented<ESPNowComponent> {
public:
template<typename V> void set_mac(V mac) { this->mac_ = mac; }
void play(Ts... x) override {
auto mac = this->mac_.value(x...);
parent_->add_peer(mac);
}
protected:
TemplatableValue<uint64_t, Ts...> mac_{};
};
template<typename... Ts> class DelPeerAction : public Action<Ts...>, public Parented<ESPNowComponent> {
public:
template<typename V> void set_mac(V mac) { this->mac_ = mac; }
void play(Ts... x) override {
auto mac = this->mac_.value(x...);
parent_->del_peer(mac);
}
protected:
TemplatableValue<uint64_t, Ts...> mac_{};
};
class ESPNowSentTrigger : public Trigger<ESPNowPacket *, bool> {
public:
explicit ESPNowSentTrigger(ESPNowComponent *parent) {
parent->get_default_protocol()->add_on_sent_callback(
[this](ESPNowPacket *packet, bool status) { this->trigger(packet, status); });
}
};
class ESPNowReceiveTrigger : public Trigger<ESPNowPacket *> {
public:
explicit ESPNowReceiveTrigger(ESPNowComponent *parent) {
parent->get_default_protocol()->add_on_receive_callback([this](ESPNowPacket *packet) { this->trigger(packet); });
}
};
class ESPNowNewPeerTrigger : public Trigger<ESPNowPacket *> {
public:
explicit ESPNowNewPeerTrigger(ESPNowComponent *parent) {
parent->get_default_protocol()->add_on_peer_callback([this](ESPNowPacket *packet) { this->trigger(packet); });
}
};
}
}

View File

@ -19,6 +19,8 @@
#include "esphome/core/version.h" #include "esphome/core/version.h"
#include "esphome/core/log.h" #include "esphome/core/log.h"
#include <memory>
namespace esphome { namespace esphome {
namespace espnow { namespace espnow {
@ -57,17 +59,17 @@ struct {
/* ESPNowPacket ********************************************************************** */ /* ESPNowPacket ********************************************************************** */
ESPNowPacket::ESPNowPacket(espnow_addr_t peer, const uint8_t *data, uint8_t size, uint32_t protocol) : ESPNowPacket() { ESPNowPacket::ESPNowPacket(uint64_t peer, const uint8_t *data, uint8_t size, uint32_t protocol) : ESPNowPacket() {
this->peer(&peer); this->peer(peer);
this->is_broadcast_ = memcpr(&this->peer(), &ESPNOW_BROADCAST_ADDR, 6); this->broadcast(std::memcmp((const void *) this->peer_as_bytes(), (const void *) &ESPNOW_BROADCAST_ADDR, 6) == 0);
this->protocol(protocol); this->protocol(protocol);
this->content()->put_bytes(data, size); this->content()->put_bytes(data, size);
this->recalc(); this->calc_crc();
} }
ESPNowPacket::ESPNowPacket(espnow_addr_t *peer, const uint8_t *data, uint8_t size) : ESPNowPacket() { ESPNowPacket::ESPNowPacket(uint64_t peer, const uint8_t *data, uint8_t size) : ESPNowPacket() {
this->peer(peer); this->peer(peer);
this->content_->set_position(0); this->content_->set_position(0);
this->content_->put_bytes(data, size); this->content_->put_bytes(data, size);
@ -76,7 +78,7 @@ ESPNowPacket::ESPNowPacket(espnow_addr_t *peer, const uint8_t *data, uint8_t siz
bool ESPNowPacket::is_valid() { bool ESPNowPacket::is_valid() {
uint16_t crc = this->crc(); uint16_t crc = this->crc();
this->calc_crc(); this->calc_crc();
bool valid = (std::memcmp(this->header(), &TRANSPORT_HEADER, 3) == 0); bool valid = (memcmp((const void *) this->content_bytes(), (const void *) &TRANSPORT_HEADER, 3) == 0);
valid &= (this->protocol() != 0); valid &= (this->protocol() != 0);
valid &= (this->crc() == crc); valid &= (this->crc() == crc);
this->crc(crc); this->crc(crc);
@ -97,7 +99,7 @@ bool ESPNowProtocol::write(uint64_t mac_address, std::vector<uint8_t> &data) {
bool ESPNowProtocol::write(ESPNowPacket *packet) { bool ESPNowProtocol::write(ESPNowPacket *packet) {
packet->protocol(this->get_protocol_id()); packet->protocol(this->get_protocol_id());
packet->packet_id(this->get_next_ref_id()); packet->packet_id(this->get_next_ref_id());
packet->recalc(); packet->calc_crc();
return this->parent_->write(packet); return this->parent_->write(packet);
} }
@ -106,7 +108,7 @@ ESPNowComponent::ESPNowComponent() { global_esp_now = this; }
void ESPNowComponent::dump_config() { void ESPNowComponent::dump_config() {
ESP_LOGCONFIG(TAG, "esp_now:"); ESP_LOGCONFIG(TAG, "esp_now:");
ESP_LOGCONFIG(TAG, " MAC Address: " MACSTR, MAC2STR(ESPNOW_ADDR_SELF)); ESP_LOGCONFIG(TAG, " MAC Address: " MACSTR, MAC2STR(ESPNOW_ADDR_SELF));
ESPNowPacket *packet = new ESPNowPacket(0x112233445566, (uint8_t *) TAG, 5, 0x111111); ESPNowPacket *packet = new ESPNowPacket(0x112233445566, (uint8_t *) TAG, 6, 0xabcdef);
ESP_LOGI(TAG, "test: %s |H:%02x%02x%02x A:%02x%02x%02x %02x T:%02x C:%02x%02x S:%02d", packet->content_bytes(), ESP_LOGI(TAG, "test: %s |H:%02x%02x%02x A:%02x%02x%02x %02x T:%02x C:%02x%02x S:%02d", packet->content_bytes(),
packet->content(0), packet->content(1), packet->content(2), packet->content(3), packet->content(4), packet->content(0), packet->content(1), packet->content(2), packet->content(3), packet->content(4),
packet->content(5), packet->content(6), packet->content(7), packet->content(8), packet->content(9), packet->content(5), packet->content(6), packet->content(7), packet->content(8), packet->content(9),
@ -178,21 +180,21 @@ void ESPNowComponent::setup() {
return; return;
} }
esp_wifi_get_mac(WIFI_IF_STA, ESPNOW_ADDR_SELF); esp_wifi_get_mac(WIFI_IF_STA, (uint8_t *) &ESPNOW_ADDR_SELF);
for (auto &address : this->peers_) { for (auto &address : this->peers_) {
ESP_LOGI(TAG, "Add peer 0x%s .", format_hex(address).c_str()); ESP_LOGI(TAG, "Add peer 0x%12x.", address);
add_peer(address); add_peer(address);
} }
this->send_queue_ = xQueueCreate(SEND_BUFFER_SIZE, sizeof(ESPNowPacket)); this->send_queue_ = xQueueCreate(SEND_BUFFER_SIZE, sizeof(ESPNowData));
if (this->send_queue_ == nullptr) { if (this->send_queue_ == nullptr) {
ESP_LOGE(TAG, "Failed to create send queue"); ESP_LOGE(TAG, "Failed to create send queue");
this->mark_failed(); this->mark_failed();
return; return;
} }
this->receive_queue_ = xQueueCreate(SEND_BUFFER_SIZE, sizeof(ESPNowPacket)); this->receive_queue_ = xQueueCreate(SEND_BUFFER_SIZE, sizeof(ESPNowData));
if (this->receive_queue_ == nullptr) { if (this->receive_queue_ == nullptr) {
ESP_LOGE(TAG, "Failed to create receive queue"); ESP_LOGE(TAG, "Failed to create receive queue");
this->mark_failed(); this->mark_failed();
@ -209,7 +211,6 @@ esp_err_t ESPNowComponent::add_peer(uint64_t addr) {
this->peers_.push_back(addr); this->peers_.push_back(addr);
return ESP_OK; return ESP_OK;
} else { } else {
uint8_t mac[6];
this->del_peer(addr); this->del_peer(addr);
esp_now_peer_info_t peer_info = {}; esp_now_peer_info_t peer_info = {};
@ -245,6 +246,7 @@ ESPNowProtocol *ESPNowComponent::get_protocol_(uint32_t protocol) {
} }
return this->protocols_[protocol]; return this->protocols_[protocol];
} }
void ESPNowComponent::on_receive_(ESPNowPacket *packet) { void ESPNowComponent::on_receive_(ESPNowPacket *packet) {
ESPNowProtocol *protocol = this->get_protocol_(packet->protocol()); ESPNowProtocol *protocol = this->get_protocol_(packet->protocol());
if (protocol != nullptr) { if (protocol != nullptr) {
@ -273,27 +275,27 @@ void ESPNowComponent::on_data_received(const esp_now_recv_info_t *recv_info, con
void ESPNowComponent::on_data_received(const uint8_t *addr, const uint8_t *data, int size) void ESPNowComponent::on_data_received(const uint8_t *addr, const uint8_t *data, int size)
#endif #endif
{ {
ESPNowPacket *packet = new ESPNowPacket(espnow_addr_t(*addr), data, size); ESPNowPacket packet((uint64_t) *addr, data, size);
wifi_pkt_rx_ctrl_t *rx_ctrl = nullptr; wifi_pkt_rx_ctrl_t *rx_ctrl = nullptr;
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 1) #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 1)
uint8_t *addr = recv_info->src_addr; uint8_t *addr = recv_info->src_addr;
packet->broadcast(*recv_info->des_addr == ESPNOW_BROADCAST_ADDR); packet.broadcast(*recv_info->des_addr == ESPNOW_BROADCAST_ADDR);
rx_ctrl = recv_info->rx_ctrl; rx_ctrl = recv_info->rx_ctrl;
#else #else
wifi_promiscuous_pkt_t *promiscuous_pkt = wifi_promiscuous_pkt_t *promiscuous_pkt =
(wifi_promiscuous_pkt_t *) (data - sizeof(wifi_pkt_rx_ctrl_t) - sizeof(espnow_frame_format_t)); (wifi_promiscuous_pkt_t *) (data - sizeof(wifi_pkt_rx_ctrl_t) - sizeof(espnow_frame_format_t));
rx_ctrl = &promiscuous_pkt->rx_ctrl; rx_ctrl = &promiscuous_pkt->rx_ctrl;
#endif #endif
packet->rssi(rx_ctrl->rssi); packet.rssi(rx_ctrl->rssi);
packet->timestamp(rx_ctrl->timestamp); packet.timestamp(rx_ctrl->timestamp);
ESP_LOGVV(TAG, "Read: %s |H:%02x%02x%02x A:%02x%02x%02x %02x T:%02x C:%02x%02x S:%02d", packet->content_bytes(), ESP_LOGVV(TAG, "Read: %s |H:%02x%02x%02x A:%02x%02x%02x %02x T:%02x C:%02x%02x S:%02d", packet.content_bytes(),
packet->content(0), packet->content(1), packet->content(2), packet->content(3), packet->content(4), packet.content(0), packet.content(1), packet.content(2), packet.content(3), packet.content(4),
packet->content(5), packet->content(6), packet->content(7), packet->content(8), packet->content(9), packet.content(5), packet.content(6), packet.content(7), packet.content(8), packet.content(9),
packet->size); packet.size());
if (packet->is_valid()) { if (packet.is_valid()) {
xQueueSendToBack(global_esp_now->receive_queue_, packet, 10); xQueueSendToBack(global_esp_now->receive_queue_, packet.retrieve(), 10);
} else { } else {
ESP_LOGE(TAG, "Invalid ESP-NOW packet received (CRC)"); ESP_LOGE(TAG, "Invalid ESP-NOW packet received (CRC)");
} }
@ -303,25 +305,24 @@ bool ESPNowComponent::write(ESPNowPacket *packet) {
ESP_LOGVV(TAG, "Write: %s |H:%02x%02x%02x A:%02x%02x%02x %02x T:%02x C:%02x%02x S:%02d", packet->content_bytes(), ESP_LOGVV(TAG, "Write: %s |H:%02x%02x%02x A:%02x%02x%02x %02x T:%02x C:%02x%02x S:%02d", packet->content_bytes(),
packet->content(0), packet->content(1), packet->content(2), packet->content(3), packet->content(4), packet->content(0), packet->content(1), packet->content(2), packet->content(3), packet->content(4),
packet->content(5), packet->content(6), packet->content(7), packet->content(8), packet->content(9), packet->content(5), packet->content(6), packet->content(7), packet->content(8), packet->content(9),
packet->size); packet->size());
espnow_addr_t *mac; uint8_t *mac = packet->peer_as_bytes();
mac = packet->peer();
if (this->is_failed()) { if (this->is_failed()) {
ESP_LOGE(TAG, "Cannot send espnow packet, espnow failed to setup"); ESP_LOGE(TAG, "Cannot send espnow packet, espnow failed to setup");
} else if (this->send_queue_full()) { } else if (this->send_queue_full()) {
ESP_LOGE(TAG, "Send Buffer Out of Memory."); ESP_LOGE(TAG, "Send Buffer Out of Memory.");
} else if (!esp_now_is_peer_exist((uint8_t *) mac)) { } else if (!esp_now_is_peer_exist(mac)) {
ESP_LOGW(TAG, "Peer not registered: 0x%12x.", (uint64_t) *mac); ESP_LOGW(TAG, "Peer not registered: 0x%12x.", packet->peer());
} else if (!packet->is_valid()) { } else if (!packet->is_valid()) {
ESP_LOGW(TAG, "Packet is invalid. maybe you need to ::recalc(). the packat before writing."); ESP_LOGW(TAG, "Packet is invalid. maybe you need to ::calc_crc(). the packat before writing.");
} else if (this->use_sent_check_) { } else if (this->use_sent_check_) {
xQueueSendToBack(this->send_queue_, packet, 10); xQueueSendToBack(this->send_queue_, packet->retrieve(), 10);
ESP_LOGVV(TAG, "Send (0x%04x.%d): 0x%s. Buffer Used: %d", packet->packet_id, packet->retrys(), ESP_LOGVV(TAG, "Send (0x%04x.%d): 0x%12x. Buffer Used: %d", packet->packet_id, packet->attempts(), packet->peer(),
format_hex(packet->peer()).c_str(), this->send_queue_used()); this->send_queue_used());
return true; return true;
} else { } else {
esp_err_t err = esp_now_send((uint8_t *) &mac, packet->content_bytes(), packet->size()); esp_err_t err = esp_now_send((uint8_t *) &mac, packet->content_bytes(), packet->size());
ESP_LOGVV(TAG, "S: 0x%04x.%d B: %d%s.", packet->packet_id(), packet->retrys(), this->send_queue_used(), ESP_LOGVV(TAG, "S: 0x%04x.%d B: %d%s.", packet->packet_id(), packet->attempts(), this->send_queue_used(),
(err == ESP_OK) ? "" : " FAILED"); (err == ESP_OK) ? "" : " FAILED");
this->defer([this, packet, err]() { this->on_sent_(packet, err == ESP_OK); }); this->defer([this, packet, err]() { this->on_sent_(packet, err == ESP_OK); });
} }
@ -333,90 +334,90 @@ void ESPNowComponent::loop() {
} }
void ESPNowComponent::runner() { void ESPNowComponent::runner() {
ESPNowPacket *packet; ESPNowPacket *packet = new ESPNowPacket();
ESPNowData data;
for (;;) { for (;;) {
if (xQueueReceive(this->receive_queue_, packet, (TickType_t) 1) == pdTRUE) { if (xQueueReceive(this->receive_queue_, &data, (TickType_t) 1) == pdTRUE) {
espnow_addr_t *mac; packet->store(data);
mac = packet->peer(); uint8_t *mac = packet->peer_as_bytes();
if (!esp_now_is_peer_exist((uint8_t *) mac)) { if (!esp_now_is_peer_exist(mac)) {
if (this->auto_add_peer_) { if (!this->auto_add_peer_) {
this->add_peer(mac); this->defer([this, packet, mac]() { this->on_new_peer_((ESPNowPacket *) &packet); });
} else { } else {
this->defer([this, packet]() { this->on_new_peer_(packet); }); this->add_peer(packet->peer());
continue;
} }
} }
if (esp_now_is_peer_exist((uint8_t *) &mac)) { this->defer([this, packet]() { this->on_receive_((ESPNowPacket *) &packet); });
this->defer([this, packet]() { this->on_receive_(packet); });
} else {
ESP_LOGE(TAG, "Peer not registered: %s", format_hex(packet->mac64).c_str());
}
} }
if (xQueueReceive(this->send_queue_, &packet, (TickType_t) 1) == pdTRUE) { if (xQueueReceive(this->send_queue_, &data, (TickType_t) 1) == pdTRUE) {
if (this->is_locked()) { packet->store(data);
if (millis() - packet->timestamp > 1000) {
if (packet->retrys() == 6) { if (packet->attempts() > MAX_NUMBER_OF_RETRYS) {
ESP_LOGW(TAG, "To many send retries. Packet dropped. 0x%04x", packet->packet_id()); ESP_LOGW(TAG, "To many send retries. Packet dropped. 0x%04x", packet->packet_id());
this->unlock(); this->unlock();
continue; continue;
} else { } else if (this->is_locked()) {
ESP_LOGE(TAG, "TimeOut (0x%04x.%d).", packet->packet_id(), packet->retrys()); if (millis() - packet->timestamp() > 1000) {
packet->retry(); ESP_LOGE(TAG, "TimeOut (0x%04x.%d).", packet->packet_id(), packet->attempts());
} packet->retry();
this->unlock(); this->unlock();
} }
} else { } else {
this->lock();
packet->retry(); packet->retry();
if (packet->retrys() == 6) { packet->timestamp(millis());
ESP_LOGW(TAG, "To many send retries. Packet dropped. 0x%04x", packet->packet_id()); uint8_t *mac = packet->peer_as_bytes();
// continue;
return; esp_err_t err = esp_now_send(mac, packet->content_bytes(), packet->size());
if (err == ESP_OK) {
ESP_LOGV(TAG, "S: 0x%04x.%d. Wait for conformation. M: %s", packet->packet_id(), packet->attempts(),
packet->content_bytes());
} else { } else {
packet->timestamp = millis(); ESP_LOGE(TAG, "S: 0x%04x.%d B: %d.", packet->packet_id(), packet->attempts(), this.send_queue_used());
this->lock(); this->unlock();
espnow_addr_t mac;
packet->get_mac(&mac);
esp_err_t err = esp_now_send((uint8_t *) &mac, packet->data, packet->size + 10);
if (err == ESP_OK) {
ESP_LOGV(TAG, "S: 0x%04x.%d. Wait for conformation. M: %s", packet->packet_id(), packet->retrys(),
packet->to_str().c_str());
} else {
ESP_LOGE(TAG, "S: 0x%04x.%d B: %d.", packet->packet_id(), packet->retrys(), this->send_queue_used());
this->unlock();
}
} }
} }
xQueueSendToFront(this->send_queue_, &packet, 10 / portTICK_PERIOD_MS); xQueueSendToFront(this->send_queue_, packet->retrieve(), 10 / portTICK_PERIOD_MS);
} }
} }
} }
void ESPNowComponent::on_data_sent(const uint8_t *mac_addr, esp_now_send_status_t status) { void ESPNowComponent::on_data_sent(const uint8_t *mac_addr, esp_now_send_status_t status) {
ESPNowPacket *packet; ESPNowPacket *packet = new ESPNowPacket();
ESPNowData data;
if (!global_esp_now->use_sent_check_) { if (!global_esp_now->use_sent_check_) {
return; return;
} }
uint64_t mac64 = packet->to_mac64((espnow_addr_t *) mac_addr); uint64_t mac64 = (uint64_t) *mac_addr;
if (xQueueReceive(global_esp_now->send_queue_, &packet, 10 / portTICK_PERIOD_MS) == pdTRUE) { if (xQueuePeek(global_esp_now->send_queue_, &data, 10 / portTICK_PERIOD_MS) == pdTRUE) {
packet->store(data);
if (status != ESP_OK) { if (status != ESP_OK) {
ESP_LOGE(TAG, "sent packet failed (0x%04x.%d)", packet->packet_id(), packet->retrys()); ESP_LOGE(TAG, "sent packet failed (0x%04x.%d)", packet->packet_id(), packet->attempts());
} else if (packet->mac64 != mac64) { } else if (packet->peer() != mac64) {
ESP_LOGE(TAG, " Invalid mac address. (0x%04x.%d) expected: %s got %s", packet->packet_id(), packet->retrys, ESP_LOGE(TAG, " Invalid mac address. (0x%04x.%d) expected: 0x%12x got: 0x%12x", packet->packet_id(),
packet->to_str().c_str(), packet->to_str(mac64).c_str()); packet->retrys, packet->peer(), mac64);
} else { } else {
ESP_LOGV(TAG, "Confirm sent (0x%04x.%d)", packet->packet_id(), packet->retrys()); ESP_LOGV(TAG, "Confirm sent (0x%04x.%d)", packet->packet_id(), packet->attempts());
global_esp_now->unlock(); global_esp_now->defer([packet]() {
global_esp_now->defer([packet]() { global_esp_now->on_sent_(packet, true); }); global_esp_now->on_sent_((ESPNowPacket *) &packet, true);
ESPNowData data;
xQueueReceive(global_esp_now->send_queue_, &data, 10 / portTICK_PERIOD_MS);
global_esp_now->unlock();
});
return; return;
} }
global_esp_now->defer([packet]() { global_esp_now->on_sent_(packet, false); }); global_esp_now->defer([packet]() {
xQueueSendToFront(global_esp_now->send_queue_, &packet, 10 / portTICK_PERIOD_MS); global_esp_now->on_sent_((ESPNowPacket *) &packet, false);
ESPNowData data;
xQueueReceive(global_esp_now->send_queue_, &data, 10 / portTICK_PERIOD_MS);
uint8_t *xyz = packet->retrieve();
xQueueSendToFront(global_esp_now->send_queue_, xyz, 10 / portTICK_PERIOD_MS);
global_esp_now->unlock();
});
} }
global_esp_now->unlock();
} }
ESPNowComponent *global_esp_now = nullptr; ESPNowComponent *global_esp_now = nullptr;

View File

@ -22,8 +22,9 @@ namespace espnow {
typedef uint8_t espnow_addr_t[6]; typedef uint8_t espnow_addr_t[6];
static const espnow_addr_t ESPNOW_BROADCAST_ADDR = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; static const uint64_t ESPNOW_BROADCAST_ADDR = 0xFFFFFFFFFFFF;
static espnow_addr_t ESPNOW_ADDR_SELF = {0};
static uint64_t ESPNOW_ADDR_SELF = {0};
static const uint8_t ESPNOW_DATA_HEADER = 0x00; static const uint8_t ESPNOW_DATA_HEADER = 0x00;
static const uint8_t ESPNOW_DATA_PROTOCOL = 0x03; static const uint8_t ESPNOW_DATA_PROTOCOL = 0x03;
@ -33,112 +34,135 @@ static const uint8_t ESPNOW_DATA_CONTENT = 0x0A;
static const uint8_t MAX_ESPNOW_DATA_SIZE = 240; static const uint8_t MAX_ESPNOW_DATA_SIZE = 240;
static const uint8_t MAX_NUMBER_OF_RETRYS = 5;
static const uint32_t TRANSPORT_HEADER = 0xC19983; static const uint32_t TRANSPORT_HEADER = 0xC19983;
static const uint32_t ESPNOW_DEFAULT_APP_ID = 0x11CFAF;
static uint8_t last_ref_id = 0; static uint8_t last_ref_id = 0;
struct ESPNowData {
union {
struct {
uint64_t peer{0};
uint8_t rssi{0};
uint8_t attempts{0};
bool is_broadcast{false};
uint32_t timestamp{0};
uint8_t size{0};
uint8_t content[251]{0};
};
uint8_t bytes[251 + 16];
};
};
class ESPNowPacket { class ESPNowPacket {
private:
espnow_addr_t peer_{0};
uint8_t rssi_{0};
uint8_t retrys_{0};
bool is_broadcast_{false};
uint32_t timestamp_{0};
ByteBuffer *content_;
public: public:
ESPNowPacket() { ESPNowPacket() {
memset((void *) &(this->data_.bytes), 0, sizeof(this->data_));
this->content_ = new ByteBuffer(251); this->content_ = new ByteBuffer(251);
this->content_->put_uint24(TRANSPORT_HEADER); this->content_->put_uint24(TRANSPORT_HEADER);
}; };
// Create packet to be send. // Create packet to be send.
ESPNowPacket(espnow_addr_t peer, const uint8_t *data, uint8_t size, uint32_t app_id); ESPNowPacket(uint64_t peer, const uint8_t *data, uint8_t size, uint32_t app_id);
// Load received packet's. // Load received packet's.
ESPNowPacket(espnow_addr_t *peer, const uint8_t *data, uint8_t size); ESPNowPacket(uint64_t peer, const uint8_t *data, uint8_t size);
espnow_addr_t *peer() { return &this->peer_; } ESPNowPacket(ESPNowData data) : ESPNowPacket() { this->store(data); }
void peer(espnow_addr_t *peer) {
if (*peer[0] == 0) { void store(ESPNowData data) {
std::memcpy(&this->peer_, &ESPNOW_BROADCAST_ADDR, 6); memcpy((void *) &(this->data_.bytes), (void *) &(data.bytes), sizeof(ESPNowData));
this->content_->clear();
this->content_->put_bytes((uint8_t *) &(data.content), data.size);
}
uint8_t *retrieve() {
memcpy((void *) &(this->data_.content), this->content_bytes(), this->size());
this->data_.size = this->size();
return (uint8_t *) &(this->data_.bytes);
}
uint64_t peer() { return this->data_.peer; }
uint8_t *peer_as_bytes() { return (uint8_t *) &(this->data_.peer); }
void peer(uint64_t peer) {
if (peer == 0) {
this->data_.peer = ESPNOW_BROADCAST_ADDR;
} else {
this->data_.peer = peer;
} }
} }
else {
std::memcpy(&this->peer_, &peer, 6); bool broadcast() { return this->data_.is_broadcast; };
void broadcast(bool state) { this->data_.is_broadcast = state; }
uint32_t timestamp() { return this->data_.timestamp; };
void timestamp(uint32_t timestamp) { this->data_.timestamp = timestamp; };
uint8_t rssi() { return this->data_.rssi; }
void rssi(uint8_t rssi) { this->data_.rssi = rssi; }
uint8_t size() {
if (this->content_->get_used_space() <= ESPNOW_DATA_CONTENT) {
return ESPNOW_DATA_CONTENT;
}
return this->content_->get_used_space();
} }
}
uint8_t uint32_t protocol() {
size() { this->content_->set_position(ESPNOW_DATA_PROTOCOL);
if (this->content_->get_used() <= ESPNOW_DATA_CONTENT) { return this->content_->get_uint24();
return ESPNOW_DATA_CONTENT;
} }
return this->content_->get_used(); void protocol(uint32_t protocol) {
} this->content_->set_position(ESPNOW_DATA_PROTOCOL);
this->content_->put_uint24(protocol);
bool broadcast(){return this->is_broadcast_};
void broadcast(bool state) { this->is_broadcast_ = state; }
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);
}
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);
}
ByteBuffer *content() {
this->content_->set_position(this->size());
return &this->content_;
}
uint8_t content(uint8_t pos) {
this->content_->set_position(pos);
return this->content_->get_uint8();
}
uint8_t *content_bytes() { return this->content_->get_data()->data(); };
void retry() {
if (this->retrys_ < 7) {
this->retrys_ = this->retrys_ + 1;
} }
}
void calc_crc() { uint8_t packet_id() {
this->crc(0); this->content_->set_position(ESPNOW_DATA_PACKET);
this->crc(esp_crc16_le(this->packet(), this->dataptr(), this->size())); 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);
}
bool is_valid(); 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(this->size());
return this->content_;
}
uint8_t content(uint8_t pos) {
this->content_->set_position(pos);
return this->content_->get_uint8();
}
uint8_t *content_bytes() { return this->content_->get_data().data(); };
void retry() { this->data_.attempts++; }
uint8_t attempts() { return this->data_.attempts; }
void calc_crc() {
this->crc(0);
this->crc(esp_crc16_le(this->packet_id(), this->content_bytes(), this->size()));
}
bool is_valid();
private:
ByteBuffer *content_{nullptr};
ESPNowData data_;
}; };
class ESPNowComponent; class ESPNowComponent;
static const uint32_t ESPNOW_DEFAULT_APP_ID = 0x11CFAF;
class ESPNowProtocol : public Parented<ESPNowComponent> { class ESPNowProtocol : public Parented<ESPNowComponent> {
public: public:
ESPNowProtocol(){}; ESPNowProtocol(){};
@ -150,8 +174,8 @@ class ESPNowProtocol : public Parented<ESPNowComponent> {
virtual uint32_t get_protocol_id() = 0; virtual uint32_t get_protocol_id() = 0;
uint8_t get_next_ref_id() { return next_ref_id_++; } uint8_t get_next_ref_id() { return next_ref_id_++; }
bool write(uint64_t mac_address, const uint8_t *data, uint8_t len); bool write(uint64_t peer, const uint8_t *data, uint8_t len);
bool write(uint64_t mac_address, std::vector<uint8_t> &data); bool write(uint64_t peer, std::vector<uint8_t> &data);
bool write(ESPNowPacket *packet); bool write(ESPNowPacket *packet);
protected: protected:
@ -281,52 +305,6 @@ template<typename... Ts> class SendAction : public Action<Ts...>, public Parente
std::vector<uint8_t> data_static_{}; std::vector<uint8_t> data_static_{};
}; };
template<typename... Ts> class NewPeerAction : public Action<Ts...>, public Parented<ESPNowComponent> {
public:
template<typename V> void set_mac(V mac) { this->mac_ = mac; }
void play(Ts... x) override {
auto mac = this->mac_.value(x...);
parent_->add_peer(mac);
}
protected:
TemplatableValue<uint64_t, Ts...> mac_{};
};
template<typename... Ts> class DelPeerAction : public Action<Ts...>, public Parented<ESPNowComponent> {
public:
template<typename V> void set_mac(V mac) { this->mac_ = mac; }
void play(Ts... x) override {
auto mac = this->mac_.value(x...);
parent_->del_peer(mac);
}
protected:
TemplatableValue<uint64_t, Ts...> mac_{};
};
class ESPNowSentTrigger : public Trigger<ESPNowPacket *, bool> {
public:
explicit ESPNowSentTrigger(ESPNowComponent *parent) {
parent->get_default_protocol()->add_on_sent_callback(
[this](ESPNowPacket *packet, bool status) { this->trigger(packet, status); });
}
};
class ESPNowReceiveTrigger : public Trigger<ESPNowPacket *> {
public:
explicit ESPNowReceiveTrigger(ESPNowComponent *parent) {
parent->get_default_protocol()->add_on_receive_callback([this](ESPNowPacket *packet) { this->trigger(packet); });
}
};
class ESPNowNewPeerTrigger : public Trigger<ESPNowPacket *> {
public:
explicit ESPNowNewPeerTrigger(ESPNowComponent *parent) {
parent->get_default_protocol()->add_on_peer_callback([this](ESPNowPacket *packet) { this->trigger(packet); });
}
};
extern ESPNowComponent *global_esp_now; extern ESPNowComponent *global_esp_now;
} // namespace espnow } // namespace espnow