moved to folders, updated etc

master
Ondřej Hruška 9 years ago
parent a6f31599c6
commit 891c07f5fb
  1. 48
      README.md
  2. 101
      circbuf.c
  3. 51
      circbuf.h
  4. 51
      circbuf/README.md
  5. 167
      circbuf/circbuf.c
  6. 93
      circbuf/circbuf.h
  7. 21
      matcher.h
  8. 14
      matcher/README.md
  9. 5
      matcher/matcher.c
  10. 39
      matcher/matcher.h
  11. 21
      meanbuf.h
  12. 11
      meanbuf/README.md
  13. 22
      meanbuf/meanbuf.c
  14. 31
      meanbuf/meanbuf.h

@ -1,43 +1,15 @@
Circular byte buffer
====================
Buffers
=======
**(and other buffers)**
This is a collection of useful buffer modules for C programs.
This is a circular buffer implementation, useful mainly for embedded systems (buffer for UART RX/TX queues etc).
- **circbuf** - generic circular buffer, queue, stack
- **matcher** - pattern matcher for character streams
- **meanbuf** - averaging (smoothing) buffer.
It should be reliable with producent / consumer threads (no race conditions, as no length variable is used).
A Matching buffer, and Averaging buffer are also included—see their header files for instructions.
Usage
-----
```c
#include <stdint.h>
#include "circbuf.h"
circbuf_t cb; // buffer instance
void main()
{
char c;
cbuf_init(&cb, 32); // init the buffer
// now it's ready for use!
cbuf_write(&cb, 'A');
if (cbuf_read(&cb, &c)) {
printf("%c", c);
}
cbuf_deinit(&cb); // free the backing array (in embedded system you don't usually need to, allocate once and keep it)
}
```
Most functions return a success flag (true - success), so make sure to check the return values.
False is returned on buffer overflow / underflow. See the header file for details.
*Please see READMEs in the project folders for more details.*
The buffers were developed for embedded microcontrollers (STM32, AVR),
but can be used anywhere, they are fully portable.
Pull requests to add new buffers or improve the current ones are welcome!

@ -1,101 +0,0 @@
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <malloc.h>
#include "circbuf.h"
void cbuf_init(circbuf_t *inst, size_t capacity)
{
inst->buf = malloc(capacity);
inst->cap = capacity;
cbuf_clear(inst);
}
void cbuf_deinit(circbuf_t *inst)
{
if (inst->buf != NULL) {
free(inst->buf);
}
}
bool cbuf_full(circbuf_t *inst)
{
return (inst->lr == inst->nw);
}
static bool can_read_at(circbuf_t *inst, size_t i)
{
if (inst->lr < inst->nw) {
return i > inst->lr && i < inst->nw;
} else {
// NW < LR
return (i < inst->cap && i > inst->lr) || i < inst->nw;
}
}
bool cbuf_empty(circbuf_t *inst)
{
return ((inst->lr + 1) % inst->cap) == inst->nw;
}
bool cbuf_write(circbuf_t *inst, uint8_t b)
{
if (cbuf_full(inst)) return false;
inst->buf[inst->nw] = b;
// increment
inst->nw++;
if (inst->nw == inst->cap) inst->nw = 0;
return true;
}
bool cbuf_read(circbuf_t *inst, uint8_t *b)
{
if (cbuf_empty(inst)) return false;
// increment
inst->lr++;
if (inst->lr == inst->cap) inst->lr = 0;
*b = inst->buf[inst->lr];
//zero out the read byte (for debug)
inst->buf[inst->lr] = 0;
return true;
}
bool cbuf_peek(circbuf_t *inst, size_t nth, uint8_t *b)
{
// check if can read there (can't use modulo, could "wrap")
size_t n = inst->lr;
for (size_t i = 0; i <= nth; i++) {
// increment N
n++;
if (n == inst->cap) n = 0;
if (!can_read_at(inst, n)) return false;
}
*b = inst->buf[n];
return true;
}
void cbuf_clear(circbuf_t *inst)
{
inst->lr = inst->cap - 1;
inst->nw = 0;
}

