|
@@ -0,0 +1,199 @@
|
|
|
+http://tath.eu/code/ring-buffer-in-c/
|
|
|
+
|
|
|
+Ring buffer is very common and useful data structure, excellent for storing
|
|
|
+asynchronous data from multiple sources in embedded devices.
|
|
|
+
|
|
|
+ringbuffer.h
|
|
|
+// Simple prove-of-concept ring buffer
|
|
|
+// Author: Adam Orcholski, www.tath.eu
|
|
|
+#pragma once
|
|
|
+
|
|
|
+// types
|
|
|
+typedef struct ring_buffer_s
|
|
|
+{
|
|
|
+ unsigned char * data; // pointer to external buffer
|
|
|
+ int size; // size of external buffer
|
|
|
+ int head; // index of free space in external buffer
|
|
|
+ int tail; // index of last item to be read
|
|
|
+ int count; // hold number of items stored but not read
|
|
|
+} ring_buffer_t;
|
|
|
+
|
|
|
+// interface
|
|
|
+void RING_Init(ring_buffer_t * const buff_state, unsigned char * in_buffer, int buffer_size_in_bytes);
|
|
|
+void RING_Reset(ring_buffer_t * const buff_state); // note: does not clear external buffer
|
|
|
+int RING_IsEmpty(ring_buffer_t * const buff_state); // return non-zero if buffer is empty
|
|
|
+int RING_IsFull(ring_buffer_t * const buff_state); // return non-zero if buffer is full
|
|
|
+int RING_AddItem(ring_buffer_t * const buff_state, unsigned char new_item); // return non-zero if buffer is full
|
|
|
+int RING_GetItem(ring_buffer_t * const buff_state, unsigned char * const out_item); // return non-zero if buffer is empty
|
|
|
+
|
|
|
+ringbuffer.c
|
|
|
+// Simple prove-of-concept ring buffer
|
|
|
+// Author: Adam Orcholski, www.tath.eu
|
|
|
+
|
|
|
+#include <ringbuffer.h>
|
|
|
+#include <assert.h>
|
|
|
+
|
|
|
+
|
|
|
+// function definitions
|
|
|
+void RING_Init(ring_buffer_t * const buff_state, unsigned char * in_buffer, int buffer_size_in_bytes)
|
|
|
+{
|
|
|
+ assert(0 != buff_state);
|
|
|
+ assert(0 != in_buffer);
|
|
|
+ assert(buffer_size_in_bytes > 0);
|
|
|
+
|
|
|
+ buff_state->data = in_buffer;
|
|
|
+ buff_state->size = buffer_size_in_bytes;
|
|
|
+ buff_state->head = 0;
|
|
|
+ buff_state->tail = 0;
|
|
|
+ buff_state->count = 0;
|
|
|
+}
|
|
|
+
|
|
|
+void RING_Reset(ring_buffer_t * const buff_state)
|
|
|
+{
|
|
|
+ assert(0 != buff_state);
|
|
|
+
|
|
|
+ buff_state->head = 0;
|
|
|
+ buff_state->tail = 0;
|
|
|
+ buff_state->count = 0;
|
|
|
+}
|
|
|
+
|
|
|
+// return non-zero value if buffer is empty
|
|
|
+int RING_IsEmpty(ring_buffer_t * const buff_state)
|
|
|
+{
|
|
|
+ int fBufferIsEmpty = 0;
|
|
|
+
|
|
|
+ assert(0 != buff_state);
|
|
|
+
|
|
|
+ if (0 == buff_state->count)
|
|
|
+ {
|
|
|
+ fBufferIsEmpty = 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ return fBufferIsEmpty;
|
|
|
+}
|
|
|
+
|
|
|
+// return non-zero value if buffer is full
|
|
|
+int RING_IsFull(ring_buffer_t * const buff_state)
|
|
|
+{
|
|
|
+ int fBufferIsFull = 0;
|
|
|
+
|
|
|
+ assert(0 != buff_state);
|
|
|
+
|
|
|
+ if (buff_state->count >= buff_state->size)
|
|
|
+ {
|
|
|
+ fBufferIsFull = 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ return fBufferIsFull;
|
|
|
+}
|
|
|
+
|
|
|
+// return non-zero value if buffer is full
|
|
|
+int RING_AddItem(ring_buffer_t * const buff_state, unsigned char new_item)
|
|
|
+{
|
|
|
+ int fBufferIsFull = 0;
|
|
|
+
|
|
|
+ assert(0 != buff_state);
|
|
|
+
|
|
|
+ fBufferIsFull = RING_IsFull(buff_state);
|
|
|
+
|
|
|
+ if (!fBufferIsFull)
|
|
|
+ {
|
|
|
+ buff_state->data[buff_state->head] = new_item;
|
|
|
+ buff_state->head++;
|
|
|
+ buff_state->count++;
|
|
|
+
|
|
|
+ if (buff_state->head >= buff_state->size)
|
|
|
+ {
|
|
|
+ buff_state->head = 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ return fBufferIsFull;
|
|
|
+}
|
|
|
+
|
|
|
+// return non-zero value if buffer is empty
|
|
|
+int RING_GetItem(ring_buffer_t * const buff_state, unsigned char * const out_item)
|
|
|
+{
|
|
|
+ int fBufferIsEmpty = 0;
|
|
|
+
|
|
|
+ assert(0 != buff_state);
|
|
|
+ assert(0 != out_item);
|
|
|
+
|
|
|
+ fBufferIsEmpty = RING_IsEmpty(buff_state);
|
|
|
+
|
|
|
+ if (!fBufferIsEmpty)
|
|
|
+ {
|
|
|
+ *out_item = buff_state->data[buff_state->tail];
|
|
|
+ buff_state->tail++;
|
|
|
+ buff_state->count--;
|
|
|
+
|
|
|
+ if (buff_state->tail >= buff_state->size)
|
|
|
+ {
|
|
|
+ buff_state->tail = 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return fBufferIsEmpty;
|
|
|
+}
|
|
|
+
|
|
|
+and example/test compiled in Microsoft Visual Studio:
|
|
|
+
|
|
|
+main.c
|
|
|
+// Simple prove-of-concept ring buffer example
|
|
|
+// Author: Adam Orcholski, www.tath.eu
|
|
|
+
|
|
|
+#include <stdio.h>
|
|
|
+#include <ringbuffer.h>
|
|
|
+
|
|
|
+#define BUFF_SIZE 4
|
|
|
+unsigned char bufffeeer[BUFF_SIZE];
|
|
|
+
|
|
|
+ring_buffer_t buff;
|
|
|
+
|
|
|
+int main()
|
|
|
+{
|
|
|
+ RING_Init(&buff, bufffeeer, sizeof(bufffeeer));
|
|
|
+
|
|
|
+ char c = 0;
|
|
|
+
|
|
|
+ while (c != 'q')
|
|
|
+ {
|
|
|
+ static char write_char = 'a';
|
|
|
+ c = getchar();
|
|
|
+
|
|
|
+ int ret = 0;
|
|
|
+
|
|
|
+ if (c == 'w')
|
|
|
+ {
|
|
|
+ ret = RING_AddItem(&buff, write_char);
|
|
|
+ if (ret)
|
|
|
+ {
|
|
|
+ printf("buffer full\r\n");
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ printf("written char = %c\r\n", write_char);
|
|
|
+ }
|
|
|
+ write_char++;
|
|
|
+ if (write_char == 'z') { write_char = 'a'; }
|
|
|
+ }
|
|
|
+ else if (c == 's')
|
|
|
+ {
|
|
|
+ char out;
|
|
|
+ ret = RING_GetItem(&buff, &out);
|
|
|
+ if (ret)
|
|
|
+ {
|
|
|
+ printf("buffer empty\r\n");
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ printf("read char = %c\r\n", out);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+Run example, and press W key to add item to buffer and S key to read last item. Press Q to quit.
|