Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RP2040 MIDI Host #1627

Open
wants to merge 29 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
2ddd74f
Add MIDI host support to tinyusb
rppicomidi Aug 12, 2022
70eefcb
Add hooks to allow cloning an attached USB device descriptor
rppicomidi Aug 25, 2022
3325e26
Make USB MIDI device code allow a device with no Audio Control interface
rppicomidi Aug 25, 2022
4fbf996
Get rid of implicit uint conversions
atoktoto Sep 8, 2022
19563b4
Simple MIDI rx example
atoktoto Sep 8, 2022
81de7f3
Add Makefile for the midi host example
atoktoto Sep 11, 2022
0763bc5
Fix printf statement
atoktoto Sep 11, 2022
c14e3e2
Fix unused errors when LOG=0
atoktoto Sep 11, 2022
a6d4b64
Removed unused function prototype
atoktoto Oct 2, 2022
21e003a
Added explicit conversions
atoktoto Nov 13, 2022
0a844f2
Fix usb hubs
atoktoto Nov 19, 2022
375e822
Merge branch 'hathach:master' into midihost
atoktoto Nov 19, 2022
34729b1
Fix usb-hub data transfer problems by AndrewCapon
atoktoto Nov 21, 2022
3ba0311
Explicit type conversion
atoktoto Nov 21, 2022
89eac75
Explicit type conversion
atoktoto Nov 21, 2022
b41f5ea
Merge branch 'master' into midihost
atoktoto Nov 21, 2022
87adc63
Merge branch 'master' into fork/atoktoto/midihost
hathach Feb 12, 2025
85247e5
clean up
hathach Feb 12, 2025
294fb26
pre-commit fix
hathach Feb 12, 2025
7c40523
fix host midi build
hathach Feb 12, 2025
86d371f
more ci fix
hathach Feb 12, 2025
e0b192b
- use CFG_TUH_MIDI as number of midi host instance
hathach Feb 12, 2025
bad6cbe
update midi host to use endpoint stream API
hathach Feb 13, 2025
ed88fc9
- remove tuh_midi_read_poll(), auto schedule EP in when set_config() …
hathach Feb 14, 2025
31a2696
- change signature of tuh_midi_mount/umount_cb()
hathach Feb 14, 2025
997771f
- rename tuh_midi_stream_flush() to tuh_midi_write_flush()
hathach Feb 14, 2025
6ebd362
Merge branch 'master' into fork/atoktoto/midihost
hathach Feb 21, 2025
b12c8a9
remove CFG_MIDI_HOST_DEVSTRINGS support, we will leave that for appli…
hathach Feb 21, 2025
35f72a9
add tuh_midi_descriptor_cb()
hathach Feb 23, 2025
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
1 change: 1 addition & 0 deletions examples/host/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ family_add_subdirectory(cdc_msc_hid)
family_add_subdirectory(cdc_msc_hid_freertos)
family_add_subdirectory(device_info)
family_add_subdirectory(hid_controller)
family_add_subdirectory(midi_rx)
family_add_subdirectory(msc_file_explorer)
3 changes: 1 addition & 2 deletions examples/host/device_info/src/tusb_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,7 @@
// only hub class is enabled
#define CFG_TUH_HUB 1

// max device support (excluding hub device)
// 1 hub typically has 4 ports
// max device support (excluding hub device): 1 hub typically has 4 ports
#define CFG_TUH_DEVICE_MAX (3*CFG_TUH_HUB + 1)

#ifdef __cplusplus
Expand Down
32 changes: 32 additions & 0 deletions examples/host/midi_rx/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
cmake_minimum_required(VERSION 3.20)

include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)

# gets PROJECT name for the example
family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})

project(${PROJECT} C CXX ASM)

# Checks this example is valid for the family and initializes the project
family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})

# Espressif has its own cmake build system
if(FAMILY STREQUAL "espressif")
return()
endif()

add_executable(${PROJECT})

# Example source
target_sources(${PROJECT} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
)

# Example include
target_include_directories(${PROJECT} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src
)

# Configure compilation flags and libraries for the example without RTOS.
# See the corresponding function in hw/bsp/FAMILY/family.cmake for details.
family_configure_host_example(${PROJECT} noos)
13 changes: 13 additions & 0 deletions examples/host/midi_rx/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
include ../../build_system/make/make.mk

INC += \
src \
$(TOP)/hw \

# Example source
EXAMPLE_SOURCE += \
src/main.c

SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))

include ../../build_system/make/rules.mk
20 changes: 20 additions & 0 deletions examples/host/midi_rx/only.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
mcu:ESP32S2
mcu:ESP32S3
mcu:ESP32P4
mcu:KINETIS_KL
mcu:LPC175X_6X
mcu:LPC177X_8X
mcu:LPC18XX
mcu:LPC40XX
mcu:LPC43XX
mcu:MAX3421
mcu:MIMXRT1XXX
mcu:MIMXRT10XX
mcu:MIMXRT11XX
mcu:MSP432E4
mcu:RP2040
mcu:RX65X
mcu:RAXXX
mcu:STM32F4
mcu:STM32F7
mcu:STM32H7
140 changes: 140 additions & 0 deletions examples/host/midi_rx/src/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
*
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "bsp/board_api.h"
#include "tusb.h"

