Compare commits
12 Commits
Author | SHA1 | Date | |
---|---|---|---|
af76d3172f | |||
a7caa89674 | |||
85d183fddb | |||
603c544e46 | |||
0f35e48fe5 | |||
1391c9b3c1 | |||
3d789205d1 | |||
2caa1477b0 | |||
b987a62438 | |||
da9da77890 | |||
17deb9f895 | |||
cedea19f1a |
@ -3,7 +3,7 @@
|
||||
## Tested on
|
||||
|
||||
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
|
||||
|
||||
@ -86,7 +86,11 @@ void app_main(void)
|
||||
strcpy(send_message.char_value, "THIS IS A CHAR");
|
||||
send_message.float_value = 1.234;
|
||||
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;
|
||||
for (;;)
|
||||
{
|
||||
|
@ -32,7 +32,7 @@ extern "C"
|
||||
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.
|
||||
uint8_t wifi_channel; // Wi-Fi channel uses to send/receive ESP-NOW data. @note Values from 1 to 14.
|
||||
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;
|
||||
|
||||
ESP_EVENT_DECLARE_BASE(ZH_ESPNOW);
|
||||
@ -116,6 +116,89 @@ extern "C"
|
||||
*/
|
||||
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
|
||||
}
|
||||
#endif
|
@ -1 +1 @@
|
||||
1.1.2
|
||||
1.9.0
|
202
zh_espnow.c
202
zh_espnow.c
@ -14,6 +14,13 @@ static const char *TAG = "zh_espnow";
|
||||
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_FAIL BIT1
|
||||
#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_register_callbacks(bool battery_mode);
|
||||
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);
|
||||
#endif
|
||||
#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);
|
||||
#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_processing(void *pvParameter);
|
||||
|
||||
static EventGroupHandle_t _event_group_handle = {0};
|
||||
static QueueHandle_t _queue_handle = {0};
|
||||
static TaskHandle_t _processing_task_handle = {0};
|
||||
static EventGroupHandle_t _event_group_handle = NULL;
|
||||
static QueueHandle_t _queue_handle = NULL;
|
||||
static TaskHandle_t _processing_task_handle = NULL;
|
||||
static zh_espnow_init_config_t _init_config = {0};
|
||||
static zh_espnow_stats_t _stats = {0};
|
||||
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;
|
||||
}
|
||||
esp_err_t err = _zh_espnow_validate_config(config);
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ZH_ESPNOW_LOGE("ESP-NOW initialization failed. Initial configuration check failed.");
|
||||
return err;
|
||||
}
|
||||
else
|
||||
{
|
||||
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.");
|
||||
}
|
||||
_init_config = *config;
|
||||
err = _zh_espnow_init_wifi(config);
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ZH_ESPNOW_LOGE("ESP-NOW initialization failed. WiFi initialization failed.");
|
||||
return err;
|
||||
}
|
||||
else
|
||||
{
|
||||
ZH_ESPNOW_CHECK(err == ESP_OK, err, "ESP-NOW initialization failed. WiFi initialization failed.");
|
||||
ZH_ESPNOW_LOGI("WiFi initialization completed successfully.");
|
||||
}
|
||||
err = _zh_espnow_init_resources(config);
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ZH_ESPNOW_LOGE("ESP-NOW initialization failed. Resources initialization failed.");
|
||||
goto CLEANUP;
|
||||
}
|
||||
else
|
||||
{
|
||||
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.");
|
||||
}
|
||||
err = esp_now_init();
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ZH_ESPNOW_LOGE_ERR("ESP-NOW initialization failed. ESP-NOW driver initialization failed.", err);
|
||||
goto CLEANUP;
|
||||
}
|
||||
else
|
||||
{
|
||||
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.");
|
||||
}
|
||||
err = _zh_espnow_register_callbacks(config->battery_mode);
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ZH_ESPNOW_LOGE("ESP-NOW initialization failed. ESP-NOW callbacks registration failed.");
|
||||
goto CLEANUP;
|
||||
}
|
||||
else
|
||||
{
|
||||
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.");
|
||||
}
|
||||
err = _zh_espnow_create_task(config);
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ZH_ESPNOW_LOGE("ESP-NOW initialization failed. Processing task initialization failed.");
|
||||
goto CLEANUP;
|
||||
}
|
||||
else
|
||||
{
|
||||
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.");
|
||||
}
|
||||
_is_initialized = true;
|
||||
ZH_ESPNOW_LOGI("ESP-NOW initialization completed successfully.");
|
||||
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();
|
||||
ZH_ESPNOW_CHECK(_event_group_handle != NULL, ESP_FAIL, "Event group creation failed.");
|
||||
_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;
|
||||
}
|
||||
|
||||
@ -312,6 +282,23 @@ static esp_err_t _zh_espnow_register_callbacks(bool battery_mode)
|
||||
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)
|
||||
{
|
||||
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();
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
||||
#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)
|
||||
@ -509,3 +497,113 @@ const zh_espnow_stats_t *zh_espnow_get_stats(void)
|
||||
{
|
||||
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.");
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user