summaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorhathach <[email protected]>2021-09-18 13:35:26 +0700
committerhathach <[email protected]>2021-09-18 13:35:26 +0700
commit3333703d257b4b2a37f543a65ea4a6e2db777fdb (patch)
treefb37112e82f7f64857473d8346f32c763bd67ec9 /examples
parent82618d2d5f15d0f8dd9631dec3807964a1281782 (diff)
parent90465299b42facff3c815d97950066706dbbd74a (diff)
Merge branch 'master' into zhangslice-master
Diffstat (limited to 'examples')
-rw-r--r--examples/device/audio_4_channel_mic/src/usb_descriptors.c2
-rw-r--r--examples/device/audio_test/src/usb_descriptors.c2
-rw-r--r--examples/device/cdc_dual_ports/src/tusb_config.h2
-rw-r--r--examples/device/cdc_dual_ports/src/usb_descriptors.c84
-rw-r--r--examples/device/cdc_msc/src/msc_disk.c19
-rw-r--r--examples/device/cdc_msc/src/tusb_config.h2
-rw-r--r--examples/device/cdc_msc/src/usb_descriptors.c100
-rw-r--r--examples/device/cdc_msc_freertos/.skip.MCU_GD32VF103 (renamed from examples/device/dfu/.skip.MCU_SAMD11)0
-rw-r--r--examples/device/cdc_msc_freertos/.skip.MCU_SAMX7X0
-rw-r--r--examples/device/cdc_msc_freertos/src/FreeRTOSConfig.h9
-rw-r--r--examples/device/cdc_msc_freertos/src/freertos_hook.c2
-rw-r--r--examples/device/cdc_msc_freertos/src/msc_disk.c8
-rw-r--r--examples/device/cdc_msc_freertos/src/usb_descriptors.c67
-rw-r--r--examples/device/dfu/src/main.c110
-rw-r--r--examples/device/dfu/src/tusb_config.h7
-rw-r--r--examples/device/dfu/src/usb_descriptors.c16
-rw-r--r--examples/device/dfu_runtime/src/usb_descriptors.c2
-rw-r--r--examples/device/dynamic_configuration/src/msc_disk.c8
-rw-r--r--examples/device/dynamic_configuration/src/usb_descriptors.c4
-rw-r--r--examples/device/hid_boot_interface/CMakeLists.txt28
-rw-r--r--examples/device/hid_boot_interface/Makefile15
-rw-r--r--examples/device/hid_boot_interface/src/main.c255
-rw-r--r--examples/device/hid_boot_interface/src/tusb_config.h111
-rw-r--r--examples/device/hid_boot_interface/src/usb_descriptors.c180
-rw-r--r--examples/device/hid_boot_interface/src/usb_descriptors.h35
-rw-r--r--examples/device/hid_composite/src/main.c44
-rw-r--r--examples/device/hid_composite/src/tusb_config.h2
-rw-r--r--examples/device/hid_composite/src/usb_descriptors.c61
-rw-r--r--examples/device/hid_composite_freertos/.skip.MCU_GD32VF1030
-rw-r--r--examples/device/hid_composite_freertos/.skip.MCU_SAMX7X0
-rw-r--r--examples/device/hid_composite_freertos/src/FreeRTOSConfig.h9
-rw-r--r--examples/device/hid_composite_freertos/src/freertos_hook.c2
-rw-r--r--examples/device/hid_composite_freertos/src/main.c41
-rw-r--r--examples/device/hid_composite_freertos/src/tusb_config.h5
-rw-r--r--examples/device/hid_composite_freertos/src/usb_descriptors.c59
-rw-r--r--examples/device/hid_generic_inout/boards.js6
-rw-r--r--examples/device/hid_generic_inout/hid_test.js11
-rw-r--r--examples/device/hid_generic_inout/hid_test.py5
-rw-r--r--examples/device/hid_generic_inout/src/main.c26
-rw-r--r--examples/device/hid_generic_inout/src/usb_descriptors.c2
-rw-r--r--examples/device/midi_test/src/main.c2
-rw-r--r--examples/device/midi_test/src/usb_descriptors.c4
-rw-r--r--examples/device/msc_dual_lun/src/msc_disk_dual.c19
-rw-r--r--examples/device/msc_dual_lun/src/usb_descriptors.c4
-rw-r--r--examples/device/net_lwip_webserver/src/main.c13
-rw-r--r--examples/device/net_lwip_webserver/src/usb_descriptors.c4
-rw-r--r--examples/device/uac2_headset/.skip.MCU_LPC11UXX0
-rw-r--r--examples/device/uac2_headset/.skip.MCU_LPC13XX0
-rw-r--r--examples/device/uac2_headset/.skip.MCU_NUC1210
-rw-r--r--examples/device/uac2_headset/src/main.c153
-rw-r--r--examples/device/uac2_headset/src/tusb_config.h60
-rw-r--r--examples/device/uac2_headset/src/usb_descriptors.c18
-rw-r--r--examples/device/uac2_headset/src/usb_descriptors.h59
-rw-r--r--examples/device/usbtmc/src/usb_descriptors.c2
-rw-r--r--examples/device/webusb_serial/src/main.c2
-rw-r--r--examples/device/webusb_serial/src/usb_descriptors.c25
-rw-r--r--examples/host/cdc_msc_hid/src/hid_app.c171
-rw-r--r--examples/host/cdc_msc_hid/src/main.c29
-rw-r--r--examples/host/cdc_msc_hid/src/msc_app.c2
-rw-r--r--examples/host/cdc_msc_hid/src/tusb_config.h11
-rw-r--r--examples/host/hid_controller/.only.MCU_LPC175X_6X0
-rw-r--r--examples/host/hid_controller/.only.MCU_LPC177X_8X0
-rw-r--r--examples/host/hid_controller/.only.MCU_LPC18XX0
-rw-r--r--examples/host/hid_controller/.only.MCU_LPC40XX0
-rw-r--r--examples/host/hid_controller/.only.MCU_LPC43XX0
-rw-r--r--examples/host/hid_controller/.only.MCU_MIMXRT10XX0
-rw-r--r--examples/host/hid_controller/.only.MCU_RP20400
-rw-r--r--examples/host/hid_controller/CMakeLists.txt28
-rw-r--r--examples/host/hid_controller/Makefile30
-rw-r--r--examples/host/hid_controller/src/hid_app.c253
-rw-r--r--examples/host/hid_controller/src/main.c94
-rw-r--r--examples/host/hid_controller/src/tusb_config.h95
-rw-r--r--examples/make.mk2
-rw-r--r--examples/rules.mk3
74 files changed, 2054 insertions, 370 deletions
diff --git a/examples/device/audio_4_channel_mic/src/usb_descriptors.c b/examples/device/audio_4_channel_mic/src/usb_descriptors.c
index 93ec6e9f7..018919bf3 100644
--- a/examples/device/audio_4_channel_mic/src/usb_descriptors.c
+++ b/examples/device/audio_4_channel_mic/src/usb_descriptors.c
@@ -92,7 +92,7 @@ enum
uint8_t const desc_configuration[] =
{
// Interface count, string index, total length, attribute, power in mA
- TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
+ TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
// Interface number, string index, EP Out & EP In address, EP size
TUD_AUDIO_MIC_FOUR_CH_DESCRIPTOR(/*_itfnum*/ ITF_NUM_AUDIO_CONTROL, /*_stridx*/ 0, /*_nBytesPerSample*/ CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX, /*_nBitsUsedPerSample*/ CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX*8, /*_epin*/ 0x80 | EPNUM_AUDIO, /*_epsize*/ CFG_TUD_AUDIO_EP_SZ_IN)
diff --git a/examples/device/audio_test/src/usb_descriptors.c b/examples/device/audio_test/src/usb_descriptors.c
index 67dd34d2a..a4e9dc8e1 100644
--- a/examples/device/audio_test/src/usb_descriptors.c
+++ b/examples/device/audio_test/src/usb_descriptors.c
@@ -92,7 +92,7 @@ enum
uint8_t const desc_configuration[] =
{
// Interface count, string index, total length, attribute, power in mA
- TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
+ TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
// Interface number, string index, EP Out & EP In address, EP size
TUD_AUDIO_MIC_ONE_CH_DESCRIPTOR(/*_itfnum*/ ITF_NUM_AUDIO_CONTROL, /*_stridx*/ 0, /*_nBytesPerSample*/ CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX, /*_nBitsUsedPerSample*/ CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX*8, /*_epin*/ 0x80 | EPNUM_AUDIO, /*_epsize*/ CFG_TUD_AUDIO_EP_SZ_IN)
diff --git a/examples/device/cdc_dual_ports/src/tusb_config.h b/examples/device/cdc_dual_ports/src/tusb_config.h
index c7e87bf67..ff8535d1a 100644
--- a/examples/device/cdc_dual_ports/src/tusb_config.h
+++ b/examples/device/cdc_dual_ports/src/tusb_config.h
@@ -48,7 +48,7 @@
// Default to Highspeed for MCU with internal HighSpeed PHY (can be port specific), otherwise FullSpeed
#ifndef BOARD_DEVICE_RHPORT_SPEED
#if (CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX || \
- CFG_TUSB_MCU == OPT_MCU_NUC505 || CFG_TUSB_MCU == OPT_MCU_CXD56)
+ CFG_TUSB_MCU == OPT_MCU_NUC505 || CFG_TUSB_MCU == OPT_MCU_CXD56 || CFG_TUSB_MCU == OPT_MCU_SAMX7X)
#define BOARD_DEVICE_RHPORT_SPEED OPT_MODE_HIGH_SPEED
#else
#define BOARD_DEVICE_RHPORT_SPEED OPT_MODE_FULL_SPEED
diff --git a/examples/device/cdc_dual_ports/src/usb_descriptors.c b/examples/device/cdc_dual_ports/src/usb_descriptors.c
index 8e19678e5..aa400d486 100644
--- a/examples/device/cdc_dual_ports/src/usb_descriptors.c
+++ b/examples/device/cdc_dual_ports/src/usb_descriptors.c
@@ -35,6 +35,9 @@
#define USB_PID (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \
_PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4) )
+#define USB_VID 0xCafe
+#define USB_BCD 0x0200
+
//--------------------------------------------------------------------+
// Device Descriptors
//--------------------------------------------------------------------+
@@ -42,7 +45,7 @@ tusb_desc_device_t const desc_device =
{
.bLength = sizeof(tusb_desc_device_t),
.bDescriptorType = TUSB_DESC_DEVICE,
- .bcdUSB = 0x0200,
+ .bcdUSB = USB_BCD,
// Use Interface Association Descriptor (IAD) for CDC
// As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1)
@@ -51,7 +54,7 @@ tusb_desc_device_t const desc_device =
.bDeviceProtocol = MISC_PROTOCOL_IAD,
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
- .idVendor = 0xCafe,
+ .idVendor = USB_VID,
.idProduct = USB_PID,
.bcdDevice = 0x0100,
@@ -87,43 +90,98 @@ enum
// LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number
// 0 control, 1 In, 2 Bulk, 3 Iso, 4 In etc ...
#define EPNUM_CDC_0_NOTIF 0x81
- #define EPNUM_CDC_0_DATA 0x02
+ #define EPNUM_CDC_0_OUT 0x02
+ #define EPNUM_CDC_0_IN 0x82
+
+ #define EPNUM_CDC_1_NOTIF 0x84
+ #define EPNUM_CDC_1_OUT 0x05
+ #define EPNUM_CDC_1_IN 0x85
+
+#elif CFG_TUSB_MCU == OPT_MCU_SAMG || CFG_TUSB_MCU == OPT_MCU_SAMX7X
+ // SAMG & SAME70 don't support a same endpoint number with different direction IN and OUT
+ // e.g EP1 OUT & EP1 IN cannot exist together
+ #define EPNUM_CDC_0_NOTIF 0x81
+ #define EPNUM_CDC_0_OUT 0x02
+ #define EPNUM_CDC_0_IN 0x83
#define EPNUM_CDC_1_NOTIF 0x84
- #define EPNUM_CDC_1_DATA 0x05
+ #define EPNUM_CDC_1_OUT 0x05
+ #define EPNUM_CDC_1_IN 0x86
+
#else
#define EPNUM_CDC_0_NOTIF 0x81
- #define EPNUM_CDC_0_DATA 0x02
+ #define EPNUM_CDC_0_OUT 0x02
+ #define EPNUM_CDC_0_IN 0x82
#define EPNUM_CDC_1_NOTIF 0x83
- #define EPNUM_CDC_1_DATA 0x04
+ #define EPNUM_CDC_1_OUT 0x04
+ #define EPNUM_CDC_1_IN 0x84
#endif
uint8_t const desc_fs_configuration[] =
{
// Config number, interface count, string index, total length, attribute, power in mA
- TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
+ TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
// 1st CDC: Interface number, string index, EP notification address and size, EP data address (out, in) and size.
- TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_0, 4, EPNUM_CDC_0_NOTIF, 8, EPNUM_CDC_0_DATA, 0x80 | EPNUM_CDC_0_DATA, 64),
+ TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_0, 4, EPNUM_CDC_0_NOTIF, 8, EPNUM_CDC_0_OUT, EPNUM_CDC_0_IN, 64),
// 2nd CDC: Interface number, string index, EP notification address and size, EP data address (out, in) and size.
- TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_1, 4, EPNUM_CDC_1_NOTIF, 8, EPNUM_CDC_1_DATA, 0x80 | EPNUM_CDC_1_DATA, 64),
+ TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_1, 4, EPNUM_CDC_1_NOTIF, 8, EPNUM_CDC_1_OUT, EPNUM_CDC_1_IN, 64),
};
#if TUD_OPT_HIGH_SPEED
+// Per USB specs: high speed capable device must report device_qualifier and other_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, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
+ TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
// 1st CDC: Interface number, string index, EP notification address and size, EP data address (out, in) and size.
- TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_0, 4, EPNUM_CDC_0_NOTIF, 8, EPNUM_CDC_0_DATA, 0x80 | EPNUM_CDC_0_DATA, 512),
+ TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_0, 4, EPNUM_CDC_0_NOTIF, 8, EPNUM_CDC_0_OUT, EPNUM_CDC_0_IN, 512),
// 2nd CDC: Interface number, string index, EP notification address and size, EP data address (out, in) and size.
- TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_1, 4, EPNUM_CDC_1_NOTIF, 8, EPNUM_CDC_1_DATA, 0x80 | EPNUM_CDC_1_DATA, 512),
+ TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_1, 4, EPNUM_CDC_1_NOTIF, 8, EPNUM_CDC_1_OUT, EPNUM_CDC_1_IN, 512),
};
-#endif
+
+// 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_t),
+ .bDescriptorType = TUSB_DESC_DEVICE,
+ .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
+ return (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_fs_configuration : desc_hs_configuration;
+}
+
+#endif // highspeed
// Invoked when received GET CONFIGURATION DESCRIPTOR
// Application return pointer to descriptor
diff --git a/examples/device/cdc_msc/src/msc_disk.c b/examples/device/cdc_msc/src/msc_disk.c
index 503baace9..cad2602a2 100644
--- a/examples/device/cdc_msc/src/msc_disk.c
+++ b/examples/device/cdc_msc/src/msc_disk.c
@@ -188,18 +188,35 @@ int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buff
{
(void) lun;
+ // out of ramdisk
+ if ( lba >= DISK_BLOCK_NUM ) return -1;
+
uint8_t const* addr = msc_disk[lba] + offset;
memcpy(buffer, addr, bufsize);
return bufsize;
}
+bool tud_msc_is_writable_cb (uint8_t lun)
+{
+ (void) lun;
+
+#ifdef CFG_EXAMPLE_MSC_READONLY
+ return false;
+#else
+ return true;
+#endif
+}
+
// Callback invoked when received WRITE10 command.
// Process data in buffer to disk's storage and return number of written bytes
int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize)
{
(void) lun;
+ // out of ramdisk
+ if ( lba >= DISK_BLOCK_NUM ) return -1;
+
#ifndef CFG_EXAMPLE_MSC_READONLY
uint8_t* addr = msc_disk[lba] + offset;
memcpy(addr, buffer, bufsize);
@@ -218,7 +235,7 @@ int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer,
// read10 & write10 has their own callback and MUST not be handled here
void const* response = NULL;
- uint16_t resplen = 0;
+ int32_t resplen = 0;
// most scsi handled is input
bool in_xfer = true;
diff --git a/examples/device/cdc_msc/src/tusb_config.h b/examples/device/cdc_msc/src/tusb_config.h
index 9a0262d30..bf6af06bc 100644
--- a/examples/device/cdc_msc/src/tusb_config.h
+++ b/examples/device/cdc_msc/src/tusb_config.h
@@ -48,7 +48,7 @@
// Default to Highspeed for MCU with internal HighSpeed PHY (can be port specific), otherwise FullSpeed
#ifndef BOARD_DEVICE_RHPORT_SPEED
#if (CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX || \
- CFG_TUSB_MCU == OPT_MCU_NUC505 || CFG_TUSB_MCU == OPT_MCU_CXD56)
+ CFG_TUSB_MCU == OPT_MCU_NUC505 || CFG_TUSB_MCU == OPT_MCU_CXD56 || CFG_TUSB_MCU == OPT_MCU_SAMX7X)
#define BOARD_DEVICE_RHPORT_SPEED OPT_MODE_HIGH_SPEED
#else
#define BOARD_DEVICE_RHPORT_SPEED OPT_MODE_FULL_SPEED
diff --git a/examples/device/cdc_msc/src/usb_descriptors.c b/examples/device/cdc_msc/src/usb_descriptors.c
index fa4342165..34537b8f0 100644
--- a/examples/device/cdc_msc/src/usb_descriptors.c
+++ b/examples/device/cdc_msc/src/usb_descriptors.c
@@ -35,32 +35,35 @@
#define USB_PID (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \
_PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4) )
+#define USB_VID 0xCafe
+#define USB_BCD 0x0200
+
//--------------------------------------------------------------------+
// Device Descriptors
//--------------------------------------------------------------------+
tusb_desc_device_t const desc_device =
{
- .bLength = sizeof(tusb_desc_device_t),
- .bDescriptorType = TUSB_DESC_DEVICE,
- .bcdUSB = 0x0200,
+ .bLength = sizeof(tusb_desc_device_t),
+ .bDescriptorType = TUSB_DESC_DEVICE,
+ .bcdUSB = USB_BCD,
- // Use Interface Association Descriptor (IAD) for CDC
- // As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1)
- .bDeviceClass = TUSB_CLASS_MISC,
- .bDeviceSubClass = MISC_SUBCLASS_COMMON,
- .bDeviceProtocol = MISC_PROTOCOL_IAD,
+ // Use Interface Association Descriptor (IAD) for CDC
+ // As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1)
+ .bDeviceClass = TUSB_CLASS_MISC,
+ .bDeviceSubClass = MISC_SUBCLASS_COMMON,
+ .bDeviceProtocol = MISC_PROTOCOL_IAD,
- .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
+ .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
- .idVendor = 0xCafe,
- .idProduct = USB_PID,
- .bcdDevice = 0x0100,
+ .idVendor = USB_VID,
+ .idProduct = USB_PID,
+ .bcdDevice = 0x0100,
- .iManufacturer = 0x01,
- .iProduct = 0x02,
- .iSerialNumber = 0x03,
+ .iManufacturer = 0x01,
+ .iProduct = 0x02,
+ .iSerialNumber = 0x03,
- .bNumConfigurations = 0x01
+ .bNumConfigurations = 0x01
};
// Invoked when received GET DEVICE DESCRIPTOR
@@ -82,8 +85,6 @@ enum
ITF_NUM_TOTAL
};
-#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN + TUD_MSC_DESC_LEN)
-
#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 ...
@@ -94,8 +95,8 @@ enum
#define EPNUM_MSC_OUT 0x05
#define EPNUM_MSC_IN 0x85
-#elif CFG_TUSB_MCU == OPT_MCU_SAMG
- // SAMG doesn't support a same endpoint number with different direction IN and OUT
+#elif CFG_TUSB_MCU == OPT_MCU_SAMG || CFG_TUSB_MCU == OPT_MCU_SAMX7X
+ // SAMG & SAME70 don't support a same endpoint number with different direction IN and OUT
// e.g EP1 OUT & EP1 IN cannot exist together
#define EPNUM_CDC_NOTIF 0x81
#define EPNUM_CDC_OUT 0x02
@@ -126,10 +127,13 @@ enum
#endif
+#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN + TUD_MSC_DESC_LEN)
+
+// full speed configuration
uint8_t const desc_fs_configuration[] =
{
// Config number, interface count, string index, total length, attribute, power in mA
- TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
+ TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
// Interface number, string index, EP notification address and size, EP data address (out, in) and size.
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT, EPNUM_CDC_IN, 64),
@@ -139,10 +143,13 @@ uint8_t const desc_fs_configuration[] =
};
#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, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
+ TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
// Interface number, string index, EP notification address and size, EP data address (out, in) and size.
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT, EPNUM_CDC_IN, 512),
@@ -150,7 +157,54 @@ uint8_t const desc_hs_configuration[] =
// Interface number, string index, EP Out & EP In address, EP size
TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 5, EPNUM_MSC_OUT, EPNUM_MSC_IN, 512),
};
-#endif
+
+// other speed configuration
+uint8_t desc_other_speed_config[CONFIG_TOTAL_LEN];
+
+// device qualifier is mostly similar to device descriptor since we don't change configuration based on speed
+tusb_desc_device_qualifier_t const desc_device_qualifier =
+{
+ .bLength = sizeof(tusb_desc_device_qualifier_t),
+ .bDescriptorType = TUSB_DESC_DEVICE_QUALIFIER,
+ .bcdUSB = USB_BCD,
+
+ .bDeviceClass = TUSB_CLASS_MISC,
+ .bDeviceSubClass = MISC_SUBCLASS_COMMON,
+ .bDeviceProtocol = MISC_PROTOCOL_IAD,
+
+ .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
+ .bNumConfigurations = 0x01,
+ .bReserved = 0x00
+};
+
+// Invoked when received GET DEVICE QUALIFIER DESCRIPTOR request
+// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete.
+// device_qualifier descriptor describes information about a high-speed capable device that would
+// change if the device were operating at the other speed. If not highspeed capable stall this request.
+uint8_t const* tud_descriptor_device_qualifier_cb(void)
+{
+ return (uint8_t const*) &desc_device_qualifier;
+}
+
+// Invoked when received GET OTHER SEED CONFIGURATION DESCRIPTOR request
+// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
+// Configuration descriptor in the other speed e.g if high speed then this is for full speed and vice versa
+uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index)
+{
+ (void) index; // for multiple configurations
+
+ // if link speed is high return fullspeed config, and vice versa
+ // Note: the descriptor type is OHER_SPEED_CONFIG instead of CONFIG
+ memcpy(desc_other_speed_config,
+ (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_fs_configuration : desc_hs_configuration,
+ CONFIG_TOTAL_LEN);
+
+ desc_other_speed_config[1] = TUSB_DESC_OTHER_SPEED_CONFIG;
+
+ return desc_other_speed_config;
+}
+
+#endif // highspeed
// Invoked when received GET CONFIGURATION DESCRIPTOR
diff --git a/examples/device/dfu/.skip.MCU_SAMD11 b/examples/device/cdc_msc_freertos/.skip.MCU_GD32VF103
index e69de29bb..e69de29bb 100644
--- a/examples/device/dfu/.skip.MCU_SAMD11
+++ b/examples/device/cdc_msc_freertos/.skip.MCU_GD32VF103
diff --git a/examples/device/cdc_msc_freertos/.skip.MCU_SAMX7X b/examples/device/cdc_msc_freertos/.skip.MCU_SAMX7X
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/examples/device/cdc_msc_freertos/.skip.MCU_SAMX7X
diff --git a/examples/device/cdc_msc_freertos/src/FreeRTOSConfig.h b/examples/device/cdc_msc_freertos/src/FreeRTOSConfig.h
index c9f553f64..4cff6e4c7 100644
--- a/examples/device/cdc_msc_freertos/src/FreeRTOSConfig.h
+++ b/examples/device/cdc_msc_freertos/src/FreeRTOSConfig.h
@@ -155,11 +155,14 @@ extern uint32_t SystemCoreClock;
//--------------------------------------------------------------------+
// Interrupt nesting behavior configuration.
//--------------------------------------------------------------------+
-/* Cortex-M specific definitions. __NVIC_PRIO_BITS is defined in core_cmx.h */
-#ifdef __NVIC_PRIO_BITS
+#if defined(__NVIC_PRIO_BITS)
+ // For Cortex-M specific: __NVIC_PRIO_BITS is defined in core_cmx.h
#define configPRIO_BITS __NVIC_PRIO_BITS
+#elif defined(__ECLIC_INTCTLBITS)
+ // RISC-V Bumblebee core from nuclei
+ #define configPRIO_BITS __ECLIC_INTCTLBITS
#else
- #error "This port requires __NVIC_PRIO_BITS to be defined"
+ #error "FreeRTOS configPRIO_BITS to be defined"
#endif
/* The lowest interrupt priority that can be used in a call to a "set priority" function. */
diff --git a/examples/device/cdc_msc_freertos/src/freertos_hook.c b/examples/device/cdc_msc_freertos/src/freertos_hook.c
index 273ad46e6..ab885947c 100644
--- a/examples/device/cdc_msc_freertos/src/freertos_hook.c
+++ b/examples/device/cdc_msc_freertos/src/freertos_hook.c
@@ -94,7 +94,7 @@ void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimerTaskTCBBuffer, Stack
*pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;
}
-#if CFG_TUSB_MCU == OPT_MCU_RX63X
+#if CFG_TUSB_MCU == OPT_MCU_RX63X | CFG_TUSB_MCU == OPT_MCU_RX65X
#include "iodefine.h"
void vApplicationSetupTimerInterrupt(void)
{
diff --git a/examples/device/cdc_msc_freertos/src/msc_disk.c b/examples/device/cdc_msc_freertos/src/msc_disk.c
index 5aa7befc9..b9205f0c2 100644
--- a/examples/device/cdc_msc_freertos/src/msc_disk.c
+++ b/examples/device/cdc_msc_freertos/src/msc_disk.c
@@ -178,6 +178,9 @@ int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buff
{
(void) lun;
+ // out of ramdisk
+ if ( lba >= DISK_BLOCK_NUM ) return -1;
+
uint8_t const* addr = msc_disk[lba] + offset;
memcpy(buffer, addr, bufsize);
@@ -190,6 +193,9 @@ int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t*
{
(void) lun;
+ // out of ramdisk
+ if ( lba >= DISK_BLOCK_NUM ) return -1;
+
#ifndef CFG_EXAMPLE_MSC_READONLY
uint8_t* addr = msc_disk[lba] + offset;
memcpy(addr, buffer, bufsize);
@@ -208,7 +214,7 @@ int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer,
// read10 & write10 has their own callback and MUST not be handled here
void const* response = NULL;
- uint16_t resplen = 0;
+ int32_t resplen = 0;
// most scsi handled is input
bool in_xfer = true;
diff --git a/examples/device/cdc_msc_freertos/src/usb_descriptors.c b/examples/device/cdc_msc_freertos/src/usb_descriptors.c
index 75b5ce7bb..f3ff305f8 100644
--- a/examples/device/cdc_msc_freertos/src/usb_descriptors.c
+++ b/examples/device/cdc_msc_freertos/src/usb_descriptors.c
@@ -35,6 +35,9 @@
#define USB_PID (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \
_PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4) )
+#define USB_VID 0xCafe
+#define USB_BCD 0x0200
+
//--------------------------------------------------------------------+
// Device Descriptors
//--------------------------------------------------------------------+
@@ -42,7 +45,7 @@ tusb_desc_device_t const desc_device =
{
.bLength = sizeof(tusb_desc_device_t),
.bDescriptorType = TUSB_DESC_DEVICE,
- .bcdUSB = 0x0200,
+ .bcdUSB = USB_BCD,
// Use Interface Association Descriptor (IAD) for CDC
// As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1)
@@ -52,7 +55,7 @@ tusb_desc_device_t const desc_device =
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
- .idVendor = 0xCafe,
+ .idVendor = USB_VID,
.idProduct = USB_PID,
.bcdDevice = 0x0100,
@@ -82,8 +85,6 @@ enum
ITF_NUM_TOTAL
};
-#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN + TUD_MSC_DESC_LEN)
-
#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 ...
@@ -114,10 +115,12 @@ enum
#endif
+#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN + TUD_MSC_DESC_LEN)
+
uint8_t const desc_fs_configuration[] =
{
// Config number, interface count, string index, total length, attribute, power in mA
- TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
+ TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
// Interface number, string index, EP notification address and size, EP data address (out, in) and size.
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT, EPNUM_CDC_IN, 64),
@@ -127,10 +130,13 @@ uint8_t const desc_fs_configuration[] =
};
#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, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
+ TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
// Interface number, string index, EP notification address and size, EP data address (out, in) and size.
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT, EPNUM_CDC_IN, 512),
@@ -138,7 +144,54 @@ uint8_t const desc_hs_configuration[] =
// Interface number, string index, EP Out & EP In address, EP size
TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 5, EPNUM_MSC_OUT, EPNUM_MSC_IN, 512),
};
-#endif
+
+// other speed configuration
+uint8_t desc_other_speed_config[CONFIG_TOTAL_LEN];
+
+// device qualifier is mostly similar to device descriptor since we don't change configuration based on speed
+tusb_desc_device_qualifier_t const desc_device_qualifier =
+{
+ .bLength = sizeof(tusb_desc_device_qualifier_t),
+ .bDescriptorType = TUSB_DESC_DEVICE_QUALIFIER,
+ .bcdUSB = USB_BCD,
+
+ .bDeviceClass = TUSB_CLASS_MISC,
+ .bDeviceSubClass = MISC_SUBCLASS_COMMON,
+ .bDeviceProtocol = MISC_PROTOCOL_IAD,
+
+ .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
+ .bNumConfigurations = 0x01,
+ .bReserved = 0x00
+};
+
+// Invoked when received GET DEVICE QUALIFIER DESCRIPTOR request
+// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete.
+// device_qualifier descriptor describes information about a high-speed capable device that would
+// change if the device were operating at the other speed. If not highspeed capable stall this request.
+uint8_t const* tud_descriptor_device_qualifier_cb(void)
+{
+ return (uint8_t const*) &desc_device_qualifier;
+}
+
+// Invoked when received GET OTHER SEED CONFIGURATION DESCRIPTOR request
+// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
+// Configuration descriptor in the other speed e.g if high speed then this is for full speed and vice versa
+uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index)
+{
+ (void) index; // for multiple configurations
+
+ // if link speed is high return fullspeed config, and vice versa
+ // Note: the descriptor type is OHER_SPEED_CONFIG instead of CONFIG
+ memcpy(desc_other_speed_config,
+ (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_fs_configuration : desc_hs_configuration,
+ CONFIG_TOTAL_LEN);
+
+ desc_other_speed_config[1] = TUSB_DESC_OTHER_SPEED_CONFIG;
+
+ return desc_other_speed_config;
+}
+
+#endif // highspeed
// Invoked when received GET CONFIGURATION DESCRIPTOR
// Application return pointer to descriptor
diff --git a/examples/device/dfu/src/main.c b/examples/device/dfu/src/main.c
index 1c09066a8..5c8464526 100644
--- a/examples/device/dfu/src/main.c
+++ b/examples/device/dfu/src/main.c
@@ -26,13 +26,15 @@
/*
* After device is enumerated in dfu mode run the following commands
*
- * To transfer firmware from host to device:
+ * To transfer firmware from host to device (best to test with text file)
*
- * $ dfu-util -D [filename]
+ * $ dfu-util -d cafe -a 0 -D [filename]
+ * $ dfu-util -d cafe -a 1 -D [filename]
*
* To transfer firmware from device to host:
*
- * $ dfu-util -U [filename]
+ * $ dfu-util -d cafe -a 0 -U [filename]
+ * $ dfu-util -d cafe -a 1 -U [filename]
*
*/
@@ -43,22 +45,21 @@
#include "bsp/board.h"
#include "tusb.h"
-
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF PROTYPES
//--------------------------------------------------------------------+
-#ifndef DFU_VERBOSE
-#define DFU_VERBOSE 0
-#endif
+const char* upload_image[2]=
+{
+ "Hello world from TinyUSB DFU! - Partition 0",
+ "Hello world from TinyUSB DFU! - Partition 1"
+};
/* Blink pattern
- * - 1000 ms : device should reboot
* - 250 ms : device not mounted
* - 1000 ms : device mounted
* - 2500 ms : device is suspended
*/
enum {
- BLINK_DFU_MODE = 100,
BLINK_NOT_MOUNTED = 250,
BLINK_MOUNTED = 1000,
BLINK_SUSPENDED = 2500,
@@ -115,58 +116,89 @@ void tud_resume_cb(void)
blink_interval_ms = BLINK_MOUNTED;
}
-// Invoked on DFU_DETACH request to reboot to the bootloader
-void tud_dfu_runtime_reboot_to_dfu_cb(void)
-{
- blink_interval_ms = BLINK_DFU_MODE;
-}
-
//--------------------------------------------------------------------+
-// Class callbacks
+// DFU callbacks
+// Note: alt is used as the partition number, in order to support multiple partitions like FLASH, EEPROM, etc.
//--------------------------------------------------------------------+
-bool tud_dfu_firmware_valid_check_cb(void)
+
+// Invoked right before tud_dfu_download_cb() (state=DFU_DNBUSY) or tud_dfu_manifest_cb() (state=DFU_MANIFEST)
+// Application return timeout in milliseconds (bwPollTimeout) for the next download/manifest operation.
+// During this period, USB host won't try to communicate with us.
+uint32_t tud_dfu_get_timeout_cb(uint8_t alt, uint8_t state)
{
- printf(" Firmware check\r\n");
- return true;
+ if ( state == DFU_DNBUSY )
+ {
+ // For this example
+ // - Atl0 Flash is fast : 1 ms
+ // - Alt1 EEPROM is slow: 100 ms
+ return (alt == 0) ? 1 : 100;
+ }
+ else if (state == DFU_MANIFEST)
+ {
+ // since we don't buffer entire image and do any flashing in manifest stage
+ return 0;
+ }
+
+ return 0;
}
-void tud_dfu_req_dnload_data_cb(uint16_t wBlockNum, uint8_t* data, uint16_t length)
+// Invoked when received DFU_DNLOAD (wLength>0) following by DFU_GETSTATUS (state=DFU_DNBUSY) requests
+// This callback could be returned before flashing op is complete (async).
+// Once finished flashing, application must call tud_dfu_finish_flashing()
+void tud_dfu_download_cb(uint8_t alt, uint16_t block_num, uint8_t const* data, uint16_t length)
{
- (void) data;
- printf(" Received BlockNum %u of length %u\r\n", wBlockNum, length);
+ (void) alt;
+ (void) block_num;
+
+ //printf("\r\nReceived Alt %u BlockNum %u of length %u\r\n", alt, wBlockNum, length);
-#if DFU_VERBOSE
for(uint16_t i=0; i<length; i++)
{
- printf(" [%u][%u]: %x\r\n", wBlockNum, i, (uint8_t)data[i]);
+ printf("%c", data[i]);
}
-#endif
- tud_dfu_dnload_complete();
+ // flashing op for download complete without error
+ tud_dfu_finish_flashing(DFU_STATUS_OK);
}
-bool tud_dfu_device_data_done_check_cb(void)
+// Invoked when download process is complete, received DFU_DNLOAD (wLength=0) following by DFU_GETSTATUS (state=Manifest)
+// Application can do checksum, or actual flashing if buffered entire image previously.
+// Once finished flashing, application must call tud_dfu_finish_flashing()
+void tud_dfu_manifest_cb(uint8_t alt)
{
- printf(" Host said no more data... Returning true\r\n");
- return true;
-}
+ (void) alt;
+ printf("Download completed, enter manifestation\r\n");
-void tud_dfu_abort_cb(void)
-{
- printf(" Host aborted transfer\r\n");
+ // flashing op for manifest is complete without error
+ // Application can perform checksum, should it fail, use appropriate status such as errVERIFY.
+ tud_dfu_finish_flashing(DFU_STATUS_OK);
}
-#define UPLOAD_SIZE (29)
-const uint8_t upload_test[UPLOAD_SIZE] = "Hello world from TinyUSB DFU!";
-
-uint16_t tud_dfu_req_upload_data_cb(uint16_t block_num, uint8_t* data, uint16_t length)
+// Invoked when received DFU_UPLOAD request
+// Application must populate data with up to length bytes and
+// Return the number of written bytes
+uint16_t tud_dfu_upload_cb(uint8_t alt, uint16_t block_num, uint8_t* data, uint16_t length)
{
(void) block_num;
(void) length;
- memcpy(data, upload_test, UPLOAD_SIZE);
+ uint16_t const xfer_len = (uint16_t) strlen(upload_image[alt]);
+ memcpy(data, upload_image[alt], xfer_len);
- return UPLOAD_SIZE;
+ return xfer_len;
+}
+
+// Invoked when the Host has terminated a download or upload transfer
+void tud_dfu_abort_cb(uint8_t alt)
+{
+ (void) alt;
+ printf("Host aborted transfer\r\n");
+}
+
+// Invoked when a DFU_DETACH request is received
+void tud_dfu_detach_cb(void)
+{
+ printf("Host detach, we should probably reboot\r\n");
}
//--------------------------------------------------------------------+
diff --git a/examples/device/dfu/src/tusb_config.h b/examples/device/dfu/src/tusb_config.h
index 90e90b2e4..66e357021 100644
--- a/examples/device/dfu/src/tusb_config.h
+++ b/examples/device/dfu/src/tusb_config.h
@@ -76,12 +76,11 @@
#define CFG_TUD_ENDPOINT0_SIZE 64
#endif
-#define CFG_TUD_DFU_TRANSFER_BUFFER_SIZE 4096
-
//------------- CLASS -------------//
+#define CFG_TUD_DFU 1
-#define CFG_TUD_DFU_RUNTIME 0
-#define CFG_TUD_DFU_MODE 1
+// DFU buffer size, it has to be set to the buffer size used in TUD_DFU_DESCRIPTOR
+#define CFG_TUD_DFU_XFER_BUFSIZE 512
#ifdef __cplusplus
}
diff --git a/examples/device/dfu/src/usb_descriptors.c b/examples/device/dfu/src/usb_descriptors.c
index 8ad64354b..350334aa5 100644
--- a/examples/device/dfu/src/usb_descriptors.c
+++ b/examples/device/dfu/src/usb_descriptors.c
@@ -81,23 +81,26 @@ uint8_t const * tud_descriptor_device_cb(void)
// Configuration Descriptor
//--------------------------------------------------------------------+
+// Number of Alternate Interface (each for 1 flash partition)
+#define ALT_COUNT 2
+
enum
{
ITF_NUM_DFU_MODE,
ITF_NUM_TOTAL
};
-#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_DFU_MODE_DESC_LEN)
+#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_DFU_DESC_LEN(ALT_COUNT))
-#define FUNC_ATTRS (DFU_FUNC_ATTR_CAN_UPLOAD_BITMASK | DFU_FUNC_ATTR_CAN_DOWNLOAD_BITMASK)
+#define FUNC_ATTRS (DFU_ATTR_CAN_UPLOAD | DFU_ATTR_CAN_DOWNLOAD | DFU_ATTR_MANIFESTATION_TOLERANT)
uint8_t const desc_configuration[] =
{
// Config number, interface count, string index, total length, attribute, power in mA
- TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
+ TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
- // Interface number, string index, attributes, detach timeout, transfer size */
- TUD_DFU_MODE_DESCRIPTOR(ITF_NUM_DFU_MODE, 0, FUNC_ATTRS, 1000, CFG_TUD_DFU_TRANSFER_BUFFER_SIZE),
+ // Interface number, Alternate count, starting string index, attributes, detach timeout, transfer size
+ TUD_DFU_DESCRIPTOR(ITF_NUM_DFU_MODE, ALT_COUNT, 4, FUNC_ATTRS, 1000, CFG_TUD_DFU_XFER_BUFSIZE),
};
// Invoked when received GET CONFIGURATION DESCRIPTOR
@@ -120,7 +123,8 @@ char const* string_desc_arr [] =
"TinyUSB", // 1: Manufacturer
"TinyUSB Device", // 2: Product
"123456", // 3: Serials, should use chip ID
- "TinyUSB DFU", // 4: DFU
+ "FLASH", // 4: DFU Partition 1
+ "EEPROM", // 5: DFU Partition 2
};
static uint16_t _desc_str[32];
diff --git a/examples/device/dfu_runtime/src/usb_descriptors.c b/examples/device/dfu_runtime/src/usb_descriptors.c
index 8b2bd265d..060943289 100644
--- a/examples/device/dfu_runtime/src/usb_descriptors.c
+++ b/examples/device/dfu_runtime/src/usb_descriptors.c
@@ -92,7 +92,7 @@ enum
uint8_t const desc_configuration[] =
{
// Config number, interface count, string index, total length, attribute, power in mA
- TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
+ TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
// Interface number, string index, attributes, detach timeout, transfer size */
TUD_DFU_RT_DESCRIPTOR(ITF_NUM_DFU_RT, 4, 0x0d, 1000, 4096),
diff --git a/examples/device/dynamic_configuration/src/msc_disk.c b/examples/device/dynamic_configuration/src/msc_disk.c
index 5aa7befc9..b9205f0c2 100644
--- a/examples/device/dynamic_configuration/src/msc_disk.c
+++ b/examples/device/dynamic_configuration/src/msc_disk.c
@@ -178,6 +178,9 @@ int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buff
{
(void) lun;
+ // out of ramdisk
+ if ( lba >= DISK_BLOCK_NUM ) return -1;
+
uint8_t const* addr = msc_disk[lba] + offset;
memcpy(buffer, addr, bufsize);
@@ -190,6 +193,9 @@ int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t*
{
(void) lun;
+ // out of ramdisk
+ if ( lba >= DISK_BLOCK_NUM ) return -1;
+
#ifndef CFG_EXAMPLE_MSC_READONLY
uint8_t* addr = msc_disk[lba] + offset;
memcpy(addr, buffer, bufsize);
@@ -208,7 +214,7 @@ int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer,
// read10 & write10 has their own callback and MUST not be handled here
void const* response = NULL;
- uint16_t resplen = 0;
+ int32_t resplen = 0;
// most scsi handled is input
bool in_xfer = true;
diff --git a/examples/device/dynamic_configuration/src/usb_descriptors.c b/examples/device/dynamic_configuration/src/usb_descriptors.c
index 9ccb37654..3352972a5 100644
--- a/examples/device/dynamic_configuration/src/usb_descriptors.c
+++ b/examples/device/dynamic_configuration/src/usb_descriptors.c
@@ -160,7 +160,7 @@ enum
uint8_t const desc_configuration_0[] =
{
// Config number, interface count, string index, total length, attribute, power in mA
- TUD_CONFIG_DESCRIPTOR(1, ITF_0_NUM_TOTAL, 0, CONFIG_0_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
+ TUD_CONFIG_DESCRIPTOR(1, ITF_0_NUM_TOTAL, 0, CONFIG_0_TOTAL_LEN, 0x00, 100),
// Interface number, string index, EP notification address and size, EP data address (out, in) and size.
TUD_CDC_DESCRIPTOR(ITF_0_NUM_CDC, 0, EPNUM_0_CDC_NOTIF, 8, EPNUM_0_CDC_OUT, EPNUM_0_CDC_IN, 64),
@@ -173,7 +173,7 @@ uint8_t const desc_configuration_0[] =
uint8_t const desc_configuraiton_1[] =
{
// Config number, interface count, string index, total length, attribute, power in mA
- TUD_CONFIG_DESCRIPTOR(1, ITF_1_NUM_TOTAL, 0, CONFIG_1_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
+ TUD_CONFIG_DESCRIPTOR(1, ITF_1_NUM_TOTAL, 0, CONFIG_1_TOTAL_LEN, 0x00, 100),
// Interface number, string index, EP Out & EP In address, EP size
TUD_MSC_DESCRIPTOR(ITF_1_NUM_MSC, 0, EPNUM_1_MSC_OUT, EPNUM_1_MSC_IN, TUD_OPT_HIGH_SPEED ? 512 : 64),
diff --git a/examples/device/hid_boot_interface/CMakeLists.txt b/examples/device/hid_boot_interface/CMakeLists.txt
new file mode 100644
index 000000000..abc4d91da
--- /dev/null
+++ b/examples/device/hid_boot_interface/CMakeLists.txt
@@ -0,0 +1,28 @@
+cmake_minimum_required(VERSION 3.5)
+
+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})
+
+# Checks this example is valid for the family and initializes the project
+family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
+
+add_executable(${PROJECT})
+
+# Example source
+target_sources(${PROJECT} PUBLIC
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c
+ )
+
+# Example include
+target_include_directories(${PROJECT} PUBLIC
+ ${CMAKE_CURRENT_SOURCE_DIR}/src
+ )
+
+# Configure compilation flags and libraries for the example... see the corresponding function
+# in hw/bsp/FAMILY/family.cmake for details.
+family_configure_device_example(${PROJECT}) \ No newline at end of file
diff --git a/examples/device/hid_boot_interface/Makefile b/examples/device/hid_boot_interface/Makefile
new file mode 100644
index 000000000..138c27846
--- /dev/null
+++ b/examples/device/hid_boot_interface/Makefile
@@ -0,0 +1,15 @@
+include ../../../tools/top.mk
+include ../../make.mk
+
+INC += \
+ src \
+ $(TOP)/hw \
+
+# Example source
+EXAMPLE_SOURCE += \
+ src/main.c \
+ src/usb_descriptors.c
+
+SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
+
+include ../../rules.mk
diff --git a/examples/device/hid_boot_interface/src/main.c b/examples/device/hid_boot_interface/src/main.c
new file mode 100644
index 000000000..e5e2f6856
--- /dev/null
+++ b/examples/device/hid_boot_interface/src/main.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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "bsp/board.h"
+#include "tusb.h"
+#include "usb_descriptors.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);
+void hid_task(void);
+
+/*------------- MAIN -------------*/
+int main(void)
+{
+ board_init();
+ tusb_init();
+
+ while (1)
+ {
+ tud_task(); // tinyusb device task
+ led_blinking_task();
+
+ hid_task();
+ }
+
+ return 0;
+}
+
+//--------------------------------------------------------------------+
+// Device callbacks
+//--------------------------------------------------------------------+
+
+// Invoked when device is mounted
+void tud_mount_cb(void)
+{
+ blink_interval_ms = BLINK_MOUNTED;
+}
+
+// Invoked when device is unmounted
+void tud_umount_cb(void)
+{
+ blink_interval_ms = BLINK_NOT_MOUNTED;
+}
+
+// Invoked when usb bus is suspended
+// remote_wakeup_en : if host allow us to perform remote wakeup
+// Within 7ms, device must draw an average of current less than 2.5 mA from bus
+void tud_suspend_cb(bool remote_wakeup_en)
+{
+ (void) remote_wakeup_en;
+ blink_interval_ms = BLINK_SUSPENDED;
+}
+
+// Invoked when usb bus is resumed
+void tud_resume_cb(void)
+{
+ blink_interval_ms = BLINK_MOUNTED;
+}
+
+//--------------------------------------------------------------------+
+// USB HID
+//--------------------------------------------------------------------+
+
+// Every 10ms, we will sent 1 report for each HID profile (keyboard, mouse etc ..)
+// tud_hid_report_complete_cb() is used to send the next report after previous one is complete
+void hid_task(void)
+{
+ // Poll every 10ms
+ const uint32_t interval_ms = 10;
+ static uint32_t start_ms = 0;
+
+ if ( board_millis() - start_ms < interval_ms) return; // not enough time
+ start_ms += interval_ms;
+
+ uint32_t const btn = board_button_read();
+
+ if ( tud_suspended() && btn )
+ {
+ // Wake up host if we are in suspend mode
+ // and REMOTE_WAKEUP feature is enabled by host
+ tud_remote_wakeup();
+ }
+ else
+ {
+ // keyboard interface
+ if ( tud_hid_n_ready(ITF_NUM_KEYBOARD) )
+ {
+ // used to avoid send multiple consecutive zero report for keyboard
+ static bool has_keyboard_key = false;
+
+ uint8_t const report_id = 0;
+ uint8_t const modifier = 0;
+
+ if ( btn )
+ {
+ uint8_t keycode[6] = { 0 };
+ keycode[0] = HID_KEY_ARROW_RIGHT;
+
+ tud_hid_n_keyboard_report(ITF_NUM_KEYBOARD, report_id, modifier, keycode);
+ has_keyboard_key = true;
+ }else
+ {
+ // send empty key report if previously has key pressed
+ if (has_keyboard_key) tud_hid_n_keyboard_report(ITF_NUM_KEYBOARD, report_id, modifier, NULL);
+ has_keyboard_key = false;
+ }
+ }
+
+ // mouse interface
+ if ( tud_hid_n_ready(ITF_NUM_MOUSE) )
+ {
+ if ( btn )
+ {
+ uint8_t const report_id = 0;
+ uint8_t const button_mask = 0;
+ uint8_t const veritical = 0;
+ uint8_t const horizontal = 0;
+ int8_t const delta = 5;
+
+ tud_hid_n_mouse_report(ITF_NUM_MOUSE, report_id, button_mask, delta, delta, veritical, horizontal);
+ }
+ }
+ }
+}
+
+// Invoked when received SET_PROTOCOL request
+// protocol is either HID_PROTOCOL_BOOT (0) or HID_PROTOCOL_REPORT (1)
+void tud_hid_set_protocol_cb(uint8_t instance, uint8_t protocol)
+{
+ (void) instance;
+ (void) protocol;
+
+ // nothing to do since we use the same compatible boot report for both Boot and Report mode.
+ // TOOD set a indicator for user
+}
+
+// Invoked when sent REPORT successfully to host
+// Application can use this to send the next report
+// Note: For composite reports, report[0] is report ID
+void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, uint8_t len)
+{
+ (void) instance;
+ (void) report;
+ (void) len;
+
+ // nothing to do
+}
+
+// Invoked when received GET_REPORT control request
+// Application must fill buffer report's content and return its length.
+// Return zero will cause the stack to STALL request
+uint16_t tud_hid_get_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen)
+{
+ // TODO not Implemented
+ (void) instance;
+ (void) report_id;
+ (void) report_type;
+ (void) buffer;
+ (void) reqlen;
+
+ return 0;
+}
+
+// Invoked when received SET_REPORT control request or
+// received data on OUT endpoint ( Report ID = 0, Type = 0 )
+void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize)
+{
+ (void) report_id;
+
+ // keyboard interface
+ if (instance == ITF_NUM_KEYBOARD)
+ {
+ // Set keyboard LED e.g Capslock, Numlock etc...
+ if (report_type == HID_REPORT_TYPE_OUTPUT)
+ {
+ // bufsize should be (at least) 1
+ if ( bufsize < 1 ) return;
+
+ uint8_t const kbd_leds = buffer[0];
+
+ if (kbd_leds & KEYBOARD_LED_CAPSLOCK)
+ {
+ // Capslock On: disable blink, turn led on
+ blink_interval_ms = 0;
+ board_led_write(true);
+ }else
+ {
+ // Caplocks Off: back to normal blink
+ board_led_write(false);
+ blink_interval_ms = BLINK_MOUNTED;
+ }
+ }
+ }
+}
+
+//--------------------------------------------------------------------+
+// BLINKING TASK
+//--------------------------------------------------------------------+
+void led_blinking_task(void)
+{
+ static uint32_t start_ms = 0;
+ static bool led_state = false;
+
+ // blink is disabled
+ if (!blink_interval_ms) return;
+
+ // 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/hid_boot_interface/src/tusb_config.h b/examples/device/hid_boot_interface/src/tusb_config.h
new file mode 100644
index 000000000..59fb9962c
--- /dev/null
+++ b/examples/device/hid_boot_interface/src/tusb_config.h
@@ -0,0 +1,111 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#ifndef _TUSB_CONFIG_H_
+#define _TUSB_CONFIG_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+//--------------------------------------------------------------------
+// COMMON CONFIGURATION
+//--------------------------------------------------------------------
+
+// defined by board.mk
+#ifndef CFG_TUSB_MCU
+ #error CFG_TUSB_MCU must be defined
+#endif
+
+// RHPort number used for device can be defined by board.mk, default to port 0
+#ifndef BOARD_DEVICE_RHPORT_NUM
+ #define BOARD_DEVICE_RHPORT_NUM 0
+#endif
+
+// RHPort max operational speed can defined by board.mk
+// Default to Highspeed for MCU with internal HighSpeed PHY (can be port specific), otherwise FullSpeed
+#ifndef BOARD_DEVICE_RHPORT_SPEED
+ #if (CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX || \
+ CFG_TUSB_MCU == OPT_MCU_NUC505 || CFG_TUSB_MCU == OPT_MCU_CXD56 || CFG_TUSB_MCU == OPT_MCU_SAMX7X)
+ #define BOARD_DEVICE_RHPORT_SPEED OPT_MODE_HIGH_SPEED
+ #else
+ #define BOARD_DEVICE_RHPORT_SPEED OPT_MODE_FULL_SPEED
+ #endif
+#endif
+
+// Device mode with rhport and speed defined by board.mk
+#if BOARD_DEVICE_RHPORT_NUM == 0
+ #define CFG_TUSB_RHPORT0_MODE (OPT_MODE_DEVICE | BOARD_DEVICE_RHPORT_SPEED)
+#elif BOARD_DEVICE_RHPORT_NUM == 1
+ #define CFG_TUSB_RHPORT1_MODE (OPT_MODE_DEVICE | BOARD_DEVICE_RHPORT_SPEED)
+#else
+ #error "Incorrect RHPort configuration"
+#endif
+
+#ifndef CFG_TUSB_OS
+#define CFG_TUSB_OS OPT_OS_NONE
+#endif
+
+// CFG_TUSB_DEBUG is defined by compiler in DEBUG build
+// #define CFG_TUSB_DEBUG 0
+
+/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.
+ * Tinyusb use follows macros to declare transferring memory so that they can be put
+ * into those specific section.
+ * e.g
+ * - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") ))
+ * - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4)))
+ */
+#ifndef CFG_TUSB_MEM_SECTION
+#define CFG_TUSB_MEM_SECTION
+#endif
+
+#ifndef CFG_TUSB_MEM_ALIGN
+#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4)))
+#endif
+
+//--------------------------------------------------------------------
+// DEVICE CONFIGURATION
+//--------------------------------------------------------------------
+
+#ifndef CFG_TUD_ENDPOINT0_SIZE
+#define CFG_TUD_ENDPOINT0_SIZE 64
+#endif
+
+//------------- CLASS -------------//
+#define CFG_TUD_HID 2 // 1 for boot keyboard, 1 for boot mouse
+#define CFG_TUD_CDC 0
+#define CFG_TUD_MSC 0
+#define CFG_TUD_MIDI 0
+#define CFG_TUD_VENDOR 0
+
+// HID buffer size Should be sufficient to hold ID (if any) + Data
+#define CFG_TUD_HID_EP_BUFSIZE 8
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _TUSB_CONFIG_H_ */
diff --git a/examples/device/hid_boot_interface/src/usb_descriptors.c b/examples/device/hid_boot_interface/src/usb_descriptors.c
new file mode 100644
index 000000000..3fa48d98d
--- /dev/null
+++ b/examples/device/hid_boot_interface/src/usb_descriptors.c
@@ -0,0 +1,180 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#include "tusb.h"
+#include "usb_descriptors.h"
+
+/* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug.
+ * Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC.
+ *
+ * Auto ProductID layout's Bitmap:
+ * [MSB] HID | MSC | CDC [LSB]
+ */
+#define _PID_MAP(itf, n) ( (CFG_TUD_##itf) << (n) )
+#define USB_PID (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \
+ _PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4) )
+
+//--------------------------------------------------------------------+
+// Device Descriptors
+//--------------------------------------------------------------------+
+tusb_desc_device_t const desc_device =
+{
+ .bLength = sizeof(tusb_desc_device_t),
+ .bDescriptorType = TUSB_DESC_DEVICE,
+ .bcdUSB = 0x0200,
+ .bDeviceClass = 0x00,
+ .bDeviceSubClass = 0x00,
+ .bDeviceProtocol = 0x00,
+ .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
+
+ .idVendor = 0xCafe,
+ .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;
+}
+
+//--------------------------------------------------------------------+
+// HID Report Descriptor
+//--------------------------------------------------------------------+
+
+uint8_t const desc_hid_keyboard_report[] =
+{
+ TUD_HID_REPORT_DESC_KEYBOARD()
+};
+
+uint8_t const desc_hid_mouse_report[] =
+{
+ TUD_HID_REPORT_DESC_MOUSE()
+};
+
+// Invoked when received GET HID REPORT DESCRIPTOR
+// Application return pointer to descriptor
+// Descriptor contents must exist long enough for transfer to complete
+uint8_t const * tud_hid_descriptor_report_cb(uint8_t instance)
+{
+ return (instance == 0) ? desc_hid_keyboard_report : desc_hid_mouse_report;
+}
+
+//--------------------------------------------------------------------+
+// Configuration Descriptor
+//--------------------------------------------------------------------+
+
+#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + 2*TUD_HID_DESC_LEN)
+
+#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
+ // 1 Interrupt, 2 Bulk, 3 Iso, 4 Interrupt, 5 Bulk etc ...
+ #define EPNUM_KEYBOARD 0x81
+ #define EPNUM_MOUSE 0x84
+#else
+ #define EPNUM_KEYBOARD 0x81
+ #define EPNUM_MOUSE 0x82
+#endif
+
+uint8_t const desc_configuration[] =
+{
+ // Config number, interface count, string index, total length, attribute, power in mA
+ TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
+
+ // Interface number, string index, protocol, report descriptor len, EP In address, size & polling interval
+ TUD_HID_DESCRIPTOR(ITF_NUM_KEYBOARD, 0, HID_ITF_PROTOCOL_KEYBOARD, sizeof(desc_hid_keyboard_report), EPNUM_KEYBOARD, CFG_TUD_HID_EP_BUFSIZE, 10),
+
+ // Interface number, string index, protocol, report descriptor len, EP In address, size & polling interval
+ TUD_HID_DESCRIPTOR(ITF_NUM_MOUSE, 0, HID_ITF_PROTOCOL_MOUSE, sizeof(desc_hid_mouse_report), EPNUM_MOUSE, CFG_TUD_HID_EP_BUFSIZE, 10)
+};
+
+// Invoked when received GET CONFIGURATION DESCRIPTOR
+// Application return pointer to descriptor
+// Descriptor contents must exist long enough for transfer to complete
+uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
+{
+ (void) index; // for multiple configurations
+ return desc_configuration;
+}
+
+//--------------------------------------------------------------------+
+// String Descriptors
+//--------------------------------------------------------------------+
+
+// array of pointer to string descriptors
+char const* string_desc_arr [] =
+{
+ (const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
+ "TinyUSB", // 1: Manufacturer
+ "TinyUSB Device", // 2: Product
+ "123456", // 3: Serials, should use chip ID
+};
+
+static uint16_t _desc_str[32];
+
+// Invoked when received GET STRING DESCRIPTOR request
+// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
+uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid)
+{
+ (void) langid;
+
+ uint8_t chr_count;
+
+ if ( index == 0)
+ {
+ memcpy(&_desc_str[1], string_desc_arr[0], 2);
+ chr_count = 1;
+ }else
+ {
+ // Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors.
+ // https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors
+
+ if ( !(index < sizeof(string_desc_arr)/sizeof(string_desc_arr[0])) ) return NULL;
+
+ const char* str = string_desc_arr[index];
+
+ // Cap at max char
+ chr_count = strlen(str);
+ if ( chr_count > 31 ) chr_count = 31;
+
+ // Convert ASCII string into UTF-16
+ for(uint8_t i=0; i<chr_count; i++)
+ {
+ _desc_str[1+i] = str[i];
+ }
+ }
+
+ // first byte is length (including header), second byte is string type
+ _desc_str[0] = (TUSB_DESC_STRING << 8 ) | (2*chr_count + 2);
+
+ return _desc_str;
+}
diff --git a/examples/device/hid_boot_interface/src/usb_descriptors.h b/examples/device/hid_boot_interface/src/usb_descriptors.h
new file mode 100644
index 000000000..57cf0e2c0
--- /dev/null
+++ b/examples/device/hid_boot_interface/src/usb_descriptors.h
@@ -0,0 +1,35 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef USB_DESCRIPTORS_H_
+#define USB_DESCRIPTORS_H_
+
+enum
+{
+ ITF_NUM_KEYBOARD,
+ ITF_NUM_MOUSE,
+ ITF_NUM_TOTAL
+};
+
+#endif
diff --git a/examples/device/hid_composite/src/main.c b/examples/device/hid_composite/src/main.c
index 512f6f9d9..fd25e620a 100644
--- a/examples/device/hid_composite/src/main.c
+++ b/examples/device/hid_composite/src/main.c
@@ -223,9 +223,9 @@ void hid_task(void)
// Invoked when sent REPORT successfully to host
// Application can use this to send the next report
// Note: For composite reports, report[0] is report ID
-void tud_hid_report_complete_cb(uint8_t itf, uint8_t const* report, uint8_t len)
+void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, uint8_t len)
{
- (void) itf;
+ (void) instance;
(void) len;
uint8_t next_report_id = report[0] + 1;
@@ -239,10 +239,10 @@ void tud_hid_report_complete_cb(uint8_t itf, uint8_t const* report, uint8_t len)
// Invoked when received GET_REPORT control request
// Application must fill buffer report's content and return its length.
// Return zero will cause the stack to STALL request
-uint16_t tud_hid_get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen)
+uint16_t tud_hid_get_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen)
{
// TODO not Implemented
- (void) itf;
+ (void) instance;
(void) report_id;
(void) report_type;
(void) buffer;
@@ -253,14 +253,33 @@ uint16_t tud_hid_get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t
// Invoked when received SET_REPORT control request or
// received data on OUT endpoint ( Report ID = 0, Type = 0 )
-void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize)
+void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize)
{
- // TODO set LED based on CAPLOCK, NUMLOCK etc...
- (void) itf;
- (void) report_id;
- (void) report_type;
- (void) buffer;
- (void) bufsize;
+ (void) instance;
+
+ if (report_type == HID_REPORT_TYPE_OUTPUT)
+ {
+ // Set keyboard LED e.g Capslock, Numlock etc...
+ if (report_id == REPORT_ID_KEYBOARD)
+ {
+ // bufsize should be (at least) 1
+ if ( bufsize < 1 ) return;
+
+ uint8_t const kbd_leds = buffer[0];
+
+ if (kbd_leds & KEYBOARD_LED_CAPSLOCK)
+ {
+ // Capslock On: disable blink, turn led on
+ blink_interval_ms = 0;
+ board_led_write(true);
+ }else
+ {
+ // Caplocks Off: back to normal blink
+ board_led_write(false);
+ blink_interval_ms = BLINK_MOUNTED;
+ }
+ }
+ }
}
//--------------------------------------------------------------------+
@@ -271,6 +290,9 @@ void led_blinking_task(void)
static uint32_t start_ms = 0;
static bool led_state = false;
+ // blink is disabled
+ if (!blink_interval_ms) return;
+
// Blink every interval ms
if ( board_millis() - start_ms < blink_interval_ms) return; // not enough time
start_ms += blink_interval_ms;
diff --git a/examples/device/hid_composite/src/tusb_config.h b/examples/device/hid_composite/src/tusb_config.h
index 3e608ed37..868424e6d 100644
--- a/examples/device/hid_composite/src/tusb_config.h
+++ b/examples/device/hid_composite/src/tusb_config.h
@@ -48,7 +48,7 @@
// Default to Highspeed for MCU with internal HighSpeed PHY (can be port specific), otherwise FullSpeed
#ifndef BOARD_DEVICE_RHPORT_SPEED
#if (CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX || \
- CFG_TUSB_MCU == OPT_MCU_NUC505 || CFG_TUSB_MCU == OPT_MCU_CXD56)
+ CFG_TUSB_MCU == OPT_MCU_NUC505 || CFG_TUSB_MCU == OPT_MCU_CXD56 || CFG_TUSB_MCU == OPT_MCU_SAMX7X)
#define BOARD_DEVICE_RHPORT_SPEED OPT_MODE_HIGH_SPEED
#else
#define BOARD_DEVICE_RHPORT_SPEED OPT_MODE_FULL_SPEED
diff --git a/examples/device/hid_composite/src/usb_descriptors.c b/examples/device/hid_composite/src/usb_descriptors.c
index 1aff5e68e..e760b20ba 100644
--- a/examples/device/hid_composite/src/usb_descriptors.c
+++ b/examples/device/hid_composite/src/usb_descriptors.c
@@ -36,6 +36,9 @@
#define USB_PID (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \
_PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4) )
+#define USB_VID 0xCafe
+#define USB_BCD 0x0200
+
//--------------------------------------------------------------------+
// Device Descriptors
//--------------------------------------------------------------------+
@@ -43,13 +46,13 @@ tusb_desc_device_t const desc_device =
{
.bLength = sizeof(tusb_desc_device_t),
.bDescriptorType = TUSB_DESC_DEVICE,
- .bcdUSB = 0x0200,
+ .bcdUSB = USB_BCD,
.bDeviceClass = 0x00,
.bDeviceSubClass = 0x00,
.bDeviceProtocol = 0x00,
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
- .idVendor = 0xCafe,
+ .idVendor = USB_VID,
.idProduct = USB_PID,
.bcdDevice = 0x0100,
@@ -82,9 +85,9 @@ uint8_t const desc_hid_report[] =
// Invoked when received GET HID REPORT DESCRIPTOR
// Application return pointer to descriptor
// Descriptor contents must exist long enough for transfer to complete
-uint8_t const * tud_hid_descriptor_report_cb(uint8_t itf)
+uint8_t const * tud_hid_descriptor_report_cb(uint8_t instance)
{
- (void) itf;
+ (void) instance;
return desc_hid_report;
}
@@ -111,12 +114,62 @@ uint8_t const desc_configuration[] =
TUD_HID_DESCRIPTOR(ITF_NUM_HID, 0, HID_ITF_PROTOCOL_NONE, sizeof(desc_hid_report), EPNUM_HID, CFG_TUD_HID_EP_BUFSIZE, 5)
};
+#if TUD_OPT_HIGH_SPEED
+// Per USB specs: high speed capable device must report device_qualifier and other_speed_configuration
+
+// 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 = 0x00,
+ .bDeviceSubClass = 0x00,
+ .bDeviceProtocol = 0x00,
+
+ .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
+
+ // other speed config is basically configuration with type = OHER_SPEED_CONFIG
+ memcpy(desc_other_speed_config, desc_configuration, CONFIG_TOTAL_LEN);
+ desc_other_speed_config[1] = TUSB_DESC_OTHER_SPEED_CONFIG;
+
+ // this example use the same configuration for both high and full speed mode
+ return desc_other_speed_config;
+}
+
+#endif // highspeed
+
// Invoked when received GET CONFIGURATION DESCRIPTOR
// Application return pointer to descriptor
// Descriptor contents must exist long enough for transfer to complete
uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
{
(void) index; // for multiple configurations
+
+ // This example use the same configuration for both high and full speed mode
return desc_configuration;
}
diff --git a/examples/device/hid_composite_freertos/.skip.MCU_GD32VF103 b/examples/device/hid_composite_freertos/.skip.MCU_GD32VF103
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/examples/device/hid_composite_freertos/.skip.MCU_GD32VF103
diff --git a/examples/device/hid_composite_freertos/.skip.MCU_SAMX7X b/examples/device/hid_composite_freertos/.skip.MCU_SAMX7X
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/examples/device/hid_composite_freertos/.skip.MCU_SAMX7X
diff --git a/examples/device/hid_composite_freertos/src/FreeRTOSConfig.h b/examples/device/hid_composite_freertos/src/FreeRTOSConfig.h
index 99c5bc328..03f351018 100644
--- a/examples/device/hid_composite_freertos/src/FreeRTOSConfig.h
+++ b/examples/device/hid_composite_freertos/src/FreeRTOSConfig.h
@@ -154,11 +154,14 @@ extern uint32_t SystemCoreClock;
//--------------------------------------------------------------------+
// Interrupt nesting behavior configuration.
//--------------------------------------------------------------------+
-/* Cortex-M specific definitions. __NVIC_PRIO_BITS is defined in core_cmx.h */
-#ifdef __NVIC_PRIO_BITS
+#if defined(__NVIC_PRIO_BITS)
+ // For Cortex-M specific: __NVIC_PRIO_BITS is defined in core_cmx.h
#define configPRIO_BITS __NVIC_PRIO_BITS
+#elif defined(__ECLIC_INTCTLBITS)
+ // RISC-V Bumblebee core from nuclei
+ #define configPRIO_BITS __ECLIC_INTCTLBITS
#else
- #error "This port requires __NVIC_PRIO_BITS to be defined"
+ #error "FreeRTOS configPRIO_BITS to be defined"
#endif
/* The lowest interrupt priority that can be used in a call to a "set priority" function. */
diff --git a/examples/device/hid_composite_freertos/src/freertos_hook.c b/examples/device/hid_composite_freertos/src/freertos_hook.c
index 273ad46e6..ab885947c 100644
--- a/examples/device/hid_composite_freertos/src/freertos_hook.c
+++ b/examples/device/hid_composite_freertos/src/freertos_hook.c
@@ -94,7 +94,7 @@ void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimerTaskTCBBuffer, Stack
*pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;
}
-#if CFG_TUSB_MCU == OPT_MCU_RX63X
+#if CFG_TUSB_MCU == OPT_MCU_RX63X | CFG_TUSB_MCU == OPT_MCU_RX65X
#include "iodefine.h"
void vApplicationSetupTimerInterrupt(void)
{
diff --git a/examples/device/hid_composite_freertos/src/main.c b/examples/device/hid_composite_freertos/src/main.c
index 47f976427..9c9830e34 100644
--- a/examples/device/hid_composite_freertos/src/main.c
+++ b/examples/device/hid_composite_freertos/src/main.c
@@ -282,9 +282,9 @@ void hid_task(void* param)
// Invoked when sent REPORT successfully to host
// Application can use this to send the next report
// Note: For composite reports, report[0] is report ID
-void tud_hid_report_complete_cb(uint8_t itf, uint8_t const* report, uint8_t len)
+void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, uint8_t len)
{
- (void) itf;
+ (void) instance;
(void) len;
uint8_t next_report_id = report[0] + 1;
@@ -299,10 +299,10 @@ void tud_hid_report_complete_cb(uint8_t itf, uint8_t const* report, uint8_t len)
// Invoked when received GET_REPORT control request
// Application must fill buffer report's content and return its length.
// Return zero will cause the stack to STALL request
-uint16_t tud_hid_get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen)
+uint16_t tud_hid_get_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen)
{
// TODO not Implemented
- (void) itf;
+ (void) instance;
(void) report_id;
(void) report_type;
(void) buffer;
@@ -313,14 +313,33 @@ uint16_t tud_hid_get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t
// Invoked when received SET_REPORT control request or
// received data on OUT endpoint ( Report ID = 0, Type = 0 )
-void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize)
+void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize)
{
- // TODO set LED based on CAPLOCK, NUMLOCK etc...
- (void) itf;
- (void) report_id;
- (void) report_type;
- (void) buffer;
- (void) bufsize;
+ (void) instance;
+
+ if (report_type == HID_REPORT_TYPE_OUTPUT)
+ {
+ // Set keyboard LED e.g Capslock, Numlock etc...
+ if (report_id == REPORT_ID_KEYBOARD)
+ {
+ // bufsize should be (at least) 1
+ if ( bufsize < 1 ) return;
+
+ uint8_t const kbd_leds = buffer[0];
+
+ if (kbd_leds & KEYBOARD_LED_CAPSLOCK)
+ {
+ // Capslock On: disable blink, turn led on
+ xTimerStop(blinky_tm, portMAX_DELAY);
+ board_led_write(true);
+ }else
+ {
+ // Caplocks Off: back to normal blink
+ board_led_write(false);
+ xTimerStart(blinky_tm, portMAX_DELAY);
+ }
+ }
+ }
}
//--------------------------------------------------------------------+
diff --git a/examples/device/hid_composite_freertos/src/tusb_config.h b/examples/device/hid_composite_freertos/src/tusb_config.h
index 4b0458ef0..4fbccc294 100644
--- a/examples/device/hid_composite_freertos/src/tusb_config.h
+++ b/examples/device/hid_composite_freertos/src/tusb_config.h
@@ -67,8 +67,9 @@
// This examples use FreeRTOS
#define CFG_TUSB_OS OPT_OS_FREERTOS
-// CFG_TUSB_DEBUG is defined by compiler in DEBUG build
-// #define CFG_TUSB_DEBUG 0
+#ifndef CFG_TUSB_DEBUG
+#define CFG_TUSB_DEBUG 0
+#endif
/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.
* Tinyusb use follows macros to declare transferring memory so that they can be put
diff --git a/examples/device/hid_composite_freertos/src/usb_descriptors.c b/examples/device/hid_composite_freertos/src/usb_descriptors.c
index 1aff5e68e..791813fdf 100644
--- a/examples/device/hid_composite_freertos/src/usb_descriptors.c
+++ b/examples/device/hid_composite_freertos/src/usb_descriptors.c
@@ -36,6 +36,9 @@
#define USB_PID (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \
_PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4) )
+#define USB_VID 0xCafe
+#define USB_BCD 0x0200
+
//--------------------------------------------------------------------+
// Device Descriptors
//--------------------------------------------------------------------+
@@ -43,13 +46,13 @@ tusb_desc_device_t const desc_device =
{
.bLength = sizeof(tusb_desc_device_t),
.bDescriptorType = TUSB_DESC_DEVICE,
- .bcdUSB = 0x0200,
+ .bcdUSB = USB_BCD,
.bDeviceClass = 0x00,
.bDeviceSubClass = 0x00,
.bDeviceProtocol = 0x00,
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
- .idVendor = 0xCafe,
+ .idVendor = USB_VID,
.idProduct = USB_PID,
.bcdDevice = 0x0100,
@@ -82,9 +85,9 @@ uint8_t const desc_hid_report[] =
// Invoked when received GET HID REPORT DESCRIPTOR
// Application return pointer to descriptor
// Descriptor contents must exist long enough for transfer to complete
-uint8_t const * tud_hid_descriptor_report_cb(uint8_t itf)
+uint8_t const * tud_hid_descriptor_report_cb(uint8_t instance)
{
- (void) itf;
+ (void) instance;
return desc_hid_report;
}
@@ -111,6 +114,54 @@ uint8_t const desc_configuration[] =
TUD_HID_DESCRIPTOR(ITF_NUM_HID, 0, HID_ITF_PROTOCOL_NONE, sizeof(desc_hid_report), EPNUM_HID, CFG_TUD_HID_EP_BUFSIZE, 5)
};
+#if TUD_OPT_HIGH_SPEED
+// Per USB specs: high speed capable device must report device_qualifier and other_speed_configuration
+
+// 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 = 0x00,
+ .bDeviceSubClass = 0x00,
+ .bDeviceProtocol = 0x00,
+
+ .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
+
+ // other speed config is basically configuration with type = OHER_SPEED_CONFIG
+ memcpy(desc_other_speed_config, desc_configuration, CONFIG_TOTAL_LEN);
+ desc_other_speed_config[1] = TUSB_DESC_OTHER_SPEED_CONFIG;
+
+ // this example use the same configuration for both high and full speed mode
+ 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
diff --git a/examples/device/hid_generic_inout/boards.js b/examples/device/hid_generic_inout/boards.js
index e8437cf53..6b78231a7 100644
--- a/examples/device/hid_generic_inout/boards.js
+++ b/examples/device/hid_generic_inout/boards.js
@@ -1,4 +1,4 @@
module.exports = {
- "Feather_nRF52840":[0X239A,0X8029],
- "Metro_nRF52840":[0X239A,0X803F],
-} \ No newline at end of file
+ "Adafruit Boards":[0x239A,0xFFFF],
+ "TinyUSB example":[0xCAFE,0xFFFF]
+}
diff --git a/examples/device/hid_generic_inout/hid_test.js b/examples/device/hid_generic_inout/hid_test.js
index eed6b78e2..daa958fd5 100644
--- a/examples/device/hid_generic_inout/hid_test.js
+++ b/examples/device/hid_generic_inout/hid_test.js
@@ -5,8 +5,6 @@ var HID = require('node-hid');
var os = require('os')
// list of supported devices
var boards = require('./boards.js')
-
-var isWin = (os.platform() === 'win32');
var devices = HID.devices();
// this will choose any device found in the boards.js file
@@ -19,10 +17,8 @@ var message = "Hello World!"
// This means if you have characters in your string that are not Latin-1 you will have to add additional logic for character codes above 255
var messageBuffer = Array.from(message, function(c){return c.charCodeAt(0)});
-// Windows wants you to prepend a 0 to whatever you send
-if(isWin){
- messageBuffer.unshift(0)
-}
+// HIDAPI requires us to prepend a 0 for single hid report as dummy reportID
+messageBuffer.unshift(0)
// Some OSes expect that you always send a buffer that equals your report length
// So lets fill up the rest of the buffer with zeros
@@ -66,6 +62,7 @@ function anySupportedBoard(d) {
function isDevice(board,d){
- return d.vendorId==board[0] && d.productId==board[1];
+ // product id 0xff is matches all
+ return d.vendorId==board[0] && (d.productId==board[1] || board[1] == 0xFFFF);
}
diff --git a/examples/device/hid_generic_inout/hid_test.py b/examples/device/hid_generic_inout/hid_test.py
index c89d89062..a42930fb5 100644
--- a/examples/device/hid_generic_inout/hid_test.py
+++ b/examples/device/hid_generic_inout/hid_test.py
@@ -11,7 +11,10 @@ for dict in hid.enumerate(USB_VID):
if dev:
while True:
# Get input from console and encode to UTF8 for array of chars.
- str_out = input("Send text to HID Device : ").encode('utf-8')
+ # hid generic inout is single report therefore by HIDAPI requirement
+ # it must be preceeded with 0x00 as dummy reportID
+ str_out = b'\x00'
+ str_out += input("Send text to HID Device : ").encode('utf-8')
dev.write(str_out)
str_in = dev.read(64)
print("Received from HID Device:", str_in, '\n')
diff --git a/examples/device/hid_generic_inout/src/main.c b/examples/device/hid_generic_inout/src/main.c
index 65874f483..32185560e 100644
--- a/examples/device/hid_generic_inout/src/main.c
+++ b/examples/device/hid_generic_inout/src/main.c
@@ -36,16 +36,24 @@
*
* There are 2 ways to test the sketch
* 1. Using nodejs
- * - Install nodejs and npm to your PC
- * - Install excellent node-hid (https://github.com/node-hid/node-hid) by
- * $ npm install node-hid
- * - Run provided hid test script
- * $ node hid_test.js
+ * - Install nodejs and npm to your PC
*
- * 2. Using python hidRun
- * - Python and `hid` package is required, for installation please follow https://pypi.org/project/hid/
- * - Run provided hid test script to send and receive data to this device.
- * $ python3 hid_test.py
+ * - Install excellent node-hid (https://github.com/node-hid/node-hid) by
+ * $ npm install node-hid
+ *
+ * - Run provided hid test script
+ * $ node hid_test.js
+ *
+ * 2. Using python
+ * - Install `hid` package (https://pypi.org/project/hid/) by
+ * $ pip install hid
+ *
+ * - hid package replies on hidapi (https://github.com/libusb/hidapi) for backend,
+ * which already available in Linux. However on windows, you may need to download its dlls from their release page and
+ * copy it over to folder where python is installed.
+ *
+ * - Run provided hid test script to send and receive data to this device.
+ * $ python3 hid_test.py
*/
//--------------------------------------------------------------------+
diff --git a/examples/device/hid_generic_inout/src/usb_descriptors.c b/examples/device/hid_generic_inout/src/usb_descriptors.c
index 5a2f5ffdc..5dabf42a3 100644
--- a/examples/device/hid_generic_inout/src/usb_descriptors.c
+++ b/examples/device/hid_generic_inout/src/usb_descriptors.c
@@ -101,7 +101,7 @@ enum
uint8_t const desc_configuration[] =
{
// Config number, interface count, string index, total length, attribute, power in mA
- TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
+ TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
// Interface number, string index, protocol, report descriptor len, EP In & Out address, size & polling interval
TUD_HID_INOUT_DESCRIPTOR(ITF_NUM_HID, 0, HID_ITF_PROTOCOL_NONE, sizeof(desc_hid_report), EPNUM_HID, 0x80 | EPNUM_HID, CFG_TUD_HID_EP_BUFSIZE, 10)
diff --git a/examples/device/midi_test/src/main.c b/examples/device/midi_test/src/main.c
index 9e0e82a10..193748477 100644
--- a/examples/device/midi_test/src/main.c
+++ b/examples/device/midi_test/src/main.c
@@ -134,7 +134,7 @@ void midi_task(void)
uint8_t packet[4];
while ( tud_midi_available() ) tud_midi_packet_read(packet);
- // send note every 1000 ms
+ // send note periodically
if (board_millis() - start_ms < 286) return; // not enough time
start_ms += 286;
diff --git a/examples/device/midi_test/src/usb_descriptors.c b/examples/device/midi_test/src/usb_descriptors.c
index 9d92a7753..bd5a0eeab 100644
--- a/examples/device/midi_test/src/usb_descriptors.c
+++ b/examples/device/midi_test/src/usb_descriptors.c
@@ -91,7 +91,7 @@ enum
uint8_t const desc_fs_configuration[] =
{
// Config number, interface count, string index, total length, attribute, power in mA
- TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
+ TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
// Interface number, string index, EP Out & EP In address, EP size
TUD_MIDI_DESCRIPTOR(ITF_NUM_MIDI, 0, EPNUM_MIDI, 0x80 | EPNUM_MIDI, 64)
@@ -101,7 +101,7 @@ uint8_t const desc_fs_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, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
+ TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
// Interface number, string index, EP Out & EP In address, EP size
TUD_MIDI_DESCRIPTOR(ITF_NUM_MIDI, 0, EPNUM_MIDI, 0x80 | EPNUM_MIDI, 512)
diff --git a/examples/device/msc_dual_lun/src/msc_disk_dual.c b/examples/device/msc_dual_lun/src/msc_disk_dual.c
index 2ab050da8..18d3ca0d7 100644
--- a/examples/device/msc_dual_lun/src/msc_disk_dual.c
+++ b/examples/device/msc_dual_lun/src/msc_disk_dual.c
@@ -268,16 +268,33 @@ bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, boo
// Copy disk's data to buffer (up to bufsize) and return number of copied bytes.
int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize)
{
+ // out of ramdisk
+ if ( lba >= DISK_BLOCK_NUM ) return -1;
+
uint8_t const* addr = (lun ? msc_disk1[lba] : msc_disk0[lba]) + offset;
memcpy(buffer, addr, bufsize);
return bufsize;
}
+bool tud_msc_is_writable_cb (uint8_t lun)
+{
+ (void) lun;
+
+#ifdef CFG_EXAMPLE_MSC_READONLY
+ return false;
+#else
+ return true;
+#endif
+}
+
// Callback invoked when received WRITE10 command.
// Process data in buffer to disk's storage and return number of written bytes
int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize)
{
+ // out of ramdisk
+ if ( lba >= DISK_BLOCK_NUM ) return -1;
+
#ifndef CFG_EXAMPLE_MSC_READONLY
uint8_t* addr = (lun ? msc_disk1[lba] : msc_disk0[lba]) + offset;
memcpy(addr, buffer, bufsize);
@@ -296,7 +313,7 @@ int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer,
// read10 & write10 has their own callback and MUST not be handled here
void const* response = NULL;
- uint16_t resplen = 0;
+ int32_t resplen = 0;
// most scsi handled is input
bool in_xfer = true;
diff --git a/examples/device/msc_dual_lun/src/usb_descriptors.c b/examples/device/msc_dual_lun/src/usb_descriptors.c
index 138de62a3..7e194ea7a 100644
--- a/examples/device/msc_dual_lun/src/usb_descriptors.c
+++ b/examples/device/msc_dual_lun/src/usb_descriptors.c
@@ -99,7 +99,7 @@ enum
uint8_t const desc_fs_configuration[] =
{
// Config number, interface count, string index, total length, attribute, power in mA
- TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
+ TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
// Interface number, string index, EP Out & EP In address, EP size
TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 0, EPNUM_MSC_OUT, EPNUM_MSC_IN, 64),
@@ -109,7 +109,7 @@ uint8_t const desc_fs_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, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
+ TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
// Interface number, string index, EP Out & EP In address, EP size
TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 0, EPNUM_MSC_OUT, EPNUM_MSC_IN, 512),
diff --git a/examples/device/net_lwip_webserver/src/main.c b/examples/device/net_lwip_webserver/src/main.c
index 27adce86f..80831921a 100644
--- a/examples/device/net_lwip_webserver/src/main.c
+++ b/examples/device/net_lwip_webserver/src/main.c
@@ -178,21 +178,10 @@ bool tud_network_recv_cb(const uint8_t *src, uint16_t size)
uint16_t tud_network_xmit_cb(uint8_t *dst, void *ref, uint16_t arg)
{
struct pbuf *p = (struct pbuf *)ref;
- struct pbuf *q;
- uint16_t len = 0;
(void)arg; /* unused for this example */
- /* traverse the "pbuf chain"; see ./lwip/src/core/pbuf.c for more info */
- for(q = p; q != NULL; q = q->next)
- {
- memcpy(dst, (char *)q->payload, q->len);
- dst += q->len;
- len += q->len;
- if (q->len == q->tot_len) break;
- }
-
- return len;
+ return pbuf_copy_partial(p, dst, p->tot_len, 0);
}
static void service_traffic(void)
diff --git a/examples/device/net_lwip_webserver/src/usb_descriptors.c b/examples/device/net_lwip_webserver/src/usb_descriptors.c
index 1a77c39d7..71e6c4582 100644
--- a/examples/device/net_lwip_webserver/src/usb_descriptors.c
+++ b/examples/device/net_lwip_webserver/src/usb_descriptors.c
@@ -107,8 +107,8 @@ uint8_t const * tud_descriptor_device_cb(void)
#define EPNUM_NET_OUT 0x02
#define EPNUM_NET_IN 0x82
-#elif CFG_TUSB_MCU == OPT_MCU_SAMG
- // SAMG doesn't support a same endpoint number with different direction IN and OUT
+#elif CFG_TUSB_MCU == OPT_MCU_SAMG || CFG_TUSB_MCU == OPT_MCU_SAMX7X
+ // SAMG & SAME70 don't support a same endpoint number with different direction IN and OUT
// e.g EP1 OUT & EP1 IN cannot exist together
#define EPNUM_NET_NOTIF 0x81
#define EPNUM_NET_OUT 0x02
diff --git a/examples/device/uac2_headset/.skip.MCU_LPC11UXX b/examples/device/uac2_headset/.skip.MCU_LPC11UXX
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/examples/device/uac2_headset/.skip.MCU_LPC11UXX
diff --git a/examples/device/uac2_headset/.skip.MCU_LPC13XX b/examples/device/uac2_headset/.skip.MCU_LPC13XX
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/examples/device/uac2_headset/.skip.MCU_LPC13XX
diff --git a/examples/device/uac2_headset/.skip.MCU_NUC121 b/examples/device/uac2_headset/.skip.MCU_NUC121
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/examples/device/uac2_headset/.skip.MCU_NUC121
diff --git a/examples/device/uac2_headset/src/main.c b/examples/device/uac2_headset/src/main.c
index 1b6a770a3..790af088f 100644
--- a/examples/device/uac2_headset/src/main.c
+++ b/examples/device/uac2_headset/src/main.c
@@ -34,9 +34,15 @@
// MACRO CONSTANT TYPEDEF PROTOTYPES
//--------------------------------------------------------------------+
-#ifndef AUDIO_SAMPLE_RATE
-#define AUDIO_SAMPLE_RATE 48000
+// List of supported sample rates
+#if defined(__RX__)
+const uint32_t sample_rates[] = {44100, 48000};
+#else
+const uint32_t sample_rates[] = {44100, 48000, 88200, 96000};
#endif
+uint32_t current_sample_rate = 44100;
+
+#define N_SAMPLE_RATES TU_ARRAY_SIZE(sample_rates)
/* Blink pattern
* - 25 ms : streaming data
@@ -76,11 +82,16 @@ int8_t mute[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX + 1]; // +1 for master chan
int16_t volume[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX + 1]; // +1 for master channel 0
// Buffer for microphone data
-int16_t mic_buf[1000];
+int32_t mic_buf[CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ / 4];
// Buffer for speaker data
-int16_t spk_buf[1000];
+int32_t spk_buf[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ / 4];
// Speaker data size received in the last frame
int spk_data_size;
+// Resolution per format
+const uint8_t resolutions_per_format[CFG_TUD_AUDIO_FUNC_1_N_FORMATS] = {CFG_TUD_AUDIO_FUNC_1_FORMAT_1_RESOLUTION_RX,
+ CFG_TUD_AUDIO_FUNC_1_FORMAT_2_RESOLUTION_RX};
+// Current resolution, update on format change
+uint8_t current_resolution;
void led_blinking_task(void);
void audio_task(void);
@@ -135,55 +146,35 @@ void tud_resume_cb(void)
blink_interval_ms = BLINK_MOUNTED;
}
-typedef struct TU_ATTR_PACKED
-{
- union
- {
- struct TU_ATTR_PACKED
- {
- uint8_t recipient : 5; ///< Recipient type tusb_request_recipient_t.
- uint8_t type : 2; ///< Request type tusb_request_type_t.
- uint8_t direction : 1; ///< Direction type. tusb_dir_t
- } bmRequestType_bit;
-
- uint8_t bmRequestType;
- };
-
- uint8_t bRequest; ///< Request type audio_cs_req_t
- uint8_t bChannelNumber;
- uint8_t bControlSelector;
- union
- {
- uint8_t bInterface;
- uint8_t bEndpoint;
- };
- uint8_t bEntityID;
- uint16_t wLength;
-} audio_control_request_t;
-
// Helper for clock get requests
static bool tud_audio_clock_get_request(uint8_t rhport, audio_control_request_t const *request)
{
TU_ASSERT(request->bEntityID == UAC2_ENTITY_CLOCK);
- // Example supports only single frequency, same value will be used for current value and range
if (request->bControlSelector == AUDIO_CS_CTRL_SAM_FREQ)
{
if (request->bRequest == AUDIO_CS_REQ_CUR)
{
- TU_LOG2("Clock get current freq %u\r\n", AUDIO_SAMPLE_RATE);
+ TU_LOG1("Clock get current freq %u\r\n", current_sample_rate);
- audio_control_cur_4_t curf = { tu_htole32(AUDIO_SAMPLE_RATE) };
+ audio_control_cur_4_t curf = { tu_htole32(current_sample_rate) };
return tud_audio_buffer_and_schedule_control_xfer(rhport, (tusb_control_request_t const *)request, &curf, sizeof(curf));
}
else if (request->bRequest == AUDIO_CS_REQ_RANGE)
{
- audio_control_range_4_n_t(1) rangef =
+ audio_control_range_4_n_t(N_SAMPLE_RATES) rangef =
{
- .wNumSubRanges = tu_htole16(1),
- .subrange[0] = { tu_htole32(AUDIO_SAMPLE_RATE), tu_htole32(AUDIO_SAMPLE_RATE), 0}
+ .wNumSubRanges = tu_htole16(N_SAMPLE_RATES)
};
- TU_LOG2("Clock get freq range (%d, %d, %d)\r\n", (int)rangef.subrange[0].bMin, (int)rangef.subrange[0].bMax, (int)rangef.subrange[0].bRes);
+ TU_LOG1("Clock get %d freq ranges\r\n", N_SAMPLE_RATES);
+ for(uint8_t i = 0; i < N_SAMPLE_RATES; i++)
+ {
+ rangef.subrange[i].bMin = sample_rates[i];
+ rangef.subrange[i].bMax = sample_rates[i];
+ rangef.subrange[i].bRes = 0;
+ TU_LOG1("Range %d (%d, %d, %d)\r\n", i, (int)rangef.subrange[i].bMin, (int)rangef.subrange[i].bMax, (int)rangef.subrange[i].bRes);
+ }
+
return tud_audio_buffer_and_schedule_control_xfer(rhport, (tusb_control_request_t const *)request, &rangef, sizeof(rangef));
}
}
@@ -191,7 +182,7 @@ static bool tud_audio_clock_get_request(uint8_t rhport, audio_control_request_t
request->bRequest == AUDIO_CS_REQ_CUR)
{
audio_control_cur_1_t cur_valid = { .bCur = 1 };
- TU_LOG2("Clock get is valid %u\r\n", cur_valid.bCur);
+ TU_LOG1("Clock get is valid %u\r\n", cur_valid.bCur);
return tud_audio_buffer_and_schedule_control_xfer(rhport, (tusb_control_request_t const *)request, &cur_valid, sizeof(cur_valid));
}
TU_LOG1("Clock get request not supported, entity = %u, selector = %u, request = %u\r\n",
@@ -199,6 +190,32 @@ static bool tud_audio_clock_get_request(uint8_t rhport, audio_control_request_t
return false;
}
+// Helper for clock set requests
+static bool tud_audio_clock_set_request(uint8_t rhport, audio_control_request_t const *request, uint8_t const *buf)
+{
+ (void)rhport;
+
+ TU_ASSERT(request->bEntityID == UAC2_ENTITY_CLOCK);
+ TU_VERIFY(request->bRequest == AUDIO_CS_REQ_CUR);
+
+ if (request->bControlSelector == AUDIO_CS_CTRL_SAM_FREQ)
+ {
+ TU_VERIFY(request->wLength == sizeof(audio_control_cur_4_t));
+
+ current_sample_rate = ((audio_control_cur_4_t *)buf)->bCur;
+
+ TU_LOG1("Clock set current freq: %d\r\n", current_sample_rate);
+
+ return true;
+ }
+ else
+ {
+ TU_LOG1("Clock set request not supported, entity = %u, selector = %u, request = %u\r\n",
+ request->bEntityID, request->bControlSelector, request->bRequest);
+ return false;
+ }
+}
+
// Helper for feature unit get requests
static bool tud_audio_feature_unit_get_request(uint8_t rhport, audio_control_request_t const *request)
{
@@ -207,7 +224,7 @@ static bool tud_audio_feature_unit_get_request(uint8_t rhport, audio_control_req
if (request->bControlSelector == AUDIO_FU_CTRL_MUTE && request->bRequest == AUDIO_CS_REQ_CUR)
{
audio_control_cur_1_t mute1 = { .bCur = mute[request->bChannelNumber] };
- TU_LOG2("Get channel %u mute %d\r\n", request->bChannelNumber, mute1.bCur);
+ TU_LOG1("Get channel %u mute %d\r\n", request->bChannelNumber, mute1.bCur);
return tud_audio_buffer_and_schedule_control_xfer(rhport, (tusb_control_request_t const *)request, &mute1, sizeof(mute1));
}
else if (UAC2_ENTITY_SPK_FEATURE_UNIT && request->bControlSelector == AUDIO_FU_CTRL_VOLUME)
@@ -218,14 +235,14 @@ static bool tud_audio_feature_unit_get_request(uint8_t rhport, audio_control_req
.wNumSubRanges = tu_htole16(1),
.subrange[0] = { .bMin = tu_htole16(-VOLUME_CTRL_50_DB), tu_htole16(VOLUME_CTRL_0_DB), tu_htole16(256) }
};
- TU_LOG2("Get channel %u volume range (%d, %d, %u) dB\r\n", request->bChannelNumber,
+ TU_LOG1("Get channel %u volume range (%d, %d, %u) dB\r\n", request->bChannelNumber,
range_vol.subrange[0].bMin / 256, range_vol.subrange[0].bMax / 256, range_vol.subrange[0].bRes / 256);
return tud_audio_buffer_and_schedule_control_xfer(rhport, (tusb_control_request_t const *)request, &range_vol, sizeof(range_vol));
}
else if (request->bRequest == AUDIO_CS_REQ_CUR)
{
audio_control_cur_2_t cur_vol = { .bCur = tu_htole16(volume[request->bChannelNumber]) };
- TU_LOG2("Get channel %u volume %u dB\r\n", request->bChannelNumber, cur_vol.bCur);
+ TU_LOG1("Get channel %u volume %d dB\r\n", request->bChannelNumber, cur_vol.bCur / 256);
return tud_audio_buffer_and_schedule_control_xfer(rhport, (tusb_control_request_t const *)request, &cur_vol, sizeof(cur_vol));
}
}
@@ -249,7 +266,7 @@ static bool tud_audio_feature_unit_set_request(uint8_t rhport, audio_control_req
mute[request->bChannelNumber] = ((audio_control_cur_1_t *)buf)->bCur;
- TU_LOG2("Set channel %d Mute: %d\r\n", request->bChannelNumber, mute[request->bChannelNumber]);
+ TU_LOG1("Set channel %d Mute: %d\r\n", request->bChannelNumber, mute[request->bChannelNumber]);
return true;
}
@@ -259,7 +276,7 @@ static bool tud_audio_feature_unit_set_request(uint8_t rhport, audio_control_req
volume[request->bChannelNumber] = ((audio_control_cur_2_t const *)buf)->bCur;
- TU_LOG2("Set channel %d volume: %d dB\r\n", request->bChannelNumber, volume[request->bChannelNumber] / 256);
+ TU_LOG1("Set channel %d volume: %d dB\r\n", request->bChannelNumber, volume[request->bChannelNumber] / 256);
return true;
}
@@ -299,7 +316,8 @@ bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p
if (request->bEntityID == UAC2_ENTITY_SPK_FEATURE_UNIT)
return tud_audio_feature_unit_set_request(rhport, request, buf);
-
+ if (request->bEntityID == UAC2_ENTITY_CLOCK)
+ return tud_audio_clock_set_request(rhport, request, buf);
TU_LOG1("Set request not handled, entity = %d, selector = %d, request = %d\r\n",
request->bEntityID, request->bControlSelector, request->bRequest);
@@ -329,6 +347,13 @@ bool tud_audio_set_itf_cb(uint8_t rhport, tusb_control_request_t const * p_reque
if (ITF_NUM_AUDIO_STREAMING_SPK == itf && alt != 0)
blink_interval_ms = BLINK_STREAMING;
+ // Clear buffer when streaming format is changed
+ spk_data_size = 0;
+ if(alt != 0)
+ {
+ current_resolution = resolutions_per_format[alt-1];
+ }
+
return true;
}
@@ -362,20 +387,40 @@ void audio_task(void)
{
// When new data arrived, copy data from speaker buffer, to microphone buffer
// and send it over
+ // Only support speaker & headphone both have the same resolution
+ // If one is 16bit another is 24bit be care of LOUD noise !
if (spk_data_size)
{
- int16_t *src = spk_buf;
- int16_t *limit = spk_buf + spk_data_size / 2;
- int16_t *dst = mic_buf;
- while (src < limit)
+ if (current_resolution == 16)
{
- // Combine two channels into one
- int32_t left = *src++;
- int32_t right = *src++;
- *dst++ = (int16_t)((left + right) / 2);
+ int16_t *src = (int16_t*)spk_buf;
+ int16_t *limit = (int16_t*)spk_buf + spk_data_size / 2;
+ int16_t *dst = (int16_t*)mic_buf;
+ while (src < limit)
+ {
+ // Combine two channels into one
+ int32_t left = *src++;
+ int32_t right = *src++;
+ *dst++ = (left >> 1) + (right >> 1);
+ }
+ tud_audio_write((uint8_t *)mic_buf, spk_data_size / 2);
+ spk_data_size = 0;
+ }
+ else if (current_resolution == 24)
+ {
+ int32_t *src = spk_buf;
+ int32_t *limit = spk_buf + spk_data_size / 4;
+ int32_t *dst = mic_buf;
+ while (src < limit)
+ {
+ // Combine two channels into one
+ int32_t left = *src++;
+ int32_t right = *src++;
+ *dst++ = ((left >> 1) + (right >> 1)) & 0xffffff00;
+ }
+ tud_audio_write((uint8_t *)mic_buf, spk_data_size / 2);
+ spk_data_size = 0;
}
- tud_audio_write((uint8_t *)mic_buf, spk_data_size / 2);
- spk_data_size = 0;
}
}
diff --git a/examples/device/uac2_headset/src/tusb_config.h b/examples/device/uac2_headset/src/tusb_config.h
index 88f9efcff..e8d93f56a 100644
--- a/examples/device/uac2_headset/src/tusb_config.h
+++ b/examples/device/uac2_headset/src/tusb_config.h
@@ -93,33 +93,61 @@ extern "C" {
//--------------------------------------------------------------------
// AUDIO CLASS DRIVER CONFIGURATION
//--------------------------------------------------------------------
-#define CFG_TUD_AUDIO_IN_PATH (CFG_TUD_AUDIO)
-#define CFG_TUD_AUDIO_OUT_PATH (CFG_TUD_AUDIO)
-//#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN 220 // This equals TUD_AUDIO_HEADSET_STEREO_DESC_LEN, however, including it from usb_descriptors.h is not possible due to some strange include hassle
-#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN TUD_AUDIO_HEADSET_STEREO_DESC_LEN
+#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN TUD_AUDIO_HEADSET_STEREO_DESC_LEN
+
+// How many formats are used, need to adjust USB descriptor if changed
+#define CFG_TUD_AUDIO_FUNC_1_N_FORMATS 2
// Audio format type I specifications
-#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX 1
-#define CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX 2
-#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX 2
-#define CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_RX 2
-#define CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP 0
+#if defined(__RX__)
+#define CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE 48000 // 16bit/48kHz is the best quality for Renesas RX
+#else
+#define CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE 96000 // 24bit/96kHz is the best quality for full-speed, high-speed is needed beyond this
+#endif
+#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX 1
+#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX 2
+
+// 16bit in 16bit slots
+#define CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_TX 2
+#define CFG_TUD_AUDIO_FUNC_1_FORMAT_1_RESOLUTION_TX 16
+#define CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_RX 2
+#define CFG_TUD_AUDIO_FUNC_1_FORMAT_1_RESOLUTION_RX 16
+
+#if defined(__RX__)
+// 8bit in 8bit slots
+#define CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_TX 1
+#define CFG_TUD_AUDIO_FUNC_1_FORMAT_2_RESOLUTION_TX 8
+#define CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_RX 1
+#define CFG_TUD_AUDIO_FUNC_1_FORMAT_2_RESOLUTION_RX 8
+#else
+// 24bit in 32bit slots
+#define CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_TX 4
+#define CFG_TUD_AUDIO_FUNC_1_FORMAT_2_RESOLUTION_TX 24
+#define CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_RX 4
+#define CFG_TUD_AUDIO_FUNC_1_FORMAT_2_RESOLUTION_RX 24
+#endif
// EP and buffer size - for isochronous EP´s, the buffer and EP size are equal (different sizes would not make sense)
#define CFG_TUD_AUDIO_ENABLE_EP_IN 1
-#define CFG_TUD_AUDIO_EP_SZ_IN (CFG_TUD_AUDIO_IN_PATH * (48 + 1) * (CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX) * (CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX)) // 48 Samples (48 kHz) x 2 Bytes/Sample x n Channels
-#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ CFG_TUD_AUDIO_EP_SZ_IN
-#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX CFG_TUD_AUDIO_EP_SZ_IN // Maximum EP IN size for all AS alternate settings used
+
+#define CFG_TUD_AUDIO_FUNC_1_FORMAT_1_EP_SZ_IN TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX)
+#define CFG_TUD_AUDIO_FUNC_1_FORMAT_2_EP_SZ_IN TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX)
+
+#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ TU_MAX(CFG_TUD_AUDIO_FUNC_1_FORMAT_1_EP_SZ_IN, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_EP_SZ_IN)*2
+#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX TU_MAX(CFG_TUD_AUDIO_FUNC_1_FORMAT_1_EP_SZ_IN, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_EP_SZ_IN) // Maximum EP IN size for all AS alternate settings used
// EP and buffer size - for isochronous EP´s, the buffer and EP size are equal (different sizes would not make sense)
#define CFG_TUD_AUDIO_ENABLE_EP_OUT 1
-#define CFG_TUD_AUDIO_EP_OUT_SZ (CFG_TUD_AUDIO_OUT_PATH * ((48 + CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP) * (CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_RX) * (CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX))) // N Samples (N kHz) x 2 Bytes/Sample x n Channels
-#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ CFG_TUD_AUDIO_EP_OUT_SZ*3
-#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX CFG_TUD_AUDIO_EP_OUT_SZ // Maximum EP IN size for all AS alternate settings used
+
+#define CFG_TUD_AUDIO_UNC_1_FORMAT_1_EP_SZ_OUT TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX)
+#define CFG_TUD_AUDIO_UNC_1_FORMAT_2_EP_SZ_OUT TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX)
+
+#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ TU_MAX(CFG_TUD_AUDIO_UNC_1_FORMAT_1_EP_SZ_OUT, CFG_TUD_AUDIO_UNC_1_FORMAT_2_EP_SZ_OUT)*2
+#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX TU_MAX(CFG_TUD_AUDIO_UNC_1_FORMAT_1_EP_SZ_OUT, CFG_TUD_AUDIO_UNC_1_FORMAT_2_EP_SZ_OUT) // Maximum EP IN size for all AS alternate settings used
// 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
+#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_headset/src/usb_descriptors.c b/examples/device/uac2_headset/src/usb_descriptors.c
index cd749eb65..64fa3c25b 100644
--- a/examples/device/uac2_headset/src/usb_descriptors.c
+++ b/examples/device/uac2_headset/src/usb_descriptors.c
@@ -79,21 +79,29 @@ uint8_t const * tud_descriptor_device_cb(void)
#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 etc ...
-#define EPNUM_AUDIO 0x03
+#define EPNUM_AUDIO_IN 0x03
+#define EPNUM_AUDIO_OUT 0x03
#elif CFG_TUSB_MCU == OPT_MCU_NRF5X
// ISO endpoints for NRF5x are fixed to 0x08 (0x88)
-#define EPNUM_AUDIO 0x08
+#define EPNUM_AUDIO_IN 0x08
+#define EPNUM_AUDIO_OUT 0x08
+#elif CFG_TUSB_MCU == OPT_MCU_SAMG || CFG_TUSB_MCU == OPT_MCU_SAMX7X
+// SAMG & SAME70 don't support a same endpoint number with different direction IN and OUT
+// e.g EP1 OUT & EP1 IN cannot exist together
+#define EPNUM_AUDIO_IN 0x01
+#define EPNUM_AUDIO_OUT 0x02
#else
-#define EPNUM_AUDIO 0x01
+#define EPNUM_AUDIO_IN 0x01
+#define EPNUM_AUDIO_OUT 0x01
#endif
uint8_t const desc_configuration[] =
{
// Interface count, string index, total length, attribute, power in mA
- TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
+ TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
// Interface number, string index, EP Out & EP In address, EP size
- TUD_AUDIO_HEADSET_STEREO_DESCRIPTOR(2, 2, 16, EPNUM_AUDIO, CFG_TUD_AUDIO_EP_OUT_SZ, EPNUM_AUDIO | 0x80, CFG_TUD_AUDIO_EP_SZ_IN)
+ TUD_AUDIO_HEADSET_STEREO_DESCRIPTOR(2, EPNUM_AUDIO_OUT, EPNUM_AUDIO_IN | 0x80)
};
// Invoked when received GET CONFIGURATION DESCRIPTOR
diff --git a/examples/device/uac2_headset/src/usb_descriptors.h b/examples/device/uac2_headset/src/usb_descriptors.h
index d9c5a63a7..d9510ea4f 100644
--- a/examples/device/uac2_headset/src/usb_descriptors.h
+++ b/examples/device/uac2_headset/src/usb_descriptors.h
@@ -55,21 +55,36 @@ enum
+ TUD_AUDIO_DESC_OUTPUT_TERM_LEN\
+ TUD_AUDIO_DESC_INPUT_TERM_LEN\
+ TUD_AUDIO_DESC_OUTPUT_TERM_LEN\
+ /* Interface 1, Alternate 0 */\
+ TUD_AUDIO_DESC_STD_AS_INT_LEN\
+ /* Interface 1, Alternate 0 */\
+ TUD_AUDIO_DESC_STD_AS_INT_LEN\
+ TUD_AUDIO_DESC_CS_AS_INT_LEN\
+ TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN\
+ TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN\
+ TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN\
+ /* Interface 1, Alternate 2 */\
+ TUD_AUDIO_DESC_STD_AS_INT_LEN\
+ + TUD_AUDIO_DESC_CS_AS_INT_LEN\
+ + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN\
+ + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN\
+ + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN\
+ /* Interface 2, Alternate 0 */\
+ + TUD_AUDIO_DESC_STD_AS_INT_LEN\
+ /* Interface 2, Alternate 1 */\
+ + TUD_AUDIO_DESC_STD_AS_INT_LEN\
+ + TUD_AUDIO_DESC_CS_AS_INT_LEN\
+ + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN\
+ + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN\
+ + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN\
+ /* Interface 2, Alternate 2 */\
+ TUD_AUDIO_DESC_STD_AS_INT_LEN\
+ TUD_AUDIO_DESC_CS_AS_INT_LEN\
+ TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN\
+ TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN\
+ TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN)
-
-#define TUD_AUDIO_HEADSET_STEREO_DESCRIPTOR(_stridx, _nBytesPerSample, _nBitsUsedPerSample, _epout, _epoutsize, _epin, _epinsize) \
+#define TUD_AUDIO_HEADSET_STEREO_DESCRIPTOR(_stridx, _epout, _epin) \
/* Standard Interface Association Descriptor (IAD) */\
TUD_AUDIO_DESC_IAD(/*_firstitfs*/ ITF_NUM_AUDIO_CONTROL, /*_nitfs*/ ITF_NUM_TOTAL, /*_stridx*/ 0x00),\
/* Standard AC Interface Descriptor(4.7.1) */\
@@ -77,13 +92,13 @@ enum
/* Class-Specific AC Interface Header Descriptor(4.7.2) */\
TUD_AUDIO_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO_FUNC_HEADSET, /*_totallen*/ TUD_AUDIO_DESC_CLK_SRC_LEN+TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL_LEN+TUD_AUDIO_DESC_INPUT_TERM_LEN+TUD_AUDIO_DESC_OUTPUT_TERM_LEN+TUD_AUDIO_DESC_INPUT_TERM_LEN+TUD_AUDIO_DESC_OUTPUT_TERM_LEN, /*_ctrl*/ AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS),\
/* Clock Source Descriptor(4.7.2.1) */\
- TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ UAC2_ENTITY_CLOCK, /*_attr*/ 3, /*_ctrl*/ 5, /*_assocTerm*/ 0x00, /*_stridx*/ 0x00), \
+ TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ UAC2_ENTITY_CLOCK, /*_attr*/ 3, /*_ctrl*/ 7, /*_assocTerm*/ 0x00, /*_stridx*/ 0x00), \
/* Input Terminal Descriptor(4.7.2.4) */\
TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ UAC2_ENTITY_SPK_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, /*_clkid*/ UAC2_ENTITY_CLOCK, /*_nchannelslogical*/ 0x02, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ 0 * (AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00),\
/* Feature Unit Descriptor(4.7.2.8) */\
TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL(/*_unitid*/ UAC2_ENTITY_SPK_FEATURE_UNIT, /*_srcid*/ UAC2_ENTITY_SPK_INPUT_TERMINAL, /*_ctrlch0master*/ (AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS), /*_ctrlch1*/ (AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS), /*_ctrlch2*/ (AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS), /*_stridx*/ 0x00),\
/* Output Terminal Descriptor(4.7.2.5) */\
- TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ UAC2_ENTITY_SPK_OUTPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_OUT_GENERIC_SPEAKER, /*_assocTerm*/ 0x00, /*_srcid*/ UAC2_ENTITY_SPK_FEATURE_UNIT, /*_clkid*/ UAC2_ENTITY_CLOCK, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00),\
+ TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ UAC2_ENTITY_SPK_OUTPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_OUT_HEADPHONES, /*_assocTerm*/ 0x00, /*_srcid*/ UAC2_ENTITY_SPK_FEATURE_UNIT, /*_clkid*/ UAC2_ENTITY_CLOCK, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00),\
/* Input Terminal Descriptor(4.7.2.4) */\
TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ UAC2_ENTITY_MIC_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_IN_GENERIC_MIC, /*_assocTerm*/ 0x00, /*_clkid*/ UAC2_ENTITY_CLOCK, /*_nchannelslogical*/ 0x01, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ 0 * (AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00),\
/* Output Terminal Descriptor(4.7.2.5) */\
@@ -95,26 +110,46 @@ enum
/* Interface 1, Alternate 1 - alternate interface for data streaming */\
TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)(ITF_NUM_AUDIO_STREAMING_SPK), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x05),\
/* Class-Specific AS Interface Descriptor(4.9.2) */\
- TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ UAC2_ENTITY_SPK_INPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ 0x02, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\
+ TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ UAC2_ENTITY_SPK_INPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\
/* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\
- TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample),\
+ TUD_AUDIO_DESC_TYPE_I_FORMAT(CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_RESOLUTION_RX),\
/* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\
- TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ADAPTIVE | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epoutsize, /*_interval*/ (CFG_TUSB_RHPORT0_MODE & OPT_MODE_HIGH_SPEED) ? 0x04 : 0x01),\
+ TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ADAPTIVE | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX), /*_interval*/ 0x01),\
+ /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\
+ TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_MILLISEC, /*_lockdelay*/ 0x0001),\
+ /* Interface 1, Alternate 2 - alternate interface for data streaming */\
+ TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)(ITF_NUM_AUDIO_STREAMING_SPK), /*_altset*/ 0x02, /*_nEPs*/ 0x01, /*_stridx*/ 0x05),\
+ /* Class-Specific AS Interface Descriptor(4.9.2) */\
+ TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ UAC2_ENTITY_SPK_INPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\
+ /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\
+ TUD_AUDIO_DESC_TYPE_I_FORMAT(CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_RESOLUTION_RX),\
+ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\
+ TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ADAPTIVE | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX), /*_interval*/ 0x01),\
/* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\
TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_MILLISEC, /*_lockdelay*/ 0x0001),\
/* Standard AS Interface Descriptor(4.9.1) */\
/* Interface 2, Alternate 0 - default alternate setting with 0 bandwidth */\
TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)(ITF_NUM_AUDIO_STREAMING_MIC), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x04),\
/* Standard AS Interface Descriptor(4.9.1) */\
- /* Interface 1, Alternate 1 - alternate interface for data streaming */\
+ /* Interface 2, Alternate 1 - alternate interface for data streaming */\
TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)(ITF_NUM_AUDIO_STREAMING_MIC), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x04),\
/* Class-Specific AS Interface Descriptor(4.9.2) */\
- TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ UAC2_ENTITY_MIC_OUTPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ 0x01, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\
+ TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ UAC2_ENTITY_MIC_OUTPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\
+ /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\
+ TUD_AUDIO_DESC_TYPE_I_FORMAT(CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_RESOLUTION_TX),\
+ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\
+ TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX), /*_interval*/ 0x01),\
+ /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\
+ TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000),\
+ /* Interface 2, Alternate 2 - alternate interface for data streaming */\
+ TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)(ITF_NUM_AUDIO_STREAMING_MIC), /*_altset*/ 0x02, /*_nEPs*/ 0x01, /*_stridx*/ 0x04),\
+ /* Class-Specific AS Interface Descriptor(4.9.2) */\
+ TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ UAC2_ENTITY_MIC_OUTPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\
/* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\
- TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample),\
+ TUD_AUDIO_DESC_TYPE_I_FORMAT(CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_RESOLUTION_TX),\
/* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\
- TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epinsize, /*_interval*/ (CFG_TUSB_RHPORT0_MODE & OPT_MODE_HIGH_SPEED) ? 0x04 : 0x01),\
+ TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX), /*_interval*/ 0x01),\
/* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\
- TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000)\
+ TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000)
#endif
diff --git a/examples/device/usbtmc/src/usb_descriptors.c b/examples/device/usbtmc/src/usb_descriptors.c
index 2336266b8..423482634 100644
--- a/examples/device/usbtmc/src/usb_descriptors.c
+++ b/examples/device/usbtmc/src/usb_descriptors.c
@@ -122,7 +122,7 @@ enum
uint8_t const desc_configuration[] =
{
// Config number, interface count, string index, total length, attribute, power in mA
- TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
+ TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
TUD_USBTMC_DESC(ITF_NUM_USBTMC),
};
diff --git a/examples/device/webusb_serial/src/main.c b/examples/device/webusb_serial/src/main.c
index c85b3cc9a..aba4aedff 100644
--- a/examples/device/webusb_serial/src/main.c
+++ b/examples/device/webusb_serial/src/main.c
@@ -71,7 +71,7 @@ enum {
static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED;
-#define URL "www.tinyusb.org/examples/webusb-serial"
+#define URL "example.tinyusb.org/webusb-serial/"
const tusb_desc_webusb_url_t desc_url =
{
diff --git a/examples/device/webusb_serial/src/usb_descriptors.c b/examples/device/webusb_serial/src/usb_descriptors.c
index 4aefdb1f7..93e802a90 100644
--- a/examples/device/webusb_serial/src/usb_descriptors.c
+++ b/examples/device/webusb_serial/src/usb_descriptors.c
@@ -86,23 +86,34 @@ enum
#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 etc ...
- #define EPNUM_CDC 2
- #define EPNUM_VENDOR 5
+ #define EPNUM_CDC_IN 2
+ #define EPNUM_CDC_OUT 2
+ #define EPNUM_VENDOR_IN 5
+ #define EPNUM_VENDOR_OUT 5
+#elif CFG_TUSB_MCU == OPT_MCU_SAMG || CFG_TUSB_MCU == OPT_MCU_SAMX7X
+ // SAMG & SAME70 don't support a same endpoint number with different direction IN and OUT
+ // e.g EP1 OUT & EP1 IN cannot exist together
+ #define EPNUM_CDC_IN 2
+ #define EPNUM_CDC_OUT 3
+ #define EPNUM_VENDOR_IN 4
+ #define EPNUM_VENDOR_OUT 5
#else
- #define EPNUM_CDC 2
- #define EPNUM_VENDOR 3
+ #define EPNUM_CDC_IN 2
+ #define EPNUM_CDC_OUT 2
+ #define EPNUM_VENDOR_IN 3
+ #define EPNUM_VENDOR_OUT 3
#endif
uint8_t const desc_configuration[] =
{
// Config number, interface count, string index, total length, attribute, power in mA
- TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
+ TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
// Interface number, string index, EP notification address and size, EP data address (out, in) and size.
- TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, 0x81, 8, EPNUM_CDC, 0x80 | EPNUM_CDC, TUD_OPT_HIGH_SPEED ? 512 : 64),
+ TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, 0x81, 8, EPNUM_CDC_OUT, 0x80 | EPNUM_CDC_IN, TUD_OPT_HIGH_SPEED ? 512 : 64),
// Interface number, string index, EP Out & IN address, EP size
- TUD_VENDOR_DESCRIPTOR(ITF_NUM_VENDOR, 5, EPNUM_VENDOR, 0x80 | EPNUM_VENDOR, TUD_OPT_HIGH_SPEED ? 512 : 64)
+ TUD_VENDOR_DESCRIPTOR(ITF_NUM_VENDOR, 5, EPNUM_VENDOR_OUT, 0x80 | EPNUM_VENDOR_IN, TUD_OPT_HIGH_SPEED ? 512 : 64)
};
// Invoked when received GET CONFIGURATION DESCRIPTOR
diff --git a/examples/host/cdc_msc_hid/src/hid_app.c b/examples/host/cdc_msc_hid/src/hid_app.c
index 23ab12404..11437c2b4 100644
--- a/examples/host/cdc_msc_hid/src/hid_app.c
+++ b/examples/host/cdc_msc_hid/src/hid_app.c
@@ -30,7 +30,8 @@
// MACRO TYPEDEF CONSTANT ENUM DECLARATION
//--------------------------------------------------------------------+
-// If your host terminal support ansi escape code, it can be use to simulate mouse cursor
+// If your host terminal support ansi escape code such as TeraTerm
+// it can be use to simulate mouse cursor movement within terminal
#define USE_ANSI_ESCAPE 0
#define MAX_REPORT 4
@@ -38,11 +39,15 @@
static uint8_t const keycode2ascii[128][2] = { HID_KEYCODE_TO_ASCII };
// Each HID instance can has multiple reports
-static uint8_t _report_count[CFG_TUH_HID];
-static tuh_hid_report_info_t _report_info_arr[CFG_TUH_HID][MAX_REPORT];
+static struct
+{
+ uint8_t report_count;
+ tuh_hid_report_info_t report_info[MAX_REPORT];
+}hid_info[CFG_TUH_HID];
static void process_kbd_report(hid_keyboard_report_t const *report);
static void process_mouse_report(hid_mouse_report_t const * report);
+static void process_generic_report(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len);
void hid_app_task(void)
{
@@ -56,17 +61,32 @@ void hid_app_task(void)
// Invoked when device with hid interface is mounted
// Report descriptor is also available for use. tuh_hid_parse_report_descriptor()
// can be used to parse common/simple enough descriptor.
+// Note: if report descriptor length > CFG_TUH_ENUMERATION_BUFSIZE, it will be skipped
+// therefore report_desc = NULL, desc_len = 0
void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len)
{
printf("HID device address = %d, instance = %d is mounted\r\n", dev_addr, instance);
- // Interface protocol
- const char* protocol_str[] = { "None", "Keyboard", "Mouse" }; // hid_protocol_type_t
- uint8_t const interface_protocol = tuh_hid_interface_protocol(dev_addr, instance);
+ // Interface protocol (hid_interface_protocol_enum_t)
+ const char* protocol_str[] = { "None", "Keyboard", "Mouse" };
+ uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, instance);
+
+ printf("HID Interface Protocol = %s\r\n", protocol_str[itf_protocol]);
- // Parse report descriptor with built-in parser
- _report_count[instance] = tuh_hid_parse_report_descriptor(_report_info_arr[instance], MAX_REPORT, desc_report, desc_len);
- printf("HID has %u reports and interface protocol = %s\r\n", _report_count[instance], protocol_str[interface_protocol]);
+ // By default host stack will use activate boot protocol on supported interface.
+ // Therefore for this simple example, we only need to parse generic report descriptor (with built-in parser)
+ if ( itf_protocol == HID_ITF_PROTOCOL_NONE )
+ {
+ hid_info[instance].report_count = tuh_hid_parse_report_descriptor(hid_info[instance].report_info, MAX_REPORT, desc_report, desc_len);
+ printf("HID has %u reports \r\n", hid_info[instance].report_count);
+ }
+
+ // request to receive report
+ // tuh_hid_report_received_cb() will be invoked when report is available
+ if ( !tuh_hid_receive_report(dev_addr, instance) )
+ {
+ printf("Error: cannot request to receive report\r\n");
+ }
}
// Invoked when device with hid interface is un-mounted
@@ -78,59 +98,30 @@ void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance)
// Invoked when received report from device via interrupt endpoint
void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len)
{
- (void) dev_addr;
-
- uint8_t const rpt_count = _report_count[instance];
- tuh_hid_report_info_t* rpt_info_arr = _report_info_arr[instance];
- tuh_hid_report_info_t* rpt_info = NULL;
+ uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, instance);
- if ( rpt_count == 1 && rpt_info_arr[0].report_id == 0)
+ switch (itf_protocol)
{
- // Simple report without report ID as 1st byte
- rpt_info = &rpt_info_arr[0];
- }else
- {
- // Composite report, 1st byte is report ID, data starts from 2nd byte
- uint8_t const rpt_id = report[0];
-
- // Find report id in the arrray
- for(uint8_t i=0; i<rpt_count; i++)
- {
- if (rpt_id == rpt_info_arr[i].report_id )
- {
- rpt_info = &rpt_info_arr[i];
- break;
- }
- }
+ case HID_ITF_PROTOCOL_KEYBOARD:
+ TU_LOG2("HID receive boot keyboard report\r\n");
+ process_kbd_report( (hid_keyboard_report_t const*) report );
+ break;
- report++;
- len--;
- }
+ case HID_ITF_PROTOCOL_MOUSE:
+ TU_LOG2("HID receive boot mouse report\r\n");
+ process_mouse_report( (hid_mouse_report_t const*) report );
+ break;
- if (!rpt_info)
- {
- printf("Couldn't find the report info for this report !\r\n");
- return;
+ default:
+ // Generic report requires matching ReportID and contents with previous parsed report info
+ process_generic_report(dev_addr, instance, report, len);
+ break;
}
- if ( rpt_info->usage_page == HID_USAGE_PAGE_DESKTOP )
+ // continue to request to receive report
+ if ( !tuh_hid_receive_report(dev_addr, instance) )
{
- switch (rpt_info->usage)
- {
- case HID_USAGE_DESKTOP_KEYBOARD:
- TU_LOG1("HID receive keyboard report\r\n");
- // Assume keyboard follow boot report layout
- process_kbd_report( (hid_keyboard_report_t const*) report );
- break;
-
- case HID_USAGE_DESKTOP_MOUSE:
- TU_LOG1("HID receive mouse report\r\n");
- // Assume mouse follow boot report layout
- process_mouse_report( (hid_mouse_report_t const*) report );
- break;
-
- default: break;
- }
+ printf("Error: cannot request to receive report\r\n");
}
}
@@ -164,7 +155,7 @@ static void process_kbd_report(hid_keyboard_report_t const *report)
}else
{
// not existed in previous report means the current key is pressed
- bool const is_shift = report->modifier & (KEYBOARD_MODIFIER_LEFTSHIFT | KEYBOARD_MODIFIER_RIGHTSHIFT);
+ bool const is_shift = report->modifier & (KEYBOARD_MODIFIER_LEFTSHIFT | KEYBOARD_MODIFIER_RIGHTSHIFT);
uint8_t ch = keycode2ascii[report->keycode[i]][is_shift ? 1 : 0];
putchar(ch);
if ( ch == '\r' ) putchar('\n'); // added new line for enter key
@@ -235,3 +226,71 @@ static void process_mouse_report(hid_mouse_report_t const * report)
//------------- cursor movement -------------//
cursor_movement(report->x, report->y, report->wheel);
}
+
+//--------------------------------------------------------------------+
+// Generic Report
+//--------------------------------------------------------------------+
+static void process_generic_report(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len)
+{
+ (void) dev_addr;
+
+ uint8_t const rpt_count = hid_info[instance].report_count;
+ tuh_hid_report_info_t* rpt_info_arr = hid_info[instance].report_info;
+ tuh_hid_report_info_t* rpt_info = NULL;
+
+ if ( rpt_count == 1 && rpt_info_arr[0].report_id == 0)
+ {
+ // Simple report without report ID as 1st byte
+ rpt_info = &rpt_info_arr[0];
+ }else
+ {
+ // Composite report, 1st byte is report ID, data starts from 2nd byte
+ uint8_t const rpt_id = report[0];
+
+ // Find report id in the arrray
+ for(uint8_t i=0; i<rpt_count; i++)
+ {
+ if (rpt_id == rpt_info_arr[i].report_id )
+ {
+ rpt_info = &rpt_info_arr[i];
+ break;
+ }
+ }
+
+ report++;
+ len--;
+ }
+
+ if (!rpt_info)
+ {
+ printf("Couldn't find the report info for this report !\r\n");
+ return;
+ }
+
+ // For complete list of Usage Page & Usage checkout src/class/hid/hid.h. For examples:
+ // - Keyboard : Desktop, Keyboard
+ // - Mouse : Desktop, Mouse
+ // - Gamepad : Desktop, Gamepad
+ // - Consumer Control (Media Key) : Consumer, Consumer Control
+ // - System Control (Power key) : Desktop, System Control
+ // - Generic (vendor) : 0xFFxx, xx
+ if ( rpt_info->usage_page == HID_USAGE_PAGE_DESKTOP )
+ {
+ switch (rpt_info->usage)
+ {
+ case HID_USAGE_DESKTOP_KEYBOARD:
+ TU_LOG1("HID receive keyboard report\r\n");
+ // Assume keyboard follow boot report layout
+ process_kbd_report( (hid_keyboard_report_t const*) report );
+ break;
+
+ case HID_USAGE_DESKTOP_MOUSE:
+ TU_LOG1("HID receive mouse report\r\n");
+ // Assume mouse follow boot report layout
+ process_mouse_report( (hid_mouse_report_t const*) report );
+ break;
+
+ default: break;
+ }
+ }
+}
diff --git a/examples/host/cdc_msc_hid/src/main.c b/examples/host/cdc_msc_hid/src/main.c
index 7ae814e38..a14be05ea 100644
--- a/examples/host/cdc_msc_hid/src/main.c
+++ b/examples/host/cdc_msc_hid/src/main.c
@@ -33,7 +33,6 @@
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF PROTYPES
//--------------------------------------------------------------------+
-void print_greeting(void);
void led_blinking_task(void);
extern void cdc_task(void);
@@ -43,7 +42,8 @@ extern void hid_app_task(void);
int main(void)
{
board_init();
- print_greeting();
+
+ printf("TinyUSB Host CDC MSC HID Example\r\n");
tusb_init();
@@ -126,28 +126,3 @@ void led_blinking_task(void)
board_led_write(led_state);
led_state = 1 - led_state; // toggle
}
-
-//--------------------------------------------------------------------+
-// HELPER FUNCTION
-//--------------------------------------------------------------------+
-void print_greeting(void)
-{
- char const * const rtos_name[] =
- {
- [OPT_OS_NONE] = "None",
- [OPT_OS_FREERTOS] = "FreeRTOS",
- [OPT_OS_MYNEWT] = "Mynewt OS",
- [OPT_OS_CUSTOM] = "Custom OS implemnted by application",
- [OPT_OS_PICO] = "Raspberry Pi Pico SDK",
- [OPT_OS_RTTHREAD] = "RT-Thread"
- };
-
- printf("----------------------------------------------------\r\n");
- printf("TinyUSB Host Example\r\n");
- printf("If you find any bugs or problems, feel free to open\r\n");
- printf("an issue at https://github.com/hathach/tinyusb\r\n");
- printf("----------------------------------------------------\r\n\r\n");
-
- printf("This Host demo is configured to support:\r\n");
- printf(" - RTOS = %s\r\n", rtos_name[CFG_TUSB_OS]);
-}
diff --git a/examples/host/cdc_msc_hid/src/msc_app.c b/examples/host/cdc_msc_hid/src/msc_app.c
index 3657a3d35..77a72052d 100644
--- a/examples/host/cdc_msc_hid/src/msc_app.c
+++ b/examples/host/cdc_msc_hid/src/msc_app.c
@@ -92,7 +92,7 @@ void tuh_msc_umount_cb(uint8_t dev_addr)
//
// if ( phy_disk == f_get_current_drive() )
// { // active drive is unplugged --> change to other drive
-// for(uint8_t i=0; i<CFG_TUSB_HOST_DEVICE_MAX; i++)
+// for(uint8_t i=0; i<CFG_TUH_DEVICE_MAX; i++)
// {
// if ( disk_is_ready(i) )
// {
diff --git a/examples/host/cdc_msc_hid/src/tusb_config.h b/examples/host/cdc_msc_hid/src/tusb_config.h
index 8253964c0..bc6c68e5b 100644
--- a/examples/host/cdc_msc_hid/src/tusb_config.h
+++ b/examples/host/cdc_msc_hid/src/tusb_config.h
@@ -72,19 +72,20 @@
//--------------------------------------------------------------------
// Size of buffer to hold descriptors and other data used for enumeration
-#define CFG_TUH_ENUMERATION_BUFSZIE 256
+#define CFG_TUH_ENUMERATION_BUFSIZE 256
#define CFG_TUH_HUB 1
#define CFG_TUH_CDC 1
-#define CFG_TUH_HID 2
+#define CFG_TUH_HID 4 // typical keyboard + mouse device can have 3-4 HID interfaces
#define CFG_TUH_MSC 1
#define CFG_TUH_VENDOR 0
-#define CFG_TUSB_HOST_DEVICE_MAX (CFG_TUH_HUB ? 5 : 1) // normal hub has 4 ports
+// max device support (excluding hub device)
+#define CFG_TUH_DEVICE_MAX (CFG_TUH_HUB ? 4 : 1) // hub typically has 4 ports
//------------- HID -------------//
-
-#define CFG_TUH_HID_EP_BUFSIZE 64
+#define CFG_TUH_HID_EPIN_BUFSIZE 64
+#define CFG_TUH_HID_EPOUT_BUFSIZE 64
#ifdef __cplusplus
}
diff --git a/examples/host/hid_controller/.only.MCU_LPC175X_6X b/examples/host/hid_controller/.only.MCU_LPC175X_6X
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/examples/host/hid_controller/.only.MCU_LPC175X_6X
diff --git a/examples/host/hid_controller/.only.MCU_LPC177X_8X b/examples/host/hid_controller/.only.MCU_LPC177X_8X
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/examples/host/hid_controller/.only.MCU_LPC177X_8X
diff --git a/examples/host/hid_controller/.only.MCU_LPC18XX b/examples/host/hid_controller/.only.MCU_LPC18XX
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/examples/host/hid_controller/.only.MCU_LPC18XX
diff --git a/examples/host/hid_controller/.only.MCU_LPC40XX b/examples/host/hid_controller/.only.MCU_LPC40XX
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/examples/host/hid_controller/.only.MCU_LPC40XX
diff --git a/examples/host/hid_controller/.only.MCU_LPC43XX b/examples/host/hid_controller/.only.MCU_LPC43XX
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/examples/host/hid_controller/.only.MCU_LPC43XX
diff --git a/examples/host/hid_controller/.only.MCU_MIMXRT10XX b/examples/host/hid_controller/.only.MCU_MIMXRT10XX
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/examples/host/hid_controller/.only.MCU_MIMXRT10XX
diff --git a/examples/host/hid_controller/.only.MCU_RP2040 b/examples/host/hid_controller/.only.MCU_RP2040
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/examples/host/hid_controller/.only.MCU_RP2040
diff --git a/examples/host/hid_controller/CMakeLists.txt b/examples/host/hid_controller/CMakeLists.txt
new file mode 100644
index 000000000..aaf8bc34f
--- /dev/null
+++ b/examples/host/hid_controller/CMakeLists.txt
@@ -0,0 +1,28 @@
+cmake_minimum_required(VERSION 3.5)
+
+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})
+
+# Checks this example is valid for the family and initializes the project
+family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
+
+add_executable(${PROJECT})
+
+# Example source
+target_sources(${PROJECT} PUBLIC
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/hid_app.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
+ )
+
+# Example include
+target_include_directories(${PROJECT} PUBLIC
+ ${CMAKE_CURRENT_SOURCE_DIR}/src
+ )
+
+# Configure compilation flags and libraries for the example... see the corresponding function
+# in hw/bsp/FAMILY/family.cmake for details.
+family_configure_host_example(${PROJECT}) \ No newline at end of file
diff --git a/examples/host/hid_controller/Makefile b/examples/host/hid_controller/Makefile
new file mode 100644
index 000000000..6f59faeee
--- /dev/null
+++ b/examples/host/hid_controller/Makefile
@@ -0,0 +1,30 @@
+include ../../../tools/top.mk
+include ../../make.mk
+
+INC += \
+ src \
+ $(TOP)/hw \
+
+# Example source
+EXAMPLE_SOURCE += \
+ src/hid_app.c \
+ src/main.c
+
+SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
+
+CFLAGS += -Wno-error=cast-align
+
+# TinyUSB Host Stack source
+SRC_C += \
+ src/class/cdc/cdc_host.c \
+ src/class/hid/hid_host.c \
+ src/class/msc/msc_host.c \
+ src/host/hub.c \
+ src/host/usbh.c \
+ src/host/usbh_control.c \
+ src/portable/ehci/ehci.c \
+ src/portable/ohci/ohci.c \
+ src/portable/nxp/transdimension/hcd_transdimension.c \
+ src/portable/nxp/lpc17_40/hcd_lpc17_40.c
+
+include ../../rules.mk
diff --git a/examples/host/hid_controller/src/hid_app.c b/examples/host/hid_controller/src/hid_app.c
new file mode 100644
index 000000000..bbfea8182
--- /dev/null
+++ b/examples/host/hid_controller/src/hid_app.c
@@ -0,0 +1,253 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021, 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.h"
+#include "tusb.h"
+
+/* From https://www.kernel.org/doc/html/latest/input/gamepad.html
+ ____________________________ __
+ / [__ZL__] [__ZR__] \ |
+ / [__ TL __] [__ TR __] \ | Front Triggers
+ __/________________________________\__ __|
+ / _ \ |
+ / /\ __ (N) \ |
+ / || __ |MO| __ _ _ \ | Main Pad
+ | <===DP===> |SE| |ST| (W) -|- (E) | |
+ \ || ___ ___ _ / |
+ /\ \/ / \ / \ (S) /\ __|
+ / \________ | LS | ____ | RS | ________/ \ |
+| / \ \___/ / \ \___/ / \ | | Control Sticks
+| / \_____/ \_____/ \ | __|
+| / \ |
+ \_____/ \_____/
+
+ |________|______| |______|___________|
+ D-Pad Left Right Action Pad
+ Stick Stick
+
+ |_____________|
+ Menu Pad
+
+ Most gamepads have the following features:
+ - Action-Pad 4 buttons in diamonds-shape (on the right side) NORTH, SOUTH, WEST and EAST.
+ - D-Pad (Direction-pad) 4 buttons (on the left side) that point up, down, left and right.
+ - Menu-Pad Different constellations, but most-times 2 buttons: SELECT - START.
+ - Analog-Sticks provide freely moveable sticks to control directions, Analog-sticks may also
+ provide a digital button if you press them.
+ - Triggers are located on the upper-side of the pad in vertical direction. The upper buttons
+ are normally named Left- and Right-Triggers, the lower buttons Z-Left and Z-Right.
+ - Rumble Many devices provide force-feedback features. But are mostly just simple rumble motors.
+ */
+
+// Sony DS4 report layout detail https://www.psdevwiki.com/ps4/DS4-USB
+typedef struct TU_ATTR_PACKED
+{
+ uint8_t x, y, z, rz; // joystick
+
+ struct {
+ uint8_t dpad : 4; // (hat format, 0x08 is released, 0=N, 1=NE, 2=E, 3=SE, 4=S, 5=SW, 6=W, 7=NW)
+ uint8_t square : 1; // west
+ uint8_t cross : 1; // south
+ uint8_t circle : 1; // east
+ uint8_t triangle : 1; // north
+ };
+
+ struct {
+ uint8_t l1 : 1;
+ uint8_t r1 : 1;
+ uint8_t l2 : 1;
+ uint8_t r2 : 1;
+ uint8_t share : 1;
+ uint8_t option : 1;
+ uint8_t l3 : 1;
+ uint8_t r3 : 1;
+ };
+
+ struct {
+ uint8_t ps : 1; // playstation button
+ uint8_t tpad : 1; // track pad click
+ uint8_t counter : 6; // +1 each report
+ };
+
+ // comment out since not used by this example
+ // uint8_t l2_trigger; // 0 released, 0xff fully pressed
+ // uint8_t r2_trigger; // as above
+
+ // uint16_t timestamp;
+ // uint8_t battery;
+ //
+ // int16_t gyro[3]; // x, y, z;
+ // int16_t accel[3]; // x, y, z
+
+ // there is still lots more info
+
+} sony_ds4_report_t;
+
+// check if device is Sony DualShock 4
+static inline bool is_sony_ds4(uint8_t dev_addr)
+{
+ uint16_t vid, pid;
+ tuh_vid_pid_get(dev_addr, &vid, &pid);
+
+ return ( (vid == 0x054c && (pid == 0x09cc || pid == 0x05c4)) // Sony DualShock4
+ || (vid == 0x0f0d && pid == 0x005e) // Hori FC4
+ || (vid == 0x0f0d && pid == 0x00ee) // Hori PS4 Mini (PS4-099U)
+ || (vid == 0x1f4f && pid == 0x1002) // ASW GG xrd controller
+ );
+}
+
+//--------------------------------------------------------------------+
+// MACRO TYPEDEF CONSTANT ENUM DECLARATION
+//--------------------------------------------------------------------+
+
+void hid_app_task(void)
+{
+ // nothing to do
+}
+
+//--------------------------------------------------------------------+
+// TinyUSB Callbacks
+//--------------------------------------------------------------------+
+
+// Invoked when device with hid interface is mounted
+// Report descriptor is also available for use. tuh_hid_parse_report_descriptor()
+// can be used to parse common/simple enough descriptor.
+// Note: if report descriptor length > CFG_TUH_ENUMERATION_BUFSIZE, it will be skipped
+// therefore report_desc = NULL, desc_len = 0
+void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len)
+{
+ uint16_t vid, pid;
+ tuh_vid_pid_get(dev_addr, &vid, &pid);
+
+ printf("HID device address = %d, instance = %d is mounted\r\n", dev_addr, instance);
+ printf("VID = %04x, PID = %04x\r\n", vid, pid);
+
+ // Sony DualShock 4 [CUH-ZCT2x]
+ if ( is_sony_ds4(dev_addr) )
+ {
+ // request to receive report
+ // tuh_hid_report_received_cb() will be invoked when report is available
+ if ( !tuh_hid_receive_report(dev_addr, instance) )
+ {
+ printf("Error: cannot request to receive report\r\n");
+ }
+ }
+}
+
+// Invoked when device with hid interface is un-mounted
+void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance)
+{
+ printf("HID device address = %d, instance = %d is unmounted\r\n", dev_addr, instance);
+
+}
+
+// check if different than 2
+bool diff_than_2(uint8_t x, uint8_t y)
+{
+ return (x - y > 2) || (y - x > 2);
+}
+
+// check if 2 reports are different enough
+bool diff_report(sony_ds4_report_t const* rpt1, sony_ds4_report_t const* rpt2)
+{
+ bool result;
+
+ // x, y, z, rz must different than 2 to be counted
+ result = diff_than_2(rpt1->x, rpt2->x) || diff_than_2(rpt1->y , rpt2->y ) ||
+ diff_than_2(rpt1->z, rpt2->z) || diff_than_2(rpt1->rz, rpt2->rz);
+
+ // check the reset with mem compare
+ result |= memcmp(&rpt1->rz + 1, &rpt2->rz + 1, sizeof(sony_ds4_report_t)-4);
+
+ return result;
+}
+
+void process_sony_ds4(uint8_t const* report, uint16_t len)
+{
+ const char* dpad_str[] = { "N", "NE", "E", "SE", "S", "SW", "W", "NW", "none" };
+
+ // previous report used to compare for changes
+ static sony_ds4_report_t prev_report = { 0 };
+
+ uint8_t const report_id = report[0];
+ report++;
+ len--;
+
+ // all buttons state is stored in ID 1
+ if (report_id == 1)
+ {
+ sony_ds4_report_t ds4_report;
+ memcpy(&ds4_report, report, sizeof(ds4_report));
+
+ // counter is +1, assign to make it easier to compare 2 report
+ prev_report.counter = ds4_report.counter;
+
+ // only print if changes since it is polled ~ 5ms
+ // Since count+1 after each report and x, y, z, rz fluctuate within 1 or 2
+ // We need more than memcmp to check if report is different enough
+ if ( diff_report(&prev_report, &ds4_report) )
+ {
+ printf("(x, y, z, rz) = (%u, %u, %u, %u)\r\n", ds4_report.x, ds4_report.y, ds4_report.z, ds4_report.rz);
+ printf("DPad = %s ", dpad_str[ds4_report.dpad]);
+
+ if (ds4_report.square ) printf("Square ");
+ if (ds4_report.cross ) printf("Cross ");
+ if (ds4_report.circle ) printf("Circle ");
+ if (ds4_report.triangle ) printf("Triangle ");
+
+ if (ds4_report.l1 ) printf("L1 ");
+ if (ds4_report.r1 ) printf("R1 ");
+ if (ds4_report.l2 ) printf("L2 ");
+ if (ds4_report.r2 ) printf("R2 ");
+
+ if (ds4_report.share ) printf("Share ");
+ if (ds4_report.option ) printf("Option ");
+ if (ds4_report.l3 ) printf("L3 ");
+ if (ds4_report.r3 ) printf("R3 ");
+
+ if (ds4_report.ps ) printf("PS ");
+ if (ds4_report.tpad ) printf("TPad ");
+
+ printf("\r\n");
+ }
+
+ prev_report = ds4_report;
+ }
+}
+
+// Invoked when received report from device via interrupt endpoint
+void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len)
+{
+ if ( is_sony_ds4(dev_addr) )
+ {
+ process_sony_ds4(report, len);
+ }
+
+ // continue to request to receive report
+ if ( !tuh_hid_receive_report(dev_addr, instance) )
+ {
+ printf("Error: cannot request to receive report\r\n");
+ }
+}
diff --git a/examples/host/hid_controller/src/main.c b/examples/host/hid_controller/src/main.c
new file mode 100644
index 000000000..b9b37a4d2
--- /dev/null
+++ b/examples/host/hid_controller/src/main.c
@@ -0,0 +1,94 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+/* This example current worked and tested with following controller
+ * - Sony DualShock 4 [CUH-ZCT2x] VID = 0x054c, PID = 0x09cc
+ */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "bsp/board.h"
+#include "tusb.h"
+
+//--------------------------------------------------------------------+
+// MACRO CONSTANT TYPEDEF PROTYPES
+//--------------------------------------------------------------------+
+void led_blinking_task(void);
+
+extern void cdc_task(void);
+extern void hid_app_task(void);
+
+/*------------- MAIN -------------*/
+int main(void)
+{
+ board_init();
+
+ printf("TinyUSB Host HID Controller Example\r\n");
+ printf("Note: Events only displayed for explictly supported controllers\r\n");
+
+ tusb_init();
+
+ while (1)
+ {
+ // tinyusb host task
+ tuh_task();
+ led_blinking_task();
+
+#if CFG_TUH_CDC
+ cdc_task();
+#endif
+
+#if CFG_TUH_HID
+ hid_app_task();
+#endif
+ }
+
+ return 0;
+}
+
+//--------------------------------------------------------------------+
+// TinyUSB Callbacks
+//--------------------------------------------------------------------+
+
+//--------------------------------------------------------------------+
+// Blinking Task
+//--------------------------------------------------------------------+
+void led_blinking_task(void)
+{
+ const uint32_t interval_ms = 1000;
+ static uint32_t start_ms = 0;
+
+ static bool led_state = false;
+
+ // Blink every interval ms
+ if ( board_millis() - start_ms < interval_ms) return; // not enough time
+ start_ms += interval_ms;
+
+ board_led_write(led_state);
+ led_state = 1 - led_state; // toggle
+}
diff --git a/examples/host/hid_controller/src/tusb_config.h b/examples/host/hid_controller/src/tusb_config.h
new file mode 100644
index 000000000..74b471ae4
--- /dev/null
+++ b/examples/host/hid_controller/src/tusb_config.h
@@ -0,0 +1,95 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#ifndef _TUSB_CONFIG_H_
+#define _TUSB_CONFIG_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+//--------------------------------------------------------------------
+// COMMON CONFIGURATION
+//--------------------------------------------------------------------
+
+// defined by compiler flags for flexibility
+#ifndef CFG_TUSB_MCU
+ #error CFG_TUSB_MCU must be defined
+#endif
+
+#if CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX
+ #define CFG_TUSB_RHPORT0_MODE (OPT_MODE_HOST | OPT_MODE_HIGH_SPEED)
+#else
+ #define CFG_TUSB_RHPORT0_MODE OPT_MODE_HOST
+#endif
+
+#ifndef CFG_TUSB_OS
+#define CFG_TUSB_OS OPT_OS_NONE
+#endif
+
+// CFG_TUSB_DEBUG is defined by compiler in DEBUG build
+// #define CFG_TUSB_DEBUG 0
+
+/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.
+ * Tinyusb use follows macros to declare transferring memory so that they can be put
+ * into those specific section.
+ * e.g
+ * - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") ))
+ * - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4)))
+ */
+#ifndef CFG_TUSB_MEM_SECTION
+#define CFG_TUSB_MEM_SECTION
+#endif
+
+#ifndef CFG_TUSB_MEM_ALIGN
+#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4)))
+#endif
+
+//--------------------------------------------------------------------
+// CONFIGURATION
+//--------------------------------------------------------------------
+
+// Size of buffer to hold descriptors and other data used for enumeration
+#define CFG_TUH_ENUMERATION_BUFSIZE 256
+
+#define CFG_TUH_HUB 0
+#define CFG_TUH_CDC 0
+#define CFG_TUH_HID 4 // typical keyboard + mouse device can have 3-4 HID interfaces
+#define CFG_TUH_MSC 0
+#define CFG_TUH_VENDOR 0
+
+// max device support (excluding hub device)
+// 1 hub typically has 4 ports
+#define CFG_TUH_DEVICE_MAX (CFG_TUH_HUB ? 4 : 1)
+
+//------------- HID -------------//
+
+#define CFG_TUH_HID_EP_BUFSIZE 64
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _TUSB_CONFIG_H_ */
diff --git a/examples/make.mk b/examples/make.mk
index 9daf60e35..c894d35f4 100644
--- a/examples/make.mk
+++ b/examples/make.mk
@@ -65,10 +65,12 @@ MKDIR = mkdir
ifeq ($(CMDEXE),1)
CP = copy
RM = del
+ PYTHON = python
else
SED = sed
CP = cp
RM = rm
+ PYTHON = python3
endif
#-------------- Source files and compiler flags --------------
diff --git a/examples/rules.mk b/examples/rules.mk
index 4fce468fd..861973284 100644
--- a/examples/rules.mk
+++ b/examples/rules.mk
@@ -169,8 +169,9 @@ flash-stlink: $(BUILD)/$(PROJECT).elf
STM32_Programmer_CLI --connect port=swd --write $< --go
# flash with pyocd
+PYOCD_OPTION ?=
flash-pyocd: $(BUILD)/$(PROJECT).hex
- pyocd flash -t $(PYOCD_TARGET) $<
+ pyocd flash -t $(PYOCD_TARGET) $(PYOCD_OPTION) $<
pyocd reset -t $(PYOCD_TARGET)
# flash with Black Magic Probe