uart_posix_nonblock.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  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 Non-Blocking Test
  13. *
  14. * Test Objectives:
  15. * - Validate POSIX-layer non-blocking serial operations using termios configuration
  16. * - Verify APIs: open/close, tcgetattr/tcsetattr, cfsetispeed/cfsetospeed, fcntl(O_NONBLOCK),
  17. * read, write, rt_thread_mdelay
  18. *
  19. * Test Scenarios:
  20. * - **Scenario 1 (Non-Blocking Echo / tc_uart_api):**
  21. * 1. Open POSIX device `RT_SERIAL_POSIX_TC_DEVICE_NAME`, configure baud, frame format, and disable flow control.
  22. * 2. Enable O_NONBLOCK mode and allocate small TX/RX buffer.
  23. * 3. Loop `RT_SERIAL_TC_SEND_ITERATIONS` times, issuing fixed-size and random-length writes, followed by reads after short delays to confirm echo data availability.
  24. *
  25. * Verification Metrics:
  26. * - Each write/read pair returns the expected number of bytes.
  27. * - No system calls fail; routine returns RT_TRUE signalling success.
  28. *
  29. * Dependencies:
  30. * - Requires `RT_UTEST_SERIAL_V2` with POSIX device exposure (`RT_SERIAL_POSIX_TC_DEVICE_NAME`) and loopback wiring.
  31. * - Operating environment must provide termios/fcntl APIs (e.g., RT-Thread POSIX layer or Linux host).
  32. *
  33. * Expected Results:
  34. * - Test executes without assertions; logs remain quiet unless errors occur.
  35. * - Utest harness prints `[ PASSED ] [ result ] testcase (components.drivers.serial.v2.uart_posix_nonblock)`.
  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_err_t uart_find(void)
  49. {
  50. serial_fd = open(RT_SERIAL_POSIX_TC_DEVICE_NAME, O_RDWR);
  51. if (serial_fd == -1)
  52. {
  53. LOG_E("find %s device failed!\n", RT_SERIAL_TC_DEVICE_NAME);
  54. return -RT_ERROR;
  55. }
  56. return RT_EOK;
  57. }
  58. static rt_err_t configureSerial(int fd, int baud)
  59. {
  60. int32_t result = 0;
  61. struct termios options;
  62. result = tcgetattr(fd, &options); // 获取当前端口的属性
  63. if (result == -1)
  64. return -RT_ERROR;
  65. // 设置波特率
  66. result = cfsetispeed(&options, baud); // 设置输入波特率
  67. if (result == -1)
  68. return -RT_ERROR;
  69. result = cfsetospeed(&options, baud); // 设置输出波特率
  70. if (result == -1)
  71. return -RT_ERROR;
  72. // 设置数据位
  73. options.c_cflag &= ~PARENB; // 清除校验位,无校验
  74. options.c_cflag &= ~CSTOPB; // 仅一个停止位
  75. options.c_cflag &= ~CSIZE; // 清除掩码
  76. options.c_cflag |= CS8; // 8位数据
  77. // 设置无流控
  78. options.c_cflag &= ~CRTSCTS; // 不使用硬件流控制
  79. options.c_iflag &= ~(IXON | IXOFF | IXANY); // 不使用软件流控制
  80. // 使能接收器和发送器
  81. options.c_cflag |= CLOCAL | CREAD;
  82. // 设置行终止符
  83. options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
  84. // 应用属性
  85. result = tcsetattr(fd, TCSANOW, &options);
  86. if (result == -1)
  87. return -RT_ERROR;
  88. return RT_EOK;
  89. }
  90. static rt_err_t uart_api()
  91. {
  92. rt_err_t result = RT_EOK;
  93. rt_uint8_t *uart_write_buffer;
  94. rt_int32_t cnt, i, send_size;
  95. int flags = 0;
  96. result = uart_find();
  97. if (result != RT_EOK)
  98. {
  99. return -RT_ERROR;
  100. }
  101. result = configureSerial(serial_fd, B115200);
  102. if (result == -1)
  103. {
  104. goto __exit;
  105. }
  106. flags = fcntl(serial_fd, F_GETFL, 0);
  107. if (flags == -1)
  108. {
  109. goto __exit;
  110. }
  111. result = fcntl(serial_fd, F_SETFL, flags | O_NONBLOCK);
  112. if (result == -1)
  113. {
  114. goto __exit;
  115. }
  116. uart_write_buffer = (rt_uint8_t *)rt_malloc(100);
  117. for (i = 0; i < RT_SERIAL_TC_SEND_ITERATIONS; i++)
  118. {
  119. send_size = 1;
  120. cnt = write(serial_fd, uart_write_buffer, send_size);
  121. if (cnt != send_size)
  122. {
  123. result = -RT_ERROR;
  124. goto __exit;
  125. }
  126. rt_thread_mdelay(2);
  127. cnt = read(serial_fd, (void *)uart_write_buffer, send_size);
  128. if (cnt != send_size)
  129. {
  130. result = -RT_ERROR;
  131. goto __exit;
  132. }
  133. send_size = rand() % 30 + 1;
  134. cnt = write(serial_fd, uart_write_buffer, send_size);
  135. if (cnt != send_size)
  136. {
  137. LOG_E("uart write failed %d %d", cnt, send_size);
  138. result = -RT_ERROR;
  139. goto __exit;
  140. }
  141. rt_thread_mdelay(send_size * 0.0868 + 5);
  142. cnt = read(serial_fd, (void *)uart_write_buffer, send_size + 1);
  143. if (cnt != send_size)
  144. {
  145. LOG_E("uart read failed %d %d", cnt, send_size);
  146. result = -RT_ERROR;
  147. goto __exit;
  148. }
  149. }
  150. __exit:
  151. rt_thread_mdelay(5);
  152. if (uart_write_buffer)
  153. rt_free(uart_write_buffer);
  154. close(serial_fd);
  155. return result == RT_EOK ? RT_TRUE : RT_FALSE;
  156. }
  157. static void tc_uart_api(void)
  158. {
  159. uassert_true(uart_api() == RT_TRUE);
  160. }
  161. static rt_err_t utest_tc_init(void)
  162. {
  163. LOG_I("UART TEST: Please connect Tx and Rx directly for self testing.");
  164. return RT_EOK;
  165. }
  166. static rt_err_t utest_tc_cleanup(void)
  167. {
  168. close(serial_fd);
  169. return RT_EOK;
  170. }
  171. static void testcase(void)
  172. {
  173. UTEST_UNIT_RUN(tc_uart_api);
  174. }
  175. UTEST_TC_EXPORT(testcase, "components.drivers.serial.v2.uart_posix_nonblock", utest_tc_init, utest_tc_cleanup, 30);
  176. #endif /* TC_UART_USING_TC */