change API to take index instead of dev address, this allow to support more than 1 midi per device.

This commit is contained in:
hathach
2025-02-24 12:39:02 +07:00
parent 71e046d9ff
commit 8c70475c23
3 changed files with 189 additions and 176 deletions

View File

@@ -30,12 +30,9 @@
#include "bsp/board_api.h" #include "bsp/board_api.h"
#include "tusb.h" #include "tusb.h"
#if CFG_TUH_MIDI
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// STATIC GLOBALS DECLARATION // STATIC GLOBALS DECLARATION
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
static uint8_t midi_dev_addr = 0;
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF PROTOTYPES // MACRO CONSTANT TYPEDEF PROTOTYPES
@@ -65,8 +62,6 @@ int main(void) {
return 0; return 0;
} }
#endif
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// Blinking Task // Blinking Task
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
@@ -88,13 +83,7 @@ void led_blinking_task(void) {
// MIDI host receive task // MIDI host receive task
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
void midi_host_rx_task(void) { void midi_host_rx_task(void) {
// device must be attached and have at least one endpoint ready to receive a message // nothing to do, we just print out received data in callback
if (!midi_dev_addr || !tuh_midi_mounted(midi_dev_addr)) {
return;
}
if (tuh_midi_get_num_rx_cables(midi_dev_addr) < 1) {
return;
}
} }
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
@@ -102,39 +91,32 @@ void midi_host_rx_task(void) {
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// Invoked when device with MIDI interface is mounted. // Invoked when device with MIDI interface is mounted.
void tuh_midi_mount_cb(uint8_t dev_addr, uint8_t num_cables_rx, uint16_t num_cables_tx) { void tuh_midi_mount_cb(uint8_t idx, uint8_t num_cables_rx, uint16_t num_cables_tx) {
(void) num_cables_rx; printf("MIDI Interface Index = %u, Number of RX cables = %u, Number of TX cables = %u\r\n",
(void) num_cables_tx; idx, num_cables_rx, num_cables_tx);
midi_dev_addr = dev_addr;
TU_LOG1("MIDI device address = %u, Number of RX cables = %u, Number of TX cables = %u\r\n",
dev_addr, num_cables_rx, num_cables_tx);
} }
// Invoked when device with hid interface is un-mounted // Invoked when device with hid interface is un-mounted
void tuh_midi_umount_cb(uint8_t dev_addr) { void tuh_midi_umount_cb(uint8_t idx) {
(void) dev_addr; printf("MIDI Interface Index = %u is unmounted\r\n", idx);
midi_dev_addr = 0;
TU_LOG1("MIDI device address = %d is unmounted\r\n", dev_addr);
} }
void tuh_midi_rx_cb(uint8_t dev_addr, uint32_t num_packets) { void tuh_midi_rx_cb(uint8_t idx, uint32_t num_packets) {
if (midi_dev_addr != dev_addr) {
return;
}
if (num_packets == 0) { if (num_packets == 0) {
return; return;
} }
uint8_t cable_num; uint8_t cable_num;
uint8_t buffer[48]; uint8_t buffer[48];
uint32_t bytes_read = tuh_midi_stream_read(dev_addr, &cable_num, buffer, sizeof(buffer)); uint32_t bytes_read = tuh_midi_stream_read(idx, &cable_num, buffer, sizeof(buffer));
(void) bytes_read;
TU_LOG1("Read bytes %lu cable %u", bytes_read, cable_num); printf("Cable %u rx %lu bytes: ", cable_num, bytes_read);
TU_LOG1_MEM(buffer, bytes_read, 2); for (uint32_t i = 0; i < bytes_read; i++) {
printf("%02X ", buffer[i]);
}
printf("\r\n");
} }
void tuh_midi_tx_cb(uint8_t dev_addr) { void tuh_midi_tx_cb(uint8_t idx) {
(void) dev_addr; (void) idx;
} }

View File

@@ -45,8 +45,9 @@
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
typedef struct { typedef struct {
uint8_t dev_addr; uint8_t daddr;
uint8_t itf_num; uint8_t bInterfaceNumber; // interface number of MIDI streaming
uint8_t itf_count; // number of interface including Audio Control + MIDI streaming
uint8_t ep_in; // IN endpoint address uint8_t ep_in; // IN endpoint address
uint8_t ep_out; // OUT endpoint address uint8_t ep_out; // OUT endpoint address
@@ -71,7 +72,7 @@ typedef struct {
uint8_t tx_ff_buf[CFG_TUH_MIDI_TX_BUFSIZE]; uint8_t tx_ff_buf[CFG_TUH_MIDI_TX_BUFSIZE];
} ep_stream; } ep_stream;
bool configured; bool mounted;
}midih_interface_t; }midih_interface_t;
typedef struct { typedef struct {
@@ -85,17 +86,24 @@ CFG_TUH_MEM_SECTION static midih_epbuf_t _midi_epbuf[CFG_TUH_MIDI];
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// Helper // Helper
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
TU_ATTR_ALWAYS_INLINE static inline midih_interface_t* find_midi_by_daddr(uint8_t dev_addr) { TU_ATTR_ALWAYS_INLINE static inline uint8_t find_new_midi_index(void) {
for (uint8_t i = 0; i < CFG_TUH_MIDI; i++) { for (uint8_t idx = 0; idx < CFG_TUH_MIDI; idx++) {
if (_midi_host[i].dev_addr == dev_addr) { if (_midi_host[idx].daddr == 0) {
return &_midi_host[i]; return idx;
} }
} }
return NULL; return TUSB_INDEX_INVALID_8;
} }
TU_ATTR_ALWAYS_INLINE static inline midih_interface_t* find_new_midi(void) { static inline uint8_t get_idx_by_ep_addr(uint8_t daddr, uint8_t ep_addr) {
return find_midi_by_daddr(0); for (uint8_t idx = 0; idx < CFG_TUH_MIDI; idx++) {
const midih_interface_t *p_midi = &_midi_host[idx];
if ((p_midi->daddr == daddr) &&
(ep_addr == p_midi->ep_stream.rx.ep_addr || ep_addr == p_midi->ep_stream.tx.ep_addr)) {
return idx;
}
}
return TUSB_INDEX_INVALID_8;
} }
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
@@ -122,32 +130,38 @@ bool midih_deinit(void) {
return true; return true;
} }
void midih_close(uint8_t dev_addr) { void midih_close(uint8_t daddr) {
midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); for (uint8_t idx = 0; idx < CFG_TUH_MIDI; idx++) {
if (p_midi_host == NULL) { midih_interface_t* p_midi = &_midi_host[idx];
return; if (p_midi->daddr == daddr) {
} TU_LOG_DRV(" MIDI close addr = %u index = %u\r\n", daddr, idx);
if (tuh_midi_umount_cb) {
tuh_midi_umount_cb(dev_addr);
}
p_midi_host->ep_in = 0;
p_midi_host->ep_out = 0;
p_midi_host->itf_num = 0;
p_midi_host->num_cables_rx = 0;
p_midi_host->num_cables_tx = 0;
p_midi_host->dev_addr = 0;
p_midi_host->configured = false;
tu_memclr(&p_midi_host->stream_read, sizeof(p_midi_host->stream_read));
tu_memclr(&p_midi_host->stream_write, sizeof(p_midi_host->stream_write));
tu_edpt_stream_close(&p_midi_host->ep_stream.rx); if (tuh_midi_umount_cb) {
tu_edpt_stream_close(&p_midi_host->ep_stream.tx); tuh_midi_umount_cb(idx);
}
p_midi->ep_in = 0;
p_midi->ep_out = 0;
p_midi->bInterfaceNumber = 0;
p_midi->num_cables_rx = 0;
p_midi->num_cables_tx = 0;
p_midi->daddr = 0;
p_midi->mounted = false;
tu_memclr(&p_midi->stream_read, sizeof(p_midi->stream_read));
tu_memclr(&p_midi->stream_write, sizeof(p_midi->stream_write));
tu_edpt_stream_close(&p_midi->ep_stream.rx);
tu_edpt_stream_close(&p_midi->ep_stream.tx);
}
}
} }
bool midih_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) { bool midih_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) {
(void) result; (void) result;
midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); const uint8_t idx = get_idx_by_ep_addr(dev_addr, ep_addr);
TU_VERIFY(p_midi_host != NULL); TU_VERIFY(idx < CFG_TUH_MIDI);
midih_interface_t *p_midi_host = &_midi_host[idx];
if (ep_addr == p_midi_host->ep_stream.rx.ep_addr) { if (ep_addr == p_midi_host->ep_stream.rx.ep_addr) {
// receive new data if available // receive new data if available
if (xferred_bytes) { if (xferred_bytes) {
@@ -167,14 +181,14 @@ bool midih_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint
} }
if (tuh_midi_rx_cb) { if (tuh_midi_rx_cb) {
tuh_midi_rx_cb(dev_addr, packets_queued); // invoke receive callback tuh_midi_rx_cb(idx, packets_queued);
} }
} }
tu_edpt_stream_read_xfer(dev_addr, &p_midi_host->ep_stream.rx); // prepare for next transfer tu_edpt_stream_read_xfer(dev_addr, &p_midi_host->ep_stream.rx); // prepare for next transfer
} else if (ep_addr == p_midi_host->ep_stream.tx.ep_addr) { } else if (ep_addr == p_midi_host->ep_stream.tx.ep_addr) {
if (tuh_midi_tx_cb) { if (tuh_midi_tx_cb) {
tuh_midi_tx_cb(dev_addr); tuh_midi_tx_cb(idx);
} }
if (0 == tu_edpt_stream_write_xfer(dev_addr, &p_midi_host->ep_stream.tx)) { if (0 == tu_edpt_stream_write_xfer(dev_addr, &p_midi_host->ep_stream.tx)) {
// If there is no data left, a ZLP should be sent if // If there is no data left, a ZLP should be sent if
@@ -192,19 +206,20 @@ bool midih_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint
bool midih_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len) { bool midih_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len) {
(void) rhport; (void) rhport;
midih_interface_t *p_midi = find_new_midi();
TU_VERIFY(p_midi != NULL);
TU_VERIFY(TUSB_CLASS_AUDIO == desc_itf->bInterfaceClass); TU_VERIFY(TUSB_CLASS_AUDIO == desc_itf->bInterfaceClass);
// There can be just a MIDI or an Audio + MIDI interface
// const uint8_t* p_start = ((uint8_t const*) desc_itf); // const uint8_t* p_start = ((uint8_t const*) desc_itf);
const uint8_t* p_end = ((uint8_t const*) desc_itf) + max_len; const uint8_t *p_end = ((const uint8_t *) desc_itf) + max_len;
uint8_t const *p_desc = (uint8_t const *) desc_itf; const uint8_t *p_desc = (const uint8_t *) desc_itf;
uint16_t len_parsed = 0;
const uint8_t idx = find_new_midi_index();
TU_VERIFY(idx < CFG_TUH_MIDI);
midih_interface_t *p_midi = &_midi_host[idx];
p_midi->itf_count = 0;
tuh_midi_descriptor_cb_t desc_cb = { 0 }; tuh_midi_descriptor_cb_t desc_cb = { 0 };
desc_cb.jack_num = 0; desc_cb.jack_num = 0;
// There can be just a MIDI or an Audio + MIDI interface
// If there is Audio Control Interface + Audio Header descriptor, skip it // If there is Audio Control Interface + Audio Header descriptor, skip it
if (AUDIO_SUBCLASS_CONTROL == desc_itf->bInterfaceSubClass) { if (AUDIO_SUBCLASS_CONTROL == desc_itf->bInterfaceSubClass) {
TU_VERIFY(max_len > 2*sizeof(tusb_desc_interface_t) + sizeof(audio_desc_cs_ac_interface_t)); TU_VERIFY(max_len > 2*sizeof(tusb_desc_interface_t) + sizeof(audio_desc_cs_ac_interface_t));
@@ -216,15 +231,16 @@ bool midih_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *d
p_desc = tu_desc_next(p_desc); p_desc = tu_desc_next(p_desc);
desc_itf = (tusb_desc_interface_t const *)p_desc; desc_itf = (tusb_desc_interface_t const *)p_desc;
TU_VERIFY(TUSB_CLASS_AUDIO == desc_itf->bInterfaceClass); TU_VERIFY(TUSB_CLASS_AUDIO == desc_itf->bInterfaceClass);
p_midi->itf_count = 1;
} }
TU_VERIFY(AUDIO_SUBCLASS_MIDI_STREAMING == desc_itf->bInterfaceSubClass); TU_VERIFY(AUDIO_SUBCLASS_MIDI_STREAMING == desc_itf->bInterfaceSubClass);
desc_cb.desc_interface = desc_itf;
len_parsed += desc_itf->bLength;
TU_LOG_DRV("MIDI opening Interface %u (addr = %u)\r\n", desc_itf->bInterfaceNumber, dev_addr); TU_LOG_DRV("MIDI opening Interface %u (addr = %u)\r\n", desc_itf->bInterfaceNumber, dev_addr);
p_midi->itf_num = desc_itf->bInterfaceNumber; p_midi->bInterfaceNumber = desc_itf->bInterfaceNumber;
p_desc = tu_desc_next(p_desc); p_midi->itf_count++;
desc_cb.desc_interface = desc_itf;
p_desc = tu_desc_next(p_desc); // next to CS Header
bool found_new_interface = false; bool found_new_interface = false;
while ((p_desc < p_end) && (tu_desc_next(p_desc) <= p_end) && !found_new_interface) { while ((p_desc < p_end) && (tu_desc_next(p_desc) <= p_end) && !found_new_interface) {
@@ -291,102 +307,115 @@ bool midih_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *d
} }
desc_cb.desc_interface_len = (uint16_t) ((uintptr_t)p_desc - (uintptr_t) desc_itf); desc_cb.desc_interface_len = (uint16_t) ((uintptr_t)p_desc - (uintptr_t) desc_itf);
p_midi->dev_addr = dev_addr; p_midi->daddr = dev_addr;
if (tuh_midi_descriptor_cb) { if (tuh_midi_descriptor_cb) {
tuh_midi_descriptor_cb(dev_addr, &desc_cb); tuh_midi_descriptor_cb(idx, &desc_cb);
} }
return true; return true;
} }
bool midih_set_config(uint8_t dev_addr, uint8_t itf_num) { bool midih_set_config(uint8_t dev_addr, uint8_t itf_num) {
(void) itf_num; uint8_t idx = tuh_midi_itf_get_index(dev_addr, itf_num);
midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); TU_ASSERT(idx < CFG_TUH_MIDI);
TU_VERIFY(p_midi_host != NULL); midih_interface_t *p_midi = &_midi_host[idx];
p_midi_host->configured = true; p_midi->mounted = true;
if (tuh_midi_mount_cb) { if (tuh_midi_mount_cb) {
tuh_midi_mount_cb(dev_addr, p_midi_host->num_cables_rx, p_midi_host->num_cables_tx); tuh_midi_mount_cb(idx, p_midi->num_cables_rx, p_midi->num_cables_tx);
} }
tu_edpt_stream_read_xfer(dev_addr, &p_midi_host->ep_stream.rx); // prepare for incoming data tu_edpt_stream_read_xfer(dev_addr, &p_midi->ep_stream.rx); // prepare for incoming data
// No special config things to do for MIDI // No special config things to do for MIDI
usbh_driver_set_config_complete(dev_addr, p_midi_host->itf_num); usbh_driver_set_config_complete(dev_addr, p_midi->bInterfaceNumber);
return true; return true;
} }
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// API // API
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
bool tuh_midi_mounted(uint8_t dev_addr) { bool tuh_midi_mounted(uint8_t idx) {
midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); TU_VERIFY(idx < CFG_TUH_MIDI);
TU_VERIFY(p_midi_host != NULL); midih_interface_t *p_midi = &_midi_host[idx];
return p_midi_host->configured; return p_midi->mounted;
} }
uint8_t tuh_midi_get_num_tx_cables (uint8_t dev_addr) { uint8_t tuh_midi_itf_get_index(uint8_t daddr, uint8_t itf_num) {
midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); for (uint8_t idx = 0; idx < CFG_TUH_MIDI; idx++) {
TU_VERIFY(p_midi_host != NULL, 0); const midih_interface_t *p_midi = &_midi_host[idx];
TU_VERIFY(p_midi_host->ep_stream.tx.ep_addr != 0, 0); if (p_midi->daddr == daddr &&
return p_midi_host->num_cables_tx; (p_midi->bInterfaceNumber == itf_num ||
p_midi->bInterfaceNumber == (uint8_t) (itf_num + p_midi->itf_count - 1))) {
return idx;
}
}
return TUSB_INDEX_INVALID_8;
} }
uint8_t tuh_midi_get_num_rx_cables (uint8_t dev_addr) { uint8_t tuh_midi_get_num_tx_cables (uint8_t idx) {
midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); TU_VERIFY(idx < CFG_TUH_MIDI);
TU_VERIFY(p_midi_host != NULL, 0); midih_interface_t *p_midi = &_midi_host[idx];
TU_VERIFY(p_midi_host->ep_stream.rx.ep_addr != 0, 0); TU_VERIFY(p_midi->ep_stream.tx.ep_addr != 0, 0);
return p_midi_host->num_cables_rx; return p_midi->num_cables_tx;
} }
uint32_t tuh_midi_read_available(uint8_t dev_addr) { uint8_t tuh_midi_get_num_rx_cables (uint8_t idx) {
midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); TU_VERIFY(idx < CFG_TUH_MIDI);
TU_VERIFY(p_midi_host != NULL); midih_interface_t *p_midi = &_midi_host[idx];
return tu_edpt_stream_read_available(&p_midi_host->ep_stream.rx); TU_VERIFY(p_midi->ep_stream.rx.ep_addr != 0, 0);
return p_midi->num_cables_rx;
} }
uint32_t tuh_midi_write_flush(uint8_t dev_addr) { uint32_t tuh_midi_read_available(uint8_t idx) {
midih_interface_t *p_midi = find_midi_by_daddr(dev_addr); TU_VERIFY(idx < CFG_TUH_MIDI);
TU_VERIFY(p_midi != NULL); midih_interface_t *p_midi = &_midi_host[idx];
return tu_edpt_stream_write_xfer(p_midi->dev_addr, &p_midi->ep_stream.tx); return tu_edpt_stream_read_available(&p_midi->ep_stream.rx);
}
uint32_t tuh_midi_write_flush(uint8_t idx) {
TU_VERIFY(idx < CFG_TUH_MIDI);
midih_interface_t *p_midi = &_midi_host[idx];
return tu_edpt_stream_write_xfer(p_midi->daddr, &p_midi->ep_stream.tx);
} }
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// Packet API // Packet API
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
uint32_t tuh_midi_packet_read_n(uint8_t idx, uint8_t* buffer, uint32_t bufsize) {
TU_VERIFY(idx < CFG_TUH_MIDI && buffer && bufsize > 0, 0);
midih_interface_t *p_midi = &_midi_host[idx];
uint32_t tuh_midi_packet_read_n(uint8_t dev_addr, uint8_t* buffer, uint32_t bufsize) { uint32_t count4 = tu_min32(bufsize, tu_edpt_stream_read_available(&p_midi->ep_stream.rx));
midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr);
TU_VERIFY(p_midi_host != NULL);
uint32_t count4 = tu_min32(bufsize, tu_edpt_stream_read_available(&p_midi_host->ep_stream.rx));
count4 = tu_align4(count4); // round down to multiple of 4 count4 = tu_align4(count4); // round down to multiple of 4
TU_VERIFY(count4 > 0, 0); TU_VERIFY(count4 > 0, 0);
return tu_edpt_stream_read(dev_addr, &p_midi_host->ep_stream.rx, buffer, count4); return tu_edpt_stream_read(p_midi->daddr, &p_midi->ep_stream.rx, buffer, count4);
} }
uint32_t tuh_midi_packet_write_n(uint8_t dev_addr, const uint8_t* buffer, uint32_t bufsize) { uint32_t tuh_midi_packet_write_n(uint8_t idx, const uint8_t* buffer, uint32_t bufsize) {
midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); TU_VERIFY(idx < CFG_TUH_MIDI && buffer && bufsize > 0, 0);
TU_VERIFY(p_midi_host != NULL, 0); midih_interface_t *p_midi = &_midi_host[idx];
uint32_t bufsize4 = tu_align4(bufsize);
return tu_edpt_stream_write(dev_addr, &p_midi_host->ep_stream.tx, buffer, bufsize4); const uint32_t bufsize4 = tu_align4(bufsize);
TU_VERIFY(bufsize4 > 0, 0);
return tu_edpt_stream_write(p_midi->daddr, &p_midi->ep_stream.tx, buffer, bufsize4);
} }
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// Stream API // Stream API
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
#if CFG_TUH_MIDI_STREAM_API #if CFG_TUH_MIDI_STREAM_API
uint32_t tuh_midi_stream_write(uint8_t dev_addr, uint8_t cable_num, uint8_t const *buffer, uint32_t bufsize) { uint32_t tuh_midi_stream_write(uint8_t idx, uint8_t cable_num, uint8_t const *buffer, uint32_t bufsize) {
midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); TU_VERIFY(idx < CFG_TUH_MIDI && buffer && bufsize > 0);
TU_VERIFY(p_midi_host != NULL); midih_interface_t *p_midi = &_midi_host[idx];
TU_VERIFY(cable_num < p_midi_host->num_cables_tx); TU_VERIFY(cable_num < p_midi->num_cables_tx);
midi_driver_stream_t *stream = &p_midi_host->stream_write; midi_driver_stream_t *stream = &p_midi->stream_write;
uint32_t i = 0; uint32_t byte_count = 0;
while ((i < bufsize) && (tu_edpt_stream_write_available(dev_addr, &p_midi_host->ep_stream.tx) >= 4)) { while ((byte_count < bufsize) && (tu_edpt_stream_write_available(p_midi->daddr, &p_midi->ep_stream.tx) >= 4)) {
uint8_t const data = buffer[i]; uint8_t const data = buffer[byte_count];
i++; byte_count++;
if (data >= MIDI_STATUS_SYSREAL_TIMING_CLOCK) { if (data >= MIDI_STATUS_SYSREAL_TIMING_CLOCK) {
// real-time messages need to be sent right away // real-time messages need to be sent right away
midi_driver_stream_t streamrt; midi_driver_stream_t streamrt;
@@ -394,8 +423,8 @@ uint32_t tuh_midi_stream_write(uint8_t dev_addr, uint8_t cable_num, uint8_t cons
streamrt.buffer[1] = data; streamrt.buffer[1] = data;
streamrt.index = 2; streamrt.index = 2;
streamrt.total = 2; streamrt.total = 2;
uint32_t const count = tu_edpt_stream_write(dev_addr, &p_midi_host->ep_stream.tx, streamrt.buffer, 4); uint32_t const count = tu_edpt_stream_write(p_midi->daddr, &p_midi->ep_stream.tx, streamrt.buffer, 4);
TU_ASSERT(count == 4, i); // Check FIFO overflown, since we already check fifo remaining. It is probably race condition TU_ASSERT(count == 4, byte_count); // Check FIFO overflown, since we already check fifo remaining. It is probably race condition
} else if (stream->index == 0) { } else if (stream->index == 0) {
//------------- New event packet -------------// //------------- New event packet -------------//
@@ -445,7 +474,7 @@ uint32_t tuh_midi_stream_write(uint8_t dev_addr, uint8_t cable_num, uint8_t cons
} }
} else { } else {
//------------- On-going (buffering) packet -------------// //------------- On-going (buffering) packet -------------//
TU_ASSERT(stream->index < 4, i); TU_ASSERT(stream->index < 4, byte_count);
stream->buffer[stream->index] = data; stream->buffer[stream->index] = data;
stream->index++; stream->index++;
// See if this byte ends a SysEx. // See if this byte ends a SysEx.
@@ -458,42 +487,41 @@ uint32_t tuh_midi_stream_write(uint8_t dev_addr, uint8_t cable_num, uint8_t cons
// Send out packet // Send out packet
if (stream->index >= 2 && stream->index == stream->total) { if (stream->index >= 2 && stream->index == stream->total) {
// zeroes unused bytes // zeroes unused bytes
for (uint8_t idx = stream->total; idx < 4; idx++) { stream->buffer[idx] = 0; } for (uint8_t i = stream->total; i < 4; i++) {
stream->buffer[i] = 0;
}
TU_LOG3_MEM(stream->buffer, 4, 2); TU_LOG3_MEM(stream->buffer, 4, 2);
uint32_t const count = tu_edpt_stream_write(dev_addr, &p_midi_host->ep_stream.tx, stream->buffer, 4); const uint32_t count = tu_edpt_stream_write(p_midi->daddr, &p_midi->ep_stream.tx, stream->buffer, 4);
// complete current event packet, reset stream // complete current event packet, reset stream
stream->index = 0; stream->index = 0;
stream->total = 0; stream->total = 0;
// FIFO overflown, since we already check fifo remaining. It is probably race condition // FIFO overflown, since we already check fifo remaining. It is probably race condition
TU_ASSERT(count == 4, i); TU_ASSERT(count == 4, byte_count);
} }
} }
return i; return byte_count;
} }
uint32_t tuh_midi_stream_read(uint8_t dev_addr, uint8_t *p_cable_num, uint8_t *p_buffer, uint16_t bufsize) { uint32_t tuh_midi_stream_read(uint8_t idx, uint8_t *p_cable_num, uint8_t *p_buffer, uint16_t bufsize) {
midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); TU_VERIFY(idx < CFG_TUH_MIDI && p_cable_num && p_buffer && bufsize > 0);
TU_VERIFY(p_midi_host != NULL); midih_interface_t *p_midi = &_midi_host[idx];
uint32_t bytes_buffered = 0; uint32_t bytes_buffered = 0;
TU_ASSERT(p_cable_num);
TU_ASSERT(p_buffer);
TU_ASSERT(bufsize);
uint8_t one_byte; uint8_t one_byte;
if (!tu_edpt_stream_peek(&p_midi_host->ep_stream.rx, &one_byte)) { if (!tu_edpt_stream_peek(&p_midi->ep_stream.rx, &one_byte)) {
return 0; return 0;
} }
*p_cable_num = (one_byte >> 4) & 0xf; *p_cable_num = (one_byte >> 4) & 0xf;
uint32_t nread = tu_edpt_stream_read(dev_addr, &p_midi_host->ep_stream.rx, p_midi_host->stream_read.buffer, 4); uint32_t nread = tu_edpt_stream_read(p_midi->daddr, &p_midi->ep_stream.rx, p_midi->stream_read.buffer, 4);
static uint16_t cable_sysex_in_progress; // bit i is set if received MIDI_STATUS_SYSEX_START but not MIDI_STATUS_SYSEX_END static uint16_t cable_sysex_in_progress;// bit i is set if received MIDI_STATUS_SYSEX_START but not MIDI_STATUS_SYSEX_END
while (nread == 4 && bytes_buffered < bufsize) { while (nread == 4 && bytes_buffered < bufsize) {
*p_cable_num = (p_midi_host->stream_read.buffer[0] >> 4) & 0x0f; *p_cable_num = (p_midi->stream_read.buffer[0] >> 4) & 0x0f;
uint8_t bytes_to_add_to_stream = 0; uint8_t bytes_to_add_to_stream = 0;
if (*p_cable_num < p_midi_host->num_cables_rx) { if (*p_cable_num < p_midi->num_cables_rx) {
// ignore the CIN field; too many devices out there encode this wrong // ignore the CIN field; too many devices out there encode this wrong
uint8_t status = p_midi_host->stream_read.buffer[1]; uint8_t status = p_midi->stream_read.buffer[1];
uint16_t cable_mask = (uint16_t) (1 << *p_cable_num); uint16_t cable_mask = (uint16_t) (1 << *p_cable_num);
if (status <= MIDI_MAX_DATA_VAL || status == MIDI_STATUS_SYSEX_START) { if (status <= MIDI_MAX_DATA_VAL || status == MIDI_STATUS_SYSEX_START) {
if (status == MIDI_STATUS_SYSEX_START) { if (status == MIDI_STATUS_SYSEX_START) {
@@ -502,13 +530,13 @@ uint32_t tuh_midi_stream_read(uint8_t dev_addr, uint8_t *p_cable_num, uint8_t *p
// only add the packet if a sysex message is in progress // only add the packet if a sysex message is in progress
if (cable_sysex_in_progress & cable_mask) { if (cable_sysex_in_progress & cable_mask) {
++bytes_to_add_to_stream; ++bytes_to_add_to_stream;
for (uint8_t idx = 2; idx < 4; idx++) { for (uint8_t i = 2; i < 4; i++) {
if (p_midi_host->stream_read.buffer[idx] <= MIDI_MAX_DATA_VAL) { if (p_midi->stream_read.buffer[i] <= MIDI_MAX_DATA_VAL) {
++bytes_to_add_to_stream; ++bytes_to_add_to_stream;
} else if (p_midi_host->stream_read.buffer[idx] == MIDI_STATUS_SYSEX_END) { } else if (p_midi->stream_read.buffer[i] == MIDI_STATUS_SYSEX_END) {
++bytes_to_add_to_stream; ++bytes_to_add_to_stream;
cable_sysex_in_progress &= (uint16_t) ~cable_mask; cable_sysex_in_progress &= (uint16_t) ~cable_mask;
idx = 4;// force the loop to exit; I hate break statements in loops i = 4;// force the loop to exit; I hate break statements in loops
} }
} }
} }
@@ -555,23 +583,22 @@ uint32_t tuh_midi_stream_read(uint8_t dev_addr, uint8_t *p_cable_num, uint8_t *p
} }
} }
for (uint8_t idx = 1; idx <= bytes_to_add_to_stream; idx++) { for (uint8_t i = 1; i <= bytes_to_add_to_stream; i++) {
*p_buffer++ = p_midi_host->stream_read.buffer[idx]; *p_buffer++ = p_midi->stream_read.buffer[i];
} }
bytes_buffered += bytes_to_add_to_stream; bytes_buffered += bytes_to_add_to_stream;
nread = 0; nread = 0;
if (tu_edpt_stream_peek(&p_midi_host->ep_stream.rx, &one_byte)) { if (tu_edpt_stream_peek(&p_midi->ep_stream.rx, &one_byte)) {
uint8_t new_cable = (one_byte >> 4) & 0xf; uint8_t new_cable = (one_byte >> 4) & 0xf;
if (new_cable == *p_cable_num) { if (new_cable == *p_cable_num) {
// still on the same cable. Continue reading the stream // still on the same cable. Continue reading the stream
nread = tu_edpt_stream_read(dev_addr, &p_midi_host->ep_stream.rx, p_midi_host->stream_read.buffer, 4); nread = tu_edpt_stream_read(p_midi->daddr, &p_midi->ep_stream.rx, p_midi->stream_read.buffer, 4);
} }
} }
} }
return bytes_buffered; return bytes_buffered;
} }
#endif #endif
#endif #endif

View File

@@ -76,22 +76,26 @@ typedef struct {
} tuh_midi_descriptor_cb_t; } tuh_midi_descriptor_cb_t;
// Check if MIDI interface is mounted // Check if MIDI interface is mounted
bool tuh_midi_mounted(uint8_t dev_addr); bool tuh_midi_mounted(uint8_t idx);
// Get Interface index from device address + interface number
// return TUSB_INDEX_INVALID_8 (0xFF) if not found
uint8_t tuh_midi_itf_get_index(uint8_t daddr, uint8_t itf_num);
// return the number of virtual midi cables on the device's IN endpoint // return the number of virtual midi cables on the device's IN endpoint
uint8_t tuh_midi_get_num_rx_cables(uint8_t dev_addr); uint8_t tuh_midi_get_num_rx_cables(uint8_t idx);
// return the number of virtual midi cables on the device's OUT endpoint // return the number of virtual midi cables on the device's OUT endpoint
uint8_t tuh_midi_get_num_tx_cables(uint8_t dev_addr); uint8_t tuh_midi_get_num_tx_cables(uint8_t idx);
// return the raw number of bytes available. // return the raw number of bytes available.
// Note: this is related but not the same as number of stream bytes available. // Note: this is related but not the same as number of stream bytes available.
uint32_t tuh_midi_read_available(uint8_t dev_addr); uint32_t tuh_midi_read_available(uint8_t idx);
// Send any queued packets to the device if the host hardware is able to do it // Send any queued packets to the device if the host hardware is able to do it
// Returns the number of bytes flushed to the host hardware or 0 if // Returns the number of bytes flushed to the host hardware or 0 if
// the host hardware is busy or there is nothing in queue to send. // the host hardware is busy or there is nothing in queue to send.
uint32_t tuh_midi_write_flush( uint8_t dev_addr); uint32_t tuh_midi_write_flush(uint8_t idx);
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// Packet API // Packet API
@@ -99,24 +103,24 @@ uint32_t tuh_midi_write_flush( uint8_t dev_addr);
// Read all available MIDI packets from the connected device // Read all available MIDI packets from the connected device
// Return number of bytes read (always multiple of 4) // Return number of bytes read (always multiple of 4)
uint32_t tuh_midi_packet_read_n(uint8_t dev_addr, uint8_t* buffer, uint32_t bufsize); uint32_t tuh_midi_packet_read_n(uint8_t idx, uint8_t* buffer, uint32_t bufsize);
// Read a raw MIDI packet from the connected device // Read a raw MIDI packet from the connected device
// Return true if a packet was returned // Return true if a packet was returned
TU_ATTR_ALWAYS_INLINE static inline TU_ATTR_ALWAYS_INLINE static inline
bool tuh_midi_packet_read (uint8_t dev_addr, uint8_t packet[4]) { bool tuh_midi_packet_read (uint8_t idx, uint8_t packet[4]) {
return 4 == tuh_midi_packet_read_n(dev_addr, packet, 4); return 4 == tuh_midi_packet_read_n(idx, packet, 4);
} }
// Write all 4-byte packets, data is locally buffered and only transferred when buffered bytes // Write all 4-byte packets, data is locally buffered and only transferred when buffered bytes
// reach the endpoint packet size or tuh_midi_write_flush() is called // reach the endpoint packet size or tuh_midi_write_flush() is called
uint32_t tuh_midi_packet_write_n(uint8_t dev_addr, const uint8_t* buffer, uint32_t bufsize); uint32_t tuh_midi_packet_write_n(uint8_t idx, const uint8_t* buffer, uint32_t bufsize);
// Write a 4-bytes packet to the device. // Write a 4-bytes packet to the device.
// Returns true if the packet was successfully queued. // Returns true if the packet was successfully queued.
TU_ATTR_ALWAYS_INLINE static inline TU_ATTR_ALWAYS_INLINE static inline
bool tuh_midi_packet_write (uint8_t dev_addr, uint8_t const packet[4]) { bool tuh_midi_packet_write (uint8_t idx, uint8_t const packet[4]) {
return 4 == tuh_midi_packet_write_n(dev_addr, packet, 4); return 4 == tuh_midi_packet_write_n(idx, packet, 4);
} }
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
@@ -127,7 +131,7 @@ bool tuh_midi_packet_write (uint8_t dev_addr, uint8_t const packet[4]) {
// Queue a message to the device using stream API. data is locally buffered and only transferred when buffered bytes // Queue a message to the device using stream API. data is locally buffered and only transferred when buffered bytes
// reach the endpoint packet size or tuh_midi_write_flush() is called // reach the endpoint packet size or tuh_midi_write_flush() is called
// Returns number of bytes was successfully queued. // Returns number of bytes was successfully queued.
uint32_t tuh_midi_stream_write (uint8_t dev_addr, uint8_t cable_num, uint8_t const* p_buffer, uint32_t bufsize); uint32_t tuh_midi_stream_write(uint8_t idx, uint8_t cable_num, uint8_t const *p_buffer, uint32_t bufsize);
// Get the MIDI stream from the device. Set the value pointed // Get the MIDI stream from the device. Set the value pointed
// to by p_cable_num to the MIDI cable number intended to receive it. // to by p_cable_num to the MIDI cable number intended to receive it.
@@ -136,7 +140,7 @@ uint32_t tuh_midi_stream_write (uint8_t dev_addr, uint8_t cable_num, uint8_t con
// Note that this function ignores the CIN field of the MIDI packet // Note that this function ignores the CIN field of the MIDI packet
// because a number of commercial devices out there do not encode // because a number of commercial devices out there do not encode
// it properly. // it properly.
uint32_t tuh_midi_stream_read (uint8_t dev_addr, uint8_t *p_cable_num, uint8_t *p_buffer, uint16_t bufsize); uint32_t tuh_midi_stream_read(uint8_t idx, uint8_t *p_cable_num, uint8_t *p_buffer, uint16_t bufsize);
#endif #endif
@@ -146,16 +150,16 @@ uint32_t tuh_midi_stream_read (uint8_t dev_addr, uint8_t *p_cable_num, uint8_t *
// Invoked when MIDI interface is detected in enumeration. Application can copy/parse descriptor if needed. // Invoked when MIDI interface is detected in enumeration. Application can copy/parse descriptor if needed.
// Note: may be fired before tuh_midi_mount_cb(), therefore midi interface is not mounted/ready. // Note: may be fired before tuh_midi_mount_cb(), therefore midi interface is not mounted/ready.
TU_ATTR_WEAK void tuh_midi_descriptor_cb(uint8_t dev_addr, tuh_midi_descriptor_cb_t const* desc_cb); TU_ATTR_WEAK void tuh_midi_descriptor_cb(uint8_t idx, const tuh_midi_descriptor_cb_t * desc_cb);
// Invoked when device with MIDI interface is mounted. // Invoked when device with MIDI interface is mounted.
TU_ATTR_WEAK void tuh_midi_mount_cb(uint8_t dev_addr, uint8_t num_cables_rx, uint16_t num_cables_tx); TU_ATTR_WEAK void tuh_midi_mount_cb(uint8_t idx, uint8_t num_cables_rx, uint16_t num_cables_tx);
// Invoked when device with MIDI interface is un-mounted // Invoked when device with MIDI interface is un-mounted
TU_ATTR_WEAK void tuh_midi_umount_cb(uint8_t dev_addr); TU_ATTR_WEAK void tuh_midi_umount_cb(uint8_t idx);
TU_ATTR_WEAK void tuh_midi_rx_cb(uint8_t dev_addr, uint32_t num_packets); TU_ATTR_WEAK void tuh_midi_rx_cb(uint8_t idx, uint32_t num_packets);
TU_ATTR_WEAK void tuh_midi_tx_cb(uint8_t dev_addr); TU_ATTR_WEAK void tuh_midi_tx_cb(uint8_t idx);
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// Internal Class Driver API // Internal Class Driver API
@@ -165,7 +169,7 @@ bool midih_deinit (void);
bool midih_open (uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len); bool midih_open (uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len);
bool midih_set_config (uint8_t dev_addr, uint8_t itf_num); bool midih_set_config (uint8_t dev_addr, uint8_t itf_num);
bool midih_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes); bool midih_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes);
void midih_close (uint8_t dev_addr); void midih_close (uint8_t daddr);
#ifdef __cplusplus #ifdef __cplusplus
} }