test_ringbuf.c 43 KB

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