]> cloudbase.mooo.com Git - z180-stamp.git/blob - avr/cmd_fat.c
Merge branch 'cli-quote'
[z180-stamp.git] / avr / cmd_fat.c
1 #include "common.h"
2 #include <stdlib.h>
3 #include <string.h>
4 #include <stdbool.h>
5
6 #include "command.h"
7 #include "ff.h"
8 #include "z80-if.h"
9 #include "con-utils.h"
10 #include "print-utils.h"
11 #include "timer.h"
12 #include "debug.h"
13
14
15 #define MAX_MEMORY (1ul << 20)
16
17 DWORD get_fattime (void)
18 {
19 /* TODO: */
20 return 0;
21 }
22
23
24 static const FLASH char * const FLASH rc_names[] = {
25 FSTR("OK"),
26 FSTR("DISK_ERR"),
27 FSTR("INT_ERR"),
28 FSTR("NOT_READY"),
29 FSTR("NO_FILE"),
30 FSTR("NO_PATH"),
31 FSTR("INVALID_NAME"),
32 FSTR("DENIED"),
33 FSTR("EXIST"),
34 FSTR("INVALID_OBJECT"),
35 FSTR("WRITE_PROTECTED"),
36 FSTR("INVALID_DRIVE"),
37 FSTR("NOT_ENABLED"),
38 FSTR("NO_FILE_SYSTEM"),
39 FSTR("MKFS_ABORTED"),
40 FSTR("TIMEOUT"),
41 FSTR("LOCKED"),
42 FSTR("NOT_ENOUGH_CORE"),
43 FSTR("TOO_MANY_OPEN_FILES")
44 };
45
46 static
47 void put_rc (FRESULT rc)
48 {
49 #if GCC_BUG_61443
50 printf_P(PSTR("rc=%u FR_"), rc);
51 my_puts_P(rc_names[rc]);
52 my_puts_P(PSTR("\n"));
53 #else
54 printf_P(PSTR("rc=%u FR_%S\n"), rc, rc_names[rc]);
55 #endif
56 }
57
58 /* Work register for fs command */
59 static DWORD AccSize;
60 static WORD AccFiles, AccDirs;
61 #if _USE_LFN
62 char Lfname[_MAX_LFN+1];
63 FILINFO Finfo = {
64 .lfname = Lfname,
65 .lfsize = sizeof Lfname
66 };
67 #else
68 FILINFO Finfo;
69 #endif
70
71 static
72 FRESULT scan_files (
73 char* path /* Pointer to the working buffer with start path */
74 )
75 {
76 DIR dirs;
77 FRESULT res;
78 int i;
79 char *fn;
80
81 res = f_opendir(&dirs, path);
82
83 if (res == FR_OK) {
84 i = strlen(path);
85 while (((res = f_readdir(&dirs, &Finfo)) == FR_OK) && Finfo.fname[0]) {
86 if (_FS_RPATH && Finfo.fname[0] == '.') continue;
87 #if _USE_LFN
88 fn = *Finfo.lfname ? Finfo.lfname : Finfo.fname;
89 #else
90 fn = Finfo.fname;
91 #endif
92 if (Finfo.fattrib & AM_DIR) {
93 AccDirs++;
94 path[i] = '/'; strcpy(path+i+1, fn);
95 res = scan_files(path);
96 path[i] = '\0';
97 if (res != FR_OK) break;
98 } else {
99 // printf_P(PSTR("%s/%s\n"), path, fn);
100 AccFiles++;
101 AccSize += Finfo.fsize;
102 }
103 }
104 }
105
106 return res;
107 }
108
109
110 /*
111 * fatstat path - Show logical drive status
112 *
113 */
114 command_ret_t do_fat_stat(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
115 {
116 FATFS *FatFs, *fs;
117 DWORD nfreeclst;
118 FRESULT res;
119 char *buffer;
120
121 (void) cmdtp; (void) flag; (void) argc;
122
123 FatFs = (FATFS *) malloc(sizeof (FATFS));
124 buffer = (char *) malloc(512);
125 if (FatFs == NULL || buffer == NULL) {
126 printf_P(PSTR("fatstat: Out of Memory!\n"));
127 free(FatFs);
128 free(buffer);
129 return CMD_RET_FAILURE;
130 }
131
132 res = f_mount(FatFs, argv[1], 0);
133 if (!res) {
134 res = f_getfree(argv[1], &nfreeclst, &fs);
135 if (!res) {
136 printf_P(PSTR(
137 "FAT type: %u\n"
138 "Bytes/Cluster: %lu\n"
139 "Number of FATs: %u\n"
140 "Root DIR entries: %u\n"
141 "Sectors/FAT: %lu\n"
142 "Number of clusters: %lu\n"
143 "FAT start (lba): %lu\n"
144 "DIR start (lba,cluster): %lu\n"
145 "Data start (lba): %lu\n"),
146 fs->fs_type, (DWORD)fs->csize * 512, fs->n_fats,
147 fs->n_rootdir, fs->fsize, fs->n_fatent - 2,
148 fs->fatbase, fs->dirbase, fs->database);
149
150 #if _USE_LABEL
151 TCHAR label[12];
152 DWORD serial;
153 res = f_getlabel(argv[1], label, &serial);
154 if (!res) {
155 printf_P(PSTR(
156 "Volume name: %s\n"
157 "Volume S/N: %04X-%04X\n"),
158 label, (WORD)(serial >> 16), (WORD)(serial & 0xFFFF));
159 }
160 #endif
161 if (!res) {
162 my_puts_P(PSTR("\n..."));
163 AccSize = AccFiles = AccDirs = 0;
164
165 strcpy(buffer, argv[1]);
166
167 res = scan_files(buffer);
168 }
169 if (!res) {
170 printf_P(PSTR("\r%u files, %lu bytes.\n%u folders.\n"
171 "%lu KB total disk space.\n%lu KB available.\n"),
172 AccFiles, AccSize, AccDirs,
173 (fs->n_fatent - 2) * (fs->csize / 2), nfreeclst * (fs->csize / 2)
174 );
175 }
176 }
177 }
178
179 f_mount(NULL, argv[1], 0);
180 if (res) {
181 put_rc(res);
182 return CMD_RET_FAILURE;
183 }
184 return CMD_RET_SUCCESS;
185 }
186
187
188 /*
189 * fatls path - Directory listing
190 *
191 */
192 command_ret_t do_fat_ls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
193 {
194 FATFS FatFs, *fs;
195 DIR Dir; /* Directory object */
196 FILINFO Finfo;
197 unsigned long p1;
198 unsigned int s1, s2;
199 FRESULT res;
200 #if _USE_LFN
201 char Lfname[_MAX_LFN+1];
202 Finfo.lfname = Lfname;
203 Finfo.lfsize = sizeof Lfname;
204 #endif
205
206 (void) cmdtp; (void) flag; (void) argc;
207
208 res = f_mount(&FatFs, argv[1], 0);
209 if (!res)
210 res = f_opendir(&Dir, argv[1]);
211 if (res) {
212 put_rc(res);
213 return CMD_RET_FAILURE;
214 }
215
216 p1 = s1 = s2 = 0;
217 for(;;) {
218 res = f_readdir(&Dir, &Finfo);
219 if ((res != FR_OK) || !Finfo.fname[0])
220 break;
221 if (Finfo.fattrib & AM_DIR) {
222 s2++;
223 } else {
224 s1++; p1 += Finfo.fsize;
225 }
226 printf_P(PSTR("%c%c%c%c%c %u/%02u/%02u %02u:%02u %9lu %s"),
227 (Finfo.fattrib & AM_DIR) ? 'D' : '-',
228 (Finfo.fattrib & AM_RDO) ? 'R' : '-',
229 (Finfo.fattrib & AM_HID) ? 'H' : '-',
230 (Finfo.fattrib & AM_SYS) ? 'S' : '-',
231 (Finfo.fattrib & AM_ARC) ? 'A' : '-',
232 (Finfo.fdate >> 9) + 1980, (Finfo.fdate >> 5) & 15, Finfo.fdate & 31,
233 (Finfo.ftime >> 11), (Finfo.ftime >> 5) & 63,
234 Finfo.fsize, &(Finfo.fname[0]));
235 #if _USE_LFN
236 for (int i = strlen(Finfo.fname); i < 14; i++)
237 putchar(' ');
238 printf_P(PSTR("%s\n"), Lfname);
239 #else
240 putchar('\n');
241 #endif
242 }
243
244 if (res == FR_OK) {
245 printf_P(PSTR("%4u File(s),%10lu bytes total\n%4u Dir(s)"), s1, p1, s2);
246 if (f_getfree(argv[1], (DWORD*)&p1, &fs) == FR_OK)
247 printf_P(PSTR(", %10luK bytes free\n"), p1 * fs->csize / 2);
248 }
249
250 if (res) {
251 put_rc(res);
252 return CMD_RET_FAILURE;
253 }
254
255 return CMD_RET_SUCCESS;
256 }
257
258
259 /*
260 * fatread - load binary file from a dos filesystem
261 * <d:/path/filename> <addr> [bytes [pos]]
262 */
263 command_ret_t do_fat_read(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
264 {
265 FATFS FatFs;
266 FIL File;
267 unsigned long bytes = 0x80000;
268 unsigned long pos= 0;
269 unsigned long bytes_read;
270 uint32_t addr;
271 FRESULT res;
272 bool buserr = 0;
273 uint32_t timer;
274 uint8_t buffer[512];
275
276 (void) cmdtp; (void) flag;
277
278 if (argc < 3)
279 return CMD_RET_USAGE;
280
281 addr = strtoul(argv[2], 0, 16);
282 if (argc > 3)
283 bytes = strtoul(argv[3], 0, 16);
284 if (argc > 4)
285 pos = strtoul(argv[4], 0, 16);
286
287 res = f_mount(&FatFs, argv[1], 0);
288 if (!res) {
289 res = f_open(&File, argv[1], FA_READ);
290
291 if (!res) {
292 res = f_lseek(&File, pos);
293 if (!res) {
294 bytes_read = 0;
295 timer = get_timer(0);
296 while (bytes) {
297 unsigned int cnt, br;
298
299 if (bytes >= sizeof buffer) {
300 cnt = sizeof buffer;
301 bytes -= sizeof buffer;
302 } else {
303 cnt = bytes; bytes = 0;
304 }
305 res = f_read(&File, buffer, cnt, &br);
306 if (res != FR_OK)
307 break;
308 if (!(z80_bus_cmd(Request) & ZST_ACQUIRED)) {
309 buserr = 1;
310 break;
311 }
312 z80_write_block(buffer, addr, br);
313 z80_bus_cmd(Release);
314 addr += br;
315
316 bytes_read += br;
317 if (cnt != br)
318 break;
319 }
320 timer = get_timer(timer);
321 printf_P(PSTR("%lu bytes read with %lu bytes/sec.\n"),
322 bytes_read, timer ? (bytes_read * 1000 / timer) : 0);
323 }
324 }
325 f_mount(NULL, argv[1], 0);
326 }
327
328 if (buserr)
329 my_puts_P(PSTR("Bus timeout\n"));
330 if (res)
331 put_rc(res);
332 if (buserr || res)
333 return CMD_RET_FAILURE;
334
335 return CMD_RET_SUCCESS;
336 }
337
338 /*
339 * fatwrite - write file into a dos filesystem
340 * <d:/path/filename> <addr> <bytes>
341 */
342 command_ret_t do_fat_write(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
343 {
344 FATFS FatFs;
345 FIL File;
346 unsigned long bytes;
347 unsigned long bytes_written;
348 uint32_t addr;
349 FRESULT res;
350 bool buserr = 0;
351 uint32_t timer;
352 uint8_t buffer[512];
353
354 (void) cmdtp; (void) flag;
355
356 if (argc < 4)
357 return CMD_RET_USAGE;
358
359 addr = strtoul(argv[2], 0, 16);
360 bytes = strtoul(argv[3], 0, 16);
361
362 res = f_mount(&FatFs, argv[1], 0);
363 if (!res) {
364 res = f_open(&File, argv[1], FA_CREATE_ALWAYS | FA_WRITE);
365 if (!res) {
366 bytes_written = 0;
367 timer = get_timer(0);
368 while (bytes) {
369 unsigned int cnt, br;
370
371 if (bytes >= sizeof buffer) {
372 cnt = sizeof buffer;
373 bytes -= sizeof buffer;
374 } else {
375 cnt = bytes; bytes = 0;
376 }
377 if (!(z80_bus_cmd(Request) & ZST_ACQUIRED)) {
378 buserr = 1;
379 break;
380 }
381 z80_read_block(buffer, addr, cnt);
382 z80_bus_cmd(Release);
383 res = f_write(&File, buffer, cnt, &br);
384 if (res != FR_OK)
385 break;
386 addr += br;
387 bytes_written += br;
388 if (cnt != br)
389 break;
390 }
391 res = f_close(&File);
392 timer = get_timer(timer);
393 printf_P(PSTR("%lu bytes written with %lu bytes/sec.\n"),
394 bytes_written, timer ? (bytes_written * 1000 / timer) : 0);
395 }
396 f_mount(NULL, argv[1], 0);
397 }
398
399 if (buserr)
400 my_puts_P(PSTR("Bus timeout\n"));
401 if (res)
402 put_rc(res);
403 if (buserr || res)
404 return CMD_RET_FAILURE;
405
406 return CMD_RET_SUCCESS;
407 }
408
409 /*
410 * fatread/write - load binary file to/from a dos filesystem
411 * read <d:/path/filename> <addr> [bytes [pos]]
412 * write <d:/path/filename> <addr> <bytes>
413 */
414 command_ret_t do_fat_rw(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
415 {
416 FATFS FatFs;
417 FIL File;
418 uint32_t addr;
419 unsigned long bytes;
420 unsigned long pos;
421 unsigned long bytes_rw;
422
423 bool dowrite = (argv[0][3] == 'w');
424 FRESULT res;
425 bool buserr = 0;
426 uint32_t timer;
427 uint8_t buffer[512];
428
429 (void) cmdtp; (void) flag;
430
431 if (argc < (dowrite ? 4 : 3))
432 return CMD_RET_USAGE;
433
434 addr = strtoul(argv[2], 0, 16);
435 if (addr >= MAX_MEMORY) {
436 printf_P(PSTR("address too high: 0x%0lx\n"), addr);
437 return CMD_RET_FAILURE;
438 }
439 if (argc > 3)
440 bytes = strtoul(argv[3], 0, 16);
441 else
442 bytes = MAX_MEMORY;
443 if (argc > 4)
444 pos = strtoul(argv[4], 0, 16);
445 else
446 pos = 0;
447
448 if (addr + bytes > MAX_MEMORY)
449 bytes = MAX_MEMORY - addr;
450
451 res = f_mount(&FatFs, argv[1], 0);
452 if (!res) {
453 res = f_open(&File, argv[1], dowrite ? FA_WRITE | FA_CREATE_ALWAYS
454 : FA_READ );
455
456 if (!res) {
457 res = f_lseek(&File, pos);
458 if (!res) {
459 bytes_rw = 0;
460 timer = get_timer(0);
461 while (bytes) {
462 unsigned int cnt, br;
463
464 if (bytes >= sizeof buffer) {
465 cnt = sizeof buffer;
466 bytes -= sizeof buffer;
467 } else {
468 cnt = bytes; bytes = 0;
469 }
470 if (dowrite) {
471 if (!(z80_bus_cmd(Request) & ZST_ACQUIRED)) {
472 buserr = 1;
473 break;
474 }
475 z80_read_block(buffer, addr, cnt);
476 z80_bus_cmd(Release);
477 res = f_write(&File, buffer, cnt, &br);
478 if (res != FR_OK)
479 break;
480 } else {
481 res = f_read(&File, buffer, cnt, &br);
482 if (res != FR_OK)
483 break;
484 if (!(z80_bus_cmd(Request) & ZST_ACQUIRED)) {
485 buserr = 1;
486 break;
487 }
488 z80_write_block(buffer, addr, br);
489 z80_bus_cmd(Release);
490 }
491 addr += br;
492
493 bytes_rw += br;
494 if (cnt != br) {
495 if (dowrite)
496 printf_P(PSTR("Disk full?\n"));
497 break;
498 }
499 if (ctrlc()) {
500 printf_P(PSTR("Abort\n"));
501 break;
502 }
503 }
504
505 FRESULT fr = f_close(&File);
506 if (!res)
507 res = fr;
508 timer = get_timer(timer);
509 printf_P(PSTR("%lu (0x%lx) bytes read/written with %lu bytes/sec.\n"),
510 bytes_rw, bytes_rw, timer ? (bytes_rw * 1000 / timer) : 0);
511 }
512 }
513 f_mount(NULL, argv[1], 0);
514 }
515
516 if (buserr)
517 my_puts_P(PSTR("Bus timeout\n"));
518 if (res)
519 put_rc(res);
520 if (buserr || res)
521 return CMD_RET_FAILURE;
522
523 return CMD_RET_SUCCESS;
524 }