Merge pull request #1449 from tannewt/midi

Add USB MIDI support for SAMD and nRF.
This commit is contained in:
Dan Halbert 2019-01-10 19:49:33 -05:00 committed by GitHub
commit 516d7da641
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 765 additions and 44 deletions

View File

@ -21,7 +21,7 @@ git:
# that SDK is shortest and add it there. In the case of major re-organizations,
# just try to make the builds "about equal in run time"
env:
- TRAVIS_TESTS="unix docs translations website" TRAVIS_BOARDS="feather_huzzah circuitplayground_express mini_sam_m4 grandcentral_m4_express pca10056 pca10059 feather_nrf52832 feather_nrf52840_express makerdiary_nrf52840_mdk particle_boron particle_argon particle_xenon sparkfun_nrf52840_mini" TRAVIS_SDK=arm:nrf:esp8266
- TRAVIS_TESTS="unix docs translations website" TRAVIS_BOARDS="feather_huzzah circuitplayground_express mini_sam_m4 grandcentral_m4_express pca10056 pca10059 feather_nrf52840_express makerdiary_nrf52840_mdk particle_boron particle_argon particle_xenon sparkfun_nrf52840_mini" TRAVIS_SDK=arm:nrf:esp8266
- TRAVIS_BOARDS="metro_m0_express metro_m4_express pirkey_m0 trellis_m4_express trinket_m0" TRAVIS_SDK=arm
- TRAVIS_BOARDS="feather_radiofruit_zigbee gemma_m0 hallowing_m0_express itsybitsy_m0_express itsybitsy_m4_express meowmeow" TRAVIS_SDK=arm
- TRAVIS_BOARDS="feather_m0_express_crickit feather_m0_rfm69 feather_m0_rfm9x feather_m4_express arduino_zero arduino_mkr1300 arduino_mkrzero" TRAVIS_SDK=arm

@ -1 +1 @@
Subproject commit 3bb53273cd3770328f55ba317af3df0cce4333c1
Subproject commit 5804e56e3c2ab4480bf72d94d997f769a645af47

View File

@ -89,13 +89,13 @@ BASE_CFLAGS = \
ifeq ($(CHIP_FAMILY), samd21)
CFLAGS += -Os -DNDEBUG
# TinyUSB defines
CFLAGS += -DCFG_TUSB_MCU=OPT_MCU_SAMD21 -DCFG_TUD_CDC_RX_BUFSIZE=128 -DCFG_TUD_CDC_TX_BUFSIZE=128 -DCFG_TUD_MSC_BUFSIZE=512
CFLAGS += -DCFG_TUSB_MCU=OPT_MCU_SAMD21 -DCFG_TUD_MIDI_RX_BUFSIZE=128 -DCFG_TUD_CDC_RX_BUFSIZE=128 -DCFG_TUD_MIDI_TX_BUFSIZE=128 -DCFG_TUD_CDC_TX_BUFSIZE=128 -DCFG_TUD_MSC_BUFSIZE=512
endif
ifeq ($(CHIP_FAMILY), samd51)
CFLAGS += -Os -DNDEBUG
# TinyUSB defines
CFLAGS += -DCFG_TUSB_MCU=OPT_MCU_SAMD51 -DCFG_TUD_CDC_RX_BUFSIZE=256 -DCFG_TUD_CDC_TX_BUFSIZE=256 -DCFG_TUD_MSC_BUFSIZE=1024
CFLAGS += -DCFG_TUSB_MCU=OPT_MCU_SAMD51 -DCFG_TUD_MIDI_RX_BUFSIZE=128 -DCFG_TUD_CDC_RX_BUFSIZE=256 -DCFG_TUD_MIDI_TX_BUFSIZE=128 -DCFG_TUD_CDC_TX_BUFSIZE=256 -DCFG_TUD_MSC_BUFSIZE=1024
endif
#Debugging/Optimization
@ -103,9 +103,9 @@ ifeq ($(DEBUG), 1)
# Turn on Python modules useful for debugging (e.g. uheap, ustack).
CFLAGS += -ggdb
# You may want to disable -flto if it interferes with debugging.
CFLAGS += -flto
# CFLAGS += -flto
# You may want to enable these flags to make setting breakpoints easier.
# CFLAGS += -fno-inline -fno-ipa-sra
CFLAGS += -fno-inline -fno-ipa-sra
ifeq ($(CHIP_FAMILY), samd21)
CFLAGS += -DENABLE_MICRO_TRACE_BUFFER
endif
@ -266,7 +266,6 @@ SRC_C = \
lib/oofatfs/option/ccsbcs.c \
lib/timeutils/timeutils.c \
lib/tinyusb/src/portable/microchip/$(CHIP_FAMILY)/dcd_$(CHIP_FAMILY).c \
lib/tinyusb/src/portable/microchip/$(CHIP_FAMILY)/hal_$(CHIP_FAMILY).c \
lib/utils/buffer_helper.c \
lib/utils/context_manager_helpers.c \
lib/utils/interrupt_char.c \

