summaryrefslogtreecommitdiff
path: root/examples/host
diff options
context:
space:
mode:
authortobozo <[email protected]>2023-03-30 19:30:24 +0000
committerGitHub <[email protected]>2023-03-30 19:30:24 +0000
commit290f18a1fe4551cb0376d356627bda595c621518 (patch)
tree789f93ee268cb9c9cccc03702f8a1769ae4a3d9d /examples/host
parent9e38b4cc68d9eeeb055349a97caf30d1cf4000e0 (diff)
parent5add4c97fa834004e6a3b267345a13c6d3c9514a (diff)
Merge branch 'hathach:master' into master
Diffstat (limited to 'examples/host')
-rw-r--r--examples/host/CMakeLists.txt2
-rw-r--r--examples/host/bare_api/CMakeLists.txt7
-rw-r--r--examples/host/bare_api/Makefile4
-rw-r--r--examples/host/bare_api/only.txt2
-rw-r--r--examples/host/bare_api/src/main.c23
-rw-r--r--examples/host/bare_api/src/tusb_config.h51
-rw-r--r--examples/host/cdc_msc_hid/CMakeLists.txt8
-rw-r--r--examples/host/cdc_msc_hid/Makefile11
-rw-r--r--examples/host/cdc_msc_hid/only.txt2
-rw-r--r--examples/host/cdc_msc_hid/src/cdc_app.c113
-rw-r--r--examples/host/cdc_msc_hid/src/hid_app.c2
-rw-r--r--examples/host/cdc_msc_hid/src/main.c44
-rw-r--r--examples/host/cdc_msc_hid/src/msc_app.c48
-rw-r--r--examples/host/cdc_msc_hid/src/tusb_config.h68
-rw-r--r--examples/host/hid_controller/CMakeLists.txt7
-rw-r--r--examples/host/hid_controller/Makefile4
-rw-r--r--examples/host/hid_controller/only.txt2
-rw-r--r--examples/host/hid_controller/src/hid_app.c89
-rw-r--r--examples/host/hid_controller/src/main.c9
-rw-r--r--examples/host/hid_controller/src/tusb_config.h56
-rw-r--r--examples/host/hid_to_cdc/Makefile19
-rw-r--r--examples/host/hid_to_cdc/only.txt2
-rw-r--r--examples/host/hid_to_cdc/src/main.c315
-rw-r--r--examples/host/hid_to_cdc/src/tusb_config.h163
-rw-r--r--examples/host/hid_to_cdc/src/usb_descriptors.c266
-rw-r--r--examples/host/msc_file_explorer/CMakeLists.txt (renamed from examples/host/hid_to_cdc/CMakeLists.txt)14
-rw-r--r--examples/host/msc_file_explorer/Makefile37
-rw-r--r--examples/host/msc_file_explorer/only.txt11
-rw-r--r--examples/host/msc_file_explorer/src/main.c127
-rw-r--r--examples/host/msc_file_explorer/src/msc_app.c640
-rw-r--r--examples/host/msc_file_explorer/src/tusb_config.h114
31 files changed, 1320 insertions, 940 deletions
diff --git a/examples/host/CMakeLists.txt b/examples/host/CMakeLists.txt
index 5c63ec0c0..758973ab2 100644
--- a/examples/host/CMakeLists.txt
+++ b/examples/host/CMakeLists.txt
@@ -6,5 +6,7 @@ project(tinyusb_host_examples)
family_initialize_project(tinyusb_host_examples ${CMAKE_CURRENT_LIST_DIR})
# family_add_subdirectory will filter what to actually add based on selected FAMILY
+family_add_subdirectory(bare_api)
family_add_subdirectory(cdc_msc_hid)
family_add_subdirectory(hid_controller)
+family_add_subdirectory(msc_file_explorer)
diff --git a/examples/host/bare_api/CMakeLists.txt b/examples/host/bare_api/CMakeLists.txt
index bff281a8c..616edd4ac 100644
--- a/examples/host/bare_api/CMakeLists.txt
+++ b/examples/host/bare_api/CMakeLists.txt
@@ -24,4 +24,9 @@ target_include_directories(${PROJECT} PUBLIC
# Configure compilation flags and libraries for the example... see the corresponding function
# in hw/bsp/FAMILY/family.cmake for details.
-family_configure_host_example(${PROJECT}) \ No newline at end of file
+family_configure_host_example(${PROJECT})
+
+# Add pico-pio-usb for rp2040 since user can choose to run on bit-banging host
+if(FAMILY STREQUAL "rp2040")
+ family_add_pico_pio_usb(${PROJECT})
+endif()
diff --git a/examples/host/bare_api/Makefile b/examples/host/bare_api/Makefile
index 13e14df53..058307c40 100644
--- a/examples/host/bare_api/Makefile
+++ b/examples/host/bare_api/Makefile
@@ -1,4 +1,3 @@
-include ../../../tools/top.mk
include ../../make.mk
INC += \
@@ -11,9 +10,6 @@ EXAMPLE_SOURCE += \
SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
-# TODO: suppress warning caused by host stack
-CFLAGS += -Wno-error=cast-align -Wno-error=null-dereference
-
# TinyUSB Host Stack source
SRC_C += \
src/class/cdc/cdc_host.c \
diff --git a/examples/host/bare_api/only.txt b/examples/host/bare_api/only.txt
index 7fe4e3f5c..fa9c14857 100644
--- a/examples/host/bare_api/only.txt
+++ b/examples/host/bare_api/only.txt
@@ -3,7 +3,9 @@ mcu:LPC177X_8X
mcu:LPC18XX
mcu:LPC40XX
mcu:LPC43XX
+mcu:MIMXRT
mcu:MIMXRT10XX
+mcu:MIMXRT11XX
mcu:RP2040
mcu:MSP432E4
mcu:RX65X
diff --git a/examples/host/bare_api/src/main.c b/examples/host/bare_api/src/main.c
index eb3f7d8d7..bb7fa850e 100644
--- a/examples/host/bare_api/src/main.c
+++ b/examples/host/bare_api/src/main.c
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@@ -62,8 +62,10 @@ int main(void)
{
board_init();
- printf("TinyUSB Host HID Controller Example\r\n");
- tusb_init();
+ printf("TinyUSB Bare API Example\r\n");
+
+ // init host stack on configured roothub port
+ tuh_init(BOARD_TUH_RHPORT);
while (1)
{
@@ -82,8 +84,8 @@ void tuh_mount_cb (uint8_t daddr)
{
printf("Device attached, address = %d\r\n", daddr);
- // Get Device Descriptor sync API
- // TODO: invoking control trannsfer now has issue with mounting hub with multiple devices attached, fix later
+ // Get Device Descriptor
+ // TODO: invoking control transfer now has issue with mounting hub with multiple devices attached, fix later
tuh_descriptor_get_device(daddr, &desc_device, 18, print_device_descriptor, 0);
}
@@ -187,7 +189,7 @@ void parse_config_descriptor(uint8_t dev_addr, tusb_desc_configuration_t const*
if( TUSB_DESC_INTERFACE != tu_desc_type(p_desc) ) return;
tusb_desc_interface_t const* desc_itf = (tusb_desc_interface_t const*) p_desc;
- uint16_t const drv_len = count_interface_total_len(desc_itf, assoc_itf_count, desc_end-p_desc);
+ uint16_t const drv_len = count_interface_total_len(desc_itf, assoc_itf_count, (uint16_t) (desc_end-p_desc));
// probably corrupted descriptor
if(drv_len < sizeof(tusb_desc_interface_t)) return;
@@ -242,7 +244,8 @@ void hid_report_received(tuh_xfer_t* xfer);
void open_hid_interface(uint8_t daddr, tusb_desc_interface_t const *desc_itf, uint16_t max_len)
{
// len = interface + hid + n*endpoints
- uint16_t const drv_len = sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) + desc_itf->bNumEndpoints*sizeof(tusb_desc_endpoint_t);
+ uint16_t const drv_len = (uint16_t) (sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) +
+ desc_itf->bNumEndpoints * sizeof(tusb_desc_endpoint_t));
// corrupted descriptor
if (max_len < drv_len) return;
@@ -375,7 +378,7 @@ static void _convert_utf16le_to_utf8(const uint16_t *utf16, size_t utf16_len, ui
for (size_t i = 0; i < utf16_len; i++) {
uint16_t chr = utf16[i];
if (chr < 0x80) {
- *utf8++ = chr & 0xff;
+ *utf8++ = chr & 0xffu;
} else if (chr < 0x800) {
*utf8++ = (uint8_t)(0xC0 | (chr >> 6 & 0x1F));
*utf8++ = (uint8_t)(0x80 | (chr >> 0 & 0x3F));
@@ -403,12 +406,12 @@ static int _count_utf8_bytes(const uint16_t *buf, size_t len) {
}
// TODO: Handle UTF-16 code points that take two entries.
}
- return total_bytes;
+ return (int) total_bytes;
}
static void print_utf16(uint16_t *temp_buf, size_t buf_len) {
size_t utf16_len = ((temp_buf[0] & 0xff) - 2) / sizeof(uint16_t);
- size_t utf8_len = _count_utf8_bytes(temp_buf + 1, utf16_len);
+ size_t utf8_len = (size_t) _count_utf8_bytes(temp_buf + 1, utf16_len);
_convert_utf16le_to_utf8(temp_buf + 1, utf16_len, (uint8_t *) temp_buf, sizeof(uint16_t) * buf_len);
((uint8_t*) temp_buf)[utf8_len] = '\0';
diff --git a/examples/host/bare_api/src/tusb_config.h b/examples/host/bare_api/src/tusb_config.h
index 9b789290d..ede9618d3 100644
--- a/examples/host/bare_api/src/tusb_config.h
+++ b/examples/host/bare_api/src/tusb_config.h
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@@ -30,27 +30,48 @@
extern "C" {
#endif
+//--------------------------------------------------------------------+
+// Board Specific Configuration
+//--------------------------------------------------------------------+
+
+#if CFG_TUSB_MCU == OPT_MCU_RP2040
+// change to 1 if using pico-pio-usb as host controller for raspberry rp2040
+#define CFG_TUH_RPI_PIO_USB 0
+#define BOARD_TUH_RHPORT CFG_TUH_RPI_PIO_USB
+#endif
+
+// 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
+
//--------------------------------------------------------------------
// COMMON CONFIGURATION
//--------------------------------------------------------------------
// defined by compiler flags for flexibility
#ifndef CFG_TUSB_MCU
- #error CFG_TUSB_MCU must be defined
+#error CFG_TUSB_MCU must be defined
#endif
-#if CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX
- #define CFG_TUSB_RHPORT0_MODE (OPT_MODE_HOST | OPT_MODE_HIGH_SPEED)
-#else
- #define CFG_TUSB_RHPORT0_MODE OPT_MODE_HOST
+#ifndef CFG_TUSB_OS
+#define CFG_TUSB_OS OPT_OS_NONE
#endif
-#ifndef CFG_TUSB_OS
-#define CFG_TUSB_OS OPT_OS_NONE
+#ifndef CFG_TUSB_DEBUG
+#define CFG_TUSB_DEBUG 0
#endif
-// CFG_TUSB_DEBUG is defined by compiler in DEBUG build
-// #define CFG_TUSB_DEBUG 0
+// Enable Host stack
+#define CFG_TUH_ENABLED 1
+
+// Default is max speed that hardware controller could support with on-chip PHY
+#define CFG_TUH_MAX_SPEED BOARD_TUH_MAX_SPEED
/* 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
@@ -59,12 +80,12 @@
* - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") ))
* - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4)))
*/
-#ifndef CFG_TUSB_MEM_SECTION
-#define CFG_TUSB_MEM_SECTION
+#ifndef CFG_TUH_MEM_SECTION
+#define CFG_TUH_MEM_SECTION
#endif
-#ifndef CFG_TUSB_MEM_ALIGN
-#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4)))
+#ifndef CFG_TUH_MEM_ALIGN
+#define CFG_TUH_MEM_ALIGN __attribute__ ((aligned(4)))
#endif
//--------------------------------------------------------------------
@@ -79,7 +100,7 @@
// max device support (excluding hub device)
// 1 hub typically has 4 ports
-#define CFG_TUH_DEVICE_MAX (CFG_TUH_HUB ? 4 : 1)
+#define CFG_TUH_DEVICE_MAX (3*CFG_TUH_HUB + 1)
// Max endpoint per device
#define CFG_TUH_ENDPOINT_MAX 8
diff --git a/examples/host/cdc_msc_hid/CMakeLists.txt b/examples/host/cdc_msc_hid/CMakeLists.txt
index 0a99bc3a9..d7d1a54d7 100644
--- a/examples/host/cdc_msc_hid/CMakeLists.txt
+++ b/examples/host/cdc_msc_hid/CMakeLists.txt
@@ -14,6 +14,7 @@ add_executable(${PROJECT})
# Example source
target_sources(${PROJECT} PUBLIC
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/cdc_app.c
${CMAKE_CURRENT_SOURCE_DIR}/src/hid_app.c
${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
${CMAKE_CURRENT_SOURCE_DIR}/src/msc_app.c
@@ -26,4 +27,9 @@ target_include_directories(${PROJECT} PUBLIC
# Configure compilation flags and libraries for the example... see the corresponding function
# in hw/bsp/FAMILY/family.cmake for details.
-family_configure_host_example(${PROJECT}) \ No newline at end of file
+family_configure_host_example(${PROJECT})
+
+# Add pico-pio-usb for rp2040 since user can choose to run on bit-banging host
+if(FAMILY STREQUAL "rp2040")
+ family_add_pico_pio_usb(${PROJECT})
+endif()
diff --git a/examples/host/cdc_msc_hid/Makefile b/examples/host/cdc_msc_hid/Makefile
index 272acbac8..7c16b39d3 100644
--- a/examples/host/cdc_msc_hid/Makefile
+++ b/examples/host/cdc_msc_hid/Makefile
@@ -1,4 +1,3 @@
-include ../../../tools/top.mk
include ../../make.mk
INC += \
@@ -6,11 +5,13 @@ INC += \
$(TOP)/hw \
# Example source
-EXAMPLE_SOURCE += $(wildcard src/*.c)
-SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
+EXAMPLE_SOURCE = \
+ src/cdc_app.c \
+ src/hid_app.c \
+ src/main.c \
+ src/msc_app.c \
-# TODO: suppress warning caused by host stack
-CFLAGS += -Wno-error=cast-align -Wno-error=null-dereference
+SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
# TinyUSB Host Stack source
SRC_C += \
diff --git a/examples/host/cdc_msc_hid/only.txt b/examples/host/cdc_msc_hid/only.txt
index 7fe4e3f5c..fa9c14857 100644
--- a/examples/host/cdc_msc_hid/only.txt
+++ b/examples/host/cdc_msc_hid/only.txt
@@ -3,7 +3,9 @@ mcu:LPC177X_8X
mcu:LPC18XX
mcu:LPC40XX
mcu:LPC43XX
+mcu:MIMXRT
mcu:MIMXRT10XX
+mcu:MIMXRT11XX
mcu:RP2040
mcu:MSP432E4
mcu:RX65X
diff --git a/examples/host/cdc_msc_hid/src/cdc_app.c b/examples/host/cdc_msc_hid/src/cdc_app.c
new file mode 100644
index 000000000..7769d109e
--- /dev/null
+++ b/examples/host/cdc_msc_hid/src/cdc_app.c
@@ -0,0 +1,113 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022, 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.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#include "tusb.h"
+#include "bsp/board.h"
+
+//--------------------------------------------------------------------+
+// MACRO TYPEDEF CONSTANT ENUM DECLARATION
+//--------------------------------------------------------------------+
+
+
+//------------- IMPLEMENTATION -------------//
+
+size_t get_console_inputs(uint8_t* buf, size_t bufsize)
+{
+ size_t count = 0;
+ while (count < bufsize)
+ {
+ int ch = board_getchar();
+ if ( ch <= 0 ) break;
+
+ buf[count] = (uint8_t) ch;
+ count++;
+ }
+
+ return count;
+}
+
+void cdc_app_task(void)
+{
+ uint8_t buf[64+1]; // +1 for extra null character
+ uint32_t const bufsize = sizeof(buf)-1;
+
+ uint32_t count = get_console_inputs(buf, bufsize);
+ buf[count] = 0;
+
+ // loop over all mounted interfaces
+ for(uint8_t idx=0; idx<CFG_TUH_CDC; idx++)
+ {
+ if ( tuh_cdc_mounted(idx) )
+ {
+ // console --> cdc interfaces
+ if (count)
+ {
+ tuh_cdc_write(idx, buf, count);
+ tuh_cdc_write_flush(idx);
+ }
+ }
+ }
+}
+
+// Invoked when received new data
+void tuh_cdc_rx_cb(uint8_t idx)
+{
+ uint8_t buf[64+1]; // +1 for extra null character
+ uint32_t const bufsize = sizeof(buf)-1;
+
+ // forward cdc interfaces -> console
+ uint32_t count = tuh_cdc_read(idx, buf, bufsize);
+ buf[count] = 0;
+
+ printf((char*) buf);
+}
+
+void tuh_cdc_mount_cb(uint8_t idx)
+{
+ tuh_itf_info_t itf_info = { 0 };
+ tuh_cdc_itf_get_info(idx, &itf_info);
+
+ printf("CDC Interface is mounted: address = %u, itf_num = %u\r\n", itf_info.daddr, itf_info.desc.bInterfaceNumber);
+
+#ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM
+ // CFG_TUH_CDC_LINE_CODING_ON_ENUM must be defined for line coding is set by tinyusb in enumeration
+ // otherwise you need to call tuh_cdc_set_line_coding() first
+ cdc_line_coding_t line_coding = { 0 };
+ if ( tuh_cdc_get_local_line_coding(idx, &line_coding) )
+ {
+ printf(" Baudrate: %lu, Stop Bits : %u\r\n", line_coding.bit_rate, line_coding.stop_bits);
+ printf(" Parity : %u, Data Width: %u\r\n", line_coding.parity , line_coding.data_bits);
+ }
+#endif
+}
+
+void tuh_cdc_umount_cb(uint8_t idx)
+{
+ tuh_itf_info_t itf_info = { 0 };
+ tuh_cdc_itf_get_info(idx, &itf_info);
+
+ printf("CDC Interface is unmounted: address = %u, itf_num = %u\r\n", itf_info.daddr, itf_info.desc.bInterfaceNumber);
+}
diff --git a/examples/host/cdc_msc_hid/src/hid_app.c b/examples/host/cdc_msc_hid/src/hid_app.c
index 11437c2b4..ed53c502d 100644
--- a/examples/host/cdc_msc_hid/src/hid_app.c
+++ b/examples/host/cdc_msc_hid/src/hid_app.c
@@ -247,7 +247,7 @@ static void process_generic_report(uint8_t dev_addr, uint8_t instance, uint8_t c
// Composite report, 1st byte is report ID, data starts from 2nd byte
uint8_t const rpt_id = report[0];
- // Find report id in the arrray
+ // Find report id in the array
for(uint8_t i=0; i<rpt_count; i++)
{
if (rpt_id == rpt_info_arr[i].report_id )
diff --git a/examples/host/cdc_msc_hid/src/main.c b/examples/host/cdc_msc_hid/src/main.c
index 0fc7ef146..1f4acb822 100644
--- a/examples/host/cdc_msc_hid/src/main.c
+++ b/examples/host/cdc_msc_hid/src/main.c
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@@ -35,7 +35,7 @@
//--------------------------------------------------------------------+
void led_blinking_task(void);
-extern void cdc_task(void);
+extern void cdc_app_task(void);
extern void hid_app_task(void);
/*------------- MAIN -------------*/
@@ -45,53 +45,21 @@ int main(void)
printf("TinyUSB Host CDC MSC HID Example\r\n");
- tusb_init();
+ // init host stack on configured roothub port
+ tuh_init(BOARD_TUH_RHPORT);
while (1)
{
// tinyusb host task
tuh_task();
- led_blinking_task();
-
-#if CFG_TUH_CDC
- cdc_task();
-#endif
-#if CFG_TUH_HID
+ led_blinking_task();
+ cdc_app_task();
hid_app_task();
-#endif
}
-
- return 0;
}
//--------------------------------------------------------------------+
-// USB CDC
-//--------------------------------------------------------------------+
-#if CFG_TUH_CDC
-CFG_TUSB_MEM_SECTION static char serial_in_buffer[64] = { 0 };
-
-// invoked ISR context
-void tuh_cdc_xfer_isr(uint8_t dev_addr, xfer_result_t event, cdc_pipeid_t pipe_id, uint32_t xferred_bytes)
-{
- (void) event;
- (void) pipe_id;
- (void) xferred_bytes;
-
- printf(serial_in_buffer);
- tu_memclr(serial_in_buffer, sizeof(serial_in_buffer));
-
- tuh_cdc_receive(dev_addr, serial_in_buffer, sizeof(serial_in_buffer), true); // waiting for next data
-}
-
-void cdc_task(void)
-{
-
-}
-
-#endif
-
-//--------------------------------------------------------------------+
// TinyUSB Callbacks
//--------------------------------------------------------------------+
diff --git a/examples/host/cdc_msc_hid/src/msc_app.c b/examples/host/cdc_msc_hid/src/msc_app.c
index 77a72052d..e9c9676b8 100644
--- a/examples/host/cdc_msc_hid/src/msc_app.c
+++ b/examples/host/cdc_msc_hid/src/msc_app.c
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@@ -25,15 +25,16 @@
#include "tusb.h"
-#if CFG_TUH_MSC
-
//--------------------------------------------------------------------+
// MACRO TYPEDEF CONSTANT ENUM DECLARATION
//--------------------------------------------------------------------+
static scsi_inquiry_resp_t inquiry_resp;
-bool inquiry_complete_cb(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw)
+bool inquiry_complete_cb(uint8_t dev_addr, tuh_msc_complete_data_t const * cb_data)
{
+ msc_cbw_t const* cbw = cb_data->cbw;
+ msc_csw_t const* csw = cb_data->csw;
+
if (csw->status != 0)
{
printf("Inquiry failed\r\n");
@@ -59,48 +60,11 @@ void tuh_msc_mount_cb(uint8_t dev_addr)
printf("A MassStorage device is mounted\r\n");
uint8_t const lun = 0;
- tuh_msc_inquiry(dev_addr, lun, &inquiry_resp, inquiry_complete_cb);
-//
-// //------------- file system (only 1 LUN support) -------------//
-// uint8_t phy_disk = dev_addr-1;
-// disk_initialize(phy_disk);
-//
-// if ( disk_is_ready(phy_disk) )
-// {
-// if ( f_mount(phy_disk, &fatfs[phy_disk]) != FR_OK )
-// {
-// puts("mount failed");
-// return;
-// }
-//
-// f_chdrive(phy_disk); // change to newly mounted drive
-// f_chdir("/"); // root as current dir
-//
-// cli_init();
-// }
+ tuh_msc_inquiry(dev_addr, lun, &inquiry_resp, inquiry_complete_cb, 0);
}
void tuh_msc_umount_cb(uint8_t dev_addr)
{
(void) dev_addr;
printf("A MassStorage device is unmounted\r\n");
-
-// uint8_t phy_disk = dev_addr-1;
-//
-// f_mount(phy_disk, NULL); // unmount disk
-// disk_deinitialize(phy_disk);
-//
-// if ( phy_disk == f_get_current_drive() )
-// { // active drive is unplugged --> change to other drive
-// for(uint8_t i=0; i<CFG_TUH_DEVICE_MAX; i++)
-// {
-// if ( disk_is_ready(i) )
-// {
-// f_chdrive(i);
-// cli_init(); // refractor, rename
-// }
-// }
-// }
}
-
-#endif
diff --git a/examples/host/cdc_msc_hid/src/tusb_config.h b/examples/host/cdc_msc_hid/src/tusb_config.h
index bc6c68e5b..1152e4910 100644
--- a/examples/host/cdc_msc_hid/src/tusb_config.h
+++ b/examples/host/cdc_msc_hid/src/tusb_config.h
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@@ -30,27 +30,48 @@
extern "C" {
#endif
+//--------------------------------------------------------------------+
+// Board Specific Configuration
+//--------------------------------------------------------------------+
+
+#if CFG_TUSB_MCU == OPT_MCU_RP2040
+// change to 1 if using pico-pio-usb as host controller for raspberry rp2040
+#define CFG_TUH_RPI_PIO_USB 0
+#define BOARD_TUH_RHPORT CFG_TUH_RPI_PIO_USB
+#endif
+
+// 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
+
//--------------------------------------------------------------------
// COMMON CONFIGURATION
//--------------------------------------------------------------------
// defined by compiler flags for flexibility
#ifndef CFG_TUSB_MCU
- #error CFG_TUSB_MCU must be defined
+#error CFG_TUSB_MCU must be defined
#endif
-#if CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX
- #define CFG_TUSB_RHPORT0_MODE (OPT_MODE_HOST | OPT_MODE_HIGH_SPEED)
-#else
- #define CFG_TUSB_RHPORT0_MODE OPT_MODE_HOST
+#ifndef CFG_TUSB_OS
+#define CFG_TUSB_OS OPT_OS_NONE
#endif
-#ifndef CFG_TUSB_OS
-#define CFG_TUSB_OS OPT_OS_NONE
+#ifndef CFG_TUSB_DEBUG
+#define CFG_TUSB_DEBUG 0
#endif
-// CFG_TUSB_DEBUG is defined by compiler in DEBUG build
-// #define CFG_TUSB_DEBUG 0
+// Enable Host stack
+#define CFG_TUH_ENABLED 1
+
+// Default is max speed that hardware controller could support with on-chip PHY
+#define CFG_TUH_MAX_SPEED BOARD_TUH_MAX_SPEED
/* 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
@@ -59,12 +80,12 @@
* - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") ))
* - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4)))
*/
-#ifndef CFG_TUSB_MEM_SECTION
-#define CFG_TUSB_MEM_SECTION
+#ifndef CFG_TUH_MEM_SECTION
+#define CFG_TUH_MEM_SECTION
#endif
-#ifndef CFG_TUSB_MEM_ALIGN
-#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4)))
+#ifndef CFG_TUH_MEM_ALIGN
+#define CFG_TUH_MEM_ALIGN __attribute__ ((aligned(4)))
#endif
//--------------------------------------------------------------------
@@ -74,19 +95,30 @@
// Size of buffer to hold descriptors and other data used for enumeration
#define CFG_TUH_ENUMERATION_BUFSIZE 256
-#define CFG_TUH_HUB 1
+#define CFG_TUH_HUB 1 // number of supported hubs
#define CFG_TUH_CDC 1
-#define CFG_TUH_HID 4 // typical keyboard + mouse device can have 3-4 HID interfaces
+#define CFG_TUH_HID (3*CFG_TUH_DEVICE_MAX) // typical keyboard + mouse device can have 3-4 HID interfaces
#define CFG_TUH_MSC 1
#define CFG_TUH_VENDOR 0
-// max device support (excluding hub device)
-#define CFG_TUH_DEVICE_MAX (CFG_TUH_HUB ? 4 : 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)
//------------- HID -------------//
#define CFG_TUH_HID_EPIN_BUFSIZE 64
#define CFG_TUH_HID_EPOUT_BUFSIZE 64
+//------------- CDC -------------//
+
+// Set Line Control state on enumeration/mounted:
+// DTR ( bit 0), RTS (bit 1)
+#define CFG_TUH_CDC_LINE_CONTROL_ON_ENUM 0x03
+
+// Set Line Coding on enumeration/mounted, value for cdc_line_coding_t
+// bit rate = 115200, 1 stop bit, no parity, 8 bit data width
+#define CFG_TUH_CDC_LINE_CODING_ON_ENUM { 115200, CDC_LINE_CONDING_STOP_BITS_1, CDC_LINE_CODING_PARITY_NONE, 8 }
+
+
#ifdef __cplusplus
}
#endif
diff --git a/examples/host/hid_controller/CMakeLists.txt b/examples/host/hid_controller/CMakeLists.txt
index aaf8bc34f..ac3070b82 100644
--- a/examples/host/hid_controller/CMakeLists.txt
+++ b/examples/host/hid_controller/CMakeLists.txt
@@ -25,4 +25,9 @@ target_include_directories(${PROJECT} PUBLIC
# Configure compilation flags and libraries for the example... see the corresponding function
# in hw/bsp/FAMILY/family.cmake for details.
-family_configure_host_example(${PROJECT}) \ No newline at end of file
+family_configure_host_example(${PROJECT})
+
+# Add pico-pio-usb for rp2040 since user can choose to run on bit-banging host
+if(FAMILY STREQUAL "rp2040")
+ family_add_pico_pio_usb(${PROJECT})
+endif()
diff --git a/examples/host/hid_controller/Makefile b/examples/host/hid_controller/Makefile
index 06dc56914..cda2977bc 100644
--- a/examples/host/hid_controller/Makefile
+++ b/examples/host/hid_controller/Makefile
@@ -1,4 +1,3 @@
-include ../../../tools/top.mk
include ../../make.mk
INC += \
@@ -12,9 +11,6 @@ EXAMPLE_SOURCE += \
SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
-# TODO: suppress warning caused by host stack
-CFLAGS += -Wno-error=cast-align -Wno-error=null-dereference
-
# TinyUSB Host Stack source
SRC_C += \
src/class/cdc/cdc_host.c \
diff --git a/examples/host/hid_controller/only.txt b/examples/host/hid_controller/only.txt
index 7fe4e3f5c..fa9c14857 100644
--- a/examples/host/hid_controller/only.txt
+++ b/examples/host/hid_controller/only.txt
@@ -3,7 +3,9 @@ mcu:LPC177X_8X
mcu:LPC18XX
mcu:LPC40XX
mcu:LPC43XX
+mcu:MIMXRT
mcu:MIMXRT10XX
+mcu:MIMXRT11XX
mcu:RP2040
mcu:MSP432E4
mcu:RX65X
diff --git a/examples/host/hid_controller/src/hid_app.c b/examples/host/hid_controller/src/hid_app.c
index 582e01959..76de97b41 100644
--- a/examples/host/hid_controller/src/hid_app.c
+++ b/examples/host/hid_controller/src/hid_app.c
@@ -91,9 +91,8 @@ typedef struct TU_ATTR_PACKED
uint8_t counter : 6; // +1 each report
};
- // comment out since not used by this example
- // uint8_t l2_trigger; // 0 released, 0xff fully pressed
- // uint8_t r2_trigger; // as above
+ uint8_t l2_trigger; // 0 released, 0xff fully pressed
+ uint8_t r2_trigger; // as above
// uint16_t timestamp;
// uint8_t battery;
@@ -105,15 +104,54 @@ typedef struct TU_ATTR_PACKED
} sony_ds4_report_t;
+typedef struct TU_ATTR_PACKED {
+ // First 16 bits set what data is pertinent in this structure (1 = set; 0 = not set)
+ uint8_t set_rumble : 1;
+ uint8_t set_led : 1;
+ uint8_t set_led_blink : 1;
+ uint8_t set_ext_write : 1;
+ uint8_t set_left_volume : 1;
+ uint8_t set_right_volume : 1;
+ uint8_t set_mic_volume : 1;
+ uint8_t set_speaker_volume : 1;
+ uint8_t set_flags2;
+
+ uint8_t reserved;
+
+ uint8_t motor_right;
+ uint8_t motor_left;
+
+ uint8_t lightbar_red;
+ uint8_t lightbar_green;
+ uint8_t lightbar_blue;
+ uint8_t lightbar_blink_on;
+ uint8_t lightbar_blink_off;
+
+ uint8_t ext_data[8];
+
+ uint8_t volume_left;
+ uint8_t volume_right;
+ uint8_t volume_mic;
+ uint8_t volume_speaker;
+
+ uint8_t other[9];
+} sony_ds4_output_report_t;
+
+static bool ds4_mounted = false;
+static uint8_t ds4_dev_addr = 0;
+static uint8_t ds4_instance = 0;
+static uint8_t motor_left = 0;
+static uint8_t motor_right = 0;
+
// check if device is Sony DualShock 4
static inline bool is_sony_ds4(uint8_t dev_addr)
{
uint16_t vid, pid;
tuh_vid_pid_get(dev_addr, &vid, &pid);
- return ( (vid == 0x054c && (pid == 0x09cc || pid == 0x05c4)) // Sony DualShock4
- || (vid == 0x0f0d && pid == 0x005e) // Hori FC4
- || (vid == 0x0f0d && pid == 0x00ee) // Hori PS4 Mini (PS4-099U)
+ return ( (vid == 0x054c && (pid == 0x09cc || pid == 0x05c4)) // Sony DualShock4
+ || (vid == 0x0f0d && pid == 0x005e) // Hori FC4
+ || (vid == 0x0f0d && pid == 0x00ee) // Hori PS4 Mini (PS4-099U)
|| (vid == 0x1f4f && pid == 0x1002) // ASW GG xrd controller
);
}
@@ -124,7 +162,23 @@ static inline bool is_sony_ds4(uint8_t dev_addr)
void hid_app_task(void)
{
- // nothing to do
+ if (ds4_mounted)
+ {
+ const uint32_t interval_ms = 200;
+ static uint32_t start_ms = 0;
+
+ uint32_t current_time_ms = board_millis();
+ if ( current_time_ms - start_ms >= interval_ms)
+ {
+ start_ms = current_time_ms;
+
+ sony_ds4_output_report_t output_report = {0};
+ output_report.set_rumble = 1;
+ output_report.motor_left = motor_left;
+ output_report.motor_right = motor_right;
+ tuh_hid_send_report(ds4_dev_addr, ds4_instance, 5, &output_report, sizeof(output_report));
+ }
+ }
}
//--------------------------------------------------------------------+
@@ -149,6 +203,14 @@ void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_re
// Sony DualShock 4 [CUH-ZCT2x]
if ( is_sony_ds4(dev_addr) )
{
+ if (!ds4_mounted)
+ {
+ ds4_dev_addr = dev_addr;
+ ds4_instance = instance;
+ motor_left = 0;
+ motor_right = 0;
+ ds4_mounted = true;
+ }
// request to receive report
// tuh_hid_report_received_cb() will be invoked when report is available
if ( !tuh_hid_receive_report(dev_addr, instance) )
@@ -162,7 +224,10 @@ void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_re
void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance)
{
printf("HID device address = %d, instance = %d is unmounted\r\n", dev_addr, instance);
-
+ if (ds4_mounted && ds4_dev_addr == dev_addr && ds4_instance == instance)
+ {
+ ds4_mounted = false;
+ }
}
// check if different than 2
@@ -180,8 +245,8 @@ bool diff_report(sony_ds4_report_t const* rpt1, sony_ds4_report_t const* rpt2)
result = diff_than_2(rpt1->x, rpt2->x) || diff_than_2(rpt1->y , rpt2->y ) ||
diff_than_2(rpt1->z, rpt2->z) || diff_than_2(rpt1->rz, rpt2->rz);
- // check the reset with mem compare
- result |= memcmp(&rpt1->rz + 1, &rpt2->rz + 1, sizeof(sony_ds4_report_t)-4);
+ // check the rest with mem compare
+ result |= memcmp(&rpt1->rz + 1, &rpt2->rz + 1, sizeof(sony_ds4_report_t)-6);
return result;
}
@@ -235,6 +300,10 @@ void process_sony_ds4(uint8_t const* report, uint16_t len)
printf("\r\n");
}
+ // The left and right triggers control the intensity of the left and right rumble motors
+ motor_left = ds4_report.l2_trigger;
+ motor_right = ds4_report.r2_trigger;
+
prev_report = ds4_report;
}
}
diff --git a/examples/host/hid_controller/src/main.c b/examples/host/hid_controller/src/main.c
index b9b37a4d2..4dcc92587 100644
--- a/examples/host/hid_controller/src/main.c
+++ b/examples/host/hid_controller/src/main.c
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@@ -49,9 +49,10 @@ int main(void)
board_init();
printf("TinyUSB Host HID Controller Example\r\n");
- printf("Note: Events only displayed for explictly supported controllers\r\n");
+ printf("Note: Events only displayed for explicit supported controllers\r\n");
- tusb_init();
+ // init host stack on configured roothub port
+ tuh_init(BOARD_TUH_RHPORT);
while (1)
{
@@ -67,8 +68,6 @@ int main(void)
hid_app_task();
#endif
}
-
- return 0;
}
//--------------------------------------------------------------------+
diff --git a/examples/host/hid_controller/src/tusb_config.h b/examples/host/hid_controller/src/tusb_config.h
index 74b471ae4..d37fc02d2 100644
--- a/examples/host/hid_controller/src/tusb_config.h
+++ b/examples/host/hid_controller/src/tusb_config.h
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@@ -30,27 +30,48 @@
extern "C" {
#endif
+//--------------------------------------------------------------------+
+// Board Specific Configuration
+//--------------------------------------------------------------------+
+
+ #if CFG_TUSB_MCU == OPT_MCU_RP2040
+// change to 1 if using pico-pio-usb as host controller for raspberry rp2040
+#define CFG_TUH_RPI_PIO_USB 0
+#define BOARD_TUH_RHPORT CFG_TUH_RPI_PIO_USB
+#endif
+
+// 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
+
//--------------------------------------------------------------------
// COMMON CONFIGURATION
//--------------------------------------------------------------------
// defined by compiler flags for flexibility
#ifndef CFG_TUSB_MCU
- #error CFG_TUSB_MCU must be defined
+#error CFG_TUSB_MCU must be defined
#endif
-#if CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX
- #define CFG_TUSB_RHPORT0_MODE (OPT_MODE_HOST | OPT_MODE_HIGH_SPEED)
-#else
- #define CFG_TUSB_RHPORT0_MODE OPT_MODE_HOST
+#ifndef CFG_TUSB_OS
+#define CFG_TUSB_OS OPT_OS_NONE
#endif
-#ifndef CFG_TUSB_OS
-#define CFG_TUSB_OS OPT_OS_NONE
+#ifndef CFG_TUSB_DEBUG
+#define CFG_TUSB_DEBUG 0
#endif
-// CFG_TUSB_DEBUG is defined by compiler in DEBUG build
-// #define CFG_TUSB_DEBUG 0
+// Enable Host stack
+#define CFG_TUH_ENABLED 1
+
+// Default is max speed that hardware controller could support with on-chip PHY
+#define CFG_TUH_MAX_SPEED BOARD_TUH_MAX_SPEED
/* 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
@@ -59,12 +80,12 @@
* - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") ))
* - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4)))
*/
-#ifndef CFG_TUSB_MEM_SECTION
-#define CFG_TUSB_MEM_SECTION
+#ifndef CFG_TUH_MEM_SECTION
+#define CFG_TUH_MEM_SECTION
#endif
-#ifndef CFG_TUSB_MEM_ALIGN
-#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4)))
+#ifndef CFG_TUH_MEM_ALIGN
+#define CFG_TUH_MEM_ALIGN __attribute__ ((aligned(4)))
#endif
//--------------------------------------------------------------------
@@ -76,13 +97,12 @@
#define CFG_TUH_HUB 0
#define CFG_TUH_CDC 0
-#define CFG_TUH_HID 4 // typical keyboard + mouse device can have 3-4 HID interfaces
+#define CFG_TUH_HID (3*CFG_TUH_DEVICE_MAX) // typical keyboard + mouse device can have 3-4 HID interfaces
#define CFG_TUH_MSC 0
#define CFG_TUH_VENDOR 0
-// max device support (excluding hub device)
-// 1 hub typically has 4 ports
-#define CFG_TUH_DEVICE_MAX (CFG_TUH_HUB ? 4 : 1)
+// max device support (excluding hub device): 1 hub typically has 4 ports
+#define CFG_TUH_DEVICE_MAX (3*CFG_TUH_HUB + 1)
//------------- HID -------------//
diff --git a/examples/host/hid_to_cdc/Makefile b/examples/host/hid_to_cdc/Makefile
deleted file mode 100644
index 3fe9b0888..000000000
--- a/examples/host/hid_to_cdc/Makefile
+++ /dev/null
@@ -1,19 +0,0 @@
-include ../../../tools/top.mk
-include ../../make.mk
-
-INC += \
- src \
- $(TOP)/hw \
-
-# Example source
-EXAMPLE_SOURCE += $(wildcard src/*.c)
-SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
-
-CFLAGS += -Wno-error=cast-align -Wno-error=null-dereference
-
-SRC_C += \
- src/class/hid/hid_host.c \
- src/host/hub.c \
- src/host/usbh.c
-
-include ../../rules.mk
diff --git a/examples/host/hid_to_cdc/only.txt b/examples/host/hid_to_cdc/only.txt
deleted file mode 100644
index 78d94e3ce..000000000
--- a/examples/host/hid_to_cdc/only.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-board:mimxrt1060_evk
-board:mimxrt1064_evk
diff --git a/examples/host/hid_to_cdc/src/main.c b/examples/host/hid_to_cdc/src/main.c
deleted file mode 100644
index cdf5d264e..000000000
--- a/examples/host/hid_to_cdc/src/main.c
+++ /dev/null
@@ -1,315 +0,0 @@
-/*
- * 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.
- *
- */
-
-// This example runs both host and device concurrently. The USB host looks for
-// any HID device with reports that are 8 bytes long and then assumes they are
-// keyboard reports. It translates the keypresses of the reports to ASCII and
-// transmits it over CDC to the device's host.
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-
-#include "bsp/board.h"
-#include "tusb.h"
-
-//--------------------------------------------------------------------+
-// MACRO CONSTANT TYPEDEF PROTYPES
-//--------------------------------------------------------------------+
-
-// uncomment if you are using colemak layout
-// #define KEYBOARD_COLEMAK
-
-#ifdef KEYBOARD_COLEMAK
-const uint8_t colemak[128] = {
- 0 , 0, 0, 0, 0, 0, 0, 22,
- 9 , 23, 7, 0, 24, 17, 8, 12,
- 0 , 14, 28, 51, 0, 19, 21, 10,
- 15 , 0, 0, 0, 13, 0, 0, 0,
- 0 , 0, 0, 0, 0, 0, 0, 0,
- 0 , 0, 0, 0, 0, 0, 0, 0,
- 0 , 0, 0, 18, 0, 0, 0, 0,
- 0 , 0, 0, 0, 0, 0, 0, 0,
- 0 , 0, 0, 0, 0, 0, 0, 0,
- 0 , 0, 0, 0, 0, 0, 0, 0
-};
-#endif
-
-static uint8_t const keycode2ascii[128][2] = { HID_KEYCODE_TO_ASCII };
-
-/* Blink pattern
- * - 250 ms : device not mounted
- * - 1000 ms : device mounted
- * - 2500 ms : device is suspended
- */
-enum {
- BLINK_NOT_MOUNTED = 250,
- BLINK_MOUNTED = 1000,
- BLINK_SUSPENDED = 2500,
-};
-
-static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED;
-
-void led_blinking_task(void);
-void cdc_task(void);
-
-/*------------- MAIN -------------*/
-int main(void)
-{
- board_init();
- tusb_init();
-
- while (1)
- {
- tud_task(); // tinyusb device task
- tuh_task(); // tinyusb host task
- led_blinking_task();
-
- cdc_task();
- }
-
- return 0;
-}
-
-//--------------------------------------------------------------------+
-// Device callbacks
-//--------------------------------------------------------------------+
-
-// Invoked when device is mounted
-void tud_mount_cb(void)
-{
- blink_interval_ms = BLINK_MOUNTED;
-}
-
-// Invoked when device is unmounted
-void tud_umount_cb(void)
-{
- blink_interval_ms = BLINK_NOT_MOUNTED;
-}
-
-// Invoked when usb bus is suspended
-// remote_wakeup_en : if host allow us to perform remote wakeup
-// Within 7ms, device must draw an average of current less than 2.5 mA from bus
-void tud_suspend_cb(bool remote_wakeup_en)
-{
- (void) remote_wakeup_en;
- blink_interval_ms = BLINK_SUSPENDED;
-}
-
-// Invoked when usb bus is resumed
-void tud_resume_cb(void)
-{
- blink_interval_ms = BLINK_MOUNTED;
-}
-
-//--------------------------------------------------------------------+
-// Host callbacks
-//--------------------------------------------------------------------+
-
-// Invoked when device with hid interface is mounted
-// Report descriptor is also available for use. tuh_hid_parse_report_descriptor()
-// can be used to parse common/simple enough descriptor.
-// Note: if report descriptor length > CFG_TUH_ENUMERATION_BUFSIZE, it will be skipped
-// therefore report_desc = NULL, desc_len = 0
-void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len)
-{
- (void)desc_report;
- (void)desc_len;
- uint16_t vid, pid;
- tuh_vid_pid_get(dev_addr, &vid, &pid);
-
- printf("HID device address = %d, instance = %d is mounted\r\n", dev_addr, instance);
- printf("VID = %04x, PID = %04x\r\n", vid, pid);
-
- // Receive any report and treat it like a keyboard.
- // tuh_hid_report_received_cb() will be invoked when report is available
- if ( !tuh_hid_receive_report(dev_addr, instance) )
- {
- printf("Error: cannot request to receive report\r\n");
- }
-}
-
-// Invoked when device with hid interface is un-mounted
-void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance)
-{
- printf("HID device address = %d, instance = %d is unmounted\r\n", dev_addr, instance);
-}
-
-// keycodes from last report to check if key is holding or newly pressed
-uint8_t last_keycodes[6] = {0};
-
-// look up new key in previous keys
-static inline bool key_in_last_report(const uint8_t key_arr[6], uint8_t keycode)
-{
- for(uint8_t i=0; i<6; i++)
- {
- if (key_arr[i] == keycode) return true;
- }
-
- return false;
-}
-
-// Invoked when received report from device via interrupt endpoint
-void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len)
-{
- if (len != 8)
- {
- char ch_num;
-
- tud_cdc_write_str("incorrect report len: ");
-
- if ( len > 10 )
- {
- ch_num = '0' + (len / 10);
- tud_cdc_write(&ch_num, 1);
- len = len % 10;
- }
-
- ch_num = '0' + len;
- tud_cdc_write(&ch_num, 1);
-
- tud_cdc_write_str("\r\n");
- tud_cdc_write_flush();
-
- // Don't request a new report for a wrong sized endpoint.
- return;
- }
-
- uint8_t const modifiers = report[0];
- bool flush = false;
-
- for (int i = 2; i < 8; i++)
- {
- uint8_t keycode = report[i];
-
- if (keycode)
- {
- if ( key_in_last_report(last_keycodes, keycode) )
- {
- // exist in previous report means the current key is holding
- // do nothing
- }else
- {
- // not existed in previous report means the current key is pressed
- // Only print keycodes 0 - 128.
- if (keycode < 128)
- {
- // remap the key code for Colemak layout so @tannewt can type.
- #ifdef KEYBOARD_COLEMAK
- uint8_t colemak_key_code = colemak[keycode];
- if (colemak_key_code != 0) keycode = colemak_key_code;
- #endif
-
- bool const is_shift = modifiers & (KEYBOARD_MODIFIER_LEFTSHIFT | KEYBOARD_MODIFIER_RIGHTSHIFT);
- char c = keycode2ascii[keycode][is_shift ? 1 : 0];
- if (c)
- {
- if (c == '\n') tud_cdc_write("\r", 1);
- tud_cdc_write(&c, 1);
- flush = true;
- }
- }
- }
- }
- }
-
- if (flush) tud_cdc_write_flush();
-
- // save current report
- memcpy(last_keycodes, report+2, 6);
-
- // continue to request to receive report
- if ( !tuh_hid_receive_report(dev_addr, instance) )
- {
- printf("Error: cannot request to receive report\r\n");
- }
-}
-
-
-
-//--------------------------------------------------------------------+
-// USB CDC
-//--------------------------------------------------------------------+
-void cdc_task(void)
-{
- // connected() check for DTR bit
- // Most but not all terminal client set this when making connection
- // if ( tud_cdc_connected() )
- {
- // connected and there are data available
- if ( tud_cdc_available() )
- {
- // read datas
- char buf[64];
- uint32_t count = tud_cdc_read(buf, sizeof(buf));
- (void) count;
-
- // Echo back
- // Note: Skip echo by commenting out write() and write_flush()
- // for throughput test e.g
- // $ dd if=/dev/zero of=/dev/ttyACM0 count=10000
- tud_cdc_write(buf, count);
- tud_cdc_write_flush();
- }
- }
-}
-
-// Invoked when cdc when line state changed e.g connected/disconnected
-void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts)
-{
- (void) itf;
- (void) rts;
-
- // TODO set some indicator
- if ( dtr )
- {
- // Terminal connected
- }else
- {
- // Terminal disconnected
- }
-}
-
-// Invoked when CDC interface received data from host
-void tud_cdc_rx_cb(uint8_t itf)
-{
- (void) itf;
-}
-
-//--------------------------------------------------------------------+
-// BLINKING TASK
-//--------------------------------------------------------------------+
-void led_blinking_task(void)
-{
- static uint32_t start_ms = 0;
- static bool led_state = false;
-
- // Blink every interval ms
- if ( board_millis() - start_ms < blink_interval_ms) return; // not enough time
- start_ms += blink_interval_ms;
-
- board_led_write(led_state);
- led_state = 1 - led_state; // toggle
-}
diff --git a/examples/host/hid_to_cdc/src/tusb_config.h b/examples/host/hid_to_cdc/src/tusb_config.h
deleted file mode 100644
index 9a35ffc30..000000000
--- a/examples/host/hid_to_cdc/src/tusb_config.h
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * 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 board.mk
-#ifndef CFG_TUSB_MCU
- #error CFG_TUSB_MCU must be defined
-#endif
-
-// RHPort number used for device can be defined by board.mk, default to port 0
-#ifndef BOARD_DEVICE_RHPORT_NUM
- #define BOARD_DEVICE_RHPORT_NUM 0
-#endif
-
-// RHPort number used for device can be defined by board.mk, default to port 1
-#ifndef BOARD_HOST_RHPORT_NUM
- #define BOARD_HOST_RHPORT_NUM 1
-#endif
-
-// RHPort max operational speed can defined by board.mk
-// Default to Highspeed for MCU with internal HighSpeed PHY (can be port specific), otherwise FullSpeed
-#ifndef BOARD_DEVICE_RHPORT_SPEED
- #if TU_CHECK_MCU(OPT_MCU_LPC18XX, OPT_MCU_LPC43XX, OPT_MCU_MIMXRT10XX, OPT_MCU_NUC505) ||\
- TU_CHECK_MCU(OPT_MCU_CXD56, OPT_MCU_SAMX7X, OPT_MCU_BCM2711) ||\
- TU_CHECK_MCU(OPT_MCU_FT90X, OPT_MCU_FT93X)
- #define BOARD_DEVICE_RHPORT_SPEED OPT_MODE_HIGH_SPEED
- #else
- #define BOARD_DEVICE_RHPORT_SPEED OPT_MODE_FULL_SPEED
- #endif
-#endif
-
-// RHPort max operational speed can defined by board.mk
-// Default to Highspeed for MCU with internal HighSpeed PHY (can be port specific), otherwise FullSpeed
-#ifndef BOARD_HOST_RHPORT_SPEED
- #if TU_CHECK_MCU(OPT_MCU_LPC18XX, OPT_MCU_LPC43XX, OPT_MCU_MIMXRT10XX, OPT_MCU_NUC505) ||\
- TU_CHECK_MCU(OPT_MCU_CXD56, OPT_MCU_SAMX7X, OPT_MCU_BCM2711) ||\
- TU_CHECK_MCU(OPT_MCU_FT90X, OPT_MCU_FT93X)
- #define BOARD_HOST_RHPORT_SPEED OPT_MODE_HIGH_SPEED
- #else
- #define BOARD_HOST_RHPORT_SPEED OPT_MODE_FULL_SPEED
- #endif
-#endif
-
-// Device mode with rhport and speed defined by board.mk
-#if BOARD_DEVICE_RHPORT_NUM == 0
- #define CFG_TUSB_RHPORT0_MODE (OPT_MODE_DEVICE | BOARD_DEVICE_RHPORT_SPEED)
-#elif BOARD_DEVICE_RHPORT_NUM == 1
- #define CFG_TUSB_RHPORT1_MODE (OPT_MODE_DEVICE | BOARD_DEVICE_RHPORT_SPEED)
-#else
- #error "Incorrect RHPort configuration"
-#endif
-
-// Device mode with rhport and speed defined by board.mk
-#if BOARD_HOST_RHPORT_NUM == 0
- #define CFG_TUSB_RHPORT0_MODE (OPT_MODE_HOST | BOARD_HOST_RHPORT_SPEED)
-#elif BOARD_HOST_RHPORT_NUM == 1
- #define CFG_TUSB_RHPORT1_MODE (OPT_MODE_HOST | BOARD_HOST_RHPORT_SPEED)
-#else
- #error "Incorrect RHPort configuration"
-#endif
-
-// This example doesn't use an RTOS
-#ifndef CFG_TUSB_OS
-#define CFG_TUSB_OS OPT_OS_NONE
-#endif
-
-// CFG_TUSB_DEBUG is defined by compiler in DEBUG build
-// #define CFG_TUSB_DEBUG 0
-
-/* 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_TUSB_MEM_SECTION
-#define CFG_TUSB_MEM_SECTION
-#endif
-
-#ifndef CFG_TUSB_MEM_ALIGN
-#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4)))
-#endif
-
-//--------------------------------------------------------------------
-// DEVICE CONFIGURATION
-//--------------------------------------------------------------------
-
-#ifndef CFG_TUD_ENDPOINT0_SIZE
-#define CFG_TUD_ENDPOINT0_SIZE 64
-#endif
-
-//------------- CLASS -------------//
-#define CFG_TUD_CDC 1
-#define CFG_TUD_MSC 0
-#define CFG_TUD_HID 0
-#define CFG_TUD_MIDI 0
-#define CFG_TUD_VENDOR 0
-
-// CDC FIFO size of TX and RX
-#define CFG_TUD_CDC_RX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
-#define CFG_TUD_CDC_TX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
-
-// CDC Endpoint transfer buffer size, more is faster
-#define CFG_TUD_CDC_EP_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
-
-//--------------------------------------------------------------------
-// HOST CONFIGURATION
-//--------------------------------------------------------------------
-
-// Size of buffer to hold descriptors and other data used for enumeration
-#define CFG_TUH_ENUMERATION_BUFSIZE 256
-
-#define CFG_TUH_HUB 1
-#define CFG_TUH_CDC 0
-#define CFG_TUH_MSC 0
-#define CFG_TUH_VENDOR 0
-
-// max device support (excluding hub device)
-#define CFG_TUH_DEVICE_MAX (CFG_TUH_HUB ? 4 : 1) // hub typically has 4 ports
-
-//------------- HID -------------//
-#define CFG_TUH_HID 4
-#define CFG_TUH_HID_EPIN_BUFSIZE 64
-#define CFG_TUH_HID_EPOUT_BUFSIZE 64
-
-#ifdef __cplusplus
- }
-#endif
-
-#endif /* _TUSB_CONFIG_H_ */
diff --git a/examples/host/hid_to_cdc/src/usb_descriptors.c b/examples/host/hid_to_cdc/src/usb_descriptors.c
deleted file mode 100644
index 7dd73937c..000000000
--- a/examples/host/hid_to_cdc/src/usb_descriptors.c
+++ /dev/null
@@ -1,266 +0,0 @@
-/*
- * 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 "tusb.h"
-
-/* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug.
- * Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC.
- *
- * Auto ProductID layout's Bitmap:
- * [MSB] HID | MSC | CDC [LSB]
- */
-#define _PID_MAP(itf, n) ( (CFG_TUD_##itf) << (n) )
-#define USB_PID (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \
- _PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4) )
-
-#define USB_VID 0xCafe
-#define USB_BCD 0x0200
-
-//--------------------------------------------------------------------+
-// Device Descriptors
-//--------------------------------------------------------------------+
-tusb_desc_device_t const desc_device =
-{
- .bLength = sizeof(tusb_desc_device_t),
- .bDescriptorType = TUSB_DESC_DEVICE,
- .bcdUSB = USB_BCD,
-
- // Use Interface Association Descriptor (IAD) for CDC
- // As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1)
- .bDeviceClass = TUSB_CLASS_MISC,
- .bDeviceSubClass = MISC_SUBCLASS_COMMON,
- .bDeviceProtocol = MISC_PROTOCOL_IAD,
-
- .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
-
- .idVendor = USB_VID,
- .idProduct = USB_PID,
- .bcdDevice = 0x0100,
-
- .iManufacturer = 0x01,
- .iProduct = 0x02,
- .iSerialNumber = 0x03,
-
- .bNumConfigurations = 0x01
-};
-
-// Invoked when received GET DEVICE DESCRIPTOR
-// Application return pointer to descriptor
-uint8_t const * tud_descriptor_device_cb(void)
-{
- return (uint8_t const *) &desc_device;
-}
-
-//--------------------------------------------------------------------+
-// Configuration Descriptor
-//--------------------------------------------------------------------+
-
-enum
-{
- ITF_NUM_CDC = 0,
- ITF_NUM_CDC_DATA,
- ITF_NUM_MSC,
- ITF_NUM_TOTAL
-};
-
-#if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX
- // LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number
- // 0 control, 1 In, 2 Bulk, 3 Iso, 4 In, 5 Bulk etc ...
- #define EPNUM_CDC_NOTIF 0x81
- #define EPNUM_CDC_OUT 0x02
- #define EPNUM_CDC_IN 0x82
-
-#elif CFG_TUSB_MCU == OPT_MCU_SAMG || CFG_TUSB_MCU == OPT_MCU_SAMX7X
- // SAMG & SAME70 don't support a same endpoint number with different direction IN and OUT
- // e.g EP1 OUT & EP1 IN cannot exist together
- #define EPNUM_CDC_NOTIF 0x81
- #define EPNUM_CDC_OUT 0x02
- #define EPNUM_CDC_IN 0x83
-
-#elif CFG_TUSB_MCU == OPT_MCU_CXD56
- // CXD56 doesn't support a same endpoint number with different direction IN and OUT
- // e.g EP1 OUT & EP1 IN cannot exist together
- // CXD56 USB driver has fixed endpoint type (bulk/interrupt/iso) and direction (IN/OUT) by its number
- // 0 control (IN/OUT), 1 Bulk (IN), 2 Bulk (OUT), 3 In (IN), 4 Bulk (IN), 5 Bulk (OUT), 6 In (IN)
- #define EPNUM_CDC_NOTIF 0x83
- #define EPNUM_CDC_OUT 0x02
- #define EPNUM_CDC_IN 0x81
-
-#elif CFG_TUSB_MCU == OPT_MCU_FT90X || CFG_TUSB_MCU == OPT_MCU_FT93X
- // FT9XX doesn't support a same endpoint number with different direction IN and OUT
- // e.g EP1 OUT & EP1 IN cannot exist together
- #define EPNUM_CDC_NOTIF 0x81
- #define EPNUM_CDC_OUT 0x02
- #define EPNUM_CDC_IN 0x83
-
-#else
- #define EPNUM_CDC_NOTIF 0x81
- #define EPNUM_CDC_OUT 0x02
- #define EPNUM_CDC_IN 0x82
-
-#endif
-
-#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN)
-
-// full speed configuration
-uint8_t const desc_fs_configuration[] =
-{
- // Config number, interface count, string index, total length, attribute, power in mA
- TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
-
- // Interface number, string index, EP notification address and size, EP data address (out, in) and size.
- TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT, EPNUM_CDC_IN, 64),
-};
-
-#if TUD_OPT_HIGH_SPEED
-// Per USB specs: high speed capable device must report device_qualifier and other_speed_configuration
-
-// high speed configuration
-uint8_t const desc_hs_configuration[] =
-{
- // Config number, interface count, string index, total length, attribute, power in mA
- TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
-
- // Interface number, string index, EP notification address and size, EP data address (out, in) and size.
- TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT, EPNUM_CDC_IN, 512),
-};
-
-// other speed configuration
-uint8_t desc_other_speed_config[CONFIG_TOTAL_LEN];
-
-// device qualifier is mostly similar to device descriptor since we don't change configuration based on speed
-tusb_desc_device_qualifier_t const desc_device_qualifier =
-{
- .bLength = sizeof(tusb_desc_device_qualifier_t),
- .bDescriptorType = TUSB_DESC_DEVICE_QUALIFIER,
- .bcdUSB = USB_BCD,
-
- .bDeviceClass = TUSB_CLASS_MISC,
- .bDeviceSubClass = MISC_SUBCLASS_COMMON,
- .bDeviceProtocol = MISC_PROTOCOL_IAD,
-
- .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
- .bNumConfigurations = 0x01,
- .bReserved = 0x00
-};
-
-// Invoked when received GET DEVICE QUALIFIER DESCRIPTOR request
-// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete.
-// device_qualifier descriptor describes information about a high-speed capable device that would
-// change if the device were operating at the other speed. If not highspeed capable stall this request.
-uint8_t const* tud_descriptor_device_qualifier_cb(void)
-{
- return (uint8_t const*) &desc_device_qualifier;
-}
-
-// Invoked when received GET OTHER SEED CONFIGURATION DESCRIPTOR request
-// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
-// Configuration descriptor in the other speed e.g if high speed then this is for full speed and vice versa
-uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index)
-{
- (void) index; // for multiple configurations
-
- // if link speed is high return fullspeed config, and vice versa
- // Note: the descriptor type is OHER_SPEED_CONFIG instead of CONFIG
- memcpy(desc_other_speed_config,
- (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_fs_configuration : desc_hs_configuration,
- CONFIG_TOTAL_LEN);
-
- desc_other_speed_config[1] = TUSB_DESC_OTHER_SPEED_CONFIG;
-
- return desc_other_speed_config;
-}
-
-#endif // highspeed
-
-
-// Invoked when received GET CONFIGURATION DESCRIPTOR
-// Application return pointer to descriptor
-// Descriptor contents must exist long enough for transfer to complete
-uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
-{
- (void) index; // for multiple configurations
-
-#if TUD_OPT_HIGH_SPEED
- // Although we are highspeed, host may be fullspeed.
- return (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_hs_configuration : desc_fs_configuration;
-#else
- return desc_fs_configuration;
-#endif
-}
-
-//--------------------------------------------------------------------+
-// String Descriptors
-//--------------------------------------------------------------------+
-
-// array of pointer to string descriptors
-char const* string_desc_arr [] =
-{
- (const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
- "TinyUSB", // 1: Manufacturer
- "TinyUSB Device", // 2: Product
- "123456789012", // 3: Serials, should use chip ID
- "TinyUSB CDC", // 4: CDC Interface
-};
-
-static uint16_t _desc_str[32];
-
-// Invoked when received GET STRING DESCRIPTOR request
-// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
-uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid)
-{
- (void) langid;
-
- uint8_t chr_count;
-
- if ( index == 0)
- {
- memcpy(&_desc_str[1], string_desc_arr[0], 2);
- chr_count = 1;
- }else
- {
- // Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors.
- // https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors
-
- if ( !(index < sizeof(string_desc_arr)/sizeof(string_desc_arr[0])) ) return NULL;
-
- const char* str = string_desc_arr[index];
-
- // Cap at max char
- chr_count = (uint8_t) strlen(str);
- if ( chr_count > 31 ) chr_count = 31;
-
- // Convert ASCII string into UTF-16
- for(uint8_t i=0; i<chr_count; i++)
- {
- _desc_str[1+i] = str[i];
- }
- }
-
- // first byte is length (including header), second byte is string type
- _desc_str[0] = (TUSB_DESC_STRING << 8 ) | (2*chr_count + 2);
-
- return _desc_str;
-}
diff --git a/examples/host/hid_to_cdc/CMakeLists.txt b/examples/host/msc_file_explorer/CMakeLists.txt
index abc4d91da..7955b3078 100644
--- a/examples/host/hid_to_cdc/CMakeLists.txt
+++ b/examples/host/msc_file_explorer/CMakeLists.txt
@@ -15,14 +15,24 @@ add_executable(${PROJECT})
# Example source
target_sources(${PROJECT} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/msc_app.c
+ ${TOP}/lib/fatfs/source/ff.c
+ ${TOP}/lib/fatfs/source/ffsystem.c
+ ${TOP}/lib/fatfs/source/ffunicode.c
)
# Example include
target_include_directories(${PROJECT} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src
+ ${TOP}/lib/fatfs/source
+ ${TOP}/lib/embedded-cli
)
# Configure compilation flags and libraries for the example... see the corresponding function
# in hw/bsp/FAMILY/family.cmake for details.
-family_configure_device_example(${PROJECT}) \ No newline at end of file
+family_configure_host_example(${PROJECT})
+
+# Add pico-pio-usb for rp2040 since user can choose to run on bit-banging host
+if(FAMILY STREQUAL "rp2040")
+ family_add_pico_pio_usb(${PROJECT})
+endif()
diff --git a/examples/host/msc_file_explorer/Makefile b/examples/host/msc_file_explorer/Makefile
new file mode 100644
index 000000000..1fda72b18
--- /dev/null
+++ b/examples/host/msc_file_explorer/Makefile
@@ -0,0 +1,37 @@
+include ../../make.mk
+
+FATFS_PATH = lib/fatfs/source
+
+INC += \
+ src \
+ $(TOP)/hw \
+ $(TOP)/$(FATFS_PATH) \
+ $(TOP)/lib/embedded-cli \
+
+# Example source
+EXAMPLE_SOURCE = \
+ src/main.c \
+ src/msc_app.c \
+
+SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
+
+# FatFS source
+SRC_C += \
+ $(FATFS_PATH)/ff.c \
+ $(FATFS_PATH)/ffsystem.c \
+ $(FATFS_PATH)/ffunicode.c \
+
+# suppress warning caused by fatfs
+CFLAGS += -Wno-error=cast-qual
+
+# TinyUSB Host Stack source
+SRC_C += \
+ src/class/cdc/cdc_host.c \
+ src/class/hid/hid_host.c \
+ src/class/msc/msc_host.c \
+ src/host/hub.c \
+ src/host/usbh.c \
+ src/portable/ohci/ohci.c \
+ src/portable/nxp/lpc17_40/hcd_lpc17_40.c
+
+include ../../rules.mk
diff --git a/examples/host/msc_file_explorer/only.txt b/examples/host/msc_file_explorer/only.txt
new file mode 100644
index 000000000..fa9c14857
--- /dev/null
+++ b/examples/host/msc_file_explorer/only.txt
@@ -0,0 +1,11 @@
+mcu:LPC175X_6X
+mcu:LPC177X_8X
+mcu:LPC18XX
+mcu:LPC40XX
+mcu:LPC43XX
+mcu:MIMXRT
+mcu:MIMXRT10XX
+mcu:MIMXRT11XX
+mcu:RP2040
+mcu:MSP432E4
+mcu:RX65X
diff --git a/examples/host/msc_file_explorer/src/main.c b/examples/host/msc_file_explorer/src/main.c
new file mode 100644
index 000000000..7b1c2ef27
--- /dev/null
+++ b/examples/host/msc_file_explorer/src/main.c
@@ -0,0 +1,127 @@
+/*
+ * 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.
+ *
+ */
+
+/* Example to show how to navigate mass storage device with built-in command line.
+ * Type help for list of supported commands and syntax (mostly linux commands)
+
+ > help
+ * help
+ Print list of commands
+ * cat
+ Usage: cat [FILE]...
+ Concatenate FILE(s) to standard output..
+ * cd
+ Usage: cd [DIR]...
+ Change the current directory to DIR.
+ * cp
+ Usage: cp SOURCE DEST
+ Copy SOURCE to DEST.
+ * ls
+ Usage: ls [DIR]...
+ List information about the FILEs (the current directory by default).
+ * pwd
+ Usage: pwd
+ Print the name of the current working directory.
+ * mkdir
+ Usage: mkdir DIR...
+ Create the DIRECTORY(ies), if they do not already exist..
+ * mv
+ Usage: mv SOURCE DEST...
+ Rename SOURCE to DEST.
+ * rm
+ Usage: rm [FILE]...
+ Remove (unlink) the FILE(s).
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "bsp/board.h"
+#include "tusb.h"
+
+//--------------------------------------------------------------------+
+// MACRO CONSTANT TYPEDEF PROTYPES
+//--------------------------------------------------------------------+
+void led_blinking_task(void);
+
+// from msc_app.c
+extern bool msc_app_init(void);
+extern void msc_app_task(void);
+
+/*------------- MAIN -------------*/
+int main(void)
+{
+ board_init();
+
+ printf("TinyUSB Host MassStorage Explorer Example\r\n");
+
+ // init host stack on configured roothub port
+ tuh_init(BOARD_TUH_RHPORT);
+ msc_app_init();
+
+ while (1)
+ {
+ // tinyusb host task
+ tuh_task();
+
+ msc_app_task();
+ led_blinking_task();
+ }
+
+ return 0;
+}
+
+//--------------------------------------------------------------------+
+// TinyUSB Callbacks
+//--------------------------------------------------------------------+
+
+void tuh_mount_cb(uint8_t dev_addr)
+{
+ (void) dev_addr;
+}
+
+void tuh_umount_cb(uint8_t dev_addr)
+{
+ (void) dev_addr;
+}
+
+//--------------------------------------------------------------------+
+// 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
+}
diff --git a/examples/host/msc_file_explorer/src/msc_app.c b/examples/host/msc_file_explorer/src/msc_app.c
new file mode 100644
index 000000000..003e2865b
--- /dev/null
+++ b/examples/host/msc_file_explorer/src/msc_app.c
@@ -0,0 +1,640 @@
+/*
+ * 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 <ctype.h>
+#include "tusb.h"
+#include "bsp/board.h"
+
+#include "ff.h"
+#include "diskio.h"
+
+// lib/embedded-cli
+#define EMBEDDED_CLI_IMPL
+#include "embedded_cli.h"
+
+
+//--------------------------------------------------------------------+
+// MACRO TYPEDEF CONSTANT ENUM DECLARATION
+//--------------------------------------------------------------------+
+
+//------------- embedded-cli -------------//
+#define CLI_BUFFER_SIZE 512
+#define CLI_RX_BUFFER_SIZE 16
+#define CLI_CMD_BUFFER_SIZE 64
+#define CLI_HISTORY_SIZE 32
+#define CLI_BINDING_COUNT 8
+
+static EmbeddedCli *_cli;
+static CLI_UINT cli_buffer[BYTES_TO_CLI_UINTS(CLI_BUFFER_SIZE)];
+
+//------------- Elm Chan FatFS -------------//
+static FATFS fatfs[CFG_TUH_DEVICE_MAX]; // for simplicity only support 1 LUN per device
+static volatile bool _disk_busy[CFG_TUH_DEVICE_MAX];
+
+static scsi_inquiry_resp_t inquiry_resp;
+
+//--------------------------------------------------------------------+
+//
+//--------------------------------------------------------------------+
+
+bool cli_init(void);
+
+bool msc_app_init(void)
+{
+ for(size_t i=0; i<CFG_TUH_DEVICE_MAX; i++) _disk_busy[i] = false;
+
+ // disable stdout buffered for echoing typing command
+ setbuf(stdout, NULL);
+ cli_init();
+
+ return true;
+}
+
+void msc_app_task(void)
+{
+ if (!_cli) return;
+
+ int ch = board_getchar();
+ if ( ch > 0 )
+ {
+ while( ch > 0 )
+ {
+ embeddedCliReceiveChar(_cli, (char) ch);
+ ch = board_getchar();
+ }
+ embeddedCliProcess(_cli);
+ }
+}
+
+//--------------------------------------------------------------------+
+//
+//--------------------------------------------------------------------+
+
+
+bool inquiry_complete_cb(uint8_t dev_addr, tuh_msc_complete_data_t const * cb_data)
+{
+ msc_cbw_t const* cbw = cb_data->cbw;
+ msc_csw_t const* csw = cb_data->csw;
+
+ if (csw->status != 0)
+ {
+ printf("Inquiry failed\r\n");
+ return false;
+ }
+
+ // Print out Vendor ID, Product ID and Rev
+ printf("%.8s %.16s rev %.4s\r\n", inquiry_resp.vendor_id, inquiry_resp.product_id, inquiry_resp.product_rev);
+
+ // Get capacity of device
+ uint32_t const block_count = tuh_msc_get_block_count(dev_addr, cbw->lun);
+ uint32_t const block_size = tuh_msc_get_block_size(dev_addr, cbw->lun);
+
+ printf("Disk Size: %lu MB\r\n", block_count / ((1024*1024)/block_size));
+ // printf("Block Count = %lu, Block Size: %lu\r\n", block_count, block_size);
+
+ // For simplicity: we only mount 1 LUN per device
+ uint8_t const drive_num = dev_addr-1;
+ char drive_path[3] = "0:";
+ drive_path[0] += drive_num;
+
+ if ( f_mount(&fatfs[drive_num], drive_path, 1) != FR_OK )
+ {
+ puts("mount failed");
+ }
+
+ // change to newly mounted drive
+ f_chdir(drive_path);
+
+ // print the drive label
+// char label[34];
+// if ( FR_OK == f_getlabel(drive_path, label, NULL) )
+// {
+// puts(label);
+// }
+
+ return true;
+}
+
+//------------- IMPLEMENTATION -------------//
+void tuh_msc_mount_cb(uint8_t dev_addr)
+{
+ printf("A MassStorage device is mounted\r\n");
+
+ uint8_t const lun = 0;
+ tuh_msc_inquiry(dev_addr, lun, &inquiry_resp, inquiry_complete_cb, 0);
+}
+
+void tuh_msc_umount_cb(uint8_t dev_addr)
+{
+ printf("A MassStorage device is unmounted\r\n");
+
+ uint8_t const drive_num = dev_addr-1;
+ char drive_path[3] = "0:";
+ drive_path[0] += drive_num;
+
+ f_unmount(drive_path);
+
+// if ( phy_disk == f_get_current_drive() )
+// { // active drive is unplugged --> change to other drive
+// for(uint8_t i=0; i<CFG_TUH_DEVICE_MAX; i++)
+// {
+// if ( disk_is_ready(i) )
+// {
+// f_chdrive(i);
+// cli_init(); // refractor, rename
+// }
+// }
+// }
+}
+
+//--------------------------------------------------------------------+
+// DiskIO
+//--------------------------------------------------------------------+
+
+static void wait_for_disk_io(BYTE pdrv)
+{
+ while(_disk_busy[pdrv])
+ {
+ tuh_task();
+ }
+}
+
+static bool disk_io_complete(uint8_t dev_addr, tuh_msc_complete_data_t const * cb_data)
+{
+ (void) dev_addr; (void) cb_data;
+ _disk_busy[dev_addr-1] = false;
+ return true;
+}
+
+DSTATUS disk_status (
+ BYTE pdrv /* Physical drive nmuber to identify the drive */
+)
+{
+ uint8_t dev_addr = pdrv + 1;
+ return tuh_msc_mounted(dev_addr) ? 0 : STA_NODISK;
+}
+
+DSTATUS disk_initialize (
+ BYTE pdrv /* Physical drive nmuber to identify the drive */
+)
+{
+ (void) pdrv;
+ return 0; // nothing to do
+}
+
+DRESULT disk_read (
+ BYTE pdrv, /* Physical drive nmuber to identify the drive */
+ BYTE *buff, /* Data buffer to store read data */
+ LBA_t sector, /* Start sector in LBA */
+ UINT count /* Number of sectors to read */
+)
+{
+ uint8_t const dev_addr = pdrv + 1;
+ uint8_t const lun = 0;
+
+ _disk_busy[pdrv] = true;
+ tuh_msc_read10(dev_addr, lun, buff, sector, (uint16_t) count, disk_io_complete, 0);
+ wait_for_disk_io(pdrv);
+
+ return RES_OK;
+}
+
+#if FF_FS_READONLY == 0
+
+DRESULT disk_write (
+ BYTE pdrv, /* Physical drive nmuber to identify the drive */
+ const BYTE *buff, /* Data to be written */
+ LBA_t sector, /* Start sector in LBA */
+ UINT count /* Number of sectors to write */
+)
+{
+ uint8_t const dev_addr = pdrv + 1;
+ uint8_t const lun = 0;
+
+ _disk_busy[pdrv] = true;
+ tuh_msc_write10(dev_addr, lun, buff, sector, (uint16_t) count, disk_io_complete, 0);
+ wait_for_disk_io(pdrv);
+
+ return RES_OK;
+}
+
+#endif
+
+DRESULT disk_ioctl (
+ BYTE pdrv, /* Physical drive nmuber (0..) */
+ BYTE cmd, /* Control code */
+ void *buff /* Buffer to send/receive control data */
+)
+{
+ uint8_t const dev_addr = pdrv + 1;
+ uint8_t const lun = 0;
+ switch ( cmd )
+ {
+ case CTRL_SYNC:
+ // nothing to do since we do blocking
+ return RES_OK;
+
+ case GET_SECTOR_COUNT:
+ *((DWORD*) buff) = (WORD) tuh_msc_get_block_count(dev_addr, lun);
+ return RES_OK;
+
+ case GET_SECTOR_SIZE:
+ *((WORD*) buff) = (WORD) tuh_msc_get_block_size(dev_addr, lun);
+ return RES_OK;
+
+ case GET_BLOCK_SIZE:
+ *((DWORD*) buff) = 1; // erase block size in units of sector size
+ return RES_OK;
+
+ default:
+ return RES_PARERR;
+ }
+
+ return RES_OK;
+}
+
+//--------------------------------------------------------------------+
+// CLI Commands
+//--------------------------------------------------------------------+
+
+void cli_cmd_cat(EmbeddedCli *cli, char *args, void *context);
+void cli_cmd_cd(EmbeddedCli *cli, char *args, void *context);
+void cli_cmd_cp(EmbeddedCli *cli, char *args, void *context);
+void cli_cmd_ls(EmbeddedCli *cli, char *args, void *context);
+void cli_cmd_pwd(EmbeddedCli *cli, char *args, void *context);
+void cli_cmd_mkdir(EmbeddedCli *cli, char *args, void *context);
+void cli_cmd_mv(EmbeddedCli *cli, char *args, void *context);
+void cli_cmd_rm(EmbeddedCli *cli, char *args, void *context);
+
+void cli_write_char(EmbeddedCli *cli, char c)
+{
+ (void) cli;
+ putchar((int) c);
+}
+
+void cli_cmd_unknown(EmbeddedCli *cli, CliCommand *command)
+{
+ (void) cli;
+ printf("%s: command not found\r\n", command->name);
+}
+
+bool cli_init(void)
+{
+ EmbeddedCliConfig *config = embeddedCliDefaultConfig();
+ config->cliBuffer = cli_buffer;
+ config->cliBufferSize = CLI_BUFFER_SIZE;
+ config->rxBufferSize = CLI_RX_BUFFER_SIZE;
+ config->cmdBufferSize = CLI_CMD_BUFFER_SIZE;
+ config->historyBufferSize = CLI_HISTORY_SIZE;
+ config->maxBindingCount = CLI_BINDING_COUNT;
+
+ TU_ASSERT(embeddedCliRequiredSize(config) <= CLI_BUFFER_SIZE);
+
+ _cli = embeddedCliNew(config);
+ TU_ASSERT(_cli != NULL);
+
+ _cli->writeChar = cli_write_char;
+
+ embeddedCliAddBinding(_cli, (CliCommandBinding) {
+ "cat",
+ "Usage: cat [FILE]...\r\n\tConcatenate FILE(s) to standard output..",
+ true,
+ NULL,
+ cli_cmd_cat
+ });
+
+ embeddedCliAddBinding(_cli, (CliCommandBinding) {
+ "cd",
+ "Usage: cd [DIR]...\r\n\tChange the current directory to DIR.",
+ true,
+ NULL,
+ cli_cmd_cd
+ });
+
+ embeddedCliAddBinding(_cli, (CliCommandBinding) {
+ "cp",
+ "Usage: cp SOURCE DEST\r\n\tCopy SOURCE to DEST.",
+ true,
+ NULL,
+ cli_cmd_cp
+ });
+
+ embeddedCliAddBinding(_cli, (CliCommandBinding) {
+ "ls",
+ "Usage: ls [DIR]...\r\n\tList information about the FILEs (the current directory by default).",
+ true,
+ NULL,
+ cli_cmd_ls
+ });
+
+ embeddedCliAddBinding(_cli, (CliCommandBinding) {
+ "pwd",
+ "Usage: pwd\r\n\tPrint the name of the current working directory.",
+ true,
+ NULL,
+ cli_cmd_pwd
+ });
+
+ embeddedCliAddBinding(_cli, (CliCommandBinding) {
+ "mkdir",
+ "Usage: mkdir DIR...\r\n\tCreate the DIRECTORY(ies), if they do not already exist..",
+ true,
+ NULL,
+ cli_cmd_mkdir
+ });
+
+ embeddedCliAddBinding(_cli, (CliCommandBinding) {
+ "mv",
+ "Usage: mv SOURCE DEST...\r\n\tRename SOURCE to DEST.",
+ true,
+ NULL,
+ cli_cmd_mv
+ });
+
+ embeddedCliAddBinding(_cli, (CliCommandBinding) {
+ "rm",
+ "Usage: rm [FILE]...\r\n\tRemove (unlink) the FILE(s).",
+ true,
+ NULL,
+ cli_cmd_rm
+ });
+
+ return true;
+}
+
+void cli_cmd_cat(EmbeddedCli *cli, char *args, void *context)
+{
+ (void) cli; (void) context;
+
+ uint16_t argc = embeddedCliGetTokenCount(args);
+
+ // need at least 1 argument
+ if ( argc == 0 )
+ {
+ printf("invalid arguments\r\n");
+ return;
+ }
+
+ for(uint16_t i=0; i<argc; i++)
+ {
+ FIL fi;
+ const char* fpath = embeddedCliGetToken(args, i+1); // token count from 1
+
+ if ( FR_OK != f_open(&fi, fpath, FA_READ) )
+ {
+ printf("%s: No such file or directory\r\n", fpath);
+ }else
+ {
+ uint8_t buf[512];
+ UINT count = 0;
+ while ( (FR_OK == f_read(&fi, buf, sizeof(buf), &count)) && (count > 0) )
+ {
+ for(UINT c = 0; c < count; c++)
+ {
+ const uint8_t ch = buf[c];
+ if (isprint(ch) || iscntrl(ch))
+ {
+ putchar(ch);
+ }else
+ {
+ putchar('.');
+ }
+ }
+ }
+ }
+
+ f_close(&fi);
+ }
+}
+
+void cli_cmd_cd(EmbeddedCli *cli, char *args, void *context)
+{
+ (void) cli; (void) context;
+
+ uint16_t argc = embeddedCliGetTokenCount(args);
+
+ // only support 1 argument
+ if ( argc != 1 )
+ {
+ printf("invalid arguments\r\n");
+ return;
+ }
+
+ // default is current directory
+ const char* dpath = args;
+
+ if ( FR_OK != f_chdir(dpath) )
+ {
+ printf("%s: No such file or directory\r\n", dpath);
+ return;
+ }
+}
+
+void cli_cmd_cp(EmbeddedCli *cli, char *args, void *context)
+{
+ (void) cli; (void) context;
+
+ uint16_t argc = embeddedCliGetTokenCount(args);
+ if ( argc != 2 )
+ {
+ printf("invalid arguments\r\n");
+ return;
+ }
+
+ // default is current directory
+ const char* src = embeddedCliGetToken(args, 1);
+ const char* dst = embeddedCliGetToken(args, 2);
+
+ FIL f_src;
+ FIL f_dst;
+
+ if ( FR_OK != f_open(&f_src, src, FA_READ) )
+ {
+ printf("cannot stat '%s': No such file or directory\r\n", src);
+ return;
+ }
+
+ if ( FR_OK != f_open(&f_dst, dst, FA_WRITE | FA_CREATE_ALWAYS) )
+ {
+ printf("cannot create '%s'\r\n", dst);
+ return;
+ }else
+ {
+ uint8_t buf[512];
+ UINT rd_count = 0;
+ while ( (FR_OK == f_read(&f_src, buf, sizeof(buf), &rd_count)) && (rd_count > 0) )
+ {
+ UINT wr_count = 0;
+
+ if ( FR_OK != f_write(&f_dst, buf, rd_count, &wr_count) )
+ {
+ printf("cannot write to '%s'\r\n", dst);
+ break;
+ }
+ }
+ }
+
+ f_close(&f_src);
+ f_close(&f_dst);
+}
+
+void cli_cmd_ls(EmbeddedCli *cli, char *args, void *context)
+{
+ (void) cli; (void) context;
+
+ uint16_t argc = embeddedCliGetTokenCount(args);
+
+ // only support 1 argument
+ if ( argc > 1 )
+ {
+ printf("invalid arguments\r\n");
+ return;
+ }
+
+ // default is current directory
+ const char* dpath = ".";
+ if (argc) dpath = args;
+
+ DIR dir;
+ if ( FR_OK != f_opendir(&dir, dpath) )
+ {
+ printf("cannot access '%s': No such file or directory\r\n", dpath);
+ return;
+ }
+
+ FILINFO fno;
+ while( (f_readdir(&dir, &fno) == FR_OK) && (fno.fname[0] != 0) )
+ {
+ if ( fno.fname[0] != '.' ) // ignore . and .. entry
+ {
+ if ( fno.fattrib & AM_DIR )
+ {
+ // directory
+ printf("/%s\r\n", fno.fname);
+ }else
+ {
+ printf("%-40s", fno.fname);
+ if (fno.fsize < 1024)
+ {
+ printf("%lu B\r\n", fno.fsize);
+ }else
+ {
+ printf("%lu KB\r\n", fno.fsize / 1024);
+ }
+ }
+ }
+ }
+
+ f_closedir(&dir);
+}
+
+void cli_cmd_pwd(EmbeddedCli *cli, char *args, void *context)
+{
+ (void) cli; (void) context;
+ uint16_t argc = embeddedCliGetTokenCount(args);
+
+ if (argc != 0)
+ {
+ printf("invalid arguments\r\n");
+ return;
+ }
+
+ char path[256];
+ if (FR_OK != f_getcwd(path, sizeof(path)))
+ {
+ printf("cannot get current working directory\r\n");
+ }
+
+ puts(path);
+}
+
+void cli_cmd_mkdir(EmbeddedCli *cli, char *args, void *context)
+{
+ (void) cli; (void) context;
+
+ uint16_t argc = embeddedCliGetTokenCount(args);
+
+ // only support 1 argument
+ if ( argc != 1 )
+ {
+ printf("invalid arguments\r\n");
+ return;
+ }
+
+ // default is current directory
+ const char* dpath = args;
+
+ if ( FR_OK != f_mkdir(dpath) )
+ {
+ printf("%s: cannot create this directory\r\n", dpath);
+ return;
+ }
+}
+
+void cli_cmd_mv(EmbeddedCli *cli, char *args, void *context)
+{
+ (void) cli; (void) context;
+
+ uint16_t argc = embeddedCliGetTokenCount(args);
+ if ( argc != 2 )
+ {
+ printf("invalid arguments\r\n");
+ return;
+ }
+
+ // default is current directory
+ const char* src = embeddedCliGetToken(args, 1);
+ const char* dst = embeddedCliGetToken(args, 2);
+
+ if ( FR_OK != f_rename(src, dst) )
+ {
+ printf("cannot mv %s to %s\r\n", src, dst);
+ return;
+ }
+}
+
+void cli_cmd_rm(EmbeddedCli *cli, char *args, void *context)
+{
+ (void) cli; (void) context;
+
+ uint16_t argc = embeddedCliGetTokenCount(args);
+
+ // need at least 1 argument
+ if ( argc == 0 )
+ {
+ printf("invalid arguments\r\n");
+ return;
+ }
+
+ for(uint16_t i=0; i<argc; i++)
+ {
+ const char* fpath = embeddedCliGetToken(args, i+1); // token count from 1
+
+ if ( FR_OK != f_unlink(fpath) )
+ {
+ printf("cannot remove '%s': No such file or directory\r\n", fpath);
+ }
+ }
+}
diff --git a/examples/host/msc_file_explorer/src/tusb_config.h b/examples/host/msc_file_explorer/src/tusb_config.h
new file mode 100644
index 000000000..1e0d067bf
--- /dev/null
+++ b/examples/host/msc_file_explorer/src/tusb_config.h
@@ -0,0 +1,114 @@
+/*
+ * 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
+
+//--------------------------------------------------------------------+
+// Board Specific Configuration
+//--------------------------------------------------------------------+
+
+#if CFG_TUSB_MCU == OPT_MCU_RP2040
+// change to 1 if using pico-pio-usb as host controller for raspberry rp2040
+#define CFG_TUH_RPI_PIO_USB 0
+#define BOARD_TUH_RHPORT CFG_TUH_RPI_PIO_USB
+#endif
+
+// 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
+
+//--------------------------------------------------------------------
+// COMMON CONFIGURATION
+//--------------------------------------------------------------------
+
+// defined by compiler flags for flexibility
+#ifndef CFG_TUSB_MCU
+#error CFG_TUSB_MCU must be defined
+#endif
+
+#ifndef CFG_TUSB_OS
+#define CFG_TUSB_OS OPT_OS_NONE
+#endif
+
+#ifndef CFG_TUSB_DEBUG
+#define CFG_TUSB_DEBUG 0
+#endif
+
+// Enable Host stack
+#define CFG_TUH_ENABLED 1
+
+// Default is max speed that hardware controller could support with on-chip PHY
+#define CFG_TUH_MAX_SPEED BOARD_TUH_MAX_SPEED
+
+/* 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
+
+//--------------------------------------------------------------------
+// CONFIGURATION
+//--------------------------------------------------------------------
+
+// Size of buffer to hold descriptors and other data used for enumeration
+#define CFG_TUH_ENUMERATION_BUFSIZE 256
+
+#define CFG_TUH_HUB 1 // number of supported hubs
+#define CFG_TUH_MSC 1
+#define CFG_TUH_CDC 0
+#define CFG_TUH_HID 0 // typical keyboard + mouse device can have 3-4 HID interfaces
+#define CFG_TUH_VENDOR 0
+
+// max device support (excluding hub device): 1 hub typically has 4 ports
+#define CFG_TUH_DEVICE_MAX (3*CFG_TUH_HUB + 1)
+
+//------------- MSC -------------//
+#define CFG_TUH_MSC_MAXLUN 4 // typical for most card reader
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _TUSB_CONFIG_H_ */