Move USB Host Shield and Arduino core to lib/ (#13973)

This commit is contained in:
Ryan 2021-08-18 18:20:25 +10:00 committed by GitHub
parent cf5e40c251
commit b16091659c
Failed to generate hash of commit
182 changed files with 6 additions and 6 deletions

View file

@ -0,0 +1,64 @@
#
# These are set for a mega 1280 + quadram plus my serial patch.
# If you lack quadram, or want to disable LFN, just change _FS_TINY=1 _USE_LFN=0
#
# If your board is a mega 2560 comment out the following two lines
BOARD = mega
BOARD_SUB = mega.menu.cpu.atmega1280
PROGRAMMER = arduino
# ...and then uncomment out the following two lines
#BOARD_SUB = mega.menu.cpu.atmega2560
#PROGRAMMER = wiring
#BOARD = teensypp2
#BOARD = teensy3
#BOARD = teensy31
# set your Arduino tty port here
PORT = /dev/ttyUSB0
EXTRA_FLAGS = -D _USE_LFN=3
# change to 0 if you have quadram to take advantage of caching FAT
EXTRA_FLAGS += -D _FS_TINY=1
EXTRA_FLAGS += -D _MAX_SS=512
# Don't worry if you don't have external RAM, xmem2 detects this situation.
# You *WILL* be wanting to get some kind of external ram on your mega in order to
# do anything that is intense.
EXTRA_FLAGS += -D EXT_RAM_STACK=1
EXTRA_FLAGS += -D EXT_RAM_HEAP=1
# These are no longer needed for the demo to work.
# In the event you need more ram, uncomment these 3 lines.
#EXTRA_FLAGS += -D DISABLE_SERIAL1
#EXTRA_FLAGS += -D DISABLE_SERIAL2
#EXTRA_FLAGS += -D DISABLE_SERIAL3
#
# Advanced debug on Serial3
#
# uncomment the next two to enable debug on Serial3
EXTRA_FLAGS += -D USB_HOST_SERIAL=Serial3
#EXTRA_FLAGS += -D DEBUG_USB_HOST
# The following are the libraries used.
LIB_DIRS += ../../
LIB_DIRS += ../testusbhostFAT/xmem2
LIB_DIRS += ../testusbhostFAT/generic_storage
LIB_DIRS += ../testusbhostFAT/RTClib
LIB_DIRS += $(ARD_HOME)/libraries/Wire
LIB_DIRS += $(ARD_HOME)/libraries/Wire/utility
LIB_DIRS += $(ARD_HOME)/hardware/arduino/$(BUILD_ARCH)/libraries/Wire
LIB_DIRS += $(ARD_HOME)/hardware/arduino/$(BUILD_ARCH)/libraries/Wire/utility
LIB_DIRS += $(ARD_HOME)/hardware/arduino/$(BUILD_ARCH)/libraries/SPI
# And finally, the part that brings everything together for you.
include Arduino_Makefile_master/_Makefile.master

View file

@ -0,0 +1,29 @@
This small sketch tests the USB host shield mass storage library.
__Note:__ This will not run a Arduino Uno due to the limited ram available in the ATmega328p.
The Arduino Mega (ATmega1280) and the Arduino Mega 2560 (ATmega2560) are confirmed to work with this test code.
To compile this example you will need the following libraries as well:
* [xmem2](https://github.com/xxxajk/xmem2)
* [generic_storage FATfs](https://github.com/xxxajk/generic_storage)
* [RTClib](https://github.com/xxxajk/RTClib)
The following shield is recommended for larger projects: <https://www.rugged-circuits.com/new-products/quadram>.
You may use the bundled [Makefile](Makefile) to compile the code instead of the Arduino IDE if you have problems or want a smaller binary. The master makefile is bundled as a submodule, but can also be downloaded manually at the following link: <https://github.com/xxxajk/Arduino_Makefile_master>.
To download the USB Host library and all the needed libraries for this test.
Run the following command in a terminal application:
```
git clone --recursive https://github.com/felis/USB_Host_Shield_2.0
```
If you want to update all the submodules run:
```
git submodule foreach --recursive git pull origin master
```

View file

@ -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"));
}
}
}
}