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