summaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorHa Thach <[email protected]>2021-08-29 21:49:10 +0700
committerGitHub <[email protected]>2021-08-29 21:49:10 +0700
commit4492a7021cb33cb3079f2e949d6e22ddd3d33f49 (patch)
treeb14be02e6d0a7d632e320431cc3543e123de78fa /examples
parent61592526928be9626317ef82bbe42d0edaf7fa14 (diff)
parent31959295965f6b19c35bb770b1e430bdfa7b4606 (diff)
Merge branch 'master' into merge-waveshare-h7
Diffstat (limited to 'examples')
-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.c12
-rw-r--r--examples/device/hid_composite/src/usb_descriptors.c4
-rw-r--r--examples/device/hid_composite_freertos/src/main.c12
-rw-r--r--examples/device/hid_composite_freertos/src/usb_descriptors.c4
-rw-r--r--examples/host/cdc_msc_hid/src/hid_app.c15
-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.h9
-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.c249
-rw-r--r--examples/host/hid_controller/src/main.c93
-rw-r--r--examples/host/hid_controller/src/tusb_config.h95
26 files changed, 1158 insertions, 48 deletions
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 d2a8a28fa..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,9 +253,9 @@ 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)
{
- (void) itf;
+ (void) instance;
if (report_type == HID_REPORT_TYPE_OUTPUT)
{
diff --git a/examples/device/hid_composite/src/usb_descriptors.c b/examples/device/hid_composite/src/usb_descriptors.c
index 1aff5e68e..b9a6e7292 100644
--- a/examples/device/hid_composite/src/usb_descriptors.c
+++ b/examples/device/hid_composite/src/usb_descriptors.c
@@ -82,9 +82,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;
}
diff --git a/examples/device/hid_composite_freertos/src/main.c b/examples/device/hid_composite_freertos/src/main.c
index a61710858..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,9 +313,9 @@ 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)
{
- (void) itf;
+ (void) instance;
if (report_type == HID_REPORT_TYPE_OUTPUT)
{
diff --git a/examples/device/hid_composite_freertos/src/usb_descriptors.c b/examples/device/hid_composite_freertos/src/usb_descriptors.c
index 1aff5e68e..b9a6e7292 100644
--- a/examples/device/hid_composite_freertos/src/usb_descriptors.c
+++ b/examples/device/hid_composite_freertos/src/usb_descriptors.c
@@ -82,9 +82,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;
}
diff --git a/examples/host/cdc_msc_hid/src/hid_app.c b/examples/host/cdc_msc_hid/src/hid_app.c
index 420600f9a..11437c2b4 100644
--- a/examples/host/cdc_msc_hid/src/hid_app.c
+++ b/examples/host/cdc_msc_hid/src/hid_app.c
@@ -61,6 +61,8 @@ 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);
@@ -78,6 +80,13 @@ void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_re
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
@@ -108,6 +117,12 @@ void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t cons
process_generic_report(dev_addr, instance, report, len);
break;
}
+
+ // 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/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 b574acf9b..bc6c68e5b 100644
--- a/examples/host/cdc_msc_hid/src/tusb_config.h
+++ b/examples/host/cdc_msc_hid/src/tusb_config.h
@@ -76,15 +76,16 @@
#define CFG_TUH_HUB 1
#define CFG_TUH_CDC 1
-#define CFG_TUH_HID 4
+#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..c61ce70f3
--- /dev/null
+++ b/examples/host/hid_controller/src/hid_app.c
@@ -0,0 +1,249 @@
+/*
+ * 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);
+}
+
+//--------------------------------------------------------------------+
+// 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..e13fa818a
--- /dev/null
+++ b/examples/host/hid_controller/src/main.c
@@ -0,0 +1,93 @@
+/*
+ * 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");
+
+ 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_ */