From 73228a67efd122915e43ed445ddaec8285786d28 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Thu, 16 Jan 2020 10:06:52 +0100 Subject: [PATCH] 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. --- src/class/midi/midi_device.c | 145 ++++++++++++++++++++++------------- src/class/midi/midi_device.h | 15 ++++ 2 files changed, 106 insertions(+), 54 deletions(-) diff --git a/src/class/midi/midi_device.c b/src/class/midi/midi_device.c index 312405621..82ceba87f 100644 --- a/src/class/midi/midi_device.c +++ b/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); -} + midid_interface_t* midi = &_midid_itf[itf]; -void tud_midi_n_read_flush (uint8_t itf, uint8_t jack_id) -{ - (void) jack_id; - tu_fifo_clear(&_midid_itf[itf].rx_ff); -} + // Fill empty buffer + if (midi->read_buffer_length == 0) { + if (!tud_midi_n_receive(itf, midi->read_buffer)) + return 0; -void midi_rx_done_cb(midid_interface_t* midi, uint8_t const* buffer, uint32_t bufsize) { - if (bufsize % 4 != 0) { - return; - } - - for(uint32_t i=0; i> 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 //--------------------------------------------------------------------+ diff --git a/src/class/midi/midi_device.h b/src/class/midi/midi_device.h index fbf4bce0b..e4d4f9d51 100644 --- a/src/class/midi/midi_device.h +++ b/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 //--------------------------------------------------------------------+