]>
cloudbase.mooo.com Git - z180-stamp.git/blob - avr/cmd_fat.c
2 * (C) Copyright 2014,2016,2018 Leo C. <erbl259-lmu@yahoo.de>
4 * SPDX-License-Identifier: GPL-2.0
8 * FAT filesystem commands
14 uint32_t fat_time(const struct tm
* timeptr
);
19 #include "con-utils.h"
20 #include "print-utils.h"
25 #define DEBUG_FA 0 /* set to 1 to debug */
26 #define DEBUG_LS 1 /* set to 1 to debug */
27 #define DEBUG_RM 1 /* set to 1 to debug */
29 #define debug_fa(fmt, args...) \
30 debug_cond(DEBUG_FA, fmt, ##args)
31 #define debug_ls(fmt, args...) \
32 debug_cond(DEBUG_LS, fmt, ##args)
33 #define debug_rm(fmt, args...) \
34 debug_cond(DEBUG_RM, fmt, ##args)
37 /* TODO: use memory size test function (z80_memsize_detect() ) */
38 #define MAX_MEMORY CONFIG_SYS_RAMSIZE_MAX
39 #define BUFFER_SIZE FF_MAX_SS
40 #define PATH_MAX CONFIG_SYS_MAX_PATHLEN
44 * Multible (fat) partitions per physical drive are not supported,
45 * but we have up to 2 sdcard slots.
50 void setup_fatfs(void)
52 f_mount(&FatFs0
, "0:", 0);
53 f_mount(&FatFs1
, "1:", 0);
56 DWORD
get_fattime (void)
62 gmtime_r(&timer
, &tm_timer
);
64 return fat_time(&tm_timer
);
69 bool check_abort(void)
74 printf_P(PSTR("Abort\n"));
80 static const FLASH
char * const FLASH rc_strings
[] = {
83 FSTR("Internal error"),
90 FSTR("Invalid object"),
91 FSTR("Write protected"),
92 FSTR("Invalid drive"),
94 FSTR("No file system"),
98 FSTR("Not enough core"),
99 FSTR("Too many open files"),
100 FSTR("Invalid parameter")
104 const FLASH
char * fat_rctostr(FRESULT rc
)
106 return rc
< ARRAY_SIZE(rc_strings
) ? rc_strings
[rc
] : PSTR(" Unknown Error");
112 static const FLASH
char swirlchar
[] = { '-','\\','|','/' };
113 static uint_fast8_t cnt
;
114 static uint32_t tstamp
;
116 if (get_timer(0) > tstamp
) {
117 tstamp
= get_timer(0) + 250;
120 putchar(swirlchar
[cnt
]);
125 * pwd - Print current directory of the current drive.
128 command_ret_t
do_pwd(cmd_tbl_t
*cmdtp UNUSED
, uint_fast8_t flag UNUSED
, int argc UNUSED
, char * const argv
[] UNUSED
)
133 res
= f_getcwd(buf
, PATH_MAX
); /* Get current directory path */
136 cmd_error(CMD_RET_FAILURE
, res
, NULL
);
140 return CMD_RET_SUCCESS
;
145 * cd - Change the current/working directory.
148 command_ret_t
do_cd(cmd_tbl_t
*cmdtp UNUSED
, uint_fast8_t flag UNUSED
, int argc
, char * const argv
[])
154 path
= getenv_str(PSTR(ENV_HOME
));
156 cmd_error(CMD_RET_FAILURE
, 0, PSTR("\"%S\" not set"), PSTR(ENV_HOME
));
161 if (strlen(path
) > 1 && path
[1] == ':')
162 res
= f_chdrive(path
);
168 cmd_error(CMD_RET_FAILURE
, res
, NULL
);
170 return CMD_RET_SUCCESS
;
175 void print_dirent(FILINFO
*f
)
177 printf_P(PSTR("%c%c%c%c%c %u/%02u/%02u %02u:%02u %9lu %s\n"),
178 (f
->fattrib
& AM_DIR
) ? 'D' : '-',
179 (f
->fattrib
& AM_RDO
) ? 'R' : '-',
180 (f
->fattrib
& AM_HID
) ? 'H' : '-',
181 (f
->fattrib
& AM_SYS
) ? 'S' : '-',
182 (f
->fattrib
& AM_ARC
) ? 'A' : '-',
183 (f
->fdate
>> 9) + 1980, (f
->fdate
>> 5) & 15, f
->fdate
& 31,
184 (f
->ftime
>> 11), (f
->ftime
>> 5) & 63,
188 char *path_split(char *p
)
190 if (isdigit(p
[0]) && (p
[1] == ':'))
193 char *ps
= strrchr(p
, '/');
197 memmove(ps
+1, ps
, strlen(ps
)+1);
206 * ls path - Directory listing
209 command_ret_t
do_ls(cmd_tbl_t
*cmdtp UNUSED
, uint_fast8_t flag UNUSED
, int argc
, char * const argv
[])
212 DIR dir
; /* Directory object */
222 memset(buf
, 0, PATH_MAX
);
226 strncpy(path
, argv
[1], PATH_MAX
-1);
228 pattern
= path_split(path
);
229 debug_ls("### path, pattern: '%s', '%s'\n", path
[0] ? path
: "<NULL>", pattern
? pattern
: "<NULL>");
231 if (pattern
== NULL
) {
232 res
= f_opendir(&dir
, path
);
233 if (res
== FR_NO_PATH
|| res
== FR_INVALID_NAME
) {
236 } else if (res
!= FR_OK
) {
237 cmd_error(CMD_RET_FAILURE
, res
, PSTR("'%s'"), path
);
240 debug_ls("### path, pattern: '%s', '%s'\n", path
, pattern
? pattern
: "<NULL>");
242 if (pattern
== NULL
|| *pattern
== '\0')
245 debug_ls("### path, pattern: '%s', '%s'\n", path
, pattern
? pattern
: "<NULL>");
247 res
= f_findfirst(&dir
, &finfo
, path
, pattern
);
252 cmd_error(CMD_RET_FAILURE
, res
, NULL
);
255 if (finfo
.fattrib
& AM_DIR
) {
258 s1
++; p1
+= finfo
.fsize
;
260 print_dirent(&finfo
);
263 res
= f_findnext(&dir
, &finfo
);
267 printf_P(PSTR("%4u File(s),%10lu bytes total\n%4u Dir(s)"), s1
, p1
, s2
);
268 if (f_getfree(path
, (DWORD
*)&p1
, &fs
) == FR_OK
)
269 printf_P(PSTR(", %10luK bytes free\n"), p1
* fs
->csize
/ 2);
273 cmd_error(CMD_RET_FAILURE
, res
, NULL
);
275 return CMD_RET_SUCCESS
;
280 * tst path - for debugging: test access with different functions
283 command_ret_t
do_tst(cmd_tbl_t
*cmdtp UNUSED
, uint_fast8_t flag UNUSED
, int argc
, char * const argv
[])
285 DIR Dir
; /* Directory object */
291 printf_P(PSTR("sizeof DIR: %u, sizeof FIL: %u\n"), sizeof (DIR), sizeof (FILINFO
));
293 char * buf
= (char *) malloc(BUFFER_SIZE
);
295 cmd_error(CMD_RET_FAILURE
, ENOMEM
, NULL
);
297 res
= f_getcwd(buf
, BUFFER_SIZE
); /* Get current directory path */
300 printf_P(PSTR("cwd: '%s'\n"), buf
);
304 cmd_error(CMD_RET_FAILURE
, res
, NULL
);
311 printf_P(PSTR("arg: '%s' '%s'\n"), path
, pattern
);
312 printf_P(PSTR("==== f_stat: "));
313 res
= f_stat(path
, &finfo
);
314 cmd_error(0, res
, NULL
);
316 print_dirent(&finfo
);
319 printf_P(PSTR("==== f_findfirst: "));
320 res
= f_findfirst(&Dir
, &finfo
, path
, pattern
); /* Start to search for files */
321 cmd_error(CMD_RET_FAILURE
, res
, NULL
);
323 print_dirent(&finfo
);
327 printf_P(PSTR("==== f_opendir: "));
328 res
= f_opendir(&Dir
, path
);
329 cmd_error(CMD_RET_FAILURE
, res
, NULL
);
332 return CMD_RET_SUCCESS
;
335 /* Work register for fs command */
338 WORD AccFiles
, AccDirs
;
344 char *path
, /* Pointer to the working buffer with start path */
345 struct stat_dat_s
*statp
353 res
= f_opendir(&dirs
, path
);
357 while (((res
= f_readdir(&dirs
, &statp
->finfo
)) == FR_OK
) &&
358 statp
->finfo
.fname
[0]) {
359 if (FF_FS_RPATH
&& statp
->finfo
.fname
[0] == '.')
361 fn
= statp
->finfo
.fname
;
362 if (statp
->finfo
.fattrib
& AM_DIR
) {
365 strcpy(path
+i
+1, fn
);
366 res
= scan_files(path
, statp
);
371 //printf_P(PSTR("%s/%s\n"), path, fn);
373 statp
->AccSize
+= statp
->finfo
.fsize
;
387 * fatstat path - Show logical drive status
390 command_ret_t
do_stat(cmd_tbl_t
*cmdtp UNUSED
, uint_fast8_t flag UNUSED
, int argc
, char * const argv
[])
397 struct stat_dat_s statp
;
399 buf
= (char *) malloc(PATH_MAX
);
401 cmd_error(CMD_RET_FAILURE
, ENOMEM
, NULL
);
405 res
= f_getfree(path
, &nfreeclst
, &fs
);
409 "Bytes/Cluster: %lu\n"
410 "Number of FATs: %u\n"
411 "Root DIR entries: %u\n"
413 "Number of clusters: %lu\n"
414 "FAT start (lba): %lu\n"
415 "DIR start (lba,cluster): %lu\n"
416 "Data start (lba): %lu\n"),
417 fs
->fs_type
, (DWORD
)fs
->csize
* 512, fs
->n_fats
,
418 fs
->n_rootdir
, fs
->fsize
, fs
->n_fatent
- 2,
419 fs
->fatbase
, fs
->dirbase
, fs
->database
);
423 res
= f_getlabel(path
, buf
, &serial
);
427 "Volume S/N: %04X-%04X\n"),
428 buf
, (WORD
)(serial
>> 16), (WORD
)(serial
& 0xFFFF));
432 statp
.AccSize
= statp
.AccFiles
= statp
.AccDirs
= 0;
435 my_puts_P(PSTR("\nCounting... "));
436 res
= scan_files(buf
, &statp
);
440 printf_P(PSTR("%u files, %lu bytes.\n%u folders.\n"
441 "%lu KB total disk space.\n%lu KB available.\n"),
442 statp
.AccFiles
, statp
.AccSize
, statp
.AccDirs
,
443 (fs
->n_fatent
- 2) * (fs
->csize
/ 2), nfreeclst
* (fs
->csize
/ 2)
450 cmd_error(CMD_RET_FAILURE
, res
, NULL
);
452 return CMD_RET_SUCCESS
;
456 * fatread/write - load binary file to/from a dos filesystem
457 * read <d:/path/filename> <addr> [bytes [pos]]
458 * write <d:/path/filename> <addr> <bytes>
460 command_ret_t
do_rw(cmd_tbl_t
*cmdtp UNUSED
, uint_fast8_t flag UNUSED
, int argc
, char * const argv
[])
466 unsigned long bytes_rw
;
468 bool dowrite
= (argv
[0][0] == 'w');
474 if (argc
< (dowrite
? 4 : 3))
475 return CMD_RET_USAGE
;
477 addr
= eval_arg(argv
[2], NULL
);
478 if (addr
>= MAX_MEMORY
)
479 cmd_error(CMD_RET_FAILURE
, 0, PSTR("Address too high: %#lx"), addr
);
482 bytes
= eval_arg(argv
[3], NULL
);
486 pos
= eval_arg(argv
[4], NULL
);
490 if (addr
+ bytes
> MAX_MEMORY
)
491 bytes
= MAX_MEMORY
- addr
;
493 buffer
= (uint8_t *) malloc(BUFFER_SIZE
);
495 cmd_error(CMD_RET_FAILURE
, ENOMEM
, NULL
);
497 res
= f_open(&File
, argv
[1], dowrite
? FA_WRITE
| FA_CREATE_ALWAYS
501 res
= f_lseek(&File
, pos
);
504 timer
= get_timer(0);
506 unsigned int cnt
, br
;
508 if (bytes
>= BUFFER_SIZE
) {
510 bytes
-= BUFFER_SIZE
;
512 cnt
= bytes
; bytes
= 0;
515 if (!(z80_bus_cmd(Request
) & ZST_ACQUIRED
)) {
519 z80_read_block(buffer
, addr
, cnt
);
520 z80_bus_cmd(Release
);
521 res
= f_write(&File
, buffer
, cnt
, &br
);
525 res
= f_read(&File
, buffer
, cnt
, &br
);
528 if (!(z80_bus_cmd(Request
) & ZST_ACQUIRED
)) {
532 z80_write_block(buffer
, addr
, br
);
533 z80_bus_cmd(Release
);
540 printf_P(PSTR("Disk full?\n"));
547 FRESULT fr
= f_close(&File
);
550 timer
= get_timer(timer
);
551 printf_P(PSTR("%lu (%#lx) bytes read/written with %lu bytes/sec.\n"),
552 bytes_rw
, bytes_rw
, timer
? (bytes_rw
* 1000 / timer
) : 0);
559 cmd_error(CMD_RET_FAILURE
, res
, PSTR("'%s'"), argv
[1]);
561 cmd_error(CMD_RET_FAILURE
, EBUSTO
, NULL
);
563 return CMD_RET_SUCCESS
;
567 * command table for fat subcommands
570 cmd_tbl_t cmd_tbl_fat
[] = {
572 status
, 2, CTBL_RPT
, do_stat
,
573 "Show logical drive status",
577 pwd
, 2, CTBL_RPT
|CTBL_SUBCMDAUTO
, do_pwd
,
578 "Print name of current/working directory",
582 cd
, 2, 0|CTBL_SUBCMDAUTO
, do_cd
,
583 "Change the current/working directory.",
587 ls
, 2, CTBL_RPT
|CTBL_SUBCMDAUTO
, do_ls
,
592 tst
, 3, CTBL_DBG
|CTBL_RPT
, do_tst
,
593 "FatFS test function",
598 "load binary file from a dos filesystem",
599 "<d:/path/filename> <addr> [bytes [pos]]\n"
600 " - Load binary file 'path/filename' on logical drive 'd'\n"
601 " to address 'addr' from dos filesystem.\n"
602 " 'pos' gives the file position to start loading from.\n"
603 " If 'pos' is omitted, 0 is used. 'pos' requires 'bytes'.\n"
604 " 'bytes' gives the size to load. If 'bytes' is 0 or omitted,\n"
605 " the load stops on end of file."
609 "write file into a dos filesystem",
610 "<d:/path/filename> <addr> <bytes>\n"
611 " - Write file to 'path/filename' on logical drive 'd' from RAM\n"
612 " starting at address 'addr'.\n"
616 help
, CONFIG_SYS_MAXARGS
, CTBL_RPT
, do_help
,
617 "Print sub command description/usage",
619 " - print brief description of all sub commands\n"
620 "fat help command ...\n"
621 " - print detailed usage of sub cmd 'command'"
624 /* This does not use the CMD_TBL_ITEM macro as ? can't be used in symbol names */
625 {FSTR("?"), CONFIG_SYS_MAXARGS
, 1, do_help
,
627 #ifdef CONFIG_SYS_LONGHELP
629 #endif /* CONFIG_SYS_LONGHELP */
631 #ifdef CONFIG_AUTO_COMPLETE
635 /* Mark end of table */
636 CMD_TBL_END(cmd_tbl_fat
)
640 command_ret_t
do_fat(cmd_tbl_t
*cmdtp UNUSED
, uint_fast8_t flag UNUSED
, int argc UNUSED
, char * const argv
[] UNUSED
)
642 puts_P(PSTR("Huch?"));
644 return CMD_RET_USAGE
;