View File

@ -237,6 +237,7 @@ extern const struct _mp_obj_module_t gamepad_module;
extern const struct _mp_obj_module_t stage_module;
extern const struct _mp_obj_module_t touchio_module;
extern const struct _mp_obj_module_t usb_hid_module;
extern const struct _mp_obj_module_t usb_midi_module;
extern const struct _mp_obj_module_t network_module;
extern const struct _mp_obj_module_t socket_module;
extern const struct _mp_obj_module_t wiznet_module;
@ -382,6 +383,7 @@ extern const struct _mp_obj_module_t wiznet_module;
{ MP_OBJ_NEW_QSTR(MP_QSTR_math), (mp_obj_t)&math_module }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR__time), (mp_obj_t)&time_module }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_usb_hid),(mp_obj_t)&usb_hid_module }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_usb_midi),(mp_obj_t)&usb_midi_module }, \
TOUCHIO_MODULE \
EXTRA_BUILTIN_MODULES
@ -410,6 +412,7 @@ extern const struct _mp_obj_module_t wiznet_module;
{ MP_OBJ_NEW_QSTR(MP_QSTR_math), (mp_obj_t)&math_module }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_time), (mp_obj_t)&time_module }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_usb_hid),(mp_obj_t)&usb_hid_module }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_usb_midi),(mp_obj_t)&usb_midi_module }, \
TOUCHIO_MODULE \
EXTRA_BUILTIN_MODULES
#endif

View File

@ -75,7 +75,7 @@ LDFLAGS += -mthumb -mabi=aapcs -T $(LD_FILE) -L boards/
LDFLAGS += -Wl,--gc-sections
# TinyUSB defines
CFLAGS += -DCFG_TUSB_MCU=OPT_MCU_NRF5X -DCFG_TUD_CDC_RX_BUFSIZE=1024 -DCFG_TUD_CDC_TX_BUFSIZE=1024 -DCFG_TUD_MSC_BUFSIZE=4096
CFLAGS += -DCFG_TUSB_MCU=OPT_MCU_NRF5X -DCFG_TUD_CDC_RX_BUFSIZE=1024 -DCFG_TUD_CDC_TX_BUFSIZE=1024 -DCFG_TUD_MSC_BUFSIZE=4096 -DCFG_TUD_MIDI_RX_BUFSIZE=128 -DCFG_TUD_MIDI_TX_BUFSIZE=128
#Debugging/Optimization
ifeq ($(DEBUG), 1)

View File

@ -175,6 +175,7 @@ extern const struct _mp_obj_module_t supervisor_module;
extern const struct _mp_obj_module_t gamepad_module;
extern const struct _mp_obj_module_t neopixel_write_module;
extern const struct _mp_obj_module_t usb_hid_module;
extern const struct _mp_obj_module_t usb_midi_module;
extern const struct _mp_obj_module_t bleio_module;
#if MICROPY_PY_BLEIO
@ -207,6 +208,7 @@ extern const struct _mp_obj_module_t bleio_module;
{ MP_OBJ_NEW_QSTR (MP_QSTR_time ), (mp_obj_t)&time_module }, \
{ MP_OBJ_NEW_QSTR (MP_QSTR_json ), (mp_obj_t)&mp_module_ujson }, \
USBHID_MODULE \
{ MP_OBJ_NEW_QSTR(MP_QSTR_usb_midi),(mp_obj_t)&usb_midi_module }, \
BLEIO_MODULE
// extra built in names to add to the global namespace

