Multi purpose buffer module.
Multipurpose ringbuffer
Since there weren't any ringbuffers available on the internet optimized for 32-Bit ARM operation without unix-calls and dynamic memory... I created one.
This module is a fixed ringbuffer, it does not allocate any memory, it can work as FIFO or LIFO or any other exotic mode depending on your imagination. With a fixed 32Bit element size it is optimized for 32 bit arm processors. Any smaller value will have overhead, any larger value will require a double entry. (not recommended)
I hope you can use it.
Information
This is not a C++ class, it is a C Module. It does work object oriented, however you cannot work on the object, you work with the object.
Import programxIFO_example
Small example for xIFO
Revision 0:a04dc0c57d20, committed 2013-10-28
- Comitter:
- jeroen3
- Date:
- Mon Oct 28 18:39:36 2013 +0000
- Child:
- 1:5f59aa9b86ed
- Commit message:
- Initial
Changed in this revision
xIFO.c | Show annotated file Show diff for this revision Revisions of this file |
xIFO.h | Show annotated file Show diff for this revision Revisions of this file |
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xIFO.c Mon Oct 28 18:39:36 2013 +0000 @@ -0,0 +1,287 @@ + + /** + * @file xifo.c + * @brief xifo circular buffer + * @details xifo supplies object oriented circular buffer with 32 bit size elements. \n + * To use either as FIFO (First In First Out) or as FILO (First In Last Out) + * + * @Author Jeroen Lodder + * @Date April 2013 + * @version 2 + * + * @{ + */ +#include "xifo.h" + +/** + * @brief Initialise buffer object structure. + * + * @note Does not clear memory pool. + * + * @param[in] c Pointer to @p xifo_t object used for configuration. + * @param[in] s Number of elements buffer can hold (size). + * @param[in] sp Start of pre-allocated memory pool. + */ +void xifo_init(xifo_t *c, uint32_t s, uint32_t *sp){ + c->startpool = sp; + c->endpool = &sp[s-1]; + c->size = s; + c->full = 0; + c->elementcount = 0; + c->read = sp; + c->write = sp; +} + +/** + * @brief Clear buffer contents + * + * @note Must be used on initialised buffer object. + * + * @param[in] c Pointer to @p xifo_t object. + */ +void xifo_clear(xifo_t *c){ + c->ptemp = c->startpool; + while(c->ptemp <= c->endpool){ + *c->ptemp++ = 0; + } +} + +/** + * @brief Read from buffer (lr) Least Recent oriented (fifo) + * + * @note Buffer state will be preserved + * + * @warning Consider this opertaion as atomic! + * + * @details Read n elements from the oldest element to the most recent. + * As for index[0] the least recently added element is returned. + * And for index[elementcount] the most recent element is returned. + * This makes it possible to peek in fifo. + * + * @param[in] c Pointer to @p xifo_t used for configuration. + * @param[in] index Index relative from least recent + * + * @return Contents of element or 0 if failed (element can hold 0) + */ +uint32_t xifo_read_lr(xifo_t *c, uint32_t index){ + /* Verify there is valid data to read */ + if(index+1 > c->elementcount){ + return 0; /* Nothing to read there */ + } + /* Calculate index of oldest element */ + index = (c->elementcount-1) - index; + /* Set pointer */ + c->ptemp = (c->read) - index; + if(c->ptemp < c->startpool){ + /* We exceeded pool boundaries */ + /* Calculate overshoot (startpool - indexptr) and subtract from end */ + /* Since one element of overshoot results in end - 1 you would miss the last value */ + c->ptemp = (c->endpool+1) - (c->startpool - c->ptemp); + } + /* Read most recent */ + return *c->ptemp; +} + +/** + * @brief Read from buffer (mr) Most Recent oriented (filo) + * + * @note Buffer state will be preserved + * + * @warning Consider this opertaion as atomic! + * + * @details Read n elements back in time. + * As for index[0] the most recently added element is returned. + * And for index[elementcount] the oldest element is returned. + * This makes it possible to keep history. For DSP application. + * + * @param[in] c Pointer to @p xifo_t used for configuration. + * @param[in] index Index relative from most recent + * + * @return Contents of element or 0 if failed (element can hold 0) + */ +uint32_t xifo_read_mr(xifo_t *c, uint32_t index){ + /* Verify there is valid data to read */ + if(index+1 > c->elementcount){ + return 0; /* Nothing to read there */ + } + /* Set pointer */ + c->ptemp = (c->read) - index; + /* Validate pointer */ + if(c->ptemp < c->startpool){ + /* We exceeded pool boundaries */ + /* Calculate overshoot (startpool - indexptr) and subtract from end */ + /* Since one element of overshoot results in end - 1 you would miss the last value */ + c->ptemp = (c->endpool+1) - (c->startpool - c->ptemp); + } + /* Read most recent */ + return *c->ptemp; +} + +/** + * @brief Pop (mr) most recent from buffer (filo) + * + * @note Buffer state will be altered + * + * @warning Consider this opertaion as atomic! + * + * @details Read and remove the most recently added from the buffer. + * Using this results in a stack type of buffer. + * + * @param[in] c Pointer to @p xifo_t used for configuration. + * + * @return Contents of element or 0 if failed (element can hold 0) + */ +uint32_t xifo_pop_mr(xifo_t *c){ + /* Verify there is valid data read */ + if(c->elementcount == 0){ + return 0; /* Nothing to read there */ + } + /* Read */ + c->temp = *c->read; + /* Empty */ + *c->read = 0; + /* Most recent element read, return write pointer */ + c->write = c->read; + /* Decrement read pointer */ + c->read--; + /* Validate pointer */ + if( c->read < c->startpool ){ + /* We exceeded pool boundaries */ + c->read = c->endpool; + } + /* Reduce elementcount */ + c->elementcount--; + if(c->elementcount < c->size) + c->full = 0; + return c->temp; +} + +/** + * @brief Pop (lr) least recent from buffer (fifo) + * + * @note Buffer state will be altered + * + * @warning Consider this opertaion as atomic! + * + * @details Read and remove the least recently added from the buffer. + * Using this results in a fifo type of buffer. + * + * @param[in] c Pointer to @p xifo_t used for configuration. + * + * @return Contents of element or 0 if failed (element can hold 0) + */ +uint32_t xifo_pop_lr(xifo_t *c){ + /* Verify there is valid data read */ + if(c->elementcount == 0){ + return 0; /* Nothing to read there */ + } + /* Derive least recent buffer element */ + c->ptemp = c->read+1 - c->elementcount; + /* Validate pointer */ + if(c->ptemp < c->startpool){ + /* We exceeded pool boundaries */ + /* Calculate overshoot (startpool - indexptr) and subtract from end */ + /* Since one element of overshoot results in end - 1 you would miss the last value */ + c->ptemp = (c->endpool+1) - (c->startpool - c->ptemp); + } + /* Read oldest buffer element */ + { /* block with temporary variable to prevent stack use */ + register uint32_t element; + /* Read to temp register */ + element = *c->ptemp; + /* Empty */ + *c->ptemp = 0; + /* Clear temp register */ + c->temp = element; + } + /* Reduce elementcount */ + c->elementcount--; + /* Check full flag */ + if(c->elementcount < c->size) + c->full = 0; + return c->temp; +} + +/** + * @brief Write to buffer + * + * @note Readpointer is automatically set to the last added element. + * + * @warning Consider this opertaion as atomic! + * + * @details Adds a value to the buffer. + * Automatically overwrites oldest elements when full. + * + * @param[in] c Pointer to @p xifo_t used for configuration. + * @param[in] data Data to add to buffer + * + * @return Number of free buffer elements + */ +uint32_t xifo_write(xifo_t *c, uint32_t data){ + /* Write data */ + *c->write = data; + /* Update read pointer to most recent element */ + c->read = c->write; + /* Write pointer increment */ + c->write += 1; + /* Validate pointer */ + if( c->write > c->endpool){ + /* We exceeded pool boundaries */ + c->write = c->startpool; + } + /* Update elementcount */ + c->elementcount++; + /* Verify full */ + if( c->elementcount >= c->size ){ + c->full = 1; + c->elementcount = c->size; + } + /* return free elements count */ + return c->size - c->elementcount; +} + +/** + * @brief Get buffer size + * + * @param[in] c Pointer to @p xifo_t used for configuration. + * + * @return Size of memory pool in elements + */ +uint32_t xifo_get_size(xifo_t *c){ + return c->size; +} + +/** + * @brief Get number of used elements + * + * @param[in] c Pointer to @p xifo_t used for configuration. + * + * @return Number of used buffer elements + */ +uint32_t xifo_get_used(xifo_t *c){ + return c->elementcount; +} + +/** +* @brief Get number of free elements +* +* @param[in] c Pointer to @p xifo_t used for configuration. +* +* @return Number of free elements +*/ +uint32_t xifo_get_free(xifo_t *c){ + return c->size - c->elementcount; +} + +/** + * @brief Get full flag + * + * @param[in] c Pointer to @p xifo_t used for configuration. + * + * @return 1 if full + */ +uint32_t xifo_get_full(xifo_t *c){ + return c->full; +} + +/** @} */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xIFO.h Mon Oct 28 18:39:36 2013 +0000 @@ -0,0 +1,92 @@ + + /** + * @file xifo.h + * @brief xifo circular buffer + * @details xifo supplies object oriented circular buffer with 32 bit size elements. \n + * To use either as FIFO (First In First Out) or as FILO (First In Last Out) + * + * @author Jeroen Lodder + * @date April 2013 + * @version 2 + * + * @{ + */ + + /** + * Code has been tested on Cortex M0 (LPC1114) + * Performance table, number of core clocks + * Measured with a timer before and after + * r1 = timer->TC + * test_function + * r2 = timer->TC + * + * Function Speed Worst Case + * + * write 69 71 + * read_mr 59 59 + * read_lr 63 70 + * pop_mr 76 78 + * pop_lr 45 45 + * + */ + +#ifndef _xifo_H_ +#define _xifo_H_ + +#include <inttypes.h> + +#if defined(__arm__) || defined(__DOXYGEN__) +#pragma anon_unions /**< Allow unnamed unions */ +#endif + +/** + * @brief Circular Buffer object. + * @details This struct holds the object of a circular buffer + */ +typedef struct { +/* Pointers: */ + uint32_t *startpool; /**< @brief First element in pool */ + uint32_t *endpool; /**< @brief Last element in pool */ + uint32_t *read; /**< @brief Read pointer */ + uint32_t *write; /**< @brief Write pointer */ +/* Variables: */ + uint32_t full; /**< @brief Flag indicating buffer is full */ + uint32_t elementcount;/**< @brief Number of elements used */ + uint32_t size; /**< @brief Size of buffer */ +/* Locally used in functions to prevent stack use: */ + /**< @brief union to prevent lvalue typecasting */ + union { + uint32_t temp; /**< @brief temp variable and padding for even sized block */ + uint32_t *ptemp; /**< @brief temp variable and padding for even sized block */ + }; +}xifo_t; + +/** + * @brief Circular Buffer memory pool type. + */ +typedef unsigned int xifo_pool_t; + +#ifdef __cplusplus +extern "C" { +#endif +/* xifo Common */ +void xifo_init(xifo_t *c, uint32_t size, uint32_t *startpool); +void xifo_clear(xifo_t *c); +uint32_t xifo_write(xifo_t *c, uint32_t data); +/* FIFO use */ +uint32_t xifo_read_lr(xifo_t *c, uint32_t index); +uint32_t xifo_pop_lr(xifo_t *c); +/* LIFO use */ +uint32_t xifo_read_mr(xifo_t *c, uint32_t index); +uint32_t xifo_pop_mr(xifo_t *c); +/* Extractors */ +uint32_t xifo_get_size(xifo_t *c); +uint32_t xifo_get_used(xifo_t *c); +uint32_t xifo_get_full(xifo_t *c); +uint32_t xifo_get_free(xifo_t *c); +#ifdef __cplusplus +} +#endif +#endif //_xifo_H_ + +/** @} */