#if CFG_TUH_MIDI

//--------------------------------------------------------------------+
// STATIC GLOBALS DECLARATION
//--------------------------------------------------------------------+
static uint8_t midi_dev_addr = 0;

//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF PROTOTYPES
//--------------------------------------------------------------------+
void led_blinking_task(void);
void midi_host_rx_task(void);

/*------------- MAIN -------------*/
int main(void) {
board_init();

printf("TinyUSB Host MIDI Example\r\n");

// init host stack on configured roothub port
tusb_rhport_init_t host_init = {
.role = TUSB_ROLE_HOST,
.speed = TUSB_SPEED_AUTO
};
tusb_init(BOARD_TUH_RHPORT, &host_init);

while (1) {
tuh_task();
led_blinking_task();
midi_host_rx_task();
}

return 0;
}

#endif

//--------------------------------------------------------------------+
// Blinking Task
//--------------------------------------------------------------------+
void led_blinking_task(void) {
const uint32_t interval_ms = 1000;
static uint32_t start_ms = 0;

static bool led_state = false;

// Blink every interval ms
if (board_millis() - start_ms < interval_ms) return;// not enough time
start_ms += interval_ms;

board_led_write(led_state);
led_state = 1 - led_state;// toggle
}

//--------------------------------------------------------------------+
// MIDI host receive task
//--------------------------------------------------------------------+
void midi_host_rx_task(void) {
// device must be attached and have at least one endpoint ready to receive a message
if (!midi_dev_addr || !tuh_midi_mounted(midi_dev_addr)) {
return;
}
if (tuh_midi_get_num_rx_cables(midi_dev_addr) < 1) {
return;
}
}

//--------------------------------------------------------------------+
// TinyUSB Callbacks
//--------------------------------------------------------------------+

// Invoked when device with MIDI interface is mounted.
void tuh_midi_mount_cb(uint8_t dev_addr, uint8_t num_cables_rx, uint16_t num_cables_tx) {
(void) num_cables_rx;
(void) num_cables_tx;
midi_dev_addr = dev_addr;
TU_LOG1("MIDI device address = %u, Number of RX cables = %u, Number of TX cables = %u\r\n",
dev_addr, num_cables_rx, num_cables_tx);
}

// Invoked when device with hid interface is un-mounted
void tuh_midi_umount_cb(uint8_t dev_addr) {
(void) dev_addr;
midi_dev_addr = 0;
TU_LOG1("MIDI device address = %d is unmounted\r\n", dev_addr);
}

void tuh_midi_rx_cb(uint8_t dev_addr, uint32_t num_packets) {
if (midi_dev_addr != dev_addr) {
return;
}

if (num_packets == 0) {
return;
}

uint8_t cable_num;
uint8_t buffer[48];
uint32_t bytes_read = tuh_midi_stream_read(dev_addr, &cable_num, buffer, sizeof(buffer));
(void) bytes_read;

TU_LOG1("Read bytes %lu cable %u", bytes_read, cable_num);
TU_LOG1_MEM(buffer, bytes_read, 2);
}

void tuh_midi_tx_cb(uint8_t dev_addr) {
(void) dev_addr;
}
120 changes: 120 additions & 0 deletions examples/host/midi_rx/src/tusb_config.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
*
* 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 TUSB_CONFIG_H_
#define TUSB_CONFIG_H_

#ifdef __cplusplus
extern "C" {
#endif

//--------------------------------------------------------------------
// Common Configuration
//--------------------------------------------------------------------

// defined by compiler flags for flexibility
#ifndef CFG_TUSB_MCU
#error CFG_TUSB_MCU must be defined
#endif

// Espressif IDF requires "freertos/" prefix in include path
#if TUSB_MCU_VENDOR_ESPRESSIF
#define CFG_TUSB_OS_INC_PATH freertos/
#endif

#ifndef CFG_TUSB_OS
#define CFG_TUSB_OS OPT_OS_NONE
#endif

#ifndef CFG_TUSB_DEBUG
#define CFG_TUSB_DEBUG 0
#endif

/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.
* Tinyusb use follows macros to declare transferring memory so that they can be put
* into those specific section.
* e.g
* - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") ))
* - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4)))
*/
#ifndef CFG_TUH_MEM_SECTION
#define CFG_TUH_MEM_SECTION
#endif

#ifndef CFG_TUH_MEM_ALIGN
#define CFG_TUH_MEM_ALIGN __attribute__ ((aligned(4)))
#endif

//--------------------------------------------------------------------
// Host Configuration
//--------------------------------------------------------------------

