2021-10-17 23:58:00 -04:00
/*
* SPDX - FileCopyrightText : 2015 - 2021 Espressif Systems ( Shanghai ) CO LTD
*
* 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"
# include "freertos/task.h"
# include "freertos/semphr.h"
# include "freertos/ringbuf.h"
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
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
2019-03-04 01:27:06 -05:00
//Static allocation related
# define rbGET_TX_SEM_HANDLE( pxRingbuffer ) ( (SemaphoreHandle_t) &(pxRingbuffer->xTransSemStatic) )
# define rbGET_RX_SEM_HANDLE( pxRingbuffer ) ( (SemaphoreHandle_t) &(pxRingbuffer->xRecvSemStatic) )
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
2019-03-04 01:27:06 -05:00
/*
* 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 .
*/
StaticSemaphore_t xTransSemStatic ;
StaticSemaphore_t xRecvSemStatic ;
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 " ) ;
2023-06-22 07:56:29 -04:00
2016-09-28 00:43:35 -04:00
/*
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
2018-04-18 13:20:34 -04:00
would need to set the maximum to the maximum amount of times a null - byte unit first in the buffer ,
2016-09-28 00:43:35 -04:00
which is quite high and so would waste a fair amount of memory .
*/
2019-03-04 01:27:06 -05:00
/* --------------------------- Static Declarations -------------------------- */
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 ) ;
/**
* 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 .
*/
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
//Generic function used to retrieve an item/data from ring buffers in an ISR
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 ) ;
/* --------------------------- 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 ;
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 ;
}
xSemaphoreGive ( rbGET_TX_SEM_HANDLE ( pxNewRingbuffer ) ) ;
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 ) ) ) {
2024-09-16 07:10:42 -04:00
// If the ring buffer is a no-split buffer, the read pointer must point to an item that has been written to.
if ( ( pxRingbuffer - > uxRingbufferFlags & ( rbBYTE_BUFFER_FLAG | rbALLOW_SPLIT_FLAG ) ) = = 0 ) {
ItemHeader_t * pxHeader = ( ItemHeader_t * ) pxRingbuffer - > pucRead ;
if ( ( pxHeader - > uxItemFlags & rbITEM_WRITTEN_FLAG ) = = 0 ) {
return pdFALSE ;
}
}
2018-04-18 13:20:34 -04:00
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
}
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 ;
BaseType_t xReturnSemaphore = pdFALSE ;
TickType_t xTicksEnd = xTaskGetTickCount ( ) + xTicksToWait ;
TickType_t xTicksRemaining = xTicksToWait ;
while ( xTicksRemaining < = xTicksToWait ) { //xTicksToWait will underflow once xTaskGetTickCount() > ticks_end
//Block until more free space becomes available or timeout
2019-03-04 01:27:06 -05:00
if ( xSemaphoreTake ( rbGET_RX_SEM_HANDLE ( pxRingbuffer ) , xTicksRemaining ) ! = pdTRUE ) {
2018-04-18 13:20:34 -04:00
xReturn = pdFALSE ; //Timed out attempting to get semaphore
break ;
}
//Semaphore obtained, check if item can be retrieved
2018-08-30 06:29:01 -04:00
portENTER_CRITICAL ( & pxRingbuffer - > mux ) ;
2018-04-18 13:20:34 -04:00
if ( prvCheckItemAvail ( pxRingbuffer ) = = pdTRUE ) {
//Item 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 ) {
//Second argument (pxIsSplit) is unused for byte buffers
* pvItem1 = pxRingbuffer - > pvGetItem ( pxRingbuffer , NULL , xMaxSize , xItemSize1 ) ;
} else {
//Third argument (xMaxSize) is unused for no-split/allow-split buffers
* pvItem1 = pxRingbuffer - > pvGetItem ( pxRingbuffer , & xIsSplit , 0 , xItemSize1 ) ;
}
//Check for item split if configured to do so
if ( ( pxRingbuffer - > uxRingbufferFlags & rbALLOW_SPLIT_FLAG ) & & ( pvItem2 ! = NULL ) & & ( xItemSize2 ! = NULL ) ) {
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 ;
if ( pxRingbuffer - > xItemsWaiting > 0 ) {
xReturnSemaphore = pdTRUE ;
}
2018-08-30 06:29:01 -04:00
portEXIT_CRITICAL ( & pxRingbuffer - > mux ) ;
2018-04-18 13:20:34 -04:00
break ;
}
//No item available for retrieval, adjust ticks and take the semaphore again
if ( xTicksToWait ! = portMAX_DELAY ) {
xTicksRemaining = xTicksEnd - xTaskGetTickCount ( ) ;
}
2018-08-30 06:29:01 -04:00
portEXIT_CRITICAL ( & pxRingbuffer - > mux ) ;
2018-04-18 13:20:34 -04:00
/*
* Gap between critical section and re - acquiring of the semaphore . If
* semaphore is given now , priority inversion might occur ( see docs )
*/
}
if ( xReturnSemaphore = = pdTRUE ) {
2019-03-04 01:27:06 -05:00
xSemaphoreGive ( rbGET_RX_SEM_HANDLE ( pxRingbuffer ) ) ; //Give semaphore back so other tasks can retrieve
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 ;
BaseType_t xReturnSemaphore = pdFALSE ;
2018-08-30 06:29:01 -04:00
portENTER_CRITICAL_ISR ( & pxRingbuffer - > mux ) ;
2018-04-18 13:20:34 -04: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 ) {
//Second argument (pxIsSplit) is unused for byte buffers
* pvItem1 = pxRingbuffer - > pvGetItem ( pxRingbuffer , NULL , xMaxSize , xItemSize1 ) ;
} else {
//Third argument (xMaxSize) is unused for no-split/allow-split buffers
* pvItem1 = pxRingbuffer - > pvGetItem ( pxRingbuffer , & xIsSplit , 0 , xItemSize1 ) ;
}
//Check for item split if configured to do so
if ( ( pxRingbuffer - > uxRingbufferFlags & rbALLOW_SPLIT_FLAG ) & & pvItem2 ! = NULL & & xItemSize2 ! = NULL ) {
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 ;
if ( pxRingbuffer - > xItemsWaiting > 0 ) {
xReturnSemaphore = pdTRUE ;
}
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
if ( xReturnSemaphore = = pdTRUE ) {
2019-03-04 01:27:06 -05:00
xSemaphoreGiveFromISR ( rbGET_RX_SEM_HANDLE ( pxRingbuffer ) , NULL ) ; //Give semaphore back so other tasks can retrieve
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
/* --------------------------- Public Definitions --------------------------- */
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
//Initialize Semaphores
//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 ) ) ;
2018-04-18 13:20:34 -04:00
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 ;
xSemaphoreCreateBinaryStatic ( & ( pxNewRingbuffer - > xTransSemStatic ) ) ;
xSemaphoreCreateBinaryStatic ( & ( pxNewRingbuffer - > xRecvSemStatic ) ) ;
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 )
{
//Check arguments
Ringbuffer_t * pxRingbuffer = ( Ringbuffer_t * ) xRingbuffer ;
configASSERT ( pxRingbuffer ) ;
configASSERT ( ppvItem ! = NULL | | xItemSize = = 0 ) ;
//currently only supported in NoSplit buffers
configASSERT ( ( pxRingbuffer - > uxRingbufferFlags & ( rbBYTE_BUFFER_FLAG | rbALLOW_SPLIT_FLAG ) ) = = 0 ) ;
* ppvItem = NULL ;
if ( xItemSize > pxRingbuffer - > xMaxItemSize ) {
return pdFALSE ; //Data will never ever fit in the queue.
}
//Attempt to send an item
BaseType_t xReturn = pdFALSE ;
BaseType_t xReturnSemaphore = pdFALSE ;
TickType_t xTicksEnd = xTaskGetTickCount ( ) + xTicksToWait ;
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 ( rbGET_TX_SEM_HANDLE ( pxRingbuffer ) , xTicksRemaining ) ! = pdTRUE ) {
xReturn = pdFALSE ;
break ;
}
//Semaphore obtained, check if item can fit
portENTER_CRITICAL ( & pxRingbuffer - > mux ) ;
if ( pxRingbuffer - > xCheckItemFits ( pxRingbuffer , xItemSize ) = = pdTRUE ) {
//Item will fit, copy item
* ppvItem = prvAcquireItemNoSplit ( pxRingbuffer , xItemSize ) ;
xReturn = pdTRUE ;
//Check if the free semaphore should be returned to allow other tasks to send
if ( prvGetFreeSize ( pxRingbuffer ) > 0 ) {
xReturnSemaphore = pdTRUE ;
}
portEXIT_CRITICAL ( & pxRingbuffer - > mux ) ;
break ;
}
//Item doesn't fit, adjust ticks and take the semaphore again
if ( xTicksToWait ! = portMAX_DELAY ) {
xTicksRemaining = xTicksEnd - xTaskGetTickCount ( ) ;
}
portEXIT_CRITICAL ( & pxRingbuffer - > mux ) ;
/*
* Gap between critical section and re - acquiring of the semaphore . If
* semaphore is given now , priority inversion might occur ( see docs )
*/
}
if ( xReturnSemaphore = = pdTRUE ) {
xSemaphoreGive ( rbGET_TX_SEM_HANDLE ( pxRingbuffer ) ) ; //Give back semaphore so other tasks can acquire
}
return xReturn ;
}
BaseType_t xRingbufferSendComplete ( RingbufHandle_t xRingbuffer , void * pvItem )
{
//Check arguments
Ringbuffer_t * pxRingbuffer = ( Ringbuffer_t * ) xRingbuffer ;
configASSERT ( pxRingbuffer ) ;
configASSERT ( pvItem ! = NULL ) ;
configASSERT ( ( pxRingbuffer - > uxRingbufferFlags & ( rbBYTE_BUFFER_FLAG | rbALLOW_SPLIT_FLAG ) ) = = 0 ) ;
portENTER_CRITICAL ( & pxRingbuffer - > mux ) ;
prvSendItemDoneNoSplit ( pxRingbuffer , pvItem ) ;
portEXIT_CRITICAL ( & pxRingbuffer - > mux ) ;
xSemaphoreGive ( rbGET_RX_SEM_HANDLE ( pxRingbuffer ) ) ;
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
{
//Check arguments
Ringbuffer_t * pxRingbuffer = ( Ringbuffer_t * ) xRingbuffer ;
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
}
//Attempt to send an item
BaseType_t xReturn = pdFALSE ;
BaseType_t xReturnSemaphore = pdFALSE ;
TickType_t xTicksEnd = xTaskGetTickCount ( ) + xTicksToWait ;
TickType_t xTicksRemaining = xTicksToWait ;
while ( xTicksRemaining < = xTicksToWait ) { //xTicksToWait will underflow once xTaskGetTickCount() > ticks_end
//Block until more free space becomes available or timeout
2019-03-04 01:27:06 -05:00
if ( xSemaphoreTake ( rbGET_TX_SEM_HANDLE ( pxRingbuffer ) , xTicksRemaining ) ! = pdTRUE ) {
2018-04-18 13:20:34 -04:00
xReturn = pdFALSE ;
break ;
}
//Semaphore obtained, check if item can fit
2018-08-30 06:29:01 -04:00
portENTER_CRITICAL ( & pxRingbuffer - > mux ) ;
2018-04-18 13:20:34 -04:00
if ( pxRingbuffer - > xCheckItemFits ( pxRingbuffer , xItemSize ) = = pdTRUE ) {
//Item will fit, copy item
pxRingbuffer - > vCopyItem ( pxRingbuffer , pvItem , xItemSize ) ;
xReturn = pdTRUE ;
//Check if the free semaphore should be returned to allow other tasks to send
if ( prvGetFreeSize ( pxRingbuffer ) > 0 ) {
xReturnSemaphore = pdTRUE ;
}
2018-08-30 06:29:01 -04:00
portEXIT_CRITICAL ( & pxRingbuffer - > mux ) ;
2018-04-18 13:20:34 -04:00
break ;
}
//Item doesn't fit, adjust ticks and take the semaphore again
if ( xTicksToWait ! = portMAX_DELAY ) {
xTicksRemaining = xTicksEnd - xTaskGetTickCount ( ) ;
}
2018-08-30 06:29:01 -04:00
portEXIT_CRITICAL ( & pxRingbuffer - > mux ) ;
2018-04-18 13:20:34 -04:00
/*
* Gap between critical section and re - acquiring of the semaphore . If
* semaphore is given now , priority inversion might occur ( see docs )
*/
}
2021-10-17 23:58:00 -04:00
if ( xReturnSemaphore = = pdTRUE ) {
xSemaphoreGive ( rbGET_TX_SEM_HANDLE ( pxRingbuffer ) ) ; //Give back semaphore so other tasks can send
}
2018-04-18 13:20:34 -04:00
if ( xReturn = = pdTRUE ) {
//Indicate item was successfully sent
2019-03-04 01:27:06 -05:00
xSemaphoreGive ( rbGET_RX_SEM_HANDLE ( pxRingbuffer ) ) ;
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
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
//Check arguments
Ringbuffer_t * pxRingbuffer = ( Ringbuffer_t * ) xRingbuffer ;
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
}
//Attempt to send an item
BaseType_t xReturn ;
BaseType_t xReturnSemaphore = pdFALSE ;
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 ) ;
xReturn = pdTRUE ;
//Check if the free semaphore should be returned to allow other tasks to send
if ( prvGetFreeSize ( pxRingbuffer ) > 0 ) {
xReturnSemaphore = pdTRUE ;
}
} else {
xReturn = pdFALSE ;
}
2018-08-30 06:29:01 -04:00
portEXIT_CRITICAL_ISR ( & pxRingbuffer - > mux ) ;
2018-04-18 13:20:34 -04:00
2021-10-17 23:58:00 -04:00
if ( xReturnSemaphore = = pdTRUE ) {
xSemaphoreGiveFromISR ( rbGET_TX_SEM_HANDLE ( pxRingbuffer ) , pxHigherPriorityTaskWoken ) ; //Give back semaphore so other tasks can send
}
2018-04-18 13:20:34 -04:00
if ( xReturn = = pdTRUE ) {
//Indicate item was successfully sent
2019-03-04 01:27:06 -05:00
xSemaphoreGiveFromISR ( rbGET_RX_SEM_HANDLE ( 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
//Check arguments
Ringbuffer_t * pxRingbuffer = ( Ringbuffer_t * ) xRingbuffer ;
configASSERT ( pxRingbuffer ) ;
//Attempt to retrieve an item
void * pvTempItem ;
size_t xTempSize ;
if ( prvReceiveGeneric ( pxRingbuffer , & pvTempItem , NULL , & xTempSize , NULL , 0 , xTicksToWait ) = = pdTRUE ) {
if ( pxItemSize ! = NULL ) {
* pxItemSize = xTempSize ;
}
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
//Check arguments
Ringbuffer_t * pxRingbuffer = ( Ringbuffer_t * ) xRingbuffer ;
configASSERT ( pxRingbuffer ) ;
//Attempt to retrieve an item
void * pvTempItem ;
size_t xTempSize ;
if ( prvReceiveGenericFromISR ( pxRingbuffer , & pvTempItem , NULL , & xTempSize , NULL , 0 ) = = pdTRUE ) {
if ( pxItemSize ! = NULL ) {
* pxItemSize = xTempSize ;
}
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
{
//Check arguments
Ringbuffer_t * pxRingbuffer = ( Ringbuffer_t * ) xRingbuffer ;
configASSERT ( pxRingbuffer ) ;
configASSERT ( pxRingbuffer - > uxRingbufferFlags & rbALLOW_SPLIT_FLAG ) ;
configASSERT ( ppvHeadItem ! = NULL & & ppvTailItem ! = NULL ) ;
//Attempt to retrieve multiple items
void * pvTempHeadItem , * pvTempTailItem ;
size_t xTempHeadSize , xTempTailSize ;
if ( prvReceiveGeneric ( pxRingbuffer , & pvTempHeadItem , & pvTempTailItem , & xTempHeadSize , & xTempTailSize , 0 , xTicksToWait ) = = pdTRUE ) {
//At least one item was retrieved
* ppvHeadItem = pvTempHeadItem ;
if ( pxHeadItemSize ! = NULL ) {
* pxHeadItemSize = xTempHeadSize ;
}
//Check to see if a second item was also retrieved
if ( pvTempTailItem ! = NULL ) {
* ppvTailItem = pvTempTailItem ;
if ( pxTailItemSize ! = NULL ) {
* pxTailItemSize = xTempTailSize ;
}
} else {
* ppvTailItem = NULL ;
}
return pdTRUE ;
} else {
//No items retrieved
* ppvHeadItem = NULL ;
* ppvTailItem = NULL ;
2016-09-28 00:43:35 -04:00
return pdFALSE ;
}
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
{
//Check arguments
Ringbuffer_t * pxRingbuffer = ( Ringbuffer_t * ) xRingbuffer ;
configASSERT ( pxRingbuffer ) ;
configASSERT ( pxRingbuffer - > uxRingbufferFlags & rbALLOW_SPLIT_FLAG ) ;
configASSERT ( ppvHeadItem ! = NULL & & ppvTailItem ! = NULL ) ;
//Attempt to retrieve multiple items
2018-12-24 06:37:09 -05:00
void * pvTempHeadItem = NULL , * pvTempTailItem = NULL ;
2018-04-18 13:20:34 -04:00
size_t xTempHeadSize , xTempTailSize ;
if ( prvReceiveGenericFromISR ( pxRingbuffer , & pvTempHeadItem , & pvTempTailItem , & xTempHeadSize , & xTempTailSize , 0 ) = = pdTRUE ) {
//At least one item was received
* ppvHeadItem = pvTempHeadItem ;
if ( pxHeadItemSize ! = NULL ) {
* pxHeadItemSize = xTempHeadSize ;
}
//Check to see if a second item was also retrieved
if ( pvTempTailItem ! = NULL ) {
* ppvTailItem = pvTempTailItem ;
if ( pxTailItemSize ! = NULL ) {
* pxTailItemSize = xTempTailSize ;
2016-09-28 00:43:35 -04:00
}
2018-04-18 13:20:34 -04:00
} else {
* ppvTailItem = NULL ;
}
return pdTRUE ;
} else {
* ppvHeadItem = NULL ;
* ppvTailItem = NULL ;
return pdFALSE ;
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
//Check arguments
Ringbuffer_t * pxRingbuffer = ( Ringbuffer_t * ) xRingbuffer ;
configASSERT ( pxRingbuffer ) ;
configASSERT ( pxRingbuffer - > uxRingbufferFlags & rbBYTE_BUFFER_FLAG ) ; //This function should only be called for byte buffers
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 ;
size_t xTempSize ;
if ( prvReceiveGeneric ( pxRingbuffer , & pvTempItem , NULL , & xTempSize , NULL , xMaxSize , xTicksToWait ) = = pdTRUE ) {
if ( pxItemSize ! = NULL ) {
* pxItemSize = xTempSize ;
}
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
//Check arguments
Ringbuffer_t * pxRingbuffer = ( Ringbuffer_t * ) xRingbuffer ;
configASSERT ( pxRingbuffer ) ;
configASSERT ( pxRingbuffer - > uxRingbufferFlags & rbBYTE_BUFFER_FLAG ) ; //This function should only be called for byte buffers
if ( xMaxSize = = 0 ) {
return NULL ;
}
//Attempt to retrieve up to xMaxSize bytes
void * pvTempItem ;
size_t xTempSize ;
if ( prvReceiveGenericFromISR ( pxRingbuffer , & pvTempItem , NULL , & xTempSize , NULL , xMaxSize ) = = pdTRUE ) {
if ( pxItemSize ! = NULL ) {
* pxItemSize = xTempSize ;
2016-09-28 00:43:35 -04:00
}
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 ) ;
2018-08-30 06:29:01 -04:00
portEXIT_CRITICAL ( & pxRingbuffer - > mux ) ;
2019-03-04 01:27:06 -05:00
xSemaphoreGive ( rbGET_TX_SEM_HANDLE ( pxRingbuffer ) ) ;
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 ) ;
2018-08-30 06:29:01 -04:00
portEXIT_CRITICAL_ISR ( & pxRingbuffer - > mux ) ;
2019-03-04 01:27:06 -05:00
xSemaphoreGiveFromISR ( rbGET_TX_SEM_HANDLE ( pxRingbuffer ) , pxHigherPriorityTaskWoken ) ;
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 ) ;
2019-03-04 01:27:06 -05:00
vSemaphoreDelete ( rbGET_TX_SEM_HANDLE ( pxRingbuffer ) ) ;
vSemaphoreDelete ( rbGET_RX_SEM_HANDLE ( pxRingbuffer ) ) ;
if ( pxRingbuffer - > uxRingbufferFlags & rbBUFFER_STATIC_FLAG ) {
//Ring buffer was statically allocated, no need to free
return ;
2018-04-18 13:20:34 -04:00
}
2023-06-22 07:56:29 -04:00
2019-03-04 01:27:06 -05:00
free ( pxRingbuffer - > pucHead ) ;
2018-04-18 13:20:34 -04:00
free ( pxRingbuffer ) ;
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 ;
configASSERT ( pxRingbuffer ) ;
BaseType_t xReturn ;
2018-08-30 06:29:01 -04:00
portENTER_CRITICAL ( & pxRingbuffer - > mux ) ;
2018-04-18 13:20:34 -04:00
//Cannot add semaphore to queue set if semaphore is not empty. Temporarily hold semaphore
2022-08-05 04:19:47 -04:00
BaseType_t result = xSemaphoreTake ( rbGET_RX_SEM_HANDLE ( pxRingbuffer ) , 0 ) ;
2019-03-04 01:27:06 -05:00
xReturn = xQueueAddToSet ( rbGET_RX_SEM_HANDLE ( pxRingbuffer ) , xQueueSet ) ;
2022-08-05 04:19:47 -04:00
if ( result = = pdTRUE ) {
2018-04-18 13:20:34 -04:00
//Return semaphore if temporarily held
2022-08-05 04:19:47 -04:00
result = xSemaphoreGive ( rbGET_RX_SEM_HANDLE ( pxRingbuffer ) ) ;
configASSERT ( result = = pdTRUE ) ;
2018-04-18 13:20:34 -04:00
}
2018-08-30 06:29:01 -04:00
portEXIT_CRITICAL ( & pxRingbuffer - > mux ) ;
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
BaseType_t xRingbufferCanRead ( RingbufHandle_t xRingbuffer , QueueSetMemberHandle_t xMember )
{
//Check if the selected queue set member is the ring buffer's read semaphore
Ringbuffer_t * pxRingbuffer = ( Ringbuffer_t * ) xRingbuffer ;
configASSERT ( pxRingbuffer ) ;
2019-03-04 01:27:06 -05:00
return ( rbGET_RX_SEM_HANDLE ( pxRingbuffer ) = = xMember ) ? pdTRUE : pdFALSE ;
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 ;
configASSERT ( pxRingbuffer ) ;
BaseType_t xReturn ;
2018-08-30 06:29:01 -04:00
portENTER_CRITICAL ( & pxRingbuffer - > mux ) ;
2018-04-18 13:20:34 -04:00
//Cannot remove semaphore from queue set if semaphore is not empty. Temporarily hold semaphore
2022-08-05 04:19:47 -04:00
BaseType_t result = xSemaphoreTake ( rbGET_RX_SEM_HANDLE ( pxRingbuffer ) , 0 ) ;
2019-03-04 01:27:06 -05:00
xReturn = xQueueRemoveFromSet ( rbGET_RX_SEM_HANDLE ( pxRingbuffer ) , xQueueSet ) ;
2022-08-05 04:19:47 -04:00
if ( result = = pdTRUE ) {
2018-04-18 13:20:34 -04:00
//Return semaphore if temporarily held
2022-08-05 04:19:47 -04:00
result = xSemaphoreGive ( rbGET_RX_SEM_HANDLE ( pxRingbuffer ) ) ;
configASSERT ( result = = pdTRUE ) ;
2018-04-18 13:20:34 -04:00
}
2018-08-30 06:29:01 -04:00
portEXIT_CRITICAL ( & pxRingbuffer - > mux ) ;
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
}