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