From 5f6418ccd79892c0f8c2152244f7e7a78e17a162 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 17 Aug 2021 13:21:24 +0700 Subject: add hid_boot_interface example --- examples/device/hid_boot_interface/CMakeLists.txt | 28 +++ examples/device/hid_boot_interface/Makefile | 15 ++ examples/device/hid_boot_interface/src/main.c | 253 +++++++++++++++++++++ .../device/hid_boot_interface/src/tusb_config.h | 111 +++++++++ .../hid_boot_interface/src/usb_descriptors.c | 180 +++++++++++++++ .../hid_boot_interface/src/usb_descriptors.h | 35 +++ examples/device/hid_composite/src/main.c | 12 +- .../device/hid_composite/src/usb_descriptors.c | 4 +- examples/device/hid_composite_freertos/src/main.c | 12 +- .../hid_composite_freertos/src/usb_descriptors.c | 4 +- 10 files changed, 638 insertions(+), 16 deletions(-) create mode 100644 examples/device/hid_boot_interface/CMakeLists.txt create mode 100644 examples/device/hid_boot_interface/Makefile create mode 100644 examples/device/hid_boot_interface/src/main.c create mode 100644 examples/device/hid_boot_interface/src/tusb_config.h create mode 100644 examples/device/hid_boot_interface/src/usb_descriptors.c create mode 100644 examples/device/hid_boot_interface/src/usb_descriptors.h (limited to 'examples') 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. -) +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..0d4bc8499 --- /dev/null +++ b/examples/device/hid_boot_interface/src/main.c @@ -0,0 +1,253 @@ +/* + * 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 +#include +#include + +#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) +{ + // 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 Date: Tue, 17 Aug 2021 13:33:15 +0700 Subject: fix ci build --- examples/device/hid_boot_interface/src/main.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'examples') diff --git a/examples/device/hid_boot_interface/src/main.c b/examples/device/hid_boot_interface/src/main.c index 0d4bc8499..e5e2f6856 100644 --- a/examples/device/hid_boot_interface/src/main.c +++ b/examples/device/hid_boot_interface/src/main.c @@ -207,6 +207,8 @@ uint16_t tud_hid_get_report_cb(uint8_t instance, uint8_t report_id, hid_report_t // 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) { -- cgit v1.3.1 From 62f2efbe8cf1e61f70660abac28f4226bca93daf Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 20 Aug 2021 18:26:56 +0700 Subject: hid host skip get report descriptor if too large instead of assert --- examples/host/cdc_msc_hid/src/hid_app.c | 2 ++ src/class/hid/hid_host.c | 58 +++++++++++++++++++++------------ src/class/hid/hid_host.h | 2 ++ src/host/usbh.c | 2 -- 4 files changed, 41 insertions(+), 23 deletions(-) (limited to 'examples') diff --git a/examples/host/cdc_msc_hid/src/hid_app.c b/examples/host/cdc_msc_hid/src/hid_app.c index 420600f9a..5e3ac6a72 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); diff --git a/src/class/hid/hid_host.c b/src/class/hid/hid_host.c index 40b6f5631..a39ac8bec 100644 --- a/src/class/hid/hid_host.c +++ b/src/class/hid/hid_host.c @@ -247,6 +247,8 @@ static bool config_set_protocol (uint8_t dev_addr, tusb_control_requ static bool config_get_report_desc (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result); static bool config_get_report_desc_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result); +static void config_driver_mount_complete(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len); + uint16_t hidh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len) { (void) max_len; @@ -367,26 +369,34 @@ static bool config_get_report_desc(uint8_t dev_addr, tusb_control_request_t cons uint8_t const instance = get_instance_id_by_itfnum(dev_addr, itf_num); hidh_interface_t* hid_itf = get_instance(dev_addr, instance); - // Get Report Descriptor + // Get Report Descriptor if possible // using usbh enumeration buffer since report descriptor can be very long - TU_ASSERT( hid_itf->report_desc_len <= CFG_TUH_ENUMERATION_BUFSIZE ); + if( hid_itf->report_desc_len > CFG_TUH_ENUMERATION_BUFSIZE ) + { + TU_LOG2("HID Skip Report Descriptor since it is too large %u bytes\r\n", hid_itf->report_desc_len); - TU_LOG2("HID Get Report Descriptor\r\n"); - tusb_control_request_t const new_request = + // Driver is mounted without report descriptor + config_driver_mount_complete(dev_addr, instance, NULL, 0); + }else { - .bmRequestType_bit = + TU_LOG2("HID Get Report Descriptor\r\n"); + tusb_control_request_t const new_request = { - .recipient = TUSB_REQ_RCPT_INTERFACE, - .type = TUSB_REQ_TYPE_STANDARD, - .direction = TUSB_DIR_IN - }, - .bRequest = TUSB_REQ_GET_DESCRIPTOR, - .wValue = tu_u16(hid_itf->report_desc_type, 0), - .wIndex = itf_num, - .wLength = hid_itf->report_desc_len - }; + .bmRequestType_bit = + { + .recipient = TUSB_REQ_RCPT_INTERFACE, + .type = TUSB_REQ_TYPE_STANDARD, + .direction = TUSB_DIR_IN + }, + .bRequest = TUSB_REQ_GET_DESCRIPTOR, + .wValue = tu_u16(hid_itf->report_desc_type, 0), + .wIndex = itf_num, + .wLength = hid_itf->report_desc_len + }; + + TU_ASSERT(tuh_control_xfer(dev_addr, &new_request, usbh_get_enum_buf(), config_get_report_desc_complete)); + } - TU_ASSERT(tuh_control_xfer(dev_addr, &new_request, usbh_get_enum_buf(), config_get_report_desc_complete)); return true; } @@ -394,13 +404,21 @@ static bool config_get_report_desc_complete(uint8_t dev_addr, tusb_control_reque { TU_ASSERT(XFER_RESULT_SUCCESS == result); - uint8_t const itf_num = (uint8_t) request->wIndex; - uint8_t const instance = get_instance_id_by_itfnum(dev_addr, itf_num); - hidh_interface_t* hid_itf = get_instance(dev_addr, instance); + uint8_t const itf_num = (uint8_t) request->wIndex; + uint8_t const instance = get_instance_id_by_itfnum(dev_addr, itf_num); uint8_t const* desc_report = usbh_get_enum_buf(); uint16_t const desc_len = request->wLength; + config_driver_mount_complete(dev_addr, instance, desc_report, desc_len); + + return true; +} + +static void config_driver_mount_complete(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len) +{ + hidh_interface_t* hid_itf = get_instance(dev_addr, instance); + // enumeration is complete tuh_hid_mount_cb(dev_addr, instance, desc_report, desc_len); @@ -408,9 +426,7 @@ static bool config_get_report_desc_complete(uint8_t dev_addr, tusb_control_reque hidh_get_report(dev_addr, hid_itf); // notify usbh that driver enumeration is complete - usbh_driver_set_config_complete(dev_addr, itf_num); - - return true; + usbh_driver_set_config_complete(dev_addr, hid_itf->itf_num); } //--------------------------------------------------------------------+ diff --git a/src/class/hid/hid_host.h b/src/class/hid/hid_host.h index ef203123d..bbef05e25 100644 --- a/src/class/hid/hid_host.h +++ b/src/class/hid/hid_host.h @@ -97,6 +97,8 @@ uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* reports_info_arr, // 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* report_desc, uint16_t desc_len); // Invoked when device with hid interface is un-mounted diff --git a/src/host/usbh.c b/src/host/usbh.c index 36c2ea7c8..979fc5065 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -892,8 +892,6 @@ static bool parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configura p_desc = tu_desc_next(p_desc); } - TU_LOG_INT(2, p_desc - (uint8_t*) desc_cfg); - TU_LOG_INT(2, tu_desc_type(p_desc)); TU_ASSERT( TUSB_DESC_INTERFACE == tu_desc_type(p_desc) ); tusb_desc_interface_t const* desc_itf = (tusb_desc_interface_t const*) p_desc; -- cgit v1.3.1 From 800f85329ea21bdefc778c246c8098dea12fb402 Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 23 Aug 2021 11:00:21 +0700 Subject: add tuh_hid_receive_report() for applicaiton to explicitly request report --- examples/host/cdc_msc_hid/src/hid_app.c | 13 ++++++++++ examples/host/cdc_msc_hid/src/main.c | 29 ++------------------- examples/host/cdc_msc_hid/src/tusb_config.h | 6 ++--- src/class/hid/hid_host.c | 39 ++++++++++++++++++----------- src/class/hid/hid_host.h | 30 +++++++++++++++++----- src/host/usbh.c | 8 +++--- src/tusb.c | 3 ++- 7 files changed, 73 insertions(+), 55 deletions(-) (limited to 'examples') diff --git a/examples/host/cdc_msc_hid/src/hid_app.c b/examples/host/cdc_msc_hid/src/hid_app.c index 5e3ac6a72..11437c2b4 100644 --- a/examples/host/cdc_msc_hid/src/hid_app.c +++ b/examples/host/cdc_msc_hid/src/hid_app.c @@ -80,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 @@ -110,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/tusb_config.h b/examples/host/cdc_msc_hid/src/tusb_config.h index b574acf9b..80f07f446 100644 --- a/examples/host/cdc_msc_hid/src/tusb_config.h +++ b/examples/host/cdc_msc_hid/src/tusb_config.h @@ -76,15 +76,15 @@ #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 //------------- 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/src/class/hid/hid_host.c b/src/class/hid/hid_host.c index 4dd198369..2d76df588 100644 --- a/src/class/hid/hid_host.c +++ b/src/class/hid/hid_host.c @@ -52,8 +52,8 @@ typedef struct uint16_t epin_size; uint16_t epout_size; - uint8_t epin_buf[CFG_TUH_HID_EP_BUFSIZE]; - uint8_t epout_buf[CFG_TUH_HID_EP_BUFSIZE]; + uint8_t epin_buf[CFG_TUH_HID_EPIN_BUFSIZE]; + uint8_t epout_buf[CFG_TUH_HID_EPOUT_BUFSIZE]; } hidh_interface_t; typedef struct @@ -72,13 +72,8 @@ TU_ATTR_ALWAYS_INLINE static inline hidh_interface_t* get_instance(uint8_t dev_a static uint8_t get_instance_id_by_itfnum(uint8_t dev_addr, uint8_t itf); static uint8_t get_instance_id_by_epaddr(uint8_t dev_addr, uint8_t ep_addr); -TU_ATTR_ALWAYS_INLINE static inline bool hidh_get_report(uint8_t dev_addr, hidh_interface_t* hid_itf) -{ - return usbh_edpt_xfer(dev_addr, hid_itf->ep_in, hid_itf->epin_buf, hid_itf->epin_size); -} - //--------------------------------------------------------------------+ -// Application API +// Interface API //--------------------------------------------------------------------+ uint8_t tuh_hid_instance_count(uint8_t dev_addr) @@ -98,6 +93,10 @@ uint8_t tuh_hid_interface_protocol(uint8_t dev_addr, uint8_t instance) return hid_itf->itf_protocol; } +//--------------------------------------------------------------------+ +// Control Endpoint API +//--------------------------------------------------------------------+ + uint8_t tuh_hid_get_protocol(uint8_t dev_addr, uint8_t instance) { hidh_interface_t* hid_itf = get_instance(dev_addr, instance); @@ -186,6 +185,20 @@ bool tuh_hid_set_report(uint8_t dev_addr, uint8_t instance, uint8_t report_id, u return true; } +//--------------------------------------------------------------------+ +// Interrupt Endpoint API +//--------------------------------------------------------------------+ + +bool tuh_hid_receive_report(uint8_t dev_addr, uint8_t instance) +{ + hidh_interface_t* hid_itf = get_instance(dev_addr, instance); + + // claim endpoint + TU_VERIFY( usbh_edpt_claim(dev_addr, hid_itf->ep_in) ); + + return usbh_edpt_xfer(dev_addr, hid_itf->ep_in, hid_itf->epin_buf, hid_itf->epin_size); +} + //bool tuh_n_hid_n_ready(uint8_t dev_addr, uint8_t instance) //{ // TU_VERIFY(tuh_n_hid_n_mounted(dev_addr, instance)); @@ -217,9 +230,6 @@ bool hidh_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint3 TU_LOG2(" Get Report callback (%u, %u)\r\n", dev_addr, instance); TU_LOG1_MEM(hid_itf->epin_buf, 8, 2); tuh_hid_report_received_cb(dev_addr, instance, hid_itf->epin_buf, xferred_bytes); - - // queue next report - hidh_get_report(dev_addr, hid_itf); }else { if (tuh_hid_report_sent_cb) tuh_hid_report_sent_cb(dev_addr, instance, hid_itf->epout_buf, xferred_bytes); @@ -255,6 +265,8 @@ bool hidh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *de TU_VERIFY(TUSB_CLASS_HID == desc_itf->bInterfaceClass); + TU_LOG2("HID opening Interface %u (addr = %u)\r\n", desc_itf->bInterfaceNumber, dev_addr); + // len = interface + hid + n*endpoints uint16_t const drv_len = sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) + desc_itf->bNumEndpoints*sizeof(tusb_desc_endpoint_t); TU_ASSERT(max_len >= drv_len); @@ -336,7 +348,7 @@ static bool config_set_protocol(uint8_t dev_addr, tusb_control_request_t const * uint8_t const instance = get_instance_id_by_itfnum(dev_addr, itf_num); hidh_interface_t* hid_itf = get_instance(dev_addr, instance); - TU_LOG2("HID Set Protocol\r\n"); + TU_LOG2("HID Set Protocol to Boot Mode\r\n"); hid_itf->protocol_mode = HID_PROTOCOL_BOOT; tusb_control_request_t const new_request = { @@ -422,9 +434,6 @@ static void config_driver_mount_complete(uint8_t dev_addr, uint8_t instance, uin // enumeration is complete tuh_hid_mount_cb(dev_addr, instance, desc_report, desc_len); - // queue transfer for IN endpoint - hidh_get_report(dev_addr, hid_itf); - // notify usbh that driver enumeration is complete usbh_driver_set_config_complete(dev_addr, hid_itf->itf_num); } diff --git a/src/class/hid/hid_host.h b/src/class/hid/hid_host.h index 9a498afec..fe09b03b2 100644 --- a/src/class/hid/hid_host.h +++ b/src/class/hid/hid_host.h @@ -38,10 +38,15 @@ //--------------------------------------------------------------------+ // TODO Highspeed interrupt can be up to 512 bytes -#ifndef CFG_TUH_HID_EP_BUFSIZE -#define CFG_TUH_HID_EP_BUFSIZE 64 +#ifndef CFG_TUH_HID_EPIN_BUFSIZE +#define CFG_TUH_HID_EPIN_BUFSIZE 64 #endif +#ifndef CFG_TUH_HID_EPOUT_BUFSIZE +#define CFG_TUH_HID_EPOUT_BUFSIZE 64 +#endif + + typedef struct { uint8_t report_id; @@ -54,7 +59,7 @@ typedef struct } tuh_hid_report_info_t; //--------------------------------------------------------------------+ -// Application API +// Interface API //--------------------------------------------------------------------+ // Get the number of HID instances @@ -66,6 +71,14 @@ bool tuh_hid_mounted(uint8_t dev_addr, uint8_t instance); // Get interface supported protocol (bInterfaceProtocol) check out hid_interface_protocol_enum_t for possible values uint8_t tuh_hid_interface_protocol(uint8_t dev_addr, uint8_t instance); +// Parse report descriptor into array of report_info struct and return number of reports. +// For complicated report, application should write its own parser. +uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* reports_info_arr, uint8_t arr_count, uint8_t const* desc_report, uint16_t desc_len) TU_ATTR_UNUSED; + +//--------------------------------------------------------------------+ +// Control Endpoint API +//--------------------------------------------------------------------+ + // Get current protocol: HID_PROTOCOL_BOOT (0) or HID_PROTOCOL_REPORT (1) // Note: Device will be initialized in Boot protocol for simplicity. // Application can use set_protocol() to switch back to Report protocol. @@ -79,13 +92,18 @@ bool tuh_hid_set_protocol(uint8_t dev_addr, uint8_t instance, uint8_t protocol); // report_type is either Intput, Output or Feature, (value from hid_report_type_t) bool tuh_hid_set_report(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, void* report, uint16_t len); -// Parse report descriptor into array of report_info struct and return number of reports. -// For complicated report, application should write its own parser. -uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* reports_info_arr, uint8_t arr_count, uint8_t const* desc_report, uint16_t desc_len) TU_ATTR_UNUSED; +//--------------------------------------------------------------------+ +// Interrupt Endpoint API +//--------------------------------------------------------------------+ // Check if the interface is ready to use //bool tuh_n_hid_n_ready(uint8_t dev_addr, uint8_t instance); +// Try to receive next report on Interrupt Endpoint. Immediately return +// - true If succeeded, tuh_hid_report_received_cb() callback will be invoked when report is available +// - false if failed to queue the transfer e.g endpoint is busy +bool tuh_hid_receive_report(uint8_t dev_addr, uint8_t instance); + // Send report using interrupt endpoint // If report_id > 0 (composite), it will be sent as 1st byte, then report contents. Otherwise only report content is sent. //void tuh_hid_send_report(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t const* report, uint16_t len); diff --git a/src/host/usbh.c b/src/host/usbh.c index 662ce2673..40c23a69d 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -186,7 +186,7 @@ bool tuh_init(uint8_t rhport) TU_LOG2("USBH init\r\n"); - tu_memclr(_usbh_devices, sizeof(usbh_device_t)*(CFG_TUSB_HOST_DEVICE_MAX+1)); + tu_memclr(_usbh_devices, sizeof(_usbh_devices)); //------------- Enumeration & Reporter Task init -------------// _usbh_q = osal_queue_create( &_usbh_qdef ); @@ -436,6 +436,7 @@ void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num) for(itf_num++; itf_num < sizeof(dev->itf2drv); itf_num++) { // continue with next valid interface + // TODO skip IAD binding interface such as CDCs uint8_t const drv_id = dev->itf2drv[itf_num]; if (drv_id != DRVID_INVALID) { @@ -474,6 +475,7 @@ static bool enum_get_config_desc_complete (uint8_t dev_addr, tusb_control_ static bool enum_set_config_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result); static bool parse_configuration_descriptor (uint8_t dev_addr, tusb_desc_configuration_t const* desc_cfg); +#if CFG_TUH_HUB static bool enum_hub_clear_reset0_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) { (void) dev_addr; (void) request; @@ -540,7 +542,7 @@ static bool enum_hub_get_status0_complete(uint8_t dev_addr, tusb_control_request return true; } - +#endif static bool enum_request_set_addr(void) { @@ -889,7 +891,7 @@ static bool parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configura if ( driver->open(dev->rhport, dev_addr, desc_itf, drv_len) ) { // open successfully - TU_LOG2("%s opened\r\n", driver->name); + TU_LOG2(" Opened successfully\r\n"); // bind interface to found driver dev->itf2drv[desc_itf->bInterfaceNumber] = drv_id; diff --git a/src/tusb.c b/src/tusb.c index 1fc775399..6494287d2 100644 --- a/src/tusb.c +++ b/src/tusb.c @@ -117,10 +117,11 @@ void tu_edpt_bind_driver(uint8_t ep2drv[][2], tusb_desc_interface_t const* desc_ { uint8_t const ep_addr = ((tusb_desc_endpoint_t const*) p_desc)->bEndpointAddress; + TU_LOG(2, " Bind EP %02x to driver id %u\r\n", ep_addr, driver_id); ep2drv[tu_edpt_number(ep_addr)][tu_edpt_dir(ep_addr)] = driver_id; } - len = (uint16_t)(len + tu_desc_len(p_desc)); + len = (uint16_t)(len + tu_desc_len(p_desc)); p_desc = tu_desc_next(p_desc); } } -- cgit v1.3.1 From 6a16f6ccddf77e1b0232aec0c89d2105e391b297 Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 23 Aug 2021 11:01:40 +0700 Subject: rename CFG_TUSB_HOST_DEVICE_MAX to CFG_TUH_DEVICE_MAX --- examples/host/cdc_msc_hid/src/msc_app.c | 2 +- examples/host/cdc_msc_hid/src/tusb_config.h | 2 +- lib/fatfs/diskio.c | 4 ++-- lib/fatfs/diskio.h | 2 +- lib/fatfs/ffconf.h | 2 +- src/class/cdc/cdc_host.c | 4 ++-- src/class/cdc/cdc_rndis_host.c | 10 +++++----- src/class/hid/hid_host.c | 2 +- src/class/msc/msc_host.c | 4 ++-- src/class/vendor/vendor_host.c | 4 ++-- src/host/hcd.h | 2 +- src/host/hub.c | 4 ++-- src/host/usbh.c | 14 +++++++------- src/host/usbh_hcd.h | 2 +- src/portable/ehci/ehci.c | 4 ++-- src/portable/ohci/ohci.h | 2 +- src/tusb_option.h | 10 +++++----- 17 files changed, 37 insertions(+), 37 deletions(-) (limited to 'examples') 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 1 && period_1ms_addr == tu_align32(next_item.address)) && - max_loop < (HCD_MAX_ENDPOINT + EHCI_MAX_ITD + EHCI_MAX_SITD)*CFG_TUSB_HOST_DEVICE_MAX) + max_loop < (HCD_MAX_ENDPOINT + EHCI_MAX_ITD + EHCI_MAX_SITD)*CFG_TUH_DEVICE_MAX) { switch ( next_item.type ) { diff --git a/src/portable/ohci/ohci.h b/src/portable/ohci/ohci.h index 6a634592a..cd90aa45a 100644 --- a/src/portable/ohci/ohci.h +++ b/src/portable/ohci/ohci.h @@ -159,7 +159,7 @@ typedef struct TU_ATTR_ALIGNED(256) struct { ohci_ed_t ed; ohci_gtd_t gtd; - }control[CFG_TUSB_HOST_DEVICE_MAX+1]; + }control[CFG_TUH_DEVICE_MAX+1]; // ochi_itd_t itd[OHCI_MAX_ITD]; // itd requires alignment of 32 ohci_ed_t ed_pool[HCD_MAX_ENDPOINT]; diff --git a/src/tusb_option.h b/src/tusb_option.h index e189c65bb..bbbf10a84 100644 --- a/src/tusb_option.h +++ b/src/tusb_option.h @@ -266,14 +266,14 @@ // HOST OPTIONS //-------------------------------------------------------------------- #if TUSB_OPT_HOST_ENABLED - #ifndef CFG_TUSB_HOST_DEVICE_MAX - #define CFG_TUSB_HOST_DEVICE_MAX 1 - #warning CFG_TUSB_HOST_DEVICE_MAX is not defined, default value is 1 + #ifndef CFG_TUH_DEVICE_MAX + #define CFG_TUH_DEVICE_MAX 1 + #warning CFG_TUH_DEVICE_MAX is not defined, default value is 1 #endif //------------- HUB CLASS -------------// - #if CFG_TUH_HUB && (CFG_TUSB_HOST_DEVICE_MAX == 1) - #error There is no benefit enable hub with max device is 1. Please disable hub or increase CFG_TUSB_HOST_DEVICE_MAX + #if CFG_TUH_HUB && (CFG_TUH_DEVICE_MAX == 1) + #error There is no benefit enable hub with max device is 1. Please disable hub or increase CFG_TUH_DEVICE_MAX #endif #ifndef CFG_TUH_ENUMERATION_BUFSIZE -- cgit v1.3.1 From 3309425211639121ce72784405106ab22c4a426e Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 23 Aug 2021 19:56:53 +0700 Subject: sepearate CFG_TUH_DEVICE_MAX and CFG_TUH_HUB separate dev0 from _usbh_devices pool to save sram --- examples/host/cdc_msc_hid/src/tusb_config.h | 3 +- src/class/cdc/cdc_host.c | 2 + src/class/hid/hid_host.c | 4 +- src/class/msc/msc_host.c | 5 +- src/host/hub.c | 36 ++++++---- src/host/usbh.c | 104 +++++++++++++++------------- src/portable/ehci/ehci.c | 2 +- 7 files changed, 93 insertions(+), 63 deletions(-) (limited to 'examples') diff --git a/examples/host/cdc_msc_hid/src/tusb_config.h b/examples/host/cdc_msc_hid/src/tusb_config.h index e2eb566bd..bc6c68e5b 100644 --- a/examples/host/cdc_msc_hid/src/tusb_config.h +++ b/examples/host/cdc_msc_hid/src/tusb_config.h @@ -80,7 +80,8 @@ #define CFG_TUH_MSC 1 #define CFG_TUH_VENDOR 0 -#define CFG_TUH_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_EPIN_BUFSIZE 64 diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index e14cb0bab..08b9bab99 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -240,6 +240,8 @@ bool cdch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32 void cdch_close(uint8_t dev_addr) { + TU_VERIFY(dev_addr <= CFG_TUH_DEVICE_MAX, ); + cdch_data_t * p_cdc = get_itf(dev_addr); tu_memclr(p_cdc, sizeof(cdch_data_t)); } diff --git a/src/class/hid/hid_host.c b/src/class/hid/hid_host.c index 915f0b21a..a9ea03de6 100644 --- a/src/class/hid/hid_host.c +++ b/src/class/hid/hid_host.c @@ -62,7 +62,7 @@ typedef struct hidh_interface_t instances[CFG_TUH_HID]; } hidh_device_t; -static hidh_device_t _hidh_dev[CFG_TUH_DEVICE_MAX-1]; +static hidh_device_t _hidh_dev[CFG_TUH_DEVICE_MAX]; //------------- Internal prototypes -------------// @@ -240,6 +240,8 @@ bool hidh_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint3 void hidh_close(uint8_t dev_addr) { + TU_VERIFY(dev_addr <= CFG_TUH_DEVICE_MAX, ); + hidh_device_t* hid_dev = get_dev(dev_addr); if (tuh_hid_umount_cb) { diff --git a/src/class/msc/msc_host.c b/src/class/msc/msc_host.c index c7669aa21..8069353cd 100644 --- a/src/class/msc/msc_host.c +++ b/src/class/msc/msc_host.c @@ -76,6 +76,7 @@ CFG_TUSB_MEM_SECTION static msch_interface_t _msch_itf[CFG_TUH_DEVICE_MAX]; CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(4) static uint8_t _msch_buffer[sizeof(scsi_inquiry_resp_t)]; +TU_ATTR_ALWAYS_INLINE static inline msch_interface_t* get_itf(uint8_t dev_addr) { return &_msch_itf[dev_addr-1]; @@ -291,11 +292,13 @@ bool tuh_msc_reset(uint8_t dev_addr) //--------------------------------------------------------------------+ void msch_init(void) { - tu_memclr(_msch_itf, sizeof(msch_interface_t)*CFG_TUH_DEVICE_MAX); + tu_memclr(_msch_itf, sizeof(_msch_itf)); } void msch_close(uint8_t dev_addr) { + TU_VERIFY(dev_addr <= CFG_TUH_DEVICE_MAX, ); + msch_interface_t* p_msc = get_itf(dev_addr); // invoke Application Callback diff --git a/src/host/hub.c b/src/host/hub.c index 65e747e41..fd4dbd04a 100644 --- a/src/host/hub.c +++ b/src/host/hub.c @@ -48,6 +48,12 @@ typedef struct CFG_TUSB_MEM_SECTION static hub_interface_t hub_data[CFG_TUH_HUB]; CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(4) static uint8_t _hub_buffer[sizeof(descriptor_hub_desc_t)]; +TU_ATTR_ALWAYS_INLINE +static inline hub_interface_t* get_itf(uint8_t dev_addr) +{ + return &hub_data[dev_addr-1-CFG_TUH_DEVICE_MAX]; +} + #if CFG_TUSB_DEBUG static char const* const _hub_feature_str[] = { @@ -167,21 +173,26 @@ bool hub_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf TU_ASSERT(usbh_edpt_open(rhport, dev_addr, desc_ep)); - hub_data[dev_addr-1].itf_num = itf_desc->bInterfaceNumber; - hub_data[dev_addr-1].ep_in = desc_ep->bEndpointAddress; + hub_interface_t* p_hub = get_itf(dev_addr); + + p_hub->itf_num = itf_desc->bInterfaceNumber; + p_hub->ep_in = desc_ep->bEndpointAddress; return true; } void hub_close(uint8_t dev_addr) { - tu_memclr(&hub_data[dev_addr-1], sizeof( hub_interface_t)); + TU_VERIFY(dev_addr > CFG_TUH_DEVICE_MAX, ); + hub_interface_t* p_hub = get_itf(dev_addr); + + if (p_hub->ep_in) tu_memclr(p_hub, sizeof( hub_interface_t)); } bool hub_status_pipe_queue(uint8_t dev_addr) { - hub_interface_t * p_hub = &hub_data[dev_addr-1]; - return usbh_edpt_xfer(dev_addr, p_hub->ep_in, &p_hub->status_change, 1); + hub_interface_t* hub_itf = get_itf(dev_addr); + return usbh_edpt_xfer(dev_addr, hub_itf->ep_in, &hub_itf->status_change, 1); } @@ -194,7 +205,7 @@ static bool config_port_power_complete (uint8_t dev_addr, tusb_control_request_t bool hub_set_config(uint8_t dev_addr, uint8_t itf_num) { - hub_interface_t* p_hub = &hub_data[dev_addr-1]; + hub_interface_t* p_hub = get_itf(dev_addr); TU_ASSERT(itf_num == p_hub->itf_num); // Get Hub Descriptor @@ -222,7 +233,7 @@ static bool config_set_port_power (uint8_t dev_addr, tusb_control_request_t cons (void) request; TU_ASSERT(XFER_RESULT_SUCCESS == result); - hub_interface_t* p_hub = &hub_data[dev_addr-1]; + hub_interface_t* p_hub = get_itf(dev_addr); // only use number of ports in hub descriptor descriptor_hub_desc_t const* desc_hub = (descriptor_hub_desc_t const*) _hub_buffer; @@ -238,7 +249,7 @@ static bool config_set_port_power (uint8_t dev_addr, tusb_control_request_t cons static bool config_port_power_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) { TU_ASSERT(XFER_RESULT_SUCCESS == result); - hub_interface_t* p_hub = &hub_data[dev_addr-1]; + hub_interface_t* p_hub = get_itf(dev_addr); if (request->wIndex == p_hub->port_count) { @@ -272,7 +283,7 @@ bool hub_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32 (void) ep_addr; TU_ASSERT(result == XFER_RESULT_SUCCESS); - hub_interface_t * p_hub = &hub_data[dev_addr-1]; + hub_interface_t* p_hub = get_itf(dev_addr); TU_LOG2(" Port Status Change = 0x%02X\r\n", p_hub->status_change); @@ -294,7 +305,8 @@ bool hub_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32 static bool connection_get_status_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) { TU_ASSERT(result == XFER_RESULT_SUCCESS); - hub_interface_t * p_hub = &hub_data[dev_addr-1]; + + hub_interface_t* p_hub = get_itf(dev_addr); uint8_t const port_num = (uint8_t) request->wIndex; // Connection change @@ -322,7 +334,7 @@ static bool connection_clear_conn_change_complete (uint8_t dev_addr, tusb_contro { TU_ASSERT(result == XFER_RESULT_SUCCESS); - hub_interface_t * p_hub = &hub_data[dev_addr-1]; + hub_interface_t* p_hub = get_itf(dev_addr); uint8_t const port_num = (uint8_t) request->wIndex; if ( p_hub->port_status.status.connection ) @@ -353,7 +365,7 @@ static bool connection_port_reset_complete (uint8_t dev_addr, tusb_control_reque { TU_ASSERT(result == XFER_RESULT_SUCCESS); - // usbh_hub_t * p_hub = &hub_data[dev_addr-1]; + // hub_interface_t* p_hub = get_itf(dev_addr); uint8_t const port_num = (uint8_t) request->wIndex; // submit attach event diff --git a/src/host/usbh.c b/src/host/usbh.c index 8e9628cb2..52c552408 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -99,6 +99,14 @@ typedef struct { } usbh_device_t; +typedef struct +{ + uint8_t rhport; + uint8_t hub_addr; + uint8_t hub_port; + uint8_t speed; +} usbh_dev0_t; + //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF @@ -106,6 +114,7 @@ typedef struct { // Invalid driver ID in itf2drv[] ep2drv[][] mapping enum { DRVID_INVALID = 0xFFu }; +enum { ADDR_INVALID = 0xFFu }; #if CFG_TUSB_DEBUG >= 2 #define DRIVER_NAME(_name) .name = _name, @@ -183,9 +192,12 @@ enum { CONFIG_NUM = 1 }; // default to use configuration 1 static bool _usbh_initialized = false; +// Device with address = 0 for enumeration +static usbh_dev0_t _dev0; + // all devices including hub and zero-address TODO exclude device0 to save space -// hub address start from CFG_TUH_DEVICE_MAX -CFG_TUSB_MEM_SECTION usbh_device_t _usbh_devices[1+CFG_TUH_DEVICE_MAX+CFG_TUH_HUB]; +// hub address start from CFG_TUH_DEVICE_MAX+1 +CFG_TUSB_MEM_SECTION usbh_device_t _usbh_devices[1 + CFG_TUH_DEVICE_MAX + CFG_TUH_HUB]; // Event queue // role device/host is used by OS NONE for mutex (disable usb isr) @@ -214,13 +226,13 @@ extern bool usbh_control_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result //--------------------------------------------------------------------+ bool tuh_device_configured(uint8_t dev_addr) { - return _usbh_devices[dev_addr].configured; + return get_device(dev_addr)->configured; } tusb_speed_t tuh_device_get_speed (uint8_t const dev_addr) { - TU_ASSERT( dev_addr <= CFG_TUH_DEVICE_MAX, TUSB_SPEED_INVALID); - return (tusb_speed_t) _usbh_devices[dev_addr].speed; + TU_ASSERT( dev_addr <= CFG_TUH_DEVICE_MAX + CFG_TUH_HUB, TUSB_SPEED_INVALID); + return (tusb_speed_t) get_device(dev_addr)->speed; } #if CFG_TUSB_OS == OPT_OS_NONE @@ -250,15 +262,16 @@ bool tuh_init(uint8_t rhport) TU_LOG2("USBH init\r\n"); tu_memclr(_usbh_devices, sizeof(_usbh_devices)); + tu_memclr(&_dev0, sizeof(_dev0)); //------------- Enumeration & Reporter Task init -------------// _usbh_q = osal_queue_create( &_usbh_qdef ); TU_ASSERT(_usbh_q != NULL); //------------- Semaphore, Mutex for Control Pipe -------------// - for(uint8_t i=0; imutex = osal_mutex_create(&dev->mutexdef); @@ -460,7 +473,7 @@ void hcd_event_device_remove(uint8_t hostid, bool in_isr) void process_device_unplugged(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port) { //------------- find the all devices (star-network) under port that is unplugged -------------// - for (uint8_t dev_addr = 0; dev_addr <= CFG_TUH_DEVICE_MAX; dev_addr ++) + for (uint8_t dev_addr = 0; dev_addr < TU_ARRAY_SIZE(_usbh_devices); dev_addr ++) { usbh_device_t* dev = &_usbh_devices[dev_addr]; @@ -493,13 +506,17 @@ void process_device_unplugged(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port //--------------------------------------------------------------------+ // INTERNAL HELPER //--------------------------------------------------------------------+ -static uint8_t get_new_address(void) +static uint8_t get_new_address(bool is_hub) { - for (uint8_t addr=1; addr <= CFG_TUH_DEVICE_MAX; addr++) + uint8_t const start = (is_hub ? CFG_TUH_DEVICE_MAX : 0) + 1; + uint8_t const count = (is_hub ? CFG_TUH_HUB : CFG_TUH_DEVICE_MAX); + + for (uint8_t i=0; i < count; i++) { + uint8_t const addr = start + i; if (_usbh_devices[addr].state == TUSB_DEVICE_STATE_UNPLUG) return addr; } - return CFG_TUH_DEVICE_MAX+1; + return ADDR_INVALID; } void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num) @@ -561,12 +578,11 @@ static bool enum_hub_clear_reset1_complete(uint8_t dev_addr, tusb_control_reques { (void) dev_addr; (void) request; TU_ASSERT(XFER_RESULT_SUCCESS == result); - usbh_device_t* dev0 = &_usbh_devices[0]; enum_request_set_addr(); // done with hub, waiting for next data on status pipe - (void) hub_status_pipe_queue( dev0->hub_addr ); + (void) hub_status_pipe_queue( _dev0.hub_addr ); return true; } @@ -575,7 +591,6 @@ static bool enum_hub_get_status1_complete(uint8_t dev_addr, tusb_control_request { (void) dev_addr; (void) request; TU_ASSERT(XFER_RESULT_SUCCESS == result); - usbh_device_t* dev0 = &_usbh_devices[0]; hub_port_status_response_t port_status; memcpy(&port_status, _usbh_ctrl_buf, sizeof(hub_port_status_response_t)); @@ -583,7 +598,7 @@ static bool enum_hub_get_status1_complete(uint8_t dev_addr, tusb_control_request // Acknowledge Port Reset Change if Reset Successful if (port_status.change.reset) { - TU_ASSERT( hub_port_clear_feature(dev0->hub_addr, dev0->hub_port, HUB_FEATURE_PORT_RESET_CHANGE, enum_hub_clear_reset1_complete) ); + TU_ASSERT( hub_port_clear_feature(_dev0.hub_addr, _dev0.hub_port, HUB_FEATURE_PORT_RESET_CHANGE, enum_hub_clear_reset1_complete) ); } return true; @@ -593,7 +608,6 @@ static bool enum_hub_get_status0_complete(uint8_t dev_addr, tusb_control_request { (void) dev_addr; (void) request; TU_ASSERT(XFER_RESULT_SUCCESS == result); - usbh_device_t* dev0 = &_usbh_devices[0]; hub_port_status_response_t port_status; memcpy(&port_status, _usbh_ctrl_buf, sizeof(hub_port_status_response_t)); @@ -604,13 +618,13 @@ static bool enum_hub_get_status0_complete(uint8_t dev_addr, tusb_control_request return hub_status_pipe_queue(dev_addr); } - dev0->speed = (port_status.status.high_speed) ? TUSB_SPEED_HIGH : + _dev0.speed = (port_status.status.high_speed) ? TUSB_SPEED_HIGH : (port_status.status.low_speed ) ? TUSB_SPEED_LOW : TUSB_SPEED_FULL; // Acknowledge Port Reset Change if (port_status.change.reset) { - hub_port_clear_feature(dev0->hub_addr, dev0->hub_port, HUB_FEATURE_PORT_RESET_CHANGE, enum_hub_clear_reset0_complete); + hub_port_clear_feature(_dev0.hub_addr, _dev0.hub_port, HUB_FEATURE_PORT_RESET_CHANGE, enum_hub_clear_reset0_complete); } return true; @@ -619,21 +633,22 @@ static bool enum_hub_get_status0_complete(uint8_t dev_addr, tusb_control_request static bool enum_request_set_addr(void) { - // Set Address - uint8_t const new_addr = get_new_address(); - TU_ASSERT(new_addr <= CFG_TUH_DEVICE_MAX); // TODO notify application we reach max devices + tusb_desc_device_t const * desc_device = (tusb_desc_device_t const*) _usbh_ctrl_buf; + + // Get new address + uint8_t const new_addr = get_new_address(desc_device->bDeviceClass == TUSB_CLASS_HUB); + TU_ASSERT(new_addr != ADDR_INVALID); TU_LOG2("Set Address = %d\r\n", new_addr); - usbh_device_t* dev0 = &_usbh_devices[0]; usbh_device_t* new_dev = &_usbh_devices[new_addr]; - new_dev->rhport = dev0->rhport; - new_dev->hub_addr = dev0->hub_addr; - new_dev->hub_port = dev0->hub_port; - new_dev->speed = dev0->speed; + new_dev->rhport = _dev0.rhport; + new_dev->hub_addr = _dev0.hub_addr; + new_dev->hub_port = _dev0.hub_port; + new_dev->speed = _dev0.speed; new_dev->connected = 1; - new_dev->ep0_packet_size = ((tusb_desc_device_t*) _usbh_ctrl_buf)->bMaxPacketSize0; + new_dev->ep0_packet_size = desc_device->bMaxPacketSize0; tusb_control_request_t const new_request = { @@ -656,22 +671,20 @@ static bool enum_request_set_addr(void) static bool enum_new_device(hcd_event_t* event) { - usbh_device_t* dev0 = &_usbh_devices[0]; - dev0->rhport = event->rhport; // TODO refractor integrate to device_pool - dev0->hub_addr = event->connection.hub_addr; - dev0->hub_port = event->connection.hub_port; - dev0->state = TUSB_DEVICE_STATE_UNPLUG; + _dev0.rhport = event->rhport; // TODO refractor integrate to device_pool + _dev0.hub_addr = event->connection.hub_addr; + _dev0.hub_port = event->connection.hub_port; //------------- connected/disconnected directly with roothub -------------// - if (dev0->hub_addr == 0) + if (_dev0.hub_addr == 0) { // wait until device is stable TODO non blocking osal_task_delay(RESET_DELAY); // device unplugged while delaying - if ( !hcd_port_connect_status(dev0->rhport) ) return true; + if ( !hcd_port_connect_status(_dev0.rhport) ) return true; - dev0->speed = hcd_port_speed_get( dev0->rhport ); + _dev0.speed = hcd_port_speed_get(_dev0.rhport ); enum_request_addr0_device_desc(); } @@ -681,7 +694,7 @@ static bool enum_new_device(hcd_event_t* event) { // wait until device is stable osal_task_delay(RESET_DELAY); - TU_ASSERT( hub_port_get_status(dev0->hub_addr, dev0->hub_port, _usbh_ctrl_buf, enum_hub_get_status0_complete) ); + TU_ASSERT( hub_port_get_status(_dev0.hub_addr, _dev0.hub_port, _usbh_ctrl_buf, enum_hub_get_status0_complete) ); } #endif // CFG_TUH_HUB @@ -719,27 +732,26 @@ static bool enum_get_addr0_device_desc_complete(uint8_t dev_addr, tusb_control_r (void) request; TU_ASSERT(0 == dev_addr); - usbh_device_t* dev0 = &_usbh_devices[0]; - if (XFER_RESULT_SUCCESS != result) { #if CFG_TUH_HUB // TODO remove, waiting for next data on status pipe - if (dev0->hub_addr != 0) hub_status_pipe_queue(dev0->hub_addr); + if (_dev0.hub_addr != 0) hub_status_pipe_queue(_dev0.hub_addr); #endif return false; } - TU_ASSERT(tu_desc_type(_usbh_ctrl_buf) == TUSB_DESC_DEVICE); + tusb_desc_device_t const * desc_device = (tusb_desc_device_t const*) _usbh_ctrl_buf; + TU_ASSERT( tu_desc_type(desc_device) == TUSB_DESC_DEVICE ); // Reset device again before Set Address TU_LOG2("Port reset \r\n"); - if (dev0->hub_addr == 0) + if (_dev0.hub_addr == 0) { // connected directly to roothub - hcd_port_reset( dev0->rhport ); // reset port after 8 byte descriptor + hcd_port_reset( _dev0.rhport ); // reset port after 8 byte descriptor osal_task_delay(RESET_DELAY); enum_request_set_addr(); @@ -748,12 +760,12 @@ static bool enum_get_addr0_device_desc_complete(uint8_t dev_addr, tusb_control_r else { // after RESET_DELAY the hub_port_reset() already complete - TU_ASSERT( hub_port_reset(dev0->hub_addr, dev0->hub_port, NULL) ); + TU_ASSERT( hub_port_reset(_dev0.hub_addr, _dev0.hub_port, NULL) ); osal_task_delay(RESET_DELAY); tuh_task(); // FIXME temporarily to clean up port_reset control transfer - TU_ASSERT( hub_port_get_status(dev0->hub_addr, dev0->hub_port, _usbh_ctrl_buf, enum_hub_get_status1_complete) ); + TU_ASSERT( hub_port_get_status(_dev0.hub_addr, _dev0.hub_port, _usbh_ctrl_buf, enum_hub_get_status1_complete) ); } #endif @@ -772,9 +784,7 @@ static bool enum_set_address_complete(uint8_t dev_addr, tusb_control_request_t c new_dev->addressed = 1; // TODO close device 0, may not be needed - usbh_device_t* dev0 = &_usbh_devices[0]; - hcd_device_close(dev0->rhport, 0); - dev0->state = TUSB_DEVICE_STATE_UNPLUG; + hcd_device_close(_dev0.rhport, 0); // open control pipe for new address TU_ASSERT( usbh_edpt_control_open(new_addr, new_dev->ep0_packet_size) ); diff --git a/src/portable/ehci/ehci.c b/src/portable/ehci/ehci.c index 124d88ff3..e3b7499cc 100644 --- a/src/portable/ehci/ehci.c +++ b/src/portable/ehci/ehci.c @@ -71,7 +71,7 @@ typedef struct struct { ehci_qhd_t qhd; ehci_qtd_t qtd; - }control[CFG_TUH_DEVICE_MAX+1]; + }control[CFG_TUH_DEVICE_MAX+CFG_TUH_HUB+1]; ehci_qhd_t qhd_pool[HCD_MAX_ENDPOINT]; ehci_qtd_t qtd_pool[HCD_MAX_XFER] TU_ATTR_ALIGNED(32); -- cgit v1.3.1 From 3c0c051df182cb7261e0f5eb6c52e84f860d0ae1 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 24 Aug 2021 19:10:23 +0700 Subject: add tuh_vid_pid_get() complete Sony PS4 dualshock controller example --- examples/host/hid_controller/.only.MCU_LPC175X_6X | 0 examples/host/hid_controller/.only.MCU_LPC177X_8X | 0 examples/host/hid_controller/.only.MCU_LPC18XX | 0 examples/host/hid_controller/.only.MCU_LPC40XX | 0 examples/host/hid_controller/.only.MCU_LPC43XX | 0 examples/host/hid_controller/.only.MCU_MIMXRT10XX | 0 examples/host/hid_controller/.only.MCU_RP2040 | 0 examples/host/hid_controller/CMakeLists.txt | 29 +++ examples/host/hid_controller/Makefile | 30 +++ examples/host/hid_controller/src/hid_app.c | 249 ++++++++++++++++++++++ examples/host/hid_controller/src/main.c | 93 ++++++++ examples/host/hid_controller/src/tusb_config.h | 95 +++++++++ src/class/hid/hid_host.c | 2 +- src/host/usbh.c | 116 ++++++---- src/host/usbh.h | 4 +- 15 files changed, 569 insertions(+), 49 deletions(-) create mode 100644 examples/host/hid_controller/.only.MCU_LPC175X_6X create mode 100644 examples/host/hid_controller/.only.MCU_LPC177X_8X create mode 100644 examples/host/hid_controller/.only.MCU_LPC18XX create mode 100644 examples/host/hid_controller/.only.MCU_LPC40XX create mode 100644 examples/host/hid_controller/.only.MCU_LPC43XX create mode 100644 examples/host/hid_controller/.only.MCU_MIMXRT10XX create mode 100644 examples/host/hid_controller/.only.MCU_RP2040 create mode 100644 examples/host/hid_controller/CMakeLists.txt create mode 100644 examples/host/hid_controller/Makefile create mode 100644 examples/host/hid_controller/src/hid_app.c create mode 100644 examples/host/hid_controller/src/main.c create mode 100644 examples/host/hid_controller/src/tusb_config.h (limited to 'examples') 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 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 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 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 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 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 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 diff --git a/examples/host/hid_controller/CMakeLists.txt b/examples/host/hid_controller/CMakeLists.txt new file mode 100644 index 000000000..0a99bc3a9 --- /dev/null +++ b/examples/host/hid_controller/CMakeLists.txt @@ -0,0 +1,29 @@ +cmake_minimum_required(VERSION 3.5) + +include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake) + +# gets PROJECT name for the example (e.g. -) +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 + ${CMAKE_CURRENT_SOURCE_DIR}/src/msc_app.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..37ae94abd --- /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 +{ + int8_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(int8_t x, int8_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) = (%d, %d, %d, %d)\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 +#include +#include + +#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_ */ diff --git a/src/class/hid/hid_host.c b/src/class/hid/hid_host.c index 3a832a247..8c66477b3 100644 --- a/src/class/hid/hid_host.c +++ b/src/class/hid/hid_host.c @@ -228,7 +228,7 @@ bool hidh_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint3 if ( dir == TUSB_DIR_IN ) { TU_LOG2(" Get Report callback (%u, %u)\r\n", dev_addr, instance); - TU_LOG1_MEM(hid_itf->epin_buf, 8, 2); + TU_LOG3_MEM(hid_itf->epin_buf, xferred_bytes, 2); tuh_hid_report_received_cb(dev_addr, instance, hid_itf->epin_buf, xferred_bytes); }else { diff --git a/src/host/usbh.c b/src/host/usbh.c index 1b5a422f4..548456a40 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -61,9 +61,13 @@ typedef struct { uint8_t speed; //------------- device descriptor -------------// - uint16_t vendor_id; - uint16_t product_id; - uint8_t ep0_packet_size; + uint16_t vid; + uint16_t pid; + + uint8_t ep0_size; + uint8_t i_manufacturer; + uint8_t i_product; + uint8_t i_serial; //------------- configuration descriptor -------------// // uint8_t interface_count; // bNumInterfaces alias @@ -105,6 +109,8 @@ typedef struct uint8_t hub_addr; uint8_t hub_port; uint8_t speed; + + volatile uint8_t connected; } usbh_dev0_t; @@ -230,9 +236,22 @@ bool tuh_mounted(uint8_t dev_addr) return get_device(dev_addr)->configured; } -tusb_speed_t tuh_speed_get (uint8_t const dev_addr) +bool tuh_vid_pid_get(uint8_t dev_addr, uint16_t* vid, uint16_t* pid) +{ + *vid = *pid = 0; + + TU_VERIFY(tuh_mounted(dev_addr)); + + usbh_device_t const* dev = get_device(dev_addr); + + *vid = dev->vid; + *pid = dev->pid; + + return true; +} + +tusb_speed_t tuh_speed_get (uint8_t dev_addr) { - TU_ASSERT( dev_addr <= CFG_TUH_DEVICE_MAX + CFG_TUH_HUB, TUSB_SPEED_INVALID); return (tusb_speed_t) get_device(dev_addr)->speed; } @@ -652,45 +671,6 @@ static bool enum_hub_get_status0_complete(uint8_t dev_addr, tusb_control_request } #endif -static bool enum_request_set_addr(void) -{ - uint8_t const addr0 = 0; - tusb_desc_device_t const * desc_device = (tusb_desc_device_t const*) _usbh_ctrl_buf; - - // Get new address - uint8_t const new_addr = get_new_address(desc_device->bDeviceClass == TUSB_CLASS_HUB); - TU_ASSERT(new_addr != ADDR_INVALID); - - TU_LOG2("Set Address = %d\r\n", new_addr); - - usbh_device_t* new_dev = get_device(new_addr); - - new_dev->rhport = _dev0.rhport; - new_dev->hub_addr = _dev0.hub_addr; - new_dev->hub_port = _dev0.hub_port; - new_dev->speed = _dev0.speed; - new_dev->connected = 1; - new_dev->ep0_packet_size = desc_device->bMaxPacketSize0; - - tusb_control_request_t const new_request = - { - .bmRequestType_bit = - { - .recipient = TUSB_REQ_RCPT_DEVICE, - .type = TUSB_REQ_TYPE_STANDARD, - .direction = TUSB_DIR_OUT - }, - .bRequest = TUSB_REQ_SET_ADDRESS, - .wValue = new_addr, - .wIndex = 0, - .wLength = 0 - }; - - TU_ASSERT( tuh_control_xfer(addr0, &new_request, NULL, enum_set_address_complete) ); - - return true; -} - static bool enum_new_device(hcd_event_t* event) { _dev0.rhport = event->rhport; // TODO refractor integrate to device_pool @@ -795,6 +775,45 @@ static bool enum_get_addr0_device_desc_complete(uint8_t dev_addr, tusb_control_r return true; } +static bool enum_request_set_addr(void) +{ + uint8_t const addr0 = 0; + tusb_desc_device_t const * desc_device = (tusb_desc_device_t const*) _usbh_ctrl_buf; + + // Get new address + uint8_t const new_addr = get_new_address(desc_device->bDeviceClass == TUSB_CLASS_HUB); + TU_ASSERT(new_addr != ADDR_INVALID); + + TU_LOG2("Set Address = %d\r\n", new_addr); + + usbh_device_t* new_dev = get_device(new_addr); + + new_dev->rhport = _dev0.rhport; + new_dev->hub_addr = _dev0.hub_addr; + new_dev->hub_port = _dev0.hub_port; + new_dev->speed = _dev0.speed; + new_dev->connected = 1; + new_dev->ep0_size = desc_device->bMaxPacketSize0; + + tusb_control_request_t const new_request = + { + .bmRequestType_bit = + { + .recipient = TUSB_REQ_RCPT_DEVICE, + .type = TUSB_REQ_TYPE_STANDARD, + .direction = TUSB_DIR_OUT + }, + .bRequest = TUSB_REQ_SET_ADDRESS, + .wValue = new_addr, + .wIndex = 0, + .wLength = 0 + }; + + TU_ASSERT( tuh_control_xfer(addr0, &new_request, NULL, enum_set_address_complete) ); + + return true; +} + // After SET_ADDRESS is complete static bool enum_set_address_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) { @@ -810,7 +829,7 @@ static bool enum_set_address_complete(uint8_t dev_addr, tusb_control_request_t c hcd_device_close(_dev0.rhport, 0); // open control pipe for new address - TU_ASSERT( usbh_edpt_control_open(new_addr, new_dev->ep0_packet_size) ); + TU_ASSERT( usbh_edpt_control_open(new_addr, new_dev->ep0_size) ); // Get full device descriptor TU_LOG2("Get Device Descriptor\r\n"); @@ -841,8 +860,11 @@ static bool enum_get_device_desc_complete(uint8_t dev_addr, tusb_control_request tusb_desc_device_t const * desc_device = (tusb_desc_device_t const*) _usbh_ctrl_buf; usbh_device_t* dev = get_device(dev_addr); - dev->vendor_id = desc_device->idVendor; - dev->product_id = desc_device->idProduct; + dev->vid = desc_device->idVendor; + dev->pid = desc_device->idProduct; + dev->i_manufacturer = desc_device->iManufacturer; + dev->i_product = desc_device->iProduct; + dev->i_serial = desc_device->iSerialNumber; // if (tuh_attach_cb) tuh_attach_cb((tusb_desc_device_t*) _usbh_ctrl_buf); diff --git a/src/host/usbh.h b/src/host/usbh.h index 5f7229f27..8411cad28 100644 --- a/src/host/usbh.h +++ b/src/host/usbh.h @@ -57,7 +57,8 @@ void tuh_task(void); extern void hcd_int_handler(uint8_t rhport); #define tuh_int_handler hcd_int_handler -tusb_speed_t tuh_speed_get (uint8_t dev_addr); +bool tuh_vid_pid_get(uint8_t dev_addr, uint16_t* vid, uint16_t* pid); +tusb_speed_t tuh_speed_get(uint8_t dev_addr); // Check if device is connected and configured bool tuh_mounted(uint8_t dev_addr); @@ -66,6 +67,7 @@ bool tuh_mounted(uint8_t dev_addr); static inline bool tuh_suspended(uint8_t dev_addr) { // TODO implement suspend & resume on host + (void) dev_addr; return false; } -- cgit v1.3.1 From 3debeb637acb49222f36fa08f904adc4f5d9e1b7 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 24 Aug 2021 21:34:51 +0700 Subject: test hid controller with rp2040 --- examples/host/hid_controller/CMakeLists.txt | 1 - examples/host/hid_controller/src/hid_app.c | 22 +++++++++++----------- src/host/usbh.c | 2 +- 3 files changed, 12 insertions(+), 13 deletions(-) (limited to 'examples') diff --git a/examples/host/hid_controller/CMakeLists.txt b/examples/host/hid_controller/CMakeLists.txt index 0a99bc3a9..aaf8bc34f 100644 --- a/examples/host/hid_controller/CMakeLists.txt +++ b/examples/host/hid_controller/CMakeLists.txt @@ -16,7 +16,6 @@ add_executable(${PROJECT}) target_sources(${PROJECT} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src/hid_app.c ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c - ${CMAKE_CURRENT_SOURCE_DIR}/src/msc_app.c ) # Example include diff --git a/examples/host/hid_controller/src/hid_app.c b/examples/host/hid_controller/src/hid_app.c index 37ae94abd..c61ce70f3 100644 --- a/examples/host/hid_controller/src/hid_app.c +++ b/examples/host/hid_controller/src/hid_app.c @@ -64,7 +64,7 @@ // Sony DS4 report layout detail https://www.psdevwiki.com/ps4/DS4-USB typedef struct TU_ATTR_PACKED { - int8_t x, y, z, rz; // joystick + 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) @@ -160,7 +160,7 @@ void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance) } // check if different than 2 -bool diff_than_2(int8_t x, int8_t y) +bool diff_than_2(uint8_t x, uint8_t y) { return (x - y > 2) || (y - x > 2); } @@ -205,7 +205,7 @@ void process_sony_ds4(uint8_t const* report, uint16_t len) // We need more than memcmp to check if report is different enough if ( diff_report(&prev_report, &ds4_report) ) { - printf("(x, y, z, rz) = (%d, %d, %d, %d)\r\n", ds4_report.x, ds4_report.y, ds4_report.z, ds4_report.rz); + 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 "); @@ -213,15 +213,15 @@ void process_sony_ds4(uint8_t const* report, uint16_t len) 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.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.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 "); diff --git a/src/host/usbh.c b/src/host/usbh.c index 548456a40..51b8f85b6 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -252,7 +252,7 @@ bool tuh_vid_pid_get(uint8_t dev_addr, uint16_t* vid, uint16_t* pid) tusb_speed_t tuh_speed_get (uint8_t dev_addr) { - return (tusb_speed_t) get_device(dev_addr)->speed; + return (tusb_speed_t) (dev_addr ? get_device(dev_addr)->speed : _dev0.speed); } #if CFG_TUSB_OS == OPT_OS_NONE -- cgit v1.3.1