View File

@ -0,0 +1,128 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2018 Scott Shawcroft for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdint.h>
#include "shared-bindings/usb_midi/PortIn.h"
#include "shared-bindings/util.h"
#include "py/ioctl.h"
#include "py/objproperty.h"
#include "py/runtime.h"
#include "py/stream.h"
#include "supervisor/shared/translate.h"
//| .. currentmodule:: usb_midi
//|
//| :class:`PortIn` -- receives midi commands over USB
//| ===================================================
//|
//| .. class:: PortIn()
//|
//| Not currently dynamically supported.
//|
//| PortIn objects are constructed for every corresponding entry in the USB descriptor and added
//| to the `usb_midi.ports` tuple.
//|
STATIC mp_obj_t usb_midi_portin_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *pos_args) {
return mp_const_none;
}
// These are standard stream methods. Code is in py/stream.c.
//
//| .. method:: read(nbytes=None)
//|
//| Read characters. If ``nbytes`` is specified then read at most that many
//| bytes. Otherwise, read everything that arrives until the connection
//| times out. Providing the number of bytes expected is highly recommended
//| because it will be faster.
//|
//| :return: Data read
//| :rtype: bytes or None
//|
//| .. method:: readinto(buf, nbytes=None)
//|
//| Read bytes into the ``buf``. If ``nbytes`` is specified then read at most
//| that many bytes. Otherwise, read at most ``len(buf)`` bytes.
//|
//| :return: number of bytes read and stored into ``buf``
//| :rtype: bytes or None
//|
// These three methods are used by the shared stream methods.
STATIC mp_uint_t usb_midi_portin_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode) {
usb_midi_portin_obj_t *self = MP_OBJ_TO_PTR(self_in);
byte *buf = buf_in;
// make sure we want at least 1 char
if (size == 0) {
return 0;
}
return common_hal_usb_midi_portin_read(self, buf, size, errcode);
}
STATIC mp_uint_t usb_midi_portin_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) {
usb_midi_portin_obj_t *self = MP_OBJ_TO_PTR(self_in);
mp_uint_t ret;
if (request == MP_IOCTL_POLL) {
mp_uint_t flags = arg;
ret = 0;
if ((flags & MP_IOCTL_POLL_RD) && common_hal_usb_midi_portin_bytes_available(self) > 0) {
ret |= MP_IOCTL_POLL_RD;
}
} else {
*errcode = MP_EINVAL;
ret = MP_STREAM_ERROR;
}
return ret;
}
STATIC const mp_rom_map_elem_t usb_midi_portin_locals_dict_table[] = {
// Standard stream methods.
{ MP_OBJ_NEW_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
};
STATIC MP_DEFINE_CONST_DICT(usb_midi_portin_locals_dict, usb_midi_portin_locals_dict_table);
STATIC const mp_stream_p_t usb_midi_portin_stream_p = {
.read = usb_midi_portin_read,
.write = NULL,
.ioctl = usb_midi_portin_ioctl,
.is_text = false,
};
const mp_obj_type_t usb_midi_portin_type = {
{ &mp_type_type },
.name = MP_QSTR_PortIn,
.make_new = usb_midi_portin_make_new,
.getiter = mp_identity_getiter,
.iternext = mp_stream_unbuffered_iter,
.protocol = &usb_midi_portin_stream_p,
.locals_dict = (mp_obj_dict_t*)&usb_midi_portin_locals_dict,
};

View File

@ -0,0 +1,44 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2018 Scott Shawcroft for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_USB_MIDI_PORTIN_H
#define MICROPY_INCLUDED_SHARED_BINDINGS_USB_MIDI_PORTIN_H
#include "shared-module/usb_midi/PortIn.h"
extern const mp_obj_type_t usb_midi_portin_type;
// Construct an underlying UART object.
extern void common_hal_usb_midi_portin_construct(usb_midi_portin_obj_t *self,
uint8_t receiver_buffer_size);
// Read characters.
extern size_t common_hal_usb_midi_portin_read(usb_midi_portin_obj_t *self,
uint8_t *data, size_t len, int *errcode);
extern uint32_t common_hal_usb_midi_portin_bytes_available(usb_midi_portin_obj_t *self);
extern void common_hal_usb_midi_portin_clear_buffer(usb_midi_portin_obj_t *self);
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_USB_MIDI_PORTIN_H

View File

@ -0,0 +1,110 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2018 Scott Shawcroft for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdint.h>
#include "shared-bindings/usb_midi/PortOut.h"
#include "shared-bindings/util.h"
#include "py/ioctl.h"
#include "py/objproperty.h"
#include "py/runtime.h"
#include "py/stream.h"
#include "supervisor/shared/translate.h"
//| .. currentmodule:: usb_midi
//|
//| :class:`PortOut` -- sends midi messages to a computer over USB
//| ==============================================================
//|
//| .. class:: PortOut()
//|
//| Not currently dynamically supported.
//|
//| PortOut objects are constructed for every corresponding entry in the USB descriptor and added
//| to the `usb_midi.ports` tuple.
//|
STATIC mp_obj_t usb_midi_portout_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *pos_args) {
return mp_const_none;
}
// These are standard stream methods. Code is in py/stream.c.
//
//| .. method:: write(buf)
//|
//| Write the buffer of bytes to the bus.
//|
//| :return: the number of bytes written
//| :rtype: int or None
//|
STATIC mp_uint_t usb_midi_portout_write(mp_obj_t self_in, const void *buf_in, mp_uint_t size, int *errcode) {
usb_midi_portout_obj_t *self = MP_OBJ_TO_PTR(self_in);
const byte *buf = buf_in;
return common_hal_usb_midi_portout_write(self, buf, size, errcode);
}
STATIC mp_uint_t usb_midi_portout_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) {
usb_midi_portout_obj_t *self = MP_OBJ_TO_PTR(self_in);
mp_uint_t ret;
if (request == MP_IOCTL_POLL) {
mp_uint_t flags = arg;
ret = 0;
if ((flags & MP_IOCTL_POLL_WR) && common_hal_usb_midi_portout_ready_to_tx(self)) {
ret |= MP_IOCTL_POLL_WR;
}
} else {
*errcode = MP_EINVAL;
ret = MP_STREAM_ERROR;
}
return ret;
}
STATIC const mp_rom_map_elem_t usb_midi_portout_locals_dict_table[] = {
// Standard stream methods.
{ MP_OBJ_NEW_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
};
STATIC MP_DEFINE_CONST_DICT(usb_midi_portout_locals_dict, usb_midi_portout_locals_dict_table);
STATIC const mp_stream_p_t usb_midi_portout_stream_p = {
.read = NULL,
.write = usb_midi_portout_write,
.ioctl = usb_midi_portout_ioctl,
.is_text = false,
};
const mp_obj_type_t usb_midi_portout_type = {
{ &mp_type_type },
.name = MP_QSTR_PortOut,
.make_new = usb_midi_portout_make_new,
.getiter = mp_identity_getiter,
.iternext = mp_stream_unbuffered_iter,
.protocol = &usb_midi_portout_stream_p,
.locals_dict = (mp_obj_dict_t*)&usb_midi_portout_locals_dict,
};

View File

@ -0,0 +1,44 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2018 Scott Shawcroft for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_USB_MIDI_PORTOUT_H
#define MICROPY_INCLUDED_SHARED_BINDINGS_USB_MIDI_PORTOUT_H
#include "shared-module/usb_midi/PortOut.h"
extern const mp_obj_type_t usb_midi_portout_type;
// Construct an underlying UART object.
extern void common_hal_usb_midi_portout_construct(usb_midi_portout_obj_t *self,
uint8_t receiver_buffer_size);
// Write characters. len is in characters NOT bytes!
extern size_t common_hal_usb_midi_portout_write(usb_midi_portout_obj_t *self,
const uint8_t *data, size_t len, int *errcode);
extern bool common_hal_usb_midi_portout_ready_to_tx(usb_midi_portout_obj_t *self);
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_USB_MIDI_PORTOUT_H

View File

@ -0,0 +1,78 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2018 Scott Shawcroft for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdint.h>
#include "py/obj.h"
#include "py/runtime.h"
#include "shared-bindings/usb_midi/__init__.h"
#include "shared-bindings/usb_midi/PortIn.h"
#include "shared-bindings/usb_midi/PortOut.h"
#include "py/runtime.h"
//| :mod:`usb_midi` --- MIDI over USB
//| =================================================
//|
//| .. module:: usb_midi
//| :synopsis: MIDI over USB
//|
//| The `usb_midi` module contains classes to transmit and receive MIDI messages over USB
//|
//| Libraries
//|
//| .. toctree::
//| :maxdepth: 3
//|
//| PortIn
//| PortOut
//|
//|
mp_map_elem_t usb_midi_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_usb_midi) },
{ MP_ROM_QSTR(MP_QSTR_ports), mp_const_empty_tuple },
{ MP_ROM_QSTR(MP_QSTR_PortIn), MP_OBJ_FROM_PTR(&usb_midi_portin_type) },
{ MP_ROM_QSTR(MP_QSTR_PortOut), MP_OBJ_FROM_PTR(&usb_midi_portout_type) },
};
// This isn't const so we can set ports dynamically.
mp_obj_dict_t usb_midi_module_globals = {
.base = {&mp_type_dict},
.map = {
.all_keys_are_qstrs = 1,
.is_fixed = 1,
.is_ordered = 1,
.used = MP_ARRAY_SIZE(usb_midi_module_globals_table),
.alloc = MP_ARRAY_SIZE(usb_midi_module_globals_table),
.table = usb_midi_module_globals_table,
},
};
const mp_obj_module_t usb_midi_module = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t*)&usb_midi_module_globals,
};

