correct midi stream read behavior to read until user buffer is full or no more data from usb fifo

This commit is contained in:
hathach 2021-04-02 15:08:36 +07:00
parent 350eb11277
commit 48bb96f507
1 changed files with 65 additions and 52 deletions

View File

@ -52,6 +52,12 @@ typedef struct
uint8_t ep_in; uint8_t ep_in;
uint8_t ep_out; 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 -------------*/ /*------------- From this point, data is not cleared by bus reset -------------*/
// FIFO // FIFO
tu_fifo_t rx_ff; tu_fifo_t rx_ff;
@ -64,12 +70,6 @@ typedef struct
osal_mutex_def_t tx_ff_mutex; osal_mutex_def_t tx_ff_mutex;
#endif #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 // Endpoint Transfer buffer
CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_MIDI_EP_BUFSIZE]; 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]; 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) uint32_t tud_midi_n_stream_read(uint8_t itf, uint8_t cable_num, void* buffer, uint32_t bufsize)
{ {
(void) cable_num; (void) cable_num;
TU_VERIFY(bufsize, 0);
uint8_t* buf8 = (uint8_t*) buffer;
midid_interface_t* midi = &_midid_itf[itf]; midid_interface_t* midi = &_midid_itf[itf];
midid_stream_t* stream = &midi->stream_read; midid_stream_t* stream = &midi->stream_read;
TU_VERIFY(bufsize, 0); uint32_t total_read = 0;
while( bufsize )
// Get new packet from fifo
if ( stream->total == 0 )
{ {
TU_VERIFY(tud_midi_n_packet_read(itf, stream->buffer), 0); // Get new packet from fifo, then set packet expected bytes
if ( stream->total == 0 )
uint8_t const code_index = stream->buffer[0] & 0x0f;
// MIDI 1.0 Table 4-1: Code Index Number Classifications
switch(code_index)
{ {
case MIDI_CIN_MISC: // return if there is no more data from fifo
case MIDI_CIN_CABLE_EVENT: if ( !tud_midi_n_packet_read(itf, stream->buffer) ) return total_read;
// These are reserved and unused, possibly issue somewhere, skip this packet
return 0;
break;
case MIDI_CIN_SYSEX_END_1BYTE: uint8_t const code_index = stream->buffer[0] & 0x0f;
case MIDI_CIN_1BYTE_DATA:
stream->total = 1;
break;
case MIDI_CIN_SYSCOM_2BYTE : // MIDI 1.0 Table 4-1: Code Index Number Classifications
case MIDI_CIN_SYSEX_END_2BYTE : switch(code_index)
case MIDI_CIN_PROGRAM_CHANGE : {
case MIDI_CIN_CHANNEL_PRESSURE : case MIDI_CIN_MISC:
stream->total = 2; case MIDI_CIN_CABLE_EVENT:
break; // These are reserved and unused, possibly issue somewhere, skip this packet
return 0;
break;
default: case MIDI_CIN_SYSEX_END_1BYTE:
stream->total = 3; case MIDI_CIN_1BYTE_DATA:
break; 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); return total_read;
// 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;
} }
bool tud_midi_n_packet_read (uint8_t itf, uint8_t packet[4]) 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; midid_stream_t* stream = &midi->stream_write;
uint32_t written = 0; uint32_t total_written = 0;
uint32_t i = 0; uint32_t i = 0;
while ( i < bufsize ) 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 // On-going (buffering) packet
TU_ASSERT(stream->index < 4, written); TU_ASSERT(stream->index < 4, total_written);
stream->buffer[stream->index] = data; stream->buffer[stream->index] = data;
stream->index++; 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); 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; stream->index = stream->total = 0;
// fifo overflow, here we assume FIFO is multiple of 4 and didn't check remaining before writing // fifo overflow, here we assume FIFO is multiple of 4 and didn't check remaining before writing
if ( count != 4 ) break; if ( count != 4 ) break;
// updated written if succeeded // updated written if succeeded
written = i; total_written = i;
} }
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); write_flush(midi);
return written; return total_written;
} }
bool tud_midi_n_packet_write (uint8_t itf, uint8_t const packet[4]) bool tud_midi_n_packet_write (uint8_t itf, uint8_t const packet[4])