6#include "AudioTools/Concurrency/RTOS.h"
7#include "AudioTools/CoreAudio/AudioBasic/StrView.h"
8#include "AudioTools/CoreAudio/BaseStream.h"
14static ESPNowStream* ESPNowStreamSelf =
nullptr;
15static const char* BROADCAST_MAC_STR =
"FF:FF:FF:FF:FF:FF";
16static const uint8_t BROADCAST_MAC[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
24 wifi_mode_t wifi_mode = WIFI_STA;
25 const char* mac_address =
nullptr;
26 uint16_t buffer_size = ESP_NOW_MAX_DATA_LEN;
27 uint16_t buffer_count = 400;
29 const char* ssid =
nullptr;
30 const char* password =
nullptr;
31 bool use_send_ack =
true;
32 uint16_t delay_after_failed_write_ms = 2000;
33 int write_retry_count = 1;
34#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
35 void (*recveive_cb)(
const esp_now_recv_info* info,
const uint8_t* data,
36 int data_len) =
nullptr;
38 void (*recveive_cb)(
const uint8_t* mac_addr,
const uint8_t* data,
39 int data_len) =
nullptr;
43 const char* local_master_key =
nullptr;
45 wifi_phy_rate_t
rate = WIFI_PHY_RATE_2M_S;
48 uint32_t ack_semaphore_timeout_ms = portMAX_DELAY;
65 if (xSemaphore !=
nullptr) vSemaphoreDelete(xSemaphore);
75 static String mac_str = WiFi.macAddress();
76 return mac_str.c_str();
92 WiFi.mode(cfg.wifi_mode);
94 if (cfg.mac_address !=
nullptr) {
95 LOGI(
"setting mac %s", cfg.mac_address);
96 byte mac[ESP_NOW_KEY_LEN];
97 str2mac(cfg.mac_address, mac);
98 if (esp_wifi_set_mac((wifi_interface_t)getInterface(), mac) != ESP_OK) {
99 LOGE(
"Could not set mac address");
106 if (strcmp(addr, cfg.mac_address) != 0) {
107 LOGE(
"Wrong mac address: %s", addr);
112 if (WiFi.status() != WL_CONNECTED && cfg.ssid !=
nullptr &&
113 cfg.password !=
nullptr) {
114 WiFi.begin(cfg.ssid, cfg.password);
115 while (WiFi.status() != WL_CONNECTED) {
121#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
122 LOGI(
"Setting ESP-NEW rate");
123 if (esp_wifi_config_espnow_rate(getInterface(), cfg.
rate) != ESP_OK) {
124 LOGW(
"Could not set rate");
129 Serial.print(
"mac: ");
130 Serial.println(WiFi.macAddress());
137 if (esp_now_deinit() != ESP_OK) {
138 LOGE(
"esp_now_deinit");
140 if (buffer.size() > 0) buffer.
resize(0);
144 is_broadcast =
false;
151 LOGE(
"addPeer before begin");
154 if (memcmp(BROADCAST_MAC, peer.peer_addr, 6) == 0) {
155 LOGI(
"Using broadcast");
158 esp_err_t result = esp_now_add_peer(&peer);
159 if (result == ESP_OK) {
160 LOGI(
"addPeer: %s", mac2str(peer.peer_addr));
163 LOGE(
"addPeer: %d", result);
165 return result == ESP_OK;
169 template <
size_t size>
172 for (
int j = 0; j < size; j++) {
173 const char* peer = array[j];
174 if (peer !=
nullptr) {
185 esp_now_peer_info_t peer;
186 peer.channel = cfg.channel;
188 peer.ifidx = getInterface();
189 peer.encrypt =
false;
191 if (
StrView(address).equals(cfg.mac_address)) {
192 LOGW(
"Did not add own address as peer");
198 strncpy((
char*)peer.lmk, cfg.local_master_key, 16);
201 if (!str2mac(address, peer.peer_addr)) {
202 LOGE(
"addPeer - Invalid address: %s", address);
211 if (cfg.use_send_ack) {
212 LOGW(
"Broadcast peer does not support use_send_ack");
213 cfg.use_send_ack =
false;
215 return addPeer(BROADCAST_MAC_STR);
219 size_t write(
const uint8_t* data,
size_t len)
override {
221 return write((
const uint8_t*)
nullptr, data, len);
225 size_t write(
const char* peer,
const uint8_t* data,
size_t len) {
227 if (!str2mac(peer, mac)) {
228 LOGE(
"write: invalid mac address %s", peer);
231 return write(mac, data, len);
235 size_t write(
const uint8_t* peer,
const uint8_t* data,
size_t len) {
240 if (!has_peers && peer ==
nullptr) {
244 size_t total_sent = 0;
245 size_t remaining = len;
247 while (remaining > 0) {
248 size_t chunk_size = min(remaining, (
size_t)ESP_NOW_MAX_DATA_LEN);
252 sendPacket(data + total_sent, chunk_size, retry_count, peer);
256 total_sent += chunk_size;
257 remaining -= chunk_size;
261 "write: failed to send chunk after %d attempts (sent %zu/%zu "
263 retry_count, total_sent, len);
274 if (!read_ready)
return 0;
275 if (buffer.size() == 0)
return 0;
279 int available()
override {
280 if (!buffer)
return 0;
281 if (!read_ready)
return 0;
282 return buffer.size() == 0 ? 0 : buffer.
available();
285 int availableForWrite()
override {
286 if (!buffer)
return 0;
287 return cfg.use_send_ack ? available_to_write : cfg.buffer_size;
292 int size = buffer.size();
294 if (size == 0)
return 0.0;
296 return 100.0 * buffer.
available() / size;
308 esp_now_recv_cb_t receive = default_recv_cb;
309 esp_now_send_cb_t send = default_send_cb;
310 volatile size_t available_to_write = 0;
311 volatile bool last_send_success =
true;
312 bool is_init =
false;
313 SemaphoreHandle_t xSemaphore =
nullptr;
314 bool has_peers =
false;
315 bool read_ready =
false;
316 bool is_broadcast =
false;
317 uint32_t last_io_success_time = 0;
319 inline void setupSemaphore() {
321 if (cfg.use_send_ack && xSemaphore ==
nullptr) {
322 xSemaphore = xSemaphoreCreateBinary();
323 xSemaphoreGive(xSemaphore);
327 inline void setupReceiveBuffer() {
330 LOGI(
"setupReceiveBuffer: %d", cfg.buffer_size * cfg.buffer_count);
331 buffer.
resize(cfg.buffer_size * cfg.buffer_count);
335 inline void resetAvailableToWrite() {
336 if (cfg.use_send_ack) {
337 available_to_write = 0;
342 bool sendPacket(
const uint8_t* data,
size_t len,
int& retry_count,
343 const uint8_t* destination =
nullptr) {
345 const uint8_t* target = destination;
346 if (target ==
nullptr && is_broadcast) {
347 target = BROADCAST_MAC;
351 resetAvailableToWrite();
354 if (cfg.use_send_ack) {
355 TickType_t ticks = (cfg.ack_semaphore_timeout_ms == portMAX_DELAY)
357 : pdMS_TO_TICKS(cfg.ack_semaphore_timeout_ms);
358 if (xSemaphoreTake(xSemaphore, ticks) != pdTRUE) {
361 if (cfg.write_retry_count >= 0 &&
362 retry_count >= cfg.write_retry_count) {
363 LOGE(
"Timeout waiting for ACK semaphore after %d retries",
368 LOGW(
"ACK semaphore timeout (attempt %d)", retry_count);
369 delay(cfg.delay_after_failed_write_ms);
375 esp_err_t rc = esp_now_send(target, data, len);
385 if (cfg.write_retry_count >= 0 &&
386 retry_count >= cfg.write_retry_count) {
392 if (cfg.use_send_ack) {
393 xSemaphoreGive(xSemaphore);
397 if (cfg.write_retry_count >= 0 &&
398 retry_count >= cfg.write_retry_count) {
399 LOGE(
"esp_now_send queue error (rc=%d/0x%04X) after %d retries", rc,
405 LOGW(
"esp_now_send failed (rc=%d/0x%04X) - retrying (attempt %d)", rc,
407 delay(cfg.delay_after_failed_write_ms);
415 if (cfg.use_send_ack) {
417 TickType_t ticks = (cfg.ack_semaphore_timeout_ms == portMAX_DELAY)
419 : pdMS_TO_TICKS(cfg.ack_semaphore_timeout_ms);
420 if (xSemaphoreTake(xSemaphore, ticks) != pdTRUE) {
422 if (cfg.write_retry_count >= 0 &&
423 retry_count >= cfg.write_retry_count) {
424 LOGE(
"Transmission callback timeout after %d retries", retry_count);
428 LOGW(
"Transmission callback timeout (attempt %d)", retry_count);
429 delay(cfg.delay_after_failed_write_ms);
434 if (last_send_success) {
435 xSemaphoreGive(xSemaphore);
438 xSemaphoreGive(xSemaphore);
441 if (cfg.write_retry_count >= 0 &&
442 retry_count >= cfg.write_retry_count) {
443 LOGE(
"Transmission failed after %d retries", retry_count);
448 LOGI(
"Transmission failed - retrying (attempt %d)", retry_count);
449 delay(cfg.delay_after_failed_write_ms);
461 if (cfg.use_send_ack) {
462 xSemaphoreGive(xSemaphore);
466 LOGW(
"esp_now_send failed to queue (rc=%d/0x%04X) - retrying (attempt %d)",
467 rc, rc, retry_count);
469 if (cfg.write_retry_count >= 0 && retry_count > cfg.write_retry_count) {
470 LOGE(
"Send queue error after %d retries", retry_count);
474 delay(cfg.delay_after_failed_write_ms);
482 wifi_interface_t getInterface() {
484 wifi_interface_t result;
485 switch (cfg.wifi_mode) {
487 result = (wifi_interface_t)ESP_IF_WIFI_STA;
490 result = (wifi_interface_t)ESP_IF_WIFI_AP;
493 result = (wifi_interface_t)0;
501 esp_err_t result = esp_now_init();
502 if (result == ESP_OK) {
505 LOGE(
"esp_now_init: %d", result);
513 if (cfg.recveive_cb !=
nullptr) {
514 esp_now_register_recv_cb(cfg.recveive_cb);
516 esp_now_register_recv_cb(receive);
518 if (cfg.use_send_ack) {
519 esp_now_register_send_cb(send);
521 available_to_write = cfg.buffer_size;
522 is_init = result == ESP_OK;
526 bool str2mac(
const char* mac, uint8_t* values) {
527 sscanf(mac,
"%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &values[0], &values[1],
528 &values[2], &values[3], &values[4], &values[5]);
529 return strlen(mac) == 17;
532 const char* mac2str(
const uint8_t* array) {
533 static char macStr[18];
534 memset(macStr, 0, 18);
535 snprintf(macStr, 18,
"%02x:%02x:%02x:%02x:%02x:%02x", array[0], array[1],
536 array[2], array[3], array[4], array[5]);
537 return (
const char*)macStr;
540 static int bufferAvailableForWrite() {
544#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
545 static void default_recv_cb(
const esp_now_recv_info* info,
546 const uint8_t* data,
int data_len)
548 static void default_recv_cb(
const uint8_t* mac_addr,
const uint8_t* data,
552 LOGD(
"rec_cb: %d", data_len);
555 ESPNowStreamSelf->setupReceiveBuffer();
558 ESPNowStreamSelf->last_io_success_time =
millis();
561 size_t result = ESPNowStreamSelf->buffer.
writeArray(data, data_len);
562 if (result != data_len) {
563 LOGE(
"writeArray %d -> %d", data_len, result);
566 if (ESPNowStreamSelf->read_ready ==
false) {
568 ESPNowStreamSelf->read_ready =
true;
571 ESPNowStreamSelf->read_ready =
577#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 5, 0)
579 static void default_send_cb(
const wifi_tx_info_t* tx_info,
580 esp_now_send_status_t status) {
581 const uint8_t* mac_addr = tx_info->des_addr;
583 static void default_send_cb(
const uint8_t* mac_addr,
584 esp_now_send_status_t status) {
586 static uint8_t first_mac[ESP_NOW_KEY_LEN] = {0};
589 if (first_mac[0] == 0) {
590 strncpy((
char*)first_mac, (
char*)mac_addr, ESP_NOW_KEY_LEN);
592 LOGD(
"default_send_cb - %s -> %s", ESPNowStreamSelf->mac2str(mac_addr),
593 status == ESP_NOW_SEND_SUCCESS ?
"+" :
"-");
596 if (strncmp((
char*)mac_addr, (
char*)first_mac, ESP_NOW_KEY_LEN) == 0) {
597 ESPNowStreamSelf->available_to_write = ESPNowStreamSelf->cfg.buffer_size;
600 ESPNowStreamSelf->last_send_success = (status == ESP_NOW_SEND_SUCCESS);
602 if (status == ESP_NOW_SEND_SUCCESS) {
603 ESPNowStreamSelf->last_io_success_time =
millis();
606 "Send Error to %s! Status: %d (Possible causes: out of range, "
607 "receiver busy/offline, channel mismatch, or buffer full)",
608 ESPNowStreamSelf->mac2str(mac_addr), status);
612 xSemaphoreGive(ESPNowStreamSelf->xSemaphore);