summaryrefslogtreecommitdiff
path: root/examples/device
diff options
context:
space:
mode:
Diffstat (limited to 'examples/device')
-rw-r--r--examples/device/CMakeLists.txt1
-rw-r--r--examples/device/audio_4_channel_mic/src/main.c4
-rw-r--r--examples/device/audio_4_channel_mic/src/tusb_config.h1
-rw-r--r--examples/device/audio_4_channel_mic_freertos/src/main.c6
-rw-r--r--examples/device/audio_4_channel_mic_freertos/src/tusb_config.h1
-rw-r--r--examples/device/audio_test/src/main.c4
-rw-r--r--examples/device/audio_test/src/tusb_config.h1
-rw-r--r--examples/device/audio_test_freertos/skip.txt1
-rw-r--r--examples/device/audio_test_freertos/src/main.c6
-rw-r--r--examples/device/audio_test_freertos/src/tusb_config.h1
-rw-r--r--examples/device/audio_test_multi_rate/src/main.c4
-rw-r--r--examples/device/audio_test_multi_rate/src/tusb_config.h1
-rw-r--r--examples/device/cdc_dual_ports/src/main.c8
-rw-r--r--examples/device/cdc_msc/src/main.c4
-rw-r--r--examples/device/cdc_msc/src/usb_descriptors.c2
-rw-r--r--examples/device/cdc_msc_freertos/src/main.c8
-rw-r--r--examples/device/cdc_msc_freertos/src/msc_disk.c2
-rw-r--r--examples/device/cdc_msc_freertos/src/usb_descriptors.c2
-rw-r--r--examples/device/cdc_uac2/src/tusb_config.h3
-rw-r--r--examples/device/cdc_uac2/src/usb_descriptors.c2
-rw-r--r--examples/device/dfu/src/main.c4
-rw-r--r--examples/device/dfu_runtime/src/main.c4
-rw-r--r--examples/device/dynamic_configuration/src/main.c4
-rw-r--r--examples/device/hid_boot_interface/src/main.c4
-rw-r--r--examples/device/hid_composite/src/main.c65
-rw-r--r--examples/device/hid_composite/src/usb_descriptors.c2
-rw-r--r--examples/device/hid_composite_freertos/src/main.c4
-rw-r--r--examples/device/hid_composite_freertos/src/usb_descriptors.c2
-rw-r--r--examples/device/hid_generic_inout/src/main.c4
-rw-r--r--examples/device/hid_multiple_interface/src/main.c4
-rw-r--r--examples/device/midi_test/src/main.c4
-rw-r--r--examples/device/midi_test_freertos/src/main.c6
-rw-r--r--examples/device/msc_dual_lun/src/main.c4
-rw-r--r--examples/device/mtp/CMakeLists.txt39
-rw-r--r--examples/device/mtp/CMakePresets.json6
-rw-r--r--examples/device/mtp/Makefile11
-rw-r--r--examples/device/mtp/prj.conf6
-rw-r--r--examples/device/mtp/skip.txt1
-rw-r--r--examples/device/mtp/src/main.c110
-rw-r--r--examples/device/mtp/src/mtp_fs_example.c624
-rw-r--r--examples/device/mtp/src/tinyusb_logo_png.h175
-rw-r--r--examples/device/mtp/src/tusb_config.h139
-rw-r--r--examples/device/mtp/src/usb_descriptors.c255
-rw-r--r--examples/device/net_lwip_webserver/src/main.c4
-rw-r--r--examples/device/uac2_headset/src/main.c4
-rw-r--r--examples/device/uac2_headset/src/tusb_config.h3
-rw-r--r--examples/device/uac2_speaker_fb/src/main.c4
-rw-r--r--examples/device/uac2_speaker_fb/src/quirk_os_guessing.c8
-rw-r--r--examples/device/uac2_speaker_fb/src/tusb_config.h5
-rw-r--r--examples/device/usbtmc/src/main.c4
-rw-r--r--examples/device/usbtmc/src/usbtmc_app.c4
-rw-r--r--examples/device/video_capture/src/main.c8
-rw-r--r--examples/device/video_capture_2ch/src/main.c8
-rw-r--r--examples/device/webusb_serial/src/main.c4
54 files changed, 1432 insertions, 163 deletions
diff --git a/examples/device/CMakeLists.txt b/examples/device/CMakeLists.txt
index bb7dd0a0f..eb625ea51 100644
--- a/examples/device/CMakeLists.txt
+++ b/examples/device/CMakeLists.txt
@@ -26,6 +26,7 @@ family_add_subdirectory(hid_generic_inout)
family_add_subdirectory(hid_multiple_interface)
family_add_subdirectory(midi_test)
family_add_subdirectory(msc_dual_lun)
+family_add_subdirectory(mtp)
family_add_subdirectory(net_lwip_webserver)
family_add_subdirectory(uac2_headset)
family_add_subdirectory(uac2_speaker_fb)
diff --git a/examples/device/audio_4_channel_mic/src/main.c b/examples/device/audio_4_channel_mic/src/main.c
index 9b169e77e..3e0f03a20 100644
--- a/examples/device/audio_4_channel_mic/src/main.c
+++ b/examples/device/audio_4_channel_mic/src/main.c
@@ -85,9 +85,7 @@ int main(void) {
.speed = TUSB_SPEED_AUTO};
tusb_init(BOARD_TUD_RHPORT, &dev_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
// Init values
sampFreq = AUDIO_SAMPLE_RATE;
diff --git a/examples/device/audio_4_channel_mic/src/tusb_config.h b/examples/device/audio_4_channel_mic/src/tusb_config.h
index 446a7a32a..0ee3ba2d0 100644
--- a/examples/device/audio_4_channel_mic/src/tusb_config.h
+++ b/examples/device/audio_4_channel_mic/src/tusb_config.h
@@ -107,7 +107,6 @@ extern "C" {
#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN TUD_AUDIO_MIC_FOUR_CH_DESC_LEN
-#define CFG_TUD_AUDIO_FUNC_1_N_AS_INT 1
#define CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ 64
#define CFG_TUD_AUDIO_ENABLE_EP_IN 1
diff --git a/examples/device/audio_4_channel_mic_freertos/src/main.c b/examples/device/audio_4_channel_mic_freertos/src/main.c
index 9c76380a2..96eca0be9 100644
--- a/examples/device/audio_4_channel_mic_freertos/src/main.c
+++ b/examples/device/audio_4_channel_mic_freertos/src/main.c
@@ -184,9 +184,7 @@ void usb_device_task(void *param) {
.speed = TUSB_SPEED_AUTO};
tusb_init(BOARD_TUD_RHPORT, &dev_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
// RTOS forever loop
while (1) {
@@ -476,13 +474,11 @@ bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p
//--------------------------------------------------------------------+
void led_blinking_task(void *param) {
(void) param;
- static uint32_t start_ms = 0;
static bool led_state = false;
while (1) {
// Blink every interval ms
vTaskDelay(blink_interval_ms / portTICK_PERIOD_MS);
- start_ms += blink_interval_ms;
board_led_write(led_state);
led_state = 1 - led_state;// toggle
diff --git a/examples/device/audio_4_channel_mic_freertos/src/tusb_config.h b/examples/device/audio_4_channel_mic_freertos/src/tusb_config.h
index f7c0efe08..d973be2af 100644
--- a/examples/device/audio_4_channel_mic_freertos/src/tusb_config.h
+++ b/examples/device/audio_4_channel_mic_freertos/src/tusb_config.h
@@ -113,7 +113,6 @@ extern "C" {
#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN TUD_AUDIO_MIC_FOUR_CH_DESC_LEN
-#define CFG_TUD_AUDIO_FUNC_1_N_AS_INT 1
#define CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ 64
#define CFG_TUD_AUDIO_ENABLE_EP_IN 1
diff --git a/examples/device/audio_test/src/main.c b/examples/device/audio_test/src/main.c
index ec47de7b8..5b3beec24 100644
--- a/examples/device/audio_test/src/main.c
+++ b/examples/device/audio_test/src/main.c
@@ -83,9 +83,7 @@ int main(void) {
.speed = TUSB_SPEED_AUTO};
tusb_init(BOARD_TUD_RHPORT, &dev_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
// Init values
sampFreq = CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE;
diff --git a/examples/device/audio_test/src/tusb_config.h b/examples/device/audio_test/src/tusb_config.h
index b38958d7c..10bf53809 100644
--- a/examples/device/audio_test/src/tusb_config.h
+++ b/examples/device/audio_test/src/tusb_config.h
@@ -109,7 +109,6 @@ extern "C" {
#define CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE 48000
#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN TUD_AUDIO_MIC_ONE_CH_DESC_LEN
-#define CFG_TUD_AUDIO_FUNC_1_N_AS_INT 1 // Number of Standard AS Interface Descriptors (4.9.1) defined per audio function - this is required to be able to remember the current alternate settings of these interfaces - We restrict us here to have a constant number for all audio functions (which means this has to be the maximum number of AS interfaces an audio function has and a second audio function with less AS interfaces just wastes a few bytes)
#define CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ 64 // Size of control request buffer
#define CFG_TUD_AUDIO_ENABLE_EP_IN 1
diff --git a/examples/device/audio_test_freertos/skip.txt b/examples/device/audio_test_freertos/skip.txt
index 650bf355b..1f3d4281a 100644
--- a/examples/device/audio_test_freertos/skip.txt
+++ b/examples/device/audio_test_freertos/skip.txt
@@ -14,3 +14,4 @@ mcu:VALENTYUSB_EPTRI
mcu:RAXXX
family:broadcom_32bit
family:broadcom_64bit
+board:stm32l0538disco
diff --git a/examples/device/audio_test_freertos/src/main.c b/examples/device/audio_test_freertos/src/main.c
index b2bed295f..1eab5dab8 100644
--- a/examples/device/audio_test_freertos/src/main.c
+++ b/examples/device/audio_test_freertos/src/main.c
@@ -167,9 +167,7 @@ void usb_device_task(void *param) {
.speed = TUSB_SPEED_AUTO};
tusb_init(BOARD_TUD_RHPORT, &dev_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
// RTOS forever loop
while (1) {
@@ -470,13 +468,11 @@ bool tud_audio_set_itf_close_ep_cb(uint8_t rhport, tusb_control_request_t const
//--------------------------------------------------------------------+
void led_blinking_task(void *param) {
(void) param;
- static uint32_t start_ms = 0;
static bool led_state = false;
while (1) {
// Blink every interval ms
vTaskDelay(blink_interval_ms / portTICK_PERIOD_MS);
- start_ms += blink_interval_ms;
board_led_write(led_state);
led_state = 1 - led_state;// toggle
diff --git a/examples/device/audio_test_freertos/src/tusb_config.h b/examples/device/audio_test_freertos/src/tusb_config.h
index b708e2541..c9dc50082 100644
--- a/examples/device/audio_test_freertos/src/tusb_config.h
+++ b/examples/device/audio_test_freertos/src/tusb_config.h
@@ -115,7 +115,6 @@ extern "C" {
#define CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE 48000
#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN TUD_AUDIO_MIC_ONE_CH_DESC_LEN
-#define CFG_TUD_AUDIO_FUNC_1_N_AS_INT 1 // Number of Standard AS Interface Descriptors (4.9.1) defined per audio function - this is required to be able to remember the current alternate settings of these interfaces - We restrict us here to have a constant number for all audio functions (which means this has to be the maximum number of AS interfaces an audio function has and a second audio function with less AS interfaces just wastes a few bytes)
#define CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ 64 // Size of control request buffer
#define CFG_TUD_AUDIO_ENABLE_EP_IN 1
diff --git a/examples/device/audio_test_multi_rate/src/main.c b/examples/device/audio_test_multi_rate/src/main.c
index 87f56f4b5..9d467991e 100644
--- a/examples/device/audio_test_multi_rate/src/main.c
+++ b/examples/device/audio_test_multi_rate/src/main.c
@@ -100,9 +100,7 @@ int main(void) {
.speed = TUSB_SPEED_AUTO};
tusb_init(BOARD_TUD_RHPORT, &dev_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
// Init values
sampFreq = sampleRatesList[0];
diff --git a/examples/device/audio_test_multi_rate/src/tusb_config.h b/examples/device/audio_test_multi_rate/src/tusb_config.h
index d9b925dcf..b48c0a0be 100644
--- a/examples/device/audio_test_multi_rate/src/tusb_config.h
+++ b/examples/device/audio_test_multi_rate/src/tusb_config.h
@@ -123,7 +123,6 @@ extern "C" {
// Have a look into audio_device.h for all configurations
#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN TUD_AUDIO_MIC_ONE_CH_2_FORMAT_DESC_LEN
-#define CFG_TUD_AUDIO_FUNC_1_N_AS_INT 1 // Number of Standard AS Interface Descriptors (4.9.1) defined per audio function - this is required to be able to remember the current alternate settings of these interfaces - We restrict us here to have a constant number for all audio functions (which means this has to be the maximum number of AS interfaces an audio function has and a second audio function with less AS interfaces just wastes a few bytes)
#define CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ 64 // Size of control request buffer
#define CFG_TUD_AUDIO_ENABLE_EP_IN 1
diff --git a/examples/device/cdc_dual_ports/src/main.c b/examples/device/cdc_dual_ports/src/main.c
index 5a3e18358..8fe003f21 100644
--- a/examples/device/cdc_dual_ports/src/main.c
+++ b/examples/device/cdc_dual_ports/src/main.c
@@ -58,9 +58,7 @@ int main(void) {
};
tusb_init(BOARD_TUD_RHPORT, &dev_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
while (1) {
tud_task(); // tinyusb device task
@@ -141,9 +139,7 @@ void tud_cdc_line_state_cb(uint8_t instance, bool dtr, bool rts) {
cdc_line_coding_t coding;
tud_cdc_get_line_coding(&coding);
if (coding.bit_rate == 1200) {
- if (board_reset_to_bootloader) {
- board_reset_to_bootloader();
- }
+ board_reset_to_bootloader();
}
}
}
diff --git a/examples/device/cdc_msc/src/main.c b/examples/device/cdc_msc/src/main.c
index 5cd93e7dd..4e7aa989e 100644
--- a/examples/device/cdc_msc/src/main.c
+++ b/examples/device/cdc_msc/src/main.c
@@ -57,9 +57,7 @@ int main(void) {
};
tusb_init(BOARD_TUD_RHPORT, &dev_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
while (1) {
tud_task(); // tinyusb device task
diff --git a/examples/device/cdc_msc/src/usb_descriptors.c b/examples/device/cdc_msc/src/usb_descriptors.c
index edcee0462..597a6b1e6 100644
--- a/examples/device/cdc_msc/src/usb_descriptors.c
+++ b/examples/device/cdc_msc/src/usb_descriptors.c
@@ -184,7 +184,7 @@ 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
+ // Note: the descriptor type is OTHER_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);
diff --git a/examples/device/cdc_msc_freertos/src/main.c b/examples/device/cdc_msc_freertos/src/main.c
index 09ccc9bf3..69f2435ba 100644
--- a/examples/device/cdc_msc_freertos/src/main.c
+++ b/examples/device/cdc_msc_freertos/src/main.c
@@ -119,9 +119,7 @@ static void usb_device_task(void *param) {
};
tusb_init(BOARD_TUD_RHPORT, &dev_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
msc_disk_init();
// RTOS forever loop
@@ -229,13 +227,11 @@ void tud_cdc_rx_cb(uint8_t itf) {
//--------------------------------------------------------------------+
void led_blinking_task(void* param) {
(void) param;
- static uint32_t start_ms = 0;
- static bool led_state = false;
+ static bool led_state = false;
while (1) {
// Blink every interval ms
vTaskDelay(blink_interval_ms / portTICK_PERIOD_MS);
- start_ms += blink_interval_ms;
board_led_write(led_state);
led_state = 1 - led_state; // toggle
diff --git a/examples/device/cdc_msc_freertos/src/msc_disk.c b/examples/device/cdc_msc_freertos/src/msc_disk.c
index 3602c991d..849712e6a 100644
--- a/examples/device/cdc_msc_freertos/src/msc_disk.c
+++ b/examples/device/cdc_msc_freertos/src/msc_disk.c
@@ -150,7 +150,7 @@ uint8_t msc_disk[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] =
};
#if CFG_EXAMPLE_MSC_ASYNC_IO
-void msc_disk_init() {
+void msc_disk_init(void) {
#if configSUPPORT_STATIC_ALLOCATION
io_queue = xQueueCreateStatic(1, sizeof(io_ops_t), io_queue_buf, &io_queue_static);
diff --git a/examples/device/cdc_msc_freertos/src/usb_descriptors.c b/examples/device/cdc_msc_freertos/src/usb_descriptors.c
index a55fa3675..cb440c209 100644
--- a/examples/device/cdc_msc_freertos/src/usb_descriptors.c
+++ b/examples/device/cdc_msc_freertos/src/usb_descriptors.c
@@ -186,7 +186,7 @@ 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
+ // Note: the descriptor type is OTHER_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);
diff --git a/examples/device/cdc_uac2/src/tusb_config.h b/examples/device/cdc_uac2/src/tusb_config.h
index 2318ccf73..2e744f8d2 100644
--- a/examples/device/cdc_uac2/src/tusb_config.h
+++ b/examples/device/cdc_uac2/src/tusb_config.h
@@ -157,9 +157,6 @@ extern "C" {
#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX TU_MAX(CFG_TUD_AUDIO_FUNC_1_FORMAT_1_EP_SZ_OUT, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_EP_SZ_OUT) // Maximum EP IN size for all AS alternate settings used
#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ (TUD_OPT_HIGH_SPEED ? 32 : 4) * CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX // Example read FIFO every 1ms, so it should be 8 times larger for HS device
-// Number of Standard AS Interface Descriptors (4.9.1) defined per audio function - this is required to be able to remember the current alternate settings of these interfaces - We restrict us here to have a constant number for all audio functions (which means this has to be the maximum number of AS interfaces an audio function has and a second audio function with less AS interfaces just wastes a few bytes)
-#define CFG_TUD_AUDIO_FUNC_1_N_AS_INT 2
-
// Size of control request buffer
#define CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ 64
diff --git a/examples/device/cdc_uac2/src/usb_descriptors.c b/examples/device/cdc_uac2/src/usb_descriptors.c
index 22d3cf05a..da55bdb5a 100644
--- a/examples/device/cdc_uac2/src/usb_descriptors.c
+++ b/examples/device/cdc_uac2/src/usb_descriptors.c
@@ -176,7 +176,7 @@ 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
+ // Note: the descriptor type is OTHER_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);
diff --git a/examples/device/dfu/src/main.c b/examples/device/dfu/src/main.c
index af9e99857..c0c848837 100644
--- a/examples/device/dfu/src/main.c
+++ b/examples/device/dfu/src/main.c
@@ -81,9 +81,7 @@ int main(void)
};
tusb_init(BOARD_TUD_RHPORT, &dev_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
while (1)
{
diff --git a/examples/device/dfu_runtime/src/main.c b/examples/device/dfu_runtime/src/main.c
index 4740c18c4..37cb80093 100644
--- a/examples/device/dfu_runtime/src/main.c
+++ b/examples/device/dfu_runtime/src/main.c
@@ -76,9 +76,7 @@ int main(void)
};
tusb_init(BOARD_TUD_RHPORT, &dev_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
while (1)
{
diff --git a/examples/device/dynamic_configuration/src/main.c b/examples/device/dynamic_configuration/src/main.c
index 32ff58232..258cfcd02 100644
--- a/examples/device/dynamic_configuration/src/main.c
+++ b/examples/device/dynamic_configuration/src/main.c
@@ -63,9 +63,7 @@ int main(void)
};
tusb_init(BOARD_TUD_RHPORT, &dev_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
while (1)
{
diff --git a/examples/device/hid_boot_interface/src/main.c b/examples/device/hid_boot_interface/src/main.c
index 570e4e801..45712cede 100644
--- a/examples/device/hid_boot_interface/src/main.c
+++ b/examples/device/hid_boot_interface/src/main.c
@@ -63,9 +63,7 @@ int main(void)
};
tusb_init(BOARD_TUD_RHPORT, &dev_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
while (1)
{
diff --git a/examples/device/hid_composite/src/main.c b/examples/device/hid_composite/src/main.c
index a58107b6f..89dab0bdc 100644
--- a/examples/device/hid_composite/src/main.c
+++ b/examples/device/hid_composite/src/main.c
@@ -64,9 +64,7 @@ int main(void)
};
tusb_init(BOARD_TUD_RHPORT, &dev_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
while (1)
{
@@ -197,41 +195,30 @@ static void send_hid_report(uint8_t report_id, uint32_t btn)
}
}
break;
- default: break;
- }
-}
-
-/* use this to send stylus touch signal through USB. */
-static void send_stylus_touch(uint16_t x, uint16_t y, bool state)
-{
- // skip if hid is not ready yet
- if ( !tud_hid_ready() ) return;
-
- static bool has_stylus_pen = false;
-
- hid_stylus_report_t report =
- {
- .attr = 0,
- .x = 0,
- .y = 0
- };
- report.x = x;
- report.y = y;
-
- if (state)
- {
- report.attr = STYLUS_ATTR_TIP_SWITCH | STYLUS_ATTR_IN_RANGE;
- tud_hid_report(REPORT_ID_STYLUS_PEN, &report, sizeof(report));
+ case REPORT_ID_STYLUS_PEN: {
+ static bool touch_state = false;
+ hid_stylus_report_t report = {
+ .attr = 0,
+ .x = 0,
+ .y = 0
+ };
- has_stylus_pen = true;
- }else
- {
- report.attr = 0;
- if (has_stylus_pen) tud_hid_report(REPORT_ID_STYLUS_PEN, &report, sizeof(report));
- has_stylus_pen = false;
+ if (btn) {
+ report.attr = STYLUS_ATTR_TIP_SWITCH | STYLUS_ATTR_IN_RANGE;
+ report.x = 100;
+ report.y = 100;
+ tud_hid_report(REPORT_ID_STYLUS_PEN, &report, sizeof(report));
+ touch_state = true;
+ } else {
+ report.attr = 0;
+ if (touch_state) tud_hid_report(REPORT_ID_STYLUS_PEN, &report, sizeof(report));
+ touch_state = false;
+ }
+ }
+ break;
+ default: break;
}
-
}
// Every 10ms, we will sent 1 report for each HID profile (keyboard, mouse etc ..)
@@ -241,14 +228,6 @@ void hid_task(void)
// Poll every 10ms
const uint32_t interval_ms = 10;
static uint32_t start_ms = 0;
- static uint32_t touch_ms = 0;
- static bool touch_state = false;
-
- if (board_millis() - touch_ms < 100) {
- touch_ms = board_millis();
- send_stylus_touch(0, 0, touch_state = !touch_state);
- return;
- }
if ( board_millis() - start_ms < interval_ms) return; // not enough time
start_ms += interval_ms;
diff --git a/examples/device/hid_composite/src/usb_descriptors.c b/examples/device/hid_composite/src/usb_descriptors.c
index 15c6e1f73..ce7fbd13f 100644
--- a/examples/device/hid_composite/src/usb_descriptors.c
+++ b/examples/device/hid_composite/src/usb_descriptors.c
@@ -154,7 +154,7 @@ uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index)
{
(void) index; // for multiple configurations
- // other speed config is basically configuration with type = OHER_SPEED_CONFIG
+ // other speed config is basically configuration with type = OTHER_SPEED_CONFIG
memcpy(desc_other_speed_config, desc_configuration, CONFIG_TOTAL_LEN);
desc_other_speed_config[1] = TUSB_DESC_OTHER_SPEED_CONFIG;
diff --git a/examples/device/hid_composite_freertos/src/main.c b/examples/device/hid_composite_freertos/src/main.c
index 3f5e8a91c..0eb13add3 100644
--- a/examples/device/hid_composite_freertos/src/main.c
+++ b/examples/device/hid_composite_freertos/src/main.c
@@ -141,9 +141,7 @@ void usb_device_task(void* param)
};
tusb_init(BOARD_TUD_RHPORT, &dev_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
// RTOS forever loop
while (1)
diff --git a/examples/device/hid_composite_freertos/src/usb_descriptors.c b/examples/device/hid_composite_freertos/src/usb_descriptors.c
index 85820de55..3f231fecc 100644
--- a/examples/device/hid_composite_freertos/src/usb_descriptors.c
+++ b/examples/device/hid_composite_freertos/src/usb_descriptors.c
@@ -153,7 +153,7 @@ uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index)
{
(void) index; // for multiple configurations
- // other speed config is basically configuration with type = OHER_SPEED_CONFIG
+ // other speed config is basically configuration with type = OTHER_SPEED_CONFIG
memcpy(desc_other_speed_config, desc_configuration, CONFIG_TOTAL_LEN);
desc_other_speed_config[1] = TUSB_DESC_OTHER_SPEED_CONFIG;
diff --git a/examples/device/hid_generic_inout/src/main.c b/examples/device/hid_generic_inout/src/main.c
index 73f51002d..9837a47d9 100644
--- a/examples/device/hid_generic_inout/src/main.c
+++ b/examples/device/hid_generic_inout/src/main.c
@@ -87,9 +87,7 @@ int main(void)
};
tusb_init(BOARD_TUD_RHPORT, &dev_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
while (1)
{
diff --git a/examples/device/hid_multiple_interface/src/main.c b/examples/device/hid_multiple_interface/src/main.c
index 92c7e8332..0bccd13c1 100644
--- a/examples/device/hid_multiple_interface/src/main.c
+++ b/examples/device/hid_multiple_interface/src/main.c
@@ -68,9 +68,7 @@ int main(void)
};
tusb_init(BOARD_TUD_RHPORT, &dev_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
while (1)
{
diff --git a/examples/device/midi_test/src/main.c b/examples/device/midi_test/src/main.c
index e5c47bdb2..fd58e3021 100644
--- a/examples/device/midi_test/src/main.c
+++ b/examples/device/midi_test/src/main.c
@@ -68,9 +68,7 @@ int main(void) {
};
tusb_init(BOARD_TUD_RHPORT, &dev_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
while (1) {
tud_task(); // tinyusb device task
diff --git a/examples/device/midi_test_freertos/src/main.c b/examples/device/midi_test_freertos/src/main.c
index 3e406d38d..9dd66c526 100644
--- a/examples/device/midi_test_freertos/src/main.c
+++ b/examples/device/midi_test_freertos/src/main.c
@@ -123,9 +123,7 @@ void usb_device_task(void *param) {
};
tusb_init(BOARD_TUD_RHPORT, &dev_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
// RTOS forever loop
while (1) {
@@ -225,13 +223,11 @@ void midi_task(void* param) {
//--------------------------------------------------------------------+
void led_blinking_task(void* param) {
(void) param;
- static uint32_t start_ms = 0;
static bool led_state = false;
while (1) {
// Blink every interval ms
vTaskDelay(blink_interval_ms / portTICK_PERIOD_MS);
- start_ms += blink_interval_ms;
board_led_write(led_state);
led_state = 1 - led_state; // toggle
diff --git a/examples/device/msc_dual_lun/src/main.c b/examples/device/msc_dual_lun/src/main.c
index 012095dca..62b1c872a 100644
--- a/examples/device/msc_dual_lun/src/main.c
+++ b/examples/device/msc_dual_lun/src/main.c
@@ -60,9 +60,7 @@ int main(void) {
};
tusb_init(BOARD_TUD_RHPORT, &dev_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
while (1) {
tud_task(); // tinyusb device task
diff --git a/examples/device/mtp/CMakeLists.txt b/examples/device/mtp/CMakeLists.txt
new file mode 100644
index 000000000..e91eb8fd9
--- /dev/null
+++ b/examples/device/mtp/CMakeLists.txt
@@ -0,0 +1,39 @@
+cmake_minimum_required(VERSION 3.20)
+
+include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
+
+# gets PROJECT name for the example (e.g. <BOARD>-<DIR_NAME>)
+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()
+
+if (RTOS STREQUAL zephyr)
+ set(EXE_NAME app)
+else()
+ set(EXE_NAME ${PROJECT})
+ add_executable(${EXE_NAME})
+endif()
+
+# Example source
+target_sources(${EXE_NAME} PRIVATE
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/mtp_fs_example.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c
+ )
+
+# Example include
+target_include_directories(${EXE_NAME} 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_device_example(${EXE_NAME} ${RTOS})
diff --git a/examples/device/mtp/CMakePresets.json b/examples/device/mtp/CMakePresets.json
new file mode 100644
index 000000000..5cd8971e9
--- /dev/null
+++ b/examples/device/mtp/CMakePresets.json
@@ -0,0 +1,6 @@
+{
+ "version": 6,
+ "include": [
+ "../../../hw/bsp/BoardPresets.json"
+ ]
+}
diff --git a/examples/device/mtp/Makefile b/examples/device/mtp/Makefile
new file mode 100644
index 000000000..7fa475da5
--- /dev/null
+++ b/examples/device/mtp/Makefile
@@ -0,0 +1,11 @@
+include ../../build_system/make/make.mk
+
+INC += \
+ src \
+ $(TOP)/hw \
+
+# Example source
+EXAMPLE_SOURCE += $(wildcard src/*.c)
+SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
+
+include ../../build_system/make/rules.mk
diff --git a/examples/device/mtp/prj.conf b/examples/device/mtp/prj.conf
new file mode 100644
index 000000000..2f5139d9d
--- /dev/null
+++ b/examples/device/mtp/prj.conf
@@ -0,0 +1,6 @@
+CONFIG_GPIO=y
+CONFIG_FPU=y
+CONFIG_NO_OPTIMIZATIONS=y
+CONFIG_UART_INTERRUPT_DRIVEN=y
+CONFIG_NRFX_POWER=y
+CONFIG_NRFX_UARTE0=y
diff --git a/examples/device/mtp/skip.txt b/examples/device/mtp/skip.txt
new file mode 100644
index 000000000..37a4485d7
--- /dev/null
+++ b/examples/device/mtp/skip.txt
@@ -0,0 +1 @@
+board:cynthion_d11
diff --git a/examples/device/mtp/src/main.c b/examples/device/mtp/src/main.c
new file mode 100644
index 000000000..57d1535b2
--- /dev/null
+++ b/examples/device/mtp/src/main.c
@@ -0,0 +1,110 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2025 Ennebi Elettronica (https://ennebielettronica.com)
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "bsp/board_api.h"
+#include "tusb.h"
+
+//--------------------------------------------------------------------+
+// MACRO CONSTANT TYPEDEF PROTYPES
+//--------------------------------------------------------------------+
+
+/* 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);
+
+/*------------- MAIN -------------*/
+int main(void) {
+ board_init();
+
+ // init device stack on configured roothub port
+ tusb_rhport_init_t dev_init = {
+ .role = TUSB_ROLE_DEVICE,
+ .speed = TUSB_SPEED_AUTO
+ };
+ tusb_init(BOARD_TUD_RHPORT, &dev_init);
+ board_init_after_tusb();
+
+ while (1) {
+ tud_task(); // tinyusb device task
+ led_blinking_task();
+ }
+}
+
+//--------------------------------------------------------------------+
+// 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 = tud_mounted() ? BLINK_MOUNTED : BLINK_NOT_MOUNTED;
+}
+
+//--------------------------------------------------------------------+
+// 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/device/mtp/src/mtp_fs_example.c b/examples/device/mtp/src/mtp_fs_example.c
new file mode 100644
index 000000000..b4772f146
--- /dev/null
+++ b/examples/device/mtp/src/mtp_fs_example.c
@@ -0,0 +1,624 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2025 Ennebi Elettronica (https://ennebielettronica.com)
+ *
+ * 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 "bsp/board_api.h"
+#include "tusb.h"
+
+#include "tinyusb_logo_png.h"
+
+//--------------------------------------------------------------------+
+// Dataset
+//--------------------------------------------------------------------+
+
+//------------- device info -------------//
+#define DEV_INFO_MANUFACTURER "TinyUSB"
+#define DEV_INFO_MODEL "MTP Example"
+#define DEV_INFO_VERSION "1.0"
+#define DEV_PROP_FRIENDLY_NAME "TinyUSB MTP"
+
+//------------- storage info -------------//
+#define STORAGE_DESCRIPTRION { 'd', 'i', 's', 'k', 0 }
+#define VOLUME_IDENTIFIER { 'v', 'o', 'l', 0 }
+
+typedef MTP_STORAGE_INFO_STRUCT(TU_ARRAY_SIZE((uint16_t[]) STORAGE_DESCRIPTRION),
+ TU_ARRAY_SIZE(((uint16_t[])VOLUME_IDENTIFIER))
+) storage_info_t;
+
+storage_info_t storage_info = {
+ #ifdef CFG_EXAMPLE_MTP_READONLY
+ .storage_type = MTP_STORAGE_TYPE_FIXED_ROM,
+ #else
+ .storage_type = MTP_STORAGE_TYPE_FIXED_RAM,
+ #endif
+
+ .filesystem_type = MTP_FILESYSTEM_TYPE_GENERIC_HIERARCHICAL,
+ .access_capability = MTP_ACCESS_CAPABILITY_READ_WRITE,
+ .max_capacity_in_bytes = 0, // calculated at runtime
+ .free_space_in_bytes = 0, // calculated at runtime
+ .free_space_in_objects = 0, // calculated at runtime
+ .storage_description = {
+ .count = (TU_FIELD_SIZE(storage_info_t, storage_description)-1) / sizeof(uint16_t),
+ .utf16 = STORAGE_DESCRIPTRION
+ },
+ .volume_identifier = {
+ .count = (TU_FIELD_SIZE(storage_info_t, volume_identifier)-1) / sizeof(uint16_t),
+ .utf16 = VOLUME_IDENTIFIER
+ }
+};
+
+//--------------------------------------------------------------------+
+// MTP FILESYSTEM
+//--------------------------------------------------------------------+
+// only allow to add 1 more object to make it simpler to manage memory
+#define FS_MAX_FILE_COUNT 3UL
+#define FS_MAX_FILENAME_LEN 16
+
+#ifdef CFG_EXAMPLE_MTP_READONLY
+ #define FS_MAX_CAPACITY_BYTES 0
+#else
+ #define FS_MAX_CAPACITY_BYTES (4 * 1024UL)
+
+ // object data buffer (excluding 2 predefined files) with simple allocation pointer
+ uint8_t fs_buf[FS_MAX_CAPACITY_BYTES];
+#endif
+
+#define FS_FIXED_DATETIME "20250808T173500.0" // "YYYYMMDDTHHMMSS.s"
+#define README_TXT_CONTENT "TinyUSB MTP Filesystem example"
+
+typedef struct {
+ uint16_t name[FS_MAX_FILENAME_LEN];
+ uint16_t object_format;
+ uint16_t protection_status;
+ uint32_t image_pix_width;
+ uint32_t image_pix_height;
+ uint32_t image_bit_depth;
+ uint32_t parent;
+ uint16_t association_type;
+ uint32_t size;
+ uint8_t* data;
+} fs_file_t;
+
+// Files system, handle is index + 1
+static fs_file_t fs_objects[FS_MAX_FILE_COUNT] = {
+ {
+ .name = { 'r', 'e', 'a', 'd', 'm', 'e', '.', 't', 'x', 't', 0 }, // readme.txt
+ .object_format = MTP_OBJ_FORMAT_TEXT,
+ .protection_status = MTP_PROTECTION_STATUS_READ_ONLY,
+ .image_pix_width = 0,
+ .image_pix_height = 0,
+ .image_bit_depth = 0,
+ .parent = 0,
+ .association_type = MTP_ASSOCIATION_UNDEFINED,
+ .size = sizeof(README_TXT_CONTENT)-1,
+ .data = (uint8_t*) (uintptr_t) README_TXT_CONTENT,
+ },
+ {
+ .name = { 't', 'i', 'n', 'y', 'u', 's', 'b', '.', 'p', 'n', 'g', 0 }, // "tinyusb.png"
+ .object_format = MTP_OBJ_FORMAT_PNG,
+ .protection_status = MTP_PROTECTION_STATUS_READ_ONLY,
+ .image_pix_width = 128,
+ .image_pix_height = 64,
+ .image_bit_depth = 32,
+ .parent = 0,
+ .association_type = MTP_ASSOCIATION_UNDEFINED,
+ .size = LOGO_LEN,
+ .data = (uint8_t*) (uintptr_t) logo_bin
+ }
+};
+
+enum {
+ SUPPORTED_STORAGE_ID = 0x00010001u // physical = 1, logical = 1
+};
+
+static int32_t fs_get_device_info(tud_mtp_cb_data_t* cb_data);
+static int32_t fs_open_close_session(tud_mtp_cb_data_t* cb_data);
+static int32_t fs_get_storage_ids(tud_mtp_cb_data_t* cb_data);
+static int32_t fs_get_storage_info(tud_mtp_cb_data_t* cb_data);
+static int32_t fs_get_device_properties(tud_mtp_cb_data_t* cb_data);
+static int32_t fs_get_object_handles(tud_mtp_cb_data_t* cb_data);
+static int32_t fs_get_object_info(tud_mtp_cb_data_t* cb_data);
+static int32_t fs_get_object(tud_mtp_cb_data_t* cb_data);
+static int32_t fs_delete_object(tud_mtp_cb_data_t* cb_data);
+static int32_t fs_send_object_info(tud_mtp_cb_data_t* cb_data);
+static int32_t fs_send_object(tud_mtp_cb_data_t* cb_data);
+
+typedef int32_t (*fs_op_handler_t)(tud_mtp_cb_data_t* cb_data);
+typedef struct {
+ uint32_t op_code;
+ fs_op_handler_t handler;
+}fs_op_handler_dict_t;
+
+fs_op_handler_dict_t fs_op_handler_dict[] = {
+ { MTP_OP_GET_DEVICE_INFO, fs_get_device_info },
+ { MTP_OP_OPEN_SESSION, fs_open_close_session },
+ { MTP_OP_CLOSE_SESSION, fs_open_close_session },
+ { MTP_OP_GET_STORAGE_IDS, fs_get_storage_ids },
+ { MTP_OP_GET_STORAGE_INFO, fs_get_storage_info },
+ { MTP_OP_GET_DEVICE_PROP_DESC, fs_get_device_properties },
+ { MTP_OP_GET_DEVICE_PROP_VALUE, fs_get_device_properties },
+ { MTP_OP_GET_OBJECT_HANDLES, fs_get_object_handles },
+ { MTP_OP_GET_OBJECT_INFO, fs_get_object_info },
+ { MTP_OP_GET_OBJECT, fs_get_object },
+ { MTP_OP_DELETE_OBJECT, fs_delete_object },
+ { MTP_OP_SEND_OBJECT_INFO, fs_send_object_info },
+ { MTP_OP_SEND_OBJECT, fs_send_object },
+};
+
+static bool is_session_opened = false;
+static uint32_t send_obj_handle = 0;
+
+//--------------------------------------------------------------------+
+//
+//--------------------------------------------------------------------+
+// Get pointer to object info from handle
+static inline fs_file_t* fs_get_file(uint32_t handle) {
+ if (handle == 0 || handle > FS_MAX_FILE_COUNT) {
+ return NULL;
+ }
+ return &fs_objects[handle-1];
+}
+
+static inline bool fs_file_exist(fs_file_t* f) {
+ return f->name[0] != 0;
+}
+
+// Get the number of allocated nodes in filesystem
+static uint32_t fs_get_file_count(void) {
+ uint32_t count = 0;
+ for (size_t i = 0; i < FS_MAX_FILE_COUNT; i++) {
+ if (fs_file_exist(&fs_objects[i])) {
+ count++;
+ }
+ }
+ return count;
+}
+
+static inline fs_file_t* fs_create_file(void) {
+ for (size_t i = 0; i < FS_MAX_FILE_COUNT; i++) {
+ fs_file_t* f = &fs_objects[i];
+ if (!fs_file_exist(f)) {
+ send_obj_handle = i + 1;
+ return f;
+ }
+ }
+ return NULL;
+}
+
+// simple malloc
+static inline uint8_t* fs_malloc(size_t size) {
+#ifdef CFG_EXAMPLE_MTP_READONLY
+ (void) size;
+ return NULL;
+#else
+ if (size > FS_MAX_CAPACITY_BYTES) {
+ return NULL;
+ }
+ return fs_buf;
+#endif
+}
+
+//--------------------------------------------------------------------+
+// Control Request callback
+//--------------------------------------------------------------------+
+bool tud_mtp_request_cancel_cb(tud_mtp_request_cb_data_t* cb_data) {
+ mtp_request_reset_cancel_data_t cancel_data;
+ memcpy(&cancel_data, cb_data->buf, sizeof(cancel_data));
+ (void) cancel_data.code;
+ (void ) cancel_data.transaction_id;
+ return true;
+}
+
+// Invoked when received Device Reset request
+// return false to stall the request
+bool tud_mtp_request_device_reset_cb(tud_mtp_request_cb_data_t* cb_data) {
+ (void) cb_data;
+ return true;
+}
+
+// Invoked when received Get Extended Event request. Application fill callback data's buffer for response
+// return negative to stall the request
+int32_t tud_mtp_request_get_extended_event_cb(tud_mtp_request_cb_data_t* cb_data) {
+ (void) cb_data;
+ return false; // not implemented yet
+}
+
+// Invoked when received Get DeviceStatus request. Application fill callback data's buffer for response
+// return negative to stall the request
+int32_t tud_mtp_request_get_device_status_cb(tud_mtp_request_cb_data_t* cb_data) {
+ uint16_t* buf16 = (uint16_t*)(uintptr_t) cb_data->buf;
+ buf16[0] = 4; // length
+ buf16[1] = MTP_RESP_OK; // status
+ return 4;
+}
+
+//--------------------------------------------------------------------+
+// Bulk Only Protocol
+//--------------------------------------------------------------------+
+int32_t tud_mtp_command_received_cb(tud_mtp_cb_data_t* cb_data) {
+ const mtp_container_command_t* command = cb_data->command_container;
+ mtp_container_info_t* io_container = &cb_data->io_container;
+ fs_op_handler_t handler = NULL;
+ for (size_t i = 0; i < TU_ARRAY_SIZE(fs_op_handler_dict); i++) {
+ if (fs_op_handler_dict[i].op_code == command->header.code) {
+ handler = fs_op_handler_dict[i].handler;
+ break;
+ }
+ }
+
+ int32_t resp_code;
+ if (handler == NULL) {
+ resp_code = MTP_RESP_OPERATION_NOT_SUPPORTED;
+ } else {
+ resp_code = handler(cb_data);
+ if (resp_code > MTP_RESP_UNDEFINED) {
+ // send response if needed
+ io_container->header->code = (uint16_t)resp_code;
+ tud_mtp_response_send(io_container);
+ }
+ }
+
+ return resp_code;
+}
+
+int32_t tud_mtp_data_xfer_cb(tud_mtp_cb_data_t* cb_data) {
+ const mtp_container_command_t* command = cb_data->command_container;
+ mtp_container_info_t* io_container = &cb_data->io_container;
+
+ fs_op_handler_t handler = NULL;
+ for (size_t i = 0; i < TU_ARRAY_SIZE(fs_op_handler_dict); i++) {
+ if (fs_op_handler_dict[i].op_code == command->header.code) {
+ handler = fs_op_handler_dict[i].handler;
+ break;
+ }
+ }
+
+ int32_t resp_code;
+ if (handler == NULL) {
+ resp_code = MTP_RESP_OPERATION_NOT_SUPPORTED;
+ } else {
+ resp_code = handler(cb_data);
+ if (resp_code > MTP_RESP_UNDEFINED) {
+ // send response if needed
+ io_container->header->code = (uint16_t)resp_code;
+ tud_mtp_response_send(io_container);
+ }
+ }
+
+ return 0;
+}
+
+int32_t tud_mtp_data_complete_cb(tud_mtp_cb_data_t* cb_data) {
+ const mtp_container_command_t* command = cb_data->command_container;
+ mtp_container_info_t* resp = &cb_data->io_container;
+ switch (command->header.code) {
+ case MTP_OP_SEND_OBJECT_INFO: {
+ fs_file_t* f = fs_get_file(send_obj_handle);
+ if (f == NULL) {
+ resp->header->code = MTP_RESP_GENERAL_ERROR;
+ break;
+ }
+ // parameter is: storage id, parent handle, new handle
+ mtp_container_add_uint32(resp, SUPPORTED_STORAGE_ID);
+ mtp_container_add_uint32(resp, f->parent);
+ mtp_container_add_uint32(resp, send_obj_handle);
+ resp->header->code = MTP_RESP_OK;
+ break;
+ }
+
+ default:
+ resp->header->code = (cb_data->xfer_result == XFER_RESULT_SUCCESS) ? MTP_RESP_OK : MTP_RESP_GENERAL_ERROR;
+ break;
+ }
+
+ tud_mtp_response_send(resp);
+ return 0;
+}
+
+int32_t tud_mtp_response_complete_cb(tud_mtp_cb_data_t* cb_data) {
+ (void) cb_data;
+ return 0; // nothing to do
+}
+
+//--------------------------------------------------------------------+
+// File System Handlers
+//--------------------------------------------------------------------+
+static int32_t fs_get_device_info(tud_mtp_cb_data_t* cb_data) {
+ // Device info is already prepared up to playback formats. Application only need to add string fields
+ mtp_container_info_t* io_container = &cb_data->io_container;
+ mtp_container_add_cstring(io_container, DEV_INFO_MANUFACTURER);
+ mtp_container_add_cstring(io_container, DEV_INFO_MODEL);
+ mtp_container_add_cstring(io_container, DEV_INFO_VERSION);
+
+ enum { MAX_SERIAL_NCHARS = 32 };
+ uint16_t serial_utf16[MAX_SERIAL_NCHARS+1];
+ size_t nchars = board_usb_get_serial(serial_utf16, MAX_SERIAL_NCHARS);
+ serial_utf16[tu_min32(nchars, MAX_SERIAL_NCHARS)] = 0; // ensure null termination
+ mtp_container_add_string(io_container, serial_utf16);
+
+ tud_mtp_data_send(io_container);
+ return 0;
+}
+
+static int32_t fs_open_close_session(tud_mtp_cb_data_t* cb_data) {
+ const mtp_container_command_t* command = cb_data->command_container;
+ if (command->header.code == MTP_OP_OPEN_SESSION) {
+ if (is_session_opened) {
+ return MTP_RESP_SESSION_ALREADY_OPEN;
+ }
+ is_session_opened = true;
+ } else { // close session
+ if (!is_session_opened) {
+ return MTP_RESP_SESSION_NOT_OPEN;
+ }
+ is_session_opened = false;
+ }
+ return MTP_RESP_OK;
+}
+
+static int32_t fs_get_storage_ids(tud_mtp_cb_data_t* cb_data) {
+ mtp_container_info_t* io_container = &cb_data->io_container;
+ uint32_t storage_ids [] = { SUPPORTED_STORAGE_ID };
+ mtp_container_add_auint32(io_container, 1, storage_ids);
+ tud_mtp_data_send(io_container);
+ return 0;
+}
+
+static int32_t fs_get_storage_info(tud_mtp_cb_data_t* cb_data) {
+ const mtp_container_command_t* command = cb_data->command_container;
+ mtp_container_info_t* io_container = &cb_data->io_container;
+ const uint32_t storage_id = command->params[0];
+ TU_VERIFY(SUPPORTED_STORAGE_ID == storage_id, -1);
+ // update storage info with current free space
+ storage_info.max_capacity_in_bytes = sizeof(README_TXT_CONTENT) + LOGO_LEN + FS_MAX_CAPACITY_BYTES;
+ storage_info.free_space_in_objects = FS_MAX_FILE_COUNT - fs_get_file_count();
+ storage_info.free_space_in_bytes = storage_info.free_space_in_objects ? FS_MAX_CAPACITY_BYTES : 0;
+ mtp_container_add_raw(io_container, &storage_info, sizeof(storage_info));
+ tud_mtp_data_send(io_container);
+ return 0;
+}
+
+static int32_t fs_get_device_properties(tud_mtp_cb_data_t* cb_data) {
+ const mtp_container_command_t* command = cb_data->command_container;
+ mtp_container_info_t* io_container = &cb_data->io_container;
+ const uint16_t dev_prop_code = (uint16_t) command->params[0];
+
+ if (command->header.code == MTP_OP_GET_DEVICE_PROP_DESC) {
+ // get describing dataset
+ mtp_device_prop_desc_header_t device_prop_header;
+ device_prop_header.device_property_code = dev_prop_code;
+ switch (dev_prop_code) {
+ case MTP_DEV_PROP_DEVICE_FRIENDLY_NAME:
+ device_prop_header.datatype = MTP_DATA_TYPE_STR;
+ device_prop_header.get_set = MTP_MODE_GET;
+ mtp_container_add_raw(io_container, &device_prop_header, sizeof(device_prop_header));
+ mtp_container_add_cstring(io_container, DEV_PROP_FRIENDLY_NAME); // factory
+ mtp_container_add_cstring(io_container, DEV_PROP_FRIENDLY_NAME); // current
+ mtp_container_add_uint8(io_container, 0); // no form
+ tud_mtp_data_send(io_container);
+ break;
+
+ default:
+ return MTP_RESP_PARAMETER_NOT_SUPPORTED;
+ }
+ } else {
+ // get value
+ switch (dev_prop_code) {
+ case MTP_DEV_PROP_DEVICE_FRIENDLY_NAME:
+ mtp_container_add_cstring(io_container, DEV_PROP_FRIENDLY_NAME);
+ tud_mtp_data_send(io_container);
+ break;
+
+ default:
+ return MTP_RESP_PARAMETER_NOT_SUPPORTED;
+ }
+ }
+ return 0;
+}
+
+static int32_t fs_get_object_handles(tud_mtp_cb_data_t* cb_data) {
+ const mtp_container_command_t* command = cb_data->command_container;
+ mtp_container_info_t* io_container = &cb_data->io_container;
+
+ const uint32_t storage_id = command->params[0];
+ const uint32_t obj_format = command->params[1]; // optional
+ const uint32_t parent_handle = command->params[2]; // folder handle, 0xFFFFFFFF is root
+ (void)obj_format;
+
+ if (storage_id != 0xFFFFFFFF && storage_id != SUPPORTED_STORAGE_ID) {
+ return MTP_RESP_INVALID_STORAGE_ID;
+ }
+
+ uint32_t handles[FS_MAX_FILE_COUNT] = { 0 };
+ uint32_t count = 0;
+ for (uint8_t i = 0; i < FS_MAX_FILE_COUNT; i++) {
+ fs_file_t* f = &fs_objects[i];
+ if (fs_file_exist(f) &&
+ (parent_handle == f->parent || (parent_handle == 0xFFFFFFFF && f->parent == 0))) {
+ handles[count++] = i + 1; // handle is index + 1
+ }
+ }
+ mtp_container_add_auint32(io_container, count, handles);
+ tud_mtp_data_send(io_container);
+
+ return 0;
+}
+
+static int32_t fs_get_object_info(tud_mtp_cb_data_t* cb_data) {
+ const mtp_container_command_t* command = cb_data->command_container;
+ mtp_container_info_t* io_container = &cb_data->io_container;
+ const uint32_t obj_handle = command->params[0];
+ fs_file_t* f = fs_get_file(obj_handle);
+ if (f == NULL) {
+ return MTP_RESP_INVALID_OBJECT_HANDLE;
+ }
+ mtp_object_info_header_t obj_info_header = {
+ .storage_id = SUPPORTED_STORAGE_ID,
+ .object_format = f->object_format,
+ .protection_status = f->protection_status,
+ .object_compressed_size = f->size,
+ .thumb_format = MTP_OBJ_FORMAT_UNDEFINED,
+ .thumb_compressed_size = 0,
+ .thumb_pix_width = 0,
+ .thumb_pix_height = 0,
+ .image_pix_width = f->image_pix_width,
+ .image_pix_height = f->image_pix_height,
+ .image_bit_depth = f->image_bit_depth,
+ .parent_object = f->parent,
+ .association_type = f->association_type,
+ .association_desc = 0,
+ .sequence_number = 0
+ };
+ mtp_container_add_raw(io_container, &obj_info_header, sizeof(obj_info_header));
+ mtp_container_add_string(io_container, f->name);
+ mtp_container_add_cstring(io_container, FS_FIXED_DATETIME);
+ mtp_container_add_cstring(io_container, FS_FIXED_DATETIME);
+ mtp_container_add_cstring(io_container, ""); // keywords, not used
+ tud_mtp_data_send(io_container);
+
+ return 0;
+}
+
+static int32_t fs_get_object(tud_mtp_cb_data_t* cb_data) {
+ const mtp_container_command_t* command = cb_data->command_container;
+ mtp_container_info_t* io_container = &cb_data->io_container;
+ const uint32_t obj_handle = command->params[0];
+ const fs_file_t* f = fs_get_file(obj_handle);
+ if (f == NULL) {
+ return MTP_RESP_INVALID_OBJECT_HANDLE;
+ }
+
+ if (cb_data->phase == MTP_PHASE_COMMAND) {
+ // If file contents is larger than CFG_TUD_MTP_EP_BUFSIZE, data may only partially is added here
+ // the rest will be sent in tud_mtp_data_more_cb
+ mtp_container_add_raw(io_container, f->data, f->size);
+ tud_mtp_data_send(io_container);
+ } else if (cb_data->phase == MTP_PHASE_DATA) {
+ // continue sending remaining data: file contents offset is xferred byte minus header size
+ const uint32_t offset = cb_data->total_xferred_bytes - sizeof(mtp_container_header_t);
+ const uint32_t xact_len = tu_min32(f->size - offset, io_container->payload_bytes);
+ if (xact_len > 0) {
+ memcpy(io_container->payload, f->data + offset, xact_len);
+ tud_mtp_data_send(io_container);
+ }
+ }
+
+ return 0;
+}
+
+static int32_t fs_send_object_info(tud_mtp_cb_data_t* cb_data) {
+ const mtp_container_command_t* command = cb_data->command_container;
+ mtp_container_info_t* io_container = &cb_data->io_container;
+ const uint32_t storage_id = command->params[0];
+ const uint32_t parent_handle = command->params[1]; // folder handle, 0xFFFFFFFF is root
+ (void) parent_handle;
+
+ if (!is_session_opened) {
+ return MTP_RESP_SESSION_NOT_OPEN;
+ }
+ if (storage_id != 0xFFFFFFFF && storage_id != SUPPORTED_STORAGE_ID) {
+ return MTP_RESP_INVALID_STORAGE_ID;
+ }
+
+ if (cb_data->phase == MTP_PHASE_COMMAND) {
+ tud_mtp_data_receive(io_container);
+ } else if (cb_data->phase == MTP_PHASE_DATA) {
+ mtp_object_info_header_t* obj_info = (mtp_object_info_header_t*) io_container->payload;
+ if (obj_info->storage_id != 0 && obj_info->storage_id != SUPPORTED_STORAGE_ID) {
+ return MTP_RESP_INVALID_STORAGE_ID;
+ }
+
+ if (obj_info->parent_object) {
+ fs_file_t* parent = fs_get_file(obj_info->parent_object);
+ if (parent == NULL || !parent->association_type) {
+ return MTP_RESP_INVALID_PARENT_OBJECT;
+ }
+ }
+
+ uint8_t* f_buf = fs_malloc(obj_info->object_compressed_size);
+ if (f_buf == NULL) {
+ return MTP_RESP_STORE_FULL;
+ }
+ fs_file_t* f = fs_create_file();
+ if (f == NULL) {
+ return MTP_RESP_STORE_FULL;
+ }
+
+ f->object_format = obj_info->object_format;
+ f->protection_status = obj_info->protection_status;
+ f->image_pix_width = obj_info->image_pix_width;
+ f->image_pix_height = obj_info->image_pix_height;
+ f->image_bit_depth = obj_info->image_bit_depth;
+ f->parent = obj_info->parent_object;
+ f->association_type = obj_info->association_type;
+ f->size = obj_info->object_compressed_size;
+ f->data = f_buf;
+ uint8_t* buf = io_container->payload + sizeof(mtp_object_info_header_t);
+ mtp_container_get_string(buf, f->name);
+ // ignore date created/modified/keywords
+ }
+
+ return 0;
+}
+
+static int32_t fs_send_object(tud_mtp_cb_data_t* cb_data) {
+ mtp_container_info_t* io_container = &cb_data->io_container;
+ fs_file_t* f = fs_get_file(send_obj_handle);
+ if (f == NULL) {
+ return MTP_RESP_INVALID_OBJECT_HANDLE;
+ }
+
+ if (cb_data->phase == MTP_PHASE_COMMAND) {
+ io_container->header->len += f->size;
+ tud_mtp_data_receive(io_container);
+ } else {
+ // file contents offset is total xferred minus header size minus last received chunk
+ const uint32_t offset = cb_data->total_xferred_bytes - sizeof(mtp_container_header_t) - io_container->payload_bytes;
+ memcpy(f->data + offset, io_container->payload, io_container->payload_bytes);
+ if (cb_data->total_xferred_bytes - sizeof(mtp_container_header_t) < f->size) {
+ tud_mtp_data_receive(io_container);
+ }
+ }
+
+ return 0;
+}
+
+static int32_t fs_delete_object(tud_mtp_cb_data_t* cb_data) {
+ const mtp_container_command_t* command = cb_data->command_container;
+ const uint32_t obj_handle = command->params[0];
+ const uint32_t obj_format = command->params[1]; // optional
+ (void) obj_format;
+
+ if (!is_session_opened) {
+ return MTP_RESP_SESSION_NOT_OPEN;
+ }
+ fs_file_t* f = fs_get_file(obj_handle);
+ if (f == NULL) {
+ return MTP_RESP_INVALID_OBJECT_HANDLE;
+ }
+
+ // delete object by clear the name
+ f->name[0] = 0;
+ return MTP_RESP_OK;
+}
diff --git a/examples/device/mtp/src/tinyusb_logo_png.h b/examples/device/mtp/src/tinyusb_logo_png.h
new file mode 100644
index 000000000..f8a9bde4e
--- /dev/null
+++ b/examples/device/mtp/src/tinyusb_logo_png.h
@@ -0,0 +1,175 @@
+// convert using tools/file2carray.py
+enum { LOGO_LEN = 2733 };
+static const uint8_t logo_bin[] __attribute__((aligned(16))) = {
+ 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
+ 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x40, 0x08, 0x06, 0x00, 0x00, 0x00, 0xd2, 0xd6, 0x7f,
+ 0x7f, 0x00, 0x00, 0x00, 0x06, 0x62, 0x4b, 0x47, 0x44, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0xa0,
+ 0xbd, 0xa7, 0x93, 0x00, 0x00, 0x0a, 0x62, 0x49, 0x44, 0x41, 0x54, 0x78, 0x9c, 0xed, 0x9c, 0x7d,
+ 0x54, 0x54, 0x65, 0x1a, 0xc0, 0x7f, 0xc3, 0x00, 0x29, 0x1f, 0x31, 0x88, 0x61, 0x90, 0xd6, 0xa1,
+ 0xb3, 0xba, 0x1a, 0x18, 0x7e, 0xf2, 0xad, 0x40, 0x82, 0xb8, 0x9b, 0x2b, 0x43, 0x1e, 0xd2, 0x00,
+ 0x53, 0xc0, 0xea, 0xec, 0xc9, 0x70, 0x18, 0x3d, 0x5b, 0xb1, 0x9e, 0x4a, 0x6d, 0x13, 0x2d, 0xcb,
+ 0x76, 0xcd, 0x00, 0xf3, 0x8b, 0x10, 0x8a, 0x8e, 0xd6, 0xee, 0xda, 0x8a, 0x96, 0x30, 0x66, 0xa2,
+ 0xa0, 0x91, 0x64, 0xae, 0x16, 0x98, 0x45, 0x9d, 0x2c, 0x93, 0x8f, 0x05, 0x11, 0x92, 0x81, 0xbb,
+ 0x7f, 0xa8, 0x93, 0x33, 0x23, 0xcc, 0xdc, 0x61, 0x60, 0x46, 0xb8, 0xbf, 0xbf, 0x78, 0xdf, 0xfb,
+ 0x3c, 0xcf, 0xfb, 0xc0, 0x7d, 0xee, 0x73, 0xdf, 0xf7, 0xb9, 0xef, 0x8b, 0x8c, 0x6b, 0x08, 0x82,
+ 0x90, 0x08, 0x2c, 0x03, 0x02, 0x81, 0x21, 0x48, 0x0c, 0x44, 0xda, 0x81, 0x6a, 0xe0, 0x55, 0x99,
+ 0x4c, 0x56, 0x0c, 0x20, 0x03, 0x10, 0x04, 0x61, 0x35, 0xb0, 0xc2, 0x86, 0x8e, 0x49, 0xf4, 0x3f,
+ 0x6b, 0x64, 0x32, 0x59, 0x96, 0x4c, 0x10, 0x84, 0x19, 0xc0, 0x47, 0x5c, 0x0b, 0x06, 0x89, 0x41,
+ 0x45, 0xac, 0x03, 0xa0, 0x42, 0xba, 0xf9, 0x83, 0x15, 0x95, 0x4c, 0x10, 0x84, 0x8b, 0x80, 0x97,
+ 0xad, 0x3d, 0x91, 0xb0, 0x09, 0x4d, 0x32, 0x41, 0x10, 0x3a, 0x01, 0x07, 0x5b, 0x7b, 0x22, 0x61,
+ 0x1b, 0x1c, 0x90, 0xd2, 0xff, 0xa0, 0x46, 0x7a, 0xf2, 0x07, 0x39, 0x52, 0x00, 0x0c, 0x72, 0x1c,
+ 0x2d, 0x55, 0x3c, 0x52, 0x5e, 0x4e, 0x53, 0x63, 0x93, 0x28, 0x9d, 0x49, 0x93, 0x27, 0x31, 0xe2,
+ 0xce, 0x3b, 0x4d, 0xca, 0x5d, 0xba, 0x74, 0x89, 0xea, 0x13, 0xd5, 0x26, 0xe5, 0x46, 0x8c, 0xf0,
+ 0xe6, 0x77, 0xa3, 0x47, 0x8b, 0xf2, 0x41, 0x42, 0x1f, 0x99, 0x20, 0x08, 0x5d, 0x58, 0x30, 0x0f,
+ 0x48, 0x7c, 0x68, 0x2e, 0x9f, 0x57, 0x55, 0x89, 0xd2, 0xd9, 0x94, 0x9b, 0xc3, 0xcc, 0xb8, 0x38,
+ 0x93, 0x72, 0x27, 0xbf, 0x38, 0x49, 0xc2, 0x9c, 0x39, 0x78, 0x78, 0x78, 0x74, 0x2b, 0xd3, 0xd6,
+ 0xd6, 0x46, 0xbc, 0x52, 0xc9, 0x9a, 0x75, 0x6b, 0x45, 0xf9, 0x20, 0xa1, 0x8f, 0xc5, 0x19, 0xa0,
+ 0x3f, 0xa8, 0xfc, 0xec, 0x38, 0x72, 0xc7, 0x9b, 0xbb, 0xb8, 0x22, 0x2b, 0x8b, 0x4e, 0x6d, 0x67,
+ 0x3f, 0x7b, 0x34, 0xf0, 0x90, 0xe6, 0x00, 0x83, 0x1c, 0xbb, 0x0e, 0x80, 0xb6, 0xb6, 0x36, 0x5e,
+ 0x5c, 0xb5, 0x8a, 0x0f, 0x76, 0xbf, 0x0f, 0x40, 0xdd, 0x77, 0xdf, 0xf1, 0xe2, 0xaa, 0x55, 0x1c,
+ 0xfe, 0xf4, 0xb0, 0x8d, 0x3d, 0x1b, 0x38, 0xd8, 0x75, 0x00, 0x68, 0xb5, 0x5a, 0x34, 0xa5, 0x65,
+ 0x9c, 0x3a, 0x75, 0x0a, 0x80, 0xa6, 0xa6, 0xff, 0xa1, 0x29, 0x2d, 0xa3, 0xae, 0xee, 0x3b, 0x1b,
+ 0x7b, 0x36, 0x70, 0xb0, 0xeb, 0x39, 0x80, 0xbb, 0xbb, 0x3b, 0x1f, 0x6b, 0xca, 0x74, 0xed, 0xfb,
+ 0x03, 0xef, 0xd7, 0xb5, 0x57, 0x64, 0x65, 0xd9, 0xca, 0xad, 0x01, 0x85, 0x5d, 0x07, 0x80, 0xbd,
+ 0x70, 0xb9, 0xf5, 0x32, 0x3f, 0x5f, 0xf8, 0x19, 0xb9, 0x83, 0x03, 0x6e, 0xee, 0xee, 0x28, 0x14,
+ 0x0a, 0x1c, 0x1c, 0xec, 0x3a, 0x79, 0x9a, 0x8d, 0xd9, 0xcb, 0xc0, 0x8e, 0x8e, 0x0e, 0x56, 0x3e,
+ 0xff, 0xbc, 0xae, 0xfd, 0xf1, 0xfe, 0x8f, 0xb8, 0x78, 0xf1, 0xa2, 0xa8, 0xc1, 0x22, 0xa6, 0x4d,
+ 0x63, 0xe4, 0xa8, 0x91, 0x7a, 0x7d, 0xa1, 0x61, 0x61, 0x3c, 0x38, 0x7b, 0xb6, 0xae, 0xfd, 0xf7,
+ 0x0d, 0x1b, 0x38, 0x73, 0xfa, 0x0c, 0xfb, 0xf7, 0xed, 0xe3, 0xe1, 0xf9, 0xf3, 0xba, 0xfd, 0x43,
+ 0x1f, 0xab, 0x3c, 0x86, 0xd0, 0xd5, 0x45, 0x50, 0x48, 0x30, 0x69, 0x8b, 0x17, 0x73, 0xef, 0xbd,
+ 0xf7, 0xea, 0xae, 0x7d, 0xb4, 0x7f, 0x3f, 0x07, 0x35, 0x1a, 0x51, 0xbe, 0xad, 0x5c, 0xbd, 0x1a,
+ 0xb9, 0x5c, 0x0e, 0x5c, 0x9d, 0x6b, 0x94, 0xec, 0x2d, 0xe1, 0xa0, 0x46, 0x43, 0xf5, 0x89, 0x13,
+ 0xb4, 0xb7, 0xb7, 0xeb, 0xc9, 0xba, 0xb9, 0xb9, 0xe1, 0x1f, 0x10, 0x40, 0x4c, 0x6c, 0x0c, 0xf1,
+ 0x09, 0x09, 0x0c, 0x1b, 0x36, 0x4c, 0x77, 0xed, 0xc7, 0x1f, 0x7f, 0x64, 0xd3, 0xc6, 0x8d, 0xa2,
+ 0xc6, 0x06, 0x70, 0x90, 0x39, 0xf0, 0xec, 0x5f, 0xb3, 0x18, 0xea, 0xe2, 0x22, 0x4a, 0xef, 0xdd,
+ 0xa2, 0x77, 0x38, 0x79, 0xf2, 0x0b, 0xbd, 0xbe, 0xe4, 0x94, 0x14, 0xc6, 0xdd, 0x77, 0x9f, 0x59,
+ 0xfa, 0x66, 0x07, 0x40, 0x5b, 0x5b, 0x1b, 0xe3, 0xc7, 0x99, 0x67, 0x54, 0x0c, 0x8b, 0xd2, 0x52,
+ 0x59, 0xf1, 0xdc, 0x73, 0xba, 0x76, 0x5c, 0x4c, 0x2c, 0x67, 0x6b, 0x6b, 0x45, 0xd9, 0x28, 0x28,
+ 0x2a, 0x24, 0x24, 0x34, 0x54, 0xd7, 0x5e, 0xff, 0xf2, 0x2b, 0xbc, 0xf9, 0xc6, 0x1b, 0xa2, 0x6c,
+ 0x9c, 0xa9, 0xad, 0xa1, 0xa1, 0xa1, 0x81, 0x7f, 0x6c, 0x78, 0x9d, 0xe2, 0xe2, 0x77, 0xcd, 0x5e,
+ 0x62, 0x0e, 0x19, 0x32, 0x84, 0xa5, 0x99, 0x99, 0xa4, 0xa5, 0xa7, 0xe9, 0x96, 0xac, 0x73, 0xe3,
+ 0x95, 0x54, 0x57, 0x9b, 0x2e, 0x64, 0x19, 0xf2, 0xf4, 0xb3, 0xcf, 0xf2, 0xd8, 0x13, 0x8f, 0x9b,
+ 0x2d, 0xdf, 0xdc, 0xdc, 0x4c, 0x44, 0x68, 0x28, 0x97, 0x5b, 0x2f, 0xeb, 0xfa, 0x14, 0x0a, 0x05,
+ 0x87, 0xca, 0x0f, 0x9b, 0x1d, 0x48, 0x03, 0x23, 0x8f, 0x59, 0x81, 0xea, 0x13, 0x27, 0x98, 0x3d,
+ 0xeb, 0x0f, 0x14, 0x15, 0x16, 0x8a, 0xaa, 0x2f, 0xb4, 0xb7, 0xb7, 0xb3, 0x76, 0xcd, 0x1a, 0x32,
+ 0x96, 0x3c, 0x45, 0xa7, 0x56, 0x0b, 0xc0, 0x53, 0xaa, 0xa5, 0x16, 0xf9, 0x90, 0x97, 0x9b, 0xa3,
+ 0x77, 0x33, 0x4d, 0x51, 0xb4, 0xb3, 0xd0, 0x48, 0x3e, 0xe5, 0xd1, 0x05, 0xa2, 0xb2, 0x88, 0x14,
+ 0x00, 0xd7, 0x78, 0xe2, 0xb1, 0xc7, 0x69, 0x68, 0x68, 0xb0, 0x58, 0x7f, 0x5f, 0x49, 0x09, 0x6b,
+ 0xb3, 0xaf, 0x56, 0x25, 0xa3, 0xa2, 0xa3, 0x09, 0x9c, 0x30, 0x41, 0xb4, 0x8d, 0xc6, 0x86, 0x46,
+ 0x76, 0x16, 0x14, 0x98, 0x25, 0xab, 0xd5, 0x6a, 0x29, 0xc8, 0xcf, 0xd7, 0xeb, 0x73, 0x72, 0x72,
+ 0x22, 0x29, 0x25, 0x45, 0xd4, 0x98, 0x66, 0x4f, 0x02, 0x9d, 0x9d, 0x9d, 0xd9, 0x71, 0x83, 0x73,
+ 0xab, 0x57, 0xae, 0xa4, 0xb6, 0xa6, 0x46, 0xd4, 0x60, 0x19, 0x2a, 0x15, 0x93, 0xa7, 0x4c, 0xd1,
+ 0xeb, 0xf3, 0xf1, 0xf5, 0x11, 0x65, 0xa3, 0xaf, 0x68, 0x6a, 0x6c, 0xec, 0xb5, 0x8d, 0x1d, 0xdb,
+ 0xb7, 0x91, 0xf8, 0x70, 0x22, 0xa3, 0xc7, 0x8c, 0x61, 0x69, 0xa6, 0x8a, 0xb4, 0x85, 0x8b, 0x44,
+ 0xdb, 0xc8, 0xcb, 0xcd, 0x21, 0x39, 0x25, 0x05, 0x17, 0xd7, 0x9e, 0x9f, 0xe2, 0x0f, 0xf7, 0xec,
+ 0xe1, 0xfc, 0xf9, 0xf3, 0x7a, 0x7d, 0x73, 0xe2, 0xe3, 0xf1, 0xf6, 0xf6, 0x16, 0x35, 0x9e, 0xd9,
+ 0x01, 0x20, 0x97, 0xcb, 0x09, 0x8f, 0x08, 0xd7, 0xb5, 0xdd, 0xdd, 0xdd, 0x45, 0x0d, 0x04, 0x30,
+ 0x76, 0xdc, 0x58, 0x3d, 0x1b, 0xf6, 0xc4, 0x5d, 0x77, 0xdd, 0x45, 0x70, 0x48, 0x08, 0x23, 0x47,
+ 0x8d, 0xa4, 0xab, 0xab, 0x8b, 0xe3, 0xc7, 0x8e, 0x73, 0xf4, 0xc8, 0x11, 0x51, 0x36, 0x3a, 0xb5,
+ 0x9d, 0x14, 0x15, 0x16, 0xf2, 0xdc, 0x0b, 0x2f, 0x30, 0x3d, 0x32, 0x92, 0x29, 0x53, 0xa7, 0x70,
+ 0xfc, 0xd8, 0x71, 0x51, 0x36, 0xae, 0x67, 0x01, 0x53, 0x73, 0x81, 0xfc, 0x6d, 0xdb, 0x8d, 0xfa,
+ 0x16, 0xa5, 0xa5, 0x8a, 0x1a, 0x0b, 0xa4, 0x57, 0x80, 0x8e, 0x98, 0x99, 0xb1, 0xac, 0x5b, 0xff,
+ 0x0a, 0x19, 0x2a, 0x15, 0x2a, 0xb5, 0x9a, 0x82, 0xa2, 0x42, 0xfe, 0xfc, 0xe4, 0x93, 0xa2, 0xed,
+ 0x94, 0x95, 0xfe, 0x56, 0xb7, 0x58, 0x92, 0x91, 0x61, 0x91, 0x2f, 0xa6, 0xe6, 0x02, 0x95, 0x15,
+ 0x15, 0x46, 0x93, 0xcc, 0xb0, 0xf0, 0x70, 0xb3, 0x67, 0xfe, 0x37, 0x22, 0x05, 0x40, 0x0f, 0x2c,
+ 0x4a, 0x4b, 0xd5, 0x2d, 0x0d, 0xcd, 0xe5, 0xfb, 0xba, 0x3a, 0x9a, 0x9a, 0xae, 0x7e, 0x26, 0x8f,
+ 0x98, 0x36, 0x8d, 0xa9, 0x41, 0x53, 0x45, 0x8f, 0x6b, 0x6a, 0x2e, 0xb0, 0xe5, 0xad, 0xb7, 0x8c,
+ 0xfa, 0x52, 0xd3, 0xd3, 0x44, 0x8f, 0x03, 0x52, 0x00, 0xf4, 0x88, 0x97, 0x97, 0x17, 0x0a, 0x85,
+ 0x42, 0xb4, 0x5e, 0x7d, 0x7d, 0xbd, 0xee, 0xe7, 0x25, 0x19, 0xd6, 0x5d, 0x11, 0x7c, 0x7b, 0xee,
+ 0x5b, 0xca, 0x0e, 0x94, 0xea, 0xf5, 0xf9, 0xf9, 0xf9, 0x11, 0x19, 0x15, 0x65, 0xd1, 0x38, 0x76,
+ 0x1b, 0x00, 0x81, 0x81, 0x81, 0x6c, 0xdc, 0xb4, 0x89, 0xdc, 0xcd, 0x9b, 0x89, 0x57, 0x2a, 0x01,
+ 0x58, 0x98, 0xba, 0x88, 0x3d, 0x25, 0x7b, 0xd9, 0xf5, 0xcf, 0x0f, 0x48, 0x4d, 0x4b, 0x43, 0x26,
+ 0xeb, 0xfb, 0xed, 0x8c, 0xb7, 0xdf, 0x7e, 0xbb, 0x68, 0x9d, 0xc6, 0x86, 0xdf, 0x26, 0x94, 0xe1,
+ 0x11, 0xe1, 0x4c, 0x0d, 0x0a, 0xb2, 0xc8, 0xc6, 0xcd, 0xb2, 0xc0, 0xb6, 0xad, 0x5b, 0xe9, 0xea,
+ 0xea, 0xd2, 0xeb, 0x4b, 0x7b, 0x6c, 0xb1, 0xc5, 0x95, 0x49, 0xbb, 0x2c, 0x05, 0xfb, 0xfa, 0xfa,
+ 0x52, 0x50, 0x54, 0xa8, 0x5b, 0xcf, 0xce, 0x88, 0x8d, 0x61, 0x7a, 0x64, 0x24, 0xf1, 0x09, 0x4a,
+ 0x9d, 0x4c, 0x60, 0x60, 0x20, 0x1d, 0x37, 0x59, 0x0a, 0x59, 0x1b, 0x4b, 0x82, 0xac, 0xab, 0x4b,
+ 0xbf, 0x8e, 0x90, 0xa1, 0x5a, 0xca, 0x82, 0xa4, 0x64, 0xd1, 0x76, 0x0c, 0x57, 0x04, 0x4d, 0x4d,
+ 0x4d, 0xec, 0xde, 0xb5, 0x4b, 0x4f, 0x46, 0xa1, 0x50, 0xa0, 0x54, 0x2a, 0x6f, 0xa6, 0x6e, 0x16,
+ 0x76, 0x99, 0x01, 0xe6, 0x28, 0x95, 0x0c, 0x75, 0x71, 0x61, 0x5d, 0x76, 0x36, 0xe1, 0x21, 0xa1,
+ 0xe4, 0x6f, 0xdf, 0x41, 0x7c, 0x82, 0x92, 0xa3, 0x47, 0x8e, 0x70, 0xbf, 0xbf, 0x3f, 0x33, 0x1f,
+ 0x98, 0x41, 0x4b, 0x4b, 0x0b, 0xf3, 0x93, 0x1e, 0xb1, 0xb5, 0xab, 0x66, 0x11, 0x1a, 0x16, 0x46,
+ 0x50, 0x70, 0xb0, 0x68, 0x3d, 0xc3, 0x2c, 0x50, 0x58, 0x50, 0x40, 0xdb, 0x65, 0xfd, 0xd7, 0x42,
+ 0xf2, 0x82, 0x14, 0xd1, 0xe5, 0xe3, 0x1b, 0xb1, 0xcb, 0x00, 0x18, 0x35, 0x6a, 0x14, 0x70, 0x75,
+ 0x69, 0xf6, 0xe8, 0xc2, 0x85, 0xb8, 0xb9, 0xbb, 0x01, 0x57, 0x9f, 0xc6, 0x27, 0x97, 0x3c, 0xc5,
+ 0xdc, 0xc4, 0x44, 0x5a, 0x2f, 0xb5, 0x72, 0xcf, 0xdd, 0x77, 0xdb, 0xd2, 0x4d, 0x51, 0xa8, 0x97,
+ 0x2f, 0xb7, 0x48, 0xef, 0xfa, 0x5c, 0x40, 0xab, 0xd5, 0x52, 0xb8, 0x73, 0xa7, 0xde, 0x35, 0x27,
+ 0x27, 0x27, 0x92, 0x17, 0x2c, 0xe8, 0x95, 0x5f, 0x76, 0xf9, 0x0a, 0x70, 0x76, 0x76, 0x06, 0x30,
+ 0xfa, 0xe5, 0x82, 0x43, 0x42, 0x08, 0x0e, 0x09, 0xd1, 0xb5, 0xaf, 0x97, 0x5e, 0x6f, 0x05, 0xa6,
+ 0x4c, 0x9d, 0x42, 0x70, 0x48, 0x08, 0x15, 0x47, 0x8f, 0x8a, 0xd2, 0xbb, 0x9e, 0x05, 0xbc, 0x86,
+ 0x7b, 0xf1, 0xd3, 0xf9, 0x9f, 0xf4, 0xae, 0x59, 0x52, 0xf8, 0x31, 0xc4, 0x2e, 0x03, 0xa0, 0x20,
+ 0x3f, 0x9f, 0xd2, 0xd2, 0x03, 0x26, 0xe5, 0x04, 0x41, 0xe8, 0x07, 0x6f, 0xac, 0x87, 0x4a, 0x9d,
+ 0xc9, 0x23, 0x0f, 0xcf, 0x13, 0xad, 0xf7, 0x56, 0x5e, 0x1e, 0xc3, 0xef, 0x18, 0x6e, 0xd4, 0x6f,
+ 0x49, 0xe1, 0xc7, 0x10, 0xbb, 0x0c, 0x80, 0xea, 0xea, 0xea, 0x9b, 0x7e, 0x4d, 0xf3, 0xf0, 0xf0,
+ 0x20, 0x2a, 0x3a, 0x9a, 0xdb, 0x86, 0xdc, 0x46, 0xd5, 0x67, 0x55, 0xa2, 0x4b, 0xd1, 0xb6, 0x66,
+ 0x6a, 0x50, 0x10, 0xa1, 0x61, 0x61, 0x1c, 0x29, 0x2f, 0x17, 0xa5, 0x57, 0x5f, 0x5f, 0xaf, 0xb7,
+ 0xb4, 0x04, 0xcb, 0x0b, 0x3f, 0x86, 0xd8, 0xe5, 0x1c, 0xe0, 0x99, 0xac, 0x2c, 0x6a, 0xbf, 0x3d,
+ 0x47, 0x4c, 0x6c, 0xac, 0xae, 0x2f, 0x6e, 0xd6, 0x2c, 0x0e, 0x68, 0xca, 0x58, 0xbf, 0xe1, 0x35,
+ 0x5e, 0xca, 0xce, 0xe6, 0xc3, 0x92, 0xbd, 0x24, 0xce, 0x13, 0xff, 0x34, 0xd9, 0x9a, 0xcc, 0x65,
+ 0x6a, 0xab, 0xd8, 0xb1, 0xb4, 0xf0, 0x63, 0x88, 0x5d, 0x06, 0xc0, 0xdd, 0xf7, 0x5c, 0x9d, 0xdc,
+ 0xd5, 0xd6, 0xd4, 0x20, 0x93, 0xc9, 0xc8, 0x50, 0xa9, 0xd8, 0xf8, 0xe6, 0x26, 0x14, 0x9e, 0x9e,
+ 0x1c, 0xd4, 0x68, 0x78, 0x79, 0xed, 0x5a, 0xae, 0x5c, 0xb9, 0xc2, 0x5f, 0x9e, 0x7e, 0xda, 0xc6,
+ 0x9e, 0x8a, 0x67, 0xd2, 0xe4, 0xc9, 0xbd, 0xfe, 0x1e, 0xd2, 0x9b, 0xc2, 0x8f, 0x21, 0x76, 0xf9,
+ 0x0a, 0xa8, 0xad, 0xa9, 0x61, 0x66, 0x5c, 0x1c, 0x1b, 0x73, 0xde, 0xa4, 0x53, 0xab, 0xc5, 0x3f,
+ 0x20, 0x00, 0xad, 0x56, 0x4b, 0xf6, 0x4b, 0x2f, 0xb1, 0x7d, 0xeb, 0x36, 0x00, 0x66, 0xc4, 0xc4,
+ 0x30, 0x61, 0xe2, 0x44, 0x9c, 0x9c, 0x9c, 0x6c, 0xec, 0xad, 0x78, 0x54, 0x6a, 0x75, 0xaf, 0x76,
+ 0x36, 0xa7, 0x2e, 0x4e, 0xb7, 0xda, 0x96, 0x34, 0xbb, 0xcc, 0x00, 0x9b, 0x73, 0xf3, 0xa8, 0xac,
+ 0xa8, 0x60, 0xec, 0xd8, 0xb1, 0xf8, 0x07, 0x04, 0xf0, 0x7d, 0x5d, 0x1d, 0x49, 0xf3, 0xe6, 0xeb,
+ 0x6e, 0xbe, 0xe7, 0x30, 0x4f, 0xc6, 0x8d, 0x1b, 0x47, 0xcd, 0xd7, 0x35, 0x74, 0x74, 0x74, 0xd8,
+ 0xd8, 0x5b, 0xf1, 0x4c, 0x9c, 0x34, 0x89, 0x88, 0x69, 0xd3, 0x2c, 0xd2, 0x55, 0x28, 0x14, 0x24,
+ 0x24, 0x24, 0x58, 0xcd, 0x17, 0x8b, 0x33, 0x80, 0x25, 0x25, 0x52, 0x73, 0x69, 0x69, 0x69, 0x21,
+ 0x69, 0xde, 0x7c, 0x7c, 0x7c, 0x7c, 0x70, 0x75, 0x73, 0xe3, 0xdc, 0x37, 0xdf, 0xd0, 0xd9, 0xf9,
+ 0x5b, 0x75, 0xad, 0xa5, 0xb9, 0x85, 0x88, 0xd0, 0x30, 0xae, 0xdc, 0x82, 0x37, 0xff, 0x3a, 0x2a,
+ 0x75, 0x26, 0x9f, 0x1e, 0x3a, 0x24, 0x5a, 0xaf, 0xb7, 0x85, 0x1f, 0x43, 0x2c, 0x0e, 0x80, 0x61,
+ 0x5e, 0xc3, 0x4c, 0x0b, 0x19, 0xf0, 0xeb, 0xaf, 0xbf, 0x9a, 0x25, 0xf7, 0xc7, 0xd9, 0x0f, 0xe2,
+ 0xef, 0x1f, 0xd0, 0xed, 0xf5, 0x96, 0xe6, 0x66, 0xaa, 0xaa, 0xaa, 0xa8, 0xac, 0xa8, 0x10, 0xed,
+ 0x83, 0xbd, 0x30, 0x61, 0xe2, 0x44, 0xa6, 0x47, 0x46, 0xf2, 0xc9, 0xc1, 0x83, 0x66, 0xeb, 0x38,
+ 0x3a, 0x3a, 0x92, 0x94, 0x2c, 0xbe, 0xa4, 0xdc, 0xa3, 0x4d, 0x4b, 0x15, 0xc7, 0x8c, 0xf9, 0xbd,
+ 0x68, 0x1d, 0xc3, 0x42, 0x46, 0x77, 0x44, 0x47, 0x3f, 0x40, 0xc2, 0xdc, 0x87, 0x4c, 0xca, 0xe5,
+ 0xe5, 0xe4, 0xb2, 0x2e, 0x3b, 0x5b, 0xb4, 0x1f, 0xf6, 0x82, 0x7a, 0xf9, 0x32, 0x0e, 0x7d, 0xf2,
+ 0x89, 0xd9, 0xf5, 0x8c, 0x39, 0xf1, 0xf1, 0x66, 0x9d, 0xae, 0x16, 0x83, 0xc5, 0x01, 0x10, 0x33,
+ 0x33, 0x96, 0xb5, 0x6b, 0xd6, 0x88, 0xd2, 0x29, 0x7e, 0xe7, 0x1d, 0x62, 0x66, 0xc6, 0xe2, 0xe7,
+ 0xe7, 0xd7, 0xa3, 0x5c, 0x5e, 0x6e, 0x2e, 0x1f, 0xbc, 0xbf, 0xbb, 0xdb, 0xeb, 0x1e, 0x0a, 0x05,
+ 0xea, 0x65, 0xcb, 0x49, 0x5f, 0x9c, 0xce, 0xeb, 0xaf, 0xbd, 0x26, 0xca, 0x07, 0x7b, 0x22, 0x60,
+ 0xfc, 0x78, 0x22, 0xa3, 0xa2, 0xd0, 0x94, 0x95, 0x99, 0x16, 0xc6, 0x7a, 0x4b, 0xbf, 0x1b, 0xb1,
+ 0x38, 0x00, 0xfc, 0xfc, 0xfc, 0x88, 0x9b, 0x35, 0x8b, 0x7d, 0x25, 0x25, 0x66, 0xeb, 0x9c, 0x3b,
+ 0x77, 0x8e, 0xb8, 0x19, 0x31, 0x78, 0x8f, 0xf0, 0xc6, 0xd5, 0xc5, 0x95, 0xfa, 0x86, 0x06, 0x94,
+ 0x09, 0x4a, 0xbd, 0x6d, 0xe1, 0x00, 0x0d, 0xf5, 0xf5, 0x46, 0x7b, 0xf1, 0x6f, 0x64, 0xc8, 0x85,
+ 0x5f, 0x68, 0x6e, 0x6e, 0xc6, 0x41, 0x2e, 0xc7, 0xb1, 0x9b, 0xd3, 0xc3, 0xb7, 0x0a, 0x2a, 0x75,
+ 0x26, 0x07, 0x35, 0x1a, 0x93, 0x59, 0xc0, 0x5a, 0x85, 0x1f, 0x43, 0x7a, 0xf5, 0xd7, 0x7b, 0x7e,
+ 0xe5, 0x0b, 0x9c, 0xfa, 0xf2, 0x4b, 0x7e, 0xf8, 0xe1, 0x07, 0xb3, 0x75, 0xba, 0xba, 0xba, 0x4c,
+ 0xbe, 0x0a, 0x9e, 0xc9, 0xca, 0x32, 0xeb, 0x15, 0xb0, 0xf7, 0xc3, 0xff, 0xd0, 0xda, 0xda, 0x6a,
+ 0xf6, 0xd8, 0xf6, 0x48, 0xc0, 0xf8, 0xf1, 0x44, 0x45, 0x47, 0x53, 0x56, 0x5a, 0xda, 0xa3, 0x5c,
+ 0x5f, 0x3c, 0xfd, 0xd0, 0xcb, 0x00, 0xf0, 0x1e, 0x31, 0x82, 0xe2, 0xdd, 0xbb, 0x58, 0x9e, 0xa9,
+ 0xa6, 0xfc, 0xb0, 0xf5, 0x4e, 0xec, 0xd6, 0xd4, 0x7c, 0xdd, 0xe3, 0x3a, 0xf9, 0xe2, 0xc5, 0x5f,
+ 0xf8, 0xec, 0xd8, 0x71, 0xde, 0x2b, 0x2e, 0xb6, 0xda, 0x98, 0xb6, 0x44, 0xa5, 0xce, 0x44, 0x53,
+ 0x56, 0xd6, 0x6d, 0x16, 0xb0, 0x66, 0xe1, 0xc7, 0x90, 0x5e, 0xe7, 0x4f, 0x6f, 0x6f, 0x6f, 0xf2,
+ 0x77, 0x16, 0x70, 0xac, 0xb2, 0x92, 0x3d, 0xff, 0xfa, 0x37, 0xe5, 0x87, 0x0f, 0x53, 0xf7, 0x7d,
+ 0x5d, 0x8f, 0x87, 0x2b, 0xe4, 0x72, 0x39, 0xc3, 0xef, 0xb8, 0x03, 0x1f, 0x1f, 0x1f, 0x46, 0x8f,
+ 0x1e, 0x63, 0x74, 0x3d, 0x2f, 0x27, 0x97, 0xbc, 0x9c, 0xdc, 0xde, 0xba, 0x76, 0xcb, 0xe0, 0x1f,
+ 0x10, 0x40, 0xf4, 0x8c, 0x07, 0x28, 0xfd, 0xf8, 0xe6, 0x1f, 0xc0, 0xac, 0x59, 0xf8, 0x31, 0xc4,
+ 0xe2, 0x7f, 0x11, 0xd3, 0x13, 0x9d, 0x5a, 0x2d, 0x3f, 0x5f, 0xb8, 0x40, 0x73, 0x73, 0x33, 0xda,
+ 0x6b, 0x6b, 0xf5, 0xa1, 0x2e, 0x2e, 0x38, 0x3b, 0x39, 0x31, 0xd4, 0xc5, 0x05, 0x4f, 0x4f, 0x4f,
+ 0xd1, 0x9b, 0x2d, 0x07, 0x3a, 0xff, 0x3d, 0x75, 0x8a, 0xf8, 0xd9, 0x7f, 0x32, 0xca, 0x02, 0x62,
+ 0x8f, 0x7a, 0x89, 0xa5, 0x4f, 0x66, 0x50, 0x72, 0x47, 0x47, 0x7c, 0x7d, 0x7d, 0xf1, 0xf5, 0xf5,
+ 0xed, 0x0b, 0xf3, 0x03, 0x92, 0xfb, 0xfc, 0xfd, 0x09, 0x09, 0x0d, 0x35, 0xfa, 0x52, 0xf8, 0x48,
+ 0x72, 0x72, 0x9f, 0xdd, 0x7c, 0xb0, 0xd3, 0x52, 0xf0, 0x60, 0xa4, 0xad, 0xad, 0x8d, 0xd3, 0xa7,
+ 0x4f, 0xeb, 0xf5, 0x39, 0x3a, 0x3a, 0x92, 0x2c, 0xf2, 0xa8, 0x97, 0x58, 0xa4, 0x00, 0xb0, 0x13,
+ 0x76, 0xbd, 0xf7, 0x9e, 0xd1, 0xf1, 0xb4, 0x39, 0xf1, 0xf1, 0xdc, 0xe9, 0x63, 0xdd, 0xc2, 0x8f,
+ 0x21, 0x52, 0x00, 0xd8, 0x01, 0x82, 0x20, 0xf0, 0xf6, 0x0e, 0xe3, 0xdd, 0xcd, 0x7d, 0xb5, 0xf4,
+ 0xbb, 0x11, 0x29, 0x00, 0xec, 0x80, 0xb2, 0x03, 0xa5, 0x9c, 0x3d, 0x7b, 0x56, 0xaf, 0x2f, 0x34,
+ 0x2c, 0xac, 0x4f, 0x0a, 0x3f, 0x86, 0x48, 0x01, 0x60, 0x07, 0x6c, 0xdd, 0xb2, 0xc5, 0xa8, 0x2f,
+ 0x35, 0x3d, 0xbd, 0x5f, 0xc6, 0x96, 0x02, 0xc0, 0xc6, 0x7c, 0x75, 0xe6, 0x2b, 0xa3, 0x9d, 0xc2,
+ 0x7e, 0x7e, 0x7e, 0x44, 0x45, 0x47, 0xf5, 0xcb, 0xf8, 0x52, 0x00, 0xd8, 0x98, 0x2d, 0x9b, 0x37,
+ 0x1b, 0xad, 0xfd, 0xfb, 0xb2, 0xf0, 0x63, 0x48, 0x9f, 0x14, 0x82, 0x24, 0xcc, 0xa3, 0xbe, 0xbe,
+ 0x9e, 0xe9, 0x61, 0xe1, 0x7a, 0xfb, 0x24, 0xfa, 0xba, 0xf0, 0x63, 0x88, 0x94, 0x01, 0x6c, 0xc8,
+ 0xdb, 0x3b, 0x76, 0x18, 0x6d, 0x92, 0x49, 0x4a, 0xb1, 0xee, 0x8e, 0x1f, 0x53, 0x48, 0x19, 0xc0,
+ 0x86, 0xb4, 0xb6, 0xb6, 0xa2, 0x35, 0x38, 0xdd, 0xe4, 0xea, 0xea, 0xda, 0xaf, 0x9f, 0xb8, 0xa5,
+ 0x00, 0x18, 0xe4, 0x38, 0x00, 0xb7, 0xd6, 0xf9, 0x2a, 0x09, 0xab, 0xe2, 0x00, 0xf4, 0xfe, 0xdf,
+ 0x63, 0x49, 0xdc, 0xaa, 0x34, 0x3a, 0x00, 0xe2, 0x0e, 0xaa, 0x49, 0x0c, 0x24, 0xca, 0x65, 0x82,
+ 0x20, 0x44, 0x03, 0x07, 0x90, 0xe6, 0x01, 0x83, 0x0d, 0x01, 0x88, 0x75, 0x90, 0xc9, 0x64, 0x65,
+ 0xc0, 0x8b, 0xb6, 0xf6, 0x46, 0xa2, 0xdf, 0xf9, 0x9b, 0x4c, 0x26, 0x3b, 0xa0, 0x7b, 0xea, 0x05,
+ 0x41, 0x98, 0x0b, 0xa8, 0x81, 0x89, 0xc0, 0x50, 0x9b, 0xb9, 0x25, 0xd1, 0x97, 0xb4, 0x03, 0x9f,
+ 0x03, 0xeb, 0x65, 0x32, 0xd9, 0x2e, 0x80, 0xff, 0x03, 0xff, 0x08, 0x81, 0xdd, 0xa8, 0xcb, 0xf5,
+ 0x99, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82,
+};
diff --git a/examples/device/mtp/src/tusb_config.h b/examples/device/mtp/src/tusb_config.h
new file mode 100644
index 000000000..4d166aa63
--- /dev/null
+++ b/examples/device/mtp/src/tusb_config.h
@@ -0,0 +1,139 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2025 Ennebi Elettronica (https://ennebielettronica.com)
+ *
+ * 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
+//--------------------------------------------------------------------+
+
+// RHPort number used for device can be defined by board.mk, default to port 0
+#ifndef BOARD_TUD_RHPORT
+#define BOARD_TUD_RHPORT 0
+#endif
+
+// RHPort max operational speed can defined by board.mk
+#ifndef BOARD_TUD_MAX_SPEED
+#define BOARD_TUD_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 Device stack
+#define CFG_TUD_ENABLED 1
+
+// Default is max speed that hardware controller could support with on-chip PHY
+#define CFG_TUD_MAX_SPEED BOARD_TUD_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_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_MTP 1
+#define CFG_TUD_MTP_EP_BUFSIZE 512
+#define CFG_TUD_MTP_EP_CONTROL_BUFSIZE 16 // should be enough to hold data in MTP control request
+
+//------------- MTP device info -------------//
+#define CFG_TUD_MTP_DEVICEINFO_EXTENSIONS "microsoft.com: 1.0; "
+#define CFG_TUD_MTP_DEVICEINFO_SUPPORTED_OPERATIONS \
+ MTP_OP_GET_DEVICE_INFO, \
+ MTP_OP_OPEN_SESSION, \
+ MTP_OP_CLOSE_SESSION, \
+ MTP_OP_GET_STORAGE_IDS, \
+ MTP_OP_GET_STORAGE_INFO, \
+ MTP_OP_GET_OBJECT_HANDLES, \
+ MTP_OP_GET_OBJECT_INFO, \
+ MTP_OP_GET_OBJECT, \
+ MTP_OP_DELETE_OBJECT, \
+ MTP_OP_SEND_OBJECT_INFO, \
+ MTP_OP_SEND_OBJECT, \
+ MTP_OP_RESET_DEVICE, \
+ MTP_OP_GET_DEVICE_PROP_DESC, \
+ MTP_OP_GET_DEVICE_PROP_VALUE, \
+ MTP_OP_SET_DEVICE_PROP_VALUE
+
+#define CFG_TUD_MTP_DEVICEINFO_SUPPORTED_EVENTS \
+ MTP_EVENT_OBJECT_ADDED
+
+#define CFG_TUD_MTP_DEVICEINFO_SUPPORTED_DEVICE_PROPERTIES \
+ MTP_DEV_PROP_DEVICE_FRIENDLY_NAME
+
+#define CFG_TUD_MTP_DEVICEINFO_CAPTURE_FORMATS \
+ MTP_OBJ_FORMAT_UNDEFINED, \
+ MTP_OBJ_FORMAT_ASSOCIATION, \
+ MTP_OBJ_FORMAT_TEXT, \
+ MTP_OBJ_FORMAT_PNG
+
+#define CFG_TUD_MTP_DEVICEINFO_PLAYBACK_FORMATS \
+ MTP_OBJ_FORMAT_UNDEFINED, \
+ MTP_OBJ_FORMAT_ASSOCIATION, \
+ MTP_OBJ_FORMAT_TEXT, \
+ MTP_OBJ_FORMAT_PNG
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _TUSB_CONFIG_H_ */
diff --git a/examples/device/mtp/src/usb_descriptors.c b/examples/device/mtp/src/usb_descriptors.c
new file mode 100644
index 000000000..80345d8f8
--- /dev/null
+++ b/examples/device/mtp/src/usb_descriptors.c
@@ -0,0 +1,255 @@
+/*
+ * 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 "bsp/board_api.h"
+#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] MTP | VENDOR | MIDI | 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) | _PID_MAP(MTP, 5))
+
+#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,
+ .bDeviceClass = TUSB_CLASS_UNSPECIFIED,
+ .bDeviceSubClass = 0x00,
+ .bDeviceProtocol = 0x00,
+ .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_MTP = 0,
+ 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_MTP_EVT 0x81
+ #define EPNUM_MTP_OUT 0x02
+ #define EPNUM_MTP_IN 0x82
+
+#elif CFG_TUSB_MCU == OPT_MCU_CXD56
+ // 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_MTP_EVT 0x83
+ #define EPNUM_MTP_OUT 0x02
+ #define EPNUM_MTP_IN 0x81
+
+#elif defined(TUD_ENDPOINT_ONE_DIRECTION_ONLY)
+ // MCUs that don't support a same endpoint number with different direction IN and OUT defined in tusb_mcu.h
+ // e.g EP1 OUT & EP1 IN cannot exist together
+ #define EPNUM_MTP_EVT 0x81
+ #define EPNUM_MTP_OUT 0x03
+ #define EPNUM_MTP_IN 0x82
+
+#else
+ #define EPNUM_MTP_EVT 0x81
+ #define EPNUM_MTP_OUT 0x02
+ #define EPNUM_MTP_IN 0x82
+#endif
+
+#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_MTP_DESC_LEN)
+
+// full speed configuration
+const uint8_t 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 event, EP event size, EP event polling, EP Out & EP In address, EP size
+ TUD_MTP_DESCRIPTOR(ITF_NUM_MTP, 4, EPNUM_MTP_EVT, 64, 1, EPNUM_MTP_OUT, EPNUM_MTP_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 event, EP event size, EP event polling, EP Out & EP In address, EP size
+ TUD_MTP_DESCRIPTOR(ITF_NUM_MTP, 4, EPNUM_MTP_EVT, 64, 1, EPNUM_MTP_OUT, EPNUM_MTP_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 OTHER_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
+const uint8_t*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
+//--------------------------------------------------------------------+
+
+// String Descriptor Index
+enum {
+ STRID_LANGID = 0,
+ STRID_MANUFACTURER,
+ STRID_PRODUCT,
+ STRID_SERIAL,
+ STRID_MTP,
+};
+
+// 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
+ NULL, // 3: Serials will use unique ID if possible
+ "TinyUSB MTP", // 4: MTP Interface
+};
+
+static uint16_t _desc_str[32 + 1];
+
+// 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;
+ size_t chr_count;
+
+ switch ( index ) {
+ case STRID_LANGID:
+ memcpy(&_desc_str[1], string_desc_arr[0], 2);
+ chr_count = 1;
+ break;
+
+ case STRID_SERIAL:
+ chr_count = board_usb_get_serial(_desc_str + 1, 32);
+ break;
+
+ default:
+ // 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 = strlen(str);
+ const size_t max_count = sizeof(_desc_str) / sizeof(_desc_str[0]) - 1; // -1 for string type
+ if ( chr_count > max_count ) {
+ chr_count = max_count;
+ }
+
+ // Convert ASCII string into UTF-16
+ for ( size_t i = 0; i < chr_count; i++ ) {
+ _desc_str[1 + i] = str[i];
+ }
+ break;
+ }
+
+ // first byte is length (including header), second byte is string type
+ _desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8) | (2 * chr_count + 2));
+
+ return _desc_str;
+}
diff --git a/examples/device/net_lwip_webserver/src/main.c b/examples/device/net_lwip_webserver/src/main.c
index 4bdddf6c5..dd9f213ae 100644
--- a/examples/device/net_lwip_webserver/src/main.c
+++ b/examples/device/net_lwip_webserver/src/main.c
@@ -250,9 +250,7 @@ int main(void) {
};
tusb_init(BOARD_TUD_RHPORT, &dev_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
/* initialize lwip, dhcp-server, dns-server, and http */
init_lwip();
diff --git a/examples/device/uac2_headset/src/main.c b/examples/device/uac2_headset/src/main.c
index d4c2b41d9..102a6eef1 100644
--- a/examples/device/uac2_headset/src/main.c
+++ b/examples/device/uac2_headset/src/main.c
@@ -102,9 +102,7 @@ int main(void) {
.speed = TUSB_SPEED_AUTO};
tusb_init(BOARD_TUD_RHPORT, &dev_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
TU_LOG1("Headset running\r\n");
diff --git a/examples/device/uac2_headset/src/tusb_config.h b/examples/device/uac2_headset/src/tusb_config.h
index e738a09af..e9165163b 100644
--- a/examples/device/uac2_headset/src/tusb_config.h
+++ b/examples/device/uac2_headset/src/tusb_config.h
@@ -158,9 +158,6 @@ extern "C" {
#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX TU_MAX(CFG_TUD_AUDIO_FUNC_1_FORMAT_1_EP_SZ_OUT, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_EP_SZ_OUT) // Maximum EP IN size for all AS alternate settings used
#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ (TUD_OPT_HIGH_SPEED ? 32 : 4) * CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX // Example read FIFO every 1ms, so it should be 8 times larger for HS device
-// Number of Standard AS Interface Descriptors (4.9.1) defined per audio function - this is required to be able to remember the current alternate settings of these interfaces - We restrict us here to have a constant number for all audio functions (which means this has to be the maximum number of AS interfaces an audio function has and a second audio function with less AS interfaces just wastes a few bytes)
-#define CFG_TUD_AUDIO_FUNC_1_N_AS_INT 2
-
// Size of control request buffer
#define CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ 64
diff --git a/examples/device/uac2_speaker_fb/src/main.c b/examples/device/uac2_speaker_fb/src/main.c
index d9f6e9259..ed9e7716d 100644
--- a/examples/device/uac2_speaker_fb/src/main.c
+++ b/examples/device/uac2_speaker_fb/src/main.c
@@ -108,9 +108,7 @@ int main(void) {
.speed = TUSB_SPEED_AUTO};
tusb_init(BOARD_TUD_RHPORT, &dev_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
TU_LOG1("Speaker running\r\n");
diff --git a/examples/device/uac2_speaker_fb/src/quirk_os_guessing.c b/examples/device/uac2_speaker_fb/src/quirk_os_guessing.c
index 965bbd6cf..92b9ab6ee 100644
--- a/examples/device/uac2_speaker_fb/src/quirk_os_guessing.c
+++ b/examples/device/uac2_speaker_fb/src/quirk_os_guessing.c
@@ -29,12 +29,12 @@ static tusb_desc_type_t desc_req_buf[2];
static int desc_req_idx = 0;
// Place at the start of tud_descriptor_device_cb()
-void quirk_os_guessing_desc_device_cb() {
+void quirk_os_guessing_desc_device_cb(void) {
desc_req_idx = 0;
}
// Place at the start of tud_descriptor_configuration_cb()
-void quirk_os_guessing_desc_configuration_cb() {
+void quirk_os_guessing_desc_configuration_cb(void) {
// Skip redundant request
if (desc_req_idx == 0 || (desc_req_idx == 1 && desc_req_buf[0] != TUSB_DESC_CONFIGURATION)) {
desc_req_buf[desc_req_idx++] = TUSB_DESC_CONFIGURATION;
@@ -42,7 +42,7 @@ void quirk_os_guessing_desc_configuration_cb() {
}
// Place at the start of tud_descriptor_bos_cb()
-void quirk_os_guessing_desc_bos_cb() {
+void quirk_os_guessing_desc_bos_cb(void) {
// Skip redundant request
if (desc_req_idx == 0 || (desc_req_idx == 1 && desc_req_buf[0] != TUSB_DESC_BOS)) {
desc_req_buf[desc_req_idx++] = TUSB_DESC_BOS;
@@ -50,7 +50,7 @@ void quirk_os_guessing_desc_bos_cb() {
}
// Place at the start of tud_descriptor_string_cb()
-void quirk_os_guessing_desc_string_cb() {
+void quirk_os_guessing_desc_string_cb(void) {
// Skip redundant request
if (desc_req_idx == 0 || (desc_req_idx == 1 && desc_req_buf[0] != TUSB_DESC_STRING)) {
desc_req_buf[desc_req_idx++] = TUSB_DESC_STRING;
diff --git a/examples/device/uac2_speaker_fb/src/tusb_config.h b/examples/device/uac2_speaker_fb/src/tusb_config.h
index fd4925c7f..18ab2ff96 100644
--- a/examples/device/uac2_speaker_fb/src/tusb_config.h
+++ b/examples/device/uac2_speaker_fb/src/tusb_config.h
@@ -130,7 +130,7 @@ extern "C" {
#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN TUD_AUDIO_SPEAKER_STEREO_FB_DESC_LEN
-// Enable if Full-Speed on OSX, also set feedback EP size to 3
+// Can be enabled with Full-Speed device on OSX, which forces feedback EP size to 3, in this case CFG_QUIRK_OS_GUESSING can be disabled
#define CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION 0
// Audio format type I specifications
@@ -155,9 +155,6 @@ extern "C" {
// Enable feedback EP
#define CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP 1
-// Number of Standard AS Interface Descriptors (4.9.1) defined per audio function - this is required to be able to remember the current alternate settings of these interfaces - We restrict us here to have a constant number for all audio functions (which means this has to be the maximum number of AS interfaces an audio function has and a second audio function with less AS interfaces just wastes a few bytes)
-#define CFG_TUD_AUDIO_FUNC_1_N_AS_INT 1
-
// Size of control request buffer
#define CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ 64
diff --git a/examples/device/usbtmc/src/main.c b/examples/device/usbtmc/src/main.c
index aa7902a15..f78cce91f 100644
--- a/examples/device/usbtmc/src/main.c
+++ b/examples/device/usbtmc/src/main.c
@@ -61,9 +61,7 @@ int main(void)
};
tusb_init(BOARD_TUD_RHPORT, &dev_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
while (1)
{
diff --git a/examples/device/usbtmc/src/usbtmc_app.c b/examples/device/usbtmc/src/usbtmc_app.c
index fb25982c7..e738f1008 100644
--- a/examples/device/usbtmc/src/usbtmc_app.c
+++ b/examples/device/usbtmc/src/usbtmc_app.c
@@ -99,7 +99,7 @@ usbtmc_response_capabilities_488_t const *
#else
usbtmc_response_capabilities_t const *
#endif
-tud_usbtmc_get_capabilities_cb()
+tud_usbtmc_get_capabilities_cb(void)
{
return &tud_usbtmc_app_capabilities;
}
@@ -161,7 +161,7 @@ bool tud_usbtmc_msg_data_cb(void *data, size_t len, bool transfer_complete)
return true;
}
-bool tud_usbtmc_msgBulkIn_complete_cb()
+bool tud_usbtmc_msgBulkIn_complete_cb(void)
{
if((buffer_tx_ix == buffer_len) || idnQuery) // done
{
diff --git a/examples/device/video_capture/src/main.c b/examples/device/video_capture/src/main.c
index 0406279fd..29656e944 100644
--- a/examples/device/video_capture/src/main.c
+++ b/examples/device/video_capture/src/main.c
@@ -74,9 +74,7 @@ int main(void) {
};
tusb_init(BOARD_TUD_RHPORT, &dev_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
while (1) {
tud_task(); // tinyusb device task
@@ -329,9 +327,7 @@ void usb_device_task(void *param) {
};
tusb_init(BOARD_TUD_RHPORT, &dev_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
// RTOS forever loop
while (1) {
diff --git a/examples/device/video_capture_2ch/src/main.c b/examples/device/video_capture_2ch/src/main.c
index dc616e3fa..f56738f67 100644
--- a/examples/device/video_capture_2ch/src/main.c
+++ b/examples/device/video_capture_2ch/src/main.c
@@ -74,9 +74,7 @@ int main(void) {
};
tusb_init(BOARD_TUD_RHPORT, &dev_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
while (1) {
tud_task(); // tinyusb device task
@@ -337,9 +335,7 @@ void usb_device_task(void *param) {
};
tusb_init(BOARD_TUD_RHPORT, &dev_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
// RTOS forever loop
while (1) {
diff --git a/examples/device/webusb_serial/src/main.c b/examples/device/webusb_serial/src/main.c
index d189af91f..4a724f45e 100644
--- a/examples/device/webusb_serial/src/main.c
+++ b/examples/device/webusb_serial/src/main.c
@@ -97,9 +97,7 @@ int main(void) {
};
tusb_init(BOARD_TUD_RHPORT, &dev_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
while (1) {
tud_task(); // tinyusb device task