2021-10-17 23:58:00 -04:00
/*
2023-02-22 23:54:06 -05:00
* SPDX - FileCopyrightText : 2023 Espressif Systems ( Shanghai ) CO LTD
2021-10-17 23:58:00 -04:00
*
* SPDX - License - Identifier : Apache - 2.0
*/
2016-09-28 00:43:35 -04:00
# include <stdlib.h>
2018-04-18 13:20:34 -04:00
# include <string.h>
2018-08-30 06:29:01 -04:00
# include "freertos/FreeRTOS.h"
2023-02-22 23:54:06 -05:00
# include "freertos/list.h"
2018-08-30 06:29:01 -04:00
# include "freertos/task.h"
2023-02-22 23:54:06 -05:00
# include "freertos/queue.h"
2018-08-30 06:29:01 -04:00
# include "freertos/ringbuf.h"
2023-06-24 09:30:53 -04:00
# include "esp_heap_caps.h"
2018-04-18 13:20:34 -04:00
2023-02-22 23:54:06 -05:00
// ------------------------------------------------- Macros and Types --------------------------------------------------
2018-04-18 13:20:34 -04:00
//32-bit alignment macros
2020-11-05 23:00:07 -05:00
# define rbALIGN_MASK (0x03)
# define rbALIGN_SIZE( xSize ) ( ( xSize + rbALIGN_MASK ) & ~rbALIGN_MASK )
# define rbCHECK_ALIGNED( pvPtr ) ( ( ( UBaseType_t ) ( pvPtr ) & rbALIGN_MASK ) == 0 )
2016-09-28 00:43:35 -04:00
2018-04-18 13:20:34 -04:00
//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)
2019-03-04 01:27:06 -05:00
# define rbBUFFER_STATIC_FLAG ( ( UBaseType_t ) 8 ) //The ring buffer is statically allocated
2023-02-22 23:54:06 -05:00
# define rbUSING_QUEUE_SET ( ( UBaseType_t ) 16 ) //The ring buffer has been added to a queue set
2016-09-28 00:43:35 -04:00
2018-04-18 13:20:34 -04:00
//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
2021-09-28 04:06:55 -04:00
# define rbITEM_WRITTEN_FLAG ( ( UBaseType_t ) 8 ) //Item has been written to by the application, thus can be read
2018-04-18 13:20:34 -04:00
typedef struct {
//This size of this structure must be 32-bit aligned
size_t xItemLen ;
UBaseType_t uxItemFlags ;
} ItemHeader_t ;
# define rbHEADER_SIZE sizeof(ItemHeader_t)
2019-03-04 01:27:06 -05:00
typedef struct RingbufferDefinition Ringbuffer_t ;
2018-04-18 13:20:34 -04:00
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 * ( * GetItemFunction_t ) ( Ringbuffer_t * pxRingbuffer , BaseType_t * pxIsSplit , size_t xMaxSize , size_t * pxItemSize ) ;
typedef void ( * ReturnItemFunction_t ) ( Ringbuffer_t * pxRingbuffer , uint8_t * pvItem ) ;
typedef size_t ( * GetCurMaxSizeFunction_t ) ( Ringbuffer_t * pxRingbuffer ) ;
2019-03-04 01:27:06 -05:00
typedef struct RingbufferDefinition {
2018-04-18 13:20:34 -04:00
size_t xSize ; //Size of the data storage
size_t xMaxItemSize ; //Maximum item size
2019-03-04 01:27:06 -05:00
UBaseType_t uxRingbufferFlags ; //Flags to indicate the type and status of ring buffer
2018-04-18 13:20:34 -04:00
CheckItemFitsFunction_t xCheckItemFits ; //Function to check if item can currently fit in ring buffer
CopyItemFunction_t vCopyItem ; //Function to copy item to ring buffer
GetItemFunction_t pvGetItem ; //Function to get item from ring buffer
ReturnItemFunction_t vReturnItem ; //Function to return item to ring buffer
GetCurMaxSizeFunction_t xGetCurMaxSize ; //Function to get current free size
2019-06-14 02:10:48 -04:00
uint8_t * pucAcquire ; //Acquire Pointer. Points to where the next item should be acquired.
2018-04-18 13:20:34 -04:00
uint8_t * pucWrite ; //Write Pointer. Points to where the next item should be written
uint8_t * pucRead ; //Read Pointer. Points to where the next item should be read from
uint8_t * pucFree ; //Free Pointer. Points to the last item that has yet to be returned to the ring buffer
uint8_t * pucHead ; //Pointer to the start of the ring buffer storage area
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
2023-02-22 23:54:06 -05:00
List_t xTasksWaitingToSend ; //List of tasks that are blocked waiting to send/acquire onto this ring buffer. Stored in priority order.
List_t xTasksWaitingToReceive ; //List of tasks that are blocked waiting to receive from this ring buffer. Stored in priority order.
QueueSetHandle_t xQueueSet ; //Ring buffer's read queue set handle.
2018-04-18 13:20:34 -04:00
portMUX_TYPE mux ; //Spinlock required for SMP
2019-03-04 01:27:06 -05:00
} Ringbuffer_t ;
2016-09-28 00:43:35 -04:00
2019-03-04 01:27:06 -05:00
_Static_assert ( sizeof ( StaticRingbuffer_t ) = = sizeof ( Ringbuffer_t ) , " StaticRingbuffer_t != Ringbuffer_t " ) ;
2016-09-28 00:43:35 -04:00
2023-02-22 23:54:06 -05:00
// ------------------------------------------------ Forward Declares ---------------------------------------------------
2018-04-18 13:20:34 -04:00
/*
* 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 )
*/
2016-09-28 00:43:35 -04:00
2019-03-04 01:27:06 -05:00
//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 ) ;
2018-04-18 13:20:34 -04:00
//Calculate current amount of free space (in bytes) in the ring buffer
static size_t prvGetFreeSize ( Ringbuffer_t * pxRingbuffer ) ;
//Checks if an item/data is currently available for retrieval
static BaseType_t prvCheckItemAvail ( Ringbuffer_t * pxRingbuffer ) ;
//Checks if an item will currently fit in a no-split/allow-split ring buffer
static BaseType_t prvCheckItemFitsDefault ( Ringbuffer_t * pxRingbuffer , size_t xItemSize ) ;
//Checks if an item will currently fit in a byte buffer
static BaseType_t prvCheckItemFitsByteBuffer ( Ringbuffer_t * pxRingbuffer , size_t xItemSize ) ;
2021-09-28 04:06:55 -04:00
/*
Copies an item to a no - split ring buffer
Entry :
- Must have already guaranteed there is sufficient space for item by calling prvCheckItemFitsDefault ( )
Exit :
- New item copied into ring buffer
- pucAcquire and pucWrite updated .
- Dummy item added if necessary
*/
2018-04-18 13:20:34 -04:00
static void prvCopyItemNoSplit ( Ringbuffer_t * pxRingbuffer , const uint8_t * pucItem , size_t xItemSize ) ;
2021-09-28 04:06:55 -04:00
/*
Copies an item to a allow - split ring buffer
Entry :
- Must have already guaranteed there is sufficient space for item by calling prvCheckItemFitsDefault ( )
Exit :
- New item copied into ring buffer
- pucAcquire and pucWrite updated
- Item may be split
*/
2018-04-18 13:20:34 -04:00
static void prvCopyItemAllowSplit ( Ringbuffer_t * pxRingbuffer , const uint8_t * pucItem , size_t xItemSize ) ;
//Copies an item to a byte buffer. Only call this function after calling prvCheckItemFitsByteBuffer()
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
2021-09-28 04:06:55 -04:00
/*
Entry :
- Must have already guaranteed that there is an item available for retrieval by calling prvCheckItemAvail ( )
- Guaranteed that pucREAD points to a valid item ( i . e . , not a dummy item )
Exit :
- Item is returned . Only first half returned if split
- pucREAD updated to point to next valid item to read , or equals to pucWrite if there are no more valid items to read
- pucREAD update must skip over dummy items
*/
2019-03-04 01:27:06 -05:00
static void * prvGetItemDefault ( Ringbuffer_t * pxRingbuffer ,
BaseType_t * pxIsSplit ,
size_t xUnusedParam ,
size_t * pxItemSize ) ;
2018-04-18 13:20:34 -04:00
//Retrieve data from byte buffer. If xMaxSize is 0, all continuous data is retrieved
2019-03-04 01:27:06 -05:00
static void * prvGetItemByteBuf ( Ringbuffer_t * pxRingbuffer ,
BaseType_t * pxUnusedParam ,
size_t xMaxSize ,
size_t * pxItemSize ) ;
2018-04-18 13:20:34 -04:00
2021-09-28 04:06:55 -04:00
/*
Return an item to a split / no - split ring buffer
Exit :
- Item is marked free rbITEM_FREE_FLAG
- pucFree is progressed as far as possible , skipping over already freed items or dummy items
*/
2018-04-18 13:20:34 -04:00
static void prvReturnItemDefault ( Ringbuffer_t * pxRingbuffer , uint8_t * pucItem ) ;
//Return data to a byte buffer
static void prvReturnItemByteBuf ( Ringbuffer_t * pxRingbuffer , uint8_t * pucItem ) ;
//Get the maximum size an item that can currently have if sent to a no-split ring buffer
static size_t prvGetCurMaxSizeNoSplit ( Ringbuffer_t * pxRingbuffer ) ;
//Get the maximum size an item that can currently have if sent to a allow-split ring buffer
static size_t prvGetCurMaxSizeAllowSplit ( Ringbuffer_t * pxRingbuffer ) ;
//Get the maximum size an item that can currently have if sent to a byte buffer
static size_t prvGetCurMaxSizeByteBuf ( Ringbuffer_t * pxRingbuffer ) ;
2023-02-22 23:54:06 -05:00
/*
Generic function used to send or acquire an item / buffer .
- If sending , set ppvItem to NULL . pvItem remains unchanged on failure .
- If acquiring , set pvItem to NULL . ppvItem remains unchanged on failure .
*/
static BaseType_t prvSendAcquireGeneric ( Ringbuffer_t * pxRingbuffer ,
const void * pvItem ,
void * * ppvItem ,
size_t xItemSize ,
TickType_t xTicksToWait ) ;
/*
Generic function used to retrieve an item / data from ring buffers . If called on
an allow - split buffer , and pvItem2 and xItemSize2 are not NULL , both parts of
a split item will be retrieved . xMaxSize will only take effect if called on
byte buffers . xItemSize must remain unchanged if no item is retrieved .
*/
2019-03-04 01:27:06 -05:00
static BaseType_t prvReceiveGeneric ( Ringbuffer_t * pxRingbuffer ,
void * * pvItem1 ,
void * * pvItem2 ,
size_t * xItemSize1 ,
size_t * xItemSize2 ,
size_t xMaxSize ,
TickType_t xTicksToWait ) ;
2018-04-18 13:20:34 -04:00
2023-02-22 23:54:06 -05:00
//From ISR version of prvReceiveGeneric()
2019-03-04 01:27:06 -05:00
static BaseType_t prvReceiveGenericFromISR ( Ringbuffer_t * pxRingbuffer ,
void * * pvItem1 ,
void * * pvItem2 ,
size_t * xItemSize1 ,
size_t * xItemSize2 ,
size_t xMaxSize ) ;
2023-02-22 23:54:06 -05:00
// ------------------------------------------------ Static Functions ---------------------------------------------------
2019-03-04 01:27:06 -05:00
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 ;
2019-06-14 02:10:48 -04:00
pxNewRingbuffer - > pucAcquire = pucRingbufferStorage ;
2019-03-04 01:27:06 -05:00
pxNewRingbuffer - > xItemsWaiting = 0 ;
pxNewRingbuffer - > uxRingbufferFlags = 0 ;
2018-04-18 13:20:34 -04:00
2019-03-04 01:27:06 -05:00
//Initialize type dependent values and function pointers
if ( xBufferType = = RINGBUF_TYPE_NOSPLIT ) {
pxNewRingbuffer - > xCheckItemFits = prvCheckItemFitsDefault ;
pxNewRingbuffer - > vCopyItem = prvCopyItemNoSplit ;
pxNewRingbuffer - > pvGetItem = prvGetItemDefault ;
pxNewRingbuffer - > vReturnItem = prvReturnItemDefault ;
/*
2019-06-14 02:10:48 -04:00
* Worst case scenario is when the read / write / acquire / free pointers are all
2019-03-04 01:27:06 -05:00
* 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 ;
}
2023-02-22 23:54:06 -05:00
vListInitialise ( & pxNewRingbuffer - > xTasksWaitingToSend ) ;
vListInitialise ( & pxNewRingbuffer - > xTasksWaitingToReceive ) ;
pxNewRingbuffer - > xQueueSet = NULL ;
2021-10-29 12:48:19 -04:00
portMUX_INITIALIZE ( & pxNewRingbuffer - > mux ) ;
2019-03-04 01:27:06 -05:00
}
2016-10-24 09:18:02 -04:00
2018-04-18 13:20:34 -04:00
static size_t prvGetFreeSize ( Ringbuffer_t * pxRingbuffer )
{
size_t xReturn ;
if ( pxRingbuffer - > uxRingbufferFlags & rbBUFFER_FULL_FLAG ) {
xReturn = 0 ;
2016-10-24 09:18:02 -04:00
} else {
2019-06-14 02:10:48 -04:00
BaseType_t xFreeSize = pxRingbuffer - > pucFree - pxRingbuffer - > pucAcquire ;
2018-04-18 13:20:34 -04:00
//Check if xFreeSize has underflowed
if ( xFreeSize < = 0 ) {
xFreeSize + = pxRingbuffer - > xSize ;
2016-10-24 09:18:02 -04:00
}
2018-04-18 13:20:34 -04:00
xReturn = xFreeSize ;
2016-10-24 09:18:02 -04:00
}
2018-04-18 13:20:34 -04:00
configASSERT ( xReturn < = pxRingbuffer - > xSize ) ;
return xReturn ;
}
2016-10-24 09:18:02 -04:00
2018-04-18 13:20:34 -04:00
static BaseType_t prvCheckItemFitsDefault ( Ringbuffer_t * pxRingbuffer , size_t xItemSize )
{
//Check arguments and buffer state
2019-06-14 02:10:48 -04:00
configASSERT ( rbCHECK_ALIGNED ( pxRingbuffer - > pucAcquire ) ) ; //pucAcquire is always aligned in no-split/allow-split ring buffers
configASSERT ( pxRingbuffer - > pucAcquire > = pxRingbuffer - > pucHead & & pxRingbuffer - > pucAcquire < pxRingbuffer - > pucTail ) ; //Check write pointer is within bounds
2018-04-18 13:20:34 -04:00
size_t xTotalItemSize = rbALIGN_SIZE ( xItemSize ) + rbHEADER_SIZE ; //Rounded up aligned item size with header
2019-06-14 02:10:48 -04:00
if ( pxRingbuffer - > pucAcquire = = pxRingbuffer - > pucFree ) {
2018-04-18 13:20:34 -04:00
//Buffer is either complete empty or completely full
return ( pxRingbuffer - > uxRingbufferFlags & rbBUFFER_FULL_FLAG ) ? pdFALSE : pdTRUE ;
}
2019-06-14 02:10:48 -04:00
if ( pxRingbuffer - > pucFree > pxRingbuffer - > pucAcquire ) {
2018-04-18 13:20:34 -04:00
//Free space does not wrap around
2019-06-14 02:10:48 -04:00
return ( xTotalItemSize < = pxRingbuffer - > pucFree - pxRingbuffer - > pucAcquire ) ? pdTRUE : pdFALSE ;
2018-04-18 13:20:34 -04:00
}
//Free space wraps around
2019-06-14 02:10:48 -04:00
if ( xTotalItemSize < = pxRingbuffer - > pucTail - pxRingbuffer - > pucAcquire ) {
2018-04-18 13:20:34 -04:00
return pdTRUE ; //Item fits without wrapping around
}
//Check if item fits by wrapping
if ( pxRingbuffer - > uxRingbufferFlags & rbALLOW_SPLIT_FLAG ) {
//Allow split wrapping incurs an extra header
2019-06-14 02:10:48 -04:00
return ( xTotalItemSize + rbHEADER_SIZE < = pxRingbuffer - > xSize - ( pxRingbuffer - > pucAcquire - pxRingbuffer - > pucFree ) ) ? pdTRUE : pdFALSE ;
2016-09-28 00:43:35 -04:00
} else {
2018-04-18 13:20:34 -04:00
return ( xTotalItemSize < = pxRingbuffer - > pucFree - pxRingbuffer - > pucHead ) ? pdTRUE : pdFALSE ;
2016-09-28 00:43:35 -04:00
}
2018-04-18 13:20:34 -04:00
}
2016-09-28 00:43:35 -04:00
2018-04-18 13:20:34 -04:00
static BaseType_t prvCheckItemFitsByteBuffer ( Ringbuffer_t * pxRingbuffer , size_t xItemSize )
{
//Check arguments and buffer state
2019-06-14 02:10:48 -04:00
configASSERT ( pxRingbuffer - > pucAcquire > = pxRingbuffer - > pucHead & & pxRingbuffer - > pucAcquire < pxRingbuffer - > pucTail ) ; //Check acquire pointer is within bounds
2016-09-28 00:43:35 -04:00
2019-06-14 02:10:48 -04:00
if ( pxRingbuffer - > pucAcquire = = pxRingbuffer - > pucFree ) {
2018-04-18 13:20:34 -04:00
//Buffer is either complete empty or completely full
return ( pxRingbuffer - > uxRingbufferFlags & rbBUFFER_FULL_FLAG ) ? pdFALSE : pdTRUE ;
2016-09-28 00:43:35 -04:00
}
2019-06-14 02:10:48 -04:00
if ( pxRingbuffer - > pucFree > pxRingbuffer - > pucAcquire ) {
2018-04-18 13:20:34 -04:00
//Free space does not wrap around
2019-06-14 02:10:48 -04:00
return ( xItemSize < = pxRingbuffer - > pucFree - pxRingbuffer - > pucAcquire ) ? pdTRUE : pdFALSE ;
2018-04-18 13:20:34 -04:00
}
//Free space wraps around
2019-06-14 02:10:48 -04:00
return ( xItemSize < = pxRingbuffer - > xSize - ( pxRingbuffer - > pucAcquire - pxRingbuffer - > pucFree ) ) ? pdTRUE : pdFALSE ;
2016-09-28 00:43:35 -04:00
}
2019-06-14 02:10:48 -04:00
static uint8_t * prvAcquireItemNoSplit ( Ringbuffer_t * pxRingbuffer , size_t xItemSize )
2018-04-18 13:20:34 -04:00
{
//Check arguments and buffer state
size_t xAlignedItemSize = rbALIGN_SIZE ( xItemSize ) ; //Rounded up aligned item size
2019-06-14 02:10:48 -04:00
size_t xRemLen = pxRingbuffer - > pucTail - pxRingbuffer - > pucAcquire ; //Length from pucAcquire until end of buffer
configASSERT ( rbCHECK_ALIGNED ( pxRingbuffer - > pucAcquire ) ) ; //pucAcquire is always aligned in no-split ring buffers
configASSERT ( pxRingbuffer - > pucAcquire > = pxRingbuffer - > pucHead & & pxRingbuffer - > pucAcquire < pxRingbuffer - > pucTail ) ; //Check write pointer is within bounds
2018-04-18 13:20:34 -04:00
configASSERT ( xRemLen > = rbHEADER_SIZE ) ; //Remaining length must be able to at least fit an item header
//If remaining length can't fit item, set as dummy data and wrap around
if ( xRemLen < xAlignedItemSize + rbHEADER_SIZE ) {
2019-06-14 02:10:48 -04:00
ItemHeader_t * pxDummy = ( ItemHeader_t * ) pxRingbuffer - > pucAcquire ;
2018-04-18 13:20:34 -04:00
pxDummy - > uxItemFlags = rbITEM_DUMMY_DATA_FLAG ; //Set remaining length as dummy data
pxDummy - > xItemLen = 0 ; //Dummy data should have no length
2019-06-14 02:10:48 -04:00
pxRingbuffer - > pucAcquire = pxRingbuffer - > pucHead ; //Reset acquire pointer to wrap around
2018-04-18 13:20:34 -04:00
}
//Item should be guaranteed to fit at this point. Set item header and copy data
2019-06-14 02:10:48 -04:00
ItemHeader_t * pxHeader = ( ItemHeader_t * ) pxRingbuffer - > pucAcquire ;
2018-04-18 13:20:34 -04:00
pxHeader - > xItemLen = xItemSize ;
pxHeader - > uxItemFlags = 0 ;
2019-06-14 02:10:48 -04:00
//hold the buffer address without touching pucWrite
uint8_t * item_address = pxRingbuffer - > pucAcquire + rbHEADER_SIZE ;
pxRingbuffer - > pucAcquire + = rbHEADER_SIZE + xAlignedItemSize ; //Advance pucAcquire past header and the item to next aligned address
//After the allocation, add some padding after the buffer and correct the flags
2018-04-18 13:20:34 -04:00
//If current remaining length can't fit a header, wrap around write pointer
2019-06-14 02:10:48 -04:00
if ( pxRingbuffer - > pucTail - pxRingbuffer - > pucAcquire < rbHEADER_SIZE ) {
pxRingbuffer - > pucAcquire = pxRingbuffer - > pucHead ; //Wrap around pucAcquire
2018-04-18 13:20:34 -04:00
}
//Check if buffer is full
2019-06-14 02:10:48 -04:00
if ( pxRingbuffer - > pucAcquire = = pxRingbuffer - > pucFree ) {
2018-04-18 13:20:34 -04:00
//Mark the buffer as full to distinguish with an empty buffer
pxRingbuffer - > uxRingbufferFlags | = rbBUFFER_FULL_FLAG ;
}
2019-06-14 02:10:48 -04:00
return item_address ;
}
static void prvSendItemDoneNoSplit ( Ringbuffer_t * pxRingbuffer , uint8_t * pucItem )
{
//Check arguments and buffer state
configASSERT ( rbCHECK_ALIGNED ( pucItem ) ) ;
configASSERT ( pucItem > = pxRingbuffer - > pucHead ) ;
configASSERT ( pucItem < = pxRingbuffer - > pucTail ) ; //Inclusive of pucTail in the case of zero length item at the very end
//Get and check header of the item
ItemHeader_t * pxCurHeader = ( ItemHeader_t * ) ( pucItem - rbHEADER_SIZE ) ;
configASSERT ( pxCurHeader - > xItemLen < = pxRingbuffer - > xMaxItemSize ) ;
configASSERT ( ( pxCurHeader - > uxItemFlags & rbITEM_DUMMY_DATA_FLAG ) = = 0 ) ; //Dummy items should never have been written
configASSERT ( ( pxCurHeader - > uxItemFlags & rbITEM_WRITTEN_FLAG ) = = 0 ) ; //Indicates item has already been written before
pxCurHeader - > uxItemFlags & = ~ rbITEM_SPLIT_FLAG ; //Clear wrap flag if set (not strictly necessary)
pxCurHeader - > uxItemFlags | = rbITEM_WRITTEN_FLAG ; //Mark as written
pxRingbuffer - > xItemsWaiting + + ;
/*
* Items might not be written in the order they were acquired . Move the
* write pointer up to the next item that has not been marked as written ( by
* written flag ) or up till the acquire pointer . When advancing the write
* pointer , items that have already been written or items with dummy data
* should be skipped over
*/
pxCurHeader = ( ItemHeader_t * ) pxRingbuffer - > pucWrite ;
//Skip over Items that have already been written or are dummy items
while ( ( ( pxCurHeader - > uxItemFlags & rbITEM_WRITTEN_FLAG ) | | ( pxCurHeader - > uxItemFlags & rbITEM_DUMMY_DATA_FLAG ) ) & & pxRingbuffer - > pucWrite ! = pxRingbuffer - > pucAcquire ) {
if ( pxCurHeader - > uxItemFlags & rbITEM_DUMMY_DATA_FLAG ) {
pxCurHeader - > uxItemFlags | = rbITEM_WRITTEN_FLAG ; //Mark as freed (not strictly necessary but adds redundancy)
pxRingbuffer - > pucWrite = pxRingbuffer - > pucHead ; //Wrap around due to dummy data
} else {
//Item with data that has already been written, advance write pointer past this item
size_t xAlignedItemSize = rbALIGN_SIZE ( pxCurHeader - > xItemLen ) ;
pxRingbuffer - > pucWrite + = xAlignedItemSize + rbHEADER_SIZE ;
//Redundancy check to ensure write pointer has not overshot buffer bounds
configASSERT ( pxRingbuffer - > pucWrite < = pxRingbuffer - > pucHead + pxRingbuffer - > xSize ) ;
}
2021-09-28 04:06:55 -04:00
//Check if pucWrite requires wrap around
2019-06-14 02:10:48 -04:00
if ( ( pxRingbuffer - > pucTail - pxRingbuffer - > pucWrite ) < rbHEADER_SIZE ) {
pxRingbuffer - > pucWrite = pxRingbuffer - > pucHead ;
}
pxCurHeader = ( ItemHeader_t * ) pxRingbuffer - > pucWrite ; //Update header to point to item
}
}
static void prvCopyItemNoSplit ( Ringbuffer_t * pxRingbuffer , const uint8_t * pucItem , size_t xItemSize )
{
uint8_t * item_addr = prvAcquireItemNoSplit ( pxRingbuffer , xItemSize ) ;
memcpy ( item_addr , pucItem , xItemSize ) ;
prvSendItemDoneNoSplit ( pxRingbuffer , item_addr ) ;
2018-04-18 13:20:34 -04:00
}
2016-10-24 09:18:02 -04:00
2018-04-18 13:20:34 -04:00
static void prvCopyItemAllowSplit ( Ringbuffer_t * pxRingbuffer , const uint8_t * pucItem , size_t xItemSize )
2016-10-24 09:18:02 -04:00
{
2018-04-18 13:20:34 -04:00
//Check arguments and buffer state
size_t xAlignedItemSize = rbALIGN_SIZE ( xItemSize ) ; //Rounded up aligned item size
2019-06-14 02:10:48 -04:00
size_t xRemLen = pxRingbuffer - > pucTail - pxRingbuffer - > pucAcquire ; //Length from pucAcquire until end of buffer
configASSERT ( rbCHECK_ALIGNED ( pxRingbuffer - > pucAcquire ) ) ; //pucAcquire is always aligned in split ring buffers
configASSERT ( pxRingbuffer - > pucAcquire > = pxRingbuffer - > pucHead & & pxRingbuffer - > pucAcquire < pxRingbuffer - > pucTail ) ; //Check write pointer is within bounds
2018-04-18 13:20:34 -04:00
configASSERT ( xRemLen > = rbHEADER_SIZE ) ; //Remaining length must be able to at least fit an item header
//Split item if necessary
if ( xRemLen < xAlignedItemSize + rbHEADER_SIZE ) {
//Write first part of the item
2019-06-14 02:10:48 -04:00
ItemHeader_t * pxFirstHeader = ( ItemHeader_t * ) pxRingbuffer - > pucAcquire ;
2018-04-18 13:20:34 -04:00
pxFirstHeader - > uxItemFlags = 0 ;
pxFirstHeader - > xItemLen = xRemLen - rbHEADER_SIZE ; //Fill remaining length with first part
2019-06-14 02:10:48 -04:00
pxRingbuffer - > pucAcquire + = rbHEADER_SIZE ; //Advance pucAcquire past header
2018-04-18 13:20:34 -04:00
xRemLen - = rbHEADER_SIZE ;
if ( xRemLen > 0 ) {
2019-06-14 02:10:48 -04:00
memcpy ( pxRingbuffer - > pucAcquire , pucItem , xRemLen ) ;
2018-04-18 13:20:34 -04:00
pxRingbuffer - > xItemsWaiting + + ;
//Update item arguments to account for data already copied
pucItem + = xRemLen ;
xItemSize - = xRemLen ;
xAlignedItemSize - = xRemLen ;
pxFirstHeader - > uxItemFlags | = rbITEM_SPLIT_FLAG ; //There must be more data
} else {
//Remaining length was only large enough to fit header
pxFirstHeader - > uxItemFlags | = rbITEM_DUMMY_DATA_FLAG ; //Item will completely be stored in 2nd part
}
2019-06-14 02:10:48 -04:00
pxRingbuffer - > pucAcquire = pxRingbuffer - > pucHead ; //Reset acquire pointer to start of buffer
2018-04-18 13:20:34 -04:00
}
//Item (whole or second part) should be guaranteed to fit at this point
2019-06-14 02:10:48 -04:00
ItemHeader_t * pxSecondHeader = ( ItemHeader_t * ) pxRingbuffer - > pucAcquire ;
2018-04-18 13:20:34 -04:00
pxSecondHeader - > xItemLen = xItemSize ;
pxSecondHeader - > uxItemFlags = 0 ;
2019-06-14 02:10:48 -04:00
pxRingbuffer - > pucAcquire + = rbHEADER_SIZE ; //Advance acquire pointer past header
memcpy ( pxRingbuffer - > pucAcquire , pucItem , xItemSize ) ;
2018-04-18 13:20:34 -04:00
pxRingbuffer - > xItemsWaiting + + ;
2019-06-14 02:10:48 -04:00
pxRingbuffer - > pucAcquire + = xAlignedItemSize ; //Advance pucAcquire past item to next aligned address
2018-04-18 13:20:34 -04:00
//If current remaining length can't fit a header, wrap around write pointer
2019-06-14 02:10:48 -04:00
if ( pxRingbuffer - > pucTail - pxRingbuffer - > pucAcquire < rbHEADER_SIZE ) {
pxRingbuffer - > pucAcquire = pxRingbuffer - > pucHead ; //Wrap around pucAcquire
2018-04-18 13:20:34 -04:00
}
//Check if buffer is full
2019-06-14 02:10:48 -04:00
if ( pxRingbuffer - > pucAcquire = = pxRingbuffer - > pucFree ) {
2018-04-18 13:20:34 -04:00
//Mark the buffer as full to distinguish with an empty buffer
pxRingbuffer - > uxRingbufferFlags | = rbBUFFER_FULL_FLAG ;
}
2019-06-14 02:10:48 -04:00
//currently the Split mode is not supported, pucWrite tracks the pucAcquire
pxRingbuffer - > pucWrite = pxRingbuffer - > pucAcquire ;
2018-04-18 13:20:34 -04:00
}
2018-03-02 17:17:32 -05:00
2018-04-18 13:20:34 -04:00
static void prvCopyItemByteBuf ( Ringbuffer_t * pxRingbuffer , const uint8_t * pucItem , size_t xItemSize )
{
//Check arguments and buffer state
2019-06-14 02:10:48 -04:00
configASSERT ( pxRingbuffer - > pucAcquire > = pxRingbuffer - > pucHead & & pxRingbuffer - > pucAcquire < pxRingbuffer - > pucTail ) ; //Check acquire pointer is within bounds
2018-04-18 13:20:34 -04:00
2019-06-14 02:10:48 -04:00
size_t xRemLen = pxRingbuffer - > pucTail - pxRingbuffer - > pucAcquire ; //Length from pucAcquire until end of buffer
2018-04-18 13:20:34 -04:00
if ( xRemLen < xItemSize ) {
//Copy as much as possible into remaining length
2019-06-14 02:10:48 -04:00
memcpy ( pxRingbuffer - > pucAcquire , pucItem , xRemLen ) ;
2018-04-18 13:20:34 -04:00
pxRingbuffer - > xItemsWaiting + = xRemLen ;
//Update item arguments to account for data already written
pucItem + = xRemLen ;
xItemSize - = xRemLen ;
2019-06-14 02:10:48 -04:00
pxRingbuffer - > pucAcquire = pxRingbuffer - > pucHead ; //Reset acquire pointer to start of buffer
2018-04-18 13:20:34 -04:00
}
//Copy all or remaining portion of the item
2019-06-14 02:10:48 -04:00
memcpy ( pxRingbuffer - > pucAcquire , pucItem , xItemSize ) ;
2018-04-18 13:20:34 -04:00
pxRingbuffer - > xItemsWaiting + = xItemSize ;
2019-06-14 02:10:48 -04:00
pxRingbuffer - > pucAcquire + = xItemSize ;
2018-04-18 13:20:34 -04:00
2019-06-14 02:10:48 -04:00
//Wrap around pucAcquire if it reaches the end
if ( pxRingbuffer - > pucAcquire = = pxRingbuffer - > pucTail ) {
pxRingbuffer - > pucAcquire = pxRingbuffer - > pucHead ;
2018-04-18 13:20:34 -04:00
}
//Check if buffer is full
2019-06-14 02:10:48 -04:00
if ( pxRingbuffer - > pucAcquire = = pxRingbuffer - > pucFree ) {
2018-04-18 13:20:34 -04:00
pxRingbuffer - > uxRingbufferFlags | = rbBUFFER_FULL_FLAG ; //Mark the buffer as full to avoid confusion with an empty buffer
2016-10-24 09:18:02 -04:00
}
2019-06-14 02:10:48 -04:00
//Currently, acquiring memory is not supported in byte mode. pucWrite tracks the pucAcquire.
pxRingbuffer - > pucWrite = pxRingbuffer - > pucAcquire ;
2018-04-18 13:20:34 -04:00
}
2016-10-24 09:18:02 -04:00
2018-04-18 13:20:34 -04:00
static BaseType_t prvCheckItemAvail ( Ringbuffer_t * pxRingbuffer )
{
if ( ( pxRingbuffer - > uxRingbufferFlags & rbBYTE_BUFFER_FLAG ) & & pxRingbuffer - > pucRead ! = pxRingbuffer - > pucFree ) {
return pdFALSE ; //Byte buffers do not allow multiple retrievals before return
}
if ( ( pxRingbuffer - > xItemsWaiting > 0 ) & & ( ( pxRingbuffer - > pucRead ! = pxRingbuffer - > pucWrite ) | | ( pxRingbuffer - > uxRingbufferFlags & rbBUFFER_FULL_FLAG ) ) ) {
return pdTRUE ; //Items/data available for retrieval
} else {
return pdFALSE ; //No items/data available for retrieval
2016-10-24 09:18:02 -04:00
}
}
2019-03-04 01:27:06 -05:00
static void * prvGetItemDefault ( Ringbuffer_t * pxRingbuffer ,
BaseType_t * pxIsSplit ,
size_t xUnusedParam ,
size_t * pxItemSize )
2016-09-28 00:43:35 -04:00
{
2018-04-18 13:20:34 -04:00
//Check arguments and buffer state
ItemHeader_t * pxHeader = ( ItemHeader_t * ) pxRingbuffer - > pucRead ;
configASSERT ( pxIsSplit ! = NULL ) ;
configASSERT ( ( pxRingbuffer - > xItemsWaiting > 0 ) & & ( ( pxRingbuffer - > pucRead ! = pxRingbuffer - > pucWrite ) | | ( pxRingbuffer - > uxRingbufferFlags & rbBUFFER_FULL_FLAG ) ) ) ; //Check there are items to be read
configASSERT ( rbCHECK_ALIGNED ( pxRingbuffer - > pucRead ) ) ; //pucRead is always aligned in split ring buffers
configASSERT ( pxRingbuffer - > pucRead > = pxRingbuffer - > pucHead & & pxRingbuffer - > pucRead < pxRingbuffer - > pucTail ) ; //Check read pointer is within bounds
configASSERT ( ( pxHeader - > xItemLen < = pxRingbuffer - > xMaxItemSize ) | | ( pxHeader - > uxItemFlags & rbITEM_DUMMY_DATA_FLAG ) ) ;
uint8_t * pcReturn ;
//Wrap around if dummy data (dummy data indicates wrap around in no-split buffers)
if ( pxHeader - > uxItemFlags & rbITEM_DUMMY_DATA_FLAG ) {
pxRingbuffer - > pucRead = pxRingbuffer - > pucHead ;
//Check for errors with the next item
pxHeader = ( ItemHeader_t * ) pxRingbuffer - > pucRead ;
configASSERT ( pxHeader - > xItemLen < = pxRingbuffer - > xMaxItemSize ) ;
2016-09-28 00:43:35 -04:00
}
2018-04-18 13:20:34 -04:00
pcReturn = pxRingbuffer - > pucRead + rbHEADER_SIZE ; //Get pointer to part of item containing data (point past the header)
if ( pxHeader - > xItemLen = = 0 ) {
//Inclusive of pucTail for special case where item of zero length just fits at the end of the buffer
configASSERT ( pcReturn > = pxRingbuffer - > pucHead & & pcReturn < = pxRingbuffer - > pucTail ) ;
} else {
2021-09-28 04:06:55 -04:00
//Exclusive of pucTail if length is larger than zero, pcReturn should never point to pucTail
2018-04-18 13:20:34 -04:00
configASSERT ( pcReturn > = pxRingbuffer - > pucHead & & pcReturn < pxRingbuffer - > pucTail ) ;
2016-10-24 09:18:02 -04:00
}
2018-04-18 13:20:34 -04:00
* pxItemSize = pxHeader - > xItemLen ; //Get length of item
pxRingbuffer - > xItemsWaiting - - ; //Update item count
* pxIsSplit = ( pxHeader - > uxItemFlags & rbITEM_SPLIT_FLAG ) ? pdTRUE : pdFALSE ;
pxRingbuffer - > pucRead + = rbHEADER_SIZE + rbALIGN_SIZE ( pxHeader - > xItemLen ) ; //Update pucRead
//Check if pucRead requires wrap around
if ( ( pxRingbuffer - > pucTail - pxRingbuffer - > pucRead ) < rbHEADER_SIZE ) {
pxRingbuffer - > pucRead = pxRingbuffer - > pucHead ;
2016-10-24 09:18:02 -04:00
}
2018-04-18 13:20:34 -04:00
return ( void * ) pcReturn ;
}
2019-03-04 01:27:06 -05:00
static void * prvGetItemByteBuf ( Ringbuffer_t * pxRingbuffer ,
BaseType_t * pxUnusedParam ,
size_t xMaxSize ,
size_t * pxItemSize )
2018-04-18 13:20:34 -04:00
{
//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
configASSERT ( pxRingbuffer - > pucRead > = pxRingbuffer - > pucHead & & pxRingbuffer - > pucRead < pxRingbuffer - > pucTail ) ; //Check read pointer is within bounds
configASSERT ( pxRingbuffer - > pucRead = = pxRingbuffer - > pucFree ) ;
uint8_t * ret = pxRingbuffer - > pucRead ;
if ( ( pxRingbuffer - > pucRead > pxRingbuffer - > pucWrite ) | | ( pxRingbuffer - > uxRingbufferFlags & rbBUFFER_FULL_FLAG ) ) { //Available data wraps around
//Return contiguous piece from read pointer until buffer tail, or xMaxSize
if ( xMaxSize = = 0 | | pxRingbuffer - > pucTail - pxRingbuffer - > pucRead < = xMaxSize ) {
//All contiguous data from read pointer to tail
* pxItemSize = pxRingbuffer - > pucTail - pxRingbuffer - > pucRead ;
pxRingbuffer - > xItemsWaiting - = pxRingbuffer - > pucTail - pxRingbuffer - > pucRead ;
pxRingbuffer - > pucRead = pxRingbuffer - > pucHead ; //Wrap around read pointer
2016-10-24 09:18:02 -04:00
} else {
2018-04-18 13:20:34 -04:00
//Return xMaxSize amount of data
* pxItemSize = xMaxSize ;
pxRingbuffer - > xItemsWaiting - = xMaxSize ;
pxRingbuffer - > pucRead + = xMaxSize ; //Advance read pointer past retrieved data
2016-10-24 09:18:02 -04:00
}
2018-04-18 13:20:34 -04:00
} else { //Available data is contiguous between read and write pointer
if ( xMaxSize = = 0 | | pxRingbuffer - > pucWrite - pxRingbuffer - > pucRead < = xMaxSize ) {
//Return all contiguous data from read to write pointer
* pxItemSize = pxRingbuffer - > pucWrite - pxRingbuffer - > pucRead ;
pxRingbuffer - > xItemsWaiting - = pxRingbuffer - > pucWrite - pxRingbuffer - > pucRead ;
pxRingbuffer - > pucRead = pxRingbuffer - > pucWrite ;
2016-10-24 09:18:02 -04:00
} else {
2018-04-18 13:20:34 -04:00
//Return xMaxSize data from read pointer
* pxItemSize = xMaxSize ;
pxRingbuffer - > xItemsWaiting - = xMaxSize ;
pxRingbuffer - > pucRead + = xMaxSize ; //Advance read pointer past retrieved data
2016-10-24 09:18:02 -04:00
}
}
2018-04-18 13:20:34 -04:00
return ( void * ) ret ;
}
static void prvReturnItemDefault ( Ringbuffer_t * pxRingbuffer , uint8_t * pucItem )
{
//Check arguments and buffer state
configASSERT ( rbCHECK_ALIGNED ( pucItem ) ) ;
configASSERT ( pucItem > = pxRingbuffer - > pucHead ) ;
configASSERT ( pucItem < = pxRingbuffer - > pucTail ) ; //Inclusive of pucTail in the case of zero length item at the very end
//Get and check header of the item
ItemHeader_t * pxCurHeader = ( ItemHeader_t * ) ( pucItem - rbHEADER_SIZE ) ;
configASSERT ( pxCurHeader - > xItemLen < = pxRingbuffer - > xMaxItemSize ) ;
configASSERT ( ( pxCurHeader - > uxItemFlags & rbITEM_DUMMY_DATA_FLAG ) = = 0 ) ; //Dummy items should never have been read
configASSERT ( ( pxCurHeader - > uxItemFlags & rbITEM_FREE_FLAG ) = = 0 ) ; //Indicates item has already been returned before
pxCurHeader - > uxItemFlags & = ~ rbITEM_SPLIT_FLAG ; //Clear wrap flag if set (not strictly necessary)
pxCurHeader - > uxItemFlags | = rbITEM_FREE_FLAG ; //Mark as free
/*
* Items might not be returned in the order they were retrieved . Move the free pointer
* up to the next item that has not been marked as free ( by free flag ) or up
* till the read pointer . When advancing the free pointer , items that have already been
* freed or items with dummy data should be skipped over
*/
pxCurHeader = ( ItemHeader_t * ) pxRingbuffer - > pucFree ;
//Skip over Items that have already been freed or are dummy items
while ( ( ( pxCurHeader - > uxItemFlags & rbITEM_FREE_FLAG ) | | ( pxCurHeader - > uxItemFlags & rbITEM_DUMMY_DATA_FLAG ) ) & & pxRingbuffer - > pucFree ! = pxRingbuffer - > pucRead ) {
if ( pxCurHeader - > uxItemFlags & rbITEM_DUMMY_DATA_FLAG ) {
pxCurHeader - > uxItemFlags | = rbITEM_FREE_FLAG ; //Mark as freed (not strictly necessary but adds redundancy)
pxRingbuffer - > pucFree = pxRingbuffer - > pucHead ; //Wrap around due to dummy data
2016-09-28 00:43:35 -04:00
} else {
2018-04-18 13:20:34 -04:00
//Item with data that has already been freed, advance free pointer past this item
size_t xAlignedItemSize = rbALIGN_SIZE ( pxCurHeader - > xItemLen ) ;
pxRingbuffer - > pucFree + = xAlignedItemSize + rbHEADER_SIZE ;
//Redundancy check to ensure free pointer has not overshot buffer bounds
configASSERT ( pxRingbuffer - > pucFree < = pxRingbuffer - > pucHead + pxRingbuffer - > xSize ) ;
2016-09-28 00:43:35 -04:00
}
2021-09-28 04:06:55 -04:00
//Check if pucFree requires wrap around
2018-04-18 13:20:34 -04:00
if ( ( pxRingbuffer - > pucTail - pxRingbuffer - > pucFree ) < rbHEADER_SIZE ) {
pxRingbuffer - > pucFree = pxRingbuffer - > pucHead ;
2016-09-28 00:43:35 -04:00
}
2018-04-18 13:20:34 -04:00
pxCurHeader = ( ItemHeader_t * ) pxRingbuffer - > pucFree ; //Update header to point to item
2016-09-28 00:43:35 -04:00
}
2018-04-18 13:20:34 -04:00
//Check if the buffer full flag should be reset
if ( pxRingbuffer - > uxRingbufferFlags & rbBUFFER_FULL_FLAG ) {
2019-06-14 02:10:48 -04:00
if ( pxRingbuffer - > pucFree ! = pxRingbuffer - > pucAcquire ) {
2018-04-18 13:20:34 -04:00
pxRingbuffer - > uxRingbufferFlags & = ~ rbBUFFER_FULL_FLAG ;
2019-06-14 02:10:48 -04:00
} else if ( pxRingbuffer - > pucFree = = pxRingbuffer - > pucAcquire & & pxRingbuffer - > pucFree = = pxRingbuffer - > pucRead ) {
2018-04-18 13:20:34 -04:00
//Special case where a full buffer is completely freed in one go
pxRingbuffer - > uxRingbufferFlags & = ~ rbBUFFER_FULL_FLAG ;
}
}
2016-10-24 09:18:02 -04:00
}
2018-04-18 13:20:34 -04:00
static void prvReturnItemByteBuf ( Ringbuffer_t * pxRingbuffer , uint8_t * pucItem )
2018-03-02 17:17:32 -05:00
{
2018-04-18 13:20:34 -04:00
//Check pointer points to address inside buffer
configASSERT ( ( uint8_t * ) pucItem > = pxRingbuffer - > pucHead ) ;
configASSERT ( ( uint8_t * ) pucItem < pxRingbuffer - > pucTail ) ;
//Free the read memory. Simply moves free pointer to read pointer as byte buffers do not allow multiple outstanding reads
pxRingbuffer - > pucFree = pxRingbuffer - > pucRead ;
//If buffer was full before, reset full flag as free pointer has moved
if ( pxRingbuffer - > uxRingbufferFlags & rbBUFFER_FULL_FLAG ) {
pxRingbuffer - > uxRingbufferFlags & = ~ rbBUFFER_FULL_FLAG ;
}
2018-03-02 17:17:32 -05:00
}
2018-04-18 13:20:34 -04:00
static size_t prvGetCurMaxSizeNoSplit ( Ringbuffer_t * pxRingbuffer )
2018-03-02 17:17:32 -05:00
{
2018-04-18 13:20:34 -04:00
BaseType_t xFreeSize ;
//Check if buffer is full
if ( pxRingbuffer - > uxRingbufferFlags & rbBUFFER_FULL_FLAG ) {
return 0 ;
}
2019-06-14 02:10:48 -04:00
if ( pxRingbuffer - > pucAcquire < pxRingbuffer - > pucFree ) {
//Free space is contiguous between pucAcquire and pucFree
xFreeSize = pxRingbuffer - > pucFree - pxRingbuffer - > pucAcquire ;
2018-04-18 13:20:34 -04:00
} else {
//Free space wraps around (or overlapped at pucHead), select largest
//contiguous free space as no-split items require contiguous space
2019-06-14 02:10:48 -04:00
size_t xSize1 = pxRingbuffer - > pucTail - pxRingbuffer - > pucAcquire ;
2018-04-18 13:20:34 -04:00
size_t xSize2 = pxRingbuffer - > pucFree - pxRingbuffer - > pucHead ;
xFreeSize = ( xSize1 > xSize2 ) ? xSize1 : xSize2 ;
}
//No-split ring buffer items need space for a header
xFreeSize - = rbHEADER_SIZE ;
2021-09-28 04:06:55 -04:00
//Check for xFreeSize < 0 before checking xFreeSize > pxRingbuffer->xMaxItemSize
//to avoid incorrect comparison operation when xFreeSize is negative
if ( xFreeSize < 0 ) {
2018-04-18 13:20:34 -04:00
//Occurs when free space is less than header size
xFreeSize = 0 ;
2021-09-28 04:06:55 -04:00
} else if ( xFreeSize > pxRingbuffer - > xMaxItemSize ) {
//Limit free size to be within bounds
xFreeSize = pxRingbuffer - > xMaxItemSize ;
2018-04-18 13:20:34 -04:00
}
return xFreeSize ;
2018-03-02 17:17:32 -05:00
}
2016-10-24 09:18:02 -04:00
2018-04-18 13:20:34 -04:00
static size_t prvGetCurMaxSizeAllowSplit ( Ringbuffer_t * pxRingbuffer )
2016-09-28 00:43:35 -04:00
{
2018-04-18 13:20:34 -04:00
BaseType_t xFreeSize ;
//Check if buffer is full
if ( pxRingbuffer - > uxRingbufferFlags & rbBUFFER_FULL_FLAG ) {
return 0 ;
}
2019-06-14 02:10:48 -04:00
if ( pxRingbuffer - > pucAcquire = = pxRingbuffer - > pucHead & & pxRingbuffer - > pucFree = = pxRingbuffer - > pucHead ) {
//Check for special case where pucAcquire and pucFree are both at pucHead
2018-04-18 13:20:34 -04:00
xFreeSize = pxRingbuffer - > xSize - rbHEADER_SIZE ;
2019-06-14 02:10:48 -04:00
} else if ( pxRingbuffer - > pucAcquire < pxRingbuffer - > pucFree ) {
//Free space is contiguous between pucAcquire and pucFree, requires single header
xFreeSize = ( pxRingbuffer - > pucFree - pxRingbuffer - > pucAcquire ) - rbHEADER_SIZE ;
2018-04-18 13:20:34 -04:00
} else {
//Free space wraps around, requires two headers
xFreeSize = ( pxRingbuffer - > pucFree - pxRingbuffer - > pucHead ) +
2019-06-14 02:10:48 -04:00
( pxRingbuffer - > pucTail - pxRingbuffer - > pucAcquire ) -
2018-04-18 13:20:34 -04:00
( rbHEADER_SIZE * 2 ) ;
}
2016-09-28 00:43:35 -04:00
2021-09-28 04:06:55 -04:00
//Check for xFreeSize < 0 before checking xFreeSize > pxRingbuffer->xMaxItemSize
//to avoid incorrect comparison operation when xFreeSize is negative
if ( xFreeSize < 0 ) {
2018-04-18 13:20:34 -04:00
xFreeSize = 0 ;
2021-09-28 04:06:55 -04:00
} else if ( xFreeSize > pxRingbuffer - > xMaxItemSize ) {
//Limit free size to be within bounds
xFreeSize = pxRingbuffer - > xMaxItemSize ;
2018-04-18 13:20:34 -04:00
}
return xFreeSize ;
}
2016-09-28 00:43:35 -04:00
2018-04-18 13:20:34 -04:00
static size_t prvGetCurMaxSizeByteBuf ( Ringbuffer_t * pxRingbuffer )
2017-11-20 08:53:25 -05:00
{
2018-04-18 13:20:34 -04:00
BaseType_t xFreeSize ;
//Check if buffer is full
if ( pxRingbuffer - > uxRingbufferFlags & rbBUFFER_FULL_FLAG ) {
return 0 ;
}
/*
* Return whatever space is available depending on relative positions of the free
2019-06-14 02:10:48 -04:00
* pointer and Acquire pointer . There is no overhead of headers in this mode
2018-04-18 13:20:34 -04:00
*/
2019-06-14 02:10:48 -04:00
xFreeSize = pxRingbuffer - > pucFree - pxRingbuffer - > pucAcquire ;
2018-04-18 13:20:34 -04:00
if ( xFreeSize < = 0 ) {
xFreeSize + = pxRingbuffer - > xSize ;
}
return xFreeSize ;
2017-11-20 08:53:25 -05:00
}
2023-02-22 23:54:06 -05:00
static BaseType_t prvSendAcquireGeneric ( Ringbuffer_t * pxRingbuffer ,
const void * pvItem ,
void * * ppvItem ,
size_t xItemSize ,
TickType_t xTicksToWait )
{
BaseType_t xReturn = pdFALSE ;
BaseType_t xExitLoop = pdFALSE ;
BaseType_t xEntryTimeSet = pdFALSE ;
BaseType_t xNotifyQueueSet = pdFALSE ;
TimeOut_t xTimeOut ;
while ( xExitLoop = = pdFALSE ) {
portENTER_CRITICAL ( & pxRingbuffer - > mux ) ;
if ( pxRingbuffer - > xCheckItemFits ( pxRingbuffer , xItemSize ) = = pdTRUE ) {
//xItemSize will fit. Copy or acquire the buffer immediately
if ( ppvItem ) {
//Acquire the buffer
* ppvItem = prvAcquireItemNoSplit ( pxRingbuffer , xItemSize ) ;
} else {
//Copy item into buffer
pxRingbuffer - > vCopyItem ( pxRingbuffer , pvItem , xItemSize ) ;
if ( pxRingbuffer - > xQueueSet ) {
//If ring buffer was added to a queue set, notify the queue set
xNotifyQueueSet = pdTRUE ;
} else {
//If a task was waiting for data to arrive on the ring buffer, unblock it immediately.
if ( listLIST_IS_EMPTY ( & pxRingbuffer - > xTasksWaitingToReceive ) = = pdFALSE ) {
if ( xTaskRemoveFromEventList ( & pxRingbuffer - > xTasksWaitingToReceive ) = = pdTRUE ) {
//The unblocked task will preempt us. Trigger a yield here.
portYIELD_WITHIN_API ( ) ;
}
}
}
}
xReturn = pdTRUE ;
xExitLoop = pdTRUE ;
goto loop_end ;
} else if ( xTicksToWait = = ( TickType_t ) 0 ) {
//No block time. Return immediately.
xExitLoop = pdTRUE ;
goto loop_end ;
} else if ( xEntryTimeSet = = pdFALSE ) {
//This is our first block. Set entry time
vTaskInternalSetTimeOutState ( & xTimeOut ) ;
xEntryTimeSet = pdTRUE ;
}
if ( xTaskCheckForTimeOut ( & xTimeOut , & xTicksToWait ) = = pdFALSE ) {
//Not timed out yet. Block the current task
vTaskPlaceOnEventList ( & pxRingbuffer - > xTasksWaitingToSend , xTicksToWait ) ;
portYIELD_WITHIN_API ( ) ;
} else {
//We have timed out
xExitLoop = pdTRUE ;
}
loop_end :
portEXIT_CRITICAL ( & pxRingbuffer - > mux ) ;
}
//Defer notifying the queue set until we are outside the loop and critical section.
if ( xNotifyQueueSet = = pdTRUE ) {
xQueueSend ( ( QueueHandle_t ) pxRingbuffer - > xQueueSet , ( QueueSetMemberHandle_t * ) & pxRingbuffer , 0 ) ;
}
return xReturn ;
}
2019-03-04 01:27:06 -05:00
static BaseType_t prvReceiveGeneric ( Ringbuffer_t * pxRingbuffer ,
void * * pvItem1 ,
void * * pvItem2 ,
size_t * xItemSize1 ,
size_t * xItemSize2 ,
size_t xMaxSize ,
TickType_t xTicksToWait )
2017-11-20 08:53:25 -05:00
{
2018-04-18 13:20:34 -04:00
BaseType_t xReturn = pdFALSE ;
2023-02-22 23:54:06 -05:00
BaseType_t xExitLoop = pdFALSE ;
BaseType_t xEntryTimeSet = pdFALSE ;
TimeOut_t xTimeOut ;
# ifdef __clang_analyzer__
// Teach clang-tidy that if NULL pointers are provided, this function will never dereference them
if ( ! pvItem1 | | ! pvItem2 | | ! xItemSize1 | | ! xItemSize2 ) {
return pdFALSE ;
}
# endif /*__clang_analyzer__ */
2018-04-18 13:20:34 -04:00
2023-02-22 23:54:06 -05:00
while ( xExitLoop = = pdFALSE ) {
2018-08-30 06:29:01 -04:00
portENTER_CRITICAL ( & pxRingbuffer - > mux ) ;
2018-04-18 13:20:34 -04:00
if ( prvCheckItemAvail ( pxRingbuffer ) = = pdTRUE ) {
2023-02-22 23:54:06 -05:00
//Item/data is available for retrieval
2022-07-27 23:15:36 -04:00
BaseType_t xIsSplit = pdFALSE ;
2018-04-18 13:20:34 -04:00
if ( pxRingbuffer - > uxRingbufferFlags & rbBYTE_BUFFER_FLAG ) {
2023-02-22 23:54:06 -05:00
//Read up to xMaxSize bytes from byte buffer
2018-04-18 13:20:34 -04:00
* pvItem1 = pxRingbuffer - > pvGetItem ( pxRingbuffer , NULL , xMaxSize , xItemSize1 ) ;
} else {
2023-02-22 23:54:06 -05:00
//Get (first) item from no-split/allow-split buffers
2018-04-18 13:20:34 -04:00
* pvItem1 = pxRingbuffer - > pvGetItem ( pxRingbuffer , & xIsSplit , 0 , xItemSize1 ) ;
}
2023-02-22 23:54:06 -05:00
//If split buffer, check for split items
if ( pxRingbuffer - > uxRingbufferFlags & rbALLOW_SPLIT_FLAG ) {
2018-04-18 13:20:34 -04:00
if ( xIsSplit = = pdTRUE ) {
* pvItem2 = pxRingbuffer - > pvGetItem ( pxRingbuffer , & xIsSplit , 0 , xItemSize2 ) ;
configASSERT ( * pvItem2 < * pvItem1 ) ; //Check wrap around has occurred
configASSERT ( xIsSplit = = pdFALSE ) ; //Second part should not have wrapped flag
} else {
* pvItem2 = NULL ;
}
}
xReturn = pdTRUE ;
2023-02-22 23:54:06 -05:00
xExitLoop = pdTRUE ;
goto loop_end ;
} else if ( xTicksToWait = = ( TickType_t ) 0 ) {
//No block time. Return immediately.
xExitLoop = pdTRUE ;
goto loop_end ;
} else if ( xEntryTimeSet = = pdFALSE ) {
//This is our first block. Set entry time
vTaskInternalSetTimeOutState ( & xTimeOut ) ;
xEntryTimeSet = pdTRUE ;
2018-04-18 13:20:34 -04:00
}
2023-02-22 23:54:06 -05:00
if ( xTaskCheckForTimeOut ( & xTimeOut , & xTicksToWait ) = = pdFALSE ) {
//Not timed out yet. Block the current task
vTaskPlaceOnEventList ( & pxRingbuffer - > xTasksWaitingToReceive , xTicksToWait ) ;
portYIELD_WITHIN_API ( ) ;
} else {
//We have timed out.
xExitLoop = pdTRUE ;
2018-04-18 13:20:34 -04:00
}
2023-02-22 23:54:06 -05:00
loop_end :
2018-08-30 06:29:01 -04:00
portEXIT_CRITICAL ( & pxRingbuffer - > mux ) ;
2018-04-18 13:20:34 -04:00
}
return xReturn ;
2017-11-20 08:53:25 -05:00
}
2019-03-04 01:27:06 -05:00
static BaseType_t prvReceiveGenericFromISR ( Ringbuffer_t * pxRingbuffer ,
void * * pvItem1 ,
void * * pvItem2 ,
size_t * xItemSize1 ,
size_t * xItemSize2 ,
size_t xMaxSize )
2017-11-20 08:53:25 -05:00
{
2018-04-18 13:20:34 -04:00
BaseType_t xReturn = pdFALSE ;
2023-02-22 23:54:06 -05:00
# ifdef __clang_analyzer__
// Teach clang-tidy that if NULL pointers are provided, this function will never dereference them
if ( ! pvItem1 | | ! pvItem2 | | ! xItemSize1 | | ! xItemSize2 ) {
return pdFALSE ;
}
# endif /*__clang_analyzer__ */
2018-04-18 13:20:34 -04:00
2018-08-30 06:29:01 -04:00
portENTER_CRITICAL_ISR ( & pxRingbuffer - > mux ) ;
2023-02-22 23:54:06 -05:00
if ( prvCheckItemAvail ( pxRingbuffer ) = = pdTRUE ) {
2022-07-27 23:15:36 -04:00
BaseType_t xIsSplit = pdFALSE ;
2018-04-18 13:20:34 -04:00
if ( pxRingbuffer - > uxRingbufferFlags & rbBYTE_BUFFER_FLAG ) {
2023-02-22 23:54:06 -05:00
//Read up to xMaxSize bytes from byte buffer
2018-04-18 13:20:34 -04:00
* pvItem1 = pxRingbuffer - > pvGetItem ( pxRingbuffer , NULL , xMaxSize , xItemSize1 ) ;
} else {
2023-02-22 23:54:06 -05:00
//Get (first) item from no-split/allow-split buffers
2018-04-18 13:20:34 -04:00
* pvItem1 = pxRingbuffer - > pvGetItem ( pxRingbuffer , & xIsSplit , 0 , xItemSize1 ) ;
}
2023-02-22 23:54:06 -05:00
//If split buffer, check for split items
if ( pxRingbuffer - > uxRingbufferFlags & rbALLOW_SPLIT_FLAG ) {
2018-04-18 13:20:34 -04:00
if ( xIsSplit = = pdTRUE ) {
* pvItem2 = pxRingbuffer - > pvGetItem ( pxRingbuffer , & xIsSplit , 0 , xItemSize2 ) ;
configASSERT ( * pvItem2 < * pvItem1 ) ; //Check wrap around has occurred
configASSERT ( xIsSplit = = pdFALSE ) ; //Second part should not have wrapped flag
} else {
* pvItem2 = NULL ;
}
}
xReturn = pdTRUE ;
2023-02-22 23:54:06 -05:00
} else {
xReturn = pdFALSE ;
2017-11-20 08:53:25 -05:00
}
2018-08-30 06:29:01 -04:00
portEXIT_CRITICAL_ISR ( & pxRingbuffer - > mux ) ;
2018-04-18 13:20:34 -04:00
return xReturn ;
2017-11-20 08:53:25 -05:00
}
2023-02-22 23:54:06 -05:00
// ------------------------------------------------ Public Functions ---------------------------------------------------
2018-04-18 13:20:34 -04:00
2019-03-04 01:27:06 -05:00
RingbufHandle_t xRingbufferCreate ( size_t xBufferSize , RingbufferType_t xBufferType )
2017-11-20 08:53:25 -05:00
{
2019-03-04 01:27:06 -05:00
configASSERT ( xBufferSize > 0 ) ;
configASSERT ( xBufferType < RINGBUF_TYPE_MAX ) ;
2018-04-18 13:20:34 -04:00
//Allocate memory
if ( xBufferType ! = RINGBUF_TYPE_BYTEBUF ) {
xBufferSize = rbALIGN_SIZE ( xBufferSize ) ; //xBufferSize is rounded up for no-split/allow-split buffers
}
2019-03-04 01:27:06 -05:00
Ringbuffer_t * pxNewRingbuffer = calloc ( 1 , sizeof ( Ringbuffer_t ) ) ;
uint8_t * pucRingbufferStorage = malloc ( xBufferSize ) ;
if ( pxNewRingbuffer = = NULL | | pucRingbufferStorage = = NULL ) {
2018-04-18 13:20:34 -04:00
goto err ;
}
2019-03-04 01:27:06 -05:00
prvInitializeNewRingbuffer ( xBufferSize , xBufferType , pxNewRingbuffer , pucRingbufferStorage ) ;
return ( RingbufHandle_t ) pxNewRingbuffer ;
2016-09-28 00:43:35 -04:00
err :
2019-03-04 01:27:06 -05:00
//An error has occurred, Free memory and return NULL
free ( pxNewRingbuffer ) ;
free ( pucRingbufferStorage ) ;
2016-09-28 00:43:35 -04:00
return NULL ;
}
2018-04-18 13:20:34 -04:00
RingbufHandle_t xRingbufferCreateNoSplit ( size_t xItemSize , size_t xItemNum )
2017-11-23 05:09:17 -05:00
{
2018-04-18 13:20:34 -04:00
return xRingbufferCreate ( ( rbALIGN_SIZE ( xItemSize ) + rbHEADER_SIZE ) * xItemNum , RINGBUF_TYPE_NOSPLIT ) ;
2017-11-23 05:09:17 -05:00
}
2019-03-04 01:27:06 -05:00
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 ;
prvInitializeNewRingbuffer ( xBufferSize , xBufferType , pxNewRingbuffer , pucRingbufferStorage ) ;
pxNewRingbuffer - > uxRingbufferFlags | = rbBUFFER_STATIC_FLAG ;
return ( RingbufHandle_t ) pxNewRingbuffer ;
}
2019-06-14 03:05:00 -04:00
BaseType_t xRingbufferSendAcquire ( RingbufHandle_t xRingbuffer , void * * ppvItem , size_t xItemSize , TickType_t xTicksToWait )
{
Ringbuffer_t * pxRingbuffer = ( Ringbuffer_t * ) xRingbuffer ;
2023-02-22 23:54:06 -05:00
//Check arguments
2019-06-14 03:05:00 -04:00
configASSERT ( pxRingbuffer ) ;
2023-02-28 02:23:24 -05:00
configASSERT ( ppvItem ! = NULL ) ;
2023-02-22 23:54:06 -05:00
configASSERT ( ( pxRingbuffer - > uxRingbufferFlags & ( rbBYTE_BUFFER_FLAG | rbALLOW_SPLIT_FLAG ) ) = = 0 ) ; //Send acquire currently only supported in NoSplit buffers
2019-06-14 03:05:00 -04:00
* ppvItem = NULL ;
if ( xItemSize > pxRingbuffer - > xMaxItemSize ) {
return pdFALSE ; //Data will never ever fit in the queue.
}
if ( ( pxRingbuffer - > uxRingbufferFlags & rbBYTE_BUFFER_FLAG ) & & xItemSize = = 0 ) {
return pdTRUE ; //Sending 0 bytes to byte buffer has no effect
}
2023-02-22 23:54:06 -05:00
return prvSendAcquireGeneric ( pxRingbuffer , NULL , ppvItem , xItemSize , xTicksToWait ) ;
2019-06-14 03:05:00 -04:00
}
BaseType_t xRingbufferSendComplete ( RingbufHandle_t xRingbuffer , void * pvItem )
{
Ringbuffer_t * pxRingbuffer = ( Ringbuffer_t * ) xRingbuffer ;
2023-02-22 23:54:06 -05:00
BaseType_t xNotifyQueueSet = pdFALSE ;
//Check arguments
2019-06-14 03:05:00 -04:00
configASSERT ( pxRingbuffer ) ;
configASSERT ( pvItem ! = NULL ) ;
configASSERT ( ( pxRingbuffer - > uxRingbufferFlags & ( rbBYTE_BUFFER_FLAG | rbALLOW_SPLIT_FLAG ) ) = = 0 ) ;
portENTER_CRITICAL ( & pxRingbuffer - > mux ) ;
prvSendItemDoneNoSplit ( pxRingbuffer , pvItem ) ;
2023-02-22 23:54:06 -05:00
if ( pxRingbuffer - > xQueueSet ) {
//If ring buffer was added to a queue set, notify the queue set
xNotifyQueueSet = pdTRUE ;
} else {
//If a task was waiting for data to arrive on the ring buffer, unblock it immediately.
if ( listLIST_IS_EMPTY ( & pxRingbuffer - > xTasksWaitingToReceive ) = = pdFALSE ) {
if ( xTaskRemoveFromEventList ( & pxRingbuffer - > xTasksWaitingToReceive ) = = pdTRUE ) {
//The unblocked task will preempt us. Trigger a yield here.
portYIELD_WITHIN_API ( ) ;
}
}
}
2019-06-14 03:05:00 -04:00
portEXIT_CRITICAL ( & pxRingbuffer - > mux ) ;
2023-02-22 23:54:06 -05:00
if ( xNotifyQueueSet = = pdTRUE ) {
xQueueSend ( ( QueueHandle_t ) pxRingbuffer - > xQueueSet , ( QueueSetMemberHandle_t * ) & pxRingbuffer , 0 ) ;
}
2019-06-14 03:05:00 -04:00
return pdTRUE ;
}
2019-03-04 01:27:06 -05:00
BaseType_t xRingbufferSend ( RingbufHandle_t xRingbuffer ,
const void * pvItem ,
size_t xItemSize ,
TickType_t xTicksToWait )
2018-04-18 13:20:34 -04:00
{
Ringbuffer_t * pxRingbuffer = ( Ringbuffer_t * ) xRingbuffer ;
2023-02-22 23:54:06 -05:00
//Check arguments
2018-04-18 13:20:34 -04:00
configASSERT ( pxRingbuffer ) ;
configASSERT ( pvItem ! = NULL | | xItemSize = = 0 ) ;
if ( xItemSize > pxRingbuffer - > xMaxItemSize ) {
return pdFALSE ; //Data will never ever fit in the queue.
}
if ( ( pxRingbuffer - > uxRingbufferFlags & rbBYTE_BUFFER_FLAG ) & & xItemSize = = 0 ) {
return pdTRUE ; //Sending 0 bytes to byte buffer has no effect
}
2023-02-22 23:54:06 -05:00
return prvSendAcquireGeneric ( pxRingbuffer , pvItem , NULL , xItemSize , xTicksToWait ) ;
2016-09-28 00:43:35 -04:00
}
2019-03-04 01:27:06 -05:00
BaseType_t xRingbufferSendFromISR ( RingbufHandle_t xRingbuffer ,
const void * pvItem ,
size_t xItemSize ,
BaseType_t * pxHigherPriorityTaskWoken )
2016-09-28 00:43:35 -04:00
{
2018-04-18 13:20:34 -04:00
Ringbuffer_t * pxRingbuffer = ( Ringbuffer_t * ) xRingbuffer ;
2023-02-22 23:54:06 -05:00
BaseType_t xNotifyQueueSet = pdFALSE ;
BaseType_t xReturn ;
//Check arguments
2018-04-18 13:20:34 -04:00
configASSERT ( pxRingbuffer ) ;
configASSERT ( pvItem ! = NULL | | xItemSize = = 0 ) ;
if ( xItemSize > pxRingbuffer - > xMaxItemSize ) {
return pdFALSE ; //Data will never ever fit in the queue.
}
if ( ( pxRingbuffer - > uxRingbufferFlags & rbBYTE_BUFFER_FLAG ) & & xItemSize = = 0 ) {
return pdTRUE ; //Sending 0 bytes to byte buffer has no effect
}
2018-08-30 06:29:01 -04:00
portENTER_CRITICAL_ISR ( & pxRingbuffer - > mux ) ;
2018-04-18 13:20:34 -04:00
if ( pxRingbuffer - > xCheckItemFits ( xRingbuffer , xItemSize ) = = pdTRUE ) {
pxRingbuffer - > vCopyItem ( xRingbuffer , pvItem , xItemSize ) ;
2023-02-22 23:54:06 -05:00
if ( pxRingbuffer - > xQueueSet ) {
//If ring buffer was added to a queue set, notify the queue set
xNotifyQueueSet = pdTRUE ;
} else {
//If a task was waiting for data to arrive on the ring buffer, unblock it immediately.
if ( listLIST_IS_EMPTY ( & pxRingbuffer - > xTasksWaitingToReceive ) = = pdFALSE ) {
if ( xTaskRemoveFromEventList ( & pxRingbuffer - > xTasksWaitingToReceive ) = = pdTRUE ) {
//The unblocked task will preempt us. Record that a context switch is required.
if ( pxHigherPriorityTaskWoken ! = NULL ) {
* pxHigherPriorityTaskWoken = pdTRUE ;
}
}
}
2018-04-18 13:20:34 -04:00
}
2023-02-22 23:54:06 -05:00
xReturn = pdTRUE ;
2018-04-18 13:20:34 -04:00
} else {
xReturn = pdFALSE ;
}
2018-08-30 06:29:01 -04:00
portEXIT_CRITICAL_ISR ( & pxRingbuffer - > mux ) ;
2023-02-28 02:23:24 -05:00
//Defer notifying the queue set until we are outside the critical section.
2023-02-22 23:54:06 -05:00
if ( xNotifyQueueSet = = pdTRUE ) {
xQueueSendFromISR ( ( QueueHandle_t ) pxRingbuffer - > xQueueSet , ( QueueSetMemberHandle_t * ) & pxRingbuffer , pxHigherPriorityTaskWoken ) ;
2018-04-18 13:20:34 -04:00
}
return xReturn ;
2016-09-28 00:43:35 -04:00
}
2018-04-18 13:20:34 -04:00
void * xRingbufferReceive ( RingbufHandle_t xRingbuffer , size_t * pxItemSize , TickType_t xTicksToWait )
2017-11-20 09:52:20 -05:00
{
2018-04-18 13:20:34 -04:00
Ringbuffer_t * pxRingbuffer = ( Ringbuffer_t * ) xRingbuffer ;
2023-02-22 23:54:06 -05:00
//Check arguments
configASSERT ( pxRingbuffer & & pxItemSize ) ;
2018-04-18 13:20:34 -04:00
//Attempt to retrieve an item
void * pvTempItem ;
2023-02-22 23:54:06 -05:00
if ( prvReceiveGeneric ( pxRingbuffer , & pvTempItem , NULL , pxItemSize , NULL , 0 , xTicksToWait ) = = pdTRUE ) {
2018-04-18 13:20:34 -04:00
return pvTempItem ;
} else {
return NULL ;
}
2017-11-20 09:52:20 -05:00
}
2018-04-18 13:20:34 -04:00
void * xRingbufferReceiveFromISR ( RingbufHandle_t xRingbuffer , size_t * pxItemSize )
2016-09-28 00:43:35 -04:00
{
2018-04-18 13:20:34 -04:00
Ringbuffer_t * pxRingbuffer = ( Ringbuffer_t * ) xRingbuffer ;
2023-02-22 23:54:06 -05:00
//Check arguments
configASSERT ( pxRingbuffer & & pxItemSize ) ;
2018-04-18 13:20:34 -04:00
//Attempt to retrieve an item
void * pvTempItem ;
2023-02-22 23:54:06 -05:00
if ( prvReceiveGenericFromISR ( pxRingbuffer , & pvTempItem , NULL , pxItemSize , NULL , 0 ) = = pdTRUE ) {
2018-04-18 13:20:34 -04:00
return pvTempItem ;
} else {
return NULL ;
}
}
2016-09-28 00:43:35 -04:00
2019-03-04 01:27:06 -05:00
BaseType_t xRingbufferReceiveSplit ( RingbufHandle_t xRingbuffer ,
void * * ppvHeadItem ,
void * * ppvTailItem ,
size_t * pxHeadItemSize ,
size_t * pxTailItemSize ,
TickType_t xTicksToWait )
2018-04-18 13:20:34 -04:00
{
Ringbuffer_t * pxRingbuffer = ( Ringbuffer_t * ) xRingbuffer ;
2023-02-22 23:54:06 -05:00
//Check arguments
configASSERT ( pxRingbuffer & & ppvHeadItem & & ppvTailItem & & pxHeadItemSize & & pxTailItemSize ) ;
2018-04-18 13:20:34 -04:00
configASSERT ( pxRingbuffer - > uxRingbufferFlags & rbALLOW_SPLIT_FLAG ) ;
2023-02-22 23:54:06 -05:00
return prvReceiveGeneric ( pxRingbuffer , ppvHeadItem , ppvTailItem , pxHeadItemSize , pxTailItemSize , 0 , xTicksToWait ) ;
2018-04-18 13:20:34 -04:00
}
2016-09-28 00:43:35 -04:00
2019-03-04 01:27:06 -05:00
BaseType_t xRingbufferReceiveSplitFromISR ( RingbufHandle_t xRingbuffer ,
void * * ppvHeadItem ,
void * * ppvTailItem ,
size_t * pxHeadItemSize ,
size_t * pxTailItemSize )
2018-04-18 13:20:34 -04:00
{
Ringbuffer_t * pxRingbuffer = ( Ringbuffer_t * ) xRingbuffer ;
2023-02-22 23:54:06 -05:00
//Check arguments
configASSERT ( pxRingbuffer & & ppvHeadItem & & ppvTailItem & & pxHeadItemSize & & pxTailItemSize ) ;
2018-04-18 13:20:34 -04:00
configASSERT ( pxRingbuffer - > uxRingbufferFlags & rbALLOW_SPLIT_FLAG ) ;
2023-02-22 23:54:06 -05:00
return prvReceiveGenericFromISR ( pxRingbuffer , ppvHeadItem , ppvTailItem , pxHeadItemSize , pxTailItemSize , 0 ) ;
2016-09-28 00:43:35 -04:00
}
2019-03-04 01:27:06 -05:00
void * xRingbufferReceiveUpTo ( RingbufHandle_t xRingbuffer ,
size_t * pxItemSize ,
TickType_t xTicksToWait ,
size_t xMaxSize )
2016-09-28 00:43:35 -04:00
{
2018-04-18 13:20:34 -04:00
Ringbuffer_t * pxRingbuffer = ( Ringbuffer_t * ) xRingbuffer ;
2023-02-22 23:54:06 -05:00
//Check arguments
configASSERT ( pxRingbuffer & & pxItemSize ) ;
2018-04-18 13:20:34 -04:00
configASSERT ( pxRingbuffer - > uxRingbufferFlags & rbBYTE_BUFFER_FLAG ) ; //This function should only be called for byte buffers
2023-02-22 23:54:06 -05:00
2018-04-18 13:20:34 -04:00
if ( xMaxSize = = 0 ) {
return NULL ;
2016-09-28 00:43:35 -04:00
}
2018-04-18 13:20:34 -04:00
//Attempt to retrieve up to xMaxSize bytes
void * pvTempItem ;
2023-02-22 23:54:06 -05:00
if ( prvReceiveGeneric ( pxRingbuffer , & pvTempItem , NULL , pxItemSize , NULL , xMaxSize , xTicksToWait ) = = pdTRUE ) {
2018-04-18 13:20:34 -04:00
return pvTempItem ;
} else {
return NULL ;
2016-09-28 00:43:35 -04:00
}
}
2018-04-18 13:20:34 -04:00
void * xRingbufferReceiveUpToFromISR ( RingbufHandle_t xRingbuffer , size_t * pxItemSize , size_t xMaxSize )
2016-09-28 00:43:35 -04:00
{
2018-04-18 13:20:34 -04:00
Ringbuffer_t * pxRingbuffer = ( Ringbuffer_t * ) xRingbuffer ;
2023-02-22 23:54:06 -05:00
//Check arguments
configASSERT ( pxRingbuffer & & pxItemSize ) ;
2018-04-18 13:20:34 -04:00
configASSERT ( pxRingbuffer - > uxRingbufferFlags & rbBYTE_BUFFER_FLAG ) ; //This function should only be called for byte buffers
2023-02-22 23:54:06 -05:00
2018-04-18 13:20:34 -04:00
if ( xMaxSize = = 0 ) {
return NULL ;
}
//Attempt to retrieve up to xMaxSize bytes
void * pvTempItem ;
2023-02-22 23:54:06 -05:00
if ( prvReceiveGenericFromISR ( pxRingbuffer , & pvTempItem , NULL , pxItemSize , NULL , xMaxSize ) = = pdTRUE ) {
2018-04-18 13:20:34 -04:00
return pvTempItem ;
} else {
return NULL ;
2016-09-28 00:43:35 -04:00
}
}
2018-04-18 13:20:34 -04:00
void vRingbufferReturnItem ( RingbufHandle_t xRingbuffer , void * pvItem )
2016-10-24 09:18:02 -04:00
{
2018-04-18 13:20:34 -04:00
Ringbuffer_t * pxRingbuffer = ( Ringbuffer_t * ) xRingbuffer ;
configASSERT ( pxRingbuffer ) ;
configASSERT ( pvItem ! = NULL ) ;
2018-08-30 06:29:01 -04:00
portENTER_CRITICAL ( & pxRingbuffer - > mux ) ;
2018-04-18 13:20:34 -04:00
pxRingbuffer - > vReturnItem ( pxRingbuffer , ( uint8_t * ) pvItem ) ;
2023-02-22 23:54:06 -05:00
//If a task was waiting for space to send, unblock it immediately.
if ( listLIST_IS_EMPTY ( & pxRingbuffer - > xTasksWaitingToSend ) = = pdFALSE ) {
if ( xTaskRemoveFromEventList ( & pxRingbuffer - > xTasksWaitingToSend ) = = pdTRUE ) {
//The unblocked task will preempt us. Trigger a yield here.
portYIELD_WITHIN_API ( ) ;
}
}
2018-08-30 06:29:01 -04:00
portEXIT_CRITICAL ( & pxRingbuffer - > mux ) ;
2016-10-24 09:18:02 -04:00
}
2018-04-18 13:20:34 -04:00
void vRingbufferReturnItemFromISR ( RingbufHandle_t xRingbuffer , void * pvItem , BaseType_t * pxHigherPriorityTaskWoken )
2016-09-28 00:43:35 -04:00
{
2018-04-18 13:20:34 -04:00
Ringbuffer_t * pxRingbuffer = ( Ringbuffer_t * ) xRingbuffer ;
configASSERT ( pxRingbuffer ) ;
configASSERT ( pvItem ! = NULL ) ;
2018-08-30 06:29:01 -04:00
portENTER_CRITICAL_ISR ( & pxRingbuffer - > mux ) ;
2018-04-18 13:20:34 -04:00
pxRingbuffer - > vReturnItem ( pxRingbuffer , ( uint8_t * ) pvItem ) ;
2023-02-22 23:54:06 -05:00
//If a task was waiting for space to send, unblock it immediately.
if ( listLIST_IS_EMPTY ( & pxRingbuffer - > xTasksWaitingToSend ) = = pdFALSE ) {
if ( xTaskRemoveFromEventList ( & pxRingbuffer - > xTasksWaitingToSend ) = = pdTRUE ) {
//The unblocked task will preempt us. Record that a context switch is required.
if ( pxHigherPriorityTaskWoken ! = NULL ) {
* pxHigherPriorityTaskWoken = pdTRUE ;
}
}
}
2018-08-30 06:29:01 -04:00
portEXIT_CRITICAL_ISR ( & pxRingbuffer - > mux ) ;
2016-10-24 09:18:02 -04:00
}
2018-04-18 13:20:34 -04:00
void vRingbufferDelete ( RingbufHandle_t xRingbuffer )
{
Ringbuffer_t * pxRingbuffer = ( Ringbuffer_t * ) xRingbuffer ;
configASSERT ( pxRingbuffer ) ;
2023-06-30 09:22:43 -04:00
//Ring buffer was not statically allocated. Free its memory.
if ( ! ( pxRingbuffer - > uxRingbufferFlags & rbBUFFER_STATIC_FLAG ) ) {
free ( pxRingbuffer - > pucHead ) ;
free ( pxRingbuffer ) ;
2018-04-18 13:20:34 -04:00
}
2016-10-24 09:18:02 -04:00
}
2018-04-18 13:20:34 -04:00
size_t xRingbufferGetMaxItemSize ( RingbufHandle_t xRingbuffer )
2016-10-24 09:18:02 -04:00
{
2018-04-18 13:20:34 -04:00
Ringbuffer_t * pxRingbuffer = ( Ringbuffer_t * ) xRingbuffer ;
configASSERT ( pxRingbuffer ) ;
return pxRingbuffer - > xMaxItemSize ;
2016-09-28 00:43:35 -04:00
}
2018-04-18 13:20:34 -04:00
size_t xRingbufferGetCurFreeSize ( RingbufHandle_t xRingbuffer )
{
Ringbuffer_t * pxRingbuffer = ( Ringbuffer_t * ) xRingbuffer ;
configASSERT ( pxRingbuffer ) ;
size_t xFreeSize ;
2018-08-30 06:29:01 -04:00
portENTER_CRITICAL ( & pxRingbuffer - > mux ) ;
2018-04-18 13:20:34 -04:00
xFreeSize = pxRingbuffer - > xGetCurMaxSize ( pxRingbuffer ) ;
2018-08-30 06:29:01 -04:00
portEXIT_CRITICAL ( & pxRingbuffer - > mux ) ;
2018-04-18 13:20:34 -04:00
return xFreeSize ;
}
2016-09-28 00:43:35 -04:00
2018-04-18 13:20:34 -04:00
BaseType_t xRingbufferAddToQueueSetRead ( RingbufHandle_t xRingbuffer , QueueSetHandle_t xQueueSet )
2016-09-28 00:43:35 -04:00
{
2018-04-18 13:20:34 -04:00
Ringbuffer_t * pxRingbuffer = ( Ringbuffer_t * ) xRingbuffer ;
BaseType_t xReturn ;
2023-02-22 23:54:06 -05:00
configASSERT ( pxRingbuffer & & xQueueSet ) ;
2018-08-30 06:29:01 -04:00
portENTER_CRITICAL ( & pxRingbuffer - > mux ) ;
2023-02-22 23:54:06 -05:00
if ( pxRingbuffer - > xQueueSet ! = NULL | | prvCheckItemAvail ( pxRingbuffer ) = = pdTRUE ) {
/*
- Cannot add ring buffer to more than one queue set
- It is dangerous to add a ring buffer to a queue set if the ring buffer currently has data to be read .
*/
xReturn = pdFALSE ;
} else {
//Add ring buffer to queue set
pxRingbuffer - > xQueueSet = xQueueSet ;
xReturn = pdTRUE ;
2018-04-18 13:20:34 -04:00
}
2018-08-30 06:29:01 -04:00
portEXIT_CRITICAL ( & pxRingbuffer - > mux ) ;
2016-09-28 00:43:35 -04:00
2023-02-22 23:54:06 -05:00
return xReturn ;
2018-04-18 13:20:34 -04:00
}
2016-09-28 00:43:35 -04:00
2018-04-18 13:20:34 -04:00
BaseType_t xRingbufferRemoveFromQueueSetRead ( RingbufHandle_t xRingbuffer , QueueSetHandle_t xQueueSet )
2016-09-28 00:43:35 -04:00
{
2018-04-18 13:20:34 -04:00
Ringbuffer_t * pxRingbuffer = ( Ringbuffer_t * ) xRingbuffer ;
BaseType_t xReturn ;
2023-02-22 23:54:06 -05:00
configASSERT ( pxRingbuffer & & xQueueSet ) ;
2018-08-30 06:29:01 -04:00
portENTER_CRITICAL ( & pxRingbuffer - > mux ) ;
2023-02-22 23:54:06 -05:00
if ( pxRingbuffer - > xQueueSet ! = xQueueSet | | prvCheckItemAvail ( pxRingbuffer ) = = pdTRUE ) {
/*
- Ring buffer was never added to this queue set
- It is dangerous to remove a ring buffer from a queue set if the ring buffer currently has data to be read .
*/
xReturn = pdFALSE ;
} else {
//Remove ring buffer from queue set
pxRingbuffer - > xQueueSet = NULL ;
xReturn = pdTRUE ;
2018-04-18 13:20:34 -04:00
}
2018-08-30 06:29:01 -04:00
portEXIT_CRITICAL ( & pxRingbuffer - > mux ) ;
2023-02-22 23:54:06 -05:00
2018-04-18 13:20:34 -04:00
return xReturn ;
2016-09-28 00:43:35 -04:00
}
2019-03-04 01:27:06 -05:00
void vRingbufferGetInfo ( RingbufHandle_t xRingbuffer ,
UBaseType_t * uxFree ,
UBaseType_t * uxRead ,
UBaseType_t * uxWrite ,
2019-06-14 02:10:48 -04:00
UBaseType_t * uxAcquire ,
2019-03-04 01:27:06 -05:00
UBaseType_t * uxItemsWaiting )
2018-04-18 13:20:34 -04:00
{
Ringbuffer_t * pxRingbuffer = ( Ringbuffer_t * ) xRingbuffer ;
configASSERT ( pxRingbuffer ) ;
2016-09-28 00:43:35 -04:00
2018-08-30 06:29:01 -04:00
portENTER_CRITICAL ( & pxRingbuffer - > mux ) ;
2018-04-18 13:20:34 -04:00
if ( uxFree ! = NULL ) {
* uxFree = ( UBaseType_t ) ( pxRingbuffer - > pucFree - pxRingbuffer - > pucHead ) ;
}
if ( uxRead ! = NULL ) {
* uxRead = ( UBaseType_t ) ( pxRingbuffer - > pucRead - pxRingbuffer - > pucHead ) ;
}
if ( uxWrite ! = NULL ) {
* uxWrite = ( UBaseType_t ) ( pxRingbuffer - > pucWrite - pxRingbuffer - > pucHead ) ;
}
2019-06-14 02:10:48 -04:00
if ( uxAcquire ! = NULL ) {
* uxAcquire = ( UBaseType_t ) ( pxRingbuffer - > pucAcquire - pxRingbuffer - > pucHead ) ;
}
2018-04-18 13:20:34 -04:00
if ( uxItemsWaiting ! = NULL ) {
* uxItemsWaiting = ( UBaseType_t ) ( pxRingbuffer - > xItemsWaiting ) ;
}
2018-08-30 06:29:01 -04:00
portEXIT_CRITICAL ( & pxRingbuffer - > mux ) ;
2018-04-18 13:20:34 -04:00
}
void xRingbufferPrintInfo ( RingbufHandle_t xRingbuffer )
2016-09-28 00:43:35 -04:00
{
2018-04-18 13:20:34 -04:00
Ringbuffer_t * pxRingbuffer = ( Ringbuffer_t * ) xRingbuffer ;
configASSERT ( pxRingbuffer ) ;
2019-06-14 02:10:48 -04:00
printf ( " Rb size:%d \t free: %d \t rptr: %d \t freeptr: %d \t wptr: %d, aptr: %d \n " ,
2018-04-18 13:20:34 -04:00
pxRingbuffer - > xSize , prvGetFreeSize ( pxRingbuffer ) ,
pxRingbuffer - > pucRead - pxRingbuffer - > pucHead ,
pxRingbuffer - > pucFree - pxRingbuffer - > pucHead ,
2019-06-14 02:10:48 -04:00
pxRingbuffer - > pucWrite - pxRingbuffer - > pucHead ,
pxRingbuffer - > pucAcquire - pxRingbuffer - > pucHead ) ;
2016-09-28 00:43:35 -04:00
}
2023-06-24 09:30:53 -04:00
BaseType_t xRingbufferGetStaticBuffer ( RingbufHandle_t xRingbuffer , uint8_t * * ppucRingbufferStorage , StaticRingbuffer_t * * ppxStaticRingbuffer )
{
Ringbuffer_t * pxRingbuffer = ( Ringbuffer_t * ) xRingbuffer ;
BaseType_t xReturn ;
configASSERT ( pxRingbuffer & & ppucRingbufferStorage & & ppxStaticRingbuffer ) ;
if ( pxRingbuffer - > uxRingbufferFlags & rbBUFFER_STATIC_FLAG ) {
* ppucRingbufferStorage = pxRingbuffer - > pucHead ;
* ppxStaticRingbuffer = ( StaticRingbuffer_t * ) pxRingbuffer ;
xReturn = pdTRUE ;
} else {
xReturn = pdFALSE ;
}
return xReturn ;
}
RingbufHandle_t xRingbufferCreateWithCaps ( size_t xBufferSize , RingbufferType_t xBufferType , UBaseType_t uxMemoryCaps )
{
RingbufHandle_t xRingbuffer ;
StaticRingbuffer_t * pxStaticRingbuffer ;
uint8_t * pucRingbufferStorage ;
pxStaticRingbuffer = heap_caps_malloc ( sizeof ( StaticRingbuffer_t ) , ( uint32_t ) uxMemoryCaps ) ;
pucRingbufferStorage = heap_caps_malloc ( xBufferSize , ( uint32_t ) uxMemoryCaps ) ;
if ( pxStaticRingbuffer = = NULL | | pucRingbufferStorage = = NULL ) {
goto err ;
}
// Create the ring buffer using static creation API
xRingbuffer = xRingbufferCreateStatic ( xBufferSize , xBufferType , pucRingbufferStorage , pxStaticRingbuffer ) ;
if ( xRingbuffer = = NULL ) {
goto err ;
}
return xRingbuffer ;
err :
heap_caps_free ( pxStaticRingbuffer ) ;
heap_caps_free ( pucRingbufferStorage ) ;
return NULL ;
}
void vRingbufferDeleteWithCaps ( RingbufHandle_t xRingbuffer )
{
BaseType_t xResult ;
StaticRingbuffer_t * pxStaticRingbuffer = NULL ;
uint8_t * pucRingbufferStorage = NULL ;
// Retrieve the buffers used to create the ring buffer before deleting it
xResult = xRingbufferGetStaticBuffer ( xRingbuffer , & pucRingbufferStorage , & pxStaticRingbuffer ) ;
configASSERT ( xResult = = pdTRUE ) ;
// Delete the ring buffer
vRingbufferDelete ( xRingbuffer ) ;
// Free the memory buffers
heap_caps_free ( pxStaticRingbuffer ) ;
heap_caps_free ( pucRingbufferStorage ) ;
}