@ -1,51 +0,0 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
// Circular Character Buffer implementation
typedef struct CircularBuffer_struct {
uint8_t *buf;
size_t cap;
size_t lr; // last read pos
size_t nw; // next write pos
} circbuf_t;
/** Init a buffer */
void cbuf_init(circbuf_t *inst, size_t capacity);
/** Deinit a buffer (free the memory) */
void cbuf_deinit(circbuf_t *inst);
/** Test for full buffer */
bool cbuf_full(circbuf_t *inst);
/** Test for empty buffer */
bool cbuf_empty(circbuf_t *inst);
/** Write a byte to buffer, returns success */
bool cbuf_write(circbuf_t *inst, uint8_t b);
/**
* Read a byte from the buffer, return susccess.
* If `b` is NULL, the read byte is discarded.
*/
bool cbuf_read(circbuf_t *inst, uint8_t *b);
/**
* Get n-th byte from the buffer, without removing it.
* Returns false if offset is invalid (ie. empty buffer).
*/
bool cbuf_peek(circbuf_t *inst, size_t nth, uint8_t *b);
/** Remove all data from buffer */
void cbuf_clear(circbuf_t *inst);

@ -0,0 +1,51 @@
Circular buffer
===============
This is a C implementation of a circular buffer, which can also be used
as a queue or stack.
Supported operations: `push`, `pop`, `append`.
To achieve thread safety (to some extent) in a producent-consumer situation,
there is no length variable, only write pointers.
The buffer has a fixed size, values are copied when inserted. The buffer is created using `malloc`.
If your platform does not support `malloc`, you will have to customize the initialization routine.
Applications
------------
- Buffer for USARTs or similar communication interfaces
- Event queue
- Object stack
Usage
-----
```c
#include <stdint.h>
#include "circbuf.h"
CircBuf *cb; // buffer instance
void main()
{
cb = cbuf_make(32, sizeof(char)); // create a char buffer of size 32.
// now it's ready for use!
// write functions return true on success:
cbuf_append(cb, 'A'); // append A (using as a queue)
cbuf_push(cb, 'B'); // push B (using as a stack)
// read all
char c;
while (cbuf_pop(cb, &c)) {
printf("%c", c);
}
cbuf_destroy(cb); // free the buffer
}
```
For details how to use each function, please read the header file.

@ -0,0 +1,167 @@
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <malloc.h>
#include "circbuf.h"
// --- Circbuf data structure ----
/** Offset in void* buffer */
#define PV_OFFS(pvBuf, elem_size, index) ((uint8_t*)(pvBuf) + ((elem_size)*(index)))
// Instance structure
struct circbuf_struct {
void *buf;
size_t elem_size;
size_t cap;
size_t lr; // last read pos
size_t nw; // next write pos
};
/**
* @brief Write data to a CircBuf slot
* @param cb : circbuf
* @param index : slot index
* @param source : data source
*/
static void write_buffer(CircBuf *cb, size_t index, const void *source)
{
memcpy(PV_OFFS(cb->buf, cb->elem_size, index), source, cb->elem_size);
}
/**
* @brief Copy data from a CircBuf slot to a buffer
* @param cb : circbuf
* @param index : slot index
* @param dest : destination buffer
*/
static void read_buffer(const CircBuf *cb, size_t index, void *dest)
{
memcpy(dest, PV_OFFS(cb->buf, cb->elem_size, index), cb->elem_size);
}
/** Create a cbuf */
CircBuf *cbuf_make(size_t capacity, size_t elem_size)
{
// add one, because one is always unused.
capacity++;
// Allocate the structure
CircBuf *cb = malloc(sizeof(CircBuf));
if (cb == NULL) {
return NULL;
}
// allocate the buffer
cb->buf = malloc(capacity * elem_size);
if (cb->buf == NULL) {
free(cb); // fail - free structure.
return NULL;
}
// set capacity, clear state
cb->elem_size = elem_size;
cb->cap = capacity;
cbuf_clear(cb);
return cb;
}
/** Release cbuf memory */
void cbuf_destroy(CircBuf *cb)
{
if (cb != NULL) {
if (cb->buf != NULL) {
free(cb->buf);
}
free(cb);
}
}
/** Check if cbuf is full */
bool cbuf_full(const CircBuf *cb)
{
if (cb == NULL) return false;
return (cb->lr == cb->nw);
}
/** Check if cbuf is empty */
bool cbuf_empty(const CircBuf *cb)
{
if (cb == NULL) return true;
return ((cb->lr + 1) % cb->cap) == cb->nw;
}
/** Write a byte to the buffer, if space left */
bool cbuf_append(CircBuf *cb, const void *source)
{
if (cb == NULL) return false;
if (source == NULL) return false;
if (cbuf_full(cb)) return false;
write_buffer(cb, cb->nw, source);
// increment
cb->nw++;
if (cb->nw == cb->cap) cb->nw = 0;
return true;
}
/** Push value to the end, like a stack. */
bool cbuf_push(CircBuf *cb, const void *source)
{
if (cb == NULL) return false;
if (source == NULL) return false;
if (cbuf_full(cb)) return false;
write_buffer(cb, cb->lr, source);
// move lr back
if (cb->lr == 0) {
cb->lr = cb->cap - 1; // wrap to the end
} else {
cb->lr--;
}
return true;
}
/** Read one byte, if not empty. */
bool cbuf_pop(CircBuf *cb, void *dest)
{
if (cb == NULL || dest == NULL) return false;
if (cbuf_empty(cb)) return false;
// increment
cb->lr++;
if (cb->lr == cb->cap) cb->lr = 0;
read_buffer(cb, cb->lr, dest);
return true;
}
/** Clear a cbuf */
void cbuf_clear(CircBuf *cb)
{
if (cb == NULL) return;
cb->lr = cb->cap - 1;
cb->nw = 0;
}

