1111* Author(s): Scott Shawcroft
1212"""
1313
14+ import usb .core
1415import adafruit_usb_host_descriptors
1516
1617__version__ = "0.0.0+auto.0"
1920
2021DIR_IN = 0x80
2122
23+
2224class MIDI :
23- def __init__ (self , device ):
25+ """
26+ Stream-like MIDI device for use with ``adafruit_midi`` and similar upstream
27+ MIDI parser libraries.
28+
29+ :param device: a ``usb.core.Device`` object which implements
30+ ``read(endpoint, buffer)`` and ``write(endpoint,buffer)``
31+ :param float timeout: timeout in seconds to wait for read or write operation
32+ to succeeds. Default to None, i.e. reads and writes will block.
33+ """
34+
35+ def __init__ (self , device , timeout = None ):
2436 self .interface_number = 0
2537 self .in_ep = 0
2638 self .out_ep = 0
2739 self .device = device
40+ self .timeout_ms = round (timeout * 1000 ) if timeout else 0
2841
2942 self .buf = bytearray (64 )
3043 self .start = 0
@@ -40,14 +53,16 @@ def __init__(self, device):
4053 descriptor_len = config_descriptor [i ]
4154 descriptor_type = config_descriptor [i + 1 ]
4255 if descriptor_type == adafruit_usb_host_descriptors .DESC_CONFIGURATION :
56+ # pylint: disable=unused-variable
4357 config_value = config_descriptor [i + 5 ]
58+ # pylint: enable=unused-variable
4459 elif descriptor_type == adafruit_usb_host_descriptors .DESC_INTERFACE :
4560 interface_number = config_descriptor [i + 2 ]
4661 interface_class = config_descriptor [i + 5 ]
4762 interface_subclass = config_descriptor [i + 6 ]
4863 midi_interface = interface_class == 0x1 and interface_subclass == 0x3
4964 if midi_interface :
50- self .interface_number = interface_number
65+ self .interface_number = interface_number
5166
5267 elif descriptor_type == adafruit_usb_host_descriptors .DESC_ENDPOINT :
5368 endpoint_address = config_descriptor [i + 2 ]
@@ -63,11 +78,50 @@ def __init__(self, device):
6378 device .detach_kernel_driver (self .interface_number )
6479
6580 def read (self , size ):
81+ """
82+ Read bytes. If ``nbytes`` is specified then read at most that many
83+ bytes. Otherwise, read everything that arrives until the connection
84+ times out. Providing the number of bytes expected is highly recommended
85+ because it will be faster. If no bytes are read, return ``None``.
86+
87+ .. note:: When no bytes are read due to a timeout, this function returns ``None``.
88+ This matches the behavior of `io.RawIOBase.read` in Python 3, but
89+ differs from pyserial which returns ``b''`` in that situation.
90+
91+ :return: Data read
92+ :rtype: bytes or None
93+ """
94+
6695 if self ._remaining == 0 :
67- self ._remaining = self .device .read (self .in_ep , self .buf ) - 1
68- self .start = 1
96+ try :
97+ n = self .device .read (self .in_ep , self .buf , self .timeout_ms )
98+ self ._remaining = n - 1
99+ self .start = 1
100+ except usb .core .USBTimeoutError :
101+ pass
69102 size = min (size , self ._remaining )
70- b = self .buf [self .start : self .start + size ]
103+ b = self .buf [self .start : self .start + size ]
71104 self .start += size
72105 self ._remaining -= size
73106 return b
107+
108+ def readinto (self , buf ):
109+ """Read bytes into the ``buf``. Read at most ``len(buf)`` bytes.
110+
111+ :return: number of bytes read and stored into ``buf``
112+ :rtype: int or None (on a non-blocking error)
113+ """
114+ b = self .read (len (buf ))
115+ n = len (b )
116+ if n :
117+ buf [:] = b
118+ return n
119+
120+ def __repr__ (self ):
121+ # also idProduct/idVendor for vid/pid
122+ return (
123+ "MIDI Device "
124+ + str (self .device .manufacturer )
125+ + "/"
126+ + str (self .device .product )
127+ )
0 commit comments