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

View File

@@ -45,8 +45,9 @@
//--------------------------------------------------------------------+
typedef struct {
uint8_t dev_addr;
uint8_t itf_num;
uint8_t daddr;
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_out; // OUT endpoint address
@@ -71,7 +72,7 @@ typedef struct {
uint8_t tx_ff_buf[CFG_TUH_MIDI_TX_BUFSIZE];
} ep_stream;
bool configured;
bool mounted;
}midih_interface_t;
typedef struct {
@@ -85,17 +86,24 @@ CFG_TUH_MEM_SECTION static midih_epbuf_t _midi_epbuf[CFG_TUH_MIDI];
//--------------------------------------------------------------------+
// Helper
//--------------------------------------------------------------------+
TU_ATTR_ALWAYS_INLINE static inline midih_interface_t* find_midi_by_daddr(uint8_t dev_addr) {
for (uint8_t i = 0; i < CFG_TUH_MIDI; i++) {
if (_midi_host[i].dev_addr == dev_addr) {
return &_midi_host[i];
TU_ATTR_ALWAYS_INLINE static inline uint8_t find_new_midi_index(void) {
for (uint8_t idx = 0; idx < CFG_TUH_MIDI; idx++) {
if (_midi_host[idx].daddr == 0) {
return idx;
}
}
return NULL;
return TUSB_INDEX_INVALID_8;
}
TU_ATTR_ALWAYS_INLINE static inline midih_interface_t* find_new_midi(void) {
return find_midi_by_daddr(0);
static inline uint8_t get_idx_by_ep_addr(uint8_t daddr, uint8_t ep_addr) {
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;
}
void midih_close(uint8_t dev_addr) {
midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr);
if (p_midi_host == NULL) {
return;
}
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));
void midih_close(uint8_t daddr) {
for (uint8_t idx = 0; idx < CFG_TUH_MIDI; idx++) {
midih_interface_t* p_midi = &_midi_host[idx];
if (p_midi->daddr == daddr) {
TU_LOG_DRV(" MIDI close addr = %u index = %u\r\n", daddr, idx);
tu_edpt_stream_close(&p_midi_host->ep_stream.rx);
tu_edpt_stream_close(&p_midi_host->ep_stream.tx);
if (tuh_midi_umount_cb) {
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) {
(void) result;
midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr);
TU_VERIFY(p_midi_host != NULL);
const uint8_t idx = get_idx_by_ep_addr(dev_addr, ep_addr);
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) {
// receive new data if available
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) {
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
} else if (ep_addr == p_midi_host->ep_stream.tx.ep_addr) {
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 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) {
(void) rhport;
midih_interface_t *p_midi = find_new_midi();
TU_VERIFY(p_midi != NULL);
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_end = ((uint8_t const*) desc_itf) + max_len;
uint8_t const *p_desc = (uint8_t const *) desc_itf;
uint16_t len_parsed = 0;
const uint8_t *p_end = ((const uint8_t *) desc_itf) + max_len;
const uint8_t *p_desc = (const uint8_t *) desc_itf;
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 };
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 (AUDIO_SUBCLASS_CONTROL == desc_itf->bInterfaceSubClass) {
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);
desc_itf = (tusb_desc_interface_t const *)p_desc;
TU_VERIFY(TUSB_CLASS_AUDIO == desc_itf->bInterfaceClass);
p_midi->itf_count = 1;
}
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);
p_midi->itf_num = desc_itf->bInterfaceNumber;
p_desc = tu_desc_next(p_desc);
p_midi->bInterfaceNumber = desc_itf->bInterfaceNumber;
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;
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);
p_midi->dev_addr = dev_addr;
p_midi->daddr = dev_addr;
if (tuh_midi_descriptor_cb) {
tuh_midi_descriptor_cb(dev_addr, &desc_cb);
tuh_midi_descriptor_cb(idx, &desc_cb);
}
return true;
}
bool midih_set_config(uint8_t dev_addr, uint8_t itf_num) {
(void) itf_num;
midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr);
TU_VERIFY(p_midi_host != NULL);
p_midi_host->configured = true;
uint8_t idx = tuh_midi_itf_get_index(dev_addr, itf_num);
TU_ASSERT(idx < CFG_TUH_MIDI);
midih_interface_t *p_midi = &_midi_host[idx];
p_midi->mounted = true;
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
usbh_driver_set_config_complete(dev_addr, p_midi_host->itf_num);
usbh_driver_set_config_complete(dev_addr, p_midi->bInterfaceNumber);
return true;
}
//--------------------------------------------------------------------+
// API
//--------------------------------------------------------------------+
bool tuh_midi_mounted(uint8_t dev_addr) {
midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr);
TU_VERIFY(p_midi_host != NULL);
return p_midi_host->configured;
bool tuh_midi_mounted(uint8_t idx) {
TU_VERIFY(idx < CFG_TUH_MIDI);
midih_interface_t *p_midi = &_midi_host[idx];
return p_midi->mounted;
}
uint8_t tuh_midi_get_num_tx_cables (uint8_t dev_addr) {
midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr);
TU_VERIFY(p_midi_host != NULL, 0);
TU_VERIFY(p_midi_host->ep_stream.tx.ep_addr != 0, 0);
return p_midi_host->num_cables_tx;
uint8_t tuh_midi_itf_get_index(uint8_t daddr, uint8_t itf_num) {
for (uint8_t idx = 0; idx < CFG_TUH_MIDI; idx++) {
const midih_interface_t *p_midi = &_midi_host[idx];
if (p_midi->daddr == daddr &&
(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) {
midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr);
TU_VERIFY(p_midi_host != NULL, 0);
TU_VERIFY(p_midi_host->ep_stream.rx.ep_addr != 0, 0);
return p_midi_host->num_cables_rx;
uint8_t tuh_midi_get_num_tx_cables (uint8_t idx) {
TU_VERIFY(idx < CFG_TUH_MIDI);
midih_interface_t *p_midi = &_midi_host[idx];
TU_VERIFY(p_midi->ep_stream.tx.ep_addr != 0, 0);
return p_midi->num_cables_tx;
}
uint32_t tuh_midi_read_available(uint8_t dev_addr) {
midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr);
TU_VERIFY(p_midi_host != NULL);
return tu_edpt_stream_read_available(&p_midi_host->ep_stream.rx);
uint8_t tuh_midi_get_num_rx_cables (uint8_t idx) {
TU_VERIFY(idx < CFG_TUH_MIDI);
midih_interface_t *p_midi = &_midi_host[idx];
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) {
midih_interface_t *p_midi = find_midi_by_daddr(dev_addr);
TU_VERIFY(p_midi != NULL);
return tu_edpt_stream_write_xfer(p_midi->dev_addr, &p_midi->ep_stream.tx);
uint32_t tuh_midi_read_available(uint8_t idx) {
TU_VERIFY(idx < CFG_TUH_MIDI);
midih_interface_t *p_midi = &_midi_host[idx];
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
//--------------------------------------------------------------------+
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) {
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));
uint32_t count4 = tu_min32(bufsize, tu_edpt_stream_read_available(&p_midi->ep_stream.rx));
count4 = tu_align4(count4); // round down to multiple of 4
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) {
midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr);
TU_VERIFY(p_midi_host != NULL, 0);
uint32_t bufsize4 = tu_align4(bufsize);
return tu_edpt_stream_write(dev_addr, &p_midi_host->ep_stream.tx, buffer, bufsize4);
uint32_t tuh_midi_packet_write_n(uint8_t idx, const uint8_t* buffer, uint32_t bufsize) {
TU_VERIFY(idx < CFG_TUH_MIDI && buffer && bufsize > 0, 0);
midih_interface_t *p_midi = &_midi_host[idx];
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
//--------------------------------------------------------------------+
#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) {
midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr);
TU_VERIFY(p_midi_host != NULL);
TU_VERIFY(cable_num < p_midi_host->num_cables_tx);
midi_driver_stream_t *stream = &p_midi_host->stream_write;
uint32_t tuh_midi_stream_write(uint8_t idx, uint8_t cable_num, uint8_t const *buffer, uint32_t bufsize) {
TU_VERIFY(idx < CFG_TUH_MIDI && buffer && bufsize > 0);
midih_interface_t *p_midi = &_midi_host[idx];
TU_VERIFY(cable_num < p_midi->num_cables_tx);
midi_driver_stream_t *stream = &p_midi->stream_write;
uint32_t i = 0;
while ((i < bufsize) && (tu_edpt_stream_write_available(dev_addr, &p_midi_host->ep_stream.tx) >= 4)) {
uint8_t const data = buffer[i];
i++;
uint32_t byte_count = 0;
while ((byte_count < bufsize) && (tu_edpt_stream_write_available(p_midi->daddr, &p_midi->ep_stream.tx) >= 4)) {
uint8_t const data = buffer[byte_count];
byte_count++;
if (data >= MIDI_STATUS_SYSREAL_TIMING_CLOCK) {
// real-time messages need to be sent right away
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.index = 2;
streamrt.total = 2;
uint32_t const count = tu_edpt_stream_write(dev_addr, &p_midi_host->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
uint32_t const count = tu_edpt_stream_write(p_midi->daddr, &p_midi->ep_stream.tx, streamrt.buffer, 4);
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) {
//------------- 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 {
//------------- On-going (buffering) packet -------------//
TU_ASSERT(stream->index < 4, i);
TU_ASSERT(stream->index < 4, byte_count);
stream->buffer[stream->index] = data;
stream->index++;
// 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
if (stream->index >= 2 && stream->index == stream->total) {
// 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);
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
stream->index = 0;
stream->total = 0;
// 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) {
midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr);
TU_VERIFY(p_midi_host != NULL);
uint32_t tuh_midi_stream_read(uint8_t idx, uint8_t *p_cable_num, uint8_t *p_buffer, uint16_t bufsize) {
TU_VERIFY(idx < CFG_TUH_MIDI && p_cable_num && p_buffer && bufsize > 0);
midih_interface_t *p_midi = &_midi_host[idx];
uint32_t bytes_buffered = 0;
TU_ASSERT(p_cable_num);
TU_ASSERT(p_buffer);
TU_ASSERT(bufsize);
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;
}
*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);
static uint16_t cable_sysex_in_progress; // bit i is set if received MIDI_STATUS_SYSEX_START but not MIDI_STATUS_SYSEX_END
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
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;
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
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);
if (status <= MIDI_MAX_DATA_VAL || 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
if (cable_sysex_in_progress & cable_mask) {
++bytes_to_add_to_stream;
for (uint8_t idx = 2; idx < 4; idx++) {
if (p_midi_host->stream_read.buffer[idx] <= MIDI_MAX_DATA_VAL) {
for (uint8_t i = 2; i < 4; i++) {
if (p_midi->stream_read.buffer[i] <= MIDI_MAX_DATA_VAL) {
++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;
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++) {
*p_buffer++ = p_midi_host->stream_read.buffer[idx];
for (uint8_t i = 1; i <= bytes_to_add_to_stream; i++) {
*p_buffer++ = p_midi->stream_read.buffer[i];
}
bytes_buffered += bytes_to_add_to_stream;
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;
if (new_cable == *p_cable_num) {
// 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;
}
#endif
#endif

View File

@@ -76,22 +76,26 @@ typedef struct {
} tuh_midi_descriptor_cb_t;
// 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
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
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.
// 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
// 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.
uint32_t tuh_midi_write_flush( uint8_t dev_addr);
uint32_t tuh_midi_write_flush(uint8_t idx);
//--------------------------------------------------------------------+
// 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
// 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
// Return true if a packet was returned
TU_ATTR_ALWAYS_INLINE static inline
bool tuh_midi_packet_read (uint8_t dev_addr, uint8_t packet[4]) {
return 4 == tuh_midi_packet_read_n(dev_addr, packet, 4);
bool tuh_midi_packet_read (uint8_t idx, uint8_t 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
// 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.
// Returns true if the packet was successfully queued.
TU_ATTR_ALWAYS_INLINE static inline
bool tuh_midi_packet_write (uint8_t dev_addr, uint8_t const packet[4]) {
return 4 == tuh_midi_packet_write_n(dev_addr, packet, 4);
bool tuh_midi_packet_write (uint8_t idx, uint8_t const 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
// reach the endpoint packet size or tuh_midi_write_flush() is called
// 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
// 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
// because a number of commercial devices out there do not encode
// 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
@@ -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.
// 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.
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
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_tx_cb(uint8_t dev_addr);
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 idx);
//--------------------------------------------------------------------+
// 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_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);
void midih_close (uint8_t dev_addr);
void midih_close (uint8_t daddr);
#ifdef __cplusplus
}