From a0598ef3699c1b502a499d76c26bd48d48355384 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Sun, 19 Apr 2020 11:44:15 +0200 Subject: [PATCH] MIDI - Add flow control to incoming packet stream Larger SysEx transfers get corrupted by incoming packets. This changes the FIFOs not to overwrite their data. MIDI should not be a transport that drops packets. A potentially blocking device is easier to detect and handle than a device that silently corrupts the packet stream at random overflows, especially when SysEx messages are involved. --- src/class/midi/midi_device.c | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/src/class/midi/midi_device.c b/src/class/midi/midi_device.c index 56a27fbce..589d0123f 100644 --- a/src/class/midi/midi_device.c +++ b/src/class/midi/midi_device.c @@ -85,6 +85,18 @@ bool tud_midi_n_mounted (uint8_t itf) return midi->ep_in && midi->ep_out; } +static void _prep_out_transaction (midid_interface_t* p_midi) +{ + // skip if previous transfer not complete + if ( usbd_edpt_busy(TUD_OPT_RHPORT, p_midi->ep_out) ) + return; + + // Prepare for incoming data but only allow what we can store in the ring buffer. + uint16_t max_read = tu_fifo_remaining(&p_midi->rx_ff); + if ( max_read >= CFG_TUD_MIDI_EPSIZE ) + usbd_edpt_xfer(TUD_OPT_RHPORT, p_midi->ep_out, p_midi->epout_buf, CFG_TUD_MIDI_EPSIZE); +} + //--------------------------------------------------------------------+ // READ API //--------------------------------------------------------------------+ @@ -138,11 +150,17 @@ void tud_midi_n_read_flush (uint8_t itf, uint8_t jack_id) { (void) jack_id; tu_fifo_clear(&_midid_itf[itf].rx_ff); + + if (tud_ready() && &_midid_itf[itf].ep_out != 0) + _prep_out_transaction(&_midid_itf[itf]); } bool tud_midi_n_receive (uint8_t itf, uint8_t packet[4]) { - return tu_fifo_read_n(&_midid_itf[itf].rx_ff, packet, 4); + if (tud_ready() && &_midid_itf[itf].ep_out != 0) + _prep_out_transaction(&_midid_itf[itf]); + + return tu_fifo_read_n(&_midid_itf[itf].rx_ff, packet, 4) == 4; } void midi_rx_done_cb(midid_interface_t* midi, uint8_t const* buffer, uint32_t bufsize) { @@ -267,8 +285,8 @@ void midid_init(void) midid_interface_t* midi = &_midid_itf[i]; // config fifo - tu_fifo_config(&midi->rx_ff, midi->rx_ff_buf, CFG_TUD_MIDI_RX_BUFSIZE, 1, true); - tu_fifo_config(&midi->tx_ff, midi->tx_ff_buf, CFG_TUD_MIDI_TX_BUFSIZE, 1, true); + tu_fifo_config(&midi->rx_ff, midi->rx_ff_buf, CFG_TUD_MIDI_RX_BUFSIZE, 1, false); + tu_fifo_config(&midi->tx_ff, midi->tx_ff_buf, CFG_TUD_MIDI_TX_BUFSIZE, 1, false); #if CFG_FIFO_MUTEX tu_fifo_config_mutex(&midi->rx_ff, osal_mutex_create(&midi->rx_ff_mutex)); @@ -358,7 +376,7 @@ bool midid_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, uint16_t *p_length = drv_len; // Prepare for incoming data - TU_ASSERT( usbd_edpt_xfer(rhport, p_midi->ep_out, p_midi->epout_buf, CFG_TUD_MIDI_EPSIZE), false); + _prep_out_transaction(p_midi); return true; } @@ -381,6 +399,7 @@ bool midid_control_request(uint8_t rhport, tusb_control_request_t const * p_requ bool midid_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) { + (void) rhport; (void) result; uint8_t itf = 0; @@ -399,7 +418,8 @@ bool midid_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32 midi_rx_done_cb(p_midi, p_midi->epout_buf, xferred_bytes); // prepare for next - TU_ASSERT( usbd_edpt_xfer(rhport, p_midi->ep_out, p_midi->epout_buf, CFG_TUD_MIDI_EPSIZE), false ); + _prep_out_transaction(p_midi); + } else if ( ep_addr == p_midi->ep_in ) { maybe_transmit(p_midi, itf); }