1 /*
2 * File : device_test.c
3 * This file is part of RT-Thread RTOS
4 * COPYRIGHT (C) 2011, RT-Thread Development Team
5 *
6 * The license and distribution terms for this file may be
7 * found in the file LICENSE in this distribution or at
8 * http://openlab.rt-thread.com/license/LICENSE.
9 *
10 * Change Logs:
11 * Date Author Notes
12 * 2011-01-01 aozima the first version.
13 * 2012-02-11 aozima add multiple sector speed test.
14 * 2012-05-27 aozima use rt_deice API.
15 */
16
17 #include <rtthread.h>
18
19 /* calculate speed */
calculate_speed_print(rt_uint32_t speed)20 static void calculate_speed_print(rt_uint32_t speed)
21 {
22 rt_uint32_t k,m;
23
24 k = speed/1024UL;
25 if( k )
26 {
27 m = k/1024UL;
28 if( m )
29 {
30 rt_kprintf("%d.%dMbyte/s",m,k%1024UL*100/1024UL);
31 }
32 else
33 {
34 rt_kprintf("%d.%dKbyte/s",k,speed%1024UL*100/1024UL);
35 }
36 }
37 else
38 {
39 rt_kprintf("%dbyte/s",speed);
40 }
41 }
42
_block_device_test(rt_device_t device)43 static rt_err_t _block_device_test(rt_device_t device)
44 {
45 rt_err_t result;
46 struct rt_device_blk_geometry geometry;
47 rt_uint8_t * read_buffer = RT_NULL;
48 rt_uint8_t * write_buffer = RT_NULL;
49
50 rt_kprintf("\r\n");
51
52 if( (device->flag & RT_DEVICE_FLAG_RDWR) == RT_DEVICE_FLAG_RDWR )
53 {
54 // device can read and write.
55 // step 1: open device
56 result = rt_device_open(device,RT_DEVICE_FLAG_RDWR);
57 if( result != RT_EOK )
58 {
59 return result;
60 }
61
62 // step 2: get device info
63 rt_memset(&geometry, 0, sizeof(geometry));
64 result = rt_device_control(device,
65 RT_DEVICE_CTRL_BLK_GETGEOME,
66 &geometry);
67 if( result != RT_EOK )
68 {
69 rt_kprintf("device : %s cmd RT_DEVICE_CTRL_BLK_GETGEOME failed.\r\n");
70 return result;
71 }
72 rt_kprintf("device info:\r\n");
73 rt_kprintf("sector size : %d byte\r\n", geometry.bytes_per_sector);
74 rt_kprintf("sector count : %d \r\n", geometry.sector_count);
75 rt_kprintf("block size : %d byte\r\n", geometry.block_size);
76
77 rt_kprintf("\r\n");
78 read_buffer = rt_malloc(geometry.bytes_per_sector);
79 if( read_buffer == RT_NULL )
80 {
81 rt_kprintf("no memory for read_buffer!\r\n");
82 goto __return;
83 }
84 write_buffer = rt_malloc(geometry.bytes_per_sector);
85 if( write_buffer == RT_NULL )
86 {
87 rt_kprintf("no memory for write_buffer!\r\n");
88 goto __return;
89 }
90
91 /* step 3: R/W test */
92 {
93 rt_uint32_t i, err_count, sector_no;
94 rt_uint8_t * data_point;
95
96 i = rt_device_read(device, 0, read_buffer, 1);
97 if(i != 1)
98 {
99 rt_kprintf("read device :%s ", device->parent.name);
100 rt_kprintf("the first sector failed.\r\n");
101 goto __return;
102 }
103
104 data_point = write_buffer;
105 for(i=0; i<geometry.bytes_per_sector; i++)
106 {
107 *data_point++ = (rt_uint8_t)i;
108 }
109
110 /* write first sector */
111 sector_no = 0;
112 data_point = write_buffer;
113 *data_point++ = (rt_uint8_t)sector_no;
114 i = rt_device_write(device, sector_no, write_buffer,1);
115 if( i != 1 )
116 {
117 rt_kprintf("read the first sector success!\r\n");
118 rt_kprintf("but write device :%s ", device->parent.name);
119 rt_kprintf("the first sector failed.\r\n");
120 rt_kprintf("maybe readonly!\r\n");
121 goto __return;
122 }
123
124 /* write the second sector */
125 sector_no = 1;
126 data_point = write_buffer;
127 *data_point++ = (rt_uint8_t)sector_no;
128 i = rt_device_write(device,sector_no,write_buffer,1);
129 if( i != 1 )
130 {
131 rt_kprintf("write device :%s ",device->parent.name);
132 rt_kprintf("the second sector failed.\r\n");
133 goto __return;
134 }
135
136 /* write the end sector */
137 sector_no = geometry.sector_count-1;
138 data_point = write_buffer;
139 *data_point++ = (rt_uint8_t)sector_no;
140 i = rt_device_write(device,sector_no,write_buffer,1);
141 if( i != 1 )
142 {
143 rt_kprintf("write device :%s ",device->parent.name);
144 rt_kprintf("the end sector failed.\r\n");
145 goto __return;
146 }
147
148 /* verify first sector */
149 sector_no = 0;
150 i = rt_device_read(device,sector_no,read_buffer,1);
151 if( i != 1 )
152 {
153 rt_kprintf("read device :%s ",device->parent.name);
154 rt_kprintf("the first sector failed.\r\n");
155 goto __return;
156 }
157 err_count = 0;
158 data_point = read_buffer;
159 if( (*data_point++) != (rt_uint8_t)sector_no)
160 {
161 err_count++;
162 }
163 for(i=1; i<geometry.bytes_per_sector; i++)
164 {
165 if( (*data_point++) != (rt_uint8_t)i )
166 {
167 err_count++;
168 }
169 }
170 if( err_count > 0 )
171 {
172 rt_kprintf("verify device :%s ",device->parent.name);
173 rt_kprintf("the first sector failed.\r\n");
174 goto __return;
175 }
176
177 /* verify sector sector */
178 sector_no = 1;
179 i = rt_device_read(device,sector_no,read_buffer,1);
180 if( i != 1 )
181 {
182 rt_kprintf("read device :%s ",device->parent.name);
183 rt_kprintf("the second sector failed.\r\n");
184 goto __return;
185 }
186 err_count = 0;
187 data_point = read_buffer;
188 if( (*data_point++) != (rt_uint8_t)sector_no)
189 {
190 err_count++;
191 }
192 for(i=1; i<geometry.bytes_per_sector; i++)
193 {
194 if( (*data_point++) != (rt_uint8_t)i )
195 {
196 err_count++;
197 }
198 }
199 if( err_count > 0 )
200 {
201 rt_kprintf("verify device :%s ",device->parent.name);
202 rt_kprintf("the second sector failed.\r\n");
203 goto __return;
204 }
205
206 /* verify the end sector */
207 sector_no = geometry.sector_count-1;
208 i = rt_device_read(device,sector_no,read_buffer,1);
209 if( i != 1 )
210 {
211 rt_kprintf("read device :%s ",device->parent.name);
212 rt_kprintf("the end sector failed.\r\n");
213 goto __return;
214 }
215 err_count = 0;
216 data_point = read_buffer;
217 if( (*data_point++) != (rt_uint8_t)sector_no)
218 {
219 err_count++;
220 }
221 for(i=1; i<geometry.bytes_per_sector; i++)
222 {
223 if( (*data_point++) != (rt_uint8_t)i )
224 {
225 err_count++;
226 }
227 }
228 if( err_count > 0 )
229 {
230 rt_kprintf("verify device :%s ",device->parent.name);
231 rt_kprintf("the end sector failed.\r\n");
232 goto __return;
233 }
234 rt_kprintf("device R/W test pass!\r\n");
235
236 } /* step 3: I/O R/W test */
237
238 rt_kprintf("\r\nRT_TICK_PER_SECOND:%d\r\n", RT_TICK_PER_SECOND);
239
240 // step 4: continuous single sector speed test
241 {
242 rt_uint32_t tick_start,tick_end;
243 rt_uint32_t i;
244
245 rt_kprintf("\r\ncontinuous single sector speed test:\r\n");
246
247 if( geometry.sector_count < 10 )
248 {
249 rt_kprintf("device sector_count < 10, speed test abort!\r\n");
250 }
251 else
252 {
253 unsigned int sector;
254
255 // sign sector write
256 rt_kprintf("write: ");
257 sector = 0;
258 tick_start = rt_tick_get();
259 for(i=0; i<200; i++)
260 {
261 sector += rt_device_write(device, i, read_buffer, 1);
262 if((i != 0) && ((i%4) == 0) )
263 {
264 if(sector < 4)
265 {
266 rt_kprintf("#");
267 }
268 else
269 {
270 rt_kprintf("<");
271 }
272 sector = 0;
273 }
274 }
275 tick_end = rt_tick_get();
276 rt_kprintf("\r\nwrite 200 sector from %d to %d, ",tick_start,tick_end);
277 calculate_speed_print( (geometry.bytes_per_sector*200UL*RT_TICK_PER_SECOND)/(tick_end-tick_start) );
278 rt_kprintf("\r\n");
279
280 // sign sector read
281 rt_kprintf("read : ");
282 sector = 0;
283 tick_start = rt_tick_get();
284 for(i=0; i<200; i++)
285 {
286 sector += rt_device_read(device, i, read_buffer, 1);
287 if((i != 0) && ((i%4) == 0) )
288 {
289 if(sector < 4)
290 {
291 rt_kprintf("#");
292 }
293 else
294 {
295 rt_kprintf(">");
296 }
297 sector = 0;
298 }
299 }
300 tick_end = rt_tick_get();
301 rt_kprintf("\r\nread 200 sector from %d to %d, ",tick_start,tick_end);
302 calculate_speed_print( (geometry.bytes_per_sector*200UL*RT_TICK_PER_SECOND)/(tick_end-tick_start) );
303 rt_kprintf("\r\n");
304 }
305 }// step 4: speed test
306
307 // step 5: random single sector speed test
308 {
309 rt_uint32_t tick_start,tick_end;
310 rt_uint32_t i;
311
312 rt_kprintf("\r\nrandom single sector speed test:\r\n");
313
314 if( geometry.sector_count < 10 )
315 {
316 rt_kprintf("device sector_count < 10, speed test abort!\r\n");
317 }
318 else
319 {
320 unsigned int sector;
321
322 // sign sector write
323 rt_kprintf("write: ");
324 sector = 0;
325 tick_start = rt_tick_get();
326 for(i=0; i<200; i++)
327 {
328 sector += rt_device_write(device, (geometry.sector_count / 10) * (i%10) + (i%10), read_buffer, 1);
329 if((i != 0) && ((i%4) == 0) )
330 {
331 if(sector < 4)
332 {
333 rt_kprintf("#");
334 }
335 else
336 {
337 rt_kprintf("<");
338 }
339 sector = 0;
340 }
341 }
342 tick_end = rt_tick_get();
343 rt_kprintf("\r\nwrite 200 sector from %d to %d, ",tick_start,tick_end);
344 calculate_speed_print( (geometry.bytes_per_sector*200UL*RT_TICK_PER_SECOND)/(tick_end-tick_start) );
345 rt_kprintf("\r\n");
346
347 // sign sector read
348 rt_kprintf("read : ");
349 sector = 0;
350 tick_start = rt_tick_get();
351 for(i=0; i<200; i++)
352 {
353 sector += rt_device_read(device, (geometry.sector_count / 10) * (i%10) + (i%10), read_buffer, 1);
354 if((i != 0) && ((i%4) == 0) )
355 {
356 if(sector < 4)
357 {
358 rt_kprintf("#");
359 }
360 else
361 {
362 rt_kprintf(">");
363 }
364 sector = 0;
365 }
366 }
367 tick_end = rt_tick_get();
368 rt_kprintf("\r\nread 200 sector from %d to %d, ",tick_start,tick_end);
369 calculate_speed_print( (geometry.bytes_per_sector*200UL*RT_TICK_PER_SECOND)/(tick_end-tick_start) );
370 rt_kprintf("\r\n");
371 }
372 }// step 4: speed test
373
374 /* step 6: multiple sector speed test */
375 {
376 rt_uint8_t * multiple_buffer;
377 rt_uint8_t * ptr;
378 rt_uint32_t tick_start,tick_end;
379 rt_uint32_t sector,i;
380
381 rt_kprintf("\r\nmultiple sector speed test\r\n");
382
383 for(sector=2; sector<256; sector=sector*2)
384 {
385 multiple_buffer = rt_malloc(geometry.bytes_per_sector * sector);
386
387 if(multiple_buffer == RT_NULL)
388 {
389 rt_kprintf("no memory for %d sector! multiple sector speed test abort!\r\n", sector);
390 break;
391 }
392
393 rt_memset(multiple_buffer, sector, geometry.bytes_per_sector * sector);
394 rt_kprintf("write: ");
395 tick_start = rt_tick_get();
396 for(i=0; i<10; i++)
397 {
398 rt_size_t n;
399 n = rt_device_write(device, 50, multiple_buffer, sector);
400 if(n == sector)
401 {
402 rt_kprintf("<");
403 }
404 else
405 {
406 rt_kprintf("#");
407 }
408 }
409 tick_end = rt_tick_get();
410 rt_kprintf("\r\n");
411 rt_kprintf("multiple write %d sector speed : ", sector);
412 calculate_speed_print( (geometry.bytes_per_sector * sector * 10 * RT_TICK_PER_SECOND)/(tick_end-tick_start) );
413 rt_kprintf("\r\n");
414
415 rt_memset(multiple_buffer, ~sector, geometry.bytes_per_sector * sector);
416 rt_kprintf("read : ");
417 tick_start = rt_tick_get();
418 for(i=0; i<10; i++)
419 {
420 rt_size_t n;
421 n = rt_device_read(device, 50, multiple_buffer, sector);
422 if(n == sector)
423 {
424 rt_kprintf(">");
425 }
426 else
427 {
428 rt_kprintf("#");
429 }
430 }
431 tick_end = rt_tick_get();
432 rt_kprintf("\r\n");
433 rt_kprintf("multiple read %d sector speed : ", sector);
434 calculate_speed_print( (geometry.bytes_per_sector * sector * 10 * RT_TICK_PER_SECOND)/(tick_end-tick_start) );
435
436 ptr = multiple_buffer;
437 for(i=0; i<geometry.bytes_per_sector * sector; i++)
438 {
439 if(*ptr != sector)
440 {
441 rt_kprintf(" but data verify fail!");
442 break;
443 }
444 ptr++;
445 }
446 rt_kprintf("\r\n\r\n");
447
448 rt_free(multiple_buffer);
449 }
450 } /* step 5: multiple sector speed test */
451
452 rt_device_close(device);
453 return RT_EOK;
454 }// device can read and write.
455 else
456 {
457 // device read only
458 rt_device_close(device);
459 return RT_EOK;
460 }// device read only
461
462 __return:
463 if( read_buffer != RT_NULL )
464 {
465 rt_free(read_buffer);
466 }
467 if( write_buffer != RT_NULL )
468 {
469 rt_free(write_buffer);
470 }
471 rt_device_close(device);
472 return RT_ERROR;
473 }
474
device_test(const char * device_name)475 int device_test(const char * device_name)
476 {
477 rt_device_t device = RT_NULL;
478
479 // step 1:find device
480 device = rt_device_find(device_name);
481 if( device == RT_NULL)
482 {
483 rt_kprintf("device %s: not found!\r\n", device_name);
484 return RT_ERROR;
485 }
486
487 // step 2:init device
488 if (!(device->flag & RT_DEVICE_FLAG_ACTIVATED))
489 {
490 rt_err_t result;
491 result = rt_device_init(device);
492 if (result != RT_EOK)
493 {
494 rt_kprintf("To initialize device:%s failed. The error code is %d\r\n",
495 device->parent.name, result);
496 return result;
497 }
498 else
499 {
500 device->flag |= RT_DEVICE_FLAG_ACTIVATED;
501 }
502 }
503
504 // step 3: device test
505 switch( device->type )
506 {
507 case RT_Device_Class_Block :
508 rt_kprintf("block device!\r\n");
509 return _block_device_test(device);
510 default:
511 rt_kprintf("unkown device type : %02X",device->type);
512 return RT_ERROR;
513 }
514 }
515
516 #ifdef RT_USING_FINSH
517 #include <finsh.h>
518 FINSH_FUNCTION_EXPORT(device_test, e.g: device_test("sd0"));
519 #endif
520
521