ringbuf: Fix bug where comparision between a signed and unsigned operand resulted in incorrect free size for no-split/allow-split buffers

This commit fixes a bug in no-split and allow-split ring buffers free buffer size calculation.
When the free size available in the buffers less than the size of one item header,
the function prvGetCurMaxSizeNoSplit/AllowSplit() incorrectly returned the maxItemSize instead of 0.
This is due to the comparision between a negative and a positive value
where both operands are treated as unsigned during the comparision operation,
thereby treating the negative operand as a large integer.

Also added new unit tests to test buffer-full and almost-full conditions
where this scenario is likely to be hit.

Closes https://github.com/espressif/esp-idf/issues/7344
Closes https://github.com/espressif/esp-idf/pull/7371
pull/7830/head
Sudeep Mohanty 2021-09-28 16:06:55 +08:00
rodzic eb50e37a40
commit ac0cbebb89
3 zmienionych plików z 418 dodań i 27 usunięć

Wyświetl plik

@ -26,7 +26,7 @@
#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
#define rbITEM_WRITTEN_FLAG ( ( UBaseType_t ) 8 ) //Item has been written to by the application, thus it is free to be read
#define rbITEM_WRITTEN_FLAG ( ( UBaseType_t ) 8 ) //Item has been written to by the application, thus can be read
//Static allocation related
#if ( configSUPPORT_STATIC_ALLOCATION == 1 )
@ -135,16 +135,41 @@ static BaseType_t prvCheckItemFitsDefault( Ringbuffer_t *pxRingbuffer, size_t xI
//Checks if an item will currently fit in a byte buffer
static BaseType_t prvCheckItemFitsByteBuffer( Ringbuffer_t *pxRingbuffer, size_t xItemSize);
//Copies an item to a no-split ring buffer. Only call this function after calling prvCheckItemFitsDefault()
/*
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
*/
static void prvCopyItemNoSplit(Ringbuffer_t *pxRingbuffer, const uint8_t *pucItem, size_t xItemSize);
//Copies an item to a allow-split ring buffer. Only call this function after calling prvCheckItemFitsDefault()
/*
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
*/
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
/*
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
*/
static void *prvGetItemDefault(Ringbuffer_t *pxRingbuffer,
BaseType_t *pxIsSplit,
size_t xUnusedParam,
@ -156,7 +181,12 @@ static void *prvGetItemByteBuf(Ringbuffer_t *pxRingbuffer,
size_t xMaxSize,
size_t *pxItemSize);
//Return an item to a split/no-split ring buffer
/*
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
*/
static void prvReturnItemDefault(Ringbuffer_t *pxRingbuffer, uint8_t *pucItem);
//Return data to a byte buffer
@ -384,7 +414,7 @@ static void prvSendItemDoneNoSplit(Ringbuffer_t *pxRingbuffer, uint8_t* pucItem)
//Redundancy check to ensure write pointer has not overshot buffer bounds
configASSERT(pxRingbuffer->pucWrite <= pxRingbuffer->pucHead + pxRingbuffer->xSize);
}
//Check if pucAcquire requires wrap around
//Check if pucWrite requires wrap around
if ((pxRingbuffer->pucTail - pxRingbuffer->pucWrite) < rbHEADER_SIZE) {
pxRingbuffer->pucWrite = pxRingbuffer->pucHead;
}
@ -525,7 +555,7 @@ static void *prvGetItemDefault(Ringbuffer_t *pxRingbuffer,
//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 {
//Exclusive of pucTali if length is larger than zero, pcReturn should never point to pucTail
//Exclusive of pucTail if length is larger than zero, pcReturn should never point to pucTail
configASSERT(pcReturn >= pxRingbuffer->pucHead && pcReturn < pxRingbuffer->pucTail);
}
*pxItemSize = pxHeader->xItemLen; //Get length of item
@ -615,7 +645,7 @@ static void prvReturnItemDefault(Ringbuffer_t *pxRingbuffer, uint8_t *pucItem)
//Redundancy check to ensure free pointer has not overshot buffer bounds
configASSERT(pxRingbuffer->pucFree <= pxRingbuffer->pucHead + pxRingbuffer->xSize);
}
//Check if pucRead requires wrap around
//Check if pucFree requires wrap around
if ((pxRingbuffer->pucTail - pxRingbuffer->pucFree) < rbHEADER_SIZE) {
pxRingbuffer->pucFree = pxRingbuffer->pucHead;
}
@ -666,12 +696,15 @@ static size_t prvGetCurMaxSizeNoSplit(Ringbuffer_t *pxRingbuffer)
//No-split ring buffer items need space for a header
xFreeSize -= rbHEADER_SIZE;
//Limit free size to be within bounds
if (xFreeSize > pxRingbuffer->xMaxItemSize) {
xFreeSize = pxRingbuffer->xMaxItemSize;
} else if (xFreeSize < 0) {
//Check for xFreeSize < 0 before checking xFreeSize > pxRingbuffer->xMaxItemSize
//to avoid incorrect comparison operation when xFreeSize is negative
if (xFreeSize < 0) {
//Occurs when free space is less than header size
xFreeSize = 0;
} else if (xFreeSize > pxRingbuffer->xMaxItemSize) {
//Limit free size to be within bounds
xFreeSize = pxRingbuffer->xMaxItemSize;
}
return xFreeSize;
}
@ -696,11 +729,13 @@ static size_t prvGetCurMaxSizeAllowSplit(Ringbuffer_t *pxRingbuffer)
(rbHEADER_SIZE * 2);
}
//Limit free size to be within bounds
if (xFreeSize > pxRingbuffer->xMaxItemSize) {
xFreeSize = pxRingbuffer->xMaxItemSize;
} else if (xFreeSize < 0) {
//Check for xFreeSize < 0 before checking xFreeSize > pxRingbuffer->xMaxItemSize
//to avoid incorrect comparison operation when xFreeSize is negative
if (xFreeSize < 0) {
xFreeSize = 0;
} else if (xFreeSize > pxRingbuffer->xMaxItemSize) {
//Limit free size to be within bounds
xFreeSize = pxRingbuffer->xMaxItemSize;
}
return xFreeSize;
}

