Adafruit_Arcada/Adafruit_Arcada_USBMSD.cpp

228 lines
7.2 KiB
C++

#include <Adafruit_Arcada.h>
// #define ARCADA_MSD_DEBUG
static uint32_t last_access_ms;
#if defined(USE_TINYUSB)
static Adafruit_USBD_MSC usb_msc;
#endif
extern FatFileSystem Arcada_QSPI_FileSys;
extern Adafruit_SPIFlash Arcada_QSPI_Flash;
int32_t qspi_msc_write_cb(uint32_t lba, uint8_t *buffer, uint32_t bufsize);
int32_t qspi_msc_read_cb(uint32_t lba, void *buffer, uint32_t bufsize);
void qspi_msc_flush_cb(void);
#if defined(ENABLE_EXTENDED_TRANSFER_CLASS)
extern SdFatEX Arcada_SD_FileSys;
#else
extern SdFat Arcada_SD_FileSys;
#endif
int32_t sd_msc_write_cb(uint32_t lba, uint8_t *buffer, uint32_t bufsize);
int32_t sd_msc_read_cb(uint32_t lba, void *buffer, uint32_t bufsize);
void sd_msc_flush_cb(void);
/**************************************************************************/
/*!
@brief Make the raw filesystem of the Arcada board available over USB
@param desiredFilesys The filesystem we'd prefer to use, can be
ARCADA_FILESYS_SD, ARCADA_FILESYS_QSPI, or ARCADA_FILESYS_SD_AND_QSPI
@return True on success, false on failure
*/
/**************************************************************************/
bool Adafruit_Arcada_SPITFT::filesysBeginMSD(
Arcada_FilesystemType desiredFilesys) {
(void)desiredFilesys;
#if defined(USE_TINYUSB)
Arcada_FilesystemType found = filesysBegin(desiredFilesys);
if (found == ARCADA_FILESYS_NONE) {
return false;
}
// arcadaBegin() could take long time to complete
// By the time this function is called, usb enumeration is probably completed
// as CDC only device Therefore we have to
// - Physically detach the device by disable pull-up resistor
// - Configure the Mass Stroage interface
// - Re-attach by enable pull-up resistor
USBDevice.detach();
delay(50); // a bit of delay for device to disconnect
if (found == ARCADA_FILESYS_SD ||
found == ARCADA_FILESYS_SD_AND_QSPI) { // SD first
// Set disk vendor id, product id and revision with string up to 8, 16, 4
// characters respectively
usb_msc.setID("Adafruit", "SD Card", "1.0");
// Set callback
usb_msc.setReadWriteCallback(sd_msc_read_cb, sd_msc_write_cb,
sd_msc_flush_cb);
usb_msc.setUnitReady(false);
usb_msc.begin();
uint32_t block_count = Arcada_SD_FileSys.card()->sectorCount();
#ifdef ARCADA_MSD_DEBUG
Serial.print("MSD for SD Card - Volume size (MB): ");
Serial.println((block_count / 2) / 1024);
#endif
// Set disk size, SD block size is always 512
usb_msc.setCapacity(block_count, 512);
// MSC is ready for read/write
usb_msc.setUnitReady(true);
// re-attach to usb bus
USBDevice.attach();
return true;
}
if (found == ARCADA_FILESYS_QSPI ||
found == ARCADA_FILESYS_SD_AND_QSPI) { // QSPI if not SD
#ifdef ARCADA_MSD_DEBUG
Serial.println("Found QSPI for MSD");
Serial.print("JEDEC ID: ");
Serial.println(Arcada_QSPI_Flash.getJEDECID(), HEX);
Serial.print("Flash size: ");
Serial.println(Arcada_QSPI_Flash.size());
#endif
// Set disk vendor id, product id and revision with string up to 8, 16, 4
// characters respectively
usb_msc.setID("Adafruit", "SPI Flash", "1.0");
// Set callback
usb_msc.setReadWriteCallback(qspi_msc_read_cb, qspi_msc_write_cb,
qspi_msc_flush_cb);
// Set disk size, block size should be 512 regardless of spi flash page size
usb_msc.setCapacity(
Arcada_QSPI_Flash.pageSize() * Arcada_QSPI_Flash.numPages() / 512, 512);
// MSC is ready for read/write
usb_msc.setUnitReady(true);
usb_msc.begin();
// re-attach to usb bus
USBDevice.attach();
return true;
}
#endif
return false;
}
/**************************************************************************/
/*!
@brief Hints whether we're doing a bunch of USB stuff recently
@param timeout The timeperiod to look at, defaults to 100ms
@return True if some USB stuff happened in last timeout # millis
*/
/**************************************************************************/
bool Adafruit_Arcada_SPITFT::recentUSB(uint32_t timeout) {
(void)timeout;
#if defined(USE_TINYUSB)
uint32_t curr_time = millis();
if (last_access_ms > curr_time) { // oi, rollover
return false;
}
if ((last_access_ms + timeout) >= curr_time) {
return true; // indeed!
}
#endif
return false;
}
// Callback invoked when received READ10 command.
// Copy disk's data to buffer (up to bufsize) and
// return number of copied bytes (must be multiple of block size)
int32_t qspi_msc_read_cb(uint32_t lba, void *buffer, uint32_t bufsize) {
#ifdef ARCADA_MSD_DEBUG
Serial.printf("QSPI Read block %08x\n", lba);
#endif
// Note: SPIFLash Bock API: readBlocks/writeBlocks/syncBlocks
// already include 4K sector caching internally. We don't need to cache it,
// yahhhh!!
return Arcada_QSPI_Flash.readBlocks(lba, (uint8_t *)buffer, bufsize / 512)
? bufsize
: -1;
}
// Callback invoked when received WRITE10 command.
// Process data in buffer to disk's storage and
// return number of written bytes (must be multiple of block size)
int32_t qspi_msc_write_cb(uint32_t lba, uint8_t *buffer, uint32_t bufsize) {
#ifdef ARCADA_MSD_DEBUG
Serial.printf("QSPI Write block %08x\n", lba);
#endif
// Note: SPIFLash Bock API: readBlocks/writeBlocks/syncBlocks
// already include 4K sector caching internally. We don't need to cache it,
// yahhhh!!
return Arcada_QSPI_Flash.writeBlocks(lba, buffer, bufsize / 512) ? bufsize
: -1;
}
// Callback invoked when WRITE10 command is completed (status received and
// accepted by host). used to flush any pending cache.
void qspi_msc_flush_cb(void) {
#ifdef ARCADA_MSD_DEBUG
Serial.printf("QSPI Flush block\n");
#endif
// sync with flash
Arcada_QSPI_Flash.syncBlocks();
// clear file system's cache to force refresh
Arcada_QSPI_FileSys.cacheClear();
last_access_ms = millis();
}
// Callback invoked when received READ10 command.
// Copy disk's data to buffer (up to bufsize) and
// return number of copied bytes (must be multiple of block size)
int32_t sd_msc_read_cb(uint32_t lba, void *buffer, uint32_t bufsize) {
#ifdef ARCADA_MSD_DEBUG
Serial.printf("SD Read block %08x\n", lba);
#endif
return Arcada_SD_FileSys.card()->readBlocks(lba, (uint8_t *)buffer,
bufsize / 512)
? bufsize
: -1;
}
// Callback invoked when received WRITE10 command.
// Process data in buffer to disk's storage and
// return number of written bytes (must be multiple of block size)
int32_t sd_msc_write_cb(uint32_t lba, uint8_t *buffer, uint32_t bufsize) {
#ifdef ARCADA_MSD_DEBUG
Serial.printf("SD Write block %08x\n", lba);
#endif
return Arcada_SD_FileSys.card()->writeBlocks(lba, buffer, bufsize / 512)
? bufsize
: -1;
}
// Callback invoked when WRITE10 command is completed (status received and
// accepted by host). used to flush any pending cache.
void sd_msc_flush_cb(void) {
#ifdef ARCADA_MSD_DEBUG
Serial.printf("SD Flush block\n");
#endif
Arcada_SD_FileSys.card()->syncBlocks();
// clear file system's cache to force refresh
Arcada_SD_FileSys.cacheClear();
last_access_ms = millis();
}