1 /*
2  * Copyright (c) 2006-2024 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  */
10 
11 #include <rtthread.h>
12 #include "utest.h"
13 #include <rtdevice.h>
14 #include <stdlib.h>
15 
16 
17 #ifdef UTEST_SERIAL_TC
18 
19 static struct rt_serial_device *serial;
20 static rt_sem_t                 rx_sem;
21 static rt_uint8_t               uart_over_flag;
22 static rt_bool_t                uart_result = RT_TRUE;
23 
uart_find(void)24 static rt_err_t uart_find(void)
25 {
26     serial = (struct rt_serial_device *)rt_device_find(RT_SERIAL_TC_DEVICE_NAME);
27 
28     if (serial == RT_NULL)
29     {
30         LOG_E("find %s device failed!\n", RT_SERIAL_TC_DEVICE_NAME);
31         return -RT_ERROR;
32     }
33 
34     return RT_EOK;
35 }
36 
uart_rx_indicate(rt_device_t device,rt_size_t size)37 static rt_err_t uart_rx_indicate(rt_device_t device, rt_size_t size)
38 {
39     rt_sem_release(rx_sem);
40 
41     return RT_EOK;
42 }
43 
uart_send_entry(void * parameter)44 static void uart_send_entry(void *parameter)
45 {
46     rt_uint8_t *uart_write_buffer;
47     rt_uint16_t send_len;
48 
49     rt_uint32_t i = 0;
50     send_len      = *(rt_uint16_t *)parameter;
51 
52     /* assign send buffer */
53     uart_write_buffer = (rt_uint8_t *)rt_malloc(send_len);
54     if (uart_write_buffer == RT_NULL)
55     {
56         LOG_E("Without spare memory for uart dma!");
57         uart_result = RT_FALSE;
58         return;
59     }
60 
61     rt_memset(uart_write_buffer, 0, send_len);
62 
63     for (i = 0; i < send_len; i++)
64     {
65         uart_write_buffer[i] = (rt_uint8_t)i;
66     }
67 
68     /* send buffer */
69     if (rt_device_write(&serial->parent, 0, uart_write_buffer, send_len) != send_len)
70     {
71         LOG_E("device write failed\r\n");
72     }
73     rt_free(uart_write_buffer);
74 }
75 
uart_rec_entry(void * parameter)76 static void uart_rec_entry(void *parameter)
77 {
78     rt_uint16_t rev_len;
79 
80     rev_len = *(rt_uint16_t *)parameter;
81     rt_uint8_t *uart_write_buffer;
82     uart_write_buffer = (rt_uint8_t *)rt_calloc(1, rev_len + 1);
83     rt_int32_t  cnt, i;
84     rt_uint8_t  last_old_data;
85     rt_bool_t   fisrt_flag         = RT_TRUE;
86     rt_uint32_t all_receive_length = 0;
87 
88     while (1)
89     {
90         rt_err_t result;
91 
92         result = rt_sem_take(rx_sem, RT_WAITING_FOREVER);
93         if (result != RT_EOK)
94         {
95             LOG_E("take sem err in recv.");
96         }
97 
98         cnt = rt_device_read(&serial->parent, 0, (void *)uart_write_buffer, rev_len);
99         if (cnt == 0)
100         {
101             continue;
102         }
103 
104         if (fisrt_flag != RT_TRUE)
105         {
106             if ((rt_uint8_t)(last_old_data + 1) != uart_write_buffer[0])
107             {
108                 LOG_E("_Read Different data -> former data: %x, current data: %x.", last_old_data, uart_write_buffer[0]);
109                 uart_result = RT_FALSE;
110                 rt_free(uart_write_buffer);
111                 return;
112             }
113         }
114         else
115         {
116             fisrt_flag = RT_FALSE;
117         }
118 
119         for (i = 0; i < cnt - 1; i++)
120         {
121             if ((rt_uint8_t)(uart_write_buffer[i] + 1) != uart_write_buffer[i + 1])
122             {
123                 LOG_E("Read Different data -> former data: %x, current data: %x.", uart_write_buffer[i], uart_write_buffer[i + 1]);
124 
125                 uart_result = RT_FALSE;
126                 rt_free(uart_write_buffer);
127                 return;
128             }
129         }
130         all_receive_length += cnt;
131         if (all_receive_length >= rev_len)
132             break;
133         else
134             last_old_data = uart_write_buffer[cnt - 1];
135     }
136     rt_free(uart_write_buffer);
137     uart_over_flag = RT_TRUE;
138 }
139 
uart_api(rt_uint16_t test_buf)140 static rt_err_t uart_api(rt_uint16_t test_buf)
141 {
142     rt_thread_t thread_send = RT_NULL;
143     rt_thread_t thread_recv = RT_NULL;
144     rt_err_t    result      = RT_EOK;
145 
146     result = uart_find();
147     if (result != RT_EOK)
148     {
149         return -RT_ERROR;
150     }
151 
152     rx_sem = rt_sem_create("rx_sem", 0, RT_IPC_FLAG_PRIO);
153     if (rx_sem == RT_NULL)
154     {
155         LOG_E("Init sem failed.");
156         uart_result = RT_FALSE;
157         return -RT_ERROR;
158     }
159 
160     /* reinitialize */
161     struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
162     config.baud_rate               = BAUD_RATE_115200;
163     config.rx_bufsz                = RT_SERIAL_TC_RXBUF_SIZE;
164     config.tx_bufsz                = RT_SERIAL_TC_TXBUF_SIZE;
165 
166 #ifdef RT_SERIAL_USING_DMA
167     config.dma_ping_bufsz = RT_SERIAL_TC_RXBUF_SIZE / 2;
168 #endif
169     rt_device_control(&serial->parent, RT_DEVICE_CTRL_CONFIG, &config);
170 
171     result = rt_device_open(&serial->parent, RT_DEVICE_FLAG_RX_NON_BLOCKING | RT_DEVICE_FLAG_TX_BLOCKING);
172     if (result != RT_EOK)
173     {
174         LOG_E("Open uart device failed.");
175         uart_result = RT_FALSE;
176         rt_sem_delete(rx_sem);
177         return -RT_ERROR;
178     }
179 
180     rt_int32_t timeout = 5000;
181     rt_device_control(&serial->parent, RT_SERIAL_CTRL_SET_RX_TIMEOUT, (void *)&timeout);
182 
183     /* set receive callback function */
184     result = rt_device_set_rx_indicate(&serial->parent, uart_rx_indicate);
185     if (result != RT_EOK)
186     {
187         goto __exit;
188     }
189 
190     thread_recv = rt_thread_create("uart_recv", uart_rec_entry, &test_buf, 1024, RT_THREAD_PRIORITY_MAX - 5, 10);
191     thread_send = rt_thread_create("uart_send", uart_send_entry, &test_buf, 1024, RT_THREAD_PRIORITY_MAX - 4, 10);
192 
193     if (thread_send != RT_NULL && thread_recv != RT_NULL)
194     {
195         rt_thread_startup(thread_recv);
196         rt_thread_startup(thread_send);
197     }
198     else
199     {
200         result = -RT_ERROR;
201         goto __exit;
202     }
203 
204     while (1)
205     {
206         if (uart_result != RT_TRUE)
207         {
208             LOG_E("The test for uart dma is failure.");
209             result = -RT_ERROR;
210             goto __exit;
211         }
212         if (uart_over_flag == RT_TRUE)
213         {
214             goto __exit;
215         }
216         /* waiting for test over */
217         rt_thread_mdelay(5);
218     }
219 __exit:
220     if (rx_sem)
221         rt_sem_delete(rx_sem);
222     rt_device_close(&serial->parent);
223     rt_thread_mdelay(5);
224     uart_over_flag = RT_FALSE;
225     return result;
226 }
227 
tc_uart_api(void)228 static void tc_uart_api(void)
229 {
230     rt_uint32_t count = 0;
231     rt_uint16_t num   = 0;
232     rt_uint32_t i     = 0;
233     for (i = 1; i < 10; i++)
234     {
235         if (uart_api(RT_SERIAL_TC_TXBUF_SIZE * i + i % 2) == RT_EOK)
236             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);
237         else
238         {
239             LOG_E("uart test error");
240             goto __exit;
241         }
242     }
243 
244     for (i = 1; i < 10; i++)
245     {
246         if (uart_api(RT_SERIAL_TC_RXBUF_SIZE * i + i % 2) == RT_EOK)
247             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);
248         else
249         {
250             LOG_E("uart test error");
251             goto __exit;
252         }
253     }
254 
255     srand(rt_tick_get());
256     while (RT_SERIAL_TC_SEND_ITERATIONS - count)
257     {
258         num = (rand() % 1000) + 1;
259         if (uart_api(num) == RT_EOK)
260             LOG_I("data_lens [%4d], it is correct to read and write data. [%d] count testing.", num, ++count);
261         else
262         {
263             LOG_E("uart test error");
264             break;
265         }
266     }
267 
268 __exit:
269     uassert_true(uart_result == RT_TRUE);
270 }
271 
utest_tc_init(void)272 static rt_err_t utest_tc_init(void)
273 {
274     LOG_I("UART TEST: Please connect Tx and Rx directly for self testing.");
275     return RT_EOK;
276 }
277 
utest_tc_cleanup(void)278 static rt_err_t utest_tc_cleanup(void)
279 {
280     rx_sem               = RT_NULL;
281     uart_result          = RT_TRUE;
282     uart_over_flag       = RT_FALSE;
283     rt_device_t uart_dev = rt_device_find(RT_SERIAL_TC_DEVICE_NAME);
284     while (rt_device_close(uart_dev) != -RT_ERROR);
285     return RT_EOK;
286 }
287 
testcase(void)288 static void testcase(void)
289 {
290     UTEST_UNIT_RUN(tc_uart_api);
291 }
292 
293 UTEST_TC_EXPORT(testcase, "testcases.drivers.uart_rxnb_txb", utest_tc_init, utest_tc_cleanup, 30);
294 
295 #endif /* TC_UART_USING_TC */
296