14const char* TAG =
"espnow_face";
20EspNowFace* EspNowFace::instance_ =
nullptr;
24 for (
auto& peer : peers_) {
29 for (
auto& pkt : rxQueue_) {
40 return Error::Success;
47 esp_err_t ret = esp_now_init();
49 ESP_LOGE(TAG,
"esp_now_init failed: %s", esp_err_to_name(ret));
50 return Error::SendFailed;
54 ret = esp_now_register_recv_cb(onReceive);
56 ESP_LOGE(TAG,
"esp_now_register_recv_cb failed: %s", esp_err_to_name(ret));
58 return Error::SendFailed;
61 ret = esp_now_register_send_cb(onSend);
63 ESP_LOGE(TAG,
"esp_now_register_send_cb failed: %s", esp_err_to_name(ret));
65 return Error::SendFailed;
69 esp_now_peer_info_t broadcastPeer = {};
71 broadcastPeer.channel = 0;
72 broadcastPeer.ifidx = WIFI_IF_STA;
73 broadcastPeer.encrypt =
false;
75 ret = esp_now_add_peer(&broadcastPeer);
76 if (ret != ESP_OK && ret != ESP_ERR_ESPNOW_EXIST) {
77 ESP_LOGE(TAG,
"esp_now_add_peer (broadcast) failed: %s", esp_err_to_name(ret));
79 return Error::SendFailed;
83 ESP_LOGI(TAG,
"ESP-NOW Face started (id=%u)", faceId_);
85 return Error::Success;
93 esp_now_unregister_recv_cb();
94 esp_now_unregister_send_cb();
100 ESP_LOGI(TAG,
"ESP-NOW Face stopped");
110 return Error::SendFailed;
114 return Error::BufferTooSmall;
118 const PeerInfo* peer = findPeer(destFace);
119 if (peer ==
nullptr) {
120 ESP_LOGW(TAG,
"Peer not found for faceId=%u", destFace);
121 return Error::NotFound;
125 if (!esp_now_is_peer_exist(peer->
mac)) {
126 esp_now_peer_info_t peerInfo = {};
127 std::memcpy(peerInfo.peer_addr, peer->
mac, 6);
128 peerInfo.channel = 0;
129 peerInfo.ifidx = WIFI_IF_STA;
130 peerInfo.encrypt =
false;
132 esp_err_t ret = esp_now_add_peer(&peerInfo);
133 if (ret != ESP_OK && ret != ESP_ERR_ESPNOW_EXIST) {
134 ESP_LOGE(TAG,
"esp_now_add_peer failed: %s", esp_err_to_name(ret));
135 return Error::SendFailed;
139 esp_err_t ret = esp_now_send(peer->
mac, data, len);
141 ESP_LOGE(TAG,
"esp_now_send failed: %s", esp_err_to_name(ret));
142 return Error::SendFailed;
145 return Error::Success;
150 return Error::SendFailed;
154 return Error::BufferTooSmall;
159 ESP_LOGE(TAG,
"esp_now_send (broadcast) failed: %s", esp_err_to_name(ret));
160 return Error::SendFailed;
163 return Error::Success;
168 PeerInfo* existing = findPeerByMac(mac);
169 if (existing !=
nullptr) {
175 for (
auto& peer : peers_) {
177 std::memcpy(peer.mac, mac, 6);
183 if (!esp_now_is_peer_exist(mac)) {
184 esp_now_peer_info_t peerInfo = {};
185 std::memcpy(peerInfo.peer_addr, mac, 6);
186 peerInfo.channel = 0;
187 peerInfo.ifidx = WIFI_IF_STA;
188 peerInfo.encrypt =
false;
189 esp_now_add_peer(&peerInfo);
192 ESP_LOGI(TAG,
"Peer added: %02x:%02x:%02x:%02x:%02x:%02x -> faceId=%u", mac[0], mac[1],
193 mac[2], mac[3], mac[4], mac[5], peer.faceId);
199 ESP_LOGW(TAG,
"Peer table full");
205 if (peer !=
nullptr) {
206 esp_now_del_peer(peer->
mac);
208 ESP_LOGI(TAG,
"Peer removed: faceId=%u", faceId);
213 const PeerInfo* peer = findPeer(faceId);
214 if (peer !=
nullptr) {
215 std::memcpy(mac, peer->
mac, 6);
223 for (
const auto& peer : peers_) {
232 while (rxQueueHead_ != rxQueueTail_) {
233 RxPacket& pkt = rxQueue_[rxQueueHead_];
235 handleReceive(pkt.srcMac, pkt.data, pkt.len);
238 rxQueueHead_ = (rxQueueHead_ + 1) % RX_QUEUE_SIZE;
242void EspNowFace::onReceive(
const esp_now_recv_info_t* info,
const uint8_t* data,
int len) {
243 if (instance_ ==
nullptr || len <= 0 ||
static_cast<size_t>(len) > ESPNOW_MAX_PAYLOAD) {
248 const size_t nextTail = (instance_->rxQueueTail_ + 1) % RX_QUEUE_SIZE;
249 if (nextTail != instance_->rxQueueHead_) {
250 RxPacket& pkt = instance_->rxQueue_[instance_->rxQueueTail_];
251 std::memcpy(pkt.srcMac, info->src_addr, 6);
252 std::memcpy(pkt.data, data, len);
253 pkt.len =
static_cast<size_t>(len);
255 instance_->rxQueueTail_ = nextTail;
257 ESP_LOGW(TAG,
"RX queue full, packet dropped");
261void EspNowFace::onSend(
const esp_now_send_info_t* info, esp_now_send_status_t status) {
262 if (status != ESP_NOW_SEND_SUCCESS && info !=
nullptr && info->des_addr !=
nullptr) {
263 const uint8_t* mac = info->des_addr;
264 ESP_LOGD(TAG,
"Send failed to %02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2],
265 mac[3], mac[4], mac[5]);
269void EspNowFace::handleReceive(
const uint8_t* srcMac,
const uint8_t* data,
size_t len) {
271 if (macFilterEnabled_) {
272 bool allowed =
false;
273 for (
size_t i = 0; i < macFilterCount_; ++i) {
274 if (std::memcmp(srcMac, macFilters_[i], 6) == 0) {
281 ESP_LOGD(TAG,
"Packet filtered: %02x:%02x:%02x:%02x:%02x:%02x", srcMac[0], srcMac[1],
282 srcMac[2], srcMac[3], srcMac[4], srcMac[5]);
289 if (srcFaceId == FACE_ID_INVALID) {
298 if (mac ==
nullptr) {
301 setMacFilters(
reinterpret_cast<const uint8_t(*)[6]
>(mac), 1);
312 for (
size_t i = 0; i < macFilterCount_; ++i) {
313 std::memcpy(macFilters_[i], macs[i], 6);
315 macFilterEnabled_ =
true;
317 ESP_LOGI(TAG,
"MAC filter enabled: %zu addresses", macFilterCount_);
318 for (
size_t i = 0; i < macFilterCount_; ++i) {
319 ESP_LOGI(TAG,
" [%zu] %02x:%02x:%02x:%02x:%02x:%02x", i, macFilters_[i][0],
320 macFilters_[i][1], macFilters_[i][2], macFilters_[i][3], macFilters_[i][4],
326 macFilterEnabled_ =
false;
328 ESP_LOGI(TAG,
"MAC filter disabled");
332 for (
auto& peer : peers_) {
333 if (peer.inUse && peer.faceId == faceId) {
340PeerInfo* EspNowFace::findPeerByMac(
const uint8_t* mac) {
341 for (
auto& peer : peers_) {
342 if (peer.inUse && std::memcmp(peer.mac, mac, 6) == 0) {
349const PeerInfo* EspNowFace::findPeer(FaceId faceId)
const {
350 for (
const auto& peer : peers_) {
351 if (peer.inUse && peer.faceId == faceId) {
~EspNowFace() override
Destructor.
static constexpr size_t MAX_MAC_FILTERS
Maximum number of filter MACs.
void stop() override
Stop ESP-NOW.
void setMacFilters(const uint8_t macs[][6], size_t count)
Set multiple MAC address filters.
bool getMacAddress(FaceId faceId, uint8_t *mac) const
Get MAC address from FaceId.
void clearMacFilters()
Clear MAC address filters.
Error send(const uint8_t *data, size_t len) override
Default send (broadcast)
Error start() override
Initialize and start ESP-NOW.
void processReceiveQueue()
Process receive events.
size_t peerCount() const
Get number of registered peers.
void setMacFilter(const uint8_t *mac)
Set MAC address filter (single MAC)
Error sendTo(FaceId destFace, const uint8_t *data, size_t len) override
Unicast send to a specific Face.
EspNowFace(FaceId faceId=2)
Constructor.
void removePeer(FaceId faceId)
Remove a peer.
Error broadcast(const uint8_t *data, size_t len) override
Broadcast send.
FaceId addPeer(const uint8_t *mac)
Add a peer.
void onPacketReceived(FaceId faceId, const uint8_t *data, size_t len)
Internal handler for packet reception.
TimeMs currentTimeMs()
Get current time (milliseconds)
constexpr FaceId FACE_ID_INVALID
Invalid Face ID.
uint16_t FaceId
Face identifier.
ESP-NOW Face implementation.
constexpr uint8_t BROADCAST_MAC[6]
Broadcast MAC address.
FaceId macToFaceId(const uint8_t *mac)
Generate FaceId from MAC address.
constexpr size_t ESPNOW_MAX_PAYLOAD
ESP-NOW maximum payload size (v2.0)
uint8_t mac[6]
MAC address.
uint32_t lastSeen
Last received time (ms)