From 48bb96f5072a173189d9076c5c2b1f5066327bf6 Mon Sep 17 00:00:00 2001
From: hathach <thach@tinyusb.org>
Date: Fri, 2 Apr 2021 15:08:36 +0700
Subject: [PATCH] correct midi stream read behavior to read until user buffer
 is full or no more data from usb fifo

---
 src/class/midi/midi_device.c | 117 +++++++++++++++++++----------------
 1 file changed, 65 insertions(+), 52 deletions(-)

diff --git a/src/class/midi/midi_device.c b/src/class/midi/midi_device.c
index a4cc104a8..9ccbb733c 100644
--- a/src/class/midi/midi_device.c
+++ b/src/class/midi/midi_device.c
@@ -52,6 +52,12 @@ typedef struct
   uint8_t ep_in;
   uint8_t ep_out;
 
+  // For Stream read()/write() API
+  // 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.
+  midid_stream_t stream_write;
+  midid_stream_t stream_read;
+
   /*------------- From this point, data is not cleared by bus reset -------------*/
   // FIFO
   tu_fifo_t rx_ff;
@@ -64,12 +70,6 @@ typedef struct
   osal_mutex_def_t tx_ff_mutex;
   #endif
 
-  // For Stream read()/write() API
-  // 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.
-  midid_stream_t stream_write;
-  midid_stream_t stream_read;
-
   // Endpoint Transfer buffer
   CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_MIDI_EP_BUFSIZE];
   CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_MIDI_EP_BUFSIZE];
@@ -127,58 +127,71 @@ uint32_t tud_midi_n_available(uint8_t itf, uint8_t cable_num)
 uint32_t tud_midi_n_stream_read(uint8_t itf, uint8_t cable_num, void* buffer, uint32_t bufsize)
 {
   (void) cable_num;
+  TU_VERIFY(bufsize, 0);
+
+  uint8_t* buf8 = (uint8_t*) buffer;
+
   midid_interface_t* midi = &_midid_itf[itf];
   midid_stream_t* stream = &midi->stream_read;
 
-  TU_VERIFY(bufsize, 0);
-
-  // Get new packet from fifo
-  if ( stream->total == 0 )
+  uint32_t total_read = 0;
+  while( bufsize )
   {
-    TU_VERIFY(tud_midi_n_packet_read(itf, stream->buffer), 0);
-
-    uint8_t const code_index = stream->buffer[0] & 0x0f;
-
-    // MIDI 1.0 Table 4-1: Code Index Number Classifications
-    switch(code_index)
+    // Get new packet from fifo, then set packet expected bytes
+    if ( stream->total == 0 )
     {
-      case MIDI_CIN_MISC:
-      case MIDI_CIN_CABLE_EVENT:
-        // These are reserved and unused, possibly issue somewhere, skip this packet
-        return 0;
-      break;
+      // return if there is no more data from fifo
+      if ( !tud_midi_n_packet_read(itf, stream->buffer) ) return total_read;
 
-      case MIDI_CIN_SYSEX_END_1BYTE:
-      case MIDI_CIN_1BYTE_DATA:
-        stream->total = 1;
-      break;
+      uint8_t const code_index = stream->buffer[0] & 0x0f;
 
-      case MIDI_CIN_SYSCOM_2BYTE     :
-      case MIDI_CIN_SYSEX_END_2BYTE  :
-      case MIDI_CIN_PROGRAM_CHANGE   :
-      case MIDI_CIN_CHANNEL_PRESSURE :
-        stream->total = 2;
-      break;
+      // MIDI 1.0 Table 4-1: Code Index Number Classifications
+      switch(code_index)
+      {
+        case MIDI_CIN_MISC:
+        case MIDI_CIN_CABLE_EVENT:
+          // These are reserved and unused, possibly issue somewhere, skip this packet
+          return 0;
+        break;
 
-      default:
-        stream->total = 3;
-      break;
+        case MIDI_CIN_SYSEX_END_1BYTE:
+        case MIDI_CIN_1BYTE_DATA:
+          stream->total = 1;
+        break;
+
+        case MIDI_CIN_SYSCOM_2BYTE     :
+        case MIDI_CIN_SYSEX_END_2BYTE  :
+        case MIDI_CIN_PROGRAM_CHANGE   :
+        case MIDI_CIN_CHANNEL_PRESSURE :
+          stream->total = 2;
+        break;
+
+        default:
+          stream->total = 3;
+        break;
+      }
+    }
+
+    // Copy data up to bufsize
+    uint32_t const count = tu_min32(stream->total - stream->index, bufsize);
+
+    // Skip the header (1st byte) in the buffer
+    memcpy(buf8, stream->buffer + 1 + stream->index, count);
+
+    total_read += count;
+    stream->index += count;
+    buf8 += count;
+    bufsize -= count;
+
+    // complete current event packet, reset stream
+    if ( stream->total == stream->index )
+    {
+      stream->index = 0;
+      stream->total = 0;
     }
   }
 
-  uint32_t const n = tu_min32(stream->total - stream->index, bufsize);
-
-  // Skip the header (1st byte) in the buffer
-  memcpy(buffer, stream->buffer + 1 + stream->index, n);
-  stream->index += n;
-
-  if ( stream->total == stream->index )
-  {
-    stream->index = 0;
-    stream->total = 0;
-  }
-
-  return n;
+  return total_read;
 }
 
 bool tud_midi_n_packet_read (uint8_t itf, uint8_t packet[4])
@@ -224,7 +237,7 @@ uint32_t tud_midi_n_stream_write(uint8_t itf, uint8_t cable_num, uint8_t const*
 
   midid_stream_t* stream = &midi->stream_write;
 
-  uint32_t written = 0;
+  uint32_t total_written = 0;
   uint32_t i = 0;
   while ( i < bufsize )
   {
@@ -296,7 +309,7 @@ uint32_t tud_midi_n_stream_write(uint8_t itf, uint8_t cable_num, uint8_t const*
     {
       // On-going (buffering) packet
 
-      TU_ASSERT(stream->index < 4, written);
+      TU_ASSERT(stream->index < 4, total_written);
       stream->buffer[stream->index] = data;
       stream->index++;
 
@@ -316,14 +329,14 @@ uint32_t tud_midi_n_stream_write(uint8_t itf, uint8_t cable_num, uint8_t const*
 
       uint16_t const count = tu_fifo_write_n(&midi->tx_ff, stream->buffer, 4);
 
-      // reset buffer
+      // complete current event packet, reset stream
       stream->index = stream->total = 0;
 
       // fifo overflow, here we assume FIFO is multiple of 4 and didn't check remaining before writing
       if ( count != 4 ) break;
 
       // updated written if succeeded
-      written = i;
+      total_written = i;
     }
 
     i++;
@@ -331,7 +344,7 @@ uint32_t tud_midi_n_stream_write(uint8_t itf, uint8_t cable_num, uint8_t const*
 
   write_flush(midi);
 
-  return written;
+  return total_written;
 }
 
 bool tud_midi_n_packet_write (uint8_t itf, uint8_t const packet[4])