diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index d00ee78bda..30f11e7d0f 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -1,86 +1,48 @@ -name: Bug Report -description: Report a problem with TinyUSB -labels: 'Bug 🐞' +name: Bug report +description: Report build and runtime bugs +labels: ["Type: Bug"] body: - - type: markdown - attributes: - value: | - Thanks for taking the time to fill out this bug report! - It's okay to leave some blank if it doesn't apply to your problem. - - - type: dropdown + - type: checkboxes + id: checklist attributes: - label: Operating System + label: Answers checklist. + description: Before submitting a new issue, please follow the checklist and try to find the answer. options: - - Linux - - MacOS - - RaspberryPi OS - - Windows 7 - - Windows 10 - - Windows 11 - - Others - validations: - required: true - + - label: I have read the component documentation [ESP-IDF Components](https://components.espressif.com) and the issue is not addressed there. + required: true + - label: I am using target and esp-idf version as defined in component's idf_component.yml + required: true + - label: I have searched the [issue tracker](https://github.com/espressif/tinyusb/issues?q=is%3Aissue) for a similar issue and not found any related issue. + required: true - type: input + id: idf_version attributes: - label: Board - placeholder: e.g Feather nRF52840 Express - validations: - required: true - - - type: textarea - attributes: - label: Firmware - placeholder: | - e.g examples/device/cdc_msc. If it is custom firmware, it is preferably compiled like one in example folder and reviewable for people to comment on. The easiest way is - - Fork this repo, checkout a new branch - - Add your-own-example based on stock one - - Push and post it here. + label: ESP-IDF version. + description: On which ESP-IDF version does this issue occur on? Run `git describe --tags` in your esp-idf folder to find it. + placeholder: ex. v5.0-rc1 validations: required: true - - - type: textarea - attributes: - label: What happened ? - placeholder: A clear and concise description of what the bug is. - validations: - required: true - - - type: textarea + - type: input + id: devkit attributes: - label: How to reproduce ? - placeholder: | - Exact steps in chronological order, details should be specific e.g if you use a command/script to test with, please post it as well. - 1. Go to '...' - 2. Click on '....' - 3. See error + label: Development Kit. + description: On which Development Kit does this issue occur on? + placeholder: ex. ESP32-Wrover-Kit v2 | Custom Board validations: required: true - - - type: textarea + - type: input + id: component_version attributes: - label: Debug Log as txt file (LOG/CFG_TUSB_DEBUG=2) - placeholder: | - Attach your debug log txt file here, where the issue occurred, best with comments to explain the actual events. - - Note1: Please DO NOT paste your lengthy log contents here since it hurts the readability. - Note2: To enable logging, add `LOG=2` to to the make command if building with stock examples or set `CFG_TUSB_DEBUG=2` in your tusb_config.h. - More information can be found at [example's readme](https://github.com/hathach/tinyusb/blob/master/docs/getting_started.md) + label: Used Component version. + description: On which Component version does this issue occur on? Check `dependencies.lock` file in your project root to find it. + placeholder: ex. v1.2.0-rc0 validations: required: true - - type: textarea + id: more-info attributes: - label: Screenshots - description: If applicable, add screenshots to help explain your problem. + label: More Information. + description: Do you have any other information from investigating this? + placeholder: ex. I tried on my friend's Windows 10 PC and the command works there. validations: required: false - - - type: checkboxes - attributes: - label: I have checked existing issues, dicussion and documentation - description: You agree to check all the resources above before opening a new issue. - options: - - label: I confirm I have checked existing issues, dicussion and documentation. - required: true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml deleted file mode 100644 index 28fd274674..0000000000 --- a/.github/ISSUE_TEMPLATE/config.yml +++ /dev/null @@ -1,8 +0,0 @@ -blank_issues_enabled: false -contact_links: - - name: TinyUSB Discussion - url: https://github.com/hathach/tinyusb/discussions - about: If you have other questions or need help, post it here. - - name: TinyUSB Docs - url: https://docs.tinyusb.org/ - about: Online documentation diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml deleted file mode 100644 index 19f403246e..0000000000 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ /dev/null @@ -1,49 +0,0 @@ -name: Feature Request -description: Suggest an idea for this project -labels: 'Feature 💡' -body: - - type: markdown - attributes: - value: | - Thanks for taking the time to fill out this request! - It's okay to leave some blank if it doesn't apply to your request. - - - type: input - attributes: - label: Related area - description: Please briefly explain the area of your Feature Request. - placeholder: eg. new port support, device stack, class driver ... - validations: - required: true - - - type: input - attributes: - label: Hardware specification - description: Please provide if your proposal depends on specific Hardware. - placeholder: eg. rp2040, samd51 ... - validations: - required: true - - - type: textarea - attributes: - label: Is your feature request related to a problem? - description: Please provide a clear and concise description of what the problem is. Add relevant issue link. - placeholder: ex. I'm facing the issue/missing function... - validations: - required: true - - - type: textarea - attributes: - label: Describe the solution you'd like - description: Please provide a clear and concise description of what you want to happen. - placeholder: ex. When using this function... - validations: - required: true - - - type: checkboxes - attributes: - label: I have checked existing issues, dicussion and documentation - description: You agree to check all the resources above before opening a new issue. - options: - - label: I confirm I have checked existing issues, dicussion and documentation. - required: true diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000000..22c9febcb0 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,17 @@ +## Requirements +_Provide a requirements for requesting changes_ + +## Limitations +_Describe limitations if there are any_ + +## Breaking change +_No breaking changes_ + +## Checklist + +- [ ] Pull Request name has appropriate format (for example: "fix(dcd_dwc2): Resolved address selection when several phy are present") +- [ ] _Optional:_ README.md updated +- [ ] CI passed + +## Related issues +_No related issues_ diff --git a/.github/ci/override_managed_component.py b/.github/ci/override_managed_component.py new file mode 100644 index 0000000000..bae246804a --- /dev/null +++ b/.github/ci/override_managed_component.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python +# +# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Apache-2.0 + +import sys +import argparse +from pathlib import Path +from glob import glob +from idf_component_tools.manifest import ManifestManager + + +def override_with_local_component(component, local_path, app): + app_path = Path(app) + + absolute_local_path = Path(local_path).absolute() + if not absolute_local_path.exists(): + print('[Error] {} path does not exist'.format(local_path)) + raise Exception + if not app_path.exists(): + print('[Error] {} path does not exist'.format(app_path)) + raise Exception + + print('[Info] Processing app {}'.format(app)) + manager = ManifestManager(app_path / 'main', 'app') + if '/' not in component: + # Prepend with default namespace + component_with_namespace = 'espressif/' + component + + try: + manager.manifest_tree['dependencies'][component_with_namespace] = { + 'version': '*', + 'override_path': str(absolute_local_path) + } + except KeyError: + print('[Error] {} app does not depend on {}'.format(app, component_with_namespace)) + raise KeyError + + manager.dump() + + +def override_with_local_component_all(component, local_path, apps): + # Process wildcard, e.g. "app_prefix_*" + apps_with_glob = list() + for app in apps: + apps_with_glob += glob(app) + + # Go through all collected apps + for app in apps_with_glob: + try: + override_with_local_component(component, local_path, app) + except: + print("[Error] Could not process app {}".format(app)) + return -1 + return 0 + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('component', help='Existing component that the app depends on') + parser.add_argument('local_path', help='Path to component that will be used instead of the managed version') + parser.add_argument('apps', nargs='*', help='List of apps to process') + args = parser.parse_args() + sys.exit(override_with_local_component_all(args.component, args.local_path, args.apps)) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md deleted file mode 100644 index aa148eb79f..0000000000 --- a/.github/pull_request_template.md +++ /dev/null @@ -1,5 +0,0 @@ -**Describe the PR** -A clear and concise description of what this PR solve. - -**Additional context** -If applicable, add any other context about the PR and/or screenshots here. diff --git a/.github/workflows/build_idf_examples.yml b/.github/workflows/build_idf_examples.yml new file mode 100644 index 0000000000..7a0a0bab4b --- /dev/null +++ b/.github/workflows/build_idf_examples.yml @@ -0,0 +1,28 @@ +name: Build ESP-IDF USB examples + +on: + schedule: + - cron: '0 0 * * SAT' # Saturday midnight + pull_request: + types: [opened, reopened, synchronize] + +jobs: + build: + strategy: + matrix: + idf_ver: ["release-v5.0", "release-v5.1", "release-v5.2", "release-v5.3", "release-v5.4", "latest"] + runs-on: ubuntu-20.04 + container: espressif/idf:${{ matrix.idf_ver }} + steps: + - uses: actions/checkout@v4 + with: + submodules: 'true' + - name: Build ESP-IDF USB Device examples + shell: bash + run: | + . ${IDF_PATH}/export.sh + pip install idf-component-manager==1.5.2 idf-build-apps --upgrade + python .github/ci/override_managed_component.py tinyusb . ${IDF_PATH}/examples/peripherals/usb/device/tusb_* + cd ${IDF_PATH} + idf-build-apps find --path examples/peripherals/usb/device/ --recursive --target all --manifest-file examples/peripherals/.build-test-rules.yml + idf-build-apps build --path examples/peripherals/usb/device/ --recursive --target all --manifest-file examples/peripherals/.build-test-rules.yml diff --git a/.github/workflows/build_iot_examples.yml b/.github/workflows/build_iot_examples.yml new file mode 100644 index 0000000000..572e760f3e --- /dev/null +++ b/.github/workflows/build_iot_examples.yml @@ -0,0 +1,30 @@ +name: Build ESP IoT Solution examples + +on: + schedule: + - cron: '0 0 * * SAT' # Saturday midnight + pull_request: + types: [opened, reopened, synchronize] + +jobs: + build: + strategy: + matrix: + idf_ver: ["latest"] + runs-on: ubuntu-20.04 + container: espressif/iot-solution:${{ matrix.idf_ver }} + steps: + - uses: actions/checkout@v4 + with: + submodules: 'true' + - name: Build ESP IOT Solution examples + shell: bash + run: | + echo ${IDF_PATH} +# run: | +# . ${IDF_PATH}/export.sh +# pip install idf-component-manager==1.5.2 idf-build-apps --upgrade +# python .github/ci/override_managed_component.py tinyusb . ${IDF_PATH}/examples/peripherals/usb/device/tusb_* +# cd ${IDF_PATH} +# idf-build-apps find --path examples/peripherals/usb/device/ --recursive --target all --manifest-file examples/peripherals/.build-test-rules.yml +# idf-build-apps build --path examples/peripherals/usb/device/ --recursive --target all --manifest-file examples/peripherals/.build-test-rules.yml diff --git a/.github/workflows/upload_component.yml b/.github/workflows/upload_component.yml new file mode 100644 index 0000000000..2dde0268ce --- /dev/null +++ b/.github/workflows/upload_component.yml @@ -0,0 +1,25 @@ +name: Push TinyUSB to Espressif Component Service + +# If the commit is tagged, it will be uploaded. Other scenario silently fail. +on: + push: + tags: + - v* + +jobs: + upload_components: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Remove unneeded files + shell: bash + run: rm -rf docs tools lib/embedded-cli lib/fatfs lib/SEGGER_RTT + + - name: Upload components to component service + uses: espressif/upload-components-ci-action@v1 + with: + name: "tinyusb" + version: ${{ github.ref_name }} + namespace: "espressif" + api_token: ${{ secrets.IDF_COMPONENT_API_TOKEN }} diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000000..c5ab91fab1 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,65 @@ +idf_build_get_property(target IDF_TARGET) + +if(target STREQUAL "esp32s3") + set(tusb_mcu "OPT_MCU_ESP32S3") + set(tusb_family "esp32sx") +elseif(target STREQUAL "esp32s2") + set(tusb_mcu "OPT_MCU_ESP32S2") + set(tusb_family "esp32sx") +elseif(target STREQUAL "esp32p4") + set(tusb_mcu "OPT_MCU_ESP32P4") + set(tusb_family "esp32px") +endif() + +set(compile_options + "-DCFG_TUSB_MCU=${tusb_mcu}" + ) + +idf_component_get_property(freertos_include freertos ORIG_INCLUDE_PATH) + +set(includes_private + "src/" + "src/device" + "lib/networking" # For RNDIS definitions + ) + +set(includes_public + "src/" + # The FreeRTOS API include convention in tinyusb is different from esp-idf + "${freertos_include}" + ) + +set(srcs + "src/class/cdc/cdc_device.c" + "src/class/hid/hid_device.c" + "src/class/midi/midi_device.c" + "src/class/msc/msc_device.c" + "src/class/vendor/vendor_device.c" + "src/class/audio/audio_device.c" + "src/class/video/video_device.c" + "src/class/bth/bth_device.c" + # NET class + "src/class/net/ecm_rndis_device.c" + "lib/networking/rndis_reports.c" + "src/class/net/ncm_device.c" + # DFU + "src/class/dfu/dfu_device.c" + "src/class/dfu/dfu_rt_device.c" + # Common, device-mode related + "src/portable/synopsys/dwc2/dcd_dwc2.c" + "src/common/tusb_fifo.c" + "src/device/usbd_control.c" + "src/device/usbd.c" + "src/tusb.c" + ) + +idf_component_register(SRCS ${srcs} + INCLUDE_DIRS ${includes_public} + PRIV_INCLUDE_DIRS ${includes_private} + PRIV_REQUIRES esp_netif # required by rndis_reports.c: #include "netif/ethernet.h" + ) + +target_compile_options(${COMPONENT_LIB} PUBLIC ${compile_options}) + +# when no builtin class driver is enabled, an uint8_t data compared with `BUILTIN_DRIVER_COUNT` will always be false +set_source_files_properties("src/device/usbd.c" PROPERTIES COMPILE_FLAGS "-Wno-type-limits") diff --git a/README.md b/README.md new file mode 100644 index 0000000000..8387bb6ed6 --- /dev/null +++ b/README.md @@ -0,0 +1,53 @@ +# Espressif TinyUSB component + +Upstream [TinyUSB](https://github.com/hathach/tinyusb) fork with integration into ESP-IDF build system. + +## How to use + +There are two options of using TinyUSB component with Espressif's SoCs: + +### 1. Use component via [Espressif TinyUSB additions](https://github.com/espressif/esp-usb/tree/master/device/esp_tinyusb) + +[Espressif TinyUSB additions](https://github.com/espressif/esp-usb/tree/master/device/esp_tinyusb) provides several preconfigured features to use benefits of TinyUSB stack faster. + +To use [Espressif TinyUSB additions](https://github.com/espressif/esp-usb/tree/master/device/esp_tinyusb), add ``idf_component.yml`` to your main component with the following content:: + +```yaml +## IDF Component Manager Manifest File +dependencies: + esp_tinyusb: "^1.0.0" # Automatically update minor releases +``` + +Or simply run: +``` +idf.py add-dependency "esp_tinyusb^1.0.0" +``` + +Then, the Espressif TinyUSB component will be added automatically during resolving dependencies by the component manager. + +### 2. Use component directly + +Use this option for custom TinyUSB applications. +In this case you will have to provide configuration header file ``tusb_config.h``. More information about TinyUSB configuration can be found [in official TinyUSB documentation](https://docs.tinyusb.org/en/latest/reference/getting_started.html). + +You will also have to tell TinyUSB where to find the configuration file. This can be achieved by adding following CMake snippet to you main component's ``CMakeLists.txt``: + +```cmake +idf_component_get_property(tusb_lib espressif__tinyusb COMPONENT_LIB) +target_include_directories(${tusb_lib} PRIVATE path_to_your_tusb_config) +``` + +Again, you can add this component to your project by adding ``idf_component.yml`` file: + +```yaml +## IDF Component Manager Manifest File +dependencies: + tinyusb: "~0.15.1" # Automatically update bugfix releases. TinyUSB does not guarantee backward compatibility +``` + +Or simply run: +``` +idf.py add-dependency "tinyusb~0.15.1" +``` + +README from the upstream TinyUSB can be found in [hathach/tinyusb/README](https://github.com/hathach/tinyusb/blob/master/README.rst). diff --git a/idf_component.yml b/idf_component.yml new file mode 100644 index 0000000000..cbc90f7cba --- /dev/null +++ b/idf_component.yml @@ -0,0 +1,10 @@ +description: TinyUSB ported to Espressif's SoCs +url: https://docs.tinyusb.org/en/latest/ +documentation: "https://docs.tinyusb.org/en/latest/" +repository: "https://github.com/espressif/tinyusb.git" +dependencies: + idf: '>=5.0' # IDF 4.x contains TinyUSB as submodule +targets: + - esp32s2 + - esp32s3 + - esp32p4 diff --git a/sbom.yml b/sbom.yml new file mode 100644 index 0000000000..91867531ab --- /dev/null +++ b/sbom.yml @@ -0,0 +1,2 @@ +supplier: 'Organization: Espressif Systems (Shanghai) CO LTD' +originator: 'Person: Ha Thach ' diff --git a/src/portable/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c index f30ec5ee39..9e507cf81f 100644 --- a/src/portable/synopsys/dwc2/dcd_dwc2.c +++ b/src/portable/synopsys/dwc2/dcd_dwc2.c @@ -234,7 +234,7 @@ static bool dfifo_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t packet_size) { // Check if free space is available TU_ASSERT(_dfifo_top >= fifo_size + dwc2->grxfsiz); _dfifo_top -= fifo_size; - TU_LOG(DWC2_DEBUG, " TX FIFO %u: allocated %u words at offset %u\r\n", epnum, fifo_size, _dfifo_top); + // TU_LOG(DWC2_DEBUG, " TX FIFO %u: allocated %u words at offset %u\r\n", epnum, fifo_size, _dfifo_top); // Both TXFD and TXSA are in unit of 32-bit words. if (epnum == 0) { @@ -683,8 +683,9 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { // Force device mode dwc2->gusbcfg = (dwc2->gusbcfg & ~GUSBCFG_FHMOD) | GUSBCFG_FDMOD; - // Clear A override, force B Valid - dwc2->gotgctl = (dwc2->gotgctl & ~GOTGCTL_AVALOEN) | GOTGCTL_BVALOEN | GOTGCTL_BVALOVAL; + // No overrides + dwc2->gotgctl &= ~(GOTGCTL_BVALOEN | GOTGCTL_BVALOVAL | GOTGCTL_VBVALOVAL); + // If USB host misbehaves during status portion of control xfer // (non zero-length packet), send STALL back and discard. diff --git a/src/tusb.h b/src/tusb.h index 2f30a57394..0753014c8e 100644 --- a/src/tusb.h +++ b/src/tusb.h @@ -140,8 +140,16 @@ bool tusb_rhport_init(uint8_t rhport, const tusb_rhport_init_t* rh_init); // Note: when using with RTOS, this should be called after scheduler/kernel is started. // Otherwise, it could cause kernel issue since USB IRQ handler does use RTOS queue API. // Note2: defined as macro for backward compatible with tusb_init(void), can be changed to function in the future. -#if defined(TUD_OPT_RHPORT) || defined(TUH_OPT_RHPORT) - #define _tusb_init_arg0() tusb_rhport_init(0, NULL) +#if defined(TUD_OPT_RHPORT) + #define TUx_OPT_RHPORT TUD_OPT_RHPORT +#endif // +#if defined(TUH_OPT_RHPORT) + #define TUx_OPT_RHPORT TUH_OPT_RHPORT +#endif // + +#if defined(TUx_OPT_RHPORT) + // _tusb_init_arg0() get the port number from TUD_OPT_RHPORT or TUH_OPT_RHPORT option + #define _tusb_init_arg0() tusb_rhport_init(TUx_OPT_RHPORT, NULL) #else #define _tusb_init_arg0() TU_VERIFY_STATIC(false, "CFG_TUSB_RHPORT0_MODE/CFG_TUSB_RHPORT1_MODE must be defined") #endif