mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'feature/ringbuf_improvement' into 'master'
Feature/ringbuf improvement See merge request !1571
This commit is contained in:
commit
361bdcf78c
@ -77,6 +77,19 @@ typedef enum {
|
||||
*/
|
||||
RingbufHandle_t xRingbufferCreate(size_t buf_length, ringbuf_type_t type);
|
||||
|
||||
/**
|
||||
* @brief Create a ring buffer of type RINGBUF_TYPE_NOSPLIT for a fixed item_size
|
||||
*
|
||||
* This API is similar to xRingbufferCreate(), but it will internally allocate
|
||||
* additional space for the headers.
|
||||
*
|
||||
* @param item_size Size of each item to be put into the ring buffer
|
||||
* @param num_item Maximum number of items the buffer needs to hold simultaneously
|
||||
*
|
||||
* @return A RingbufHandle_t handle to the created ringbuffer, or NULL in case of error.
|
||||
*/
|
||||
RingbufHandle_t xRingbufferCreateNoSplit(size_t item_size, size_t num_item);
|
||||
|
||||
/**
|
||||
* @brief Delete a ring buffer
|
||||
*
|
||||
@ -94,6 +107,38 @@ 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 Check if the next item is wrapped
|
||||
*
|
||||
* This API tells if the next item that is available for a Receive is wrapped
|
||||
* or not. This is valid only if the ring buffer type is RINGBUF_TYPE_ALLOWSPLIT
|
||||
*
|
||||
* @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 Receive
|
||||
*
|
||||
* @param ringbuf - Ring buffer to query
|
||||
*
|
||||
* @return true if the next item is wrapped around
|
||||
* @return false if the next item is not wrapped
|
||||
*/
|
||||
bool xRingbufferIsNextItemWrapped(RingbufHandle_t ringbuf);
|
||||
|
||||
/**
|
||||
* @brief Insert an item into the ring buffer
|
||||
|
@ -32,6 +32,7 @@ typedef enum {
|
||||
typedef enum {
|
||||
iflag_free = 1, //Buffer is not read and given back by application, free to overwrite
|
||||
iflag_dummydata = 2, //Data from here to end of ringbuffer is dummy. Restart reading at start of ringbuffer.
|
||||
iflag_wrap = 4, //Valid for RINGBUF_TYPE_ALLOWSPLIT, indicating that rest of the data is wrapped around
|
||||
} itemflag_t;
|
||||
|
||||
|
||||
@ -53,6 +54,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 +84,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
|
||||
@ -203,6 +204,9 @@ static BaseType_t copyItemToRingbufAllowSplit(ringbuf_t *rb, uint8_t *buffer, si
|
||||
if (buffer_size == 0) {
|
||||
rb->write_ptr=rb->data;
|
||||
return pdTRUE;
|
||||
} else {
|
||||
/* Indicate the wrapping */
|
||||
hdr->flags|=iflag_wrap;
|
||||
}
|
||||
} else {
|
||||
//Huh, only the header fit. Mark as dummy so the receive function doesn't receive
|
||||
@ -359,6 +363,7 @@ static void returnItemToRingbufDefault(ringbuf_t *rb, void *item) {
|
||||
configASSERT((hdr->flags & iflag_dummydata)==0);
|
||||
configASSERT((hdr->flags & iflag_free)==0);
|
||||
//Mark the buffer as free.
|
||||
hdr->flags&=~iflag_wrap;
|
||||
hdr->flags|=iflag_free;
|
||||
|
||||
//Do a cleanup pass.
|
||||
@ -415,6 +420,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 +503,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 +511,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 +521,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);
|
||||
}
|
||||
@ -472,6 +541,12 @@ err:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
RingbufHandle_t xRingbufferCreateNoSplit(size_t item_size, size_t num_item)
|
||||
{
|
||||
size_t aligned_size = (item_size+3)&~3;
|
||||
return xRingbufferCreate((aligned_size + sizeof(buf_entry_hdr_t)) * num_item, RINGBUF_TYPE_NOSPLIT);
|
||||
}
|
||||
|
||||
void vRingbufferDelete(RingbufHandle_t ringbuf) {
|
||||
ringbuf_t *rb=(ringbuf_t *)ringbuf;
|
||||
if (rb) {
|
||||
@ -489,6 +564,15 @@ size_t xRingbufferGetMaxItemSize(RingbufHandle_t ringbuf)
|
||||
return rb->maxItemSize;
|
||||
}
|
||||
|
||||
bool xRingbufferIsNextItemWrapped(RingbufHandle_t ringbuf)
|
||||
{
|
||||
ringbuf_t *rb=(ringbuf_t *)ringbuf;
|
||||
configASSERT(rb);
|
||||
buf_entry_hdr_t *hdr=(buf_entry_hdr_t *)rb->read_ptr;
|
||||
return hdr->flags & iflag_wrap;
|
||||
}
|
||||
|
||||
|
||||
BaseType_t xRingbufferSend(RingbufHandle_t ringbuf, void *data, size_t dataSize, TickType_t ticks_to_wait)
|
||||
{
|
||||
ringbuf_t *rb=(ringbuf_t *)ringbuf;
|
||||
|
Loading…
x
Reference in New Issue
Block a user