Преглед изворни кода

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
Sudeep Mohanty пре 4 година
родитељ
комит
6e0fae9878
3 измењених фајлова са 417 додато и 30 уклоњено
  1. 1 6
      .gitlab-ci.yml
  2. 48 13
      components/esp_ringbuf/ringbuf.c
  3. 368 11
      components/esp_ringbuf/test/test_ringbuf.c

+ 1 - 6
.gitlab-ci.yml

@@ -1306,12 +1306,7 @@ UT_029:
 
 UT_030:
   <<: *unit_test_template
-  tags:
-    - ESP32_IDF
-    - UT_T1_1
-
-UT_031:
-  <<: *unit_test_template
+  parallel: 3
   tags:
     - ESP32_IDF
     - UT_T1_1

+ 48 - 13
components/esp_ringbuf/ringbuf.c

@@ -97,22 +97,52 @@ 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, size_t *pxItemSize);
 
 //Retrieve data from byte buffer. If xMaxSize is 0, all continuous data is retrieved
 static void *prvGetItemByteBuf(Ringbuffer_t *pxRingbuffer, BaseType_t *pxUnusedParam ,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
@@ -356,7 +386,7 @@ static void *prvGetItemDefault(Ringbuffer_t *pxRingbuffer, BaseType_t *pxIsSplit
         //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
@@ -443,7 +473,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;
         }
@@ -494,12 +524,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;
 }
@@ -524,11 +557,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;
 }

+ 368 - 11
components/esp_ringbuf/test/test_ringbuf.c

@@ -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"
@@ -15,7 +21,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};
@@ -35,6 +42,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
@@ -71,7 +89,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");
 
@@ -157,19 +174,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", "[freertos]")
+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);
 
@@ -177,11 +212,21 @@ TEST_CASE("Test ring buffer No-Split", "[freertos]")
     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, &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, &items_waiting);
+    TEST_ASSERT_MESSAGE(items_waiting == 0, "Incorrect items waiting");
+
     //Write pointer should be near the end, test wrap around
     uint32_t write_pos_before, write_pos_after;
     vRingbufferGetInfo(buffer_handle, NULL, NULL, &write_pos_before, NULL);
@@ -196,11 +241,112 @@ TEST_CASE("Test ring buffer No-Split", "[freertos]")
     vRingbufferDelete(buffer_handle);
 }
 
-TEST_CASE("Test ring buffer Allow-Split", "[freertos]")
+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, &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, &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, &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, &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);
 
@@ -208,11 +354,21 @@ TEST_CASE("Test ring buffer Allow-Split", "[freertos]")
     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, &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, &items_waiting);
+    TEST_ASSERT_MESSAGE(items_waiting == 0, "Incorrect items waiting");
+
     //Write pointer should be near the end, test wrap around
     uint32_t write_pos_before, write_pos_after;
     vRingbufferGetInfo(buffer_handle, NULL, NULL, &write_pos_before, NULL);
@@ -227,11 +383,112 @@ TEST_CASE("Test ring buffer Allow-Split", "[freertos]")
     vRingbufferDelete(buffer_handle);
 }
 
-TEST_CASE("Test ring buffer Byte Buffer", "[freertos]")
+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, &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, &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, &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, &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;
 
@@ -239,11 +496,21 @@ TEST_CASE("Test ring buffer Byte Buffer", "[freertos]")
     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, &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, &items_waiting);
+    TEST_ASSERT_MESSAGE(items_waiting == 0, "Incorrect number of bytes waiting");
+
     //Write pointer should be near the end, test wrap around
     uint32_t write_pos_before, write_pos_after;
     vRingbufferGetInfo(buffer_handle, NULL, NULL, &write_pos_before, NULL);
@@ -258,6 +525,96 @@ TEST_CASE("Test ring buffer Byte Buffer", "[freertos]")
     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, &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, &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, &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, &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...