diff --git a/README.md b/README.md
index 3d230cf6..f053fffb 100644
--- a/README.md
+++ b/README.md
@@ -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_multi.ino](examples/USBH_MIDI/USB_MIDI_converter_multi/USB_MIDI_converter_multi.ino)
-For information see the following page: .
+For more information see : .
### [amBX Library](AMBX.cpp)
diff --git a/examples/USBH_MIDI/USBH_MIDI_dump/USBH_MIDI_dump.ino b/examples/USBH_MIDI/USBH_MIDI_dump/USBH_MIDI_dump.ino
index 377a5a63..645131ad 100644
--- a/examples/USBH_MIDI/USBH_MIDI_dump/USBH_MIDI_dump.ino
+++ b/examples/USBH_MIDI/USBH_MIDI_dump/USBH_MIDI_dump.ino
@@ -1,7 +1,7 @@
/*
*******************************************************************************
* 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
* https://github.com/felis/USB_Host_Shield_2.0
@@ -13,35 +13,37 @@
#include
#include
-// Satisfy the IDE, which needs to see the include statment in the ino too.
-#ifdef dobogusinclude
-#include
-#endif
-#include
-
USB Usb;
-//USBHub Hub(&Usb);
+USBHub Hub(&Usb);
USBH_MIDI Midi(&Usb);
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()
{
- vid = pid = 0;
Serial.begin(115200);
if (Usb.Init() == -1) {
while (1); //halt
}//if (Usb.Init() == -1...
delay( 200 );
+
+ // Register onInit() function
+ Midi.attachOnInit(onInit);
}
void loop()
{
Usb.Task();
- //uint32_t t1 = (uint32_t)micros();
if ( Midi ) {
MIDI_poll();
}
@@ -50,23 +52,16 @@ void loop()
// Poll USB MIDI Controler and send to serial MIDI
void MIDI_poll()
{
- char buf[20];
- uint8_t bufMidi[64];
+ char buf[16];
+ uint8_t bufMidi[MIDI_EVENT_PACKET_SIZE];
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 ) {
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(rcvd);
- Serial.print(':');
- for (int i = 0; i < 64; i++) {
+
+ for (int i = 0; i < MIDI_EVENT_PACKET_SIZE; i++) {
sprintf(buf, " %02X", bufMidi[i]);
Serial.print(buf);
}
diff --git a/examples/USBH_MIDI/USB_MIDI_converter/USB_MIDI_converter.ino b/examples/USBH_MIDI/USB_MIDI_converter/USB_MIDI_converter.ino
index 1f5d1561..4f988183 100644
--- a/examples/USBH_MIDI/USB_MIDI_converter/USB_MIDI_converter.ino
+++ b/examples/USBH_MIDI/USB_MIDI_converter/USB_MIDI_converter.ino
@@ -1,7 +1,7 @@
/*
*******************************************************************************
* 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
* by Collin Cunningham - makezine.com, narbotic.com
@@ -13,12 +13,6 @@
#include
#include
-// Satisfy the IDE, which needs to see the include statment in the ino too.
-#ifdef dobogusinclude
-#include
-#endif
-#include
-
#ifdef USBCON
#define _MIDI_SERIAL_PORT Serial1
#else
@@ -40,7 +34,6 @@ USB Usb;
USBH_MIDI Midi(&Usb);
void MIDI_poll();
-void doDelay(uint32_t t1, uint32_t t2, uint32_t delayTime);
void setup()
{
@@ -55,12 +48,12 @@ void setup()
void loop()
{
Usb.Task();
- uint32_t t1 = (uint32_t)micros();
+
if ( Midi ) {
MIDI_poll();
}
- //delay(1ms)
- doDelay(t1, (uint32_t)micros(), 1000);
+ //delay(1ms) if you want
+ //delayMicroseconds(1000);
}
// Poll USB MIDI Controler and send to serial MIDI
@@ -79,14 +72,3 @@ void MIDI_poll()
}
} 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);
- }
-}
diff --git a/examples/USBH_MIDI/USB_MIDI_converter_multi/USB_MIDI_converter_multi.ino b/examples/USBH_MIDI/USB_MIDI_converter_multi/USB_MIDI_converter_multi.ino
index 5c841a0c..ebbf63ad 100644
--- a/examples/USBH_MIDI/USB_MIDI_converter_multi/USB_MIDI_converter_multi.ino
+++ b/examples/USBH_MIDI/USB_MIDI_converter_multi/USB_MIDI_converter_multi.ino
@@ -1,7 +1,7 @@
/*
*******************************************************************************
* 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
* by Collin Cunningham - makezine.com, narbotic.com
@@ -13,12 +13,6 @@
#include
#include
-// Satisfy the IDE, which needs to see the include statment in the ino too.
-#ifdef dobogusinclude
-#include
-#endif
-#include
-
#ifdef USBCON
#define _MIDI_SERIAL_PORT Serial1
#else
@@ -41,8 +35,7 @@ USBHub Hub1(&Usb);
USBH_MIDI Midi1(&Usb);
USBH_MIDI Midi2(&Usb);
-void MIDI_poll();
-void doDelay(uint32_t t1, uint32_t t2, uint32_t delayTime);
+void MIDI_poll(USBH_MIDI &Midi);
void setup()
{
@@ -57,15 +50,15 @@ void setup()
void loop()
{
Usb.Task();
- uint32_t t1 = (uint32_t)micros();
+
if ( Midi1 ) {
MIDI_poll(Midi1);
}
if ( Midi2 ) {
MIDI_poll(Midi2);
}
- //delay(1ms)
- doDelay(t1, (uint32_t)micros(), 1000);
+ //delay(1ms) if you want
+ //delayMicroseconds(1000);
}
// Poll USB MIDI Controler and send to serial MIDI
diff --git a/examples/USBH_MIDI/bidirectional_converter/bidirectional_converter.ino b/examples/USBH_MIDI/bidirectional_converter/bidirectional_converter.ino
index 18c7cc8a..ece2774f 100644
--- a/examples/USBH_MIDI/bidirectional_converter/bidirectional_converter.ino
+++ b/examples/USBH_MIDI/bidirectional_converter/bidirectional_converter.ino
@@ -16,12 +16,6 @@
#include
#include
-// Satisfy the IDE, which needs to see the include statment in the ino too.
-#ifdef dobogusinclude
-#include
-#endif
-#include
-
//Arduino MIDI library v4.2 compatibility
#ifdef MIDI_CREATE_DEFAULT_INSTANCE
MIDI_CREATE_DEFAULT_INSTANCE();
@@ -44,7 +38,6 @@ MIDI_CREATE_DEFAULT_INSTANCE();
//////////////////////////
USB Usb;
-//USBHub Hub1(&Usb);
USBH_MIDI Midi(&Usb);
void MIDI_poll();
diff --git a/examples/USBH_MIDI/eVY1_sample/eVY1_sample.ino b/examples/USBH_MIDI/eVY1_sample/eVY1_sample.ino
index c0e2afab..0b4e0bed 100644
--- a/examples/USBH_MIDI/eVY1_sample/eVY1_sample.ino
+++ b/examples/USBH_MIDI/eVY1_sample/eVY1_sample.ino
@@ -1,7 +1,7 @@
/*
*******************************************************************************
* 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.
*******************************************************************************
@@ -9,12 +9,6 @@
#include
#include
-// Satisfy the IDE, which needs to see the include statment in the ino too.
-#ifdef dobogusinclude
-#include
-#endif
-#include
-
USB Usb;
//USBHub Hub(&Usb);
USBH_MIDI Midi(&Usb);
@@ -23,7 +17,6 @@ void MIDI_poll();
void noteOn(uint8_t note);
void noteOff(uint8_t note);
-uint16_t pid, vid;
uint8_t exdata[] = {
0xf0, 0x43, 0x79, 0x09, 0x00, 0x50, 0x10,
'k', ' ', 'o', ',', //Ko
@@ -34,15 +27,22 @@ uint8_t exdata[] = {
0x00, 0xf7
};
+void onInit()
+{
+ // Send Phonetic symbols via SysEx
+ Midi.SendSysEx(exdata, sizeof(exdata));
+ delay(500);
+}
+
void setup()
{
- vid = pid = 0;
- Serial.begin(115200);
-
if (Usb.Init() == -1) {
while (1); //halt
}//if (Usb.Init() == -1...
delay( 200 );
+
+ // Register onInit() function
+ Midi.attachOnInit(onInit);
}
void loop()
@@ -61,13 +61,6 @@ void loop()
void MIDI_poll()
{
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);
}
diff --git a/usbh_midi.cpp b/usbh_midi.cpp
index 4de21770..e7bfcaf1 100644
--- a/usbh_midi.cpp
+++ b/usbh_midi.cpp
@@ -1,7 +1,7 @@
/*
*******************************************************************************
* 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
* by Collin Cunningham - makezine.com, narbotic.com
@@ -25,6 +25,9 @@
*/
#include "usbh_midi.h"
+// To enable serial debugging see "settings.h"
+//#define EXTRADEBUG // Uncomment to get even more debugging data
+
//////////////////////////
// MIDI MESAGES
// midi.org/techspecs/
@@ -79,24 +82,16 @@
//| 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) :
pUsb(p),
bAddress(0),
-bNumEP(1),
bPollEnable(false),
-isMidiFound(false),
readPtr(0) {
// initialize endpoint data structures
for(uint8_t i=0; igetConfDescr(bAddress, 0, i, &midiDescParser);
+ if(rcode) // Check error code
goto FailGetConfDescr;
- if (bNumEP > 1)
+ bNumEP += midiDescParser.getNumEPs();
+ if(bNumEP > 1) {// All endpoints extracted
+ bConfNum = midiDescParser.getConfValue();
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.
rcode = 0xff;
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
rcode = pUsb->setEpInfoEntry(bAddress, 3, epInfo);
USBTRACE2("Conf:", bConfNum);
@@ -242,9 +255,12 @@ uint8_t USBH_MIDI::Init(uint8_t parent, uint8_t port, bool lowspeed)
// Set Configuration Value
rcode = pUsb->setConf(bAddress, 0, bConfNum);
- if (rcode) {
+ if (rcode)
goto FailSetConfDescr;
- }
+
+ if(pFuncOnInit)
+ pFuncOnInit(); // Call the user function
+
bPollEnable = true;
USBTRACE("Init done.\r\n");
return 0;
@@ -256,92 +272,10 @@ FailSetConfDescr:
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 */
uint8_t USBH_MIDI::Release()
{
pUsb->GetAddressPool().FreeAddress(bAddress);
- bNumEP = 1; //must have to be reset to 1
bAddress = 0;
bPollEnable = false;
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;
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)){
dataptr[*bytes_rcvd] = '\0';
dataptr[(*bytes_rcvd)+1] = '\0';
@@ -421,60 +358,52 @@ RecvData_return_from_buffer:
*(outBuf++) = m = recvBuf[readPtr++];
*(outBuf++) = recvBuf[readPtr++];
*(outBuf++) = recvBuf[readPtr++];
- return lookupMsgSize(m, cin);
-}
-/* Receive raw data from MIDI device */
-uint8_t USBH_MIDI::RecvRawData(uint8_t *outBuf)
-{
- return RecvData(outBuf, true);
+ return getMsgSizeFromCin(cin);
}
/* Send data to MIDI device */
uint8_t USBH_MIDI::SendData(uint8_t *dataptr, uint8_t nCable)
{
uint8_t buf[4];
- uint8_t msg;
+ uint8_t status = dataptr[0];
- msg = dataptr[0];
- // SysEx long message ?
- if( msg == 0xf0 )
- {
+ uint8_t cin = convertStatus2Cin(status);
+ if ( status == 0xf0 ) {
+ // SysEx long message
return SendSysEx(dataptr, countSysExDataSize(dataptr), nCable);
}
- buf[0] = (nCable << 4) | (msg >> 4);
- if( msg < 0xf0 ) msg = msg & 0xf0;
-
-
//Building USB-MIDI Event Packets
+ buf[0] = (uint8_t)(nCable << 4) | cin;
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
case 3 :
- if(msg == 0xf2) {//system common message(SPP)
- buf[0] = (nCable << 4) | 3;
- }
+ buf[2] = dataptr[1];
+ buf[3] = dataptr[2];
break;
//2 bytes message
case 2 :
- if(msg == 0xf1 || msg == 0xf3) {//system common message(MTC/SongSelect)
- buf[0] = (nCable << 4) | 2;
- }
+ buf[2] = dataptr[1];
buf[3] = 0;
break;
//1 byte message
case 1 :
- default :
buf[2] = 0;
buf[3] = 0;
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);
}
@@ -495,54 +424,13 @@ void USBH_MIDI::PrintEndpointDescriptor( const USB_ENDPOINT_DESCRIPTOR* ep_ptr )
/*Return */
/* 0 : undefined message */
/* 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;
-
- //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;
+ if( cin == 0 ){
+ cin = convertStatus2Cin(status);
}
-
- 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;
+ return getMsgSizeFromCin(cin);
}
/* SysEx data size counter */
@@ -555,11 +443,9 @@ uint16_t USBH_MIDI::countSysExDataSize(uint8_t *dataptr)
}
//Search terminator(0xf7)
- while(*dataptr != 0xf7)
- {
+ while(*dataptr != 0xf7) {
dataptr++;
c++;
-
//Limiter (default: 256 bytes)
if(c > MIDI_MAX_SYSEX_SIZE){
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 rc = 0;
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 maxpkt = epInfo[epDataInIndex].maxPktSize;
- if( maxpkt > MIDI_EVENT_PACKET_SIZE ) maxpkt = MIDI_EVENT_PACKET_SIZE;
-
USBTRACE("SendSysEx:\r\t");
USBTRACE2(" Length:\t", datasize);
+#ifdef EXTRADEBUG
+ uint16_t pktSize = (n+2)/3; //Calculate total USB MIDI packet size
USBTRACE2(" Total pktSize:\t", pktSize);
+#endif
while(n > 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++] = 0x00;
buf[wptr++] = 0x00;
- n = n - 1;
+ n = 0;
break;
case 2 :
buf[wptr++] = (nCable << 4) | 0x6; //x6 SysEx ends with following two bytes.
buf[wptr++] = *(dataptr++);
buf[wptr++] = *(dataptr++);
buf[wptr++] = 0x00;
- n = n - 2;
+ n = 0;
break;
case 3 :
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 ){
break;
}
- wptr = 0; //rewind data pointer
+ wptr = 0; //rewind write pointer
}
}
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 rc = 0;
@@ -664,3 +543,150 @@ uint8_t USBH_MIDI::extractSysExData(uint8_t *p, uint8_t *buf)
}
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(varBuffer);
+ USB_INTERFACE_DESCRIPTOR* uid = reinterpret_cast(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;
+}
diff --git a/usbh_midi.h b/usbh_midi.h
index 4f1c4494..5309a185 100644
--- a/usbh_midi.h
+++ b/usbh_midi.h
@@ -1,7 +1,7 @@
/*
*******************************************************************************
* 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
* by Collin Cunningham - makezine.com, narbotic.com
@@ -26,31 +26,67 @@
#if !defined(_USBH_MIDI_H_)
#define _USBH_MIDI_H_
-//#define DEBUG_USB_HOST
#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 DESC_BUFF_SIZE 256
#define MIDI_EVENT_PACKET_SIZE 64
#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:
- static const uint8_t epDataInIndex; // DataIn endpoint index(MIDI)
- static const uint8_t epDataOutIndex; // 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)
+ static const uint8_t epDataInIndex = 1; // DataIn endpoint index(MIDI)
+ static const uint8_t epDataOutIndex= 2; // DataOUT endpoint index(MIDI)
/* mandatory members */
USB *pUsb;
uint8_t bAddress;
- uint8_t bConfNum; // configuration number
- uint8_t bNumEP; // total number of EP in the configuration
bool bPollEnable;
- bool isMidiFound;
uint16_t pid, vid; // ProductID, VendorID
uint8_t bTransferTypeMask;
/* Endpoint data structure */
@@ -59,27 +95,36 @@ protected:
uint8_t recvBuf[MIDI_EVENT_PACKET_SIZE];
uint8_t readPtr;
- uint8_t parseConfigDescr(uint8_t addr, uint8_t conf);
uint16_t countSysExDataSize(uint8_t *dataptr);
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
void PrintEndpointDescriptor( const USB_ENDPOINT_DESCRIPTOR* ep_ptr );
#endif
public:
USBH_MIDI(USB *p);
// Misc functions
- operator bool() { return (pUsb->getUsbTaskState()==USB_STATE_RUNNING); }
+ operator bool() { return (bPollEnable); }
uint16_t idVendor() { return vid; }
uint16_t idProduct() { return pid; }
// Methods for recieving and sending data
uint8_t RecvData(uint16_t *bytes_rcvd, uint8_t *dataptr);
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);
+ 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 SendSysEx(uint8_t *dataptr, uint16_t datasize, uint8_t nCable=0);
uint8_t extractSysExData(uint8_t *p, uint8_t *buf);
- uint8_t SendRawData(uint16_t bytes_send, uint8_t *dataptr);
// backward compatibility functions
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); };
@@ -88,5 +133,12 @@ public:
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
virtual uint8_t Release();
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_