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);