name: Build

on:
  push:
  pull_request:

  # Run automatically every monday
  schedule:
    - cron: 1 12 * * 1

env:

  # Override OSX architecture detection. Required for CMake versions < 3.19.2.
  CMAKE_OSX_ARCHITECTURES: arm64

jobs:
  host:
    strategy:
      matrix:
        sys:
          - {os: 'macos', shell: 'bash'}
          - {os: 'ubuntu', shell: 'bash'}
          - {os: 'windows', shell: 'pwsh'}
          - {os: 'windows', shell: 'msys2'}
        cmake: ['3.10.0', '3.16.0', '3.21.0', '4.0.0', 'latest']
        exclude:
          # GitHub runners use Visual Studio 2022. Support added in CMake 3.21.
          - sys: {os: 'windows', shell: 'pwsh'}
            cmake: '3.10.0'
          - sys: {os: 'windows', shell: 'pwsh'}
            cmake: '3.16.0'
          # MSYS2 always supplies the latest cmake.
          - sys: {os: 'windows', shell: 'msys2'}
            cmake: '3.10.0'
          - sys: {os: 'windows', shell: 'msys2'}
            cmake: '3.16.0'
          - sys: {os: 'windows', shell: 'msys2'}
            cmake: '3.21.0'
          - sys: {os: 'windows', shell: 'msys2'}
            cmake: '4.0.0'
        include:
          - sys: {os: 'windows', shell: 'pwsh'}
            cmake_args: >-
              -DPKG_CONFIG_EXECUTABLE=C:/vcpkg/installed/x64-windows/tools/pkgconf/pkgconf.exe
              -DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake
              --install-prefix=$env:GITHUB_WORKSPACE/install
          - sys: {os: 'windows', shell: 'msys2'}
            cmake_args: >-
              --install-prefix=/usr/local

      # Don't cancel all builds when one fails
      fail-fast: false
    runs-on: ${{ matrix.sys.os }}-latest

    defaults:
      run:
        shell: '${{ matrix.sys.shell }} {0}'

    steps:
    - uses: actions/checkout@v4

    - name: Setup cmake
      uses: jwlawson/actions-setup-cmake@v2
      with:
        cmake-version: ${{ matrix.cmake }}
      if: matrix.sys.shell != 'msys2'

    - name: Install dependencies (macOS)
      run: brew install fftw
      if: matrix.sys.os == 'macos'

    - name: Install dependencies (Ubuntu)
      run: |
        sudo apt update
        sudo apt install libfftw3-dev libusb-1.0-0-dev
      if: matrix.sys.os == 'ubuntu'

    - name: Install dependencies (Windows)
      run: vcpkg install --triplet=x64-windows libusb fftw3 pthreads pkgconf
      if: matrix.sys.os == 'windows' && matrix.sys.shell != 'msys2'

    - name: Setup MSYS (Windows)
      if: matrix.sys.os == 'windows' && matrix.sys.shell == 'msys2'
      uses: msys2/setup-msys2@v2
      with:
        msystem: UCRT64
        install: >-
          git
          make
          mingw-w64-ucrt-x86_64-cmake
          mingw-w64-ucrt-x86_64-toolchain
          mingw-w64-ucrt-x86_64-libusb
          mingw-w64-ucrt-x86_64-fftw

    # Build libhackrf and hackrf-tools together

    - name: Configure & Build
      run: |
        cmake -E make_directory host/build
        cd host/build
        cmake .. -DCMAKE_BUILD_TYPE=Release ${{matrix.cmake_args}}
        cmake --build . --config Release

    # Build libhackrf ONLY

    - name: Configure & Build (libhackrf)
      run: |
        cmake -E make_directory host/libhackrf/build
        cd host/libhackrf/build
        cmake .. -DCMAKE_BUILD_TYPE=Release ${{ matrix.cmake_args }}
        cmake --build . --config Release

    - name: Install (libhackrf)
      run: |
        sudo cmake --install host/libhackrf/build --config Release
      if: matrix.sys.os != 'windows' && matrix.cmake != '3.10.0'

    - name: Install (libhackrf, CMake 3.10)
      run: |
        sudo cmake --build host/libhackrf/build --target install --config Release
      if: matrix.sys.os != 'windows' && matrix.cmake == '3.10.0'

    - name: Install (libhackrf, Windows)
      run: cmake --install host/libhackrf/build --config Release
      if: matrix.sys.os == 'windows'

    # Build hackrf-tools ONLY

    - name: Configure & Build (hackrf-tools)
      run: |
        cmake -E make_directory host/hackrf-tools/build
        cd host/hackrf-tools/build
        cmake .. -DCMAKE_BUILD_TYPE=Release ${{ matrix.cmake_args }}
        cmake --build . --config Release

    - name: Install (hackrf-tools)
      run: |
        sudo cmake --install host/hackrf-tools/build --config Release
      if: matrix.sys.os != 'windows' && matrix.cmake != '3.10.0'

    - name: Install (hackrf-tools, CMake 3.10)
      run: |
        sudo cmake --build host/hackrf-tools/build --target install --config Release
      if: matrix.sys.os != 'windows' && matrix.cmake == '3.10.0'

    - name: Install (hackrf-tools, Windows)
      run: cmake --install host/hackrf-tools/build --config Release
      if: matrix.sys.os == 'windows'

    # Publish the contents of install/bin (which should be the combination libhackrf and host-tools) for Windows
    - name: Publish Artifacts (Windows)
      uses: actions/upload-artifact@v4
      with:
        name: hackrf-tools-windows
        path: ${{github.workspace}}/install/bin
      if: matrix.sys.os == 'windows' && matrix.cmake == 'latest' && matrix.sys.shell == 'pwsh'

  firmware:
    strategy:
      matrix:
        os: ['macos', 'ubuntu', 'windows']
        board: ['HACKRF_ONE', 'JAWBREAKER', 'RAD1O', 'PRALINE']
        cmake: ['3.10.0', 'latest']
        exclude:
          - os: 'windows'
            cmake: '3.10.0'

      # Don't cancel all builds when one fails
      fail-fast: false
    runs-on: ${{ matrix.os }}-latest

    steps:
    - uses: actions/checkout@v4
      with:
        submodules: true

    - name: Setup cmake
      uses: jwlawson/actions-setup-cmake@v2
      with:
        cmake-version: ${{ matrix.cmake }}
      if: matrix.os != 'windows'

    - name: Install Arm GNU Toolchain
      uses: carlosperate/arm-none-eabi-gcc-action@v1
      if: matrix.os != 'windows'

    - name: Install dependencies (macOS)
      run: |
        brew install dfu-util
        python3 -m venv environment && source environment/bin/activate
        python3 -m pip install PyYAML
      if: matrix.os == 'macos'

    - name: Install dependencies (Ubuntu)
      run: |
        python3 -m venv environment && source environment/bin/activate
        python3 -m pip install PyYAML
        sudo apt install dfu-util
      if: matrix.os == 'ubuntu'

    - name: Build libopencm3
      shell: bash
      working-directory: ${{github.workspace}}/firmware/libopencm3/
      run: |
        source ../../environment/bin/activate
        make
      if: matrix.os != 'windows'

    - name: Create Build Environment
      run: cmake -E make_directory ${{github.workspace}}/firmware/build
      if: matrix.os != 'windows'

    - name: Configure CMake
      shell: bash
      working-directory: ${{github.workspace}}/firmware/build
      run: cmake $GITHUB_WORKSPACE/firmware/ -DCMAKE_BUILD_TYPE=Release -DBOARD=${{ matrix.board }}
      if: matrix.os != 'windows'

    - name: Build
      working-directory: ${{github.workspace}}/firmware/build
      shell: bash
      run: |
        source ../../environment/bin/activate
        cmake --build . --config Release
      if: matrix.os != 'windows'

    - name: Setup MSYS (Windows)
      if: matrix.os == 'windows'
      uses: msys2/setup-msys2@v2
      with:
        msystem: UCRT64
        update: true
        install: >-
          git
          make
          mingw-w64-ucrt-x86_64-arm-none-eabi-gcc
          mingw-w64-ucrt-x86_64-cmake
          mingw-w64-ucrt-x86_64-dfu-util
          mingw-w64-ucrt-x86_64-python-yaml

    - name: Build with MSYS (Windows)
      if: matrix.os == 'windows'
      shell: msys2 {0}
      run: |
        mkdir firmware/build
        cd firmware/build
        cmake -G "MSYS Makefiles" -DCMAKE_BUILD_TYPE=Release -DBOARD=${{ matrix.board }} ..
        make
