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-2021 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  if(pFuncOnInit)
262  pFuncOnInit(); // Call the user function
263 
264  bPollEnable = true;
265  USBTRACE("Init done.\r\n");
266  return 0;
267 FailGetDevDescr:
268 FailSetDevTblEntry:
269 FailGetConfDescr:
270 FailSetConfDescr:
271  Release();
272  return rcode;
273 }
274 
275 /* Performs a cleanup after failed Init() attempt */
277 {
279  bAddress = 0;
280  bPollEnable = false;
281  readPtr = 0;
282  return 0;
283 }
284 
285 /* Setup for well known vendor/device specific configuration */
287 {
288  // Novation
289  if( vid == 0x1235 ) {
290  // LaunchPad and LaunchKey endpoint attribute is interrupt
291  // https://github.com/YuuichiAkagawa/USBH_MIDI/wiki/Novation-USB-Product-ID-List
292 
293  // LaunchPad: 0x20:S, 0x36:Mini, 0x51:Pro, 0x69:MK2
294  if( pid == 0x20 || pid == 0x36 || pid == 0x51 || pid == 0x69 ) {
295  bTransferTypeMask = 2;
296  return;
297  }
298 
299  // LaunchKey: 0x30-32, 0x35:Mini, 0x7B-0x7D:MK2
300  if( ( 0x30 <= pid && pid <= 0x32) || pid == 0x35 || ( 0x7B <= pid && pid <= 0x7D) ) {
301  bTransferTypeMask = 2;
302  return;
303  }
304  }
305 }
306 
307 /* Receive data from MIDI device */
308 uint8_t USBH_MIDI::RecvData(uint16_t *bytes_rcvd, uint8_t *dataptr)
309 {
310  *bytes_rcvd = (uint16_t)epInfo[epDataInIndex].maxPktSize;
311  uint8_t r = pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, bytes_rcvd, dataptr);
312 #ifdef EXTRADEBUG
313  if( r )
314  USBTRACE2("inTransfer():", r);
315 #endif
316  if( *bytes_rcvd < (MIDI_EVENT_PACKET_SIZE-4)){
317  dataptr[*bytes_rcvd] = '\0';
318  dataptr[(*bytes_rcvd)+1] = '\0';
319  }
320  return r;
321 }
322 
323 /* Receive data from MIDI device */
324 uint8_t USBH_MIDI::RecvData(uint8_t *outBuf, bool isRaw)
325 {
326  uint8_t rcode = 0; //return code
327  uint16_t rcvd;
328 
329  if( bPollEnable == false ) return 0;
330 
331  //Checking unprocessed message in buffer.
332  if( readPtr != 0 && readPtr < MIDI_EVENT_PACKET_SIZE ){
333  if(recvBuf[readPtr] == 0 && recvBuf[readPtr+1] == 0) {
334  //no unprocessed message left in the buffer.
335  }else{
336  goto RecvData_return_from_buffer;
337  }
338  }
339 
340  readPtr = 0;
341  rcode = RecvData( &rcvd, recvBuf);
342  if( rcode != 0 ) {
343  return 0;
344  }
345 
346  //if all data is zero, no valid data received.
347  if( recvBuf[0] == 0 && recvBuf[1] == 0 && recvBuf[2] == 0 && recvBuf[3] == 0 ) {
348  return 0;
349  }
350 
351 RecvData_return_from_buffer:
352  uint8_t m;
353  uint8_t cin = recvBuf[readPtr];
354  if( isRaw == true ) {
355  *(outBuf++) = cin;
356  }
357  readPtr++;
358  *(outBuf++) = m = recvBuf[readPtr++];
359  *(outBuf++) = recvBuf[readPtr++];
360  *(outBuf++) = recvBuf[readPtr++];
361 
362  return getMsgSizeFromCin(cin);
363 }
364 
365 /* Send data to MIDI device */
366 uint8_t USBH_MIDI::SendData(uint8_t *dataptr, uint8_t nCable)
367 {
368  uint8_t buf[4];
369  uint8_t status = dataptr[0];
370 
371  uint8_t cin = convertStatus2Cin(status);
372  if ( status == 0xf0 ) {
373  // SysEx long message
374  return SendSysEx(dataptr, countSysExDataSize(dataptr), nCable);
375  }
376 
377  //Building USB-MIDI Event Packets
378  buf[0] = (uint8_t)(nCable << 4) | cin;
379  buf[1] = dataptr[0];
380 
381  uint8_t msglen = getMsgSizeFromCin(cin);
382  switch(msglen) {
383  //3 bytes message
384  case 3 :
385  buf[2] = dataptr[1];
386  buf[3] = dataptr[2];
387  break;
388 
389  //2 bytes message
390  case 2 :
391  buf[2] = dataptr[1];
392  buf[3] = 0;
393  break;
394 
395  //1 byte message
396  case 1 :
397  buf[2] = 0;
398  buf[3] = 0;
399  break;
400  default :
401  break;
402  }
403 #ifdef EXTRADEBUG
404  //Dump for raw USB-MIDI event packet
405  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);
406 #endif
407  return pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, 4, buf);
408 }
409 
410 #ifdef DEBUG_USB_HOST
411 void USBH_MIDI::PrintEndpointDescriptor( const USB_ENDPOINT_DESCRIPTOR* ep_ptr )
412 {
413  USBTRACE("Endpoint descriptor:\r\n");
414  USBTRACE2(" Length:\t", ep_ptr->bLength);
415  USBTRACE2(" Type:\t\t", ep_ptr->bDescriptorType);
416  USBTRACE2(" Address:\t", ep_ptr->bEndpointAddress);
417  USBTRACE2(" Attributes:\t", ep_ptr->bmAttributes);
418  USBTRACE2(" MaxPktSize:\t", ep_ptr->wMaxPacketSize);
419  USBTRACE2(" Poll Intrv:\t", ep_ptr->bInterval);
420 }
421 #endif
422 
423 /* look up a MIDI message size from spec */
424 /*Return */
425 /* 0 : undefined message */
426 /* 0<: Vaild message size(1-3) */
427 //uint8_t USBH_MIDI::lookupMsgSize(uint8_t midiMsg, uint8_t cin)
428 uint8_t USBH_MIDI::lookupMsgSize(uint8_t status, uint8_t cin)
429 {
430  if( cin == 0 ){
431  cin = convertStatus2Cin(status);
432  }
433  return getMsgSizeFromCin(cin);
434 }
435 
436 /* SysEx data size counter */
437 uint16_t USBH_MIDI::countSysExDataSize(uint8_t *dataptr)
438 {
439  uint16_t c = 1;
440 
441  if( *dataptr != 0xf0 ){ //not SysEx
442  return 0;
443  }
444 
445  //Search terminator(0xf7)
446  while(*dataptr != 0xf7) {
447  dataptr++;
448  c++;
449  //Limiter (default: 256 bytes)
450  if(c > MIDI_MAX_SYSEX_SIZE){
451  c = 0;
452  break;
453  }
454  }
455  return c;
456 }
457 
458 /* Send SysEx message to MIDI device */
459 uint8_t USBH_MIDI::SendSysEx(uint8_t *dataptr, uint16_t datasize, uint8_t nCable)
460 {
461  uint8_t buf[MIDI_EVENT_PACKET_SIZE];
462  uint8_t rc = 0;
463  uint16_t n = datasize;
464  uint8_t wptr = 0;
465  uint8_t maxpkt = epInfo[epDataInIndex].maxPktSize;
466 
467  USBTRACE("SendSysEx:\r\t");
468  USBTRACE2(" Length:\t", datasize);
469 #ifdef EXTRADEBUG
470  uint16_t pktSize = (n+2)/3; //Calculate total USB MIDI packet size
471  USBTRACE2(" Total pktSize:\t", pktSize);
472 #endif
473 
474  while(n > 0) {
475  //Byte 0
476  buf[wptr] = (nCable << 4) | 0x4; //x4 SysEx starts or continues
477 
478  switch ( n ) {
479  case 1 :
480  buf[wptr++] = (nCable << 4) | 0x5; //x5 SysEx ends with following single byte.
481  buf[wptr++] = *(dataptr++);
482  buf[wptr++] = 0x00;
483  buf[wptr++] = 0x00;
484  n = 0;
485  break;
486  case 2 :
487  buf[wptr++] = (nCable << 4) | 0x6; //x6 SysEx ends with following two bytes.
488  buf[wptr++] = *(dataptr++);
489  buf[wptr++] = *(dataptr++);
490  buf[wptr++] = 0x00;
491  n = 0;
492  break;
493  case 3 :
494  buf[wptr] = (nCable << 4) | 0x7; //x7 SysEx ends with following three bytes.
495  // fall through
496  default :
497  wptr++;
498  buf[wptr++] = *(dataptr++);
499  buf[wptr++] = *(dataptr++);
500  buf[wptr++] = *(dataptr++);
501  n = n - 3;
502  break;
503  }
504 
505  if( wptr >= maxpkt || n == 0 ){ //Reach a maxPktSize or data end.
506  USBTRACE2(" wptr:\t", wptr);
507  if( (rc = pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, wptr, buf)) != 0 ){
508  break;
509  }
510  wptr = 0; //rewind write pointer
511  }
512  }
513  return(rc);
514 }
515 
516 uint8_t USBH_MIDI::extractSysExData(uint8_t *p, uint8_t *buf)
517 {
518  uint8_t rc = 0;
519  uint8_t cin = *(p) & 0x0f;
520 
521  //SysEx message?
522  if( (cin & 0xc) != 4 ) return rc;
523 
524  switch(cin) {
525  case 4:
526  case 7:
527  *buf++ = *(p+1);
528  *buf++ = *(p+2);
529  *buf++ = *(p+3);
530  rc = 3;
531  break;
532  case 6:
533  *buf++ = *(p+1);
534  *buf++ = *(p+2);
535  rc = 2;
536  break;
537  case 5:
538  *buf++ = *(p+1);
539  rc = 1;
540  break;
541  default:
542  break;
543  }
544  return(rc);
545 }
546 
547 // Configuration Descriptor Parser
548 // Copied from confdescparser.h and modifiy.
550 theXtractor(xtractor),
551 stateParseDescr(0),
552 dscrLen(0),
553 dscrType(0),
554 nEPs(0),
555 isMidiSearch(modeMidi){
556  theBuffer.pValue = varBuffer;
557  valParser.Initialize(&theBuffer);
558  theSkipper.Initialize(&theBuffer);
559 }
560 void MidiDescParser::Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset __attribute__((unused))) {
561  uint16_t cntdn = (uint16_t)len;
562  uint8_t *p = (uint8_t*)pbuf;
563 
564  while(cntdn)
565  if(!ParseDescriptor(&p, &cntdn))
566  return;
567 }
568 
569 bool MidiDescParser::ParseDescriptor(uint8_t **pp, uint16_t *pcntdn) {
570  USB_CONFIGURATION_DESCRIPTOR* ucd = reinterpret_cast<USB_CONFIGURATION_DESCRIPTOR*>(varBuffer);
571  USB_INTERFACE_DESCRIPTOR* uid = reinterpret_cast<USB_INTERFACE_DESCRIPTOR*>(varBuffer);
572  switch(stateParseDescr) {
573  case 0:
574  theBuffer.valueSize = 2;
575  valParser.Initialize(&theBuffer);
576  stateParseDescr = 1;
577  // fall through
578  case 1:
579  if(!valParser.Parse(pp, pcntdn))
580  return false;
581  dscrLen = *((uint8_t*)theBuffer.pValue);
582  dscrType = *((uint8_t*)theBuffer.pValue + 1);
583  stateParseDescr = 2;
584  // fall through
585  case 2:
586  // This is a sort of hack. Assuming that two bytes are all ready in the buffer
587  // the pointer is positioned two bytes ahead in order for the rest of descriptor
588  // to be read right after the size and the type fields.
589  // This should be used carefully. varBuffer should be used directly to handle data
590  // in the buffer.
591  theBuffer.pValue = varBuffer + 2;
592  stateParseDescr = 3;
593  // fall through
594  case 3:
595  switch(dscrType) {
597  isGoodInterface = false;
598  break;
601  case HID_DESCRIPTOR_HID:
602  break;
603  }
604  theBuffer.valueSize = dscrLen - 2;
605  valParser.Initialize(&theBuffer);
606  stateParseDescr = 4;
607  // fall through
608  case 4:
609  switch(dscrType) {
611  if(!valParser.Parse(pp, pcntdn))
612  return false;
613  confValue = ucd->bConfigurationValue;
614  break;
616  if(!valParser.Parse(pp, pcntdn))
617  return false;
618  USBTRACE("Interface descriptor:\r\n");
619  USBTRACE2(" Inf#:\t\t", uid->bInterfaceNumber);
620  USBTRACE2(" Alt:\t\t", uid->bAlternateSetting);
621  USBTRACE2(" EPs:\t\t", uid->bNumEndpoints);
622  USBTRACE2(" IntCl:\t\t", uid->bInterfaceClass);
623  USBTRACE2(" IntSubcl:\t", uid->bInterfaceSubClass);
624  USBTRACE2(" Protocol:\t", uid->bInterfaceProtocol);
625  // MIDI check mode ?
626  if( isMidiSearch ){ //true: MIDI Streaming, false: ALL
628  // MIDI found.
629  USBTRACE("+MIDI found\r\n\r\n");
630  }else{
631  USBTRACE("-MIDI not found\r\n\r\n");
632  break;
633  }
634  }
635  isGoodInterface = true;
636  // Initialize the counter if no two endpoints can be found in one interface.
637  if(nEPs < 2)
638  // reset endpoint counter
639  nEPs = 0;
640  break;
642  if(!valParser.Parse(pp, pcntdn))
643  return false;
644  if(isGoodInterface && nEPs < 2){
645  USBTRACE(">Extracting endpoint\r\n");
646  if( theXtractor->EndpointXtract(confValue, 0, 0, 0, (USB_ENDPOINT_DESCRIPTOR*)varBuffer) )
647  nEPs++;
648  }
649  break;
650 
651  default:
652  if(!theSkipper.Skip(pp, pcntdn, dscrLen - 2))
653  return false;
654  }
655  theBuffer.pValue = varBuffer;
656  stateParseDescr = 0;
657  }
658  return true;
659 }
660 
661 /* Extracts endpoint information from config descriptor */
662 bool USBH_MIDI::EndpointXtract(uint8_t conf __attribute__((unused)),
663  uint8_t iface __attribute__((unused)),
664  uint8_t alt __attribute__((unused)),
665  uint8_t proto __attribute__((unused)),
666  const USB_ENDPOINT_DESCRIPTOR *pep)
667 {
668  uint8_t index;
669 
670 #ifdef DEBUG_USB_HOST
671  PrintEndpointDescriptor(pep);
672 #endif
673  // Is the endpoint transfer type bulk?
675  USBTRACE("+valid EP found.\r\n");
676  index = (pep->bEndpointAddress & 0x80) == 0x80 ? epDataInIndex : epDataOutIndex;
677  } else {
678  USBTRACE("-No valid EP found.\r\n");
679  return false;
680  }
681 
682  // Fill the rest of endpoint data structure
683  epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
684  // The maximum packet size for the USB Host Shield 2.0 library is 64 bytes.
687  } else {
688  epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize;
689  }
690 
691  return true;
692 }
USB::outTransfer
uint8_t outTransfer(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t *data)
Definition: Usb.cpp:303
USB_CONFIGURATION_DESCRIPTOR::bConfigurationValue
uint8_t bConfigurationValue
Definition: usb_ch9.h:128
USB_ENDPOINT_DESCRIPTOR::bInterval
uint8_t bInterval
Definition: usb_ch9.h:154
AddressPool::GetUsbDevicePtr
virtual UsbDevice * GetUsbDevicePtr(uint8_t addr)=0
USB_INTERFACE_DESCRIPTOR::bInterfaceClass
uint8_t bInterfaceClass
Definition: usb_ch9.h:141
AddressPool
Definition: address.h:90
EpInfo::bmSndToggle
uint8_t bmSndToggle
Definition: address.h:47
UsbDevice::lowspeed
bool lowspeed
Definition: address.h:86
USB::RegisterDeviceClass
uint8_t RegisterDeviceClass(USBDeviceConfig *pdev)
Definition: UsbCore.h:230
AddressPool::AllocAddress
virtual uint8_t AllocAddress(uint8_t parent, bool is_hub=false, uint8_t port=0)=0
USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE
#define USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE
Definition: UsbCore.h:98
USBH_MIDI::countSysExDataSize
uint16_t countSysExDataSize(uint8_t *dataptr)
Definition: usbh_midi.cpp:437
USBH_MIDI::pUsb
USB * pUsb
Definition: usbh_midi.h:87
USB::getDevDescr
uint8_t getDevDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t *dataptr)
defined(USB_METHODS_INLINE)
Definition: Usb.cpp:801
USB_ENDPOINT_DESCRIPTOR
Definition: usb_ch9.h:148
ByteSkipper::Initialize
void Initialize(MultiValueBuffer *pbuf)
Definition: parsetools.h:72
USB_INTERFACE_DESCRIPTOR::bInterfaceSubClass
uint8_t bInterfaceSubClass
Definition: usb_ch9.h:142
UsbMidiConfigXtracter::EndpointXtract
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
USBH_MIDI::bAddress
uint8_t bAddress
Definition: usbh_midi.h:88
USB_INTERFACE_DESCRIPTOR::bNumEndpoints
uint8_t bNumEndpoints
Definition: usb_ch9.h:140
USB_ENDPOINT_DESCRIPTOR::bLength
uint8_t bLength
Definition: usb_ch9.h:149
EpInfo::epAddr
uint8_t epAddr
Definition: address.h:40
MidiDescParser::Parse
void Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset)
Definition: usbh_midi.cpp:560
Notify
#define Notify(...)
Definition: message.h:51
USBH_MIDI_VERSION
#define USBH_MIDI_VERSION
Definition: usbh_midi.h:31
MIDI_MAX_SYSEX_SIZE
#define MIDI_MAX_SYSEX_SIZE
Definition: usbh_midi.h:35
USB_DESCRIPTOR_ENDPOINT
#define USB_DESCRIPTOR_ENDPOINT
Definition: usb_ch9.h:74
USBH_MIDI::vid
uint16_t vid
Definition: usbh_midi.h:90
USB_DESCRIPTOR_CONFIGURATION
#define USB_DESCRIPTOR_CONFIGURATION
Definition: usb_ch9.h:71
D_PrintHex
void D_PrintHex(T val, int lvl)
Definition: printhex.h:76
USB_CLASS_AUDIO
#define USB_CLASS_AUDIO
Definition: UsbCore.h:70
MultiByteValueParser::Parse
bool Parse(uint8_t **pp, uint16_t *pcntdn)
Definition: parsetools.cpp:26
USBH_MIDI::USBH_MIDI
USBH_MIDI(USB *p)
Definition: usbh_midi.cpp:85
USB_DEVICE_DESCRIPTOR
Definition: usb_ch9.h:105
EpInfo::bmNakPower
uint8_t bmNakPower
Definition: address.h:49
HID_DESCRIPTOR_HID
#define HID_DESCRIPTOR_HID
Definition: usb_ch9.h:80
USB_INTERFACE_DESCRIPTOR::bInterfaceNumber
uint8_t bInterfaceNumber
Definition: usb_ch9.h:138
USBH_MIDI::getMsgSizeFromCin
uint8_t getMsgSizeFromCin(uint8_t cin)
Definition: usbh_midi.h:103
USB::getConfDescr
uint8_t getConfDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t conf, uint8_t *dataptr)
Definition: Usb.cpp:806
USBH_MIDI::Init
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed)
Definition: usbh_midi.cpp:103
USBH_MIDI::epDataInIndex
static const uint8_t epDataInIndex
Definition: usbh_midi.h:83
UsbMidiConfigXtracter
Definition: usbh_midi.h:43
MidiDescParser::getConfValue
uint8_t getConfValue()
Definition: usbh_midi.h:75
USB_INTERFACE_DESCRIPTOR::bInterfaceProtocol
uint8_t bInterfaceProtocol
Definition: usb_ch9.h:143
USB_SUBCLASS_MIDISTREAMING
#define USB_SUBCLASS_MIDISTREAMING
Definition: usbh_midi.h:33
MultiByteValueParser::Initialize
void Initialize(MultiValueBuffer *const pbuf)
Definition: parsetools.h:54
USB_NAK_MAX_POWER
#define USB_NAK_MAX_POWER
Definition: address.h:34
USBH_MIDI::recvBuf
uint8_t recvBuf[MIDI_EVENT_PACKET_SIZE]
Definition: usbh_midi.h:95
USB_DESCRIPTOR_INTERFACE
#define USB_DESCRIPTOR_INTERFACE
Definition: usb_ch9.h:73
USBH_MIDI::convertStatus2Cin
uint8_t convertStatus2Cin(uint8_t status)
Definition: usbh_midi.h:100
bmUSB_TRANSFER_TYPE
#define bmUSB_TRANSFER_TYPE
Definition: usb_ch9.h:94
USBH_MIDI::setupDeviceSpecific
void setupDeviceSpecific()
Definition: usbh_midi.cpp:286
USBH_MIDI::lookupMsgSize
uint8_t lookupMsgSize(uint8_t midiMsg, uint8_t cin=0)
Definition: usbh_midi.cpp:428
EpInfo
Definition: address.h:39
USB_ENDPOINT_DESCRIPTOR::bEndpointAddress
uint8_t bEndpointAddress
Definition: usb_ch9.h:151
USB_NAK_NOWAIT
#define USB_NAK_NOWAIT
Definition: address.h:36
EpInfo::bmRcvToggle
uint8_t bmRcvToggle
Definition: address.h:48
MIDI_MAX_ENDPOINTS
#define MIDI_MAX_ENDPOINTS
Definition: usbh_midi.h:32
USBH_MIDI::extractSysExData
uint8_t extractSysExData(uint8_t *p, uint8_t *buf)
Definition: usbh_midi.cpp:516
USBH_MIDI::SendData
uint8_t SendData(uint8_t *dataptr, uint8_t nCable=0)
Definition: usbh_midi.cpp:366
USB_CONFIGURATION_DESCRIPTOR
Definition: usb_ch9.h:123
USB
Definition: UsbCore.h:210
USB::inTransfer
uint8_t inTransfer(uint8_t addr, uint8_t ep, uint16_t *nbytesptr, uint8_t *data, uint8_t bInterval=0)
Definition: Usb.cpp:209
MidiDescParser
Definition: usbh_midi.h:53
usbh_midi.h
USB_ERROR_EPINFO_IS_NULL
#define USB_ERROR_EPINFO_IS_NULL
Definition: UsbCore.h:96
UsbDevice
Definition: address.h:82
USBH_MIDI::pid
uint16_t pid
Definition: usbh_midi.h:90
USB_ENDPOINT_DESCRIPTOR::bDescriptorType
uint8_t bDescriptorType
Definition: usb_ch9.h:150
USBH_MIDI::Release
virtual uint8_t Release()
Definition: usbh_midi.cpp:276
USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL
#define USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL
Definition: UsbCore.h:95
ByteSkipper::Skip
bool Skip(uint8_t **pp, uint16_t *pcntdn, uint16_t bytes_to_skip)
Definition: parsetools.h:77
USBH_MIDI::bPollEnable
bool bPollEnable
Definition: usbh_midi.h:89
USB::setConf
uint8_t setConf(uint8_t addr, uint8_t ep, uint8_t conf_value)
Definition: Usb.cpp:845
USBTRACE
#define USBTRACE(s)
Definition: macros.h:82
PSTR
#define PSTR(str)
Definition: version_helper.h:54
USBTRACE2
#define USBTRACE2(s, r)
Definition: macros.h:84
USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL
#define USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL
Definition: UsbCore.h:93
MultiValueBuffer::pValue
void * pValue
Definition: parsetools.h:32
MidiDescParser::getNumEPs
uint8_t getNumEPs()
Definition: usbh_midi.h:76
USBH_MIDI::bTransferTypeMask
uint8_t bTransferTypeMask
Definition: usbh_midi.h:91
USBH_MIDI::EndpointXtract
bool EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep)
Definition: usbh_midi.cpp:662
USBH_MIDI::readPtr
uint8_t readPtr
Definition: usbh_midi.h:96
AddressPool::FreeAddress
virtual void FreeAddress(uint8_t addr)=0
USB::setAddr
uint8_t setAddr(uint8_t oldaddr, uint8_t ep, uint8_t newaddr)
Definition: Usb.cpp:836
USBH_MIDI::SendSysEx
uint8_t SendSysEx(uint8_t *dataptr, uint16_t datasize, uint8_t nCable=0)
Definition: usbh_midi.cpp:459
EpInfo::maxPktSize
uint8_t maxPktSize
Definition: address.h:41
USB::setEpInfoEntry
uint8_t setEpInfoEntry(uint8_t addr, uint8_t epcount, EpInfo *eprecord_ptr)
Definition: Usb.cpp:64
USB_ENDPOINT_DESCRIPTOR::bmAttributes
uint8_t bmAttributes
Definition: usb_ch9.h:152
USB_INTERFACE_DESCRIPTOR::bAlternateSetting
uint8_t bAlternateSetting
Definition: usb_ch9.h:139
MultiValueBuffer::valueSize
uint8_t valueSize
Definition: parsetools.h:31
MidiDescParser::MidiDescParser
MidiDescParser(UsbMidiConfigXtracter *xtractor, bool modeMidi)
Definition: usbh_midi.cpp:549
MIDI_EVENT_PACKET_SIZE
#define MIDI_EVENT_PACKET_SIZE
Definition: usbh_midi.h:34
USBH_MIDI::epInfo
EpInfo epInfo[MIDI_MAX_ENDPOINTS]
Definition: usbh_midi.h:93
USBH_MIDI::epDataOutIndex
static const uint8_t epDataOutIndex
Definition: usbh_midi.h:84
USB_TRANSFER_TYPE_BULK
#define USB_TRANSFER_TYPE_BULK
Definition: usb_ch9.h:92
USBH_MIDI::RecvData
uint8_t RecvData(uint16_t *bytes_rcvd, uint8_t *dataptr)
Definition: usbh_midi.cpp:308
USB_INTERFACE_DESCRIPTOR
Definition: usb_ch9.h:135
USB::GetAddressPool
AddressPool & GetAddressPool()
Definition: UsbCore.h:226
USB_ENDPOINT_DESCRIPTOR::wMaxPacketSize
uint16_t wMaxPacketSize
Definition: usb_ch9.h:153
UsbDevice::epinfo
EpInfo * epinfo
Definition: address.h:83