mirror of
https://github.com/felis/USB_Host_Shield_2.0.git
synced 2024-03-22 11:31:26 +01:00
Merge pull request #634 from YuuichiAkagawa/pr_usbh_midi_060
Update MIDI driver v0.6.0
This commit is contained in:
commit
13449cbf47
8 changed files with 334 additions and 300 deletions
|
@ -355,7 +355,7 @@ You can convert USB MIDI keyboard to legacy serial MIDI.
|
||||||
* [USB_MIDI_converter.ino](examples/USBH_MIDI/USB_MIDI_converter/USB_MIDI_converter.ino)
|
* [USB_MIDI_converter.ino](examples/USBH_MIDI/USB_MIDI_converter/USB_MIDI_converter.ino)
|
||||||
* [USB_MIDI_converter_multi.ino](examples/USBH_MIDI/USB_MIDI_converter_multi/USB_MIDI_converter_multi.ino)
|
* [USB_MIDI_converter_multi.ino](examples/USBH_MIDI/USB_MIDI_converter_multi/USB_MIDI_converter_multi.ino)
|
||||||
|
|
||||||
For information see the following page: <http://yuuichiakagawa.github.io/USBH_MIDI/>.
|
For more information see : <https://github.com/YuuichiAkagawa/USBH_MIDI>.
|
||||||
|
|
||||||
### [amBX Library](AMBX.cpp)
|
### [amBX Library](AMBX.cpp)
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
*******************************************************************************
|
*******************************************************************************
|
||||||
* USB-MIDI dump utility
|
* USB-MIDI dump utility
|
||||||
* Copyright (C) 2013-2017 Yuuichi Akagawa
|
* Copyright (C) 2013-2021 Yuuichi Akagawa
|
||||||
*
|
*
|
||||||
* for use with USB Host Shield 2.0 from Circuitsathome.com
|
* for use with USB Host Shield 2.0 from Circuitsathome.com
|
||||||
* https://github.com/felis/USB_Host_Shield_2.0
|
* https://github.com/felis/USB_Host_Shield_2.0
|
||||||
|
@ -13,35 +13,37 @@
|
||||||
#include <usbh_midi.h>
|
#include <usbh_midi.h>
|
||||||
#include <usbhub.h>
|
#include <usbhub.h>
|
||||||
|
|
||||||
// Satisfy the IDE, which needs to see the include statment in the ino too.
|
|
||||||
#ifdef dobogusinclude
|
|
||||||
#include <spi4teensy3.h>
|
|
||||||
#endif
|
|
||||||
#include <SPI.h>
|
|
||||||
|
|
||||||
USB Usb;
|
USB Usb;
|
||||||
//USBHub Hub(&Usb);
|
USBHub Hub(&Usb);
|
||||||
USBH_MIDI Midi(&Usb);
|
USBH_MIDI Midi(&Usb);
|
||||||
|
|
||||||
void MIDI_poll();
|
void MIDI_poll();
|
||||||
|
|
||||||
uint16_t pid, vid;
|
void onInit()
|
||||||
|
{
|
||||||
|
char buf[20];
|
||||||
|
uint16_t vid = Midi.idVendor();
|
||||||
|
uint16_t pid = Midi.idProduct();
|
||||||
|
sprintf(buf, "VID:%04X, PID:%04X", vid, pid);
|
||||||
|
Serial.println(buf);
|
||||||
|
}
|
||||||
|
|
||||||
void setup()
|
void setup()
|
||||||
{
|
{
|
||||||
vid = pid = 0;
|
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
|
||||||
if (Usb.Init() == -1) {
|
if (Usb.Init() == -1) {
|
||||||
while (1); //halt
|
while (1); //halt
|
||||||
}//if (Usb.Init() == -1...
|
}//if (Usb.Init() == -1...
|
||||||
delay( 200 );
|
delay( 200 );
|
||||||
|
|
||||||
|
// Register onInit() function
|
||||||
|
Midi.attachOnInit(onInit);
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop()
|
void loop()
|
||||||
{
|
{
|
||||||
Usb.Task();
|
Usb.Task();
|
||||||
//uint32_t t1 = (uint32_t)micros();
|
|
||||||
if ( Midi ) {
|
if ( Midi ) {
|
||||||
MIDI_poll();
|
MIDI_poll();
|
||||||
}
|
}
|
||||||
|
@ -50,23 +52,16 @@ void loop()
|
||||||
// Poll USB MIDI Controler and send to serial MIDI
|
// Poll USB MIDI Controler and send to serial MIDI
|
||||||
void MIDI_poll()
|
void MIDI_poll()
|
||||||
{
|
{
|
||||||
char buf[20];
|
char buf[16];
|
||||||
uint8_t bufMidi[64];
|
uint8_t bufMidi[MIDI_EVENT_PACKET_SIZE];
|
||||||
uint16_t rcvd;
|
uint16_t rcvd;
|
||||||
|
|
||||||
if (Midi.idVendor() != vid || Midi.idProduct() != pid) {
|
|
||||||
vid = Midi.idVendor();
|
|
||||||
pid = Midi.idProduct();
|
|
||||||
sprintf(buf, "VID:%04X, PID:%04X", vid, pid);
|
|
||||||
Serial.println(buf);
|
|
||||||
}
|
|
||||||
if (Midi.RecvData( &rcvd, bufMidi) == 0 ) {
|
if (Midi.RecvData( &rcvd, bufMidi) == 0 ) {
|
||||||
uint32_t time = (uint32_t)millis();
|
uint32_t time = (uint32_t)millis();
|
||||||
sprintf(buf, "%04X%04X: ", (uint16_t)(time >> 16), (uint16_t)(time & 0xFFFF)); // Split variable to prevent warnings on the ESP8266 platform
|
sprintf(buf, "%04X%04X:%3d:", (uint16_t)(time >> 16), (uint16_t)(time & 0xFFFF), rcvd); // Split variable to prevent warnings on the ESP8266 platform
|
||||||
Serial.print(buf);
|
Serial.print(buf);
|
||||||
Serial.print(rcvd);
|
|
||||||
Serial.print(':');
|
for (int i = 0; i < MIDI_EVENT_PACKET_SIZE; i++) {
|
||||||
for (int i = 0; i < 64; i++) {
|
|
||||||
sprintf(buf, " %02X", bufMidi[i]);
|
sprintf(buf, " %02X", bufMidi[i]);
|
||||||
Serial.print(buf);
|
Serial.print(buf);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
*******************************************************************************
|
*******************************************************************************
|
||||||
* USB-MIDI to Legacy Serial MIDI converter
|
* USB-MIDI to Legacy Serial MIDI converter
|
||||||
* Copyright (C) 2012-2020 Yuuichi Akagawa
|
* Copyright (C) 2012-2021 Yuuichi Akagawa
|
||||||
*
|
*
|
||||||
* Idea from LPK25 USB-MIDI to Serial MIDI converter
|
* Idea from LPK25 USB-MIDI to Serial MIDI converter
|
||||||
* by Collin Cunningham - makezine.com, narbotic.com
|
* by Collin Cunningham - makezine.com, narbotic.com
|
||||||
|
@ -13,12 +13,6 @@
|
||||||
#include <usbh_midi.h>
|
#include <usbh_midi.h>
|
||||||
#include <usbhub.h>
|
#include <usbhub.h>
|
||||||
|
|
||||||
// Satisfy the IDE, which needs to see the include statment in the ino too.
|
|
||||||
#ifdef dobogusinclude
|
|
||||||
#include <spi4teensy3.h>
|
|
||||||
#endif
|
|
||||||
#include <SPI.h>
|
|
||||||
|
|
||||||
#ifdef USBCON
|
#ifdef USBCON
|
||||||
#define _MIDI_SERIAL_PORT Serial1
|
#define _MIDI_SERIAL_PORT Serial1
|
||||||
#else
|
#else
|
||||||
|
@ -40,7 +34,6 @@ USB Usb;
|
||||||
USBH_MIDI Midi(&Usb);
|
USBH_MIDI Midi(&Usb);
|
||||||
|
|
||||||
void MIDI_poll();
|
void MIDI_poll();
|
||||||
void doDelay(uint32_t t1, uint32_t t2, uint32_t delayTime);
|
|
||||||
|
|
||||||
void setup()
|
void setup()
|
||||||
{
|
{
|
||||||
|
@ -55,12 +48,12 @@ void setup()
|
||||||
void loop()
|
void loop()
|
||||||
{
|
{
|
||||||
Usb.Task();
|
Usb.Task();
|
||||||
uint32_t t1 = (uint32_t)micros();
|
|
||||||
if ( Midi ) {
|
if ( Midi ) {
|
||||||
MIDI_poll();
|
MIDI_poll();
|
||||||
}
|
}
|
||||||
//delay(1ms)
|
//delay(1ms) if you want
|
||||||
doDelay(t1, (uint32_t)micros(), 1000);
|
//delayMicroseconds(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Poll USB MIDI Controler and send to serial MIDI
|
// Poll USB MIDI Controler and send to serial MIDI
|
||||||
|
@ -79,14 +72,3 @@ void MIDI_poll()
|
||||||
}
|
}
|
||||||
} while (size > 0);
|
} while (size > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delay time (max 16383 us)
|
|
||||||
void doDelay(uint32_t t1, uint32_t t2, uint32_t delayTime)
|
|
||||||
{
|
|
||||||
uint32_t t3;
|
|
||||||
|
|
||||||
t3 = t2 - t1;
|
|
||||||
if ( t3 < delayTime ) {
|
|
||||||
delayMicroseconds(delayTime - t3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
*******************************************************************************
|
*******************************************************************************
|
||||||
* USB-MIDI to Legacy Serial MIDI converter
|
* USB-MIDI to Legacy Serial MIDI converter
|
||||||
* Copyright (C) 2012-2020 Yuuichi Akagawa
|
* Copyright (C) 2012-2021 Yuuichi Akagawa
|
||||||
*
|
*
|
||||||
* Idea from LPK25 USB-MIDI to Serial MIDI converter
|
* Idea from LPK25 USB-MIDI to Serial MIDI converter
|
||||||
* by Collin Cunningham - makezine.com, narbotic.com
|
* by Collin Cunningham - makezine.com, narbotic.com
|
||||||
|
@ -13,12 +13,6 @@
|
||||||
#include <usbh_midi.h>
|
#include <usbh_midi.h>
|
||||||
#include <usbhub.h>
|
#include <usbhub.h>
|
||||||
|
|
||||||
// Satisfy the IDE, which needs to see the include statment in the ino too.
|
|
||||||
#ifdef dobogusinclude
|
|
||||||
#include <spi4teensy3.h>
|
|
||||||
#endif
|
|
||||||
#include <SPI.h>
|
|
||||||
|
|
||||||
#ifdef USBCON
|
#ifdef USBCON
|
||||||
#define _MIDI_SERIAL_PORT Serial1
|
#define _MIDI_SERIAL_PORT Serial1
|
||||||
#else
|
#else
|
||||||
|
@ -41,8 +35,7 @@ USBHub Hub1(&Usb);
|
||||||
USBH_MIDI Midi1(&Usb);
|
USBH_MIDI Midi1(&Usb);
|
||||||
USBH_MIDI Midi2(&Usb);
|
USBH_MIDI Midi2(&Usb);
|
||||||
|
|
||||||
void MIDI_poll();
|
void MIDI_poll(USBH_MIDI &Midi);
|
||||||
void doDelay(uint32_t t1, uint32_t t2, uint32_t delayTime);
|
|
||||||
|
|
||||||
void setup()
|
void setup()
|
||||||
{
|
{
|
||||||
|
@ -57,15 +50,15 @@ void setup()
|
||||||
void loop()
|
void loop()
|
||||||
{
|
{
|
||||||
Usb.Task();
|
Usb.Task();
|
||||||
uint32_t t1 = (uint32_t)micros();
|
|
||||||
if ( Midi1 ) {
|
if ( Midi1 ) {
|
||||||
MIDI_poll(Midi1);
|
MIDI_poll(Midi1);
|
||||||
}
|
}
|
||||||
if ( Midi2 ) {
|
if ( Midi2 ) {
|
||||||
MIDI_poll(Midi2);
|
MIDI_poll(Midi2);
|
||||||
}
|
}
|
||||||
//delay(1ms)
|
//delay(1ms) if you want
|
||||||
doDelay(t1, (uint32_t)micros(), 1000);
|
//delayMicroseconds(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Poll USB MIDI Controler and send to serial MIDI
|
// Poll USB MIDI Controler and send to serial MIDI
|
||||||
|
|
|
@ -16,12 +16,6 @@
|
||||||
#include <usbh_midi.h>
|
#include <usbh_midi.h>
|
||||||
#include <usbhub.h>
|
#include <usbhub.h>
|
||||||
|
|
||||||
// Satisfy the IDE, which needs to see the include statment in the ino too.
|
|
||||||
#ifdef dobogusinclude
|
|
||||||
#include <spi4teensy3.h>
|
|
||||||
#endif
|
|
||||||
#include <SPI.h>
|
|
||||||
|
|
||||||
//Arduino MIDI library v4.2 compatibility
|
//Arduino MIDI library v4.2 compatibility
|
||||||
#ifdef MIDI_CREATE_DEFAULT_INSTANCE
|
#ifdef MIDI_CREATE_DEFAULT_INSTANCE
|
||||||
MIDI_CREATE_DEFAULT_INSTANCE();
|
MIDI_CREATE_DEFAULT_INSTANCE();
|
||||||
|
@ -44,7 +38,6 @@ MIDI_CREATE_DEFAULT_INSTANCE();
|
||||||
//////////////////////////
|
//////////////////////////
|
||||||
|
|
||||||
USB Usb;
|
USB Usb;
|
||||||
//USBHub Hub1(&Usb);
|
|
||||||
USBH_MIDI Midi(&Usb);
|
USBH_MIDI Midi(&Usb);
|
||||||
|
|
||||||
void MIDI_poll();
|
void MIDI_poll();
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
*******************************************************************************
|
*******************************************************************************
|
||||||
* eVY1 Shield sample - Say 'Konnichiwa'
|
* eVY1 Shield sample - Say 'Konnichiwa'
|
||||||
* Copyright (C) 2014-2016 Yuuichi Akagawa
|
* Copyright (C) 2014-2021 Yuuichi Akagawa
|
||||||
*
|
*
|
||||||
* This is sample program. Do not expect perfect behavior.
|
* This is sample program. Do not expect perfect behavior.
|
||||||
*******************************************************************************
|
*******************************************************************************
|
||||||
|
@ -9,12 +9,6 @@
|
||||||
#include <usbh_midi.h>
|
#include <usbh_midi.h>
|
||||||
#include <usbhub.h>
|
#include <usbhub.h>
|
||||||
|
|
||||||
// Satisfy the IDE, which needs to see the include statment in the ino too.
|
|
||||||
#ifdef dobogusinclude
|
|
||||||
#include <spi4teensy3.h>
|
|
||||||
#endif
|
|
||||||
#include <SPI.h>
|
|
||||||
|
|
||||||
USB Usb;
|
USB Usb;
|
||||||
//USBHub Hub(&Usb);
|
//USBHub Hub(&Usb);
|
||||||
USBH_MIDI Midi(&Usb);
|
USBH_MIDI Midi(&Usb);
|
||||||
|
@ -23,7 +17,6 @@ void MIDI_poll();
|
||||||
void noteOn(uint8_t note);
|
void noteOn(uint8_t note);
|
||||||
void noteOff(uint8_t note);
|
void noteOff(uint8_t note);
|
||||||
|
|
||||||
uint16_t pid, vid;
|
|
||||||
uint8_t exdata[] = {
|
uint8_t exdata[] = {
|
||||||
0xf0, 0x43, 0x79, 0x09, 0x00, 0x50, 0x10,
|
0xf0, 0x43, 0x79, 0x09, 0x00, 0x50, 0x10,
|
||||||
'k', ' ', 'o', ',', //Ko
|
'k', ' ', 'o', ',', //Ko
|
||||||
|
@ -34,15 +27,22 @@ uint8_t exdata[] = {
|
||||||
0x00, 0xf7
|
0x00, 0xf7
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void onInit()
|
||||||
|
{
|
||||||
|
// Send Phonetic symbols via SysEx
|
||||||
|
Midi.SendSysEx(exdata, sizeof(exdata));
|
||||||
|
delay(500);
|
||||||
|
}
|
||||||
|
|
||||||
void setup()
|
void setup()
|
||||||
{
|
{
|
||||||
vid = pid = 0;
|
|
||||||
Serial.begin(115200);
|
|
||||||
|
|
||||||
if (Usb.Init() == -1) {
|
if (Usb.Init() == -1) {
|
||||||
while (1); //halt
|
while (1); //halt
|
||||||
}//if (Usb.Init() == -1...
|
}//if (Usb.Init() == -1...
|
||||||
delay( 200 );
|
delay( 200 );
|
||||||
|
|
||||||
|
// Register onInit() function
|
||||||
|
Midi.attachOnInit(onInit);
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop()
|
void loop()
|
||||||
|
@ -61,13 +61,6 @@ void loop()
|
||||||
void MIDI_poll()
|
void MIDI_poll()
|
||||||
{
|
{
|
||||||
uint8_t inBuf[ 3 ];
|
uint8_t inBuf[ 3 ];
|
||||||
|
|
||||||
//first call?
|
|
||||||
if (Midi.idVendor() != vid || Midi.idProduct() != pid) {
|
|
||||||
vid = Midi.idVendor(); pid = Midi.idProduct();
|
|
||||||
Midi.SendSysEx(exdata, sizeof(exdata));
|
|
||||||
delay(500);
|
|
||||||
}
|
|
||||||
Midi.RecvData(inBuf);
|
Midi.RecvData(inBuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
424
usbh_midi.cpp
424
usbh_midi.cpp
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
*******************************************************************************
|
*******************************************************************************
|
||||||
* USB-MIDI class driver for USB Host Shield 2.0 Library
|
* USB-MIDI class driver for USB Host Shield 2.0 Library
|
||||||
* Copyright (c) 2012-2018 Yuuichi Akagawa
|
* Copyright (c) 2012-2021 Yuuichi Akagawa
|
||||||
*
|
*
|
||||||
* Idea from LPK25 USB-MIDI to Serial MIDI converter
|
* Idea from LPK25 USB-MIDI to Serial MIDI converter
|
||||||
* by Collin Cunningham - makezine.com, narbotic.com
|
* by Collin Cunningham - makezine.com, narbotic.com
|
||||||
|
@ -25,6 +25,9 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "usbh_midi.h"
|
#include "usbh_midi.h"
|
||||||
|
// To enable serial debugging see "settings.h"
|
||||||
|
//#define EXTRADEBUG // Uncomment to get even more debugging data
|
||||||
|
|
||||||
//////////////////////////
|
//////////////////////////
|
||||||
// MIDI MESAGES
|
// MIDI MESAGES
|
||||||
// midi.org/techspecs/
|
// midi.org/techspecs/
|
||||||
|
@ -79,24 +82,16 @@
|
||||||
//| 0xF | 1 |Single Byte
|
//| 0xF | 1 |Single Byte
|
||||||
//+-----+-----------+-------------------------------------------------------------------
|
//+-----+-----------+-------------------------------------------------------------------
|
||||||
|
|
||||||
const uint8_t USBH_MIDI::epDataInIndex = 1;
|
|
||||||
const uint8_t USBH_MIDI::epDataOutIndex = 2;
|
|
||||||
const uint8_t USBH_MIDI::epDataInIndexVSP = 3;
|
|
||||||
const uint8_t USBH_MIDI::epDataOutIndexVSP = 4;
|
|
||||||
|
|
||||||
USBH_MIDI::USBH_MIDI(USB *p) :
|
USBH_MIDI::USBH_MIDI(USB *p) :
|
||||||
pUsb(p),
|
pUsb(p),
|
||||||
bAddress(0),
|
bAddress(0),
|
||||||
bNumEP(1),
|
|
||||||
bPollEnable(false),
|
bPollEnable(false),
|
||||||
isMidiFound(false),
|
|
||||||
readPtr(0) {
|
readPtr(0) {
|
||||||
// initialize endpoint data structures
|
// initialize endpoint data structures
|
||||||
for(uint8_t i=0; i<MIDI_MAX_ENDPOINTS; i++) {
|
for(uint8_t i=0; i<MIDI_MAX_ENDPOINTS; i++) {
|
||||||
epInfo[i].epAddr = 0;
|
epInfo[i].epAddr = 0;
|
||||||
epInfo[i].maxPktSize = (i) ? 0 : 8;
|
epInfo[i].maxPktSize = (i) ? 0 : 8;
|
||||||
epInfo[i].bmNakPower = (i) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER;
|
epInfo[i].bmNakPower = (i) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER;
|
||||||
|
|
||||||
}
|
}
|
||||||
// register in USB subsystem
|
// register in USB subsystem
|
||||||
if (pUsb) {
|
if (pUsb) {
|
||||||
|
@ -113,15 +108,20 @@ uint8_t USBH_MIDI::Init(uint8_t parent, uint8_t port, bool lowspeed)
|
||||||
UsbDevice *p = NULL;
|
UsbDevice *p = NULL;
|
||||||
EpInfo *oldep_ptr = NULL;
|
EpInfo *oldep_ptr = NULL;
|
||||||
uint8_t num_of_conf; // number of configurations
|
uint8_t num_of_conf; // number of configurations
|
||||||
|
uint8_t bConfNum = 0; // configuration number
|
||||||
|
uint8_t bNumEP = 1; // total number of EP in the configuration
|
||||||
|
|
||||||
USBTRACE("\rMIDI Init\r\n");
|
USBTRACE("\rMIDI Init\r\n");
|
||||||
|
#ifdef DEBUG_USB_HOST
|
||||||
|
Notify(PSTR("USBH_MIDI version "), 0x80), D_PrintHex((uint8_t) (USBH_MIDI_VERSION / 10000), 0x80), D_PrintHex((uint8_t) (USBH_MIDI_VERSION / 100 % 100), 0x80), D_PrintHex((uint8_t) (USBH_MIDI_VERSION % 100), 0x80), Notify(PSTR("\r\n"), 0x80);
|
||||||
|
#endif
|
||||||
|
|
||||||
//for reconnect
|
//for reconnect
|
||||||
for(uint8_t i=epDataInIndex; i<=epDataOutIndex; i++) {
|
for(uint8_t i=epDataInIndex; i<=epDataOutIndex; i++) {
|
||||||
epInfo[i].epAddr = (i==epDataInIndex) ? 0x81 : 0x01;
|
|
||||||
epInfo[i].maxPktSize = 0;
|
|
||||||
epInfo[i].bmSndToggle = 0;
|
epInfo[i].bmSndToggle = 0;
|
||||||
epInfo[i].bmRcvToggle = 0;
|
epInfo[i].bmRcvToggle = 0;
|
||||||
|
// If you want to retry if you get a NAK response when sending, enable the following:
|
||||||
|
// epInfo[i].bmNakPower = (i==epDataOutIndex) ? 10 : USB_NAK_NOWAIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get memory address of USB device address pool
|
// get memory address of USB device address pool
|
||||||
|
@ -210,30 +210,43 @@ uint8_t USBH_MIDI::Init(uint8_t parent, uint8_t port, bool lowspeed)
|
||||||
bTransferTypeMask = bmUSB_TRANSFER_TYPE;
|
bTransferTypeMask = bmUSB_TRANSFER_TYPE;
|
||||||
setupDeviceSpecific();
|
setupDeviceSpecific();
|
||||||
|
|
||||||
isMidiFound = false;
|
// STEP1: Check if attached device is a MIDI device and fill endpoint data structure
|
||||||
for (uint8_t i=0; i<num_of_conf; i++) {
|
USBTRACE("\r\nSTEP1: MIDI Start\r\n");
|
||||||
rcode = parseConfigDescr(bAddress, i);
|
for(uint8_t i = 0; i < num_of_conf; i++) {
|
||||||
if( rcode )
|
MidiDescParser midiDescParser(this, true); // Check for MIDI device
|
||||||
|
rcode = pUsb->getConfDescr(bAddress, 0, i, &midiDescParser);
|
||||||
|
if(rcode) // Check error code
|
||||||
goto FailGetConfDescr;
|
goto FailGetConfDescr;
|
||||||
if (bNumEP > 1)
|
bNumEP += midiDescParser.getNumEPs();
|
||||||
|
if(bNumEP > 1) {// All endpoints extracted
|
||||||
|
bConfNum = midiDescParser.getConfValue();
|
||||||
break;
|
break;
|
||||||
} // for
|
}
|
||||||
|
}
|
||||||
USBTRACE2("\r\nNumEP:", bNumEP);
|
USBTRACE2("STEP1: MIDI,NumEP:", bNumEP);
|
||||||
|
//Found the MIDI device?
|
||||||
|
if( bNumEP == 1 ){ //Device not found.
|
||||||
|
USBTRACE("MIDI not found.\r\nSTEP2: Attempts vendor specific bulk device\r\n");
|
||||||
|
// STEP2: Check if attached device is a MIDI device and fill endpoint data structure
|
||||||
|
for(uint8_t i = 0; i < num_of_conf; i++) {
|
||||||
|
MidiDescParser midiDescParser(this, false); // Allow all devices, vendor specific class with Bulk transfer
|
||||||
|
rcode = pUsb->getConfDescr(bAddress, 0, i, &midiDescParser);
|
||||||
|
if(rcode) // Check error code
|
||||||
|
goto FailGetConfDescr;
|
||||||
|
bNumEP += midiDescParser.getNumEPs();
|
||||||
|
if(bNumEP > 1) {// All endpoints extracted
|
||||||
|
bConfNum = midiDescParser.getConfValue();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
USBTRACE2("\r\nSTEP2: Vendor,NumEP:", bNumEP);
|
||||||
|
}
|
||||||
|
|
||||||
if( bNumEP < 2 ){ //Device not found.
|
if( bNumEP < 2 ){ //Device not found.
|
||||||
rcode = 0xff;
|
rcode = 0xff;
|
||||||
goto FailGetConfDescr;
|
goto FailGetConfDescr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !isMidiFound ){ //MIDI Device not found. Try last Bulk transfer device
|
|
||||||
USBTRACE("MIDI not found. Attempts bulk device\r\n");
|
|
||||||
epInfo[epDataInIndex].epAddr = epInfo[epDataInIndexVSP].epAddr;
|
|
||||||
epInfo[epDataInIndex].maxPktSize = epInfo[epDataInIndexVSP].maxPktSize;
|
|
||||||
epInfo[epDataOutIndex].epAddr = epInfo[epDataOutIndexVSP].epAddr;
|
|
||||||
epInfo[epDataOutIndex].maxPktSize = epInfo[epDataOutIndexVSP].maxPktSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assign epInfo to epinfo pointer
|
// Assign epInfo to epinfo pointer
|
||||||
rcode = pUsb->setEpInfoEntry(bAddress, 3, epInfo);
|
rcode = pUsb->setEpInfoEntry(bAddress, 3, epInfo);
|
||||||
USBTRACE2("Conf:", bConfNum);
|
USBTRACE2("Conf:", bConfNum);
|
||||||
|
@ -242,9 +255,12 @@ uint8_t USBH_MIDI::Init(uint8_t parent, uint8_t port, bool lowspeed)
|
||||||
|
|
||||||
// Set Configuration Value
|
// Set Configuration Value
|
||||||
rcode = pUsb->setConf(bAddress, 0, bConfNum);
|
rcode = pUsb->setConf(bAddress, 0, bConfNum);
|
||||||
if (rcode) {
|
if (rcode)
|
||||||
goto FailSetConfDescr;
|
goto FailSetConfDescr;
|
||||||
}
|
|
||||||
|
if(pFuncOnInit)
|
||||||
|
pFuncOnInit(); // Call the user function
|
||||||
|
|
||||||
bPollEnable = true;
|
bPollEnable = true;
|
||||||
USBTRACE("Init done.\r\n");
|
USBTRACE("Init done.\r\n");
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -256,92 +272,10 @@ FailSetConfDescr:
|
||||||
return rcode;
|
return rcode;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get and parse config descriptor */
|
|
||||||
uint8_t USBH_MIDI::parseConfigDescr( uint8_t addr, uint8_t conf )
|
|
||||||
{
|
|
||||||
uint8_t buf[ DESC_BUFF_SIZE ];
|
|
||||||
uint8_t* buf_ptr = buf;
|
|
||||||
uint8_t rcode;
|
|
||||||
uint8_t descr_length;
|
|
||||||
uint8_t descr_type;
|
|
||||||
uint16_t total_length;
|
|
||||||
USB_ENDPOINT_DESCRIPTOR *epDesc;
|
|
||||||
bool isMidi = false;
|
|
||||||
|
|
||||||
// get configuration descriptor (get descriptor size only)
|
|
||||||
rcode = pUsb->getConfDescr( addr, 0, 4, conf, buf );
|
|
||||||
if( rcode ){
|
|
||||||
return rcode;
|
|
||||||
}
|
|
||||||
total_length = buf[2] | ((int)buf[3] << 8);
|
|
||||||
if( total_length > DESC_BUFF_SIZE ) { //check if total length is larger than buffer
|
|
||||||
total_length = DESC_BUFF_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get configuration descriptor (all)
|
|
||||||
rcode = pUsb->getConfDescr( addr, 0, total_length, conf, buf ); //get the whole descriptor
|
|
||||||
if( rcode ){
|
|
||||||
return rcode;
|
|
||||||
}
|
|
||||||
|
|
||||||
//parsing descriptors
|
|
||||||
while( buf_ptr < buf + total_length ) {
|
|
||||||
descr_length = *( buf_ptr );
|
|
||||||
descr_type = *( buf_ptr + 1 );
|
|
||||||
switch( descr_type ) {
|
|
||||||
case USB_DESCRIPTOR_CONFIGURATION :
|
|
||||||
bConfNum = buf_ptr[5];
|
|
||||||
break;
|
|
||||||
case USB_DESCRIPTOR_INTERFACE :
|
|
||||||
USBTRACE("\r\nConf:"), D_PrintHex(bConfNum, 0x80);
|
|
||||||
USBTRACE(" Int:"), D_PrintHex(buf_ptr[2], 0x80);
|
|
||||||
USBTRACE(" Alt:"), D_PrintHex(buf_ptr[3], 0x80);
|
|
||||||
USBTRACE(" EPs:"), D_PrintHex(buf_ptr[4], 0x80);
|
|
||||||
USBTRACE(" IntCl:"), D_PrintHex(buf_ptr[5], 0x80);
|
|
||||||
USBTRACE(" IntSubCl:"), D_PrintHex(buf_ptr[6], 0x80);
|
|
||||||
USBTRACE("\r\n");
|
|
||||||
|
|
||||||
if( buf_ptr[5] == USB_CLASS_AUDIO && buf_ptr[6] == USB_SUBCLASS_MIDISTREAMING ) { //p[5]; bInterfaceClass = 1(Audio), p[6]; bInterfaceSubClass = 3(MIDI Streaming)
|
|
||||||
isMidiFound = true; //MIDI device found.
|
|
||||||
isMidi = true;
|
|
||||||
USBTRACE("MIDI Device\r\n");
|
|
||||||
}else{
|
|
||||||
isMidi = false;
|
|
||||||
USBTRACE("No MIDI Device\r\n");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case USB_DESCRIPTOR_ENDPOINT :
|
|
||||||
epDesc = (USB_ENDPOINT_DESCRIPTOR *)buf_ptr;
|
|
||||||
USBTRACE("-EPAddr:"), D_PrintHex(epDesc->bEndpointAddress, 0x80);
|
|
||||||
USBTRACE(" bmAttr:"), D_PrintHex(epDesc->bmAttributes, 0x80);
|
|
||||||
USBTRACE2(" MaxPktSz:", (uint8_t)epDesc->wMaxPacketSize);
|
|
||||||
if ((epDesc->bmAttributes & bTransferTypeMask) == USB_TRANSFER_TYPE_BULK) {//bulk
|
|
||||||
uint8_t index;
|
|
||||||
if( isMidi )
|
|
||||||
index = ((epDesc->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex;
|
|
||||||
else
|
|
||||||
index = ((epDesc->bEndpointAddress & 0x80) == 0x80) ? epDataInIndexVSP : epDataOutIndexVSP;
|
|
||||||
epInfo[index].epAddr = (epDesc->bEndpointAddress & 0x0F);
|
|
||||||
epInfo[index].maxPktSize = (uint8_t)epDesc->wMaxPacketSize;
|
|
||||||
bNumEP ++;
|
|
||||||
#ifdef DEBUG_USB_HOST
|
|
||||||
PrintEndpointDescriptor(epDesc);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}//switch( descr_type
|
|
||||||
buf_ptr += descr_length; //advance buffer pointer
|
|
||||||
}//while( buf_ptr <=...
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Performs a cleanup after failed Init() attempt */
|
/* Performs a cleanup after failed Init() attempt */
|
||||||
uint8_t USBH_MIDI::Release()
|
uint8_t USBH_MIDI::Release()
|
||||||
{
|
{
|
||||||
pUsb->GetAddressPool().FreeAddress(bAddress);
|
pUsb->GetAddressPool().FreeAddress(bAddress);
|
||||||
bNumEP = 1; //must have to be reset to 1
|
|
||||||
bAddress = 0;
|
bAddress = 0;
|
||||||
bPollEnable = false;
|
bPollEnable = false;
|
||||||
readPtr = 0;
|
readPtr = 0;
|
||||||
|
@ -375,7 +309,10 @@ uint8_t USBH_MIDI::RecvData(uint16_t *bytes_rcvd, uint8_t *dataptr)
|
||||||
{
|
{
|
||||||
*bytes_rcvd = (uint16_t)epInfo[epDataInIndex].maxPktSize;
|
*bytes_rcvd = (uint16_t)epInfo[epDataInIndex].maxPktSize;
|
||||||
uint8_t r = pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, bytes_rcvd, dataptr);
|
uint8_t r = pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, bytes_rcvd, dataptr);
|
||||||
|
#ifdef EXTRADEBUG
|
||||||
|
if( r )
|
||||||
|
USBTRACE2("inTransfer():", r);
|
||||||
|
#endif
|
||||||
if( *bytes_rcvd < (MIDI_EVENT_PACKET_SIZE-4)){
|
if( *bytes_rcvd < (MIDI_EVENT_PACKET_SIZE-4)){
|
||||||
dataptr[*bytes_rcvd] = '\0';
|
dataptr[*bytes_rcvd] = '\0';
|
||||||
dataptr[(*bytes_rcvd)+1] = '\0';
|
dataptr[(*bytes_rcvd)+1] = '\0';
|
||||||
|
@ -421,60 +358,52 @@ RecvData_return_from_buffer:
|
||||||
*(outBuf++) = m = recvBuf[readPtr++];
|
*(outBuf++) = m = recvBuf[readPtr++];
|
||||||
*(outBuf++) = recvBuf[readPtr++];
|
*(outBuf++) = recvBuf[readPtr++];
|
||||||
*(outBuf++) = recvBuf[readPtr++];
|
*(outBuf++) = recvBuf[readPtr++];
|
||||||
return lookupMsgSize(m, cin);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Receive raw data from MIDI device */
|
return getMsgSizeFromCin(cin);
|
||||||
uint8_t USBH_MIDI::RecvRawData(uint8_t *outBuf)
|
|
||||||
{
|
|
||||||
return RecvData(outBuf, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Send data to MIDI device */
|
/* Send data to MIDI device */
|
||||||
uint8_t USBH_MIDI::SendData(uint8_t *dataptr, uint8_t nCable)
|
uint8_t USBH_MIDI::SendData(uint8_t *dataptr, uint8_t nCable)
|
||||||
{
|
{
|
||||||
uint8_t buf[4];
|
uint8_t buf[4];
|
||||||
uint8_t msg;
|
uint8_t status = dataptr[0];
|
||||||
|
|
||||||
msg = dataptr[0];
|
uint8_t cin = convertStatus2Cin(status);
|
||||||
// SysEx long message ?
|
if ( status == 0xf0 ) {
|
||||||
if( msg == 0xf0 )
|
// SysEx long message
|
||||||
{
|
|
||||||
return SendSysEx(dataptr, countSysExDataSize(dataptr), nCable);
|
return SendSysEx(dataptr, countSysExDataSize(dataptr), nCable);
|
||||||
}
|
}
|
||||||
|
|
||||||
buf[0] = (nCable << 4) | (msg >> 4);
|
|
||||||
if( msg < 0xf0 ) msg = msg & 0xf0;
|
|
||||||
|
|
||||||
|
|
||||||
//Building USB-MIDI Event Packets
|
//Building USB-MIDI Event Packets
|
||||||
|
buf[0] = (uint8_t)(nCable << 4) | cin;
|
||||||
buf[1] = dataptr[0];
|
buf[1] = dataptr[0];
|
||||||
buf[2] = dataptr[1];
|
|
||||||
buf[3] = dataptr[2];
|
|
||||||
|
|
||||||
switch(lookupMsgSize(msg)) {
|
uint8_t msglen = getMsgSizeFromCin(cin);
|
||||||
|
switch(msglen) {
|
||||||
//3 bytes message
|
//3 bytes message
|
||||||
case 3 :
|
case 3 :
|
||||||
if(msg == 0xf2) {//system common message(SPP)
|
buf[2] = dataptr[1];
|
||||||
buf[0] = (nCable << 4) | 3;
|
buf[3] = dataptr[2];
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
//2 bytes message
|
//2 bytes message
|
||||||
case 2 :
|
case 2 :
|
||||||
if(msg == 0xf1 || msg == 0xf3) {//system common message(MTC/SongSelect)
|
buf[2] = dataptr[1];
|
||||||
buf[0] = (nCable << 4) | 2;
|
|
||||||
}
|
|
||||||
buf[3] = 0;
|
buf[3] = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
//1 byte message
|
//1 byte message
|
||||||
case 1 :
|
case 1 :
|
||||||
default :
|
|
||||||
buf[2] = 0;
|
buf[2] = 0;
|
||||||
buf[3] = 0;
|
buf[3] = 0;
|
||||||
break;
|
break;
|
||||||
|
default :
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
#ifdef EXTRADEBUG
|
||||||
|
//Dump for raw USB-MIDI event packet
|
||||||
|
Notify(PSTR("SendData():"), 0x80), D_PrintHex((buf[0]), 0x80), D_PrintHex((buf[1]), 0x80), D_PrintHex((buf[2]), 0x80), D_PrintHex((buf[3]), 0x80), Notify(PSTR("\r\n"), 0x80);
|
||||||
|
#endif
|
||||||
return pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, 4, buf);
|
return pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, 4, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -495,54 +424,13 @@ void USBH_MIDI::PrintEndpointDescriptor( const USB_ENDPOINT_DESCRIPTOR* ep_ptr )
|
||||||
/*Return */
|
/*Return */
|
||||||
/* 0 : undefined message */
|
/* 0 : undefined message */
|
||||||
/* 0<: Vaild message size(1-3) */
|
/* 0<: Vaild message size(1-3) */
|
||||||
uint8_t USBH_MIDI::lookupMsgSize(uint8_t midiMsg, uint8_t cin)
|
//uint8_t USBH_MIDI::lookupMsgSize(uint8_t midiMsg, uint8_t cin)
|
||||||
|
uint8_t USBH_MIDI::lookupMsgSize(uint8_t status, uint8_t cin)
|
||||||
{
|
{
|
||||||
uint8_t msgSize = 0;
|
if( cin == 0 ){
|
||||||
|
cin = convertStatus2Cin(status);
|
||||||
//SysEx message?
|
|
||||||
cin = cin & 0x0f;
|
|
||||||
if( (cin & 0xc) == 4 ) {
|
|
||||||
if( cin == 4 || cin == 7 ) return 3;
|
|
||||||
if( cin == 6 ) return 2;
|
|
||||||
if( cin == 5 ) return 1;
|
|
||||||
}
|
}
|
||||||
|
return getMsgSizeFromCin(cin);
|
||||||
if( midiMsg < 0xf0 ) midiMsg &= 0xf0;
|
|
||||||
switch(midiMsg) {
|
|
||||||
//3 bytes messages
|
|
||||||
case 0xf2 : //system common message(SPP)
|
|
||||||
case 0x80 : //Note off
|
|
||||||
case 0x90 : //Note on
|
|
||||||
case 0xa0 : //Poly KeyPress
|
|
||||||
case 0xb0 : //Control Change
|
|
||||||
case 0xe0 : //PitchBend Change
|
|
||||||
msgSize = 3;
|
|
||||||
break;
|
|
||||||
|
|
||||||
//2 bytes messages
|
|
||||||
case 0xf1 : //system common message(MTC)
|
|
||||||
case 0xf3 : //system common message(SongSelect)
|
|
||||||
case 0xc0 : //Program Change
|
|
||||||
case 0xd0 : //Channel Pressure
|
|
||||||
msgSize = 2;
|
|
||||||
break;
|
|
||||||
|
|
||||||
//1 byte messages
|
|
||||||
case 0xf8 : //system realtime message
|
|
||||||
case 0xf9 : //system realtime message
|
|
||||||
case 0xfa : //system realtime message
|
|
||||||
case 0xfb : //system realtime message
|
|
||||||
case 0xfc : //system realtime message
|
|
||||||
case 0xfe : //system realtime message
|
|
||||||
case 0xff : //system realtime message
|
|
||||||
msgSize = 1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
//undefine messages
|
|
||||||
default :
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return msgSize;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* SysEx data size counter */
|
/* SysEx data size counter */
|
||||||
|
@ -555,11 +443,9 @@ uint16_t USBH_MIDI::countSysExDataSize(uint8_t *dataptr)
|
||||||
}
|
}
|
||||||
|
|
||||||
//Search terminator(0xf7)
|
//Search terminator(0xf7)
|
||||||
while(*dataptr != 0xf7)
|
while(*dataptr != 0xf7) {
|
||||||
{
|
|
||||||
dataptr++;
|
dataptr++;
|
||||||
c++;
|
c++;
|
||||||
|
|
||||||
//Limiter (default: 256 bytes)
|
//Limiter (default: 256 bytes)
|
||||||
if(c > MIDI_MAX_SYSEX_SIZE){
|
if(c > MIDI_MAX_SYSEX_SIZE){
|
||||||
c = 0;
|
c = 0;
|
||||||
|
@ -575,15 +461,15 @@ uint8_t USBH_MIDI::SendSysEx(uint8_t *dataptr, uint16_t datasize, uint8_t nCable
|
||||||
uint8_t buf[MIDI_EVENT_PACKET_SIZE];
|
uint8_t buf[MIDI_EVENT_PACKET_SIZE];
|
||||||
uint8_t rc = 0;
|
uint8_t rc = 0;
|
||||||
uint16_t n = datasize;
|
uint16_t n = datasize;
|
||||||
uint16_t pktSize = (n*10/3+7)/10*4; //Calculate total USB MIDI packet size
|
|
||||||
uint8_t wptr = 0;
|
uint8_t wptr = 0;
|
||||||
uint8_t maxpkt = epInfo[epDataInIndex].maxPktSize;
|
uint8_t maxpkt = epInfo[epDataInIndex].maxPktSize;
|
||||||
|
|
||||||
if( maxpkt > MIDI_EVENT_PACKET_SIZE ) maxpkt = MIDI_EVENT_PACKET_SIZE;
|
|
||||||
|
|
||||||
USBTRACE("SendSysEx:\r\t");
|
USBTRACE("SendSysEx:\r\t");
|
||||||
USBTRACE2(" Length:\t", datasize);
|
USBTRACE2(" Length:\t", datasize);
|
||||||
|
#ifdef EXTRADEBUG
|
||||||
|
uint16_t pktSize = (n+2)/3; //Calculate total USB MIDI packet size
|
||||||
USBTRACE2(" Total pktSize:\t", pktSize);
|
USBTRACE2(" Total pktSize:\t", pktSize);
|
||||||
|
#endif
|
||||||
|
|
||||||
while(n > 0) {
|
while(n > 0) {
|
||||||
//Byte 0
|
//Byte 0
|
||||||
|
@ -595,14 +481,14 @@ uint8_t USBH_MIDI::SendSysEx(uint8_t *dataptr, uint16_t datasize, uint8_t nCable
|
||||||
buf[wptr++] = *(dataptr++);
|
buf[wptr++] = *(dataptr++);
|
||||||
buf[wptr++] = 0x00;
|
buf[wptr++] = 0x00;
|
||||||
buf[wptr++] = 0x00;
|
buf[wptr++] = 0x00;
|
||||||
n = n - 1;
|
n = 0;
|
||||||
break;
|
break;
|
||||||
case 2 :
|
case 2 :
|
||||||
buf[wptr++] = (nCable << 4) | 0x6; //x6 SysEx ends with following two bytes.
|
buf[wptr++] = (nCable << 4) | 0x6; //x6 SysEx ends with following two bytes.
|
||||||
buf[wptr++] = *(dataptr++);
|
buf[wptr++] = *(dataptr++);
|
||||||
buf[wptr++] = *(dataptr++);
|
buf[wptr++] = *(dataptr++);
|
||||||
buf[wptr++] = 0x00;
|
buf[wptr++] = 0x00;
|
||||||
n = n - 2;
|
n = 0;
|
||||||
break;
|
break;
|
||||||
case 3 :
|
case 3 :
|
||||||
buf[wptr] = (nCable << 4) | 0x7; //x7 SysEx ends with following three bytes.
|
buf[wptr] = (nCable << 4) | 0x7; //x7 SysEx ends with following three bytes.
|
||||||
|
@ -621,19 +507,12 @@ uint8_t USBH_MIDI::SendSysEx(uint8_t *dataptr, uint16_t datasize, uint8_t nCable
|
||||||
if( (rc = pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, wptr, buf)) != 0 ){
|
if( (rc = pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, wptr, buf)) != 0 ){
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
wptr = 0; //rewind data pointer
|
wptr = 0; //rewind write pointer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return(rc);
|
return(rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Send raw data to MIDI device */
|
|
||||||
uint8_t USBH_MIDI::SendRawData(uint16_t bytes_send, uint8_t *dataptr)
|
|
||||||
{
|
|
||||||
return pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, bytes_send, dataptr);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t USBH_MIDI::extractSysExData(uint8_t *p, uint8_t *buf)
|
uint8_t USBH_MIDI::extractSysExData(uint8_t *p, uint8_t *buf)
|
||||||
{
|
{
|
||||||
uint8_t rc = 0;
|
uint8_t rc = 0;
|
||||||
|
@ -664,3 +543,150 @@ uint8_t USBH_MIDI::extractSysExData(uint8_t *p, uint8_t *buf)
|
||||||
}
|
}
|
||||||
return(rc);
|
return(rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Configuration Descriptor Parser
|
||||||
|
// Copied from confdescparser.h and modifiy.
|
||||||
|
MidiDescParser::MidiDescParser(UsbMidiConfigXtracter *xtractor, bool modeMidi) :
|
||||||
|
theXtractor(xtractor),
|
||||||
|
stateParseDescr(0),
|
||||||
|
dscrLen(0),
|
||||||
|
dscrType(0),
|
||||||
|
nEPs(0),
|
||||||
|
isMidiSearch(modeMidi){
|
||||||
|
theBuffer.pValue = varBuffer;
|
||||||
|
valParser.Initialize(&theBuffer);
|
||||||
|
theSkipper.Initialize(&theBuffer);
|
||||||
|
}
|
||||||
|
void MidiDescParser::Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset __attribute__((unused))) {
|
||||||
|
uint16_t cntdn = (uint16_t)len;
|
||||||
|
uint8_t *p = (uint8_t*)pbuf;
|
||||||
|
|
||||||
|
while(cntdn)
|
||||||
|
if(!ParseDescriptor(&p, &cntdn))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MidiDescParser::ParseDescriptor(uint8_t **pp, uint16_t *pcntdn) {
|
||||||
|
USB_CONFIGURATION_DESCRIPTOR* ucd = reinterpret_cast<USB_CONFIGURATION_DESCRIPTOR*>(varBuffer);
|
||||||
|
USB_INTERFACE_DESCRIPTOR* uid = reinterpret_cast<USB_INTERFACE_DESCRIPTOR*>(varBuffer);
|
||||||
|
switch(stateParseDescr) {
|
||||||
|
case 0:
|
||||||
|
theBuffer.valueSize = 2;
|
||||||
|
valParser.Initialize(&theBuffer);
|
||||||
|
stateParseDescr = 1;
|
||||||
|
// fall through
|
||||||
|
case 1:
|
||||||
|
if(!valParser.Parse(pp, pcntdn))
|
||||||
|
return false;
|
||||||
|
dscrLen = *((uint8_t*)theBuffer.pValue);
|
||||||
|
dscrType = *((uint8_t*)theBuffer.pValue + 1);
|
||||||
|
stateParseDescr = 2;
|
||||||
|
// fall through
|
||||||
|
case 2:
|
||||||
|
// This is a sort of hack. Assuming that two bytes are all ready in the buffer
|
||||||
|
// the pointer is positioned two bytes ahead in order for the rest of descriptor
|
||||||
|
// to be read right after the size and the type fields.
|
||||||
|
// This should be used carefully. varBuffer should be used directly to handle data
|
||||||
|
// in the buffer.
|
||||||
|
theBuffer.pValue = varBuffer + 2;
|
||||||
|
stateParseDescr = 3;
|
||||||
|
// fall through
|
||||||
|
case 3:
|
||||||
|
switch(dscrType) {
|
||||||
|
case USB_DESCRIPTOR_INTERFACE:
|
||||||
|
isGoodInterface = false;
|
||||||
|
break;
|
||||||
|
case USB_DESCRIPTOR_CONFIGURATION:
|
||||||
|
case USB_DESCRIPTOR_ENDPOINT:
|
||||||
|
case HID_DESCRIPTOR_HID:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
theBuffer.valueSize = dscrLen - 2;
|
||||||
|
valParser.Initialize(&theBuffer);
|
||||||
|
stateParseDescr = 4;
|
||||||
|
// fall through
|
||||||
|
case 4:
|
||||||
|
switch(dscrType) {
|
||||||
|
case USB_DESCRIPTOR_CONFIGURATION:
|
||||||
|
if(!valParser.Parse(pp, pcntdn))
|
||||||
|
return false;
|
||||||
|
confValue = ucd->bConfigurationValue;
|
||||||
|
break;
|
||||||
|
case USB_DESCRIPTOR_INTERFACE:
|
||||||
|
if(!valParser.Parse(pp, pcntdn))
|
||||||
|
return false;
|
||||||
|
USBTRACE("Interface descriptor:\r\n");
|
||||||
|
USBTRACE2(" Inf#:\t\t", uid->bInterfaceNumber);
|
||||||
|
USBTRACE2(" Alt:\t\t", uid->bAlternateSetting);
|
||||||
|
USBTRACE2(" EPs:\t\t", uid->bNumEndpoints);
|
||||||
|
USBTRACE2(" IntCl:\t\t", uid->bInterfaceClass);
|
||||||
|
USBTRACE2(" IntSubcl:\t", uid->bInterfaceSubClass);
|
||||||
|
USBTRACE2(" Protocol:\t", uid->bInterfaceProtocol);
|
||||||
|
// MIDI check mode ?
|
||||||
|
if( isMidiSearch ){ //true: MIDI Streaming, false: ALL
|
||||||
|
if( uid->bInterfaceClass == USB_CLASS_AUDIO && uid->bInterfaceSubClass == USB_SUBCLASS_MIDISTREAMING ) {
|
||||||
|
// MIDI found.
|
||||||
|
USBTRACE("+MIDI found\r\n\r\n");
|
||||||
|
}else{
|
||||||
|
USBTRACE("-MIDI not found\r\n\r\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
isGoodInterface = true;
|
||||||
|
// Initialize the counter if no two endpoints can be found in one interface.
|
||||||
|
if(nEPs < 2)
|
||||||
|
// reset endpoint counter
|
||||||
|
nEPs = 0;
|
||||||
|
break;
|
||||||
|
case USB_DESCRIPTOR_ENDPOINT:
|
||||||
|
if(!valParser.Parse(pp, pcntdn))
|
||||||
|
return false;
|
||||||
|
if(isGoodInterface && nEPs < 2){
|
||||||
|
USBTRACE(">Extracting endpoint\r\n");
|
||||||
|
if( theXtractor->EndpointXtract(confValue, 0, 0, 0, (USB_ENDPOINT_DESCRIPTOR*)varBuffer) )
|
||||||
|
nEPs++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if(!theSkipper.Skip(pp, pcntdn, dscrLen - 2))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
theBuffer.pValue = varBuffer;
|
||||||
|
stateParseDescr = 0;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Extracts endpoint information from config descriptor */
|
||||||
|
bool USBH_MIDI::EndpointXtract(uint8_t conf __attribute__((unused)),
|
||||||
|
uint8_t iface __attribute__((unused)),
|
||||||
|
uint8_t alt __attribute__((unused)),
|
||||||
|
uint8_t proto __attribute__((unused)),
|
||||||
|
const USB_ENDPOINT_DESCRIPTOR *pep)
|
||||||
|
{
|
||||||
|
uint8_t index;
|
||||||
|
|
||||||
|
#ifdef DEBUG_USB_HOST
|
||||||
|
PrintEndpointDescriptor(pep);
|
||||||
|
#endif
|
||||||
|
// Is the endpoint transfer type bulk?
|
||||||
|
if((pep->bmAttributes & bTransferTypeMask) == USB_TRANSFER_TYPE_BULK) {
|
||||||
|
USBTRACE("+valid EP found.\r\n");
|
||||||
|
index = (pep->bEndpointAddress & 0x80) == 0x80 ? epDataInIndex : epDataOutIndex;
|
||||||
|
} else {
|
||||||
|
USBTRACE("-No valid EP found.\r\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill the rest of endpoint data structure
|
||||||
|
epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
|
||||||
|
// The maximum packet size for the USB Host Shield 2.0 library is 64 bytes.
|
||||||
|
if(pep->wMaxPacketSize > MIDI_EVENT_PACKET_SIZE) {
|
||||||
|
epInfo[index].maxPktSize = MIDI_EVENT_PACKET_SIZE;
|
||||||
|
} else {
|
||||||
|
epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
86
usbh_midi.h
86
usbh_midi.h
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
*******************************************************************************
|
*******************************************************************************
|
||||||
* USB-MIDI class driver for USB Host Shield 2.0 Library
|
* USB-MIDI class driver for USB Host Shield 2.0 Library
|
||||||
* Copyright (c) 2012-2018 Yuuichi Akagawa
|
* Copyright (c) 2012-2021 Yuuichi Akagawa
|
||||||
*
|
*
|
||||||
* Idea from LPK25 USB-MIDI to Serial MIDI converter
|
* Idea from LPK25 USB-MIDI to Serial MIDI converter
|
||||||
* by Collin Cunningham - makezine.com, narbotic.com
|
* by Collin Cunningham - makezine.com, narbotic.com
|
||||||
|
@ -26,31 +26,67 @@
|
||||||
|
|
||||||
#if !defined(_USBH_MIDI_H_)
|
#if !defined(_USBH_MIDI_H_)
|
||||||
#define _USBH_MIDI_H_
|
#define _USBH_MIDI_H_
|
||||||
//#define DEBUG_USB_HOST
|
|
||||||
#include "Usb.h"
|
#include "Usb.h"
|
||||||
|
|
||||||
#define MIDI_MAX_ENDPOINTS 5 //endpoint 0, bulk_IN(MIDI), bulk_OUT(MIDI), bulk_IN(VSP), bulk_OUT(VSP)
|
#define USBH_MIDI_VERSION 600
|
||||||
|
#define MIDI_MAX_ENDPOINTS 3 //endpoint 0, bulk_IN(MIDI), bulk_OUT(MIDI)
|
||||||
#define USB_SUBCLASS_MIDISTREAMING 3
|
#define USB_SUBCLASS_MIDISTREAMING 3
|
||||||
#define DESC_BUFF_SIZE 256
|
|
||||||
#define MIDI_EVENT_PACKET_SIZE 64
|
#define MIDI_EVENT_PACKET_SIZE 64
|
||||||
#define MIDI_MAX_SYSEX_SIZE 256
|
#define MIDI_MAX_SYSEX_SIZE 256
|
||||||
class USBH_MIDI;
|
|
||||||
|
|
||||||
class USBH_MIDI : public USBDeviceConfig
|
namespace _ns_USBH_MIDI {
|
||||||
|
const uint8_t cin2len[] PROGMEM = {0, 0, 2, 3, 3, 1, 2, 3, 3, 3, 3, 3, 2, 2, 3, 1};
|
||||||
|
const uint8_t sys2cin[] PROGMEM = {0, 2, 3, 2, 0, 0, 5, 0, 0xf, 0, 0xf, 0xf, 0xf, 0, 0xf, 0xf};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Endpoint Descriptor extracter Class
|
||||||
|
class UsbMidiConfigXtracter {
|
||||||
|
public:
|
||||||
|
//virtual void ConfigXtract(const USB_CONFIGURATION_DESCRIPTOR *conf) = 0;
|
||||||
|
//virtual void InterfaceXtract(uint8_t conf, const USB_INTERFACE_DESCRIPTOR *iface) = 0;
|
||||||
|
|
||||||
|
virtual bool EndpointXtract(uint8_t conf __attribute__((unused)), uint8_t iface __attribute__((unused)), uint8_t alt __attribute__((unused)), uint8_t proto __attribute__((unused)), const USB_ENDPOINT_DESCRIPTOR *ep __attribute__((unused))) {
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
// Configuration Descriptor Parser Class
|
||||||
|
class MidiDescParser : public USBReadParser {
|
||||||
|
UsbMidiConfigXtracter *theXtractor;
|
||||||
|
MultiValueBuffer theBuffer;
|
||||||
|
MultiByteValueParser valParser;
|
||||||
|
ByteSkipper theSkipper;
|
||||||
|
uint8_t varBuffer[16 /*sizeof(USB_CONFIGURATION_DESCRIPTOR)*/];
|
||||||
|
|
||||||
|
uint8_t stateParseDescr; // ParseDescriptor state
|
||||||
|
|
||||||
|
uint8_t dscrLen; // Descriptor length
|
||||||
|
uint8_t dscrType; // Descriptor type
|
||||||
|
uint8_t nEPs; // number of valid endpoint
|
||||||
|
bool isMidiSearch; //Configuration mode true: MIDI, false: Vendor specific
|
||||||
|
|
||||||
|
bool isGoodInterface; // Apropriate interface flag
|
||||||
|
uint8_t confValue; // Configuration value
|
||||||
|
|
||||||
|
bool ParseDescriptor(uint8_t **pp, uint16_t *pcntdn);
|
||||||
|
|
||||||
|
public:
|
||||||
|
MidiDescParser(UsbMidiConfigXtracter *xtractor, bool modeMidi);
|
||||||
|
void Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset);
|
||||||
|
inline uint8_t getConfValue() { return confValue; };
|
||||||
|
inline uint8_t getNumEPs() { return nEPs; };
|
||||||
|
};
|
||||||
|
|
||||||
|
/** This class implements support for a MIDI device. */
|
||||||
|
class USBH_MIDI : public USBDeviceConfig, public UsbMidiConfigXtracter
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
static const uint8_t epDataInIndex; // DataIn endpoint index(MIDI)
|
static const uint8_t epDataInIndex = 1; // DataIn endpoint index(MIDI)
|
||||||
static const uint8_t epDataOutIndex; // DataOUT endpoint index(MIDI)
|
static const uint8_t epDataOutIndex= 2; // DataOUT endpoint index(MIDI)
|
||||||
static const uint8_t epDataInIndexVSP; // DataIn endpoint index(Vendor Specific Protocl)
|
|
||||||
static const uint8_t epDataOutIndexVSP; // DataOUT endpoint index(Vendor Specific Protocl)
|
|
||||||
|
|
||||||
/* mandatory members */
|
/* mandatory members */
|
||||||
USB *pUsb;
|
USB *pUsb;
|
||||||
uint8_t bAddress;
|
uint8_t bAddress;
|
||||||
uint8_t bConfNum; // configuration number
|
|
||||||
uint8_t bNumEP; // total number of EP in the configuration
|
|
||||||
bool bPollEnable;
|
bool bPollEnable;
|
||||||
bool isMidiFound;
|
|
||||||
uint16_t pid, vid; // ProductID, VendorID
|
uint16_t pid, vid; // ProductID, VendorID
|
||||||
uint8_t bTransferTypeMask;
|
uint8_t bTransferTypeMask;
|
||||||
/* Endpoint data structure */
|
/* Endpoint data structure */
|
||||||
|
@ -59,27 +95,36 @@ protected:
|
||||||
uint8_t recvBuf[MIDI_EVENT_PACKET_SIZE];
|
uint8_t recvBuf[MIDI_EVENT_PACKET_SIZE];
|
||||||
uint8_t readPtr;
|
uint8_t readPtr;
|
||||||
|
|
||||||
uint8_t parseConfigDescr(uint8_t addr, uint8_t conf);
|
|
||||||
uint16_t countSysExDataSize(uint8_t *dataptr);
|
uint16_t countSysExDataSize(uint8_t *dataptr);
|
||||||
void setupDeviceSpecific();
|
void setupDeviceSpecific();
|
||||||
|
inline uint8_t convertStatus2Cin(uint8_t status) {
|
||||||
|
return ((status < 0xf0) ? ((status & 0xF0) >> 4) : pgm_read_byte_near(_ns_USBH_MIDI::sys2cin + (status & 0x0F)));
|
||||||
|
};
|
||||||
|
inline uint8_t getMsgSizeFromCin(uint8_t cin) {
|
||||||
|
return pgm_read_byte_near(_ns_USBH_MIDI::cin2len + cin);
|
||||||
|
};
|
||||||
|
|
||||||
|
/* UsbConfigXtracter implementation */
|
||||||
|
bool EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);
|
||||||
|
|
||||||
#ifdef DEBUG_USB_HOST
|
#ifdef DEBUG_USB_HOST
|
||||||
void PrintEndpointDescriptor( const USB_ENDPOINT_DESCRIPTOR* ep_ptr );
|
void PrintEndpointDescriptor( const USB_ENDPOINT_DESCRIPTOR* ep_ptr );
|
||||||
#endif
|
#endif
|
||||||
public:
|
public:
|
||||||
USBH_MIDI(USB *p);
|
USBH_MIDI(USB *p);
|
||||||
// Misc functions
|
// Misc functions
|
||||||
operator bool() { return (pUsb->getUsbTaskState()==USB_STATE_RUNNING); }
|
operator bool() { return (bPollEnable); }
|
||||||
uint16_t idVendor() { return vid; }
|
uint16_t idVendor() { return vid; }
|
||||||
uint16_t idProduct() { return pid; }
|
uint16_t idProduct() { return pid; }
|
||||||
// Methods for recieving and sending data
|
// Methods for recieving and sending data
|
||||||
uint8_t RecvData(uint16_t *bytes_rcvd, uint8_t *dataptr);
|
uint8_t RecvData(uint16_t *bytes_rcvd, uint8_t *dataptr);
|
||||||
uint8_t RecvData(uint8_t *outBuf, bool isRaw=false);
|
uint8_t RecvData(uint8_t *outBuf, bool isRaw=false);
|
||||||
uint8_t RecvRawData(uint8_t *outBuf);
|
inline uint8_t RecvRawData(uint8_t *outBuf) { return RecvData(outBuf, true); };
|
||||||
uint8_t SendData(uint8_t *dataptr, uint8_t nCable=0);
|
uint8_t SendData(uint8_t *dataptr, uint8_t nCable=0);
|
||||||
|
inline uint8_t SendRawData(uint16_t bytes_send, uint8_t *dataptr) { return pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, bytes_send, dataptr); };
|
||||||
uint8_t lookupMsgSize(uint8_t midiMsg, uint8_t cin=0);
|
uint8_t lookupMsgSize(uint8_t midiMsg, uint8_t cin=0);
|
||||||
uint8_t SendSysEx(uint8_t *dataptr, uint16_t datasize, uint8_t nCable=0);
|
uint8_t SendSysEx(uint8_t *dataptr, uint16_t datasize, uint8_t nCable=0);
|
||||||
uint8_t extractSysExData(uint8_t *p, uint8_t *buf);
|
uint8_t extractSysExData(uint8_t *p, uint8_t *buf);
|
||||||
uint8_t SendRawData(uint16_t bytes_send, uint8_t *dataptr);
|
|
||||||
// backward compatibility functions
|
// backward compatibility functions
|
||||||
inline uint8_t RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr) { return RecvData(bytes_rcvd, dataptr); };
|
inline uint8_t RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr) { return RecvData(bytes_rcvd, dataptr); };
|
||||||
inline uint8_t RcvData(uint8_t *outBuf) { return RecvData(outBuf); };
|
inline uint8_t RcvData(uint8_t *outBuf) { return RecvData(outBuf); };
|
||||||
|
@ -88,5 +133,12 @@ public:
|
||||||
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
|
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
|
||||||
virtual uint8_t Release();
|
virtual uint8_t Release();
|
||||||
virtual uint8_t GetAddress() { return bAddress; };
|
virtual uint8_t GetAddress() { return bAddress; };
|
||||||
|
|
||||||
|
void attachOnInit(void (*funcOnInit)(void)) {
|
||||||
|
pFuncOnInit = funcOnInit;
|
||||||
|
};
|
||||||
|
private:
|
||||||
|
void (*pFuncOnInit)(void) = nullptr; // Pointer to function called in onInit()
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //_USBH_MIDI_H_
|
#endif //_USBH_MIDI_H_
|
||||||
|
|
Loading…
Reference in a new issue