Просмотр исходного кода

Merge pull request #618 from homeodor/master

A CDC-like blocking behaviour for MIDI, incl. SysEx
Ha Thach 5 лет назад
Родитель
Сommit
be1bd74b4b

+ 6 - 0
examples/device/dynamic_configuration/src/main.c

@@ -165,6 +165,12 @@ void midi_task(void)
 {
   static uint32_t start_ms = 0;
 
+  // The MIDI interface always creates input and output port/jack descriptors
+  // regardless of these being used or not. Therefore incoming traffic should be read
+  // (possibly just discarded) to avoid the sender blocking in IO
+  uint8_t packet[4];
+  while(tud_midi_available()) tud_midi_receive(packet);
+
   // send note every 1000 ms
   if (board_millis() - start_ms < 286) return; // not enough time
   start_ms += 286;

+ 6 - 0
examples/device/midi_test/src/main.c

@@ -125,6 +125,12 @@ void midi_task(void)
 {
   static uint32_t start_ms = 0;
 
+  // The MIDI interface always creates input and output port/jack descriptors
+  // regardless of these being used or not. Therefore incoming traffic should be read
+  // (possibly just discarded) to avoid the sender blocking in IO
+  uint8_t packet[4];
+  while(tud_midi_available()) tud_midi_receive(packet);
+
   // send note every 1000 ms
   if (board_millis() - start_ms < 286) return; // not enough time
   start_ms += 286;

+ 38 - 10
src/class/midi/midi_device.c

@@ -85,6 +85,32 @@ 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)
+{
+  uint8_t const rhport = TUD_OPT_RHPORT;
+  uint16_t available = tu_fifo_remaining(&p_midi->rx_ff);
+
+  // Prepare for incoming data but only allow what we can store in the ring buffer.
+  // TODO Actually we can still carry out the transfer, keeping count of received bytes
+  // and slowly move it to the FIFO when read().
+  // This pre-check reduces endpoint claiming
+  TU_VERIFY(available >= sizeof(p_midi->epout_buf), );
+
+  // claim endpoint
+  TU_VERIFY(usbd_edpt_claim(rhport, p_midi->ep_out), );
+
+  // fifo can be changed before endpoint is claimed
+  available = tu_fifo_remaining(&p_midi->rx_ff);
+
+  if ( available >= sizeof(p_midi->epout_buf) )  {
+    usbd_edpt_xfer(rhport, p_midi->ep_out, p_midi->epout_buf, sizeof(p_midi->epout_buf));
+  }else
+  {
+    // Release endpoint since we don't make any transfer
+    usbd_edpt_release(rhport, p_midi->ep_out);
+  }
+}
+
 //--------------------------------------------------------------------+
 // READ API
 //--------------------------------------------------------------------+
@@ -135,12 +161,17 @@ uint32_t tud_midi_n_read(uint8_t itf, uint8_t jack_id, void* buffer, uint32_t bu
 void tud_midi_n_read_flush (uint8_t itf, uint8_t jack_id)
 {
   (void) jack_id;
-  tu_fifo_clear(&_midid_itf[itf].rx_ff);
+  midid_interface_t* p_midi = &_midid_itf[itf];
+  tu_fifo_clear(&p_midi->rx_ff);
+  _prep_out_transaction(p_midi);
 }
 
 bool tud_midi_n_receive (uint8_t itf, uint8_t packet[4])
 {
-  return tu_fifo_read_n(&_midid_itf[itf].rx_ff, packet, 4);
+  midid_interface_t* p_midi = &_midid_itf[itf];
+  uint32_t num_read = tu_fifo_read_n(&p_midi->rx_ff, packet, 4);
+  _prep_out_transaction(p_midi);
+  return (num_read == 4);
 }
 
 void midi_rx_done_cb(midid_interface_t* midi, uint8_t const* buffer, uint32_t bufsize) {
@@ -275,8 +306,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); // true, true
+    tu_fifo_config(&midi->tx_ff, midi->tx_ff_buf, CFG_TUD_MIDI_TX_BUFSIZE, 1, false); // OBVS.
 
     #if CFG_FIFO_MUTEX
     tu_fifo_config_mutex(&midi->rx_ff, osal_mutex_create(&midi->rx_ff_mutex));
@@ -367,11 +398,7 @@ uint16_t midid_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, uint
   }
 
   // Prepare for incoming data
-  if ( !usbd_edpt_xfer(rhport, p_midi->ep_out, p_midi->epout_buf, CFG_TUD_MIDI_EP_BUFSIZE) )
-  {
-    TU_LOG1_FAILED();
-    TU_BREAKPOINT();
-  }
+  _prep_out_transaction(p_midi);
 
   return drv_len;
 }
@@ -392,6 +419,7 @@ bool midid_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t
 bool midid_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
 {
   (void) result;
+  (void) rhport;
 
   uint8_t itf;
   midid_interface_t* p_midi;
@@ -415,7 +443,7 @@ bool midid_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32
     // prepare for next
     // TODO for now ep_out is not used by public API therefore there is no race condition,
     // and does not need to claim like ep_in
-    TU_ASSERT(usbd_edpt_xfer(rhport, p_midi->ep_out, p_midi->epout_buf, CFG_TUD_MIDI_EP_BUFSIZE), false);
+    _prep_out_transaction(p_midi);
   }
   else if ( ep_addr == p_midi->ep_in )
   {