diff --git a/examples/main_launchpad.cc b/examples/main_launchpad.cc index f68b3c8..67015f0 100644 --- a/examples/main_launchpad.cc +++ b/examples/main_launchpad.cc @@ -59,9 +59,11 @@ int main(void) hw.PrintLine("MIDI USB Host start"); /** Configure USB host */ - USBHostHandle::Config usbhConfig; - usbhConfig.connect_callback = USBH_Connect, usbhConfig.disconnect_callback = USBH_Disconnect, - usbhConfig.class_active_callback = USBH_ClassActive, usbhConfig.error_callback = USBH_Error, + USBHostHandle::Config usbhConfig{}; + usbhConfig.connect_callback = USBH_Connect; + usbhConfig.disconnect_callback = USBH_Disconnect; + usbhConfig.class_active_callback = USBH_ClassActive; + usbhConfig.error_callback = USBH_Error; usbHost.Init(usbhConfig); usbHost.RegisterClass(USBH_MIDI_LAUNCHPAD_CLASS); @@ -100,13 +102,15 @@ int main(void) * See DaisyExamples for some examples of this */ switch (msg.type) { + case NoteOn: + case NoteOff: // Do something on Note On events { - uint8_t bytes[3] = { 0x90, 0x00, 0x00 }; - bytes[1] = msg.data[0]; - bytes[2] = msg.data[1]; - midi.SendMessage(bytes, 3); + uint8_t bytes[2] = { 0x00, 0x00 }; + bytes[0] = msg.data[0]; + bytes[1] = msg.data[1]; + midi.SendMessage(bytes, 2); } break; default: diff --git a/src/usb_midi_launchpad_transport.cc b/src/usb_midi_launchpad_transport.cc index 2fc1902..ee1b421 100644 --- a/src/usb_midi_launchpad_transport.cc +++ b/src/usb_midi_launchpad_transport.cc @@ -3,6 +3,7 @@ #include "usbh_midi_launchpad.h" #include "usb_midi_launchpad_transport.hh" #include +#include "daisy_seed.h" extern "C" { @@ -30,7 +31,7 @@ public: void FlushRx() { rx_buffer_.Flush(); } void Tx(uint8_t* buffer, size_t size); - void UsbToMidi(uint8_t* buffer, uint8_t length); + void UsbToMidi(uint8_t); void MidiToUsb(uint8_t* buffer, size_t length); void Parse(); @@ -75,16 +76,37 @@ private: // Global Impl static UsbMidiLaunchpadTransport::Impl midi_usb_handle; +extern daisy::DaisySeed hw; + +void to_string_array_uint(char* outbuf, uint8_t* arr, size_t len) +{ + for (uint32_t i = 0; i < len; i++) { + char charbuf[100] = ""; + sprintf(charbuf, "[%x]", arr[i]); + strcat(outbuf, charbuf); + } +} + void ReceiveCallback(uint8_t* buffer, uint32_t* length) { - if(midi_usb_handle.RxActive()) { - for(uint16_t i = 0; i < *length; i += 4) - { - size_t remaining_bytes = *length - i; - uint8_t packet_length = remaining_bytes > 4 ? 4 : remaining_bytes; - midi_usb_handle.UsbToMidi(buffer + i, packet_length); + char strbuf[1000] = ""; + to_string_array_uint(strbuf, buffer, *length); + hw.PrintLine("RX RAW: %x - %s", *length, strbuf); + } + if (midi_usb_handle.RxActive()) { + for (unsigned int notemsg = 0; notemsg < *length; notemsg += 2) { + uint8_t midi_note[3] = { 0x90, 0x00, 0x00 }; + midi_note[1] = buffer[notemsg]; + midi_note[2] = buffer[notemsg += 1]; + midi_usb_handle.UsbToMidi(midi_note[0]); + midi_usb_handle.UsbToMidi(midi_note[1]); + midi_usb_handle.UsbToMidi(midi_note[2]); midi_usb_handle.Parse(); + + char strbuf[1000] = ""; + to_string_array_uint(strbuf, midi_note, 3); + hw.PrintLine("RX NOTE: %s", strbuf); } } } @@ -132,189 +154,47 @@ void UsbMidiLaunchpadTransport::Impl::Tx(uint8_t* buffer, size_t size) int attempt_count = config_.tx_retry_count; bool should_retry; - MidiToUsb(buffer, size); - do - { - if(config_.periph == Config::HOST) - { + // MidiToUsb(buffer, size); + do { + if (config_.periph == Config::HOST) { MIDI_Launchpad_ErrorTypeDef result; - result = USBH_MIDI_Launchpad_Transmit(pUSB_Host, tx_buffer_, tx_ptr_); + result = USBH_MIDI_Launchpad_Transmit(pUSB_Host, buffer, size); + { + char strbuf[1000] = ""; + to_string_array_uint(strbuf, buffer, size); + hw.PrintLine("Transport Tx() RES=%i - %s",result, strbuf); + } + should_retry = (result == MIDI_BUSY) && attempt_count--; } - else - { - UsbHandle::Result result; - if(config_.periph == Config::EXTERNAL) - result = usb_handle_.TransmitExternal(tx_buffer_, tx_ptr_); - else - result = usb_handle_.TransmitInternal(tx_buffer_, tx_ptr_); - should_retry - = (result == UsbHandle::Result::ERR) && attempt_count--; - } - - - if(should_retry) + if (should_retry) { System::DelayUs(100); - } while(should_retry); + } + } while (should_retry); tx_ptr_ = 0; } -void UsbMidiLaunchpadTransport::Impl::UsbToMidi(uint8_t* buffer, uint8_t length) +void UsbMidiLaunchpadTransport::Impl::UsbToMidi(uint8_t buffer) { - // A length of less than four in the buffer indicates - // a garbled message, since USB MIDI packets usually* - // require 4 bytes per message - if(length < 4) - return; - - // Right now, Daisy only supports a single cable, so we don't - // need to extract that value from the upper nibble - uint8_t code_index = buffer[0] & 0xF; - if(code_index == 0x0 || code_index == 0x1) - { - // 0x0 and 0x1 are reserved codes, and if they come up, - // there's probably been an error. *0xF indicates data is - // sent one byte at a time, rather than in packets of four. - // This functionality could be supported later. - // The single-byte mode does still come through as 32-bit messages - return; - } - - // Only writing as many bytes as necessary - for(uint8_t i = 0; i < code_index_size_[code_index]; i++) - { - if(rx_buffer_.writable() > 0) - rx_buffer_.Write(buffer[1 + i]); - else - { - rx_active_ = false; // disable on overflow - break; - } + if (rx_buffer_.writable() > 0) { + rx_buffer_.Write(buffer); + } else { + rx_active_ = false; // disable on overflow } } void UsbMidiLaunchpadTransport::Impl::MidiToUsbSingle(uint8_t* buffer, size_t size) { - if(size == 0) - return; - - // Channel voice messages - if((buffer[0] & 0xF0) != 0xF0) - { - // Check message validity - if((buffer[0] & 0xF0) == 0xC0 || (buffer[0] & 0xF0) == 0xD0) - { - if(size != 2) - return; // error - } - else - { - if(size != 3) - return; //error - } - - // CIN is the same as status byte for channel voice messages - tx_buffer_[tx_ptr_ + 0] = (buffer[0] & 0xF0) >> 4; - tx_buffer_[tx_ptr_ + 1] = buffer[0]; - tx_buffer_[tx_ptr_ + 2] = buffer[1]; - tx_buffer_[tx_ptr_ + 3] = size == 3 ? buffer[2] : 0; - - tx_ptr_ += 4; - } - else // buffer[0] & 0xF0 == 0xF0 aka System common or realtime - { - if(0xF2 == buffer[0]) - // three byte message - { - if(size != 3) - return; // error - - tx_buffer_[tx_ptr_ + 0] = 0x03; - tx_buffer_[tx_ptr_ + 1] = buffer[0]; - tx_buffer_[tx_ptr_ + 2] = buffer[1]; - tx_buffer_[tx_ptr_ + 3] = buffer[2]; - - tx_ptr_ += 4; - } - if(0xF1 == buffer[0] || 0xF3 == buffer[0]) - // two byte messages - { - if(size != 2) - return; // error - - tx_buffer_[tx_ptr_ + 0] = 0x02; - tx_buffer_[tx_ptr_ + 1] = buffer[0]; - tx_buffer_[tx_ptr_ + 2] = buffer[1]; - tx_buffer_[tx_ptr_ + 3] = 0; - - tx_ptr_ += 4; - } - else if(0xF4 <= buffer[0]) - // one byte message - { - if(size != 1) - return; // error - - tx_buffer_[tx_ptr_ + 0] = 0x05; - tx_buffer_[tx_ptr_ + 1] = buffer[0]; - tx_buffer_[tx_ptr_ + 2] = 0; - tx_buffer_[tx_ptr_ + 3] = 0; - - tx_ptr_ += 4; - } - else // sysex - { - size_t i = 0; - // Sysex messages are split up into several 4 bytes packets - // first ones use CIN 0x04 - // but packet containing the SysEx stop byte use a different CIN - for(i = 0; i + 3 < size; i += 3, tx_ptr_ += 4) - { - tx_buffer_[tx_ptr_] = 0x04; - tx_buffer_[tx_ptr_ + 1] = buffer[i]; - tx_buffer_[tx_ptr_ + 2] = buffer[i + 1]; - tx_buffer_[tx_ptr_ + 3] = buffer[i + 2]; - } - - // Fill CIN for terminating bytes - // 0x05 for 1 remaining byte - // 0x06 for 2 - // 0x07 for 3 - tx_buffer_[tx_ptr_] = 0x05 + (size - i - 1); - tx_ptr_++; - for(; i < size; ++i, ++tx_ptr_) - tx_buffer_[tx_ptr_] = buffer[i]; - for(; (tx_ptr_ % 4) != 0; ++tx_ptr_) - tx_buffer_[tx_ptr_] = 0; - } + for (int i = 0; i < size; i++) { + tx_buffer_[tx_ptr_] = buffer[i]; + tx_ptr_++; } } void UsbMidiLaunchpadTransport::Impl::MidiToUsb(uint8_t* buffer, size_t size) { - // We'll assume your message starts with a status byte! - size_t status_index = 0; - while(status_index < size) - { - // Search for next status byte or end - size_t next_status = status_index; - for(size_t j = status_index + 1; j < size; j++) - { - if(buffer[j] & 0x80) - { - next_status = j; - break; - } - } - if(next_status == status_index) - { - // Either we're at the end or it's malformed - next_status = size; - } - MidiToUsbSingle(buffer + status_index, next_status - status_index); - status_index = next_status; - } + MidiToUsbSingle(buffer, size); } void UsbMidiLaunchpadTransport::Impl::Parse() diff --git a/src/usbh_midi_launchpad.c b/src/usbh_midi_launchpad.c index cb4c8d5..bcb5fad 100644 --- a/src/usbh_midi_launchpad.c +++ b/src/usbh_midi_launchpad.c @@ -1,5 +1,6 @@ #include "usbh_midi_launchpad.h" #include "daisy_core.h" +#include static USB_MIDI_Launchpad_HandleTypeDef DMA_BUFFER_MEM_SECTION static_midi; @@ -20,7 +21,7 @@ USBH_ClassTypeDef USBH_Launchpad_midi = { NULL, }; -#define EP_IN 0x80U +#define EP_IN 0x81U /** * @brief USBH_MIDI_InterfaceInit @@ -64,6 +65,9 @@ static USBH_StatusTypeDef USBH_MIDI_InterfaceInit(USBH_HandleTypeDef *phost) USBH_OpenPipe(phost, MIDI_Handle->InPipe, MIDI_Handle->InEp, phost->device.address, phost->device.speed, USB_EP_TYPE_BULK, MIDI_Handle->InEpSize); +// USBH_OpenPipe(phost, MIDI_Handle->InPipe, MIDI_Handle->InEp, +// phost->device.address, phost->device.speed, USB_EP_TYPE_INTR, +// MIDI_Handle->InEpSize); (void)USBH_LL_SetToggle(phost, MIDI_Handle->InPipe, 0U); USBH_UsrLog("InEP[%d] %02x size=%u", ep, MIDI_Handle->InEp, MIDI_Handle->InEpSize); } else { @@ -74,6 +78,9 @@ static USBH_StatusTypeDef USBH_MIDI_InterfaceInit(USBH_HandleTypeDef *phost) USBH_OpenPipe(phost, MIDI_Handle->OutPipe, MIDI_Handle->OutEp, phost->device.address, phost->device.speed, USB_EP_TYPE_BULK, MIDI_Handle->OutEpSize); +// USBH_OpenPipe(phost, MIDI_Handle->OutPipe, MIDI_Handle->OutEp, +// phost->device.address, phost->device.speed, USB_EP_TYPE_INTR, +// MIDI_Handle->OutEpSize); (void)USBH_LL_SetToggle(phost, MIDI_Handle->OutPipe, 0U); USBH_UsrLog("OutEP[%d] %02x size=%u", ep, MIDI_Handle->OutEp, MIDI_Handle->OutEpSize); } @@ -150,6 +157,15 @@ static USBH_StatusTypeDef USBH_MIDI_Process(USBH_HandleTypeDef *phost) break; case MIDI_RX: // Always returns USBH_OK, call USBH_LL_GetURBState() for status +// USBH_InterruptReceiveData(phost, hMidi->rxBuffer, hMidi->InEpSize, hMidi->InPipe); +// static uint8_t togglestate = 0; +// if(togglestate == 0) { +// togglestate = 1; +// } else { +// togglestate = 0; +// } +// (void)USBH_LL_SetToggle(phost, hMidi->InPipe, togglestate); + USBH_BulkReceiveData(phost, hMidi->rxBuffer, hMidi->InEpSize, hMidi->InPipe); hMidi->state = MIDI_RX_POLL; break; @@ -227,6 +243,7 @@ MIDI_Launchpad_ErrorTypeDef USBH_MIDI_Launchpad_Transmit(USBH_HandleTypeDef *pho } size_t sz = (len <= hMidi->OutEpSize) ? len : hMidi->OutEpSize; USBH_BulkSendData(phost, data, sz, hMidi->OutPipe, 1); +// USBH_InterruptSendData(phost, data, sz, hMidi->OutPipe); len -= sz; ++numUrbs; } diff --git a/src/usbh_midi_launchpad.h b/src/usbh_midi_launchpad.h index 02e27f0..91b206e 100644 --- a/src/usbh_midi_launchpad.h +++ b/src/usbh_midi_launchpad.h @@ -14,7 +14,7 @@ extern "C" { MIDI_RX_POLL, MIDI_RX_ERROR, MIDI_FATAL_ERROR - } USB_MIDI_Launchpad_StateTypeDef; + } MIDI_Launchpad_StateTypeDef; typedef enum { MIDI_OK, @@ -34,7 +34,7 @@ extern "C" { uint8_t OutPipe; uint8_t OutEp; uint16_t OutEpSize; - USB_MIDI_Launchpad_StateTypeDef state; + MIDI_Launchpad_StateTypeDef state; MIDI_Launchpad_ErrorTypeDef error; USBH_MIDI_Launchpad_RxCallback callback; void* pUser; @@ -42,8 +42,8 @@ extern "C" { } USB_MIDI_Launchpad_HandleTypeDef; /* MIDI Class Codes */ -#define USB_LAUNCHPAD_CLASS 0x01U -#define USB_LAUNCHPAD_STREAMING_SUBCLASS 0x03U +#define USB_LAUNCHPAD_CLASS 0xFFU +#define USB_LAUNCHPAD_STREAMING_SUBCLASS 0x0U extern USBH_ClassTypeDef USBH_Launchpad_midi; #define USBH_MIDI_LAUNCHPAD_CLASS &USBH_Launchpad_midi