Skip to content

Commit 08a0e0e

Browse files
authored
Implement a (Firmware) Circular Buffer (#1442)
* Add circular buffer skeleton with push and rudimentary get_index methods * Add implmenetation with error catching on get_index * Add comment headers in header file * Fix formatting * Fix comment * Fix functions to resemble fw standards * Fix minor cbuffer comments * Clean up comments and variable names * Fix assert statement * Test death assertions and remove destroy() * Add front method and tests, clean up variable names * Remove assertion with negative for uint8 * Re-add circularbufferdestroy * Add initzero test and nitpicks * Change to size_t head and tail * Add test for circular_buffer_create init 0 * Add @pre * Remove stdint * Add stdbool * Rephrase comment in header * Add empty to tests * Fix comments
1 parent 1631d77 commit 08a0e0e

File tree

4 files changed

+395
-0
lines changed

4 files changed

+395
-0
lines changed

src/firmware/shared/BUILD

+18
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,21 @@ cc_library(
2727
"//firmware/shared/math:tbots_math",
2828
],
2929
)
30+
31+
cc_library(
32+
name = "circular_buffer",
33+
srcs = ["circular_buffer.c"],
34+
hdrs = ["circular_buffer.h"],
35+
deps = [
36+
"//shared:constants",
37+
],
38+
)
39+
40+
cc_test(
41+
name = "circular_buffer_test",
42+
srcs = ["circular_buffer_test.cpp"],
43+
deps = [
44+
":circular_buffer",
45+
"@gtest//:gtest_main",
46+
],
47+
)

src/firmware/shared/circular_buffer.c

+88
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
#include "firmware/shared/circular_buffer.h"
2+
3+
#include <assert.h>
4+
5+
struct CircularBuffer
6+
{
7+
size_t head;
8+
size_t tail;
9+
size_t max_size;
10+
float *buffer_data;
11+
bool is_full;
12+
};
13+
14+
CircularBuffer_t *circular_buffer_create(size_t size)
15+
{
16+
// Check if size is greater than 0
17+
assert(size > 0);
18+
19+
CircularBuffer_t *new_cbuffer = malloc(sizeof(CircularBuffer_t));
20+
21+
new_cbuffer->head = 0;
22+
new_cbuffer->tail = 0;
23+
new_cbuffer->max_size = size;
24+
new_cbuffer->buffer_data = (float *)malloc(sizeof(float) * new_cbuffer->max_size);
25+
new_cbuffer->is_full = false;
26+
27+
return new_cbuffer;
28+
}
29+
30+
void circular_buffer_destroy(CircularBuffer_t *cbuffer)
31+
{
32+
free(cbuffer->buffer_data);
33+
free(cbuffer);
34+
}
35+
36+
void circular_buffer_push(CircularBuffer_t *cbuffer, float data)
37+
{
38+
cbuffer->buffer_data[cbuffer->head] = data;
39+
cbuffer->head = ++(cbuffer->head) % cbuffer->max_size;
40+
if (circular_buffer_isFull(cbuffer) == true)
41+
{
42+
cbuffer->tail = ++(cbuffer->tail) % cbuffer->max_size;
43+
}
44+
45+
// Implementation assumes head and tail are equal when full
46+
if (cbuffer->head == cbuffer->tail)
47+
{
48+
cbuffer->is_full = true;
49+
}
50+
}
51+
52+
float circular_buffer_getAtIndex(CircularBuffer_t *cbuffer, size_t index)
53+
{
54+
// Check if index is larger than the maximum buffer size
55+
assert(index <= cbuffer->max_size);
56+
57+
// Check if enough items are in the buffer for index
58+
assert(circular_buffer_isFull(cbuffer) == true || index <= cbuffer->head);
59+
60+
int requested_index = (cbuffer->head % cbuffer->max_size) - index - 1;
61+
62+
// Check if requestedIndex needs to be looped
63+
if (requested_index < 0)
64+
{
65+
requested_index = cbuffer->max_size + requested_index;
66+
}
67+
float res = cbuffer->buffer_data[requested_index];
68+
return res;
69+
}
70+
71+
float circular_buffer_front(CircularBuffer_t *cbuffer)
72+
{
73+
// Check if buffer is empty
74+
assert(!circular_buffer_isEmpty(cbuffer));
75+
76+
float res = circular_buffer_getAtIndex(cbuffer, 0);
77+
return res;
78+
}
79+
80+
bool circular_buffer_isFull(CircularBuffer_t *cbuffer)
81+
{
82+
return cbuffer->is_full;
83+
}
84+
85+
bool circular_buffer_isEmpty(CircularBuffer_t *cbuffer)
86+
{
87+
return (circular_buffer_isFull(cbuffer) == false && cbuffer->head == 0);
88+
}

src/firmware/shared/circular_buffer.h

+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
#include <stdbool.h>
2+
#include <stdlib.h>
3+
4+
/**
5+
* This struct represents the circular buffer properties
6+
*/
7+
typedef struct CircularBuffer CircularBuffer_t;
8+
9+
/**
10+
* Initialize the circular_buffer struct members
11+
*
12+
* @param size Size of the circular_buffer to set
13+
*
14+
* @pre: `size` must be larger than 0
15+
*
16+
* @return A pointer to the created circular_buffer, ownership is given to the caller
17+
*/
18+
CircularBuffer_t *circular_buffer_create(size_t size);
19+
20+
/**
21+
* Destroy the circular_buffer, freeing any memory allocated for it
22+
*
23+
* @param cbuffer The circular_buffer to destroy
24+
*/
25+
void circular_buffer_destroy(CircularBuffer_t *cbuffer);
26+
27+
/**
28+
* Push data into the circular_buffer
29+
* If full, will overwrite the oldest value
30+
*
31+
* @param cbuffer The circular_buffer
32+
* @param data Value to be inserted into the circular_buffer
33+
*/
34+
void circular_buffer_push(CircularBuffer_t *cbuffer, float data);
35+
36+
/**
37+
* Retrieve a relative recent value in the circular_buffer
38+
*
39+
* @param cbuffer The circular_buffer
40+
* @param index Index relative to the most recent value in the buffer
41+
*
42+
* @pre: `index` must be less than the max_size of the circular_buffer
43+
*
44+
* @return Data from the index which is relative to the most recent value in the buffer.
45+
* Eg. 0 is the most recent value, 1 is the second most recent, etc
46+
*/
47+
float circular_buffer_getAtIndex(CircularBuffer_t *cbuffer, size_t index);
48+
49+
/**
50+
* Retrieve the most recent value in the circular_buffer
51+
* Retrieved value is not destroyed or removed from circular_buffer
52+
*
53+
* @param cbuffer The circular_buffer
54+
*
55+
* @pre: At least one item must be in the circular_buffer
56+
*
57+
* @return The most recent value
58+
*/
59+
float circular_buffer_front(CircularBuffer_t *cbuffer);
60+
61+
/**
62+
* Return if the circular_buffer is full
63+
*
64+
* @param cbuffer The circular_buffer
65+
*
66+
* @return A boolean indicating if the circular_buffer is full
67+
*/
68+
bool circular_buffer_isFull(CircularBuffer_t *cbuffer);
69+
70+
/**
71+
* Return if the circular_buffer is empty
72+
*
73+
* @param cbuffer The circular_buffer
74+
*
75+
* @return A boolean indicating if the circular_buffer is empty
76+
*/
77+
bool circular_buffer_isEmpty(CircularBuffer_t *cbuffer);

0 commit comments

Comments
 (0)