296 lines
6.8 KiB
C
296 lines
6.8 KiB
C
/**
|
|
* @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);
|
|
|
|
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);
|
|
}
|