View File

@ -0,0 +1,34 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2018 Scott Shawcroft
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_USB_MIDI___INIT___H
#define MICROPY_INCLUDED_SHARED_BINDINGS_USB_MIDI___INIT___H
#include "py/obj.h"
extern mp_obj_dict_t usb_midi_module_globals;
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_USB_MIDI___INIT___H

View File

@ -0,0 +1,40 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2018 Scott Shawcroft for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "shared-module/usb_midi/PortIn.h"
#include "supervisor/shared/translate.h"
#include "tusb.h"
void common_hal_usb_midi_portin_construct(usb_midi_portin_obj_t *self, uint8_t receiver_buffer_size) {
}
size_t common_hal_usb_midi_portin_read(usb_midi_portin_obj_t *self, uint8_t *data, size_t len, int *errcode) {
return tud_midi_read(data, len);
}
uint32_t common_hal_usb_midi_portin_bytes_available(usb_midi_portin_obj_t *self) {
return tud_midi_available();
}

View File

@ -0,0 +1,39 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2018 Scott Shawcroft for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef SHARED_MODULE_USB_MIDI_PORTIN_H
#define SHARED_MODULE_USB_MIDI_PORTIN_H
#include <stdint.h>
#include <stdbool.h>
#include "py/obj.h"
typedef struct {
mp_obj_base_t base;
} usb_midi_portin_obj_t;
#endif /* SHARED_MODULE_USB_MIDI_PORTIN_H */

