update midi host to use endpoint stream API

This commit is contained in:
hathach
2025-02-13 15:52:30 +07:00
parent e0b192b633
commit bad6cbe489
6 changed files with 174 additions and 316 deletions

View File

@@ -691,10 +691,10 @@ bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t
} }
} else if ( ep_addr == p_cdc->stream.rx.ep_addr ) { } else if ( ep_addr == p_cdc->stream.rx.ep_addr ) {
#if CFG_TUH_CDC_FTDI #if CFG_TUH_CDC_FTDI
if (p_cdc->serial_drid == SERIAL_DRIVER_FTDI) { if (p_cdc->serial_drid == SERIAL_DRIVER_FTDI && xferred_bytes > 2) {
// FTDI reserve 2 bytes for status // FTDI reserve 2 bytes for status
// uint8_t status[2] = {p_cdc->stream.rx.ep_buf[0], p_cdc->stream.rx.ep_buf[1]}; // uint8_t status[2] = {p_cdc->stream.rx.ep_buf[0], p_cdc->stream.rx.ep_buf[1]};
tu_edpt_stream_read_xfer_complete_offset(&p_cdc->stream.rx, xferred_bytes, 2); tu_edpt_stream_read_xfer_complete_with_buf(&p_cdc->stream.rx, p_cdc->stream.rx.ep_buf+2, xferred_bytes-2);
}else }else
#endif #endif
{ {

View File

@@ -45,15 +45,12 @@ typedef struct
uint8_t total; uint8_t total;
}midi_stream_t; }midi_stream_t;
typedef struct typedef struct {
{
uint8_t dev_addr; uint8_t dev_addr;
uint8_t itf_num; uint8_t itf_num;
uint8_t ep_in; // IN endpoint address uint8_t ep_in; // IN endpoint address
uint8_t ep_out; // OUT endpoint address uint8_t ep_out; // OUT endpoint address
uint16_t ep_in_max; // min( CFG_TUH_MIDI_RX_BUFSIZE, wMaxPacketSize of the IN endpoint)
uint16_t ep_out_max; // min( CFG_TUH_MIDI_TX_BUFSIZE, wMaxPacketSize of the OUT endpoint)
uint8_t num_cables_rx; // IN endpoint CS descriptor bNumEmbMIDIJack value uint8_t num_cables_rx; // IN endpoint CS descriptor bNumEmbMIDIJack value
uint8_t num_cables_tx; // OUT endpoint CS descriptor bNumEmbMIDIJack value uint8_t num_cables_tx; // OUT endpoint CS descriptor bNumEmbMIDIJack value
@@ -65,22 +62,14 @@ typedef struct
midi_stream_t stream_read; midi_stream_t stream_read;
/*------------- From this point, data is not cleared by bus reset -------------*/ /*------------- From this point, data is not cleared by bus reset -------------*/
// Endpoint FIFOs // Endpoint stream
tu_fifo_t rx_ff; struct {
tu_fifo_t tx_ff; tu_edpt_stream_t tx;
tu_edpt_stream_t rx;
uint8_t rx_ff_buf[CFG_TUH_MIDI_RX_BUFSIZE]; uint8_t rx_ff_buf[CFG_TUH_MIDI_RX_BUFSIZE];
uint8_t tx_ff_buf[CFG_TUH_MIDI_TX_BUFSIZE]; uint8_t tx_ff_buf[CFG_TUH_MIDI_TX_BUFSIZE];
} ep_stream;
#if CFG_FIFO_MUTEX
osal_mutex_def_t rx_ff_mutex;
osal_mutex_def_t tx_ff_mutex;
#endif
// Endpoint Transfer buffer
CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUH_MIDI_EP_BUFSIZE];
CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUH_MIDI_EP_BUFSIZE];
bool configured; bool configured;
@@ -109,15 +98,17 @@ typedef struct
#endif #endif
}midih_interface_t; }midih_interface_t;
static midih_interface_t _midi_host[CFG_TUH_MIDI]; typedef struct {
TUH_EPBUF_DEF(tx, TUH_EPSIZE_BULK_MPS);
TUH_EPBUF_DEF(rx, TUH_EPSIZE_BULK_MPS);
} midih_epbuf_t;
//------------- Internal prototypes -------------// static midih_interface_t _midi_host[CFG_TUH_MIDI];
static uint32_t write_flush(uint8_t dev_addr, midih_interface_t* midi); CFG_TUH_MEM_SECTION static midih_epbuf_t _midi_epbuf[CFG_TUH_MIDI];
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// Helper // Helper
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
TU_ATTR_ALWAYS_INLINE static inline midih_interface_t* find_midi_by_daddr(uint8_t dev_addr) { TU_ATTR_ALWAYS_INLINE static inline midih_interface_t* find_midi_by_daddr(uint8_t dev_addr) {
for (uint8_t i = 0; i < CFG_TUH_MIDI; i++) { for (uint8_t i = 0; i < CFG_TUH_MIDI; i++) {
if (_midi_host[i].dev_addr == dev_addr) { if (_midi_host[i].dev_addr == dev_addr) {
@@ -131,85 +122,27 @@ TU_ATTR_ALWAYS_INLINE static inline midih_interface_t* find_new_midi(void) {
return find_midi_by_daddr(0); return find_midi_by_daddr(0);
} }
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// USBH API // USBH API
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
bool midih_init(void) { bool midih_init(void) {
tu_memclr(&_midi_host, sizeof(_midi_host)); tu_memclr(&_midi_host, sizeof(_midi_host));
// config fifos
for (int inst = 0; inst < CFG_TUH_MIDI; inst++) { for (int inst = 0; inst < CFG_TUH_MIDI; inst++) {
midih_interface_t *p_midi_host = &_midi_host[inst]; midih_interface_t *p_midi_host = &_midi_host[inst];
tu_fifo_config(&p_midi_host->rx_ff, p_midi_host->rx_ff_buf, CFG_TUH_MIDI_RX_BUFSIZE, 1, false);// true, true tu_edpt_stream_init(&p_midi_host->ep_stream.rx, true, false, false,
tu_fifo_config(&p_midi_host->tx_ff, p_midi_host->tx_ff_buf, CFG_TUH_MIDI_TX_BUFSIZE, 1, false);// OBVS. p_midi_host->ep_stream.rx_ff_buf, CFG_TUH_MIDI_RX_BUFSIZE, _midi_epbuf->rx, TUH_EPSIZE_BULK_MPS);
tu_edpt_stream_init(&p_midi_host->ep_stream.tx, true, true, false,
#if CFG_FIFO_MUTEX p_midi_host->ep_stream.tx_ff_buf, CFG_TUH_MIDI_TX_BUFSIZE, _midi_epbuf->tx, TUH_EPSIZE_BULK_MPS);
tu_fifo_config_mutex(&p_midi_host->rx_ff, NULL, osal_mutex_create(&p_midi_host->rx_ff_mutex));
tu_fifo_config_mutex(&p_midi_host->tx_ff, osal_mutex_create(&p_midi_host->tx_ff_mutex), NULL);
#endif
} }
return true; return true;
} }
bool midih_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) bool midih_deinit(void) {
{ for (size_t i = 0; i < CFG_TUH_MIDI; i++) {
(void)result; midih_interface_t* p_midi = &_midi_host[i];
midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); tu_edpt_stream_deinit(&p_midi->ep_stream.rx);
TU_VERIFY(p_midi_host != NULL); tu_edpt_stream_deinit(&p_midi->ep_stream.tx);
if ( ep_addr == p_midi_host->ep_in)
{
if (0 == xferred_bytes)
{
return true; // No data to handle
} }
// receive new data if available
uint32_t packets_queued = 0;
if (xferred_bytes)
{
// put in the RX FIFO only non-zero MIDI IN 4-byte packets
uint8_t* buf = p_midi_host->epin_buf;
uint32_t npackets = xferred_bytes / 4;
uint32_t packet_num;
for (packet_num = 0; packet_num < npackets; packet_num++)
{
// some devices send back all zero packets even if there is no data ready
uint32_t packet = (uint32_t)((*buf)<<24) | ((uint32_t)(*(buf+1))<<16) | ((uint32_t)(*(buf+2))<<8) | ((uint32_t)(*(buf+3)));
if (packet != 0)
{
tu_fifo_write_n(&p_midi_host->rx_ff, buf, 4);
++packets_queued;
TU_LOG3("MIDI RX=%08x\r\n", packet);
}
buf += 4;
}
}
// invoke receive callback if available
if (tuh_midi_rx_cb)
{
tuh_midi_rx_cb(dev_addr, packets_queued);
}
}
else if ( ep_addr == p_midi_host->ep_out )
{
if (0 == write_flush(dev_addr, p_midi_host))
{
// If there is no data left, a ZLP should be sent if
// xferred_bytes is multiple of EP size and not zero
if ( !tu_fifo_count(&p_midi_host->tx_ff) && xferred_bytes && (0 == (xferred_bytes % p_midi_host->ep_out_max)) )
{
if ( usbh_edpt_claim(dev_addr, p_midi_host->ep_out) )
{
TU_ASSERT(usbh_edpt_xfer(dev_addr, p_midi_host->ep_out, XFER_RESULT_SUCCESS, 0));
}
}
}
if (tuh_midi_tx_cb)
{
tuh_midi_tx_cb(dev_addr);
}
}
return true; return true;
} }
@@ -221,26 +154,67 @@ void midih_close(uint8_t dev_addr) {
if (tuh_midi_umount_cb) { if (tuh_midi_umount_cb) {
tuh_midi_umount_cb(dev_addr, 0); tuh_midi_umount_cb(dev_addr, 0);
} }
tu_fifo_clear(&p_midi_host->rx_ff);
tu_fifo_clear(&p_midi_host->tx_ff);
p_midi_host->ep_in = 0; p_midi_host->ep_in = 0;
p_midi_host->ep_in_max = 0;
p_midi_host->ep_out = 0; p_midi_host->ep_out = 0;
p_midi_host->ep_out_max = 0;
p_midi_host->itf_num = 0; p_midi_host->itf_num = 0;
p_midi_host->num_cables_rx = 0; p_midi_host->num_cables_rx = 0;
p_midi_host->num_cables_tx = 0; p_midi_host->num_cables_tx = 0;
p_midi_host->dev_addr = 255; // invalid p_midi_host->dev_addr = 0;
p_midi_host->configured = false; p_midi_host->configured = false;
tu_memclr(&p_midi_host->stream_read, sizeof(p_midi_host->stream_read)); tu_memclr(&p_midi_host->stream_read, sizeof(p_midi_host->stream_read));
tu_memclr(&p_midi_host->stream_write, sizeof(p_midi_host->stream_write)); tu_memclr(&p_midi_host->stream_write, sizeof(p_midi_host->stream_write));
tu_edpt_stream_close(&p_midi_host->ep_stream.rx);
tu_edpt_stream_close(&p_midi_host->ep_stream.tx);
}
bool midih_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) {
(void) result;
midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr);
TU_VERIFY(p_midi_host != NULL);
if (ep_addr == p_midi_host->ep_stream.rx.ep_addr) {
// receive new data if available
if (xferred_bytes) {
// put in the RX FIFO only non-zero MIDI IN 4-byte packets
uint32_t packets_queued = 0;
uint8_t *buf = _midi_epbuf->rx;
const uint32_t npackets = xferred_bytes / 4;
for (uint32_t p = 0; p < npackets; p++) {
// some devices send back all zero packets even if there is no data ready
const uint32_t packet = tu_unaligned_read32(buf);
if (packet != 0) {
tu_edpt_stream_read_xfer_complete_with_buf(&p_midi_host->ep_stream.rx, buf, 4);
++packets_queued;
TU_LOG3("MIDI RX=%08x\r\n", packet);
}
buf += 4;
}
if (tuh_midi_rx_cb) {
tuh_midi_rx_cb(dev_addr, packets_queued); // invoke receive callback
}
}
// prepare for next transfer if needed
tu_edpt_stream_read_xfer(dev_addr, &p_midi_host->ep_stream.rx);
} else if (ep_addr == p_midi_host->ep_stream.tx.ep_addr) {
if (tuh_midi_tx_cb) {
tuh_midi_tx_cb(dev_addr);
}
if (0 == tu_edpt_stream_write_xfer(dev_addr, &p_midi_host->ep_stream.tx)) {
// If there is no data left, a ZLP should be sent if
// xferred_bytes is multiple of EP size and not zero
tu_edpt_stream_write_zlp_if_needed(dev_addr, &p_midi_host->ep_stream.tx, xferred_bytes);
}
}
return true;
} }
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// Enumeration // Enumeration
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
bool midih_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len) bool midih_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len) {
{
(void) rhport; (void) rhport;
midih_interface_t *p_midi_host = find_new_midi(); midih_interface_t *p_midi_host = find_new_midi();
@@ -402,20 +376,12 @@ bool midih_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *d
TU_VERIFY(p_midi_host->ep_out == 0); TU_VERIFY(p_midi_host->ep_out == 0);
TU_VERIFY(p_midi_host->num_cables_tx == 0); TU_VERIFY(p_midi_host->num_cables_tx == 0);
p_midi_host->ep_out = p_ep->bEndpointAddress; p_midi_host->ep_out = p_ep->bEndpointAddress;
p_midi_host->ep_out_max = p_ep->wMaxPacketSize;
if (p_midi_host->ep_out_max > CFG_TUH_MIDI_TX_BUFSIZE) {
p_midi_host->ep_out_max = CFG_TUH_MIDI_TX_BUFSIZE;
}
prev_ep_addr = p_midi_host->ep_out; prev_ep_addr = p_midi_host->ep_out;
out_desc = p_ep; out_desc = p_ep;
} else { } else {
TU_VERIFY(p_midi_host->ep_in == 0); TU_VERIFY(p_midi_host->ep_in == 0);
TU_VERIFY(p_midi_host->num_cables_rx == 0); TU_VERIFY(p_midi_host->num_cables_rx == 0);
p_midi_host->ep_in = p_ep->bEndpointAddress; p_midi_host->ep_in = p_ep->bEndpointAddress;
p_midi_host->ep_in_max = p_ep->wMaxPacketSize;
if (p_midi_host->ep_in_max > CFG_TUH_MIDI_RX_BUFSIZE) {
p_midi_host->ep_in_max = CFG_TUH_MIDI_RX_BUFSIZE;
}
prev_ep_addr = p_midi_host->ep_in; prev_ep_addr = p_midi_host->ep_in;
in_desc = p_ep; in_desc = p_ep;
} }
@@ -439,36 +405,34 @@ bool midih_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *d
} }
if (in_desc) { if (in_desc) {
TU_ASSERT(tuh_edpt_open(dev_addr, in_desc)); TU_ASSERT(tuh_edpt_open(dev_addr, in_desc));
// Some devices always return exactly the request length so transfers won't complete tu_edpt_stream_open(&p_midi_host->ep_stream.rx, in_desc);
// unless you assume every transfer is the last one.
// TODO usbh_edpt_force_last_buffer(dev_addr, p_midi_host->ep_in, true);
} }
if (out_desc) { if (out_desc) {
TU_ASSERT(tuh_edpt_open(dev_addr, out_desc)); TU_ASSERT(tuh_edpt_open(dev_addr, out_desc));
tu_edpt_stream_open(&p_midi_host->ep_stream.tx, out_desc);
} }
p_midi_host->dev_addr = dev_addr; p_midi_host->dev_addr = dev_addr;
if (tuh_midi_mount_cb) {
tuh_midi_mount_cb(dev_addr, p_midi_host->ep_in, p_midi_host->ep_out, p_midi_host->num_cables_rx, p_midi_host->num_cables_tx);
}
return true; return true;
} }
bool tuh_midi_configured(uint8_t dev_addr) bool tuh_midi_configured(uint8_t dev_addr) {
{
midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr);
TU_VERIFY(p_midi_host != NULL); TU_VERIFY(p_midi_host != NULL);
return p_midi_host->configured; return p_midi_host->configured;
} }
bool midih_set_config(uint8_t dev_addr, uint8_t itf_num) bool midih_set_config(uint8_t dev_addr, uint8_t itf_num) {
{
(void) itf_num; (void) itf_num;
midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr);
TU_VERIFY(p_midi_host != NULL); TU_VERIFY(p_midi_host != NULL);
p_midi_host->configured = true; p_midi_host->configured = true;
// TODO I don't think there are any special config things to do for MIDI if (tuh_midi_mount_cb) {
tuh_midi_mount_cb(dev_addr, p_midi_host->ep_in, p_midi_host->ep_out, p_midi_host->num_cables_rx, p_midi_host->num_cables_tx);
}
// No special config things to do for MIDI
usbh_driver_set_config_complete(dev_addr, p_midi_host->itf_num); usbh_driver_set_config_complete(dev_addr, p_midi_host->itf_num);
return true; return true;
} }
@@ -476,71 +440,32 @@ bool midih_set_config(uint8_t dev_addr, uint8_t itf_num)
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// Stream API // Stream API
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
static uint32_t write_flush(uint8_t dev_addr, midih_interface_t* midi) {
// No data to send
if ( !tu_fifo_count(&midi->tx_ff) ) { return 0; }
// skip if previous transfer not complete
TU_VERIFY( usbh_edpt_claim(dev_addr, midi->ep_out) );
uint16_t count = tu_fifo_read_n(&midi->tx_ff, midi->epout_buf, midi->ep_out_max);
if (count) {
TU_ASSERT(usbh_edpt_xfer(dev_addr, midi->ep_out, midi->epout_buf, count), 0);
return count;
} else {
// Release endpoint since we don't make any transfer
usbh_edpt_release(dev_addr, midi->ep_out);
return 0;
}
}
bool tuh_midi_read_poll(uint8_t dev_addr) { bool tuh_midi_read_poll(uint8_t dev_addr) {
midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr);
TU_VERIFY(p_midi_host != NULL); TU_VERIFY(p_midi_host != NULL);
bool result = false; return tu_edpt_stream_read_xfer(dev_addr, &p_midi_host->ep_stream.rx) > 0;
bool in_edpt_not_busy = !usbh_edpt_busy(dev_addr, p_midi_host->ep_in);
if (in_edpt_not_busy) {
TU_LOG2("Requesting poll IN endpoint %d\r\n", p_midi_host->ep_in);
TU_ASSERT(usbh_edpt_xfer(p_midi_host->dev_addr, p_midi_host->ep_in, p_midi_host->epin_buf, p_midi_host->ep_in_max), 0);
result = true;
} else {
// Maybe the IN endpoint is only busy because the RP2040 host hardware
// is retrying a NAK'd IN transfer forever. Try aborting the NAK'd
// transfer to allow other transfers to happen on the one shared
// epx endpoint.
// TODO for RP2040 USB shared endpoint: usbh_edpt_clear_in_on_nak(p_midi_host->dev_addr, p_midi_host->ep_in);
}
return result;
} }
uint32_t tuh_midi_stream_write (uint8_t dev_addr, uint8_t cable_num, uint8_t const* buffer, uint32_t bufsize) uint32_t tuh_midi_stream_write(uint8_t dev_addr, uint8_t cable_num, uint8_t const *buffer, uint32_t bufsize) {
{
midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr);
TU_VERIFY(p_midi_host != NULL); TU_VERIFY(p_midi_host != NULL);
TU_VERIFY(cable_num < p_midi_host->num_cables_tx); TU_VERIFY(cable_num < p_midi_host->num_cables_tx);
midi_stream_t *stream = &p_midi_host->stream_write; midi_stream_t *stream = &p_midi_host->stream_write;
uint32_t i = 0; uint32_t i = 0;
while ( (i < bufsize) && (tu_fifo_remaining(&p_midi_host->tx_ff) >= 4) ) while ((i < bufsize) && (tu_edpt_stream_write_available(dev_addr, &p_midi_host->ep_stream.tx) >= 4)) {
{
uint8_t const data = buffer[i]; uint8_t const data = buffer[i];
i++; i++;
if (data >= MIDI_STATUS_SYSREAL_TIMING_CLOCK) if (data >= MIDI_STATUS_SYSREAL_TIMING_CLOCK) {
{
// real-time messages need to be sent right away // real-time messages need to be sent right away
midi_stream_t streamrt; midi_stream_t streamrt;
streamrt.buffer[0] = MIDI_CIN_SYSEX_END_1BYTE; streamrt.buffer[0] = MIDI_CIN_SYSEX_END_1BYTE;
streamrt.buffer[1] = data; streamrt.buffer[1] = data;
streamrt.index = 2; streamrt.index = 2;
streamrt.total = 2; streamrt.total = 2;
uint16_t const count = tu_fifo_write_n(&p_midi_host->tx_ff, streamrt.buffer, 4); uint32_t const count = tu_edpt_stream_write(dev_addr, &p_midi_host->ep_stream.tx, streamrt.buffer, 4);
// FIFO overflown, since we already check fifo remaining. It is probably race condition TU_ASSERT(count == 4, i); // Check FIFO overflown, since we already check fifo remaining. It is probably race condition
TU_ASSERT(count == 4, i); } else if (stream->index == 0) {
}
else if ( stream->index == 0 )
{
//------------- New event packet -------------// //------------- New event packet -------------//
uint8_t const msg = data >> 4; uint8_t const msg = data >> 4;
@@ -549,56 +474,37 @@ uint32_t tuh_midi_stream_write (uint8_t dev_addr, uint8_t cable_num, uint8_t con
stream->buffer[1] = data; stream->buffer[1] = data;
// Check to see if we're still in a SysEx transmit. // Check to see if we're still in a SysEx transmit.
if ( stream->buffer[0] == MIDI_CIN_SYSEX_START ) if (stream->buffer[0] == MIDI_CIN_SYSEX_START) {
{ if (data == MIDI_STATUS_SYSEX_END) {
if ( data == MIDI_STATUS_SYSEX_END )
{
stream->buffer[0] = MIDI_CIN_SYSEX_END_1BYTE; stream->buffer[0] = MIDI_CIN_SYSEX_END_1BYTE;
stream->total = 2; stream->total = 2;
} } else {
else
{
stream->total = 4; stream->total = 4;
} }
} } else if ((msg >= 0x8 && msg <= 0xB) || msg == 0xE) {
else if ( (msg >= 0x8 && msg <= 0xB) || msg == 0xE )
{
// Channel Voice Messages // Channel Voice Messages
stream->buffer[0] = (uint8_t) ((cable_num << 4) | msg); stream->buffer[0] = (uint8_t) ((cable_num << 4) | msg);
stream->total = 4; stream->total = 4;
} } else if (msg == 0xC || msg == 0xD) {
else if ( msg == 0xC || msg == 0xD)
{
// Channel Voice Messages, two-byte variants (Program Change and Channel Pressure) // Channel Voice Messages, two-byte variants (Program Change and Channel Pressure)
stream->buffer[0] = (uint8_t) ((cable_num << 4) | msg); stream->buffer[0] = (uint8_t) ((cable_num << 4) | msg);
stream->total = 3; stream->total = 3;
} } else if (msg == 0xf) {
else if ( msg == 0xf )
{
// System message // System message
if ( data == MIDI_STATUS_SYSEX_START ) if (data == MIDI_STATUS_SYSEX_START) {
{
stream->buffer[0] = MIDI_CIN_SYSEX_START; stream->buffer[0] = MIDI_CIN_SYSEX_START;
stream->total = 4; stream->total = 4;
} } else if (data == MIDI_STATUS_SYSCOM_TIME_CODE_QUARTER_FRAME || data == MIDI_STATUS_SYSCOM_SONG_SELECT) {
else if ( data == MIDI_STATUS_SYSCOM_TIME_CODE_QUARTER_FRAME || data == MIDI_STATUS_SYSCOM_SONG_SELECT )
{
stream->buffer[0] = MIDI_CIN_SYSCOM_2BYTE; stream->buffer[0] = MIDI_CIN_SYSCOM_2BYTE;
stream->total = 3; stream->total = 3;
} } else if (data == MIDI_STATUS_SYSCOM_SONG_POSITION_POINTER) {
else if ( data == MIDI_STATUS_SYSCOM_SONG_POSITION_POINTER )
{
stream->buffer[0] = MIDI_CIN_SYSCOM_3BYTE; stream->buffer[0] = MIDI_CIN_SYSCOM_3BYTE;
stream->total = 4; stream->total = 4;
} } else {
else
{
stream->buffer[0] = MIDI_CIN_SYSEX_END_1BYTE; stream->buffer[0] = MIDI_CIN_SYSEX_END_1BYTE;
stream->total = 2; stream->total = 2;
} }
} } else {
else
{
// Pack individual bytes if we don't support packing them into words. // Pack individual bytes if we don't support packing them into words.
stream->buffer[0] = (uint8_t) (cable_num << 4 | 0xf); stream->buffer[0] = (uint8_t) (cable_num << 4 | 0xf);
stream->buffer[2] = 0; stream->buffer[2] = 0;
@@ -606,30 +512,25 @@ uint32_t tuh_midi_stream_write (uint8_t dev_addr, uint8_t cable_num, uint8_t con
stream->index = 2; stream->index = 2;
stream->total = 2; stream->total = 2;
} }
} } else {
else
{
//------------- On-going (buffering) packet -------------// //------------- On-going (buffering) packet -------------//
TU_ASSERT(stream->index < 4, i); TU_ASSERT(stream->index < 4, i);
stream->buffer[stream->index] = data; stream->buffer[stream->index] = data;
stream->index++; stream->index++;
// See if this byte ends a SysEx. // See if this byte ends a SysEx.
if ( stream->buffer[0] == MIDI_CIN_SYSEX_START && data == MIDI_STATUS_SYSEX_END ) if (stream->buffer[0] == MIDI_CIN_SYSEX_START && data == MIDI_STATUS_SYSEX_END) {
{
stream->buffer[0] = MIDI_CIN_SYSEX_START + (stream->index - 1); stream->buffer[0] = MIDI_CIN_SYSEX_START + (stream->index - 1);
stream->total = stream->index; stream->total = stream->index;
} }
} }
// Send out packet // Send out packet
if ( stream->index >= 2 && stream->index == stream->total ) if (stream->index >= 2 && stream->index == stream->total) {
{
// zeroes unused bytes // zeroes unused bytes
for(uint8_t idx = stream->total; idx < 4; idx++) stream->buffer[idx] = 0; for (uint8_t idx = stream->total; idx < 4; idx++) { stream->buffer[idx] = 0; }
TU_LOG3_MEM(stream->buffer, 4, 2); TU_LOG3_MEM(stream->buffer, 4, 2);
uint16_t const count = tu_fifo_write_n(&p_midi_host->tx_ff, stream->buffer, 4); uint32_t const count = tu_edpt_stream_write(dev_addr, &p_midi_host->ep_stream.tx, stream->buffer, 4);
// complete current event packet, reset stream // complete current event packet, reset stream
stream->index = 0; stream->index = 0;
@@ -642,32 +543,16 @@ uint32_t tuh_midi_stream_write (uint8_t dev_addr, uint8_t cable_num, uint8_t con
return i; return i;
} }
bool tuh_midi_packet_write (uint8_t dev_addr, uint8_t const packet[4]) bool tuh_midi_packet_write (uint8_t dev_addr, uint8_t const packet[4]) {
{
midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr);
TU_VERIFY(p_midi_host != NULL); TU_VERIFY(p_midi_host != NULL);
return 4 == tu_edpt_stream_write(dev_addr, &p_midi_host->ep_stream.tx, packet, 4);
if (tu_fifo_remaining(&p_midi_host->tx_ff) < 4)
{
return false;
} }
tu_fifo_write_n(&p_midi_host->tx_ff, packet, 4); uint32_t tuh_midi_stream_flush(uint8_t dev_addr) {
midih_interface_t *p_midi = find_midi_by_daddr(dev_addr);
return true; TU_VERIFY(p_midi != NULL);
} return tu_edpt_stream_write_xfer(p_midi->dev_addr, &p_midi->ep_stream.tx);
uint32_t tuh_midi_stream_flush( uint8_t dev_addr )
{
midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr);
TU_VERIFY(p_midi_host != NULL);
uint32_t bytes_flushed = 0;
if (!usbh_edpt_busy(p_midi_host->dev_addr, p_midi_host->ep_out))
{
bytes_flushed = write_flush(dev_addr, p_midi_host);
}
return bytes_flushed;
} }
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// Helper // Helper
@@ -692,12 +577,11 @@ bool tuh_midi_packet_read (uint8_t dev_addr, uint8_t packet[4])
{ {
midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr);
TU_VERIFY(p_midi_host != NULL); TU_VERIFY(p_midi_host != NULL);
TU_VERIFY(tu_fifo_count(&p_midi_host->rx_ff) >= 4); TU_VERIFY(tu_edpt_stream_read_available(&p_midi_host->ep_stream.rx) >= 4);
return tu_fifo_read_n(&p_midi_host->rx_ff, packet, 4) == 4; return 4 == tu_edpt_stream_read(dev_addr, &p_midi_host->ep_stream.rx, packet, 4);
} }
uint32_t tuh_midi_stream_read (uint8_t dev_addr, uint8_t *p_cable_num, uint8_t *p_buffer, uint16_t bufsize) uint32_t tuh_midi_stream_read(uint8_t dev_addr, uint8_t *p_cable_num, uint8_t *p_buffer, uint16_t bufsize) {
{
midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr);
TU_VERIFY(p_midi_host != NULL); TU_VERIFY(p_midi_host != NULL);
uint32_t bytes_buffered = 0; uint32_t bytes_buffered = 0;
@@ -705,54 +589,40 @@ uint32_t tuh_midi_stream_read (uint8_t dev_addr, uint8_t *p_cable_num, uint8_t *
TU_ASSERT(p_buffer); TU_ASSERT(p_buffer);
TU_ASSERT(bufsize); TU_ASSERT(bufsize);
uint8_t one_byte; uint8_t one_byte;
if (!tu_fifo_peek(&p_midi_host->rx_ff, &one_byte)) if (!tu_edpt_stream_peek(&p_midi_host->ep_stream.rx, &one_byte)) {
{
return 0; return 0;
} }
*p_cable_num = (one_byte >> 4) & 0xf; *p_cable_num = (one_byte >> 4) & 0xf;
uint32_t nread = tu_fifo_read_n(&p_midi_host->rx_ff, p_midi_host->stream_read.buffer, 4); uint32_t nread = tu_edpt_stream_read(dev_addr, &p_midi_host->ep_stream.rx, p_midi_host->stream_read.buffer, 4);
static uint16_t cable_sysex_in_progress; // bit i is set if received MIDI_STATUS_SYSEX_START but not MIDI_STATUS_SYSEX_END static uint16_t cable_sysex_in_progress; // bit i is set if received MIDI_STATUS_SYSEX_START but not MIDI_STATUS_SYSEX_END
while (nread == 4 && bytes_buffered < bufsize) while (nread == 4 && bytes_buffered < bufsize) {
{
*p_cable_num = (p_midi_host->stream_read.buffer[0] >> 4) & 0x0f; *p_cable_num = (p_midi_host->stream_read.buffer[0] >> 4) & 0x0f;
uint8_t bytes_to_add_to_stream = 0; uint8_t bytes_to_add_to_stream = 0;
if (*p_cable_num < p_midi_host->num_cables_rx) if (*p_cable_num < p_midi_host->num_cables_rx) {
{
// ignore the CIN field; too many devices out there encode this wrong // ignore the CIN field; too many devices out there encode this wrong
uint8_t status = p_midi_host->stream_read.buffer[1]; uint8_t status = p_midi_host->stream_read.buffer[1];
uint16_t cable_mask = (uint16_t) (1 << *p_cable_num); uint16_t cable_mask = (uint16_t) (1 << *p_cable_num);
if (status <= MIDI_MAX_DATA_VAL || status == MIDI_STATUS_SYSEX_START) if (status <= MIDI_MAX_DATA_VAL || status == MIDI_STATUS_SYSEX_START) {
{ if (status == MIDI_STATUS_SYSEX_START) {
if (status == MIDI_STATUS_SYSEX_START)
{
cable_sysex_in_progress |= cable_mask; cable_sysex_in_progress |= cable_mask;
} }
// only add the packet if a sysex message is in progress // only add the packet if a sysex message is in progress
if (cable_sysex_in_progress & cable_mask) if (cable_sysex_in_progress & cable_mask) {
{
++bytes_to_add_to_stream; ++bytes_to_add_to_stream;
uint8_t idx; for (uint8_t idx = 2; idx < 4; idx++) {
for (idx = 2; idx < 4; idx++) if (p_midi_host->stream_read.buffer[idx] <= MIDI_MAX_DATA_VAL) {
{
if (p_midi_host->stream_read.buffer[idx] <= MIDI_MAX_DATA_VAL)
{
++bytes_to_add_to_stream; ++bytes_to_add_to_stream;
} } else if (p_midi_host->stream_read.buffer[idx] == MIDI_STATUS_SYSEX_END) {
else if (p_midi_host->stream_read.buffer[idx] == MIDI_STATUS_SYSEX_END)
{
++bytes_to_add_to_stream; ++bytes_to_add_to_stream;
cable_sysex_in_progress &= (uint16_t) ~cable_mask; cable_sysex_in_progress &= (uint16_t) ~cable_mask;
idx = 4;// force the loop to exit; I hate break statements in loops idx = 4;// force the loop to exit; I hate break statements in loops
} }
} }
} }
} } else if (status < MIDI_STATUS_SYSEX_START) {
else if (status < MIDI_STATUS_SYSEX_START)
{
// then it is a channel message either three bytes or two // then it is a channel message either three bytes or two
uint8_t fake_cin = (status & 0xf0) >> 4; uint8_t fake_cin = (status & 0xf0) >> 4;
switch (fake_cin) switch (fake_cin) {
{
case MIDI_CIN_NOTE_OFF: case MIDI_CIN_NOTE_OFF:
case MIDI_CIN_NOTE_ON: case MIDI_CIN_NOTE_ON:
case MIDI_CIN_POLY_KEYPRESS: case MIDI_CIN_POLY_KEYPRESS:
@@ -768,11 +638,8 @@ uint32_t tuh_midi_stream_read (uint8_t dev_addr, uint8_t *p_cable_num, uint8_t *
break;// Should not get this break;// Should not get this
} }
cable_sysex_in_progress &= (uint16_t) ~cable_mask; cable_sysex_in_progress &= (uint16_t) ~cable_mask;
} } else if (status < MIDI_STATUS_SYSREAL_TIMING_CLOCK) {
else if (status < MIDI_STATUS_SYSREAL_TIMING_CLOCK) switch (status) {
{
switch (status)
{
case MIDI_STATUS_SYSCOM_TIME_CODE_QUARTER_FRAME: case MIDI_STATUS_SYSCOM_TIME_CODE_QUARTER_FRAME:
case MIDI_STATUS_SYSCOM_SONG_SELECT: case MIDI_STATUS_SYSCOM_SONG_SELECT:
bytes_to_add_to_stream = 2; bytes_to_add_to_stream = 2;
@@ -788,28 +655,22 @@ uint32_t tuh_midi_stream_read (uint8_t dev_addr, uint8_t *p_cable_num, uint8_t *
break; break;
cable_sysex_in_progress &= (uint16_t) ~cable_mask; cable_sysex_in_progress &= (uint16_t) ~cable_mask;
} }
} } else {
else
{
// Real-time message: can be inserted into a sysex message, // Real-time message: can be inserted into a sysex message,
// so do don't clear cable_sysex_in_progress bit // so do don't clear cable_sysex_in_progress bit
bytes_to_add_to_stream = 1; bytes_to_add_to_stream = 1;
} }
} }
uint8_t idx; for (uint8_t idx = 1; idx <= bytes_to_add_to_stream; idx++) {
for (idx = 1; idx <= bytes_to_add_to_stream; idx++)
{
*p_buffer++ = p_midi_host->stream_read.buffer[idx]; *p_buffer++ = p_midi_host->stream_read.buffer[idx];
} }
bytes_buffered += bytes_to_add_to_stream; bytes_buffered += bytes_to_add_to_stream;
nread = 0; nread = 0;
if (tu_fifo_peek(&p_midi_host->rx_ff, &one_byte)) if (tu_edpt_stream_peek(&p_midi_host->ep_stream.rx, &one_byte)) {
{
uint8_t new_cable = (one_byte >> 4) & 0xf; uint8_t new_cable = (one_byte >> 4) & 0xf;
if (new_cable == *p_cable_num) if (new_cable == *p_cable_num) {
{
// still on the same cable. Continue reading the stream // still on the same cable. Continue reading the stream
nread = tu_fifo_read_n(&p_midi_host->rx_ff, p_midi_host->stream_read.buffer, 4); nread = tu_edpt_stream_read(dev_addr, &p_midi_host->ep_stream.rx, p_midi_host->stream_read.buffer, 4);
} }
} }
} }
@@ -865,19 +726,14 @@ static uint8_t find_string_index(midih_interface_t *ptr, uint8_t jack_id)
#endif #endif
#if CFG_MIDI_HOST_DEVSTRINGS #if CFG_MIDI_HOST_DEVSTRINGS
uint8_t tuh_midi_get_rx_cable_istrings(uint8_t dev_addr, uint8_t* istrings, uint8_t max_istrings) uint8_t tuh_midi_get_rx_cable_istrings(uint8_t dev_addr, uint8_t* istrings, uint8_t max_istrings) {
{
uint8_t nstrings = 0;
midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr);
TU_VERIFY(p_midi_host != NULL); TU_VERIFY(p_midi_host != NULL, 0);
nstrings = p_midi_host->num_cables_rx; uint8_t nstrings = p_midi_host->num_cables_rx;
if (nstrings > max_istrings) if (nstrings > max_istrings) {
{
nstrings = max_istrings; nstrings = max_istrings;
} }
uint8_t jack; for (uint8_t jack = 0; jack<nstrings; jack++) {
for (jack=0; jack<nstrings; jack++)
{
uint8_t jack_id = p_midi_host->ep_in_associated_jacks[jack]; uint8_t jack_id = p_midi_host->ep_in_associated_jacks[jack];
istrings[jack] = find_string_index(p_midi_host, jack_id); istrings[jack] = find_string_index(p_midi_host, jack_id);
} }
@@ -886,17 +742,13 @@ uint8_t tuh_midi_get_rx_cable_istrings(uint8_t dev_addr, uint8_t* istrings, uint
uint8_t tuh_midi_get_tx_cable_istrings(uint8_t dev_addr, uint8_t* istrings, uint8_t max_istrings) uint8_t tuh_midi_get_tx_cable_istrings(uint8_t dev_addr, uint8_t* istrings, uint8_t max_istrings)
{ {
uint8_t nstrings = 0;
midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr);
TU_VERIFY(p_midi_host != NULL); TU_VERIFY(p_midi_host != NULL, 0);
nstrings = p_midi_host->num_cables_tx; uint8_t nstrings = p_midi_host->num_cables_tx;
if (nstrings > max_istrings) if (nstrings > max_istrings) {
{
nstrings = max_istrings; nstrings = max_istrings;
} }
uint8_t jack; for (uint8_t jack = 0; jack<nstrings; jack++) {
for (jack=0; jack<nstrings; jack++)
{
uint8_t jack_id = p_midi_host->ep_out_associated_jacks[jack]; uint8_t jack_id = p_midi_host->ep_out_associated_jacks[jack];
istrings[jack] = find_string_index(p_midi_host, jack_id); istrings[jack] = find_string_index(p_midi_host, jack_id);
} }
@@ -909,8 +761,7 @@ uint8_t tuh_midi_get_all_istrings(uint8_t dev_addr, const uint8_t** istrings)
midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr);
TU_VERIFY(p_midi_host != NULL); TU_VERIFY(p_midi_host != NULL);
uint8_t nstrings = p_midi_host->num_string_indices; uint8_t nstrings = p_midi_host->num_string_indices;
if (nstrings) if (nstrings) { *istrings = p_midi_host->all_string_indices; }
*istrings = p_midi_host->all_string_indices;
return nstrings; return nstrings;
} }
#endif #endif

View File

@@ -42,15 +42,15 @@
#endif #endif
#ifndef CFG_TUH_MIDI_RX_BUFSIZE #ifndef CFG_TUH_MIDI_RX_BUFSIZE
#define CFG_TUH_MIDI_RX_BUFSIZE 64 #define CFG_TUH_MIDI_RX_BUFSIZE TUH_EPSIZE_BULK_MPS
#endif #endif
#ifndef CFG_TUH_MIDI_TX_BUFSIZE #ifndef CFG_TUH_MIDI_TX_BUFSIZE
#define CFG_TUH_MIDI_TX_BUFSIZE 64 #define CFG_TUH_MIDI_TX_BUFSIZE TUH_EPSIZE_BULK_MPS
#endif #endif
#ifndef CFG_TUH_MIDI_EP_BUFSIZE #ifndef CFG_TUH_MIDI_EP_BUFSIZE
#define CFG_TUH_MIDI_EP_BUFSIZE 64 #define CFG_TUH_MIDI_EP_BUFSIZE TUH_EPSIZE_BULK_MPS
#endif #endif
#ifndef CFG_MIDI_HOST_DEVSTRINGS #ifndef CFG_MIDI_HOST_DEVSTRINGS
@@ -113,14 +113,6 @@ uint8_t tuh_midi_get_rx_cable_istrings(uint8_t dev_addr, uint8_t* istrings, uint
uint8_t tuh_midi_get_tx_cable_istrings(uint8_t dev_addr, uint8_t* istrings, uint8_t max_istrings); uint8_t tuh_midi_get_tx_cable_istrings(uint8_t dev_addr, uint8_t* istrings, uint8_t max_istrings);
uint8_t tuh_midi_get_all_istrings(uint8_t dev_addr, const uint8_t** istrings); uint8_t tuh_midi_get_all_istrings(uint8_t dev_addr, const uint8_t** istrings);
#endif #endif
//--------------------------------------------------------------------+
// Internal Class Driver API
//--------------------------------------------------------------------+
bool midih_init (void);
bool midih_open (uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len);
bool midih_set_config (uint8_t dev_addr, uint8_t itf_num);
bool midih_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes);
void midih_close (uint8_t dev_addr);
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// Callbacks (Weak is optional) // Callbacks (Weak is optional)
@@ -138,6 +130,17 @@ TU_ATTR_WEAK void tuh_midi_umount_cb(uint8_t dev_addr, uint8_t instance);
TU_ATTR_WEAK void tuh_midi_rx_cb(uint8_t dev_addr, uint32_t num_packets); TU_ATTR_WEAK void tuh_midi_rx_cb(uint8_t dev_addr, uint32_t num_packets);
TU_ATTR_WEAK void tuh_midi_tx_cb(uint8_t dev_addr); TU_ATTR_WEAK void tuh_midi_tx_cb(uint8_t dev_addr);
//--------------------------------------------------------------------+
// Internal Class Driver API
//--------------------------------------------------------------------+
bool midih_init (void);
bool midih_deinit (void);
bool midih_open (uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len);
bool midih_set_config (uint8_t dev_addr, uint8_t itf_num);
bool midih_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes);
void midih_close (uint8_t dev_addr);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -138,7 +138,7 @@ uint32_t tu_edpt_stream_read(uint8_t hwid, tu_edpt_stream_t* s, void* buffer, ui
// Start an usb transfer if endpoint is not busy // Start an usb transfer if endpoint is not busy
uint32_t tu_edpt_stream_read_xfer(uint8_t hwid, tu_edpt_stream_t* s); uint32_t tu_edpt_stream_read_xfer(uint8_t hwid, tu_edpt_stream_t* s);
// Must be called in the transfer complete callback // Complete read transfer by writing EP -> FIFO. Must be called in the transfer complete callback
TU_ATTR_ALWAYS_INLINE static inline TU_ATTR_ALWAYS_INLINE static inline
void tu_edpt_stream_read_xfer_complete(tu_edpt_stream_t* s, uint32_t xferred_bytes) { void tu_edpt_stream_read_xfer_complete(tu_edpt_stream_t* s, uint32_t xferred_bytes) {
if (tu_fifo_depth(&s->ff)) { if (tu_fifo_depth(&s->ff)) {
@@ -146,11 +146,11 @@ void tu_edpt_stream_read_xfer_complete(tu_edpt_stream_t* s, uint32_t xferred_byt
} }
} }
// Same as tu_edpt_stream_read_xfer_complete but skip the first n bytes // Complete read transfer with provided buffer
TU_ATTR_ALWAYS_INLINE static inline TU_ATTR_ALWAYS_INLINE static inline
void tu_edpt_stream_read_xfer_complete_offset(tu_edpt_stream_t* s, uint32_t xferred_bytes, uint32_t skip_offset) { void tu_edpt_stream_read_xfer_complete_with_buf(tu_edpt_stream_t* s, const void * buf, uint32_t xferred_bytes) {
if (tu_fifo_depth(&s->ff) && (skip_offset < xferred_bytes)) { if (tu_fifo_depth(&s->ff)) {
tu_fifo_write_n(&s->ff, s->ep_buf + skip_offset, (uint16_t) (xferred_bytes - skip_offset)); tu_fifo_write_n(&s->ff, buf, (uint16_t) xferred_bytes);
} }
} }

View File

@@ -192,6 +192,7 @@ static usbh_class_driver_t const usbh_class_drivers[] = {
{ {
.name = DRIVER_NAME("MIDI"), .name = DRIVER_NAME("MIDI"),
.init = midih_init, .init = midih_init,
.deinit = midih_deinit,
.open = midih_open, .open = midih_open,
.set_config = midih_set_config, .set_config = midih_set_config,
.xfer_cb = midih_xfer_cb, .xfer_cb = midih_xfer_cb,
@@ -1672,7 +1673,7 @@ static bool _parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configur
if ( 0 == tu_desc_len(p_desc) ) { if ( 0 == tu_desc_len(p_desc) ) {
// A zero length descriptor indicates that the device is off spec (e.g. wrong wTotalLength). // A zero length descriptor indicates that the device is off spec (e.g. wrong wTotalLength).
// Parsed interfaces should still be usable // Parsed interfaces should still be usable
TU_LOG_USBH("Encountered a zero-length descriptor after %u bytes\r\n", (uint32_t)p_desc - (uint32_t)desc_cfg); TU_LOG_USBH("Encountered a zero-length descriptor after %" PRIu32 " bytes\r\n", (uint32_t)p_desc - (uint32_t)desc_cfg);
break; break;
} }

View File

@@ -37,6 +37,9 @@
// MACRO CONSTANT TYPEDEF // MACRO CONSTANT TYPEDEF
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// Endpoint Bulk size depending on host mx speed
#define TUH_EPSIZE_BULK_MPS (TUD_OPT_HIGH_SPEED ? TUSB_EPSIZE_BULK_HS : TUSB_EPSIZE_BULK_FS)
// forward declaration // forward declaration
struct tuh_xfer_s; struct tuh_xfer_s;
typedef struct tuh_xfer_s tuh_xfer_t; typedef struct tuh_xfer_s tuh_xfer_t;