I want both, a Config file on the MSC and also FW Update via USB.
Right now I can choose on a Hold Button which should be done.
But it shows always two Drives instead of one. One Drive is empty and the other one is with a file.
What do I need to change, that only one Drive is shown?
#if ARDUINO_USB_MODE
#warning This sketch should be used when USB is in OTG mode
void setup() {}
void loop() {}
#else
#include "USB.h"
#include "FirmwareMSC.h"
#include "USBMSC.h"
#include "FFat.h"
#include "FS.h"
#if !ARDUINO_USB_MSC_ON_BOOT
FirmwareMSC MSC_Update;
// USB Mass Storage Class (MSC) object
USBMSC msc;
#endif
#if ARDUINO_USB_CDC_ON_BOOT
#define HWSerial Serial0
#define USBSerial Serial
#else
#define HWSerial Serial
USBCDC USBSerial;
#endif
#endif
// Block size of flash memory (in bytes) (4KB)
#define BLOCK_SIZE 4096
// Flash memory object
EspClass _flash;
// Partition information object
const esp_partition_t* Partition;
void listDir(fs::FS& fs, const char* dirname, int numTabs = 0);
const esp_partition_t* partition() {
// Return the first FAT partition found (should be the only one)
return esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_FAT, NULL);
}
static int32_t onWrite(uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize) {
//Serial.println("Write lba: " + String(lba) + " offset: " + String(offset) + " bufsize: " + String(bufsize));
// Erase block before writing as to not leave any garbage
_flash.partitionEraseRange(Partition, offset + (lba * BLOCK_SIZE), bufsize);
// Write data to flash memory in blocks from buffer
_flash.partitionWrite(Partition, offset + (lba * BLOCK_SIZE), (uint32_t*)buffer, bufsize);
return bufsize;
}
static int32_t onRead(uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize) {
//Serial.println("Read lba: " + String(lba) + " offset: " + String(offset) + " bufsize: " + String(bufsize));
// Read data from flash memory in blocks and store in buffer
_flash.partitionRead(Partition, offset + (lba * BLOCK_SIZE), (uint32_t*)buffer, bufsize);
return bufsize;
}
static bool onStartStop(uint8_t power_condition, bool start, bool load_eject) {
return true;
}
static void usbEventCallback(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) {
if (event_base == ARDUINO_USB_EVENTS) {
arduino_usb_event_data_t * data = (arduino_usb_event_data_t*)event_data;
switch (event_id) {
case ARDUINO_USB_STARTED_EVENT:
HWSerial.println("USB PLUGGED");
break;
case ARDUINO_USB_STOPPED_EVENT:
HWSerial.println("USB UNPLUGGED");
break;
case ARDUINO_USB_SUSPEND_EVENT:
HWSerial.printf("USB SUSPENDED: remote_wakeup_en: %u\n", data->suspend.remote_wakeup_en);
break;
case ARDUINO_USB_RESUME_EVENT:
HWSerial.println("USB RESUMED");
break;
default:
break;
}
} else if (event_base == ARDUINO_FIRMWARE_MSC_EVENTS) {
arduino_firmware_msc_event_data_t * data = (arduino_firmware_msc_event_data_t*)event_data;
switch (event_id) {
case ARDUINO_FIRMWARE_MSC_START_EVENT:
HWSerial.println("MSC Update Start");
break;
case ARDUINO_FIRMWARE_MSC_WRITE_EVENT:
//HWSerial.printf("MSC Update Write %u bytes at offset %u\n", data->write.size, data->write.offset);
HWSerial.print(".");
break;
case ARDUINO_FIRMWARE_MSC_END_EVENT:
HWSerial.printf("\nMSC Update End: %u bytes\n", data->end.size);
break;
case ARDUINO_FIRMWARE_MSC_ERROR_EVENT:
HWSerial.printf("MSC Update ERROR! Progress: %u bytes\n", data->error.size);
break;
case ARDUINO_FIRMWARE_MSC_POWER_EVENT:
HWSerial.printf("MSC Update Power: power: %u, start: %u, eject: %u", data->power.power_condition, data->power.start, data->power.load_eject);
break;
default:
break;
}
}
}
void setup() {
HWSerial.begin(115200);
HWSerial.setDebugOutput(true);
Serial.begin(115200);
Serial.println("Starting Serial");
Serial.println("Initializing FFat");
pinMode(0, INPUT);
pinMode(17, OUTPUT);
digitalWrite(17, LOW);
delay(3000);
// False for the msc mode and True for internal filesystem mode
// Since both cannot write to the same table at the same time
if (digitalRead(0)) {
// begin(true) will format on fail
if (!FFat.begin()) {
Serial.println("Mount Failed, formatting...");
// If mount fails, format the partition (Feels cleaner than FFat.begin(true))
if (FFat.format(FFAT_WIPE_FULL)) {
Serial.println("Format Success");
} else {
Serial.println("Format Failed");
}
} else {
Serial.println("fat success");
}
Serial.println("Listing before");
listDir(FFat, "/");
if (!FFat.exists("/config.json")) {
Serial.println("Creating file");
// Create a file | use F("...") on file paths or it creates weird problems (idk why)
File f = FFat.open(F("/config.json"), FILE_WRITE, true);
// Write to file (using F("...") here just to be safe)
f.println(F("{\n \"r\": 255,\n \"g\": 0,\n \"b\": 0,\n \"w\": 0,\n \"offset\": 0\n}"));
// Close and flush file (Not sure if flush is needed, but there to be safe)
f.flush();
f.close();
Serial.println("Listing After");
// Print directory contents
listDir(FFat, "/");
}
} else {
digitalWrite(17, HIGH);
delay(3000);
Serial.println("Initializing MSC");
// Initialize USB metadata and callbacks for MSC (Mass Storage Class)
if (digitalRead(0)) {
Serial.println("Getting partition info");
// Get partition information
Partition = partition();
msc.vendorID("ESP32");
msc.productID("USB_MSC");
msc.productRevision("1.0");
msc.onRead(onRead);
msc.onWrite(onWrite);
msc.onStartStop(onStartStop);
msc.mediaPresent(true);
msc.begin(Partition->size / BLOCK_SIZE, BLOCK_SIZE);
digitalWrite(17, HIGH);
} else {
MSC_Update.onEvent(usbEventCallback);
MSC_Update.begin();
digitalWrite(17, LOW);
}
USBSerial.begin();
Serial.println("Initializing USB");
USB.begin();
Serial.println("Printing flash size");
//Print flash size
char buff[50];
sprintf(buff, "Flash Size: %d", Partition->size);
Serial.println(buff);
}
}
void loop() {
delay(5000);
}
void listDir(fs::FS& fs, const char* dirname, int numTabs) {
File dir = fs.open(F(dirname));
if (!dir) {
Serial.print("Failed to open directory: ");
Serial.println(dirname);
return;
}
if (!dir.isDirectory()) {
Serial.println("Not a directory");
return;
}
while (true) {
File file = dir.openNextFile();
if (!file) {
// no more files
break;
}
for (uint8_t i = 0; i < numTabs; i++) {
Serial.print('\t');
}
Serial.print(file.name());
if (file.isDirectory()) {
Serial.println("/");
// Ugly string concatenation to get the full path
listDir(fs, ((std::string)"/" + (std::string)file.name()).c_str(), numTabs + 1);
} else {
// files have sizes, directories do not
Serial.print("\t\t\tSize: ");
Serial.println(file.size(), DEC);
}
file.close();
}
}