1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
|
/*
* Copyright (c) 2006-2025 RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-06-16 KyleChan the first version
* 2025-11-13 CYFS Add standardized utest documentation block
*/
/**
* Test Case Name: UART POSIX Non-Blocking Test
*
* Test Objectives:
* - Validate POSIX-layer non-blocking serial operations using termios configuration
* - Verify APIs: open/close, tcgetattr/tcsetattr, cfsetispeed/cfsetospeed, fcntl(O_NONBLOCK),
* read, write, rt_thread_mdelay
*
* Test Scenarios:
* - **Scenario 1 (Non-Blocking Echo / tc_uart_api):**
* 1. Open POSIX device `RT_SERIAL_POSIX_TC_DEVICE_NAME`, configure baud, frame format, and disable flow control.
* 2. Enable O_NONBLOCK mode and allocate small TX/RX buffer.
* 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.
*
* Verification Metrics:
* - Each write/read pair returns the expected number of bytes.
* - No system calls fail; routine returns RT_TRUE signalling success.
*
* Dependencies:
* - Requires `RT_UTEST_SERIAL_V2` with POSIX device exposure (`RT_SERIAL_POSIX_TC_DEVICE_NAME`) and loopback wiring.
* - Operating environment must provide termios/fcntl APIs (e.g., RT-Thread POSIX layer or Linux host).
*
* Expected Results:
* - Test executes without assertions; logs remain quiet unless errors occur.
* - Utest harness prints `[ PASSED ] [ result ] testcase (components.drivers.serial.v2.uart_posix_nonblock)`.
*/
#include <rtthread.h>
#include "utest.h"
#include <rtdevice.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <fcntl.h>
#include <unistd.h>
#ifdef RT_UTEST_SERIAL_V2
static int32_t serial_fd;
static rt_err_t uart_find(void)
{
serial_fd = open(RT_SERIAL_POSIX_TC_DEVICE_NAME, O_RDWR);
if (serial_fd == -1)
{
LOG_E("find %s device failed!\n", RT_SERIAL_TC_DEVICE_NAME);
return -RT_ERROR;
}
return RT_EOK;
}
static rt_err_t configureSerial(int fd, int baud)
{
int32_t result = 0;
struct termios options;
result = tcgetattr(fd, &options); // 获取当前端口的属性
if (result == -1)
return -RT_ERROR;
// 设置波特率
result = cfsetispeed(&options, baud); // 设置输入波特率
if (result == -1)
return -RT_ERROR;
result = cfsetospeed(&options, baud); // 设置输出波特率
if (result == -1)
return -RT_ERROR;
// 设置数据位
options.c_cflag &= ~PARENB; // 清除校验位,无校验
options.c_cflag &= ~CSTOPB; // 仅一个停止位
options.c_cflag &= ~CSIZE; // 清除掩码
options.c_cflag |= CS8; // 8位数据
// 设置无流控
options.c_cflag &= ~CRTSCTS; // 不使用硬件流控制
options.c_iflag &= ~(IXON | IXOFF | IXANY); // 不使用软件流控制
// 使能接收器和发送器
options.c_cflag |= CLOCAL | CREAD;
// 设置行终止符
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
// 应用属性
result = tcsetattr(fd, TCSANOW, &options);
if (result == -1)
return -RT_ERROR;
return RT_EOK;
}
static rt_err_t uart_api()
{
rt_err_t result = RT_EOK;
rt_uint8_t *uart_write_buffer;
rt_int32_t cnt, i, send_size;
int flags = 0;
result = uart_find();
if (result != RT_EOK)
{
return -RT_ERROR;
}
result = configureSerial(serial_fd, B115200);
if (result == -1)
{
goto __exit;
}
flags = fcntl(serial_fd, F_GETFL, 0);
if (flags == -1)
{
goto __exit;
}
result = fcntl(serial_fd, F_SETFL, flags | O_NONBLOCK);
if (result == -1)
{
goto __exit;
}
uart_write_buffer = (rt_uint8_t *)rt_malloc(100);
for (i = 0; i < RT_SERIAL_TC_SEND_ITERATIONS; i++)
{
send_size = 1;
cnt = write(serial_fd, uart_write_buffer, send_size);
if (cnt != send_size)
{
result = -RT_ERROR;
goto __exit;
}
rt_thread_mdelay(2);
cnt = read(serial_fd, (void *)uart_write_buffer, send_size);
if (cnt != send_size)
{
result = -RT_ERROR;
goto __exit;
}
send_size = rand() % 30 + 1;
cnt = write(serial_fd, uart_write_buffer, send_size);
if (cnt != send_size)
{
LOG_E("uart write failed %d %d", cnt, send_size);
result = -RT_ERROR;
goto __exit;
}
rt_thread_mdelay(send_size * 0.0868 + 5);
cnt = read(serial_fd, (void *)uart_write_buffer, send_size + 1);
if (cnt != send_size)
{
LOG_E("uart read failed %d %d", cnt, send_size);
result = -RT_ERROR;
goto __exit;
}
}
__exit:
rt_thread_mdelay(5);
if (uart_write_buffer)
rt_free(uart_write_buffer);
close(serial_fd);
return result == RT_EOK ? RT_TRUE : RT_FALSE;
}
static void tc_uart_api(void)
{
uassert_true(uart_api() == RT_TRUE);
}
static rt_err_t utest_tc_init(void)
{
LOG_I("UART TEST: Please connect Tx and Rx directly for self testing.");
return RT_EOK;
}
static rt_err_t utest_tc_cleanup(void)
{
close(serial_fd);
return RT_EOK;
}
static void testcase(void)
{
UTEST_UNIT_RUN(tc_uart_api);
}
UTEST_TC_EXPORT(testcase, "components.drivers.serial.v2.uart_posix_nonblock", utest_tc_init, utest_tc_cleanup, 30);
#endif /* TC_UART_USING_TC */
|