diff --git a/CircularBuffer/inc/PCircularBuffer.h b/CircularBuffer/inc/PCircularBuffer.h deleted file mode 100644 index 1301201..0000000 --- a/CircularBuffer/inc/PCircularBuffer.h +++ /dev/null @@ -1,198 +0,0 @@ -// 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__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 -#include - -// comment this out for release builds -//#define PB_CB_DEBUG - -// Making these PB_EN/DIS rather than just ENABLE/DISABLE because -// some enable/disable definition might already exist that is -// inversely active (enabled = 0, disable = 1) -// this way our en/dis definitions are explicit -#ifndef PB_ENABLE -#define PB_ENABLE (1) -#endif - -#ifndef PB_DISABLE -#define PB_DISABLE (0) -#endif - -// Max size is 65535 (2^16 - 1) so variables can be safely set 16 bits (unsigned) -// If you want to change this, you'll need to change the sizes of all heads and max lengths -#define PB_CB_MAX_BUFFER_SIZE (65535) - -// Config -// Disable or Enable types needed here -// We can save code size this way -// While there are better ways to do this, this is the most accessible for anyone imo -#define PB_CB_FLOAT PB_DISABLE -#define PB_CB_DOUBLE PB_ENABLE -#define PB_CB_U8 PB_DISABLE -#define PB_CB_U16 PB_DISABLE -#define PB_CB_U32 PB_DISABLE -#define PB_CB_U64 PB_DISABLE -#define PB_CB_I8 PB_DISABLE -#define PB_CB_I16 PB_DISABLE -#define PB_CB_I32 PB_DISABLE -#define PB_CB_I64 PB_DISABLE - -typedef enum PB_CB_STATUS -{ - PB_CB_GOOD = 0, - PB_CB_BAD = 1, - PB_CB_BAD_BUFFER_SIZE = 2, - PB_CB_NULL_BUFFER = 3, - PB_CB_NULL_CBUFFER = 4 -} PB_CB_STATUS; - -#if PB_CB_U8 -typedef struct p_cb_u8 -{ - uint8_t *buffer; - uint16_t head; - uint16_t max_len; - // Signifies the buffer being filled at least once. - // Useful for initializing sensor data - bool b_filled; - // Signifies the buffer being empty - // Useful for knowing if data is being received - bool b_empty; - - PB_CB_STATUS (*push)(struct p_cb_u8 *cbuffer, uint8_t value); - PB_CB_STATUS (*empty)(struct p_cb_u8 *cbuffer); -} p_cb_u8; - -PB_CB_STATUS p_cb_u8_init(p_cb_u8 *circ_buffer, uint8_t *buff, uint32_t max_length); -#endif - -#if PB_CB_U16 -typedef struct p_cb_u16 -{ - uint16_t *buffer; - uint16_t head; - uint16_t max_len; - // Signifies the buffer being filled at least once. - // Useful for initializing sensor data - bool b_filled; - // Signifies the buffer being empty - // Useful for knowing if data is being received - bool b_empty; - - PB_CB_STATUS (*push)(struct p_cb_u16 *cbuffer, uint16_t value); - PB_CB_STATUS (*empty)(struct p_cb_u16 *cbuffer); -} p_cb_u16; - -PB_CB_STATUS p_cb_u16_init(p_cb_u16 *circ_buffer, uint16_t *buff, uint32_t max_length); -#endif - -#if PB_CB_U32 -typedef struct p_cb_u32 -{ - uint32_t *buffer; - uint16_t head; - uint16_t max_len; - // Signifies the buffer being filled at least once. - // Useful for initializing sensor data - bool b_filled; - // Signifies the buffer being empty - // Useful for knowing if data is being received - bool b_empty; - - PB_CB_STATUS (*push)(struct p_cb_u32 *cbuffer, uint32_t value); - PB_CB_STATUS (*empty)(struct p_cb_u32 *cbuffer); -} p_cb_u32; - -PB_CB_STATUS p_cb_u32_init(p_cb_u32 *circ_buffer, uint32_t *buff, uint32_t max_length); -#endif - -#if PB_CB_U64 -typedef struct p_cb_u64 -{ - uint64_t *buffer; - uint16_t head; - uint16_t max_len; - // Signifies the buffer being filled at least once. - // Useful for initializing sensor data - bool b_filled; - // Signifies the buffer being empty - // Useful for knowing if data is being received - bool b_empty; - - PB_CB_STATUS (*push)(struct p_cb_u64 *cbuffer, uint64_t value); - PB_CB_STATUS (*empty)(struct p_cb_u64 *cbuffer); -} p_cb_u64; - -PB_CB_STATUS p_cb_u64_init(p_cb_u64 *circ_buffer, uint64_t *buff, uint32_t max_length); -#endif - -#if PB_CB_FLOAT -typedef struct p_cb_float -{ - float *buffer; - uint16_t head; - uint16_t max_len; - // Signifies the buffer being filled at least once. - // Useful for initializing sensor data - bool b_filled; - // Signifies the buffer being empty - // Useful for knowing if data is being received - bool b_empty; - - PB_CB_STATUS (*push)(struct p_cb_float *cbuffer, float value); - PB_CB_STATUS (*empty)(struct p_cb_float *cbuffer); -} p_cb_float; - -PB_CB_STATUS p_cb_float_init(p_cb_float *circ_buffer, float *buff, uint32_t max_length); -#endif - -#if PB_CB_DOUBLE -typedef struct p_cb_double -{ - double *buffer; - uint16_t head; - uint16_t max_len; - // Signifies the buffer being filled at least once. - // Useful for initializing sensor data - bool b_filled; - // Signifies the buffer being empty - // Useful for knowing if data is being received - bool b_empty; - - PB_CB_STATUS (*push)(struct p_cb_double *cbuffer, double value); - PB_CB_STATUS (*empty)(struct p_cb_double *cbuffer); -} p_cb_double; - -PB_CB_STATUS p_cb_double_init(p_cb_double *circ_buffer, double *buff, uint32_t max_length); -#endif - -#endif diff --git a/CircularBuffer/p_cbuffer.c b/CircularBuffer/p_cbuffer.c new file mode 100644 index 0000000..b7b6b31 --- /dev/null +++ b/CircularBuffer/p_cbuffer.c @@ -0,0 +1,77 @@ +#include + +// Error handler used for debugging only + +// Circular Buffer Prototypes -- Double +static PB_CB_STATUS p_cb_double_push(p_cb_double *cbuffer, double value); +static PB_CB_STATUS p_cb_double_empty(p_cb_double *cbuffer); + +// Circular Buffer Definitions -- double +PB_CB_STATUS p_cb_double_init(p_cb_double *circ_buffer, double *buff, uint32_t max_length) +{ + PB_CB_STATUS ret = PB_CB_GOOD; + do + { + // Make sure the buffer isn't bad (null) + if (!buff) + { + ret = PB_CB_NULL_BUFFER; + break; + } + + // Make sure the max buffer is a useable size + if (max_length > PB_CB_MAX_BUFFER_SIZE || max_length <= 0) + { + ret = PB_CB_BAD_BUFFER_SIZE; + break; + } + circ_buffer->buffer = buff; + circ_buffer->max_len = (uint16_t)max_length; + circ_buffer->head = 0; + circ_buffer->push = p_cb_double_push; + circ_buffer->empty = p_cb_double_empty; + circ_buffer->empty(circ_buffer); + } while (0); + + return ret; +} + +PB_CB_STATUS p_cb_double_push(p_cb_double *cbuffer, double value) +{ + PB_CB_STATUS ret = PB_CB_GOOD; + + if (!cbuffer) + { + ret = PB_CB_NULL_CBUFFER; + } + else + { + cbuffer->buffer[cbuffer->head] = value; + cbuffer->head = (cbuffer->head + 1) % cbuffer->max_len; + } + + return ret; +} +PB_CB_STATUS p_cb_double_empty(p_cb_double *cbuffer) +{ + PB_CB_STATUS ret = PB_CB_GOOD; + do + { + if (!cbuffer) + { + ret = PB_CB_NULL_CBUFFER; + break; + } + + if (!cbuffer->buffer) + { + ret = PB_CB_NULL_BUFFER; + break; + } + memset(cbuffer->buffer, 0, sizeof(double) * cbuffer->max_len); + cbuffer->head = 0; + cbuffer->b_empty = true; + cbuffer->b_filled = false; + } while (0); + return ret; +} diff --git a/CircularBuffer/p_cbuffer.h b/CircularBuffer/p_cbuffer.h new file mode 100644 index 0000000..41ba807 --- /dev/null +++ b/CircularBuffer/p_cbuffer.h @@ -0,0 +1,64 @@ +// 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__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 +#include + +typedef enum PB_CB_STATUS +{ + PB_CB_GOOD = 0, + PB_CB_BAD = 1, + PB_CB_BAD_BUFFER_SIZE = 2, + PB_CB_NULL_BUFFER = 3, + PB_CB_NULL_CBUFFER = 4 +} PB_CB_STATUS; + +#if PB_CB_DOUBLE +typedef struct p_cb_double +{ + double *buffer; + uint16_t head; + uint16_t max_len; + // Signifies the buffer being filled at least once. + // Useful for initializing sensor data + bool b_filled; + // Signifies the buffer being empty + // Useful for knowing if data is being received + bool b_empty; + + PB_CB_STATUS (*push)(struct p_cb_double *cbuffer, double value); + PB_CB_STATUS (*empty)(struct p_cb_double *cbuffer); +} p_cb_double; + +PB_CB_STATUS p_cb_double_init(p_cb_double *circ_buffer, double *buff, uint32_t max_length); +#endif + +#endif diff --git a/CircularBuffer/src/PCircularBuffer.c b/CircularBuffer/src/PCircularBuffer.c deleted file mode 100644 index 6e9ea78..0000000 --- a/CircularBuffer/src/PCircularBuffer.c +++ /dev/null @@ -1,448 +0,0 @@ -#include - -// Error handler used for debugging only -#ifdef PB_CB_DEBUG -#include -static void handle_status(const char *func, PB_CB_STATUS status_code) -{ - if (status_code != PB_CB_GOOD) - { - printf("%s failed: error code: %d\r\n", func, status_code); - } -} -#endif - -// Circular Buffer Prototypes -- uint8_t -#if PB_CB_U8 -static PB_CB_STATUS p_cb_u8_push(p_cb_double *cbuffer, uint8_t value); -static PB_CB_STATUS p_cb_u8_empty(p_cb_double *cbuffer); -#endif - -// Circular Buffer Prototypes -- uint16_t -#if PB_CB_U16 -static PB_CB_STATUS p_cb_u16_push(p_cb_double *cbuffer, uint16_t value); -static PB_CB_STATUS p_cb_u16_empty(p_cb_double *cbuffer); -#endif - -// Circular Buffer Prototypes -- uint32_t -#if PB_CB_U32 -static PB_CB_STATUS p_cb_u32_push(p_cb_double *cbuffer, uint32_t value); -static PB_CB_STATUS p_cb_u32_empty(p_cb_double *cbuffer); -#endif - -// Circular Buffer Prototypes -- uint64_t -#if PB_CB_U64 -static PB_CB_STATUS p_cb_u64_push(p_cb_double *cbuffer, uint64_t value); -static PB_CB_STATUS p_cb_u64_empty(p_cb_double *cbuffer); -#endif - -// Circular Buffer Prototypes -- int8_t -#if PB_CB_I8 -static PB_CB_STATUS p_cb_i8_push(p_cb_double *cbuffer, int8_t value); -static PB_CB_STATUS p_cb_i8_empty(p_cb_double *cbuffer); -#endif - -// Circular Buffer Prototypes -- int16_t -#if PB_CB_I16 -static PB_CB_STATUS p_cb_i16_push(p_cb_double *cbuffer, int16_t value); -static PB_CB_STATUS p_cb_i16_empty(p_cb_double *cbuffer); -#endif - -// Circular Buffer Prototypes -- int32_t -#if PB_CB_I32 -static PB_CB_STATUS p_cb_i32_push(p_cb_double *cbuffer, int32_t value); -static PB_CB_STATUS p_cb_i32_empty(p_cb_double *cbuffer); -#endif - -// Circular Buffer Prototypes -- int64_t -#if PB_CB_I64 -static PB_CB_STATUS p_cb_i64_push(p_cb_double *cbuffer, int64_t value); -static PB_CB_STATUS p_cb_i64_empty(p_cb_double *cbuffer); -#endif - -// Circular Buffer Prototypes -- Float -#if PB_CB_FLOAT -static PB_CB_STATUS p_cb_float_push(p_cb_double *cbuffer, float value); -static PB_CB_STATUS p_cb_float_empty(p_cb_double *cbuffer); -#endif - -// Circular Buffer Prototypes -- Double -#if PB_CB_DOUBLE -static PB_CB_STATUS p_cb_double_push(p_cb_double *cbuffer, double value); -static PB_CB_STATUS p_cb_double_empty(p_cb_double *cbuffer); -#endif - -// Circular Buffer Definitions -- uint8_t -#if PB_CB_U8 -PB_CB_STATUS p_cb_u8_init(p_cb_u8 *circ_buffer, uint8_t *buff, uint32_t max_length) -{ - PB_CB_STATUS ret = PB_CB_GOOD; - do - { - // Make sure the buffer isn't bad (null) - if (!buff) - { - ret = PB_CB_NULL_BUFFER; - break; - } - - // Make sure the max buffer is a useable size - if (max_length > PB_CB_MAX_BUFFER_SIZE || max_length <= 0) - { - ret = PB_CB_BAD_BUFFER_SIZE; - break; - } - } while (0); - -// Debugging -#ifdef PB_CB_DEBUG - handle_status(__func__, ret); -#endif - - return ret; -} - -PB_CB_STATUS p_cb_u8_push(p_cb_double *cbuffer, uint8_t value) -{ - PB_CB_STATUS ret = PB_CB_GOOD; - - if (!cbuffer) - { - ret = PB_CB_NULL_CBUFFER; - } - else - { - cbuffer->buffer[cbuffer->head] = value; - cbuffer->head = (cbuffer->head + 1) % cbuffer->max_len; - } - -// Debugging -#ifdef PB_CB_DEBUG - handle_status(__func__, ret); -#endif - - return ret; -} -PB_CB_STATUS p_cb_u8_empty(p_cb_double *cbuffer) -{ - PB_CB_STATUS ret = PB_CB_GOOD; - - do - { - if (!cbuffer) - { - ret = PB_CB_NULL_CBUFFER; - break; - } - - if (!cbuffer->buffer) - { - ret = PB_CB_NULL_BUFFER; - break; - } - memset(cbuffer->buffer, 0, cbuffer->max_len); - cbuffer->head = 0; - cbuffer->b_empty = true; - cbuffer->b_filled = false; - } while (0); - -// Debugging -#ifdef PB_CB_DEBUG - handle_status(__func__, ret); -#endif - - return ret; -} -#endif -// Circular Buffer Definitions -- uint16_t -#if PB_CB_U16 -PB_CB_STATUS p_cb_u16_init(p_cb_u16 *circ_buffer, uint16_t *buff, uint32_t max_length) -{ - PB_CB_STATUS ret = PB_CB_GOOD; - do - { - // Make sure the buffer isn't bad (null) - if (!buff) - { - ret = PB_CB_NULL_BUFFER; - break; - } - - // Make sure the max buffer is a useable size - if (max_length > PB_CB_MAX_BUFFER_SIZE || max_length <= 0) - { - ret = PB_CB_BAD_BUFFER_SIZE; - break; - } - } while (0); - -// Debugging -#ifdef PB_CB_DEBUG - handle_status(__func__, ret); -#endif - - return ret; -} - -PB_CB_STATUS p_cb_u16_push(p_cb_double *cbuffer, uint16_t value) -{ - PB_CB_STATUS ret = PB_CB_GOOD; -// Debugging -#ifdef PB_CB_DEBUG - handle_status(__func__, ret); -#endif - - return ret; -} -PB_CB_STATUS p_cb_u16_empty(p_cb_double *cbuffer) -{ - PB_CB_STATUS ret = PB_CB_GOOD; -// Debugging -#ifdef PB_CB_DEBUG - handle_status(__func__, ret); -#endif - - return ret; -} -#endif - -// Circular Buffer Definitions -- uint32_t -#if PB_CB_U32 -PB_CB_STATUS p_cb_u32_init(p_cb_u32 *circ_buffer, uint32_t *buff, uint32_t max_length) -{ - PB_CB_STATUS ret = PB_CB_GOOD; - do - { - // Make sure the buffer isn't bad (null) - if (!buff) - { - ret = PB_CB_NULL_BUFFER; - break; - } - - // Make sure the max buffer is a useable size - if (max_length > PB_CB_MAX_BUFFER_SIZE || max_length <= 0) - { - ret = PB_CB_BAD_BUFFER_SIZE; - break; - } - } while (0); - -// Debugging -#ifdef PB_CB_DEBUG - handle_status(__func__, ret); -#endif - - return ret; -} -PB_CB_STATUS p_cb_u32_push(p_cb_double *cbuffer, uint32_t value) -{ - PB_CB_STATUS ret = PB_CB_GOOD; -// Debugging -#ifdef PB_CB_DEBUG - handle_status(__func__, ret); -#endif - - return ret; -} -PB_CB_STATUS p_cb_u32_empty(p_cb_double *cbuffer) -{ - PB_CB_STATUS ret = PB_CB_GOOD; -// Debugging -#ifdef PB_CB_DEBUG - handle_status(__func__, ret); -#endif - - return ret; -} -#endif - -// Circular Buffer Definitions -- uint64_t -#if PB_CB_U64 -PB_CB_STATUS p_cb_u64_init(p_cb_u64 *circ_buffer, uint64_t *buff, uint32_t max_length) -{ - PB_CB_STATUS ret = PB_CB_GOOD; - do - { - // Make sure the buffer isn't bad (null) - if (!buff) - { - ret = PB_CB_NULL_BUFFER; - break; - } - - // Make sure the max buffer is a useable size - if (max_length > PB_CB_MAX_BUFFER_SIZE || max_length <= 0) - { - ret = PB_CB_BAD_BUFFER_SIZE; - break; - } - } while (0); - -// Debugging -#ifdef PB_CB_DEBUG - handle_status(__func__, ret); -#endif - - return ret; -} -PB_CB_STATUS p_cb_u64_push(p_cb_double *cbuffer, uint64_t value) -{ - PB_CB_STATUS ret = PB_CB_GOOD; -// Debugging -#ifdef PB_CB_DEBUG - handle_status(__func__, ret); -#endif - - return ret; -} -PB_CB_STATUS p_cb_u64_empty(p_cb_double *cbuffer) -{ - PB_CB_STATUS ret = PB_CB_GOOD; -// Debugging -#ifdef PB_CB_DEBUG - handle_status(__func__, ret); -#endif - - return ret; -} -#endif - -#if PB_CB_FLOAT -PB_CB_STATUS p_cb_float_init(p_cb_float *circ_buffer, float *buff, uint32_t max_length) -{ - PB_CB_STATUS ret = PB_CB_GOOD; - do - { - // Make sure the buffer isn't bad (null) - if (!buff) - { - ret = PB_CB_NULL_BUFFER; - break; - } - - // Make sure the max buffer is a useable size - if (max_length > PB_CB_MAX_BUFFER_SIZE || max_length <= 0) - { - ret = PB_CB_BAD_BUFFER_SIZE; - break; - } - } while (0); - -// Debugging -#ifdef PB_CB_DEBUG - handle_status(__func__, ret); -#endif - - return ret; -} -PB_CB_STATUS p_cb_float_push(p_cb_double *cbuffer, float value) -{ - PB_CB_STATUS ret = PB_CB_GOOD; -// Debugging -#ifdef PB_CB_DEBUG - handle_status(__func__, ret); -#endif - - return ret; -} -PB_CB_STATUS p_cb_float_empty(p_cb_double *cbuffer) -{ - PB_CB_STATUS ret = PB_CB_GOOD; -// Debugging -#ifdef PB_CB_DEBUG - handle_status(__func__, ret); -#endif - - return ret; -} -#endif - -// Circular Buffer Definitions -- double -#if PB_CB_DOUBLE -PB_CB_STATUS p_cb_double_init(p_cb_double *circ_buffer, double *buff, uint32_t max_length) -{ - PB_CB_STATUS ret = PB_CB_GOOD; - do - { - // Make sure the buffer isn't bad (null) - if (!buff) - { - ret = PB_CB_NULL_BUFFER; - break; - } - - // Make sure the max buffer is a useable size - if (max_length > PB_CB_MAX_BUFFER_SIZE || max_length <= 0) - { - ret = PB_CB_BAD_BUFFER_SIZE; - break; - } - circ_buffer->buffer = buff; - circ_buffer->max_len = (uint16_t)max_length; - circ_buffer->head = 0; - circ_buffer->push = p_cb_double_push; - circ_buffer->empty = p_cb_double_empty; - circ_buffer->empty(circ_buffer); - } while (0); - -// Debugging -#ifdef PB_CB_DEBUG - handle_status(__func__, ret); -#endif - - return ret; -} - -PB_CB_STATUS p_cb_double_push(p_cb_double *cbuffer, double value) -{ - PB_CB_STATUS ret = PB_CB_GOOD; - - if (!cbuffer) - { - ret = PB_CB_NULL_CBUFFER; - } - else - { - cbuffer->buffer[cbuffer->head] = value; - cbuffer->head = (cbuffer->head + 1) % cbuffer->max_len; - } - -// Debugging -#ifdef PB_CB_DEBUG - handle_status(__func__, ret); -#endif - - return ret; -} -PB_CB_STATUS p_cb_double_empty(p_cb_double *cbuffer) -{ - PB_CB_STATUS ret = PB_CB_GOOD; - - do - { - if (!cbuffer) - { - ret = PB_CB_NULL_CBUFFER; - break; - } - - if (!cbuffer->buffer) - { - ret = PB_CB_NULL_BUFFER; - break; - } - memset(cbuffer->buffer, 0, sizeof(double) * cbuffer->max_len); - cbuffer->head = 0; - cbuffer->b_empty = true; - cbuffer->b_filled = false; - } while (0); - -// Debugging -#ifdef PB_CB_DEBUG - handle_status(__func__, ret); -#endif - - return ret; -} -#endif