uart_rxnb_txnb.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. /*
  2. * Copyright (c) 2006-2025 RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2021-06-16 KyleChan the first version
  9. * 2025-11-13 CYFS Add standardized utest documentation block
  10. */
  11. /**
  12. * Test Case Name: UART Non-Blocking RX & TX Integration Test
  13. *
  14. * Test Objectives:
  15. * - Validate fully non-blocking UART workflow leveraging TX completion and RX indication callbacks
  16. * - Verify APIs: rt_device_find, rt_device_control(RT_DEVICE_CTRL_CONFIG / RT_SERIAL_CTRL_SET_RX_TIMEOUT),
  17. * rt_device_open with RT_DEVICE_FLAG_RX_NON_BLOCKING | RT_DEVICE_FLAG_TX_NON_BLOCKING,
  18. * rt_device_set_rx_indicate, rt_device_set_tx_complete, rt_device_read, rt_device_write, rt_sem APIs
  19. *
  20. * Test Scenarios:
  21. * - **Scenario 1 (Callback-Synchronized Duplex Transfer / tc_uart_api):**
  22. * 1. Configure UART buffers (optional DMA ping buffer) and create paired RX/TX semaphores.
  23. * 2. Register RX indication and TX completion callbacks to release semaphores on asynchronous events.
  24. * 3. Launch sender/receiver threads for deterministic and random payload sizes; sender fragments writes, waiting on TX semaphore, while receiver waits on RX semaphore before draining data.
  25. * 4. Verify data ordering continuously and stop once requested byte count satisfied per iteration.
  26. *
  27. * Verification Metrics:
  28. * - Received bytes maintain sequential increments; `uart_result` never flips to RT_FALSE.
  29. * - Semaphore waits succeed; non-blocking read/write calls progress without deadlock.
  30. * - UART handles close cleanly; semaphores deleted during cleanup.
  31. *
  32. * Dependencies:
  33. * - Requires `RT_UTEST_SERIAL_V2`, loopback on `RT_SERIAL_TC_DEVICE_NAME`, and callback-capable UART driver.
  34. * - Adequate heap for buffers, semaphores, and two 1 KB thread stacks.
  35. *
  36. * Expected Results:
  37. * - Unit test completes without assertions; logs reflect pass counts across length sweep.
  38. * - Utest harness prints `[ PASSED ] [ result ] testcase (components.drivers.serial.v2.uart_rxnb_txnb)`.
  39. */
  40. #include <rtthread.h>
  41. #include "utest.h"
  42. #include <rtdevice.h>
  43. #include <stdlib.h>
  44. #ifdef RT_UTEST_SERIAL_V2
  45. static struct rt_serial_device *serial;
  46. static rt_sem_t tx_sem;
  47. static rt_sem_t rx_sem;
  48. static rt_uint8_t uart_over_flag;
  49. static rt_bool_t uart_result = RT_TRUE;
  50. static rt_err_t uart_find(void)
  51. {
  52. serial = (struct rt_serial_device *)rt_device_find(RT_SERIAL_TC_DEVICE_NAME);
  53. if (serial == RT_NULL)
  54. {
  55. LOG_E("find %s device failed!\n", RT_SERIAL_TC_DEVICE_NAME);
  56. return -RT_ERROR;
  57. }
  58. return RT_EOK;
  59. }
  60. static rt_err_t uart_tx_completion(rt_device_t device, void *buffer)
  61. {
  62. rt_sem_release(tx_sem);
  63. return RT_EOK;
  64. }
  65. static rt_err_t uart_rx_indicate(rt_device_t device, rt_size_t size)
  66. {
  67. rt_sem_release(rx_sem);
  68. return RT_EOK;
  69. }
  70. static void uart_send_entry(void *parameter)
  71. {
  72. rt_uint8_t *uart_write_buffer;
  73. rt_uint16_t send_len, len = 0;
  74. rt_err_t result;
  75. rt_uint32_t i = 0;
  76. send_len = *(rt_uint16_t *)parameter;
  77. /* assign send buffer */
  78. uart_write_buffer = (rt_uint8_t *)rt_malloc(send_len);
  79. if (uart_write_buffer == RT_NULL)
  80. {
  81. LOG_E("Without spare memory for uart dma!");
  82. uart_result = RT_FALSE;
  83. return;
  84. }
  85. rt_memset(uart_write_buffer, 0, send_len);
  86. for (i = 0; i < send_len; i++)
  87. {
  88. uart_write_buffer[i] = (rt_uint8_t)i;
  89. }
  90. /* send buffer */
  91. while (send_len - len)
  92. {
  93. len += rt_device_write(&serial->parent, 0, uart_write_buffer + len, send_len - len);
  94. result = rt_sem_take(tx_sem, RT_WAITING_FOREVER);
  95. if (result != RT_EOK)
  96. {
  97. LOG_E("take sem err in send.");
  98. }
  99. }
  100. rt_free(uart_write_buffer);
  101. }
  102. static void uart_rec_entry(void *parameter)
  103. {
  104. rt_uint16_t rev_len;
  105. rev_len = *(rt_uint16_t *)parameter;
  106. rt_uint8_t *uart_write_buffer;
  107. uart_write_buffer = (rt_uint8_t *)rt_calloc(1, rev_len + 1);
  108. rt_int32_t cnt, i;
  109. rt_uint8_t last_old_data;
  110. rt_bool_t fisrt_flag = RT_TRUE;
  111. rt_uint32_t all_receive_length = 0;
  112. while (1)
  113. {
  114. rt_err_t result;
  115. result = rt_sem_take(rx_sem, RT_WAITING_FOREVER);
  116. if (result != RT_EOK)
  117. {
  118. LOG_E("take sem err in recv.");
  119. }
  120. cnt = rt_device_read(&serial->parent, 0, (void *)uart_write_buffer, rev_len);
  121. if (cnt == 0)
  122. {
  123. continue;
  124. }
  125. if (fisrt_flag != RT_TRUE)
  126. {
  127. if ((rt_uint8_t)(last_old_data + 1) != uart_write_buffer[0])
  128. {
  129. LOG_E("_Read Different data -> former data: %x, current data: %x.", last_old_data, uart_write_buffer[0]);
  130. uart_result = RT_FALSE;
  131. rt_free(uart_write_buffer);
  132. return;
  133. }
  134. }
  135. else
  136. {
  137. fisrt_flag = RT_FALSE;
  138. }
  139. for (i = 0; i < cnt - 1; i++)
  140. {
  141. if ((rt_uint8_t)(uart_write_buffer[i] + 1) != uart_write_buffer[i + 1])
  142. {
  143. LOG_E("Read Different data -> former data: %x, current data: %x.", uart_write_buffer[i], uart_write_buffer[i + 1]);
  144. uart_result = RT_FALSE;
  145. rt_free(uart_write_buffer);
  146. return;
  147. }
  148. }
  149. all_receive_length += cnt;
  150. if (all_receive_length >= rev_len)
  151. break;
  152. else
  153. last_old_data = uart_write_buffer[cnt - 1];
  154. }
  155. rt_free(uart_write_buffer);
  156. uart_over_flag = RT_TRUE;
  157. }
  158. static rt_err_t uart_api(rt_uint16_t test_buf)
  159. {
  160. rt_thread_t thread_send = RT_NULL;
  161. rt_thread_t thread_recv = RT_NULL;
  162. rt_err_t result = RT_EOK;
  163. uart_over_flag = RT_FALSE;
  164. result = uart_find();
  165. if (result != RT_EOK)
  166. {
  167. return -RT_ERROR;
  168. }
  169. rx_sem = rt_sem_create("rx_sem", 0, RT_IPC_FLAG_PRIO);
  170. if (rx_sem == RT_NULL)
  171. {
  172. LOG_E("Init rx_sem failed.");
  173. uart_result = RT_FALSE;
  174. return -RT_ERROR;
  175. }
  176. tx_sem = rt_sem_create("tx_sem", 0, RT_IPC_FLAG_PRIO);
  177. if (tx_sem == RT_NULL)
  178. {
  179. LOG_E("Init tx_sem failed.");
  180. uart_result = RT_FALSE;
  181. return -RT_ERROR;
  182. }
  183. /* reinitialize */
  184. struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
  185. config.baud_rate = BAUD_RATE_115200;
  186. config.rx_bufsz = RT_SERIAL_TC_RXBUF_SIZE;
  187. config.tx_bufsz = RT_SERIAL_TC_TXBUF_SIZE;
  188. #ifdef RT_SERIAL_USING_DMA
  189. config.dma_ping_bufsz = RT_SERIAL_TC_RXBUF_SIZE / 2;
  190. #endif
  191. rt_device_control(&serial->parent, RT_DEVICE_CTRL_CONFIG, &config);
  192. result = rt_device_open(&serial->parent, RT_DEVICE_FLAG_RX_NON_BLOCKING | RT_DEVICE_FLAG_TX_NON_BLOCKING);
  193. if (result != RT_EOK)
  194. {
  195. LOG_E("Open uart device failed.");
  196. uart_result = RT_FALSE;
  197. return -RT_ERROR;
  198. }
  199. rt_int32_t timeout = 5000;
  200. rt_device_control(&serial->parent, RT_SERIAL_CTRL_SET_RX_TIMEOUT, (void *)&timeout);
  201. /* set receive callback function */
  202. result = rt_device_set_tx_complete(&serial->parent, uart_tx_completion);
  203. if (result != RT_EOK)
  204. {
  205. goto __exit;
  206. }
  207. result = rt_device_set_rx_indicate(&serial->parent, uart_rx_indicate);
  208. if (result != RT_EOK)
  209. {
  210. goto __exit;
  211. }
  212. thread_recv = rt_thread_create("uart_recv", uart_rec_entry, &test_buf, 1024, RT_THREAD_PRIORITY_MAX - 5, 10);
  213. thread_send = rt_thread_create("uart_send", uart_send_entry, &test_buf, 1024, RT_THREAD_PRIORITY_MAX - 4, 10);
  214. if (thread_send != RT_NULL && thread_recv != RT_NULL)
  215. {
  216. rt_thread_startup(thread_recv);
  217. rt_thread_startup(thread_send);
  218. }
  219. else
  220. {
  221. result = -RT_ERROR;
  222. goto __exit;
  223. }
  224. while (1)
  225. {
  226. if (uart_result != RT_TRUE)
  227. {
  228. LOG_E("The test for uart dma is failure.");
  229. result = -RT_ERROR;
  230. goto __exit;
  231. }
  232. if (uart_over_flag == RT_TRUE)
  233. {
  234. goto __exit;
  235. }
  236. /* waiting for test over */
  237. rt_thread_mdelay(5);
  238. }
  239. __exit:
  240. if (tx_sem)
  241. rt_sem_delete(tx_sem);
  242. if (rx_sem)
  243. rt_sem_delete(rx_sem);
  244. rt_device_close(&serial->parent);
  245. rt_thread_mdelay(5);
  246. uart_over_flag = RT_FALSE;
  247. return result;
  248. }
  249. static void tc_uart_api(void)
  250. {
  251. rt_uint32_t count = 0;
  252. rt_uint16_t num = 0;
  253. rt_uint32_t i = 0;
  254. for (i = 1; i < 10; i++)
  255. {
  256. if (uart_api(RT_SERIAL_TC_TXBUF_SIZE * i + i % 2) == RT_EOK)
  257. LOG_I("data_lens [%4d], it is correct to read and write data. [%d] count testing.", RT_SERIAL_TC_TXBUF_SIZE * i + i % 2, ++count);
  258. else
  259. {
  260. LOG_E("uart test error");
  261. goto __exit;
  262. }
  263. }
  264. for (i = 1; i < 10; i++)
  265. {
  266. if (uart_api(RT_SERIAL_TC_RXBUF_SIZE * i + i % 2) == RT_EOK)
  267. LOG_I("data_lens [%4d], it is correct to read and write data. [%d] count testing.", RT_SERIAL_TC_RXBUF_SIZE * i + i % 2, ++count);
  268. else
  269. {
  270. LOG_E("uart test error");
  271. goto __exit;
  272. }
  273. }
  274. srand(rt_tick_get());
  275. while (RT_SERIAL_TC_SEND_ITERATIONS - count)
  276. {
  277. num = (rand() % 1000) + 1;
  278. if (uart_api(num) == RT_EOK)
  279. LOG_I("data_lens [%4d], it is correct to read and write data. [%d] count testing.", num, ++count);
  280. else
  281. {
  282. LOG_E("uart test error");
  283. break;
  284. }
  285. }
  286. __exit:
  287. uassert_true(uart_result == RT_TRUE);
  288. }
  289. static rt_err_t utest_tc_init(void)
  290. {
  291. LOG_I("UART TEST: Please connect Tx and Rx directly for self testing.");
  292. return RT_EOK;
  293. }
  294. static rt_err_t utest_tc_cleanup(void)
  295. {
  296. tx_sem = RT_NULL;
  297. uart_result = RT_TRUE;
  298. uart_over_flag = RT_FALSE;
  299. rt_device_t uart_dev = rt_device_find(RT_SERIAL_TC_DEVICE_NAME);
  300. while (rt_device_close(uart_dev) != -RT_ERROR);
  301. return RT_EOK;
  302. }
  303. static void testcase(void)
  304. {
  305. UTEST_UNIT_RUN(tc_uart_api);
  306. }
  307. UTEST_TC_EXPORT(testcase, "components.drivers.serial.v2.uart_rxnb_txnb", utest_tc_init, utest_tc_cleanup, 30);
  308. #endif