diff --git a/src/core/massStorage.cpp b/src/core/massStorage.cpp index ab01bc263c..fe90075e72 100644 --- a/src/core/massStorage.cpp +++ b/src/core/massStorage.cpp @@ -1,8 +1,7 @@ - - #include "massStorage.h" #include "core/display.h" #include +#include #if defined(SOC_USB_OTG_SUPPORTED) bool MassStorage::shouldStop = false; int32_t MassStorage::status = -1; @@ -40,10 +39,10 @@ void MassStorage::loop() { if (prev_status != status) { vTaskDelay(100 / portTICK_PERIOD_MS); switch (status) { - case ARDUINO_USB_STARTED_EVENT: drawUSBStickIcon(true); break; + case ARDUINO_USB_STARTED_EVENT: drawUSBStickIcon(true); break; + case ARDUINO_USB_RESUME_EVENT: drawUSBStickIcon(true); break; case ARDUINO_USB_STOPPED_EVENT: drawUSBStickIcon(false); break; - case ARDUINO_USB_SUSPEND_EVENT: MassStorage::displayMessage("USB suspend"); break; - case ARDUINO_USB_RESUME_EVENT: MassStorage::displayMessage("USB resume"); break; + case ARDUINO_USB_SUSPEND_EVENT: drawUSBStickIcon(false); break; default: break; } prev_status = status; @@ -56,6 +55,13 @@ void MassStorage::beginUsb() { setupUsbEvent(); drawUSBStickIcon(false); USB.begin(); + // If USB was already connected before opening mass storage, + // STARTED event already fired before our listener was registered. + // Check and force status so loop() picks it up immediately. + vTaskDelay(300 / portTICK_PERIOD_MS); + if (tud_connected()) { + status = ARDUINO_USB_STARTED_EVENT; + } } void MassStorage::setupUsbCallback() { @@ -132,8 +138,6 @@ bool usbStartStopCallback(uint8_t power_condition, bool start, bool load_eject) } void drawUSBStickIcon(bool plugged) { - static bool first = true; - float scale; if (bruceConfigPins.rotation & 0b01) scale = float((float)tftHeight / (float)135); else scale = float((float)tftWidth / (float)240); @@ -167,17 +171,14 @@ void drawUSBStickIcon(bool plugged) { int ledX = bodyX + 2 * ledW; int ledY = bodyY + (iconH - ledH) / 2; - if (first) { - MassStorage::displayMessage(""); - // Body - tft.fillRoundRect(bodyX, bodyY, bodyW, bodyH, radius, TFT_DARKCYAN); - // Port USB - tft.fillRoundRect(portX, portY, portW, portH, radius, TFT_LIGHTGREY); - // Small square on port - tft.fillRoundRect(portDetailX, portDetailY1, portDetailW, portDetailH, radius, TFT_DARKGREY); - tft.fillRoundRect(portDetailX, portDetailY2, portDetailW, portDetailH, radius, TFT_DARKGREY); - first = false; - } + MassStorage::displayMessage(""); + // Body + tft.fillRoundRect(bodyX, bodyY, bodyW, bodyH, radius, TFT_DARKCYAN); + // Port USB + tft.fillRoundRect(portX, portY, portW, portH, radius, TFT_LIGHTGREY); + // Small square on port + tft.fillRoundRect(portDetailX, portDetailY1, portDetailW, portDetailH, radius, TFT_DARKGREY); + tft.fillRoundRect(portDetailX, portDetailY2, portDetailW, portDetailH, radius, TFT_DARKGREY); // Led tft.fillRoundRect(ledX, ledY, ledW, ledH, radius, plugged ? TFT_GREEN : TFT_RED); } diff --git a/src/core/massStorage_m5_Launcher.cpp b/src/core/massStorage_m5_Launcher.cpp new file mode 100644 index 0000000000..bb8d360dad --- /dev/null +++ b/src/core/massStorage_m5_Launcher.cpp @@ -0,0 +1,188 @@ +#ifdef ARDUINO_USB_MODE + +#include "massStorage.h" +#include "display.h" +#include "sd_functions.h" +#include + +bool MassStorage::shouldStop = false; + +MassStorage::MassStorage() { setup(); } + +MassStorage::~MassStorage() { + msc.end(); + USB.~ESPUSB(); + + // Hack to make USB back to flash mode + USB.enableDFU(); +} + +void MassStorage::setup() { + displayMessage("Mounting..."); + + setShouldStop(false); + + if (!setupSdCard()) { + displayRedStripe("SD card not found."); + delay(1000); + return; + } + + beginUsb(); + + vTaskDelay(pdTICKS_TO_MS(500)); + return loop(); +} + +void MassStorage::loop() { + while (!check(EscPress) && !shouldStop) yield(); +} + +void MassStorage::beginUsb() { + setupUsbCallback(); + setupUsbEvent(); + drawUSBStickIcon(false); + USB.begin(); +} + +void MassStorage::setupUsbCallback() { + uint32_t secSize = SDM.sectorSize(); + uint32_t numSectors = SDM.numSectors(); + + msc.vendorID("ESP32"); + msc.productID("Launcher"); + msc.productRevision("1.0"); + + msc.onRead(usbReadCallback); + msc.onWrite(usbWriteCallback); + msc.onStartStop(usbStartStopCallback); + + msc.mediaPresent(true); + msc.begin(numSectors, secSize); +} + +void MassStorage::setupUsbEvent() { + USB.onEvent([](void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) { + if (event_base == ARDUINO_USB_EVENTS) { + auto *data = reinterpret_cast(event_data); + switch (event_id) { + case ARDUINO_USB_STARTED_EVENT: drawUSBStickIcon(true); break; + case ARDUINO_USB_STOPPED_EVENT: drawUSBStickIcon(false); break; + case ARDUINO_USB_SUSPEND_EVENT: MassStorage::displayMessage("USB suspend"); break; + case ARDUINO_USB_RESUME_EVENT: MassStorage::displayMessage("USB resume"); break; + default: break; + } + } + }); +} + +void MassStorage::displayMessage(String message) { + tft->drawRoundRect(5, 5, tftWidth - 10, tftHeight - 10, 5, ALCOLOR); + tft->fillRoundRect(6, 6, tftWidth - 12, tftHeight - 12, 5, BGCOLOR); + setTftDisplay(7, 7, ALCOLOR, FP, BGCOLOR); + tft->drawCentreString("-= USB MSC =-", tftWidth / 2, 0, 8); + tft->setCursor(10, 20); + tftprint(message, 10, 5); +} + +int32_t usbWriteCallback(uint32_t lba, uint32_t offset, uint8_t *buffer, uint32_t bufsize) { + // Verify freespace + uint64_t freeSpace = SDM.totalBytes() - SDM.usedBytes(); + if (bufsize > freeSpace) { + return -1; // no space available + } + + // Verify sector size + const uint32_t secSize = SDM.sectorSize(); + if (secSize == 0) return -1; // disk error + + // Write blocs + for (uint32_t x = 0; x < bufsize / secSize; ++x) { + uint8_t blkBuffer[secSize]; + memcpy(blkBuffer, buffer + secSize * x, secSize); + if (!SDM.writeRAW(blkBuffer, lba + x)) { + return -1; // write error + } + } + return bufsize; +} + +int32_t usbReadCallback(uint32_t lba, uint32_t offset, void *buffer, uint32_t bufsize) { + // Verify sector size + const uint32_t secSize = SDM.sectorSize(); + if (secSize == 0) return -1; // disk error + + // Read blocs + for (uint32_t x = 0; x < bufsize / secSize; ++x) { + if (!SDM.readRAW(reinterpret_cast(buffer) + (x * secSize), lba + x)) { + return -1; // read error + } + } + return bufsize; +} + +bool usbStartStopCallback(uint8_t power_condition, bool start, bool load_eject) { + if (!start && load_eject) { + MassStorage::setShouldStop(true); + return false; + } + + return true; +} + +void drawUSBStickIcon(bool plugged) { +#ifdef E_PAPER_DISPLAY + tft->stopCallback(); +#endif + MassStorage::displayMessage(""); + + float scale; + if (rotation & 0b01) scale = float((float)tftHeight / (float)135); + else scale = float((float)tftWidth / (float)240); + + int iconW = scale * 120; + int iconH = scale * 40; + + if (iconW % 2 != 0) iconW++; + if (iconH % 2 != 0) iconH++; + + int radius = 5; + + int bodyW = 2 * iconW / 3; + int bodyH = iconH; + int bodyX = tftWidth / 2 - iconW / 2; + int bodyY = tftHeight / 2; + + int portW = iconW - bodyW; + int portH = 0.8 * bodyH; + int portX = bodyX + bodyW; + int portY = bodyY + (bodyH - portH) / 2; + + int portDetailW = portW / 2; + int portDetailH = portH / 4; + int portDetailX = portX + (portW - portDetailW) / 2; + int portDetailY1 = portY + 0.8 * portDetailH; + int portDetailY2 = portY + portH - 1.8 * portDetailH; + + int ledW = 0.1 * bodyH; + int ledH = 0.6 * bodyH; + int ledX = bodyX + 2 * ledW; + int ledY = bodyY + (iconH - ledH) / 2; + + // Body + tft->fillRoundRect(bodyX, bodyY, bodyW, bodyH, radius, DARKCYAN); + // Port USB + tft->fillRoundRect(portX, portY, portW, portH, radius, LIGHTGREY); + // Small square on port + tft->fillRoundRect(portDetailX, portDetailY1, portDetailW, portDetailH, radius, DARKGREY); + tft->fillRoundRect(portDetailX, portDetailY2, portDetailW, portDetailH, radius, DARKGREY); + // Led + tft->fillRoundRect(ledX, ledY, ledW, ledH, radius, plugged ? GREEN : RED); + + tft->display(false); +#ifdef E_PAPER_DISPLAY + tft->startCallback(); +#endif +} + +#endif // ARDUINO_USB_MODE