Skip to content

Commit 78f1dd2

Browse files
authored
Merge pull request #157 from adafruit/msc-unit-ready
Enhance MSC multiple LUN with dynamic medium removal support
2 parents 707dfe7 + 68f3982 commit 78f1dd2

File tree

25 files changed

+605
-242
lines changed

25 files changed

+605
-242
lines changed

examples/MassStorage/msc_external_flash_sdcard/msc_external_flash_sdcard.ino

Lines changed: 81 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@
2424
#include "Adafruit_SPIFlash.h"
2525
#include "Adafruit_TinyUSB.h"
2626

27+
//--------------------------------------------------------------------+
28+
// External Flash Config
29+
//--------------------------------------------------------------------+
30+
2731
// Un-comment to run example with custom SPI SPI and SS e.g with FRAM breakout
2832
// #define CUSTOM_CS A5
2933
// #define CUSTOM_SPI SPI
@@ -65,27 +69,41 @@
6569

6670
Adafruit_SPIFlash flash(&flashTransport);
6771

68-
// File system object on external flash from SdFat
72+
// External Flash File system
6973
FatFileSystem fatfs;
7074

71-
const int chipSelect = 10;
75+
//--------------------------------------------------------------------+
76+
// SDCard Config
77+
//--------------------------------------------------------------------+
7278

73-
// File system on SD Card
79+
#if defined(ARDUINO_PYPORTAL_M4) || defined(ARDUINO_PYPORTAL_M4_TITANO)
80+
// PyPortal has on-board card reader
81+
#define SDCARD_CS 32
82+
#define SDCARD_DETECT 33
83+
#else
84+
#define SDCARD_CS 10
85+
// no detect
86+
#endif
87+
88+
// SDCard File system
7489
SdFat sd;
7590

7691
// USB Mass Storage object
7792
Adafruit_USBD_MSC usb_msc;
7893

7994
// Set to true when PC write to flash
8095
bool sd_changed = false;
96+
bool sd_inited = false;
8197
bool flash_changed = false;
8298

8399
// the setup function runs once when you press reset or power the board
84100
void setup()
85101
{
86102
pinMode(LED_BUILTIN, OUTPUT);
87103

88-
// MSC with 2 Logical Units
104+
Serial.begin(115200);
105+
106+
// MSC with 2 Logical Units: LUN0: External Flash, LUN1: SDCard
89107
usb_msc.setMaxLun(2);
90108

91109
usb_msc.setID(0, "Adafruit", "External Flash", "1.0");
@@ -108,21 +126,45 @@ void setup()
108126
flash_changed = true; // to print contents initially
109127

110128
//------------- Lun 1 for SD card -------------//
111-
if ( sd.begin(chipSelect, SD_SCK_MHZ(50)) )
129+
#ifdef SDCARD_DETECT
130+
// DETECT pin is available, detect card present on the fly with test unit ready
131+
pinMode(SDCARD_DETECT, INPUT);
132+
usb_msc.setReadyCallback(1, sdcard_ready_callback);
133+
#else
134+
// no DETECT pin, card must be inserted when powered on
135+
init_sdcard();
136+
sd_inited = true;
137+
usb_msc.setUnitReady(1, true);
138+
#endif
139+
140+
// while ( !Serial ) delay(10); // wait for native usb
141+
Serial.println("Adafruit TinyUSB Mass Storage External Flash + SD Card example");
142+
delay(1000);
143+
}
144+
145+
bool init_sdcard(void)
146+
{
147+
Serial.print("Init SDCard ... ");
148+
149+
if ( !sd.begin(SDCARD_CS, SD_SCK_MHZ(50)) )
112150
{
113-
uint32_t block_count = sd.card()->cardSize();
114-
usb_msc.setCapacity(1, block_count, 512);
115-
usb_msc.setReadWriteCallback(1, sdcard_read_cb, sdcard_write_cb, sdcard_flush_cb);
116-
usb_msc.setUnitReady(1, true);
151+
Serial.print("Failed ");
152+
sd.errorPrint();
117153

118-
sd_changed = true; // to print contents initially
154+
return false;
119155
}
120156

121-
Serial.begin(115200);
122-
//while ( !Serial ) delay(10); // wait for native usb
157+
uint32_t block_count = sd.card()->cardSize();
158+
usb_msc.setCapacity(1, block_count, 512);
159+
usb_msc.setReadWriteCallback(1, sdcard_read_cb, sdcard_write_cb, sdcard_flush_cb);
123160

124-
Serial.println("Adafruit TinyUSB Mass Storage External Flash + SD Card example");
125-
delay(1000);
161+
sd_changed = true; // to print contents initially
162+
163+
Serial.print("OK, Card size = ");
164+
Serial.print((block_count / (1024*1024)) * 512);
165+
Serial.println(" MB");
166+
167+
return true;
126168
}
127169

