Improve demo debug info
[lwext4.git] / demos / stm32f429_disco / main.c
1 /*\r
2  * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)\r
3  * All rights reserved.\r
4  *\r
5  * Redistribution and use in source and binary forms, with or without\r
6  * modification, are permitted provided that the following conditions\r
7  * are met:\r
8  *\r
9  * - Redistributions of source code must retain the above copyright\r
10  *   notice, this list of conditions and the following disclaimer.\r
11  * - Redistributions in binary form must reproduce the above copyright\r
12  *   notice, this list of conditions and the following disclaimer in the\r
13  *   documentation and/or other materials provided with the distribution.\r
14  * - The name of the author may not be used to endorse or promote products\r
15  *   derived from this software without specific prior written permission.\r
16  *\r
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\r
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\r
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\r
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
27  */\r
28 \r
29 #include <config.h>\r
30 #include <hw_init.h>\r
31 \r
32 #include <stdio.h>\r
33 #include <stdlib.h>\r
34 #include <string.h>\r
35 #include <unistd.h>\r
36 #include <getopt.h>\r
37 #include <stdbool.h>\r
38 #include <time.h>\r
39 #include <unistd.h>\r
40 \r
41 #include <usb_msc_lwext4.h>\r
42 #include <ext4.h>\r
43 \r
44 /**@brief   Read-write size*/\r
45 #define READ_WRITE_SZIZE 1024 * 16\r
46 \r
47 /**@brief   Delay test (slower LCD scroll)*/\r
48 #define TEST_DELAY_MS    1000\r
49 \r
50 /**@brief   Input stream name.*/\r
51 char input_name[128] = "ext2";\r
52 \r
53 /**@brief   Read-write size*/\r
54 static int rw_szie  = READ_WRITE_SZIZE;\r
55 \r
56 /**@brief   Read-write size*/\r
57 static int rw_count = 100;\r
58 \r
59 /**@brief   Directory test count*/\r
60 static int dir_cnt  = 100;\r
61 \r
62 /**@brief   Static or dynamic cache mode*/\r
63 static bool cache_mode = false;\r
64 \r
65 /**@brief   Cleanup after test.*/\r
66 static bool cleanup_flag = false;\r
67 \r
68 /**@brief   Block device stats.*/\r
69 static bool bstat = false;\r
70 \r
71 /**@brief   Superblock stats.*/\r
72 static bool sbstat = false;\r
73 \r
74 /**@brief   File write buffer*/\r
75 static uint8_t wr_buff[READ_WRITE_SZIZE];\r
76 \r
77 /**@brief   File read buffer.*/\r
78 static uint8_t rd_buff[READ_WRITE_SZIZE];\r
79 \r
80 /**@brief   Block device handle.*/\r
81 static struct ext4_blockdev *bd;\r
82 \r
83 /**@brief   Block cache handle.*/\r
84 static struct ext4_bcache   *bc;\r
85 \r
86 static char* entry_to_str(uint8_t type)\r
87 {\r
88     switch(type){\r
89     case EXT4_DIRENTRY_UNKNOWN:\r
90         return "[UNK] ";\r
91     case EXT4_DIRENTRY_REG_FILE:\r
92         return "[FIL] ";\r
93     case EXT4_DIRENTRY_DIR:\r
94         return "[DIR] ";\r
95     case EXT4_DIRENTRY_CHRDEV:\r
96         return "[CHA] ";\r
97     case EXT4_DIRENTRY_BLKDEV:\r
98         return "[BLK] ";\r
99     case EXT4_DIRENTRY_FIFO:\r
100         return "[FIF] ";\r
101     case EXT4_DIRENTRY_SOCK:\r
102         return "[SOC] ";\r
103     case EXT4_DIRENTRY_SYMLINK:\r
104         return "[SYM] ";\r
105     default:\r
106         break;\r
107     }\r
108     return "[???]";\r
109 }\r
110 \r
111 static void dir_ls(const char *path)\r
112 {\r
113     int j = 0;\r
114     char sss[255];\r
115     ext4_dir d;\r
116     ext4_direntry *de;\r
117 \r
118     printf("ls %s\n", path);\r
119 \r
120     ext4_dir_open(&d, path);\r
121     de = ext4_dir_entry_get(&d, j++);\r
122 \r
123     while(de){\r
124         memcpy(sss, de->name, de->name_length);\r
125         sss[de->name_length] = 0;\r
126         printf("  %s", entry_to_str(de->inode_type));\r
127         printf("%s", sss);\r
128         printf("\n");\r
129         de = ext4_dir_entry_get(&d, j++);\r
130     }\r
131     ext4_dir_close(&d);\r
132 }\r
133 \r
134 static void mp_stats(void)\r
135 {\r
136     struct ext4_mount_stats stats;\r
137     ext4_mount_point_stats("/mp/", &stats);\r
138 \r
139     printf("********************\n");\r
140     printf("ext4_mount_point_stats\n");\r
141     printf("inodes_count = %u\n", stats.inodes_count);\r
142     printf("free_inodes_count = %u\n", stats.free_inodes_count);\r
143     printf("blocks_count = %u\n", (uint32_t)stats.blocks_count);\r
144     printf("free_blocks_count = %u\n", (uint32_t)stats.free_blocks_count);\r
145     printf("block_size = %u\n", stats.block_size);\r
146     printf("block_group_count = %u\n", stats.block_group_count);\r
147     printf("blocks_per_group= %u\n", stats.blocks_per_group);\r
148     printf("inodes_per_group = %u\n", stats.inodes_per_group);\r
149     printf("volume_name = %s\n", stats.volume_name);\r
150 \r
151     printf("********************\n");\r
152 \r
153 }\r
154 \r
155 static void block_stats(void)\r
156 {\r
157     uint32_t i;\r
158 \r
159     printf("********************\n");\r
160     printf("ext4 blockdev stats\n");\r
161     printf("bdev->bread_ctr = %u\n", bd->bread_ctr);\r
162     printf("bdev->bwrite_ctr = %u\n", bd->bwrite_ctr);\r
163 \r
164 \r
165     printf("bcache->ref_blocks = %u\n", bc->ref_blocks);\r
166     printf("bcache->max_ref_blocks = %u\n", bc->max_ref_blocks);\r
167     printf("bcache->lru_ctr = %u\n", bc->lru_ctr);\r
168 \r
169     printf("\n");\r
170     for (i = 0; i < bc->cnt; ++i) {\r
171         printf("bcache->refctr[%d]= %u\n", i, bc->refctr[i]);\r
172     }\r
173 \r
174     printf("\n");\r
175     for (i = 0; i < bc->cnt; ++i) {\r
176         printf("bcache->lru_id[%d] = %u\n", i, bc->lru_id[i]);\r
177     }\r
178 \r
179     printf("\n");\r
180     for (i = 0; i < bc->cnt; ++i) {\r
181         printf("bcache->free_delay[%d] = %d\n", i, bc->free_delay[i]);\r
182     }\r
183 \r
184     printf("\n");\r
185     for (i = 0; i < bc->cnt; ++i) {\r
186         printf("bcache->lba[%d] = %u\n", i, (uint32_t)bc->lba[i]);\r
187     }\r
188 \r
189     printf("********************\n");\r
190 }\r
191 \r
192 static clock_t get_ms(void)\r
193 {\r
194     return hw_get_ms();\r
195 }\r
196 \r
197 static void printf_io_timings(clock_t diff)\r
198 {\r
199     const struct ext4_io_stats *stats = ext4_io_timings_get(diff);\r
200     printf("io_timings:\n");\r
201     printf("  io_read: %.3f%%\n", stats->io_read);\r
202     printf("  io_write: %.3f%%\n", stats->io_write);\r
203     printf("  io_cpu: %.3f%%\n", stats->cpu);\r
204 }\r
205 \r
206 static bool dir_test(int len)\r
207 {\r
208     ext4_file f;\r
209     int       r;\r
210     int       i;\r
211     char path[64];\r
212     clock_t diff;\r
213     clock_t stop;\r
214     clock_t start;\r
215 \r
216     printf("\ndir_test: %d\n", len);\r
217     ext4_io_timings_clear();\r
218     start = get_ms();\r
219 \r
220     printf("directory create: /mp/dir1\n");\r
221     r = ext4_dir_mk("/mp/dir1");\r
222     if(r != EOK){\r
223         printf("ext4_dir_mk: rc = %d\n", r);\r
224         return false;\r
225     }\r
226 \r
227     printf("add files to: /mp/dir1\n");\r
228     for (i = 0; i < len; ++i) {\r
229         sprintf(path, "/mp/dir1/f%d", i);\r
230         r = ext4_fopen(&f, path, "wb");\r
231         if(r != EOK){\r
232             printf("ext4_fopen: rc = %d\n", r);\r
233             return false;\r
234         }\r
235     }\r
236 \r
237     stop =  get_ms();\r
238     diff = stop - start;\r
239     dir_ls("/mp/dir1");\r
240     printf("dir_test: time: %d ms\n", (int)diff);\r
241     printf_io_timings(diff);\r
242     return true;\r
243 }\r
244 \r
245 \r
246 static bool file_test(void)\r
247 {\r
248     int r;\r
249     uint32_t  size;\r
250     ext4_file f;\r
251     int i;\r
252     clock_t start;\r
253     clock_t stop;\r
254     clock_t diff;\r
255     uint32_t kbps;\r
256     uint64_t size_bytes;\r
257 \r
258     printf("\nfile_test:\n");\r
259 \r
260     /*Add hello world file.*/\r
261     r = ext4_fopen(&f, "/mp/hello.txt", "wb");\r
262     r = ext4_fwrite(&f, "Hello World !\n", strlen("Hello World !\n"), 0);\r
263     r = ext4_fclose(&f);\r
264 \r
265 \r
266     printf("ext4_fopen: test1\n");\r
267     ext4_io_timings_clear();\r
268     start = get_ms();\r
269     r = ext4_fopen(&f, "/mp/test1", "wb");\r
270     if(r != EOK){\r
271         printf("ext4_fopen ERROR = %d\n", r);\r
272         return false;\r
273     }\r
274 \r
275     printf("ext4_write: %d * %d ...\n" , rw_szie, rw_count);\r
276     for (i = 0; i < rw_count; ++i) {\r
277 \r
278         memset(wr_buff, i % 10 + '0', rw_szie);\r
279 \r
280         r = ext4_fwrite(&f, wr_buff, rw_szie, &size);\r
281 \r
282         if((r != EOK) || (size != rw_szie))\r
283             break;\r
284     }\r
285 \r
286     if(i != rw_count){\r
287         printf("  file_test: rw_count = %d\n", i);\r
288         return false;\r
289     }\r
290 \r
291     stop = get_ms();\r
292     diff = stop - start;\r
293     size_bytes = rw_szie * rw_count;\r
294     size_bytes = (size_bytes * 1000) / 1024;\r
295     kbps = (size_bytes) / (diff + 1);\r
296     printf("  write time: %d ms\n", (int)diff);\r
297     printf("  write speed: %d KB/s\n", kbps);\r
298     printf_io_timings(diff);\r
299     r = ext4_fclose(&f);\r
300 \r
301 \r
302     printf("ext4_fopen: test1\n");\r
303     ext4_io_timings_clear();\r
304     start = get_ms();\r
305     r = ext4_fopen(&f, "/mp/test1", "r+");\r
306     if(r != EOK){\r
307         printf("ext4_fopen ERROR = %d\n", r);\r
308         return false;\r
309     }\r
310 \r
311     printf("ext4_read: %d * %d ...\n" , rw_szie, rw_count);\r
312 \r
313     for (i = 0; i < rw_count; ++i) {\r
314         memset(wr_buff, i % 10 + '0', rw_szie);\r
315         r = ext4_fread(&f, rd_buff, rw_szie, &size);\r
316 \r
317         if((r != EOK) || (size != rw_szie))\r
318             break;\r
319 \r
320         if(memcmp(rd_buff, wr_buff, rw_szie))\r
321             break;\r
322     }\r
323 \r
324     if(i != rw_count){\r
325         printf("  file_test: rw_count = %d\n", i);\r
326         return false;\r
327     }\r
328 \r
329     stop = get_ms();\r
330     diff = stop - start;\r
331     size_bytes = rw_szie * rw_count;\r
332     size_bytes = (size_bytes * 1000) / 1024;\r
333     kbps = (size_bytes) / (diff + 1);\r
334     printf("  read time: %d ms\n", (int)diff);\r
335     printf("  read speed: %d KB/s\n", kbps);\r
336     printf_io_timings(diff);\r
337 \r
338     r = ext4_fclose(&f);\r
339     return true;\r
340 \r
341 }\r
342 static void cleanup(void)\r
343 {\r
344     clock_t start;\r
345     clock_t stop;\r
346     clock_t diff;\r
347 \r
348     printf("\ncleanup:\n");\r
349     ext4_fremove("/mp/hello.txt");\r
350 \r
351     printf("remove /mp/test1\n");\r
352     ext4_fremove("/mp/test1");\r
353 \r
354 \r
355     printf("remove /mp/dir1\n");\r
356     ext4_io_timings_clear();\r
357     start = get_ms();\r
358     ext4_dir_rm("/mp/dir1");\r
359     stop = get_ms();\r
360     diff = stop - start;\r
361     printf("cleanup: time: %d ms\n", (int)diff);\r
362     printf_io_timings(diff);\r
363 }\r
364 \r
365 static bool open_filedev(void)\r
366 {\r
367 \r
368     bd = ext4_usb_msc_get();\r
369     bc = ext4_usb_msc_cache_get();\r
370     if(!bd || !bc){\r
371         printf("open_filedev: fail\n");\r
372         return false;\r
373     }\r
374     return true;\r
375 }\r
376 \r
377 static bool mount(void)\r
378 {\r
379     int r;\r
380 \r
381     if(!open_filedev())\r
382         return false;\r
383 \r
384     ext4_dmask_set(EXT4_DEBUG_ALL);\r
385 \r
386     r = ext4_device_register(bd, cache_mode ? 0 : bc, "ext4_fs");\r
387     if(r != EOK){\r
388         printf("ext4_device_register: rc = %d\n", r);\r
389         return false;\r
390     }\r
391 \r
392     r = ext4_mount("ext4_fs", "/mp/");\r
393     if(r != EOK){\r
394         printf("ext4_mount: rc = %d\n", r);\r
395         return false;\r
396     }\r
397 \r
398     return true;\r
399 }\r
400 \r
401 static bool umount(void)\r
402 {\r
403     int r = ext4_umount("/mp/");\r
404     if(r != EOK){\r
405         printf("ext4_umount: fail %d", r);\r
406         return false;\r
407     }\r
408     return true;\r
409 }\r
410 \r
411 \r
412 int main(void)\r
413 {\r
414     hw_init();\r
415 \r
416     setbuf(stdout, 0);\r
417     printf("connect usb drive...\n");\r
418 \r
419     while(!hw_usb_connected())\r
420         hw_usb_process();\r
421     printf("usb drive connected\n");\r
422 \r
423     while(!hw_usb_enum_done())\r
424         hw_usb_process();\r
425     printf("usb drive enum done\n");\r
426 \r
427     hw_led_red(1);\r
428 \r
429     printf("test conditions:\n");\r
430     printf("  rw size: %d\n",  rw_szie);\r
431     printf("  rw count: %d\n", rw_count);\r
432     printf("  cache mode: %s\n", cache_mode ? "dynamic" : "static");\r
433 \r
434 \r
435     hw_wait_ms(TEST_DELAY_MS);\r
436     if(!mount())\r
437         return EXIT_FAILURE;\r
438 \r
439     hw_wait_ms(TEST_DELAY_MS);\r
440 \r
441     ext4_cache_write_back("/mp/", 1);\r
442     cleanup();\r
443 \r
444     if(sbstat){\r
445         hw_wait_ms(TEST_DELAY_MS);\r
446         mp_stats();\r
447     }\r
448 \r
449     hw_wait_ms(TEST_DELAY_MS);\r
450     dir_ls("/mp/");\r
451     if(!dir_test(dir_cnt))\r
452         return EXIT_FAILURE;\r
453 \r
454     hw_wait_ms(TEST_DELAY_MS);\r
455     if(!file_test())\r
456         return EXIT_FAILURE;\r
457 \r
458     dir_ls("/mp/");\r
459 \r
460     if(sbstat){\r
461         hw_wait_ms(TEST_DELAY_MS);\r
462         mp_stats();\r
463     }\r
464 \r
465     if(cleanup_flag){\r
466         hw_wait_ms(TEST_DELAY_MS);\r
467         cleanup();\r
468     }\r
469 \r
470     if(bstat){\r
471         hw_wait_ms(TEST_DELAY_MS);\r
472         block_stats();\r
473     }\r
474 \r
475     ext4_cache_write_back("/mp/", 0);\r
476     if(!umount())\r
477         return EXIT_FAILURE;\r
478 \r
479     printf("\npress RESET button to restart\n");\r
480 \r
481     while (1) {\r
482         hw_wait_ms(500);\r
483         hw_led_green(1);\r
484         hw_wait_ms(500);\r
485         hw_led_green(0);\r
486 \r
487     }\r
488 }\r
489 \r