]> git.donarmstrong.com Git - qmk_firmware.git/blob - tmk_core/protocol/usb_hid/USB_Host_Shield_2.0/examples/testusbhostFAT/testusbhostFAT.ino
Merge commit 'f6d56675f9f981c5464f0ca7a1fbb0162154e8c5'
[qmk_firmware.git] / tmk_core / protocol / usb_hid / USB_Host_Shield_2.0 / examples / testusbhostFAT / testusbhostFAT.ino
1 /*
2  * Mega + USB storage + optional DS1307 + optional expansion RAM + funky status LED,
3  * Includes interactive debug level setting, and supports hot-plug.
4  *
5  * IMPORTANT! PLEASE USE Arduino 1.0.5 or better!
6  * Older versions HAVE MAJOR BUGS AND WILL NOT WORK AT ALL!
7  * Use of gcc-avr and lib-c that is newer than the Arduino version is even better.
8  * If you experience random crashes, use make.
9  * The options that the IDE use can generate bad code and cause the AVR to crash.
10  *
11  * This sketch requires the following libraries:
12  * https://github.com/felis/USB_Host_Shield_2.0 Install as 'USB_Host_Shield_2_0'
13  * https://github.com/xxxajk/xmem2 Install as 'xmem', provides memory services.
14  * https://github.com/xxxajk/generic_storage provides access to FAT file system.
15  * https://github.com/xxxajk/RTClib provides access to DS1307, or fake clock.
16  *
17  * Optional, to use the Makefile (Recommended! See above!):
18  * https://github.com/xxxajk/Arduino_Makefile_master
19  *
20  */
21
22 /////////////////////////////////////////////////////////////
23 // Please Note:                                            //
24 // This section is for info with the Arduino IDE ONLY.     //
25 // Unfortunately due to short sightedness of the Arduino   //
26 // code team, that you must set the following in the       //
27 // respective libraries.                                   //
28 // Changing them here will have _NO_ effect!               //
29 /////////////////////////////////////////////////////////////
30
31 // Uncomment to enable debugging
32 //#define DEBUG_USB_HOST
33 // This is where stderr/USB debugging goes to
34 //#define USB_HOST_SERIAL Serial3
35
36 // If you have external memory, setting this to 0 enables FAT table caches.
37 // The 0 setting is recommended only if you have external memory.
38 //#define _FS_TINY 1
39
40 //#define _USE_LFN 3
41 //#define _MAX_SS 512
42
43
44 /////////////////////////////////////////////////////////////
45 // End of Arduino IDE specific information                 //
46 /////////////////////////////////////////////////////////////
47
48 // You can set this to 0 if you are not using a USB hub.
49 // It will save a little bit of flash and RAM.
50 // Set to 1 if you want to use a hub.
51 #define WANT_HUB_TEST 1
52
53 // this is for XMEM2
54 #define EXT_RAM_STACK 1
55 #define EXT_RAM_HEAP 1
56 #define LOAD_XMEM
57
58 #if defined(CORE_TEENSY) && !defined(_AVR_)
59 #include <xmem.h>
60 #include <spi4teensy3.h>
61 #endif
62
63 #if defined(__AVR__)
64 #include <xmem.h>
65 #include <SPI.h>
66 #elif defined(ARDUINO_ARCH_SAM)
67 #include <SPI.h>
68 #endif
69
70 #if WANT_HUB_TEST
71 #include <usbhub.h>
72 #endif
73 #include <Wire.h>
74 #define LOAD_RTCLIB
75 #include <RTClib.h>
76 #include <masstorage.h>
77 #include <Storage.h>
78 #include <PCpartition/PCPartition.h>
79 #include <avr/interrupt.h>
80 #include <FAT/FAT.h>
81 #include <stdio.h>
82 #if defined(__AVR__)
83 static FILE tty_stdio;
84 static FILE tty_stderr;
85 volatile uint32_t LEDnext_time; // fade timeout
86 volatile uint32_t HEAPnext_time; // when to print out next heap report
87 volatile int brightness = 0; // how bright the LED is
88 volatile int fadeAmount = 80; // how many points to fade the LED by
89 #endif
90
91 USB Usb;
92
93 volatile uint8_t current_state = 1;
94 volatile uint8_t last_state = 0;
95 volatile bool fatready = false;
96 volatile bool partsready = false;
97 volatile bool notified = false;
98 volatile bool runtest = false;
99 volatile bool usbon = false;
100 volatile uint32_t usbon_time;
101 volatile bool change = false;
102 volatile bool reportlvl = false;
103 int cpart = 0;
104 PCPartition *PT;
105
106 #if WANT_HUB_TEST
107 #define MAX_HUBS 1
108 USBHub *Hubs[MAX_HUBS];
109 #endif
110
111 static PFAT *Fats[_VOLUMES];
112 static part_t parts[_VOLUMES];
113 static storage_t sto[_VOLUMES];
114
115 /*make sure this is a power of two. */
116 #define mbxs 128
117 static uint8_t My_Buff_x[mbxs]; /* File read buffer */
118
119 #if defined(__AVR__)
120
121 #define prescale1       ((1 << WGM12) | (1 << CS10))
122 #define prescale8       ((1 << WGM12) | (1 << CS11))
123 #define prescale64      ((1 << WGM12) | (1 << CS10) | (1 << CS11))
124 #define prescale256     ((1 << WGM12) | (1 << CS12))
125 #define prescale1024    ((1 << WGM12) | (1 << CS12) | (1 << CS10))
126
127 extern "C" {
128          extern unsigned int freeHeap();
129 }
130 static int tty_stderr_putc(char c, FILE *t) {
131         USB_HOST_SERIAL.write(c);
132         return 0;
133 }
134
135 static int __attribute__((unused)) tty_stderr_flush(FILE *t) {
136         USB_HOST_SERIAL.flush();
137         return 0;
138 }
139
140 static int tty_std_putc(char c, FILE *t) {
141         Serial.write(c);
142         return 0;
143 }
144
145 static int tty_std_getc(FILE *t) {
146         while(!Serial.available());
147         return Serial.read();
148 }
149
150 static int __attribute__((unused)) tty_std_flush(FILE *t) {
151         Serial.flush();
152         return 0;
153 }
154
155 #else
156 // Supposedly the DUE has stdio already pointing to serial...
157 #if !defined(ARDUINO_ARCH_SAM)
158 // But newlib needs this...
159 extern "C" {
160         int _write(int fd, const char *ptr, int len) {
161                 int j;
162                 for(j = 0; j < len; j++) {
163                         if(fd == 1)
164                                 Serial.write(*ptr++);
165                         else if(fd == 2)
166                                 USB_HOST_SERIAL.write(*ptr++);
167                 }
168                 return len;
169         }
170
171         int _read(int fd, char *ptr, int len) {
172                 if(len > 0 && fd == 0) {
173                         while(!Serial.available());
174                         *ptr = Serial.read();
175                         return 1;
176                 }
177                 return 0;
178         }
179
180 #include <sys/stat.h>
181
182         int _fstat(int fd, struct stat *st) {
183                 memset(st, 0, sizeof (*st));
184                 st->st_mode = S_IFCHR;
185                 st->st_blksize = 1024;
186                 return 0;
187         }
188
189         int _isatty(int fd) {
190                 return (fd < 3) ? 1 : 0;
191         }
192 }
193 #endif // !defined(ARDUINO_ARCH_SAM)
194 #endif
195
196 void setup() {
197         bool serr = false;
198         for(int i = 0; i < _VOLUMES; i++) {
199                 Fats[i] = NULL;
200                 sto[i].private_data = new pvt_t;
201                 ((pvt_t *)sto[i].private_data)->B = 255; // impossible
202         }
203         // Set this to higher values to enable more debug information
204         // minimum 0x00, maximum 0xff
205         UsbDEBUGlvl = 0x81;
206
207 #if !defined(CORE_TEENSY) && defined(__AVR__)
208         // make LED pin as an output:
209         pinMode(LED_BUILTIN, OUTPUT);
210         pinMode(2, OUTPUT);
211         // Ensure TX is off
212         _SFR_BYTE(UCSR0B) &= ~_BV(TXEN0);
213         // Initialize 'debug' serial port
214         USB_HOST_SERIAL.begin(115200);
215         // Do not start primary Serial port if already started.
216         if(bit_is_clear(UCSR0B, TXEN0)) {
217                 Serial.begin(115200);
218                 serr = true;
219         }
220
221
222         // Blink LED
223         delay(500);
224         analogWrite(LED_BUILTIN, 255);
225         delay(500);
226         analogWrite(LED_BUILTIN, 0);
227         delay(500);
228 #else
229         while(!Serial);
230         Serial.begin(115200); // On the Teensy 3.x we get a delay at least!
231 #endif
232 #if defined(__AVR__)
233         // Set up stdio/stderr
234         tty_stdio.put = tty_std_putc;
235         tty_stdio.get = tty_std_getc;
236         tty_stdio.flags = _FDEV_SETUP_RW;
237         tty_stdio.udata = 0;
238
239         tty_stderr.put = tty_stderr_putc;
240         tty_stderr.get = NULL;
241         tty_stderr.flags = _FDEV_SETUP_WRITE;
242         tty_stderr.udata = 0;
243
244         stdout = &tty_stdio;
245         stdin = &tty_stdio;
246         stderr = &tty_stderr;
247 #endif
248         printf_P(PSTR("\r\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nStart\r\n"));
249         printf_P(PSTR("Current UsbDEBUGlvl %02x\r\n"), UsbDEBUGlvl);
250         printf_P(PSTR("'+' and '-' increase/decrease by 0x01\r\n"));
251         printf_P(PSTR("'.' and ',' increase/decrease by 0x10\r\n"));
252         printf_P(PSTR("'t' will run a 10MB write/read test and print out the time it took.\r\n"));
253         printf_P(PSTR("'e' will toggle vbus off for a few moments.\r\n\r\n"));
254         printf_P(PSTR("Long filename support: "
255 #if _USE_LFN
256                 "Enabled"
257 #else
258                 "Disabled"
259 #endif
260                 "\r\n"));
261         if(serr) {
262                 fprintf_P(stderr, PSTR("\r\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nStart\r\n"));
263                 fprintf_P(stderr, PSTR("Current UsbDEBUGlvl %02x\r\n"), UsbDEBUGlvl);
264                 fprintf_P(stderr, PSTR("Long filename support: "
265 #if _USE_LFN
266                         "Enabled"
267 #else
268                         "Disabled"
269 #endif
270                         "\r\n"));
271         }
272
273 #if !defined(CORE_TEENSY) && defined(__AVR__)
274         analogWrite(LED_BUILTIN, 255);
275         delay(500);
276         analogWrite(LED_BUILTIN, 0);
277         delay(500);
278         analogWrite(LED_BUILTIN, 255);
279         delay(500);
280         analogWrite(LED_BUILTIN, 0);
281         delay(500);
282         analogWrite(LED_BUILTIN, 255);
283         delay(500);
284         analogWrite(LED_BUILTIN, 0);
285         delay(500);
286
287         LEDnext_time = millis() + 1;
288 #if EXT_RAM
289         printf_P(PSTR("Total EXT RAM banks %i\r\n"), xmem::getTotalBanks());
290 #endif
291         printf_P(PSTR("Available heap: %u Bytes\r\n"), freeHeap());
292         printf_P(PSTR("SP %x\r\n"), (uint8_t *)(SP));
293 #endif
294
295         // Even though I'm not going to actually be deleting,
296         // I want to be able to have slightly more control.
297         // Besides, it is easier to initialize stuff...
298 #if WANT_HUB_TEST
299         for(int i = 0; i < MAX_HUBS; i++) {
300                 Hubs[i] = new USBHub(&Usb);
301 #if defined(__AVR__)
302                 printf_P(PSTR("Available heap: %u Bytes\r\n"), freeHeap());
303 #endif
304         }
305 #endif
306         // Initialize generic storage. This must be done before USB starts.
307         Init_Generic_Storage();
308
309         while(Usb.Init(1000) == -1) {
310                 printf_P(PSTR("No USB HOST Shield?\r\n"));
311                 Notify(PSTR("OSC did not start."), 0x40);
312         }
313
314 #if !defined(CORE_TEENSY) && defined(__AVR__)
315         cli();
316         TCCR3A = 0;
317         TCCR3B = 0;
318         // (0.01/(1/((16 *(10^6)) / 8))) - 1 = 19999
319         OCR3A = 19999;
320         TCCR3B |= prescale8;
321         TIMSK3 |= (1 << OCIE1A);
322         sei();
323
324         HEAPnext_time = millis() + 10000;
325 #endif
326 #if defined(__AVR__)
327         HEAPnext_time = millis() + 10000;
328 #endif
329 }
330
331 void serialEvent() {
332         // Adjust UsbDEBUGlvl level on-the-fly.
333         // + to increase, - to decrease, * to display current level.
334         // . to increase by 16, , to decrease by 16
335         // e to flick VBUS
336         // * to report debug level
337         if(Serial.available()) {
338                 int inByte = Serial.read();
339                 switch(inByte) {
340                         case '+':
341                                 if(UsbDEBUGlvl < 0xff) UsbDEBUGlvl++;
342                                 reportlvl = true;
343                                 break;
344                         case '-':
345                                 if(UsbDEBUGlvl > 0x00) UsbDEBUGlvl--;
346                                 reportlvl = true;
347                                 break;
348                         case '.':
349                                 if(UsbDEBUGlvl < 0xf0) UsbDEBUGlvl += 16;
350                                 reportlvl = true;
351                                 break;
352                         case ',':
353                                 if(UsbDEBUGlvl > 0x0f) UsbDEBUGlvl -= 16;
354                                 reportlvl = true;
355                                 break;
356                         case '*':
357                                 reportlvl = true;
358                                 break;
359                         case 't':
360                                 runtest = true;
361                                 break;
362                         case 'e':
363                                 change = true;
364                                 usbon = false;
365                                 break;
366                 }
367         }
368 }
369
370 #if !defined(CORE_TEENSY) && defined(__AVR__)
371 // ALL teensy versions LACK PWM ON LED
372
373 ISR(TIMER3_COMPA_vect) {
374         if((long)(millis() - LEDnext_time) >= 0L) {
375                 LEDnext_time = millis() + 30;
376
377                 // set the brightness of LED
378                 analogWrite(LED_BUILTIN, brightness);
379
380                 // change the brightness for next time through the loop:
381                 brightness = brightness + fadeAmount;
382
383                 // reverse the direction of the fading at the ends of the fade:
384                 if(brightness <= 0) {
385                         brightness = 0;
386                         fadeAmount = -fadeAmount;
387                 }
388                 if(brightness >= 255) {
389                         brightness = 255;
390                         fadeAmount = -fadeAmount;
391                 }
392         }
393 }
394 #endif
395
396 bool isfat(uint8_t t) {
397         return (t == 0x01 || t == 0x04 || t == 0x06 || t == 0x0b || t == 0x0c || t == 0x0e || t == 0x1);
398 }
399
400 void die(FRESULT rc) {
401         printf_P(PSTR("Failed with rc=%u.\r\n"), rc);
402         //for (;;);
403 }
404
405 void loop() {
406         FIL My_File_Object_x; /* File object */
407
408 #if defined(__AVR__)
409         // Print a heap status report about every 10 seconds.
410         if((long)(millis() - HEAPnext_time) >= 0L) {
411                 if(UsbDEBUGlvl > 0x50) {
412                         printf_P(PSTR("Available heap: %u Bytes\r\n"), freeHeap());
413                 }
414                 HEAPnext_time = millis() + 10000;
415         }
416         TCCR3B = 0;
417 #endif
418 #if defined(CORE_TEENSY)
419         // Teensy suffers here, oh well...
420         serialEvent();
421 #endif
422         // Horrid! This sort of thing really belongs in an ISR, not here!
423         // We also will be needing to test each hub port, we don't do this yet!
424         if(!change && !usbon && (long)(millis() - usbon_time) >= 0L) {
425                 change = true;
426                 usbon = true;
427         }
428
429         if(change) {
430                 change = false;
431                 if(usbon) {
432                         Usb.vbusPower(vbus_on);
433                         printf_P(PSTR("VBUS on\r\n"));
434                 } else {
435                         Usb.vbusPower(vbus_off);
436                         usbon_time = millis() + 2000;
437                 }
438         }
439         Usb.Task();
440         current_state = Usb.getUsbTaskState();
441         if(current_state != last_state) {
442                 if(UsbDEBUGlvl > 0x50)
443                         printf_P(PSTR("USB state = %x\r\n"), current_state);
444 #if !defined(CORE_TEENSY) && defined(__AVR__)
445                 if(current_state == USB_STATE_RUNNING) {
446                         fadeAmount = 30;
447                 }
448 #endif
449                 if(current_state == USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE) {
450 #if !defined(CORE_TEENSY) && defined(__AVR__)
451                         fadeAmount = 80;
452 #endif
453                         partsready = false;
454                         for(int i = 0; i < cpart; i++) {
455                                 if(Fats[i] != NULL)
456                                         delete Fats[i];
457                                 Fats[i] = NULL;
458                         }
459                         fatready = false;
460                         notified = false;
461                         cpart = 0;
462                 }
463                 last_state = current_state;
464         }
465
466         // only do any of this if usb is on
467         if(usbon) {
468                 if(partsready && !fatready) {
469                         if(cpart > 0) fatready = true;
470                 }
471                 // This is horrible, and needs to be moved elsewhere!
472                 for(int B = 0; B < MAX_USB_MS_DRIVERS; B++) {
473                         if((!partsready) && (UHS_USB_BulkOnly[B]->GetAddress())) {
474
475                                 // Build a list.
476                                 int ML = UHS_USB_BulkOnly[B]->GetbMaxLUN();
477                                 //printf("MAXLUN = %i\r\n", ML);
478                                 ML++;
479                                 for(int i = 0; i < ML; i++) {
480                                         if(UHS_USB_BulkOnly[B]->LUNIsGood(i)) {
481                                                 partsready = true;
482                                                 ((pvt_t *)(sto[i].private_data))->lun = i;
483                                                 ((pvt_t *)(sto[i].private_data))->B = B;
484                                                 sto[i].Reads = *UHS_USB_BulkOnly_Read;
485                                                 sto[i].Writes = *UHS_USB_BulkOnly_Write;
486                                                 sto[i].Status = *UHS_USB_BulkOnly_Status;
487                                                 sto[i].Initialize = *UHS_USB_BulkOnly_Initialize;
488                                                 sto[i].Commit = *UHS_USB_BulkOnly_Commit;
489                                                 sto[i].TotalSectors = UHS_USB_BulkOnly[B]->GetCapacity(i);
490                                                 sto[i].SectorSize = UHS_USB_BulkOnly[B]->GetSectorSize(i);
491                                                 printf_P(PSTR("LUN:\t\t%u\r\n"), i);
492                                                 printf_P(PSTR("Total Sectors:\t%08lx\t%lu\r\n"), sto[i].TotalSectors, sto[i].TotalSectors);
493                                                 printf_P(PSTR("Sector Size:\t%04x\t\t%u\r\n"), sto[i].SectorSize, sto[i].SectorSize);
494                                                 // get the partition data...
495                                                 PT = new PCPartition;
496
497                                                 if(!PT->Init(&sto[i])) {
498                                                         part_t *apart;
499                                                         for(int j = 0; j < 4; j++) {
500                                                                 apart = PT->GetPart(j);
501                                                                 if(apart != NULL && apart->type != 0x00) {
502                                                                         memcpy(&(parts[cpart]), apart, sizeof (part_t));
503                                                                         printf_P(PSTR("Partition %u type %#02x\r\n"), j, parts[cpart].type);
504                                                                         // for now
505                                                                         if(isfat(parts[cpart].type)) {
506                                                                                 Fats[cpart] = new PFAT(&sto[i], cpart, parts[cpart].firstSector);
507                                                                                 //int r = Fats[cpart]->Good();
508                                                                                 if(Fats[cpart]->MountStatus()) {
509                                                                                         delete Fats[cpart];
510                                                                                         Fats[cpart] = NULL;
511                                                                                 } else cpart++;
512                                                                         }
513                                                                 }
514                                                         }
515                                                 } else {
516                                                         // try superblock
517                                                         Fats[cpart] = new PFAT(&sto[i], cpart, 0);
518                                                         //int r = Fats[cpart]->Good();
519                                                         if(Fats[cpart]->MountStatus()) {
520                                                                 //printf_P(PSTR("Superblock error %x\r\n"), r);
521                                                                 delete Fats[cpart];
522                                                                 Fats[cpart] = NULL;
523                                                         } else cpart++;
524
525                                                 }
526                                                 delete PT;
527                                         } else {
528                                                 sto[i].Writes = NULL;
529                                                 sto[i].Reads = NULL;
530                                                 sto[i].Initialize = NULL;
531                                                 sto[i].TotalSectors = 0UL;
532                                                 sto[i].SectorSize = 0;
533                                         }
534                                 }
535
536                         }
537                 }
538
539                 if(fatready) {
540                         if(Fats[0] != NULL) {
541                                 struct Pvt * p;
542                                 p = ((struct Pvt *)(Fats[0]->storage->private_data));
543                                 if(!UHS_USB_BulkOnly[p->B]->LUNIsGood(p->lun)) {
544                                         // media change
545 #if !defined(CORE_TEENSY) && defined(__AVR__)
546                                         fadeAmount = 80;
547 #endif
548                                         partsready = false;
549                                         for(int i = 0; i < cpart; i++) {
550                                                 if(Fats[i] != NULL)
551                                                         delete Fats[i];
552                                                 Fats[cpart] = NULL;
553                                         }
554                                         fatready = false;
555                                         notified = false;
556                                         cpart = 0;
557                                 }
558
559                         }
560                 }
561                 if(fatready) {
562                         FRESULT rc; /* Result code */
563                         UINT bw, br, i;
564                         if(!notified) {
565 #if !defined(CORE_TEENSY) && defined(__AVR__)
566                                 fadeAmount = 5;
567 #endif
568                                 notified = true;
569                                 FATFS *fs = NULL;
570                                 for(int zz = 0; zz < _VOLUMES; zz++) {
571                                         if(Fats[zz]->volmap == 0) fs = Fats[zz]->ffs;
572                                 }
573                                 printf_P(PSTR("\r\nOpen an existing file (message.txt).\r\n"));
574                                 rc = f_open(&My_File_Object_x, "0:/MESSAGE.TXT", FA_READ);
575                                 if(rc) printf_P(PSTR("Error %i, message.txt not found.\r\n"), rc);
576                                 else {
577                                         printf_P(PSTR("\r\nType the file content.\r\n"));
578                                         for(;;) {
579                                                 rc = f_read(&My_File_Object_x, My_Buff_x, mbxs, &br); /* Read a chunk of file */
580                                                 if(rc || !br) break; /* Error or end of file */
581                                                 for(i = 0; i < br; i++) {
582                                                         /* Type the data */
583                                                         if(My_Buff_x[i] == '\n')
584                                                                 Serial.write('\r');
585                                                         if(My_Buff_x[i] != '\r')
586                                                                 Serial.write(My_Buff_x[i]);
587                                                         Serial.flush();
588                                                 }
589                                         }
590                                         if(rc) {
591                                                 f_close(&My_File_Object_x);
592                                                 goto out;
593                                         }
594
595                                         printf_P(PSTR("\r\nClose the file.\r\n"));
596                                         rc = f_close(&My_File_Object_x);
597                                         if(rc) goto out;
598                                 }
599                                 printf_P(PSTR("\r\nCreate a new file (hello.txt).\r\n"));
600                                 rc = f_open(&My_File_Object_x, "0:/Hello.TxT", FA_WRITE | FA_CREATE_ALWAYS);
601                                 if(rc) {
602                                         die(rc);
603                                         goto outdir;
604                                 }
605                                 printf_P(PSTR("\r\nWrite a text data. (Hello world!)\r\n"));
606                                 rc = f_write(&My_File_Object_x, "Hello world!\r\n", 14, &bw);
607                                 if(rc) {
608                                         goto out;
609                                 }
610                                 printf_P(PSTR("%u bytes written.\r\n"), bw);
611
612                                 printf_P(PSTR("\r\nClose the file.\r\n"));
613                                 rc = f_close(&My_File_Object_x);
614                                 if(rc) {
615                                         die(rc);
616                                         goto out;
617                                 }
618 outdir:{
619 #if _USE_LFN
620                                         char lfn[_MAX_LFN + 1];
621                                         FILINFO My_File_Info_Object_x; /* File information object */
622                                         My_File_Info_Object_x.lfname = lfn;
623 #endif
624                                         DIR My_Dir_Object_x; /* Directory object */
625                                         printf_P(PSTR("\r\nOpen root directory.\r\n"));
626                                         rc = f_opendir(&My_Dir_Object_x, "0:/");
627                                         if(rc) {
628                                                 die(rc);
629                                                 goto out;
630                                         }
631
632                                         printf_P(PSTR("\r\nDirectory listing...\r\n"));
633 #if defined(__AVR__)
634                                         printf_P(PSTR("Available heap: %u Bytes\r\n"), freeHeap());
635 #endif
636                                         for(;;) {
637 #if _USE_LFN
638                                                 My_File_Info_Object_x.lfsize = _MAX_LFN;
639 #endif
640
641                                                 rc = f_readdir(&My_Dir_Object_x, &My_File_Info_Object_x); /* Read a directory item */
642                                                 if(rc || !My_File_Info_Object_x.fname[0]) break; /* Error or end of dir */
643
644                                                 if(My_File_Info_Object_x.fattrib & AM_DIR) {
645                                                         Serial.write('d');
646                                                 } else {
647                                                         Serial.write('-');
648                                                 }
649                                                 Serial.write('r');
650
651                                                 if(My_File_Info_Object_x.fattrib & AM_RDO) {
652                                                         Serial.write('-');
653                                                 } else {
654                                                         Serial.write('w');
655                                                 }
656                                                 if(My_File_Info_Object_x.fattrib & AM_HID) {
657                                                         Serial.write('h');
658                                                 } else {
659                                                         Serial.write('-');
660                                                 }
661
662                                                 if(My_File_Info_Object_x.fattrib & AM_SYS) {
663                                                         Serial.write('s');
664                                                 } else {
665                                                         Serial.write('-');
666                                                 }
667
668                                                 if(My_File_Info_Object_x.fattrib & AM_ARC) {
669                                                         Serial.write('a');
670                                                 } else {
671                                                         Serial.write('-');
672                                                 }
673
674 #if _USE_LFN
675                                                 if(*My_File_Info_Object_x.lfname)
676                                                         printf_P(PSTR(" %8lu  %s (%s)\r\n"), My_File_Info_Object_x.fsize, My_File_Info_Object_x.fname, My_File_Info_Object_x.lfname);
677                                                 else
678 #endif
679                                                         printf_P(PSTR(" %8lu  %s\r\n"), My_File_Info_Object_x.fsize, &(My_File_Info_Object_x.fname[0]));
680                                         }
681                                 }
682 out:
683                                 if(rc) die(rc);
684
685                                 DISK_IOCTL(fs->drv, CTRL_COMMIT, 0);
686                                 printf_P(PSTR("\r\nTest completed.\r\n"));
687
688                         }
689
690                         if(runtest) {
691                                 ULONG ii, wt, rt, start, end;
692                                 FATFS *fs = NULL;
693                                 for(int zz = 0; zz < _VOLUMES; zz++) {
694                                         if(Fats[zz]->volmap == 0) fs = Fats[zz]->ffs;
695                                 }
696                                 runtest = false;
697                                 f_unlink("0:/10MB.bin");
698                                 printf_P(PSTR("\r\nCreate a new 10MB test file (10MB.bin).\r\n"));
699                                 rc = f_open(&My_File_Object_x, "0:/10MB.bin", FA_WRITE | FA_CREATE_ALWAYS);
700                                 if(rc) goto failed;
701                                 for(bw = 0; bw < mbxs; bw++) My_Buff_x[bw] = bw & 0xff;
702                                 fflush(stdout);
703                                 start = millis();
704                                 while(start == millis());
705                                 for(ii = 10485760LU / mbxs; ii > 0LU; ii--) {
706                                         rc = f_write(&My_File_Object_x, My_Buff_x, mbxs, &bw);
707                                         if(rc || !bw) goto failed;
708                                 }
709                                 rc = f_close(&My_File_Object_x);
710                                 if(rc) goto failed;
711                                 end = millis();
712                                 wt = (end - start) - 1;
713                                 printf_P(PSTR("Time to write 10485760 bytes: %lu ms (%lu sec) \r\n"), wt, (500 + wt) / 1000UL);
714                                 rc = f_open(&My_File_Object_x, "0:/10MB.bin", FA_READ);
715                                 fflush(stdout);
716                                 start = millis();
717                                 while(start == millis());
718                                 if(rc) goto failed;
719                                 for(;;) {
720                                         rc = f_read(&My_File_Object_x, My_Buff_x, mbxs, &bw); /* Read a chunk of file */
721                                         if(rc || !bw) break; /* Error or end of file */
722                                 }
723                                 end = millis();
724                                 if(rc) goto failed;
725                                 rc = f_close(&My_File_Object_x);
726                                 if(rc) goto failed;
727                                 rt = (end - start) - 1;
728                                 printf_P(PSTR("Time to read 10485760 bytes: %lu ms (%lu sec)\r\nDelete test file\r\n"), rt, (500 + rt) / 1000UL);
729 failed:
730                                 if(rc) die(rc);
731                                 DISK_IOCTL(fs->drv, CTRL_COMMIT, 0);
732                                 printf_P(PSTR("10MB timing test finished.\r\n"));
733                         }
734                 }
735         }
736 }