From c2243dfa4f5b67440d832573eaf40bd4156dec16 Mon Sep 17 00:00:00 2001 From: Alexey Zholtikov Date: Sun, 6 Apr 2025 12:43:01 +0300 Subject: [PATCH] feat: initial --- .gitignore | 6 +- CMakeLists.txt | 2 +- README.md | 75 +++++++++++++++++- include/main.h | 0 include/zh_vector.h | 115 +++++++++++++++++++++++++++ main.c | 0 version.txt | 1 + zh_vector.c | 188 ++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 379 insertions(+), 8 deletions(-) delete mode 100644 include/main.h create mode 100644 include/zh_vector.h delete mode 100644 main.c create mode 100644 zh_vector.c diff --git a/.gitignore b/.gitignore index 65225d8..496ee2c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1 @@ -.DS_Store -.vscode -build -sdkconfig -sdkconfig.old \ No newline at end of file +.DS_Store \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 9ab5c51..403c1c5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1 +1 @@ -idf_component_register(SRCS "main.c" INCLUDE_DIRS "include") \ No newline at end of file +idf_component_register(SRCS "zh_vector.c" INCLUDE_DIRS "include") \ No newline at end of file diff --git a/README.md b/README.md index 3df3e4d..12355b6 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,74 @@ -# esp_component_template +# ESP32 ESP-IDF and ESP8266 RTOS SDK component for vector (dynamic array) -esp_component_template \ No newline at end of file +## Tested on + +1. ESP8266 RTOS_SDK v3.4 +2. ESP32 ESP-IDF v5.4 + +## Features + +1. Support of any data types. +2. The maximum size of the veсtor is 65535 elements. + +## Using + +In an existing project, run the following command to install the component: + +```text +cd ../your_project/components +git clone http://git.zh.com.ru/alexey.zholtikov/zh_vector +``` + +In the application, add the component: + +```c +#include "zh_vector.h" +``` + +## Example + +Create, add, read, modify and delete items: + +```c +#include "zh_vector.h" + +zh_vector_t vector = {0}; + +char example[10] = {0}; + +void app_main(void) +{ + esp_log_level_set("zh_vector", ESP_LOG_NONE); + zh_vector_init(&vector, sizeof(example)); + printf("Initial vector size is: %d\n", zh_vector_get_size(&vector)); + strcpy(example, "Item 1"); + zh_vector_push_back(&vector, &example); + strcpy(example, "Item 2"); + zh_vector_push_back(&vector, &example); + strcpy(example, "Item 3"); + zh_vector_push_back(&vector, &example); + strcpy(example, "Item 4"); + zh_vector_push_back(&vector, &example); + strcpy(example, "Item 5"); + zh_vector_push_back(&vector, &example); + printf("Add 5 items. New vector size is: %d\n", zh_vector_get_size(&vector)); + for (uint16_t i = 0; i < zh_vector_get_size(&vector); ++i) + { + printf("Item position %d is: %s\n", i, (char *)zh_vector_get_item(&vector, i)); + } + strcpy(example, "Item 6"); + zh_vector_change_item(&vector, 3, &example); + printf("Change item on 3 position.\n"); + for (uint16_t i = 0; i < zh_vector_get_size(&vector); ++i) + { + printf("Item position %d is: %s\n", i, (char *)zh_vector_get_item(&vector, i)); + } + zh_vector_delete_item(&vector, 2); + printf("Delete item on 2 position. New vector size is: %d\n", zh_vector_get_size(&vector)); + for (uint16_t i = 0; i < zh_vector_get_size(&vector); ++i) + { + printf("Item position %d is: %s\n", i, (char *)zh_vector_get_item(&vector, i)); + } + zh_vector_free(&vector); +} +``` diff --git a/include/main.h b/include/main.h deleted file mode 100644 index e69de29..0000000 diff --git a/include/zh_vector.h b/include/zh_vector.h new file mode 100644 index 0000000..5aa5a93 --- /dev/null +++ b/include/zh_vector.h @@ -0,0 +1,115 @@ +#pragma once + +#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 65535. + bool status; // Vector initialization status flag. @note Used to prevent execution of vector functions without prior vector initialization. + } zh_vector_t; + + /** + * @brief Initialize vector. + * + * @param[in] vector Pointer to main structure of vector data. + * @param[in] unit Size of vector item. + * + * @return + * - ESP_OK if initialization was success + * - ESP_ERR_INVALID_ARG if parameter error + * - ESP_ERR_INVALID_STATE if vector already initialized + */ + esp_err_t zh_vector_init(zh_vector_t *vector, uint16_t unit); + + /** + * @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/main.c b/main.c deleted file mode 100644 index e69de29..0000000 diff --git a/version.txt b/version.txt index e69de29..afaf360 100644 --- a/version.txt +++ b/version.txt @@ -0,0 +1 @@ +1.0.0 \ No newline at end of file diff --git a/zh_vector.c b/zh_vector.c new file mode 100644 index 0000000..0863374 --- /dev/null +++ b/zh_vector.c @@ -0,0 +1,188 @@ +#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) +{ + 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) + { + ESP_LOGE(TAG, "Vector initialization fail. Vector already initialized."); + return ESP_ERR_INVALID_STATE; + } + vector->capacity = 0; + vector->size = 0; + vector->unit = unit; + vector->status = true; + ESP_LOGI(TAG, "Vector initialization success."); + 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; + } + } + vector->items[vector->size] = heap_caps_calloc(1, 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; + } + 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; + } +} + +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) + { + vector->items = heap_caps_realloc(vector->items, sizeof(void *) * capacity, MALLOC_CAP_8BIT); + 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->capacity = capacity; + ESP_LOGI(TAG, "Vector resize success. New capacity: %d.", vector->capacity); + return ESP_OK; +} \ No newline at end of file