// Enable Host stack
#define CFG_TUH_ENABLED 1

#if CFG_TUSB_MCU == OPT_MCU_RP2040
// #define CFG_TUH_RPI_PIO_USB 1 // use pio-usb as host controller
// #define CFG_TUH_MAX3421 1 // use max3421 as host controller

// host roothub port is 1 if using either pio-usb or max3421
#if (defined(CFG_TUH_RPI_PIO_USB) && CFG_TUH_RPI_PIO_USB) || (defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421)
#define BOARD_TUH_RHPORT 1
#endif
#endif

// Default is max speed that hardware controller could support with on-chip PHY
#define CFG_TUH_MAX_SPEED BOARD_TUH_MAX_SPEED

//------------------------- Board Specific --------------------------

// RHPort number used for host can be defined by board.mk, default to port 0
#ifndef BOARD_TUH_RHPORT
#define BOARD_TUH_RHPORT 0
#endif

// RHPort max operational speed can defined by board.mk
#ifndef BOARD_TUH_MAX_SPEED
#define BOARD_TUH_MAX_SPEED OPT_MODE_DEFAULT_SPEED
#endif

//--------------------------------------------------------------------
// Driver Configuration
//--------------------------------------------------------------------

// Size of buffer to hold descriptors and other data used for enumeration
#define CFG_TUH_ENUMERATION_BUFSIZE 256

#define CFG_TUH_HUB 1
// max device support (excluding hub device): 1 hub typically has 4 ports
#define CFG_TUH_DEVICE_MAX (3*CFG_TUH_HUB + 1)
#define CFG_TUH_MIDI CFG_TUH_DEVICE_MAX

#define CFG_MIDI_HOST_DEVSTRINGS 1

#ifdef __cplusplus
}
#endif

#endif
4 changes: 3 additions & 1 deletion hw/bsp/rp2040/family.c
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,9 @@ int board_getchar(void) {
#if CFG_TUH_ENABLED && defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421

void max3421_int_handler(uint gpio, uint32_t event_mask) {
if (!(gpio == MAX3421_INTR_PIN && event_mask & GPIO_IRQ_EDGE_FALL)) return;
if (!(gpio == MAX3421_INTR_PIN && event_mask & GPIO_IRQ_EDGE_FALL)) {
return;
}
tuh_int_handler(BOARD_TUH_RHPORT, true);
}

Expand Down
1 change: 1 addition & 0 deletions hw/bsp/rp2040/family.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ target_sources(tinyusb_host_base INTERFACE
${TOP}/src/host/hub.c
${TOP}/src/class/cdc/cdc_host.c
${TOP}/src/class/hid/hid_host.c
${TOP}/src/class/midi/midi_host.c
${TOP}/src/class/msc/msc_host.c
${TOP}/src/class/vendor/vendor_host.c
)
Expand Down
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ function(tinyusb_target_add TARGET)
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/host/hub.c
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/class/cdc/cdc_host.c
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/class/hid/hid_host.c
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/class/midi/midi_host.c
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/class/msc/msc_host.c
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/class/vendor/vendor_host.c
# typec
Expand Down
1 change: 1 addition & 0 deletions src/class/audio/audio.h
Original file line number Diff line number Diff line change
Expand Up @@ -661,6 +661,7 @@ typedef struct TU_ATTR_PACKED
uint16_t wTotalLength ; ///< Total number of bytes returned for the class-specific AudioControl interface descriptor. Includes the combined length of this descriptor header and all Clock Source, Unit and Terminal descriptors.
uint8_t bmControls ; ///< See: audio_cs_ac_interface_control_pos_t.
} audio_desc_cs_ac_interface_t;
TU_VERIFY_STATIC(sizeof(audio_desc_cs_ac_interface_t) == 9, "size is not correct");

/// AUDIO Clock Source Descriptor (4.7.2.1)
typedef struct TU_ATTR_PACKED
Expand Down
4 changes: 2 additions & 2 deletions src/class/cdc/cdc_host.c
Original file line number Diff line number Diff line change
Expand Up @@ -691,10 +691,10 @@ bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t
}
} else if ( ep_addr == p_cdc->stream.rx.ep_addr ) {
#if CFG_TUH_CDC_FTDI
if (p_cdc->serial_drid == SERIAL_DRIVER_FTDI) {
if (p_cdc->serial_drid == SERIAL_DRIVER_FTDI && xferred_bytes > 2) {
// FTDI reserve 2 bytes for status
// uint8_t status[2] = {p_cdc->stream.rx.ep_buf[0], p_cdc->stream.rx.ep_buf[1]};
tu_edpt_stream_read_xfer_complete_offset(&p_cdc->stream.rx, xferred_bytes, 2);
tu_edpt_stream_read_xfer_complete_with_buf(&p_cdc->stream.rx, p_cdc->stream.rx.ep_buf+2, xferred_bytes-2);
}else
#endif
{
Expand Down
Loading