diff --git a/micropython/usb/usb-device-midi/manifest.py b/micropython/usb/usb-device-midi/manifest.py index af9b8cb84..4520325e3 100644 --- a/micropython/usb/usb-device-midi/manifest.py +++ b/micropython/usb/usb-device-midi/manifest.py @@ -1,3 +1,3 @@ -metadata(version="0.1.0") +metadata(version="0.1.1") require("usb-device") package("usb") diff --git a/micropython/usb/usb-device-midi/usb/device/midi.py b/micropython/usb/usb-device-midi/usb/device/midi.py index 55bfbd08b..f484a079f 100644 --- a/micropython/usb/usb-device-midi/usb/device/midi.py +++ b/micropython/usb/usb-device-midi/usb/device/midi.py @@ -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. # @@ -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() @@ -160,6 +173,7 @@ 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: @@ -167,6 +181,7 @@ def _on_rx(self, _): 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