commit 0fb32781c9631d62b312af6427a100a32a4081ed Author: Ondřej Hruška Date: Sun Nov 29 12:36:14 2015 +0100 source added diff --git a/README.md b/README.md new file mode 100644 index 0000000..d91e016 --- /dev/null +++ b/README.md @@ -0,0 +1,33 @@ +Circular byte buffer +==================== + +This is a circular buffer implementation, useful for embedded systems (buffer for UART RX queue etc). + + +Usage +----- + +```c +#include + +uint8_t buffer[32]; // array backing the buffer + +CircularByteBuffer cb; // buffer instance + +void main() +{ + cbuf_init(&cb, buffer, 32); // init the buffer + + // now it's ready for use! +} +``` + +Many function return success flag, so make sure to check the return values. + +False is returned on buffer overflow / underflow, attempted read past available data size etc. See the header file for details. + + +License +------- + +Do whatever you want with the code. \ No newline at end of file diff --git a/circbuf.c b/circbuf.c new file mode 100644 index 0000000..b9d2892 --- /dev/null +++ b/circbuf.c @@ -0,0 +1,175 @@ +#include +#include +#include + +#include "circbuf.h" + + +void cbuf_init(CircularBuffer *inst, uint8_t *buffer, uint16_t length) +{ + inst->buffer = buffer; + inst->capacity = length; + + cbuf_clear(inst); +} + + +bool cbuf_full(CircularBuffer *inst) +{ + return inst->data_len == inst->capacity; +} + + +bool cbuf_empty(CircularBuffer *inst) +{ + return inst->data_len == 0; +} + + +bool cbuf_write(CircularBuffer *inst, uint8_t b) +{ + if (cbuf_full(inst)) return false; + + inst->buffer[inst->write_pos] = b; + + inst->write_pos++; + inst->data_len++; + + // wrap + if (inst->write_pos >= inst->capacity) { + inst->write_pos = 0; + } + + return true; +} + + +bool cbuf_read(CircularBuffer *inst, uint8_t *b) +{ + if (cbuf_empty(inst)) return false; + + *b = inst->buffer[inst->read_pos]; + + inst->read_pos++; + inst->data_len--; + + // wrap + if (inst->read_pos >= inst->capacity) { + inst->read_pos = 0; + } + + return true; +} + + +bool cbuf_peek(CircularBuffer *inst, uint8_t *b) +{ + if (cbuf_empty(inst)) return false; + + *b = inst->buffer[inst->read_pos]; + return true; +} + + +uint16_t cbuf_data_size(CircularBuffer *inst) +{ + return inst->data_len; +} + + +uint16_t cbuf_free_space(CircularBuffer *inst) +{ + return inst->capacity - inst->data_len; +} + + +void cbuf_clear(CircularBuffer *inst) +{ + inst->read_pos = 0; + inst->write_pos = 0; + inst->data_len = 0; +} + + +bool cbuf_write_n(CircularBuffer *inst, const uint8_t *b, uint16_t count) +{ + if (cbuf_free_space(inst) < count) return false; + + for (uint16_t i = 0; i < count; i++) { + cbuf_write(inst, *(b + i)); + } + + return true; +} + + +bool cbuf_write_string(CircularBuffer *inst, const char *str) +{ + return cbuf_write_n(inst, (uint8_t *) str, strlen(str)); +} + + +bool cbuf_read_n(CircularBuffer *inst, uint8_t *buf, uint16_t len) +{ + if (cbuf_data_size(inst) < len) return false; + + for (uint16_t i = 0; i < len; i++) { + cbuf_read(inst, buf + i); + } + + return true; +} + + +bool cbuf_read_string(CircularBuffer *inst, char *str, uint16_t len) +{ + bool b = cbuf_read_n(inst, (uint8_t *) str, len); + if (!b) return false; + + str[len] = 0; + + return true; +} + + +uint16_t cbuf_read_upto(CircularBuffer *inst, uint8_t *buf, uint16_t max) +{ + uint16_t i; + for (i = 0; i < max; i++) { + if (cbuf_empty(inst)) break; + cbuf_read(inst, buf + i); + } + + return i; +} + + +uint16_t cbuf_read_string_upto(CircularBuffer *inst, char *str, uint16_t max) +{ + uint16_t cnt = cbuf_read_upto(inst, (uint8_t *) str, max); + str[cnt] = 0; + return cnt; +} + + +int32_t cbuf_find(CircularBuffer *inst, uint8_t b) +{ + uint16_t cursor = inst->read_pos; + uint16_t cnt = 0; + + while (cursor != inst->write_pos) { + + if (inst->buffer[cursor] == b) return cnt; + + cursor++; + cnt++; + + // wrap + if (cursor >= inst->capacity) { + cursor = 0; + } + } + + return -1; +} + diff --git a/circbuf.h b/circbuf.h new file mode 100644 index 0000000..6fb0d97 --- /dev/null +++ b/circbuf.h @@ -0,0 +1,79 @@ +#pragma once +#include +#include + +typedef struct { + uint8_t *buffer; + uint16_t capacity; + uint16_t read_pos; + uint16_t write_pos; + uint16_t data_len; +} CircularByteBuffer; + + +/** Init a buffer */ +void cbuf_init(CircularByteBuffer *inst, uint8_t *buffer, uint16_t length); + + +/** Test for full buffer */ +bool cbuf_full(CircularByteBuffer *inst); + + +/** Test for empty buffer */ +bool cbuf_empty(CircularByteBuffer *inst); + + +/** Write a byte to buffer, returns success */ +bool cbuf_write(CircularByteBuffer *inst, uint8_t b); + + +/** Read a byte from the buffer, return susccess */ +bool cbuf_read(CircularByteBuffer *inst, uint8_t *b); + + +/** Get byte at the read cursor, without incrementing it. False on empty. */ +bool cbuf_peek(CircularByteBuffer *inst, uint8_t *b); + + +/** Get data count */ +uint16_t cbuf_data_size(CircularByteBuffer *inst); + + +/** Get free space in the buffer */ +uint16_t cbuf_free_space(CircularByteBuffer *inst); + + +/** Remove all data from buffer */ +void cbuf_clear(CircularByteBuffer *inst); + + +/** Write N bytes. Returns success */ +bool cbuf_write_n(CircularByteBuffer *inst, const uint8_t *b, uint16_t count); + + +/** Write a string (without \0) */ +bool cbuf_write_string(CircularByteBuffer *inst, const char *str); + + +/** Read N bytes, if available. Returns success. */ +bool cbuf_read_n(CircularByteBuffer *inst, uint8_t *buf, uint16_t len); + + +/** Read string of given length, append \0. `str` must be len+1 long */ +bool cbuf_read_string(CircularByteBuffer *inst, char *str, uint16_t len); + + +/** Read up to N bytes. Returns byte count */ +uint16_t cbuf_read_upto(CircularByteBuffer *inst, uint8_t *buf, uint16_t max); + + +/** Read string up to N chars long, append \0. `str` must be max+1 long */ +uint16_t cbuf_read_string_upto(CircularByteBuffer *inst, char *str, uint16_t max); + + +/** + * Search buffer and return position of the first occurence + * of the given byte (position relative to read_pos). + * Returns -1 if not found. + */ +int32_t cbuf_find(CircularByteBuffer *inst, uint8_t b);