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

MIDI: Add packet interface

This changes the internal buffering to the raw 4-byte messages. The
conversion of the messages to a byte-stream moved to the read/write
methods.

It adds a raw packet interface to send and retrieve the raw 4-byte
USB MIDI message:
  static inline bool     tud_midi_receive    (uint8_t packet[4]);
  static inline bool     tud_midi_send       (uint8_t const packet[4]);

MIDI USB packets carry virtual cable/wire/plug data in the packet header,
which cannot be exported in the byte-stream interface. The raw packet
interface allows to send and and receive the complete USB message.
Kay Sievers 6 лет назад
Родитель
Сommit
73228a67ef
2 измененных файлов с 106 добавлено и 54 удалено
  1. 91 54
      src/class/midi/midi_device.c
  2. 15 0
      src/class/midi/midi_device.h

+ 91 - 54
src/class/midi/midi_device.c

@@ -56,11 +56,15 @@ typedef struct
   osal_mutex_def_t tx_ff_mutex;
   #endif
 
-  // We need to pack messages into words before queueing their transmission so buffer across write
-  // calls.
-  uint8_t message_buffer[4];
-  uint8_t message_buffer_length;
-  uint8_t message_target_length;
+  // Messages are always 4 bytes long, queue them for reading and writing so the
+  // callers can use the Stream interface with single-byte read/write calls.
+  uint8_t write_buffer[4];
+  uint8_t write_buffer_length;
+  uint8_t write_target_length;
+
+  uint8_t read_buffer[4];
+  uint8_t read_buffer_length;
+  uint8_t read_target_length;
 
   // Endpoint Transfer buffer
   CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_MIDI_EPSIZE];
@@ -93,24 +97,14 @@ uint32_t tud_midi_n_available(uint8_t itf, uint8_t jack_id)
 uint32_t tud_midi_n_read(uint8_t itf, uint8_t jack_id, void* buffer, uint32_t bufsize)
 {
   (void) jack_id;
-  return tu_fifo_read_n(&_midid_itf[itf].rx_ff, buffer, bufsize);
-}
-
-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* midi = &_midid_itf[itf];
 
-void midi_rx_done_cb(midid_interface_t* midi, uint8_t const* buffer, uint32_t bufsize) {
-  if (bufsize % 4 != 0) {
-    return;
-  }
+  // Fill empty buffer
+  if (midi->read_buffer_length == 0) {
+    if (!tud_midi_n_receive(itf, midi->read_buffer))
+      return 0;
 
-  for(uint32_t i=0; i<bufsize; i += 4) {
-    uint8_t header = buffer[i];
-    // uint8_t cable_number = (header & 0xf0) >> 4;
-    uint8_t code_index = header & 0x0f;
+    uint8_t code_index = midi->read_buffer[0] & 0x0f;
     // We always copy over the first byte.
     uint8_t count = 1;
     // Ignore subsequent bytes based on the code.
@@ -120,10 +114,40 @@ void midi_rx_done_cb(midid_interface_t* midi, uint8_t const* buffer, uint32_t bu
         count = 3;
       }
     }
-    tu_fifo_write_n(&midi->rx_ff, &buffer[i + 1], count);
+
+    midi->read_buffer_length = count;
+  }
+
+  uint32_t n = midi->read_buffer_length - midi->read_target_length;
+  if (bufsize < n)
+    n = bufsize;
+
+  // Skip the header in the buffer
+  memcpy(buffer, midi->read_buffer + 1 + midi->read_target_length, n);
+  midi->read_target_length += n;
+
+  if (midi->read_target_length == midi->read_buffer_length) {
+    midi->read_buffer_length = 0;
+    midi->read_target_length = 0;
   }
+
+  return n;
+}
+
+void tud_midi_n_read_flush (uint8_t itf, uint8_t jack_id)
+{
+  (void) jack_id;
+  tu_fifo_clear(&_midid_itf[itf].rx_ff);
+}
+
+bool tud_midi_n_receive (uint8_t itf, uint8_t packet[4])
+{
+  return tu_fifo_read_n(&_midid_itf[itf].rx_ff, packet, 4);
 }
 
+void midi_rx_done_cb(midid_interface_t* midi, uint8_t const* buffer, uint32_t bufsize) {
+  tu_fifo_write_n(&midi->rx_ff, buffer, bufsize);
+}
 
 //--------------------------------------------------------------------+
 // WRITE API