Wyświetl plik

@ -1,3 +1,9 @@
/*
* SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
@ -17,7 +23,8 @@
#define NO_OF_RB_TYPES 3
#define ITEM_HDR_SIZE 8
#define SMALL_ITEM_SIZE 8
#define LARGE_ITEM_SIZE (2 * SMALL_ITEM_SIZE)
#define MEDIUM_ITEM_SIZE ((3 * SMALL_ITEM_SIZE) >> 1) //12 bytes
#define LARGE_ITEM_SIZE (2 * SMALL_ITEM_SIZE) //16 bytes
#define BUFFER_SIZE 160 //4Byte aligned size
static const uint8_t small_item[SMALL_ITEM_SIZE] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
@ -37,6 +44,17 @@ static void send_item_and_check(RingbufHandle_t handle, const uint8_t *item, si
TEST_ASSERT_MESSAGE(ret == pdTRUE, "Failed to send item");
}
static void send_item_and_check_failure(RingbufHandle_t handle, const uint8_t *item, size_t item_size, TickType_t ticks_to_wait, bool in_isr)
{
BaseType_t ret;
if (in_isr) {
ret = xRingbufferSendFromISR(handle, (void *)item, item_size, NULL);
} else {
ret = xRingbufferSend(handle, (void *)item, item_size, ticks_to_wait);
}
TEST_ASSERT_MESSAGE(ret == pdFALSE, "Sent an item to a full buffer");
}
static void receive_check_and_return_item_no_split(RingbufHandle_t handle, const uint8_t *expected_data, size_t expected_size, TickType_t ticks_to_wait, bool in_isr)
{
//Receive item from no-split buffer
@ -73,7 +91,6 @@ static void receive_check_and_return_item_allow_split(RingbufHandle_t handle, co
} else {
ret = xRingbufferReceiveSplit(handle, (void**)&item1, (void **)&item2, &item_size1, &item_size2, ticks_to_wait);
}
//= xRingbufferReceiveSplit(handle, (void**)&item1, (void **)&item2, &item_size1, &item_size2, ticks_to_wait);
TEST_ASSERT_MESSAGE(ret == pdTRUE, "Failed to receive item");
TEST_ASSERT_MESSAGE(item1 != NULL, "Failed to receive item");
@ -159,19 +176,37 @@ static void receive_check_and_return_item_byte_buffer(RingbufHandle_t handle, co
}
/* ----------------- Basic ring buffer behavior tests cases --------------------
* The following test cases will test basic send, receive, and wrap around
* behavior of each type of ring buffer. Each test case will do the following
* 1) Send multiple items (nearly fill the buffer)
* 2) Receive and check the sent items (also prepares the buffer for a wrap around
* 3) Send a final item that causes a wrap around
* 4) Receive and check the wrapped item
* The following set of test cases will test basic send, receive, wrap around and buffer full
* behavior of each type of ring buffer.
* Test Case 1:
* 1) Send multiple items (nearly fill the buffer)
* 2) Receive and check the sent items (also prepares the buffer for a wrap around)
* 3) Send a final item that causes a wrap around
* 4) Receive and check the wrapped item
*
* Test Case 2:
* 1) Send multiple items (completely fill the buffer)
* 2) Send another item and verify that send failure occurs
* 3) Receive one item and verify that space is freed up in the buffer
* 4) Receive and check the remaining sent items
*
* Test Case 3:
* 1) Send multiple items (nearly fill the buffer)
* 2) Send another small sized item to fill the buffer without causing a wrap around (not needed in case of byte buffer)
* 2) Send another item and verify that send failure occurs
* 4) Receive and check the sent items
*/
TEST_CASE("Test ring buffer No-Split", "[esp_ringbuf]")
TEST_CASE("TC#1: No-Split", "[esp_ringbuf]")
{
//Create buffer
RingbufHandle_t buffer_handle = xRingbufferCreate(BUFFER_SIZE, RINGBUF_TYPE_NOSPLIT);
TEST_ASSERT_MESSAGE(buffer_handle != NULL, "Failed to create ring buffer");
//Check buffer free size and max item size upon buffer creation. Should be BUFFER_SIZE/2 - ITEM_HDR_SIZE.
TEST_ASSERT_MESSAGE(xRingbufferGetCurFreeSize(buffer_handle) == ((BUFFER_SIZE >> 1) - ITEM_HDR_SIZE), "Incorrect buffer free size received");
TEST_ASSERT_MESSAGE(xRingbufferGetMaxItemSize(buffer_handle) == ((BUFFER_SIZE >> 1) - ITEM_HDR_SIZE), "Incorrect max item size received");
//Calculate number of items to send. Aim to almost fill buffer to setup for wrap around
int no_of_items = (BUFFER_SIZE - (ITEM_HDR_SIZE + SMALL_ITEM_SIZE)) / (ITEM_HDR_SIZE + SMALL_ITEM_SIZE);
@ -179,11 +214,21 @@ TEST_CASE("Test ring buffer No-Split", "[esp_ringbuf]")
for (int i = 0; i < no_of_items; i++) {
send_item_and_check(buffer_handle, small_item, SMALL_ITEM_SIZE, TIMEOUT_TICKS, false);
}
//Verify items waiting matches with the number of items sent
UBaseType_t items_waiting;
vRingbufferGetInfo(buffer_handle, NULL, NULL, NULL, NULL, &items_waiting);
TEST_ASSERT_MESSAGE(items_waiting == no_of_items, "Incorrect items waiting");
//Test receiving items
for (int i = 0; i < no_of_items; i++) {
receive_check_and_return_item_no_split(buffer_handle, small_item, SMALL_ITEM_SIZE, TIMEOUT_TICKS, false);
}
//Verify that no items are waiting
vRingbufferGetInfo(buffer_handle, NULL, NULL, NULL, NULL, &items_waiting);
TEST_ASSERT_MESSAGE(items_waiting == 0, "Incorrect items waiting");
//Write pointer should be near the end, test wrap around
UBaseType_t write_pos_before, write_pos_after;
vRingbufferGetInfo(buffer_handle, NULL, NULL, &write_pos_before, NULL, NULL);
@ -198,11 +243,112 @@ TEST_CASE("Test ring buffer No-Split", "[esp_ringbuf]")
vRingbufferDelete(buffer_handle);
}
TEST_CASE("Test ring buffer Allow-Split", "[esp_ringbuf]")
TEST_CASE("TC#2: No-Split", "[esp_ringbuf]")
{
//Create buffer
RingbufHandle_t buffer_handle = xRingbufferCreate(BUFFER_SIZE, RINGBUF_TYPE_NOSPLIT);
TEST_ASSERT_MESSAGE(buffer_handle != NULL, "Failed to create ring buffer");
//Check buffer free size and max item size upon buffer creation. Should be BUFFER_SIZE/2 - ITEM_HDR_SIZE.
TEST_ASSERT_MESSAGE(xRingbufferGetCurFreeSize(buffer_handle) == ((BUFFER_SIZE >> 1) - ITEM_HDR_SIZE), "Incorrect buffer free size received");
TEST_ASSERT_MESSAGE(xRingbufferGetMaxItemSize(buffer_handle) == ((BUFFER_SIZE >> 1) - ITEM_HDR_SIZE), "Incorrect max item size received");
//Calculate number of items to send. Aim to fill the buffer
int no_of_items = (BUFFER_SIZE) / (ITEM_HDR_SIZE + SMALL_ITEM_SIZE);
//Test sending items
for (int i = 0; i < no_of_items; i++) {
send_item_and_check(buffer_handle, small_item, SMALL_ITEM_SIZE, TIMEOUT_TICKS, false);
}
//Verify items waiting matches with the number of items sent
UBaseType_t items_waiting;
vRingbufferGetInfo(buffer_handle, NULL, NULL, NULL, NULL, &items_waiting);
TEST_ASSERT_MESSAGE(items_waiting == no_of_items, "Incorrect items waiting");
//At this point, the buffer should be full.
TEST_ASSERT_MESSAGE(xRingbufferGetCurFreeSize(buffer_handle) == 0, "Buffer full not achieved");
//Send an item. The item should not be sent to a full buffer.
send_item_and_check_failure(buffer_handle, small_item, SMALL_ITEM_SIZE, TIMEOUT_TICKS, false);
//Receive one item
receive_check_and_return_item_no_split(buffer_handle, small_item, SMALL_ITEM_SIZE, TIMEOUT_TICKS, false);
//At this point, the buffer should not be full any more
TEST_ASSERT_MESSAGE(xRingbufferGetCurFreeSize(buffer_handle) > 0, "Buffer should have free space");
//Test receiving remaining items
for (int i = 0; i < no_of_items - 1; i++) {
receive_check_and_return_item_no_split(buffer_handle, small_item, SMALL_ITEM_SIZE, TIMEOUT_TICKS, false);
}
//Verify that no items are waiting
vRingbufferGetInfo(buffer_handle, NULL, NULL, NULL, NULL, &items_waiting);
TEST_ASSERT_MESSAGE(items_waiting == 0, "Incorrect items waiting");
//Cleanup
vRingbufferDelete(buffer_handle);
}
TEST_CASE("TC#3: No-Split", "[esp_ringbuf]")
{
//Create buffer
RingbufHandle_t buffer_handle = xRingbufferCreate(BUFFER_SIZE, RINGBUF_TYPE_NOSPLIT);
TEST_ASSERT_MESSAGE(buffer_handle != NULL, "Failed to create ring buffer");
//Check buffer free size and max item size upon buffer creation. Should be BUFFER_SIZE/2 - ITEM_HDR_SIZE.
TEST_ASSERT_MESSAGE(xRingbufferGetCurFreeSize(buffer_handle) == ((BUFFER_SIZE >> 1) - ITEM_HDR_SIZE), "Incorrect buffer free size received");
TEST_ASSERT_MESSAGE(xRingbufferGetMaxItemSize(buffer_handle) == ((BUFFER_SIZE >> 1) - ITEM_HDR_SIZE), "Incorrect max item size received");
//Calculate number of medium items to send. Aim to almost fill the buffer
int no_of_medium_items = (BUFFER_SIZE - (ITEM_HDR_SIZE + MEDIUM_ITEM_SIZE)) / (ITEM_HDR_SIZE + MEDIUM_ITEM_SIZE);
//Test sending items
for (int i = 0; i < no_of_medium_items; i++) {
send_item_and_check(buffer_handle, large_item, MEDIUM_ITEM_SIZE, TIMEOUT_TICKS, false);
}
//Verify items waiting matches with the number of medium items sent
UBaseType_t items_waiting;
vRingbufferGetInfo(buffer_handle, NULL, NULL, NULL, NULL, &items_waiting);
TEST_ASSERT_MESSAGE(items_waiting == no_of_medium_items, "Incorrect items waiting");
//Send one small sized item. This will ensure that the item fits at the end of the buffer without causing the write pointer to wrap around.
send_item_and_check(buffer_handle, small_item, SMALL_ITEM_SIZE, TIMEOUT_TICKS, false);
//The buffer should not have any free space as the number of bytes remaining should be < ITEM_HDR_SIZE.
TEST_ASSERT_MESSAGE(xRingbufferGetCurFreeSize(buffer_handle) == 0, "Buffer full not achieved");
//Send an item. The item should not be sent to a full buffer.
send_item_and_check_failure(buffer_handle, small_item, SMALL_ITEM_SIZE, TIMEOUT_TICKS, false);
//Test receiving medium items
for (int i = 0; i < no_of_medium_items; i++) {
receive_check_and_return_item_no_split(buffer_handle, large_item, MEDIUM_ITEM_SIZE, TIMEOUT_TICKS, false);
}
//Test receiving small item
receive_check_and_return_item_no_split(buffer_handle, small_item, SMALL_ITEM_SIZE, TIMEOUT_TICKS, false);
//Verify that no items are waiting
vRingbufferGetInfo(buffer_handle, NULL, NULL, NULL, NULL, &items_waiting);
TEST_ASSERT_MESSAGE(items_waiting == 0, "Incorrect items waiting");
//Cleanup
vRingbufferDelete(buffer_handle);
}
TEST_CASE("TC#1: Allow-Split", "[esp_ringbuf]")
{
//Create buffer
RingbufHandle_t buffer_handle = xRingbufferCreate(BUFFER_SIZE, RINGBUF_TYPE_ALLOWSPLIT);
TEST_ASSERT_MESSAGE(buffer_handle != NULL, "Failed to create ring buffer");
//Check buffer free size and max item size upon buffer creation. Should be BUFFER_SIZE - (ITEM_HDR_SIZE * 2).
TEST_ASSERT_MESSAGE(xRingbufferGetCurFreeSize(buffer_handle) == (BUFFER_SIZE - (ITEM_HDR_SIZE * 2)), "Incorrect buffer free size received");
TEST_ASSERT_MESSAGE(xRingbufferGetMaxItemSize(buffer_handle) == (BUFFER_SIZE - (ITEM_HDR_SIZE * 2)), "Incorrect max item size received");
//Calculate number of items to send. Aim to almost fill buffer to setup for wrap around
int no_of_items = (BUFFER_SIZE - (ITEM_HDR_SIZE + SMALL_ITEM_SIZE)) / (ITEM_HDR_SIZE + SMALL_ITEM_SIZE);
@ -210,11 +356,21 @@ TEST_CASE("Test ring buffer Allow-Split", "[esp_ringbuf]")
for (int i = 0; i < no_of_items; i++) {
send_item_and_check(buffer_handle, small_item, SMALL_ITEM_SIZE, TIMEOUT_TICKS, false);
}
//Verify items waiting matches with the number of items sent
UBaseType_t items_waiting;
vRingbufferGetInfo(buffer_handle, NULL, NULL, NULL, NULL, &items_waiting);
TEST_ASSERT_MESSAGE(items_waiting == no_of_items, "Incorrect items waiting");
//Test receiving items
for (int i = 0; i < no_of_items; i++) {
receive_check_and_return_item_allow_split(buffer_handle, small_item, SMALL_ITEM_SIZE, TIMEOUT_TICKS, false);
}
//Verify that no items are waiting
vRingbufferGetInfo(buffer_handle, NULL, NULL, NULL, NULL, &items_waiting);
TEST_ASSERT_MESSAGE(items_waiting == 0, "Incorrect items waiting");
//Write pointer should be near the end, test wrap around
UBaseType_t write_pos_before, write_pos_after;
vRingbufferGetInfo(buffer_handle, NULL, NULL, &write_pos_before, NULL, NULL);
@ -229,11 +385,112 @@ TEST_CASE("Test ring buffer Allow-Split", "[esp_ringbuf]")
vRingbufferDelete(buffer_handle);
}
TEST_CASE("Test ring buffer Byte Buffer", "[esp_ringbuf]")
TEST_CASE("TC#2: Allow-Split", "[esp_ringbuf]")
{
//Create buffer
RingbufHandle_t buffer_handle = xRingbufferCreate(BUFFER_SIZE, RINGBUF_TYPE_ALLOWSPLIT);
TEST_ASSERT_MESSAGE(buffer_handle != NULL, "Failed to create ring buffer");
//Check buffer free size and max item size upon buffer creation. Should be BUFFER_SIZE - (ITEM_HDR_SIZE * 2).
TEST_ASSERT_MESSAGE(xRingbufferGetCurFreeSize(buffer_handle) == (BUFFER_SIZE - (ITEM_HDR_SIZE * 2)), "Incorrect buffer free size received");
TEST_ASSERT_MESSAGE(xRingbufferGetMaxItemSize(buffer_handle) == (BUFFER_SIZE - (ITEM_HDR_SIZE * 2)), "Incorrect max item size received");
//Calculate number of items to send. Aim to fill the buffer
int no_of_items = (BUFFER_SIZE) / (ITEM_HDR_SIZE + SMALL_ITEM_SIZE);
//Test sending items
for (int i = 0; i < no_of_items; i++) {
send_item_and_check(buffer_handle, small_item, SMALL_ITEM_SIZE, TIMEOUT_TICKS, false);
}
//Verify items waiting matches with the number of items sent
UBaseType_t items_waiting;
vRingbufferGetInfo(buffer_handle, NULL, NULL, NULL, NULL, &items_waiting);
TEST_ASSERT_MESSAGE(items_waiting == no_of_items, "Incorrect items waiting");
//At this point, the buffer should be full.
TEST_ASSERT_MESSAGE(xRingbufferGetCurFreeSize(buffer_handle) == 0, "Buffer full not achieved");
//Send an item. The item should not be sent to a full buffer.
send_item_and_check_failure(buffer_handle, small_item, SMALL_ITEM_SIZE, TIMEOUT_TICKS, false);
//Receive one item
receive_check_and_return_item_allow_split(buffer_handle, small_item, SMALL_ITEM_SIZE, TIMEOUT_TICKS, false);
//At this point, the buffer should not be full any more
TEST_ASSERT_MESSAGE(xRingbufferGetCurFreeSize(buffer_handle) > 0, "Buffer should have free space");
//Test receiving remaining items
for (int i = 0; i < no_of_items - 1; i++) {
receive_check_and_return_item_allow_split(buffer_handle, small_item, SMALL_ITEM_SIZE, TIMEOUT_TICKS, false);
}
//Verify that no items are waiting
vRingbufferGetInfo(buffer_handle, NULL, NULL, NULL, NULL, &items_waiting);
TEST_ASSERT_MESSAGE(items_waiting == 0, "Incorrect items waiting");
//Cleanup
vRingbufferDelete(buffer_handle);
}
TEST_CASE("TC#3: Allow-Split", "[esp_ringbuf]")
{
//Create buffer
RingbufHandle_t buffer_handle = xRingbufferCreate(BUFFER_SIZE, RINGBUF_TYPE_ALLOWSPLIT);
TEST_ASSERT_MESSAGE(buffer_handle != NULL, "Failed to create ring buffer");
//Check buffer free size and max item size upon buffer creation. Should be BUFFER_SIZE - (ITEM_HDR_SIZE * 2).
TEST_ASSERT_MESSAGE(xRingbufferGetCurFreeSize(buffer_handle) == (BUFFER_SIZE - (ITEM_HDR_SIZE * 2)), "Incorrect buffer free size received");
TEST_ASSERT_MESSAGE(xRingbufferGetMaxItemSize(buffer_handle) == (BUFFER_SIZE - (ITEM_HDR_SIZE * 2)), "Incorrect max item size received");
//Calculate number of medium items to send. Aim to almost fill the buffer
int no_of_medium_items = (BUFFER_SIZE - (ITEM_HDR_SIZE + MEDIUM_ITEM_SIZE)) / (ITEM_HDR_SIZE + MEDIUM_ITEM_SIZE);
//Test sending items
for (int i = 0; i < no_of_medium_items; i++) {
send_item_and_check(buffer_handle, large_item, MEDIUM_ITEM_SIZE, TIMEOUT_TICKS, false);
}
//Verify items waiting matches with the number of medium items sent
UBaseType_t items_waiting;
vRingbufferGetInfo(buffer_handle, NULL, NULL, NULL, NULL, &items_waiting);
TEST_ASSERT_MESSAGE(items_waiting == no_of_medium_items, "Incorrect items waiting");
//Send one small sized item. This will ensure that the item fits at the end of the buffer without causing the write pointer to wrap around.
send_item_and_check(buffer_handle, small_item, SMALL_ITEM_SIZE, TIMEOUT_TICKS, false);
//The buffer should not have any free space as the number of bytes remaining should be < ITEM_HDR_SIZE.
TEST_ASSERT_MESSAGE(xRingbufferGetCurFreeSize(buffer_handle) == 0, "Buffer full not achieved");
//Send an item. The item should not be sent to a full buffer.
send_item_and_check_failure(buffer_handle, small_item, SMALL_ITEM_SIZE, TIMEOUT_TICKS, false);
//Test receiving medium items
for (int i = 0; i < no_of_medium_items; i++) {
receive_check_and_return_item_allow_split(buffer_handle, large_item, MEDIUM_ITEM_SIZE, TIMEOUT_TICKS, false);
}
//Test receiving small item
receive_check_and_return_item_allow_split(buffer_handle, small_item, SMALL_ITEM_SIZE, TIMEOUT_TICKS, false);
//Verify that no items are waiting
vRingbufferGetInfo(buffer_handle, NULL, NULL, NULL, NULL, &items_waiting);
TEST_ASSERT_MESSAGE(items_waiting == 0, "Incorrect items waiting");
//Cleanup
vRingbufferDelete(buffer_handle);
}
TEST_CASE("TC#1: Byte buffer", "[esp_ringbuf]")
{
//Create buffer
RingbufHandle_t buffer_handle = xRingbufferCreate(BUFFER_SIZE, RINGBUF_TYPE_BYTEBUF);
TEST_ASSERT_MESSAGE(buffer_handle != NULL, "Failed to create ring buffer");
//Check buffer free size and max item size upon buffer creation. Should be BUFFER_SIZE
TEST_ASSERT_MESSAGE(xRingbufferGetCurFreeSize(buffer_handle) == BUFFER_SIZE, "Incorrect buffer free size received");
TEST_ASSERT_MESSAGE(xRingbufferGetMaxItemSize(buffer_handle) == BUFFER_SIZE, "Incorrect max item size received");
//Calculate number of items to send. Aim to almost fill buffer to setup for wrap around
int no_of_items = (BUFFER_SIZE - SMALL_ITEM_SIZE) / SMALL_ITEM_SIZE;
@ -241,11 +498,21 @@ TEST_CASE("Test ring buffer Byte Buffer", "[esp_ringbuf]")
for (int i = 0; i < no_of_items; i++) {
send_item_and_check(buffer_handle, small_item, SMALL_ITEM_SIZE, TIMEOUT_TICKS, false);
}
//Verify items waiting matches with the number of items sent
UBaseType_t items_waiting;
vRingbufferGetInfo(buffer_handle, NULL, NULL, NULL, NULL, &items_waiting);
TEST_ASSERT_MESSAGE(items_waiting == no_of_items * SMALL_ITEM_SIZE, "Incorrect number of bytes waiting");
//Test receiving items
for (int i = 0; i < no_of_items; i++) {
receive_check_and_return_item_byte_buffer(buffer_handle, small_item, SMALL_ITEM_SIZE, TIMEOUT_TICKS, false);
}
//Verify that no items are waiting
vRingbufferGetInfo(buffer_handle, NULL, NULL, NULL, NULL, &items_waiting);
TEST_ASSERT_MESSAGE(items_waiting == 0, "Incorrect number of bytes waiting");
//Write pointer should be near the end, test wrap around
UBaseType_t write_pos_before, write_pos_after;
vRingbufferGetInfo(buffer_handle, NULL, NULL, &write_pos_before, NULL, NULL);
@ -260,6 +527,96 @@ TEST_CASE("Test ring buffer Byte Buffer", "[esp_ringbuf]")
vRingbufferDelete(buffer_handle);
}
TEST_CASE("TC#2: Byte buffer", "[esp_ringbuf]")
{
//Create buffer
RingbufHandle_t buffer_handle = xRingbufferCreate(BUFFER_SIZE, RINGBUF_TYPE_BYTEBUF);
TEST_ASSERT_MESSAGE(buffer_handle != NULL, "Failed to create ring buffer");
//Check buffer free size and max item size upon buffer creation. Should be BUFFER_SIZE.
TEST_ASSERT_MESSAGE(xRingbufferGetCurFreeSize(buffer_handle) == BUFFER_SIZE, "Incorrect buffer free size received");
TEST_ASSERT_MESSAGE(xRingbufferGetMaxItemSize(buffer_handle) == BUFFER_SIZE, "Incorrect max item size received");
//Calculate number of items to send. Aim to fill the buffer
int no_of_items = BUFFER_SIZE / SMALL_ITEM_SIZE;
//Test sending items
for (int i = 0; i < no_of_items; i++) {
send_item_and_check(buffer_handle, small_item, SMALL_ITEM_SIZE, TIMEOUT_TICKS, false);
}
//Verify items waiting matches with the number of items sent
UBaseType_t items_waiting;
vRingbufferGetInfo(buffer_handle, NULL, NULL, NULL, NULL, &items_waiting);
TEST_ASSERT_MESSAGE(items_waiting == no_of_items * SMALL_ITEM_SIZE, "Incorrect number of bytes waiting");
//At this point, the buffer should be full.
TEST_ASSERT_MESSAGE(xRingbufferGetCurFreeSize(buffer_handle) == 0, "Buffer full not achieved");
//Send an item. The item should not be sent to a full buffer.
send_item_and_check_failure(buffer_handle, small_item, SMALL_ITEM_SIZE, TIMEOUT_TICKS, false);
//Receive one item
receive_check_and_return_item_byte_buffer(buffer_handle, small_item, SMALL_ITEM_SIZE, TIMEOUT_TICKS, false);
//At this point, the buffer should not be full any more
TEST_ASSERT_MESSAGE(xRingbufferGetCurFreeSize(buffer_handle) > 0, "Buffer should have free space");
//Test receiving remaining items
for (int i = 0; i < no_of_items - 1; i++) {
receive_check_and_return_item_byte_buffer(buffer_handle, small_item, SMALL_ITEM_SIZE, TIMEOUT_TICKS, false);
}
//Verify that no items are waiting
vRingbufferGetInfo(buffer_handle, NULL, NULL, NULL, NULL, &items_waiting);
TEST_ASSERT_MESSAGE(items_waiting == 0, "Incorrect items waiting");
//Cleanup
vRingbufferDelete(buffer_handle);
}
TEST_CASE("TC#3: Byte buffer", "[esp_ringbuf]")
{
//Create buffer
RingbufHandle_t buffer_handle = xRingbufferCreate(BUFFER_SIZE, RINGBUF_TYPE_BYTEBUF);
TEST_ASSERT_MESSAGE(buffer_handle != NULL, "Failed to create ring buffer");
//Check buffer free size and max item size upon buffer creation. Should be BUFFER_SIZE.
TEST_ASSERT_MESSAGE(xRingbufferGetCurFreeSize(buffer_handle) == BUFFER_SIZE, "Incorrect buffer free size received");
TEST_ASSERT_MESSAGE(xRingbufferGetMaxItemSize(buffer_handle) == BUFFER_SIZE, "Incorrect max item size received");
//Calculate number of medium items to send. Aim to almost fill the buffer
int no_of_medium_items = BUFFER_SIZE / MEDIUM_ITEM_SIZE;
//Test sending items
for (int i = 0; i < no_of_medium_items; i++) {
send_item_and_check(buffer_handle, large_item, MEDIUM_ITEM_SIZE, TIMEOUT_TICKS, false);
}
//Verify items waiting matches with the number of medium items sent
UBaseType_t items_waiting;
vRingbufferGetInfo(buffer_handle, NULL, NULL, NULL, NULL, &items_waiting);
TEST_ASSERT_MESSAGE(items_waiting == no_of_medium_items * MEDIUM_ITEM_SIZE, "Incorrect number of bytes waiting");
//The buffer should not have any free space for one small item.
TEST_ASSERT_MESSAGE(xRingbufferGetCurFreeSize(buffer_handle) < SMALL_ITEM_SIZE, "Buffer full not achieved");
//Send an item. The item should not be sent to a full buffer.
send_item_and_check_failure(buffer_handle, small_item, SMALL_ITEM_SIZE, TIMEOUT_TICKS, false);
//Test receiving medium items
for (int i = 0; i < no_of_medium_items; i++) {
receive_check_and_return_item_byte_buffer(buffer_handle, large_item, MEDIUM_ITEM_SIZE, TIMEOUT_TICKS, false);
}
//Verify that no items are waiting
vRingbufferGetInfo(buffer_handle, NULL, NULL, NULL, NULL, &items_waiting);
TEST_ASSERT_MESSAGE(items_waiting == 0, "Incorrect items waiting");
//Cleanup
vRingbufferDelete(buffer_handle);
}
/* ----------------------- Ring buffer queue sets test ------------------------
* The following test case will test receiving from ring buffers that have been
* added to a queue set. The test case will do the following...

Wyświetl plik

@ -877,7 +877,6 @@ components/esp_pm/pm_locks.c
components/esp_pm/pm_trace.c
components/esp_pm/test/test_pm.c
components/esp_ringbuf/include/freertos/ringbuf.h
components/esp_ringbuf/test/test_ringbuf.c
components/esp_rom/esp32/esp_rom_caps.h
components/esp_rom/esp32/ld/esp32.rom.api.ld
components/esp_rom/esp32/ld/esp32.rom.eco3.ld