From 647ab3aa876b04fc6747306b0b604e1313368954 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Wed, 27 Aug 2025 10:35:25 +0200 Subject: [PATCH] common: Add circular buffer API for data streaming Add a simple ring buffer implementation with claiming/committing, consumption tracking, and automatic compaction when needed. A better solution would be to implement Bip Buffer: https://www.codeproject.com/Articles/3479/The-Bip-Buffer-The-Circular-Buffer-with-a-Twist Signed-off-by: iabdalkader --- common/omv_buffer.h | 94 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 common/omv_buffer.h diff --git a/common/omv_buffer.h b/common/omv_buffer.h new file mode 100644 index 000000000..96e000f56 --- /dev/null +++ b/common/omv_buffer.h @@ -0,0 +1,94 @@ +#ifndef __OMV_BUFFER_H__ +#define __OMV_BUFFER_H__ + +#include +#include +#include +#include + +typedef struct { + size_t size; // Total buffer size + uint8_t *read_ptr; // Where to read/process from + uint8_t *write_ptr; // Where to write new data + size_t used; // Bytes currently in buffer (unprocessed) + uint8_t *data; // The actual buffer memory +} omv_buffer_t; + +// Initialize buffer with pre-allocated memory +static inline void omv_buffer_init(omv_buffer_t *buf, uint8_t *buffer, size_t size) { + buf->data = buffer; + buf->size = size; + buf->read_ptr = buffer; + buf->write_ptr = buffer; + buf->used = 0; +} + +// Reset buffer to empty state +static inline void omv_buffer_clear(omv_buffer_t *buf) { + buf->read_ptr = buf->data; + buf->write_ptr = buf->data; + buf->used = 0; +} + +// Get number of bytes available for reading +static inline size_t omv_buffer_avail(omv_buffer_t *buf) { + return buf->used; +} + +// Get number of bytes available for writing +static inline size_t omv_buffer_free(omv_buffer_t *buf) { + return buf->size - buf->used; +} + +// Get pointer to readable data +// Returns data pointer or NULL if buffer is empty +static inline void *omv_buffer_data(omv_buffer_t *buf) { + return (buf->used > 0) ? buf->read_ptr : NULL; +} + +// Peek at 16-bit value at start of buffer +// Caller must ensure omv_buffer_avail(buf) >= 2 +static inline uint16_t omv_buffer_peek16(omv_buffer_t *buf) { + return *((uint16_t *) buf->read_ptr); +} + +// Mark data as consumed and advance read pointer +// Resets buffer to beginning when empty +static inline void omv_buffer_consume(omv_buffer_t *buf, size_t consumed) { + buf->read_ptr += consumed; + buf->used -= consumed; + + // Reset to beginning if buffer is empty + if (buf->used == 0) { + buf->read_ptr = buf->data; + buf->write_ptr = buf->data; + } +} + +// Claim contiguous space for writing, compacting buffer if needed +static inline void *omv_buffer_claim(omv_buffer_t *buf, size_t requested_size) { + // Check if we have enough total space + if (buf->used + requested_size > buf->size) { + return NULL; // Buffer full + } + + size_t space_to_end = buf->size - (buf->write_ptr - buf->data); + + // If not enough contiguous space at the end, move unprocessed data to beginning + if (space_to_end < requested_size && buf->used > 0) { + // Move unprocessed data to the beginning + memmove(buf->data, buf->read_ptr, buf->used); + buf->read_ptr = buf->data; + buf->write_ptr = buf->data + buf->used; + } + + return buf->write_ptr; +} + +// Commit written data to the buffer +// Call this after successfully writing to the claimed space +static inline void omv_buffer_commit(omv_buffer_t *buf, size_t written) { + buf->write_ptr += written; + buf->used += written; +} +#endif // __OMV_BUFFER_H__