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.
This commit is contained in:
Darian Leung
2025-09-02 21:27:05 +08:00
committed by Guillaume Souchere
parent 13ec7d2d2a
commit 589d5b132d
3 changed files with 95 additions and 0 deletions

View File

@@ -386,6 +386,15 @@ void vRingbufferReturnItem(RingbufHandle_t xRingbuffer, void *pvItem);
*/ */
void vRingbufferReturnItemFromISR(RingbufHandle_t xRingbuffer, void *pvItem, BaseType_t *pxHigherPriorityTaskWoken); 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 * @brief Delete a ring buffer
* *

View File

@@ -1252,6 +1252,32 @@ void vRingbufferReturnItemFromISR(RingbufHandle_t xRingbuffer, void *pvItem, Bas
portEXIT_CRITICAL_ISR(&pxRingbuffer->mux); 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) void vRingbufferDelete(RingbufHandle_t xRingbuffer)
{ {
Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer; Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer;

View File

@@ -20,6 +20,7 @@
#include "freertos/ringbuf.h" #include "freertos/ringbuf.h"
#include "unity.h" #include "unity.h"
#include "esp_rom_sys.h" #include "esp_rom_sys.h"
#include "esp_task.h"
#include "test_functions.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); TEST_ASSERT_NOT_NULL(slot);
vRingbufferDelete(buffer_handle); 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);
}