name: HIL

on:
  pull_request:
    types: [opened, synchronize, reopened, ready_for_review]
  merge_group:
  workflow_dispatch:
    inputs:
      repository:
        description: "Owner and repository to test"
        required: true
        default: 'esp-rs/esp-hal'
      branch:
        description: "Branch, tag or SHA to checkout."
        required: true
        default: "main"

# Cancel any currently running workflows from the same PR, branch, or
# tag when a new workflow is triggered.
#
# https://stackoverflow.com/a/66336834
concurrency:
  cancel-in-progress: true
  group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}

env:
  CARGO_TERM_COLOR: always
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

jobs:
  build-xtasks:
    name: Build xtasks | ${{ matrix.host.arch }}
    runs-on: ubuntu-latest

    strategy:
      fail-fast: false
      matrix:
        host:
          - arch: armv7
            rust-target: armv7-unknown-linux-gnueabihf
          - arch: aarch64
            rust-target: aarch64-unknown-linux-gnu

    steps:
      - uses: actions/checkout@v4
        if: github.event_name != 'workflow_dispatch'
      - uses: actions/checkout@v4
        if: github.event_name == 'workflow_dispatch'
        with:
          repository: ${{ github.event.inputs.repository }}
          ref: ${{ github.event.inputs.branch }}

      - name: Install Rust toolchain
        uses: dtolnay/rust-toolchain@v1
        with:
          toolchain: stable
          components: rust-src

      - name: Install cross
        run: cargo install cross

      - name: Build xtasks
        run: cross build --release --target ${{ matrix.host.rust-target }} -p xtask

      - name: Upload artifact
        uses: actions/upload-artifact@v4
        with:
          name: xtask-${{ matrix.host.arch }}
          path: target/${{ matrix.host.rust-target }}/release/xtask

  build-tests:
    name: Build HIL Tests | ${{ matrix.target.soc }}
    runs-on: ubuntu-latest

    strategy:
      fail-fast: false
      matrix:
        target:
          # RISC-V devices:
          - soc: esp32c2
            rust-target: riscv32imc-unknown-none-elf
          - soc: esp32c3
            rust-target: riscv32imc-unknown-none-elf
          - soc: esp32c6
            rust-target: riscv32imac-unknown-none-elf
          - soc: esp32h2
            rust-target: riscv32imac-unknown-none-elf
          # # Xtensa devices:
          - soc: esp32
            rust-target: xtensa-esp32-none-elf
          - soc: esp32s2
            rust-target: xtensa-esp32s2-none-elf
          - soc: esp32s3
            rust-target: xtensa-esp32s3-none-elf

    steps:
      - uses: actions/checkout@v4
        if: github.event_name != 'workflow_dispatch'
      - uses: actions/checkout@v4
        if: github.event_name == 'workflow_dispatch'
        with:
          repository: ${{ github.event.inputs.repository }}
          ref: ${{ github.event.inputs.branch }}

      # Install the Rust toolchain for RISC-V devices:
      - if: ${{ !contains(fromJson('["esp32", "esp32s2", "esp32s3"]'), matrix.target.soc) }}
        uses: dtolnay/rust-toolchain@v1
        with:
          target: ${{ matrix.target.rust-target }}
          toolchain: stable
          components: rust-src
      # Install the Rust toolchain for Xtensa devices:
      - if: contains(fromJson('["esp32", "esp32s2", "esp32s3"]'), matrix.target.soc)
        uses: esp-rs/xtensa-toolchain@v1.5
        with:
          buildtargets: ${{ matrix.target.soc }}
          default: true
          ldproxy: false

      - name: Build tests
        run: cargo xtask build-tests ${{ matrix.target.soc }}

      - name: Prepare artifact
        run: |
          # Create the 'tests' directory if it doesn't exist
          mkdir -p tests

          # Find ELF files in the specified path and move them to 'tests'
          find "hil-test/target/${{ matrix.target.rust-target }}/release/deps/" -type f -exec file {} + | \
          grep ELF | \
          awk -F: '{print $1}' | \
          xargs -I {} mv {} tests

          # Rename files in 'tests' by removing everything after the first dash
          for file in tests/*-*; do
            base_name="$(basename "$file" | cut -d'-' -f1)"
            mv "$file" "tests/$base_name"
          done
      - uses: actions/upload-artifact@v4
        with:
          name: tests-${{ matrix.target.soc }}
          path: /home/runner/work/esp-hal/esp-hal/tests
          if-no-files-found: error
          overwrite: true

  hil:
    name: Run HIL Tests | ${{ matrix.target.soc }}
    needs: [build-tests, build-xtasks]
    runs-on:
      labels: [self-hosted, "${{ matrix.target.runner }}"]
    strategy:
      fail-fast: false
      matrix:
        target:
          # RISC-V devices:
          - soc: esp32c2
            runner: esp32c2-jtag
            host: aarch64
            hubs: "1 3"
          - soc: esp32c3
            runner: esp32c3-usb
            host: armv7
            hubs: "1-1"
          - soc: esp32c6
            runner: esp32c6-usb
            host: armv7
            hubs: "1-1"
          - soc: esp32h2
            runner: esp32h2-usb
            host: armv7
            hubs: "1-1"
          # Xtensa devices:
          - soc: esp32
            runner: esp32-jtag
            host: aarch64
            hubs: "1 3"
          - soc: esp32s2
            runner: esp32s2-jtag
            host: armv7
            hubs: "1-1"
          - soc: esp32s3
            runner: esp32s3-usb
            host: armv7
            hubs: "1-1"
    steps:
      - uses: actions/download-artifact@v4
        with:
          name: tests-${{ matrix.target.soc }}
          path: tests-${{ matrix.target.soc }}

      - uses: actions/download-artifact@v4
        with:
          name: xtask-${{ matrix.target.host }}

      - name: Cycle USB ports
        run: |
          export PATH=$PATH:/home/espressif/.cargo/bin
          for i in {1..10}; do
            # Disable all used hubs
            for hub in ${{ matrix.target.hubs }}; do
              sudo uhubctl -a off -l $hub
            done

            sleep 0.5

            # Enable all used hubs
            for hub in ${{ matrix.target.hubs }}; do
              sudo uhubctl -a on -l $hub
            done

            sleep 0.5

            if probe-rs list | grep -q "\[0\]:"; then
              break
            fi
          done

      - name: Run Tests
        id: run-tests
        run: |
          export PATH=$PATH:/home/espressif/.cargo/bin
          chmod +x xtask
          ./xtask run-elfs ${{ matrix.target.soc }} tests-${{ matrix.target.soc }}

      - name: Clean up
        if: always()
        run: |
          rm -rf tests-${{ matrix.target.soc }}
          rm -f xtask
