Skip to content

Commit

Permalink
Add USB mass storage
Browse files Browse the repository at this point in the history
  • Loading branch information
rennancockles committed Mar 7, 2025
1 parent 580a04d commit 877de70
Show file tree
Hide file tree
Showing 4 changed files with 255 additions and 4 deletions.
198 changes: 198 additions & 0 deletions src/core/massStorage.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
#include "massStorage.h"
#include "core/display.h"
#include <USB.h>

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()) {
displayError("SD card not found.");
delay(1000);
return;
}

beginUsb();

delay(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 = SD.sectorSize();
uint32_t numSectors = SD.numSectors();

msc.vendorID("ESP32");
msc.productID("BRUCE");
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<arduino_usb_event_data_t*>(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) {
drawMainBorderWithTitle("Mass Storage");
padprintln("");
padprintln(message);
}


int32_t usbWriteCallback(uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize) {
// Verify freespace
uint64_t freeSpace = SD.totalBytes() - SD.usedBytes();
if (bufsize > freeSpace) {
return -1; // no space available
}

// Verify sector size
const uint32_t secSize = SD.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 (!SD.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 = SD.sectorSize();
if (secSize == 0) return -1; // disk error

// Read blocs
for (uint32_t x = 0; x < bufsize / secSize; ++x) {
if (!SD.readRAW(reinterpret_cast<uint8_t*>(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) {
MassStorage::displayMessage("");

float scale;
if (bruceConfig.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, 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);
}
51 changes: 51 additions & 0 deletions src/core/massStorage.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#ifndef __MASS_STORAGE_H__
#define __MASS_STORAGE_H__

#include <globals.h>
#include <USBMSC.h>


class MassStorage {
public:
static bool shouldStop;

/////////////////////////////////////////////////////////////////////////////////////
// Constructor
/////////////////////////////////////////////////////////////////////////////////////
MassStorage();
~MassStorage();

/////////////////////////////////////////////////////////////////////////////////////
// Life Cycle
/////////////////////////////////////////////////////////////////////////////////////
void setup();
void loop();

/////////////////////////////////////////////////////////////////////////////////////
// Operations
/////////////////////////////////////////////////////////////////////////////////////
static void setShouldStop(bool value) { shouldStop = value; }

/////////////////////////////////////////////////////////////////////////////////////
// Display functions
/////////////////////////////////////////////////////////////////////////////////////
static void displayMessage(String message);

private:
USBMSC msc;

/////////////////////////////////////////////////////////////////////////////////////
// Setup
/////////////////////////////////////////////////////////////////////////////////////
void beginUsb(void);
void setupUsbCallback(void);
void setupUsbEvent(void);
};

int32_t usbWriteCallback(uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize);
int32_t usbReadCallback(uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize);
bool usbStartStopCallback(uint8_t power_condition, bool start, bool load_eject);

void drawUSBStickIcon(bool plugged);

#endif // MASS_STORAGE_H
8 changes: 4 additions & 4 deletions src/core/menu_items/ConfigMenu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,24 +26,24 @@ void ConfigMenu::optionsMenu() {
{"Sleep", [=]() { setSleepMode(); }},
{"Factory Reset", [=]() { bruceConfig.factoryReset(); }},
{"Restart", [=]() { ESP.restart(); }},
{"About", [=]() { showDeviceInfo(); }},
};

#if defined(T_EMBED_1101)
options.emplace_back("Turn-off", [=]() { powerOff(); });
options.emplace_back("DeepSleep", [=]() { digitalWrite(PIN_POWER_ON,LOW); esp_sleep_enable_ext0_wakeup(GPIO_NUM_6,LOW); esp_deep_sleep_start(); });
options.emplace_back("Turn-off", [=]() { powerOff(); });
options.emplace_back("Deep Sleep", [=]() { digitalWrite(PIN_POWER_ON,LOW); esp_sleep_enable_ext0_wakeup(GPIO_NUM_6,LOW); esp_deep_sleep_start(); });
#elif defined(T_DISPLAY_S3)
options.emplace_back("Turn-off", [=]()
{
tft.fillScreen(TFT_BLACK);
digitalWrite(PIN_POWER_ON, LOW);
digitalWrite(TFT_BL, LOW);
tft.writecommand(0x10);
esp_deep_sleep_start();
esp_deep_sleep_start();
});
#endif
if (bruceConfig.devMode) options.emplace_back("Dev Mode", [=]() { devMenu(); });

options.emplace_back("About", [=]() { showDeviceInfo(); });
options.emplace_back("Main Menu", [=]() { backToMenu(); });

loopOptions(options,false,true,"Config");
Expand Down
2 changes: 2 additions & 0 deletions src/core/menu_items/FileMenu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@
#include "core/sd_functions.h"
#include "modules/others/webInterface.h"
#include "core/utils.h"
#include "core/massStorage.h"

void FileMenu::optionsMenu() {
options = {
{"SD Card", [=]() { loopSD(SD); }},
{"LittleFS", [=]() { loopSD(LittleFS); }},
{"WebUI", [=]() { loopOptionsWebUi(); }},
{"Mass Storage", [=]() { MassStorage(); }},
{"Main Menu", [=]() { backToMenu(); }},
};

Expand Down

0 comments on commit 877de70

Please sign in to comment.