From d08d54596987f30ee5ec450470621ba7c5145016 Mon Sep 17 00:00:00 2001 From: Benign X <1341398182@qq.com> Date: Thu, 19 Sep 2024 17:14:24 +0800 Subject: [PATCH] feat(circle_buff): add lv_circle_buf_t component --- lvgl.h | 1 + src/misc/lv_array.c | 33 ++- src/misc/lv_array.h | 15 +- src/misc/lv_circle_buf.c | 296 +++++++++++++++++++++++++ src/misc/lv_circle_buf.h | 191 ++++++++++++++++ src/misc/lv_types.h | 2 + tests/src/test_cases/test_circle_buf.c | 167 ++++++++++++++ 7 files changed, 700 insertions(+), 5 deletions(-) create mode 100644 src/misc/lv_circle_buf.c create mode 100644 src/misc/lv_circle_buf.h create mode 100644 tests/src/test_cases/test_circle_buf.c diff --git a/lvgl.h b/lvgl.h index bbb5d0bd8..dbc757046 100644 --- a/lvgl.h +++ b/lvgl.h @@ -34,6 +34,7 @@ extern "C" { #include "src/misc/lv_rb.h" #include "src/misc/lv_utils.h" #include "src/misc/lv_iter.h" +#include "src/misc/lv_circle_buf.h" #include "src/tick/lv_tick.h" diff --git a/src/misc/lv_array.c b/src/misc/lv_array.c index 1080cda99..9376fb3bc 100644 --- a/src/misc/lv_array.c +++ b/src/misc/lv_array.c @@ -42,13 +42,25 @@ void lv_array_init(lv_array_t * array, uint32_t capacity, uint32_t element_size) array->element_size = element_size; array->data = lv_malloc(capacity * element_size); + array->inner_alloc = true; LV_ASSERT_MALLOC(array->data); } +void lv_array_init_from_buf(lv_array_t * array, void * buf, uint32_t capacity, uint32_t element_size) +{ + LV_ASSERT_NULL(buf); + array->size = 0; + array->capacity = capacity; + array->element_size = element_size; + + array->data = buf; + array->inner_alloc = false; +} + void lv_array_deinit(lv_array_t * array) { if(array->data) { - lv_free(array->data); + if(array->inner_alloc) lv_free(array->data); array->data = NULL; } @@ -122,15 +134,24 @@ lv_result_t lv_array_erase(lv_array_t * array, uint32_t start, uint32_t end) return LV_RESULT_OK; } -void lv_array_resize(lv_array_t * array, uint32_t new_capacity) +bool lv_array_resize(lv_array_t * array, uint32_t new_capacity) { + if(array->inner_alloc == false) { + LV_LOG_WARN("Cannot resize array with external buffer"); + return false; + } + uint8_t * data = lv_realloc(array->data, new_capacity * array->element_size); LV_ASSERT_NULL(data); + + if(data == NULL) return false; + array->data = data; array->capacity = new_capacity; if(array->size > new_capacity) { array->size = new_capacity; } + return true; } lv_result_t lv_array_concat(lv_array_t * array, const lv_array_t * other) @@ -139,7 +160,9 @@ lv_result_t lv_array_concat(lv_array_t * array, const lv_array_t * other) uint32_t size = other->size; if(array->size + size > array->capacity) { /*array is full*/ - lv_array_resize(array, array->size + size); + if(lv_array_resize(array, array->size + size) == false) { + return LV_RESULT_INVALID; + } } uint8_t * data = array->data + array->size * array->element_size; @@ -154,7 +177,9 @@ lv_result_t lv_array_push_back(lv_array_t * array, const void * element) if(array->size == array->capacity) { /*array is full*/ - lv_array_resize(array, array->capacity + LV_ARRAY_DEFAULT_CAPACITY); + if(lv_array_resize(array, array->capacity + LV_ARRAY_DEFAULT_CAPACITY) == false) { + return LV_RESULT_INVALID; + } } /** diff --git a/src/misc/lv_array.h b/src/misc/lv_array.h index 5eee02f2b..78f7ac3d8 100644 --- a/src/misc/lv_array.h +++ b/src/misc/lv_array.h @@ -37,6 +37,8 @@ struct _lv_array_t { uint32_t size; uint32_t capacity; uint32_t element_size; + + bool inner_alloc; /* true: data is allocated by the array; false: data is allocated by the user */ }; /********************** @@ -51,13 +53,24 @@ struct _lv_array_t { */ void lv_array_init(lv_array_t * array, uint32_t capacity, uint32_t element_size); +/** + * Init an array from a buffer. + * @note The buffer must be large enough to store `capacity` elements. The array will not release the buffer and reallocate it. + * The user must ensure that the buffer is valid during the lifetime of the array. And release the buffer when the array is no longer needed. + * @param array pointer to an `lv_array_t` variable to initialize + * @param buf pointer to a buffer to use as the array's data + * @param capacity the initial capacity of the array + * @param element_size the size of an element in bytes + */ +void lv_array_init_from_buf(lv_array_t * array, void * buf, uint32_t capacity, uint32_t element_size); + /** * Resize the array to the given capacity. * @note if the new capacity is smaller than the current size, the array will be truncated. * @param array pointer to an `lv_array_t` variable * @param new_capacity the new capacity of the array */ -void lv_array_resize(lv_array_t * array, uint32_t new_capacity); +bool lv_array_resize(lv_array_t * array, uint32_t new_capacity); /** * Deinit the array, and free the allocated memory diff --git a/src/misc/lv_circle_buf.c b/src/misc/lv_circle_buf.c new file mode 100644 index 000000000..1380f5674 --- /dev/null +++ b/src/misc/lv_circle_buf.c @@ -0,0 +1,296 @@ +/** + * @file lv_circle_buf.c + * + */ + +/********************* + * INCLUDES + *********************/ + +#include "lv_assert.h" + +#include "lv_circle_buf.h" +#include "lv_array.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +struct _lv_circle_buf_t { + lv_array_t array; + uint32_t head; + uint32_t tail; /**< The next write position */ + + bool inner_alloc; /**< true: the array is allocated by the buffer, false: the array is created from an external buffer */ +}; + +/********************** + * STATIC PROTOTYPES + **********************/ + +static void circle_buf_prepare_empty(lv_circle_buf_t * circle_buf); + +/********************** + * GLOBAL VARIABLES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +lv_circle_buf_t * lv_circle_buf_create(const uint32_t capacity, const uint32_t element_size) +{ + lv_circle_buf_t * circle_buf = lv_malloc(sizeof(lv_circle_buf_t)); + LV_ASSERT_MALLOC(circle_buf); + + if(circle_buf == NULL) { + return NULL; + } + + lv_array_init(&circle_buf->array, capacity, element_size); + circle_buf->head = 0; + circle_buf->tail = 0; + circle_buf->inner_alloc = true; + + circle_buf_prepare_empty(circle_buf); + + return circle_buf; +} + +lv_circle_buf_t * lv_circle_buf_create_from_buf(void * buf, const uint32_t capacity, const uint32_t element_size) +{ + LV_ASSERT_NULL(buf); + + lv_circle_buf_t * circle_buf = lv_malloc(sizeof(lv_circle_buf_t)); + LV_ASSERT_MALLOC(circle_buf); + + if(circle_buf == NULL) { + return NULL; + } + + lv_array_init_from_buf(&circle_buf->array, buf, capacity, element_size); + circle_buf->head = 0; + circle_buf->tail = 0; + circle_buf->inner_alloc = false; + + circle_buf_prepare_empty(circle_buf); + + return circle_buf; +} + +lv_circle_buf_t * lv_circle_buf_create_from_array(const lv_array_t * array) +{ + LV_ASSERT_NULL(array); + if(array == NULL) { + return NULL; + } + + lv_circle_buf_t * circle_buf = lv_malloc(sizeof(lv_circle_buf_t)); + LV_ASSERT_MALLOC(circle_buf); + + if(circle_buf == NULL) { + return NULL; + } + + circle_buf->array = *array; + circle_buf->head = 0; + circle_buf->tail = 0; + circle_buf->inner_alloc = false; + + circle_buf_prepare_empty(circle_buf); + + return circle_buf; +} + +lv_result_t lv_circle_buf_resize(lv_circle_buf_t * circle_buf, const uint32_t capacity) +{ + LV_ASSERT_NULL(circle_buf); + + if(lv_array_resize(&circle_buf->array, capacity) == false) { + return LV_RESULT_INVALID; + } + + circle_buf->head = 0; + circle_buf->tail = 0; + + circle_buf_prepare_empty(circle_buf); + + return LV_RESULT_OK; +} + +void lv_circle_buf_destroy(lv_circle_buf_t * circle_buf) +{ + LV_ASSERT_NULL(circle_buf); + + lv_array_deinit(&circle_buf->array); + + lv_free(circle_buf); +} + +uint32_t lv_circle_buf_size(const lv_circle_buf_t * circle_buf) +{ + LV_ASSERT_NULL(circle_buf); + + return circle_buf->tail - circle_buf->head; +} + +uint32_t lv_circle_buf_capacity(const lv_circle_buf_t * circle_buf) +{ + LV_ASSERT_NULL(circle_buf); + + return lv_array_capacity(&circle_buf->array); +} + +uint32_t lv_circle_buf_remain(const lv_circle_buf_t * circle_buf) +{ + LV_ASSERT_NULL(circle_buf); + + return lv_circle_buf_capacity(circle_buf) - lv_circle_buf_size(circle_buf); +} + +bool lv_circle_buf_is_empty(const lv_circle_buf_t * circle_buf) +{ + LV_ASSERT_NULL(circle_buf); + + return !lv_circle_buf_size(circle_buf); +} + +bool lv_circle_buf_is_full(const lv_circle_buf_t * circle_buf) +{ + LV_ASSERT_NULL(circle_buf); + + return !lv_circle_buf_remain(circle_buf); +} + +void lv_circle_buf_reset(lv_circle_buf_t * circle_buf) +{ + LV_ASSERT_NULL(circle_buf); + + lv_array_clear(&circle_buf->array); + circle_buf->head = 0; + circle_buf->tail = 0; +} + +void * lv_circle_buf_head(const lv_circle_buf_t * circle_buf) +{ + LV_ASSERT_NULL(circle_buf); + + return lv_array_at(&circle_buf->array, + circle_buf->head % lv_circle_buf_capacity(circle_buf)); +} + +void * lv_circle_buf_tail(const lv_circle_buf_t * circle_buf) +{ + LV_ASSERT_NULL(circle_buf); + + return lv_array_at(&circle_buf->array, + circle_buf->tail % lv_circle_buf_capacity(circle_buf)); +} + +lv_result_t lv_circle_buf_read(lv_circle_buf_t * circle_buf, void * data) +{ + LV_ASSERT_NULL(circle_buf); + + if(lv_circle_buf_is_empty(circle_buf)) { + circle_buf->head = 0; + circle_buf->tail = 0; + return LV_RESULT_INVALID; + } + + lv_circle_buf_peek_at(circle_buf, 0, data); + circle_buf->head++; + + return LV_RESULT_OK; +} + +lv_result_t lv_circle_buf_write(lv_circle_buf_t * circle_buf, const void * data) +{ + LV_ASSERT_NULL(circle_buf); + + if(lv_circle_buf_is_full(circle_buf)) { + return LV_RESULT_INVALID; + } + + lv_array_assign(&circle_buf->array, circle_buf->tail % lv_circle_buf_capacity(circle_buf), data); + circle_buf->tail++; + + return LV_RESULT_OK; +} + +uint32_t lv_circle_buf_fill(lv_circle_buf_t * circle_buf, uint32_t count, lv_circle_buf_fill_cb_t fill_cb, + void * user_data) +{ + LV_ASSERT_NULL(circle_buf); + LV_ASSERT_NULL(fill_cb); + + uint32_t filled = 0; + while(count > 0 && !lv_circle_buf_is_full(circle_buf)) { + void * data = lv_circle_buf_tail(circle_buf); + if(fill_cb(data, circle_buf->array.element_size, (int32_t)filled, user_data) == LV_RESULT_OK) { + circle_buf->tail++; + filled++; + } + else break; + + count--; + } + + return filled; +} + +lv_result_t lv_circle_buf_skip(lv_circle_buf_t * circle_buf) +{ + LV_ASSERT_NULL(circle_buf); + + if(lv_circle_buf_is_empty(circle_buf)) { + circle_buf->head = 0; + circle_buf->tail = 0; + return LV_RESULT_INVALID; + } + + circle_buf->head++; + + return LV_RESULT_OK; +} + +lv_result_t lv_circle_buf_peek(const lv_circle_buf_t * circle_buf, void * data) +{ + LV_ASSERT_NULL(circle_buf); + LV_ASSERT_NULL(data); + + return lv_circle_buf_peek_at(circle_buf, 0, data); +} + +lv_result_t lv_circle_buf_peek_at(const lv_circle_buf_t * circle_buf, const uint32_t index, void * data) +{ + LV_ASSERT_NULL(circle_buf); + LV_ASSERT_NULL(data); + + const uint32_t real_index = (index % lv_circle_buf_size(circle_buf) + circle_buf->head) % lv_circle_buf_capacity( + circle_buf); + lv_memcpy(data, lv_array_at(&circle_buf->array, real_index), circle_buf->array.element_size); + + return LV_RESULT_OK; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +static void circle_buf_prepare_empty(lv_circle_buf_t * circle_buf) +{ + const uint32_t required = lv_array_capacity(&circle_buf->array) - lv_array_size(&circle_buf->array); + for(uint32_t i = 0; i < required; i++) lv_array_push_back(&circle_buf->array, NULL); +} diff --git a/src/misc/lv_circle_buf.h b/src/misc/lv_circle_buf.h new file mode 100644 index 000000000..614900084 --- /dev/null +++ b/src/misc/lv_circle_buf.h @@ -0,0 +1,191 @@ +/** +* @file lv_circle_buf.h +* + */ + + +#ifndef LV_CIRCLE_BUF_H +#define LV_CIRCLE_BUF_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ + +#include "lv_types.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +typedef bool (*lv_circle_buf_fill_cb_t)(void * buf, uint32_t buff_len, int32_t index, void * user_data); + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a circle buffer + * @param capacity the maximum number of elements in the buffer + * @param element_size the size of an element in bytes + * @return pointer to the created buffer + */ +lv_circle_buf_t * lv_circle_buf_create(uint32_t capacity, uint32_t element_size); + +/** + * Create a circle buffer from an existing buffer + * @param buf pointer to a buffer + * @param capacity the maximum number of elements in the buffer + * @param element_size the size of an element in bytes + * @return pointer to the created buffer + */ +lv_circle_buf_t * lv_circle_buf_create_from_buf(void * buf, uint32_t capacity, uint32_t element_size); + +/** + * Create a circle buffer from an existing array + * @param array pointer to an array + * @return pointer to the created buffer + */ +lv_circle_buf_t * lv_circle_buf_create_from_array(const lv_array_t * array); + +/** + * Resize the buffer + * @param circle_buf pointer to a buffer + * @param capacity the new capacity of the buffer + * @return LV_RESULT_OK: the buffer is resized; LV_RESULT_INVALID: the buffer is not resized + */ +lv_result_t lv_circle_buf_resize(lv_circle_buf_t * circle_buf, uint32_t capacity); + +/** + * Destroy a circle buffer + * @param circle_buf pointer to buffer + */ +void lv_circle_buf_destroy(lv_circle_buf_t * circle_buf); + +/** + * Get the size of the buffer + * @param circle_buf pointer to buffer + * @return the number of elements in the buffer + */ +uint32_t lv_circle_buf_size(const lv_circle_buf_t * circle_buf); + +/** + * Get the capacity of the buffer + * @param circle_buf pointer to buffer + * @return the maximum number of elements in the buffer + */ +uint32_t lv_circle_buf_capacity(const lv_circle_buf_t * circle_buf); + +/** + * Get the remaining space in the buffer + * @param circle_buf pointer to buffer + * @return the number of elements that can be written to the buffer + */ +uint32_t lv_circle_buf_remain(const lv_circle_buf_t * circle_buf); + +/** + * Check if the buffer is empty + * @param circle_buf pointer to buffer + * @return true: the buffer is empty; false: the buffer is not empty + */ +bool lv_circle_buf_is_empty(const lv_circle_buf_t * circle_buf); + +/** + * Check if the buffer is full + * @param circle_buf pointer to buffer + * @return true: the buffer is full; false: the buffer is not full + */ +bool lv_circle_buf_is_full(const lv_circle_buf_t * circle_buf); + +/** + * Reset the buffer + * @param circle_buf pointer to buffer + * @return LV_RESULT_OK: the buffer is reset; LV_RESULT_INVALID: the buffer is not reset + */ +void lv_circle_buf_reset(lv_circle_buf_t * circle_buf); + +/** + * Get the head of the buffer + * @param circle_buf pointer to buffer + * @return pointer to the head of the buffer + */ +void * lv_circle_buf_head(const lv_circle_buf_t * circle_buf); + +/** + * Get the tail of the buffer + * @param circle_buf pointer to buffer + * @return pointer to the tail of the buffer + */ +void * lv_circle_buf_tail(const lv_circle_buf_t * circle_buf); + +/** + * Read a value + * @param circle_buf pointer to buffer + * @param data pointer to a variable to store the read value + * @return LV_RESULT_OK: the value is read; LV_RESULT_INVALID: the value is not read + */ +lv_result_t lv_circle_buf_read(lv_circle_buf_t * circle_buf, void * data); + +/** + * Write a value + * @param circle_buf pointer to buffer + * @param data pointer to the value to write + * @return LV_RESULT_OK: the value is written; LV_RESULT_INVALID: the value is not written + */ +lv_result_t lv_circle_buf_write(lv_circle_buf_t * circle_buf, const void * data); + +/** + * Fill the buffer with values + * @param circle_buf pointer to buffer + * @param count the number of values to fill + * @param fill_cb the callback function to fill the buffer + * @param user_data + * @return the number of values filled + */ +uint32_t lv_circle_buf_fill(lv_circle_buf_t * circle_buf, uint32_t count, lv_circle_buf_fill_cb_t fill_cb, + void * user_data); + +/** + * Skip a value + * @param circle_buf pointer to buffer + * @return LV_RESULT_OK: the value is skipped; LV_RESULT_INVALID: the value is not skipped + */ +lv_result_t lv_circle_buf_skip(lv_circle_buf_t * circle_buf); + +/** + * Peek a value + * @param circle_buf pointer to buffer + * @param data pointer to a variable to store the peeked value + * @return LV_RESULT_OK: the value is peeked; LV_RESULT_INVALID: the value is not peeked + */ +lv_result_t lv_circle_buf_peek(const lv_circle_buf_t * circle_buf, void * data); + +/** + * Peek a value at an index + * @param circle_buf pointer to buffer + * @param index the index of the value to peek, if the index is greater than the size of the buffer, it will return looply. + * @param data pointer to a variable to store the peeked value + * @return LV_RESULT_OK: the value is peeked; LV_RESULT_INVALID: the value is not peeked + */ +lv_result_t lv_circle_buf_peek_at(const lv_circle_buf_t * circle_buf, uint32_t index, void * data); + +/************************* + * GLOBAL VARIABLES + *************************/ + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_CIRCLE_BUF_H*/ diff --git a/src/misc/lv_types.h b/src/misc/lv_types.h index 8f6caf9ae..d86284a7c 100644 --- a/src/misc/lv_types.h +++ b/src/misc/lv_types.h @@ -326,6 +326,8 @@ typedef struct _lv_array_t lv_array_t; typedef struct _lv_iter_t lv_iter_t; +typedef struct _lv_circle_buf_t lv_circle_buf_t; + typedef struct _lv_draw_buf_t lv_draw_buf_t; #if LV_USE_OBJ_PROPERTY diff --git a/tests/src/test_cases/test_circle_buf.c b/tests/src/test_cases/test_circle_buf.c new file mode 100644 index 000000000..ba31f3ce3 --- /dev/null +++ b/tests/src/test_cases/test_circle_buf.c @@ -0,0 +1,167 @@ +#if LV_BUILD_TEST +#include "../lvgl.h" +#include "../../lvgl_private.h" + +#include "unity/unity.h" + +static lv_circle_buf_t * circle_buf; + +#define circle_buf_CAPACITY 4 + +void setUp(void) +{ + circle_buf = lv_circle_buf_create(circle_buf_CAPACITY, sizeof(int32_t)); + + TEST_ASSERT_EQUAL_UINT32(lv_circle_buf_capacity(circle_buf), circle_buf_CAPACITY); + TEST_ASSERT_EQUAL_UINT32(0, lv_circle_buf_size(circle_buf)); + + /** + * Write values to the circle buffer. The max size of the buffer is circle_buf_CAPACITY. + * When the buffer is full, the write operation should return LV_RESULT_INVALID. + */ + for(int32_t i = 0; i < circle_buf_CAPACITY * 2; i++) { + const lv_result_t res = lv_circle_buf_write(circle_buf, &i); + + if(i < circle_buf_CAPACITY) TEST_ASSERT_EQUAL(LV_RESULT_OK, res); + else TEST_ASSERT_EQUAL(LV_RESULT_INVALID, res); + } + + /** + * After writing values to the buffer, the size of the buffer should be equal to the capacity. + */ + TEST_ASSERT_EQUAL_UINT32(lv_circle_buf_size(circle_buf), circle_buf_CAPACITY); +} + +void tearDown(void) +{ + lv_circle_buf_destroy(circle_buf); + circle_buf = NULL; +} + +void test_circle_buf_read_write_peek_values(void) +{ + /** + * Read 1 value from the buffer. + */ + { + int32_t value; + const lv_result_t res = lv_circle_buf_read(circle_buf, &value); + + TEST_ASSERT_EQUAL(LV_RESULT_OK, res); + TEST_ASSERT_EQUAL_INT32(0, value); + } + + /** + * Peek values will not advance the read and write cursors. + * If the peek index is greater than the size of the buffer, it will returns looply. + */ + for(int32_t i = 0, j = 1; i < circle_buf_CAPACITY * 10; i++, j++) { + int32_t value; + const lv_result_t res = lv_circle_buf_peek_at(circle_buf, i, &value); + + TEST_ASSERT_EQUAL(LV_RESULT_OK, res); + TEST_ASSERT_EQUAL_INT32(j, value); + + if(j == 3) j = 0; + } + + /** + * Read values from the circle buffer. The max size of the buffer is circle_buf_CAPACITY. + * When the buffer is empty, the read operation should return LV_RESULT_INVALID. + */ + for(int32_t i = 1; i < circle_buf_CAPACITY * 2; i++) { + int32_t value; + const lv_result_t res = lv_circle_buf_read(circle_buf, &value); + + if(i < circle_buf_CAPACITY) { + TEST_ASSERT_EQUAL(LV_RESULT_OK, res); + TEST_ASSERT_EQUAL_INT32(i, value); + } + else { + TEST_ASSERT_EQUAL(LV_RESULT_INVALID, res); + } + } + + /** + * After reading values from the buffer, the size of the buffer should be equal to 0. + */ + TEST_ASSERT_EQUAL_INT32(0, lv_circle_buf_size(circle_buf)); +} + +void test_circle_buf_skip_values(void) +{ + /** + * Skip 1 value from the buffer. + */ + { + const lv_result_t res = lv_circle_buf_skip(circle_buf); + + TEST_ASSERT_EQUAL(LV_RESULT_OK, res); + } + + /** + * Skip values from the circle buffer. The max size of the buffer is circle_buf_CAPACITY. + * When the buffer is empty, the skip operation should return LV_RESULT_INVALID. + */ + for(int32_t i = 1; i < circle_buf_CAPACITY * 2; i++) { + const lv_result_t res = lv_circle_buf_skip(circle_buf); + + if(i < circle_buf_CAPACITY) { + TEST_ASSERT_EQUAL(LV_RESULT_OK, res); + } + else { + TEST_ASSERT_EQUAL(LV_RESULT_INVALID, res); + } + } + + /** + * After skipping values from the buffer, the size of the buffer should be equal to 0. + */ + TEST_ASSERT_EQUAL_INT32(0, lv_circle_buf_size(circle_buf)); +} + +void test_circle_buf_read_after_read_and_write(void) +{ + /** + * Read 1 value from the buffer. + */ + { + int32_t value; + const lv_result_t res = lv_circle_buf_read(circle_buf, &value); + + TEST_ASSERT_EQUAL(LV_RESULT_OK, res); + TEST_ASSERT_EQUAL_INT32(0, value); + } + + /** + * Write 1 value to the buffer. + */ + { + const int32_t value = 4; + const lv_result_t res = lv_circle_buf_write(circle_buf, &value); + + TEST_ASSERT_EQUAL(LV_RESULT_OK, res); + } + + const int32_t expected[] = {4, 1, 2, 3}; + TEST_ASSERT_EQUAL_INT32_ARRAY(expected, ((lv_array_t *)circle_buf)->data, 4); + + /** + * Read values from the circle buffer. The max size of the buffer is circle_buf_CAPACITY. + * When the buffer is empty, the read operation should return LV_RESULT_INVALID. + */ + for(int32_t i = 1; i < circle_buf_CAPACITY * 2; i++) { + int32_t value; + const lv_result_t res = lv_circle_buf_read(circle_buf, &value); + + if(i <= circle_buf_CAPACITY) { + TEST_ASSERT_EQUAL(LV_RESULT_OK, res); + TEST_ASSERT_EQUAL_INT32(i, value); + } + else { + TEST_ASSERT_EQUAL(LV_RESULT_INVALID, res); + } + } +} + +#endif