View File

@ -0,0 +1,40 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2018 Scott Shawcroft for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "shared-module/usb_midi/PortOut.h"
#include "supervisor/shared/translate.h"
#include "tusb.h"
void common_hal_usb_midi_portout_construct(usb_midi_portout_obj_t *self) {
}
size_t common_hal_usb_midi_portout_write(usb_midi_portout_obj_t *self, const uint8_t *data, size_t len, int *errcode) {
return tud_midi_write(0, data, len);
}
bool common_hal_usb_midi_portout_ready_to_tx(usb_midi_portout_obj_t *self) {
return tud_midi_connected();
}

View File

@ -0,0 +1,39 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2018 Scott Shawcroft for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef SHARED_MODULE_USB_MIDI_PORTOUT_H
#define SHARED_MODULE_USB_MIDI_PORTOUT_H
#include <stdint.h>
#include <stdbool.h>
#include "py/obj.h"
typedef struct {
mp_obj_base_t base;
} usb_midi_portout_obj_t;
#endif /* SHARED_MODULE_USB_MIDI_PORTOUT_H */

View File

@ -0,0 +1,63 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2018 hathach for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "shared-bindings/usb_midi/__init__.h"
#include "genhdr/autogen_usb_descriptor.h"
#include "py/obj.h"
#include "py/mphal.h"
#include "py/runtime.h"
#include "py/objtuple.h"
#include "shared-bindings/usb_midi/PortIn.h"
#include "shared-bindings/usb_midi/PortOut.h"
#include "supervisor/memory.h"
#include "tusb.h"
supervisor_allocation* usb_midi_allocation;
void usb_midi_init(void) {
// TODO(tannewt): Make this dynamic.
uint16_t tuple_size = align32_size(sizeof(mp_obj_tuple_t) + sizeof(mp_obj_t*) * 2);
uint16_t portin_size = align32_size(sizeof(usb_midi_portin_obj_t));
uint16_t portout_size = align32_size(sizeof(usb_midi_portout_obj_t));
// For each embedded MIDI Jack in the descriptor we create a Port
usb_midi_allocation = allocate_memory(tuple_size + portin_size + portout_size, false);
mp_obj_tuple_t *ports = (mp_obj_tuple_t *) usb_midi_allocation->ptr;
ports->base.type = &mp_type_tuple;
ports->len = 2;
usb_midi_portin_obj_t* in = (usb_midi_portin_obj_t *) (usb_midi_allocation->ptr + tuple_size / 4);
in->base.type = &usb_midi_portin_type;
ports->items[0] = MP_OBJ_FROM_PTR(in);
usb_midi_portout_obj_t* out = (usb_midi_portout_obj_t *) (usb_midi_allocation->ptr + tuple_size / 4 + portin_size / 4);
out->base.type = &usb_midi_portout_type;
ports->items[1] = MP_OBJ_FROM_PTR(out);
mp_map_lookup(&usb_midi_module_globals.map, MP_ROM_QSTR(MP_QSTR_ports), MP_MAP_LOOKUP)->value = MP_OBJ_FROM_PTR(ports);
}

