1 /*
2  * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include "freertos/FreeRTOS.h"
10 #include "freertos/task.h"
11 #include "freertos/queue.h"
12 #include "freertos/semphr.h"
13 #include "freertos/ringbuf.h"
14 #include "driver/timer.h"
15 #include "esp_heap_caps.h"
16 #include "esp_spi_flash.h"
17 #include "unity.h"
18 #include "test_utils.h"
19 #include "esp_rom_sys.h"
20 
21 //Definitions used in multiple test cases
22 #define TIMEOUT_TICKS               10
23 #define NO_OF_RB_TYPES              3
24 #define ITEM_HDR_SIZE               8
25 #define SMALL_ITEM_SIZE             8
26 #define MEDIUM_ITEM_SIZE            ((3 * SMALL_ITEM_SIZE) >> 1)  //12 bytes
27 #define LARGE_ITEM_SIZE             (2 * SMALL_ITEM_SIZE)  //16 bytes
28 #define BUFFER_SIZE                 160     //4Byte aligned size
29 
30 static const uint8_t small_item[SMALL_ITEM_SIZE] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
31 static const uint8_t large_item[LARGE_ITEM_SIZE] = { 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
32                                                      0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17};
33 static RingbufHandle_t buffer_handles[NO_OF_RB_TYPES];
34 static SemaphoreHandle_t done_sem;
35 
send_item_and_check(RingbufHandle_t handle,const uint8_t * item,size_t item_size,TickType_t ticks_to_wait,bool in_isr)36 static void send_item_and_check(RingbufHandle_t handle, const uint8_t *item,  size_t item_size, TickType_t ticks_to_wait, bool in_isr)
37 {
38     BaseType_t ret;
39     if (in_isr) {
40         ret = xRingbufferSendFromISR(handle, (void *)item, item_size, NULL);
41     } else {
42         ret = xRingbufferSend(handle, (void *)item, item_size, ticks_to_wait);
43     }
44     TEST_ASSERT_MESSAGE(ret == pdTRUE, "Failed to send item");
45 }
46 
send_item_and_check_failure(RingbufHandle_t handle,const uint8_t * item,size_t item_size,TickType_t ticks_to_wait,bool in_isr)47 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)
48 {
49     BaseType_t ret;
50     if (in_isr) {
51         ret = xRingbufferSendFromISR(handle, (void *)item, item_size, NULL);
52     } else {
53         ret = xRingbufferSend(handle, (void *)item, item_size, ticks_to_wait);
54     }
55     TEST_ASSERT_MESSAGE(ret == pdFALSE, "Sent an item to a full buffer");
56 }
57 
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)58 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)
59 {
60     //Receive item from no-split buffer
61     size_t item_size;
62     uint8_t *item;
63     if (in_isr) {
64         item = (uint8_t *)xRingbufferReceiveFromISR(handle, &item_size);
65     } else {
66         item = (uint8_t *)xRingbufferReceive(handle, &item_size, ticks_to_wait);
67     }
68     TEST_ASSERT_MESSAGE(item != NULL, "Failed to receive item");
69     TEST_ASSERT_MESSAGE(item_size == expected_size, "Item size is incorrect");
70     //Check data of received item
71     for (int i = 0; i < item_size; i++) {
72         TEST_ASSERT_MESSAGE(item[i] == expected_data[i], "Item data is invalid");
73     }
74     //Return item
75     if (in_isr) {
76         vRingbufferReturnItemFromISR(handle, (void *)item, NULL);
77     } else {
78         vRingbufferReturnItem(handle, (void *)item);
79     }
80 
81 }
82 
receive_check_and_return_item_allow_split(RingbufHandle_t handle,const uint8_t * expected_data,size_t expected_size,TickType_t ticks_to_wait,bool in_isr)83 static void receive_check_and_return_item_allow_split(RingbufHandle_t handle, const uint8_t *expected_data, size_t expected_size, TickType_t ticks_to_wait, bool in_isr)
84 {
85     //Receive item
86     size_t item_size1, item_size2;
87     uint8_t *item1, *item2;
88     BaseType_t ret;
89     if (in_isr) {
90         ret = xRingbufferReceiveSplitFromISR(handle, (void**)&item1, (void **)&item2, &item_size1, &item_size2);
91     } else {
92         ret = xRingbufferReceiveSplit(handle, (void**)&item1, (void **)&item2, &item_size1, &item_size2, ticks_to_wait);
93     }
94     TEST_ASSERT_MESSAGE(ret == pdTRUE, "Failed to receive item");
95     TEST_ASSERT_MESSAGE(item1 != NULL, "Failed to receive item");
96 
97     //Check data of received item(s) and return them
98     if (item2 == NULL) {
99         TEST_ASSERT_MESSAGE(item_size1 == expected_size, "Item size is incorrect");
100         for (int i = 0; i < item_size1; i++) {
101             TEST_ASSERT_MESSAGE(item1[i] == expected_data[i], "Item data is invalid");
102         }
103         //Return item
104         if (in_isr) {
105             vRingbufferReturnItemFromISR(handle, (void *)item1, NULL);
106         } else {
107             vRingbufferReturnItem(handle, (void *)item1);
108         }
109     } else {
110         //Item was split
111         TEST_ASSERT_MESSAGE(item_size1 + item_size2 == expected_size, "Total item size is incorrect");
112         for (int i = 0; i < item_size1; i++) {
113             TEST_ASSERT_MESSAGE(item1[i] == expected_data[i], "Head item data is invalid");
114         }
115         for (int i = 0; i < item_size2; i++) {
116             TEST_ASSERT_MESSAGE(item2[i] == expected_data[item_size1 + i], "Head item data is invalid");
117         }
118         //Return Items
119         if (in_isr) {
120             vRingbufferReturnItemFromISR(handle, (void *)item1, NULL);
121             vRingbufferReturnItemFromISR(handle, (void *)item2, NULL);
122         } else {
123             vRingbufferReturnItem(handle, (void *)item1);
124             vRingbufferReturnItem(handle, (void *)item2);
125         }
126     }
127 }
128 
receive_check_and_return_item_byte_buffer(RingbufHandle_t handle,const uint8_t * expected_data,size_t expected_size,TickType_t ticks_to_wait,bool in_isr)129 static void receive_check_and_return_item_byte_buffer(RingbufHandle_t handle, const uint8_t *expected_data, size_t expected_size, TickType_t ticks_to_wait, bool in_isr)
130 {
131     //Receive item
132     size_t item_size;
133     uint8_t *item;
134     if (in_isr) {
135         item = (uint8_t *)xRingbufferReceiveUpToFromISR(handle, &item_size, expected_size);
136     } else {
137         item = (uint8_t *)xRingbufferReceiveUpTo(handle, &item_size, ticks_to_wait, expected_size);   //Limit amount of bytes returned to the size of one item
138     }
139     TEST_ASSERT_MESSAGE(item != NULL, "Failed to receive item");
140 
141     //Check data of received item
142     for (int i = 0; i < item_size; i++) {
143         TEST_ASSERT_MESSAGE(item[i] == expected_data[i], "Item data is invalid");
144     }
145     //Return item
146     if (in_isr) {
147         vRingbufferReturnItemFromISR(handle, (void *)item, NULL);
148     } else {
149         vRingbufferReturnItem(handle, (void *)item);
150     }
151 
152     //Check if item wrapped around
153     if (item_size < expected_size) {
154         //Item is wrapped, receive second portion
155         size_t item_size2;
156         uint8_t *item2;
157         if (in_isr) {
158             item2 = (uint8_t *)xRingbufferReceiveUpToFromISR(handle, &item_size2, expected_size - item_size);
159         } else {
160             item2 = (uint8_t *)xRingbufferReceiveUpTo(handle, &item_size2, ticks_to_wait, expected_size - item_size);
161         }
162         //= (uint8_t *)xRingbufferReceiveUpTo(handle, &item_size2, ticks_to_wait, expected_size - item_size);
163         TEST_ASSERT_MESSAGE(item2 != NULL, "Failed to receive item");
164         TEST_ASSERT_MESSAGE(item_size + item_size2 == expected_size, "Total item size is incorrect");
165         for (int i = 0; i < item_size2; i++) {
166             TEST_ASSERT_MESSAGE(item2[i] == expected_data[item_size + i], "Item data is invalid");
167         }
168         if (in_isr) {
169             vRingbufferReturnItemFromISR(handle, (void *)item2, NULL);
170         } else {
171             vRingbufferReturnItem(handle, (void *)item2);
172         }
173     } else {
174         TEST_ASSERT_MESSAGE(item_size == expected_size, "Item size is incorrect");
175     }
176 }
177 
178 /* ----------------- Basic ring buffer behavior tests cases --------------------
179  * The following set of test cases will test basic send, receive, wrap around and buffer full
180  * behavior of each type of ring buffer.
181  * Test Case 1:
182  *     1) Send multiple items (nearly fill the buffer)
183  *     2) Receive and check the sent items (also prepares the buffer for a wrap around)
184  *     3) Send a final item that causes a wrap around
185  *     4) Receive and check the wrapped item
186  *
187  * Test Case 2:
188  *     1) Send multiple items (completely fill the buffer)
189  *     2) Send another item and verify that send failure occurs
190  *     3) Receive one item and verify that space is freed up in the buffer
191  *     4) Receive and check the remaining sent items
192  *
193  * Test Case 3:
194  *     1) Send multiple items (nearly fill the buffer)
195  *     2) Send another small sized item to fill the buffer without causing a wrap around (not needed in case of byte buffer)
196  *     2) Send another item and verify that send failure occurs
197  *     4) Receive and check the sent items
198  */
199 
200 TEST_CASE("TC#1: No-Split", "[esp_ringbuf]")
201 {
202     //Create buffer
203     RingbufHandle_t buffer_handle = xRingbufferCreate(BUFFER_SIZE, RINGBUF_TYPE_NOSPLIT);
204     TEST_ASSERT_MESSAGE(buffer_handle != NULL, "Failed to create ring buffer");
205 
206     //Check buffer free size and max item size upon buffer creation. Should be BUFFER_SIZE/2 - ITEM_HDR_SIZE.
207     TEST_ASSERT_MESSAGE(xRingbufferGetCurFreeSize(buffer_handle) == ((BUFFER_SIZE >> 1) - ITEM_HDR_SIZE), "Incorrect buffer free size received");
208     TEST_ASSERT_MESSAGE(xRingbufferGetMaxItemSize(buffer_handle) == ((BUFFER_SIZE >> 1) - ITEM_HDR_SIZE), "Incorrect max item size received");
209 
210     //Calculate number of items to send. Aim to almost fill buffer to setup for wrap around
211     int no_of_items = (BUFFER_SIZE - (ITEM_HDR_SIZE + SMALL_ITEM_SIZE)) / (ITEM_HDR_SIZE + SMALL_ITEM_SIZE);
212 
213     //Test sending items
214     for (int i = 0; i < no_of_items; i++) {
215         send_item_and_check(buffer_handle, small_item, SMALL_ITEM_SIZE, TIMEOUT_TICKS, false);
216     }
217 
218     //Verify items waiting matches with the number of items sent
219     UBaseType_t items_waiting;
220     vRingbufferGetInfo(buffer_handle, NULL, NULL, NULL, NULL, &items_waiting);
221     TEST_ASSERT_MESSAGE(items_waiting == no_of_items, "Incorrect items waiting");
222 
223     //Test receiving items
224     for (int i = 0; i < no_of_items; i++) {
225         receive_check_and_return_item_no_split(buffer_handle, small_item, SMALL_ITEM_SIZE, TIMEOUT_TICKS, false);
226     }
227 
228     //Verify that no items are waiting
229     vRingbufferGetInfo(buffer_handle, NULL, NULL, NULL, NULL, &items_waiting);
230     TEST_ASSERT_MESSAGE(items_waiting == 0, "Incorrect items waiting");
231 
232     //Write pointer should be near the end, test wrap around
233     UBaseType_t write_pos_before, write_pos_after;
234     vRingbufferGetInfo(buffer_handle, NULL, NULL, &write_pos_before, NULL, NULL);
235     //Send large item that causes wrap around
236     send_item_and_check(buffer_handle, large_item, LARGE_ITEM_SIZE, TIMEOUT_TICKS, false);
237     //Receive wrapped item
238     receive_check_and_return_item_no_split(buffer_handle, large_item, LARGE_ITEM_SIZE, TIMEOUT_TICKS, false);
239     vRingbufferGetInfo(buffer_handle, NULL, NULL, &write_pos_after, NULL, NULL);
240     TEST_ASSERT_MESSAGE(write_pos_after < write_pos_before, "Failed to wrap around");
241 
242     //Cleanup
243     vRingbufferDelete(buffer_handle);
244 }
245 
246 TEST_CASE("TC#2: No-Split", "[esp_ringbuf]")
247 {
248     //Create buffer
249     RingbufHandle_t buffer_handle = xRingbufferCreate(BUFFER_SIZE, RINGBUF_TYPE_NOSPLIT);
250     TEST_ASSERT_MESSAGE(buffer_handle != NULL, "Failed to create ring buffer");
251 
252     //Check buffer free size and max item size upon buffer creation. Should be BUFFER_SIZE/2 - ITEM_HDR_SIZE.
253     TEST_ASSERT_MESSAGE(xRingbufferGetCurFreeSize(buffer_handle) == ((BUFFER_SIZE >> 1) - ITEM_HDR_SIZE), "Incorrect buffer free size received");
254     TEST_ASSERT_MESSAGE(xRingbufferGetMaxItemSize(buffer_handle) == ((BUFFER_SIZE >> 1) - ITEM_HDR_SIZE), "Incorrect max item size received");
255 
256     //Calculate number of items to send. Aim to fill the buffer
257     int no_of_items = (BUFFER_SIZE) / (ITEM_HDR_SIZE + SMALL_ITEM_SIZE);
258 
259     //Test sending items
260     for (int i = 0; i < no_of_items; i++) {
261         send_item_and_check(buffer_handle, small_item, SMALL_ITEM_SIZE, TIMEOUT_TICKS, false);
262     }
263 
264     //Verify items waiting matches with the number of items sent
265     UBaseType_t items_waiting;
266     vRingbufferGetInfo(buffer_handle, NULL, NULL, NULL, NULL, &items_waiting);
267     TEST_ASSERT_MESSAGE(items_waiting == no_of_items, "Incorrect items waiting");
268 
269     //At this point, the buffer should be full.
270     TEST_ASSERT_MESSAGE(xRingbufferGetCurFreeSize(buffer_handle) == 0, "Buffer full not achieved");
271 
272     //Send an item. The item should not be sent to a full buffer.
273     send_item_and_check_failure(buffer_handle, small_item, SMALL_ITEM_SIZE, TIMEOUT_TICKS, false);
274 
275     //Receive one item
276     receive_check_and_return_item_no_split(buffer_handle, small_item, SMALL_ITEM_SIZE, TIMEOUT_TICKS, false);
277 
278     //At this point, the buffer should not be full any more
279     TEST_ASSERT_MESSAGE(xRingbufferGetCurFreeSize(buffer_handle) > 0, "Buffer should have free space");
280 
281     //Test receiving remaining items
282     for (int i = 0; i < no_of_items - 1; i++) {
283         receive_check_and_return_item_no_split(buffer_handle, small_item, SMALL_ITEM_SIZE, TIMEOUT_TICKS, false);
284     }
285 
286     //Verify that no items are waiting
287     vRingbufferGetInfo(buffer_handle, NULL, NULL, NULL, NULL, &items_waiting);
288     TEST_ASSERT_MESSAGE(items_waiting == 0, "Incorrect items waiting");
289 
290     //Cleanup
291     vRingbufferDelete(buffer_handle);
292 }
293 
294 TEST_CASE("TC#3: No-Split", "[esp_ringbuf]")
295 {
296     //Create buffer
297     RingbufHandle_t buffer_handle = xRingbufferCreate(BUFFER_SIZE, RINGBUF_TYPE_NOSPLIT);
298     TEST_ASSERT_MESSAGE(buffer_handle != NULL, "Failed to create ring buffer");
299 
300     //Check buffer free size and max item size upon buffer creation. Should be BUFFER_SIZE/2 - ITEM_HDR_SIZE.
301     TEST_ASSERT_MESSAGE(xRingbufferGetCurFreeSize(buffer_handle) == ((BUFFER_SIZE >> 1) - ITEM_HDR_SIZE), "Incorrect buffer free size received");
302     TEST_ASSERT_MESSAGE(xRingbufferGetMaxItemSize(buffer_handle) == ((BUFFER_SIZE >> 1) - ITEM_HDR_SIZE), "Incorrect max item size received");
303 
304     //Calculate number of medium items to send. Aim to almost fill the buffer
305     int no_of_medium_items = (BUFFER_SIZE - (ITEM_HDR_SIZE + MEDIUM_ITEM_SIZE)) / (ITEM_HDR_SIZE + MEDIUM_ITEM_SIZE);
306 
307     //Test sending items
308     for (int i = 0; i < no_of_medium_items; i++) {
309         send_item_and_check(buffer_handle, large_item, MEDIUM_ITEM_SIZE, TIMEOUT_TICKS, false);
310     }
311 
312     //Verify items waiting matches with the number of medium items sent
313     UBaseType_t items_waiting;
314     vRingbufferGetInfo(buffer_handle, NULL, NULL, NULL, NULL, &items_waiting);
315     TEST_ASSERT_MESSAGE(items_waiting == no_of_medium_items, "Incorrect items waiting");
316 
317     //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.
318     send_item_and_check(buffer_handle, small_item, SMALL_ITEM_SIZE, TIMEOUT_TICKS, false);
319 
320     //The buffer should not have any free space as the number of bytes remaining should be < ITEM_HDR_SIZE.
321     TEST_ASSERT_MESSAGE(xRingbufferGetCurFreeSize(buffer_handle) == 0, "Buffer full not achieved");
322 
323     //Send an item. The item should not be sent to a full buffer.
324     send_item_and_check_failure(buffer_handle, small_item, SMALL_ITEM_SIZE, TIMEOUT_TICKS, false);
325 
326     //Test receiving medium items
327     for (int i = 0; i < no_of_medium_items; i++) {
328         receive_check_and_return_item_no_split(buffer_handle, large_item, MEDIUM_ITEM_SIZE, TIMEOUT_TICKS, false);
329     }
330 
331     //Test receiving small item
332     receive_check_and_return_item_no_split(buffer_handle, small_item, SMALL_ITEM_SIZE, TIMEOUT_TICKS, false);
333 
334     //Verify that no items are waiting
335     vRingbufferGetInfo(buffer_handle, NULL, NULL, NULL, NULL, &items_waiting);
336     TEST_ASSERT_MESSAGE(items_waiting == 0, "Incorrect items waiting");
337 
338     //Cleanup
339     vRingbufferDelete(buffer_handle);
340 }
341 
342 TEST_CASE("TC#1: Allow-Split", "[esp_ringbuf]")
343 {
344     //Create buffer
345     RingbufHandle_t buffer_handle = xRingbufferCreate(BUFFER_SIZE, RINGBUF_TYPE_ALLOWSPLIT);
346     TEST_ASSERT_MESSAGE(buffer_handle != NULL, "Failed to create ring buffer");
347 
348     //Check buffer free size and max item size upon buffer creation. Should be BUFFER_SIZE - (ITEM_HDR_SIZE * 2).
349     TEST_ASSERT_MESSAGE(xRingbufferGetCurFreeSize(buffer_handle) == (BUFFER_SIZE - (ITEM_HDR_SIZE * 2)), "Incorrect buffer free size received");
350     TEST_ASSERT_MESSAGE(xRingbufferGetMaxItemSize(buffer_handle) == (BUFFER_SIZE - (ITEM_HDR_SIZE * 2)), "Incorrect max item size received");
351 
352     //Calculate number of items to send. Aim to almost fill buffer to setup for wrap around
353     int no_of_items = (BUFFER_SIZE - (ITEM_HDR_SIZE + SMALL_ITEM_SIZE)) / (ITEM_HDR_SIZE + SMALL_ITEM_SIZE);
354 
355     //Test sending items
356     for (int i = 0; i < no_of_items; i++) {
357         send_item_and_check(buffer_handle, small_item, SMALL_ITEM_SIZE, TIMEOUT_TICKS, false);
358     }
359 
360     //Verify items waiting matches with the number of items sent
361     UBaseType_t items_waiting;
362     vRingbufferGetInfo(buffer_handle, NULL, NULL, NULL, NULL, &items_waiting);
363     TEST_ASSERT_MESSAGE(items_waiting == no_of_items, "Incorrect items waiting");
364 
365     //Test receiving items
366     for (int i = 0; i < no_of_items; i++) {
367         receive_check_and_return_item_allow_split(buffer_handle, small_item, SMALL_ITEM_SIZE, TIMEOUT_TICKS, false);
368     }
369 
370     //Verify that no items are waiting
371     vRingbufferGetInfo(buffer_handle, NULL, NULL, NULL, NULL, &items_waiting);
372     TEST_ASSERT_MESSAGE(items_waiting == 0, "Incorrect items waiting");
373 
374     //Write pointer should be near the end, test wrap around
375     UBaseType_t write_pos_before, write_pos_after;
376     vRingbufferGetInfo(buffer_handle, NULL, NULL, &write_pos_before, NULL, NULL);
377     //Send large item that causes wrap around
378     send_item_and_check(buffer_handle, large_item, LARGE_ITEM_SIZE, TIMEOUT_TICKS, false);
379     //Receive wrapped item
380     receive_check_and_return_item_allow_split(buffer_handle, large_item, LARGE_ITEM_SIZE, TIMEOUT_TICKS, false);
381     vRingbufferGetInfo(buffer_handle, NULL, NULL, &write_pos_after, NULL, NULL);
382     TEST_ASSERT_MESSAGE(write_pos_after < write_pos_before, "Failed to wrap around");
383 
384     //Cleanup
385     vRingbufferDelete(buffer_handle);
386 }
387 
388 TEST_CASE("TC#2: Allow-Split", "[esp_ringbuf]")
389 {
390     //Create buffer
391     RingbufHandle_t buffer_handle = xRingbufferCreate(BUFFER_SIZE, RINGBUF_TYPE_ALLOWSPLIT);
392     TEST_ASSERT_MESSAGE(buffer_handle != NULL, "Failed to create ring buffer");
393 
394     //Check buffer free size and max item size upon buffer creation. Should be BUFFER_SIZE - (ITEM_HDR_SIZE * 2).
395     TEST_ASSERT_MESSAGE(xRingbufferGetCurFreeSize(buffer_handle) == (BUFFER_SIZE - (ITEM_HDR_SIZE * 2)), "Incorrect buffer free size received");
396     TEST_ASSERT_MESSAGE(xRingbufferGetMaxItemSize(buffer_handle) == (BUFFER_SIZE - (ITEM_HDR_SIZE * 2)), "Incorrect max item size received");
397 
398     //Calculate number of items to send. Aim to fill the buffer
399     int no_of_items = (BUFFER_SIZE) / (ITEM_HDR_SIZE + SMALL_ITEM_SIZE);
400 
401     //Test sending items
402     for (int i = 0; i < no_of_items; i++) {
403         send_item_and_check(buffer_handle, small_item, SMALL_ITEM_SIZE, TIMEOUT_TICKS, false);
404     }
405 
406     //Verify items waiting matches with the number of items sent
407     UBaseType_t items_waiting;
408     vRingbufferGetInfo(buffer_handle, NULL, NULL, NULL, NULL, &items_waiting);
409     TEST_ASSERT_MESSAGE(items_waiting == no_of_items, "Incorrect items waiting");
410 
411     //At this point, the buffer should be full.
412     TEST_ASSERT_MESSAGE(xRingbufferGetCurFreeSize(buffer_handle) == 0, "Buffer full not achieved");
413 
414     //Send an item. The item should not be sent to a full buffer.
415     send_item_and_check_failure(buffer_handle, small_item, SMALL_ITEM_SIZE, TIMEOUT_TICKS, false);
416 
417     //Receive one item
418     receive_check_and_return_item_allow_split(buffer_handle, small_item, SMALL_ITEM_SIZE, TIMEOUT_TICKS, false);
419 
420     //At this point, the buffer should not be full any more
421     TEST_ASSERT_MESSAGE(xRingbufferGetCurFreeSize(buffer_handle) > 0, "Buffer should have free space");
422 
423     //Test receiving remaining items
424     for (int i = 0; i < no_of_items - 1; i++) {
425         receive_check_and_return_item_allow_split(buffer_handle, small_item, SMALL_ITEM_SIZE, TIMEOUT_TICKS, false);
426     }
427 
428     //Verify that no items are waiting
429     vRingbufferGetInfo(buffer_handle, NULL, NULL, NULL, NULL, &items_waiting);
430     TEST_ASSERT_MESSAGE(items_waiting == 0, "Incorrect items waiting");
431 
432     //Cleanup
433     vRingbufferDelete(buffer_handle);
434 }
435 
436 TEST_CASE("TC#3: Allow-Split", "[esp_ringbuf]")
437 {
438     //Create buffer
439     RingbufHandle_t buffer_handle = xRingbufferCreate(BUFFER_SIZE, RINGBUF_TYPE_ALLOWSPLIT);
440     TEST_ASSERT_MESSAGE(buffer_handle != NULL, "Failed to create ring buffer");
441 
442     //Check buffer free size and max item size upon buffer creation. Should be BUFFER_SIZE - (ITEM_HDR_SIZE * 2).
443     TEST_ASSERT_MESSAGE(xRingbufferGetCurFreeSize(buffer_handle) == (BUFFER_SIZE - (ITEM_HDR_SIZE * 2)), "Incorrect buffer free size received");
444     TEST_ASSERT_MESSAGE(xRingbufferGetMaxItemSize(buffer_handle) == (BUFFER_SIZE - (ITEM_HDR_SIZE * 2)), "Incorrect max item size received");
445 
446     //Calculate number of medium items to send. Aim to almost fill the buffer
447     int no_of_medium_items = (BUFFER_SIZE - (ITEM_HDR_SIZE + MEDIUM_ITEM_SIZE)) / (ITEM_HDR_SIZE + MEDIUM_ITEM_SIZE);
448 
449     //Test sending items
450     for (int i = 0; i < no_of_medium_items; i++) {
451         send_item_and_check(buffer_handle, large_item, MEDIUM_ITEM_SIZE, TIMEOUT_TICKS, false);
452     }
453 
454     //Verify items waiting matches with the number of medium items sent
455     UBaseType_t items_waiting;
456     vRingbufferGetInfo(buffer_handle, NULL, NULL, NULL, NULL, &items_waiting);
457     TEST_ASSERT_MESSAGE(items_waiting == no_of_medium_items, "Incorrect items waiting");
458 
459     //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.
460     send_item_and_check(buffer_handle, small_item, SMALL_ITEM_SIZE, TIMEOUT_TICKS, false);
461 
462     //The buffer should not have any free space as the number of bytes remaining should be < ITEM_HDR_SIZE.
463     TEST_ASSERT_MESSAGE(xRingbufferGetCurFreeSize(buffer_handle) == 0, "Buffer full not achieved");
464 
465     //Send an item. The item should not be sent to a full buffer.
466     send_item_and_check_failure(buffer_handle, small_item, SMALL_ITEM_SIZE, TIMEOUT_TICKS, false);
467 
468     //Test receiving medium items
469     for (int i = 0; i < no_of_medium_items; i++) {
470         receive_check_and_return_item_allow_split(buffer_handle, large_item, MEDIUM_ITEM_SIZE, TIMEOUT_TICKS, false);
471     }
472 
473     //Test receiving small item
474     receive_check_and_return_item_allow_split(buffer_handle, small_item, SMALL_ITEM_SIZE, TIMEOUT_TICKS, false);
475 
476     //Verify that no items are waiting
477     vRingbufferGetInfo(buffer_handle, NULL, NULL, NULL, NULL, &items_waiting);
478     TEST_ASSERT_MESSAGE(items_waiting == 0, "Incorrect items waiting");
479 
480     //Cleanup
481     vRingbufferDelete(buffer_handle);
482 }
483 
484 TEST_CASE("TC#1: Byte buffer", "[esp_ringbuf]")
485 {
486     //Create buffer
487     RingbufHandle_t buffer_handle = xRingbufferCreate(BUFFER_SIZE, RINGBUF_TYPE_BYTEBUF);
488     TEST_ASSERT_MESSAGE(buffer_handle != NULL, "Failed to create ring buffer");
489 
490     //Check buffer free size and max item size upon buffer creation. Should be BUFFER_SIZE
491     TEST_ASSERT_MESSAGE(xRingbufferGetCurFreeSize(buffer_handle) == BUFFER_SIZE, "Incorrect buffer free size received");
492     TEST_ASSERT_MESSAGE(xRingbufferGetMaxItemSize(buffer_handle) == BUFFER_SIZE, "Incorrect max item size received");
493 
494     //Calculate number of items to send. Aim to almost fill buffer to setup for wrap around
495     int no_of_items = (BUFFER_SIZE - SMALL_ITEM_SIZE) / SMALL_ITEM_SIZE;
496 
497     //Test sending items
498     for (int i = 0; i < no_of_items; i++) {
499         send_item_and_check(buffer_handle, small_item, SMALL_ITEM_SIZE, TIMEOUT_TICKS, false);
500     }
501 
502     //Verify items waiting matches with the number of items sent
503     UBaseType_t items_waiting;
504     vRingbufferGetInfo(buffer_handle, NULL, NULL, NULL, NULL, &items_waiting);
505     TEST_ASSERT_MESSAGE(items_waiting == no_of_items * SMALL_ITEM_SIZE, "Incorrect number of bytes waiting");
506 
507     //Test receiving items
508     for (int i = 0; i < no_of_items; i++) {
509         receive_check_and_return_item_byte_buffer(buffer_handle, small_item, SMALL_ITEM_SIZE, TIMEOUT_TICKS, false);
510     }
511 
512     //Verify that no items are waiting
513     vRingbufferGetInfo(buffer_handle, NULL, NULL, NULL, NULL, &items_waiting);
514     TEST_ASSERT_MESSAGE(items_waiting == 0, "Incorrect number of bytes waiting");
515 
516     //Write pointer should be near the end, test wrap around
517     UBaseType_t write_pos_before, write_pos_after;
518     vRingbufferGetInfo(buffer_handle, NULL, NULL, &write_pos_before, NULL, NULL);
519     //Send large item that causes wrap around
520     send_item_and_check(buffer_handle, large_item, LARGE_ITEM_SIZE, TIMEOUT_TICKS, false);
521     //Receive wrapped item
522     receive_check_and_return_item_byte_buffer(buffer_handle, large_item, LARGE_ITEM_SIZE, TIMEOUT_TICKS, false);
523     vRingbufferGetInfo(buffer_handle, NULL, NULL, &write_pos_after, NULL, NULL);
524     TEST_ASSERT_MESSAGE(write_pos_after < write_pos_before, "Failed to wrap around");
525 
526     //Cleanup
527     vRingbufferDelete(buffer_handle);
528 }
529 
530 TEST_CASE("TC#2: Byte buffer", "[esp_ringbuf]")
531 {
532     //Create buffer
533     RingbufHandle_t buffer_handle = xRingbufferCreate(BUFFER_SIZE, RINGBUF_TYPE_BYTEBUF);
534     TEST_ASSERT_MESSAGE(buffer_handle != NULL, "Failed to create ring buffer");
535 
536     //Check buffer free size and max item size upon buffer creation. Should be BUFFER_SIZE.
537     TEST_ASSERT_MESSAGE(xRingbufferGetCurFreeSize(buffer_handle) == BUFFER_SIZE, "Incorrect buffer free size received");
538     TEST_ASSERT_MESSAGE(xRingbufferGetMaxItemSize(buffer_handle) == BUFFER_SIZE, "Incorrect max item size received");
539 
540     //Calculate number of items to send. Aim to fill the buffer
541     int no_of_items = BUFFER_SIZE / SMALL_ITEM_SIZE;
542 
543     //Test sending items
544     for (int i = 0; i < no_of_items; i++) {
545         send_item_and_check(buffer_handle, small_item, SMALL_ITEM_SIZE, TIMEOUT_TICKS, false);
546     }
547 
548     //Verify items waiting matches with the number of items sent
549     UBaseType_t items_waiting;
550     vRingbufferGetInfo(buffer_handle, NULL, NULL, NULL, NULL, &items_waiting);
551     TEST_ASSERT_MESSAGE(items_waiting == no_of_items * SMALL_ITEM_SIZE, "Incorrect number of bytes waiting");
552 
553     //At this point, the buffer should be full.
554     TEST_ASSERT_MESSAGE(xRingbufferGetCurFreeSize(buffer_handle) == 0, "Buffer full not achieved");
555 
556     //Send an item. The item should not be sent to a full buffer.
557     send_item_and_check_failure(buffer_handle, small_item, SMALL_ITEM_SIZE, TIMEOUT_TICKS, false);
558 
559     //Receive one item
560     receive_check_and_return_item_byte_buffer(buffer_handle, small_item, SMALL_ITEM_SIZE, TIMEOUT_TICKS, false);
561 
562     //At this point, the buffer should not be full any more
563     TEST_ASSERT_MESSAGE(xRingbufferGetCurFreeSize(buffer_handle) > 0, "Buffer should have free space");
564 
565     //Test receiving remaining items
566     for (int i = 0; i < no_of_items - 1; i++) {
567         receive_check_and_return_item_byte_buffer(buffer_handle, small_item, SMALL_ITEM_SIZE, TIMEOUT_TICKS, false);
568     }
569 
570     //Verify that no items are waiting
571     vRingbufferGetInfo(buffer_handle, NULL, NULL, NULL, NULL, &items_waiting);
572     TEST_ASSERT_MESSAGE(items_waiting == 0, "Incorrect items waiting");
573 
574     //Cleanup
575     vRingbufferDelete(buffer_handle);
576 }
577 
578 TEST_CASE("TC#3: Byte buffer", "[esp_ringbuf]")
579 {
580     //Create buffer
581     RingbufHandle_t buffer_handle = xRingbufferCreate(BUFFER_SIZE, RINGBUF_TYPE_BYTEBUF);
582     TEST_ASSERT_MESSAGE(buffer_handle != NULL, "Failed to create ring buffer");
583 
584     //Check buffer free size and max item size upon buffer creation. Should be BUFFER_SIZE.
585     TEST_ASSERT_MESSAGE(xRingbufferGetCurFreeSize(buffer_handle) == BUFFER_SIZE, "Incorrect buffer free size received");
586     TEST_ASSERT_MESSAGE(xRingbufferGetMaxItemSize(buffer_handle) == BUFFER_SIZE, "Incorrect max item size received");
587 
588     //Calculate number of medium items to send. Aim to almost fill the buffer
589     int no_of_medium_items = BUFFER_SIZE / MEDIUM_ITEM_SIZE;
590 
591     //Test sending items
592     for (int i = 0; i < no_of_medium_items; i++) {
593         send_item_and_check(buffer_handle, large_item, MEDIUM_ITEM_SIZE, TIMEOUT_TICKS, false);
594     }
595 
596     //Verify items waiting matches with the number of medium items sent
597     UBaseType_t items_waiting;
598     vRingbufferGetInfo(buffer_handle, NULL, NULL, NULL, NULL, &items_waiting);
599     TEST_ASSERT_MESSAGE(items_waiting == no_of_medium_items * MEDIUM_ITEM_SIZE, "Incorrect number of bytes waiting");
600 
601     //The buffer should not have any free space for one small item.
602     TEST_ASSERT_MESSAGE(xRingbufferGetCurFreeSize(buffer_handle) < SMALL_ITEM_SIZE, "Buffer full not achieved");
603 
604     //Send an item. The item should not be sent to a full buffer.
605     send_item_and_check_failure(buffer_handle, small_item, SMALL_ITEM_SIZE, TIMEOUT_TICKS, false);
606 
607     //Test receiving medium items
608     for (int i = 0; i < no_of_medium_items; i++) {
609         receive_check_and_return_item_byte_buffer(buffer_handle, large_item, MEDIUM_ITEM_SIZE, TIMEOUT_TICKS, false);
610     }
611 
612     //Verify that no items are waiting
613     vRingbufferGetInfo(buffer_handle, NULL, NULL, NULL, NULL, &items_waiting);
614     TEST_ASSERT_MESSAGE(items_waiting == 0, "Incorrect items waiting");
615 
616     //Cleanup
617     vRingbufferDelete(buffer_handle);
618 }
619 
620 /* ----------------------- Ring buffer queue sets test ------------------------
621  * The following test case will test receiving from ring buffers that have been
622  * added to a queue set. The test case will do the following...
623  * 1) Ring buffer of each type is created and added to the queue set
624  * 2) A receiving task is created to select from the queue set and read from the appropriate ring buffer
625  */
626 
queue_set_receiving_task(void * queue_set_handle)627 static void queue_set_receiving_task(void *queue_set_handle)
628 {
629     QueueSetHandle_t queue_set = (QueueSetHandle_t)queue_set_handle;
630 
631     //Receive multiple items via queue set
632     BaseType_t done = pdFALSE;
633     int no_of_items = BUFFER_SIZE / SMALL_ITEM_SIZE;
634     int items_rec_count[NO_OF_RB_TYPES] = {0};
635     while (done != pdTRUE) {
636         xQueueSetMemberHandle member = xQueueSelectFromSet(queue_set, TIMEOUT_TICKS);
637         //Read from selected ring buffer
638         if (xRingbufferCanRead(buffer_handles[0], member) == pdTRUE) {
639             //No-split buffer
640             receive_check_and_return_item_no_split(buffer_handles[0], small_item, SMALL_ITEM_SIZE, 0, false);
641             items_rec_count[0] ++;
642         } else if (xRingbufferCanRead(buffer_handles[1], member) == pdTRUE) {
643             //Allow-split buffer
644             receive_check_and_return_item_allow_split(buffer_handles[1], small_item, SMALL_ITEM_SIZE, 0, false);
645             items_rec_count[1] ++;
646         } else if (xRingbufferCanRead(buffer_handles[2], member) == pdTRUE){
647             //Byte buffer
648             receive_check_and_return_item_byte_buffer(buffer_handles[2], small_item, SMALL_ITEM_SIZE, 0, false);
649             items_rec_count[2] ++;
650         } else {
651             TEST_ASSERT_MESSAGE( false, "Error with queue set member");
652         }
653 
654         //Check for completion
655         if (items_rec_count[0] == no_of_items &&
656             items_rec_count[1] == no_of_items &&
657             items_rec_count[2] == no_of_items) {
658             done = pdTRUE;
659         }
660     }
661 
662     xSemaphoreGive(done_sem);
663     vTaskDelete(NULL);
664 }
665 
666 TEST_CASE("Test ring buffer with queue sets", "[esp_ringbuf]")
667 {
668     QueueSetHandle_t queue_set = xQueueCreateSet(NO_OF_RB_TYPES);
669     done_sem = xSemaphoreCreateBinary();
670 
671     //Create ring buffer of each type, then add them to a queue set
672     for (int i = 0; i < NO_OF_RB_TYPES; i++) {
673         buffer_handles[i] = xRingbufferCreate(BUFFER_SIZE, i);
674         TEST_ASSERT_MESSAGE(buffer_handles[i] != NULL, "Failed to create ring buffer");
675         TEST_ASSERT_MESSAGE(xRingbufferAddToQueueSetRead(buffer_handles[i], queue_set) == pdPASS, "Failed to add to read queue set");
676     }
677     //Create a task to send items to each ring buffer
678     int no_of_items = BUFFER_SIZE / SMALL_ITEM_SIZE;
679     xTaskCreatePinnedToCore(queue_set_receiving_task, "rec tsk", 2048, (void *)queue_set, UNITY_FREERTOS_PRIORITY + 1 , NULL, 0);
680 
681     //Send multiple items to each type of ring buffer
682     for (int i = 0; i < no_of_items; i++) {
683         for (int j = 0; j < NO_OF_RB_TYPES; j++) {
684             send_item_and_check(buffer_handles[j], small_item, SMALL_ITEM_SIZE, TIMEOUT_TICKS, false);
685         }
686     }
687 
688     xSemaphoreTake(done_sem, portMAX_DELAY);
689     vSemaphoreDelete(done_sem);
690    //Remove and delete ring buffers from queue sets
691     for (int i = 0; i < NO_OF_RB_TYPES; i++) {
692         TEST_ASSERT_MESSAGE(xRingbufferRemoveFromQueueSetRead(buffer_handles[i], queue_set) == pdTRUE, "Failed to remove from read queue set");
693         vRingbufferDelete(buffer_handles[i]);
694     }
695     vQueueDelete(queue_set);
696 }
697 
698 /* -------------------------- Test ring buffer ISR -----------------------------
699  * The following test case tests ring buffer ISR API. A timer is used to trigger
700  * the ISR. The test case will do the following
701  * 1) ISR will be triggered periodically by timer
702  * 2) The ISR will iterate through all ring buffer types where each iteration
703  *    will send then receive an item to a ring buffer.
704  */
705 
706 #define TIMER_GROUP     0
707 #define TIMER_NUMBER    0
708 #define ISR_ITERATIONS  ((BUFFER_SIZE / SMALL_ITEM_SIZE) * 2)
709 
710 intr_handle_t ringbuffer_isr_handle;
711 static int buf_type;
712 static int iterations;
713 
ringbuffer_isr(void * arg)714 static void ringbuffer_isr(void *arg)
715 {
716     //Clear timer interrupt
717     timer_group_clr_intr_status_in_isr(TIMER_GROUP_0, TIMER_0);
718     timer_group_enable_alarm_in_isr(TIMER_GROUP_0, xPortGetCoreID());
719 
720     //Test sending to buffer from ISR from ISR
721     if (buf_type < NO_OF_RB_TYPES) {
722         send_item_and_check(buffer_handles[buf_type], (void *)small_item, SMALL_ITEM_SIZE, 0, true);
723     }
724 
725     //Receive item from ISR
726     if (buf_type == RINGBUF_TYPE_NOSPLIT) {
727         //Test receive from ISR for no-split buffer
728         receive_check_and_return_item_no_split(buffer_handles[buf_type], (void *)small_item, SMALL_ITEM_SIZE, 0, true);
729         buf_type++;
730     } else if (buf_type == RINGBUF_TYPE_ALLOWSPLIT) {
731         //Test send from ISR to allow-split buffer
732         receive_check_and_return_item_allow_split(buffer_handles[buf_type], (void *)small_item, SMALL_ITEM_SIZE, 0, true);
733         buf_type++;
734     } else if (buf_type == RINGBUF_TYPE_BYTEBUF) {
735         //Test receive from ISR for byte buffer
736         receive_check_and_return_item_byte_buffer(buffer_handles[buf_type], (void *)small_item, SMALL_ITEM_SIZE, 0, true);
737         buf_type++;
738     } else if (buf_type == NO_OF_RB_TYPES) {
739         //Check if all iterations complete
740         if (iterations < ISR_ITERATIONS) {
741             iterations++;
742             buf_type = 0;   //Reset and iterate through each buffer type again
743             return;
744         } else {
745             //Signal complete
746             BaseType_t task_woken = pdFALSE;
747             xSemaphoreGiveFromISR(done_sem, &task_woken);
748             if (task_woken == pdTRUE) {
749                 buf_type++;
750                 portYIELD_FROM_ISR();
751             }
752         }
753     }
754 }
755 
setup_timer(void)756 static void setup_timer(void)
757 {
758     //Setup timer for ISR
759     int timer_group = TIMER_GROUP;
760     int timer_idx = TIMER_NUMBER;
761     timer_config_t config;
762     config.alarm_en = 1;
763     config.auto_reload = 1;
764     config.counter_dir = TIMER_COUNT_UP;
765     config.divider = 10000;
766     config.intr_type = TIMER_INTR_LEVEL;
767     config.counter_en = TIMER_PAUSE;
768     timer_init(timer_group, timer_idx, &config);    //Configure timer
769     timer_pause(timer_group, timer_idx);    //Stop timer counter
770     timer_set_counter_value(timer_group, timer_idx, 0x00000000ULL); //Load counter value
771     timer_set_alarm_value(timer_group, timer_idx, 20); //Set alarm value
772     timer_enable_intr(timer_group, timer_idx);  //Enable timer interrupt
773     timer_set_auto_reload(timer_group, timer_idx, 1);   //Auto Reload
774     timer_isr_register(timer_group, timer_idx, ringbuffer_isr, NULL, 0, &ringbuffer_isr_handle);    //Set ISR handler
775 }
776 
cleanup_timer(void)777 static void cleanup_timer(void)
778 {
779     timer_disable_intr(TIMER_GROUP, TIMER_NUMBER);
780     esp_intr_free(ringbuffer_isr_handle);
781 }
782 
783 TEST_CASE("Test ring buffer ISR", "[esp_ringbuf]")
784 {
785     for (int i = 0; i < NO_OF_RB_TYPES; i++) {
786         buffer_handles[i] = xRingbufferCreate(BUFFER_SIZE, i);
787     }
788     done_sem = xSemaphoreCreateBinary();
789     buf_type = 0;
790     iterations = 0;
791     setup_timer();
792     //Start timer to trigger ISR
793     timer_start(TIMER_GROUP, TIMER_NUMBER);
794     //Wait for ISR to complete multiple iterations
795     xSemaphoreTake(done_sem, portMAX_DELAY);
796 
797     //Cleanup
798     cleanup_timer();
799     vSemaphoreDelete(done_sem);
800     for (int i = 0; i < NO_OF_RB_TYPES; i++) {
801         vRingbufferDelete(buffer_handles[i]);
802     }
803 }
804 
805 /* ---------------------------- Test ring buffer SMP ---------------------------
806  * The following test case tests each type of ring buffer in an SMP fashion. A
807  * sending task and a receiving task is created. The sending task will split
808  * a continuous piece of data into items of random length and send it to a ring
809  * buffer. The receiving task will receive and check those items.
810  * Every permutation of core pinning of the sending and receiving task will be
811  * tested.
812  */
813 
814 #define SRAND_SEED                      3   //Arbitrarily chosen srand() seed
815 #define SMP_TEST_ITERATIONS             4
816 
817 static const char continuous_data[] = {"A_very_long_string_that_will_be_split_into_"
818                                        "items_of_random_lengths_and_sent_to_the_ring_"
819                                        "buffer._The_maximum_random_length_will_also_"
820                                        "be_increased_over_multiple_iterations_in_this"
821                                        "_test"};
822 #define CONT_DATA_LEN                   sizeof(continuous_data)
823 //32-bit aligned size that guarantees a wrap around at some point
824 #define CONT_DATA_TEST_BUFF_LEN         (((CONT_DATA_LEN/2) + 0x03) & ~0x3)
825 
826 typedef struct {
827     RingbufHandle_t buffer;
828     RingbufferType_t type;
829 } task_args_t;
830 
831 static SemaphoreHandle_t tasks_done;
832 static SemaphoreHandle_t tx_done;
833 static SemaphoreHandle_t rx_done;
834 
send_to_buffer(RingbufHandle_t buffer,size_t max_item_size)835 static void send_to_buffer(RingbufHandle_t buffer, size_t max_item_size)
836 {
837     for (int iter = 0; iter < SMP_TEST_ITERATIONS; iter++) {
838         size_t bytes_sent = 0;      //Number of data bytes sent in this iteration
839         size_t next_item_size;      //Size of next item to send
840 
841         while (bytes_sent < CONT_DATA_LEN) {
842             //Get size of next item
843             next_item_size = rand() % (max_item_size + 1);
844             if (next_item_size + bytes_sent > CONT_DATA_LEN) {
845                 next_item_size = CONT_DATA_LEN - bytes_sent;
846             }
847 
848             //Send item
849             TEST_ASSERT_MESSAGE(xRingbufferSend(buffer, (void *)&(continuous_data[bytes_sent]), next_item_size, TIMEOUT_TICKS) == pdTRUE, "Failed to send an item");
850             bytes_sent += next_item_size;
851         }
852         xSemaphoreGive(tx_done);
853         xSemaphoreTake(rx_done, portMAX_DELAY);
854     }
855 }
856 
read_from_buffer(RingbufHandle_t buffer,RingbufferType_t buf_type,size_t max_rec_size)857 static void read_from_buffer(RingbufHandle_t buffer, RingbufferType_t buf_type, size_t max_rec_size)
858 {
859     for (int iter = 0; iter < SMP_TEST_ITERATIONS; iter++) {
860         size_t bytes_rec = 0;      //Number of data bytes received in this iteration
861         while (bytes_rec < CONT_DATA_LEN) {
862             size_t item_size, item_size2;    //Possible for allow split buffers to receive two items
863             char *item_data, *item_data2;
864 
865             //Select appropriate receive function for type of ring buffer
866             if (buf_type ==  RINGBUF_TYPE_NOSPLIT) {
867                 item_data = (char *)xRingbufferReceive(buffer, &item_size, TIMEOUT_TICKS);
868             } else if (buf_type == RINGBUF_TYPE_ALLOWSPLIT) {
869                 BaseType_t ret = xRingbufferReceiveSplit(buffer, (void **)&item_data, (void **)&item_data2, &item_size, &item_size2, TIMEOUT_TICKS);
870                 TEST_ASSERT_MESSAGE(ret == pdTRUE, "Failed to receive any item");
871             } else {
872                 item_data = (char *)xRingbufferReceiveUpTo(buffer, &item_size, TIMEOUT_TICKS, max_rec_size);
873             }
874 
875             //Check received item and return it
876             TEST_ASSERT_MESSAGE(item_data != NULL, "Failed to receive an item");
877             if (buf_type == RINGBUF_TYPE_BYTEBUF) {
878                 TEST_ASSERT_MESSAGE(item_size <= max_rec_size, "Received data exceeds max size");
879             }
880             for (int i = 0; i < item_size; i++) {
881                 //Check item_data is valid
882                 TEST_ASSERT_MESSAGE(item_data[i] == continuous_data[bytes_rec + i], "Received data is corrupted");
883             }
884             bytes_rec += item_size;
885             vRingbufferReturnItem(buffer, item_data);
886             if (buf_type == RINGBUF_TYPE_ALLOWSPLIT && item_data2 != NULL) {
887                 //Check item_data2 is valid
888                 for (int i = 0; i < item_size2; i++) {
889                     TEST_ASSERT_MESSAGE(item_data2[i] == continuous_data[bytes_rec + i], "Received split data is corrupted");
890                 }
891                 bytes_rec += item_size2;
892                 vRingbufferReturnItem(buffer, item_data2);
893             }
894         }
895         TEST_ASSERT_MESSAGE(bytes_rec == CONT_DATA_LEN, "Total length of received data is incorrect");
896         xSemaphoreGive(rx_done);
897         xSemaphoreTake(tx_done, portMAX_DELAY);
898     }
899 }
900 
send_task(void * args)901 static void send_task(void *args)
902 {
903     RingbufHandle_t buffer = ((task_args_t *)args)->buffer;
904     size_t max_item_len = xRingbufferGetMaxItemSize(buffer);
905 
906     //Test sending short length items
907     send_to_buffer(buffer, 1);
908     //Test sending mid length items
909     send_to_buffer(buffer, max_item_len/2);
910     //Test sending long length items
911     send_to_buffer(buffer, max_item_len);
912     vTaskDelete(NULL);
913 }
914 
rec_task(void * args)915 static void rec_task(void *args)
916 {
917     RingbufHandle_t buffer = ((task_args_t *)args)->buffer;
918     size_t max_rec_len = xRingbufferGetMaxItemSize(buffer);
919 
920     //Test receiving short length items
921     read_from_buffer(buffer, ((task_args_t *)args)->type, 1);
922     //Test receiving mid length items
923     read_from_buffer(buffer, ((task_args_t *)args)->type, max_rec_len/2);
924     //Test receiving long length items
925     read_from_buffer(buffer, ((task_args_t *)args)->type, max_rec_len);
926 
927     xSemaphoreGive(tasks_done);
928     vTaskDelete(NULL);
929 }
930 
setup(void)931 static void setup(void)
932 {
933     esp_rom_printf("Size of test data: %d\n", CONT_DATA_LEN);
934     tx_done = xSemaphoreCreateBinary();                 //Semaphore to indicate send is done for a particular iteration
935     rx_done = xSemaphoreCreateBinary();                 //Semaphore to indicate receive is done for a particular iteration
936     tasks_done = xSemaphoreCreateBinary();              //Semaphore used to to indicate send and receive tasks completed running
937     srand(SRAND_SEED);                                  //Seed RNG
938 }
939 
cleanup(void)940 static void cleanup(void)
941 {
942     //Cleanup
943     vSemaphoreDelete(tx_done);
944     vSemaphoreDelete(rx_done);
945     vSemaphoreDelete(tasks_done);
946 }
947 
948 TEST_CASE("Test ring buffer SMP", "[esp_ringbuf]")
949 {
950     setup();
951     //Iterate through buffer types (No split, split, then byte buff)
952     for (RingbufferType_t buf_type = 0; buf_type < RINGBUF_TYPE_MAX; buf_type++) {
953         //Create buffer
954         task_args_t task_args;
955         task_args.buffer = xRingbufferCreate(CONT_DATA_TEST_BUFF_LEN, buf_type); //Create buffer of selected type
956         task_args.type = buf_type;
957         TEST_ASSERT_MESSAGE(task_args.buffer != NULL, "Failed to create ring buffer");
958 
959         for (int prior_mod = -1; prior_mod < 2; prior_mod++) {  //Test different relative priorities
960             //Test every permutation of core affinity
961             for (int send_core = 0; send_core < portNUM_PROCESSORS; send_core++) {
962                 for (int rec_core = 0; rec_core < portNUM_PROCESSORS; rec_core ++) {
963                     esp_rom_printf("Type: %d, PM: %d, SC: %d, RC: %d\n", buf_type, prior_mod, send_core, rec_core);
964                     xTaskCreatePinnedToCore(send_task, "send tsk", 2048, (void *)&task_args, 10 + prior_mod, NULL, send_core);
965                     xTaskCreatePinnedToCore(rec_task, "rec tsk", 2048, (void *)&task_args, 10, NULL, rec_core);
966                     xSemaphoreTake(tasks_done, portMAX_DELAY);
967                     vTaskDelay(5);  //Allow idle to clean up
968                 }
969             }
970         }
971 
972         //Delete ring buffer
973         vRingbufferDelete(task_args.buffer);
974         vTaskDelay(10);
975     }
976     cleanup();
977 }
978 
979 #if ( configSUPPORT_STATIC_ALLOCATION == 1 )
980 TEST_CASE("Test static ring buffer SMP", "[esp_ringbuf]")
981 {
982     setup();
983     //Iterate through buffer types (No split, split, then byte buff)
984     for (RingbufferType_t buf_type = 0; buf_type < RINGBUF_TYPE_MAX; buf_type++) {
985         StaticRingbuffer_t *buffer_struct;
986         uint8_t *buffer_storage;
987         //Allocate memory and create semaphores
988 #if CONFIG_SPIRAM_USE_CAPS_ALLOC   //When SPIRAM can only be allocated using heap_caps_malloc()
989         buffer_struct = (StaticRingbuffer_t *)heap_caps_malloc(sizeof(StaticRingbuffer_t), MALLOC_CAP_SPIRAM);
990         buffer_storage = (uint8_t *)heap_caps_malloc(sizeof(uint8_t)*CONT_DATA_TEST_BUFF_LEN, MALLOC_CAP_SPIRAM);
991 #else   //Case where SPIRAM is disabled or when SPIRAM is allocatable through malloc()
992         buffer_struct = (StaticRingbuffer_t *)malloc(sizeof(StaticRingbuffer_t));
993         buffer_storage = (uint8_t *)malloc(sizeof(uint8_t)*CONT_DATA_TEST_BUFF_LEN);
994 #endif
995         TEST_ASSERT(buffer_struct != NULL && buffer_storage != NULL);
996 
997         //Create buffer
998         task_args_t task_args;
999         task_args.buffer = xRingbufferCreateStatic(CONT_DATA_TEST_BUFF_LEN, buf_type, buffer_storage, buffer_struct); //Create buffer of selected type
1000         task_args.type = buf_type;
1001         TEST_ASSERT_MESSAGE(task_args.buffer != NULL, "Failed to create ring buffer");
1002 
1003         for (int prior_mod = -1; prior_mod < 2; prior_mod++) {  //Test different relative priorities
1004             //Test every permutation of core affinity
1005             for (int send_core = 0; send_core < portNUM_PROCESSORS; send_core++) {
1006                 for (int rec_core = 0; rec_core < portNUM_PROCESSORS; rec_core ++) {
1007                     esp_rom_printf("Type: %d, PM: %d, SC: %d, RC: %d\n", buf_type, prior_mod, send_core, rec_core);
1008                     xTaskCreatePinnedToCore(send_task, "send tsk", 2048, (void *)&task_args, 10 + prior_mod, NULL, send_core);
1009                     xTaskCreatePinnedToCore(rec_task, "rec tsk", 2048, (void *)&task_args, 10, NULL, rec_core);
1010                     xSemaphoreTake(tasks_done, portMAX_DELAY);
1011                     vTaskDelay(5);  //Allow idle to clean up
1012                 }
1013             }
1014         }
1015 
1016         //Delete ring buffer
1017         vRingbufferDelete(task_args.buffer);
1018 
1019         //Deallocate memory
1020         free(buffer_storage);
1021         free(buffer_struct);
1022         vTaskDelay(10);
1023     }
1024     cleanup();
1025 }
1026 #endif
1027 
1028 /* -------------------------- Test ring buffer IRAM ------------------------- */
1029 
iram_ringbuf_test(void)1030 static IRAM_ATTR __attribute__((noinline)) bool iram_ringbuf_test(void)
1031 {
1032     bool result = true;
1033 
1034     RingbufHandle_t handle = xRingbufferCreate(CONT_DATA_TEST_BUFF_LEN, RINGBUF_TYPE_NOSPLIT);
1035     result = result && (handle != NULL);
1036     spi_flash_guard_get()->start(); // Disables flash cache
1037     xRingbufferGetMaxItemSize(handle);
1038     spi_flash_guard_get()->end(); // Re-enables flash cache
1039     vRingbufferDelete(handle);
1040 
1041     return result;
1042 }
1043 
1044 TEST_CASE("Test ringbuffer functions work with flash cache disabled", "[esp_ringbuf]")
1045 {
1046     TEST_ASSERT( iram_ringbuf_test() );
1047 }
1048