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 * 2025-05-01 wumingzi first version
9 */
10
11 /* The file can test the rt-thread audio driver framework including following api via memory
12 * simulation.
13 *
14 * rt_audio_register
15 * rt_audio_rx_done
16 * rt_audio_tx_complete
17 *
18 * When audio devices generate or receive new data, the corresponding buffer in device will
19 * receive date from kernel or surroundings. The same phenomenon will also happen at the
20 * application level. Thus we can fill memory to simulate the generation of data then track
21 * and check memory to ensure kernel processing audio data correctly. And this depends on
22 * implementations of audio drivers.
23 *
24 * Therefore, if the player_test testcase failed, it could mean rt_audio_register or
25 * rt_audio_tx_complete existing bugs. Similarly, if mic_test testcase failed, it could mean
26 * rt_audio_register or rt_audio_rx_done existing bugs.
27 */
28
29 #include "tc_audio_common.h"
30
31 rt_uint8_t audio_fsm_step = 0;
32
33 /* Allocate and initialize memory filled by fill_byte */
alloc_filled_mem(rt_uint8_t fill_byte,rt_size_t size)34 static void *alloc_filled_mem(rt_uint8_t fill_byte, rt_size_t size)
35 {
36 void *ptr = rt_malloc(size);
37 if (ptr != NULL)
38 {
39 rt_memset(ptr, fill_byte, size);
40 }
41 return ptr;
42 }
43
44 /* Check if the memory is filled with fill_byte */
check_filled_mem(rt_uint8_t fill_byte,rt_uint8_t * mem,size_t size)45 static rt_err_t check_filled_mem(rt_uint8_t fill_byte, rt_uint8_t *mem, size_t size)
46 {
47 rt_uint8_t *p = mem;
48 for (size_t i = 0; i < size; ++i)
49 {
50 if (*(p+i) != fill_byte)
51 {
52 return -RT_ERROR;
53 }
54 }
55 return RT_EOK;
56 }
57
player_test(void)58 static void player_test(void)
59 {
60 int res = 0;
61 void* player_buffer = RT_NULL;
62 rt_device_t dev_obj;
63
64 dev_obj = rt_device_find(SOUND_PLAYER_DEVICE_NAME);
65 if (dev_obj == RT_NULL)
66 {
67 uassert_not_null(dev_obj);
68 goto __exit;
69 }
70 if (dev_obj->type != RT_Device_Class_Sound)
71 {
72 LOG_E("Not an audio player device\n");
73 goto __exit;
74 }
75
76 res = rt_device_open(dev_obj, RT_DEVICE_OFLAG_WRONLY);
77 if (res != RT_EOK)
78 {
79 LOG_E("Audio player device failed\n");
80 uassert_true(0);
81 goto __exit;
82 }
83
84 /* The sampling rate is set by the driver default, so there isn't configuration step */
85
86 struct rt_audio_device *audio_dev = rt_container_of(dev_obj, struct rt_audio_device, parent);
87 struct rt_audio_buf_info buf_info = audio_dev->replay->buf_info;
88 struct sound_device *snd_dev = rt_container_of(audio_dev, struct sound_device, audio);
89
90 player_buffer = alloc_filled_mem(0xAA, TX_DMA_BLOCK_SIZE);
91 if (player_buffer == RT_NULL)
92 {
93 rt_kprintf("Allocate test memory failed\n");
94 uassert_true(0);
95 goto __exit;
96 }
97
98 if(snd_dev->tx_fifo == RT_NULL)
99 {
100 rt_kprintf("snd_dev->tx_fifo == RT_NULL ");
101 uassert_true(0);
102 goto __exit;
103 }
104 res = rt_device_write(dev_obj, 0, player_buffer, TX_DMA_BLOCK_SIZE);
105 if (res != RT_EOK && res != TX_DMA_BLOCK_SIZE)
106 {
107 rt_kprintf("Failed to write data to the player device, res = %d\n",res);
108 uassert_true(0);
109 goto __exit;
110 }
111
112 audio_fsm_step = 1;
113 while (1)
114 {
115 if(audio_fsm_step == 2)
116 {
117 break;
118 }
119 rt_thread_mdelay(10);
120 }
121
122 res = check_filled_mem(0xAA, &buf_info.buffer[0], TX_DMA_BLOCK_SIZE);
123 if (res != RT_EOK)
124 {
125 rt_kprintf("The first memory check failed! Buffer dump\n");
126
127 for (rt_size_t i = 0; i < TX_DMA_FIFO_SIZE; i++)
128 {
129 rt_kprintf("%02X ", buf_info.buffer[i]);
130 if (i % 16 == 15) rt_kprintf("\n");
131 }
132 rt_kprintf("\n");
133 uassert_true(0);
134 goto __exit;
135 }
136
137 rt_free(player_buffer);
138 player_buffer = RT_NULL;
139
140 player_buffer = alloc_filled_mem(0x55, TX_DMA_BLOCK_SIZE);
141 if (player_buffer == RT_NULL)
142 {
143 rt_kprintf("Allocate test memory failed\n");
144 uassert_true(0);
145 goto __exit;
146 }
147
148 res = rt_device_write(dev_obj, TX_DMA_BLOCK_SIZE, player_buffer, TX_DMA_BLOCK_SIZE);
149 if (res != RT_EOK && res != TX_DMA_BLOCK_SIZE)
150 {
151 rt_kprintf("Failed to write data to the player device, res = %d\n",res);
152 uassert_true(0);
153 goto __exit;
154 }
155
156 audio_fsm_step = 2;
157 while (res != RT_EOK)
158 {
159 if(audio_fsm_step == 3)
160 {
161 break;
162 }
163
164 rt_thread_mdelay(10);
165 }
166
167 res = check_filled_mem(0x55,&buf_info.buffer[TX_DMA_BLOCK_SIZE], TX_DMA_BLOCK_SIZE);
168 if (res != RT_EOK)
169 {
170 rt_kprintf("The second memory check failed! Buffer dump\n");
171
172 for (rt_size_t i = 0; i < TX_DMA_FIFO_SIZE; i++)
173 {
174 rt_kprintf("%02X ", buf_info.buffer[i]);
175 if (i % 16 == 15) rt_kprintf("\n");
176 }
177 rt_kprintf("\n");
178 uassert_true(0);
179 goto __exit;
180 }
181
182 __exit:
183
184 if (player_buffer)
185 {
186 rt_free(player_buffer);
187 player_buffer = RT_NULL;
188 }
189
190 if (dev_obj != RT_NULL)
191 {
192 audio_fsm_step = 4;
193 rt_device_close(dev_obj);
194 }
195 }
196
mic_test(void)197 static void mic_test(void)
198 {
199 rt_device_t dev_obj;
200 rt_uint8_t *mic_buffer = RT_NULL;
201 rt_ssize_t res = 0;
202 rt_ssize_t length = 0;
203 mic_buffer = (rt_uint8_t *)rt_malloc(RX_DMA_BLOCK_SIZE);
204 if (mic_buffer == RT_NULL)
205 {
206 rt_kprintf("The mic_buffer memory allocate failed\n");
207 uassert_true(0);
208 goto __exit;
209 }
210
211
212 dev_obj = rt_device_find(SOUND_MIC_DEVICE_NAME);
213 if (dev_obj == RT_NULL)
214 {
215 LOG_E("Not a mic device\n");
216 uassert_true(0);
217 goto __exit;
218 }
219
220 res = rt_device_open(dev_obj, RT_DEVICE_OFLAG_RDONLY);
221 if (res != RT_EOK)
222 {
223 LOG_E("Audio player device failed\n");
224 uassert_true(0);
225 goto __exit;
226 }
227
228 length = rt_device_read(dev_obj, 0, mic_buffer,RX_DMA_BLOCK_SIZE);
229 if(length < 0)
230 {
231 LOG_E("Mic device read err\n");
232 }
233 if(audio_fsm_step == 1)
234 {
235 res = check_filled_mem(0xAA, (rt_uint8_t*)(mic_buffer), length);
236 }
237 if (res != RT_EOK)
238 {
239 LOG_E("The first memory check failed! Buffer dump\n");
240 for (rt_size_t i = 0; i < RX_DMA_FIFO_SIZE; i++)
241 {
242 rt_kprintf("%02X ",mic_buffer[i]);
243 if (i % 16 == 15) rt_kprintf("\n");
244 }
245 rt_kprintf("\n");
246 uassert_true(0);
247 goto __exit;
248 }
249 audio_fsm_step = 2;
250
251 while (1)
252 {
253 if(audio_fsm_step == 3)
254 {
255 length = rt_device_read(dev_obj, 0, mic_buffer, RX_DMA_FIFO_SIZE);
256 if(length < 0)
257 {
258 LOG_E("Mic device read err\n");
259 }
260 res = check_filled_mem(0x55, (rt_uint8_t*)(&mic_buffer[0]), length);
261
262 if(res != RT_EOK)
263 {
264 LOG_E("The second memory check failed! Buffer dump\n");
265 for (rt_size_t i = 0; i < RX_DMA_FIFO_SIZE; i++)
266 {
267 rt_kprintf("%02X ",mic_buffer[i]);
268 if (i % 16 == 15) rt_kprintf("\n");
269 }
270 rt_kprintf("\n");
271 uassert_true(0);
272 goto __exit;
273 }
274
275 break;
276 }
277 rt_thread_mdelay(100);
278 }
279
280 __exit:
281 if (mic_buffer)
282 {
283 rt_free(mic_buffer);
284 }
285
286 if (dev_obj != RT_NULL)
287 {
288 audio_fsm_step = 4;
289 rt_device_close(dev_obj);
290 }
291 }
292
testcase(void)293 static void testcase(void)
294 {
295 UTEST_UNIT_RUN(player_test);
296 UTEST_UNIT_RUN(mic_test);
297 }
298
utest_tc_init(void)299 static rt_err_t utest_tc_init(void)
300 {
301 return RT_EOK;
302 }
303
utest_tc_cleanup(void)304 static rt_err_t utest_tc_cleanup(void)
305 {
306 return RT_EOK;
307 }
308
309 UTEST_TC_EXPORT(testcase, "audio.tc_audio_main", utest_tc_init, utest_tc_cleanup, 10);