Merge branch 'feature/ringbuffer_static_allocation' into 'master'
Ringbuffers: Add static allocation, refactor, and update API reference Closes IDFGH-639 and IDFGH-902 See merge request idf/esp-idf!4426
This commit is contained in:
commit
e6d229d301
4 changed files with 497 additions and 247 deletions
|
@ -16,7 +16,7 @@
|
|||
#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
|
||||
|
@ -33,27 +33,52 @@ extern "C" {
|
|||
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
|
||||
|
@ -66,7 +91,7 @@ typedef enum {
|
|||
*
|
||||
* @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
|
||||
|
@ -81,11 +106,36 @@ RingbufHandle_t xRingbufferCreate(size_t xBufferSize, ringbuf_type_t xBufferType
|
|||
*/
|
||||
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.
|
||||
|
@ -101,7 +151,10 @@ RingbufHandle_t xRingbufferCreateNoSplit(size_t xItemSize, size_t xItemNum);
|
|||
* - 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
|
||||
|
@ -123,13 +176,16 @@ BaseType_t xRingbufferSend(RingbufHandle_t xRingbuffer, const void *pvItem, size
|
|||
* - 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.
|
||||
|
@ -168,7 +224,7 @@ void *xRingbufferReceiveFromISR(RingbufHandle_t xRingbuffer, size_t *pxItemSize)
|
|||
* 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)
|
||||
|
@ -184,7 +240,12 @@ void *xRingbufferReceiveFromISR(RingbufHandle_t xRingbuffer, size_t *pxItemSize)
|
|||
* - 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
|
||||
|
@ -207,14 +268,18 @@ BaseType_t xRingbufferReceiveSplit(RingbufHandle_t xRingbuffer, void **ppvHeadIt
|
|||
* - 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.
|
||||
|
@ -230,7 +295,10 @@ BaseType_t xRingbufferReceiveSplitFromISR(RingbufHandle_t xRingbuffer, void **pp
|
|||
* 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
|
||||
|
@ -281,6 +349,10 @@ void vRingbufferReturnItemFromISR(RingbufHandle_t xRingbuffer, void *pvItem, Bas
|
|||
* @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);
|
||||
|
||||
|
@ -292,6 +364,12 @@ 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);
|
||||
|
@ -307,6 +385,10 @@ 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
|
||||
|
@ -373,7 +455,11 @@ BaseType_t xRingbufferRemoveFromQueueSetRead(RingbufHandle_t xRingbuffer, QueueS
|
|||
* @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
|
||||
|
@ -382,30 +468,9 @@ void vRingbufferGetInfo(RingbufHandle_t xRingbuffer, UBaseType_t *uxFree, UBaseT
|
|||
*/
|
||||
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
|
||||
}
|
||||
|
|
|
@ -21,18 +21,28 @@
|
|||
|
||||
//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;
|
||||
|
@ -40,7 +50,7 @@ typedef struct {
|
|||
} 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);
|
||||
|
@ -48,10 +58,10 @@ typedef void *(*GetItemFunction_t)(Ringbuffer_t *pxRingbuffer, BaseType_t *pxIsS
|
|||
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
|
||||
|
@ -66,11 +76,37 @@ struct Ringbuffer_t {
|
|||
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
|
||||
|
@ -78,13 +114,20 @@ would need to set the maximum to the maximum amount of times a null-byte unit fi
|
|||
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);
|
||||
|
||||
|
@ -107,10 +150,16 @@ static void prvCopyItemAllowSplit(Ringbuffer_t *pxRingbuffer, const uint8_t *puc
|
|||
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);
|
||||
|
@ -133,12 +182,73 @@ static size_t prvGetCurMaxSizeByteBuf(Ringbuffer_t *pxRingbuffer);
|
|||
* 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 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;
|
||||
|
||||
//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)
|
||||
{
|
||||
|
@ -333,7 +443,10 @@ static BaseType_t prvCheckItemAvail(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;
|
||||
|
@ -371,7 +484,10 @@ static void *prvGetItemDefault(Ringbuffer_t *pxRingbuffer, BaseType_t *pxIsSplit
|
|||
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
|
||||
|
@ -552,7 +668,13 @@ static size_t prvGetCurMaxSizeByteBuf(Ringbuffer_t *pxRingbuffer)
|
|||
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;
|
||||
|
@ -560,7 +682,7 @@ static BaseType_t prvReceiveGeneric(Ringbuffer_t *pxRingbuffer, void **pvItem1,
|
|||
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;
|
||||
}
|
||||
|
@ -606,12 +728,17 @@ static BaseType_t prvReceiveGeneric(Ringbuffer_t *pxRingbuffer, void **pvItem1,
|
|||
}
|
||||
|
||||
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;
|
||||
|
@ -644,95 +771,54 @@ static BaseType_t prvReceiveGenericFromISR(Ringbuffer_t *pxRingbuffer, void **pv
|
|||
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;
|
||||
}
|
||||
|
||||
|
@ -741,7 +827,34 @@ RingbufHandle_t xRingbufferCreateNoSplit(size_t xItemSize, size_t xItemNum)
|
|||
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;
|
||||
|
@ -761,7 +874,7 @@ BaseType_t xRingbufferSend(RingbufHandle_t xRingbuffer, const void *pvItem, size
|
|||
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;
|
||||
}
|
||||
|
@ -791,15 +904,18 @@ BaseType_t xRingbufferSend(RingbufHandle_t xRingbuffer, const void *pvItem, size
|
|||
|
||||
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;
|
||||
|
@ -830,10 +946,10 @@ BaseType_t xRingbufferSendFromISR(RingbufHandle_t xRingbuffer, const void *pvIte
|
|||
|
||||
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;
|
||||
}
|
||||
|
@ -876,7 +992,12 @@ void *xRingbufferReceiveFromISR(RingbufHandle_t xRingbuffer, size_t *pxItemSize)
|
|||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -911,7 +1032,11 @@ BaseType_t xRingbufferReceiveSplit(RingbufHandle_t xRingbuffer, void **ppvHeadIt
|
|||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -945,7 +1070,10 @@ BaseType_t xRingbufferReceiveSplitFromISR(RingbufHandle_t xRingbuffer, void **pp
|
|||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -1000,7 +1128,7 @@ void vRingbufferReturnItem(RingbufHandle_t xRingbuffer, void *pvItem)
|
|||
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)
|
||||
|
@ -1012,7 +1140,7 @@ void vRingbufferReturnItemFromISR(RingbufHandle_t xRingbuffer, void *pvItem, Bas
|
|||
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)
|
||||
|
@ -1020,15 +1148,16 @@ 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);
|
||||
}
|
||||
|
||||
|
@ -1059,11 +1188,11 @@ BaseType_t xRingbufferAddToQueueSetRead(RingbufHandle_t xRingbuffer, QueueSetHan
|
|||
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;
|
||||
|
@ -1074,7 +1203,7 @@ BaseType_t xRingbufferCanRead(RingbufHandle_t xRingbuffer, QueueSetMemberHandle_
|
|||
//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)
|
||||
|
@ -1085,17 +1214,21 @@ BaseType_t xRingbufferRemoveFromQueueSetRead(RingbufHandle_t xRingbuffer, QueueS
|
|||
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);
|
||||
|
@ -1127,58 +1260,3 @@ void xRingbufferPrintInfo(RingbufHandle_t xRingbuffer)
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#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"
|
||||
|
@ -165,7 +166,7 @@ static void receive_check_and_return_item_byte_buffer(RingbufHandle_t handle, co
|
|||
* 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);
|
||||
|
@ -196,7 +197,7 @@ TEST_CASE("Test ring buffer No-Split", "[freertos]")
|
|||
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);
|
||||
|
@ -227,7 +228,7 @@ TEST_CASE("Test ring buffer Allow-Split", "[freertos]")
|
|||
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);
|
||||
|
@ -304,7 +305,7 @@ static void queue_set_receiving_task(void *queue_set_handle)
|
|||
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();
|
||||
|
@ -421,7 +422,7 @@ static void cleanup_timer()
|
|||
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);
|
||||
|
@ -461,11 +462,12 @@ static const char continuous_data[] = {"A_very_long_string_that_will_be_split_in
|
|||
"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;
|
||||
|
@ -494,7 +496,7 @@ static void send_to_buffer(RingbufHandle_t buffer, size_t max_item_size)
|
|||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -568,20 +570,33 @@ static void rec_task(void *args)
|
|||
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
|
||||
|
@ -600,13 +615,60 @@ TEST_CASE("Test ring buffer SMP", "[freertos]")
|
|||
vRingbufferDelete(task_args.buffer);
|
||||
vTaskDelay(10);
|
||||
}
|
||||
|
||||
//Cleanup
|
||||
vSemaphoreDelete(tx_done);
|
||||
vSemaphoreDelete(rx_done);
|
||||
vSemaphoreDelete(tasks_done);
|
||||
cleanup();
|
||||
}
|
||||
|
||||
#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()
|
||||
{
|
||||
bool result = true;
|
||||
|
@ -621,7 +683,7 @@ 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() );
|
||||
}
|
||||
|
|
|
@ -323,6 +323,51 @@ The following example demonstrates queue set usage with ring buffers.
|
|||
...
|
||||
}
|
||||
|
||||
Ring Buffers with Static Allocation
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The :cpp:func:`xRingbufferCreateStatic` can be used to create ring buffers with specific memory requirements (such as a ring buffer being allocated in external RAM). All blocks of memory used by a ring buffer must be manually allocated beforehand then passed to the :cpp:func:`xRingbufferCreateStatic` to be initialized as a ring buffer. These blocks include the following:
|
||||
|
||||
- The ring buffer's data structure of type :cpp:type:`StaticRingbuffer_t`
|
||||
- The ring buffer's storage area of size ``xBufferSize``. Note that ``xBufferSize`` must be 32-bit aligned for no-split/allow-split buffers.
|
||||
|
||||
The manner in which these blocks are allocated will depend on the users requirements (e.g. all blocks being statically declared, or dynamically allocated with specific capabilities such as external RAM).
|
||||
|
||||
.. note::
|
||||
The :ref:`CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION` option must be enabled in `menuconfig` for statically allocated ring buffers to be available.
|
||||
|
||||
.. note::
|
||||
When deleting a ring buffer created via :cpp:func:`xRingbufferCreateStatic`,
|
||||
the function :cpp:func:`vRingbufferDelete` will not free any of the memory blocks. This must be done manually by the user after :cpp:func:`vRingbufferDelete` is called.
|
||||
|
||||
The code snippet below demonstrates a ring buffer being allocated entirely in external RAM.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#include "freertos/ringbuf.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "esp_heap_caps.h"
|
||||
|
||||
#define BUFFER_SIZE 400 //32-bit aligned size
|
||||
#define BUFFER_TYPE RINGBUF_TYPE_NOSPLIT
|
||||
...
|
||||
|
||||
//Allocate ring buffer data structure and storage area into external RAM
|
||||
StaticRingbuffer_t *buffer_struct = (StaticRingbuffer_t *)heap_caps_malloc(sizeof(StaticRingbuffer_t), MALLOC_CAP_SPIRAM);
|
||||
uint8_t *buffer_storage = (uint8_t *)heap_caps_malloc(sizeof(uint8_t)*BUFFER_SIZE, MALLOC_CAP_SPIRAM);
|
||||
|
||||
//Create a ring buffer with manually allocated memory
|
||||
RingbufHandle_t handle = xRingbufferCreateStatic(BUFFER_SIZE, BUFFER_TYPE, buffer_storage, buffer_struct);
|
||||
|
||||
...
|
||||
|
||||
//Delete the ring buffer after used
|
||||
vRingbufferDelete(handle);
|
||||
|
||||
//Manually free all blocks of memory
|
||||
free(buffer_struct);
|
||||
free(buffer_storage);
|
||||
|
||||
|
||||
Ring Buffer API Reference
|
||||
-------------------------
|
||||
|
|
Loading…
Reference in a new issue