diff --git a/components/esp_ringbuf/include/freertos/ringbuf.h b/components/esp_ringbuf/include/freertos/ringbuf.h index 6e97530b8f..9a2ee166e2 100644 --- a/components/esp_ringbuf/include/freertos/ringbuf.h +++ b/components/esp_ringbuf/include/freertos/ringbuf.h @@ -126,6 +126,10 @@ RingbufHandle_t xRingbufferCreateStatic(size_t xBufferSize, * the item will occupy will be rounded up to the nearest 32-bit aligned * size. This is done to ensure all items are always stored in 32-bit * aligned fashion. + * @note For no-split/allow-split buffers, an xItemSize of 0 will result in + * an item with no data being set (i.e., item only contains the header). + * For byte buffers, an xItemSize of 0 will simply return pdTRUE without + * copying any data. * * @return * - pdTRUE if succeeded @@ -151,6 +155,10 @@ BaseType_t xRingbufferSend(RingbufHandle_t xRingbuffer, * the item will occupy will be rounded up to the nearest 32-bit aligned * size. This is done to ensure all items are always stored in 32-bit * aligned fashion. + * @note For no-split/allow-split buffers, an xItemSize of 0 will result in + * an item with no data being set (i.e., item only contains the header). + * For byte buffers, an xItemSize of 0 will simply return pdTRUE without + * copying any data. * * @return * - pdTRUE if succeeded @@ -182,6 +190,8 @@ BaseType_t xRingbufferSendFromISR(RingbufHandle_t xRingbuffer, * memory that the item will occupy will be rounded up to the nearest 32-bit * aligned size. This is done to ensure all items are always stored in 32-bit * aligned fashion. + * @note An xItemSize of 0 will result in a buffer being acquired, but the buffer + * will have a size of 0. * * @return * - pdTRUE if succeeded @@ -216,6 +226,7 @@ BaseType_t xRingbufferSendComplete(RingbufHandle_t xRingbuffer, void *pvItem); * @param[in] xTicksToWait Ticks to wait for items in the ring buffer. * * @note A call to vRingbufferReturnItem() is required after this to free the item retrieved. + * @note It is possible to receive items with a pxItemSize of 0 on no-split/allow split buffers. * * @return * - Pointer to the retrieved item on success; *pxItemSize filled with the length of the item. @@ -236,6 +247,7 @@ void *xRingbufferReceive(RingbufHandle_t xRingbuffer, size_t *pxItemSize, TickTy * @note A call to vRingbufferReturnItemFromISR() is required after this to free the item retrieved. * @note Byte buffers do not allow multiple retrievals before returning an item * @note Two calls to RingbufferReceiveFromISR() are required if the bytes wrap around the end of the ring buffer. + * @note It is possible to receive items with a pxItemSize of 0 on no-split/allow split buffers. * * @return * - Pointer to the retrieved item on success; *pxItemSize filled with the length of the item. @@ -260,6 +272,7 @@ void *xRingbufferReceiveFromISR(RingbufHandle_t xRingbuffer, size_t *pxItemSize) * * @note Call(s) to vRingbufferReturnItem() is required after this to free up the item(s) retrieved. * @note This function should only be called on allow-split buffers + * @note It is possible to receive items with a pxItemSize of 0 on allow split buffers. * * @return * - pdTRUE if an item (split or unsplit) was retrieved @@ -288,6 +301,7 @@ BaseType_t xRingbufferReceiveSplit(RingbufHandle_t xRingbuffer, * * @note Calls to vRingbufferReturnItemFromISR() is required after this to free up the item(s) retrieved. * @note This function should only be called on allow-split buffers + * @note It is possible to receive items with a pxItemSize of 0 on allow split buffers. * * @return * - pdTRUE if an item (split or unsplit) was retrieved @@ -336,7 +350,7 @@ void *xRingbufferReceiveUpTo(RingbufHandle_t xRingbuffer, * * @param[in] xRingbuffer Ring buffer to retrieve the item from * @param[out] pxItemSize Pointer to a variable to which the size of the retrieved item will be written. - * @param[in] xMaxSize Maximum number of bytes to return. + * @param[in] xMaxSize Maximum number of bytes to return. Size of 0 simply returns NULL. * * @note A call to vRingbufferReturnItemFromISR() is required after this to free up the data received. * @note This function should only be called on byte buffers diff --git a/components/esp_ringbuf/ringbuf.c b/components/esp_ringbuf/ringbuf.c index abe296e125..0f9ab40bdc 100644 --- a/components/esp_ringbuf/ringbuf.c +++ b/components/esp_ringbuf/ringbuf.c @@ -982,7 +982,7 @@ BaseType_t xRingbufferSendAcquire(RingbufHandle_t xRingbuffer, void **ppvItem, s //Check arguments configASSERT(pxRingbuffer); - configASSERT(ppvItem != NULL || xItemSize == 0); + configASSERT(ppvItem != NULL); configASSERT((pxRingbuffer->uxRingbufferFlags & (rbBYTE_BUFFER_FLAG | rbALLOW_SPLIT_FLAG)) == 0); //Send acquire currently only supported in NoSplit buffers *ppvItem = NULL; @@ -1089,7 +1089,7 @@ BaseType_t xRingbufferSendFromISR(RingbufHandle_t xRingbuffer, xReturn = pdFALSE; } portEXIT_CRITICAL_ISR(&pxRingbuffer->mux); - + //Defer notifying the queue set until we are outside the critical section. if (xNotifyQueueSet == pdTRUE) { xQueueSendFromISR((QueueHandle_t)pxRingbuffer->xQueueSet, (QueueSetMemberHandle_t *)&pxRingbuffer, pxHigherPriorityTaskWoken); } diff --git a/components/esp_ringbuf/test_apps/main/test_ringbuf.c b/components/esp_ringbuf/test_apps/main/test_ringbuf.c index 8264b6fb06..09fdc04f02 100644 --- a/components/esp_ringbuf/test_apps/main/test_ringbuf.c +++ b/components/esp_ringbuf/test_apps/main/test_ringbuf.c @@ -1046,3 +1046,49 @@ TEST_CASE("Test ringbuffer functions work with flash cache disabled", "[esp_ring TEST_ASSERT( iram_ringbuf_test() ); } #endif /* !CONFIG_RINGBUF_PLACE_FUNCTIONS_INTO_FLASH && !CONFIG_RINGBUF_PLACE_ISR_FUNCTIONS_INTO_FLASH */ + +/* ------------------------ Test ring buffer 0 Item Size ----------------------- + * The following test case tests that sending/acquiring an item/bytes of 0 size + * is permissible. + */ + +TEST_CASE("Test ringbuffer 0 item size", "[esp_ringbuf]") +{ + RingbufHandle_t no_split_rb = xRingbufferCreate(BUFFER_SIZE, RINGBUF_TYPE_NOSPLIT); + RingbufHandle_t allow_split_rb = xRingbufferCreate(BUFFER_SIZE, RINGBUF_TYPE_ALLOWSPLIT); + RingbufHandle_t byte_rb = xRingbufferCreate(BUFFER_SIZE, RINGBUF_TYPE_BYTEBUF); + TEST_ASSERT_MESSAGE(no_split_rb && allow_split_rb && byte_rb, "Failed to create ring buffers"); + + void *pvItem1; + void *pvItem2; + size_t xItemSize1; + size_t xItemSize2; + + //Test that 0 item size on no split buffers should only send a header with no data + TEST_ASSERT_EQUAL(pdTRUE, xRingbufferSend(no_split_rb, NULL, 0, 0)); + TEST_ASSERT_NOT_EQUAL(NULL, xRingbufferReceive(no_split_rb, &xItemSize1, 0)); + TEST_ASSERT_EQUAL(0, xItemSize1); + + //Test that acquiring 0 item size on no split buffers should only send a header without reserving a data buffer + TEST_ASSERT_EQUAL(pdTRUE, xRingbufferSendAcquire(no_split_rb, &pvItem1, 0, 0)); + TEST_ASSERT_NOT_EQUAL(NULL, pvItem1); + TEST_ASSERT_EQUAL(pdTRUE, xRingbufferSendComplete(no_split_rb, pvItem1)); + TEST_ASSERT_NOT_EQUAL(NULL, xRingbufferReceive(no_split_rb, &xItemSize1, 0)); + TEST_ASSERT_EQUAL(0, xItemSize1); + + //Test that 0 item size on allow split buffers should only send a header with no data + TEST_ASSERT_EQUAL(pdTRUE, xRingbufferSend(allow_split_rb, NULL, 0, 0)); + TEST_ASSERT_EQUAL(pdTRUE, xRingbufferReceiveSplit(allow_split_rb, &pvItem1, &pvItem2, &xItemSize1, &xItemSize2, 0)); + TEST_ASSERT_NOT_EQUAL(NULL, pvItem1); + TEST_ASSERT_EQUAL(NULL, pvItem2); + TEST_ASSERT_EQUAL(0, xItemSize1); + + //Test that 0 item size on byte buffers should send nothing + TEST_ASSERT_EQUAL(pdTRUE, xRingbufferSend(byte_rb, NULL, 0, 0)); + TEST_ASSERT_EQUAL(pdFALSE, xRingbufferReceiveUpTo(byte_rb, &xItemSize1, 0, BUFFER_SIZE)); + + //Cleanup + vRingbufferDelete(no_split_rb); + vRingbufferDelete(allow_split_rb); + vRingbufferDelete(byte_rb); +}