]>
cloudbase.mooo.com Git - z180-stamp.git/blob - avr/cmd_fat.c
2 * (C) Copyright 2014,2016 Leo C. <erbl259-lmu@yahoo.de>
4 * SPDX-License-Identifier: GPL-2.0
8 * FAT filesystem commands
20 #include "con-utils.h"
21 #include "print-utils.h"
26 #include "getopt-min.h"
28 /* TODO: use memory size test function (cmd_mem.c) */
29 #define MAX_MEMORY (1ul << 19)
30 #define BUFFER_SIZE 512
38 DWORD
get_fattime (void)
44 gmtime_r(&timer
, &tm_timer
);
46 return fatfs_time(&tm_timer
);
50 static bool check_abort(void)
55 printf_P(PSTR("Abort\n"));
61 static const FLASH
char * const FLASH rc_names
[] = {
71 FSTR("INVALID_OBJECT"),
72 FSTR("WRITE_PROTECTED"),
73 FSTR("INVALID_DRIVE"),
75 FSTR("NO_FILE_SYSTEM"),
79 FSTR("NOT_ENOUGH_CORE"),
80 FSTR("TOO_MANY_OPEN_FILES"),
81 FSTR("INVALID_PARAMETER")
85 void put_rc (FRESULT rc
)
88 printf_P(PSTR("rc=%u FR_"), rc
);
89 my_puts_P(rc
< ARRAY_SIZE(rc_names
) ? rc_names
[rc
] : PSTR(" Unknown Error"));
90 my_puts_P(PSTR("\n"));
92 printf_P(PSTR("rc=%u FR_%S\n"), rc
,
93 rc
< ARRAY_SIZE(rc_names
) ? rc_names
[rc
] : PSTR(" Unknown Error"));
98 void setup_fatfs(void)
100 f_mount(&FatFs0
, "0:", 0);
101 f_mount(&FatFs1
, "1:", 0);
105 static void swirl(void)
107 static const FLASH
char swirlchar
[] = { '-','\\','|','/' };
108 static uint_fast8_t cnt
;
109 static uint32_t tstamp
;
111 if (get_timer(0) > tstamp
) {
112 printf_P(PSTR("\b%c"), swirlchar
[cnt
]);
113 cnt
= (cnt
+1) % ARRAY_SIZE(swirlchar
);
114 tstamp
= get_timer(0) + 250;
118 /* Work register for fs command */
121 WORD AccFiles
, AccDirs
;
127 char *path
, /* Pointer to the working buffer with start path */
128 struct stat_dat_s
*statp
136 res
= f_opendir(&dirs
, path
);
140 while (((res
= f_readdir(&dirs
, &statp
->Finfo
)) == FR_OK
) &&
141 statp
->Finfo
.fname
[0]) {
142 if (_FS_RPATH
&& statp
->Finfo
.fname
[0] == '.')
144 fn
= statp
->Finfo
.fname
;
145 if (statp
->Finfo
.fattrib
& AM_DIR
) {
148 strcpy(path
+i
+1, fn
);
149 res
= scan_files(path
, statp
);
154 //printf_P(PSTR("%s/%s\n"), path, fn);
156 statp
->AccSize
+= statp
->Finfo
.fsize
;
170 * fatstat path - Show logical drive status
173 command_ret_t
do_stat(cmd_tbl_t
*cmdtp
, uint_fast8_t flag
, int argc
, char * const argv
[])
180 struct stat_dat_s statp
;
182 (void) cmdtp
; (void) flag
; (void) argc
;
184 buf
= (char *) malloc(BUFFER_SIZE
);
186 printf_P(PSTR("fat stat: Out of Memory!\n"));
187 return CMD_RET_FAILURE
;
192 res
= f_getfree(path
, &nfreeclst
, &fs
);
196 "Bytes/Cluster: %lu\n"
197 "Number of FATs: %u\n"
198 "Root DIR entries: %u\n"
200 "Number of clusters: %lu\n"
201 "FAT start (lba): %lu\n"
202 "DIR start (lba,cluster): %lu\n"
203 "Data start (lba): %lu\n"),
204 fs
->fs_type
, (DWORD
)fs
->csize
* 512, fs
->n_fats
,
205 fs
->n_rootdir
, fs
->fsize
, fs
->n_fatent
- 2,
206 fs
->fatbase
, fs
->dirbase
, fs
->database
);
210 res
= f_getlabel(path
, buf
, &serial
);
214 "Volume S/N: %04X-%04X\n"),
215 buf
, (WORD
)(serial
>> 16), (WORD
)(serial
& 0xFFFF));
219 my_puts_P(PSTR("\nCounting... "));
220 statp
.AccSize
= statp
.AccFiles
= statp
.AccDirs
= 0;
223 res
= scan_files(buf
, &statp
);
226 printf_P(PSTR("\r%u files, %lu bytes.\n%u folders.\n"
227 "%lu KB total disk space.\n%lu KB available.\n"),
228 statp
.AccFiles
, statp
.AccSize
, statp
.AccDirs
,
229 (fs
->n_fatent
- 2) * (fs
->csize
/ 2), nfreeclst
* (fs
->csize
/ 2)
237 return CMD_RET_FAILURE
;
239 return CMD_RET_SUCCESS
;
243 * pwd - Print current directory of the current drive.
246 command_ret_t
do_pwd(cmd_tbl_t
*cmdtp
, uint_fast8_t flag
, int argc
, char * const argv
[])
251 (void) cmdtp
; (void) flag
; (void) argc
; (void) argv
;
253 buf
= (char *) malloc(BUFFER_SIZE
);
255 printf_P(PSTR("pwd: Out of Memory!\n"));
257 return CMD_RET_FAILURE
;
260 res
= f_getcwd(buf
, BUFFER_SIZE
); /* Get current directory path */
268 return CMD_RET_FAILURE
;
270 return CMD_RET_SUCCESS
;
275 * cd - Change the current/working directory.
278 command_ret_t
do_cd(cmd_tbl_t
*cmdtp
, uint_fast8_t flag
, int argc
, char * const argv
[])
283 (void) cmdtp
; (void) flag
; (void) argc
;
286 arg
= getenv_str(PSTR(ENV_HOME
));
288 printf_P(PSTR("%s: \"%S\" is not set\n"), argv
[0], PSTR(ENV_HOME
));
289 return CMD_RET_FAILURE
;
299 res
= f_chdrive(drv
);
307 return CMD_RET_FAILURE
;
309 return CMD_RET_SUCCESS
;
312 #define MAX_PATHLEN 255
314 /* Remove trailing slashes,
315 * but keep a leading slash (absolute path)
317 void strip_trailing_slash_relpath(char *p
)
321 if (n
>= 2 && (p
[0] & 0x38) == '0' && p
[1] == ':') {
325 if (n
>= 1 && p
[0] == '/') {
329 while (n
-- != 0 && p
[n
] == '/')
333 int print_dirent(FILINFO
*f
)
335 return printf_P(PSTR("%c%c%c%c%c %u/%02u/%02u %02u:%02u %9lu %s\n"),
336 (f
->fattrib
& AM_DIR
) ? 'D' : '-',
337 (f
->fattrib
& AM_RDO
) ? 'R' : '-',
338 (f
->fattrib
& AM_HID
) ? 'H' : '-',
339 (f
->fattrib
& AM_SYS
) ? 'S' : '-',
340 (f
->fattrib
& AM_ARC
) ? 'A' : '-',
341 (f
->fdate
>> 9) + 1980, (f
->fdate
>> 5) & 15, f
->fdate
& 31,
342 (f
->ftime
>> 11), (f
->ftime
>> 5) & 63,
347 * fatls path - Directory listing
350 command_ret_t
do_ls(cmd_tbl_t
*cmdtp
, uint_fast8_t flag
, int argc
, char * const argv
[])
353 DIR Dir
; /* Directory object */
358 (void) cmdtp
; (void) flag
; (void) argc
;
364 strip_trailing_slash_relpath(path
);
366 char *p
= strrchr(path
, '/');
372 if ((*q
++ & 0x38) == '0' && *q
++ == ':')
376 char *pattern
= NULL
;
377 if (strpbrk_P(p
, PSTR("*?")) ||
378 (f_stat(path
, &Finfo
) == FR_OK
&& !(Finfo
.fattrib
& AM_DIR
))) {
382 strip_trailing_slash_relpath(path
);
384 printf_P(PSTR("*: |%s| |%s|\n"), path
? path
: "<NULL>", pattern
? pattern
: "<NULL>");
387 res
= f_findfirst(&Dir
, &Finfo
, path
, pattern
? pattern
: "*"); /* Start to search for files */
388 while (res
== FR_OK
&& Finfo
.fname
[0]) {
389 if (Finfo
.fattrib
& AM_DIR
) {
392 s1
++; p1
+= Finfo
.fsize
;
394 print_dirent(&Finfo
);
397 res
= f_findnext(&Dir
, &Finfo
);
403 printf_P(PSTR("%4u File(s),%10lu bytes total\n%4u Dir(s)"), s1
, p1
, s2
);
404 if (f_getfree(path
, (DWORD
*)&p1
, &fs
) == FR_OK
)
405 printf_P(PSTR(", %10luK bytes free\n"), p1
* fs
->csize
/ 2);
410 return CMD_RET_FAILURE
;
413 return CMD_RET_SUCCESS
;
416 command_ret_t
do_tst(cmd_tbl_t
*cmdtp
, uint_fast8_t flag
, int argc
, char * const argv
[])
418 DIR Dir
; /* Directory object */
423 (void) cmdtp
; (void) flag
;
425 printf_P(PSTR("sizeof DIR: %u, sizeof FIL: %u\n"), sizeof (DIR), sizeof (FILINFO
));
427 char * buf
= (char *) malloc(BUFFER_SIZE
);
429 printf_P(PSTR("pwd: Out of Memory!\n"));
431 return CMD_RET_FAILURE
;
433 res
= f_getcwd(buf
, BUFFER_SIZE
); /* Get current directory path */
436 printf_P(PSTR("cwd: |%s|\n"), buf
);
441 return CMD_RET_FAILURE
;
449 printf_P(PSTR("arg: |%s|\n"), path
);
450 printf_P(PSTR("==== f_stat: "));
451 res
= f_stat(path
, &Finfo
);
454 print_dirent(&Finfo
);
457 printf_P(PSTR("==== f_findfirst: "));
458 res
= f_findfirst(&Dir
, &Finfo
, path
, "*"); /* Start to search for files */
461 print_dirent(&Finfo
);
465 printf_P(PSTR("==== f_opendir: "));
466 res
= f_opendir(&Dir
, path
);
470 return CMD_RET_SUCCESS
;
474 FRESULT
mkpath(TCHAR
*path
)
483 res
= f_stat (path
, &fd
)
485 p
= strchr(path
, ':');
486 if (p
== NULL
|| *++p
== '\0' || *p
++ != '/')
489 while ((q
= strchr(p
, '/')) != NULL
) {
493 if (ret
!= FR_OK
&& ret
!= FR_EXIST
)
503 * fatread/write - load binary file to/from a dos filesystem
504 * read <d:/path/filename> <addr> [bytes [pos]]
505 * write <d:/path/filename> <addr> <bytes>
507 command_ret_t
do_rw(cmd_tbl_t
*cmdtp
, uint_fast8_t flag
, int argc
, char * const argv
[])
513 unsigned long bytes_rw
;
515 bool dowrite
= (argv
[0][0] == 'w');
521 (void) cmdtp
; (void) flag
;
523 if (argc
< (dowrite
? 4 : 3))
524 return CMD_RET_USAGE
;
526 addr
= eval_arg(argv
[2], NULL
);
527 if (addr
>= MAX_MEMORY
) {
528 printf_P(PSTR("address too high: 0x%0lx\n"), addr
);
529 return CMD_RET_FAILURE
;
532 bytes
= eval_arg(argv
[3], NULL
);
536 pos
= eval_arg(argv
[4], NULL
);
540 if (addr
+ bytes
> MAX_MEMORY
)
541 bytes
= MAX_MEMORY
- addr
;
543 buffer
= (uint8_t *) malloc(BUFFER_SIZE
);
544 if (buffer
== NULL
) {
545 printf_P(PSTR("fatstat: Out of Memory!\n"));
547 return CMD_RET_FAILURE
;
551 res
= mkpath(argv
[1]);
554 res
= f_open(&File
, argv
[1], dowrite
? FA_WRITE
| FA_CREATE_ALWAYS
558 res
= f_lseek(&File
, pos
);
561 timer
= get_timer(0);
563 unsigned int cnt
, br
;
565 if (bytes
>= BUFFER_SIZE
) {
567 bytes
-= BUFFER_SIZE
;
569 cnt
= bytes
; bytes
= 0;
572 if (!(z80_bus_cmd(Request
) & ZST_ACQUIRED
)) {
576 z80_read_block(buffer
, addr
, cnt
);
577 z80_bus_cmd(Release
);
578 res
= f_write(&File
, buffer
, cnt
, &br
);
582 res
= f_read(&File
, buffer
, cnt
, &br
);
585 if (!(z80_bus_cmd(Request
) & ZST_ACQUIRED
)) {
589 z80_write_block(buffer
, addr
, br
);
590 z80_bus_cmd(Release
);
597 printf_P(PSTR("Disk full?\n"));
604 FRESULT fr
= f_close(&File
);
607 timer
= get_timer(timer
);
608 printf_P(PSTR("%lu (0x%lx) bytes read/written with %lu bytes/sec.\n"),
609 bytes_rw
, bytes_rw
, timer
? (bytes_rw
* 1000 / timer
) : 0);
617 my_puts_P(PSTR("Bus timeout\n"));
621 return CMD_RET_FAILURE
;
623 return CMD_RET_SUCCESS
;
626 /* ========================================================================== */
630 char *p_end
; /* pointer to NULL at end of path */
631 char p_path
[MAX_PATHLEN
+ 1]; /* pointer to the start of a path */
634 static inline void strip_trailing_slash(PATH_T
*p
)
636 while (p
->p_end
> p
->p_path
&& p
->p_end
[-1] == '/')
641 * Move specified string into path. Convert "" to "." to handle BSD
642 * semantics for a null path. Strip trailing slashes.
645 path_set(PATH_T
*p
, char *string
)
647 if (strlen(string
) > MAX_PATHLEN
) {
648 //err("%s: name too long", string);
652 (void)strcpy(p
->p_path
, string
);
653 p
->p_end
= p
->p_path
+ strlen(p
->p_path
);
655 if (p
->p_path
== p
->p_end
) {
660 strip_trailing_slash(p
);
664 #define R_FLAG (1<<0)
665 #define I_FLAG (1<<1)
666 #define N_FLAG (1<<2)
667 #define F_FLAG (1<<3)
668 #define P_FLAG (1<<4)
669 #define V_FLAG (1<<5)
671 command_ret_t
do_cp(cmd_tbl_t
*cmdtp UNUSED
, uint_fast8_t flag UNUSED
, int argc
, char * const argv
[])
674 FRESULT fr
; /* Return value */
675 DIR dj
; /* Directory search object */
676 FILINFO fno
; /* File information */
685 while ((opt
= getopt(argc
, argv
, PSTR("Rrfip"))) != -1) {
705 return CMD_RET_USAGE
;
713 return CMD_RET_USAGE
;
716 /* consume last argument first. */
717 if (!path_set(&to
, argv
[--argc
]))
722 printf_P((PSTR("%s %s -> %s\n", badcp
? : "ERR:" : " ",
723 curr
->fts_path
, to
.p_path
);
726 /* Search a directory for objects and display it */
729 fr
= f_findfirst(&dj
, &fno
, argv
[1], argv
[2]); /* Start to search for files */
731 while (fr
== FR_OK
&& fno
.fname
[0]) { /* Repeat while an item is found */
732 printf_P(PSTR("%c%c%c%c%c %u/%02u/%02u %02u:%02u %9lu %s\n"),
733 (fno
.fattrib
& AM_DIR
) ? 'D' : '-',
734 (fno
.fattrib
& AM_RDO
) ? 'R' : '-',
735 (fno
.fattrib
& AM_HID
) ? 'H' : '-',
736 (fno
.fattrib
& AM_SYS
) ? 'S' : '-',
737 (fno
.fattrib
& AM_ARC
) ? 'A' : '-',
738 (fno
.fdate
>> 9) + 1980, (fno
.fdate
>> 5) & 15, fno
.fdate
& 31,
739 (fno
.ftime
>> 11), (fno
.ftime
>> 5) & 63,
740 fno
.fsize
, fno
.fname
);
741 fr
= f_findnext(&dj
, &fno
); /* Search for next item */
746 return CMD_RET_SUCCESS
;
751 command_ret_t
do_help(cmd_tbl_t
*cmdtp
, uint_fast8_t flag
, int argc
, char * const argv
[]);
753 cmd_tbl_t cmd_fat_sub
[] = {
755 stat
, 2, CTBL_REPEAT
, do_stat
,
756 "Show logical drive status",
760 pwd
, 2, CTBL_REPEAT
, do_pwd
,
761 "Print name of current/working directory",
765 cd
, 2, CTBL_REPEAT
, do_cd
,
766 "Change the current/working directory.",
770 ls
, 2, CTBL_REPEAT
, do_ls
,
775 tst
, 2, CTBL_REPEAT
, do_tst
,
776 "FatFS test function",
781 "load binary file from a dos filesystem",
782 "<d:/path/filename> <addr> [bytes [pos]]\n"
783 " - Load binary file 'path/filename' on logical drive 'd'\n"
784 " to address 'addr' from dos filesystem.\n"
785 " 'pos' gives the file position to start loading from.\n"
786 " If 'pos' is omitted, 0 is used. 'pos' requires 'bytes'.\n"
787 " 'bytes' gives the size to load. If 'bytes' is 0 or omitted,\n"
788 " the load stops on end of file."
792 "write file into a dos filesystem",
793 "<d:/path/filename> <addr> <bytes>\n"
794 " - Write file to 'path/filename' on logical drive 'd' from RAM\n"
795 " starting at address 'addr'.\n"
799 cp
, CONFIG_SYS_MAXARGS
, 0, do_cp
,
801 "cp [-R] [-f | -i | -n] [-aprv] source_file target_file\n"
806 help
, CONFIG_SYS_MAXARGS
, CTBL_REPEAT
, do_help
,
807 "Print sub command description/usage",
809 " - print brief description of all sub commands\n"
810 "fat help command ...\n"
811 " - print detailed usage of sub cmd 'command'"
814 /* This does not use the CMD_TBL_ITEM macro as ? can't be used in symbol names */
815 {FSTR("?"), CONFIG_SYS_MAXARGS
, 1, do_help
,
816 FSTR("Alias for 'help'"),
817 #ifdef CONFIG_SYS_LONGHELP
819 #endif /* CONFIG_SYS_LONGHELP */
820 #ifdef CONFIG_AUTO_COMPLETE
827 command_ret_t
do_help(cmd_tbl_t
*cmdtp
, uint_fast8_t flag
, int argc
, char * const argv
[])
829 return _do_help(cmd_fat_sub
, ARRAY_SIZE(cmd_fat_sub
), cmdtp
, flag
, argc
, argv
);
833 command_ret_t
do_fat(cmd_tbl_t
*cmdtp
, uint_fast8_t flag
, int argc
, char * const argv
[])
838 return CMD_RET_USAGE
;
840 /* drop initial "fat" arg */
844 cp
= find_cmd_tbl(argv
[0], cmd_fat_sub
, ARRAY_SIZE(cmd_fat_sub
));
847 return cp
->cmd(cmdtp
, flag
, argc
, argv
);
849 return CMD_RET_USAGE
;