From 99d760729409c19f852ba694b32f0a422d37a0ca Mon Sep 17 00:00:00 2001 From: Conner Date: Fri, 11 Oct 2024 20:25:58 +0200 Subject: [PATCH] components --- embedded/components/network/CMakeLists.txt | 6 + embedded/components/network/component.mk | 0 .../components/network/include/zh_network.h | 127 +++ embedded/components/network/zh_network.c | 904 ++++++++++++++++++ embedded/components/vector/CMakeLists.txt | 1 + embedded/components/vector/component.mk | 0 .../components/vector/include/zh_vector.h | 122 +++ embedded/components/vector/zh_vector.c | 242 +++++ embedded/components/zh_network | 1 - embedded/components/zh_vector | 1 - 10 files changed, 1402 insertions(+), 2 deletions(-) create mode 100644 embedded/components/network/CMakeLists.txt create mode 100644 embedded/components/network/component.mk create mode 100644 embedded/components/network/include/zh_network.h create mode 100644 embedded/components/network/zh_network.c create mode 100644 embedded/components/vector/CMakeLists.txt create mode 100644 embedded/components/vector/component.mk create mode 100644 embedded/components/vector/include/zh_vector.h create mode 100644 embedded/components/vector/zh_vector.c delete mode 160000 embedded/components/zh_network delete mode 160000 embedded/components/zh_vector diff --git a/embedded/components/network/CMakeLists.txt b/embedded/components/network/CMakeLists.txt new file mode 100644 index 0000000..6f262bd --- /dev/null +++ b/embedded/components/network/CMakeLists.txt @@ -0,0 +1,6 @@ +if(${IDF_TARGET} STREQUAL esp8266) + set(requires zh_vector) +else() + set(requires zh_vector esp_timer esp_wifi) +endif() +idf_component_register(SRCS "zh_network.c" INCLUDE_DIRS "include" REQUIRES ${requires}) \ No newline at end of file diff --git a/embedded/components/network/component.mk b/embedded/components/network/component.mk new file mode 100644 index 0000000..e69de29 diff --git a/embedded/components/network/include/zh_network.h b/embedded/components/network/include/zh_network.h new file mode 100644 index 0000000..d30d948 --- /dev/null +++ b/embedded/components/network/include/zh_network.h @@ -0,0 +1,127 @@ +#pragma once + +#include "string.h" +#include "esp_err.h" +#include "esp_timer.h" +#include "esp_wifi.h" +#include "esp_now.h" +#include "freertos/FreeRTOS.h" +#include "freertos/event_groups.h" +#include "esp_log.h" +#include "esp_heap_caps.h" +#include "zh_vector.h" +#ifdef CONFIG_IDF_TARGET_ESP8266 +#include "esp_system.h" +#else +#include "esp_random.h" +#include "esp_mac.h" +#endif + +#define ZH_NETWORK_MAX_MESSAGE_SIZE 218 // Maximum value of the transmitted data size. @attention All devices on the network must have the same ZH_NETWORK_MAX_MESSAGE_SIZE. + +#define ZH_NETWORK_INIT_CONFIG_DEFAULT() \ + { \ + .network_id = 0xFAFBFCFD, \ + .task_priority = 4, \ + .stack_size = 3072, \ + .queue_size = 32, \ + .max_waiting_time = 1000, \ + .id_vector_size = 100, \ + .route_vector_size = 100, \ + .wifi_interface = WIFI_IF_STA, \ + .wifi_channel = 1, \ + .attempts = 3 \ + } + +#ifdef __cplusplus +extern "C" +{ +#endif + + typedef struct // Structure for initial initialization of ESP-NOW interface. + { + uint32_t network_id; // A unique ID for the mesh network. @attention The ID must be the same for all nodes in the network. + uint8_t task_priority; // Task priority for the ESP-NOW messages processing. @note It is not recommended to set a value less than 4. + uint16_t stack_size; // Stack size for task for the ESP-NOW messages processing. @note The minimum size is 3072 bytes. + 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. It is not recommended to set the value less than 32. + uint16_t max_waiting_time; // Maximum time to wait a response message from target node (in milliseconds). @note If a response message from the target node is not received within this time, the status of the sent message will be "sent fail". + 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; + + ESP_EVENT_DECLARE_BASE(ZH_NETWORK); + + typedef enum // Enumeration of possible ESP-NOW events. + { + ZH_NETWORK_ON_RECV_EVENT, // The event when the ESP-NOW message was received. + ZH_NETWORK_ON_SEND_EVENT // The event when the ESP-NOW message was sent. + } zh_network_event_type_t; + + typedef enum // Enumeration of possible status of sent ESP-NOW message. + { + ZH_NETWORK_SEND_SUCCESS, // If ESP-NOW message was sent success. + ZH_NETWORK_SEND_FAIL // If ESP-NOW message was sent fail. + } zh_network_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_NETWORK event base and ZH_NETWORK_ON_SEND_EVENT event. + { + uint8_t mac_addr[6]; // MAC address of the device to which the ESP-NOW message was sent. + zh_network_on_send_event_type_t status; // Status of sent ESP-NOW message. + } zh_network_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_NETWORK event base and ZH_NETWORK_ON_RECV_EVENT event. + { + uint8_t mac_addr[6]; // MAC address of the sender ESP-NOW message. + uint8_t *data; // Pointer to the data of the received ESP-NOW message. + uint8_t data_len; // Size of the received ESP-NOW message. + } zh_network_event_on_recv_t; + + /** + * @brief Initialize ESP-NOW interface. + * + * @note Before initialize ESP-NOW interface recommend initialize zh_network_init_config_t structure with default values. + * + * @code zh_network_init_config_t config = ZH_NETWORK_INIT_CONFIG_DEFAULT() @endcode + * + * @param[in] config Pointer to ESP-NOW initialized configuration structure. Can point to a temporary variable. + * + * @return + * - ESP_OK if initialization was success + * - ESP_ERR_INVALID_ARG if parameter error + * - ESP_ERR_WIFI_NOT_INIT if WiFi is not initialized + * - ESP_FAIL if any internal error + */ + esp_err_t zh_network_init(const zh_network_init_config_t *config); + + /** + * @brief Deinitialize ESP-NOW interface. + * + * @return + * - ESP_OK if deinitialization was success + * - ESP_FAIL if ESP-NOW is not initialized + */ + esp_err_t zh_network_deinit(void); + + /** + * @brief Send ESP-NOW data. + * + * @param[in] target Pointer to a buffer containing an eight-byte target MAC. Can be NULL for broadcast. + * @param[in] data Pointer to a buffer containing the data for send. + * @param[in] data_len Sending data length. + * + * @note The function will return an ESP_ERR_INVALID_STATE error if less than 50% of the size set at initialization remains in the message queue. + * + * @return + * - 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 or any internal error + */ + esp_err_t zh_network_send(const uint8_t *target, const uint8_t *data, const uint8_t data_len); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/embedded/components/network/zh_network.c b/embedded/components/network/zh_network.c new file mode 100644 index 0000000..7054915 --- /dev/null +++ b/embedded/components/network/zh_network.c @@ -0,0 +1,904 @@ +#include "zh_network.h" + +#define DATA_SEND_SUCCESS BIT0 +#define DATA_SEND_FAIL BIT1 +#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] + +static void _send_cb(const uint8_t *mac_addr, esp_now_send_status_t status); +#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 +static void _processing(void *pvParameter); + +static const char *TAG = "zh_network"; + +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}; +static zh_network_init_config_t _init_config = {0}; +static zh_vector_t _id_vector = {0}; +static zh_vector_t _session_vector = {0}; +static zh_vector_t _route_vector = {0}; +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; + +typedef struct +{ + uint8_t original_target_mac[6]; + uint8_t intermediate_target_mac[6]; +} _routing_table_t; + +typedef struct +{ + uint64_t time; + 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); + +esp_err_t zh_network_init(const zh_network_init_config_t *config) +{ + ESP_LOGI(TAG, "ESP-NOW initialization begin."); + if (config == NULL) + { + ESP_LOGE(TAG, "ESP-NOW initialization fail. Invalid argument."); + return ESP_ERR_INVALID_ARG; + } + _init_config = *config; + if (_init_config.wifi_channel < 1 || _init_config.wifi_channel > 14) + { + ESP_LOGE(TAG, "ESP-NOW initialization fail. WiFi channel incorrect."); + 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; + } + 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; + } + if (_init_config.wifi_interface == WIFI_IF_STA) + { + esp_read_mac(_self_mac, ESP_MAC_WIFI_STA); + } + else + { + esp_read_mac(_self_mac, ESP_MAC_WIFI_SOFTAP); + } + _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(&_session_vector, sizeof(uint32_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) + { + ESP_LOGE(TAG, "ESP-NOW initialization fail. Internal error."); + return ESP_FAIL; + } + if (xTaskCreatePinnedToCore(&_processing, "NULL", _init_config.stack_size, NULL, _init_config.task_priority, &_processing_task_handle, tskNO_AFFINITY) != pdPASS) + { + ESP_LOGE(TAG, "ESP-NOW initialization fail. Internal error."); + return ESP_FAIL; + } + _is_initialized = true; + ESP_LOGI(TAG, "ESP-NOW initialization success."); + return ESP_OK; +} + +esp_err_t zh_network_deinit(void) +{ + ESP_LOGI(TAG, "ESP-NOW deinitialization begin."); + if (_is_initialized == false) + { + ESP_LOGE(TAG, "ESP-NOW deinitialization fail. ESP-NOW not initialized."); + return ESP_FAIL; + } + vEventGroupDelete(_event_group_handle); + vQueueDelete(_queue_handle); + esp_now_unregister_send_cb(); + esp_now_unregister_recv_cb(); + esp_now_deinit(); + zh_vector_free(&_id_vector); + zh_vector_free(&_route_vector); + zh_vector_free(&_response_vector); + vTaskDelete(_processing_task_handle); + _is_initialized = false; + ESP_LOGI(TAG, "ESP-NOW deinitialization success."); + return ESP_OK; +} + +esp_err_t zh_network_send(const uint8_t *target, const uint8_t *data, const uint8_t data_len) +{ + if (target == NULL) + { + ESP_LOGI(TAG, "Adding outgoing ESP-NOW data to MAC FF:FF:FF:FF:FF:FF to queue begin."); + } + else + { + ESP_LOGI(TAG, "Adding outgoing ESP-NOW data to MAC %02X:%02X:%02X:%02X:%02X:%02X to queue begin.", MAC2STR(target)); + } + if (_is_initialized == false) + { + ESP_LOGE(TAG, "Adding outgoing ESP-NOW data to queue fail. ESP-NOW not initialized."); + return ESP_FAIL; + } + if (data_len == 0 || data == NULL || data_len > ZH_NETWORK_MAX_MESSAGE_SIZE) + { + ESP_LOGE(TAG, "Adding outgoing ESP-NOW data to queue fail. Invalid argument."); + return ESP_ERR_INVALID_ARG; + } + if (uxQueueSpacesAvailable(_queue_handle) < _init_config.queue_size / 2) + { + 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.id = TO_SEND; + 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) + { + queue.data.message_type = BROADCAST; + memcpy(queue.data.original_target_mac, _broadcast_mac, 6); + } + else + { + if (memcmp(target, _broadcast_mac, 6) != 0) + { + queue.data.message_type = UNICAST; + memcpy(queue.data.original_target_mac, target, 6); + } + else + { + queue.data.message_type = BROADCAST; + memcpy(queue.data.original_target_mac, _broadcast_mac, 6); + } + } + 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."); + } + else + { + ESP_LOGI(TAG, "Adding outgoing ESP-NOW data to MAC %02X:%02X:%02X:%02X:%02X:%02X to queue success.", MAC2STR(target)); + } + if (xQueueSend(_queue_handle, &queue, portTICK_PERIOD_MS) != pdTRUE) + { + ESP_LOGE(TAG, "ESP-NOW message processing task internal error at line %d.", __LINE__); + return ESP_FAIL; + } + return ESP_OK; +} + +static void _send_cb(const uint8_t *mac_addr, esp_now_send_status_t status) +{ + if (status == ESP_NOW_SEND_SUCCESS) + { + xEventGroupSetBits(_event_group_handle, DATA_SEND_SUCCESS); + } + else + { + xEventGroupSetBits(_event_group_handle, DATA_SEND_FAIL); + } +} + +#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 +{ +#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)); +#endif + if (uxQueueSpacesAvailable(_queue_handle) < (_init_config.queue_size - 2)) + { + ESP_LOGW(TAG, "Adding incoming ESP-NOW data to queue fail. Queue is almost full."); + return; + } + if (data_len == sizeof(_queue_t) - 14) + { + _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; + } + 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(&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; + } + } + if (xSemaphoreTake(_id_vector_mutex, portTICK_PERIOD_MS) == pdTRUE) + { + 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); + } +#if defined CONFIG_IDF_TARGET_ESP8266 || ESP_IDF_VERSION_MAJOR == 4 + memcpy(queue.data.sender_mac, mac_addr, 6); +#else + memcpy(queue.data.sender_mac, esp_now_info->src_addr, 6); +#endif +#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 at line %d.", __LINE__); + } + } + else + { + ESP_LOGW(TAG, "Adding incoming ESP-NOW data to queue fail. Incorrect ESP-NOW data size."); + } +} + +static void _processing(void *pvParameter) +{ + _queue_t queue = {0}; + while (xQueueReceive(_queue_handle, &queue, portMAX_DELAY) == pdTRUE) + { + bool flag = false; + switch (queue.id) + { + case TO_SEND: + ESP_LOGI(TAG, "Outgoing 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)); + esp_now_peer_info_t *peer = heap_caps_malloc(sizeof(esp_now_peer_info_t), MALLOC_CAP_8BIT); + if (peer == NULL) + { + ESP_LOGE(TAG, "Outgoing ESP-NOW data processing fail. Memory allocation fail or no free memory in the heap."); + heap_caps_free(peer); + break; + } + memset(peer, 0, sizeof(esp_now_peer_info_t)); + peer->ifidx = _init_config.wifi_interface; + 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(queue.data.original_sender_mac, _self_mac, 6) == 0) + { + if (xSemaphoreTake(_id_vector_mutex, portTICK_PERIOD_MS) == pdTRUE) + { + 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); + } + } + } + else + { + ESP_LOGI(TAG, "Checking routing table to MAC %02X:%02X:%02X:%02X:%02X:%02X.", MAC2STR(queue.data.original_target_mac)); + int64_t route_time = esp_timer_get_time(); + printf("-------------\n"); + 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); + printf("%02X:%02X:%02X:%02X:%02X:%02X -> %02X:%02X:%02X:%02X:%02X:%02X\n", MAC2STR(routing_table->original_target_mac), MAC2STR(routing_table->intermediate_target_mac)); + 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; + ESP_LOGI(TAG, "Routing to MAC %02X:%02X:%02X:%02X:%02X:%02X is found. Forwarding via MAC %02X:%02X:%02X:%02X:%02X:%02X.", MAC2STR(queue.data.original_target_mac), MAC2STR(peer->peer_addr)); + printf("found route in cache"); + break; + } + } + route_time = esp_timer_get_time() - route_time; + printf("Took: %lld\n", route_time); + if (flag == false) + { + ESP_LOGI(TAG, "Routing to MAC %02X:%02X:%02X:%02X:%02X:%02X not found.", MAC2STR(queue.data.original_target_mac)); + 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)); + } + else + { + 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)); + } + queue.id = WAIT_ROUTE; + 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 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; + 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 at line %d.", __LINE__); + } + heap_caps_free(peer); + break; + } + } + if (esp_now_add_peer(peer) != ESP_OK) + { + ESP_LOGE(TAG, "Outgoing ESP-NOW data processing fail. Internal error with adding peer."); + heap_caps_free(peer); + break; + } + 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, "Outgoing ESP-NOW data processing fail. Memory allocation fail or no free memory in the heap."); + heap_caps_free(peer); + heap_caps_free(on_send); + break; + } + memset(on_send, 0, sizeof(zh_network_event_on_send_t)); + 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 at line %d.", __LINE__); + heap_caps_free(peer); + heap_caps_free(on_send); + break; + } + 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) + { + _attempts = 0; + if (memcmp(queue.data.original_sender_mac, _self_mac, 6) == 0) + { + if (queue.data.message_type == BROADCAST) + { + printf("BROADCAST STARTED"); + 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 at line %d.", __LINE__); + } + } + if (queue.data.message_type == SEARCH_REQUEST) + { + printf("SEARCH REQUEST SENT"); + 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 (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 (queue.data.message_type == DELIVERY_CONFIRM) + { + printf("Sent Delivery Confirm: %d", queue.data.message_id); + 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 (queue.data.message_type == UNICAST) + { + printf("Queued waiting for response"); + 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)); + 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)); + queue.id = WAIT_RESPONSE; + queue.time = esp_timer_get_time() / 1000; + zh_vector_push_back(&_session_vector, &queue.data.message_id); + if (xQueueSend(_queue_handle, &queue, portTICK_PERIOD_MS) != pdTRUE) + { + ESP_LOGE(TAG, "ESP-NOW message processing task internal error at line %d.", __LINE__); + } + } + } + else + { + 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 (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 (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 (queue.data.message_type == DELIVERY_CONFIRM) + { + printf("Sent Delivery Confirm: %d\n", queue.data.message_id); + 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 (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)); + } + } + } + else + { + 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(queue.data.original_target_mac, routing_table->original_target_mac, 6) == 0) + { + zh_vector_delete_item(&_route_vector, i); + } + } + 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 (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)); + } + queue.id = WAIT_ROUTE; + 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 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; + 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 at line %d.", __LINE__); + } + } + } + esp_now_del_peer(peer->peer_addr); + heap_caps_free(on_send); + heap_caps_free(peer); + 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 (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 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, 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 at line %d.", __LINE__); + heap_caps_free(on_recv); + heap_caps_free(on_recv->data); + break; + } + 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 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 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(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 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, 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 at line %d.", __LINE__); + heap_caps_free(on_recv); + heap_caps_free(on_recv->data); + break; + } + 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 at line %d.", __LINE__); + } + heap_caps_free(on_recv); + queue.id = TO_SEND; + 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 at line %d.", __LINE__); + } + break; + } + ESP_LOGI(TAG, "Unicast message from MAC %02X:%02X:%02X:%02X:%02X:%02X to MAC %02X:%02X:%02X:%02X:%02X:%02X added to queue for forwarding.", 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 at line %d.", __LINE__); + } + break; + case DELIVERY_CONFIRM: + printf("Received Delivery Confirm: %d\n", queue.data.message_id); + 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(queue.data.original_target_mac, _self_mac, 6) == 0) + { + for (uint16_t i = 0; i < zh_vector_get_size(&_session_vector); ++i) + { + uint32_t *message_id = zh_vector_get_item(&_session_vector, i); + if (memcmp(&queue.data.confirm_id, message_id, sizeof(uint32_t)) == 0) + { + printf("SESSION MATCHED\n"); + + 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); + } + 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)); + break; + } + } + break; + } + ESP_LOGI(TAG, "System message for message receiving confirmation from MAC %02X:%02X:%02X:%02X:%02X:%02X fto MAC %02X:%02X:%02X:%02X:%02X:%02X added to queue for forwarding.", 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 at line %d.", __LINE__); + } + break; + case SEARCH_REQUEST: + printf("SEARCH REQUEST RECEIVED\n"); + 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(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, 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(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; + 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 at line %d.", __LINE__); + } + break; + } + ESP_LOGI(TAG, "System message for routing request to MAC %02X:%02X:%02X:%02X:%02X:%02X from MAC %02X:%02X:%02X:%02X:%02X:%02X added to queue for resend to all nodes.", MAC2STR(queue.data.original_target_mac), MAC2STR(queue.data.original_sender_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 at line %d.", __LINE__); + } + break; + case SEARCH_RESPONSE: + printf("Received Search Response\n"); + 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(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, 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(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 at line %d.", __LINE__); + } + break; + } + 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)); + break; + default: + break; + } + break; + case WAIT_RESPONSE: + printf("WAIT_RESPONSE queue entry: %d\n", zh_vector_get_size(&_response_vector)); + 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(&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 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, 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 at line %d.", __LINE__); + } + heap_caps_free(on_send); + flag = true; + for (uint16_t i = 0; i < zh_vector_get_size(&_session_vector); ++i) + { + uint32_t *message_id = zh_vector_get_item(&_session_vector, i); + if (memcmp(&queue.data.message_id, message_id, sizeof(uint32_t)) == 0) + { + zh_vector_delete_item(&_session_vector, i); + printf("FREED SESSION: %d\n", queue.data.message_id); + break; + } + } + break; + } + } + if (flag == false) + { + 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)); + for (uint16_t i = 0; i < zh_vector_get_size(&_session_vector); ++i) + { + uint32_t *message_id = zh_vector_get_item(&_session_vector, i); + if (memcmp(&queue.data.message_id, message_id, sizeof(uint32_t)) == 0) + { + zh_vector_delete_item(&_session_vector, i); + printf("FREED SESSION: %d\n", queue.data.message_id); + break; + } + } + 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 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, 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 at line %d.", __LINE__); + } + heap_caps_free(on_send); + } + break; + } + if (xQueueSend(_queue_handle, &queue, portTICK_PERIOD_MS) != pdTRUE) + { + ESP_LOGE(TAG, "ESP-NOW message processing task internal error at line %d.", __LINE__); + } + } + break; + case WAIT_ROUTE: + printf("Wait Route Queue Entry\n"); + 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(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 (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 (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 at line %d.", __LINE__); + } + flag = true; + break; + } + } + if (flag == false) + { + 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(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 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, 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 at line %d.", __LINE__); + } + heap_caps_free(on_send); + } + else + { + 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 (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)); + } + } + break; + } + if (xQueueSend(_queue_handle, &queue, portTICK_PERIOD_MS) != pdTRUE) + { + ESP_LOGE(TAG, "ESP-NOW message processing task internal error at line %d.", __LINE__); + } + } + break; + default: + break; + } + } + vTaskDelete(NULL); +} \ No newline at end of file diff --git a/embedded/components/vector/CMakeLists.txt b/embedded/components/vector/CMakeLists.txt new file mode 100644 index 0000000..403c1c5 --- /dev/null +++ b/embedded/components/vector/CMakeLists.txt @@ -0,0 +1 @@ +idf_component_register(SRCS "zh_vector.c" INCLUDE_DIRS "include") \ No newline at end of file diff --git a/embedded/components/vector/component.mk b/embedded/components/vector/component.mk new file mode 100644 index 0000000..e69de29 diff --git a/embedded/components/vector/include/zh_vector.h b/embedded/components/vector/include/zh_vector.h new file mode 100644 index 0000000..d773c5d --- /dev/null +++ b/embedded/components/vector/include/zh_vector.h @@ -0,0 +1,122 @@ +#pragma once + +#include "stdlib.h" +#include "string.h" +#include "esp_err.h" +#include "esp_log.h" +#include "esp_heap_caps.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + + typedef struct // Main structure of vector data. + { + void **items; // Array of pointers of vector items. + uint16_t capacity; // Maximum capacity of the vector. @note Used to control the size of allocated memory for array of pointers of vector items. Usually equal to the current number of items in the vector. Automatically changes when items are added or deleted. + uint16_t size; // Number of items in the vector. @note Can be read with zh_vector_get_size(). + uint16_t unit; // Vector item size. @note Possible values from 1 to 65536. + bool status; // Vector initialization status flag. @note Used to prevent execution of vector functions without prior vector initialization. + bool spi_ram; // SPI RAM using status flag. @note True - vector will be placed in SPI RAM, false - vector will be placed in RAM. + } zh_vector_t; + + /** + * @brief Initialize vector. + * + * @param[in] vector Pointer to main structure of vector data. + * @param[in] unit Size of vector item. + * @param[in] spiram SPI RAM using (true - vector will be placed in SPI RAM, false - vector will be placed in RAM). + * + * @attention For using SPI RAM select “Make RAM allocatable using heap_caps_malloc(…, MALLOC_CAP_SPIRAM)” from CONFIG_SPIRAM_USE. For ESP32 with external, SPI-connected RAM only. + * + * @note If SPI RAM is not supported or not initialised via menuconfig vector will be placed in RAM regardless of the set spiram value. + * + * @return + * - ESP_OK if initialization was success + * - ESP_ERR_INVALID_ARG if parameter error + * - ESP_ERR_INVALID_STATE if vector already initialized with other item size + */ + esp_err_t zh_vector_init(zh_vector_t *vector, uint16_t unit, bool spiram); + + /** + * @brief Deinitialize vector. Free all allocated memory. + * + * @param[in] vector Pointer to main structure of vector data. + * + * @return + * - ESP_OK if deinitialization was success + * - ESP_ERR_INVALID_ARG if parameter error + * - ESP_ERR_INVALID_STATE if vector not initialized + */ + esp_err_t zh_vector_free(zh_vector_t *vector); + + /** + * @brief Get current vector size. + * + * @param[in] vector Pointer to main structure of vector data. + * + * @return + * - Vector size + * - ESP_FAIL if parameter error or vector not initialized + */ + esp_err_t zh_vector_get_size(zh_vector_t *vector); + + /** + * @brief Add item at end of vector. + * + * @param[in] vector Pointer to main structure of vector data. + * @param[in] item Pointer to item for add. + * + * @return + * - ESP_OK if add was success + * - ESP_ERR_INVALID_ARG if parameter error + * - ESP_ERR_NO_MEM if memory allocation fail or no free memory in the heap + * - ESP_ERR_INVALID_STATE if vector not initialized + */ + esp_err_t zh_vector_push_back(zh_vector_t *vector, void *item); + + /** + * @brief Change item by index. + * + * @param[in] vector Pointer to main structure of vector data. + * @param[in] index Index of item for change. + * @param[in] item Pointer to new data of item. + * + * @return + * - ESP_OK if change was success + * - ESP_ERR_INVALID_ARG if parameter error + * - ESP_ERR_INVALID_STATE if vector not initialized + * - ESP_FAIL if index does not exist + */ + esp_err_t zh_vector_change_item(zh_vector_t *vector, uint16_t index, void *item); + + /** + * @brief Get item by index. + * + * @param[in] vector Pointer to main structure of vector data. + * @param[in] index Index of item for get. + * + * @return + * - Pointer to item + * - NULL if parameter error or vector not initialized or if index does not exist + */ + void *zh_vector_get_item(zh_vector_t *vector, uint16_t index); + + /** + * @brief Delete item by index and shifts all elements in vector. + * + * @param[in] vector Pointer to main structure of vector data. + * @param[in] index Index of item for delete. + * + * @return + * - ESP_OK if delete was success + * - ESP_ERR_INVALID_ARG if parameter error + * - ESP_ERR_INVALID_STATE if vector not initialized + * - ESP_FAIL if index does not exist + */ + esp_err_t zh_vector_delete_item(zh_vector_t *vector, uint16_t index); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/embedded/components/vector/zh_vector.c b/embedded/components/vector/zh_vector.c new file mode 100644 index 0000000..a8e9907 --- /dev/null +++ b/embedded/components/vector/zh_vector.c @@ -0,0 +1,242 @@ +#include "zh_vector.h" + +static const char *TAG = "zh_vector"; + +static esp_err_t _resize(zh_vector_t *vector, uint16_t capacity); + +esp_err_t zh_vector_init(zh_vector_t *vector, uint16_t unit, bool spiram) +{ + ESP_LOGI(TAG, "Vector initialization begin."); + if (vector == NULL || unit == 0) + { + ESP_LOGE(TAG, "Vector initialization fail. Invalid argument."); + return ESP_ERR_INVALID_ARG; + } + if (vector->status == true) + { + if (vector->unit == unit) + { + goto ZH_VECTOR_INIT_EXIT; + } + else + { + ESP_LOGE(TAG, "Vector initialization fail. Vector already initialized with other item size."); + return ESP_ERR_INVALID_STATE; + } + } + vector->capacity = 0; + vector->size = 0; + vector->unit = unit; + vector->status = true; + vector->spi_ram = spiram; + if (vector->spi_ram == true) + { +#ifdef CONFIG_IDF_TARGET_ESP8266 + ESP_LOGW(TAG, "SPI RAM not supported. Will be used IRAM."); + vector->spi_ram = false; +#else +#ifndef CONFIG_SPIRAM + ESP_LOGW(TAG, "SPI RAM not initialized. Will be used IRAM."); + vector->spi_ram = false; +#endif +#endif + } +ZH_VECTOR_INIT_EXIT: + if (vector->spi_ram == true) + { + ESP_LOGI(TAG, "Vector initialization success. Vector located in SPI RAM."); + } + else + { + ESP_LOGI(TAG, "Vector initialization success. Vector located in IRAM."); + } + return ESP_OK; +} + +esp_err_t zh_vector_free(zh_vector_t *vector) +{ + ESP_LOGI(TAG, "Vector deletion begin."); + if (vector == NULL) + { + ESP_LOGE(TAG, "Vector deletion fail. Invalid argument."); + return ESP_ERR_INVALID_ARG; + } + if (vector->status == false) + { + ESP_LOGE(TAG, "Vector deletion fail. Vector not initialized."); + return ESP_ERR_INVALID_STATE; + } + for (uint16_t i = 0; i < vector->size; ++i) + { + heap_caps_free(vector->items[i]); + } + vector->status = false; + ESP_LOGI(TAG, "Vector deletion success."); + return ESP_OK; +} + +esp_err_t zh_vector_get_size(zh_vector_t *vector) +{ + /*ESP_LOGI(TAG, "Getting vector size begin."); + if (vector == NULL || vector->status == false) + { + ESP_LOGE(TAG, "Getting vector size fail. Invalid argument or vector not initialized."); + return ESP_FAIL; + } + ESP_LOGI(TAG, "Getting vector size success. Size: %d", vector->size);*/ + return vector->size; +} + +esp_err_t zh_vector_push_back(zh_vector_t *vector, void *item) +{ + ESP_LOGI(TAG, "Adding item to vector begin."); + if (vector == NULL || item == NULL) + { + ESP_LOGE(TAG, "Adding item to vector fail. Invalid argument."); + return ESP_ERR_INVALID_ARG; + } + if (vector->status == false) + { + ESP_LOGE(TAG, "Adding item to vector fail. Vector not initialized."); + return ESP_ERR_INVALID_STATE; + } + if (vector->capacity == vector->size) + { + if (_resize(vector, vector->capacity + 1) == ESP_ERR_NO_MEM) + { + ESP_LOGE(TAG, "Adding item to vector fail. Memory allocation fail or no free memory in the heap."); + return ESP_ERR_NO_MEM; + } + } + if (vector->spi_ram == true) + { + vector->items[vector->size] = heap_caps_malloc(vector->unit, MALLOC_CAP_SPIRAM); + } + else + { + if (vector->unit / sizeof(void *) == 0) + { + vector->items[vector->size] = heap_caps_malloc(vector->unit, MALLOC_CAP_32BIT); + } + else + { + vector->items[vector->size] = heap_caps_malloc(vector->unit, MALLOC_CAP_8BIT); + } + } + if (vector->items[vector->size] == NULL) + { + ESP_LOGE(TAG, "Adding item to vector fail. Memory allocation fail or no free memory in the heap."); + return ESP_ERR_NO_MEM; + } + memset(vector->items[vector->size], 0, vector->unit); + memcpy(vector->items[vector->size++], item, vector->unit); + ESP_LOGI(TAG, "Adding item to vector success."); + return ESP_OK; +} + +esp_err_t zh_vector_change_item(zh_vector_t *vector, uint16_t index, void *item) +{ + ESP_LOGI(TAG, "Changing item in vector begin."); + if (vector == NULL || item == NULL) + { + ESP_LOGE(TAG, "Changing item in vector fail. Invalid argument."); + return ESP_ERR_INVALID_ARG; + } + if (vector->status == false) + { + ESP_LOGE(TAG, "Changing item in vector fail. Vector not initialized."); + return ESP_ERR_INVALID_STATE; + } + if (index < vector->size) + { + memcpy(vector->items[index], item, vector->unit); + ESP_LOGI(TAG, "Changing item in vector success."); + return ESP_OK; + } + ESP_LOGE(TAG, "Changing item in vector fail. Index does not exist."); + return ESP_FAIL; +} + +void *zh_vector_get_item(zh_vector_t *vector, uint16_t index) +{ + /*ESP_LOGI(TAG, "Getting item from vector begin."); + if (vector == NULL) + { + ESP_LOGE(TAG, "Getting item from vector fail. Invalid argument."); + return NULL; + } + if (vector->status == false) + { + ESP_LOGE(TAG, "Getting item from vector fail. Vector not initialized."); + return NULL; + } + if (index < vector->size) + { + void *item = vector->items[index]; + ESP_LOGI(TAG, "Getting item from vector success."); + return item; + } + else + { + ESP_LOGE(TAG, "Getting item from vector fail. Index does not exist."); + return NULL; + }*/ + void *item = vector->items[index]; + return item; +} + +esp_err_t zh_vector_delete_item(zh_vector_t *vector, uint16_t index) +{ + ESP_LOGI(TAG, "Deleting item in vector begin."); + if (vector == NULL) + { + ESP_LOGE(TAG, "Deleting item in vector fail. Invalid argument."); + return ESP_ERR_INVALID_ARG; + } + if (vector->status == false) + { + ESP_LOGE(TAG, "Deleting item in vector fail. Vector not initialized."); + return ESP_ERR_INVALID_STATE; + } + if (index < vector->size) + { + heap_caps_free(vector->items[index]); + for (uint8_t i = index; i < (vector->size - 1); ++i) + { + vector->items[i] = vector->items[i + 1]; + vector->items[i + 1] = NULL; + } + --vector->size; + _resize(vector, vector->capacity - 1); + ESP_LOGI(TAG, "Deleting item in vector success."); + return ESP_OK; + } + ESP_LOGE(TAG, "Deleting item in vector fail. Index does not exist."); + return ESP_FAIL; +} + +static esp_err_t _resize(zh_vector_t *vector, uint16_t capacity) +{ + ESP_LOGI(TAG, "Vector resize begin."); + if (capacity == 0) + { + goto VECTOR_RESIZE_EXIT; + } + if (vector->spi_ram == true) + { + vector->items = heap_caps_realloc(vector->items, sizeof(void *) * capacity, MALLOC_CAP_SPIRAM); + } + else + { + vector->items = heap_caps_realloc(vector->items, sizeof(void *) * capacity, MALLOC_CAP_32BIT); + } + if (vector->items == NULL) + { + ESP_LOGE(TAG, "Vector resize fail. Memory allocation fail or no free memory in the heap."); + return ESP_ERR_NO_MEM; + } +VECTOR_RESIZE_EXIT: + vector->capacity = capacity; + ESP_LOGI(TAG, "Vector resize success. New capacity: %d", vector->capacity); + return ESP_OK; +} \ No newline at end of file diff --git a/embedded/components/zh_network b/embedded/components/zh_network deleted file mode 160000 index ebe0b8c..0000000 --- a/embedded/components/zh_network +++ /dev/null @@ -1 +0,0 @@ -Subproject commit ebe0b8cbf52c97b532c620b57ef0a3da7869228a diff --git a/embedded/components/zh_vector b/embedded/components/zh_vector deleted file mode 160000 index 4e0c0a6..0000000 --- a/embedded/components/zh_vector +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 4e0c0a6623afc0eb0816b0447d8567bf6867247c