test_ringbuf.c 46 KB

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