Skip to content

Commit e07957c

Browse files
committed
Add initial support for USB MSC
1 parent 65eafd1 commit e07957c

File tree

10 files changed

+491
-20
lines changed

10 files changed

+491
-20
lines changed

cores/esp32/USB.cpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,6 @@
3535
#if CFG_TUD_DFU_RUNTIME
3636
static uint16_t load_dfu_descriptor(uint8_t * dst, uint8_t * itf)
3737
{
38-
#define DFU_ATTR_CAN_DOWNLOAD 1
39-
#define DFU_ATTR_CAN_UPLOAD 2
40-
#define DFU_ATTR_MANIFESTATION_TOLERANT 4
41-
#define DFU_ATTR_WILL_DETACH 8
4238
#define DFU_ATTRS (DFU_ATTR_CAN_DOWNLOAD | DFU_ATTR_CAN_UPLOAD | DFU_ATTR_MANIFESTATION_TOLERANT)
4339

4440
uint8_t str_index = tinyusb_add_string_descriptor("TinyUSB DFU_RT");

cores/esp32/USB.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
#include "Arduino.h"
2020
#include "USBCDC.h"
21-
21+
#include "common/tusb_common.h"
2222
#include "esp_event.h"
2323

2424
ESP_EVENT_DECLARE_BASE(ARDUINO_USB_EVENTS);

cores/esp32/esp32-hal-tinyusb.c

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -72,20 +72,15 @@ static void configure_pins(usb_hal_context_t *usb)
7272

7373
esp_err_t tinyusb_driver_install(const tinyusb_config_t *config)
7474
{
75-
log_i("Driver installation...");
76-
77-
// Hal init
7875
usb_hal_context_t hal = {
7976
.use_external_phy = config->external_phy
8077
};
8178
usb_hal_init(&hal);
8279
configure_pins(&hal);
83-
8480
if (!tusb_init()) {
8581
log_e("Can't initialize the TinyUSB stack.");
8682
return ESP_FAIL;
8783
}
88-
log_i("Driver installed");
8984
return ESP_OK;
9085
}
9186

@@ -106,6 +101,7 @@ static tusb_str_t WEBUSB_URL = "";
106101
static tusb_str_t USB_DEVICE_PRODUCT = "";
107102
static tusb_str_t USB_DEVICE_MANUFACTURER = "";
108103
static tusb_str_t USB_DEVICE_SERIAL = "";
104+
static tusb_str_t USB_DEVICE_LANGUAGE = "\x09\x04";//English (0x0409)
109105

110106
static uint8_t USB_DEVICE_ATTRIBUTES = 0;
111107
static uint16_t USB_DEVICE_POWER = 0;
@@ -140,7 +136,7 @@ static tusb_desc_device_t tinyusb_device_descriptor = {
140136
static uint32_t tinyusb_string_descriptor_len = 4;
141137
static char * tinyusb_string_descriptor[MAX_STRING_DESCRIPTORS] = {
142138
// array of pointer to string descriptors
143-
"\x09\x04", // 0: is supported language is English (0x0409)
139+
USB_DEVICE_LANGUAGE, // 0: is supported language
144140
USB_DEVICE_MANUFACTURER,// 1: Manufacturer
145141
USB_DEVICE_PRODUCT, // 2: Product
146142
USB_DEVICE_SERIAL, // 3: Serials, should use chip ID
@@ -563,31 +559,37 @@ static void usb_device_task(void *param) {
563559
/*
564560
* PUBLIC API
565561
* */
562+
static const char *tinyusb_interface_names[USB_INTERFACE_MAX] = {"CDC", "MSC", "DFU", "HID", "VENDOR", "MIDI", "CUSTOM"};
563+
564+
static bool tinyusb_is_initialized = false;
566565

567566
esp_err_t tinyusb_enable_interface(tinyusb_interface_t interface, uint16_t descriptor_len, tinyusb_descriptor_cb_t cb)
568567
{
568+
if(tinyusb_is_initialized){
569+
log_e("TinyUSB has already started! Interface %s not enabled", (interface >= USB_INTERFACE_MAX)?"":tinyusb_interface_names[interface]);
570+
return ESP_FAIL;
571+
}
569572
if((interface >= USB_INTERFACE_MAX) || (tinyusb_loaded_interfaces_mask & (1U << interface))){
570-
log_e("Interface %u not enabled", interface);
573+
log_e("Interface %s invalid or already enabled", (interface >= USB_INTERFACE_MAX)?"":tinyusb_interface_names[interface]);
571574
return ESP_FAIL;
572575
}
573576
tinyusb_loaded_interfaces_mask |= (1U << interface);
574577
tinyusb_config_descriptor_len += descriptor_len;
575578
tinyusb_loaded_interfaces_callbacks[interface] = cb;
576-
log_d("Interface %u enabled", interface);
579+
log_d("Interface %s enabled", tinyusb_interface_names[interface]);
577580
return ESP_OK;
578581
}
579582

580583
esp_err_t tinyusb_init(tinyusb_device_config_t *config) {
581-
static bool initialized = false;
582-
if(initialized){
584+
if(tinyusb_is_initialized){
583585
return ESP_OK;
584586
}
585-
initialized = true;
587+
tinyusb_is_initialized = true;
586588

587589
tinyusb_endpoints.val = 0;
588590
tinyusb_apply_device_config(config);
589591
if (!tinyusb_load_enabled_interfaces()) {
590-
initialized = false;
592+
tinyusb_is_initialized = false;
591593
return ESP_FAIL;
592594
}
593595

@@ -605,7 +607,7 @@ esp_err_t tinyusb_init(tinyusb_device_config_t *config) {
605607
}
606608

607609
if (esp_register_shutdown_handler(usb_persist_shutdown_handler) != ESP_OK) {
608-
initialized = false;
610+
tinyusb_is_initialized = false;
609611
return ESP_FAIL;
610612
}
611613

@@ -614,7 +616,7 @@ esp_err_t tinyusb_init(tinyusb_device_config_t *config) {
614616
};
615617
esp_err_t err = tinyusb_driver_install(&tusb_cfg);
616618
if (err != ESP_OK) {
617-
initialized = false;
619+
tinyusb_is_initialized = false;
618620
return err;
619621
}
620622
xTaskCreate(usb_device_task, "usbd", 4096, NULL, configMAX_PRIORITIES - 1, NULL);

cores/esp32/esp32-hal-tinyusb.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,10 @@ void usb_persist_restart(restart_type_t mode);
8383
// The following definitions and functions are to be used only by the drivers
8484
typedef enum {
8585
USB_INTERFACE_CDC,
86+
USB_INTERFACE_MSC,
8687
USB_INTERFACE_DFU,
8788
USB_INTERFACE_HID,
8889
USB_INTERFACE_VENDOR,
89-
USB_INTERFACE_MSC,
9090
USB_INTERFACE_MIDI,
9191
USB_INTERFACE_CUSTOM,
9292
USB_INTERFACE_MAX

libraries/USB/examples/USBMSC/.skip.esp32

Whitespace-only changes.

libraries/USB/examples/USBMSC/.skip.esp32c3

Whitespace-only changes.
Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
#include "USB.h"
2+
#include "USBMSC.h"
3+
4+
#if ARDUINO_SERIAL_PORT
5+
#define HWSerial Serial0
6+
#define USBSerial Serial
7+
#else
8+
#define HWSerial Serial
9+
//USBCDC USBSerial; // Windows does not like it if both devices are on
10+
#endif
11+
12+
USBMSC MSC;
13+
14+
#define FAT_U8(v) ((v) & 0xFF)
15+
#define FAT_U16(v) FAT_U8(v), FAT_U8((v) >> 8)
16+
#define FAT_U32(v) FAT_U8(v), FAT_U8((v) >> 8), FAT_U8((v) >> 16), FAT_U8((v) >> 24)
17+
#define FAT_MS2B(s,ms) FAT_U8(((((s) & 0x1) * 1000) + (ms)) / 10)
18+
#define FAT_HMS2B(h,m,s) FAT_U8(((s) >> 1)|(((m) & 0x7) << 5)), FAT_U8((((m) >> 3) & 0x7)|((h) << 3))
19+
#define FAT_YMD2B(y,m,d) FAT_U8(((d) & 0x1F)|(((m) & 0x7) << 5)), FAT_U8((((m) >> 3) & 0x1)|((((y) - 1980) & 0x7F) << 1))
20+
21+
#define README_CONTENTS "This is tinyusb's MassStorage Class demo.\r\n\r\nIf you find any bugs or get any questions, feel free to file an\r\nissue at github.com/hathach/tinyusb"
22+
23+
static const uint32_t DISK_SECTOR_COUNT = 2 * 8; // 8KB is the smallest size that windows allow to mount
24+
static const uint16_t DISK_SECTOR_SIZE = 512; // Should be 512
25+
static const uint16_t DISC_SECTORS_PER_TABLE = 1; //each table sector can fit 170KB (340 sectors)
26+
27+
static uint8_t msc_disk[DISK_SECTOR_COUNT][DISK_SECTOR_SIZE] =
28+
{
29+
//------------- Block0: Boot Sector -------------//
30+
{
31+
// Header (62 bytes)
32+
0xEB, 0x3C, 0x90, //jump_instruction
33+
'M' , 'S' , 'D' , 'O' , 'S' , '5' , '.' , '0' , //oem_name
34+
FAT_U16(DISK_SECTOR_SIZE), //bytes_per_sector
35+
FAT_U8(1), //sectors_per_cluster
36+
FAT_U16(1), //reserved_sectors_count
37+
FAT_U8(1), //file_alloc_tables_num
38+
FAT_U16(16), //max_root_dir_entries
39+
FAT_U16(DISK_SECTOR_COUNT), //fat12_sector_num
40+
0xF8, //media_descriptor
41+
FAT_U16(DISC_SECTORS_PER_TABLE), //sectors_per_alloc_table;//FAT12 and FAT16
42+
FAT_U16(1), //sectors_per_track;//A value of 0 may indicate LBA-only access
43+
FAT_U16(1), //num_heads
44+
FAT_U32(0), //hidden_sectors_count
45+
FAT_U32(0), //total_sectors_32
46+
0x00, //physical_drive_number;0x00 for (first) removable media, 0x80 for (first) fixed disk
47+
0x00, //reserved
48+
0x29, //extended_boot_signature;//should be 0x29
49+
FAT_U32(0x1234), //serial_number: 0x1234 => 1234
50+
'T' , 'i' , 'n' , 'y' , 'U' , 'S' , 'B' , ' ' , 'M' , 'S' , 'C' , //volume_label padded with spaces (0x20)
51+
'F' , 'A' , 'T' , '1' , '2' , ' ' , ' ' , ' ' , //file_system_type padded with spaces (0x20)
52+
53+
// Zero up to 2 last bytes of FAT magic code (448 bytes)
54+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
55+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
56+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
57+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
58+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
59+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
60+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
61+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
62+
63+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
64+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
65+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
66+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
67+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
68+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
69+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
70+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
71+
72+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
73+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
74+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
75+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
76+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
77+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
78+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
79+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
80+
81+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
82+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
83+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
84+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
85+
86+
//boot signature (2 bytes)
87+
0x55, 0xAA
88+
},
89+
90+
//------------- Block1: FAT12 Table -------------//
91+
{
92+
0xF8, 0xFF, 0xFF, 0xFF, 0x0F // // first 2 entries must be F8FF, third entry is cluster end of readme file
93+
},
94+
95+
//------------- Block2: Root Directory -------------//
96+
{
97+
// first entry is volume label
98+
'E' , 'S' , 'P' , '3' , '2' , 'S' , '2' , ' ' ,
99+
'M' , 'S' , 'C' ,
100+
0x08, //FILE_ATTR_VOLUME_LABEL
101+
0x00,
102+
FAT_MS2B(0,0),
103+
FAT_HMS2B(0,0,0),
104+
FAT_YMD2B(0,0,0),
105+
FAT_YMD2B(0,0,0),
106+
FAT_U16(0),
107+
FAT_HMS2B(13,42,30), //last_modified_hms
108+
FAT_YMD2B(2018,11,5), //last_modified_ymd
109+
FAT_U16(0),
110+
FAT_U32(0),
111+
112+
// second entry is readme file
113+
'R' , 'E' , 'A' , 'D' , 'M' , 'E' , ' ' , ' ' ,//file_name[8]; padded with spaces (0x20)
114+
'T' , 'X' , 'T' , //file_extension[3]; padded with spaces (0x20)
115+
0x20, //file attributes: FILE_ATTR_ARCHIVE
116+
0x00, //ignore
117+
FAT_MS2B(1,980), //creation_time_10_ms (max 199x10 = 1s 990ms)
118+
FAT_HMS2B(13,42,36), //create_time_hms [5:6:5] => h:m:(s/2)
119+
FAT_YMD2B(2018,11,5), //create_time_ymd [7:4:5] => (y+1980):m:d
120+
FAT_YMD2B(2020,11,5), //last_access_ymd
121+
FAT_U16(0), //extended_attributes
122+
FAT_HMS2B(13,44,16), //last_modified_hms
123+
FAT_YMD2B(2019,11,5), //last_modified_ymd
124+
FAT_U16(2), //start of file in cluster
125+
FAT_U32(sizeof(README_CONTENTS) - 1) //file size
126+
},
127+
128+
//------------- Block3: Readme Content -------------//
129+
README_CONTENTS
130+
};
131+
132+
static int32_t onWrite(uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize){
133+
HWSerial.printf("MSC WRITE: lba: %u, offset: %u, bufsize: %u\n", lba, offset, bufsize);
134+
memcpy(msc_disk[lba] + offset, buffer, bufsize);
135+
return bufsize;
136+
}
137+
138+
static int32_t onRead(uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize){
139+
HWSerial.printf("MSC READ: lba: %u, offset: %u, bufsize: %u\n", lba, offset, bufsize);
140+
memcpy(buffer, msc_disk[lba] + offset, bufsize);
141+
return bufsize;
142+
}
143+
144+
static bool onStartStop(uint8_t power_condition, bool start, bool load_eject){
145+
HWSerial.printf("MSC START/STOP: power: %u, start: %u, eject: %u\n", power_condition, start, load_eject);
146+
return true;
147+
}
148+
149+
static void usbEventCallback(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data){
150+
if(event_base == ARDUINO_USB_EVENTS){
151+
arduino_usb_event_data_t * data = (arduino_usb_event_data_t*)event_data;
152+
switch (event_id){
153+
case ARDUINO_USB_STARTED_EVENT:
154+
HWSerial.println("USB PLUGGED");
155+
break;
156+
case ARDUINO_USB_STOPPED_EVENT:
157+
HWSerial.println("USB UNPLUGGED");
158+
break;
159+
case ARDUINO_USB_SUSPEND_EVENT:
160+
HWSerial.printf("USB SUSPENDED: remote_wakeup_en: %u\n", data->suspend.remote_wakeup_en);
161+
break;
162+
case ARDUINO_USB_RESUME_EVENT:
163+
HWSerial.println("USB RESUMED");
164+
break;
165+
166+
default:
167+
break;
168+
}
169+
}
170+
}
171+
172+
void setup() {
173+
HWSerial.begin(115200);
174+
HWSerial.setDebugOutput(true);
175+
176+
USB.onEvent(usbEventCallback);
177+
MSC.vendorID("ESP32");//max 8 chars
178+
MSC.productID("USB_MSC");//max 16 chars
179+
MSC.productRevision("1.0");//max 4 chars
180+
MSC.onStartStop(onStartStop);
181+
MSC.onRead(onRead);
182+
MSC.onWrite(onWrite);
183+
MSC.mediaPresent(true);
184+
MSC.begin(DISK_SECTOR_COUNT, DISK_SECTOR_SIZE);
185+
#if !ARDUINO_SERIAL_PORT
186+
//USBSerial.begin(); // Windows does not like it if both devices are on
187+
USB.begin();
188+
#endif
189+
}
190+
191+
void loop() {
192+
// put your main code here, to run repeatedly:
193+
}

libraries/USB/keywords.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
USB KEYWORD1
1010
USBCDC KEYWORD1
11+
USBMSC KEYWORD1
1112

1213
#######################################
1314
# Methods and Functions (KEYWORD2)
@@ -18,6 +19,14 @@ end KEYWORD2
1819
onEvent KEYWORD2
1920
enableReset KEYWORD2
2021

22+
vendorID KEYWORD2
23+
productID KEYWORD2
24+
productRevision KEYWORD2
25+
mediaPresent KEYWORD2
26+
onStartStop KEYWORD2
27+
onRead KEYWORD2
28+
onWrite KEYWORD2
29+
2130
#######################################
2231
# Constants (LITERAL1)
2332
#######################################

0 commit comments

Comments
 (0)