View File

@ -0,0 +1,32 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2018 Scott Shawcroft for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef SHARED_MODULE_USB_MIDI___INIT___H
#define SHARED_MODULE_USB_MIDI___INIT___H
void usb_midi_init(void);
#endif /* SHARED_MODULE_USB_MIDI___INIT___H */

View File

@ -39,6 +39,8 @@ typedef struct {
uint32_t length; // in bytes
} supervisor_allocation;
void memory_init(void);
void free_memory(supervisor_allocation* allocation);
supervisor_allocation* allocate_remaining_memory(void);
@ -48,4 +50,11 @@ supervisor_allocation* allocate_remaining_memory(void);
// statically allocated memory.
supervisor_allocation* allocate_memory(uint32_t length, bool high_address);
static inline uint16_t align32_size(uint16_t size) {
if (size % 4 != 0) {
return (size & 0xfffc) + 0x4;
}
return size;
}
#endif // MICROPY_INCLUDED_SUPERVISOR_MEMORY_H

View File

@ -75,6 +75,7 @@
#define CFG_TUD_CDC 1
#define CFG_TUD_MSC 1
#define CFG_TUD_HID 1
#define CFG_TUD_MIDI 1
#define CFG_TUD_CUSTOM_CLASS 0
/*------------------------------------------------------------------*/

