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