summaryrefslogtreecommitdiff
path: root/protocol/usb_hid/USB_Host_Shield_2.0/examples/testusbhostFAT/testusbhostFAT.ino
diff options
context:
space:
mode:
Diffstat (limited to 'protocol/usb_hid/USB_Host_Shield_2.0/examples/testusbhostFAT/testusbhostFAT.ino')
m---------protocol/usb_hid/USB_Host_Shield_2.00
-rw-r--r--protocol/usb_hid/USB_Host_Shield_2.0/examples/testusbhostFAT/testusbhostFAT.ino736
2 files changed, 736 insertions, 0 deletions
diff --git a/protocol/usb_hid/USB_Host_Shield_2.0 b/protocol/usb_hid/USB_Host_Shield_2.0
deleted file mode 160000
-Subproject 7c2e6c1bcdcc22cfdbd82edd9d8fc4c4276ead4
diff --git a/protocol/usb_hid/USB_Host_Shield_2.0/examples/testusbhostFAT/testusbhostFAT.ino b/protocol/usb_hid/USB_Host_Shield_2.0/examples/testusbhostFAT/testusbhostFAT.ino
new file mode 100644
index 0000000000..e8b9cd3592
--- /dev/null
+++ b/protocol/usb_hid/USB_Host_Shield_2.0/examples/testusbhostFAT/testusbhostFAT.ino
@@ -0,0 +1,736 @@
+/*
+ * Mega + USB storage + optional DS1307 + optional expansion RAM + funky status LED,
+ * Includes interactive debug level setting, and supports hot-plug.
+ *
+ * IMPORTANT! PLEASE USE Arduino 1.0.5 or better!
+ * Older versions HAVE MAJOR BUGS AND WILL NOT WORK AT ALL!
+ * Use of gcc-avr and lib-c that is newer than the Arduino version is even better.
+ * If you experience random crashes, use make.
+ * The options that the IDE use can generate bad code and cause the AVR to crash.
+ *
+ * This sketch requires the following libraries:
+ * https://github.com/felis/USB_Host_Shield_2.0 Install as 'USB_Host_Shield_2_0'
+ * https://github.com/xxxajk/xmem2 Install as 'xmem', provides memory services.
+ * https://github.com/xxxajk/generic_storage provides access to FAT file system.
+ * https://github.com/xxxajk/RTClib provides access to DS1307, or fake clock.
+ *
+ * Optional, to use the Makefile (Recommended! See above!):
+ * https://github.com/xxxajk/Arduino_Makefile_master
+ *
+ */
+
+/////////////////////////////////////////////////////////////
+// Please Note: //
+// This section is for info with the Arduino IDE ONLY. //
+// Unfortunately due to short sightedness of the Arduino //
+// code team, that you must set the following in the //
+// respective libraries. //
+// Changing them here will have _NO_ effect! //
+/////////////////////////////////////////////////////////////
+
+// Uncomment to enable debugging
+//#define DEBUG_USB_HOST
+// This is where stderr/USB debugging goes to
+//#define USB_HOST_SERIAL Serial3
+
+// If you have external memory, setting this to 0 enables FAT table caches.
+// The 0 setting is recommended only if you have external memory.
+//#define _FS_TINY 1
+
+//#define _USE_LFN 3
+//#define _MAX_SS 512
+
+
+/////////////////////////////////////////////////////////////
+// End of Arduino IDE specific information //
+/////////////////////////////////////////////////////////////
+
+// You can set this to 0 if you are not using a USB hub.
+// It will save a little bit of flash and RAM.
+// Set to 1 if you want to use a hub.
+#define WANT_HUB_TEST 1
+
+// this is for XMEM2
+#define EXT_RAM_STACK 1
+#define EXT_RAM_HEAP 1
+#define LOAD_XMEM
+
+#if defined(CORE_TEENSY) && !defined(_AVR_)
+#include <xmem.h>
+#include <spi4teensy3.h>
+#endif
+
+#if defined(__AVR__)
+#include <xmem.h>
+#include <SPI.h>
+#elif defined(ARDUINO_ARCH_SAM)
+#include <SPI.h>
+#endif
+
+#if WANT_HUB_TEST
+#include <usbhub.h>
+#endif
+#include <Wire.h>
+#define LOAD_RTCLIB
+#include <RTClib.h>
+#include <masstorage.h>
+#include <Storage.h>
+#include <PCpartition/PCPartition.h>
+#include <avr/interrupt.h>
+#include <FAT/FAT.h>
+#include <stdio.h>
+#if defined(__AVR__)
+static FILE tty_stdio;
+static FILE tty_stderr;
+volatile uint32_t LEDnext_time; // fade timeout
+volatile uint32_t HEAPnext_time; // when to print out next heap report
+volatile int brightness = 0; // how bright the LED is
+volatile int fadeAmount = 80; // how many points to fade the LED by
+#endif
+
+USB Usb;
+
+volatile uint8_t current_state = 1;
+volatile uint8_t last_state = 0;
+volatile bool fatready = false;
+volatile bool partsready = false;
+volatile bool notified = false;
+volatile bool runtest = false;
+volatile bool usbon = false;
+volatile uint32_t usbon_time;
+volatile bool change = false;
+volatile bool reportlvl = false;
+int cpart = 0;
+PCPartition *PT;
+
+#if WANT_HUB_TEST
+#define MAX_HUBS 1
+USBHub *Hubs[MAX_HUBS];
+#endif
+
+static PFAT *Fats[_VOLUMES];
+static part_t parts[_VOLUMES];
+static storage_t sto[_VOLUMES];
+
+/*make sure this is a power of two. */
+#define mbxs 128
+static uint8_t My_Buff_x[mbxs]; /* File read buffer */
+
+#if defined(__AVR__)
+
+#define prescale1 ((1 << WGM12) | (1 << CS10))
+#define prescale8 ((1 << WGM12) | (1 << CS11))
+#define prescale64 ((1 << WGM12) | (1 << CS10) | (1 << CS11))
+#define prescale256 ((1 << WGM12) | (1 << CS12))
+#define prescale1024 ((1 << WGM12) | (1 << CS12) | (1 << CS10))
+
+extern "C" {
+ extern unsigned int freeHeap();
+}
+static int tty_stderr_putc(char c, FILE *t) {
+ USB_HOST_SERIAL.write(c);
+ return 0;
+}
+
+static int __attribute__((unused)) tty_stderr_flush(FILE *t) {
+ USB_HOST_SERIAL.flush();
+ return 0;
+}
+
+static int tty_std_putc(char c, FILE *t) {
+ Serial.write(c);
+ return 0;
+}
+
+static int tty_std_getc(FILE *t) {
+ while(!Serial.available());
+ return Serial.read();
+}
+
+static int __attribute__((unused)) tty_std_flush(FILE *t) {
+ Serial.flush();
+ return 0;
+}
+
+#else
+// Supposedly the DUE has stdio already pointing to serial...
+#if !defined(ARDUINO_ARCH_SAM)
+// But newlib needs this...
+extern "C" {
+ int _write(int fd, const char *ptr, int len) {
+ int j;
+ for(j = 0; j < len; j++) {
+ if(fd == 1)
+ Serial.write(*ptr++);
+ else if(fd == 2)
+ USB_HOST_SERIAL.write(*ptr++);
+ }
+ return len;
+ }
+
+ int _read(int fd, char *ptr, int len) {
+ if(len > 0 && fd == 0) {
+ while(!Serial.available());
+ *ptr = Serial.read();
+ return 1;
+ }
+ return 0;
+ }
+
+#include <sys/stat.h>
+
+ int _fstat(int fd, struct stat *st) {
+ memset(st, 0, sizeof (*st));
+ st->st_mode = S_IFCHR;
+ st->st_blksize = 1024;
+ return 0;
+ }
+
+ int _isatty(int fd) {
+ return (fd < 3) ? 1 : 0;
+ }
+}
+#endif // !defined(ARDUINO_ARCH_SAM)
+#endif
+
+void setup() {
+ bool serr = false;
+ for(int i = 0; i < _VOLUMES; i++) {
+ Fats[i] = NULL;
+ sto[i].private_data = new pvt_t;
+ ((pvt_t *)sto[i].private_data)->B = 255; // impossible
+ }
+ // Set this to higher values to enable more debug information
+ // minimum 0x00, maximum 0xff
+ UsbDEBUGlvl = 0x81;
+
+#if !defined(CORE_TEENSY) && defined(__AVR__)
+ // make LED pin as an output:
+ pinMode(LED_BUILTIN, OUTPUT);
+ pinMode(2, OUTPUT);
+ // Ensure TX is off
+ _SFR_BYTE(UCSR0B) &= ~_BV(TXEN0);
+ // Initialize 'debug' serial port
+ USB_HOST_SERIAL.begin(115200);
+ // Do not start primary Serial port if already started.
+ if(bit_is_clear(UCSR0B, TXEN0)) {
+ Serial.begin(115200);
+ serr = true;
+ }
+
+
+ // Blink LED
+ delay(500);
+ analogWrite(LED_BUILTIN, 255);
+ delay(500);
+ analogWrite(LED_BUILTIN, 0);
+ delay(500);
+#else
+ while(!Serial);
+ Serial.begin(115200); // On the Teensy 3.x we get a delay at least!
+#endif
+#if defined(__AVR__)
+ // Set up stdio/stderr
+ tty_stdio.put = tty_std_putc;
+ tty_stdio.get = tty_std_getc;
+ tty_stdio.flags = _FDEV_SETUP_RW;
+ tty_stdio.udata = 0;
+
+ tty_stderr.put = tty_stderr_putc;
+ tty_stderr.get = NULL;
+ tty_stderr.flags = _FDEV_SETUP_WRITE;
+ tty_stderr.udata = 0;
+
+ stdout = &tty_stdio;
+ stdin = &tty_stdio;
+ stderr = &tty_stderr;
+#endif
+ printf_P(PSTR("\r\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nStart\r\n"));
+ printf_P(PSTR("Current UsbDEBUGlvl %02x\r\n"), UsbDEBUGlvl);
+ printf_P(PSTR("'+' and '-' increase/decrease by 0x01\r\n"));
+ printf_P(PSTR("'.' and ',' increase/decrease by 0x10\r\n"));
+ printf_P(PSTR("'t' will run a 10MB write/read test and print out the time it took.\r\n"));
+ printf_P(PSTR("'e' will toggle vbus off for a few moments.\r\n\r\n"));
+ printf_P(PSTR("Long filename support: "
+#if _USE_LFN
+ "Enabled"
+#else
+ "Disabled"
+#endif
+ "\r\n"));
+ if(serr) {
+ fprintf_P(stderr, PSTR("\r\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nStart\r\n"));
+ fprintf_P(stderr, PSTR("Current UsbDEBUGlvl %02x\r\n"), UsbDEBUGlvl);
+ fprintf_P(stderr, PSTR("Long filename support: "
+#if _USE_LFN
+ "Enabled"
+#else
+ "Disabled"
+#endif
+ "\r\n"));
+ }
+
+#if !defined(CORE_TEENSY) && defined(__AVR__)
+ analogWrite(LED_BUILTIN, 255);
+ delay(500);
+ analogWrite(LED_BUILTIN, 0);
+ delay(500);
+ analogWrite(LED_BUILTIN, 255);
+ delay(500);
+ analogWrite(LED_BUILTIN, 0);
+ delay(500);
+ analogWrite(LED_BUILTIN, 255);
+ delay(500);
+ analogWrite(LED_BUILTIN, 0);
+ delay(500);
+
+ LEDnext_time = millis() + 1;
+#if EXT_RAM
+ printf_P(PSTR("Total EXT RAM banks %i\r\n"), xmem::getTotalBanks());
+#endif
+ printf_P(PSTR("Available heap: %u Bytes\r\n"), freeHeap());
+ printf_P(PSTR("SP %x\r\n"), (uint8_t *)(SP));
+#endif
+
+ // Even though I'm not going to actually be deleting,
+ // I want to be able to have slightly more control.
+ // Besides, it is easier to initialize stuff...
+#if WANT_HUB_TEST
+ for(int i = 0; i < MAX_HUBS; i++) {
+ Hubs[i] = new USBHub(&Usb);
+#if defined(__AVR__)
+ printf_P(PSTR("Available heap: %u Bytes\r\n"), freeHeap());
+#endif
+ }
+#endif
+ // Initialize generic storage. This must be done before USB starts.
+ Init_Generic_Storage();
+
+ while(Usb.Init(1000) == -1) {
+ printf_P(PSTR("No USB HOST Shield?\r\n"));
+ Notify(PSTR("OSC did not start."), 0x40);
+ }
+
+#if !defined(CORE_TEENSY) && defined(__AVR__)
+ cli();
+ TCCR3A = 0;
+ TCCR3B = 0;
+ // (0.01/(1/((16 *(10^6)) / 8))) - 1 = 19999
+ OCR3A = 19999;
+ TCCR3B |= prescale8;
+ TIMSK3 |= (1 << OCIE1A);
+ sei();
+
+ HEAPnext_time = millis() + 10000;
+#endif
+#if defined(__AVR__)
+ HEAPnext_time = millis() + 10000;
+#endif
+}
+
+void serialEvent() {
+ // Adjust UsbDEBUGlvl level on-the-fly.
+ // + to increase, - to decrease, * to display current level.
+ // . to increase by 16, , to decrease by 16
+ // e to flick VBUS
+ // * to report debug level
+ if(Serial.available()) {
+ int inByte = Serial.read();
+ switch(inByte) {
+ case '+':
+ if(UsbDEBUGlvl < 0xff) UsbDEBUGlvl++;
+ reportlvl = true;
+ break;
+ case '-':
+ if(UsbDEBUGlvl > 0x00) UsbDEBUGlvl--;
+ reportlvl = true;
+ break;
+ case '.':
+ if(UsbDEBUGlvl < 0xf0) UsbDEBUGlvl += 16;
+ reportlvl = true;
+ break;
+ case ',':
+ if(UsbDEBUGlvl > 0x0f) UsbDEBUGlvl -= 16;
+ reportlvl = true;
+ break;
+ case '*':
+ reportlvl = true;
+ break;
+ case 't':
+ runtest = true;
+ break;
+ case 'e':
+ change = true;
+ usbon = false;
+ break;
+ }
+ }
+}
+
+#if !defined(CORE_TEENSY) && defined(__AVR__)
+// ALL teensy versions LACK PWM ON LED
+
+ISR(TIMER3_COMPA_vect) {
+ if((long)(millis() - LEDnext_time) >= 0L) {
+ LEDnext_time = millis() + 30;
+
+ // set the brightness of LED
+ analogWrite(LED_BUILTIN, brightness);
+
+ // change the brightness for next time through the loop:
+ brightness = brightness + fadeAmount;
+
+ // reverse the direction of the fading at the ends of the fade:
+ if(brightness <= 0) {
+ brightness = 0;
+ fadeAmount = -fadeAmount;
+ }
+ if(brightness >= 255) {
+ brightness = 255;
+ fadeAmount = -fadeAmount;
+ }
+ }
+}
+#endif
+
+bool isfat(uint8_t t) {
+ return (t == 0x01 || t == 0x04 || t == 0x06 || t == 0x0b || t == 0x0c || t == 0x0e || t == 0x1);
+}
+
+void die(FRESULT rc) {
+ printf_P(PSTR("Failed with rc=%u.\r\n"), rc);
+ //for (;;);
+}
+
+void loop() {
+ FIL My_File_Object_x; /* File object */
+
+#if defined(__AVR__)
+ // Print a heap status report about every 10 seconds.
+ if((long)(millis() - HEAPnext_time) >= 0L) {
+ if(UsbDEBUGlvl > 0x50) {
+ printf_P(PSTR("Available heap: %u Bytes\r\n"), freeHeap());
+ }
+ HEAPnext_time = millis() + 10000;
+ }
+ TCCR3B = 0;
+#endif
+#if defined(CORE_TEENSY)
+ // Teensy suffers here, oh well...
+ serialEvent();
+#endif
+ // Horrid! This sort of thing really belongs in an ISR, not here!
+ // We also will be needing to test each hub port, we don't do this yet!
+ if(!change && !usbon && (long)(millis() - usbon_time) >= 0L) {
+ change = true;
+ usbon = true;
+ }
+
+ if(change) {
+ change = false;
+ if(usbon) {
+ Usb.vbusPower(vbus_on);
+ printf_P(PSTR("VBUS on\r\n"));
+ } else {
+ Usb.vbusPower(vbus_off);
+ usbon_time = millis() + 2000;
+ }
+ }
+ Usb.Task();
+ current_state = Usb.getUsbTaskState();
+ if(current_state != last_state) {
+ if(UsbDEBUGlvl > 0x50)
+ printf_P(PSTR("USB state = %x\r\n"), current_state);
+#if !defined(CORE_TEENSY) && defined(__AVR__)
+ if(current_state == USB_STATE_RUNNING) {
+ fadeAmount = 30;
+ }
+#endif
+ if(current_state == USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE) {
+#if !defined(CORE_TEENSY) && defined(__AVR__)
+ fadeAmount = 80;
+#endif
+ partsready = false;
+ for(int i = 0; i < cpart; i++) {
+ if(Fats[i] != NULL)
+ delete Fats[i];
+ Fats[i] = NULL;
+ }
+ fatready = false;
+ notified = false;
+ cpart = 0;
+ }
+ last_state = current_state;
+ }
+
+ // only do any of this if usb is on
+ if(usbon) {
+ if(partsready && !fatready) {
+ if(cpart > 0) fatready = true;
+ }
+ // This is horrible, and needs to be moved elsewhere!
+ for(int B = 0; B < MAX_USB_MS_DRIVERS; B++) {
+ if((!partsready) && (UHS_USB_BulkOnly[B]->GetAddress())) {
+
+ // Build a list.
+ int ML = UHS_USB_BulkOnly[B]->GetbMaxLUN();
+ //printf("MAXLUN = %i\r\n", ML);
+ ML++;
+ for(int i = 0; i < ML; i++) {
+ if(UHS_USB_BulkOnly[B]->LUNIsGood(i)) {
+ partsready = true;
+ ((pvt_t *)(sto[i].private_data))->lun = i;
+ ((pvt_t *)(sto[i].private_data))->B = B;
+ sto[i].Reads = *UHS_USB_BulkOnly_Read;
+ sto[i].Writes = *UHS_USB_BulkOnly_Write;
+ sto[i].Status = *UHS_USB_BulkOnly_Status;
+ sto[i].Initialize = *UHS_USB_BulkOnly_Initialize;
+ sto[i].Commit = *UHS_USB_BulkOnly_Commit;
+ sto[i].TotalSectors = UHS_USB_BulkOnly[B]->GetCapacity(i);
+ sto[i].SectorSize = UHS_USB_BulkOnly[B]->GetSectorSize(i);
+ printf_P(PSTR("LUN:\t\t%u\r\n"), i);
+ printf_P(PSTR("Total Sectors:\t%08lx\t%lu\r\n"), sto[i].TotalSectors, sto[i].TotalSectors);
+ printf_P(PSTR("Sector Size:\t%04x\t\t%u\r\n"), sto[i].SectorSize, sto[i].SectorSize);
+ // get the partition data...
+ PT = new PCPartition;
+
+ if(!PT->Init(&sto[i])) {
+ part_t *apart;
+ for(int j = 0; j < 4; j++) {
+ apart = PT->GetPart(j);
+ if(apart != NULL && apart->type != 0x00) {
+ memcpy(&(parts[cpart]), apart, sizeof (part_t));
+ printf_P(PSTR("Partition %u type %#02x\r\n"), j, parts[cpart].type);
+ // for now
+ if(isfat(parts[cpart].type)) {
+ Fats[cpart] = new PFAT(&sto[i], cpart, parts[cpart].firstSector);
+ //int r = Fats[cpart]->Good();
+ if(Fats[cpart]->MountStatus()) {
+ delete Fats[cpart];
+ Fats[cpart] = NULL;
+ } else cpart++;
+ }
+ }
+ }
+ } else {
+ // try superblock
+ Fats[cpart] = new PFAT(&sto[i], cpart, 0);
+ //int r = Fats[cpart]->Good();
+ if(Fats[cpart]->MountStatus()) {
+ //printf_P(PSTR("Superblock error %x\r\n"), r);
+ delete Fats[cpart];
+ Fats[cpart] = NULL;
+ } else cpart++;
+
+ }
+ delete PT;
+ } else {
+ sto[i].Writes = NULL;
+ sto[i].Reads = NULL;
+ sto[i].Initialize = NULL;
+ sto[i].TotalSectors = 0UL;
+ sto[i].SectorSize = 0;
+ }
+ }
+
+ }
+ }
+
+ if(fatready) {
+ if(Fats[0] != NULL) {
+ struct Pvt * p;
+ p = ((struct Pvt *)(Fats[0]->storage->private_data));
+ if(!UHS_USB_BulkOnly[p->B]->LUNIsGood(p->lun)) {
+ // media change
+#if !defined(CORE_TEENSY) && defined(__AVR__)
+ fadeAmount = 80;
+#endif
+ partsready = false;
+ for(int i = 0; i < cpart; i++) {
+ if(Fats[i] != NULL)
+ delete Fats[i];
+ Fats[cpart] = NULL;
+ }
+ fatready = false;
+ notified = false;
+ cpart = 0;
+ }
+
+ }
+ }
+ if(fatready) {
+ FRESULT rc; /* Result code */
+ UINT bw, br, i;
+ if(!notified) {
+#if !defined(CORE_TEENSY) && defined(__AVR__)
+ fadeAmount = 5;
+#endif
+ notified = true;
+ FATFS *fs = NULL;
+ for(int zz = 0; zz < _VOLUMES; zz++) {
+ if(Fats[zz]->volmap == 0) fs = Fats[zz]->ffs;
+ }
+ printf_P(PSTR("\r\nOpen an existing file (message.txt).\r\n"));
+ rc = f_open(&My_File_Object_x, "0:/MESSAGE.TXT", FA_READ);
+ if(rc) printf_P(PSTR("Error %i, message.txt not found.\r\n"), rc);
+ else {
+ printf_P(PSTR("\r\nType the file content.\r\n"));
+ for(;;) {
+ rc = f_read(&My_File_Object_x, My_Buff_x, mbxs, &br); /* Read a chunk of file */
+ if(rc || !br) break; /* Error or end of file */
+ for(i = 0; i < br; i++) {
+ /* Type the data */
+ if(My_Buff_x[i] == '\n')
+ Serial.write('\r');
+ if(My_Buff_x[i] != '\r')
+ Serial.write(My_Buff_x[i]);
+ Serial.flush();
+ }
+ }
+ if(rc) {
+ f_close(&My_File_Object_x);
+ goto out;
+ }
+
+ printf_P(PSTR("\r\nClose the file.\r\n"));
+ rc = f_close(&My_File_Object_x);
+ if(rc) goto out;
+ }
+ printf_P(PSTR("\r\nCreate a new file (hello.txt).\r\n"));
+ rc = f_open(&My_File_Object_x, "0:/Hello.TxT", FA_WRITE | FA_CREATE_ALWAYS);
+ if(rc) {
+ die(rc);
+ goto outdir;
+ }
+ printf_P(PSTR("\r\nWrite a text data. (Hello world!)\r\n"));
+ rc = f_write(&My_File_Object_x, "Hello world!\r\n", 14, &bw);
+ if(rc) {
+ goto out;
+ }
+ printf_P(PSTR("%u bytes written.\r\n"), bw);
+
+ printf_P(PSTR("\r\nClose the file.\r\n"));
+ rc = f_close(&My_File_Object_x);
+ if(rc) {
+ die(rc);
+ goto out;
+ }
+outdir:{
+#if _USE_LFN
+ char lfn[_MAX_LFN + 1];
+ FILINFO My_File_Info_Object_x; /* File information object */
+ My_File_Info_Object_x.lfname = lfn;
+#endif
+ DIR My_Dir_Object_x; /* Directory object */
+ printf_P(PSTR("\r\nOpen root directory.\r\n"));
+ rc = f_opendir(&My_Dir_Object_x, "0:/");
+ if(rc) {
+ die(rc);
+ goto out;
+ }
+
+ printf_P(PSTR("\r\nDirectory listing...\r\n"));
+#if defined(__AVR__)
+ printf_P(PSTR("Available heap: %u Bytes\r\n"), freeHeap());
+#endif
+ for(;;) {
+#if _USE_LFN
+ My_File_Info_Object_x.lfsize = _MAX_LFN;
+#endif
+
+ rc = f_readdir(&My_Dir_Object_x, &My_File_Info_Object_x); /* Read a directory item */
+ if(rc || !My_File_Info_Object_x.fname[0]) break; /* Error or end of dir */
+
+ if(My_File_Info_Object_x.fattrib & AM_DIR) {
+ Serial.write('d');
+ } else {
+ Serial.write('-');
+ }
+ Serial.write('r');
+
+ if(My_File_Info_Object_x.fattrib & AM_RDO) {
+ Serial.write('-');
+ } else {
+ Serial.write('w');
+ }
+ if(My_File_Info_Object_x.fattrib & AM_HID) {
+ Serial.write('h');
+ } else {
+ Serial.write('-');
+ }
+
+ if(My_File_Info_Object_x.fattrib & AM_SYS) {
+ Serial.write('s');
+ } else {
+ Serial.write('-');
+ }
+
+ if(My_File_Info_Object_x.fattrib & AM_ARC) {
+ Serial.write('a');
+ } else {
+ Serial.write('-');
+ }
+
+#if _USE_LFN
+ if(*My_File_Info_Object_x.lfname)
+ 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);
+ else
+#endif
+ printf_P(PSTR(" %8lu %s\r\n"), My_File_Info_Object_x.fsize, &(My_File_Info_Object_x.fname[0]));
+ }
+ }
+out:
+ if(rc) die(rc);
+
+ DISK_IOCTL(fs->drv, CTRL_COMMIT, 0);
+ printf_P(PSTR("\r\nTest completed.\r\n"));
+
+ }
+
+ if(runtest) {
+ ULONG ii, wt, rt, start, end;
+ FATFS *fs = NULL;
+ for(int zz = 0; zz < _VOLUMES; zz++) {
+ if(Fats[zz]->volmap == 0) fs = Fats[zz]->ffs;
+ }
+ runtest = false;
+ f_unlink("0:/10MB.bin");
+ printf_P(PSTR("\r\nCreate a new 10MB test file (10MB.bin).\r\n"));
+ rc = f_open(&My_File_Object_x, "0:/10MB.bin", FA_WRITE | FA_CREATE_ALWAYS);
+ if(rc) goto failed;
+ for(bw = 0; bw < mbxs; bw++) My_Buff_x[bw] = bw & 0xff;
+ fflush(stdout);
+ start = millis();
+ while(start == millis());
+ for(ii = 10485760LU / mbxs; ii > 0LU; ii--) {
+ rc = f_write(&My_File_Object_x, My_Buff_x, mbxs, &bw);
+ if(rc || !bw) goto failed;
+ }
+ rc = f_close(&My_File_Object_x);
+ if(rc) goto failed;
+ end = millis();
+ wt = (end - start) - 1;
+ printf_P(PSTR("Time to write 10485760 bytes: %lu ms (%lu sec) \r\n"), wt, (500 + wt) / 1000UL);
+ rc = f_open(&My_File_Object_x, "0:/10MB.bin", FA_READ);
+ fflush(stdout);
+ start = millis();
+ while(start == millis());
+ if(rc) goto failed;
+ for(;;) {
+ rc = f_read(&My_File_Object_x, My_Buff_x, mbxs, &bw); /* Read a chunk of file */
+ if(rc || !bw) break; /* Error or end of file */
+ }
+ end = millis();
+ if(rc) goto failed;
+ rc = f_close(&My_File_Object_x);
+ if(rc) goto failed;
+ rt = (end - start) - 1;
+ printf_P(PSTR("Time to read 10485760 bytes: %lu ms (%lu sec)\r\nDelete test file\r\n"), rt, (500 + rt) / 1000UL);
+failed:
+ if(rc) die(rc);
+ DISK_IOCTL(fs->drv, CTRL_COMMIT, 0);
+ printf_P(PSTR("10MB timing test finished.\r\n"));
+ }
+ }
+ }
+}