d2f1b0752e80098d15ccab82548df277a65e93e3
[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   Input stream name.*/\r
45 char input_name[128] = "ext2";\r
46 \r
47 /**@brief   Read-write size*/\r
48 #define READ_WRITE_SZIZE 1024 * 8\r
49 \r
50 /**@brief   Read-write size*/\r
51 static int rw_szie  = READ_WRITE_SZIZE;\r
52 \r
53 /**@brief   Read-write size*/\r
54 static int rw_count = 1000;\r
55 \r
56 /**@brief   Directory test count*/\r
57 static int dir_cnt  = 10;\r
58 \r
59 /**@brief   Static or dynamic cache mode*/\r
60 static bool cache_mode = false;\r
61 \r
62 /**@brief   Cleanup after test.*/\r
63 static bool cleanup_flag = false;\r
64 \r
65 /**@brief   Block device stats.*/\r
66 static bool bstat = false;\r
67 \r
68 /**@brief   Superblock stats.*/\r
69 static bool sbstat = false;\r
70 \r
71 /**@brief   File write buffer*/\r
72 static uint8_t wr_buff[READ_WRITE_SZIZE];\r
73 \r
74 /**@brief   File read buffer.*/\r
75 static uint8_t rd_buff[READ_WRITE_SZIZE];\r
76 \r
77 /**@brief   Block device handle.*/\r
78 static struct ext4_blockdev *bd;\r
79 \r
80 /**@brief   Block cache handle.*/\r
81 static struct ext4_bcache   *bc;\r
82 \r
83 static char* entry_to_str(uint8_t type)\r
84 {\r
85     switch(type){\r
86     case EXT4_DIRENTRY_UNKNOWN:\r
87         return "[UNK] ";\r
88     case EXT4_DIRENTRY_REG_FILE:\r
89         return "[FIL] ";\r
90     case EXT4_DIRENTRY_DIR:\r
91         return "[DIR] ";\r
92     case EXT4_DIRENTRY_CHRDEV:\r
93         return "[CHA] ";\r
94     case EXT4_DIRENTRY_BLKDEV:\r
95         return "[BLK] ";\r
96     case EXT4_DIRENTRY_FIFO:\r
97         return "[FIF] ";\r
98     case EXT4_DIRENTRY_SOCK:\r
99         return "[SOC] ";\r
100     case EXT4_DIRENTRY_SYMLINK:\r
101         return "[SYM] ";\r
102     default:\r
103         break;\r
104     }\r
105     return "[???]";\r
106 }\r
107 \r
108 static void dir_ls(const char *path)\r
109 {\r
110     int j = 0;\r
111     char sss[255];\r
112     ext4_dir d;\r
113     ext4_direntry *de;\r
114 \r
115     printf("********************\n");\r
116 \r
117     ext4_dir_open(&d, path);\r
118     de = ext4_dir_entry_get(&d, j++);\r
119     printf("ls %s\n", path);\r
120 \r
121     while(de){\r
122         memcpy(sss, de->name, de->name_length);\r
123         sss[de->name_length] = 0;\r
124         printf("%s", entry_to_str(de->inode_type));\r
125         printf("%s", sss);\r
126         printf("\n");\r
127         de = ext4_dir_entry_get(&d, j++);\r
128     }\r
129     printf("********************\n");\r
130     ext4_dir_close(&d);\r
131 }\r
132 \r
133 static void mp_stats(void)\r
134 {\r
135     struct ext4_mount_stats stats;\r
136     ext4_mount_point_stats("/mp/", &stats);\r
137 \r
138     printf("********************\n");\r
139     printf("ext4_mount_point_stats\n");\r
140     printf("inodes_count = %u\n", stats.inodes_count);\r
141     printf("free_inodes_count = %u\n", stats.free_inodes_count);\r
142     printf("blocks_count = %u\n", (uint32_t)stats.blocks_count);\r
143     printf("free_blocks_count = %u\n", (uint32_t)stats.free_blocks_count);\r
144     printf("block_size = %u\n", stats.block_size);\r
145     printf("block_group_count = %u\n", stats.block_group_count);\r
146     printf("blocks_per_group= %u\n", stats.blocks_per_group);\r
147     printf("inodes_per_group = %u\n", stats.inodes_per_group);\r
148     printf("volume_name = %s\n", stats.volume_name);\r
149 \r
150     printf("********************\n");\r
151 \r
152 }\r
153 \r
154 static void block_stats(void)\r
155 {\r
156     uint32_t i;\r
157 \r
158     printf("********************\n");\r
159     printf("ext4 blockdev stats\n");\r
160     printf("bdev->bread_ctr = %u\n", bd->bread_ctr);\r
161     printf("bdev->bwrite_ctr = %u\n", bd->bwrite_ctr);\r
162 \r
163 \r
164     printf("bcache->ref_blocks = %u\n", bc->ref_blocks);\r
165     printf("bcache->max_ref_blocks = %u\n", bc->max_ref_blocks);\r
166     printf("bcache->lru_ctr = %u\n", bc->lru_ctr);\r
167 \r
168     printf("\n");\r
169     for (i = 0; i < bc->cnt; ++i) {\r
170         printf("bcache->refctr[%d]= %u\n", i, bc->refctr[i]);\r
171     }\r
172 \r
173     printf("\n");\r
174     for (i = 0; i < bc->cnt; ++i) {\r
175         printf("bcache->lru_id[%d] = %u\n", i, bc->lru_id[i]);\r
176     }\r
177 \r
178     printf("\n");\r
179     for (i = 0; i < bc->cnt; ++i) {\r
180         printf("bcache->free_delay[%d] = %d\n", i, bc->free_delay[i]);\r
181     }\r
182 \r
183     printf("\n");\r
184     for (i = 0; i < bc->cnt; ++i) {\r
185         printf("bcache->lba[%d] = %u\n", i, (uint32_t)bc->lba[i]);\r
186     }\r
187 \r
188     printf("********************\n");\r
189 }\r
190 \r
191 static clock_t get_ms(void)\r
192 {\r
193     return hw_get_ms();\r
194 }\r
195 \r
196 static bool dir_test(int len)\r
197 {\r
198     ext4_file f;\r
199     int       r;\r
200     int       i;\r
201     char path[64];\r
202     clock_t diff;\r
203     clock_t stop;\r
204     clock_t start;\r
205     start = get_ms();\r
206 \r
207     printf("Directory create: /mp/dir1\n");\r
208     r = ext4_dir_mk("/mp/dir1");\r
209     if(r != EOK){\r
210         printf("Unable to create directory: /mp/dir1\n");\r
211         return false;\r
212     }\r
213 \r
214 \r
215     printf("Add files to: /mp/dir1\n");\r
216     for (i = 0; i < len; ++i) {\r
217         sprintf(path, "/mp/dir1/f%d", i);\r
218         r = ext4_fopen(&f, path, "wb");\r
219         if(r != EOK){\r
220             printf("Unable to create file in directory: /mp/dir1\n");\r
221             return false;\r
222         }\r
223     }\r
224 \r
225     stop =  get_ms();\r
226     diff = stop - start;\r
227     dir_ls("/mp/dir1");\r
228     printf("dir_test time: %d ms\n", (int)diff);\r
229     return true;\r
230 }\r
231 \r
232 \r
233 static bool file_test(void)\r
234 {\r
235     int r;\r
236     uint32_t  size;\r
237     ext4_file f;\r
238     int i;\r
239     clock_t start;\r
240     clock_t stop;\r
241     clock_t diff;\r
242     uint32_t kbps;\r
243     uint64_t size_bytes;\r
244     /*Add hello world file.*/\r
245     r = ext4_fopen(&f, "/mp/hello.txt", "wb");\r
246     r = ext4_fwrite(&f, "Hello World !\n", strlen("Hello World !\n"), 0);\r
247     r = ext4_fclose(&f);\r
248 \r
249 \r
250     printf("ext4_fopen: test1\n");\r
251 \r
252     start = get_ms();\r
253     r = ext4_fopen(&f, "/mp/test1", "wb");\r
254     if(r != EOK){\r
255         printf("ext4_fopen ERROR = %d\n", r);\r
256         return false;\r
257     }\r
258 \r
259     printf("ext4_write: %d * %d ...\n" , rw_szie, rw_count);\r
260     for (i = 0; i < rw_count; ++i) {\r
261 \r
262         memset(wr_buff, i % 10 + '0', rw_szie);\r
263 \r
264         r = ext4_fwrite(&f, wr_buff, rw_szie, &size);\r
265 \r
266         if((r != EOK) || (size != rw_szie))\r
267             break;\r
268 \r
269         if(!(i % (rw_count >> 3))){\r
270             printf("*");\r
271             fflush(stdout);\r
272         }\r
273     }\r
274 \r
275     if(i != rw_count){\r
276         printf("ERROR: rw_count = %d\n", i);\r
277         return false;\r
278     }\r
279 \r
280     printf(" OK\n");\r
281     stop = get_ms();\r
282     diff = stop - start;\r
283     size_bytes = rw_szie * rw_count;\r
284     size_bytes = (size_bytes * 1000) / 1024;\r
285     kbps = (size_bytes) / (diff + 1);\r
286     printf("file_test write time: %d ms\n", (int)diff);\r
287     printf("file_test write speed: %d KB/s\n", (int)kbps);\r
288     r = ext4_fclose(&f);\r
289     printf("ext4_fopen: test1\n");\r
290 \r
291 \r
292     start = get_ms();\r
293     r = ext4_fopen(&f, "/mp/test1", "r+");\r
294     if(r != EOK){\r
295         printf("ext4_fopen ERROR = %d\n", r);\r
296         return false;\r
297     }\r
298 \r
299     printf("ext4_read: %d * %d ...\n" , rw_szie, rw_count);\r
300 \r
301     for (i = 0; i < rw_count; ++i) {\r
302         memset(wr_buff, i % 10 + '0', rw_szie);\r
303         r = ext4_fread(&f, rd_buff, rw_szie, &size);\r
304 \r
305         if((r != EOK) || (size != rw_szie))\r
306             break;\r
307 \r
308         if(memcmp(rd_buff, wr_buff, rw_szie))\r
309             break;\r
310 \r
311 \r
312         if(!(i % (rw_count >> 3)))\r
313             printf("*");\r
314     }\r
315     if(i != rw_count){\r
316         printf("ERROR: rw_count = %d\n", i);\r
317         return false;\r
318     }\r
319     printf(" OK\n");\r
320     stop = get_ms();\r
321     diff = stop - start;\r
322     size_bytes = rw_szie * rw_count;\r
323     size_bytes = (size_bytes * 1000) / 1024;\r
324     kbps = (size_bytes) / (diff + 1);\r
325     printf("file_test read time: %d ms\n", (int)diff);\r
326     printf("file_test read speed: %d KB/s\n", kbps);\r
327     r = ext4_fclose(&f);\r
328 \r
329     return true;\r
330 \r
331 }\r
332 static void cleanup(void)\r
333 {\r
334     clock_t start;\r
335     clock_t stop;\r
336     clock_t diff;\r
337 \r
338     ext4_fremove("/mp/hello.txt");\r
339 \r
340     printf("cleanup: remove /mp/test1\n");\r
341     start = get_ms();\r
342     ext4_fremove("/mp/test1");\r
343     stop = get_ms();\r
344     diff = stop - start;\r
345     printf("cleanup: time: %d ms\n", (int)diff);\r
346 \r
347 \r
348     printf("cleanup: remove /mp/dir1\n");\r
349     start =get_ms();\r
350     ext4_dir_rm("/mp/dir1");\r
351     stop = get_ms();\r
352     diff = stop - start;\r
353     printf("cleanup: time: %d ms\n", (int)diff);\r
354 }\r
355 \r
356 static bool open_filedev(void)\r
357 {\r
358 \r
359     bd = ext4_usb_msc_get();\r
360     bc = ext4_usb_msc_cache_get();\r
361     if(!bd || !bc){\r
362         printf("Block device ERROR\n");\r
363         return false;\r
364     }\r
365     return true;\r
366 }\r
367 \r
368 static bool mount(void)\r
369 {\r
370     int r;\r
371 \r
372     if(!open_filedev())\r
373         return false;\r
374 \r
375     ext4_dmask_set(EXT4_DEBUG_ALL);\r
376 \r
377     r = ext4_device_register(bd, cache_mode ? 0 : bc, "ext4_filesim");\r
378     if(r != EOK){\r
379         printf("ext4_device_register ERROR = %d\n", r);\r
380         return false;\r
381     }\r
382 \r
383     r = ext4_mount("ext4_filesim", "/mp/");\r
384     if(r != EOK){\r
385         printf("ext4_mount ERROR = %d\n", r);\r
386         return false;\r
387     }\r
388 \r
389     return true;\r
390 }\r
391 \r
392 static bool umount(void)\r
393 {\r
394     int r = ext4_umount("/mp/");\r
395     if(r != EOK){\r
396         printf("ext4_umount: FAIL %d", r);\r
397         return false;\r
398     }\r
399     return true;\r
400 }\r
401 \r
402 \r
403 int main(void)\r
404 {\r
405     hw_init();\r
406 \r
407     setbuf(stdout, 0);\r
408     printf("Connect USB drive...\n");\r
409 \r
410     while(!hw_usb_connected())\r
411         hw_usb_process();\r
412     printf("USB drive connected\n");\r
413 \r
414     while(!hw_usb_enum_done())\r
415         hw_usb_process();\r
416     printf("USB drive enum done\n");\r
417 \r
418     hw_led_red(1);\r
419 \r
420     printf("Test conditions:\n");\r
421     printf("Imput name: %s\n", input_name);\r
422     printf("RW size: %d\n",  rw_szie);\r
423     printf("RW count: %d\n", rw_count);\r
424     printf("Cache mode: %s\n", cache_mode ? "dynamic" : "static");\r
425 \r
426     if(!mount())\r
427         return EXIT_FAILURE;\r
428 \r
429 \r
430     cleanup();\r
431 \r
432     if(sbstat)\r
433         mp_stats();\r
434 \r
435     dir_ls("/mp/");\r
436     if(!dir_test(dir_cnt))\r
437         return EXIT_FAILURE;\r
438 \r
439     if(!file_test())\r
440         return EXIT_FAILURE;\r
441 \r
442     dir_ls("/mp/");\r
443 \r
444     if(sbstat)\r
445         mp_stats();\r
446 \r
447     if(cleanup_flag)\r
448         cleanup();\r
449 \r
450     if(bstat)\r
451         block_stats();\r
452 \r
453     if(!umount())\r
454         return EXIT_FAILURE;\r
455 \r
456     printf("Test finish: OK\n");\r
457     printf("Press RESET to restart\n");\r
458     while (1)\r
459     {\r
460         volatile int count;\r
461         for (count = 0; count < 1000000; count++);\r
462         hw_led_green(1);\r
463         for (count = 0; count < 1000000; count++);\r
464         hw_led_green(0);\r
465 \r
466     }\r
467 }\r
468 \r
469 /**     @} (end addtogroup subgroup)    */\r
470 /** @} (end addtogroup group)           */\r