From b08f672daf1efadd9c77a775332dc0b64ac22e4a Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 24 Oct 2025 17:24:55 +0700 Subject: add pvs-studio analyze to ci --- .github/workflows/static_analysis.yml | 43 +++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 .github/workflows/static_analysis.yml (limited to '.github/workflows/static_analysis.yml') diff --git a/.github/workflows/static_analysis.yml b/.github/workflows/static_analysis.yml new file mode 100644 index 000000000..3ace5cf99 --- /dev/null +++ b/.github/workflows/static_analysis.yml @@ -0,0 +1,43 @@ +name: Static Analysis +on: + workflow_dispatch: + push: + branches: + - master + pull_request: + types: [opened, synchronize, reopened] +jobs: +# SonarQube: +# name: Build and analyze +# runs-on: ubuntu-latest +# env: +# BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory # Directory where build-wrapper output will be placed +# steps: +# - uses: actions/checkout@v4 +# with: +# fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis +# - name: Install Build Wrapper +# uses: SonarSource/sonarqube-scan-action/install-build-wrapper@v6 +# - name: Run Build Wrapper +# run: | +# build-wrapper-linux-x86-64 --out-dir ${{ env.BUILD_WRAPPER_OUT_DIR }} cmake --build --preset ${{ env.BOARD }} -t ${{ env.EXAMPLE }} +# - name: SonarQube Scan +# uses: SonarSource/sonarqube-scan-action@v6 +# env: +# SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} +# with: +# args: > +# --define "sonar.cfamily.compile-commands=${{ env.BUILD_WRAPPER_OUT_DIR }}/compile_commands.json" + PVS-Studio: + uses: ./.github/workflows/build_util.yml + strategy: + fail-fast: false + matrix: + board: + - 'stm32h743eval' + with: + build-system: 'cmake' + toolchain: 'arm-gcc' + build-args: '-b${{ matrix.board }}' + one-per-family: true + analyze-pvs: true -- cgit v1.3.1 From 948ba203ca8d31de3f0947bc01b5852174bc8404 Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 25 Oct 2025 00:15:41 +0700 Subject: add pvs-studio analyze to ci --- .github/workflows/build_util.yml | 26 ----------------------- .github/workflows/static_analysis.yml | 39 ++++++++++++++++++++++++++++------- 2 files changed, 32 insertions(+), 33 deletions(-) (limited to '.github/workflows/static_analysis.yml') diff --git a/.github/workflows/build_util.yml b/.github/workflows/build_util.yml index d52924efd..a2c96f3c0 100644 --- a/.github/workflows/build_util.yml +++ b/.github/workflows/build_util.yml @@ -20,10 +20,6 @@ on: required: false default: false type: boolean - analyze-pvs: - required: false - default: false - type: boolean os: required: false type: string @@ -72,28 +68,6 @@ jobs: fi shell: bash - - name: PVS-Studio analyze - if: ${{ inputs.analyze-pvs }} - run: | - wget -q -O - https://files.pvs-studio.com/etc/pubkey.txt | sudo apt-key add - - sudo wget -O /etc/apt/sources.list.d/viva64.list https://files.pvs-studio.com/etc/viva64.list - sudo apt update - sudo apt install pvs-studio - pvs-studio-analyzer credentials ${{ secrets.PVS_STUDIO_CREDENTIALS }} - mkdir -p sarif-reports - for build_dir in cmake-build/cmake-build-*; do - BOARD=${build_dir#cmake-build/cmake-build-} - pvs-studio-analyzer analyze -f ${build_dir}/compile_commands.json -j -o ${build_dir}/pvs-report.log --exclude-path hw/mcu/ --exclude-path lib/ - plog-converter -t sarif -o sarif-reports/${BOARD}.sarif ${build_dir}/pvs-report.log - done - - - name: PVS-Studio upload SARIF - if: ${{ inputs.analyze-pvs }} - uses: github/codeql-action/upload-sarif@v4 - with: - sarif_file: sarif-reports/ - category: PVS-Studio - - name: Upload Artifacts for Hardware Testing if: ${{ inputs.upload-artifacts }} uses: actions/upload-artifact@v4 diff --git a/.github/workflows/static_analysis.yml b/.github/workflows/static_analysis.yml index 3ace5cf99..6541be129 100644 --- a/.github/workflows/static_analysis.yml +++ b/.github/workflows/static_analysis.yml @@ -29,15 +29,40 @@ jobs: # args: > # --define "sonar.cfamily.compile-commands=${{ env.BUILD_WRAPPER_OUT_DIR }}/compile_commands.json" PVS-Studio: - uses: ./.github/workflows/build_util.yml + runs-on: ubuntu-latest strategy: fail-fast: false matrix: board: - 'stm32h743eval' - with: - build-system: 'cmake' - toolchain: 'arm-gcc' - build-args: '-b${{ matrix.board }}' - one-per-family: true - analyze-pvs: true + steps: + - name: Checkout TinyUSB + uses: actions/checkout@v4 + + - name: Get Dependencies + uses: ./.github/actions/get_deps + with: + arg: -b${{ matrix.board }} + + - name: Setup Toolchain + uses: ./.github/actions/setup_toolchain + with: + toolchain: 'arm-gcc' + + - name: Analyze + run: | + wget -q -O - https://files.pvs-studio.com/etc/pubkey.txt | sudo apt-key add - + sudo wget -O /etc/apt/sources.list.d/viva64.list https://files.pvs-studio.com/etc/viva64.list + sudo apt update + sudo apt install pvs-studio + pvs-studio-analyzer credentials ${{ secrets.PVS_STUDIO_CREDENTIALS }} + cmake examples -B build -G Ninja -DBOARD=${{ matrix.board }} -DCMAKE_BUILD_TYPE=MinSizeRel + cmake --build build + pvs-studio-analyzer analyze -f build/compile_commands.json -j --exclude-path hw/mcu/ --exclude-path lib/ + plog-converter -t sarif -o pvs.sarif PVS-Studio.log + + - name: Upload SARIF + uses: github/codeql-action/upload-sarif@v4 + with: + sarif_file: pvs.sarif + category: PVS-Studio -- cgit v1.3.1 From 5e3e24337f82582103ce7e9d8498c49547cab42b Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 25 Oct 2025 12:28:20 +0700 Subject: merge codeql and pvs-studio to static_analysis.yml --- .github/workflows/codeql.yml | 1 + .github/workflows/static_analysis.yml | 119 ++++++++++++++++++++++++++++------ 2 files changed, 99 insertions(+), 21 deletions(-) (limited to '.github/workflows/static_analysis.yml') diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index dfcca6315..21ed9c223 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -41,6 +41,7 @@ jobs: # Consider using larger runners for possible analysis time improvements. runs-on: ubuntu-latest timeout-minutes: 360 + if: false permissions: actions: read contents: read diff --git a/.github/workflows/static_analysis.yml b/.github/workflows/static_analysis.yml index 6541be129..f391855f5 100644 --- a/.github/workflows/static_analysis.yml +++ b/.github/workflows/static_analysis.yml @@ -6,28 +6,80 @@ on: - master pull_request: types: [opened, synchronize, reopened] + +permissions: + actions: read + contents: read + security-events: write + jobs: -# SonarQube: -# name: Build and analyze -# runs-on: ubuntu-latest -# env: -# BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory # Directory where build-wrapper output will be placed -# steps: -# - uses: actions/checkout@v4 + CodeQL: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + board: + - 'raspberry_pi_pico' + steps: + - name: Checkout TinyUSB + uses: actions/checkout@v4 + + - name: Get Dependencies + uses: ./.github/actions/get_deps + with: + arg: -b${{ matrix.board }} + + - name: Setup Toolchain + uses: ./.github/actions/setup_toolchain + with: + toolchain: 'arm-gcc' + + - name: Initialize CodeQL + uses: github/codeql-action/init@v4 + with: + languages: 'c-cpp' + queries: security-and-quality + + - name: Build + run: | + cmake examples -B build -G Ninja -DBOARD=${{ matrix.board }} -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_BUILD_TYPE=MinSizeRel + cmake --build build + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v4 + with: + category: CodeQL + upload: always + id: step1 + +# - name: Filter out unwanted errors and warnings +# uses: advanced-security/filter-sarif@v1 # with: -# fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis -# - name: Install Build Wrapper -# uses: SonarSource/sonarqube-scan-action/install-build-wrapper@v6 -# - name: Run Build Wrapper -# run: | -# build-wrapper-linux-x86-64 --out-dir ${{ env.BUILD_WRAPPER_OUT_DIR }} cmake --build --preset ${{ env.BOARD }} -t ${{ env.EXAMPLE }} -# - name: SonarQube Scan -# uses: SonarSource/sonarqube-scan-action@v6 -# env: -# SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} +# patterns: | +# -**:cpp/path-injection +# -**:cpp/world-writable-file-creation +# -**:cpp/poorly-documented-function +# -**:cpp/potentially-dangerous-function +# -**:cpp/use-of-goto +# -**:cpp/integer-multiplication-cast-to-long +# -**:cpp/comparison-with-wider-type +# -**:cpp/leap-year/* +# -**:cpp/ambiguously-signed-bit-field +# -**:cpp/suspicious-pointer-scaling +# -**:cpp/suspicious-pointer-scaling-void +# -**:cpp/unsigned-comparison-zero +# -**/third*party/** +# -**/3rd*party/** +# -**/external/** +# input: ${{ steps.step1.outputs.sarif-output }}/cpp.sarif +# output: ${{ steps.step1.outputs.sarif-output }}/cpp.sarif +# +# - name: Upload SARIF +# uses: github/codeql-action/upload-sarif@v4 # with: -# args: > -# --define "sonar.cfamily.compile-commands=${{ env.BUILD_WRAPPER_OUT_DIR }}/compile_commands.json" +# sarif_file: ${{ steps.step1.outputs.sarif-output }} +# category: CodeQL + PVS-Studio: runs-on: ubuntu-latest strategy: @@ -49,14 +101,17 @@ jobs: with: toolchain: 'arm-gcc' - - name: Analyze + - name: Install Tools run: | wget -q -O - https://files.pvs-studio.com/etc/pubkey.txt | sudo apt-key add - sudo wget -O /etc/apt/sources.list.d/viva64.list https://files.pvs-studio.com/etc/viva64.list sudo apt update sudo apt install pvs-studio pvs-studio-analyzer credentials ${{ secrets.PVS_STUDIO_CREDENTIALS }} - cmake examples -B build -G Ninja -DBOARD=${{ matrix.board }} -DCMAKE_BUILD_TYPE=MinSizeRel + + - name: Analyze + run: | + cmake examples -B build -G Ninja -DBOARD=${{ matrix.board }} -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_BUILD_TYPE=MinSizeRel cmake --build build pvs-studio-analyzer analyze -f build/compile_commands.json -j --exclude-path hw/mcu/ --exclude-path lib/ plog-converter -t sarif -o pvs.sarif PVS-Studio.log @@ -66,3 +121,25 @@ jobs: with: sarif_file: pvs.sarif category: PVS-Studio + +# SonarQube: +# name: Build and analyze +# runs-on: ubuntu-latest +# env: +# BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory # Directory where build-wrapper output will be placed +# steps: +# - uses: actions/checkout@v4 +# with: +# fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis +# - name: Install Build Wrapper +# uses: SonarSource/sonarqube-scan-action/install-build-wrapper@v6 +# - name: Run Build Wrapper +# run: | +# build-wrapper-linux-x86-64 --out-dir ${{ env.BUILD_WRAPPER_OUT_DIR }} cmake --build --preset ${{ env.BOARD }} -t ${{ env.EXAMPLE }} +# - name: SonarQube Scan +# uses: SonarSource/sonarqube-scan-action@v6 +# env: +# SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} +# with: +# args: > +# --define "sonar.cfamily.compile-commands=${{ env.BUILD_WRAPPER_OUT_DIR }}/compile_commands.json" -- cgit v1.3.1 From 6cc445ef0f3e7b29cfe2e3d90bb3364afbc424af Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 25 Oct 2025 12:54:40 +0700 Subject: download ninja binary, apt seems take too long ~ 1 min also upload sarif as artifacts --- .github/actions/get_deps/action.yml | 5 ++++- .github/workflows/static_analysis.yml | 25 +++++++++++++++++++------ 2 files changed, 23 insertions(+), 7 deletions(-) (limited to '.github/workflows/static_analysis.yml') diff --git a/.github/actions/get_deps/action.yml b/.github/actions/get_deps/action.yml index ae9e7bbef..b0d6d1066 100644 --- a/.github/actions/get_deps/action.yml +++ b/.github/actions/get_deps/action.yml @@ -19,7 +19,10 @@ runs: - name: Linux dependencies if: runner.os == 'Linux' run: | - sudo apt install -y ninja-build + NINJA_URL=https://github.com/ninja-build/ninja/releases/download/v1.13.1/ninja-linux.zip + wget $NINJA_URL -O ninja-linux.zip + unzip ninja-linux.zip -d ninja-bin + echo >> $GITHUB_PATH "${{ github.workspace }}/ninja-bin" shell: bash - name: Get Dependencies diff --git a/.github/workflows/static_analysis.yml b/.github/workflows/static_analysis.yml index f391855f5..bbb7229df 100644 --- a/.github/workflows/static_analysis.yml +++ b/.github/workflows/static_analysis.yml @@ -50,7 +50,7 @@ jobs: with: category: CodeQL upload: always - id: step1 + id: analyze # - name: Filter out unwanted errors and warnings # uses: advanced-security/filter-sarif@v1 @@ -71,15 +71,21 @@ jobs: # -**/third*party/** # -**/3rd*party/** # -**/external/** -# input: ${{ steps.step1.outputs.sarif-output }}/cpp.sarif -# output: ${{ steps.step1.outputs.sarif-output }}/cpp.sarif +# input: ${{ steps.analyze.outputs.sarif-output }}/cpp.sarif +# output: ${{ steps.analyze.outputs.sarif-output }}/cpp.sarif # # - name: Upload SARIF # uses: github/codeql-action/upload-sarif@v4 # with: -# sarif_file: ${{ steps.step1.outputs.sarif-output }} +# sarif_file: ${{ steps.analyze.outputs.sarif-output }} # category: CodeQL + - name: Upload artifact + uses: actions/upload-artifact@v5 + with: + name: codeql-${{ matrix.board }} + path: ${{ steps.analyze.outputs.sarif-output }} + PVS-Studio: runs-on: ubuntu-latest strategy: @@ -114,14 +120,21 @@ jobs: cmake examples -B build -G Ninja -DBOARD=${{ matrix.board }} -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_BUILD_TYPE=MinSizeRel cmake --build build pvs-studio-analyzer analyze -f build/compile_commands.json -j --exclude-path hw/mcu/ --exclude-path lib/ - plog-converter -t sarif -o pvs.sarif PVS-Studio.log + plog-converter -t sarif -o pvs-${{ matrix.board }}.sarif PVS-Studio.log - name: Upload SARIF uses: github/codeql-action/upload-sarif@v4 with: - sarif_file: pvs.sarif + sarif_file: pvs-${{ matrix.board }}.sarif category: PVS-Studio + - name: Upload artifact + uses: actions/upload-artifact@v5 + with: + name: pvs-${{ matrix.board }} + path: pvs-${{ matrix.board }}.sarif + + # SonarQube: # name: Build and analyze # runs-on: ubuntu-latest -- cgit v1.3.1 From 531009c9a02d719d3222c89dc9d31f5967e23af3 Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 25 Oct 2025 13:36:26 +0700 Subject: add SonarQube scan --- .github/workflows/static_analysis.yml | 70 +++++++++++++++++++++++------------ 1 file changed, 46 insertions(+), 24 deletions(-) (limited to '.github/workflows/static_analysis.yml') diff --git a/.github/workflows/static_analysis.yml b/.github/workflows/static_analysis.yml index bbb7229df..e5254344b 100644 --- a/.github/workflows/static_analysis.yml +++ b/.github/workflows/static_analysis.yml @@ -42,6 +42,7 @@ jobs: - name: Build run: | + mkdir -p build cmake examples -B build -G Ninja -DBOARD=${{ matrix.board }} -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_BUILD_TYPE=MinSizeRel cmake --build build @@ -117,10 +118,11 @@ jobs: - name: Analyze run: | + mkdir -p build cmake examples -B build -G Ninja -DBOARD=${{ matrix.board }} -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_BUILD_TYPE=MinSizeRel cmake --build build pvs-studio-analyzer analyze -f build/compile_commands.json -j --exclude-path hw/mcu/ --exclude-path lib/ - plog-converter -t sarif -o pvs-${{ matrix.board }}.sarif PVS-Studio.log + plog-converter -t sarif -o pvs-studio-${{ matrix.board }}.sarif PVS-Studio.log - name: Upload SARIF uses: github/codeql-action/upload-sarif@v4 @@ -131,28 +133,48 @@ jobs: - name: Upload artifact uses: actions/upload-artifact@v5 with: - name: pvs-${{ matrix.board }} - path: pvs-${{ matrix.board }}.sarif + name: pvs-studio-${{ matrix.board }} + path: pvs-studio-${{ matrix.board }}.sarif + SonarQube: + runs-on: ubuntu-latest + env: + BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory + strategy: + fail-fast: false + matrix: + board: + - 'metro_m4_express' + steps: + - name: Checkout TinyUSB + uses: actions/checkout@v4 + with: + fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis -# SonarQube: -# name: Build and analyze -# runs-on: ubuntu-latest -# env: -# BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory # Directory where build-wrapper output will be placed -# steps: -# - uses: actions/checkout@v4 -# with: -# fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis -# - name: Install Build Wrapper -# uses: SonarSource/sonarqube-scan-action/install-build-wrapper@v6 -# - name: Run Build Wrapper -# run: | -# build-wrapper-linux-x86-64 --out-dir ${{ env.BUILD_WRAPPER_OUT_DIR }} cmake --build --preset ${{ env.BOARD }} -t ${{ env.EXAMPLE }} -# - name: SonarQube Scan -# uses: SonarSource/sonarqube-scan-action@v6 -# env: -# SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} -# with: -# args: > -# --define "sonar.cfamily.compile-commands=${{ env.BUILD_WRAPPER_OUT_DIR }}/compile_commands.json" + - name: Get Dependencies + uses: ./.github/actions/get_deps + with: + arg: -b${{ matrix.board }} + + - name: Setup Toolchain + uses: ./.github/actions/setup_toolchain + with: + toolchain: 'arm-gcc' + + - name: Install Build Wrapper + uses: SonarSource/sonarqube-scan-action/install-build-wrapper@v6 + + - name: Run Build Wrapper + run: | + cmake examples -B build -G Ninja -DBOARD=${{ matrix.board }} -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_BUILD_TYPE=MinSizeRel + build-wrapper-linux-x86-64 --out-dir ${{ env.BUILD_WRAPPER_OUT_DIR }} cmake --build build/ + + - name: SonarQube Scan + uses: SonarSource/sonarqube-scan-action@v6 + env: + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + SONAR_ROOT_CERT: ${{ secrets.SONAR_ROOT_CERT }} + with: + # Consult https://docs.sonarsource.com/sonarqube-server/latest/analyzing-source-code/scanners/sonarscanner/ for more information and options + args: > + --define sonar.cfamily.compile-commands="${{ env.BUILD_WRAPPER_OUT_DIR }}/compile_commands.json" -- cgit v1.3.1 From 5818db49b2de8689a07007a5e4d329b94d67ef42 Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 25 Oct 2025 13:54:10 +0700 Subject: add SonarQube scan --- .github/workflows/static_analysis.yml | 5 ++--- sonar-project.properties | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 3 deletions(-) create mode 100644 sonar-project.properties (limited to '.github/workflows/static_analysis.yml') diff --git a/.github/workflows/static_analysis.yml b/.github/workflows/static_analysis.yml index e5254344b..45c5c959b 100644 --- a/.github/workflows/static_analysis.yml +++ b/.github/workflows/static_analysis.yml @@ -127,7 +127,7 @@ jobs: - name: Upload SARIF uses: github/codeql-action/upload-sarif@v4 with: - sarif_file: pvs-${{ matrix.board }}.sarif + sarif_file: pvs-studio-${{ matrix.board }}.sarif category: PVS-Studio - name: Upload artifact @@ -173,8 +173,7 @@ jobs: uses: SonarSource/sonarqube-scan-action@v6 env: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - SONAR_ROOT_CERT: ${{ secrets.SONAR_ROOT_CERT }} with: # Consult https://docs.sonarsource.com/sonarqube-server/latest/analyzing-source-code/scanners/sonarscanner/ for more information and options args: > - --define sonar.cfamily.compile-commands="${{ env.BUILD_WRAPPER_OUT_DIR }}/compile_commands.json" + --define sonar.cfamily.compile-commands=${{ env.BUILD_WRAPPER_OUT_DIR }}/compile_commands.json diff --git a/sonar-project.properties b/sonar-project.properties new file mode 100644 index 000000000..d797bfe6f --- /dev/null +++ b/sonar-project.properties @@ -0,0 +1,14 @@ +sonar.projectKey=hathach_tinyusb +sonar.organization=hathach + + +# This is the name and version displayed in the SonarCloud UI. +sonar.projectName=tinyusb +sonar.projectVersion=0.19.0 + + +# Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows. +#sonar.sources=. + +# Encoding of the source code. Default is default system encoding +#sonar.sourceEncoding=UTF-8 -- cgit v1.3.1 From d7c4bf14b464a509120ff18f94e9b02cd1c6f9fa Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 25 Oct 2025 16:30:42 +0700 Subject: add IAR CStat to static_analysis.yml --- .circleci/config2.yml | 2 + .../actions/setup_toolchain/download/action.yml | 4 +- .github/actions/setup_toolchain/toolchain.json | 2 +- .github/workflows/codeql-buildscript.sh | 6 - .github/workflows/codeql.yml | 138 --------------------- .github/workflows/fail_on_error.py | 34 ----- .github/workflows/static_analysis.yml | 55 +++++++- tools/make_release.py | 11 ++ 8 files changed, 67 insertions(+), 185 deletions(-) delete mode 100644 .github/workflows/codeql-buildscript.sh delete mode 100644 .github/workflows/codeql.yml delete mode 100755 .github/workflows/fail_on_error.py (limited to '.github/workflows/static_analysis.yml') diff --git a/.circleci/config2.yml b/.circleci/config2.yml index d86a3f662..bd2a7d02a 100644 --- a/.circleci/config2.yml +++ b/.circleci/config2.yml @@ -34,6 +34,7 @@ commands: chmod +x toolchain.run ./toolchain.run -p ~/cache/<< parameters.toolchain >>/gnurx -y elif [[ << parameters.toolchain >> == arm-iar ]]; then + wget --progress=dot:giga https://netstorage.iar.com/FileStore/STANDARD/001/003/926/iar-lmsc-tools_1.8_amd64.deb -O ~/cache/<< parameters.toolchain >>/iar-lmsc-tools.deb wget --progress=dot:giga $toolchain_url -O ~/cache/<< parameters.toolchain >>/toolchain.deb else wget --progress=dot:giga $toolchain_url -O toolchain.tar.gz @@ -44,6 +45,7 @@ commands: # Add toolchain to PATH if [[ << parameters.toolchain >> == arm-iar ]]; then # Install IAR since we only cache deb file + sudo dpkg -i ~/cache/<< parameters.toolchain >>/iar-lmsc-tools.deb sudo dpkg --ignore-depends=libusb-1.0-0 -i ~/cache/<< parameters.toolchain >>/toolchain.deb echo "export PATH=$PATH:/opt/iar/cxarm/arm/bin" >> $BASH_ENV else diff --git a/.github/actions/setup_toolchain/download/action.yml b/.github/actions/setup_toolchain/download/action.yml index ce9643010..514b38f19 100644 --- a/.github/actions/setup_toolchain/download/action.yml +++ b/.github/actions/setup_toolchain/download/action.yml @@ -29,6 +29,7 @@ runs: chmod +x toolchain.run ./toolchain.run -p ~/cache/${{ inputs.toolchain }}/gnurx -y elif [[ ${{ inputs.toolchain }} == arm-iar ]]; then + wget --progress=dot:giga https://netstorage.iar.com/FileStore/STANDARD/001/003/926/iar-lmsc-tools_1.8_amd64.deb -O ~/cache/${{ inputs.toolchain }}/iar-lmsc-tools.deb wget --progress=dot:giga ${{ inputs.toolchain_url }} -O ~/cache/${{ inputs.toolchain }}/cxarm.deb else wget --progress=dot:giga ${{ inputs.toolchain_url }} -O toolchain.tar.gz @@ -39,7 +40,8 @@ runs: - name: Setup Toolchain run: | if [[ ${{ inputs.toolchain }} == arm-iar ]]; then - sudo apt-get install -y ~/cache/${{ inputs.toolchain }}/cxarm.deb + sudo dpkg -i ~/cache/${{ inputs.toolchain }}/iar-lmsc-tools.deb + sudo apt install -y ~/cache/${{ inputs.toolchain }}/cxarm.deb echo >> $GITHUB_PATH "/opt/iar/cxarm/arm/bin" else echo >> $GITHUB_PATH `echo ~/cache/${{ inputs.toolchain }}/*/bin` diff --git a/.github/actions/setup_toolchain/toolchain.json b/.github/actions/setup_toolchain/toolchain.json index f7123ef11..8496dcad3 100644 --- a/.github/actions/setup_toolchain/toolchain.json +++ b/.github/actions/setup_toolchain/toolchain.json @@ -5,5 +5,5 @@ "msp430-gcc": "http://software-dl.ti.com/msp430/msp430_public_sw/mcu/msp430/MSPGCC/9_2_0_0/export/msp430-gcc-9.2.0.50_linux64.tar.bz2", "riscv-gcc": "https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack/releases/download/v13.2.0-2/xpack-riscv-none-elf-gcc-13.2.0-2-linux-x64.tar.gz", "rx-gcc": "https://github.com/hathach/rx_device/releases/download/0.0.1/gcc-8.3.0.202411-GNURX-ELF.run", - "arm-iar": "https://netstorage.iar.com/FileStore/STANDARD/001/003/583/cxarm-9.60.4.deb" + "arm-iar": "https://netstorage.iar.com/FileStore/STANDARD/001/003/723/cxarm-9.70.1.deb" } diff --git a/.github/workflows/codeql-buildscript.sh b/.github/workflows/codeql-buildscript.sh deleted file mode 100644 index 272b55d22..000000000 --- a/.github/workflows/codeql-buildscript.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env bash - -FAMILY=stm32l4 -pip install click -python3 tools/get_deps.py $FAMILY -python3 tools/build.py -s make $FAMILY diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml deleted file mode 100644 index 21ed9c223..000000000 --- a/.github/workflows/codeql.yml +++ /dev/null @@ -1,138 +0,0 @@ -# For most projects, this workflow file will not need changing; you simply need -# to commit it to your repository. -# -# You may wish to alter this file to override the set of languages analyzed, -# or to provide custom queries or build logic. -# -# ******** NOTE ******** -# We have attempted to detect the languages in your repository. Please check -# the `language` matrix defined below to confirm you have the correct set of -# supported CodeQL languages. -# -name: "CodeQL" - -on: - push: - branches: [ 'master' ] - paths: - - 'src/**' - - 'examples/**' - - 'lib/**' - - 'hw/**' - - '.github/workflows/codeql.yml' - pull_request: - branches: [ 'master' ] - paths: - - 'src/**' - - 'examples/**' - - 'lib/**' - - 'hw/**' - - '.github/workflows/codeql.yml' - schedule: - - cron: '0 0 * * *' - -jobs: - analyze: - name: Analyze - # Runner size impacts CodeQL analysis time. To learn more, please see: - # - https://gh.io/recommended-hardware-resources-for-running-codeql - # - https://gh.io/supported-runners-and-hardware-resources - # - https://gh.io/using-larger-runners - # Consider using larger runners for possible analysis time improvements. - runs-on: ubuntu-latest - timeout-minutes: 360 - if: false - permissions: - actions: read - contents: read - security-events: write - - strategy: - fail-fast: false - matrix: - language: [ 'c-cpp' ] - # CodeQL supports [ 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift' ] - # Use only 'java-kotlin' to analyze code written in Java, Kotlin or both - # Use only 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both - # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Setup Toolchain - uses: ./.github/actions/setup_toolchain - with: - toolchain: 'arm-gcc' - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v3 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - - # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs - # queries: security-extended,security-and-quality - queries: security-and-quality - - - # Autobuild attempts to build any compiled languages (C/C++, C#, Go, Java, or Swift). - # If this step fails, then you should remove it and run the build manually (see below) - #- name: Autobuild - # uses: github/codeql-action/autobuild@v2 - - # â„šī¸ Command-line programs to run using the OS shell. - # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun - - # If the Autobuild fails above, remove it and uncomment the following three lines. - # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. - - - run: | - ./.github/workflows/codeql-buildscript.sh - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v3 - with: - category: "/language:${{matrix.language}}" - upload: false - id: step1 - - # Filter out rules with low severity or high false positive rate - # Also filter out warnings in third-party code - - name: Filter out unwanted errors and warnings - uses: advanced-security/filter-sarif@v1 - with: - patterns: | - -**:cpp/path-injection - -**:cpp/world-writable-file-creation - -**:cpp/poorly-documented-function - -**:cpp/potentially-dangerous-function - -**:cpp/use-of-goto - -**:cpp/integer-multiplication-cast-to-long - -**:cpp/comparison-with-wider-type - -**:cpp/leap-year/* - -**:cpp/ambiguously-signed-bit-field - -**:cpp/suspicious-pointer-scaling - -**:cpp/suspicious-pointer-scaling-void - -**:cpp/unsigned-comparison-zero - -**/third*party/** - -**/3rd*party/** - -**/external/** - input: ${{ steps.step1.outputs.sarif-output }}/cpp.sarif - output: ${{ steps.step1.outputs.sarif-output }}/cpp.sarif - - - name: Upload SARIF - uses: github/codeql-action/upload-sarif@v3 - with: - sarif_file: ${{ steps.step1.outputs.sarif-output }} - category: "/language:${{matrix.language}}" - - - name: Upload CodeQL results as an artifact - uses: actions/upload-artifact@v4 - with: - name: codeql-results - path: ${{ steps.step1.outputs.sarif-output }} - retention-days: 5 diff --git a/.github/workflows/fail_on_error.py b/.github/workflows/fail_on_error.py deleted file mode 100755 index 29791742b..000000000 --- a/.github/workflows/fail_on_error.py +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env python3 - -import json -import sys - -# Return whether SARIF file contains error-level results -def codeql_sarif_contain_error(filename): - with open(filename, 'r') as f: - s = json.load(f) - - for run in s.get('runs', []): - rules_metadata = run['tool']['driver']['rules'] - if not rules_metadata: - rules_metadata = run['tool']['extensions'][0]['rules'] - - for res in run.get('results', []): - if 'ruleIndex' in res: - rule_index = res['ruleIndex'] - elif 'rule' in res and 'index' in res['rule']: - rule_index = res['rule']['index'] - else: - continue - try: - rule_level = rules_metadata[rule_index]['defaultConfiguration']['level'] - except IndexError as e: - print(e, rule_index, len(rules_metadata)) - else: - if rule_level == 'error': - return True - return False - -if __name__ == "__main__": - if codeql_sarif_contain_error(sys.argv[1]): - sys.exit(1) diff --git a/.github/workflows/static_analysis.yml b/.github/workflows/static_analysis.yml index 45c5c959b..e060dfbc9 100644 --- a/.github/workflows/static_analysis.yml +++ b/.github/workflows/static_analysis.yml @@ -19,7 +19,7 @@ jobs: fail-fast: false matrix: board: - - 'raspberry_pi_pico' + - 'metro_m4_express' steps: - name: Checkout TinyUSB uses: actions/checkout@v4 @@ -88,12 +88,13 @@ jobs: path: ${{ steps.analyze.outputs.sarif-output }} PVS-Studio: + if: github.repository_owner == 'hathach' runs-on: ubuntu-latest strategy: fail-fast: false matrix: board: - - 'stm32h743eval' + - 'raspberry_pi_pico' steps: - name: Checkout TinyUSB uses: actions/checkout@v4 @@ -119,7 +120,7 @@ jobs: - name: Analyze run: | mkdir -p build - cmake examples -B build -G Ninja -DBOARD=${{ matrix.board }} -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_BUILD_TYPE=MinSizeRel + cmake examples -B build -G Ninja -DBOARD=${{ matrix.board }} -DCMAKE_BUILD_TYPE=MinSizeRel cmake --build build pvs-studio-analyzer analyze -f build/compile_commands.json -j --exclude-path hw/mcu/ --exclude-path lib/ plog-converter -t sarif -o pvs-studio-${{ matrix.board }}.sarif PVS-Studio.log @@ -137,6 +138,7 @@ jobs: path: pvs-studio-${{ matrix.board }}.sarif SonarQube: + if: github.repository_owner == 'hathach' runs-on: ubuntu-latest env: BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory @@ -144,7 +146,7 @@ jobs: fail-fast: false matrix: board: - - 'metro_m4_express' + - 'stm32h743eval' steps: - name: Checkout TinyUSB uses: actions/checkout@v4 @@ -166,7 +168,7 @@ jobs: - name: Run Build Wrapper run: | - cmake examples -B build -G Ninja -DBOARD=${{ matrix.board }} -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_BUILD_TYPE=MinSizeRel + cmake examples -B build -G Ninja -DBOARD=${{ matrix.board }} -DCMAKE_BUILD_TYPE=MinSizeRel build-wrapper-linux-x86-64 --out-dir ${{ env.BUILD_WRAPPER_OUT_DIR }} cmake --build build/ - name: SonarQube Scan @@ -177,3 +179,46 @@ jobs: # Consult https://docs.sonarsource.com/sonarqube-server/latest/analyzing-source-code/scanners/sonarscanner/ for more information and options args: > --define sonar.cfamily.compile-commands=${{ env.BUILD_WRAPPER_OUT_DIR }}/compile_commands.json + + IAR-CStat: + if: github.repository_owner == 'hathach' + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + board: + - 'b_g474e_dpow1' + steps: + - name: Checkout TinyUSB + uses: actions/checkout@v4 + + - name: Get Dependencies + uses: ./.github/actions/get_deps + with: + arg: -b${{ matrix.board }} + + - name: Setup Toolchain + uses: ./.github/actions/setup_toolchain + with: + toolchain: 'arm-iar' + + - name: Run IAR C-STAT Analysis + env: + IAR_LMS_BEARER_TOKEN: ${{ secrets.IAR_LMS_BEARER_TOKEN }} + run: | + # CMake run post build to generate C-STAT SARIF report + mkdir -p build + cmake examples -B build -G Ninja -DBOARD=${{ matrix.board }} -DTOOLCHAIN=iar -DIAR_CSTAT=1 -DCMAKE_BUILD_TYPE=MinSizeRel + cmake --build build + + - name: Upload SARIF + uses: github/codeql-action/upload-sarif@v4 + with: + sarif_file: build/cstat_sarif + category: IAR-CStat + + - name: Upload artifact + uses: actions/upload-artifact@v5 + with: + name: iar-cstat-${{ matrix.board }} + path: build/cstat_sarif diff --git a/tools/make_release.py b/tools/make_release.py index 488ad4901..0e7919f46 100755 --- a/tools/make_release.py +++ b/tools/make_release.py @@ -44,6 +44,17 @@ with open(f_library_json) as f: with open(f_library_json, 'w') as f: f.write(fdata) +################### +# sonar-project.properties +################### +f_sonar_properties = 'sonar-project.properties' +with open(f_sonar_properties) as f: + fdata = f.read() + fdata = re.sub(r'(sonar\.projectVersion=)\d+\.\d+\.\d+', rf'\1{version}', fdata) + +with open(f_sonar_properties, 'w') as f: + f.write(fdata) + ################### # docs/info/changelog.rst ################### -- cgit v1.3.1 From 42f000df8e52cfe0a46867a5e1fa5817cd58bc8a Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 25 Oct 2025 17:36:01 +0700 Subject: iar cstat require cmake at least 4.1 --- .github/workflows/static_analysis.yml | 19 +++++++++++++++---- examples/build_system/cmake/toolchain/arm_iar.cmake | 1 + hw/bsp/family_support.cmake | 8 ++++---- 3 files changed, 20 insertions(+), 8 deletions(-) (limited to '.github/workflows/static_analysis.yml') diff --git a/.github/workflows/static_analysis.yml b/.github/workflows/static_analysis.yml index e060dfbc9..0af8ac42c 100644 --- a/.github/workflows/static_analysis.yml +++ b/.github/workflows/static_analysis.yml @@ -202,23 +202,34 @@ jobs: with: toolchain: 'arm-iar' - - name: Run IAR C-STAT Analysis + - name: Install CMake 4.2 + run: | + # IAR CSTAT requires CMake >= 4.1 + wget -q https://github.com/Kitware/CMake/releases/download/v4.2.0-rc1/cmake-4.2.0-rc1-linux-x86_64.tar.gz + tar -xzf cmake-4.2.0-rc1-linux-x86_64.tar.gz + echo "${{ github.workspace }}/cmake-4.2.0-rc1-linux-x86_64/bin" >> $GITHUB_PATH + + - name: Build and run IAR C-STAT Analysis env: IAR_LMS_BEARER_TOKEN: ${{ secrets.IAR_LMS_BEARER_TOKEN }} run: | # CMake run post build to generate C-STAT SARIF report + cmake --version mkdir -p build - cmake examples -B build -G Ninja -DBOARD=${{ matrix.board }} -DTOOLCHAIN=iar -DIAR_CSTAT=1 -DCMAKE_BUILD_TYPE=MinSizeRel + cmake examples/device/cdc_msc -B build -G Ninja -DBOARD=${{ matrix.board }} -DTOOLCHAIN=iar -DIAR_CSTAT=1 -DCMAKE_BUILD_TYPE=MinSizeRel cmake --build build + # Merge sarif files for codeql upload + npm i -g @microsoft/sarif-multitool + npx @microsoft/sarif-multitool merge --merge-runs --output-file iar-cstat-${{ matrix.board }}.sarif build/cstat_sarif/*.sarif - name: Upload SARIF uses: github/codeql-action/upload-sarif@v4 with: - sarif_file: build/cstat_sarif + sarif_file: iar-cstat-${{ matrix.board }}.sarif category: IAR-CStat - name: Upload artifact uses: actions/upload-artifact@v5 with: name: iar-cstat-${{ matrix.board }} - path: build/cstat_sarif + path: iar-cstat-${{ matrix.board }}.sarif diff --git a/examples/build_system/cmake/toolchain/arm_iar.cmake b/examples/build_system/cmake/toolchain/arm_iar.cmake index 42b057020..f4c0a500e 100644 --- a/examples/build_system/cmake/toolchain/arm_iar.cmake +++ b/examples/build_system/cmake/toolchain/arm_iar.cmake @@ -19,6 +19,7 @@ find_program(CMAKE_IAR_CHECKS ichecks) find_program(CMAKE_IAR_REPORT ireport) if (IAR_CSTAT) +cmake_minimum_required(VERSION 4.1) set(CMAKE_C_ICSTAT ${CMAKE_IAR_CSTAT} --checks=${CMAKE_CURRENT_LIST_DIR}/cstat_sel_checks.txt --db=${CMAKE_BINARY_DIR}/cstat.db --sarif_dir=${CMAKE_BINARY_DIR}/cstat_sarif) endif () diff --git a/hw/bsp/family_support.cmake b/hw/bsp/family_support.cmake index 79a9f459b..912e0f4d7 100644 --- a/hw/bsp/family_support.cmake +++ b/hw/bsp/family_support.cmake @@ -300,10 +300,10 @@ function(family_configure_common TARGET RTOS) COMMAND_EXPAND_LISTS ) # generate C-STAT report - add_custom_command(TARGET ${TARGET} POST_BUILD - COMMAND mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/cstat_report - COMMAND ireport --db=${CMAKE_BINARY_DIR}/cstat.db --full --project ${TARGET} --output ${CMAKE_CURRENT_BINARY_DIR}/cstat_report/index.html - ) +# add_custom_command(TARGET ${TARGET} POST_BUILD +# COMMAND mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/cstat_report +# COMMAND ireport --db=${CMAKE_BINARY_DIR}/cstat.db --full --project ${TARGET} --output ${CMAKE_CURRENT_BINARY_DIR}/cstat_report/index.html +# ) endif () endif () -- cgit v1.3.1 From 8865ec47814628ba1c50e52f09b7ef2fe10d463d Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 27 Oct 2025 12:09:33 +0700 Subject: update static_analysis.yml workflow --- .github/workflows/static_analysis.yml | 21 ++++++++++++++++++--- sonar-project.properties | 1 + 2 files changed, 19 insertions(+), 3 deletions(-) (limited to '.github/workflows/static_analysis.yml') diff --git a/.github/workflows/static_analysis.yml b/.github/workflows/static_analysis.yml index 0af8ac42c..83eea5283 100644 --- a/.github/workflows/static_analysis.yml +++ b/.github/workflows/static_analysis.yml @@ -2,15 +2,30 @@ name: Static Analysis on: workflow_dispatch: push: - branches: - - master + branches: [ master ] + paths: + - 'src/**' + - 'examples/**' + - 'hw/bsp/**' + - '.github/workflows/static_analysis.yml' pull_request: - types: [opened, synchronize, reopened] + branches: [ master ] + paths: + - 'src/**' + - 'examples/**' + - 'hw/bsp/**' + - '.github/workflows/static_analysis.yml' permissions: actions: read contents: read security-events: write +# pull-requests: write +# checks: write + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: CodeQL: diff --git a/sonar-project.properties b/sonar-project.properties index d797bfe6f..5a19a234d 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -9,6 +9,7 @@ sonar.projectVersion=0.19.0 # Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows. #sonar.sources=. +sonar.exclusions=lib/**,hw/mcu/**,test/** # Encoding of the source code. Default is default system encoding #sonar.sourceEncoding=UTF-8 -- cgit v1.3.1 From 621123b9b3709bfd1768778f5d526498549eadae Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 28 Oct 2025 00:16:40 +0700 Subject: added .pvsconfig to exclude some rules --- .PVS-Studio/.pvsconfig | 1 + .github/workflows/static_analysis.yml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 .PVS-Studio/.pvsconfig (limited to '.github/workflows/static_analysis.yml') diff --git a/.PVS-Studio/.pvsconfig b/.PVS-Studio/.pvsconfig new file mode 100644 index 000000000..b722c6d10 --- /dev/null +++ b/.PVS-Studio/.pvsconfig @@ -0,0 +1 @@ +//-V::2506,2514 diff --git a/.github/workflows/static_analysis.yml b/.github/workflows/static_analysis.yml index 83eea5283..5d2a6c962 100644 --- a/.github/workflows/static_analysis.yml +++ b/.github/workflows/static_analysis.yml @@ -137,7 +137,7 @@ jobs: mkdir -p build cmake examples -B build -G Ninja -DBOARD=${{ matrix.board }} -DCMAKE_BUILD_TYPE=MinSizeRel cmake --build build - pvs-studio-analyzer analyze -f build/compile_commands.json -j --exclude-path hw/mcu/ --exclude-path lib/ + pvs-studio-analyzer analyze -R .PVS-Studio/.pvsconfig -f build/compile_commands.json --exclude-path hw/mcu/ --exclude-path lib/ -j plog-converter -t sarif -o pvs-studio-${{ matrix.board }}.sarif PVS-Studio.log - name: Upload SARIF -- cgit v1.3.1 From 78bd6230649aee3f7731ffbce603742f31c2295e Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 28 Oct 2025 17:56:07 +0700 Subject: filter out sarif for codeql hw/mcu and lib/ --- .github/workflows/static_analysis.yml | 43 ++++++++++++----------------------- 1 file changed, 15 insertions(+), 28 deletions(-) (limited to '.github/workflows/static_analysis.yml') diff --git a/.github/workflows/static_analysis.yml b/.github/workflows/static_analysis.yml index 5d2a6c962..7e74f77ce 100644 --- a/.github/workflows/static_analysis.yml +++ b/.github/workflows/static_analysis.yml @@ -65,36 +65,23 @@ jobs: uses: github/codeql-action/analyze@v4 with: category: CodeQL - upload: always + upload: false id: analyze -# - name: Filter out unwanted errors and warnings -# uses: advanced-security/filter-sarif@v1 -# with: -# patterns: | -# -**:cpp/path-injection -# -**:cpp/world-writable-file-creation -# -**:cpp/poorly-documented-function -# -**:cpp/potentially-dangerous-function -# -**:cpp/use-of-goto -# -**:cpp/integer-multiplication-cast-to-long -# -**:cpp/comparison-with-wider-type -# -**:cpp/leap-year/* -# -**:cpp/ambiguously-signed-bit-field -# -**:cpp/suspicious-pointer-scaling -# -**:cpp/suspicious-pointer-scaling-void -# -**:cpp/unsigned-comparison-zero -# -**/third*party/** -# -**/3rd*party/** -# -**/external/** -# input: ${{ steps.analyze.outputs.sarif-output }}/cpp.sarif -# output: ${{ steps.analyze.outputs.sarif-output }}/cpp.sarif -# -# - name: Upload SARIF -# uses: github/codeql-action/upload-sarif@v4 -# with: -# sarif_file: ${{ steps.analyze.outputs.sarif-output }} -# category: CodeQL + - name: Filter SARIF report + uses: advanced-security/filter-sarif@v1 + with: + patterns: | + -hw/mcu/** + -lib/** + input: ${{ steps.analyze.outputs.sarif-output }}/cpp.sarif + output: ${{ steps.analyze.outputs.sarif-output }}/cpp.sarif + + - name: Upload SARIF + uses: github/codeql-action/upload-sarif@v4 + with: + sarif_file: ${{ steps.analyze.outputs.sarif-output }} + category: CodeQL - name: Upload artifact uses: actions/upload-artifact@v5 -- cgit v1.3.1 From 1f04fe7924e8777c1583323171c0e1cabcb29062 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 5 Nov 2025 15:31:02 +0700 Subject: added .clang-format fix more alerts disable IAR CStat since pvs-studio check is better integrated with clion --- .PVS-Studio/.pvsconfig | 13 +- .clang-format | 102 ++++++---- .github/workflows/static_analysis.yml | 3 +- README.rst | 6 +- examples/device/audio_4_channel_mic/src/main.c | 8 +- .../src/usb_descriptors.c | 8 +- examples/device/audio_test/src/main.c | 8 +- examples/device/audio_test/src/usb_descriptors.c | 8 +- .../audio_test_freertos/src/usb_descriptors.c | 8 +- examples/device/audio_test_multi_rate/src/main.c | 8 +- .../audio_test_multi_rate/src/usb_descriptors.c | 8 +- examples/device/cdc_dual_ports/src/main.c | 12 +- examples/device/cdc_msc/src/msc_disk.c | 28 ++- examples/device/cdc_uac2/src/uac2_app.c | 28 +-- examples/device/cdc_uac2/src/usb_descriptors.c | 8 +- examples/device/dfu/src/usb_descriptors.c | 8 +- examples/device/dfu_runtime/src/main.c | 4 +- examples/device/dfu_runtime/src/usb_descriptors.c | 8 +- examples/device/dynamic_configuration/src/main.c | 56 +++--- .../device/dynamic_configuration/src/msc_disk.c | 14 +- .../dynamic_configuration/src/usb_descriptors.c | 8 +- examples/device/hid_boot_interface/src/main.c | 147 +++++++------- .../hid_boot_interface/src/usb_descriptors.c | 124 ++++++------ examples/device/hid_composite/src/main.c | 211 ++++++++++----------- examples/device/mtp/src/mtp_fs_example.c | 90 +++++---- hw/bsp/family_support.cmake | 8 +- src/class/mtp/mtp.h | 14 +- src/class/mtp/mtp_device.h | 10 +- src/class/video/video.h | 10 +- src/common/tusb_common.h | 7 +- src/common/tusb_debug.h | 4 +- src/device/usbd_control.c | 6 +- src/device/usbd_pvt.h | 5 - src/tusb.c | 4 +- 34 files changed, 523 insertions(+), 471 deletions(-) (limited to '.github/workflows/static_analysis.yml') diff --git a/.PVS-Studio/.pvsconfig b/.PVS-Studio/.pvsconfig index 32125c2f7..2e231c939 100644 --- a/.PVS-Studio/.pvsconfig +++ b/.PVS-Studio/.pvsconfig @@ -1,3 +1,10 @@ -//-V::2506 -//-V::2514 -//-V::2614 +//V_EXCLUDE_PATH */iar/cxarm* +//V_EXCLUDE_PATH */pico-sdk/* + +//-V::2506 MISRA. A function should have a single point of exit at the end. +//-V::2514 MISRA. Unions should not be used. +//-V:memcpy:2547 [MISRA-C-17.7] The return value of non-void function 'memcpy' should be used. +//-V:printf:2547 [MISRA-C-17.7] The return value of non-void function 'printf' should be used. +//-V::2600 [MISRA-C-21.6] The function with the 'printf' name should not be used. +//+V2614 DISABLE_LENGHT_LIMIT_CHECK:YES +//-V:memcpy:2628 Pointer arguments to the 'memcpy' function should be pointers to qualified or unqualified versions of compatible types. diff --git a/.clang-format b/.clang-format index 0fd168e5a..79a160a8d 100644 --- a/.clang-format +++ b/.clang-format @@ -1,66 +1,88 @@ -# Generated from CLion C/C++ Code Style settings +--- +Language: Cpp BasedOnStyle: LLVM -AccessModifierOffset: -2 -AlignAfterOpenBracket: Align -AlignConsecutiveAssignments: None -AlignOperands: Align +AlignAfterOpenBracket: AlwaysBreak +AlignConsecutiveAssignments: + Enabled: true + AcrossEmptyLines: false + AcrossComments: false +AlignConsecutiveBitFields: + Enabled: true + AcrossEmptyLines: false + AcrossComments: false +AlignConsecutiveDeclarations: + Enabled: true + AcrossEmptyLines: false + AcrossComments: false +AlignConsecutiveMacros: + Enabled: true + AcrossEmptyLines: true + AcrossComments: false +AlignConsecutiveShortCaseStatements: + Enabled: true + AcrossEmptyLines: true + AcrossComments: true + AlignCaseColons: false +AlignEscapedNewlines: LeftWithLastLine +AlignOperands: true +AlignTrailingComments: + Kind: Always + OverEmptyLines: 2 AllowAllArgumentsOnNextLine: false AllowAllConstructorInitializersOnNextLine: false AllowAllParametersOfDeclarationOnNextLine: false -AllowShortBlocksOnASingleLine: Always -AllowShortCaseLabelsOnASingleLine: false -AllowShortFunctionsOnASingleLine: All -AllowShortIfStatementsOnASingleLine: Always -AllowShortLambdasOnASingleLine: All -AllowShortLoopsOnASingleLine: true -AlwaysBreakAfterReturnType: None +AllowShortBlocksOnASingleLine: Empty +AllowShortCaseExpressionOnASingleLine: true +AllowShortCaseLabelsOnASingleLine: true +AllowShortFunctionsOnASingleLine: None +AllowShortIfStatementsOnASingleLine: Never AlwaysBreakTemplateDeclarations: Yes BreakBeforeBraces: Custom BraceWrapping: AfterCaseLabel: false AfterClass: false - AfterControlStatement: Never + AfterControlStatement: false AfterEnum: false AfterFunction: false AfterNamespace: false + AfterStruct: false AfterUnion: false - BeforeCatch: false + AfterExternBlock: false + BeforeCatch: true BeforeElse: false - IndentBraces: false - SplitEmptyFunction: false + BeforeLambdaBody: false + BeforeWhile: false + SplitEmptyFunction: true SplitEmptyRecord: true -BreakBeforeBinaryOperators: None -BreakBeforeTernaryOperators: true -BreakConstructorInitializers: BeforeColon -BreakInheritanceList: BeforeColon -ColumnLimit: 0 -CompactNamespaces: false -ContinuationIndentWidth: 4 + SplitEmptyNamespace: true +BracedInitializerIndentWidth: 2 +BreakConstructorInitializers: AfterColon +BreakConstructorInitializersBeforeComma: false +ColumnLimit: 120 +ConstructorInitializerAllOnOneLineOrOnePerLine: false +Cpp11BracedListStyle: true +IncludeCategories: + - Regex: '^<.*' + Priority: 1 + - Regex: '^".*' + Priority: 2 + - Regex: '.*' + Priority: 3 +IncludeIsMainRegex: '([-_](test|unittest))?$' +InsertBraces: true IndentCaseLabels: true -IndentPPDirectives: BeforeHash -IndentWidth: 2 -KeepEmptyLinesAtTheStartOfBlocks: true +InsertNewlineAtEOF: true +MacroBlockBegin: '' +MacroBlockEnd: '' MaxEmptyLinesToKeep: 2 NamespaceIndentation: All -ObjCSpaceAfterProperty: false -ObjCSpaceBeforeProtocolList: true -PointerAlignment: Right ReflowComments: false -SpaceAfterCStyleCast: true -SpaceAfterLogicalNot: false SpaceAfterTemplateKeyword: false -SpaceBeforeAssignmentOperators: true -SpaceBeforeCpp11BracedList: false -SpaceBeforeCtorInitializerColon: true -SpaceBeforeInheritanceColon: true -SpaceBeforeParens: ControlStatements SpaceBeforeRangeBasedForLoopColon: false SpaceInEmptyParentheses: false -SpacesBeforeTrailingComments: 0 SpacesInAngles: false +SpacesInConditionalStatement: false SpacesInCStyleCastParentheses: false -SpacesInContainerLiterals: true SpacesInParentheses: false -SpacesInSquareBrackets: false TabWidth: 2 -UseTab: Never +... diff --git a/.github/workflows/static_analysis.yml b/.github/workflows/static_analysis.yml index 7e74f77ce..227f5e103 100644 --- a/.github/workflows/static_analysis.yml +++ b/.github/workflows/static_analysis.yml @@ -183,7 +183,8 @@ jobs: --define sonar.cfamily.compile-commands=${{ env.BUILD_WRAPPER_OUT_DIR }}/compile_commands.json IAR-CStat: - if: github.repository_owner == 'hathach' + #if: github.repository_owner == 'hathach' + if: false runs-on: ubuntu-latest strategy: fail-fast: false diff --git a/README.rst b/README.rst index 38ebcc8da..fcec5d613 100644 --- a/README.rst +++ b/README.rst @@ -1,4 +1,4 @@ -|Build Status| |CircleCI Status| |Documentation Status| |Fuzzing Status| |License| +|Build Status| |CircleCI Status| |Documentation Status| |Static Analysis| |Fuzzing Status| |License| Sponsors ======== @@ -252,11 +252,13 @@ The following tools are provided freely to support the development of the TinyUS .. |Build Status| image:: https://github.com/hathach/tinyusb/actions/workflows/build.yml/badge.svg - :target: https://github.com/hathach/tinyusb/actions + :target: https://github.com/hathach/tinyusb/actions/workflows/build.yml .. |CircleCI Status| image:: https://dl.circleci.com/status-badge/img/circleci/4AYHvUhFxdnY4rA7LEsdqW/QmrpoL2AjGqetvFQNqtWyq/tree/master.svg?style=svg :target: https://dl.circleci.com/status-badge/redirect/circleci/4AYHvUhFxdnY4rA7LEsdqW/QmrpoL2AjGqetvFQNqtWyq/tree/master .. |Documentation Status| image:: https://readthedocs.org/projects/tinyusb/badge/?version=latest :target: https://docs.tinyusb.org/en/latest/?badge=latest +.. |Static Analysis| image:: https://github.com/hathach/tinyusb/actions/workflows/static_analysis.yml/badge.svg + :target: https://github.com/hathach/tinyusb/actions/workflows/static_analysis.yml .. |Fuzzing Status| image:: https://oss-fuzz-build-logs.storage.googleapis.com/badges/tinyusb.svg :target: https://oss-fuzz-build-logs.storage.googleapis.com/index.html#tinyusb .. |License| image:: https://img.shields.io/badge/license-MIT-brightgreen.svg diff --git a/examples/device/audio_4_channel_mic/src/main.c b/examples/device/audio_4_channel_mic/src/main.c index de9e8a06a..5767c7453 100644 --- a/examples/device/audio_4_channel_mic/src/main.c +++ b/examples/device/audio_4_channel_mic/src/main.c @@ -156,7 +156,9 @@ void tud_resume_cb(void) { void audio_task(void) { static uint32_t start_ms = 0; uint32_t curr_ms = board_millis(); - if (start_ms == curr_ms) return;// not enough time + if (start_ms == curr_ms) { + return; // not enough time + } start_ms = curr_ms; tud_audio_write(i2s_dummy_buffer, AUDIO_SAMPLE_RATE / 1000 * CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX * CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX); } @@ -406,7 +408,9 @@ void led_blinking_task(void) { static bool led_state = false; // Blink every interval ms - if (board_millis() - start_ms < blink_interval_ms) return;// not enough time + if (board_millis() - start_ms < blink_interval_ms) { + return; // not enough time + } start_ms += blink_interval_ms; board_led_write(led_state); diff --git a/examples/device/audio_4_channel_mic_freertos/src/usb_descriptors.c b/examples/device/audio_4_channel_mic_freertos/src/usb_descriptors.c index 2f5f67f66..3bb93f67d 100644 --- a/examples/device/audio_4_channel_mic_freertos/src/usb_descriptors.c +++ b/examples/device/audio_4_channel_mic_freertos/src/usb_descriptors.c @@ -156,14 +156,18 @@ uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) { // 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; + 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); size_t const max_count = sizeof(_desc_str) / sizeof(_desc_str[0]) - 1; // -1 for string type - if ( chr_count > max_count ) chr_count = max_count; + if ( chr_count > max_count ) { + chr_count = max_count; + } // Convert ASCII string into UTF-16 for ( size_t i = 0; i < chr_count; i++ ) { diff --git a/examples/device/audio_test/src/main.c b/examples/device/audio_test/src/main.c index 875d0b7f0..2441eefbc 100644 --- a/examples/device/audio_test/src/main.c +++ b/examples/device/audio_test/src/main.c @@ -139,7 +139,9 @@ void tud_resume_cb(void) { void audio_task(void) { static uint32_t start_ms = 0; uint32_t curr_ms = board_millis(); - if (start_ms == curr_ms) return;// not enough time + if (start_ms == curr_ms) { + return; // not enough time + } start_ms = curr_ms; for (size_t cnt = 0; cnt < sizeof(test_buffer_audio) / 2; cnt++) { test_buffer_audio[cnt] = startVal++; @@ -400,7 +402,9 @@ void led_blinking_task(void) { static bool led_state = false; // Blink every interval ms - if (board_millis() - start_ms < blink_interval_ms) return;// not enough time + if (board_millis() - start_ms < blink_interval_ms) { + return; // not enough time + } start_ms += blink_interval_ms; board_led_write(led_state); diff --git a/examples/device/audio_test/src/usb_descriptors.c b/examples/device/audio_test/src/usb_descriptors.c index b6c19deba..ad161939e 100644 --- a/examples/device/audio_test/src/usb_descriptors.c +++ b/examples/device/audio_test/src/usb_descriptors.c @@ -158,14 +158,18 @@ uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) { // 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; + 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); size_t const max_count = sizeof(_desc_str) / sizeof(_desc_str[0]) - 1; // -1 for string type - if ( chr_count > max_count ) chr_count = max_count; + if (chr_count > max_count) { + chr_count = max_count; + } // Convert ASCII string into UTF-16 for ( size_t i = 0; i < chr_count; i++ ) { diff --git a/examples/device/audio_test_freertos/src/usb_descriptors.c b/examples/device/audio_test_freertos/src/usb_descriptors.c index b6c19deba..ad161939e 100644 --- a/examples/device/audio_test_freertos/src/usb_descriptors.c +++ b/examples/device/audio_test_freertos/src/usb_descriptors.c @@ -158,14 +158,18 @@ uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) { // 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; + 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); size_t const max_count = sizeof(_desc_str) / sizeof(_desc_str[0]) - 1; // -1 for string type - if ( chr_count > max_count ) chr_count = max_count; + if (chr_count > max_count) { + chr_count = max_count; + } // Convert ASCII string into UTF-16 for ( size_t i = 0; i < chr_count; i++ ) { diff --git a/examples/device/audio_test_multi_rate/src/main.c b/examples/device/audio_test_multi_rate/src/main.c index 55a649613..baeec870f 100644 --- a/examples/device/audio_test_multi_rate/src/main.c +++ b/examples/device/audio_test_multi_rate/src/main.c @@ -147,7 +147,9 @@ void tud_resume_cb(void) { void audio_task(void) { static uint32_t start_ms = 0; uint32_t curr_ms = board_millis(); - if (start_ms == curr_ms) return;// not enough time + if (start_ms == curr_ms) { + return; // not enough time + } start_ms = curr_ms; // 16bit if (bytesPerSample == 2) { @@ -612,7 +614,9 @@ void led_blinking_task(void) { static bool led_state = false; // Blink every interval ms - if (board_millis() - start_ms < blink_interval_ms) return;// not enough time + if (board_millis() - start_ms < blink_interval_ms) { + return; // not enough time + } start_ms += blink_interval_ms; board_led_write(led_state); diff --git a/examples/device/audio_test_multi_rate/src/usb_descriptors.c b/examples/device/audio_test_multi_rate/src/usb_descriptors.c index 1912a81e2..471eb4f2e 100644 --- a/examples/device/audio_test_multi_rate/src/usb_descriptors.c +++ b/examples/device/audio_test_multi_rate/src/usb_descriptors.c @@ -213,14 +213,18 @@ uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) { // 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; + 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); size_t const max_count = sizeof(_desc_str) / sizeof(_desc_str[0]) - 1; // -1 for string type - if ( chr_count > max_count ) chr_count = max_count; + if (chr_count > max_count) { + chr_count = max_count; + } // Convert ASCII string into UTF-16 for ( size_t i = 0; i < chr_count; i++ ) { diff --git a/examples/device/cdc_dual_ports/src/main.c b/examples/device/cdc_dual_ports/src/main.c index 8fe003f21..5ccb06a8a 100644 --- a/examples/device/cdc_dual_ports/src/main.c +++ b/examples/device/cdc_dual_ports/src/main.c @@ -75,10 +75,14 @@ static void echo_serial_port(uint8_t itf, uint8_t buf[], uint32_t count) { for (uint32_t i = 0; i < count; i++) { if (itf == 0) { // echo back 1st port as lower case - if (isupper(buf[i])) buf[i] += case_diff; + if (isupper(buf[i])) { + buf[i] += case_diff; + } } else { // echo back 2nd port as upper case - if (islower(buf[i])) buf[i] -= case_diff; + if (islower(buf[i])) { + buf[i] -= case_diff; + } } tud_cdc_n_write_char(itf, buf[i]); @@ -153,7 +157,9 @@ void led_blinking_task(void) { static bool led_state = false; // Blink every interval ms - if (board_millis() - start_ms < blink_interval_ms) return; // not enough time + if (board_millis() - start_ms < blink_interval_ms) { + return; // not enough time + } start_ms += blink_interval_ms; board_led_write(led_state); diff --git a/examples/device/cdc_msc/src/msc_disk.c b/examples/device/cdc_msc/src/msc_disk.c index 1a95f7f8b..e091c2985 100644 --- a/examples/device/cdc_msc/src/msc_disk.c +++ b/examples/device/cdc_msc/src/msc_disk.c @@ -128,9 +128,9 @@ uint32_t tud_msc_inquiry2_cb(uint8_t lun, scsi_inquiry_resp_t *inquiry_resp, uin const char pid[] = "Mass Storage"; const char rev[] = "1.0"; - strncpy((char*) inquiry_resp->vendor_id, vid, 8); - strncpy((char*) inquiry_resp->product_id, pid, 16); - strncpy((char*) inquiry_resp->product_rev, rev, 4); + (void) strncpy((char*) inquiry_resp->vendor_id, vid, 8); + (void) strncpy((char*) inquiry_resp->product_id, pid, 16); + (void) strncpy((char*) inquiry_resp->product_rev, rev, 4); return sizeof(scsi_inquiry_resp_t); // 36 bytes } @@ -143,8 +143,7 @@ bool tud_msc_test_unit_ready_cb(uint8_t lun) { // RAM disk is ready until ejected if (ejected) { // Additional Sense 3A-00 is NOT_FOUND - tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x3a, 0x00); - return false; + return tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x3a, 0x00); } return true; @@ -154,7 +153,6 @@ bool tud_msc_test_unit_ready_cb(uint8_t lun) { // Application update block count and block size void tud_msc_capacity_cb(uint8_t lun, uint32_t *block_count, uint16_t *block_size) { (void) lun; - *block_count = DISK_BLOCK_NUM; *block_size = DISK_BLOCK_SIZE; } @@ -194,7 +192,7 @@ int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void *buff } uint8_t const *addr = msc_disk[lba] + offset; - memcpy(buffer, addr, bufsize); + (void) memcpy(buffer, addr, bufsize); return (int32_t) bufsize; } @@ -221,7 +219,7 @@ int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t * #ifndef CFG_EXAMPLE_MSC_READONLY uint8_t *addr = msc_disk[lba] + offset; - memcpy(addr, buffer, bufsize); + (void) memcpy(addr, buffer, bufsize); #else (void) lba; (void) offset; @@ -235,19 +233,17 @@ int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t * // - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, MODE_SENSE6, REQUEST_SENSE // - READ10 and WRITE10 has their own callbacks int32_t tud_msc_scsi_cb(uint8_t lun, uint8_t const scsi_cmd[16], void *buffer, uint16_t bufsize) { + (void) lun; + (void) scsi_cmd; (void) buffer; (void) bufsize; - switch (scsi_cmd[0]) { - default: - // Set Sense = Invalid Command Operation - tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00); + // currently no other commands is supported - // negative means error -> tinyusb could stall and/or response with failed status - return -1; - } + // Set Sense = Invalid Command Operation + (void) tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00); - return -1; + return -1; // stall/failed command request; } #endif diff --git a/examples/device/cdc_uac2/src/uac2_app.c b/examples/device/cdc_uac2/src/uac2_app.c index cb7b716e8..73a262d0c 100644 --- a/examples/device/cdc_uac2/src/uac2_app.c +++ b/examples/device/cdc_uac2/src/uac2_app.c @@ -67,7 +67,9 @@ uint8_t current_resolution; void audio_task(void) { static uint32_t start_ms = 0; uint32_t curr_ms = board_millis(); - if (start_ms == curr_ms) return;// not enough time + if (start_ms == curr_ms) { + return; // not enough time + } start_ms = curr_ms; // When new data arrived, copy data from speaker buffer, to microphone buffer // and send it over @@ -226,16 +228,15 @@ static bool tud_audio_feature_unit_set_request(uint8_t rhport, audio20_control_r //--------------------------------------------------------------------+ // Invoked when audio class specific get request received for an entity -bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p_request) -{ +bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p_request) { audio20_control_request_t const *request = (audio20_control_request_t const *)p_request; - if (request->bEntityID == UAC2_ENTITY_CLOCK) + if (request->bEntityID == UAC2_ENTITY_CLOCK) { return tud_audio_clock_get_request(rhport, request); - if (request->bEntityID == UAC2_ENTITY_SPK_FEATURE_UNIT) + } + if (request->bEntityID == UAC2_ENTITY_SPK_FEATURE_UNIT) { return tud_audio_feature_unit_get_request(rhport, request); - else - { + } else { TU_LOG1("Get request not handled, entity = %d, selector = %d, request = %d\r\n", request->bEntityID, request->bControlSelector, request->bRequest); } @@ -243,14 +244,15 @@ bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p } // Invoked when audio class specific set request received for an entity -bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p_request, uint8_t *buf) -{ +bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p_request, uint8_t *buf) { audio20_control_request_t const *request = (audio20_control_request_t const *)p_request; - if (request->bEntityID == UAC2_ENTITY_SPK_FEATURE_UNIT) + if (request->bEntityID == UAC2_ENTITY_SPK_FEATURE_UNIT) { return tud_audio_feature_unit_set_request(rhport, request, buf); - if (request->bEntityID == UAC2_ENTITY_CLOCK) + } + if (request->bEntityID == UAC2_ENTITY_CLOCK) { return tud_audio_clock_set_request(rhport, request, buf); + } TU_LOG1("Set request not handled, entity = %d, selector = %d, request = %d\r\n", request->bEntityID, request->bControlSelector, request->bRequest); @@ -301,7 +303,9 @@ void led_blinking_task(void) static bool led_state = false; // Blink every interval ms - if (board_millis() - start_ms < blink_interval_ms) return; + if (board_millis() - start_ms < blink_interval_ms) { + return; + } start_ms += blink_interval_ms; board_led_write(led_state); diff --git a/examples/device/cdc_uac2/src/usb_descriptors.c b/examples/device/cdc_uac2/src/usb_descriptors.c index 252b602ac..e6caaa971 100644 --- a/examples/device/cdc_uac2/src/usb_descriptors.c +++ b/examples/device/cdc_uac2/src/usb_descriptors.c @@ -248,14 +248,18 @@ uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) { // 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; + 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); size_t const max_count = sizeof(_desc_str) / sizeof(_desc_str[0]) - 1; // -1 for string type - if ( chr_count > max_count ) chr_count = max_count; + if (chr_count > max_count) { + chr_count = max_count; + } // Convert ASCII string into UTF-16 for ( size_t i = 0; i < chr_count; i++ ) { diff --git a/examples/device/dfu/src/usb_descriptors.c b/examples/device/dfu/src/usb_descriptors.c index 14ec315ea..48c9985f3 100644 --- a/examples/device/dfu/src/usb_descriptors.c +++ b/examples/device/dfu/src/usb_descriptors.c @@ -158,14 +158,18 @@ uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) { // 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; + 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); size_t const max_count = sizeof(_desc_str) / sizeof(_desc_str[0]) - 1; // -1 for string type - if ( chr_count > max_count ) chr_count = max_count; + if (chr_count > max_count) { + chr_count = max_count; + } // Convert ASCII string into UTF-16 for ( size_t i = 0; i < chr_count; i++ ) { diff --git a/examples/device/dfu_runtime/src/main.c b/examples/device/dfu_runtime/src/main.c index 37cb80093..5de651bcd 100644 --- a/examples/device/dfu_runtime/src/main.c +++ b/examples/device/dfu_runtime/src/main.c @@ -132,7 +132,9 @@ void led_blinking_task(void) static bool led_state = false; // Blink every interval ms - if ( board_millis() - start_ms < blink_interval_ms) return; // not enough time + if (board_millis() - start_ms < blink_interval_ms) { + return; // not enough time + } start_ms += blink_interval_ms; board_led_write(led_state); diff --git a/examples/device/dfu_runtime/src/usb_descriptors.c b/examples/device/dfu_runtime/src/usb_descriptors.c index 1d46ee252..5d5cf52cd 100644 --- a/examples/device/dfu_runtime/src/usb_descriptors.c +++ b/examples/device/dfu_runtime/src/usb_descriptors.c @@ -153,14 +153,18 @@ uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) { // 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; + 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); size_t const max_count = sizeof(_desc_str) / sizeof(_desc_str[0]) - 1; // -1 for string type - if ( chr_count > max_count ) chr_count = max_count; + if (chr_count > max_count) { + chr_count = max_count; + } // Convert ASCII string into UTF-16 for ( size_t i = 0; i < chr_count; i++ ) { diff --git a/examples/device/dynamic_configuration/src/main.c b/examples/device/dynamic_configuration/src/main.c index 258cfcd02..dac74bb7a 100644 --- a/examples/device/dynamic_configuration/src/main.c +++ b/examples/device/dynamic_configuration/src/main.c @@ -109,23 +109,18 @@ void tud_resume_cb(void) //--------------------------------------------------------------------+ // USB CDC //--------------------------------------------------------------------+ -void cdc_task(void) -{ - if ( tud_cdc_connected() ) - { - // connected and there are data available - if ( tud_cdc_available() ) - { +void cdc_task(void) { + if (tud_cdc_connected()) { + // connected and there are data available read and echo back + if (tud_cdc_available()) { uint8_t buf[64]; - - // read and echo back uint32_t count = tud_cdc_read(buf, sizeof(buf)); - for(uint32_t i=0; i= sizeof(note_sequence)) note_pos = 0; + if (note_pos >= sizeof(note_sequence)) { + note_pos = 0; + } } //--------------------------------------------------------------------+ // BLINKING TASK //--------------------------------------------------------------------+ -void led_blinking_task(void) -{ +void led_blinking_task(void) { static uint32_t start_ms = 0; static bool led_state = false; // Blink every interval ms - if ( board_millis() - start_ms < blink_interval_ms) return; // not enough time + 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 + led_state = 1 - led_state;// toggle } diff --git a/examples/device/dynamic_configuration/src/msc_disk.c b/examples/device/dynamic_configuration/src/msc_disk.c index ab71b02d6..e95b2e197 100644 --- a/examples/device/dynamic_configuration/src/msc_disk.c +++ b/examples/device/dynamic_configuration/src/msc_disk.c @@ -177,12 +177,13 @@ bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, boo // Callback invoked when received READ10 command. // Copy disk's data to buffer (up to bufsize) and return number of copied bytes. -int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize) -{ +int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize) { (void) lun; // out of ramdisk - if ( lba >= DISK_BLOCK_NUM ) return -1; + if ( lba >= DISK_BLOCK_NUM ) { + return -1; + } uint8_t const* addr = msc_disk[lba] + offset; memcpy(buffer, addr, bufsize); @@ -192,12 +193,13 @@ int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buff // Callback invoked when received WRITE10 command. // Process data in buffer to disk's storage and return number of written bytes -int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize) -{ +int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize) { (void) lun; // out of ramdisk - if ( lba >= DISK_BLOCK_NUM ) return -1; + if ( lba >= DISK_BLOCK_NUM ) { + return -1; + } #ifndef CFG_EXAMPLE_MSC_READONLY uint8_t* addr = msc_disk[lba] + offset; diff --git a/examples/device/dynamic_configuration/src/usb_descriptors.c b/examples/device/dynamic_configuration/src/usb_descriptors.c index 083279938..458b7c2a5 100644 --- a/examples/device/dynamic_configuration/src/usb_descriptors.c +++ b/examples/device/dynamic_configuration/src/usb_descriptors.c @@ -232,14 +232,18 @@ uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) { // 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; + 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); size_t const max_count = sizeof(_desc_str) / sizeof(_desc_str[0]) - 1; // -1 for string type - if ( chr_count > max_count ) chr_count = max_count; + if (chr_count > max_count) { + chr_count = max_count; + } // Convert ASCII string into UTF-16 for ( size_t i = 0; i < chr_count; i++ ) { diff --git a/examples/device/hid_boot_interface/src/main.c b/examples/device/hid_boot_interface/src/main.c index 45712cede..44a91db67 100644 --- a/examples/device/hid_boot_interface/src/main.c +++ b/examples/device/hid_boot_interface/src/main.c @@ -23,8 +23,8 @@ * */ -#include #include +#include #include #include "bsp/board_api.h" @@ -40,10 +40,10 @@ * - 1000 ms : device mounted * - 2500 ms : device is suspended */ -enum { +enum { BLINK_NOT_MOUNTED = 250, - BLINK_MOUNTED = 1000, - BLINK_SUSPENDED = 2500, + BLINK_MOUNTED = 1000, + BLINK_SUSPENDED = 2500, }; static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED; @@ -52,21 +52,16 @@ void led_blinking_task(void); void hid_task(void); /*------------- MAIN -------------*/ -int main(void) -{ +int main(void) { board_init(); // init device stack on configured roothub port - tusb_rhport_init_t dev_init = { - .role = TUSB_ROLE_DEVICE, - .speed = TUSB_SPEED_AUTO - }; + tusb_rhport_init_t dev_init = {.role = TUSB_ROLE_DEVICE, .speed = TUSB_SPEED_AUTO}; tusb_init(BOARD_TUD_RHPORT, &dev_init); board_init_after_tusb(); - while (1) - { + while (1) { tud_task(); // tinyusb device task led_blinking_task(); @@ -81,29 +76,25 @@ int main(void) //--------------------------------------------------------------------+ // Invoked when device is mounted -void tud_mount_cb(void) -{ +void tud_mount_cb(void) { blink_interval_ms = BLINK_MOUNTED; } // Invoked when device is unmounted -void tud_umount_cb(void) -{ +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; +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) -{ +void tud_resume_cb(void) { blink_interval_ms = tud_mounted() ? BLINK_MOUNTED : BLINK_NOT_MOUNTED; } @@ -113,59 +104,54 @@ void tud_resume_cb(void) // 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) -{ +void hid_task(void) { // Poll every 10ms - const uint32_t interval_ms = 10; - static uint32_t start_ms = 0; + const uint32_t interval_ms = 10; + static uint32_t start_ms = 0; - if ( board_millis() - start_ms < interval_ms) return; // not enough time + 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 ) - { + 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 - { + } else { // keyboard interface - if ( tud_hid_n_ready(ITF_NUM_KEYBOARD) ) - { + 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; + 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 - { + } 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); + 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 ) - { + if (tud_hid_n_ready(ITF_NUM_MOUSE)) { + if (btn) { uint8_t const report_id = 0; uint8_t const button_mask = 0; - int8_t const vertical = 0; - int8_t const horizontal = 0; - int8_t const delta = 5; + int8_t const vertical = 0; + int8_t const horizontal = 0; + int8_t const delta = 5; tud_hid_n_mouse_report(ITF_NUM_MOUSE, report_id, button_mask, delta, delta, vertical, horizontal); } @@ -175,10 +161,9 @@ void hid_task(void) // 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; +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. // TODO set a indicator for user @@ -187,11 +172,10 @@ void tud_hid_set_protocol_cb(uint8_t instance, uint8_t protocol) // 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, uint16_t len) -{ - (void) instance; - (void) report; - (void) len; +void tud_hid_report_complete_cb(uint8_t instance, uint8_t const *report, uint16_t len) { + (void)instance; + (void)report; + (void)len; // nothing to do } @@ -199,42 +183,40 @@ void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, uint16_ // 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) -{ +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; + (void)instance; + (void)report_id; + (void)report_type; + (void)buffer; + (void)reqlen; return 0; } // Invoked when received SET_REPORT control request or // received data on OUT endpoint ( Report ID = 0, Type = 0 ) -void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize) -{ - (void) report_id; +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) - { + if (instance == ITF_NUM_KEYBOARD) { // Set keyboard LED e.g Capslock, Numlock etc... - if (report_type == HID_REPORT_TYPE_OUTPUT) - { + if (report_type == HID_REPORT_TYPE_OUTPUT) { // bufsize should be (at least) 1 - if ( bufsize < 1 ) return; + if (bufsize < 1) { + return; + } uint8_t const kbd_leds = buffer[0]; - if (kbd_leds & KEYBOARD_LED_CAPSLOCK) - { + if (kbd_leds & KEYBOARD_LED_CAPSLOCK) { // Capslock On: disable blink, turn led on blink_interval_ms = 0; board_led_write(true); - }else - { + } else { // Caplocks Off: back to normal blink board_led_write(false); blink_interval_ms = BLINK_MOUNTED; @@ -246,16 +228,19 @@ void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_ //--------------------------------------------------------------------+ // BLINKING TASK //--------------------------------------------------------------------+ -void led_blinking_task(void) -{ - static uint32_t start_ms = 0; - static bool led_state = false; +void led_blinking_task(void) { + static uint32_t start_ms = 0; + static bool led_state = false; // blink is disabled - if (!blink_interval_ms) return; + if (!blink_interval_ms) { + return; + } // Blink every interval ms - if ( board_millis() - start_ms < blink_interval_ms) return; // not enough time + if (board_millis() - start_ms < blink_interval_ms) { + return; // not enough time + } start_ms += blink_interval_ms; board_led_write(led_state); diff --git a/examples/device/hid_boot_interface/src/usb_descriptors.c b/examples/device/hid_boot_interface/src/usb_descriptors.c index 9b4becc85..b5c31a94a 100644 --- a/examples/device/hid_boot_interface/src/usb_descriptors.c +++ b/examples/device/hid_boot_interface/src/usb_descriptors.c @@ -33,60 +33,49 @@ * Auto ProductID layout's Bitmap: * [MSB] HID | MSC | CDC [LSB] */ -#define PID_MAP(itf, n) ((CFG_TUD_##itf) ? (1 << (n)) : 0) -#define USB_PID (0x4000 | PID_MAP(CDC, 0) | PID_MAP(MSC, 1) | PID_MAP(HID, 2) | \ - PID_MAP(MIDI, 3) | PID_MAP(VENDOR, 4) ) +#define PID_MAP(itf, n) ((CFG_TUD_##itf) ? (1 << (n)) : 0) +#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 //--------------------------------------------------------------------+ -static 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 -}; +static 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; +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_keyboard_report[] = {TUD_HID_REPORT_DESC_KEYBOARD()}; -uint8_t const desc_hid_mouse_report[] = -{ - TUD_HID_REPORT_DESC_MOUSE() -}; +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) -{ +uint8_t const *tud_hid_descriptor_report_cb(uint8_t instance) { return (instance == 0) ? desc_hid_keyboard_report : desc_hid_mouse_report; } @@ -94,36 +83,37 @@ uint8_t const * tud_hid_descriptor_report_cb(uint8_t instance) // Configuration Descriptor //--------------------------------------------------------------------+ -#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + 2*TUD_HID_DESC_LEN) +#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 +// 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 +#define EPNUM_KEYBOARD 0x81 +#define EPNUM_MOUSE 0x82 #endif -uint8_t const desc_configuration[] = -{ +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), + 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) -}; + 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 +uint8_t const *tud_descriptor_configuration_cb(uint8_t index) { + (void)index; // for multiple configurations return desc_configuration; } @@ -140,12 +130,11 @@ enum { }; // array of pointer to string descriptors -static char const *string_desc_arr[] = -{ - (const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409) - "TinyUSB", // 1: Manufacturer - "TinyUSB Device", // 2: Product - NULL, // 3: Serials will use unique ID if possible +static char const *string_desc_arr[] = { + (const char[]){0x09, 0x04}, // 0: is supported language is English (0x0409) + "TinyUSB", // 1: Manufacturer + "TinyUSB Device", // 2: Product + NULL, // 3: Serials will use unique ID if possible }; static uint16_t _desc_str[32 + 1]; @@ -153,41 +142,44 @@ static uint16_t _desc_str[32 + 1]; // 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; + (void)langid; size_t chr_count; - switch ( index ) { + switch (index) { case STRID_LANGID: memcpy(&_desc_str[1], string_desc_arr[0], 2); chr_count = 1; break; - case STRID_SERIAL: - chr_count = board_usb_get_serial(_desc_str + 1, 32); - break; + case STRID_SERIAL: chr_count = board_usb_get_serial(_desc_str + 1, 32); break; default: // 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; + 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); + size_t const max_count = sizeof(_desc_str) / sizeof(_desc_str[0]) - 1; // -1 for string type - if ( chr_count > max_count ) chr_count = max_count; + if (chr_count > max_count) { + chr_count = max_count; + } // Convert ASCII string into UTF-16 - for ( size_t i = 0; i < chr_count; i++ ) { + for (size_t i = 0; i < chr_count; i++) { _desc_str[1 + i] = str[i]; } break; } // first byte is length (including header), second byte is string type - _desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8) | (2 * chr_count + 2)); + _desc_str[0] = (uint16_t)((TUSB_DESC_STRING << 8) | (2 * chr_count + 2)); return _desc_str; } diff --git a/examples/device/hid_composite/src/main.c b/examples/device/hid_composite/src/main.c index 89dab0bdc..9693d564d 100644 --- a/examples/device/hid_composite/src/main.c +++ b/examples/device/hid_composite/src/main.c @@ -23,8 +23,8 @@ * */ -#include #include +#include #include #include "bsp/board_api.h" @@ -41,10 +41,10 @@ * - 1000 ms : device mounted * - 2500 ms : device is suspended */ -enum { +enum { BLINK_NOT_MOUNTED = 250, - BLINK_MOUNTED = 1000, - BLINK_SUSPENDED = 2500, + BLINK_MOUNTED = 1000, + BLINK_SUSPENDED = 2500, }; static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED; @@ -53,24 +53,18 @@ void led_blinking_task(void); void hid_task(void); /*------------- MAIN -------------*/ -int main(void) -{ +int main(void) { board_init(); // init device stack on configured roothub port - tusb_rhport_init_t dev_init = { - .role = TUSB_ROLE_DEVICE, - .speed = TUSB_SPEED_AUTO - }; + tusb_rhport_init_t dev_init = {.role = TUSB_ROLE_DEVICE, .speed = TUSB_SPEED_AUTO}; tusb_init(BOARD_TUD_RHPORT, &dev_init); board_init_after_tusb(); - while (1) - { + while (1) { tud_task(); // tinyusb device task led_blinking_task(); - hid_task(); } } @@ -80,29 +74,25 @@ int main(void) //--------------------------------------------------------------------+ // Invoked when device is mounted -void tud_mount_cb(void) -{ +void tud_mount_cb(void) { blink_interval_ms = BLINK_MOUNTED; } // Invoked when device is unmounted -void tud_umount_cb(void) -{ +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; +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) -{ +void tud_resume_cb(void) { blink_interval_ms = tud_mounted() ? BLINK_MOUNTED : BLINK_NOT_MOUNTED; } @@ -110,138 +100,128 @@ void tud_resume_cb(void) // USB HID //--------------------------------------------------------------------+ -static void send_hid_report(uint8_t report_id, uint32_t btn) -{ +static void send_hid_report(uint8_t report_id, uint32_t btn) { // skip if hid is not ready yet - if ( !tud_hid_ready() ) return; + if (!tud_hid_ready()) { + return; + } - switch(report_id) - { - case REPORT_ID_KEYBOARD: - { + switch (report_id) { + case REPORT_ID_KEYBOARD: { // use to avoid send multiple consecutive zero report for keyboard static bool has_keyboard_key = false; - if ( btn ) - { - uint8_t keycode[6] = { 0 }; - keycode[0] = HID_KEY_A; + if (btn != 0u) { + uint8_t keycode[6] = {0}; + keycode[0] = HID_KEY_A; tud_hid_keyboard_report(REPORT_ID_KEYBOARD, 0, keycode); has_keyboard_key = true; - }else - { + } else { // send empty key report if previously has key pressed - if (has_keyboard_key) tud_hid_keyboard_report(REPORT_ID_KEYBOARD, 0, NULL); + if (has_keyboard_key) { + tud_hid_keyboard_report(REPORT_ID_KEYBOARD, 0, NULL); + } has_keyboard_key = false; } + break; } - break; - case REPORT_ID_MOUSE: - { + case REPORT_ID_MOUSE: { int8_t const delta = 5; // no button, right + down, no scroll, no pan tud_hid_mouse_report(REPORT_ID_MOUSE, 0x00, delta, delta, 0, 0); + break; } - break; - case REPORT_ID_CONSUMER_CONTROL: - { + case REPORT_ID_CONSUMER_CONTROL: { // use to avoid send multiple consecutive zero report static bool has_consumer_key = false; - if ( btn ) - { + if (btn != 0u) { // volume down uint16_t volume_down = HID_USAGE_CONSUMER_VOLUME_DECREMENT; tud_hid_report(REPORT_ID_CONSUMER_CONTROL, &volume_down, 2); has_consumer_key = true; - }else - { + } else { // send empty key report (release key) if previously has key pressed uint16_t empty_key = 0; - if (has_consumer_key) tud_hid_report(REPORT_ID_CONSUMER_CONTROL, &empty_key, 2); + if (has_consumer_key) { + tud_hid_report(REPORT_ID_CONSUMER_CONTROL, &empty_key, 2); + } has_consumer_key = false; } + break; } - break; - case REPORT_ID_GAMEPAD: - { + case REPORT_ID_GAMEPAD: { // use to avoid send multiple consecutive zero report for keyboard static bool has_gamepad_key = false; - hid_gamepad_report_t report = - { - .x = 0, .y = 0, .z = 0, .rz = 0, .rx = 0, .ry = 0, - .hat = 0, .buttons = 0 - }; + hid_gamepad_report_t report = {.x = 0, .y = 0, .z = 0, .rz = 0, .rx = 0, .ry = 0, .hat = 0, .buttons = 0}; - if ( btn ) - { - report.hat = GAMEPAD_HAT_UP; + if (btn != 0u) { + report.hat = GAMEPAD_HAT_UP; report.buttons = GAMEPAD_BUTTON_A; tud_hid_report(REPORT_ID_GAMEPAD, &report, sizeof(report)); has_gamepad_key = true; - }else - { - report.hat = GAMEPAD_HAT_CENTERED; + } else { + report.hat = GAMEPAD_HAT_CENTERED; report.buttons = 0; - if (has_gamepad_key) tud_hid_report(REPORT_ID_GAMEPAD, &report, sizeof(report)); + if (has_gamepad_key) { + tud_hid_report(REPORT_ID_GAMEPAD, &report, sizeof(report)); + } has_gamepad_key = false; } + break; } - break; case REPORT_ID_STYLUS_PEN: { - static bool touch_state = false; - hid_stylus_report_t report = { - .attr = 0, - .x = 0, - .y = 0 - }; - - if (btn) { + static bool touch_state = false; + hid_stylus_report_t report = {.attr = 0, .x = 0, .y = 0}; + + if (btn != 0u) { report.attr = STYLUS_ATTR_TIP_SWITCH | STYLUS_ATTR_IN_RANGE; - report.x = 100; - report.y = 100; + report.x = 100; + report.y = 100; tud_hid_report(REPORT_ID_STYLUS_PEN, &report, sizeof(report)); touch_state = true; } else { report.attr = 0; - if (touch_state) tud_hid_report(REPORT_ID_STYLUS_PEN, &report, sizeof(report)); + if (touch_state) { + tud_hid_report(REPORT_ID_STYLUS_PEN, &report, sizeof(report)); + } touch_state = false; } + break; } - break; - default: break; + + default: break; // unknown report id } } // 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) -{ +void hid_task(void) { // Poll every 10ms - const uint32_t interval_ms = 10; - static uint32_t start_ms = 0; + const uint32_t interval_ms = 10; + static uint32_t start_ms = 0; - if ( board_millis() - start_ms < interval_ms) return; // not enough time + if (board_millis() - start_ms < interval_ms) { + return; // not enough time + } start_ms += interval_ms; uint32_t const btn = board_button_read(); // Remote wakeup - if ( tud_suspended() && btn ) - { + if (tud_suspended() && btn != 0u) { // Wake up host if we are in suspend mode // and REMOTE_WAKEUP feature is enabled by host tud_remote_wakeup(); - }else - { + } else { // Send the 1st of report chain, the rest will be sent by tud_hid_report_complete_cb() send_hid_report(REPORT_ID_KEYBOARD, btn); } @@ -250,15 +230,13 @@ void hid_task(void) // Invoked when sent REPORT successfully to host // Application can use this to send the next report // Note: For composite reports, report[0] is report ID -void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, uint16_t len) -{ - (void) instance; - (void) len; +void tud_hid_report_complete_cb(uint8_t instance, uint8_t const *report, uint16_t len) { + (void)instance; + (void)len; uint8_t next_report_id = report[0] + 1u; - if (next_report_id < REPORT_ID_COUNT) - { + if (next_report_id < REPORT_ID_COUNT) { send_hid_report(next_report_id, board_button_read()); } } @@ -266,41 +244,39 @@ void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, uint16_ // 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) -{ +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; + (void)instance; + (void)report_id; + (void)report_type; + (void)buffer; + (void)reqlen; return 0; } // Invoked when received SET_REPORT control request or // received data on OUT endpoint ( Report ID = 0, Type = 0 ) -void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize) -{ - (void) instance; +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)instance; - if (report_type == HID_REPORT_TYPE_OUTPUT) - { + if (report_type == HID_REPORT_TYPE_OUTPUT) { // Set keyboard LED e.g Capslock, Numlock etc... - if (report_id == REPORT_ID_KEYBOARD) - { + if (report_id == REPORT_ID_KEYBOARD) { // bufsize should be (at least) 1 - if ( bufsize < 1 ) return; + if (bufsize < 1) { + return; + } uint8_t const kbd_leds = buffer[0]; - if (kbd_leds & KEYBOARD_LED_CAPSLOCK) - { + if ((kbd_leds & KEYBOARD_LED_CAPSLOCK) != 0u) { // Capslock On: disable blink, turn led on blink_interval_ms = 0; board_led_write(true); - }else - { + } else { // Caplocks Off: back to normal blink board_led_write(false); blink_interval_ms = BLINK_MOUNTED; @@ -312,16 +288,19 @@ void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_ //--------------------------------------------------------------------+ // BLINKING TASK //--------------------------------------------------------------------+ -void led_blinking_task(void) -{ - static uint32_t start_ms = 0; - static bool led_state = false; +void led_blinking_task(void) { + static uint32_t start_ms = 0; + static bool led_state = false; // blink is disabled - if (!blink_interval_ms) return; + if (0u == blink_interval_ms) { + return; + } // Blink every interval ms - if ( board_millis() - start_ms < blink_interval_ms) return; // not enough time + if (board_millis() - start_ms < blink_interval_ms) { + return; // not enough time + } start_ms += blink_interval_ms; board_led_write(led_state); diff --git a/examples/device/mtp/src/mtp_fs_example.c b/examples/device/mtp/src/mtp_fs_example.c index b4772f146..1c287be4d 100644 --- a/examples/device/mtp/src/mtp_fs_example.c +++ b/examples/device/mtp/src/mtp_fs_example.c @@ -39,12 +39,15 @@ #define DEV_PROP_FRIENDLY_NAME "TinyUSB MTP" //------------- storage info -------------// -#define STORAGE_DESCRIPTRION { 'd', 'i', 's', 'k', 0 } +#define STORAGE_DESCRIPTION { 'd', 'i', 's', 'k', 0 } #define VOLUME_IDENTIFIER { 'v', 'o', 'l', 0 } -typedef MTP_STORAGE_INFO_STRUCT(TU_ARRAY_SIZE((uint16_t[]) STORAGE_DESCRIPTRION), - TU_ARRAY_SIZE(((uint16_t[])VOLUME_IDENTIFIER)) -) storage_info_t; +enum { + STORAGE_DESC_LEN = TU_ARRAY_SIZE((uint16_t[]) STORAGE_DESCRIPTION), + VOLUME_ID_LEN = TU_ARRAY_SIZE((uint16_t[])VOLUME_IDENTIFIER) +}; + +typedef MTP_STORAGE_INFO_STRUCT(STORAGE_DESC_LEN, VOLUME_ID_LEN) storage_info_t; storage_info_t storage_info = { #ifdef CFG_EXAMPLE_MTP_READONLY @@ -60,7 +63,7 @@ storage_info_t storage_info = { .free_space_in_objects = 0, // calculated at runtime .storage_description = { .count = (TU_FIELD_SIZE(storage_info_t, storage_description)-1) / sizeof(uint16_t), - .utf16 = STORAGE_DESCRIPTRION + .utf16 = STORAGE_DESCRIPTION }, .volume_identifier = { .count = (TU_FIELD_SIZE(storage_info_t, volume_identifier)-1) / sizeof(uint16_t), @@ -320,9 +323,9 @@ int32_t tud_mtp_data_complete_cb(tud_mtp_cb_data_t* cb_data) { break; } // parameter is: storage id, parent handle, new handle - mtp_container_add_uint32(resp, SUPPORTED_STORAGE_ID); - mtp_container_add_uint32(resp, f->parent); - mtp_container_add_uint32(resp, send_obj_handle); + (void) mtp_container_add_uint32(resp, SUPPORTED_STORAGE_ID); + (void) mtp_container_add_uint32(resp, f->parent); + (void) mtp_container_add_uint32(resp, send_obj_handle); resp->header->code = MTP_RESP_OK; break; } @@ -346,19 +349,22 @@ int32_t tud_mtp_response_complete_cb(tud_mtp_cb_data_t* cb_data) { //--------------------------------------------------------------------+ static int32_t fs_get_device_info(tud_mtp_cb_data_t* cb_data) { // Device info is already prepared up to playback formats. Application only need to add string fields + int32_t resp_code = 0; mtp_container_info_t* io_container = &cb_data->io_container; - mtp_container_add_cstring(io_container, DEV_INFO_MANUFACTURER); - mtp_container_add_cstring(io_container, DEV_INFO_MODEL); - mtp_container_add_cstring(io_container, DEV_INFO_VERSION); + (void) mtp_container_add_cstring(io_container, DEV_INFO_MANUFACTURER); + (void) mtp_container_add_cstring(io_container, DEV_INFO_MODEL); + (void) mtp_container_add_cstring(io_container, DEV_INFO_VERSION); enum { MAX_SERIAL_NCHARS = 32 }; uint16_t serial_utf16[MAX_SERIAL_NCHARS+1]; size_t nchars = board_usb_get_serial(serial_utf16, MAX_SERIAL_NCHARS); serial_utf16[tu_min32(nchars, MAX_SERIAL_NCHARS)] = 0; // ensure null termination - mtp_container_add_string(io_container, serial_utf16); + (void) mtp_container_add_string(io_container, serial_utf16); - tud_mtp_data_send(io_container); - return 0; + if (!tud_mtp_data_send(io_container)) { + resp_code = MTP_RESP_DEVICE_BUSY; + } + return resp_code; } static int32_t fs_open_close_session(tud_mtp_cb_data_t* cb_data) { @@ -380,7 +386,7 @@ static int32_t fs_open_close_session(tud_mtp_cb_data_t* cb_data) { static int32_t fs_get_storage_ids(tud_mtp_cb_data_t* cb_data) { mtp_container_info_t* io_container = &cb_data->io_container; uint32_t storage_ids [] = { SUPPORTED_STORAGE_ID }; - mtp_container_add_auint32(io_container, 1, storage_ids); + (void) mtp_container_add_auint32(io_container, 1, storage_ids); tud_mtp_data_send(io_container); return 0; } @@ -394,7 +400,7 @@ static int32_t fs_get_storage_info(tud_mtp_cb_data_t* cb_data) { storage_info.max_capacity_in_bytes = sizeof(README_TXT_CONTENT) + LOGO_LEN + FS_MAX_CAPACITY_BYTES; storage_info.free_space_in_objects = FS_MAX_FILE_COUNT - fs_get_file_count(); storage_info.free_space_in_bytes = storage_info.free_space_in_objects ? FS_MAX_CAPACITY_BYTES : 0; - mtp_container_add_raw(io_container, &storage_info, sizeof(storage_info)); + (void) mtp_container_add_raw(io_container, &storage_info, sizeof(storage_info)); tud_mtp_data_send(io_container); return 0; } @@ -408,14 +414,14 @@ static int32_t fs_get_device_properties(tud_mtp_cb_data_t* cb_data) { // get describing dataset mtp_device_prop_desc_header_t device_prop_header; device_prop_header.device_property_code = dev_prop_code; - switch (dev_prop_code) { + switch (dev_prop_code) { //-V2520 //-V2659 case MTP_DEV_PROP_DEVICE_FRIENDLY_NAME: device_prop_header.datatype = MTP_DATA_TYPE_STR; device_prop_header.get_set = MTP_MODE_GET; - mtp_container_add_raw(io_container, &device_prop_header, sizeof(device_prop_header)); - mtp_container_add_cstring(io_container, DEV_PROP_FRIENDLY_NAME); // factory - mtp_container_add_cstring(io_container, DEV_PROP_FRIENDLY_NAME); // current - mtp_container_add_uint8(io_container, 0); // no form + (void) mtp_container_add_raw(io_container, &device_prop_header, sizeof(device_prop_header)); + (void) mtp_container_add_cstring(io_container, DEV_PROP_FRIENDLY_NAME); // factory + (void) mtp_container_add_cstring(io_container, DEV_PROP_FRIENDLY_NAME); // current + (void) mtp_container_add_uint8(io_container, 0); // no form tud_mtp_data_send(io_container); break; @@ -424,9 +430,9 @@ static int32_t fs_get_device_properties(tud_mtp_cb_data_t* cb_data) { } } else { // get value - switch (dev_prop_code) { + switch (dev_prop_code) { //-V2520 //-V2659 case MTP_DEV_PROP_DEVICE_FRIENDLY_NAME: - mtp_container_add_cstring(io_container, DEV_PROP_FRIENDLY_NAME); + (void) mtp_container_add_cstring(io_container, DEV_PROP_FRIENDLY_NAME); tud_mtp_data_send(io_container); break; @@ -446,20 +452,20 @@ static int32_t fs_get_object_handles(tud_mtp_cb_data_t* cb_data) { const uint32_t parent_handle = command->params[2]; // folder handle, 0xFFFFFFFF is root (void)obj_format; - if (storage_id != 0xFFFFFFFF && storage_id != SUPPORTED_STORAGE_ID) { + if (storage_id != 0xFFFFFFFFu && storage_id != SUPPORTED_STORAGE_ID) { return MTP_RESP_INVALID_STORAGE_ID; } uint32_t handles[FS_MAX_FILE_COUNT] = { 0 }; - uint32_t count = 0; - for (uint8_t i = 0; i < FS_MAX_FILE_COUNT; i++) { + uint32_t count = 0u; + for (uint8_t i = 0u; i < FS_MAX_FILE_COUNT; i++) { fs_file_t* f = &fs_objects[i]; if (fs_file_exist(f) && - (parent_handle == f->parent || (parent_handle == 0xFFFFFFFF && f->parent == 0))) { - handles[count++] = i + 1; // handle is index + 1 + (parent_handle == f->parent || (parent_handle == 0xFFFFFFFFu && f->parent == 0u))) { + handles[count++] = (uint32_t) i + 1u; // handle is index + 1 } } - mtp_container_add_auint32(io_container, count, handles); + (void) mtp_container_add_auint32(io_container, count, handles); tud_mtp_data_send(io_container); return 0; @@ -490,11 +496,11 @@ static int32_t fs_get_object_info(tud_mtp_cb_data_t* cb_data) { .association_desc = 0, .sequence_number = 0 }; - mtp_container_add_raw(io_container, &obj_info_header, sizeof(obj_info_header)); - mtp_container_add_string(io_container, f->name); - mtp_container_add_cstring(io_container, FS_FIXED_DATETIME); - mtp_container_add_cstring(io_container, FS_FIXED_DATETIME); - mtp_container_add_cstring(io_container, ""); // keywords, not used + (void) mtp_container_add_raw(io_container, &obj_info_header, sizeof(obj_info_header)); + (void) mtp_container_add_string(io_container, f->name); + (void) mtp_container_add_cstring(io_container, FS_FIXED_DATETIME); + (void) mtp_container_add_cstring(io_container, FS_FIXED_DATETIME); + (void) mtp_container_add_cstring(io_container, ""); // keywords, not used tud_mtp_data_send(io_container); return 0; @@ -512,7 +518,7 @@ static int32_t fs_get_object(tud_mtp_cb_data_t* cb_data) { if (cb_data->phase == MTP_PHASE_COMMAND) { // If file contents is larger than CFG_TUD_MTP_EP_BUFSIZE, data may only partially is added here // the rest will be sent in tud_mtp_data_more_cb - mtp_container_add_raw(io_container, f->data, f->size); + (void) mtp_container_add_raw(io_container, f->data, f->size); tud_mtp_data_send(io_container); } else if (cb_data->phase == MTP_PHASE_DATA) { // continue sending remaining data: file contents offset is xferred byte minus header size @@ -522,6 +528,8 @@ static int32_t fs_get_object(tud_mtp_cb_data_t* cb_data) { memcpy(io_container->payload, f->data + offset, xact_len); tud_mtp_data_send(io_container); } + } else { + // nothing to do } return 0; @@ -537,21 +545,21 @@ static int32_t fs_send_object_info(tud_mtp_cb_data_t* cb_data) { if (!is_session_opened) { return MTP_RESP_SESSION_NOT_OPEN; } - if (storage_id != 0xFFFFFFFF && storage_id != SUPPORTED_STORAGE_ID) { + if (storage_id != 0xFFFFFFFFu && storage_id != SUPPORTED_STORAGE_ID) { return MTP_RESP_INVALID_STORAGE_ID; } if (cb_data->phase == MTP_PHASE_COMMAND) { - tud_mtp_data_receive(io_container); + (void) tud_mtp_data_receive(io_container); } else if (cb_data->phase == MTP_PHASE_DATA) { mtp_object_info_header_t* obj_info = (mtp_object_info_header_t*) io_container->payload; if (obj_info->storage_id != 0 && obj_info->storage_id != SUPPORTED_STORAGE_ID) { return MTP_RESP_INVALID_STORAGE_ID; } - if (obj_info->parent_object) { + if (obj_info->parent_object != 0) { // not root fs_file_t* parent = fs_get_file(obj_info->parent_object); - if (parent == NULL || !parent->association_type) { + if (parent == NULL || 0u == parent->association_type) { return MTP_RESP_INVALID_PARENT_OBJECT; } } @@ -575,8 +583,10 @@ static int32_t fs_send_object_info(tud_mtp_cb_data_t* cb_data) { f->size = obj_info->object_compressed_size; f->data = f_buf; uint8_t* buf = io_container->payload + sizeof(mtp_object_info_header_t); - mtp_container_get_string(buf, f->name); + (void) mtp_container_get_string(buf, f->name); // ignore date created/modified/keywords + } else { + // nothing to do } return 0; diff --git a/hw/bsp/family_support.cmake b/hw/bsp/family_support.cmake index 16c0d48d7..c2e7bf8f2 100644 --- a/hw/bsp/family_support.cmake +++ b/hw/bsp/family_support.cmake @@ -301,10 +301,10 @@ function(family_configure_common TARGET RTOS) COMMAND_EXPAND_LISTS ) # generate C-STAT report -# add_custom_command(TARGET ${TARGET} POST_BUILD -# COMMAND mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/cstat_report -# COMMAND ireport --db=${CMAKE_BINARY_DIR}/cstat.db --full --project ${TARGET} --output ${CMAKE_CURRENT_BINARY_DIR}/cstat_report/index.html -# ) + add_custom_command(TARGET ${TARGET} POST_BUILD + COMMAND mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/cstat_report + COMMAND ireport --db=${CMAKE_BINARY_DIR}/cstat.db --full --project ${TARGET} --output ${CMAKE_CURRENT_BINARY_DIR}/cstat_report/index.html + ) endif () endif () diff --git a/src/class/mtp/mtp.h b/src/class/mtp/mtp.h index 40b6dd8b0..236cf98e0 100644 --- a/src/class/mtp/mtp.h +++ b/src/class/mtp/mtp.h @@ -799,18 +799,18 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_array(mtp_contain TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_string(mtp_container_info_t* p_container, uint16_t* utf16) { uint8_t count = 0; - while (utf16[count]) { + while (utf16[count] != 0u) { count++; } - const uint32_t added_len = 1u + 2u * count; + const uint32_t added_len = 1u + (uint32_t) count * 2u; TU_ASSERT(p_container->header->len + added_len < CFG_TUD_MTP_EP_BUFSIZE, 0); uint8_t* buf = p_container->payload + p_container->header->len - sizeof(mtp_container_header_t); *buf++ = count; p_container->header->len++; - memcpy(buf, utf16, 2 * count); - p_container->header->len += 2 * count; + memcpy(buf, utf16, 2u * (uint32_t) count); + p_container->header->len += 2u * count; return added_len; } @@ -824,7 +824,7 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_cstring(mtp_conta // empty string (null only): single zero byte *buf = 0; p_container->header->len++; - return 1; + return 1u; } else { *buf++ = len; p_container->header->len++; @@ -875,8 +875,8 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_auint32(mtp_conta // //--------------------------------------------------------------------+ TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_get_string(uint8_t* buf, uint16_t utf16[]) { - uint8_t nchars = *buf++; - memcpy(utf16, buf, 2 * nchars); + size_t nchars = *buf++; + memcpy(utf16, buf, 2u * nchars); return 1u + 2u * nchars; } diff --git a/src/class/mtp/mtp_device.h b/src/class/mtp/mtp_device.h index 397fbbbce..a33f1dc08 100644 --- a/src/class/mtp/mtp_device.h +++ b/src/class/mtp/mtp_device.h @@ -53,12 +53,14 @@ typedef struct { typedef struct { uint8_t idx; uint8_t stage; // control stage - uint32_t session_id; - const tusb_control_request_t* request; // buffer for data stage - uint8_t* buf; uint16_t bufsize; + uint8_t* buf; + + const tusb_control_request_t* request; + + uint32_t session_id; } tud_mtp_request_cb_data_t; // Number of supported operations, events, device properties, capture formats, playback formats @@ -78,7 +80,7 @@ typedef struct { /* string fields will be added using append function */ \ } -typedef MTP_DEVICE_INFO_STRUCT( +typedef MTP_DEVICE_INFO_STRUCT( //-V2586 [MISRA-C-18.7] Flexible array members should not be declared sizeof(CFG_TUD_MTP_DEVICEINFO_EXTENSIONS), TU_ARGS_NUM(CFG_TUD_MTP_DEVICEINFO_SUPPORTED_OPERATIONS), TU_ARGS_NUM(CFG_TUD_MTP_DEVICEINFO_SUPPORTED_EVENTS), TU_ARGS_NUM(CFG_TUD_MTP_DEVICEINFO_SUPPORTED_DEVICE_PROPERTIES), TU_ARGS_NUM(CFG_TUD_MTP_DEVICEINFO_CAPTURE_FORMATS), TU_ARGS_NUM(CFG_TUD_MTP_DEVICEINFO_PLAYBACK_FORMATS) diff --git a/src/class/video/video.h b/src/class/video/video.h index f348e187b..5bdf4b840 100644 --- a/src/class/video/video.h +++ b/src/class/video/video.h @@ -219,11 +219,11 @@ typedef enum { uint8_t baInterfaceNr[_nitf]; \ } -typedef tusb_desc_video_control_header_nitf_t() tusb_desc_video_control_header_t; -typedef tusb_desc_video_control_header_nitf_t(1) tusb_desc_video_control_header_1itf_t; -typedef tusb_desc_video_control_header_nitf_t(2) tusb_desc_video_control_header_2itf_t; -typedef tusb_desc_video_control_header_nitf_t(3) tusb_desc_video_control_header_3itf_t; -typedef tusb_desc_video_control_header_nitf_t(4) tusb_desc_video_control_header_4itf_t; +typedef tusb_desc_video_control_header_nitf_t() tusb_desc_video_control_header_t; //-V2586 incorrectly detected as flexible array +typedef tusb_desc_video_control_header_nitf_t(1) tusb_desc_video_control_header_1itf_t; //-V2586 incorrectly detected as flexible array +typedef tusb_desc_video_control_header_nitf_t(2) tusb_desc_video_control_header_2itf_t; //-V2586 incorrectly detected as flexible array +typedef tusb_desc_video_control_header_nitf_t(3) tusb_desc_video_control_header_3itf_t; //-V2586 incorrectly detected as flexible array +typedef tusb_desc_video_control_header_nitf_t(4) tusb_desc_video_control_header_4itf_t; //-V2586 incorrectly detected as flexible array typedef struct TU_ATTR_PACKED { uint8_t bLength; diff --git a/src/common/tusb_common.h b/src/common/tusb_common.h index 5f659eb95..7aa42a2d7 100644 --- a/src/common/tusb_common.h +++ b/src/common/tusb_common.h @@ -236,7 +236,7 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_round_up(uint32_t v, uint32_t f) // TODO use clz TODO remove TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_log2(uint32_t value) { uint8_t result = 0; - while (value >>= 1) { + while ((value >>= 1u) != 0u) { result++; } return result; @@ -355,7 +355,10 @@ TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_desc_subtype(void const* desc) { } TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_desc_in_bounds(uint8_t const* p_desc, uint8_t const* desc_end) { - return (p_desc < desc_end) && (tu_desc_next(p_desc) <= desc_end); + if (p_desc >= desc_end) { + return false; + } + return tu_desc_next(p_desc) <= desc_end; } // find descriptor that match byte1 (type) diff --git a/src/common/tusb_debug.h b/src/common/tusb_debug.h index df4034098..a7bf3e959 100644 --- a/src/common/tusb_debug.h +++ b/src/common/tusb_debug.h @@ -119,7 +119,9 @@ static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint3 // not found return the key value in hex static char not_found[11]; - snprintf(not_found, sizeof(not_found), "0x%08lX", (unsigned long) key); + if (snprintf(not_found, sizeof(not_found), "0x%08lX", (unsigned long) key) <= 0) { + not_found[0] = 0; + } return not_found; } diff --git a/src/device/usbd_control.c b/src/device/usbd_control.c index c9700fd9d..2c2ff76b7 100644 --- a/src/device/usbd_control.c +++ b/src/device/usbd_control.c @@ -93,7 +93,7 @@ static bool data_stage_xact(uint8_t rhport) { if (_ctrl_xfer.request.bmRequestType_bit.direction == TUSB_DIR_IN) { ep_addr = EDPT_CTRL_IN; - if (xact_len) { + if (0u != xact_len) { TU_VERIFY(0 == tu_memcpy_s(_ctrl_epbuf.buf, CFG_TUD_ENDPOINT0_SIZE, _ctrl_xfer.buffer, xact_len)); } } @@ -159,7 +159,7 @@ bool usbd_control_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, // invoke optional dcd hook if available dcd_edpt0_status_complete(rhport, &_ctrl_xfer.request); - if (_ctrl_xfer.complete_cb) { + if (NULL != _ctrl_xfer.complete_cb) { // TODO refactor with usbd_driver_print_control_complete_name _ctrl_xfer.complete_cb(rhport, CONTROL_STAGE_ACK, &_ctrl_xfer.request); } @@ -185,7 +185,7 @@ bool usbd_control_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, // invoke complete callback if set // callback can still stall control in status phase e.g out data does not make sense - if (_ctrl_xfer.complete_cb) { + if (NULL != _ctrl_xfer.complete_cb) { #if CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL usbd_driver_print_control_complete_name(_ctrl_xfer.complete_cb); #endif diff --git a/src/device/usbd_pvt.h b/src/device/usbd_pvt.h index 2894d3023..6e220129a 100644 --- a/src/device/usbd_pvt.h +++ b/src/device/usbd_pvt.h @@ -125,14 +125,9 @@ bool usbd_edpt_ready(uint8_t rhport, uint8_t ep_addr) { // Enable SOF interrupt void usbd_sof_enable(uint8_t rhport, sof_consumer_t consumer, bool en); -/*------------------------------------------------------------------*/ -/* Helper - *------------------------------------------------------------------*/ - bool usbd_open_edpt_pair(uint8_t rhport, uint8_t const* p_desc, uint8_t ep_count, uint8_t xfer_type, uint8_t* ep_out, uint8_t* ep_in); void usbd_defer_func(osal_task_func_t func, void *param, bool in_isr); - #if CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL void usbd_driver_print_control_complete_name(usbd_control_xfer_cb_t callback); #endif diff --git a/src/tusb.c b/src/tusb.c index d52c156ab..be67eead2 100644 --- a/src/tusb.c +++ b/src/tusb.c @@ -599,7 +599,9 @@ void tu_print_mem(void const* buf, uint32_t count, uint8_t indent) { if (remain) { for (uint32_t i = 0; i < 16 - remain; i++) { tu_printf(" "); - for (int j = 0; j < 2 * size; j++) tu_printf(" "); + for (int j = 0; j < 2 * size; j++) { + tu_printf(" "); + } } } -- cgit v1.3.1 From 7f173ab5ed6a80a5fd6780779fe63fb97d2be0e9 Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 8 Nov 2025 15:54:02 +0700 Subject: fix more alerts --- .PVS-Studio/.pvsconfig | 1 + .clang-format | 1 + .github/workflows/static_analysis.yml | 3 +- examples/device/cdc_uac2/src/cdc_app.c | 2 +- examples/device/net_lwip_webserver/src/arch/cc.h | 6 +- examples/host/cdc_msc_hid/src/cdc_app.c | 2 +- src/class/audio/audio_device.c | 35 +- src/class/cdc/cdc_host.c | 81 +++-- src/class/msc/msc_host.c | 5 +- src/common/tusb_debug.h | 16 +- src/common/tusb_fifo.c | 414 ++++++++++------------- src/common/tusb_fifo.h | 25 +- src/common/tusb_private.h | 21 +- src/tusb.c | 38 ++- 14 files changed, 314 insertions(+), 336 deletions(-) (limited to '.github/workflows/static_analysis.yml') diff --git a/.PVS-Studio/.pvsconfig b/.PVS-Studio/.pvsconfig index d8654b077..c9e60c996 100644 --- a/.PVS-Studio/.pvsconfig +++ b/.PVS-Studio/.pvsconfig @@ -10,6 +10,7 @@ //-V::2520 [MISRA-C-16.3] Every switch-clause should be terminated by an unconditional 'break' statement //-V:memcpy:2547 [MISRA-C-17.7] The return value of non-void function 'memcpy' should be used. //-V:memmove:2547 [MISRA-C-17.7] The return value of non-void function 'memmove' should be used. +//-V:printf:2547 [MISRA-C-17.7] //-V::2584::{gintsts} dwc2 //-V::2600 [MISRA-C-21.6] The function with the 'printf' name should not be used. //+V2614 DISABLE_LENGHT_LIMIT_CHECK:YES diff --git a/.clang-format b/.clang-format index c7d769172..907dd7cdd 100644 --- a/.clang-format +++ b/.clang-format @@ -87,5 +87,6 @@ SpacesInAngles: false SpacesInConditionalStatement: false SpacesInCStyleCastParentheses: false SpacesInParentheses: false +SortIncludes: false TabWidth: 2 ... diff --git a/.github/workflows/static_analysis.yml b/.github/workflows/static_analysis.yml index 227f5e103..a89cdc279 100644 --- a/.github/workflows/static_analysis.yml +++ b/.github/workflows/static_analysis.yml @@ -118,13 +118,14 @@ jobs: sudo apt update sudo apt install pvs-studio pvs-studio-analyzer credentials ${{ secrets.PVS_STUDIO_CREDENTIALS }} + pvs-studio-analyzer --version - name: Analyze run: | mkdir -p build cmake examples -B build -G Ninja -DBOARD=${{ matrix.board }} -DCMAKE_BUILD_TYPE=MinSizeRel cmake --build build - pvs-studio-analyzer analyze -R .PVS-Studio/.pvsconfig -f build/compile_commands.json --exclude-path hw/mcu/ --exclude-path lib/ -j + pvs-studio-analyzer analyze -f build/compile_commands.json -R .PVS-Studio/.pvsconfig -j4 --security-related-issues --misra-cpp-version 2008 --misra-c-version 2023 --use-old-parser -e lib/ -e hw/mcu/ -e */iar/cxarm/ -e pico-sdk/ plog-converter -t sarif -o pvs-studio-${{ matrix.board }}.sarif PVS-Studio.log - name: Upload SARIF diff --git a/examples/device/cdc_uac2/src/cdc_app.c b/examples/device/cdc_uac2/src/cdc_app.c index e3ad8a9ac..6d18a0e69 100644 --- a/examples/device/cdc_uac2/src/cdc_app.c +++ b/examples/device/cdc_uac2/src/cdc_app.c @@ -48,7 +48,7 @@ void tud_cdc_rx_cb(uint8_t itf) { // connected() check for DTR bit // Most but not all terminal client set this when making connection if (tud_cdc_connected()) { - if (tud_cdc_available()) { + if (tud_cdc_available() > 0) { count = tud_cdc_n_read(itf, buf, sizeof(buf)); (void) count; diff --git a/examples/device/net_lwip_webserver/src/arch/cc.h b/examples/device/net_lwip_webserver/src/arch/cc.h index 9f30b91cb..c3fc12dda 100644 --- a/examples/device/net_lwip_webserver/src/arch/cc.h +++ b/examples/device/net_lwip_webserver/src/arch/cc.h @@ -29,8 +29,8 @@ * Author: Adam Dunkels * */ -#ifndef __CC_H__ -#define __CC_H__ +#ifndef CC_H__ +#define CC_H__ //#include "cpu.h" @@ -72,4 +72,4 @@ typedef int sys_prot_t; #define LWIP_PLATFORM_ASSERT(x) do { if(!(x)) while(1); } while(0) -#endif /* __CC_H__ */ +#endif /* CC_H__ */ diff --git a/examples/host/cdc_msc_hid/src/cdc_app.c b/examples/host/cdc_msc_hid/src/cdc_app.c index d3daedffc..4c2c5e807 100644 --- a/examples/host/cdc_msc_hid/src/cdc_app.c +++ b/examples/host/cdc_msc_hid/src/cdc_app.c @@ -51,7 +51,7 @@ void cdc_app_task(void) { for (uint8_t idx = 0; idx < CFG_TUH_CDC; idx++) { if (tuh_cdc_mounted(idx)) { // console --> cdc interfaces - if (count) { + if (count > 0) { tuh_cdc_write(idx, buf, count); tuh_cdc_write_flush(idx); } diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index d47d87a69..f074b7d02 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -503,7 +503,7 @@ static bool audiod_rx_xfer_isr(uint8_t rhport, audiod_function_t* audio, uint16_ #if USE_LINEAR_BUFFER_RX // Data currently is in linear buffer, copy into EP OUT FIFO - TU_VERIFY(tu_fifo_write_n(&audio->ep_out_ff, audio->lin_buf_out, n_bytes_received)); + TU_VERIFY(0 < tu_fifo_write_n(&audio->ep_out_ff, audio->lin_buf_out, n_bytes_received)); // Schedule for next receive TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_out, audio->lin_buf_out, audio->ep_out_sz), false); @@ -672,8 +672,12 @@ uint32_t tud_audio_feedback_update(uint8_t func_id, uint32_t cycles) { // The size of isochronous packets created by the device must be within the limits specified in FMT-2.0 section 2.3.1.1. // This means that the deviation of actual packet size from nominal size must not exceed +/- one audio slot // (audio slot = channel count samples). - if (feedback > audio->feedback.max_value) feedback = audio->feedback.max_value; - if (feedback < audio->feedback.min_value) feedback = audio->feedback.min_value; + if (feedback > audio->feedback.max_value) { + feedback = audio->feedback.max_value; + } + if (feedback < audio->feedback.min_value) { + feedback = audio->feedback.min_value; + } tud_audio_n_fb_set(func_id, feedback); @@ -714,7 +718,6 @@ void audiod_init(void) { // Initialize IN EP FIFO if required #if CFG_TUD_AUDIO_ENABLE_EP_IN - switch (i) { #if CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0 case 0: @@ -883,9 +886,11 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint || tu_desc_type(p_desc) == TUSB_DESC_INTERFACE_ASSOCIATION) { break; } else if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const *) p_desc)->bInterfaceSubClass == AUDIO_SUBCLASS_STREAMING) { - if (_audiod_fct[i].p_desc_as == 0) { + if (_audiod_fct[i].p_desc_as == NULL) { _audiod_fct[i].p_desc_as = p_desc; } + } else { + // nothing to do } total_len += p_desc[0]; p_desc = tu_desc_next(p_desc); @@ -957,19 +962,19 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint } #if CFG_TUD_AUDIO_ENABLE_EP_IN - if (ep_in) { + if (ep_in != 0) { usbd_edpt_iso_alloc(rhport, ep_in, ep_in_size); } #endif #if CFG_TUD_AUDIO_ENABLE_EP_OUT - if (ep_out) { + if (ep_out != 0) { usbd_edpt_iso_alloc(rhport, ep_out, ep_out_size); } #endif #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - if (ep_fb) { + if (ep_fb != 0) { usbd_edpt_iso_alloc(rhport, ep_fb, 4); } #endif @@ -998,6 +1003,8 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint if (tu_unaligned_read16(p_desc + 4) == AUDIO_TERM_TYPE_USB_STREAMING) { _audiod_fct[i].bclock_id_tx = p_desc[8]; } + } else { + // nothing to do } p_desc = tu_desc_next(p_desc); } @@ -1458,6 +1465,8 @@ bool audiod_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_ return audiod_control_request(rhport, request); } else if (stage == CONTROL_STAGE_DATA) { return audiod_control_complete(rhport, request); + } else { + // nothing to do } return true; @@ -1633,8 +1642,12 @@ static void audiod_fb_fifo_count_update(audiod_function_t *audio, uint16_t lvl_n feedback = audio->feedback.compute.fifo_count.nom_value - (ff_lvl - ff_thr) * rate[1]; } - if (feedback > audio->feedback.max_value) feedback = audio->feedback.max_value; - if (feedback < audio->feedback.min_value) feedback = audio->feedback.min_value; + if (feedback > audio->feedback.max_value) { + feedback = audio->feedback.max_value; + } + if (feedback < audio->feedback.min_value) { + feedback = audio->feedback.min_value; + } audio->feedback.value = feedback; } @@ -1754,7 +1767,7 @@ static bool audiod_verify_entity_exists(uint8_t itf, uint8_t entityID, uint8_t * static bool audiod_verify_itf_exists(uint8_t itf, uint8_t *func_id) { uint8_t i; for (i = 0; i < CFG_TUD_AUDIO; i++) { - if (_audiod_fct[i].p_desc) { + if (_audiod_fct[i].p_desc != NULL) { // Get pointer at beginning and end uint8_t const *p_desc = _audiod_fct[i].p_desc; uint8_t const *p_desc_end = _audiod_fct[i].p_desc + _audiod_fct[i].desc_length; diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 3fc6a9adf..7fdf0a7b9 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -602,7 +602,7 @@ bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const *line_coding, p_cdc->requested_line.coding = *line_coding; p_cdc->user_complete_cb = complete_cb; - if (driver->set_line_coding) { + if (driver->set_line_coding != NULL) { // driver support set_line_coding request TU_VERIFY(driver->set_line_coding(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); @@ -611,7 +611,7 @@ bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const *line_coding, } } else { // driver does not support set_line_coding and need 2 stage to set baudrate and data format separately - if (complete_cb) { + if (complete_cb != NULL) { // non-blocking TU_VERIFY(driver->set_baudrate(p_cdc, cdch_set_line_coding_stage1_baudrate_complete, user_data)); } else { @@ -619,7 +619,7 @@ bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const *line_coding, xfer_result_t result = XFER_RESULT_INVALID; TU_VERIFY(driver->set_baudrate(p_cdc, NULL, (uintptr_t) &result)); - if (user_data) { + if (user_data != 0) { *((xfer_result_t *) user_data) = result; } TU_VERIFY(result == XFER_RESULT_SUCCESS); @@ -627,7 +627,7 @@ bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const *line_coding, result = XFER_RESULT_INVALID; TU_VERIFY(driver->set_data_format(p_cdc, NULL, (uintptr_t) &result)); - if (user_data) { + if (user_data != 0) { *((xfer_result_t *) user_data) = result; } TU_VERIFY(result == XFER_RESULT_SUCCESS); @@ -777,6 +777,8 @@ bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *itf_d } } } + } else { + // not supported class } return false; @@ -894,7 +896,7 @@ static void cdch_internal_control_complete(tuh_xfer_t *xfer) { // Invoke application callback xfer->complete_cb = p_cdc->user_complete_cb; - if (xfer->complete_cb) { + if (xfer->complete_cb != NULL) { xfer->complete_cb(xfer); } } @@ -910,7 +912,7 @@ static void cdch_set_line_coding_stage1_baudrate_complete(tuh_xfer_t *xfer) { TU_ASSERT(driver->set_data_format(p_cdc, cdch_set_line_coding_stage2_data_format_complete, xfer->user_data),); } else { xfer->complete_cb = p_cdc->user_complete_cb; - if (xfer->complete_cb) { + if (xfer->complete_cb != NULL) { xfer->complete_cb(xfer); } } @@ -926,7 +928,7 @@ static void cdch_set_line_coding_stage2_data_format_complete(tuh_xfer_t *xfer) { } xfer->complete_cb = p_cdc->user_complete_cb; - if (xfer->complete_cb) { + if (xfer->complete_cb != NULL) { xfer->complete_cb(xfer); } } @@ -950,12 +952,12 @@ static void acm_internal_control_complete(cdch_interface_t *p_cdc, tuh_xfer_t *x break; default: - break; + break; // unknown request } } static bool acm_set_control_line_state(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - TU_VERIFY(p_cdc->acm.capability.support_line_request); + TU_VERIFY(p_cdc->acm.capability.support_line_request != 0); const tusb_control_request_t request = { .bmRequestType_bit = { @@ -982,7 +984,7 @@ static bool acm_set_control_line_state(cdch_interface_t *p_cdc, tuh_xfer_cb_t co } static bool acm_set_line_coding(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - TU_VERIFY(p_cdc->acm.capability.support_line_request); + TU_VERIFY(p_cdc->acm.capability.support_line_request != 0); TU_VERIFY((p_cdc->requested_line.coding.data_bits >= 5 && p_cdc->requested_line.coding.data_bits <= 8) || p_cdc->requested_line.coding.data_bits == 16); @@ -1167,10 +1169,10 @@ static bool ftdi_set_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete static bool ftdi_set_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { uint32_t index_value = ftdi_get_divisor(p_cdc); - TU_VERIFY(index_value); + TU_VERIFY(index_value != 0); uint16_t value = (uint16_t) index_value; uint16_t index = (uint16_t) (index_value >> 16); - if (p_cdc->ftdi.channel) { + if (p_cdc->ftdi.channel != 0) { index = (uint16_t) ((index << 8) | p_cdc->ftdi.channel); } @@ -1372,6 +1374,8 @@ static uint32_t ftdi_232bm_baud_base_to_divisor(uint32_t baud, uint32_t base) { divisor = 0; } else if (divisor == 0x4001) /* 1.5 */ { divisor = 1; + } else { + // nothing to do } return divisor; } @@ -1395,12 +1399,13 @@ static uint32_t ftdi_2232h_baud_base_to_divisor(uint32_t baud, uint32_t base) { divisor = 0; } else if (divisor == 0x4001) /* 1.5 */ { divisor = 1; + } else { + // nothing to do } - /* - * Set this bit to turn off a divide by 2.5 on baud rate generator + + /* Set this bit to turn off a divide by 2.5 on baud rate generator * This enables baud rates up to 12Mbaud but cannot reach below 1200 - * baud with this bit set - */ + * baud with this bit set */ divisor |= 0x00020000; return divisor; } @@ -1412,7 +1417,7 @@ static inline uint32_t ftdi_2232h_baud_to_divisor(uint32_t baud) { static inline uint32_t ftdi_get_divisor(cdch_interface_t *p_cdc) { uint32_t baud = p_cdc->requested_line.coding.bit_rate; uint32_t div_value = 0; - TU_VERIFY(baud); + TU_VERIFY(baud != 0); switch (p_cdc->ftdi.chip_type) { case FTDI_UNKNOWN: @@ -1552,7 +1557,8 @@ static void cp210x_internal_control_complete(cdch_interface_t *p_cdc, tuh_xfer_t p_cdc->line.coding.bit_rate = p_cdc->requested_line.coding.bit_rate; break; - default: break; + default: + break; // unsupported request } } @@ -1713,7 +1719,8 @@ static void ch34x_internal_control_complete(cdch_interface_t *p_cdc, tuh_xfer_t p_cdc->line.coding.data_bits = p_cdc->requested_line.coding.data_bits; break; - default: break; + default: + break; // unsupported } break; @@ -1721,19 +1728,20 @@ static void ch34x_internal_control_complete(cdch_interface_t *p_cdc, tuh_xfer_t p_cdc->line.control_state = p_cdc->requested_line.control_state; break; - default: break; + default: + break; // unsupported request } } static bool ch34x_set_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { const uint8_t lcr = ch34x_get_lcr(p_cdc); - TU_VERIFY(lcr); + TU_VERIFY(lcr > 0); return ch34x_write_reg(p_cdc, CH32X_REG16_LCR2_LCR, lcr, complete_cb, user_data); } static bool ch34x_set_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { const uint16_t div_ps = ch34x_get_divisor_prescaler(p_cdc); - TU_VERIFY(div_ps); + TU_VERIFY(div_ps > 0); return ch34x_write_reg(p_cdc, CH34X_REG16_DIVISOR_PRESCALER, div_ps, complete_cb, user_data); } @@ -1916,7 +1924,8 @@ static uint8_t ch34x_get_lcr(cdch_interface_t *p_cdc) { lcr |= CH34X_LCR_ENABLE_PAR | CH34X_LCR_MARK_SPACE | CH34X_LCR_PAR_EVEN; break; - default: break; + default: + break; // invalid parity } // 1.5 stop bits not supported @@ -1999,13 +2008,15 @@ static inline bool pl2303_supports_hx_status(cdch_interface_t *p_cdc, tuh_xfer_c // return pl2303_set_request(p_cdc, PL2303_BREAK_REQUEST, PL2303_BREAK_REQUEST_TYPE, state, 0, NULL, 0); //} -static inline int pl2303_clear_halt(cdch_interface_t *p_cdc, uint8_t endp, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static inline bool +pl2303_clear_halt(cdch_interface_t *p_cdc, uint8_t endp, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { /* we don't care if it wasn't halted first. in fact some devices * (like some ibmcam model 1 units) seem to expect hosts to make * this request for iso endpoints, which can't halt! */ - return pl2303_set_request(p_cdc, TUSB_REQ_CLEAR_FEATURE, PL2303_CLEAR_HALT_REQUEST_TYPE, TUSB_REQ_FEATURE_EDPT_HALT, endp, - NULL, 0, complete_cb, user_data); + return pl2303_set_request( + p_cdc, TUSB_REQ_CLEAR_FEATURE, PL2303_CLEAR_HALT_REQUEST_TYPE, TUSB_REQ_FEATURE_EDPT_HALT, endp, NULL, 0, + complete_cb, user_data); } //------------- Driver API -------------// @@ -2130,10 +2141,9 @@ static bool pl2303_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) if (type == PL2303_TYPE_NEED_SUPPORTS_HX_STATUS) { TU_ASSERT(pl2303_supports_hx_status(p_cdc, cdch_process_set_config, CONFIG_PL2303_READ1)); break; - } else { - // no transfer triggered and continue with CONFIG_PL2303_READ1 - TU_ATTR_FALLTHROUGH; } + // no transfer triggered and continue with CONFIG_PL2303_READ1 + TU_ATTR_FALLTHROUGH; case CONFIG_PL2303_READ1: // get supports_hx_status, type and quirks (step 2), do special read @@ -2378,10 +2388,12 @@ static pl2303_type_t pl2303_detect_type(cdch_interface_t *p_cdc, uint8_t step) { return PL2303_TYPE_HXN; default: - break; + break; // unknown device } break; - default: break; + + default: + break; // unknown device } TU_LOG_CDC(p_cdc, "unknown device type bcdUSB = 0x%04x", desc_dev.bcdUSB); @@ -2443,8 +2455,9 @@ static uint32_t pl2303_encode_baud_rate_divisor(uint8_t buf[PL2303_LINE_CODING_B */ baseline = 12000000 * 32; mantissa = baseline / baud; - if (mantissa == 0) + if (mantissa == 0) { mantissa = 1; /* Avoid dividing by zero if baud > 32 * 12M. */ + } exponent = 0; while (mantissa >= 512) { if (exponent < 7) { @@ -2516,7 +2529,7 @@ static bool pl2303_encode_baud_rate(cdch_interface_t *p_cdc, uint8_t buf[PL2303_ * Use direct method for supported baud rates, otherwise use divisors. * Newer chip types do not support divisor encoding. */ - if (type_data->no_divisors) { + if (type_data->no_divisors != 0) { baud_sup = baud; } else { baud_sup = pl2303_get_supported_baud_rate(baud); @@ -2524,7 +2537,7 @@ static bool pl2303_encode_baud_rate(cdch_interface_t *p_cdc, uint8_t buf[PL2303_ if (baud == baud_sup) { baud = pl2303_encode_baud_rate_direct(buf, baud); - } else if (type_data->alt_divisors) { + } else if (type_data->alt_divisors != 0) { baud = pl2303_encode_baud_rate_divisor_alt(buf, baud); } else { baud = pl2303_encode_baud_rate_divisor(buf, baud); diff --git a/src/class/msc/msc_host.c b/src/class/msc/msc_host.c index ce2884f2e..daff345c5 100644 --- a/src/class/msc/msc_host.c +++ b/src/class/msc/msc_host.c @@ -123,7 +123,10 @@ bool tuh_msc_mounted(uint8_t dev_addr) { bool tuh_msc_ready(uint8_t dev_addr) { msch_interface_t* p_msc = get_itf(dev_addr); - return p_msc->mounted && !usbh_edpt_busy(dev_addr, p_msc->ep_in) && !usbh_edpt_busy(dev_addr, p_msc->ep_out); + TU_VERIFY(p_msc->mounted); + const bool epin_busy = usbh_edpt_busy(dev_addr, p_msc->ep_in); + const bool epout_busy = usbh_edpt_busy(dev_addr, p_msc->ep_out); + return !epin_busy && !epout_busy; } //--------------------------------------------------------------------+ diff --git a/src/common/tusb_debug.h b/src/common/tusb_debug.h index 08117283f..e0e09f5ce 100644 --- a/src/common/tusb_debug.h +++ b/src/common/tusb_debug.h @@ -56,14 +56,14 @@ void tu_print_mem(void const *buf, uint32_t count, uint8_t indent); #define tu_printf CFG_TUSB_DEBUG_PRINTF #else #include - #define tu_printf printf + #define tu_printf(...) (void) printf(__VA_ARGS__) #endif TU_ATTR_ALWAYS_INLINE static inline void tu_print_buf(uint8_t const* buf, uint32_t bufsize) { for(uint32_t i=0; i= 2 diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c index 3b8920c01..419046b8b 100644 --- a/src/common/tusb_fifo.c +++ b/src/common/tusb_fifo.c @@ -28,7 +28,7 @@ #include "osal/osal.h" #include "tusb_fifo.h" -#define TU_FIFO_DBG 0 +#define TU_FIFO_DBG 0 // Suppress IAR warning // Warning[Pa082]: undefined behavior: the order of volatile accesses is undefined in this statement @@ -39,13 +39,13 @@ #if OSAL_MUTEX_REQUIRED TU_ATTR_ALWAYS_INLINE static inline void _ff_lock(osal_mutex_t mutex) { - if (mutex) { + if (mutex != NULL) { osal_mutex_lock(mutex, OSAL_TIMEOUT_WAIT_FOREVER); } } TU_ATTR_ALWAYS_INLINE static inline void _ff_unlock(osal_mutex_t mutex) { - if (mutex) { + if (mutex != NULL) { osal_mutex_unlock(mutex); } } @@ -62,14 +62,13 @@ TU_ATTR_ALWAYS_INLINE static inline void _ff_unlock(osal_mutex_t mutex) { * copy data to and from USB hardware FIFOs as needed for e.g. STM32s and others */ typedef enum { - TU_FIFO_COPY_INC, ///< Copy from/to an increasing source/destination address - default mode + TU_FIFO_COPY_INC, ///< Copy from/to an increasing source/destination address - default mode #ifdef TUP_MEM_CONST_ADDR TU_FIFO_COPY_CST_FULL_WORDS, ///< Copy from/to a constant source/destination address - required for e.g. STM32 to write into USB hardware FIFO #endif } tu_fifo_copy_mode_t; -bool tu_fifo_config(tu_fifo_t *f, void* buffer, uint16_t depth, uint16_t item_size, bool overwritable) -{ +bool tu_fifo_config(tu_fifo_t *f, void *buffer, uint16_t depth, uint16_t item_size, bool overwritable) { // Limit index space to 2*depth - this allows for a fast "modulo" calculation // but limits the maximum depth to 2^16/2 = 2^15 and buffer overflows are detectable // only if overflow happens once (important for unsupervised DMA applications) @@ -80,9 +79,9 @@ bool tu_fifo_config(tu_fifo_t *f, void* buffer, uint16_t depth, uint16_t item_si _ff_lock(f->mutex_wr); _ff_lock(f->mutex_rd); - f->buffer = (uint8_t*) buffer; + f->buffer = (uint8_t *)buffer; f->depth = depth; - f->item_size = (uint16_t) (item_size & 0x7FFF); + f->item_size = (uint16_t)(item_size & 0x7FFF); f->overwritable = overwritable; f->rd_idx = 0; f->wr_idx = 0; @@ -101,18 +100,18 @@ bool tu_fifo_config(tu_fifo_t *f, void* buffer, uint16_t depth, uint16_t item_si // Intended to be used to read from hardware USB FIFO in e.g. STM32 where all data is read from a constant address // Code adapted from dcd_synopsys.c // TODO generalize with configurable 1 byte or 4 byte each read -static void _ff_push_const_addr(uint8_t * ff_buf, const void * app_buf, uint16_t len) { - volatile const uint32_t * reg_rx = (volatile const uint32_t *) app_buf; +static void _ff_push_const_addr(uint8_t *ff_buf, const void *app_buf, uint16_t len) { + const volatile uint32_t *reg_rx = (volatile const uint32_t *)app_buf; // Reading full available 32 bit words from const app address uint16_t full_words = len >> 2; - while(full_words--) { + while (full_words--) { tu_unaligned_write32(ff_buf, *reg_rx); ff_buf += 4; } // Read the remaining 1-3 bytes from const app address - uint8_t const bytes_rem = len & 0x03; + const uint8_t bytes_rem = len & 0x03; if (bytes_rem) { uint32_t tmp32 = *reg_rx; memcpy(ff_buf, &tmp32, bytes_rem); @@ -121,18 +120,18 @@ static void _ff_push_const_addr(uint8_t * ff_buf, const void * app_buf, uint16_t // Intended to be used to write to hardware USB FIFO in e.g. STM32 // where all data is written to a constant address in full word copies -static void _ff_pull_const_addr(void * app_buf, const uint8_t * ff_buf, uint16_t len) { - volatile uint32_t * reg_tx = (volatile uint32_t *) app_buf; +static void _ff_pull_const_addr(void *app_buf, const uint8_t *ff_buf, uint16_t len) { + volatile uint32_t *reg_tx = (volatile uint32_t *)app_buf; // Write full available 32 bit words to const address uint16_t full_words = len >> 2; - while(full_words--) { + while (full_words--) { *reg_tx = tu_unaligned_read32(ff_buf); ff_buf += 4; } // Write the remaining 1-3 bytes into const address - uint8_t const bytes_rem = len & 0x03; + const uint8_t bytes_rem = len & 0x03; if (bytes_rem) { uint32_t tmp32 = 0; memcpy(&tmp32, ff_buf, bytes_rem); @@ -143,32 +142,27 @@ static void _ff_pull_const_addr(void * app_buf, const uint8_t * ff_buf, uint16_t #endif // send one item to fifo WITHOUT updating write pointer -static inline void _ff_push(tu_fifo_t* f, void const * app_buf, uint16_t rel) { +static inline void _ff_push(tu_fifo_t *f, const void *app_buf, uint16_t rel) { memcpy(f->buffer + (rel * f->item_size), app_buf, f->item_size); } // send n items to fifo WITHOUT updating write pointer -static void _ff_push_n(tu_fifo_t* f, void const * app_buf, uint16_t n, uint16_t wr_ptr, tu_fifo_copy_mode_t copy_mode) -{ - uint16_t const lin_count = f->depth - wr_ptr; - uint16_t const wrap_count = n - lin_count; +static void _ff_push_n(tu_fifo_t *f, const void *app_buf, uint16_t n, uint16_t wr_ptr, tu_fifo_copy_mode_t copy_mode) { + const uint16_t lin_count = f->depth - wr_ptr; + const uint16_t wrap_count = n - lin_count; - uint16_t lin_bytes = lin_count * f->item_size; + uint16_t lin_bytes = lin_count * f->item_size; uint16_t wrap_bytes = wrap_count * f->item_size; // current buffer of fifo - uint8_t* ff_buf = f->buffer + (wr_ptr * f->item_size); + uint8_t *ff_buf = f->buffer + (wr_ptr * f->item_size); - switch (copy_mode) - { + switch (copy_mode) { case TU_FIFO_COPY_INC: - if(n <= lin_count) - { + if (n <= lin_count) { // Linear only - memcpy(ff_buf, app_buf, n*f->item_size); - } - else - { + memcpy(ff_buf, app_buf, n * f->item_size); + } else { // Wrap around // Write data to linear part of buffer @@ -176,19 +170,17 @@ static void _ff_push_n(tu_fifo_t* f, void const * app_buf, uint16_t n, uint16_t // Write data wrapped around // TU_ASSERT(nWrap_bytes <= f->depth, ); - memcpy(f->buffer, ((uint8_t const*) app_buf) + lin_bytes, wrap_bytes); + memcpy(f->buffer, ((const uint8_t *)app_buf) + lin_bytes, wrap_bytes); } break; + #ifdef TUP_MEM_CONST_ADDR case TU_FIFO_COPY_CST_FULL_WORDS: // Intended for hardware buffers from which it can be read word by word only - if(n <= lin_count) - { + if (n <= lin_count) { // Linear only - _ff_push_const_addr(ff_buf, app_buf, n*f->item_size); - } - else - { + _ff_push_const_addr(ff_buf, app_buf, n * f->item_size); + } else { // Wrap around case // Write full words to linear part of buffer @@ -198,83 +190,80 @@ static void _ff_push_n(tu_fifo_t* f, void const * app_buf, uint16_t n, uint16_t // There could be odd 1-3 bytes before the wrap-around boundary uint8_t rem = lin_bytes & 0x03; - if (rem > 0) - { - volatile const uint32_t * rx_fifo = (volatile const uint32_t *) app_buf; + if (rem > 0) { + const volatile uint32_t *rx_fifo = (volatile const uint32_t *)app_buf; - uint8_t remrem = (uint8_t) tu_min16(wrap_bytes, 4-rem); + uint8_t remrem = (uint8_t)tu_min16(wrap_bytes, 4 - rem); wrap_bytes -= remrem; - uint32_t tmp32 = *rx_fifo; - uint8_t * src_u8 = ((uint8_t *) &tmp32); + uint32_t tmp32 = *rx_fifo; + uint8_t *src_u8 = ((uint8_t *)&tmp32); // Write 1-3 bytes before wrapped boundary - while(rem--) *ff_buf++ = *src_u8++; + while (rem--) { + *ff_buf++ = *src_u8++; + } // Read more bytes to beginning to complete a word ff_buf = f->buffer; - while(remrem--) *ff_buf++ = *src_u8++; - } - else - { + while (remrem--) { + *ff_buf++ = *src_u8++; + } + } else { ff_buf = f->buffer; // wrap around to beginning } // Write data wrapped part - if (wrap_bytes > 0) _ff_push_const_addr(ff_buf, app_buf, wrap_bytes); + if (wrap_bytes > 0) { + _ff_push_const_addr(ff_buf, app_buf, wrap_bytes); + } } break; #endif - default: break; + + default: + break; // unknown mode } } // get one item from fifo WITHOUT updating read pointer -static inline void _ff_pull(tu_fifo_t* f, void * app_buf, uint16_t rel) -{ +static inline void _ff_pull(tu_fifo_t *f, void *app_buf, uint16_t rel) { memcpy(app_buf, f->buffer + (rel * f->item_size), f->item_size); } // get n items from fifo WITHOUT updating read pointer -static void _ff_pull_n(tu_fifo_t* f, void* app_buf, uint16_t n, uint16_t rd_ptr, tu_fifo_copy_mode_t copy_mode) -{ - uint16_t const lin_count = f->depth - rd_ptr; - uint16_t const wrap_count = n - lin_count; // only used if wrapped +static void _ff_pull_n(tu_fifo_t *f, void *app_buf, uint16_t n, uint16_t rd_ptr, tu_fifo_copy_mode_t copy_mode) { + const uint16_t lin_count = f->depth - rd_ptr; + const uint16_t wrap_count = n - lin_count; // only used if wrapped - uint16_t lin_bytes = lin_count * f->item_size; + uint16_t lin_bytes = lin_count * f->item_size; uint16_t wrap_bytes = wrap_count * f->item_size; // current buffer of fifo - uint8_t* ff_buf = f->buffer + (rd_ptr * f->item_size); + uint8_t *ff_buf = f->buffer + (rd_ptr * f->item_size); - switch (copy_mode) - { + switch (copy_mode) { case TU_FIFO_COPY_INC: - if ( n <= lin_count ) - { + if (n <= lin_count) { // Linear only - memcpy(app_buf, ff_buf, n*f->item_size); - } - else - { + memcpy(app_buf, ff_buf, n * f->item_size); + } else { // Wrap around // Read data from linear part of buffer memcpy(app_buf, ff_buf, lin_bytes); // Read data wrapped part - memcpy((uint8_t*) app_buf + lin_bytes, f->buffer, wrap_bytes); + memcpy((uint8_t *)app_buf + lin_bytes, f->buffer, wrap_bytes); } - break; + break; + #ifdef TUP_MEM_CONST_ADDR case TU_FIFO_COPY_CST_FULL_WORDS: - if ( n <= lin_count ) - { + if (n <= lin_count) { // Linear only - _ff_pull_const_addr(app_buf, ff_buf, n*f->item_size); - } - else - { + _ff_pull_const_addr(app_buf, ff_buf, n * f->item_size); + } else { // Wrap around case // Read full words from linear part of buffer @@ -284,36 +273,41 @@ static void _ff_pull_n(tu_fifo_t* f, void* app_buf, uint16_t n, uint16_t rd_ptr, // There could be odd 1-3 bytes before the wrap-around boundary uint8_t rem = lin_bytes & 0x03; - if (rem > 0) - { - volatile uint32_t * reg_tx = (volatile uint32_t *) app_buf; + if (rem > 0) { + volatile uint32_t *reg_tx = (volatile uint32_t *)app_buf; - uint8_t remrem = (uint8_t) tu_min16(wrap_bytes, 4-rem); + uint8_t remrem = (uint8_t)tu_min16(wrap_bytes, 4 - rem); wrap_bytes -= remrem; - uint32_t tmp32=0; - uint8_t * dst_u8 = (uint8_t *)&tmp32; + uint32_t tmp32 = 0; + uint8_t *dst_u8 = (uint8_t *)&tmp32; // Read 1-3 bytes before wrapped boundary - while(rem--) *dst_u8++ = *ff_buf++; + while (rem--) { + *dst_u8++ = *ff_buf++; + } // Read more bytes from beginning to complete a word ff_buf = f->buffer; - while(remrem--) *dst_u8++ = *ff_buf++; + while (remrem--) { + *dst_u8++ = *ff_buf++; + } *reg_tx = tmp32; - } - else - { + } else { ff_buf = f->buffer; // wrap around to beginning } // Read data wrapped part - if (wrap_bytes > 0) _ff_pull_const_addr(app_buf, ff_buf, wrap_bytes); + if (wrap_bytes > 0) { + _ff_pull_const_addr(app_buf, ff_buf, wrap_bytes); + } } - break; + break; #endif - default: break; + + default: + break; // unknown mode } } @@ -322,24 +316,18 @@ static void _ff_pull_n(tu_fifo_t* f, void* app_buf, uint16_t n, uint16_t rd_ptr, //--------------------------------------------------------------------+ // return only the index difference and as such can be used to determine an overflow i.e overflowable count -TU_ATTR_ALWAYS_INLINE static inline -uint16_t _ff_count(uint16_t depth, uint16_t wr_idx, uint16_t rd_idx) -{ +TU_ATTR_ALWAYS_INLINE static inline uint16_t _ff_count(uint16_t depth, uint16_t wr_idx, uint16_t rd_idx) { // In case we have non-power of two depth we need a further modification - if (wr_idx >= rd_idx) - { - return (uint16_t) (wr_idx - rd_idx); - } else - { - return (uint16_t) (2*depth - (rd_idx - wr_idx)); + if (wr_idx >= rd_idx) { + return (uint16_t)(wr_idx - rd_idx); + } else { + return (uint16_t)(2 * depth - (rd_idx - wr_idx)); } } // return remaining slot in fifo -TU_ATTR_ALWAYS_INLINE static inline -uint16_t _ff_remaining(uint16_t depth, uint16_t wr_idx, uint16_t rd_idx) -{ - uint16_t const count = _ff_count(depth, wr_idx, rd_idx); +TU_ATTR_ALWAYS_INLINE static inline uint16_t _ff_remaining(uint16_t depth, uint16_t wr_idx, uint16_t rd_idx) { + const uint16_t count = _ff_count(depth, wr_idx, rd_idx); return (depth > count) ? (depth - count) : 0; } @@ -349,16 +337,14 @@ uint16_t _ff_remaining(uint16_t depth, uint16_t wr_idx, uint16_t rd_idx) // Advance an absolute index // "absolute" index is only in the range of [0..2*depth) -static uint16_t advance_index(uint16_t depth, uint16_t idx, uint16_t offset) -{ +static uint16_t advance_index(uint16_t depth, uint16_t idx, uint16_t offset) { // We limit the index space of p such that a correct wrap around happens // Check for a wrap around or if we are in unused index space - This has to be checked first!! // We are exploiting the wrap around to the correct index - uint16_t new_idx = (uint16_t) (idx + offset); - if ( (idx > new_idx) || (new_idx >= 2*depth) ) - { - uint16_t const non_used_index_space = (uint16_t) (UINT16_MAX - (2*depth-1)); - new_idx = (uint16_t) (new_idx + non_used_index_space); + uint16_t new_idx = (uint16_t)(idx + offset); + if ((idx > new_idx) || (new_idx >= 2 * depth)) { + const uint16_t non_used_index_space = (uint16_t)(UINT16_MAX - (2 * depth - 1)); + new_idx = (uint16_t)(new_idx + non_used_index_space); } return new_idx; @@ -366,14 +352,12 @@ static uint16_t advance_index(uint16_t depth, uint16_t idx, uint16_t offset) #if 0 // not used but // Backward an absolute index -static uint16_t backward_index(uint16_t depth, uint16_t idx, uint16_t offset) -{ +static uint16_t backward_index(uint16_t depth, uint16_t idx, uint16_t offset) { // We limit the index space of p such that a correct wrap around happens // Check for a wrap around or if we are in unused index space - This has to be checked first!! // We are exploiting the wrap around to the correct index uint16_t new_idx = (uint16_t) (idx - offset); - if ( (idx < new_idx) || (new_idx >= 2*depth) ) - { + if ( (idx < new_idx) || (new_idx >= 2*depth) ) { uint16_t const non_used_index_space = (uint16_t) (UINT16_MAX - (2*depth-1)); new_idx = (uint16_t) (new_idx - non_used_index_space); } @@ -383,26 +367,22 @@ static uint16_t backward_index(uint16_t depth, uint16_t idx, uint16_t offset) #endif // index to pointer, simply an modulo with minus. -TU_ATTR_ALWAYS_INLINE static inline -uint16_t idx2ptr(uint16_t depth, uint16_t idx) -{ +TU_ATTR_ALWAYS_INLINE static inline uint16_t idx2ptr(uint16_t depth, uint16_t idx) { // Only run at most 3 times since index is limit in the range of [0..2*depth) - while ( idx >= depth ) idx -= depth; + while (idx >= depth) { + idx -= depth; + } return idx; } // Works on local copies of w // When an overwritable fifo is overflowed, rd_idx will be re-index so that it forms // an full fifo i.e _ff_count() = depth -TU_ATTR_ALWAYS_INLINE static inline -uint16_t _ff_correct_read_index(tu_fifo_t* f, uint16_t wr_idx) -{ +TU_ATTR_ALWAYS_INLINE static inline uint16_t _ff_correct_read_index(tu_fifo_t *f, uint16_t wr_idx) { uint16_t rd_idx; - if ( wr_idx >= f->depth ) - { + if (wr_idx >= f->depth) { rd_idx = wr_idx - f->depth; - }else - { + } else { rd_idx = wr_idx + f->depth; } @@ -413,16 +393,16 @@ uint16_t _ff_correct_read_index(tu_fifo_t* f, uint16_t wr_idx) // Works on local copies of w and r // Must be protected by mutexes since in case of an overflow read pointer gets modified -static bool _tu_fifo_peek(tu_fifo_t* f, void * p_buffer, uint16_t wr_idx, uint16_t rd_idx) -{ +static bool _tu_fifo_peek(tu_fifo_t *f, void *p_buffer, uint16_t wr_idx, uint16_t rd_idx) { uint16_t cnt = _ff_count(f->depth, wr_idx, rd_idx); // nothing to peek - if ( cnt == 0 ) return false; + if (cnt == 0) { + return false; + } // Check overflow and correct if required - if ( cnt > f->depth ) - { + if (cnt > f->depth) { rd_idx = _ff_correct_read_index(f, wr_idx); } @@ -436,22 +416,25 @@ static bool _tu_fifo_peek(tu_fifo_t* f, void * p_buffer, uint16_t wr_idx, uint16 // Works on local copies of w and r // Must be protected by mutexes since in case of an overflow read pointer gets modified -static uint16_t _tu_fifo_peek_n(tu_fifo_t* f, void * p_buffer, uint16_t n, uint16_t wr_idx, uint16_t rd_idx, tu_fifo_copy_mode_t copy_mode) -{ +static uint16_t _tu_fifo_peek_n( + tu_fifo_t *f, void *p_buffer, uint16_t n, uint16_t wr_idx, uint16_t rd_idx, tu_fifo_copy_mode_t copy_mode) { uint16_t cnt = _ff_count(f->depth, wr_idx, rd_idx); // nothing to peek - if ( cnt == 0 ) return 0; + if (cnt == 0) { + return 0; + } // Check overflow and correct if required - if ( cnt > f->depth ) - { + if (cnt > f->depth) { rd_idx = _ff_correct_read_index(f, wr_idx); - cnt = f->depth; + cnt = f->depth; } // Check if we can read something at and after offset - if too less is available we read what remains - if ( cnt < n ) n = cnt; + if (cnt < n) { + n = cnt; + } uint16_t rd_ptr = idx2ptr(f->depth, rd_idx); @@ -461,40 +444,36 @@ static uint16_t _tu_fifo_peek_n(tu_fifo_t* f, void * p_buffer, uint16_t n, uint1 return n; } -static uint16_t _tu_fifo_write_n(tu_fifo_t* f, const void * data, uint16_t n, tu_fifo_copy_mode_t copy_mode) -{ - if ( n == 0 ) return 0; +static uint16_t _tu_fifo_write_n(tu_fifo_t *f, const void *data, uint16_t n, tu_fifo_copy_mode_t copy_mode) { + if (n == 0) { + return 0; + } _ff_lock(f->mutex_wr); uint16_t wr_idx = f->wr_idx; uint16_t rd_idx = f->rd_idx; - uint8_t const* buf8 = (uint8_t const*) data; + const uint8_t *buf8 = (const uint8_t *)data; - TU_LOG(TU_FIFO_DBG, "rd = %3u, wr = %3u, count = %3u, remain = %3u, n = %3u: ", - rd_idx, wr_idx, _ff_count(f->depth, wr_idx, rd_idx), _ff_remaining(f->depth, wr_idx, rd_idx), n); + TU_LOG( + TU_FIFO_DBG, "rd = %3u, wr = %3u, count = %3u, remain = %3u, n = %3u: ", rd_idx, wr_idx, + _ff_count(f->depth, wr_idx, rd_idx), _ff_remaining(f->depth, wr_idx, rd_idx), n); - if ( !f->overwritable ) - { + if (!f->overwritable) { // limit up to full - uint16_t const remain = _ff_remaining(f->depth, wr_idx, rd_idx); - n = tu_min16(n, remain); - } - else - { + const uint16_t remain = _ff_remaining(f->depth, wr_idx, rd_idx); + n = tu_min16(n, remain); + } else { // In over-writable mode, fifo_write() is allowed even when fifo is full. In such case, // oldest data in fifo i.e at read pointer data will be overwritten // Note: we can modify read buffer contents but we must not modify the read index itself within a write function! // Since it would end up in a race condition with read functions! - if ( n >= f->depth ) - { + if (n >= f->depth) { // Only copy last part - if ( copy_mode == TU_FIFO_COPY_INC ) - { + if (copy_mode == TU_FIFO_COPY_INC) { buf8 += (n - f->depth) * f->item_size; - }else - { + } else { // TODO should read from hw fifo to discard data, however reading an odd number could // accidentally discard data. } @@ -503,12 +482,9 @@ static uint16_t _tu_fifo_write_n(tu_fifo_t* f, const void * data, uint16_t n, tu // We start writing at the read pointer's position since we fill the whole buffer wr_idx = rd_idx; - } - else - { - uint16_t const overflowable_count = _ff_count(f->depth, wr_idx, rd_idx); - if (overflowable_count + n >= 2*f->depth) - { + } else { + const uint16_t overflowable_count = _ff_count(f->depth, wr_idx, rd_idx); + if (overflowable_count + n >= 2 * f->depth) { // Double overflowed // Index is bigger than the allowed range [0,2*depth) // re-position write index to have a full fifo after pushed @@ -518,8 +494,7 @@ static uint16_t _tu_fifo_write_n(tu_fifo_t* f, const void * data, uint16_t n, tu // However memmove() is expensive due to actual copying + wrapping consideration. // Also race condition could happen anyway if read() is invoke while moving result in corrupted memory // currently deliberately not implemented --> result in incorrect data read back - }else - { + } else { // normal + single overflowed: // Index is in the range of [0,2*depth) and thus detect and recoverable. Recovering is handled in read() // Therefore we just increase write index @@ -528,16 +503,11 @@ static uint16_t _tu_fifo_write_n(tu_fifo_t* f, const void * data, uint16_t n, tu } } - if (n) - { + if (n) { uint16_t wr_ptr = idx2ptr(f->depth, wr_idx); - TU_LOG(TU_FIFO_DBG, "actual_n = %u, wr_ptr = %u", n, wr_ptr); - // Write data _ff_push_n(f, buf8, n, wr_ptr, copy_mode); - - // Advance index f->wr_idx = advance_index(f->depth, wr_idx, n); TU_LOG(TU_FIFO_DBG, "\tnew_wr = %u\r\n", f->wr_idx); @@ -548,8 +518,7 @@ static uint16_t _tu_fifo_write_n(tu_fifo_t* f, const void * data, uint16_t n, tu return n; } -static uint16_t _tu_fifo_read_n(tu_fifo_t* f, void * buffer, uint16_t n, tu_fifo_copy_mode_t copy_mode) -{ +static uint16_t _tu_fifo_read_n(tu_fifo_t *f, void *buffer, uint16_t n, tu_fifo_copy_mode_t copy_mode) { _ff_lock(f->mutex_rd); // Peek the data @@ -582,8 +551,7 @@ static uint16_t _tu_fifo_read_n(tu_fifo_t* f, void * buffer, uint16_t n, tu_fifo @returns Number of items in FIFO */ /******************************************************************************/ -uint16_t tu_fifo_count(tu_fifo_t* f) -{ +uint16_t tu_fifo_count(tu_fifo_t *f) { return tu_min16(_ff_count(f->depth, f->wr_idx, f->rd_idx), f->depth); } @@ -600,8 +568,7 @@ uint16_t tu_fifo_count(tu_fifo_t* f) @returns Number of items in FIFO */ /******************************************************************************/ -bool tu_fifo_empty(tu_fifo_t* f) -{ +bool tu_fifo_empty(tu_fifo_t *f) { return f->wr_idx == f->rd_idx; } @@ -618,8 +585,7 @@ bool tu_fifo_empty(tu_fifo_t* f) @returns Number of items in FIFO */ /******************************************************************************/ -bool tu_fifo_full(tu_fifo_t* f) -{ +bool tu_fifo_full(tu_fifo_t *f) { return _ff_count(f->depth, f->wr_idx, f->rd_idx) >= f->depth; } @@ -636,8 +602,7 @@ bool tu_fifo_full(tu_fifo_t* f) @returns Number of items in FIFO */ /******************************************************************************/ -uint16_t tu_fifo_remaining(tu_fifo_t* f) -{ +uint16_t tu_fifo_remaining(tu_fifo_t *f) { return _ff_remaining(f->depth, f->wr_idx, f->rd_idx); } @@ -662,14 +627,12 @@ uint16_t tu_fifo_remaining(tu_fifo_t* f) @returns True if overflow happened */ /******************************************************************************/ -bool tu_fifo_overflowed(tu_fifo_t* f) -{ +bool tu_fifo_overflowed(tu_fifo_t *f) { return _ff_count(f->depth, f->wr_idx, f->rd_idx) > f->depth; } // Only use in case tu_fifo_overflow() returned true! -void tu_fifo_correct_read_pointer(tu_fifo_t* f) -{ +void tu_fifo_correct_read_pointer(tu_fifo_t *f) { _ff_lock(f->mutex_rd); _ff_correct_read_index(f, f->wr_idx); _ff_unlock(f->mutex_rd); @@ -691,8 +654,7 @@ void tu_fifo_correct_read_pointer(tu_fifo_t* f) @returns TRUE if the queue is not empty */ /******************************************************************************/ -bool tu_fifo_read(tu_fifo_t* f, void * buffer) -{ +bool tu_fifo_read(tu_fifo_t *f, void *buffer) { _ff_lock(f->mutex_rd); // Peek the data @@ -722,8 +684,7 @@ bool tu_fifo_read(tu_fifo_t* f, void * buffer) @returns number of items read from the FIFO */ /******************************************************************************/ -uint16_t tu_fifo_read_n(tu_fifo_t* f, void * buffer, uint16_t n) -{ +uint16_t tu_fifo_read_n(tu_fifo_t *f, void *buffer, uint16_t n) { return _tu_fifo_read_n(f, buffer, n, TU_FIFO_COPY_INC); } @@ -745,8 +706,7 @@ uint16_t tu_fifo_read_n(tu_fifo_t* f, void * buffer, uint16_t n) @returns number of items read from the FIFO */ /******************************************************************************/ -uint16_t tu_fifo_read_n_const_addr_full_words(tu_fifo_t* f, void * buffer, uint16_t n) -{ +uint16_t tu_fifo_read_n_const_addr_full_words(tu_fifo_t *f, void *buffer, uint16_t n) { return _tu_fifo_read_n(f, buffer, n, TU_FIFO_COPY_CST_FULL_WORDS); } #endif @@ -764,8 +724,7 @@ uint16_t tu_fifo_read_n_const_addr_full_words(tu_fifo_t* f, void * buffer, uint1 @returns TRUE if the queue is not empty */ /******************************************************************************/ -bool tu_fifo_peek(tu_fifo_t* f, void * p_buffer) -{ +bool tu_fifo_peek(tu_fifo_t *f, void *p_buffer) { _ff_lock(f->mutex_rd); bool ret = _tu_fifo_peek(f, p_buffer, f->wr_idx, f->rd_idx); _ff_unlock(f->mutex_rd); @@ -787,8 +746,7 @@ bool tu_fifo_peek(tu_fifo_t* f, void * p_buffer) @returns Number of bytes written to p_buffer */ /******************************************************************************/ -uint16_t tu_fifo_peek_n(tu_fifo_t* f, void * p_buffer, uint16_t n) -{ +uint16_t tu_fifo_peek_n(tu_fifo_t *f, void *p_buffer, uint16_t n) { _ff_lock(f->mutex_rd); uint16_t ret = _tu_fifo_peek_n(f, p_buffer, n, f->wr_idx, f->rd_idx, TU_FIFO_COPY_INC); _ff_unlock(f->mutex_rd); @@ -811,27 +769,19 @@ uint16_t tu_fifo_peek_n(tu_fifo_t* f, void * p_buffer, uint16_t n) FIFO will always return TRUE) */ /******************************************************************************/ -bool tu_fifo_write(tu_fifo_t* f, const void * data) -{ +bool tu_fifo_write(tu_fifo_t *f, const void *data) { _ff_lock(f->mutex_wr); - bool ret; - uint16_t const wr_idx = f->wr_idx; + bool ret; + const uint16_t wr_idx = f->wr_idx; - if ( tu_fifo_full(f) && !f->overwritable ) - { + if (tu_fifo_full(f) && !f->overwritable) { ret = false; - }else - { + } else { uint16_t wr_ptr = idx2ptr(f->depth, wr_idx); - - // Write data _ff_push(f, data, wr_ptr); - - // Advance pointer f->wr_idx = advance_index(f->depth, wr_idx, 1); - - ret = true; + ret = true; } _ff_unlock(f->mutex_wr); @@ -853,8 +803,7 @@ bool tu_fifo_write(tu_fifo_t* f, const void * data) @return Number of written elements */ /******************************************************************************/ -uint16_t tu_fifo_write_n(tu_fifo_t* f, const void * data, uint16_t n) -{ +uint16_t tu_fifo_write_n(tu_fifo_t *f, const void *data, uint16_t n) { return _tu_fifo_write_n(f, data, n, TU_FIFO_COPY_INC); } @@ -874,8 +823,7 @@ uint16_t tu_fifo_write_n(tu_fifo_t* f, const void * data, uint16_t n) @return Number of written elements */ /******************************************************************************/ -uint16_t tu_fifo_write_n_const_addr_full_words(tu_fifo_t* f, const void * data, uint16_t n) -{ +uint16_t tu_fifo_write_n_const_addr_full_words(tu_fifo_t *f, const void *data, uint16_t n) { return _tu_fifo_write_n(f, data, n, TU_FIFO_COPY_CST_FULL_WORDS); } #endif @@ -888,8 +836,7 @@ uint16_t tu_fifo_write_n_const_addr_full_words(tu_fifo_t* f, const void * data, Pointer to the FIFO buffer to manipulate */ /******************************************************************************/ -bool tu_fifo_clear(tu_fifo_t *f) -{ +bool tu_fifo_clear(tu_fifo_t *f) { _ff_lock(f->mutex_wr); _ff_lock(f->mutex_rd); @@ -943,8 +890,7 @@ bool tu_fifo_set_overwritable(tu_fifo_t *f, bool overwritable) { Number of items the write pointer moves forward */ /******************************************************************************/ -void tu_fifo_advance_write_pointer(tu_fifo_t *f, uint16_t n) -{ +void tu_fifo_advance_write_pointer(tu_fifo_t *f, uint16_t n) { f->wr_idx = advance_index(f->depth, f->wr_idx, n); } @@ -964,8 +910,7 @@ void tu_fifo_advance_write_pointer(tu_fifo_t *f, uint16_t n) Number of items the read pointer moves forward */ /******************************************************************************/ -void tu_fifo_advance_read_pointer(tu_fifo_t *f, uint16_t n) -{ +void tu_fifo_advance_read_pointer(tu_fifo_t *f, uint16_t n) { f->rd_idx = advance_index(f->depth, f->rd_idx, n); } @@ -984,8 +929,7 @@ void tu_fifo_advance_read_pointer(tu_fifo_t *f, uint16_t n) Pointer to struct which holds the desired infos */ /******************************************************************************/ -void tu_fifo_get_read_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info) -{ +void tu_fifo_get_read_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info) { // Operate on temporary values in case they change in between uint16_t wr_idx = f->wr_idx; uint16_t rd_idx = f->rd_idx; @@ -993,8 +937,7 @@ void tu_fifo_get_read_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info) uint16_t cnt = _ff_count(f->depth, wr_idx, rd_idx); // Check overflow and correct if required - may happen in case a DMA wrote too fast - if (cnt > f->depth) - { + if (cnt > f->depth) { _ff_lock(f->mutex_rd); rd_idx = _ff_correct_read_index(f, wr_idx); _ff_unlock(f->mutex_rd); @@ -1003,8 +946,7 @@ void tu_fifo_get_read_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info) } // Check if fifo is empty - if (cnt == 0) - { + if (cnt == 0) { info->len_lin = 0; info->len_wrap = 0; info->ptr_lin = NULL; @@ -1020,17 +962,14 @@ void tu_fifo_get_read_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info) info->ptr_lin = &f->buffer[rd_ptr]; // Check if there is a wrap around necessary - if (wr_ptr > rd_ptr) - { + if (wr_ptr > rd_ptr) { // Non wrapping case - info->len_lin = cnt; + info->len_lin = cnt; info->len_wrap = 0; info->ptr_wrap = NULL; - } - else - { - info->len_lin = f->depth - rd_ptr; // Also the case if FIFO was full + } else { + info->len_lin = f->depth - rd_ptr; // Also the case if FIFO was full info->len_wrap = cnt - info->len_lin; info->ptr_wrap = f->buffer; @@ -1052,14 +991,12 @@ void tu_fifo_get_read_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info) Pointer to struct which holds the desired infos */ /******************************************************************************/ -void tu_fifo_get_write_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info) -{ +void tu_fifo_get_write_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info) { uint16_t wr_idx = f->wr_idx; uint16_t rd_idx = f->rd_idx; uint16_t remain = _ff_remaining(f->depth, wr_idx, rd_idx); - if (remain == 0) - { + if (remain == 0) { info->len_lin = 0; info->len_wrap = 0; info->ptr_lin = NULL; @@ -1074,15 +1011,12 @@ void tu_fifo_get_write_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info) // Copy pointer to buffer to start writing to info->ptr_lin = &f->buffer[wr_ptr]; - if (wr_ptr < rd_ptr) - { + if (wr_ptr < rd_ptr) { // Non wrapping case - info->len_lin = rd_ptr-wr_ptr; + info->len_lin = rd_ptr - wr_ptr; info->len_wrap = 0; info->ptr_wrap = NULL; - } - else - { + } else { info->len_lin = f->depth - wr_ptr; info->len_wrap = remain - info->len_lin; // Remaining length - n already was limited to remain or FIFO depth info->ptr_wrap = f->buffer; // Always start of buffer diff --git a/src/common/tusb_fifo.h b/src/common/tusb_fifo.h index f2a6c5469..0f4ba00d8 100644 --- a/src/common/tusb_fifo.h +++ b/src/common/tusb_fifo.h @@ -104,16 +104,16 @@ extern "C" { * | R | 1 | 2 | W | 4 | 5 | */ typedef struct { - uint8_t* buffer ; // buffer pointer - uint16_t depth ; // max items + uint8_t *buffer; // buffer pointer + uint16_t depth; // max items struct TU_ATTR_PACKED { - uint16_t item_size : 15; // size of each item - bool overwritable : 1 ; // ovwerwritable when full + uint16_t item_size : 15; // size of each item + bool overwritable : 1; // ovwerwritable when full }; - volatile uint16_t wr_idx ; // write index - volatile uint16_t rd_idx ; // read index + volatile uint16_t wr_idx; // write index + volatile uint16_t rd_idx; // read index #if OSAL_MUTEX_REQUIRED osal_mutex_t mutex_wr; @@ -129,12 +129,13 @@ typedef struct { void * ptr_wrap ; ///< wrapped part start pointer } tu_fifo_buffer_info_t; -#define TU_FIFO_INIT(_buffer, _depth, _type, _overwritable){\ - .buffer = _buffer, \ - .depth = _depth, \ - .item_size = sizeof(_type), \ - .overwritable = _overwritable, \ -} +#define TU_FIFO_INIT(_buffer, _depth, _type, _overwritable) \ + { \ + .buffer = _buffer, \ + .depth = _depth, \ + .item_size = sizeof(_type), \ + .overwritable = _overwritable, \ + } #define TU_FIFO_DEF(_name, _depth, _type, _overwritable) \ uint8_t _name##_buf[_depth*sizeof(_type)]; \ diff --git a/src/common/tusb_private.h b/src/common/tusb_private.h index 5e1d59233..dcd5c45d6 100644 --- a/src/common/tusb_private.h +++ b/src/common/tusb_private.h @@ -40,6 +40,12 @@ extern tusb_role_t _tusb_rhport_role[TUP_USBIP_CONTROLLER_NUM]; // Endpoint //--------------------------------------------------------------------+ +enum { + TU_EDPT_STATE_BUSY = 0x01, + TU_EDPT_STATE_STALLED = 0x02, + TU_EDPT_STATE_CLAIMED = 0x04, +}; + typedef struct TU_ATTR_PACKED { volatile uint8_t busy : 1; volatile uint8_t stalled : 1; @@ -48,8 +54,8 @@ typedef struct TU_ATTR_PACKED { typedef struct { struct TU_ATTR_PACKED { - uint8_t is_host : 1; // 1: host, 0: device - uint8_t is_mps512 : 1; // 1: 512, 0: 64 since stream is used for Bulk only + bool is_host : 1; // 1: host, 0: device + bool is_mps512 : 1; // 1: 512, 0: 64 since stream is used for Bulk only }; uint8_t ep_addr; uint16_t ep_bufsize; @@ -93,21 +99,18 @@ bool tu_edpt_stream_init(tu_edpt_stream_t* s, bool is_host, bool is_tx, bool ove bool tu_edpt_stream_deinit(tu_edpt_stream_t* s); // Open an stream for an endpoint -TU_ATTR_ALWAYS_INLINE static inline -void tu_edpt_stream_open(tu_edpt_stream_t* s, tusb_desc_endpoint_t const *desc_ep) { +TU_ATTR_ALWAYS_INLINE static inline void tu_edpt_stream_open(tu_edpt_stream_t* s, tusb_desc_endpoint_t const *desc_ep) { tu_fifo_clear(&s->ff); s->ep_addr = desc_ep->bEndpointAddress; - s->is_mps512 = (tu_edpt_packet_size(desc_ep) == 512) ? 1 : 0; + s->is_mps512 = tu_edpt_packet_size(desc_ep) == 512; } -TU_ATTR_ALWAYS_INLINE static inline -void tu_edpt_stream_close(tu_edpt_stream_t* s) { +TU_ATTR_ALWAYS_INLINE static inline void tu_edpt_stream_close(tu_edpt_stream_t* s) { s->ep_addr = 0; } // Clear fifo -TU_ATTR_ALWAYS_INLINE static inline -bool tu_edpt_stream_clear(tu_edpt_stream_t* s) { +TU_ATTR_ALWAYS_INLINE static inline bool tu_edpt_stream_clear(tu_edpt_stream_t* s) { return tu_fifo_clear(&s->ff); } diff --git a/src/tusb.c b/src/tusb.c index be67eead2..7411f19df 100644 --- a/src/tusb.c +++ b/src/tusb.c @@ -117,11 +117,15 @@ bool tusb_inited(void) { bool ret = false; #if CFG_TUD_ENABLED - ret = ret || tud_inited(); + if (tud_inited()) { + ret = true; + } #endif #if CFG_TUH_ENABLED - ret = ret || tuh_inited(); + if (tuh_inited()) { + ret = true; + } #endif return ret; @@ -209,7 +213,8 @@ bool tu_edpt_claim(tu_edpt_state_t* ep_state, osal_mutex_t mutex) { (void) mutex; // pre-check to help reducing mutex lock - TU_VERIFY((ep_state->busy == 0) && (ep_state->claimed == 0)); + TU_VERIFY(ep_state->busy == 0); + TU_VERIFY(ep_state->claimed == 0); (void) osal_mutex_lock(mutex, OSAL_TIMEOUT_WAIT_FOREVER); // can only claim the endpoint if it is not busy and not claimed yet. @@ -298,7 +303,7 @@ uint16_t tu_desc_get_interface_total_len(tusb_desc_interface_t const* desc_itf, uint8_t const* p_desc = (uint8_t const*) desc_itf; uint16_t len = 0; - while (itf_count--) { + while ((itf_count--) > 0) { // Next on interface desc len += tu_desc_len(desc_itf); p_desc = tu_desc_next(p_desc); @@ -337,7 +342,7 @@ bool tu_edpt_stream_init(tu_edpt_stream_t* s, bool is_host, bool is_tx, bool ove tu_fifo_config(&s->ff, ff_buf, ff_bufsize, 1, overwritable); #if OSAL_MUTEX_REQUIRED - if (ff_buf && ff_bufsize) { + if (ff_buf != NULL && ff_bufsize > 0) { osal_mutex_t new_mutex = osal_mutex_create(&s->ff_mutexdef); tu_fifo_config_mutex(&s->ff, is_tx ? new_mutex : NULL, is_tx ? NULL : new_mutex); } @@ -352,9 +357,13 @@ bool tu_edpt_stream_init(tu_edpt_stream_t* s, bool is_host, bool is_tx, bool ove bool tu_edpt_stream_deinit(tu_edpt_stream_t* s) { (void) s; #if OSAL_MUTEX_REQUIRED - if (s->ff.mutex_wr) osal_mutex_delete(s->ff.mutex_wr); - if (s->ff.mutex_rd) osal_mutex_delete(s->ff.mutex_rd); - #endif + if (s->ff.mutex_wr) { + osal_mutex_delete(s->ff.mutex_wr); + } + if (s->ff.mutex_rd) { + osal_mutex_delete(s->ff.mutex_rd); + } +#endif return true; } @@ -403,7 +412,7 @@ TU_ATTR_ALWAYS_INLINE static inline bool stream_release(uint8_t hwid, tu_edpt_st bool tu_edpt_stream_write_zlp_if_needed(uint8_t hwid, tu_edpt_stream_t* s, uint32_t last_xferred_bytes) { // ZLP condition: no pending data, last transferred bytes is multiple of packet size const uint16_t mps = s->is_mps512 ? TUSB_EPSIZE_BULK_HS : TUSB_EPSIZE_BULK_FS; - TU_VERIFY(!tu_fifo_count(&s->ff) && last_xferred_bytes && (0 == (last_xferred_bytes & (mps - 1)))); + TU_VERIFY(!tu_fifo_count(&s->ff) && last_xferred_bytes > 0 && (0 == (last_xferred_bytes & (mps - 1)))); TU_VERIFY(stream_claim(hwid, s)); TU_ASSERT(stream_xfer(hwid, s, 0)); return true; @@ -411,14 +420,13 @@ bool tu_edpt_stream_write_zlp_if_needed(uint8_t hwid, tu_edpt_stream_t* s, uint3 uint32_t tu_edpt_stream_write_xfer(uint8_t hwid, tu_edpt_stream_t* s) { // skip if no data - TU_VERIFY(tu_fifo_count(&s->ff), 0); - + TU_VERIFY(tu_fifo_count(&s->ff) > 0, 0); TU_VERIFY(stream_claim(hwid, s), 0); // Pull data from FIFO -> EP buf uint16_t const count = tu_fifo_read_n(&s->ff, s->ep_buf, s->ep_bufsize); - if (count) { + if (count > 0) { TU_ASSERT(stream_xfer(hwid, s, count), 0); return count; } else { @@ -430,7 +438,7 @@ uint32_t tu_edpt_stream_write_xfer(uint8_t hwid, tu_edpt_stream_t* s) { } uint32_t tu_edpt_stream_write(uint8_t hwid, tu_edpt_stream_t* s, void const* buffer, uint32_t bufsize) { - TU_VERIFY(bufsize); // TODO support ZLP + TU_VERIFY(bufsize > 0); // TODO support ZLP if (0 == tu_fifo_depth(&s->ff)) { // no fifo for buffered @@ -453,7 +461,7 @@ uint32_t tu_edpt_stream_write(uint8_t hwid, tu_edpt_stream_t* s, void const* buf } uint32_t tu_edpt_stream_write_available(uint8_t hwid, tu_edpt_stream_t* s) { - if (tu_fifo_depth(&s->ff)) { + if (tu_fifo_depth(&s->ff) > 0) { return (uint32_t) tu_fifo_remaining(&s->ff); } else { bool is_busy = true; @@ -596,7 +604,7 @@ void tu_print_mem(void const* buf, uint32_t count, uint8_t indent) { // fill up last row to 16 for printing ascii const uint32_t remain = count % 16; uint8_t nback = (uint8_t) (remain ? remain : 16); - if (remain) { + if (remain > 0) { for (uint32_t i = 0; i < 16 - remain; i++) { tu_printf(" "); for (int j = 0; j < 2 * size; j++) { -- cgit v1.3.1 From a1ae5b20ccf760282538dd81b9290527757fa9c7 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 11 Nov 2025 10:27:47 +0700 Subject: update doc --- .github/workflows/static_analysis.yml | 9 +- README.rst | 56 ++++++-- docs/_static/custom.css | 3 + docs/conf.py | 8 +- docs/contributing/code_of_conduct.rst | 1 - docs/contributing/index.rst | 22 --- docs/contributing/porting.rst | 243 ---------------------------------- docs/faq.rst | 32 +---- docs/getting_started.rst | 159 ++++++++++++---------- docs/index.rst | 37 +----- docs/info/changelog.rst | 48 +++++++ docs/info/code_of_conduct.rst | 1 + docs/info/index.rst | 1 + docs/integration.rst | 93 +++++++++++++ docs/porting.rst | 243 ++++++++++++++++++++++++++++++++++ docs/reference/architecture.rst | 39 ++---- docs/reference/boards.rst | 31 +++-- docs/reference/dependencies.rst | 12 +- docs/reference/glossary.rst | 2 +- docs/troubleshooting.rst | 43 ++++-- hw/bsp/family_support.cmake | 49 +++++-- tools/gen_doc.py | 2 +- 22 files changed, 640 insertions(+), 494 deletions(-) create mode 100644 docs/_static/custom.css delete mode 100644 docs/contributing/code_of_conduct.rst delete mode 100644 docs/contributing/index.rst delete mode 100644 docs/contributing/porting.rst create mode 100644 docs/info/code_of_conduct.rst create mode 100644 docs/integration.rst create mode 100644 docs/porting.rst (limited to '.github/workflows/static_analysis.yml') diff --git a/.github/workflows/static_analysis.yml b/.github/workflows/static_analysis.yml index a89cdc279..4db267517 100644 --- a/.github/workflows/static_analysis.yml +++ b/.github/workflows/static_analysis.yml @@ -90,7 +90,8 @@ jobs: path: ${{ steps.analyze.outputs.sarif-output }} PVS-Studio: - if: github.repository_owner == 'hathach' + # Only run on non-forked PR since secrets token is required + if: github.repository_owner == 'hathach' && github.event.pull_request.head.repo.fork == false runs-on: ubuntu-latest strategy: fail-fast: false @@ -141,7 +142,8 @@ jobs: path: pvs-studio-${{ matrix.board }}.sarif SonarQube: - if: github.repository_owner == 'hathach' + # Only run on non-forked PR since secrets token is required + if: github.repository_owner == 'hathach' && github.event.pull_request.head.repo.fork == false runs-on: ubuntu-latest env: BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory @@ -184,7 +186,8 @@ jobs: --define sonar.cfamily.compile-commands=${{ env.BUILD_WRAPPER_OUT_DIR }}/compile_commands.json IAR-CStat: - #if: github.repository_owner == 'hathach' + # Only run on non-forked PR since secrets token is required + #if: github.repository_owner == 'hathach' && github.event.pull_request.head.repo.fork == false if: false runs-on: ubuntu-latest strategy: diff --git a/README.rst b/README.rst index 2d84a2f6c..d0586f55a 100644 --- a/README.rst +++ b/README.rst @@ -1,26 +1,55 @@ +TinyUSB +======= + |Build Status| |CircleCI Status| |Documentation Status| |Static Analysis| |Fuzzing Status| |License| Sponsors -======== +-------- TinyUSB is funded by: Adafruit. Purchasing products from them helps to support this project. .. figure:: docs/assets/adafruit_logo.svg :alt: Adafruit Logo + :align: left :target: https://www.adafruit.com -TinyUSB Project -=============== +.. raw:: html + +
+ +Overview +-------- .. figure:: docs/assets/logo.svg :alt: TinyUSB + :align: left + +.. raw:: html + +
+ +TinyUSB is an open-source cross-platform USB Host/Device stack for embedded systems. It’s designed for memory safety +(no dynamic allocation) and thread safety (all interrupts deferred to non-ISR task functions). The stack emphasizes portability, +small footprint, and real-time performance across 50+ MCU families. -TinyUSB is an open-source cross-platform USB Host/Device stack for embedded system, designed to be memory-safe with no dynamic allocation and thread-safe with all interrupt events are deferred then handled in the non-ISR task function. Check out the online `documentation `__ for more details. +Key Features +------------ + +* **Thread-safe:** USB interrupts deferred to task context +* **Memory-safe:** No dynamic allocation, all buffers static +* **Portable:** Supports 50+ MCU families +* **Comprehensive:** Includes CDC, HID, MSC, Audio, and Host support +* **RTOS-friendly:** Works with bare metal, FreeRTOS, RT-Thread, and Mynewt .. figure:: docs/assets/stack.svg :width: 500px + :align: left :alt: stackup +.. raw:: html + +
+ :: . @@ -36,7 +65,7 @@ TinyUSB is an open-source cross-platform USB Host/Device stack for embedded syst Getting started -=============== +--------------- See the `online documentation `_ for information about using TinyUSB and how it is implemented. @@ -49,7 +78,7 @@ For bugs and feature requests, please `raise an issue `_ Host Stack -========== +---------- - Human Interface Device (HID): Keyboard, Mouse, Generic - Mass Storage Class (MSC) @@ -81,14 +110,14 @@ Host Stack Similar to the Device Stack, if you have a special requirement, ``usbh_app_driver_get_cb()`` can be used to write your own class driver without modifying the stack. Power Delivery Stack -==================== +-------------------- - Power Delivery 3.0 (PD3.0) with USB Type-C support (WIP) - Super early stage, only for testing purpose - Only support STM32 G4 OS Abstraction layer -==================== +-------------------- TinyUSB is completely thread-safe by pushing all Interrupt Service Request (ISR) events into a central queue, then processing them later in the non-ISR context task function. It also uses semaphore/mutex to access shared resources such as Communication Device Class (CDC) FIFO. Therefore the stack needs to use some of the OS's basic APIs. Following OSes are already supported out of the box. @@ -98,7 +127,7 @@ TinyUSB is completely thread-safe by pushing all Interrupt Service Request (ISR) - **Mynewt** Due to the newt package build system, Mynewt examples are better to be on its `own repo `_ Supported CPUs -============== +-------------- +--------------+-----------------------------+--------+------+-----------+------------------------+-------------------+ | Manufacturer | Family | Device | Host | Highspeed | Driver | Note | @@ -234,7 +263,7 @@ Supported CPUs +--------------+-----------------------------+--------+------+-----------+------------------------+-------------------+ Table Legend ------------- +^^^^^^^^^^^^ ========= ========================= ✔ Supported @@ -244,7 +273,7 @@ Table Legend ========= ========================= Development Tools -================= +----------------- The following tools are provided freely to support the development of the TinyUSB project: @@ -273,6 +302,5 @@ The following tools are provided freely to support the development of the TinyUS .. _Supported Boards: docs/reference/boards.rst .. _Dependencies: docs/reference/dependencies.rst .. _Concurrency: docs/reference/concurrency.rst -.. _Contributing: docs/contributing/index.rst .. _Code of Conduct: CODE_OF_CONDUCT.rst -.. _Porting: docs/contributing/porting.rst +.. _Porting: docs/porting.rst diff --git a/docs/_static/custom.css b/docs/_static/custom.css new file mode 100644 index 000000000..d64d26047 --- /dev/null +++ b/docs/_static/custom.css @@ -0,0 +1,3 @@ +.clear-both { + clear: both; +} diff --git a/docs/conf.py b/docs/conf.py index 4249d41f7..cd0338413 100755 --- a/docs/conf.py +++ b/docs/conf.py @@ -14,7 +14,7 @@ from pathlib import Path # -- Project information ----------------------------------------------------- project = 'TinyUSB' -copyright = '2024, Ha Thach' +copyright = '2025, Ha Thach' author = 'Ha Thach' @@ -41,6 +41,8 @@ html_favicon = 'assets/logo.svg' html_theme_options = { 'sidebar_hide_name': True, } +html_static_path = ['_static'] +html_css_files = ['custom.css'] todo_include_todos = True @@ -52,7 +54,9 @@ def preprocess_readme(): if src.exists(): content = src.read_text() content = re.sub(r"docs/", r"", content) - content = re.sub(r".rst", r".html", content) + content = re.sub(r"\.rst\b", r".html", content) + if not content.endswith("\n"): + content += "\n" tgt.write_text(content) preprocess_readme() diff --git a/docs/contributing/code_of_conduct.rst b/docs/contributing/code_of_conduct.rst deleted file mode 100644 index fb1859c75..000000000 --- a/docs/contributing/code_of_conduct.rst +++ /dev/null @@ -1 +0,0 @@ -.. include:: ../../CODE_OF_CONDUCT.rst \ No newline at end of file diff --git a/docs/contributing/index.rst b/docs/contributing/index.rst deleted file mode 100644 index 78933a3ca..000000000 --- a/docs/contributing/index.rst +++ /dev/null @@ -1,22 +0,0 @@ -************ -Contributing -************ - -Contributing can be highly rewarding, but it can also be frustrating at times. -It takes time to review patches, and as this is an open source project, that -sometimes can take a while. The reviewing process depends on the availability -of the maintainers, who may not be always available. Please try to be -understanding through the process. - -There a few guidelines you need to keep in mind when contributing. Please have -a look at them as that will make the contribution process easier for all -parties. - -Index -===== - -.. toctree:: - :maxdepth: 2 - - code_of_conduct - porting diff --git a/docs/contributing/porting.rst b/docs/contributing/porting.rst deleted file mode 100644 index c3076354c..000000000 --- a/docs/contributing/porting.rst +++ /dev/null @@ -1,243 +0,0 @@ - -******* -Porting -******* - -TinyUSB is designed to be a universal USB protocol stack for microcontrollers. It -handles most of the high level USB protocol and relies on the microcontroller's USB peripheral for -data transactions on different endpoints. Porting is the process of adding low-level support for -the rest of the common stack. Once the low-level is implemented, it is very easy to add USB support -for the microcontroller to other projects, especially those already using TinyUSB such as CircuitPython. - -Below are instructions on how to get the cdc_msc device example running on a new microcontroller. Doing so includes adding the common code necessary for other uses while minimizing other extra code. Whenever you see a phrase or word in ``<>`` it should be replaced. - -Register defs -------------- - -The first step to adding support is including the register definitions and startup code for the -microcontroller in TinyUSB. We write the TinyUSB implementation against these structs instead of higher level functions to keep the code small and to prevent function name collisions in linking of larger projects. For ARM microcontrollers this is the CMSIS definitions. They should be -placed in the ``hw/mcu//`` directory. - -Once this is done, create a directory in ``hw/bsp/`` for the specific board you are using to test the code (duplicating an existing board's directory is the best way to get started). The board should be a readily available development board so that others can also test. - -Build ------ - -Now that those directories are in place, we can start our iteration process to get the example building successfully. To build, run from the root of TinyUSB: - -.. code-block:: bash - - make -C examples/device/cdc_msc BOARD= - -Unless you've read ahead, this will fail miserably. Now, lets get it to fail less by updating the files in the board directory. The code in the board's directory is responsible for setting up the microcontroller's clocks and pins so that USB works. TinyUSB itself only operates on the USB peripheral. The board directory also includes information what files are needed to build the example. - -One of the first things to change is the ``-DCFG_TUSB_MCU`` C flag in the ``board.mk`` file. This is used to tell TinyUSB what platform is being built. So, add an entry to ``src/tusb_option.h`` and update the ``CFLAGS`` to match. - -Update ``board.mk``'s VENDOR and CHIP_FAMILY values when creating the directory for the struct files. Duplicate one of the other sources from ``src/portable`` into ``src/portable//`` and delete all of the implementation internals. We'll cover what everything there does later. For now, get it compiling. - -Implementation --------------- - -At this point you should get an error due to an implementation issue and hopefully the build is setup for the new MCU. You will still need to modify the ``board.mk`` to include specific ``CFLAGS``, the linker script, linker flags, source files, include directories. All file paths are relative to the top of the TinyUSB repo. - -Board Support (BSP) -^^^^^^^^^^^^^^^^^^^ - -The board support code is only used for self-contained examples and testing. It is not used when TinyUSB is part of a larger project. Its responsible for getting the MCU started and the USB peripheral clocked. It also optionally provides LED definitions that are used to blink an LED to show that the code is running. - -It is located in ``hw/bsp//board_.c``. - -``board_init()`` -~~~~~~~~~~~~~~~~ - -``board_init()`` is responsible for starting the MCU, setting up the USB clock and USB pins. It is also responsible for initializing LED pins. - -One useful clock debugging technique is to set up a PWM output at a known value such as 500hz based on the USB clock so that you can verify it is correct with a logic probe or oscilloscope. - -Setup your USB in a crystal-less mode when available. That makes the code easier to port across boards. - -``board_led_write()`` -~~~~~~~~~~~~~~~~~~~~~ - -Feel free to skip this until you want to verify your demo code is running. To implement, set the pin corresponding to the led to output a value that lights the LED when ``state`` is true. - -OS Abstraction Layer (OSAL) -^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -The OS Abstraction Layer is responsible for providing basic data structures for TinyUSB that may allow for concurrency when used with an RTOS. Without an RTOS it simply handles concurrency issues between the main code and interrupts. The code is almost entirely agnostic of MCU and lives in ``src/osal``. - -In RTOS configurations, ``tud_task()``/``tuh_task()`` blocks behind a synchronization structure when the event queue is empty, so that the scheduler may give the CPU to a different task. To take advantage of the library's capability to yield the CPU when there are no actionable USB device events, ensure that the ``CFG_TUSB_OS`` symbol is defined, e.g ``OPT_OS_FREERTOS`` enables the FreeRTOS scheduler to schedule other threads than that which calls ``tud_task()``/``tuh_task()``. - -Device API -^^^^^^^^^^ - -After the USB device is setup, the USB device code works by processing events on the main thread (by calling ``tud_task()``). These events are queued by the USB interrupt handler. So, there are three parts to the device low-level API: device setup, endpoint setup and interrupt processing. - -All of the code for the low-level device API is in ``src/portable///dcd_.c``. - -Device Setup -~~~~~~~~~~~~ - -``dcd_init()`` -"""""""""""""" - -Initializes the USB peripheral for device mode and enables it. -This function should enable internal D+/D- pull-up for enumeration. - -``dcd_int_enable()`` / ``dcd_int_disable()`` -"""""""""""""""""""""""""""""""""""""""""""" - -Enables or disables the USB device interrupt(s). May be used to prevent concurrency issues when mutating data structures shared between main code and the interrupt handler. - -``dcd_int_handler()`` -""""""""""""""""""""" - -Processes all the hardware generated events e.g Bus reset, new data packet from host etc ... It will be called by application in the MCU USB interrupt handler. - -``dcd_set_address()`` -""""""""""""""""""""" - -Called when the device is given a new bus address. - -If your peripheral automatically changes address during enumeration (like the nrf52) you may leave this empty and also no queue an event for the corresponding SETUP packet. - -``dcd_remote_wakeup()`` -""""""""""""""""""""""" - -Called to remote wake up host when suspended (e.g hid keyboard) - -``dcd_connect()`` / ``dcd_disconnect()`` -"""""""""""""""""""""""""""""""""""""""" - -Connect or disconnect the data-line pull-up resistor. Define only if MCU has an internal pull-up. (BSP may define for MCU without internal pull-up.) - -Special events -~~~~~~~~~~~~~~ - -You must let TinyUSB know when certain events occur so that it can continue its work. There are a few methods you can call to queue events for TinyUSB to process. - -``dcd_event_bus_signal()`` -"""""""""""""""""""""""""" - -There are a number of events that your peripheral may communicate about the state of the bus. Here is an overview of what they are. Events in **BOLD** must be provided for TinyUSB to work. - - -* **DCD_EVENT_RESET** - Triggered when the host resets the bus causing the peripheral to reset. Do any other internal reset you need from the interrupt handler such as resetting the control endpoint. -* DCD_EVENT_SOF - Signals the start of a new USB frame. - -Calls to this look like: - -.. code-block:: c - - dcd_event_bus_signal(0, DCD_EVENT_BUS_RESET, true); - - -The first ``0`` is the USB peripheral number. Statically saying ``0`` is common for single USB device MCUs. - -The ``true`` indicates the call is from an interrupt handler and will always be the case when porting in this way. - -``dcd_setup_received()`` -"""""""""""""""""""""""" - -SETUP packets are a special type of transaction that can occur at any time on the control endpoint, numbered ``0``. Since they are unique, most peripherals have special handling for them. Their data is always 8 bytes in length as well. - -Calls to this look like: - -.. code-block:: c - - dcd_event_setup_received(0, setup, true); - - -As before with ``dcd_event_bus_signal()`` the first argument is the USB peripheral number and the third is true to signal its being called from an interrupt handler. The middle argument is byte array of length 8 with the contents of the SETUP packet. It can be stack allocated because it is copied into the queue. - -Endpoints -~~~~~~~~~ - -Endpoints are the core of the USB data transfer process. They come in a few forms such as control, isochronous, bulk, and interrupt. We won't cover the details here except with some caveats in open below. In general, data is transferred by setting up a buffer of a given length to be transferred on a given endpoint address and then waiting for an interrupt to signal that the transfer is finished. Further details below. - -Endpoints within USB have an address which encodes both the number and direction of an endpoint. TinyUSB provides ``tu_edpt_number()`` and ``tu_edpt_dir()`` to unpack this data from the address. Here is a snippet that does it. - -.. code-block:: c - - uint8_t epnum = tu_edpt_number(ep_addr); - uint8_t dir = tu_edpt_dir(ep_addr); - - -``dcd_edpt_open()`` -""""""""""""""""""" - -Opening an endpoint is done for all non-control endpoints once the host picks a configuration that the device should use. At this point, the endpoint should be enabled in the peripheral and configured to match the endpoint descriptor. Pay special attention to the direction of the endpoint you can get from the helper methods above. It will likely change what registers you are setting. - -Also make sure to enable endpoint specific interrupts. - -``dcd_edpt_close()`` -"""""""""""""""""""" - -Close an endpoint. his function is used for implementing alternate settings. - -After calling this, the device should not respond to any packets directed towards this endpoint. When called, this function must abort any transfers in progress through this endpoint, before returning. - -Implementation is optional. Must be called from the USB task. Interrupts could be disabled or enabled during the call. - -``dcd_edpt_xfer()`` -""""""""""""""""""" - -``dcd_edpt_xfer()`` is responsible for configuring the peripheral to send or receive data from the host. "xfer" is short for "transfer". **This is one of the core methods you must implement for TinyUSB to work (one other is the interrupt handler).** Data from the host is the OUT direction and data to the host is IN. It is used for all endpoints including the control endpoint 0. Make sure to handle the zero-length packet STATUS packet on endpoint 0 correctly. It may be a special transaction to the peripheral. - -Besides that, all other transactions are relatively straight-forward. The endpoint address provides the endpoint -number and direction which usually determines where to write the buffer info. The buffer and its length are usually -written to a specific location in memory and the peripheral is told the data is valid. (Maybe by writing a 1 to a -register or setting a counter register to 0 for OUT or length for IN.) - -The transmit buffer alignment is determined by ``CFG_TUSB_MEM_ALIGN``. - -One potential pitfall is that the buffer may be longer than the maximum endpoint size of one USB -packet. Some peripherals can handle transmitting multiple USB packets for a provided buffer (like the SAMD21). -Others (like the nRF52) may need each USB packet queued individually. To make this work you'll need to track -some state for yourself and queue up an intermediate USB packet from the interrupt handler. - -Once the transaction is going, the interrupt handler will notify TinyUSB of transfer completion. -During transmission, the IN data buffer is guaranteed to remain unchanged in memory until the ``dcd_xfer_complete()`` function is called. - -The ``dcd_edpt_xfer()`` function must never add zero-length-packets (ZLP) on its own to a transfer. If a ZLP is required, -then it must be explicitly sent by the stack calling ``dcd_edpt_xfer()``, by calling ``dcd_edpt_xfer()`` a second time with len=0. -For control transfers, this is automatically done in ``usbd_control.c``. - -At the moment, only a single buffer can be transmitted at once. There is no provision for double-buffering. new ``dcd_edpt_xfer()`` will not -be called again on the same endpoint address until the driver calls ``dcd_xfer_complete()`` (except in cases of USB resets). - -``dcd_xfer_complete()`` -""""""""""""""""""""""" - -Once a transfer completes you must call ``dcd_xfer_complete()`` from the USB interrupt handler to let TinyUSB know that a transaction has completed. Here is a sample call: - -.. code-block:: c - - dcd_event_xfer_complete(0, ep_addr, xfer->actual_len, XFER_RESULT_SUCCESS, true); - - -The arguments are: - - -* the USB peripheral number -* the endpoint address -* the actual length of the transfer. (OUT transfers may be smaller than the buffer given in ``dcd_edpt_xfer()``) -* the result of the transfer. Failure isn't handled yet. -* ``true`` to note the call is from an interrupt handler. - -``dcd_edpt_stall()`` / ``dcd_edpt_clear_stall()`` -""""""""""""""""""""""""""""""""""""""""""""""""" - -Stalling is one way an endpoint can indicate failure such as when an unsupported command is transmitted. The pair of ``dcd_edpt_stall()``, ``dcd_edpt_clear_stall()`` help manage the stall state of all endpoints. - -Woohoo! -------- - -At this point you should have everything working! 🙂 Of course, you may not write perfect code. Here are some tips and tricks for debugging. - -Use `WireShark `_ or `a Beagle `_ to sniff the USB traffic. When things aren't working its likely very early in the USB enumeration process. Figuring out where can help clue in where the issue is. For example: - - -* If the host sends a SETUP packet and its not ACKed then your USB peripheral probably isn't started correctly. -* If the peripheral is started correctly but it still didn't work, then verify your usb clock is correct. (You did output a PWM based on it right? 🙂) -* If the SETUP packet is ACKed but nothing is sent back then you interrupt handler isn't queueing the setup packet correctly. (Also, if you are using your own code instead of an example ``tud_task()`` may not be called.) If that's OK, the ``dcd_xfer_complete()`` may not be setting up the next transaction correctly. diff --git a/docs/faq.rst b/docs/faq.rst index ade51a379..a5fe09495 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -7,7 +7,7 @@ General Questions **Q: What microcontrollers does TinyUSB support?** -TinyUSB supports 30+ MCU families including STM32, RP2040, NXP (iMXRT, Kinetis, LPC), Microchip SAM, Nordic nRF5x, ESP32, and many others. See :doc:`reference/boards` for the complete list. +TinyUSB supports 50+ MCU families including STM32, RP2040, NXP (iMXRT, Kinetis, LPC), Microchip SAM, Nordic nRF5x, ESP32, and many others. See :doc:`reference/boards` for the complete list. **Q: Can I use TinyUSB in commercial projects?** @@ -178,33 +178,3 @@ ESP32-S3 has specific USB implementation challenges: - Check power supply requirements for host mode - Some features may be limited compared to other MCUs - Use ESP32-S3 specific examples and documentation - -STM32CubeIDE Integration -======================== - -**Q: How do I integrate TinyUSB with STM32CubeIDE?** - -1. In STM32CubeMX, enable USB_OTG_FS/HS under Connectivity, set to "Device_Only" mode -2. Enable the USB global interrupt in NVIC Settings -3. Add ``tusb.h`` include and call ``tusb_init()`` in main.c -4. Call ``tud_task()`` in your main loop -5. In the generated ``stm32xxx_it.c``, modify the USB IRQ handler to call ``tud_int_handler(0)`` -6. Create ``tusb_config.h`` and ``usb_descriptors.c`` files - -**Q: STM32CubeIDE generated code conflicts with TinyUSB** - -Don't use STM32's built-in USB middleware (USB Device Library) when using TinyUSB. Disable USB code generation in STM32CubeMX and let TinyUSB handle all USB functionality. - -**Q: STM32 USB interrupt handler setup** - -Replace the generated USB interrupt handler with a call to TinyUSB: - -.. code-block:: c - - void OTG_FS_IRQHandler(void) { - tud_int_handler(0); - } - -**Q: Which STM32 families work best with TinyUSB?** - -STM32F4, F7, and H7 families have the most mature TinyUSB support. STM32F0, F1, F3, L4 families are also supported but may have more limitations. Check the supported boards list for your specific variant. \ No newline at end of file diff --git a/docs/getting_started.rst b/docs/getting_started.rst index 32c80b91c..0c3fcec80 100644 --- a/docs/getting_started.rst +++ b/docs/getting_started.rst @@ -2,14 +2,39 @@ Getting Started *************** -This guide will get you up and running with TinyUSB quickly. We'll start with working examples, then show you how to integrate TinyUSB into your own projects. +This guide will get you up and running with TinyUSB quickly with working examples. + +Project Structure +==================== + +TinyUSB separates example applications from board-specific hardware configurations: + +* **Example applications**: Located in `examples/ `_ directories +* **Board Support Packages (BSP)**: Located in ``hw/bsp/FAMILY/boards/BOARD_NAME/`` with hardware abstraction including pin mappings, clock settings, and linker scripts +* **Build system**: Located in `examples/build_system/ `_ which supports both Make and CMake. Though some MCU families such as espressif or rp2040 only support cmake + +For example, stm32h743eval is located in `hw/bsp/stm32h7/boards/stm32h743eval `_ where ``FAMILY=stm32h7`` and ``BOARD=stm32h743eval``. When you build with ``BOARD=stm32h743eval``, the build system automatically finds the corresponding BSP using the FAMILY. + +For guidance on integrating TinyUSB into your own firmware (configuration, descriptors, initialization, and callback workflow), see :doc:`integration`. Quick Start Examples ==================== The fastest way to understand TinyUSB is to see it working. These examples demonstrate core functionality and can be built immediately. -We'll assume you are using the stm32f407disco board. For other boards, see ``Board Support Packages`` below. +We'll assume you are using the **STM32H743 Eval board** (BOARD=stm32h743eval) under the **stm32h7** family. For other boards, see ``Board Support Packages`` below. + +Get the Code +------------ + +.. code-block:: bash + + $ git clone https://github.com/hathach/tinyusb tinyusb + $ cd tinyusb + $ python tools/get_deps.py -b stm32h743eval # or python tools/get_deps.py stm32h7 + +.. note:: + For rp2040 `pico-sdk `_ or `esp-idf `_ for Espressif targets are required; install them per vendor instructions. Simple Device Example --------------------- @@ -17,20 +42,33 @@ Simple Device Example The `cdc_msc `_ example creates a USB device with both a virtual serial port (CDC) and mass storage (MSC). **What it does:** + * Appears as a serial port that echoes back any text you send * Appears as a small USB drive with a README.TXT file * Blinks an LED to show activity -**Build and run:** +**Build and run with CMake:** + +.. code-block:: bash + + $ cd examples/device/cdc_msc + $ cmake -DBOARD=stm32h743eval -B build # add "-G Ninja" to use Ninja build + $ cmake --build build + # cmake --build build --target cdc_msc-jlink + +.. tip:: + Flashed/Debugger can be selected with --target ``-jlink``, ``-stlink`` or ``-openocd`` depending on your board. Use ``--target help`` to list all supported targets. + +**Build and run with Make:** .. code-block:: bash - $ git clone https://github.com/hathach/tinyusb tinyusb - $ cd tinyusb - $ python tools/get_deps.py stm32f4 # download dependencies, note ESP and RP2 need their SDKs, too $ cd examples/device/cdc_msc - $ cmake -DBOARD=stm32f407disco -B build # add "-G Ninja ." on Windows - $ cmake --build build # add "--target cdc_msc-jlink" for flashing using J-Link, "--target help" to list targets + $ make BOARD=stm32h743eval all + $ make BOARD=stm32h743eval flash-jlink + +.. tip:: + Flashed/Debugger can be selected with target ``flash-jlink``, ``flash-stlink`` or ``flash-openocd`` depending on your board. Connect the device to your computer and you'll see both a new serial port and a small USB drive appear. @@ -40,113 +78,91 @@ Simple Host Example The `cdc_msc_hid `_ example creates a USB host that can connect to USB devices with CDC, MSC, or HID interfaces. **What it does:** + * Detects and enumerates connected USB devices * Communicates with CDC devices (like USB-to-serial adapters) * Reads from MSC devices (like USB drives) * Receives input from HID devices (like keyboards and mice) -**Build and run:** +**Build and run with CMake:** .. code-block:: bash - $ # initial setup see previous example $ cd examples/host/cdc_msc_hid - $ cmake -DBOARD=stm32f407disco -B build # add "-G Ninja ." on Windows - $ cmake --build build # add "--target cdc_msc_hid-jlink" for flashing using J-Link, "--target help" to list targets - -Connect USB devices to see enumeration messages and device-specific interactions in the serial output. - -Project Structure ------------------ - -TinyUSB separates example applications from board-specific hardware configurations: - -* **Example applications**: Located in `examples/device/ `_, `examples/host/ `_, and `examples/dual/ `_ directories -* **Board Support Packages (BSP)**: Located in ``hw/bsp/FAMILY/boards/BOARD_NAME/`` with hardware abstraction including pin mappings, clock settings, and linker scripts - -For example, raspberry_pi_pico is located in `hw/bsp/rp2040/boards/raspberry_pi_pico `_ where ``FAMILY=rp2040`` and ``BOARD=raspberry_pi_pico``. When you build with ``BOARD=raspberry_pi_pico``, the build system automatically finds the corresponding BSP using the FAMILY. - -Add TinyUSB to Your Project -============================ + $ cmake -DBOARD=stm32h743eval -B build + $ cmake --build build -Once you've seen TinyUSB working, here's how to integrate it into your own project: +**Build and run with Make:** -Integration Steps ------------------ +.. code-block:: bash -1. **Get TinyUSB**: Copy this repository or add it as a git submodule to your project at ``your_project/tinyusb`` + $ cd examples/host/cdc_msc_hid + $ make BOARD=stm32h743eval all + $ make BOARD=stm32h743eval flash-jlink -2. **Add source files**: Add all ``.c`` files from ``tinyusb/src/`` to your project +Connect USB devices to see enumeration messages and device-specific interactions in the serial output. -3. **Configure include paths**: Add ``your_project/tinyusb/src`` to your include path. Ensure your include path contains ``tusb_config.h`` +Additional Build Options +------------------------ -4. **Configure TinyUSB**: Create ``tusb_config.h`` with required macros like ``CFG_TUSB_MCU`` and ``CFG_TUSB_OS``. Copy from ``examples/device/*/tusb_config.h`` as a starting point +Debug and Logging +^^^^^^^^^^^^^^^^^ -5. **Implement USB descriptors**: For device stack, implement all ``tud_descriptor_*_cb()`` callbacks +TinyUSB built-in logging can be enabled by setting `CFG_TUSB_DEBUG` which is done by passing ``LOG=level``. The higher the level, the more verbose the logging. -6. **Initialize TinyUSB**: Add ``tusb_init()`` to your initialization code +In addition to traditional hw uart as default, logging with debugger such as `Segger RTT `_ (10x faster) is also supported with `LOGGER=rtt` option. -7. **Handle interrupts**: Call ``tusb_int_handler()`` from your USB IRQ handler +.. code-block:: bash -8. **Run USB tasks**: Call ``tud_task()`` (device) or ``tuh_task()`` (host) periodically in your main loop + $ cmake -B build -DBOARD=stm32h743eval -DLOG=2 # logging level 2 with uart + $ cmake -B build -DBOARD=stm32h743eval -DLOG=2 -DLOGGER=rtt # logging level 2 with RTT -9. **Implement class callbacks**: Implement callbacks for enabled USB classes +.. code-block:: bash -Simple Integration Example --------------------------- + $ make BOARD=stm32h743eval LOG=2 all # logging level 2 with uart + $ make BOARD=stm32h743eval LOG=2 LOGGER=rtt all # logging level 2 with RTT -.. code-block:: c +RootHub Port Selection +^^^^^^^^^^^^^^^^^^^^^^ - #include "tusb.h" +Some boards support multiple usb controllers (roothub ports), by default one rh port is used as device, another as host in ``board.mk/board.cmake``. This can be overridden with option ``RHPORT_DEVICE=n`` or ``RHPORT_HOST=n`` To choose another port. For example to select the HS port of a STM32F746Disco board, use: - int main(void) { - board_init(); // Your board initialization +.. code-block:: bash - tusb_rhport_init_t dev_init = { - .role = TUSB_ROLE_DEVICE, - .speed = TUSB_SPEED_AUTO - }; - // tud_descriptor_* callbacks omitted here - tusb_init(0, &dev_init); + $ cmake -B build -DBOARD=stm32h743eval -DRHPORT_DEVICE=1 # select roothub port 1 as device - while(1) { - tud_task(); // TinyUSB device task - your_application(); // Your application code - } - } +.. code-block:: bash - void USB_IRQHandler(void) { - tusb_int_handler(0, true); - } + $ make BOARD=stm32h743eval RHPORT_DEVICE=1 all # select roothub port 1 as device -.. note:: - Unlike many libraries, TinyUSB callbacks don't need to be explicitly registered. The stack automatically calls functions with specific names (e.g., ``tud_cdc_rx_cb()``) when events occur. Simply implement the callbacks you need. +RootHub Port Speed +^^^^^^^^^^^^^^^^^^ -.. note:: - TinyUSB uses consistent naming prefixes: ``tud_`` for device stack functions and ``tuh_`` for host stack functions. See the :doc:`reference/glossary` for more details. +A MCU can support multiple operational speed. By default, the example build system will use the fastest supported on the board. Use option ``RHPORT_DEVICE_SPEED=OPT_MODE_FULL/HIGH_SPEED/`` or ``RHPORT_HOST_SPEED=OPT_MODE_FULL/HIGH_SPEED/`` e.g To force operating speed -Development Tips -================ +.. code-block:: bash -**Debug builds and logging:** + $ cmake -B build -DBOARD=stm32h743eval -DRHPORT_DEVICE_SPEED=OPT_MODE_FULL_SPEED .. code-block:: bash - $ cmake -DBOARD=stm32f407disco -DDEBUG=1 ... # Debug build - $ cmake -DBOARD=stm32f407disco -DLOG=2 ... # Enable detailed logging + $ make BOARD=stm32h743eval RHPORT_DEVICE_SPEED=OPT_MODE_FULL_SPEED all + -**IAR Embedded Workbench:** +IAR Embedded Workbench +---------------------- For IAR users, project connection files are available. Import `tools/iar_template.ipcf `_ or use native CMake support (IAR 9.50.1+). See `tools/iar_gen.py `_ for automated project generation. + Common Issues and Solutions -=========================== +--------------------------- **Build Errors** * **"arm-none-eabi-gcc: command not found"**: Install ARM GCC toolchain: ``sudo apt-get install gcc-arm-none-eabi`` * **"Board 'X' not found"**: Check the available boards in ``hw/bsp/FAMILY/boards/`` or run ``python tools/build.py -l`` -* **Missing dependencies**: Run ``python tools/get_deps.py FAMILY`` where FAMILY matches your board +* **Missing dependencies**: Run ``python tools/get_deps.py FAMILY`` where FAMILY matches your board or ``python tools/get_deps.py -b BOARD`` **Runtime Issues** @@ -166,6 +182,7 @@ Some examples require udev permissions to access USB devices: Next Steps ========== +* Check :doc:`integration` for integrating TinyUSB into your own firmware * Check :doc:`reference/boards` for board-specific information * Explore more examples in `examples/device/ `_ and `examples/host/ `_ directories * Read :doc:`reference/usb_concepts` to understand USB fundamentals diff --git a/docs/index.rst b/docs/index.rst index ac10dbfd7..39d30a038 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,45 +1,21 @@ -TinyUSB Documentation -===================== - -TinyUSB is an open-source cross-platform USB Host/Device stack for embedded systems, designed to be memory-safe with no dynamic allocation and thread-safe with all interrupt events deferred to non-ISR task functions. - -For Developers --------------- - -TinyUSB provides a complete USB stack implementation supporting both device and host modes across a wide range of microcontrollers. The stack is designed for resource-constrained embedded systems with emphasis on code size, memory efficiency, and real-time performance. - -**Key Features:** - -* **Thread-safe design**: All USB interrupts are deferred to task context -* **Memory-safe**: No dynamic allocation, all buffers are statically allocated -* **Portable**: Supports 30+ MCU families from major vendors -* **Comprehensive**: Device classes (CDC, HID, MSC, Audio, etc.) and Host stack -* **RTOS support**: Works with bare metal, FreeRTOS, RT-Thread, and Mynewt - -**Quick Navigation:** - -* New to TinyUSB? Start with :doc:`getting_started` and :doc:`reference/glossary` -* Want to understand the design? Read :doc:`reference/architecture` and :doc:`reference/usb_concepts` -* Having issues? Check :doc:`faq` and :doc:`troubleshooting` - -Documentation Structure ------------------------ +.. include:: ../README_processed.rst .. toctree:: :maxdepth: 2 :caption: Information getting_started + integration + porting + reference/index faq troubleshooting - reference/index .. toctree:: :maxdepth: 1 :caption: Project Info info/index - contributing/index .. toctree:: :caption: External Links @@ -48,8 +24,3 @@ Documentation Structure Source Code Issue Tracker Discussions - -GitHub Project Main README -========================== - -.. include:: ../README_processed.rst diff --git a/docs/info/changelog.rst b/docs/info/changelog.rst index b4423f81e..d6bf846ed 100644 --- a/docs/info/changelog.rst +++ b/docs/info/changelog.rst @@ -20,6 +20,7 @@ API Changes ----------- - Core APIs + - Add weak callbacks with new syntax for better compiler compatibility - Add ``tusb_deinit()`` to cleanup stack - Add time functions: ``tusb_time_millis_api()`` and ``tusb_time_delay_ms_api()`` @@ -27,6 +28,7 @@ API Changes - Introduce ``xfer_isr()`` callback for ISO transfer optimization in device classes - Device APIs + - CDC: Add notification support ``tud_cdc_configure()``, ``tud_cdc_n_notify_uart_state()``, ``tud_cdc_n_notify_conn_speed_change()``, ``tud_cdc_notify_complete_cb()`` - MSC: Add ``tud_msc_inquiry2_cb()`` with bufsize parameter, update ``tud_msc_async_io_done()`` @@ -36,6 +38,7 @@ API Changes ``tud_mtp_response_send()``, ``tud_mtp_event_send()`` - Host APIs + - Core: Add ``tuh_edpt_close()``, ``tuh_address_set()``, ``tuh_descriptor_get_device_local()``, ``tuh_descriptor_get_string_langid()``, ``tuh_connected()``, ``tuh_bus_info_get()`` - Add enumeration callbacks: ``tuh_enum_descriptor_device_cb()``, @@ -50,6 +53,7 @@ Controller Driver (DCD & HCD) ----------------------------- - DWC2 + - Support DWC2 v4.30a with improved reset procedure - Fix core reset: wait for AHB idle before reset - Add STM32 DWC2 data cache support with proper alignment @@ -64,6 +68,7 @@ Controller Driver (DCD & HCD) - Refactor bitfields for better code generation - FSDEV (STM32) + - Fix AT32 compile issues after single-buffered endpoint changes - Add configurable single-buffered isochronous endpoints - Fix STM32H7 recurrent suspend ISR @@ -72,35 +77,42 @@ Controller Driver (DCD & HCD) - Improve PMA size handling for STM32U0 - EHCI + - Fix removed QHD getting reused - Fix NXP USBPHY disconnection detection - Chipidea/NXP + - Fix race condition with spinlock - Improve iMXRT support: fix build, disable BOARD_ConfigMPU, fix attach debouncing on port1 highspeed - Fix iMXRT1064 and add to HIL test pool - MAX3421E + - Use spinlock for thread safety instead of atomic flag - Implement ``hcd_edpt_close()`` - RP2040 + - Fix audio ISO transfer: reset state before notifying stack - Fix CMake RTOS cache variable - Abort transfer if active in ``iso_activate()`` - SAMD + - Add host controller driver support Device Stack ------------ - USBD Core + - Introduce ``xfer_isr()`` callback for interrupt-time transfer handling - Add ``usbd_edpt_xfer_fifo()`` stub - Revert endpoint busy/claim status if ``xfer_isr()`` defers to ``xfer_cb()`` - Audio + - Major simplification of UAC driver and alt settings management - Move ISO transfers into ``xfer_isr()`` for better performance - Remove FIFO mutex (single producer/consumer optimization) @@ -109,25 +121,30 @@ Device Stack - Update buffer macros with cache line size alignment - CDC + - Add notification support: ``CFG_TUD_CDC_NOTIFY``, ``tud_cdc_n_notify_conn_speed_change()``, ``tud_cdc_notify_complete_cb()`` - Reduce default bInterval from 16ms to 1ms for better responsiveness - Rename ``tud_cdc_configure_fifo()`` to ``tud_cdc_configure()`` and add ``tx_overwritable_if_not_connected`` option - Fix web serial robustness with major overhaul and logic cleanup - HID + - Add Usage Page and Table for Power Devices (0x84 - 0x85) - Fix HID descriptor parser variable size and 4-byte item handling - Add consumer page configurations - MIDI + - Fix MIDI interface descriptor handling after audio streaming interface - Skip RX data with all zeroes - MSC + - Add async I/O support for MSC using ``tud_msc_async_io_done()`` - Add ``tud_msc_inquiry2_cb()`` with bufsize for full inquiry response - MTP + - Add new Media Transfer Protocol (MTP) device class driver - Support MTP operations: GetDeviceInfo, SendObjectInfo, SendObject - Add MTP event support with ``tud_mtp_event_send()`` @@ -135,13 +152,16 @@ Device Stack - Add hardware-in-the-loop testing support - NCM + - Add USB NCM link state control support - Fix DHCP offer/ACK destination - USBTMC + - Add vendor-specific message support - Vendor + - Fix vendor device reset and open issues - Fix descriptor parsing for ``CFG_TUD_VENDOR > 1`` - Fix vendor FIFO argument calculation @@ -150,6 +170,7 @@ Host Stack ---------- - USBH Core + - Major enumeration improvements: - Fix enumeration racing conditions - Add proper attach debouncing with hub/rootport handling (200ms delay) @@ -173,6 +194,7 @@ Host Stack - Force removed devices in same bus info before setting address - CDC Serial Host + - Major refactor to generalize CDC serial drivers (FTDI, CP210x, CH34x, PL2303, ACM) - Add explicit ``sync()`` API with ``TU_API_SYNC()`` returning ``tusb_xfer_result_t`` - Rename ``tuh_cdc_get_local_line_coding()`` to ``tuh_cdc_get_line_coding_local()`` @@ -180,6 +202,7 @@ Host Stack - Implement ``tuh_cdc_get/set_dtr/rts()`` as inline functions - MIDI Host + - Major API changes: - Rename ``tuh_midi_stream_flush()`` to ``tuh_midi_write_flush()`` - Add ``tuh_midi_packet_read_n()`` and ``tuh_midi_packet_write_n()`` @@ -189,9 +212,11 @@ Host Stack - Add ``tuh_midi_descriptor_cb()`` and ``tuh_midi_itf_get_info()`` - MSC Host + - Continue async I/O improvements - HID Host + - Fix version string to actually show version 0.18.0 @@ -226,6 +251,7 @@ Controller Driver (DCD & HCD) ----------------------------- - DWC2 + - Add DMA support for both device and host controller - Add host driver support including: full/high speed, control/bulk/interrupt (CBI) transfer, split CBI i.e FS/LS attached via highspeed hub, hub support @@ -695,6 +721,7 @@ Controller Driver (DCD & HCD) ----------------------------- - [DWC2] Generalize synopsys dwc2 with synopsys/dwc2 which support both FS and HS phy (UTMI and ULPI) for various MCUs. + - Broadcom 28/27xx on raspberrypi SBC - Silicon Labs EFM32 - Espressif ESP32 Sx @@ -916,6 +943,7 @@ HID - Add more hid keys constant from 0x6B to 0xA4 - [Breaking] rename API + - ``HID_PROTOCOL_NONE/KEYBOARD/MOUSE`` to ``HID_ITF_PROTOCOL_NONE/KEYBOARD/MOUSE`` - ``tud_hid_boot_mode()`` to ``tud_hid_get_protocol()`` - ``tud_hid_boot_mode_cb()`` to ``tud_hid_set_protocol_cb()`` @@ -925,6 +953,7 @@ MIDI - Fix MIDI buffer overflow issue - [Breaking] rename API + - Rename ``tud_midi_read()`` to ``tud_midi_stream_read()`` - Rename ``tud_midi_write()`` to ``tud_midi_stream_write()`` - Rename ``tud_midi_receive()`` to ``tud_midi_packet_read()`` @@ -1075,15 +1104,19 @@ Device Controller Driver - Use ``dcd_event_bus_reset()`` with link speed to replace bus_signal - ESP32-S2: + - Add bus suspend and wakeup support - SAMD21: + - Fix (walkaround) samd21 setup_packet overflow by USB DMA - STM32 Synopsys: + - Rework USB FIFO allocation scheme and allow RX FIFO size reduction - Sony CXD56 + - Update Update Spresense SDK to 2.0.2 - Fix dcd issues with setup packets - Correct EP number for cdc_msc example @@ -1100,19 +1133,24 @@ USB Device **Class Driver** - CDC + - Allow to transmit data, even if the host does not support control line states i.e set DTR - HID + - change default ``CFG_TUD_HID_EP_BUFSIZE`` from 16 to 64 - MIDI + - Fix midi sysex sending bug - MSC + - Invoke only scsi complete callback after status transaction is complete. - Fix ``scsi_mode_sense6_t`` padding, which cause IAR compiler internal error. - USBTMC + - Change interrupt endpoint example size to 8 instead of 2 for better compatibility with mcu **Example** @@ -1154,6 +1192,7 @@ Device Controller Driver - Enhance STM32 Synopsys - Support bus events disconnection/suspend/resume/wakeup + - Improve transfer performance with optimizing xfer and fifo size - Support Highspeed port (OTG_HS) with both internal and external PHY - Support multiple usb ports with rhport=1 is highspeed on selected MCUs e.g H743, F23. It is possible to have OTG_HS to run on Fullspeed PHY (e.g lacking external PHY) @@ -1163,6 +1202,7 @@ Device Controller Driver - Support F105, F107 - Enhance STM32 fsdev + - Improve dcd fifo allocation - Fix ISTR race condition - Support remap USB IRQ on supported MCUs @@ -1171,6 +1211,7 @@ Device Controller Driver - Enhance NUC 505: enhance set configure behavior - Enhance SAMD + - Fix race condition with setup packet - Add SAMD11 option ``OPT_MCU_SAMD11`` - Add SAME5x option ``OPT_MCU_SAME5X`` @@ -1178,6 +1219,7 @@ Device Controller Driver - Fix SAMG control data toggle and stall race condition - Enhance nRF + - Fix hanged when ``tud_task()`` is called within critical section (disabled interrupt) - Fix disconnect bus event not submitted - Implement ISO transfer and ``dcd_edpt_close()`` @@ -1203,6 +1245,7 @@ USB Device - Improve USB Highspeed support with actual link speed detection with ``dcd_event_bus_reset()`` - Enhance class driver management + - ``usbd_driver_open()`` add max length argument, and return length of interface (0 for not supported). Return value is used for finding appropriate driver - Add application implemented class driver via ``usbd_app_driver_get_cb()`` - IAD is handled to assign driver id @@ -1219,11 +1262,13 @@ USB Device - USBTMC: fix descriptors when INT EP is disabled - CDC: + - Send zero length packet for end of data when needed - Add ``tud_cdc_tx_complete_cb()`` callback - Change ``tud_cdc_n_write_flush()`` return number of bytes forced to transfer, and flush when writing enough data to fifo - MIDI: + - Add packet interface - Add multiple jack descriptors - Fix MIDI driver for sysex @@ -1231,12 +1276,14 @@ USB Device - DFU Runtime: fix response to SET_INTERFACE and DFU_GETSTATUS request - Rename some configure macro to make it clear that those are used directly for endpoint transfer + - ``CFG_TUD_HID_BUFSIZE`` to ``CFG_TUD_HID_EP_BUFSIZE`` - ``CFG_TUD_CDC_EPSIZE`` to ``CFG_TUD_CDC_EP_BUFSIZE`` - ``CFG_TUD_MSC_BUFSIZE`` to ``CFG_TUD_MSC_EP_BUFSIZE`` - ``CFG_TUD_MIDI_EPSIZE`` to ``CFG_TUD_MIDI_EP_BUFSIZE`` - HID: + - Fix gamepad template descriptor - Add multiple HID interface API - Add extra comma to HID_REPORT_ID @@ -1258,6 +1305,7 @@ Examples - Add new ``hid_multiple_interface`` - Enhance ``net_lwip_webserver`` example + - Add multiple configuration: RNDIS for Windows, CDC-ECM for macOS (Linux will work with both) - Update lwip to STABLE-2_1_2_RELEASE for ``net_lwip_webserver`` diff --git a/docs/info/code_of_conduct.rst b/docs/info/code_of_conduct.rst new file mode 100644 index 000000000..2d70708d4 --- /dev/null +++ b/docs/info/code_of_conduct.rst @@ -0,0 +1 @@ +.. include:: ../../CODE_OF_CONDUCT.rst diff --git a/docs/info/index.rst b/docs/info/index.rst index a636f37dc..b6d30b432 100644 --- a/docs/info/index.rst +++ b/docs/info/index.rst @@ -10,3 +10,4 @@ Index changelog contributors + code_of_conduct diff --git a/docs/integration.rst b/docs/integration.rst new file mode 100644 index 000000000..3480746d0 --- /dev/null +++ b/docs/integration.rst @@ -0,0 +1,93 @@ +******************* +Integrating TinyUSB +******************* + +Once you've seen TinyUSB working in the examples, use this guide to wire the stack into your own firmware. + +Integration Steps +================= + +1. **Get TinyUSB**: Copy this repository or add it as a git submodule to your project at ``your_project/tinyusb``. +2. **Add source files**: Add every ``.c`` file from ``tinyusb/src/`` to your project build system. + +.. note:: + Only supported dcd/hcd drivers for your CPU sources under ``tinyusb/src/portable/vendor/usbip/`` are needed. Add + +3. **Configure TinyUSB**: Create ``tusb_config.h`` with macros such as ``CFG_TUSB_MCU``, ``CFG_TUSB_OS``, and class enable flags. Start from any example's ``tusb_config.h`` and tweak. +4. **Configure include paths**: Add ``your_project/tinyusb/src`` (and the folder holding ``tusb_config.h``) to your include paths. +5. **Implement USB descriptors**: For device stack, implement the ``tud_descriptor_*_cb()`` callbacks (device) or host descriptor helpers that match your product. +6. **Initialize TinyUSB**: Call ``tusb_init()`` once the clocks/peripherals are ready. Pass ``tusb_rhport_init_t`` if you need per-port settings. +7. **Handle interrupts**: From the USB ISR call ``tusb_int_handler(rhport, true)`` so the stack can process events. +8. **Run USB tasks**: Call ``tud_task()`` (device) or ``tuh_task()`` (host) regularly from the main loop, RTOS task. +9. **Implement class callbacks**: Provide the callbacks for the classes you enabled (e.g., ``tud_cdc_rx_cb()``, ``tuh_msc_mount_cb()``). + +Minimal Example +=============== + +.. code-block:: c + + #include "tusb.h" + + int main(void) { + board_init(); // Your board initialization + + // Init device stack on roothub port 0 for highspeed device + tusb_rhport_init_t dev_init = { + .role = TUSB_ROLE_DEVICE, + .speed = TUSB_SPEED_HIGH + }; + tusb_init(0, &dev_init); + + // init host stack on roothub port 1 for fullspeed host + tusb_rhport_init_t host_init = { + .role = TUSB_ROLE_DEVICE, + .speed = TUSB_SPEED_FULL + }; + tusb_init(1, &host_init); + + while (1) { + tud_task(); // device task + tuh_task(); // host task + + app_task(); // Your application logic + } + } + + void USB0_IRQHandler(void) { + // forward interrupt port 0 to TinyUSB stack + tusb_int_handler(0, true); + } + + void USB1_IRQHandler(void) { + // forward interrupt port 0 to TinyUSB stack + tusb_int_handler(1, true); + } + +.. note:: + Unlike many libraries, TinyUSB callbacks don't need to be registered. Implement functions with the prescribed names (for example ``tud_cdc_rx_cb()``) and the stack will invoke them automatically. + +.. note:: + Naming follows ``tud_*`` for device APIs and ``tuh_*`` for host APIs. Refer to :doc:`reference/glossary` for a summary of the prefixes and callback naming rules. + + +STM32CubeIDE Integration +======================== + +To integrate TinyUSB device stack with STM32CubeIDE + +1. In STM32CubeMX, enable USB_OTG_FS/HS under Connectivity, set to "Device_Only" mode +2. Enable the USB global interrupt in NVIC Settings +3. Add ``tusb.h`` include and call ``tusb_init()`` in main.c +4. Call ``tud_task()`` in your main loop +5. In the generated ``stm32xxx_it.c``, modify the USB IRQ handler to call ``tud_int_handler(0)`` + +.. code-block:: c + + void OTG_FS_IRQHandler(void) { + tud_int_handler(0); + } + +6. Create ``tusb_config.h`` and ``usb_descriptors.c`` files + +.. tip:: + STM32CubeIDE generated code conflicts with TinyUSB. Don't use STM32's built-in USB middleware (USB Device Library) when using TinyUSB. Disable USB code generation in STM32CubeMX and let TinyUSB handle all USB functionality. diff --git a/docs/porting.rst b/docs/porting.rst new file mode 100644 index 000000000..c3076354c --- /dev/null +++ b/docs/porting.rst @@ -0,0 +1,243 @@ + +******* +Porting +******* + +TinyUSB is designed to be a universal USB protocol stack for microcontrollers. It +handles most of the high level USB protocol and relies on the microcontroller's USB peripheral for +data transactions on different endpoints. Porting is the process of adding low-level support for +the rest of the common stack. Once the low-level is implemented, it is very easy to add USB support +for the microcontroller to other projects, especially those already using TinyUSB such as CircuitPython. + +Below are instructions on how to get the cdc_msc device example running on a new microcontroller. Doing so includes adding the common code necessary for other uses while minimizing other extra code. Whenever you see a phrase or word in ``<>`` it should be replaced. + +Register defs +------------- + +The first step to adding support is including the register definitions and startup code for the +microcontroller in TinyUSB. We write the TinyUSB implementation against these structs instead of higher level functions to keep the code small and to prevent function name collisions in linking of larger projects. For ARM microcontrollers this is the CMSIS definitions. They should be +placed in the ``hw/mcu//`` directory. + +Once this is done, create a directory in ``hw/bsp/`` for the specific board you are using to test the code (duplicating an existing board's directory is the best way to get started). The board should be a readily available development board so that others can also test. + +Build +----- + +Now that those directories are in place, we can start our iteration process to get the example building successfully. To build, run from the root of TinyUSB: + +.. code-block:: bash + + make -C examples/device/cdc_msc BOARD= + +Unless you've read ahead, this will fail miserably. Now, lets get it to fail less by updating the files in the board directory. The code in the board's directory is responsible for setting up the microcontroller's clocks and pins so that USB works. TinyUSB itself only operates on the USB peripheral. The board directory also includes information what files are needed to build the example. + +One of the first things to change is the ``-DCFG_TUSB_MCU`` C flag in the ``board.mk`` file. This is used to tell TinyUSB what platform is being built. So, add an entry to ``src/tusb_option.h`` and update the ``CFLAGS`` to match. + +Update ``board.mk``'s VENDOR and CHIP_FAMILY values when creating the directory for the struct files. Duplicate one of the other sources from ``src/portable`` into ``src/portable//`` and delete all of the implementation internals. We'll cover what everything there does later. For now, get it compiling. + +Implementation +-------------- + +At this point you should get an error due to an implementation issue and hopefully the build is setup for the new MCU. You will still need to modify the ``board.mk`` to include specific ``CFLAGS``, the linker script, linker flags, source files, include directories. All file paths are relative to the top of the TinyUSB repo. + +Board Support (BSP) +^^^^^^^^^^^^^^^^^^^ + +The board support code is only used for self-contained examples and testing. It is not used when TinyUSB is part of a larger project. Its responsible for getting the MCU started and the USB peripheral clocked. It also optionally provides LED definitions that are used to blink an LED to show that the code is running. + +It is located in ``hw/bsp//board_.c``. + +``board_init()`` +~~~~~~~~~~~~~~~~ + +``board_init()`` is responsible for starting the MCU, setting up the USB clock and USB pins. It is also responsible for initializing LED pins. + +One useful clock debugging technique is to set up a PWM output at a known value such as 500hz based on the USB clock so that you can verify it is correct with a logic probe or oscilloscope. + +Setup your USB in a crystal-less mode when available. That makes the code easier to port across boards. + +``board_led_write()`` +~~~~~~~~~~~~~~~~~~~~~ + +Feel free to skip this until you want to verify your demo code is running. To implement, set the pin corresponding to the led to output a value that lights the LED when ``state`` is true. + +OS Abstraction Layer (OSAL) +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The OS Abstraction Layer is responsible for providing basic data structures for TinyUSB that may allow for concurrency when used with an RTOS. Without an RTOS it simply handles concurrency issues between the main code and interrupts. The code is almost entirely agnostic of MCU and lives in ``src/osal``. + +In RTOS configurations, ``tud_task()``/``tuh_task()`` blocks behind a synchronization structure when the event queue is empty, so that the scheduler may give the CPU to a different task. To take advantage of the library's capability to yield the CPU when there are no actionable USB device events, ensure that the ``CFG_TUSB_OS`` symbol is defined, e.g ``OPT_OS_FREERTOS`` enables the FreeRTOS scheduler to schedule other threads than that which calls ``tud_task()``/``tuh_task()``. + +Device API +^^^^^^^^^^ + +After the USB device is setup, the USB device code works by processing events on the main thread (by calling ``tud_task()``). These events are queued by the USB interrupt handler. So, there are three parts to the device low-level API: device setup, endpoint setup and interrupt processing. + +All of the code for the low-level device API is in ``src/portable///dcd_.c``. + +Device Setup +~~~~~~~~~~~~ + +``dcd_init()`` +"""""""""""""" + +Initializes the USB peripheral for device mode and enables it. +This function should enable internal D+/D- pull-up for enumeration. + +``dcd_int_enable()`` / ``dcd_int_disable()`` +"""""""""""""""""""""""""""""""""""""""""""" + +Enables or disables the USB device interrupt(s). May be used to prevent concurrency issues when mutating data structures shared between main code and the interrupt handler. + +``dcd_int_handler()`` +""""""""""""""""""""" + +Processes all the hardware generated events e.g Bus reset, new data packet from host etc ... It will be called by application in the MCU USB interrupt handler. + +``dcd_set_address()`` +""""""""""""""""""""" + +Called when the device is given a new bus address. + +If your peripheral automatically changes address during enumeration (like the nrf52) you may leave this empty and also no queue an event for the corresponding SETUP packet. + +``dcd_remote_wakeup()`` +""""""""""""""""""""""" + +Called to remote wake up host when suspended (e.g hid keyboard) + +``dcd_connect()`` / ``dcd_disconnect()`` +"""""""""""""""""""""""""""""""""""""""" + +Connect or disconnect the data-line pull-up resistor. Define only if MCU has an internal pull-up. (BSP may define for MCU without internal pull-up.) + +Special events +~~~~~~~~~~~~~~ + +You must let TinyUSB know when certain events occur so that it can continue its work. There are a few methods you can call to queue events for TinyUSB to process. + +``dcd_event_bus_signal()`` +"""""""""""""""""""""""""" + +There are a number of events that your peripheral may communicate about the state of the bus. Here is an overview of what they are. Events in **BOLD** must be provided for TinyUSB to work. + + +* **DCD_EVENT_RESET** - Triggered when the host resets the bus causing the peripheral to reset. Do any other internal reset you need from the interrupt handler such as resetting the control endpoint. +* DCD_EVENT_SOF - Signals the start of a new USB frame. + +Calls to this look like: + +.. code-block:: c + + dcd_event_bus_signal(0, DCD_EVENT_BUS_RESET, true); + + +The first ``0`` is the USB peripheral number. Statically saying ``0`` is common for single USB device MCUs. + +The ``true`` indicates the call is from an interrupt handler and will always be the case when porting in this way. + +``dcd_setup_received()`` +"""""""""""""""""""""""" + +SETUP packets are a special type of transaction that can occur at any time on the control endpoint, numbered ``0``. Since they are unique, most peripherals have special handling for them. Their data is always 8 bytes in length as well. + +Calls to this look like: + +.. code-block:: c + + dcd_event_setup_received(0, setup, true); + + +As before with ``dcd_event_bus_signal()`` the first argument is the USB peripheral number and the third is true to signal its being called from an interrupt handler. The middle argument is byte array of length 8 with the contents of the SETUP packet. It can be stack allocated because it is copied into the queue. + +Endpoints +~~~~~~~~~ + +Endpoints are the core of the USB data transfer process. They come in a few forms such as control, isochronous, bulk, and interrupt. We won't cover the details here except with some caveats in open below. In general, data is transferred by setting up a buffer of a given length to be transferred on a given endpoint address and then waiting for an interrupt to signal that the transfer is finished. Further details below. + +Endpoints within USB have an address which encodes both the number and direction of an endpoint. TinyUSB provides ``tu_edpt_number()`` and ``tu_edpt_dir()`` to unpack this data from the address. Here is a snippet that does it. + +.. code-block:: c + + uint8_t epnum = tu_edpt_number(ep_addr); + uint8_t dir = tu_edpt_dir(ep_addr); + + +``dcd_edpt_open()`` +""""""""""""""""""" + +Opening an endpoint is done for all non-control endpoints once the host picks a configuration that the device should use. At this point, the endpoint should be enabled in the peripheral and configured to match the endpoint descriptor. Pay special attention to the direction of the endpoint you can get from the helper methods above. It will likely change what registers you are setting. + +Also make sure to enable endpoint specific interrupts. + +``dcd_edpt_close()`` +"""""""""""""""""""" + +Close an endpoint. his function is used for implementing alternate settings. + +After calling this, the device should not respond to any packets directed towards this endpoint. When called, this function must abort any transfers in progress through this endpoint, before returning. + +Implementation is optional. Must be called from the USB task. Interrupts could be disabled or enabled during the call. + +``dcd_edpt_xfer()`` +""""""""""""""""""" + +``dcd_edpt_xfer()`` is responsible for configuring the peripheral to send or receive data from the host. "xfer" is short for "transfer". **This is one of the core methods you must implement for TinyUSB to work (one other is the interrupt handler).** Data from the host is the OUT direction and data to the host is IN. It is used for all endpoints including the control endpoint 0. Make sure to handle the zero-length packet STATUS packet on endpoint 0 correctly. It may be a special transaction to the peripheral. + +Besides that, all other transactions are relatively straight-forward. The endpoint address provides the endpoint +number and direction which usually determines where to write the buffer info. The buffer and its length are usually +written to a specific location in memory and the peripheral is told the data is valid. (Maybe by writing a 1 to a +register or setting a counter register to 0 for OUT or length for IN.) + +The transmit buffer alignment is determined by ``CFG_TUSB_MEM_ALIGN``. + +One potential pitfall is that the buffer may be longer than the maximum endpoint size of one USB +packet. Some peripherals can handle transmitting multiple USB packets for a provided buffer (like the SAMD21). +Others (like the nRF52) may need each USB packet queued individually. To make this work you'll need to track +some state for yourself and queue up an intermediate USB packet from the interrupt handler. + +Once the transaction is going, the interrupt handler will notify TinyUSB of transfer completion. +During transmission, the IN data buffer is guaranteed to remain unchanged in memory until the ``dcd_xfer_complete()`` function is called. + +The ``dcd_edpt_xfer()`` function must never add zero-length-packets (ZLP) on its own to a transfer. If a ZLP is required, +then it must be explicitly sent by the stack calling ``dcd_edpt_xfer()``, by calling ``dcd_edpt_xfer()`` a second time with len=0. +For control transfers, this is automatically done in ``usbd_control.c``. + +At the moment, only a single buffer can be transmitted at once. There is no provision for double-buffering. new ``dcd_edpt_xfer()`` will not +be called again on the same endpoint address until the driver calls ``dcd_xfer_complete()`` (except in cases of USB resets). + +``dcd_xfer_complete()`` +""""""""""""""""""""""" + +Once a transfer completes you must call ``dcd_xfer_complete()`` from the USB interrupt handler to let TinyUSB know that a transaction has completed. Here is a sample call: + +.. code-block:: c + + dcd_event_xfer_complete(0, ep_addr, xfer->actual_len, XFER_RESULT_SUCCESS, true); + + +The arguments are: + + +* the USB peripheral number +* the endpoint address +* the actual length of the transfer. (OUT transfers may be smaller than the buffer given in ``dcd_edpt_xfer()``) +* the result of the transfer. Failure isn't handled yet. +* ``true`` to note the call is from an interrupt handler. + +``dcd_edpt_stall()`` / ``dcd_edpt_clear_stall()`` +""""""""""""""""""""""""""""""""""""""""""""""""" + +Stalling is one way an endpoint can indicate failure such as when an unsupported command is transmitted. The pair of ``dcd_edpt_stall()``, ``dcd_edpt_clear_stall()`` help manage the stall state of all endpoints. + +Woohoo! +------- + +At this point you should have everything working! 🙂 Of course, you may not write perfect code. Here are some tips and tricks for debugging. + +Use `WireShark `_ or `a Beagle `_ to sniff the USB traffic. When things aren't working its likely very early in the USB enumeration process. Figuring out where can help clue in where the issue is. For example: + + +* If the host sends a SETUP packet and its not ACKed then your USB peripheral probably isn't started correctly. +* If the peripheral is started correctly but it still didn't work, then verify your usb clock is correct. (You did output a PWM based on it right? 🙂) +* If the SETUP packet is ACKed but nothing is sent back then you interrupt handler isn't queueing the setup packet correctly. (Also, if you are using your own code instead of an example ``tud_task()`` may not be called.) If that's OK, the ``dcd_xfer_complete()`` may not be setting up the next transaction correctly. diff --git a/docs/reference/architecture.rst b/docs/reference/architecture.rst index 8e4c6890e..70ea17ed4 100644 --- a/docs/reference/architecture.rst +++ b/docs/reference/architecture.rst @@ -42,36 +42,23 @@ Layer Structure TinyUSB follows a layered architecture from hardware to application: -.. code-block:: none +.. figure:: ../assets/stack.svg + :width: 500px + :align: left + :alt: stackup + +.. raw:: html - ┌─────────────────────────────────────────┐ - │ Application Layer │ ← Your code - ├─────────────────────────────────────────┤ - │ USB Class Drivers │ ← CDC, HID, MSC, etc. - ├─────────────────────────────────────────┤ - │ Device/Host Stack Core │ ← USB protocol handling - ├─────────────────────────────────────────┤ - │ Hardware Abstraction (DCD/HCD) │ ← MCU-specific drivers - ├─────────────────────────────────────────┤ - │ OS Abstraction (OSAL) │ ← RTOS integration - ├─────────────────────────────────────────┤ - │ Common Utilities & FIFO │ ← Shared components - └─────────────────────────────────────────┘ +
Component Overview ------------------ -**Application Layer**: Your main application code that uses TinyUSB APIs. - -**Class Drivers**: Implement specific USB device classes (CDC, HID, MSC, etc.) and handle class-specific requests. - -**Device/Host Core**: Implements USB protocol state machines, endpoint management, and core USB functionality. - -**Hardware Abstraction**: MCU-specific code that interfaces with USB peripheral hardware. - -**OS Abstraction**: Provides threading primitives and synchronization for different RTOS environments. - -**Common Utilities**: Shared code including FIFO implementations, binary helpers, and utility functions. +- **Application Layer**: Your main application code that uses TinyUSB APIs. +- **Class Drivers**: Implement specific USB device classes (CDC, HID, MSC, etc.) and handle class-specific requests. +- **Device/Host Core**: Implements USB protocol state machines, endpoint management, and core USB functionality. +- **OS Abstraction**: Provides threading primitives and synchronization for different RTOS environments. +- **Device/Host Controller Driver**: drivers that interface with MCU USB peripherals. Several MCUs may share a common driver. Device Stack Architecture ========================= @@ -85,7 +72,7 @@ Core Components - MCU-specific USB device peripheral driver - Handles endpoint configuration and data transfers - Abstracts hardware differences between MCU families -- Located in ``src/portable/VENDOR/FAMILY/`` +- Located in ``src/portable/VENDOR/USBIP/`` **USB Device Core (USBD)**: - Implements USB device state machine diff --git a/docs/reference/boards.rst b/docs/reference/boards.rst index e668e2693..12da5c90b 100644 --- a/docs/reference/boards.rst +++ b/docs/reference/boards.rst @@ -107,17 +107,20 @@ olimex_emz64 Olimex PIC32-EMZ64 pic32mz http olimex_hmz144 Olimex PIC32-HMZ144 pic32mz https://www.olimex.com/Products/PIC/Development/PIC32-HMZ144/open-source-hardware cynthion_d11 Great Scott Gadgets Cynthion samd11 https://greatscottgadgets.com/cynthion/ samd11_xplained SAMD11 Xplained Pro samd11 https://www.microchip.com/en-us/development-tool/ATSAMD11-XPRO -atsamd21_xpro SAMD21 Xplained Pro samd21 https://www.microchip.com/DevelopmentTools/ProductDetails/ATSAMD21-XPRO -circuitplayground_express Adafruit Circuit Playground Express samd21 https://www.adafruit.com/product/3333 -curiosity_nano SAMD21 Curiosty Nano samd21 https://www.microchip.com/en-us/development-tool/dm320119 -cynthion_d21 Great Scott Gadgets Cynthion samd21 https://greatscottgadgets.com/cynthion/ -feather_m0_express Adafruit Feather M0 Express samd21 https://www.adafruit.com/product/3403 -itsybitsy_m0 Adafruit ItsyBitsy M0 samd21 https://www.adafruit.com/product/3727 -metro_m0_express Adafruit Metro M0 Express samd21 https://www.adafruit.com/product/3505 -qtpy Adafruit QT Py samd21 https://www.adafruit.com/product/4600 -seeeduino_xiao Seeeduino XIAO samd21 https://wiki.seeedstudio.com/Seeeduino-XIAO/ -sparkfun_samd21_mini_usb SparkFun SAMD21 Mini samd21 https://www.sparkfun.com/products/13664 -trinket_m0 Adafruit Trinket M0 samd21 https://www.adafruit.com/product/3500 +atsamd21_xpro SAMD21 Xplained Pro samd2x_l2x https://www.microchip.com/DevelopmentTools/ProductDetails/ATSAMD21-XPRO +atsaml21_xpro SAML21 Xplained Pro samd2x_l2x https://www.microchip.com/en-us/development-tool/atsaml21-xpro-b +circuitplayground_express Adafruit Circuit Playground Express samd2x_l2x https://www.adafruit.com/product/3333 +curiosity_nano SAMD21 Curiosty Nano samd2x_l2x https://www.microchip.com/en-us/development-tool/dm320119 +cynthion_d21 Great Scott Gadgets Cynthion samd2x_l2x https://greatscottgadgets.com/cynthion/ +feather_m0_express Adafruit Feather M0 Express samd2x_l2x https://www.adafruit.com/product/3403 +itsybitsy_m0 Adafruit ItsyBitsy M0 samd2x_l2x https://www.adafruit.com/product/3727 +metro_m0_express Adafruit Metro M0 Express samd2x_l2x https://www.adafruit.com/product/3505 +qtpy Adafruit QT Py samd2x_l2x https://www.adafruit.com/product/4600 +saml22_feather SAML22 Feather samd2x_l2x https://github.com/joeycastillo/Feather-Projects/tree/main/SAML22%20Feather +seeeduino_xiao Seeeduino XIAO samd2x_l2x https://wiki.seeedstudio.com/Seeeduino-XIAO/ +sensorwatch_m0 SensorWatch samd2x_l2x https://github.com/joeycastillo/Sensor-Watch +sparkfun_samd21_mini_usb SparkFun SAMD21 Mini samd2x_l2x https://www.sparkfun.com/products/13664 +trinket_m0 Adafruit Trinket M0 samd2x_l2x https://www.adafruit.com/product/3500 d5035_01 D5035-01 samd5x_e5x https://github.com/RudolphRiedel/USB_CAN-FD feather_m4_express Adafruit Feather M4 Express samd5x_e5x https://www.adafruit.com/product/3857 itsybitsy_m4 Adafruit ItsyBitsy M4 samd5x_e5x https://www.adafruit.com/product/3800 @@ -125,10 +128,9 @@ metro_m4_express Adafruit Metro M4 Express samd5x_e5x http pybadge Adafruit PyBadge samd5x_e5x https://www.adafruit.com/product/4200 pyportal Adafruit PyPortal samd5x_e5x https://www.adafruit.com/product/4116 same54_xplained SAME54 Xplained Pro samd5x_e5x https://www.microchip.com/DevelopmentTools/ProductDetails/ATSAME54-XPRO +same70_qmtech SAME70 QMTech same7x https://www.aliexpress.com/item/1005003173783268.html +same70_xplained SAME70 Xplained same7x https://www.microchip.com/en-us/development-tool/atsame70-xpld samg55_xplained SAMG55 Xplained Pro samg https://www.microchip.com/DevelopmentTools/ProductDetails/ATSAMG55-XPRO -atsaml21_xpro SAML21 Xplained Pro saml2x https://www.microchip.com/en-us/development-tool/atsaml21-xpro-b -saml22_feather SAML22 Feather saml2x https://github.com/joeycastillo/Feather-Projects/tree/main/SAML22%20Feather -sensorwatch_m0 SensorWatch saml2x https://github.com/joeycastillo/Sensor-Watch ========================= =================================== ========== ================================================================================= ====== MindMotion @@ -295,6 +297,7 @@ stm32l052dap52 STM32 L052 DAP stm32l0 n/a stm32l0538disco STM32 L0538 Discovery stm32l0 https://www.st.com/en/evaluation-tools/32l0538discovery.html stm32l412nucleo STM32 L412 Nucleo stm32l4 https://www.st.com/en/evaluation-tools/nucleo-l412kb.html stm32l476disco STM32 L476 Disco stm32l4 https://www.st.com/en/evaluation-tools/32l476gdiscovery.html +stm32l496nucleo STM32 L496 Nucleo stm32l4 https://www.st.com/en/evaluation-tools/nucleo-l496ZG-P.html stm32l4p5nucleo STM32 L4P5 Nucleo stm32l4 https://www.st.com/en/evaluation-tools/nucleo-l4p5zg.html stm32l4r5nucleo STM32 L4R5 Nucleo stm32l4 https://www.st.com/en/evaluation-tools/nucleo-l4r5zi.html stm32n6570dk STM32 N6570-DK stm32n6 https://www.st.com/en/evaluation-tools/stm32n6570-dk.html diff --git a/docs/reference/dependencies.rst b/docs/reference/dependencies.rst index e04cc2c2f..de1603383 100644 --- a/docs/reference/dependencies.rst +++ b/docs/reference/dependencies.rst @@ -4,9 +4,9 @@ Dependencies MCU low-level peripheral drivers and external libraries for building TinyUSB examples -======================================== ================================================================ ======================================== ====================================================================================================================================================================================================================================================================================================================================================================== +======================================== ================================================================ ======================================== ============================================================================================================================================================================================================================================================================================================================================================== Local Path Repo Commit Required by -======================================== ================================================================ ======================================== ====================================================================================================================================================================================================================================================================================================================================================================== +======================================== ================================================================ ======================================== ============================================================================================================================================================================================================================================================================================================================================================== hw/mcu/allwinner https://github.com/hathach/allwinner_driver.git 8e5e89e8e132c0fd90e72d5422e5d3d68232b756 fc100s hw/mcu/analog/msdk https://github.com/analogdevicesinc/msdk.git b20b398d3e5e2007594e54a74ba3d2a2e50ddd75 maxim hw/mcu/artery/at32f402_405 https://github.com/ArteryTek/AT32F402_405_Firmware_Library.git 4424515c2663e82438654e0947695295df2abdfe at32f402_405 @@ -23,7 +23,7 @@ hw/mcu/infineon/mtb-xmclib-cat3 https://github.com/Infineon/mtb-xmclib hw/mcu/microchip https://github.com/hathach/microchip_driver.git 9e8b37e307d8404033bb881623a113931e1edf27 sam3x samd11 samd21 samd51 samd5x_e5x same5x same7x saml2x samg hw/mcu/mindmotion/mm32sdk https://github.com/hathach/mm32sdk.git b93e856211060ae825216c6a1d6aa347ec758843 mm32 hw/mcu/nordic/nrfx https://github.com/NordicSemiconductor/nrfx.git 11f57e578c7feea13f21c79ea0efab2630ac68c7 nrf -hw/mcu/nuvoton https://github.com/majbthrd/nuc_driver.git 2204191ec76283371419fbcec207da02e1bc22fa nuc +hw/mcu/nuvoton https://github.com/majbthrd/nuc_driver.git 2204191ec76283371419fbcec207da02e1bc22fa nuc100_120 nuc121_125 nuc126 nuc505 hw/mcu/nxp/lpcopen https://github.com/hathach/nxp_lpcopen.git b41cf930e65c734d8ec6de04f1d57d46787c76ae lpc11 lpc13 lpc15 lpc17 lpc18 lpc40 lpc43 hw/mcu/nxp/mcux-sdk https://github.com/nxp-mcuxpresso/mcux-sdk a1bdae309a14ec95a4f64a96d3315a4f89c397c6 kinetis_k kinetis_k32l2 kinetis_kl lpc51 lpc54 lpc55 mcx imxrt hw/mcu/raspberry_pi/Pico-PIO-USB https://github.com/sekigon-gonnoc/Pico-PIO-USB.git 675543bcc9baa8170f868ab7ba316d418dbcf41f rp2040 @@ -80,10 +80,10 @@ hw/mcu/wch/ch32f20x https://github.com/openwch/ch32f20x.gi hw/mcu/wch/ch32v103 https://github.com/openwch/ch32v103.git 7578cae0b21f86dd053a1f781b2fc6ab99d0ec17 ch32v10x hw/mcu/wch/ch32v20x https://github.com/openwch/ch32v20x.git c4c38f507e258a4e69b059ccc2dc27dde33cea1b ch32v20x hw/mcu/wch/ch32v307 https://github.com/openwch/ch32v307.git 184f21b852cb95eed58e86e901837bc9fff68775 ch32v30x -lib/CMSIS_5 https://github.com/ARM-software/CMSIS_5.git 2b7495b8535bdcb306dac29b9ded4cfb679d7e5c imxrt kinetis_k32l2 kinetis_kl lpc51 lpc54 lpc55 mcx mm32 msp432e4 nrf saml2x lpc11 lpc13 lpc15 lpc17 lpc18 lpc40 lpc43 stm32c0 stm32f0 stm32f1 stm32f2 stm32f3 stm32f4 stm32f7 stm32g0 stm32g4 stm32h5 stm32h7 stm32h7rs stm32l0 stm32l1 stm32l4 stm32l5 stm32n6 stm32u0 stm32u5 stm32wb stm32wbasam3x samd11 samd21 samd51 samd5x_e5x same5x same7x saml2x samg tm4c -lib/CMSIS_6 https://github.com/ARM-software/CMSIS_6.git b0bbb0423b278ca632cfe1474eb227961d835fd2 ra +lib/CMSIS_5 https://github.com/ARM-software/CMSIS_5.git 2b7495b8535bdcb306dac29b9ded4cfb679d7e5c imxrt kinetis_k32l2 kinetis_kl lpc51 lpc54 lpc55 mcx mm32 msp432e4 nrf saml2x lpc11 lpc13 lpc15 lpc17 lpc18 lpc40 lpc43 stm32c0 stm32f0 stm32f1 stm32f2 stm32f3 stm32f4 stm32f7 stm32g0 stm32g4 stm32h5 stm32h7 stm32h7rs stm32l0 stm32l1 stm32l4 stm32l5 stm32u0 stm32u5 stm32wb stm32wbasam3x samd11 samd21 samd51 samd5x_e5x same5x same7x saml2x samg tm4c +lib/CMSIS_6 https://github.com/ARM-software/CMSIS_6.git 6f0a58d01aa9bd2feba212097f9afe7acd991d52 ra stm32n6 lib/FreeRTOS-Kernel https://github.com/FreeRTOS/FreeRTOS-Kernel.git cc0e0707c0c748713485b870bb980852b210877f all lib/lwip https://github.com/lwip-tcpip/lwip.git 159e31b689577dbf69cf0683bbaffbd71fa5ee10 all lib/sct_neopixel https://github.com/gsteiert/sct_neopixel.git e73e04ca63495672d955f9268e003cffe168fcd8 lpc55 tools/uf2 https://github.com/microsoft/uf2.git c594542b2faa01cc33a2b97c9fbebc38549df80a all -======================================== ================================================================ ======================================== ====================================================================================================================================================================================================================================================================================================================================================================== +======================================== ================================================================ ======================================== ============================================================================================================================================================================================================================================================================================================================================================== diff --git a/docs/reference/glossary.rst b/docs/reference/glossary.rst index 561780c53..537769c43 100644 --- a/docs/reference/glossary.rst +++ b/docs/reference/glossary.rst @@ -95,4 +95,4 @@ Glossary Product Identifier. 16-bit number assigned by vendor to identify specific products. USB-IF - USB Implementers Forum. Organization that maintains USB specifications and assigns VIDs. \ No newline at end of file + USB Implementers Forum. Organization that maintains USB specifications and assigns VIDs. diff --git a/docs/troubleshooting.rst b/docs/troubleshooting.rst index e30210d01..bb9f15166 100644 --- a/docs/troubleshooting.rst +++ b/docs/troubleshooting.rst @@ -15,13 +15,14 @@ Toolchain Problems The ARM GCC toolchain is not installed or not in PATH. *Solution*: + .. code-block:: bash # Ubuntu/Debian - sudo apt-get update && sudo apt-get install gcc-arm-none-eabi + $ sudo apt-get update && sudo apt-get install gcc-arm-none-eabi # macOS with Homebrew - brew install --cask gcc-arm-embedded + $ brew install --cask gcc-arm-embedded # Windows: Download from ARM website and add to PATH @@ -30,14 +31,15 @@ The ARM GCC toolchain is not installed or not in PATH. Build tools are missing. *Solution*: + .. code-block:: bash # Ubuntu/Debian - sudo apt-get install build-essential cmake + $ sudo apt-get install build-essential cmake # macOS - xcode-select --install - brew install cmake + $ xcode-select --install + $ brew install cmake Dependency Issues ----------------- @@ -47,10 +49,12 @@ Dependency Issues Dependencies for your MCU family are not downloaded. *Solution*: + .. code-block:: bash - # Download dependencies for specific family - python tools/get_deps.py stm32f4 # Replace with your family + # Download dependencies for specific board or family + $ python tools/get_deps.py -b stm32h743eval # Replace with your board + $ python tools/get_deps.py stm32f4 # Replace with your family # Or from example directory cd examples/device/cdc_msc @@ -61,14 +65,12 @@ Dependencies for your MCU family are not downloaded. Invalid board name in build command. *Diagnosis*: + .. code-block:: bash # List available boards for a family ls hw/bsp/stm32f4/boards/ - # List all supported boards - python tools/build.py -l - *Solution*: Use exact board name from the listing. Runtime Issues @@ -82,6 +84,7 @@ Device Mode Problems The most common issue - host doesn't see your USB device. *Diagnosis steps*: + 1. Check USB cable (must support data, not just power) 2. Enable logging: build with ``LOG=2`` 3. Use different USB ports/hosts @@ -99,17 +102,20 @@ The most common issue - host doesn't see your USB device. Device is detected but configuration fails. *Diagnosis*: + .. code-block:: bash # Build with logging enabled make BOARD=your_board LOG=2 all *Look for*: + - Setup request handling errors - Endpoint configuration problems - String descriptor issues *Solutions*: + - Implement all required descriptors - Check endpoint sizes match descriptors - Ensure control endpoint (EP0) handling is correct @@ -119,11 +125,13 @@ Device is detected but configuration fails. Device enumerates but data doesn't transfer correctly. *Common causes*: + - Buffer overruns in class callbacks - Incorrect endpoint usage (IN vs OUT) - Flow control issues in CDC class *Solutions*: + - Check buffer sizes in callbacks - Verify endpoint directions in descriptors - Implement proper flow control @@ -136,11 +144,13 @@ Host Mode Problems Host application doesn't see connected devices. *Hardware checks*: + - Power supply adequate for host mode - USB-A connector for host (not micro-USB) - Board supports host mode on selected port *Software checks*: + - ``tuh_task()`` called regularly - Host stack enabled in ``tusb_config.h`` - Correct root hub port configuration @@ -150,12 +160,14 @@ Host application doesn't see connected devices. Devices connect but enumeration fails. *Diagnosis*: + .. code-block:: bash # Enable host logging make BOARD=your_board LOG=2 RHPORT_HOST=1 all *Common issues*: + - Power supply insufficient during enumeration - Timing issues with slow devices - USB hub compatibility problems @@ -165,6 +177,7 @@ Devices connect but enumeration fails. Device enumerates but class-specific communication fails. *Troubleshooting*: + - Check device descriptors match expected class - Verify interface/endpoint assignments - Some devices need device-specific handling @@ -185,6 +198,7 @@ High CPU Usage **Symptoms**: MCU spending too much time in USB handling *Solutions*: + - Use efficient logging (RTT/SWO instead of UART) - Reduce log level in production builds - Optimize descriptor parsing @@ -197,11 +211,13 @@ STM32 Issues ------------ **Clock configuration problems**: + - USB requires precise 48MHz clock - HSE crystal must be configured correctly - PLL settings affect USB timing **Pin configuration**: + - USB pins need specific alternate function settings - VBUS sensing configuration - ID pin for OTG applications @@ -210,6 +226,7 @@ RP2040 Issues ------------- **PIO-USB for host mode**: + - Requires specific pin assignments - CPU overclocking may be needed for reliable operation - Timing-sensitive - avoid long interrupt disable periods @@ -218,8 +235,8 @@ ESP32 Issues ------------ **USB peripheral differences**: -- ESP32-S2/S3 have different USB capabilities -- Some variants only support device mode + +- ESP32-S2/S3/P4 have different USB capabilities - DMA configuration varies between models Advanced Debugging @@ -249,6 +266,7 @@ However, especially for diagnosis of crashes, it can still be useful. arm-none-eabi-gdb build/your_app.elf *Useful breakpoints*: + - ``dcd_int_handler()`` - USB interrupt entry - ``tud_task()`` - Main device task - Class-specific callbacks @@ -280,6 +298,7 @@ When reporting issues: 5. **Host environment**: OS version, USB port type **Resources**: + - GitHub Discussions: https://github.com/hathach/tinyusb/discussions - Issue Tracker: https://github.com/hathach/tinyusb/issues - Documentation: https://docs.tinyusb.org diff --git a/hw/bsp/family_support.cmake b/hw/bsp/family_support.cmake index ad68957df..23dfb9d80 100644 --- a/hw/bsp/family_support.cmake +++ b/hw/bsp/family_support.cmake @@ -10,6 +10,40 @@ get_filename_component(TOP ${TOP} ABSOLUTE) set(UF2CONV_PY ${TOP}/tools/uf2/utils/uf2conv.py) +function(family_resolve_board BOARD_NAME BOARD_PATH_OUT) + if ("${BOARD_NAME}" STREQUAL "") + message(FATAL_ERROR "You must set BOARD (e.g. metro_m4_express, raspberry_pi_pico). Use -DBOARD=xxx on the cmake command line.") + endif() + + file(GLOB _board_paths + LIST_DIRECTORIES true + RELATIVE ${TOP}/hw/bsp + ${TOP}/hw/bsp/*/boards/* + ) + + set(_hint_names "") + foreach(_board_path ${_board_paths}) + get_filename_component(_board_name ${_board_path} NAME) + if (_board_name STREQUAL "${BOARD_NAME}") + set(${BOARD_PATH_OUT} ${_board_path} PARENT_SCOPE) + return() + endif() + string(FIND "${_board_name}" "${BOARD_NAME}" _pos) + if (_pos EQUAL 0) + list(APPEND _hint_names ${_board_name}) + endif() + endforeach() + + if (_hint_names) + list(REMOVE_DUPLICATES _hint_names) + list(SORT _hint_names) + list(JOIN _hint_names ", " _hint_str) + message(FATAL_ERROR "BOARD '${BOARD_NAME}' not found. Boards with the same prefix:\n${_hint_str}") + else() + message(FATAL_ERROR "BOARD '${BOARD_NAME}' not found under hw/bsp/*/boards") + endif() +endfunction() + #------------------------------------------------------------- # Toolchain # Can be changed via -DTOOLCHAIN=gcc|iar or -DCMAKE_C_COMPILER= or ENV{CC}= @@ -78,21 +112,8 @@ endif () # FAMILY and BOARD #------------------------------------------------------------- if (NOT DEFINED FAMILY) - if (NOT DEFINED BOARD) - message(FATAL_ERROR "You must set a BOARD variable for the build (e.g. metro_m4_express, raspberry_pi_pico). - You can do this via -DBOARD=xxx on the cmake command line") - endif () - - # Find path contains BOARD - file(GLOB BOARD_PATH LIST_DIRECTORIES true - RELATIVE ${TOP}/hw/bsp - ${TOP}/hw/bsp/*/boards/${BOARD} - ) - if (NOT BOARD_PATH) - message(FATAL_ERROR "Could not detect FAMILY from BOARD=${BOARD}") - endif () + family_resolve_board("${BOARD}" BOARD_PATH) - # replace / with ; so that we can get the first element as FAMILY string(REPLACE "/" ";" BOARD_PATH ${BOARD_PATH}) list(GET BOARD_PATH 0 FAMILY) set(FAMILY ${FAMILY} CACHE STRING "Board family") diff --git a/tools/gen_doc.py b/tools/gen_doc.py index ab07bc116..3920531d5 100755 --- a/tools/gen_doc.py +++ b/tools/gen_doc.py @@ -23,7 +23,7 @@ def gen_deps_doc(): Dependencies ************ -MCU low-level peripheral driver and external libraries for building TinyUSB examples +MCU low-level peripheral drivers and external libraries for building TinyUSB examples {tabulate(df, headers="keys", tablefmt='rst')} """ -- cgit v1.3.1 From 20b03bbc081353295f7a491038bd3efbc9c3a75a Mon Sep 17 00:00:00 2001 From: Ha Thach Date: Sat, 13 Dec 2025 15:13:02 +0700 Subject: upload metrics.json and metrics compare to release page (#3409) * upload metrics.json and metrics compare to release page * Adjust workflow comment handling for forks --- .github/workflows/build.yml | 43 ++++++++++++++++++++++++++++------- .github/workflows/build_util.yml | 2 +- .github/workflows/metrics_comment.yml | 1 + .github/workflows/pre-commit.yml | 2 +- .github/workflows/static_analysis.yml | 8 +++---- .github/workflows/trigger.yml | 2 +- tools/metrics.py | 24 +++++++------------ 7 files changed, 51 insertions(+), 31 deletions(-) (limited to '.github/workflows/static_analysis.yml') diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c062aca46..781d3b002 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -27,6 +27,8 @@ on: - '.github/workflows/build.yml' - '.github/workflows/build_util.yml' - '.github/workflows/ci_set_matrix.py' + release: + types: [ published ] concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true @@ -42,7 +44,7 @@ jobs: hil_json: ${{ steps.set-matrix-json.outputs.hil_matrix }} steps: - name: Checkout TinyUSB - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Generate matrix json id: set-matrix-json @@ -86,9 +88,12 @@ jobs: runs-on: ubuntu-latest permissions: pull-requests: write + contents: write steps: - name: Checkout TinyUSB - uses: actions/checkout@v4 + uses: actions/checkout@v6 + with: + fetch-tags: ${{ github.event_name == 'release' }} - name: Download Artifacts uses: actions/download-artifact@v5 @@ -103,14 +108,14 @@ jobs: python tools/metrics.py combine -j -m -f tinyusb/src cmake-build/*/metrics.json - name: Upload Metrics Artifact - if: github.event_name == 'push' + if: github.event_name == 'push' || github.event_name == 'release' uses: actions/upload-artifact@v5 with: name: metrics-tinyusb path: metrics.json - name: Download Base Branch Metrics - if: github.event_name != 'push' + if: github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch' uses: dawidd6/action-download-artifact@v11 with: workflow: build.yml @@ -119,6 +124,18 @@ jobs: path: base-metrics continue-on-error: true + - name: Download Previous Release Asset + if: github.event_name == 'release' + env: + GH_TOKEN: ${{ github.token }} + run: | + PREV_TAG=$(git tag --sort=-creatordate | head -n 2 | tail -n 1) + echo "Previous Release: $PREV_TAG" + echo "PREV_TAG=$PREV_TAG" >> $GITHUB_ENV + + mkdir -p base-metrics + gh release download $PREV_TAG -p metrics.json -D base-metrics || echo "No metrics.json found in $PREV_TAG release" + - name: Compare with Base Branch if: github.event_name != 'push' run: | @@ -130,6 +147,16 @@ jobs: cp metrics.md metrics_compare.md fi + - name: Upload Release Assets + if: github.event_name == 'release' + env: + GH_TOKEN: ${{ github.token }} + run: | + CURR_TAG=${{ github.event.release.tag_name }} + COMPARE_FILE="metrics_compare_${CURR_TAG}-${PREV_TAG}.md" + mv metrics_compare.md $COMPARE_FILE + gh release upload $CURR_TAG metrics.json $COMPARE_FILE + - name: Save PR number if: github.event_name == 'pull_request' run: echo ${{ github.event.number }} > pr_number.txt @@ -144,7 +171,7 @@ jobs: pr_number.txt - name: Post Code Metrics as PR Comment - if: github.event_name != 'push' + if: (github.event_name == 'workflow_dispatch') || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == false) uses: marocchino/sticky-pull-request-comment@v2 with: header: code-metrics @@ -175,7 +202,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout TinyUSB - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Setup Zephyr project uses: zephyrproject-rtos/action-zephyr-setup@v1 @@ -237,7 +264,7 @@ jobs: mkdir -p "${{ github.workspace }}" - name: Checkout TinyUSB - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Download Artifacts uses: actions/download-artifact@v5 @@ -275,7 +302,7 @@ jobs: iccarm --version - name: Checkout TinyUSB - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Get build boards run: | diff --git a/.github/workflows/build_util.yml b/.github/workflows/build_util.yml index 1cbd02f1b..540ee8b47 100644 --- a/.github/workflows/build_util.yml +++ b/.github/workflows/build_util.yml @@ -38,7 +38,7 @@ jobs: arg: ${{ fromJSON(inputs.build-args) }} steps: - name: Checkout TinyUSB - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Setup Toolchain id: setup-toolchain diff --git a/.github/workflows/metrics_comment.yml b/.github/workflows/metrics_comment.yml index 2f1b0d631..7443f7367 100644 --- a/.github/workflows/metrics_comment.yml +++ b/.github/workflows/metrics_comment.yml @@ -13,6 +13,7 @@ jobs: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success' permissions: + actions: read pull-requests: write steps: - name: Download Artifacts diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index ed0efd66e..b9bfaf9b6 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -20,7 +20,7 @@ jobs: ruby-version: '3.0' - name: Checkout TinyUSB - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Get Dependencies run: | diff --git a/.github/workflows/static_analysis.yml b/.github/workflows/static_analysis.yml index 4db267517..a78682d7a 100644 --- a/.github/workflows/static_analysis.yml +++ b/.github/workflows/static_analysis.yml @@ -37,7 +37,7 @@ jobs: - 'metro_m4_express' steps: - name: Checkout TinyUSB - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Get Dependencies uses: ./.github/actions/get_deps @@ -100,7 +100,7 @@ jobs: - 'raspberry_pi_pico' steps: - name: Checkout TinyUSB - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Get Dependencies uses: ./.github/actions/get_deps @@ -154,7 +154,7 @@ jobs: - 'stm32h743eval' steps: - name: Checkout TinyUSB - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis @@ -197,7 +197,7 @@ jobs: - 'b_g474e_dpow1' steps: - name: Checkout TinyUSB - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Get Dependencies uses: ./.github/actions/get_deps diff --git a/.github/workflows/trigger.yml b/.github/workflows/trigger.yml index cf40ac955..fd7c0b713 100644 --- a/.github/workflows/trigger.yml +++ b/.github/workflows/trigger.yml @@ -23,7 +23,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Push to tinyusb_src run: | diff --git a/tools/metrics.py b/tools/metrics.py index 50709d5ba..6b992c8f5 100644 --- a/tools/metrics.py +++ b/tools/metrics.py @@ -74,7 +74,6 @@ def parse_bloaty_csv(csv_text, filters=None): "file": os.path.basename(unit_path) or unit_path, "path": unit_path, "size": total_size, - "total": total_size, "symbols": symbols, "sections": sections, } @@ -146,7 +145,7 @@ def compute_avg(all_json_data): return None # Merge files with the same 'file' value and compute averages - file_accumulator = {} # key: file name, value: {"sizes": [sizes], "totals": [totals], "symbols": {name: [sizes]}, "sections": {name: [sizes]}} + file_accumulator = {} # key: file name, value: {"sizes": [sizes], "symbols": {name: [sizes]}, "sections": {name: [sizes]}} for json_data in all_json_data["data"]: for f in json_data.get("files", []): @@ -154,14 +153,12 @@ def compute_avg(all_json_data): if fname not in file_accumulator: file_accumulator[fname] = { "sizes": [], - "totals": [], "path": f.get("path"), "symbols": defaultdict(list), "sections": defaultdict(list), } - size_val = f.get("size", f.get("total", 0)) + size_val = f.get("size", 0) file_accumulator[fname]["sizes"].append(size_val) - file_accumulator[fname]["totals"].append(f.get("total", size_val)) for sym in f.get("symbols", []): name = sym.get("name") if name is None: @@ -196,9 +193,7 @@ def compute_avg(all_json_data): } ) - totals_list = [d.get("TOTAL") for d in all_json_data["data"] if isinstance(d.get("TOTAL"), (int, float))] - total_size = round(sum(totals_list) / len(totals_list)) if totals_list else ( - sum(f["size"] for f in files_average) or 1) + total_size = sum(f["size"] for f in files_average) or 1 for f in files_average: f["percent"] = (f["size"] / total_size) * 100 if total_size else 0 @@ -207,7 +202,6 @@ def compute_avg(all_json_data): json_average = { "file_list": all_json_data["file_list"], - "TOTAL": total_size, "files": files_average, } @@ -262,10 +256,12 @@ def compare_files(base_file, new_file, filters=None): }, }) + base_total = sum(f["size"] for f in base_avg["files"]) + new_total = sum(f["size"] for f in new_avg["files"]) total = { - "base": base_avg.get("TOTAL", 0), - "new": new_avg.get("TOTAL", 0), - "diff": new_avg.get("TOTAL", 0) - base_avg.get("TOTAL", 0), + "base": base_total, + "new": new_total, + "diff": new_total - base_total, } return { @@ -287,10 +283,6 @@ def get_sort_key(sort_order): """ def _size_val(entry): - if isinstance(entry.get('total'), int): - return entry.get('total', 0) - if isinstance(entry.get('total'), dict): - return entry['total'].get('new', 0) return entry.get('size', 0) if sort_order == 'size-': -- cgit v1.3.1 From 6c895e7af45107702705cc532af4abb35d2546cf Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 18 Mar 2026 00:26:18 +0700 Subject: Update several actions to latest version --- .github/actions/setup_toolchain/download/action.yml | 2 +- .github/actions/setup_toolchain/espressif/action.yml | 2 +- .github/workflows/build.yml | 6 +++--- .github/workflows/build_util.yml | 4 ++-- .github/workflows/cifuzz.yml | 2 +- .github/workflows/static_analysis.yml | 6 +++--- 6 files changed, 11 insertions(+), 11 deletions(-) (limited to '.github/workflows/static_analysis.yml') diff --git a/.github/actions/setup_toolchain/download/action.yml b/.github/actions/setup_toolchain/download/action.yml index f691b0499..77d3bcf19 100644 --- a/.github/actions/setup_toolchain/download/action.yml +++ b/.github/actions/setup_toolchain/download/action.yml @@ -13,7 +13,7 @@ runs: steps: - name: Cache Toolchain if: ${{ !startsWith(inputs.toolchain_url, 'https://github.com') }} - uses: actions/cache@v4 + uses: actions/cache@v5 id: cache-toolchain-download with: path: ~/cache/${{ inputs.toolchain }} diff --git a/.github/actions/setup_toolchain/espressif/action.yml b/.github/actions/setup_toolchain/espressif/action.yml index 90ef753c4..ec1ff2e91 100644 --- a/.github/actions/setup_toolchain/espressif/action.yml +++ b/.github/actions/setup_toolchain/espressif/action.yml @@ -21,7 +21,7 @@ runs: shell: bash - name: Cache Docker Image - uses: actions/cache@v4 + uses: actions/cache@v5 id: cache-toolchain-espressif with: path: ${{ env.DOCKER_ESP_IDF }} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 960ccf8ee..f549bb1e4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -29,7 +29,7 @@ jobs: - uses: actions/checkout@v6 with: fetch-depth: 2 # Needed for push commit comparison - - uses: dorny/paths-filter@v3 + - uses: dorny/paths-filter@v4 id: filter with: filters: | @@ -124,7 +124,7 @@ jobs: - name: Upload Metrics Artifact if: github.event_name == 'push' || github.event_name == 'release' - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v7 with: name: metrics-tinyusb path: metrics.json @@ -179,7 +179,7 @@ jobs: - name: Upload Metrics Comment Artifact if: github.event_name == 'pull_request' - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v7 with: name: metrics-comment path: | diff --git a/.github/workflows/build_util.yml b/.github/workflows/build_util.yml index c9b0d36d9..69b6f28d5 100644 --- a/.github/workflows/build_util.yml +++ b/.github/workflows/build_util.yml @@ -90,14 +90,14 @@ jobs: - name: Upload Artifacts for Metrics if: inputs.upload-metrics == true && inputs.code-changed == true - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v7 with: name: metrics-${{ matrix.arg }} path: cmake-build/cmake-build-*/metrics.json - name: Upload Artifacts for Hardware Testing if: inputs.upload-artifacts == true && inputs.code-changed == true - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v7 with: name: binaries-${{ matrix.arg }} path: | diff --git a/.github/workflows/cifuzz.yml b/.github/workflows/cifuzz.yml index 9b3756a72..ff75a8ba6 100644 --- a/.github/workflows/cifuzz.yml +++ b/.github/workflows/cifuzz.yml @@ -29,7 +29,7 @@ jobs: fuzz-seconds: 400 - name: Upload Crash - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v7 if: failure() && steps.build.outcome == 'success' with: name: artifacts diff --git a/.github/workflows/static_analysis.yml b/.github/workflows/static_analysis.yml index a78682d7a..d440bf69e 100644 --- a/.github/workflows/static_analysis.yml +++ b/.github/workflows/static_analysis.yml @@ -84,7 +84,7 @@ jobs: category: CodeQL - name: Upload artifact - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v7 with: name: codeql-${{ matrix.board }} path: ${{ steps.analyze.outputs.sarif-output }} @@ -136,7 +136,7 @@ jobs: category: PVS-Studio - name: Upload artifact - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v7 with: name: pvs-studio-${{ matrix.board }} path: pvs-studio-${{ matrix.board }}.sarif @@ -236,7 +236,7 @@ jobs: category: IAR-CStat - name: Upload artifact - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v7 with: name: iar-cstat-${{ matrix.board }} path: iar-cstat-${{ matrix.board }}.sarif -- cgit v1.3.1