Appiko
|
This file contains global definitions for circular buffer manipulation. More...
Go to the source code of this file.
Macros | |
#define | CBUF_H |
#define | CBUF_Init(cbuf) cbuf.m_getIdx = cbuf.m_putIdx = 0 |
#define | CBUF_Len(cbuf) ((typeof( cbuf.m_putIdx ))(( cbuf.m_putIdx ) - ( cbuf.m_getIdx ))) |
#define | CBUF_Push(cbuf, elem) (cbuf.m_entry)[ cbuf.m_putIdx++ & (( cbuf##_SIZE ) - 1 )] = (elem) |
#define | CBUF_Pop(cbuf) (cbuf.m_entry)[ cbuf.m_getIdx++ & (( cbuf##_SIZE ) - 1 )] |
#define | CBUF_Get(cbuf, idx) (cbuf.m_entry)[( cbuf.m_getIdx + idx ) & (( cbuf##_SIZE ) - 1 )] |
#define | CBUF_GetEnd(cbuf, idx) (cbuf.m_entry)[( cbuf.m_putIdx - idx - 1 ) & (( cbuf##_SIZE ) - 1 )] |
#define | CBUF_IsEmpty(cbuf) ( CBUF_Len( cbuf ) == 0 ) |
#define | CBUF_IsFull(cbuf) ( CBUF_Len( cbuf ) == ( cbuf##_SIZE )) |
#define | CBUF_Error(cbuf) ( CBUF_Len( cbuf ) > cbuf##_SIZE ) |
#define | CBUF_GetPtr(cbuf, idx) ((typeof( &cbuf.m_entry[0]))( cbuf.m_entry + (( cbuf.m_getIdx + idx ) & (( cbuf##_SIZE ) - 1 )))) |
#define | CBUF_Remove(cbuf, idx) ({cbuf.m_getIdx += ( idx );}) |
These macros implement a circular buffer which employs get and put pointers, in such a way that mutual exclusion is not required (assumes one reader & one writer).
It requires that the circular buffer size be a power of two, and the size of the buffer needs to smaller than the index. So an 8 bit index supports a circular buffer upto ( 1 << 7 ) = 128 entries, and a 16 bit index supports a circular buffer upto ( 1 << 15 ) = 32768 entries.
The basis for these routines came from an article in Jack Ganssle's Embedded Muse: http://www.ganssle.com/tem/tem110.pdf
In order to offer the most amount of flexibility for embedded environments you need to define a macro for the size.
First, you need to name your circular buffer. For this example, we'll call it myQ.
The size macro that needs to be defined will be the name of the circular buffer followed by _SIZE. The size must be a power of two and it needs to fit in the get/put indicies. i.e. if you use an 8 bit index, then the maximum supported size would be 128.
The structure which defines the circular buffer needs to have 3 members m_getIdx, m_putIdx, and m_entry.
m_getIdx and m_putIdx need to be unsigned integers of the same size.
m_entry needs to be an array of xxx_SIZE entries, or a pointer to an array of xxx_SIZE entries. The type of each entry is entirely up to the caller.
#define myQ_SIZE 64
volatile struct { uint8_t m_getIdx; uint8_t m_putIdx; uint8_t m_entry[ myQ_SIZE ];
} myQ;
You could then use
CBUF_Push( myQ, 'x' );
to add a character to the circular buffer, or
ch = CBUF_Pop( myQ );
to retrieve an element from the buffer.
If you happen to prefer to use C++ instead, there is a templatized version which requires no macros. You just declare 3 template parameters:
- The type that should be used for the index - The size of the circular buffer - The type that should be used for the entry
For example:
CBUF< uint8_t, 64, char > myQ;
Definition in file CBUF.h.
#define CBUF_Error | ( | cbuf | ) | ( CBUF_Len( cbuf ) > cbuf##_SIZE ) |
#define CBUF_Get | ( | cbuf, | |
idx | |||
) | (cbuf.m_entry)[( cbuf.m_getIdx + idx ) & (( cbuf##_SIZE ) - 1 )] |
#define CBUF_GetEnd | ( | cbuf, | |
idx | |||
) | (cbuf.m_entry)[( cbuf.m_putIdx - idx - 1 ) & (( cbuf##_SIZE ) - 1 )] |
#define CBUF_GetPtr | ( | cbuf, | |
idx | |||
) | ((typeof( &cbuf.m_entry[0]))( cbuf.m_entry + (( cbuf.m_getIdx + idx ) & (( cbuf##_SIZE ) - 1 )))) |
#define CBUF_Init | ( | cbuf | ) | cbuf.m_getIdx = cbuf.m_putIdx = 0 |
#define CBUF_IsEmpty | ( | cbuf | ) | ( CBUF_Len( cbuf ) == 0 ) |
#define CBUF_IsFull | ( | cbuf | ) | ( CBUF_Len( cbuf ) == ( cbuf##_SIZE )) |
#define CBUF_Len | ( | cbuf | ) | ((typeof( cbuf.m_putIdx ))(( cbuf.m_putIdx ) - ( cbuf.m_getIdx ))) |
#define CBUF_Pop | ( | cbuf | ) | (cbuf.m_entry)[ cbuf.m_getIdx++ & (( cbuf##_SIZE ) - 1 )] |
#define CBUF_Push | ( | cbuf, | |
elem | |||
) | (cbuf.m_entry)[ cbuf.m_putIdx++ & (( cbuf##_SIZE ) - 1 )] = (elem) |