diff --git a/examples/host/bare_api/src/main.c b/examples/host/bare_api/src/main.c index 5f8f886c..73e97c39 100644 --- a/examples/host/bare_api/src/main.c +++ b/examples/host/bare_api/src/main.c @@ -46,8 +46,6 @@ int main(void) board_init(); printf("TinyUSB Host HID Controller Example\r\n"); - printf("Note: Events only displayed for explictly supported controllers\r\n"); - tusb_init(); while (1) @@ -64,10 +62,74 @@ int main(void) // TinyUSB Callbacks //--------------------------------------------------------------------+ -uint8_t usb_buf[256] TU_ATTR_ALIGNED(4); +// English +#define LANGUAGE_ID 0x0409 +//uint8_t usb_buf[256] TU_ATTR_ALIGNED(4); tusb_desc_device_t desc_device; +static volatile xfer_result_t _get_string_result; + +static bool _transfer_done_cb(uint8_t daddr, tusb_control_request_t const *request, xfer_result_t result) { + (void)daddr; + (void)request; + _get_string_result = result; + return true; +} + +static void _convert_utf16le_to_utf8(const uint16_t *utf16, size_t utf16_len, uint8_t *utf8, size_t utf8_len) { + // TODO: Check for runover. + (void)utf8_len; + // Get the UTF-16 length out of the data itself. + + for (size_t i = 0; i < utf16_len; i++) { + uint16_t chr = utf16[i]; + if (chr < 0x80) { + *utf8++ = chr & 0xff; + } else if (chr < 0x800) { + *utf8++ = (uint8_t)(0xC0 | (chr >> 6 & 0x1F)); + *utf8++ = (uint8_t)(0x80 | (chr >> 0 & 0x3F)); + } else { + // TODO: Verify surrogate. + *utf8++ = (uint8_t)(0xE0 | (chr >> 12 & 0x0F)); + *utf8++ = (uint8_t)(0x80 | (chr >> 6 & 0x3F)); + *utf8++ = (uint8_t)(0x80 | (chr >> 0 & 0x3F)); + } + // TODO: Handle UTF-16 code points that take two entries. + } +} + +// Count how many bytes a utf-16-le encoded string will take in utf-8. +static int _count_utf8_bytes(const uint16_t *buf, size_t len) { + size_t total_bytes = 0; + for (size_t i = 0; i < len; i++) { + uint16_t chr = buf[i]; + if (chr < 0x80) { + total_bytes += 1; + } else if (chr < 0x800) { + total_bytes += 2; + } else { + total_bytes += 3; + } + // TODO: Handle UTF-16 code points that take two entries. + } + return total_bytes; +} + +static void _wait_and_convert(uint16_t *temp_buf, size_t buf_len) { + while (_get_string_result == 0xff) { + tuh_task(); + } + if (_get_string_result != XFER_RESULT_SUCCESS) { + temp_buf[0] = 0; + return; + } + size_t utf16_len = ((temp_buf[0] & 0xff) - 2) / sizeof(uint16_t); + size_t utf8_len = _count_utf8_bytes(temp_buf + 1, utf16_len); + _convert_utf16le_to_utf8(temp_buf + 1, utf16_len, (uint8_t *) temp_buf, sizeof(uint16_t) * buf_len); + ((uint8_t*) temp_buf)[utf8_len] = '\0'; +} + bool print_device_descriptor(uint8_t daddr, tusb_control_request_t const * request, xfer_result_t result) { (void) request; @@ -78,26 +140,49 @@ bool print_device_descriptor(uint8_t daddr, tusb_control_request_t const * reque return false; } - printf("Rhport %u Device %u: ID %04x:%04x\r\n", 0, daddr, desc_device.idVendor, desc_device.idProduct); + printf("Device %u: ID %04x:%04x\r\n", daddr, desc_device.idVendor, desc_device.idProduct); printf("Device Descriptor:\r\n"); - printf(" bLength %u\r\n", desc_device.bLength); - printf(" bDescriptorType %u\r\n", desc_device.bDescriptorType); - printf(" bcdUSB %04x\r\n", desc_device.bcdUSB); + printf(" bLength %u\r\n" , desc_device.bLength); + printf(" bDescriptorType %u\r\n" , desc_device.bDescriptorType); + printf(" bcdUSB %04x\r\n" , desc_device.bcdUSB); + printf(" bDeviceClass %u\r\n" , desc_device.bDeviceClass); + printf(" bDeviceSubClass %u\r\n" , desc_device.bDeviceSubClass); + printf(" bDeviceProtocol %u\r\n" , desc_device.bDeviceProtocol); + printf(" bMaxPacketSize0 %u\r\n" , desc_device.bMaxPacketSize0); + printf(" idVendor 0x%04x\r\n" , desc_device.idVendor); + printf(" idProduct 0x%04x\r\n" , desc_device.idProduct); + printf(" bcdDevice %04x\r\n" , desc_device.bcdDevice); - printf(" bDeviceClass %u\r\n", desc_device.bDeviceClass); - printf(" bDeviceSubClass %u\r\n", desc_device.bDeviceSubClass); - printf(" bDeviceProtocol %u\r\n", desc_device.bDeviceProtocol); - printf(" bMaxPacketSize0 %u\r\n", desc_device.bMaxPacketSize0); + _get_string_result = 0xff; + uint16_t temp_buf[128]; - printf(" idVendor 0x%04x\r\n", desc_device.idVendor); - printf(" idProduct 0x%04x\r\n", desc_device.idProduct); - printf(" bcdDevice %04x\r\n", desc_device.bcdDevice); + printf(" iManufacturer %u " , desc_device.iManufacturer); + temp_buf[0] = 0; + if (tuh_descriptor_get_manufacturer_string(daddr, LANGUAGE_ID, temp_buf, TU_ARRAY_SIZE(temp_buf), _transfer_done_cb)) { + _wait_and_convert(temp_buf, TU_ARRAY_SIZE(temp_buf)); + printf((const char*) temp_buf); + } + printf("\r\n"); - printf(" iManufacturer %u\r\n", desc_device.iManufacturer); - printf(" iProduct %u\r\n", desc_device.iProduct); - printf(" iSerialNumber %u\r\n", desc_device.iSerialNumber); + printf(" iProduct %u " , desc_device.iProduct); + _get_string_result = 0xff; + temp_buf[0] = 0; + if (tuh_descriptor_get_product_string(daddr, LANGUAGE_ID, temp_buf, TU_ARRAY_SIZE(temp_buf), _transfer_done_cb)) { + _wait_and_convert(temp_buf, TU_ARRAY_SIZE(temp_buf)); + printf((const char*) temp_buf); + } + printf("\r\n"); - printf(" bNumConfigurations %u\r\n", desc_device.bNumConfigurations); + printf(" iSerialNumber %u " , desc_device.iSerialNumber); + _get_string_result = 0xff; + temp_buf[0] = 0; + if (tuh_descriptor_get_serial_string(daddr, LANGUAGE_ID, temp_buf, TU_ARRAY_SIZE(temp_buf), _transfer_done_cb)) { + _wait_and_convert(temp_buf, TU_ARRAY_SIZE(temp_buf)); + printf((const char*) temp_buf); + } + printf("\r\n"); + + printf(" bNumConfigurations %u\r\n" , desc_device.bNumConfigurations); return true; } @@ -107,7 +192,7 @@ void tuh_mount_cb (uint8_t daddr) { printf("Device attached, address = %d\r\n", daddr); - // get device descriptor + // Get Device Descriptor tuh_descriptor_get_device(daddr, &desc_device, 18, print_device_descriptor); } diff --git a/examples/host/device_info/CMakeLists.txt b/examples/host/device_info/CMakeLists.txt deleted file mode 100644 index bff281a8..00000000 --- a/examples/host/device_info/CMakeLists.txt +++ /dev/null @@ -1,27 +0,0 @@ -cmake_minimum_required(VERSION 3.5) - -include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake) - -# gets PROJECT name for the example -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 - ) - -# 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/device_info/Makefile b/examples/host/device_info/Makefile deleted file mode 100644 index c59369ff..00000000 --- a/examples/host/device_info/Makefile +++ /dev/null @@ -1,28 +0,0 @@ -include ../../../tools/top.mk -include ../../make.mk - -INC += \ - src \ - $(TOP)/hw \ - -# Example source -EXAMPLE_SOURCE += \ - src/main.c - -SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE)) - -# TODO: suppress warning caused by host stack -CFLAGS += -Wno-error=cast-align -Wno-error=null-dereference - -# TinyUSB Host Stack source -SRC_C += \ - src/class/cdc/cdc_host.c \ - 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/ohci/ohci.c \ - src/portable/nxp/lpc17_40/hcd_lpc17_40.c - -include ../../rules.mk diff --git a/examples/host/device_info/only.txt b/examples/host/device_info/only.txt deleted file mode 100644 index 7fe4e3f5..00000000 --- a/examples/host/device_info/only.txt +++ /dev/null @@ -1,9 +0,0 @@ -mcu:LPC175X_6X -mcu:LPC177X_8X -mcu:LPC18XX -mcu:LPC40XX -mcu:LPC43XX -mcu:MIMXRT10XX -mcu:RP2040 -mcu:MSP432E4 -mcu:RX65X diff --git a/examples/host/device_info/src/main.c b/examples/host/device_info/src/main.c deleted file mode 100644 index e6149db8..00000000 --- a/examples/host/device_info/src/main.c +++ /dev/null @@ -1,194 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2022 Scott Shawcroft for Adafruit Industries - * - * 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 prints out info about the enumerated devices. */ - - -#include -#include -#include - -#include "bsp/board.h" -#include "tusb.h" - -//--------------------------------------------------------------------+ -// MACRO CONSTANT TYPEDEF PROTYPES -//--------------------------------------------------------------------+ -void led_blinking_task(void); - -static xfer_result_t _get_string_result; - -static bool _transfer_done_cb(uint8_t daddr, tusb_control_request_t const *request, xfer_result_t result) { - (void)daddr; - (void)request; - _get_string_result = result; - return true; -} - -static void _convert_utf16le_to_utf8(const uint16_t *utf16, size_t utf16_len, uint8_t *utf8, size_t utf8_len) { - // TODO: Check for runover. - (void)utf8_len; - // Get the UTF-16 length out of the data itself. - - for (size_t i = 0; i < utf16_len; i++) { - uint16_t chr = utf16[i]; - if (chr < 0x80) { - *utf8++ = chr & 0xff; - } else if (chr < 0x800) { - *utf8++ = (uint8_t)(0xC0 | (chr >> 6 & 0x1F)); - *utf8++ = (uint8_t)(0x80 | (chr >> 0 & 0x3F)); - } else { - // TODO: Verify surrogate. - *utf8++ = (uint8_t)(0xE0 | (chr >> 12 & 0x0F)); - *utf8++ = (uint8_t)(0x80 | (chr >> 6 & 0x3F)); - *utf8++ = (uint8_t)(0x80 | (chr >> 0 & 0x3F)); - } - // TODO: Handle UTF-16 code points that take two entries. - } -} - -// Count how many bytes a utf-16-le encoded string will take in utf-8. -static int _count_utf8_bytes(const uint16_t *buf, size_t len) { - size_t total_bytes = 0; - for (size_t i = 0; i < len; i++) { - uint16_t chr = buf[i]; - if (chr < 0x80) { - total_bytes += 1; - } else if (chr < 0x800) { - total_bytes += 2; - } else { - total_bytes += 3; - } - // TODO: Handle UTF-16 code points that take two entries. - } - return total_bytes; -} - -static void _wait_and_convert(uint16_t *temp_buf, size_t buf_len) { - while (_get_string_result == 0xff) { - tuh_task(); - } - if (_get_string_result != XFER_RESULT_SUCCESS) { - temp_buf[0] = 0; - return; - } - size_t utf16_len = ((temp_buf[0] & 0xff) - 2) / sizeof(uint16_t); - size_t utf8_len = _count_utf8_bytes(temp_buf + 1, utf16_len); - _convert_utf16le_to_utf8(temp_buf + 1, utf16_len, (uint8_t *) temp_buf, sizeof(uint16_t) * buf_len); - ((uint8_t*) temp_buf)[utf8_len] = '\0'; -} - -/*------------- MAIN -------------*/ -int main(void) -{ - board_init(); - - printf("TinyUSB Host Device Info Example\r\n"); - - tusb_init(); - - uint32_t interval_ms = 5000; - uint32_t start_time = 0; - - while (1) - { - // tinyusb host task - tuh_task(); - led_blinking_task(); - - if (board_millis() - start_time < interval_ms) { - continue; - } - start_time = board_millis(); - // Brute force check every device address to see if it is active. - for (int i = 1; i < CFG_TUH_DEVICE_MAX + CFG_TUH_HUB + 1; i++) { - if (!tuh_ready(i)) { - continue; - } - uint16_t vid; - uint16_t pid; - tuh_vid_pid_get(i, &vid, &pid); - printf("%d vid %04x pid %04x\r\n", i, vid, pid); - - tusb_speed_t speed = tuh_speed_get(i); - switch (speed) { - case TUSB_SPEED_FULL: - printf("Full speed\r\n"); - break; - case TUSB_SPEED_LOW: - printf("Low speed\r\n"); - break; - case TUSB_SPEED_HIGH: - printf("High speed\r\n"); - break; - default: - break; - } - - _get_string_result = 0xff; - uint16_t temp_buf[127]; - if (tuh_descriptor_string_serial_get(i, 0, temp_buf, TU_ARRAY_SIZE(temp_buf), _transfer_done_cb)) { - _wait_and_convert(temp_buf, TU_ARRAY_SIZE(temp_buf)); - printf("Serial: %s\r\n", (const char*) temp_buf); - } - - _get_string_result = 0xff; - temp_buf[0] = 0; - if (tuh_descriptor_string_product_get(i, 0, temp_buf, TU_ARRAY_SIZE(temp_buf), _transfer_done_cb)) { - _wait_and_convert(temp_buf, TU_ARRAY_SIZE(temp_buf)); - printf("Product: %s\r\n", (const char*) temp_buf); - } - - _get_string_result = 0xff; - temp_buf[0] = 0; - if (tuh_descriptor_string_manufacturer_get(i, 0, temp_buf, TU_ARRAY_SIZE(temp_buf), _transfer_done_cb)) { - _wait_and_convert(temp_buf, TU_ARRAY_SIZE(temp_buf)); - printf("Manufacturer: %s\r\n", (const char*) temp_buf); - } - } - printf("\n"); - } - - return 0; -} - - -//--------------------------------------------------------------------+ -// 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/device_info/src/tusb_config.h b/examples/host/device_info/src/tusb_config.h deleted file mode 100644 index 6b413e46..00000000 --- a/examples/host/device_info/src/tusb_config.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - */ - -#ifndef _TUSB_CONFIG_H_ -#define _TUSB_CONFIG_H_ - -#ifdef __cplusplus - extern "C" { -#endif - -//-------------------------------------------------------------------- -// COMMON CONFIGURATION -//-------------------------------------------------------------------- - -// defined by 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 - -// only hub class is enabled -#define CFG_TUH_HUB 1 - -// max device support (excluding hub device) -// 1 hub typically has 4 ports -#define CFG_TUH_DEVICE_MAX (CFG_TUH_HUB ? 4 : 1) - -#define CFG_TUH_ENDPOINT_MAX 8 - -#define CFG_TUH_TASK_QUEUE_SZ 64 - -//------------- HID -------------// - -#define CFG_TUH_HID_EP_BUFSIZE 64 - -#ifdef __cplusplus - } -#endif - -#endif /* _TUSB_CONFIG_H_ */ diff --git a/src/host/usbh.c b/src/host/usbh.c index 11bf2f99..617aff79 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -535,7 +535,7 @@ void tuh_task(void) break; case HCD_EVENT_DEVICE_REMOVE: - TU_LOG2("USBH DEVICE REMOVED\r\n"); + TU_LOG2("[%u:%u:%u] USBH DEVICE REMOVED\r\n", event.rhport, event.connection.hub_addr, event.connection.hub_port); process_device_unplugged(event.rhport, event.connection.hub_addr, event.connection.hub_port); #if CFG_TUH_HUB @@ -924,6 +924,8 @@ static void process_device_unplugged(uint8_t rhport, uint8_t hub_addr, uint8_t h (hub_port == 0 || dev->hub_port == hub_port) && dev->connected) { + TU_LOG2(" Address = %u\r\n", dev_addr); + // Invoke callback before close driver if (tuh_umount_cb) tuh_umount_cb(dev_addr);