View File

@ -26,6 +26,7 @@
#include "tick.h"
#include "shared-bindings/microcontroller/Processor.h"
#include "shared-module/usb_midi/__init__.h"
#include "supervisor/port.h"
#include "supervisor/usb.h"
#include "lib/utils/interrupt_char.h"
@ -71,11 +72,13 @@ void usb_init(void) {
// This callback always got invoked regardless of mp_interrupt_char value since we only set it once here
tud_cdc_set_wanted_char(CHAR_CTRL_C);
#endif
usb_midi_init();
}
void usb_background(void) {
if (usb_enabled()) {
tusb_task();
tud_task();
tud_cdc_write_flush();
}
}

View File

@ -49,6 +49,7 @@ else
lib/tinyusb/src/class/msc/msc_device.c \
lib/tinyusb/src/class/cdc/cdc_device.c \
lib/tinyusb/src/class/hid/hid_device.c \
lib/tinyusb/src/class/midi/midi_device.c \
lib/tinyusb/src/tusb.c \
supervisor/shared/serial.c \
supervisor/usb.c \
@ -57,8 +58,14 @@ else
supervisor/shared/usb/usb_msc_flash.c \
shared-bindings/usb_hid/__init__.c \
shared-bindings/usb_hid/Device.c \
shared-bindings/usb_midi/__init__.c \
shared-bindings/usb_midi/PortIn.c \
shared-bindings/usb_midi/PortOut.c \
shared-module/usb_hid/__init__.c \
shared-module/usb_hid/Device.c \
shared-module/usb_midi/__init__.c \
shared-module/usb_midi/PortIn.c \
shared-module/usb_midi/PortOut.c \
$(BUILD)/autogen_usb_descriptor.c
CFLAGS += -DUSB_AVAILABLE
endif

View File

