From 76281e85be8bd7570c5a0d5d49626242c0c798c3 Mon Sep 17 00:00:00 2001 From: Alexey Zholtikov Date: Wed, 12 Jun 2024 22:54:28 +0300 Subject: [PATCH] Version 1.0.1 Added multiple attempts to send a message. Fixed bug with ESP-NOW channel setting when device is connected to router. Changed internal error message. Added support of ESP-IDF v4.x.x. Medium main code refactoring. Added WiFi channel selection. --- README.md | 5 +- include/zh_network.h | 10 +- version.txt | 2 +- zh_network.c | 406 ++++++++++++++++++++++--------------------- zh_network.zip | Bin 0 -> 15381 bytes 5 files changed, 222 insertions(+), 201 deletions(-) create mode 100644 zh_network.zip diff --git a/README.md b/README.md index ef5ebee..2636d2f 100644 --- a/README.md +++ b/README.md @@ -21,8 +21,9 @@ ## Attention 1. The definition of ZH_NETWORK_MAX_MESSAGE_SIZE in the zh_network.h can be changed between 1 and 218. Smaller size - higher transmission speed. All devices on the network must have the same ZH_NETWORK_MAX_MESSAGE_SIZE. -2. For correct work at ESP-NOW + STA mode your WiFi router must be set on channel 1. -3. The ZHNetwork and the zh_network are incompatible. +2. For correct operation in ESP-NOW + STA mode, your WiFi router must be set to the same channel as ESP-NOW. +3. All devices on the network must have the same WiFi channel. +4. The ZHNetwork and the zh_network are incompatible. ## Testing diff --git a/include/zh_network.h b/include/zh_network.h index 55c07ee..470ba5b 100644 --- a/include/zh_network.h +++ b/include/zh_network.h @@ -51,7 +51,9 @@ .max_waiting_time = 1000, \ .id_vector_size = 100, \ .route_vector_size = 100, \ - .wifi_interface = WIFI_IF_STA \ + .wifi_interface = WIFI_IF_STA, \ + .wifi_channel = 1, \ + .attempts = 3 \ } #ifdef __cplusplus @@ -76,6 +78,8 @@ extern "C" uint16_t id_vector_size; ///< Maximum size of unique ID of received messages. @note If the size is exceeded, the first value will be deleted. Minimum recommended value: number of planned nodes in the network + 10%. uint16_t route_vector_size; ///< The maximum size of the routing table. @note If the size is exceeded, the first route will be deleted. Minimum recommended value: number of planned nodes in the network + 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. + uint8_t wifi_channel; ///< Wi-Fi channel uses to send/receive ESPNOW 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 5. } zh_network_init_config_t; /// \cond @@ -140,7 +144,7 @@ extern "C" * - ESP_ERR_WIFI_NOT_INIT if WiFi is not initialized * - ESP_FAIL if any internal error */ - esp_err_t zh_network_init(zh_network_init_config_t *config); + esp_err_t zh_network_init(const zh_network_init_config_t *config); /** * @brief Deinitialize ESP-NOW interface. @@ -164,7 +168,7 @@ extern "C" * - ESP_OK if sent was success * - ESP_ERR_INVALID_ARG if parameter error * - ESP_ERR_INVALID_STATE if queue for outgoing data is almost full - * - ESP_FAIL if ESP-NOW is not initialized + * - ESP_FAIL if ESP-NOW is not initialized or any internal error */ esp_err_t zh_network_send(const uint8_t *target, const uint8_t *data, const uint8_t data_len); diff --git a/version.txt b/version.txt index afaf360..7f20734 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.0.0 \ No newline at end of file +1.0.1 \ No newline at end of file diff --git a/zh_network.c b/zh_network.c index 3d16451..5d3ac0d 100644 --- a/zh_network.c +++ b/zh_network.c @@ -12,7 +12,7 @@ /// \endcond static void _send_cb(const uint8_t *mac_addr, esp_now_send_status_t status); -#ifdef CONFIG_IDF_TARGET_ESP8266 +#if defined CONFIG_IDF_TARGET_ESP8266 || ESP_IDF_VERSION_MAJOR == 4 static void _recv_cb(const uint8_t *mac_addr, const uint8_t *data, int data_len); #else static void _recv_cb(const esp_now_recv_info_t *esp_now_info, const uint8_t *data, int data_len); @@ -21,7 +21,7 @@ static void _processing(void *pvParameter); static const char *TAG = "zh_network"; -static EventGroupHandle_t _send_cb_status_event_group_handle = {0}; +static EventGroupHandle_t _event_group_handle = {0}; static QueueHandle_t _queue_handle = {0}; static TaskHandle_t _processing_task_handle = {0}; static SemaphoreHandle_t _id_vector_mutex = {0}; @@ -32,55 +32,50 @@ static zh_vector_t _response_vector = {0}; static uint8_t _self_mac[6] = {0}; static const uint8_t _broadcast_mac[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; static bool _is_initialized = false; +static uint8_t _attempts = 0; /// \cond -typedef enum -{ - BROADCAST, - UNICAST, - DELIVERY_CONFIRM, - SEARCH_REQUEST, - SEARCH_RESPONSE -} message_type_t; - -typedef struct -{ - message_type_t message_type; - uint32_t network_id; - uint32_t message_id; - uint32_t confirm_id; - uint8_t original_target_mac[6]; - uint8_t original_sender_mac[6]; - uint8_t sender_mac[6]; - uint8_t data[ZH_NETWORK_MAX_MESSAGE_SIZE]; - uint8_t data_len; -} data_t; - typedef struct { uint8_t original_target_mac[6]; uint8_t intermediate_target_mac[6]; -} routing_table_t; - -typedef enum -{ - TO_SEND, - ON_RECV, - WAIT_ROUTE, - WAIT_RESPONSE, -} queue_id_t; +} _routing_table_t; typedef struct { - queue_id_t id; uint64_t time; - data_t data; -} queue_t; + enum + { + TO_SEND, + ON_RECV, + WAIT_ROUTE, + WAIT_RESPONSE, + } id; + struct + { + enum + { + BROADCAST, + UNICAST, + DELIVERY_CONFIRM, + SEARCH_REQUEST, + SEARCH_RESPONSE + } __attribute__((packed)) message_type; + uint32_t network_id; + uint32_t message_id; + uint32_t confirm_id; + uint8_t original_target_mac[6]; + uint8_t original_sender_mac[6]; + uint8_t sender_mac[6]; + uint8_t payload[ZH_NETWORK_MAX_MESSAGE_SIZE]; + uint8_t payload_len; + } __attribute__((packed)) data; +} _queue_t; ESP_EVENT_DEFINE_BASE(ZH_NETWORK); /// \endcond -esp_err_t zh_network_init(zh_network_init_config_t *config) +esp_err_t zh_network_init(const zh_network_init_config_t *config) { ESP_LOGI(TAG, "ESP-NOW initialization begin."); if (config == NULL) @@ -88,12 +83,29 @@ esp_err_t zh_network_init(zh_network_init_config_t *config) ESP_LOGE(TAG, "ESP-NOW initialization fail. Invalid argument."); return ESP_ERR_INVALID_ARG; } - if (esp_wifi_set_channel(1, WIFI_SECOND_CHAN_NONE) == ESP_ERR_WIFI_NOT_INIT) + _init_config = *config; + if (_init_config.wifi_channel < 1 || _init_config.wifi_channel > 14) + { + ESP_LOGE(TAG, "ESP-NOW initialization fail. WiFi channel."); + return ESP_ERR_INVALID_ARG; + } + esp_err_t err = esp_wifi_set_channel(_init_config.wifi_channel, WIFI_SECOND_CHAN_NONE); + if (err == ESP_ERR_WIFI_NOT_INIT || err == ESP_ERR_WIFI_NOT_STARTED) { ESP_LOGE(TAG, "ESP-NOW initialization fail. WiFi not initialized."); return ESP_ERR_WIFI_NOT_INIT; } - if (sizeof(data_t) > ESP_NOW_MAX_DATA_LEN) + else if (err == ESP_FAIL) + { + uint8_t prim = 0; + wifi_second_chan_t sec = 0; + esp_wifi_get_channel(&prim, &sec); + if (prim != _init_config.wifi_channel) + { + ESP_LOGW(TAG, "ESP-NOW initialization warning. The device is connected to the router. Channel %d will be used for ESP-NOW.", prim); + } + } + if ((sizeof(_queue_t) - 14) > ESP_NOW_MAX_DATA_LEN) { ESP_LOGE(TAG, "ESP-NOW initialization fail. The maximum value of the transmitted data size is incorrect."); return ESP_ERR_INVALID_ARG; @@ -106,11 +118,10 @@ esp_err_t zh_network_init(zh_network_init_config_t *config) { esp_read_mac(_self_mac, ESP_MAC_WIFI_SOFTAP); } - _init_config = *config; - _send_cb_status_event_group_handle = xEventGroupCreate(); - _queue_handle = xQueueCreate(_init_config.queue_size, sizeof(queue_t)); + _event_group_handle = xEventGroupCreate(); + _queue_handle = xQueueCreate(_init_config.queue_size, sizeof(_queue_t)); zh_vector_init(&_id_vector, sizeof(uint32_t), false); - zh_vector_init(&_route_vector, sizeof(routing_table_t), false); + zh_vector_init(&_route_vector, sizeof(_routing_table_t), false); zh_vector_init(&_response_vector, sizeof(uint32_t), false); _id_vector_mutex = xSemaphoreCreateMutex(); if (esp_now_init() != ESP_OK || esp_now_register_send_cb(_send_cb) != ESP_OK || esp_now_register_recv_cb(_recv_cb) != ESP_OK) @@ -136,7 +147,7 @@ esp_err_t zh_network_deinit(void) ESP_LOGE(TAG, "ESP-NOW deinitialization fail. ESP-NOW not initialized."); return ESP_FAIL; } - vEventGroupDelete(_send_cb_status_event_group_handle); + vEventGroupDelete(_event_group_handle); vQueueDelete(_queue_handle); esp_now_unregister_send_cb(); esp_now_unregister_recv_cb(); @@ -175,32 +186,31 @@ esp_err_t zh_network_send(const uint8_t *target, const uint8_t *data, const uint ESP_LOGW(TAG, "Adding outgoing ESP-NOW data to queue fail. Queue is almost full."); return ESP_ERR_INVALID_STATE; } - queue_t queue = {0}; + _queue_t queue = {0}; queue.id = TO_SEND; - data_t *send_data = &queue.data; - send_data->network_id = _init_config.network_id; - send_data->message_id = abs(esp_random()); // It is not clear why esp_random() sometimes gives negative values. - memcpy(send_data->original_sender_mac, &_self_mac, 6); + queue.data.network_id = _init_config.network_id; + queue.data.message_id = abs(esp_random()); // It is not clear why esp_random() sometimes gives negative values. + memcpy(queue.data.original_sender_mac, _self_mac, 6); if (target == NULL) { - send_data->message_type = BROADCAST; - memcpy(send_data->original_target_mac, &_broadcast_mac, 6); + queue.data.message_type = BROADCAST; + memcpy(queue.data.original_target_mac, _broadcast_mac, 6); } else { - if (memcmp(target, &_broadcast_mac, 6) != 0) + if (memcmp(target, _broadcast_mac, 6) != 0) { - send_data->message_type = UNICAST; - memcpy(send_data->original_target_mac, target, 6); + queue.data.message_type = UNICAST; + memcpy(queue.data.original_target_mac, target, 6); } else { - send_data->message_type = BROADCAST; - memcpy(send_data->original_target_mac, &_broadcast_mac, 6); + queue.data.message_type = BROADCAST; + memcpy(queue.data.original_target_mac, _broadcast_mac, 6); } } - memcpy(&send_data->data, data, data_len); - send_data->data_len = data_len; + memcpy(queue.data.payload, data, data_len); + queue.data.payload_len = data_len; if (target == NULL) { ESP_LOGI(TAG, "Adding outgoing ESP-NOW data to MAC FF:FF:FF:FF:FF:FF to queue success."); @@ -211,7 +221,8 @@ esp_err_t zh_network_send(const uint8_t *target, const uint8_t *data, const uint } if (xQueueSend(_queue_handle, &queue, portTICK_PERIOD_MS) != pdTRUE) { - ESP_LOGE(TAG, "ESP-NOW message processing task internal error."); + ESP_LOGE(TAG, "ESP-NOW message processing task internal error at line %d.", __LINE__); + return ESP_FAIL; } return ESP_OK; } @@ -220,21 +231,21 @@ static void _send_cb(const uint8_t *mac_addr, esp_now_send_status_t status) { if (status == ESP_NOW_SEND_SUCCESS) { - xEventGroupSetBits(_send_cb_status_event_group_handle, DATA_SEND_SUCCESS); + xEventGroupSetBits(_event_group_handle, DATA_SEND_SUCCESS); } else { - xEventGroupSetBits(_send_cb_status_event_group_handle, DATA_SEND_FAIL); + xEventGroupSetBits(_event_group_handle, DATA_SEND_FAIL); } } -#ifdef CONFIG_IDF_TARGET_ESP8266 +#if defined CONFIG_IDF_TARGET_ESP8266 || ESP_IDF_VERSION_MAJOR == 4 static void _recv_cb(const uint8_t *mac_addr, const uint8_t *data, int data_len) #else static void _recv_cb(const esp_now_recv_info_t *esp_now_info, const uint8_t *data, int data_len) #endif { -#ifdef CONFIG_IDF_TARGET_ESP8266 +#if defined CONFIG_IDF_TARGET_ESP8266 || ESP_IDF_VERSION_MAJOR == 4 ESP_LOGI(TAG, "Adding incoming ESP-NOW data from MAC %02X:%02X:%02X:%02X:%02X:%02X to queue begin.", MAC2STR(mac_addr)); #else ESP_LOGI(TAG, "Adding incoming ESP-NOW data from MAC %02X:%02X:%02X:%02X:%02X:%02X to queue begin.", MAC2STR(esp_now_info->src_addr)); @@ -244,10 +255,12 @@ static void _recv_cb(const esp_now_recv_info_t *esp_now_info, const uint8_t *dat ESP_LOGW(TAG, "Adding incoming ESP-NOW data to queue fail. Queue is almost full."); return; } - if (data_len == sizeof(data_t)) + if (data_len == sizeof(_queue_t) - 14) { - data_t *recv_data = (data_t *)data; - if (memcmp(&recv_data->network_id, &_init_config.network_id, sizeof(recv_data->network_id)) != 0) + _queue_t queue = {0}; + queue.id = ON_RECV; + memcpy(&queue.data, data, data_len); + if (memcmp(&queue.data.network_id, &_init_config.network_id, sizeof(queue.data.network_id)) != 0) { ESP_LOGW(TAG, "Adding incoming ESP-NOW data to queue fail. Incorrect mesh network ID."); return; @@ -255,7 +268,7 @@ static void _recv_cb(const esp_now_recv_info_t *esp_now_info, const uint8_t *dat for (uint16_t i = 0; i < zh_vector_get_size(&_id_vector); ++i) { uint32_t *message_id = zh_vector_get_item(&_id_vector, i); - if (memcmp(&recv_data->message_id, message_id, sizeof(recv_data->message_id)) == 0) + if (memcmp(&queue.data.message_id, message_id, sizeof(queue.data.message_id)) == 0) { ESP_LOGW(TAG, "Adding incoming ESP-NOW data to queue fail. Repeat message received."); return; @@ -263,30 +276,26 @@ static void _recv_cb(const esp_now_recv_info_t *esp_now_info, const uint8_t *dat } if (xSemaphoreTake(_id_vector_mutex, portTICK_PERIOD_MS) == pdTRUE) { - zh_vector_push_back(&_id_vector, &recv_data->message_id); + zh_vector_push_back(&_id_vector, &queue.data.message_id); if (zh_vector_get_size(&_id_vector) > _init_config.id_vector_size) { zh_vector_delete_item(&_id_vector, 0); } xSemaphoreGive(_id_vector_mutex); } - queue_t queue = {0}; - queue.id = ON_RECV; - recv_data = &queue.data; - memcpy(recv_data, data, data_len); -#ifdef CONFIG_IDF_TARGET_ESP8266 - memcpy(recv_data->sender_mac, mac_addr, 6); +#if defined CONFIG_IDF_TARGET_ESP8266 || ESP_IDF_VERSION_MAJOR == 4 + memcpy(queue.data.sender_mac, mac_addr, 6); #else - memcpy(recv_data->sender_mac, esp_now_info->src_addr, 6); + memcpy(queue.data.sender_mac, esp_now_info->src_addr, 6); #endif -#ifdef CONFIG_IDF_TARGET_ESP8266 +#if defined CONFIG_IDF_TARGET_ESP8266 || ESP_IDF_VERSION_MAJOR == 4 ESP_LOGI(TAG, "Adding incoming ESP-NOW data from MAC %02X:%02X:%02X:%02X:%02X:%02X to queue success.", MAC2STR(mac_addr)); #else ESP_LOGI(TAG, "Adding incoming ESP-NOW data from MAC %02X:%02X:%02X:%02X:%02X:%02X to queue success.", MAC2STR(esp_now_info->src_addr)); #endif if (xQueueSendToFront(_queue_handle, &queue, portTICK_PERIOD_MS) != pdTRUE) { - ESP_LOGE(TAG, "ESP-NOW message processing task internal error."); + ESP_LOGE(TAG, "ESP-NOW message processing task internal error at line %d.", __LINE__); } } else @@ -297,11 +306,10 @@ static void _recv_cb(const esp_now_recv_info_t *esp_now_info, const uint8_t *dat static void _processing(void *pvParameter) { - queue_t queue = {0}; + _queue_t queue = {0}; while (xQueueReceive(_queue_handle, &queue, portMAX_DELAY) == pdTRUE) { bool flag = false; - data_t *data = &queue.data; switch (queue.id) { case TO_SEND: @@ -315,14 +323,14 @@ static void _processing(void *pvParameter) } memset(peer, 0, sizeof(esp_now_peer_info_t)); peer->ifidx = _init_config.wifi_interface; - if (data->message_type == BROADCAST || data->message_type == SEARCH_REQUEST || data->message_type == SEARCH_RESPONSE) + if (queue.data.message_type == BROADCAST || queue.data.message_type == SEARCH_REQUEST || queue.data.message_type == SEARCH_RESPONSE) { - memcpy(peer->peer_addr, &_broadcast_mac, 6); - if (memcmp(data->original_sender_mac, &_self_mac, 6) == 0) + memcpy(peer->peer_addr, _broadcast_mac, 6); + if (memcmp(queue.data.original_sender_mac, _self_mac, 6) == 0) { if (xSemaphoreTake(_id_vector_mutex, portTICK_PERIOD_MS) == pdTRUE) { - zh_vector_push_back(&_id_vector, &data->message_id); + zh_vector_push_back(&_id_vector, &queue.data.message_id); if (zh_vector_get_size(&_id_vector) > _init_config.id_vector_size) { zh_vector_delete_item(&_id_vector, 0); @@ -336,8 +344,8 @@ static void _processing(void *pvParameter) ESP_LOGI(TAG, "Checking routing table to MAC %02X:%02X:%02X:%02X:%02X:%02X.", MAC2STR(queue.data.original_target_mac)); for (uint16_t i = 0; i < zh_vector_get_size(&_route_vector); ++i) { - routing_table_t *routing_table = zh_vector_get_item(&_route_vector, i); - if (memcmp(data->original_target_mac, routing_table->original_target_mac, 6) == 0) + _routing_table_t *routing_table = zh_vector_get_item(&_route_vector, i); + if (memcmp(queue.data.original_target_mac, routing_table->original_target_mac, 6) == 0) { memcpy(peer->peer_addr, routing_table->intermediate_target_mac, 6); flag = true; @@ -348,7 +356,7 @@ static void _processing(void *pvParameter) if (flag == false) { ESP_LOGI(TAG, "Routing to MAC %02X:%02X:%02X:%02X:%02X:%02X not found.", MAC2STR(queue.data.original_target_mac)); - if (data->message_type == UNICAST) + if (queue.data.message_type == UNICAST) { ESP_LOGI(TAG, "Unicast message from MAC %02X:%02X:%02X:%02X:%02X:%02X to MAC %02X:%02X:%02X:%02X:%02X:%02X transferred to routing waiting list.", MAC2STR(queue.data.original_sender_mac), MAC2STR(queue.data.original_target_mac)); } @@ -360,19 +368,19 @@ static void _processing(void *pvParameter) queue.time = esp_timer_get_time() / 1000; if (xQueueSend(_queue_handle, &queue, portTICK_PERIOD_MS) != pdTRUE) { - ESP_LOGE(TAG, "ESP-NOW message processing task internal error."); + ESP_LOGE(TAG, "ESP-NOW message processing task internal error at line %d.", __LINE__); } ESP_LOGI(TAG, "System message for routing request from MAC %02X:%02X:%02X:%02X:%02X:%02X to MAC %02X:%02X:%02X:%02X:%02X:%02X added to queue.", MAC2STR(queue.data.original_sender_mac), MAC2STR(queue.data.original_target_mac)); queue.id = TO_SEND; - data->message_type = SEARCH_REQUEST; - memcpy(data->original_sender_mac, &_self_mac, 6); - data->data_len = 0; - memset(data->data, 0, ZH_NETWORK_MAX_MESSAGE_SIZE); - data->message_id = abs(esp_random()); // It is not clear why esp_random() sometimes gives negative values. + queue.data.message_type = SEARCH_REQUEST; + memcpy(queue.data.original_sender_mac, _self_mac, 6); + queue.data.payload_len = 0; + memset(queue.data.payload, 0, ZH_NETWORK_MAX_MESSAGE_SIZE); + queue.data.message_id = abs(esp_random()); // It is not clear why esp_random() sometimes gives negative values. ESP_LOGI(TAG, "Outgoing ESP-NOW data from MAC %02X:%02X:%02X:%02X:%02X:%02X to MAC %02X:%02X:%02X:%02X:%02X:%02X processed success.", MAC2STR(queue.data.original_sender_mac), MAC2STR(queue.data.original_target_mac)); if (xQueueSendToFront(_queue_handle, &queue, portTICK_PERIOD_MS) != pdTRUE) { - ESP_LOGE(TAG, "ESP-NOW message processing task internal error."); + ESP_LOGE(TAG, "ESP-NOW message processing task internal error at line %d.", __LINE__); } heap_caps_free(peer); break; @@ -393,45 +401,48 @@ static void _processing(void *pvParameter) break; } memset(on_send, 0, sizeof(zh_network_event_on_send_t)); - memcpy(on_send->mac_addr, data->original_target_mac, 6); - if (esp_now_send((uint8_t *)peer->peer_addr, (uint8_t *)data, sizeof(data_t)) != ESP_OK) + memcpy(on_send->mac_addr, queue.data.original_target_mac, 6); + SEND: + ++_attempts; + if (esp_now_send((uint8_t *)peer->peer_addr, (uint8_t *)&queue.data, sizeof(_queue_t) - 14) != ESP_OK) { - ESP_LOGE(TAG, "ESP-NOW message processing task internal error."); + ESP_LOGE(TAG, "ESP-NOW message processing task internal error at line %d.", __LINE__); heap_caps_free(peer); heap_caps_free(on_send); break; } - EventBits_t bit = xEventGroupWaitBits(_send_cb_status_event_group_handle, DATA_SEND_SUCCESS | DATA_SEND_FAIL, pdTRUE, pdFALSE, 50 / portTICK_PERIOD_MS); + EventBits_t bit = xEventGroupWaitBits(_event_group_handle, DATA_SEND_SUCCESS | DATA_SEND_FAIL, pdTRUE, pdFALSE, 50 / portTICK_PERIOD_MS); if ((bit & DATA_SEND_SUCCESS) != 0) { - if (memcmp(data->original_sender_mac, &_self_mac, 6) == 0) + _attempts = 0; + if (memcmp(queue.data.original_sender_mac, _self_mac, 6) == 0) { - if (data->message_type == BROADCAST) + if (queue.data.message_type == BROADCAST) { ESP_LOGI(TAG, "Broadcast message from MAC %02X:%02X:%02X:%02X:%02X:%02X to MAC %02X:%02X:%02X:%02X:%02X:%02X sent success.", MAC2STR(queue.data.original_sender_mac), MAC2STR(queue.data.original_target_mac)); on_send->status = ZH_NETWORK_SEND_SUCCESS; ESP_LOGI(TAG, "Outgoing ESP-NOW data from MAC %02X:%02X:%02X:%02X:%02X:%02X to MAC %02X:%02X:%02X:%02X:%02X:%02X processed success.", MAC2STR(queue.data.original_sender_mac), MAC2STR(queue.data.original_target_mac)); if (esp_event_post(ZH_NETWORK, ZH_NETWORK_ON_SEND_EVENT, on_send, sizeof(zh_network_event_on_send_t), portTICK_PERIOD_MS) != ESP_OK) { - ESP_LOGE(TAG, "ESP-NOW message processing task internal error."); + ESP_LOGE(TAG, "ESP-NOW message processing task internal error at line %d.", __LINE__); } } - if (data->message_type == SEARCH_REQUEST) + if (queue.data.message_type == SEARCH_REQUEST) { ESP_LOGI(TAG, "System message for routing request from MAC %02X:%02X:%02X:%02X:%02X:%02X to MAC %02X:%02X:%02X:%02X:%02X:%02X sent success.", MAC2STR(queue.data.original_sender_mac), MAC2STR(queue.data.original_target_mac)); ESP_LOGI(TAG, "Outgoing ESP-NOW data from MAC %02X:%02X:%02X:%02X:%02X:%02X to MAC %02X:%02X:%02X:%02X:%02X:%02X processed success.", MAC2STR(queue.data.original_sender_mac), MAC2STR(queue.data.original_target_mac)); } - if (data->message_type == SEARCH_RESPONSE) + if (queue.data.message_type == SEARCH_RESPONSE) { ESP_LOGI(TAG, "System message for routing response from MAC %02X:%02X:%02X:%02X:%02X:%02X to MAC %02X:%02X:%02X:%02X:%02X:%02X sent success.", MAC2STR(queue.data.original_sender_mac), MAC2STR(queue.data.original_target_mac)); ESP_LOGI(TAG, "Outgoing ESP-NOW data from MAC %02X:%02X:%02X:%02X:%02X:%02X to MAC %02X:%02X:%02X:%02X:%02X:%02X processed success.", MAC2STR(queue.data.original_sender_mac), MAC2STR(queue.data.original_target_mac)); } - if (data->message_type == DELIVERY_CONFIRM) + if (queue.data.message_type == DELIVERY_CONFIRM) { ESP_LOGI(TAG, "System message for message receiving confirmation from MAC %02X:%02X:%02X:%02X:%02X:%02X to MAC %02X:%02X:%02X:%02X:%02X:%02X via MAC %02X:%02X:%02X:%02X:%02X:%02X sent success.", MAC2STR(queue.data.original_sender_mac), MAC2STR(queue.data.original_target_mac), MAC2STR(peer->peer_addr)); ESP_LOGI(TAG, "Outgoing ESP-NOW data from MAC %02X:%02X:%02X:%02X:%02X:%02X to MAC %02X:%02X:%02X:%02X:%02X:%02X processed success.", MAC2STR(queue.data.original_sender_mac), MAC2STR(queue.data.original_target_mac)); } - if (data->message_type == UNICAST) + if (queue.data.message_type == UNICAST) { ESP_LOGI(TAG, "Unicast message from MAC %02X:%02X:%02X:%02X:%02X:%02X to MAC %02X:%02X:%02X:%02X:%02X:%02X via MAC %02X:%02X:%02X:%02X:%02X:%02X sent success.", MAC2STR(queue.data.original_sender_mac), MAC2STR(queue.data.original_target_mac), MAC2STR(peer->peer_addr)); ESP_LOGI(TAG, "Unicast message from MAC %02X:%02X:%02X:%02X:%02X:%02X to MAC %02X:%02X:%02X:%02X:%02X:%02X transferred to confirmation message waiting list.", MAC2STR(queue.data.original_sender_mac), MAC2STR(queue.data.original_target_mac)); @@ -440,33 +451,33 @@ static void _processing(void *pvParameter) queue.time = esp_timer_get_time() / 1000; if (xQueueSend(_queue_handle, &queue, portTICK_PERIOD_MS) != pdTRUE) { - ESP_LOGE(TAG, "ESP-NOW message processing task internal error."); + ESP_LOGE(TAG, "ESP-NOW message processing task internal error at line %d.", __LINE__); } } } else { - if (data->message_type == BROADCAST) + if (queue.data.message_type == BROADCAST) { ESP_LOGI(TAG, "Broadcast message from MAC %02X:%02X:%02X:%02X:%02X:%02X to MAC %02X:%02X:%02X:%02X:%02X:%02X sent success.", MAC2STR(queue.data.original_sender_mac), MAC2STR(queue.data.original_target_mac)); ESP_LOGI(TAG, "Outgoing ESP-NOW data from MAC %02X:%02X:%02X:%02X:%02X:%02X to MAC %02X:%02X:%02X:%02X:%02X:%02X processed success.", MAC2STR(queue.data.original_sender_mac), MAC2STR(queue.data.original_target_mac)); } - if (data->message_type == SEARCH_REQUEST) + if (queue.data.message_type == SEARCH_REQUEST) { ESP_LOGI(TAG, "System message for routing request from MAC %02X:%02X:%02X:%02X:%02X:%02X to MAC %02X:%02X:%02X:%02X:%02X:%02X sent success.", MAC2STR(queue.data.original_sender_mac), MAC2STR(queue.data.original_target_mac)); ESP_LOGI(TAG, "Outgoing ESP-NOW data from MAC %02X:%02X:%02X:%02X:%02X:%02X to MAC %02X:%02X:%02X:%02X:%02X:%02X processed success.", MAC2STR(queue.data.original_sender_mac), MAC2STR(queue.data.original_target_mac)); } - if (data->message_type == SEARCH_RESPONSE) + if (queue.data.message_type == SEARCH_RESPONSE) { ESP_LOGI(TAG, "System message for routing response from MAC %02X:%02X:%02X:%02X:%02X:%02X to MAC %02X:%02X:%02X:%02X:%02X:%02X sent success.", MAC2STR(queue.data.original_sender_mac), MAC2STR(queue.data.original_target_mac)); ESP_LOGI(TAG, "Outgoing ESP-NOW data from MAC %02X:%02X:%02X:%02X:%02X:%02X to MAC %02X:%02X:%02X:%02X:%02X:%02X processed success.", MAC2STR(queue.data.original_sender_mac), MAC2STR(queue.data.original_target_mac)); } - if (data->message_type == DELIVERY_CONFIRM) + if (queue.data.message_type == DELIVERY_CONFIRM) { ESP_LOGI(TAG, "System message for message receiving confirmation from MAC %02X:%02X:%02X:%02X:%02X:%02X to MAC %02X:%02X:%02X:%02X:%02X:%02X via MAC %02X:%02X:%02X:%02X:%02X:%02X sent success.", MAC2STR(queue.data.original_sender_mac), MAC2STR(queue.data.original_target_mac), MAC2STR(peer->peer_addr)); ESP_LOGI(TAG, "Outgoing ESP-NOW data from MAC %02X:%02X:%02X:%02X:%02X:%02X to MAC %02X:%02X:%02X:%02X:%02X:%02X processed success.", MAC2STR(queue.data.original_sender_mac), MAC2STR(queue.data.original_target_mac)); } - if (data->message_type == UNICAST) + if (queue.data.message_type == UNICAST) { ESP_LOGI(TAG, "Unicast message from MAC %02X:%02X:%02X:%02X:%02X:%02X to MAC %02X:%02X:%02X:%02X:%02X:%02X via MAC %02X:%02X:%02X:%02X:%02X:%02X sent success.", MAC2STR(queue.data.original_sender_mac), MAC2STR(queue.data.original_target_mac), MAC2STR(peer->peer_addr)); ESP_LOGI(TAG, "Outgoing ESP-NOW data from MAC %02X:%02X:%02X:%02X:%02X:%02X to MAC %02X:%02X:%02X:%02X:%02X:%02X processed success.", MAC2STR(queue.data.original_sender_mac), MAC2STR(queue.data.original_target_mac)); @@ -475,22 +486,27 @@ static void _processing(void *pvParameter) } else { - if (memcmp(data->original_target_mac, &_broadcast_mac, 6) != 0) + if (_attempts < _init_config.attempts) + { + goto SEND; + } + _attempts = 0; + if (memcmp(queue.data.original_target_mac, _broadcast_mac, 6) != 0) { ESP_LOGI(TAG, "Routing to MAC %02X:%02X:%02X:%02X:%02X:%02X via MAC %02X:%02X:%02X:%02X:%02X:%02X is incorrect.", MAC2STR(queue.data.original_target_mac), MAC2STR(peer->peer_addr)); for (uint16_t i = 0; i < zh_vector_get_size(&_route_vector); ++i) { - routing_table_t *routing_table = zh_vector_get_item(&_route_vector, i); - if (memcmp(data->original_target_mac, routing_table->original_target_mac, 6) == 0) + _routing_table_t *routing_table = zh_vector_get_item(&_route_vector, i); + if (memcmp(queue.data.original_target_mac, routing_table->original_target_mac, 6) == 0) { zh_vector_delete_item(&_route_vector, i); } } - if (data->message_type == UNICAST) + if (queue.data.message_type == UNICAST) { ESP_LOGI(TAG, "Unicast message from MAC %02X:%02X:%02X:%02X:%02X:%02X to MAC %02X:%02X:%02X:%02X:%02X:%02X transferred to routing waiting list.", MAC2STR(queue.data.original_sender_mac), MAC2STR(queue.data.original_target_mac)); } - if (data->message_type == DELIVERY_CONFIRM) + if (queue.data.message_type == DELIVERY_CONFIRM) { ESP_LOGI(TAG, "System message for message receiving confirmation from MAC %02X:%02X:%02X:%02X:%02X:%02X to MAC %02X:%02X:%02X:%02X:%02X:%02X transferred to routing waiting list.", MAC2STR(queue.data.original_sender_mac), MAC2STR(queue.data.original_target_mac)); } @@ -498,19 +514,19 @@ static void _processing(void *pvParameter) queue.time = esp_timer_get_time() / 1000; if (xQueueSend(_queue_handle, &queue, portTICK_PERIOD_MS) != pdTRUE) { - ESP_LOGE(TAG, "ESP-NOW message processing task internal error."); + ESP_LOGE(TAG, "ESP-NOW message processing task internal error at line %d.", __LINE__); } ESP_LOGI(TAG, "System message for routing request to MAC %02X:%02X:%02X:%02X:%02X:%02X added to queue.", MAC2STR(queue.data.original_target_mac)); queue.id = TO_SEND; - data->message_type = SEARCH_REQUEST; - memcpy(data->original_sender_mac, &_self_mac, 6); - data->data_len = 0; - memset(data->data, 0, ZH_NETWORK_MAX_MESSAGE_SIZE); - data->message_id = abs(esp_random()); // It is not clear why esp_random() sometimes gives negative values. + queue.data.message_type = SEARCH_REQUEST; + memcpy(queue.data.original_sender_mac, _self_mac, 6); + queue.data.payload_len = 0; + memset(queue.data.payload, 0, ZH_NETWORK_MAX_MESSAGE_SIZE); + queue.data.message_id = abs(esp_random()); // It is not clear why esp_random() sometimes gives negative values. ESP_LOGI(TAG, "Outgoing ESP-NOW data from MAC %02X:%02X:%02X:%02X:%02X:%02X to MAC %02X:%02X:%02X:%02X:%02X:%02X processed success.", MAC2STR(queue.data.original_sender_mac), MAC2STR(queue.data.original_target_mac)); if (xQueueSendToFront(_queue_handle, &queue, portTICK_PERIOD_MS) != pdTRUE) { - ESP_LOGE(TAG, "ESP-NOW message processing task internal error."); + ESP_LOGE(TAG, "ESP-NOW message processing task internal error at line %d.", __LINE__); } } } @@ -520,84 +536,84 @@ static void _processing(void *pvParameter) break; case ON_RECV: ESP_LOGI(TAG, "Incoming ESP-NOW data from MAC %02X:%02X:%02X:%02X:%02X:%02X to MAC %02X:%02X:%02X:%02X:%02X:%02X processing begin.", MAC2STR(queue.data.original_sender_mac), MAC2STR(queue.data.original_target_mac)); - switch (data->message_type) + switch (queue.data.message_type) { case BROADCAST: ESP_LOGI(TAG, "Broadcast message from MAC %02X:%02X:%02X:%02X:%02X:%02X to MAC %02X:%02X:%02X:%02X:%02X:%02X is received.", MAC2STR(queue.data.original_sender_mac), MAC2STR(queue.data.original_target_mac)); zh_network_event_on_recv_t *on_recv = heap_caps_malloc(sizeof(zh_network_event_on_recv_t), MALLOC_CAP_8BIT); if (on_recv == NULL) { - ESP_LOGE(TAG, "ESP-NOW message processing task internal error."); + ESP_LOGE(TAG, "ESP-NOW message processing task internal error at line %d.", __LINE__); heap_caps_free(on_recv); break; } memset(on_recv, 0, sizeof(zh_network_event_on_recv_t)); - memcpy(on_recv->mac_addr, data->original_sender_mac, 6); - on_recv->data_len = data->data_len; - on_recv->data = heap_caps_malloc(data->data_len, MALLOC_CAP_8BIT); + memcpy(on_recv->mac_addr, queue.data.original_sender_mac, 6); + on_recv->data_len = queue.data.payload_len; + on_recv->data = heap_caps_malloc(queue.data.payload_len, MALLOC_CAP_8BIT); if (on_recv->data == NULL) { - ESP_LOGE(TAG, "ESP-NOW message processing task internal error."); + ESP_LOGE(TAG, "ESP-NOW message processing task internal error at line %d.", __LINE__); heap_caps_free(on_recv); heap_caps_free(on_recv->data); break; } - memset(on_recv->data, 0, data->data_len); - memcpy(on_recv->data, data->data, data->data_len); + memset(on_recv->data, 0, queue.data.payload_len); + memcpy(on_recv->data, queue.data.payload, queue.data.payload_len); ESP_LOGI(TAG, "Broadcast message from MAC %02X:%02X:%02X:%02X:%02X:%02X to MAC %02X:%02X:%02X:%02X:%02X:%02X added to queue for resend to all nodes.", MAC2STR(queue.data.original_sender_mac), MAC2STR(queue.data.original_target_mac)); ESP_LOGI(TAG, "Incoming ESP-NOW data from MAC %02X:%02X:%02X:%02X:%02X:%02X to MAC %02X:%02X:%02X:%02X:%02X:%02X processed success.", MAC2STR(queue.data.original_sender_mac), MAC2STR(queue.data.original_target_mac)); if (esp_event_post(ZH_NETWORK, ZH_NETWORK_ON_RECV_EVENT, on_recv, sizeof(zh_network_event_on_recv_t) + on_recv->data_len + sizeof(on_recv->data_len), portTICK_PERIOD_MS) != ESP_OK) { - ESP_LOGE(TAG, "ESP-NOW message processing task internal error."); + ESP_LOGE(TAG, "ESP-NOW message processing task internal error at line %d.", __LINE__); } heap_caps_free(on_recv); queue.id = TO_SEND; if (xQueueSend(_queue_handle, &queue, portTICK_PERIOD_MS) != pdTRUE) { - ESP_LOGE(TAG, "ESP-NOW message processing task internal error."); + ESP_LOGE(TAG, "ESP-NOW message processing task internal error at line %d.", __LINE__); } break; case UNICAST: ESP_LOGI(TAG, "Unicast message from MAC %02X:%02X:%02X:%02X:%02X:%02X to MAC %02X:%02X:%02X:%02X:%02X:%02X is received.", MAC2STR(queue.data.original_sender_mac), MAC2STR(queue.data.original_target_mac)); - if (memcmp(data->original_target_mac, &_self_mac, 6) == 0) + if (memcmp(queue.data.original_target_mac, _self_mac, 6) == 0) { zh_network_event_on_recv_t *on_recv = heap_caps_malloc(sizeof(zh_network_event_on_recv_t), MALLOC_CAP_8BIT); if (on_recv == NULL) { - ESP_LOGE(TAG, "ESP-NOW message processing task internal error."); + ESP_LOGE(TAG, "ESP-NOW message processing task internal error at line %d.", __LINE__); heap_caps_free(on_recv); break; } memset(on_recv, 0, sizeof(zh_network_event_on_recv_t)); - memcpy(on_recv->mac_addr, data->original_sender_mac, 6); - on_recv->data_len = data->data_len; - on_recv->data = heap_caps_malloc(data->data_len, MALLOC_CAP_8BIT); + memcpy(on_recv->mac_addr, queue.data.original_sender_mac, 6); + on_recv->data_len = queue.data.payload_len; + on_recv->data = heap_caps_malloc(queue.data.payload_len, MALLOC_CAP_8BIT); if (on_recv->data == NULL) { - ESP_LOGE(TAG, "ESP-NOW message processing task internal error."); + ESP_LOGE(TAG, "ESP-NOW message processing task internal error at line %d.", __LINE__); heap_caps_free(on_recv); heap_caps_free(on_recv->data); break; } - memset(on_recv->data, 0, data->data_len); - memcpy(on_recv->data, data->data, data->data_len); + memset(on_recv->data, 0, queue.data.payload_len); + memcpy(on_recv->data, queue.data.payload, queue.data.payload_len); ESP_LOGI(TAG, "Incoming ESP-NOW data from MAC %02X:%02X:%02X:%02X:%02X:%02X to MAC %02X:%02X:%02X:%02X:%02X:%02X processed success.", MAC2STR(queue.data.original_sender_mac), MAC2STR(queue.data.original_target_mac)); if (esp_event_post(ZH_NETWORK, ZH_NETWORK_ON_RECV_EVENT, on_recv, sizeof(zh_network_event_on_recv_t) + on_recv->data_len + sizeof(on_recv->data_len), portTICK_PERIOD_MS) != ESP_OK) { - ESP_LOGE(TAG, "ESP-NOW message processing task internal error."); + ESP_LOGE(TAG, "ESP-NOW message processing task internal error at line %d.", __LINE__); } heap_caps_free(on_recv); queue.id = TO_SEND; - data->message_type = DELIVERY_CONFIRM; - memcpy(data->original_target_mac, data->original_sender_mac, 6); - memcpy(data->original_sender_mac, &_self_mac, 6); - data->data_len = 0; - memset(data->data, 0, ZH_NETWORK_MAX_MESSAGE_SIZE); - data->confirm_id = data->message_id; - data->message_id = abs(esp_random()); // It is not clear why esp_random() sometimes gives negative values. + queue.data.message_type = DELIVERY_CONFIRM; + memcpy(queue.data.original_target_mac, queue.data.original_sender_mac, 6); + memcpy(queue.data.original_sender_mac, _self_mac, 6); + queue.data.payload_len = 0; + memset(queue.data.payload, 0, ZH_NETWORK_MAX_MESSAGE_SIZE); + queue.data.confirm_id = queue.data.message_id; + queue.data.message_id = abs(esp_random()); // It is not clear why esp_random() sometimes gives negative values. if (xQueueSendToFront(_queue_handle, &queue, portTICK_PERIOD_MS) != pdTRUE) { - ESP_LOGE(TAG, "ESP-NOW message processing task internal error."); + ESP_LOGE(TAG, "ESP-NOW message processing task internal error at line %d.", __LINE__); } break; } @@ -606,14 +622,14 @@ static void _processing(void *pvParameter) queue.id = TO_SEND; if (xQueueSendToFront(_queue_handle, &queue, portTICK_PERIOD_MS) != pdTRUE) { - ESP_LOGE(TAG, "ESP-NOW message processing task internal error."); + ESP_LOGE(TAG, "ESP-NOW message processing task internal error at line %d.", __LINE__); } break; case DELIVERY_CONFIRM: ESP_LOGI(TAG, "System message for message receiving confirmation from MAC %02X:%02X:%02X:%02X:%02X:%02X to MAC %02X:%02X:%02X:%02X:%02X:%02X is received.", MAC2STR(queue.data.original_sender_mac), MAC2STR(queue.data.original_target_mac)); - if (memcmp(data->original_target_mac, &_self_mac, 6) == 0) + if (memcmp(queue.data.original_target_mac, _self_mac, 6) == 0) { - zh_vector_push_back(&_response_vector, &data->confirm_id); + zh_vector_push_back(&_response_vector, &queue.data.confirm_id); if (zh_vector_get_size(&_response_vector) > _init_config.queue_size) { zh_vector_delete_item(&_response_vector, 0); @@ -626,43 +642,43 @@ static void _processing(void *pvParameter) queue.id = TO_SEND; if (xQueueSendToFront(_queue_handle, &queue, portTICK_PERIOD_MS) != pdTRUE) { - ESP_LOGE(TAG, "ESP-NOW message processing task internal error."); + ESP_LOGE(TAG, "ESP-NOW message processing task internal error at line %d.", __LINE__); } break; case SEARCH_REQUEST: ESP_LOGI(TAG, "System message for routing request from MAC %02X:%02X:%02X:%02X:%02X:%02X to MAC %02X:%02X:%02X:%02X:%02X:%02X is received.", MAC2STR(queue.data.original_sender_mac), MAC2STR(queue.data.original_target_mac)); for (uint16_t i = 0; i < zh_vector_get_size(&_route_vector); ++i) { - routing_table_t *routing_table = zh_vector_get_item(&_route_vector, i); - if (memcmp(data->original_target_mac, routing_table->original_target_mac, 6) == 0) + _routing_table_t *routing_table = zh_vector_get_item(&_route_vector, i); + if (memcmp(queue.data.original_target_mac, routing_table->original_target_mac, 6) == 0) { zh_vector_delete_item(&_route_vector, i); } } { // Just to avoid the compiler warning. - routing_table_t routing_table = {0}; - memcpy(&routing_table.original_target_mac, data->original_sender_mac, 6); - memcpy(&routing_table.intermediate_target_mac, data->sender_mac, 6); + _routing_table_t routing_table = {0}; + memcpy(routing_table.original_target_mac, queue.data.original_sender_mac, 6); + memcpy(routing_table.intermediate_target_mac, queue.data.sender_mac, 6); zh_vector_push_back(&_route_vector, &routing_table); } if (zh_vector_get_size(&_route_vector) > _init_config.route_vector_size) { zh_vector_delete_item(&_route_vector, 0); } - if (memcmp(data->original_target_mac, &_self_mac, 6) == 0) + if (memcmp(queue.data.original_target_mac, _self_mac, 6) == 0) { ESP_LOGI(TAG, "System message for routing response from MAC %02X:%02X:%02X:%02X:%02X:%02X to MAC %02X:%02X:%02X:%02X:%02X:%02X added to the queue.", MAC2STR(queue.data.original_target_mac), MAC2STR(queue.data.original_sender_mac)); queue.id = TO_SEND; - data->message_type = SEARCH_RESPONSE; - memcpy(data->original_target_mac, data->original_sender_mac, 6); - memcpy(data->original_sender_mac, &_self_mac, 6); - data->data_len = 0; - memset(data->data, 0, ZH_NETWORK_MAX_MESSAGE_SIZE); - data->message_id = abs(esp_random()); // It is not clear why esp_random() sometimes gives negative values. + queue.data.message_type = SEARCH_RESPONSE; + memcpy(queue.data.original_target_mac, queue.data.original_sender_mac, 6); + memcpy(queue.data.original_sender_mac, _self_mac, 6); + queue.data.payload_len = 0; + memset(queue.data.payload, 0, ZH_NETWORK_MAX_MESSAGE_SIZE); + queue.data.message_id = abs(esp_random()); // It is not clear why esp_random() sometimes gives negative values. ESP_LOGI(TAG, "Incoming ESP-NOW data from MAC %02X:%02X:%02X:%02X:%02X:%02X to MAC %02X:%02X:%02X:%02X:%02X:%02X processed success.", MAC2STR(queue.data.original_sender_mac), MAC2STR(queue.data.original_target_mac)); if (xQueueSendToFront(_queue_handle, &queue, portTICK_PERIOD_MS) != pdTRUE) { - ESP_LOGE(TAG, "ESP-NOW message processing task internal error."); + ESP_LOGE(TAG, "ESP-NOW message processing task internal error at line %d.", __LINE__); } break; } @@ -671,37 +687,37 @@ static void _processing(void *pvParameter) queue.id = TO_SEND; if (xQueueSendToFront(_queue_handle, &queue, portTICK_PERIOD_MS) != pdTRUE) { - ESP_LOGE(TAG, "ESP-NOW message processing task internal error."); + ESP_LOGE(TAG, "ESP-NOW message processing task internal error at line %d.", __LINE__); } break; case SEARCH_RESPONSE: ESP_LOGI(TAG, "System message for routing response from MAC %02X:%02X:%02X:%02X:%02X:%02X to MAC %02X:%02X:%02X:%02X:%02X:%02X is received.", MAC2STR(queue.data.original_sender_mac), MAC2STR(queue.data.original_target_mac)); for (uint16_t i = 0; i < zh_vector_get_size(&_route_vector); ++i) { - routing_table_t *routing_table = zh_vector_get_item(&_route_vector, i); - if (memcmp(data->original_target_mac, routing_table->original_target_mac, 6) == 0) + _routing_table_t *routing_table = zh_vector_get_item(&_route_vector, i); + if (memcmp(queue.data.original_target_mac, routing_table->original_target_mac, 6) == 0) { zh_vector_delete_item(&_route_vector, i); } } { // Just to avoid the compiler warning. - routing_table_t routing_table = {0}; - memcpy(&routing_table.original_target_mac, data->original_sender_mac, 6); - memcpy(&routing_table.intermediate_target_mac, data->sender_mac, 6); + _routing_table_t routing_table = {0}; + memcpy(routing_table.original_target_mac, queue.data.original_sender_mac, 6); + memcpy(routing_table.intermediate_target_mac, queue.data.sender_mac, 6); zh_vector_push_back(&_route_vector, &routing_table); } if (zh_vector_get_size(&_route_vector) > _init_config.route_vector_size) { zh_vector_delete_item(&_route_vector, 0); } - if (memcmp(data->original_target_mac, &_self_mac, 6) != 0) + if (memcmp(queue.data.original_target_mac, _self_mac, 6) != 0) { ESP_LOGI(TAG, "System message for routing response from MAC %02X:%02X:%02X:%02X:%02X:%02X to MAC %02X:%02X:%02X:%02X:%02X:%02X added to queue for resend to all nodes.", MAC2STR(queue.data.original_sender_mac), MAC2STR(queue.data.original_target_mac)); ESP_LOGI(TAG, "Incoming ESP-NOW data from MAC %02X:%02X:%02X:%02X:%02X:%02X to MAC %02X:%02X:%02X:%02X:%02X:%02X processed success.", MAC2STR(queue.data.original_sender_mac), MAC2STR(queue.data.original_target_mac)); queue.id = TO_SEND; if (xQueueSendToFront(_queue_handle, &queue, portTICK_PERIOD_MS) != pdTRUE) { - ESP_LOGE(TAG, "ESP-NOW message processing task internal error."); + ESP_LOGE(TAG, "ESP-NOW message processing task internal error at line %d.", __LINE__); } break; } @@ -715,24 +731,24 @@ static void _processing(void *pvParameter) for (uint16_t i = 0; i < zh_vector_get_size(&_response_vector); ++i) { uint32_t *message_id = zh_vector_get_item(&_response_vector, i); - if (memcmp(&data->message_id, message_id, sizeof(data->message_id)) == 0) + if (memcmp(&queue.data.message_id, message_id, sizeof(queue.data.message_id)) == 0) { zh_vector_delete_item(&_response_vector, i); zh_network_event_on_send_t *on_send = heap_caps_malloc(sizeof(zh_network_event_on_send_t), MALLOC_CAP_8BIT); if (on_send == NULL) { - ESP_LOGE(TAG, "ESP-NOW message processing task internal error."); + ESP_LOGE(TAG, "ESP-NOW message processing task internal error at line %d.", __LINE__); heap_caps_free(on_send); break; } memset(on_send, 0, sizeof(zh_network_event_on_send_t)); - memcpy(on_send->mac_addr, data->original_target_mac, 6); + memcpy(on_send->mac_addr, queue.data.original_target_mac, 6); on_send->status = ZH_NETWORK_SEND_SUCCESS; ESP_LOGI(TAG, "Unicast message from MAC %02X:%02X:%02X:%02X:%02X:%02X to MAC %02X:%02X:%02X:%02X:%02X:%02X sent success.", MAC2STR(queue.data.original_sender_mac), MAC2STR(queue.data.original_target_mac)); ESP_LOGI(TAG, "Unicast message from MAC %02X:%02X:%02X:%02X:%02X:%02X to MAC %02X:%02X:%02X:%02X:%02X:%02X removed from confirmation message waiting list.", MAC2STR(queue.data.original_sender_mac), MAC2STR(queue.data.original_target_mac)); if (esp_event_post(ZH_NETWORK, ZH_NETWORK_ON_SEND_EVENT, on_send, sizeof(zh_network_event_on_send_t), portTICK_PERIOD_MS) != ESP_OK) { - ESP_LOGE(TAG, "ESP-NOW message processing task internal error."); + ESP_LOGE(TAG, "ESP-NOW message processing task internal error at line %d.", __LINE__); } heap_caps_free(on_send); flag = true; @@ -744,23 +760,23 @@ static void _processing(void *pvParameter) if ((esp_timer_get_time() / 1000 - queue.time) > _init_config.max_waiting_time) { ESP_LOGW(TAG, "Time for waiting confirmation message from MAC %02X:%02X:%02X:%02X:%02X:%02X is expired.", MAC2STR(queue.data.original_target_mac)); - if (memcmp(data->original_sender_mac, &_self_mac, 6) == 0) + if (memcmp(queue.data.original_sender_mac, _self_mac, 6) == 0) { zh_network_event_on_send_t *on_send = heap_caps_malloc(sizeof(zh_network_event_on_send_t), MALLOC_CAP_8BIT); if (on_send == NULL) { - ESP_LOGE(TAG, "ESP-NOW message processing task internal error."); + ESP_LOGE(TAG, "ESP-NOW message processing task internal error at line %d.", __LINE__); heap_caps_free(on_send); break; } memset(on_send, 0, sizeof(zh_network_event_on_send_t)); - memcpy(on_send->mac_addr, data->original_target_mac, 6); + memcpy(on_send->mac_addr, queue.data.original_target_mac, 6); on_send->status = ZH_NETWORK_SEND_FAIL; ESP_LOGE(TAG, "Unicast message from MAC %02X:%02X:%02X:%02X:%02X:%02X to MAC %02X:%02X:%02X:%02X:%02X:%02X sent fail.", MAC2STR(queue.data.original_sender_mac), MAC2STR(queue.data.original_target_mac)); ESP_LOGI(TAG, "Unicast message from MAC %02X:%02X:%02X:%02X:%02X:%02X to MAC %02X:%02X:%02X:%02X:%02X:%02X removed from confirmation message waiting list.", MAC2STR(queue.data.original_sender_mac), MAC2STR(queue.data.original_target_mac)); if (esp_event_post(ZH_NETWORK, ZH_NETWORK_ON_SEND_EVENT, on_send, sizeof(zh_network_event_on_send_t), portTICK_PERIOD_MS) != ESP_OK) { - ESP_LOGE(TAG, "ESP-NOW message processing task internal error."); + ESP_LOGE(TAG, "ESP-NOW message processing task internal error at line %d.", __LINE__); } heap_caps_free(on_send); } @@ -768,29 +784,29 @@ static void _processing(void *pvParameter) } if (xQueueSend(_queue_handle, &queue, portTICK_PERIOD_MS) != pdTRUE) { - ESP_LOGE(TAG, "ESP-NOW message processing task internal error."); + ESP_LOGE(TAG, "ESP-NOW message processing task internal error at line %d.", __LINE__); } } break; case WAIT_ROUTE: for (uint16_t i = 0; i < zh_vector_get_size(&_route_vector); ++i) { - routing_table_t *routing_table = zh_vector_get_item(&_route_vector, i); - if (memcmp(data->original_target_mac, routing_table->original_target_mac, 6) == 0) + _routing_table_t *routing_table = zh_vector_get_item(&_route_vector, i); + if (memcmp(queue.data.original_target_mac, routing_table->original_target_mac, 6) == 0) { ESP_LOGI(TAG, "Routing to MAC %02X:%02X:%02X:%02X:%02X:%02X is received.", MAC2STR(queue.data.original_target_mac)); - if (data->message_type == UNICAST) + if (queue.data.message_type == UNICAST) { ESP_LOGI(TAG, "Unicast message from MAC %02X:%02X:%02X:%02X:%02X:%02X to MAC %02X:%02X:%02X:%02X:%02X:%02X removed from routing waiting list and added to queue.", MAC2STR(queue.data.original_sender_mac), MAC2STR(queue.data.original_target_mac)); } - if (data->message_type == DELIVERY_CONFIRM) + if (queue.data.message_type == DELIVERY_CONFIRM) { ESP_LOGI(TAG, "System message for message receiving confirmation from MAC %02X:%02X:%02X:%02X:%02X:%02X to MAC %02X:%02X:%02X:%02X:%02X:%02X removed from routing waiting list and added to queue.", MAC2STR(queue.data.original_sender_mac), MAC2STR(queue.data.original_target_mac)); } queue.id = TO_SEND; if (xQueueSend(_queue_handle, &queue, portTICK_PERIOD_MS) != pdTRUE) { - ESP_LOGE(TAG, "ESP-NOW message processing task internal error."); + ESP_LOGE(TAG, "ESP-NOW message processing task internal error at line %d.", __LINE__); } flag = true; break; @@ -801,33 +817,33 @@ static void _processing(void *pvParameter) if ((esp_timer_get_time() / 1000 - queue.time) > _init_config.max_waiting_time) { ESP_LOGW(TAG, "Time for waiting routing to MAC %02X:%02X:%02X:%02X:%02X:%02X is expired.", MAC2STR(queue.data.original_target_mac)); - if (memcmp(data->original_sender_mac, &_self_mac, 6) == 0) + if (memcmp(queue.data.original_sender_mac, _self_mac, 6) == 0) { zh_network_event_on_send_t *on_send = heap_caps_malloc(sizeof(zh_network_event_on_send_t), MALLOC_CAP_8BIT); if (on_send == NULL) { - ESP_LOGE(TAG, "ESP-NOW message processing task internal error."); + ESP_LOGE(TAG, "ESP-NOW message processing task internal error at line %d.", __LINE__); heap_caps_free(on_send); break; } memset(on_send, 0, sizeof(zh_network_event_on_send_t)); - memcpy(on_send->mac_addr, data->original_target_mac, 6); + memcpy(on_send->mac_addr, queue.data.original_target_mac, 6); on_send->status = ZH_NETWORK_SEND_FAIL; ESP_LOGE(TAG, "Unicast message from MAC %02X:%02X:%02X:%02X:%02X:%02X to MAC %02X:%02X:%02X:%02X:%02X:%02X sent fail.", MAC2STR(queue.data.original_sender_mac), MAC2STR(queue.data.original_target_mac)); ESP_LOGI(TAG, "Unicast message from MAC %02X:%02X:%02X:%02X:%02X:%02X to MAC %02X:%02X:%02X:%02X:%02X:%02X removed from routing waiting list.", MAC2STR(queue.data.original_sender_mac), MAC2STR(queue.data.original_target_mac)); if (esp_event_post(ZH_NETWORK, ZH_NETWORK_ON_SEND_EVENT, on_send, sizeof(zh_network_event_on_send_t), portTICK_PERIOD_MS) != ESP_OK) { - ESP_LOGE(TAG, "ESP-NOW message processing task internal error."); + ESP_LOGE(TAG, "ESP-NOW message processing task internal error at line %d.", __LINE__); } heap_caps_free(on_send); } else { - if (data->message_type == UNICAST) + if (queue.data.message_type == UNICAST) { ESP_LOGI(TAG, "Unicast message from MAC %02X:%02X:%02X:%02X:%02X:%02X to MAC %02X:%02X:%02X:%02X:%02X:%02X removed from routing waiting list.", MAC2STR(queue.data.original_sender_mac), MAC2STR(queue.data.original_target_mac)); } - if (data->message_type == DELIVERY_CONFIRM) + if (queue.data.message_type == DELIVERY_CONFIRM) { ESP_LOGI(TAG, "System message for message receiving confirmation from MAC %02X:%02X:%02X:%02X:%02X:%02X to MAC %02X:%02X:%02X:%02X:%02X:%02X removed from routing waiting list.", MAC2STR(queue.data.original_sender_mac), MAC2STR(queue.data.original_target_mac)); } @@ -836,7 +852,7 @@ static void _processing(void *pvParameter) } if (xQueueSend(_queue_handle, &queue, portTICK_PERIOD_MS) != pdTRUE) { - ESP_LOGE(TAG, "ESP-NOW message processing task internal error."); + ESP_LOGE(TAG, "ESP-NOW message processing task internal error at line %d.", __LINE__); } } break; diff --git a/zh_network.zip b/zh_network.zip new file mode 100644 index 0000000000000000000000000000000000000000..06c8831893efcc5bef30df6447a0868d848b343f GIT binary patch literal 15381 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