128170
void print_rootdir(File* rdir)
@@ -214,6 +256,31 @@ void sdcard_flush_cb (void)
214256
digitalWrite(LED_BUILTIN, LOW);
215257
}
216258

259+
#ifdef SDCARD_DETECT
260+
// Invoked when received Test Unit Ready command.
261+
// return true allowing host to read/write this LUN e.g SD card inserted
262+
bool sdcard_ready_callback(void)
263+
{
264+
// Card is inserted
265+
if ( digitalRead(SDCARD_DETECT) == HIGH )
266+
{
267+
// init SD card if not already
268+
if ( !sd_inited )
269+
{
270+
sd_inited = init_sdcard();
271+
}
272+
}else
273+
{
274+
sd_inited = false;
275+
usb_msc.setReadWriteCallback(1, NULL, NULL, NULL);
276+
}
277+
278+
Serial.println(sd_inited);
279+
280+
return sd_inited;
281+
}
282+
#endif
283+
217284
//--------------------------------------------------------------------+
218285
// External Flash callbacks
219286
//--------------------------------------------------------------------+

src/arduino/msc/Adafruit_USBD_MSC.cpp

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -200,13 +200,9 @@ void tud_msc_capacity_cb(uint8_t lun, uint32_t *block_count,
200200
int32_t tud_msc_scsi_cb(uint8_t lun, const uint8_t scsi_cmd[16], void *buffer,
201201
uint16_t bufsize) {
202202
const void *response = NULL;
203-
uint16_t resplen = 0;
203+
int32_t resplen = 0;
204204

205205
switch (scsi_cmd[0]) {
206-
case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
207-
// Host is about to read/write etc ... better not to disconnect disk
208-
resplen = 0;
209-
break;
210206

211207
default:
212208
// Set Sense = Invalid Command Operation
@@ -224,7 +220,7 @@ int32_t tud_msc_scsi_cb(uint8_t lun, const uint8_t scsi_cmd[16], void *buffer,
224220
}
225221

226222
// copy response to stack's buffer if any
227-
if (response && resplen) {
223+
if (response && (resplen > 0)) {
228224
memcpy(buffer, response, resplen);
229225
}
230226

src/class/audio/audio_device.c

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2247,24 +2247,28 @@ static void audiod_parse_for_AS_params(audiod_function_t* audio, uint8_t const *
22472247

22482248
#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
22492249

2250-
// Input value feedback has to be in 16.16 format - the format will be converted according to speed settings automatically
22512250
bool tud_audio_n_fb_set(uint8_t func_id, uint32_t feedback)
22522251
{
22532252
TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL);
22542253

22552254
// Format the feedback value
2256-
#if !TUD_OPT_HIGH_SPEED
2257-
uint8_t * fb = (uint8_t *) &_audiod_fct[func_id].fb_val;
2258-
2259-
// For FS format is 10.14
2260-
*(fb++) = (feedback >> 2) & 0xFF;
2261-
*(fb++) = (feedback >> 10) & 0xFF;
2262-
*(fb++) = (feedback >> 18) & 0xFF;
2263-
// 4th byte is needed to work correctly with MS Windows
2264-
*fb = 0;
2255+
#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION
2256+
if ( TUSB_SPEED_FULL == tud_speed_get() )
2257+
{
2258+
uint8_t * fb = (uint8_t *) &_audiod_fct[func_id].fb_val;
2259+
2260+
// For FS format is 10.14
2261+
*(fb++) = (feedback >> 2) & 0xFF;
2262+
*(fb++) = (feedback >> 10) & 0xFF;
2263+
*(fb++) = (feedback >> 18) & 0xFF;
2264+
// 4th byte is needed to work correctly with MS Windows
2265+
*fb = 0;
2266+
}else
22652267
#else
2266-
// For HS format is 16.16 as originally demanded
2267-
_audiod_fct[func_id].fb_val = feedback;
2268+
{
2269+
// Send value as-is, caller will choose the appropriate format
2270+
_audiod_fct[func_id].fb_val = feedback;
2271+
}
22682272
#endif
22692273

22702274
// Schedule a transmit with the new value if EP is not busy - this triggers repetitive scheduling of the feedback value

src/class/audio/audio_device.h

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,11 @@
186186
#define CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP 0 // Feedback - 0 or 1
187187
#endif
188188

189+
// Enable/disable conversion from 16.16 to 10.14 format on full-speed devices. See tud_audio_n_fb_set().
190+
#ifndef CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION
191+
#define CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION 0 // 0 or 1
192+
#endif
193+
189194
// Audio interrupt control EP size - disabled if 0
190195
#ifndef CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN
191196
#define CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN 0 // Audio interrupt control - if required - 6 Bytes according to UAC 2 specification (p. 74)
@@ -454,10 +459,15 @@ TU_ATTR_WEAK bool tud_audio_rx_done_post_read_cb(uint8_t rhport, uint16_t n_byte
454459

455460
#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
456461
TU_ATTR_WEAK bool tud_audio_fb_done_cb(uint8_t rhport);
457-
// User code should call this function with feedback value in 16.16 format for FS and HS.
458-
// Value will be corrected for FS to 10.14 format automatically.
459-
// (see Universal Serial Bus Specification Revision 2.0 5.12.4.2).
460-
// Feedback value will be sent at FB endpoint interval till it's changed.
462+
463+
// This function is used to provide data rate feedback from an asynchronous sink. Feedback value will be sent at FB endpoint interval till it's changed.
464+
//
465+
// The feedback format is specified to be 16.16 for HS and 10.14 for FS devices (see Universal Serial Bus Specification Revision 2.0 5.12.4.2). By default,
466+
// the choice of format is left to the caller and feedback argument is sent as-is. If CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION is set, then tinyusb
467+
// expects 16.16 format and handles the conversion to 10.14 on FS.
468+
//
469+
// Note that due to a bug in its USB Audio 2.0 driver, Windows currently requires 16.16 format for _all_ USB 2.0 devices. On Linux and macOS it seems the
470+
// driver can work with either format. So a good compromise is to keep format correction disabled and stick to 16.16 format.
461471
bool tud_audio_n_fb_set(uint8_t func_id, uint32_t feedback);
462472
static inline bool tud_audio_fb_set(uint32_t feedback);
463473
#endif

src/class/hid/hid_device.h

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -310,46 +310,46 @@ static inline bool tud_hid_gamepad_report(uint8_t report_id, int8_t x, int8_t y
310310
HID_COLLECTION_END \
311311

312312
// Gamepad Report Descriptor Template
313-
// with 16 buttons, 2 joysticks and 1 hat/dpad with following layout
314-
// | X | Y | Z | Rz | Rx | Ry (1 byte each) | hat/DPAD (1 byte) | Button Map (2 bytes) |
313+
// with 32 buttons, 2 joysticks and 1 hat/dpad with following layout
314+
// | X | Y | Z | Rz | Rx | Ry (1 byte each) | hat/DPAD (1 byte) | Button Map (4 bytes) |
315315
#define TUD_HID_REPORT_DESC_GAMEPAD(...) \
316316
HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\
317317
HID_USAGE ( HID_USAGE_DESKTOP_GAMEPAD ) ,\
318318
HID_COLLECTION ( HID_COLLECTION_APPLICATION ) ,\
319319
/* Report ID if any */\
320320
__VA_ARGS__ \
321321
/* 8 bit X, Y, Z, Rz, Rx, Ry (min -127, max 127 ) */ \
322-
HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\
323-
HID_USAGE ( HID_USAGE_DESKTOP_X ) ,\
324-
HID_USAGE ( HID_USAGE_DESKTOP_Y ) ,\
325-
HID_USAGE ( HID_USAGE_DESKTOP_Z ) ,\
326-
HID_USAGE ( HID_USAGE_DESKTOP_RZ ) ,\
327-
HID_USAGE ( HID_USAGE_DESKTOP_RX ) ,\
328-
HID_USAGE ( HID_USAGE_DESKTOP_RY ) ,\
329-
HID_LOGICAL_MIN ( 0x81 ) ,\
330-
HID_LOGICAL_MAX ( 0x7f ) ,\
331-
HID_REPORT_COUNT ( 6 ) ,\
332-
HID_REPORT_SIZE ( 8 ) ,\
333-
HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\
322+
HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\
323+
HID_USAGE ( HID_USAGE_DESKTOP_X ) ,\
324+
HID_USAGE ( HID_USAGE_DESKTOP_Y ) ,\
325+
HID_USAGE ( HID_USAGE_DESKTOP_Z ) ,\
326+
HID_USAGE ( HID_USAGE_DESKTOP_RZ ) ,\
327+
HID_USAGE ( HID_USAGE_DESKTOP_RX ) ,\
328+
HID_USAGE ( HID_USAGE_DESKTOP_RY ) ,\
329+
HID_LOGICAL_MIN ( 0x81 ) ,\
330+
HID_LOGICAL_MAX ( 0x7f ) ,\
331+
HID_REPORT_COUNT ( 6 ) ,\
332+
HID_REPORT_SIZE ( 8 ) ,\
333+
HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\
334334
/* 8 bit DPad/Hat Button Map */ \
335-
HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\
336-
HID_USAGE ( HID_USAGE_DESKTOP_HAT_SWITCH ) ,\
337-
HID_LOGICAL_MIN ( 1 ) ,\
338-
HID_LOGICAL_MAX ( 8 ) ,\
339-
HID_PHYSICAL_MIN ( 0 ) ,\
340-
HID_PHYSICAL_MAX_N ( 315, 2 ) ,\
341-
HID_REPORT_COUNT ( 1 ) ,\
342-
HID_REPORT_SIZE ( 8 ) ,\
343-
HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\
344-
/* 16 bit Button Map */ \
345-
HID_USAGE_PAGE ( HID_USAGE_PAGE_BUTTON ) ,\
346-
HID_USAGE_MIN ( 1 ) ,\
347-
HID_USAGE_MAX ( 32 ) ,\
348-
HID_LOGICAL_MIN ( 0 ) ,\
349-
HID_LOGICAL_MAX ( 1 ) ,\
350-
HID_REPORT_COUNT ( 32 ) ,\
351-
HID_REPORT_SIZE ( 1 ) ,\
352-
HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\
335+
HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\
336+
HID_USAGE ( HID_USAGE_DESKTOP_HAT_SWITCH ) ,\
337+
HID_LOGICAL_MIN ( 1 ) ,\
338+
HID_LOGICAL_MAX ( 8 ) ,\
339+
HID_PHYSICAL_MIN ( 0 ) ,\
340+
HID_PHYSICAL_MAX_N ( 315, 2 ) ,\
341+
HID_REPORT_COUNT ( 1 ) ,\
342+
HID_REPORT_SIZE ( 8 ) ,\
343+
HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\
344+
/* 32 bit Button Map */ \
345+
HID_USAGE_PAGE ( HID_USAGE_PAGE_BUTTON ) ,\
346+
HID_USAGE_MIN ( 1 ) ,\
347+
HID_USAGE_MAX ( 32 ) ,\
348+
HID_LOGICAL_MIN ( 0 ) ,\
349+
HID_LOGICAL_MAX ( 1 ) ,\
350+
HID_REPORT_COUNT ( 32 ) ,\
351+
HID_REPORT_SIZE ( 1 ) ,\
352+
HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\
353353
HID_COLLECTION_END \
354354

355355
// HID Generic Input & Output

0 commit comments

Comments
 (0)