openmv/common/omv_buffer.h
iabdalkader 53f986b3f9 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 <i.abdalkader@gmail.com>
2025-09-19 19:53:01 +02:00

95 lines
2.8 KiB
C

#ifndef __OMV_BUFFER_H__
#define __OMV_BUFFER_H__
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <string.h>
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__