uart_posix_echo_block.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  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 POSIX Blocking Echo Test
  13. *
  14. * Test Objectives:
  15. * - Validate POSIX blocking serial IO paths with multi-threaded send/receive verification
  16. * - Verify APIs: open/close, tcgetattr/tcsetattr, cfsetispeed/cfsetospeed, fcntl clearing O_NONBLOCK,
  17. * read, write, rt_thread_create/startup
  18. *
  19. * Test Scenarios:
  20. * - **Scenario 1 (Length Sweep Echo / tc_uart_api):**
  21. * 1. Open POSIX serial device, configure canonical settings, and enforce blocking mode.
  22. * 2. Launch sender/receiver threads; sender streams sequential byte patterns while receiver checks ordering until quota met.
  23. * 3. Iterate through deterministic and random lengths, mirroring behavior of kernel-space blocking tests, and monitor global flags for errors.
  24. *
  25. * Verification Metrics:
  26. * - Received data remains sequential; `uart_result` stays RT_TRUE; `uart_over_flag` raised after completion.
  27. * - No termios or fcntl calls fail; thread creation succeeds.
  28. *
  29. * Dependencies:
  30. * - Requires `RT_UTEST_SERIAL_V2` with POSIX serial device `RT_SERIAL_POSIX_TC_DEVICE_NAME` looped back.
  31. * - Host environment must provide POSIX termios/fcntl APIs; adequate heap for buffers and thread stacks.
  32. *
  33. * Expected Results:
  34. * - Test completes without assertions; logs reflect pass counts for each payload length.
  35. * - Utest harness prints `[ PASSED ] [ result ] testcase (components.drivers.serial.v2.uart_posix_echo_block)`.
  36. */
  37. #include <rtthread.h>
  38. #include "utest.h"
  39. #include <rtdevice.h>
  40. #include <stdio.h>
  41. #include <stdlib.h>
  42. #include <string.h>
  43. #include <termios.h>
  44. #include <fcntl.h>
  45. #include <unistd.h>
  46. #ifdef RT_UTEST_SERIAL_V2
  47. static int32_t serial_fd;
  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_fd = open(RT_SERIAL_POSIX_TC_DEVICE_NAME, O_RDWR);
  53. if (serial_fd == -1)
  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 configureSerial(int fd, int baud)
  61. {
  62. int32_t result = 0;
  63. struct termios options;
  64. result = tcgetattr(fd, &options); // 获取当前端口的属性
  65. if (result == -1)
  66. return -RT_ERROR;
  67. // 设置波特率
  68. result = cfsetispeed(&options, baud); // 设置输入波特率
  69. if (result == -1)
  70. return -RT_ERROR;
  71. result = cfsetospeed(&options, baud); // 设置输出波特率
  72. if (result == -1)
  73. return -RT_ERROR;
  74. // 设置数据位
  75. options.c_cflag &= ~PARENB; // 清除校验位,无校验
  76. options.c_cflag &= ~CSTOPB; // 仅一个停止位
  77. options.c_cflag &= ~CSIZE; // 清除掩码
  78. options.c_cflag |= CS8; // 8位数据
  79. // 设置无流控
  80. options.c_cflag &= ~CRTSCTS; // 不使用硬件流控制
  81. options.c_iflag &= ~(IXON | IXOFF | IXANY); // 不使用软件流控制
  82. // 使能接收器和发送器
  83. options.c_cflag |= CLOCAL | CREAD;
  84. // 设置行终止符
  85. options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
  86. // 应用属性
  87. result = tcsetattr(fd, TCSANOW, &options);
  88. if (result == -1)
  89. return -RT_ERROR;
  90. return RT_EOK;
  91. }
  92. static void uart_send_entry(void *parameter)
  93. {
  94. rt_uint8_t *uart_write_buffer;
  95. rt_uint16_t send_len;
  96. rt_uint32_t i = 0;
  97. send_len = *(rt_uint16_t *)parameter;
  98. /* assign send buffer */
  99. uart_write_buffer = (rt_uint8_t *)rt_malloc(send_len);
  100. if (uart_write_buffer == RT_NULL)
  101. {
  102. LOG_E("Without spare memory for uart dma!");
  103. uart_result = RT_FALSE;
  104. return;
  105. }
  106. rt_memset(uart_write_buffer, 0, send_len);
  107. for (i = 0; i < send_len; i++)
  108. {
  109. uart_write_buffer[i] = (rt_uint8_t)i;
  110. }
  111. /* send buffer */
  112. if (write(serial_fd, uart_write_buffer, send_len) != send_len)
  113. {
  114. LOG_E("device write failed\r\n");
  115. }
  116. rt_free(uart_write_buffer);
  117. }
  118. static void uart_rec_entry(void *parameter)
  119. {
  120. rt_uint16_t rev_len;
  121. rev_len = *(rt_uint16_t *)parameter;
  122. rt_uint8_t *uart_write_buffer;
  123. uart_write_buffer = (rt_uint8_t *)rt_calloc(1, rev_len + 1);
  124. rt_int32_t cnt, i;
  125. rt_uint8_t last_old_data;
  126. rt_bool_t fisrt_flag = RT_TRUE;
  127. rt_uint32_t all_receive_length = 0;
  128. while (1)
  129. {
  130. cnt = read(serial_fd, (void *)uart_write_buffer, rev_len);
  131. if (cnt == 0)
  132. {
  133. continue;
  134. }
  135. if (fisrt_flag != RT_TRUE)
  136. {
  137. if ((rt_uint8_t)(last_old_data + 1) != uart_write_buffer[0])
  138. {
  139. LOG_E("_Read Different data -> former data: %x, current data: %x.", last_old_data, uart_write_buffer[0]);
  140. uart_result = RT_FALSE;
  141. rt_free(uart_write_buffer);
  142. return;
  143. }
  144. }
  145. else
  146. {
  147. fisrt_flag = RT_FALSE;
  148. }
  149. for (i = 0; i < cnt - 1; i++)
  150. {
  151. if ((rt_uint8_t)(uart_write_buffer[i] + 1) != uart_write_buffer[i + 1])
  152. {
  153. LOG_E("Read Different data -> former data: %x, current data: %x.", uart_write_buffer[i], uart_write_buffer[i + 1]);
  154. uart_result = RT_FALSE;
  155. rt_free(uart_write_buffer);
  156. return;
  157. }
  158. }
  159. all_receive_length += cnt;
  160. if (all_receive_length >= rev_len)
  161. break;
  162. else
  163. last_old_data = uart_write_buffer[cnt - 1];
  164. }
  165. rt_free(uart_write_buffer);
  166. uart_over_flag = RT_TRUE;
  167. }
  168. static rt_err_t uart_api(rt_uint16_t length)
  169. {
  170. rt_thread_t thread_send = RT_NULL;
  171. rt_thread_t thread_recv = RT_NULL;
  172. rt_err_t result = RT_EOK;
  173. int flags = 0;
  174. uart_over_flag = RT_FALSE;
  175. result = uart_find();
  176. if (result != RT_EOK)
  177. {
  178. return -RT_ERROR;
  179. }
  180. result = configureSerial(serial_fd, B115200);
  181. if (result == -1)
  182. {
  183. goto __exit;
  184. }
  185. flags = fcntl(serial_fd, F_GETFL, 0);
  186. if (flags == -1)
  187. {
  188. goto __exit;
  189. }
  190. result = fcntl(serial_fd, F_SETFL, flags & ~O_NONBLOCK);
  191. if (result == -1)
  192. {
  193. goto __exit;
  194. }
  195. thread_send = rt_thread_create("uart_send", uart_send_entry, &length, 1024, RT_THREAD_PRIORITY_MAX - 4, 10);
  196. thread_recv = rt_thread_create("uart_recv", uart_rec_entry, &length, 1024, RT_THREAD_PRIORITY_MAX - 5, 10);
  197. if ((thread_send != RT_NULL) && (thread_recv != RT_NULL))
  198. {
  199. rt_thread_startup(thread_send);
  200. rt_thread_startup(thread_recv);
  201. }
  202. else
  203. {
  204. result = -RT_ERROR;
  205. goto __exit;
  206. }
  207. while (1)
  208. {
  209. if (uart_result != RT_TRUE)
  210. {
  211. LOG_E("The test for uart dma is failure.");
  212. result = -RT_ERROR;
  213. goto __exit;
  214. }
  215. if (uart_over_flag == RT_TRUE)
  216. {
  217. goto __exit;
  218. }
  219. /* waiting for test over */
  220. rt_thread_mdelay(5);
  221. }
  222. __exit:
  223. rt_thread_mdelay(5);
  224. close(serial_fd);
  225. uart_over_flag = RT_FALSE;
  226. return result;
  227. }
  228. static void tc_uart_api(void)
  229. {
  230. rt_uint32_t times = 0;
  231. rt_uint16_t num = 0;
  232. rt_uint32_t i = 0;
  233. while (RT_SERIAL_POSIX_TC_SEND_ITERATIONS - times)
  234. {
  235. num = (rand() % 1000) + 1;
  236. if (uart_api(num) == RT_EOK)
  237. LOG_I("data_lens [%4d], it is correct to read and write data. [%d] times testing.", num, ++times);
  238. else
  239. {
  240. LOG_E("uart test error");
  241. break;
  242. }
  243. }
  244. __exit:
  245. uassert_true(uart_result == RT_TRUE);
  246. }
  247. static rt_err_t utest_tc_init(void)
  248. {
  249. LOG_I("UART TEST: Please connect Tx and Rx directly for self testing.");
  250. return RT_EOK;
  251. }
  252. static rt_err_t utest_tc_cleanup(void)
  253. {
  254. uart_result = RT_TRUE;
  255. uart_over_flag = RT_FALSE;
  256. close(serial_fd);
  257. return RT_EOK;
  258. }
  259. static void testcase(void)
  260. {
  261. UTEST_UNIT_RUN(tc_uart_api);
  262. }
  263. UTEST_TC_EXPORT(testcase, "components.drivers.serial.v2.uart_posix_echo_block", utest_tc_init, utest_tc_cleanup, 30);
  264. #endif /* TC_UART_USING_TC */