4 Commits

4 changed files with 86 additions and 65 deletions

View File

@ -3,7 +3,7 @@
## Tested on ## Tested on
1. [ESP8266 RTOS_SDK v3.4](https://docs.espressif.com/projects/esp8266-rtos-sdk/en/latest/index.html#) 1. [ESP8266 RTOS_SDK v3.4](https://docs.espressif.com/projects/esp8266-rtos-sdk/en/latest/index.html#)
2. [ESP32 ESP-IDF v5.4](https://docs.espressif.com/projects/esp-idf/en/release-v5.4/esp32/index.html) 2. [ESP32 ESP-IDF v5.5](https://docs.espressif.com/projects/esp-idf/en/release-v5.5/esp32/index.html)
## Features ## Features

View File

@ -187,6 +187,18 @@ extern "C"
*/ */
esp_err_t zh_espnow_get_mac(uint8_t *mac_addr); esp_err_t zh_espnow_get_mac(uint8_t *mac_addr);
/**
* @brief Get the number of available places in the queue.
*
* @return Number of available places.
*/
uint8_t zh_espnow_get_queue_space(void);
/**
* @brief Clean up the message queue.
*/
void zh_espnow_clear_queue(void);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -1 +1 @@
1.7.0 1.9.0

View File

@ -14,6 +14,13 @@ static const char *TAG = "zh_espnow";
return err; \ return err; \
} }
#define ZH_ESPNOW_CHECK_GOTO(cond, err, tag, msg, ...) \
if (!(cond)) \
{ \
ZH_ESPNOW_LOGE_ERR(msg, err); \
goto tag; \
}
#define DATA_SEND_SUCCESS BIT0 #define DATA_SEND_SUCCESS BIT0
#define DATA_SEND_FAIL BIT1 #define DATA_SEND_FAIL BIT1
#define WAIT_CONFIRM_MAX_TIME 50 #define WAIT_CONFIRM_MAX_TIME 50
@ -41,7 +48,12 @@ static esp_err_t _zh_espnow_init_resources(const zh_espnow_init_config_t *config
static esp_err_t _zh_espnow_validate_config(const zh_espnow_init_config_t *config); static esp_err_t _zh_espnow_validate_config(const zh_espnow_init_config_t *config);
static esp_err_t _zh_espnow_register_callbacks(bool battery_mode); static esp_err_t _zh_espnow_register_callbacks(bool battery_mode);
static esp_err_t _zh_espnow_create_task(const zh_espnow_init_config_t *config); static esp_err_t _zh_espnow_create_task(const zh_espnow_init_config_t *config);
#if ESP_IDF_VERSION_MAJOR >= 5 && ESP_IDF_VERSION_MINOR >= 5
static void _zh_espnow_send_cb(const esp_now_send_info_t *esp_now_info, esp_now_send_status_t status);
#else
static void _zh_espnow_send_cb(const uint8_t *mac_addr, esp_now_send_status_t status); static void _zh_espnow_send_cb(const uint8_t *mac_addr, esp_now_send_status_t status);
#endif
#if defined CONFIG_IDF_TARGET_ESP8266 || ESP_IDF_VERSION_MAJOR == 4 #if defined CONFIG_IDF_TARGET_ESP8266 || ESP_IDF_VERSION_MAJOR == 4
static void _zh_espnow_recv_cb(const uint8_t *mac_addr, const uint8_t *data, int data_len); static void _zh_espnow_recv_cb(const uint8_t *mac_addr, const uint8_t *data, int data_len);
#else #else
@ -51,9 +63,9 @@ static void _zh_espnow_process_send(_queue_t *queue);
static void _zh_espnow_process_recv(_queue_t *queue); static void _zh_espnow_process_recv(_queue_t *queue);
static void _zh_espnow_processing(void *pvParameter); static void _zh_espnow_processing(void *pvParameter);
static EventGroupHandle_t _event_group_handle = {0}; static EventGroupHandle_t _event_group_handle = NULL;
static QueueHandle_t _queue_handle = {0}; static QueueHandle_t _queue_handle = NULL;
static TaskHandle_t _processing_task_handle = {0}; static TaskHandle_t _processing_task_handle = NULL;
static zh_espnow_init_config_t _init_config = {0}; static zh_espnow_init_config_t _init_config = {0};
static zh_espnow_stats_t _stats = {0}; static zh_espnow_stats_t _stats = {0};
static bool _is_initialized = false; static bool _is_initialized = false;
@ -73,66 +85,24 @@ esp_err_t zh_espnow_init(const zh_espnow_init_config_t *config)
return ESP_OK; return ESP_OK;
} }
esp_err_t err = _zh_espnow_validate_config(config); esp_err_t err = _zh_espnow_validate_config(config);
if (err != ESP_OK) ZH_ESPNOW_CHECK(err == ESP_OK, err, "ESP-NOW initialization failed. Initial configuration check failed.");
{ ZH_ESPNOW_LOGI("ESP-NOW initial configuration check completed successfully.");
ZH_ESPNOW_LOGE("ESP-NOW initialization failed. Initial configuration check failed.");
return err;
}
else
{
ZH_ESPNOW_LOGI("ESP-NOW initial configuration check completed successfully.");
}
_init_config = *config; _init_config = *config;
err = _zh_espnow_init_wifi(config); err = _zh_espnow_init_wifi(config);
if (err != ESP_OK) ZH_ESPNOW_CHECK(err == ESP_OK, err, "ESP-NOW initialization failed. WiFi initialization failed.");
{ ZH_ESPNOW_LOGI("WiFi initialization completed successfully.");
ZH_ESPNOW_LOGE("ESP-NOW initialization failed. WiFi initialization failed.");
return err;
}
else
{
ZH_ESPNOW_LOGI("WiFi initialization completed successfully.");
}
err = _zh_espnow_init_resources(config); err = _zh_espnow_init_resources(config);
if (err != ESP_OK) ZH_ESPNOW_CHECK_GOTO(err == ESP_OK, err, CLEANUP, "ESP-NOW initialization failed. Resources initialization failed.");
{ ZH_ESPNOW_LOGI("ESP-NOW resources initialization completed successfully.");
ZH_ESPNOW_LOGE("ESP-NOW initialization failed. Resources initialization failed.");
goto CLEANUP;
}
else
{
ZH_ESPNOW_LOGI("ESP-NOW resources initialization completed successfully.");
}
err = esp_now_init(); err = esp_now_init();
if (err != ESP_OK) ZH_ESPNOW_CHECK_GOTO(err == ESP_OK, err, CLEANUP, "ESP-NOW initialization failed. ESP-NOW driver initialization failed.");
{ ZH_ESPNOW_LOGI("ESP-NOW driver initialization completed successfully.");
ZH_ESPNOW_LOGE_ERR("ESP-NOW initialization failed. ESP-NOW driver initialization failed.", err);
goto CLEANUP;
}
else
{
ZH_ESPNOW_LOGI("ESP-NOW driver initialization completed successfully.");
}
err = _zh_espnow_register_callbacks(config->battery_mode); err = _zh_espnow_register_callbacks(config->battery_mode);
if (err != ESP_OK) ZH_ESPNOW_CHECK_GOTO(err == ESP_OK, err, CLEANUP, "ESP-NOW initialization failed. ESP-NOW callbacks registration failed.");
{ ZH_ESPNOW_LOGI("ESP-NOW callbacks registered successfully.");
ZH_ESPNOW_LOGE("ESP-NOW initialization failed. ESP-NOW callbacks registration failed.");
goto CLEANUP;
}
else
{
ZH_ESPNOW_LOGI("ESP-NOW callbacks registered successfully.");
}
err = _zh_espnow_create_task(config); err = _zh_espnow_create_task(config);
if (err != ESP_OK) ZH_ESPNOW_CHECK_GOTO(err == ESP_OK, err, CLEANUP, "ESP-NOW initialization failed. Processing task initialization failed.");
{ ZH_ESPNOW_LOGI("ESP-NOW processing task initialization completed successfully.");
ZH_ESPNOW_LOGE("ESP-NOW initialization failed. Processing task initialization failed.");
goto CLEANUP;
}
else
{
ZH_ESPNOW_LOGI("ESP-NOW processing task initialization completed successfully.");
}
_is_initialized = true; _is_initialized = true;
ZH_ESPNOW_LOGI("ESP-NOW initialization completed successfully."); ZH_ESPNOW_LOGI("ESP-NOW initialization completed successfully.");
return ESP_OK; return ESP_OK;
@ -272,7 +242,7 @@ static esp_err_t _zh_espnow_init_resources(const zh_espnow_init_config_t *config
_event_group_handle = xEventGroupCreate(); _event_group_handle = xEventGroupCreate();
ZH_ESPNOW_CHECK(_event_group_handle != NULL, ESP_FAIL, "Event group creation failed."); ZH_ESPNOW_CHECK(_event_group_handle != NULL, ESP_FAIL, "Event group creation failed.");
_queue_handle = xQueueCreate(config->queue_size, sizeof(_queue_t)); _queue_handle = xQueueCreate(config->queue_size, sizeof(_queue_t));
ZH_ESPNOW_CHECK(_queue_handle != 0, ESP_FAIL, "Queue creation failed."); ZH_ESPNOW_CHECK(_queue_handle != NULL, ESP_FAIL, "Queue creation failed.");
return ESP_OK; return ESP_OK;
} }
@ -312,6 +282,23 @@ static esp_err_t _zh_espnow_register_callbacks(bool battery_mode)
return ESP_OK; return ESP_OK;
} }
#if ESP_IDF_VERSION_MAJOR >= 5 && ESP_IDF_VERSION_MINOR >= 5
static void IRAM_ATTR _zh_espnow_send_cb(const esp_now_send_info_t *esp_now_info, esp_now_send_status_t status)
{
if (esp_now_info == NULL)
{
ZH_ESPNOW_LOGE("Send callback received NULL MAC address.");
return;
}
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
ZH_ESPNOW_LOGI("ESP-NOW send callback: %s for MAC %02X:%02X:%02X:%02X:%02X:%02X.", (status == ESP_NOW_SEND_SUCCESS) ? "SUCCESS" : "FAIL", MAC2STR(esp_now_info->des_addr));
xEventGroupSetBitsFromISR(_event_group_handle, (status == ESP_NOW_SEND_SUCCESS) ? DATA_SEND_SUCCESS : DATA_SEND_FAIL, &xHigherPriorityTaskWoken);
if (xHigherPriorityTaskWoken == pdTRUE)
{
portYIELD_FROM_ISR();
};
}
#else
static void IRAM_ATTR _zh_espnow_send_cb(const uint8_t *mac_addr, esp_now_send_status_t status) static void IRAM_ATTR _zh_espnow_send_cb(const uint8_t *mac_addr, esp_now_send_status_t status)
{ {
if (mac_addr == NULL) if (mac_addr == NULL)
@ -327,6 +314,7 @@ static void IRAM_ATTR _zh_espnow_send_cb(const uint8_t *mac_addr, esp_now_send_s
portYIELD_FROM_ISR(); portYIELD_FROM_ISR();
}; };
} }
#endif
#if defined CONFIG_IDF_TARGET_ESP8266 || ESP_IDF_VERSION_MAJOR == 4 #if defined CONFIG_IDF_TARGET_ESP8266 || ESP_IDF_VERSION_MAJOR == 4
static void IRAM_ATTR _zh_espnow_recv_cb(const uint8_t *mac_addr, const uint8_t *data, int data_len) static void IRAM_ATTR _zh_espnow_recv_cb(const uint8_t *mac_addr, const uint8_t *data, int data_len)
@ -562,11 +550,7 @@ esp_err_t zh_espnow_set_channel(uint8_t channel)
ZH_ESPNOW_CHECK(_is_initialized == true, ESP_ERR_INVALID_STATE, "ESP-NOW channel set failed. ESP-NOW is not initialized."); ZH_ESPNOW_CHECK(_is_initialized == true, ESP_ERR_INVALID_STATE, "ESP-NOW channel set failed. ESP-NOW is not initialized.");
ZH_ESPNOW_CHECK(channel > 0 && channel < 15, ESP_ERR_INVALID_ARG, "ESP-NOW channel set failed. Invalid channel."); ZH_ESPNOW_CHECK(channel > 0 && channel < 15, ESP_ERR_INVALID_ARG, "ESP-NOW channel set failed. Invalid channel.");
esp_err_t err = esp_wifi_set_channel(channel, WIFI_SECOND_CHAN_NONE); esp_err_t err = esp_wifi_set_channel(channel, WIFI_SECOND_CHAN_NONE);
if (err != ESP_OK) ZH_ESPNOW_CHECK(err == ESP_OK, err, "ESP-NOW channel set failed.");
{
ZH_ESPNOW_LOGE_ERR("ESP-NOW channel set failed.", err);
return err;
}
_init_config.wifi_channel = channel; _init_config.wifi_channel = channel;
ZH_ESPNOW_LOGI("ESP-NOW channel set successfully."); ZH_ESPNOW_LOGI("ESP-NOW channel set successfully.");
return err; return err;
@ -597,4 +581,29 @@ esp_err_t zh_espnow_set_battery_mode(bool battery_mode)
esp_err_t zh_espnow_get_mac(uint8_t *mac_addr) esp_err_t zh_espnow_get_mac(uint8_t *mac_addr)
{ {
return esp_wifi_get_mac(_init_config.wifi_interface, mac_addr); return esp_wifi_get_mac(_init_config.wifi_interface, mac_addr);
}
uint8_t zh_espnow_get_queue_space(void)
{
if (_queue_handle == NULL)
{
return 0;
}
return uxQueueSpacesAvailable(_queue_handle);
}
void zh_espnow_clear_queue(void)
{
if (_queue_handle != NULL)
{
_queue_t queue = {0};
while (xQueueReceive(_queue_handle, &queue, 0) == pdTRUE)
{
if (queue.data.payload != NULL)
{
heap_caps_free(queue.data.payload);
}
}
ZH_ESPNOW_LOGI("Queue clear completed successfully.");
}
} }