freertos/ringbuf: Add an API xRingbufferGetCurFreeSize() to fetch current free size available

The earlier available API (xRingbufferGetMaxItemSize())just gives
a static max entry value possible for given ring buffer.
There was a feature request for an API which could provide
a real time available buffer size. See below:

https://github.com/espressif/esp-idf/issues/806

Signed-off-by: Piyush Shah <piyush@espressif.com>
This commit is contained in:
Piyush Shah 2017-11-20 19:23:25 +05:30 committed by Ivan Grokhotkov
parent c4b861ad65
commit 50637f638f
2 changed files with 80 additions and 1 deletions

View file

@ -94,6 +94,21 @@ void vRingbufferDelete(RingbufHandle_t ringbuf);
*/
size_t xRingbufferGetMaxItemSize(RingbufHandle_t ringbuf);
/**
* @brief Get current free size available in the buffer
*
* This gives the real time free space available in the ring buffer. So basically,
* this will be the maximum size of the entry that can be sent into the buffer.
*
* @note This API is not thread safe. So, if multiple threads are accessing the same
* ring buffer, it is the application's responsibility to ensure atomic access to this
* API and the subsequent Send
*
* @param ringbuf - Ring buffer to query
*
* @return Current free size, in bytes, available for an entry
*/
size_t xRingbufferGetCurFreeSize(RingbufHandle_t ringbuf);
/**
* @brief Insert an item into the ring buffer

View file

@ -53,6 +53,7 @@ struct ringbuf_t {
BaseType_t (*copyItemToRingbufImpl)(ringbuf_t *rb, uint8_t *buffer, size_t buffer_size);
uint8_t *(*getItemFromRingbufImpl)(ringbuf_t *rb, size_t *length, int wanted_length);
void (*returnItemToRingbufImpl)(ringbuf_t *rb, void *item);
size_t (*getFreeSizeImpl)(ringbuf_t *rb);
};
@ -82,7 +83,6 @@ static int ringbufferFreeMem(ringbuf_t *rb)
return free_size-1;
}
//Copies a single item to the ring buffer; refuses to split items. Assumes there is space in the ringbuffer and
//the ringbuffer is locked. Increases write_ptr to the next item. Returns pdTRUE on
//success, pdFALSE if it can't make the item fit and the calling routine needs to retry
@ -415,6 +415,67 @@ void xRingbufferPrintInfo(RingbufHandle_t ringbuf)
}
size_t xRingbufferGetCurFreeSize(RingbufHandle_t ringbuf)
{
ringbuf_t *rb=(ringbuf_t *)ringbuf;
configASSERT(rb);
configASSERT(rb->getFreeSizeImpl);
int free_size = rb->getFreeSizeImpl(rb);
//Reserve one byte. If we do not do this and the entire buffer is filled, we get a situation
//where read_ptr == free_ptr, messing up the next calculation.
return free_size - 1;
}
static size_t getCurFreeSizeByteBuf(ringbuf_t *rb)
{
//Return whatever space is available depending on relative positions of
//the free pointer and write pointer. There is no overhead of headers in
//this mode
int free_size = rb->free_ptr-rb->write_ptr;
if (free_size <= 0)
free_size += rb->size;
return free_size;
}
static size_t getCurFreeSizeAllowSplit(ringbuf_t *rb)
{
int free_size;
//If Both, the write and free pointer are at the start. Hence, the entire buffer
//is available (minus the space for the header)
if (rb->write_ptr == rb->free_ptr && rb->write_ptr == rb->data) {
free_size = rb->size - sizeof(buf_entry_hdr_t);
} else if (rb->write_ptr < rb->free_ptr) {
//Else if the free pointer is beyond the write pointer, only the space between
//them would be available (minus the space for the header)
free_size = rb->free_ptr - rb->write_ptr - sizeof(buf_entry_hdr_t);
} else {
//Else the data can wrap around and 2 headers will be required
free_size = rb->free_ptr - rb->write_ptr + rb->size - (2 * sizeof(buf_entry_hdr_t));
}
return free_size;
}
static size_t getCurFreeSizeNoSplit(ringbuf_t *rb)
{
int free_size;
//If the free pointer is beyond the write pointer, only the space between
//them would be available
if (rb->write_ptr < rb->free_ptr) {
free_size = rb->free_ptr - rb->write_ptr;
} else {
//Else check which one is bigger amongst the below 2
//1) Space from the write pointer to the end of buffer
int size1 = rb->data + rb->size - rb->write_ptr;
//2) Space from the start of buffer to the free pointer
int size2 = rb->free_ptr - rb->data;
//And then select the larger of the two
free_size = size1 > size2 ? size1 : size2;
}
//In any case, a single header will be used, so subtracting the space that
//would be required for it
return free_size - sizeof(buf_entry_hdr_t);
}
RingbufHandle_t xRingbufferCreate(size_t buf_length, ringbuf_type_t type)
{
@ -437,6 +498,7 @@ RingbufHandle_t xRingbufferCreate(size_t buf_length, ringbuf_type_t type)
rb->returnItemToRingbufImpl=returnItemToRingbufDefault;
//Calculate max item size. Worst case, we need to split an item into two, which means two headers of overhead.
rb->maxItemSize=rb->size-(sizeof(buf_entry_hdr_t)*2)-4;
rb->getFreeSizeImpl=getCurFreeSizeAllowSplit;
} else if (type==RINGBUF_TYPE_BYTEBUF) {
rb->flags|=flag_bytebuf;
rb->copyItemToRingbufImpl=copyItemToRingbufByteBuf;
@ -444,6 +506,7 @@ RingbufHandle_t xRingbufferCreate(size_t buf_length, ringbuf_type_t type)
rb->returnItemToRingbufImpl=returnItemToRingbufBytebuf;
//Calculate max item size. We have no headers and can split anywhere -> size is total size minus one.
rb->maxItemSize=rb->size-1;
rb->getFreeSizeImpl=getCurFreeSizeByteBuf;
} else if (type==RINGBUF_TYPE_NOSPLIT) {
rb->copyItemToRingbufImpl=copyItemToRingbufNoSplit;
rb->getItemFromRingbufImpl=getItemFromRingbufDefault;
@ -453,6 +516,7 @@ RingbufHandle_t xRingbufferCreate(size_t buf_length, ringbuf_type_t type)
//(item_data-4) bytes of buffer, then we only have (size-(item_data-4) bytes left to fill
//with the real item. (item size being header+data)
rb->maxItemSize=(rb->size/2)-sizeof(buf_entry_hdr_t)-4;
rb->getFreeSizeImpl=getCurFreeSizeNoSplit;
} else {
configASSERT(0);
}