From b5e40f52c2b1c2890c866d7305e0e99b4811b7f5 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Fri, 16 Nov 2018 17:04:42 -0800 Subject: Add USB MIDI support for SAMD and nRF. The API should be identical to using a UART for MIDI. Fixes #672 --- tools/gen_usb_descriptor.py | 72 ++++++++++++++++++++++++--------------------- tools/usb_descriptor | 2 +- 2 files changed, 39 insertions(+), 35 deletions(-) (limited to 'tools') diff --git a/tools/gen_usb_descriptor.py b/tools/gen_usb_descriptor.py index 2cb06ec2f..e8d66443d 100644 --- a/tools/gen_usb_descriptor.py +++ b/tools/gen_usb_descriptor.py @@ -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=0) -midi_out_jack = midi.OutJackDescriptor( - description="MIDI PC -> CircuitPython internals", + 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) + +# 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,11 @@ 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) +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 diff --git a/tools/usb_descriptor b/tools/usb_descriptor index 57bf602da..e2e79566a 160000 --- a/tools/usb_descriptor +++ b/tools/usb_descriptor @@ -1 +1 @@ -Subproject commit 57bf602dac9cba8c4226f764c286cbc60103d67d +Subproject commit e2e79566a807b7230dddbc53a103c19b2f65e2cb -- cgit v1.2.3 From 3dd59c3d5fa59f5bea3acc8e55c4d4a5091e66eb Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Thu, 10 Jan 2019 11:00:40 -0800 Subject: Polish thanks to Dan's feedback --- .travis.yml | 2 +- shared-bindings/usb_midi/PortIn.c | 3 +++ shared-bindings/usb_midi/PortOut.c | 3 +++ shared-module/usb_midi/__init__.c | 13 +++---------- supervisor/memory.h | 9 +++++++++ tools/gen_usb_descriptor.py | 2 ++ 6 files changed, 21 insertions(+), 11 deletions(-) (limited to 'tools') diff --git a/.travis.yml b/.travis.yml index d3e9f4bf1..bab5a2456 100755 --- a/.travis.yml +++ b/.travis.yml @@ -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 diff --git a/shared-bindings/usb_midi/PortIn.c b/shared-bindings/usb_midi/PortIn.c index 0309b70f7..3c4d4f73f 100644 --- a/shared-bindings/usb_midi/PortIn.c +++ b/shared-bindings/usb_midi/PortIn.c @@ -45,6 +45,9 @@ //| //| 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; diff --git a/shared-bindings/usb_midi/PortOut.c b/shared-bindings/usb_midi/PortOut.c index 156a092e0..8b26b8ffc 100644 --- a/shared-bindings/usb_midi/PortOut.c +++ b/shared-bindings/usb_midi/PortOut.c @@ -45,6 +45,9 @@ //| //| 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; diff --git a/shared-module/usb_midi/__init__.c b/shared-module/usb_midi/__init__.c index 60afeeef1..73a314b99 100644 --- a/shared-module/usb_midi/__init__.c +++ b/shared-module/usb_midi/__init__.c @@ -38,18 +38,11 @@ supervisor_allocation* usb_midi_allocation; -static inline uint16_t word_align(uint16_t size) { - if (size % 4 != 0) { - return (size & 0xfffc) + 0x4; - } - return size; -} - void usb_midi_init(void) { // TODO(tannewt): Make this dynamic. - uint16_t tuple_size = word_align(sizeof(mp_obj_tuple_t) + sizeof(mp_obj_t*) * 2); - uint16_t portin_size = word_align(sizeof(usb_midi_portin_obj_t)); - uint16_t portout_size = word_align(sizeof(usb_midi_portout_obj_t)); + 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); diff --git a/supervisor/memory.h b/supervisor/memory.h index 4f8317a2d..c89f14bd9 100755 --- a/supervisor/memory.h +++ b/supervisor/memory.h @@ -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 diff --git a/tools/gen_usb_descriptor.py b/tools/gen_usb_descriptor.py index e8d66443d..10bbf5066 100644 --- a/tools/gen_usb_descriptor.py +++ b/tools/gen_usb_descriptor.py @@ -274,6 +274,8 @@ descriptor_list = [] descriptor_list.append(cdc_iad) descriptor_list.extend(cdc_interfaces) descriptor_list.extend(msc_interfaces) +# 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 -- cgit v1.2.3