@ -176,16 +176,33 @@ hid_interfaces = [
]
# Audio!
midi_in_jack = midi.InJackDescriptor(
description="MIDI PC <- CircuitPython internals",
# In and out here are relative to CircuitPython
# USB OUT -> midi_in_jack_emb -> midi_out_jack_ext -> CircuitPython
midi_in_jack_emb = midi.InJackDescriptor(
description="MIDI PC -> CircuitPython",
bJackType=midi.JACK_TYPE_EMBEDDED,
iJack=StringIndex.index("CircuitPython usb_midi.ports[0]"))
midi_out_jack_ext = midi.OutJackDescriptor(
description="MIDI data out to user code.",
bJackType=midi.JACK_TYPE_EXTERNAL,
input_pins=[(midi_in_jack_emb, 1)],
iJack=0)
midi_out_jack = midi.OutJackDescriptor(
description="MIDI PC -> CircuitPython internals",
# USB IN <- midi_out_jack_emb <- midi_in_jack_ext <- CircuitPython
midi_in_jack_ext = midi.InJackDescriptor(
description="MIDI data in from user code.",
bJackType=midi.JACK_TYPE_EXTERNAL,
iJack=0)
midi_out_jack_emb = midi.OutJackDescriptor(
description="MIDI PC <- CircuitPython",
bJackType=midi.JACK_TYPE_EMBEDDED,
iJack=0)
input_pins=[(midi_in_jack_ext, 1)],
iJack=StringIndex.index("CircuitPython usb_midi.ports[1]"))
audio_midi_interface = standard.InterfaceDescriptor(
description="All the audio",
description="Midi goodness",
bInterfaceClass=audio.AUDIO_CLASS_DEVICE,
bInterfaceSubClass=audio.AUDIO_SUBCLASS_MIDI_STREAMING,
bInterfaceProtocol=audio.AUDIO_PROTOCOL_V1,
@ -193,26 +210,23 @@ audio_midi_interface = standard.InterfaceDescriptor(
subdescriptors=[
midi.Header(
jacks_and_elements=[
midi_in_jack,
midi.InJackDescriptor(
description="MIDI data in from user code.",
bJackType=midi.JACK_TYPE_EXTERNAL, iJack=0),
midi_out_jack,
midi.OutJackDescriptor(
description="MIDI data out to user code.",
bJackType=midi.JACK_TYPE_EXTERNAL, iJack=0),
]
midi_in_jack_emb,
midi_in_jack_ext,
midi_out_jack_emb,
midi_out_jack_ext
],
),
standard.EndpointDescriptor(
description="MIDI data out",
description="MIDI data out to CircuitPython",
bEndpointAddress=0x0 | standard.EndpointDescriptor.DIRECTION_OUT,
bmAttributes=standard.EndpointDescriptor.TYPE_BULK),
midi.DataEndpointDescriptor(baAssocJack=[midi_out_jack]),
midi.DataEndpointDescriptor(baAssocJack=[midi_in_jack_emb]),
standard.EndpointDescriptor(
description="MIDI data in",
description="MIDI data in from CircuitPython",
bEndpointAddress=0x0 | standard.EndpointDescriptor.DIRECTION_IN,
bmAttributes=standard.EndpointDescriptor.TYPE_BULK),
midi.DataEndpointDescriptor(baAssocJack=[midi_in_jack]),
bmAttributes=standard.EndpointDescriptor.TYPE_BULK,
bInterval = 0x0),
midi.DataEndpointDescriptor(baAssocJack=[midi_out_jack_emb]),
])
cs_ac_interface = audio10.AudioControlInterface(
@ -234,12 +248,12 @@ audio_control_interface = standard.InterfaceDescriptor(
])
# Audio streaming interfaces must occur before MIDI ones.
# audio_interfaces = [audio_control_interface] + cs_ac_interface.audio_streaming_interfaces + cs_ac_interface.midi_streaming_interfaces
audio_interfaces = [audio_control_interface] + cs_ac_interface.audio_streaming_interfaces + cs_ac_interface.midi_streaming_interfaces
# This will renumber the endpoints to make them unique across descriptors,
# and renumber the interfaces in order. But we still need to fix up certain
# interface cross-references.
interfaces = util.join_interfaces(cdc_interfaces, msc_interfaces, hid_interfaces)
interfaces = util.join_interfaces(cdc_interfaces, msc_interfaces, hid_interfaces, audio_interfaces)
# Now adjust the CDC interface cross-references.
@ -256,21 +270,13 @@ cdc_iad = standard.InterfaceAssociationDescriptor(
bFunctionSubClass=cdc.CDC_SUBCLASS_ACM, # Abstract control model
bFunctionProtocol=cdc.CDC_PROTOCOL_NONE)
# audio_iad = standard.InterfaceAssociationDescriptor(
# description="Audio IAD",
# bFirstInterface=audio_control_interface.bInterfaceNumber,
# bInterfaceCount=len(audio_interfaces),
# bFunctionClass=audio.AUDIO_CLASS_DEVICE,
# bFunctionSubClass=audio.AUDIO_SUBCLASS_UNKNOWN,
# bFunctionProtocol=audio.AUDIO_PROTOCOL_V1)
descriptor_list = []
descriptor_list.append(cdc_iad)
# descriptor_list.append(audio_iad)
descriptor_list.extend(cdc_interfaces)
descriptor_list.extend(msc_interfaces)
# descriptor_list.append(audio_control_interface)
# Only add the control interface because other audio interfaces are managed by it to ensure the
# correct ordering.
descriptor_list.append(audio_control_interface)
# Put the CDC IAD just before the CDC interfaces.
# There appears to be a bug in the Windows composite USB driver that requests the
# HID report descriptor with the wrong interface number if the HID interface is not given

@ -1 +1 @@
Subproject commit 57bf602dac9cba8c4226f764c286cbc60103d67d
Subproject commit e2e79566a807b7230dddbc53a103c19b2f65e2cb