@ -0,0 +1,93 @@
/**
* @file circbuf.h
* @author Ondřej Hruška, 2016
*
* Circular buffer / queue / stack.
* Slots are pre-allocated, values are copied into the buffer.
*
* The buffer may be used as a stack, event queue or a simple buffer.
*
* -------------------------------------
*
* NW LR
* append -> [][][][] -> pop
* <- push
*
* NW - next write pointer (stack base)
* LR - last read position (stack top)
*
* -------------------------------------
*
* MIT license
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
typedef struct circbuf_struct CircBuf;
/**
* @brief Initialize a circular buffer. The buffer is malloc'd.
* @param capacity : buffer capacity
* @param elem_size : size of one element
* @return pointer to the buffer instance
*/
CircBuf *cbuf_make(size_t capacity, size_t elem_size);
/**
* @brief Destroy a buffer, freeing used memory.
*
* @attention
* If the buffer items have malloc'd members, you have
* to free them manually to avoid a memory leak.
*
* @param cb : buffer
*/
void cbuf_destroy(CircBuf *cb);
/** Test for full buffer */
bool cbuf_full(const CircBuf *cb);
/** Test for empty buffer */
bool cbuf_empty(const CircBuf *cb);
/**
* @brief Append a value to the buffer (FIFO)
* @param cb : buffer
* @param source : pointer to a value (will be copied)
* @return success
*/
bool cbuf_append(CircBuf *cb, const void *source);
/**
* @brief Push a value into the circbuf (LIFO).
*
* @param cb : buffer
* @param source : pointer to a value (will be copied)
* @return success
*/
bool cbuf_push(CircBuf *cb, const void *source);
/**
* @brief Read a value from the buffer, return susccess.
*
* @param cb : buffer
* @param dest : read destionation. If NULL, value is discarded.
* @return success
*/
bool cbuf_pop(CircBuf *cb, void *dest);
/** @brief Remove all data from buffer */
void cbuf_clear(CircBuf *cb);

@ -1,21 +0,0 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
typedef struct {
const char *pattern;
size_t cursor;
} matcher_t;
/**
* Consume an incoming character.
* If this char was the last char of the pattern, returns true and rewinds.
*
* If the char is not in the pattern, resets match state.
*
* @returns true if the char concluded the expected pattern.
*/
bool matcher_test(matcher_t * mb, uint8_t b);

@ -0,0 +1,14 @@
Character stream pattern matcher
================================
Matcher can be used for detecting a pattern in a stream of characters.
With each incoming character, call `matcher_test()`.
It will return true if the character completed a match.
Applications
------------
This buffer was designed for parsing responses to AT commands from ESP8266.
It can be used for any similar purpose.

