]> cloudbase.mooo.com Git - z180-stamp.git/blob - avr/cmd_fat.c
c4d17b3661159ec83696f451fc8673c210ed7645
[z180-stamp.git] / avr / cmd_fat.c
1 /*
2 * (C) Copyright 2014,2016,2018 Leo C. <erbl259-lmu@yahoo.de>
3 *
4 * SPDX-License-Identifier: GPL-2.0
5 */
6
7 /*
8 * FAT filesystem commands
9 */
10
11 #include "common.h"
12 #include "cmd_fat.h"
13 #include <time.h>
14 uint32_t fat_time(const struct tm * timeptr);
15
16 #include "ff.h"
17 #include "z80-if.h"
18 #include "eval_arg.h"
19 #include "con-utils.h"
20 #include "print-utils.h"
21 #include "timer.h"
22 #include "debug.h"
23 #include "env.h"
24 #include "getopt-min.h"
25
26 #define DEBUG_FA 0 /* set to 1 to debug */
27 #define DEBUG_LS 1 /* set to 1 to debug */
28 #define DEBUG_RM 0 /* set to 1 to debug */
29
30 #define debug_fa(fmt, args...) \
31 debug_cond(DEBUG_FA, fmt, ##args)
32 #define debug_ls(fmt, args...) \
33 debug_cond(DEBUG_LS, fmt, ##args)
34 #define debug_rm(fmt, args...) \
35 debug_cond(DEBUG_RM, fmt, ##args)
36
37
38 /* TODO: use memory size test function (z80_memsize_detect() ) */
39 #define MAX_MEMORY CONFIG_SYS_RAMSIZE_MAX
40 #define BUFFER_SIZE FF_MAX_SS
41 #define PATH_MAX CONFIG_SYS_MAX_PATHLEN
42
43
44 /*
45 * Multible (fat) partitions per physical drive are not supported,
46 * but we have up to 2 sdcard slots.
47 */
48 static FATFS FatFs0;
49 static FATFS FatFs1;
50
51 void setup_fatfs(void)
52 {
53 f_mount(&FatFs0, "0:", 0);
54 f_mount(&FatFs1, "1:", 0);
55 }
56
57 DWORD get_fattime (void)
58 {
59 time_t timer;
60 struct tm tm_timer;
61
62 time(&timer);
63 gmtime_r(&timer, &tm_timer);
64
65 return fat_time(&tm_timer);
66 }
67
68
69 static
70 bool check_abort(void)
71 {
72 bool ret = ctrlc();
73
74 if (ret)
75 printf_P(PSTR("Abort\n"));
76
77 return ret;
78 }
79
80
81 static const FLASH char * const FLASH rc_strings[] = {
82 FSTR("Success"),
83 FSTR("Disk error"),
84 FSTR("Internal error"),
85 FSTR("Not ready"),
86 FSTR("No file"),
87 FSTR("No path"),
88 FSTR("Invalid name"),
89 FSTR("Denied"),
90 FSTR("Exist"),
91 FSTR("Invalid object"),
92 FSTR("Write protected"),
93 FSTR("Invalid drive"),
94 FSTR("Not enabled"),
95 FSTR("No file system"),
96 FSTR("Mkfs aborted"),
97 FSTR("Timeout"),
98 FSTR("Locked"),
99 FSTR("Not enough core"),
100 FSTR("Too many open files"),
101 FSTR("Invalid parameter")
102 };
103
104
105 const FLASH char * fat_rctostr(FRESULT rc)
106 {
107 return rc < ARRAY_SIZE(rc_strings) ? rc_strings[rc] : PSTR(" Unknown Error");
108 }
109
110 static
111 void swirl(void)
112 {
113 static const FLASH char swirlchar[] = { '-','\\','|','/' };
114 static uint_fast8_t cnt;
115 static uint32_t tstamp;
116
117 if (get_timer(0) > tstamp) {
118 tstamp = get_timer(0) + 250;
119 putchar('\b');
120 cnt = (cnt+1) & 3;
121 putchar(swirlchar[cnt]);
122 }
123 }
124
125 /*
126 * pwd - Print current directory of the current drive.
127 *
128 */
129 command_ret_t do_pwd(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc UNUSED, char * const argv[] UNUSED)
130 {
131 FRESULT res;
132 TCHAR buf[PATH_MAX];
133
134 res = f_getcwd(buf, PATH_MAX); /* Get current directory path */
135
136 if (res != FR_OK)
137 cmd_error(CMD_RET_FAILURE, res, NULL);
138
139 puts(buf);
140
141 return CMD_RET_SUCCESS;
142 }
143
144
145 /*
146 * cd - Change the current/working directory.
147 *
148 */
149 command_ret_t do_cd(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc, char * const argv[])
150 {
151 TCHAR *path;
152 FRESULT res = FR_OK;
153
154 if (argc < 2) {
155 path = getenv_str(PSTR(ENV_HOME));
156 if (path == NULL) {
157 cmd_error(CMD_RET_FAILURE, 0, PSTR("\"%S\" not set"), PSTR(ENV_HOME));
158 }
159 } else
160 path = argv[1];
161
162 if (strlen(path) > 1 && path[1] == ':')
163 res = f_chdrive(path);
164
165 if (res == FR_OK)
166 res = f_chdir(path);
167
168 if (res != FR_OK)
169 cmd_error(CMD_RET_FAILURE, res, NULL);
170
171 return CMD_RET_SUCCESS;
172 }
173
174
175 static
176 void print_dirent(FILINFO *f)
177 {
178 printf_P(PSTR("%c%c%c%c%c %u/%02u/%02u %02u:%02u %9lu %s\n"),
179 (f->fattrib & AM_DIR) ? 'D' : '-',
180 (f->fattrib & AM_RDO) ? 'R' : '-',
181 (f->fattrib & AM_HID) ? 'H' : '-',
182 (f->fattrib & AM_SYS) ? 'S' : '-',
183 (f->fattrib & AM_ARC) ? 'A' : '-',
184 (f->fdate >> 9) + 1980, (f->fdate >> 5) & 15, f->fdate & 31,
185 (f->ftime >> 11), (f->ftime >> 5) & 63,
186 f->fsize, f->fname);
187 }
188
189 char *path_split(char *p)
190 {
191 if (isdigit(p[0]) && (p[1] == ':'))
192 p += 2;
193
194 char *ps = strrchr(p, '/');
195 if (ps) {
196 if (ps == p) {
197 ++ps;
198 memmove(ps+1, ps, strlen(ps)+1);
199 }
200 *ps++ = '\0';
201 }
202
203 return ps;
204 }
205
206 command_ret_t do_mkdir(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc, char * const argv[])
207 {
208 int ret = CMD_RET_SUCCESS;
209 FRESULT res;
210
211 if (argc < 1)
212 return CMD_RET_USAGE;
213
214 for (uint8_t i = 1; i < argc; i++) {
215 if ((res = f_mkdir(argv[i])) != FR_OK) {
216 ret = CMD_RET_FAILURE;
217 cmd_error(0, res, PSTR("cannot create directory '%s'"), argv[i]);
218 }
219 }
220 return ret;
221 }
222
223 /*
224 * ls path - Directory listing
225 *
226 */
227 command_ret_t do_ls(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc, char * const argv[])
228 {
229 FATFS *fs;
230 DIR dir; /* Directory object */
231 FILINFO finfo;
232 unsigned long p1;
233 unsigned int s1, s2;
234 FRESULT res = FR_OK;
235 char buf[PATH_MAX];
236 char *path = buf;
237 char *pattern;
238
239
240 memset(buf, 0, PATH_MAX);
241 if (argc < 2) {
242 buf[0] = '.';
243 } else {
244 strncpy(path, argv[1], PATH_MAX-1);
245 }
246 pattern = path_split(path);
247 debug_ls("### path, pattern: '%s', '%s'\n", path[0] ? path : "<NULL>", pattern ? pattern : "<NULL>");
248
249 if (pattern == NULL) {
250 res = f_opendir(&dir, path);
251 if (res == FR_NO_PATH || res == FR_INVALID_NAME) {
252 pattern = path;
253 path = ".";
254 } else if (res != FR_OK) {
255 cmd_error(CMD_RET_FAILURE, res, PSTR("'%s'"), path);
256 }
257 }
258 debug_ls("### path, pattern: '%s', '%s'\n", path, pattern ? pattern : "<NULL>");
259
260 if (pattern == NULL || *pattern == '\0')
261 pattern = "*";
262
263 debug_ls("### path, pattern: '%s', '%s'\n", path, pattern ? pattern : "<NULL>");
264
265 res = f_findfirst(&dir, &finfo, path, pattern);
266
267 p1 = s1 = s2 = 0;
268 for(;;) {
269 if (res != FR_OK)
270 cmd_error(CMD_RET_FAILURE, res, NULL);
271 if (!finfo.fname[0])
272 break;
273 if (finfo.fattrib & AM_DIR) {
274 s2++;
275 } else {
276 s1++; p1 += finfo.fsize;
277 }
278 print_dirent(&finfo);
279 if (check_abort())
280 break;
281 res = f_findnext(&dir, &finfo);
282 }
283
284 if (res == FR_OK) {
285 printf_P(PSTR("%4u File(s),%10lu bytes total\n%4u Dir(s)"), s1, p1, s2);
286 if (f_getfree(path, (DWORD*)&p1, &fs) == FR_OK)
287 printf_P(PSTR(", %10luK bytes free\n"), p1 * fs->csize / 2);
288 }
289
290 if (res)
291 cmd_error(CMD_RET_FAILURE, res, NULL);
292
293 return CMD_RET_SUCCESS;
294 }
295
296 typedef FRESULT (*fatfunc_t)(const TCHAR* path_old, const TCHAR* path_new);
297
298 uint8_t cmd_flags;
299 #define I_FLAG (1<<1) // prompt before overwrite (overrides a previous -n option)
300 #define N_FLAG (1<<2) // do not overwrite an existing file (overrides a previous -i option)
301 #define F_FLAG (1<<3) // overwrite existing file ignoring write protection
302 #define P_FLAG (1<<4) // preserve attributes and timestamps
303 #define V_FLAG (1<<5) // explain what is being done
304
305 char* splitpath(const char* path)
306 {
307 char* fs = strrchr(path, '/');
308 char* bs = strrchr(path, '\\');
309 if (fs > bs) {
310 *fs = '\0';
311 return fs + 1;
312 } else if (bs != NULL) {
313 *bs = '\0';
314 return bs + 1;
315 }
316 return NULL;
317 }
318
319 FRESULT ff_remove(const TCHAR *file, const TCHAR *dest UNUSED)
320 {
321 FRESULT res = FR_OK;
322
323 debug_rm("==== ff_remove: '%s'\n", file);
324
325 if (!(cmd_flags & N_FLAG)) {
326 if ((res = f_unlink(file)) == FR_OK) {
327 if (cmd_flags & V_FLAG)
328 printf_P(PSTR("removed '%s'\n"), file);
329 } else {
330 cmd_error(0, res, PSTR("cannot remove '%s'"), file);
331 }
332 } else {
333 printf_P(PSTR("not removed '%s'\n"), file);
334 }
335
336 return res;
337 }
338
339 void ff_iterate(fatfunc_t fatfunc, int count, char* const file[], char* dest)
340 {
341 FRESULT res = 0;
342 DIR dir;
343 FILINFO finfo;
344 char srcpath[PATH_MAX], destpath[PATH_MAX];
345
346 uint8_t dest_is_dir = dest != NULL && f_stat(dest, &finfo) == FR_OK && finfo.fattrib & AM_DIR;
347 for (uint8_t i = 0; i < count; i++) {
348 char* pattern = NULL;
349 strcpy(srcpath, file[i]);
350 char* p1 = path_split(srcpath);
351
352 if (p1 != NULL) {
353 pattern = (char *) malloc(strlen(p1)+1);
354 strcpy(pattern, p1);
355 }
356
357 debug_rm("### iter1 srcpath, pattern: '%s', '%s'\n", srcpath, pattern ? pattern : "<NULL>");
358
359 if (pattern != NULL) {
360 res = f_findfirst(&dir, &finfo, srcpath, pattern);
361 p1 = srcpath+strlen(srcpath)-1;
362 if (*p1++ != '/')
363 *(p1++) = '/';
364 } else {
365 res = f_findfirst(&dir, &finfo, ".", file[i]);
366 p1 = srcpath;
367 }
368 if (finfo.fname[0] == 0)
369 cmd_error(0, res, PSTR("cannot remove '%s': no such file or directory"), file[i]);
370
371
372 while (res == FR_OK && finfo.fname[0] != 0) {
373 strcpy(p1, finfo.fname);
374
375 debug_rm("### iter3 srcpath: '%s'\n", srcpath);
376
377 if (dest != NULL) {
378 strcpy(destpath, dest);
379 if (dest_is_dir) {
380 strcat_P(destpath, PSTR("/"));
381 strcat(destpath, finfo.fname);
382 }
383 }
384 fatfunc(srcpath, destpath);
385 res = f_findnext(&dir, &finfo);
386 debug_rm("### iter4 res, .fname: %d, '%s'\n", res, finfo.fname);
387
388 }
389 res = f_closedir(&dir);
390 free(pattern);
391 }
392 if (res != FR_OK)
393 cmd_error(CMD_RET_FAILURE, res, PSTR("error enumerating files"));
394 //printf_P(PSTR("error enumerating files: %S\n"), ffw_error(res));
395 }
396
397 command_ret_t do_rm(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc, char * const argv[])
398 {
399
400 cmd_flags = 0;
401 int opt;
402 while ((opt = getopt(argc, argv, PSTR("nv"))) != -1) {
403 switch (opt) {
404 case 'n':
405 cmd_flags |= N_FLAG;
406 break;
407 case 'v':
408 cmd_flags |= V_FLAG;
409 break;
410 default:
411 return CMD_RET_USAGE;
412 break;
413 }
414 }
415 argc -= optind;
416 argv += optind;
417
418 debug_rm("==== do_rm: argc, argv[0]: %d, '%s'\n", argc, argv[0]);
419
420 if (argc < 1)
421 return CMD_RET_USAGE;
422
423 ff_iterate(ff_remove, argc, argv, NULL);
424
425 return CMD_RET_SUCCESS;
426 }
427
428 /*
429 * tst path - for debugging: test access with different functions
430 *
431 */
432 command_ret_t do_tst(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc, char * const argv[])
433 {
434 DIR Dir; /* Directory object */
435 FILINFO finfo;
436 FRESULT res = FR_OK;
437 char *path = "";
438 char *pattern = "*";
439
440 printf_P(PSTR("sizeof DIR: %u, sizeof FIL: %u\n"), sizeof (DIR), sizeof (FILINFO));
441
442 char * buf = (char *) malloc(BUFFER_SIZE);
443 if (buf == NULL) {
444 cmd_error(CMD_RET_FAILURE, ENOMEM, NULL);
445 }
446 res = f_getcwd(buf, BUFFER_SIZE); /* Get current directory path */
447
448 if (!res) {
449 printf_P(PSTR("cwd: '%s'\n"), buf);
450 }
451 free(buf);
452 if (res)
453 cmd_error(CMD_RET_FAILURE, res, NULL);
454
455 if (argc > 1)
456 path = argv[1];
457 if (argc > 2)
458 pattern = argv[2];
459
460 printf_P(PSTR("arg: '%s' '%s'\n"), path, pattern);
461 printf_P(PSTR("==== f_stat: "));
462 res = f_stat(path, &finfo);
463 cmd_error(0, res, NULL);
464 if (res == FR_OK) {
465 print_dirent(&finfo);
466 }
467
468 printf_P(PSTR("==== f_findfirst: "));
469 res = f_findfirst(&Dir, &finfo, path, pattern); /* Start to search for files */
470 cmd_error(CMD_RET_FAILURE, res, NULL);
471 if (res == FR_OK) {
472 print_dirent(&finfo);
473 }
474 f_closedir(&Dir);
475
476 printf_P(PSTR("==== f_opendir: "));
477 res = f_opendir(&Dir, path);
478 cmd_error(CMD_RET_FAILURE, res, NULL);
479 f_closedir(&Dir);
480
481 return CMD_RET_SUCCESS;
482 }
483
484 /* Work register for fs command */
485 struct stat_dat_s {
486 DWORD AccSize;
487 WORD AccFiles, AccDirs;
488 FILINFO finfo;
489 };
490
491 static
492 FRESULT scan_files (
493 char *path, /* Pointer to the working buffer with start path */
494 struct stat_dat_s *statp
495 )
496 {
497 DIR dirs;
498 FRESULT res;
499 int i;
500 char *fn;
501
502 res = f_opendir(&dirs, path);
503 swirl();
504 if (res == FR_OK) {
505 i = strlen(path);
506 while (((res = f_readdir(&dirs, &statp->finfo)) == FR_OK) &&
507 statp->finfo.fname[0]) {
508 if (FF_FS_RPATH && statp->finfo.fname[0] == '.')
509 continue;
510 fn = statp->finfo.fname;
511 if (statp->finfo.fattrib & AM_DIR) {
512 statp->AccDirs++;
513 path[i] = '/';
514 strcpy(path+i+1, fn);
515 res = scan_files(path, statp);
516 path[i] = '\0';
517 if (res != FR_OK)
518 break;
519 } else {
520 //printf_P(PSTR("%s/%s\n"), path, fn);
521 statp->AccFiles++;
522 statp->AccSize += statp->finfo.fsize;
523 }
524 if (check_abort()) {
525 res = 255;
526 break;
527 }
528 }
529 }
530
531 return res;
532 }
533
534
535 /*
536 * fatstat path - Show logical drive status
537 *
538 */
539 command_ret_t do_stat(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc, char * const argv[])
540 {
541 FATFS *fs;
542 DWORD nfreeclst;
543 FRESULT res;
544 char *buf;
545 char *path = "";
546 struct stat_dat_s statp;
547
548 buf = (char *) malloc(PATH_MAX);
549 if (buf == NULL)
550 cmd_error(CMD_RET_FAILURE, ENOMEM, NULL);
551
552 if (argc > 1)
553 path = argv[1];
554 res = f_getfree(path, &nfreeclst, &fs);
555 if (!res) {
556 printf_P(PSTR(
557 "FAT type: %u\n"
558 "Bytes/Cluster: %lu\n"
559 "Number of FATs: %u\n"
560 "Root DIR entries: %u\n"
561 "Sectors/FAT: %lu\n"
562 "Number of clusters: %lu\n"
563 "FAT start (lba): %lu\n"
564 "DIR start (lba,cluster): %lu\n"
565 "Data start (lba): %lu\n"),
566 fs->fs_type, (DWORD)fs->csize * 512, fs->n_fats,
567 fs->n_rootdir, fs->fsize, fs->n_fatent - 2,
568 fs->fatbase, fs->dirbase, fs->database);
569
570 #if FF_USE_LABEL
571 DWORD serial;
572 res = f_getlabel(path, buf, &serial);
573 if (!res) {
574 printf_P(PSTR(
575 "Volume name: %s\n"
576 "Volume S/N: %04X-%04X\n"),
577 buf, (WORD)(serial >> 16), (WORD)(serial & 0xFFFF));
578 }
579 #endif
580 if (!res) {
581 statp.AccSize = statp.AccFiles = statp.AccDirs = 0;
582 strcpy(buf, path);
583
584 my_puts_P(PSTR("\nCounting... "));
585 res = scan_files(buf, &statp);
586 putchar('\r');
587 }
588 if (!res) {
589 printf_P(PSTR("%u files, %lu bytes.\n%u folders.\n"
590 "%lu KB total disk space.\n%lu KB available.\n"),
591 statp.AccFiles, statp.AccSize, statp.AccDirs,
592 (fs->n_fatent - 2) * (fs->csize / 2), nfreeclst * (fs->csize / 2)
593 );
594 }
595 }
596
597 free(buf);
598 if (res)
599 cmd_error(CMD_RET_FAILURE, res, NULL);
600
601 return CMD_RET_SUCCESS;
602 }
603
604 /*
605 * fatread/write - load binary file to/from a dos filesystem
606 * read <d:/path/filename> <addr> [bytes [pos]]
607 * write <d:/path/filename> <addr> <bytes>
608 */
609 command_ret_t do_rw(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc, char * const argv[])
610 {
611 FIL File;
612 uint32_t addr;
613 unsigned long bytes;
614 unsigned long pos;
615 unsigned long bytes_rw;
616
617 bool dowrite = (argv[0][0] == 'w');
618 FRESULT res = FR_OK;
619 bool buserr = 0;
620 uint32_t timer;
621 uint8_t *buffer;
622
623 if (argc < (dowrite ? 4 : 3))
624 return CMD_RET_USAGE;
625
626 addr = eval_arg(argv[2], NULL);
627 if (addr >= MAX_MEMORY)
628 cmd_error(CMD_RET_FAILURE, 0, PSTR("Address too high: %#lx"), addr);
629
630 if (argc > 3)
631 bytes = eval_arg(argv[3], NULL);
632 else
633 bytes = MAX_MEMORY;
634 if (argc > 4)
635 pos = eval_arg(argv[4], NULL);
636 else
637 pos = 0;
638
639 if (addr + bytes > MAX_MEMORY)
640 bytes = MAX_MEMORY - addr;
641
642 buffer = (uint8_t *) malloc(BUFFER_SIZE);
643 if (buffer == NULL)
644 cmd_error(CMD_RET_FAILURE, ENOMEM, NULL);
645
646 res = f_open(&File, argv[1], dowrite ? FA_WRITE | FA_CREATE_ALWAYS
647 : FA_READ );
648
649 if (!res) {
650 res = f_lseek(&File, pos);
651 if (!res) {
652 bytes_rw = 0;
653 timer = get_timer(0);
654 while (bytes) {
655 unsigned int cnt, br;
656
657 if (bytes >= BUFFER_SIZE) {
658 cnt = BUFFER_SIZE;
659 bytes -= BUFFER_SIZE;
660 } else {
661 cnt = bytes; bytes = 0;
662 }
663 if (dowrite) {
664 if (!(z80_bus_cmd(Request) & ZST_ACQUIRED)) {
665 buserr = 1;
666 break;
667 }
668 z80_read_block(buffer, addr, cnt);
669 z80_bus_cmd(Release);
670 res = f_write(&File, buffer, cnt, &br);
671 if (res != FR_OK)
672 break;
673 } else {
674 res = f_read(&File, buffer, cnt, &br);
675 if (res != FR_OK)
676 break;
677 if (!(z80_bus_cmd(Request) & ZST_ACQUIRED)) {
678 buserr = 1;
679 break;
680 }
681 z80_write_block(buffer, addr, br);
682 z80_bus_cmd(Release);
683 }
684 addr += br;
685
686 bytes_rw += br;
687 if (cnt != br) {
688 if (dowrite)
689 printf_P(PSTR("Disk full?\n"));
690 break;
691 }
692 if (check_abort())
693 break;
694 }
695
696 FRESULT fr = f_close(&File);
697 if (!res)
698 res = fr;
699 timer = get_timer(timer);
700 printf_P(PSTR("%lu (%#lx) bytes read/written with %lu bytes/sec.\n"),
701 bytes_rw, bytes_rw, timer ? (bytes_rw * 1000 / timer) : 0);
702 }
703 }
704
705 free(buffer);
706
707 if (res)
708 cmd_error(CMD_RET_FAILURE, res, PSTR("'%s'"), argv[1]);
709 if (buserr)
710 cmd_error(CMD_RET_FAILURE, EBUSTO, NULL);
711
712 return CMD_RET_SUCCESS;
713 }
714
715 /*
716 * command table for fat subcommands
717 */
718
719 cmd_tbl_t cmd_tbl_fat[] = {
720 CMD_TBL_ITEM(
721 status, 2, CTBL_RPT, do_stat,
722 "Show logical drive status",
723 "dev"
724 ),
725 CMD_TBL_ITEM(
726 pwd, 2, CTBL_RPT|CTBL_SUBCMDAUTO, do_pwd,
727 "Print name of current/working directory",
728 ""
729 ),
730 CMD_TBL_ITEM(
731 cd, 2, 0|CTBL_SUBCMDAUTO, do_cd,
732 "Change the current/working directory.",
733 "path"
734 ),
735 CMD_TBL_ITEM(
736 mkdir, CONFIG_SYS_MAXARGS, 0, do_mkdir,
737 "Create the DIRECTORY(ies), if they do not already exist.",
738 "DIRECTORY..."
739 ),
740 CMD_TBL_ITEM(
741 ls, 2, CTBL_RPT|CTBL_SUBCMDAUTO, do_ls,
742 "Directory listing",
743 "path"
744 ),
745 CMD_TBL_ITEM(
746 tst, 3, CTBL_DBG|CTBL_RPT, do_tst,
747 "FatFS test function",
748 "[path [pattern]]"
749 ),
750 CMD_TBL_ITEM(
751 rm, CONFIG_SYS_MAXARGS, 0, do_rm,
752 "Remove FILE(s)",
753 "[OPTION]... [FILE]...\n"
754 //" -i prompt before removal\n"
755 " -v explain what is being done\n"
756 "\n"
757 "rm removes directories, if they are empty."
758 ),
759 CMD_TBL_ITEM(
760 load, 5, 0, do_rw,
761 "load binary file from a dos filesystem",
762 "<d:/path/filename> <addr> [bytes [pos]]\n"
763 " - Load binary file 'path/filename' on logical drive 'd'\n"
764 " to address 'addr' from dos filesystem.\n"
765 " 'pos' gives the file position to start loading from.\n"
766 " If 'pos' is omitted, 0 is used. 'pos' requires 'bytes'.\n"
767 " 'bytes' gives the size to load. If 'bytes' is 0 or omitted,\n"
768 " the load stops on end of file."
769 ),
770 CMD_TBL_ITEM(
771 write, 4, 0, do_rw,
772 "write file into a dos filesystem",
773 "<d:/path/filename> <addr> <bytes>\n"
774 " - Write file to 'path/filename' on logical drive 'd' from RAM\n"
775 " starting at address 'addr'.\n"
776 ),
777
778 CMD_TBL_ITEM(
779 help, CONFIG_SYS_MAXARGS, CTBL_RPT, do_help,
780 "Print sub command description/usage",
781 "\n"
782 " - print brief description of all sub commands\n"
783 "fat help command ...\n"
784 " - print detailed usage of sub cmd 'command'"
785 ),
786
787 /* This does not use the CMD_TBL_ITEM macro as ? can't be used in symbol names */
788 {FSTR("?"), CONFIG_SYS_MAXARGS, 1, do_help,
789 NULL,
790 #ifdef CONFIG_SYS_LONGHELP
791 FSTR(""),
792 #endif /* CONFIG_SYS_LONGHELP */
793 NULL,
794 #ifdef CONFIG_AUTO_COMPLETE
795 NULL,
796 #endif
797 },
798 /* Mark end of table */
799 CMD_TBL_END(cmd_tbl_fat)
800 };
801
802
803 command_ret_t do_fat(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc UNUSED, char * const argv[] UNUSED)
804 {
805 puts_P(PSTR("Huch?"));
806
807 return CMD_RET_USAGE;
808 }