Browse Source

launchpad as usb midi driver: rx working. (almost) minimal changes

usb_midi_launchpad
heck 6 months ago
parent
commit
58adc59e59
  1. 18
      examples/main_launchpad.cc
  2. 222
      src/usb_midi_launchpad_transport.cc
  3. 19
      src/usbh_midi_launchpad.c
  4. 8
      src/usbh_midi_launchpad.h

18
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:

222
src/usb_midi_launchpad_transport.cc

@ -3,6 +3,7 @@
#include "usbh_midi_launchpad.h"
#include "usb_midi_launchpad_transport.hh"
#include <cassert>
#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()

19
src/usbh_midi_launchpad.c

@ -1,5 +1,6 @@
#include "usbh_midi_launchpad.h"
#include "daisy_core.h"
#include <stdbool.h>
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;
}

8
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

Loading…
Cancel
Save