diff --git a/examples/atmega32u4-device-arduino/src/ci_responder.c b/examples/atmega32u4-device-arduino/src/ci_responder.c index d2e912b..ceb716f 100644 --- a/examples/atmega32u4-device-arduino/src/ci_responder.c +++ b/examples/atmega32u4-device-arduino/src/ci_responder.c @@ -43,10 +43,15 @@ static uint32_t ci_rng(void *ctx) { static uint32_t ci_write_fn(const uint32_t *words, uint32_t count, void *ctx) { (void)ctx; - for (uint32_t i = 0; i < count; i++) - if (!midi2duino_write_word(words[i])) - return i; /* ring full: partial write reported */ - return count; + /* Whole packet or nothing: a split would leave half a UMP in the ring and + * corrupt the USB output. Pump the transport while the ring is full, with + * a bound so a host that stops reading cannot hang the responder. */ + for (uint16_t tries = 0; tries < 1000; tries++) { + if (midi2duino_write(words, (uint8_t)count)) + return count; + midi2duino_task(); + } + return 0; } void ci_responder_init(void) { diff --git a/examples/atmega32u4-device-arduino/src/midi2_usb.cpp b/examples/atmega32u4-device-arduino/src/midi2_usb.cpp index b0f56af..c0a9d38 100644 --- a/examples/atmega32u4-device-arduino/src/midi2_usb.cpp +++ b/examples/atmega32u4-device-arduino/src/midi2_usb.cpp @@ -17,12 +17,12 @@ static midi2_dispatch g_dp; static midi2_proc_state g_proc; static uint8_t g_sysex7_buf[160]; /* MIDI-CI reassembly */ -/* Stream messages (MT 0xF) drive the responder; everything else echoes back. +/* Stream messages drive the responder; everything else echoes back. * SysEx7 never lands here: the processor reassembles it and delivers it * through on_sysex7 to the MIDI-CI responder. */ static void on_ump(const uint32_t *words, uint8_t word_count, void *ctx) { (void)ctx; - if ((words[0] >> 28) == 0xF) + if (midi2_msg_get_mt(words) == MIDI2_MT_STREAM) midi2_dispatch_feed(words, word_count, &g_dp); else midi2duino_write(words, word_count); @@ -56,13 +56,19 @@ void Midi2Usb::task() { return; have = 1; } - uint8_t need = midi2_msg_word_count((uint8_t)(msg[0] >> 28)); + uint8_t mt = midi2_msg_get_mt(msg); + uint8_t need = midi2_msg_word_count(mt); while (have < need) { if (!midi2duino_read(&w)) return; /* rest of the message next round */ msg[have++] = w; } - midi2_proc_feed(&g_proc, msg, need); + /* Data128 (SysEx8 / MDS) is echoed raw: midi2_proc consumes it for + * reassembly, which is off here, so it never reaches on_ump. */ + if (mt == MIDI2_MT_DATA128) + midi2duino_write(msg, need); + else + midi2_proc_feed(&g_proc, msg, need); have = 0; } } diff --git a/examples/atmega32u4-device-arduino/src/stream_responder.c b/examples/atmega32u4-device-arduino/src/stream_responder.c index 0e945d9..5897c56 100644 --- a/examples/atmega32u4-device-arduino/src/stream_responder.c +++ b/examples/atmega32u4-device-arduino/src/stream_responder.c @@ -11,8 +11,15 @@ #define IDENT_VERSION 0x00010000UL /* 1.0 */ #define FB_NUM_MAIN 0 +/* A dropped Stream reply breaks host discovery, so pump the transport until + * the packet fits. Bounded so a host that stops reading cannot hang the loop + * (the pump only moves rings to endpoints; it never re-enters the processor). */ static void send4(const uint32_t *w) { - midi2duino_write(w, 4); + for (uint16_t tries = 0; tries < 1000; tries++) { + if (midi2duino_write(w, 4)) + return; + midi2duino_task(); + } } /* multi-packet text notification, 14 bytes per UMP (13 for FB name) */