#define FREERTOS_RINGBUF_H
#ifndef INC_FREERTOS_H
- #error "include FreeRTOS.h" must appear in source files before "include ringbuf.h"
+ #error "include FreeRTOS.h" must appear in source files before "include ringbuf.h"
#endif
#ifdef __cplusplus
typedef void * RingbufHandle_t;
typedef enum {
- /**
- * No-split buffers will only store an item in contiguous memory and will
- * never split an item. Each item requires an 8 byte overhead for a header
- * and will always internally occupy a 32-bit aligned size of space.
- */
- RINGBUF_TYPE_NOSPLIT = 0,
- /**
- * Allow-split buffers will split an item into two parts if necessary in
- * order to store it. Each item requires an 8 byte overhead for a header,
- * splitting incurs an extra header. Each item will always internally occupy
- * a 32-bit aligned size of space.
- */
- RINGBUF_TYPE_ALLOWSPLIT,
- /**
- * Byte buffers store data as a sequence of bytes and do not maintain separate
- * items, therefore byte buffers have no overhead. All data is stored as a
- * sequence of byte and any number of bytes can be sent or retrieved each
- * time.
- */
- RINGBUF_TYPE_BYTEBUF
-} ringbuf_type_t;
+ /**
+ * No-split buffers will only store an item in contiguous memory and will
+ * never split an item. Each item requires an 8 byte overhead for a header
+ * and will always internally occupy a 32-bit aligned size of space.
+ */
+ RINGBUF_TYPE_NOSPLIT = 0,
+ /**
+ * Allow-split buffers will split an item into two parts if necessary in
+ * order to store it. Each item requires an 8 byte overhead for a header,
+ * splitting incurs an extra header. Each item will always internally occupy
+ * a 32-bit aligned size of space.
+ */
+ RINGBUF_TYPE_ALLOWSPLIT,
+ /**
+ * Byte buffers store data as a sequence of bytes and do not maintain separate
+ * items, therefore byte buffers have no overhead. All data is stored as a
+ * sequence of byte and any number of bytes can be sent or retrieved each
+ * time.
+ */
+ RINGBUF_TYPE_BYTEBUF,
+ RINGBUF_TYPE_MAX,
+} RingbufferType_t;
+
+/**
+ * @brief Struct that is equivalent in size to the ring buffer's data structure
+ *
+ * The contents of this struct are not meant to be used directly. This
+ * structure is meant to be used when creating a statically allocated ring
+ * buffer where this struct is of the exact size required to store a ring
+ * buffer's control data structure.
+ *
+ * @note The CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION option must be enabled for
+ * this structure to be available.
+ */
+#if ( configSUPPORT_STATIC_ALLOCATION == 1)
+typedef struct xSTATIC_RINGBUFFER {
+ /** @cond */ //Doxygen command to hide this structure from API Reference
+ size_t xDummy1[2];
+ UBaseType_t uxDummy2;
+ BaseType_t xDummy3;
+ void *pvDummy4[10];
+ StaticSemaphore_t xDummy5[2];
+ portMUX_TYPE muxDummy;
+ /** @endcond */
+} StaticRingbuffer_t;
+#endif
/**
* @brief Create a ring buffer
*
* @return A handle to the created ring buffer, or NULL in case of error.
*/
-RingbufHandle_t xRingbufferCreate(size_t xBufferSize, ringbuf_type_t xBufferType);
+RingbufHandle_t xRingbufferCreate(size_t xBufferSize, RingbufferType_t xBufferType);
/**
* @brief Create a ring buffer of type RINGBUF_TYPE_NOSPLIT for a fixed item_size
*/
RingbufHandle_t xRingbufferCreateNoSplit(size_t xItemSize, size_t xItemNum);
+
+/**
+ * @brief Create a ring buffer but manually provide the required memory
+ *
+ * @param[in] xBufferSize Size of the buffer in bytes.
+ * @param[in] xBufferType Type of ring buffer, see documentation
+ * @param[in] pucRingbufferStorage Pointer to the ring buffer's storage area.
+ * Storage area must of the same size as specified by xBufferSize
+ * @param[in] pxStaticRingbuffer Pointed to a struct of type StaticRingbuffer_t
+ * which will be used to hold the ring buffer's data structure
+ *
+ * @note The CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION option must be enabled
+ * for this to be available
+ *
+ * @note xBufferSize of no-split/allow-split buffers MUST be 32-bit aligned.
+ *
+ * @return A handle to the created ring buffer
+ */
+#if ( configSUPPORT_STATIC_ALLOCATION == 1)
+RingbufHandle_t xRingbufferCreateStatic(size_t xBufferSize,
+ RingbufferType_t xBufferType,
+ uint8_t *pucRingbufferStorage,
+ StaticRingbuffer_t *pxStaticRingbuffer);
+#endif
+
/**
* @brief Insert an item into the ring buffer
*
* Attempt to insert an item into the ring buffer. This function will block until
- * enough free space is available or until it timesout.
+ * enough free space is available or until it times out.
*
* @param[in] xRingbuffer Ring buffer to insert the item into
* @param[in] pvItem Pointer to data to insert. NULL is allowed if xItemSize is 0.
* - pdTRUE if succeeded
* - pdFALSE on time-out or when the data is larger than the maximum permissible size of the buffer
*/
-BaseType_t xRingbufferSend(RingbufHandle_t xRingbuffer, const void *pvItem, size_t xItemSize, TickType_t xTicksToWait);
+BaseType_t xRingbufferSend(RingbufHandle_t xRingbuffer,
+ const void *pvItem,
+ size_t xItemSize,
+ TickType_t xTicksToWait);
/**
* @brief Insert an item into the ring buffer in an ISR
* - pdTRUE if succeeded
* - pdFALSE when the ring buffer does not have space.
*/
-BaseType_t xRingbufferSendFromISR(RingbufHandle_t xRingbuffer, const void *pvItem, size_t xItemSize, BaseType_t *pxHigherPriorityTaskWoken);
+BaseType_t xRingbufferSendFromISR(RingbufHandle_t xRingbuffer,
+ const void *pvItem,
+ size_t xItemSize,
+ BaseType_t *pxHigherPriorityTaskWoken);
/**
* @brief Retrieve an item from the ring buffer
*
* Attempt to retrieve an item from the ring buffer. This function will block
- * until an item is available or until it timesout.
+ * until an item is available or until it times out.
*
* @param[in] xRingbuffer Ring buffer to retrieve the item from
* @param[out] pxItemSize Pointer to a variable to which the size of the retrieved item will be written.
* Attempt to retrieve a split item from an allow-split ring buffer. If the item
* is not split, only a single item is retried. If the item is split, both parts
* will be retrieved. This function will block until an item is available or
- * until it timesout.
+ * until it times out.
*
* @param[in] xRingbuffer Ring buffer to retrieve the item from
* @param[out] ppvHeadItem Double pointer to first part (set to NULL if no items were retrieved)
* - pdTRUE if an item (split or unsplit) was retrieved
* - pdFALSE when no item was retrieved
*/
-BaseType_t xRingbufferReceiveSplit(RingbufHandle_t xRingbuffer, void **ppvHeadItem, void **ppvTailItem, size_t *pxHeadItemSize, size_t *pxTailItemSize, TickType_t xTicksToWait);
+BaseType_t xRingbufferReceiveSplit(RingbufHandle_t xRingbuffer,
+ void **ppvHeadItem,
+ void **ppvTailItem,
+ size_t *pxHeadItemSize,
+ size_t *pxTailItemSize,
+ TickType_t xTicksToWait);
/**
* @brief Retrieve a split item from an allow-split ring buffer in an ISR
* - pdTRUE if an item (split or unsplit) was retrieved
* - pdFALSE when no item was retrieved
*/
-BaseType_t xRingbufferReceiveSplitFromISR(RingbufHandle_t xRingbuffer, void **ppvHeadItem, void **ppvTailItem, size_t *pxHeadItemSize, size_t *pxTailItemSize);
+BaseType_t xRingbufferReceiveSplitFromISR(RingbufHandle_t xRingbuffer,
+ void **ppvHeadItem,
+ void **ppvTailItem,
+ size_t *pxHeadItemSize,
+ size_t *pxTailItemSize);
/**
* @brief Retrieve bytes from a byte buffer, specifying the maximum amount of bytes to retrieve
*
* Attempt to retrieve data from a byte buffer whilst specifying a maximum number
* of bytes to retrieve. This function will block until there is data available
- * for retrieval or until it timesout.
+ * for retrieval or until it times out.
*
* @param[in] xRingbuffer Ring buffer to retrieve the item from
* @param[out] pxItemSize Pointer to a variable to which the size of the retrieved item will be written.
* the length of the item.
* - NULL on timeout, *pxItemSize is untouched in that case.
*/
-void *xRingbufferReceiveUpTo(RingbufHandle_t xRingbuffer, size_t *pxItemSize, TickType_t xTicksToWait, size_t xMaxSize);
+void *xRingbufferReceiveUpTo(RingbufHandle_t xRingbuffer,
+ size_t *pxItemSize,
+ TickType_t xTicksToWait,
+ size_t xMaxSize);
/**
* @brief Retrieve bytes from a byte buffer, specifying the maximum amount of
* @brief Delete a ring buffer
*
* @param[in] xRingbuffer Ring buffer to delete
+ *
+ * @note This function will not deallocate any memory if the ring buffer was
+ * created using xRingbufferCreateStatic(). Deallocation must be done
+ * manually be the user.
*/
void vRingbufferDelete(RingbufHandle_t xRingbuffer);
*
* @param[in] xRingbuffer Ring buffer to query
*
+ * @note The max item size for a no-split buffer is limited to
+ * ((buffer_size/2)-header_size). This limit is imposed so that an item
+ * of max item size can always be sent to the an empty no-split buffer
+ * regardless of the internal positions of the buffer's read/write/free
+ * pointers.
+ *
* @return Maximum size, in bytes, of an item that can be placed in a ring buffer.
*/
size_t xRingbufferGetMaxItemSize(RingbufHandle_t xRingbuffer);
* the same ring buffer, it is the application's responsibility to
* ensure atomic access to this API and the subsequent Send
*
+ * @note An empty no-split buffer has a max current free size for an item
+ * that is limited to ((buffer_size/2)-header_size). See API reference
+ * for xRingbufferGetMaxItemSize().
+ *
* @param[in] xRingbuffer Ring buffer to query
*
* @return Current free size, in bytes, available for an entry
* @param[out] uxWrite Pointer use to store write pointer position
* @param[out] uxItemsWaiting Pointer use to store number of items (bytes for byte buffer) waiting to be retrieved
*/
-void vRingbufferGetInfo(RingbufHandle_t xRingbuffer, UBaseType_t *uxFree, UBaseType_t *uxRead, UBaseType_t *uxWrite, UBaseType_t *uxItemsWaiting);
+void vRingbufferGetInfo(RingbufHandle_t xRingbuffer,
+ UBaseType_t *uxFree,
+ UBaseType_t *uxRead,
+ UBaseType_t *uxWrite,
+ UBaseType_t *uxItemsWaiting);
/**
* @brief Debugging function to print the internal pointers in the ring buffer
*/
void xRingbufferPrintInfo(RingbufHandle_t xRingbuffer);
-/* -------------------------------- Deprecated Functions --------------------------- */
+/* ------------------------------- Deprecated ------------------------------- */
-/** @cond */ //Doxygen command to hide deprecated function from API Reference
-/*
- * Deprecated as function is not thread safe and does not check if an item is
- * actually available for retrieval. Use xRingbufferReceiveSplit() instead for
- * thread safe method of retrieve a split item.
- */
-bool xRingbufferIsNextItemWrapped(RingbufHandle_t xRingbuffer) __attribute__((deprecated));
-
-/*
- * Deprecated as queue sets are not meant to be used for writing to buffers. Adding
- * the ring buffer write semaphore to a queue set will break queue set usage rules,
- * as every read of a semaphore must be preceded by a call to xQueueSelectFromSet().
- * QueueSetWrite no longer supported.
- */
-BaseType_t xRingbufferAddToQueueSetWrite(RingbufHandle_t xRingbuffer, QueueSetHandle_t xQueueSet) __attribute__((deprecated));
-
-/*
- * Deprecated as queue sets are not meant to be used for writing to buffers.
- * QueueSetWrite no longer supported.
- */
-BaseType_t xRingbufferRemoveFromQueueSetWrite(RingbufHandle_t xRingbuffer, QueueSetHandle_t xQueueSet) __attribute__((deprecated));
-/** @endcond */
+typedef RingbufferType_t ringbuf_type_t __attribute__((deprecated));
#ifdef __cplusplus
}
//32-bit alignment macros
#define rbALIGN_SIZE( xSize ) ( ( xSize + portBYTE_ALIGNMENT_MASK ) & ~portBYTE_ALIGNMENT_MASK )
-#define rbCHECK_ALIGNED( pvPtr ) ( ( ( UBaseType_t ) pvPtr & portBYTE_ALIGNMENT_MASK ) == 0 )
+#define rbCHECK_ALIGNED( pvPtr ) ( ( ( UBaseType_t ) ( pvPtr ) & portBYTE_ALIGNMENT_MASK ) == 0 )
//Ring buffer flags
#define rbALLOW_SPLIT_FLAG ( ( UBaseType_t ) 1 ) //The ring buffer allows items to be split
#define rbBYTE_BUFFER_FLAG ( ( UBaseType_t ) 2 ) //The ring buffer is a byte buffer
#define rbBUFFER_FULL_FLAG ( ( UBaseType_t ) 4 ) //The ring buffer is currently full (write pointer == free pointer)
+#define rbBUFFER_STATIC_FLAG ( ( UBaseType_t ) 8 ) //The ring buffer is statically allocated
//Item flags
#define rbITEM_FREE_FLAG ( ( UBaseType_t ) 1 ) //Item has been retrieved and returned by application, free to overwrite
#define rbITEM_DUMMY_DATA_FLAG ( ( UBaseType_t ) 2 ) //Data from here to end of the ring buffer is dummy data. Restart reading at start of head of the buffer
#define rbITEM_SPLIT_FLAG ( ( UBaseType_t ) 4 ) //Valid for RINGBUF_TYPE_ALLOWSPLIT, indicating that rest of the data is wrapped around
+//Static allocation related
+#if ( configSUPPORT_STATIC_ALLOCATION == 1 )
+#define rbGET_TX_SEM_HANDLE( pxRingbuffer ) ( (SemaphoreHandle_t) &(pxRingbuffer->xTransSemStatic) )
+#define rbGET_RX_SEM_HANDLE( pxRingbuffer ) ( (SemaphoreHandle_t) &(pxRingbuffer->xRecvSemStatic) )
+#else
+#define rbGET_TX_SEM_HANDLE( pxRingbuffer ) ( pxRingbuffer->xTransSemHandle )
+#define rbGET_RX_SEM_HANDLE( pxRingbuffer ) ( pxRingbuffer->xRecvSemHandle )
+#endif
+
typedef struct {
//This size of this structure must be 32-bit aligned
size_t xItemLen;
} ItemHeader_t;
#define rbHEADER_SIZE sizeof(ItemHeader_t)
-typedef struct Ringbuffer_t Ringbuffer_t;
+typedef struct RingbufferDefinition Ringbuffer_t;
typedef BaseType_t (*CheckItemFitsFunction_t)(Ringbuffer_t *pxRingbuffer, size_t xItemSize);
typedef void (*CopyItemFunction_t)(Ringbuffer_t *pxRingbuffer, const uint8_t *pcItem, size_t xItemSize);
typedef BaseType_t (*CheckItemAvailFunction_t) (Ringbuffer_t *pxRingbuffer);
typedef void (*ReturnItemFunction_t)(Ringbuffer_t *pxRingbuffer, uint8_t *pvItem);
typedef size_t (*GetCurMaxSizeFunction_t)(Ringbuffer_t *pxRingbuffer);
-struct Ringbuffer_t {
+typedef struct RingbufferDefinition {
size_t xSize; //Size of the data storage
- UBaseType_t uxRingbufferFlags; //Flags to indicate the type and status of ring buffer
size_t xMaxItemSize; //Maximum item size
+ UBaseType_t uxRingbufferFlags; //Flags to indicate the type and status of ring buffer
CheckItemFitsFunction_t xCheckItemFits; //Function to check if item can currently fit in ring buffer
CopyItemFunction_t vCopyItem; //Function to copy item to ring buffer
uint8_t *pucTail; //Pointer to the end of the ring buffer storage area
BaseType_t xItemsWaiting; //Number of items/bytes(for byte buffers) currently in ring buffer that have not yet been read
- SemaphoreHandle_t xFreeSpaceSemaphore; //Binary semaphore, wakes up writing threads when more free space becomes available or when another thread times out attempting to write
- SemaphoreHandle_t xItemsBufferedSemaphore; //Binary semaphore, indicates there are new packets in the circular buffer. See remark.
+ /*
+ * TransSem: Binary semaphore used to indicate to a blocked transmitting tasks
+ * that more free space has become available or that the block has
+ * timed out.
+ *
+ * RecvSem: Binary semaphore used to indicate to a blocked receiving task that
+ * new data/item has been written to the ring buffer.
+ *
+ * Note - When static allocation is enabled, the two semaphores are always
+ * statically stored in the ring buffer's control structure
+ * regardless of whether the ring buffer is allocated dynamically or
+ * statically. When static allocation is disabled, the two semaphores
+ * are allocated dynamically and their handles stored instead, thus
+ * making the ring buffer's control structure slightly smaller when
+ * static allocation is disabled.
+ */
+#if ( configSUPPORT_STATIC_ALLOCATION == 1 )
+ StaticSemaphore_t xTransSemStatic;
+ StaticSemaphore_t xRecvSemStatic;
+#else
+ SemaphoreHandle_t xTransSemHandle;
+ SemaphoreHandle_t xRecvSemHandle;
+#endif
portMUX_TYPE mux; //Spinlock required for SMP
-};
+} Ringbuffer_t;
+#if ( configSUPPORT_STATIC_ALLOCATION == 1 )
+#if __GNUC_PREREQ(4, 6)
+_Static_assert(sizeof(StaticRingbuffer_t) == sizeof(Ringbuffer_t), "StaticRingbuffer_t != Ringbuffer_t");
+#endif
+#endif
/*
Remark: A counting semaphore for items_buffered_sem would be more logical, but counting semaphores in
FreeRTOS need a maximum count, and allocate more memory the larger the maximum count is. Here, we
which is quite high and so would waste a fair amount of memory.
*/
-/* ------------------------------------------------ Static Declarations ------------------------------------------ */
+/* --------------------------- Static Declarations -------------------------- */
/*
* WARNING: All of the following static functions (except generic functions)
* ARE NOT THREAD SAFE. Therefore they should only be called within a critical
* section (using spin locks)
*/
+
+//Initialize a ring buffer after space has been allocated for it
+static void prvInitializeNewRingbuffer(size_t xBufferSize,
+ RingbufferType_t xBufferType,
+ Ringbuffer_t *pxNewRingbuffer,
+ uint8_t *pucRingbufferStorage);
+
//Calculate current amount of free space (in bytes) in the ring buffer
static size_t prvGetFreeSize(Ringbuffer_t *pxRingbuffer);
static void prvCopyItemByteBuf(Ringbuffer_t *pxRingbuffer, const uint8_t *pucItem, size_t xItemSize);
//Retrieve item from no-split/allow-split ring buffer. *pxIsSplit is set to pdTRUE if the retrieved item is split
-static void *prvGetItemDefault(Ringbuffer_t *pxRingbuffer, BaseType_t *pxIsSplit, size_t xUnusedParam, size_t *pxItemSize);
+static void *prvGetItemDefault(Ringbuffer_t *pxRingbuffer,
+ BaseType_t *pxIsSplit,
+ size_t xUnusedParam,
+ size_t *pxItemSize);
//Retrieve data from byte buffer. If xMaxSize is 0, all continuous data is retrieved
-static void *prvGetItemByteBuf(Ringbuffer_t *pxRingbuffer, BaseType_t *pxUnusedParam ,size_t xMaxSize, size_t *pxItemSize);
+static void *prvGetItemByteBuf(Ringbuffer_t *pxRingbuffer,
+ BaseType_t *pxUnusedParam,
+ size_t xMaxSize,
+ size_t *pxItemSize);
//Return an item to a split/no-split ring buffer
static void prvReturnItemDefault(Ringbuffer_t *pxRingbuffer, uint8_t *pucItem);
* a split item will be retrieved. xMaxSize will only take effect if called on
* byte buffers.
*/
-static BaseType_t prvReceiveGeneric(Ringbuffer_t *pxRingbuffer, void **pvItem1, void **pvItem2, size_t *xItemSize1, size_t *xItemSize2, size_t xMaxSize, TickType_t xTicksToWait);
+static BaseType_t prvReceiveGeneric(Ringbuffer_t *pxRingbuffer,
+ void **pvItem1,
+ void **pvItem2,
+ size_t *xItemSize1,
+ size_t *xItemSize2,
+ size_t xMaxSize,
+ TickType_t xTicksToWait);
//Generic function used to retrieve an item/data from ring buffers in an ISR
-static BaseType_t prvReceiveGenericFromISR(Ringbuffer_t *pxRingbuffer, void **pvItem1, void **pvItem2, size_t *xItemSize1, size_t *xItemSize2, size_t xMaxSize);
+static BaseType_t prvReceiveGenericFromISR(Ringbuffer_t *pxRingbuffer,
+ void **pvItem1,
+ void **pvItem2,
+ size_t *xItemSize1,
+ size_t *xItemSize2,
+ size_t xMaxSize);
+
+/* --------------------------- Static Definitions --------------------------- */
+
+static void prvInitializeNewRingbuffer(size_t xBufferSize,
+ RingbufferType_t xBufferType,
+ Ringbuffer_t *pxNewRingbuffer,
+ uint8_t *pucRingbufferStorage)
+{
+ //Initialize values
+ pxNewRingbuffer->xSize = xBufferSize;
+ pxNewRingbuffer->pucHead = pucRingbufferStorage;
+ pxNewRingbuffer->pucTail = pucRingbufferStorage + xBufferSize;
+ pxNewRingbuffer->pucFree = pucRingbufferStorage;
+ pxNewRingbuffer->pucRead = pucRingbufferStorage;
+ pxNewRingbuffer->pucWrite = pucRingbufferStorage;
+ pxNewRingbuffer->xItemsWaiting = 0;
+ pxNewRingbuffer->uxRingbufferFlags = 0;
-/* ------------------------------------------------ Static Definitions ------------------------------------------- */
+ //Initialize type dependent values and function pointers
+ if (xBufferType == RINGBUF_TYPE_NOSPLIT) {
+ pxNewRingbuffer->xCheckItemFits = prvCheckItemFitsDefault;
+ pxNewRingbuffer->vCopyItem = prvCopyItemNoSplit;
+ pxNewRingbuffer->pvGetItem = prvGetItemDefault;
+ pxNewRingbuffer->vReturnItem = prvReturnItemDefault;
+ /*
+ * Worst case scenario is when the read/write/free pointers are all
+ * pointing to the halfway point of the buffer.
+ */
+ pxNewRingbuffer->xMaxItemSize = rbALIGN_SIZE(pxNewRingbuffer->xSize / 2) - rbHEADER_SIZE;
+ pxNewRingbuffer->xGetCurMaxSize = prvGetCurMaxSizeNoSplit;
+ } else if (xBufferType == RINGBUF_TYPE_ALLOWSPLIT) {
+ pxNewRingbuffer->uxRingbufferFlags |= rbALLOW_SPLIT_FLAG;
+ pxNewRingbuffer->xCheckItemFits = prvCheckItemFitsDefault;
+ pxNewRingbuffer->vCopyItem = prvCopyItemAllowSplit;
+ pxNewRingbuffer->pvGetItem = prvGetItemDefault;
+ pxNewRingbuffer->vReturnItem = prvReturnItemDefault;
+ //Worst case an item is split into two, incurring two headers of overhead
+ pxNewRingbuffer->xMaxItemSize = pxNewRingbuffer->xSize - (sizeof(ItemHeader_t) * 2);
+ pxNewRingbuffer->xGetCurMaxSize = prvGetCurMaxSizeAllowSplit;
+ } else { //Byte Buffer
+ pxNewRingbuffer->uxRingbufferFlags |= rbBYTE_BUFFER_FLAG;
+ pxNewRingbuffer->xCheckItemFits = prvCheckItemFitsByteBuffer;
+ pxNewRingbuffer->vCopyItem = prvCopyItemByteBuf;
+ pxNewRingbuffer->pvGetItem = prvGetItemByteBuf;
+ pxNewRingbuffer->vReturnItem = prvReturnItemByteBuf;
+ //Byte buffers do not incur any overhead
+ pxNewRingbuffer->xMaxItemSize = pxNewRingbuffer->xSize;
+ pxNewRingbuffer->xGetCurMaxSize = prvGetCurMaxSizeByteBuf;
+ }
+ xSemaphoreGive(rbGET_TX_SEM_HANDLE(pxNewRingbuffer));
+ vPortCPUInitializeMutex(&pxNewRingbuffer->mux);
+}
static size_t prvGetFreeSize(Ringbuffer_t *pxRingbuffer)
{
}
}
-static void *prvGetItemDefault(Ringbuffer_t *pxRingbuffer, BaseType_t *pxIsSplit, size_t xUnusedParam, size_t *pxItemSize)
+static void *prvGetItemDefault(Ringbuffer_t *pxRingbuffer,
+ BaseType_t *pxIsSplit,
+ size_t xUnusedParam,
+ size_t *pxItemSize)
{
//Check arguments and buffer state
ItemHeader_t *pxHeader = (ItemHeader_t *)pxRingbuffer->pucRead;
return (void *)pcReturn;
}
-static void *prvGetItemByteBuf(Ringbuffer_t *pxRingbuffer, BaseType_t *pxUnusedParam ,size_t xMaxSize, size_t *pxItemSize)
+static void *prvGetItemByteBuf(Ringbuffer_t *pxRingbuffer,
+ BaseType_t *pxUnusedParam,
+ size_t xMaxSize,
+ size_t *pxItemSize)
{
//Check arguments and buffer state
configASSERT((pxRingbuffer->xItemsWaiting > 0) && ((pxRingbuffer->pucRead != pxRingbuffer->pucWrite) || (pxRingbuffer->uxRingbufferFlags & rbBUFFER_FULL_FLAG))); //Check there are items to be read
return xFreeSize;
}
-static BaseType_t prvReceiveGeneric(Ringbuffer_t *pxRingbuffer, void **pvItem1, void **pvItem2, size_t *xItemSize1, size_t *xItemSize2, size_t xMaxSize, TickType_t xTicksToWait)
+static BaseType_t prvReceiveGeneric(Ringbuffer_t *pxRingbuffer,
+ void **pvItem1,
+ void **pvItem2,
+ size_t *xItemSize1,
+ size_t *xItemSize2,
+ size_t xMaxSize,
+ TickType_t xTicksToWait)
{
BaseType_t xReturn = pdFALSE;
BaseType_t xReturnSemaphore = pdFALSE;
TickType_t xTicksRemaining = xTicksToWait;
while (xTicksRemaining <= xTicksToWait) { //xTicksToWait will underflow once xTaskGetTickCount() > ticks_end
//Block until more free space becomes available or timeout
- if (xSemaphoreTake(pxRingbuffer->xItemsBufferedSemaphore, xTicksRemaining) != pdTRUE) {
+ if (xSemaphoreTake(rbGET_RX_SEM_HANDLE(pxRingbuffer), xTicksRemaining) != pdTRUE) {
xReturn = pdFALSE; //Timed out attempting to get semaphore
break;
}
}
if (xReturnSemaphore == pdTRUE) {
- xSemaphoreGive(pxRingbuffer->xItemsBufferedSemaphore); //Give semaphore back so other tasks can retrieve
+ xSemaphoreGive(rbGET_RX_SEM_HANDLE(pxRingbuffer)); //Give semaphore back so other tasks can retrieve
}
return xReturn;
}
-static BaseType_t prvReceiveGenericFromISR(Ringbuffer_t *pxRingbuffer, void **pvItem1, void **pvItem2, size_t *xItemSize1, size_t *xItemSize2, size_t xMaxSize)
+static BaseType_t prvReceiveGenericFromISR(Ringbuffer_t *pxRingbuffer,
+ void **pvItem1,
+ void **pvItem2,
+ size_t *xItemSize1,
+ size_t *xItemSize2,
+ size_t xMaxSize)
{
BaseType_t xReturn = pdFALSE;
BaseType_t xReturnSemaphore = pdFALSE;
portEXIT_CRITICAL_ISR(&pxRingbuffer->mux);
if (xReturnSemaphore == pdTRUE) {
- xSemaphoreGiveFromISR(pxRingbuffer->xItemsBufferedSemaphore, NULL); //Give semaphore back so other tasks can retrieve
+ xSemaphoreGiveFromISR(rbGET_RX_SEM_HANDLE(pxRingbuffer), NULL); //Give semaphore back so other tasks can retrieve
}
return xReturn;
}
-/* ------------------------------------------------- Public Definitions -------------------------------------------- */
+/* --------------------------- Public Definitions --------------------------- */
-RingbufHandle_t xRingbufferCreate(size_t xBufferSize, ringbuf_type_t xBufferType)
+RingbufHandle_t xRingbufferCreate(size_t xBufferSize, RingbufferType_t xBufferType)
{
+ configASSERT(xBufferSize > 0);
+ configASSERT(xBufferType < RINGBUF_TYPE_MAX);
+
//Allocate memory
- Ringbuffer_t *pxRingbuffer = calloc(1, sizeof(Ringbuffer_t));
- if (pxRingbuffer == NULL) {
- goto err;
- }
if (xBufferType != RINGBUF_TYPE_BYTEBUF) {
xBufferSize = rbALIGN_SIZE(xBufferSize); //xBufferSize is rounded up for no-split/allow-split buffers
}
- pxRingbuffer->pucHead = malloc(xBufferSize);
- if (pxRingbuffer->pucHead == NULL) {
+ Ringbuffer_t *pxNewRingbuffer = calloc(1, sizeof(Ringbuffer_t));
+ uint8_t *pucRingbufferStorage = malloc(xBufferSize);
+ if (pxNewRingbuffer == NULL || pucRingbufferStorage == NULL) {
goto err;
}
- //Initialize values
- pxRingbuffer->xSize = xBufferSize;
- pxRingbuffer->pucTail = pxRingbuffer->pucHead + xBufferSize;
- pxRingbuffer->pucFree = pxRingbuffer->pucHead;
- pxRingbuffer->pucRead = pxRingbuffer->pucHead;
- pxRingbuffer->pucWrite = pxRingbuffer->pucHead;
- pxRingbuffer->xItemsWaiting = 0;
- pxRingbuffer->xFreeSpaceSemaphore = xSemaphoreCreateBinary();
- pxRingbuffer->xItemsBufferedSemaphore = xSemaphoreCreateBinary();
- pxRingbuffer->uxRingbufferFlags = 0;
-
- //Initialize type dependent values and function pointers
- if (xBufferType == RINGBUF_TYPE_NOSPLIT) {
- pxRingbuffer->xCheckItemFits = prvCheckItemFitsDefault;
- pxRingbuffer->vCopyItem = prvCopyItemNoSplit;
- pxRingbuffer->pvGetItem = prvGetItemDefault;
- pxRingbuffer->vReturnItem = prvReturnItemDefault;
- /*
- * Buffer lengths are always aligned. No-split buffer (read/write/free)
- * pointers are also always aligned. Therefore worse case scenario is
- * the write pointer is at the most aligned halfway point.
- */
- pxRingbuffer->xMaxItemSize = rbALIGN_SIZE(pxRingbuffer->xSize / 2) - rbHEADER_SIZE;
- pxRingbuffer->xGetCurMaxSize = prvGetCurMaxSizeNoSplit;
- } else if (xBufferType == RINGBUF_TYPE_ALLOWSPLIT) {
- pxRingbuffer->uxRingbufferFlags |= rbALLOW_SPLIT_FLAG;
- pxRingbuffer->xCheckItemFits = prvCheckItemFitsDefault;
- pxRingbuffer->vCopyItem = prvCopyItemAllowSplit;
- pxRingbuffer->pvGetItem = prvGetItemDefault;
- pxRingbuffer->vReturnItem = prvReturnItemDefault;
- //Worst case an item is split into two, incurring two headers of overhead
- pxRingbuffer->xMaxItemSize = pxRingbuffer->xSize - (sizeof(ItemHeader_t) * 2);
- pxRingbuffer->xGetCurMaxSize = prvGetCurMaxSizeAllowSplit;
- } else if (xBufferType == RINGBUF_TYPE_BYTEBUF) {
- pxRingbuffer->uxRingbufferFlags |= rbBYTE_BUFFER_FLAG;
- pxRingbuffer->xCheckItemFits = prvCheckItemFitsByteBuffer;
- pxRingbuffer->vCopyItem = prvCopyItemByteBuf;
- pxRingbuffer->pvGetItem = prvGetItemByteBuf;
- pxRingbuffer->vReturnItem = prvReturnItemByteBuf;
- //Byte buffers do not incur any overhead
- pxRingbuffer->xMaxItemSize = pxRingbuffer->xSize;
- pxRingbuffer->xGetCurMaxSize = prvGetCurMaxSizeByteBuf;
- } else {
- //Unsupported type
- configASSERT(0);
- }
-
- if (pxRingbuffer->xFreeSpaceSemaphore == NULL || pxRingbuffer->xItemsBufferedSemaphore == NULL) {
+ //Initialize Semaphores
+#if ( configSUPPORT_STATIC_ALLOCATION == 1)
+ //We don't use the handles for static semaphores, and xSemaphoreCreateBinaryStatic will never fail thus no need to check static case
+ xSemaphoreCreateBinaryStatic(&(pxNewRingbuffer->xTransSemStatic));
+ xSemaphoreCreateBinaryStatic(&(pxNewRingbuffer->xRecvSemStatic));
+#else
+ pxNewRingbuffer->xTransSemHandle = xSemaphoreCreateBinary();
+ pxNewRingbuffer->xRecvSemHandle = xSemaphoreCreateBinary();
+ if (pxNewRingbuffer->xTransSemHandle == NULL || pxNewRingbuffer->xRecvSemHandle == NULL) {
+ if (pxNewRingbuffer->xTransSemHandle != NULL) {
+ vSemaphoreDelete(pxNewRingbuffer->xTransSemHandle);
+ }
+ if (pxNewRingbuffer->xRecvSemHandle != NULL) {
+ vSemaphoreDelete(pxNewRingbuffer->xRecvSemHandle);
+ }
goto err;
}
- xSemaphoreGive(pxRingbuffer->xFreeSpaceSemaphore);
- vPortCPUInitializeMutex(&pxRingbuffer->mux);
+#endif
- return (RingbufHandle_t)pxRingbuffer;
+ prvInitializeNewRingbuffer(xBufferSize, xBufferType, pxNewRingbuffer, pucRingbufferStorage);
+ return (RingbufHandle_t)pxNewRingbuffer;
err:
- //Some error has happened. Free/destroy all allocated things and return NULL.
- if (pxRingbuffer) {
- free(pxRingbuffer->pucHead);
- if (pxRingbuffer->xFreeSpaceSemaphore) {
- vSemaphoreDelete(pxRingbuffer->xFreeSpaceSemaphore);
- }
- if (pxRingbuffer->xItemsBufferedSemaphore) {
- vSemaphoreDelete(pxRingbuffer->xItemsBufferedSemaphore);
- }
- }
- free(pxRingbuffer);
+ //An error has occurred, Free memory and return NULL
+ free(pxNewRingbuffer);
+ free(pucRingbufferStorage);
return NULL;
}
return xRingbufferCreate((rbALIGN_SIZE(xItemSize) + rbHEADER_SIZE) * xItemNum, RINGBUF_TYPE_NOSPLIT);
}
-BaseType_t xRingbufferSend(RingbufHandle_t xRingbuffer, const void *pvItem, size_t xItemSize, TickType_t xTicksToWait)
+#if ( configSUPPORT_STATIC_ALLOCATION == 1 )
+RingbufHandle_t xRingbufferCreateStatic(size_t xBufferSize,
+ RingbufferType_t xBufferType,
+ uint8_t *pucRingbufferStorage,
+ StaticRingbuffer_t *pxStaticRingbuffer)
+{
+ //Check arguments
+ configASSERT(xBufferSize > 0);
+ configASSERT(xBufferType < RINGBUF_TYPE_MAX);
+ configASSERT(pucRingbufferStorage != NULL && pxStaticRingbuffer != NULL);
+ if (xBufferType != RINGBUF_TYPE_BYTEBUF) {
+ //No-split/allow-split buffer sizes must be 32-bit aligned
+ configASSERT(rbCHECK_ALIGNED(xBufferSize));
+ }
+
+ Ringbuffer_t *pxNewRingbuffer = (Ringbuffer_t *)pxStaticRingbuffer;
+ xSemaphoreCreateBinaryStatic(&(pxNewRingbuffer->xTransSemStatic));
+ xSemaphoreCreateBinaryStatic(&(pxNewRingbuffer->xRecvSemStatic));
+ prvInitializeNewRingbuffer(xBufferSize, xBufferType, pxNewRingbuffer, pucRingbufferStorage);
+ pxNewRingbuffer->uxRingbufferFlags |= rbBUFFER_STATIC_FLAG;
+ return (RingbufHandle_t)pxNewRingbuffer;
+}
+#endif
+
+BaseType_t xRingbufferSend(RingbufHandle_t xRingbuffer,
+ const void *pvItem,
+ size_t xItemSize,
+ TickType_t xTicksToWait)
{
//Check arguments
Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer;
TickType_t xTicksRemaining = xTicksToWait;
while (xTicksRemaining <= xTicksToWait) { //xTicksToWait will underflow once xTaskGetTickCount() > ticks_end
//Block until more free space becomes available or timeout
- if (xSemaphoreTake(pxRingbuffer->xFreeSpaceSemaphore, xTicksRemaining) != pdTRUE) {
+ if (xSemaphoreTake(rbGET_TX_SEM_HANDLE(pxRingbuffer), xTicksRemaining) != pdTRUE) {
xReturn = pdFALSE;
break;
}
if (xReturn == pdTRUE) {
//Indicate item was successfully sent
- xSemaphoreGive(pxRingbuffer->xItemsBufferedSemaphore);
+ xSemaphoreGive(rbGET_RX_SEM_HANDLE(pxRingbuffer));
}
if (xReturnSemaphore == pdTRUE) {
- xSemaphoreGive(pxRingbuffer->xFreeSpaceSemaphore); //Give back semaphore so other tasks can send
+ xSemaphoreGive(rbGET_TX_SEM_HANDLE(pxRingbuffer)); //Give back semaphore so other tasks can send
}
return xReturn;
}
-BaseType_t xRingbufferSendFromISR(RingbufHandle_t xRingbuffer, const void *pvItem, size_t xItemSize, BaseType_t *pxHigherPriorityTaskWoken)
+BaseType_t xRingbufferSendFromISR(RingbufHandle_t xRingbuffer,
+ const void *pvItem,
+ size_t xItemSize,
+ BaseType_t *pxHigherPriorityTaskWoken)
{
//Check arguments
Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer;
if (xReturn == pdTRUE) {
//Indicate item was successfully sent
- xSemaphoreGiveFromISR(pxRingbuffer->xItemsBufferedSemaphore, pxHigherPriorityTaskWoken);
+ xSemaphoreGiveFromISR(rbGET_RX_SEM_HANDLE(pxRingbuffer), pxHigherPriorityTaskWoken);
}
if (xReturnSemaphore == pdTRUE) {
- xSemaphoreGiveFromISR(pxRingbuffer->xFreeSpaceSemaphore, pxHigherPriorityTaskWoken); //Give back semaphore so other tasks can send
+ xSemaphoreGiveFromISR(rbGET_TX_SEM_HANDLE(pxRingbuffer), pxHigherPriorityTaskWoken); //Give back semaphore so other tasks can send
}
return xReturn;
}
}
}
-BaseType_t xRingbufferReceiveSplit(RingbufHandle_t xRingbuffer, void **ppvHeadItem, void **ppvTailItem, size_t *pxHeadItemSize, size_t *pxTailItemSize, TickType_t xTicksToWait)
+BaseType_t xRingbufferReceiveSplit(RingbufHandle_t xRingbuffer,
+ void **ppvHeadItem,
+ void **ppvTailItem,
+ size_t *pxHeadItemSize,
+ size_t *pxTailItemSize,
+ TickType_t xTicksToWait)
{
//Check arguments
Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer;
}
}
-BaseType_t xRingbufferReceiveSplitFromISR(RingbufHandle_t xRingbuffer, void **ppvHeadItem, void **ppvTailItem, size_t *pxHeadItemSize, size_t *pxTailItemSize)
+BaseType_t xRingbufferReceiveSplitFromISR(RingbufHandle_t xRingbuffer,
+ void **ppvHeadItem,
+ void **ppvTailItem,
+ size_t *pxHeadItemSize,
+ size_t *pxTailItemSize)
{
//Check arguments
Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer;
}
}
-void *xRingbufferReceiveUpTo(RingbufHandle_t xRingbuffer, size_t *pxItemSize, TickType_t xTicksToWait, size_t xMaxSize)
+void *xRingbufferReceiveUpTo(RingbufHandle_t xRingbuffer,
+ size_t *pxItemSize,
+ TickType_t xTicksToWait,
+ size_t xMaxSize)
{
//Check arguments
Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer;
portENTER_CRITICAL(&pxRingbuffer->mux);
pxRingbuffer->vReturnItem(pxRingbuffer, (uint8_t *)pvItem);
portEXIT_CRITICAL(&pxRingbuffer->mux);
- xSemaphoreGive(pxRingbuffer->xFreeSpaceSemaphore);
+ xSemaphoreGive(rbGET_TX_SEM_HANDLE(pxRingbuffer));
}
void vRingbufferReturnItemFromISR(RingbufHandle_t xRingbuffer, void *pvItem, BaseType_t *pxHigherPriorityTaskWoken)
portENTER_CRITICAL_ISR(&pxRingbuffer->mux);
pxRingbuffer->vReturnItem(pxRingbuffer, (uint8_t *)pvItem);
portEXIT_CRITICAL_ISR(&pxRingbuffer->mux);
- xSemaphoreGiveFromISR(pxRingbuffer->xFreeSpaceSemaphore, pxHigherPriorityTaskWoken);
+ xSemaphoreGiveFromISR(rbGET_TX_SEM_HANDLE(pxRingbuffer), pxHigherPriorityTaskWoken);
}
void vRingbufferDelete(RingbufHandle_t xRingbuffer)
Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer;
configASSERT(pxRingbuffer);
- if (pxRingbuffer) {
- free(pxRingbuffer->pucHead);
- if (pxRingbuffer->xFreeSpaceSemaphore) {
- vSemaphoreDelete(pxRingbuffer->xFreeSpaceSemaphore);
- }
- if (pxRingbuffer->xItemsBufferedSemaphore) {
- vSemaphoreDelete(pxRingbuffer->xItemsBufferedSemaphore);
- }
+ vSemaphoreDelete(rbGET_TX_SEM_HANDLE(pxRingbuffer));
+ vSemaphoreDelete(rbGET_RX_SEM_HANDLE(pxRingbuffer));
+
+#if ( configSUPPORT_STATIC_ALLOCATION == 1 )
+ if (pxRingbuffer->uxRingbufferFlags & rbBUFFER_STATIC_FLAG) {
+ //Ring buffer was statically allocated, no need to free
+ return;
}
+#endif
+ free(pxRingbuffer->pucHead);
free(pxRingbuffer);
}
BaseType_t xReturn;
portENTER_CRITICAL(&pxRingbuffer->mux);
//Cannot add semaphore to queue set if semaphore is not empty. Temporarily hold semaphore
- BaseType_t xHoldSemaphore = xSemaphoreTake(pxRingbuffer->xItemsBufferedSemaphore, 0);
- xReturn = xQueueAddToSet(pxRingbuffer->xItemsBufferedSemaphore, xQueueSet);
+ BaseType_t xHoldSemaphore = xSemaphoreTake(rbGET_RX_SEM_HANDLE(pxRingbuffer), 0);
+ xReturn = xQueueAddToSet(rbGET_RX_SEM_HANDLE(pxRingbuffer), xQueueSet);
if (xHoldSemaphore == pdTRUE) {
//Return semaphore if temporarily held
- configASSERT(xSemaphoreGive(pxRingbuffer->xItemsBufferedSemaphore) == pdTRUE);
+ configASSERT(xSemaphoreGive(rbGET_RX_SEM_HANDLE(pxRingbuffer)) == pdTRUE);
}
portEXIT_CRITICAL(&pxRingbuffer->mux);
return xReturn;
//Check if the selected queue set member is the ring buffer's read semaphore
Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer;
configASSERT(pxRingbuffer);
- return (pxRingbuffer->xItemsBufferedSemaphore == xMember) ? pdTRUE : pdFALSE;
+ return (rbGET_RX_SEM_HANDLE(pxRingbuffer) == xMember) ? pdTRUE : pdFALSE;
}
BaseType_t xRingbufferRemoveFromQueueSetRead(RingbufHandle_t xRingbuffer, QueueSetHandle_t xQueueSet)
BaseType_t xReturn;
portENTER_CRITICAL(&pxRingbuffer->mux);
//Cannot remove semaphore from queue set if semaphore is not empty. Temporarily hold semaphore
- BaseType_t xHoldSemaphore = xSemaphoreTake(pxRingbuffer->xItemsBufferedSemaphore, 0);
- xReturn = xQueueRemoveFromSet(pxRingbuffer->xItemsBufferedSemaphore, xQueueSet);
+ BaseType_t xHoldSemaphore = xSemaphoreTake(rbGET_RX_SEM_HANDLE(pxRingbuffer), 0);
+ xReturn = xQueueRemoveFromSet(rbGET_RX_SEM_HANDLE(pxRingbuffer), xQueueSet);
if (xHoldSemaphore == pdTRUE) {
//Return semaphore if temporarily held
- configASSERT(xSemaphoreGive(pxRingbuffer->xItemsBufferedSemaphore) == pdTRUE);
+ configASSERT(xSemaphoreGive(rbGET_RX_SEM_HANDLE(pxRingbuffer)) == pdTRUE);
}
portEXIT_CRITICAL(&pxRingbuffer->mux);
return xReturn;
}
-void vRingbufferGetInfo(RingbufHandle_t xRingbuffer, UBaseType_t *uxFree, UBaseType_t *uxRead, UBaseType_t *uxWrite, UBaseType_t *uxItemsWaiting)
+void vRingbufferGetInfo(RingbufHandle_t xRingbuffer,
+ UBaseType_t *uxFree,
+ UBaseType_t *uxRead,
+ UBaseType_t *uxWrite,
+ UBaseType_t *uxItemsWaiting)
{
Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer;
configASSERT(pxRingbuffer);
pxRingbuffer->pucWrite - pxRingbuffer->pucHead);
}
-/* --------------------------------- Deprecated Functions ------------------------------ */
-//Todo: Remove the following deprecated functions in next release
-
-bool xRingbufferIsNextItemWrapped(RingbufHandle_t xRingbuffer)
-{
- //This function is deprecated, use xRingbufferReceiveSplit() instead
- Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer;
- configASSERT(pxRingbuffer);
- bool is_wrapped;
-
- portENTER_CRITICAL(&pxRingbuffer->mux);
- ItemHeader_t *xHeader = (ItemHeader_t *)pxRingbuffer->pucRead;
- is_wrapped = xHeader->uxItemFlags & rbITEM_SPLIT_FLAG;
- portEXIT_CRITICAL(&pxRingbuffer->mux);
- return is_wrapped;
-}
-
-BaseType_t xRingbufferAddToQueueSetWrite(RingbufHandle_t xRingbuffer, QueueSetHandle_t xQueueSet)
-{
- //This function is deprecated. QueueSetWrite no longer supported
- Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer;
- configASSERT(pxRingbuffer);
-
- BaseType_t xReturn;
- portENTER_CRITICAL(&pxRingbuffer->mux);
- //Cannot add semaphore to queue set if semaphore is not empty. Temporary hold semaphore
- BaseType_t xHoldSemaphore = xSemaphoreTake(pxRingbuffer->xFreeSpaceSemaphore, 0);
- xReturn = xQueueAddToSet(pxRingbuffer->xFreeSpaceSemaphore, xQueueSet);
- if (xHoldSemaphore == pdTRUE) {
- //Return semaphore is temporarily held
- configASSERT(xSemaphoreGive(pxRingbuffer->xFreeSpaceSemaphore) == pdTRUE);
- }
- portEXIT_CRITICAL(&pxRingbuffer->mux);
- return xReturn;
-}
-
-BaseType_t xRingbufferRemoveFromQueueSetWrite(RingbufHandle_t xRingbuffer, QueueSetHandle_t xQueueSet)
-{
- //This function is deprecated. QueueSetWrite no longer supported
- Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer;
- configASSERT(pxRingbuffer);
-
- BaseType_t xReturn;
- portENTER_CRITICAL(&pxRingbuffer->mux);
- //Cannot remove semaphore from queue set if semaphore is not empty. Temporary hold semaphore
- BaseType_t xHoldSemaphore = xSemaphoreTake(pxRingbuffer->xFreeSpaceSemaphore, 0);
- xReturn = xQueueRemoveFromSet(pxRingbuffer->xFreeSpaceSemaphore, xQueueSet);
- if (xHoldSemaphore == pdTRUE) {
- //Return semaphore is temporarily held
- configASSERT(xSemaphoreGive(pxRingbuffer->xFreeSpaceSemaphore) == pdTRUE);
- }
- portEXIT_CRITICAL(&pxRingbuffer->mux);
- return xReturn;
-}
-
#include "freertos/semphr.h"
#include "freertos/ringbuf.h"
#include "driver/timer.h"
+#include "esp_heap_caps.h"
#include "esp_spi_flash.h"
#include "unity.h"
#include "test_utils.h"
* 4) Receive and check the wrapped item
*/
-TEST_CASE("Test ring buffer No-Split", "[freertos]")
+TEST_CASE("Test ring buffer No-Split", "[esp_ringbuf]")
{
//Create buffer
RingbufHandle_t buffer_handle = xRingbufferCreate(BUFFER_SIZE, RINGBUF_TYPE_NOSPLIT);
vRingbufferDelete(buffer_handle);
}
-TEST_CASE("Test ring buffer Allow-Split", "[freertos]")
+TEST_CASE("Test ring buffer Allow-Split", "[esp_ringbuf]")
{
//Create buffer
RingbufHandle_t buffer_handle = xRingbufferCreate(BUFFER_SIZE, RINGBUF_TYPE_ALLOWSPLIT);
vRingbufferDelete(buffer_handle);
}
-TEST_CASE("Test ring buffer Byte Buffer", "[freertos]")
+TEST_CASE("Test ring buffer Byte Buffer", "[esp_ringbuf]")
{
//Create buffer
RingbufHandle_t buffer_handle = xRingbufferCreate(BUFFER_SIZE, RINGBUF_TYPE_BYTEBUF);
vTaskDelete(NULL);
}
-TEST_CASE("Test ring buffer with queue sets", "[freertos]")
+TEST_CASE("Test ring buffer with queue sets", "[esp_ringbuf]")
{
QueueSetHandle_t queue_set = xQueueCreateSet(NO_OF_RB_TYPES);
done_sem = xSemaphoreCreateBinary();
esp_intr_free(ringbuffer_isr_handle);
}
-TEST_CASE("Test ring buffer ISR", "[freertos]")
+TEST_CASE("Test ring buffer ISR", "[esp_ringbuf]")
{
for (int i = 0; i < NO_OF_RB_TYPES; i++) {
buffer_handles[i] = xRingbufferCreate(BUFFER_SIZE, i);
"be_increased_over_multiple_iterations_in_this"
"_test"};
#define CONT_DATA_LEN sizeof(continuous_data)
-#define CONT_DATA_TEST_BUFF_LEN (CONT_DATA_LEN/2) //This will guarantee that the buffer must do a wrap around at some point
+//32-bit aligned size that guarantees a wrap around at some point
+#define CONT_DATA_TEST_BUFF_LEN (((CONT_DATA_LEN/2) + 0x03) & ~0x3)
typedef struct {
RingbufHandle_t buffer;
- ringbuf_type_t type;
+ RingbufferType_t type;
} task_args_t;
static SemaphoreHandle_t tasks_done;
}
}
-static void read_from_buffer(RingbufHandle_t buffer, ringbuf_type_t buf_type, size_t max_rec_size)
+static void read_from_buffer(RingbufHandle_t buffer, RingbufferType_t buf_type, size_t max_rec_size)
{
for (int iter = 0; iter < SMP_TEST_ITERATIONS; iter++) {
size_t bytes_rec = 0; //Number of data bytes received in this iteration
vTaskDelete(NULL);
}
-TEST_CASE("Test ring buffer SMP", "[freertos]")
+static void setup()
{
- ets_printf("size of buf %d\n", CONT_DATA_LEN);
+ ets_printf("Size of test data: %d\n", CONT_DATA_LEN);
tx_done = xSemaphoreCreateBinary(); //Semaphore to indicate send is done for a particular iteration
rx_done = xSemaphoreCreateBinary(); //Semaphore to indicate receive is done for a particular iteration
- tasks_done = xSemaphoreCreateBinary(); //Semaphore used to to indicate send and receive tasks completed running
+ tasks_done = xSemaphoreCreateBinary(); //Semaphore used to to indicate send and receive tasks completed running
srand(SRAND_SEED); //Seed RNG
+}
+
+static void cleanup()
+{
+ //Cleanup
+ vSemaphoreDelete(tx_done);
+ vSemaphoreDelete(rx_done);
+ vSemaphoreDelete(tasks_done);
+}
+TEST_CASE("Test ring buffer SMP", "[esp_ringbuf]")
+{
+ setup();
//Iterate through buffer types (No split, split, then byte buff)
- for (ringbuf_type_t buf_type = 0; buf_type <= RINGBUF_TYPE_BYTEBUF; buf_type++) {
+ for (RingbufferType_t buf_type = 0; buf_type < RINGBUF_TYPE_MAX; buf_type++) {
//Create buffer
task_args_t task_args;
task_args.buffer = xRingbufferCreate(CONT_DATA_TEST_BUFF_LEN, buf_type); //Create buffer of selected type
task_args.type = buf_type;
+ TEST_ASSERT_MESSAGE(task_args.buffer != NULL, "Failed to create ring buffer");
for (int prior_mod = -1; prior_mod < 2; prior_mod++) { //Test different relative priorities
//Test every permutation of core affinity
vRingbufferDelete(task_args.buffer);
vTaskDelay(10);
}
+ cleanup();
+}
- //Cleanup
- vSemaphoreDelete(tx_done);
- vSemaphoreDelete(rx_done);
- vSemaphoreDelete(tasks_done);
+#if ( configSUPPORT_STATIC_ALLOCATION == 1 )
+TEST_CASE("Test static ring buffer SMP", "[esp_ringbuf]")
+{
+ setup();
+ //Iterate through buffer types (No split, split, then byte buff)
+ for (RingbufferType_t buf_type = 0; buf_type < RINGBUF_TYPE_MAX; buf_type++) {
+ StaticRingbuffer_t *buffer_struct;
+ uint8_t *buffer_storage;
+ //Allocate memory and create semaphores
+#if CONFIG_SPIRAM_USE_CAPS_ALLOC //When SPIRAM can only be allocated using heap_caps_malloc()
+ buffer_struct = (StaticRingbuffer_t *)heap_caps_malloc(sizeof(StaticRingbuffer_t), MALLOC_CAP_SPIRAM);
+ buffer_storage = (uint8_t *)heap_caps_malloc(sizeof(uint8_t)*CONT_DATA_TEST_BUFF_LEN, MALLOC_CAP_SPIRAM);
+#else //Case where SPIRAM is disabled or when SPIRAM is allocatable through malloc()
+ buffer_struct = (StaticRingbuffer_t *)malloc(sizeof(StaticRingbuffer_t));
+ buffer_storage = (uint8_t *)malloc(sizeof(uint8_t)*CONT_DATA_TEST_BUFF_LEN);
+#endif
+ TEST_ASSERT(buffer_struct != NULL && buffer_storage != NULL);
+
+ //Create buffer
+ task_args_t task_args;
+ task_args.buffer = xRingbufferCreateStatic(CONT_DATA_TEST_BUFF_LEN, buf_type, buffer_storage, buffer_struct); //Create buffer of selected type
+ task_args.type = buf_type;
+ TEST_ASSERT_MESSAGE(task_args.buffer != NULL, "Failed to create ring buffer");
+
+ for (int prior_mod = -1; prior_mod < 2; prior_mod++) { //Test different relative priorities
+ //Test every permutation of core affinity
+ for (int send_core = 0; send_core < portNUM_PROCESSORS; send_core++) {
+ for (int rec_core = 0; rec_core < portNUM_PROCESSORS; rec_core ++) {
+ ets_printf("Type: %d, PM: %d, SC: %d, RC: %d\n", buf_type, prior_mod, send_core, rec_core);
+ xTaskCreatePinnedToCore(send_task, "send tsk", 2048, (void *)&task_args, 10 + prior_mod, NULL, send_core);
+ xTaskCreatePinnedToCore(rec_task, "rec tsk", 2048, (void *)&task_args, 10, NULL, rec_core);
+ xSemaphoreTake(tasks_done, portMAX_DELAY);
+ vTaskDelay(5); //Allow idle to clean up
+ }
+ }
+ }
+
+ //Delete ring buffer
+ vRingbufferDelete(task_args.buffer);
+
+ //Deallocate memory
+ free(buffer_storage);
+ free(buffer_struct);
+ vTaskDelay(10);
+ }
+ cleanup();
}
+#endif
+
+/* -------------------------- Test ring buffer IRAM ------------------------- */
static IRAM_ATTR __attribute__((noinline)) bool iram_ringbuf_test()
{
return result;
}
-TEST_CASE("Test ringbuffer functions work with flash cache disabled", "[freertos]")
+TEST_CASE("Test ringbuffer functions work with flash cache disabled", "[esp_ringbuf]")
{
TEST_ASSERT( iram_ringbuf_test() );
}