@@ -154,62 +178,59 @@ uint32_t tud_midi_n_write(uint8_t itf, uint8_t jack_id, uint8_t const* buffer, u
   uint32_t i = 0;
   while (i < bufsize) {
     uint8_t data = buffer[i];
-    if (midi->message_buffer_length == 0) {
+    if (midi->write_buffer_length == 0) {
         uint8_t msg = data >> 4;
-        midi->message_buffer[1] = data;
-        midi->message_buffer_length = 2;
+        midi->write_buffer[1] = data;
+        midi->write_buffer_length = 2;
         // Check to see if we're still in a SysEx transmit.
-        if (midi->message_buffer[0] == 0x4) {
+        if (midi->write_buffer[0] == 0x4) {
             if (data == 0xf7) {
-                midi->message_buffer[0] = 0x5;
+                midi->write_buffer[0] = 0x5;
             } else {
-                midi->message_buffer_length = 4;
+                midi->write_buffer_length = 4;
             }
         } else if ((msg >= 0x8 && msg <= 0xB) || msg == 0xE) {
-            midi->message_buffer[0] = jack_id << 4 | msg;
-            midi->message_target_length = 4;
-        } else if (msg == 0xC || msg == 0xD) {
-            midi->message_buffer[0] = jack_id << 4 | msg;
-            midi->message_target_length = 3;
+            midi->write_buffer[0] = jack_id << 4 | msg;
+            midi->write_target_length = 4;
         } else if (msg == 0xf) {
             if (data == 0xf0) {
-                midi->message_buffer[0] = 0x4;
-                midi->message_target_length = 4;
+                midi->write_buffer[0] = 0x4;
+                midi->write_target_length = 4;
             } else if (data == 0xf1 || data == 0xf3) {
-                midi->message_buffer[0] = 0x2;
-                midi->message_target_length = 3;
+                midi->write_buffer[0] = 0x2;
+                midi->write_target_length = 3;
             } else if (data == 0xf2) {
-                midi->message_buffer[0] = 0x3;
-                midi->message_target_length = 4;
+                midi->write_buffer[0] = 0x3;
+                midi->write_target_length = 4;
             } else {
-                midi->message_buffer[0] = 0x5;
-                midi->message_target_length = 2;
+                midi->write_buffer[0] = 0x5;
+                midi->write_target_length = 2;
             }
         } else {
             // Pack individual bytes if we don't support packing them into words.
-            midi->message_buffer[0] = jack_id << 4 | 0xf;
-            midi->message_buffer[2] = 0;
-            midi->message_buffer[3] = 0;
-            midi->message_buffer_length = 2;
-            midi->message_target_length = 2;
+            midi->write_buffer[0] = jack_id << 4 | 0xf;
+            midi->write_buffer[2] = 0;
+            midi->write_buffer[3] = 0;
+            midi->write_buffer_length = 2;
+            midi->write_target_length = 2;
         }
     } else {
-        midi->message_buffer[midi->message_buffer_length] = data;
-        midi->message_buffer_length += 1;
+        midi->write_buffer[midi->write_buffer_length] = data;
+        midi->write_buffer_length += 1;
         // See if this byte ends a SysEx.
-        if (midi->message_buffer[0] == 0x4 && data == 0xf7) {
-            midi->message_buffer[0] = 0x4 + (midi->message_buffer_length - 1);
-            midi->message_target_length = midi->message_buffer_length;
+        if (midi->write_buffer[0] == 0x4 && data == 0xf7) {
+            midi->write_buffer[0] = 0x4 + (midi->write_buffer_length - 1);
+            midi->write_target_length = midi->write_buffer_length;
         }
     }
 
-    if (midi->message_buffer_length == midi->message_target_length) {
-        uint16_t written = tu_fifo_write_n(&midi->tx_ff, midi->message_buffer, 4);
+    if (midi->write_buffer_length == midi->write_target_length) {
+        uint16_t written = tu_fifo_write_n(&midi->tx_ff, midi->write_buffer, 4);
         if (written < 4) {
             TU_ASSERT( written == 0 );
             break;
         }
-        midi->message_buffer_length = 0;
+        midi->write_buffer_length = 0;
     }
     i++;
   }
@@ -218,6 +239,22 @@ uint32_t tud_midi_n_write(uint8_t itf, uint8_t jack_id, uint8_t const* buffer, u
   return i;
 }
 
+bool tud_midi_n_send (uint8_t itf, uint8_t const packet[4])
+{
+  midid_interface_t* midi = &_midid_itf[itf];
+  if (midi->itf_num == 0) {
+    return 0;
+  }
+
+  if (tu_fifo_remaining(&midi->tx_ff) < 4)
+    return false;
+
+  tu_fifo_write_n(&midi->tx_ff, packet, 4);
+  maybe_transmit(midi, itf);
+
+  return true;
+}
+
 //--------------------------------------------------------------------+
 // USBD Driver API
 //--------------------------------------------------------------------+

+ 15 - 0
src/class/midi/midi_device.h

@@ -62,6 +62,9 @@ uint32_t tud_midi_n_write      (uint8_t itf, uint8_t jack_id, uint8_t const* buf
 static inline
 uint32_t tud_midi_n_write24    (uint8_t itf, uint8_t jack_id, uint8_t b1, uint8_t b2, uint8_t b3);
 
+bool tud_midi_n_receive        (uint8_t itf, uint8_t packet[4]);
+bool tud_midi_n_send           (uint8_t itf, uint8_t const packet[4]);
+
 //--------------------------------------------------------------------+
 // Application API (Interface0)
 //--------------------------------------------------------------------+
@@ -71,6 +74,8 @@ static inline uint32_t tud_midi_read       (void* buffer, uint32_t bufsize);
 static inline void     tud_midi_read_flush (void);
 static inline uint32_t tud_midi_write      (uint8_t jack_id, uint8_t const* buffer, uint32_t bufsize);
 static inline uint32_t tudi_midi_write24   (uint8_t jack_id, uint8_t b1, uint8_t b2, uint8_t b3);
+static inline bool     tud_midi_receive    (uint8_t packet[4]);
+static inline bool     tud_midi_send       (uint8_t const packet[4]);
 
 //--------------------------------------------------------------------+
 // Application Callback API (weak is optional)
@@ -118,6 +123,16 @@ static inline uint32_t tudi_midi_write24 (uint8_t jack_id, uint8_t b1, uint8_t b
   return tud_midi_write(jack_id, msg, 3);
 }
 
+static inline bool tud_midi_receive (uint8_t packet[4])
+{
+  return tud_midi_n_receive(0, packet);
+}
+
+static inline bool tud_midi_send (uint8_t const packet[4])
+{
+  return tud_midi_n_send(0, packet);
+}
+
 //--------------------------------------------------------------------+
 // Internal Class Driver API
 //--------------------------------------------------------------------+