]>
cloudbase.mooo.com Git - z180-stamp.git/blob - avr/cmd_fat.c
60102ed87df35a2d402d81f06a9d7f60bb667f5a
2 * (C) Copyright 2014,2016,2018 Leo C. <erbl259-lmu@yahoo.de>
4 * SPDX-License-Identifier: GPL-2.0
8 * FAT filesystem commands
16 #include "con-utils.h"
17 #include "print-utils.h"
24 #define DEBUG_FA 0 /* set to 1 to debug */
26 #define debug_fa(fmt, args...) \
27 debug_cond(DEBUG_FA, fmt, ##args)
30 /* TODO: use memory size test function (detect_ramsize() in cmd_loadihex.c) */
31 /* TODO: detect_ramsize() should be moved to z80-if.c */
32 #define MAX_MEMORY CONFIG_SYS_RAMSIZE_MAX
33 #define BUFFER_SIZE 512
36 * Multible (fat) partitions per physical drive are not supported,
37 * but we have up to 2 sdcard slots.
42 void setup_fatfs(void)
44 f_mount(&FatFs0
, "0:", 0);
45 f_mount(&FatFs1
, "1:", 0);
48 DWORD
get_fattime (void)
54 gmtime_r(&timer
, &tm_timer
);
56 return fatfs_time(&tm_timer
);
60 static bool check_abort(void)
65 printf_P(PSTR("Abort\n"));
71 static const FLASH
char * const FLASH rc_names
[] = {
81 FSTR("INVALID_OBJECT"),
82 FSTR("WRITE_PROTECTED"),
83 FSTR("INVALID_DRIVE"),
85 FSTR("NO_FILE_SYSTEM"),
89 FSTR("NOT_ENOUGH_CORE"),
90 FSTR("TOO_MANY_OPEN_FILES"),
91 FSTR("INVALID_PARAMETER")
95 void put_rc (FRESULT rc
)
98 printf_P(PSTR("rc=%u FR_"), rc
);
99 my_puts_P(rc
< ARRAY_SIZE(rc_names
) ? rc_names
[rc
] : PSTR(" Unknown Error"));
100 my_puts_P(PSTR("\n"));
102 printf_P(PSTR("rc=%u FR_%S\n"), rc
,
103 rc
< ARRAY_SIZE(rc_names
) ? rc_names
[rc
] : PSTR(" Unknown Error"));
108 static void swirl(void)
110 static const FLASH
char swirlchar
[] = { '-','\\','|','/' };
111 static uint_fast8_t cnt
;
112 static uint32_t tstamp
;
114 if (get_timer(0) > tstamp
) {
115 tstamp
= get_timer(0) + 250;
118 putchar(swirlchar
[cnt
]);
123 * pwd - Print current directory of the current drive.
126 command_ret_t
do_pwd(cmd_tbl_t
*cmdtp UNUSED
, uint_fast8_t flag UNUSED
, int argc UNUSED
, char * const argv
[] UNUSED
)
131 buf
= (char *) malloc(BUFFER_SIZE
);
133 printf_P(PSTR("pwd: Out of Memory!\n"));
135 return CMD_RET_FAILURE
;
138 res
= f_getcwd(buf
, BUFFER_SIZE
); /* Get current directory path */
146 return CMD_RET_FAILURE
;
148 return CMD_RET_SUCCESS
;
153 * cd - Change the current/working directory.
156 command_ret_t
do_cd(cmd_tbl_t
*cmdtp UNUSED
, uint_fast8_t flag UNUSED
, int argc
, char * const argv
[])
162 arg
= getenv_str(PSTR(ENV_HOME
));
164 printf_P(PSTR("%s: \"%S\" is not set\n"), argv
[0], PSTR(ENV_HOME
));
165 return CMD_RET_FAILURE
;
171 res
= f_chdrive(arg
);
172 debug_fa("### f_chdrive(): arg: '%s', res: %d\n", arg
, res
);
174 if (arg
[2] == '\0') {
180 debug_fa("### f_chdir(): arg: '%s', res: %d\n", arg
, res
);
183 return CMD_RET_FAILURE
;
185 return CMD_RET_SUCCESS
;
190 * ls path - Directory listing
193 command_ret_t
do_ls(cmd_tbl_t
*cmdtp UNUSED
, uint_fast8_t flag UNUSED
, int argc
, char * const argv
[])
196 DIR Dir
; /* Directory object */
204 buf
= (char *) malloc(BUFFER_SIZE
);
206 printf_P(PSTR("pwd: Out of Memory!\n"));
208 return CMD_RET_FAILURE
;
212 res
= f_getcwd(buf
, BUFFER_SIZE
); /* Get current directory path */
214 strncpy(buf
, argv
[1], BUFFER_SIZE
);
217 res
= f_opendir(&Dir
, buf
);
221 return CMD_RET_FAILURE
;
226 res
= f_readdir(&Dir
, &Finfo
);
227 if ((res
!= FR_OK
) || !Finfo
.fname
[0])
229 if (Finfo
.fattrib
& AM_DIR
) {
232 s1
++; p1
+= Finfo
.fsize
;
234 printf_P(PSTR("%c%c%c%c%c %u/%02u/%02u %02u:%02u %9lu %s\n"),
235 (Finfo
.fattrib
& AM_DIR
) ? 'D' : '-',
236 (Finfo
.fattrib
& AM_RDO
) ? 'R' : '-',
237 (Finfo
.fattrib
& AM_HID
) ? 'H' : '-',
238 (Finfo
.fattrib
& AM_SYS
) ? 'S' : '-',
239 (Finfo
.fattrib
& AM_ARC
) ? 'A' : '-',
240 (Finfo
.fdate
>> 9) + 1980, (Finfo
.fdate
>> 5) & 15, Finfo
.fdate
& 31,
241 (Finfo
.ftime
>> 11), (Finfo
.ftime
>> 5) & 63,
242 Finfo
.fsize
, Finfo
.fname
);
248 printf_P(PSTR("%4u File(s),%10lu bytes total\n%4u Dir(s)"), s1
, p1
, s2
);
249 if (f_getfree(buf
, (DWORD
*)&p1
, &fs
) == FR_OK
)
250 printf_P(PSTR(", %10luK bytes free\n"), p1
* fs
->csize
/ 2);
256 return CMD_RET_FAILURE
;
259 return CMD_RET_SUCCESS
;
264 FRESULT
mkpath(TCHAR
*path
)
272 res
= f_stat (path
, &fd
)
274 p
= strchr(path
, ':');
275 if (p
== NULL
|| *++p
== '\0' || *p
++ != '/')
278 while ((q
= strchr(p
, '/')) != NULL
) {
282 if (ret
!= FR_OK
&& ret
!= FR_EXIST
)
291 /* Work register for fs command */
294 WORD AccFiles
, AccDirs
;
300 char *path
, /* Pointer to the working buffer with start path */
301 struct stat_dat_s
*statp
309 res
= f_opendir(&dirs
, path
);
313 while (((res
= f_readdir(&dirs
, &statp
->Finfo
)) == FR_OK
) &&
314 statp
->Finfo
.fname
[0]) {
315 if (FF_FS_RPATH
&& statp
->Finfo
.fname
[0] == '.')
317 fn
= statp
->Finfo
.fname
;
318 if (statp
->Finfo
.fattrib
& AM_DIR
) {
321 strcpy(path
+i
+1, fn
);
322 res
= scan_files(path
, statp
);
327 //printf_P(PSTR("%s/%s\n"), path, fn);
329 statp
->AccSize
+= statp
->Finfo
.fsize
;
343 * fatstat path - Show logical drive status
346 command_ret_t
do_stat(cmd_tbl_t
*cmdtp UNUSED
, uint_fast8_t flag UNUSED
, int argc
, char * const argv
[])
353 struct stat_dat_s statp
;
355 buf
= (char *) malloc(BUFFER_SIZE
);
357 printf_P(PSTR("fat stat: Out of Memory!\n"));
358 return CMD_RET_FAILURE
;
363 res
= f_getfree(path
, &nfreeclst
, &fs
);
367 "Bytes/Cluster: %lu\n"
368 "Number of FATs: %u\n"
369 "Root DIR entries: %u\n"
371 "Number of clusters: %lu\n"
372 "FAT start (lba): %lu\n"
373 "DIR start (lba,cluster): %lu\n"
374 "Data start (lba): %lu\n"),
375 fs
->fs_type
, (DWORD
)fs
->csize
* 512, fs
->n_fats
,
376 fs
->n_rootdir
, fs
->fsize
, fs
->n_fatent
- 2,
377 fs
->fatbase
, fs
->dirbase
, fs
->database
);
381 res
= f_getlabel(path
, buf
, &serial
);
385 "Volume S/N: %04X-%04X\n"),
386 buf
, (WORD
)(serial
>> 16), (WORD
)(serial
& 0xFFFF));
390 statp
.AccSize
= statp
.AccFiles
= statp
.AccDirs
= 0;
393 my_puts_P(PSTR("\nCounting... "));
394 res
= scan_files(buf
, &statp
);
398 printf_P(PSTR("%u files, %lu bytes.\n%u folders.\n"
399 "%lu KB total disk space.\n%lu KB available.\n"),
400 statp
.AccFiles
, statp
.AccSize
, statp
.AccDirs
,
401 (fs
->n_fatent
- 2) * (fs
->csize
/ 2), nfreeclst
* (fs
->csize
/ 2)
409 return CMD_RET_FAILURE
;
411 return CMD_RET_SUCCESS
;
415 * fatread/write - load binary file to/from a dos filesystem
416 * read <d:/path/filename> <addr> [bytes [pos]]
417 * write <d:/path/filename> <addr> <bytes>
419 command_ret_t
do_rw(cmd_tbl_t
*cmdtp UNUSED
, uint_fast8_t flag UNUSED
, int argc
, char * const argv
[])
425 unsigned long bytes_rw
;
427 bool dowrite
= (argv
[0][0] == 'w');
433 if (argc
< (dowrite
? 4 : 3))
434 return CMD_RET_USAGE
;
436 addr
= eval_arg(argv
[2], NULL
);
437 if (addr
>= MAX_MEMORY
) {
438 printf_P(PSTR("address too high: 0x%0lx\n"), addr
);
439 return CMD_RET_FAILURE
;
442 bytes
= eval_arg(argv
[3], NULL
);
446 pos
= eval_arg(argv
[4], NULL
);
450 if (addr
+ bytes
> MAX_MEMORY
)
451 bytes
= MAX_MEMORY
- addr
;
453 buffer
= (uint8_t *) malloc(BUFFER_SIZE
);
454 if (buffer
== NULL
) {
455 printf_P(PSTR("fatstat: Out of Memory!\n"));
457 return CMD_RET_FAILURE
;
461 res
= f_open(&File
, argv
[1], dowrite
? FA_WRITE
| FA_CREATE_ALWAYS
465 res
= f_lseek(&File
, pos
);
468 timer
= get_timer(0);
470 unsigned int cnt
, br
;
472 if (bytes
>= BUFFER_SIZE
) {
474 bytes
-= BUFFER_SIZE
;
476 cnt
= bytes
; bytes
= 0;
479 if (!(z80_bus_cmd(Request
) & ZST_ACQUIRED
)) {
483 z80_read_block(buffer
, addr
, cnt
);
484 z80_bus_cmd(Release
);
485 res
= f_write(&File
, buffer
, cnt
, &br
);
489 res
= f_read(&File
, buffer
, cnt
, &br
);
492 if (!(z80_bus_cmd(Request
) & ZST_ACQUIRED
)) {
496 z80_write_block(buffer
, addr
, br
);
497 z80_bus_cmd(Release
);
504 printf_P(PSTR("Disk full?\n"));
511 FRESULT fr
= f_close(&File
);
514 timer
= get_timer(timer
);
515 printf_P(PSTR("%lu (0x%lx) bytes read/written with %lu bytes/sec.\n"),
516 bytes_rw
, bytes_rw
, timer
? (bytes_rw
* 1000 / timer
) : 0);
524 my_puts_P(PSTR("Bus timeout\n"));
528 return CMD_RET_FAILURE
;
530 return CMD_RET_SUCCESS
;
534 * command table for fat subcommands
537 cmd_tbl_t cmd_tbl_fat
[] = {
539 status
, 2, CTBL_RPT
, do_stat
,
540 "Show logical drive status",
544 pwd
, 2, CTBL_RPT
|CTBL_SUBCMDAUTO
, do_pwd
,
545 "Print name of current/working directory",
549 cd
, 2, 0|CTBL_SUBCMDAUTO
, do_cd
,
550 "Change the current/working directory.",
554 ls
, 2, CTBL_RPT
|CTBL_SUBCMDAUTO
, do_ls
,
560 "load binary file from a dos filesystem",
561 "<d:/path/filename> <addr> [bytes [pos]]\n"
562 " - Load binary file 'path/filename' on logical drive 'd'\n"
563 " to address 'addr' from dos filesystem.\n"
564 " 'pos' gives the file position to start loading from.\n"
565 " If 'pos' is omitted, 0 is used. 'pos' requires 'bytes'.\n"
566 " 'bytes' gives the size to load. If 'bytes' is 0 or omitted,\n"
567 " the load stops on end of file."
571 "write file into a dos filesystem",
572 "<d:/path/filename> <addr> <bytes>\n"
573 " - Write file to 'path/filename' on logical drive 'd' from RAM\n"
574 " starting at address 'addr'.\n"
578 help
, CONFIG_SYS_MAXARGS
, CTBL_RPT
, do_help
,
579 "Print sub command description/usage",
581 " - print brief description of all sub commands\n"
582 "fat help command ...\n"
583 " - print detailed usage of sub cmd 'command'"
586 /* This does not use the CMD_TBL_ITEM macro as ? can't be used in symbol names */
587 {FSTR("?"), CONFIG_SYS_MAXARGS
, 1, do_help
,
589 #ifdef CONFIG_SYS_LONGHELP
591 #endif /* CONFIG_SYS_LONGHELP */
593 #ifdef CONFIG_AUTO_COMPLETE
597 /* Mark end of table */
598 CMD_TBL_END(cmd_tbl_fat
)
602 command_ret_t
do_fat(cmd_tbl_t
*cmdtp UNUSED
, uint_fast8_t flag UNUSED
, int argc UNUSED
, char * const argv
[] UNUSED
)
604 puts_P(PSTR("Huch?"));
606 return CMD_RET_USAGE
;