diff --git a/.github/scripts/docs_build_examples.py b/.github/scripts/docs_build_examples.py new file mode 100755 index 00000000000..32f9fd90008 --- /dev/null +++ b/.github/scripts/docs_build_examples.py @@ -0,0 +1,327 @@ +#!/usr/bin/env python3 +""" +Python port of .github/scripts/docs_build_examples.sh +Preserves behavior and CLI options of the original bash script. + +Usage: docs_build_examples.py -ai -au [options] +""" + +import argparse +from argparse import RawDescriptionHelpFormatter +# from esp_docs.generic_extensions.docs_embed.tool.wokwi_tool import DiagramSync +import json +import os +import shutil +import subprocess +import sys +from pathlib import Path + +SCRIPT_DIR = Path(__file__).resolve().parent + +# Determine SDKCONFIG_DIR like the shell script +ARDUINO_ESP32_PATH = os.environ.get("ARDUINO_ESP32_PATH") +GITHUB_WORKSPACE = os.environ.get("GITHUB_WORKSPACE") +DOCS_DEPLOY_URL_BASE = os.environ.get("DOCS_PROD_URL_BASE") +REPO_URL_PREFIX = os.environ.get("REPO_URL_PREFIX") + + +if ARDUINO_ESP32_PATH and (Path(ARDUINO_ESP32_PATH) / "tools" / "esp32-arduino-libs").is_dir(): + SDKCONFIG_DIR = Path(ARDUINO_ESP32_PATH) / "tools" / "esp32-arduino-libs" +elif GITHUB_WORKSPACE and (Path(GITHUB_WORKSPACE) / "tools" / "esp32-arduino-libs").is_dir(): + SDKCONFIG_DIR = Path(GITHUB_WORKSPACE) / "tools" / "esp32-arduino-libs" +else: + SDKCONFIG_DIR = Path("tools/esp32-arduino-libs") + +# Wrapper functions to call sketch_utils.sh +SKETCH_UTILS = SCRIPT_DIR / "sketch_utils.sh" + +KEEP_FILES = [ + "*.merged.bin", + "ci.json", + "launchpad.toml", + "diagram*.json", +] +DOCS_BINARIES_DIR = Path("docs/_static/binaries") +GENERATE_DIAGRAMS = False +GENERATE_LAUNCHPAD_CONFIG = False + + +def run_cmd(cmd, check=True, capture_output=False, text=True): + try: + return subprocess.run(cmd, check=check, capture_output=capture_output, text=text) + except subprocess.CalledProcessError as e: + # CalledProcessError is raised only when check=True and the command exits non-zero + print(f"ERROR: Command failed: {' '.join(cmd)}") + print(f"Exit code: {e.returncode}") + if hasattr(e, 'stdout') and e.stdout: + print("--- stdout ---") + print(e.stdout) + if hasattr(e, 'stderr') and e.stderr: + print("--- stderr ---") + print(e.stderr) + # Exit the whole script with the same return code to mimic shell behavior + sys.exit(e.returncode) + except FileNotFoundError: + print(f"ERROR: Command not found: {cmd[0]}") + sys.exit(127) + + +def check_requirements(sketch_dir, sdkconfig_path): + # Call sketch_utils.sh check_requirements + cmd = [str(SKETCH_UTILS), "check_requirements", sketch_dir, str(sdkconfig_path)] + try: + res = run_cmd(cmd, check=False, capture_output=True) + return res.returncode == 0 + except Exception: + return False + + +def install_libs(*args): + cmd = [str(SKETCH_UTILS), "install_libs"] + list(args) + return run_cmd(cmd, check=False) + + +def build_sketch(args_list): + cmd = [str(SKETCH_UTILS), "build"] + args_list + return run_cmd(cmd, check=False) + + +def parse_args(argv): + epilog_text = ( + "Example:\n" + " docs_build_examples.py -ai /usr/local/bin -au ~/.arduino15 -d -l https://storage.example.com\n\n" + "This script finds Arduino sketches that include a 'ci.json' with an 'upload-binary'\n" + "section and builds binaries for the listed targets. The built outputs are placed\n" + "under docs/_static/binaries///\n" + ) + + p = argparse.ArgumentParser( + description="Build examples that have ci.json with upload-binary targets", + formatter_class=RawDescriptionHelpFormatter, + epilog=epilog_text, + ) + p.add_argument( + "-ai", + dest="arduino_cli_path", + help=( + "Path to Arduino CLI installation (directory containing the 'arduino-cli' binary)" + ), + ) + p.add_argument( + "-au", + dest="user_path", + help="Arduino user path (for example: ~/.arduino15)", + ) + p.add_argument( + "-c", + dest="cleanup", + action="store_true", + help="Clean up docs binaries directory and exit", + ) + p.add_argument( + "-d", + dest="generate_diagrams", + action="store_true", + help="Generate diagrams for built examples using docs-embed", + ) + p.add_argument( + "-l", + dest="generate_launchpad_config", + action="store_true", + help="Generate LaunchPad config with configured storage URL", + ) + return p.parse_args(argv) + + +def validate_prerequisites(args): + if not args.arduino_cli_path: + print("ERROR: Arduino CLI path not provided (-ai option required)") + sys.exit(1) + if not args.user_path: + print("ERROR: Arduino user path not provided (-au option required)") + sys.exit(1) + arduino_cli_exe = Path(args.arduino_cli_path) / "arduino-cli" + if not arduino_cli_exe.exists(): + print(f"ERROR: arduino-cli not found at {arduino_cli_exe}") + sys.exit(1) + if not Path(args.user_path).is_dir(): + print(f"ERROR: Arduino user path does not exist: {args.user_path}") + sys.exit(1) + + +def cleanup_binaries(): + print(f"Cleaning up binaries directory: {DOCS_BINARIES_DIR}") + if not DOCS_BINARIES_DIR.exists(): + print("Binaries directory does not exist, nothing to clean") + return + for root, dirs, files in os.walk(DOCS_BINARIES_DIR): + for fname in files: + fpath = Path(root) / fname + parent = Path(root).name + # Always remove sketch/ci.json + if parent == "sketch" and fname == "ci.json": + fpath.unlink() + continue + keep = False + for pattern in KEEP_FILES: + if Path(fname).match(pattern): + keep = True + break + if not keep: + print(f"Removing: {fpath}") + fpath.unlink() + else: + print(f"Keeping: {fpath}") + # remove empty dirs + for root, dirs, files in os.walk(DOCS_BINARIES_DIR, topdown=False): + if not os.listdir(root): + try: + os.rmdir(root) + except Exception: + pass + print("Cleanup completed") + + +def find_examples_with_upload_binary(): + res = [] + for ino in Path('.').rglob('*.ino'): + sketch_dir = ino.parent + sketch_name = ino.stem + dir_name = sketch_dir.name + if dir_name != sketch_name: + continue + ci_json = sketch_dir / 'ci.json' + if ci_json.exists(): + try: + data = json.loads(ci_json.read_text()) + if 'upload-binary' in data and data['upload-binary']: + res.append(str(ino)) + except Exception: + continue + return res + + +def get_upload_binary_targets(sketch_dir): + ci_json = Path(sketch_dir) / 'ci.json' + try: + data = json.loads(ci_json.read_text()) + targets = data.get('upload-binary', {}).get('targets', []) + return targets + except Exception: + return [] + + +def build_example_for_target(sketch_dir, target, relative_path, args): + print(f"\n > Building example: {relative_path} for target: {target}") + output_dir = DOCS_BINARIES_DIR / relative_path / target + output_dir.mkdir(parents=True, exist_ok=True) + + sdkconfig = SDKCONFIG_DIR / target / 'sdkconfig' + if not check_requirements(str(sketch_dir), sdkconfig): + print(f"Target {target} does not meet the requirements for {Path(sketch_dir).name}. Skipping.") + return True + + # Build the sketch using sketch_utils.sh build - pass args as in shell script + build_args = [ + "-ai", + args.arduino_cli_path, + "-au", + args.user_path, + "-s", + str(sketch_dir), + "-t", + target, + "-b", + str(output_dir), + "--first-only", + ] + res = build_sketch(build_args) + if res.returncode == 0: + print(f"Successfully built {relative_path} for {target}") + ci_json = Path(sketch_dir) / 'ci.json' + if ci_json.exists(): + shutil.copy(ci_json, output_dir / 'ci.json') + # if GENERATE_DIAGRAMS: + # print(f"Generating diagram for {relative_path} ({target})...") + # try: + # sync = DiagramSync(output_dir) + # sync.generate_diagram_from_ci(target) + # except Exception as e: + # print(f"WARNING: Failed to generate diagram for {relative_path} ({target}): {e}") + # if GENERATE_LAUNCHPAD_CONFIG: + # print(f"Generating LaunchPad config for {relative_path} ({target})...") + # try: + # sync = DiagramSync(output_dir) + # sync.generate_launchpad_config(DOCS_DEPLOY_URL_BASE, REPO_URL_PREFIX) + # except Exception as e: + # print(f"WARNING: Failed to generate LaunchPad config for {relative_path} ({target}): {e}") + else: + print(f"ERROR: Failed to build {relative_path} for {target}") + return False + + +def build_all_examples(args): + total_built = 0 + total_failed = 0 + + if DOCS_BINARIES_DIR.exists(): + shutil.rmtree(DOCS_BINARIES_DIR) + print(f"Removed existing build directory: {DOCS_BINARIES_DIR}") + + examples = find_examples_with_upload_binary() + if not examples: + print("No examples found with upload-binary configuration") + return 0 + + print('\nExamples to be built:') + print('====================') + for i, example in enumerate(examples, start=1): + sketch_dir = Path(example).parent + relative_path = str(sketch_dir).lstrip('./') + targets = get_upload_binary_targets(sketch_dir) + if targets: + print(f"{i}. {relative_path} (targets: {' '.join(targets)})") + print() + + for example in examples: + sketch_dir = Path(example).parent + relative_path = str(sketch_dir).lstrip('./') + targets = get_upload_binary_targets(sketch_dir) + if not targets: + print(f"WARNING: No targets found for {relative_path}") + continue + print(f"Building {relative_path} for targets: {targets}") + for target in targets: + ok = build_example_for_target(sketch_dir, target, relative_path, args) + if ok: + total_built += 1 + else: + total_failed += 1 + + print('\nBuild summary:') + print(f" Successfully built: {total_built}") + print(f" Failed builds: {total_failed}") + print(f" Output directory: {DOCS_BINARIES_DIR}") + return total_failed + + +def main(argv): + global GENERATE_DIAGRAMS, GENERATE_LAUNCHPAD_CONFIG + args = parse_args(argv) + if args.cleanup: + cleanup_binaries() + return + validate_prerequisites(args) + GENERATE_DIAGRAMS = args.generate_diagrams + GENERATE_LAUNCHPAD_CONFIG = args.generate_launchpad_config + DOCS_BINARIES_DIR.mkdir(parents=True, exist_ok=True) + result = build_all_examples(args) + if result == 0: + print('\nAll examples built successfully!') + else: + print('\nSome builds failed. Check the output above for details.') + sys.exit(1) + + +if __name__ == '__main__': + main(sys.argv[1:]) diff --git a/.github/scripts/on-push.sh b/.github/scripts/on-push.sh index 3eb020c09a3..f91c731f92f 100755 --- a/.github/scripts/on-push.sh +++ b/.github/scripts/on-push.sh @@ -2,8 +2,6 @@ set -e -export ARDUINO_BUILD_DIR="$HOME/.arduino/build.tmp" - function build { local target=$1 local chunk_index=$2 diff --git a/.github/scripts/sketch_utils.sh b/.github/scripts/sketch_utils.sh index 02990ca8914..4e700947c00 100755 --- a/.github/scripts/sketch_utils.sh +++ b/.github/scripts/sketch_utils.sh @@ -54,6 +54,8 @@ function check_requirements { # check_requirements } function build_sketch { # build_sketch [extra-options] + local first_only=false + while [ -n "$1" ]; do case "$1" in -ai ) @@ -92,6 +94,36 @@ function build_sketch { # build_sketch [ext shift debug_level="DebugLevel=$1" ;; + -b ) + shift + custom_build_dir=$1 + ;; + --first-only ) + first_only=true + ;; + -h ) + echo "Usage: build_sketch [options]" + echo "" + echo "Build an Arduino sketch for ESP32 targets." + echo "" + echo "Required options:" + echo " -ai Arduino IDE path" + echo " -au Arduino user path" + echo " -s Sketch directory containing .ino file and ci.json" + echo " -t Target chip (esp32, esp32s2, esp32c3, esp32s3, esp32c6, esp32h2, esp32p4, esp32c5)" + echo " Required unless -fqbn is specified" + echo "" + echo "Optional options:" + echo " -fqbn Fully qualified board name (alternative to -t)" + echo " -o Board options (PSRAM, USBMode, etc.) [default: chip-specific]" + echo " -i Chunk index for parallel builds [default: none]" + echo " -l Log compilation output to JSON file [default: none]" + echo " -d Debug level (DebugLevel=...) [default: none]" + echo " -b Custom build directory [default: \$ARDUINO_BUILD_DIR or \$HOME/.arduino/tests/\$target/\$sketchname/build.tmp]" + echo " --first-only Build only the first FQBN from ci.json configurations [default: false]" + echo " -h Show this help message" + exit 0 + ;; * ) break ;; @@ -128,7 +160,14 @@ function build_sketch { # build_sketch [ext len=$(jq -r --arg target "$target" '.fqbn[$target] | length' "$sketchdir"/ci.json) if [ "$len" -gt 0 ]; then - fqbn=$(jq -r --arg target "$target" '.fqbn[$target] | sort' "$sketchdir"/ci.json) + if [ "$first_only" = true ]; then + # Get only the first FQBN from the array (original order) + fqbn=$(jq -r --arg target "$target" '.fqbn[$target] | .[0]' "$sketchdir"/ci.json) + len=1 + fqbn="[\"$fqbn\"]" + else + fqbn=$(jq -r --arg target "$target" '.fqbn[$target] | sort' "$sketchdir"/ci.json) + fi fi fi @@ -219,12 +258,14 @@ function build_sketch { # build_sketch [ext fi # The directory that will hold all the artifacts (the build directory) is - # provided through: - # 1. An env variable called ARDUINO_BUILD_DIR. - # 2. Created at the sketch level as "build" in the case of a single - # configuration test. - # 3. Created at the sketch level as "buildX" where X is the number - # of configuration built in case of a multiconfiguration test. + # determined by the following priority: + # 1. Custom build directory via -b flag: + # - If path contains "docs/_static/binaries", use as exact path (for docs builds) + # - Otherwise, append target name to custom directory + # 2. ARDUINO_BUILD_DIR environment variable (if set) + # 3. Default: $HOME/.arduino/tests/$target/$sketchname/build.tmp + # + # For multiple configurations, subsequent builds use .1, .2, etc. suffixes sketchname=$(basename "$sketchdir") local has_requirements @@ -253,22 +294,35 @@ function build_sketch { # build_sketch [ext fi ARDUINO_CACHE_DIR="$HOME/.arduino/cache.tmp" - if [ -n "$ARDUINO_BUILD_DIR" ]; then - build_dir="$ARDUINO_BUILD_DIR" - elif [ "$len" -eq 1 ]; then - # build_dir="$sketchdir/build" - build_dir="$HOME/.arduino/tests/$target/$sketchname/build.tmp" + + # Determine base build directory + if [ -n "$custom_build_dir" ]; then + # If custom_build_dir contains docs/_static/binaries, use it as exact path + if [[ "$custom_build_dir" == *"docs/_static/binaries"* ]]; then + build_dir_base="$custom_build_dir" + else + build_dir_base="$custom_build_dir/$target" + fi + elif [ -n "$ARDUINO_BUILD_DIR" ]; then + build_dir_base="$ARDUINO_BUILD_DIR" + else + build_dir_base="$HOME/.arduino/tests/$target/$sketchname/build.tmp" fi output_file="$HOME/.arduino/cli_compile_output.txt" sizes_file="$GITHUB_WORKSPACE/cli_compile_$chunk_index.json" mkdir -p "$ARDUINO_CACHE_DIR" + for i in $(seq 0 $((len - 1))); do - if [ "$len" -ne 1 ]; then - # build_dir="$sketchdir/build$i" - build_dir="$HOME/.arduino/tests/$target/$sketchname/build$i.tmp" + # Calculate build directory for this configuration + if [ "$i" -eq 0 ]; then + build_dir="$build_dir_base" + else + build_dir="${build_dir_base}.${i}" fi + + # Prepare build directory rm -rf "$build_dir" mkdir -p "$build_dir" diff --git a/.github/workflows/docs_build.yml b/.github/workflows/docs_build.yml index 5253c166f85..9657a89f08f 100644 --- a/.github/workflows/docs_build.yml +++ b/.github/workflows/docs_build.yml @@ -1,10 +1,23 @@ name: Documentation Build and Deploy CI on: + # Wait for Compilation Tests workflow to complete (uses macOS binaries) + workflow_run: + workflows: ["Compilation Tests"] + types: + - completed + branches: + - master + - release/v2.x + - wokwi-embed-launchpad + # Manual trigger for testing docs changes without waiting for compilation + workflow_dispatch: + # Also run on direct pushes to docs or workflow files (for testing) push: branches: - master - release/v2.x + - wokwi-embed-launchpad paths: - "docs/**" - ".github/workflows/docs_build.yml" @@ -34,6 +47,163 @@ jobs: cache: "pip" python-version: "3.10" + - name: Restore docs binaries from cache (macOS builds) + id: cache-restore + uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 + with: + key: docs-binaries-macos-${{ github.event.workflow_run.head_sha || github.sha }} + restore-keys: | + docs-binaries-macos- + path: docs_binaries + lookup-only: false + + - name: Download docs binaries artifact (fallback) + if: steps.cache-restore.outputs.cache-hit != 'true' + uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4.2.1 + with: + name: docs-binaries-macos + path: docs_binaries + continue-on-error: true + + - name: Debug - List cached binaries structure + run: | + echo "==========================================" + echo "Debugging cached binaries structure (macOS builds)" + echo "==========================================" + if [ -d "docs_binaries" ]; then + echo "✓ docs_binaries directory exists" + echo "" + echo "Directory tree (first 50 entries):" + find docs_binaries -type f | head -50 | sort + echo "" + echo "Binary files (.bin):" + find docs_binaries -type f -name "*.bin" | head -30 + echo "" + echo "ELF files:" + find docs_binaries -type f -name "*.elf" | head -30 + echo "" + echo "Total binary files: $(find docs_binaries -type f -name "*.bin" | wc -l)" + echo "Total ELF files: $(find docs_binaries -type f -name "*.elf" | wc -l)" + echo "" + echo "Sample directory structure:" + ls -la docs_binaries/ || true + else + echo "✗ docs_binaries directory NOT found" + echo "WARNING: No cached binaries available!" + fi + echo "==========================================" + + - name: Copy cached binaries to docs/_static/binaries/ + run: | + echo "Copying cached binaries to docs/_static/binaries/" + mkdir -p docs/_static/binaries + + if [ ! -d "docs_binaries" ]; then + echo "ERROR: No docs_binaries directory found!" + echo "Cannot proceed without binaries. Exiting." + exit 1 + fi + + # Find all .bin files in docs_binaries + echo "Processing binary files from macOS builds..." + bin_count=0 + skip_count=0 + + # Binaries are stored in structure like: + # docs_binaries/{target}/{SketchName}/build.tmp/{SketchName}.ino.bin + # We need to: + # 1. Extract sketch name and target from path + # 2. Find the sketch in libraries/ directory + # 3. Copy to docs/_static/binaries/libraries/{LibraryName}/examples/{SketchName}/{target}/ + + find docs_binaries -type f -name "*.bin" | while read -r bin_file; do + echo "Processing: $bin_file" + + # Extract the binary filename (e.g., WiFiClientSecure.ino.bin) + bin_name=$(basename "$bin_file") + + # Extract sketch name (remove .ino.bin or .bin extension) + sketch_name="${bin_name%.ino.bin}" + if [ "$sketch_name" == "$bin_name" ]; then + sketch_name="${bin_name%.bin}" + fi + + # Extract target from path (esp32, esp32s2, esp32s3, esp32c3, esp32c6, esp32h2, esp32p4, esp32c5) + if [[ "$bin_file" =~ /(esp32[a-z0-9]*)/ ]]; then + target="${BASH_REMATCH[1]}" + else + echo " ⚠ Could not determine target from path: $bin_file" + skip_count=$((skip_count + 1)) + continue + fi + + # Search for the sketch in libraries directory + sketch_ino_file=$(find libraries -type f -name "${sketch_name}.ino" 2>/dev/null | head -1) + + if [ -z "$sketch_ino_file" ]; then + echo " ⚠ Could not find sketch '${sketch_name}.ino' in libraries/" + skip_count=$((skip_count + 1)) + continue + fi + + # Extract the relative path from libraries/ + # e.g., libraries/NetworkClientSecure/examples/WiFiClientSecure/WiFiClientSecure.ino + # becomes: NetworkClientSecure/examples/WiFiClientSecure + sketch_dir=$(dirname "$sketch_ino_file") + relative_path="${sketch_dir#libraries/}" + + echo " ✓ Found sketch at: $sketch_ino_file" + echo " ✓ Target: $target" + echo " ✓ Relative path: $relative_path" + + # Create output directory + output_dir="docs/_static/binaries/libraries/${relative_path}/${target}" + mkdir -p "$output_dir" + + # Copy the binary + cp "$bin_file" "$output_dir/" + echo " → Copied to: $output_dir/$bin_name" + bin_count=$((bin_count + 1)) + done + + echo "" + echo "==========================================" + echo "Binary copy completed!" + echo " Binaries copied: $bin_count" + echo " Binaries skipped: $skip_count" + echo "==========================================" + echo "" + echo "Final structure in docs/_static/binaries/:" + find docs/_static/binaries -type f -name "*.bin" | head -30 + echo "" + echo "Total binaries in docs/_static/binaries/: $(find docs/_static/binaries -type f -name "*.bin" | wc -l)" + + - name: Cleanup Binaries + run: | + python3 .github/scripts/docs_build_examples.py -c + + - name: Debug - Final binaries structure after cleanup + run: | + echo "==========================================" + echo "Final structure in docs/_static/binaries/ (after cleanup)" + echo "==========================================" + if [ -d "docs/_static/binaries" ]; then + echo "Directory tree:" + find docs/_static/binaries -type f | sort + echo "" + echo "Files by type:" + echo " .bin files: $(find docs/_static/binaries -type f -name "*.bin" | wc -l)" + echo " .elf files: $(find docs/_static/binaries -type f -name "*.elf" | wc -l)" + echo " .json files: $(find docs/_static/binaries -type f -name "*.json" | wc -l)" + echo " .toml files: $(find docs/_static/binaries -type f -name "*.toml" | wc -l)" + echo "" + echo "Example of final structure (first 20 files):" + find docs/_static/binaries -type f | head -20 + else + echo "WARNING: docs/_static/binaries/ directory not found!" + fi + echo "==========================================" + - name: Build run: | sudo apt update @@ -48,4 +218,4 @@ jobs: uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: docs - path: docs + path: docs \ No newline at end of file diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 690993504c2..0dbd6fb9670 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -22,6 +22,7 @@ on: branches: - master - release/* + - wokwi-embed-launchpad pull_request: paths: - "cores/**" @@ -119,61 +120,80 @@ jobs: dependencies_reverse.json if-no-files-found: warn - # Ubuntu - build-arduino-linux: - name: Arduino ${{ matrix.chunk }} on ubuntu-latest - if: ${{ needs.gen-chunks.outputs.should_build == '1' }} - needs: gen-chunks - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - chunk: ${{ fromJson(needs.gen-chunks.outputs.chunks) }} + # # Ubuntu + # build-arduino-linux: + # name: Arduino ${{ matrix.chunk }} on ubuntu-latest + # if: ${{ needs.gen-chunks.outputs.should_build == '1' }} + # needs: gen-chunks + # runs-on: ubuntu-latest + # strategy: + # fail-fast: false + # matrix: + # chunk: ${{ fromJson(needs.gen-chunks.outputs.chunks) }} - steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - - uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.0.4 - with: - python-version: "3.x" + # steps: + # - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + # - uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.0.4 + # with: + # python-version: "3.x" - - name: Get libs cache - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 - with: - key: libs-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('package/package_esp32_index.template.json', 'tools/get.py') }} - path: | - ./tools/dist - ./tools/esp32-arduino-libs - ./tools/esptool - ./tools/mk* - ./tools/openocd-esp32 - ./tools/riscv32-* - ./tools/xtensa-* - - - name: Set Log Level - run: | - if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then - echo "LOG_LEVEL=${{ github.event.inputs.log_level }}" >> $GITHUB_ENV - elif [ "${{ github.event_name }}" == "schedule" ]; then - echo "LOG_LEVEL=verbose" >> $GITHUB_ENV - else - echo "LOG_LEVEL=none" >> $GITHUB_ENV - fi - - - name: Download affected sketches - uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4.2.1 - with: - name: affected_sketches + # - name: Get libs cache + # uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 + # with: + # key: libs-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('package/package_esp32_index.template.json', 'tools/get.py') }} + # path: | + # ./tools/dist + # ./tools/esp32-arduino-libs + # ./tools/esptool + # ./tools/mk* + # ./tools/openocd-esp32 + # ./tools/riscv32-* + # ./tools/xtensa-* - - name: Build selected sketches - run: bash ./.github/scripts/on-push.sh ${{ matrix.chunk }} ${{ needs.gen-chunks.outputs.chunk_count }} 1 ${{ env.LOG_LEVEL }} affected_sketches.txt + # - name: Set Log Level + # run: | + # if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then + # echo "LOG_LEVEL=${{ github.event.inputs.log_level }}" >> $GITHUB_ENV + # elif [ "${{ github.event_name }}" == "schedule" ]; then + # echo "LOG_LEVEL=verbose" >> $GITHUB_ENV + # else + # echo "LOG_LEVEL=none" >> $GITHUB_ENV + # fi - #Upload cli compile json as artifact - - name: Upload cli compile json - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 - with: - name: pr_cli_compile_${{ matrix.chunk }} - path: cli_compile_${{ matrix.chunk }}.json - overwrite: true + # - name: Download affected sketches + # uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4.2.1 + # with: + # name: affected_sketches + + # - name: Build selected sketches + # run: bash ./.github/scripts/on-push.sh ${{ matrix.chunk }} ${{ needs.gen-chunks.outputs.chunk_count }} 1 ${{ env.LOG_LEVEL }} affected_sketches.txt + + # - name: Collect compiled binaries + # run: | + # mkdir -p compiled_binaries + # # Find and copy all compiled binaries (*.bin, *.elf files) + # find . -name "*.bin" -o -name "*.elf" | grep -E "(build|target)" | while read file; do + # # Create relative path structure in compiled_binaries + # rel_path=$(echo "$file" | sed 's|^\./||') + # target_dir="compiled_binaries/$(dirname "$rel_path")" + # mkdir -p "$target_dir" + # cp "$file" "$target_dir/" + # done + + # - name: Upload compiled binaries as artifact + # uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + # with: + # name: compiled-binaries-${{ matrix.chunk }} + # path: compiled_binaries + # retention-days: 1 + + # #Upload cli compile json as artifact + # - name: Upload cli compile json + # uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + # with: + # name: pr_cli_compile_${{ matrix.chunk }} + # path: cli_compile_${{ matrix.chunk }}.json + # overwrite: true # Windows and MacOS build-arduino-win-mac: @@ -194,58 +214,95 @@ jobs: - name: Build Sketches run: bash ./.github/scripts/on-push.sh - # Save artifacts to gh-pages - save-master-artifacts: - name: Save master artifacts - needs: build-arduino-linux - if: github.event_name == 'push' && github.ref == 'refs/heads/master' - runs-on: ubuntu-latest - steps: - # Check out repository - - name: Checkout repository - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - with: - token: ${{secrets.GITHUB_TOKEN}} - fetch-depth: "0" + - name: Collect docs binaries (macOS only) + if: matrix.os == 'macOS-latest' + run: | + echo "Collecting binaries for documentation from macOS build..." + mkdir -p docs_binaries - - name: Switch branch - run: git checkout remotes/origin/gh-pages + # Find all compiled binaries from the build + find "$HOME/.arduino/tests" -type f -name "*.bin" 2>/dev/null | while read -r bin_file; do + echo "Found: $bin_file" - - name: Download sketches reports artifact - uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4.2.1 + # Preserve directory structure + rel_path="${bin_file#$HOME/.arduino/tests/}" + target_dir="docs_binaries/$(dirname "$rel_path")" + mkdir -p "$target_dir" + cp "$bin_file" "$target_dir/" + done + + echo "" + echo "Collected binaries for docs:" + find docs_binaries -type f -name "*.bin" | head -20 + echo "Total: $(find docs_binaries -type f -name "*.bin" | wc -l) binary files" + + - name: Save docs binaries to cache (macOS only) + if: matrix.os == 'macOS-latest' + uses: actions/cache/save@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 with: - pattern: pr_cli_compile_* - merge-multiple: true - path: master_cli_compile + key: docs-binaries-macos-${{ github.sha }} + path: docs_binaries - - name: List files in the directory - run: ls -R + - name: Upload docs binaries as artifact (macOS only) + if: matrix.os == 'macOS-latest' + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: docs-binaries-macos + path: docs_binaries + retention-days: 7 - - name: Commit json files to gh-pages if on master - if: github.event_name == 'push' && github.ref == 'refs/heads/master' - continue-on-error: true - run: | - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add --all - git commit -m "Updated cli compile json files" - git push origin HEAD:gh-pages + # Save artifacts to gh-pages + # save-master-artifacts: + # name: Save master artifacts + # needs: build-arduino-linux + # if: github.event_name == 'push' && github.ref == 'refs/heads/master' + # runs-on: ubuntu-latest + # steps: + # # Check out repository + # - name: Checkout repository + # uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + # with: + # token: ${{secrets.GITHUB_TOKEN}} + # fetch-depth: "0" + + # - name: Switch branch + # run: git checkout remotes/origin/gh-pages + + # - name: Download sketches reports artifact + # uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4.2.1 + # with: + # pattern: pr_cli_compile_* + # merge-multiple: true + # path: master_cli_compile + + # - name: List files in the directory + # run: ls -R + + # - name: Commit json files to gh-pages if on master + # if: github.event_name == 'push' && github.ref == 'refs/heads/master' + # continue-on-error: true + # run: | + # git config user.name "github-actions[bot]" + # git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + # git add --all + # git commit -m "Updated cli compile json files" + # git push origin HEAD:gh-pages #Upload PR number as artifact - upload-pr-number: - name: Upload PR number - if: ${{ github.event_name == 'pull_request' && !startsWith(github.head_ref, 'release/') }} - runs-on: ubuntu-latest - steps: - - name: Save the PR number in an artifact - shell: bash - env: - PR_NUM: ${{ github.event.number }} - run: echo $PR_NUM > pr_num.txt + # upload-pr-number: + # name: Upload PR number + # if: ${{ github.event_name == 'pull_request' && !startsWith(github.head_ref, 'release/') }} + # runs-on: ubuntu-latest + # steps: + # - name: Save the PR number in an artifact + # shell: bash + # env: + # PR_NUM: ${{ github.event.number }} + # run: echo $PR_NUM > pr_num.txt - - name: Upload PR number - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 - with: - name: pr_number - path: ./pr_num.txt - overwrite: true + # - name: Upload PR number + # uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + # with: + # name: pr_number + # path: ./pr_num.txt + # overwrite: true diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 00000000000..b59d4f5156f --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1 @@ +_static/binaries/ diff --git a/docs/requirements.txt b/docs/requirements.txt index ef2ab88cb65..3aba296fa3f 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,7 +1,7 @@ -sphinx==4.5.0 -esp-docs>=1.4.0 -sphinx-copybutton==0.5.0 -sphinx-tabs==3.2.0 -numpydoc==1.5.0 -standard-imghdr==3.13.0 -Sphinx-Substitution-Extensions==2022.2.16 +sphinx +esp-docs @ git+https://github.com/JakubAndrysek/esp-docs.git@extensions/wokwi_embed +sphinx-copybutton +sphinx-tabs +numpydoc +standard-imghdr +Sphinx-Substitution-Extensions diff --git a/libraries/ESP32/examples/GPIO/FunctionalInterrupt/ci.json b/libraries/ESP32/examples/GPIO/FunctionalInterrupt/ci.json new file mode 100644 index 00000000000..adab5922626 --- /dev/null +++ b/libraries/ESP32/examples/GPIO/FunctionalInterrupt/ci.json @@ -0,0 +1,121 @@ +{ + "fqbn":{ + "esp32":[ + "espressif:esp32:esp32:PSRAM=enabled,PartitionScheme=huge_app,FlashMode=dio", + "espressif:esp32:esp32:PSRAM=enabled,PartitionScheme=huge_app,FlashMode=qio" + ], + "esp32c3":[ + "espressif:esp32:esp32c3:PartitionScheme=huge_app,FlashMode=dio", + "espressif:esp32:esp32c3:PartitionScheme=huge_app,FlashMode=qio" + ], + "esp32c6":[ + "espressif:esp32:esp32c6:PartitionScheme=huge_app,FlashMode=dio", + "espressif:esp32:esp32c6:PartitionScheme=huge_app,FlashMode=dio,FlashFreq=40", + "espressif:esp32:esp32c6:PartitionScheme=huge_app,FlashMode=qio", + "espressif:esp32:esp32c6:PartitionScheme=huge_app,FlashMode=qio,FlashFreq=40" + ], + "esp32h2":[ + "espressif:esp32:esp32h2:PartitionScheme=huge_app,FlashMode=dio", + "espressif:esp32:esp32h2:PartitionScheme=huge_app,FlashMode=dio,FlashFreq=16", + "espressif:esp32:esp32h2:PartitionScheme=huge_app,FlashMode=qio", + "espressif:esp32:esp32h2:PartitionScheme=huge_app,FlashMode=qio,FlashFreq=16" + ], + "esp32s2":[ + "espressif:esp32:esp32s2:PSRAM=enabled,PartitionScheme=huge_app,FlashMode=dio", + "espressif:esp32:esp32s2:PSRAM=enabled,PartitionScheme=huge_app,FlashMode=qio" + ], + "esp32s3":[ + "espressif:esp32:esp32s3:PSRAM=opi,USBMode=default,PartitionScheme=huge_app,FlashMode=qio", + "espressif:esp32:esp32s3:PSRAM=opi,USBMode=default,PartitionScheme=huge_app,FlashMode=qio120", + "espressif:esp32:esp32s3:PSRAM=opi,USBMode=default,PartitionScheme=huge_app,FlashMode=dio" + ], + "esp32p4":[ + "espressif:esp32:esp32p4:PSRAM=enabled,USBMode=default,PartitionScheme=huge_app,FlashMode=dio", + "espressif:esp32:esp32p4:PSRAM=enabled,USBMode=default,PartitionScheme=huge_app,FlashMode=dio,FlashFreq=40", + "espressif:esp32:esp32p4:PSRAM=enabled,USBMode=default,PartitionScheme=huge_app,FlashMode=qio", + "espressif:esp32:esp32p4:PSRAM=enabled,USBMode=default,PartitionScheme=huge_app,FlashMode=qio,FlashFreq=40" + ] + }, + "platforms":{ + "qemu":false + }, + "upload-binary":{ + "targets":[ + "esp32s3", + "esp32" + ], + "wokwi-simulation":[ + "esp32s3", + "esp32" + ], + "description":"BlinkRGB LED control example with push button input", + "diagram":{ + "esp32s3":{ + "parts":[ + { + "type":"wokwi-pushbutton", + "id":"btn1", + "top":172.7, + "left":137.9, + "rotate":90, + "attrs":{ + "color":"green" + } + } + ], + "connections":[ + [ + "btn1:1.l", + "esp:0", + "blue", + [ + "v-9.6", + "h-90.97" + ] + ], + [ + "esp:GND.4", + "btn1:2.r", + "black", + [ + + ] + ] + ] + }, + "esp32":{ + "parts":[ + { + "type":"wokwi-pushbutton", + "id":"btn1", + "top":95.6, + "left":131.6, + "rotate":270, + "attrs":{ + "color":"green" + } + } + ], + "connections":[ + [ + "btn1:1.l", + "esp:0", + "blue", + [ + + ] + ], + [ + "esp:GND.2", + "btn1:2.r", + "black", + [ + "v0", + "h52.84" + ] + ] + ] + } + } + } +} diff --git a/libraries/ESP32/examples/GPIO/GPIOInterrupt/ci.json b/libraries/ESP32/examples/GPIO/GPIOInterrupt/ci.json new file mode 100644 index 00000000000..398a66e2ce5 --- /dev/null +++ b/libraries/ESP32/examples/GPIO/GPIOInterrupt/ci.json @@ -0,0 +1,120 @@ +{ + "fqbn":{ + "esp32":[ + "espressif:esp32:esp32:PSRAM=enabled,PartitionScheme=huge_app,FlashMode=dio", + "espressif:esp32:esp32:PSRAM=enabled,PartitionScheme=huge_app,FlashMode=qio" + ], + "esp32c3":[ + "espressif:esp32:esp32c3:PartitionScheme=huge_app,FlashMode=dio", + "espressif:esp32:esp32c3:PartitionScheme=huge_app,FlashMode=qio" + ], + "esp32c6":[ + "espressif:esp32:esp32c6:PartitionScheme=huge_app,FlashMode=dio", + "espressif:esp32:esp32c6:PartitionScheme=huge_app,FlashMode=dio,FlashFreq=40", + "espressif:esp32:esp32c6:PartitionScheme=huge_app,FlashMode=qio", + "espressif:esp32:esp32c6:PartitionScheme=huge_app,FlashMode=qio,FlashFreq=40" + ], + "esp32h2":[ + "espressif:esp32:esp32h2:PartitionScheme=huge_app,FlashMode=dio", + "espressif:esp32:esp32h2:PartitionScheme=huge_app,FlashMode=dio,FlashFreq=16", + "espressif:esp32:esp32h2:PartitionScheme=huge_app,FlashMode=qio", + "espressif:esp32:esp32h2:PartitionScheme=huge_app,FlashMode=qio,FlashFreq=16" + ], + "esp32s2":[ + "espressif:esp32:esp32s2:PSRAM=enabled,PartitionScheme=huge_app,FlashMode=dio", + "espressif:esp32:esp32s2:PSRAM=enabled,PartitionScheme=huge_app,FlashMode=qio" + ], + "esp32s3":[ + "espressif:esp32:esp32s3:PSRAM=opi,USBMode=default,PartitionScheme=huge_app,FlashMode=qio", + "espressif:esp32:esp32s3:PSRAM=opi,USBMode=default,PartitionScheme=huge_app,FlashMode=qio120", + "espressif:esp32:esp32s3:PSRAM=opi,USBMode=default,PartitionScheme=huge_app,FlashMode=dio" + ], + "esp32p4":[ + "espressif:esp32:esp32p4:PSRAM=enabled,USBMode=default,PartitionScheme=huge_app,FlashMode=dio", + "espressif:esp32:esp32p4:PSRAM=enabled,USBMode=default,PartitionScheme=huge_app,FlashMode=dio,FlashFreq=40", + "espressif:esp32:esp32p4:PSRAM=enabled,USBMode=default,PartitionScheme=huge_app,FlashMode=qio", + "espressif:esp32:esp32p4:PSRAM=enabled,USBMode=default,PartitionScheme=huge_app,FlashMode=qio,FlashFreq=40" + ] + }, + "platforms":{ + "qemu":false + }, + "upload-binary":{ + "targets":[ + "esp32s3" + ], + "wokwi-simulation":[ + "esp32s3", + "esp32" + ], + "description":"BlinkRGB LED control example with push button input", + "diagram":{ + "esp32s3":{ + "parts":[ + { + "type":"wokwi-pushbutton", + "id":"btn1", + "top":172.7, + "left":137.9, + "rotate":90, + "attrs":{ + "color":"green" + } + } + ], + "connections":[ + [ + "btn1:1.l", + "esp:0", + "blue", + [ + "v-9.6", + "h-90.97" + ] + ], + [ + "esp:GND.4", + "btn1:2.r", + "black", + [ + + ] + ] + ] + }, + "esp32":{ + "parts":[ + { + "type":"wokwi-pushbutton", + "id":"btn1", + "top":95.6, + "left":131.6, + "rotate":270, + "attrs":{ + "color":"green" + } + } + ], + "connections":[ + [ + "btn1:1.l", + "esp:0", + "blue", + [ + + ] + ], + [ + "esp:GND.2", + "btn1:2.r", + "black", + [ + "v0", + "h52.84" + ] + ] + ] + } + } + } +}