Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion micropython/usb/usb-device-midi/manifest.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
metadata(version="0.1.0")
metadata(version="0.1.1")
require("usb-device")
package("usb")
23 changes: 19 additions & 4 deletions micropython/usb/usb-device-midi/usb/device/midi.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ def __init__(self, rxlen=16, txlen=16):
self.ep_in = None # TX direction (device to host)
self._rx = Buffer(rxlen)
self._tx = Buffer(txlen)
self._on_rx_schedule = False

# Callbacks for handling received MIDI messages.
#
Expand Down Expand Up @@ -147,10 +148,22 @@ def _rx_xfer(self):
self.submit_xfer(self.ep_out, self._rx.pend_write(), self._rx_cb)

def _rx_cb(self, ep, res, num_bytes):
if res == 0:
self._rx.finish_write(num_bytes)
schedule(self._on_rx, None)
self._rx_xfer()
# This function assumes it's only called via an irq (soft or hard), and therefore
# it won't be interrupted by its own scheduled callback until it finishes.
try:
if res == 0:
# Queue at most one concurrent call to self._on_rx, as each execution
# will read all the bytes queued in self._rx buffer
if not self._on_rx_schedule:
schedule(self._on_rx, None)
self._on_rx_schedule = True
# Ordering so that if the schedule() call fails, the bytes
# already in the buffer will be lost (overwritten by the next
# xfer). This prevents wedging the MIDI RX path with a full buffer
# and no call to _on_rx pending.
self._rx.finish_write(num_bytes)
finally:
self._rx_xfer()

def on_open(self):
super().on_open()
Expand All @@ -160,13 +173,15 @@ def on_open(self):

def _on_rx(self, _):
# Receive MIDI events. Called via micropython.schedule, outside of the USB callback function.
self._on_rx_schedule = False
m = self._rx.pend_read()
i = 0
while i <= len(m) - 4:
cin = m[i] & 0x0F
self.on_midi_event(cin, m[i + 1], m[i + 2], m[i + 3])
i += 4
self._rx.finish_read(i)
self._rx_xfer() # resume xfer if needed because _rx buffer was previously full

def desc_cfg(self, desc, itf_num, ep_num, strs):
# Start by registering a USB Audio Control interface, that is required to point to the
Expand Down
Loading