BriComp
Well-known member
EDIT: I have changed the name of the library to UniversalRingBuffer. It is stored/available here. Where CircularBuffer is stated "insert" RingBuffer. Nothing other than the name has changed except SaveRBInfo and SaveRBInfo rather than CB.
I have just created a new Library here which creates/manages a CircularBuffer aka software Rolodex.
It can be used for any type of data as long as each entry is of the same physical size.
I will post the ReadMe below, but would appreciate your help. Is CircularBuffer the correct/appropriate name for the library?
I have just created a new Library here which creates/manages a CircularBuffer aka software Rolodex.
It can be used for any type of data as long as each entry is of the same physical size.
I will post the ReadMe below, but would appreciate your help. Is CircularBuffer the correct/appropriate name for the library?
The following sketch is an example of it's usage.***CircularBuffer***
This library is designed to offer a Circular buffer control aka **Rolodex**.
Although other libraries exist they are usually limited to storing standard numeric
types, eg uint32_t, int etc. With this library you can use any type you wish, create
your own type in a struct and use that. No problem.
The library manages the index into the array/storage structure. It is NOT limited to
storage in an array in memory but could be used to store data in EEPROM, SD card or
any other storage medium.
If you examine the Example **TestCircularBuffer** I have used an array of char, just because
it's easy to track the addition of ASCII characters to demonstrate usage.
You start off by defining your storage medium. As I said before it can be used for
any storage medium but for the purposes of describing it's usage I will use arrays of char
by way of examples.
Then create an instance of the **CircularBuffer** passing the Maximum size of the array.
By maximum size I mean maximum index, NOT the storage size i.e. `data[ maximumSize]`.
AddDataToBuffer()
Ok, that's it we can now start storing data into our "**Rolodex**" type storage medium.
To add data just use **AddDataToBuffer()**. This function returns the index of the array
where the data is to be stored. So usage is **buffer[ cBuf.AddDataToBuffe() ] = dataChar**.
You can keep on adding data to your hearts content, storing many more items than the
original array could accommodate. Bear in mind that once you have exceeded the size of the
original array that the data will roll over and overwrite the original data. The array index
returned by **AddDataToBuffer()** will always be a legal array location. Think of this like
having completely filled your Rolodex and have to remove a card to add new information.
The library works in a LIFO manner.
ReadFromHead(), ReadFromTail()
Having stored the data you will want to do something with it. Retrieval of the data starts
by using the functions either **ReadFromHead()** or **ReadFromTail()**. Head represents the
last entered data and tail represents the first entered data. **ReadFromHead()** and
**ReadFromTail()** both return an index into the array of data. they can be used like:-
`Serial.print( buffer[ cBuf.ReadFromHead() ] );` where the data is returned from the array
and printed.
ReadNext()
In order to continue retrieving data from the store (array) we now use the function
**ReadNext().** This returns the next array index in the sequence and is used in the
same manner as the previously described functions **ReadFromHead()** and **ReadFromTail()**,
those having set the direction for subsequent **ReadNext()**s. As you can imagine it would
be possible to read past head or tail which would give rise to an erroneous condition.
To ensure that this does not happen the boolean variable **badCommand** is set to true
and the index returned by **ReadNext()** is NOT incremented or decremented, i.e. the
previous value is returned.
The **badCommand** is reset to false by using either **ReadFromHead()** or **ReadFromTail()** again.
MaxBufferSize(), currentBufferLength()
In order to help with data management there are two functions which return array information.
these are **MaxBufferSize()**, which effectively returns the original maximum array index passed
when the instance of **CircularBuffer** was created, and **currentBufferLength()** which returns the
number of entries into the array. If the system has started to roll over then **currentBufferLength()**
will be the same as **MaxBufferSize()**.
Obviously before any data has been added **currentBufferLength()** will be zero.
SaveCBInfo(), RestoreCBInfo()
Should you wish to power down your system, but not lose your Circular Buffer database, then you can use the function **SaveCBInfo()**. First start by saving your Array Data away then get the **CircularBuffer**
internal data with `CircularBuffer::infoType cbData = SaveCBData();` then save that cbData away.
To recover your Circular Buffer restore your array data and then read in your cbData and then
use the function **RestoreCBInfo( cbData )** to put the data back. This function attempts to check
the validity of the data and return bool if the data looks legal. If false is returned the data is
not valid and the **CircularBuffer** internal variables will NOT have been updated.
Code:
/*
Name: aaTestCircularBuffer.ino
Created: 01/05/2023 16:01:48
Author: Robert E Bridges (C) 4 May 2023
*/
#include "Arduino.h"
#include <CircularBuffer.h>
#include <EEPROM.h>
#define CircularBufferArrayEEPROMAddr 0
CircularBuffer::infoType data;
uint32_t currentBufferSize;
#define arrayBufferSize 20
char buffer[arrayBufferSize];
CircularBuffer cBuf(arrayBufferSize);
void setup()
{
Serial.begin(9600);
while (!Serial && millis() < 5000);
Serial.println(F("Putting some data uint32_to Circular Buffer, but NOT filling it."));
Serial.println(F("Adding to buffer with A to K inclusive"));
for (char i = 'A'; i < 'L'; i++) {
buffer[cBuf.AddDataToBuffer()] = i;
}
Serial.println(F("Reading from circular buffer - from Head to Tail (LIFO)"));
Serial.print( buffer[ cBuf.ReadFromHead() ] );
for (uint32_t i = 1; i < cBuf.currentBufferLength(); i++) { // wouldn't normally use "i < cBuf.BufferLength();" just used to demonstrate use
Serial.print( buffer[ cBuf.ReadNext() ]); // better to use next example. The limit is not repeatedly evaluated.
}
Serial.println();
Serial.println(F("Reading from circular buffer in opposite direction - from Tail to Head (FIFO)"));
Serial.print( buffer[ cBuf.ReadFromTail() ] );
currentBufferSize = cBuf.currentBufferLength();
for (uint32_t i = 1; i < currentBufferSize; i++) {
Serial.print( buffer[ cBuf.ReadNext() ] );
}
Serial.println();
Serial.println(F("Adding more data to just fill the buffer."));
Serial.println(F("Adding extra to buffer with L to U inclusive"));
for (char i = 'L'; i < 'U'; i++) {
buffer[cBuf.AddDataToBuffer()] = i;
}
Serial.print( buffer[ cBuf.ReadFromHead() ] );
currentBufferSize = cBuf.currentBufferLength();
for (uint32_t i = 1; i < currentBufferSize; i++) {
Serial.print( buffer[ cBuf.ReadNext() ] );
}
Serial.println();
Serial.print( buffer[ cBuf.ReadFromTail() ] );
for (uint32_t i = 1; i < cBuf.currentBufferLength(); i++) {
Serial.print( buffer[ cBuf.ReadNext() ] );
}
Serial.println();
Serial.println(F("Adding extra to go uint32_to roll over."));
Serial.println(F("Adding extra to buffer with U to Z inclusive" ));
for (char i = 'U'; i < '['; i++) {
buffer[cBuf.AddDataToBuffer()] = i;
}
Serial.print( buffer[ cBuf.ReadFromHead() ] );
currentBufferSize = cBuf.currentBufferLength();
for (uint32_t i = 1; i < currentBufferSize; i++) {
Serial.print( buffer[ cBuf.ReadNext() ] );
}
Serial.println();
Serial.print( buffer[ cBuf.ReadFromTail() ] );
for (uint32_t i = 1; i < currentBufferSize; i++) {
Serial.println( buffer[cBuf.ReadNext() ] );
}
Serial.println();
Serial.println("Save away Circular Buffer to EEPROM");
data=cBuf.SaveCBInfo();
EEPROM.put(CircularBufferArrayEEPROMAddr, buffer);
EEPROM.put(CircularBufferArrayEEPROMAddr + sizeof(buffer), data);
Serial.println("Get Back Circular Buffer from EEPROM");
EEPROM.get(CircularBufferArrayEEPROMAddr, buffer);
EEPROM.get(CircularBufferArrayEEPROMAddr + sizeof(buffer), data);
cBuf.RestoreCBInfo(data);
}
void loop()
{
}
Last edited: