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