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 ) {
#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
// 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
#endif
{

View File

@@ -45,15 +45,12 @@ typedef struct
uint8_t total;
}midi_stream_t;
typedef struct
{
typedef struct {
uint8_t dev_addr;
uint8_t itf_num;
uint8_t ep_in; // IN 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_tx; // OUT endpoint CS descriptor bNumEmbMIDIJack value
@@ -65,22 +62,14 @@ typedef struct
midi_stream_t stream_read;
/*------------- From this point, data is not cleared by bus reset -------------*/
// Endpoint FIFOs
tu_fifo_t rx_ff;
tu_fifo_t tx_ff;
// Endpoint stream
struct {
tu_edpt_stream_t tx;
tu_edpt_stream_t rx;
uint8_t rx_ff_buf[CFG_TUH_MIDI_RX_BUFSIZE];
uint8_t tx_ff_buf[CFG_TUH_MIDI_TX_BUFSIZE];
#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];
uint8_t rx_ff_buf[CFG_TUH_MIDI_RX_BUFSIZE];
uint8_t tx_ff_buf[CFG_TUH_MIDI_TX_BUFSIZE];
} ep_stream;
bool configured;
@@ -109,15 +98,17 @@ typedef struct
#endif
}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 uint32_t write_flush(uint8_t dev_addr, midih_interface_t* midi);
static midih_interface_t _midi_host[CFG_TUH_MIDI];
CFG_TUH_MEM_SECTION static midih_epbuf_t _midi_epbuf[CFG_TUH_MIDI];
//--------------------------------------------------------------------+
// Helper
//--------------------------------------------------------------------+
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++) {
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);
}
//--------------------------------------------------------------------+
// USBH API
//--------------------------------------------------------------------+
bool midih_init(void) {
tu_memclr(&_midi_host, sizeof(_midi_host));
// config fifos
for (int inst = 0; inst < CFG_TUH_MIDI; 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_fifo_config(&p_midi_host->tx_ff, p_midi_host->tx_ff_buf, CFG_TUH_MIDI_TX_BUFSIZE, 1, false);// OBVS.
#if CFG_FIFO_MUTEX
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
tu_edpt_stream_init(&p_midi_host->ep_stream.rx, true, false, false,
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,
p_midi_host->ep_stream.tx_ff_buf, CFG_TUH_MIDI_TX_BUFSIZE, _midi_epbuf->tx, TUH_EPSIZE_BULK_MPS);
}
return true;
}
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_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);
}
bool midih_deinit(void) {
for (size_t i = 0; i < CFG_TUH_MIDI; i++) {
midih_interface_t* p_midi = &_midi_host[i];
tu_edpt_stream_deinit(&p_midi->ep_stream.rx);
tu_edpt_stream_deinit(&p_midi->ep_stream.tx);
}
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;
}
@@ -221,26 +154,67 @@ void midih_close(uint8_t dev_addr) {
if (tuh_midi_umount_cb) {
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_max = 0;
p_midi_host->ep_out = 0;
p_midi_host->ep_out_max = 0;
p_midi_host->itf_num = 0;
p_midi_host->num_cables_rx = 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;
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_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
//--------------------------------------------------------------------+
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;
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->num_cables_tx == 0);
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;
out_desc = p_ep;
} else {
TU_VERIFY(p_midi_host->ep_in == 0);
TU_VERIFY(p_midi_host->num_cables_rx == 0);
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;
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) {
TU_ASSERT(tuh_edpt_open(dev_addr, in_desc));
// Some devices always return exactly the request length so transfers won't complete
// unless you assume every transfer is the last one.
// TODO usbh_edpt_force_last_buffer(dev_addr, p_midi_host->ep_in, true);
tu_edpt_stream_open(&p_midi_host->ep_stream.rx, in_desc);
}
if (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;
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;
}
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);
TU_VERIFY(p_midi_host != NULL);
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;
midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr);
TU_VERIFY(p_midi_host != NULL);
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);
return true;
}
@@ -476,71 +440,32 @@ bool midih_set_config(uint8_t dev_addr, uint8_t itf_num)
//--------------------------------------------------------------------+
// 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) {
midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr);
TU_VERIFY(p_midi_host != NULL);
bool result = false;
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;
return tu_edpt_stream_read_xfer(dev_addr, &p_midi_host->ep_stream.rx) > 0;
}
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);
TU_VERIFY(p_midi_host != NULL);
TU_VERIFY(cable_num < p_midi_host->num_cables_tx);
midi_stream_t *stream = &p_midi_host->stream_write;
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];
i++;
if (data >= MIDI_STATUS_SYSREAL_TIMING_CLOCK)
{
if (data >= MIDI_STATUS_SYSREAL_TIMING_CLOCK) {
// real-time messages need to be sent right away
midi_stream_t streamrt;
streamrt.buffer[0] = MIDI_CIN_SYSEX_END_1BYTE;
streamrt.buffer[1] = data;
streamrt.index = 2;
streamrt.total = 2;
uint16_t const count = tu_fifo_write_n(&p_midi_host->tx_ff, streamrt.buffer, 4);
// FIFO overflown, since we already check fifo remaining. It is probably race condition
TU_ASSERT(count == 4, i);
}
else if ( stream->index == 0 )
{
uint32_t const count = tu_edpt_stream_write(dev_addr, &p_midi_host->ep_stream.tx, streamrt.buffer, 4);
TU_ASSERT(count == 4, i); // Check FIFO overflown, since we already check fifo remaining. It is probably race condition
} else if (stream->index == 0) {
//------------- New event packet -------------//
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;
// Check to see if we're still in a SysEx transmit.
if ( stream->buffer[0] == MIDI_CIN_SYSEX_START )
{
if ( data == MIDI_STATUS_SYSEX_END )
{
if (stream->buffer[0] == MIDI_CIN_SYSEX_START) {
if (data == MIDI_STATUS_SYSEX_END) {
stream->buffer[0] = MIDI_CIN_SYSEX_END_1BYTE;
stream->total = 2;
}
else
{
} else {
stream->total = 4;
}
}
else if ( (msg >= 0x8 && msg <= 0xB) || msg == 0xE )
{
} else if ((msg >= 0x8 && msg <= 0xB) || msg == 0xE) {
// Channel Voice Messages
stream->buffer[0] = (uint8_t) ((cable_num << 4) | msg);
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)
stream->buffer[0] = (uint8_t) ((cable_num << 4) | msg);
stream->total = 3;
}
else if ( msg == 0xf )
{
} else if (msg == 0xf) {
// System message
if ( data == MIDI_STATUS_SYSEX_START )
{
if (data == MIDI_STATUS_SYSEX_START) {
stream->buffer[0] = MIDI_CIN_SYSEX_START;
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->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->total = 4;
}
else
{
} else {
stream->buffer[0] = MIDI_CIN_SYSEX_END_1BYTE;
stream->total = 2;
}
}
else
{
} else {
// Pack individual bytes if we don't support packing them into words.
stream->buffer[0] = (uint8_t) (cable_num << 4 | 0xf);
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->total = 2;
}
}
else
{
} else {
//------------- On-going (buffering) packet -------------//
TU_ASSERT(stream->index < 4, i);
stream->buffer[stream->index] = data;
stream->index++;
// 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->total = stream->index;
}
}
// Send out packet
if ( stream->index >= 2 && stream->index == stream->total )
{
if (stream->index >= 2 && stream->index == stream->total) {
// 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);
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
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;
}
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);
TU_VERIFY(p_midi_host != NULL);
if (tu_fifo_remaining(&p_midi_host->tx_ff) < 4)
{
return false;
}
tu_fifo_write_n(&p_midi_host->tx_ff, packet, 4);
return true;
return 4 == tu_edpt_stream_write(dev_addr, &p_midi_host->ep_stream.tx, packet, 4);
}
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;
uint32_t tuh_midi_stream_flush(uint8_t dev_addr) {
midih_interface_t *p_midi = find_midi_by_daddr(dev_addr);
TU_VERIFY(p_midi != NULL);
return tu_edpt_stream_write_xfer(p_midi->dev_addr, &p_midi->ep_stream.tx);
}
//--------------------------------------------------------------------+
// 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);
TU_VERIFY(p_midi_host != NULL);
TU_VERIFY(tu_fifo_count(&p_midi_host->rx_ff) >= 4);
return tu_fifo_read_n(&p_midi_host->rx_ff, packet, 4) == 4;
TU_VERIFY(tu_edpt_stream_read_available(&p_midi_host->ep_stream.rx) >= 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);
TU_VERIFY(p_midi_host != NULL);
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(bufsize);
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;
}
*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
while (nread == 4 && bytes_buffered < bufsize)
{
*p_cable_num=(p_midi_host->stream_read.buffer[0] >> 4) & 0x0f;
while (nread == 4 && bytes_buffered < bufsize) {
*p_cable_num = (p_midi_host->stream_read.buffer[0] >> 4) & 0x0f;
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
uint8_t status = p_midi_host->stream_read.buffer[1];
uint16_t cable_mask = (uint16_t) (1 << *p_cable_num);
if (status <= MIDI_MAX_DATA_VAL || status == MIDI_STATUS_SYSEX_START)
{
if (status == MIDI_STATUS_SYSEX_START)
{
if (status <= MIDI_MAX_DATA_VAL || status == MIDI_STATUS_SYSEX_START) {
if (status == MIDI_STATUS_SYSEX_START) {
cable_sysex_in_progress |= cable_mask;
}
// 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;
uint8_t idx;
for (idx = 2; idx < 4; idx++)
{
if (p_midi_host->stream_read.buffer[idx] <= MIDI_MAX_DATA_VAL)
{
for (uint8_t idx = 2; idx < 4; idx++) {
if (p_midi_host->stream_read.buffer[idx] <= MIDI_MAX_DATA_VAL) {
++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;
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
uint8_t fake_cin = (status & 0xf0) >> 4;
switch (fake_cin)
{
switch (fake_cin) {
case MIDI_CIN_NOTE_OFF:
case MIDI_CIN_NOTE_ON:
case MIDI_CIN_POLY_KEYPRESS:
@@ -765,14 +635,11 @@ uint32_t tuh_midi_stream_read (uint8_t dev_addr, uint8_t *p_cable_num, uint8_t *
bytes_to_add_to_stream = 2;
break;
default:
break; // Should not get this
break;// Should not get this
}
cable_sysex_in_progress &= (uint16_t)~cable_mask;
}
else if (status < MIDI_STATUS_SYSREAL_TIMING_CLOCK)
{
switch (status)
{
cable_sysex_in_progress &= (uint16_t) ~cable_mask;
} else if (status < MIDI_STATUS_SYSREAL_TIMING_CLOCK) {
switch (status) {
case MIDI_STATUS_SYSCOM_TIME_CODE_QUARTER_FRAME:
case MIDI_STATUS_SYSCOM_SONG_SELECT:
bytes_to_add_to_stream = 2;
@@ -786,30 +653,24 @@ uint32_t tuh_midi_stream_read (uint8_t dev_addr, uint8_t *p_cable_num, uint8_t *
break;
default:
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,
// so do don't clear cable_sysex_in_progress bit
bytes_to_add_to_stream = 1;
}
}
uint8_t idx;
for (idx = 1; idx <= bytes_to_add_to_stream; idx++)
{
for (uint8_t idx = 1; idx <= bytes_to_add_to_stream; idx++) {
*p_buffer++ = p_midi_host->stream_read.buffer[idx];
}
bytes_buffered += bytes_to_add_to_stream;
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;
if (new_cable == *p_cable_num)
{
if (new_cable == *p_cable_num) {
// 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
#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 nstrings = 0;
uint8_t tuh_midi_get_rx_cable_istrings(uint8_t dev_addr, uint8_t* istrings, uint8_t max_istrings) {
midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr);
TU_VERIFY(p_midi_host != NULL);
nstrings = p_midi_host->num_cables_rx;
if (nstrings > max_istrings)
{
nstrings = max_istrings;
TU_VERIFY(p_midi_host != NULL, 0);
uint8_t nstrings = p_midi_host->num_cables_rx;
if (nstrings > max_istrings) {
nstrings = max_istrings;
}
uint8_t jack;
for (jack=0; jack<nstrings; jack++)
{
for (uint8_t jack = 0; jack<nstrings; jack++) {
uint8_t jack_id = p_midi_host->ep_in_associated_jacks[jack];
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 nstrings = 0;
midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr);
TU_VERIFY(p_midi_host != NULL);
nstrings = p_midi_host->num_cables_tx;
if (nstrings > max_istrings)
{
nstrings = max_istrings;
TU_VERIFY(p_midi_host != NULL, 0);
uint8_t nstrings = p_midi_host->num_cables_tx;
if (nstrings > max_istrings) {
nstrings = max_istrings;
}
uint8_t jack;
for (jack=0; jack<nstrings; jack++)
{
for (uint8_t jack = 0; jack<nstrings; jack++) {
uint8_t jack_id = p_midi_host->ep_out_associated_jacks[jack];
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);
TU_VERIFY(p_midi_host != NULL);
uint8_t nstrings = p_midi_host->num_string_indices;
if (nstrings)
*istrings = p_midi_host->all_string_indices;
if (nstrings) { *istrings = p_midi_host->all_string_indices; }
return nstrings;
}
#endif

View File

@@ -42,15 +42,15 @@
#endif
#ifndef CFG_TUH_MIDI_RX_BUFSIZE
#define CFG_TUH_MIDI_RX_BUFSIZE 64
#define CFG_TUH_MIDI_RX_BUFSIZE TUH_EPSIZE_BULK_MPS
#endif
#ifndef CFG_TUH_MIDI_TX_BUFSIZE
#define CFG_TUH_MIDI_TX_BUFSIZE 64
#define CFG_TUH_MIDI_TX_BUFSIZE TUH_EPSIZE_BULK_MPS
#endif
#ifndef CFG_TUH_MIDI_EP_BUFSIZE
#define CFG_TUH_MIDI_EP_BUFSIZE 64
#define CFG_TUH_MIDI_EP_BUFSIZE TUH_EPSIZE_BULK_MPS
#endif
#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_all_istrings(uint8_t dev_addr, const uint8_t** istrings);
#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)
@@ -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_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
}
#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
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
void tu_edpt_stream_read_xfer_complete(tu_edpt_stream_t* s, uint32_t xferred_bytes) {
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
void tu_edpt_stream_read_xfer_complete_offset(tu_edpt_stream_t* s, uint32_t xferred_bytes, uint32_t skip_offset) {
if (tu_fifo_depth(&s->ff) && (skip_offset < xferred_bytes)) {
tu_fifo_write_n(&s->ff, s->ep_buf + skip_offset, (uint16_t) (xferred_bytes - 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)) {
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"),
.init = midih_init,
.deinit = midih_deinit,
.open = midih_open,
.set_config = midih_set_config,
.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) ) {
// A zero length descriptor indicates that the device is off spec (e.g. wrong wTotalLength).
// 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;
}

View File

@@ -37,6 +37,9 @@
// 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
struct tuh_xfer_s;
typedef struct tuh_xfer_s tuh_xfer_t;