test_ringbuf.c 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047
  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. config.alarm_en = 1;
  637. config.auto_reload = 1;
  638. config.counter_dir = TIMER_COUNT_UP;
  639. config.divider = 10000;
  640. config.intr_type = TIMER_INTR_LEVEL;
  641. config.counter_en = TIMER_PAUSE;
  642. timer_init(timer_group, timer_idx, &config); //Configure timer
  643. timer_pause(timer_group, timer_idx); //Stop timer counter
  644. timer_set_counter_value(timer_group, timer_idx, 0x00000000ULL); //Load counter value
  645. timer_set_alarm_value(timer_group, timer_idx, 20); //Set alarm value
  646. timer_enable_intr(timer_group, timer_idx); //Enable timer interrupt
  647. timer_set_auto_reload(timer_group, timer_idx, 1); //Auto Reload
  648. timer_isr_register(timer_group, timer_idx, ringbuffer_isr, NULL, 0, &ringbuffer_isr_handle); //Set ISR handler
  649. }
  650. static void cleanup_timer(void)
  651. {
  652. timer_disable_intr(TIMER_GROUP, TIMER_NUMBER);
  653. esp_intr_free(ringbuffer_isr_handle);
  654. }
  655. TEST_CASE("Test ring buffer ISR", "[esp_ringbuf]")
  656. {
  657. for (int i = 0; i < NO_OF_RB_TYPES; i++) {
  658. buffer_handles[i] = xRingbufferCreate(BUFFER_SIZE, i);
  659. }
  660. done_sem = xSemaphoreCreateBinary();
  661. buf_type = 0;
  662. iterations = 0;
  663. setup_timer();
  664. //Start timer to trigger ISR
  665. timer_start(TIMER_GROUP, TIMER_NUMBER);
  666. //Wait for ISR to complete multiple iterations
  667. xSemaphoreTake(done_sem, portMAX_DELAY);
  668. //Cleanup
  669. cleanup_timer();
  670. vSemaphoreDelete(done_sem);
  671. for (int i = 0; i < NO_OF_RB_TYPES; i++) {
  672. vRingbufferDelete(buffer_handles[i]);
  673. }
  674. }
  675. /* ---------------------------- Test ring buffer SMP ---------------------------
  676. * The following test case tests each type of ring buffer in an SMP fashion. A
  677. * sending task and a receiving task is created. The sending task will split
  678. * a continuous piece of data into items of random length and send it to a ring
  679. * buffer. The receiving task will receive and check those items.
  680. * Every permutation of core pinning of the sending and receiving task will be
  681. * tested.
  682. */
  683. #define SRAND_SEED 3 //Arbitrarily chosen srand() seed
  684. #define SMP_TEST_ITERATIONS 4
  685. static const char continuous_data[] = {"A_very_long_string_that_will_be_split_into_"
  686. "items_of_random_lengths_and_sent_to_the_ring_"
  687. "buffer._The_maximum_random_length_will_also_"
  688. "be_increased_over_multiple_iterations_in_this"
  689. "_test"};
  690. #define CONT_DATA_LEN sizeof(continuous_data)
  691. //32-bit aligned size that guarantees a wrap around at some point
  692. #define CONT_DATA_TEST_BUFF_LEN (((CONT_DATA_LEN/2) + 0x03) & ~0x3)
  693. typedef struct {
  694. RingbufHandle_t buffer;
  695. RingbufferType_t type;
  696. } task_args_t;
  697. static SemaphoreHandle_t tasks_done;
  698. static SemaphoreHandle_t tx_done;
  699. static SemaphoreHandle_t rx_done;
  700. static void send_to_buffer(RingbufHandle_t buffer, size_t max_item_size)
  701. {
  702. for (int iter = 0; iter < SMP_TEST_ITERATIONS; iter++) {
  703. size_t bytes_sent = 0; //Number of data bytes sent in this iteration
  704. size_t next_item_size; //Size of next item to send
  705. while (bytes_sent < CONT_DATA_LEN) {
  706. //Get size of next item
  707. next_item_size = rand() % (max_item_size + 1);
  708. if (next_item_size + bytes_sent > CONT_DATA_LEN) {
  709. next_item_size = CONT_DATA_LEN - bytes_sent;
  710. }
  711. //Send item
  712. TEST_ASSERT_MESSAGE(xRingbufferSend(buffer, (void *)&(continuous_data[bytes_sent]), next_item_size, TIMEOUT_TICKS) == pdTRUE, "Failed to send an item");
  713. bytes_sent += next_item_size;
  714. }
  715. xSemaphoreGive(tx_done);
  716. xSemaphoreTake(rx_done, portMAX_DELAY);
  717. }
  718. }
  719. static void read_from_buffer(RingbufHandle_t buffer, RingbufferType_t buf_type, size_t max_rec_size)
  720. {
  721. for (int iter = 0; iter < SMP_TEST_ITERATIONS; iter++) {
  722. size_t bytes_rec = 0; //Number of data bytes received in this iteration
  723. while (bytes_rec < CONT_DATA_LEN) {
  724. size_t item_size, item_size2; //Possible for allow split buffers to receive two items
  725. char *item_data, *item_data2;
  726. //Select appropriate receive function for type of ring buffer
  727. if (buf_type == RINGBUF_TYPE_NOSPLIT) {
  728. item_data = (char *)xRingbufferReceive(buffer, &item_size, TIMEOUT_TICKS);
  729. } else if (buf_type == RINGBUF_TYPE_ALLOWSPLIT) {
  730. BaseType_t ret = xRingbufferReceiveSplit(buffer, (void **)&item_data, (void **)&item_data2, &item_size, &item_size2, TIMEOUT_TICKS);
  731. TEST_ASSERT_MESSAGE(ret == pdTRUE, "Failed to receive any item");
  732. } else {
  733. item_data = (char *)xRingbufferReceiveUpTo(buffer, &item_size, TIMEOUT_TICKS, max_rec_size);
  734. }
  735. //Check received item and return it
  736. TEST_ASSERT_MESSAGE(item_data != NULL, "Failed to receive an item");
  737. if (buf_type == RINGBUF_TYPE_BYTEBUF) {
  738. TEST_ASSERT_MESSAGE(item_size <= max_rec_size, "Received data exceeds max size");
  739. }
  740. for (int i = 0; i < item_size; i++) {
  741. //Check item_data is valid
  742. TEST_ASSERT_MESSAGE(item_data[i] == continuous_data[bytes_rec + i], "Received data is corrupted");
  743. }
  744. bytes_rec += item_size;
  745. vRingbufferReturnItem(buffer, item_data);
  746. if (buf_type == RINGBUF_TYPE_ALLOWSPLIT && item_data2 != NULL) {
  747. //Check item_data2 is valid
  748. for (int i = 0; i < item_size2; i++) {
  749. TEST_ASSERT_MESSAGE(item_data2[i] == continuous_data[bytes_rec + i], "Received split data is corrupted");
  750. }
  751. bytes_rec += item_size2;
  752. vRingbufferReturnItem(buffer, item_data2);
  753. }
  754. }
  755. TEST_ASSERT_MESSAGE(bytes_rec == CONT_DATA_LEN, "Total length of received data is incorrect");
  756. xSemaphoreGive(rx_done);
  757. xSemaphoreTake(tx_done, portMAX_DELAY);
  758. }
  759. }
  760. static void send_task(void *args)
  761. {
  762. RingbufHandle_t buffer = ((task_args_t *)args)->buffer;
  763. size_t max_item_len = xRingbufferGetMaxItemSize(buffer);
  764. //Test sending short length items
  765. send_to_buffer(buffer, 1);
  766. //Test sending mid length items
  767. send_to_buffer(buffer, max_item_len/2);
  768. //Test sending long length items
  769. send_to_buffer(buffer, max_item_len);
  770. vTaskDelete(NULL);
  771. }
  772. static void rec_task(void *args)
  773. {
  774. RingbufHandle_t buffer = ((task_args_t *)args)->buffer;
  775. size_t max_rec_len = xRingbufferGetMaxItemSize(buffer);
  776. //Test receiving short length items
  777. read_from_buffer(buffer, ((task_args_t *)args)->type, 1);
  778. //Test receiving mid length items
  779. read_from_buffer(buffer, ((task_args_t *)args)->type, max_rec_len/2);
  780. //Test receiving long length items
  781. read_from_buffer(buffer, ((task_args_t *)args)->type, max_rec_len);
  782. xSemaphoreGive(tasks_done);
  783. vTaskDelete(NULL);
  784. }
  785. static void setup(void)
  786. {
  787. esp_rom_printf("Size of test data: %d\n", CONT_DATA_LEN);
  788. tx_done = xSemaphoreCreateBinary(); //Semaphore to indicate send is done for a particular iteration
  789. rx_done = xSemaphoreCreateBinary(); //Semaphore to indicate receive is done for a particular iteration
  790. tasks_done = xSemaphoreCreateBinary(); //Semaphore used to to indicate send and receive tasks completed running
  791. srand(SRAND_SEED); //Seed RNG
  792. }
  793. static void cleanup(void)
  794. {
  795. //Cleanup
  796. vSemaphoreDelete(tx_done);
  797. vSemaphoreDelete(rx_done);
  798. vSemaphoreDelete(tasks_done);
  799. }
  800. TEST_CASE("Test ring buffer SMP", "[esp_ringbuf]")
  801. {
  802. setup();
  803. //Iterate through buffer types (No split, split, then byte buff)
  804. for (RingbufferType_t buf_type = 0; buf_type < RINGBUF_TYPE_MAX; buf_type++) {
  805. //Create buffer
  806. task_args_t task_args;
  807. task_args.buffer = xRingbufferCreate(CONT_DATA_TEST_BUFF_LEN, buf_type); //Create buffer of selected type
  808. task_args.type = buf_type;
  809. TEST_ASSERT_MESSAGE(task_args.buffer != NULL, "Failed to create ring buffer");
  810. for (int prior_mod = -1; prior_mod < 2; prior_mod++) { //Test different relative priorities
  811. //Test every permutation of core affinity
  812. for (int send_core = 0; send_core < portNUM_PROCESSORS; send_core++) {
  813. for (int rec_core = 0; rec_core < portNUM_PROCESSORS; rec_core ++) {
  814. esp_rom_printf("Type: %d, PM: %d, SC: %d, RC: %d\n", buf_type, prior_mod, send_core, rec_core);
  815. xTaskCreatePinnedToCore(send_task, "send tsk", 2048, (void *)&task_args, 10 + prior_mod, NULL, send_core);
  816. xTaskCreatePinnedToCore(rec_task, "rec tsk", 2048, (void *)&task_args, 10, NULL, rec_core);
  817. xSemaphoreTake(tasks_done, portMAX_DELAY);
  818. vTaskDelay(5); //Allow idle to clean up
  819. }
  820. }
  821. }
  822. //Delete ring buffer
  823. vRingbufferDelete(task_args.buffer);
  824. vTaskDelay(10);
  825. }
  826. cleanup();
  827. }
  828. #if ( configSUPPORT_STATIC_ALLOCATION == 1 )
  829. TEST_CASE("Test static ring buffer SMP", "[esp_ringbuf]")
  830. {
  831. setup();
  832. //Iterate through buffer types (No split, split, then byte buff)
  833. for (RingbufferType_t buf_type = 0; buf_type < RINGBUF_TYPE_MAX; buf_type++) {
  834. StaticRingbuffer_t *buffer_struct;
  835. uint8_t *buffer_storage;
  836. //Allocate memory and create semaphores
  837. #if CONFIG_SPIRAM_USE_CAPS_ALLOC //When SPIRAM can only be allocated using heap_caps_malloc()
  838. buffer_struct = (StaticRingbuffer_t *)heap_caps_malloc(sizeof(StaticRingbuffer_t), MALLOC_CAP_SPIRAM);
  839. buffer_storage = (uint8_t *)heap_caps_malloc(sizeof(uint8_t)*CONT_DATA_TEST_BUFF_LEN, MALLOC_CAP_SPIRAM);
  840. #else //Case where SPIRAM is disabled or when SPIRAM is allocatable through malloc()
  841. buffer_struct = (StaticRingbuffer_t *)malloc(sizeof(StaticRingbuffer_t));
  842. buffer_storage = (uint8_t *)malloc(sizeof(uint8_t)*CONT_DATA_TEST_BUFF_LEN);
  843. #endif
  844. TEST_ASSERT(buffer_struct != NULL && buffer_storage != NULL);
  845. //Create buffer
  846. task_args_t task_args;
  847. task_args.buffer = xRingbufferCreateStatic(CONT_DATA_TEST_BUFF_LEN, buf_type, buffer_storage, buffer_struct); //Create buffer of selected type
  848. task_args.type = buf_type;
  849. TEST_ASSERT_MESSAGE(task_args.buffer != NULL, "Failed to create ring buffer");
  850. for (int prior_mod = -1; prior_mod < 2; prior_mod++) { //Test different relative priorities
  851. //Test every permutation of core affinity
  852. for (int send_core = 0; send_core < portNUM_PROCESSORS; send_core++) {
  853. for (int rec_core = 0; rec_core < portNUM_PROCESSORS; rec_core ++) {
  854. esp_rom_printf("Type: %d, PM: %d, SC: %d, RC: %d\n", buf_type, prior_mod, send_core, rec_core);
  855. xTaskCreatePinnedToCore(send_task, "send tsk", 2048, (void *)&task_args, 10 + prior_mod, NULL, send_core);
  856. xTaskCreatePinnedToCore(rec_task, "rec tsk", 2048, (void *)&task_args, 10, NULL, rec_core);
  857. xSemaphoreTake(tasks_done, portMAX_DELAY);
  858. vTaskDelay(5); //Allow idle to clean up
  859. }
  860. }
  861. }
  862. //Delete ring buffer
  863. vRingbufferDelete(task_args.buffer);
  864. //Deallocate memory
  865. free(buffer_storage);
  866. free(buffer_struct);
  867. vTaskDelay(10);
  868. }
  869. cleanup();
  870. }
  871. #endif
  872. /* -------------------------- Test ring buffer IRAM ------------------------- */
  873. static IRAM_ATTR __attribute__((noinline)) bool iram_ringbuf_test(void)
  874. {
  875. bool result = true;
  876. RingbufHandle_t handle = xRingbufferCreate(CONT_DATA_TEST_BUFF_LEN, RINGBUF_TYPE_NOSPLIT);
  877. result = result && (handle != NULL);
  878. spi_flash_guard_get()->start(); // Disables flash cache
  879. xRingbufferGetMaxItemSize(handle);
  880. spi_flash_guard_get()->end(); // Re-enables flash cache
  881. vRingbufferDelete(handle);
  882. return result;
  883. }
  884. TEST_CASE("Test ringbuffer functions work with flash cache disabled", "[esp_ringbuf]")
  885. {
  886. TEST_ASSERT( iram_ringbuf_test() );
  887. }