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