@ -5,6 +5,11 @@
#include "matcher.h"
void matcher_reset(matcher_t *m)
{
m->cursor = 0;
}
/** Handle incoming char. Returns true if this char completed the match. */
bool matcher_test(matcher_t * m, uint8_t b)

@ -0,0 +1,39 @@
/**
* @file matcher.h
* @author Ondřej Hruška, 2016
*
* String matching utility.
*
* Matcher can be used for detecting a pattern in a stream of characters.
* With each incoming character, call matcher_test().
*
* It will return true if the character completed a match.
*
* MIT license
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
typedef struct {
const char *pattern;
size_t cursor;
} matcher_t;
/** reset match progress */
void matcher_reset(matcher_t *m);
/**
* Consume an incoming character.
* If this char was the last char of the pattern, returns true and resets matcher.
*
* If the char is not in the pattern, resets matcher.
*
* @returns true if the char concluded the expected pattern.
*/
bool matcher_test(matcher_t * mb, uint8_t b);

@ -1,21 +0,0 @@
#pragma once
#include <stdlib.h>
#include <stdint.h>
typedef struct {
float * buf; // buffer (allocated at init)
size_t cap; // capacity
size_t nw; // next write index
float mean; // updated on write
} meanbuf_t;
/** Init a buffer */
void meanbuf_init(meanbuf_t *mb, size_t size);
/** Deinit a buffer (free buffer array) */
void meanbuf_deinit(meanbuf_t *mb);
/** Add a value to the buffer. Returns current mean. */
float meanbuf_add(meanbuf_t *mb, float f);

@ -0,0 +1,11 @@
Averaging float buffer
======================
*(You can adjust it to use doubles, if you prefer.)*
The `meanbuf_create()` function allocates a buffer.
You can then call `meanbuf_add()` to add a new value into the buffer (and remove the oldest).
This function returns the current average value.
This buffer can be used for **signal smoothing** (such as from an analogue sensor).

@ -4,9 +4,19 @@
#include "meanbuf.h"
struct meanbuf_struct {
float * buf; // buffer (allocated at init)
size_t cap; // capacity
size_t nw; // next write index
float mean; // updated on write
};
/** Init a buffer */
void meanbuf_init(meanbuf_t *mb, size_t size)
MeanBuf *meanbuf_create(size_t size)
{
MeanBuf *mb = malloc(sizeof(MeanBuf));
if (size < 1) size = 1;
mb->buf = calloc(size, sizeof(float)); // calloc, so it starts with zeros.
@ -18,19 +28,25 @@ void meanbuf_init(meanbuf_t *mb, size_t size)
for (uint16_t i = 0; i < size; i++) {
mb->buf[i] = 0;
}
return mb;
}
void meanbuf_deinit(meanbuf_t *mb)
void meanbuf_destroy(MeanBuf *mb)
{
if (mb == NULL) return;
if (mb->buf != NULL) {
free(mb->buf);
}
free(mb);
}
/** Add a value to the buffer. Returns current mean. */
float meanbuf_add(meanbuf_t *mb, float f)
float meanbuf_add(MeanBuf *mb, float f)
{
// add sample
mb->buf[mb->nw++] = f;

@ -0,0 +1,31 @@
/**
* @file meanbuf.h
* @author Ondřej Hruška, 2016
*
* Averaging float buffer. (You can adjust it to use doubles, if you prefer.)
*
* The meanbuf_create() function allocates a buffer.
*
* You can then call meanbuf_add() to add a new value into the buffer (and remove the oldest).
* This function returns the current average value.
*
* This buffer can be used for signal smoothing (such as from an analogue sensor).
*
* MIT license
*/
#pragma once
#include <stdlib.h>
#include <stdint.h>
typedef struct meanbuf_struct MeanBuf;
/** Init a buffer */
MeanBuf *meanbuf_create(size_t size);
/** Deinit a buffer (free buffer array) */
void meanbuf_destroy(MeanBuf *mb);
/** Add a value to the buffer. Returns current mean. */
float meanbuf_add(MeanBuf *mb, float f);
Loading…
Cancel
Save