diff --git a/.github/workflows/ifx_build.yml b/.github/workflows/ifx_build.yml new file mode 100644 index 000000000..6257071d3 --- /dev/null +++ b/.github/workflows/ifx_build.yml @@ -0,0 +1,94 @@ +# Copyright (c) Arduino s.r.l. and/or its affiliated companies +# SPDX-License-Identifier: Apache-2.0 + +# Infineon-specific counterpart of build.yml: builds the same native Zephyr +# samples upstream builds, plus each feature board's own native samples (as +# declared by .build.feature_board=true and +# .build.ci_native_samples in boards.txt). +# +# Kept as a separate file (instead of editing build.yml) so upstream's own +# CI workflow stays untouched and rebases/syncs from upstream/main never +# conflict here. + +name: Build native Zephyr samples (Infineon) + +on: + push: + branches: + - edge-main + - control-main + pull_request: + branches: + - edge-main + - control-main + +permissions: + contents: read + +jobs: + build: + name: Build native Zephyr samples + runs-on: ubuntu-latest + container: zephyrprojectrtos/ci-base:latest + env: + CMAKE_PREFIX_PATH: /opt/toolchains + CCACHE_IGNOREOPTIONS: -specs=* + MODULE_PATH: ../modules/lib/ArduinoCore-zephyr + + # action-setup-zephyr will initialize the repo in $GITHUB_WORKSPACE/.., + # so we need to put the module in $GITHUB_WORKSPACE's parent, but + # actions/checkout would not be able to checkout the module there + # directly, so we use "subfolder" and move it later. + # + # using action-setup-zephyr also requires a local west.yml and so the + # folder must be manually added to Zephyr as a module via + # EXTRA_ZEPHYR_MODULES. + + steps: + - uses: actions/checkout@v6 + with: + fetch-depth: 0 + persist-credentials: false + path: subfolder + + - name: Fix module path, list needed HALs + run: | + mkdir -p $(dirname $MODULE_PATH) && mv subfolder $MODULE_PATH + NEEDED_HALS=$(grep 'build.zephyr_hals=' $MODULE_PATH/boards.txt | cut -d '=' -f 2 | xargs -n 1 echo | sort -u) + HAL_FILTER="-hal_.*" + for hal in $NEEDED_HALS; do + HAL_FILTER="$HAL_FILTER,+$hal" + done + echo "HAL_FILTER=$HAL_FILTER" | tee -a $GITHUB_ENV + + - name: Setup Zephyr project + uses: zephyrproject-rtos/action-zephyr-setup@v1 + with: + toolchains: arm-zephyr-eabi + manifest-file-name: ${{ env.MODULE_PATH }}/west.yml + west-project-filter: ${{ env.HAL_FILTER }} + enable-ccache: false + + - name: Add manifest path as module + run: | + echo EXTRA_ZEPHYR_MODULES="$(pwd)/$MODULE_PATH" >> $GITHUB_ENV + + - name: Fetch the Arduino API + run: | + west blobs --auto-accept fetch arduino-api + + - name: Build fade + run: | + west build -p -b arduino_nano_33_ble//sense $MODULE_PATH/samples/fade + + - name: Build i2cdemo + run: | + west build -p -b ek_ra8d1 $MODULE_PATH/samples/i2cdemo + + - name: Build adc + run: | + west build -p -b arduino_nano_33_ble/nrf52840/sense $MODULE_PATH/samples/analog_input + + - name: Build feature boards' native samples + run: | + bash $MODULE_PATH/extra/ci_build_native_samples.sh $MODULE_PATH diff --git a/.github/workflows/ifx_commit_check.yml b/.github/workflows/ifx_commit_check.yml new file mode 100644 index 000000000..dcd5c6461 --- /dev/null +++ b/.github/workflows/ifx_commit_check.yml @@ -0,0 +1,37 @@ +name: 'Infineon Check Commit Message' + +on: + pull_request: + types: + - opened + - edited + - reopened + - synchronize + branches: + - 'ifx-main' + - 'edge-main' + - 'control-main' + +jobs: + check-commit-messages: + runs-on: ubuntu-latest + steps: + - name: 'Check commit messages format' + uses: gsactions/commit-message-checker@v2 + with: + pattern: '^[^!]+: [A-Za-z]+.+ .+$' + flags: 'gm' + error: 'Commit subject line / PR title must match the following pattern: : ' + excludeTitle: 'false' + excludeDescription: 'true' + checkAllCommitMessages: 'true' + accessToken: ${{ secrets.GITHUB_TOKEN }} + - name: 'Check commit messages length' + uses: gsactions/commit-message-checker@v2 + with: + pattern: '^[^#].{10,80}$' + error: 'Commit subject line maximum line length of 80 characters is exceeded.' + excludeTitle: 'true' + excludeDescription: 'true' + checkAllCommitMessages: 'true' + accessToken: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/ifx_format_check.yml b/.github/workflows/ifx_format_check.yml new file mode 100644 index 000000000..696b1caf6 --- /dev/null +++ b/.github/workflows/ifx_format_check.yml @@ -0,0 +1,58 @@ +name: 'Infineon Format Check' + +on: + push: + branches: + - 'ifx-main' + - 'edge-main' + - 'control-main' + + pull_request: + types: + - opened + - edited + - reopened + - synchronize + branches: + - 'ifx-main' + - 'edge-main' + - 'control-main' + +jobs: + verify-format: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v6 + with: + submodules: false + persist-credentials: false + - name: Get changed source files that need format check + id: changed-files + uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c # v46.0.5 + with: + files: | + cores/arduino/**/*.{c,cpp,h,hpp} + loader/**/*.{c,cpp,h,hpp} + libraries/**/*.{c,cpp,h,hpp} + files_ignore: | + cores/arduino/api/** + loader/llext_exports.c + loader/blobs/4343WA1_*.c + loader/blobs/wifi_nvram_image_data.h + libraries/examples/** + libraries/extras/** + libraries/ea_malloc/** + libraries/Storage/examples/FlashFormat/4343WA1_bin.h + json: true + - name: Export changed files in a text file, one per line + if: steps.changed-files.outputs.any_changed == 'true' + run: | + echo ${{ steps.changed-files.outputs.all_changed_files }} | jq -r '.[]' > all_changed_files.txt + cat all_changed_files.txt + - name: Run clang-format check + if: steps.changed-files.outputs.any_changed == 'true' + uses: pillo79/clang-format-action@05f671e71f0758aba4d3c9dbb0ee81bc5f0137c6 + with: + clang-format-version: '19' + check-files-from: all_changed_files.txt diff --git a/.github/workflows/ifx_package_core.yml b/.github/workflows/ifx_package_core.yml new file mode 100644 index 000000000..6c8e4373e --- /dev/null +++ b/.github/workflows/ifx_package_core.yml @@ -0,0 +1,778 @@ +# Copyright (c) Arduino s.r.l. and/or its affiliated companies +# SPDX-License-Identifier: Apache-2.0 + +# Infineon-specific counterpart of package_core.yml: same build/package/test +# pipeline, minus the Arduino-only publishing jobs (S3 upload, ci-builds +# upload) that need secrets this fork doesn't have. +# +# Kept as a separate file (instead of editing package_core.yml) so upstream's +# own CI workflow stays untouched and rebases/syncs from upstream/main never +# conflict here. + +name: Package, test and upload core (Infineon) + +on: + push: + branches: + - edge-main + - control-main + tags-ignore: + - 'tools/**' # do not run on tags created for tool releases + pull_request: + branches: + - edge-main + - control-main + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }}-${{ github.actor }} + cancel-in-progress: ${{ github.event_name != 'push' }} + +env: + # use the head SHA for PR hashes, instead of the merge commit + HEAD_REF: ${{ github.event.pull_request.head.sha || github.ref }} + +jobs: + + + + # Prepare the Zephyr build environment once for all boards, to speed up the + # overall process and ensure all builds use the same environment and metadata. + # Several outputs are made available for later jobs to use. + + build-env: + name: Prepare build environment + runs-on: ubuntu-latest + outputs: + # User-friendly SemVer-compatible version for the build. Matches the tag + # name if building a tagged commit, otherwise it is "slightly more" than + # the latest tag. + CORE_VER: ${{ steps.identify-core.outputs.CORE_VER }} + # Tag (if found) or hash identifying this core build, should be used for + # user-friendly strings and file names + CORE_TAG: ${{ env.CORE_TAG }} + # Target branch referred to by this workflow (HEAD_REF for branch pushes, + # or closest branch that contains the tag), used for ci-builds tracking + CORE_BRANCH: ${{ env.CORE_BRANCH }} + # Hash identifying this core build, should be used for exact version match + CORE_HASH: ${{ env.CORE_HASH }} + # JSON describing all boards to build, collected by get_board_details.sh + ALL_BOARD_DATA: ${{ env.ALL_BOARD_DATA }} + # Extended version of ALL_BOARD_DATA with link_mode alternatives added + ALL_BOARD_FQBNS: ${{ env.ALL_BOARD_FQBNS }} + # List of artifacts to produce, including the "zephyr" umbrella artifact + ARTIFACTS: ${{ env.ARTIFACTS }} + # List of architectures the artifacts will be built for + SUB_ARCHES: ${{ env.SUB_ARCHES }} + # URL of the latest ci-builds index for this branch, if any + CI_BUILDS_URL: ${{ env.CI_BUILDS_URL }} + steps: + + - name: Install OS dependencies + working-directory: /opt + timeout-minutes: 5 # early error on Github network issues + run: | + sudo apt-get remove --purge man-db -y # skips the mandb triggers + sudo apt-get update + sudo apt-get install -y --no-install-recommends git cmake wget python3-pip ninja-build + + - uses: actions/checkout@v6 + with: + submodules: 'recursive' + fetch-depth: 0 + persist-credentials: false + fetch-tags: true # needed for get_core_version.sh + + - name: Identify current version and board set + id: identify-core + run: | + # Set up basic environment for later steps + CORE_VER=$(extra/get_core_version.sh) + ALL_BOARD_DATA=$(extra/get_board_details.sh | jq -c 'sort_by(.variant)') + # limit builds/tests to this board family's own boards, for both + # direct pushes and PRs. Only apply the filter if it leaves at + # least one board, so branches with no feature_board opted in yet + # keep building the full board set. + FEATURE_BOARD_DATA=$(jq -c 'map(select(.feature_board == true))' <<< "${ALL_BOARD_DATA}") + if [[ "$(jq 'length' <<< "${FEATURE_BOARD_DATA}")" -gt 0 ]]; then + ALL_BOARD_DATA="${FEATURE_BOARD_DATA}" + fi + echo "CORE_HASH=$(git describe --always $HEAD_REF)" >> "$GITHUB_ENV" + echo "ALL_BOARD_DATA=${ALL_BOARD_DATA}" >> "$GITHUB_ENV" + echo "CORE_VER=${CORE_VER}" >> "$GITHUB_ENV" + echo "CORE_VER=${CORE_VER}" >> "$GITHUB_OUTPUT" + + - name: Map output packages + # needs the above env vars + run: | + echo "## Building \`$CORE_VER\`" >> "$GITHUB_STEP_SUMMARY" + echo "CORE_TAG=$(git describe --tags --exact-match --exclude '*/*' 2>/dev/null || echo $CORE_HASH)" >> "$GITHUB_ENV" + if [[ "${{ github.ref_type }}" == "tag" ]]; then + BRANCH=$(git branch -r --contains HEAD --sort=-committerdate --format='%(refname:short)' | sed 's|origin/||' | grep -v HEAD | head -1) + [[ -n "$BRANCH" ]] || { echo "::error::No branch found containing tag ${{ github.ref_name }}"; exit 1; } + echo "CORE_BRANCH=${BRANCH}" >> "$GITHUB_ENV" + else + echo "CORE_BRANCH=${{ github.base_ref || github.ref_name }}" >> "$GITHUB_ENV" + fi + echo "ALL_BOARD_FQBNS=$(jq -c 'map((. + {link_mode: "static"}), (. + {link_mode: "dynamic"}))' <<< ${ALL_BOARD_DATA})" >> "$GITHUB_ENV" + echo "ARTIFACTS=$(jq -c '["zephyr"] + (map(.artifact) | unique)' <<< ${ALL_BOARD_DATA})" >> "$GITHUB_ENV" + echo "SUB_ARCHES=$(jq -c 'map(.subarch) | unique' <<< ${ALL_BOARD_DATA})" >> "$GITHUB_ENV" + + - name: Cache west modules and blobs + uses: actions/cache@v5 + with: + key: west-cache-${{ hashFiles('west.yml', 'boards.txt') }} + restore-keys: | + west-blobs- + path: ${{ runner.temp }}/west-cache + + - name: Initialize Zephyr environment + timeout-minutes: 10 # early error on Github network issues + env: + WEST_CACHE: ${{ runner.temp }}/west-cache + run: | + # Install Zephyr as a core user would, but faster + yes | ./extra/bootstrap.sh -o=--filter=tree:0 + # Archive the build environment for later jobs + (cd && tar cphf - .cmake work zephyr-sdk-* | zstd > build-env.tar.zstd) + + - name: Get ci-builds package index link + run: | + # use the latest official Arduino ci-built core as a reference, falling back to main + CI_BUILDS_URL="https://arduino.github.io/core-ci-builds/package_arduino_zephyr_${CORE_BRANCH}_ci_index.json" + if ! wget -q --method=HEAD "$CI_BUILDS_URL" >& /dev/null ; then + CLOSEST_BRANCH=$(git branch -r | grep -vE "HEAD|/$(git branch --show-current)$" | while read -r b; do \ + echo "$(git rev-list --count $b..HEAD) $b" ; \ + done | sort -n | head -n 1 | awk '{print $2}' | cut -d / -f 2) + [ -z "$CLOSEST_BRANCH" ] && CLOSEST_BRANCH="main" + echo "::warning::No ci-builds index found for branch $CORE_BRANCH, using $CLOSEST_BRANCH" + CI_BUILDS_URL="https://arduino.github.io/core-ci-builds/package_arduino_zephyr_${CLOSEST_BRANCH}_ci_index.json" + if ! wget -q --method=HEAD "$CI_BUILDS_URL" >& /dev/null ; then + echo "::warning::No ci-builds index found for branch $CLOSEST_BRANCH, using main" + CI_BUILDS_URL="https://arduino.github.io/core-ci-builds/package_arduino_zephyr_main_ci_index.json" + fi + fi + echo "CI_BUILDS_URL=$CI_BUILDS_URL" >> "$GITHUB_ENV" + + - name: Download test data + run: | + extra/ci_fetch_tests.sh + + - name: Archive test data + uses: actions/upload-artifact@v7 + with: + name: test-data + path: test-data/ + retention-days: 1 + + - name: Archive build environment + uses: actions/upload-artifact@v7 + with: + name: build-env + path: ~/build-env.tar.zstd + retention-days: 1 + archive: false + + + + # Extract the build environment and compile the loader project for each board + # in parallel. The build logs and artifacts are intermediate results archived + # for later jobs. + + build-board: + # NOTE: this name is hardcoded in ci_collect_data.py + name: Build for ${{ matrix.board }} + runs-on: ubuntu-latest + needs: + - build-env + env: + # Reuse the version computed by build-env instead of recomputing it per board. + PINNED_CORE_VERSION: ${{ needs.build-env.outputs.CORE_VER }} + # ccache, don't look for the spec file anywhere + CCACHE_IGNOREOPTIONS: -specs=* + # build-specific name of the generated artifacts + ARTIFACT_TAG: ${{ needs.build-env.outputs.CORE_HASH }}-${{ matrix.board }} + # report file stem for this board + REPORT: reports/zephyr-${{ matrix.variant }} + strategy: + matrix: + include: + ${{ fromJSON( needs.build-env.outputs.ALL_BOARD_DATA ) }} + fail-fast: false + steps: + + - uses: actions/download-artifact@v8 + timeout-minutes: 10 # early error on Github network issues + with: + path: /home/runner + name: build-env.tar.zstd + + - name: Restore build environment + id: restore-env + timeout-minutes: 5 # early error on Github network issues + run: | + sudo apt-get remove --purge man-db -y # skips the mandb triggers + sudo apt-get update + sudo apt-get install -y --no-install-recommends git cmake wget python3-pip ninja-build ccache + (cd ~ && tar --use-compress-program=unzstd -xpf build-env.tar.zstd && rm build-env.tar.zstd) + + - name: ccache + uses: actions/cache@v5 + with: + key: ${{ github.job }}-${{ matrix.board }} # independent caches + path: ~/.cache/ccache + + - name: Install PSE84 signing dependencies + if: ${{ matrix.board == 'kit_pse84_ai' }} + run: | + # imgtool (invoked by hal_infineon's pse84_metadata.cmake to sign the + # image) needs these; its own pip-install-at-configure-time attempt + # only warns on failure, so pre-install them here to be safe. + source venv/bin/activate + pip3 install cryptography cbor2 click intelhex Pillow + + - name: Build loader + shell: bash + run: | + # create the report directory + mkdir -p reports + echo "::group::ccache stats before build" + ccache --show-stats + echo "::endgroup::" + # run the build, capturing stdout and stderr + if ! ./extra/build.sh ${{ matrix.board }} 1> >(tee $REPORT.stdout) 2> >(tee $REPORT.stderr) ; then + # build failed, capture errors in summary and stop job without artifacts + echo "### :x: ${{ matrix.board }} (\`${{ matrix.variant }}\`) build errors" > $GITHUB_STEP_SUMMARY + echo >> $GITHUB_STEP_SUMMARY + echo "\`\`\`" >> $GITHUB_STEP_SUMMARY + cat $REPORT.stderr >> $GITHUB_STEP_SUMMARY + echo "\`\`\`" >> $GITHUB_STEP_SUMMARY + exit 1 + fi + + # look for warnings (errors are a happy path!) + grep -i "warning:" $REPORT.stdout > $REPORT.warnings || true + + # extract the memory usage table (from the header to the first non-% line) + # override the size of the Flash with the size of the loader partition + # and add the size of the sketch partition (not reported by Zephyr) + LOADER_SIZE=$(( $(cat variants/${{ matrix.variant }}/syms-static.ld | grep '_loader_max_size' | cut -d '=' -f 2 | tr -d ') ;') )) + SKETCH_SIZE=$(( $(cat variants/${{ matrix.variant }}/syms-static.ld | grep '_sketch_max_size' | cut -d '=' -f 2 | tr -d ') ;') )) + cat $REPORT.stdout | sed -n '/^Memory region/,/^[^%]*$/p' | head -n -1 \ + | awk 'BEGIN {split("B KB MB GB", u); for(i in u) m[u[i]]=1024^(i-1)} /:/ {print "[\"" $1 "\"," $2*m[$3] "," $4*m[$5] "]"}' \ + | sort \ + | jq -s "map((select(.[0] == \"FLASH:\") | .[2]) |= ${LOADER_SIZE}) + [ [ \"SKETCH:\", 0, ${SKETCH_SIZE} ] ]" > $REPORT.meminfo + + # ccache stats update + echo "::group::ccache stats after build" + ccache --evict-older-than 30d + ccache --show-stats + echo "::endgroup::" + + - name: Package board artifacts + if: ${{ steps.restore-env.outcome == 'success' && !cancelled() }} + run: | + # add the config file to the report files, list them for later archiving + cp firmwares/zephyr-${{ matrix.variant }}.config $REPORT.config + echo "REPORT_FILES<> $GITHUB_ENV + ls reports/* >> $GITHUB_ENV + echo "EOF" >> $GITHUB_ENV + + # Preprare an archive of the built binaries (and build dir on failure) + [ "${{ job.status }}" == "failure" ] && FULL_BUILD_DIR="build/${{ matrix.variant }}/" + sed -e '/^#/d' boards.local.txt > boards.local_${{ matrix.variant }}.txt + tar chf - \ + firmwares/*${{ matrix.variant }}* \ + variants/${{ matrix.variant }}/ \ + boards.local_${{ matrix.variant }}.txt \ + cores/arduino/api/ \ + ${FULL_BUILD_DIR} \ + | zstd > binaries-${ARTIFACT_TAG}.tar.zstd + + - name: Archive board binaries + if: ${{ steps.restore-env.outcome == 'success' && !cancelled() }} + uses: actions/upload-artifact@v7 + with: + # prefix the name with 'failed-' if the build failed, so that it is not removed + name: ${{ format('{0}binaries-{1}', (job.status == 'failure') && 'failed-' || '', env.ARTIFACT_TAG) }} + path: binaries-${{ env.ARTIFACT_TAG }}.tar.zstd + retention-days: 7 # for failed build inspection + archive: false + + - name: Archive build reports + if: ${{ steps.restore-env.outcome == 'success' && !cancelled() }} + uses: actions/upload-artifact@v7 + with: + name: build-report-${{ env.ARTIFACT_TAG }} + path: ${{ env.REPORT_FILES }} + retention-days: 1 + + + + # Compose the core packages for each architecture in parallel, by retrieving + # the API snapshot and the built binaries for all boards and packaging them. + # The resulting core packages are final artifacts, ready for publishing. + # The 'zephyr' umbrella package is also created here by including all others. + + package-core: + name: Package ${{ matrix.artifact }} + runs-on: ubuntu-latest + needs: + - build-env + - build-board + env: + ALL_BOARD_DATA: ${{ needs.build-env.outputs.ALL_BOARD_DATA }} + CORE_ARTIFACT: ArduinoCore-${{ matrix.artifact }}-${{ needs.build-env.outputs.CORE_HASH }}.tar.bz2 + CORE_TAG: ${{ needs.build-env.outputs.CORE_TAG }} + strategy: + matrix: + artifact: ${{ fromJSON( needs.build-env.outputs.ARTIFACTS ) }} + fail-fast: false + if: ${{ !cancelled() && needs.build-env.result == 'success' }} + steps: + + - uses: actions/checkout@v6 + with: + submodules: 'recursive' + fetch-depth: 0 + persist-credentials: false + fetch-tags: true + + # Get all built binaries + - uses: actions/download-artifact@v8 + with: + path: . + pattern: binaries-* + merge-multiple: true + + - name: Package core + run: | + # Extract the board binaries in place + # (each will also include the same copy of the API) + for f in binaries-*.tar.zstd ; do + tar --use-compress-program=unzstd -xpf $f + done + cat $(ls boards.local_*.txt | sort) >> boards.local.txt + # Create the core artifact for this set of boards + ./extra/package_core.sh ${{ matrix.artifact }} ${CORE_TAG} distrib/${CORE_ARTIFACT} + + - uses: actions/upload-artifact@v7 + id: upload-core + if: ${{ success() || failure() }} + with: + name: ${{ env.CORE_ARTIFACT }} + path: distrib/${{ env.CORE_ARTIFACT }} + archive: false + + - name: Archive artifact ID + run: | + echo '${{ steps.upload-core.outputs.artifact-id }}' > ${{ matrix.artifact }}.id + + - uses: actions/upload-artifact@v7 + with: + name: artifact-id-${{ matrix.artifact }} + path: ${{ matrix.artifact }}.id + + + + # Prepare this PR's temporary package index JSON by merging the newly + # built core packages with the latest package index from ci-builds. + + package-index: + name: Package index URL for offline tests + runs-on: ubuntu-latest + needs: + - build-env + - package-core + if: ${{ github.event_name == 'pull_request' && needs.build-env.outputs.CI_BUILDS_URL != '' }} + env: + CORE_HASH: ${{ needs.build-env.outputs.CORE_HASH }} + CORE_BRANCH: ${{ needs.build-env.outputs.CORE_BRANCH }} + ARTIFACTS: ${{ needs.build-env.outputs.ARTIFACTS }} + CI_BUILDS_URL: ${{ needs.build-env.outputs.CI_BUILDS_URL }} + steps: + + - uses: actions/checkout@v6 + with: + fetch-depth: 0 + persist-credentials: false + fetch-tags: true + + - uses: actions/download-artifact@v8 + with: + pattern: ArduinoCore-*.tar.bz2 + path: . + merge-multiple: true + + - uses: actions/download-artifact@v8 + with: + pattern: artifact-id-* + path: . + merge-multiple: true + + - name: Prepare PR package index + run: | + wget ${CI_BUILDS_URL} -O ci_index.json + # clear other platforms from the index + jq '.packages[0].platforms = []' ci_index.json > ci_index.tmp && mv ci_index.tmp ci_index.json + + mkdir -p snippets/platforms/ + jq -cr '.[]' <<< ${ARTIFACTS} | while read -r artifact; do + [ $artifact == "zephyr" ] && continue + ARTIFACT_FILE=ArduinoCore-${artifact}-${CORE_HASH}.tar.bz2 + PACKAGE_JSON=snippets/platforms/${artifact}.json + ./extra/gen_package_index_json.sh ${artifact} ${ARTIFACT_FILE} ${PACKAGE_JSON} + # replace the download URL with this PR's artifact link + ARTIFACT_ID=$(cat ${artifact}.id) + ARTIFACT_URL="https://api.github.com/repos/${{ github.repository }}/actions/artifacts/${ARTIFACT_ID}/zip" + sed -i -e "s!\"url\":.*!\"url\": \"${ARTIFACT_URL}\",!" ${PACKAGE_JSON} + # append the new snippet to the index + jq -s '.[0].packages[0].platforms += .[1].packages[0].platforms | .[0]' \ + ci_index.json ${PACKAGE_JSON} > ci_index.tmp && mv ci_index.tmp ci_index.json + done + PACKAGE_INDEX_FILE="package_arduino_zephyr_pr_${{ github.event.pull_request.number }}_ci_index.json" + echo "PACKAGE_INDEX_FILE=${PACKAGE_INDEX_FILE}" >> $GITHUB_ENV + mv ci_index.json ${PACKAGE_INDEX_FILE} + + - name: Archive PR package index + id: package-index-json + uses: actions/upload-artifact@v7 + with: + name: ${{ env.PACKAGE_INDEX_FILE }} + path: ${{ env.PACKAGE_INDEX_FILE }} + archive: false + + - name: Display final URL in the summary + run: | + ARTIFACT_ID=${{ steps.package-index-json.outputs.artifact-id }} + PACKAGE_INDEX_URL="https://api.github.com/repos/${{ github.repository }}/actions/artifacts/${ARTIFACT_ID}/zip" + PACKAGE_INDEX_URL="${PACKAGE_INDEX_URL}#${{ env.PACKAGE_INDEX_FILE }}" + echo "[${PACKAGE_INDEX_URL}](${PACKAGE_INDEX_URL})" >> $GITHUB_STEP_SUMMARY + + + + # After generating the final cores, the following temporary artifacts are + # no longer used and can be removed: + # + # - the Zephyr build environment + # - the API and per-board binaries + # - the artifact download URLs + + cleanup-build: + name: Clean up intermediates + runs-on: ubuntu-latest + needs: + - package-core + - package-index + permissions: + actions: write + steps: + + - uses: geekyeggo/delete-artifact@v6 + with: + name: | + arduino-api.tar.zstd + binaries-* + build-env.tar.zstd + artifact-id-* + failOnError: false + + + + # For each board and link mode, compile all test sketches using the just + # built core. The compilation reports are archived for later inspection. + # This step never fails, so that expected errors do not block the CI run. + + test-core: + # NOTE: this name is hardcoded in ci_collect_data.py + name: Test ${{ matrix.board }}:${{ matrix.link_mode }} + runs-on: ubuntu-latest + needs: + - build-env + - package-core + strategy: + matrix: + include: + ${{ fromJSON( needs.build-env.outputs.ALL_BOARD_FQBNS ) }} + fail-fast: false + env: + PLAT: arduino:${{ matrix.subarch }} + FQBN: arduino:${{ matrix.subarch }}:${{ matrix.board }}:link_mode=${{ matrix.link_mode }} + CORE_ARTIFACT: ArduinoCore-${{ matrix.artifact }}-${{ needs.build-env.outputs.CORE_HASH }}.tar.bz2 + ARTIFACT_TAG: ${{ needs.build-env.outputs.CORE_HASH }}-${{ matrix.board }}-${{ matrix.link_mode }} + CI_BUILDS_URL: ${{ needs.build-env.outputs.CI_BUILDS_URL }} + if: ${{ !cancelled() && needs.build-env.result == 'success' }} + steps: + + # only needs the test list generator and artifact information + - uses: actions/checkout@v6 + with: + fetch-depth: 0 + persist-credentials: false + sparse-checkout: | + extra/ci_apply_tests.sh + extra/artifacts/ + variants/*/test_setup.sh + sparse-checkout-cone-mode: false + + - uses: actions/download-artifact@v8 + with: + name: ${{ env.CORE_ARTIFACT }} + + - uses: actions/download-artifact@v8 + with: + name: test-data + path: test-data/ + + - name: Set up core + run: | + tar xf ${CORE_ARTIFACT} # will create ArduinoCore-zephyr/ + echo "REPORT_FILE=$(echo ${FQBN} | tr ':' '-').json" >> $GITHUB_ENV + + - name: Get test sketches + run: | + # sets ALL_TESTS and ALL_LIBRARIES env vars in GITHUB_ENV + extra/ci_apply_tests.sh ${{ matrix.artifact }} ${{ matrix.variant }} + + - name: Compile tests for ${{ matrix.board }} + uses: pillo79/compile-sketches@next + with: + # Use ci-builds core, if possible, to use the exact set of tools required by the source + fqbn: ${{ env.FQBN }} + platforms: | + # Use Board Manager version first to install the tools + - name: ${{ env.PLAT }} + ${{ env.CI_BUILDS_URL != '' && format('source-url: {0}', env.CI_BUILDS_URL) || '' }} + # ... then replace that with the local version + - name: ${{ env.PLAT }} + source-path: "ArduinoCore-zephyr" + sketch-paths: | + ${{ env.ALL_TESTS }} + libraries: | + ${{ env.ALL_LIBRARIES }} + cli-compile-flags: | + - '--build-property' + - 'compiler.c.extra_flags=-Wno-type-limits -Wno-missing-field-initializers' + - '--build-property' + - 'compiler.cpp.extra_flags=-Wno-type-limits -Wno-missing-field-initializers' + verbose: 'false' + enable-deltas-report: 'false' + enable-issues-report: 'true' + always-succeed: 'true' + + - name: Prepare log + if: ${{ success() || failure() }} + run: | + # make sure to create an empty report if none was created + [ ! -f sketches-reports/${REPORT_FILE} ] && mkdir -p sketches-reports && echo "{}" > sketches-reports/${REPORT_FILE} + # remove base path of the core install from all file references to make logs cleaner + sed -i -e 's!/home/runner/.arduino15/packages/arduino/hardware/zephyr/[^/]*/!!g' sketches-reports/${REPORT_FILE} + + # archive the compile report for later + - uses: actions/upload-artifact@v7 + if: ${{ success() || failure() }} + with: + name: test-report-${{ env.ARTIFACT_TAG }} + path: sketches-reports/* + retention-days: 1 + + + + # Collect all build and test reports, analyze them and produce a summary. + # See ci_collect_data.py and ci_generate_report.py for details. + + verify-core: + runs-on: ubuntu-latest + needs: + - build-env + - package-core + - test-core + if: ${{ !cancelled() }} + permissions: + contents: read + actions: read + env: + ALL_BOARD_DATA: ${{ needs.build-env.outputs.ALL_BOARD_DATA }} + CORE_VER: ${{ needs.build-env.outputs.CORE_VER }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_REPO: ${{ github.repository }} + steps: + + - uses: actions/checkout@v6 + with: + fetch-depth: 0 + persist-credentials: false + fetch-tags: true + + - uses: actions/download-artifact@v8 + with: + path: . + pattern: "*-report-*" + merge-multiple: true + + - name: Generate workflow summary + run: | + # gather the array of job metadata (especially name and ID) for the current workflow run + export WORKFLOW_JOBS=$(gh run view ${{ github.run_id }} --attempt ${{ github.run_attempt }} --json jobs --jq '.jobs') + # Archive the input set of reports for later inspection + tar jchf build-reports-${{ needs.build-env.outputs.CORE_HASH }}.tar.bz2 zephyr-* arduino-*.json + # Collect all CI data into a JSON file, then generate the report + extra/ci_collect_data.py build_info.json + extra/ci_generate_report.py build_info.json result summary full_log + cat result + + # Display the summary and full log in the step summary + cat summary >> $GITHUB_STEP_SUMMARY + cat full_log >> $GITHUB_STEP_SUMMARY + + # Create a comment for PRs using the summary file + if [ "${{ github.event_name }}" == "pull_request" ]; then + mkdir -p comment-request + echo "${{ github.event.pull_request.number }}" > comment-request/pr_number + echo -e "## Built \`$CORE_VER\`\n" > comment-request/comment_body + # strip LaTeX color commands and escape sequences for mail readability + cat summary | sed -e 's!\${\\color{\S*}\(.*\)}\$!\1!g' -e 's!\\%!%!g' >> comment-request/comment_body + fi + + # Prepare latest size artifact file on push events + if [ "${{ github.event_name }}" == "push" ]; then + tar jchf size-reports-${{ needs.build-env.outputs.CORE_HASH }}.tar.bz2 arduino-*.json + fi + + - name: Compute code size changes + if: ${{ github.event_name == 'pull_request' }} + run: | + export GITHUB_BASE_SHA=$(git rev-list --parents -n 1 HEAD | cut -d' ' -f2) + # errors due to race conditions with parallel branch runs should not fail the job + extra/ci_calc_size_reports.py ${GITHUB_BASE_SHA} sketches-reports/ || true + + # upload build metadata artifact, for upload to ci-builds + - name: Archive build metadata information + uses: actions/upload-artifact@v7 + with: + name: build-metadata + path: build_info.json + retention-days: 1 + + # upload comment request artifact (will be retrieved by leave_pr_comment.yml) + - name: Archive comment information + uses: actions/upload-artifact@v7 + if: ${{ github.event_name == 'pull_request' }} + with: + name: comment-request + path: comment-request/ + retention-days: 1 + + # upload size delta report artifact (will be retrieved by report_size_deltas.yml) + - name: Archive size deltas report information + uses: actions/upload-artifact@v7 + if: ${{ github.event_name == 'pull_request' }} + with: + name: sketches-reports + path: sketches-reports/ + retention-days: 1 + + # upload new official test size artifact (for AWS storage) + - name: Archive sketch size information + uses: actions/upload-artifact@v7 + if: ${{ github.event_name == 'push' }} + with: + name: size-reports + path: size-reports-${{ needs.build-env.outputs.CORE_HASH }}.tar.bz2 + retention-days: 1 + archive: false + + # upload input set of build reports artifact (for CI debugging) + - name: Archive input test reports + uses: actions/upload-artifact@v7 + with: + name: build-reports + path: build-reports-${{ needs.build-env.outputs.CORE_HASH }}.tar.bz2 + retention-days: 1 + archive: false + + # The last line makes the job fail if the 'result' file does not contain "PASSED". + # No further actions are allowed in case of error. + - run: | + cat result + grep -q "PASSED" result # otherwise CI test failed + + + + # Clean up test results only if the verification actually passed, so that + # they are still available for action re-runs in case of failure. + + clean-temps: + name: Clean up test results + runs-on: ubuntu-latest + if: ${{ needs.verify-core.result == 'success' }} + needs: + - build-env + - package-core + - verify-core + permissions: + actions: write + steps: + + - name: Clean up intermediate artifacts + uses: geekyeggo/delete-artifact@v6 + with: + name: | + build-report-* + test-report-* + failOnError: false + + + + # Prepare the package index JSON snippets for the newly built core packages. + # (Arduino's S3/ci-builds publishing jobs are intentionally not replicated + # here: they need Arduino-only secrets this fork doesn't have.) + + prepare-json: + name: Prepare jsons + runs-on: ubuntu-latest + needs: + - build-env + - package-core + - verify-core + env: + CORE_TAG: ${{ needs.build-env.outputs.CORE_TAG }} + CORE_HASH: ${{ needs.build-env.outputs.CORE_HASH }} + ARTIFACTS: ${{ needs.build-env.outputs.ARTIFACTS }} + steps: + + - uses: actions/checkout@v6 + with: + fetch-depth: 0 + persist-credentials: false + fetch-tags: true + + - uses: actions/download-artifact@v8 + with: + pattern: ArduinoCore-*.tar.bz2 + path: . + merge-multiple: true + + - uses: actions/download-artifact@v8 + with: + name: build-metadata + path: snippets/metadata/ + + - name: Prepare package index snippets + run: | + mkdir -p snippets/platforms/ + jq -cr '.[]' <<< ${ARTIFACTS} | while read -r artifact; do + # note: the archive names are always hash-based so they use a + # predictable pattern. JSON files can use the tag for user-friendliness. + ARTIFACT_FILE=ArduinoCore-${artifact}-${CORE_HASH}.tar.bz2 + PACKAGE_JSON=snippets/platforms/ArduinoCore-${artifact}-${CORE_TAG}.json + ./extra/gen_package_index_json.sh ${artifact} ${ARTIFACT_FILE} ${PACKAGE_JSON} + done + + - name: Archive package index snippets + uses: actions/upload-artifact@v7 + with: + name: snippets-${{ env.CORE_TAG }} + path: snippets/ diff --git a/.github/workflows/release_boards.yml b/.github/workflows/release_boards.yml new file mode 100644 index 000000000..c1a8abd0c --- /dev/null +++ b/.github/workflows/release_boards.yml @@ -0,0 +1,272 @@ +# Copyright (c) Arduino s.r.l. and/or its affiliated companies +# SPDX-License-Identifier: Apache-2.0 + +# Generic Infineon release workflow: triggered manually, or by pushing a +# semver tag. Bumps the version (when not already tagged), tags the commit, +# and publishes one release package per board release group (as declared by +# .build.release_group in boards.txt), reusing this single workflow +# instead of one workflow per board/group. +# +# Releases are only allowed from family branches (RELEASE_BRANCHES below): +# workflow_dispatch must be run on one of them, and a pushed tag must point +# to a commit reachable from one of them. +# +# Requires a successful "Package, test and upload core" run for the released +# commit, whose artifacts are reused (nothing is rebuilt here). +# +# A release group is only published if both of these exist: +# - at least one board with build.release_group= in boards.txt +# - a matching package/package_infineon__index.template.json + +name: Release boards + +on: + workflow_dispatch: {} + push: + tags: + - '[0-9]+.[0-9]+.[0-9]+' + +permissions: + contents: read + +jobs: + + discover-release-groups: + name: Discover release groups + runs-on: ubuntu-latest + if: ${{ endsWith(github.repository, '/ArduinoCore-zephyr') }} + outputs: + groups: ${{ steps.groups.outputs.groups }} + permissions: + contents: read + env: + RELEASE_BRANCHES: edge-main control-main + steps: + + - uses: actions/checkout@v6 + with: + fetch-depth: 0 + + - name: Validate release is from an allowed family branch + run: | + if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then + BRANCH="${{ github.ref_name }}" + for b in $RELEASE_BRANCHES; do + [ "$BRANCH" == "$b" ] && { echo "Dispatched from allowed branch: $BRANCH"; exit 0; } + done + echo "::error::Releases can only be dispatched from: $RELEASE_BRANCHES (got '$BRANCH')" + exit 1 + fi + + # tag push: the tagged commit must be reachable from an allowed branch + git fetch origin $RELEASE_BRANCHES + for b in $RELEASE_BRANCHES; do + if git merge-base --is-ancestor "${{ github.sha }}" "origin/$b"; then + echo "Tag ${{ github.ref_name }} (${{ github.sha }}) is on $b" + exit 0 + fi + done + echo "::error::Tag ${{ github.ref_name }} (${{ github.sha }}) is not reachable from: $RELEASE_BRANCHES" + exit 1 + + - name: Discover release groups with a matching package template + id: groups + run: | + BOARD_GROUPS=$(extra/get_board_details.sh | jq -c '[.[] | select(.release_group != "") | .release_group] | unique') + TEMPLATE_GROUPS=$(basename -a package/package_infineon_*_index.template.json 2>/dev/null \ + | sed -e 's/^package_infineon_//' -e 's/_index\.template\.json$//' \ + | jq -R -s -c 'split("\n") | map(select(length > 0))') + GROUPS=$(jq -c -n --argjson boards "$BOARD_GROUPS" --argjson templates "$TEMPLATE_GROUPS" \ + '[$boards[] | select(. as $g | $templates | index($g))]') + echo "groups=${GROUPS}" >> "$GITHUB_OUTPUT" + echo "Discovered release groups: ${GROUPS}" + + resolve-release: + name: Resolve release tag and build run + runs-on: ubuntu-latest + needs: + - discover-release-groups + if: ${{ needs.discover-release-groups.outputs.groups != '[]' }} + permissions: + contents: write + actions: read + outputs: + release_tag: ${{ steps.release_tag.outputs.release_tag }} + build_run_id: ${{ steps.build_run.outputs.build_run_id }} + env: + GH_TOKEN: ${{ github.token }} + GH_REPO: ${{ github.repository }} + steps: + + - uses: actions/checkout@v6 + with: + fetch-depth: 0 + fetch-tags: true + + - name: Compute release tag + id: release_tag + env: + RELEASE_BUMP: patch + run: | + if [ "${{ github.ref_type }}" == "tag" ]; then + echo "release_tag=${{ github.ref_name }}" >> "$GITHUB_OUTPUT" + exit 0 + fi + + git fetch --tags + + EXISTING_TAG=$(git tag --points-at "${{ github.sha }}" --list '[0-9]*.[0-9]*.[0-9]*' --sort=-v:refname | head -n1) + if [ -n "${EXISTING_TAG}" ]; then + echo "Using existing tag on HEAD: ${EXISTING_TAG}" + echo "release_tag=${EXISTING_TAG}" >> "$GITHUB_OUTPUT" + exit 0 + fi + + LAST_TAG=$(git tag --list '[0-9]*.[0-9]*.[0-9]*' --sort=-v:refname | head -n1) + if [ -z "${LAST_TAG}" ]; then + LAST_TAG="0.0.0" + fi + + IFS='.' read -r MAJOR MINOR PATCH <<< "${LAST_TAG}" + case "${RELEASE_BUMP}" in + major) + MAJOR=$((MAJOR + 1)) + MINOR=0 + PATCH=0 + ;; + minor) + MINOR=$((MINOR + 1)) + PATCH=0 + ;; + *) + PATCH=$((PATCH + 1)) + ;; + esac + + NEW_TAG="${MAJOR}.${MINOR}.${PATCH}" + echo "release_tag=${NEW_TAG}" >> "$GITHUB_OUTPUT" + + - name: Create release (and tag if missing) + env: + TAG: ${{ steps.release_tag.outputs.release_tag }} + run: | + if gh release view "${TAG}" >/dev/null 2>&1; then + echo "Release ${TAG} already exists" + else + gh release create "${TAG}" \ + --target "${{ github.sha }}" \ + --title "ArduinoCore-zephyr ${TAG}" \ + --notes "Release for ${{ github.sha }}." + fi + + - name: Find successful package build for this commit + id: build_run + run: | + RUN_ID=$(gh run list --workflow "package_core.yml" --json databaseId,headSha,conclusion,createdAt \ + --jq "[.[] | select(.headSha == \"${{ github.sha }}\" and .conclusion == \"success\")] | sort_by(.createdAt) | last | .databaseId") + if [ -z "${RUN_ID}" ] || [ "${RUN_ID}" == "null" ]; then + echo "::error::No successful 'Package, test and upload core' run found for commit ${{ github.sha }}. Push/re-run it before releasing." >&2 + exit 1 + fi + echo "build_run_id=${RUN_ID}" >> "$GITHUB_OUTPUT" + + publish-release-group: + name: Publish ${{ matrix.release_group }} release assets + runs-on: ubuntu-latest + needs: + - discover-release-groups + - resolve-release + if: ${{ needs.resolve-release.result == 'success' }} + strategy: + matrix: + release_group: ${{ fromJSON(needs.discover-release-groups.outputs.groups) }} + fail-fast: false + # Serialize uploads to avoid concurrent asset uploads to the same release. + max-parallel: 1 + permissions: + contents: write + actions: read + env: + GH_TOKEN: ${{ github.token }} + GH_REPO: ${{ github.repository }} + TAG: ${{ needs.resolve-release.outputs.release_tag }} + RELEASE_GROUP: ${{ matrix.release_group }} + steps: + + - uses: actions/checkout@v6 + with: + fetch-depth: 0 + persist-credentials: false + fetch-tags: true + + - name: Determine core artifact for this release group + id: artifact + run: | + ARTIFACT=$(extra/get_board_details.sh | jq -r --arg g "${RELEASE_GROUP}" '[.[] | select(.release_group == $g)][0].artifact') + if [ -z "${ARTIFACT}" ] || [ "${ARTIFACT}" == "null" ]; then + echo "No board found for release group '${RELEASE_GROUP}'" >&2 + exit 1 + fi + echo "ARTIFACT=${ARTIFACT}" >> "$GITHUB_ENV" + + - name: Download ${{ env.ARTIFACT }} artifact from the resolved build run + uses: actions/download-artifact@v8 + with: + pattern: ArduinoCore-${{ env.ARTIFACT }}-* + path: release-assets + merge-multiple: true + run-id: ${{ needs.resolve-release.outputs.build_run_id }} + github-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Create release-group archive + run: | + if [ -z "${TAG}" ]; then + echo "Release tag is empty" >&2 + exit 1 + fi + + TAR_FILE=$(find release-assets -maxdepth 1 -name "ArduinoCore-${ARTIFACT}-*.tar.bz2" -print -quit) + if [ -z "${TAR_FILE}" ]; then + echo "Downloaded artifact does not contain expected tarball" >&2 + exit 1 + fi + + TAR_BASENAME="ArduinoCore-zephyr_${RELEASE_GROUP}-${TAG}.tar.bz2" + ./extra/package_release_group.sh "${RELEASE_GROUP}" "${TAR_FILE}" "release-assets/${TAR_BASENAME}" + rm -f "${TAR_FILE}" + echo "TAR_BASENAME=${TAR_BASENAME}" >> "$GITHUB_ENV" + + - name: Generate package index JSON + run: | + ARTIFACT_PATH="release-assets/${TAR_BASENAME}" + SIZE=$(wc -c < "${ARTIFACT_PATH}") + SHA256=$(sha256sum "${ARTIFACT_PATH}" | cut -d' ' -f1) + URL="https://github.com/${GH_REPO}/releases/download/${TAG}/${TAR_BASENAME}" + TEMPLATE="package/package_infineon_${RELEASE_GROUP}_index.template.json" + + python3 - <> $env:GITHUB_ENV + + - name: Compute SHA-256 and size + run: | + $hash = (Get-FileHash -Algorithm SHA256 $env:TAR_NAME).Hash.ToLower() + $size = (Get-Item $env:TAR_NAME).Length + echo "TAR_SHA256=$hash" >> $env:GITHUB_ENV + echo "TAR_SIZE=$size" >> $env:GITHUB_ENV + + - name: Upload to GitHub Release + uses: softprops/action-gh-release@v2 + with: + tag_name: ${{ github.event.inputs.release_tag }} + files: ${{ env.TAR_NAME }} + + - name: Print package index values + run: | + Write-Host "" + Write-Host "=== Paste these into the Windows entry of the package index template ===" + Write-Host "archiveFileName : $env:TAR_NAME" + Write-Host "url : https://github.com/${{ github.repository }}/releases/download/${{ github.event.inputs.release_tag }}/$env:TAR_NAME" + Write-Host "checksum : SHA-256:$env:TAR_SHA256" + Write-Host "size : $env:TAR_SIZE" diff --git a/.github/workflows/sync_upstream_main.yml b/.github/workflows/sync_upstream_main.yml new file mode 100644 index 000000000..70d534586 --- /dev/null +++ b/.github/workflows/sync_upstream_main.yml @@ -0,0 +1,117 @@ +name: Sync main with upstream + +# Keeps the fork's main branch synchronized with arduino/ArduinoCore-zephyr's +# main branch. Infineon-specific commits belong on the downstream branches. + +on: + schedule: + - cron: '0 3 * * *' # nightly, 03:00 UTC + workflow_dispatch: + +permissions: + contents: write + +jobs: + sync: + if: ${{ github.repository != 'arduino/ArduinoCore-zephyr' }} + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + with: + ref: main + fetch-depth: 0 + token: ${{ secrets.GH_ACT_SYNCH_UPSTREAM }} + persist-credentials: false + + - name: Sync main from upstream + id: sync + uses: aormsby/Fork-Sync-With-Upstream-action@v3.4.1 + with: + target_sync_branch: main + target_repo_token: ${{ secrets.GH_ACT_SYNCH_UPSTREAM }} + upstream_sync_branch: main + upstream_sync_repo: arduino/ArduinoCore-zephyr + upstream_repo_access_token: ${{ secrets.GH_ACT_SYNCH_UPSTREAM }} + + - name: Main sync result + if: steps.sync.outputs.has_new_commits == 'true' + run: echo "New commits were found to sync into main." + + - name: Main already up to date + if: steps.sync.outputs.has_new_commits == 'false' + run: echo "main was already up to date." + + - name: Show main sync status + run: echo "has_new_commits=${{ steps.sync.outputs.has_new_commits }}" + + # Rebase the common Infineon branch onto the synchronized fork mirror. + rebase-ifx-main: + needs: sync + if: ${{ github.repository != 'arduino/ArduinoCore-zephyr' }} + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + with: + ref: ifx-main + token: ${{ secrets.GH_ACT_SYNCH_UPSTREAM }} + + - name: Rebase ifx-main onto main + id: sync + uses: aormsby/Fork-Sync-With-Upstream-action@v3.4.1 + with: + target_sync_branch: ifx-main + target_repo_token: ${{ secrets.GH_ACT_SYNCH_UPSTREAM }} + upstream_sync_branch: main + upstream_sync_repo: ${{ github.repository }} + git_config_pull_rebase: true + target_branch_push_args: '--force-with-lease' + + - name: ifx-main sync result + if: steps.sync.outputs.has_new_commits == 'true' + run: echo "New commits were found to sync into ifx-main." + + - name: ifx-main already up to date + if: steps.sync.outputs.has_new_commits == 'false' + run: echo "ifx-main was already up to date." + + - name: Show ifx-main sync status + run: echo "has_new_commits=${{ steps.sync.outputs.has_new_commits }}" + + # Rebase each MCU-family branch onto the common Infineon branch. + rebase-mcu-branches: + needs: rebase-ifx-main + if: ${{ github.repository != 'arduino/ArduinoCore-zephyr' }} + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + branch: + - edge-main + - control-main + steps: + - uses: actions/checkout@v7 + with: + ref: ${{ matrix.branch }} + token: ${{ secrets.GH_ACT_SYNCH_UPSTREAM }} + + - name: Rebase family branch onto ifx-main + id: sync + uses: aormsby/Fork-Sync-With-Upstream-action@v3.4.1 + with: + target_sync_branch: ${{ matrix.branch }} + target_repo_token: ${{ secrets.GH_ACT_SYNCH_UPSTREAM }} + upstream_sync_branch: ifx-main + upstream_sync_repo: ${{ github.repository }} + git_config_pull_rebase: true + target_branch_push_args: '--force-with-lease' + + - name: Family branch sync result + if: steps.sync.outputs.has_new_commits == 'true' + run: echo "New commits were found to sync into ${{ matrix.branch }}." + + - name: Family branch already up to date + if: steps.sync.outputs.has_new_commits == 'false' + run: echo "${{ matrix.branch }} was already up to date." + + - name: Show family branch sync status + run: echo "${{ matrix.branch }} has_new_commits=${{ steps.sync.outputs.has_new_commits }}" diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 000000000..c0a89d397 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,17 @@ +repos: + - repo: local + hooks: + - id: arduino-zephyr-commit-message + name: Check commit message format + entry: >- + python3 -c "import re, sys; lines = open(sys.argv[1], encoding='utf-8').read().splitlines(); msg = lines[0] if lines else ''; sys.exit(0 if re.fullmatch(r'^[^!]+: [A-Za-z]+.+ .+$', msg) and re.fullmatch(r'^[^#].{10,80}$', msg) else 1)" + language: system + stages: [commit-msg] + pass_filenames: true + - id: arduino-zephyr-clang-format + name: Check clang-format + entry: >- + bash -c 'formatter=$(command -v clang-format-19 || command -v clang-format) || { echo "clang-format or clang-format-19 is required" >&2; exit 1; }; "$formatter" --dry-run --Werror "$@"' -- + language: system + files: '^(cores/arduino|loader|libraries)/.*\.(c|cpp|h|hpp)$' + exclude: '^(cores/arduino/api/|loader/llext_exports\.c$|loader/blobs/4343WA1_.*\.c$|loader/blobs/wifi_nvram_image_data\.h$|libraries/examples/|libraries/extras/|libraries/ea_malloc/|libraries/Storage/examples/FlashFormat/4343WA1_bin\.h$)' diff --git a/README.md b/README.md index ddef61b37..4c2684943 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,41 @@ -[![Default branch status](https://github.com/arduino/ArduinoCore-zephyr/actions/workflows/package_core.yml/badge.svg?branch=main&event=push)](https://github.com/arduino/ArduinoCore-zephyr/actions/workflows/package_core.yml) +[![Branch status](https://github.com/Infineon/ArduinoCore-zephyr/actions/workflows/package_core.yml/badge.svg?branch=ifx-main&event=push)](https://github.com/Infineon/ArduinoCore-zephyr/actions/workflows/package_core.yml?query=branch%3Aifx-main) -# 🪁 Arduino Core for Zephyr +# Infineon ArduinoCore-Zephyr + +This repository hosts the enablement of Infineon microcontrollers in +[ArduinoCore-Zephyr](https://github.com/zephyrproject-rtos/arduino-core-zephyr). + +> [!NOTE] +> This project is still in early development and may change as Infineon +> microcontroller support evolves. + +The [`ifx-main`](https://github.com/Infineon/ArduinoCore-zephyr/tree/ifx-main) +branch extends the upstream project with the configuration and workflows needed +to enable preliminary releases before the changes are officially merged +upstream. + +## Supported Infineon Microcontrollers + +Infineon support is currently being implemented for two microcontrollers families: + +* [**PSOC™ Edge**](https://www.infineon.com/products/microcontroller/32-bit-psoc-arm-cortex/32-bit-psoc-edge-arm): Development is hosted in the + [`edge-main`](https://github.com/Infineon/ArduinoCore-zephyr/tree/edge-main) + branch. + +> [!TIP] +> The installation instructions for the basic PSOC™ Edge enablement, version +> `0.0.1`, are temporarily available in the +> [`psoc-edge-main`](https://github.com/Infineon/ArduinoCore-zephyr/tree/psoc-edge-main) +> branch. + + +* [**PSOC™ Control**](https://www.infineon.com/products/microcontroller/32-bit-psoc-arm-cortex/32-bit-psoc-control-arm-cortex-m33-mcu): Development is hosted in the + [`control-main`](https://github.com/Infineon/ArduinoCore-zephyr/tree/control-main) + branch. + +-------------------------------------- + +## Arduino Core for Zephyr This repository is a downstream fork of the [Arduino Core for Zephyr RTOS-based boards](https://github.com/zephyrproject-rtos/arduino-core-zephyr) that diff --git a/api_support_tracking.md b/api_support_tracking.md new file mode 100644 index 000000000..f717596f6 --- /dev/null +++ b/api_support_tracking.md @@ -0,0 +1,162 @@ +### PSE84 Arduino API Support Tracking + +#### Legend +| Symbol | Meaning | +|--------|---------| +| ✅ | Confirmed working | +| ⚠️ | Not yet tested | +| ❌ | Not yet supported | + +--- + +#### API Support Table + +| Function | Scope | Status | +|----------|-------|--------| +| **Digital I/O** | | | +| `digitalRead()` | Digital GPIO | ✅ | +| `digitalWrite()` | Digital GPIO | ✅ | +| `pinMode()` | Digital GPIO | ✅ | +| **Analog I/O** | | | +| `analogRead()` | Analog | ❌ | +| `analogReadResolution()` | Analog | ❌ | +| `analogReference()` | Analog | ❌ | +| `analogWrite()` | Analog | ❌ | +| `analogWriteResolution()` | Analog | ❌ | +| **Advanced I/O** | | | +| `tone()` | Digital GPIO | ⚠️ | +| `noTone()` | Digital GPIO | ⚠️ | +| `pulseIn()` | Digital GPIO | ⚠️ | +| `pulseInLong()` | Digital GPIO | ⚠️ | +| `shiftIn()` | Digital GPIO | ⚠️ | +| `shiftOut()` | Digital GPIO | ⚠️ | +| **Time** | | | +| `delay()` | Timing | ✅ | +| `delayMicroseconds()` | Timing | ⚠️ | +| `millis()` | Timing | ✅ | +| `micros()` | Timing | ✅ | +| **Math** | | | +| `abs()` | Math | ⚠️ | +| `constrain()` | Math | ⚠️ | +| `map()` | Math | ⚠️ | +| `max()` | Math | ⚠️ | +| `min()` | Math | ⚠️ | +| `pow()` | Math | ⚠️ | +| `sq()` | Math | ⚠️ | +| `sqrt()` | Math | ⚠️ | +| **Trigonometry** | | | +| `cos()` | Math | ⚠️ | +| `sin()` | Math | ⚠️ | +| `tan()` | Math | ⚠️ | +| **Characters** | | | +| `isAlpha()` | Characters | ⚠️ | +| `isAlphaNumeric()` | Characters | ⚠️ | +| `isAscii()` | Characters | ⚠️ | +| `isControl()` | Characters | ⚠️ | +| `isDigit()` | Characters | ⚠️ | +| `isGraph()` | Characters | ⚠️ | +| `isHexadecimalDigit()` | Characters | ⚠️ | +| `isLowerCase()` | Characters | ⚠️ | +| `isPrintable()` | Characters | ⚠️ | +| `isPunct()` | Characters | ⚠️ | +| `isSpace()` | Characters | ⚠️ | +| `isUpperCase()` | Characters | ⚠️ | +| `isWhitespace()` | Characters | ⚠️ | +| **Random Numbers** | | | +| `random()` | Random | ⚠️ | +| `randomSeed()` | Random | ⚠️ | +| **Bits and Bytes** | | | +| `bit()` | Bits & Bytes | ⚠️ | +| `bitClear()` | Bits & Bytes | ⚠️ | +| `bitRead()` | Bits & Bytes | ⚠️ | +| `bitSet()` | Bits & Bytes | ⚠️ | +| `bitWrite()` | Bits & Bytes | ⚠️ | +| `highByte()` | Bits & Bytes | ⚠️ | +| `lowByte()` | Bits & Bytes | ⚠️ | +| **External Interrupts** | | | +| `attachInterrupt()` | Interrupts | ✅ | +| `detachInterrupt()` | Interrupts | ✅ | +| `digitalPinToInterrupt()` | Interrupts | ✅ | +| **Interrupts** | | | +| `interrupts()` | Interrupts | ⚠️ | +| `noInterrupts()` | Interrupts | ⚠️ | +| **Stream** | | | +| `available()` | Serial / UART | ⚠️ | +| `read()` | Serial / UART | ⚠️ | +| `flush()` | Serial / UART | ⚠️ | +| `find()` | Serial / UART | ⚠️ | +| `findUntil()` | Serial / UART | ⚠️ | +| `peek()` | Serial / UART | ⚠️ | +| `readBytes()` | Serial / UART | ⚠️ | +| `readBytesUntil()` | Serial / UART | ⚠️ | +| `readString()` | Serial / UART | ⚠️ | +| `readStringUntil()` | Serial / UART | ⚠️ | +| `parseInt()` | Serial / UART | ⚠️ | +| `parseFloat()` | Serial / UART | ⚠️ | +| `setTimeout()` | Serial / UART | ⚠️ | +| **Serial** | | | +| `if(Serial)` | Serial / UART | ⚠️ | +| `Serial1` / `Serial2` | Serial / UART | ⚠️ | +| USB Serial | Serial / UART | ⚠️ | +| `Serial.available()` | Serial / UART | ⚠️ | +| `Serial.availableForWrite()` | Serial / UART | ⚠️ | +| `Serial.begin()` | Serial / UART | ✅ | +| `Serial.end()` | Serial / UART | ⚠️ | +| `Serial.find()` | Serial / UART | ⚠️ | +| `Serial.findUntil()` | Serial / UART | ⚠️ | +| `Serial.flush()` | Serial / UART | ⚠️ | +| `Serial.parseFloat()` | Serial / UART | ⚠️ | +| `Serial.parseInt()` | Serial / UART | ⚠️ | +| `Serial.peek()` | Serial / UART | ⚠️ | +| `Serial.print()` | Serial / UART | ✅ | +| `Serial.println()` | Serial / UART | ✅ | +| `Serial.read()` | Serial / UART | ⚠️ | +| `Serial.readBytes()` | Serial / UART | ⚠️ | +| `Serial.readBytesUntil()` | Serial / UART | ⚠️ | +| `Serial.readString()` | Serial / UART | ⚠️ | +| `Serial.readStringUntil()` | Serial / UART | ⚠️ | +| `Serial.setTimeout()` | Serial / UART | ⚠️ | +| `Serial.write()` | Serial / UART | ⚠️ | +| `Serial.serialEvent()` | Serial / UART | ⚠️ | +| **SPI** | | | +| `SPI` | SPI | ❌ | +| I2C (Wire) | | | +| `Wire` / `Wire1` | I2C | ✅ | +| `Wire.begin()` | I2C | ⚠️ | +| `Wire.end()` | I2C | ⚠️ | +| `Wire.requestFrom()` | I2C | ⚠️ | +| `Wire.beginTransmission()` | I2C | ⚠️ | +| `Wire.endTransmission()` | I2C | ⚠️ | +| `Wire.write()` | I2C | ⚠️ | +| `Wire.available()` | I2C | ⚠️ | +| `Wire.read()` | I2C | ⚠️ | +| `Wire.setClock()` | I2C | ⚠️ | +| `Wire.onReceive()` | I2C | ⚠️ | +| `Wire.onRequest()` | I2C | ⚠️ | +| `Wire.setWireTimeout()` | I2C | ⚠️ | +| `Wire.clearWireTimeoutFlag()` | I2C | ⚠️ | +| `Wire.getWireTimeoutFlag()` | I2C | ⚠️ | +| **Sketch** | | | +| `loop()` | Core | ✅ | +| `setup()` | Core | ✅ | +| **Other** | | | +| `init()` | Core | ⚠️ | +| `initVariant()` | Core | ⚠️ | +| `yield()` | Timing | ✅ | +| Threads | Libraries | ❌ | +| CAN | Libraries | ❌ | +| Ethernet | Libraries | ❌ | +| RTC | Libraries | ❌ | +| WiFi | Libraries | ❌ | +| USB Peripherals | Libraries | ❌ | + +--- + +#### Reference Links + +| Resource | URL | +|----------|-----| +| Arduino API Reference | https://www.arduino.cc/reference/en/ | +| Arduino API Programming Reference | https://docs.arduino.cc/learn/programming/reference/ | +| ArduinoCore-API (source of truth) | https://github.com/arduino/ArduinoCore-API | +| ArduinoCore-API `/api` folder | https://github.com/arduino/ArduinoCore-API/tree/master/api | \ No newline at end of file diff --git a/boards.txt b/boards.txt index 798564387..4262baf49 100644 --- a/boards.txt +++ b/boards.txt @@ -727,3 +727,64 @@ ventunoq.bootloader.tool=remoteocd ventunoq.bootloader.tool.default=remoteocd ventunoq.bootloader.file=zephyr-{build.variant}.elf ventunoq.bootloader.target=stm32h5f5xx + +############################################################################################################## + +kit_pse84_ai.name=Infineon KIT-PSE84-AI (PSOC Edge E84) +kit_pse84_ai.build.core=arduino +kit_pse84_ai.build.crossprefix=arm-zephyr-eabi- +kit_pse84_ai.build.compiler_path={runtime.tools.arm-zephyr-eabi-1.0.1.path}/bin/ + +kit_pse84_ai.menu.debug.false=Standard +kit_pse84_ai.menu.debug.true=Debug +kit_pse84_ai.menu.debug.true.build.zsk_args.debug=-debug + +kit_pse84_ai.menu.link_mode.dynamic=Dynamic +kit_pse84_ai.menu.link_mode.static=Static +kit_pse84_ai.menu.link_mode.static.build.link_mode=static +kit_pse84_ai.menu.link_mode.static.upload.extension=bin-zsk.bin + +kit_pse84_ai.build.zephyr_target=kit_pse84_ai/pse846gps2dbzc4a/m33 +kit_pse84_ai.build.zephyr_args= +kit_pse84_ai.build.zephyr_hals=hal_infineon +kit_pse84_ai.build.variant=kit_pse84_ai_pse846gps2dbzc4a_m33 +kit_pse84_ai.build.release_group=pse84 +kit_pse84_ai.build.feature_board=true +kit_pse84_ai.build.ci_native_samples=blinky_arduino,hello_arduino,threads_arduino +kit_pse84_ai.build.mcu=cortex-m33 +kit_pse84_ai.build.fpu=-mfpu=fpv5-sp-d16 +kit_pse84_ai.build.architecture=cortex-m33 +kit_pse84_ai.build.float-abi=-mfloat-abi=hard +kit_pse84_ai.compiler.zephyr.specs= +kit_pse84_ai.build.extra_flags= +kit_pse84_ai.build.specs= +kit_pse84_ai.build.link_command="{compiler.path}{compiler.c.elf.cmd}" "-L{build.path}" "-L{build.variant.path}" {compiler.c.elf.flags} {compiler.c.elf.extra_flags} {build.extra_flags} {build.extra_ldflags} {compiler.zephyr.common_ldflags} {compiler.ldflags} {object_files} -Wl,--start-group "{build.path}/{archive_file}" {compiler.zephyr.extra_ldflags} {compiler.libraries.ldflags} -Wl,--end-group {build.link_args.{build.link_mode}} +kit_pse84_ai.build.postbuild.cmd="{tools.openocd.path}/{tools.openocd.cmd}" exit +kit_pse84_ai.build.board=KIT_PSE84_AI +kit_pse84_ai.upload.address=0x60200000 +kit_pse84_ai.upload.target=pse84 +kit_pse84_ai.upload.tool=openocd +kit_pse84_ai.upload.tool.default=openocd +kit_pse84_ai.tools.openocd.path={runtime.tools.openocd.path} +kit_pse84_ai.tools.openocd.cmd=bin/openocd +kit_pse84_ai.tools.openocd.cmd.windows=bin/openocd.exe +kit_pse84_ai.programmer.default=cmsis-dap +kit_pse84_ai.tools.openocd.upload.pattern="{path}/{cmd}" {upload.verbose} -s "{path}/scripts/" -s "{path}/share/openocd/scripts/" -s "{runtime.platform.path}/variants/{build.variant}/" -f "{runtime.platform.path}/variants/{build.variant}/openocd.cfg" -c "telnet_port disabled; init; reset init; halt; adapter speed 10000; flash write_image erase {{build.path}/{build.project_name}.{upload.extension}} {upload.address} bin; reset run; shutdown" +kit_pse84_ai.tools.openocd.program.pattern="{path}/{cmd}" {program.verbose} -s "{path}/scripts/" -s "{path}/share/openocd/scripts/" -s "{runtime.platform.path}/variants/{build.variant}/" -f "{runtime.platform.path}/variants/{build.variant}/openocd.cfg" -c "telnet_port disabled; init; reset init; halt; adapter speed 10000; flash write_image erase {{build.path}/{build.project_name}.{upload.extension}} {upload.address} bin; reset run; shutdown" +kit_pse84_ai.tools.openocd.bootloader.pattern="{path}/{cmd}" {bootloader.verbose} -s "{path}/scripts/" -s "{path}/share/openocd/scripts/" -s "{runtime.platform.path}/variants/{build.variant}/" -f "{runtime.platform.path}/variants/{build.variant}/openocd.cfg" -c "telnet_port disabled; init; reset init; halt; adapter speed 10000; program {{runtime.platform.path}/firmwares/zephyr-{build.variant}.hex}; reset run; shutdown" +kit_pse84_ai.tools.openocd.upload.pattern.windows=cmd /C cd /D "{build.path}" && "{path}/{cmd}" {upload.verbose} -s "{path}/scripts/" -s "{path}/share/openocd/scripts/" -s "{runtime.platform.path}/variants/{build.variant}/" -f "{runtime.platform.path}/variants/{build.variant}/openocd.cfg" -c "set sketch_file [list {build.project_name}.{upload.extension}]; telnet_port disabled; init; reset init; halt; adapter speed 10000; flash write_image erase $sketch_file {upload.address} bin; reset run; shutdown" +kit_pse84_ai.tools.openocd.program.pattern.windows=cmd /C cd /D "{build.path}" && "{path}/{cmd}" {program.verbose} -s "{path}/scripts/" -s "{path}/share/openocd/scripts/" -s "{runtime.platform.path}/variants/{build.variant}/" -f "{runtime.platform.path}/variants/{build.variant}/openocd.cfg" -c "set sketch_file [list {build.project_name}.{upload.extension}]; telnet_port disabled; init; reset init; halt; adapter speed 10000; flash write_image erase $sketch_file {upload.address} bin; reset run; shutdown" +kit_pse84_ai.upload.protocol= +kit_pse84_ai.upload.transport= +kit_pse84_ai.upload.interface=0 +kit_pse84_ai.upload.use_1200bps_touch=false +kit_pse84_ai.upload.wait_for_upload_port=false +kit_pse84_ai.upload.native_usb=false +kit_pse84_ai.upload.maximum_size=1047552 +kit_pse84_ai.upload.maximum_data_size=135168 +kit_pse84_ai.bootloader.tool=openocd +kit_pse84_ai.bootloader.tool.default=openocd +kit_pse84_ai.tools.openocd.bootloader.pattern.windows=cmd /C cd /D "{runtime.platform.path}/firmwares" && "{path}/{cmd}" {bootloader.verbose} -s "{path}/scripts/" -s "{path}/share/openocd/scripts/" -s "{runtime.platform.path}/variants/{build.variant}/" -f "{runtime.platform.path}/variants/{build.variant}/openocd.cfg" -c "set bootloader_file [list zephyr-{build.variant}.hex]; telnet_port disabled; init; reset init; halt; adapter speed 10000; program $bootloader_file; reset run; shutdown" +kit_pse84_ai.bootloader.target=pse84 + +############################################################################################################## diff --git a/extra/ci_build_native_samples.sh b/extra/ci_build_native_samples.sh new file mode 100755 index 000000000..202db103b --- /dev/null +++ b/extra/ci_build_native_samples.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +# Copyright (c) Arduino s.r.l. and/or its affiliated companies +# SPDX-License-Identifier: Apache-2.0 + +# Native-builds each feature board's own ci_native_samples (as declared by +# .build.feature_board=true and .build.ci_native_samples in +# boards.txt), on top of the fixed set of samples ifx_build.yml already +# builds for other boards. +# +# Called as: bash extra/ci_build_native_samples.sh +# Invoking it via "bash