You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
134 lines
7.9 KiB
C
134 lines
7.9 KiB
C
// Resource/Inspiration:
|
|
// https://embedjournal.com/implementing-circular-buffer-embedded-c/
|
|
|
|
/*
|
|
Penguin's Circular Buffer -- a simple floating queue designed for low memory
|
|
usage (mainly for embedded)
|
|
|
|
This is a ring buffer with limited capabilities. It is meant as a container
|
|
for moving data. Normally included features such as checks to see if the
|
|
buffer is full or empty have been omitted because this type of buffer is
|
|
being implemented mainly for sensor data usage. Data is almost never read
|
|
individually, and even if it is, it isn't meant to be cleared on read. It is
|
|
a simple moving buffer that automatically writes over old data for the
|
|
purpose of keeping track of the most up to date data.
|
|
|
|
Notes:
|
|
- Initialization is mandatory using p_cb_<type>_init.
|
|
- If a circular buffer is not initialized, you will run into a LOT of
|
|
hard-to-debug problems. Just initialize it.
|
|
- By default, all cb types should be defined as disabled. This is to save
|
|
on size. Enable the ones you want to use.
|
|
|
|
Behavior:
|
|
- Oldest data is overwritten
|
|
- popping of data isn't implemented. If this feature is required, use a
|
|
ring buffer.
|
|
|
|
Acronyms:
|
|
- p: penguin
|
|
- pb: penguin buffer
|
|
- cb: circular buffer
|
|
- uX, where X is bit size: unsigned X bit integer
|
|
- iX, where X is bit size: signed X bit integer
|
|
*/
|
|
|
|
#ifndef _PCIRCULARBUFFER_H_
|
|
#define _PCIRCULARBUFFER_H_
|
|
|
|
#include "p_buffer.h"
|
|
|
|
#define DEFINE_CBUFFER(type) \
|
|
typedef struct cbuffer_##type##_t \
|
|
{ \
|
|
type* buffer; \
|
|
int head; \
|
|
int csize; \
|
|
int msize; \
|
|
\
|
|
PB_STATUS (*push)(struct cbuffer_##type##_t * cbuffer, type value); \
|
|
PB_STATUS (*empty)(struct cbuffer_##type##_t * cbuffer); \
|
|
PB_STATUS (*is_filled)(struct cbuffer_##type##_t * cbuffer); \
|
|
} cbuffer_##type##_t; \
|
|
\
|
|
PB_STATUS cbuffer_##type##_is_filled(cbuffer_##type##_t* cbuffer) \
|
|
{ \
|
|
return (cbuffer->csize == cbuffer->msize); \
|
|
} \
|
|
\
|
|
PB_STATUS cbuffer_##type##_push(cbuffer_##type##_t* cbuffer, type value) \
|
|
{ \
|
|
PB_STATUS ret = PB_GOOD; \
|
|
\
|
|
if (!cbuffer) \
|
|
{ \
|
|
ret = PB_NULL_BUFFER; \
|
|
} \
|
|
else \
|
|
{ \
|
|
cbuffer->csize = \
|
|
(cbuffer->csize >= cbuffer->msize ? cbuffer->msize \
|
|
: cbuffer->csize + 1); \
|
|
cbuffer->buffer[cbuffer->head] = value; \
|
|
cbuffer->head = (cbuffer->head + 1) % cbuffer->msize; \
|
|
} \
|
|
\
|
|
return ret; \
|
|
} \
|
|
PB_STATUS cbuffer_##type##_empty(cbuffer_##type##_t* cbuffer) \
|
|
{ \
|
|
PB_STATUS ret = PB_GOOD; \
|
|
do \
|
|
{ \
|
|
if (!cbuffer) \
|
|
{ \
|
|
ret = PB_NULL_BUFFER; \
|
|
break; \
|
|
} \
|
|
\
|
|
if (!cbuffer->buffer) \
|
|
{ \
|
|
ret = PB_NULL_DATA; \
|
|
break; \
|
|
} \
|
|
memset(cbuffer->buffer, 0, sizeof(type) * cbuffer->msize); \
|
|
cbuffer->head = 0; \
|
|
cbuffer->csize = 0; \
|
|
} while (0); \
|
|
return ret; \
|
|
} \
|
|
\
|
|
PB_STATUS cbuffer_##type##_init(cbuffer_##type##_t* circ_buffer, \
|
|
type* buff, int total_length) \
|
|
{ \
|
|
PB_STATUS ret = PB_GOOD; \
|
|
do \
|
|
{ \
|
|
if (!buff) \
|
|
{ \
|
|
ret = PB_NULL_DATA; \
|
|
break; \
|
|
} \
|
|
\
|
|
if (total_length > MAX_CBUFFER_SIZE || total_length <= 0) \
|
|
{ \
|
|
ret = PB_BAD_BUFFER_SIZE; \
|
|
break; \
|
|
} \
|
|
memset(circ_buffer, 0, sizeof(cbuffer_##type##_t)); \
|
|
memset(buff, 0, sizeof(type) * total_length); \
|
|
circ_buffer->buffer = buff; \
|
|
circ_buffer->msize = total_length; \
|
|
circ_buffer->csize = 0; \
|
|
circ_buffer->head = 0; \
|
|
circ_buffer->push = cbuffer_##type##_push; \
|
|
circ_buffer->empty = cbuffer_##type##_empty; \
|
|
circ_buffer->is_filled = cbuffer_##type##_is_filled; \
|
|
circ_buffer->empty(circ_buffer); \
|
|
} while (0); \
|
|
\
|
|
return ret; \
|
|
}
|
|
|
|
#endif
|