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-2016 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"
29 // MIDI MESAGES
30 // midi.org/techspecs/
32 // STATUS BYTES
33 // 0x8n == noteOff
34 // 0x9n == noteOn
35 // 0xAn == afterTouch
36 // 0xBn == controlChange
37 // n == Channel(0x0-0xf)
39 //DATA BYTE 1
40 // note# == (0-127)
41 // or
42 // control# == (0-119)
44 // DATA BYTE 2
45 // velocity == (0-127)
46 // or
47 // controlVal == (0-127)
49 // USB-MIDI Event Packets
50 // usb.org - Universal Serial Bus Device Class Definition for MIDI Devices 1.0
52 //+-------------+-------------+-------------+-------------+
53 //| Byte 0 | Byte 1 | Byte 2 | Byte 3 |
54 //+------+------+-------------+-------------+-------------+
55 //|Cable | Code | | | |
56 //|Number|Index | MIDI_0 | MIDI_1 | MIDI_2 |
57 //| |Number| | | |
58 //|(4bit)|(4bit)| (8bit) | (8bit) | (8bit) |
59 //+------+------+-------------+-------------+-------------+
60 // CN == 0x0-0xf
61 //+-----+-----------+-------------------------------------------------------------------
62 //| CIN |MIDI_x size|Description
63 //+-----+-----------+-------------------------------------------------------------------
64 //| 0x0 | 1, 2 or 3 |Miscellaneous function codes. Reserved for future extensions.
65 //| 0x1 | 1, 2 or 3 |Cable events. Reserved for future expansion.
66 //| 0x2 | 2 |Two-byte System Common messages like MTC, SongSelect, etc.
67 //| 0x3 | 3 |Three-byte System Common messages like SPP, etc.
68 //| 0x4 | 3 |SysEx starts or continues
69 //| 0x5 | 1 |Single-byte System Common Message or SysEx ends with following single byte.
70 //| 0x6 | 2 |SysEx ends with following two bytes.
71 //| 0x7 | 3 |SysEx ends with following three bytes.
72 //| 0x8 | 3 |Note-off
73 //| 0x9 | 3 |Note-on
74 //| 0xA | 3 |Poly-KeyPress
75 //| 0xB | 3 |Control Change
76 //| 0xC | 2 |Program Change
77 //| 0xD | 2 |Channel Pressure
78 //| 0xE | 3 |PitchBend Change
79 //| 0xF | 1 |Single Byte
80 //+-----+-----------+-------------------------------------------------------------------
81 
82 const uint8_t USBH_MIDI::epDataInIndex = 1;
83 const uint8_t USBH_MIDI::epDataOutIndex = 2;
84 const uint8_t USBH_MIDI::epDataInIndexVSP = 3;
85 const uint8_t USBH_MIDI::epDataOutIndexVSP = 4;
86 
88 pUsb(p),
89 bAddress(0),
90 bNumEP(1),
91 bPollEnable(false),
92 isMidiFound(false),
93 readPtr(0) {
94  // initialize endpoint data structures
95  for(uint8_t i=0; i<MIDI_MAX_ENDPOINTS; i++) {
96  epInfo[i].epAddr = 0;
97  epInfo[i].maxPktSize = (i) ? 0 : 8;
98  epInfo[i].epAttribs = 0;
99 // epInfo[i].bmNakPower = (i) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER;
100  epInfo[i].bmNakPower = (i) ? USB_NAK_NOWAIT : 4;
101 
102  }
103  // register in USB subsystem
104  if (pUsb) {
105  pUsb->RegisterDeviceClass(this);
106  }
107 }
108 
109 /* Connection initialization of an MIDI Device */
110 uint8_t USBH_MIDI::Init(uint8_t parent, uint8_t port, bool lowspeed)
111 {
112  uint8_t buf[DESC_BUFF_SIZE];
113  USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf);
114  uint8_t rcode;
115  UsbDevice *p = NULL;
116  EpInfo *oldep_ptr = NULL;
117  uint8_t num_of_conf; // number of configurations
118 
119  // get memory address of USB device address pool
120  AddressPool &addrPool = pUsb->GetAddressPool();
121 #ifdef DEBUG_USB_HOST
122  USBTRACE("\rMIDI Init\r\n");
123 #endif
124  // check if address has already been assigned to an instance
125  if (bAddress) {
127  }
128  // Get pointer to pseudo device with address 0 assigned
129  p = addrPool.GetUsbDevicePtr(bAddress);
130  if (!p) {
132  }
133  if (!p->epinfo) {
135  }
136 
137  // Save old pointer to EP_RECORD of address 0
138  oldep_ptr = p->epinfo;
139 
140  // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
141  p->epinfo = epInfo;
142  p->lowspeed = lowspeed;
143 
144  // Get device descriptor
145  rcode = pUsb->getDevDescr( 0, 0, sizeof(USB_DEVICE_DESCRIPTOR), (uint8_t*)buf );
146  vid = udd->idVendor;
147  pid = udd->idProduct;
148  // Restore p->epinfo
149  p->epinfo = oldep_ptr;
150 
151  if( rcode ){
152  goto FailGetDevDescr;
153  }
154 
155  // Allocate new address according to device class
156  bAddress = addrPool.AllocAddress(parent, false, port);
157  if (!bAddress) {
159  }
160 
161  // Extract Max Packet Size from device descriptor
163 
164  // Assign new address to the device
165  rcode = pUsb->setAddr( 0, 0, bAddress );
166  if (rcode) {
167  p->lowspeed = false;
168  addrPool.FreeAddress(bAddress);
169  bAddress = 0;
170  return rcode;
171  }//if (rcode...
172 #ifdef DEBUG_USB_HOST
173  USBTRACE2("Addr:", bAddress);
174 #endif
175  p->lowspeed = false;
176 
177  //get pointer to assigned address record
178  p = addrPool.GetUsbDevicePtr(bAddress);
179  if (!p) {
181  }
182  p->lowspeed = lowspeed;
183 
184  num_of_conf = udd->bNumConfigurations;
185 
186  // Assign epInfo to epinfo pointer
187  rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
188  if (rcode) {
189 #ifdef DEBUG_USB_HOST
190  USBTRACE("setEpInfoEntry failed");
191 #endif
192  goto FailSetDevTblEntry;
193  }
194 #ifdef DEBUG_USB_HOST
195  USBTRACE2("NC:", num_of_conf);
196 #endif
197  for (uint8_t i=0; i<num_of_conf; i++) {
199  if (bNumEP > 1)
200  break;
201  } // for
202 #ifdef DEBUG_USB_HOST
203  USBTRACE2("NumEP:", bNumEP);
204 #endif
205  if( bConfNum == 0 ){ //Device not found.
206  goto FailGetConfDescr;
207  }
208 
209  if( !isMidiFound ){ //MIDI Device not found. Try first Bulk transfer device
214  }
215 
216  // Assign epInfo to epinfo pointer
218 #ifdef DEBUG_USB_HOST
219  USBTRACE2("Conf:", bConfNum);
220 #endif
221  // Set Configuration Value
222  rcode = pUsb->setConf(bAddress, 0, bConfNum);
223  if (rcode) {
224  goto FailSetConfDescr;
225  }
226 #ifdef DEBUG_USB_HOST
227  USBTRACE("Init done.");
228 #endif
229  bPollEnable = true;
230  return 0;
231 FailGetDevDescr:
232 FailSetDevTblEntry:
233 FailGetConfDescr:
234 FailSetConfDescr:
235  Release();
236  return rcode;
237 }
238 
239 /* get and parse config descriptor */
240 void USBH_MIDI::parseConfigDescr( byte addr, byte conf )
241 {
242  uint8_t buf[ DESC_BUFF_SIZE ];
243  uint8_t* buf_ptr = buf;
244  byte rcode;
245  byte descr_length;
246  byte descr_type;
247  unsigned int total_length;
248  USB_ENDPOINT_DESCRIPTOR *epDesc;
249  boolean isMidi = false;
250 
251  // get configuration descriptor (get descriptor size only)
252  rcode = pUsb->getConfDescr( addr, 0, 4, conf, buf );
253  if( rcode ){
254  return;
255  }
256  total_length = buf[2] | ((int)buf[3] << 8);
257  if( total_length > DESC_BUFF_SIZE ) { //check if total length is larger than buffer
258  total_length = DESC_BUFF_SIZE;
259  }
260 
261  // get configuration descriptor (all)
262  rcode = pUsb->getConfDescr( addr, 0, total_length, conf, buf ); //get the whole descriptor
263  if( rcode ){
264  return;
265  }
266 
267  //parsing descriptors
268  while( buf_ptr < buf + total_length ) {
269  descr_length = *( buf_ptr );
270  descr_type = *( buf_ptr + 1 );
271  switch( descr_type ) {
273  bConfNum = buf_ptr[5];
274  break;
276  if( buf_ptr[5] == USB_CLASS_AUDIO && buf_ptr[6] == USB_SUBCLASS_MIDISTREAMING ) { //p[5]; bInterfaceClass = 1(Audio), p[6]; bInterfaceSubClass = 3(MIDI Streaming)
277  isMidiFound = true; //MIDI device found.
278  isMidi = true;
279  }else{
280 #ifdef DEBUG_USB_HOST
281  USBTRACE("No MIDI Device\n");
282 #endif
283  isMidi = false;
284  }
285  break;
287  epDesc = (USB_ENDPOINT_DESCRIPTOR *)buf_ptr;
288  if ((epDesc->bmAttributes & 0x02) == 2) {//bulk
289  uint8_t index;
290  if( isMidi )
291  index = ((epDesc->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex;
292  else
293  index = ((epDesc->bEndpointAddress & 0x80) == 0x80) ? epDataInIndexVSP : epDataOutIndexVSP;
294  epInfo[index].epAddr = (epDesc->bEndpointAddress & 0x0F);
295  epInfo[index].maxPktSize = (uint8_t)epDesc->wMaxPacketSize;
296  bNumEP ++;
297 #ifdef DEBUG_USB_HOST
298  PrintEndpointDescriptor(epDesc);
299 #endif
300  }
301  break;
302  default:
303  break;
304  }//switch( descr_type
305  buf_ptr += descr_length; //advance buffer pointer
306  }//while( buf_ptr <=...
307 }
308 
309 /* Performs a cleanup after failed Init() attempt */
311 {
313  bNumEP = 1; //must have to be reset to 1
314  bAddress = 0;
315  bPollEnable = false;
316  readPtr = 0;
317  return 0;
318 }
319 
320 /* Receive data from MIDI device */
321 uint8_t USBH_MIDI::RecvData(uint16_t *bytes_rcvd, uint8_t *dataptr)
322 {
323  *bytes_rcvd = (uint16_t)epInfo[epDataInIndex].maxPktSize;
324  uint8_t r = pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, bytes_rcvd, dataptr);
325 
326  if( *bytes_rcvd < (MIDI_EVENT_PACKET_SIZE-4)){
327  dataptr[*bytes_rcvd] = '\0';
328  dataptr[(*bytes_rcvd)+1] = '\0';
329  }
330  return r;
331 }
332 
333 /* Receive data from MIDI device */
334 uint8_t USBH_MIDI::RecvData(uint8_t *outBuf)
335 {
336  byte rcode = 0; //return code
337  uint16_t rcvd;
338 
339  if( bPollEnable == false ) return false;
340 
341  //Checking unprocessed message in buffer.
342  if( readPtr != 0 && readPtr < MIDI_EVENT_PACKET_SIZE ){
343  if(recvBuf[readPtr] == 0 && recvBuf[readPtr+1] == 0) {
344  //no unprocessed message left in the buffer.
345  }else{
346  goto RecvData_return_from_buffer;
347  }
348  }
349 
350  readPtr = 0;
351  rcode = RecvData( &rcvd, recvBuf);
352  if( rcode != 0 ) {
353  return 0;
354  }
355 
356  //if all data is zero, no valid data received.
357  if( recvBuf[0] == 0 && recvBuf[1] == 0 && recvBuf[2] == 0 && recvBuf[3] == 0 ) {
358  return 0;
359  }
360 
361 RecvData_return_from_buffer:
362  readPtr++;
363  outBuf[0] = recvBuf[readPtr];
364  readPtr++;
365  outBuf[1] = recvBuf[readPtr];
366  readPtr++;
367  outBuf[2] = recvBuf[readPtr];
368  readPtr++;
369  return lookupMsgSize(outBuf[0]);
370 }
371 
372 /* Send data to MIDI device */
373 uint8_t USBH_MIDI::SendData(uint8_t *dataptr, byte nCable)
374 {
375  byte buf[4];
376  byte msg;
377 
378  msg = dataptr[0];
379  // SysEx long message ?
380  if( msg == 0xf0 )
381  {
382  return SendSysEx(dataptr, countSysExDataSize(dataptr), nCable);
383  }
384 
385  buf[0] = (nCable << 4) | (msg >> 4);
386  if( msg < 0xf0 ) msg = msg & 0xf0;
387 
388 
389  //Building USB-MIDI Event Packets
390  buf[1] = dataptr[0];
391  buf[2] = dataptr[1];
392  buf[3] = dataptr[2];
393 
394  switch(lookupMsgSize(msg)) {
395  //3 bytes message
396  case 3 :
397  if(msg == 0xf2) {//system common message(SPP)
398  buf[0] = (nCable << 4) | 3;
399  }
400  break;
401 
402  //2 bytes message
403  case 2 :
404  if(msg == 0xf1 || msg == 0xf3) {//system common message(MTC/SongSelect)
405  buf[0] = (nCable << 4) | 2;
406  }
407  buf[3] = 0;
408  break;
409 
410  //1 bytes message
411  case 1 :
412  default :
413  buf[2] = 0;
414  buf[3] = 0;
415  break;
416  }
417  return pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, 4, buf);
418 }
419 
420 #ifdef DEBUG_USB_HOST
421 void USBH_MIDI::PrintEndpointDescriptor( const USB_ENDPOINT_DESCRIPTOR* ep_ptr )
422 {
423  Notify(PSTR("Endpoint descriptor:"), 0x80);
424  Notify(PSTR("\r\nLength:\t\t"), 0x80);
425  PrintHex<uint8_t>(ep_ptr->bLength, 0x80);
426  Notify(PSTR("\r\nType:\t\t"), 0x80);
427  PrintHex<uint8_t>(ep_ptr->bDescriptorType, 0x80);
428  Notify(PSTR("\r\nAddress:\t"), 0x80);
429  PrintHex<uint8_t>(ep_ptr->bEndpointAddress, 0x80);
430  Notify(PSTR("\r\nAttributes:\t"), 0x80);
431  PrintHex<uint8_t>(ep_ptr->bmAttributes, 0x80);
432  Notify(PSTR("\r\nMaxPktSize:\t"), 0x80);
433  PrintHex<uint16_t>(ep_ptr->wMaxPacketSize, 0x80);
434  Notify(PSTR("\r\nPoll Intrv:\t"), 0x80);
435  PrintHex<uint8_t>(ep_ptr->bInterval, 0x80);
436  Notify(PSTR("\r\n"), 0x80);
437 }
438 #endif
439 
440 /* look up a MIDI message size from spec */
441 /*Return */
442 /* 0 : undefined message */
443 /* 0<: Vaild message size(1-3) */
444 uint8_t USBH_MIDI::lookupMsgSize(uint8_t midiMsg)
445 {
446  uint8_t msgSize = 0;
447 
448  if( midiMsg < 0xf0 ) midiMsg &= 0xf0;
449  switch(midiMsg) {
450  //3 bytes messages
451  case 0xf2 : //system common message(SPP)
452  case 0x80 : //Note off
453  case 0x90 : //Note on
454  case 0xa0 : //Poly KeyPress
455  case 0xb0 : //Control Change
456  case 0xe0 : //PitchBend Change
457  msgSize = 3;
458  break;
459 
460  //2 bytes messages
461  case 0xf1 : //system common message(MTC)
462  case 0xf3 : //system common message(SongSelect)
463  case 0xc0 : //Program Change
464  case 0xd0 : //Channel Pressure
465  msgSize = 2;
466  break;
467 
468  //1 bytes messages
469  case 0xf8 : //system realtime message
470  case 0xf9 : //system realtime message
471  case 0xfa : //system realtime message
472  case 0xfb : //system realtime message
473  case 0xfc : //system realtime message
474  case 0xfe : //system realtime message
475  case 0xff : //system realtime message
476  msgSize = 1;
477  break;
478 
479  //undefine messages
480  default :
481  break;
482  }
483  return msgSize;
484 }
485 
486 /* SysEx data size counter */
487 unsigned int USBH_MIDI::countSysExDataSize(uint8_t *dataptr)
488 {
489  unsigned int c = 1;
490 
491  if( *dataptr != 0xf0 ){ //not SysEx
492  return 0;
493  }
494 
495  //Search terminator(0xf7)
496  while(*dataptr != 0xf7)
497  {
498  dataptr++;
499  c++;
500 
501  //Limiter (upto 256 bytes)
502  if(c > 256){
503  c = 0;
504  break;
505  }
506  }
507  return c;
508 }
509 
510 /* Send SysEx message to MIDI device */
511 uint8_t USBH_MIDI::SendSysEx(uint8_t *dataptr, unsigned int datasize, byte nCable)
512 {
513  byte buf[4];
514  uint8_t rc;
515  unsigned int n = datasize;
516 
517  while(n > 0) {
518  //Byte 0
519  buf[0] = (nCable << 4) | 0x4; //x4 SysEx starts or continues
520 
521  switch ( n ) {
522  case 1 :
523  buf[0] = (nCable << 4) | 0x5; //x5 SysEx ends with following single byte.
524  buf[1] = *(dataptr++);
525  buf[2] = 0x00;
526  buf[3] = 0x00;
527  n = n - 1;
528  break;
529  case 2 :
530  buf[0] = (nCable << 4) | 0x6; //x6 SysEx ends with following two bytes.
531  buf[1] = *(dataptr++);
532  buf[2] = *(dataptr++);
533  buf[3] = 0x00;
534  n = n - 2;
535  break;
536  case 3 :
537  buf[0] = (nCable << 4) | 0x7; //x7 SysEx ends with following three bytes.
538  default :
539  buf[1] = *(dataptr++);
540  buf[2] = *(dataptr++);
541  buf[3] = *(dataptr++);
542  n = n - 3;
543  break;
544  }
545  rc = pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, 4, buf);
546  if(rc != 0)
547  break;
548  }
549  return(rc);
550 }
uint8_t getConfDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t conf, uint8_t *dataptr)
Definition: Usb.cpp:771
static const uint8_t epDataInIndexVSP
Definition: usbh_midi.h:45
EpInfo * epinfo
Definition: address.h:76
bool lowspeed
Definition: address.h:79
#define USB_ERROR_EPINFO_IS_NULL
Definition: UsbCore.h:83
uint8_t readPtr
Definition: usbh_midi.h:60
uint8_t bmNakPower
Definition: address.h:42
uint8_t RecvData(uint16_t *bytes_rcvd, uint8_t *dataptr)
Definition: usbh_midi.cpp:321
uint8_t bMaxPacketSize0
Definition: usb_ch9.h:105
uint16_t vid
Definition: usbh_midi.h:68
uint8_t setConf(uint8_t addr, uint8_t ep, uint8_t conf_value)
Definition: Usb.cpp:810
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed)
Definition: usbh_midi.cpp:110
#define USB_DESCRIPTOR_ENDPOINT
Definition: usb_ch9.h:67
#define USB_SUBCLASS_MIDISTREAMING
Definition: usbh_midi.h:32
uint8_t setEpInfoEntry(uint8_t addr, uint8_t epcount, EpInfo *eprecord_ptr)
Definition: Usb.cpp:64
USB * pUsb
Definition: usbh_midi.h:49
void parseConfigDescr(byte addr, byte conf)
Definition: usbh_midi.cpp:240
virtual void FreeAddress(uint8_t addr)=0
uint8_t epAttribs
Definition: address.h:37
static const uint8_t epDataOutIndexVSP
Definition: usbh_midi.h:46
#define USB_DESCRIPTOR_CONFIGURATION
Definition: usb_ch9.h:64
virtual UsbDevice * GetUsbDevicePtr(uint8_t addr)=0
#define Notify(...)
Definition: message.h:44
#define USBTRACE2(s, r)
Definition: macros.h:77
uint8_t setAddr(uint8_t oldaddr, uint8_t ep, uint8_t newaddr)
Definition: Usb.cpp:801
uint8_t epAddr
Definition: address.h:33
uint8_t bNumEP
Definition: usbh_midi.h:52
uint8_t bAddress
Definition: usbh_midi.h:50
Definition: address.h:32
uint16_t pid
Definition: usbh_midi.h:68
uint8_t outTransfer(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t *data)
Definition: Usb.cpp:293
virtual uint8_t Release()
Definition: usbh_midi.cpp:310
uint16_t wMaxPacketSize
Definition: usb_ch9.h:146
#define USB_CLASS_AUDIO
Definition: UsbCore.h:57
bool isMidiFound
Definition: usbh_midi.h:55
unsigned int countSysExDataSize(uint8_t *dataptr)
Definition: usbh_midi.cpp:487
bool bPollEnable
Definition: usbh_midi.h:53
USBH_MIDI(USB *p)
Definition: usbh_midi.cpp:87
virtual uint8_t AllocAddress(uint8_t parent, bool is_hub=false, uint8_t port=0)=0
uint8_t bEndpointAddress
Definition: usb_ch9.h:144
#define USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE
Definition: UsbCore.h:85
#define PSTR(str)
static const uint8_t epDataInIndex
Definition: usbh_midi.h:43
#define MIDI_EVENT_PACKET_SIZE
Definition: usbh_midi.h:34
#define USB_NAK_NOWAIT
Definition: address.h:29
uint8_t SendData(uint8_t *dataptr, byte nCable=0)
Definition: usbh_midi.cpp:373
uint8_t recvBuf[MIDI_EVENT_PACKET_SIZE]
Definition: usbh_midi.h:59
#define USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL
Definition: UsbCore.h:82
uint16_t idProduct
Definition: usb_ch9.h:107
uint8_t bConfNum
Definition: usbh_midi.h:51
EpInfo epInfo[MIDI_MAX_ENDPOINTS]
Definition: usbh_midi.h:57
uint8_t inTransfer(uint8_t addr, uint8_t ep, uint16_t *nbytesptr, uint8_t *data, uint8_t bInterval=0)
Definition: Usb.cpp:206
uint8_t bNumConfigurations
Definition: usb_ch9.h:112
#define USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL
Definition: UsbCore.h:80
static const uint8_t epDataOutIndex
Definition: usbh_midi.h:44
#define MIDI_MAX_ENDPOINTS
Definition: usbh_midi.h:31
uint8_t maxPktSize
Definition: address.h:34
AddressPool & GetAddressPool()
Definition: UsbCore.h:213
Definition: UsbCore.h:197
#define DESC_BUFF_SIZE
Definition: usbh_midi.h:33
uint8_t RegisterDeviceClass(USBDeviceConfig *pdev)
Definition: UsbCore.h:217
#define USBTRACE(s)
Definition: macros.h:75
uint8_t getDevDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t *dataptr)
defined(USB_METHODS_INLINE)
Definition: Usb.cpp:766
uint8_t SendSysEx(uint8_t *dataptr, unsigned int datasize, byte nCable=0)
Definition: usbh_midi.cpp:511
#define USB_DESCRIPTOR_INTERFACE
Definition: usb_ch9.h:66