USB Host Shield 2.0
usbh_midi.cpp
Go to the documentation of this file.
1 /*
2  *******************************************************************************
3  * USB-MIDI class driver for USB Host Shield 2.0 Library
4  * Copyright (c) 2012-2022 Yuuichi Akagawa
5  *
6  * Idea from LPK25 USB-MIDI to Serial MIDI converter
7  * by Collin Cunningham - makezine.com, narbotic.com
8  *
9  * for use with USB Host Shield 2.0 from Circuitsathome.com
10  * https://github.com/felis/USB_Host_Shield_2.0
11  *******************************************************************************
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program. If not, see <http://www.gnu.org/licenses/>
24  *******************************************************************************
25  */
26 
27 #include "usbh_midi.h"
28 // To enable serial debugging see "settings.h"
29 //#define EXTRADEBUG // Uncomment to get even more debugging data
30 
32 // MIDI MESAGES
33 // midi.org/techspecs/
35 // STATUS BYTES
36 // 0x8n == noteOff
37 // 0x9n == noteOn
38 // 0xAn == afterTouch
39 // 0xBn == controlChange
40 // n == Channel(0x0-0xf)
42 //DATA BYTE 1
43 // note# == (0-127)
44 // or
45 // control# == (0-119)
47 // DATA BYTE 2
48 // velocity == (0-127)
49 // or
50 // controlVal == (0-127)
52 // USB-MIDI Event Packets
53 // usb.org - Universal Serial Bus Device Class Definition for MIDI Devices 1.0
55 //+-------------+-------------+-------------+-------------+
56 //| Byte 0 | Byte 1 | Byte 2 | Byte 3 |
57 //+------+------+-------------+-------------+-------------+
58 //|Cable | Code | | | |
59 //|Number|Index | MIDI_0 | MIDI_1 | MIDI_2 |
60 //| |Number| | | |
61 //|(4bit)|(4bit)| (8bit) | (8bit) | (8bit) |
62 //+------+------+-------------+-------------+-------------+
63 // CN == 0x0-0xf
64 //+-----+-----------+-------------------------------------------------------------------
65 //| CIN |MIDI_x size|Description
66 //+-----+-----------+-------------------------------------------------------------------
67 //| 0x0 | 1, 2 or 3 |Miscellaneous function codes. Reserved for future extensions.
68 //| 0x1 | 1, 2 or 3 |Cable events. Reserved for future expansion.
69 //| 0x2 | 2 |Two-byte System Common messages like MTC, SongSelect, etc.
70 //| 0x3 | 3 |Three-byte System Common messages like SPP, etc.
71 //| 0x4 | 3 |SysEx starts or continues
72 //| 0x5 | 1 |Single-byte System Common Message or SysEx ends with following single byte.
73 //| 0x6 | 2 |SysEx ends with following two bytes.
74 //| 0x7 | 3 |SysEx ends with following three bytes.
75 //| 0x8 | 3 |Note-off
76 //| 0x9 | 3 |Note-on
77 //| 0xA | 3 |Poly-KeyPress
78 //| 0xB | 3 |Control Change
79 //| 0xC | 2 |Program Change
80 //| 0xD | 2 |Channel Pressure
81 //| 0xE | 3 |PitchBend Change
82 //| 0xF | 1 |Single Byte
83 //+-----+-----------+-------------------------------------------------------------------
84 
86 pUsb(p),
87 bAddress(0),
88 bPollEnable(false),
89 readPtr(0) {
90  // initialize endpoint data structures
91  for(uint8_t i=0; i<MIDI_MAX_ENDPOINTS; i++) {
92  epInfo[i].epAddr = 0;
93  epInfo[i].maxPktSize = (i) ? 0 : 8;
95  }
96  // register in USB subsystem
97  if (pUsb) {
99  }
100 }
101 
102 /* Connection initialization of an MIDI Device */
103 uint8_t USBH_MIDI::Init(uint8_t parent, uint8_t port, bool lowspeed)
104 {
105  uint8_t buf[sizeof (USB_DEVICE_DESCRIPTOR)];
106  USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf);
107  uint8_t rcode;
108  UsbDevice *p = NULL;
109  EpInfo *oldep_ptr = NULL;
110  uint8_t num_of_conf; // number of configurations
111  uint8_t bConfNum = 0; // configuration number
112  uint8_t bNumEP = 1; // total number of EP in the configuration
113 
114  USBTRACE("\rMIDI Init\r\n");
115 #ifdef DEBUG_USB_HOST
116  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);
117 #endif
118 
119  //for reconnect
120  for(uint8_t i=epDataInIndex; i<=epDataOutIndex; i++) {
121  epInfo[i].bmSndToggle = 0;
122  epInfo[i].bmRcvToggle = 0;
123  // If you want to retry if you get a NAK response when sending, enable the following:
124  // epInfo[i].bmNakPower = (i==epDataOutIndex) ? 10 : USB_NAK_NOWAIT;
125  }
126 
127  // get memory address of USB device address pool
128  AddressPool &addrPool = pUsb->GetAddressPool();
129 
130  // check if address has already been assigned to an instance
131  if (bAddress) {
133  }
134  // Get pointer to pseudo device with address 0 assigned
135  p = addrPool.GetUsbDevicePtr(bAddress);
136  if (!p) {
138  }
139  if (!p->epinfo) {
141  }
142 
143  // Save old pointer to EP_RECORD of address 0
144  oldep_ptr = p->epinfo;
145 
146  // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
147  p->epinfo = epInfo;
148  p->lowspeed = lowspeed;
149 
150  // First Device Descriptor Request (Initially first 8 bytes)
151  // https://techcommunity.microsoft.com/t5/microsoft-usb-blog/how-does-usb-stack-enumerate-a-device/ba-p/270685#_First_Device_Descriptor
152  rcode = pUsb->getDevDescr( 0, 0, 8, (uint8_t*)buf );
153 
154  // Restore p->epinfo
155  p->epinfo = oldep_ptr;
156 
157  if( rcode ){
158  goto FailGetDevDescr;
159  }
160 
161  // Allocate new address according to device class
162  bAddress = addrPool.AllocAddress(parent, false, port);
163  if (!bAddress) {
165  }
166 
167  // Extract Max Packet Size from device descriptor
168  epInfo[0].maxPktSize = udd->bMaxPacketSize0;
169 
170  // Assign new address to the device
171  rcode = pUsb->setAddr( 0, 0, bAddress );
172  if (rcode) {
173  p->lowspeed = false;
174  addrPool.FreeAddress(bAddress);
175  bAddress = 0;
176  return rcode;
177  }//if (rcode...
178  USBTRACE2("Addr:", bAddress);
179 
180  p->lowspeed = false;
181 
182  //get pointer to assigned address record
183  p = addrPool.GetUsbDevicePtr(bAddress);
184  if (!p) {
186  }
187  p->lowspeed = lowspeed;
188 
189  // Second Device Descriptor Request (Full)
190  rcode = pUsb->getDevDescr( bAddress, 0, sizeof(USB_DEVICE_DESCRIPTOR), (uint8_t*)buf );
191  if( rcode ){
192  goto FailGetDevDescr;
193  }
194  vid = udd->idVendor;
195  pid = udd->idProduct;
196  num_of_conf = udd->bNumConfigurations;
197 
198  // Assign epInfo to epinfo pointer
199  rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
200  if (rcode) {
201  USBTRACE("setEpInfoEntry failed");
202  goto FailSetDevTblEntry;
203  }
204 
205  USBTRACE("VID:"), D_PrintHex(vid, 0x80);
206  USBTRACE(" PID:"), D_PrintHex(pid, 0x80);
207  USBTRACE2(" #Conf:", num_of_conf);
208 
209  //Setup for well known vendor/device specific configuration
212 
213  // STEP1: Check if attached device is a MIDI device and fill endpoint data structure
214  USBTRACE("\r\nSTEP1: MIDI Start\r\n");
215  for(uint8_t i = 0; i < num_of_conf; i++) {
216  MidiDescParser midiDescParser(this, true); // Check for MIDI device
217  rcode = pUsb->getConfDescr(bAddress, 0, i, &midiDescParser);
218  if(rcode) // Check error code
219  goto FailGetConfDescr;
220  bNumEP += midiDescParser.getNumEPs();
221  if(bNumEP > 1) {// All endpoints extracted
222  bConfNum = midiDescParser.getConfValue();
223  break;
224  }
225  }
226  USBTRACE2("STEP1: MIDI,NumEP:", bNumEP);
227  //Found the MIDI device?
228  if( bNumEP == 1 ){ //Device not found.
229  USBTRACE("MIDI not found.\r\nSTEP2: Attempts vendor specific bulk device\r\n");
230  // STEP2: Check if attached device is a MIDI device and fill endpoint data structure
231  for(uint8_t i = 0; i < num_of_conf; i++) {
232  MidiDescParser midiDescParser(this, false); // Allow all devices, vendor specific class with Bulk transfer
233  rcode = pUsb->getConfDescr(bAddress, 0, i, &midiDescParser);
234  if(rcode) // Check error code
235  goto FailGetConfDescr;
236  bNumEP += midiDescParser.getNumEPs();
237  if(bNumEP > 1) {// All endpoints extracted
238  bConfNum = midiDescParser.getConfValue();
239  break;
240  }
241  }
242  USBTRACE2("\r\nSTEP2: Vendor,NumEP:", bNumEP);
243  }
244 
245  if( bNumEP < 2 ){ //Device not found.
246  rcode = 0xff;
247  goto FailGetConfDescr;
248  }
249 
250  // Assign epInfo to epinfo pointer
251  rcode = pUsb->setEpInfoEntry(bAddress, 3, epInfo);
252  USBTRACE2("Conf:", bConfNum);
253  USBTRACE2("EPin :", (uint8_t)(epInfo[epDataInIndex].epAddr + 0x80));
254  USBTRACE2("EPout:", epInfo[epDataOutIndex].epAddr);
255 
256  // Set Configuration Value
257  rcode = pUsb->setConf(bAddress, 0, bConfNum);
258  if (rcode)
259  goto FailSetConfDescr;
260 
261  bPollEnable = true;
262 
263  if(pFuncOnInit)
264  pFuncOnInit(); // Call the user function
265 
266  USBTRACE("Init done.\r\n");
267  return 0;
268 FailGetDevDescr:
269 FailSetDevTblEntry:
270 FailGetConfDescr:
271 FailSetConfDescr:
272  Release();
273  return rcode;
274 }
275 
276 /* Performs a cleanup after failed Init() attempt */
278 {
279  if(pFuncOnRelease && bPollEnable)
280  pFuncOnRelease(); // Call the user function
281 
283  bAddress = 0;
284  bPollEnable = false;
285  readPtr = 0;
286 
287  return 0;
288 }
289 
290 /* Setup for well known vendor/device specific configuration */
292 {
293  // Novation
294  if( vid == 0x1235 ) {
295  // LaunchPad and LaunchKey endpoint attribute is interrupt
296  // https://github.com/YuuichiAkagawa/USBH_MIDI/wiki/Novation-USB-Product-ID-List
297 
298  // LaunchPad: 0x20:S, 0x36:Mini, 0x51:Pro, 0x69:MK2
299  if( pid == 0x20 || pid == 0x36 || pid == 0x51 || pid == 0x69 ) {
300  bTransferTypeMask = 2;
301  return;
302  }
303 
304  // LaunchKey: 0x30-32, 0x35:Mini, 0x7B-0x7D:MK2, 0x0102,0x113-0x122:MiniMk3, 0x134-0x137:MK3
305  if( (0x30 <= pid && pid <= 0x32) || pid == 0x35 || (0x7B <= pid && pid <= 0x7D)
306  || pid == 0x102 || (0x113 <= pid && pid <= 0x122) || (0x134 <= pid && pid <= 0x137) ) {
307  bTransferTypeMask = 2;
308  return;
309  }
310  }
311 }
312 
313 /* Receive data from MIDI device */
314 uint8_t USBH_MIDI::RecvData(uint16_t *bytes_rcvd, uint8_t *dataptr)
315 {
316  *bytes_rcvd = (uint16_t)epInfo[epDataInIndex].maxPktSize;
317  uint8_t r = pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, bytes_rcvd, dataptr);
318 #ifdef EXTRADEBUG
319  if( r )
320  USBTRACE2("inTransfer():", r);
321 #endif
322  if( *bytes_rcvd < (MIDI_EVENT_PACKET_SIZE-4)){
323  dataptr[*bytes_rcvd] = '\0';
324  dataptr[(*bytes_rcvd)+1] = '\0';
325  }
326  return r;
327 }
328 
329 /* Receive data from MIDI device */
330 uint8_t USBH_MIDI::RecvData(uint8_t *outBuf, bool isRaw)
331 {
332  uint8_t rcode = 0; //return code
333  uint16_t rcvd;
334 
335  if( bPollEnable == false ) return 0;
336 
337  //Checking unprocessed message in buffer.
338  if( readPtr != 0 && readPtr < MIDI_EVENT_PACKET_SIZE ){
339  if(recvBuf[readPtr] == 0 && recvBuf[readPtr+1] == 0) {
340  //no unprocessed message left in the buffer.
341  }else{
342  goto RecvData_return_from_buffer;
343  }
344  }
345 
346  readPtr = 0;
347  rcode = RecvData( &rcvd, recvBuf);
348  if( rcode != 0 ) {
349  return 0;
350  }
351 
352  //if all data is zero, no valid data received.
353  if( recvBuf[0] == 0 && recvBuf[1] == 0 && recvBuf[2] == 0 && recvBuf[3] == 0 ) {
354  return 0;
355  }
356 
357 RecvData_return_from_buffer:
358  uint8_t m;
359  uint8_t cin = recvBuf[readPtr];
360  if( isRaw == true ) {
361  *(outBuf++) = cin;
362  }
363  readPtr++;
364  *(outBuf++) = m = recvBuf[readPtr++];
365  *(outBuf++) = recvBuf[readPtr++];
366  *(outBuf++) = recvBuf[readPtr++];
367 
368  return getMsgSizeFromCin(cin & 0x0f);
369 }
370 
371 /* Send data to MIDI device */
372 uint8_t USBH_MIDI::SendData(uint8_t *dataptr, uint8_t nCable)
373 {
374  uint8_t buf[4];
375  uint8_t status = dataptr[0];
376 
377  uint8_t cin = convertStatus2Cin(status);
378  if ( status == 0xf0 ) {
379  // SysEx long message
380  return SendSysEx(dataptr, countSysExDataSize(dataptr), nCable);
381  }
382 
383  //Building USB-MIDI Event Packets
384  buf[0] = (uint8_t)(nCable << 4) | cin;
385  buf[1] = dataptr[0];
386 
387  uint8_t msglen = getMsgSizeFromCin(cin);
388  switch(msglen) {
389  //3 bytes message
390  case 3 :
391  buf[2] = dataptr[1];
392  buf[3] = dataptr[2];
393  break;
394 
395  //2 bytes message
396  case 2 :
397  buf[2] = dataptr[1];
398  buf[3] = 0;
399  break;
400 
401  //1 byte message
402  case 1 :
403  buf[2] = 0;
404  buf[3] = 0;
405  break;
406  default :
407  break;
408  }
409 #ifdef EXTRADEBUG
410  //Dump for raw USB-MIDI event packet
411  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);
412 #endif
413  return pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, 4, buf);
414 }
415 
416 #ifdef DEBUG_USB_HOST
417 void USBH_MIDI::PrintEndpointDescriptor( const USB_ENDPOINT_DESCRIPTOR* ep_ptr )
418 {
419  USBTRACE("Endpoint descriptor:\r\n");
420  USBTRACE2(" Length:\t", ep_ptr->bLength);
421  USBTRACE2(" Type:\t\t", ep_ptr->bDescriptorType);
422  USBTRACE2(" Address:\t", ep_ptr->bEndpointAddress);
423  USBTRACE2(" Attributes:\t", ep_ptr->bmAttributes);
424  USBTRACE2(" MaxPktSize:\t", ep_ptr->wMaxPacketSize);
425  USBTRACE2(" Poll Intrv:\t", ep_ptr->bInterval);
426 }
427 #endif
428 
429 /* look up a MIDI message size from spec */
430 /*Return */
431 /* 0 : undefined message */
432 /* 0<: Vaild message size(1-3) */
433 //uint8_t USBH_MIDI::lookupMsgSize(uint8_t midiMsg, uint8_t cin)
434 uint8_t USBH_MIDI::lookupMsgSize(uint8_t status, uint8_t cin)
435 {
436  if( cin == 0 ){
437  cin = convertStatus2Cin(status);
438  }
439  return getMsgSizeFromCin(cin);
440 }
441 
442 /* SysEx data size counter */
443 uint16_t USBH_MIDI::countSysExDataSize(uint8_t *dataptr)
444 {
445  uint16_t c = 1;
446 
447  if( *dataptr != 0xf0 ){ //not SysEx
448  return 0;
449  }
450 
451  //Search terminator(0xf7)
452  while(*dataptr != 0xf7) {
453  dataptr++;
454  c++;
455  //Limiter (default: 256 bytes)
456  if(c > MIDI_MAX_SYSEX_SIZE){
457  c = 0;
458  break;
459  }
460  }
461  return c;
462 }
463 
464 /* Send SysEx message to MIDI device */
465 uint8_t USBH_MIDI::SendSysEx(uint8_t *dataptr, uint16_t datasize, uint8_t nCable)
466 {
467  uint8_t buf[MIDI_EVENT_PACKET_SIZE];
468  uint8_t rc = 0;
469  uint16_t n = datasize;
470  uint8_t wptr = 0;
471  uint8_t maxpkt = epInfo[epDataInIndex].maxPktSize;
472 
473  USBTRACE("SendSysEx:\r\t");
474  USBTRACE2(" Length:\t", datasize);
475 #ifdef EXTRADEBUG
476  uint16_t pktSize = (n+2)/3; //Calculate total USB MIDI packet size
477  USBTRACE2(" Total pktSize:\t", pktSize);
478 #endif
479 
480  while(n > 0) {
481  //Byte 0
482  buf[wptr] = (nCable << 4) | 0x4; //x4 SysEx starts or continues
483 
484  switch ( n ) {
485  case 1 :
486  buf[wptr++] = (nCable << 4) | 0x5; //x5 SysEx ends with following single byte.
487  buf[wptr++] = *(dataptr++);
488  buf[wptr++] = 0x00;
489  buf[wptr++] = 0x00;
490  n = 0;
491  break;
492  case 2 :
493  buf[wptr++] = (nCable << 4) | 0x6; //x6 SysEx ends with following two bytes.
494  buf[wptr++] = *(dataptr++);
495  buf[wptr++] = *(dataptr++);
496  buf[wptr++] = 0x00;
497  n = 0;
498  break;
499  case 3 :
500  buf[wptr] = (nCable << 4) | 0x7; //x7 SysEx ends with following three bytes.
501  // fall through
502  default :
503  wptr++;
504  buf[wptr++] = *(dataptr++);
505  buf[wptr++] = *(dataptr++);
506  buf[wptr++] = *(dataptr++);
507  n = n - 3;
508  break;
509  }
510 
511  if( wptr >= maxpkt || n == 0 ){ //Reach a maxPktSize or data end.
512  USBTRACE2(" wptr:\t", wptr);
513  if( (rc = pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, wptr, buf)) != 0 ){
514  break;
515  }
516  wptr = 0; //rewind write pointer
517  }
518  }
519  return(rc);
520 }
521 
522 uint8_t USBH_MIDI::extractSysExData(uint8_t *p, uint8_t *buf)
523 {
524  uint8_t rc = 0;
525  uint8_t cin = *(p) & 0x0f;
526 
527  //SysEx message?
528  if( (cin & 0xc) != 4 ) return rc;
529 
530  switch(cin) {
531  case 4:
532  case 7:
533  *buf++ = *(p+1);
534  *buf++ = *(p+2);
535  *buf++ = *(p+3);
536  rc = 3;
537  break;
538  case 6:
539  *buf++ = *(p+1);
540  *buf++ = *(p+2);
541  rc = 2;
542  break;
543  case 5:
544  *buf++ = *(p+1);
545  rc = 1;
546  break;
547  default:
548  break;
549  }
550  return(rc);
551 }
552 
553 // Configuration Descriptor Parser
554 // Copied from confdescparser.h and modifiy.
556 theXtractor(xtractor),
557 stateParseDescr(0),
558 dscrLen(0),
559 dscrType(0),
560 nEPs(0),
561 isMidiSearch(modeMidi){
562  theBuffer.pValue = varBuffer;
563  valParser.Initialize(&theBuffer);
564  theSkipper.Initialize(&theBuffer);
565 }
566 void MidiDescParser::Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset __attribute__((unused))) {
567  uint16_t cntdn = (uint16_t)len;
568  uint8_t *p = (uint8_t*)pbuf;
569 
570  while(cntdn)
571  if(!ParseDescriptor(&p, &cntdn))
572  return;
573 }
574 
575 bool MidiDescParser::ParseDescriptor(uint8_t **pp, uint16_t *pcntdn) {
576  USB_CONFIGURATION_DESCRIPTOR* ucd = reinterpret_cast<USB_CONFIGURATION_DESCRIPTOR*>(varBuffer);
577  USB_INTERFACE_DESCRIPTOR* uid = reinterpret_cast<USB_INTERFACE_DESCRIPTOR*>(varBuffer);
578  switch(stateParseDescr) {
579  case 0:
580  theBuffer.valueSize = 2;
581  valParser.Initialize(&theBuffer);
582  stateParseDescr = 1;
583  // fall through
584  case 1:
585  if(!valParser.Parse(pp, pcntdn))
586  return false;
587  dscrLen = *((uint8_t*)theBuffer.pValue);
588  dscrType = *((uint8_t*)theBuffer.pValue + 1);
589  stateParseDescr = 2;
590  // fall through
591  case 2:
592  // This is a sort of hack. Assuming that two bytes are all ready in the buffer
593  // the pointer is positioned two bytes ahead in order for the rest of descriptor
594  // to be read right after the size and the type fields.
595  // This should be used carefully. varBuffer should be used directly to handle data
596  // in the buffer.
597  theBuffer.pValue = varBuffer + 2;
598  stateParseDescr = 3;
599  // fall through
600  case 3:
601  switch(dscrType) {
603  isGoodInterface = false;
604  break;
607  case HID_DESCRIPTOR_HID:
608  break;
609  }
610  theBuffer.valueSize = dscrLen - 2;
611  valParser.Initialize(&theBuffer);
612  stateParseDescr = 4;
613  // fall through
614  case 4:
615  switch(dscrType) {
617  if(!valParser.Parse(pp, pcntdn))
618  return false;
619  confValue = ucd->bConfigurationValue;
620  break;
622  if(!valParser.Parse(pp, pcntdn))
623  return false;
624  USBTRACE("Interface descriptor:\r\n");
625  USBTRACE2(" Inf#:\t\t", uid->bInterfaceNumber);
626  USBTRACE2(" Alt:\t\t", uid->bAlternateSetting);
627  USBTRACE2(" EPs:\t\t", uid->bNumEndpoints);
628  USBTRACE2(" IntCl:\t\t", uid->bInterfaceClass);
629  USBTRACE2(" IntSubcl:\t", uid->bInterfaceSubClass);
630  USBTRACE2(" Protocol:\t", uid->bInterfaceProtocol);
631  // MIDI check mode ?
632  if( isMidiSearch ){ //true: MIDI Streaming, false: ALL
634  // MIDI found.
635  USBTRACE("+MIDI found\r\n\r\n");
636  }else{
637  USBTRACE("-MIDI not found\r\n\r\n");
638  break;
639  }
640  }
641  isGoodInterface = true;
642  // Initialize the counter if no two endpoints can be found in one interface.
643  if(nEPs < 2)
644  // reset endpoint counter
645  nEPs = 0;
646  break;
648  if(!valParser.Parse(pp, pcntdn))
649  return false;
650  if(isGoodInterface && nEPs < 2){
651  USBTRACE(">Extracting endpoint\r\n");
652  if( theXtractor->EndpointXtract(confValue, 0, 0, 0, (USB_ENDPOINT_DESCRIPTOR*)varBuffer) )
653  nEPs++;
654  }
655  break;
656 
657  default:
658  if(!theSkipper.Skip(pp, pcntdn, dscrLen - 2))
659  return false;
660  }
661  theBuffer.pValue = varBuffer;
662  stateParseDescr = 0;
663  }
664  return true;
665 }
666 
667 /* Extracts endpoint information from config descriptor */
668 bool USBH_MIDI::EndpointXtract(uint8_t conf __attribute__((unused)),
669  uint8_t iface __attribute__((unused)),
670  uint8_t alt __attribute__((unused)),
671  uint8_t proto __attribute__((unused)),
672  const USB_ENDPOINT_DESCRIPTOR *pep)
673 {
674  uint8_t index;
675 
676 #ifdef DEBUG_USB_HOST
677  PrintEndpointDescriptor(pep);
678 #endif
679  // Is the endpoint transfer type bulk?
681  USBTRACE("+valid EP found.\r\n");
682  index = (pep->bEndpointAddress & 0x80) == 0x80 ? epDataInIndex : epDataOutIndex;
683  } else {
684  USBTRACE("-No valid EP found.\r\n");
685  return false;
686  }
687 
688  // Fill the rest of endpoint data structure
689  epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
690  // The maximum packet size for the USB Host Shield 2.0 library is 64 bytes.
693  } else {
694  epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize;
695  }
696 
697  return true;
698 }
#define USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL
Definition: UsbCore.h:95
#define USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE
Definition: UsbCore.h:100
#define USB_CLASS_AUDIO
Definition: UsbCore.h:72
#define USB_ERROR_EPINFO_IS_NULL
Definition: UsbCore.h:98
#define USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL
Definition: UsbCore.h:97
#define USB_NAK_MAX_POWER
Definition: address.h:34
#define USB_NAK_NOWAIT
Definition: address.h:36
virtual void FreeAddress(uint8_t addr)=0
virtual uint8_t AllocAddress(uint8_t parent, bool is_hub=false, uint8_t port=0)=0
virtual UsbDevice * GetUsbDevicePtr(uint8_t addr)=0
bool Skip(uint8_t **pp, uint16_t *pcntdn, uint16_t bytes_to_skip)
Definition: parsetools.h:77
void Initialize(MultiValueBuffer *pbuf)
Definition: parsetools.h:72
void Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset)
Definition: usbh_midi.cpp:566
uint8_t getConfValue()
Definition: usbh_midi.h:75
MidiDescParser(UsbMidiConfigXtracter *xtractor, bool modeMidi)
Definition: usbh_midi.cpp:555
uint8_t getNumEPs()
Definition: usbh_midi.h:76
void Initialize(MultiValueBuffer *const pbuf)
Definition: parsetools.h:54
bool Parse(uint8_t **pp, uint16_t *pcntdn)
Definition: parsetools.cpp:26
static const uint8_t epDataInIndex
Definition: usbh_midi.h:83
uint8_t convertStatus2Cin(uint8_t status)
Definition: usbh_midi.h:100
bool EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep)
Definition: usbh_midi.cpp:668
uint8_t bTransferTypeMask
Definition: usbh_midi.h:91
static const uint8_t epDataOutIndex
Definition: usbh_midi.h:84
bool bPollEnable
Definition: usbh_midi.h:89
uint8_t SendData(uint8_t *dataptr, uint8_t nCable=0)
Definition: usbh_midi.cpp:372
USBH_MIDI(USB *p)
Definition: usbh_midi.cpp:85
uint8_t lookupMsgSize(uint8_t midiMsg, uint8_t cin=0)
Definition: usbh_midi.cpp:434
virtual uint8_t Release()
Definition: usbh_midi.cpp:277
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed)
Definition: usbh_midi.cpp:103
uint8_t SendSysEx(uint8_t *dataptr, uint16_t datasize, uint8_t nCable=0)
Definition: usbh_midi.cpp:465
uint16_t vid
Definition: usbh_midi.h:90
uint8_t recvBuf[MIDI_EVENT_PACKET_SIZE]
Definition: usbh_midi.h:95
void setupDeviceSpecific()
Definition: usbh_midi.cpp:291
uint8_t readPtr
Definition: usbh_midi.h:96
uint16_t pid
Definition: usbh_midi.h:90
uint16_t countSysExDataSize(uint8_t *dataptr)
Definition: usbh_midi.cpp:443
uint8_t extractSysExData(uint8_t *p, uint8_t *buf)
Definition: usbh_midi.cpp:522
EpInfo epInfo[MIDI_MAX_ENDPOINTS]
Definition: usbh_midi.h:93
uint8_t RecvData(uint16_t *bytes_rcvd, uint8_t *dataptr)
Definition: usbh_midi.cpp:314
uint8_t getMsgSizeFromCin(uint8_t cin)
Definition: usbh_midi.h:103
uint8_t bAddress
Definition: usbh_midi.h:88
USB * pUsb
Definition: usbh_midi.h:87
Definition: UsbCore.h:212
uint8_t getDevDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t *dataptr)
defined(USB_METHODS_INLINE)
Definition: Usb.cpp:801
uint8_t setConf(uint8_t addr, uint8_t ep, uint8_t conf_value)
Definition: Usb.cpp:845
uint8_t setAddr(uint8_t oldaddr, uint8_t ep, uint8_t newaddr)
Definition: Usb.cpp:836
uint8_t RegisterDeviceClass(USBDeviceConfig *pdev)
Definition: UsbCore.h:232
uint8_t getConfDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t conf, uint8_t *dataptr)
Definition: Usb.cpp:806
AddressPool & GetAddressPool()
Definition: UsbCore.h:228
uint8_t setEpInfoEntry(uint8_t addr, uint8_t epcount, EpInfo *eprecord_ptr)
Definition: Usb.cpp:64
uint8_t inTransfer(uint8_t addr, uint8_t ep, uint16_t *nbytesptr, uint8_t *data, uint8_t bInterval=0)
Definition: Usb.cpp:209
uint8_t outTransfer(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t *data)
Definition: Usb.cpp:303
virtual bool EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep)
Definition: usbh_midi.h:48
#define USBTRACE2(s, r)
Definition: macros.h:84
#define USBTRACE(s)
Definition: macros.h:82
#define Notify(...)
Definition: message.h:51
void D_PrintHex(T val, int lvl)
Definition: printhex.h:76
Definition: address.h:39
uint8_t bmNakPower
Definition: address.h:49
uint8_t bmRcvToggle
Definition: address.h:48
uint8_t epAddr
Definition: address.h:40
uint8_t maxPktSize
Definition: address.h:41
uint8_t bmSndToggle
Definition: address.h:47
uint8_t valueSize
Definition: parsetools.h:31
uint8_t bEndpointAddress
Definition: usb_ch9.h:151
uint16_t wMaxPacketSize
Definition: usb_ch9.h:153
uint8_t bInterfaceSubClass
Definition: usb_ch9.h:142
uint8_t bInterfaceProtocol
Definition: usb_ch9.h:143
EpInfo * epinfo
Definition: address.h:83
bool lowspeed
Definition: address.h:86
#define USB_TRANSFER_TYPE_BULK
Definition: usb_ch9.h:92
#define USB_DESCRIPTOR_INTERFACE
Definition: usb_ch9.h:73
#define HID_DESCRIPTOR_HID
Definition: usb_ch9.h:80
#define USB_DESCRIPTOR_CONFIGURATION
Definition: usb_ch9.h:71
#define bmUSB_TRANSFER_TYPE
Definition: usb_ch9.h:94
#define USB_DESCRIPTOR_ENDPOINT
Definition: usb_ch9.h:74
#define USB_SUBCLASS_MIDISTREAMING
Definition: usbh_midi.h:33
#define MIDI_EVENT_PACKET_SIZE
Definition: usbh_midi.h:34
#define MIDI_MAX_ENDPOINTS
Definition: usbh_midi.h:32
#define MIDI_MAX_SYSEX_SIZE
Definition: usbh_midi.h:35
#define USBH_MIDI_VERSION
Definition: usbh_midi.h:31
#define PSTR(str)