17 Commits
v1.1.0 ... dev

Author SHA1 Message Date
01c909fce5 perf: renamed task handle 2026-02-08 22:28:44 +03:00
8dd239ce69 doc: update some comments for doxygen style 2026-02-08 22:15:37 +03:00
af76d3172f feat: esp-idf v5.5 support 2025-06-14 07:27:44 +03:00
a7caa89674 refactor: logging refactoring 2025-05-09 09:32:41 +03:00
85d183fddb refactor: changed pointers initialization values 2025-05-07 09:36:42 +03:00
603c544e46 feat: added queue operations 2025-05-06 11:54:25 +03:00
0f35e48fe5 feat: added get mac address 2025-05-06 11:32:11 +03:00
1391c9b3c1 feat: added get/set battery mode 2025-05-06 11:12:29 +03:00
3d789205d1 refactor: updated log messages 2025-05-06 10:41:52 +03:00
2caa1477b0 feat: added get/set espnow channel 2025-05-06 10:35:59 +03:00
b987a62438 style: typo 2025-05-06 09:32:40 +03:00
da9da77890 feat: added get/set attemps 2025-05-06 09:31:46 +03:00
17deb9f895 feat: added get initialization status 2025-05-06 09:07:52 +03:00
cedea19f1a feat: added reset statistics 2025-05-06 08:58:28 +03:00
7d1653b076 fix: error receiveng 1 to 6 bytes data 2025-05-06 08:10:39 +03:00
87d4713b40 fix: error sending more than 255 bytes 2025-05-04 13:40:18 +03:00
7c4650d87a style: removed empty file 2025-05-04 12:28:50 +03:00
5 changed files with 309 additions and 93 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
@@ -86,7 +86,11 @@ void app_main(void)
strcpy(send_message.char_value, "THIS IS A CHAR"); strcpy(send_message.char_value, "THIS IS A CHAR");
send_message.float_value = 1.234; send_message.float_value = 1.234;
send_message.bool_value = false; send_message.bool_value = false;
printf("Used ESP-NOW version %d.\n", zh_espnow_get_version()); printf("ESP-NOW version %d.\n", zh_espnow_get_version());
printf("ESP-NOW channel %d. \n", zh_espnow_get_channel());
uint8_t node_mac[6] = {0};
zh_espnow_get_mac(node_mac);
printf("ESP-NOW MAC %02X:%02X:%02X:%02X:%02X:%02X.\n", MAC2STR(node_mac));
uint8_t counter = 0; uint8_t counter = 0;
for (;;) for (;;)
{ {

View File

@@ -1,3 +1,7 @@
/**
* @file zh_espnow.h
*/
#pragma once #pragma once
#include "string.h" #include "string.h"
@@ -9,6 +13,9 @@
#include "esp_log.h" #include "esp_log.h"
#include "esp_heap_caps.h" #include "esp_heap_caps.h"
/**
* @brief ESP-NOW interface initial default values.
*/
#define ZH_ESPNOW_INIT_CONFIG_DEFAULT() \ #define ZH_ESPNOW_INIT_CONFIG_DEFAULT() \
{ \ { \
.task_priority = 10, \ .task_priority = 10, \
@@ -24,49 +31,73 @@ extern "C"
{ {
#endif #endif
typedef struct // Structure for initial initialization of ESP-NOW interface. extern TaskHandle_t zh_espnow; /*!< ESP-NOW interface Task Handle. */
/**
* @brief Structure for initial initialization of ESP-NOW interface.
*/
typedef struct
{ {
uint8_t task_priority; // Task priority for the ESP-NOW messages processing. @note The minimum size is 5. uint8_t task_priority; /*!< Task priority for the ESP-NOW messages processing. @note The minimum value is 5. */
uint16_t stack_size; // Stack size for task for the ESP-NOW messages processing. @note The minimum size is 2048. uint16_t stack_size; /*!< Stack size for task for the ESP-NOW messages processing. @note The minimum size is 2048. */
uint8_t queue_size; // Queue size for task for the ESP-NOW messages processing. @note The size depends on the number of messages to be processed. The minimum size is 16. uint8_t queue_size; /*!< Queue size for task for the ESP-NOW messages processing. @note The minimum value is 10. */
wifi_interface_t wifi_interface; // WiFi interface (STA or AP) used for ESP-NOW operation. @note The MAC address of the device depends on the selected WiFi interface. wifi_interface_t wifi_interface; /*!< WiFi interface (STA or AP) used for ESP-NOW operation. */
uint8_t wifi_channel; // Wi-Fi channel uses to send/receive ESP-NOW data. @note Values from 1 to 14. uint8_t wifi_channel; /*!< Wi-Fi channel uses to send/receive ESP-NOW data. */
uint8_t attempts; // Maximum number of attempts to send a message. @note It is not recommended to set a value greater than 10. uint8_t attempts; /*!< Maximum number of attempts to send a message. @note It is not recommended to set a value greater than 10. */
bool battery_mode; // Battery operation mode. If true, the node does not receive messages. bool battery_mode; /*!< Battery operation mode. If true the node does not receive messages. */
} zh_espnow_init_config_t; } zh_espnow_init_config_t;
ESP_EVENT_DECLARE_BASE(ZH_ESPNOW); ESP_EVENT_DECLARE_BASE(ZH_ESPNOW);
typedef enum // Enumeration of possible ESP-NOW events. /**
* @brief Enumeration of possible ESP-NOW events.
*/
typedef enum
{ {
ZH_ESPNOW_ON_RECV_EVENT, // The event when the ESP-NOW message was received. ZH_ESPNOW_ON_RECV_EVENT, /*!< The event when the ESP-NOW message was received. */
ZH_ESPNOW_ON_SEND_EVENT // The event when the ESP-NOW message was sent. ZH_ESPNOW_ON_SEND_EVENT /*!< The event when the ESP-NOW message was sent. */
} zh_espnow_event_type_t; } zh_espnow_event_type_t;
typedef enum // Enumeration of possible status of sent ESP-NOW message. /**
* @brief Enumeration of possible status of sent ESP-NOW message.
*/
typedef enum
{ {
ZH_ESPNOW_SEND_SUCCESS, // If ESP-NOW message was sent success. ZH_ESPNOW_SEND_SUCCESS, /*!< If ESP-NOW message was sent success. */
ZH_ESPNOW_SEND_FAIL // If ESP-NOW message was sent fail. ZH_ESPNOW_SEND_FAIL /*!< If ESP-NOW message was sent fail. */
} zh_espnow_on_send_event_type_t; } zh_espnow_on_send_event_type_t;
typedef struct // Structure for sending data to the event handler when an ESP-NOW message was sent. @note Should be used with ZH_ESPNOW event base and ZH_ESPNOW_ON_SEND_EVENT event. /**
* @brief Structure for sending data to the event handler when an ESP-NOW message was sent.
*
* @note Should be used with ZH_ESPNOW event base and ZH_ESPNOW_ON_SEND_EVENT event.
*/
typedef struct
{ {
uint8_t mac_addr[ESP_NOW_ETH_ALEN]; // MAC address of the device to which the ESP-NOW message was sent. uint8_t mac_addr[ESP_NOW_ETH_ALEN]; /*!< MAC address of the device to which the ESP-NOW message was sent. */
zh_espnow_on_send_event_type_t status; // Status of sent ESP-NOW message. zh_espnow_on_send_event_type_t status; /*!< Status of sent ESP-NOW message. */
} zh_espnow_event_on_send_t; } zh_espnow_event_on_send_t;
typedef struct // Structure for sending data to the event handler when an ESP-NOW message was received. @note Should be used with ZH_ESPNOW event base and ZH_ESPNOW_ON_RECV_EVENT event. /**
* @brief Structure for sending data to the event handler when an ESP-NOW message was received.
*
* @note Should be used with ZH_ESPNOW event base and ZH_ESPNOW_ON_RECV_EVENT event.
*/
typedef struct
{ {
uint8_t mac_addr[ESP_NOW_ETH_ALEN]; // MAC address of the sender ESP-NOW message. uint8_t mac_addr[ESP_NOW_ETH_ALEN]; /*!< MAC address of the sender ESP-NOW message. */
uint8_t *data; // Pointer to the data of the received ESP-NOW message. uint8_t *data; /*!< Pointer to the data of the received ESP-NOW message. */
uint16_t data_len; // Size of the received ESP-NOW message. uint16_t data_len; /*!< Size of the received ESP-NOW message. */
} zh_espnow_event_on_recv_t; } zh_espnow_event_on_recv_t;
typedef struct // Structure for message statistics storage. /**
* @brief Structure for message statistics storage.
*/
typedef struct
{ {
uint32_t sent_success; // Number of successfully sent messages. uint32_t sent_success; /*!< Number of successfully sent messages. */
uint32_t sent_fail; // Number of failed sent messages. uint32_t sent_fail; /*!< Number of failed sent messages. */
uint32_t received; // Number of received messages. uint32_t received; /*!< Number of received messages. */
} zh_espnow_stats_t; } zh_espnow_stats_t;
/** /**
@@ -100,7 +131,7 @@ extern "C"
* *
* @return ESP_OK if success or an error code otherwise. * @return ESP_OK if success or an error code otherwise.
*/ */
esp_err_t zh_espnow_send(const uint8_t *target, const uint8_t *data, const uint8_t data_len); esp_err_t zh_espnow_send(const uint8_t *target, const uint8_t *data, const uint16_t data_len);
/** /**
* @brief Get ESP-NOW version. * @brief Get ESP-NOW version.
@@ -116,6 +147,89 @@ extern "C"
*/ */
const zh_espnow_stats_t *zh_espnow_get_stats(void); const zh_espnow_stats_t *zh_espnow_get_stats(void);
/**
* @brief Reset ESP-NOW statistics.
*/
void zh_espnow_reset_stats(void);
/**
* @brief Check ESP-NOW initialization status.
*
* @return True if ESP-NOW is initialized false otherwise.
*/
bool zh_espnow_is_initialized(void);
/**
* @brief Get number of attempts.
*
* @return Attemps number.
*/
uint8_t zh_espnow_get_attempts(void);
/**
* @brief Set number of attempts.
*
* @param[in] attempts Attemps number.
*
* @return ESP_OK if success or an error code otherwise.
*/
esp_err_t zh_espnow_set_attempts(uint8_t attempts);
/**
* @brief Get ESP-NOW channel.
*
* @return ESP-NOW channel if success or 0 otherwise.
*/
uint8_t zh_espnow_get_channel(void);
/**
* @brief Set ESP-NOW channel.
*
* @param[in] channel ESP-NOW channel (1-14).
*
* @return ESP_OK if success or an error code otherwise.
*/
esp_err_t zh_espnow_set_channel(uint8_t channel);
/**
* @brief Get battery mode.
*
* @return True if battery mode set false otherwise.
*/
bool zh_espnow_get_battery_mode(void);
/**
* @brief Set battery mode.
*
* @param[in] battery_mode True to enable the mode false to disable it.
*
* @note If true the node does not receive messages.
*
* @return ESP_OK if success or an error code otherwise.
*/
esp_err_t zh_espnow_set_battery_mode(bool battery_mode);
/**
* @brief Get MAC address of the node.
*
* @param[out] mac_addr Pointer to a buffer containing an eight-byte MAC.
*
* @return ESP_OK if success or an error code otherwise.
*/
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

0
main.c
View File

View File

@@ -1 +1 @@
1.1.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}; TaskHandle_t zh_espnow = NULL;
static QueueHandle_t _queue_handle = {0}; static EventGroupHandle_t _event_group_handle = NULL;
static TaskHandle_t _processing_task_handle = {0}; static QueueHandle_t _queue_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;
@@ -204,10 +174,10 @@ esp_err_t zh_espnow_deinit(void)
{ {
ZH_ESPNOW_LOGI("ESP-NOW driver deinitialized."); ZH_ESPNOW_LOGI("ESP-NOW driver deinitialized.");
} }
if (_processing_task_handle != NULL) if (zh_espnow != NULL)
{ {
vTaskDelete(_processing_task_handle); vTaskDelete(zh_espnow);
_processing_task_handle = NULL; zh_espnow = NULL;
ZH_ESPNOW_LOGI("Processing task deleted."); ZH_ESPNOW_LOGI("Processing task deleted.");
} }
_is_initialized = false; _is_initialized = false;
@@ -215,7 +185,7 @@ esp_err_t zh_espnow_deinit(void)
return final_status; return final_status;
} }
esp_err_t zh_espnow_send(const uint8_t *target, const uint8_t *data, const uint8_t data_len) esp_err_t zh_espnow_send(const uint8_t *target, const uint8_t *data, const uint16_t data_len)
{ {
ZH_ESPNOW_LOGI("Adding to queue outgoing ESP-NOW data to MAC %02X:%02X:%02X:%02X:%02X:%02X started.", MAC2STR((target == NULL) ? _broadcast_mac : target)); ZH_ESPNOW_LOGI("Adding to queue outgoing ESP-NOW data to MAC %02X:%02X:%02X:%02X:%02X:%02X started.", MAC2STR((target == NULL) ? _broadcast_mac : target));
if (_is_initialized == false) if (_is_initialized == false)
@@ -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;
} }
@@ -284,7 +254,7 @@ static esp_err_t _zh_espnow_create_task(const zh_espnow_init_config_t *config)
config->stack_size, config->stack_size,
NULL, NULL,
config->task_priority, config->task_priority,
&_processing_task_handle, &zh_espnow,
tskNO_AFFINITY); tskNO_AFFINITY);
ZH_ESPNOW_CHECK(err == pdPASS, ESP_FAIL, "Task creation failed."); ZH_ESPNOW_CHECK(err == pdPASS, ESP_FAIL, "Task 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)
@@ -459,7 +447,7 @@ static void _zh_espnow_process_recv(_queue_t *queue)
ZH_ESPNOW_LOGI("Processing incoming ESP-NOW data from MAC %02X:%02X:%02X:%02X:%02X:%02X started.", MAC2STR(queue->data.mac_addr)); ZH_ESPNOW_LOGI("Processing incoming ESP-NOW data from MAC %02X:%02X:%02X:%02X:%02X:%02X started.", MAC2STR(queue->data.mac_addr));
zh_espnow_event_on_recv_t *recv_data = (zh_espnow_event_on_recv_t *)&queue->data; zh_espnow_event_on_recv_t *recv_data = (zh_espnow_event_on_recv_t *)&queue->data;
++_stats.received; ++_stats.received;
esp_err_t err = esp_event_post(ZH_ESPNOW, ZH_ESPNOW_ON_RECV_EVENT, recv_data, recv_data->data_len + sizeof(recv_data->mac_addr) + sizeof(uint8_t), portTICK_PERIOD_MS); esp_err_t err = esp_event_post(ZH_ESPNOW, ZH_ESPNOW_ON_RECV_EVENT, recv_data, sizeof(zh_espnow_event_on_recv_t), portTICK_PERIOD_MS);
if (err == ESP_OK) if (err == ESP_OK)
{ {
ZH_ESPNOW_LOGI("Incoming ESP-NOW data from MAC %02X:%02X:%02X:%02X:%02X:%02X processed successfully.", MAC2STR(queue->data.mac_addr)); ZH_ESPNOW_LOGI("Incoming ESP-NOW data from MAC %02X:%02X:%02X:%02X:%02X:%02X processed successfully.", MAC2STR(queue->data.mac_addr));
@@ -508,4 +496,114 @@ uint8_t zh_espnow_get_version(void)
const zh_espnow_stats_t *zh_espnow_get_stats(void) const zh_espnow_stats_t *zh_espnow_get_stats(void)
{ {
return &_stats; return &_stats;
}
void zh_espnow_reset_stats(void)
{
_stats.sent_success = 0;
_stats.sent_fail = 0;
_stats.received = 0;
ZH_ESPNOW_LOGI("ESP-NOW statistic reset successfully.");
}
bool zh_espnow_is_initialized(void)
{
return _is_initialized;
}
uint8_t zh_espnow_get_attempts(void)
{
return _init_config.attempts;
}
esp_err_t zh_espnow_set_attempts(uint8_t attempts)
{
ZH_ESPNOW_CHECK(_is_initialized == true, ESP_ERR_INVALID_STATE, "Number of attempts set failed. ESP-NOW is not initialized.");
ZH_ESPNOW_CHECK(attempts > 0, ESP_ERR_INVALID_ARG, "Number of attempts set failed. Invalid number.");
_init_config.attempts = attempts;
ZH_ESPNOW_LOGI("Number of attempts set successfully.");
return ESP_OK;
}
uint8_t zh_espnow_get_channel(void)
{
if (_is_initialized == false)
{
ZH_ESPNOW_LOGE("ESP-NOW channel receiption failed. ESP-NOW is not initialized.");
return 0;
}
uint8_t prim_channel = 0;
wifi_second_chan_t sec_channel = 0;
esp_err_t err = esp_wifi_get_channel(&prim_channel, &sec_channel);
if (err != ESP_OK)
{
ZH_ESPNOW_LOGE_ERR("ESP-NOW channel receiption failed.", err);
return 0;
}
_init_config.wifi_channel = prim_channel;
ZH_ESPNOW_LOGI("ESP-NOW channel receiption successfully.");
return prim_channel;
}
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(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);
ZH_ESPNOW_CHECK(err == ESP_OK, err, "ESP-NOW channel set failed.");
_init_config.wifi_channel = channel;
ZH_ESPNOW_LOGI("ESP-NOW channel set successfully.");
return err;
}
bool zh_espnow_get_battery_mode(void)
{
return _init_config.battery_mode;
}
esp_err_t zh_espnow_set_battery_mode(bool battery_mode)
{
ZH_ESPNOW_CHECK(_is_initialized == true, ESP_ERR_INVALID_STATE, "Battery mode set failed. ESP-NOW is not initialized.");
esp_err_t err = esp_now_unregister_send_cb();
ZH_ESPNOW_CHECK(err == ESP_OK, err, "Battery mode set failed. Failed to unregister send callback.");
if (_init_config.battery_mode == false)
{
err = esp_now_unregister_recv_cb();
ZH_ESPNOW_CHECK(err == ESP_OK, err, "Battery mode set failed. Failed to unregister receive callback.");
}
err = _zh_espnow_register_callbacks(battery_mode);
ZH_ESPNOW_CHECK(err == ESP_OK, err, "Battery mode set failed. Failed to register callbacks.");
_init_config.battery_mode = battery_mode;
ZH_ESPNOW_LOGI("Battery mode set successfully.");
return ESP_OK;
}
esp_err_t zh_espnow_get_mac(uint8_t *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.");
}
} }