From 589d5b132daccd272668e715c49437b5fac23464 Mon Sep 17 00:00:00 2001 From: Darian Leung <32921628+Dazza0@users.noreply.github.com> Date: Tue, 2 Sep 2025 21:27:05 +0800 Subject: [PATCH 1/2] feat(esp_ringbuf): Add vRingbufferReset Function has similar behavior to xQueueReset() where... - Buffer is emptied - Blocked sender is unblocked Aslo added associated unit test cases. --- .../esp_ringbuf/include/freertos/ringbuf.h | 9 +++ components/esp_ringbuf/ringbuf.c | 26 ++++++++ .../test_apps/main/test_ringbuf_common.c | 60 +++++++++++++++++++ 3 files changed, 95 insertions(+) diff --git a/components/esp_ringbuf/include/freertos/ringbuf.h b/components/esp_ringbuf/include/freertos/ringbuf.h index 6791975072..ba9f0696dd 100644 --- a/components/esp_ringbuf/include/freertos/ringbuf.h +++ b/components/esp_ringbuf/include/freertos/ringbuf.h @@ -386,6 +386,15 @@ void vRingbufferReturnItem(RingbufHandle_t xRingbuffer, void *pvItem); */ void vRingbufferReturnItemFromISR(RingbufHandle_t xRingbuffer, void *pvItem, BaseType_t *pxHigherPriorityTaskWoken); +/** + * @brief Reset a ring buffer back to its original empty state + * + * @param[in] xRingbuffer Ring buffer to reset + * + * @note Users must ensure that all buffers are returned before calling this function + */ +void vRingbufferReset(RingbufHandle_t xRingbuffer); + /** * @brief Delete a ring buffer * diff --git a/components/esp_ringbuf/ringbuf.c b/components/esp_ringbuf/ringbuf.c index f205f9afad..85f4142f1e 100644 --- a/components/esp_ringbuf/ringbuf.c +++ b/components/esp_ringbuf/ringbuf.c @@ -1252,6 +1252,32 @@ void vRingbufferReturnItemFromISR(RingbufHandle_t xRingbuffer, void *pvItem, Bas portEXIT_CRITICAL_ISR(&pxRingbuffer->mux); } +void vRingbufferReset(RingbufHandle_t xRingbuffer) +{ + Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer; + configASSERT(pxRingbuffer); + + portENTER_CRITICAL(&pxRingbuffer->mux); + // Check for unreturned buffers + configASSERT(pxRingbuffer->pucAcquire == pxRingbuffer->pucWrite); + configASSERT(pxRingbuffer->pucRead == pxRingbuffer->pucFree); + // Reset state + pxRingbuffer->pucAcquire = pxRingbuffer->pucHead; + pxRingbuffer->pucWrite = pxRingbuffer->pucHead; + pxRingbuffer->pucRead = pxRingbuffer->pucHead; + pxRingbuffer->pucFree = pxRingbuffer->pucHead; + pxRingbuffer->xItemsWaiting = 0; + pxRingbuffer->uxRingbufferFlags &= ~rbBUFFER_FULL_FLAG; + + // If there's a task waiting to transmit, unblock it + if (listLIST_IS_EMPTY(&pxRingbuffer->xTasksWaitingToSend) == pdFALSE) { + if (xTaskRemoveFromEventList(&pxRingbuffer->xTasksWaitingToSend) == pdTRUE) { + portYIELD_WITHIN_API(); + } + } + portEXIT_CRITICAL(&pxRingbuffer->mux); +} + void vRingbufferDelete(RingbufHandle_t xRingbuffer) { Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer; diff --git a/components/esp_ringbuf/test_apps/main/test_ringbuf_common.c b/components/esp_ringbuf/test_apps/main/test_ringbuf_common.c index 028671dbe0..64418c1d58 100644 --- a/components/esp_ringbuf/test_apps/main/test_ringbuf_common.c +++ b/components/esp_ringbuf/test_apps/main/test_ringbuf_common.c @@ -20,6 +20,7 @@ #include "freertos/ringbuf.h" #include "unity.h" #include "esp_rom_sys.h" +#include "esp_task.h" #include "test_functions.h" @@ -1318,3 +1319,62 @@ TEST_CASE("Test no-split full buffer becomes empty when oldest is returned last" TEST_ASSERT_NOT_NULL(slot); vRingbufferDelete(buffer_handle); } + +/* ----------------------------------- Test ring buffer reset -------------------------------------- + * Reset Case: Test that vRingbufferReset() empties the ring buffer + * Reset unblocks sender: Test that vRingbufferReset() will unblock a previously blocked sender + */ + +static uint8_t item[SMALL_ITEM_SIZE] = {0}; + +TEST_CASE("Test ring buffer reset", "[esp_ringbuf][linux]") +{ + // Create buffer + RingbufHandle_t rb = xRingbufferCreate(SMALL_ITEM_SIZE, RINGBUF_TYPE_BYTEBUF); + TEST_ASSERT_MESSAGE(rb != NULL, "Failed to create ring buffer"); + // Fill buffer + TEST_ASSERT_EQUAL(pdTRUE, xRingbufferSend(rb, item, SMALL_ITEM_SIZE, 0)); + // Confirm buffer is full + TEST_ASSERT_EQUAL(0, xRingbufferGetCurFreeSize(rb)); + // Reset ring buffer + vRingbufferReset(rb); + // Confirm buffer is empty + TEST_ASSERT_EQUAL(SMALL_ITEM_SIZE, xRingbufferGetCurFreeSize(rb)); + // Cleanup + vRingbufferDelete(rb); +} + +static volatile bool post_reset_send = false; + +static void post_reset_send_task(void *arg) +{ + RingbufHandle_t rb = (RingbufHandle_t)arg; + TEST_ASSERT_EQUAL(pdTRUE, xRingbufferSend(rb, item, SMALL_ITEM_SIZE, portMAX_DELAY)); + post_reset_send = true; + vTaskDelete(NULL); +} + +TEST_CASE("Test ring buffer reset unblocks sender ", "[esp_ringbuf][linux]") +{ + // Create buffer + RingbufHandle_t rb = xRingbufferCreate(SMALL_ITEM_SIZE, RINGBUF_TYPE_BYTEBUF); + TEST_ASSERT_MESSAGE(rb != NULL, "Failed to create ring buffer"); + // Fill buffer + TEST_ASSERT_EQUAL(pdTRUE, xRingbufferSend(rb, item, SMALL_ITEM_SIZE, 0)); + // Confirm buffer is full + TEST_ASSERT_EQUAL(0, xRingbufferGetCurFreeSize(rb)); + // Launch task to block on sending to full ring buffer + post_reset_send = false; + xTaskCreatePinnedToCore(post_reset_send_task, "send tsk", 2048, (void*)rb, ESP_TASK_MAIN_PRIO + 1, NULL, 0); + vTaskDelay(10); + // Confirm blocked task has not sent + TEST_ASSERT_EQUAL(false, post_reset_send); + // Reset the ring buffer + vRingbufferReset(rb); + // Check task has unblocked and sent + vTaskDelay(1); + TEST_ASSERT_EQUAL(true, post_reset_send); + // Cleanup + vRingbufferDelete(rb); + vTaskDelay(1); +} From c03987ca4918bf280a549d7443555ea8821f741e Mon Sep 17 00:00:00 2001 From: Guillaume Souchere Date: Tue, 23 Sep 2025 08:38:22 +0200 Subject: [PATCH 2/2] feat(esp_ringbuf): Update vRingbufferReset to return an error when items are not sent, complete or returned, make the function return an error instead of checking the state in an assert. --- components/esp_ringbuf/include/freertos/ringbuf.h | 5 +++-- components/esp_ringbuf/ringbuf.c | 12 +++++++++--- .../esp_ringbuf/test_apps/main/test_ringbuf_common.c | 3 +-- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/components/esp_ringbuf/include/freertos/ringbuf.h b/components/esp_ringbuf/include/freertos/ringbuf.h index ba9f0696dd..02d252afbf 100644 --- a/components/esp_ringbuf/include/freertos/ringbuf.h +++ b/components/esp_ringbuf/include/freertos/ringbuf.h @@ -391,9 +391,10 @@ void vRingbufferReturnItemFromISR(RingbufHandle_t xRingbuffer, void *pvItem, Bas * * @param[in] xRingbuffer Ring buffer to reset * - * @note Users must ensure that all buffers are returned before calling this function + * @return ESP_ERR_INVALID_STATE if one or more items are not sent, completed or returned + * ESP_OK if the operation was successful */ -void vRingbufferReset(RingbufHandle_t xRingbuffer); +esp_err_t vRingbufferReset(RingbufHandle_t xRingbuffer); /** * @brief Delete a ring buffer diff --git a/components/esp_ringbuf/ringbuf.c b/components/esp_ringbuf/ringbuf.c index 85f4142f1e..7addde73a4 100644 --- a/components/esp_ringbuf/ringbuf.c +++ b/components/esp_ringbuf/ringbuf.c @@ -1252,15 +1252,19 @@ void vRingbufferReturnItemFromISR(RingbufHandle_t xRingbuffer, void *pvItem, Bas portEXIT_CRITICAL_ISR(&pxRingbuffer->mux); } -void vRingbufferReset(RingbufHandle_t xRingbuffer) +esp_err_t vRingbufferReset(RingbufHandle_t xRingbuffer) { Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer; configASSERT(pxRingbuffer); portENTER_CRITICAL(&pxRingbuffer->mux); // Check for unreturned buffers - configASSERT(pxRingbuffer->pucAcquire == pxRingbuffer->pucWrite); - configASSERT(pxRingbuffer->pucRead == pxRingbuffer->pucFree); + if ((pxRingbuffer->pucAcquire != pxRingbuffer->pucWrite) || + (pxRingbuffer->pucRead != pxRingbuffer->pucFree)) { + portEXIT_CRITICAL(&pxRingbuffer->mux); + return ESP_ERR_INVALID_STATE; + } + // Reset state pxRingbuffer->pucAcquire = pxRingbuffer->pucHead; pxRingbuffer->pucWrite = pxRingbuffer->pucHead; @@ -1276,6 +1280,8 @@ void vRingbufferReset(RingbufHandle_t xRingbuffer) } } portEXIT_CRITICAL(&pxRingbuffer->mux); + + return ESP_OK; } void vRingbufferDelete(RingbufHandle_t xRingbuffer) diff --git a/components/esp_ringbuf/test_apps/main/test_ringbuf_common.c b/components/esp_ringbuf/test_apps/main/test_ringbuf_common.c index 64418c1d58..c5e81d7a4c 100644 --- a/components/esp_ringbuf/test_apps/main/test_ringbuf_common.c +++ b/components/esp_ringbuf/test_apps/main/test_ringbuf_common.c @@ -1371,8 +1371,7 @@ TEST_CASE("Test ring buffer reset unblocks sender ", "[esp_ringbuf][linux]") TEST_ASSERT_EQUAL(false, post_reset_send); // Reset the ring buffer vRingbufferReset(rb); - // Check task has unblocked and sent - vTaskDelay(1); + TEST_ASSERT_EQUAL(true, post_reset_send); // Cleanup vRingbufferDelete(rb);