USB mass storage driver (#146)
This commit is contained in:
parent
ec90198dbf
commit
a9e890a7f3
@ -4,4 +4,8 @@ dependencies:
|
|||||||
espressif/esp_lcd_touch_gt911: "1.1.1~2"
|
espressif/esp_lcd_touch_gt911: "1.1.1~2"
|
||||||
espressif/esp_lcd_touch_ft5x06: "1.0.6~1"
|
espressif/esp_lcd_touch_ft5x06: "1.0.6~1"
|
||||||
espressif/esp_lcd_touch: "1.1.2"
|
espressif/esp_lcd_touch: "1.1.2"
|
||||||
|
espressif/esp_tinyusb:
|
||||||
|
version: "1.5.0"
|
||||||
|
rules:
|
||||||
|
- if: "target == esp32s3"
|
||||||
idf: '5.3.2'
|
idf: '5.3.2'
|
||||||
|
|||||||
@ -32,13 +32,13 @@ if (DEFINED ENV{ESP_IDF_VERSION})
|
|||||||
|
|
||||||
set(EXCLUDE_COMPONENTS "Simulator")
|
set(EXCLUDE_COMPONENTS "Simulator")
|
||||||
|
|
||||||
# ESP32 boards
|
# Non-ESP32 boards
|
||||||
if(NOT "${IDF_TARGET}" STREQUAL "esp32")
|
if(NOT "${IDF_TARGET}" STREQUAL "esp32")
|
||||||
set(EXCLUDE_COMPONENTS "YellowBoard")
|
set(EXCLUDE_COMPONENTS "YellowBoard")
|
||||||
set(EXCLUDE_COMPONENTS "M5stackCore2")
|
set(EXCLUDE_COMPONENTS "M5stackCore2")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# ESP32-S3 boards
|
# Non-ESP32-S3 boards
|
||||||
if(NOT "${IDF_TARGET}" STREQUAL "esp32s3")
|
if(NOT "${IDF_TARGET}" STREQUAL "esp32s3")
|
||||||
set(EXCLUDE_COMPONENTS "LilygoTdeck")
|
set(EXCLUDE_COMPONENTS "LilygoTdeck")
|
||||||
set(EXCLUDE_COMPONENTS "M5stackCoreS3")
|
set(EXCLUDE_COMPONENTS "M5stackCoreS3")
|
||||||
|
|||||||
BIN
Data/assets/boot_logo_usb.png
Normal file
BIN
Data/assets/boot_logo_usb.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 688 B |
41
Data/assets_sources/boot_logo_usb.svg
Normal file
41
Data/assets_sources/boot_logo_usb.svg
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
height="24px"
|
||||||
|
viewBox="0 -960 960 960"
|
||||||
|
width="24px"
|
||||||
|
fill="#e8eaed"
|
||||||
|
version="1.1"
|
||||||
|
id="svg1"
|
||||||
|
sodipodi:docname="boot_logo_usb.svg"
|
||||||
|
inkscape:export-filename="../assets/boot_logo_usb.png"
|
||||||
|
inkscape:export-xdpi="192"
|
||||||
|
inkscape:export-ydpi="192"
|
||||||
|
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<defs
|
||||||
|
id="defs1" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="namedview1"
|
||||||
|
pagecolor="#505050"
|
||||||
|
bordercolor="#eeeeee"
|
||||||
|
borderopacity="1"
|
||||||
|
inkscape:showpageshadow="0"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:deskcolor="#d1d1d1"
|
||||||
|
inkscape:zoom="27.5"
|
||||||
|
inkscape:cx="12.018182"
|
||||||
|
inkscape:cy="12"
|
||||||
|
inkscape:window-width="1503"
|
||||||
|
inkscape:window-height="930"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="svg1" />
|
||||||
|
<path
|
||||||
|
d="M480-80q-33 0-56.5-23.5T400-160q0-21 11-39t29-29v-92H320q-33 0-56.5-23.5T240-400v-92q-18-9-29-27t-11-41q0-33 23.5-56.5T280-640q33 0 56.5 23.5T360-560q0 23-11 40t-29 28v92h120v-320h-80l120-160 120 160h-80v320h120v-80h-40v-160h160v160h-40v80q0 33-23.5 56.5T640-320H520v92q19 10 29.5 28t10.5 40q0 33-23.5 56.5T480-80Z"
|
||||||
|
id="path1" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.5 KiB |
@ -54,6 +54,7 @@ namespace app {
|
|||||||
namespace settings { extern const AppManifest manifest; }
|
namespace settings { extern const AppManifest manifest; }
|
||||||
namespace systeminfo { extern const AppManifest manifest; }
|
namespace systeminfo { extern const AppManifest manifest; }
|
||||||
namespace textviewer { extern const AppManifest manifest; }
|
namespace textviewer { extern const AppManifest manifest; }
|
||||||
|
namespace usbsettings { extern const AppManifest manifest; }
|
||||||
namespace wifiapsettings { extern const AppManifest manifest; }
|
namespace wifiapsettings { extern const AppManifest manifest; }
|
||||||
namespace wificonnect { extern const AppManifest manifest; }
|
namespace wificonnect { extern const AppManifest manifest; }
|
||||||
namespace wifimanage { extern const AppManifest manifest; }
|
namespace wifimanage { extern const AppManifest manifest; }
|
||||||
@ -86,6 +87,7 @@ static const std::vector<const app::AppManifest*> system_apps = {
|
|||||||
&app::selectiondialog::manifest,
|
&app::selectiondialog::manifest,
|
||||||
&app::systeminfo::manifest,
|
&app::systeminfo::manifest,
|
||||||
&app::textviewer::manifest,
|
&app::textviewer::manifest,
|
||||||
|
&app::usbsettings::manifest,
|
||||||
&app::wifiapsettings::manifest,
|
&app::wifiapsettings::manifest,
|
||||||
&app::wificonnect::manifest,
|
&app::wificonnect::manifest,
|
||||||
&app::wifimanage::manifest,
|
&app::wifimanage::manifest,
|
||||||
|
|||||||
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#include "lvgl.h"
|
#include "lvgl.h"
|
||||||
#include "Tactility.h"
|
#include "Tactility.h"
|
||||||
|
#include "hal/usb/Usb.h"
|
||||||
|
|
||||||
#ifdef ESP_PLATFORM
|
#ifdef ESP_PLATFORM
|
||||||
#include "kernel/PanicHandler.h"
|
#include "kernel/PanicHandler.h"
|
||||||
@ -31,28 +32,32 @@ struct Data {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static int32_t bootThreadCallback(TT_UNUSED void* context) {
|
static int32_t bootThreadCallback(TT_UNUSED void* context) {
|
||||||
TickType_t start_time = tt::kernel::getTicks();
|
TickType_t start_time = kernel::getTicks();
|
||||||
|
|
||||||
auto* lvgl_display = lv_display_get_default();
|
auto* lvgl_display = lv_display_get_default();
|
||||||
tt_assert(lvgl_display != nullptr);
|
tt_assert(lvgl_display != nullptr);
|
||||||
auto* hal_display = (tt::hal::Display*)lv_display_get_user_data(lvgl_display);
|
auto* hal_display = (hal::Display*)lv_display_get_user_data(lvgl_display);
|
||||||
tt_assert(hal_display != nullptr);
|
tt_assert(hal_display != nullptr);
|
||||||
if (hal_display->supportsBacklightDuty()) {
|
if (hal_display->supportsBacklightDuty()) {
|
||||||
int32_t backlight_duty = app::display::getBacklightDuty();
|
int32_t backlight_duty = app::display::getBacklightDuty();
|
||||||
hal_display->setBacklightDuty(backlight_duty);
|
hal_display->setBacklightDuty(backlight_duty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hal::usb::isUsbBootMode()) {
|
||||||
|
TT_LOG_I(TAG, "Rebooting into mass storage device mode");
|
||||||
|
hal::usb::resetUsbBootMode();
|
||||||
|
hal::usb::startMassStorageWithSdmmc();
|
||||||
|
} else {
|
||||||
TickType_t end_time = tt::kernel::getTicks();
|
TickType_t end_time = tt::kernel::getTicks();
|
||||||
TickType_t ticks_passed = end_time - start_time;
|
TickType_t ticks_passed = end_time - start_time;
|
||||||
TickType_t minimum_ticks = (CONFIG_TT_SPLASH_DURATION / portTICK_PERIOD_MS);
|
TickType_t minimum_ticks = (CONFIG_TT_SPLASH_DURATION / portTICK_PERIOD_MS);
|
||||||
if (minimum_ticks > ticks_passed) {
|
if (minimum_ticks > ticks_passed) {
|
||||||
tt::kernel::delayTicks(minimum_ticks - ticks_passed);
|
kernel::delayTicks(minimum_ticks - ticks_passed);
|
||||||
}
|
}
|
||||||
|
|
||||||
tt::service::loader::stopApp();
|
tt::service::loader::stopApp();
|
||||||
|
|
||||||
|
|
||||||
startNextApp();
|
startNextApp();
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -84,7 +89,13 @@ static void onShow(TT_UNUSED AppContext& app, lv_obj_t* parent) {
|
|||||||
|
|
||||||
lv_obj_t* image = lv_image_create(parent);
|
lv_obj_t* image = lv_image_create(parent);
|
||||||
lv_obj_set_size(image, LV_PCT(100), LV_PCT(100));
|
lv_obj_set_size(image, LV_PCT(100), LV_PCT(100));
|
||||||
|
|
||||||
|
if (hal::usb::isUsbBootMode()) {
|
||||||
|
lv_image_set_src(image, TT_ASSETS_BOOT_LOGO_USB);
|
||||||
|
} else {
|
||||||
lv_image_set_src(image, TT_ASSETS_BOOT_LOGO);
|
lv_image_set_src(image, TT_ASSETS_BOOT_LOGO);
|
||||||
|
}
|
||||||
|
|
||||||
lvgl::obj_set_style_bg_blacken(parent);
|
lvgl::obj_set_style_bg_blacken(parent);
|
||||||
|
|
||||||
data->thread.start();
|
data->thread.start();
|
||||||
|
|||||||
45
Tactility/Source/app/usbsettings/UsbSettings.cpp
Normal file
45
Tactility/Source/app/usbsettings/UsbSettings.cpp
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
#include "lvgl.h"
|
||||||
|
#include "lvgl/Toolbar.h"
|
||||||
|
#include "hal/usb/Usb.h"
|
||||||
|
|
||||||
|
#define TAG "usb_settings"
|
||||||
|
|
||||||
|
namespace tt::app::usbsettings {
|
||||||
|
|
||||||
|
static void onRebootMassStorage(TT_UNUSED lv_event_t* event) {
|
||||||
|
hal::usb::rebootIntoMassStorageSdmmc();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void onShow(AppContext& app, lv_obj_t* parent) {
|
||||||
|
auto* toolbar = lvgl::toolbar_create(parent, app);
|
||||||
|
lv_obj_align(toolbar, LV_ALIGN_TOP_MID, 0, 0);
|
||||||
|
|
||||||
|
if (hal::usb::canRebootIntoMassStorageSdmmc()) {
|
||||||
|
auto* button = lv_button_create(parent);
|
||||||
|
auto* label = lv_label_create(button);
|
||||||
|
lv_label_set_text(label, "Reboot as USB storage");
|
||||||
|
lv_obj_align(button, LV_ALIGN_CENTER, 0, 0);
|
||||||
|
lv_obj_add_event_cb(button, onRebootMassStorage, LV_EVENT_SHORT_CLICKED, nullptr);
|
||||||
|
} else {
|
||||||
|
bool supported = hal::usb::isSupported();
|
||||||
|
const char* first = supported ? "USB storage not available:" : "USB driver not supported";
|
||||||
|
const char* second = supported ? "SD card not mounted" : "on this hardware";
|
||||||
|
auto* label_a = lv_label_create(parent);
|
||||||
|
lv_label_set_text(label_a, first);
|
||||||
|
lv_obj_align(label_a, LV_ALIGN_CENTER, 0, 0);
|
||||||
|
auto* label_b = lv_label_create(parent);
|
||||||
|
lv_label_set_text(label_b, second);
|
||||||
|
lv_obj_align_to(label_b, label_a, LV_ALIGN_OUT_BOTTOM_MID, 0, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extern const AppManifest manifest = {
|
||||||
|
.id = "UsbSettings",
|
||||||
|
.name = "USB",
|
||||||
|
.icon = LV_SYMBOL_USB,
|
||||||
|
.type = TypeSettings,
|
||||||
|
.onShow = onShow
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
@ -6,11 +6,16 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
|||||||
if (DEFINED ENV{ESP_IDF_VERSION})
|
if (DEFINED ENV{ESP_IDF_VERSION})
|
||||||
file(GLOB_RECURSE SOURCE_FILES Source/*.c*)
|
file(GLOB_RECURSE SOURCE_FILES Source/*.c*)
|
||||||
|
|
||||||
|
list(APPEND REQUIRES_LIST TactilityCore esp_wifi nvs_flash driver spiffs vfs fatfs )
|
||||||
|
if("${IDF_TARGET}" STREQUAL "esp32s3")
|
||||||
|
list(APPEND REQUIRES_LIST esp_tinyusb)
|
||||||
|
endif()
|
||||||
|
|
||||||
idf_component_register(
|
idf_component_register(
|
||||||
SRCS ${SOURCE_FILES}
|
SRCS ${SOURCE_FILES}
|
||||||
INCLUDE_DIRS "Source/"
|
INCLUDE_DIRS "Source/"
|
||||||
PRIV_INCLUDE_DIRS "Private/"
|
PRIV_INCLUDE_DIRS "Private/"
|
||||||
REQUIRES TactilityCore esp_wifi nvs_flash driver spiffs vfs fatfs
|
REQUIRES ${REQUIRES_LIST}
|
||||||
)
|
)
|
||||||
|
|
||||||
if (NOT DEFINED TACTILITY_SKIP_SPIFFS)
|
if (NOT DEFINED TACTILITY_SKIP_SPIFFS)
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
// Splash
|
// Splash
|
||||||
#define TT_ASSETS_BOOT_LOGO TT_ASSET("boot_logo.png")
|
#define TT_ASSETS_BOOT_LOGO TT_ASSET("boot_logo.png")
|
||||||
|
#define TT_ASSETS_BOOT_LOGO_USB TT_ASSET("boot_logo_usb.png")
|
||||||
|
|
||||||
// UI
|
// UI
|
||||||
#define TT_ASSETS_UI_SPINNER TT_ASSET("spinner.png")
|
#define TT_ASSETS_UI_SPINNER TT_ASSET("spinner.png")
|
||||||
|
|||||||
@ -73,6 +73,8 @@ public:
|
|||||||
bool mount(const char* mountPath) override;
|
bool mount(const char* mountPath) override;
|
||||||
bool unmount() override;
|
bool unmount() override;
|
||||||
State getState() const override;
|
State getState() const override;
|
||||||
|
|
||||||
|
sdmmc_card_t* _Nullable getCard() { return card; }
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
108
TactilityHeadless/Source/hal/usb/Usb.cpp
Normal file
108
TactilityHeadless/Source/hal/usb/Usb.cpp
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
#ifdef ESP_PLATFORM
|
||||||
|
|
||||||
|
#include <Log.h>
|
||||||
|
#include "Usb.h"
|
||||||
|
#include "UsbTusb.h"
|
||||||
|
#include "TactilityHeadless.h"
|
||||||
|
#include "hal/SpiSdCard.h"
|
||||||
|
|
||||||
|
namespace tt::hal::usb {
|
||||||
|
|
||||||
|
#define TAG "usb"
|
||||||
|
|
||||||
|
#define BOOT_FLAG 42
|
||||||
|
|
||||||
|
struct BootMode {
|
||||||
|
uint32_t flag = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
static Mode currentMode = ModeDefault;
|
||||||
|
static RTC_NOINIT_ATTR BootMode bootMode;
|
||||||
|
|
||||||
|
sdmmc_card_t* _Nullable getCard() {
|
||||||
|
auto sdcard = getConfiguration().sdcard;
|
||||||
|
if (sdcard == nullptr) {
|
||||||
|
TT_LOG_W(TAG, "No SD card configuration found");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sdcard->isMounted()) {
|
||||||
|
TT_LOG_W(TAG, "SD card not mounted");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto spi_sdcard = std::static_pointer_cast<SpiSdCard>(sdcard);
|
||||||
|
if (spi_sdcard == nullptr) {
|
||||||
|
TT_LOG_W(TAG, "SD card interface is not supported (must be SpiSdCard)");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* card = spi_sdcard->getCard();
|
||||||
|
if (card == nullptr) {
|
||||||
|
TT_LOG_W(TAG, "SD card has no card object available");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return card;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool canStartNewMode() {
|
||||||
|
return isSupported() && (currentMode == ModeDefault || currentMode == ModeNone);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isSupported() {
|
||||||
|
return tusbIsSupported();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool startMassStorageWithSdmmc() {
|
||||||
|
if (!canStartNewMode()) {
|
||||||
|
TT_LOG_E(TAG, "Can't start");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto result = tusbStartMassStorageWithSdmmc();
|
||||||
|
if (result != ESP_OK) {
|
||||||
|
TT_LOG_E(TAG, "Failed to init mass storage: %s", esp_err_to_name(result));
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
currentMode = ModeMassStorageSdmmc;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void stop() {
|
||||||
|
if (canStartNewMode()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tusbStop();
|
||||||
|
|
||||||
|
currentMode = ModeNone;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mode getMode() {
|
||||||
|
return currentMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool canRebootIntoMassStorageSdmmc() {
|
||||||
|
return tusbIsSupported() && getCard() != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rebootIntoMassStorageSdmmc() {
|
||||||
|
if (tusbIsSupported()) {
|
||||||
|
bootMode.flag = BOOT_FLAG;
|
||||||
|
esp_restart();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isUsbBootMode() {
|
||||||
|
return bootMode.flag == BOOT_FLAG;
|
||||||
|
}
|
||||||
|
|
||||||
|
void resetUsbBootMode() {
|
||||||
|
bootMode.flag = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
21
TactilityHeadless/Source/hal/usb/Usb.h
Normal file
21
TactilityHeadless/Source/hal/usb/Usb.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace tt::hal::usb {
|
||||||
|
|
||||||
|
enum Mode {
|
||||||
|
ModeDefault, // Default state of USB stack
|
||||||
|
ModeNone, // State after TinyUSB was used and (partially) deinitialized
|
||||||
|
ModeMassStorageSdmmc
|
||||||
|
};
|
||||||
|
|
||||||
|
bool startMassStorageWithSdmmc();
|
||||||
|
void stop();
|
||||||
|
Mode getMode();
|
||||||
|
bool isSupported();
|
||||||
|
|
||||||
|
bool canRebootIntoMassStorageSdmmc();
|
||||||
|
void rebootIntoMassStorageSdmmc();
|
||||||
|
bool isUsbBootMode();
|
||||||
|
void resetUsbBootMode();
|
||||||
|
|
||||||
|
}
|
||||||
21
TactilityHeadless/Source/hal/usb/UsbMock.cpp
Normal file
21
TactilityHeadless/Source/hal/usb/UsbMock.cpp
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#ifndef ESP_PLATFORM
|
||||||
|
|
||||||
|
#include "Usb.h"
|
||||||
|
|
||||||
|
#define TAG "usb"
|
||||||
|
|
||||||
|
namespace tt::hal::usb {
|
||||||
|
|
||||||
|
bool startMassStorageWithSdmmc() { return false; }
|
||||||
|
void stop() {}
|
||||||
|
Mode getMode() { return ModeDefault; }
|
||||||
|
bool isSupported() { return false; }
|
||||||
|
|
||||||
|
bool canRebootIntoMassStorageSdmmc() { return false; }
|
||||||
|
void rebootIntoMassStorageSdmmc() {}
|
||||||
|
bool isUsbBootMode() { return false; }
|
||||||
|
void resetUsbBootMode() {}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
167
TactilityHeadless/Source/hal/usb/UsbTusb.cpp
Normal file
167
TactilityHeadless/Source/hal/usb/UsbTusb.cpp
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
#ifdef ESP_PLATFORM
|
||||||
|
|
||||||
|
#include "UsbTusb.h"
|
||||||
|
#include "sdkconfig.h"
|
||||||
|
|
||||||
|
#if CONFIG_TINYUSB_MSC_ENABLED == 1
|
||||||
|
|
||||||
|
#include "Log.h"
|
||||||
|
#include "tinyusb.h"
|
||||||
|
#include "tusb_msc_storage.h"
|
||||||
|
|
||||||
|
#define TAG "usb"
|
||||||
|
#define EPNUM_MSC 1
|
||||||
|
#define TUSB_DESC_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_MSC_DESC_LEN)
|
||||||
|
|
||||||
|
namespace tt::hal::usb {
|
||||||
|
extern sdmmc_card_t* _Nullable getCard();
|
||||||
|
}
|
||||||
|
|
||||||
|
enum {
|
||||||
|
ITF_NUM_MSC = 0,
|
||||||
|
ITF_NUM_TOTAL
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
EDPT_CTRL_OUT = 0x00,
|
||||||
|
EDPT_CTRL_IN = 0x80,
|
||||||
|
|
||||||
|
EDPT_MSC_OUT = 0x01,
|
||||||
|
EDPT_MSC_IN = 0x81,
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool driverInstalled = false;
|
||||||
|
|
||||||
|
static tusb_desc_device_t descriptor_config = {
|
||||||
|
.bLength = sizeof(descriptor_config),
|
||||||
|
.bDescriptorType = TUSB_DESC_DEVICE,
|
||||||
|
.bcdUSB = 0x0200,
|
||||||
|
.bDeviceClass = TUSB_CLASS_MISC,
|
||||||
|
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
|
||||||
|
.bDeviceProtocol = MISC_PROTOCOL_IAD,
|
||||||
|
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
|
||||||
|
.idVendor = 0x303A, // TODO: Espressif VID. Do we need to change this?
|
||||||
|
.idProduct = 0x4002,
|
||||||
|
.bcdDevice = 0x100,
|
||||||
|
.iManufacturer = 0x01,
|
||||||
|
.iProduct = 0x02,
|
||||||
|
.iSerialNumber = 0x03,
|
||||||
|
.bNumConfigurations = 0x01
|
||||||
|
};
|
||||||
|
|
||||||
|
static char const* string_desc_arr[] = {
|
||||||
|
(const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
|
||||||
|
"Espressif", // 1: Manufacturer
|
||||||
|
"Tactility Device", // 2: Product
|
||||||
|
"42", // 3: Serials
|
||||||
|
"Tactility Mass Storage", // 4. MSC
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint8_t const msc_fs_configuration_desc[] = {
|
||||||
|
// Config number, interface count, string index, total length, attribute, power in mA
|
||||||
|
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, TUSB_DESC_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
|
||||||
|
|
||||||
|
// Interface number, string index, EP Out & EP In address, EP size
|
||||||
|
TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 0, EDPT_MSC_OUT, EDPT_MSC_IN, 64),
|
||||||
|
};
|
||||||
|
|
||||||
|
#if (TUD_OPT_HIGH_SPEED)
|
||||||
|
static const tusb_desc_device_qualifier_t device_qualifier = {
|
||||||
|
.bLength = sizeof(tusb_desc_device_qualifier_t),
|
||||||
|
.bDescriptorType = TUSB_DESC_DEVICE_QUALIFIER,
|
||||||
|
.bcdUSB = 0x0200,
|
||||||
|
.bDeviceClass = TUSB_CLASS_MISC,
|
||||||
|
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
|
||||||
|
.bDeviceProtocol = MISC_PROTOCOL_IAD,
|
||||||
|
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
|
||||||
|
.bNumConfigurations = 0x01,
|
||||||
|
.bReserved = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint8_t const msc_hs_configuration_desc[] = {
|
||||||
|
// Config number, interface count, string index, total length, attribute, power in mA
|
||||||
|
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, TUSB_DESC_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
|
||||||
|
|
||||||
|
// Interface number, string index, EP Out & EP In address, EP size
|
||||||
|
TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 0, EDPT_MSC_OUT, EDPT_MSC_IN, 512),
|
||||||
|
};
|
||||||
|
#endif // TUD_OPT_HIGH_SPEED
|
||||||
|
|
||||||
|
static void storage_mount_changed_cb(tinyusb_msc_event_t* event) {
|
||||||
|
if (event->mount_changed_data.is_mounted) {
|
||||||
|
TT_LOG_I(TAG, "Mounted");
|
||||||
|
} else {
|
||||||
|
TT_LOG_I(TAG, "Unmounted");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ensureDriverInstalled() {
|
||||||
|
if (driverInstalled) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const tinyusb_config_t tusb_cfg = {
|
||||||
|
.device_descriptor = &descriptor_config,
|
||||||
|
.string_descriptor = string_desc_arr,
|
||||||
|
.string_descriptor_count = sizeof(string_desc_arr) / sizeof(string_desc_arr[0]),
|
||||||
|
.external_phy = false,
|
||||||
|
#if (TUD_OPT_HIGH_SPEED)
|
||||||
|
.fs_configuration_descriptor = msc_fs_configuration_desc,
|
||||||
|
.hs_configuration_descriptor = msc_hs_configuration_desc,
|
||||||
|
.qualifier_descriptor = &device_qualifier,
|
||||||
|
#else
|
||||||
|
.configuration_descriptor = msc_fs_configuration_desc,
|
||||||
|
#endif // TUD_OPT_HIGH_SPEED
|
||||||
|
.self_powered = false,
|
||||||
|
.vbus_monitor_io = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
if (tinyusb_driver_install(&tusb_cfg) != ESP_OK) {
|
||||||
|
TT_LOG_E(TAG, "Failed to install TinyUSB driver");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
driverInstalled = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool tusbIsSupported() { return true; }
|
||||||
|
|
||||||
|
bool tusbStartMassStorageWithSdmmc() {
|
||||||
|
ensureDriverInstalled();
|
||||||
|
|
||||||
|
auto* card = tt::hal::usb::getCard();
|
||||||
|
if (card == nullptr) {
|
||||||
|
TT_LOG_E(TAG, "SD card not mounted");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const tinyusb_msc_sdmmc_config_t config_sdmmc = {
|
||||||
|
.card = card,
|
||||||
|
.callback_mount_changed = storage_mount_changed_cb,
|
||||||
|
.callback_premount_changed = nullptr,
|
||||||
|
.mount_config = {
|
||||||
|
.format_if_mount_failed = false,
|
||||||
|
.max_files = 5,
|
||||||
|
.allocation_unit_size = 0,
|
||||||
|
.disk_status_check_enable = false,
|
||||||
|
.use_one_fat = false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return tinyusb_msc_storage_init_sdmmc(&config_sdmmc) == ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tusbStop() {
|
||||||
|
tinyusb_msc_storage_deinit();
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
bool tusbIsSupported() { return false; }
|
||||||
|
bool tusbStartMassStorageWithSdmmc() { return false; }
|
||||||
|
void tusbStop() {}
|
||||||
|
|
||||||
|
#endif // TinyUSB enabled
|
||||||
|
|
||||||
|
#endif // ESP_PLATFORM
|
||||||
5
TactilityHeadless/Source/hal/usb/UsbTusb.h
Normal file
5
TactilityHeadless/Source/hal/usb/UsbTusb.h
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
bool tusbIsSupported();
|
||||||
|
bool tusbStartMassStorageWithSdmmc();
|
||||||
|
void tusbStop();
|
||||||
@ -24,6 +24,8 @@ CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
|
|||||||
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
|
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
|
||||||
CONFIG_ELF_LOADER_CUSTOMER_SYMBOLS=y
|
CONFIG_ELF_LOADER_CUSTOMER_SYMBOLS=y
|
||||||
CONFIG_FATFS_LFN_HEAP=y
|
CONFIG_FATFS_LFN_HEAP=y
|
||||||
|
CONFIG_TINYUSB_MSC_ENABLED=y
|
||||||
|
CONFIG_TINYUSB_MSC_MOUNT_PATH="/sdcard"
|
||||||
|
|
||||||
# Hardware: Main
|
# Hardware: Main
|
||||||
CONFIG_TT_BOARD_LILYGO_TDECK=y
|
CONFIG_TT_BOARD_LILYGO_TDECK=y
|
||||||
|
|||||||
@ -24,6 +24,8 @@ CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
|
|||||||
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
|
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
|
||||||
CONFIG_ELF_LOADER_CUSTOMER_SYMBOLS=y
|
CONFIG_ELF_LOADER_CUSTOMER_SYMBOLS=y
|
||||||
CONFIG_FATFS_LFN_HEAP=y
|
CONFIG_FATFS_LFN_HEAP=y
|
||||||
|
CONFIG_TINYUSB_MSC_ENABLED=y
|
||||||
|
CONFIG_TINYUSB_MSC_MOUNT_PATH="/sdcard"
|
||||||
|
|
||||||
# Hardware: Main
|
# Hardware: Main
|
||||||
CONFIG_TT_BOARD_M5STACK_CORES3=y
|
CONFIG_TT_BOARD_M5STACK_CORES3=y
|
||||||
|
|||||||
@ -23,6 +23,8 @@ CONFIG_PARTITION_TABLE_CUSTOM=y
|
|||||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
|
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
|
||||||
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
|
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
|
||||||
CONFIG_ELF_LOADER_CUSTOMER_SYMBOLS=y
|
CONFIG_ELF_LOADER_CUSTOMER_SYMBOLS=y
|
||||||
|
CONFIG_TINYUSB_MSC_ENABLED=y
|
||||||
|
CONFIG_TINYUSB_MSC_MOUNT_PATH="/sdcard"
|
||||||
|
|
||||||
# Hardware defaults
|
# Hardware defaults
|
||||||
CONFIG_TT_BOARD_CUSTOM=y
|
CONFIG_TT_BOARD_CUSTOM=y
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user