diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 21593d8a..eaa1d982 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -17,127 +17,70 @@ jobs: host: strategy: matrix: - os: ['macos', 'ubuntu', 'windows'] - cmake: ['3.10.0', '3.21.7', '4.2.6', 'latest'] - compiler: ['gcc', 'msvc'] + 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: - # MSVC only runs on Windows. - - os: 'macos' - compiler: 'msvc' - - os: 'ubuntu' - compiler: 'msvc' - # We can't use the oldest CMake versions on Windows. - - os: 'windows' + # GitHub runners use Visual Studio 2022. Support added in CMake 3.21. + - sys: {os: 'windows', shell: 'pwsh'} cmake: '3.10.0' - # The in-between CMake versions aren't so intersting with GCC. - - compiler: 'gcc' - cmake: '3.21.7' - - compiler: 'gcc' - cmake: '4.2.6' + - 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: - # Shell selection - - os: 'macos' - shell: 'bash' - - os: 'ubuntu' - shell: 'bash' - - os: 'windows' - compiler: 'msvc' - shell: 'pwsh' - - os: 'windows' - compiler: 'gcc' - shell: 'msys2' - # MSVC version selection - - cmake: '3.21.7' - msvc: '17.14' - - cmake: '4.2.6' - msvc: 'latest' - - cmake: 'latest' - msvc: 'latest' - # CMake generator selection - - os: 'macos' - generator: 'Unix Makefiles' - - os: 'ubuntu' - generator: 'Unix Makefiles' - - compiler: 'msvc' - cmake: '3.21.7' - generator: 'Visual Studio 17 2022' - - compiler: 'msvc' - cmake: '4.2.6' - generator: 'Visual Studio 18 2026' - - compiler: 'msvc' - cmake: 'latest' - generator: 'Visual Studio 18 2026' - - os: 'windows' - compiler: 'gcc' - generator: 'MSYS Makefiles' - # Additional CMake arguments - - os: 'windows' - compiler: 'msvc' + - 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 - - os: 'windows' - compiler: 'gcc' + - sys: {os: 'windows', shell: 'msys2'} cmake_args: >- --install-prefix=/usr/local - # CMake 3.10 uses --build with --target install - - cmake: '3.10.0' - install_cmd: --build - install_args: --target install - # Later versions just use --install - - cmake: '3.21.7' - install_cmd: --install - - cmake: '4.2.6' - install_cmd: --install - - cmake: 'latest' - install_cmd: --install - # We need sudo on MacOS and Ubuntu only - - os: macos - sudo: sudo - - os: ubuntu - sudo: sudo - # Don't cancel all builds when one fails fail-fast: false - runs-on: ${{ matrix.os }}-latest + runs-on: ${{ matrix.sys.os }}-latest defaults: run: - shell: '${{ matrix.shell }} {0}' + shell: '${{ matrix.sys.shell }} {0}' steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v4 - name: Setup cmake - uses: lukka/get-cmake@latest + uses: jwlawson/actions-setup-cmake@v2 with: - cmakeVersion: ${{ matrix.cmake }} - if: matrix.shell != 'msys2' - - - name: Install MSVC (Windows) - uses: k3DW/setup-msvc@v1 - with: - vs-version: ${{ matrix.msvc }} - if: matrix.compiler == 'msvc' && matrix.msvc != 'latest' + cmake-version: ${{ matrix.cmake }} + if: matrix.sys.shell != 'msys2' - name: Install dependencies (macOS) run: brew install fftw - if: matrix.os == 'macos' + 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.os == 'ubuntu' + if: matrix.sys.os == 'ubuntu' - name: Install dependencies (Windows) run: vcpkg install --triplet=x64-windows libusb fftw3 pthreads pkgconf - if: matrix.os == 'windows' && matrix.shell != 'msys2' + if: matrix.sys.os == 'windows' && matrix.sys.shell != 'msys2' - name: Setup MSYS (Windows) - if: matrix.os == 'windows' && matrix.shell == 'msys2' + if: matrix.sys.os == 'windows' && matrix.sys.shell == 'msys2' uses: msys2/setup-msys2@v2 with: msystem: UCRT64 @@ -155,7 +98,7 @@ jobs: run: | cmake -E make_directory host/build cd host/build - cmake .. -G "${{ matrix.generator }}" -DCMAKE_BUILD_TYPE=Release ${{matrix.cmake_args}} + cmake .. -DCMAKE_BUILD_TYPE=Release ${{matrix.cmake_args}} cmake --build . --config Release # Build libhackrf ONLY @@ -164,12 +107,22 @@ jobs: run: | cmake -E make_directory host/libhackrf/build cd host/libhackrf/build - cmake .. -G "${{ matrix.generator }}" -DCMAKE_BUILD_TYPE=Release ${{ matrix.cmake_args }} + cmake .. -DCMAKE_BUILD_TYPE=Release ${{ matrix.cmake_args }} cmake --build . --config Release - name: Install (libhackrf) run: | - ${{ matrix.sudo }} cmake ${{ matrix.install_cmd }} host/libhackrf/build ${{ matrix.install_args }} --config Release + 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 @@ -177,12 +130,22 @@ jobs: run: | cmake -E make_directory host/hackrf-tools/build cd host/hackrf-tools/build - cmake .. -G "${{ matrix.generator }}" -DCMAKE_BUILD_TYPE=Release ${{ matrix.cmake_args }} + cmake .. -DCMAKE_BUILD_TYPE=Release ${{ matrix.cmake_args }} cmake --build . --config Release - name: Install (hackrf-tools) run: | - ${{ matrix.sudo }} cmake ${{ matrix.install_cmd }} host/hackrf-tools/build ${{ matrix.install_args }} + 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) @@ -190,40 +153,31 @@ jobs: with: name: hackrf-tools-windows path: ${{github.workspace}}/install/bin - if: matrix.os == 'windows' && matrix.cmake == 'latest' && matrix.shell == 'pwsh' + 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', 'UNIVERSAL'] - cmake: ['3.12.0', 'latest'] + board: ['HACKRF_ONE', 'JAWBREAKER', 'RAD1O', 'PRALINE'] + cmake: ['3.10.0', 'latest'] exclude: - os: 'windows' - cmake: '3.12.0' - # GitHub doesn't give us many macOS runners, so don't build for every board. - # We just need to know that building firmware works on macOS. Use PRALINE - # since that's the most complicated one due to FPGA bitstreams. - - os: 'macos' - board: 'HACKRF_ONE' - - os: 'macos' - board: 'JAWBREAKER' - - os: 'macos' - board: 'RAD1O' + cmake: '3.10.0' # Don't cancel all builds when one fails fail-fast: false runs-on: ${{ matrix.os }}-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v4 with: submodules: true - name: Setup cmake - uses: lukka/get-cmake@latest + uses: jwlawson/actions-setup-cmake@v2 with: - cmakeVersion: ${{ matrix.cmake }} + cmake-version: ${{ matrix.cmake }} if: matrix.os != 'windows' - name: Install Arm GNU Toolchain diff --git a/.github/workflows/clang-format-check.yml b/.github/workflows/clang-format-check.yml index d498d609..0bf33429 100644 --- a/.github/workflows/clang-format-check.yml +++ b/.github/workflows/clang-format-check.yml @@ -16,7 +16,7 @@ jobs: - check: 'firmware/hackrf_usb' exclude: '' steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v4 - name: Run clang-format-action uses: jidicula/clang-format-action@v4.6.2 with: diff --git a/.github/workflows/includes-check.yml b/.github/workflows/includes-check.yml deleted file mode 100644 index f16800fe..00000000 --- a/.github/workflows/includes-check.yml +++ /dev/null @@ -1,96 +0,0 @@ -name: Check includes -on: [push, pull_request] - -defaults: - run: - shell: bash - -jobs: - includes-check: - runs-on: ubuntu-latest - container: - image: "debian:13" - options: --user 0 - strategy: - matrix: - board: ['HACKRF_ONE', 'JAWBREAKER', 'RAD1O', 'PRALINE', 'UNIVERSAL'] - cmake: ['3.12.0', 'latest'] - - # Don't cancel all builds when one fails - fail-fast: false - - steps: - - - name: Make it work on debian - run: | - apt update - apt install -y git python3 python3-pip python3-venv nodejs unzip - # actions/checkout insists on putting the checkout in the - # working directory rather than ${{ github.workspace }}. - # - # This may just be because the 'runner' user does not exist - # in the docker image at startup. - # - # also see: https://github.com/actions/runner/issues/878 - useradd -ms /bin/bash runner - ln -s /__w /home/runner/work - - - name: Checkout repository - uses: actions/checkout@v6 - with: - submodules: true - - - name: Setup cmake - uses: lukka/get-cmake@latest - with: - cmakeVersion: ${{ matrix.cmake }} - - - name: Install Arm GNU Toolchain - uses: carlosperate/arm-none-eabi-gcc-action@v1 - - - name: Install dependencies - run: | - python3 -m venv environment && source environment/bin/activate - python3 -m pip install PyYAML - apt install -y iwyu - iwyu --version - - - name: Build libopencm3 - working-directory: ${{github.workspace}}/firmware/libopencm3/ - run: | - source ../../environment/bin/activate - make - - - name: Create Build Environment - run: cmake -E make_directory ${{github.workspace}}/firmware/build - - - name: Configure CMake - working-directory: ${{github.workspace}}/firmware/build - run: cmake ${{github.workspace}}/firmware/ -DCMAKE_BUILD_TYPE=Release -DBOARD=${{ matrix.board }} -DCHECK_INCLUDES=1 - - - name: Build - working-directory: ${{github.workspace}}/firmware/build - run: | - source ../../environment/bin/activate - output="$(cmake --build . --config Release 2>&1)" - while IFS= read -r line - do - if [[ "${line}" == "Warning: include-what-you-use"* ]]; then - exit_code=1 - dump=1 - echo - elif [[ "${line}" == "---" ]]; then - dump=0 - echo - fi - if [[ ${dump} == "1" ]]; then - echo "${line}" - fi - done <<< ${output} - if [[ ${exit_code} == "1" ]]; then - echo "Includes check failed for board target: ${{ matrix.board }}" - else - echo "Includes check succeeded for board target: ${{ matrix.board }}" - fi - echo $(include-what-you-use --version) - exit ${exit_code} diff --git a/Jenkinsfile b/Jenkinsfile index dcfd9ad8..76718a59 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,125 +1,33 @@ -import org.jenkinsci.plugins.workflow.steps.FlowInterruptedException - -def docker_args = '''--group-add=20 --group-add=46 --device-cgroup-rule="c 189:* rmw" \ - --device-cgroup-rule="c 166:* rmw" -v /dev/bus/usb:/dev/bus/usb \ - -v /tmp/req_pipe:/tmp/req_pipe -v /tmp/res_pipe:/tmp/res_pipe''' - -def h1_test = '''python3 ci-scripts/hackrf_test.py --ci --log log \ - --hostdir host/build/hackrf-tools/src/ \ - --fwupdate firmware/hackrf_usb/build/ \ - --tester 0000000000000000325866e629a25623 \ - --eut RunningFromRAM --unattended --rev r4''' - -def hpro_test = '''python3 ci-scripts/hackrf_pro_test.py --ci --log log \ - --hostdir host/build/hackrf-tools/src \ - --fwupdate firmware/hackrf_usb/build \ - --tester 0000000000000000a06063c82338145f \ - --eut RunningFromRAM -p --rev r1.2''' - pipeline { agent any stages { stage('Build Docker Image') { - options { - timeout(time: 20, unit: 'MINUTES') - } steps { sh 'docker build -t hackrf https://github.com/greatscottgadgets/hackrf.git' } } - stage('Test HackRF One with BOARD=HACKRF_ONE') { + stage('Test Suite') { agent { docker { image 'hackrf' reuseNode true - args docker_args + args '--group-add=20 --group-add=46 --device-cgroup-rule="c 189:* rmw" --device-cgroup-rule="c 166:* rmw" -v /dev/bus/usb:/dev/bus/usb -e TESTER=0000000000000000325866e629a25623 -e EUT=RunningFromRAM' } } - options { - timeout(time: 20, unit: 'MINUTES') - } steps { - runCommand("Install Host Tools", './ci-scripts/install_host.sh', 3, 1, 'MINUTES') - runCommand("Build HackRF One Firmware", './ci-scripts/build_firmware.sh HACKRF_ONE', 3, 1, 'MINUTES') - lock('HIL_hubs') { - script { - allOff() - runTest("Check Host", 'h1_eut', './ci-scripts/test_host.sh') - runTest("HackRF One HIL Test", 'h1_tester h1_eut', h1_test) - runTest("SGPIO Debug Test", 'h1_eut', 'python3 ci-scripts/test_sgpio_debug.py') - } + sh './ci-scripts/install-host.sh' + sh './ci-scripts/install-firmware.sh' + sh 'hubs all off' + retry(3) { + sh './ci-scripts/test-host.sh' } - } - } - stage('Test HackRF One with BOARD=UNIVERSAL') { - agent { - docker { - image 'hackrf' - reuseNode true - args docker_args - } - } - options { - timeout(time: 20, unit: 'MINUTES') - } - steps { - runCommand("Install Host Tools", './ci-scripts/install_host.sh', 3, 1, 'MINUTES') - runCommand("Build Universal Firmware", './ci-scripts/build_firmware.sh UNIVERSAL', 3, 1, 'MINUTES') - lock('HIL_hubs') { - script { - allOff() - runTest("Check Host", 'h1_eut', './ci-scripts/test_host.sh') - runTest("HackRF One HIL Test", 'h1_tester h1_eut', h1_test) - runTest("SGPIO Debug Test", 'h1_eut', 'python3 ci-scripts/test_sgpio_debug.py') - } - } - - } - } - stage('Test HackRF Pro with BOARD=PRALINE') { - agent { - docker { - image 'hackrf' - reuseNode true - args "$docker_args" - } - } - options { - timeout(time: 20, unit: 'MINUTES') - } - steps { - runCommand("Install Host Tools", './ci-scripts/install_host.sh', 3, 1, 'MINUTES') - runCommand("Build Praline Firmware", './ci-scripts/build_firmware.sh PRALINE', 3, 1, 'MINUTES') - lock('HIL_hubs') { - script { - allOff() - runTest("Check Host", 'hpro_eut', './ci-scripts/test_host.sh') - runTest("HackRF Pro HIL Test", 'hpro_tester hpro_eut', hpro_test) - } - } - } - } - stage('Test HackRF Pro with BOARD=UNIVERSAL') { - agent { - docker { - image 'hackrf' - reuseNode true - args "$docker_args" - } - } - options { - timeout(time: 20, unit: 'MINUTES') - } - steps { - runCommand("Install Host Tools", './ci-scripts/install_host.sh', 3, 1, 'MINUTES') - runCommand("Build Universal Firmware", './ci-scripts/build_firmware.sh UNIVERSAL', 3, 1, 'MINUTES') - lock('HIL_hubs') { - script { - allOff() - runTest("Check Host", 'hpro_eut', './ci-scripts/test_host.sh') - runTest("HackRF Pro HIL Test", 'hpro_tester hpro_eut', hpro_test) - } + sh 'hubs hackrf hackrf_dfu on' + sh 'python3 ci-scripts/hackrf_test.py --unattended --ci --log log --rev r4 --manufacturer --hostdir host/build/hackrf-tools/src/ --fwupdate firmware/hackrf_usb/build/ --tester 0000000000000000325866e629a25623 --eut RunningFromRAM' + sh 'hubs all off' + retry(3) { + sh 'python3 ci-scripts/test-sgpio-debug.py' } + sh 'hubs all reset' } } } @@ -132,46 +40,3 @@ pipeline { } } } - -def allOff() { - // Allow up to 3 retries, 20 seconds each, for the USB hub port power server to respond appropriately - runCommand('USB hub port power server command', "hubs all off", 3, 20, 'SECONDS') -} - -def reset(devices) { - // Allow up to 3 retries, 20 seconds each, for the USB hub port power server to respond appropriately - runCommand('USB hub port power server command', "hubs ${devices} reset", 3, 20, 'SECONDS') -} - -def runCommand(title, cmd, retries, time, unit) { - retry(retries) { - try { - timeout(time: time, unit: unit) { - sh "${cmd}" - } - } catch (FlowInterruptedException err) { - // Check if the cause was specifically an exceeded timeout - def cause = err.getCauses().get(0) - if (cause instanceof org.jenkinsci.plugins.workflow.steps.TimeoutStepExecution.ExceededTimeout) { - echo "${title} timeout reached." - throw err // Re-throw the exception to fail the build - } else { - echo "Build interrupted for another reason." - throw err // Re-throw the exception to fail the build - } - } catch (Exception err) { - echo "An unrelated error occurred: ${err.getMessage()}" - throw err - } - } -} - -def runTest(title, devices, cmd) { - retry(3) { - // reset() retains it's own internal retries - reset(devices) - sh 'sleep 1s' - // run the test with 0 internal retries and 3 external retries to ensure resets between runs - runCommand(title, cmd, 0, 5, 'MINUTES') - } -} diff --git a/ci-scripts/hackrf_pro_test.py b/ci-scripts/hackrf_pro_test.py deleted file mode 100644 index 44b6eb56..00000000 --- a/ci-scripts/hackrf_pro_test.py +++ /dev/null @@ -1,1684 +0,0 @@ -#!/usr/bin/env python3 - -import sys -import subprocess -import time -import os, shutil -import usb -from datetime import datetime -from dataclasses import dataclass -import argparse -import numpy as np -import traceback -import re - -DFU_UTIL = "/usr/bin/dfu-util" -TMP_DIR = "/tmp/" -WAVEFORM = TMP_DIR + "waveform100" -NOISE = TMP_DIR + "noise" -VENDOR_ID = 0x1d50 -PRODUCT_ID = 0x6089 -DFU_VENDOR_ID = 0x1fc9 -DFU_PRODUCT_ID = 0x000c -ONE_MHZ = 1000000 -TIMEOUT = 5 -MAX_PPM = 20 -MAX_BASELINE = -20 -SIGNAL_THRESHOLD = -25 -MAX_DC_DBC = -27 -MAX_M_DBC = -27 -MAX_MH2_DBC = -40 -MAX_H2_DBC = -39 -MAX_OTHER_DBC = -34 -LP2_CORRECTION = 10 -MAX_POWER = -10 -IF_REQUIRED_MIN = 2320 -IF_REQUIRED_MAX = 2580 -IF_TEST_RANGE = 256 -SLEEP_TIME = 0.05 # seconds to wait between start of TX and start of RX - -@dataclass -class TestCase(): - name: str - freq: int - amp: bool - direction: str - base_ecode: int - rx_lna_gain: int - rx_vga_gain: int - tx_gain: int - -# Try to keep rx_lna_gain and rx_vga_gain between 8 and 32. -bp1txamp = TestCase(name="BP1-TX-amp", freq=2500, amp=True, direction="tx", - base_ecode=320, rx_lna_gain=8, rx_vga_gain=16, tx_gain=5) -lp1txamp = TestCase(name="LP1-TX-amp", freq=915, amp=True, direction="tx", - base_ecode=420, rx_lna_gain=8, rx_vga_gain=16, tx_gain=14) -lp2txamp = TestCase(name="LP2-TX-amp", freq=12, amp=True, direction="tx", - base_ecode=2420, rx_lna_gain=8, rx_vga_gain=16, tx_gain=13) -hp1txamp = TestCase(name="HP1-TX-amp", freq=5995, amp=True, direction="tx", - base_ecode=520, rx_lna_gain=32, rx_vga_gain=16, tx_gain=18) - -bp1txnoamp = TestCase(name="BP1-TX-noamp", freq=2500, amp=False, direction="tx", - base_ecode=350, rx_lna_gain=16, rx_vga_gain=16, tx_gain=14) -lp1txnoamp = TestCase(name="LP1-TX-noamp", freq=915, amp=False, direction="tx", - base_ecode=450, rx_lna_gain=16, rx_vga_gain=12, tx_gain=27) -lp2txnoamp = TestCase(name="LP2-TX-noamp", freq=12, amp=False, direction="tx", - base_ecode=2450, rx_lna_gain=16, rx_vga_gain=18, tx_gain=20) -hp1txnoamp = TestCase(name="HP1-TX-noamp", freq=5995, amp=False, direction="tx", - base_ecode=550, rx_lna_gain=32, rx_vga_gain=24, tx_gain=19) - -# Much of the information in the RX test cases is a duplication of information -# in the TX test cases, but it's easier to keep legacy error codes this way. -bp1rxamp = TestCase(name="BP1-RX-amp", freq=2500, amp=True, direction="rx", - base_ecode=620, rx_lna_gain=8, rx_vga_gain=16, tx_gain=16) -lp1rxamp = TestCase(name="LP1-RX-amp", freq=915, amp=True, direction="rx", - base_ecode=720, rx_lna_gain=16, rx_vga_gain=16, tx_gain=18) -lp2rxamp = TestCase(name="LP2-RX-amp", freq=12, amp=True, direction="rx", - base_ecode=2720, rx_lna_gain=16, rx_vga_gain=16, tx_gain=18) -hp1rxamp = TestCase(name="HP1-RX-amp", freq=5995, amp=True, direction="rx", - base_ecode=820, rx_lna_gain=16, rx_vga_gain=28, tx_gain=38) - -bp1rxnoamp = TestCase(name="BP1-RX-noamp", freq=2500, amp=False, direction="rx", - base_ecode=650, rx_lna_gain=16, rx_vga_gain=16, tx_gain=15) -lp1rxnoamp = TestCase(name="LP1-RX-noamp", freq=915, amp=False, direction="rx", - base_ecode=750, rx_lna_gain=16, rx_vga_gain=16, tx_gain=35) -lp2rxnoamp = TestCase(name="LP2-RX-noamp", freq=12, amp=False, direction="rx", - base_ecode=2750, rx_lna_gain=16, rx_vga_gain=16, tx_gain=38) -hp1rxnoamp = TestCase(name="HP1-RX-noamp", freq=5995, amp=False, direction="rx", - base_ecode=850, rx_lna_gain=16, rx_vga_gain=36, tx_gain=46) - -praline_rf_test_cases = ( - bp1txamp, lp1txamp, lp2txamp, hp1txamp, - bp1txnoamp, lp1txnoamp, lp2txnoamp, hp1txnoamp, - bp1rxamp, lp1rxamp, lp2rxamp, hp1rxamp, - bp1rxnoamp, lp1rxnoamp, lp2rxnoamp, hp1rxnoamp) - -# Praline r1.1.0 requires different gain configuration -r110_bp1rxnoamp = TestCase(name="BP1-RX-noamp", freq=2500, amp=False, direction="rx", - base_ecode=650, rx_lna_gain=16, rx_vga_gain=16, tx_gain=15) -r110_lp1rxnoamp = TestCase(name="LP1-RX-noamp", freq=915, amp=False, direction="rx", - base_ecode=750, rx_lna_gain=16, rx_vga_gain=16, tx_gain=35) -r110_lp2rxnoamp = TestCase(name="LP2-RX-noamp", freq=12, amp=False, direction="rx", - base_ecode=2750, rx_lna_gain=16, rx_vga_gain=16, tx_gain=38) -r110_hp1rxnoamp = TestCase(name="HP1-RX-noamp", freq=5995, amp=False, direction="rx", - base_ecode=850, rx_lna_gain=16, rx_vga_gain=36, tx_gain=46) - -r110_bp1txamp = TestCase(name="BP1-TX-amp", freq=2500, amp=True, direction="tx", - base_ecode=320, rx_lna_gain=8, rx_vga_gain=16, tx_gain=5) -r110_lp1txamp = TestCase(name="LP1-TX-amp", freq=915, amp=True, direction="tx", - base_ecode=420, rx_lna_gain=8, rx_vga_gain=16, tx_gain=10) -r110_lp2txamp = TestCase(name="LP2-TX-amp", freq=12, amp=True, direction="tx", - base_ecode=2420, rx_lna_gain=8, rx_vga_gain=16, tx_gain=12) -r110_hp1txamp = TestCase(name="HP1-TX-amp", freq=5995, amp=True, direction="tx", - base_ecode=520, rx_lna_gain=32, rx_vga_gain=16, tx_gain=17) - -r110_bp1txnoamp = TestCase(name="BP1-TX-noamp", freq=2500, amp=False, direction="tx", - base_ecode=350, rx_lna_gain=16, rx_vga_gain=16, tx_gain=13) -r110_lp1txnoamp = TestCase(name="LP1-TX-noamp", freq=915, amp=False, direction="tx", - base_ecode=450, rx_lna_gain=16, rx_vga_gain=12, tx_gain=23) -r110_lp2txnoamp = TestCase(name="LP2-TX-noamp", freq=12, amp=False, direction="tx", - base_ecode=2450, rx_lna_gain=16, rx_vga_gain=18, tx_gain=18) -r110_hp1txnoamp = TestCase(name="HP1-TX-noamp", freq=5995, amp=False, direction="tx", - base_ecode=550, rx_lna_gain=32, rx_vga_gain=24, tx_gain=18) - -r110_bp1rxamp = TestCase(name="BP1-RX-amp", freq=2500, amp=True, direction="rx", - base_ecode=620, rx_lna_gain=8, rx_vga_gain=16, tx_gain=16) -r110_lp1rxamp = TestCase(name="LP1-RX-amp", freq=915, amp=True, direction="rx", - base_ecode=720, rx_lna_gain=16, rx_vga_gain=16, tx_gain=8) -r110_lp2rxamp = TestCase(name="LP2-RX-amp", freq=12, amp=True, direction="rx", - base_ecode=2720, rx_lna_gain=16, rx_vga_gain=16, tx_gain=10) -r110_hp1rxamp = TestCase(name="HP1-RX-amp", freq=5995, amp=True, direction="rx", - base_ecode=820, rx_lna_gain=16, rx_vga_gain=28, tx_gain=25) - -r110_bp1rxnoamp = TestCase(name="BP1-RX-noamp", freq=2500, amp=False, direction="rx", - base_ecode=650, rx_lna_gain=16, rx_vga_gain=16, tx_gain=15) -r110_lp1rxnoamp = TestCase(name="LP1-RX-noamp", freq=915, amp=False, direction="rx", - base_ecode=750, rx_lna_gain=16, rx_vga_gain=16, tx_gain=24) -r110_lp2rxnoamp = TestCase(name="LP2-RX-noamp", freq=12, amp=False, direction="rx", - base_ecode=2750, rx_lna_gain=16, rx_vga_gain=16, tx_gain=28) -r110_hp1rxnoamp = TestCase(name="HP1-RX-noamp", freq=5995, amp=False, direction="rx", - base_ecode=850, rx_lna_gain=16, rx_vga_gain=36, tx_gain=30) - -praline_r110_rf_test_cases = ( - r110_bp1txamp, r110_lp1txamp, r110_lp2txamp, r110_hp1txamp, - r110_bp1txnoamp, r110_lp1txnoamp, r110_lp2txnoamp, r110_hp1txnoamp, - r110_bp1rxamp, r110_lp1rxamp, r110_lp2rxamp, r110_hp1rxamp, - r110_bp1rxnoamp, r110_lp1rxnoamp, r110_lp2rxnoamp, r110_hp1rxnoamp) - -ifmin = TestCase(name="IF-min", freq=IF_REQUIRED_MIN, amp=None, direction=None, - base_ecode=None, rx_lna_gain=16, rx_vga_gain=16, tx_gain=12) -ifmax = TestCase(name="IF-max", freq=IF_REQUIRED_MAX, amp=None, direction=None, - base_ecode=None, rx_lna_gain=16, rx_vga_gain=16, tx_gain=18) - -ppm = TestCase(name="PPM", freq=2507, amp=False, direction=None, - base_ecode=None, rx_lna_gain=16, rx_vga_gain=16, tx_gain=18) - -noise = TestCase(name="Noise", freq=2550, amp=True, direction=None, - base_ecode=None, rx_lna_gain=40, rx_vga_gain=52, tx_gain=None) - -r9_tester_cal = [1.1, 0.4, 0.4, 1.1, 0.8, 0.2, 0.6, 1.6, -0.4, -1.2, -1.1, 1.1, -1.4, -0.9, 0.1, 1.8] -r9_eut_cal = [-1.1, -1.6, -1.4, -1.3, -1.3, -0.9, 0.1, 1.8, 0.8, 1.1, 0.9, -0.2, 0.9, 0.2, 0.6, 1.5] -og_tester_cal = [-0.4, -0.3, -0.2, -0.4, -0.8, -0.5, -0., -0.1, 1.4, 2., 1.6, -0.1, 1.5, 0.7, 0.5, -0.3] -og_eut_cal = [1.8, 1.8, 1.6, 2., 1.3, 0.7, 0.5, -0.3, 0.2, -0.3, -0.5, 1.2, -0.8, -0.5, -0., -0.1] - -emessages = { - 1: "Wrong device placed in DFU mode", - 2: "DFU device not found", - 3: "Failed to parse a serial number from hackrf_info", - 4: "No path to hackrf host tools found. Please provide a directory via --hostdir", - 5: """Specified TESTER binary directory must be different from the found EUT bin directory - If shared TESTER/EUT binary directory is intended, omit --testerdir""", - 6: "Unable to parse valid serial number from connected devices", - 7: "TESTER and EUT cannot be the same device", - 8: "Invalid TESTER unit, please use a HackRF One", - 9: "Invalid EUT unit, please use a HackRF Pro", - 10: "Clock readback failed", - 11: "SGPIO RX test failed", - 12: "Loopback test failed", - 13: "Self-test failed, see above", - 14: "FPGA configuration failed", - 15: "Multiple self-test failures, see above", - 16: "Mixer self-test failed", - 17: "Transceiver self-test failed", - 18: "32kHz oscillator test failed", - 19: "Too many devices found using unique host tool directory", - 20: "Factory TESTER device not found", - 21: "Factory EUT device not found", - 22: "SGPIO RX test timed out", - 23: "Loopback test timed out", - 24: "FPGA SPI test failed", - 60: "Unable to program firmware via DFU", - 65: "EUT not detected after DFU programming", - 70: "Unable to program SPI flash", - 75: "EUT not detected after flashing", - 76: "Unable to reset EUT", - 77: "Unable to reset TESTER", - 78: "EUT not detected after reset", - 79: "TESTER not detected after reset", - 80: "Could not find EUT", - 81: "Could not find TESTER", - 82: "Found multiple candidate EUTs", - 83: "Found multiple candidate TESTERs", - 84: "EUT running from RAM instead of flash", - 85: "TESTER running from RAM instead of flash", - 86: "Couldn't parse hackrf_info output", - 87: "hackrf_info command failed", - 88: "Incorrect EUT hardware revision", - 89: "Incorrect TESTER hardware revision", - 90: "EUT has incorrect manufacturer pin strap", - 91: "TESTER has incorrect manufacturer pin strap", - 92: "No HackRFs found", - 99: "Incorrect device name", - 100: "EUT couldn't verify clkgen register", - 101: "TESTER couldn't verify clkgen register", - 120: "EUT couldn't verify xcvr register", - 121: "TESTER couldn't verify xcvr register", - 140: "EUT couldn't verify mixer register", - 141: "TESTER couldn't verify mixer register", - 150: "Failed RX for IF verification", - 152: "Couldn't parse received power", - 154: "Received power out of bounds", - 160: "Insufficient IF range", - 170: "RX operation failed", - 172: "Couldn't parse hackrf_sweep output", - 180: "Subprocess timed out", - 190: "Failed to configure LEDs", - 200: "hackrf_clock command failed", - 210: "TESTER failed to detect EUT CLKOUT", - 211: "EUT failed to detect TESTER CLKOUT", - 212: "TESTER detected spurious CLKIN", - 213: "EUT detected spurious CLKIN", - 220: "Failed TESTER CLKIN activation RX", - 221: "Failed EUT CLKIN activation RX", - 230: "Failed TESTER PLL check", - 231: "Failed EUT PLL check", - 232: "TESTER PLL failed to lock", - 233: "EUT PLL failed to lock", - 240: "Clock synchronization failure", - 250: "Failed PPM detection sweep", - 252: "Couldn't parse PPM test sweep data", - 254: "TESTER couldn't detect PPM test transmission", - 255: "EUT couldn't detect PPM test transmission", - 260: "Frequency error exceeds limit", - 300: "Failed baseline RX", - 302: "Couldn't parse baseline RX power", - 306: "Baseline RX power too high", - 310: "Failed noise RX", - 311: "Couldn't parse noise RX power", - 312: "Noise RX power out of range", - 313: "Required noise gain out of range", - 315: "Couldn't read noise RX file", - 316: "Too little variation in ADC bit", - 317: "ADC bit correlates strongly with another bit", - 321: "Excessive TX DC offset in AMP txbp1", - 322: "insufficient signal strength in AMP txbp1", - 323: "AMP txbp1 clipping", - 325: "peak found at unexpected frequency in AMP txbp1", - 330: "harmonics detected in AMP txbp1", - 335: "neighbor magnitude exceeded in AMP txbp1", - 340: "neighbor magnitude exceeded in AMP txbp1", - 345: "spectrum mirrored or inverted in AMP txbp1", - 350: "excessive power out of channel in AMP txbp1", - 351: "Excessive TX DC offset in NOAMP txbp1", - 352: "insufficient signal strength in NOAMP txbp1", - 353: "NOAMP txbp1 clipping", - 355: "peak found at unexpected frequency in NOAMP txbp1", - 360: "harmonics detected in NOAMP txbp1", - 365: "neighbor magnitude exceeded in NOAMP txbp1", - 370: "neighbor magnitude exceeded in NOAMP txbp1", - 375: "spectrum mirrored or inverted in NOAMP txbp1", - 380: "excessive power out of channel in NOAMP txbp1", - 421: "Excessive TX DC offset in AMP txlp1", - 422: "insufficient signal strength in AMP txlp1", - 423: "AMP txlp1 clipping", - 425: "peak found at unexpected frequency in AMP txlp1", - 430: "harmonics detected in AMP txlp1", - 435: "neighbor magnitude exceeded in AMP txlp1", - 440: "neighbor magnitude exceeded in AMP txlp1", - 445: "spectrum mirrored or inverted in AMP txlp1", - 450: "excessive power out of channel in AMP txlp1", - 451: "Excessive TX DC offset in NOAMP txlp1", - 452: "insufficient signal strength in NOAMP txlp1", - 453: "NOAMP txlp1 clipping", - 455: "peak found at unexpected frequency in NOAMP txlp1", - 460: "harmonics detected in NOAMP txlp1", - 465: "neighbor magnitude exceeded in NOAMP txlp1", - 470: "neighbor magnitude exceeded in NOAMP txlp1", - 475: "spectrum mirrored or inverted in NOAMP txlp1", - 480: "excessive power out of channel in NOAMP txlp1", - 2421: "Excessive TX DC offset in AMP txlp2", - 2422: "insufficient signal strength in AMP txlp2", - 2423: "AMP txlp2 clipping", - 2425: "peak found at unexpected frequency in AMP txlp2", - 2430: "harmonics detected in AMP txlp2", - 2435: "neighbor magnitude exceeded in AMP txlp2", - 2440: "neighbor magnitude exceeded in AMP txlp2", - 2445: "spectrum mirrored or inverted in AMP txlp2", - 2450: "excessive power out of channel in AMP txlp2", - 2451: "Excessive TX DC offset in NOAMP txlp2", - 2452: "insufficient signal strength in NOAMP txlp2", - 2453: "NOAMP txlp2 clipping", - 2455: "peak found at unexpected frequency in NOAMP txlp2", - 2460: "harmonics detected in NOAMP txlp2", - 2465: "neighbor magnitude exceeded in NOAMP txlp2", - 2470: "neighbor magnitude exceeded in NOAMP txlp2", - 2475: "spectrum mirrored or inverted in NOAMP txlp2", - 2480: "excessive power out of channel in NOAMP txlp2", - 521: "Excessive TX DC offset in AMP txhp1", - 522: "insufficient signal strength in AMP txhp1", - 523: "AMP txhp1 clipping", - 525: "peak found at unexpected frequency in AMP txhp1", - 530: "harmonics detected in AMP txhp1", - 535: "neighbor magnitude exceeded in AMP txhp1", - 540: "neighbor magnitude exceeded in AMP txhp1", - 545: "spectrum mirrored or inverted in AMP txhp1", - 550: "excessive power out of channel in AMP txhp1", - 551: "Excessive TX DC offset in NOAMP txhp1", - 552: "insufficient signal strength in NOAMP txhp1", - 553: "NOAMP txhp1 clipping", - 555: "peak found at unexpected frequency in NOAMP txhp1", - 560: "harmonics detected in NOAMP txhp1", - 565: "neighbor magnitude exceeded in NOAMP txhp1", - 570: "neighbor magnitude exceeded in NOAMP txhp1", - 575: "spectrum mirrored or inverted in NOAMP txhp1", - 580: "excessive power out of channel in NOAMP txhp1", - 621: "Excessive TX DC offset in AMP rxbp1", - 622: "insufficient signal strength in AMP rxbp1", - 623: "AMP rxbp1 clipping", - 625: "peak found at unexpected frequency in AMP rxbp1", - 630: "harmonics detected in AMP rxbp1", - 635: "neighbor magnitude exceeded in AMP rxbp1", - 640: "neighbor magnitude exceeded in AMP rxbp1", - 645: "spectrum mirrored or inverted in AMP rxbp1", - 650: "excessive power out of channel in AMP rxbp1", - 651: "Excessive TX DC offset in NOAMP rxbp1", - 652: "insufficient signal strength in NOAMP rxbp1", - 653: "NOAMP rxbp1 clipping", - 655: "peak found at unexpected frequency in NOAMP rxbp1", - 660: "harmonics detected in NOAMP rxbp1", - 665: "neighbor magnitude exceeded in NOAMP rxbp1", - 670: "neighbor magnitude exceeded in NOAMP rxbp1", - 675: "spectrum mirrored or inverted in NOAMP rxbp1", - 680: "excessive power out of channel in NOAMP rxbp1", - 721: "Excessive TX DC offset in AMP rxlp1", - 722: "insufficient signal strength in AMP rxlp1", - 723: "AMP rxlp1 clipping", - 725: "peak found at unexpected frequency in AMP rxlp1", - 730: "harmonics detected in AMP rxlp1", - 735: "neighbor magnitude exceeded in AMP rxlp1", - 740: "neighbor magnitude exceeded in AMP rxlp1", - 745: "spectrum mirrored or inverted in AMP rxlp1", - 750: "excessive power out of channel in AMP rxlp1", - 751: "Excessive TX DC offset in NOAMP rxlp1", - 752: "insufficient signal strength in NOAMP rxlp1", - 753: "NOAMP rxlp1 clipping", - 755: "peak found at unexpected frequency in NOAMP rxlp1", - 760: "harmonics detected in NOAMP rxlp1", - 765: "neighbor magnitude exceeded in NOAMP rxlp1", - 770: "neighbor magnitude exceeded in NOAMP rxlp1", - 775: "spectrum mirrored or inverted in NOAMP rxlp1", - 780: "excessive power out of channel in NOAMP rxlp1", - 2721: "Excessive TX DC offset in AMP rxlp2", - 2722: "insufficient signal strength in AMP rxlp2", - 2723: "AMP rxlp2 clipping", - 2725: "peak found at unexpected frequency in AMP rxlp2", - 2730: "harmonics detected in AMP rxlp2", - 2735: "neighbor magnitude exceeded in AMP rxlp2", - 2740: "neighbor magnitude exceeded in AMP rxlp2", - 2745: "spectrum mirrored or inverted in AMP rxlp2", - 2750: "excessive power out of channel in AMP rxlp2", - 2751: "Excessive TX DC offset in NOAMP rxlp2", - 2752: "insufficient signal strength in NOAMP rxlp2", - 2753: "NOAMP rxlp2 clipping", - 2755: "peak found at unexpected frequency in NOAMP rxlp2", - 2760: "harmonics detected in NOAMP rxlp2", - 2765: "neighbor magnitude exceeded in NOAMP rxlp2", - 2770: "neighbor magnitude exceeded in NOAMP rxlp2", - 2775: "spectrum mirrored or inverted in NOAMP rxlp2", - 2780: "excessive power out of channel in NOAMP rxlp2", - 821: "Excessive TX DC offset in AMP rxhp1", - 822: "insufficient signal strength in AMP rxhp1", - 823: "AMP rxhp1 clipping", - 825: "peak found at unexpected frequency in AMP rxhp1", - 830: "harmonics detected in AMP rxhp1", - 835: "neighbor magnitude exceeded in AMP rxhp1", - 840: "neighbor magnitude exceeded in AMP rxhp1", - 845: "spectrum mirrored or inverted in AMP rxhp1", - 850: "excessive power out of channel in AMP rxhp1", - 851: "Excessive TX DC offset in NOAMP rxhp1", - 852: "insufficient signal strength in NOAMP rxhp1", - 853: "NOAMP rxhp1 clipping", - 855: "peak found at unexpected frequency in NOAMP rxhp1", - 860: "harmonics detected in NOAMP rxhp1", - 865: "neighbor magnitude exceeded in NOAMP rxhp1", - 870: "neighbor magnitude exceeded in NOAMP rxhp1", - 875: "spectrum mirrored or inverted in NOAMP rxhp1", - 880: "excessive power out of channel in NOAMP rxhp1", - 3000: "BP TX failure", - 3010: "BP RX failure", - 3020: "HP TX failure", - 3030: "HP RX failure", - 3040: "LP TX failure", - 3050: "LP RX failure", - 3060: "TX AMP failure", - 3070: "RX AMP failure", - 3080: "AMP bypass failure", - 3090: "LPF failure", - 3100: "HPF failure", - 3110: "mixer bypass failure", - 3120: "mixer failure", - 3130: "TX failure", - 3140: "RX failure", - 3150: "mixer TX failure", - 3160: "mixer RX failure", - 3170: "LP2 TX failure", - 3180: "LP2 RX failure", - 3190: "LP2 TX/RX failure", - 3200: "total RF failure", - 3210: "multiple RF failures, see list above", - 3220: "multiple clipping failures", - 3230: "TX clipping failure", - 3240: "RX clipping failure" -} - -def fail_rf(errors): - # check for combinations of RF errors - ecode = 0 - eset = set(errors) - - # error affects only bp tx - if ((322 in eset) and (422 not in eset) and (2422 not in eset) and (522 not in eset) and (622 not in eset) and (722 not in eset) and (2722 not in eset) and (822 not in eset)): - ecode = 3000 - errors.append(ecode) - - # error affects only bp rx - if ((322 not in eset) and (422 not in eset) and (2422 not in eset) and (522 not in eset) and (622 in eset) and (722 not in eset) and (2722 not in eset) and (822 not in eset)): - ecode = 3010 - errors.append(ecode) - - # error affects only hp tx - if ((322 not in eset) and (422 not in eset) and (2422 not in eset) and (522 in eset) and (622 not in eset) and (722 not in eset) and (2722 not in eset) and (822 not in eset)): - ecode = 3020 - errors.append(ecode) - - # error affects only hp rx - if ((322 not in eset) and (422 not in eset) and (2422 not in eset) and (522 not in eset) and (622 not in eset) and (722 not in eset) and (2722 not in eset) and (822 in eset)): - ecode = 3030 - errors.append(ecode) - - # error affects only lp tx (both lp1 and lp2) - if ((322 not in eset) and (422 in eset) and (2422 in eset) and (522 not in eset) and (622 not in eset) and (722 not in eset) and (2722 not in eset) and (822 not in eset)): - ecode = 3040 - errors.append(ecode) - - # error affects only lp rx (both lp1 and lp2) - if ((322 not in eset) and (422 not in eset) and (2422 not in eset) and (522 not in eset) and (622 not in eset) and (722 in eset) and (2722 in eset) and (822 not in eset)): - ecode = 3050 - errors.append(ecode) - - # error in tx amp path - if ((2422 in eset) and (352 not in eset) and (452 not in eset) and (2452 not in eset)): - ecode = 3060 - errors.append(ecode) - - # error in rx amp path - if ((2722 in eset) and (652 not in eset) and (752 not in eset) and (2752 not in eset)): - ecode = 3070 - errors.append(ecode) - - # error in amp bypass path - if ((352 in eset) and (452 in eset) and (2452 in eset) and (652 in eset) and (752 in eset) and (2752 in eset) and (322 not in eset) and (422 not in eset) and (2422 not in eset) and (622 not in eset) and (722 not in eset) and (2722 not in eset)): - ecode = 3080 - errors.append(ecode) - - # error in lpf path - if (((422 in eset) and (2422 in eset)) and ((722 in eset) and (2722 in eset)) and ((322 not in eset) and (622 not in eset)) and ((522 not in eset) and (822 not in eset))): - ecode = 3090 - errors.append(ecode) - - # error in hpf path - if (((522 in eset) and (822 in eset)) and ((322 not in eset) and (622 not in eset)) and ((422 not in eset) and (2422 not in eset) and (722 not in eset) and (2722 not in eset))): - ecode = 3100 - errors.append(ecode) - - # error affects both mixer bypass paths - if ((322 in eset) and (422 not in eset) and (2422 not in eset) and (522 not in eset) and (622 in eset) and (722 not in eset) and (2722 not in eset) and (822 not in eset)): - ecode = 3110 - errors.append(ecode) - - # error in mixer tx/rx - if ((322 not in eset) and ((422 in eset) or (2422 in eset)) and (522 in eset) and (622 not in eset) and ((722 in eset) or (2722 in eset) or (822 in eset))): - ecode = 3120 - errors.append(ecode) - - if ((322 not in eset) and ((422 in eset) or (2422 in eset) or (522 in eset)) and (622 not in eset) and ((722 in eset) and (2722 in eset) and (822 in eset))): - ecode = 3120 - errors.append(ecode) - - # error in all tx, no rx - if ((322 in eset) and (422 in eset) and (2422 in eset) and (522 in eset) and (622 not in eset) and (722 not in eset) and (2722 not in eset) and (822 not in eset) and (352 in eset) and (452 in eset) and (2452 in eset) and (552 in eset)): - ecode = 3130 - errors.append(ecode) - - # error in all rx, no tx - if ((322 not in eset) and (422 not in eset) and (2422 not in eset) and (522 not in eset) and (622 in eset) and (722 in eset) and (2722 in eset) and (822 in eset) and (652 in eset) and (752 in eset) and (2752 in eset) and (852 in eset)): - ecode = 3140 - errors.append(ecode) - - # error in all mixer tx - if ((322 not in eset) and (422 in eset) and (2422 in eset) and (522 in eset) and (622 not in eset) and (722 not in eset) and (2722 not in eset) and (822 not in eset)): - ecode = 3150 - errors.append(ecode) - - # error in all mixer rx - if ((322 not in eset) and (422 not in eset) and (2422 not in eset) and (522 not in eset) and (622 not in eset) and (722 in eset) and (2722 in eset) and (822 in eset)): - ecode = 3160 - errors.append(ecode) - - # error affecting only lp2 tx - if ((322 not in eset) and (422 not in eset) and (2422 in eset) and (522 not in eset) and (622 not in eset) and (722 not in eset) and (2722 not in eset) and (822 not in eset) and (2752 in eset)): - ecode = 3170 - errors.append(ecode) - - # error affecting only lp2 rx - if ((322 not in eset) and (422 not in eset) and (2422 not in eset) and (522 not in eset) and (622 not in eset) and (722 not in eset) and (2722 in eset) and (822 not in eset) and (2752 in eset)): - ecode = 3180 - errors.append(ecode) - - # error affecting only lp2 rx/tx - if ((322 not in eset) and (422 not in eset) and (2422 in eset) and (522 not in eset) and (622 not in eset) and (722 not in eset) and (2722 in eset) and (822 not in eset)): - ecode = 3190 - errors.append(ecode) - - # error in all rx/tx - if ((322 in eset) and (422 in eset) and (2422 in eset) and (522 in eset) and (622 in eset) and (722 in eset) and (2722 in eset) and (822 in eset)): - ecode = 3200 - errors.append(ecode) - - # If there are clipping failures, we can't trust the other RF results, so fail(). - tx_clipping_count = 0 - rx_clipping_count = 0 - for code in (323, 353, 423, 453, 2423, 2453, 523, 553): - if code in eset: - tx_clipping_count += 1 - for code in (623, 653, 723, 753, 2723, 2753, 823, 853): - if code in eset: - rx_clipping_count += 1 - if tx_clipping_count > 1 and rx_clipping_count == 0: - fail(3230) - elif tx_clipping_count == 0 and rx_clipping_count > 1: - fail(3240) - elif tx_clipping_count > 0 and rx_clipping_count > 0: - fail(3220) - - elif (not ecode) and (len(errors) > 1): - # multiple failures without a logical grouping - ecode = 3210 - errors.append(ecode) - - for error in errors[:-1]: - out(f"RF failure {error}: {emessages[error]}") - fail(errors[-1]) - -def log(message=""): - if args.log: - with open(args.log, "a") as log_file: - print(message, file=log_file) - return - -def out(message=""): - log(message) - print(message) - -def fail(error_code): - out(f"FAIL {error_code}: {emessages[error_code]}") - sys.exit(2) - -class HackRF: - def __init__(self, name, bin_dir, serial, mf_check, id=None, revision=None, unique_bin=False, factory_test=False): - self.name = name - self.bin_dir = bin_dir - self.unique_bin = unique_bin - self.id = None - self.revision = None - self.serial = None - self.clkout_connected = False - self.tester_cal = [0] * 16 - self.eut_cal = [0] * 16 - self.errors = [] - self.unit_number = 0 - self.partner = None - - if self.name == "TESTER": - self.unit_number = 1 - elif self.name == "EUT": - self.rf_test_cases = praline_rf_test_cases - else: - fail(99) - - info = subprocess.run([bin_dir + "/hackrf_info"], capture_output=True, - encoding="utf-8", timeout=TIMEOUT) - log(info.stdout + info.stderr) - if info.returncode != 0 or "failed" in info.stderr: - fail(87) - - # parse the hackrf_info output - count = info.stdout.count("Found HackRF") - if count < 1: - fail(92) - if count > 1 and self.name == "TESTER" and self.unique_bin: - fail(83) - if mf_check and "does not appear to have been manufactured by Great Scott Gadgets" in info.stdout: - fail(90 + self.unit_number) - - try: - sn = "" - devices_list = [d.strip() for d in info.stdout.split("Found HackRF") if d.strip()] - for device in devices_list: - sn_found = re.search(r'Serial number: \w+', device) - if sn_found: - sn = sn_found.group(0).split(': ')[1] - - id_found = re.search(r'Board ID Number: .', device) - if id_found: - id = id_found.group(0).split(': ')[1] - - rev_found = re.search(r'Hardware Revision: .+', device) - if rev_found: - rev = rev_found.group(0).split(': ')[1] - - if sn == serial: - self.serial = sn - self.id = id - self.revision = rev - break - - out(f"{self.name} Serial number: {self.serial}") - out(f"{self.name} Board ID: {self.id}") - out(f"{self.name} Hardware Revision: {self.revision}") - out(f"{self.name} binary directory {self.bin_dir}") - except: - out(traceback.format_exc()) - fail(6) - - if self.serial == None: - fail(80 + self.unit_number) - - if self.name == "TESTER" and factory_test and (self.id != "2" and self.id != "4"): - fail(8) - elif self.name == "EUT" and factory_test and self.id != "5": - fail(9) - - if revision and self.revision != revision: - fail(88 + self.unit_number) - - if self.revision == "r9": - self.tester_cal = r9_tester_cal - self.eut_cal = r9_eut_cal - else: - self.tester_cal = og_tester_cal - self.eut_cal = og_eut_cal - - if self.name == "EUT" and self.id == "5" and self.revision == "r1.1": - self.rf_test_cases = praline_r110_rf_test_cases - - def clkin(self): - command = subprocess.run([self.bin_dir + "/hackrf_clock", "-i", "-d", - self.serial], capture_output=True, encoding="utf-8", - timeout=TIMEOUT) - if command.returncode != 0: - log(command.stdout + command.stderr) - out(f"{self.name} CLKIN request failed") - fail(200) - if "no clock signal detected" in command.stdout: - log(f"{self.name}: no clock signal detected") - return False - elif "clock signal detected" in command.stdout: - log(f"{self.name}: clock signal detected") - return True - else: - log(command.stdout + command.stderr) - out(f"Couldn't parse {self.name} CLKIN status") - fail(200) - - # Warning: Avoid clock loops by disabling your partner's CLKOUT before - # enabling your own. - def clkout(self, enable): - command = subprocess.run([self.bin_dir + "/hackrf_clock", "-o", - "1" if enable else "0", "-d", self.serial], capture_output=True, - encoding="utf-8", timeout=TIMEOUT) - if command.returncode != 0: - log(command.stdout + command.stderr) - out(f"{self.name} CLKOUT control failed") - fail(200) - - if self.partner and self.clkout_connected: - timeout = time.time() + 1 - while time.time() < timeout: - if self.partner.clkin() == enable: - break - if self.partner.clkin() != enable: - if enable: - fail(210 + self.unit_number) - else: - if self.name == "EUT": - out("Note: use --tcxo to use TCXO or external reference on TESTER") - fail(212 + self.unit_number) - - # transceiver operation to switch clock source - source = "CLKIN" if enable else "crystal" - log(f"switching {self.partner.name} to {source}") - receive = subprocess.run([self.partner.bin_dir + "/hackrf_transfer", "-d", - self.partner.serial, "-n1", "-r", "/dev/null", "-f", "2500000000", - "-a", "0", "-l", "0", "-g", "0"], capture_output=True, - encoding="utf-8", timeout=TIMEOUT) - if receive.returncode != 0: - log(receive.stdout + receive.stderr) - fail(220 + self.unit_number) - - # confirm that PLL A locked to new source - timeout = time.time() + 1 - while time.time() < timeout: - debug = subprocess.run([self.partner.bin_dir + "/hackrf_debug", "-d", - self.partner.serial, "-srn0"], capture_output=True, - encoding="utf-8", timeout=TIMEOUT) - log(debug.stdout) - if debug.returncode != 0: - log(debug.stderr) - fail(230 + self.unit_number) - output = str(debug.stdout).split() - try: - val = int(output[3], 0) - except: - log(debug.stderr) - log(traceback.format_exc()) - fail(230 + self.unit_number) - # Check LOL_A - if not (val >> 5) & 1: - break - if (val >> 5) & 1: - fail(232 + self.unit_number) - time.sleep(0.1) - else: - time.sleep(0.2) - - def test_clkout(self): - assert self.clkout_connected - self.partner.clkout(False) - self.clkout(True) - frequency_error_ppm = self.clock_error_ppm() - log(f"{self.name}->{self.partner.name} CLK: {frequency_error_ppm} ppm") - if abs(frequency_error_ppm) > 1: - out(f"{self.partner.name} CLKIN: unexpected frequency error while synchronized") - fail(240) - - def test_clkin(self): - self.partner.test_clkout() - - def clock_error_ppm(self): - # ppm.freq is in MHz, but we use it as Hz for the FFT bin width, - # resulting in bins with a width of 1 ppm of the transmission - # frequency. - bin_width = str(ppm.freq) - tx_frequency = str(ppm.freq * ONE_MHZ) - sweep_range = f"{ppm.freq-1}:{ppm.freq+19}" - expected_bin = round(ONE_MHZ/ppm.freq) - - log(f"{self.name} transmitting to {self.partner.name} for PPM measurement") - transmit = subprocess.Popen([self.bin_dir + "/hackrf_transfer", "-d", - self.serial, "-c", "127", "-a", "0", "-x", f"{ppm.tx_gain}", "-f", - tx_frequency], stdout=subprocess.PIPE, stderr=subprocess.PIPE, - encoding="utf-8") - - time.sleep(SLEEP_TIME) - sweep = subprocess.run([self.partner.bin_dir + "/hackrf_sweep", "-d", - self.partner.serial, "-N", "13", "-w", bin_width, "-f", sweep_range, "-a", - "0", "-l", f"{ppm.rx_lna_gain}", "-g", f"{ppm.rx_vga_gain}"], - capture_output=True, encoding="utf-8", timeout=TIMEOUT) - if sweep.returncode != 0: - log(sweep.stdout + sweep.stderr) - fail(250) - - # parse the hackrf_sweep output - try: - rows = sweep.stdout.split("\n") - # Note: skipping data from the first twelve sweeps until issue #1230 is resolved. - row = rows[48].split(", ") - bins = [float(bin) for bin in row[6:]] - peak_bin = bins.index(max(bins)) - frequency_error_ppm = peak_bin - expected_bin - except: - log(sweep.stdout + sweep.stderr) - log(traceback.format_exc()) - fail(252) - - log(f"PPM max bin {peak_bin} power: {bins[peak_bin]}") - for row in rows[0:49:4]: - bins = [float(bin) for bin in row.split(", ")[6:]] - peak_bin = bins.index(max(bins)) - log(f"peak bin {peak_bin}: {bins[peak_bin]}") - if max(bins) < SIGNAL_THRESHOLD: - fail(254 + self.unit_number) - transmit.terminate() - tx_out, tx_err = transmit.communicate(timeout=TIMEOUT) - if transmit.returncode != 0: - log(tx_out + tx_err) - out(f"Warning: {self.name} PPM test transmit failed") - return frequency_error_ppm - - def test_xtal(self): - self.clkout(False) - self.partner.clkout(False) - frequency_error_ppm = self.clock_error_ppm() - out(f"{self.name} crystal frequency error: {frequency_error_ppm} ppm") - if abs(frequency_error_ppm) > MAX_PPM: - fail(260) - - def verify_register(self, target, address, value): - command = subprocess.run([self.bin_dir + "/hackrf_debug", - f"--{target}", "--register", address, "--read", "--device", - self.serial], capture_output=True, encoding="UTF-8") - log(f"Checking {target} register {address}") - if value in command.stdout: - return True - else: - log("Unexpected result:") - log(command.stdout + command.stderr) - return False - - def test_clkgen(self): - if not self.verify_register("si5351", "2", "0x03"): - fail(100 + self.unit_number) - - def test_mixer(self): - if not self.verify_register("rffc5072", "2", "0x9055"): - fail(140 + self.unit_number) - - def test_xcvr(self): - if not self.verify_register("max283", "28", "0x0c0"): - fail(120 + self.unit_number) - - def test_serial(self): - log(f"Testing {self.name} serial communications") - self.test_clkgen() - self.test_mixer() - self.test_xcvr() - - # Ensure that hackrf_transfer works and that the received power is within - # the expected range with no transmission active. - def baseline_rx(self, test_case): - # Test at the TX tuning frequency of measure_rf() - center_freq = (test_case.freq * ONE_MHZ) + 1500000 - receive = subprocess.run([self.bin_dir + "/hackrf_transfer", "-d", - self.serial, "-n10000", "-r", "/dev/null", "-f", - f"{center_freq}", "-a", "0", "-l", f"{test_case.rx_lna_gain}", - "-g", f"{test_case.rx_vga_gain}", "-b", - "1750000"], capture_output=True, encoding="utf-8", timeout=TIMEOUT) - if receive.returncode != 0: - log(receive.stdout + receive.stderr) - log(f"Failed {self.name} {test_case.name} baseline RX") - fail(300) - - output = str(receive.stderr).split() - try: - power = float(output[output.index("power") + 1]) - except: - log(receive.stdout + receive.stderr) - log(traceback.format_exc()) - log(f"Couldn't parse {self.name} {test_case.name} baseline RX power") - fail(302) - # The theoretical minimum power is about -48 dB. The expected power is - # about -30 dB. - log(f"{self.name} {test_case.name} baseline power: {power}") - if power > MAX_BASELINE: - fail(306) - - # Check the ADC for shorts or other unexpected behavior by sampling - # amplified noise. - def noise_rx(self, test_case): - num_samples = 1000 - log(f"Testing {self.name} {test_case.name}") - center_freq = test_case.freq * ONE_MHZ - - low_gain = 0 - high_gain = 16 - while high_gain > low_gain: - gain = (high_gain + low_gain) // 2 - receive = subprocess.run([self.bin_dir + "/hackrf_transfer", "-d", - self.serial, "-n", f"{num_samples*10}", "-r", f"{NOISE}", "-f", - f"{center_freq}", "-a", "1" if test_case.amp else "0", "-l", - f"{test_case.rx_lna_gain}", "-g", f"{gain*2 + 32}", "-b", - "28000000"], capture_output=True, encoding="utf-8", timeout=TIMEOUT) - if receive.returncode != 0: - log(receive.stdout + receive.stderr) - fail(310) - output = str(receive.stderr).split() - try: - power = float(output[output.index("power") + 1]) - except: - log(receive.stdout + receive.stderr) - log(traceback.format_exc()) - fail(311) - log(f"{self.name} {test_case.name} RX power at -g {gain*2 + 32}: {power}") - if power > -2: - high_gain = gain - elif power > -5: - break - else: - low_gain = gain + 1 - - # We want the power to be between -1 and -9 dB to ensure that all eight - # bits are flipped without much clipping. - if power < -9 or power > -1: - fail(312) - elif gain > 16 or gain < 4: - fail(313) - - bit_count = [0] * 8 - matches = [] - for bit in range(8): - matches.append([0] * 8) - - try: - file = open(f"{NOISE}", "rb") - data = file.read() - assert len(data) == num_samples * 20 - data = data[-num_samples*2:] - for byte in data: - for bit in range(8): - bit_count[bit] += (byte>>bit)&1 - for match_bit in range(bit + 1, 8): - if (byte>>bit)&1 == (byte>>match_bit)&1: - matches[bit][match_bit] += 1 - except: - fail(315) - log(f"{self.name} ADC bit counts: {bit_count}") - log(f"{self.name} ADC bit matches: {matches}") - for bit in range(7): - if bit_count[bit] < (0.2 * len(data)) or bit_count[bit] > (0.8 * len(data)): - log(f"{self.name} ADC bit {bit} set in {bit_count[bit]} out of {len(data)} bytes") - fail(316) - # Check for correlations between adjacent bits except between 6 and 7 (highest). - #for match_bit in range(bit + 1, 7): - for match_bit in range(bit + 1, 8): - if matches[bit][match_bit] > (0.999 * len(data)): - out(f"{self.name} ADC bit {bit} correlates with bit {match_bit}") - fail(317) - # DC bias can cause bit 7 to be predominantly unchanged, so only - # error if there is less than 1% variation. - if bit_count[7] < (0.001 * len(data)) or bit_count[bit] > (0.999 * len(data)): - out(f"{self.name} ADC bit 7 set in {bit_count[7]} out of {len(data)} bytes") - fail(316) - - def analyze_transfer(self, transfer, test_case): - # parse the hackrf_transfer output - output = str(transfer.stderr).split() - try: - power = float(output[output.index("power") + 1]) - except: - log(transfer.stdout + transfer.stderr) - log(traceback.format_exc()) - fail(152) - log(f"{test_case.name} power at {test_case.freq} MHz: {power}") - - if test_case.base_ecode: - if power < SIGNAL_THRESHOLD: - log(f"{test_case.name} signal not strong enough") - self.errors.append(test_case.base_ecode + 2) - if power > -3: - log(f"{test_case.name} signal clipping") - self.errors.append(test_case.base_ecode + 3) - elif power < -48 or power > 0: - fail(154) - return power - - # Verify that signal power at a given IF in MHz is detected. - def verify_if_tuning(self, test_case): - transmit = subprocess.Popen([self.bin_dir + "/hackrf_transfer", "-d", - self.serial, "-c", "127", "-a", "0", "-x", f"{test_case.tx_gain}", - "-i", f"{test_case.freq*ONE_MHZ}", "-m", "0", "-F"], - stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding="utf-8") - - time.sleep(SLEEP_TIME) - receive = subprocess.run([self.partner.bin_dir + "/hackrf_transfer", "-d", - self.partner.serial, "-n10000", "-r", "/dev/null", "-f", - f"{(test_case.freq+1)*ONE_MHZ}", "-a", "0", "-l", - f"{test_case.rx_lna_gain}", "-g", f"{test_case.rx_vga_gain}", "-b", - "2500000"], capture_output=True, encoding="utf-8", timeout=TIMEOUT) - transmit.terminate() - if receive.returncode != 0: - log(receive.stdout + receive.stderr) - fail(150) - - power = self.analyze_transfer(receive, test_case) - - tx_out, tx_err = transmit.communicate(timeout=TIMEOUT) - if transmit.returncode != 0: - log(tx_out + tx_err) - out(f"Warning: {self.name} IF transmit failed") - return power > SIGNAL_THRESHOLD - - def test_if_range(self, min_case, max_case): - low_end = IF_REQUIRED_MIN - (IF_TEST_RANGE // 2) - min_freq = IF_REQUIRED_MIN + (IF_TEST_RANGE // 2) - while min_freq > low_end: - min_case.freq = (min_freq + low_end) // 2 - if self.verify_if_tuning(min_case): - min_freq = min_case.freq - else: - low_end = min_case.freq + 1 - - high_end = IF_REQUIRED_MAX + (IF_TEST_RANGE // 2) - max_freq = IF_REQUIRED_MAX - (IF_TEST_RANGE // 2) - while max_freq < high_end: - max_case.freq = (max_freq + high_end + 1) // 2 - if self.verify_if_tuning(max_case): - max_freq = max_case.freq - else: - high_end = max_case.freq - 1 - - out(f"{self.name} IF range: {min_freq}-{max_freq} MHz") - if min_freq > IF_REQUIRED_MIN or max_freq < IF_REQUIRED_MAX: - fail(160) - - def analyze_sweep(self, sweep, test_case): - eut_cal = self.eut_cal[self.rf_test_cases.index(test_case)] - tester_cal = self.partner.tester_cal[self.rf_test_cases.index(test_case)] - correction = LP2_CORRECTION if test_case.freq < 30 else 0 - - # parse the hackrf_sweep output - try: - rows = sweep.stdout.split("\n") - # Note: skipping data from the first twelve sweeps until issue #1230 is resolved. - bins = np.zeros(225) - # average 10 sweeps - row_count = 0 - for row in rows[48:88:4]: - bins += np.array([float(x) for x in row.split(", ")[6:231]]) - row_count += 1 - assert row_count == 10 - bins /= 10 - # log the raw hackrf_sweep data before calibration - log(f"{', '.join(rows[12].split(', ')[:6])}, {np.array2string(bins, separator=', ', max_line_width=3000)[1:-1]}") - # apply calibration - bins -= eut_cal - bins -= tester_cal - peak_bin = bins.argmax() - except: - log(sweep.stdout + sweep.stderr) - log(traceback.format_exc()) - out(f"Couldn't parse {test_case.name} sweep data") - fail(172) - - # ensure acceptable performance - log(f"peak ({peak_bin}) {test_case.name}: {bins[peak_bin]:.2f}") - if bins[peak_bin] < SIGNAL_THRESHOLD: - for row in rows[0:88:4]: - bins = [float(bin) for bin in row.split(", ")[6:]] - peak_bin = bins.index(max(bins)) - log(f"peak bin {peak_bin}: {bins[peak_bin]}") - log(f"{test_case.name} signal not strong enough") - self.errors.append(test_case.base_ecode + 2) - return bins[peak_bin] - elif bins[peak_bin] > MAX_POWER: - log(f"{test_case.name} signal clipping") - self.errors.append(test_case.base_ecode + 3) - return bins[peak_bin] - tx_dc_power_dbc = bins[112] - bins[peak_bin] - if tx_dc_power_dbc > MAX_DC_DBC + correction: - log(f"{test_case.name} excessive TX DC offset {tx_dc_power_dbc:.1f} dBc") - self.errors.append(test_case.base_ecode + 1) - if peak_bin == 157: - log(f"{test_case.name} TX spectrum inverted") - self.errors.append(test_case.base_ecode + 25) - return bins[peak_bin] - elif peak_bin == 112: - log(f"{test_case.name} peak found at DC") - self.errors.append(test_case.base_ecode + 1) - return bins[peak_bin] - elif peak_bin >= 52 and peak_bin < 67: - log(f"{test_case.name} peak found at adjacent frequency") - self.errors.append(test_case.base_ecode + 15) - return bins[peak_bin] - elif peak_bin > 67 and peak_bin <= 82: - log(f"{test_case.name} peak found at adjacent frequency") - self.errors.append(test_case.base_ecode + 20) - return bins[peak_bin] - elif peak_bin != 67: - log(f"{test_case.name} peak found at unexpected frequency") - self.errors.append(test_case.base_ecode + 5) - return bins[peak_bin] - - if bins[157] - bins[67] > MAX_M_DBC + correction: - log(f"{test_case.name} TX spectrum mirrored") - self.errors.append(test_case.base_ecode + 25) - if (bins[22] - bins[67]) > MAX_H2_DBC + correction: - log(f"{test_case.name} excessive TX harmonic (bin 22): {bins[22]}") - self.errors.append(test_case.base_ecode + 10) - if (bins[202] - bins[67]) > MAX_MH2_DBC + correction: - log(f"{test_case.name} excessive TX harmonic (bin 202): {bins[202]}") - self.errors.append(test_case.base_ecode + 10) - worst_other_dbc = -999 - worst_other_bin = 999 - for i in range(225): - # Skip various frequencies where spurs are expected (most of which have their own tests above). - if (i < 52 and i != 22) or (i > 82 and i < 111) or (i > 113 and i < 156) or (i > 158 and i != 202): - other_dbc = bins[i] - bins[67] - if other_dbc > worst_other_dbc: - worst_other_dbc = other_dbc - worst_other_bin = i - if worst_other_dbc > MAX_OTHER_DBC + correction: - log(f"{test_case.name} excessive power at unexpected frequency ({worst_other_bin}: {bins[worst_other_bin]})") - self.errors.append(test_case.base_ecode + 30) - log(f"h2 (22) {test_case.name}: {(bins[22] - bins[67]):.2f}") - log(f"DC (112) {test_case.name}: {(bins[112] - bins[67]):.2f}") - log(f"m (157) {test_case.name}: {(bins[157] - bins[67]):.2f}") - log(f"mh2 (202) {test_case.name}: {(bins[202] - bins[67]):.2f}") - log(f"other ({worst_other_bin}) {test_case.name}: {worst_other_dbc:.2f}") - #FIXME look in another row for RX inversion? - return bins[peak_bin] - - def measure_rf(self, test_case, sweep=True): - log(f"Executing RF test case {test_case.name}, sweep={sweep}") - if test_case.direction == "tx": - transmitter = self - tx_amp = "1" if test_case.amp else "0" - receiver = self.partner - rx_amp = "0" - elif test_case.direction == "rx": - transmitter = self.partner - tx_amp = "0" - receiver = self - rx_amp = "1" if test_case.amp else "0" - else: - out(f"Error: Invalid direction in {test_case.name}") - sys.exit(1) - - # The nominal test frequency (as specified in test_case) is 1 MHz above - # the low end of the sweep range. The transmitted signal is 500 kHz - # above the nominal frequency, and the tuning (center) frequency of the - # transmitting device is 1 MHz above that. - tx_center_freq = (test_case.freq * ONE_MHZ) + 1500000 - sweep_range = f"{test_case.freq-1}:{test_case.freq+19}" - - transmit = subprocess.Popen([transmitter.bin_dir + "/hackrf_transfer", "-d", - transmitter.serial, "-R", "-t", WAVEFORM, "-a", tx_amp, "-x", - f"{test_case.tx_gain}", "-f", str(tx_center_freq)], - stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding="utf-8") - - time.sleep(SLEEP_TIME) - if sweep: - receive = subprocess.run([receiver.bin_dir + "/hackrf_sweep", - "-d", receiver.serial, "-N", "22", "-w", "22222", "-f", - sweep_range, "-a", rx_amp, "-l", f"{test_case.rx_lna_gain}", - "-g", f"{test_case.rx_vga_gain}"], capture_output=True, - encoding="utf-8", timeout=TIMEOUT) - else: - receive = subprocess.run([receiver.bin_dir + "/hackrf_transfer", - "-d", receiver.serial, "-n10000", "-r", "/dev/null", "-f", - f"{(test_case.freq)*ONE_MHZ}", "-a", rx_amp, "-l", - f"{test_case.rx_lna_gain}", "-g", f"{test_case.rx_vga_gain}", - "-b", "2500000"], capture_output=True, encoding="utf-8", - timeout=TIMEOUT) - transmit.terminate() - if receive.returncode != 0: - log(receive.stdout + receive.stderr) - log(f"{receiver.name} Failed RX, sweep={sweep}") - fail(170) - - if sweep: - rssi = self.analyze_sweep(receive, test_case) - else: - rssi = self.analyze_transfer(receive, test_case) - - tx_out, tx_err = transmit.communicate(timeout=TIMEOUT) - if transmit.returncode != 0: - out(tx_out + tx_err) - out(f"Warning: {transmitter.name} transmit failed") - return rssi - - def test_rf_preliminary(self): - results = [] - - for test_case in (self.rf_test_cases): - if test_case.amp == False: - if test_case.direction == "rx": - self.baseline_rx(test_case) - elif self.partner: - self.partner.baseline_rx(test_case) - - self.noise_rx(noise) - # FIXME test for RX DC offset? - - if not self.partner: - out("Skipping RF tests") - return - - for test_case in (self.rf_test_cases): - results.append(int(round(self.measure_rf(test_case, sweep=False) - (SIGNAL_THRESHOLD + 11)))) - - log(f"Preliminary results: {results}") - if self.errors: - fail_rf(self.errors) - - def test_rf(self): - assert self.partner - results = [] - - for test_case in (self.rf_test_cases): - results.append(int(round(self.measure_rf(test_case, sweep=True) - (SIGNAL_THRESHOLD + 5)))) - - out(f"RF results summary: {results}") - if self.errors: - fail_rf(self.errors) - - def activate_leds(self, enable): - if enable: - out(f"Activating {self.name} LEDs") - state = 7 - else: - state = 1 - # Always illuminate MCU LED on Praline. - if self.id == "5": - state |= 8 - command = subprocess.run([self.bin_dir + "/hackrf_debug", "-d", self.serial, "--leds", - f"{state}"], capture_output=True, encoding="utf-8", timeout=TIMEOUT) - if command.returncode != 0: - log(command.stdout + command.stderr) - log(f"Failed to configure {self.name} LEDs ({state})") - fail(190) - - def debug_selftest(self): - errors = [] - - debug = subprocess.run([self.bin_dir + "/hackrf_debug", "-to", "-d", self.serial], - capture_output=True, encoding="utf-8", timeout=TIMEOUT) - log(debug.stdout + debug.stderr) - - fpga_test_found = re.search(r'FPGA configuration: \w+', debug.stdout) - if fpga_test_found: - if fpga_test_found.group(0).split(': ')[-1] != "PASS": - errors.append(14) - else: - out("Failure to find FPGA configuration result. Wrong firmware version? Continuing...") - - # Check for FPGA SPI result only if FPGA configuration passed. - if len(errors) == 0: - sgpio_test_found = re.search(r'FPGA SPI: \w+', debug.stdout) - if sgpio_test_found: - if sgpio_test_found.group(0).split(': ')[-1] != "PASS": - errors.append(24) - else: - out("Failure to find FPGA SPI test result. Wrong firmware version? Continuing...") - - # Check for SGPIO result only if FPGA configuration and SPI passed. - if len(errors) == 0: - sgpio_test_found = re.search(r'SGPIO RX test: \w+', debug.stdout) - if sgpio_test_found: - if sgpio_test_found.group(0).split(': ')[-1] == "TIMEOUT": - errors.append(22) - elif sgpio_test_found.group(0).split(': ')[-1] == "FAIL": - errors.append(11) - else: - out("Failure to find sgpio test result. Wrong firmware version? Continuing...") - - # Check for loopback result only if FPGA, SPI, and SGPIO passed. - if len(errors) == 0: - loopback_test_found = re.search(r'Loopback test: \w+', debug.stdout) - if loopback_test_found: - if loopback_test_found.group(0).split(': ')[-1] == "TIMEOUT": - errors.append(23) - elif loopback_test_found.group(0).split(': ')[-1] == "FAIL": - errors.append(12) - else: - out("Failure to find loopback test result. Wrong firmware version? Continuing...") - - clock_found = re.search(r'Clock: \w+, \w+: \d, readback: \w+', debug.stdout) - if clock_found: - if clock_found.group(0).split(': ')[-1] != "OK": - errors.append(10) - else: - out("Failure to find clock results. Wrong firmware version? Continuing...") - - mixer_found = re.search(r'Mixer: \w+, ID: \d+', debug.stdout) - if mixer_found: - if mixer_found.group(0).split(': ')[-1] != "4416": - errors.append(16) - else: - out("Failure to find mixer results. Wrong firmware version? Continuing...") - - # Check for transceiver result only if FPGA configuration passed. - if 14 not in errors: - xcvr_found = re.search(r'Transceiver: \w+, RSSI mux test: \w+', debug.stdout) - if xcvr_found: - if xcvr_found.group(0).split(': ')[-1] != "PASS": - errors.append(17) - else: - out("Failure to find transceiver results. Wrong firmware version? Continuing...") - - rtc_found = re.search(r'RTC test result: \w+', debug.stdout) - if rtc_found: - if rtc_found.group(0).split(': ')[-1] != "PASS": - errors.append(18) - else: - out("Failure to find 32kHz oscillator results. Wrong firmware version? Continuing...") - - # Provide entire self-test report if there is an unrecognized self-test failure - if len(errors) == 0: - selftest_found = re.search(r'Self-test result: \w+', debug.stdout) - if selftest_found: - if selftest_found.group(0).split(': ')[-1] != "PASS": - out(debug.stdout) - fail(13) - else: - out("Failure to find selftest results. Wrong firmware version? Continuing...") - - # Report multiple self-test failures - if len(errors) > 1: - for error in errors: - out(f"Self-test failure {error}: {emessages[error]}") - fail(15) - - if len(errors) > 0: - fail(errors[-1]) - - def reset(self): - out(f"Resetting {self.name}") - spiflash = subprocess.run([self.bin_dir + "/hackrf_spiflash", "-d", self.serial, "-R"], - capture_output=True, encoding="utf-8", timeout=TIMEOUT) - if spiflash.returncode != 0: - out(spiflash.stdout + spiflash.stderr) - fail(76 + self.unit_number) - - then = time.time() - device_found = False - while time.time() < (then + 5): - time.sleep(1) - info = subprocess.run([self.bin_dir + "/hackrf_info"], - capture_output=True, timeout=TIMEOUT) - if self.serial in info.stdout.decode('utf-8', errors='ignore'): - device_found = True - break - time.sleep(0.1) - if not device_found: - fail(78 + self.unit_number) - - -# This waveform is a full-scale complex exponential with a frequency of -1/10 the -# sample rate. When transmitted at 10 Msps, the frequency is 1 MHz below the -# center frequency. - -def write_waveform(): - tx_bytes = b'\x7f\x00\x67\xb5\x27\x87\xd9\x87\x99\xb5\x81\x00\x99\x4b\xd9\x79\x27\x79\x67\x4b' - # defective waveform with DC offset: - #tx_bytes = b'\x7f\x10\x67\xa5\x27\x97\xd9\x97\x99\xc5\x81\x10\x99\x5b\xd9\x7f\x27\x7f\x67\x5b' - # defective waveform with missing Q channel: - #tx_bytes = b'\x7f\x00\x67\x00\x27\x00\xd9\x00\x99\x00\x81\x00\x99\x00\xd9\x00\x27\x00\x67\x00' - with open(WAVEFORM, "wb") as bin_file: - for i in range(50000): # 1MB file size - bin_file.write(tx_bytes) - - -def program(bin_dir, fw_dir, serial, unattended=False): - binary = "hackrf_usb.bin" - dfu_stub = "hackrf_usb.dfu" - - # EUTs in unattended (including Jenkins CI) setups have pins jumped to always boot into DFU mode, so resetting is undesirable - if unattended: - reset_write = "-w" - else: - reset_write = "-Rw" - - if not usb.core.find(idVendor=DFU_VENDOR_ID, idProduct=DFU_PRODUCT_ID): - print("ACTION REQUIRED: Press and release EUT RESET button while holding DFU button.") - while not usb.core.find(idVendor=DFU_VENDOR_ID, idProduct=DFU_PRODUCT_ID): - time.sleep(0.1) - - out("Programming EUT in DFU mode") - dfu = subprocess.run([f"{DFU_UTIL}", "--device", - f"{DFU_VENDOR_ID}:{DFU_PRODUCT_ID}", "--alt", "0", "--download", - f"{fw_dir}/{dfu_stub}"], capture_output=True, encoding="utf-8", - timeout=TIMEOUT) - out(dfu.stdout + dfu.stderr) - - #dfu-util: unable to read DFU status after completion (LIBUSB_ERROR_IO) - # despite successful download; present as of at least dfu-util 0.11 - if "Download done." not in dfu.stdout: - fail(60) - - # Wait for device to boot from DFU. - then = time.time() - dfu_device_found = False - while time.time() < (then + 50): - dfu_info = subprocess.run([bin_dir + "/hackrf_info"], capture_output=True, - encoding="utf-8", timeout=TIMEOUT) - - if "RunningFromRAM" in dfu_info.stdout: - if serial in dfu_info.stdout and serial != "RunningFromRAM": - fail(1) - else: - dfu_device_found = True - break - time.sleep(0.1) - if not dfu_device_found: - fail(2) - - out("Programming EUT SPI flash") - spiflash = subprocess.run([bin_dir + "/hackrf_spiflash", "-d", - "RunningFromRAM", reset_write, f"{fw_dir}/{binary}"], - capture_output=True, encoding="utf-8", timeout=TIMEOUT+20) - if spiflash.returncode != 0: - log(spiflash.stdout + spiflash.stderr) - fail(70) - time.sleep(3) - - then = time.time() - device_found = False - while time.time() < (then + 5): - flash_info = subprocess.run([bin_dir + "/hackrf_info"], capture_output=True, - timeout=TIMEOUT) - if serial == "RunningFromRAM" and not unattended: - try: - devices_list = [d.strip() for d in flash_info.stdout.decode('utf-8', errors='ignore').split("Found HackRF") if d.strip()] - for device in devices_list: - sn_found = re.search(r'Serial number: \w+', device) - if sn_found: - serial = sn_found.group(0).split(': ')[1] - except: - log(traceback.format_exc()) - fail(6) - if serial in flash_info.stdout.decode('utf-8', errors='ignore'): - device_found = True - break - time.sleep(1) - if not device_found: - fail(75) - - -def find_sn(name, bin_dir, factory_test, claimed_sns=[]): - while True: - sn_list = [] - info = subprocess.run([bin_dir + "/hackrf_info"], capture_output=True, - encoding="utf-8", timeout=TIMEOUT) - try: - sn = "" - devices_list = [d.strip() for d in info.stdout.split("Found HackRF") if d.strip()] - for device in devices_list: - sn_found = re.search(r'Serial number: \w+', device) - if sn_found: - new_sn = sn_found.group(0).split(': ')[1] - if new_sn not in claimed_sns: - sn_list.append(new_sn) - except: - log(traceback.format_exc()) - fail(6) - - if factory_test: - if len(sn_list) > 1: - fail(19) - elif len(sn_list) < 1: - if name == "TESTER": - fail(20) - elif name == "EUT": - fail(21) - else: - sn = sn_list[0] - break - else: - if len(sn_list) > 1: - out(f"\nPotential {name}(s) found:\n") - for i in range(len(sn_list)): - out(f"{i}: {sn_list[i]}") - choice = int(input(f"\nEnter the index of your target {name}s serial number: ")) - if 0 <= choice < len(sn_list): - sn = sn_list[choice] - break - else: - out("Incorrect choice, try again.") - elif len(sn_list) == 1: - sn = sn_list[0] - break - else: - fail(3) - return sn - - -def get_version(): - version = subprocess.run(["git", "log", "-n" "1", "--format=%h"], - capture_output=True, encoding="utf-8", timeout=TIMEOUT) - if version.returncode != 0: - return "2026.01.3+" - elif version.returncode == 0: - dirty = subprocess.run(["git", "status", "-s", "--untracked-files=no"], - capture_output=True, encoding="utf-8", timeout=TIMEOUT) - if dirty.stdout != "": - dirty_flag = "*" - else: - dirty_flag = "" - return f"git-{version.stdout.strip()}{dirty_flag}" - - -def main(): - - write_waveform() - - parser = argparse.ArgumentParser(description="Utility for testing HackRF One") - parser.add_argument("-c", "--noclk", action="store_true", help="skip CLKIN, CLKOUT, and PPM tests") - parser.add_argument("-i", "--noif", action="store_true", help="skip IF tuning range test") - parser.add_argument("-l", "--loop", action="store_true", help="repeat the test until terminated with ctrl-c") - parser.add_argument("-m", "--manufacturer", action="store_true", help="check the manufacturer of target devices") - parser.add_argument("-r", "--rev", metavar=" or \"any\"", type=str, - help="check EUT pin straps for specific hardware revision (default: \"r9\")", - default="r9") - parser.add_argument("-s", "--solo", action="store_true", help="perform limited tests on a single EUT with no TESTER") - parser.add_argument("-t", "--tcxo", action="store_true", help="skip CLKIN/CLKOUT tests and use TCXO instead") - parser.add_argument("-E", "--eut", metavar="", type=str, - help="EUT serial number") - parser.add_argument("-T", "--tester", metavar="", type=str, - help="TESTER serial number") - parser.add_argument("-f", "--fwupdate", metavar="", type=str, - help="update firmware with binaries from specified directory") - parser.add_argument("-H", "--hostdir", metavar="", type=str, - help="location of installed hackrf host tools, will attempt to find them if omitted") - parser.add_argument("-b", "--testerdir", metavar="", type=str, - help="necessary only if EUT/TESTER have separate host binaries") - parser.add_argument("-C", "--ci", action="store_true", help="For use with Jenkins CI user") - parser.add_argument("-p", "--praline", action="store_true", help="Force Praline mode") - parser.add_argument("-F", "--factory", action="store_true", help="Force factory test mode") - parser.add_argument("-u", "--unattended", action="store_true", help="For use with unattended hardware") - parser.add_argument("-L", "--log", metavar="", type=str, - help="log file location") - global args - args = parser.parse_args() - - if args.ci: - user = "jenkins" - else: - user = os.getlogin() - - if "any" in args.rev.lower(): - args.rev = None - elif args.rev.lower() == "r1" or args.rev.lower() == "r4": - args.rev = "older than r6" - - if args.hostdir: - eut_host_dir = args.hostdir - else: - try: - eut_host_dir = os.path.dirname(shutil.which('hackrf_info')) - except: - fail(4) - - if args.testerdir: - if args.testerdir == eut_host_dir: - fail(5) - else: - tester_host_dir = args.testerdir - else: - tester_host_dir = eut_host_dir - - unique_bin = (tester_host_dir != eut_host_dir) - count = 0 - - while True: - log() - log("================================") - log(datetime.now()) - log(sys.argv) - log(f"user: {user}") - log(f"version: {get_version()}") - log(f"pid: {os.getpid()}") - if args.loop: - log(f"repeat count: {count}") - log("================================") - log() - - if args.eut: - eut_sn = args.eut - else: - if args.tester: - eut_sn = find_sn("EUT", eut_host_dir, args.factory, [args.tester]) - else: - eut_sn = find_sn("EUT", eut_host_dir, args.factory) - if args.tester: - tester_sn = args.tester - else: - tester_sn = find_sn("TESTER", tester_host_dir, args.factory, [eut_sn]) - - if eut_sn == tester_sn: - fail(7) - - # TODO: check if the provided firmware directory exists - if args.fwupdate: - program(eut_host_dir, args.fwupdate, eut_sn, args.unattended) - eut_sn = find_sn("EUT", eut_host_dir, args.factory, [tester_sn]) - - if not args.rev: - out("Skipping EUT hardware revision check") - eut = HackRF("EUT", eut_host_dir, eut_sn, args.manufacturer, revision=args.rev, factory_test=args.factory) - - if args.solo: - tester = None - else: - tester = HackRF("TESTER", tester_host_dir, tester_sn, args.manufacturer, unique_bin=unique_bin, factory_test=args.factory) - tester.partner = eut - eut.partner = tester - - out("\nTest started, please wait...") - if args.solo: - eut.clkout_connected = False - elif args.noclk: - eut.clkout_connected = False - tester.clkout_connected = False - elif args.tcxo: - eut.clkout_connected = False - tester.clkout_connected = True - else: - eut.clkout_connected = True - tester.clkout_connected = True - - if count > 0 and not args.fwupdate: - eut.activate_leds(False) - - if not args.unattended: - eut.reset() - eut.debug_selftest() - # limited RF test without clock synchronization - eut.test_rf_preliminary() - - if args.noclk or args.solo: - out("Skipping CLKIN, CLKOUT, and PPM tests") - else: - eut.test_xtal() - if not args.tcxo: - eut.test_clkout() - eut.test_clkin() - - eut.clkout(False) - - if tester: - tester.clkout(True) - - if args.tcxo: - if args.solo: - out("Error: --solo is incompatible with --tcxo") - sys.exit(1) - if tester.clkin(): - out("Using TCXO on TESTER") - else: - out("Warning: No TCXO or external clock detected on TESTER") - out("Skipping CLKOUT test") - if not args.noclk and not eut.clkin(): - fail(211) - - # full RF test with clock synchronization - if tester: - eut.test_rf() - - if args.noif or args.solo: - out("Skipping IF tuning range test") - else: - eut.test_if_range(ifmin, ifmax) - - eut.activate_leds(True) - - if (args.solo or args.noif or args.noclk or args.tcxo or not args.rev): - out("Limited test complete") - else: - out("PASS if all 6 LEDs active with correct color") - - count += 1 - if not args.loop: - break - - -if __name__ == "__main__": - try: - main() - except KeyboardInterrupt: - print() - out("KeyboardInterrupt") - sys.exit(0) - except subprocess.TimeoutExpired: - log(traceback.format_exc()) - fail(180) diff --git a/ci-scripts/hackrf_test.py b/ci-scripts/hackrf_test.py index 13948ad3..3b304156 100644 --- a/ci-scripts/hackrf_test.py +++ b/ci-scripts/hackrf_test.py @@ -595,7 +595,8 @@ class HackRF: log(receive.stdout + receive.stderr) fail(220 + self.unit_number) - # confirm that PLL A locked to new source + # confirm that PLL locked to new source + expected_value = "0x01" if (enable and self.partner.revision != "r9") else "0x51" timeout = time.time() + 1 while time.time() < timeout: debug = subprocess.run([self.partner.bin_dir + "hackrf_debug", "-d", @@ -605,17 +606,9 @@ class HackRF: if debug.returncode != 0: log(debug.stderr) fail(230 + self.unit_number) - output = str(debug.stdout).split() - try: - val = int(output[3], 0) - except: - log(debug.stderr) - log(traceback.format_exc()) - fail(230 + self.unit_number) - # Check LOL_A - if not (val >> 5) & 1: + if expected_value in debug.stdout: break - if (val >> 5) & 1: + if expected_value not in debug.stdout: fail(232 + self.unit_number) time.sleep(0.1) else: @@ -1052,7 +1045,7 @@ class HackRF: tx_out, tx_err = transmit.communicate(timeout=TIMEOUT) if transmit.returncode != 0: - out(tx_out + tx_err) + log(tx_out + tx_err) out(f"Warning: {transmitter.name} transmit failed") return rssi @@ -1226,7 +1219,7 @@ def get_version(): version = subprocess.run(["git", "log", "-n" "1", "--format=%h"], capture_output=True, encoding="utf-8", timeout=TIMEOUT) if version.returncode != 0: - return "2026.01.3+" + return "2026.01.2+" elif version.returncode == 0: dirty = subprocess.run(["git", "status", "-s", "--untracked-files=no"], capture_output=True, encoding="utf-8", timeout=TIMEOUT) @@ -1358,7 +1351,7 @@ def main(): eut.clkout_connected = True tester.clkout_connected = True - if count > 0 and not args.fwupdate: + if count > 0 and not args.fw_update: eut.activate_leds(False) eut.test_serial() diff --git a/ci-scripts/build_firmware.sh b/ci-scripts/install-firmware.sh similarity index 74% rename from ci-scripts/build_firmware.sh rename to ci-scripts/install-firmware.sh index b6fc4ec4..a50785a8 100755 --- a/ci-scripts/build_firmware.sh +++ b/ci-scripts/install-firmware.sh @@ -3,7 +3,6 @@ set -e git submodule init git submodule update cd firmware/hackrf_usb -rm -rf build -cmake -DBOARD=$1 -B build +cmake -B build cmake --build build cd ../.. diff --git a/ci-scripts/install_host.sh b/ci-scripts/install-host.sh similarity index 100% rename from ci-scripts/install_host.sh rename to ci-scripts/install-host.sh diff --git a/ci-scripts/test-firmware-program.sh b/ci-scripts/test-firmware-program.sh index 26be84c6..a9e786a7 100755 --- a/ci-scripts/test-firmware-program.sh +++ b/ci-scripts/test-firmware-program.sh @@ -1,4 +1,6 @@ #!/bin/bash +hubs hackrf_dfu reset +sleep 1s dfu-util --device 1fc9:000c --alt 0 --download firmware/hackrf_usb/build/hackrf_usb.dfu sleep 1s EXIT_CODE="$?" diff --git a/ci-scripts/test_host.sh b/ci-scripts/test-host.sh similarity index 93% rename from ci-scripts/test_host.sh rename to ci-scripts/test-host.sh index 5cc8b621..903fefd0 100755 --- a/ci-scripts/test_host.sh +++ b/ci-scripts/test-host.sh @@ -1,4 +1,6 @@ #!/bin/bash +hubs hackrf_dfu reset +sleep 1s host/build/hackrf-tools/src/hackrf_info EXIT_CODE="$?" if [ "$EXIT_CODE" == "1" ] diff --git a/ci-scripts/test_sgpio_debug.py b/ci-scripts/test-sgpio-debug.py similarity index 100% rename from ci-scripts/test_sgpio_debug.py rename to ci-scripts/test-sgpio-debug.py diff --git a/docs/images/gateware-basic-block-diagram.png b/docs/images/gateware-basic-block-diagram.png deleted file mode 100644 index 58f99e7c..00000000 Binary files a/docs/images/gateware-basic-block-diagram.png and /dev/null differ diff --git a/docs/images/gateware-basic-block-diagram.svg b/docs/images/gateware-basic-block-diagram.svg deleted file mode 100644 index ae6d5cf4..00000000 --- a/docs/images/gateware-basic-block-diagram.svg +++ /dev/null @@ -1,4 +0,0 @@ - - -eyJ2ZXJzaW9uIjoiMSIsImVuY29kaW5nIjoiYnN0cmluZyIsImNvbXByZXNzZWQiOnRydWUsImVuY29kZWQiOiJ4nO1dWXPiyLJ+n1/h8H1cdTAwMWR0qrL284aN9729+/ZcdFx1MDAwN1x1MDAwNrG02VxmeD0x//1kyTaS0Fx1MDAwMrLFmPbAxHR0I6moUuXyfVWZWf/9Y2lpefjcc5f/vbTsPlXKrWa1X35cXP7Tfv/g9lx1MDAwN81uXHUwMDA3L4H370H3vl/x7mxcZoe9wb//9S//XHSn0m2/PuW23LbbXHUwMDE5XHUwMDBl8L7/x38vLf3X+1x1MDAxM680q/bZy8Y57Dw/XFzXXG6lm63rWsttNODMe9S76b0zfbcyLHfqLde/9ITfXHUwMDBiplx1MDAxZC6lJpRcdTAwMWJQIOTo6jNeLVxi4kiqqZLMXGIpXHUwMDA1gdHlx2Z12MBbuGGOJMZQwyhhyojRXHUwMDFkXHK3WW9cZu0tXHUwMDAyb9GMXHSuXHJlknM+uue1R/9eXCKjb1x1MDAwNsN+99Zd7ba6fdvt/6Ou/c/v9E25clvvd+87Vf+emvfx76k1W63j4bPXMr5lfKPLY+2fv/VcdTAwMWXGvk96XG5/sN7ouINBqK/dXrnSXHUwMDFj2lx1MDAxN0WJ/63tXW+r6k3Yf/w+9cttd8vOWOe+1Vx1MDAxYX3d7FRdO1x1MDAwZstXw9Cvdapvv1x1MDAxNrp74LpV74Vcblx0kjL/PfqiRSnR41/vdzuenFx1MDAwMVGMXHUwMDEzQYnxf39QQlx1MDAwMVx1MDAxYnrN1sqtgeu/aNuJtYDw+WO571XLr49QpYxWlFBcclKNrreandvxrre6lVv/V7xv//ozTp77va6QzeKPYbn93H/aboq7X5t3U8szyrCjXHUwMDE4MYJzqViiPFx1MDAwYq1cdTAwMDRII6iIXGI0UOJwbjTBh1x1MDAxNSdU6DiJXHUwMDA2x1DBOGgjlFxuXGZ9IdAjgX6cXqCpJGiCXHUwMDE4XHUwMDFholx1MDAxOInWPFwi5+9cdTAwMDJNJTVAgc2xON+d3pTkbu38+fjxeO30x+GAtqE2tThcdTAwMWKiXHUwMDFkTZRcdTAwMDLzKs5cIizOlDl4UVx1MDAxOM5cdFx1MDAwMEHZ11x1MDAxMXGmXHUwMDAwjqZCXHUwMDFhRjRcdTAwMTeKU1x1MDAxYVx1MDAxNWctUZpcdTAwMDHbodaQa5m3fS6Lqv7txflpY3p5NtpcdTAwMTBuqDIx4mxcdTAwMDLiOi7OIIxC4aNcdTAwMWZcdTAwMTLot1x1MDAwYr5cdTAwMDRcdTAwMDaksLr1dFN5Wi109tpnJXq4Uz68a5vReEKSWO73u4/Loyt//ZnWLu+drJUu9tdXKrtcdTAwMWJseHhr9lZcdTAwMGZcdTAwMGbj21x1MDAxZLpPw0Czb3+bpIU6XHUwMDFmLUzvZ7iPYVx1MDAwNWTEUVx1MDAxYYBTKVxmXHRaXHUwMDA1K1bCYUorjW5cdTAwMDS1XHUwMDA3b4jCI4X6K/GjcV6pojrGmVxikq+6XHL75c6gV+6jXFz87ip3lsGFIPrU+Js8ol3WwIlEXHUwMDE3gu7DoFx1MDAxN6FCfUTn8lx1MDAxNF9fXHUwMDFhrVx1MDAxNOL4i6XVn51mZ+j2a+VKYM5r3c7wuPnyiuhC366X282Wffky1Fix1azb17BcXHFta8vBdzFsXCLlXHUwMDE43dBuVqtBXHUwMDFmVMFGy82O29+axpl1+816s1NunfhcdTAwMDNYiul/+X7Y/eFcdTAwMGVeRzDs37vBl+RuvutcdTAwMDV1QKSo9EGZXGbW9eXOpTxfLz5fXHUwMDFmXFxcdTAwMGW2V1x1MDAxZad2rIiSlcNcdTAwMTVcdTAwMTNcdTAwMDIo/i+1b6rDQFx1MDAxMalcdTAwMGZcdTAwMTGKcP+NRoBcIpNEMJzwWOrzXHUwMDBlXHUwMDE0lWZCcl+5XHUwMDE2QHGk5s/Ta7lcdTAwMTTANVx1MDAxMTpcdTAwMGUnUqLE+Ncjz6qRMFmOO8/Mxz0s3Ynmw01p0NpbP+akqzZLMUz+1UGHpFlcdTAwMWHuXGJASSaaIezgYZjIqEZcdTAwMWZmXHUwMDE0gJJSXHRCorKMJN6qXHUwMDAxXHUwMDE4fFxcXCKLZ1FRXHUwMDA2plx1MDAxZKRVQiiNnJ+agG2bLMtaatfIL3Fb1fKg4f69XHUwMDAy/TK9QKNcdTAwMTFcdTAwMTFaK4g6KG9WXCJcdTAwMDAyXHUwMDAwXHUwMDE1XHUwMDA1XGL0a7NcdTAwMTBoTTNcYvTo6163OY5E/b8t+e/a+8fo7//5M/ZuLlx1MDAxZMlQmNF4Wsn1efznny5cdTAwMDA1XHUwMDBlRUhGXHUwMDE5YUC5MJOaS9SOmTRcdTAwMTfRM7+9XGJoXHUwMDFlXGbL/eFcbkpes1PHN+8j9Pdlw1e/Te7Of1xmLnuuu71XP9m5X19bXHUwMDFmnq5cdTAwMDVg+nK7W/WUpdu/aVx1MDAwZYNcdTAwMTdqzSe3emhnNjSxS+idXHQzdj1cdTAwMGZcdTAwMTiSSuIvOtlcdTAwMGY6RqNcdTAwMTFcdTAwMTbjXHUwMDFmXHUwMDFh/1BcdTAwMTJcImNcdTAwMTjximW3U508guur45dcdTAwMWQlXHUwMDBipdvqxd7dkOzp9lnxcyOwnTSMXHTKuUTYSKVSf4ZcdTAwMDcosftEKoJcZpyjXHUwMDBmT1x1MDAxOYM3XHUwMDBmRWuYXHUwMDFibjliXHUwMDE5cITBa2jqmmOQxG3ddFx1MDAxZj2dXG7hIa/vx259XHUwMDEyx3uzPFx1MDAxMOz/a5/GxjxBNYKqXHUwMDE1XHUwMDEy39dBZG0sRTX8l5hCMd+GxT4/rPSeTFx1MDAxY2eqxk4/znj13Vx1MDAxYVx1MDAxY/fcSrPcilhU7ErkYlxufrgvXHUwMDBmyo9rZ5f9XHUwMDBlb/bO13ZcdTAwMGau8P6pXHUwMDExMaJYh0lBJOfK4IBYmOratSaDKFxu2SxeQs5rokun/lpcdTAwMTPlaFx1MDAxZGhcdTAwMDBU+zBcdTAwMDK0Q6lWyvcx+UDhXHUwMDFiqMHNze9ccoXLXHUwMDA30yNcdTAwMDfFXGZcdTAwMDGUd/83g0umdPxbXHUwMDFmOFx1MDAxOFBcdTAwMDKn5kPAIUFRPfHbXFzbKdS7e9Qt1I6u3EpVN0QhjzWmo+Lx1UOrddXacMU+2dgtdfZXrqZaY0ptdqUn6V79cqO92qn1n1bbJ7/Ory+n625Ej2e6dpU+/pS1K9RAR1x1MDAxMlx0XFxgd1x1MDAwNKNhVoD8V9idXHUwMDEy6+KQOlx1MDAwNCTmXZ2tQbBcdTAwMWYgkiokXHUwMDBlMWtXIPLV4m+zdlU+nF6TcXKEZuhX4jiANMmkXHUwMDE2XGYxYDjMglx1MDAwMyiSQXp9YXxb+TneONxcbtiyr1uxmuBcdTAwMTPHV6zG+p3PSlU6dp3kl1x1MDAxNVx1MDAwNU9RhUK3ySlcdTAwMWJbqEK3XGZcblxiIYogV5CBvbKRV1x1MDAxNoh0iZZcdTAwMWPVXHUwMDFjXbuKW6dCY0CJolJIdPxIOfJep/pcdTAwMGU7QOWjXGbOWUlGXHRcdTAwMDdcYlxu7ptGM1x1MDAxNXHZ71x1MDAxYc3RXHUwMDE2U5wkf4Zy8s3pS0shMczkm2HlobHdbFx1MDAxZWzxl5PTx3Jzc/C0df553zyr7arS3p5unD5etEFcdTAwMGWO+Fx1MDAxMWlcXD33e/Po89Pfa4rPR+rjXGKJqoxcdTAwMDZDIFx1MDAwMVx1MDAwZvt8qlx1MDAxY4VcdTAwMDBdXHUwMDAzKrti1PhcdTAwMTDfh/Dc4dbpcyaIQJTv25OF059sITJsWGmpXHUwMDA1XHUwMDEwXHUwMDA1cUvZLFx1MDAxOb8rbXcluJrFdtXnfP6Pi6XS8eFSpYHud1x1MDAxZVxc/1x1MDAwNLc77vrju59cdTAwMGZcdTAwMDJwz55qvc06O+a7l8eX5uCktlH8kVx0XHUwMDAxKIluXHUwMDFjfbNgwMZ0XHUwMDFhlENcdTAwMDDhvaHUbjLFbELPXHUwMDAzXHUwMDAyqNUqpmJ+c/0+nl69mdSccFx1MDAxZavegieG6EkphcZZyFx1MDAxYlx1MDAwMNBcdTAwMTV1uK86xeLwR+vxviV27s9rjVx1MDAxYzzqzWDQ6pdZof1jyG/qLWJWSi/Dz1x1MDAwM4Dn/e1cbu3tt3bL7ZWD+52Dx63CeUKzmbq7/oOd9n+121x1MDAxN6o9XHUwMDFjlipcdTAwMDf7dyu7c0n6099rKlx1MDAwMJBcdTAwMGWzLp5cdEC+wHzt8XRAaIcobdCUgFx1MDAxMujk/Y0+XHUwMDFmXHUwMDAxMIchnyCIIOz+t45cdFx1MDAxOFsggCRcdTAwMGJxkiFIXGZsXHUwMDE4qlFcdTAwMTFbYIlANHTMj3m0XHUwMDBitERcdTAwMDUgwrwggJM5Q1x1MDAwMFx1MDAxM9zuOFx1MDAwMojvfk7RKpX2rSno2/XLwu456TUua7Xn8keiVSxcdTAwMDQggcjv90VcdTAwMDDNXHUwMDEx9nN0XHUwMDFk2saDxsSBToNcdTAwMDFcdTAwMTZxoJM1/CaDhlx1MDAxYuBGiyjft3aaJ2u4UZJ7QUV5o4DaRfual3a2iqq1Vzu77lV/XGZkZypv/fd6v/R+png/Sjl1UIS1kppcdTAwMTLJXHUwMDAzkbRv/Jda6ouqpIlmLMp/OXNQ9o3RXHUwMDFjXHIs0uRcdTAwMDX/zaJcdTAwMWKVXGaL3lxcMMNcdTAwMTTEXHUwMDAyZClcdTAwMTOVgyM5YYhs5s/7XHUwMDE1S6vz4PQmeJqYXHUwMDE4zbx9XePm/PHa7PRKtfvhk7o5XZVX3Ytsvk4hXHUwMDE1RXCE2qzHXHUwMDExLOJbg1x1MDAxN1xyXHUwMDAz0IIyXHUwMDE23bfKRHdtXHUwMDAyT5BSL9juSJur02sz4ERcdTAwMTh847FhbGhLk8EssSSEm9xd3Uuh9munXFzefNp7pCuVlave3vlqwor3l7q69H5OcnVcdTAwMTI05YZgh1x1MDAxNFx1MDAwZqe6eUxcdTAwMGaQwdm9W6ZETNAnXHUwMDA3R9jcXHUwMDA0IbnhlFx1MDAwN+5YuLqJyuFmcHVUXHUwMDFhZG3BXHL0XHUwMDAwXHUwMDBlVFx1MDAxMVx1MDAwN/iuXHUwMDFjTFBE9EzNJL3tU5lcdKXiXFy4ulx0jmbc1YV6nZOr2yj21l+u6NMludx+qOtOsdIoTaO9fp4q06ihvlx1MDAxM/P4nPVOQmj0dYpcdTAwMWFcdTAwMDJcdTAwMTBccrXiwlx1MDAwMYtTXHIwRZAqxLi4he4m6W4zg+6i4WSII2TcTi5Pic9W0jCNNOTLc1Mjyru3epqH8rbc2jBFdYfdXpLehjo7rqSh3uWjpMVCf3ejfK97PXq2s3lz8uNwcPWUKS5SU2RcdTAwMWRcXFxuXHUwMDBlJLBcXGdfXHUwMDBlaONIw7lcdTAwMDaG01wilIqJv1x1MDAwMPTTXHUwMDAyXHUwMDA0wk1OhM1cdTAwMTiP6qowjkJnTYBLyuxeTt6A9FtER/6aXm+5VNJcdTAwMTKIuKVcdTAwMTdk9Ynbq1xiZJFeasHyXHUwMDBmj9zYPN1erz5t9y/JVePlWP56gFx1MDAxY3ZK+Fx1MDAwNdTF2epq79I9JSdrXHUwMDA3zy/P9Vp8s1+7o5E+/lx1MDAxNFeJwPR17ZOCje/mYT7IiHJsglx1MDAxZcNcdTAwMWJcdTAwMTS3YVx1MDAwYlx1MDAxMVx1MDAwNWRvcYyow1x1MDAwNrFcdTAwMTgsNjQy6Nzt9DonKFVM0Vx1MDAwNJ1jiXGMgFx1MDAxNFx1MDAxZDWOzGJJ53M49/hwa1x1MDAxZXDuXHUwMDA0XHUwMDA3XHUwMDE2XHRiXGb2Olx1MDAxZlx1MDAxN5qeQDRNkSGKfo2gd+NMqfCiLCiB+ol+z1x1MDAxONRjQaNEdVx1MDAxZeJcdTAwMTe+hVx1MDAwM+1kXHUwMDAwvlx1MDAxMnDahGJxpFXqxFx1MDAxNVx1MDAxZCFcYlx1MDAwNfPBXHUwMDEyQ2mO7nCvWd+H++NVpuBcdTAwMDW2f1x1MDAxZLfbv3hcdTAwMGUhXHUwMDAxs4qMmFXI5dlFvchcdTAwMWae6XqtWNi/b9bldVx1MDAxMe7/QThcIn38KThCSOZozblhTKGRXGLbIGOvjVKkI1x1MDAxNsgsynh83Op0p7c6klx1MDAxOC5s2FSc0ZHJy8goXlx1MDAxMslcdTAwMTWbXHUwMDA121aQQXDjIMSSdef9butnp+/Wm1x1MDAwM4RcdTAwMDKDeUBcdTAwMTVcdTAwMTN8elxmqnhcdTAwMWbIUsw48sFcdTAwMTnpxnjWJVx1MDAxMJA9SIVcdTAwMWNfXHUwMDBirnjMxi9aXHUwMDAxaXeLNFx1MDAwMSNcdTAwMTDrZomP+EdVQLghJMtOsLSp5ELE8Vx1MDAwNkheXHUwMDFlp1RcdTAwMTjgdEbpTyYov19SXHUwMDAyIVEgP/90IVwiyX5zXHUwMDExb/6PqTGQXHUwMDFlLvahXHUwMDExRGpcZvxcdTAwMTlcdTAwMWVeuMJA2lxi/qZcblx1MDAwM2FcdTAwMDVcdTAwMWRPT1x1MDAxZv/N8Wspln3/8mFtX93frJpB8aBeLojn1pqJWvaJXGZcdTAwMTLtO1qKaPybl1x1MDAwNEdBXHUwMDEyKVx1MDAxOYnZMMmWm1x1MDAwZVx1MDAxYWFcdTAwMWWhi1XYONvOp7ftRmgk5Do2xlx1MDAxNbuSuH2CRJ5cdTAwMTG0TrmHXHUwMDA1zIpFvlx1MDAxNFx1MDAwZlulW1a7u9u/bT+QXHUwMDAzXtzY2P88K/tEknpqu59IhEtt97eJr0+frzRcdTAwMTbJuWNQMqkhVFx1MDAxYaXDVTKUQJipmOZMXHUwMDE5XHUwMDAzXHUwMDEwXHUwMDAzMynxSoUgXaHAXHUwMDA0XHUwMDBiLnctqORk2yOy4Epcbmh6XGKLw5WGJlfIIHYhkbM5rFxi6aWnL5U71Z+dWqv7+M7H5oFNTvDvsYn2diRL8Vx1MDAwM8mHTqabzzQ6yTWqKaIyYZeKJKVcdTAwMTCOrjLGwW+1QCShXHUwMDE0XHUwMDA0QrlcdTAwMDOxVYaB4lx1MDAxNuDZqkExe07EQSlcdTAwMDNEM4pcdMlcdTAwMDSC9YXWJ2i9zKD1OCH4SmVsJFwiqJRIRFx1MDAwZcBQ9WdcdTAwMTJY/CGtz7egXpJAek9HRNFvLuKXp+SD6ZU3PspcdTAwMDc5Uj5mw+nAmLGigJZq2T1iXHUwMDAwjuPkRIrIIDJcdTAwMTLCdJv2oSFcdTAwMTTI2Fx1MDAxOFx1MDAwNKFcdTAwMWZcdTAwMWZFhFx1MDAxNMZcdTAwMTG/XGbUMCx/+XLD0bV298Hda76+ncF5c9h4U6QpUFv6JkW6PffOOeGKKsNcdTAwMTWTMmzPXHUwMDE5NfjiLcFcdTAwMDQ0XHUwMDA0jETzpzhz8GnCkFx1MDAxOVx1MDAxYYnTomP2IIkjwFJQramWXHUwMDA2mM5SXCL1n2XRi1x1MDAxOSw6cnWlNfC4TFx1MDAxMZqyKVx1MDAwMIpSbmZcdTAwMTNXoD+UKpKvRU+USPspRIXx8zY9PVx1MDAxMOFDXHUwMDA2kThm7Fx1MDAxMzaHglx1MDAxMPpZOz6DpUmSqZeztdOfMKjpyyGp+y12zY0qxDZcbqRcbsa2e/up0kyK6WCOQrFVaJNfXHUwMDE3oWNcdTAwMTAyV462K6eCI9RG6rSoOJ1oT1cy2FOcNqS3sYl3QJKrzTHEj0ZcdTAwMGI6XHUwMDBiWjxcdTAwMDfmNHR3XHUwMDAxuFx1MDAwMyh5mttQXCJcdTAwMDVcdTAwMDBi0vOFZImeUYtcdTAwMTH1+LyBn4WlTNtcdTAwMDKxcHisynKUenw9avfGgC9ZKWortEk/JMB+kJaAsTtcdTAwMGZInFx1MDAwNFx1MDAxMqjvvI2z/djZfJG7W1x1MDAwN72Ty5eSXFw3m/x5Olx1MDAwNE5cdJNcdTAwMGVRXvo157ZKc8hjUPRcdTAwMThGS+RENl3NXHUwMDA0XHUwMDE3yt5dhiBcdTAwMGVFZ8KVRoxcdTAwMWVKXGZcciBwXCKNd9iD5lx1MDAwNEGjWUDwRJexkXCgVUCv3qZcdTAwMTOiYvxW5lAghZWxeW1cXKfkxtiUJ1x1MDAwMfpDVY5mssCaqydJlFPv6aiETm+2x1x1MDAxNTfhSn5GJjeguXVx+HJ5Vjhw60ebp1x1MDAxN9u6eqzPnqe0XHUwMDFiSN3tijzRRkJwXHUwMDA17zVwz+FcdTAwMWPdXG4om2KJnnWi2YhLlbOVz1x1MDAxNTf2hD2cXHUwMDE1rSDnXHUwMDAzXHUwMDFkv5PVSChxmMFq2FO68IO8Po7Qq+TzS5HOS4pOQs9PRmyuhqOQKKre1aiU/lx1MDAxMyxHei3YNMthXGKEXHUwMDBlz1xmXHUwMDA3jdisIMWVrZJcdTAwMDaKXHUwMDEzo6OZe4w5KFx1MDAxN1x1MDAwNGxNXpQ9XHUwMDFlXHUwMDEzMkIspFGIbilcYiDYXHUwMDFjyblo0jcyXHUwMDFkm1x1MDAxOeKAQTGrXHUwMDAzcXHAMcdq+shC2JM3P1Y4af73cFxuiVx1MDAwMuldjZHF6VxyRFx1MDAxMptKP/LvY2wqjIfyWOGbwfFANFMv59BwptfQTDOcXHUwMDFhuZhccn+z5eRcYoWxaDu8YuuOXGK7X8pcclx1MDAxOFx1MDAxMa2ihXKqXHUwMDE46lwiNSijwCiLXHRyIY7dbuXcxnba80jEYvs7yXBuT284XHUwMDExXHUwMDFmW1x1MDAwM1x1MDAxMLv5nVxmrHCmOMOpmMne99dHUieLo/d4RFx1MDAxMD9vNWdcdTAwMTBKnM1cdTAwMWX9Vlx1MDAxMC89XHUwMDFhMc1SKVwiU1x1MDAwZcdAiFx1MDAwN4JcYips4mgoXHUwMDAzeWSojCM5s2XupeE26DTeUKG5XHUwMDAzyoRWqFqC6Vx1MDAwNTtMslQ7XHUwMDE5LFx1MDAxNTFEXGJcdTAwMTmbX1xuJFx1MDAwMvz84pj4kFx1MDAxNCC/adZHIVkkvcsx0vh5czWL01x1MDAxNfNcdTAwMDd5M1nY14iW0V96tetsenm421RrZZNMmEBSgaz890KA6dHYqbu7UjpcYu28SrTaXHUwMDA0z7F5RYDUwUtWXGKptPWpokdcdTAwMGWgXHUwMDE0a4Z+lYNGXHUwMDE1x1x1MDAxN5xcdTAwMTAuY5SR9qBTZY/IXtjVJLu6m2F7V9pVZUhcYpdJrnxDXHUwMDEx61x1MDAxM2aPt5yBYZ2D/d1kibSfQlRcdTAwMTg/b1ZnZLBcYpNApFeYzOixcJnwVVx1MDAxM1x1MDAxOcNcdTAwMWOkxP3uvPqsdCbg4Gylen3SfKhXXHUwMDFlz39cdTAwMWScvUStanJ5W+lwavNdgVxigLHAXHUwMDE5zsBcdTAwMTGM2NPDXGLYglx1MDAwM1x1MDAxMctcbsi+KVx1MDAxMlx1MDAxNkWEttluMYaVKsfYwDBAeGWDXHUwMDFhM1x1MDAxY7VcdTAwMWFrM79rLfdcdTAwMWJyOb1d5UZcImJlJra6XHUwMDExXHJcdTAwMTSwjYQhXCLx1kLCl6eTpMj0odxs883DXfLyfFC63ylcdTAwMWT1e49TXHUwMDE156KUolx1MDAwZSvQiuAwXHUwMDExXHUwMDE0hFx1MDAxOVx1MDAxOFx1MDAxYVtHeWdcdTAwMTLYXHUwMDE1XHUwMDA2Q2Kq49mzlW3YXHUwMDFmol1cckGkMVx1MDAxMme1KM6VJL/1LGG00mLZuFx1MDAxNXVtXHUwMDEy6Vx1MDAxNlBg6DbFXHUwMDFjXHUwMDE25yqWVpcq9p6larddbnZ+dkrF8W+2bFJTp9xcbn2dR7rUjKpf5jCmfDKnXGZpbm1dXHUwMDBmfvXPa/fd44vtl6Z4gGlcZoLN1LZ1OIywXHUwMDAxXHUwMDBlJlx1MDAxY2Y/KmzLiJdcdTAwMWbJosRBwGulXHUwMDFkrpGSKS5cdTAwMTfF+rLYg0ZcdTAwMDZ7YJhBXHUwMDA0XHUwMDExXHUwMDFmXHUwMDA3ynXiWrGHkdlcdTAwMDfPXHUwMDBmn6lBWD/cKM6xboe7l4+a7lZa5cpg82b7onL1eFcv6MrBVUy9nFx1MDAxOL/tR9VQXHUwMDAzXFyIXHUwMDA0RVx1MDAwNcmNlzBcdTAwMTN13Fx1MDAwNFx1MDAxY7Cng1x1MDAxYm+H3cR57oWmJmpqllx1MDAxYdRcdTAwMTZcdTAwMWFcdTAwMTlccrFcdTAwMDVyZDSKxkeejFx1MDAwYjs1c6epJ3ZcdTAwMWUrbvMhmHE8d1xuXHUwMDFi28ucXHUwMDBlXHUwMDA0vT0o7Jw97YrCY6l+L3dcdTAwMTivXHUwMDE0N6J6m8AhXHLRjrEn+FwiIbF+NKS6o/NAcaao3fGKOVx1MDAwZnRUXHUwMDBihWguXHUwMDE0j8u9mPVZYN/hhJRcdTAwMWKa4bxfJrVdkolcdTAwMWX75XVFJfJHe667srvxXHUwMDFm0eK3XHUwMDBisbU6NrZ3bju1lcu14+vm1vUjOT+UVb9wbEhcdTAwMGW/9ISU9H6m+DhcdTAwMTRvXHUwMDA3XHRcdTAwMGZw1Fx1MDAxM2NcdTAwMGL/hPWEXHUwMDBix1x1MDAwNjhcdTAwMThbO5CK4DFcdTAwMWLveqJcdTAwMTZVXHUwMDFmP6FcdTAwMWLn0+uGXHUwMDAxZcNcdTAwMWVlZHF6Ob1MXHUwMDEwTlx1MDAxYlx1MDAxMEQgM8lJ+vRcdTAwMTEpPztNS9Vq5Yqbh5f79GmY6T4n5rSUpZj+5+P/XHUwMDFlaiedo6fHw1bhrrzz3KtcXJfPiyeZ/Fx1MDAxZqNSXG5qfZfSY9hcdTAwMTXVnlx1MDAwMOFGSiOIXHKjjTvm3lx1MDAxZXIrUepcdTAwMTRIyoMxxz54lcRRjNlcdTAwMTRcdTAwMDdGSDBbYaHpYU2/yIBl0Vx1MDAxNiOxMFx1MDAxMMkztC6SJFx1MDAxN3tEsmqPdfzYYUhpbnBzbadQ7+5Rt1A7unIrVd1cdTAwMTBcdTAwMDVcdTAwMTPvXHUwMDA2M5XCOrr/Je5uh8f99v7m1uauW6qyJzmH7jW9n2nuXHUwMDE1jENcdTAwMTQh9uBcdTAwMDV7SlVcdTAwMTiGauIwbrNcXEBcdTAwMWGjILrwq6mjJ1x1MDAxYzPNXHUwMDE3zjVR5TIgT1x1MDAxMIYjXHUwMDAy4rHeNaqIvsrZwzKk/tCGcKhcdTAwMWazZZA/O+1u9b5cdTAwMTXvY1x1MDAwM5nnf4ePneDXUlx1MDAxOObS+CDycbTp1i21Yoo9tkghtqLEXHUwMDFlXHUwMDBmKGDs1Fx1MDAwNiC2XCIn2mUuJFM05iR5wbVcclx1MDAxM7FFKFx1MDAwNFx1MDAwZorRSMGZxJ/QNqLLxt4gzcy5ojKyTPvJVdm/ILufZtimtCVS7SuNi1x1MDAwMFx1MDAxNjKygjTa5/GssJjJWYOBPae5SO6PSt2kx5MkOf/WqHSEMdowZZNkkd5Eyz/NQyWu8YR4qUKBczYjXlx1MDAwMlVeqI1cdTAwMTEmXHUwMDFhS5MxXHUwMDBlJd2ufmZcYoZQLkBcdTAwMDD4SYXvI2A298FcIlx1MDAxNMGViqbS/O1J/Ukw9s1OhNKMX/s0NuQxPUiV3ZD0vo5cItJamiBPajxcdTAwMDXuRupcdTAwMTWEXHLDWMGCSfh2cEsutsrlo9OXe1edNjZpoSdcdTAwMDdRXHUwMDBmmFx1MDAxNq5cdTAwMDPcXHUwMDAyITBcXGkxXHUwMDE23yCUXHUwMDAzzNZTQSaqKYkyzTlcdNf5XHUwMDFly61XXHUwMDE5QC+1oas0elCRXHUwMDA3emky0SRcbmVZqC+Pd0hcdTAwMTHpXHUwMDE3/VLq9s5cdTAwMWFcdTAwMGZ8d4dcZpvq7rh2dPdcdTAwMDGRXHUwMDE2ilj9XHUwMDFji0BDYmYrRVx1MDAxYeWleFGIXHUwMDAyuzmR6W9RTZ2WM8i04XZeoqfOvrK15Fx1MDAxMDRCXGYxTMCXXHUwMDE33HhcdTAwMTXqP96s/XK51ztcdTAwMWVikyPPv/zQdFx1MDAxZleSgfxcdTAwMWZvKmHn2vXKXHUwMDBl/PXHX/9cdTAwMDPhIXiWIn0=ADCinterfaceSGPIORX DSP chainTX DSP chainADCDACMCUSPISPI controlregistersSGPIO andflow controlADC clock domainDAC clock domainInternal clock domainFPGATransceiverDACinterfaceTransceivermodule \ No newline at end of file diff --git a/docs/images/gateware-ext-prec-rx-dsp-chain.png b/docs/images/gateware-ext-prec-rx-dsp-chain.png deleted file mode 100644 index 6dc48330..00000000 Binary files a/docs/images/gateware-ext-prec-rx-dsp-chain.png and /dev/null differ diff --git a/docs/images/gateware-ext-prec-rx-dsp-chain.svg b/docs/images/gateware-ext-prec-rx-dsp-chain.svg deleted file mode 100644 index af05bf82..00000000 --- a/docs/images/gateware-ext-prec-rx-dsp-chain.svg +++ /dev/null @@ -1,4 +0,0 @@ - - -eyJ2ZXJzaW9uIjoiMSIsImVuY29kaW5nIjoiYnN0cmluZyIsImNvbXByZXNzZWQiOnRydWUsImVuY29kZWQiOiJ4nO1cXGtX2tpcdTAwMTb93l/h8H6tOfv96DdcdTAwMTRbrbVS0YLee8ZcdTAwMTlcdTAwMDFcdTAwMDJEIGBcYr7O6H+/K1x1MDAxMUnIi6Dx0XOkY3RAnjt7rznnmnuv+PeHjY1N73ZibX7a2LRu2ubQ7rjm9eZHf/uV5U7tsVx1MDAwM7tI8Hs6nrnt4Mi+502mn/74IzzDaI9H92dZQ2tkOd5cdTAwMTSO+y/83tj4O/hcdTAwMWb22Fx1MDAxZP/cXHUwMDAxXHUwMDFi1UjnR52cWiNcdTAwMTfzztGX47NqcGpw0ENjXFyr7ZlOb2iFu25gO1XIUIJhJTinVCC92HtcdTAwMGJ7XHUwMDA1XHUwMDE2hmSUK0RcdTAwMTknSMvF3mu74/X9I6Q2JMaUI6mJxpoujuhbdq/vwSGYcINIjCjVcFx1MDAxNVxuX1x1MDAxNsfcN+jTXHUwMDA2WmyZeu54YO2Mh2PXb/V/sOX/XHUwMDBi29wy24OeO545nfBcdTAwMTiTd1S3XHUwMDFiXHUwMDFl07WHw7p3XHUwMDFiXFxcdTAwMTk6XHUwMDE5OnQzdv3GvPUktj3rLLhhr+9Y0+lSW8dcdTAwMTOzbXt+P2FcdTAwMTRu9Vs32e9cdTAwMDTj9WfYJtdcdTAwMWNZ+/6AObPhcLHZdjqWP1xmmy28fDunM7/d0uFTy/IvgSXCkispwvaHscVcdTAwMTCOb/0+doI4w0RKIbnkLGzAtFxuXHUwMDAx5lx1MDAwNZftmsOpXHUwMDE19rTfiN1I8IVcdTAwMGYzm3RMb95cdTAwMTKFkIBBZUiEXHUwMDE3XHUwMDFk2s4g3vThuD1cYu9cdTAwMTJs/fUxLZ57s9aoWzl1XHUwMDFiqGI3XHUwMDFid1edm+Z1L1x1MDAxOc+edeNlhTLTXHUwMDFjIyaWQlx1MDAxOWLYkJxzLVx1MDAxNYFwXHUwMDE2XCJcdTAwMTHKmDCDUfhAwCOuuGbJWCa83Nj1XFzTmU5MXHUwMDE3+vh3j9/RXHUwMDFh8UuEkppTiVLiVyiaXHUwMDE1v5Ip4Fx1MDAxOVx1MDAxZVx0+1dcbt8wXHUwMDFh/SiExz9ublTrtY1237SdyECOXHUwMDFkr27f+U0naGnrZ3NkXHUwMDBmXHUwMDAzhl26VGVo9/w+2Fx1MDAxY1rdSEBAN3g2KMNitzeehHvbcD24reUmh2fs2j3bMYcnuc00Z9742JreN9RzZ1a0J6y9XHUwMDA1j1x1MDAxYoTn4PZscHg7Q9VcdTAwMTG9uFx1MDAxZTc+XHUwMDFm1Vpm87BZWIc0Jlx1MDAwNlwimkqCKVxmXHUwMDA2XHUwMDBmh9jvJSmlIbVcdTAwMTZUXHUwMDEzXHUwMDA0YYPDvVx1MDAwZuBV2Fx1MDAxMIJcYo65XHUwMDEyRFx1MDAwYlx1MDAxZPbrXHUwMDAyu1x1MDAxNFx1MDAxOVxiXHUwMDAxNSDKXHUwMDE5QJxHWHA1lpVQllx1MDAxNvk61FxyPr87jq/Tcfww2uFQ0vmWX3F4c4A2YErJaFx1MDAwMD+gm2SiXHUwMDFiXHUwMDEzXCKVxlH8r1x1MDAwMe9F88KGZqlFJGhcdTAwMWLt4/rB972qvVe56Fx1MDAxZrpH9i69+2tzcdyvj+mXvT+ZnDZPyOi0zr7efLeOr26mXYYry3d5uL/puuPryHXn37I4iVx0TVx1MDAxNWZcdTAwMTF+fJKkpj9lXHUwMDAxSdVEXHUwMDFhWjNEIcOD9FxysWVUKmIoRDBmVFx1MDAxMa50XHUwMDAylFxmckNfUKmfqzDBVJqiondcdTAwMTSmoPCmuJpcbn9kqMA6XHUwMDA1bkwlti7ghlx1MDAxMFChZlx1MDAxYT9cdTAwMDZuZUZuQk13XHUwMDFks1x1MDAxNVx1MDAxNYiIjmKxtHWVjrahvZabo6Qju9OJ3mpZTFeJWlxcX+Ncci9HWe2rs7Z73WPfKLOP7trbtdu2OCmsrEoxcGhaXHRcZiktwTrm8LgwYKNQioA3k1wiXGaGRVpMOXBA5Fx1MDAxM9L6XHUwMDAyxFx1MDAwMHRcdTAwMTY9RIXDUY7F+2eA+naNXHUwMDE0WSsmMWRDaahcdTAwMDanknB+XHUwMDBmsOaQ43Ck9Fx1MDAwYopos950K4NWt1t1rratXHUwMDFmg8Fs0Jq8gIjmXrd+cHgzkzY7bc+8Kq3v3V5cdTAwMWXJy1x1MDAxMq77rXV8e3nuNr80rquN8eR0cnP4xStL9Fx1MDAxOVwiiNEoSTxe9NNHpYjoY5xHXHUwMDE4Qlx1MDAxOdDSXHUwMDFjwlBhbP6TfHP4oOWSwl1xUoBUXHUwMDBiLDBcdTAwMDbrnEZcbogkNi+0nvpcdTAwMTTPXHUwMDExXHS5u1x1MDAxY61nXGJcdTAwMTH2JOdcXN3ZaPmHlOGan6r2K4Q2rvbJppej907vroKtXHUwMDFkfjGhSDly9HnQ/bZXWO+Fkr6iz+FLYjn7g95rVKbeh4e8y/1cdTAwMDLZXHUwMDA0rYFs5HtmjlGaZ4ZdmcDmgGtcdEP5cmo/aX5v91x1MDAxYs27Rnt/n8krp7ZdZWdF1bN71G25jVx1MDAwYqfDL6fyYLfROoFcdTAwMTF6XbVfrcpUc0jEylHl9N4roMqSXCJcdTAwMDODXHUwMDEx19yfsNRcdTAwMTIvw3quytmw5sggK734u0pnYVx1MDAxOa+RumPEgXlcdTAwMTlPrMNsXHUwMDA2M5mZWNbUXHUwMDFmXypcdTAwMWWVuj+rIT+0b6K6+npcbr1CXHUwMDFh41xuXHUwMDFka3c58jz7flBxZ5XmUbd/dT447rZofeBcdTAwMTSWZ0ZQJLsmkcXQYnacIG6g6CdMz7Pt+Ls8p0CarDHFxqnyeTfVjDOWWMZ6gDSBMSScs/C8Z5fnqz103t/+2mh1f17QqkNqfFTfem15lmdnPycnP05ml1x1MDAwN9Ci3Z81+vlgtzzTrJSQUSg/Xp7Te6+APDOq82C90jRjkZJmv+txJnjpOqvNjFx1MDAxMK0pTdNjTJKL0OGCXHUwMDE0435dXHUwMDBiKts1P12Qq1bbXHUwMDFlmVx1MDAxZTR2Y+qZPWv6XHUwMDE2xHmFMCbsc/YzlCPU+VOLMcZZQrPmxFBcXHJNsUIkOt9yv1x1MDAxYY2XVqOTaIZUXHUwMDFkXHUwMDEzJVx1MDAxMCQpWlxiIWlEglx1MDAxN+hcdTAwMTbIgOCCfF5z0OiIRrzZdbCOOe1bL6zSbFx1MDAxZKBcdTAwMDOsqNJpOGfJrYtcdTAwMTlzzZRmUXEvcW6MRyO3KMonYzueXHUwMDAzhN82wq5cdTAwMGV+LL7/+TH16K2cYFxm9sfjMLxgQntcdTAwMDGnrrdccqNjO73NpZqAeZVikVUzOHo07lx1MDAwNFx1MDAwMTV2W3Y0v4AgvbE6Nf/xl55cdTAwMWVcdTAwMWXT4CgsbIs9+PxbWIhgOZ3Vrcyf7SuplXg5WYeQyGl20L1cdTAwMTWfjvqWmVx1MDAwMFx1MDAwNTxUdFx1MDAxZqi5XHUwMDFk81x1MDAxN9awNb5OiaegvXWr91x1MDAxMLXL4PFvuj+tT4COzWHKTTP3jcZX1qF931x1MDAxMdOG7fXnwCiQZ+1/nX3bObn2zveG28dfL88vqtK9TFJzhoeSSFx1MDAxOJhLTSSFeCZ6udLPL1x1MDAxNlx1MDAwMlx1MDAwMHKNKGVcZstcdTAwMTCCXHUwMDBm9KyZoZHiXHUwMDE4ICE5XHUwMDExJLVY6O3T8St4Jv7k4iDFKVFKpk50YsQyZ0eIX/cnMX1BK3Xa3MV1tFO7MpuXuq/GX4Zd77So5dlcdTAwMTlhd3+G735sfz2vkcb0wu10XHUwMDBm3mJxUPpTXHUwMDE2sDwwXHUwMDE4hoJcZlx1MDAxOVx1MDAwYoxcdTAwMTRcZkysZC8oXHUwMDBlykOh1Fx1MDAwNvcnJFx0mFwiiFx1MDAwN5RSOv5eXHUwMDFjlIpCUTwnooQz8KXpcCNUZcFccmNIXHUwMDE4YGRKXzF8uvep9c2pXHUwMDA1lsGKrGa/XoXQXG4li5uetMaX43byXHQnz+1ITlxySUBcdTAwMGKl0r5PTrqdfCBDjoM51YJpKZAmNGKI4maHaUjPpcJ8nZmNf5HbkcWRzVx1MDAwNEHCdzwpyFY5NfSKXHUwMDBiTVx1MDAwNH47VX+lup3sWPQ/W4kwTGTja5udfFx1MDAwMnhps5NM7f9cdTAwMTV+Yq/RPN5pnHi1o2mjentTV2fbzXHxNVx1MDAxOaZcciRcdTAwMTBTWEmCo4XroZ/QnFx1MDAwNS9cdTAwMGZA8pokQMZccq6IYEiAq1x1MDAxMJHpolx1MDAwNf/x90wmje/Uk/1cdTAwMDRcdTAwMTZcblx1MDAxMc2oTJv10dlLM5hcYimYovxcdTAwMDVLJyr7jf3rn6je2Fx1MDAxN5O9mTPtXHUwMDFkkT1eeFxypfZcdTAwMDVXd2rNu8pgq+38PK//dXzlvEVDkf6UXHUwMDA1XGZcdTAwMDVcdTAwMTNcdTAwMDKA5s+4alx0Y0NTXzfIxSFcdTAwMDZ6XHUwMDBmXHUwMDE2PJlkmKTlIexcdTAwMWSHaTjUa8yySjB8XHUwMDFhYiZ1OVx1MDAwNdHsXHUwMDE3XHUwMDBlqNBAkoi/ndTjwVJ8Ntve2J1++p9cdTAwMDPuXHUwMDAxPNPHXHLBPlx1MDAwMkWot+AwVmhb3GFcdTAwMTR4lnJcZkc+IeVcdTAwMTlcdTAwMGVOsKFcdTAwMTnnXGa0UlxuLmI4XHUwMDBmXGZHiPPkm7rI8F82p0RcdTAwMTDwI5gqnlJx7Gd6imnIXHUwMDA2NXhcdTAwMWKy1kvn/1wiw1FZXHUwMDAz+FpcYlxuakvTqo+5znRcdTAwMWMwxkpcdTAwMTCFy15feSOOIztcdTAwMTj9z1ZcIlx1MDAwZVx1MDAxM5n82o4jn1x1MDAxMN5cdTAwMWTHiziO/FKZPPZcdTAwMTNcbudcdTAwMTVoK2RoycBLICA/zpKvOoNZSTFcdTAwMTjofqFcdIPrlVxc+G/RXHUwMDAyWOU6rzhcdTAwMTer/Grrtv7ds53tNUiPXHUwMDAyov0107Rkh2TnOkQyf4qBPWb6dKlcdTAwMWQp1ch+Pcur095WNFxmg1xyXHUwMDE5XHUwMDEx+HS+yy/6fFx1MDAxY98tPWtAfkX5LquV+dUvj2RlXHUwMDFk+6zV7JLJOIdcZvPL7/PIUEmV97LZnFxmqWJ+NqiSlTaxUlfOVlIj4lxmnD9cdTAwMDTnOzemceNOcW6UfsVcYqMsjVx1MDAxYiPKk1hZ4lx1MDAwNJJ6Rlx1MDAxZjPxkk+Nb6XiJjsog/MzwvHpRPlcdTAwMWNcdTAwMTUt5Vx1MDAxM+Uz0HmyyuY1ibKM9DL/NeM8RsWIiGgpclx1MDAwNqFmXHUwMDE1XCJLf1Ffcq7nPZnGp+/EmUKcu8WJU1x1MDAwMN6ha5OvXHUwMDAy+YKY89fbuO9cbtSzXHUwMDEwp4j+yaXXXCLOzNiLnf2G+PGJzLOGk07jnWVmWmatwslb/stcdTAwMTl5VMMwy3vpYTXXMFx1MDAwM8KOMTzvupRXXHUwMDEy37kmjWs+r2FgfTj5r0CkOlic/SdcdTAwMDNcdTAwMDQlkj+HgWWYM1x1MDAxYy7evFqWllx1MDAxOX2x01x1MDAxZss2z2FcYp+LXFzKcIZcdTAwMWbmfbRpTiZ1XHUwMDBmxnzRN5tXtnW9nT2J/mHealx1MDAxZo1WsP7768Ov/1x1MDAwM1x1MDAxNahInyJ9RX DSP chainEnableDC blockMixerDecimation stagesPhase stepFactors:16, 32, 64, 128 \ No newline at end of file diff --git a/docs/images/gateware-ext-prec-tx-dsp-chain.png b/docs/images/gateware-ext-prec-tx-dsp-chain.png deleted file mode 100644 index d0a97190..00000000 Binary files a/docs/images/gateware-ext-prec-tx-dsp-chain.png and /dev/null differ diff --git a/docs/images/gateware-ext-prec-tx-dsp-chain.svg b/docs/images/gateware-ext-prec-tx-dsp-chain.svg deleted file mode 100644 index 707ef6c3..00000000 --- a/docs/images/gateware-ext-prec-tx-dsp-chain.svg +++ /dev/null @@ -1,4 +0,0 @@ - - -eyJ2ZXJzaW9uIjoiMSIsImVuY29kaW5nIjoiYnN0cmluZyIsImNvbXByZXNzZWQiOnRydWUsImVuY29kZWQiOiJ4nO1Z2VLbSFx1MDAxNH3nK1xcnldQel/yxjrxXGaLwVAwSyolW42tIEtGkiFL8e9zWzZabNlcdTAwMTiGQCZcdTAwMTNRRcm93r59zrm3W1/XXHUwMDFhjWb6eWSab1x1MDAxYk3zqedcdTAwMDa+XHUwMDE3u7fNdVt+Y+LEj0KoXCLZ7yRcdTAwMWHHvazlIE1Hyds3b4pcdTAwMWVOL1x1MDAxYU56mcBcZk2YJtDuL/jdaHzN/kON79m+p8zEvJNcdTAwMWOP37VGZ6fB2a3Z+bibdc1cdTAwMWHdXHUwMDFiXHUwMDEzm17qhv3AXHUwMDE0VZ+gnFHqaMFcdTAwMTjHSHHKXHUwMDE5y2s/Q60m2sFcdTAwMTRrLrDgnGic1976XjqAXHUwMDE2QmpHYkw5ktBcdTAwMThrmrdcdTAwMThcdTAwMTi/P0ihXHQm3CFcdTAwMTIjSjVlnMJL3mZi0NtcdTAwMDbKS5I0jq7Mdlx1MDAxNESxtfpcdTAwMTds7F9hc9ftXfXjaFx1MDAxY3pFm8vLnu7pos2lXHUwMDFmXHUwMDA0nfRzNjI4XHUwMDE5XHUwMDFj2pxcdTAwMTn/fGo9mSlf1Fx1MDAwYibsXHUwMDBmQpMkXHUwMDE1W6OR2/NT6yeMilJr3ajlZfv1vrApdoemZTcsXHUwMDFjXHUwMDA3QV7sh56x29Ds4s3KdKE3na7SPDHGXHUwMDBlgaVcdTAwMTaKXHStZV5TYItcdTAwMTEyW3pcdTAwMTiFXHUwMDE5zjChkjKCS/38ZFx1MDAwN1x1MDAwMJZmw166QWJcbk9bI3ZL4CtcdTAwMTYzXHUwMDFleW46tURqhYTmXHUwMDFjoWLQwFx1MDAwZq9mTVx1MDAwZqLeVTFLVnq3Xofnrcs+v1x0qdy49kLe0ofph/Pj7sp4tnhcdTAwMDSEcSVcdTAwMDRRiGNRxbOQXHUwMDBl4JAjzlx1MDAxNEWU6Tk8XHUwMDEzxFx1MDAxZFR+9DygmXaYLj3q2fFsn/86nvdcdTAwMWWBZ4awJKRcdTAwMWXPXHUwMDE49nEhoCVTXHUwMDE20SXZeVx1MDAwNKCnXHUwMDE1XHUwMDA1XHUwMDAyK1x1MDAwMEvNpzRfQlx0n2r3ZGe/e8A628Ptsf6yd9GSO2Ezb3e3Xj/spPPg3UmqWu3u79t70YfBvt44P9w/r85yP79cdTAwMWLH0e2q435s6+OtUXRxe33UPVx1MDAxZW7GbX1w/G61cadvL8Tueu/Nsbvi/Fx0sTV2iCU2RCpcdTAwMDJokVViXHUwMDAz7YlaRmyskKMsoSmoguRSzfOa8Oclclx1MDAxYbthMnJjwNtLkVx1MDAxOX8jMv/6XGIyXHUwMDBixJGGXHUwMDEwVUtmTOaK78lMXHUwMDEwg1RcdTAwMDNpwZ9C5ufEb1x1MDAwMUdcdTAwMGJDcEArTE08ilx1MDAwMjdcdTAwMDV7XHUwMDFiSer2TVLa0ihMO/6XyVx1MDAxYSqle+7QXHUwMDBm7Fx1MDAxZYjKkJuB37feaPaMXHUwMDFkuFn2SOpDXG6YN1x1MDAxOPqeV1x1MDAwZXE9XHUwMDE41PVDXHUwMDEzt1aJlVHs9/3QXHJOV1qGO06jXHUwMDEzk0xcdTAwMTaSxmNT9ph5l6dzXHUwMDBl4UtcYv6ZXGbD06M/bvg1XHUwMDFhjLzNXHUwMDEzwlx1MDAwZY9OVyF4KVx1MDAxMyVcdTAwMTJpVcDfOlBp6mBGtaRcdTAwMDJcdTAwMTjORVGbXHUwMDEznFCHllx0XnDhR2L4t1xu1789guFEMK0gXHUwMDA15WXgTlx1MDAxOS5L6f1stFx1MDAwNiaCRENa9t1cdTAwMTH89KKx02k3elx1MDAwMyDXc1x1MDAxMDswl+lcdTAwMTJap9FoXHUwMDExpytWz1x1MDAxMrjezOchbnt89Sc6iL4kvyc4XHUwMDE4dM8vTkQsV867JVKOwoRcYiFcdTAwMTjSxVx1MDAwNk/gqSA6cySYkJRcYlWKvTl5XHUwMDE5d7hcdTAwMDJcXCFAlcXJPHd5sVx1MDAwM1x1MDAwZnNXXHRltPg/pNnH9bwtcsT7naPTkrvC+Hs6w2FJg/d1XHUwMDE5sFM6g9YuojOnQlx1MDAwMp/Jk9j8tNw7PPvY9sjw7GDbhF2yMVx1MDAxNPu7x19WzZHjLd7ekPuD8Ijs6tPt3vl1lOx9jzly/SpXXGKhklxih8OWKCmZYJKRXHUwMDE5XHUwMDFhavZcdTAwMTBccjFyUHakhd6Y4JpcdTAwMTDKftKwjoYnq4dPgimmXGLcX8c3jcRcIr5cdFwiJIYkmTyFb/XQhVx1MDAwM5FcdTAwMDBcdTAwMDJDykRcdTAwMWVcdTAwMDHduei55/bSKE7e/lx1MDAxZGKx3qBkvSHYutWV2lBaupN5iVx1MDAxY/mBuDZcdTAwMWJiV1jL88Tb5XI0I0VVmivsXGJtOcwg2ipZ4GhcdTAwMWFt6Vx1MDAwMzRHjr2shUrCsMSIlSCV81xcgFx1MDAxMiimXHUwMDEx5lpcdTAwMTJKXHUwMDFldWn7SrT33GRgXpj3nUfwXnFifVl3LubzpXnWrCiVXHUwMDEyjjWvfmmbXHUwMDE3j1wifzaMXHUwMDE3b43C19mP/P39en3rhWC0z8ZcdTAwMWNcdTAwMGWL8eaiMpxo43RcdTAwMGJ2x1x1MDAwZvvVXHUwMDFjaPpcdTAwMTFlXHUwMDE1RYDWw8jLXHUwMDAwXHUwMDE1xV2/nIdcdTAwMDBIP1x1MDAxOa9tV19ZvF1cdTAwMDT4XHUwMDEyL1j3XFziZUKvsLJcblx1MDAxNbuCTUv5gXHncFx1MDAwN/3KdXD89GdScVx1MDAxM3Sj25pcdTAwMWTLXGbvmP49LuYnbSWdken5blAz6cK6YXRjXHUwMDBl/IlHknM/XHUwMDFkTKG3QpKz/CZ0mfyBrFWu+GduXHUwMDAyNXZAIC2WtMKKXHUwMDE1upVf8UvhXGJE4PyqkKZKXHUwMDE1/XPxQ1x1MDAwZSWMXHTFYFx1MDAxY8GZZj8/WdWJ3+nq4lx1MDAwNykl4japrFx1MDAxMT86f/LIxY9Km6Dw0oXuMyQ9TGjYUy6LjOO1xG9jIVx1MDAxOLPaeVx1MDAxY/579Vt+Z/g09ausOZPC51G/OoWramBVqqrqt0R9ln8vWaY+XHUwMDE4c+5cdTAwMTBFJLdwXHUwMDA2LapRXHUwMDFmxfjkO0RxNM7FR3BcdTAwMDdLjWG/IXmDo0Dxwb1Qn59iUyM2Z4/ItFx1MDAxMFdYXHUwMDEwKetOWISw2dJ7tbE5NaGodOz9wcRmIfhm+j+kLbNcdMKrqFx1MDAwZa5+qEeokjg+KEPfRGzWpk5ruqNRJ1x1MDAwNVx1MDAxNOQuad745nZr8UFobWqbZafJbvDu1u7+XHUwMDAxkVx1MDAxMOB/In0=Interpolation stagesTX DSP chainFactors:16, 32, 64, 128 \ No newline at end of file diff --git a/docs/images/gateware-halfprec-dsp-chain.png b/docs/images/gateware-halfprec-dsp-chain.png deleted file mode 100644 index a0b6c5ed..00000000 Binary files a/docs/images/gateware-halfprec-dsp-chain.png and /dev/null differ diff --git a/docs/images/gateware-halfprec-dsp-chain.svg b/docs/images/gateware-halfprec-dsp-chain.svg deleted file mode 100644 index fa0aa1e7..00000000 --- a/docs/images/gateware-halfprec-dsp-chain.svg +++ /dev/null @@ -1,4 +0,0 @@ - - -eyJ2ZXJzaW9uIjoiMSIsImVuY29kaW5nIjoiYnN0cmluZyIsImNvbXByZXNzZWQiOnRydWUsImVuY29kZWQiOiJ4nO1ba1faSFx1MDAxOP7eX8Fxv5Z07pd+XHUwMDAzldW1VVx1MDAxMbva7tnTXHUwMDEzIEI0JFx1MDAxOIKoe/rf901EkpCLQNPWtrLnbDGTmUxmnue9PPPy36tabSu4XHUwMDFiW1tva1vWbc907L5vzrZeh9dvLH9iey40kejviTf1e9GdwyBcdTAwMThP3r55XHUwMDEz9zB63uihl+VYI8tcciZw3z/wd632X/R/aLH7YV98Izv9XHRvKlx1MDAxM1x1MDAwZqzGYa/eXHJmR1HX6KbHyfhWLzDdgWPFTbdwnVFqaMFcdTAwMThHUkmBqVq03kGrYNRQhFwiTTFnQiZaZ3Y/XHUwMDE4hndIbUiMKfTXRGNNXHUwMDE3d1xmLXswXGbgXHUwMDE2TLhBJEaUaso4hS+Le1x1MDAxZSb0toZcdTAwMTZXJoHvXVnbnuP54az/wFb4Xzznrtm7XHUwMDFh+N7U7cf3mLyvLi7iey5sx+lcdTAwMDR30ciwyLCgW0vjn81nT5auXHUwMDE39YJcdTAwMDdcdTAwMGWGrjWZpObqjc2eXHUwMDFkhOuEUXw1nN14v1x1MDAxZu3Xv/GcfHNk7YdcdTAwMWLmTlx1MDAxZGdx2Xb7VrhcclufblJPc/vzp6XunlhWOFx1MDAwMtNIcS3jZYyBRSlZvnrouVx1MDAxMchgd6RAXFzi+OGTXHUwMDFkXHUwMDAwV1x1MDAxMI15YTpcdTAwMTMrXuVwXHUwMDA2u1x04MUvMlx1MDAxZPfNhy5YSq1gX6XERC7aXHUwMDFk271anrfj9a7ip0RXv7zOw3Ljvd9cdTAwMTX9v+uHXHUwMDFlac66XHUwMDFmqX1w0GxmsVx1MDAxY1i3QSGMiaZcXHKZxjGShqJcdTAwMWNjJKjkXGLJXGaOMWFcdTAwMDZcZkIpXHUwMDAzKHNYXpZcdTAwMDUy4dVcdTAwMDI38E13MjZ9WOSfXHUwMDFivF3krI5ejFx1MDAxNZhcdFx1MDAwMluRg1+BWVx1MDAxMX45w5grTemPxm9cZsdcdTAwMTCG8Pon57WdznGtNzRtN7GRnlx1MDAxYnTs+4h6KHW1ZY5sJ4JlaqiGY1x1MDAwZsI12HKsi1x1MDAwNCBgXHUwMDE5XHUwMDAyXHUwMDFi3MKiOfDGcWtcdTAwMGbGg8dafnZ7PN9cdTAwMWXYrumclk7TnFx1MDAwNt6JNXmYaOBPreRKWHtcdTAwMGIjblx1MDAxMF5CXFx9dDZcdTAwMWIzb3zFJi25Z3kmXHUwMDFhje+yxDV935ulmUuVNlx1MDAxMGaKYqaFVIn9XHUwMDBmV0hcImEwXHUwMDAx5CSwR1IpnSWuklx1MDAwNngmRmFcYspJnlx1MDAwM0LwXHUwMDAwXHUwMDBlvkdppbgkQsbPeOFxmse3+Tx+3O14K8n8ypdlesOOMcKVTOJ3Tm7JMy7rkdywP4TB1rBcbtmtXHUwMDEwXHUwMDEzWnCRfOxcdTAwMWHsXHUwMDFle3Yy6lxuP/G3WrxcdTAwMDPRXHUwMDFmi+//vs69u1x1MDAxMKVR71xmPuPhXi1cclx1MDAwYlx1MDAxODH9oFx0W2a7g+U3sdx+QUvUq1x1MDAxMbJvaJn9XHUwMDA30NpL4SD0Tt6RXHUwMDFl2el6s5xFXHUwMDFheTfWe7t/XHUwMDFjrdWZXHUwMDFkXGbn27KCr1x1MDAxZnnmZNS4PT1jl3V60fXsk8O/XHUwMDBlVzJcdTAwMTlaXHRcdTAwMDNgRpWgXHUwMDE0QTxcdTAwMTlcdTAwMWKF2GQoXHUwMDAyK6oohKcx2Vx1MDAxNyZDXHUwMDEyXHUwMDAzXHUwMDFjXHLmhHKtOM1x9bAlXGJcdTAwMTFKhFawXHUwMDFmOlxmXHRwXHUwMDFj/L5YjbTVuPtqq1x1MDAwMelcdTAwMDXjXHUwMDEwn4m8oFx1MDAxNsK2wqhcdTAwMTbCXGItJUL6VzVcdTAwMWNFWFxyP/VcXJj+XHUwMDBlxuOUWT7vTNrTvf3xh1Pnw8zaudxdP+nFkEhRgF7KgEBcdTAwMWVrYIo1XHUwMDE3WHCw1XHC9JyS3ouLnu7pn9xy4MZcdTAwMWF5g9RCXHUwMDAxMXVeaMFIJptYWFxioSFhRlx1MDAwMv3wxKFcdTAwMDTPzYtcdTAwMDG/camsX/ddvq9cdTAwMGaDz2ft7sp4XHUwMDBl8VxiXGLjSlxiolx1MDAxMMdcIo1nIVxywCFcdTAwMThcdTAwMDdcYj5cdTAwMTBl2Vx1MDAxOJogXHUwMDFlXHUwMDFhkvijs4Bm2mA68anYXHUwMDFiXHUwMDAynsPPz47n1lx1MDAxYXhmXGKMO8nHMyaqMFx1MDAxMYZOglwihDdcdTAwMTJyXHUwMDE2ziF2zlx1MDAwYlx1MDAxMKrdk5133fessz3anur71vm+3IkzxVx1MDAxNFx1MDAxMKPUd9Hw5XXZsMO9k0DtXHUwMDFmd1x1MDAwZrZb3ufhO10/O3x3lj/sQ7C34riXx7rdXHUwMDFje+ez66Nue9Twj/X79t5q42ZcdTAwMWNjPrlVNeQuX9dcdTAwMTJVXHUwMDBiQlx1MDAxYkMqoVx00vBcdTAwMGaVS7xcdTAwMDbWXHUwMDEzVcZrXGbMXHUwMDE3oaiFXHSkXHUwMDE2RGGS5fUvIGrhb0TmP9cgs0BcdTAwMWNpcFG5ZMZcdTAwMWNcdTAwMTWRXHUwMDE5Ylx1MDAwNM1cdE7ky1x1MDAxNTgncJRgoelm4eujqrV7XHUwMDFiQFBXXHUwMDBivJqqd+2gtv+mXYW41YPJW36JvDWy+/2kg0srXFxPecpl0av0LarRvu7IyD09+njDr9Fw3G+cXHUwMDEwdnh0upZoXHL5jURcdTAwMTDCp+itNDUwo1pSXHUwMDAx/OZcIm6NNWtq0NBdU/D5kktcdTAwMTVcdTAwMTPhV6L3t/LVf61Bb1wimFZAK57E7aOshTKkX7BcdTAwMWKB6WWYVZmdViRan/5cdTAwMWOidf40qyFueWBSpkBcdEnLXHUwMDAybo2NUMnGYNshXHUwMDFmZ1lcdTAwMDWKSGFcYkRcdTAwMDBQXG5pqlTcP6FAUcJcdTAwMThkPDCO4Fx1MDAwMlVcdTAwMWZv/1xu+ePp6lx1MDAxY4aUXHUwMDA1XCIlyXBcdTAwMTKki2PTwmibKYS5XHUwMDE0skJcdTAwMDdcdTAwMWTpS5xrMFxymzC4Un2pXlxixag1g8J4vExcZr0kLiXUv3lcdMMqXHUwMDBlvFx1MDAxNspC/VxiTp5cdTAwMGZcdTAwMGU72XBh31pcdTAwMGZqUerll1/Z4JBcdTAwMWNl5lx1MDAxOUuOP5XQVZ7klNkoiDo55Fx1MDAwN0TyXHUwMDEw9VwiUS5cdTAwMTDbKMX4Q/JcdTAwMTD7tYWJXHUwMDEy3IB4XHUwMDE2XHUwMDAzLlx1MDAxOFi5vNQhpu+LSYpN0ofVTVx1MDAxMlx09VpBwKXn2CRCMlfjsIJJyFxyXHSvsJbjeVx1MDAxOaVcIvAtdX/KXHUwMDA2XHUwMDE1XHUwMDBi3N/ROuG0toZQ+m2eMlfP0Ci977mSbX/g7+5uXHUwMDBmXHUwMDA2nfp9bzjw0MpqJYSvhpI8VGSFojhdcVx1MDAwNjBcdTAwMDSjJSlcIlx1MDAxMD2Bw8lmPVxuXHUwMDFiXHUwMDAwXHTBMURf4LZ0TuxEw3NcdTAwMTGmOVxutX3KwcatYamUUJZcdTAwMTa/g1j596rHdjRcdTAwMGLKXHUwMDA3XHUwMDAzxjXDmlKVZ78kL5TkXHUwMDE5h1CMk81cdTAwMTT5xexyJMFb11He5Hra4uxcdTAwMTS3XHUwMDBlxp/a15PGVpJum0mNXHUwMDFme1x1MDAwN/fjY7IzpXrUu79u3e01XHUwMDBld1ZSRjNcdTAwMTYqe9CIXHUwMDA0IH1ccptbQszyeZZIXHUwMDExSoVcdTAwMDVyXHUwMDFhXHUwMDEyXHUwMDE2KqRglC6RMlRcdTAwMWG1lJIyJWW2XG6UaUOGOiNkRNBbMJVXPbdOuPD7kPBs9XBcdTAwMDFcdTAwMDDDXHSjXHUwMDA051x1MDAxZJJcdTAwMGJSqDFiTFxiwbCpelx1MDAxM75VXHTdXHUwMDE4iY/ynGt2k/4hoT8kkurvoSs+4dMyuuLSxKtRJE7Oj3a8XfdMclNMPu9eXHUwMDBlu62RXt2xMjavi4FMLqymSpFYgONkVDCiXHSkXHUwMDA2XCLvuIByI3nEl1x1MDAxMLOLj1x1MDAwMeOHvJxcdTAwMDPGrD5fh9WcSFxmVjNPmMBSXHUwMDE2ioswT1x1MDAwZTGy2qxmrszd/dncbrJcdTAwMDa5PJ/dXFw1d4/Odi/b2F/J3ZV60W/lncfKufx8fHCpj0xnXHUwMDFiXHUwMDA391x1MDAxZph/VcVB4LxcdTAwMGVIaVbRKX/5upa5Z1ximUuYrakhVFx1MDAxObPVy8HfOuz9uIaqKFC4MTj33C95aLNM3uhcXJclq4uei0/e2a51w1uew2nfXHUwMDEzXHUwMDBlcdkrZ6dejV+2W5/2fLTf9vbZSdup351cXOJcdTAwMWSxsl/milx1MDAwMD9cdTAwMTVcdTAwMTFz9qbrVZ/2yy/lOVVcdTAwMTH701x1MDAxYW5cdTAwMTlrzlx1MDAwNaIo1y1rpZYvL5itgYdMbFx1MDAxOG2X+bmLsXvsdO6mreOPnVtZ327ttVx1MDAwZiuoz/m27lNgjdepQyhhYfn7l9XRIGpwXG5cdTAwMDRkYVGvTpd7Pu09sVg6Z39xpmtwzlxcg3NcdTAwMWFBXHUwMDBlI7HK5Vx1MDAxYyS/hZwjklx1MDAxMsE5qzzDpWC0N1x1MDAxMsRcdTAwMTc/XHUwMDBlXHUwMDBin1x1MDAxNtafsOdURfOEQ8v8dKzkJarxsOW5QemvQTAxJGZR0Vx1MDAxM0VcIlFcdTAwMTZcdTAwMTn9XHUwMDFhRKsn9ORIK+ZcdTAwMDA7sNiSc1xuVj9HvVx1MDAxMtigXHUwMDFjKXDeXHUwMDFjvCtH66S9P0jM6puTofWdXHUwMDFkbHdcdTAwMWSyQ0BEwa7m1dRgJIpcdTAwMWSsXHUwMDEwSnJK5fORsyo9/SpcdTAwMDNk+KlnsFx1MDAxOI+YccgrXHUwMDFlyperX7WNXHUwMDBl5aODrYI3n38rOJQvmmV5NlDRLLPHdSXTzlx1MDAxY84tnzg+dXBXcDhcdTAwMTfNt2Ncclx1MDAxZWGbLVPYn3TGVs82nZyHXHUwMDE2tn3FmV95lFhmoFx1MDAxNVUl4kX4c70wRJSF4Vx1MDAxN4PsXHUwMDA3Qlx1MDAwMjzPbEROleNLJUKeMe6tU+DIXHSTXGbMTZ4x5sXVUVx1MDAxMlx1MDAxYyvs6iYqRmpcdTAwMWU5iVx1MDAwM8csXoNcdTAwMWZWilCIvqXum1reb2HTUlNcXKtcdTAwMWOqaJbl8eJGs6y6LOLrLO+D5Xs138AtczzuXHUwMDA0XHUwMDAwyMWSbN3Y1qxZXHUwMDFjuL2azy00XHUwMDE1VnSK/uXVl/9cdTAwMDEsMploIn0=RX DSP chainExtend to 8-bit I/QTX DSP chainEnableDC blockRound to 4-bit I/Q \ No newline at end of file diff --git a/docs/images/gateware-rx-only-basic-block-diagram.png b/docs/images/gateware-rx-only-basic-block-diagram.png deleted file mode 100644 index 421ae2c7..00000000 Binary files a/docs/images/gateware-rx-only-basic-block-diagram.png and /dev/null differ diff --git a/docs/images/gateware-rx-only-basic-block-diagram.svg b/docs/images/gateware-rx-only-basic-block-diagram.svg deleted file mode 100644 index bf470a17..00000000 --- a/docs/images/gateware-rx-only-basic-block-diagram.svg +++ /dev/null @@ -1,4 +0,0 @@ - - -eyJ2ZXJzaW9uIjoiMSIsImVuY29kaW5nIjoiYnN0cmluZyIsImNvbXByZXNzZWQiOnRydWUsImVuY29kZWQiOiJ4nO1d2XLiyFx1MDAxMn3vr3D4vjaaytpr3mjjfaPbu+/ccFxiXHUwMDEwoDabXHUwMDAxL3hi/v1mYVx1MDAxYklIXGKE5W6Pw3SMx9ZSVKky85zMyiz9/WVlZXU46nmrf66selx1MDAwZlW35df67v3qV3v8zutcdTAwMGb8blx1MDAwN0/R8d+D7m2/Or6yOVx1MDAxY/ZcdTAwMDZ//vFHcIdT7baf7vJaXtvrXGZcdTAwMDd43X/x75WVv8c/8Yxfs/deNM/o7ujuql4oVbav6i2v2aSn41vHXHUwMDE3vXSm71WHbqfR8oJTXHUwMDBmeFxcMO1wKTVcdTAwMDFuqKJCTs6O8GyBa4dcYmXwnz3HXHUwMDE5nZy+92vDJl7CXHJzJDFcdTAwMDZcZlx1MDAwM8KUXHUwMDExkyuant9oXHUwMDBl7Wg1OFx1MDAwMlxiMDBaaS745JKnXHUwMDBl/blCJkdcdTAwMDbDfvfaW+u2un3b6/+AZ/9cdTAwMDV9rrjV60a/e9upXHUwMDA119THn+Caut9qXHUwMDFkXHJH45bxIeNcdTAwMDNdnWr/7LnzdOr4rLvwXHUwMDBiXHUwMDFizY43XHUwMDE4RPra7blVf2ifXHUwMDEzkOCo7V1vuzaer/9cdTAwMDV96rttb9tOWOe21ZpcdTAwMWP2OzXPTsPq5TDybZ3a87dFrlx1MDAxZXiebYFcdTAwMGIhqVx1MDAwNFx1MDAxNjzHQLKA89jhg25nLGaUaU6lYkFf/UFcdMVrOG617rZcdTAwMDZe8JxtXHUwMDFm1kOiXHUwMDE3XGbltldzn25cdTAwMDGlXHSRnEtNZfCtLb9zPd3zVrd6XHUwMDFkfMv46D9fk6S53+tcbulcdTAwMTd/XGbd9qj/sOOLm59bN1x1MDAwYkszSrCD4zNcdTAwMDL7pFhMmlx1MDAwNXEkaFBCK0GlXHUwMDExIGLiTIE4nFx1MDAxYk3wZsVcdFxinSTP3CGKMKqe2/mU57g83y8uzyBcdFx1MDAxYSCGZihBoLVms+RcdTAwMTm4UspIQmneXHUwMDAyrVCNIFx1MDAxZoG+OamU5F79bHR0f7R+8qM8gDatLyzQhmhHXHUwMDEzNL7mSaBFVKCBoSAqYTjHh0BQ+nVMoIFSR4OQhlx1MDAxMTS9ilx1MDAwM8RcdTAwMDVaS8dcdTAwMDDFdsBcdTAwMWFyLfM20K6o6X+9QD9sLi7RRlx1MDAxYsJcciiTINCGxsR8XCLQRCptOFx1MDAxNUtZ6OdcdTAwMTOBXHUwMDA0hqSwtv1QqT6sXHUwMDE1Ovvt01x1MDAxMpR33fJN20zGXHUwMDEzkUS33+/er07O/PM1rV3eO14vnVx1MDAxZmx8q+5tsmH52uyvlcvJ7Vx1MDAwZb2H4aLNbq3vXHUwMDE2XHUwMDFh3X3wXG7175detaaborBgd59/S9Fuxlx1MDAwNf6Wj3anjz869qhiM+IoTSlcdTAwMDcpXGZBVI4otnBcdTAwMThii0aAQq3EXHUwMDBi4rRLoV2Q+NGKXHUwMDAwKNBcdDBcdTAwMTWSolxc1HjYdzuDnttHefu3q/JpXHUwMDA2cEJWq/E7eVxmhqzhXHUwMDE0M3XZIKRpXCJcYiyjysnSq4yRaFe01lnIViCMVlxicfjF0tpfXHUwMDFkvzP0+nW3XHUwMDFhmvJ6tzM88lx1MDAxZsdMkUSObrhtv2WfvYw0Vmz5XHL7XHUwMDE0VquebW01/CiGPnoyk1x1MDAwYtp+rVx1MDAxNoa2Kjbq+lx1MDAxZK+/vVxiRnb7fsPvuK3jYFx1MDAwMCtcdP13b4fdXHUwMDFm3uBpXHUwMDA0w/6tXHUwMDE3fkje1otagENFikZcdTAwMWa6ZLChL3Yv5NlGcXR1eDHY+Xa/MF5cdTAwMDPRyuGKXHRBXHUwMDAx/5M6QIAoXHUwMDAzVZKhY0V48ERjXGaUSVwimFx1MDAwMpLoUb0w0Jd2PiloXFzNR4truVx1MDAxNJSjtuokXHUwMDA2XG7hrkxpOUP6r1xmzlbuXGaUh1x1MDAxYn1cdTAwMTVGeeXSjfDvKqVBa3/jiJOu2iolXHUwMDA0XGKegDRcIs3SWDFjXHUwMDE0u8KQzfAo+0Rwclx1MDAxMJ7wySkplSBExWR5XHUwMDFjXHUwMDFi4MBcYt4umTJcdNxcdTAwMTM9NmSvTFx1MDAxOM1cclx1MDAwMzRwXHUwMDE5JFlL7Vx1MDAxOflbQKvmXHUwMDBlmt6vXHUwMDE158fFxVx1MDAxOW2I0FpRkVx1MDAxOFwioFxuZsmzvVFcbkVV/jFcdTAwMDJcYmtXXHUwMDA22Op1/WmCXHUwMDFi/LZcdTAwMTI87PFcdTAwMWaT3//3NfHqmVx1MDAwMvn6u1x1MDAwYjFJXHUwMDBlmouR0sHQ7Vx1MDAwZr/h3PqdXHUwMDA2XHUwMDBlLaDAL+G+J2AkN2c/XHUwMDA2XHUwMDE3Pc/b2W9cdTAwMWPv3m6sb1xmT9ZDPHi13a2NxbHbr/jD8Im6/+DVyvbRRZ7cXG7CXHUwMDFm9l5cdTAwMWJglKEzSIiOPFx1MDAwMVx1MDAwN1VcdTAwMWRpJ/7QNlgnaWxcZlx1MDAxM+K+6nVq80dwdXn0uKtkoXRdO9+/XHUwMDE5kn3dPi2+blx1MDAwNLaThjGBPjrOXHUwMDA2XHUwMDAzqdTX6Fx1MDAwMCV2XHUwMDFmXSnkX2izXHUwMDE4T1x1MDAxOcN4XHUwMDFlitbyNT03pns4wvA5NCb+XHUwMDE05nutSvd+LLRcdTAwMTHCMe77kdd40Yyojtrv3Fx1MDAxZVx1MDAxY/W8qu+2XHUwMDEyvnP6XFyKbb91XHUwMDA37v366UW/w/3e2fre4SWqzsJsXHUwMDA1XHUwMDE5hsOkXHUwMDE4442hYFjUXHUwMDBiseFcdTAwMDWjJUVHXHUwMDAzT6E7YuLxsiC8XHUwMDAw3KpFiPBcdTAwMDThXHUwMDA15Whcbuh1PTVcdTAwMTNYgXy4SoXWaaXy7+Yq7uHixl0xdFx1MDAxOI2BXHUwMDE4KbGPWurpo5PgXHUwMDAy+lwiaNp1KGycU3Dhe/Ho8q7VumxteuKAbO6VOlx1MDAwN98uX1x1MDAxZlx1MDAwNPjWk7DfuNhsr3Xq/Ye19vHPs6uLXHUwMDFjYlx1MDAxNm9cdTAwMWJcXGBcIrxcdTAwMDbyKuKW/lxcU4JcdTAwMGKoh1xiVJJynHItXHUwMDE4TPE29FAo53hcdTAwMTGeXHUwMDAyXHUwMDEydlx1MDAxZV602tpcdTAwMDX7oUSCQm6XXHUwMDE0XHUwMDA0zznq/WGiXHUwMDBibnlxVcbZXHUwMDExmiGVSOJpis6kacCUpnhnyH3Mh6ZlXHUwMDE230BcdTAwMWGfnfOjzfJ2yJj9vqDCXHUwMDFjaJxcdTAwMGUqTPU7n2BCOvuZXHUwMDA3z1xuqCOU9e9cdTAwMDE00s6pWFx1MDAwMqIzVZSg30WQbUpcdTAwMWVXYzT5XHUwMDBlJ1pySdFJMyoplIDgjDZcdTAwMDCRQVwi/lx1MDAxYqlcdTAwMDNF+oz9T1T6e1x1MDAwNnRWklx1MDAwMeGhNalAo5mauZZFiUZcdTAwMDfbXHUwMDE4vtRaVlx1MDAxYdzRb3fNXHUwMDFk3z/c5o/HJ/euvzV42D57PTq/1YpCaX9fN0/uz9tUXHUwMDBlvvPvpHk56vdyaDc9XG6S2u5cdTAwMDKoL7nSKmxcIpZH/fT5SkF9dPdcdTAwMWQhUZfRYlxi9OFiqK+QqCNcdTAwMTEnSqF7XHUwMDFhXHUwMDBm1lx1MDAwMOVcdTAwMGW3qM+ZIFx1MDAwMtl+YFA+UX++iciwpoAsXVCi4lx1MDAwYoHWRsRcdTAwMTdcdTAwMWEmqK9xXlxm1yE37b2sKfw4XylcdTAwMWSVV6pNXHUwMDA04PdcdTAwMDD+c4B3XHUwMDFh/JO7n9OCQrV9bVxu+nrjorB3RnrNi3p95C6zoGCYYCTkvb2QXHUwMDAwzVHruVx1MDAwNqltJkBCXHUwMDA2wFwiLOAzXHUwMDAzYL6KV1x1MDAxNtdwY2zQXFyoJFx1MDAxZl2JlPArJ0ZIXHUwMDAzS2l4XHUwMDFh/NXP21e8tLtdVK39+ulVr/ZjIDtcdTAwMGKxgFT0W858pGhLej9T0Fx1MDAwZoCDXHUwMDAzNiVLakBIXHUwMDA2XHUwMDE2UVx1MDAxNIQ/6+sqVCVNNGNx+OPMQdk3RnPFXHUwMDAxUfJcdTAwMTP+suhGNYPTy1x1MDAwNTNM0UT4k7PXJlx1MDAwMKdNKibpu1xcUn9cdTAwMGaoN1x1MDAwN2pcdTAwMTLW0fNcdTAwMDa75maxt/F4XHRcdTAwMGZcdTAwMTfkYueuoTvFarO0iPpcdTAwMDaZm0xLXGJcdMFcdTAwMTjlrJMqhFx1MDAwNoriYVxipfE4NFx1MDAxN1x1MDAwZbXaayhTRFx1MDAxMpG0aP6pvDOU18+gvIJIVEEqk/zbcNJkLGJlXHUwMDE0slx1MDAwZmreRHlZWFizKu/+2klcdTAwMWXK2/Lqw1x1MDAxNNVcdTAwMWR2e7P0NtLZaSWN9C5cdTAwMWYlLVx1MDAxNvp7m+6t7vXgdHercvyjPLh8yL5ohD84ejFcdTAwMDHhXHUwMDFjSyNlXHUwMDBlaEI1Z6isQqmEqFx1MDAxNFx1MDAwNUdcbirQU+VEUJ1UMiCMg+4sXHUwMDEwyiUg7YXcc6w/xKLRz8X1lkslhVaJi0ZcdTAwMTCOXHUwMDA2TOuttCutXG5nNG9GurW5dbKzUXvY6V+Qy+bjkfx5R4dcdTAwMGIx0q9pzfJz2lx1MDAxMKdra71cdTAwMGLvhFx1MDAxY69cdTAwMWaOXHUwMDFlR416crPZ4zzcXG5sTkw3ffwpUMmJdKxiXGJCXHUwMDE5OmuhiOFYrDhxUC81eoxCccZcdTAwMTmLKSB7Xt1haD5cdTAwMDHCfOpcdTAwMTMr5+rc9eI6J1x1MDAwMFx1MDAxNFMwQ+dYXGZBX3ROWD+f8eWywNOlXHUwMDE3zfNroPKovP1cdTAwMWV47lx1MDAxY1x1MDAwMIst7YR7nVx1MDAwZoSmJ+bML7pTjpRcXFx1MDAxMiaBszBGPlx0qbb5XHUwMDEyhiPqKVwiQMazv9/Dws6HQNBOXHUwMDA25iupYFooXHUwMDE2y7CwXHUwMDBmW8zUZkAuZG9drkopXHLqTs9cdTAwMWJFfjeCjXqxcHDrN+RVkd6+XHUwMDFlQV+xUvJWyJzarto+6P9sjjr1q7K7Y6rtbqmyX32PiJ8+XymILyRzOFx1MDAwMrp1blGbp1xit3JYOFx1MDAwYjeO9+azVmR5XHUwMDBi0c2QRE5cZoI250musYbZrrGg6Fx1MDAxYmtcdLknkWeV3SS8X7HY2++2/ur0vYY/QNxcdTAwMWW8XHUwMDA3XG4wXHUwMDA3gFx1MDAxMyjAy0BWXHUwMDEyxpFcdTAwMGYpOLi4Wz9Qt5U1MyhcdTAwMWU23IJcdTAwMTi11k1cdTAwMDZSoFx1MDAxZGSFKECCaCFIfKFnnO1cdTAwMDFUXHUwMDEyKVx1MDAxOUmIgS2YizlmXHUwMDA18rmZvFx1MDAxN3o+XHUwMDAyK6hcdTAwMTCeYaVHaGRYWiWxgrTKXHUwMDExQFx1MDAwN04ztN65p2M+XHUwMDE2y63SNavf3Fx1MDAxY1xct+/IIS9ublx1MDAxZbzfdMy3Svh4U1rAcMJlTlx0XHUwMDFm6fOVRlx1MDAwYjh3XGbTXHUwMDA0XGZcdTAwMDFpwlx0KE81pNTme4CWXHUwMDA2oZ+bOC9cdTAwMDBiXHUwMDFjsMSAo1soXHUwMDE4elx1MDAxYZ/EIIORXHUwMDEwWZa8gKKNICwpXHUwMDE0YMzMXHUwMDFkO2z0zVYwmKWMRGqeJ4HQ4vSyeZ4rbqf2V6fe6t6/oOt74Fx1MDAwNnNwODHz045kJXkg+ZCDdPOZVoXHtbEhdVszXG5GXHUwMDAy0OiuJtQ4WoNcdTAwMDRcIlx0UYxcdTAwMTBcdTAwMWVcdTAwMGZcdTAwMTdwinZcdTAwMDKRxtbFXHUwMDE4JFx1MDAwNlx0XHUwMDAxP+IwobhcdTAwMDFcIpTgzKA3kTMz+ECKLzMovlHomymZWIjH9MxiXHJcdTAwMGVgluVcdTAwMDYpai9cdTAwMThcbsFSap9rXHUwMDE13kx5XHUwMDFj31x1MDAxZJfEoL1cdTAwMTgyL1hIl55cZr6yZCFcdTAwMWTXWjBpQFJjgp1cdTAwMDCeXHUwMDA2wfFcdTAwMTDCKqVcdTAwMWNcdTAwMDfKiVx1MDAxNLFBZKykS7dqS1xyoUCmxlx1MDAxMNquIPsoYrV0SfVy0Yq6aOXbpJYuKnr5XHUwMDE2003Otbt33r7/9FxcXHUwMDA2Z/6w+axDXHUwMDBiMLb0SFa6LddcdTAwMGWx5f9EXHUwMDE5rpicWjxcdTAwMTWoXHUwMDE4SuH/KCBGk3guXHUwMDFmZ47ktvBfI1x1MDAxNKB7XHUwMDFmUL6QJVx1MDAxN9Q6iXpM/YCGss0+XHJ51JBcdTAwMTczXHUwMDE4cvSmldaUJ+bswsycXck1RVx1MDAwNVx1MDAxM3lb8uXXcvK15LPk0X5cbnFRfL0lT1/7WcpcZlx1MDAxMsdMfaJGUFx1MDAxMFx1MDAxMu94Ruv9XHUwMDA2ldwkUy+XsM6p9c5RoXqFMd0+Lz9enFx1MDAxNlx1MDAwZb3G962T81x1MDAxZF070qejhYwpoGCNo1lEXHUwMDFiSamK+r/Ii1FJOPJcZlx1MDAwNDe7RWHcmlxu4qBcdTAwMTckuEL+zG0tXlwiL5bIRuzea5pcdTAwMTOtaPAln9Y0ak03Z1RAhFTieTJpXFw6n60sui/4XHUwMDAxSIymJWSvTPiysvlEMlQ78buzy3I1s4WZkjo+XHUwMDFiXHUwMDE30sXt7DRfmnEmv41cdTAwMTJyM1x1MDAxY+lcdTAwMTVoaYbDXHUwMDEwXHUwMDFh2VUxXHUwMDFharfpMYorhC6NpJdcdTAwMThcdTAwMWRPYWPM0YhrVFx1MDAwMkVh5Twh0I7UWoFiXHUwMDAy/XVBXHQ2l3eo/Vx1MDAwM1mOrVxma2xUMatcdTAwMDNJa2ygU1x1MDAwYiuIYeEo6McyXHUwMDEwMyVyfDZBXHUwMDE4X8/E0ndt+1x1MDAwNZTmd21AXHUwMDAzmXr5XHUwMDBlLWf6kkua5VREhkvSY4aT2q1JkHFJ677Ga2yYcezaiUC7i+4v6IRcdTAwMDVcdTAwMDewcmyUVFx1MDAxNFxiXHUwMDE4vNArfFKuWYZzd3HDSYkhQsjE7CUmZvqvjKLhVOGZzilcdTAwMTJpXHUwMDE3s4NH+fvs5iyJXHUwMDFjn01cdTAwMTLG11x1MDAxYs632Fx1MDAxMyt/w/lcdTAwMDbxxn+94TwtnVxuenj6rXZ17N81qvdnP1x1MDAwZk9cdTAwMWbjhnN2LS9cdTAwMGVaXHUwMDExxjklgk5vT09cdTAwMDV6rFx1MDAwNvk7JYjjUsb9VWp3XHUwMDBmXHUwMDFkr9xcdG3TN1x1MDAxMvxVUI6x8Vx1MDAxOGycXHUwMDE5YFmCf4l28aNcdTAwMTbzVsjF4raTXHUwMDFiidaTmcRE7jDOTS/fXHUwMDAyMjJcdTAwMDTD3HdTXHUwMDE0oJXJKSuxLLfafKu8R1x1MDAxZUeHpdvd0vd+736hOlx1MDAwNFx1MDAwMMJcdTAwMWRFXHUwMDE5XHUwMDEzxu5eYqbjL1x1MDAwMqlcdTAwMDJnUlBcclx1MDAxY59dQiGQYVx1MDAwZdhwXHUwMDFiml5Nw1umfKZcdTAwMWbMl99GluC11DZ4nSC+JlRZXHUwMDE1Sz7gyjAlVN55iXYjukzvXHUwMDBiXHSEMbRcdTAwMDN01V6zUuu2Xb/zV2fbplxmdNxW5HBcdTAwMWXJXGJvVNaXeVx1MDAwNPlkIVx1MDAxOOJvb19ccn72z+q33aPznUdf3NGFco2YduyylFx1MDAxMVJzYqZerPJSn4u20Fx1MDAxOEpcdTAwMTNeXHUwMDEzJOhTXHUwMDBlMrrLKFZcXH7WXHUwMDFjZdH1ZpaMXHUwMDAzZpBcdTAwMWSwxOp6XHUwMDFlh7BcdTAwMDCrqFwiaMjfYYHuRnmz+I5VOdq9fPR0r9pyq4Otys559fL+plHQ1cPL5kKgXHUwMDFjrImAofZNUcmaSqXdbEyx+P7zQKhD7d6PZlx1MDAxYyA1SbD8qaozVTVLLb3lPUaHX/dcdTAwMTLaXGKDzlZVXHUwMDAxdjNtSoOw83tR1WM7kVXPv1x1MDAwYufvvTuNTexlPoqbvrlsamqILYu3XHUwMDFiJCCtNlx1MDAxY1x1MDAwNI1uYKOkXHUwMDAzTElcIkBcdTAwMTD0XHUwMDFlTVxccVx1MDAwNddcdTAwMGV6loix6K4gXHUwMDFkT4JY5lx1MDAxMI183Vx1MDAxOPt2XG5mZJaiwFx1MDAwNXbbf4v3Rvz6nfYrkME3tPVcdTAwMWFKm+Sd9iFcdTAwMWVumyixwilAzyn3XHUwMDFjP3RcdTAwMGXDW4X+rsha5Oq43M27faYwv0FzzJFG4VxcXGKhXHUwMDA0sagog+a+TDX7XHUwMDFiXHUwMDEzXHUwMDBlx9l4oIVSoIlEXHUwMDE3Klx1MDAxMFx1MDAxZPtcdTAwMDGHUEnBVpIxlEdcdTAwMTNcdTAwMGZUZlxmXHUwMDAwvsX6TnhcYnanYTE1XHUwMDAyxCCG7lx1MDAwMVx1MDAwM1x1MDAwNlxcMpYyhF+0c/+sSptnW0HD/X/q09SQpzQhVXgj4vs0ilhrqZI8r/XJ7/FcdTAwMTKXWFwiZdQ2TGVSzq1p0Y+lbu+0ecf3dsnQVzdH9e+Lv8YzXGKUMkVQlqdee2jffiRtXHUwMDFlhNKCo0+aUFxu905cIqVcdTAwMWaiXHUwMDFhXHUwMDBl3MXRXHUwMDEwXHUwMDFkXHUwMDA2qoxiSS8+RI2OXHUwMDFknqRJMmmE3W4+ZzBcdTAwMTTAc1x1MDAwYpSmXHUwMDE3lGV5j9LUflx1MDAwZtPvUUqIlDLpSFx1MDAwMdq+koVwXHUwMDFiUI3L8+T1M8+t5E3t3kCWf1x1MDAwN7XLsIkngJGCiMQlUzq7slOg1Fx1MDAxMSXpMrJcdTAwMWPpRmJBN1sqcJpz+cYrLi9cYkQowe1cdTAwMGXUXHUwMDA00JOBudytgNqTLPxv0l5Mj15PXHUwMDA2f8FrnFR0Tqbe44Qg+Fo2+Fx1MDAwNsvB04Q2OobQe5xcdTAwMTghdufPd89cdTAwMDZZuP8z2GBUXHUwMDFiUuV3XHUwMDExOpguzPOaf1x1MDAwYj745bmVVbfXO1x1MDAxYaJcdTAwMDGbXGLV6p3v3X+bXHUwMDFkNfjyPKNcdTAwMTZavHHm8D9f/vk/eadZeyJ9ADCinterfaceSGPIORX DSP chainADCMCUSPISPI controlregistersSGPIO andflow controlADC clock domainInternal clock domainFPGATransceiver \ No newline at end of file diff --git a/docs/images/gateware-standard-dsp-chain.png b/docs/images/gateware-standard-dsp-chain.png deleted file mode 100644 index 69973a94..00000000 Binary files a/docs/images/gateware-standard-dsp-chain.png and /dev/null differ diff --git a/docs/images/gateware-standard-dsp-chain.svg b/docs/images/gateware-standard-dsp-chain.svg deleted file mode 100644 index 4290646a..00000000 --- a/docs/images/gateware-standard-dsp-chain.svg +++ /dev/null @@ -1,4 +0,0 @@ - - -eyJ2ZXJzaW9uIjoiMSIsImVuY29kaW5nIjoiYnN0cmluZyIsImNvbXByZXNzZWQiOnRydWUsImVuY29kZWQiOiJ4nO1d2VbbSpe+P0/hRd+CTs3DuVx1MDAwM8yUwzyEoftfLNmWsYItXHUwMDE5WYbAv3Lzv0a/XT9J73KIJWsoPIhAcnBWsohKkmvY37eH2rv491x1MDAxZrXaUvzY95b+qi15X5tu129F7sPSsrl+70VcdTAwMDM/XGagiYz+P1xih1FzdGcnjvuDv/78M3nCaYa97095Xa/nXHUwMDA18Vx1MDAwMO77b/h/rfbv0b/Q4rfMs6fMi/jJ4Gi4vdM/O+2ePXj1L1x1MDAxYqNHRzf96EzkNWM3uOl6SdNXuM4odbRgjGOkOOWMjVtcdTAwMWahVVx1MDAxM+1gijVcdTAwMTdYcE40XHUwMDFltz74rbhcdTAwMDN3XGKpXHUwMDFkiTHlSMLNWNPxXHUwMDFkXHUwMDFkz7/pxHBcdTAwMGIm3CFcdTAwMTIjSjVlnMJcdTAwMGbje7536K9cdTAwMWFcdTAwMWFfXHUwMDE5xFF4662H3TAyvf4v7Jk/SZ9cdTAwMWJu8/YmXG6HQSu5p91u6qZO7mn73e5J/Dh6M0wyTOhS5v3nz70nmetlT8FcdTAwMTfedFx1MDAwMm8wmOhr2HebfmzmXHSj5KrpXX+nNVqvfyV9ityet2NcdTAwMTYsXHUwMDE4drvjy37Q8swyLDXw6sTXXHUwMDA1reevm7h94HnmXHUwMDE1WGqhmNBajltcdTAwMTLZYoRlr+6HwUjOMMZSaiZZso7+oFx1MDAwZVx1MDAwMlx1MDAxNo9e23a7XHUwMDAzL5lp04mNlPAlg1x1MDAxOfZbbvzcXHUwMDEzqZVEmktcdTAwMTCfcXvXXHUwMDBmbrNd74bN2+RbRle/LVx1MDAxN8nzWvuG31x1MDAwN1Su3LVcdTAwMDK+o/fj6/OjxtTybORcdTAwMTEkjCshiEJcdTAwMWOLSXlcdTAwMTbSXHUwMDAxOeSIM0VcdTAwMTFlOifPXHUwMDA0cVx1MDAwN6U/Oi/QTDtMpz6qcnk2n19dnjdnkGeGsCSkWJ4xUaRMoFx1MDAxNVx1MDAxMrCKSuh55Pm5IVx1MDAxMcCUXHUwMDEwqo3j+m5jj52s99aH+mnzYkfWg/GAJlx1MDAwNDH2vsZL44Zvy7bXdraPY7Vz2Ph7fTO87uzqlfP93fPi17pRXHUwMDE0Pkz73i+H+mitXHUwMDFmXjzcXHUwMDFkNI56q9Gh3jvanu69zz/9JHDb53VyTidxrbFDXGauQVFcdTAwMTFcdTAwMTBcdTAwMTY5iWtAPVE2XFxjhVx1MDAxY2XwTIFcdTAwMTQklypcdTAwMGZrwqvFcVx1MDAxY7nBoO9GIG8/XHUwMDBiy/iVsLw1XHUwMDAzllx1MDAwNeJIg4YqxDImulxmy1xcaIWVlPNAuUrpTYTRXGIhXGZ/J4i9qFx1MDAxZnbdXHUwMDE4eltcdTAwMWLE7o03SC1oXHUwMDE4xCf+kzfSXHUwMDFkXHUwMDEzVzfdnt81KyAmXrna9W/MXFwsNT3z4qX0fMQ+2H/jXHUwMDFien6rldZvTXip61x1MDAwN160M42iXGYj/8ZcdTAwMGbc7ulUw3CHcXjsXHK+XHUwMDBmJI6GXnrGvO2xLedcdTAwMTBugfcj6Vx1MDAwNadcdTAwMDeX9/xcdTAwMGV1+q3VY8L2XHUwMDBmTqeBd8pcZiWwZinGN1x1MDAxM6g0dTCjWlJcdTAwMDH45lwiaVx1MDAxZMObUIem4Z0g4XfC92vp6k8z4JtcYqZcdTAwMTXYnzwtuM/4lih3dWx7XCIw/Vx1MDAwNVx1MDAxMjS5471cdTAwMDD89KJWPzmsNTtcdTAwMDCuKoDd9dqxXHUwMDA11nHYL8P0RK+zXHUwMDAwLu5mNcA9XHUwMDFj3l6hvfBp8PdcdTAwMDB3O43zi2NcdTAwMTHJqY1uWFx1MDAwMEdhQoRcdTAwMTBcZtZjXHUwMDAyu+BXgm7mSDAhKVx1MDAxMSqlecfgZdzhXG7kXG6BVGGResFcdTAwMTi7PFmBl7GrhPK0+CfY2EfFuE0sxFx1MDAxZitHn698Szr/XHUwMDAzzuApaZj9nF42vEtzSnxcZmdcdNa6UmQ+fW2zZYOzL4ct0jvbW/eCXHUwMDA2WemJ3Y2jp8VN72iNXHUwMDFmrsjdTnBANvTpevP8Llx1MDAxY2y+R1x1MDAxM9k+fotcdTAwMGWVoFx1MDAwM1x1MDAxOTcmMuNScK4zONTsJVx1MDAxY2Lxolx1MDAxMmVcdTAwMWZALFx1MDAwMuLx9FxulGCKKYL5L0RcXCrElkVcdTAwMWPhsG6a8/dnIW+6zTiMXHUwMDA2f/1PgJdhWWpsuaaWwVx1MDAxM1iuUVKoUFNhmZ9hKb+g3bKKdrrhVKN47bSUoaRJuCvsXGJtsMxA7abx/Kx26Vx1MDAwYnBHjlx02UIjYVhiXFzoXHUwMDEzXHUwMDBi5CDFNMJcXFx1MDAwM72QmUK3b4T+ljvoeD9cdTAwMTn+JzPAX3Fi5rLIPeYpds2gX1xiglx1MDAxOWbiNVwit3ou8PdDP6vNk59qyVSP/jP++V/LxXeXyqL5rOTEMHlfTjmDZ1x1MDAxYsVrsDh+cDNpXHUwMDBiPe+kTMNcdHB3L2yN5CmMXHUwMDFhfpxuaPtfvdahXHUwMDE5/cTgzSA4Qrhk3DlcdTAwMDPMXHUwMDBiWkkvJyXFjGDVIL7juTmxg+fSbeCG+lx1MDAxOZPc6zbCh4JcdTAwMTVcdTAwMWJ1/MS7+SFcdTAwMTf5L91cdTAwMTmc9L2m73ZcdTAwMGK+tLStXHUwMDE33nt7/vdcdTAwMTlcdTAwMTmc+3HnWfSmsHXs8VBcdTAwMWL7XHUwMDAxq9ni/Fx1MDAxYTvAj0aWTFAptas1jvNL4VxiRMCPVUhTpZLnx9yHXHUwMDFjSlx1MDAxOFx1MDAxM1xuYIdcdTAwMDVcdTAwMTeo+jD/77BtdTo99Wlccis1sfuUUFx1MDAxZqWlQX4wS5HkYDQlymdh7lNcYlx1MDAxNlYzmtaLb8V9K6WyOGrNieHi3GePXHUwMDFjzsd9XHUwMDEzQ1x1MDAxZVx1MDAxMWE13FfEb5NcZjhJVCXct1x1MDAwMEnZN1dsJFx1MDAwNYqMO1x1MDAwNJxkbsRcdTAwMWUoq4CkXHUwMDE04983LVx1MDAxMiU85ijBXHUwMDFk8LMxyFx1MDAwNTP6P0FIwlFcdTAwMWacVMBJZzOYY4grLFxiXHUwMDE4Q1x1MDAwNaRESGn8Q2IlXGJcdTAwMDVe+l05qUz2Mo+/REFZK+JNyFx0T27pIzQ5mpfY6lx1MDAxZHLS7Tq5XHUwMDE41Fl8NVx1MDAxY6qDcO3pcvUpKNhoKYnXgqZxXHUwMDE4xVx1MDAwNHxcdTAwMDBcdTAwMGVOXHUwMDAwy+y2YPBZJUNcdTAwMTgxijjIeI6YjOcpQEIwmF+gtnSB8UTBYkdMc2RyiihcdTAwMDeOe/+e41x1MDAxYjDV54VcdTAwMDO4RIF1ZPbEXHUwMDBi+Fx1MDAwYlxm5PJwXHUwMDEyo0A1Ku2IVlx1MDAxNMDtKD+6blx1MDAxY1x1MDAwN4/bW9dbu7c7X/Vnd23xXHUwMDAwrvs5OOycrq9tnZBe/bS+XHUwMDFl99TaVvFrZ1xu4Fx1MDAxYdrVwPRcdTAwMTQnKmChXHUwMDAwrn38llx1MDAwMK5WzKGaKylcdTAwMDCWWGuWgaVcdTAwMDBYXG6mwFx1MDAwNpSSqbxPw7QjqfmYVzCRviXZXHUwMDA0/YjfXHUwMDE24fB8eotBwdowpFx1MDAwYr1cdTAwMTiVz3pcdTAwMTjjTYNcdTAwMTmPXHUwMDE4mStVqUrJTVx1MDAwNPE53LlcdTAwMTG4jbSGeLs47Vx1MDAwYlotXHUwMDFip812vJqI7Omd6oDBs7Xh9tXjdeess3Z54s+eT1x1MDAwYlx1MDAxMkJoemVG88aRI8Gs4lx1MDAwNINiJTqP4feQT+vylvr1IX0xi1x1MDAxM1x1MDAwMI6aJunko1x1MDAwNNNC0ezVZEtGgzFcdJZSxZGJXHUwMDExqFNMvdh+4uOOwndt9Zntb39cIlx1MDAxN+7R6lE0nN5UZNgxhlwiXHUwMDAyjcNcdTAwMTHJiLPSjtBcZnHNJDLZ4zlxXHUwMDA2QXbSqbIpfixPp1x1MDAxNVx1MDAxNcvz76GiLmfJwdOMM5DNolx1MDAxY1x1MDAxZFxmdnuZQFx1MDAxM1xmsmzqXHUwMDAwKjdcbsVcdTAwMDV5XHUwMDFhbqjO5sHaIKQqfFqNXHUwMDA2f7+pUWh975eocbZ23FhZP4zu7878XHUwMDBidiGu9qs0NqtCt31ebcYm+IClwJZcYjua2YCtXG6CUb9Bgt1rJdBeTVx1MDAwZl7gQi4oxoX5s6w8TFx1MDAwZUyNtEjn5b2RLspcdTAwMTmY9fVaw9zyXHUwMDFlkmZf0IZZXHUwMDEzM9/1aozMvZZUXHUwMDE3+nz1VNdcdTAwMDP/PNLxlUc70+fbMepcYoNd9Vx1MDAxZLuJ1P7Qylx1MDAwNrXoXHUwMDE5vIlxsohWTm75UMpcdK7dXHUwMDE5lLJSXHUwMDAyLHtVXHUwMDE4qFx1MDAxMaxcdTAwMTTXYJxcbsxcdTAwMTWuXidcdTAwMGauVp+6nd7h54N24+q6fbPbXHUwMDFjXHUwMDA07cV18lx1MDAwMrrT+t6bu83Nk0/tLbGFVm56+497V+crjVxudTKZKe5uXHUwMDAxt31ebVx1MDAxOXySOoQqKimVmCM6WeQyUsrchmspXHUwMDFjKYSQXGJGg8CD/ChymVx1MDAwNcuNXHUwMDE5sIw0kuD6XHUwMDE1OoyYcVx1MDAwYpjhISTFa4SBZpPfnJZu/99//vdPVlx1MDAxYnT8dPb622nqXHUwMDE3VGRWU1x1MDAxN3e/XHUwMDFhbb3d7O5ds6143+1cZleaq2ir8XnFnVpbMyknLO1MrkrWic7D+qMmtSqIN6eHONec4lx0rZtCuCYqezlcdTAwMWRcdTAwMTNcdTAwMTJEcl29ut5e94afXHUwMDFlb3tbjYvL/fud/kEjOlhcXF0voFat763rXnSng/teXHUwMDE339w/tL8+tHdcdTAwMWb33qNcdTAwMGJtn1db0ZpcdTAwMTY2YGed6Fx1MDAwMjtcXFx1MDAxNFx1MDAxON5cdTAwMWZcdTAwMWG6XHUwMDE0vq1cdTAwMTk0NEVcdTAwMDLULCneXHUwMDE3leUhMKwolpKQ+WrKX9eP9pp+771Vob6gXHUwMDFic1x1MDAwZXX5XHUwMDE4qtHVvZOzzue7/k33cmd3Z79/XHUwMDExn8SbfCo0U+IgwUA2lGJIcj5ZxyYwc8xcdTAwMTFcdTAwMDVCXHUwMDBiU2IjXG5i3YQ5zGy/MlOIrrgu2n799cH9Wrr5Zlx1MDAwNt3MYY1Eusw/wbampVx1MDAxNeagzFx1MDAwNVZcdTAwMTN+VUXQxohcIpZcdTAwMTbXWaF9/GuUoFx1MDAxNnezXHUwMDFh4NpD+dY0S7CI4d0mdc5cdTAwMWNcYpJO5lx1MDAxZSVOIP5CPlx1MDAxM3KwqYOERVRaXGKNMC3IaDI1XGJSa440XHUwMDA3+5pcdTAwMTP2XHUwMDBiZDS9RS3Ml1n2qThlSqNCXHUwMDFjI8sxRlxmXHUwMDAxiLV4P6HuapMvLfI4as+LYvLKnO08ZU64Pfei9pPrYcp6aVx1MDAwZt9X1Mt8uqil2/+cYp2jT+s+2vXq3Wh4dsc+3fH11bDAsio9I4CZ2KY2me5cdTAwMTRcdTAwMDPuJzna5Jxqjlx1MDAwNdZaUc5cdTAwMTP+XHUwMDFkXHUwMDA3QcD+MlXNnCmEwfxcdTAwMTJcdTAwMDWZMVx1MDAxZqdcdTAwMDRcdTAwMTQy8m0xI89ySlx1MDAwMMVmd5FcdTAwMTduXlx1MDAxMExLqVphXHUwMDA15DWnMzXuX0F0YYWc7+1cdTAwMWNHT/XHK1x1MDAxMoWXfuvk6SxNV1lTf9xgXHUwMDBmWlx1MDAxY7VcdTAwMDdb267Hn64/0/OGqp/fXHUwMDA3XHUwMDE36j3uMdjHb9tjwMSh0lx1MDAwNC0kpzqd6TFOMrXiXHUwMDEwa+VcdTAwMTRcdTAwMWPQ8XEuQCH0utNcdTAwMWJD4FmC36h0LtvMXGYpjaDsuVmKw3yiKlx1MDAwZs6qaEdhXHUwMDBmdLGpol977LuDwfL32Hxt2P/xUyt8KHZ2fnLa6Vx1MDAwYoot61x1MDAwNM02rGqcIzsv2Zwjo1lcdTAwMTlh5rRcdTAwMTYhKUZcdTAwMTm9a3wju951sGJwh2ImNX1cIvCROyWAUHCwXHUwMDA0YrNcdTAwMDQ5/kGeUW+GJCBcdTAwMDGeqix0jLBkpVx0qdRcdTAwMWPlIVx1MDAwNHpcdTAwMDXHiMi5kswrrkorXHUwMDE1xlFzTlx1MDAwZXN2+8xukZ1cdTAwMWJ+tlv0XHUwMDBmPSagcY3r9Vhuy8ujrcbGWexdf5LTXHUwMDFmXHTMgeOYIJRIpqUmkmfCQ1x1MDAxOI3OXG5cdTAwMDDsXHUwMDEwhNXH8WTVXHUwMDExXlCB46E4XHUwMDAzNFx1MDAxN2cyp8srcuVthFHCOa58XHUwMDFi1ttcdTAwMTen3FtcdTAwMGKlqIefLlx1MDAxYfuPO/Hd+uKeR/9cdTAwMTI3TlZ2j46C/WPqtY+e3G1cdTAwMTlX6HnQ1E7YQp6HffxcdTAwMTbPg1x1MDAxM2SO7DCuO4a/uVxiXHUwMDAwf1x1MDAwMYZcdTAwMWank82Lw3CWLEVEwPJghcd7YipLM5ukyXug88HtVSyPX+Vwslx1MDAxN5TbW1x1MDAxZU5m5ySb11x1MDAwMfB0sJFcIqE1XHUwMDE2XFxlvVx1MDAwZWbHOnI0ZVxuXHUwMDEzxFx1MDAxOFwiWOmiYF/mTCj84XRcdTAwMTRivz899lx0XHUwMDA1L1HwwpQnbUG+xliZqqHqoT+b0nolp6NcXFx1MDAxOEfNOTnMXHUwMDE58zM7XHUwMDFkdkr4cDp+itPRf1x1MDAxNP2VePf0yX98Wlx0XHUwMDA2N5u0j6Y7mVx1MDAxMSNcdTAwMDXESkyxXHUwMDBlXHUwMDE3xnGYZD+JmcNMXHUwMDFltzJcdTAwMGWJkoV53FgrRTHlXHUwMDFhcEVcdTAwMGLYb3S8XHUwMDA2Zlx1MDAxOFMwpaSpXHUwMDA0Rlx1MDAxNVdo/EapJXfT+iEkh4Txb9xcdTAwMDHvXHUwMDBmVlx1MDAxM1x1MDAxNUVnYaFF9vLYXHUwMDBmMedzmi2vytlx7pyTStmxVFRHT1x1MDAxN1xi6fTsWH500Ls/McxaXHUwMDAxY6NcdTAwMGVNuaUqXHUwMDEziINaqzJ/ZIGr5yTwgkRxWFx1MDAxM4zJOFdcdTAwMWMx/vH7uFxuSSOa3nDS5uQuc+pKXHUwMDAxOVx1MDAxMFp6pivmmChN6Fxc3DDRj3ebyVIqkKPHXHUwMDBiRHFx4+lcdTAwMTVSRMBcdTAwMDRcdTAwMDTjXHUwMDBmYylcZvDMoUmcTVx1MDAwZcREXHUwMDE2U3/yLDdjnou9+GWuQeDsXHUwMDE4lHVcYvljJl8j52XCNa3WXHUwMDA2tPCzveTBeug2lZbK21x1MDAxMUFbK/RcdTAwMDBcdTAwMGb8e1x0z+gjeOG5s1x1MDAwNlx1MDAxNvxH8lx1MDAxMVapKOdcdTAwMDdBJ1x1MDAwNFx1MDAxZM9A0NpQbXpjMkXQurSWR4HZXHUwMDA3xs1cXMV6v1xmP5fI46i5QFx1MDAxNFx1MDAxNyfoV+C2mVx02sZuU1x1MDAxMbS97GFegiaagMP4/E9ytmjRXHUwMDEwVH4lflx1MDAxZoK2147ZXGKaSWytyTK+tzlcdTAwMTmnlKFcdTAwMTVytPltlIhQsOlAklxuXGL6g45cdTAwMGLo+H6WTVx1MDAwNkaEQMWJ3+lcdTAwMDT9XGZcdTAwMWYzs2RIonl+XHTCr8HHpdKXeXxe7n1cdTAwMDXaerWTvyuKLE7nx//xPJlLbr9/XHUwMDEyg3CMJ3Hp3vdcdTAwMWXWyjdcYv54XHUwMDFlnoGtN1xuK33749v/XHUwMDAzf9FPsyJ9Interpolation stagesTX DSP chainFactors:1, 2, 4, 8, 16, 32EnableDC blockfâ‚›/4 shiftDecimation stagesRX DSP chainModes:Bypass, shift up, shift downFactors:1, 2, 4, 8, 16, 32 \ No newline at end of file diff --git a/docs/images/gateware-tx-only-basic-block-diagram.png b/docs/images/gateware-tx-only-basic-block-diagram.png deleted file mode 100644 index fbd1639c..00000000 Binary files a/docs/images/gateware-tx-only-basic-block-diagram.png and /dev/null differ diff --git a/docs/images/gateware-tx-only-basic-block-diagram.svg b/docs/images/gateware-tx-only-basic-block-diagram.svg deleted file mode 100644 index 61aea1e2..00000000 --- a/docs/images/gateware-tx-only-basic-block-diagram.svg +++ /dev/null @@ -1,4 +0,0 @@ - - -eyJ2ZXJzaW9uIjoiMSIsImVuY29kaW5nIjoiYnN0cmluZyIsImNvbXByZXNzZWQiOnRydWUsImVuY29kZWQiOiJ4nO1dWVfbyFx1MDAxMn7Pr+BwX2NNV+89b1x1MDAwZWZcdTAwMGbgXHUwMDA0wnbnXHUwMDFljrBlW8FcdTAwMWK2WefMf7/VYpFkLVi2SFx1MDAxOFx1MDAwZc5cdTAwMTlcdTAwMDYsud0tVdX31db6+9PS0vLkbugt/7m07N023K7fXHUwMDFjuTfLn+37195o7Fx1MDAwZvp4iFx1MDAwNn+PXHUwMDA3V6NGcGZnMlx1MDAxOY7//OOP8Fx1MDAxM05j0Hv4lNf1el5/Msbz/ot/Ly39XHUwMDFk/MQjftN+9qRzRLfvrs9aldr55lmr63U69DD4aHDS02RGXmPi9ttdLzx0i+9cdTAwMGKmXHUwMDFkLqUmwFxyVVTI56N3eLTCtUOEMvjPXHUwMDFl44w+XHUwMDFmvvGbk1x1MDAwZZ7CXHJzJDFcdTAwMDZcZlx1MDAwM8KUXHUwMDExz2d0PL/dmdjVanBcdTAwMDRcdTAwMTBgYLTSXFzw51NcdTAwMWUm9OdcdTAwMTJ5fmc8XHUwMDE5XHIuvJVBdzCys/5cdTAwMGZ49l8453O3cdFcdTAwMWVccq76zfCcVvBcbs9p+d3u/uQuXHUwMDE4XHUwMDE5LzJe0OWp8Y9cdTAwMWUnT6fez/pcdTAwMTR+YbvT98bj2FxcXHUwMDA3Q7fhT+x1XHUwMDAyXHUwMDEyvmtnN9xsXHUwMDA29+t/4ZxGbs/btDesf9XtPr/t95uevVxyy6eT2Lf1m4/fXHUwMDE2O3vseXZcdTAwMDQuhKRcdTAwMTJYeFx1MDAxZEPJXHUwMDAyzlx1MDAxM2/vXHUwMDBl+oGYUaY5lYqFc/XHNVx1MDAxNK9JMGrL7Y698DrbOaxGRC9cXMrVsOk+fFx1MDAwNJQmRHIuNZXht3b9/sX0zLuDxkX4LcG7/3xOk+bRcCCkX/0+cXt3o9stX1xc/ty4nFmaUYJcdTAwMWRcXJ9cdTAwMTE4J8VcdTAwMTLSLIgjQYNcdTAwMTJaXHQqjVx1MDAwMJFcdTAwMTBnXG7E4dxoglx1MDAxZlacgNBp8sxcdTAwMWSiXGKj6nGcXHUwMDBmeU7K883s8lxmkqBcdTAwMDFiaIZSXHUwMDA0WmuWJc/AlVJGXHUwMDEySstcdTAwMTZohWpcdTAwMDTlXGL05Y/zmvzaOrrbv9lf/fG9PoZcdTAwMWVtzSzQhmhHXHUwMDEzNL7mQaBFXFyggaEgKmE4x4tAUPp1QqCBUkeDkIZcdTAwMTE0vYpcdTAwMDMkXHUwMDA1WkvHXHUwMDAwxXHAXHUwMDFhci3LN9BcctMw/3KBvl2fXaKNNoRcdTAwMWJQJkWgXHUwMDExZjNccrRCRbDGdFx1MDAxZXl+PFx1MDAxMFxuYERcYpubt+eN25VKf6d3WIP6tlu/7IX3IyaI7mg0uFl+PvLP57xx+fBgtXa8u/al8XWdTepcdTAwMTdmZ6VeT1x1MDAxZnfi3U5mXHUwMDFkdmN1u9JcdTAwMWXsgFdpfTv1XHUwMDFhTd1cdTAwMTGVXHUwMDE5p/v4W45yS1xuXHUwMDAwpFx1MDAxY+XOX3987XG9ZsRRmlJcdTAwMGVSXHUwMDE4gqBcdTAwMWPTa+EwhFx1MDAxNo34hEqJJyRZl0KzIPGlXHUwMDE1XHUwMDAxUKBTUEqQcrV4MnL746E7Qnn7t2vyYVx1MDAwMWxCUqvxO3lcdTAwMDKFXHUwMDAyu1x0WapcZlx1MDAwNJmEQcqr59HlPPFFaKJFxDeURiuFuP5adeWvvt+feKOW24jc89agP9n371x1MDAwM0NEYu+uuT2/ay++jFxyVu36bXtcdTAwMTmWXHUwMDFinlx1MDAxZG05ei0mPnoyzyf0/GYzXG5tXHJcdTAwMWPU9fveaHNcdTAwMTaMXHUwMDFjjPy233e7XHUwMDA34Vx1MDAwMpZS5u9eTVx1MDAwNt+98cNcbiajKy96kbyNJ71cdTAwMDCHilx1MDAxY5Xec8l4TZ9sn8ijterd2d7JeOvLzcx4XHJEK4crJlx1MDAwNFx1MDAwNfxP6lx1MDAxMFx1MDAwMeJcZlRJho5cdTAwMTXh4Vx1MDAxNU0wUCaJYFxuSKpH9cRAn8b5oKBJPb+bXc2loFxcXHUwMDEzodNcdTAwMTgoRKcypeZcZum/Mni3SmegPDroQiDl1WuXwr8+r427O2v7nFxm1EYtJUDwgKQxaZbGilx1MDAxOaM4XHUwMDE1hmyGx9knopOD+IRXTkmpXHUwMDA0ISohy0FsgFx1MDAwMyP4ccmUSeGe6LEhe2XCaG5cdTAwMThcdTAwMThpXG5IMnIlz8jfglpNd9zxfq04388uzmhDhNaKitRcdTAwMTBcdTAwMDFVmbBlPyiFQlwiWrZAS4hqV1x1MDAwMdhcdTAwMWFcdTAwMGX8aYZcdTAwMWL+tlx1MDAxNF7s4I/n3//3OfXsTIFcXPzTlYQkh8MlWOl44o4mX/De+v02Li3kwE/hvlx1MDAwN2Akl0ffxydDz9vaaVx1MDAxZmxfra2uTX6sRojwcm/QXGbEcTA69yfRXHUwMDAzLf/Wa9btpYtduSWEP5y9RmZCXHUwMDE5OoOE6NhcdTAwMTVwUNWRd+JcdTAwMGZtg3WSJtbwzNyXvX7z5Vx1MDAxNZyd7t9vK1mpXTSPdy4nZEf3XHUwMDBlq4utwE7SMCaQXGLh3WAglfpcdTAwMWNfoMTpXHUwMDEzqVxies5cXDCes4bgPlSt5et4bkL3cIXRY2hM/CnM97rng5tAaGOEI5j7vtd+0oy4jtrv3Fx1MDAxY+9cdTAwMGa9hu92U75z+liObb9yx+7N6uHJqM/94dHq171TVJ2Z2VxuMlxmh0lcdTAwMTHgjaFgWNxccrHhXHUwMDA1oyVFT1x1MDAwM1x1MDAwZqE/YpLxsjC8XHUwMDAw3KpFhPCE4Vx1MDAwNeVoXG5cXMDDMKFcdTAwMTUoh6uc01x1MDAxNj0//3dzXHUwMDE1d292465cdTAwMTh6jMZAgpRcdTAwMDRcdTAwMWWJnn732SNcdTAwMTFcdTAwMDSdTaUjYeOSolx1MDAwYt+q+6fX3e5pd91cdTAwMTO7ZP1rrb/75XTxKMCXoYSd9sl6b6XfXHUwMDFh3a70XHUwMDBlflx1MDAxZZ2dlFx1MDAxMLR41ehcdTAwMDLapWhcdTAwMGVkIeKWf11zolx1MDAwYqiHXGJUknK85VowmOJt6KFQzvEkPFx1MDAwNCTqPDxptbVcdTAwMGL2RYlcdTAwMDSF3C4tXGJectT73YRcdTAwMTfc+uyqjHdHaIZUXCKNpymaXHUwMDFkXWBKU/wknytSWKb4htL46Jzvr9c3I8bs91x1MDAwNVx1MDAxNV6AxumgwtS8y1x0JuSzn5fgWVx1MDAwMXWEsv49gEbaOVx1MDAxNUtAdKaKXHUwMDEy9LtcYrJNyZNqjCbf4UTbmCc6aUalhVx1MDAxMlx1MDAxMJzRXHUwMDA2IDJIxH8jdahIXHUwMDFmsf9nlf5WXHUwMDAwnZVkQHgkJ1x1MDAxNWp0ip6H8UK0tpJxKFx1MDAxZJ3pl+vOlu/vbfL7g1x1MDAxZjeuvzG+3TxaXHUwMDFjnV8rpVDb2dGdXHUwMDFmN8c9Ksff+DfSOb1cdTAwMWJccktcdTAwMTg3P1xukjvuy6hfZk4h/37loL6i0kHf3qZcdTAwMGVcYnqgLJ78RtRXSNSRiFx1MDAxM6XQPU1cdTAwMDZrgDKHoTkhaHFshFKnRGs+UD/TRFx1MDAxNEgqIEtcdTAwMTeUKJpcdTAwMTZtZJEo27SN0Fx1MDAxY1x1MDAxMVx1MDAxYUWuZNCXXHUwMDAwplC6O1x1MDAwMfpcdTAwMDfHS7X9+lKjg/j7XHUwMDE2sP9cdTAwMDXcncb+9OmXlE9o9C5MRV+snVS+XHUwMDFlkWHnpNW6c4vlXHUwMDEzmKRcYiqGXHRGWLJcdTAwMDBcdTAwMDCUhXZcclLbQoCUXHUwMDAygFlIwEdcdTAwMDHAy1x1MDAxYX4+u4JcdTAwMWJjY+ZCpbnoSmXm/1x1MDAwMZDOqVfgXHUwMDAwrePeXHUwMDE5r21vVlV3p3V4Nmx+XHUwMDFmy/5MXHUwMDFjYFx1MDAxNuwzlJWUqsifZ1x1MDAwZfZcdTAwMDFw1EPNlEDmRY1JeLxcdTAwMDH2gWKaaMaS2MeRadt8upBcdTAwMWNNIScyqSNcdTAwMWbQl6VcdTAwMTiNXHUwMDAyXHUwMDBlL1x1MDAxN2jIXHUwMDE0TYU+aVx1MDAxMvUyYalcdTAwMTf6J8Bp6bWLhaU3gX216spbgLxcdTAwMTdwJiWHXjbSddarw7X7U7g9ISdb123drzY6tVmUN6zaZFpCJDlcdTAwMTVAnHVQXHUwMDA16i6VXG5cZqE0XHUwMDE5g+bCQZXHXHUwMDE3ZYpIXCLSXHUwMDEy5lx1MDAxZsqbobx+XHUwMDAx5Vx1MDAxNURcIlx1MDAxN6EyzbeNXHUwMDE2TCaiVUYh9aCR9O/CyquMkYZwXHUwMDFkLVx1MDAwZp1DeXdWfpShvF2vNclR3clgmKW3sclOK2lsduUoabUy+rruXunhXHUwMDEwXHUwMDBltzfOXHUwMDBmvtfHp7fFXHUwMDEzRviDo1x1MDAwN1x1MDAxM1x1MDAxYc5AXHUwMDFh0YFcdTAwMDRNqOZcZpVVKJVcdTAwMTKRouBIQVx1MDAwNVFcYrKC6rR2XHUwMDAxYVx1MDAxY0VcdTAwMDVcdTAwMTCKjlx0cl4ovb76XSSMfs6ut1xcKim0Sk1cdTAwMThBNFx1MDAxMjCtt9JmWVx1MDAxMSfnqq/O46NcdTAwMWLrXHUwMDFiP7bWmrdbo1x1MDAxM3Laud+XP6/pZCY++jlvWH5M2+JwZWV44v0gXHUwMDA3q3t393ftVvqwxWM83FxubEldXHUwMDBl+evPgUpkpo5VXGZBKENPjdO4XHUwMDAycuKgXmomhFCcccZcdTAwMTJcbshcdTAwMWUzO1xmzSeApFx1MDAxZjGeXHUwMDAyOncxu85cdEBnQ0GGzrFcdTAwMDSCPumcsE4+46JsnovSi+Z5XHUwMDExqNyvb75cdTAwMDWe+1x1MDAwMoAl0jrRWZdcdTAwMDOh+UU5LzfcKUei30GYXHUwMDA0zqJcdTAwMTj5IKTa1kqgXHUwMDBmaoRcIlx1MDAwMmSy9PstJHXeXHUwMDA1gvZcdTAwMGIwX0lcdTAwMDXTQrFEdYW92FwiU5tcdTAwMDG5kP3ofFx1MDAxZEp5UHd43K7y6ztYa1Uru1d+W55V6dXiXGK6QJbktZA5d1xctbk7+tm567fO6u6WafRcdTAwMDa1853GW0T8/PuVg/hCMocjoFvnXHUwMDE2tXmKcCuHRStwk3hvPlx1MDAxYUXmt1x1MDAxMINcdTAwMDJcdTAwMDXkxCBoc57mXHUwMDFha8h2jVx1MDAwNUXfWMvS20RcbstuXHUwMDFh3i9Z7Fx1MDAxZFxyun/1R17bXHUwMDFmI26P31x1MDAwMlx1MDAwNXhcdTAwMDGAUyjA00KWUtZRXHUwMDBlKdg9uV7dVVfnK2ZcXN1ru1x1MDAxNXHXXTVcdTAwMDVIgXaQXHUwMDE1olx1MDAwMFx0ooUgcVLwXFzpXHUwMDAxVFx1MDAxMilcdTAwMTlJiYHNWIdcdTAwMTmwXHUwMDAy+ThM2Vme98Bcbs5cdC+Q5lx1MDAxMVx1MDAxYVx1MDAxOZZWaawgr2tcdTAwMDTQgdNcZq136Yme+2q9W7tgrcvL3YveNdnj1fX13bdbivlaxVx1MDAxZa9KXHUwMDBiXHUwMDE43vBIw+ZCtCD/fuXRXHUwMDAyzlx1MDAxZMM0XHUwMDAxQ0BcdTAwMWGlp1x1MDAxYkhpkO/S0iD0c5PkXHUwMDA1QIxcdTAwMDOWXHUwMDE4cHRcdTAwMGJcdTAwMDVDT+ODXHUwMDE4XHUwMDE0MFx1MDAxMqJIylx1MDAwYijaXGLC0kJcdTAwMDHGZFeESVx1MDAxYlx1MDAwN2DczGUkcms8XHREMtPz1nguuf3mX/1Wd3DzhK5vgVx1MDAxYryAw6lVn3YlS+lcdTAwMGIph1x1MDAxY+Sbz7xcdTAwMGU8ro1ccqnbflEwXHUwMDEygMaLuqhxtFx1MDAwNlx0RFx1MDAxMqJcdTAwMTghPFx1MDAxOS7gXHUwMDE07Vx1MDAwNFwije2JMUhcZlJcdTAwMDJ+xGFCcVx1MDAwM0QowZlBb6JkZvCOXHUwMDE0X1x1MDAxNlB8o9A3UzK1XHSPmeyeUlx1MDAwNYozWXpcdTAwMGKe3SbEzFx1MDAxNVx1MDAwMiy1XHUwMDA1L1Mgg08nRTFcdTAwMWMvXHUwMDAxzTN20eVXgi/N2UXHtVx1MDAxNkxcdTAwMWGQttxExlx1MDAxN8HxLcRVSjkulFx1MDAxMylcdTAwMTKLKNhGl2/W5lpChUytQVx1MDAxMJh/XHUwMDE15TXSxUWv3E6652O9wbW34z9cXJfxkT/pPOrQXGaULT+UlW/MtUNsZS1Rhismp7KnXHUwMDAyXHUwMDE1Qyn8XHUwMDFmXHUwMDA1XHUwMDA0aZKs5OPMkdx2/WvEXHUwMDAy9O9Dzlx1MDAxNzHlglovUVx1MDAwN9xcdTAwMGaoXGLN/Yclj1vyalx1MDAwMUuO7rTSmvLUgl3I3KBKck1RwUTZXGZu/mROuZY8S1x1MDAxZe2rklx1MDAxNMXFLXl+8mcuM0hcdTAwMWMz9YpcdTAwMWJBQUhy4lx1MDAwNa33K7Rxk0KzTFjnNFx1MDAwYjy3jV7AmG5cdTAwMWXX709cdTAwMGUre17728aP4y3d3NeHdzNcdTAwMTlTQMFcbsJZRFx1MDAxYkmpijvASIxRSTjyXGZcdTAwMDQ3uz9h0ppcbuKgXHUwMDFiJLgtnea2XHUwMDExL5VcdTAwMThLZCN24zXNiVaRnbs+rGncmq5ntD9EVOLxZtKkdD5aWfRf8Fx1MDAwNZBcdTAwMWFOU5CdZbNmUUP5SXM0XqDnXG6il2pnK5miXHUwMDFhXHUwMDFjTUrp7IZ2mjBlXHUwMDFjmcN+xEcu33Lk95/lWVx1MDAwZUNobE/FeLDdXHUwMDE2yCiuXHUwMDEwuzSyXmJ0soiNMUcjsFFcdFx1MDAxNKVcdTAwMTWdqjTLgZZJMYFcdTAwMWW7oFx1MDAwNIcrO9j+jkzHRoEsXHUwMDFiVczqQFqWXHJyNlxu1XaLPVx1MDAxNt0y4X1cdTAwMTmITIlcZo6mXGLj4lQsf8+2X8Bpftf2M1Bolm/QcuYnXfIsp1wiMtqQnjCc1G5MgpRLWv812WTDjGOzJ1x1MDAwMu0u+r+gU1JcdTAwMGVg5dgoqShcdTAwMTAweKJX+eBcXFmGc3t2w0mJIULI1PolJjI7TjXj2lD5bolVpkRcdTAwMDZH04RxccP5XHUwMDFhO2KVbzhfIeD4rzech7VDQfdcdTAwMGW/NM9cdTAwMGX863bj5ujn3uF90nBmt/Liolx1MDAxNWF2/1ZBpzenp1x1MDAwMl1Wg/ydXHUwMDEyxHEpk1x1MDAwZSu1e4dcdTAwMDa5O6FtXHUwMDAxR4rDXG7KMTYgg4Mj22FFon+pdvG99vKek5PZbSc3XHUwMDEyrWdKwsZOJVx1MDAxYadNsE6Bt5lqVnq/PouFXCJcdTAwMTYqQKjLjVx1MDAxZd+ofyX3d3u1q+3at9HwZqZOXHUwMDA0XHUwMDAwwlx1MDAxZEVcdTAwMTlcdTAwMTOGojU301x1MDAwMVx1MDAxOIFUgTMpKDrmeO1SWoFcZnPAxtvQ9GpcdTAwMWHdMOWjXHUwMDAw4WX5bVx1MDAxN4leS22j1ynia0y29FL7XHUwMDEwhPkqlHJlV5DFNpiyuz837DlLzUHP9ft/9TdtyUDf7cbeLqNcdTAwMTjhldr6XG6voJwqXHUwMDA0Q/zNzbPxz9FR62qwf7x174trOlOtXHUwMDEx047NSlx1MDAxOSE1J2bqoSpP/bnI+I2hNOVcdTAwMTFBgj7UIHOtJUqU/Og5KqLpnVwiXHUwMDE1XHUwMDA3zCA3YKnd9Ty74lx1MDAwMFDZXHSa8TfYoLtWX6++YVWOT69cdTAwMWM9/drouo3xxvnWceP05rJd0Y29085MkFx1MDAxY6ZEwFD7lKh0TaWSmyBcdTAwMDGdxGRCXHUwMDFkavd9NEF41KSB8oeqZqpqkV56y3qMplwijVVKmq2qXHUwMDAy7EbalIZB57eiqlx1MDAwN/ZGNjz/Olq/9+Y0NnWW5Shu/sayuZUhti3ebpCApNpwXHUwMDEwkeS+vUJKOsCUJFx1MDAwMlx1MDAwNEHf0SRcdTAwMTVXcO2gX4lcdTAwMTiLzlxukvE0iGVcdTAwMGXRyNaNsU+mYEZcdTAwMTZpXG6cYaf913hmxK/fZf9cdTAwMWNcbniGtl9DaZO+yz4kg23PSqzwXHUwMDE2oN9UOrvmaFx1MDAxZFwi24T+rrha7Oyk3L308UxhfoXhmCONwnshhELHXHUwMDA0UVGGw32aXHUwMDFh9jfWXHUwMDFiXHUwMDA2xXighVKgiVx1MDAwNClD0bEvcFxilVx1MDAxNGwnXHUwMDE5Q3k0yTBlwfDfa2R3okuwu1xmi6lcdTAwMTUgXHUwMDA2MXRcdTAwMGZcdTAwMTgwQDeR5SzhXHUwMDE37dqf1WnzaCtodP5cdTAwMGZzmlrylCbkXG5vTHxcdTAwMWZWkVx1MDAxOC1Xkl9cdTAwMWH9+fdki0uijjJuXHUwMDFiplxuKV/sadH3tcHwsHPNv26Tia8u91vfZn+EZ1x1MDAxOCZliqAsTz3y0D75SNoqXGKl7VZvkNJcbvdG4qTvolx1MDAxYlx1MDAwZdzZ0Vx1MDAxMFx1MDAxZFx1MDAwNqqMYmlcdTAwMGY9RI3O3NtNMmmE3Wq+ZDBcdTAwMTTAlSmpfTu/oazIM5Sm9nuYfoZSSpyUSUdcbtD2cSyE23BqUp6fXHUwMDFmPfM4StnU7lx1MDAxNWT5d1C7XHUwMDAyO3hcdTAwMDJcdTAwMTgpiEhNmNLszk6BUkeUnOtcdJ6xaaQ2dLPfnzLldIHTK1x1MDAwMlx1MDAxMUpwu/s0XHUwMDAx9GTgRe5WQe1JXHUwMDE3/ldcdTAwMTkvoUeLk8Ff8FxiJ1x1MDAxNb8nU89wQlx1MDAxMFxclFxyvkIyeJrQxtdcdTAwMTB5hlx1MDAxMyOESfX22SCLzj+DXHLGtSFXfmehg/nC/NLwr8FcdTAwMDc/PY6y7Fx1MDAwZYf7XHUwMDEzNGDPQrV87Xs3X7KjXHUwMDA2n1x1MDAxZe+ohVx1MDAxNi8oXHUwMDFj/ufTP/9cdTAwMDf5elfzIn0=DACinterfaceSGPIOTX DSP chainDACMCUSPISPI controlregistersSGPIO andflow controlDAC clock domainInternal clock domainFPGATransceiver \ No newline at end of file diff --git a/docs/source/external_clock_interface.rst b/docs/source/external_clock_interface.rst index 9c09ca66..fc3f3b1d 100644 --- a/docs/source/external_clock_interface.rst +++ b/docs/source/external_clock_interface.rst @@ -9,18 +9,12 @@ HackRF Pro HackRF Pro has two configurable SMA ports, P1 and P2. By default, P1 is configured as CLKIN and P2 as CLKOUT. The default behaviour of these signals is as described for HackRF One below. -A second CLKIN signal is available on header P22 pin 2. Unlike HackRF One, HackRF Pro's P22_CLKIN is a separate signal from P1_CLKIN. To enable P22_CLKIN instead of P1_CLKIN use ``hackrf_clock -c p22``. - -Various internal signals can be connected to P1 or P2 instead of the default CLKIN and CLKOUT signals. Use ``hackrf_clock -1`` or ``hackrf_clock -2`` to select a different signal. - HackRF One ~~~~~~~~~~ -HackRF One produces a 10 MHz clock signal on the CLKOUT SMA port. The signal is a 3.3 V, 10 MHz square wave intended for a high impedance load. +HackRF One produces a 10 MHz clock signal on CLKOUT. The signal is a 3.3 V, 10 MHz square wave intended for a high impedance load. -The CLKIN SMA port on HackRF One is a high impedance input that expects 3.3 V square wave at 10 MHz. Do not exceed 3.3 V or drop below 0 V on this input. Do not connect a clock signal at a frequency other than 10 MHz (unless you modify the firmware to support this). You may directly connect the CLKOUT port of one HackRF One to the CLKIN port of another HackRF. - -The CLKIN signal is also connected to header P22 pin 2. Unlike HackRF Pro, HackRF One has only one CLKIN signal shared between P22 pin 2 and the CLKIN port. Do not connect input signals to both CLKIN and P22 pin 2 simultaneously. +The CLKIN port on HackRF One is a high impedance input that expects 3.3 V square wave at 10 MHz. Do not exceed 3.3 V or drop below 0 V on this input. Do not connect a clock signal at a frequency other than 10 MHz (unless you modify the firmware to support this). You may directly connect the CLKOUT port of one HackRF One to the CLKIN port of another HackRF One. HackRF One uses CLKIN instead of the internal crystal when a clock signal is detected on CLKIN. The switch to or from CLKIN only happens when a transmit or receive operation begins. diff --git a/docs/source/gateware.rst b/docs/source/gateware.rst deleted file mode 100644 index f560b583..00000000 --- a/docs/source/gateware.rst +++ /dev/null @@ -1,118 +0,0 @@ -================================================ -Gateware -================================================ - -One of the significant hardware changes in :ref:`HackRF Pro ` is the replacement of the CPLD with a FPGA. While the older CPLD primarily provided glue logic between the MCU and RF front end, the FPGA in HackRF Pro introduces more logic and DSP capability. This enables offloading digital signal processing tasks from the MCU. - -FPGAs are highly flexible devices whose behavior is defined by *gateware*: hardware descriptions that configure the internal logic fabric. HackRF Pro gateware is written in `Amaranth HDL `__, a Python-based hardware description language. - -The specific FPGA device used in HackRF Pro is the Lattice iCE40UP5K, which features -5280 LUT4s and 8 dedicated DSP (multiply-accumulate) blocks. We rely on the `open-source iCE40 FPGA toolchain `__ to build the required bitstreams that are bundled in the firmware. - -All gateware source code lives under `firmware/fpga/` in the HackRF repository. Top-level designs reside in `firmware/fpga/top/` and are the primary entry points for different operational modes. - -By default, a standard gateware configuration is loaded at boot. However, the firmware can dynamically reconfigure the FPGA at runtime to switch between different gateware variants. - - -Standard gateware -~~~~~~~~~~~~~~~~~ - -The standard gateware is used by default when the firmware has not requested an alternative bitstream. - -The standard gateware provides a balanced configuration optimized for general-purpose operation. It implements configurable digital signal processing paths for the reception and transmission paths, capable of (limited) frequency translation and supporting a wide range of sample rates. - -Block diagram -^^^^^^^^^^^^^ - -.. image:: ../images/gateware-basic-block-diagram.png - :align: center - -.. image:: ../images/gateware-standard-dsp-chain.png - :align: center - :width: 75% - -Features -^^^^^^^^ -* 8-bit I, 8-bit Q data format -* Receiver signal chain: - * Optional DC offset removal (DC blocker) - * Configurable fs/4 shifter (quarter sample rate): bypass, shift up or shift down - * Configurable decimation rates: 1x, 2x, 4x, 8x, 16x, 32x -* Transmitter signal chain: - * Configurable interpolation rates: 1x, 2x, 4x, 8x, 16x, 32x -* SPI control interface for register configuration -* Double data rate (DDR) interface to RF transceiver -* Interface to MCU (SGPIO) - - -Half-precision gateware -~~~~~~~~~~~~~~~~~~~~~~~ - -The half-precision gateware reduces sample width to 4 bits per I/Q component, enabling higher throughput within the constraints of the USB interface (up to 40 Msps). - -This configuration is intended for applications where bandwidth is more critical than dynamic range, such as wideband spectrum monitoring. - -Block diagram -^^^^^^^^^^^^^ - -.. image:: ../images/gateware-basic-block-diagram.png - :align: center - -.. image:: ../images/gateware-halfprec-dsp-chain.png - :align: center - :width: 75% - -Features -^^^^^^^^ -* 4-bit I, 4-bit Q data format -* Receiver signal chain: - * Optional DC offset removal (DC blocker) - * Round to 4-bit I/Q -* Transmitter signal chain: - * Extend width to 8-bit I/Q -* SPI control interface for register configuration -* Double data rate (DDR) interface to RF transceiver -* Interface to MCU (SGPIO) - -Extended-precision gateware (RX and TX) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The extended-precision gateware increases internal signal processing precision and output sample width to improve signal quality. The main drawback is that the minimum decimation or interpolation factor is 16x. Due to increased logic requirements, this gateware is split in two top-level designs (RX and TX). - -Samples are 16-bit I/Q, while the effective number of bits (ENOB) depends on the selected configuration and typically ranges between 9 and 11 bits. - -The increased dynamic range of the output makes it particularly useful for weak and/or narrowband signals. - -Block diagram (RX) -^^^^^^^^^^^^^^^^^^ - -.. image:: ../images/gateware-rx-only-basic-block-diagram.png - :align: center - -.. image:: ../images/gateware-ext-prec-rx-dsp-chain.png - :align: center - :width: 75% - -Block diagram (TX) -^^^^^^^^^^^^^^^^^^ - -.. image:: ../images/gateware-tx-only-basic-block-diagram.png - :align: center - -.. image:: ../images/gateware-ext-prec-tx-dsp-chain.png - :align: center - :width: 75% - -Features -^^^^^^^^ -* 16-bit I, 16-bit Q data format -* Receiver signal chain (RX extended-precision gateware): - * Optional DC offset removal (DC blocker) - * Configurable mixer (in fs/128 steps) - * Configurable decimation rates: 16x, 32x, 64x, 128x -* Transmitter signal chain (TX extended-precision gateware): - * Configurable interpolation rates: 16x, 32x, 64x, 128x -* SPI control interface for register configuration -* Double data rate (DDR) interface to RF transceiver -* Interface to MCU (SGPIO) - diff --git a/docs/source/hackrf_pro.rst b/docs/source/hackrf_pro.rst index e47dbb0b..18e4a151 100644 --- a/docs/source/hackrf_pro.rst +++ b/docs/source/hackrf_pro.rst @@ -2,8 +2,6 @@ HackRF Pro ================================================ -.. _hackrf_pro: - .. image:: ../images/hackrf-pro-preliminary-photo.jpg :alt: HackRF Pro diff --git a/docs/source/index.rst b/docs/source/index.rst index 401fbb3b..ce845e66 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -57,13 +57,6 @@ Welcome to HackRF's documentation! setting_gain virtual_machines - -.. toctree:: - :maxdepth: 2 - :caption: Gateware - - gateware - .. toctree:: :maxdepth: 2 :caption: Opera Cake Documentation diff --git a/docs/source/software_support.rst b/docs/source/software_support.rst index 66594e6b..e8487652 100644 --- a/docs/source/software_support.rst +++ b/docs/source/software_support.rst @@ -43,11 +43,6 @@ Software That Has Direct Support For HackRF * `https://xakcop.com/aprs-sdr `__ -* SigDigger (Windows/Linux/macOS) - - * `https://github.com/BatchDrake/SigDigger `__ - * Supports HackRF through SoapySDR / SoapyHackRF - Software That Can Use Data From HackRF @@ -79,4 +74,4 @@ Troubleshooting Recommendations Many of these tools require libhackrf and at times HackRF Tools. It may help you to have updated libhackrf and HackRF Tools when troubleshooting these applications. -It is also strongly suggested, and usually required, that your HackRF Tools and HackRF firmware match. +It is also strongly suggested, and usually required, that your HackRF Tools and HackRF firmware match. \ No newline at end of file diff --git a/firmware/CMakeLists.txt b/firmware/CMakeLists.txt index 844ae708..10c2d09d 100644 --- a/firmware/CMakeLists.txt +++ b/firmware/CMakeLists.txt @@ -20,17 +20,10 @@ # Top directory CMake project for HackRF firmware -option(CHECK_INCLUDES - "Check firmware sources for unused includes and transitive dependencies. (Requires iwyu)" OFF) - -cmake_minimum_required(VERSION 3.12.0) +cmake_minimum_required(VERSION 3.10.0) set(CMAKE_TOOLCHAIN_FILE toolchain-arm-cortex-m.cmake) project (hackrf_firmware_all C) -if(CHECK_INCLUDES) - include(include-what-you-use.cmake) -endif() - add_subdirectory(blinky) add_subdirectory(hackrf_usb) diff --git a/firmware/blinky/blinky.c b/firmware/blinky/blinky.c index 4bd11106..95b1173e 100644 --- a/firmware/blinky/blinky.c +++ b/firmware/blinky/blinky.c @@ -19,16 +19,13 @@ * Boston, MA 02110-1301, USA. */ -#include "delay.h" -#include "leds.h" -#include "pins.h" +#include "hackrf_core.h" #include "platform_detect.h" -#include "power.h" int main(void) { detect_hardware_platform(); - pins_setup(); + pin_setup(); #ifndef PRALINE /* enable 1V8 power supply so that the 1V8 LED lights up */ @@ -39,19 +36,19 @@ int main(void) #endif /* Blink LED1/2/3 on the board. */ - while (1) + while (1) { led_on(LED1); led_on(LED2); led_on(LED3); - delay_ms(150); - + delay(2000000); + led_off(LED1); led_off(LED2); led_off(LED3); - - delay_ms(150); + + delay(2000000); } return 0; diff --git a/firmware/common/LPC4320_M4_memory.ld b/firmware/common/LPC4320_M4_memory.ld index 48be94da..a5997f32 100644 --- a/firmware/common/LPC4320_M4_memory.ld +++ b/firmware/common/LPC4320_M4_memory.ld @@ -26,8 +26,7 @@ MEMORY { /* rom is really the shadow region that points to SPI flash or elsewhere */ rom (rx) : ORIGIN = 0x00000000, LENGTH = 1M - ram_local1 (rwx) : ORIGIN = 0x10000000, LENGTH = 64K - ram_usb (rw) : ORIGIN = 0x10010000, LENGTH = 32K + ram_local1 (rwx) : ORIGIN = 0x10000000, LENGTH = 96K ram_local2 (rwx) : ORIGIN = 0x10080000, LENGTH = 32K ram_sleep (rwx) : ORIGIN = 0x10088000, LENGTH = 8K } diff --git a/firmware/common/LPC4330_M4_memory.ld b/firmware/common/LPC4330_M4_memory.ld index 1d42ebee..1e886d3a 100644 --- a/firmware/common/LPC4330_M4_memory.ld +++ b/firmware/common/LPC4330_M4_memory.ld @@ -26,8 +26,7 @@ MEMORY { /* rom is really the shadow region that points to SPI flash or elsewhere */ rom (rx) : ORIGIN = 0x00000000, LENGTH = 128K - ram_local1 (rwx) : ORIGIN = 0x10000000, LENGTH = 96K - ram_usb(rw) : ORIGIN = 0x10018000, LENGTH = 32K + ram_local1 (rwx) : ORIGIN = 0x10000000, LENGTH = 128K ram_local2 (rwx) : ORIGIN = 0x10080000, LENGTH = 64K ram_sleep (rwx) : ORIGIN = 0x10090000, LENGTH = 8K } diff --git a/firmware/common/LPC43xx_M0_memory.ld b/firmware/common/LPC43xx_M0_memory.ld index 5a873132..cbf04d5e 100644 --- a/firmware/common/LPC43xx_M0_memory.ld +++ b/firmware/common/LPC43xx_M0_memory.ld @@ -22,5 +22,5 @@ MEMORY { - ram (rwx) : ORIGIN = 0x00000000, LENGTH = 20K + ram (rwx) : ORIGIN = 0x00000000, LENGTH = 28K } diff --git a/firmware/common/LPC43xx_M4_memory.ld b/firmware/common/LPC43xx_M4_memory.ld index fc7dcee7..b49e8cb9 100644 --- a/firmware/common/LPC43xx_M4_memory.ld +++ b/firmware/common/LPC43xx_M4_memory.ld @@ -23,24 +23,16 @@ MEMORY { /* Physical address in Flash used to copy Code from Flash to RAM */ - rom_flash (rx) : ORIGIN = 0x80000000, LENGTH = 1M - /* Buffers for LZ4 decompression */ - ram_lz4_in (rwx) : ORIGIN = 0x20000000, LENGTH = 4K - ram_lz4_out (rwx) : ORIGIN = 0x20001000, LENGTH = 4K - /* RAM for M0 code */ - ram_m0 (rwx) : ORIGIN = 0x20002000, LENGTH = 20K - /* RAM shared between M0 and M4 */ - ram_shared (rwx) : ORIGIN = 0x20007000, LENGTH = 4K - /* USB buffer. Straddles two blocks of RAM + rom_flash (rx) : ORIGIN = 0x80000000, LENGTH = 1M + ram_m0 (rwx) : ORIGIN = 0x20000000, LENGTH = 28K + ram_shared (rwx) : ORIGIN = 0x20007000, LENGTH = 4K + ram_usb (rwx) : ORIGIN = 0x20008000, LENGTH = 32K + /* ram_usb: USB buffer. Straddles two blocks of RAM * to get performance benefit of having two USB buffers addressable * simultaneously (on two different buses of the AHB multilayer matrix) */ - ram_samp (rwx) : ORIGIN = 0x20008000, LENGTH = 32K } -lz4_in_buf = ORIGIN(ram_lz4_in); -lz4_out_buf = ORIGIN(ram_lz4_out); -usb_samp_buffer = ORIGIN(ram_samp); usb_bulk_buffer = ORIGIN(ram_usb); m0_state = ORIGIN(ram_shared); PROVIDE(__ram_m0_start__ = ORIGIN(ram_m0)); diff --git a/firmware/common/adc.c b/firmware/common/adc.c index 9355567f..5d1ddaca 100644 --- a/firmware/common/adc.c +++ b/firmware/common/adc.c @@ -19,13 +19,10 @@ * Boston, MA 02110-1301, USA. */ -#include - +#include "adc.h" #include #include -#include "adc.h" - uint16_t adc_read(uint8_t pin) { bool alt_pin = (pin & 0x80); diff --git a/firmware/common/adc.h b/firmware/common/adc.h index b74125af..94481678 100644 --- a/firmware/common/adc.h +++ b/firmware/common/adc.h @@ -19,9 +19,12 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __ADC_H__ +#define __ADC_H__ #include uint16_t adc_read(uint8_t pin); void adc_off(void); + +#endif // __ADC_H__ diff --git a/firmware/common/bitband.h b/firmware/common/bitband.h index 8a0afed5..dcf7aefb 100644 --- a/firmware/common/bitband.h +++ b/firmware/common/bitband.h @@ -20,7 +20,8 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __BITBAND_H__ +#define __BITBAND_H__ #include @@ -36,3 +37,5 @@ void peripheral_bitband_clear( uint32_t peripheral_bitband_get( volatile void* const peripheral_address, const uint_fast8_t bit_number); + +#endif //__BITBAND_H__ diff --git a/firmware/common/clock_io.c b/firmware/common/clkin.c similarity index 75% rename from firmware/common/clock_io.c rename to firmware/common/clkin.c index d4d14af0..5ab8123a 100644 --- a/firmware/common/clock_io.c +++ b/firmware/common/clkin.c @@ -1,5 +1,5 @@ /* - * Copyright 2022-2026 Great Scott Gadgets + * Copyright 2022 Great Scott Gadgets * * This file is part of HackRF. * @@ -19,27 +19,12 @@ * Boston, MA 02110-1301, USA. */ -#include "clock_io.h" - -#include -#include - +#include "gpdma.h" #include #include #include -#include #include - -#include "gpdma.h" -#include "gpio.h" -#include "platform_detect.h" -#ifdef IS_NOT_PRALINE - #include "sgpio.h" -#endif -#ifdef IS_PRALINE - #include "fpga.h" - #include "platform_gpio.h" -#endif +#include #define CLOCK_CYCLES_1_MS (204000) #define MEASUREMENT_WINDOW_MS (50) @@ -124,47 +109,4 @@ void clkin_detect_init(void) uint32_t clkin_frequency(void) { return TIMER2_CR3 * (1000 / MEASUREMENT_WINDOW_MS); -} - -void trigger_enable(const bool enable) -{ -#ifdef IS_NOT_PRALINE - if (IS_NOT_PRALINE) { - gpio_write(sgpio_config.gpio_trigger_enable, enable); - } -#endif -#ifdef IS_PRALINE - if (IS_PRALINE) { - fpga_set_trigger_enable(&fpga, enable); - } -#endif -} - -#ifdef IS_PRALINE -void clkin_ctrl_set(const clkin_signal_t signal) -{ - gpio_write(platform_gpio()->clkin_ctrl, signal & 1); -} - -void p1_ctrl_set(const p1_ctrl_signal_t signal) -{ - const platform_gpio_t* gpio = platform_gpio(); - - gpio_write(gpio->p1_ctrl0, signal & 1); - gpio_write(gpio->p1_ctrl1, (signal >> 1) & 1); - gpio_write(gpio->p1_ctrl2, (signal >> 2) & 1); -} - -void p2_ctrl_set(const p2_ctrl_signal_t signal) -{ - const platform_gpio_t* gpio = platform_gpio(); - - gpio_write(gpio->p2_ctrl0, signal & 1); - gpio_write(gpio->p2_ctrl1, (signal >> 1) & 1); -} - -void pps_out_set(const uint8_t value) -{ - gpio_write(platform_gpio()->pps_out, value & 1); -} -#endif +}; diff --git a/firmware/common/da7219.h b/firmware/common/clkin.h similarity index 80% rename from firmware/common/da7219.h rename to firmware/common/clkin.h index c81ece20..2f2fa274 100644 --- a/firmware/common/da7219.h +++ b/firmware/common/clkin.h @@ -1,5 +1,5 @@ /* - * Copyright 2026 Great Scott Gadgets + * Copyright 2022 Great Scott Gadgets * * This file is part of HackRF. * @@ -19,10 +19,12 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __CLKIN_H__ +#define __CLKIN_H__ -#include +#include -#define DA7219_ADDRESS 0x1A +void clkin_detect_init(void); +uint32_t clkin_frequency(void); -bool da7219_detect(void); +#endif //__CLKIN_H__ diff --git a/firmware/common/clock_gen.c b/firmware/common/clock_gen.c deleted file mode 100644 index a709960b..00000000 --- a/firmware/common/clock_gen.c +++ /dev/null @@ -1,420 +0,0 @@ -/* - * Copyright 2026 Great Scott Gadgets - * - * This file is part of HackRF. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#include "clock_gen.h" - -#include - -#include "hackrf_ui.h" -#include "platform_detect.h" -#include "sgpio.h" -#include "si5351c.h" -#if defined(IS_HACKRF_ONE) || defined(IS_PRALINE) - #include "delay.h" - #include "portapack.h" -#endif - -void clock_gen_init(void) -{ - si5351c_init(&si5351c); - si5351c_disable_all_outputs(&si5351c); - si5351c_disable_oeb_pin_control(&si5351c); - si5351c_power_down_all_clocks(&si5351c); - si5351c_set_crystal_configuration(&si5351c); - si5351c_enable_xo_and_ms_fanout(&si5351c); - - /* - * Clocks on HackRF One r9: - * CLK0 -> MAX5864/CPLD/SGPIO (sample clocks) - * CLK1 -> RFFC5072/MAX2839 - * CLK2 -> External Clock Output/LPC43xx (power down at boot) - * - * Clocks on other platforms: - * CLK0 -> MAX5864/CPLD - * CLK1 -> CPLD - * CLK2 -> SGPIO - * CLK3 -> External Clock Output (power down at boot) - * CLK4 -> RFFC5072 (MAX2837 on rad1o) - * CLK5 -> MAX2837 (MAX2871 on rad1o) - * CLK6 -> none - * CLK7 -> LPC43xx (uses a 12MHz crystal by default) - * - * Clocks on Praline: - * CLK0 -> AFE_CLK (MAX5864/FPGA) - * CLK1 -> SCT_CLK - * CLK2 -> MCU_CLK (uses a 12MHz crystal by default) - * CLK3 -> External Clock Output (power down at boot) - * CLK4 -> XCVR_CLK (MAX2837) - * CLK5 -> MIX_CLK (RFFC5072) - * CLK6 -> AUX_CLK1 - * CLK7 -> AUX_CLK2 - */ - -#ifdef IS_H1_R9 - if (IS_H1_R9) { - /* MS0/CLK0 is the reference for both RFFC5071 and MAX2839. */ - si5351c_configure_multisynth( - &si5351c, - 0, - 20 * 128 - 512, - 0, - 1, - 0); /* 800/20 = 40MHz */ - } -#endif -#ifdef IS_NOT_H1_R9 - if (IS_NOT_H1_R9) { - /* MS4/CLK4 is the source for the RFFC5071 mixer (MAX2837 on rad1o). */ - si5351c_configure_multisynth( - &si5351c, - 4, - 20 * 128 - 512, - 0, - 1, - 0); /* 800/20 = 40MHz */ - /* MS5/CLK5 is the source for the MAX2837 clock input (MAX2871 on rad1o). */ - si5351c_configure_multisynth( - &si5351c, - 5, - 20 * 128 - 512, - 0, - 1, - 0); /* 800/20 = 40MHz */ - } -#endif - - /* MS6/CLK6 is unused. */ - /* MS7/CLK7 is unused. */ - - /* Set to 10 MHz, the common rate between Jawbreaker and HackRF One. */ - sample_rate_set(SR_FP_MHZ(10), true); - - si5351c_configure_clock_control(&si5351c); - si5351c_change_input(&si5351c, SI5351C_INPUT_XTAL); - // soft reset - si5351c_reset_plls(&si5351c, SI5351C_PLL_MASK_BOTH); - si5351c_enable_clock_outputs(&si5351c); -} - -void clock_gen_shutdown(void) -{ - si5351c_disable_all_outputs(&si5351c); - si5351c_disable_oeb_pin_control(&si5351c); - si5351c_power_down_all_clocks(&si5351c); -} - -clock_source_t activate_best_clock_source(void) -{ -#ifdef IS_EXPANSION_COMPATIBLE - if (IS_EXPANSION_COMPATIBLE) { - /* Ensure PortaPack reference oscillator is off while checking for external clock input. */ - if (portapack_present()) { - portapack_reference_oscillator(false); - } - } -#endif - - clock_source_t source = CLOCK_SOURCE_HACKRF; - - /* Check for external clock input. */ - if (si5351c_clkin_signal_valid(&si5351c)) { - source = CLOCK_SOURCE_EXTERNAL; - } else { -#ifdef IS_EXPANSION_COMPATIBLE - if (IS_EXPANSION_COMPATIBLE) { - /* Enable PortaPack reference oscillator (if present), and check for valid clock. */ - if (portapack_present()) { - portapack_reference_oscillator(true); - delay_ms(18); // for oscillator to enable. - if (si5351c_clkin_signal_valid(&si5351c)) { - source = CLOCK_SOURCE_PORTAPACK; - } else { - portapack_reference_oscillator(false); - } - } - } -#endif - /* No external or PortaPack clock was found. Use HackRF Si5351C crystal. */ - } - - si5351c_input_t input = (source == CLOCK_SOURCE_HACKRF) ? SI5351C_INPUT_XTAL : - SI5351C_INPUT_CLKIN; - si5351c_change_input(&si5351c, input); - - hackrf_ui()->set_clock_source(source); - - return source; -} - -/* - * Closest fraction to m/d with denominator <= max_den. - * Returns result in *r / *s with gcd(*r, *s) == 1 and 0 < *s <= max_den. - * Straight port from CPython's fractions, and better documented there. - */ -void limit_denominator( - uint64_t m, - uint64_t d, - const uint64_t max_den, - uint64_t* r, - uint64_t* s) -{ - if (d <= max_den) { - *r = m; - *s = d; - return; - } - - uint64_t p0 = 0, q0 = 1, p1 = 1, q1 = 0; - uint64_t n = m, orig_d = d; - uint64_t tmp; - - while (1) { - uint64_t a = n / d; - uint64_t q2 = q0 + a * q1; - - if (q2 > max_den) - break; - - tmp = p0 + a * p1; - p0 = p1; - q0 = q1; - p1 = tmp; - q1 = q2; - - tmp = n - a * d; - n = d; - d = tmp; - if (d == 0) - break; - } - - uint64_t k = (max_den - q0) / q1; - - /* Return closer candidate. */ - if (2 * d * (q0 + k * q1) <= orig_d) { - *r = p1; - *s = q1; - } else { - *r = p0 + k * p1; - *s = q0 + k * q1; - } -} - -/* - * Configure clock generator to produce sample clock in units of 1/(2**36) Hz. - * Can be called with program=false for a dry run that returns the resultant - * frequency without actually configuring the clock generator. - * - * The clock generator output frequency is: - * - * fs = 128 * vco / (512 + p1 + p2/p3)) - * - * where p1, p2, and p3 are register values. - * - * For more information see: - * https://www.pa3fwm.nl/technotes/tn42a-si5351-programming.html - */ -fp_28_36_t sample_rate_set(const fp_28_36_t sample_rate, const bool program) -{ - const uint64_t vco_hz = 800 * 1000ULL * 1000ULL; - uint64_t p1, p2, p3; - uint64_t n, d, q1, q2, q3, r1, r2; - fp_28_36_t resultant_rate; - - /* - * First double the sample rate so that we can produce a clock at twice - * the intended sample rate. The 2x clock is sometimes used directly, - * and it is divided by two in an output divider to produce the actual - * AFE clock. - */ - fp_28_36_t rate = sample_rate * 2; - - /* - * Computes p1 = (N << 36) / rate - 512, where N = 128 * vco_hz. - * - * Full numerator (N << 36) is 73 bits, so we split the division: - * - * (N << 36) / rate = ((N << 27) / rate) << 9 - * + (((N << 27) % rate) << 9) / rate - * - * IMPORTANT: Assumes sample rate is in [200e3 << 36, 43.6e6 << 36]. - */ - const uint64_t A = (128 * vco_hz) << 27; - - q1 = A / rate; - r1 = A % rate; - - // Remaining 9 bits with long division. - q2 = 0; - r2 = r1; - for (int j = 0; j < 9; j++) { - uint64_t msb = r2 >> 63; - r2 <<= 1; - q2 <<= 1; - if (msb || r2 >= rate) { - r2 -= rate; - q2 |= 1; - } - } - - p1 = (q1 << 9) + q2 - 512; - - if (r2) { - /* Use the remainder for the fractional part. */ - n = r2; - d = rate; - - /* Reduce fraction. */ - const uint64_t p3_max = 0xfffff; - limit_denominator(n, d, p3_max, &p2, &p3); - - /* Roll over to next p1 to enable integer mode. */ - if (p2 >= p3) { - p1++; - p2 = 0; - } - } else { - p2 = 0; - } - - /* Maximum: (128 * 2048) - 512 */ - if (p1 > 0x3fe00) { - p1 = 0x3fe00; - p2 = 0; - } - - if (p2 == 0) { - /* Use unity denominator for integer mode. */ - p3 = 1; - n = (128 * vco_hz) << 18; - d = (p1 + 512); - q1 = n / d; - r1 = n % d; - q2 = ((r1 << 18) + (d / 2)) / d; - resultant_rate = (q1 << 18) + q2; - } else { - n = p3 * vco_hz * 128; - d = p3 * (p1 + 512) + p2; - q1 = n / d; - r1 = n % d; - q2 = (r1 << 18) / d; - r2 = (r1 << 18) % d; - q3 = ((r2 << 18) + (d / 2)) / d; - resultant_rate = (q1 << 36) + (q2 << 18) + q3; - } - - /* Return MCU sample rate, not AFE clock rate. */ - resultant_rate = (resultant_rate + 1) / 2; - - if (!program) { - return resultant_rate; - } - - bool streaming = sgpio_cpld_stream_is_enabled(&sgpio_config); - - if (streaming) { - sgpio_cpld_stream_disable(&sgpio_config); - } - -#ifdef IS_NOT_PRALINE - if (IS_NOT_PRALINE) { - /* Integer mode can be enabled if p1 is even and p2 is zero. */ - if (p1 & 0x1 || p2) { - si5351c_set_int_mode(&si5351c, 0, 0); - } else { - si5351c_set_int_mode(&si5351c, 0, 1); - } - - #ifdef IS_H1_R9 - if (IS_H1_R9) { - /* - * On HackRF One r9 all sample clocks are externally derived - * from MS1/CLK1 operating at twice the sample rate. - */ - si5351c_configure_multisynth(&si5351c, 1, p1, p2, p3, 0); - } - #endif - #ifdef IS_NOT_H1_R9 - if (IS_NOT_H1_R9) { - /* - * On other platforms the clock generator produces three - * different sample clocks, all derived from multisynth 0. - */ - /* MS0/CLK0 is the source for the MAX5864/CPLD (CODEC_CLK). */ - si5351c_configure_multisynth(&si5351c, 0, p1, p2, p3, 1); - - /* MS0/CLK1 is the source for the CPLD (CODEC_X2_CLK). */ - si5351c_configure_multisynth( - &si5351c, - 1, - 0, - 0, - 0, - 0); //p1 doesn't matter - - /* MS0/CLK2 is the source for SGPIO (CODEC_X2_CLK) */ - si5351c_configure_multisynth( - &si5351c, - 2, - 0, - 0, - 0, - 0); //p1 doesn't matter - } - #endif - } -#endif -#ifdef IS_PRALINE - if (IS_PRALINE) { - /* MS0/CLK0 is the source for the MAX5864 (AFE_CLK). */ - si5351c_configure_multisynth(&si5351c, 0, p1, p2, p3, 1); - - /* MS1/CLK1 is the source for the FPGA (FPGA_CLK and SCT_CLK). */ - si5351c_configure_multisynth(&si5351c, 1, p1, p2, p3, 1); - - /* Delay FPGA_CLK relative to AFE_CLK. */ - uint8_t phase_offset = 0; - if (p1 < 2100) { - phase_offset = (p1 >> 4) - 6; - } - si5351c_set_phase(&si5351c, 1, phase_offset); - - if ((detected_revision() & ~BOARD_REV_GSG) < BOARD_REV_PRALINE_R1_1) { - /* - * On older boards FPGA_CLK is on CLK2 while SCT_CLK is on - * CLK1. We configure both so that behavior is consistent with - * newer boards that use CLK1 for both FPGA_CLK and SCT_CLK. - */ - si5351c_configure_multisynth(&si5351c, 2, p1, p2, p3, 1); - si5351c_set_phase(&si5351c, 2, phase_offset); - } - - /* Reset PLL to synchronize output clock phase. */ - si5351c_reset_plls(&si5351c, SI5351C_PLL_MASK_A); - } -#endif - - if (streaming) { - sgpio_cpld_stream_enable(&sgpio_config); - } - - return resultant_rate; -} diff --git a/firmware/common/clock_gen.h b/firmware/common/clock_gen.h deleted file mode 100644 index fa1d3da0..00000000 --- a/firmware/common/clock_gen.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2026 Great Scott Gadgets - * - * This file is part of HackRF. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -#include "fixed_point.h" - -typedef enum { - CLOCK_SOURCE_HACKRF = 0, - CLOCK_SOURCE_EXTERNAL = 1, - CLOCK_SOURCE_PORTAPACK = 2, -} clock_source_t; - -void clock_gen_init(void); -void clock_gen_shutdown(void); - -clock_source_t activate_best_clock_source(void); - -fp_28_36_t sample_rate_set(const fp_28_36_t sample_rate, const bool program); - -#ifdef __cplusplus -} -#endif diff --git a/firmware/common/clock_io.h b/firmware/common/clock_io.h deleted file mode 100644 index 4868b2d9..00000000 --- a/firmware/common/clock_io.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2022-2026 Great Scott Gadgets - * - * This file is part of HackRF. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#pragma once - -#include -#include - -void clkin_detect_init(void); -uint32_t clkin_frequency(void); - -void trigger_enable(const bool enable); - -#ifdef IS_PRALINE -typedef enum { - CLKIN_SIGNAL_P1 = 0, - CLKIN_SIGNAL_P22 = 1, -} clkin_signal_t; - -typedef enum { - P1_SIGNAL_TRIGGER_IN = 0, - P1_SIGNAL_AUX_CLK1 = 1, - P1_SIGNAL_CLKIN = 2, - P1_SIGNAL_TRIGGER_OUT = 3, - P1_SIGNAL_P22_CLKIN = 4, - P1_SIGNAL_P2_5 = 5, - P1_SIGNAL_NC = 6, - P1_SIGNAL_AUX_CLK2 = 7, -} p1_ctrl_signal_t; - -typedef enum { - P2_SIGNAL_CLK3 = 0, - P2_SIGNAL_TRIGGER_IN = 2, - P2_SIGNAL_TRIGGER_OUT = 3, -} p2_ctrl_signal_t; - -void clkin_ctrl_set(const clkin_signal_t value); -void p1_ctrl_set(const p1_ctrl_signal_t signal); -void p2_ctrl_set(const p2_ctrl_signal_t signal); - -void pps_out_set(const uint8_t value); -#endif diff --git a/firmware/common/cpld_jtag.c b/firmware/common/cpld_jtag.c index ab998808..1641499b 100644 --- a/firmware/common/cpld_jtag.c +++ b/firmware/common/cpld_jtag.c @@ -20,51 +20,17 @@ */ #include "cpld_jtag.h" +#include "hackrf_core.h" +#include "xapp058/micro.h" +#include +#include -#include "platform_detect.h" -#include "platform_gpio.h" -#ifdef IS_NOT_PRALINE - #include - #include - #include "xapp058/micro.h" - #include "cpld_xc2c.h" -#endif - -#ifdef IS_NOT_PRALINE +#ifndef PRALINE static refill_buffer_cb refill_buffer; static uint32_t xsvf_buffer_len, xsvf_pos; static unsigned char* xsvf_buffer; #endif -/* Driver instance. */ -jtag_gpio_t jtag_gpio_cpld = {}; - -jtag_t jtag_cpld = { - .gpio = &jtag_gpio_cpld, -}; - -void cpld_jtag_pin_setup(void) -{ - const platform_gpio_t* gpio = platform_gpio(); - - jtag_gpio_cpld.gpio_tck = gpio->cpld_tck; - -#ifdef IS_NOT_PRALINE - if (IS_NOT_PRALINE) { - jtag_gpio_cpld.gpio_tms = gpio->cpld_tms; - jtag_gpio_cpld.gpio_tdi = gpio->cpld_tdi; - jtag_gpio_cpld.gpio_tdo = gpio->cpld_tdo; - } -#endif - -#ifdef IS_EXPANSION_COMPATIBLE - if (IS_EXPANSION_COMPATIBLE) { - jtag_gpio_cpld.gpio_pp_tms = gpio->cpld_pp_tms; - jtag_gpio_cpld.gpio_pp_tdo = gpio->cpld_pp_tdo; - } -#endif -} - void cpld_jtag_take(jtag_t* const jtag) { const jtag_gpio_t* const gpio = jtag->gpio; @@ -72,37 +38,25 @@ void cpld_jtag_take(jtag_t* const jtag) /* Set initial GPIO state to the voltages of the internal or external pull-ups/downs, * to avoid any glitches. */ -#ifdef IS_EXPANSION_COMPATIBLE - if (IS_EXPANSION_COMPATIBLE) { - gpio_set(gpio->gpio_pp_tms); - } +#if (defined HACKRF_ONE || defined PRALINE) + gpio_set(gpio->gpio_pp_tms); #endif - gpio_clear(gpio->gpio_tck); - -#ifdef IS_NOT_PRALINE - if (IS_NOT_PRALINE) { - gpio_set(gpio->gpio_tms); - gpio_set(gpio->gpio_tdi); - } +#ifndef PRALINE + gpio_set(gpio->gpio_tms); + gpio_set(gpio->gpio_tdi); #endif -#ifdef IS_EXPANSION_COMPATIBLE - if (IS_EXPANSION_COMPATIBLE) { - /* Do not drive PortaPack-specific TMS pin initially, just to be cautious. */ - gpio_input(gpio->gpio_pp_tms); - gpio_input(gpio->gpio_pp_tdo); - } +#if (defined HACKRF_ONE || defined PRALINE) + /* Do not drive PortaPack-specific TMS pin initially, just to be cautious. */ + gpio_input(gpio->gpio_pp_tms); + gpio_input(gpio->gpio_pp_tdo); #endif - gpio_output(gpio->gpio_tck); - -#ifdef IS_NOT_PRALINE - if (IS_NOT_PRALINE) { - gpio_output(gpio->gpio_tms); - gpio_output(gpio->gpio_tdi); - gpio_input(gpio->gpio_tdo); - } +#ifndef PRALINE + gpio_output(gpio->gpio_tms); + gpio_output(gpio->gpio_tdi); + gpio_input(gpio->gpio_tdo); #endif } @@ -113,26 +67,20 @@ void cpld_jtag_release(jtag_t* const jtag) /* Make all pins inputs when JTAG interface not active. * Let the pull-ups/downs do the work. */ -#ifdef IS_EXPANSION_COMPATIBLE - if (IS_EXPANSION_COMPATIBLE) { - /* Do not drive PortaPack-specific pins, initially, just to be cautious. */ - gpio_input(gpio->gpio_pp_tms); - gpio_input(gpio->gpio_pp_tdo); - } +#if (defined HACKRF_ONE || defined PRALINE) + /* Do not drive PortaPack-specific pins, initially, just to be cautious. */ + gpio_input(gpio->gpio_pp_tms); + gpio_input(gpio->gpio_pp_tdo); #endif - gpio_input(gpio->gpio_tck); - -#ifdef IS_NOT_PRALINE - if (IS_NOT_PRALINE) { - gpio_input(gpio->gpio_tms); - gpio_input(gpio->gpio_tdi); - gpio_input(gpio->gpio_tdo); - } +#ifndef PRALINE + gpio_input(gpio->gpio_tms); + gpio_input(gpio->gpio_tdi); + gpio_input(gpio->gpio_tdo); #endif } -#ifdef IS_NOT_PRALINE +#ifndef PRALINE /* return 0 if success else return error code see xsvfExecute() */ int cpld_jtag_program( jtag_t* const jtag, @@ -163,16 +111,4 @@ unsigned char cpld_jtag_get_next_byte(void) xsvf_pos++; return byte; } - -bool cpld_jtag_sram_load(jtag_t* const jtag) -{ - cpld_jtag_take(jtag); - cpld_xc2c64a_jtag_sram_write(jtag, &cpld_hackrf_program_sram); - const bool success = cpld_xc2c64a_jtag_sram_verify( - jtag, - &cpld_hackrf_program_sram, - &cpld_hackrf_verify); - cpld_jtag_release(jtag); - return success; -} -#endif +#endif \ No newline at end of file diff --git a/firmware/common/cpld_jtag.h b/firmware/common/cpld_jtag.h index 39cfc1e7..9219dbcb 100644 --- a/firmware/common/cpld_jtag.h +++ b/firmware/common/cpld_jtag.h @@ -19,33 +19,32 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __CPLD_JTAG_H__ +#define __CPLD_JTAG_H__ -#include #include #include "gpio.h" -typedef struct { +typedef struct jtag_gpio_t { gpio_t gpio_tck; -#ifdef IS_NOT_PRALINE +#ifndef PRALINE gpio_t gpio_tms; gpio_t gpio_tdi; gpio_t gpio_tdo; #endif -#ifdef IS_EXPANSION_COMPATIBLE +#if (defined HACKRF_ONE || defined PRALINE) gpio_t gpio_pp_tms; gpio_t gpio_pp_tdo; #endif } jtag_gpio_t; -typedef struct { +typedef struct jtag_t { jtag_gpio_t* const gpio; } jtag_t; typedef void (*refill_buffer_cb)(void); -void cpld_jtag_pin_setup(void); void cpld_jtag_take(jtag_t* const jtag); void cpld_jtag_release(jtag_t* const jtag); @@ -60,8 +59,5 @@ int cpld_jtag_program( unsigned char* const buffer, refill_buffer_cb refill); unsigned char cpld_jtag_get_next_byte(void); -bool cpld_jtag_sram_load(jtag_t* const jtag); -/* Driver instance. */ -extern jtag_gpio_t jtag_gpio_cpld; -extern jtag_t jtag_cpld; +#endif //__CPLD_JTAG_H__ diff --git a/firmware/common/cpld_xc2c.c b/firmware/common/cpld_xc2c.c index ec5ffeb1..58a5a6b6 100644 --- a/firmware/common/cpld_xc2c.c +++ b/firmware/common/cpld_xc2c.c @@ -22,10 +22,10 @@ #include "cpld_xc2c.h" -#include - #include "crc.h" -#include "gpio.h" + +#include +#include // clang-format off typedef enum { diff --git a/firmware/common/cpld_xc2c.h b/firmware/common/cpld_xc2c.h index c48dae31..2e33967b 100644 --- a/firmware/common/cpld_xc2c.h +++ b/firmware/common/cpld_xc2c.h @@ -20,10 +20,11 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __CPLD_XC2C_H__ +#define __CPLD_XC2C_H__ -#include #include +#include #include "cpld_jtag.h" @@ -68,3 +69,5 @@ bool cpld_xc2c64a_jtag_sram_verify( extern const cpld_xc2c64a_program_t cpld_hackrf_program_sram; extern const cpld_xc2c64a_verify_t cpld_hackrf_verify; extern const cpld_xc2c64a_row_addresses_t cpld_hackrf_row_addresses; + +#endif /*__CPLD_XC2C_H__*/ diff --git a/firmware/common/cpu_clock.c b/firmware/common/cpu_clock.c deleted file mode 100644 index 32fd012c..00000000 --- a/firmware/common/cpu_clock.c +++ /dev/null @@ -1,262 +0,0 @@ -/* - * Copyright 2026 Great Scott Gadgets - * - * This file is part of HackRF. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#include "cpu_clock.h" - -#include - -#include -#if defined(IS_JAWBREAKER) || defined(IS_HACKRF_ONE) || defined(IS_PRALINE) - #include -#endif - -#include "delay.h" -#include "i2c_bus.h" -#include "i2c_lpc.h" -#include "si5351c.h" - -/* We start with the CPU clock at 96MHz */ -unsigned int cpu_clock_mhz = 96; - -/* -Configure PLL1 (Main MCU Clock) to max speed (204MHz). -Note: PLL1 clock is used by M4/M0 core, Peripheral, APB1. -This function shall be called after cpu_clock_init(). -*/ -static void cpu_clock_pll1_max_speed(void) -{ - uint32_t reg_val; - - /* This function implements the sequence recommended in: - * UM10503 Rev 2.4 (Aug 2018), section 13.2.1.1, page 167. */ - - /* 1. Select the IRC as BASE_M4_CLK source. */ - reg_val = CGU_BASE_M4_CLK; - reg_val &= ~CGU_BASE_M4_CLK_CLK_SEL_MASK; - reg_val |= CGU_BASE_M4_CLK_CLK_SEL(CGU_SRC_IRC) | CGU_BASE_M4_CLK_AUTOBLOCK(1); - CGU_BASE_M4_CLK = reg_val; - - /* CPU is now at 12MHz */ - cpu_clock_mhz = 12; - - /* 2. Enable the crystal oscillator. */ - CGU_XTAL_OSC_CTRL &= ~CGU_XTAL_OSC_CTRL_ENABLE_MASK; - - /* 3. Wait 250us. */ - delay_us(250); - - /* 4. Set the AUTOBLOCK bit. */ - CGU_PLL1_CTRL |= CGU_PLL1_CTRL_AUTOBLOCK(1); - - /* 5. Reconfigure PLL1 to produce the final output frequency, with the - * crystal oscillator as clock source. */ - reg_val = CGU_PLL1_CTRL; - // clang-format off - reg_val &= ~( CGU_PLL1_CTRL_CLK_SEL_MASK | - CGU_PLL1_CTRL_PD_MASK | - CGU_PLL1_CTRL_FBSEL_MASK | - CGU_PLL1_CTRL_BYPASS_MASK | - CGU_PLL1_CTRL_DIRECT_MASK | - CGU_PLL1_CTRL_PSEL_MASK | - CGU_PLL1_CTRL_MSEL_MASK | - CGU_PLL1_CTRL_NSEL_MASK ); - /* Set PLL1 up to 12MHz * 17 = 204MHz. - * Direct mode: FCLKOUT = FCCO = M*(FCLKIN/N) */ - reg_val |= CGU_PLL1_CTRL_CLK_SEL(CGU_SRC_XTAL) | - CGU_PLL1_CTRL_PSEL(0) | - CGU_PLL1_CTRL_NSEL(0) | - CGU_PLL1_CTRL_MSEL(16) | - CGU_PLL1_CTRL_FBSEL(0) | - CGU_PLL1_CTRL_DIRECT(1); - // clang-format on - CGU_PLL1_CTRL = reg_val; - - /* 6. Wait for PLL1 to lock. */ - while (!(CGU_PLL1_STAT & CGU_PLL1_STAT_LOCK_MASK)) {} - - /* 7. Set the PLL1 P-divider to divide by 2 (DIRECT=0, PSEL=0). */ - CGU_PLL1_CTRL &= ~CGU_PLL1_CTRL_DIRECT_MASK; - - /* 8. Select PLL1 as BASE_M4_CLK source. */ - reg_val = CGU_BASE_M4_CLK; - reg_val &= ~CGU_BASE_M4_CLK_CLK_SEL_MASK; - reg_val |= CGU_BASE_M4_CLK_CLK_SEL(CGU_SRC_PLL1); - CGU_BASE_M4_CLK = reg_val; - - /* CPU is now at 102MHz */ - cpu_clock_mhz = 102; - - /* 9. Wait 50us. */ - delay_us(50); - - /* 10. Set the PLL1 P-divider to direct output mode (DIRECT=1). */ - CGU_PLL1_CTRL |= CGU_PLL1_CTRL_DIRECT_MASK; - - /* CPU is now at 204MHz */ - cpu_clock_mhz = 204; -} - -/* clock startup for LPC4320 configure PLL1 to max speed (204MHz). -Note: PLL1 clock is used by M4/M0 core, Peripheral, APB1. */ -void cpu_clock_init(void) -{ - /* use IRC as clock source for APB1 (including I2C0) */ - CGU_BASE_APB1_CLK = CGU_BASE_APB1_CLK_CLK_SEL(CGU_SRC_IRC); - - /* use IRC as clock source for APB3 */ - CGU_BASE_APB3_CLK = CGU_BASE_APB3_CLK_CLK_SEL(CGU_SRC_IRC); - - //FIXME disable I2C - /* Kick I2C0 down to 400kHz when we switch over to APB1 clock = 204MHz */ - i2c_bus_start(si5351c.bus, &i2c_config_fast_clock); - - /* - * 12MHz clock is entering LPC XTAL1/OSC input now. - * On HackRF One and Jawbreaker, there is a 12 MHz crystal at the LPC. - * Set up PLL1 to run from XTAL1 input. - */ - - //FIXME a lot of the details here should be in a CGU driver - - /* set xtal oscillator to low frequency mode */ - CGU_XTAL_OSC_CTRL &= ~CGU_XTAL_OSC_CTRL_HF_MASK; - - cpu_clock_pll1_max_speed(); - - /* use XTAL_OSC as clock source for APB1 */ - CGU_BASE_APB1_CLK = - CGU_BASE_APB1_CLK_AUTOBLOCK(1) | CGU_BASE_APB1_CLK_CLK_SEL(CGU_SRC_XTAL); - - /* use XTAL_OSC as clock source for APB3 */ - CGU_BASE_APB3_CLK = - CGU_BASE_APB3_CLK_AUTOBLOCK(1) | CGU_BASE_APB3_CLK_CLK_SEL(CGU_SRC_XTAL); - - /* use XTAL_OSC as clock source for PLL0USB */ - CGU_PLL0USB_CTRL = CGU_PLL0USB_CTRL_PD(1) | CGU_PLL0USB_CTRL_AUTOBLOCK(1) | - CGU_PLL0USB_CTRL_CLK_SEL(CGU_SRC_XTAL); - while (CGU_PLL0USB_STAT & CGU_PLL0USB_STAT_LOCK_MASK) {} - - /* configure PLL0USB to produce 480 MHz clock from 12 MHz XTAL_OSC */ - /* Values from User Manual v1.4 Table 94, for 12MHz oscillator. */ - CGU_PLL0USB_MDIV = 0x06167FFA; - CGU_PLL0USB_NP_DIV = 0x00302062; - CGU_PLL0USB_CTRL |= - (CGU_PLL0USB_CTRL_PD(1) | CGU_PLL0USB_CTRL_DIRECTI(1) | - CGU_PLL0USB_CTRL_DIRECTO(1) | CGU_PLL0USB_CTRL_CLKEN(1)); - - /* power on PLL0USB and wait until stable */ - CGU_PLL0USB_CTRL &= ~CGU_PLL0USB_CTRL_PD_MASK; - while (!(CGU_PLL0USB_STAT & CGU_PLL0USB_STAT_LOCK_MASK)) {} - - /* use PLL0USB as clock source for USB0 */ - CGU_BASE_USB0_CLK = CGU_BASE_USB0_CLK_AUTOBLOCK(1) | - CGU_BASE_USB0_CLK_CLK_SEL(CGU_SRC_PLL0USB); - - /* Switch peripheral clock over to use PLL1 (204MHz) */ - CGU_BASE_PERIPH_CLK = CGU_BASE_PERIPH_CLK_AUTOBLOCK(1) | - CGU_BASE_PERIPH_CLK_CLK_SEL(CGU_SRC_PLL1); - - /* Switch APB1 clock over to use PLL1 (204MHz) */ - CGU_BASE_APB1_CLK = - CGU_BASE_APB1_CLK_AUTOBLOCK(1) | CGU_BASE_APB1_CLK_CLK_SEL(CGU_SRC_PLL1); - - /* Switch APB3 clock over to use PLL1 (204MHz) */ - CGU_BASE_APB3_CLK = - CGU_BASE_APB3_CLK_AUTOBLOCK(1) | CGU_BASE_APB3_CLK_CLK_SEL(CGU_SRC_PLL1); - - CGU_BASE_SSP0_CLK = - CGU_BASE_SSP0_CLK_AUTOBLOCK(1) | CGU_BASE_SSP0_CLK_CLK_SEL(CGU_SRC_PLL1); - - CGU_BASE_SSP1_CLK = - CGU_BASE_SSP1_CLK_AUTOBLOCK(1) | CGU_BASE_SSP1_CLK_CLK_SEL(CGU_SRC_PLL1); - -#ifdef IS_NOT_RAD1O - if (IS_NOT_RAD1O) { - /* Disable unused clocks */ - /* Start with PLLs */ - CGU_PLL0AUDIO_CTRL = CGU_PLL0AUDIO_CTRL_PD(1); - - /* Dividers */ - CGU_IDIVA_CTRL = CGU_IDIVA_CTRL_PD(1); - CGU_IDIVB_CTRL = CGU_IDIVB_CTRL_PD(1); - CGU_IDIVC_CTRL = CGU_IDIVC_CTRL_PD(1); - CGU_IDIVD_CTRL = CGU_IDIVD_CTRL_PD(1); - CGU_IDIVE_CTRL = CGU_IDIVE_CTRL_PD(1); - - /* Base clocks */ - CGU_BASE_SPIFI_CLK = - CGU_BASE_SPIFI_CLK_PD(1); /* SPIFI is only used at boot */ - CGU_BASE_USB1_CLK = - CGU_BASE_USB1_CLK_PD(1); /* USB1 is not exposed on HackRF */ - CGU_BASE_PHY_RX_CLK = CGU_BASE_PHY_RX_CLK_PD(1); - CGU_BASE_PHY_TX_CLK = CGU_BASE_PHY_TX_CLK_PD(1); - CGU_BASE_LCD_CLK = CGU_BASE_LCD_CLK_PD(1); - CGU_BASE_VADC_CLK = CGU_BASE_VADC_CLK_PD(1); - CGU_BASE_SDIO_CLK = CGU_BASE_SDIO_CLK_PD(1); - CGU_BASE_UART0_CLK = CGU_BASE_UART0_CLK_PD(1); - CGU_BASE_UART1_CLK = CGU_BASE_UART1_CLK_PD(1); - CGU_BASE_UART2_CLK = CGU_BASE_UART2_CLK_PD(1); - CGU_BASE_UART3_CLK = CGU_BASE_UART3_CLK_PD(1); - CGU_BASE_OUT_CLK = CGU_BASE_OUT_CLK_PD(1); - CGU_BASE_AUDIO_CLK = CGU_BASE_AUDIO_CLK_PD(1); - CGU_BASE_CGU_OUT0_CLK = CGU_BASE_CGU_OUT0_CLK_PD(1); - CGU_BASE_CGU_OUT1_CLK = CGU_BASE_CGU_OUT1_CLK_PD(1); - - /* Disable unused peripheral clocks */ - CCU1_CLK_APB1_CAN1_CFG = 0; - CCU1_CLK_APB1_I2S_CFG = 0; - CCU1_CLK_APB1_MOTOCONPWM_CFG = 0; - //CCU1_CLK_APB3_ADC0_CFG = 0; - CCU1_CLK_APB3_ADC1_CFG = 0; - CCU1_CLK_APB3_CAN0_CFG = 0; - CCU1_CLK_APB3_DAC_CFG = 0; - //CCU1_CLK_M4_DMA_CFG = 0; - CCU1_CLK_M4_EMC_CFG = 0; - CCU1_CLK_M4_EMCDIV_CFG = 0; - CCU1_CLK_M4_ETHERNET_CFG = 0; - CCU1_CLK_M4_LCD_CFG = 0; - CCU1_CLK_M4_QEI_CFG = 0; - CCU1_CLK_M4_RITIMER_CFG = 0; - // CCU1_CLK_M4_SCT_CFG = 0; - CCU1_CLK_M4_SDIO_CFG = 0; - CCU1_CLK_M4_SPIFI_CFG = 0; - CCU1_CLK_M4_TIMER0_CFG = 0; - //CCU1_CLK_M4_TIMER1_CFG = 0; - //CCU1_CLK_M4_TIMER2_CFG = 0; - CCU1_CLK_M4_TIMER3_CFG = 0; - CCU1_CLK_M4_UART1_CFG = 0; - CCU1_CLK_M4_USART0_CFG = 0; - CCU1_CLK_M4_USART2_CFG = 0; - CCU1_CLK_M4_USART3_CFG = 0; - CCU1_CLK_M4_USB1_CFG = 0; - CCU1_CLK_M4_VADC_CFG = 0; - // CCU1_CLK_SPIFI_CFG = 0; - // CCU1_CLK_USB1_CFG = 0; - // CCU1_CLK_VADC_CFG = 0; - // CCU2_CLK_APB0_UART1_CFG = 0; - // CCU2_CLK_APB0_USART0_CFG = 0; - // CCU2_CLK_APB2_USART2_CFG = 0; - // CCU2_CLK_APB2_USART3_CFG = 0; - // CCU2_CLK_APLL_CFG = 0; - // CCU2_CLK_SDIO_CFG = 0; - } -#endif -} diff --git a/firmware/common/cpu_clock.h b/firmware/common/cpu_clock.h deleted file mode 100644 index 04929643..00000000 --- a/firmware/common/cpu_clock.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2026 Great Scott Gadgets - * - * This file is part of HackRF. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -void cpu_clock_init(void); - -// Current clock speed in MHz, updated on clock changes. -extern unsigned int cpu_clock_mhz; - -#ifdef __cplusplus -} -#endif diff --git a/firmware/common/crc.h b/firmware/common/crc.h index ee33d7df..787b29a6 100644 --- a/firmware/common/crc.h +++ b/firmware/common/crc.h @@ -20,10 +20,11 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __CRC_H__ +#define __CRC_H__ -#include #include +#include typedef struct { uint32_t remainder; @@ -34,3 +35,5 @@ typedef struct { void crc32_init(crc32_t* const crc); void crc32_update(crc32_t* const crc, const uint8_t* const data, const size_t byte_count); uint32_t crc32_digest(const crc32_t* const crc); + +#endif //__CRC_H__ diff --git a/firmware/common/da7219.c b/firmware/common/da7219.c deleted file mode 100644 index de85d2b8..00000000 --- a/firmware/common/da7219.c +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2026 Great Scott Gadgets - * - * This file is part of HackRF. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#include - -#include "da7219.h" -#include "i2c_bus.h" -#include "i2c_lpc.h" - -#define DA7219_REG_CHIP_ID1 0x81 -#define DA7219_REG_CHIP_ID2 0x82 - -i2c_bus_t* const da7219_bus = &i2c0; - -uint8_t da7219_read_reg(i2c_bus_t* const bus, uint8_t reg) -{ - const uint8_t data_tx[] = {reg}; - uint8_t data_rx[] = {0x00}; - i2c_bus_transfer(bus, DA7219_ADDRESS, data_tx, 1, data_rx, 1); - return data_rx[0]; -} - -bool da7219_detect(void) -{ - uint8_t chip_id1 = da7219_read_reg(da7219_bus, DA7219_REG_CHIP_ID1); - uint8_t chip_id2 = da7219_read_reg(da7219_bus, DA7219_REG_CHIP_ID2); - return (chip_id1 == 0x23) && (chip_id2 == 0x93); -} diff --git a/firmware/common/delay.c b/firmware/common/delay.c deleted file mode 100644 index b74389b2..00000000 --- a/firmware/common/delay.c +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2026 Great Scott Gadgets - * - * This file is part of HackRF. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#include "delay.h" - -#include "cpu_clock.h" - -static void delay_us_at_mhz(uint32_t us, uint32_t mhz) -{ -#if defined(LPC43XX_M4) - // The loop below takes 3 cycles per iteration. - uint32_t loop_iterations = (us * mhz) / 3; - asm volatile("start%=:\n" - " subs %[ITERATIONS], #1\n" // 1 cycle - " bpl start%=\n" // 2 cycles - : - : [ITERATIONS] "r"(loop_iterations)); -#elif defined(LPC43XX_M0) - // The loop below takes 4 cycles per iteration. - uint32_t loop_iterations = (us * mhz) / 4; - asm volatile("start%=:\n" - " sub %[ITERATIONS], #1\n" // 1 cycle - " bpl start%=\n" // 3 cycles - : - : [ITERATIONS] "r"(loop_iterations)); -#else - #error "No delay loop implementation" -#endif -} - -void delay_us(uint32_t us) -{ - delay_us_at_mhz(us, cpu_clock_mhz); -} - -void delay_ms(uint32_t ms) -{ - delay_us_at_mhz(ms * 1000, cpu_clock_mhz); -} diff --git a/firmware/common/delay.h b/firmware/common/delay.h deleted file mode 100644 index eed806bb..00000000 --- a/firmware/common/delay.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2026 Great Scott Gadgets - * - * This file is part of HackRF. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -void delay_us(uint32_t us); -void delay_ms(uint32_t ms); - -#ifdef __cplusplus -} -#endif diff --git a/firmware/common/fault_handler.c b/firmware/common/fault_handler.c index 9d20c71e..413ce8a8 100644 --- a/firmware/common/fault_handler.c +++ b/firmware/common/fault_handler.c @@ -21,10 +21,10 @@ * Boston, MA 02110-1301, USA. */ -#include "fault_handler.h" - #include +#include "fault_handler.h" + typedef struct { uint32_t r0; uint32_t r1; @@ -73,17 +73,17 @@ __attribute__((used)) void hard_fault_handler_c(uint32_t* args) while (1) {} } -void mem_manage_handler(void) +void mem_manage_handler() { while (1) {} } -void bus_fault_handler(void) +void bus_fault_handler() { while (1) {} } -void usage_fault_handler(void) +void usage_fault_handler() { while (1) {} } diff --git a/firmware/common/fault_handler.h b/firmware/common/fault_handler.h index 0b499acb..efccea24 100644 --- a/firmware/common/fault_handler.h +++ b/firmware/common/fault_handler.h @@ -20,7 +20,8 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __FAULT_HANDLER__ +#define __FAULT_HANDLER__ #include @@ -29,7 +30,9 @@ // TODO: Move all this to a Cortex-M(?) include file, since these // structures are supposedly the same between processors (to an // undetermined extent). -typedef struct { +typedef struct armv7m_scb_t armv7m_scb_t; + +struct armv7m_scb_t { volatile const uint32_t CPUID; volatile uint32_t ICSR; volatile uint32_t VTOR; @@ -61,10 +64,12 @@ typedef struct { volatile const uint32_t ID_ISAR4; volatile const uint32_t __reserved_0x74_0x87[5]; volatile uint32_t CPACR; -} __attribute__((packed)) armv7m_scb_t; +} __attribute__((packed)); static armv7m_scb_t* const SCB = (armv7m_scb_t*) SCB_BASE; #define SCB_HFSR_DEBUGEVT (1 << 31) #define SCB_HFSR_FORCED (1 << 30) #define SCB_HFSR_VECTTBL (1 << 1) + +#endif //__FAULT_HANDLER__ diff --git a/firmware/common/firmware_info.c b/firmware/common/firmware_info.c index 527dd19b..2b3d25ff 100644 --- a/firmware/common/firmware_info.c +++ b/firmware/common/firmware_info.c @@ -21,6 +21,11 @@ #include "firmware_info.h" #include "platform_detect.h" +#include "gpio_lpc.h" +#include "hackrf_core.h" + +#include +#include #ifdef JAWBREAKER #define SUPPORTED_PLATFORM PLATFORM_JAWBREAKER @@ -30,9 +35,6 @@ #define SUPPORTED_PLATFORM PLATFORM_RAD1O #elif PRALINE #define SUPPORTED_PLATFORM PLATFORM_PRALINE -#elif UNIVERSAL - #define SUPPORTED_PLATFORM \ - (PLATFORM_PRALINE | PLATFORM_HACKRF1_OG | PLATFORM_HACKRF1_R9) #else #define SUPPORTED_PLATFORM 0 #endif diff --git a/firmware/common/firmware_info.h b/firmware/common/firmware_info.h index a7ae09f6..99706dfb 100644 --- a/firmware/common/firmware_info.h +++ b/firmware/common/firmware_info.h @@ -19,12 +19,13 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef FIRMWARE_INFO_H +#define FIRMWARE_INFO_H #include struct firmware_info_t { - __attribute__((nonstring)) char magic[8]; + char magic[8]; uint16_t struct_version; uint16_t dfu_mode; uint32_t supported_platform; @@ -32,3 +33,5 @@ struct firmware_info_t { } __attribute__((packed, aligned(1))); extern const struct firmware_info_t firmware_info; + +#endif \ No newline at end of file diff --git a/firmware/common/fixed_point.h b/firmware/common/fixed_point.h deleted file mode 100644 index 974e34d2..00000000 --- a/firmware/common/fixed_point.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2026 Great Scott Gadgets - * - * This file is part of HackRF. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#pragma once - -#include - -/* 40.24 fixed-point */ -typedef uint64_t fp_40_24_t; - -/* one million in 40.24 fixed-point */ -#define FP_ONE_MHZ ((1000ULL * 1000ULL) << 24) - -/* one thousand in 40.24 fixed-point */ -#define FP_ONE_KHZ ((1000ULL) << 24) - -/* one in 40.24 fixed-point */ -#define FP_ONE_HZ (1 << 24) - -#define FP_MHZ(mhz) (mhz##ULL * FP_ONE_MHZ) -#define FP_KHZ(khz) (khz##ULL * FP_ONE_KHZ) -#define FP_HZ(hz) (hz##ULL * FP_ONE_HZ) - -/* 28.36 fixed-point */ -typedef uint64_t fp_28_36_t; - -/* one million in 28.36 fixed-point */ -#define SR_FP_ONE_MHZ ((1000ULL * 1000ULL) << 36) - -/* one thousand in 28.36 fixed-point */ -#define SR_FP_ONE_KHZ (1000ULL << 36) - -/* one in 28.36 fixed-point */ -#define SR_FP_ONE_HZ (1ULL << 36) - -#define SR_FP_MHZ(mhz) (mhz##ULL * SR_FP_ONE_MHZ) -#define SR_FP_KHZ(khz) (khz##ULL * SR_FP_ONE_KHZ) -#define SR_FP_HZ(hz) (hz##ULL * SR_FP_ONE_HZ) - -/* 1.63 fixed point */ -typedef uint64_t fp_1_63_t; - -#define FRAC_ONE (1ULL << 63) - -/* one hundredth in 1.63 fixed point */ -#define FRAC_ONE_PERCENT (FRAC_ONE / (100ULL)) - -/* one thousandth in 1.63 fixed point */ -#define FRAC_ONE_PERMILLE (FRAC_ONE / (1000ULL)) - -/* one millionth in 1.63 fixed point */ -#define FRAC_ONE_PPM (FRAC_ONE / (1000000ULL)) - -/* one billionth in 1.63 fixed point */ -#define FRAC_ONE_PPB (FRAC_ONE / (1000000000ULL)) diff --git a/firmware/common/fpga.c b/firmware/common/fpga.c index ec4ff2ec..069d1a09 100644 --- a/firmware/common/fpga.c +++ b/firmware/common/fpga.c @@ -19,24 +19,19 @@ * Boston, MA 02110-1301, USA. */ +#include +#include "hackrf_core.h" +#include "ice40_spi.h" #include "fpga.h" #include "fpga_regs.def" -#include - -#include "ice40_spi.h" - -/* Driver instance. */ -fpga_driver_t fpga = { - .bus = &ice40, -}; - /* Set up all registers according to the loaded bitstream's defaults. */ void fpga_init(fpga_driver_t* const drv) { // Standard bitstream default register values. set_FPGA_STANDARD_CTRL_DC_BLOCK(drv, true); - set_FPGA_STANDARD_RX_PSTEP(drv, 0); + set_FPGA_STANDARD_CTRL_QUARTER_SHIFT_EN(drv, false); + set_FPGA_STANDARD_CTRL_QUARTER_SHIFT_UP(drv, false); set_FPGA_STANDARD_CTRL_PRBS(drv, false); set_FPGA_STANDARD_CTRL_TRIGGER_EN(drv, false); set_FPGA_STANDARD_TX_CTRL(drv, 0); @@ -56,7 +51,9 @@ void fpga_setup(fpga_driver_t* const drv) uint8_t fpga_reg_read(fpga_driver_t* const drv, uint8_t r) { uint8_t v; + ssp1_set_mode_ice40(); v = ice40_spi_read(drv->bus, r); + ssp1_set_mode_max283x(); drv->regs[r] = v; return v; } @@ -64,7 +61,9 @@ uint8_t fpga_reg_read(fpga_driver_t* const drv, uint8_t r) void fpga_reg_write(fpga_driver_t* const drv, uint8_t r, uint8_t v) { drv->regs[r] = v; + ssp1_set_mode_ice40(); ice40_spi_write(drv->bus, r, v); + ssp1_set_mode_max283x(); FPGA_REG_SET_CLEAN(drv, r); } @@ -106,7 +105,8 @@ void fpga_set_rx_quarter_shift_mode( fpga_driver_t* const drv, const fpga_quarter_shift_mode_t mode) { - set_FPGA_STANDARD_RX_PSTEP(drv, (mode & 0b11) << 6); + set_FPGA_STANDARD_CTRL_QUARTER_SHIFT_EN(drv, (mode >> 0) & 0b1); + set_FPGA_STANDARD_CTRL_QUARTER_SHIFT_UP(drv, (mode >> 1) & 0b1); fpga_regs_commit(drv); } diff --git a/firmware/common/fpga.h b/firmware/common/fpga.h index 1765fcdd..fb4270a8 100644 --- a/firmware/common/fpga.h +++ b/firmware/common/fpga.h @@ -19,15 +19,14 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __FPGA_H +#define __FPGA_H #include -#include - #include "ice40_spi.h" -/* Up to 7 registers, each containing up to 8 bits of data */ -#define FPGA_NUM_REGS 7 +/* Up to 6 registers, each containing up to 8 bits of data */ +#define FPGA_NUM_REGS 6 #define FPGA_DATA_REGS_MAX_VALUE 255 typedef enum { @@ -36,23 +35,13 @@ typedef enum { FPGA_QUARTER_SHIFT_MODE_DOWN = 0b01, } fpga_quarter_shift_mode_t; -typedef struct { +struct fpga_driver_t; +typedef struct fpga_driver_t fpga_driver_t; + +struct fpga_driver_t { ice40_spi_driver_t* bus; uint8_t regs[FPGA_NUM_REGS]; uint8_t regs_dirty; -} fpga_driver_t; - -struct fpga_loader_t { - /* Start address added as an offset to all read() calls. */ - uint32_t start_addr; - /* Any one-off setup needed before calling read(). May be NULL. */ - void (*setup)(void); - /* Read data from the specified address. */ - void (*read)(uint32_t addr, uint32_t len, uint8_t* const data); - /* Buffer to use for compressed data (4096 bytes). */ - uint8_t* in_buffer; - /* Buffer to use for decompressed data (4096 bytes). */ - uint8_t* out_buffer; }; /* Initialize the loaded bitstream's registers to their default values. */ @@ -86,10 +75,9 @@ void fpga_set_prbs_enable(fpga_driver_t* const drv, const bool enable); void fpga_set_tx_nco_enable(fpga_driver_t* const drv, const bool enable); void fpga_set_tx_nco_pstep(fpga_driver_t* const drv, const uint8_t phase_increment); -bool fpga_image_load(struct fpga_loader_t* loader, unsigned int index); -bool fpga_spi_selftest(void); -bool fpga_sgpio_selftest(void); -bool fpga_if_xcvr_selftest(void); +bool fpga_image_load(unsigned int index); +bool fpga_spi_selftest(); +bool fpga_sgpio_selftest(); +bool fpga_if_xcvr_selftest(); -/* Driver instance. */ -extern fpga_driver_t fpga; +#endif // __FPGA_H diff --git a/firmware/common/fpga_image.c b/firmware/common/fpga_image.c index 6b440337..ddac8595 100644 --- a/firmware/common/fpga_image.c +++ b/firmware/common/fpga_image.c @@ -19,35 +19,32 @@ * Boston, MA 02110-1301, USA. */ -#include -#include -#include - -#include "fpga.h" -#include "ice40_spi.h" +#include "hackrf_core.h" #include "lz4_blk.h" #include "selftest.h" +// FPGA bitstreams blob. +extern uint32_t _binary_fpga_bin_start; +extern uint32_t _binary_fpga_bin_end; +extern uint32_t _binary_fpga_bin_size; + struct fpga_image_read_ctx { - struct fpga_loader_t* loader; uint32_t addr; size_t next_block_sz; uint8_t init_flag; + uint8_t buffer[4096 + 2]; }; -static size_t fpga_image_read_block_cb(void* _ctx) +static size_t fpga_image_read_block_cb(void* _ctx, uint8_t* out_buffer) { // Assume out_buffer is 4KB struct fpga_image_read_ctx* ctx = _ctx; - struct fpga_loader_t* loader = ctx->loader; size_t block_sz = ctx->next_block_sz; - uint8_t block_sz_buf[2]; - // first iteration: read first block size if (ctx->init_flag == 0) { - loader->read(ctx->addr, 2, block_sz_buf); - block_sz = block_sz_buf[0] | block_sz_buf[1] << 8; + w25q80bv_read(&spi_flash, ctx->addr, 2, ctx->buffer); + block_sz = ctx->buffer[0] | (ctx->buffer[1] << 8); ctx->addr += 2; ctx->init_flag = 1; } @@ -57,43 +54,49 @@ static size_t fpga_image_read_block_cb(void* _ctx) return 0; // Read compressed block (and the next block size) from flash. - loader->read(ctx->addr, block_sz, loader->in_buffer); - ctx->addr += block_sz; - loader->read(ctx->addr, 2, block_sz_buf); - ctx->next_block_sz = block_sz_buf[0] | block_sz_buf[1] << 8; - ctx->addr += 2; + w25q80bv_read(&spi_flash, ctx->addr, block_sz + 2, ctx->buffer); + ctx->addr += block_sz + 2; + ctx->next_block_sz = ctx->buffer[block_sz] | (ctx->buffer[block_sz + 1] << 8); // Decompress block. - return lz4_blk_decompress(loader->in_buffer, loader->out_buffer, block_sz); + return lz4_blk_decompress(ctx->buffer, out_buffer, block_sz); } -bool fpga_image_load(struct fpga_loader_t* loader, unsigned int index) +bool fpga_image_load(unsigned int index) { +#if defined(DFU_MODE) || defined(RAM_MODE) + selftest.fpga_image_load = SKIPPED; + selftest.report.pass = false; + return false; +#endif + // TODO: do SPI setup and read number of bitstreams once! - if (loader->setup != NULL) - loader->setup(); + + // Prepare for SPI flash access. + spi_bus_start(spi_flash.bus, &ssp_config_w25q80bv); + w25q80bv_setup(&spi_flash); // Read number of bitstreams from flash. // Check the bitstream exists, and extract its offset. - uint32_t addr = loader->start_addr; + uint32_t addr = (uint32_t) &_binary_fpga_bin_start; uint32_t num_bitstreams, bitstream_offset; - loader->read(addr, 4, (uint8_t*) &num_bitstreams); + w25q80bv_read(&spi_flash, addr, 4, (uint8_t*) &num_bitstreams); if (index >= num_bitstreams) return false; - loader->read(addr + 4 * (index + 1), 4, (uint8_t*) &bitstream_offset); + w25q80bv_read(&spi_flash, addr + 4 * (index + 1), 4, (uint8_t*) &bitstream_offset); // A callback function is used by the FPGA programmer // to obtain consecutive gateware chunks. ice40_spi_target_init(&ice40); + ssp1_set_mode_ice40(); struct fpga_image_read_ctx fpga_image_ctx = { - .loader = loader, - .addr = loader->start_addr + bitstream_offset, + .addr = (uint32_t) &_binary_fpga_bin_start + bitstream_offset, }; const bool success = ice40_spi_syscfg_program( &ice40, - loader->out_buffer, fpga_image_read_block_cb, &fpga_image_ctx); + ssp1_set_mode_max283x(); // Update selftest result. selftest.fpga_image_load = success ? PASSED : FAILED; diff --git a/firmware/common/fpga_regs.def b/firmware/common/fpga_regs.def index 0a8ce828..c575c493 100644 --- a/firmware/common/fpga_regs.def +++ b/firmware/common/fpga_regs.def @@ -1,7 +1,7 @@ /* -*- mode: c -*- * * Copyright 2012 Michael Ossmann - * Copyright 2025-2026 Great Scott Gadgets + * Copyright 2025 Great Scott Gadgets * * This file is part of HackRF. * @@ -21,7 +21,8 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __FPGA_REGS_DEF +#define __FPGA_REGS_DEF #define FPGA_REG_SET_CLEAN(_d, _r) (_d->regs_dirty &= ~(1UL<<_r)) #define FPGA_REG_SET_DIRTY(_d, _r) (_d->regs_dirty |= (1UL<<_r)) @@ -52,21 +53,22 @@ const uint8_t n = r; /* REG 01 (1): CTRL */ __MREG__(FPGA_STANDARD_CTRL, 1, 0, 8) __MREG__(FPGA_STANDARD_CTRL_DC_BLOCK, 1, 0, 1) +__MREG__(FPGA_STANDARD_CTRL_QUARTER_SHIFT_EN, 1, 1, 1) +__MREG__(FPGA_STANDARD_CTRL_QUARTER_SHIFT_UP, 1, 2, 1) __MREG__(FPGA_STANDARD_CTRL_PRBS, 1, 6, 1) __MREG__(FPGA_STANDARD_CTRL_TRIGGER_EN, 1, 7, 1) /* REG 02 (2): RX_DECIM */ __MREG__(FPGA_STANDARD_RX_DECIM, 2, 0, 3) -/* REG 03 (3): RX_PSTEP */ -__MREG__(FPGA_STANDARD_RX_PSTEP, 3, 0, 8) +/* REG 03 (3): TX_CTRL */ +__MREG__(FPGA_STANDARD_TX_CTRL, 3, 0, 1) +__MREG__(FPGA_STANDARD_TX_CTRL_NCO_EN, 3, 0, 1) -/* REG 04 (4): TX_CTRL */ -__MREG__(FPGA_STANDARD_TX_CTRL, 4, 0, 1) -__MREG__(FPGA_STANDARD_TX_CTRL_NCO_EN, 4, 0, 1) +/* REG 04 (4): TX_INTRP */ +__MREG__(FPGA_STANDARD_TX_INTRP, 4, 0, 3) -/* REG 05 (5): TX_INTRP */ -__MREG__(FPGA_STANDARD_TX_INTRP, 5, 0, 3) +/* REG 05 (5): TX_PSTEP */ +__MREG__(FPGA_STANDARD_TX_PSTEP, 5, 0, 8) -/* REG 06 (6): TX_PSTEP */ -__MREG__(FPGA_STANDARD_TX_PSTEP, 6, 0, 8) +#endif // __FPGA_REGS_DEF diff --git a/firmware/common/fpga_selftest.c b/firmware/common/fpga_selftest.c index 58fc7bb4..287c6adc 100644 --- a/firmware/common/fpga_selftest.c +++ b/firmware/common/fpga_selftest.c @@ -1,5 +1,5 @@ /* - * Copyright 2025-2026 Great Scott Gadgets + * Copyright 2025 Great Scott Gadgets * * This file is part of HackRF. * @@ -19,25 +19,15 @@ * Boston, MA 02110-1301, USA. */ -#include -#include -#include - -#include "clock_gen.h" -#include "delay.h" -#include "fixed_point.h" -#include "fpga.h" -#include "ice40_spi.h" +#include "hackrf_core.h" #include "m0_state.h" -#include "max283x.h" -#include "rf_path.h" -#include "selftest.h" -#include "sgpio.h" #include "streaming.h" +#include "selftest.h" +#include "fpga.h" // USB buffer used during selftests. -#define USB_SAMP_BUFFER_SIZE 0x8000 -extern uint8_t usb_samp_buffer[USB_SAMP_BUFFER_SIZE]; +#define USB_BULK_BUFFER_SIZE 0x8000 +extern uint8_t usb_bulk_buffer[USB_BULK_BUFFER_SIZE]; static int rx_samples(const unsigned int num_samples, uint32_t max_cycles) { @@ -60,7 +50,7 @@ static int rx_samples(const unsigned int num_samples, uint32_t max_cycles) return rc; } -bool fpga_spi_selftest(void) +bool fpga_spi_selftest() { // Skip if FPGA configuration failed. if (selftest.fpga_image_load != PASSED) { @@ -69,10 +59,12 @@ bool fpga_spi_selftest(void) } // Test writing a register and reading it back. - uint8_t reg = 6; + uint8_t reg = 5; uint8_t write_value = 0xA5; + ssp1_set_mode_ice40(); ice40_spi_write(&ice40, reg, write_value); uint8_t read_value = ice40_spi_read(&ice40, reg); + ssp1_set_mode_max283x(); // Update selftest result. selftest.fpga_spi = (read_value == write_value) ? PASSED : FAILED; @@ -89,7 +81,7 @@ static uint8_t lfsr_advance(uint8_t v) return (v << 1) | feedback; } -bool fpga_sgpio_selftest(void) +bool fpga_sgpio_selftest() { bool timeout = false; @@ -112,10 +104,10 @@ bool fpga_sgpio_selftest(void) fpga_set_prbs_enable(&fpga, false); // Generate sequence from first value and compare. - bool seq_in_sync = (usb_samp_buffer[0] != 0); - uint8_t seq = lfsr_advance(usb_samp_buffer[0]); + bool seq_in_sync = (usb_bulk_buffer[0] != 0); + uint8_t seq = lfsr_advance(usb_bulk_buffer[0]); for (int i = 1; i < 512; ++i) { - if (usb_samp_buffer[i] != seq) { + if (usb_bulk_buffer[i] != seq) { seq_in_sync = false; break; } @@ -176,7 +168,7 @@ static bool in_range(int value, int expected, int error) return (value > min) && (value < max); } -bool fpga_if_xcvr_selftest(void) +bool fpga_if_xcvr_selftest() { bool timeout = false; @@ -186,64 +178,64 @@ bool fpga_if_xcvr_selftest(void) return false; } - const size_t num_samples = USB_SAMP_BUFFER_SIZE / 2; + const size_t num_samples = USB_BULK_BUFFER_SIZE / 2; // Set common RX path and gateware settings for the measurements. fpga_set_tx_nco_pstep(&fpga, 64); // NCO phase increment fpga_set_tx_nco_enable(&fpga, true); // TX enable rf_path_set_direction(&rf_path, RF_PATH_DIRECTION_RX_CALIBRATION); - max283x_set_lna_gain(&max283x, 16); - max283x_set_vga_gain(&max283x, 36); - max283x_set_frequency(&max283x, FP_MHZ(2500), true); + max2831_set_lna_gain(&max283x, 16); + max2831_set_vga_gain(&max283x, 36); + max2831_set_frequency(&max283x, 2500000000); // Capture 1: 4 Msps, tone at 0.5 MHz, narrowband filter OFF - sample_rate_set(SR_FP_MHZ(4), true); - delay_ms(1); + sample_rate_frac_set(4000000 * 2, 1); + delay_us_at_mhz(1000, 204); if (rx_samples(num_samples, 2000000) == -1) { timeout = true; } measure_tone( - (int8_t*) usb_samp_buffer, + (int8_t*) usb_bulk_buffer, num_samples, &selftest.xcvr_measurements[0]); // Capture 2: 4 Msps, tone at 0.5 MHz, narrowband filter ON narrowband_filter_set(1); - delay_ms(1); + delay_us_at_mhz(1000, 204); if (rx_samples(num_samples, 2000000) == -1) { timeout = true; } measure_tone( - (int8_t*) usb_samp_buffer, + (int8_t*) usb_bulk_buffer, num_samples, &selftest.xcvr_measurements[1]); // Capture 3: 20 Msps, tone at 5 MHz, narrowband filter OFF fpga_set_tx_nco_pstep(&fpga, 255); - sample_rate_set(SR_FP_MHZ(20), true); + sample_rate_frac_set(20000000 * 2, 1); narrowband_filter_set(0); - delay_ms(1); + delay_us_at_mhz(1000, 204); if (rx_samples(num_samples, 2000000) == -1) { timeout = true; } measure_tone( - (int8_t*) usb_samp_buffer, + (int8_t*) usb_bulk_buffer, num_samples, &selftest.xcvr_measurements[2]); // Capture 4: 20 Msps, tone at 5 MHz, narrowband filter ON narrowband_filter_set(1); - delay_ms(1); + delay_us_at_mhz(1000, 204); if (rx_samples(num_samples, 2000000) == -1) { timeout = true; } measure_tone( - (int8_t*) usb_samp_buffer, + (int8_t*) usb_bulk_buffer, num_samples, &selftest.xcvr_measurements[3]); // Restore default settings. - sample_rate_set(SR_FP_MHZ(10), true); + sample_rate_set(10000000); rf_path_set_direction(&rf_path, RF_PATH_DIRECTION_OFF); narrowband_filter_set(0); fpga_init(&fpga); diff --git a/firmware/common/gpdma.c b/firmware/common/gpdma.c index 3dc61452..ac51f432 100644 --- a/firmware/common/gpdma.c +++ b/firmware/common/gpdma.c @@ -20,11 +20,11 @@ * Boston, MA 02110-1301, USA. */ -#include "gpdma.h" +#include #include -void gpdma_controller_enable(void) +void gpdma_controller_enable() { GPDMA_CONFIG |= GPDMA_CONFIG_E(1); while ((GPDMA_CONFIG & GPDMA_CONFIG_E_MASK) == 0) {} diff --git a/firmware/common/gpdma.h b/firmware/common/gpdma.h index dc469da9..e14b0c41 100644 --- a/firmware/common/gpdma.h +++ b/firmware/common/gpdma.h @@ -20,14 +20,15 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __GPDMA_H__ +#define __GPDMA_H__ #include #include #include -void gpdma_controller_enable(void); +void gpdma_controller_enable(); void gpdma_channel_enable(const uint_fast8_t channel); void gpdma_channel_disable(const uint_fast8_t channel); @@ -39,3 +40,5 @@ void gpdma_lli_enable_interrupt(gpdma_lli_t* const lli); void gpdma_lli_create_loop(gpdma_lli_t* const lli, const size_t lli_count); void gpdma_lli_create_oneshot(gpdma_lli_t* const lli, const size_t lli_count); + +#endif /*__GPDMA_H__*/ diff --git a/firmware/common/gpio.h b/firmware/common/gpio.h index 749fa021..868fc628 100644 --- a/firmware/common/gpio.h +++ b/firmware/common/gpio.h @@ -20,13 +20,14 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __GPIO_H__ +#define __GPIO_H__ #include -typedef const struct gpio* gpio_t; +typedef const struct gpio_t* gpio_t; -void gpio_init(void); +void gpio_init(); void gpio_set(gpio_t gpio); void gpio_clear(gpio_t gpio); void gpio_toggle(gpio_t gpio); @@ -34,3 +35,5 @@ void gpio_output(gpio_t gpio); void gpio_input(gpio_t gpio); void gpio_write(gpio_t gpio, const bool value); bool gpio_read(gpio_t gpio); + +#endif /*__GPIO_H__*/ diff --git a/firmware/common/gpio_lpc.c b/firmware/common/gpio_lpc.c index 16a436cc..d05b7fa8 100644 --- a/firmware/common/gpio_lpc.c +++ b/firmware/common/gpio_lpc.c @@ -22,12 +22,9 @@ #include "gpio_lpc.h" -#include #include -#include "gpio.h" - -void gpio_init(void) +void gpio_init() { for (size_t i = 0; i < 8; i++) { GPIO_LPC_PORT(i)->dir = 0; @@ -46,7 +43,7 @@ void gpio_clear(gpio_t gpio) void gpio_toggle(gpio_t gpio) { - gpio->port->inv = gpio->mask; + gpio->port->not = gpio->mask; } void gpio_output(gpio_t gpio) diff --git a/firmware/common/gpio_lpc.h b/firmware/common/gpio_lpc.h index 0987537f..f51ffd2b 100644 --- a/firmware/common/gpio_lpc.h +++ b/firmware/common/gpio_lpc.h @@ -20,16 +20,19 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __GPIO_LPC_H__ +#define __GPIO_LPC_H__ #include +#include "gpio.h" + /* NOTE: libopencm3 constants and functions not used here due to naming * conflicts. I'd recommend changes to libopencm3 design to separate * register #defines and API declarations into separate header files. */ -typedef struct { +typedef struct gpio_port_t { volatile uint32_t dir; /* +0x000 */ uint32_t _reserved0[31]; volatile uint32_t mask; /* +0x080 */ @@ -42,10 +45,10 @@ typedef struct { uint32_t _reserved4[31]; volatile uint32_t clr; /* +0x280 */ uint32_t _reserved5[31]; - volatile uint32_t inv; /* +0x300 */ + volatile uint32_t not ; /* +0x300 */ } gpio_port_t; -struct gpio { +struct gpio_t { const uint32_t mask; gpio_port_t* const port; volatile uint32_t* const gpio_w; @@ -68,3 +71,5 @@ struct gpio { .gpio_w = GPIO_LPC_W(_port_num, _pin_num), \ } // clang-format on + +#endif /*__GPIO_LPC_H__*/ diff --git a/firmware/common/hackrf_core.c b/firmware/common/hackrf_core.c new file mode 100644 index 00000000..5d59da00 --- /dev/null +++ b/firmware/common/hackrf_core.c @@ -0,0 +1,1418 @@ +/* + * Copyright 2012-2022 Great Scott Gadgets + * Copyright 2012 Jared Boone + * Copyright 2013 Benjamin Vernoux + * + * This file is part of HackRF. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "hackrf_core.h" +#include "hackrf_ui.h" +#include "sgpio.h" +#include "si5351c.h" +#include "spi_ssp.h" +#include "max2831.h" +#include "max2831_target.h" +#include "max283x.h" +#include "max5864.h" +#include "max5864_target.h" +#include "w25q80bv.h" +#include "w25q80bv_target.h" +#include "i2c_bus.h" +#include "i2c_lpc.h" +#include "cpld_jtag.h" +#include "ice40_spi.h" +#include "platform_detect.h" +#include "clkin.h" +#include +#include +#include +#include + +#if (defined HACKRF_ONE || defined PRALINE) + #include "portapack.h" +#endif + +#include "gpio_lpc.h" + +/* GPIO Output PinMux */ +static struct gpio_t gpio_led[] = { + GPIO(2, 1), + GPIO(2, 2), + GPIO(2, 8), +#ifdef RAD1O + GPIO(5, 26), +#endif +#ifdef PRALINE + GPIO(4, 6), +#endif +}; + +// clang-format off +#ifndef PRALINE +static struct gpio_t gpio_1v8_enable = GPIO(3, 6); +#else +static struct gpio_t gpio_1v2_enable = GPIO(4, 7); +static struct gpio_t gpio_3v3aux_enable_n = GPIO(5, 15); +#endif + +/* MAX283x GPIO (XCVR_CTL / CS_XCVR) PinMux */ +#ifdef PRALINE +static struct gpio_t gpio_max283x_select = GPIO(6, 28); +#else +static struct gpio_t gpio_max283x_select = GPIO(0, 15); +#endif + +/* MAX5864 SPI chip select (AD_CS / CS_AD) GPIO PinMux */ +#ifdef PRALINE +static struct gpio_t gpio_max5864_select = GPIO(6, 30); +#else +static struct gpio_t gpio_max5864_select = GPIO(2, 7); +#endif + +/* RFFC5071 GPIO serial interface PinMux */ +// #ifdef RAD1O +// static struct gpio_t gpio_rffc5072_select = GPIO(2, 13); +// static struct gpio_t gpio_rffc5072_clock = GPIO(5, 6); +// static struct gpio_t gpio_rffc5072_data = GPIO(3, 3); +// static struct gpio_t gpio_rffc5072_reset = GPIO(2, 14); +// #endif + +/* RF supply (VAA) control */ +#ifdef HACKRF_ONE +static struct gpio_t gpio_vaa_disable = GPIO(2, 9); +#endif +#ifdef PRALINE +static struct gpio_t gpio_vaa_disable = GPIO(4, 1); +#endif +#ifdef RAD1O +static struct gpio_t gpio_vaa_enable = GPIO(2, 9); +#endif + +static struct gpio_t gpio_w25q80bv_hold = GPIO(1, 14); +static struct gpio_t gpio_w25q80bv_wp = GPIO(1, 15); +static struct gpio_t gpio_w25q80bv_select = GPIO(5, 11); + +/* RF switch control */ +#ifdef HACKRF_ONE +static struct gpio_t gpio_hp = GPIO(2, 0); +static struct gpio_t gpio_lp = GPIO(2, 10); +static struct gpio_t gpio_tx_mix_bp = GPIO(2, 11); +static struct gpio_t gpio_no_mix_bypass = GPIO(1, 0); +static struct gpio_t gpio_rx_mix_bp = GPIO(2, 12); +static struct gpio_t gpio_tx_amp = GPIO(2, 15); +static struct gpio_t gpio_tx = GPIO(5, 15); +static struct gpio_t gpio_mix_bypass = GPIO(5, 16); +static struct gpio_t gpio_rx = GPIO(5, 5); +static struct gpio_t gpio_no_tx_amp_pwr = GPIO(3, 5); +static struct gpio_t gpio_amp_bypass = GPIO(0, 14); +static struct gpio_t gpio_rx_amp = GPIO(1, 11); +static struct gpio_t gpio_no_rx_amp_pwr = GPIO(1, 12); +#endif +#ifdef RAD1O +static struct gpio_t gpio_tx_rx_n = GPIO(1, 11); +static struct gpio_t gpio_tx_rx = GPIO(0, 14); +static struct gpio_t gpio_by_mix = GPIO(1, 12); +static struct gpio_t gpio_by_mix_n = GPIO(2, 10); +static struct gpio_t gpio_by_amp = GPIO(1, 0); +static struct gpio_t gpio_by_amp_n = GPIO(5, 5); +static struct gpio_t gpio_mixer_en = GPIO(5, 16); +static struct gpio_t gpio_low_high_filt = GPIO(2, 11); +static struct gpio_t gpio_low_high_filt_n = GPIO(2, 12); +static struct gpio_t gpio_tx_amp = GPIO(2, 15); +static struct gpio_t gpio_rx_lna = GPIO(5, 15); +#endif +#ifdef PRALINE +static struct gpio_t gpio_tx_en = GPIO(3, 4); +static struct gpio_t gpio_mix_en_n = GPIO(3, 2); +static struct gpio_t gpio_mix_en_n_r1_0 = GPIO(5, 6); +static struct gpio_t gpio_lpf_en = GPIO(4, 8); +static struct gpio_t gpio_rf_amp_en = GPIO(4, 9); +static struct gpio_t gpio_ant_bias_en_n = GPIO(1, 12); +#endif + +/* CPLD JTAG interface GPIO pins, FPGA config pins in Praline */ +static struct gpio_t gpio_cpld_tck = GPIO(3, 0); +#ifdef PRALINE +static struct gpio_t gpio_fpga_cfg_creset = GPIO(2, 11); +static struct gpio_t gpio_fpga_cfg_cdone = GPIO(5, 14); +static struct gpio_t gpio_fpga_cfg_spi_cs = GPIO(2, 10); +#else +static struct gpio_t gpio_cpld_tdo = GPIO(5, 18); +#if (defined HACKRF_ONE || defined RAD1O) +static struct gpio_t gpio_cpld_tms = GPIO(3, 4); +static struct gpio_t gpio_cpld_tdi = GPIO(3, 1); +#else +static struct gpio_t gpio_cpld_tms = GPIO(3, 1); +static struct gpio_t gpio_cpld_tdi = GPIO(3, 4); +#endif +#endif + +#if (defined HACKRF_ONE || defined PRALINE) +static struct gpio_t gpio_cpld_pp_tms = GPIO(1, 1); +static struct gpio_t gpio_cpld_pp_tdo = GPIO(1, 8); +#endif + +/* other CPLD interface GPIO pins */ +#ifndef PRALINE +static struct gpio_t gpio_trigger_enable = GPIO(5, 12); +#endif +static struct gpio_t gpio_q_invert = GPIO(0, 13); + +/* HackRF One r9 */ +#ifdef HACKRF_ONE +static struct gpio_t gpio_h1r9_rx = GPIO(0, 7); +static struct gpio_t gpio_h1r9_1v8_enable = GPIO(2, 9); +static struct gpio_t gpio_h1r9_vaa_disable = GPIO(3, 6); +static struct gpio_t gpio_h1r9_trigger_enable = GPIO(5, 5); +#endif + +#ifdef PRALINE +static struct gpio_t gpio_p2_ctrl0 = GPIO(7, 3); +static struct gpio_t gpio_p2_ctrl1 = GPIO(7, 4); +static struct gpio_t gpio_p1_ctrl0 = GPIO(0, 14); +static struct gpio_t gpio_p1_ctrl1 = GPIO(5, 16); +static struct gpio_t gpio_p1_ctrl2 = GPIO(3, 5); +static struct gpio_t gpio_clkin_ctrl = GPIO(0, 15); +static struct gpio_t gpio_aa_en = GPIO(1, 7); +static struct gpio_t gpio_trigger_in = GPIO(6, 26); +static struct gpio_t gpio_trigger_out = GPIO(5, 6); +static struct gpio_t gpio_pps_out = GPIO(5, 5); +#endif +// clang-format on + +i2c_bus_t i2c0 = { + .obj = (void*) I2C0_BASE, + .start = i2c_lpc_start, + .stop = i2c_lpc_stop, + .transfer = i2c_lpc_transfer, +}; + +i2c_bus_t i2c1 = { + .obj = (void*) I2C1_BASE, + .start = i2c_lpc_start, + .stop = i2c_lpc_stop, + .transfer = i2c_lpc_transfer, +}; + +// const i2c_lpc_config_t i2c_config_si5351c_slow_clock = { +// .duty_cycle_count = 15, +// }; + +const i2c_lpc_config_t i2c_config_si5351c_fast_clock = { + .duty_cycle_count = 255, +}; + +si5351c_driver_t clock_gen = { + .bus = &i2c0, + .i2c_address = 0x60, +}; + +spi_bus_t spi_bus_ssp1 = { + .obj = (void*) SSP1_BASE, + .config = &ssp_config_max5864, + .start = spi_ssp_start, + .stop = spi_ssp_stop, + .transfer = spi_ssp_transfer, + .transfer_gather = spi_ssp_transfer_gather, +}; + +#ifdef PRALINE +const ssp_config_t ssp_config_max283x = { + /* FIXME speed up once everything is working reliably */ + /* + // Freq About 0.0498MHz / 49.8KHz => Freq = PCLK / (CPSDVSR * [SCR+1]) with PCLK=PLL1=204MHz + const uint8_t serial_clock_rate = 32; + const uint8_t clock_prescale_rate = 128; + */ + // Freq About 4.857MHz => Freq = PCLK / (CPSDVSR * [SCR+1]) with PCLK=PLL1=204MHz + .data_bits = SSP_DATA_9BITS, // send 2 words + .serial_clock_rate = 21, + .clock_prescale_rate = 2, + .gpio_select = &gpio_max283x_select, +}; + +static struct gpio_t gpio_max2831_enable = GPIO(7, 1); +static struct gpio_t gpio_max2831_rx_enable = GPIO(7, 2); +static struct gpio_t gpio_max2831_rxhp = GPIO(6, 29); +static struct gpio_t gpio_max2831_ld = GPIO(4, 11); + +max2831_driver_t max283x = { + .bus = &spi_bus_ssp1, + .gpio_enable = &gpio_max2831_enable, + .gpio_rxtx = &gpio_max2831_rx_enable, + .gpio_rxhp = &gpio_max2831_rxhp, + .gpio_ld = &gpio_max2831_ld, + .target_init = max2831_target_init, + .set_mode = max2831_target_set_mode, +}; +#else +const ssp_config_t ssp_config_max283x = { + /* FIXME speed up once everything is working reliably */ + /* + // Freq About 0.0498MHz / 49.8KHz => Freq = PCLK / (CPSDVSR * [SCR+1]) with PCLK=PLL1=204MHz + const uint8_t serial_clock_rate = 32; + const uint8_t clock_prescale_rate = 128; + */ + // Freq About 4.857MHz => Freq = PCLK / (CPSDVSR * [SCR+1]) with PCLK=PLL1=204MHz + .data_bits = SSP_DATA_16BITS, + .serial_clock_rate = 21, + .clock_prescale_rate = 2, + .gpio_select = &gpio_max283x_select, +}; + +max283x_driver_t max283x = {}; +#endif + +const ssp_config_t ssp_config_max5864 = { + /* FIXME speed up once everything is working reliably */ + /* + // Freq About 0.0498MHz / 49.8KHz => Freq = PCLK / (CPSDVSR * [SCR+1]) with PCLK=PLL1=204MHz + const uint8_t serial_clock_rate = 32; + const uint8_t clock_prescale_rate = 128; + */ + // Freq About 4.857MHz => Freq = PCLK / (CPSDVSR * [SCR+1]) with PCLK=PLL1=204MHz + .data_bits = SSP_DATA_8BITS, + .serial_clock_rate = 21, + .clock_prescale_rate = 2, + .gpio_select = &gpio_max5864_select, +}; + +max5864_driver_t max5864 = { + .bus = &spi_bus_ssp1, + .target_init = max5864_target_init, +}; + +const ssp_config_t ssp_config_w25q80bv = { + .data_bits = SSP_DATA_8BITS, + .serial_clock_rate = 2, + .clock_prescale_rate = 2, + .gpio_select = &gpio_w25q80bv_select, +}; + +spi_bus_t spi_bus_ssp0 = { + .obj = (void*) SSP0_BASE, + .config = &ssp_config_w25q80bv, + .start = spi_ssp_start, + .stop = spi_ssp_stop, + .transfer = spi_ssp_transfer, + .transfer_gather = spi_ssp_transfer_gather, +}; + +w25q80bv_driver_t spi_flash = { + .bus = &spi_bus_ssp0, + .gpio_hold = &gpio_w25q80bv_hold, + .gpio_wp = &gpio_w25q80bv_wp, + .target_init = w25q80bv_target_init, +}; + +sgpio_config_t sgpio_config = { + .gpio_q_invert = &gpio_q_invert, +#ifndef PRALINE + .gpio_trigger_enable = &gpio_trigger_enable, +#endif + .slice_mode_multislice = true, +}; + +#ifdef PRALINE +const ssp_config_t ssp_config_ice40_fpga = { + .data_bits = SSP_DATA_8BITS, + .spi_mode = SSP_CPOL_1_CPHA_1, + .serial_clock_rate = 21, + .clock_prescale_rate = 2, + .gpio_select = &gpio_fpga_cfg_spi_cs, +}; + +ice40_spi_driver_t ice40 = { + .bus = &spi_bus_ssp1, + .gpio_select = &gpio_fpga_cfg_spi_cs, + .gpio_creset = &gpio_fpga_cfg_creset, + .gpio_cdone = &gpio_fpga_cfg_cdone, +}; + +fpga_driver_t fpga = { + .bus = &ice40, +}; +#endif + +radio_t radio = { + .channel[RADIO_CHANNEL0] = + { + .id = RADIO_CHANNEL0, + .config = + { + .sample_rate[RADIO_SAMPLE_RATE_CLOCKGEN] = + {.hz = 0}, + .filter[RADIO_FILTER_BASEBAND] = {.hz = 0}, + .frequency[RADIO_FREQUENCY_RF] = + { + .hz = 0, + .if_hz = 0, + .lo_hz = 0, + .path = 0, + }, + .gain[RADIO_GAIN_RF_AMP] = {.enable = 0}, + .gain[RADIO_GAIN_RX_LNA] = {.db = 0}, + .gain[RADIO_GAIN_RX_VGA] = {.db = 0}, + .gain[RADIO_GAIN_TX_VGA] = {.db = 0}, + .antenna[RADIO_ANTENNA_BIAS_TEE] = + {.enable = false}, + .mode = TRANSCEIVER_MODE_OFF, + .clock[RADIO_CLOCK_CLKIN] = {.enable = false}, + .clock[RADIO_CLOCK_CLKOUT] = {.enable = false}, + .trigger_enable = false, +#ifdef PRALINE + .resampling_n = 0, + .shift = FPGA_QUARTER_SHIFT_MODE_NONE, +#endif + }, + .clock_source = CLOCK_SOURCE_HACKRF, + }, +}; + +rf_path_t rf_path = { + .switchctrl = 0, +#ifdef HACKRF_ONE + .gpio_hp = &gpio_hp, + .gpio_lp = &gpio_lp, + .gpio_tx_mix_bp = &gpio_tx_mix_bp, + .gpio_no_mix_bypass = &gpio_no_mix_bypass, + .gpio_rx_mix_bp = &gpio_rx_mix_bp, + .gpio_tx_amp = &gpio_tx_amp, + .gpio_tx = &gpio_tx, + .gpio_mix_bypass = &gpio_mix_bypass, + .gpio_rx = &gpio_rx, + .gpio_no_tx_amp_pwr = &gpio_no_tx_amp_pwr, + .gpio_amp_bypass = &gpio_amp_bypass, + .gpio_rx_amp = &gpio_rx_amp, + .gpio_no_rx_amp_pwr = &gpio_no_rx_amp_pwr, +#endif +#ifdef RAD1O + .gpio_tx_rx_n = &gpio_tx_rx_n, + .gpio_tx_rx = &gpio_tx_rx, + .gpio_by_mix = &gpio_by_mix, + .gpio_by_mix_n = &gpio_by_mix_n, + .gpio_by_amp = &gpio_by_amp, + .gpio_by_amp_n = &gpio_by_amp_n, + .gpio_mixer_en = &gpio_mixer_en, + .gpio_low_high_filt = &gpio_low_high_filt, + .gpio_low_high_filt_n = &gpio_low_high_filt_n, + .gpio_tx_amp = &gpio_tx_amp, + .gpio_rx_lna = &gpio_rx_lna, +#endif +#ifdef PRALINE + .gpio_tx_en = &gpio_tx_en, + .gpio_mix_en_n = &gpio_mix_en_n, + .gpio_lpf_en = &gpio_lpf_en, + .gpio_rf_amp_en = &gpio_rf_amp_en, + .gpio_ant_bias_en_n = &gpio_ant_bias_en_n, +#endif +}; + +jtag_gpio_t jtag_gpio_cpld = { + .gpio_tck = &gpio_cpld_tck, +#ifndef PRALINE + .gpio_tms = &gpio_cpld_tms, + .gpio_tdi = &gpio_cpld_tdi, + .gpio_tdo = &gpio_cpld_tdo, +#endif +#if (defined HACKRF_ONE || defined PRALINE) + .gpio_pp_tms = &gpio_cpld_pp_tms, + .gpio_pp_tdo = &gpio_cpld_pp_tdo, +#endif +}; + +jtag_t jtag_cpld = { + .gpio = &jtag_gpio_cpld, +}; + +void delay(uint32_t duration) +{ + uint32_t i; + + for (i = 0; i < duration; i++) { + __asm__("nop"); + } +} + +void delay_us_at_mhz(uint32_t us, uint32_t mhz) +{ + // The loop below takes 3 cycles per iteration. + uint32_t loop_iterations = (us * mhz) / 3; + asm volatile("start%=:\n" + " subs %[ITERATIONS], #1\n" // 1 cycle + " bpl start%=\n" // 2 cycles + : + : [ITERATIONS] "r"(loop_iterations)); +} + +/* GCD algo from wikipedia */ +/* http://en.wikipedia.org/wiki/Greatest_common_divisor */ +static uint32_t gcd(uint32_t u, uint32_t v) +{ + int s; + + if (!u || !v) { + return u | v; + } + + for (s = 0; !((u | v) & 1); s++) { + u >>= 1; + v >>= 1; + } + + while (!(u & 1)) { + u >>= 1; + } + + do { + while (!(v & 1)) { + v >>= 1; + } + + if (u > v) { + uint32_t t; + t = v; + v = u; + u = t; + } + + v = v - u; + } while (v); + + return u << s; +} + +bool sample_rate_frac_set(uint32_t rate_num, uint32_t rate_denom) +{ + const uint64_t VCO_FREQ = 800 * 1000 * 1000; /* 800 MHz */ + uint32_t MSx_P1, MSx_P2, MSx_P3; + uint32_t a, b, c; + uint32_t rem; + + hackrf_ui()->set_sample_rate(rate_num / 2); + + /* Find best config */ + a = (VCO_FREQ * rate_denom) / rate_num; + + rem = (VCO_FREQ * rate_denom) - (a * rate_num); + + if (!rem) { + /* Integer mode */ + b = 0; + c = 1; + } else { + /* Fractional */ + uint32_t g = gcd(rem, rate_num); + rem /= g; + rate_num /= g; + + if (rate_num < (1 << 20)) { + /* Perfect match */ + b = rem; + c = rate_num; + } else { + /* Approximate */ + c = (1 << 20) - 1; + b = ((uint64_t) c * (uint64_t) rem) / rate_num; + + g = gcd(b, c); + b /= g; + c /= g; + } + } + + bool streaming = sgpio_cpld_stream_is_enabled(&sgpio_config); + + if (streaming) { + sgpio_cpld_stream_disable(&sgpio_config); + } + + /* Can we enable integer mode ? */ + if (a & 0x1 || b) { + si5351c_set_int_mode(&clock_gen, 0, 0); + } else { + si5351c_set_int_mode(&clock_gen, 0, 1); + } + + /* Final MS values */ + MSx_P1 = 128 * a + (128 * b / c) - 512; + MSx_P2 = (128 * b) % c; + MSx_P3 = c; + +#ifndef PRALINE + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + /* + * On HackRF One r9 all sample clocks are externally derived + * from MS1/CLK1 operating at twice the sample rate. + */ + si5351c_configure_multisynth(&clock_gen, 1, MSx_P1, MSx_P2, MSx_P3, 0); + } else { + /* + * On other platforms the clock generator produces three + * different sample clocks, all derived from multisynth 0. + */ + /* MS0/CLK0 is the source for the MAX5864/CPLD (CODEC_CLK). */ + si5351c_configure_multisynth(&clock_gen, 0, MSx_P1, MSx_P2, MSx_P3, 1); + + /* MS0/CLK1 is the source for the CPLD (CODEC_X2_CLK). */ + si5351c_configure_multisynth(&clock_gen, 1, 0, 0, 0, 0); //p1 doesn't matter + + /* MS0/CLK2 is the source for SGPIO (CODEC_X2_CLK) */ + si5351c_configure_multisynth(&clock_gen, 2, 0, 0, 0, 0); //p1 doesn't matter + } +#else + /* MS0/CLK0 is the source for the MAX5864/FPGA (AFE_CLK). */ + si5351c_configure_multisynth(&clock_gen, 0, MSx_P1, MSx_P2, MSx_P3, 1); +#endif + + if (streaming) { + sgpio_cpld_stream_enable(&sgpio_config); + } + + return true; +} + +bool sample_rate_set(const uint32_t sample_rate_hz) +{ + uint32_t p1 = 4608; + uint32_t p2 = 0; + uint32_t p3 = 0; + + switch (sample_rate_hz) { + case 8000000: + p1 = SI_INTDIV(50); // 800MHz / 50 = 16 MHz (SGPIO), 8 MHz (codec) + break; + + case 9216000: + // 43.40277777777778: a = 43; b = 29; c = 72 + p1 = 5043; + p2 = 40; + p3 = 72; + break; + + case 10000000: + p1 = SI_INTDIV(40); // 800MHz / 40 = 20 MHz (SGPIO), 10 MHz (codec) + break; + + case 12288000: + // 32.552083333333336: a = 32; b = 159; c = 288 + p1 = 3654; + p2 = 192; + p3 = 288; + break; + + case 12500000: + p1 = SI_INTDIV(32); // 800MHz / 32 = 25 MHz (SGPIO), 12.5 MHz (codec) + break; + + case 16000000: + p1 = SI_INTDIV(25); // 800MHz / 25 = 32 MHz (SGPIO), 16 MHz (codec) + break; + + case 18432000: + // 21.70138888889: a = 21; b = 101; c = 144 + p1 = 2265; + p2 = 112; + p3 = 144; + break; + + case 20000000: + p1 = SI_INTDIV(20); // 800MHz / 20 = 40 MHz (SGPIO), 20 MHz (codec) + break; + + default: + return false; + } + +#ifndef PRALINE + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + /* + * On HackRF One r9 all sample clocks are externally derived + * from MS1/CLK1 operating at twice the sample rate. + */ + si5351c_configure_multisynth(&clock_gen, 1, p1, p2, p3, 0); + } else { + /* + * On other platforms the clock generator produces three + * different sample clocks, all derived from multisynth 0. + */ + /* MS0/CLK0 is the source for the MAX5864/CPLD (CODEC_CLK). */ + si5351c_configure_multisynth(&clock_gen, 0, p1, p2, p3, 1); + + /* MS0/CLK1 is the source for the CPLD (CODEC_X2_CLK). */ + si5351c_configure_multisynth( + &clock_gen, + 1, + p1, + 0, + 1, + 0); //p1 doesn't matter + + /* MS0/CLK2 is the source for SGPIO (CODEC_X2_CLK) */ + si5351c_configure_multisynth( + &clock_gen, + 2, + p1, + 0, + 1, + 0); //p1 doesn't matter + } +#else + /* MS0/CLK0 is the source for the MAX5864/FPGA (AFE_CLK). */ + si5351c_configure_multisynth(&clock_gen, 0, p1, p2, p3, 1); + + /* MS0/CLK1 is the source for SCT_CLK (CODEC_X2_CLK). */ + si5351c_configure_multisynth(&clock_gen, 1, p1, p2, p3, 0); +#endif + + return true; +} + +/* +Configure PLL1 (Main MCU Clock) to max speed (204MHz). +Note: PLL1 clock is used by M4/M0 core, Peripheral, APB1. +This function shall be called after cpu_clock_init(). +*/ +static void cpu_clock_pll1_max_speed(void) +{ + uint32_t reg_val; + + /* This function implements the sequence recommended in: + * UM10503 Rev 2.4 (Aug 2018), section 13.2.1.1, page 167. */ + + /* 1. Select the IRC as BASE_M4_CLK source. */ + reg_val = CGU_BASE_M4_CLK; + reg_val &= ~CGU_BASE_M4_CLK_CLK_SEL_MASK; + reg_val |= CGU_BASE_M4_CLK_CLK_SEL(CGU_SRC_IRC) | CGU_BASE_M4_CLK_AUTOBLOCK(1); + CGU_BASE_M4_CLK = reg_val; + + /* 2. Enable the crystal oscillator. */ + CGU_XTAL_OSC_CTRL &= ~CGU_XTAL_OSC_CTRL_ENABLE_MASK; + + /* 3. Wait 250us. */ + delay_us_at_mhz(250, 12); + + /* 4. Set the AUTOBLOCK bit. */ + CGU_PLL1_CTRL |= CGU_PLL1_CTRL_AUTOBLOCK(1); + + /* 5. Reconfigure PLL1 to produce the final output frequency, with the + * crystal oscillator as clock source. */ + reg_val = CGU_PLL1_CTRL; + // clang-format off + reg_val &= ~( CGU_PLL1_CTRL_CLK_SEL_MASK | + CGU_PLL1_CTRL_PD_MASK | + CGU_PLL1_CTRL_FBSEL_MASK | + CGU_PLL1_CTRL_BYPASS_MASK | + CGU_PLL1_CTRL_DIRECT_MASK | + CGU_PLL1_CTRL_PSEL_MASK | + CGU_PLL1_CTRL_MSEL_MASK | + CGU_PLL1_CTRL_NSEL_MASK ); + /* Set PLL1 up to 12MHz * 17 = 204MHz. + * Direct mode: FCLKOUT = FCCO = M*(FCLKIN/N) */ + reg_val |= CGU_PLL1_CTRL_CLK_SEL(CGU_SRC_XTAL) | + CGU_PLL1_CTRL_PSEL(0) | + CGU_PLL1_CTRL_NSEL(0) | + CGU_PLL1_CTRL_MSEL(16) | + CGU_PLL1_CTRL_FBSEL(0) | + CGU_PLL1_CTRL_DIRECT(1); + // clang-format on + CGU_PLL1_CTRL = reg_val; + + /* 6. Wait for PLL1 to lock. */ + while (!(CGU_PLL1_STAT & CGU_PLL1_STAT_LOCK_MASK)) {} + + /* 7. Set the PLL1 P-divider to divide by 2 (DIRECT=0, PSEL=0). */ + CGU_PLL1_CTRL &= ~CGU_PLL1_CTRL_DIRECT_MASK; + + /* 8. Select PLL1 as BASE_M4_CLK source. */ + reg_val = CGU_BASE_M4_CLK; + reg_val &= ~CGU_BASE_M4_CLK_CLK_SEL_MASK; + reg_val |= CGU_BASE_M4_CLK_CLK_SEL(CGU_SRC_PLL1); + CGU_BASE_M4_CLK = reg_val; + + /* 9. Wait 50us. */ + delay_us_at_mhz(50, 102); + + /* 10. Set the PLL1 P-divider to direct output mode (DIRECT=1). */ + CGU_PLL1_CTRL |= CGU_PLL1_CTRL_DIRECT_MASK; +} + +/* clock startup for LPC4320 configure PLL1 to max speed (204MHz). +Note: PLL1 clock is used by M4/M0 core, Peripheral, APB1. */ +void cpu_clock_init(void) +{ + /* use IRC as clock source for APB1 (including I2C0) */ + CGU_BASE_APB1_CLK = CGU_BASE_APB1_CLK_CLK_SEL(CGU_SRC_IRC); + + /* use IRC as clock source for APB3 */ + CGU_BASE_APB3_CLK = CGU_BASE_APB3_CLK_CLK_SEL(CGU_SRC_IRC); + + //FIXME disable I2C + /* Kick I2C0 down to 400kHz when we switch over to APB1 clock = 204MHz */ + i2c_bus_start(clock_gen.bus, &i2c_config_si5351c_fast_clock); + + /* + * 12MHz clock is entering LPC XTAL1/OSC input now. + * On HackRF One and Jawbreaker, there is a 12 MHz crystal at the LPC. + * Set up PLL1 to run from XTAL1 input. + */ + + //FIXME a lot of the details here should be in a CGU driver + + /* set xtal oscillator to low frequency mode */ + CGU_XTAL_OSC_CTRL &= ~CGU_XTAL_OSC_CTRL_HF_MASK; + + cpu_clock_pll1_max_speed(); + + /* use XTAL_OSC as clock source for APB1 */ + CGU_BASE_APB1_CLK = + CGU_BASE_APB1_CLK_AUTOBLOCK(1) | CGU_BASE_APB1_CLK_CLK_SEL(CGU_SRC_XTAL); + + /* use XTAL_OSC as clock source for APB3 */ + CGU_BASE_APB3_CLK = + CGU_BASE_APB3_CLK_AUTOBLOCK(1) | CGU_BASE_APB3_CLK_CLK_SEL(CGU_SRC_XTAL); + + /* use XTAL_OSC as clock source for PLL0USB */ + CGU_PLL0USB_CTRL = CGU_PLL0USB_CTRL_PD(1) | CGU_PLL0USB_CTRL_AUTOBLOCK(1) | + CGU_PLL0USB_CTRL_CLK_SEL(CGU_SRC_XTAL); + while (CGU_PLL0USB_STAT & CGU_PLL0USB_STAT_LOCK_MASK) {} + + /* configure PLL0USB to produce 480 MHz clock from 12 MHz XTAL_OSC */ + /* Values from User Manual v1.4 Table 94, for 12MHz oscillator. */ + CGU_PLL0USB_MDIV = 0x06167FFA; + CGU_PLL0USB_NP_DIV = 0x00302062; + CGU_PLL0USB_CTRL |= + (CGU_PLL0USB_CTRL_PD(1) | CGU_PLL0USB_CTRL_DIRECTI(1) | + CGU_PLL0USB_CTRL_DIRECTO(1) | CGU_PLL0USB_CTRL_CLKEN(1)); + + /* power on PLL0USB and wait until stable */ + CGU_PLL0USB_CTRL &= ~CGU_PLL0USB_CTRL_PD_MASK; + while (!(CGU_PLL0USB_STAT & CGU_PLL0USB_STAT_LOCK_MASK)) {} + + /* use PLL0USB as clock source for USB0 */ + CGU_BASE_USB0_CLK = CGU_BASE_USB0_CLK_AUTOBLOCK(1) | + CGU_BASE_USB0_CLK_CLK_SEL(CGU_SRC_PLL0USB); + + /* Switch peripheral clock over to use PLL1 (204MHz) */ + CGU_BASE_PERIPH_CLK = CGU_BASE_PERIPH_CLK_AUTOBLOCK(1) | + CGU_BASE_PERIPH_CLK_CLK_SEL(CGU_SRC_PLL1); + + /* Switch APB1 clock over to use PLL1 (204MHz) */ + CGU_BASE_APB1_CLK = + CGU_BASE_APB1_CLK_AUTOBLOCK(1) | CGU_BASE_APB1_CLK_CLK_SEL(CGU_SRC_PLL1); + + /* Switch APB3 clock over to use PLL1 (204MHz) */ + CGU_BASE_APB3_CLK = + CGU_BASE_APB3_CLK_AUTOBLOCK(1) | CGU_BASE_APB3_CLK_CLK_SEL(CGU_SRC_PLL1); + + CGU_BASE_SSP0_CLK = + CGU_BASE_SSP0_CLK_AUTOBLOCK(1) | CGU_BASE_SSP0_CLK_CLK_SEL(CGU_SRC_PLL1); + + CGU_BASE_SSP1_CLK = + CGU_BASE_SSP1_CLK_AUTOBLOCK(1) | CGU_BASE_SSP1_CLK_CLK_SEL(CGU_SRC_PLL1); + +#if (defined JAWBREAKER || defined HACKRF_ONE || defined PRALINE) + /* Disable unused clocks */ + /* Start with PLLs */ + CGU_PLL0AUDIO_CTRL = CGU_PLL0AUDIO_CTRL_PD(1); + + /* Dividers */ + CGU_IDIVA_CTRL = CGU_IDIVA_CTRL_PD(1); + CGU_IDIVB_CTRL = CGU_IDIVB_CTRL_PD(1); + CGU_IDIVC_CTRL = CGU_IDIVC_CTRL_PD(1); + CGU_IDIVD_CTRL = CGU_IDIVD_CTRL_PD(1); + CGU_IDIVE_CTRL = CGU_IDIVE_CTRL_PD(1); + + /* Base clocks */ + CGU_BASE_SPIFI_CLK = CGU_BASE_SPIFI_CLK_PD(1); /* SPIFI is only used at boot */ + CGU_BASE_USB1_CLK = CGU_BASE_USB1_CLK_PD(1); /* USB1 is not exposed on HackRF */ + CGU_BASE_PHY_RX_CLK = CGU_BASE_PHY_RX_CLK_PD(1); + CGU_BASE_PHY_TX_CLK = CGU_BASE_PHY_TX_CLK_PD(1); + CGU_BASE_LCD_CLK = CGU_BASE_LCD_CLK_PD(1); + CGU_BASE_VADC_CLK = CGU_BASE_VADC_CLK_PD(1); + CGU_BASE_SDIO_CLK = CGU_BASE_SDIO_CLK_PD(1); + CGU_BASE_UART0_CLK = CGU_BASE_UART0_CLK_PD(1); + CGU_BASE_UART1_CLK = CGU_BASE_UART1_CLK_PD(1); + CGU_BASE_UART2_CLK = CGU_BASE_UART2_CLK_PD(1); + CGU_BASE_UART3_CLK = CGU_BASE_UART3_CLK_PD(1); + CGU_BASE_OUT_CLK = CGU_BASE_OUT_CLK_PD(1); + CGU_BASE_AUDIO_CLK = CGU_BASE_AUDIO_CLK_PD(1); + CGU_BASE_CGU_OUT0_CLK = CGU_BASE_CGU_OUT0_CLK_PD(1); + CGU_BASE_CGU_OUT1_CLK = CGU_BASE_CGU_OUT1_CLK_PD(1); + + /* Disable unused peripheral clocks */ + CCU1_CLK_APB1_CAN1_CFG = 0; + CCU1_CLK_APB1_I2S_CFG = 0; + CCU1_CLK_APB1_MOTOCONPWM_CFG = 0; + //CCU1_CLK_APB3_ADC0_CFG = 0; + CCU1_CLK_APB3_ADC1_CFG = 0; + CCU1_CLK_APB3_CAN0_CFG = 0; + CCU1_CLK_APB3_DAC_CFG = 0; + //CCU1_CLK_M4_DMA_CFG = 0; + CCU1_CLK_M4_EMC_CFG = 0; + CCU1_CLK_M4_EMCDIV_CFG = 0; + CCU1_CLK_M4_ETHERNET_CFG = 0; + CCU1_CLK_M4_LCD_CFG = 0; + CCU1_CLK_M4_QEI_CFG = 0; + CCU1_CLK_M4_RITIMER_CFG = 0; + // CCU1_CLK_M4_SCT_CFG = 0; + CCU1_CLK_M4_SDIO_CFG = 0; + CCU1_CLK_M4_SPIFI_CFG = 0; + CCU1_CLK_M4_TIMER0_CFG = 0; + //CCU1_CLK_M4_TIMER1_CFG = 0; + //CCU1_CLK_M4_TIMER2_CFG = 0; + CCU1_CLK_M4_TIMER3_CFG = 0; + CCU1_CLK_M4_UART1_CFG = 0; + CCU1_CLK_M4_USART0_CFG = 0; + CCU1_CLK_M4_USART2_CFG = 0; + CCU1_CLK_M4_USART3_CFG = 0; + CCU1_CLK_M4_USB1_CFG = 0; + CCU1_CLK_M4_VADC_CFG = 0; + // CCU1_CLK_SPIFI_CFG = 0; + // CCU1_CLK_USB1_CFG = 0; + // CCU1_CLK_VADC_CFG = 0; + // CCU2_CLK_APB0_UART1_CFG = 0; + // CCU2_CLK_APB0_USART0_CFG = 0; + // CCU2_CLK_APB2_USART2_CFG = 0; + // CCU2_CLK_APB2_USART3_CFG = 0; + // CCU2_CLK_APLL_CFG = 0; + // CCU2_CLK_SDIO_CFG = 0; +#endif +} + +void clock_gen_init(void) +{ + i2c_bus_start(clock_gen.bus, &i2c_config_si5351c_fast_clock); + + si5351c_init(&clock_gen); + si5351c_disable_all_outputs(&clock_gen); + si5351c_disable_oeb_pin_control(&clock_gen); + si5351c_power_down_all_clocks(&clock_gen); + si5351c_set_crystal_configuration(&clock_gen); + si5351c_enable_xo_and_ms_fanout(&clock_gen); + si5351c_configure_pll_sources(&clock_gen); + si5351c_configure_pll_multisynth(&clock_gen); + + /* + * Clocks on HackRF One r9: + * CLK0 -> MAX5864/CPLD/SGPIO (sample clocks) + * CLK1 -> RFFC5072/MAX2839 + * CLK2 -> External Clock Output/LPC43xx (power down at boot) + * + * Clocks on other platforms: + * CLK0 -> MAX5864/CPLD + * CLK1 -> CPLD + * CLK2 -> SGPIO + * CLK3 -> External Clock Output (power down at boot) + * CLK4 -> RFFC5072 (MAX2837 on rad1o) + * CLK5 -> MAX2837 (MAX2871 on rad1o) + * CLK6 -> none + * CLK7 -> LPC43xx (uses a 12MHz crystal by default) + * + * Clocks on Praline: + * CLK0 -> AFE_CLK (MAX5864/FPGA) + * CLK1 -> SCT_CLK + * CLK2 -> MCU_CLK (uses a 12MHz crystal by default) + * CLK3 -> External Clock Output (power down at boot) + * CLK4 -> XCVR_CLK (MAX2837) + * CLK5 -> MIX_CLK (RFFC5072) + * CLK6 -> AUX_CLK1 + * CLK7 -> AUX_CLK2 + */ + + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + /* MS0/CLK0 is the reference for both RFFC5071 and MAX2839. */ + si5351c_configure_multisynth( + &clock_gen, + 0, + 20 * 128 - 512, + 0, + 1, + 0); /* 800/20 = 40MHz */ + } else { + /* MS4/CLK4 is the source for the RFFC5071 mixer (MAX2837 on rad1o). */ + si5351c_configure_multisynth( + &clock_gen, + 4, + 20 * 128 - 512, + 0, + 1, + 0); /* 800/20 = 40MHz */ + /* MS5/CLK5 is the source for the MAX2837 clock input (MAX2871 on rad1o). */ + si5351c_configure_multisynth( + &clock_gen, + 5, + 20 * 128 - 512, + 0, + 1, + 0); /* 800/20 = 40MHz */ + } + + /* MS6/CLK6 is unused. */ + /* MS7/CLK7 is unused. */ + + /* Set to 10 MHz, the common rate between Jawbreaker and HackRF One. */ + sample_rate_set(10000000); + + si5351c_set_clock_source(&clock_gen, PLL_SOURCE_XTAL); + // soft reset + si5351c_reset_pll(&clock_gen); + si5351c_enable_clock_outputs(&clock_gen); +} + +void clock_gen_shutdown(void) +{ + i2c_bus_start(clock_gen.bus, &i2c_config_si5351c_fast_clock); + si5351c_disable_all_outputs(&clock_gen); + si5351c_disable_oeb_pin_control(&clock_gen); + si5351c_power_down_all_clocks(&clock_gen); +} + +clock_source_t activate_best_clock_source(void) +{ +#if (defined HACKRF_ONE || defined PRALINE) + /* Ensure PortaPack reference oscillator is off while checking for external clock input. */ + if (portapack_reference_oscillator && portapack()) { + portapack_reference_oscillator(false); + } +#endif + + clock_source_t source = CLOCK_SOURCE_HACKRF; + + /* Check for external clock input. */ + if (si5351c_clkin_signal_valid(&clock_gen)) { + source = CLOCK_SOURCE_EXTERNAL; + } else { +#if (defined HACKRF_ONE || defined PRALINE) + /* Enable PortaPack reference oscillator (if present), and check for valid clock. */ + if (portapack_reference_oscillator && portapack()) { + portapack_reference_oscillator(true); + delay(510000); /* loop iterations @ 204MHz for >10ms for oscillator to enable. */ + if (si5351c_clkin_signal_valid(&clock_gen)) { + source = CLOCK_SOURCE_PORTAPACK; + } else { + portapack_reference_oscillator(false); + } + } +#endif + /* No external or PortaPack clock was found. Use HackRF Si5351C crystal. */ + } + + si5351c_set_clock_source( + &clock_gen, + (source == CLOCK_SOURCE_HACKRF) ? PLL_SOURCE_XTAL : PLL_SOURCE_CLKIN); + hackrf_ui()->set_clock_source(source); + radio.channel[RADIO_CHANNEL0].clock_source = source; + + return source; +} + +void ssp1_set_mode_max283x(void) +{ + spi_bus_start(&spi_bus_ssp1, &ssp_config_max283x); +} + +void ssp1_set_mode_max5864(void) +{ + spi_bus_start(max5864.bus, &ssp_config_max5864); +} + +#ifdef PRALINE +void ssp1_set_mode_ice40(void) +{ + spi_bus_start(&spi_bus_ssp1, &ssp_config_ice40_fpga); +} +#endif + +void pin_shutdown(void) +{ + /* Configure all GPIO as Input (safe state) */ + gpio_init(); + + /* TDI and TMS pull-ups are required in all JTAG-compliant devices. + * + * The HackRF CPLD is always present, so let the CPLD pull up its TDI and TMS. + * + * The PortaPack may not be present, so pull up the PortaPack TMS pin from the + * microcontroller. + * + * TCK is recommended to be held low, so use microcontroller pull-down. + * + * TDO is undriven except when in Shift-IR or Shift-DR phases. + * Use the microcontroller to pull down to keep from floating. + * + * LPC43xx pull-up and pull-down resistors are approximately 53K. + */ +#if (defined HACKRF_ONE || defined PRALINE) + scu_pinmux(SCU_PINMUX_PP_TMS, SCU_GPIO_PUP | SCU_CONF_FUNCTION0); + scu_pinmux(SCU_PINMUX_PP_TDO, SCU_GPIO_PDN | SCU_CONF_FUNCTION0); +#endif + scu_pinmux(SCU_PINMUX_CPLD_TCK, SCU_GPIO_PDN | SCU_CONF_FUNCTION0); +#ifndef PRALINE + scu_pinmux(SCU_PINMUX_CPLD_TMS, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0); + scu_pinmux(SCU_PINMUX_CPLD_TDI, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0); + scu_pinmux(SCU_PINMUX_CPLD_TDO, SCU_GPIO_PDN | SCU_CONF_FUNCTION4); +#endif + + /* Configure SCU Pin Mux as GPIO */ + scu_pinmux(SCU_PINMUX_LED1, SCU_GPIO_NOPULL); + scu_pinmux(SCU_PINMUX_LED2, SCU_GPIO_NOPULL); + scu_pinmux(SCU_PINMUX_LED3, SCU_GPIO_NOPULL); +#ifdef RAD1O + scu_pinmux(SCU_PINMUX_LED4, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION4); +#endif +#ifdef PRALINE + scu_pinmux(SCU_PINMUX_LED4, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0); +#endif + + /* Configure USB indicators */ +#ifdef JAWBREAKER + scu_pinmux(SCU_PINMUX_USB_LED0, SCU_CONF_FUNCTION3); + scu_pinmux(SCU_PINMUX_USB_LED1, SCU_CONF_FUNCTION3); +#endif + +#ifdef PRALINE + disable_1v2_power(); + disable_3v3aux_power(); + gpio_output(&gpio_1v2_enable); + gpio_output(&gpio_3v3aux_enable_n); + scu_pinmux(SCU_PINMUX_EN1V2, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + scu_pinmux(SCU_PINMUX_EN3V3_AUX_N, SCU_GPIO_FAST | SCU_CONF_FUNCTION4); +#else + disable_1v8_power(); + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + #ifdef HACKRF_ONE + gpio_output(&gpio_h1r9_1v8_enable); + scu_pinmux(SCU_H1R9_EN1V8, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + #endif + } else { + gpio_output(&gpio_1v8_enable); + scu_pinmux(SCU_PINMUX_EN1V8, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + } +#endif + +#if (defined HACKRF_ONE || defined PRALINE) + /* Safe state: start with VAA turned off: */ + disable_rf_power(); + + /* Configure RF power supply (VAA) switch control signal as output */ + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + #ifdef HACKRF_ONE + gpio_output(&gpio_h1r9_vaa_disable); + #endif + } else { + gpio_output(&gpio_vaa_disable); + } +#endif + +#ifdef RAD1O + /* Safe state: start with VAA turned off: */ + disable_rf_power(); + + /* Configure RF power supply (VAA) switch control signal as output */ + gpio_output(&gpio_vaa_enable); + + /* Disable unused clock outputs. They generate noise. */ + scu_pinmux(CLK0, SCU_CLK_IN | SCU_CONF_FUNCTION7); + scu_pinmux(CLK2, SCU_CLK_IN | SCU_CONF_FUNCTION7); + + scu_pinmux(SCU_PINMUX_GPIO3_10, SCU_GPIO_PDN | SCU_CONF_FUNCTION0); + scu_pinmux(SCU_PINMUX_GPIO3_11, SCU_GPIO_PDN | SCU_CONF_FUNCTION0); +#endif + +#ifdef PRALINE + scu_pinmux(SCU_P2_CTRL0, SCU_P2_CTRL0_PINCFG); + scu_pinmux(SCU_P2_CTRL1, SCU_P2_CTRL1_PINCFG); + scu_pinmux(SCU_P1_CTRL0, SCU_P1_CTRL0_PINCFG); + scu_pinmux(SCU_P1_CTRL1, SCU_P1_CTRL1_PINCFG); + scu_pinmux(SCU_P1_CTRL2, SCU_P1_CTRL2_PINCFG); + scu_pinmux(SCU_CLKIN_CTRL, SCU_CLKIN_CTRL_PINCFG); + scu_pinmux(SCU_AA_EN, SCU_AA_EN_PINCFG); + scu_pinmux(SCU_TRIGGER_IN, SCU_TRIGGER_IN_PINCFG); + scu_pinmux(SCU_TRIGGER_OUT, SCU_TRIGGER_OUT_PINCFG); + scu_pinmux(SCU_PPS_OUT, SCU_PPS_OUT_PINCFG); + scu_pinmux(SCU_PINMUX_FPGA_CRESET, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0); + scu_pinmux(SCU_PINMUX_FPGA_CDONE, SCU_GPIO_PUP | SCU_CONF_FUNCTION4); + scu_pinmux(SCU_PINMUX_FPGA_SPI_CS, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0); + + p2_ctrl_set(P2_SIGNAL_CLK3); + p1_ctrl_set(P1_SIGNAL_CLKIN); + narrowband_filter_set(0); + clkin_ctrl_set(CLKIN_SIGNAL_P22); + + gpio_output(&gpio_p2_ctrl0); + gpio_output(&gpio_p2_ctrl1); + gpio_output(&gpio_p1_ctrl0); + gpio_output(&gpio_p1_ctrl1); + gpio_output(&gpio_p1_ctrl2); + gpio_output(&gpio_clkin_ctrl); + gpio_output(&gpio_pps_out); + gpio_output(&gpio_aa_en); + gpio_input(&gpio_trigger_in); + gpio_input(&gpio_trigger_out); + gpio_clear(&gpio_fpga_cfg_spi_cs); + gpio_output(&gpio_fpga_cfg_spi_cs); + gpio_clear(&gpio_fpga_cfg_creset); + gpio_output(&gpio_fpga_cfg_creset); + gpio_input(&gpio_fpga_cfg_cdone); +#endif + + /* enable input on SCL and SDA pins */ + SCU_SFSI2C0 = SCU_I2C0_NOMINAL; +} + +/* Run after pin_shutdown() and prior to enabling power supplies. */ +void pin_setup(void) +{ + led_off(0); + led_off(1); + led_off(2); +#ifdef RAD1O + led_off(3); +#endif + + gpio_output(&gpio_led[0]); + gpio_output(&gpio_led[1]); + gpio_output(&gpio_led[2]); +#if (defined RAD1O || defined PRALINE) + gpio_output(&gpio_led[3]); +#endif + + ssp1_set_mode_max283x(); + + mixer_bus_setup(&mixer); + +#ifdef HACKRF_ONE + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + rf_path.gpio_rx = &gpio_h1r9_rx; + sgpio_config.gpio_trigger_enable = &gpio_h1r9_trigger_enable; + } +#endif + +#ifdef PRALINE + board_rev_t rev = detected_revision(); + if ((rev == BOARD_REV_PRALINE_R1_0) || (rev == BOARD_REV_GSG_PRALINE_R1_0)) { + rf_path.gpio_mix_en_n = &gpio_mix_en_n_r1_0; + } +#endif + + rf_path_pin_setup(&rf_path); + + /* Configure external clock in */ + scu_pinmux(SCU_PINMUX_GP_CLKIN, SCU_CLK_IN | SCU_CONF_FUNCTION1); + + sgpio_configure_pin_functions(&sgpio_config); +} + +#ifdef PRALINE +void enable_1v2_power(void) +{ + gpio_set(&gpio_1v2_enable); +} + +void disable_1v2_power(void) +{ + gpio_clear(&gpio_1v2_enable); +} + +void enable_3v3aux_power(void) +{ + gpio_clear(&gpio_3v3aux_enable_n); +} + +void disable_3v3aux_power(void) +{ + gpio_set(&gpio_3v3aux_enable_n); +} +#else +void enable_1v8_power(void) +{ + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + #ifdef HACKRF_ONE + gpio_set(&gpio_h1r9_1v8_enable); + #endif + } else { + gpio_set(&gpio_1v8_enable); + } +} + +void disable_1v8_power(void) +{ + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + #ifdef HACKRF_ONE + gpio_clear(&gpio_h1r9_1v8_enable); + #endif + } else { + gpio_clear(&gpio_1v8_enable); + } +} +#endif + +#ifdef HACKRF_ONE +void enable_rf_power(void) +{ + uint32_t i; + + /* many short pulses to avoid one big voltage glitch */ + for (i = 0; i < 1000; i++) { + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + gpio_set(&gpio_h1r9_vaa_disable); + gpio_clear(&gpio_h1r9_vaa_disable); + } else { + gpio_set(&gpio_vaa_disable); + gpio_clear(&gpio_vaa_disable); + } + } +} + +void disable_rf_power(void) +{ + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + gpio_set(&gpio_h1r9_vaa_disable); + } else { + gpio_set(&gpio_vaa_disable); + } +} +#endif + +#ifdef PRALINE +void enable_rf_power(void) +{ + gpio_clear(&gpio_vaa_disable); + + /* Let the voltage stabilize */ + delay(1000000); +} + +void disable_rf_power(void) +{ + gpio_set(&gpio_vaa_disable); +} +#endif + +#ifdef RAD1O +void enable_rf_power(void) +{ + gpio_set(&gpio_vaa_enable); + + /* Let the voltage stabilize */ + delay(1000000); +} + +void disable_rf_power(void) +{ + gpio_clear(&gpio_vaa_enable); +} +#endif + +#ifdef PRALINE +void led_on(const led_t led) +{ + gpio_clear(&gpio_led[led]); +} + +void led_off(const led_t led) +{ + gpio_set(&gpio_led[led]); +} +#else +void led_on(const led_t led) +{ + gpio_set(&gpio_led[led]); +} + +void led_off(const led_t led) +{ + gpio_clear(&gpio_led[led]); +} +#endif + +void led_toggle(const led_t led) +{ + gpio_toggle(&gpio_led[led]); +} + +void set_leds(const uint8_t state) +{ + int num_leds = 3; +#if (defined RAD1O || defined PRALINE) + num_leds = 4; +#endif + for (int i = 0; i < num_leds; i++) { +#ifdef PRALINE + gpio_write(&gpio_led[i], ((state >> i) & 1) == 0); +#else + gpio_write(&gpio_led[i], ((state >> i) & 1) == 1); +#endif + } +} + +void trigger_enable(const bool enable) +{ +#ifndef PRALINE + gpio_write(sgpio_config.gpio_trigger_enable, enable); +#else + fpga_set_trigger_enable(&fpga, enable); +#endif +} + +void halt_and_flash(const uint32_t duration) +{ + /* blink LED1, LED2, and LED3 */ + while (1) { + led_on(LED1); + led_on(LED2); + led_on(LED3); + delay(duration); + led_off(LED1); + led_off(LED2); + led_off(LED3); + delay(duration); + } +} + +#ifdef PRALINE +void p1_ctrl_set(const p1_ctrl_signal_t signal) +{ + gpio_write(&gpio_p1_ctrl0, signal & 1); + gpio_write(&gpio_p1_ctrl1, (signal >> 1) & 1); + gpio_write(&gpio_p1_ctrl2, (signal >> 2) & 1); +} + +void p2_ctrl_set(const p2_ctrl_signal_t signal) +{ + gpio_write(&gpio_p2_ctrl0, signal & 1); + gpio_write(&gpio_p2_ctrl1, (signal >> 1) & 1); +} + +void clkin_ctrl_set(const clkin_signal_t signal) +{ + gpio_write(&gpio_clkin_ctrl, signal & 1); +} + +void pps_out_set(const uint8_t value) +{ + gpio_write(&gpio_pps_out, value & 1); +} + +void narrowband_filter_set(const uint8_t value) +{ + gpio_write(&gpio_aa_en, value & 1); +} +#endif diff --git a/firmware/common/hackrf_core.h b/firmware/common/hackrf_core.h new file mode 100644 index 00000000..301cb7aa --- /dev/null +++ b/firmware/common/hackrf_core.h @@ -0,0 +1,501 @@ +/* + * Copyright 2012-2022 Great Scott Gadgets + * Copyright 2012 Benjamin Vernoux + * Copyright 2012 Jared Boone + * + * This file is part of HackRF. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __HACKRF_CORE_H +#define __HACKRF_CORE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#include "si5351c.h" +#include "spi_ssp.h" + +#include "max2831.h" +#include "max283x.h" +#include "max5864.h" +#include "mixer.h" +#include "w25q80bv.h" +#include "sgpio.h" +#include "radio.h" +#include "rf_path.h" +#include "cpld_jtag.h" +#include "ice40_spi.h" +#include "fpga.h" + +/* + * SCU PinMux + */ + +/* GPIO Output PinMux */ +#define SCU_PINMUX_LED1 (P4_1) /* GPIO2[1] on P4_1 */ +#define SCU_PINMUX_LED2 (P4_2) /* GPIO2[2] on P4_2 */ +#define SCU_PINMUX_LED3 (P6_12) /* GPIO2[8] on P6_12 */ +#ifdef RAD1O + #define SCU_PINMUX_LED4 (PB_6) /* GPIO5[26] on PB_6 */ +#endif +#ifdef PRALINE + #define SCU_PINMUX_LED4 (P8_6) /* GPIO4[6] on P8_6 */ +#endif + +#define SCU_PINMUX_EN1V8 (P6_10) /* GPIO3[6] on P6_10 */ +#define SCU_PINMUX_EN1V2 (P8_7) /* GPIO4[7] on P8_7 */ +#ifdef PRALINE + #define SCU_PINMUX_EN3V3_AUX_N (P6_7) /* GPIO5[15] on P6_7 */ + #define SCU_PINMUX_EN3V3_OC_N (P6_11) /* GPIO3[7] on P6_11 */ +#endif + +/* GPIO Input PinMux */ +#define SCU_PINMUX_BOOT0 (P1_1) /* GPIO0[8] on P1_1 */ +#define SCU_PINMUX_BOOT1 (P1_2) /* GPIO0[9] on P1_2 */ +#ifndef HACKRF_ONE + #define SCU_PINMUX_BOOT2 (P2_8) /* GPIO5[7] on P2_8 */ + #define SCU_PINMUX_BOOT3 (P2_9) /* GPIO1[10] on P2_9 */ +#endif +#define SCU_PINMUX_PP_LCD_TE (P2_3) /* GPIO5[3] on P2_3 */ +#define SCU_PINMUX_PP_LCD_RDX (P2_4) /* GPIO5[4] on P2_4 */ +#define SCU_PINMUX_PP_UNUSED (P2_8) /* GPIO5[7] on P2_8 */ +#define SCU_PINMUX_PP_LCD_WRX (P2_9) /* GPIO1[10] on P2_9 */ +#define SCU_PINMUX_PP_DIR (P2_13) /* GPIO1[13] on P2_13 */ + +/* USB peripheral */ +#ifdef JAWBREAKER + #define SCU_PINMUX_USB_LED0 (P6_8) + #define SCU_PINMUX_USB_LED1 (P6_7) +#endif + +/* SSP1 Peripheral PinMux */ +#define SCU_SSP1_CIPO (P1_3) /* P1_3 */ +#define SCU_SSP1_COPI (P1_4) /* P1_4 */ +#define SCU_SSP1_SCK (P1_19) /* P1_19 */ +#define SCU_SSP1_CS (P1_20) /* P1_20 */ + +/* CPLD JTAG interface */ +#ifdef PRALINE + #define SCU_PINMUX_FPGA_CRESET (P5_2) /* GPIO2[11] on P5_2 */ + #define SCU_PINMUX_FPGA_CDONE (P4_10) /* GPIO5[14] */ + #define SCU_PINMUX_FPGA_SPI_CS (P5_1) /* GPIO2[10] */ +#endif +#define SCU_PINMUX_CPLD_TDO (P9_5) /* GPIO5[18] */ +#define SCU_PINMUX_CPLD_TCK (P6_1) /* GPIO3[ 0] */ +#if (defined HACKRF_ONE || defined RAD1O || defined PRALINE) + #define SCU_PINMUX_CPLD_TMS (P6_5) /* GPIO3[ 4] */ + #define SCU_PINMUX_CPLD_TDI (P6_2) /* GPIO3[ 1] */ +#else + #define SCU_PINMUX_CPLD_TMS (P6_2) /* GPIO3[ 1] */ + #define SCU_PINMUX_CPLD_TDI (P6_5) /* GPIO3[ 4] */ +#endif + +/* CPLD SGPIO interface */ +#ifdef PRALINE + #define SCU_PINMUX_SGPIO0 (P0_0) + #define SCU_PINMUX_SGPIO1 (P0_1) + #define SCU_PINMUX_SGPIO2 (P1_15) + #define SCU_PINMUX_SGPIO3 (P1_16) + #define SCU_PINMUX_SGPIO4 (P9_4) + #define SCU_PINMUX_SGPIO5 (P6_6) + #define SCU_PINMUX_SGPIO6 (P2_2) + #define SCU_PINMUX_SGPIO7 (P1_0) + #define SCU_PINMUX_SGPIO8 (P8_0) + #define SCU_PINMUX_SGPIO9 (P9_3) + #define SCU_PINMUX_SGPIO10 (P8_2) + #define SCU_PINMUX_SGPIO11 (P1_17) + #define SCU_PINMUX_SGPIO12 (P1_18) + #define SCU_PINMUX_SGPIO14 (P1_18) + #define SCU_PINMUX_SGPIO15 (P1_18) + + #define SCU_PINMUX_SGPIO0_PINCFG (SCU_GPIO_FAST | SCU_CONF_FUNCTION3) + #define SCU_PINMUX_SGPIO1_PINCFG (SCU_GPIO_FAST | SCU_CONF_FUNCTION3) + #define SCU_PINMUX_SGPIO2_PINCFG (SCU_GPIO_FAST | SCU_CONF_FUNCTION2) + #define SCU_PINMUX_SGPIO3_PINCFG (SCU_GPIO_FAST | SCU_CONF_FUNCTION2) + #define SCU_PINMUX_SGPIO4_PINCFG (SCU_GPIO_FAST | SCU_CONF_FUNCTION6) + #define SCU_PINMUX_SGPIO5_PINCFG (SCU_GPIO_FAST | SCU_CONF_FUNCTION2) + #define SCU_PINMUX_SGPIO6_PINCFG (SCU_GPIO_FAST | SCU_CONF_FUNCTION0) + #define SCU_PINMUX_SGPIO7_PINCFG (SCU_GPIO_FAST | SCU_CONF_FUNCTION6) + #define SCU_PINMUX_SGPIO8_PINCFG (SCU_GPIO_FAST | SCU_CONF_FUNCTION4) + #define SCU_PINMUX_SGPIO9_PINCFG (SCU_GPIO_FAST | SCU_CONF_FUNCTION6) + #define SCU_PINMUX_SGPIO10_PINCFG (SCU_GPIO_FAST | SCU_CONF_FUNCTION4) + #define SCU_PINMUX_SGPIO11_PINCFG (SCU_GPIO_FAST | SCU_CONF_FUNCTION6) + #define SCU_PINMUX_SGPIO12_PINCFG (SCU_GPIO_FAST | SCU_CONF_FUNCTION0) + #define SCU_PINMUX_SGPIO14_PINCFG (SCU_GPIO_FAST | SCU_CONF_FUNCTION0) + #define SCU_PINMUX_SGPIO15_PINCFG (SCU_GPIO_FAST | SCU_CONF_FUNCTION0) + +#else + #define SCU_PINMUX_SGPIO0 (P0_0) + #define SCU_PINMUX_SGPIO1 (P0_1) + #define SCU_PINMUX_SGPIO2 (P1_15) + #define SCU_PINMUX_SGPIO3 (P1_16) + #define SCU_PINMUX_SGPIO4 (P6_3) + #define SCU_PINMUX_SGPIO5 (P6_6) + #define SCU_PINMUX_SGPIO6 (P2_2) + #define SCU_PINMUX_SGPIO7 (P1_0) + #if (defined JAWBREAKER || defined HACKRF_ONE || defined RAD1O) + #define SCU_PINMUX_SGPIO8 (P9_6) + #endif + #define SCU_PINMUX_SGPIO9 (P4_3) + #define SCU_PINMUX_SGPIO10 (P1_14) + #define SCU_PINMUX_SGPIO11 (P1_17) + #define SCU_PINMUX_SGPIO12 (P1_18) + #define SCU_PINMUX_SGPIO14 (P4_9) + #define SCU_PINMUX_SGPIO15 (P4_10) + + #define SCU_PINMUX_SGPIO0_PINCFG (SCU_GPIO_FAST | SCU_CONF_FUNCTION3) + #define SCU_PINMUX_SGPIO1_PINCFG (SCU_GPIO_FAST | SCU_CONF_FUNCTION3) + #define SCU_PINMUX_SGPIO2_PINCFG (SCU_GPIO_FAST | SCU_CONF_FUNCTION2) + #define SCU_PINMUX_SGPIO3_PINCFG (SCU_GPIO_FAST | SCU_CONF_FUNCTION2) + #define SCU_PINMUX_SGPIO4_PINCFG (SCU_GPIO_FAST | SCU_CONF_FUNCTION2) + #define SCU_PINMUX_SGPIO5_PINCFG (SCU_GPIO_FAST | SCU_CONF_FUNCTION2) + #define SCU_PINMUX_SGPIO6_PINCFG (SCU_GPIO_FAST | SCU_CONF_FUNCTION0) + #define SCU_PINMUX_SGPIO7_PINCFG (SCU_GPIO_FAST | SCU_CONF_FUNCTION6) + #define SCU_PINMUX_SGPIO8_PINCFG (SCU_GPIO_FAST | SCU_CONF_FUNCTION6) + #define SCU_PINMUX_SGPIO9_PINCFG (SCU_GPIO_FAST | SCU_CONF_FUNCTION7) + #define SCU_PINMUX_SGPIO10_PINCFG (SCU_GPIO_FAST | SCU_CONF_FUNCTION6) + #define SCU_PINMUX_SGPIO11_PINCFG (SCU_GPIO_FAST | SCU_CONF_FUNCTION6) + #define SCU_PINMUX_SGPIO12_PINCFG (SCU_GPIO_FAST | SCU_CONF_FUNCTION0) + #define SCU_PINMUX_SGPIO14_PINCFG (SCU_GPIO_FAST | SCU_CONF_FUNCTION4) + #define SCU_PINMUX_SGPIO15_PINCFG (SCU_GPIO_FAST | SCU_CONF_FUNCTION4) + +#endif +#define SCU_TRIGGER_EN (P4_8) /* GPIO5[12] on P4_8 */ + +/* MAX2837 GPIO (XCVR_CTL) PinMux */ +#ifdef RAD1O + #define SCU_XCVR_RXHP (P8_1) /* GPIO[] on P8_1 */ + #define SCU_XCVR_B6 (P8_2) /* GPIO[] on P8_2 */ + #define SCU_XCVR_B7 (P9_3) /* GPIO[] on P8_3 */ +#endif + +#ifdef PRALINE + #define SCU_XCVR_ENABLE (PE_1) /* GPIO7[1] on PE_1 */ + #define SCU_XCVR_RXENABLE (PE_2) /* GPIO7[2] on PE_2 */ + #define SCU_XCVR_CS (PD_14) /* GPIO6[28] on PD_14 */ + #define SCU_XCVR_RXHP (PD_15) /* GPIO6[29] on PD_15 */ + #define SCU_XCVR_LD (P9_6) /* GPIO4[11] on P9_6 */ + + #define SCU_XCVR_ENABLE_PINCFG (SCU_GPIO_FAST | SCU_CONF_FUNCTION4) + #define SCU_XCVR_RXENABLE_PINCFG (SCU_GPIO_FAST | SCU_CONF_FUNCTION4) + #define SCU_XCVR_CS_PINCFG (SCU_GPIO_FAST | SCU_CONF_FUNCTION4) + #define SCU_XCVR_RXHP_PINCFG (SCU_GPIO_FAST | SCU_CONF_FUNCTION4) + #define SCU_XCVR_LD_PINCFG \ + (SCU_GPIO_FAST | SCU_CONF_FUNCTION0 | SCU_CONF_EPD_EN_PULLDOWN | \ + SCU_CONF_EPUN_DIS_PULLUP) +#else + #define SCU_XCVR_ENABLE (P4_6) /* GPIO2[6] on P4_6 */ + #define SCU_XCVR_RXENABLE (P4_5) /* GPIO2[5] on P4_5 */ + #define SCU_XCVR_TXENABLE (P4_4) /* GPIO2[4] on P4_4 */ + #define SCU_XCVR_CS (P1_20) /* GPIO0[15] on P1_20 */ + + #define SCU_XCVR_ENABLE_PINCFG (SCU_GPIO_FAST) + #define SCU_XCVR_RXENABLE_PINCFG (SCU_GPIO_FAST) + #define SCU_XCVR_TXENABLE_PINCFG (SCU_GPIO_FAST) + #define SCU_XCVR_CS_PINCFG (SCU_GPIO_FAST) +#endif + +/* MAX5864 SPI chip select (AD_CS) GPIO PinMux */ +#ifdef PRALINE + #define SCU_AD_CS (PD_16) /* GPIO6[30] on PD_16 */ + #define SCU_AD_CS_PINCFG (SCU_GPIO_FAST | SCU_CONF_FUNCTION4) +#else + #define SCU_AD_CS (P5_7) /* GPIO2[7] on P5_7 */ + #define SCU_AD_CS_PINCFG (SCU_GPIO_FAST) +#endif + +/* RFFC5071 GPIO serial interface PinMux */ +#if (defined JAWBREAKER || defined HACKRF_ONE) + #define SCU_MIXER_ENX (P5_4) /* GPIO2[13] on P5_4 */ + #define SCU_MIXER_SCLK (P2_6) /* GPIO5[6] on P2_6 */ + #define SCU_MIXER_SDATA (P6_4) /* GPIO3[3] on P6_4 */ + #define SCU_MIXER_RESETX (P5_5) /* GPIO2[14] on P5_5 */ + + #define SCU_MIXER_SCLK_PINCFG (SCU_GPIO_FAST | SCU_CONF_FUNCTION4) + #define SCU_MIXER_SDATA_PINCFG (SCU_GPIO_FAST | SCU_CONF_FUNCTION0) +#endif +#ifdef PRALINE + #define SCU_MIXER_ENX (P5_4) /* GPIO2[13] on P5_4 */ + #define SCU_MIXER_SCLK (P9_5) /* GPIO5[18] on P9_5 */ + #define SCU_MIXER_SDATA (P9_2) /* GPIO4[14] on P9_2 */ + #define SCU_MIXER_RESETX (P5_5) /* GPIO2[14] on P5_5 */ + #define SCU_MIXER_LD (PD_11) /* GPIO6[25] on PD_11 */ + + #define SCU_MIXER_SCLK_PINCFG (SCU_GPIO_FAST | SCU_CONF_FUNCTION4) + #define SCU_MIXER_SDATA_PINCFG (SCU_GPIO_FAST | SCU_CONF_FUNCTION0) + #define SCU_MIXER_LD_PINCFG (SCU_GPIO_FAST | SCU_CONF_FUNCTION4) +#endif +#ifdef RAD1O + #define SCU_VCO_CE (P5_4) /* GPIO2[13] on P5_4 */ + #define SCU_VCO_SCLK (P2_6) /* GPIO5[6] on P2_6 */ + #define SCU_VCO_SDATA (P6_4) /* GPIO3[3] on P6_4 */ + #define SCU_VCO_LE (P5_5) /* GPIO2[14] on P5_5 */ + #define SCU_VCO_MUX (PB_5) /* GPIO5[25] on PB_5 */ + #define SCU_MIXER_EN (P6_8) /* GPIO5[16] on P6_8 */ + #define SCU_SYNT_RFOUT_EN (P6_9) /* GPIO3[5] on P6_9 */ +#endif + +/* RF LDO control */ +#ifdef JAWBREAKER + #define SCU_RF_LDO_ENABLE (P5_0) /* GPIO2[9] on P5_0 */ +#endif + +/* RF supply (VAA) control */ +#ifdef HACKRF_ONE + #define SCU_NO_VAA_ENABLE (P5_0) /* GPIO2[9] on P5_0 */ +#endif +#ifdef PRALINE + #define SCU_NO_VAA_ENABLE (P8_1) /* GPIO4[1] on P8_1 */ +#endif +#ifdef RAD1O + #define SCU_VAA_ENABLE (P5_0) /* GPIO2[9] on P5_0 */ +#endif + +/* SPI flash */ +#define SCU_SSP0_CIPO (P3_6) +#define SCU_SSP0_COPI (P3_7) +#define SCU_SSP0_SCK (P3_3) +#define SCU_SSP0_CS (P3_8) /* GPIO5[11] on P3_8 */ +#define SCU_FLASH_HOLD (P3_4) /* GPIO1[14] on P3_4 */ +#define SCU_FLASH_WP (P3_5) /* GPIO1[15] on P3_5 */ + +/* RF switch control */ +#ifdef HACKRF_ONE + #define SCU_HP (P4_0) /* GPIO2[0] on P4_0 */ + #define SCU_LP (P5_1) /* GPIO2[10] on P5_1 */ + #define SCU_TX_MIX_BP (P5_2) /* GPIO2[11] on P5_2 */ + #define SCU_NO_MIX_BYPASS (P1_7) /* GPIO1[0] on P1_7 */ + #define SCU_RX_MIX_BP (P5_3) /* GPIO2[12] on P5_3 */ + #define SCU_TX_AMP (P5_6) /* GPIO2[15] on P5_6 */ + #define SCU_TX (P6_7) /* GPIO5[15] on P6_7 */ + #define SCU_MIX_BYPASS (P6_8) /* GPIO5[16] on P6_8 */ + #define SCU_RX (P2_5) /* GPIO5[5] on P2_5 */ + #define SCU_NO_TX_AMP_PWR (P6_9) /* GPIO3[5] on P6_9 */ + #define SCU_AMP_BYPASS (P2_10) /* GPIO0[14] on P2_10 */ + #define SCU_RX_AMP (P2_11) /* GPIO1[11] on P2_11 */ + #define SCU_NO_RX_AMP_PWR (P2_12) /* GPIO1[12] on P2_12 */ +#endif +#ifdef RAD1O + #define SCU_BY_AMP (P1_7) /* GPIO1[0] on P1_7 */ + #define SCU_BY_AMP_N (P2_5) /* GPIO5[5] on P2_5 */ + #define SCU_TX_RX (P2_10) /* GPIO0[14] on P2_10 */ + #define SCU_TX_RX_N (P2_11) /* GPIO1[11] on P2_11 */ + #define SCU_BY_MIX (P2_12) /* GPIO1[12] on P2_12 */ + #define SCU_BY_MIX_N (P5_1) /* GPIO2[10] on P5_1 */ + #define SCU_LOW_HIGH_FILT (P5_2) /* GPIO2[11] on P5_2 */ + #define SCU_LOW_HIGH_FILT_N (P5_3) /* GPIO2[12] on P5_3 */ + #define SCU_TX_AMP (P5_6) /* GPIO2[15] on P5_6 */ + #define SCU_RX_LNA (P6_7) /* GPIO5[15] on P6_7 */ +#endif +#ifdef PRALINE + #define SCU_TX_EN (P6_5) /* GPIO3[4] on P6_5 */ + #define SCU_MIX_EN_N (P6_3) /* GPIO3[2] on P6_3 */ + #define SCU_MIX_EN_N_R1_0 (P2_6) /* GPIO5[6] on P2_6 */ + #define SCU_LPF_EN (PA_1) /* GPIO4[8] on PA_1 */ + #define SCU_RF_AMP_EN (PA_2) /* GPIO4[9] on PA_2 */ + #define SCU_ANT_BIAS_EN_N (P2_12) /* GPIO1[12] on P2_12 */ + #define SCU_ANT_BIAS_OC_N (P2_11) /* GPIO1[11] on P2_11 */ +#endif + +#ifdef PRALINE + #define SCU_P2_CTRL0 (PE_3) /* GPIO7[3] on PE_3 */ + #define SCU_P2_CTRL1 (PE_4) /* GPIO7[4] on PE_4 */ + #define SCU_P1_CTRL0 (P2_10) /* GPIO0[14] on P2_10 */ + #define SCU_P1_CTRL1 (P6_8) /* GPIO5[16] on P6_8 */ + #define SCU_P1_CTRL2 (P6_9) /* GPIO3[5] on P6_9 */ + #define SCU_CLKIN_CTRL (P1_20) /* GPIO0[15] on P1_20 */ + #define SCU_AA_EN (P1_14) /* GPIO1[7] on P1_14 */ + #define SCU_TRIGGER_IN (PD_12) /* GPIO6[26] on PD_12 */ + #define SCU_TRIGGER_OUT (P2_6) /* GPIO5[6] on P2_6 */ + #define SCU_PPS_OUT (P2_5) /* GPIO5[5] on P2_5 */ + + #define SCU_P2_CTRL0_PINCFG (SCU_GPIO_FAST | SCU_CONF_FUNCTION4) + #define SCU_P2_CTRL1_PINCFG (SCU_GPIO_FAST | SCU_CONF_FUNCTION4) + #define SCU_P1_CTRL0_PINCFG (SCU_GPIO_FAST | SCU_CONF_FUNCTION0) + #define SCU_P1_CTRL1_PINCFG (SCU_GPIO_FAST | SCU_CONF_FUNCTION4) + #define SCU_P1_CTRL2_PINCFG (SCU_GPIO_FAST | SCU_CONF_FUNCTION0) + #define SCU_CLKIN_CTRL_PINCFG (SCU_GPIO_FAST | SCU_CONF_FUNCTION0) + #define SCU_AA_EN_PINCFG (SCU_GPIO_FAST | SCU_CONF_FUNCTION0) + #define SCU_TRIGGER_IN_PINCFG (SCU_GPIO_FAST | SCU_CONF_FUNCTION4) + #define SCU_TRIGGER_OUT_PINCFG (SCU_GPIO_FAST | SCU_CONF_FUNCTION4) + #define SCU_PPS_OUT_PINCFG (SCU_GPIO_FAST | SCU_CONF_FUNCTION4) + +#endif + +#define SCU_PINMUX_PP_D0 (P7_0) /* GPIO3[8] */ +#define SCU_PINMUX_PP_D1 (P7_1) /* GPIO3[9] */ +#define SCU_PINMUX_PP_D2 (P7_2) /* GPIO3[10] */ +#define SCU_PINMUX_PP_D3 (P7_3) /* GPIO3[11] */ +#define SCU_PINMUX_PP_D4 (P7_4) /* GPIO3[12] */ +#define SCU_PINMUX_PP_D5 (P7_5) /* GPIO3[13] */ +#define SCU_PINMUX_PP_D6 (P7_6) /* GPIO3[14] */ +#define SCU_PINMUX_PP_D7 (P7_7) /* GPIO3[15] */ +/* TODO add other Pins */ +#define SCU_PINMUX_GPIO3_8 (P7_0) /* GPIO3[8] */ +#define SCU_PINMUX_GPIO3_9 (P7_1) /* GPIO3[9] */ +#define SCU_PINMUX_GPIO3_10 (P7_2) /* GPIO3[10] */ +#define SCU_PINMUX_GPIO3_11 (P7_3) /* GPIO3[11] */ +#define SCU_PINMUX_GPIO3_12 (P7_4) /* GPIO3[12] */ +#define SCU_PINMUX_GPIO3_13 (P7_5) /* GPIO3[13] */ +#define SCU_PINMUX_GPIO3_14 (P7_6) /* GPIO3[14] */ +#define SCU_PINMUX_GPIO3_15 (P7_7) /* GPIO3[15] */ + +#define SCU_PINMUX_PP_TDO (P1_5) /* GPIO1[8] */ +#define SCU_PINMUX_SD_POW (P1_5) /* GPIO1[8] */ +#define SCU_PINMUX_SD_CMD (P1_6) /* GPIO1[9] */ +#define SCU_PINMUX_PP_TMS (P1_8) /* GPIO1[1] */ +#define SCU_PINMUX_SD_VOLT0 (P1_8) /* GPIO1[1] */ +#define SCU_PINMUX_SD_DAT0 (P1_9) /* GPIO1[2] */ +#define SCU_PINMUX_SD_DAT1 (P1_10) /* GPIO1[3] */ +#define SCU_PINMUX_SD_DAT2 (P1_11) /* GPIO1[4] */ +#define SCU_PINMUX_SD_DAT3 (P1_12) /* GPIO1[5] */ +#define SCU_PINMUX_SD_CD (P1_13) /* GPIO1[6] */ + +#define SCU_PINMUX_PP_IO_STBX (P2_0) /* GPIO5[0] */ +#define SCU_PINMUX_PP_ADDR (P2_1) /* GPIO5[1] */ +#define SCU_PINMUX_U0_TXD (P2_0) /* GPIO5[0] */ +#define SCU_PINMUX_U0_RXD (P2_1) /* GPIO5[1] */ + +#define SCU_PINMUX_ISP (P2_7) /* GPIO0[7] */ + +#define SCU_PINMUX_GP_CLKIN (P4_7) + +/* HackRF One r9 */ +#define SCU_H1R9_CLKIN_EN (P6_7) /* GPIO5[15] on P6_7 */ +#define SCU_H1R9_CLKOUT_EN (P1_2) /* GPIO0[9] on P1_2 (has boot pull-down) */ +#define SCU_H1R9_MCU_CLK_EN (P1_1) /* GPIO0[8] on P1_1 (has boot pull-up) */ +#define SCU_H1R9_RX (P2_7) /* GPIO0[7] on P4_4 (has boot pull-up) */ +#define SCU_H1R9_NO_ANT_PWR (P4_4) /* GPIO2[4] on P4_4 */ +#define SCU_H1R9_EN1V8 (P5_0) /* GPIO2[9] on P5_0 */ +#define SCU_H1R9_NO_VAA_EN (P6_10) /* GPIO3[6] on P6_10 */ +#define SCU_H1R9_TRIGGER_EN (P2_5) /* GPIO5[5] on P2_5 */ + +void delay(uint32_t duration); +void delay_us_at_mhz(uint32_t us, uint32_t mhz); + +/* TODO: Hide these configurations */ +extern si5351c_driver_t clock_gen; +extern const ssp_config_t ssp_config_w25q80bv; +extern const ssp_config_t ssp_config_max283x; +extern const ssp_config_t ssp_config_max5864; + +#ifndef PRALINE +extern max283x_driver_t max283x; +#else +extern max2831_driver_t max283x; +extern ice40_spi_driver_t ice40; +extern fpga_driver_t fpga; + +#endif +extern max5864_driver_t max5864; +extern mixer_driver_t mixer; +extern w25q80bv_driver_t spi_flash; +extern sgpio_config_t sgpio_config; +extern radio_t radio; +extern rf_path_t rf_path; +extern jtag_t jtag_cpld; +extern i2c_bus_t i2c0; + +void cpu_clock_init(void); +void clock_gen_init(void); +void clock_gen_shutdown(void); +void ssp1_set_mode_max283x(void); +void ssp1_set_mode_max5864(void); +#ifdef PRALINE +void ssp1_set_mode_max2831(void); +void ssp1_set_mode_ice40(void); +#endif + +void pin_shutdown(void); +void pin_setup(void); + +#ifdef PRALINE +void enable_1v2_power(void); +void disable_1v2_power(void); +void enable_3v3aux_power(void); +void disable_3v3aux_power(void); +#else +void enable_1v8_power(void); +void disable_1v8_power(void); +#endif + +bool sample_rate_frac_set(uint32_t rate_num, uint32_t rate_denom); +bool sample_rate_set(const uint32_t sampling_rate_hz); + +clock_source_t activate_best_clock_source(void); + +#if (defined HACKRF_ONE || defined RAD1O || defined PRALINE) +void enable_rf_power(void); +void disable_rf_power(void); +#endif + +typedef enum { + LED1 = 0, + LED2 = 1, + LED3 = 2, + LED4 = 3, +} led_t; + +void led_on(const led_t led); +void led_off(const led_t led); +void led_toggle(const led_t led); +void set_leds(const uint8_t state); + +void trigger_enable(const bool enable); + +void halt_and_flash(const uint32_t duration); + +#ifdef PRALINE +typedef enum { + P1_SIGNAL_TRIGGER_IN = 0, + P1_SIGNAL_AUX_CLK1 = 1, + P1_SIGNAL_CLKIN = 2, + P1_SIGNAL_TRIGGER_OUT = 3, + P1_SIGNAL_P22_CLKIN = 4, + P1_SIGNAL_P2_5 = 5, + P1_SIGNAL_NC = 6, + P1_SIGNAL_AUX_CLK2 = 7, +} p1_ctrl_signal_t; + +typedef enum { + P2_SIGNAL_CLK3 = 0, + P2_SIGNAL_TRIGGER_IN = 2, + P2_SIGNAL_TRIGGER_OUT = 3, +} p2_ctrl_signal_t; + +typedef enum { + CLKIN_SIGNAL_P1 = 0, + CLKIN_SIGNAL_P22 = 1, +} clkin_signal_t; + +void p1_ctrl_set(const p1_ctrl_signal_t signal); +void p2_ctrl_set(const p2_ctrl_signal_t signal); +void narrowband_filter_set(const uint8_t value); +void clkin_ctrl_set(const clkin_signal_t value); +void pps_out_set(const uint8_t value); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __HACKRF_CORE_H */ diff --git a/firmware/common/hackrf_ui.c b/firmware/common/hackrf_ui.c index ac243890..ac7f1c18 100644 --- a/firmware/common/hackrf_ui.c +++ b/firmware/common/hackrf_ui.c @@ -20,16 +20,12 @@ * Boston, MA 02110-1301, USA. */ -#include - #include "hackrf_ui.h" -#include "transceiver_mode.h" -#ifdef IS_EXPANSION_COMPATIBLE - #include "ui_portapack.h" -#endif -#ifdef IS_RAD1O - #include "ui_rad1o.h" -#endif + +#include "ui_portapack.h" +#include "ui_rad1o.h" + +#include #define UNUSED(x) (void) (x) @@ -82,18 +78,14 @@ const hackrf_ui_t* hackrf_ui(void) { /* Detect on first use. If no UI hardware is detected, use a stub function table. */ if (ui == NULL && ui_enabled) { -#ifdef IS_EXPANSION_COMPATIBLE - if (IS_EXPANSION_COMPATIBLE) { - if (portapack_hackrf_ui_init) { - ui = portapack_hackrf_ui_init(); - } +#if (defined HACKRF_ONE || defined PRALINE) + if (portapack_hackrf_ui_init) { + ui = portapack_hackrf_ui_init(); } #endif -#ifdef IS_RAD1O - if (IS_RAD1O) { - if (rad1o_ui_setup) { - ui = rad1o_ui_setup(); - } +#ifdef RAD1O + if (rad1o_ui_setup) { + ui = rad1o_ui_setup(); } #endif } diff --git a/firmware/common/hackrf_ui.h b/firmware/common/hackrf_ui.h index 7b7d67e4..cc9a6fa6 100644 --- a/firmware/common/hackrf_ui.h +++ b/firmware/common/hackrf_ui.h @@ -20,15 +20,12 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef HACKRF_UI_H +#define HACKRF_UI_H -#include +#include #include -#include "clock_gen.h" -#include "rf_path.h" -#include "transceiver_mode.h" - typedef void (*hackrf_ui_init_fn)(void); typedef void (*hackrf_ui_deinit_fn)(void); typedef void (*hackrf_ui_set_frequency_fn)(uint64_t frequency); @@ -71,3 +68,5 @@ typedef struct { */ const hackrf_ui_t* hackrf_ui(void); void hackrf_ui_set_enable(bool); + +#endif diff --git a/firmware/common/i2c_bus.h b/firmware/common/i2c_bus.h index 7519ba14..7eb745c7 100644 --- a/firmware/common/i2c_bus.h +++ b/firmware/common/i2c_bus.h @@ -20,23 +20,27 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __I2C_BUS_H__ +#define __I2C_BUS_H__ -#include #include +#include -typedef struct _i2c_bus_t { +struct i2c_bus_t; +typedef struct i2c_bus_t i2c_bus_t; + +struct i2c_bus_t { void* const obj; - void (*start)(struct _i2c_bus_t* const bus, const void* const config); - void (*stop)(struct _i2c_bus_t* const bus); + void (*start)(i2c_bus_t* const bus, const void* const config); + void (*stop)(i2c_bus_t* const bus); void (*transfer)( - struct _i2c_bus_t* const bus, + i2c_bus_t* const bus, const uint_fast8_t peripheral_address, const uint8_t* const tx, const size_t tx_count, uint8_t* const rx, const size_t rx_count); -} i2c_bus_t; +}; void i2c_bus_start(i2c_bus_t* const bus, const void* const config); void i2c_bus_stop(i2c_bus_t* const bus); @@ -47,3 +51,5 @@ void i2c_bus_transfer( const size_t tx_count, uint8_t* const rx, const size_t rx_count); + +#endif /*__I2C_BUS_H__*/ diff --git a/firmware/common/i2c_lpc.c b/firmware/common/i2c_lpc.c index 2c0fc5e2..05631f05 100644 --- a/firmware/common/i2c_lpc.c +++ b/firmware/common/i2c_lpc.c @@ -23,28 +23,6 @@ #include "i2c_lpc.h" #include -#include - -#include "cpu_clock.h" - -/* Driver instances. */ -i2c_bus_t i2c0 = { - .obj = (void*) I2C0_BASE, - .start = i2c_lpc_start, - .stop = i2c_lpc_stop, - .transfer = i2c_lpc_transfer, -}; - -i2c_bus_t i2c1 = { - .obj = (void*) I2C1_BASE, - .start = i2c_lpc_start, - .stop = i2c_lpc_stop, - .transfer = i2c_lpc_transfer, -}; - -const i2c_lpc_config_t i2c_config_fast_clock = { - .clock_khz = 400, -}; /* FIXME return i2c0 status from each function */ @@ -53,9 +31,7 @@ void i2c_lpc_start(i2c_bus_t* const bus, const void* const _config) const i2c_lpc_config_t* const config = _config; const uint32_t port = (uint32_t) bus->obj; - const uint16_t duty_cycle_count = - (cpu_clock_mhz * (2000 / config->clock_khz)) / 4; - i2c_init(port, duty_cycle_count); + i2c_init(port, config->duty_cycle_count); } void i2c_lpc_stop(i2c_bus_t* const bus) diff --git a/firmware/common/i2c_lpc.h b/firmware/common/i2c_lpc.h index 2a2562ee..db57282f 100644 --- a/firmware/common/i2c_lpc.h +++ b/firmware/common/i2c_lpc.h @@ -20,16 +20,17 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __I2C_LPC_H__ +#define __I2C_LPC_H__ -#include -#include #include +#include +#include #include "i2c_bus.h" -typedef struct { - const uint16_t clock_khz; +typedef struct i2c_lpc_config_t { + const uint16_t duty_cycle_count; } i2c_lpc_config_t; void i2c_lpc_start(i2c_bus_t* const bus, const void* const config); @@ -43,7 +44,4 @@ void i2c_lpc_transfer( const size_t count_rx); bool i2c_probe(i2c_bus_t* const bus, const uint_fast8_t device_address); -/* Driver instances. */ -extern const i2c_lpc_config_t i2c_config_fast_clock; -extern i2c_bus_t i2c0; -extern i2c_bus_t i2c1; +#endif /*__I2C_LPC_H__*/ diff --git a/firmware/common/ice40_spi.c b/firmware/common/ice40_spi.c index 6c078941..d3ac713c 100644 --- a/firmware/common/ice40_spi.c +++ b/firmware/common/ice40_spi.c @@ -21,44 +21,18 @@ #include "ice40_spi.h" -#include #include -#include - -#include "delay.h" -#include "platform_gpio.h" -#include "platform_scu.h" - -/* Driver instance. */ -ssp_config_t ssp_config_ice40_fpga = { - .data_bits = SSP_DATA_8BITS, - .spi_mode = SSP_CPOL_1_CPHA_1, - .serial_clock_rate = 21, - .clock_prescale_rate = 2, -}; - -ice40_spi_driver_t ice40 = { - .bus = &spi_bus_ssp1, -}; +#include "hackrf_core.h" void ice40_spi_target_init(ice40_spi_driver_t* const drv) { - const platform_gpio_t* gpio = platform_gpio(); - const platform_scu_t* scu = platform_scu(); - - /* Configure drivers and driver pins */ - ssp_config_ice40_fpga.gpio_select = gpio->fpga_cfg_spi_cs; - ice40.gpio_select = gpio->fpga_cfg_spi_cs; - ice40.gpio_creset = gpio->fpga_cfg_creset; - ice40.gpio_cdone = gpio->fpga_cfg_cdone; - /* Configure SSP1 Peripheral and relevant FPGA pins. */ - scu_pinmux(scu->SSP1_CIPO, (SCU_SSP_IO | SCU_CONF_FUNCTION5)); - scu_pinmux(scu->SSP1_COPI, (SCU_SSP_IO | SCU_CONF_FUNCTION5)); - scu_pinmux(scu->SSP1_SCK, (SCU_SSP_IO | SCU_CONF_FUNCTION1)); - scu_pinmux(scu->PINMUX_FPGA_CRESET, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0); - scu_pinmux(scu->PINMUX_FPGA_CDONE, SCU_GPIO_PUP | SCU_CONF_FUNCTION4); - scu_pinmux(scu->PINMUX_FPGA_SPI_CS, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0); + scu_pinmux(SCU_SSP1_CIPO, (SCU_SSP_IO | SCU_CONF_FUNCTION5)); + scu_pinmux(SCU_SSP1_COPI, (SCU_SSP_IO | SCU_CONF_FUNCTION5)); + scu_pinmux(SCU_SSP1_SCK, (SCU_SSP_IO | SCU_CONF_FUNCTION1)); + scu_pinmux(SCU_PINMUX_FPGA_CRESET, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0); + scu_pinmux(SCU_PINMUX_FPGA_CDONE, SCU_GPIO_PUP | SCU_CONF_FUNCTION4); + scu_pinmux(SCU_PINMUX_FPGA_SPI_CS, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0); /* Configure GPIOs as inputs or outputs as needed. */ gpio_clear(drv->gpio_creset); @@ -70,27 +44,27 @@ void ice40_spi_target_init(ice40_spi_driver_t* const drv) uint8_t ice40_spi_read(ice40_spi_driver_t* const drv, uint8_t r) { uint8_t value[3] = {r & 0x7F, 0, 0}; - spi_bus_transfer(drv->bus, &ssp_config_ice40_fpga, value, 3); + spi_bus_transfer(drv->bus, value, 3); return value[2]; } void ice40_spi_write(ice40_spi_driver_t* const drv, uint8_t r, uint16_t v) { uint8_t value[3] = {(r & 0x7F) | 0x80, v, 0}; - spi_bus_transfer(drv->bus, &ssp_config_ice40_fpga, value, 3); + spi_bus_transfer(drv->bus, value, 3); } -static void spi_ssp1_wait_for_tx_fifo_not_full(void) +static void spi_ssp1_wait_for_tx_fifo_not_full() { while ((SSP_SR(SSP1_BASE) & SSP_SR_TNF) == 0) {} } -static void spi_ssp1_wait_for_rx_fifo_not_empty(void) +static void spi_ssp1_wait_for_rx_fifo_not_empty() { while ((SSP_SR(SSP1_BASE) & SSP_SR_RNE) == 0) {} } -static void spi_ssp1_wait_for_not_busy(void) +static void spi_ssp1_wait_for_not_busy() { while (SSP_SR(SSP1_BASE) & SSP_SR_BSY) {} } @@ -106,25 +80,22 @@ static uint32_t spi_ssp1_transfer_word(const uint32_t data) bool ice40_spi_syscfg_program( ice40_spi_driver_t* const drv, - uint8_t* buf, - size_t (*read_block_cb)(void* ctx), + size_t (*read_block_cb)(void* ctx, uint8_t* buffer), void* read_ctx) { - spi_bus_start(drv->bus, &ssp_config_ice40_fpga); - // Drive CRESET_B = 0, SPI_SS = 0, SPI_SCK = 1. gpio_clear(drv->gpio_creset); gpio_clear(drv->gpio_select); // Wait a minimum of 200 ns. - delay_us(1); + delay_us_at_mhz(1, 204 / 4); // 250 ns. // Release CRESET_B or drive CRESET_B = 1. gpio_set(drv->gpio_creset); // Wait a minimum of 1200 μs to clear internal configuration memory. // Testing showed us that we need to wait longer. Let's wait 1800 μs. - delay_us(1800); + delay_us_at_mhz(1800, 204); // Set SPI_SS = 1, Send 8 dummy clocks. gpio_set(drv->gpio_select); @@ -132,13 +103,14 @@ bool ice40_spi_syscfg_program( // Send configuration image serially on SPI_SI to iCE40, most-significant bit // first, on falling edge of SPI_SCK. + uint8_t out_buffer[4096] = {0}; gpio_clear(drv->gpio_select); for (;;) { - size_t read_sz = read_block_cb(read_ctx); + size_t read_sz = read_block_cb(read_ctx, out_buffer); if (read_sz == 0) break; for (size_t j = 0; j < read_sz; j++) { - spi_ssp1_transfer_word(buf[j]); + spi_ssp1_transfer_word(out_buffer[j]); } } diff --git a/firmware/common/ice40_spi.h b/firmware/common/ice40_spi.h index 331814aa..93c5adc6 100644 --- a/firmware/common/ice40_spi.h +++ b/firmware/common/ice40_spi.h @@ -19,32 +19,30 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __ICE40_SPI_H +#define __ICE40_SPI_H -#include #include #include - #include "gpio.h" #include "spi_bus.h" -#include "spi_ssp.h" -typedef struct { +struct ice40_spi_driver_t; +typedef struct ice40_spi_driver_t ice40_spi_driver_t; + +struct ice40_spi_driver_t { spi_bus_t* const bus; gpio_t gpio_select; gpio_t gpio_creset; gpio_t gpio_cdone; -} ice40_spi_driver_t; +}; void ice40_spi_target_init(ice40_spi_driver_t* const drv); uint8_t ice40_spi_read(ice40_spi_driver_t* const drv, uint8_t r); void ice40_spi_write(ice40_spi_driver_t* const drv, uint8_t r, uint16_t v); bool ice40_spi_syscfg_program( ice40_spi_driver_t* const drv, - uint8_t* buf, - size_t (*read_block_cb)(void* ctx), + size_t (*read_block_cb)(void* ctx, uint8_t* buffer), void* read_ctx); -/* Driver instance. */ -extern ssp_config_t ssp_config_ice40_fpga; -extern ice40_spi_driver_t ice40; +#endif // __ICE40_SPI_H diff --git a/firmware/common/leds.c b/firmware/common/leds.c deleted file mode 100644 index e1fd507b..00000000 --- a/firmware/common/leds.c +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright 2026 Great Scott Gadgets - * - * This file is part of HackRF. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#include "leds.h" - -#include - -#include "delay.h" -#include "gpio.h" -#include "platform_detect.h" -#include "platform_gpio.h" - -void led_on(const led_t led) -{ -#ifdef IS_PRALINE - if (IS_PRALINE) { - gpio_clear(platform_gpio()->led[led]); - } -#endif -#ifdef IS_NOT_PRALINE - if (IS_NOT_PRALINE) { - gpio_set(platform_gpio()->led[led]); - } -#endif -} - -void led_off(const led_t led) -{ -#ifdef IS_PRALINE - if (IS_PRALINE) { - gpio_set(platform_gpio()->led[led]); - } -#endif -#ifdef IS_NOT_PRALINE - if (IS_NOT_PRALINE) { - gpio_clear(platform_gpio()->led[led]); - } -#endif -} - -void led_toggle(const led_t led) -{ - gpio_toggle(platform_gpio()->led[led]); -} - -void set_leds(const uint8_t state) -{ - int num_leds = 3; -#ifdef IS_FOUR_LEDS - if (IS_FOUR_LEDS) { - num_leds = 4; - } -#endif - - for (int i = 0; i < num_leds; i++) { -#ifdef IS_PRALINE - if (IS_PRALINE) { - gpio_write(platform_gpio()->led[i], ((state >> i) & 1) == 0); - } -#endif -#ifdef IS_NOT_PRALINE - if (IS_NOT_PRALINE) { - gpio_write(platform_gpio()->led[i], ((state >> i) & 1) == 1); - } -#endif - } -} - -void halt_and_flash(const uint32_t period_ms) -{ - /* blink LED1, LED2, and LED3 */ - while (1) { - led_on(LED1); - led_on(LED2); - led_on(LED3); - delay_ms(period_ms / 2); - led_off(LED1); - led_off(LED2); - led_off(LED3); - delay_ms(period_ms / 2); - } -} diff --git a/firmware/common/locking.h b/firmware/common/locking.h index 54ba7a70..5620f2f9 100644 --- a/firmware/common/locking.h +++ b/firmware/common/locking.h @@ -19,7 +19,8 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __LOCKING_H__ +#define __LOCKING_H__ #include @@ -50,3 +51,5 @@ static inline uint32_t store_exclusive(uint32_t val, volatile uint32_t* addr) return 0; } #endif + +#endif /* __LOCKING_H__ */ diff --git a/firmware/common/lz4_blk.h b/firmware/common/lz4_blk.h index f4e25f7a..19c8207e 100644 --- a/firmware/common/lz4_blk.h +++ b/firmware/common/lz4_blk.h @@ -19,9 +19,12 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __LZ4_BLK_H +#define __LZ4_BLK_H #include #include int lz4_blk_decompress(const uint8_t* src, uint8_t* dst, size_t length); + +#endif \ No newline at end of file diff --git a/firmware/common/lz4_buf.h b/firmware/common/lz4_buf.h deleted file mode 100644 index ab073d43..00000000 --- a/firmware/common/lz4_buf.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2026 Great Scott Gadgets - * - * This file is part of HackRF. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#pragma once - -#include - -#define LZ4_BUFFER_SIZE 0x1000 - -/* Addresses of these buffers are set in linker script. If you change the name - * of these buffers, you must also adjust the linker script. */ - -extern uint8_t lz4_in_buf[LZ4_BUFFER_SIZE]; -extern uint8_t lz4_out_buf[LZ4_BUFFER_SIZE]; diff --git a/firmware/common/m0_sleep.c b/firmware/common/m0_sleep.c index 09067bc6..722c6f10 100644 --- a/firmware/common/m0_sleep.c +++ b/firmware/common/m0_sleep.c @@ -20,7 +20,7 @@ * Boston, MA 02110-1301, USA. */ -int main(void) +int main() { while (1) {} } diff --git a/firmware/common/m0_state.c b/firmware/common/m0_state.c index cfb74295..83af28d0 100644 --- a/firmware/common/m0_state.c +++ b/firmware/common/m0_state.c @@ -20,8 +20,8 @@ */ #include "m0_state.h" - #include +#include void m0_set_mode(enum m0_mode mode) { diff --git a/firmware/common/m0_state.h b/firmware/common/m0_state.h index b7c26e8b..cd0391fc 100644 --- a/firmware/common/m0_state.h +++ b/firmware/common/m0_state.h @@ -19,7 +19,8 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __M0_STATE_H__ +#define __M0_STATE_H__ #include @@ -59,3 +60,5 @@ enum m0_error { extern volatile struct m0_state m0_state; void m0_set_mode(enum m0_mode mode); + +#endif /*__M0_STATE_H__*/ diff --git a/firmware/common/max2831.c b/firmware/common/max2831.c index 08e59a59..6f641f54 100644 --- a/firmware/common/max2831.c +++ b/firmware/common/max2831.c @@ -1,5 +1,5 @@ /* - * Copyright 2025-2026 Great Scott Gadgets + * Copyright 2025 Great Scott Gadgets * * This file is part of HackRF. * @@ -27,18 +27,14 @@ * pirate commands to do the same thing. */ -#include "max2831.h" - -#include #include #include -#include "fixed_point.h" +#include "max2831.h" #include "max2831_regs.def" // private register def macros #include "selftest.h" #include "adc.h" #define MIN(x, y) ((x) < (y) ? (x) : (y)) -#define MAX(x, y) ((x) > (y) ? (x) : (y)) /* Default register values. */ static const uint16_t max2831_regs_default[MAX2831_NUM_REGS] = { @@ -109,7 +105,7 @@ static void max2831_write(max2831_driver_t* const drv, uint8_t r, uint16_t v) { uint32_t word = (((uint32_t) v & 0x3fff) << 4) | (r & 0xf); uint16_t values[2] = {word >> 9, word & 0x1ff}; - spi_bus_transfer(drv->bus, drv->config, values, 2); + spi_bus_transfer(drv->bus, values, 2); } uint16_t max2831_reg_read(max2831_driver_t* const drv, uint8_t r) @@ -154,7 +150,7 @@ void max2831_set_mode(max2831_driver_t* const drv, const max2831_mode_t new_mode } drv->set_mode(drv, new_mode); - max2831_set_lpf_bandwidth(drv, new_mode, drv->desired_lpf_bw); + max2831_set_lpf_bandwidth(drv, drv->desired_lpf_bw); } max2831_mode_t max2831_mode(max2831_driver_t* const drv) @@ -226,40 +222,36 @@ void max2831_stop(max2831_driver_t* const drv) max2831_set_mode(drv, MAX2831_MODE_SHUTDOWN); } -/* Assume 40 MHz reference clock with R divider of 2. */ -#define PFD_FREQ_HZ (20ULL * (1000ULL * 1000ULL)) - -#define MIN_FREQ FP_MHZ(2000) -#define MAX_FREQ FP_MHZ(3000) - -fp_40_24_t max2831_set_frequency( - max2831_driver_t* const drv, - fp_40_24_t freq, - bool program) +void max2831_set_frequency(max2831_driver_t* const drv, uint32_t freq) { - uint64_t div; + uint32_t div_frac; + uint32_t div_int; + uint32_t div_rem; + uint32_t div_cmp; + int i; - freq = MIN(freq, MAX_FREQ); - freq = MAX(freq, MIN_FREQ); - - freq += ((PFD_FREQ_HZ * FP_ONE_HZ) >> 21); /* round to nearest frequency */ - div = freq / PFD_FREQ_HZ; - - /* - * Shift from 40.24 fixed-point to 44.20 to match 20-bit fractional - * divider. - */ - div = div >> 4; - - if (program) { - //set_MAX2831_SYN_REF_DIV(drv, MAX2831_SYN_REF_DIV_2); - set_MAX2831_SYN_INT(drv, (div >> 20) & 0xff); - set_MAX2831_SYN_FRAC_HI(drv, (div >> 6) & 0x3fff); - set_MAX2831_SYN_FRAC_LO(drv, div & 0x3f); - max2831_regs_commit(drv); + /* ASSUME 40MHz PLL. Ratio = F*R/40,000,000. */ + /* TODO: fixed to R=2. Check if it's worth exploring R=1. */ + freq += (20000000 >> 21); /* round to nearest frequency */ + div_int = freq / 20000000; + div_rem = freq % 20000000; + div_frac = 0; + div_cmp = 20000000; + for (i = 0; i < 20; i++) { + div_frac <<= 1; + div_rem <<= 1; + if (div_rem >= div_cmp) { + div_frac |= 0x1; + div_rem -= div_cmp; + } } - return PFD_FREQ_HZ * (div << 4); + /* Write order matters? */ + //set_MAX2831_SYN_REF_DIV(drv, MAX2831_SYN_REF_DIV_2); + set_MAX2831_SYN_INT(drv, div_int); + set_MAX2831_SYN_FRAC_HI(drv, (div_frac >> 6) & 0x3fff); + set_MAX2831_SYN_FRAC_LO(drv, div_frac & 0x3f); + max2831_regs_commit(drv); } typedef struct { @@ -312,13 +304,13 @@ static const max2831_ft_fine_t max2831_tx_ft_fine[] = { //clang-format on -uint32_t max2831_set_lpf_bandwidth(max2831_driver_t* const drv, const max2831_mode_t mode, const uint32_t bandwidth_hz) { +uint32_t max2831_set_lpf_bandwidth(max2831_driver_t* const drv, const uint32_t bandwidth_hz) { const max2831_ft_t* coarse; const max2831_ft_fine_t* fine; drv->desired_lpf_bw = bandwidth_hz; - if (mode == MAX2831_MODE_RX) { + if (drv->mode == MAX2831_MODE_RX) { coarse = max2831_rx_ft; fine = max2831_rx_ft_fine; } else { @@ -351,7 +343,7 @@ uint32_t max2831_set_lpf_bandwidth(max2831_driver_t* const drv, const max2831_mo /* Program found settings. */ set_MAX2831_LPF_COARSE(drv, coarse->ft); - if (mode == MAX2831_MODE_RX) { + if (drv->mode == MAX2831_MODE_RX) { set_MAX2831_RX_LPF_FINE_ADJ(drv, f->ft_fine); } else { set_MAX2831_TX_LPF_FINE_ADJ(drv, f->ft_fine); diff --git a/firmware/common/max2831.h b/firmware/common/max2831.h index f1a28c54..033b590e 100644 --- a/firmware/common/max2831.h +++ b/firmware/common/max2831.h @@ -1,5 +1,5 @@ /* - * Copyright 2025-2026 Great Scott Gadgets + * Copyright 2025 Great Scott Gadgets * * This file is part of HackRF. * @@ -19,12 +19,12 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __MAX2831_H +#define __MAX2831_H -#include #include +#include -#include "fixed_point.h" #include "gpio.h" #include "spi_bus.h" @@ -37,8 +37,8 @@ typedef enum { MAX2831_MODE_STANDBY, MAX2831_MODE_TX, MAX2831_MODE_RX, - MAX2831_MODE_RX_CALIBRATION, MAX2831_MODE_TX_CALIBRATION, + MAX2831_MODE_RX_CALIBRATION, } max2831_mode_t; typedef enum { @@ -48,22 +48,22 @@ typedef enum { MAX2831_RX_HPF_600_KHZ = 3, } max2831_rx_hpf_freq_t; -typedef struct _max2831_driver_t { +struct max2831_driver_t; +typedef struct max2831_driver_t max2831_driver_t; + +struct max2831_driver_t { spi_bus_t* bus; - void* config; gpio_t gpio_enable; gpio_t gpio_rxtx; gpio_t gpio_rxhp; gpio_t gpio_ld; - void (*target_init)(struct _max2831_driver_t* const drv); - void (*set_mode)( - struct _max2831_driver_t* const drv, - const max2831_mode_t new_mode); + void (*target_init)(max2831_driver_t* const drv); + void (*set_mode)(max2831_driver_t* const drv, const max2831_mode_t new_mode); max2831_mode_t mode; uint16_t regs[MAX2831_NUM_REGS]; uint16_t regs_dirty; uint32_t desired_lpf_bw; -} max2831_driver_t; +}; /* Initialize chip. */ extern void max2831_setup(max2831_driver_t* const drv); @@ -88,14 +88,11 @@ void max2831_set_mode(max2831_driver_t* const drv, const max2831_mode_t new_mode extern void max2831_start(max2831_driver_t* const drv); extern void max2831_stop(max2831_driver_t* const drv); -/* Set frequency in 1/(2**24) Hz */ -extern fp_40_24_t max2831_set_frequency( - max2831_driver_t* const drv, - fp_40_24_t freq, - bool program); +/* Set frequency in Hz. Frequency setting is a multi-step function + * where order of register writes matters. */ +extern void max2831_set_frequency(max2831_driver_t* const drv, uint32_t freq); uint32_t max2831_set_lpf_bandwidth( max2831_driver_t* const drv, - const max2831_mode_t mode, const uint32_t bandwidth_hz); bool max2831_set_lna_gain(max2831_driver_t* const drv, const uint32_t gain_db); bool max2831_set_vga_gain(max2831_driver_t* const drv, const uint32_t gain_db); @@ -110,3 +107,5 @@ extern void max2831_tx(max2831_driver_t* const drv); extern void max2831_rx(max2831_driver_t* const drv); extern void max2831_tx_calibration(max2831_driver_t* const drv); extern void max2831_rx_calibration(max2831_driver_t* const drv); + +#endif // __MAX2831_H diff --git a/firmware/common/max2831_regs.def b/firmware/common/max2831_regs.def index fd09707d..fb8fa8a9 100644 --- a/firmware/common/max2831_regs.def +++ b/firmware/common/max2831_regs.def @@ -1,27 +1,7 @@ -/* -*- mode: c -*- - * - * Copyright 2012 Michael Ossmann - * Copyright 2025-2026 Great Scott Gadgets - * - * This file is part of HackRF. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ +/* -*- mode: c -*- */ -#pragma once +#ifndef __MAX2831_REGS_DEF +#define __MAX2831_REGS_DEF /* Generate static inline accessors that operate on the global * regs. Done this way to (1) allow defs to be scraped out and used @@ -148,3 +128,5 @@ __MREG__(MAX2831_RXIQ_VCM,15,10,2) // RX I/Q output common mode #define MAX2831_RXIQ_VCM_1_2 1 // 1.2V #define MAX2831_RXIQ_VCM_1_3 2 // 1.3V #define MAX2831_RXIQ_VCM_1_45 3 // 1.45V + +#endif // __MAX2831_REGS_DEF \ No newline at end of file diff --git a/firmware/common/max2831_target.c b/firmware/common/max2831_target.c index 21c8a16d..757ebae0 100644 --- a/firmware/common/max2831_target.c +++ b/firmware/common/max2831_target.c @@ -22,19 +22,15 @@ #include "max2831_target.h" #include - -#include "gpio.h" -#include "platform_scu.h" +#include "hackrf_core.h" void max2831_target_init(max2831_driver_t* const drv) { - const platform_scu_t* scu = platform_scu(); - /* Configure SSP1 Peripheral (to be moved later in SSP driver) */ - scu_pinmux(scu->SSP1_COPI, (SCU_SSP_IO | SCU_CONF_FUNCTION5)); - scu_pinmux(scu->SSP1_SCK, (SCU_SSP_IO | SCU_CONF_FUNCTION1)); + scu_pinmux(SCU_SSP1_COPI, (SCU_SSP_IO | SCU_CONF_FUNCTION5)); + scu_pinmux(SCU_SSP1_SCK, (SCU_SSP_IO | SCU_CONF_FUNCTION1)); - scu_pinmux(scu->XCVR_CS, scu->XCVR_CS_PINCFG); + scu_pinmux(SCU_XCVR_CS, SCU_XCVR_CS_PINCFG); /* * Configure XCVR_CTL GPIO pins. @@ -43,10 +39,10 @@ void max2831_target_init(max2831_driver_t* const drv) * MAX2837 which had a separate TXENABLE. On MAX2831 a single RXTX pin * switches between RX (high) and TX (low) modes. */ - scu_pinmux(scu->XCVR_ENABLE, scu->XCVR_ENABLE_PINCFG); - scu_pinmux(scu->XCVR_RXENABLE, scu->XCVR_RXENABLE_PINCFG); - scu_pinmux(scu->XCVR_RXHP, scu->XCVR_RXHP_PINCFG); - scu_pinmux(scu->XCVR_LD, scu->XCVR_LD_PINCFG); + scu_pinmux(SCU_XCVR_ENABLE, SCU_XCVR_ENABLE_PINCFG); + scu_pinmux(SCU_XCVR_RXENABLE, SCU_XCVR_RXENABLE_PINCFG); + scu_pinmux(SCU_XCVR_RXHP, SCU_XCVR_RXHP_PINCFG); + scu_pinmux(SCU_XCVR_LD, SCU_XCVR_LD_PINCFG); /* Set GPIO pins as outputs. */ gpio_output(drv->gpio_enable); diff --git a/firmware/common/max2831_target.h b/firmware/common/max2831_target.h index 072faf22..11671b73 100644 --- a/firmware/common/max2831_target.h +++ b/firmware/common/max2831_target.h @@ -19,9 +19,12 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __MAX2831_TARGET_H +#define __MAX2831_TARGET_H #include "max2831.h" void max2831_target_init(max2831_driver_t* const drv); void max2831_target_set_mode(max2831_driver_t* const drv, const max2831_mode_t new_mode); + +#endif // __MAX2831_TARGET_H diff --git a/firmware/common/max2837.c b/firmware/common/max2837.c index f512c6af..a3e91498 100644 --- a/firmware/common/max2837.c +++ b/firmware/common/max2837.c @@ -1,5 +1,5 @@ /* - * Copyright 2012-2026 Great Scott Gadgets + * Copyright 2012-2022 Great Scott Gadgets * Copyright 2012 Will Code * Copyright 2014 Jared Boone * @@ -29,18 +29,12 @@ * pirate commands to do the same thing. */ -#include "max2837.h" - -#include #include #include -#include "fixed_point.h" +#include "max2837.h" #include "max2837_regs.def" // private register def macros #include "selftest.h" -#define MIN(x, y) ((x) < (y) ? (x) : (y)) -#define MAX(x, y) ((x) > (y) ? (x) : (y)) - /* Default register values. */ static const uint16_t max2837_regs_default[MAX2837_NUM_REGS] = { 0x150, /* 0 */ @@ -156,14 +150,14 @@ void max2837_setup(max2837_driver_t* const drv) static uint16_t max2837_read(max2837_driver_t* const drv, uint8_t r) { uint16_t value = (1 << 15) | (r << 10); - spi_bus_transfer(drv->bus, drv->config, &value, 1); + spi_bus_transfer(drv->bus, &value, 1); return value & 0x3ff; } static void max2837_write(max2837_driver_t* const drv, uint8_t r, uint16_t v) { uint16_t value = (r << 10) | (v & 0x3ff); - spi_bus_transfer(drv->bus, drv->config, &value, 1); + spi_bus_transfer(drv->bus, &value, 1); } uint16_t max2837_reg_read(max2837_driver_t* const drv, uint8_t r) @@ -234,32 +228,24 @@ void max2837_stop(max2837_driver_t* const drv) max2837_set_mode(drv, MAX2837_MODE_SHUTDOWN); } -/* Assume 40 MHz reference clock with R divider of 1. */ -#define PFD_FREQ_HZ (40ULL * (1000ULL * 1000ULL)) - -#define MIN_FREQ FP_MHZ(2000) -#define MAX_FREQ FP_MHZ(3000) - -fp_40_24_t max2837_set_frequency( - max2837_driver_t* const drv, - fp_40_24_t freq, - bool program) +void max2837_set_frequency(max2837_driver_t* const drv, uint32_t freq) { uint8_t band; uint8_t lna_band; - uint64_t div; - - freq = MIN(freq, MAX_FREQ); - freq = MAX(freq, MIN_FREQ); + uint32_t div_frac; + uint32_t div_int; + uint32_t div_rem; + uint32_t div_cmp; + int i; /* Select band. Allow tuning outside specified bands. */ - if (freq < FP_MHZ(2400)) { + if (freq < 2400000000U) { band = MAX2837_LOGEN_BSW_2_3; lna_band = MAX2837_LNAband_2_4; - } else if (freq < FP_MHZ(2500)) { + } else if (freq < 2500000000U) { band = MAX2837_LOGEN_BSW_2_4; lna_band = MAX2837_LNAband_2_4; - } else if (freq < FP_MHZ(2600)) { + } else if (freq < 2600000000U) { band = MAX2837_LOGEN_BSW_2_5; lna_band = MAX2837_LNAband_2_6; } else { @@ -267,34 +253,35 @@ fp_40_24_t max2837_set_frequency( lna_band = MAX2837_LNAband_2_6; } - fp_40_24_t vco = (freq * 4) / 3; - - vco += ((PFD_FREQ_HZ * FP_ONE_HZ) >> 21); /* round to nearest frequency */ - div = vco / PFD_FREQ_HZ; - - /* - * Shift from 40.24 fixed-point to 44.20 to match 20-bit fractional - * divider. - */ - div = div >> 4; - - if (program) { - /* Band settings */ - set_MAX2837_LOGEN_BSW(drv, band); - set_MAX2837_LNAband(drv, lna_band); - - /* - * Write order matters here, so commit INT and FRAC_HI before - * committing FRAC_LO, which is the trigger for VCO auto-select. - */ - set_MAX2837_SYN_INT(drv, (div >> 20) & 0xff); - set_MAX2837_SYN_FRAC_HI(drv, (div >> 10) & 0x3ff); - max2837_regs_commit(drv); - set_MAX2837_SYN_FRAC_LO(drv, div & 0x3ff); - max2837_regs_commit(drv); + /* ASSUME 40MHz PLL. Ratio = F*(4/3)/40,000,000 = F/30,000,000 */ + freq += (30000000 >> 21); /* round to nearest frequency */ + div_int = freq / 30000000; + div_rem = freq % 30000000; + div_frac = 0; + div_cmp = 30000000; + for (i = 0; i < 20; i++) { + div_frac <<= 1; + div_rem <<= 1; + if (div_rem >= div_cmp) { + div_frac |= 0x1; + div_rem -= div_cmp; + } } - return ((PFD_FREQ_HZ * 3) / 4) * (div << 4); + /* Band settings */ + set_MAX2837_LOGEN_BSW(drv, band); + set_MAX2837_LNAband(drv, lna_band); + + /* Write order matters here, so commit INT and FRAC_HI before + * committing FRAC_LO, which is the trigger for VCO + * auto-select. TODO - it's cleaner this way, but it would be + * faster to explicitly commit the registers explicitly so the + * dirty bits aren't scanned twice. */ + set_MAX2837_SYN_INT(drv, div_int); + set_MAX2837_SYN_FRAC_HI(drv, (div_frac >> 10) & 0x3ff); + max2837_regs_commit(drv); + set_MAX2837_SYN_FRAC_LO(drv, div_frac & 0x3ff); + max2837_regs_commit(drv); } typedef struct { diff --git a/firmware/common/max2837.h b/firmware/common/max2837.h index a33179ac..5f0b0024 100644 --- a/firmware/common/max2837.h +++ b/firmware/common/max2837.h @@ -1,5 +1,5 @@ /* - * Copyright 2012-2026 Great Scott Gadgets + * Copyright 2012-2022 Great Scott Gadgets * Copyright 2012 Will Code * Copyright 2014 Jared Boone * @@ -21,12 +21,12 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __MAX2837_H +#define __MAX2837_H -#include #include +#include -#include "fixed_point.h" #include "gpio.h" #include "spi_bus.h" @@ -41,20 +41,20 @@ typedef enum { MAX2837_MODE_RX } max2837_mode_t; -typedef struct _max2837_driver_t { +struct max2837_driver_t; +typedef struct max2837_driver_t max2837_driver_t; + +struct max2837_driver_t { spi_bus_t* bus; - void* config; gpio_t gpio_enable; gpio_t gpio_rx_enable; gpio_t gpio_tx_enable; - void (*target_init)(struct _max2837_driver_t* const drv); - void (*set_mode)( - struct _max2837_driver_t* const drv, - const max2837_mode_t new_mode); + void (*target_init)(max2837_driver_t* const drv); + void (*set_mode)(max2837_driver_t* const drv, const max2837_mode_t new_mode); max2837_mode_t mode; uint16_t regs[MAX2837_NUM_REGS]; uint32_t regs_dirty; -} max2837_driver_t; +}; /* Initialize chip. */ extern void max2837_setup(max2837_driver_t* const drv); @@ -79,11 +79,9 @@ void max2837_set_mode(max2837_driver_t* const drv, const max2837_mode_t new_mode extern void max2837_start(max2837_driver_t* const drv); extern void max2837_stop(max2837_driver_t* const drv); -/* Set frequency in 1/(2**24) Hz. */ -extern fp_40_24_t max2837_set_frequency( - max2837_driver_t* const drv, - fp_40_24_t freq, - bool program); +/* Set frequency in Hz. Frequency setting is a multi-step function + * where order of register writes matters. */ +extern void max2837_set_frequency(max2837_driver_t* const drv, uint32_t freq); uint32_t max2837_set_lpf_bandwidth( max2837_driver_t* const drv, const uint32_t bandwidth_hz); @@ -93,3 +91,5 @@ bool max2837_set_txvga_gain(max2837_driver_t* const drv, const uint32_t gain_db) extern void max2837_tx(max2837_driver_t* const drv); extern void max2837_rx(max2837_driver_t* const drv); + +#endif // __MAX2837_H diff --git a/firmware/common/max2837_regs.def b/firmware/common/max2837_regs.def index 67eb6dd7..0aa2f9e5 100644 --- a/firmware/common/max2837_regs.def +++ b/firmware/common/max2837_regs.def @@ -1,26 +1,7 @@ -/* -*- mode: c -*- * - * Copyright 2012 Michael Ossmann - * Copyright 2025-2026 Great Scott Gadgets - * - * This file is part of HackRF. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ +/* -*- mode: c -*- */ -#pragma once +#ifndef __MAX2837_REGS_DEF +#define __MAX2837_REGS_DEF /* Generate static inline accessors that operate on the global * regs. Done this way to (1) allow defs to be scraped out and used @@ -423,3 +404,5 @@ __MREG__(MAX2837_FUSE_RTH,30,9,1) // 0 -> 992/0uA correction, 15 -> 0/992uA correction ... if TX_DCCORR_SPI_EN __MREG__(MAX2837_TX_DCCORR_I,31,4,5) __MREG__(MAX2837_TX_DCCORR_Q,31,9,5) + +#endif // __MAX2837_REGS_DEF diff --git a/firmware/common/max2837_target.c b/firmware/common/max2837_target.c index 6446a48c..dc8f69c1 100644 --- a/firmware/common/max2837_target.c +++ b/firmware/common/max2837_target.c @@ -24,25 +24,21 @@ #include "max2837_target.h" #include - -#include "gpio.h" -#include "platform_scu.h" +#include "hackrf_core.h" void max2837_target_init(max2837_driver_t* const drv) { - const platform_scu_t* scu = platform_scu(); - /* Configure SSP1 Peripheral (to be moved later in SSP driver) */ - scu_pinmux(scu->SSP1_CIPO, (SCU_SSP_IO | SCU_CONF_FUNCTION5)); - scu_pinmux(scu->SSP1_COPI, (SCU_SSP_IO | SCU_CONF_FUNCTION5)); - scu_pinmux(scu->SSP1_SCK, (SCU_SSP_IO | SCU_CONF_FUNCTION1)); + scu_pinmux(SCU_SSP1_CIPO, (SCU_SSP_IO | SCU_CONF_FUNCTION5)); + scu_pinmux(SCU_SSP1_COPI, (SCU_SSP_IO | SCU_CONF_FUNCTION5)); + scu_pinmux(SCU_SSP1_SCK, (SCU_SSP_IO | SCU_CONF_FUNCTION1)); - scu_pinmux(scu->XCVR_CS, scu->XCVR_CS_PINCFG); + scu_pinmux(SCU_XCVR_CS, SCU_XCVR_CS_PINCFG); /* Configure XCVR_CTL GPIO pins. */ - scu_pinmux(scu->XCVR_ENABLE, scu->XCVR_ENABLE_PINCFG); - scu_pinmux(scu->XCVR_RXENABLE, scu->XCVR_RXENABLE_PINCFG); - scu_pinmux(scu->XCVR_TXENABLE, scu->XCVR_TXENABLE_PINCFG); + scu_pinmux(SCU_XCVR_ENABLE, SCU_XCVR_ENABLE_PINCFG); + scu_pinmux(SCU_XCVR_RXENABLE, SCU_XCVR_RXENABLE_PINCFG); + scu_pinmux(SCU_XCVR_TXENABLE, SCU_XCVR_TXENABLE_PINCFG); /* Set GPIO pins as outputs. */ gpio_output(drv->gpio_enable); diff --git a/firmware/common/max2837_target.h b/firmware/common/max2837_target.h index 2910791e..75d87698 100644 --- a/firmware/common/max2837_target.h +++ b/firmware/common/max2837_target.h @@ -21,9 +21,12 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __MAX2837_TARGET_H +#define __MAX2837_TARGET_H #include "max2837.h" void max2837_target_init(max2837_driver_t* const drv); void max2837_target_set_mode(max2837_driver_t* const drv, const max2837_mode_t new_mode); + +#endif // __MAX2837_TARGET_H diff --git a/firmware/common/max2839.c b/firmware/common/max2839.c index a938b733..62c5561f 100644 --- a/firmware/common/max2839.c +++ b/firmware/common/max2839.c @@ -1,5 +1,5 @@ /* - * Copyright 2012-2026 Great Scott Gadgets + * Copyright 2012-2022 Great Scott Gadgets * Copyright 2012 Will Code * Copyright 2014 Jared Boone * @@ -29,18 +29,12 @@ * pirate commands to do the same thing. */ -#include "max2839.h" - -#include #include #include -#include "fixed_point.h" +#include "max2839.h" #include "max2839_regs.def" // private register def macros #include "selftest.h" -#define MIN(x, y) ((x) < (y) ? (x) : (y)) -#define MAX(x, y) ((x) > (y) ? (x) : (y)) - static uint8_t requested_lna_gain = 0; static uint8_t requested_vga_gain = 0; @@ -164,14 +158,14 @@ void max2839_setup(max2839_driver_t* const drv) static uint16_t max2839_read(max2839_driver_t* const drv, uint8_t r) { uint16_t value = (1 << 15) | (r << 10); - spi_bus_transfer(drv->bus, drv->config, &value, 1); + spi_bus_transfer(drv->bus, &value, 1); return value & 0x3ff; } static void max2839_write(max2839_driver_t* const drv, uint8_t r, uint16_t v) { uint16_t value = (r << 10) | (v & 0x3ff); - spi_bus_transfer(drv->bus, drv->config, &value, 1); + spi_bus_transfer(drv->bus, &value, 1); } uint16_t max2839_reg_read(max2839_driver_t* const drv, uint8_t r) @@ -245,61 +239,54 @@ void max2839_stop(max2839_driver_t* const drv) max2839_set_mode(drv, MAX2839_MODE_SHUTDOWN); } -/* Assume 40 MHz reference clock with R divider of 1. */ -#define PFD_FREQ_HZ (40ULL * (1000ULL * 1000ULL)) - -#define MIN_FREQ FP_MHZ(2000) -#define MAX_FREQ FP_MHZ(3000) - -fp_40_24_t max2839_set_frequency( - max2839_driver_t* const drv, - fp_40_24_t freq, - bool program) +void max2839_set_frequency(max2839_driver_t* const drv, uint32_t freq) { uint8_t band; - uint64_t div; - - freq = MIN(freq, MAX_FREQ); - freq = MAX(freq, MIN_FREQ); + uint32_t div_frac; + uint32_t div_int; + uint32_t div_rem; + uint32_t div_cmp; + int i; /* Select band. Allow tuning outside specified bands. */ - if (freq < FP_MHZ(2400)) { + if (freq < 2400000000U) { band = MAX2839_LOGEN_BSW_2_3; - } else if (freq < FP_MHZ(2500)) { + } else if (freq < 2500000000U) { band = MAX2839_LOGEN_BSW_2_4; - } else if (freq < FP_MHZ(2600)) { + } else if (freq < 2600000000U) { band = MAX2839_LOGEN_BSW_2_5; } else { band = MAX2839_LOGEN_BSW_2_6; } - fp_40_24_t vco = (freq * 4) / 3; - - vco += ((PFD_FREQ_HZ * FP_ONE_HZ) >> 21); /* round to nearest frequency */ - div = vco / PFD_FREQ_HZ; - - /* - * Shift from 40.24 fixed-point to 44.20 to match 20-bit fractional - * divider. - */ - div = div >> 4; - - if (program) { - /* Band settings */ - set_MAX2839_LOGEN_BSW(drv, band); - - /* - * Write order matters here, so commit INT and FRAC_HI before - * committing FRAC_LO, which is the trigger for VCO auto-select. - */ - set_MAX2839_SYN_INT(drv, (div >> 20) & 0xff); - set_MAX2839_SYN_FRAC_HI(drv, (div >> 10) & 0x3ff); - max2839_regs_commit(drv); - set_MAX2839_SYN_FRAC_LO(drv, div & 0x3ff); - max2839_regs_commit(drv); + /* ASSUME 40MHz PLL. Ratio = F*(4/3)/40,000,000 = F/30,000,000 */ + freq += (30000000 >> 21); /* round to nearest frequency */ + div_int = freq / 30000000; + div_rem = freq % 30000000; + div_frac = 0; + div_cmp = 30000000; + for (i = 0; i < 20; i++) { + div_frac <<= 1; + div_rem <<= 1; + if (div_rem >= div_cmp) { + div_frac |= 0x1; + div_rem -= div_cmp; + } } - return ((PFD_FREQ_HZ * 3) / 4) * (div << 4); + /* Band settings */ + set_MAX2839_LOGEN_BSW(drv, band); + + /* Write order matters here, so commit INT and FRAC_HI before + * committing FRAC_LO, which is the trigger for VCO + * auto-select. TODO - it's cleaner this way, but it would be + * faster to explicitly commit the registers explicitly so the + * dirty bits aren't scanned twice. */ + set_MAX2839_SYN_INT(drv, div_int); + set_MAX2839_SYN_FRAC_HI(drv, (div_frac >> 10) & 0x3ff); + max2839_regs_commit(drv); + set_MAX2839_SYN_FRAC_LO(drv, div_frac & 0x3ff); + max2839_regs_commit(drv); } typedef struct { diff --git a/firmware/common/max2839.h b/firmware/common/max2839.h index 6430ce37..fbffa5b1 100644 --- a/firmware/common/max2839.h +++ b/firmware/common/max2839.h @@ -1,5 +1,5 @@ /* - * Copyright 2012-2026 Great Scott Gadgets + * Copyright 2012-2022 Great Scott Gadgets * Copyright 2012 Will Code * Copyright 2014 Jared Boone * @@ -21,12 +21,12 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __MAX2839_H +#define __MAX2839_H -#include #include +#include -#include "fixed_point.h" #include "gpio.h" #include "spi_bus.h" @@ -44,19 +44,19 @@ typedef enum { MAX2839_MODE_CLKOUT, } max2839_mode_t; -typedef struct _max2839_driver_t { +struct max2839_driver_t; +typedef struct max2839_driver_t max2839_driver_t; + +struct max2839_driver_t { spi_bus_t* bus; - void* config; gpio_t gpio_enable; gpio_t gpio_rxtx; - void (*target_init)(struct _max2839_driver_t* const drv); - void (*set_mode)( - struct _max2839_driver_t* const drv, - const max2839_mode_t new_mode); + void (*target_init)(max2839_driver_t* const drv); + void (*set_mode)(max2839_driver_t* const drv, const max2839_mode_t new_mode); max2839_mode_t mode; uint16_t regs[MAX2839_NUM_REGS]; uint32_t regs_dirty; -} max2839_driver_t; +}; /* Initialize chip. */ extern void max2839_setup(max2839_driver_t* const drv); @@ -81,11 +81,9 @@ void max2839_set_mode(max2839_driver_t* const drv, const max2839_mode_t new_mode extern void max2839_start(max2839_driver_t* const drv); extern void max2839_stop(max2839_driver_t* const drv); -/* Set frequency in 1/(2**24) Hz. */ -extern fp_40_24_t max2839_set_frequency( - max2839_driver_t* const drv, - fp_40_24_t freq, - bool program); +/* Set frequency in Hz. Frequency setting is a multi-step function + * where order of register writes matters. */ +extern void max2839_set_frequency(max2839_driver_t* const drv, uint32_t freq); uint32_t max2839_set_lpf_bandwidth( max2839_driver_t* const drv, const uint32_t bandwidth_hz); @@ -95,3 +93,5 @@ bool max2839_set_txvga_gain(max2839_driver_t* const drv, const uint32_t gain_db) extern void max2839_tx(max2839_driver_t* const drv); extern void max2839_rx(max2839_driver_t* const drv); + +#endif // __MAX2839_H diff --git a/firmware/common/max2839_regs.def b/firmware/common/max2839_regs.def index 11b1d80d..bee66846 100644 --- a/firmware/common/max2839_regs.def +++ b/firmware/common/max2839_regs.def @@ -1,26 +1,7 @@ -/* -*- mode: c -*- * - * Copyright 2012 Michael Ossmann - * Copyright 2025-2026 Great Scott Gadgets - * - * This file is part of HackRF. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ +/* -*- mode: c -*- */ -#pragma once +#ifndef __MAX2839_REGS_DEF +#define __MAX2839_REGS_DEF /* Generate static inline accessors that operate on the global * regs. Done this way to (1) allow defs to be scraped out and used @@ -274,3 +255,5 @@ __MREG__(MAX2839_PA_DAC_Voltage_Mode_Output_Select,30,9,1) __MREG__(MAX2839_TX_DC_Offset_Correction_QChannel,31,5,6) __MREG__(MAX2839_RESERVED_31_8,31,8,3) __MREG__(MAX2839_PA_DAC_Clk_Divide_Ratio,31,9,1) + +#endif // __MAX2839_REGS_DEF diff --git a/firmware/common/max2839_target.c b/firmware/common/max2839_target.c index 3932bb7a..356313e9 100644 --- a/firmware/common/max2839_target.c +++ b/firmware/common/max2839_target.c @@ -24,20 +24,16 @@ #include "max2839_target.h" #include - -#include "gpio.h" -#include "platform_scu.h" +#include "hackrf_core.h" void max2839_target_init(max2839_driver_t* const drv) { - const platform_scu_t* scu = platform_scu(); - /* Configure SSP1 Peripheral (to be moved later in SSP driver) */ - scu_pinmux(scu->SSP1_CIPO, (SCU_SSP_IO | SCU_CONF_FUNCTION5)); - scu_pinmux(scu->SSP1_COPI, (SCU_SSP_IO | SCU_CONF_FUNCTION5)); - scu_pinmux(scu->SSP1_SCK, (SCU_SSP_IO | SCU_CONF_FUNCTION1)); + scu_pinmux(SCU_SSP1_CIPO, (SCU_SSP_IO | SCU_CONF_FUNCTION5)); + scu_pinmux(SCU_SSP1_COPI, (SCU_SSP_IO | SCU_CONF_FUNCTION5)); + scu_pinmux(SCU_SSP1_SCK, (SCU_SSP_IO | SCU_CONF_FUNCTION1)); - scu_pinmux(scu->XCVR_CS, SCU_GPIO_FAST); + scu_pinmux(SCU_XCVR_CS, SCU_GPIO_FAST); /* * Configure XCVR_CTL GPIO pins. @@ -46,8 +42,8 @@ void max2839_target_init(max2839_driver_t* const drv) * MAX2837 which had a separate TXENABLE. On MAX2839 a single RXTX pin * switches between RX (high) and TX (low) modes. */ - scu_pinmux(scu->XCVR_ENABLE, SCU_GPIO_FAST); - scu_pinmux(scu->XCVR_RXENABLE, SCU_GPIO_FAST); + scu_pinmux(SCU_XCVR_ENABLE, SCU_GPIO_FAST); + scu_pinmux(SCU_XCVR_RXENABLE, SCU_GPIO_FAST); /* Set GPIO pins as outputs. */ gpio_output(drv->gpio_enable); diff --git a/firmware/common/max2839_target.h b/firmware/common/max2839_target.h index 0c21e98d..89488243 100644 --- a/firmware/common/max2839_target.h +++ b/firmware/common/max2839_target.h @@ -21,7 +21,12 @@ * Boston, MA 02110-1301, USA. */ +#ifndef __MAX2839_TARGET_H +#define __MAX2839_TARGET_H + #include "max2839.h" void max2839_target_init(max2839_driver_t* const drv); void max2839_target_set_mode(max2839_driver_t* const drv, const max2839_mode_t new_mode); + +#endif // __MAX2839_TARGET_H diff --git a/firmware/common/max283x.c b/firmware/common/max283x.c index f9486921..5d291804 100644 --- a/firmware/common/max283x.c +++ b/firmware/common/max283x.c @@ -1,5 +1,5 @@ /* - * Copyright 2012-2026 Great Scott Gadgets + * Copyright 2012-2022 Great Scott Gadgets * Copyright 2012 Will Code * Copyright 2014 Jared Boone * @@ -23,201 +23,89 @@ #include "max283x.h" -#include -#include +#include "gpio.h" +#include "gpio_lpc.h" +#include "max2837.h" +#include "max2837_target.h" +#include "max2839.h" +#include "max2839_target.h" +#include "spi_bus.h" -#include - -#include "fixed_point.h" -#include "platform_detect.h" -#include "platform_gpio.h" - -#ifdef IS_PRALINE - #include "max2831_target.h" -#endif -#ifdef IS_NOT_PRALINE - #include "max2837_target.h" -#endif -#ifdef IS_H1_R9 - #include "max2839_target.h" +extern spi_bus_t spi_bus_ssp1; +#ifdef PRALINE +static struct gpio_t gpio_max2837_enable = GPIO(6, 29); +static struct gpio_t gpio_max2837_rx_enable = GPIO(3, 3); +static struct gpio_t gpio_max2837_tx_enable = GPIO(3, 2); +#else +static struct gpio_t gpio_max2837_enable = GPIO(2, 6); +static struct gpio_t gpio_max2837_rx_enable = GPIO(2, 5); +static struct gpio_t gpio_max2837_tx_enable = GPIO(2, 4); #endif -/* Driver instance. */ -ssp_config_t ssp_config_max283x = { - /* FIXME speed up once everything is working reliably */ - /* - // Freq About 0.0498MHz / 49.8KHz => Freq = PCLK / (CPSDVSR * [SCR+1]) with PCLK=PLL1=204MHz - const uint8_t serial_clock_rate = 32; - const uint8_t clock_prescale_rate = 128; - */ - // Freq About 4.857MHz => Freq = PCLK / (CPSDVSR * [SCR+1]) with PCLK=PLL1=204MHz - .serial_clock_rate = 21, - .clock_prescale_rate = 2, -}; - -max283x_driver_t max283x = {}; - -#ifdef IS_PRALINE -max2831_driver_t max2831 = { - .bus = &spi_bus_ssp1, - .config = &ssp_config_max283x, - .target_init = max2831_target_init, - .set_mode = max2831_target_set_mode, -}; -#endif - -#ifdef IS_NOT_PRALINE max2837_driver_t max2837 = { .bus = &spi_bus_ssp1, - .config = &ssp_config_max283x, + .gpio_enable = &gpio_max2837_enable, + .gpio_rx_enable = &gpio_max2837_rx_enable, + .gpio_tx_enable = &gpio_max2837_tx_enable, .target_init = max2837_target_init, .set_mode = max2837_target_set_mode, }; -#endif -#ifdef IS_HACKRF_ONE max2839_driver_t max2839 = { .bus = &spi_bus_ssp1, - .config = &ssp_config_max283x, + .gpio_enable = &gpio_max2837_enable, + .gpio_rxtx = &gpio_max2837_rx_enable, .target_init = max2839_target_init, .set_mode = max2839_target_set_mode, }; -#endif /* Initialize chip. */ -void max283x_setup(max283x_driver_t* const drv) +void max283x_setup(max283x_driver_t* const drv, max283x_variant_t type) { - const platform_gpio_t* gpio = platform_gpio(); + drv->type = type; + switch (type) { + case MAX2837_VARIANT: + memcpy(&drv->drv.max2837, &max2837, sizeof(max2837)); + max2837_setup(&drv->drv.max2837); + break; - /* MAX283x GPIO PinMux */ - ssp_config_max283x.gpio_select = gpio->max283x_select; -#ifdef IS_PRALINE - if (IS_PRALINE) { - ssp_config_max283x.data_bits = SSP_DATA_9BITS; - drv->type = MAX2831_VARIANT; - max2831.gpio_enable = gpio->max283x_enable; - max2831.gpio_rxtx = gpio->max283x_rx_enable; - max2831.gpio_rxhp = gpio->max2831_rxhp; - max2831.gpio_ld = gpio->max2831_ld; - memcpy(&drv->drv.max2831, &max2831, sizeof(max2831)); - max2831_setup(&drv->drv.max2831); + case MAX2839_VARIANT: + memcpy(&drv->drv.max2839, &max2839, sizeof(max2839)); + max2839_setup(&drv->drv.max2839); + break; } -#endif -#ifdef IS_NOT_PRALINE - if (IS_NOT_PRALINE) { - ssp_config_max283x.data_bits = SSP_DATA_16BITS; - #ifdef IS_H1_R9 - if (IS_H1_R9) { - drv->type = MAX2839_VARIANT; - max2839.gpio_enable = gpio->max283x_enable; - max2839.gpio_rxtx = gpio->max283x_rx_enable; - memcpy(&drv->drv.max2839, &max2839, sizeof(max2839)); - max2839_setup(&drv->drv.max2839); - } - #endif - #ifdef IS_NOT_H1_R9 - if (IS_NOT_H1_R9) { - drv->type = MAX2837_VARIANT; - max2837.gpio_enable = gpio->max283x_enable; - max2837.gpio_rx_enable = gpio->max283x_rx_enable; - max2837.gpio_tx_enable = gpio->max283x_tx_enable; - memcpy(&drv->drv.max2837, &max2837, sizeof(max2837)); - max2837_setup(&drv->drv.max2837); - } - #endif - } -#endif -} - -/* Macros to simplify dispatch of variant-specific operations. */ - -/* clang-format off */ - -#if UNIVERSAL - // UNIVERSAL: all variants - #define DISPATCH(_drv, _max2831, _max2837, _max2839) \ - if (_drv->type == MAX2831_VARIANT) { \ - _max2831; \ - } else if (_drv->type == MAX2837_VARIANT) { \ - _max2837; \ - } else { \ - _max2839; \ - } -#elif HACKRF_ONE - // HACKRF_ONE: MAX2837 and MAX2839 only - #define DISPATCH(_drv, _max2831, _max2837, _max2839) \ - if (_drv->type == MAX2837_VARIANT) { \ - _max2837; \ - } else { \ - _max2839; \ - } -#elif PRALINE - // PRALINE: MAX2831 only - #define DISPATCH(_drv, _max2831, _max2837, _max2839) \ - (void) drv; \ - _max2831 -#else - // JAWBREAKER, RAD1O: MAX2837 only - #define DISPATCH(_drv, _max2831, _max2837, _max2839) \ - (void) drv; \ - _max2837 -#endif - -#define CALL(_drv, _func, ...) \ - DISPATCH(drv, \ - max2831_ ## _func(&_drv->drv.max2831, ##__VA_ARGS__), \ - max2837_ ## _func(&_drv->drv.max2837, ##__VA_ARGS__), \ - max2839_ ## _func(&_drv->drv.max2839, ##__VA_ARGS__) \ - ); \ - -#define RESULT(_drv, _type, _func, ...) ({ \ - _type _result; \ - DISPATCH(drv, \ - _result = max2831_ ## _func(&_drv->drv.max2831, ##__VA_ARGS__), \ - _result = max2837_ ## _func(&_drv->drv.max2837, ##__VA_ARGS__), \ - _result = max2839_ ## _func(&_drv->drv.max2839, ##__VA_ARGS__) \ - ); \ - _result; \ -}) - -#define CONSTANT(_drv, _type, _name) ({\ - _type value; \ - DISPATCH(drv, \ - value = MAX2831_ ## _name, \ - value = MAX2837_ ## _name, \ - value = MAX2839_ ## _name \ - ); \ - value; \ -}) - -#define PRALINE_ONLY(_drv, _max2831) DISPATCH(_drv, _max2831, , ) - -/* clang-format on */ - -/* Returns the number of registers supported by the driver. */ -uint16_t max283x_num_regs(max283x_driver_t* const drv) -{ - return CONSTANT(drv, uint16_t, NUM_REGS); -} - -/* Returns the maximum data register value supported by the driver. */ -uint16_t max283x_data_regs_max_value(max283x_driver_t* const drv) -{ - return CONSTANT(drv, uint16_t, DATA_REGS_MAX_VALUE); } /* Read a register via SPI. Save a copy to memory and return * value. Mark clean. */ uint16_t max283x_reg_read(max283x_driver_t* const drv, uint8_t r) { - return RESULT(drv, uint16_t, reg_read, r); + switch (drv->type) { + case MAX2837_VARIANT: + return max2837_reg_read(&drv->drv.max2837, r); + break; + + case MAX2839_VARIANT: + return max2839_reg_read(&drv->drv.max2839, r); + break; + } + + return 0; } /* Write value to register via SPI and save a copy to memory. Mark * clean. */ void max283x_reg_write(max283x_driver_t* const drv, uint8_t r, uint16_t v) { - CALL(drv, reg_write, r, v); + switch (drv->type) { + case MAX2837_VARIANT: + max2837_reg_write(&drv->drv.max2837, r, v); + break; + + case MAX2839_VARIANT: + max2839_reg_write(&drv->drv.max2839, r, v); + break; + } } /* Write all dirty registers via SPI from memory. Mark all clean. Some @@ -225,107 +113,174 @@ void max283x_reg_write(max283x_driver_t* const drv, uint8_t r, uint16_t v) * provided routines for those operations. */ void max283x_regs_commit(max283x_driver_t* const drv) { - CALL(drv, regs_commit); + switch (drv->type) { + case MAX2837_VARIANT: + max2837_regs_commit(&drv->drv.max2837); + break; + + case MAX2839_VARIANT: + max2839_regs_commit(&drv->drv.max2839); + break; + } } void max283x_set_mode(max283x_driver_t* const drv, const max283x_mode_t new_mode) { - DISPATCH( - drv, - max2831_set_mode(&drv->drv.max2831, (max2831_mode_t) new_mode), - max2837_set_mode(&drv->drv.max2837, (max2837_mode_t) new_mode), - max2839_set_mode(&drv->drv.max2839, (max2839_mode_t) new_mode)); + switch (drv->type) { + case MAX2837_VARIANT: + max2837_set_mode(&drv->drv.max2837, (max2837_mode_t) new_mode); + break; + + case MAX2839_VARIANT: + max2839_set_mode(&drv->drv.max2839, (max2839_mode_t) new_mode); + break; + } } max283x_mode_t max283x_mode(max283x_driver_t* const drv) { - DISPATCH( - drv, - return (max283x_mode_t) max2831_mode(&drv->drv.max2831), - return (max283x_mode_t) max2837_mode(&drv->drv.max2837), - return (max283x_mode_t) max2839_mode(&drv->drv.max2839)); + switch (drv->type) { + case MAX2837_VARIANT: + return (max283x_mode_t) max2837_mode(&drv->drv.max2837); + break; + + case MAX2839_VARIANT: + return (max283x_mode_t) max2839_mode(&drv->drv.max2839); + break; + } + + return 0; } +//max283x_mode_t max283x_mode(max283x_driver_t* const drv); +//void max283x_set_mode(max283x_driver_t* const drv, const max283x_mode_t new_mode); + /* Turn on/off all chip functions. Does not control oscillator and CLKOUT */ void max283x_start(max283x_driver_t* const drv) { - CALL(drv, start); + switch (drv->type) { + case MAX2837_VARIANT: + max2837_start(&drv->drv.max2837); + break; + + case MAX2839_VARIANT: + max2839_start(&drv->drv.max2839); + break; + } } void max283x_stop(max283x_driver_t* const drv) { - CALL(drv, stop); + switch (drv->type) { + case MAX2837_VARIANT: + max2837_stop(&drv->drv.max2837); + break; + + case MAX2839_VARIANT: + max2839_stop(&drv->drv.max2839); + break; + } } -/* Set frequency in 1/(2**24) Hz. */ -fp_40_24_t max283x_set_frequency( - max283x_driver_t* const drv, - fp_40_24_t freq, - bool program) +/* Set frequency in Hz. Frequency setting is a multi-step function + * where order of register writes matters. */ +void max283x_set_frequency(max283x_driver_t* const drv, uint32_t freq) { - return RESULT(drv, fp_40_24_t, set_frequency, freq, program); + switch (drv->type) { + case MAX2837_VARIANT: + max2837_set_frequency(&drv->drv.max2837, freq); + break; + + case MAX2839_VARIANT: + max2839_set_frequency(&drv->drv.max2839, freq); + break; + } } uint32_t max283x_set_lpf_bandwidth( max283x_driver_t* const drv, - const max283x_mode_t mode, const uint32_t bandwidth_hz) { - (void) mode; - DISPATCH( - drv, - return max2831_set_lpf_bandwidth( - &drv->drv.max2831, - (max2831_mode_t) mode, - bandwidth_hz), - return max2837_set_lpf_bandwidth(&drv->drv.max2837, bandwidth_hz), - return max2839_set_lpf_bandwidth(&drv->drv.max2839, bandwidth_hz)); + switch (drv->type) { + case MAX2837_VARIANT: + return max2837_set_lpf_bandwidth(&drv->drv.max2837, bandwidth_hz); + break; + + case MAX2839_VARIANT: + return max2839_set_lpf_bandwidth(&drv->drv.max2839, bandwidth_hz); + break; + } + + return 0; } bool max283x_set_lna_gain(max283x_driver_t* const drv, const uint32_t gain_db) { - return RESULT(drv, bool, set_lna_gain, gain_db); + switch (drv->type) { + case MAX2837_VARIANT: + return max2837_set_lna_gain(&drv->drv.max2837, gain_db); + break; + + case MAX2839_VARIANT: + return max2839_set_lna_gain(&drv->drv.max2839, gain_db); + break; + } + + return false; } bool max283x_set_vga_gain(max283x_driver_t* const drv, const uint32_t gain_db) { - return RESULT(drv, bool, set_vga_gain, gain_db); + switch (drv->type) { + case MAX2837_VARIANT: + return max2837_set_vga_gain(&drv->drv.max2837, gain_db); + break; + + case MAX2839_VARIANT: + return max2839_set_vga_gain(&drv->drv.max2839, gain_db); + break; + } + + return false; } bool max283x_set_txvga_gain(max283x_driver_t* const drv, const uint32_t gain_db) { - return RESULT(drv, bool, set_txvga_gain, gain_db); + switch (drv->type) { + case MAX2837_VARIANT: + return max2837_set_txvga_gain(&drv->drv.max2837, gain_db); + break; + + case MAX2839_VARIANT: + return max2839_set_txvga_gain(&drv->drv.max2839, gain_db); + break; + } + + return false; } void max283x_tx(max283x_driver_t* const drv) { - CALL(drv, tx); + switch (drv->type) { + case MAX2837_VARIANT: + max2837_tx(&drv->drv.max2837); + break; + + case MAX2839_VARIANT: + max2839_tx(&drv->drv.max2839); + break; + } } void max283x_rx(max283x_driver_t* const drv) { - CALL(drv, rx); -} + switch (drv->type) { + case MAX2837_VARIANT: + max2837_rx(&drv->drv.max2837); + break; -/* Set MAX2831 receiver high-pass filter corner frequency in Hz */ -void max283x_set_rx_hpf_frequency( - max283x_driver_t* const drv, - const max283x_rx_hpf_freq_t freq) -{ - (void) freq; - PRALINE_ONLY( - drv, - max2831_set_rx_hpf_frequency( - &drv->drv.max2831, - (max2831_rx_hpf_freq_t) freq)); -} - -void max283x_tx_calibration(max283x_driver_t* const drv) -{ - PRALINE_ONLY(drv, max2831_tx_calibration(&drv->drv.max2831)); -} - -void max283x_rx_calibration(max283x_driver_t* const drv) -{ - PRALINE_ONLY(drv, max2831_rx_calibration(&drv->drv.max2831)); + case MAX2839_VARIANT: + max2839_rx(&drv->drv.max2839); + break; + } } diff --git a/firmware/common/max283x.h b/firmware/common/max283x.h index 7c9c03dd..06ff6465 100644 --- a/firmware/common/max283x.h +++ b/firmware/common/max283x.h @@ -1,5 +1,5 @@ /* - * Copyright 2012-2026 Great Scott Gadgets + * Copyright 2012-2022 Great Scott Gadgets * Copyright 2012 Will Code * Copyright 2014 Jared Boone * @@ -21,23 +21,20 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __MAX283x_H +#define __MAX283x_H -#include #include +#include +#include -#include "fixed_point.h" -#include "spi_ssp.h" - -#ifdef IS_PRALINE - #include "max2831.h" -#endif -#ifdef IS_NOT_PRALINE - #include "max2837.h" -#endif -#ifdef IS_H1_R9 - #include "max2839.h" -#endif +#include "gpio.h" +#include "gpio_lpc.h" +#include "max2837.h" +#include "max2837_target.h" +#include "max2839.h" +#include "max2839_target.h" +#include "spi_bus.h" typedef enum { MAX283x_MODE_SHUTDOWN, @@ -50,48 +47,21 @@ typedef enum { } max283x_mode_t; typedef enum { - MAX283x_RX_HPF_100_HZ = 0, - MAX283x_RX_HPF_4_KHZ = 1, - MAX283x_RX_HPF_30_KHZ = 2, - MAX283x_RX_HPF_600_KHZ = 3, -} max283x_rx_hpf_freq_t; - -typedef enum { -#ifdef IS_PRALINE - MAX2831_VARIANT, -#endif -#ifdef IS_NOT_PRALINE MAX2837_VARIANT, -#endif -#ifdef IS_H1_R9 MAX2839_VARIANT, -#endif } max283x_variant_t; typedef struct { max283x_variant_t type; union { -#ifdef IS_PRALINE - max2831_driver_t max2831; -#endif -#ifdef IS_NOT_PRALINE max2837_driver_t max2837; -#endif -#ifdef IS_H1_R9 max2839_driver_t max2839; -#endif } drv; } max283x_driver_t; /* Initialize chip. */ -void max283x_setup(max283x_driver_t* const drv); - -/* Returns the number of registers supported by the driver. */ -uint16_t max283x_num_regs(max283x_driver_t* const drv); - -/* Returns the maximum data register value supported by the driver. */ -uint16_t max283x_data_regs_max_value(max283x_driver_t* const drv); +void max283x_setup(max283x_driver_t* const drv, max283x_variant_t type); /* Read a register via SPI. Save a copy to memory and return * value. Mark clean. */ @@ -113,14 +83,11 @@ void max283x_set_mode(max283x_driver_t* const drv, const max283x_mode_t new_mode void max283x_start(max283x_driver_t* const drv); void max283x_stop(max283x_driver_t* const drv); -/* Set frequency in 1/(2**24) Hz. */ -fp_40_24_t max283x_set_frequency( - max283x_driver_t* const drv, - fp_40_24_t freq, - bool program); +/* Set frequency in Hz. Frequency setting is a multi-step function + * where order of register writes matters. */ +void max283x_set_frequency(max283x_driver_t* const drv, uint32_t freq); uint32_t max283x_set_lpf_bandwidth( max283x_driver_t* const drv, - const max283x_mode_t mode, const uint32_t bandwidth_hz); bool max283x_set_lna_gain(max283x_driver_t* const drv, const uint32_t gain_db); @@ -131,15 +98,4 @@ bool max283x_set_txvga_gain(max283x_driver_t* const drv, const uint32_t gain_db) void max283x_tx(max283x_driver_t* const drv); void max283x_rx(max283x_driver_t* const drv); -/* Set MAX2831 receiver high-pass filter corner frequency in Hz */ -void max283x_set_rx_hpf_frequency( - max283x_driver_t* const drv, - const max283x_rx_hpf_freq_t freq); - -/* Perform MAX2831 TX and RX calibration. */ -void max283x_tx_calibration(max283x_driver_t* const drv); -void max283x_rx_calibration(max283x_driver_t* const drv); - -/* Driver instance. */ -extern ssp_config_t ssp_config_max283x; -extern max283x_driver_t max283x; +#endif // __MAX283x_H diff --git a/firmware/common/max2871.c b/firmware/common/max2871.c index 05840678..598599cc 100644 --- a/firmware/common/max2871.c +++ b/firmware/common/max2871.c @@ -1,5 +1,5 @@ /* - * Copyright 2015-2026 Great Scott Gadgets + * Copyright 2015-2022 Great Scott Gadgets * * This file is part of HackRF. * @@ -20,15 +20,7 @@ */ #include "max2871.h" - -#include -#include - -#include - -#include "fixed_point.h" #include "max2871_regs.h" -#include "platform_scu.h" #include "selftest.h" #if (defined DEBUG) @@ -36,10 +28,13 @@ #define LOG printf #else #define LOG(x, ...) + #include + #include + #include "hackrf_core.h" #endif -#define MIN(x, y) ((x) < (y) ? (x) : (y)) -#define MAX(x, y) ((x) > (y) ? (x) : (y)) +#include +#include static uint32_t max2871_spi_read(max2871_driver_t* const drv); static void max2871_spi_write(max2871_driver_t* const drv, uint8_t r, uint32_t v); @@ -48,16 +43,14 @@ static void delay_ms(int ms); void max2871_setup(max2871_driver_t* const drv) { - const platform_scu_t* scu = platform_scu(); - /* Configure GPIO pins. */ - scu_pinmux(scu->VCO_CE, SCU_GPIO_FAST); - scu_pinmux(scu->VCO_SCLK, SCU_GPIO_FAST | SCU_CONF_FUNCTION4); - /* Only used for the debug pin config: scu_pinmux(scu->VCO_SCLK, SCU_GPIO_FAST); */ - scu_pinmux(scu->VCO_SDATA, SCU_GPIO_FAST); - scu_pinmux(scu->VCO_LE, SCU_GPIO_FAST); - scu_pinmux(scu->VCO_MUX, SCU_GPIO_FAST | SCU_CONF_FUNCTION4); - scu_pinmux(scu->SYNT_RFOUT_EN, SCU_GPIO_FAST); + scu_pinmux(SCU_VCO_CE, SCU_GPIO_FAST); + scu_pinmux(SCU_VCO_SCLK, SCU_GPIO_FAST | SCU_CONF_FUNCTION4); + /* Only used for the debug pin config: scu_pinmux(SCU_VCO_SCLK, SCU_GPIO_FAST); */ + scu_pinmux(SCU_VCO_SDATA, SCU_GPIO_FAST); + scu_pinmux(SCU_VCO_LE, SCU_GPIO_FAST); + scu_pinmux(SCU_VCO_MUX, SCU_GPIO_FAST | SCU_CONF_FUNCTION4); + scu_pinmux(SCU_SYNT_RFOUT_EN, SCU_GPIO_FAST); /* Set GPIO pins as outputs. */ gpio_output(drv->gpio_vco_ce); @@ -137,7 +130,7 @@ void max2871_setup(max2871_driver_t* const drv) max2871_write_registers(drv); - max2871_set_frequency(drv, FP_MHZ(3500), true); + max2871_set_frequency(drv, 3500); } static void delay_ms(int ms) @@ -233,16 +226,9 @@ static void max2871_write_registers(max2871_driver_t* const drv) } } -#define MIN_LO FP_MHZ(40) -#define MAX_LO FP_MHZ(6000) - -/* Set frequency in 1/(2**24) Hz, rounded to nearest 40 MHz. */ -fp_40_24_t max2871_set_frequency(max2871_driver_t* const drv, fp_40_24_t lo, bool program) +/* Set frequency (MHz). */ +uint64_t max2871_set_frequency(max2871_driver_t* const drv, uint16_t mhz) { - lo = MIN(lo, MAX_LO); - lo = MAX(lo, MIN_LO); - - uint16_t mhz = lo / FP_ONE_MHZ; int n = mhz / 40; int diva = 0; @@ -251,21 +237,19 @@ fp_40_24_t max2871_set_frequency(max2871_driver_t* const drv, fp_40_24_t lo, boo diva += 1; } - if (program) { - max2871_set_RFA_EN(0); - max2871_write_registers(drv); + max2871_set_RFA_EN(0); + max2871_write_registers(drv); - max2871_set_N(n); - max2871_set_DIVA(diva); - max2871_write_registers(drv); + max2871_set_N(n); + max2871_set_DIVA(diva); + max2871_write_registers(drv); - while (max2871_spi_read(drv) & MAX2871_VASA) {} + while (max2871_spi_read(drv) & MAX2871_VASA) {} - max2871_set_RFA_EN(1); - max2871_write_registers(drv); - } + max2871_set_RFA_EN(1); + max2871_write_registers(drv); - return (mhz / 40) * FP_MHZ(40); + return (mhz / 40) * 40 * 1000000; } void max2871_enable(max2871_driver_t* const drv) diff --git a/firmware/common/max2871.h b/firmware/common/max2871.h index 682ee8c0..a11172bc 100644 --- a/firmware/common/max2871.h +++ b/firmware/common/max2871.h @@ -1,5 +1,5 @@ /* - * Copyright 2017-2026 Great Scott Gadgets + * Copyright 2017 Great Scott Gadgets * * This file is part of HackRF. * @@ -19,13 +19,13 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef MAX2871_H +#define MAX2871_H -#include - -#include "fixed_point.h" #include "gpio.h" +#include + typedef struct { gpio_t gpio_vco_ce; gpio_t gpio_vco_sclk; @@ -36,9 +36,7 @@ typedef struct { } max2871_driver_t; extern void max2871_setup(max2871_driver_t* const drv); -extern fp_40_24_t max2871_set_frequency( - max2871_driver_t* const drv, - fp_40_24_t lo, - bool program); +extern uint64_t max2871_set_frequency(max2871_driver_t* const drv, uint16_t mhz); extern void max2871_enable(max2871_driver_t* const drv); extern void max2871_disable(max2871_driver_t* const drv); +#endif diff --git a/firmware/common/max2871_regs.h b/firmware/common/max2871_regs.h index b0dbdacf..a18f6217 100644 --- a/firmware/common/max2871_regs.h +++ b/firmware/common/max2871_regs.h @@ -19,8 +19,8 @@ * Boston, MA 02110-1301, USA. */ -#pragma once - +#ifndef MAX2871_REGS_H +#define MAX2871_REGS_H #include #define MAX2871_VASA (1 << 9) @@ -75,3 +75,4 @@ void max2871_set_F01(uint32_t v); void max2871_set_LD(uint32_t v); void max2871_set_ADCS(uint32_t v); void max2871_set_ADCM(uint32_t v); +#endif diff --git a/firmware/common/max5864.c b/firmware/common/max5864.c index 0b825fcd..78a84661 100644 --- a/firmware/common/max5864.c +++ b/firmware/common/max5864.c @@ -20,38 +20,13 @@ * Boston, MA 02110-1301, USA. */ -#include "max5864.h" - #include -#include - -#include "max5864_target.h" -#include "platform_gpio.h" -#include "spi_bus.h" - -/* Driver instance. */ -ssp_config_t ssp_config_max5864 = { - /* FIXME speed up once everything is working reliably */ - /* - // Freq About 0.0498MHz / 49.8KHz => Freq = PCLK / (CPSDVSR * [SCR+1]) with PCLK=PLL1=204MHz - const uint8_t serial_clock_rate = 32; - const uint8_t clock_prescale_rate = 128; - */ - // Freq About 4.857MHz => Freq = PCLK / (CPSDVSR * [SCR+1]) with PCLK=PLL1=204MHz - .data_bits = SSP_DATA_8BITS, - .serial_clock_rate = 21, - .clock_prescale_rate = 2, -}; - -max5864_driver_t max5864 = { - .bus = &spi_bus_ssp1, - .target_init = max5864_target_init, -}; +#include "max5864.h" static void max5864_write(max5864_driver_t* const drv, uint8_t value) { - spi_bus_transfer(drv->bus, &ssp_config_max5864, &value, 1); + spi_bus_transfer(drv->bus, &value, 1); } static void max5864_init(max5864_driver_t* const drv) @@ -61,8 +36,6 @@ static void max5864_init(max5864_driver_t* const drv) void max5864_setup(max5864_driver_t* const drv) { - ssp_config_max5864.gpio_select = platform_gpio()->max5864_select; - max5864_init(drv); } diff --git a/firmware/common/max5864.h b/firmware/common/max5864.h index 0f561685..a0602e50 100644 --- a/firmware/common/max5864.h +++ b/firmware/common/max5864.h @@ -20,15 +20,18 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __MAX5864_H +#define __MAX5864_H #include "spi_bus.h" -#include "spi_ssp.h" -typedef struct _max5864_driver_t { +struct max5864_driver_t; +typedef struct max5864_driver_t max5864_driver_t; + +struct max5864_driver_t { spi_bus_t* const bus; - void (*target_init)(struct _max5864_driver_t* const drv); -} max5864_driver_t; + void (*target_init)(max5864_driver_t* const drv); +}; void max5864_setup(max5864_driver_t* const drv); @@ -39,6 +42,4 @@ void max5864_rx(max5864_driver_t* const drv); void max5864_tx(max5864_driver_t* const drv); void max5864_xcvr(max5864_driver_t* const drv); -/* Driver instance. */ -extern ssp_config_t ssp_config_max5864; -extern max5864_driver_t max5864; +#endif // __MAX5864_H diff --git a/firmware/common/max5864_target.c b/firmware/common/max5864_target.c index 1fc64934..ed433415 100644 --- a/firmware/common/max5864_target.c +++ b/firmware/common/max5864_target.c @@ -23,23 +23,20 @@ #include "max5864_target.h" #include - -#include "platform_scu.h" +#include "hackrf_core.h" void max5864_target_init(max5864_driver_t* const drv) { (void) drv; - const platform_scu_t* scu = platform_scu(); - /* Configure SSP1 Peripheral (to be moved later in SSP driver) */ - scu_pinmux(scu->SSP1_CIPO, (SCU_SSP_IO | SCU_CONF_FUNCTION5)); - scu_pinmux(scu->SSP1_COPI, (SCU_SSP_IO | SCU_CONF_FUNCTION5)); - scu_pinmux(scu->SSP1_SCK, (SCU_SSP_IO | SCU_CONF_FUNCTION1)); + scu_pinmux(SCU_SSP1_CIPO, (SCU_SSP_IO | SCU_CONF_FUNCTION5)); + scu_pinmux(SCU_SSP1_COPI, (SCU_SSP_IO | SCU_CONF_FUNCTION5)); + scu_pinmux(SCU_SSP1_SCK, (SCU_SSP_IO | SCU_CONF_FUNCTION1)); /* * Configure CS_AD pin to keep the MAX5864 SPI disabled while we use the * SPI bus for the MAX2837. FIXME: this should probably be somewhere else. */ - scu_pinmux(scu->AD_CS, scu->AD_CS_PINCFG); + scu_pinmux(SCU_AD_CS, SCU_AD_CS_PINCFG); } diff --git a/firmware/common/max5864_target.h b/firmware/common/max5864_target.h index a162e0ac..2ddd9ed1 100644 --- a/firmware/common/max5864_target.h +++ b/firmware/common/max5864_target.h @@ -20,8 +20,11 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __MAX5864_TARGET_H__ +#define __MAX5864_TARGET_H__ #include "max5864.h" void max5864_target_init(max5864_driver_t* const drv); + +#endif /*__MAX5864_TARGET_H__*/ diff --git a/firmware/common/mixer.c b/firmware/common/mixer.c index e38c28bf..e9c512fe 100644 --- a/firmware/common/mixer.c +++ b/firmware/common/mixer.c @@ -1,5 +1,5 @@ /* - * Copyright 2017-2026 Great Scott Gadgets + * Copyright 2017-2022 Great Scott Gadgets * * This file is part of HackRF. * @@ -20,147 +20,158 @@ */ #include "mixer.h" +#include "rffc5071.h" +#include "rffc5071_spi.h" +#include "max2871.h" +#include "gpio_lpc.h" -#include - -#include "fixed_point.h" -#include "platform_detect.h" -#include "platform_gpio.h" -#ifdef IS_RAD1O - #include "max2871.h" +/* RFFC5071 GPIO serial interface PinMux */ +// clang-format off +#if (defined JAWBREAKER || defined HACKRF_ONE) +static struct gpio_t gpio_rffc5072_select = GPIO(2, 13); +static struct gpio_t gpio_rffc5072_clock = GPIO(5, 6); +static struct gpio_t gpio_rffc5072_data = GPIO(3, 3); +static struct gpio_t gpio_rffc5072_reset = GPIO(2, 14); #endif -#ifdef IS_NOT_RAD1O - #include "rffc5071.h" - #include "rffc5071_spi.h" - #include "spi_bus.h" +#ifdef RAD1O +static struct gpio_t gpio_vco_ce = GPIO(2, 13); +static struct gpio_t gpio_vco_sclk = GPIO(5, 6); +static struct gpio_t gpio_vco_sdata = GPIO(3, 3); +static struct gpio_t gpio_vco_le = GPIO(2, 14); +static struct gpio_t gpio_vco_mux = GPIO(5, 25); +static struct gpio_t gpio_synt_rfout_en = GPIO(3, 5); #endif +#ifdef PRALINE +static struct gpio_t gpio_rffc5072_select = GPIO(2, 13); +static struct gpio_t gpio_rffc5072_clock = GPIO(5, 18); +static struct gpio_t gpio_rffc5072_data = GPIO(4, 14); +static struct gpio_t gpio_rffc5072_reset = GPIO(2, 14); +static struct gpio_t gpio_rffc5072_ld = GPIO(6, 25); +#endif +// clang-format on -#ifdef IS_NOT_RAD1O -static rffc5071_spi_config_t rffc5071_spi_config; +#if (defined JAWBREAKER || defined HACKRF_ONE || defined PRALINE) +const rffc5071_spi_config_t rffc5071_spi_config = { + .gpio_select = &gpio_rffc5072_select, + .gpio_clock = &gpio_rffc5072_clock, + .gpio_data = &gpio_rffc5072_data, +}; -static spi_bus_t spi_bus_rffc5071 = { +spi_bus_t spi_bus_rffc5071 = { .config = &rffc5071_spi_config, .start = rffc5071_spi_start, .stop = rffc5071_spi_stop, .transfer = rffc5071_spi_transfer, .transfer_gather = rffc5071_spi_transfer_gather, }; -#endif mixer_driver_t mixer = { -#ifdef IS_NOT_RAD1O - .rffc5071.bus = &spi_bus_rffc5071, -#endif + .bus = &spi_bus_rffc5071, + .gpio_reset = &gpio_rffc5072_reset, + #ifdef PRALINE + .gpio_ld = &gpio_rffc5072_ld, + #endif }; +#endif +#ifdef RAD1O +mixer_driver_t mixer = { + .gpio_vco_ce = &gpio_vco_ce, + .gpio_vco_sclk = &gpio_vco_sclk, + .gpio_vco_sdata = &gpio_vco_sdata, + .gpio_vco_le = &gpio_vco_le, + .gpio_synt_rfout_en = &gpio_synt_rfout_en, + .gpio_vco_mux = &gpio_vco_mux, +}; +#endif void mixer_bus_setup(mixer_driver_t* const mixer) { +#if (defined JAWBREAKER || defined HACKRF_ONE || defined PRALINE) + (void) mixer; + spi_bus_start(&spi_bus_rffc5071, &rffc5071_spi_config); +#endif +#ifdef RAD1O (void) mixer; - -#ifdef IS_NOT_RAD1O - if (IS_NOT_RAD1O) { - const platform_gpio_t* gpio = platform_gpio(); - - rffc5071_spi_config = (rffc5071_spi_config_t){ - .gpio_select = gpio->rffc5072_select, - .gpio_clock = gpio->rffc5072_clock, - .gpio_data = gpio->rffc5072_data, - }; - spi_bus_start(&spi_bus_rffc5071, &rffc5071_spi_config); - } #endif } -void mixer_setup(mixer_driver_t* const mixer, mixer_variant_t type) +void mixer_setup(mixer_driver_t* const mixer) { - mixer->type = type; - - const platform_gpio_t* gpio = platform_gpio(); - - /* Mixer GPIO serial interface PinMux */ -#ifdef IS_PRALINE - if (IS_PRALINE) { - mixer->rffc5071.gpio_ld = gpio->rffc5072_ld; - } +#if (defined JAWBREAKER || defined HACKRF_ONE || defined PRALINE) + rffc5071_setup(mixer); #endif - -#ifdef IS_NOT_RAD1O - if (IS_NOT_RAD1O) { - mixer->rffc5071.gpio_reset = gpio->rffc5072_reset; - rffc5071_setup(&mixer->rffc5071); - } -#endif - -#ifdef IS_RAD1O - if (IS_RAD1O) { - mixer->max2871.gpio_vco_ce = gpio->vco_ce; - mixer->max2871.gpio_vco_sclk = gpio->vco_sclk; - mixer->max2871.gpio_vco_sdata = gpio->vco_sdata; - mixer->max2871.gpio_vco_le = gpio->vco_le; - mixer->max2871.gpio_synt_rfout_en = gpio->synt_rfout_en; - mixer->max2871.gpio_vco_mux = gpio->vco_mux; - max2871_setup(&mixer->max2871); - } +#ifdef RAD1O + max2871_setup(mixer); #endif } -fp_40_24_t mixer_set_frequency(mixer_driver_t* const mixer, fp_40_24_t lo, bool program) +uint64_t mixer_set_frequency(mixer_driver_t* const mixer, uint64_t hz) { -#ifdef IS_NOT_RAD1O - if (IS_NOT_RAD1O) { - return rffc5071_set_frequency(&mixer->rffc5071, lo, program); - } +#if (defined JAWBREAKER || defined HACKRF_ONE || defined PRALINE) + return rffc5071_set_frequency(mixer, hz); #endif +#ifdef RAD1O + return max2871_set_frequency(mixer, hz / 1000000); +#endif +} -#ifdef IS_RAD1O - if (IS_RAD1O) { - return max2871_set_frequency(&mixer->max2871, lo, program); - } +void mixer_tx(mixer_driver_t* const mixer) +{ +#if (defined JAWBREAKER || defined HACKRF_ONE || defined PRALINE) + rffc5071_tx(mixer); +#endif +#ifdef RAD1O + (void) mixer; +#endif +} + +void mixer_rx(mixer_driver_t* const mixer) +{ +#if (defined JAWBREAKER || defined HACKRF_ONE || defined PRALINE) + rffc5071_rx(mixer); +#endif +#ifdef RAD1O + (void) mixer; +#endif +} + +void mixer_rxtx(mixer_driver_t* const mixer) +{ +#if (defined JAWBREAKER || defined HACKRF_ONE || defined PRALINE) + rffc5071_rxtx(mixer); +#endif +#ifdef RAD1O + (void) mixer; #endif } void mixer_enable(mixer_driver_t* const mixer) { -#ifdef IS_NOT_RAD1O - if (IS_NOT_RAD1O) { - rffc5071_enable(&mixer->rffc5071); - } +#if (defined JAWBREAKER || defined HACKRF_ONE || defined PRALINE) + rffc5071_enable(mixer); #endif - -#ifdef IS_RAD1O - if (IS_RAD1O) { - max2871_enable(&mixer->max2871); - } +#ifdef RAD1O + max2871_enable(mixer); #endif } void mixer_disable(mixer_driver_t* const mixer) { -#ifdef IS_NOT_RAD1O - if (IS_NOT_RAD1O) { - rffc5071_disable(&mixer->rffc5071); - } +#if (defined JAWBREAKER || defined HACKRF_ONE || defined PRALINE) + rffc5071_disable(mixer); #endif - -#ifdef IS_RAD1O - if (IS_RAD1O) { - max2871_disable(&mixer->max2871); - } +#ifdef RAD1O + max2871_disable(mixer); #endif } void mixer_set_gpo(mixer_driver_t* const mixer, uint8_t gpo) { -#ifdef IS_NOT_RAD1O - if (IS_NOT_RAD1O) { - rffc5071_set_gpo(&mixer->rffc5071, gpo); - } +#if (defined JAWBREAKER || defined HACKRF_ONE || defined PRALINE) + rffc5071_set_gpo(mixer, gpo); #endif - -#ifdef IS_RAD1O - if (IS_RAD1O) { - (void) mixer; - (void) gpo; - } +#ifdef RAD1O + (void) mixer; + (void) gpo; #endif } diff --git a/firmware/common/mixer.h b/firmware/common/mixer.h index 15afe35e..fc732275 100644 --- a/firmware/common/mixer.h +++ b/firmware/common/mixer.h @@ -1,5 +1,5 @@ /* - * Copyright 2012-2026 Great Scott Gadgets + * Copyright 2012-2022 Great Scott Gadgets * Copyright 2014 Jared Boone * * This file is part of HackRF. @@ -20,49 +20,33 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __MIXER_H +#define __MIXER_H -#include -#include - -#include "fixed_point.h" -#ifdef IS_RAD1O - #include "max2871.h" -#endif -#ifdef IS_NOT_RAD1O +#if (defined JAWBREAKER || defined HACKRF_ONE || defined PRALINE) #include "rffc5071.h" +typedef rffc5071_driver_t mixer_driver_t; #endif -typedef enum { - RFFC5071_VARIANT, - MAX2871_VARIANT, -} mixer_variant_t; - -typedef struct { - mixer_variant_t type; - - union { -#ifdef IS_RAD1O - max2871_driver_t max2871; +#ifdef RAD1O + #include "max2871.h" +typedef max2871_driver_t mixer_driver_t; #endif -#ifdef IS_NOT_RAD1O - rffc5071_driver_t rffc5071; -#endif - }; -} mixer_driver_t; +#include extern void mixer_bus_setup(mixer_driver_t* const mixer); -extern void mixer_setup(mixer_driver_t* const mixer, mixer_variant_t type); +extern void mixer_setup(mixer_driver_t* const mixer); /* Set frequency (Hz). */ -extern fp_40_24_t mixer_set_frequency( - mixer_driver_t* const mixer, - fp_40_24_t lo, - bool program); +extern uint64_t mixer_set_frequency(mixer_driver_t* const mixer, uint64_t hz); +/* Set up rx only, tx only, or full duplex. Chip should be disabled + * before _tx, _rx, or _rxtx are called. */ +extern void mixer_tx(mixer_driver_t* const mixer); +extern void mixer_rx(mixer_driver_t* const mixer); +extern void mixer_rxtx(mixer_driver_t* const mixer); extern void mixer_enable(mixer_driver_t* const mixer); extern void mixer_disable(mixer_driver_t* const mixer); extern void mixer_set_gpo(mixer_driver_t* const drv, uint8_t gpo); -/* Mixer instance. */ -extern mixer_driver_t mixer; +#endif // __MIXER_H diff --git a/firmware/common/operacake.c b/firmware/common/operacake.c index bce51b76..297f5099 100644 --- a/firmware/common/operacake.c +++ b/firmware/common/operacake.c @@ -21,17 +21,12 @@ */ #include "operacake.h" - -#include - -#include - +#include "operacake_sctimer.h" +#include "hackrf_core.h" #include "gpio.h" #include "gpio_lpc.h" #include "i2c_bus.h" -#include "i2c_lpc.h" -#include "operacake_sctimer.h" -#include "platform_scu.h" +#include /* * I2C Mode @@ -82,7 +77,6 @@ #define INVALID_RANGE 0xFF; static uint8_t current_range = INVALID_RANGE; -static uint8_t skip_address = OPERACAKE_ADDRESS_INVALID; i2c_bus_t* const oc_bus = &i2c0; @@ -128,9 +122,6 @@ uint8_t operacake_init(bool allow_gpio) { /* Find connected operacakes */ for (int addr = 0; addr < 8; addr++) { - if (addr + OPERACAKE_ADDRESS_DEFAULT == skip_address) { - continue; - } operacake_write_reg( oc_bus, addr, @@ -155,15 +146,6 @@ uint8_t operacake_init(bool allow_gpio) return 0; } -void operacake_skip_i2c_address(uint8_t address) -{ - skip_address = address; - uint8_t board_addr = address - OPERACAKE_ADDRESS_DEFAULT; - if (board_addr < 8) { - operacake_boards[board_addr].present = false; - } -} - bool operacake_is_board_present(uint8_t address) { if (address >= OPERACAKE_MAX_BOARDS) { @@ -405,15 +387,13 @@ uint16_t gpio_test(uint8_t address) return 0xFFFF; } - const platform_scu_t* scu = platform_scu(); + scu_pinmux(SCU_PINMUX_GPIO3_8, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + scu_pinmux(SCU_PINMUX_GPIO3_12, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + scu_pinmux(SCU_PINMUX_GPIO3_13, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + scu_pinmux(SCU_PINMUX_GPIO3_14, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + scu_pinmux(SCU_PINMUX_GPIO3_15, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); - scu_pinmux(scu->PINMUX_GPIO3_8, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); - scu_pinmux(scu->PINMUX_GPIO3_12, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); - scu_pinmux(scu->PINMUX_GPIO3_13, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); - scu_pinmux(scu->PINMUX_GPIO3_14, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); - scu_pinmux(scu->PINMUX_GPIO3_15, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); - - static struct gpio gpio_pins[] = { + static struct gpio_t gpio_pins[] = { GPIO(3, 8), // u1ctrl IO2 GPIO(3, 14), // u3ctrl0 IO3 GPIO(3, 15), // u3ctrl1 IO4 diff --git a/firmware/common/operacake.h b/firmware/common/operacake.h index b604c513..8183cf2a 100644 --- a/firmware/common/operacake.h +++ b/firmware/common/operacake.h @@ -20,14 +20,15 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __OPERACAKE_H +#define __OPERACAKE_H #ifdef __cplusplus extern "C" { #endif -#include #include +#include #define OPERACAKE_PA1 0 #define OPERACAKE_PA2 1 @@ -42,7 +43,6 @@ extern "C" { #define MAX_OPERACAKE_RANGES 8 uint8_t operacake_init(bool allow_gpio); -void operacake_skip_i2c_address(uint8_t address); bool operacake_is_board_present(uint8_t address); void operacake_get_boards(uint8_t* addresses); bool operacake_set_mode(uint8_t address, uint8_t mode); @@ -56,3 +56,5 @@ uint16_t gpio_test(uint8_t address); #ifdef __cplusplus } #endif + +#endif /* __OPERACAKE_H */ diff --git a/firmware/common/operacake_sctimer.c b/firmware/common/operacake_sctimer.c index c5ec8a3b..fca5d03b 100644 --- a/firmware/common/operacake_sctimer.c +++ b/firmware/common/operacake_sctimer.c @@ -22,18 +22,13 @@ #include "operacake_sctimer.h" -#include +#include + +#include #include #include - -#include "delay.h" -#include "platform_detect.h" -#include "platform_scu.h" +#include #include "sct.h" -#ifdef IS_NOT_PRALINE - #include - #include -#endif #define U1CTRL_SET SCT_OUT14_SET #define U1CTRL_CLR SCT_OUT14_CLR @@ -60,10 +55,8 @@ static uint32_t default_output = 0; * On Praline, instead, MS0/CLK1 (SCT_CLK) is configured to output its * clock (f=2 * sample clock) to the SCTimer. */ -void operacake_sctimer_init(void) +void operacake_sctimer_init() { - const platform_scu_t* scu = platform_scu(); - // We start by resetting the SCTimer RESET_CTRL1 = RESET_CTRL1_SCT_RST; @@ -75,45 +68,48 @@ void operacake_sctimer_init(void) // there are additional instructions that fill the time. If the duration of // the actions from here to the first access to the SCTimer is changed, then // this delay may need to be increased. - delay_us(1); + delay(8); // Pin definitions for the HackRF // U2CTRL0 - scu_pinmux(scu->CTOUT_13, scu->CTOUT_PINCFG); + scu_pinmux( + P7_4, + SCU_CONF_EPUN_DIS_PULLUP | SCU_CONF_EHS_FAST | SCU_CONF_FUNCTION1); // U2CTRL1 - scu_pinmux(scu->CTOUT_12, scu->CTOUT_PINCFG); + scu_pinmux( + P7_5, + SCU_CONF_EPUN_DIS_PULLUP | SCU_CONF_EHS_FAST | SCU_CONF_FUNCTION1); // U3CTRL0 - scu_pinmux(scu->CTOUT_11, scu->CTOUT_PINCFG); + scu_pinmux( + P7_6, + SCU_CONF_EPUN_DIS_PULLUP | SCU_CONF_EHS_FAST | SCU_CONF_FUNCTION1); // U3CTRL1 - scu_pinmux(scu->CTOUT_8, scu->CTOUT_PINCFG); + scu_pinmux( + P7_7, + SCU_CONF_EPUN_DIS_PULLUP | SCU_CONF_EHS_FAST | SCU_CONF_FUNCTION1); // U1CTRL - scu_pinmux(scu->CTOUT_14, scu->CTOUT_PINCFG); + scu_pinmux( + P7_0, + SCU_CONF_EPUN_DIS_PULLUP | SCU_CONF_EHS_FAST | SCU_CONF_FUNCTION1); - uint8_t sct_clock_input; -#ifdef IS_NOT_PRALINE - if (IS_NOT_PRALINE) { - // Configure the SGPIO to output the clock (f=2 * sample clock) on pin 12 - SGPIO_OUT_MUX_CFG12 = - SGPIO_OUT_MUX_CFG_P_OUT_CFG(0x08) | // clkout output mode - SGPIO_OUT_MUX_CFG_P_OE_CFG(0); // gpio_oe - SGPIO_GPIO_OENREG |= BIT12; +#ifndef PRALINE + // Configure the SGPIO to output the clock (f=2 * sample clock) on pin 12 + SGPIO_OUT_MUX_CFG12 = SGPIO_OUT_MUX_CFG_P_OUT_CFG(0x08) | // clkout output mode + SGPIO_OUT_MUX_CFG_P_OE_CFG(0); // gpio_oe + SGPIO_GPIO_OENREG |= BIT12; - // Use the GIMA to connect the SGPIO clock to the SCTimer - GIMA_CTIN_1_IN = 0x2 << 4; // Route SGPIO12 to SCTIN1 + // Use the GIMA to connect the SGPIO clock to the SCTimer + GIMA_CTIN_1_IN = 0x2 << 4; // Route SGPIO12 to SCTIN1 - sct_clock_input = SCT_CONFIG_CKSEL_RISING_EDGES_ON_INPUT_1; - } -#endif -#ifdef IS_PRALINE - if (IS_PRALINE) { - // Configure pin P6_4 as CTIN_6 - scu_pinmux(scu->SCT_CLK, scu->SCT_CLK_PINCFG); + uint8_t sct_clock_input = SCT_CONFIG_CKSEL_RISING_EDGES_ON_INPUT_1; +#else + // Configure pin P6_4 as SCT_IN_6 + scu_pinmux(P6_4, SCU_CLK_IN | SCU_CONF_FUNCTION1); - // Use the GIMA to connect MS0/CLK1 (SCT_CLK) on pin P6_4 to the SCTimer - GIMA_CTIN_6_IN = 0x0 << 4; + // Use the GIMA to connect MS0/CLK1 (SCT_CLK) on pin P6_4 to the SCTimer + GIMA_CTIN_6_IN = 0x0 << 4; - sct_clock_input = SCT_CONFIG_CKSEL_RISING_EDGES_ON_INPUT_6; - } + uint8_t sct_clock_input = SCT_CONFIG_CKSEL_RISING_EDGES_ON_INPUT_6; #endif // We configure this register first, because the user manual says to @@ -220,7 +216,7 @@ void operacake_sctimer_set_dwell_times(struct operacake_dwell_times* times, int SCT_CTRL &= ~SCT_CTRL_HALT_L(1); } -void operacake_sctimer_stop(void) +void operacake_sctimer_stop() { // Halt timer SCT_CTRL |= SCT_CTRL_HALT_L(1); @@ -232,7 +228,7 @@ void operacake_sctimer_stop(void) * called by set_transceiver_mode so the HackRF starts capturing with the * same antenna selected each time. */ -void operacake_sctimer_reset_state(void) +void operacake_sctimer_reset_state() { SCT_CTRL |= SCT_CTRL_HALT_L(1); diff --git a/firmware/common/operacake_sctimer.h b/firmware/common/operacake_sctimer.h index 04c86e92..6c5d0f61 100644 --- a/firmware/common/operacake_sctimer.h +++ b/firmware/common/operacake_sctimer.h @@ -21,7 +21,8 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __OPERACAKE_SCTIMER_H +#define __OPERACAKE_SCTIMER_H #include #include @@ -31,8 +32,10 @@ struct operacake_dwell_times { uint8_t port; }; -void operacake_sctimer_init(void); +void operacake_sctimer_init(); void operacake_sctimer_enable(bool enable); void operacake_sctimer_set_dwell_times(struct operacake_dwell_times* times, int n); -void operacake_sctimer_stop(void); -void operacake_sctimer_reset_state(void); +void operacake_sctimer_stop(); +void operacake_sctimer_reset_state(); + +#endif /* __OPERACAKE_SCTIMER_H */ diff --git a/firmware/common/picoprintf.c b/firmware/common/picoprintf.c deleted file mode 100644 index 1959edb5..00000000 --- a/firmware/common/picoprintf.c +++ /dev/null @@ -1,433 +0,0 @@ -/* MIT License - * - * Copyright (c) 2023-2026 rom-p - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include "picoprintf.h" - -#include // llabs() - -#ifdef PICOFORMAT_HANDLE_FLOATS - #include // fabs() -#endif - -static void flip(char* pLeft, char* pRight) -{ - pRight--; - while (pLeft < pRight) { - char tmp = *pLeft; - *pLeft = *pRight; - *pRight = tmp; - pLeft++; - pRight--; - } -} - -// using #define over `inline` for enabling porting to old C -#if !defined(MIN) - #define MIN(left, right) (((left) < (right)) ? (left) : (right)) -#endif -#if !defined(MAX) - #define MAX(left, right) (((left) > (right)) ? (left) : (right)) -#endif - -// returns the pointer to the null-terminating character of the filled string -int pico_vsnprintf(char* pDest, size_t cbDest, const char* pFormat, va_list vl) -{ -#if defined(PICOFORMAT_HANDLE_BIN) || defined(PICOFORMAT_HANDLE_OCT) || \ - defined(PICOFORMAT_HANDLE_HEX) - const char* pLowercaseNumberDigits = "0123456789abcdef"; -#endif -#if defined(PICOFORMAT_HANDLE_HEX) - const char* pUppercaseNumberDigits = "0123456789ABCDEF"; -#elif defined(PICOFORMAT_HANDLE_OCT) - const char* pOctalDigits = pLowercaseNumberDigits; -#elif defined(PICOFORMAT_HANDLE_BIN) - const char* pBinaryDigits = pLowercaseNumberDigits; -#endif - char* pStart = pDest; - for (char* pEnd = pDest + cbDest - 1; *pFormat && pDest < pEnd;) { - if (*pFormat != '%') { - *pDest++ = *pFormat++; - } else { // format starts here - pFormat++; // skipping the '%' - if (*pFormat == '%') { // unless it's indeed a '%' - *pDest++ = *pFormat++; - } else { // first, collect the format - char format = '\0'; -#if defined(PICOFORMAT_HANDLE_BIN) || defined(PICOFORMAT_HANDLE_OCT) || \ - defined(PICOFORMAT_HANDLE_HEX) - int bits_per_digit = - 0; // valid in 'b', 'o', 'p' and 'x'/'X' modes only -#endif - int whole_chars = - 0; // number of chars in the whole part of the number - int decimal_chars = - -1; // if not specified, %f are rendered with 6, while %g are rendered with 0 -#ifdef __aarch64__ // these platforms benefit from packing flags into a single variable - struct { - unsigned force_sign : 1; - unsigned fill_zeros : 1; - unsigned left_align : 1; - unsigned seen_period : 1; - unsigned seen_numbers : 1; - unsigned treat_as_unsigned : 1; - unsigned treat_as_long : 1; - unsigned render_in_lowercase : 1; - } flags = {0}; - - #define FLAGS flags. - -#else // other platforms do not benefit from struct packing - unsigned force_sign = 0; - unsigned fill_zeros = 0; - #ifdef PICOFORMAT_HANDLE_FILL - unsigned left_align = 0; - #endif - unsigned seen_period = 0; - unsigned seen_numbers = 0; - unsigned treat_as_unsigned = 0; - unsigned treat_as_long = 0; - #if defined(PICOFORMAT_HANDLE_HEX) || defined(PICOFORMAT_HANDLE_FLOATS) - unsigned render_in_lowercase = 0; - #endif - #define FLAGS -#endif // struct packing platforms - for (; *pFormat && '\0' == format; pFormat++) { - switch (*pFormat) { -#ifdef PICOFORMAT_HANDLE_FORCEDSIGN - case '+': - FLAGS force_sign = 1; - break; -#endif // PICOFORMAT_HANDLE_FORCEDSIGN -#ifdef PICOFORMAT_HANDLE_FILL - case '-': // left-align flag - FLAGS left_align = 1; - break; -#endif // PICOFORMAT_HANDLE_FILL - case '0': - if (!FLAGS seen_numbers) { - FLAGS fill_zeros = 1; - break; - } - // fall through - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - *(FLAGS seen_period ? &decimal_chars : - &whole_chars) *= 10; - *(FLAGS seen_period ? &decimal_chars : - &whole_chars) += - *pFormat - '0'; - FLAGS seen_numbers = 1; - break; - case '.': - FLAGS seen_numbers = FLAGS seen_period = - 1; - decimal_chars = 0; - break; - case '*': // dynamic width/precision: read value from arg list - *(FLAGS seen_period ? &decimal_chars : - &whole_chars) = - va_arg(vl, int); - FLAGS seen_numbers = 1; - break; - case 'l': // long modifier - FLAGS treat_as_long = 1; - break; - case 'u': // unsigned decimal integer - FLAGS treat_as_unsigned = 1; - format = 'd'; - break; -#ifdef PICOFORMAT_HANDLE_BIN - case 'b': - bits_per_digit = 0; - FLAGS treat_as_unsigned = 1; - format = 'b'; - break; -#endif // PICOFORMAT_HANDLE_BIN -#ifdef PICOFORMAT_HANDLE_OCT - case 'o': // octal integer - bits_per_digit = 3; - FLAGS treat_as_unsigned = 1; - format = 'b'; - break; -#endif // PICOFORMAT_HANDLE_OCT -#ifdef PICOFORMAT_HANDLE_HEX - case 'x': // hexadecimal integer - case 'p': // pointer - bits_per_digit = 4; - FLAGS treat_as_unsigned = 1; - FLAGS render_in_lowercase = 1; - format = 'b'; - break; - case 'X': // hexadecimal integer, uppercase - bits_per_digit = 4; - FLAGS treat_as_unsigned = 1; - format = 'b'; - break; -#endif // PICOFORMAT_HANDLE_HEX -#ifdef PICOFORMAT_HANDLE_FLOATS - case 'a': - #ifdef PICOFORMAT_HANDLE_EXPONENTS - case 'e': // floating point, exponent format - #endif // PICOFORMAT_HANDLE_EXPONENTS - case 'f': - FLAGS render_in_lowercase = 1; - // fall through - case 'F': -#endif // PICOFORMAT_HANDLE_FLOATS - case 'c': // single char: always supported - case 'd': // integer: always supported - case 'i': // integer: always supported - case 's': // string of native `char`s: always supported - format = *pFormat; - break; - default: - FORMAT_ERROR_DELEGATE( - "detected unhandled format specifier: %c", - *pFormat); - break; - } - } - - // format is parsed, now render the value - char* pParamStarts = pDest; - switch (format) { - case 'c': // single char - *pDest++ = va_arg(vl, int) & 0xff; - break; - case 's': { // null-terminated string -#ifdef PICOFORMAT_HANDLE_FILL - int len = - 0; // effective length, bounded by precision if set - const char* pStr = va_arg(vl, const char*); - for (; pStr[len] && - (decimal_chars < 0 || len < decimal_chars); - len++) - ; - if (!FLAGS left_align) { // right-align: pad on the left - #ifdef PICOFORMAT_CLANG_QUIRK // clang's non-standard: '0' flag zero-pads strings - char chFill = - FLAGS fill_zeros ? '0' : ' '; - #else // PICOFORMAT_CLANG_QUIRK // standard C: '0' flag is undefined for %s, use spaces - char chFill = ' '; - #endif // PICOFORMAT_CLANG_QUIRK - for (; pDest < pEnd && whole_chars > len; - whole_chars--) { - *pDest++ = chFill; - } - } - for (int ii = 0; ii < len && pDest < pEnd; ii++) { - *pDest++ = pStr[ii]; - } - if (FLAGS left_align) { // left-align: pad on the right (always spaces; '-' flag overrides '0') - for (; pDest < pEnd && whole_chars > len; - whole_chars--) { - *pDest++ = ' '; - } - } -#else // PICOFORMAT_HANDLE_FILL - for (const char* pStr = va_arg(vl, const char*); - *pStr && pDest < pEnd;) { - *pDest++ = *pStr++; - } -#endif // PICOFORMAT_HANDLE_FILL - } break; -#if defined(PICOFORMAT_HANDLE_HEX) || defined(PICOFORMAT_HANDLE_OCT) || \ - defined(PICOFORMAT_HANDLE_BIN) - case 'b': { // binary, oct, or hex integer, always unsigned - long long int val = 0; - if (FLAGS treat_as_long) { - val = va_arg(vl, unsigned long long int); - } else { - val = va_arg(vl, unsigned); - } - unsigned mask = bits_per_digit == 4 ? 0x0f : - bits_per_digit == 3 ? 0x07 : - 0x01; - #if defined(PICOFORMAT_HANDLE_HEX) - const char* chars = FLAGS render_in_lowercase ? - pLowercaseNumberDigits : - pUppercaseNumberDigits; - #elif defined(PICOFORMAT_HANDLE_OCT) - const char* chars = pOctalDigits; - #elif defined(PICOFORMAT_HANDLE_BIN) - const char* chars = pBinaryDigits; - #endif // individual non-decimal formats - while (pDest < pEnd && - (pDest == pParamStarts || val || - pDest - pParamStarts < whole_chars)) { - char ch; - if (pDest == pParamStarts || - 0 != val) { // if first char or there's still meaningful digits - ch = chars[val & mask]; - val >>= bits_per_digit; - } else { - ch = FLAGS fill_zeros ? '0' : ' '; - } - *pDest++ = ch; - } - flip(pParamStarts, pDest); - } break; -#endif // defined(PICOFORMAT_HANDLE_BIN) || defined(PICOFORMAT_HANDLE_OCT) || defined(PICOFORMAT_HANDLE_HEX) - case 'd': // decimal integer - case 'i': { - long long int val = 0; - if (FLAGS treat_as_long) { - if (FLAGS treat_as_unsigned) { - val = va_arg( - vl, - unsigned long long int); - } else { - val = va_arg(vl, long long int); - } - } else { - if (FLAGS treat_as_unsigned) { - val = va_arg(vl, unsigned); - } else { - val = va_arg(vl, int); - } - } - char chSign = '\0'; - if ((FLAGS force_sign || val < 0) && - pDest < pEnd) { - chSign = val < 0 ? '-' : '+'; - val = llabs(val); - whole_chars--; - } - while (pDest < pEnd && - (pDest == pParamStarts || val || - pDest - pParamStarts < whole_chars)) { - char ch; - if (pDest == pParamStarts || - 0 != val) { // if first digit (i.e. zero) or there's still non-zero digits to write - ch = val % 10 + '0'; - val /= 10; - } else { - if ('\0' != chSign && - !FLAGS fill_zeros) { // write a sign if filling with spaces, not with zeros - *pDest++ = chSign; - whole_chars++; - chSign = - '\0'; // prevent the sign from being written twice - } -#ifdef PICOFORMAT_HANDLE_FILL - ch = FLAGS fill_zeros ? '0' : ' '; -#else // PICOFORMAT_HANDLE_FILL - break; -#endif // PICOFORMAT_HANDLE_FILL - } - *pDest++ = ch; - } - if ('\0' != - chSign) { // write a sign if it wasn't written before - *pDest++ = chSign; - } - flip(pParamStarts, pDest); - } break; -#ifdef PICOFORMAT_HANDLE_FLOATS - case 'f': - case 'F': { - double val = va_arg(vl, double); - if (FLAGS force_sign || val < 0.f) { - *pDest++ = val < 0.f ? '-' : '+'; - val = fabs(val); - pParamStarts = pDest; - } - if (val == INFINITY || val == -INFINITY || - isnan(val)) { - for (const char* pszVal = isnan(val) ? - FLAGS render_in_lowercase ? - "nan" : - "NAN" : - FLAGS render_in_lowercase ? - "inf" : - "INF"; - pDest < pEnd && *pszVal; - *pDest++ = *pszVal++) - ; - } else { - if (decimal_chars == -1) { - if (format == 'g') { - decimal_chars = 0; - } else { - decimal_chars = 6; - } - } - whole_chars = - MAX(0, - whole_chars - decimal_chars); - whole_chars = MAX( - whole_chars, - pDest - pParamStarts + - 1); // at least sign (if present) and first char - for (float digit = 1.f; pDest < pEnd && - (val >= digit || - pDest - pParamStarts < whole_chars); - digit *= 10.f) { - char ch = - (int) (val / digit) % 10 + - '0'; - *pDest++ = ch; - } - flip(pParamStarts, pDest); - if (decimal_chars && pDest < pEnd) { - *pDest++ = '.'; - val += .5f * - pow(10.f, - -decimal_chars); // compensating for rounding error - for (size_t digit = 0; - pDest < pEnd && - digit < decimal_chars; - digit++) { - val = (val - - (int) (val)) * - 10.f; - *pDest++ = - (int) (val) + '0'; - } - } - } - } break; -#endif // PICOFORMAT_HANDLE_FLOATS - } - } - } - } - *pDest = '\0'; - return pDest - pStart; -} - -int pico_snprintf(char* pDest, size_t cbDest, const char* pFormat, ...) -{ - va_list vl; - va_start(vl, pFormat); - int result = pico_vsnprintf(pDest, cbDest, pFormat, vl); - va_end(vl); - return result; -} diff --git a/firmware/common/picoprintf.h b/firmware/common/picoprintf.h deleted file mode 100644 index 313ee91d..00000000 --- a/firmware/common/picoprintf.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2023-2026 rom-p - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#pragma once - -#include // size_t -#include // va_* - -int pico_snprintf(char* pDest, size_t cbDest, const char* pFormat, ...); -int pico_vsnprintf(char* pDest, size_t cbDest, const char* pFormat, va_list vl); - -// PLEASE use `pico_snprintf()` instead!!! This function is vulnerable to buffer overflows -inline int pico_sprintf(char* pDest, const char* pFormat, ...) -{ - va_list vl; - va_start(vl, pFormat); - int result = pico_vsnprintf(pDest, -1, pFormat, vl); - va_end(vl); - return result; -} - -// -// IMPORTANT!!! -// comment/uncomment the following lines corresponding to the features you need -// -#define PICOFORMAT_HANDLE_FILL // uncomment this line to handle "%6i" and "%04d" -- the fill with zeroes or spaces -// #define PICOFORMAT_HANDLE_FORCEDSIGN // uncomment this line to handle "%+d" -- the forced sign placement -// #define PICOFORMAT_HANDLE_BIN // uncomment this line to handle "%b" -- binary representation -// #define PICOFORMAT_HANDLE_OCT // uncomment this line to handle "%o" -#define PICOFORMAT_HANDLE_HEX // uncomment this line to handle "%x" and "%X" -// #define PICOFORMAT_HANDLE_FLOATS // uncomment this line to handle the "%f" -// #define PICOFORMAT_CLANG_QUIRK // uncomment this line to match clang's non-standard "%010s" behavior (zero-pad strings when both '0' flag and width are set) - -// by default, the debug builds (determined by `#define _DEBUG`) will real-time print errors when a feature is used that is not enabled above -#ifndef FORMAT_ERROR_DELEGATE - #ifdef _DEBUG - #define FORMAT_ERROR_DELEGATE(__message, __arg) \ - printf(__message, __arg); \ - printf("\n"); - #else // _DEBUG - #define FORMAT_ERROR_DELEGATE(__message, __arg) - #endif // _DEBUG -#endif // FORMAT_ERROR_DELEGATE diff --git a/firmware/common/pins.c b/firmware/common/pins.c deleted file mode 100644 index 51cfec0f..00000000 --- a/firmware/common/pins.c +++ /dev/null @@ -1,256 +0,0 @@ -/* - * Copyright 2012-2026 Great Scott Gadgets - * Copyright 2012 Jared Boone - * Copyright 2013 Benjamin Vernoux - * - * This file is part of HackRF. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#include "pins.h" - -#include - -#include "gpio.h" -#include "leds.h" -#include "platform_detect.h" -#include "platform_gpio.h" -#include "platform_scu.h" -#include "power.h" -#ifdef IS_PRALINE - #include "clock_io.h" -#endif - -void pins_shutdown(void) -{ - /* Configure all GPIO as Input (safe state) */ - gpio_init(); - - /* Detect Platform */ - const platform_gpio_t* gpio = platform_gpio(); - const platform_scu_t* scu = platform_scu(); - - /* TDI and TMS pull-ups are required in all JTAG-compliant devices. - * - * The HackRF CPLD is always present, so let the CPLD pull up its TDI and TMS. - * - * The PortaPack may not be present, so pull up the PortaPack TMS pin from the - * microcontroller. - * - * TCK is recommended to be held low, so use microcontroller pull-down. - * - * TDO is undriven except when in Shift-IR or Shift-DR phases. - * Use the microcontroller to pull down to keep from floating. - * - * LPC43xx pull-up and pull-down resistors are approximately 53K. - */ -#ifdef IS_EXPANSION_COMPATIBLE - if (IS_EXPANSION_COMPATIBLE) { - scu_pinmux(scu->PINMUX_PP_TMS, SCU_GPIO_PUP | SCU_CONF_FUNCTION0); - scu_pinmux(scu->PINMUX_PP_TDO, SCU_GPIO_PDN | SCU_CONF_FUNCTION0); - } -#endif - scu_pinmux(scu->PINMUX_CPLD_TCK, SCU_GPIO_PDN | SCU_CONF_FUNCTION0); -#ifdef IS_NOT_PRALINE - if (IS_NOT_PRALINE) { - scu_pinmux(scu->PINMUX_CPLD_TMS, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0); - scu_pinmux(scu->PINMUX_CPLD_TDI, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0); - scu_pinmux(scu->PINMUX_CPLD_TDO, SCU_GPIO_PDN | SCU_CONF_FUNCTION4); - } -#endif - - /* Configure SCU Pin Mux as GPIO */ - scu_pinmux(scu->PINMUX_LED1, SCU_GPIO_NOPULL); - scu_pinmux(scu->PINMUX_LED2, SCU_GPIO_NOPULL); - scu_pinmux(scu->PINMUX_LED3, SCU_GPIO_NOPULL); -#ifdef IS_RAD1O - if (IS_RAD1O) { - scu_pinmux(scu->PINMUX_LED4, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION4); - } -#endif -#ifdef IS_PRALINE - if (IS_PRALINE) { - scu_pinmux(scu->PINMUX_LED4, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0); - } -#endif - - /* Configure USB indicators */ -#ifdef IS_JAWBREAKER - if (IS_JAWBREAKER) { - scu_pinmux(scu->PINMUX_USB_LED0, SCU_CONF_FUNCTION3); - scu_pinmux(scu->PINMUX_USB_LED1, SCU_CONF_FUNCTION3); - } -#endif - -#ifdef IS_PRALINE - if (IS_PRALINE) { - disable_1v2_power(); - disable_3v3aux_power(); - gpio_output(gpio->gpio_1v2_enable); - gpio_output(gpio->gpio_3v3aux_enable_n); - scu_pinmux(scu->PINMUX_EN1V2, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); - scu_pinmux(scu->PINMUX_EN3V3_AUX_N, SCU_GPIO_FAST | SCU_CONF_FUNCTION4); - } -#endif - -#ifdef IS_NOT_PRALINE - if (IS_NOT_PRALINE) { - disable_1v8_power(); - #ifdef IS_H1_R9 - if (IS_H1_R9) { - gpio_output(gpio->h1r9_1v8_enable); - scu_pinmux(scu->H1R9_EN1V8, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); - } - #endif - #ifdef IS_NOT_H1_R9 - if (IS_NOT_H1_R9) { - gpio_output(gpio->gpio_1v8_enable); - scu_pinmux(scu->PINMUX_EN1V8, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); - } - #endif - } -#endif - -#ifdef IS_H1_OR_PRALINE - if (IS_H1_OR_PRALINE) { - /* Safe state: start with VAA turned off: */ - disable_rf_power(); - - /* Configure RF power supply (VAA) switch control signal as output */ - #ifdef IS_H1_R9 - if (IS_H1_R9) { - gpio_output(gpio->h1r9_vaa_disable); - } - #endif - #ifdef IS_NOT_H1_R9 - if (IS_NOT_H1_R9) { - gpio_output(gpio->vaa_disable); - } - #endif - } -#endif - -#ifdef IS_RAD1O - if (IS_RAD1O) { - /* Safe state: start with VAA turned off: */ - disable_rf_power(); - - /* Configure RF power supply (VAA) switch control signal as output */ - gpio_output(gpio->vaa_enable); - - /* Disable unused clock outputs. They generate noise. */ - scu_pinmux(CLK0, SCU_CLK_IN | SCU_CONF_FUNCTION7); - scu_pinmux(CLK2, SCU_CLK_IN | SCU_CONF_FUNCTION7); - - scu_pinmux(scu->PINMUX_GPIO3_10, SCU_GPIO_PDN | SCU_CONF_FUNCTION0); - scu_pinmux(scu->PINMUX_GPIO3_11, SCU_GPIO_PDN | SCU_CONF_FUNCTION0); - } -#endif - -#ifdef IS_PRALINE - if (IS_PRALINE) { - scu_pinmux(scu->P2_CTRL0, scu->P2_CTRL0_PINCFG); - scu_pinmux(scu->P2_CTRL1, scu->P2_CTRL1_PINCFG); - scu_pinmux(scu->P1_CTRL0, scu->P1_CTRL0_PINCFG); - scu_pinmux(scu->P1_CTRL1, scu->P1_CTRL1_PINCFG); - scu_pinmux(scu->P1_CTRL2, scu->P1_CTRL2_PINCFG); - scu_pinmux(scu->CLKIN_CTRL, scu->CLKIN_CTRL_PINCFG); - scu_pinmux(scu->AA_EN, scu->AA_EN_PINCFG); - scu_pinmux(scu->TRIGGER_IN, scu->TRIGGER_IN_PINCFG); - scu_pinmux(scu->TRIGGER_OUT, scu->TRIGGER_OUT_PINCFG); - scu_pinmux(scu->PPS_OUT, scu->PPS_OUT_PINCFG); - scu_pinmux(scu->SCT_CLK, scu->SCT_CLK_PINCFG); - - scu_pinmux(scu->PINMUX_FPGA_CRESET, SCU_GPIO_PDN | SCU_CONF_FUNCTION0); - scu_pinmux(scu->PINMUX_FPGA_CDONE, SCU_GPIO_PDN | SCU_CONF_FUNCTION4); - scu_pinmux(scu->PINMUX_FPGA_SPI_CS, SCU_GPIO_PDN | SCU_CONF_FUNCTION0); - - scu_pinmux(scu->SSP1_CIPO, SCU_GPIO_PDN | SCU_CONF_FUNCTION0); - scu_pinmux(scu->SSP1_COPI, SCU_GPIO_PDN | SCU_CONF_FUNCTION0); - scu_pinmux(scu->SSP1_SCK, SCU_GPIO_PDN | SCU_CONF_FUNCTION2); - - scu_pinmux(scu->XCVR_ENABLE, SCU_GPIO_PDN | SCU_CONF_FUNCTION4); - scu_pinmux(scu->XCVR_RXENABLE, SCU_GPIO_PDN | SCU_CONF_FUNCTION4); - scu_pinmux(scu->XCVR_CS, SCU_GPIO_PDN | SCU_CONF_FUNCTION4); - scu_pinmux(scu->XCVR_RXHP, SCU_GPIO_PDN | SCU_CONF_FUNCTION4); - scu_pinmux(scu->XCVR_LD, SCU_GPIO_PDN | SCU_CONF_FUNCTION0); - - scu_pinmux(scu->MIXER_LD, SCU_GPIO_PDN | SCU_CONF_FUNCTION4); - scu_pinmux(scu->MIXER_SCLK, SCU_GPIO_PDN | SCU_CONF_FUNCTION4); - scu_pinmux(scu->MIXER_SDATA, SCU_GPIO_PDN | SCU_CONF_FUNCTION0); - scu_pinmux(scu->MIXER_ENX, SCU_GPIO_PDN | SCU_CONF_FUNCTION0); - scu_pinmux(scu->MIXER_RESETX, SCU_GPIO_PDN | SCU_CONF_FUNCTION0); - scu_pinmux(scu->MIXER_ENBL, SCU_GPIO_PDN | SCU_CONF_FUNCTION0); - - scu_pinmux(scu->AD_CS, SCU_GPIO_PDN | SCU_CONF_FUNCTION4); - - p2_ctrl_set(P2_SIGNAL_CLK3); - p1_ctrl_set(P1_SIGNAL_CLKIN); - clkin_ctrl_set(CLKIN_SIGNAL_P1); - - gpio_output(gpio->p2_ctrl0); - gpio_output(gpio->p2_ctrl1); - gpio_output(gpio->p1_ctrl0); - gpio_output(gpio->p1_ctrl1); - gpio_output(gpio->p1_ctrl2); - gpio_output(gpio->clkin_ctrl); - gpio_output(gpio->pps_out); - gpio_input(gpio->trigger_in); - gpio_input(gpio->trigger_out); - gpio_clear(gpio->fpga_cfg_spi_cs); - gpio_output(gpio->fpga_cfg_spi_cs); - gpio_clear(gpio->fpga_cfg_creset); - gpio_output(gpio->fpga_cfg_creset); - gpio_input(gpio->fpga_cfg_cdone); - gpio_input(gpio->max5864_select); - } -#endif - - /* enable input on SCL and SDA pins */ - SCU_SFSI2C0 = SCU_I2C0_NOMINAL; -} - -/* Run after pins_shutdown() and prior to enabling power supplies. */ -void pins_setup(void) -{ - /* Detect Platform */ - const platform_gpio_t* gpio = platform_gpio(); - const platform_scu_t* scu = platform_scu(); - - /* Configure LEDs */ - led_off(0); - led_off(1); - led_off(2); -#ifdef IS_FOUR_LEDS - if (IS_FOUR_LEDS) { - led_off(3); - } -#endif - - gpio_output(gpio->led[0]); - gpio_output(gpio->led[1]); - gpio_output(gpio->led[2]); - -#ifdef IS_FOUR_LEDS - if (IS_FOUR_LEDS) { - gpio_output(gpio->led[3]); - } -#endif - - /* Configure external clock in */ - scu_pinmux(scu->PINMUX_GP_CLKIN, SCU_CLK_IN | SCU_CONF_FUNCTION1); -} diff --git a/firmware/common/pins.h b/firmware/common/pins.h deleted file mode 100644 index bc109e5b..00000000 --- a/firmware/common/pins.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2012-2026 Great Scott Gadgets - * Copyright 2012 Benjamin Vernoux - * Copyright 2012 Jared Boone - * - * This file is part of HackRF. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -void pins_shutdown(void); -void pins_setup(void); - -#ifdef __cplusplus -} -#endif diff --git a/firmware/common/platform_detect.c b/firmware/common/platform_detect.c index 475ad1e1..ec00a3b8 100644 --- a/firmware/common/platform_detect.c +++ b/firmware/common/platform_detect.c @@ -19,24 +19,21 @@ * Boston, MA 02110-1301, USA. */ -#include - -#include "adc.h" -#include "delay.h" -#include "firmware_info.h" -#include "gpio.h" -#include "gpio_lpc.h" -#include "leds.h" #include "platform_detect.h" -#include "platform_scu.h" +#include "firmware_info.h" +#include "gpio_lpc.h" +#include "hackrf_core.h" +#include "adc.h" + +#include static board_id_t platform = BOARD_ID_UNDETECTED; static board_rev_t revision = BOARD_REV_UNDETECTED; -static struct gpio gpio2_9_on_P5_0 = GPIO(2, 9); -static struct gpio gpio3_6_on_P6_10 = GPIO(3, 6); -static struct gpio gpio3_4_on_P6_5 = GPIO(3, 4); -static struct gpio gpio2_6_on_P4_6 = GPIO(2, 6); +static struct gpio_t gpio2_9_on_P5_0 = GPIO(2, 9); +static struct gpio_t gpio3_6_on_P6_10 = GPIO(3, 6); +static struct gpio_t gpio3_4_on_P6_5 = GPIO(3, 4); +static struct gpio_t gpio2_6_on_P4_6 = GPIO(2, 6); #define P5_0_PUP (1 << 0) #define P5_0_PDN (1 << 1) @@ -63,9 +60,9 @@ static struct gpio gpio2_6_on_P4_6 = GPIO(2, 6); * hardware detection failure, but three LEDs are flashed if CPLD/FPGA configuration * fails. */ -static struct gpio gpio_led1 = GPIO(2, 1); -static struct gpio gpio_led2 = GPIO(2, 2); -static struct gpio gpio_led3 = GPIO(2, 8); +static struct gpio_t gpio_led1 = GPIO(2, 1); +static struct gpio_t gpio_led2 = GPIO(2, 2); +static struct gpio_t gpio_led3 = GPIO(2, 8); /* * Starting with r6, HackRF One has pin straps on ADC pins that indicate @@ -194,11 +191,11 @@ void detect_hardware_platform(void) /* activate internal pull-down */ scu_pinmux(P5_0, SCU_GPIO_PDN | SCU_CONF_FUNCTION0); scu_pinmux(P6_10, SCU_GPIO_PDN | SCU_CONF_FUNCTION0); - delay_us(4); + delay_us_at_mhz(4, 96); /* tri-state for a moment before testing input */ scu_pinmux(P5_0, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0); scu_pinmux(P6_10, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0); - delay_us(4); + delay_us_at_mhz(4, 96); /* if input rose quickly, there must be an external pull-up */ detected_resistors |= (gpio_read(&gpio2_9_on_P5_0)) ? P5_0_PUP : 0; detected_resistors |= (gpio_read(&gpio3_6_on_P6_10)) ? P6_10_PUP : 0; @@ -207,12 +204,12 @@ void detect_hardware_platform(void) scu_pinmux(P5_0, SCU_GPIO_PUP | SCU_CONF_FUNCTION0); scu_pinmux(P6_10, SCU_GPIO_PUP | SCU_CONF_FUNCTION0); scu_pinmux(P6_5, SCU_GPIO_PUP | SCU_CONF_FUNCTION0); - delay_us(4); + delay_us_at_mhz(4, 96); /* tri-state for a moment before testing input */ scu_pinmux(P5_0, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0); scu_pinmux(P6_10, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0); scu_pinmux(P6_5, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0); - delay_us(4); + delay_us_at_mhz(4, 96); /* if input fell quickly, there must be an external pull-down */ detected_resistors |= (gpio_read(&gpio2_9_on_P5_0)) ? 0 : P5_0_PDN; detected_resistors |= (gpio_read(&gpio3_6_on_P6_10)) ? 0 : P6_10_PDN; @@ -221,37 +218,37 @@ void detect_hardware_platform(void) switch (detected_resistors) { case JAWBREAKER_RESISTORS: if (!(supported_platform() & PLATFORM_JAWBREAKER)) { - halt_and_flash(500); + halt_and_flash(3000000); } platform = BOARD_ID_JAWBREAKER; return; case RAD1O_RESISTORS: if (!(supported_platform() & PLATFORM_RAD1O)) { - halt_and_flash(500); + halt_and_flash(3000000); } platform = BOARD_ID_RAD1O; return; case HACKRF1_OG_RESISTORS: if (!(supported_platform() & PLATFORM_HACKRF1_OG)) { - halt_and_flash(500); + halt_and_flash(3000000); } platform = BOARD_ID_HACKRF1_OG; break; case HACKRF1_R9_RESISTORS: if (!(supported_platform() & PLATFORM_HACKRF1_R9)) { - halt_and_flash(500); + halt_and_flash(3000000); } platform = BOARD_ID_HACKRF1_R9; break; case PRALINE_RESISTORS: if (!(supported_platform() & PLATFORM_PRALINE)) { - halt_and_flash(500); + halt_and_flash(3000000); } platform = BOARD_ID_PRALINE; break; default: platform = BOARD_ID_UNRECOGNIZED; - halt_and_flash(150); + halt_and_flash(1000000); } uint32_t adc0_3 = check_pin_strap(3); diff --git a/firmware/common/platform_detect.h b/firmware/common/platform_detect.h index 4f0f0f43..f02e733b 100644 --- a/firmware/common/platform_detect.h +++ b/firmware/common/platform_detect.h @@ -19,7 +19,8 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __PLATFORM_DETECT_H__ +#define __PLATFORM_DETECT_H__ #include @@ -75,3 +76,5 @@ void detect_hardware_platform(void); board_id_t detected_platform(void); board_rev_t detected_revision(void); uint32_t supported_platform(void); + +#endif //__PLATFORM_DETECT_H__ diff --git a/firmware/common/platform_gpio.c b/firmware/common/platform_gpio.c deleted file mode 100644 index eeecd90e..00000000 --- a/firmware/common/platform_gpio.c +++ /dev/null @@ -1,294 +0,0 @@ -/* - * Copyright 2012-2026 Great Scott Gadgets - * - * This file is part of HackRF. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#include "platform_gpio.h" - -#include - -#include "platform_detect.h" - -// clang-format off - -const platform_gpio_t* platform_gpio(void) -{ - static const platform_gpio_t* _platform_gpio = NULL; - if (_platform_gpio != NULL) { - return _platform_gpio; - } - - static platform_gpio_t gpio; - - /* LEDs */ - gpio.led[0] = &GPIO2_1; - gpio.led[1] = &GPIO2_2; - gpio.led[2] = &GPIO2_8; -#ifdef IS_RAD1O - if (IS_RAD1O) { - gpio.led[3] = &GPIO5_26; - } -#endif -#ifdef IS_PRALINE - if (IS_PRALINE) { - gpio.led[3] = &GPIO4_6; - } -#endif - - /* Power Supply Control */ -#ifdef IS_PRALINE - if (IS_PRALINE) { - gpio.gpio_1v2_enable = &GPIO4_7; - gpio.gpio_3v3aux_enable_n = &GPIO5_15; - } -#endif -#ifdef IS_NOT_PRALINE - if (IS_NOT_PRALINE) { - gpio.gpio_1v8_enable = &GPIO3_6; - } -#endif - - /* MAX283x GPIO (XCVR_CTL / CS_XCVR) PinMux */ -#ifdef IS_PRALINE - if (IS_PRALINE) { - gpio.max283x_select = &GPIO6_28; - gpio.max283x_enable = &GPIO7_1; - gpio.max283x_rx_enable = &GPIO7_2; - gpio.max2831_rxhp = &GPIO6_29; - gpio.max2831_ld = &GPIO4_11; - } -#endif -#ifdef IS_NOT_PRALINE - if (IS_NOT_PRALINE) { - gpio.max283x_select = &GPIO0_15; - gpio.max283x_enable = &GPIO2_6; - gpio.max283x_rx_enable = &GPIO2_5; - gpio.max283x_tx_enable = &GPIO2_4; - } -#endif - - /* MAX5864 SPI chip select (AD_CS / CS_AD) GPIO PinMux */ -#ifdef IS_PRALINE - if (IS_PRALINE) { - gpio.max5864_select = &GPIO6_30; - } -#endif -#ifdef IS_NOT_PRALINE - if (IS_NOT_PRALINE) { - gpio.max5864_select = &GPIO2_7; - } -#endif - - /* RF supply (VAA) control */ -#ifdef IS_HACKRF_ONE - if (IS_HACKRF_ONE) { - gpio.vaa_disable = &GPIO2_9; - } -#endif -#ifdef IS_PRALINE - if (IS_PRALINE) { - gpio.vaa_disable = &GPIO4_1; - } -#endif -#ifdef IS_RAD1O - if (IS_RAD1O) { - gpio.vaa_enable = &GPIO2_9; - } -#endif - - /* W25Q80BV Flash */ - gpio.w25q80bv_hold = &GPIO1_14; - gpio.w25q80bv_wp = &GPIO1_15; - gpio.w25q80bv_select = &GPIO5_11; - - /* RF switch control */ -#ifdef IS_HACKRF_ONE - if (IS_HACKRF_ONE) { - gpio.hp = &GPIO2_0; - gpio.lp = &GPIO2_10; - gpio.tx_mix_bp = &GPIO2_11; - gpio.no_mix_bypass = &GPIO1_0; - gpio.rx_mix_bp = &GPIO2_12; - gpio.tx_amp = &GPIO2_15; - gpio.tx = &GPIO5_15; - gpio.mix_bypass = &GPIO5_16; - gpio.rx = &GPIO5_5; - gpio.no_tx_amp_pwr = &GPIO3_5; - gpio.amp_bypass = &GPIO0_14; - gpio.rx_amp = &GPIO1_11; - gpio.no_rx_amp_pwr = &GPIO1_12; -#ifdef IS_H1_R9 - if (IS_H1_R9) { - gpio.h1r9_rx = &GPIO0_7; - gpio.h1r9_no_ant_pwr = &GPIO2_4; - } -#endif - } -#endif -#ifdef IS_RAD1O - if (IS_RAD1O) { - gpio.tx_rx_n = &GPIO1_11; - gpio.tx_rx = &GPIO0_14; - gpio.by_mix = &GPIO1_12; - gpio.by_mix_n = &GPIO2_10; - gpio.by_amp = &GPIO1_0; - gpio.by_amp_n = &GPIO5_5; - gpio.mixer_en = &GPIO5_16; - gpio.low_high_filt = &GPIO2_11; - gpio.low_high_filt_n = &GPIO2_12; - gpio.tx_amp = &GPIO2_15; - gpio.rx_lna = &GPIO5_15; - } -#endif -#ifdef IS_PRALINE - if (IS_PRALINE) { - gpio.tx_en = &GPIO3_4; - gpio.mix_en_n = &GPIO3_2; - gpio.mix_en_n_r1_0 = &GPIO5_6; - gpio.lpf_en = &GPIO4_8; - gpio.rf_amp_en = &GPIO4_9; - gpio.ant_bias_en_n = &GPIO1_12; - } -#endif - - /* CPLD JTAG interface GPIO pins_FPGA config pins in Praline */ - gpio.cpld_tck = &GPIO3_0; -#ifdef IS_PRALINE - if (IS_PRALINE) { - gpio.fpga_cfg_creset = &GPIO2_11; - gpio.fpga_cfg_cdone = &GPIO5_14; - gpio.fpga_cfg_spi_cs = &GPIO2_10; - } -#endif -#ifdef IS_NOT_PRALINE - if (IS_NOT_PRALINE) { - gpio.cpld_tdo = &GPIO5_18; - } -#endif -#ifdef IS_H1_OR_RAD1O - if (IS_H1_OR_RAD1O) { - gpio.cpld_tms = &GPIO3_4; - gpio.cpld_tdi = &GPIO3_1; - } -#endif -#ifdef IS_JAWBREAKER - if (IS_JAWBREAKER) { - gpio.cpld_tms = &GPIO3_1; - gpio.cpld_tdi = &GPIO3_4; - } -#endif -#ifdef IS_EXPANSION_COMPATIBLE - if (IS_EXPANSION_COMPATIBLE) { - gpio.cpld_pp_tms = &GPIO1_1; - gpio.cpld_pp_tdo = &GPIO1_8; - } -#endif - - /* Other CPLD interface GPIO pins */ -#ifdef IS_NOT_PRALINE - if (IS_NOT_PRALINE) { - gpio.trigger_enable = &GPIO5_12; - } -#endif - gpio.q_invert = &GPIO0_13; - - /* RFFC5071 GPIO serial interface PinMux */ -#ifdef IS_NOT_RAD1O - if (IS_NOT_RAD1O) { - gpio.rffc5072_select = &GPIO2_13; - gpio.rffc5072_clock = &GPIO5_6; - gpio.rffc5072_data = &GPIO3_3; - gpio.rffc5072_reset = &GPIO2_14; - } -#endif -#ifdef IS_RAD1O - if (IS_RAD1O) { - gpio.vco_ce = &GPIO2_13; - gpio.vco_sclk = &GPIO5_6; - gpio.vco_sdata = &GPIO3_3; - gpio.vco_le = &GPIO2_14; - gpio.vco_mux = &GPIO5_25; - gpio.synt_rfout_en = &GPIO3_5; - } -#endif -#ifdef IS_PRALINE - if (IS_PRALINE) { - gpio.rffc5072_select = &GPIO2_13; - gpio.rffc5072_clock = &GPIO5_18; - gpio.rffc5072_data = &GPIO4_14; - gpio.rffc5072_reset = &GPIO2_14; - gpio.rffc5072_ld = &GPIO6_25; - gpio.rffc5072_enbl = &GPIO4_12; - } -#endif - - /* Praline */ -#ifdef IS_PRALINE - if (IS_PRALINE) { - gpio.p2_ctrl0 = &GPIO7_3; - gpio.p2_ctrl1 = &GPIO7_4; - gpio.p1_ctrl0 = &GPIO0_14; - gpio.p1_ctrl1 = &GPIO5_16; - gpio.p1_ctrl2 = &GPIO3_5; - gpio.clkin_ctrl = &GPIO0_15; - gpio.aa_en = &GPIO1_7; - gpio.trigger_in = &GPIO6_26; - gpio.trigger_out = &GPIO5_6; - gpio.pps_out = &GPIO5_5; - } -#endif - - /* HackRF One r9 clock control */ -#ifdef IS_H1_R9 - if (IS_H1_R9) { - gpio.h1r9_clkin_en = &GPIO5_15; - gpio.h1r9_clkout_en = &GPIO0_9; - gpio.h1r9_mcu_clk_en = &GPIO0_8; - gpio.h1r9_1v8_enable = &GPIO2_9; - gpio.h1r9_vaa_disable = &GPIO3_6; - gpio.h1r9_trigger_enable = &GPIO5_5; - } -#endif - - /* rad1o LCD */ -#ifdef IS_RAD1O - if (IS_RAD1O) { - gpio.lcd_cs = &GPIO4_12; /* P9_0 */ - gpio.lcd_bl_en = &GPIO0_8; /* P1_1 */ - gpio.lcd_reset = &GPIO5_17; /* P9_4 */ - } -#endif - - /* Portapack */ -#ifdef IS_EXPANSION_COMPATIBLE - if (IS_EXPANSION_COMPATIBLE) { - gpio.io_stbx = &GPIO5_0; /* P2_0 */ - gpio.addr = &GPIO5_1; /* P2_1 */ - gpio.lcd_rdx = &GPIO5_4; /* P2_4 */ - gpio.lcd_wrx = &GPIO1_10; /* P2_9 */ - gpio.dir = &GPIO1_13; /* P2_13 */ - } -#endif - - _platform_gpio = &gpio; - - return _platform_gpio; -} - -// clang-format on diff --git a/firmware/common/platform_gpio.h b/firmware/common/platform_gpio.h deleted file mode 100644 index c57df96e..00000000 --- a/firmware/common/platform_gpio.h +++ /dev/null @@ -1,368 +0,0 @@ -/* - * Copyright 2012-2026 Great Scott Gadgets - * - * This file is part of HackRF. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -#include "gpio.h" -#include "gpio_lpc.h" - -typedef struct { - /* LEDs */ -#ifdef IS_FOUR_LEDS - gpio_t led[4]; -#else - gpio_t led[3]; -#endif - - /* Power Supply Control */ - gpio_t gpio_1v8_enable; -#ifdef IS_PRALINE - gpio_t gpio_1v2_enable; - gpio_t gpio_3v3aux_enable_n; -#endif - - /* MAX283x GPIO (XCVR_CTL / CS_XCVR) PinMux */ - gpio_t max283x_select; - gpio_t max283x_enable; - gpio_t max283x_rx_enable; - gpio_t max283x_tx_enable; -#ifdef IS_PRALINE - gpio_t max2831_rxhp; - gpio_t max2831_ld; -#endif - - /* MAX5864 SPI chip select (AD_CS / CS_AD) GPIO PinMux */ - gpio_t max5864_select; - - /* RF supply (VAA) control */ - gpio_t vaa_disable; -#ifdef IS_RAD1O - gpio_t vaa_enable; -#endif - - /* W25Q80BV Flash */ - gpio_t w25q80bv_hold; - gpio_t w25q80bv_wp; - gpio_t w25q80bv_select; - - /* RF switch control */ -#ifdef IS_HACKRF_ONE - gpio_t hp; - gpio_t lp; - gpio_t tx_mix_bp; - gpio_t no_mix_bypass; - gpio_t rx_mix_bp; - gpio_t tx_amp; - gpio_t tx; - gpio_t mix_bypass; - gpio_t rx; - gpio_t no_tx_amp_pwr; - gpio_t amp_bypass; - gpio_t rx_amp; - gpio_t no_rx_amp_pwr; - gpio_t h1r9_no_ant_pwr; // HACKRF_ONE r9 - gpio_t h1r9_rx; // HACKRF_ONE r9 -#endif -#ifdef IS_RAD1O - gpio_t tx_rx_n; - gpio_t tx_rx; - gpio_t by_mix; - gpio_t by_mix_n; - gpio_t by_amp; - gpio_t by_amp_n; - gpio_t mixer_en; - gpio_t low_high_filt; - gpio_t low_high_filt_n; - gpio_t tx_amp; - gpio_t rx_lna; -#endif -#ifdef IS_PRALINE - gpio_t tx_en; - gpio_t mix_en_n; - gpio_t mix_en_n_r1_0; - gpio_t lpf_en; - gpio_t rf_amp_en; - gpio_t ant_bias_en_n; -#endif - - /* CPLD JTAG interface GPIO pins, FPGA config pins in Praline */ - gpio_t cpld_tck; -#ifdef IS_NOT_PRALINE - gpio_t cpld_tdo; - gpio_t cpld_tms; - gpio_t cpld_tdi; -#endif -#ifdef IS_EXPANSION_COMPATIBLE - gpio_t cpld_pp_tms; - gpio_t cpld_pp_tdo; -#endif -#ifdef IS_PRALINE - gpio_t fpga_cfg_creset; - gpio_t fpga_cfg_cdone; - gpio_t fpga_cfg_spi_cs; -#endif - - /* Other CPLD interface GPIO pins */ -#ifdef IS_NOT_PRALINE - gpio_t trigger_enable; -#endif - gpio_t q_invert; - - /* RFFC5071 GPIO serial interface PinMux */ - gpio_t rffc5072_select; - gpio_t rffc5072_clock; - gpio_t rffc5072_data; - gpio_t rffc5072_reset; - gpio_t rffc5072_ld; // PRALINE - gpio_t rffc5072_enbl; // PRALINE - gpio_t vco_ce; // RAD1O - gpio_t vco_sclk; // RAD1O - gpio_t vco_sdata; // RAD1O - gpio_t vco_le; // RAD1O - gpio_t vco_mux; // RAD1O - gpio_t synt_rfout_en; // RAD1O - - /* Praline */ -#ifdef IS_PRALINE - gpio_t p2_ctrl0; - gpio_t p2_ctrl1; - gpio_t p1_ctrl0; - gpio_t p1_ctrl1; - gpio_t p1_ctrl2; - gpio_t clkin_ctrl; - gpio_t aa_en; - gpio_t trigger_in; - gpio_t trigger_out; - gpio_t pps_out; -#endif - -#ifdef IS_HACKRF_ONE - /* HackRF One r9 clock control */ - gpio_t h1r9_clkin_en; - gpio_t h1r9_clkout_en; - gpio_t h1r9_mcu_clk_en; - - gpio_t h1r9_1v8_enable; - gpio_t h1r9_vaa_disable; - gpio_t h1r9_trigger_enable; -#endif - - /* RAD1O */ -#ifdef IS_RAD1O - gpio_t lcd_cs; - gpio_t lcd_bl_en; - gpio_t lcd_reset; -#endif - - /* Portapack */ -#ifdef IS_EXPANSION_COMPATIBLE - gpio_t io_stbx; - gpio_t addr; - gpio_t lcd_rdx; - gpio_t lcd_wrx; - gpio_t dir; -#endif -} platform_gpio_t; - -// Detects and returns the global platform gpio instance of the active board id and revision. -const platform_gpio_t* platform_gpio(void); - -/* LPC43xx GPIO pre-declarations - we use these instead of the GPIO() - macro so that we can assign them at runtime. */ -static const struct gpio GPIO0_0 = GPIO(0, 0); -static const struct gpio GPIO0_1 = GPIO(0, 1); -static const struct gpio GPIO0_2 = GPIO(0, 2); -static const struct gpio GPIO0_3 = GPIO(0, 3); -static const struct gpio GPIO0_4 = GPIO(0, 4); -static const struct gpio GPIO0_5 = GPIO(0, 5); -static const struct gpio GPIO0_6 = GPIO(0, 6); -static const struct gpio GPIO0_7 = GPIO(0, 7); -static const struct gpio GPIO0_8 = GPIO(0, 8); -static const struct gpio GPIO0_9 = GPIO(0, 9); -static const struct gpio GPIO0_10 = GPIO(0, 10); -static const struct gpio GPIO0_11 = GPIO(0, 11); -static const struct gpio GPIO0_12 = GPIO(0, 12); -static const struct gpio GPIO0_13 = GPIO(0, 13); -static const struct gpio GPIO0_14 = GPIO(0, 14); -static const struct gpio GPIO0_15 = GPIO(0, 15); - -static const struct gpio GPIO1_0 = GPIO(1, 0); -static const struct gpio GPIO1_1 = GPIO(1, 1); -static const struct gpio GPIO1_2 = GPIO(1, 2); -static const struct gpio GPIO1_3 = GPIO(1, 3); -static const struct gpio GPIO1_4 = GPIO(1, 4); -static const struct gpio GPIO1_5 = GPIO(1, 5); -static const struct gpio GPIO1_6 = GPIO(1, 6); -static const struct gpio GPIO1_7 = GPIO(1, 7); -static const struct gpio GPIO1_8 = GPIO(1, 8); -static const struct gpio GPIO1_9 = GPIO(1, 9); -static const struct gpio GPIO1_10 = GPIO(1, 10); -static const struct gpio GPIO1_11 = GPIO(1, 11); -static const struct gpio GPIO1_12 = GPIO(1, 12); -static const struct gpio GPIO1_13 = GPIO(1, 13); -static const struct gpio GPIO1_14 = GPIO(1, 14); -static const struct gpio GPIO1_15 = GPIO(1, 15); - -static const struct gpio GPIO2_0 = GPIO(2, 0); -static const struct gpio GPIO2_1 = GPIO(2, 1); -static const struct gpio GPIO2_2 = GPIO(2, 2); -static const struct gpio GPIO2_3 = GPIO(2, 3); -static const struct gpio GPIO2_4 = GPIO(2, 4); -static const struct gpio GPIO2_5 = GPIO(2, 5); -static const struct gpio GPIO2_6 = GPIO(2, 6); -static const struct gpio GPIO2_7 = GPIO(2, 7); -static const struct gpio GPIO2_8 = GPIO(2, 8); -static const struct gpio GPIO2_9 = GPIO(2, 9); -static const struct gpio GPIO2_10 = GPIO(2, 10); -static const struct gpio GPIO2_11 = GPIO(2, 11); -static const struct gpio GPIO2_12 = GPIO(2, 12); -static const struct gpio GPIO2_13 = GPIO(2, 13); -static const struct gpio GPIO2_14 = GPIO(2, 14); -static const struct gpio GPIO2_15 = GPIO(2, 15); - -static const struct gpio GPIO3_0 = GPIO(3, 0); -static const struct gpio GPIO3_1 = GPIO(3, 1); -static const struct gpio GPIO3_2 = GPIO(3, 2); -static const struct gpio GPIO3_3 = GPIO(3, 3); -static const struct gpio GPIO3_4 = GPIO(3, 4); -static const struct gpio GPIO3_5 = GPIO(3, 5); -static const struct gpio GPIO3_6 = GPIO(3, 6); -static const struct gpio GPIO3_7 = GPIO(3, 7); -static const struct gpio GPIO3_8 = GPIO(3, 8); -static const struct gpio GPIO3_9 = GPIO(3, 9); -static const struct gpio GPIO3_10 = GPIO(3, 10); -static const struct gpio GPIO3_11 = GPIO(3, 11); -static const struct gpio GPIO3_12 = GPIO(3, 12); -static const struct gpio GPIO3_13 = GPIO(3, 13); -static const struct gpio GPIO3_14 = GPIO(3, 14); -static const struct gpio GPIO3_15 = GPIO(3, 15); - -static const struct gpio GPIO4_0 = GPIO(4, 0); -static const struct gpio GPIO4_1 = GPIO(4, 1); -static const struct gpio GPIO4_2 = GPIO(4, 2); -static const struct gpio GPIO4_3 = GPIO(4, 3); -static const struct gpio GPIO4_4 = GPIO(4, 4); -static const struct gpio GPIO4_5 = GPIO(4, 5); -static const struct gpio GPIO4_6 = GPIO(4, 6); -static const struct gpio GPIO4_7 = GPIO(4, 7); -static const struct gpio GPIO4_8 = GPIO(4, 8); -static const struct gpio GPIO4_9 = GPIO(4, 9); -static const struct gpio GPIO4_10 = GPIO(4, 10); -static const struct gpio GPIO4_11 = GPIO(4, 11); -static const struct gpio GPIO4_12 = GPIO(4, 12); -static const struct gpio GPIO4_13 = GPIO(4, 13); -static const struct gpio GPIO4_14 = GPIO(4, 14); -static const struct gpio GPIO4_15 = GPIO(4, 15); - -static const struct gpio GPIO5_0 = GPIO(5, 0); -static const struct gpio GPIO5_1 = GPIO(5, 1); -static const struct gpio GPIO5_2 = GPIO(5, 2); -static const struct gpio GPIO5_3 = GPIO(5, 3); -static const struct gpio GPIO5_4 = GPIO(5, 4); -static const struct gpio GPIO5_5 = GPIO(5, 5); -static const struct gpio GPIO5_6 = GPIO(5, 6); -static const struct gpio GPIO5_7 = GPIO(5, 7); -static const struct gpio GPIO5_8 = GPIO(5, 8); -static const struct gpio GPIO5_9 = GPIO(5, 9); -static const struct gpio GPIO5_10 = GPIO(5, 10); -static const struct gpio GPIO5_11 = GPIO(5, 11); -static const struct gpio GPIO5_12 = GPIO(5, 12); -static const struct gpio GPIO5_13 = GPIO(5, 13); -static const struct gpio GPIO5_14 = GPIO(5, 14); -static const struct gpio GPIO5_15 = GPIO(5, 15); -static const struct gpio GPIO5_16 = GPIO(5, 16); -static const struct gpio GPIO5_17 = GPIO(5, 17); -static const struct gpio GPIO5_18 = GPIO(5, 18); -static const struct gpio GPIO5_19 = GPIO(5, 19); -static const struct gpio GPIO5_20 = GPIO(5, 20); -static const struct gpio GPIO5_21 = GPIO(5, 21); -static const struct gpio GPIO5_22 = GPIO(5, 22); -static const struct gpio GPIO5_23 = GPIO(5, 23); -static const struct gpio GPIO5_24 = GPIO(5, 24); -static const struct gpio GPIO5_25 = GPIO(5, 25); -static const struct gpio GPIO5_26 = GPIO(5, 26); - -static const struct gpio GPIO6_0 = GPIO(6, 0); -static const struct gpio GPIO6_1 = GPIO(6, 1); -static const struct gpio GPIO6_2 = GPIO(6, 2); -static const struct gpio GPIO6_3 = GPIO(6, 3); -static const struct gpio GPIO6_4 = GPIO(6, 4); -static const struct gpio GPIO6_5 = GPIO(6, 5); -static const struct gpio GPIO6_6 = GPIO(6, 6); -static const struct gpio GPIO6_7 = GPIO(6, 7); -static const struct gpio GPIO6_8 = GPIO(6, 8); -static const struct gpio GPIO6_9 = GPIO(6, 9); -static const struct gpio GPIO6_10 = GPIO(6, 10); -static const struct gpio GPIO6_11 = GPIO(6, 11); -static const struct gpio GPIO6_12 = GPIO(6, 12); -static const struct gpio GPIO6_13 = GPIO(6, 13); -static const struct gpio GPIO6_14 = GPIO(6, 14); -static const struct gpio GPIO6_15 = GPIO(6, 15); -static const struct gpio GPIO6_16 = GPIO(6, 16); -static const struct gpio GPIO6_17 = GPIO(6, 17); -static const struct gpio GPIO6_18 = GPIO(6, 18); -static const struct gpio GPIO6_19 = GPIO(6, 19); -static const struct gpio GPIO6_20 = GPIO(6, 20); -static const struct gpio GPIO6_21 = GPIO(6, 21); -static const struct gpio GPIO6_22 = GPIO(6, 22); -static const struct gpio GPIO6_23 = GPIO(6, 23); -static const struct gpio GPIO6_24 = GPIO(6, 24); -static const struct gpio GPIO6_25 = GPIO(6, 25); -static const struct gpio GPIO6_26 = GPIO(6, 26); -static const struct gpio GPIO6_27 = GPIO(6, 27); -static const struct gpio GPIO6_28 = GPIO(6, 28); -static const struct gpio GPIO6_29 = GPIO(6, 29); -static const struct gpio GPIO6_30 = GPIO(6, 30); - -static const struct gpio GPIO7_0 = GPIO(7, 0); -static const struct gpio GPIO7_1 = GPIO(7, 1); -static const struct gpio GPIO7_2 = GPIO(7, 2); -static const struct gpio GPIO7_3 = GPIO(7, 3); -static const struct gpio GPIO7_4 = GPIO(7, 4); -static const struct gpio GPIO7_5 = GPIO(7, 5); -static const struct gpio GPIO7_6 = GPIO(7, 6); -static const struct gpio GPIO7_7 = GPIO(7, 7); -static const struct gpio GPIO7_8 = GPIO(7, 8); -static const struct gpio GPIO7_9 = GPIO(7, 9); -static const struct gpio GPIO7_10 = GPIO(7, 10); -static const struct gpio GPIO7_11 = GPIO(7, 11); -static const struct gpio GPIO7_12 = GPIO(7, 12); -static const struct gpio GPIO7_13 = GPIO(7, 13); -static const struct gpio GPIO7_14 = GPIO(7, 14); -static const struct gpio GPIO7_15 = GPIO(7, 15); -static const struct gpio GPIO7_16 = GPIO(7, 16); -static const struct gpio GPIO7_17 = GPIO(7, 17); -static const struct gpio GPIO7_18 = GPIO(7, 18); -static const struct gpio GPIO7_19 = GPIO(7, 19); -static const struct gpio GPIO7_20 = GPIO(7, 20); -static const struct gpio GPIO7_21 = GPIO(7, 21); -static const struct gpio GPIO7_22 = GPIO(7, 22); -static const struct gpio GPIO7_23 = GPIO(7, 23); -static const struct gpio GPIO7_24 = GPIO(7, 24); -static const struct gpio GPIO7_25 = GPIO(7, 25); - -#ifdef __cplusplus -} -#endif diff --git a/firmware/common/platform_scu.c b/firmware/common/platform_scu.c deleted file mode 100644 index c9e468e9..00000000 --- a/firmware/common/platform_scu.c +++ /dev/null @@ -1,462 +0,0 @@ -/* - * Copyright 2012-2026 Great Scott Gadgets - * - * This file is part of HackRF. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#include "platform_scu.h" - -#include - -#include - -#include "platform_detect.h" - -// clang-format off - -const platform_scu_t* platform_scu(void) -{ - static const platform_scu_t* _platform_scu = NULL; - if (_platform_scu != NULL) { - return _platform_scu; - } - - static platform_scu_t scu; - - /* LED PinMux */ - scu.PINMUX_LED1 = SCU_PINMUX_LED1; /* GPIO2[1] on P4_1 */ - scu.PINMUX_LED2 = SCU_PINMUX_LED2; /* GPIO2[2] on P4_2 */ - scu.PINMUX_LED3 = SCU_PINMUX_LED3; /* GPIO2[8] on P6_12 */ -#ifdef IS_RAD1O - if (IS_RAD1O) { - scu.PINMUX_LED4 = (PB_6); /* GPIO5[26] on PB_6 */ - } -#endif -#ifdef IS_PRALINE - if (IS_PRALINE) { - scu.PINMUX_LED4 = (P8_6); /* GPIO4[6] on P8_6 */ - } -#endif - - /* Power Supply PinMux */ - scu.PINMUX_EN1V8 = (P6_10); /* GPIO3[6] on P6_10 */ - scu.PINMUX_EN1V2 = (P8_7); /* GPIO4[7] on P8_7 */ -#ifdef IS_PRALINE - if (IS_PRALINE) { - scu.PINMUX_EN3V3_AUX_N = (P6_7); /* GPIO5[15] on P6_7 */ - scu.PINMUX_EN3V3_OC_N = (P6_11); /* GPIO3[7] on P6_11 */ - } -#endif - - /* GPIO Input PinMux */ - scu.PINMUX_BOOT0 = (P1_1); /* GPIO0[8] on P1_1 */ - scu.PINMUX_BOOT1 = (P1_2); /* GPIO0[9] on P1_2 */ -#ifdef IS_NOT_HACKRF_ONE - if (IS_NOT_HACKRF_ONE) { - scu.PINMUX_BOOT2 = (P2_8); /* GPIO5[7] on P2_8 */ - scu.PINMUX_BOOT3 = (P2_9); /* GPIO1[10] on P2_9 */ - } -#endif - - /* USB peripheral */ -#ifdef IS_JAWBREAKER - if (IS_JAWBREAKER) { - scu.PINMUX_USB_LED0 = (P6_8); - scu.PINMUX_USB_LED1 = (P6_7); - } -#endif - - /* SSP1 Peripheral PinMux */ - scu.SSP1_CIPO = (P1_3); /* P1_3 */ - scu.SSP1_COPI = (P1_4); /* P1_4 */ - scu.SSP1_SCK = (P1_19); /* P1_19 */ - scu.SSP1_CS = (P1_20); /* P1_20 */ - - /* CPLD JTAG interface */ - scu.PINMUX_CPLD_TCK = (P6_1); /* GPIO3[ 0] */ -#ifdef IS_PRALINE - if (IS_PRALINE) { - scu.PINMUX_FPGA_CRESET = (P5_2); /* GPIO2[11] on P5_2 */ - scu.PINMUX_FPGA_CDONE = (P4_10); /* GPIO5[14] */ - scu.PINMUX_FPGA_SPI_CS = (P5_1); /* GPIO2[10] */ - } -#endif -#ifdef IS_NOT_PRALINE - if (IS_NOT_PRALINE) { - scu.PINMUX_CPLD_TDO = (P9_5); /* GPIO5[18] */ - } -#endif -#ifdef IS_H1_OR_RAD1O - if (IS_H1_OR_RAD1O) { - scu.PINMUX_CPLD_TMS = (P6_5); /* GPIO3[ 4] */ - scu.PINMUX_CPLD_TDI = (P6_2); /* GPIO3[ 1] */ - } -#endif -#ifdef IS_JAWBREAKER - if (IS_JAWBREAKER) { - scu.PINMUX_CPLD_TMS = (P6_2); /* GPIO3[ 1] */ - scu.PINMUX_CPLD_TDI = (P6_5); /* GPIO3[ 4] */ - } -#endif - - /* CPLD SGPIO interface */ -#ifdef IS_PRALINE - if (IS_PRALINE) { - scu.PINMUX_SGPIO0 = (P0_0); - scu.PINMUX_SGPIO1 = (P0_1); - scu.PINMUX_SGPIO2 = (P1_15); - scu.PINMUX_SGPIO3 = (P1_16); - scu.PINMUX_SGPIO4 = (P9_4); - scu.PINMUX_SGPIO5 = (P6_6); - scu.PINMUX_SGPIO6 = (P2_2); - scu.PINMUX_SGPIO7 = (P1_0); - scu.PINMUX_SGPIO8 = (P8_0); - scu.PINMUX_SGPIO9 = (P9_3); - scu.PINMUX_SGPIO10 = (P8_2); - scu.PINMUX_SGPIO11 = (P1_17); - scu.PINMUX_SGPIO12 = (P1_18); - scu.PINMUX_SGPIO14 = (P1_18); - scu.PINMUX_SGPIO15 = (P1_18); - - scu.PINMUX_SGPIO0_PINCFG = (SCU_GPIO_FAST | SCU_CONF_FUNCTION3); - scu.PINMUX_SGPIO1_PINCFG = (SCU_GPIO_FAST | SCU_CONF_FUNCTION3); - scu.PINMUX_SGPIO2_PINCFG = (SCU_GPIO_FAST | SCU_CONF_FUNCTION2); - scu.PINMUX_SGPIO3_PINCFG = (SCU_GPIO_FAST | SCU_CONF_FUNCTION2); - scu.PINMUX_SGPIO4_PINCFG = (SCU_GPIO_FAST | SCU_CONF_FUNCTION6); - scu.PINMUX_SGPIO5_PINCFG = (SCU_GPIO_FAST | SCU_CONF_FUNCTION2); - scu.PINMUX_SGPIO6_PINCFG = (SCU_GPIO_FAST | SCU_CONF_FUNCTION0); - scu.PINMUX_SGPIO7_PINCFG = (SCU_GPIO_FAST | SCU_CONF_FUNCTION6); - scu.PINMUX_SGPIO8_PINCFG = (SCU_GPIO_FAST | SCU_CONF_FUNCTION4); - scu.PINMUX_SGPIO9_PINCFG = (SCU_GPIO_FAST | SCU_CONF_FUNCTION6); - scu.PINMUX_SGPIO10_PINCFG = (SCU_GPIO_FAST | SCU_CONF_FUNCTION4); - scu.PINMUX_SGPIO11_PINCFG = (SCU_GPIO_FAST | SCU_CONF_FUNCTION6); - scu.PINMUX_SGPIO12_PINCFG = (SCU_GPIO_FAST | SCU_CONF_FUNCTION0); - scu.PINMUX_SGPIO14_PINCFG = (SCU_GPIO_FAST | SCU_CONF_FUNCTION0); - scu.PINMUX_SGPIO15_PINCFG = (SCU_GPIO_FAST | SCU_CONF_FUNCTION0); - } -#endif -#ifdef IS_NOT_PRALINE - if (IS_NOT_PRALINE) { - scu.PINMUX_SGPIO0 = (P0_0); - scu.PINMUX_SGPIO1 = (P0_1); - scu.PINMUX_SGPIO2 = (P1_15); - scu.PINMUX_SGPIO3 = (P1_16); - scu.PINMUX_SGPIO4 = (P6_3); - scu.PINMUX_SGPIO5 = (P6_6); - scu.PINMUX_SGPIO6 = (P2_2); - scu.PINMUX_SGPIO7 = (P1_0); - scu.PINMUX_SGPIO8 = (P9_6); - scu.PINMUX_SGPIO9 = (P4_3); - scu.PINMUX_SGPIO10 = (P1_14); - scu.PINMUX_SGPIO11 = (P1_17); - scu.PINMUX_SGPIO12 = (P1_18); - scu.PINMUX_SGPIO14 = (P4_9); - scu.PINMUX_SGPIO15 = (P4_10); - - scu.PINMUX_SGPIO0_PINCFG = (SCU_GPIO_FAST | SCU_CONF_FUNCTION3); - scu.PINMUX_SGPIO1_PINCFG = (SCU_GPIO_FAST | SCU_CONF_FUNCTION3); - scu.PINMUX_SGPIO2_PINCFG = (SCU_GPIO_FAST | SCU_CONF_FUNCTION2); - scu.PINMUX_SGPIO3_PINCFG = (SCU_GPIO_FAST | SCU_CONF_FUNCTION2); - scu.PINMUX_SGPIO4_PINCFG = (SCU_GPIO_FAST | SCU_CONF_FUNCTION2); - scu.PINMUX_SGPIO5_PINCFG = (SCU_GPIO_FAST | SCU_CONF_FUNCTION2); - scu.PINMUX_SGPIO6_PINCFG = (SCU_GPIO_FAST | SCU_CONF_FUNCTION0); - scu.PINMUX_SGPIO7_PINCFG = (SCU_GPIO_FAST | SCU_CONF_FUNCTION6); - scu.PINMUX_SGPIO8_PINCFG = (SCU_GPIO_FAST | SCU_CONF_FUNCTION6); - scu.PINMUX_SGPIO9_PINCFG = (SCU_GPIO_FAST | SCU_CONF_FUNCTION7); - scu.PINMUX_SGPIO10_PINCFG = (SCU_GPIO_FAST | SCU_CONF_FUNCTION6); - scu.PINMUX_SGPIO11_PINCFG = (SCU_GPIO_FAST | SCU_CONF_FUNCTION6); - scu.PINMUX_SGPIO12_PINCFG = (SCU_GPIO_FAST | SCU_CONF_FUNCTION0); - scu.PINMUX_SGPIO14_PINCFG = (SCU_GPIO_FAST | SCU_CONF_FUNCTION4); - scu.PINMUX_SGPIO15_PINCFG = (SCU_GPIO_FAST | SCU_CONF_FUNCTION4); - } -#endif - scu.TRIGGER_EN = (P4_8); /* GPIO5[12] on P4_8 */ - - /* MAX283x GPIO (XCVR_CTL) PinMux */ -#ifdef IS_RAD1O - if (IS_RAD1O) { - scu.XCVR_RXHP = P8_1; /* GPIO[] on P8_1 */ - scu.XCVR_B6 = P8_2; /* GPIO[] on P8_2 */ - scu.XCVR_B7 = P9_3; /* GPIO[] on P9_3 */ - } -#endif -#ifdef IS_PRALINE - if (IS_PRALINE) { - scu.XCVR_ENABLE = PE_1; /* GPIO7[1] on PE_1 */ - scu.XCVR_RXENABLE = PE_2; /* GPIO7[2] on PE_2 */ - scu.XCVR_CS = PD_14; /* GPIO6[28] on PD_14 */ - scu.XCVR_RXHP = PD_15; /* GPIO6[29] on PD_15 */ - scu.XCVR_LD = P9_6; /* GPIO4[11] on P9_6 */ - - scu.XCVR_ENABLE_PINCFG = (SCU_GPIO_FAST | SCU_CONF_FUNCTION4); - scu.XCVR_RXENABLE_PINCFG = (SCU_GPIO_FAST | SCU_CONF_FUNCTION4); - scu.XCVR_CS_PINCFG = (SCU_GPIO_FAST | SCU_CONF_FUNCTION4); - scu.XCVR_RXHP_PINCFG = (SCU_GPIO_FAST | SCU_CONF_FUNCTION4); - scu.XCVR_LD_PINCFG = (SCU_GPIO_FAST | SCU_CONF_FUNCTION0 | - SCU_CONF_EPD_EN_PULLDOWN | SCU_CONF_EPUN_DIS_PULLUP); - } -#endif -#ifdef IS_H1_OR_JAWBREAKER - if (IS_H1_OR_JAWBREAKER) { - scu.XCVR_ENABLE = P4_6; /* GPIO2[6] on P4_6 */ - scu.XCVR_RXENABLE = P4_5; /* GPIO2[5] on P4_5 */ - scu.XCVR_TXENABLE = P4_4; /* GPIO2[4] on P4_4 */ - scu.XCVR_CS = P1_20; /* GPIO0[15] on P1_20 */ - - scu.XCVR_ENABLE_PINCFG = (SCU_GPIO_FAST); - scu.XCVR_RXENABLE_PINCFG = (SCU_GPIO_FAST); - scu.XCVR_TXENABLE_PINCFG = (SCU_GPIO_FAST); - scu.XCVR_CS_PINCFG = (SCU_GPIO_FAST); - } -#endif - - /* MAX5864 SPI chip select (AD_CS) GPIO PinMux */ -#ifdef IS_PRALINE - if (IS_PRALINE) { - scu.AD_CS = (PD_16); /* GPIO6[30] on PD_16 */ - scu.AD_CS_PINCFG = (SCU_GPIO_FAST | SCU_CONF_FUNCTION4); - } -#endif -#ifdef IS_NOT_PRALINE - if (IS_NOT_PRALINE) { - scu.AD_CS = (P5_7); /* GPIO2[7] on P5_7 */ - scu.AD_CS_PINCFG = (SCU_GPIO_FAST); - } -#endif - - /* RFFC5071 GPIO serial interface PinMux */ -#ifdef IS_H1_OR_JAWBREAKER - if (IS_H1_OR_JAWBREAKER) { - scu.MIXER_ENX = (P5_4); /* GPIO2[13] on P5_4 */ - scu.MIXER_SCLK = (P2_6); /* GPIO5[6] on P2_6 */ - scu.MIXER_SDATA = (P6_4); /* GPIO3[3] on P6_4 */ - scu.MIXER_RESETX = (P5_5); /* GPIO2[14] on P5_5 */ - - scu.MIXER_SCLK_PINCFG = (SCU_GPIO_FAST | SCU_CONF_FUNCTION4); - scu.MIXER_SDATA_PINCFG = (SCU_GPIO_FAST | SCU_CONF_FUNCTION0); - } -#endif -#ifdef IS_PRALINE - if (IS_PRALINE) { - scu.MIXER_ENX = (P5_4); /* GPIO2[13] on P5_4 */ - scu.MIXER_SCLK = (P9_5); /* GPIO5[18] on P9_5 */ - scu.MIXER_SDATA = (P9_2); /* GPIO4[14] on P9_2 */ - scu.MIXER_RESETX = (P5_5); /* GPIO2[14] on P5_5 */ - scu.MIXER_LD = (PD_11); /* GPIO6[25] on PD_11 */ - scu.MIXER_ENBL = (P9_0); /* GPIO4[12] on P9_0 */ - - scu.MIXER_SCLK_PINCFG = (SCU_GPIO_FAST | SCU_CONF_FUNCTION4); - scu.MIXER_SDATA_PINCFG = (SCU_GPIO_FAST | SCU_CONF_FUNCTION0); - scu.MIXER_LD_PINCFG = (SCU_GPIO_FAST | SCU_CONF_FUNCTION4); - scu.MIXER_ENBL_PINCFG = (SCU_GPIO_FAST | SCU_CONF_FUNCTION0); - } -#endif -#ifdef IS_RAD1O - if (IS_RAD1O) { - scu.VCO_CE = (P5_4); /* GPIO2[13] on P5_4 */ - scu.VCO_SCLK = (P2_6); /* GPIO5[6] on P2_6 */ - scu.VCO_SDATA = (P6_4); /* GPIO3[3] on P6_4 */ - scu.VCO_LE = (P5_5); /* GPIO2[14] on P5_5 */ - scu.VCO_MUX = (PB_5); /* GPIO5[25] on PB_5 */ - scu.MIXER_EN = (P6_8); /* GPIO5[16] on P6_8 */ - scu.SYNT_RFOUT_EN = (P6_9); /* GPIO3[5] on P6_9 */ - } -#endif - - /* RF LDO control */ -#ifdef IS_JAWBREAKER - if (IS_JAWBREAKER) { - scu.RF_LDO_ENABLE = (P5_0); /* GPIO2[9] on P5_0 */ - } -#endif - - /* RF supply (VAA) control */ -#ifdef IS_HACKRF_ONE - if (IS_HACKRF_ONE) { - scu.NO_VAA_ENABLE = P5_0; /* GPIO2[9] on P5_0 */ - } -#endif -#ifdef IS_PRALINE - if (IS_PRALINE) { - scu.NO_VAA_ENABLE = P8_1; /* GPIO4[1] on P8_1 */ - } -#endif -#ifdef IS_RAD1O - if (IS_RAD1O) { - scu.VAA_ENABLE = P5_0; /* GPIO2[9] on P5_0 */ - } -#endif - - /* SPI flash */ - scu.SSP0_CIPO = (P3_6); - scu.SSP0_COPI = (P3_7); - scu.SSP0_SCK = (P3_3); - scu.SSP0_CS = (P3_8); /* GPIO5[11] on P3_8 */ - scu.FLASH_HOLD = (P3_4); /* GPIO1[14] on P3_4 */ - scu.FLASH_WP = (P3_5); /* GPIO1[15] on P3_5 */ - - /* RF switch control */ -#ifdef IS_HACKRF_ONE - if (IS_HACKRF_ONE) { - scu.HP = P4_0; /* GPIO2[0] on P4_0 */ - scu.LP = P5_1; /* GPIO2[10] on P5_1 */ - scu.TX_MIX_BP = P5_2; /* GPIO2[11] on P5_2 */ - scu.NO_MIX_BYPASS = P1_7; /* GPIO1[0] on P1_7 */ - scu.RX_MIX_BP = P5_3; /* GPIO2[12] on P5_3 */ - scu.TX_AMP = P5_6; /* GPIO2[15] on P5_6 */ - scu.TX = P6_7; /* GPIO5[15] on P6_7 */ - scu.MIX_BYPASS = P6_8; /* GPIO5[16] on P6_8 */ - scu.RX = P2_5; /* GPIO5[5] on P2_5 */ - scu.NO_TX_AMP_PWR = P6_9; /* GPIO3[5] on P6_9 */ - scu.AMP_BYPASS = P2_10; /* GPIO0[14] on P2_10 */ - scu.RX_AMP = P2_11; /* GPIO1[11] on P2_11 */ - scu.NO_RX_AMP_PWR = P2_12; /* GPIO1[12] on P2_12 */ - } -#endif -#ifdef IS_RAD1O - if (IS_RAD1O) { - scu.BY_AMP = P1_7; /* GPIO1[0] on P1_7 */ - scu.BY_AMP_N = P2_5; /* GPIO5[5] on P2_5 */ - scu.TX_RX = P2_10; /* GPIO0[14] on P2_10 */ - scu.TX_RX_N = P2_11; /* GPIO1[11] on P2_11 */ - scu.BY_MIX = P2_12; /* GPIO1[12] on P2_12 */ - scu.BY_MIX_N = P5_1; /* GPIO2[10] on P5_1 */ - scu.LOW_HIGH_FILT = P5_2; /* GPIO2[11] on P5_2 */ - scu.LOW_HIGH_FILT_N = P5_3; /* GPIO2[12] on P5_3 */ - scu.TX_AMP = P5_6; /* GPIO2[15] on P5_6 */ - scu.RX_LNA = P6_7; /* GPIO5[15] on P6_7 */ - } -#endif -#ifdef IS_PRALINE - if (IS_PRALINE) { - scu.TX_EN = P6_5; /* GPIO3[4] on P6_5 */ - scu.MIX_EN_N = P6_3; /* GPIO3[2] on P6_3 */ - scu.MIX_EN_N_R1_0 = P2_6; /* GPIO5[6] on P2_6 */ - scu.LPF_EN = PA_1; /* GPIO4[8] on PA_1 */ - scu.RF_AMP_EN = PA_2; /* GPIO4[9] on PA_2 */ - scu.ANT_BIAS_EN_N = P2_12; /* GPIO1[12] on P2_12 */ - scu.ANT_BIAS_OC_N = P2_11; /* GPIO1[11] on P2_11 */ - } -#endif - - /* Praline */ -#ifdef IS_PRALINE - if (IS_PRALINE) { - scu.P2_CTRL0 = (PE_3); /* GPIO7[3] on PE_3 */ - scu.P2_CTRL1 = (PE_4); /* GPIO7[4] on PE_4 */ - scu.P1_CTRL0 = (P2_10); /* GPIO0[14] on P2_10 */ - scu.P1_CTRL1 = (P6_8); /* GPIO5[16] on P6_8 */ - scu.P1_CTRL2 = (P6_9); /* GPIO3[5] on P6_9 */ - scu.CLKIN_CTRL = (P1_20); /* GPIO0[15] on P1_20 */ - scu.AA_EN = (P1_14); /* GPIO1[7] on P1_14 */ - scu.TRIGGER_IN = (PD_12); /* GPIO6[26] on PD_12 */ - scu.TRIGGER_OUT = (P2_6); /* GPIO5[6] on P2_6 */ - scu.PPS_OUT = (P2_5); /* GPIO5[5] on P2_5 */ - scu.SCT_CLK = (P6_4); /* CTIN_6 on P6_4 */ - - scu.P2_CTRL0_PINCFG = (SCU_GPIO_FAST | SCU_CONF_FUNCTION4); - scu.P2_CTRL1_PINCFG = (SCU_GPIO_FAST | SCU_CONF_FUNCTION4); - scu.P1_CTRL0_PINCFG = (SCU_GPIO_FAST | SCU_CONF_FUNCTION0); - scu.P1_CTRL1_PINCFG = (SCU_GPIO_FAST | SCU_CONF_FUNCTION4); - scu.P1_CTRL2_PINCFG = (SCU_GPIO_FAST | SCU_CONF_FUNCTION0); - scu.CLKIN_CTRL_PINCFG = (SCU_GPIO_FAST | SCU_CONF_FUNCTION0); - scu.AA_EN_PINCFG = (SCU_GPIO_FAST | SCU_CONF_FUNCTION0); - scu.TRIGGER_IN_PINCFG = (SCU_GPIO_FAST | SCU_CONF_FUNCTION4); - scu.TRIGGER_OUT_PINCFG = (SCU_GPIO_FAST | SCU_CONF_FUNCTION4); - scu.PPS_OUT_PINCFG = (SCU_GPIO_FAST | SCU_CONF_FUNCTION4); - scu.SCT_CLK_PINCFG = (SCU_CLK_IN | SCU_CONF_FUNCTION1); - } -#endif - - /* HackRF One r9 */ -#ifdef IS_H1_R9 - if (IS_H1_R9) { - scu.H1R9_CLKIN_EN = P6_7; /* GPIO5[15] on P6_7 */ - scu.H1R9_CLKOUT_EN = P1_2; /* GPIO0[9] on P1_2 = has boot pull-down; */ - scu.H1R9_MCU_CLK_EN = P1_1; /* GPIO0[8] on P1_1 = has boot pull-up; */ - scu.H1R9_RX = P2_7; /* GPIO0[7] on P4_4 = has boot pull-up; */ - scu.H1R9_NO_ANT_PWR = P4_4; /* GPIO2[4] on P4_4 */ - scu.H1R9_EN1V8 = P5_0; /* GPIO2[9] on P5_0 */ - scu.H1R9_NO_VAA_EN = P6_10; /* GPIO3[6] on P6_10 */ - scu.H1R9_TRIGGER_EN = P2_5; /* GPIO5[5] on P2_5 */ - } -#endif - - /* Expansion headers */ -#ifdef IS_EXPANSION_COMPATIBLE - if (IS_EXPANSION_COMPATIBLE) { - scu.PINMUX_PP_D0 = (P7_0); /* GPIO3[8] */ - scu.PINMUX_PP_D1 = (P7_1); /* GPIO3[9] */ - scu.PINMUX_PP_D2 = (P7_2); /* GPIO3[10] */ - scu.PINMUX_PP_D3 = (P7_3); /* GPIO3[11] */ - scu.PINMUX_PP_D4 = (P7_4); /* GPIO3[12] */ - scu.PINMUX_PP_D5 = (P7_5); /* GPIO3[13] */ - scu.PINMUX_PP_D6 = (P7_6); /* GPIO3[14] */ - scu.PINMUX_PP_D7 = (P7_7); /* GPIO3[15] */ - - scu.PINMUX_PP_LCD_TE = (P2_3); /* GPIO5[3] on P2_3 */ - scu.PINMUX_PP_LCD_RDX = (P2_4); /* GPIO5[4] on P2_4 */ - scu.PINMUX_PP_UNUSED = (P2_8); /* GPIO5[7] on P2_8 */ - scu.PINMUX_PP_LCD_WRX = (P2_9); /* GPIO1[10] on P2_9 */ - scu.PINMUX_PP_DIR = (P2_13); /* GPIO1[13] on P2_13 */ - - scu.PINMUX_PP_TDO = (P1_5); /* GPIO1[8] */ - scu.PINMUX_SD_POW = (P1_5); /* GPIO1[8] */ - scu.PINMUX_SD_CMD = (P1_6); /* GPIO1[9] */ - scu.PINMUX_PP_TMS = (P1_8); /* GPIO1[1] */ - scu.PINMUX_SD_VOLT0 = (P1_8); /* GPIO1[1] */ - scu.PINMUX_SD_DAT0 = (P1_9); /* GPIO1[2] */ - scu.PINMUX_SD_DAT1 = (P1_10); /* GPIO1[3] */ - scu.PINMUX_SD_DAT2 = (P1_11); /* GPIO1[4] */ - scu.PINMUX_SD_DAT3 = (P1_12); /* GPIO1[5] */ - scu.PINMUX_SD_CD = (P1_13); /* GPIO1[6] */ - - scu.PINMUX_PP_IO_STBX = (P2_0); /* GPIO5[0] */ - scu.PINMUX_PP_ADDR = (P2_1); /* GPIO5[1] */ - scu.PINMUX_U0_TXD = (P2_0); /* GPIO5[0] */ - scu.PINMUX_U0_RXD = (P2_1); /* GPIO5[1] */ - - scu.PINMUX_GPIO3_8 = (P7_0); /* GPIO3[8] */ - scu.PINMUX_GPIO3_9 = (P7_1); /* GPIO3[9] */ - scu.PINMUX_GPIO3_10 = (P7_2); /* GPIO3[10] */ - scu.PINMUX_GPIO3_11 = (P7_3); /* GPIO3[11] */ - scu.PINMUX_GPIO3_12 = (P7_4); /* GPIO3[12] */ - scu.PINMUX_GPIO3_13 = (P7_5); /* GPIO3[13] */ - scu.PINMUX_GPIO3_14 = (P7_6); /* GPIO3[14] */ - scu.PINMUX_GPIO3_15 = (P7_7); /* GPIO3[15] */ - } -#endif - - /* SCT */ - scu.CTOUT_8 = (P7_7); - scu.CTOUT_11 = (P7_6); - scu.CTOUT_12 = (P7_5); - scu.CTOUT_13 = (P7_4); - scu.CTOUT_14 = (P7_0); - scu.CTOUT_PINCFG = (SCU_CONF_EPUN_DIS_PULLUP | SCU_CONF_EHS_FAST | SCU_CONF_FUNCTION1); - - scu.PINMUX_ISP = (P2_7); /* GPIO0[7] */ - - scu.PINMUX_GP_CLKIN = (P4_7); - - _platform_scu = &scu; - - return _platform_scu; -} - -// clang-format on diff --git a/firmware/common/platform_scu.h b/firmware/common/platform_scu.h deleted file mode 100644 index a3702bf7..00000000 --- a/firmware/common/platform_scu.h +++ /dev/null @@ -1,328 +0,0 @@ -/* - * Copyright 2012-2026 Great Scott Gadgets - * - * This file is part of HackRF. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -#include - -/* - * SCU PinMux - */ - -typedef struct { - /* GPIO Output PinMux */ - scu_grp_pin_t PINMUX_LED1; - scu_grp_pin_t PINMUX_LED2; - scu_grp_pin_t PINMUX_LED3; -#ifdef IS_FOUR_LEDS - scu_grp_pin_t PINMUX_LED4; -#endif - - scu_grp_pin_t PINMUX_EN1V8; - scu_grp_pin_t PINMUX_EN1V2; -#ifdef IS_PRALINE - scu_grp_pin_t PINMUX_EN3V3_AUX_N; - scu_grp_pin_t PINMUX_EN3V3_OC_N; -#endif - - /* GPIO Input PinMux */ - scu_grp_pin_t PINMUX_BOOT0; - scu_grp_pin_t PINMUX_BOOT1; -#ifdef IS_NOT_HACKRF_ONE - scu_grp_pin_t PINMUX_BOOT2; - scu_grp_pin_t PINMUX_BOOT3; -#endif - scu_grp_pin_t PINMUX_PP_LCD_TE; - scu_grp_pin_t PINMUX_PP_LCD_RDX; - scu_grp_pin_t PINMUX_PP_UNUSED; - scu_grp_pin_t PINMUX_PP_LCD_WRX; - scu_grp_pin_t PINMUX_PP_DIR; - - /* USB peripheral */ -#ifdef IS_JAWBREAKER - scu_grp_pin_t PINMUX_USB_LED0; - scu_grp_pin_t PINMUX_USB_LED1; -#endif - - /* SSP1 Peripheral PinMux */ - scu_grp_pin_t SSP1_CIPO; - scu_grp_pin_t SSP1_COPI; - scu_grp_pin_t SSP1_SCK; - scu_grp_pin_t SSP1_CS; - - /* CPLD JTAG interface */ -#ifdef IS_PRALINE - scu_grp_pin_t PINMUX_FPGA_CRESET; - scu_grp_pin_t PINMUX_FPGA_CDONE; - scu_grp_pin_t PINMUX_FPGA_SPI_CS; -#endif - scu_grp_pin_t PINMUX_CPLD_TDO; - scu_grp_pin_t PINMUX_CPLD_TCK; - scu_grp_pin_t PINMUX_CPLD_TMS; - scu_grp_pin_t PINMUX_CPLD_TDI; - - /* CPLD SGPIO interface */ - scu_grp_pin_t PINMUX_SGPIO0; - scu_grp_pin_t PINMUX_SGPIO1; - scu_grp_pin_t PINMUX_SGPIO2; - scu_grp_pin_t PINMUX_SGPIO3; - scu_grp_pin_t PINMUX_SGPIO4; - scu_grp_pin_t PINMUX_SGPIO5; - scu_grp_pin_t PINMUX_SGPIO6; - scu_grp_pin_t PINMUX_SGPIO7; - scu_grp_pin_t PINMUX_SGPIO8; - scu_grp_pin_t PINMUX_SGPIO9; - scu_grp_pin_t PINMUX_SGPIO10; - scu_grp_pin_t PINMUX_SGPIO11; - scu_grp_pin_t PINMUX_SGPIO12; - scu_grp_pin_t PINMUX_SGPIO14; - scu_grp_pin_t PINMUX_SGPIO15; - scu_grp_pin_t PINMUX_SGPIO0_PINCFG; - scu_grp_pin_t PINMUX_SGPIO1_PINCFG; - scu_grp_pin_t PINMUX_SGPIO2_PINCFG; - scu_grp_pin_t PINMUX_SGPIO3_PINCFG; - scu_grp_pin_t PINMUX_SGPIO4_PINCFG; - scu_grp_pin_t PINMUX_SGPIO5_PINCFG; - scu_grp_pin_t PINMUX_SGPIO6_PINCFG; - scu_grp_pin_t PINMUX_SGPIO7_PINCFG; - scu_grp_pin_t PINMUX_SGPIO8_PINCFG; - scu_grp_pin_t PINMUX_SGPIO9_PINCFG; - scu_grp_pin_t PINMUX_SGPIO10_PINCFG; - scu_grp_pin_t PINMUX_SGPIO11_PINCFG; - scu_grp_pin_t PINMUX_SGPIO12_PINCFG; - scu_grp_pin_t PINMUX_SGPIO14_PINCFG; - scu_grp_pin_t PINMUX_SGPIO15_PINCFG; - scu_grp_pin_t TRIGGER_EN; - - /* MAX283x GPIO (XCVR_CTL) PinMux */ - scu_grp_pin_t XCVR_ENABLE; - scu_grp_pin_t XCVR_RXENABLE; - scu_grp_pin_t XCVR_TXENABLE; - scu_grp_pin_t XCVR_CS; - uint32_t XCVR_ENABLE_PINCFG; - uint32_t XCVR_RXENABLE_PINCFG; - uint32_t XCVR_TXENABLE_PINCFG; - uint32_t XCVR_CS_PINCFG; -#ifdef IS_PRALINE - scu_grp_pin_t XCVR_LD; - uint32_t XCVR_LD_PINCFG; - uint32_t XCVR_RXHP_PINCFG; -#endif -#if defined(IS_RAD1O) || defined(IS_PRALINE) - scu_grp_pin_t XCVR_RXHP; -#endif -#ifdef IS_RAD1O - scu_grp_pin_t XCVR_B6; - scu_grp_pin_t XCVR_B7; -#endif - - /* MAX5864 SPI chip select (AD_CS) GPIO PinMux */ - scu_grp_pin_t AD_CS; - scu_grp_pin_t AD_CS_PINCFG; - - /* RFFC5071 GPIO serial interface PinMux */ -#ifdef IS_NOT_RAD1O - scu_grp_pin_t MIXER_ENX; - scu_grp_pin_t MIXER_SCLK; - scu_grp_pin_t MIXER_SDATA; - scu_grp_pin_t MIXER_RESETX; - uint32_t MIXER_SCLK_PINCFG; - uint32_t MIXER_SDATA_PINCFG; -#endif -#ifdef IS_PRALINE - scu_grp_pin_t MIXER_LD; - scu_grp_pin_t MIXER_ENBL; - uint32_t MIXER_LD_PINCFG; - uint32_t MIXER_ENBL_PINCFG; -#endif -#ifdef IS_RAD1O - scu_grp_pin_t VCO_CE; - scu_grp_pin_t VCO_SCLK; - scu_grp_pin_t VCO_SDATA; - scu_grp_pin_t VCO_LE; - scu_grp_pin_t VCO_MUX; - scu_grp_pin_t MIXER_EN; - scu_grp_pin_t SYNT_RFOUT_EN; -#endif - - /* RF LDO control */ -#ifdef IS_JAWBREAKER - scu_grp_pin_t RF_LDO_ENABLE; -#endif - - /* RF supply (VAA) control */ -#if defined(IS_PRALINE) || defined(IS_HACKRF_ONE) - scu_grp_pin_t NO_VAA_ENABLE; -#endif -#ifdef IS_RAD1O - scu_grp_pin_t VAA_ENABLE; -#endif - - /* SPI flash */ - scu_grp_pin_t SSP0_CIPO; - scu_grp_pin_t SSP0_COPI; - scu_grp_pin_t SSP0_SCK; - scu_grp_pin_t SSP0_CS; - scu_grp_pin_t FLASH_HOLD; - scu_grp_pin_t FLASH_WP; - - /* RF switch control */ -#ifdef IS_PRALINE - scu_grp_pin_t TX_EN; - scu_grp_pin_t MIX_EN_N; - scu_grp_pin_t MIX_EN_N_R1_0; - scu_grp_pin_t LPF_EN; - scu_grp_pin_t RF_AMP_EN; - scu_grp_pin_t ANT_BIAS_EN_N; - scu_grp_pin_t ANT_BIAS_OC_N; -#endif -#ifdef IS_HACKRF_ONE - scu_grp_pin_t HP; - scu_grp_pin_t LP; - scu_grp_pin_t TX_MIX_BP; - scu_grp_pin_t NO_MIX_BYPASS; - scu_grp_pin_t RX_MIX_BP; - scu_grp_pin_t TX_AMP; - scu_grp_pin_t TX; - scu_grp_pin_t MIX_BYPASS; - scu_grp_pin_t RX; - scu_grp_pin_t NO_TX_AMP_PWR; - scu_grp_pin_t AMP_BYPASS; - scu_grp_pin_t RX_AMP; - scu_grp_pin_t NO_RX_AMP_PWR; -#endif -#ifdef IS_RAD1O - scu_grp_pin_t BY_AMP; - scu_grp_pin_t BY_AMP_N; - scu_grp_pin_t TX_RX; - scu_grp_pin_t TX_RX_N; - scu_grp_pin_t BY_MIX; - scu_grp_pin_t BY_MIX_N; - scu_grp_pin_t LOW_HIGH_FILT; - scu_grp_pin_t LOW_HIGH_FILT_N; - scu_grp_pin_t TX_AMP; - scu_grp_pin_t RX_LNA; -#endif - - /* Praline */ -#ifdef IS_PRALINE - scu_grp_pin_t P2_CTRL0; - scu_grp_pin_t P2_CTRL1; - scu_grp_pin_t P1_CTRL0; - scu_grp_pin_t P1_CTRL1; - scu_grp_pin_t P1_CTRL2; - scu_grp_pin_t CLKIN_CTRL; - scu_grp_pin_t AA_EN; - scu_grp_pin_t TRIGGER_IN; - scu_grp_pin_t TRIGGER_OUT; - scu_grp_pin_t PPS_OUT; - scu_grp_pin_t SCT_CLK; - - scu_grp_pin_t P2_CTRL0_PINCFG; - scu_grp_pin_t P2_CTRL1_PINCFG; - scu_grp_pin_t P1_CTRL0_PINCFG; - scu_grp_pin_t P1_CTRL1_PINCFG; - scu_grp_pin_t P1_CTRL2_PINCFG; - scu_grp_pin_t CLKIN_CTRL_PINCFG; - scu_grp_pin_t AA_EN_PINCFG; - scu_grp_pin_t TRIGGER_IN_PINCFG; - scu_grp_pin_t TRIGGER_OUT_PINCFG; - scu_grp_pin_t PPS_OUT_PINCFG; - scu_grp_pin_t SCT_CLK_PINCFG; -#endif - - /* HackRF One r9 */ -#ifdef IS_HACKRF_ONE - scu_grp_pin_t H1R9_CLKIN_EN; - scu_grp_pin_t H1R9_CLKOUT_EN; - scu_grp_pin_t H1R9_MCU_CLK_EN; - scu_grp_pin_t H1R9_RX; - scu_grp_pin_t H1R9_NO_ANT_PWR; - scu_grp_pin_t H1R9_EN1V8; - scu_grp_pin_t H1R9_NO_VAA_EN; - scu_grp_pin_t H1R9_TRIGGER_EN; -#endif - - /* Miscellaneous */ - scu_grp_pin_t PINMUX_PP_D0; - scu_grp_pin_t PINMUX_PP_D1; - scu_grp_pin_t PINMUX_PP_D2; - scu_grp_pin_t PINMUX_PP_D3; - scu_grp_pin_t PINMUX_PP_D4; - scu_grp_pin_t PINMUX_PP_D5; - scu_grp_pin_t PINMUX_PP_D6; - scu_grp_pin_t PINMUX_PP_D7; - /* TODO add other Pins */ - scu_grp_pin_t PINMUX_GPIO3_8; - scu_grp_pin_t PINMUX_GPIO3_9; - scu_grp_pin_t PINMUX_GPIO3_10; - scu_grp_pin_t PINMUX_GPIO3_11; - scu_grp_pin_t PINMUX_GPIO3_12; - scu_grp_pin_t PINMUX_GPIO3_13; - scu_grp_pin_t PINMUX_GPIO3_14; - scu_grp_pin_t PINMUX_GPIO3_15; - - scu_grp_pin_t PINMUX_PP_TDO; - scu_grp_pin_t PINMUX_SD_POW; - scu_grp_pin_t PINMUX_SD_CMD; - scu_grp_pin_t PINMUX_PP_TMS; - scu_grp_pin_t PINMUX_SD_VOLT0; - scu_grp_pin_t PINMUX_SD_DAT0; - scu_grp_pin_t PINMUX_SD_DAT1; - scu_grp_pin_t PINMUX_SD_DAT2; - scu_grp_pin_t PINMUX_SD_DAT3; - scu_grp_pin_t PINMUX_SD_CD; - - scu_grp_pin_t PINMUX_PP_IO_STBX; - scu_grp_pin_t PINMUX_PP_ADDR; - scu_grp_pin_t PINMUX_U0_TXD; - scu_grp_pin_t PINMUX_U0_RXD; - - /* SCT */ - scu_grp_pin_t CTOUT_8; - scu_grp_pin_t CTOUT_11; - scu_grp_pin_t CTOUT_12; - scu_grp_pin_t CTOUT_13; - scu_grp_pin_t CTOUT_14; - scu_grp_pin_t CTOUT_PINCFG; - - scu_grp_pin_t PINMUX_ISP; - - scu_grp_pin_t PINMUX_GP_CLKIN; -} platform_scu_t; - -// Detects and returns the global platform scu instance of the active board id and revision. -const platform_scu_t* platform_scu(void); - -// Platform detection needs these for error indication. -#define SCU_PINMUX_LED1 (P4_1) /* GPIO2[1] on P4_1 */ -#define SCU_PINMUX_LED2 (P4_2) /* GPIO2[2] on P4_2 */ -#define SCU_PINMUX_LED3 (P6_12) /* GPIO2[8] on P6_12 */ - -#ifdef __cplusplus -} -#endif diff --git a/firmware/common/portapack.c b/firmware/common/portapack.c index b84bf03c..e123affa 100644 --- a/firmware/common/portapack.c +++ b/firmware/common/portapack.c @@ -22,16 +22,31 @@ #include "portapack.h" +#include "hackrf_core.h" +#include "gpio_lpc.h" + #include -#include "cpld_jtag.h" -#include "delay.h" -#include "gpio.h" -#include "gpio_lpc.h" -#include "platform_gpio.h" -#include "platform_scu.h" +static void portapack_sleep_milliseconds(const uint32_t milliseconds) +{ + /* NOTE: Naively assumes 204 MHz instruction cycle clock and five instructions per count */ + delay(milliseconds * 40800); +} -typedef struct { +// clang-format off +static struct gpio_t gpio_io_stbx = GPIO(5, 0); /* P2_0 */ +static struct gpio_t gpio_addr = GPIO(5, 1); /* P2_1 */ +__attribute__((unused)) +static struct gpio_t gpio_lcd_te = GPIO(5, 3); /* P2_3 */ +__attribute__((unused)) +static struct gpio_t gpio_unused = GPIO(5, 7); /* P2_8 */ +static struct gpio_t gpio_lcd_rdx = GPIO(5, 4); /* P2_4 */ +static struct gpio_t gpio_lcd_wrx = GPIO(1, 10); /* P2_9 */ +static struct gpio_t gpio_dir = GPIO(1, 13); /* P2_13 */ + +// clang-format on + +typedef struct portapack_if_t { gpio_t gpio_dir; gpio_t gpio_lcd_rdx; gpio_t gpio_lcd_wrx; @@ -42,6 +57,11 @@ typedef struct { } portapack_if_t; static portapack_if_t portapack_if = { + .gpio_dir = &gpio_dir, + .gpio_lcd_rdx = &gpio_lcd_rdx, + .gpio_lcd_wrx = &gpio_lcd_wrx, + .gpio_io_stbx = &gpio_io_stbx, + .gpio_addr = &gpio_addr, .gpio_port_data = GPIO_LPC_PORT(3), .io_reg = 0x03, }; @@ -50,7 +70,7 @@ static portapack_if_t portapack_if = { #define GPIO_DATA_SHIFT (8) static const uint32_t gpio_data_mask = 0xFFU << GPIO_DATA_SHIFT; -static void portapack_data_mask_set(void) +static void portapack_data_mask_set() { portapack_if.gpio_port_data->mask = ~gpio_data_mask; } @@ -67,13 +87,13 @@ static void portapack_data_write_high(const uint32_t value) portapack_if.gpio_port_data->mpin = value; } -static void portapack_dir_read(void) +static void portapack_dir_read() { portapack_if.gpio_port_data->dir &= ~gpio_data_mask; gpio_set(portapack_if.gpio_dir); } -static void portapack_dir_write(void) +static void portapack_dir_write() { gpio_clear(portapack_if.gpio_dir); portapack_if.gpio_port_data->dir |= gpio_data_mask; @@ -85,32 +105,32 @@ static void portapack_dir_write(void) */ } -__attribute__((unused)) static void portapack_lcd_rd_assert(void) +__attribute__((unused)) static void portapack_lcd_rd_assert() { gpio_clear(portapack_if.gpio_lcd_rdx); } -static void portapack_lcd_rd_deassert(void) +static void portapack_lcd_rd_deassert() { gpio_set(portapack_if.gpio_lcd_rdx); } -static void portapack_lcd_wr_assert(void) +static void portapack_lcd_wr_assert() { gpio_clear(portapack_if.gpio_lcd_wrx); } -static void portapack_lcd_wr_deassert(void) +static void portapack_lcd_wr_deassert() { gpio_set(portapack_if.gpio_lcd_wrx); } -static void portapack_io_stb_assert(void) +static void portapack_io_stb_assert() { gpio_clear(portapack_if.gpio_io_stbx); } -static void portapack_io_stb_deassert(void) +static void portapack_io_stb_deassert() { gpio_set(portapack_if.gpio_io_stbx); } @@ -168,17 +188,8 @@ static void portapack_io_write(const bool address, const uint_fast16_t value) portapack_io_stb_deassert(); } -static void portapack_if_init(void) +static void portapack_if_init() { - const platform_gpio_t* gpio = platform_gpio(); - const platform_scu_t* scu = platform_scu(); - - portapack_if.gpio_dir = gpio->dir; - portapack_if.gpio_lcd_rdx = gpio->lcd_rdx; - portapack_if.gpio_lcd_wrx = gpio->lcd_wrx; - portapack_if.gpio_io_stbx = gpio->io_stbx; - portapack_if.gpio_addr = gpio->addr; - portapack_data_mask_set(); portapack_data_write_high(0); @@ -196,22 +207,22 @@ static void portapack_if_init(void) /* gpio_input(portapack_if.gpio_rot_a); */ /* gpio_input(portapack_if.gpio_rot_b); */ - scu_pinmux(scu->PINMUX_PP_D0, SCU_CONF_FUNCTION0 | SCU_GPIO_PDN); - scu_pinmux(scu->PINMUX_PP_D1, SCU_CONF_FUNCTION0 | SCU_GPIO_PDN); - scu_pinmux(scu->PINMUX_PP_D2, SCU_CONF_FUNCTION0 | SCU_GPIO_PDN); - scu_pinmux(scu->PINMUX_PP_D3, SCU_CONF_FUNCTION0 | SCU_GPIO_PDN); - scu_pinmux(scu->PINMUX_PP_D4, SCU_CONF_FUNCTION0 | SCU_GPIO_PDN); - scu_pinmux(scu->PINMUX_PP_D5, SCU_CONF_FUNCTION0 | SCU_GPIO_PDN); - scu_pinmux(scu->PINMUX_PP_D6, SCU_CONF_FUNCTION0 | SCU_GPIO_PDN); - scu_pinmux(scu->PINMUX_PP_D7, SCU_CONF_FUNCTION0 | SCU_GPIO_PDN); + scu_pinmux(SCU_PINMUX_PP_D0, SCU_CONF_FUNCTION0 | SCU_GPIO_PDN); + scu_pinmux(SCU_PINMUX_PP_D1, SCU_CONF_FUNCTION0 | SCU_GPIO_PDN); + scu_pinmux(SCU_PINMUX_PP_D2, SCU_CONF_FUNCTION0 | SCU_GPIO_PDN); + scu_pinmux(SCU_PINMUX_PP_D3, SCU_CONF_FUNCTION0 | SCU_GPIO_PDN); + scu_pinmux(SCU_PINMUX_PP_D4, SCU_CONF_FUNCTION0 | SCU_GPIO_PDN); + scu_pinmux(SCU_PINMUX_PP_D5, SCU_CONF_FUNCTION0 | SCU_GPIO_PDN); + scu_pinmux(SCU_PINMUX_PP_D6, SCU_CONF_FUNCTION0 | SCU_GPIO_PDN); + scu_pinmux(SCU_PINMUX_PP_D7, SCU_CONF_FUNCTION0 | SCU_GPIO_PDN); - scu_pinmux(scu->PINMUX_PP_DIR, SCU_CONF_FUNCTION0 | SCU_GPIO_NOPULL); - scu_pinmux(scu->PINMUX_PP_LCD_RDX, SCU_CONF_FUNCTION4 | SCU_GPIO_NOPULL); - scu_pinmux(scu->PINMUX_PP_LCD_WRX, SCU_CONF_FUNCTION0 | SCU_GPIO_NOPULL); - scu_pinmux(scu->PINMUX_PP_IO_STBX, SCU_CONF_FUNCTION4 | SCU_GPIO_NOPULL); - scu_pinmux(scu->PINMUX_PP_ADDR, SCU_CONF_FUNCTION4 | SCU_GPIO_NOPULL); - /* scu_pinmux(scu->PINMUX_PP_LCD_TE, SCU_CONF_FUNCTION4 | SCU_GPIO_NOPULL); */ - /* scu_pinmux(scu->PINMUX_PP_UNUSED, SCU_CONF_FUNCTION4 | SCU_GPIO_NOPULL); */ + scu_pinmux(SCU_PINMUX_PP_DIR, SCU_CONF_FUNCTION0 | SCU_GPIO_NOPULL); + scu_pinmux(SCU_PINMUX_PP_LCD_RDX, SCU_CONF_FUNCTION4 | SCU_GPIO_NOPULL); + scu_pinmux(SCU_PINMUX_PP_LCD_WRX, SCU_CONF_FUNCTION0 | SCU_GPIO_NOPULL); + scu_pinmux(SCU_PINMUX_PP_IO_STBX, SCU_CONF_FUNCTION4 | SCU_GPIO_NOPULL); + scu_pinmux(SCU_PINMUX_PP_ADDR, SCU_CONF_FUNCTION4 | SCU_GPIO_NOPULL); + /* scu_pinmux(SCU_PINMUX_PP_LCD_TE, SCU_CONF_FUNCTION4 | SCU_GPIO_NOPULL); */ + /* scu_pinmux(SCU_PINMUX_PP_UNUSED, SCU_CONF_FUNCTION4 | SCU_GPIO_NOPULL); */ } static void portapack_lcd_reset_state(const bool active) @@ -231,23 +242,23 @@ static void portapack_lcd_data_write_command_and_data( } } -static void portapack_lcd_sleep_out(void) +static void portapack_lcd_sleep_out() { const uint8_t cmd_11[] = {}; portapack_lcd_data_write_command_and_data(0x11, cmd_11, ARRAY_SIZEOF(cmd_11)); // "It will be necessary to wait 120msec after sending Sleep Out // command (when in Sleep In Mode) before Sleep In command can be // sent." - delay_ms(120); + portapack_sleep_milliseconds(120); } -static void portapack_lcd_display_on(void) +static void portapack_lcd_display_on() { const uint8_t cmd_29[] = {}; portapack_lcd_data_write_command_and_data(0x29, cmd_29, ARRAY_SIZEOF(cmd_29)); } -static void portapack_lcd_ramwr_start(void) +static void portapack_lcd_ramwr_start() { const uint8_t cmd_2c[] = {}; portapack_lcd_data_write_command_and_data(0x2c, cmd_2c, ARRAY_SIZEOF(cmd_2c)); @@ -295,23 +306,23 @@ static void portapack_lcd_write_pixels_color(const ui_color_t c, size_t n) } } -static void portapack_lcd_wake(void) +static void portapack_lcd_wake() { portapack_lcd_sleep_out(); portapack_lcd_display_on(); } -static void portapack_lcd_reset(void) +static void portapack_lcd_reset() { portapack_lcd_reset_state(false); - delay_ms(1); + portapack_sleep_milliseconds(1); portapack_lcd_reset_state(true); - delay_ms(10); + portapack_sleep_milliseconds(10); portapack_lcd_reset_state(false); - delay_ms(120); + portapack_sleep_milliseconds(120); } -static void portapack_lcd_init(void) +static void portapack_lcd_init() { // LCDs are configured for IM[2:0] = 001 // 8080-I system, 16-bit parallel bus @@ -610,23 +621,23 @@ static bool portapack_detect(void) return idcode == 0x020A50DD || idcode == 0x00025610; } -static bool portapack_detected = false; +static const portapack_t portapack_instance = {}; -bool portapack_present(void) +static const portapack_t* portapack_pointer = NULL; + +const portapack_t* portapack(void) { - return portapack_detected; + return portapack_pointer; } -bool portapack_init(void) +void portapack_init(void) { if (portapack_detect()) { portapack_if_init(); portapack_lcd_reset(); portapack_lcd_init(); - portapack_detected = true; + portapack_pointer = &portapack_instance; } else { - portapack_detected = false; + portapack_pointer = NULL; } - - return portapack_detected; } diff --git a/firmware/common/portapack.h b/firmware/common/portapack.h index 3926bc3f..b24e75f1 100644 --- a/firmware/common/portapack.h +++ b/firmware/common/portapack.h @@ -20,39 +20,40 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __PORTAPACK_H__ +#define __PORTAPACK_H__ -#include -#include #include +#include +#include #define ARRAY_SIZEOF(x) (sizeof(x) / sizeof(x[0])) -typedef struct { +typedef struct ui_color_t { uint16_t v; } ui_color_t; -typedef struct { +typedef struct ui_point_t { int16_t x; int16_t y; } ui_point_t; -typedef struct { +typedef struct ui_size_t { int16_t width; int16_t height; } ui_size_t; -typedef struct { +typedef struct ui_rect_t { ui_point_t point; ui_size_t size; } ui_rect_t; -typedef struct { +typedef struct ui_bitmap_t { ui_size_t size; const uint8_t* const data; } ui_bitmap_t; -typedef struct { +typedef struct ui_font_t { const ui_size_t glyph_size; const uint8_t* const data; char c_start; @@ -60,16 +61,18 @@ typedef struct { size_t data_stride; } ui_font_t; -typedef struct { +typedef struct portapack_t { } portapack_t; -bool portapack_init(void); +void portapack_init(void); -bool portapack_present(void); +/* If the "portapack" symbol is defined, PortaPack support is compiled in */ +/* If the portapack() call returns non-NULL, a PortaPack was detected and is initialized. */ +const portapack_t* portapack(void) __attribute__((weak)); void portapack_backlight(const bool on); -void portapack_reference_oscillator(const bool on); +void portapack_reference_oscillator(const bool on) __attribute__((weak)); void portapack_fill_rectangle(const ui_rect_t rect, const ui_color_t color); @@ -82,3 +85,5 @@ void portapack_draw_bitmap( const ui_color_t background); ui_bitmap_t portapack_font_glyph(const ui_font_t* const font, const char c); + +#endif /*__PORTAPACK_H__*/ diff --git a/firmware/common/power.c b/firmware/common/power.c deleted file mode 100644 index 70c8c0f1..00000000 --- a/firmware/common/power.c +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright 2026 Great Scott Gadgets - * - * This file is part of HackRF. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#include "power.h" - -#if defined(IS_HACKRF_ONE) - #include -#endif - -#include "gpio.h" -#include "platform_detect.h" -#include "platform_gpio.h" -#if defined(IS_PRALINE) || defined(IS_RAD1O) - #include "delay.h" -#endif - -#ifdef IS_PRALINE -void enable_1v2_power(void) -{ - if (IS_PRALINE) { - gpio_set(platform_gpio()->gpio_1v2_enable); - } -} - -void disable_1v2_power(void) -{ - if (IS_PRALINE) { - gpio_clear(platform_gpio()->gpio_1v2_enable); - } -} - -void enable_3v3aux_power(void) -{ - if (IS_PRALINE) { - gpio_clear(platform_gpio()->gpio_3v3aux_enable_n); - } -} - -void disable_3v3aux_power(void) -{ - if (IS_PRALINE) { - gpio_set(platform_gpio()->gpio_3v3aux_enable_n); - } -} -#endif - -void enable_1v8_power(void) -{ -#ifdef IS_NOT_PRALINE - if (IS_NOT_PRALINE) { - #ifdef IS_H1_R9 - if (IS_H1_R9) { - gpio_set(platform_gpio()->h1r9_1v8_enable); - } - #endif - #ifdef IS_NOT_H1_R9 - if (IS_NOT_H1_R9) { - gpio_set(platform_gpio()->gpio_1v8_enable); - } - #endif - } -#endif -} - -void disable_1v8_power(void) -{ -#ifdef IS_NOT_PRALINE - if (IS_NOT_PRALINE) { - #ifdef IS_H1_R9 - if (IS_H1_R9) { - gpio_clear(platform_gpio()->h1r9_1v8_enable); - } - #endif - #ifdef IS_NOT_H1_R9 - if (IS_NOT_H1_R9) { - gpio_clear(platform_gpio()->gpio_1v8_enable); - } - #endif - } -#endif -} - -#ifdef IS_HACKRF_ONE -static inline void enable_rf_power_hackrf_one(void) -{ - const platform_gpio_t* gpio = platform_gpio(); - uint32_t i; - - /* many short pulses to avoid one big voltage glitch */ - for (i = 0; i < 1000; i++) { - if (detected_platform() == BOARD_ID_HACKRF1_R9) { - gpio_set(gpio->h1r9_vaa_disable); - gpio_clear(gpio->h1r9_vaa_disable); - } else { - gpio_set(gpio->vaa_disable); - gpio_clear(gpio->vaa_disable); - } - } -} - -static inline void disable_rf_power_hackrf_one(void) -{ - if (detected_platform() == BOARD_ID_HACKRF1_R9) { - gpio_set(platform_gpio()->h1r9_vaa_disable); - } else { - gpio_set(platform_gpio()->vaa_disable); - } -} -#endif - -#ifdef IS_PRALINE -static inline void enable_rf_power_praline(void) -{ - gpio_clear(platform_gpio()->vaa_disable); - - /* Let the voltage stabilize */ - delay_ms(35); -} - -static inline void disable_rf_power_praline(void) -{ - gpio_set(platform_gpio()->vaa_disable); -} -#endif - -#ifdef IS_RAD1O -static inline void enable_rf_power_rad1o(void) -{ - gpio_set(platform_gpio()->vaa_enable); - - /* Let the voltage stabilize */ - delay_ms(35); -} - -static inline void disable_rf_power_rad1o(void) -{ - gpio_clear(platform_gpio()->vaa_enable); -} -#endif - -void enable_rf_power(void) -{ -#ifdef IS_HACKRF_ONE - if (IS_HACKRF_ONE) { - enable_rf_power_hackrf_one(); - } -#endif -#ifdef IS_PRALINE - if (IS_PRALINE) { - enable_rf_power_praline(); - } -#endif -#ifdef IS_RAD1O - if (IS_RAD1O) { - enable_rf_power_rad1o(); - } -#endif -} - -void disable_rf_power(void) -{ -#ifdef IS_HACKRF_ONE - if (IS_HACKRF_ONE) { - disable_rf_power_hackrf_one(); - } -#endif -#ifdef IS_PRALINE - if (IS_PRALINE) { - disable_rf_power_praline(); - } -#endif -#ifdef IS_RAD1O - if (IS_RAD1O) { - disable_rf_power_rad1o(); - } -#endif -} diff --git a/firmware/common/power.h b/firmware/common/power.h deleted file mode 100644 index fc8af67a..00000000 --- a/firmware/common/power.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2026 Great Scott Gadgets - * - * This file is part of HackRF. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef IS_PRALINE -void enable_1v2_power(void); -void disable_1v2_power(void); -void enable_3v3aux_power(void); -void disable_3v3aux_power(void); -#endif -void enable_1v8_power(void); -void disable_1v8_power(void); - -#if defined(IS_RAD1O) || defined(IS_HACKRF_ONE) || defined(IS_PRALINE) -void enable_rf_power(void); -void disable_rf_power(void); -#endif - -#ifdef __cplusplus -} -#endif diff --git a/firmware/common/rad1o/decoder.c b/firmware/common/rad1o/decoder.c index 53d3636c..46791756 100644 --- a/firmware/common/rad1o/decoder.c +++ b/firmware/common/rad1o/decoder.c @@ -1,7 +1,8 @@ -#include - +#include "fonts.h" #include "render.h" +#include + // Local function: Get next nibble. static int ctr = 0; // offset for next nibble static int hilo = 0; // 0= high nibble next, 1=low nibble next @@ -11,7 +12,7 @@ static const uint8_t* data; static uint8_t charBuf[MAXCHR]; // Get next nibble -static uint8_t gnn(void) +static uint8_t gnn() { static uint8_t byte; uint8_t val; diff --git a/firmware/common/rad1o/decoder.h b/firmware/common/rad1o/decoder.h index 5575ef93..5f1bcda4 100644 --- a/firmware/common/rad1o/decoder.h +++ b/firmware/common/rad1o/decoder.h @@ -1,5 +1,8 @@ -#pragma once +#ifndef __RAD1O_DECODER_H__ +#define __RAD1O_DECODER_H__ #include uint8_t* rad1o_pk_decode(const uint8_t* data, int* len); + +#endif diff --git a/firmware/common/rad1o/display.c b/firmware/common/rad1o/display.c index c0c090b3..517db0a0 100644 --- a/firmware/common/rad1o/display.c +++ b/firmware/common/rad1o/display.c @@ -1,18 +1,24 @@ #include "display.h" +#include "gpio_lpc.h" +#include "hackrf_core.h" + +#include +#include + #include #include #include -#include +static void delayms(const uint32_t milliseconds) +{ + /* NOTE: Naively assumes 204 MHz instruction cycle clock and five instructions per count */ + delay(milliseconds * 40800); +} -#include "gpio.h" -#include "gpio_lpc.h" -#include "delay.h" - -static struct gpio gpio_lcd_cs = GPIO(4, 12); /* P9_0 */ -static struct gpio gpio_lcd_bl_en = GPIO(0, 8); /* P1_1 */ -static struct gpio gpio_lcd_reset = GPIO(5, 17); /* P9_4 */ +static struct gpio_t gpio_lcd_cs = GPIO(4, 12); /* P9_0 */ +static struct gpio_t gpio_lcd_bl_en = GPIO(0, 8); /* P1_1 */ +static struct gpio_t gpio_lcd_reset = GPIO(5, 17); /* P9_4 */ /**************************************************************************/ /* Utility routines to manage nokia display */ @@ -24,7 +30,7 @@ static uint8_t lcdBuffer[RESX * RESY]; static bool isTurned; -static void select(void) +static void select() { /* * The LCD requires 9-Bit frames @@ -52,7 +58,7 @@ static void select(void) gpio_clear(&gpio_lcd_cs); } -static void deselect(void) +static void deselect() { gpio_set(&gpio_lcd_cs); } @@ -79,9 +85,9 @@ void rad1o_lcdInit(void) // Reset the display gpio_clear(&gpio_lcd_reset); - delay_ms(100); + delayms(100); gpio_set(&gpio_lcd_reset); - delay_ms(100); + delayms(100); select(); @@ -109,7 +115,7 @@ void rad1o_lcdInit(void) (1 << 12) | (0 << 13) | (0 << 14) | 0); write(0, 0x01); /* most color displays need the pause */ - delay_ms(10); + delayms(10); size_t i = 0; while (i < sizeof(initseq_d)) { diff --git a/firmware/common/rad1o/display.h b/firmware/common/rad1o/display.h index af5da5e1..7a9e077f 100644 --- a/firmware/common/rad1o/display.h +++ b/firmware/common/rad1o/display.h @@ -1,10 +1,10 @@ -#pragma once +#ifndef __RAD1O_DISPLAY_H__ +#define __RAD1O_DISPLAY_H__ + +#include #include -#include -#include - #define RESX 130 #define RESY 130 @@ -26,3 +26,5 @@ void rad1o_lcdFill(uint8_t f); void rad1o_lcdDisplay(void); void rad1o_lcdSetPixel(uint8_t x, uint8_t y, uint8_t f); uint8_t* rad1o_lcdGetBuffer(void); + +#endif diff --git a/firmware/common/rad1o/draw.h b/firmware/common/rad1o/draw.h index dfdaaf68..c8f6708b 100644 --- a/firmware/common/rad1o/draw.h +++ b/firmware/common/rad1o/draw.h @@ -1,6 +1,9 @@ -#pragma once +#ifndef __RAD1O_DRAW_H__ +#define __RAD1O_DRAW_H__ #include void rad1o_drawHLine(uint8_t y, uint8_t x1, uint8_t x2, uint8_t color); void rad1o_drawVLine(uint8_t x, uint8_t y1, uint8_t y2, uint8_t color); + +#endif diff --git a/firmware/common/rad1o/fonts.h b/firmware/common/rad1o/fonts.h index bd1ce0b5..98e0a7ac 100644 --- a/firmware/common/rad1o/fonts.h +++ b/firmware/common/rad1o/fonts.h @@ -1,4 +1,5 @@ -#pragma once +#ifndef __RAD1O_FONTS_H__ +#define __RAD1O_FONTS_H__ #include @@ -30,3 +31,5 @@ typedef const struct FONT_DEF* FONT; #define FONT_DEFAULT 0 #define FONT_INTERNAL 1 #define FONT_EXTERNAL 2 + +#endif diff --git a/firmware/common/rad1o/print.c b/firmware/common/rad1o/print.c index 345af5e0..4b9958cd 100644 --- a/firmware/common/rad1o/print.c +++ b/firmware/common/rad1o/print.c @@ -1,29 +1,15 @@ #include "print.h" - -#include -#include -#include - -#include - #include "display.h" +#include "fonts.h" #include "render.h" #include "smallfonts.h" static int32_t x = 0; static int32_t y = 0; -void rad1o_lcdPrint(const char* fmt, ...) +void rad1o_lcdPrint(const char* string) { - va_list args1, args2; - va_start(args1, fmt); - va_copy(args2, args1); - int buflen = pico_vsnprintf(NULL, 0, fmt, args1) + 1; - va_end(args1); - char* buf = alloca(buflen); - pico_vsnprintf(buf, buflen, fmt, args2); - va_end(args2); - x = rad1o_DoString(x, y, buf); + x = rad1o_DoString(x, y, string); } void rad1o_lcdNl(void) diff --git a/firmware/common/rad1o/print.h b/firmware/common/rad1o/print.h index 858f1b22..19ef1631 100644 --- a/firmware/common/rad1o/print.h +++ b/firmware/common/rad1o/print.h @@ -1,10 +1,13 @@ -#pragma once +#ifndef __RAD1O_PRINT_H__ +#define __RAD1O_PRINT_H__ #include -void rad1o_lcdPrint(const char* string, ...); +void rad1o_lcdPrint(const char* string); void rad1o_lcdNl(void); void rad1o_lcdClear(void); void rad1o_lcdMoveCrsr(int32_t dx, int32_t dy); void rad1o_lcdSetCrsr(int32_t dx, int32_t dy); void rad1o_setSystemFont(void); + +#endif diff --git a/firmware/common/rad1o/render.h b/firmware/common/rad1o/render.h index 535ee471..dcfdd6c8 100644 --- a/firmware/common/rad1o/render.h +++ b/firmware/common/rad1o/render.h @@ -1,6 +1,5 @@ -#pragma once - -#include +#ifndef __RENDER_H_ +#define __RENDER_H_ #include "fonts.h" @@ -9,3 +8,4 @@ void rad1o_setIntFont(const struct FONT_DEF* font); int rad1o_getFontHeight(void); int rad1o_DoString(int sx, int sy, const char* s); int rad1o_DoChar(int sx, int sy, int c); +#endif diff --git a/firmware/common/rad1o/smallfonts.c b/firmware/common/rad1o/smallfonts.c index 7bae79ee..14413a75 100644 --- a/firmware/common/rad1o/smallfonts.c +++ b/firmware/common/rad1o/smallfonts.c @@ -37,14 +37,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /**************************************************************************/ - #include "smallfonts.h" -#include -#include - -#include "fonts.h" - /* System 7x8 */ const uint8_t au8Font7x8[] = { 0, 0, 0, 0, 0, 0, 0, //' ' diff --git a/firmware/common/rad1o/smallfonts.h b/firmware/common/rad1o/smallfonts.h index 3204e62a..d195c28b 100644 --- a/firmware/common/rad1o/smallfonts.h +++ b/firmware/common/rad1o/smallfonts.h @@ -35,10 +35,17 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /**************************************************************************/ +#ifndef __RAD1O_SMALLFONTS_H__ +#define __RAD1O_SMALLFONTS_H__ -#pragma once +#include "fonts.h" + +#include +#include /* Partially based on original code for the KS0108 by Stephane Rey */ /* Current version by Kevin Townsend */ extern const struct FONT_DEF Font_7x8; + +#endif diff --git a/firmware/common/rad1o/ubuntu18.c b/firmware/common/rad1o/ubuntu18.c index 524667ff..d47ef49d 100644 --- a/firmware/common/rad1o/ubuntu18.c +++ b/firmware/common/rad1o/ubuntu18.c @@ -1,9 +1,5 @@ #include "ubuntu18.h" -#include - -#include "fonts.h" - /* Font data for Ubuntu Regular 18pt */ /* Copyright 2010 Canonical Ltd. Licensed under the Ubuntu Font Licence 1.0 diff --git a/firmware/common/rad1o/ubuntu18.h b/firmware/common/rad1o/ubuntu18.h index b8d28b07..fe9a9923 100644 --- a/firmware/common/rad1o/ubuntu18.h +++ b/firmware/common/rad1o/ubuntu18.h @@ -1,3 +1,7 @@ -#pragma once +#ifndef __RAD1O_UBUNTU18_H__ +#define __RAD1O_UBUNTU18_H__ +#include "fonts.h" extern const struct FONT_DEF Font_Ubuntu18pt; + +#endif diff --git a/firmware/common/radio.c b/firmware/common/radio.c index 36f65cad..29aba95c 100644 --- a/firmware/common/radio.c +++ b/firmware/common/radio.c @@ -1,5 +1,7 @@ /* - * Copyright 2025-2026 Great Scott Gadgets + * Copyright 2012-2025 Great Scott Gadgets + * Copyright 2012 Jared Boone + * Copyright 2013 Benjamin Vernoux * * This file is part of HackRF. * @@ -19,994 +21,533 @@ * Boston, MA 02110-1301, USA. */ +#include "hackrf_core.h" +#include "tuning.h" + #include "radio.h" -#include +radio_error_t radio_set_sample_rate( + radio_t* radio, + radio_chan_id chan_id, + radio_sample_rate_id element, + radio_sample_rate_t sample_rate) +{ + // we only support the clock generator at the moment + if (element != RADIO_SAMPLE_RATE_CLOCKGEN) { + return RADIO_ERR_INVALID_ELEMENT; + } -#include + radio_config_t* config = &radio->channel[chan_id].config; -#include "clock_gen.h" -#include "clock_io.h" -#include "fixed_point.h" -#include "max283x.h" -#include "mixer.h" -#include "platform_detect.h" -#include "rf_path.h" -#include "transceiver_mode.h" -#include "tuning.h" -#include "u128.h" -#ifdef IS_PRALINE - #include "fpga.h" - #include "tune_config.h" + /* + * Store the sample rate rounded to the nearest Hz for convenience. + */ + if (sample_rate.div == 0) { + return RADIO_ERR_INVALID_PARAM; + } + sample_rate.hz = (sample_rate.num + (sample_rate.div >> 1)) / sample_rate.div; + + if (config->mode == TRANSCEIVER_MODE_OFF) { + config->sample_rate[element] = sample_rate; + return RADIO_OK; + } + +#ifdef PRALINE + #define MAX_AFE_RATE 40000000 + #define MAX_N 5 + uint8_t n = 0; // resampling ratio is 2**n + if ((config->mode == TRANSCEIVER_MODE_RX) || + (config->mode == TRANSCEIVER_MODE_RX_SWEEP)) { + n = 1; + uint32_t afe_rate_x2 = 2 * sample_rate.hz; + while ((afe_rate_x2 <= MAX_AFE_RATE) && (n < MAX_N)) { + afe_rate_x2 <<= 1; + n++; + } + fpga_set_rx_decimation_ratio(&fpga, n); + } + config->resampling_n = n; + bool ok = sample_rate_frac_set(sample_rate.num << n, sample_rate.div); + if (ok) { + config->sample_rate[element] = sample_rate; + radio_channel_t* channel = &radio->channel[chan_id]; + radio_frequency_t frequency = + radio_get_frequency(radio, channel->id, RADIO_FREQUENCY_RF); + ok = radio_set_frequency( + radio, + channel->id, + RADIO_FREQUENCY_RF, + frequency); + } +#else + bool ok = sample_rate_frac_set(sample_rate.num, sample_rate.div); #endif - -#define MIN(x, y) ((x) < (y) ? (x) : (y)) -#define MAX(x, y) ((x) > (y) ? (x) : (y)) - -/* Driver instance. */ -radio_t radio; - -void radio_init(radio_t* const radio) -{ - for (uint8_t bank = 0; bank < RADIO_NUM_BANKS; bank++) { - for (uint8_t reg = 0; reg < RADIO_NUM_REGS; reg++) { - radio->config[bank][reg] = RADIO_UNSET; - } - } - radio->config[RADIO_BANK_APPLIED][RADIO_OPMODE] = TRANSCEIVER_MODE_OFF; - radio->config[RADIO_BANK_REQUESTED][RADIO_OPMODE] = TRANSCEIVER_MODE_OFF; - radio->config[RADIO_BANK_IDLE][RADIO_OPMODE] = TRANSCEIVER_MODE_OFF; - radio->config[RADIO_BANK_RX][RADIO_OPMODE] = TRANSCEIVER_MODE_RX; - radio->config[RADIO_BANK_TX][RADIO_OPMODE] = TRANSCEIVER_MODE_TX; - radio->config[RADIO_BANK_IDLE][RADIO_BIAS_TEE] = false; - radio->regs_dirty = 0; -} - -static inline void mark_dirty(radio_t* const radio, radio_register_t reg) -{ - radio->regs_dirty |= (1 << reg); -} - -radio_error_t radio_reg_write( - radio_t* const radio, - const radio_register_bank_t bank, - const radio_register_t reg, - const uint64_t value) -{ - if (reg > RADIO_NUM_REGS) { - return RADIO_ERR_INVALID_REGISTER; - } - - switch (bank) { - case RADIO_BANK_REQUESTED: - mark_dirty(radio, reg); - /* fall through */ - case RADIO_BANK_IDLE: - case RADIO_BANK_RX: - case RADIO_BANK_TX: - radio->config[bank][reg] = value; - break; - case RADIO_BANK_ALL: - for (uint8_t b = 1; b < RADIO_NUM_BANKS; b++) { - radio->config[b][reg] = value; - } - mark_dirty(radio, reg); - break; - default: - return RADIO_ERR_INVALID_BANK; + if (!ok) { + return RADIO_ERR_INVALID_PARAM; } + config->sample_rate[element] = sample_rate; return RADIO_OK; } -uint64_t radio_reg_read( - radio_t* const radio, - const radio_register_bank_t bank, - const radio_register_t reg) +radio_sample_rate_t radio_get_sample_rate( + radio_t* radio, + radio_chan_id chan_id, + radio_sample_rate_id element) { - return radio->config[bank][reg]; + return radio->channel[chan_id].config.sample_rate[element]; } -static uint32_t radio_update_direction(radio_t* const radio, uint64_t* bank) +radio_error_t radio_set_filter( + radio_t* radio, + radio_chan_id chan_id, + radio_filter_id element, + radio_filter_t filter) { - const uint64_t requested = bank[RADIO_OPMODE]; - - if (requested == RADIO_UNSET) { - return 0; + // we only support the baseband filter at the moment + if (element != RADIO_FILTER_BASEBAND) { + return RADIO_ERR_INVALID_ELEMENT; } - rf_path_direction_t direction; - switch (bank[RADIO_OPMODE]) { - case TRANSCEIVER_MODE_TX: - case TRANSCEIVER_MODE_SS: - direction = RF_PATH_DIRECTION_TX; + radio_config_t* config = &radio->channel[chan_id].config; + + if (config->mode == TRANSCEIVER_MODE_OFF) { + config->filter[element] = filter; + return RADIO_OK; + } + +#ifndef PRALINE + max283x_set_lpf_bandwidth(&max283x, filter.hz); +#else + uint32_t lpf_bandwidth = + (config->sample_rate[RADIO_SAMPLE_RATE_CLOCKGEN].hz * 3) / 8; + uint32_t offset = 0; + if (config->shift != FPGA_QUARTER_SHIFT_MODE_NONE) { + offset = (config->sample_rate[RADIO_SAMPLE_RATE_CLOCKGEN].hz + << config->resampling_n) / + 8; + } + lpf_bandwidth += offset * 2; + max2831_set_lpf_bandwidth(&max283x, lpf_bandwidth); +#endif + + config->filter[element] = filter; + return RADIO_OK; +} + +radio_filter_t radio_get_filter( + radio_t* radio, + radio_chan_id chan_id, + radio_filter_id element) +{ + return radio->channel[chan_id].config.filter[element]; +} + +radio_error_t radio_set_gain( + radio_t* radio, + radio_chan_id chan_id, + radio_gain_id element, + radio_gain_t gain) +{ + if (element > RADIO_GAIN_COUNT) { + return RADIO_ERR_INVALID_ELEMENT; + } + + radio_config_t* config = &radio->channel[chan_id].config; + + if (config->mode == TRANSCEIVER_MODE_OFF) { + config->gain[element] = gain; + return RADIO_OK; + } + + uint8_t real_db; + switch (element) { + case RADIO_GAIN_RF_AMP: + rf_path_set_lna(&rf_path, gain.enable); break; + case RADIO_GAIN_RX_LNA: +#ifndef PRALINE + real_db = max283x_set_lna_gain(&max283x, gain.db); +#else + real_db = max2831_set_lna_gain(&max283x, gain.db); +#endif + if (real_db == 0) { + return RADIO_ERR_INVALID_PARAM; + } + break; + case RADIO_GAIN_RX_VGA: +#ifndef PRALINE + real_db = max283x_set_vga_gain(&max283x, gain.db); +#else + real_db = max2831_set_vga_gain(&max283x, gain.db); +#endif + if (real_db == 0) { + return RADIO_ERR_INVALID_PARAM; + } + break; + case RADIO_GAIN_TX_VGA: +#ifndef PRALINE + real_db = max283x_set_txvga_gain(&max283x, gain.db); +#else + real_db = max2831_set_txvga_gain(&max283x, gain.db); +#endif + if (real_db == 0) { + return RADIO_ERR_INVALID_PARAM; + } + break; + } + + config->gain[element] = gain; + return RADIO_OK; +} + +radio_gain_t radio_get_gain(radio_t* radio, radio_chan_id chan_id, radio_gain_id element) +{ + return radio->channel[chan_id].config.gain[element]; +} + +static uint64_t applied_freq = 0xffffffffffffffff; + +radio_error_t radio_set_frequency( + radio_t* radio, + radio_chan_id chan_id, + radio_frequency_id element, + radio_frequency_t frequency) +{ + // we only support setting the final rf frequency at the moment + if (element != RADIO_FREQUENCY_RF) { + return RADIO_ERR_INVALID_ELEMENT; + } + + radio_config_t* config = &radio->channel[chan_id].config; + + if (config->mode == TRANSCEIVER_MODE_OFF) { + config->frequency[element] = frequency; + return RADIO_OK; + } + + // explicit + if (frequency.if_hz || frequency.lo_hz) { + bool ok = set_freq_explicit( + frequency.if_hz, + frequency.lo_hz, + frequency.path); +#ifdef PRALINE + if (ok) { + fpga_set_rx_quarter_shift_mode( + &fpga, + FPGA_QUARTER_SHIFT_MODE_NONE); + config->shift = FPGA_QUARTER_SHIFT_MODE_NONE; + radio_channel_t* channel = &radio->channel[chan_id]; + radio_filter_t filter = radio_get_filter( + radio, + channel->id, + RADIO_FILTER_BASEBAND); + ok = radio_set_filter( + radio, + channel->id, + RADIO_FILTER_BASEBAND, + filter); + } +#endif + if (!ok) { + return RADIO_ERR_INVALID_PARAM; + } + + config->frequency[element] = frequency; + return RADIO_OK; + } + + // auto-tune + if (frequency.hz == applied_freq) { + return RADIO_OK; + } + applied_freq = frequency.hz; + bool ok; +#ifndef PRALINE + switch (config->mode) { case TRANSCEIVER_MODE_RX: case TRANSCEIVER_MODE_RX_SWEEP: - direction = RF_PATH_DIRECTION_RX; - break; - default: - direction = RF_PATH_DIRECTION_OFF; - } - radio->config[RADIO_BANK_APPLIED][RADIO_OPMODE] = requested; - rf_path_set_direction(&rf_path, direction); - return (1 << RADIO_OPMODE); -} - -/* Apply correction to a true frequency to get an adjusted frequency. */ -static uint64_t adjust(uint64_t freq, uint64_t correction) -{ - /* skip if we can */ - if (correction == FRAC_ONE) { - return freq; - } - - u128 product = u128_multiply(freq, correction); - - /* product >> 63 */ - return (product.hi << 1) | (product.lo >> 63); -} - -/* Given an adjusted frequency and correction, return the true frequency. */ -static uint64_t unadjust(uint64_t freq, uint64_t correction) -{ - /* skip if we can */ - if (correction == FRAC_ONE) { - return freq; - } - - /* (1 << (63 + 63)) */ - u128 numerator = (u128){ - .hi = 1ULL << 62, - .lo = 0, - }; - u128 denominator = (u128){ - .hi = 0, - .lo = correction, - }; - u128 reciprocal = u128_divide(numerator, denominator); - return adjust(freq, reciprocal.lo); -} - -static uint64_t restrict_correction(uint64_t requested_correction) -{ - /* Correction should be in the range 0.99 to 1.01 */ - const uint64_t min_correction = FRAC_ONE - FRAC_ONE_PERCENT; - const uint64_t max_correction = FRAC_ONE + FRAC_ONE_PERCENT; - if (requested_correction >= min_correction && - requested_correction <= max_correction) { - return requested_correction; - } else { - return FRAC_ONE; - } -} - -static uint64_t set_lo(uint64_t freq_lo, uint64_t correction, bool apply) -{ - fp_40_24_t corrected_lo = adjust(freq_lo, correction); - fp_40_24_t achieved_lo = mixer_set_frequency(&mixer, corrected_lo, apply); - return unadjust(achieved_lo, correction); -} - -static uint64_t set_if(uint64_t freq_if, uint64_t correction, bool apply) -{ - fp_40_24_t corrected_if = adjust(freq_if, correction); - fp_40_24_t achieved_if = max283x_set_frequency(&max283x, corrected_if, apply); - return unadjust(achieved_if, correction); -} - -static uint64_t set_afe_rate(uint64_t afe_rate, uint64_t correction, bool apply) -{ - fp_28_36_t corrected_rate = adjust(afe_rate, correction); - fp_28_36_t achieved_rate = sample_rate_set(corrected_rate, apply); - return unadjust(achieved_rate, correction); -} - -#define ABSOLUTE_MIN_AFE_RATE SR_FP_KHZ(200) -#define ABSOLUTE_MAX_AFE_RATE SR_FP_KHZ(43600) -#define MAX_SUPPORTED_AFE_RATE SR_FP_KHZ(40000) - -static inline uint8_t compute_resample_log( - const fp_28_36_t sample_rate, - const uint64_t requested_n) -{ - if (detected_platform() != BOARD_ID_PRALINE) { - return 0; - } - uint8_t n = 0; // resampling ratio is 2**n - const uint8_t max_n = 5; - fp_28_36_t afe_rate = 0; - - if (requested_n == RADIO_UNSET) { - /* Find highest supported resampling ratio of at least 2 (n=1). */ - while (((afe_rate * 2) <= MAX_SUPPORTED_AFE_RATE) && (n < max_n)) { - n++; - afe_rate = sample_rate << n; - } - } else { - /* Restrict requested resampling ratio within allowable limits. */ - n = MIN(max_n, requested_n); - afe_rate = sample_rate << n; - while ((afe_rate < ABSOLUTE_MIN_AFE_RATE) && (n < max_n)) { - n++; - afe_rate <<= 1; - } - while ((afe_rate > ABSOLUTE_MAX_AFE_RATE) && (n > 0)) { - n--; - afe_rate >>= 1; - } - } - return n; -} - -#define MIN_MCU_RATE SR_FP_KHZ(200) -#define MAX_MCU_RATE SR_FP_KHZ(21800) -#define DEFAULT_MCU_RATE SR_FP_KHZ(10000) - -static uint32_t radio_update_sample_rate(radio_t* const radio, uint64_t* bank) -{ - fp_28_36_t rate, afe_rate, previous_rate, previous_afe_rate; - uint64_t previous_n, requested_n; - uint8_t n = 0; - bool new_afe_rate = false; - bool new_rate = false; - bool new_n = false; - - const uint64_t requested_rate = bank[RADIO_SAMPLE_RATE]; - const uint64_t requested_correction = bank[RADIO_CLOCK_CORRECTION]; - - uint64_t correction = restrict_correction(requested_correction); - - if (requested_rate != RADIO_UNSET) { - rate = MIN(requested_rate, MAX_MCU_RATE); - rate = MAX(rate, MIN_MCU_RATE); - } else { - rate = radio->config[RADIO_BANK_APPLIED][RADIO_SAMPLE_RATE]; - if (rate == RADIO_UNSET) { - rate = DEFAULT_MCU_RATE; - } - } - - const uint64_t previous_opmode = radio->config[RADIO_BANK_APPLIED][RADIO_OPMODE]; - uint64_t opmode = bank[RADIO_OPMODE]; - if (opmode == RADIO_UNSET) { - opmode = previous_opmode; - } - switch (previous_opmode) { case TRANSCEIVER_MODE_TX: - case TRANSCEIVER_MODE_SS: - previous_n = radio->config[RADIO_BANK_APPLIED][RADIO_RESAMPLE_TX]; + ok = set_freq(frequency.hz); break; default: - previous_n = radio->config[RADIO_BANK_APPLIED][RADIO_RESAMPLE_RX]; + return RADIO_ERR_INVALID_CONFIG; } - switch (opmode) { - case TRANSCEIVER_MODE_TX: - case TRANSCEIVER_MODE_SS: - requested_n = bank[RADIO_RESAMPLE_TX]; - n = compute_resample_log(rate, requested_n); - if (n != radio->config[RADIO_BANK_APPLIED][RADIO_RESAMPLE_TX]) { -#ifdef IS_PRALINE - if (IS_PRALINE) { - fpga_set_tx_interpolation_ratio(&fpga, n); - } -#endif - radio->config[RADIO_BANK_APPLIED][RADIO_RESAMPLE_TX] = n; - } - break; - default: - requested_n = bank[RADIO_RESAMPLE_RX]; - n = compute_resample_log(rate, requested_n); - if (n != radio->config[RADIO_BANK_APPLIED][RADIO_RESAMPLE_RX]) { -#ifdef IS_PRALINE - if (IS_PRALINE) { - fpga_set_rx_decimation_ratio(&fpga, n); - } -#endif - radio->config[RADIO_BANK_APPLIED][RADIO_RESAMPLE_RX] = n; - } - } - new_n = (n != previous_n); - - afe_rate = rate << n; - afe_rate = set_afe_rate(afe_rate, correction, false); - previous_rate = radio->config[RADIO_BANK_APPLIED][RADIO_SAMPLE_RATE]; - if ((previous_n == RADIO_UNSET) || previous_rate == RADIO_UNSET) { - previous_afe_rate = RADIO_UNSET; - } else { - previous_afe_rate = previous_rate << previous_n; - } - new_afe_rate = (afe_rate != previous_afe_rate); - if (new_afe_rate) { - afe_rate = set_afe_rate(afe_rate, correction, true); - } - - rate = afe_rate >> n; - new_rate = (rate != previous_rate); - if (new_rate) { - radio->config[RADIO_BANK_APPLIED][RADIO_SAMPLE_RATE] = rate; - } - - return ((new_afe_rate || new_rate || new_n) << RADIO_SAMPLE_RATE); -} - -/* - * Compute frequency offset in 1/(2**24) Hz for a given rotation. This is an - * unsigned value that does not indicate direction of frequency shift. - */ -static fp_40_24_t compute_offset(radio_t* const radio, uint64_t opmode, uint64_t rotation) -{ - uint64_t n; - fp_40_24_t offset = 0; - const fp_28_36_t mcu_rate = radio->config[RADIO_BANK_APPLIED][RADIO_SAMPLE_RATE]; - - switch (opmode) { - case TRANSCEIVER_MODE_TX: - case TRANSCEIVER_MODE_SS: - n = radio->config[RADIO_BANK_APPLIED][RADIO_RESAMPLE_TX]; - break; - default: - n = radio->config[RADIO_BANK_APPLIED][RADIO_RESAMPLE_RX]; - } - if ((rotation != 0) && (rotation != RADIO_UNSET) && (mcu_rate != RADIO_UNSET) && - (n != RADIO_UNSET)) { - const fp_40_24_t afe_rate = mcu_rate >> (12 - n); - if (rotation & 0x80000000) { - rotation = 0x100000000 - rotation; - } - offset = (afe_rate * (rotation >> 24)) >> 8; - } - return offset; -} - -/* - * Convert center frequency of analog baseband (as seen by ADC/DAC) to center - * frequency of digital baseband (as seen by MCU). - */ -static fp_40_24_t digital_from_analog_rf( - radio_t* const radio, - const fp_40_24_t arf, - uint64_t opmode, - uint64_t rotation) -{ - fp_40_24_t offset = compute_offset(radio, opmode, rotation); - fp_40_24_t drf = arf; - if (rotation > 0x80000000) { - if (offset > arf) { - drf = offset - arf; - } else { - drf = arf - offset; - } - } else if ((rotation & 0x7fffffff) > 0) { - drf = arf + offset; - } - return drf; -} - -#ifdef IS_PRALINE -/* - * Convert center frequency of digital baseband (as seen by MCU) to center - * frequency of analog baseband (as seen by ADC/DAC). - */ -static fp_40_24_t analog_from_digital_rf( - radio_t* const radio, - const fp_40_24_t drf, - uint64_t opmode, - uint64_t rotation) -{ - fp_40_24_t offset = compute_offset(radio, opmode, rotation); - fp_40_24_t arf = drf; - if (rotation > 0x80000000) { - arf = drf + offset; - } else if ((rotation & 0x7fffffff) > 0) { - if (offset > drf) { - arf = offset - drf; - } else { - arf = drf - offset; - } - } - return arf; -} - -static const tune_config_t* select_tune_config(uint64_t opmode, fp_40_24_t freq_rf) -{ +#else const tune_config_t* tune_config; - - switch (opmode) { - case TRANSCEIVER_MODE_TX: - case TRANSCEIVER_MODE_SS: - tune_config = praline_tune_config_tx; + switch (config->mode) { + case TRANSCEIVER_MODE_RX: + tune_config = praline_tune_config_rx; break; case TRANSCEIVER_MODE_RX_SWEEP: tune_config = praline_tune_config_rx_sweep; break; + case TRANSCEIVER_MODE_TX: + tune_config = praline_tune_config_tx; + break; default: - tune_config = praline_tune_config_rx; + return RADIO_ERR_INVALID_CONFIG; } - while ((tune_config->rf_range_end_mhz != 0) || (tune_config->if_mhz != 0)) { - if ((freq_rf == 0) || - (tune_config->rf_range_end_mhz > (freq_rf / FP_ONE_MHZ))) { + bool found = false; + for (; (tune_config->rf_range_end_mhz != 0) || (tune_config->if_mhz != 0); + tune_config++) { + if ((frequency.hz == 0) || + (tune_config->rf_range_end_mhz > (frequency.hz / FREQ_ONE_MHZ))) { + found = true; break; } - tune_config++; } - return tune_config; -} -#endif - -static uint32_t radio_update_frequency(radio_t* const radio, uint64_t* bank) -{ - uint32_t changed = 0; - bool high_lo = false; - - const uint64_t requested_rf = bank[RADIO_FREQUENCY_RF]; - const uint64_t requested_if = bank[RADIO_FREQUENCY_IF]; - const uint64_t requested_lo = bank[RADIO_FREQUENCY_LO]; - const uint64_t requested_img_reject = bank[RADIO_IMAGE_REJECT]; -#ifdef IS_PRALINE - const uint64_t requested_rotation = bank[RADIO_ROTATION]; -#endif - const uint64_t requested_correction = bank[RADIO_CLOCK_CORRECTION]; - - const uint64_t applied_rf = radio->config[RADIO_BANK_APPLIED][RADIO_FREQUENCY_RF]; - const uint64_t applied_if = radio->config[RADIO_BANK_APPLIED][RADIO_FREQUENCY_IF]; - const uint64_t applied_lo = radio->config[RADIO_BANK_APPLIED][RADIO_FREQUENCY_LO]; - const uint64_t applied_img_reject = - radio->config[RADIO_BANK_APPLIED][RADIO_IMAGE_REJECT]; - const uint64_t applied_rotation = - radio->config[RADIO_BANK_APPLIED][RADIO_ROTATION]; - const uint64_t applied_correction = - radio->config[RADIO_BANK_APPLIED][RADIO_CLOCK_CORRECTION]; - - uint64_t freq_rf = applied_rf; - uint64_t analog_rf = applied_rf; - uint64_t freq_if = applied_if; - uint64_t freq_lo = applied_lo; - uint64_t img_reject = applied_img_reject; - uint64_t rotation = applied_rotation; - uint64_t correction = applied_correction; - - uint64_t opmode = bank[RADIO_OPMODE]; - if (opmode == RADIO_UNSET) { - opmode = radio->config[RADIO_BANK_APPLIED][RADIO_OPMODE]; + if (!found) { + return RADIO_ERR_INVALID_PARAM; } - /* Restrict requested settings to valid ranges. */ - if (requested_img_reject != RADIO_UNSET) { - switch (requested_img_reject) { - case RF_PATH_FILTER_LOW_PASS: - case RF_PATH_FILTER_HIGH_PASS: - img_reject = requested_img_reject; - break; - default: - img_reject = RF_PATH_FILTER_BYPASS; - } - } - correction = restrict_correction(requested_correction); - if (requested_if != RADIO_UNSET) { - freq_if = set_if(requested_if, correction, false); - } - if (requested_lo != RADIO_UNSET) { - freq_lo = set_lo(requested_lo, correction, false); - } -#ifdef IS_PRALINE - if (IS_PRALINE) { - if (requested_rotation != RADIO_UNSET) { - rotation = requested_rotation; - } - switch (opmode) { - case TRANSCEIVER_MODE_RX: - case TRANSCEIVER_MODE_RX_SWEEP: - /* Round to nearest supported rotation. */ - rotation = (rotation + 0x20000000) & 0xc0000000; - if (rotation == 0x80000000) { - rotation = 0; - } - break; - default: - rotation = 0; - } + fpga_set_rx_quarter_shift_mode(&fpga, tune_config->shift); + config->shift = tune_config->shift; + uint32_t offset = (config->sample_rate[RADIO_SAMPLE_RATE_CLOCKGEN].hz + << config->resampling_n) / + 8; + ok = tuning_set_frequency(tune_config, frequency.hz, offset); + if (ok) { + radio_channel_t* channel = &radio->channel[chan_id]; + radio_filter_t filter = + radio_get_filter(radio, channel->id, RADIO_FILTER_BASEBAND); + ok = radio_set_filter(radio, channel->id, RADIO_FILTER_BASEBAND, filter); } #endif -#ifdef IS_NOT_PRALINE - if (IS_NOT_PRALINE) { - rotation = 0; - } -#endif - - /* Handle requested RF (auto-tune). */ - if (requested_rf != RADIO_UNSET) { - if (requested_img_reject == RADIO_UNSET) { - img_reject = select_img_reject(requested_rf); - } - freq_rf = restrict_rf(requested_rf, img_reject); - - /* Look up settings appropriate for requested RF. */ -#ifdef IS_PRALINE - if (IS_PRALINE) { - const tune_config_t* tune_config = - select_tune_config(opmode, freq_rf); - if (requested_rotation == RADIO_UNSET) { - rotation = (uint64_t) (tune_config->shift) << 30; - } - analog_rf = - analog_from_digital_rf(radio, freq_rf, opmode, rotation); - if (requested_if == RADIO_UNSET) { - if (tune_config->if_mhz == 0) { - freq_if = analog_rf; - } else { - freq_if = tune_config->if_mhz * FP_ONE_MHZ; - } - } - high_lo = tune_config->high_lo; - } -#endif -#ifdef IS_NOT_PRALINE - if (IS_NOT_PRALINE) { - /* Use graduated or fixed IF on older platforms. */ - if (requested_if == RADIO_UNSET) { - freq_if = select_graduated_if(freq_rf, img_reject); - } - high_lo = (img_reject == RF_PATH_FILTER_LOW_PASS); - analog_rf = freq_rf; - } -#endif - - /* Compute precise LO. This is done first because the mixer LO is set in coarse steps. */ - if (requested_lo == RADIO_UNSET) { - switch (img_reject) { - case RF_PATH_FILTER_LOW_PASS: - if (high_lo) { - freq_lo = freq_if + analog_rf; - } else { - freq_lo = freq_if - analog_rf; - } - break; - case RF_PATH_FILTER_HIGH_PASS: - freq_lo = analog_rf - freq_if; - break; - default: - freq_lo = RADIO_UNSET; - } - if (freq_lo != RADIO_UNSET) { - freq_lo = set_lo(freq_lo, correction, false); - } - } - - /* Recompute IF, compensating for rounding of mixer LO. */ - if (requested_if == RADIO_UNSET) { - switch (img_reject) { - case RF_PATH_FILTER_LOW_PASS: - if (high_lo) { - freq_if = freq_lo - analog_rf; - } else { - freq_if = freq_lo + analog_rf; - } - break; - case RF_PATH_FILTER_HIGH_PASS: - freq_if = analog_rf - freq_lo; - } - } + if (!ok) { + return RADIO_ERR_INVALID_PARAM; } - /* Apply settings. */ - if ((freq_if != applied_if) && (freq_if != RADIO_UNSET)) { - freq_if = set_if(freq_if, correction, true); - radio->config[RADIO_BANK_APPLIED][RADIO_FREQUENCY_IF] = freq_if; - changed |= (1 << RADIO_FREQUENCY_IF); - } - if ((freq_lo != applied_lo) && (freq_lo != RADIO_UNSET)) { - freq_lo = set_lo(freq_lo, correction, true); - radio->config[RADIO_BANK_APPLIED][RADIO_FREQUENCY_LO] = freq_lo; - changed |= (1 << RADIO_FREQUENCY_LO); - } - if ((img_reject != applied_img_reject) && (img_reject != RADIO_UNSET)) { - rf_path_set_filter(&rf_path, img_reject); - radio->config[RADIO_BANK_APPLIED][RADIO_IMAGE_REJECT] = img_reject; - changed |= (1 << RADIO_IMAGE_REJECT); - } - if ((rotation != applied_rotation) && (rotation != RADIO_UNSET)) { -#ifdef IS_PRALINE - if (IS_PRALINE) { - fpga_set_rx_quarter_shift_mode(&fpga, rotation >> 30); - } -#endif - radio->config[RADIO_BANK_APPLIED][RADIO_ROTATION] = rotation; - changed |= (1 << RADIO_ROTATION); - } - - /* Compute precise RF. */ - if ((img_reject != RADIO_UNSET) && (freq_if != RADIO_UNSET) && - (rotation != RADIO_UNSET) && - ((freq_lo != RADIO_UNSET) || (img_reject == RF_PATH_FILTER_BYPASS))) { - switch (img_reject) { - case RF_PATH_FILTER_LOW_PASS: - if (freq_lo > freq_if) { - analog_rf = freq_lo - freq_if; - } else { - analog_rf = freq_if - freq_lo; - } - break; - case RF_PATH_FILTER_HIGH_PASS: - analog_rf = freq_if + freq_lo; - break; - default: - analog_rf = freq_if; - } - freq_rf = digital_from_analog_rf(radio, analog_rf, opmode, rotation); - } - if ((freq_rf != applied_rf) && (freq_rf != RADIO_UNSET)) { - radio->config[RADIO_BANK_APPLIED][RADIO_FREQUENCY_RF] = freq_rf; - changed |= (1 << RADIO_FREQUENCY_RF); - } - if ((correction != applied_correction) && (correction != RADIO_UNSET)) { - radio->config[RADIO_BANK_APPLIED][RADIO_CLOCK_CORRECTION] = correction; - changed |= (1 << RADIO_CLOCK_CORRECTION); - } - - return changed; + config->frequency[element] = frequency; + return RADIO_OK; } -static uint32_t auto_bandwidth(radio_t* const radio, uint64_t opmode) +radio_frequency_t radio_get_frequency( + radio_t* radio, + radio_chan_id chan_id, + radio_frequency_id element) { - uint32_t offset_hz = 0; - uint64_t rotation = radio->config[RADIO_BANK_APPLIED][RADIO_ROTATION]; - - uint32_t sample_rate_hz = DEFAULT_MCU_RATE / SR_FP_ONE_HZ; - if (radio->config[RADIO_BANK_APPLIED][RADIO_SAMPLE_RATE] != RADIO_UNSET) { - sample_rate_hz = radio->config[RADIO_BANK_APPLIED][RADIO_SAMPLE_RATE] / - SR_FP_ONE_HZ; - } - - const fp_40_24_t offset = compute_offset(radio, opmode, rotation); - offset_hz = offset >> 24; - - const uint32_t bb_bandwidth = (sample_rate_hz * 3) / 4; - const uint32_t lpf_bandwidth = bb_bandwidth + offset_hz * 2; - - radio->config[RADIO_BANK_APPLIED][RADIO_BB_BANDWIDTH_TX] = bb_bandwidth; - radio->config[RADIO_BANK_APPLIED][RADIO_BB_BANDWIDTH_RX] = bb_bandwidth; - - return lpf_bandwidth; + return radio->channel[chan_id].config.frequency[element]; } -static uint32_t radio_update_bandwidth(radio_t* const radio, uint64_t* bank) +radio_error_t radio_set_antenna( + radio_t* radio, + radio_chan_id chan_id, + radio_antenna_id element, + radio_antenna_t value) { - uint32_t changed = 0; - - uint64_t opmode = bank[RADIO_OPMODE]; - if (opmode == RADIO_UNSET) { - opmode = radio->config[RADIO_BANK_APPLIED][RADIO_OPMODE]; + if (element > RADIO_ANTENNA_COUNT) { + return RADIO_ERR_INVALID_ELEMENT; } -#ifdef IS_PRALINE - if (IS_PRALINE) { - /* Praline legacy mode always sets baseband bandwidth automatically. */ - (void) bank; - uint32_t lpf_bandwidth = auto_bandwidth(radio, opmode); + radio_config_t* config = &radio->channel[chan_id].config; - if (radio->config[RADIO_BANK_APPLIED][RADIO_XCVR_TX_LPF] != - lpf_bandwidth) { - max283x_set_lpf_bandwidth( - &max283x, - MAX283x_MODE_TX, - lpf_bandwidth); - radio->config[RADIO_BANK_APPLIED][RADIO_XCVR_TX_LPF] = - lpf_bandwidth; - changed |= (1 << RADIO_XCVR_TX_LPF); - } - if (radio->config[RADIO_BANK_APPLIED][RADIO_XCVR_RX_LPF] != - lpf_bandwidth) { - max283x_set_lpf_bandwidth( - &max283x, - MAX283x_MODE_RX, - lpf_bandwidth); - radio->config[RADIO_BANK_APPLIED][RADIO_XCVR_RX_LPF] = - lpf_bandwidth; - changed |= (1 << RADIO_XCVR_RX_LPF); - } - bool narrow_lpf_enable = false; - bool applied_narrow_lpf_enable = - radio->config[RADIO_BANK_APPLIED][RADIO_RX_NARROW_LPF]; - if (lpf_bandwidth <= 1750000) { - narrow_lpf_enable = true; - } - if (applied_narrow_lpf_enable != narrow_lpf_enable) { - narrowband_filter_set(narrow_lpf_enable); - radio->config[RADIO_BANK_APPLIED][RADIO_RX_NARROW_LPF] = - narrow_lpf_enable; - changed |= (1 << RADIO_RX_NARROW_LPF); - } - /* Always set HPF bandwidth to 30 kHz for now. */ - const max283x_rx_hpf_freq_t hpf_bandwidth = MAX283x_RX_HPF_30_KHZ; - if (radio->config[RADIO_BANK_APPLIED][RADIO_XCVR_RX_HPF] != - hpf_bandwidth) { - max283x_set_rx_hpf_frequency(&max283x, hpf_bandwidth); - radio->config[RADIO_BANK_APPLIED][RADIO_XCVR_RX_HPF] = - hpf_bandwidth; - changed |= (1 << RADIO_XCVR_RX_HPF); - } + if (config->mode == TRANSCEIVER_MODE_OFF) { + config->antenna[element] = value; + return RADIO_OK; } -#endif -#ifdef IS_NOT_PRALINE - if (IS_NOT_PRALINE) { - uint64_t lpf_bandwidth; - lpf_bandwidth = bank[RADIO_XCVR_TX_LPF]; - if (lpf_bandwidth == RADIO_UNSET) { - lpf_bandwidth = bank[RADIO_XCVR_RX_LPF]; - } - if (lpf_bandwidth == RADIO_UNSET) { - lpf_bandwidth = bank[RADIO_BB_BANDWIDTH_TX]; - } - if (lpf_bandwidth == RADIO_UNSET) { - lpf_bandwidth = bank[RADIO_BB_BANDWIDTH_RX]; - } - if (lpf_bandwidth == RADIO_UNSET) { - lpf_bandwidth = - radio->config[RADIO_BANK_APPLIED][RADIO_XCVR_TX_LPF]; - } - if (lpf_bandwidth == RADIO_UNSET) { - lpf_bandwidth = auto_bandwidth(radio, opmode); - } - if (radio->config[RADIO_BANK_APPLIED][RADIO_XCVR_TX_LPF] != - lpf_bandwidth) { - max283x_set_lpf_bandwidth( - &max283x, - MAX283x_MODE_TX, - lpf_bandwidth); - radio->config[RADIO_BANK_APPLIED][RADIO_BB_BANDWIDTH_RX] = - lpf_bandwidth; - radio->config[RADIO_BANK_APPLIED][RADIO_BB_BANDWIDTH_TX] = - lpf_bandwidth; - radio->config[RADIO_BANK_APPLIED][RADIO_XCVR_TX_LPF] = - lpf_bandwidth; - radio->config[RADIO_BANK_APPLIED][RADIO_XCVR_RX_LPF] = - lpf_bandwidth; - changed |= - ((1 << RADIO_BB_BANDWIDTH_RX) | - (1 << RADIO_BB_BANDWIDTH_TX) | (1 << RADIO_XCVR_TX_LPF) | - (1 << RADIO_XCVR_RX_LPF)); - } + switch (element) { + case RADIO_ANTENNA_BIAS_TEE: + rf_path_set_antenna( + &rf_path, + config->antenna[RADIO_ANTENNA_BIAS_TEE].enable); + break; } -#endif - return changed; + + config->antenna[element] = value; + return RADIO_OK; } -#define DEFAULT_GAIN_RF (0) -#define DEFAULT_GAIN_IF (16) -#define DEFAULT_GAIN_BB (12) - -static uint32_t radio_update_gain(radio_t* const radio, uint64_t* bank) +radio_antenna_t radio_get_antenna( + radio_t* radio, + radio_chan_id chan_id, + radio_antenna_id element) { - uint32_t changed = 0; - uint64_t gain, tx_rf_gain, rx_rf_gain; - uint64_t opmode = bank[RADIO_OPMODE]; - if (opmode == RADIO_UNSET) { - opmode = radio->config[RADIO_BANK_APPLIED][RADIO_OPMODE]; + return radio->channel[chan_id].config.antenna[element]; +} + +radio_error_t radio_set_clock( + radio_t* radio, + radio_chan_id chan_id, + radio_clock_id element, + radio_clock_t value) +{ + radio_config_t* config = &radio->channel[chan_id].config; + + if (element > RADIO_CLOCK_COUNT) { + return RADIO_ERR_INVALID_ELEMENT; + } + + // CLKIN is not supported as it is automatically detected from hardware state + if (element == RADIO_CLOCK_CLKIN) { + return RADIO_ERR_UNSUPPORTED_OPERATION; + } + + si5351c_clkout_enable(&clock_gen, value.enable); + + config->clock[element] = value; + return RADIO_OK; +} + +radio_clock_t radio_get_clock( + radio_t* radio, + radio_chan_id chan_id, + radio_clock_id element) +{ + if (element == RADIO_CLOCK_CLKIN) { + return (radio_clock_t){ + .enable = si5351c_clkin_signal_valid(&clock_gen), + }; + } + + return radio->channel[chan_id].config.clock[element]; +} + +radio_error_t radio_set_trigger_enable(radio_t* radio, radio_chan_id chan_id, bool enable) +{ + radio_config_t* config = &radio->channel[chan_id].config; + + config->trigger_enable = enable; + return RADIO_OK; +} + +bool radio_get_trigger_enable(radio_t* radio, radio_chan_id chan_id) +{ + return radio->channel[chan_id].config.trigger_enable; +} + +transceiver_mode_t radio_get_mode(radio_t* radio, radio_chan_id chan_id) +{ + return radio->channel[chan_id].config.mode; +} + +rf_path_direction_t radio_get_direction(radio_t* radio, radio_chan_id chan_id) +{ + radio_config_t* config = &radio->channel[chan_id].config; + + switch (config->mode) { + case TRANSCEIVER_MODE_RX: + case TRANSCEIVER_MODE_RX_SWEEP: + return RF_PATH_DIRECTION_RX; + case TRANSCEIVER_MODE_TX: + return RF_PATH_DIRECTION_TX; + default: + return RF_PATH_DIRECTION_OFF; + } +} + +clock_source_t radio_get_clock_source(radio_t* radio, radio_chan_id chan_id) +{ + return radio->channel[chan_id].clock_source; +} + +radio_error_t radio_switch_mode( + radio_t* radio, + radio_chan_id chan_id, + transceiver_mode_t mode) +{ + radio_error_t result; + radio_channel_t* channel = &radio->channel[chan_id]; + radio_config_t* config = &channel->config; + + // configure firmware direction from mode (but don't configure the hardware yet!) + rf_path_direction_t direction; + switch (mode) { + case TRANSCEIVER_MODE_RX: + case TRANSCEIVER_MODE_RX_SWEEP: + direction = RF_PATH_DIRECTION_RX; + break; + case TRANSCEIVER_MODE_TX: + direction = RF_PATH_DIRECTION_TX; + break; + default: + rf_path_set_direction(&rf_path, RF_PATH_DIRECTION_OFF); + config->mode = mode; + return RADIO_OK; + } + config->mode = mode; + + // sample rate + radio_sample_rate_t sample_rate = + radio_get_sample_rate(radio, channel->id, RADIO_SAMPLE_RATE_CLOCKGEN); + result = radio_set_sample_rate( + radio, + channel->id, + RADIO_SAMPLE_RATE_CLOCKGEN, + sample_rate); + if (result != RADIO_OK) { + return result; } /* - * Because control signals are shared by the two RF amps, the setting - * for the active amp is reapplied at every opportunity. This ensures - * override of any setting from a previous operating mode. + * Because of offset tuning on Praline, the sample rate can affect the + * tuning configuration, so radio_set_sample_rate() calls + * radio_set_frequency(). Also because of offset tuning, the tuning + * configuration can affect the baseband filter bandwidth (in addition + * to the filter bandwidth being automatically based on the sample + * rate), so radio_set_frequency() calls radio_set_filter(). */ - switch (opmode) { - case TRANSCEIVER_MODE_TX: - case TRANSCEIVER_MODE_SS: - tx_rf_gain = bank[RADIO_GAIN_TX_RF]; - if (tx_rf_gain == RADIO_UNSET) { - tx_rf_gain = DEFAULT_GAIN_RF; - } - rf_path_set_lna(&rf_path, tx_rf_gain); - rx_rf_gain = 0; - break; - case TRANSCEIVER_MODE_RX: - case TRANSCEIVER_MODE_RX_SWEEP: - rx_rf_gain = bank[RADIO_GAIN_RX_RF]; - if (rx_rf_gain == RADIO_UNSET) { - rx_rf_gain = DEFAULT_GAIN_RF; - } - rf_path_set_lna(&rf_path, rx_rf_gain); - tx_rf_gain = 0; - break; - default: - rf_path_set_lna(&rf_path, 0); - tx_rf_gain = 0; - rx_rf_gain = 0; - } - if (radio->config[RADIO_BANK_APPLIED][RADIO_GAIN_TX_RF] != tx_rf_gain) { - radio->config[RADIO_BANK_APPLIED][RADIO_GAIN_TX_RF] = tx_rf_gain; - changed |= (1 << RADIO_GAIN_TX_RF); - } - if (radio->config[RADIO_BANK_APPLIED][RADIO_GAIN_RX_RF] != rx_rf_gain) { - radio->config[RADIO_BANK_APPLIED][RADIO_GAIN_RX_RF] = rx_rf_gain; - changed |= (1 << RADIO_GAIN_RX_RF); +#ifndef PRALINE + // tuning frequency + radio_frequency_t frequency = + radio_get_frequency(radio, channel->id, RADIO_FREQUENCY_RF); + result = radio_set_frequency(radio, channel->id, RADIO_FREQUENCY_RF, frequency); + if (result != RADIO_OK) { + return result; } - gain = bank[RADIO_GAIN_TX_IF]; - if ((gain != RADIO_UNSET) && - (gain != radio->config[RADIO_BANK_APPLIED][RADIO_GAIN_TX_IF])) { - max283x_set_txvga_gain(&max283x, gain); - radio->config[RADIO_BANK_APPLIED][RADIO_GAIN_TX_IF] = gain; - changed |= (1 << RADIO_GAIN_TX_IF); - } else if (radio->config[RADIO_BANK_APPLIED][RADIO_GAIN_TX_IF] == RADIO_UNSET) { - max283x_set_txvga_gain(&max283x, DEFAULT_GAIN_IF); - radio->config[RADIO_BANK_APPLIED][RADIO_GAIN_TX_IF] = DEFAULT_GAIN_IF; - changed |= (1 << RADIO_GAIN_TX_IF); - } - - gain = bank[RADIO_GAIN_RX_IF]; - if ((gain != RADIO_UNSET) && - (gain != radio->config[RADIO_BANK_APPLIED][RADIO_GAIN_RX_IF])) { - max283x_set_lna_gain(&max283x, gain); - radio->config[RADIO_BANK_APPLIED][RADIO_GAIN_RX_IF] = gain; - changed |= (1 << RADIO_GAIN_RX_IF); - } else if (radio->config[RADIO_BANK_APPLIED][RADIO_GAIN_RX_IF] == RADIO_UNSET) { - max283x_set_lna_gain(&max283x, DEFAULT_GAIN_IF); - radio->config[RADIO_BANK_APPLIED][RADIO_GAIN_RX_IF] = DEFAULT_GAIN_IF; - changed |= (1 << RADIO_GAIN_RX_IF); - } - - gain = bank[RADIO_GAIN_RX_BB]; - if ((gain != RADIO_UNSET) && - (gain != radio->config[RADIO_BANK_APPLIED][RADIO_GAIN_RX_BB])) { - max283x_set_vga_gain(&max283x, gain); - radio->config[RADIO_BANK_APPLIED][RADIO_GAIN_RX_BB] = gain; - changed |= (1 << RADIO_GAIN_RX_BB); - } else if (radio->config[RADIO_BANK_APPLIED][RADIO_GAIN_RX_BB] == RADIO_UNSET) { - max283x_set_vga_gain(&max283x, DEFAULT_GAIN_BB); - radio->config[RADIO_BANK_APPLIED][RADIO_GAIN_RX_BB] = DEFAULT_GAIN_BB; - changed |= (1 << RADIO_GAIN_RX_BB); - } - - return changed; -} - -static uint32_t radio_update_bias_tee(radio_t* const radio, uint64_t* bank) -{ - if (detected_platform() == BOARD_ID_JAWBREAKER) { - return 0; - } - - const uint64_t requested = bank[RADIO_BIAS_TEE]; - const bool enable = requested; - - if (requested == RADIO_UNSET) { - return 0; - } - - if (radio->config[RADIO_BANK_APPLIED][RADIO_BIAS_TEE] == (uint64_t) enable) { - return 0; - } - - rf_path_set_antenna(&rf_path, enable); - radio->config[RADIO_BANK_APPLIED][RADIO_BIAS_TEE] = enable; - return (1 << RADIO_BIAS_TEE); -} - -static uint32_t radio_update_trigger(radio_t* const radio, uint64_t* bank) -{ - const uint64_t requested = bank[RADIO_TRIGGER]; - bool enable = requested; - - if (requested == RADIO_UNSET) { - enable = false; - } - - if (radio->config[RADIO_BANK_APPLIED][RADIO_TRIGGER] == (uint64_t) enable) { - return 0; - } - - trigger_enable(enable); - radio->config[RADIO_BANK_APPLIED][RADIO_TRIGGER] = enable; - return (1 << RADIO_TRIGGER); -} - -static uint32_t radio_update_dc_block(radio_t* const radio, uint64_t* bank) -{ -#ifdef IS_PRALINE - if (IS_PRALINE) { - const uint64_t requested = bank[RADIO_DC_BLOCK]; - bool enable = requested; - - if (radio->config[RADIO_BANK_APPLIED][RADIO_DC_BLOCK] == - (uint64_t) enable) { - return 0; - } - - fpga_set_rx_dc_block_enable(&fpga, enable); - radio->config[RADIO_BANK_APPLIED][RADIO_DC_BLOCK] = enable; - return (1 << RADIO_DC_BLOCK); + // baseband filter bandwidth + radio_filter_t filter = + radio_get_filter(radio, channel->id, RADIO_FILTER_BASEBAND); + result = radio_set_filter(radio, channel->id, RADIO_FILTER_BASEBAND, filter); + if (result != RADIO_OK) { + return result; } #endif - (void) radio; - (void) bank; - return false; -} - -bool radio_update(radio_t* const radio) -{ - uint64_t tmp_bank[RADIO_NUM_REGS]; - nvic_disable_irq(NVIC_USB0_IRQ); - uint32_t dirty = radio->regs_dirty; - uint32_t changed = 0; - if (dirty == 0) { - nvic_enable_irq(NVIC_USB0_IRQ); - return false; - } - radio->regs_dirty = 0; - memcpy(&tmp_bank[0], &(radio->config[RADIO_BANK_REQUESTED][0]), sizeof(tmp_bank)); - nvic_enable_irq(NVIC_USB0_IRQ); - - if ((dirty & RADIO_REG_GROUP_RATE) || - ((detected_platform() == BOARD_ID_PRALINE) && - (dirty & (1 << RADIO_OPMODE)))) { - changed |= radio_update_sample_rate(radio, &tmp_bank[0]); - } - if ((dirty & RADIO_REG_GROUP_FREQ) || - ((detected_platform() == BOARD_ID_PRALINE) && - ((changed & RADIO_REG_GROUP_RATE) || (dirty & (1 << RADIO_OPMODE))))) { - changed |= radio_update_frequency(radio, &tmp_bank[0]); - } - if ((dirty & RADIO_REG_GROUP_BW) || - ((detected_platform() == BOARD_ID_PRALINE) && - (changed & (RADIO_REG_GROUP_RATE | RADIO_REG_GROUP_FREQ)))) { - changed |= radio_update_bandwidth(radio, &tmp_bank[0]); - } - if (dirty & (RADIO_REG_GROUP_GAIN | (1 << RADIO_OPMODE))) { - changed |= radio_update_gain(radio, &tmp_bank[0]); - } - if (dirty & ((1 << RADIO_BIAS_TEE) | (1 << RADIO_OPMODE))) { - changed |= radio_update_bias_tee(radio, &tmp_bank[0]); - } - if (dirty & (1 << RADIO_TRIGGER)) { - changed |= radio_update_trigger(radio, &tmp_bank[0]); - } - if (dirty & (1 << RADIO_DC_BLOCK)) { - changed |= radio_update_dc_block(radio, &tmp_bank[0]); - } - if (dirty & (1 << RADIO_OPMODE)) { - changed |= radio_update_direction(radio, &tmp_bank[0]); + // rf_amp enable + radio_gain_t enable = radio_get_gain(radio, channel->id, RADIO_GAIN_RF_AMP); + result = radio_set_gain(radio, channel->id, RADIO_GAIN_RF_AMP, enable); + if (result != RADIO_OK) { + return result; } - if (radio->update_cb) { - radio->update_cb(changed); - } - return (changed != 0); -} + // gain + radio_gain_t gain; + if (config->mode == TRANSCEIVER_MODE_RX || + config->mode == TRANSCEIVER_MODE_RX_SWEEP) { + gain = radio_get_gain(radio, channel->id, RADIO_GAIN_RX_LNA); + result = radio_set_gain(radio, channel->id, RADIO_GAIN_RX_LNA, gain); + if (result != RADIO_OK) { + return result; + } -void radio_switch_opmode(radio_t* const radio, const transceiver_mode_t mode) -{ - radio_register_bank_t source_bank; - uint64_t value, previous; + gain = radio_get_gain(radio, channel->id, RADIO_GAIN_RX_VGA); + result = radio_set_gain(radio, channel->id, RADIO_GAIN_RX_VGA, gain); + if (result != RADIO_OK) { + return result; + } - switch (mode) { - case TRANSCEIVER_MODE_RX_SWEEP: - case TRANSCEIVER_MODE_RX: - source_bank = RADIO_BANK_RX; - break; - case TRANSCEIVER_MODE_TX: - case TRANSCEIVER_MODE_SS: - source_bank = RADIO_BANK_TX; - break; - default: - source_bank = RADIO_BANK_IDLE; - } - - nvic_disable_irq(NVIC_USB0_IRQ); - for (uint8_t reg = 0; reg < RADIO_NUM_REGS; reg++) { - value = radio->config[source_bank][reg]; - previous = radio->config[RADIO_BANK_REQUESTED][reg]; - if ((value != RADIO_UNSET) && (value != previous)) { - radio->config[RADIO_BANK_REQUESTED][reg] = value; - mark_dirty(radio, reg); + } else if (config->mode == TRANSCEIVER_MODE_TX) { + gain = radio_get_gain(radio, channel->id, RADIO_GAIN_TX_VGA); + result = radio_set_gain(radio, channel->id, RADIO_GAIN_TX_VGA, gain); + if (result != RADIO_OK) { + return result; } } - radio->config[RADIO_BANK_REQUESTED][RADIO_OPMODE] = mode; - mark_dirty(radio, RADIO_OPMODE); - nvic_enable_irq(NVIC_USB0_IRQ); - radio_update(radio); + // antenna + radio_antenna_t bias_tee = + radio_get_antenna(radio, channel->id, RADIO_ANTENNA_BIAS_TEE); + result = radio_set_antenna(radio, channel->id, RADIO_ANTENNA_BIAS_TEE, bias_tee); + if (result != RADIO_OK) { + return result; + } + + // finally, set the rf path direction + rf_path_set_direction(&rf_path, direction); + + return RADIO_OK; } diff --git a/firmware/common/radio.h b/firmware/common/radio.h index 8e12471a..60e2cc4d 100644 --- a/firmware/common/radio.h +++ b/firmware/common/radio.h @@ -1,5 +1,5 @@ /* - * Copyright 2012-2026 Great Scott Gadgets + * Copyright 2012-2025 Great Scott Gadgets * Copyright 2012 Jared Boone * Copyright 2013 Benjamin Vernoux * @@ -21,32 +21,59 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __RF_CONFIG_H__ +#define __RF_CONFIG_H__ -#include #include +#include -#include "fixed_point.h" -#include "transceiver_mode.h" +#include "rf_path.h" +#include "fpga.h" typedef enum { RADIO_OK = 1, RADIO_ERR_INVALID_PARAM = -2, - RADIO_ERR_INVALID_BANK = -3, - RADIO_ERR_INVALID_REGISTER = -4, + RADIO_ERR_INVALID_CONFIG = -3, + RADIO_ERR_INVALID_CHANNEL = -4, + RADIO_ERR_INVALID_ELEMENT = -5, RADIO_ERR_UNSUPPORTED_OPERATION = -10, RADIO_ERR_UNIMPLEMENTED = -19, RADIO_ERR_OTHER = -9999, } radio_error_t; -/* radio configuration modes */ typedef enum { - RADIO_CONFIG_LEGACY = 0, - RADIO_CONFIG_STANDARD = 1, - RADIO_CONFIG_EXT_PRECISION_RX = 2, - RADIO_CONFIG_EXT_PRECISION_TX = 3, - RADIO_CONFIG_HALF_PRECISION = 4, -} radio_config_mode_t; + RADIO_CHANNEL0 = 0x00, +} radio_chan_id; + +typedef enum { + RADIO_FILTER_BASEBAND = 0x00, +} radio_filter_id; + +typedef enum { + RADIO_SAMPLE_RATE_CLOCKGEN = 0x00, +} radio_sample_rate_id; + +typedef enum { + RADIO_FREQUENCY_RF = 0x00, + RADIO_FREQUENCY_IF = 0x01, + RADIO_FREQUENCY_OF = 0x02, +} radio_frequency_id; + +typedef enum { + RADIO_GAIN_RF_AMP = 0x00, + RADIO_GAIN_RX_LNA = 0x01, + RADIO_GAIN_RX_VGA = 0x02, + RADIO_GAIN_TX_VGA = 0x03, +} radio_gain_id; + +typedef enum { + RADIO_ANTENNA_BIAS_TEE = 0x00, +} radio_antenna_id; + +typedef enum { + RADIO_CLOCK_CLKIN = 0x00, + RADIO_CLOCK_CLKOUT = 0x01, +} radio_clock_id; typedef struct { uint32_t num; @@ -54,219 +81,185 @@ typedef struct { uint32_t hz; } radio_sample_rate_t; -/** - * Configurable registers stored as uint64_t. Any register may be set to - * RADIO_UNSET. When not RADIO_UNSET, some registers are read as a specific type - * as noted. - */ -typedef enum { - /** - * Radio transceiver operating mode of type transceiver_mode_t. - */ - RADIO_OPMODE = 0, - /** - * Center frequency (as seen by MCU/host) in 1/(2**24) Hz. - */ - RADIO_FREQUENCY_RF = 1, - /** - * Intermediate frequency in 1/(2**24) Hz that the quadrature - * transceiver is tuned to. Overrides RADIO_FREQUENCY_RF if specified. - */ - RADIO_FREQUENCY_IF = 2, - /** - * Local oscillator frequency in 1/(2**24) Hz of the front-end mixer. - * Overrides RADIO_FREQUENCY_RF if specified. - */ - RADIO_FREQUENCY_LO = 3, - /** - * Image reject path of type rf_path_filter_t. Overrides - * RADIO_FREQUENCY_RF if specified. - */ - RADIO_IMAGE_REJECT = 4, - /** - * Digital frequency conversion of type uint8_t in tau/(2**32) steps with - * respect to AFE clock. - */ - RADIO_ROTATION = 5, - /** - * Sample rate (as seen by MCU/host) in 1/(2**36) Hz. - */ - RADIO_SAMPLE_RATE = 6, - /** - * Base two logarithm of TX decimation ratio (0 means a ratio of 1). - */ - RADIO_RESAMPLE_TX = 7, - /** - * Base two logarithm of RX decimation ratio (0 means a ratio of 1). - */ - RADIO_RESAMPLE_RX = 8, - /** - * TX RF amplifier enable of type bool. - */ - RADIO_GAIN_TX_RF = 9, - /** - * TX IF amplifier gain in dB. - */ - RADIO_GAIN_TX_IF = 10, - /** - * RX RF amplifier enable of type bool. - */ - RADIO_GAIN_RX_RF = 11, - /** - * RX IF amplifier gain in dB. - */ - RADIO_GAIN_RX_IF = 12, - /** - * RX baseband amplifier gain in dB. - */ - RADIO_GAIN_RX_BB = 13, - /** - * TX baseband bandwidth in Hz. This controls analog baseband filter - * settings but is specified as the desired bandwidth centered in - * digital baseband as seen by the MCU/host. - */ - RADIO_BB_BANDWIDTH_TX = 14, - /** - * RX baseband bandwidth in Hz. This controls analog baseband filter - * settings but is specified as the desired bandwidth centered in - * digital baseband as seen by the MCU/host. - */ - RADIO_BB_BANDWIDTH_RX = 15, - /** - * Quadrature transceiver TX baseband LPF bandwidth in Hz. If no - * rotation is performed, this is set to match RADIO_BB_BANDWIDTH. - * Currently unused. - */ - RADIO_XCVR_TX_LPF = 16, - /** - * Quadrature transceiver RX baseband LPF bandwidth in Hz. If no - * rotation is performed, this is set to match RADIO_BB_BANDWIDTH. - * Currently unused. - */ - RADIO_XCVR_RX_LPF = 17, - /** - * Quadrature transceiver RX baseband HPF bandwidth in Hz. Currently - * unused. - */ - RADIO_XCVR_RX_HPF = 18, - /** - * Narrowband RX analog baseband LPF enable of type bool. Currently unused. - */ - RADIO_RX_NARROW_LPF = 19, - /** - * RF port bias tee enable of type bool. - */ - RADIO_BIAS_TEE = 20, - /** - * Trigger input enable of type bool. - */ - RADIO_TRIGGER = 21, - /** - * DC block enable of type bool. - */ - RADIO_DC_BLOCK = 22, - /** - * Correction factor for radio reference clock, of type fp_1_63_t. - */ - RADIO_CLOCK_CORRECTION = 23, -} radio_register_t; - -#define RADIO_NUM_REGS (24) -#define RADIO_UNSET (0xffffffffffffffff) - -/* register groups for bitfield convenience */ -#define RADIO_REG_GROUP_RATE \ - ((1 << RADIO_SAMPLE_RATE) | (1 << RADIO_RESAMPLE_TX) | \ - (1 << RADIO_RESAMPLE_RX) | (1 << RADIO_CLOCK_CORRECTION)) -#define RADIO_REG_GROUP_FREQ \ - ((1 << RADIO_FREQUENCY_RF) | (1 << RADIO_FREQUENCY_IF) | \ - (1 << RADIO_FREQUENCY_LO) | (1 << RADIO_IMAGE_REJECT) | (1 << RADIO_ROTATION) | \ - (1 << RADIO_CLOCK_CORRECTION)) -#define RADIO_REG_GROUP_BW \ - ((1 << RADIO_BB_BANDWIDTH_TX) | (1 << RADIO_BB_BANDWIDTH_RX) | \ - (1 << RADIO_XCVR_TX_LPF) | (1 << RADIO_XCVR_RX_LPF) | \ - (1 << RADIO_XCVR_RX_HPF) | (1 << RADIO_RX_NARROW_LPF)) -#define RADIO_REG_GROUP_GAIN \ - ((1 << RADIO_GAIN_TX_RF) | (1 << RADIO_GAIN_TX_IF) | (1 << RADIO_GAIN_RX_RF) | \ - (1 << RADIO_GAIN_RX_IF) | (1 << RADIO_GAIN_RX_BB)) - -/** - * Register bank RADIO_BANK_REQUESTED stores the active configuration. Active - * register settings are copied to the applied register when applied. - * - * The other three banks store settings that will be applied when switching to - * that operating mode. - * - * RADIO_BANK_ALL may be used to write to all banks at once except for - * RADIO_BANK_APPLIED. - */ -typedef enum { - RADIO_BANK_APPLIED = 0, - RADIO_BANK_REQUESTED = 1, - RADIO_BANK_IDLE = 2, - RADIO_BANK_RX = 3, - RADIO_BANK_TX = 4, - RADIO_BANK_ALL = 255, -} radio_register_bank_t; - -#define RADIO_NUM_BANKS (5) - -/** - * A callback function must be provided that configures clock generation to - * produce the requested sample clock frequency. The function must return the - * configured sample rate. A boolean program argument may be set to false to - * execute a dry run, returning the sample rate without configuring clock - * generation. - */ -typedef fp_28_36_t (*sample_rate_fn)(const fp_28_36_t sample_rate, const bool program); - -/** - * An optional callback may be provided that is called after each time the - * radio configuration has been updated. The single argument is a bitfield - * indicating registers that have been changed. - */ -typedef void (*update_fn)(const uint32_t changed_regs); +typedef struct { + uint64_t hz; +} radio_filter_t; typedef struct { - radio_config_mode_t config_mode; - uint64_t config[RADIO_NUM_BANKS][RADIO_NUM_REGS]; - volatile uint32_t regs_dirty; - update_fn update_cb; + union { + bool enable; + uint8_t db; + }; +} radio_gain_t; + +typedef struct { + uint64_t hz; // desired frequency + uint64_t if_hz; // intermediate frequency + uint64_t lo_hz; // front-end local oscillator frequency + uint8_t path; // image rejection filter path +} radio_frequency_t; + +typedef struct { + bool enable; +} radio_antenna_t; + +typedef struct { + bool enable; +} radio_clock_t; + +// legacy type, moved from hackrf_core +typedef enum { + CLOCK_SOURCE_HACKRF = 0, + CLOCK_SOURCE_EXTERNAL = 1, + CLOCK_SOURCE_PORTAPACK = 2, +} clock_source_t; + +// legacy type, moved from usb_api_transceiver +typedef enum { + TRANSCEIVER_MODE_OFF = 0, + TRANSCEIVER_MODE_RX = 1, + TRANSCEIVER_MODE_TX = 2, + TRANSCEIVER_MODE_SS = 3, + TRANSCEIVER_MODE_CPLD_UPDATE = 4, + TRANSCEIVER_MODE_RX_SWEEP = 5, +} transceiver_mode_t; + +#define RADIO_CHANNEL_COUNT 1 +#define RADIO_SAMPLE_RATE_COUNT 1 +#define RADIO_FILTER_COUNT 1 +#define RADIO_FREQUENCY_COUNT 4 +#define RADIO_GAIN_COUNT 4 +#define RADIO_ANTENNA_COUNT 1 +#define RADIO_CLOCK_COUNT 2 +#define RADIO_MODE_COUNT 6 + +typedef struct { + // sample rate elements + radio_sample_rate_t sample_rate[RADIO_SAMPLE_RATE_COUNT]; + + // filter elements + radio_filter_t filter[RADIO_FILTER_COUNT]; + + // gain elements + radio_gain_t gain[RADIO_GAIN_COUNT]; + + // frequency elements + radio_frequency_t frequency[RADIO_FREQUENCY_COUNT]; + + // antenna elements + radio_antenna_t antenna[RADIO_ANTENNA_COUNT]; + + // clock elements + radio_clock_t clock[RADIO_CLOCK_COUNT]; + + // trigger elements + bool trigger_enable; + + // currently active transceiver mode + transceiver_mode_t mode; + +#ifdef PRALINE + // resampling ratio is 2**n + uint8_t resampling_n; + + // quarter-rate shift configuration for offset tuning + fpga_quarter_shift_mode_t shift; +#endif + +} radio_config_t; + +typedef struct radio_channel_t { + radio_chan_id id; + radio_config_t config; + radio_config_t mode[RADIO_MODE_COUNT]; + clock_source_t clock_source; +} radio_channel_t; + +typedef struct radio_t { + radio_channel_t channel[RADIO_CHANNEL_COUNT]; } radio_t; -void radio_init(radio_t* const radio); - /** - * Write to one or more registers. Writes to RADIO_BANK_REQUESTED are applied at - * the next radio_update(). Writes to RADIO_BANK_APPLIED are not supported. + * API Notes + * + * - All radio_set_*() functions return a radio_error_t + * - radio_set_*() functions work as follows: + * - if the channel mode is TRANSCEIVER_MODE_OFF only the configuration will + * be updated, the hardware state will remain unaffected. + * - if the channel is something other than TRANSCEIVER_MODE_OFF both the + * configuration and hardware state will be updated. + * - this makes it possible to maintain multiple channel configurations and + * switch between them with a single call to radio_switch_mode() */ -radio_error_t radio_reg_write( - radio_t* const radio, - const radio_register_bank_t bank, - const radio_register_t reg, - const uint64_t value); -/** - * Read from a register. - */ -uint64_t radio_reg_read( - radio_t* const radio, - const radio_register_bank_t bank, - const radio_register_t reg); +radio_error_t radio_set_sample_rate( + radio_t* radio, + radio_chan_id chan_id, + radio_sample_rate_id element, + radio_sample_rate_t sample_rate); +radio_sample_rate_t radio_get_sample_rate( + radio_t* radio, + radio_chan_id chan_id, + radio_sample_rate_id element); -/** - * Apply changes requested in RADIO_BANK_REQUESTED. - * Return true if any changes were applied. - */ -bool radio_update(radio_t* const radio); +radio_error_t radio_set_filter( + radio_t* radio, + radio_chan_id chan_id, + radio_filter_id element, + radio_filter_t filter); +radio_filter_t radio_get_filter( + radio_t* radio, + radio_chan_id chan_id, + radio_filter_id element); -/** - * Switch to a new operating mode and apply complete configuration stored in - * the request bank for the new mode. - */ -void radio_switch_opmode(radio_t* const radio, const transceiver_mode_t mode); +radio_error_t radio_set_frequency( + radio_t* radio, + radio_chan_id chan_id, + radio_frequency_id element, + radio_frequency_t frequency); +radio_frequency_t radio_get_frequency( + radio_t* radio, + radio_chan_id chan_id, + radio_frequency_id element); -/** - * Driver instance. - */ -extern radio_t radio; +radio_error_t radio_set_gain( + radio_t* radio, + radio_chan_id chan_id, + radio_gain_id element, + radio_gain_t gain); +radio_gain_t radio_get_gain(radio_t* radio, radio_chan_id chan_id, radio_gain_id element); + +radio_error_t radio_set_antenna( + radio_t* radio, + radio_chan_id chan_id, + radio_antenna_id element, + radio_antenna_t value); +radio_antenna_t radio_get_antenna( + radio_t* radio, + radio_chan_id chan_id, + radio_antenna_id element); + +radio_error_t radio_set_clock( + radio_t* radio, + radio_chan_id chan_id, + radio_clock_id element, + radio_clock_t value); +radio_clock_t radio_get_clock( + radio_t* radio, + radio_chan_id chan_id, + radio_clock_id element); + +radio_error_t radio_set_trigger_enable(radio_t* radio, radio_chan_id chan_id, bool enable); +bool radio_get_trigger_enable(radio_t* radio, radio_chan_id chan_id); + +transceiver_mode_t radio_get_mode(radio_t* radio, radio_chan_id chan_id); +rf_path_direction_t radio_get_direction(radio_t* radio, radio_chan_id chan_id); +clock_source_t radio_get_clock_source(radio_t* radio, radio_chan_id chan_id); + +// apply the current channel configuration and switch to the given transceiver mode +radio_error_t radio_switch_mode( + radio_t* radio, + radio_chan_id chan_id, + transceiver_mode_t mode); + +#endif /*__RF_CONFIG_H__*/ diff --git a/firmware/common/rf_path.c b/firmware/common/rf_path.c index 51488c16..5f41ec0c 100644 --- a/firmware/common/rf_path.c +++ b/firmware/common/rf_path.c @@ -1,5 +1,5 @@ /* - * Copyright 2012-2026 Great Scott Gadgets + * Copyright 2012-2022 Great Scott Gadgets * Copyright 2012 Jared Boone * Copyright 2013 Benjamin Vernoux * @@ -23,70 +23,71 @@ #include "rf_path.h" +#include + +#include + +#include "hackrf_ui.h" +#include "gpio_lpc.h" +#include "platform_detect.h" +#include "mixer.h" +#include "max2831.h" #include "max283x.h" #include "max5864.h" -#include "mixer.h" -#include "platform_detect.h" -#ifdef IS_NOT_JAWBREAKER - #include - #include "platform_scu.h" - #include "platform_gpio.h" +#include "sgpio.h" +#include "user_config.h" + +#if (defined JAWBREAKER || defined HACKRF_ONE || defined RAD1O || defined PRALINE) + /* + * RF switches on Jawbreaker are controlled by General Purpose Outputs (GPO) on + * the RFFC5072. + * + * On HackRF One, the same signals are controlled by GPIO on the LPC. + * SWITCHCTRL_NO_TX_AMP_PWR and SWITCHCTRL_NO_RX_AMP_PWR are not normally used + * on HackRF One as the amplifier power is instead controlled only by + * SWITCHCTRL_AMP_BYPASS. + * + * The rad1o also uses GPIO pins to control the different switches. The amplifiers + * are also connected to the LPC. + * + * On Praline, a subset of control signals is managed by GPIO pins on the LPC, while + * the remaining signals are generated through combinatorial logic in hardware. + */ + #define SWITCHCTRL_NO_TX_AMP_PWR (1 << 0) /* GPO1 turn off TX amp power */ + #define SWITCHCTRL_AMP_BYPASS (1 << 1) /* GPO2 bypass amp section */ + #define SWITCHCTRL_TX (1 << 2) /* GPO3 1 for TX mode, 0 for RX mode */ + #define SWITCHCTRL_MIX_BYPASS (1 << 3) /* GPO4 bypass RFFC5072 mixer section */ + #define SWITCHCTRL_HP (1 << 4) /* GPO5 1 for high-pass, 0 for low-pass */ + #define SWITCHCTRL_NO_RX_AMP_PWR (1 << 5) /* GPO6 turn off RX amp power */ + + /* + GPO6 GPO5 GPO4 GPO3 GPO2 GPO1 + !RXAMP HP MIXBP TX AMPBP !TXAMP Mix mode Amp mode + 1 X 1 1 1 1 TX bypass Bypass + 1 X 1 1 0 0 TX bypass TX amplified + 1 1 0 1 1 1 TX high Bypass + 1 1 0 1 0 0 TX high TX amplified + 1 0 0 1 1 1 TX low Bypass + 1 0 0 1 0 0 TX low TX amplified + 1 X 1 0 1 1 RX bypass Bypass + 0 X 1 0 0 1 RX bypass RX amplified + 1 1 0 0 1 1 RX high Bypass + 0 1 0 0 0 1 RX high RX amplified + 1 0 0 0 1 1 RX low Bypass + 0 0 0 0 0 1 RX low RX amplified + */ + + /* + * Safe (initial) switch settings turn off both amplifiers and enable both amp + * bypass and mixer bypass. + */ + #define SWITCHCTRL_SAFE \ + (SWITCHCTRL_NO_TX_AMP_PWR | SWITCHCTRL_AMP_BYPASS | SWITCHCTRL_TX | \ + SWITCHCTRL_MIX_BYPASS | SWITCHCTRL_HP | SWITCHCTRL_NO_RX_AMP_PWR) #endif -/* RF Path instance. */ -rf_path_t rf_path = { - .switchctrl = 0, -}; - /* - * RF switches on Jawbreaker are controlled by General Purpose Outputs (GPO) on - * the RFFC5072. - * - * On HackRF One, the same signals are controlled by GPIO on the LPC. - * SWITCHCTRL_NO_TX_AMP_PWR and SWITCHCTRL_NO_RX_AMP_PWR are not normally used - * on HackRF One as the amplifier power is instead controlled only by - * SWITCHCTRL_AMP_BYPASS. - * - * The rad1o also uses GPIO pins to control the different switches. The amplifiers - * are also connected to the LPC. - * - * On Praline, a subset of control signals is managed by GPIO pins on the LPC, while - * the remaining signals are generated through combinatorial logic in hardware. - */ -#define SWITCHCTRL_NO_TX_AMP_PWR (1 << 0) /* GPO1 turn off TX amp power */ -#define SWITCHCTRL_AMP_BYPASS (1 << 1) /* GPO2 bypass amp section */ -#define SWITCHCTRL_TX (1 << 2) /* GPO3 1 for TX mode, 0 for RX mode */ -#define SWITCHCTRL_MIX_BYPASS (1 << 3) /* GPO4 bypass RFFC5072 mixer section */ -#define SWITCHCTRL_HP (1 << 4) /* GPO5 1 for high-pass, 0 for low-pass */ -#define SWITCHCTRL_NO_RX_AMP_PWR (1 << 5) /* GPO6 turn off RX amp power */ - -/* - * GPO6 GPO5 GPO4 GPO3 GPO2 GPO1 - * !RXAMP HP MIXBP TX AMPBP !TXAMP Mix mode Amp mode - * 1 X 1 1 1 1 TX bypass Bypass - * 1 X 1 1 0 0 TX bypass TX amplified - * 1 1 0 1 1 1 TX high Bypass - * 1 1 0 1 0 0 TX high TX amplified - * 1 0 0 1 1 1 TX low Bypass - * 1 0 0 1 0 0 TX low TX amplified - * 1 X 1 0 1 1 RX bypass Bypass - * 0 X 1 0 0 1 RX bypass RX amplified - * 1 1 0 0 1 1 RX high Bypass - * 0 1 0 0 0 1 RX high RX amplified - * 1 0 0 0 1 1 RX low Bypass - * 0 0 0 0 0 1 RX low RX amplified - */ - -/* - * Safe (initial) switch settings turn off both amplifiers and enable both amp - * bypass and mixer bypass. - */ -#define SWITCHCTRL_SAFE \ - (SWITCHCTRL_NO_TX_AMP_PWR | SWITCHCTRL_AMP_BYPASS | SWITCHCTRL_TX | \ - SWITCHCTRL_MIX_BYPASS | SWITCHCTRL_HP | SWITCHCTRL_NO_RX_AMP_PWR) - -/* - * Antenna port power on HackRF One (except r9) is controlled by GPO1 on the + * Antenna port power on HackRF One (prior to r9) is controlled by GPO1 on the * RFFC5072. This is the only thing we use RFFC5072 GPO for on HackRF One. * The value of SWITCHCTRL_NO_ANT_PWR does not correspond to the GPO1 bit in * the gpo register. @@ -94,18 +95,22 @@ rf_path_t rf_path = { #define SWITCHCTRL_ANT_PWR (1 << 6) /* turn on antenna port power */ -#ifdef IS_HACKRF_ONE +#ifdef HACKRF_ONE +/* + * In HackRF One r9 this control signal has been moved to the microcontroller. + */ + +static struct gpio_t gpio_h1r9_no_ant_pwr = GPIO(2, 4); + static void switchctrl_set_hackrf_one(rf_path_t* const rf_path, uint8_t ctrl) { - board_id_t board_id = detected_platform(); - if (ctrl & SWITCHCTRL_TX) { - if (board_id != BOARD_ID_HACKRF1_R9) { + if (detected_platform() != BOARD_ID_HACKRF1_R9) { gpio_set(rf_path->gpio_tx); } gpio_clear(rf_path->gpio_rx); } else { - if (board_id != BOARD_ID_HACKRF1_R9) { + if (detected_platform() != BOARD_ID_HACKRF1_R9) { gpio_clear(rf_path->gpio_tx); } gpio_set(rf_path->gpio_rx); @@ -168,11 +173,11 @@ static void switchctrl_set_hackrf_one(rf_path_t* const rf_path, uint8_t ctrl) gpio_set(rf_path->gpio_no_rx_amp_pwr); } - if (board_id == BOARD_ID_HACKRF1_R9) { + if (detected_platform() == BOARD_ID_HACKRF1_R9) { if (ctrl & SWITCHCTRL_ANT_PWR) { - gpio_clear(rf_path->gpio_h1r9_no_ant_pwr); + gpio_clear(&gpio_h1r9_no_ant_pwr); } else { - gpio_set(rf_path->gpio_h1r9_no_ant_pwr); + gpio_set(&gpio_h1r9_no_ant_pwr); } } else { if (ctrl & SWITCHCTRL_ANT_PWR) { @@ -188,7 +193,7 @@ static void switchctrl_set_hackrf_one(rf_path_t* const rf_path, uint8_t ctrl) } #endif -#ifdef IS_PRALINE +#ifdef PRALINE static void switchctrl_set_praline(rf_path_t* const rf_path, uint8_t ctrl) { if (ctrl & SWITCHCTRL_TX) { @@ -229,7 +234,7 @@ static void switchctrl_set_praline(rf_path_t* const rf_path, uint8_t ctrl) } #endif -#ifdef IS_RAD1O +#ifdef RAD1O static void switchctrl_set_rad1o(rf_path_t* const rf_path, uint8_t ctrl) { if (ctrl & SWITCHCTRL_TX) { @@ -296,293 +301,163 @@ static void switchctrl_set_rad1o(rf_path_t* const rf_path, uint8_t ctrl) static void switchctrl_set(rf_path_t* const rf_path, const uint8_t gpo) { -#ifdef IS_JAWBREAKER - if (IS_JAWBREAKER) { - (void) rf_path; - mixer_set_gpo(&mixer, gpo); - } -#endif -#ifdef IS_HACKRF_ONE - if (IS_HACKRF_ONE) { - switchctrl_set_hackrf_one(rf_path, gpo); - } -#endif -#ifdef IS_PRALINE - if (IS_PRALINE) { - switchctrl_set_praline(rf_path, gpo); - } -#endif -#ifdef IS_RAD1O - if (IS_RAD1O) { - switchctrl_set_rad1o(rf_path, gpo); - } -#endif -} - -void rf_path_pin_shutdown(void) -{ -#ifdef IS_PRALINE - if (IS_PRALINE) { - const platform_scu_t* scu = platform_scu(); - - /* Configure RF switch control signals */ - scu_pinmux(scu->TX_EN, SCU_GPIO_PDN | SCU_CONF_FUNCTION0); - board_rev_t rev = detected_revision(); - if ((rev == BOARD_REV_PRALINE_R1_0) || - (rev == BOARD_REV_GSG_PRALINE_R1_0)) { - scu_pinmux(scu->MIX_EN_N_R1_0, SCU_GPIO_PDN | SCU_CONF_FUNCTION4); - } else { - scu_pinmux(scu->MIX_EN_N, SCU_GPIO_PDN | SCU_CONF_FUNCTION0); - } - scu_pinmux(scu->LPF_EN, SCU_GPIO_PDN | SCU_CONF_FUNCTION0); - scu_pinmux(scu->RF_AMP_EN, SCU_GPIO_PDN | SCU_CONF_FUNCTION0); - - /* Configure antenna port power control signal */ - scu_pinmux(scu->ANT_BIAS_EN_N, SCU_GPIO_PDN | SCU_CONF_FUNCTION0); - - /* Configure RF power supply (VAA) switch */ - scu_pinmux(scu->NO_VAA_ENABLE, SCU_GPIO_PDN | SCU_CONF_FUNCTION0); - - /* Disable narrowband filter. */ - narrowband_filter_set(0); - gpio_output(platform_gpio()->aa_en); - } +#ifdef JAWBREAKER + (void) rf_path; /* silence unused param warning */ + mixer_set_gpo(&mixer, gpo); +#elif HACKRF_ONE + switchctrl_set_hackrf_one(rf_path, gpo); +#elif PRALINE + switchctrl_set_praline(rf_path, gpo); +#elif RAD1O + switchctrl_set_rad1o(rf_path, gpo); +#else + (void) gpo; #endif } void rf_path_pin_setup(rf_path_t* const rf_path) { -#ifdef IS_JAWBREAKER - (void) rf_path; +#ifdef HACKRF_ONE + /* Configure RF switch control signals */ + // clang-format off + scu_pinmux(SCU_HP, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + scu_pinmux(SCU_LP, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + scu_pinmux(SCU_TX_MIX_BP, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + scu_pinmux(SCU_NO_MIX_BYPASS, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + scu_pinmux(SCU_RX_MIX_BP, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + scu_pinmux(SCU_TX_AMP, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + scu_pinmux(SCU_MIX_BYPASS, SCU_GPIO_FAST | SCU_CONF_FUNCTION4); + scu_pinmux(SCU_NO_TX_AMP_PWR, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + scu_pinmux(SCU_AMP_BYPASS, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + scu_pinmux(SCU_RX_AMP, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + scu_pinmux(SCU_NO_RX_AMP_PWR, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + // clang-format on + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + scu_pinmux(SCU_H1R9_RX, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + scu_pinmux(SCU_H1R9_NO_ANT_PWR, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + gpio_clear(&gpio_h1r9_no_ant_pwr); + gpio_output(&gpio_h1r9_no_ant_pwr); + scu_pinmux(SCU_H1R9_NO_VAA_EN, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + } else { + scu_pinmux(SCU_TX, SCU_GPIO_FAST | SCU_CONF_FUNCTION4); + scu_pinmux(SCU_RX, SCU_GPIO_FAST | SCU_CONF_FUNCTION4); + gpio_output(rf_path->gpio_tx); + scu_pinmux(SCU_NO_VAA_ENABLE, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + } + + /* + * Safe (initial) switch settings turn off both amplifiers and antenna port + * power and enable both amp bypass and mixer bypass. + */ + switchctrl_set(rf_path, SWITCHCTRL_SAFE); + + /* Configure RF switch control signals as outputs */ + gpio_output(rf_path->gpio_amp_bypass); + gpio_output(rf_path->gpio_no_mix_bypass); + gpio_output(rf_path->gpio_rx_amp); + gpio_output(rf_path->gpio_no_rx_amp_pwr); + gpio_output(rf_path->gpio_hp); + gpio_output(rf_path->gpio_lp); + gpio_output(rf_path->gpio_tx_mix_bp); + gpio_output(rf_path->gpio_rx_mix_bp); + gpio_output(rf_path->gpio_tx_amp); + gpio_output(rf_path->gpio_no_tx_amp_pwr); + gpio_output(rf_path->gpio_mix_bypass); + gpio_output(rf_path->gpio_rx); +#elif RAD1O + /* Configure RF switch control signals */ + // clang-format off + scu_pinmux(SCU_BY_AMP, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + scu_pinmux(SCU_BY_AMP_N, SCU_GPIO_FAST | SCU_CONF_FUNCTION4); + scu_pinmux(SCU_TX_RX, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + scu_pinmux(SCU_TX_RX_N, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + scu_pinmux(SCU_BY_MIX, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + scu_pinmux(SCU_BY_MIX_N, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + scu_pinmux(SCU_LOW_HIGH_FILT, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + scu_pinmux(SCU_LOW_HIGH_FILT_N, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + scu_pinmux(SCU_TX_AMP, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + scu_pinmux(SCU_RX_LNA, SCU_GPIO_FAST | SCU_CONF_FUNCTION4); + scu_pinmux(SCU_MIXER_EN, SCU_GPIO_FAST | SCU_CONF_FUNCTION4); + // clang-format on + + /* Configure RF power supply (VAA) switch */ + scu_pinmux(SCU_VAA_ENABLE, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + + /* + * Safe (initial) switch settings turn off both amplifiers and antenna port + * power and enable both amp bypass and mixer bypass. + */ + switchctrl_set(rf_path, SWITCHCTRL_SAFE); + + /* Configure RF switch control signals as outputs */ + gpio_output(rf_path->gpio_tx_rx_n); + gpio_output(rf_path->gpio_tx_rx); + gpio_output(rf_path->gpio_by_mix); + gpio_output(rf_path->gpio_by_mix_n); + gpio_output(rf_path->gpio_by_amp); + gpio_output(rf_path->gpio_by_amp_n); + gpio_output(rf_path->gpio_mixer_en); + gpio_output(rf_path->gpio_low_high_filt); + gpio_output(rf_path->gpio_low_high_filt_n); + gpio_output(rf_path->gpio_tx_amp); + gpio_output(rf_path->gpio_rx_lna); +#elif PRALINE + /* Configure RF switch control signals */ + scu_pinmux(SCU_TX_EN, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + board_rev_t rev = detected_revision(); + if ((rev == BOARD_REV_PRALINE_R1_0) || (rev == BOARD_REV_GSG_PRALINE_R1_0)) { + scu_pinmux(SCU_MIX_EN_N_R1_0, SCU_GPIO_FAST | SCU_CONF_FUNCTION4); + } else { + scu_pinmux(SCU_MIX_EN_N, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + } + scu_pinmux(SCU_LPF_EN, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + scu_pinmux(SCU_RF_AMP_EN, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + + /* Configure antenna port power control signal */ + scu_pinmux(SCU_ANT_BIAS_EN_N, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + + /* Configure RF power supply (VAA) switch */ + scu_pinmux(SCU_NO_VAA_ENABLE, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + + /* + * Safe (initial) switch settings turn off both amplifiers and antenna port + * power and enable both amp bypass and mixer bypass. + */ + switchctrl_set(rf_path, SWITCHCTRL_SAFE); + + /* Configure RF switch control signals as outputs */ + gpio_output(rf_path->gpio_ant_bias_en_n); + gpio_output(rf_path->gpio_tx_en); + gpio_output(rf_path->gpio_mix_en_n); + gpio_output(rf_path->gpio_lpf_en); + gpio_output(rf_path->gpio_rf_amp_en); #else - const platform_gpio_t* gpio = platform_gpio(); - const platform_scu_t* scu = platform_scu(); -#endif - - // initialize rf_path struct and assign gpio's -#ifdef IS_HACKRF_ONE - if (IS_HACKRF_ONE) { - *rf_path = (rf_path_t){ - .switchctrl = 0, - .gpio_hp = gpio->hp, - .gpio_lp = gpio->lp, - .gpio_tx_mix_bp = gpio->tx_mix_bp, - .gpio_no_mix_bypass = gpio->no_mix_bypass, - .gpio_rx_mix_bp = gpio->rx_mix_bp, - .gpio_tx_amp = gpio->tx_amp, - .gpio_tx = gpio->tx, - .gpio_mix_bypass = gpio->mix_bypass, - .gpio_rx = gpio->rx, - .gpio_no_tx_amp_pwr = gpio->no_tx_amp_pwr, - .gpio_amp_bypass = gpio->amp_bypass, - .gpio_rx_amp = gpio->rx_amp, - .gpio_no_rx_amp_pwr = gpio->no_rx_amp_pwr, - }; - #ifdef IS_H1_R9 - if (IS_H1_R9) { - rf_path->gpio_rx = gpio->h1r9_rx; - rf_path->gpio_h1r9_no_ant_pwr = gpio->h1r9_no_ant_pwr; - } - #endif - } -#endif - -#ifdef IS_RAD1O - if (IS_RAD1O) { - *rf_path = (rf_path_t){ - .switchctrl = 0, - .gpio_tx_rx_n = gpio->tx_rx_n, - .gpio_tx_rx = gpio->tx_rx, - .gpio_by_mix = gpio->by_mix, - .gpio_by_mix_n = gpio->by_mix_n, - .gpio_by_amp = gpio->by_amp, - .gpio_by_amp_n = gpio->by_amp_n, - .gpio_mixer_en = gpio->mixer_en, - .gpio_low_high_filt = gpio->low_high_filt, - .gpio_low_high_filt_n = gpio->low_high_filt_n, - .gpio_tx_amp = gpio->tx_amp, - .gpio_rx_lna = gpio->rx_lna, - }; - } -#endif - -#ifdef IS_PRALINE - if (IS_PRALINE) { - *rf_path = (rf_path_t){ - .switchctrl = 0, - .gpio_tx_en = gpio->tx_en, - .gpio_mix_en_n = gpio->mix_en_n, - .gpio_lpf_en = gpio->lpf_en, - .gpio_rf_amp_en = gpio->rf_amp_en, - .gpio_ant_bias_en_n = gpio->ant_bias_en_n, - }; - if ((detected_revision() == BOARD_REV_PRALINE_R1_0) || - (detected_revision() == BOARD_REV_GSG_PRALINE_R1_0)) { - rf_path->gpio_mix_en_n = gpio->mix_en_n_r1_0; - } - scu_pinmux(scu->PINMUX_FPGA_CRESET, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0); - scu_pinmux(scu->PINMUX_FPGA_CDONE, SCU_GPIO_PUP | SCU_CONF_FUNCTION4); - scu_pinmux(scu->PINMUX_FPGA_SPI_CS, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0); - } -#endif - -#ifdef IS_HACKRF_ONE - if (IS_HACKRF_ONE) { - /* Configure RF switch control signals */ - // clang-format off - scu_pinmux(scu->HP, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); - scu_pinmux(scu->LP, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); - scu_pinmux(scu->TX_MIX_BP, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); - scu_pinmux(scu->NO_MIX_BYPASS, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); - scu_pinmux(scu->RX_MIX_BP, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); - scu_pinmux(scu->TX_AMP, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); - scu_pinmux(scu->MIX_BYPASS, SCU_GPIO_FAST | SCU_CONF_FUNCTION4); - scu_pinmux(scu->NO_TX_AMP_PWR, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); - scu_pinmux(scu->AMP_BYPASS, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); - scu_pinmux(scu->RX_AMP, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); - scu_pinmux(scu->NO_RX_AMP_PWR, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); - // clang-format on - #ifdef IS_H1_R9 - if (IS_H1_R9) { - scu_pinmux(scu->H1R9_RX, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); - scu_pinmux( - scu->H1R9_NO_ANT_PWR, - SCU_GPIO_FAST | SCU_CONF_FUNCTION0); - gpio_clear(rf_path->gpio_h1r9_no_ant_pwr); - gpio_output(rf_path->gpio_h1r9_no_ant_pwr); - scu_pinmux( - scu->H1R9_NO_VAA_EN, - SCU_GPIO_FAST | SCU_CONF_FUNCTION0); - } - #endif - #ifdef IS_NOT_H1_R9 - if (IS_NOT_H1_R9) { - scu_pinmux(scu->TX, SCU_GPIO_FAST | SCU_CONF_FUNCTION4); - scu_pinmux(scu->RX, SCU_GPIO_FAST | SCU_CONF_FUNCTION4); - gpio_output(rf_path->gpio_tx); - scu_pinmux(scu->NO_VAA_ENABLE, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); - } - #endif - - /* - * Safe (initial) switch settings turn off both amplifiers and antenna port - * power and enable both amp bypass and mixer bypass. - */ - switchctrl_set(rf_path, SWITCHCTRL_SAFE); - - /* Configure RF switch control signals as outputs */ - gpio_output(rf_path->gpio_amp_bypass); - gpio_output(rf_path->gpio_no_mix_bypass); - gpio_output(rf_path->gpio_rx_amp); - gpio_output(rf_path->gpio_no_rx_amp_pwr); - gpio_output(rf_path->gpio_hp); - gpio_output(rf_path->gpio_lp); - gpio_output(rf_path->gpio_tx_mix_bp); - gpio_output(rf_path->gpio_rx_mix_bp); - gpio_output(rf_path->gpio_tx_amp); - gpio_output(rf_path->gpio_no_tx_amp_pwr); - gpio_output(rf_path->gpio_mix_bypass); - gpio_output(rf_path->gpio_rx); - } -#endif -#ifdef IS_RAD1O - if (IS_RAD1O) { - /* Configure RF switch control signals */ - // clang-format off - scu_pinmux(scu->BY_AMP, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); - scu_pinmux(scu->BY_AMP_N, SCU_GPIO_FAST | SCU_CONF_FUNCTION4); - scu_pinmux(scu->TX_RX, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); - scu_pinmux(scu->TX_RX_N, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); - scu_pinmux(scu->BY_MIX, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); - scu_pinmux(scu->BY_MIX_N, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); - scu_pinmux(scu->LOW_HIGH_FILT, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); - scu_pinmux(scu->LOW_HIGH_FILT_N, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); - scu_pinmux(scu->TX_AMP, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); - scu_pinmux(scu->RX_LNA, SCU_GPIO_FAST | SCU_CONF_FUNCTION4); - scu_pinmux(scu->MIXER_EN, SCU_GPIO_FAST | SCU_CONF_FUNCTION4); - // clang-format on - - /* Configure RF power supply (VAA) switch */ - scu_pinmux(scu->VAA_ENABLE, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); - - /* - * Safe (initial) switch settings turn off both amplifiers and antenna port - * power and enable both amp bypass and mixer bypass. - */ - switchctrl_set(rf_path, SWITCHCTRL_SAFE); - - /* Configure RF switch control signals as outputs */ - gpio_output(rf_path->gpio_tx_rx_n); - gpio_output(rf_path->gpio_tx_rx); - gpio_output(rf_path->gpio_by_mix); - gpio_output(rf_path->gpio_by_mix_n); - gpio_output(rf_path->gpio_by_amp); - gpio_output(rf_path->gpio_by_amp_n); - gpio_output(rf_path->gpio_mixer_en); - gpio_output(rf_path->gpio_low_high_filt); - gpio_output(rf_path->gpio_low_high_filt_n); - gpio_output(rf_path->gpio_tx_amp); - gpio_output(rf_path->gpio_rx_lna); - } -#endif - -#ifdef IS_PRALINE - if (IS_PRALINE) { - /* Configure RF switch control signals */ - scu_pinmux(scu->TX_EN, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); - board_rev_t rev = detected_revision(); - if ((rev == BOARD_REV_PRALINE_R1_0) || - (rev == BOARD_REV_GSG_PRALINE_R1_0)) { - scu_pinmux(scu->MIX_EN_N_R1_0, SCU_GPIO_FAST | SCU_CONF_FUNCTION4); - } else { - scu_pinmux(scu->MIX_EN_N, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); - } - scu_pinmux(scu->LPF_EN, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); - scu_pinmux(scu->RF_AMP_EN, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); - - /* Configure antenna port power control signal */ - scu_pinmux(scu->ANT_BIAS_EN_N, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); - - /* Configure RF power supply (VAA) switch */ - scu_pinmux(scu->NO_VAA_ENABLE, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); - - /* - * Safe (initial) switch settings turn off both amplifiers and antenna port - * power and enable both amp bypass and mixer bypass. - */ - switchctrl_set(rf_path, SWITCHCTRL_SAFE); - - /* Configure RF switch control signals as outputs */ - gpio_output(rf_path->gpio_ant_bias_en_n); - gpio_output(rf_path->gpio_tx_en); - gpio_output(rf_path->gpio_mix_en_n); - gpio_output(rf_path->gpio_lpf_en); - gpio_output(rf_path->gpio_rf_amp_en); - } + (void) rf_path; /* silence unused param warning */ #endif } void rf_path_init(rf_path_t* const rf_path) { + ssp1_set_mode_max5864(); max5864_setup(&max5864); max5864_shutdown(&max5864); - max283x_setup(&max283x); + ssp1_set_mode_max283x(); +#ifdef PRALINE + max2831_setup(&max283x); + max2831_start(&max283x); +#else + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + max283x_setup(&max283x, MAX2839_VARIANT); + } else { + max283x_setup(&max283x, MAX2837_VARIANT); + } max283x_start(&max283x); - -#ifdef IS_RAD1O - if (IS_RAD1O) { - mixer_setup(&mixer, MAX2871_VARIANT); - } #endif -#ifdef IS_NOT_RAD1O - if (IS_NOT_RAD1O) { - #ifdef IS_NOT_HACKRF_ONE - if (IS_NOT_HACKRF_ONE) { - mixer_setup(&mixer, RFFC5071_VARIANT); - } - #endif - } + + // On HackRF One, the mixer is now set up earlier in boot. +#ifndef HACKRF_ONE + mixer_setup(&mixer); #endif rf_path->switchctrl = SWITCHCTRL_SAFE; } @@ -592,6 +467,9 @@ void rf_path_set_direction(rf_path_t* const rf_path, const rf_path_direction_t d /* Turn off TX and RX amplifiers, then enable based on direction and bypass state. */ rf_path->switchctrl |= SWITCHCTRL_NO_TX_AMP_PWR | SWITCHCTRL_NO_RX_AMP_PWR; + // Perform any user-requested actions for mode switch + user_config_on_rf_path_direction_change(rf_path, direction); + switch (direction) { case RF_PATH_DIRECTION_TX: rf_path->switchctrl |= SWITCHCTRL_TX; @@ -599,13 +477,21 @@ void rf_path_set_direction(rf_path_t* const rf_path, const rf_path_direction_t d /* TX amplifier is in path, be sure to enable TX amplifier. */ rf_path->switchctrl &= ~SWITCHCTRL_NO_TX_AMP_PWR; } + mixer_tx(&mixer); if (rf_path->switchctrl & SWITCHCTRL_MIX_BYPASS) { mixer_disable(&mixer); } else { mixer_enable(&mixer); } + ssp1_set_mode_max5864(); max5864_tx(&max5864); + ssp1_set_mode_max283x(); +#ifdef PRALINE + max2831_tx(&max283x); +#else max283x_tx(&max283x); +#endif + sgpio_configure(&sgpio_config, SGPIO_DIRECTION_TX); break; case RF_PATH_DIRECTION_RX: @@ -614,26 +500,37 @@ void rf_path_set_direction(rf_path_t* const rf_path, const rf_path_direction_t d /* RX amplifier is in path, be sure to enable RX amplifier. */ rf_path->switchctrl &= ~SWITCHCTRL_NO_RX_AMP_PWR; } + mixer_rx(&mixer); if (rf_path->switchctrl & SWITCHCTRL_MIX_BYPASS) { mixer_disable(&mixer); } else { mixer_enable(&mixer); } + ssp1_set_mode_max5864(); max5864_rx(&max5864); + ssp1_set_mode_max283x(); +#ifdef PRALINE + max2831_rx(&max283x); +#else max283x_rx(&max283x); +#endif + sgpio_configure(&sgpio_config, SGPIO_DIRECTION_RX); break; -#ifdef IS_PRALINE +#ifdef PRALINE case RF_PATH_DIRECTION_TX_CALIBRATION: case RF_PATH_DIRECTION_RX_CALIBRATION: rf_path->switchctrl &= ~SWITCHCTRL_TX; mixer_disable(&mixer); + ssp1_set_mode_max5864(); max5864_xcvr(&max5864); + ssp1_set_mode_max283x(); if (direction == RF_PATH_DIRECTION_TX_CALIBRATION) { - max283x_tx_calibration(&max283x); + max2831_tx_calibration(&max283x); } else { - max283x_rx_calibration(&max283x); + max2831_rx_calibration(&max283x); } + sgpio_configure(&sgpio_config, SGPIO_DIRECTION_RX); break; #endif @@ -643,12 +540,21 @@ void rf_path_set_direction(rf_path_t* const rf_path, const rf_path_direction_t d /* Set RF path to receive direction when "off" */ rf_path->switchctrl &= ~SWITCHCTRL_TX; mixer_disable(&mixer); + ssp1_set_mode_max5864(); max5864_standby(&max5864); + ssp1_set_mode_max283x(); +#ifdef PRALINE + max2831_set_mode(&max283x, MAX2831_MODE_STANDBY); +#else max283x_set_mode(&max283x, MAX283x_MODE_STANDBY); +#endif + sgpio_configure(&sgpio_config, SGPIO_DIRECTION_RX); break; } switchctrl_set(rf_path, rf_path->switchctrl); + + hackrf_ui()->set_direction(direction); } void rf_path_set_filter(rf_path_t* const rf_path, const rf_path_filter_t filter) @@ -673,6 +579,8 @@ void rf_path_set_filter(rf_path_t* const rf_path, const rf_path_filter_t filter) } switchctrl_set(rf_path, rf_path->switchctrl); + + hackrf_ui()->set_filter(filter); } void rf_path_set_lna(rf_path_t* const rf_path, const uint_fast8_t enable) @@ -696,6 +604,8 @@ void rf_path_set_lna(rf_path_t* const rf_path, const uint_fast8_t enable) } switchctrl_set(rf_path, rf_path->switchctrl); + + hackrf_ui()->set_lna_power(enable); } /* antenna port power control */ @@ -708,11 +618,6 @@ void rf_path_set_antenna(rf_path_t* const rf_path, const uint_fast8_t enable) } switchctrl_set(rf_path, rf_path->switchctrl); -} -#ifdef IS_PRALINE -void narrowband_filter_set(const uint8_t value) -{ - gpio_write(platform_gpio()->aa_en, value & 1); -} -#endif + hackrf_ui()->set_antenna_bias(enable); +} \ No newline at end of file diff --git a/firmware/common/rf_path.h b/firmware/common/rf_path.h index a1796f13..0ebc75f2 100644 --- a/firmware/common/rf_path.h +++ b/firmware/common/rf_path.h @@ -21,19 +21,18 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __RFPATH_H__ +#define __RFPATH_H__ #include -#ifdef IS_NOT_JAWBREAKER - #include "gpio.h" -#endif +#include "gpio.h" typedef enum { RF_PATH_DIRECTION_OFF, RF_PATH_DIRECTION_RX, RF_PATH_DIRECTION_TX, -#ifdef IS_PRALINE +#ifdef PRALINE RF_PATH_DIRECTION_TX_CALIBRATION, RF_PATH_DIRECTION_RX_CALIBRATION, #endif @@ -45,53 +44,45 @@ typedef enum { RF_PATH_FILTER_HIGH_PASS = 2, } rf_path_filter_t; -typedef struct { +typedef struct rf_path_t { uint8_t switchctrl; - - struct { -#ifdef IS_HACKRF_ONE - gpio_t gpio_hp; - gpio_t gpio_lp; - gpio_t gpio_tx_mix_bp; - gpio_t gpio_no_mix_bypass; - gpio_t gpio_rx_mix_bp; - gpio_t gpio_tx_amp; - gpio_t gpio_tx; - gpio_t gpio_mix_bypass; - gpio_t gpio_rx; - gpio_t gpio_no_tx_amp_pwr; - gpio_t gpio_amp_bypass; - gpio_t gpio_rx_amp; - gpio_t gpio_no_rx_amp_pwr; - // In HackRF One r9 this control signal has been moved to the microcontroller. - gpio_t gpio_h1r9_no_ant_pwr; +#ifdef HACKRF_ONE + gpio_t gpio_hp; + gpio_t gpio_lp; + gpio_t gpio_tx_mix_bp; + gpio_t gpio_no_mix_bypass; + gpio_t gpio_rx_mix_bp; + gpio_t gpio_tx_amp; + gpio_t gpio_tx; + gpio_t gpio_mix_bypass; + gpio_t gpio_rx; + gpio_t gpio_no_tx_amp_pwr; + gpio_t gpio_amp_bypass; + gpio_t gpio_rx_amp; + gpio_t gpio_no_rx_amp_pwr; #endif - -#ifdef IS_RAD1O - gpio_t gpio_tx_rx_n; - gpio_t gpio_tx_rx; - gpio_t gpio_by_mix; - gpio_t gpio_by_mix_n; - gpio_t gpio_by_amp; - gpio_t gpio_by_amp_n; - gpio_t gpio_mixer_en; - gpio_t gpio_low_high_filt; - gpio_t gpio_low_high_filt_n; - gpio_t gpio_tx_amp; - gpio_t gpio_rx_lna; +#ifdef RAD1O + gpio_t gpio_tx_rx_n; + gpio_t gpio_tx_rx; + gpio_t gpio_by_mix; + gpio_t gpio_by_mix_n; + gpio_t gpio_by_amp; + gpio_t gpio_by_amp_n; + gpio_t gpio_mixer_en; + gpio_t gpio_low_high_filt; + gpio_t gpio_low_high_filt_n; + gpio_t gpio_tx_amp; + gpio_t gpio_rx_lna; #endif - -#ifdef IS_PRALINE - gpio_t gpio_tx_en; - gpio_t gpio_mix_en_n; - gpio_t gpio_lpf_en; - gpio_t gpio_rf_amp_en; - gpio_t gpio_ant_bias_en_n; +#ifdef PRALINE + gpio_t gpio_tx_en; + gpio_t gpio_mix_en_n; + gpio_t gpio_lpf_en; + gpio_t gpio_rf_amp_en; + gpio_t gpio_ant_bias_en_n; #endif - }; } rf_path_t; -void rf_path_pin_shutdown(void); void rf_path_pin_setup(rf_path_t* const rf_path); void rf_path_init(rf_path_t* const rf_path); @@ -102,9 +93,4 @@ void rf_path_set_filter(rf_path_t* const rf_path, const rf_path_filter_t filter) void rf_path_set_lna(rf_path_t* const rf_path, const uint_fast8_t enable); void rf_path_set_antenna(rf_path_t* const rf_path, const uint_fast8_t enable); -#ifdef IS_PRALINE -void narrowband_filter_set(const uint8_t value); -#endif - -/* RF Path instance. */ -extern rf_path_t rf_path; +#endif /*__RFPATH_H__*/ diff --git a/firmware/common/rffc5071.c b/firmware/common/rffc5071.c index d847b5c4..541dde2a 100644 --- a/firmware/common/rffc5071.c +++ b/firmware/common/rffc5071.c @@ -1,5 +1,5 @@ /* - * Copyright 2012-2026 Great Scott Gadgets + * Copyright 2012-2022 Great Scott Gadgets * Copyright 2014 Jared Boone * * This file is part of HackRF. @@ -31,25 +31,14 @@ * that the RFFC5071 includes a second mixer. */ -#include #include #include - -#include "delay.h" -#include "fixed_point.h" -#include "platform_detect.h" #include "rffc5071.h" #include "rffc5071_regs.def" // private register def macros #include "selftest.h" -#ifdef IS_PRALINE - #include - #include "platform_scu.h" -#endif -#define MIN(x, y) ((x) < (y) ? (x) : (y)) -#define MAX(x, y) ((x) > (y) ? (x) : (y)) - -static bool enabled = false; +#include +#include "hackrf_core.h" /* Default register values from vendor documentation or software. */ static const uint16_t rffc5071_regs_default[RFFC5071_NUM_REGS] = { @@ -110,13 +99,10 @@ void rffc5071_setup(rffc5071_driver_t* const drv) gpio_set(drv->gpio_reset); gpio_output(drv->gpio_reset); -#ifdef IS_PRALINE - if (IS_PRALINE) { - /* Configure mixer PLL lock detect pin */ - const platform_scu_t* scu = platform_scu(); - scu_pinmux(scu->MIXER_LD, scu->MIXER_LD_PINCFG); - gpio_input(drv->gpio_ld); - } +#ifdef PRALINE + /* Configure mixer PLL lock detect pin */ + scu_pinmux(SCU_MIXER_LD, SCU_MIXER_LD_PINCFG); + gpio_input(drv->gpio_ld); #endif rffc5071_init(drv); @@ -131,14 +117,9 @@ void rffc5071_setup(rffc5071_driver_t* const drv) /* GPOs are active at all times */ set_RFFC5071_GATE(drv, 1); - /* mixer 2 used for both RX and TX */ - set_RFFC5071_FULLD(drv, 0); - set_RFFC5071_MODE(drv, 1); - -#ifdef IS_H1_OR_PRALINE - if (IS_H1_OR_PRALINE) { - set_RFFC5071_LOCK(drv, 1); - } +#if defined(PRALINE) || defined(HACKRF_ONE) + /* Enable GPO Lock output signal */ + set_RFFC5071_LOCK(drv, 1); #endif /* Enable reference oscillator standby */ @@ -159,18 +140,14 @@ void rffc5071_lock_test(rffc5071_driver_t* const drv) for (int i = 0; i < NUM_LOCK_ATTEMPTS; i++) { // Tune to 100MHz. - rffc5071_set_frequency(drv, FP_MHZ(100), true); - rffc5071_enable(drv); + rffc5071_set_frequency(drv, 100000000); // Wait 1ms. - delay_ms(1); + delay_us_at_mhz(1000, 204); // Check for lock. lock = rffc5071_check_lock(drv); - rffc5071_disable(drv); - delay_us(100); - selftest.mixer_locks[i] = lock; } @@ -182,19 +159,13 @@ void rffc5071_lock_test(rffc5071_driver_t* const drv) bool rffc5071_check_lock(rffc5071_driver_t* const drv) { -#ifdef IS_PRALINE - if (IS_PRALINE) { - return gpio_read(drv->gpio_ld); - } +#ifdef PRALINE + return gpio_read(drv->gpio_ld); +#else + set_RFFC5071_READSEL(drv, 0b0001); + rffc5071_regs_commit(drv); + return !!(rffc5071_reg_read(drv, RFFC5071_READBACK_REG) & 0x8000); #endif -#ifdef IS_NOT_PRALINE - if (IS_NOT_PRALINE) { - set_RFFC5071_READSEL(drv, 0b0001); - rffc5071_regs_commit(drv); - return !!(rffc5071_reg_read(drv, RFFC5071_READBACK_REG) & 0x8000); - } -#endif - return false; } static uint16_t rffc5071_spi_read(rffc5071_driver_t* const drv, uint8_t r) @@ -202,7 +173,7 @@ static uint16_t rffc5071_spi_read(rffc5071_driver_t* const drv, uint8_t r) (void) drv; uint16_t data[] = {0x80 | (r & 0x7f), 0xffff}; - spi_bus_transfer(drv->bus, drv->bus->config, data, 2); + spi_bus_transfer(drv->bus, data, 2); return data[1]; } @@ -211,7 +182,7 @@ static void rffc5071_spi_write(rffc5071_driver_t* const drv, uint8_t r, uint16_t (void) drv; uint16_t data[] = {0x00 | (r & 0x7f), v}; - spi_bus_transfer(drv->bus, drv->bus->config, data, 2); + spi_bus_transfer(drv->bus, data, 2); } uint16_t rffc5071_reg_read(rffc5071_driver_t* const drv, uint8_t r) @@ -251,45 +222,64 @@ void rffc5071_regs_commit(rffc5071_driver_t* const drv) } } +void rffc5071_tx(rffc5071_driver_t* const drv) +{ + set_RFFC5071_ENBL(drv, 0); + set_RFFC5071_FULLD(drv, 0); + set_RFFC5071_MODE(drv, 1); /* mixer 2 used for both RX and TX */ + rffc5071_regs_commit(drv); +} + +void rffc5071_rx(rffc5071_driver_t* const drv) +{ + set_RFFC5071_ENBL(drv, 0); + set_RFFC5071_FULLD(drv, 0); + set_RFFC5071_MODE(drv, 1); /* mixer 2 used for both RX and TX */ + rffc5071_regs_commit(drv); +} + +/* + * This function turns on both mixer (full-duplex) on the RFFC5071, but our + * current hardware designs do not support full-duplex operation. + */ +void rffc5071_rxtx(rffc5071_driver_t* const drv) +{ + set_RFFC5071_ENBL(drv, 0); + set_RFFC5071_FULLD(drv, 1); /* mixer 1 and mixer 2 (RXTX) */ + rffc5071_regs_commit(drv); + + rffc5071_enable(drv); +} + void rffc5071_disable(rffc5071_driver_t* const drv) { - if (enabled) { - set_RFFC5071_ENBL(drv, 0); - rffc5071_regs_commit(drv); - enabled = false; - } + set_RFFC5071_ENBL(drv, 0); + rffc5071_regs_commit(drv); } void rffc5071_enable(rffc5071_driver_t* const drv) { - if (!enabled) { - set_RFFC5071_ENBL(drv, 1); - rffc5071_regs_commit(drv); - enabled = true; - } + set_RFFC5071_ENBL(drv, 1); + rffc5071_regs_commit(drv); } -#define REF_FREQ_HZ (40ULL * (1000ULL * 1000ULL)) -#define MIN_LO FP_KHZ(84375) -#define MAX_LO FP_MHZ(5400) +#define FREQ_ONE_MHZ (1000ULL * 1000ULL) +#define REF_FREQ (40 * FREQ_ONE_MHZ) +#define LO_MAX (5400 * FREQ_ONE_MHZ) -/* configure frequency synthesizer (lo in 1/(2**24) Hz) */ -fp_40_24_t rffc5071_config_synth(rffc5071_driver_t* const drv, fp_40_24_t lo, bool program) +/* configure frequency synthesizer (lo in Hz) */ +uint64_t rffc5071_config_synth(rffc5071_driver_t* const drv, uint64_t lo) { - fp_40_24_t fvco; + uint64_t fvco; uint8_t fbkdivlog; uint16_t n; - fp_40_24_t tune_freq; + uint64_t tune_freq_hz; uint16_t p1nmsb; uint8_t p1nlsb; - uint8_t charge_pump_leakage; - - lo = MIN(lo, MAX_LO); - lo = MAX(lo, MIN_LO); /* Calculate n_lo (no division) */ uint8_t n_lo = 0; - fp_40_24_t x = MAX_LO >> 1; + uint64_t x = LO_MAX >> 1; while ((x >= lo) && (n_lo < 5)) { n_lo++; x >>= 1; @@ -301,15 +291,15 @@ fp_40_24_t rffc5071_config_synth(rffc5071_driver_t* const drv, fp_40_24_t lo, bo * Higher charge pump leakage setting and fbkdivlog are required above * 3.2 GHz. */ - if (fvco > FP_MHZ(3200)) { + if (fvco > (3200 * FREQ_ONE_MHZ)) { fbkdivlog = 2; - charge_pump_leakage = 3; + set_RFFC5071_PLLCPL(drv, 3); } else { fbkdivlog = 1; - charge_pump_leakage = 2; + set_RFFC5071_PLLCPL(drv, 2); } - uint64_t tmp_n = (fvco / REF_FREQ_HZ) >> fbkdivlog; + uint64_t tmp_n = (fvco << (24ULL - fbkdivlog)) / REF_FREQ; /* Round to nearest step = ref_MHz / 2**s. For s=6, step=625000 Hz */ /* This also ensures the lowest 22-s fractional bits are set to 0. */ @@ -317,43 +307,34 @@ fp_40_24_t rffc5071_config_synth(rffc5071_driver_t* const drv, fp_40_24_t lo, bo const uint8_t d = (24 - fbkdivlog + n_lo) - s; tmp_n = ((tmp_n + (1 << (d - 1))) >> d) << d; - tune_freq = ((tmp_n * REF_FREQ_HZ) << fbkdivlog) >> n_lo; + n = tmp_n >> 24ULL; + p1nmsb = (tmp_n >> 8ULL) & 0xffff; + p1nlsb = tmp_n & 0xff; - if (program) { - set_RFFC5071_PLLCPL(drv, charge_pump_leakage); + tune_freq_hz = (tmp_n * REF_FREQ) >> (24 - fbkdivlog + n_lo); - n = tmp_n >> 24ULL; - p1nmsb = (tmp_n >> 8ULL) & 0xffff; - p1nlsb = tmp_n & 0xff; - - /* Path 2 */ - set_RFFC5071_P2LODIV(drv, n_lo); - set_RFFC5071_P2N(drv, n); - set_RFFC5071_P2PRESC(drv, fbkdivlog); - set_RFFC5071_P2NMSB(drv, p1nmsb); - if (s > 14) { - /* Only set when the step size is small enough. */ - set_RFFC5071_P2NLSB(drv, p1nlsb); - } - - rffc5071_regs_commit(drv); + /* Path 2 */ + set_RFFC5071_P2LODIV(drv, n_lo); + set_RFFC5071_P2N(drv, n); + set_RFFC5071_P2PRESC(drv, fbkdivlog); + set_RFFC5071_P2NMSB(drv, p1nmsb); + if (s > 14) { + /* Only set when the step size is small enough. */ + set_RFFC5071_P2NLSB(drv, p1nlsb); } - return tune_freq; + rffc5071_regs_commit(drv); + + return tune_freq_hz; } -fp_40_24_t rffc5071_set_frequency( - rffc5071_driver_t* const drv, - fp_40_24_t lo, - bool program) +uint64_t rffc5071_set_frequency(rffc5071_driver_t* const drv, uint64_t hz) { - fp_40_24_t tune_freq; + uint32_t tune_freq; - tune_freq = rffc5071_config_synth(drv, lo, program); - if (enabled && program) { - set_RFFC5071_RELOK(drv, 1); - rffc5071_regs_commit(drv); - } + rffc5071_disable(drv); + tune_freq = rffc5071_config_synth(drv, hz); + rffc5071_enable(drv); return tune_freq; } @@ -367,19 +348,9 @@ void rffc5071_set_gpo(rffc5071_driver_t* const drv, uint8_t gpo) rffc5071_regs_commit(drv); } -#ifdef IS_PRALINE +#ifdef PRALINE bool rffc5071_poll_ld(rffc5071_driver_t* const drv, uint8_t* prelock_state) { - // This is only supported on Praline hardware. - // - // For all other boards we'll just return true to avoid a situation where a - // a caller is waiting for a lock signal that will never be detected. - #ifdef IS_NOT_PRALINE - if (IS_NOT_PRALINE) { - return true; - } - #endif - // The RFFC5072 can be configured to output PLL lock status on // GPO4. The lock detect signal is produced by a window detector // on the VCO tuning voltage. It goes high to show PLL lock when diff --git a/firmware/common/rffc5071.h b/firmware/common/rffc5071.h index 40971061..164f6324 100644 --- a/firmware/common/rffc5071.h +++ b/firmware/common/rffc5071.h @@ -1,5 +1,5 @@ /* - * Copyright 2012-2026 Great Scott Gadgets + * Copyright 2012-2014 Great Scott Gadgets * Copyright 2014 Jared Boone * * This file is part of HackRF. @@ -20,14 +20,13 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __RFFC5071_H +#define __RFFC5071_H -#include #include -#include "fixed_point.h" -#include "gpio.h" #include "spi_bus.h" +#include "gpio.h" /* 31 registers, each containing 16 bits of data. */ #define RFFC5071_NUM_REGS 31 @@ -35,7 +34,7 @@ typedef struct { spi_bus_t* const bus; gpio_t gpio_reset; -#ifdef IS_PRALINE +#ifdef PRALINE gpio_t gpio_ld; #endif uint16_t regs[RFFC5071_NUM_REGS]; @@ -60,17 +59,21 @@ extern void rffc5071_reg_write(rffc5071_driver_t* const drv, uint8_t r, uint16_t * provided routines for those operations. */ extern void rffc5071_regs_commit(rffc5071_driver_t* const drv); -/* Set frequency in 1/(2**24) Hz. */ -extern fp_40_24_t rffc5071_set_frequency( - rffc5071_driver_t* const drv, - fp_40_24_t lo, - bool program); +/* Set frequency (Hz). */ +extern uint64_t rffc5071_set_frequency(rffc5071_driver_t* const drv, uint64_t hz); +/* Set up rx only, tx only, or full duplex. Chip should be disabled + * before _tx, _rx, or _rxtx are called. */ +extern void rffc5071_tx(rffc5071_driver_t* const drv); +extern void rffc5071_rx(rffc5071_driver_t* const drv); +extern void rffc5071_rxtx(rffc5071_driver_t* const drv); extern void rffc5071_enable(rffc5071_driver_t* const drv); extern void rffc5071_disable(rffc5071_driver_t* const drv); extern void rffc5071_set_gpo(rffc5071_driver_t* const drv, uint8_t); -#ifdef IS_PRALINE +#ifdef PRALINE extern bool rffc5071_poll_ld(rffc5071_driver_t* const drv, uint8_t* prelock_state); #endif extern bool rffc5071_check_lock(rffc5071_driver_t* const drv); + +#endif // __RFFC5071_H diff --git a/firmware/common/rffc5071_regs.def b/firmware/common/rffc5071_regs.def index dd352a03..022010c0 100644 --- a/firmware/common/rffc5071_regs.def +++ b/firmware/common/rffc5071_regs.def @@ -20,7 +20,8 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __RFFC5071_REGS_DEF +#define __RFFC5071_REGS_DEF #define RFFC5071_REG_SET_CLEAN(_d, _r) (_d->regs_dirty &= ~(1UL<<_r)) #define RFFC5071_REG_SET_DIRTY(_d, _r) (_d->regs_dirty |= (1UL<<_r)) @@ -256,3 +257,5 @@ __MREG__(RFFC5071_LFSR,30,9,1) __MREG__(RFFC5071_TSEL,30,10,2) __MREG__(RFFC5071_TMUX,30,12,3) __MREG__(RFFC5071_TEN,30,15,1) + +#endif // __RFFC5071_REGS_DEF diff --git a/firmware/common/rffc5071_spi.c b/firmware/common/rffc5071_spi.c index 6fd2c936..3254ebdb 100644 --- a/firmware/common/rffc5071_spi.c +++ b/firmware/common/rffc5071_spi.c @@ -20,14 +20,10 @@ * Boston, MA 02110-1301, USA. */ -#include "rffc5071_spi.h" - -#include -#include - #include +#include "hackrf_core.h" -#include "platform_scu.h" +#include "rffc5071_spi.h" static void rffc5071_spi_target_select(spi_bus_t* const bus) { @@ -69,9 +65,8 @@ static void rffc5071_spi_bus_init(spi_bus_t* const bus) { const rffc5071_spi_config_t* const config = bus->config; - const platform_scu_t* scu = platform_scu(); - scu_pinmux(scu->MIXER_SCLK, scu->MIXER_SCLK_PINCFG); - scu_pinmux(scu->MIXER_SDATA, scu->MIXER_SDATA_PINCFG); + scu_pinmux(SCU_MIXER_SCLK, SCU_MIXER_SCLK_PINCFG); + scu_pinmux(SCU_MIXER_SDATA, SCU_MIXER_SDATA_PINCFG); gpio_output(config->gpio_clock); rffc5071_spi_direction_out(bus); @@ -85,9 +80,8 @@ static void rffc5071_spi_target_init(spi_bus_t* const bus) const rffc5071_spi_config_t* const config = bus->config; /* Configure GPIO pins. */ - const platform_scu_t* scu = platform_scu(); - scu_pinmux(scu->MIXER_ENX, SCU_GPIO_FAST); - scu_pinmux(scu->MIXER_RESETX, SCU_GPIO_FAST); + scu_pinmux(SCU_MIXER_ENX, SCU_GPIO_FAST); + scu_pinmux(SCU_MIXER_RESETX, SCU_GPIO_FAST); /* Set GPIO pins as outputs. */ gpio_output(config->gpio_select); diff --git a/firmware/common/rffc5071_spi.h b/firmware/common/rffc5071_spi.h index 552d0769..fddf67d8 100644 --- a/firmware/common/rffc5071_spi.h +++ b/firmware/common/rffc5071_spi.h @@ -20,14 +20,14 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __RFFC5071_SPI_H +#define __RFFC5071_SPI_H -#include - -#include "gpio.h" #include "spi_bus.h" -typedef struct { +#include "gpio.h" + +typedef struct rffc5071_spi_config_t { gpio_t gpio_select; gpio_t gpio_clock; gpio_t gpio_data; @@ -40,3 +40,5 @@ void rffc5071_spi_transfer_gather( spi_bus_t* const bus, const spi_transfer_t* const transfer, const size_t count); + +#endif // __RFFC5071_SPI_H diff --git a/firmware/common/rom_iap.c b/firmware/common/rom_iap.c index ce1f113b..c926359a 100644 --- a/firmware/common/rom_iap.c +++ b/firmware/common/rom_iap.c @@ -20,6 +20,7 @@ * Boston, MA 02110-1301, USA. */ +#include "hackrf_core.h" #include #include "rom_iap.h" @@ -76,6 +77,7 @@ isp_iap_ret_code_t iap_cmd_call(iap_cmd_res_t* iap_cmd_res) Alternative way to retrieve Part Id on MCU with no IAP Read Serial No => Read Unique ID in SPIFI (only compatible with W25Q80BV */ + spi_bus_start(spi_flash.bus, &ssp_config_w25q80bv); w25q80bv_setup(&spi_flash); switch (iap_cmd_res->cmd_param.command_code) { diff --git a/firmware/common/rom_iap.h b/firmware/common/rom_iap.h index 8b027342..171f2678 100644 --- a/firmware/common/rom_iap.h +++ b/firmware/common/rom_iap.h @@ -20,10 +20,11 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __ROM_IAP__ +#define __ROM_IAP__ -#include #include +#include typedef enum { /* TODO define other commands */ @@ -92,7 +93,7 @@ typedef enum INVALID_FLASH_UNIT = 0x00000014, /* Invalid flash unit. */ USER_CODE_CHECKSUM = 0x00000015, ERROR_SETTING_ACTIVE_PARTITION = 0x00000016, - + /* Special Error */ ERROR_IAP_NOT_IMPLEMENTED = 0x00000100 /* IAP is not implemented in this part */ } isp_iap_ret_code_t; @@ -117,3 +118,5 @@ typedef struct { bool iap_is_implemented(void); isp_iap_ret_code_t iap_cmd_call(iap_cmd_res_t* iap_cmd_res); + +#endif //__ROM_IAP__ diff --git a/firmware/common/sct.h b/firmware/common/sct.h index 5bedfa75..61c43199 100644 --- a/firmware/common/sct.h +++ b/firmware/common/sct.h @@ -19,8 +19,6 @@ * Boston, MA 02110-1301, USA. */ -#pragma once - #include #include diff --git a/firmware/common/selftest.h b/firmware/common/selftest.h index cea60da2..86ee2213 100644 --- a/firmware/common/selftest.h +++ b/firmware/common/selftest.h @@ -19,7 +19,8 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __SELFTEST_H +#define __SELFTEST_H #include #include @@ -37,22 +38,23 @@ typedef uint8_t test_result_t; typedef struct { uint16_t mixer_id; -#ifdef IS_NOT_RAD1O +#ifndef RAD1O bool mixer_locks[NUM_LOCK_ATTEMPTS]; #endif -#ifdef IS_PRALINE +#ifdef PRALINE uint16_t max2831_mux_rssi_1; uint16_t max2831_mux_temp; uint16_t max2831_mux_rssi_2; bool max2831_mux_test_ok; -#endif +#else uint16_t max283x_readback_bad_value; uint16_t max283x_readback_expected_value; uint8_t max283x_readback_register_count; uint8_t max283x_readback_total_registers; +#endif uint8_t si5351_rev_id; bool si5351_readback_ok; -#ifdef IS_PRALINE +#ifdef PRALINE test_result_t fpga_image_load; test_result_t fpga_spi; test_result_t sgpio_rx; @@ -74,3 +76,5 @@ typedef struct { } selftest_t; extern selftest_t selftest; + +#endif // __SELFTEST_H diff --git a/firmware/common/sgpio.c b/firmware/common/sgpio.c index 1528933a..50b98d77 100644 --- a/firmware/common/sgpio.c +++ b/firmware/common/sgpio.c @@ -22,132 +22,50 @@ * Boston, MA 02110-1301, USA. */ -#include - -#include #include #include +#include "hackrf_core.h" #include "platform_detect.h" -#include "platform_gpio.h" -#include "platform_scu.h" -#include "sgpio.h" -#ifdef IS_NOT_PRALINE - #include "clock_io.h" -#endif -/* Driver configuration instance. */ -sgpio_config_t sgpio_config = { - .slice_mode_multislice = true, -}; +#include "sgpio.h" static void update_q_invert(sgpio_config_t* const config); -void sgpio_pin_shutdown(sgpio_config_t* const config) -{ - const platform_scu_t* scu = platform_scu(); - -#ifdef IS_PRALINE - if (IS_PRALINE) { - scu_pinmux(scu->PINMUX_SGPIO0, SCU_GPIO_PDN | SCU_CONF_FUNCTION0); - scu_pinmux(scu->PINMUX_SGPIO1, SCU_GPIO_PDN | SCU_CONF_FUNCTION0); - scu_pinmux(scu->PINMUX_SGPIO2, SCU_GPIO_PDN | SCU_CONF_FUNCTION0); - scu_pinmux(scu->PINMUX_SGPIO3, SCU_GPIO_PDN | SCU_CONF_FUNCTION0); - scu_pinmux(scu->PINMUX_SGPIO4, SCU_GPIO_PDN | SCU_CONF_FUNCTION4); - scu_pinmux(scu->PINMUX_SGPIO5, SCU_GPIO_PDN | SCU_CONF_FUNCTION0); - scu_pinmux(scu->PINMUX_SGPIO6, SCU_GPIO_PDN | SCU_CONF_FUNCTION4); - scu_pinmux(scu->PINMUX_SGPIO7, SCU_GPIO_PDN | SCU_CONF_FUNCTION0); - scu_pinmux(scu->PINMUX_SGPIO8, SCU_GPIO_PDN | SCU_CONF_FUNCTION0); - scu_pinmux(scu->PINMUX_SGPIO9, SCU_GPIO_PDN | SCU_CONF_FUNCTION0); - scu_pinmux(scu->PINMUX_SGPIO10, SCU_GPIO_PDN | SCU_CONF_FUNCTION0); - scu_pinmux(scu->PINMUX_SGPIO11, SCU_GPIO_PDN | SCU_CONF_FUNCTION0); - scu_pinmux(scu->PINMUX_SGPIO12, SCU_GPIO_PDN | SCU_CONF_FUNCTION0); - } -#endif - -#ifdef IS_H1_R9 - if (IS_H1_R9) { - scu_pinmux( - scu->H1R9_TRIGGER_EN, - SCU_GPIO_PDN | SCU_CONF_FUNCTION4); /* GPIO5[5] */ - } -#endif -#ifdef IS_NOT_H1_R9 - if (IS_NOT_H1_R9) { - scu_pinmux( - scu->TRIGGER_EN, - SCU_GPIO_PDN | SCU_CONF_FUNCTION4); /* GPIO5[12] */ - } -#endif - - gpio_input(config->gpio_q_invert); - -#ifdef IS_NOT_PRALINE - if (IS_NOT_PRALINE) { - trigger_enable(false); - gpio_output(config->gpio_trigger_enable); - } -#endif -} - void sgpio_configure_pin_functions(sgpio_config_t* const config) { - const platform_gpio_t* gpio = platform_gpio(); - const platform_scu_t* scu = platform_scu(); + scu_pinmux(SCU_PINMUX_SGPIO0, SCU_PINMUX_SGPIO0_PINCFG); + scu_pinmux(SCU_PINMUX_SGPIO1, SCU_PINMUX_SGPIO1_PINCFG); + scu_pinmux(SCU_PINMUX_SGPIO2, SCU_PINMUX_SGPIO2_PINCFG); + scu_pinmux(SCU_PINMUX_SGPIO3, SCU_PINMUX_SGPIO3_PINCFG); + scu_pinmux(SCU_PINMUX_SGPIO4, SCU_PINMUX_SGPIO4_PINCFG); + scu_pinmux(SCU_PINMUX_SGPIO5, SCU_PINMUX_SGPIO5_PINCFG); + scu_pinmux(SCU_PINMUX_SGPIO6, SCU_PINMUX_SGPIO6_PINCFG); + scu_pinmux(SCU_PINMUX_SGPIO7, SCU_PINMUX_SGPIO7_PINCFG); + scu_pinmux(SCU_PINMUX_SGPIO8, SCU_PINMUX_SGPIO8_PINCFG); + scu_pinmux(SCU_PINMUX_SGPIO9, SCU_PINMUX_SGPIO9_PINCFG); + scu_pinmux(SCU_PINMUX_SGPIO10, SCU_PINMUX_SGPIO10_PINCFG); + scu_pinmux(SCU_PINMUX_SGPIO11, SCU_PINMUX_SGPIO11_PINCFG); + scu_pinmux(SCU_PINMUX_SGPIO12, SCU_PINMUX_SGPIO12_PINCFG); /* GPIO0[13] */ + scu_pinmux(SCU_PINMUX_SGPIO14, SCU_PINMUX_SGPIO14_PINCFG); /* GPIO5[13] */ + scu_pinmux(SCU_PINMUX_SGPIO15, SCU_PINMUX_SGPIO15_PINCFG); /* GPIO5[14] */ - config->gpio_q_invert = gpio->q_invert; - -#ifdef IS_NOT_PRALINE - if (IS_NOT_PRALINE) { - config->gpio_trigger_enable = gpio->trigger_enable; - } -#endif - -#ifdef IS_H1_R9 - if (IS_H1_R9) { - config->gpio_trigger_enable = gpio->h1r9_trigger_enable; - } -#endif - - scu_pinmux(scu->PINMUX_SGPIO0, scu->PINMUX_SGPIO0_PINCFG); - scu_pinmux(scu->PINMUX_SGPIO1, scu->PINMUX_SGPIO1_PINCFG); - scu_pinmux(scu->PINMUX_SGPIO2, scu->PINMUX_SGPIO2_PINCFG); - scu_pinmux(scu->PINMUX_SGPIO3, scu->PINMUX_SGPIO3_PINCFG); - scu_pinmux(scu->PINMUX_SGPIO4, scu->PINMUX_SGPIO4_PINCFG); - scu_pinmux(scu->PINMUX_SGPIO5, scu->PINMUX_SGPIO5_PINCFG); - scu_pinmux(scu->PINMUX_SGPIO6, scu->PINMUX_SGPIO6_PINCFG); - scu_pinmux(scu->PINMUX_SGPIO7, scu->PINMUX_SGPIO7_PINCFG); - scu_pinmux(scu->PINMUX_SGPIO8, scu->PINMUX_SGPIO8_PINCFG); - scu_pinmux(scu->PINMUX_SGPIO9, scu->PINMUX_SGPIO9_PINCFG); - scu_pinmux(scu->PINMUX_SGPIO10, scu->PINMUX_SGPIO10_PINCFG); - scu_pinmux(scu->PINMUX_SGPIO11, scu->PINMUX_SGPIO11_PINCFG); - scu_pinmux(scu->PINMUX_SGPIO12, scu->PINMUX_SGPIO12_PINCFG); /* GPIO0[13] */ - scu_pinmux(scu->PINMUX_SGPIO14, scu->PINMUX_SGPIO14_PINCFG); /* GPIO5[13] */ - scu_pinmux(scu->PINMUX_SGPIO15, scu->PINMUX_SGPIO15_PINCFG); /* GPIO5[14] */ - -#ifdef IS_H1_R9 - if (IS_H1_R9) { + if (detected_platform() == BOARD_ID_HACKRF1_R9) { scu_pinmux( - scu->H1R9_TRIGGER_EN, + SCU_H1R9_TRIGGER_EN, SCU_GPIO_FAST | SCU_CONF_FUNCTION4); /* GPIO5[5] */ - } -#endif -#ifdef IS_NOT_H1_R9 - if (IS_NOT_H1_R9) { + } else { scu_pinmux( - scu->TRIGGER_EN, + SCU_TRIGGER_EN, SCU_GPIO_FAST | SCU_CONF_FUNCTION4); /* GPIO5[12] */ } -#endif sgpio_cpld_set_mixer_invert(config, 0); gpio_output(config->gpio_q_invert); -#ifdef IS_NOT_PRALINE - if (IS_NOT_PRALINE) { - trigger_enable(false); - gpio_output(config->gpio_trigger_enable); - } +#ifndef PRALINE + trigger_enable(false); + gpio_output(config->gpio_trigger_enable); #endif } @@ -230,11 +148,11 @@ void sgpio_configure(sgpio_config_t* const config, const sgpio_direction_t direc SGPIO_OUT_MUX_CFG_P_OE_CFG(0) // gpio_oe (state set by GPIO_OEREG) | SGPIO_OUT_MUX_CFG_P_OUT_CFG(0) // dout_doutm1 (1-bit mode) ; - SGPIO_OUT_MUX_CFG(10) = // GPIO10: Output: disable + SGPIO_OUT_MUX_CFG(10) = // GPIO10: Output: disable SGPIO_OUT_MUX_CFG_P_OE_CFG(0) // gpio_oe (state set by GPIO_OEREG) | SGPIO_OUT_MUX_CFG_P_OUT_CFG(4) // gpio_out (level set by GPIO_OUTREG) ; - SGPIO_OUT_MUX_CFG(11) = // GPIO11: Output: direction + SGPIO_OUT_MUX_CFG(11) = // GPIO11: Output: direction SGPIO_OUT_MUX_CFG_P_OE_CFG(0) // gpio_oe (state set by GPIO_OEREG) | SGPIO_OUT_MUX_CFG_P_OUT_CFG(4) // gpio_out (level set by GPIO_OUTREG) ; diff --git a/firmware/common/sgpio.h b/firmware/common/sgpio.h index 0aebdb5f..0d8e9f0f 100644 --- a/firmware/common/sgpio.h +++ b/firmware/common/sgpio.h @@ -20,10 +20,13 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __SGPIO_H__ +#define __SGPIO_H__ -#include #include +#include + +#include #include "gpio.h" @@ -32,15 +35,14 @@ typedef enum { SGPIO_DIRECTION_TX, } sgpio_direction_t; -typedef struct { +typedef struct sgpio_config_t { gpio_t gpio_q_invert; -#ifdef IS_NOT_PRALINE +#ifndef PRALINE gpio_t gpio_trigger_enable; #endif bool slice_mode_multislice; } sgpio_config_t; -void sgpio_pin_shutdown(sgpio_config_t* const config); void sgpio_configure_pin_functions(sgpio_config_t* const config); void sgpio_test_interface(sgpio_config_t* const config); void sgpio_set_slice_mode(sgpio_config_t* const config, const bool multi_slice); @@ -51,5 +53,4 @@ bool sgpio_cpld_stream_is_enabled(sgpio_config_t* const config); void sgpio_cpld_set_mixer_invert(sgpio_config_t* const config, uint_fast8_t invert); -/* Driver configuration instance. */ -extern sgpio_config_t sgpio_config; +#endif //__SGPIO_H__ diff --git a/firmware/common/si5351c.c b/firmware/common/si5351c.c index a455a23e..d9686ea1 100644 --- a/firmware/common/si5351c.c +++ b/firmware/common/si5351c.c @@ -1,5 +1,5 @@ /* - * Copyright 2012-2026 Great Scott Gadgets + * Copyright 2012-2022 Great Scott Gadgets * Copyright 2012 Jared Boone * * This file is part of HackRF. @@ -20,40 +20,32 @@ * Boston, MA 02110-1301, USA. */ -#include -#include -#include - -#include "clock_io.h" -#include "delay.h" -#include "i2c_lpc.h" -#include "platform_detect.h" -#include "selftest.h" #include "si5351c.h" -#ifdef IS_HACKRF_ONE - #include - #include "gpio.h" - #include "platform_gpio.h" - #include "platform_scu.h" -#endif +#include "clkin.h" +#include "platform_detect.h" +#include "gpio_lpc.h" +#include "hackrf_core.h" +#include "selftest.h" +#include -#include "si5351c_regs.def" +/* HackRF One r9 clock control */ +// clang-format off +static struct gpio_t gpio_h1r9_clkin_en = GPIO(5, 15); +static struct gpio_t gpio_h1r9_clkout_en = GPIO(0, 9); +static struct gpio_t gpio_h1r9_mcu_clk_en = GPIO(0, 8); +// clang-format on -/* Driver instance. */ -si5351c_driver_t si5351c = { - .bus = &i2c0, - .i2c_address = 0x60, -}; +#include + +static enum pll_sources active_clock_source = PLL_SOURCE_UNINITIALIZED; +/* External clock output default is deactivated as it creates noise */ +static bool clkout_enabled = false; /* write to single register */ void si5351c_write_single(si5351c_driver_t* const drv, uint8_t reg, uint8_t val) { const uint8_t data_tx[] = {reg, val}; - i2c_bus_transfer(drv->bus, drv->i2c_address, data_tx, 2, NULL, 0); - if (reg < SI5351C_CACHED_REGS) { - drv->regs[reg] = val; - si5351c_reg_set_clean(drv, reg); - } + si5351c_write(drv, data_tx, 2); } /* read single register */ @@ -62,100 +54,49 @@ uint8_t si5351c_read_single(si5351c_driver_t* const drv, uint8_t reg) const uint8_t data_tx[] = {reg}; uint8_t data_rx[] = {0x00}; i2c_bus_transfer(drv->bus, drv->i2c_address, data_tx, 1, data_rx, 1); - uint8_t val = data_rx[0]; - if (reg < SI5351C_CACHED_REGS) { - drv->regs[reg] = val; - si5351c_reg_set_clean(drv, reg); - } - return val; + return data_rx[0]; } -/* Commit changes to register values. */ -void si5351c_regs_commit(si5351c_driver_t* drv) +/* + * Write to one or more contiguous registers. data[0] should be the first + * register number, one or more values follow. + */ +void si5351c_write( + si5351c_driver_t* const drv, + const uint8_t* const data, + const size_t data_count) { - for (int start = 0; start < SI5351C_CACHED_REGS; start++) { - if (si5351c_reg_is_dirty(drv, start)) { - if (start == SI5351C_CACHED_REGS - 1) { - si5351c_write_single(drv, start, drv->regs[start]); - } else { - int end; - for (end = start + 1; end < 256; end++) { - if (!si5351c_reg_is_dirty(drv, end)) - break; - } - size_t len = 1 + (end - start); - uint8_t data_tx[len]; - data_tx[0] = start; - for (int i = 0; i < (end - start); i++) { - data_tx[1 + i] = drv->regs[start + i]; - } - i2c_bus_transfer( - drv->bus, - drv->i2c_address, - data_tx, - len, - NULL, - 0); - for (int i = start; i < end; i++) { - si5351c_reg_set_clean(drv, i); - } - start = end; - } - } - } - - /* Reset bits are self-clearing. */ - drv->regs[177] = 0; + i2c_bus_transfer(drv->bus, drv->i2c_address, data, data_count, NULL, 0); } /* Disable all CLKx outputs. */ void si5351c_disable_all_outputs(si5351c_driver_t* const drv) { - set_all_CLK_OEB(drv, SI5351C_OUTPUT_DISABLE); - si5351c_regs_commit(drv); -} - -/* Disable all CLKx outputs using selected PLL. */ -void si5351c_disable_pll_outputs(si5351c_driver_t* const drv, si5351c_pll_mask_t mask) -{ - /* For each CLKx output, check if it is using the specified PLL. */ - for (int op = 0; op < 8; op++) { - int ms; - /* First check which multisynth is used by this output. */ - switch (get_CLK_SRC(drv, op)) { - case SI5351C_SRC_MULTISYNTH_SELF: - ms = op; - break; - case SI5351C_SRC_MULTISYNTH_0_4: - ms = (op < 4) ? 0 : 4; - break; - default: - /* This output is not using any PLL */ - continue; - } - /* Now check which PLL is used by that multisynth. */ - if (mask & (1 << get_MS_SRC(drv, ms))) { - /* This output depends on the specified PLL; disable it. */ - set_CLK_OEB(drv, op, SI5351C_OUTPUT_DISABLE); - } - } - si5351c_regs_commit(drv); + uint8_t data[] = {3, 0xFF}; + si5351c_write(drv, data, sizeof(data)); } /* Turn off OEB pin control for all CLKx */ void si5351c_disable_oeb_pin_control(si5351c_driver_t* const drv) { - set_all_OEB_MASK(drv, true); - si5351c_regs_commit(drv); + uint8_t data[] = {9, 0xFF}; + si5351c_write(drv, data, sizeof(data)); } /* Power down all CLKx */ void si5351c_power_down_all_clocks(si5351c_driver_t* const drv) { - set_all_CLK_PDN(drv, true); - set_FBA_INT(drv, true); - set_FBB_INT(drv, true); - si5351c_regs_commit(drv); + uint8_t data[] = { + 16, + SI5351C_CLK_POWERDOWN, + SI5351C_CLK_POWERDOWN, + SI5351C_CLK_POWERDOWN, + SI5351C_CLK_POWERDOWN, + SI5351C_CLK_POWERDOWN, + SI5351C_CLK_POWERDOWN, + SI5351C_CLK_POWERDOWN | SI5351C_CLK_INT_MODE, + SI5351C_CLK_POWERDOWN | SI5351C_CLK_INT_MODE}; + si5351c_write(drv, data, sizeof(data)); } /* @@ -165,8 +106,8 @@ void si5351c_power_down_all_clocks(si5351c_driver_t* const drv) */ void si5351c_set_crystal_configuration(si5351c_driver_t* const drv) { - set_XTAL_CL(drv, SI5351C_XTAL_8PF); - si5351c_regs_commit(drv); + uint8_t data[] = {183, 0x80}; + si5351c_write(drv, data, sizeof(data)); } /* @@ -175,52 +116,41 @@ void si5351c_set_crystal_configuration(si5351c_driver_t* const drv) */ void si5351c_enable_xo_and_ms_fanout(si5351c_driver_t* const drv) { - set_CLKIN_FANOUT_EN(drv, true); - set_XO_FANOUT_EN(drv, true); - set_MS_FANOUT_EN(drv, true); - si5351c_regs_commit(drv); + uint8_t data[] = {187, 0xD0}; + si5351c_write(drv, data, sizeof(data)); } /* * Register 15: PLL Input Source * CLKIN_DIV=0 (Divide by 1) - * Set both PLLA_SRC and PLLB_SRC + * PLLA_SRC=0 (XTAL) + * PLLB_SRC=1 (CLKIN) */ -void si5351c_configure_inputs(si5351c_driver_t* const drv, const si5351c_input_t input) +void si5351c_configure_pll_sources(si5351c_driver_t* const drv) { - set_CLKIN_DIV(drv, SI5351C_DIV_1); - set_PLLA_SRC(drv, input); - set_PLLB_SRC(drv, input); - si5351c_regs_commit(drv); + uint8_t data[] = {15, 0x08}; + + si5351c_write(drv, data, sizeof(data)); } /* MultiSynth NA (PLLA) and NB (PLLB) */ -void si5351c_configure_pll_multisynth( - si5351c_driver_t* const drv, - const si5351c_input_t input) +void si5351c_configure_pll_multisynth(si5351c_driver_t* const drv) { - for (si5351c_pll_t pll = SI5351C_PLL_A; pll <= SI5351C_PLL_B; pll++) { - if (input == SI5351C_INPUT_CLKIN) { - /* CLKIN: 10 MHz * (0x2600 + 512) / 128 = 800 MHz, integer mode */ - set_MSN_P1(drv, pll, 0x2600); - } else { - /* XTAL: 25 MHz * (0x0e00 + 512) / 128 = 800 MHz, integer mode */ - set_MSN_P1(drv, pll, 0x0E00); - } - set_MSN_P2(drv, pll, 0); - set_MSN_P3(drv, pll, 1); - } - si5351c_regs_commit(drv); + /*PLLA: 25MHz XTAL * (0x0e00+512)/128 = 800mhz -> int mode */ + uint8_t data[] = {26, 0x00, 0x01, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00}; + si5351c_write(drv, data, sizeof(data)); + + /*PLLB: 10MHz CLKIN * (0x2600+512)/128 = 800mhz */ + data[0] = 34; + data[4] = 0x26; + si5351c_write(drv, data, sizeof(data)); } -void si5351c_reset_plls(si5351c_driver_t* const drv, si5351c_pll_mask_t mask) +void si5351c_reset_pll(si5351c_driver_t* const drv) { - si5351c_disable_pll_outputs(drv, mask); - set_PLLA_RST(drv, (mask & SI5351C_PLL_MASK_A) ? true : false); - set_PLLB_RST(drv, (mask & SI5351C_PLL_MASK_B) ? true : false); - si5351c_regs_commit(drv); - delay_ms(2); - si5351c_enable_clock_outputs(drv); + /* reset PLLA and PLLB */ + uint8_t data[] = {177, 0xA0}; + si5351c_write(drv, data, sizeof(data)); } void si5351c_configure_multisynth( @@ -243,37 +173,151 @@ void si5351c_configure_multisynth( * ... * 7 means divide by 128 */ - set_MS_P1(drv, ms_number, p1); - set_MS_P2(drv, ms_number, p2); - set_MS_P3(drv, ms_number, p3); - set_R_DIV(drv, ms_number, r_div); - si5351c_regs_commit(drv); + const uint_fast8_t register_number = 42 + (ms_number * 8); + uint8_t data[] = { + register_number, + (p3 >> 8) & 0xFF, + (p3 >> 0) & 0xFF, + (r_div << 4) | (0 << 2) | ((p1 >> 16) & 0x3), + (p1 >> 8) & 0xFF, + (p1 >> 0) & 0xFF, + (((p3 >> 16) & 0xF) << 4) | (((p2 >> 16) & 0xF) << 0), + (p2 >> 8) & 0xFF, + (p2 >> 0) & 0xFF}; + si5351c_write(drv, data, sizeof(data)); } -void si5351c_configure_clock_control(si5351c_driver_t* const drv) +void si5351c_configure_clock_control( + si5351c_driver_t* const drv, + const enum pll_sources source) { - for (int i = 0; i < 8; i++) { - set_CLK_PDN(drv, i, drv->clk[i].power_down); - set_MS_INT(drv, i, drv->clk[i].mode); - set_MS_SRC(drv, i, drv->clk[i].pll); - set_CLK_SRC(drv, i, drv->clk[i].source); - set_CLK_IDRV(drv, i, drv->clk[i].drive); - set_CLK_INV(drv, i, drv->clk[i].invert); + uint8_t pll; + uint8_t clkout_ctrl; + +#ifdef RAD1O + (void) source; + /* PLLA on XTAL */ + pll = SI5351C_CLK_PLL_SRC_A; +#endif + +#if (defined JAWBREAKER || defined HACKRF_ONE || defined PRALINE) + if (source == PLL_SOURCE_CLKIN) { + /* PLLB on CLKIN */ + pll = SI5351C_CLK_PLL_SRC_B; + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + /* + * HackRF One r9 always uses PLL A on the XTAL input + * but externally switches that input to CLKIN. + */ + pll = SI5351C_CLK_PLL_SRC_A; + gpio_set(&gpio_h1r9_clkin_en); + } + } else { + /* PLLA on XTAL */ + pll = SI5351C_CLK_PLL_SRC_A; + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + gpio_clear(&gpio_h1r9_clkin_en); + } + } +#endif + if (clkout_enabled) { + clkout_ctrl = SI5351C_CLK_INT_MODE | SI5351C_CLK_PLL_SRC(pll) | + SI5351C_CLK_SRC(SI5351C_CLK_SRC_MULTISYNTH_SELF) | + SI5351C_CLK_IDRV(SI5351C_CLK_IDRV_8MA); + } else { + clkout_ctrl = SI5351C_CLK_POWERDOWN | SI5351C_CLK_INT_MODE; } - si5351c_regs_commit(drv); + /* Clock to CPU is deactivated as it is not used and creates noise */ + /* External clock output is kept in current state */ + uint8_t data[] = { + 16, + SI5351C_CLK_FRAC_MODE | SI5351C_CLK_PLL_SRC(pll) | + SI5351C_CLK_SRC(SI5351C_CLK_SRC_MULTISYNTH_SELF) | + SI5351C_CLK_IDRV(SI5351C_CLK_IDRV_8MA), + SI5351C_CLK_INT_MODE | SI5351C_CLK_PLL_SRC(pll) | + SI5351C_CLK_SRC(SI5351C_CLK_SRC_MULTISYNTH_0_4) | + SI5351C_CLK_IDRV(SI5351C_CLK_IDRV_2MA) | SI5351C_CLK_INV, + SI5351C_CLK_INT_MODE | SI5351C_CLK_PLL_SRC(pll) | + SI5351C_CLK_SRC(SI5351C_CLK_SRC_MULTISYNTH_0_4) | + SI5351C_CLK_IDRV(SI5351C_CLK_IDRV_2MA), + clkout_ctrl, + SI5351C_CLK_INT_MODE | SI5351C_CLK_PLL_SRC(pll) | + SI5351C_CLK_SRC(SI5351C_CLK_SRC_MULTISYNTH_SELF) | + SI5351C_CLK_IDRV(SI5351C_CLK_IDRV_6MA) | SI5351C_CLK_INV, + SI5351C_CLK_INT_MODE | SI5351C_CLK_PLL_SRC(pll) | + SI5351C_CLK_SRC(SI5351C_CLK_SRC_MULTISYNTH_SELF) | + SI5351C_CLK_IDRV(SI5351C_CLK_IDRV_4MA), + SI5351C_CLK_POWERDOWN | + SI5351C_CLK_INT_MODE, /* not connected, but: PLL A int mode */ + SI5351C_CLK_POWERDOWN | + SI5351C_CLK_INT_MODE /* not connected, but: PLL B int mode */ + }; + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + data[1] = SI5351C_CLK_INT_MODE | SI5351C_CLK_PLL_SRC_A | + SI5351C_CLK_SRC(SI5351C_CLK_SRC_MULTISYNTH_SELF) | + SI5351C_CLK_IDRV(SI5351C_CLK_IDRV_6MA); + data[2] = SI5351C_CLK_FRAC_MODE | SI5351C_CLK_PLL_SRC_A | + SI5351C_CLK_SRC(SI5351C_CLK_SRC_MULTISYNTH_SELF) | + SI5351C_CLK_IDRV(SI5351C_CLK_IDRV_4MA); + data[3] = clkout_ctrl; + data[4] = SI5351C_CLK_POWERDOWN; + data[5] = SI5351C_CLK_POWERDOWN; + data[6] = SI5351C_CLK_POWERDOWN; + } +#ifdef PRALINE + data[1] = SI5351C_CLK_FRAC_MODE | SI5351C_CLK_PLL_SRC(pll) | + SI5351C_CLK_SRC(SI5351C_CLK_SRC_MULTISYNTH_SELF) | + SI5351C_CLK_IDRV(SI5351C_CLK_IDRV_4MA); + data[3] = clkout_ctrl; + data[5] = SI5351C_CLK_INT_MODE | SI5351C_CLK_PLL_SRC(pll) | + SI5351C_CLK_SRC(SI5351C_CLK_SRC_MULTISYNTH_SELF) | + SI5351C_CLK_IDRV(SI5351C_CLK_IDRV_4MA) | SI5351C_CLK_INV; +#endif + si5351c_write(drv, data, sizeof(data)); } +#define SI5351C_CLK_ENABLE(x) (0 << x) +#define SI5351C_CLK_DISABLE(x) (1 << x) +#define SI5351C_REG_OUTPUT_EN (3) + void si5351c_enable_clock_outputs(si5351c_driver_t* const drv) { - for (int i = 0; i < 8; i++) { - set_CLK_OEB( - drv, - i, - drv->clk[i].output_enable ? SI5351C_OUTPUT_ENABLE : - SI5351C_OUTPUT_DISABLE); + /* Enable CLK outputs 0, 1, 2, 4, 5 only. */ + /* Praline: enable 0, 4, 5 only. */ + /* 7: Clock to CPU is deactivated as it is not used and creates noise */ + /* 3: External clock output is deactivated by default */ + +#ifndef PRALINE + uint8_t value = SI5351C_CLK_ENABLE(0) | SI5351C_CLK_ENABLE(1) | + SI5351C_CLK_ENABLE(2) | SI5351C_CLK_ENABLE(4) | SI5351C_CLK_ENABLE(5) | + SI5351C_CLK_DISABLE(6) | SI5351C_CLK_DISABLE(7); +#else + uint8_t value = SI5351C_CLK_ENABLE(0) | SI5351C_CLK_ENABLE(1) | + SI5351C_CLK_DISABLE(2) | SI5351C_CLK_ENABLE(4) | SI5351C_CLK_ENABLE(5) | + SI5351C_CLK_DISABLE(6) | SI5351C_CLK_DISABLE(7); +#endif + uint8_t clkout = 3; + + /* HackRF One r9 has only three clock generator outputs. */ + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + clkout = 2; + value = SI5351C_CLK_ENABLE(0) | SI5351C_CLK_ENABLE(1) | + SI5351C_CLK_DISABLE(3) | SI5351C_CLK_DISABLE(4) | + SI5351C_CLK_DISABLE(5) | SI5351C_CLK_DISABLE(6) | + SI5351C_CLK_DISABLE(7); + } + + value |= (clkout_enabled) ? SI5351C_CLK_ENABLE(clkout) : + SI5351C_CLK_DISABLE(clkout); + uint8_t data[] = {SI5351C_REG_OUTPUT_EN, value}; + si5351c_write(drv, data, sizeof(data)); + + if ((clkout_enabled) && (detected_platform() == BOARD_ID_HACKRF1_R9)) { + gpio_set(&gpio_h1r9_clkout_en); + } else { + gpio_clear(&gpio_h1r9_clkout_en); } - si5351c_regs_commit(drv); } void si5351c_set_int_mode( @@ -281,39 +325,39 @@ void si5351c_set_int_mode( const uint_fast8_t ms_number, const uint_fast8_t on) { - set_MS_INT(drv, ms_number, on); - si5351c_regs_commit(drv); + uint8_t data[] = {16, 0}; + + if (ms_number < 8) { + data[0] = 16 + ms_number; + data[1] = si5351c_read_single(drv, data[0]); + + if (on) { + data[1] |= SI5351C_CLK_INT_MODE; + } else { + data[1] &= ~(SI5351C_CLK_INT_MODE); + } + + si5351c_write(drv, data, 2); + } } -void si5351c_change_input(si5351c_driver_t* const drv, si5351c_input_t input) +void si5351c_set_clock_source(si5351c_driver_t* const drv, const enum pll_sources source) { - if (drv->input_initialized && input == drv->active_input) { + if (source == active_clock_source) { return; } - si5351c_disable_all_outputs(drv); -#ifdef IS_H1_R9 - if (IS_H1_R9) { - /* - * HackRF One r9 always uses PLL A on the XTAL input - * but externally switches that input to CLKIN. - */ - si5351c_configure_inputs(drv, SI5351C_INPUT_XTAL); - if (input == SI5351C_INPUT_CLKIN) { - gpio_set(platform_gpio()->h1r9_clkin_en); - } else { - gpio_clear(platform_gpio()->h1r9_clkin_en); + si5351c_configure_clock_control(drv, source); + active_clock_source = source; + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + /* 25MHz XTAL * (0x0e00+512)/128 = 800mhz -> int mode */ + uint8_t pll_data[] = {26, 0x00, 0x01, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00}; + if (source == PLL_SOURCE_CLKIN) { + /* 10MHz CLKIN * (0x2600+512)/128 = 800mhz */ + pll_data[4] = 0x26; } + si5351c_write(drv, pll_data, sizeof(pll_data)); + si5351c_reset_pll(drv); } -#endif -#ifdef IS_NOT_H1_R9 - if (IS_NOT_H1_R9) { - si5351c_configure_inputs(drv, input); - } -#endif - si5351c_configure_pll_multisynth(drv, input); - drv->active_input = input; - drv->input_initialized = true; - si5351c_reset_plls(drv, SI5351C_PLL_MASK_BOTH); } bool si5351c_clkin_signal_valid(si5351c_driver_t* const drv) @@ -322,93 +366,31 @@ bool si5351c_clkin_signal_valid(si5351c_driver_t* const drv) uint32_t f = clkin_frequency(); return (f > 9000000) && (f < 11000000); } else { - si5351c_read_single(drv, LOS_CLKIN); - bool los_clkin = get_LOS_CLKIN(drv); - return !los_clkin; + return (si5351c_read_single(drv, 0) & SI5351C_LOS) == 0; } } -static void si5351c_clkout_ms_enable(si5351c_driver_t* const drv, bool enable) +void si5351c_clkout_enable(si5351c_driver_t* const drv, uint8_t enable) { - drv->clk[drv->clkout_id].output_enable = enable; - drv->clk[drv->clkout_id].power_down = !enable; + clkout_enabled = (enable > 0); + uint8_t clkout = 3; + + /* HackRF One r9 has only three clock generator outputs. */ + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + clkout = 2; + } /* Configure clock to 10MHz */ - si5351c_configure_multisynth(drv, drv->clkout_id, 80 * 128 - 512, 0, 1, 0); + si5351c_configure_multisynth(drv, clkout, 80 * 128 - 512, 0, 1, 0); - si5351c_configure_clock_control(drv); + si5351c_configure_clock_control(drv, active_clock_source); si5351c_enable_clock_outputs(drv); } -void si5351c_clkout_enable(si5351c_driver_t* const drv, bool enable) -{ -#ifdef IS_H1_R9 - if (IS_H1_R9) { - const platform_gpio_t* gpio = platform_gpio(); - - /* CLKOUT is shared with MCU_CLK, enable MS when either on. */ - bool mcu_clkin_enabled = gpio_read(gpio->h1r9_mcu_clk_en); - bool ms_needed = enable | mcu_clkin_enabled; - si5351c_clkout_ms_enable(drv, ms_needed); - - /* Set GPIO to gate CLKOUT output downstream of MS. */ - gpio_write(gpio->h1r9_clkout_en, enable); - } -#endif -#ifdef IS_NOT_H1_R9 - if (IS_NOT_H1_R9) { - /* We have a dedicated CLKOUT multisynth. */ - si5351c_clkout_ms_enable(drv, enable); - } -#endif -} - -void si5351c_mcu_clkin_enable(si5351c_driver_t* const drv, bool enable) -{ -#ifdef IS_H1_R9 - if (IS_H1_R9) { - const platform_gpio_t* gpio = platform_gpio(); - - /* MCU_CLK is shared with CLKOUT, enable MS when either on. */ - bool clkout_enabled = gpio_read(gpio->h1r9_clkout_en); - bool ms_needed = enable | clkout_enabled; - si5351c_clkout_ms_enable(drv, ms_needed); - - /* Set GPIO to gate MCU_CLK output downstream of MS. */ - gpio_write(gpio->h1r9_mcu_clk_en, enable); - } -#endif -#ifdef IS_NOT_H1_R9 - if (IS_NOT_H1_R9) { - drv->clk[drv->mcu_clkin_id].output_enable = enable; - drv->clk[drv->mcu_clkin_id].power_down = !enable; - - /* Configure clock to 40MHz */ - if (drv->mcu_clkin_id >= 6) { - // MCU_CLKIN on CLK6 or CLK7, integer only MS. - si5351c_configure_multisynth(drv, drv->mcu_clkin_id, 20, 0, 0, 0); - } else { - // MCU_CLKIN on CLK0 to CLK5, fractional-capable MS. - si5351c_configure_multisynth( - drv, - drv->mcu_clkin_id, - 20 * 128 - 512, - 0, - 1, - 0); - } - - si5351c_configure_clock_control(drv); - si5351c_enable_clock_outputs(drv); - } -#endif -} - void si5351c_init(si5351c_driver_t* const drv) { /* Read revision ID */ - si5351c_read_single(drv, REVID); - selftest.si5351_rev_id = get_REVID(drv); + selftest.si5351_rev_id = si5351c_read_single(drv, 0) & SI5351C_REVID; /* Read back interrupt status mask register, flip the mask bits and verify. */ uint8_t int_mask = si5351c_read_single(drv, 2); @@ -427,221 +409,21 @@ void si5351c_init(si5351c_driver_t* const drv) selftest.report.pass = false; } - /* Wait for on-chip initialization to complete. */ - while (get_SYS_INIT(drv)) { - si5351c_read_single(drv, SYS_INIT); - } - - /* Cache all current register values. */ - uint8_t data_tx[] = {0}; - i2c_bus_transfer( - drv->bus, - drv->i2c_address, - data_tx, - 1, - drv->regs, - sizeof(drv->regs)); - memset(drv->regs_dirty, 0, sizeof(drv->regs_dirty)); - -#ifdef IS_H1_R9 - if (IS_H1_R9) { - const platform_gpio_t* gpio = platform_gpio(); - const platform_scu_t* scu = platform_scu(); - + if (detected_platform() == BOARD_ID_HACKRF1_R9) { /* CLKIN_EN */ - scu_pinmux(scu->H1R9_CLKIN_EN, SCU_GPIO_FAST | SCU_CONF_FUNCTION4); - gpio_clear(gpio->h1r9_clkin_en); - gpio_output(gpio->h1r9_clkin_en); + scu_pinmux(SCU_H1R9_CLKIN_EN, SCU_GPIO_FAST | SCU_CONF_FUNCTION4); + gpio_clear(&gpio_h1r9_clkin_en); + gpio_output(&gpio_h1r9_clkin_en); /* CLKOUT_EN */ - scu_pinmux(scu->H1R9_CLKOUT_EN, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); - gpio_clear(gpio->h1r9_clkout_en); - gpio_output(gpio->h1r9_clkout_en); + scu_pinmux(SCU_H1R9_CLKOUT_EN, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + gpio_clear(&gpio_h1r9_clkout_en); + gpio_output(&gpio_h1r9_clkout_en); /* MCU_CLK_EN */ - scu_pinmux(scu->H1R9_MCU_CLK_EN, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); - gpio_clear(gpio->h1r9_mcu_clk_en); - gpio_output(gpio->h1r9_mcu_clk_en); + scu_pinmux(SCU_H1R9_MCU_CLK_EN, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + gpio_clear(&gpio_h1r9_mcu_clk_en); + gpio_output(&gpio_h1r9_mcu_clk_en); } -#endif - - si5351c_clk_t clkout = { - .output_enable = false, - .power_down = true, - .mode = SI5351C_MODE_INT, - .pll = SI5351C_PLL_A, - .source = SI5351C_SRC_MULTISYNTH_SELF, - .drive = SI5351C_DRIVE_8MA, - }; - - si5351c_clk_t mcu_clkin = { - .output_enable = false, - .power_down = true, - .mode = SI5351C_MODE_INT, - .pll = SI5351C_PLL_A, - .source = SI5351C_SRC_MULTISYNTH_SELF, - .drive = SI5351C_DRIVE_2MA, - }; - - si5351c_clk_t powered_down = { - .output_enable = false, - .power_down = true, - .mode = SI5351C_MODE_INT, - }; - - /* CLK0: MAX5864/CPLD */ - drv->clk[0] = (si5351c_clk_t){ - .output_enable = true, - .mode = SI5351C_MODE_FRAC, - .pll = SI5351C_PLL_A, - .source = SI5351C_SRC_MULTISYNTH_SELF, - .drive = SI5351C_DRIVE_8MA, - }; - /* CLK1: CPLD */ - drv->clk[1] = (si5351c_clk_t){ - .output_enable = true, - .mode = SI5351C_MODE_INT, - .pll = SI5351C_PLL_A, - .source = SI5351C_SRC_MULTISYNTH_0_4, - .drive = SI5351C_DRIVE_2MA, - .invert = true, - }; - /* CLK2: SGPIO */ - drv->clk[2] = (si5351c_clk_t){ - .output_enable = true, - .mode = SI5351C_MODE_INT, - .pll = SI5351C_PLL_A, - .source = SI5351C_SRC_MULTISYNTH_0_4, - .drive = SI5351C_DRIVE_2MA, - }; - /* CLK3: CLKOUT */ - drv->clk[3] = clkout; - drv->clkout_id = 3; - /* CLK4: RFFC5072 (MAX2837 on rad1o) */ - drv->clk[4] = (si5351c_clk_t){ - .output_enable = true, - .mode = SI5351C_MODE_INT, - .pll = SI5351C_PLL_A, - .source = SI5351C_SRC_MULTISYNTH_SELF, - .drive = SI5351C_DRIVE_6MA, - .invert = true, - }; - /* CLK5: MAX2837 (MAX2871 on rad1o) */ - drv->clk[5] = (si5351c_clk_t){ - .output_enable = true, - .mode = SI5351C_MODE_INT, - .pll = SI5351C_PLL_A, - .source = SI5351C_SRC_MULTISYNTH_SELF, - .drive = SI5351C_DRIVE_4MA, - }; - /* CLK6: none */ - drv->clk[6] = powered_down; - /* CLK7: LPC43xx */ - drv->clk[7] = mcu_clkin; - drv->mcu_clkin_id = 7; - -#ifdef IS_H1_R9 - if (IS_H1_R9) { - /* CLK0: MAX5864/CPLD/SGPIO (sample clocks) */ - drv->clk[0] = (si5351c_clk_t){ - .output_enable = true, - .mode = SI5351C_MODE_INT, - .pll = SI5351C_PLL_A, - .source = SI5351C_SRC_MULTISYNTH_SELF, - .drive = SI5351C_DRIVE_6MA, - }; - /* CLK1: RFFC5072/MAX2839 */ - drv->clk[1] = (si5351c_clk_t){ - .output_enable = true, - .mode = SI5351C_MODE_FRAC, - .pll = SI5351C_PLL_A, - .source = SI5351C_SRC_MULTISYNTH_SELF, - .drive = SI5351C_DRIVE_4MA, - }; - /* CLK2: CLKOUT/LPC4320 */ - drv->clk[2] = clkout; - drv->clkout_id = 2; - drv->mcu_clkin_id = 2; - /* Other outputs not present on Si5351A */ - drv->clk[3] = powered_down; - drv->clk[4] = powered_down; - drv->clk[5] = powered_down; - drv->clk[6] = powered_down; - drv->clk[7] = powered_down; - } -#endif -#ifdef IS_PRALINE - if (IS_PRALINE) { - /* CLK0: AFE_CLK */ - drv->clk[0] = (si5351c_clk_t){ - .output_enable = true, - .mode = SI5351C_MODE_FRAC, - .pll = SI5351C_PLL_A, - .source = SI5351C_SRC_MULTISYNTH_SELF, - .drive = SI5351C_DRIVE_4MA, - }; - /* CLK1: SCT_CLK and FPGA_CLK */ - drv->clk[1] = (si5351c_clk_t){ - .output_enable = true, - .mode = SI5351C_MODE_FRAC, - .pll = SI5351C_PLL_A, - .source = SI5351C_SRC_MULTISYNTH_SELF, - .drive = SI5351C_DRIVE_2MA, - }; - /* CLK3: CLKOUT */ - clkout.pll = SI5351C_PLL_B; - drv->clk[3] = clkout; - drv->clkout_id = 3; - /* CLK4: XCVR_CLK */ - drv->clk[4] = (si5351c_clk_t){ - .output_enable = true, - .mode = SI5351C_MODE_INT, - .pll = SI5351C_PLL_B, - .source = SI5351C_SRC_MULTISYNTH_SELF, - .drive = SI5351C_DRIVE_4MA, - .invert = true, - }; - /* CLK5: MIX_CLK */ - drv->clk[5] = (si5351c_clk_t){ - .output_enable = true, - .mode = SI5351C_MODE_INT, - .pll = SI5351C_PLL_B, - .source = SI5351C_SRC_MULTISYNTH_SELF, - .drive = SI5351C_DRIVE_4MA, - }; - if ((detected_revision() & ~BOARD_REV_GSG) < BOARD_REV_PRALINE_R1_1) { - /* CLK2: FPGA_CLK (not shared with SCT_CLK on older boards) */ - drv->clk[2] = (si5351c_clk_t){ - .output_enable = true, - .mode = SI5351C_MODE_FRAC, - .pll = SI5351C_PLL_A, - .source = SI5351C_SRC_MULTISYNTH_SELF, - .drive = SI5351C_DRIVE_2MA, - }; - } else { - /* CLK2: MCU_CLK */ - drv->clk[2] = mcu_clkin; - drv->mcu_clkin_id = 2; - } - - // Use PLL B for MCU, since we reset PLL A during sample_rate_set. - drv->clk[drv->mcu_clkin_id].pll = SI5351C_PLL_B; - } -#endif -} - -/* - * Set initial phase offset of output multisynth. AN619 associates this setting - * with outputs, but it seems to really be a multisynth setting. - * - * After changing this setting, you must call si5351c_reset_pll() to - * synchronize outputs with the new phase offset. - */ -void si5351c_set_phase( - si5351c_driver_t* const drv, - const uint8_t ms_number, - const uint8_t offset) -{ - set_CLK_PHOFF(drv, ms_number, offset); - si5351c_regs_commit(drv); + (void) drv; } diff --git a/firmware/common/si5351c.h b/firmware/common/si5351c.h index fd2d1aed..4c91bfba 100644 --- a/firmware/common/si5351c.h +++ b/firmware/common/si5351c.h @@ -1,5 +1,5 @@ /* - * Copyright 2012-2026 Great Scott Gadgets + * Copyright 2012-2022 Great Scott Gadgets * Copyright 2012 Jared Boone * * This file is part of HackRF. @@ -20,94 +20,54 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __SI5351C_H +#define __SI5351C_H #ifdef __cplusplus extern "C" { #endif -#include #include +#include #include "i2c_bus.h" #define SI_INTDIV(x) (x * 128 - 512) -#define SI5351C_CACHED_REGS 188 +#define SI5351C_CLK_POWERDOWN (1 << 7) +#define SI5351C_CLK_INT_MODE (1 << 6) +#define SI5351C_CLK_FRAC_MODE (0 << 6) -typedef enum { - SI5351C_MODE_FRAC = 0, - SI5351C_MODE_INT = 1, -} si5351c_mode_t; +#define SI5351C_CLK_PLL_SRC(x) (x << 5) +#define SI5351C_CLK_PLL_SRC_A 0 +#define SI5351C_CLK_PLL_SRC_B 1 -typedef enum { - SI5351C_SRC_XTAL = 0, - SI5351C_SRC_CLKIN = 1, - SI5351C_SRC_MULTISYNTH_0_4 = 2, - SI5351C_SRC_MULTISYNTH_SELF = 3, -} si5351c_src_t; +#define SI5351C_CLK_INV (1 << 4) -typedef enum { - SI5351C_DRIVE_2MA = 0, - SI5351C_DRIVE_4MA = 1, - SI5351C_DRIVE_6MA = 2, - SI5351C_DRIVE_8MA = 3, -} si5351c_drive_t; +#define SI5351C_CLK_SRC(x) (x << 2) +#define SI5351C_CLK_SRC_XTAL 0 +#define SI5351C_CLK_SRC_CLKIN 1 +#define SI5351C_CLK_SRC_MULTISYNTH_0_4 2 +#define SI5351C_CLK_SRC_MULTISYNTH_SELF 3 -typedef enum { - SI5351C_PLL_A = 0, - SI5351C_PLL_B = 1, -} si5351c_pll_t; +#define SI5351C_CLK_IDRV(x) (x << 0) +#define SI5351C_CLK_IDRV_2MA 0 +#define SI5351C_CLK_IDRV_4MA 1 +#define SI5351C_CLK_IDRV_6MA 2 +#define SI5351C_CLK_IDRV_8MA 3 -typedef enum { - SI5351C_PLL_MASK_A = 1, - SI5351C_PLL_MASK_B = 2, - SI5351C_PLL_MASK_BOTH = 3, -} si5351c_pll_mask_t; +#define SI5351C_LOS (1 << 4) +#define SI5351C_REVID 0x03 -typedef enum { - SI5351C_XTAL_6PF = 1, - SI5351C_XTAL_8PF = 2, - SI5351C_XTAL_10PF = 3, -} si5351c_xtal_t; - -typedef enum { - SI5351C_OUTPUT_ENABLE = 0, - SI5351C_OUTPUT_DISABLE = 1, -} si5351c_output_t; - -typedef enum { - SI5351C_DIV_1 = 0, - SI5351C_DIV_2 = 1, - SI5351C_DIV_4 = 2, - SI5351C_DIV_8 = 3, -} si5351c_div_t; - -typedef enum { - SI5351C_INPUT_XTAL = 0, - SI5351C_INPUT_CLKIN = 1, -} si5351c_input_t; - -typedef struct { - bool output_enable; - bool power_down; - si5351c_mode_t mode; - si5351c_pll_t pll; - si5351c_src_t source; - si5351c_drive_t drive; - bool invert; -} si5351c_clk_t; +enum pll_sources { + PLL_SOURCE_UNINITIALIZED = -1, + PLL_SOURCE_XTAL = 0, + PLL_SOURCE_CLKIN = 1, +}; typedef struct { i2c_bus_t* const bus; uint8_t i2c_address; - si5351c_clk_t clk[8]; - uint8_t clkout_id; - uint8_t mcu_clkin_id; - bool input_initialized; - si5351c_input_t active_input; - uint8_t regs[SI5351C_CACHED_REGS]; - uint32_t regs_dirty[(SI5351C_CACHED_REGS + 31) / 32]; } si5351c_driver_t; void si5351c_disable_all_outputs(si5351c_driver_t* const drv); @@ -115,11 +75,9 @@ void si5351c_disable_oeb_pin_control(si5351c_driver_t* const drv); void si5351c_power_down_all_clocks(si5351c_driver_t* const drv); void si5351c_set_crystal_configuration(si5351c_driver_t* const drv); void si5351c_enable_xo_and_ms_fanout(si5351c_driver_t* const drv); -void si5351c_configure_inputs(si5351c_driver_t* const drv, const si5351c_input_t input); -void si5351c_configure_pll_multisynth( - si5351c_driver_t* const drv, - const si5351c_input_t input); -void si5351c_reset_plls(si5351c_driver_t* const drv, si5351c_pll_mask_t mask); +void si5351c_configure_pll_sources(si5351c_driver_t* const drv); +void si5351c_configure_pll_multisynth(si5351c_driver_t* const drv); +void si5351c_reset_pll(si5351c_driver_t* const drv); void si5351c_configure_multisynth( si5351c_driver_t* const drv, const uint_fast8_t ms_number, @@ -127,28 +85,28 @@ void si5351c_configure_multisynth( const uint32_t p2, const uint32_t p3, const uint_fast8_t r_div); -void si5351c_configure_clock_control(si5351c_driver_t* const drv); +void si5351c_configure_clock_control( + si5351c_driver_t* const drv, + const enum pll_sources source); void si5351c_enable_clock_outputs(si5351c_driver_t* const drv); void si5351c_set_int_mode( si5351c_driver_t* const drv, const uint_fast8_t ms_number, const uint_fast8_t on); -void si5351c_change_input(si5351c_driver_t* const drv, const si5351c_input_t input); +void si5351c_set_clock_source(si5351c_driver_t* const drv, const enum pll_sources source); bool si5351c_clkin_signal_valid(si5351c_driver_t* const drv); void si5351c_write_single(si5351c_driver_t* const drv, uint8_t reg, uint8_t val); uint8_t si5351c_read_single(si5351c_driver_t* const drv, uint8_t reg); -void si5351c_clkout_enable(si5351c_driver_t* const drv, bool enable); -void si5351c_mcu_clkin_enable(si5351c_driver_t* const drv, bool enable); -void si5351c_init(si5351c_driver_t* const drv); -void si5351c_set_phase( +void si5351c_write( si5351c_driver_t* const drv, - const uint8_t ms_number, - const uint8_t offset); - -/* Driver Instance. */ -extern si5351c_driver_t si5351c; + const uint8_t* const data, + const size_t data_count); +void si5351c_clkout_enable(si5351c_driver_t* const drv, uint8_t enable); +void si5351c_init(si5351c_driver_t* const drv); #ifdef __cplusplus } #endif + +#endif /* __SI5351C_H */ diff --git a/firmware/common/si5351c_regs.def b/firmware/common/si5351c_regs.def deleted file mode 100644 index 5c3a6774..00000000 --- a/firmware/common/si5351c_regs.def +++ /dev/null @@ -1,494 +0,0 @@ -/* - * Copyright 2026 Great Scott Gadgets - * - * This file is part of HackRF. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -static inline void si5351c_reg_set_clean(si5351c_driver_t* drv, int reg) -{ - drv->regs_dirty[reg / 32] &= ~(1 << (reg % 32)); -} - -static inline void si5351c_reg_set_dirty(si5351c_driver_t* drv, int reg) -{ - drv->regs_dirty[reg / 32] |= (1 << (reg % 32)); -} - -static inline bool si5351c_reg_is_dirty(si5351c_driver_t* drv, int reg) -{ - return (drv->regs_dirty[reg / 32] & (1 << (reg % 32))) ? true : false; -} - -/* Generate static inline accessors that operate on the global - * regs. Done this way to (1) allow defs to be scraped out and used - * elsewhere, e.g. in scripts, (2) to avoid dealing with endian - * (structs). This may be used in firmware, or on host predefined - * register loads. */ - -/* On set_, register is always set dirty, even if nothing - * changed. This makes sure that writes that have side effects, - * e.g. frequency setting, are not skipped. */ - -/* n=name, r=regnum, o=offset (bits from LSB) of LSB of field, - * l=length (bits) */ -#define __MREG__(n,r,o,l) \ -static inline uint8_t get_##n(si5351c_driver_t* const _d) { \ - return (_d->regs[r] >> o) & ((1L<regs[r] &= (uint8_t)(~(((1L<regs[r] |= (uint8_t)(((v&((1L<> 8); \ - set_##n##_BOT(_d, v); \ -} - -#define __3PART__(n) \ -static inline uint32_t get_##n(si5351c_driver_t* const _d) { \ - return (get_##n##_TOP(_d) << 16) | (get_##n##_MID(_d) << 8) | get_##n##_BOT(_d); \ -} \ -static inline void set_##n(si5351c_driver_t* const _d, uint32_t v) { \ - set_##n##_TOP(_d, v >> 16); \ - set_##n##_MID(_d, v >> 8); \ - set_##n##_BOT(_d, v); \ -} - -/* Generate accessors for per-PLL and per-multisynth registers */ -/* n=name, p=prefix, s=suffix */ - -#define __PER_PLL__(n, p, s) \ -static inline uint32_t get_##n(si5351c_driver_t* const _d, si5351c_pll_t pll) { \ - return (pll == SI5351C_PLL_A) ? get_##p##A##s(_d) : get_##p##B##s(_d); \ -} \ -static inline void set_##n(si5351c_driver_t* const _d, si5351c_pll_t pll, uint32_t v) { \ - if (pll == SI5351C_PLL_A) { \ - set_##p##A##s(_d, v); \ - } else { \ - set_##p##B##s(_d, v); \ - } \ -} - -#define __PER_MS__(n, p, s) \ -static inline uint32_t get_##n(si5351c_driver_t* const _d, uint8_t i) { \ - switch (i) { \ - case 0: return get_##p##0##s(_d); \ - case 1: return get_##p##1##s(_d); \ - case 2: return get_##p##2##s(_d); \ - case 3: return get_##p##3##s(_d); \ - case 4: return get_##p##4##s(_d); \ - case 5: return get_##p##5##s(_d); \ - case 6: return get_##p##6##s(_d); \ - case 7: return get_##p##7##s(_d); \ - default: return 0; \ - } \ -} \ -static inline void set_##n(si5351c_driver_t* const _d, uint8_t i, uint32_t v) { \ - switch (i) { \ - case 0: set_##p##0##s(_d, v); return; \ - case 1: set_##p##1##s(_d, v); return; \ - case 2: set_##p##2##s(_d, v); return; \ - case 3: set_##p##3##s(_d, v); return; \ - case 4: set_##p##4##s(_d, v); return; \ - case 5: set_##p##5##s(_d, v); return; \ - case 6: set_##p##6##s(_d, v); return; \ - case 7: set_##p##7##s(_d, v); return; \ - } \ -} \ -static inline void set_all_##n(si5351c_driver_t* const _d, uint32_t v) { \ - set_##p##0##s(_d, v); \ - set_##p##1##s(_d, v); \ - set_##p##2##s(_d, v); \ - set_##p##3##s(_d, v); \ - set_##p##4##s(_d, v); \ - set_##p##5##s(_d, v); \ - set_##p##6##s(_d, v); \ - set_##p##7##s(_d, v); \ -} - -#define __PER_FRAC_MS__(n, p, s) \ -static inline void set_##n(si5351c_driver_t* const _d, uint8_t i, uint32_t v) { \ - switch (i) { \ - case 0: set_##p##0##s(_d, v); return; \ - case 1: set_##p##1##s(_d, v); return; \ - case 2: set_##p##2##s(_d, v); return; \ - case 3: set_##p##3##s(_d, v); return; \ - case 4: set_##p##4##s(_d, v); return; \ - case 5: set_##p##5##s(_d, v); return; \ - } \ -} - -/* Register 0: Device Status */ -__MREG__(SYS_INIT, 0, 7, 1) -__MREG__(LOL_B, 0, 6, 1) -__MREG__(LOL_A, 0, 5, 1) -__MREG__(LOS_CLKIN, 0, 4, 1) -__MREG__(LOS_XTAL, 0, 3, 1) -__MREG__(REVID, 0, 0, 2) - -/* Register 1: Interrupt Status Sticky */ -__MREG__(SYS_INIT_STKY, 1, 7, 1) -__MREG__(LOL_B_STKY, 1, 6, 1) -__MREG__(LOL_A_STKY, 1, 5, 1) -__MREG__(LOS_CLKIN_STKY, 1, 4, 1) -__MREG__(LOS_XTAL_STKY, 1, 3, 1) - -/* Register 2: Interrupt Status Mask */ -__MREG__(SYS_INIT_MASK, 2, 7, 1) -__MREG__(LOL_B_MASK, 2, 6, 1) -__MREG__(LOL_A_MASK, 2, 5, 1) -__MREG__(LOS_CLKIN_MASK, 2, 4, 1) -__MREG__(LOS_XTAL_MASK, 2, 3, 1) - -/* Register 3: Output Enable Control */ -__MREG__(CLK7_OEB, 3, 7, 1) -__MREG__(CLK6_OEB, 3, 6, 1) -__MREG__(CLK5_OEB, 3, 5, 1) -__MREG__(CLK4_OEB, 3, 4, 1) -__MREG__(CLK3_OEB, 3, 3, 1) -__MREG__(CLK2_OEB, 3, 2, 1) -__MREG__(CLK1_OEB, 3, 1, 1) -__MREG__(CLK0_OEB, 3, 0, 1) - -/* Register 4: OEB Pin Enable Control */ -__MREG__(OEB_CLK7, 4, 7, 1) -__MREG__(OEB_CLK6, 4, 6, 1) -__MREG__(OEB_CLK5, 4, 5, 1) -__MREG__(OEB_CLK4, 4, 4, 1) -__MREG__(OEB_CLK3, 4, 3, 1) -__MREG__(OEB_CLK2, 4, 2, 1) -__MREG__(OEB_CLK1, 4, 1, 1) -__MREG__(OEB_CLK0, 4, 0, 1) - -/* Register 9: OEB Pin Enable Control Mask */ -__MREG__(OEB_MASK7, 9, 7, 1) -__MREG__(OEB_MASK6, 9, 6, 1) -__MREG__(OEB_MASK5, 9, 5, 1) -__MREG__(OEB_MASK4, 9, 4, 1) -__MREG__(OEB_MASK3, 9, 3, 1) -__MREG__(OEB_MASK2, 9, 2, 1) -__MREG__(OEB_MASK1, 9, 1, 1) -__MREG__(OEB_MASK0, 9, 0, 1) - -/* Register 15: PLL Input Source */ -__MREG__(CLKIN_DIV, 15, 6, 2) -__MREG__(PLLB_SRC, 15, 3, 1) -__MREG__(PLLA_SRC, 15, 2, 1) - -/* Register 16: CLK0 Control */ -__MREG__(CLK0_PDN, 16, 7, 1) -__MREG__(MS0_INT, 16, 6, 1) -__MREG__(MS0_SRC, 16, 5, 1) -__MREG__(CLK0_INV, 16, 4, 1) -__MREG__(CLK0_SRC, 16, 2, 2) -__MREG__(CLK0_IDRV, 16, 0, 2) - -/* Register 17: CLK1 Control */ -__MREG__(CLK1_PDN, 17, 7, 1) -__MREG__(MS1_INT, 17, 6, 1) -__MREG__(MS1_SRC, 17, 5, 1) -__MREG__(CLK1_INV, 17, 4, 1) -__MREG__(CLK1_SRC, 17, 2, 2) -__MREG__(CLK1_IDRV, 17, 0, 2) - -/* Register 18: CLK2 Control */ -__MREG__(CLK2_PDN, 18, 7, 1) -__MREG__(MS2_INT, 18, 6, 1) -__MREG__(MS2_SRC, 18, 5, 1) -__MREG__(CLK2_INV, 18, 4, 1) -__MREG__(CLK2_SRC, 18, 2, 2) -__MREG__(CLK2_IDRV, 18, 0, 2) - -/* Register 19: CLK3 Control */ -__MREG__(CLK3_PDN, 19, 7, 1) -__MREG__(MS3_INT, 19, 6, 1) -__MREG__(MS3_SRC, 19, 5, 1) -__MREG__(CLK3_INV, 19, 4, 1) -__MREG__(CLK3_SRC, 19, 2, 2) -__MREG__(CLK3_IDRV, 19, 0, 2) - -/* Register 20: CLK4 Control */ -__MREG__(CLK4_PDN, 20, 7, 1) -__MREG__(MS4_INT, 20, 6, 1) -__MREG__(MS4_SRC, 20, 5, 1) -__MREG__(CLK4_INV, 20, 4, 1) -__MREG__(CLK4_SRC, 20, 2, 2) -__MREG__(CLK4_IDRV, 20, 0, 2) - -/* Register 21: CLK5 Control */ -__MREG__(CLK5_PDN, 21, 7, 1) -__MREG__(MS5_INT, 21, 6, 1) -__MREG__(MS5_SRC, 21, 5, 1) -__MREG__(CLK5_INV, 21, 4, 1) -__MREG__(CLK5_SRC, 21, 2, 2) -__MREG__(CLK5_IDRV, 21, 0, 2) - -/* Register 22: CLK6 Control */ -__MREG__(CLK6_PDN, 22, 7, 1) -__MREG__(FBA_INT, 22, 6, 1) -__MREG__(MS6_SRC, 22, 5, 1) -__MREG__(CLK6_INV, 22, 4, 1) -__MREG__(CLK6_SRC, 22, 2, 2) -__MREG__(CLK6_IDRV, 22, 0, 2) - -/* Register 23: CLK7 Control */ -__MREG__(CLK7_PDN, 23, 7, 1) -__MREG__(FBB_INT, 23, 6, 1) -__MREG__(MS7_SRC, 23, 5, 1) -__MREG__(CLK7_INV, 23, 4, 1) -__MREG__(CLK7_SRC, 23, 2, 2) -__MREG__(CLK7_IDRV, 23, 0, 2) - -/* Register 24: CLK0-CLK3 Disable State */ -__MREG__(CLK3_DIS_STATE, 24, 6, 2) -__MREG__(CLK2_DIS_STATE, 24, 4, 2) -__MREG__(CLK1_DIS_STATE, 24, 2, 2) -__MREG__(CLK0_DIS_STATE, 24, 0, 2) - -/* Register 25: CLK4-CLK7 Disable State */ -__MREG__(CLK7_DIS_STATE, 25, 6, 2) -__MREG__(CLK6_DIS_STATE, 25, 4, 2) -__MREG__(CLK5_DIS_STATE, 25, 2, 2) -__MREG__(CLK4_DIS_STATE, 25, 0, 2) - -/* Registers 26-33: Multisynth NA Parameters */ -__MREG__(MSNA_P3_MID, 26, 0, 8) -__MREG__(MSNA_P3_BOT, 27, 0, 8) -__MREG__(MSNA_P1_TOP, 28, 0, 2) -__MREG__(MSNA_P1_MID, 29, 0, 8) -__MREG__(MSNA_P1_BOT, 30, 0, 8) -__MREG__(MSNA_P3_TOP, 31, 4, 4) -__MREG__(MSNA_P2_TOP, 31, 0, 4) -__MREG__(MSNA_P2_MID, 32, 0, 8) -__MREG__(MSNA_P2_BOT, 33, 0, 8) - -/* Registers 34-41: Multisynth NB Parameters */ -__MREG__(MSNB_P3_MID, 34, 0, 8) -__MREG__(MSNB_P3_BOT, 35, 0, 8) -__MREG__(MSNB_P1_TOP, 36, 0, 2) -__MREG__(MSNB_P1_MID, 37, 0, 8) -__MREG__(MSNB_P1_BOT, 38, 0, 8) -__MREG__(MSNB_P3_TOP, 39, 4, 4) -__MREG__(MSNB_P2_TOP, 39, 0, 4) -__MREG__(MSNB_P2_MID, 40, 0, 8) -__MREG__(MSNB_P2_BOT, 41, 0, 8) - -/* Registers 42-49: Multisynth 0 Parameters */ -__MREG__(MS0_P3_MID, 42, 0, 8) -__MREG__(MS0_P3_BOT, 43, 0, 8) -__MREG__(R0_DIV, 44, 4, 3) -__MREG__(MS0_DIVBY4, 44, 2, 2) -__MREG__(MS0_P1_TOP, 44, 0, 2) -__MREG__(MS0_P1_MID, 45, 0, 8) -__MREG__(MS0_P1_BOT, 46, 0, 8) -__MREG__(MS0_P3_TOP, 47, 4, 4) -__MREG__(MS0_P2_TOP, 47, 0, 4) -__MREG__(MS0_P2_MID, 48, 0, 8) -__MREG__(MS0_P2_BOT, 49, 0, 8) - -/* Registers 50-57: Multisynth 1 Parameters */ -__MREG__(MS1_P3_MID, 50, 0, 8) -__MREG__(MS1_P3_BOT, 51, 0, 8) -__MREG__(R1_DIV, 52, 4, 3) -__MREG__(MS1_DIVBY4, 52, 2, 2) -__MREG__(MS1_P1_TOP, 52, 0, 2) -__MREG__(MS1_P1_MID, 53, 0, 8) -__MREG__(MS1_P1_BOT, 54, 0, 8) -__MREG__(MS1_P3_TOP, 55, 4, 4) -__MREG__(MS1_P2_TOP, 55, 0, 4) -__MREG__(MS1_P2_MID, 56, 0, 8) -__MREG__(MS1_P2_BOT, 57, 0, 8) - -/* Registers 58-65: Multisynth 2 Parameters */ -__MREG__(MS2_P3_MID, 58, 0, 8) -__MREG__(MS2_P3_BOT, 59, 0, 8) -__MREG__(R2_DIV, 60, 4, 3) -__MREG__(MS2_DIVBY4, 60, 2, 2) -__MREG__(MS2_P1_TOP, 60, 0, 2) -__MREG__(MS2_P1_MID, 61, 0, 8) -__MREG__(MS2_P1_BOT, 62, 0, 8) -__MREG__(MS2_P3_TOP, 63, 4, 4) -__MREG__(MS2_P2_TOP, 63, 0, 4) -__MREG__(MS2_P2_MID, 64, 0, 8) -__MREG__(MS2_P2_BOT, 65, 0, 8) - -/* Registers 66-73: Multisynth 3 Parameters */ -__MREG__(MS3_P3_MID, 66, 0, 8) -__MREG__(MS3_P3_BOT, 67, 0, 8) -__MREG__(R3_DIV, 68, 4, 3) -__MREG__(MS3_DIVBY4, 68, 2, 2) -__MREG__(MS3_P1_TOP, 68, 0, 2) -__MREG__(MS3_P1_MID, 69, 0, 8) -__MREG__(MS3_P1_BOT, 70, 0, 8) -__MREG__(MS3_P3_TOP, 71, 4, 4) -__MREG__(MS3_P2_TOP, 71, 0, 4) -__MREG__(MS3_P2_MID, 72, 0, 8) -__MREG__(MS3_P2_BOT, 73, 0, 8) - -/* Registers 74-81: Multisynth 4 Parameters */ -__MREG__(MS4_P3_MID, 74, 0, 8) -__MREG__(MS4_P3_BOT, 75, 0, 8) -__MREG__(R4_DIV, 76, 4, 3) -__MREG__(MS4_DIVBY4, 76, 2, 2) -__MREG__(MS4_P1_TOP, 76, 0, 2) -__MREG__(MS4_P1_MID, 77, 0, 8) -__MREG__(MS4_P1_BOT, 78, 0, 8) -__MREG__(MS4_P3_TOP, 79, 4, 4) -__MREG__(MS4_P2_TOP, 79, 0, 4) -__MREG__(MS4_P2_MID, 80, 0, 8) -__MREG__(MS4_P2_BOT, 81, 0, 8) - -/* Registers 82-89: Multisynth 5 Parameters */ -__MREG__(MS5_P3_MID, 82, 0, 8) -__MREG__(MS5_P3_BOT, 83, 0, 8) -__MREG__(R5_DIV, 84, 4, 3) -__MREG__(MS5_DIVBY4, 84, 2, 2) -__MREG__(MS5_P1_TOP, 84, 0, 2) -__MREG__(MS5_P1_MID, 85, 0, 8) -__MREG__(MS5_P1_BOT, 86, 0, 8) -__MREG__(MS5_P3_TOP, 87, 4, 4) -__MREG__(MS5_P2_TOP, 87, 0, 4) -__MREG__(MS5_P2_MID, 88, 0, 8) -__MREG__(MS5_P2_BOT, 89, 0, 8) - -/* Register 90: Multisynth 6 Parameters */ -__MREG__(MS6_P1, 90, 0, 8) - -/* Register 91: Multisynth 7 Parameters */ -__MREG__(MS7_P1, 91, 0, 8) - -/* Register 92: Clock 6 and 7 Output Divider */ -__MREG__(R7_DIV, 92, 4, 3) -__MREG__(R6_DIV, 92, 0, 3) - -/* Registers 149-161: Spread Spectrum Parameters */ -__MREG__(SSC_EN, 149, 7, 1) -__MREG__(SSDN_P2_TOP, 149, 0, 7) -__MREG__(SSDN_P2_BOT, 150, 0, 8) -__MREG__(SSC_MODE, 151, 7, 1) -__MREG__(SSDN_P3_TOP, 151, 0, 7) -__MREG__(SSDN_P3_BOT, 152, 0, 8) -__MREG__(SSDN_P1_BOT, 153, 0, 8) -__MREG__(SSUDP_TOP, 154, 4, 4) -__MREG__(SSDN_P1_TOP, 154, 0, 4) -__MREG__(SSUDP_BOT, 155, 0, 8) -__MREG__(SSUP_P2_TOP, 156, 0, 7) -__MREG__(SSUP_P2_BOT, 157, 0, 8) -__MREG__(SSUP_P3_TOP, 158, 0, 8) -__MREG__(SSUP_P3_BOT, 159, 0, 8) -__MREG__(SSUP_P1_BOT, 160, 0, 8) -__MREG__(SS_NCLK, 161, 4, 4) -__MREG__(SSUP_P1_TOP, 161, 0, 4) - -/* Registers 162-163: VCXO Parameter */ -__MREG__(VCXO_PARAM_BOT, 162, 0, 8) -__MREG__(VCXO_PARAM_MID, 163, 0, 8) -__MREG__(VCXO_PARAM_TOP, 164, 0, 6) - -/* Registers 165-170: CLK0-CLK5 Initial Phase Offsets */ -__MREG__(CLK0_PHOFF, 165, 0, 7) -__MREG__(CLK1_PHOFF, 166, 0, 7) -__MREG__(CLK2_PHOFF, 167, 0, 7) -__MREG__(CLK3_PHOFF, 168, 0, 7) -__MREG__(CLK4_PHOFF, 169, 0, 7) -__MREG__(CLK5_PHOFF, 170, 0, 7) - -/* Register 177: PLL Reset */ -__MREG__(PLLB_RST, 177, 7, 1) -__MREG__(PLLA_RST, 177, 5, 1) - -/* Register 183: Crystal Internal Load Capacitance */ -__MREG__(XTAL_CL, 183, 6, 2) - -/* Register 187: Fanout Enable */ -__MREG__(CLKIN_FANOUT_EN, 187, 7, 1) -__MREG__(XO_FANOUT_EN, 187, 6, 1) -__MREG__(MS_FANOUT_EN, 187, 4, 1) - -/* 3-part parameters */ -__3PART__(MSNA_P1) -__3PART__(MSNA_P2) -__3PART__(MSNA_P3) -__3PART__(MSNB_P1) -__3PART__(MSNB_P2) -__3PART__(MSNB_P3) -__3PART__(MS0_P1) -__3PART__(MS0_P2) -__3PART__(MS0_P3) -__3PART__(MS1_P1) -__3PART__(MS1_P2) -__3PART__(MS1_P3) -__3PART__(MS2_P1) -__3PART__(MS2_P2) -__3PART__(MS2_P3) -__3PART__(MS3_P1) -__3PART__(MS3_P2) -__3PART__(MS3_P3) -__3PART__(MS4_P1) -__3PART__(MS4_P2) -__3PART__(MS4_P3) -__3PART__(MS5_P1) -__3PART__(MS5_P2) -__3PART__(MS5_P3) - -/* 2-part parameters */ -__2PART__(SSDN_P1) -__2PART__(SSDN_P2) -__2PART__(SSDN_P3) -__2PART__(SSUP_P1) -__2PART__(SSUP_P2) -__2PART__(SSUP_P3) -__2PART__(SSUDP) - -/* Per-PLL register groups */ -__PER_PLL__(LOL, LOL_, ) -__PER_PLL__(LOL_STKY, LOL_, _STKY) -__PER_PLL__(LOL_MASK, LOL_, _MASK) -__PER_PLL__(PLL_SRC, PLL, _SRC) -__PER_PLL__(MSN_P1, MSN, _P1) -__PER_PLL__(MSN_P2, MSN, _P2) -__PER_PLL__(MSN_P3, MSN, _P3) -__PER_PLL__(PLL_RST, PLL, _RST) - -/* Per-multisynth register groups */ -__PER_MS__(CLK_OEB, CLK, _OEB) -__PER_MS__(OEB_CLK, OEB_CLK, ) -__PER_MS__(OEB_MASK, OEB_MASK, ) -__PER_MS__(CLK_PDN, CLK, _PDN) -__PER_MS__(MS_SRC, MS, _SRC) -__PER_MS__(CLK_INV, CLK, _INV) -__PER_MS__(CLK_SRC, CLK, _SRC) -__PER_MS__(CLK_IDRV, CLK, _IDRV) -__PER_MS__(CLK_DIS_STATE, CLK, _DIS_STATE) -__PER_MS__(R_DIV, R, _DIV) -__PER_MS__(MS_P1, MS, _P1) -__PER_FRAC_MS__(MS_INT, MS, _INT) -__PER_FRAC_MS__(MS_P2, MS, _P2) -__PER_FRAC_MS__(MS_P3, MS, _P3) -__PER_FRAC_MS__(MS_DIVBY4, MS, _DIVBY4) -__PER_FRAC_MS__(CLK_PHOFF, CLK, _PHOFF) diff --git a/firmware/common/spi_bus.c b/firmware/common/spi_bus.c index a667db8a..a26b4bab 100644 --- a/firmware/common/spi_bus.c +++ b/firmware/common/spi_bus.c @@ -24,36 +24,23 @@ void spi_bus_start(spi_bus_t* const bus, const void* const config) { - bus->config = config; bus->start(bus, config); } void spi_bus_stop(spi_bus_t* const bus) { bus->stop(bus); - bus->config = NULL; } -void spi_bus_transfer( - spi_bus_t* const bus, - const void* const config, - void* const data, - const size_t count) +void spi_bus_transfer(spi_bus_t* const bus, void* const data, const size_t count) { - if (config != bus->config) { - spi_bus_start(bus, config); - } bus->transfer(bus, data, count); } void spi_bus_transfer_gather( spi_bus_t* const bus, - const void* const config, const spi_transfer_t* const transfers, const size_t count) { - if (config != bus->config) { - spi_bus_start(bus, config); - } bus->transfer_gather(bus, transfers, count); } diff --git a/firmware/common/spi_bus.h b/firmware/common/spi_bus.h index bc9c7dee..d24e2bbf 100644 --- a/firmware/common/spi_bus.h +++ b/firmware/common/spi_bus.h @@ -20,7 +20,8 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __SPI_BUS_H__ +#define __SPI_BUS_H__ #include @@ -29,30 +30,27 @@ typedef struct { const size_t count; } spi_transfer_t; -typedef struct _spi_bus_t { +struct spi_bus_t; +typedef struct spi_bus_t spi_bus_t; + +struct spi_bus_t { void* const obj; const void* config; - void (*start)(struct _spi_bus_t* const bus, const void* const config); - void (*stop)(struct _spi_bus_t* const bus); - void (*transfer)( - struct _spi_bus_t* const bus, - void* const data, - const size_t count); + void (*start)(spi_bus_t* const bus, const void* const config); + void (*stop)(spi_bus_t* const bus); + void (*transfer)(spi_bus_t* const bus, void* const data, const size_t count); void (*transfer_gather)( - struct _spi_bus_t* const bus, + spi_bus_t* const bus, const spi_transfer_t* const transfers, const size_t count); -} spi_bus_t; +}; void spi_bus_start(spi_bus_t* const bus, const void* const config); void spi_bus_stop(spi_bus_t* const bus); -void spi_bus_transfer( - spi_bus_t* const bus, - const void* const config, - void* const data, - const size_t count); +void spi_bus_transfer(spi_bus_t* const bus, void* const data, const size_t count); void spi_bus_transfer_gather( spi_bus_t* const bus, - const void* const config, const spi_transfer_t* const transfers, const size_t count); + +#endif /*__SPI_BUS_H__*/ diff --git a/firmware/common/spi_ssp.c b/firmware/common/spi_ssp.c index 868556be..4e25aa4a 100644 --- a/firmware/common/spi_ssp.c +++ b/firmware/common/spi_ssp.c @@ -22,29 +22,9 @@ #include "spi_ssp.h" -#include - -#include #include #include -/* Driver instances. */ -spi_bus_t spi_bus_ssp0 = { - .obj = (void*) SSP0_BASE, - .start = spi_ssp_start, - .stop = spi_ssp_stop, - .transfer = spi_ssp_transfer, - .transfer_gather = spi_ssp_transfer_gather, -}; - -spi_bus_t spi_bus_ssp1 = { - .obj = (void*) SSP1_BASE, - .start = spi_ssp_start, - .stop = spi_ssp_stop, - .transfer = spi_ssp_transfer, - .transfer_gather = spi_ssp_transfer_gather, -}; - void spi_ssp_start(spi_bus_t* const bus, const void* const _config) { const ssp_config_t* const config = _config; diff --git a/firmware/common/spi_ssp.h b/firmware/common/spi_ssp.h index 5e754dc4..769277dd 100644 --- a/firmware/common/spi_ssp.h +++ b/firmware/common/spi_ssp.h @@ -20,17 +20,19 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __SPI_SSP_H__ +#define __SPI_SSP_H__ #include #include -#include - -#include "gpio.h" #include "spi_bus.h" -typedef struct { +#include "gpio.h" + +#include + +typedef struct ssp_config_t { ssp_datasize_t data_bits; ssp_cpol_cpha_t spi_mode; uint8_t serial_clock_rate; @@ -46,6 +48,4 @@ void spi_ssp_transfer_gather( const spi_transfer_t* const transfers, const size_t count); -/* Driver instances. */ -extern spi_bus_t spi_bus_ssp0; -extern spi_bus_t spi_bus_ssp1; +#endif /*__SPI_SSP_H__*/ diff --git a/firmware/common/streaming.c b/firmware/common/streaming.c index 1c2440fb..d984fe25 100644 --- a/firmware/common/streaming.c +++ b/firmware/common/streaming.c @@ -23,10 +23,9 @@ #include +#include #include -#include "sgpio.h" - void baseband_streaming_enable(sgpio_config_t* const sgpio_config) { SGPIO_SET_EN_1 = (1 << SGPIO_SLICE_A); diff --git a/firmware/common/streaming.h b/firmware/common/streaming.h index 47af5120..47f466c1 100644 --- a/firmware/common/streaming.h +++ b/firmware/common/streaming.h @@ -21,9 +21,12 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __STREAMING_H__ +#define __STREAMING_H__ #include void baseband_streaming_enable(sgpio_config_t* const sgpio_config); void baseband_streaming_disable(sgpio_config_t* const sgpio_config); + +#endif /*__STREAMING_H__*/ diff --git a/firmware/common/transceiver_mode.h b/firmware/common/transceiver_mode.h deleted file mode 100644 index dccb71b2..00000000 --- a/firmware/common/transceiver_mode.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2012-2026 Great Scott Gadgets - * Copyright 2012 Jared Boone - * Copyright 2013 Benjamin Vernoux - * - * This file is part of HackRF. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#pragma once - -typedef enum { - TRANSCEIVER_MODE_OFF = 0, - TRANSCEIVER_MODE_RX = 1, - TRANSCEIVER_MODE_TX = 2, - TRANSCEIVER_MODE_SS = 3, - TRANSCEIVER_MODE_CPLD_UPDATE = 4, - TRANSCEIVER_MODE_RX_SWEEP = 5, -} transceiver_mode_t; diff --git a/firmware/common/tune_config.h b/firmware/common/tune_config.h index dd81f62d..dd21d028 100644 --- a/firmware/common/tune_config.h +++ b/firmware/common/tune_config.h @@ -19,11 +19,10 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __TUNE_CONFIG_H__ +#define __TUNE_CONFIG_H__ -#include "platform_detect.h" - -#ifdef IS_PRALINE +#ifdef PRALINE #include "fpga.h" typedef struct { @@ -392,3 +391,5 @@ static const tune_config_t praline_tune_config_rx[] = { }; // clang-format on #endif + +#endif /*__TUNE_CONFIG_H__*/ diff --git a/firmware/common/tuning.c b/firmware/common/tuning.c index 9e3c41ba..e1a1d951 100644 --- a/firmware/common/tuning.c +++ b/firmware/common/tuning.c @@ -1,5 +1,5 @@ /* - * Copyright 2012-2026 Great Scott Gadgets + * Copyright 2012-2022 Great Scott Gadgets * Copyright 2012 Jared Boone * Copyright 2013 Benjamin Vernoux * @@ -22,96 +22,219 @@ */ #include "tuning.h" - -#include "fixed_point.h" +#include "hackrf_ui.h" +#include "hackrf_core.h" +#include "mixer.h" +#include "max2831.h" +#include "max2837.h" +#include "max2839.h" +#include "sgpio.h" +#include "operacake.h" #include "platform_detect.h" -#define MIN(x, y) ((x) < (y) ? (x) : (y)) -#define MAX(x, y) ((x) > (y) ? (x) : (y)) +#ifndef PRALINE -#define MID1_HP_FREQ FP_MHZ(3600) -#define MID2_HP_FREQ FP_MHZ(5100) -#define MAX_HP_FREQ FP_MHZ(7250) + #define MIN_LP_FREQ_MHZ (0) + #define MAX_LP_FREQ_MHZ (2170ULL) -static fp_40_24_t min_bypass_freq = FP_MHZ(2170); -static fp_40_24_t max_bypass_freq = FP_MHZ(2740); + #define ABS_MIN_BYPASS_FREQ_MHZ (2000ULL) + #define MIN_BYPASS_FREQ_MHZ (MAX_LP_FREQ_MHZ) + #define MAX_BYPASS_FREQ_MHZ (2740ULL) + #define ABS_MAX_BYPASS_FREQ_MHZ (3000ULL) -void tuning_setup(void) + #define MIN_HP_FREQ_MHZ (MAX_BYPASS_FREQ_MHZ) + #define MID1_HP_FREQ_MHZ (3600ULL) + #define MID2_HP_FREQ_MHZ (5100ULL) + #define MAX_HP_FREQ_MHZ (7250ULL) + + #define MIN_LO_FREQ_HZ (84375000ULL) + #define MAX_LO_FREQ_HZ (5400000000ULL) + +#else + + #define MIN_LP_FREQ_MHZ (0) + #define MAX_LP_FREQ_MHZ (2320ULL) + + #define ABS_MIN_BYPASS_FREQ_MHZ (2000ULL) + #define MIN_BYPASS_FREQ_MHZ (MAX_LP_FREQ_MHZ) + #define MAX_BYPASS_FREQ_MHZ (2580ULL) + #define ABS_MAX_BYPASS_FREQ_MHZ (3000ULL) + + #define MIN_HP_FREQ_MHZ (MAX_BYPASS_FREQ_MHZ) + #define MAX_HP_FREQ_MHZ (7250ULL) + + #define MIN_LO_FREQ_HZ (84375000ULL) + #define MAX_LO_FREQ_HZ (5400000000ULL) + +#endif + +#ifndef PRALINE +static uint32_t max2837_freq_nominal_hz = 2560000000; + +/* + * Set freq/tuning between 0MHz to 7250 MHz (less than 16bits really used) + * hz between 0 to 999999 Hz (not checked) + * return false on error or true if success. + */ +bool set_freq(const uint64_t freq) { -#ifdef IS_PRALINE - if (IS_PRALINE) { - min_bypass_freq = FP_MHZ(2320); - max_bypass_freq = FP_MHZ(2580); - } -#endif -} + bool success; + uint64_t mixer_freq_hz; + uint64_t real_mixer_freq_hz; -fp_40_24_t select_graduated_if(fp_40_24_t freq_rf, rf_path_filter_t img_reject) -{ - fp_40_24_t freq_if; + const uint32_t freq_mhz = freq / FREQ_ONE_MHZ; - switch (img_reject) { - case RF_PATH_FILTER_LOW_PASS: -#ifdef IS_RAD1O - if (IS_RAD1O) { - freq_if = FP_MHZ(2300); - } -#endif -#ifdef IS_NOT_RAD1O - if (IS_NOT_RAD1O) { - /* IF is graduated from 2650 MHz to 2340 MHz */ - freq_if = FP_MHZ(2650) - (freq_rf / 7); - } -#endif - break; - case RF_PATH_FILTER_HIGH_PASS: - if (freq_rf < MID1_HP_FREQ) { + success = true; + + max283x_mode_t prior_max283x_mode = max283x_mode(&max283x); + max283x_set_mode(&max283x, MAX283x_MODE_STANDBY); + if (freq_mhz < MAX_LP_FREQ_MHZ) { + rf_path_set_filter(&rf_path, RF_PATH_FILTER_LOW_PASS); + #ifdef RAD1O + max2837_freq_nominal_hz = 2300 * FREQ_ONE_MHZ; + #else + /* IF is graduated from 2650 MHz to 2340 MHz */ + max2837_freq_nominal_hz = (2650 * FREQ_ONE_MHZ) - (freq / 7); + #endif + mixer_freq_hz = max2837_freq_nominal_hz + freq; + /* Set Freq and read real freq */ + real_mixer_freq_hz = mixer_set_frequency(&mixer, mixer_freq_hz); + max283x_set_frequency(&max283x, real_mixer_freq_hz - freq); + sgpio_cpld_set_mixer_invert(&sgpio_config, 1); + } else if ((freq_mhz >= MIN_BYPASS_FREQ_MHZ) && (freq_mhz < MAX_BYPASS_FREQ_MHZ)) { + rf_path_set_filter(&rf_path, RF_PATH_FILTER_BYPASS); + /* mixer_freq_mhz <= not used in Bypass mode */ + max283x_set_frequency(&max283x, freq); + sgpio_cpld_set_mixer_invert(&sgpio_config, 0); + } else if ((freq_mhz >= MIN_HP_FREQ_MHZ) && (freq_mhz <= MAX_HP_FREQ_MHZ)) { + if (freq_mhz < MID1_HP_FREQ_MHZ) { /* IF is graduated from 2170 MHz to 2740 MHz */ - freq_if = min_bypass_freq + - (((freq_rf - (max_bypass_freq)) * 57) / 86); - } else if (freq_rf < MID2_HP_FREQ) { + max2837_freq_nominal_hz = (MIN_BYPASS_FREQ_MHZ * FREQ_ONE_MHZ) + + (((freq - (MAX_BYPASS_FREQ_MHZ * FREQ_ONE_MHZ)) * 57) / + 86); + } else if (freq_mhz < MID2_HP_FREQ_MHZ) { /* IF is graduated from 2350 MHz to 2650 MHz */ - freq_if = FP_MHZ(2350) + ((freq_rf - (MID1_HP_FREQ)) / 5); + max2837_freq_nominal_hz = (2350 * FREQ_ONE_MHZ) + + ((freq - (MID1_HP_FREQ_MHZ * FREQ_ONE_MHZ)) / 5); } else { /* IF is graduated from 2500 MHz to 2738 MHz */ - freq_if = FP_MHZ(2500) + ((freq_rf - (MID2_HP_FREQ)) / 9); + max2837_freq_nominal_hz = (2500 * FREQ_ONE_MHZ) + + ((freq - (MID2_HP_FREQ_MHZ * FREQ_ONE_MHZ)) / 9); } - break; - default: - freq_if = freq_rf; - } - return freq_if; -} - -rf_path_filter_t select_img_reject(fp_40_24_t freq_rf) -{ - if (freq_rf > max_bypass_freq) { - return RF_PATH_FILTER_HIGH_PASS; - } else if (freq_rf >= min_bypass_freq) { - return RF_PATH_FILTER_BYPASS; + rf_path_set_filter(&rf_path, RF_PATH_FILTER_HIGH_PASS); + mixer_freq_hz = freq - max2837_freq_nominal_hz; + /* Set Freq and read real freq */ + real_mixer_freq_hz = mixer_set_frequency(&mixer, mixer_freq_hz); + max283x_set_frequency(&max283x, freq - real_mixer_freq_hz); + sgpio_cpld_set_mixer_invert(&sgpio_config, 0); } else { - return RF_PATH_FILTER_LOW_PASS; + /* Error freq_mhz too high */ + success = false; } + max283x_set_mode(&max283x, prior_max283x_mode); + if (success) { + hackrf_ui()->set_frequency(freq); + #ifdef HACKRF_ONE + operacake_set_range(freq_mhz); + #endif + } + return success; } -fp_40_24_t restrict_rf(fp_40_24_t freq_rf, rf_path_filter_t img_reject) +#else + +bool tuning_set_frequency( + const tune_config_t* cfg, + const uint64_t freq, + const uint32_t offset) { - fp_40_24_t min_rf = 0; - fp_40_24_t max_rf = MAX_HP_FREQ; + uint64_t mixer_freq_hz; + uint64_t real_mixer_freq_hz; - switch (img_reject) { - case RF_PATH_FILTER_LOW_PASS: - max_rf = min_bypass_freq; - break; - case RF_PATH_FILTER_HIGH_PASS: - min_rf = max_bypass_freq; - break; - default: - min_rf = min_bypass_freq; - max_rf = max_bypass_freq; + if (freq > (MAX_HP_FREQ_MHZ * FREQ_ONE_MHZ)) { + return false; } - freq_rf = MIN(freq_rf, max_rf); - freq_rf = MAX(freq_rf, min_rf); - return freq_rf; + const uint16_t freq_mhz = freq / FREQ_ONE_MHZ; + + uint64_t rf = freq; + if (cfg->shift == FPGA_QUARTER_SHIFT_MODE_DOWN) { + if (offset > rf) { + rf = offset - rf; + } else { + rf = rf - offset; + } + } else if (cfg->shift == FPGA_QUARTER_SHIFT_MODE_UP) { + rf = rf + offset; + } + + max2831_mode_t prior_max2831_mode = max2831_mode(&max283x); + max2831_set_mode(&max283x, MAX2831_MODE_STANDBY); + + if (cfg->if_mhz == 0) { + rf_path_set_filter(&rf_path, RF_PATH_FILTER_BYPASS); + max2831_set_frequency(&max283x, rf); + sgpio_cpld_set_mixer_invert(&sgpio_config, 0); + } else if (cfg->if_mhz > freq_mhz) { + rf_path_set_filter(&rf_path, RF_PATH_FILTER_LOW_PASS); + if (cfg->high_lo) { + mixer_freq_hz = FREQ_ONE_MHZ * cfg->if_mhz + rf; + real_mixer_freq_hz = mixer_set_frequency(&mixer, mixer_freq_hz); + max2831_set_frequency(&max283x, real_mixer_freq_hz - rf); + sgpio_cpld_set_mixer_invert(&sgpio_config, 1); + } else { + mixer_freq_hz = FREQ_ONE_MHZ * cfg->if_mhz - rf; + real_mixer_freq_hz = mixer_set_frequency(&mixer, mixer_freq_hz); + max2831_set_frequency(&max283x, real_mixer_freq_hz + rf); + sgpio_cpld_set_mixer_invert(&sgpio_config, 0); + } + } else { + rf_path_set_filter(&rf_path, RF_PATH_FILTER_HIGH_PASS); + mixer_freq_hz = rf - FREQ_ONE_MHZ * cfg->if_mhz; + real_mixer_freq_hz = mixer_set_frequency(&mixer, mixer_freq_hz); + max2831_set_frequency(&max283x, rf - real_mixer_freq_hz); + sgpio_cpld_set_mixer_invert(&sgpio_config, 0); + } + + max2831_set_mode(&max283x, prior_max2831_mode); + hackrf_ui()->set_frequency(freq); + operacake_set_range(freq_mhz); + return true; +} +#endif + +bool set_freq_explicit( + const uint64_t if_freq_hz, + const uint64_t lo_freq_hz, + const rf_path_filter_t path) +{ + if ((if_freq_hz < ((uint64_t) ABS_MIN_BYPASS_FREQ_MHZ * FREQ_ONE_MHZ)) || + (if_freq_hz > ((uint64_t) ABS_MAX_BYPASS_FREQ_MHZ * FREQ_ONE_MHZ))) { + return false; + } + + if ((path != RF_PATH_FILTER_BYPASS) && + ((lo_freq_hz < MIN_LO_FREQ_HZ) || (lo_freq_hz > MAX_LO_FREQ_HZ))) { + return false; + } + + if (path > 2) { + return false; + } + + rf_path_set_filter(&rf_path, path); +#ifdef PRALINE + max2831_set_frequency(&max283x, if_freq_hz); +#else + max283x_set_frequency(&max283x, if_freq_hz); +#endif + if (lo_freq_hz > if_freq_hz) { + sgpio_cpld_set_mixer_invert(&sgpio_config, 1); + } else { + sgpio_cpld_set_mixer_invert(&sgpio_config, 0); + } + if (path != RF_PATH_FILTER_BYPASS) { + (void) mixer_set_frequency(&mixer, lo_freq_hz); + } + return true; } diff --git a/firmware/common/tuning.h b/firmware/common/tuning.h index db123ee3..863fe6a0 100644 --- a/firmware/common/tuning.h +++ b/firmware/common/tuning.h @@ -1,5 +1,5 @@ /* - * Copyright 2012-2026 Great Scott Gadgets + * Copyright 2012-2022 Great Scott Gadgets * Copyright 2012 Jared Boone * Copyright 2013 Benjamin Vernoux * @@ -21,24 +21,28 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __TUNING_H__ +#define __TUNING_H__ -#include "fixed_point.h" #include "rf_path.h" +#include "tune_config.h" -void tuning_setup(void); +#include +#include -/** - * Select fixed or graduated IF for a given RF and image reject filter. - */ -fp_40_24_t select_graduated_if(fp_40_24_t freq_rf, rf_path_filter_t img_reject); +#define FREQ_ONE_MHZ (1000ULL * 1000) -/** - * Select image reject filter appropriate for a given RF. - */ -rf_path_filter_t select_img_reject(fp_40_24_t freq_rf); +bool set_freq(const uint64_t freq); +bool set_freq_explicit( + const uint64_t if_freq_hz, + const uint64_t lo_freq_hz, + const rf_path_filter_t path); -/** - * Restrict RF to range appropriate for a given image reject filter. - */ -fp_40_24_t restrict_rf(fp_40_24_t freq_rf, rf_path_filter_t img_reject); +#ifdef PRALINE +bool tuning_set_frequency( + const tune_config_t* cfg, + const uint64_t freq, + const uint32_t offset); +#endif + +#endif /*__TUNING_H__*/ diff --git a/firmware/common/u128.c b/firmware/common/u128.c deleted file mode 100644 index 3543f332..00000000 --- a/firmware/common/u128.c +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2026 Great Scott Gadgets - * - * This file is part of HackRF. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#include "u128.h" - -/* From https://stackoverflow.com/a/58381061 */ - -u128 u128_multiply(uint64_t lhs, uint64_t rhs) -{ - uint64_t lo_lo = (lhs & 0xFFFFFFFF) * (rhs & 0xFFFFFFFF); - uint64_t hi_lo = (lhs >> 32) * (rhs & 0xFFFFFFFF); - uint64_t lo_hi = (lhs & 0xFFFFFFFF) * (rhs >> 32); - uint64_t hi_hi = (lhs >> 32) * (rhs >> 32); - uint64_t cross = ((lo_lo >> 32) + (hi_lo & 0xFFFFFFFF) + lo_hi); - return (u128){ - .hi = ((hi_lo >> 32) + (cross >> 32) + hi_hi), - .lo = ((cross << 32) | (lo_lo & 0xFFFFFFFF)), - }; -} - -/* From https://stackoverflow.com/a/70052545 */ - -/* clang-format off */ - -#define SUBCcc(a,b,cy,t0,t1,t2) \ - (t0=(b)+cy, t1=(a), cy=t0= divisor - rem.lo = tmp.lo; - rem.hi = tmp.hi; - quot.lo |= 1; - } - } - - return quot; -} diff --git a/firmware/common/u128.h b/firmware/common/u128.h deleted file mode 100644 index c51dc5f5..00000000 --- a/firmware/common/u128.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2026 Great Scott Gadgets - * - * This file is part of HackRF. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#pragma once - -#include - -typedef struct { - uint64_t hi; - uint64_t lo; -} u128; - -u128 u128_multiply(uint64_t a, uint64_t b); -u128 u128_divide(u128 dvnd, u128 dvsr); diff --git a/firmware/common/ui_portapack.c b/firmware/common/ui_portapack.c index 3387b5eb..9918157c 100644 --- a/firmware/common/ui_portapack.c +++ b/firmware/common/ui_portapack.c @@ -22,14 +22,7 @@ #include "ui_portapack.h" -#include -#include -#include - -#include "clock_gen.h" #include "portapack.h" -#include "rf_path.h" -#include "transceiver_mode.h" /* Pixel data within a font or bitmap byte is "reversed": LSB is left-most pixel. */ @@ -394,7 +387,7 @@ static ui_point_t portapack_lcd_draw_string(ui_point_t point, const char* s) return point; } -typedef struct { +typedef struct draw_list_t { const ui_bitmap_t* bitmap; const ui_point_t point; } draw_list_t; @@ -495,11 +488,8 @@ static void portapack_radio_path_item_update( static rf_path_direction_t portapack_direction = RF_PATH_DIRECTION_OFF; static bool portapack_lna_on = false; -static uint32_t tx_if_gain = 0; -static uint32_t rx_if_gain = 0; -static uint32_t rx_bb_gain = 0; -static void portapack_radio_path_redraw(void) +static void portapack_radio_path_redraw() { for (size_t i = 0; i < ARRAY_SIZEOF(radio_draw_list); i++) { portapack_draw_radio_path_item(i); @@ -521,7 +511,7 @@ static void portapack_ui_deinit(void) static void portapack_ui_set_frequency(uint64_t frequency) { - __attribute__((nonstring)) static char last[10] = " "; + static char last[10] = " "; ui_point_t point = {240 - 20, 16}; @@ -529,7 +519,7 @@ static void portapack_ui_set_frequency(uint64_t frequency) char s[10]; for (int i = 0; i < 10; i++) { const char c = '0' + value % 10; - s[i] = ((i >= 7) && (value == 0)) ? ' ' : c; + s[i] = ((i >= 6) && (value == 0)) ? ' ' : c; value /= 10; } @@ -572,6 +562,51 @@ static void portapack_ui_set_sample_rate(uint32_t sample_rate) #endif } +static void portapack_ui_set_direction(const rf_path_direction_t direction) +{ + switch (direction) { + case RF_PATH_DIRECTION_TX: + portapack_radio_path_item_update( + RADIO_DRAW_LIST_ITEM_WAVES, + &bitmap_waves_tx); + portapack_radio_path_item_update( + RADIO_DRAW_LIST_ITEM_RF_AMP, + portapack_lna_on ? &bitmap_amp_tx : &bitmap_wire_24); + portapack_radio_path_item_update( + RADIO_DRAW_LIST_ITEM_BB_LNA_AMP, + &bitmap_amp_tx); + portapack_radio_path_item_update( + RADIO_DRAW_LIST_ITEM_BB_VGA_AMP, + &bitmap_wire_24); + portapack_ui_draw_string(RADIO_DRAW_LIST_ITEM_BB_VGA_AMP, " "); + break; + + case RF_PATH_DIRECTION_RX: + portapack_radio_path_item_update( + RADIO_DRAW_LIST_ITEM_WAVES, + &bitmap_waves_rx); + portapack_radio_path_item_update( + RADIO_DRAW_LIST_ITEM_RF_AMP, + portapack_lna_on ? &bitmap_amp_rx : &bitmap_wire_24); + portapack_radio_path_item_update( + RADIO_DRAW_LIST_ITEM_BB_LNA_AMP, + &bitmap_amp_rx); + portapack_radio_path_item_update( + RADIO_DRAW_LIST_ITEM_BB_VGA_AMP, + &bitmap_amp_rx); + break; + + case RF_PATH_DIRECTION_OFF: + default: + portapack_radio_path_item_update( + RADIO_DRAW_LIST_ITEM_WAVES, + &bitmap_blank_24); + break; + } + + portapack_direction = direction; +} + static void portapack_ui_set_filter_bw(uint32_t bandwidth) { portapack_ui_draw_bw_mhz(RADIO_DRAW_LIST_ITEM_BB_FILTER, bandwidth); @@ -592,18 +627,12 @@ static void portapack_ui_set_lna_power(bool lna_on) static void portapack_ui_set_bb_lna_gain(const uint32_t gain_db) { - rx_if_gain = gain_db; - if (portapack_direction == RF_PATH_DIRECTION_RX) { - portapack_ui_draw_db(RADIO_DRAW_LIST_ITEM_BB_LNA_AMP, gain_db); - } + portapack_ui_draw_db(RADIO_DRAW_LIST_ITEM_BB_LNA_AMP, gain_db); } static void portapack_ui_set_bb_vga_gain(const uint32_t gain_db) { - rx_bb_gain = gain_db; - if (portapack_direction == RF_PATH_DIRECTION_RX) { - portapack_ui_draw_db(RADIO_DRAW_LIST_ITEM_BB_VGA_AMP, gain_db); - } + portapack_ui_draw_db(RADIO_DRAW_LIST_ITEM_BB_VGA_AMP, gain_db); } static void portapack_ui_set_bb_tx_vga_gain(const uint32_t gain_db) @@ -612,10 +641,7 @@ static void portapack_ui_set_bb_tx_vga_gain(const uint32_t gain_db) * According to the MAX2837 datasheet diagram, there is no baseband gain in the TX path. * This gets called when the TX IF gain is changed. */ - tx_if_gain = gain_db; - if (portapack_direction == RF_PATH_DIRECTION_TX) { - portapack_ui_draw_db(RADIO_DRAW_LIST_ITEM_BB_LNA_AMP, gain_db); - } + portapack_ui_draw_db(RADIO_DRAW_LIST_ITEM_BB_LNA_AMP, gain_db); } static void portapack_ui_set_first_if_frequency(const uint64_t frequency) @@ -691,54 +717,6 @@ static bool portapack_ui_operacake_gpio_compatible(void) return false; } -static void portapack_ui_set_direction(const rf_path_direction_t direction) -{ - portapack_direction = direction; - - switch (direction) { - case RF_PATH_DIRECTION_TX: - portapack_radio_path_item_update( - RADIO_DRAW_LIST_ITEM_WAVES, - &bitmap_waves_tx); - portapack_radio_path_item_update( - RADIO_DRAW_LIST_ITEM_RF_AMP, - portapack_lna_on ? &bitmap_amp_tx : &bitmap_wire_24); - portapack_radio_path_item_update( - RADIO_DRAW_LIST_ITEM_BB_LNA_AMP, - &bitmap_amp_tx); - portapack_radio_path_item_update( - RADIO_DRAW_LIST_ITEM_BB_VGA_AMP, - &bitmap_wire_24); - portapack_ui_draw_string(RADIO_DRAW_LIST_ITEM_BB_VGA_AMP, " "); - portapack_ui_set_bb_tx_vga_gain(tx_if_gain); - break; - - case RF_PATH_DIRECTION_RX: - portapack_radio_path_item_update( - RADIO_DRAW_LIST_ITEM_WAVES, - &bitmap_waves_rx); - portapack_radio_path_item_update( - RADIO_DRAW_LIST_ITEM_RF_AMP, - portapack_lna_on ? &bitmap_amp_rx : &bitmap_wire_24); - portapack_radio_path_item_update( - RADIO_DRAW_LIST_ITEM_BB_LNA_AMP, - &bitmap_amp_rx); - portapack_radio_path_item_update( - RADIO_DRAW_LIST_ITEM_BB_VGA_AMP, - &bitmap_amp_rx); - portapack_ui_set_bb_vga_gain(rx_bb_gain); - portapack_ui_set_bb_lna_gain(rx_if_gain); - break; - - case RF_PATH_DIRECTION_OFF: - default: - portapack_radio_path_item_update( - RADIO_DRAW_LIST_ITEM_WAVES, - &bitmap_blank_24); - break; - } -} - const hackrf_ui_t portapack_hackrf_ui = { &portapack_ui_init, &portapack_ui_deinit, @@ -758,9 +736,9 @@ const hackrf_ui_t portapack_hackrf_ui = { &portapack_ui_operacake_gpio_compatible, }; -const hackrf_ui_t* portapack_hackrf_ui_init(void) +const hackrf_ui_t* portapack_hackrf_ui_init() { - if (portapack_present()) { + if (portapack()) { return &portapack_hackrf_ui; } else { return NULL; diff --git a/firmware/common/ui_portapack.h b/firmware/common/ui_portapack.h index e0695839..d712c895 100644 --- a/firmware/common/ui_portapack.h +++ b/firmware/common/ui_portapack.h @@ -20,8 +20,11 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __UI_PORTAPACK_H__ +#define __UI_PORTAPACK_H__ #include "hackrf_ui.h" -const hackrf_ui_t* portapack_hackrf_ui_init(void) __attribute__((weak)); +const hackrf_ui_t* portapack_hackrf_ui_init() __attribute__((weak)); + +#endif /*__UI_PORTAPACK_H__*/ diff --git a/firmware/common/ui_rad1o.c b/firmware/common/ui_rad1o.c index a6d3e544..8312c12b 100644 --- a/firmware/common/ui_rad1o.c +++ b/firmware/common/ui_rad1o.c @@ -22,13 +22,6 @@ #include "ui_rad1o.h" -#include -#include - -#include "clock_gen.h" -#include "rf_path.h" -#include "transceiver_mode.h" - #include "rad1o/display.h" #include "rad1o/draw.h" #include "rad1o/print.h" @@ -36,6 +29,8 @@ #include "rad1o/smallfonts.h" #include "rad1o/ubuntu18.h" +#include + static uint64_t freq = 0; static uint32_t sample_rate = 0; static uint32_t filter_bw = 0; @@ -56,22 +51,20 @@ static bool enabled = false; #define WHITE 0b11111111 #define GREY 0b01001101 -#define DIV_ROUND_CLOSEST(n, d) ((n + (d / 2)) / d) - -static void print_hz(char* fmt, uint64_t hz) -{ - uint32_t mhz, khz; - mhz = DIV_ROUND_CLOSEST(hz, 1000000); - hz -= mhz * 1000000; - khz = DIV_ROUND_CLOSEST(hz, 1000); - rad1o_lcdPrint(fmt, (unsigned int) mhz, (unsigned int) khz); -} - static void draw_frequency(void) { + char tmp[100]; + uint32_t mhz; + uint32_t khz; + + mhz = freq / 1000000; + khz = (freq - mhz * 1000000) / 1000; + rad1o_setTextColor(BLACK, GREEN); rad1o_setIntFont(&Font_Ubuntu18pt); - print_hz("%4u.%03u", freq); + sprintf(tmp, "%4u.%03u", (unsigned int) mhz, (unsigned int) khz); + rad1o_lcdPrint(tmp); + rad1o_setIntFont(&Font_7x8); rad1o_lcdMoveCrsr(1, 18 - 7); rad1o_lcdPrint("MHz"); @@ -111,6 +104,10 @@ static void draw_tx_rx(void) static void ui_update(void) { + char tmp[100]; + uint32_t mhz; + uint32_t khz; + if (!enabled) { return; } @@ -150,12 +147,18 @@ static void ui_update(void) rad1o_setTextColor(BLACK, WHITE); rad1o_lcdSetCrsr(2, 71); rad1o_lcdPrint("Rate: "); - print_hz("%2u.%03u MHz", sample_rate); + mhz = sample_rate / 1000000; + khz = (sample_rate - mhz * 1000000) / 1000; + sprintf(tmp, "%2u.%03u MHz", (unsigned int) mhz, (unsigned int) khz); + rad1o_lcdPrint(tmp); rad1o_lcdNl(); rad1o_lcdMoveCrsr(2, 0); rad1o_lcdPrint("Filter: "); - print_hz("%2u.%03u MHz", filter_bw); + mhz = filter_bw / 1000000; + khz = (filter_bw - mhz * 1000000) / 1000; + sprintf(tmp, "%2u.%03u MHz", (unsigned int) mhz, (unsigned int) khz); + rad1o_lcdPrint(tmp); rad1o_lcdNl(); rad1o_drawHLine(88, 0, RESX - 1, WHITE); @@ -179,7 +182,8 @@ static void ui_update(void) if (direction == RF_PATH_DIRECTION_TX) { rad1o_setTextColor(BLACK, RED); } - rad1o_lcdPrint(" TX: %u dB", (unsigned int) bbtxvga_gain); + sprintf(tmp, " TX: %u dB", (unsigned int) bbtxvga_gain); + rad1o_lcdPrint(tmp); rad1o_lcdNl(); rad1o_lcdMoveCrsr(2, 0); @@ -187,13 +191,18 @@ static void ui_update(void) if (direction == RF_PATH_DIRECTION_RX) { rad1o_setTextColor(BLACK, GREEN); } - rad1o_lcdPrint("LNA: %2u dB", (unsigned int) bblna_gain); + sprintf(tmp, "LNA: %2u dB", (unsigned int) bblna_gain); + rad1o_lcdPrint(tmp); rad1o_lcdNl(); rad1o_lcdMoveCrsr(2, 0); - rad1o_lcdPrint("VGA: %2u dB", (unsigned int) bbvga_gain); + sprintf(tmp, "VGA: %2u dB", (unsigned int) bbvga_gain); + rad1o_lcdPrint(tmp); rad1o_lcdNl(); rad1o_lcdDisplay(); + + // Don't ask... + ssp1_set_mode_max283x(); } static void rad1o_ui_init(void) @@ -207,6 +216,8 @@ static void rad1o_ui_deinit(void) { rad1o_lcdDeInit(); enabled = false; + // Don't ask... + ssp1_set_mode_max283x(); } static void rad1o_ui_set_frequency(uint64_t frequency) diff --git a/firmware/common/ui_rad1o.h b/firmware/common/ui_rad1o.h index 73350d11..5b3e7421 100644 --- a/firmware/common/ui_rad1o.h +++ b/firmware/common/ui_rad1o.h @@ -20,8 +20,11 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __UI_RAD1O_H__ +#define __UI_RAD1O_H__ #include "hackrf_ui.h" const hackrf_ui_t* rad1o_ui_setup(void) __attribute__((weak)); + +#endif /*__UI_RAD1O_H__*/ diff --git a/firmware/common/usb.c b/firmware/common/usb.c index 026b7ec9..9188da73 100644 --- a/firmware/common/usb.c +++ b/firmware/common/usb.c @@ -20,18 +20,18 @@ * Boston, MA 02110-1301, USA. */ -#include #include - -#include -#include -#include -#include +#include #include "usb.h" +#include "usb_type.h" #include "usb_queue.h" #include "usb_standard_request.h" -#include "usb_type.h" + +#include +#include +#include +#include usb_device_t* usb_device_usb0 = 0; @@ -67,7 +67,7 @@ static uint_fast8_t usb_endpoint_number(const uint_fast8_t endpoint_address) return (endpoint_address & 0xF); } -void usb_peripheral_reset(void) +void usb_peripheral_reset() { RESET_CTRL0 = RESET_CTRL0_USB0_RST; RESET_CTRL0 = 0; @@ -75,7 +75,7 @@ void usb_peripheral_reset(void) while ((RESET_ACTIVE_STATUS0 & RESET_CTRL0_USB0_RST) == 0) {} } -void usb_phy_enable(void) +void usb_phy_enable() { CREG_CREG0 &= ~CREG_CREG0_USB0PHY; } @@ -634,7 +634,7 @@ static void usb_check_for_transfer_events(void) } } -void usb0_isr(void) +void usb0_isr() { const uint32_t status = usb_get_status(); diff --git a/firmware/common/usb.h b/firmware/common/usb.h index 2b8c6c8c..3d089816 100644 --- a/firmware/common/usb.h +++ b/firmware/common/usb.h @@ -20,10 +20,8 @@ * Boston, MA 02110-1301, USA. */ -#pragma once - -#include -#include +#ifndef __USB_H__ +#define __USB_H__ // TODO: Refactor to support high performance operations without having to // expose usb_transfer_descriptor_t. Or usb_endpoint_prime(). Or, or, or... @@ -31,8 +29,6 @@ #include "usb_type.h" -usb_queue_head_t* usb_queue_head(const uint_fast8_t endpoint_address); - void usb_peripheral_reset(void); void usb_phy_enable(void); @@ -78,3 +74,5 @@ void usb_endpoint_schedule_append( const usb_endpoint_t* const endpoint, usb_transfer_descriptor_t* const tail_td, usb_transfer_descriptor_t* const new_td); + +#endif //__USB_H__ diff --git a/firmware/common/usb_queue.c b/firmware/common/usb_queue.c index 3d5a4c34..a4cab94a 100644 --- a/firmware/common/usb_queue.c +++ b/firmware/common/usb_queue.c @@ -21,12 +21,12 @@ * Boston, MA 02110-1301, USA. */ +#include #include #include -#include +#include #include -#include #include "locking.h" #include "usb.h" diff --git a/firmware/common/usb_queue.h b/firmware/common/usb_queue.h index b6134946..793db5e0 100644 --- a/firmware/common/usb_queue.h +++ b/firmware/common/usb_queue.h @@ -21,33 +21,34 @@ * Boston, MA 02110-1301, USA. */ -#pragma once - -#include +#ifndef __USB_QUEUE_H__ +#define __USB_QUEUE_H__ #include #include "usb_type.h" +typedef struct _usb_transfer_t usb_transfer_t; +typedef struct _usb_queue_t usb_queue_t; typedef void (*transfer_completion_cb)(void*, unsigned int); // This is an opaque datatype. Thou shall not touch these members. -typedef struct _usb_transfer_t { +struct _usb_transfer_t { struct _usb_transfer_t* next; usb_transfer_descriptor_t td ATTR_ALIGNED(64); unsigned int maximum_length; struct _usb_queue_t* queue; transfer_completion_cb completion_cb; void* user_data; -} usb_transfer_t; +}; // This is an opaque datatype. Thou shall not touch these members. -typedef struct _usb_queue_t { - usb_endpoint_t* endpoint; +struct _usb_queue_t { + struct usb_endpoint_t* endpoint; const unsigned int pool_size; usb_transfer_t* volatile free_transfers; usb_transfer_t* volatile active; -} usb_queue_t; +}; #define USB_DECLARE_QUEUE(endpoint_name) struct _usb_queue_t endpoint_name##_queue; #define USB_DEFINE_QUEUE(endpoint_name, _pool_size) \ @@ -78,3 +79,5 @@ int usb_transfer_schedule_ack(const usb_endpoint_t* const endpoint); void usb_queue_init(usb_queue_t* const queue); void usb_queue_transfer_complete(usb_endpoint_t* const endpoint); + +#endif //__USB_QUEUE_H__ diff --git a/firmware/common/usb_request.c b/firmware/common/usb_request.c index e05cfa01..9aa2f595 100644 --- a/firmware/common/usb_request.c +++ b/firmware/common/usb_request.c @@ -20,13 +20,12 @@ * Boston, MA 02110-1301, USA. */ +#include "usb.h" #include "usb_request.h" +#include "usb_queue.h" #include -#include "usb.h" -#include "usb_queue.h" - static void usb_request(usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage) { usb_request_status_t status = USB_REQUEST_STATUS_STALL; diff --git a/firmware/common/usb_request.h b/firmware/common/usb_request.h index c61d77d6..40d5013d 100644 --- a/firmware/common/usb_request.h +++ b/firmware/common/usb_request.h @@ -20,7 +20,8 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __USB_REQUEST_H__ +#define __USB_REQUEST_H__ #include "usb_type.h" @@ -60,3 +61,5 @@ void usb_setup_complete(usb_endpoint_t* const endpoint); void usb_control_in_complete(usb_endpoint_t* const endpoint); void usb_control_out_complete(usb_endpoint_t* const endpoint); + +#endif //__USB_REQUEST_H__ diff --git a/firmware/common/usb_standard_request.c b/firmware/common/usb_standard_request.c index 152802c8..9671f5bf 100644 --- a/firmware/common/usb_standard_request.c +++ b/firmware/common/usb_standard_request.c @@ -20,14 +20,14 @@ * Boston, MA 02110-1301, USA. */ +#include +#include + #include "usb_standard_request.h" -#include -#include - #include "usb.h" -#include "usb_queue.h" #include "usb_type.h" +#include "usb_queue.h" const uint8_t* usb_endpoint_descriptor(const usb_endpoint_t* const endpoint) { diff --git a/firmware/common/usb_standard_request.h b/firmware/common/usb_standard_request.h index 84a8c458..f27d4292 100644 --- a/firmware/common/usb_standard_request.h +++ b/firmware/common/usb_standard_request.h @@ -20,13 +20,11 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __USB_STANDARD_REQUEST_H__ +#define __USB_STANDARD_REQUEST_H__ -#include -#include - -#include "usb_request.h" #include "usb_type.h" +#include "usb_request.h" void usb_set_configuration_changed_cb(void (*callback)(usb_device_t* const)); @@ -49,3 +47,5 @@ usb_transfer_type_t usb_endpoint_descriptor_transfer_type( bool usb_set_configuration( usb_device_t* const device, const uint_fast8_t configuration_number); + +#endif //__USB_STANDARD_REQUEST_H__ diff --git a/firmware/common/usb_type.h b/firmware/common/usb_type.h index 44810de5..fcff336c 100644 --- a/firmware/common/usb_type.h +++ b/firmware/common/usb_type.h @@ -20,9 +20,11 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __USB_TYPE_H__ +#define __USB_TYPE_H__ #include +#include // TODO: Move this to some common compiler-tricks location. #define ATTR_PACKED __attribute__((packed)) @@ -144,13 +146,17 @@ typedef struct { uint8_t* wcid_extended_properties_descriptor; } usb_device_t; -typedef struct _usb_endpoint_t { +typedef struct usb_endpoint_t usb_endpoint_t; + +struct usb_endpoint_t { usb_setup_t setup; uint8_t buffer[32]; // Buffer for use during IN stage. const uint_fast8_t address; usb_device_t* const device; - struct _usb_endpoint_t* const in; - struct _usb_endpoint_t* const out; - void (*setup_complete)(struct _usb_endpoint_t* const endpoint); - void (*transfer_complete)(struct _usb_endpoint_t* const endpoint); -} usb_endpoint_t; + usb_endpoint_t* const in; + usb_endpoint_t* const out; + void (*setup_complete)(usb_endpoint_t* const endpoint); + void (*transfer_complete)(usb_endpoint_t* const endpoint); +}; + +#endif //__USB_TYPE_H__ diff --git a/firmware/common/user_config.c b/firmware/common/user_config.c new file mode 100644 index 00000000..6c1ba419 --- /dev/null +++ b/firmware/common/user_config.c @@ -0,0 +1,112 @@ +/* + * Copyright 2023 Jonathan Suite (GitHub: @ai6aj) + * + * This file is part of HackRF. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "user_config.h" + +static user_config_user_opt_t user_direction_rx_bias_t_opts = RF_DIRECTION_USER_OPT_NOP; +static user_config_user_opt_t user_direction_tx_bias_t_opts = RF_DIRECTION_USER_OPT_NOP; +static user_config_user_opt_t user_direction_off_bias_t_opts = + RF_DIRECTION_USER_OPT_CLEAR; + +// Perform user-specified actions to Bias T power when transitioning modes +static void _rf_path_handle_user_bias_t_action(rf_path_t* const rf_path, int action) +{ + switch (action) { + case RF_DIRECTION_USER_OPT_SET: + rf_path_set_antenna(rf_path, 1); + break; + + case RF_DIRECTION_USER_OPT_CLEAR: + rf_path_set_antenna(rf_path, 0); + break; + + case RF_DIRECTION_USER_OPT_NOP: + default: + break; + } +} + +void user_config_on_rf_path_direction_change( + rf_path_t* const rf_path, + const rf_path_direction_t direction) +{ + switch (direction) { + case RF_PATH_DIRECTION_RX: + _rf_path_handle_user_bias_t_action(rf_path, user_direction_rx_bias_t_opts); + break; + + case RF_PATH_DIRECTION_TX: + _rf_path_handle_user_bias_t_action(rf_path, user_direction_tx_bias_t_opts); + break; + + case RF_PATH_DIRECTION_OFF: + default: + _rf_path_handle_user_bias_t_action( + rf_path, + user_direction_off_bias_t_opts); + break; + } +} + +void user_config_set_bias_t_opt( + const rf_path_direction_t direction, + const user_config_user_opt_t option) +{ + switch (direction) { + case RF_PATH_DIRECTION_RX: + user_direction_rx_bias_t_opts = option; + break; + + case RF_PATH_DIRECTION_TX: + user_direction_tx_bias_t_opts = option; + break; + + case RF_PATH_DIRECTION_OFF: + user_direction_off_bias_t_opts = option; + break; + + default: + break; + } +} + +/* + Bias T options are set as follows: + Bits 0,1: One of NOP (0), CLEAR (0b10), or SET (0b11) + Bit 2: 1=Set OFF behavior according to bits 0,1 0=Don't change + Bits 3,4: One of NOP (0), CLEAR (0b10), or SET (0b11) + Bit 5: 1=Set RX behavior according to bits 0,1 0=Don't change + Bits 6,7: One of NOP (0), CLEAR (0b10), or SET (0b11) + Bit 8: 1=Set TX behavior according to bits 0,1 0=Don't change + Bits 9-15: Ignored; set to 0 +*/ +void user_config_set_bias_t_opts(uint16_t value) +{ + if (value & 0x4) { + user_config_set_bias_t_opt(RF_PATH_DIRECTION_OFF, value & 0x3); + } + if (value & 0x20) { + user_config_set_bias_t_opt(RF_PATH_DIRECTION_RX, (value & 0x18) >> 3); + } + if (value & 0x100) { + user_config_set_bias_t_opt(RF_PATH_DIRECTION_TX, (value & 0xC0) >> 6); + } +} diff --git a/firmware/common/leds.h b/firmware/common/user_config.h similarity index 54% rename from firmware/common/leds.h rename to firmware/common/user_config.h index a552dca6..114ba0f3 100644 --- a/firmware/common/leds.h +++ b/firmware/common/user_config.h @@ -1,5 +1,5 @@ /* - * Copyright 2026 Great Scott Gadgets + * Copyright 2023 Jonathan Suite (GitHub: @ai6aj) * * This file is part of HackRF. * @@ -19,28 +19,25 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __USER_CONFIG_H__ +#define __USER_CONFIG_H__ -#ifdef __cplusplus -extern "C" { -#endif - -#include +#include "rf_path.h" typedef enum { - LED1 = 0, - LED2 = 1, - LED3 = 2, - LED4 = 3, -} led_t; + RF_DIRECTION_USER_OPT_NOP, // No OPeration / Ignore the thing + RF_DIRECTION_USER_OPT_RESERVED, // Currently a NOP + RF_DIRECTION_USER_OPT_CLEAR, // Clear/Disable the thing + RF_DIRECTION_USER_OPT_SET, // Set/Enable the thing +} user_config_user_opt_t; -void led_on(const led_t led); -void led_off(const led_t led); -void led_toggle(const led_t led); -void set_leds(const uint8_t state); +void user_config_set_bias_t_opt( + const rf_path_direction_t direction, + const user_config_user_opt_t action); +void user_config_set_bias_t_opts(uint16_t value); -void halt_and_flash(const uint32_t duration); +void user_config_on_rf_path_direction_change( + rf_path_t* const rf_path, + const rf_path_direction_t direction); -#ifdef __cplusplus -} -#endif +#endif \ No newline at end of file diff --git a/firmware/common/w25q80bv.c b/firmware/common/w25q80bv.c index abd18624..fe09a2e8 100644 --- a/firmware/common/w25q80bv.c +++ b/firmware/common/w25q80bv.c @@ -27,16 +27,10 @@ * programming the flash. */ -#include "w25q80bv.h" - #include #include -#include - -#include "platform_detect.h" -#include "platform_gpio.h" -#include "w25q80bv_target.h" +#include "w25q80bv.h" #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) @@ -56,34 +50,6 @@ #define W25Q80BV_DEVICE_ID_RES 0x13 /* Expected device_id for W25Q80BV */ -/* Driver instance. */ -ssp_config_t ssp_config_w25q80bv = { - .data_bits = SSP_DATA_8BITS, - .serial_clock_rate = 2, - .clock_prescale_rate = 2, -}; - -w25q80bv_driver_t spi_flash = { - .bus = &spi_bus_ssp0, - .target_init = w25q80bv_target_init, -}; - -static void w25q80bv_transfer( - w25q80bv_driver_t* const drv, - void* const data, - const size_t count) -{ - spi_bus_transfer(drv->bus, &ssp_config_w25q80bv, data, count); -} - -static void w25q80bv_transfer_gather( - w25q80bv_driver_t* const drv, - const spi_transfer_t* const transfers, - size_t size) -{ - spi_bus_transfer_gather(drv->bus, &ssp_config_w25q80bv, transfers, size); -} - /* * Set up pins for GPIO and SPI control, configure SSP0 peripheral for SPI. * SSP0_CS is controlled by GPIO in order to handle various transfer lengths. @@ -91,20 +57,10 @@ static void w25q80bv_transfer_gather( void w25q80bv_setup(w25q80bv_driver_t* const drv) { uint8_t device_id; - const platform_gpio_t* gpio = platform_gpio(); - - ssp_config_w25q80bv.gpio_select = gpio->w25q80bv_select; - spi_flash.gpio_hold = gpio->w25q80bv_hold; - spi_flash.gpio_wp = gpio->w25q80bv_wp; drv->page_len = 256U; - if (detected_platform() == BOARD_ID_PRALINE) { - drv->num_pages = 16384U; - drv->num_bytes = 4194304U; - } else { - drv->num_pages = 4096U; - drv->num_bytes = 1048576U; - } + drv->num_pages = 4096U; + drv->num_bytes = 1048576U; drv->target_init(drv); @@ -118,7 +74,7 @@ void w25q80bv_setup(w25q80bv_driver_t* const drv) uint8_t w25q80bv_get_status(w25q80bv_driver_t* const drv) { uint8_t data[] = {W25Q80BV_READ_STATUS1, 0xFF}; - w25q80bv_transfer(drv, data, ARRAY_SIZE(data)); + spi_bus_transfer(drv->bus, data, ARRAY_SIZE(data)); return data[1]; } @@ -126,7 +82,7 @@ uint8_t w25q80bv_get_status(w25q80bv_driver_t* const drv) uint8_t w25q80bv_get_device_id(w25q80bv_driver_t* const drv) { uint8_t data[] = {W25Q80BV_DEVICE_ID, 0xFF, 0xFF, 0xFF, 0xFF}; - w25q80bv_transfer(drv, data, ARRAY_SIZE(data)); + spi_bus_transfer(drv->bus, data, ARRAY_SIZE(data)); return data[4]; } @@ -146,7 +102,7 @@ void w25q80bv_get_unique_id(w25q80bv_driver_t* const drv, w25q80bv_unique_id_t* 0xFF, 0xFF, 0xFF}; - w25q80bv_transfer(drv, data, ARRAY_SIZE(data)); + spi_bus_transfer(drv->bus, data, ARRAY_SIZE(data)); for (size_t i = 0; i < 8; i++) { unique_id->id_8b[i] = data[5 + i]; @@ -163,7 +119,7 @@ void w25q80bv_write_enable(w25q80bv_driver_t* const drv) w25q80bv_wait_while_busy(drv); uint8_t data[] = {W25Q80BV_WRITE_ENABLE}; - w25q80bv_transfer(drv, data, ARRAY_SIZE(data)); + spi_bus_transfer(drv->bus, data, ARRAY_SIZE(data)); while (!(w25q80bv_get_status(drv) & W25Q80BV_STATUS_WEL)) {} } @@ -181,7 +137,7 @@ void w25q80bv_chip_erase(w25q80bv_driver_t* const drv) w25q80bv_write_enable(drv); uint8_t data[] = {W25Q80BV_CHIP_ERASE}; - w25q80bv_transfer(drv, data, ARRAY_SIZE(data)); + spi_bus_transfer(drv->bus, data, ARRAY_SIZE(data)); } /* write up a 256 byte page or partial page */ @@ -212,7 +168,7 @@ static void w25q80bv_page_program( const spi_transfer_t transfers[] = {{header, ARRAY_SIZE(header)}, {data, len}}; - w25q80bv_transfer_gather(drv, transfers, ARRAY_SIZE(transfers)); + spi_bus_transfer_gather(drv->bus, transfers, ARRAY_SIZE(transfers)); } /* write an arbitrary number of bytes */ @@ -287,7 +243,7 @@ void w25q80bv_read( const spi_transfer_t transfers[] = {{header, ARRAY_SIZE(header)}, {data, len}}; - w25q80bv_transfer_gather(drv, transfers, ARRAY_SIZE(transfers)); + spi_bus_transfer_gather(drv->bus, transfers, ARRAY_SIZE(transfers)); } void w25q80bv_clear_status(w25q80bv_driver_t* const drv) @@ -295,16 +251,16 @@ void w25q80bv_clear_status(w25q80bv_driver_t* const drv) w25q80bv_wait_while_busy(drv); w25q80bv_write_enable(drv); uint8_t data[] = {W25Q80BV_WRITE_STATUS, 0x00, 0x00}; - w25q80bv_transfer(drv, data, ARRAY_SIZE(data)); + spi_bus_transfer(drv->bus, data, ARRAY_SIZE(data)); } void w25q80bv_get_full_status(w25q80bv_driver_t* const drv, uint8_t* data) { uint8_t cmd[] = {W25Q80BV_READ_STATUS1, 0xFF}; - w25q80bv_transfer(drv, cmd, ARRAY_SIZE(cmd)); + spi_bus_transfer(drv->bus, cmd, ARRAY_SIZE(cmd)); data[0] = cmd[1]; cmd[0] = W25Q80BV_READ_STATUS2; cmd[1] = 0xFF; - w25q80bv_transfer(drv, cmd, ARRAY_SIZE(cmd)); + spi_bus_transfer(drv->bus, cmd, ARRAY_SIZE(cmd)); data[1] = cmd[1]; } diff --git a/firmware/common/w25q80bv.h b/firmware/common/w25q80bv.h index 21d0814b..55fefaad 100644 --- a/firmware/common/w25q80bv.h +++ b/firmware/common/w25q80bv.h @@ -21,18 +21,17 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __W25Q80BV_H__ +#define __W25Q80BV_H__ -#include #include - -#include "gpio.h" -#include "spi_bus.h" -#include "spi_ssp.h" +#include #define W25Q80BV_DEVICE_ID_RES 0x13 /* Expected device_id for W25Q80BV */ #define W25Q16DV_DEVICE_ID_RES 0x14 /* Expected device_id for W25Q16DV */ #define W25Q32JV_DEVICE_ID_RES 0x15 /* Expected device_id for W25Q32JV */ +#include "spi_bus.h" +#include "gpio.h" typedef union { uint64_t id_64b; @@ -40,15 +39,18 @@ typedef union { uint8_t id_8b[8]; /* 8*8bits 64bits Unique ID */ } w25q80bv_unique_id_t; -typedef struct _w25q80bv_driver_t { +struct w25q80bv_driver_t; +typedef struct w25q80bv_driver_t w25q80bv_driver_t; + +struct w25q80bv_driver_t { spi_bus_t* bus; gpio_t gpio_hold; gpio_t gpio_wp; - void (*target_init)(struct _w25q80bv_driver_t* const drv); + void (*target_init)(w25q80bv_driver_t* const drv); size_t page_len; size_t num_pages; size_t num_bytes; -} w25q80bv_driver_t; +}; void w25q80bv_setup(w25q80bv_driver_t* const drv); void w25q80bv_get_full_status(w25q80bv_driver_t* const drv, uint8_t* data); @@ -67,6 +69,4 @@ void w25q80bv_read( uint8_t* const data); void w25q80bv_clear_status(w25q80bv_driver_t* const drv); -/* Driver instance. */ -extern ssp_config_t ssp_config_w25q80bv; -extern w25q80bv_driver_t spi_flash; +#endif //__W25Q80BV_H__ diff --git a/firmware/common/w25q80bv_target.c b/firmware/common/w25q80bv_target.c index 40fd4fbb..a83f5d98 100644 --- a/firmware/common/w25q80bv_target.c +++ b/firmware/common/w25q80bv_target.c @@ -23,9 +23,7 @@ #include "w25q80bv_target.h" #include - -#include "gpio.h" -#include "platform_scu.h" +#include "hackrf_core.h" /* TODO: Why is CS being controlled manually when SSP0 could do it * automatically? @@ -37,8 +35,6 @@ void w25q80bv_target_init(w25q80bv_driver_t* const drv) /* Init SPIFI GPIO to Normal GPIO */ - const platform_scu_t* scu = platform_scu(); - // P3_3 SPIFI_SCK => SSP0_SCK scu_pinmux(P3_3, (SCU_SSP_IO | SCU_CONF_FUNCTION2)); // P3_4 SPIFI SPIFI_SIO3 IO3 => GPIO1[14] @@ -53,14 +49,14 @@ void w25q80bv_target_init(w25q80bv_driver_t* const drv) scu_pinmux(P3_8, (SCU_GPIO_FAST | SCU_CONF_FUNCTION4)); /* configure SSP pins */ - scu_pinmux(scu->SSP0_CIPO, (SCU_SSP_IO | SCU_CONF_FUNCTION5)); - scu_pinmux(scu->SSP0_COPI, (SCU_SSP_IO | SCU_CONF_FUNCTION5)); - scu_pinmux(scu->SSP0_SCK, (SCU_SSP_IO | SCU_CONF_FUNCTION2)); + scu_pinmux(SCU_SSP0_CIPO, (SCU_SSP_IO | SCU_CONF_FUNCTION5)); + scu_pinmux(SCU_SSP0_COPI, (SCU_SSP_IO | SCU_CONF_FUNCTION5)); + scu_pinmux(SCU_SSP0_SCK, (SCU_SSP_IO | SCU_CONF_FUNCTION2)); /* configure GPIO pins */ - scu_pinmux(scu->FLASH_HOLD, SCU_GPIO_FAST); - scu_pinmux(scu->FLASH_WP, SCU_GPIO_FAST); - scu_pinmux(scu->SSP0_CS, (SCU_GPIO_FAST | SCU_CONF_FUNCTION4)); + scu_pinmux(SCU_FLASH_HOLD, SCU_GPIO_FAST); + scu_pinmux(SCU_FLASH_WP, SCU_GPIO_FAST); + scu_pinmux(SCU_SSP0_CS, (SCU_GPIO_FAST | SCU_CONF_FUNCTION4)); /* drive CS, HOLD, and WP pins high */ gpio_set(drv->gpio_hold); diff --git a/firmware/common/w25q80bv_target.h b/firmware/common/w25q80bv_target.h index 8da28d25..2fad7aa3 100644 --- a/firmware/common/w25q80bv_target.h +++ b/firmware/common/w25q80bv_target.h @@ -20,8 +20,11 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __W25Q80BV_TARGET_H__ +#define __W25Q80BV_TARGET_H__ #include "w25q80bv.h" void w25q80bv_target_init(w25q80bv_driver_t* const drv); + +#endif /*__W25Q80BV_TARGET_H__*/ diff --git a/firmware/common/xapp058/ports.c b/firmware/common/xapp058/ports.c index 16b4b03d..336c83cf 100644 --- a/firmware/common/xapp058/ports.c +++ b/firmware/common/xapp058/ports.c @@ -9,12 +9,11 @@ /* Updated comments to clarify instructions.*/ /* Add print in setPort for xapp058_example.exe.*/ /*******************************************************/ - #include "ports.h" -#include - +#include "hackrf_core.h" #include "cpld_jtag.h" + #include "gpio.h" void delay_jtag(uint32_t duration) diff --git a/firmware/fpga/board.py b/firmware/fpga/board.py index a52045cd..d5c22361 100644 --- a/firmware/fpga/board.py +++ b/firmware/fpga/board.py @@ -5,7 +5,7 @@ # Copyright (c) 2024 Great Scott Gadgets # SPDX-License-Identifier: BSD-3-Clause -from amaranth import Elaboratable, Signal, Const, Instance, Module, ClockDomain +from amaranth import Elaboratable, Signal, Instance, Module, ClockDomain from amaranth.build import Resource, Pins, Clock, Attrs from amaranth.vendor import LatticeICE40Platform from amaranth_boards.resources import SPIResource @@ -21,8 +21,8 @@ class PralinePlatform(LatticeICE40Platform): hfosc_div = 0 # Do not divide resources = [ - Resource("fpga_clk", 0, Pins("47", dir="i"), - Attrs(IO_STANDARD="SB_LVCMOS")), + Resource("fpga_clk", 0, Pins("39", dir="i"), + Attrs(GLOBAL=True, IO_STANDARD="SB_LVCMOS")), # ADC/DAC interfaces. Resource("afe_clk", 0, Pins("35", dir="i"), @@ -65,23 +65,15 @@ class PralinePlatform(LatticeICE40Platform): class ClockDomainGenerator(Elaboratable): @staticmethod - def lut_delay(m, signal, *, depth, invert=False, bel=None): - # Each LUT introduces a minimum propagation delay of 9ns (best case). + def lut_delay(m, signal, *, depth): signal_out = signal for i in range(depth): signal_in = signal_out - signal_out = Signal(attrs={"keep": True}) # avoid LUT optimization - other_opts = {} - if bel is not None: - other_opts["a_BEL"] = f"{bel}/lc{i}" + signal_out = Signal() m.submodules += Instance("SB_LUT4", - p_LUT_INIT=Const(0b01 if invert else 0b10, 16), + p_LUT_INIT=0xAAAA, # Buffer configuration i_I0=signal_in, - i_I1=Const(0), - i_I2=Const(0), - i_I3=Const(0), o_O=signal_out, - **other_opts, ) return signal_out @@ -89,17 +81,12 @@ class ClockDomainGenerator(Elaboratable): m = Module() # Define clock domains. - m.domains.adclk = cd_adclk = ClockDomain(name="adclk", reset_less=True) - m.domains.daclk = cd_daclk = ClockDomain(name="daclk", reset_less=True) + m.domains.gck1 = cd_gck1 = ClockDomain(name="gck1", reset_less=True) # analog front-end clock. - adclk_ref = platform.request("afe_clk").i - fpgaclk_ref = platform.request("fpga_clk").i - - delayed_adclk = self.lut_delay(m, adclk_ref, depth=1, bel="X12/Y30") # delay `afe_clk` clock by at least 8ns - m.d.comb += cd_adclk.clk.eq(delayed_adclk) - platform.add_clock_constraint(delayed_adclk, 40e6) - - m.d.comb += cd_daclk.clk.eq(fpgaclk_ref) - platform.add_clock_constraint(cd_daclk.clk, 40e6) + # We need to delay `gck1` clock by at least 8ns, not possible with the PLL alone. + # Each LUT introduces a minimum propagation delay of 9ns (best case). + delayed_gck1 = self.lut_delay(m, platform.request("afe_clk").i, depth=2) + m.d.comb += cd_gck1.clk.eq(delayed_gck1) + platform.add_clock_constraint(delayed_gck1, 40e6) return m diff --git a/firmware/fpga/build/praline_fpga.bin b/firmware/fpga/build/praline_fpga.bin index 64dd9b4b..460d2552 100644 Binary files a/firmware/fpga/build/praline_fpga.bin and b/firmware/fpga/build/praline_fpga.bin differ diff --git a/firmware/fpga/dsp/cic.py b/firmware/fpga/dsp/cic.py index 99f5376a..fa0f3fa0 100644 --- a/firmware/fpga/dsp/cic.py +++ b/firmware/fpga/dsp/cic.py @@ -240,7 +240,6 @@ class ProgrammableShift(wiring.Component): # Implement the map itself (should it be done outside?) max_shift = max(self.shift_map.values()) - min_shift = min(self.shift_map.values()) value_scaled = [ Signal(signed(self.width_in + max_shift)) for _ in range(self.num_channels) ] scaled_valid = Signal() @@ -256,9 +255,7 @@ class ProgrammableShift(wiring.Component): for k, v in self.shift_map.items(): with m.Case(k): m.d.sync += value_scaled[c].eq(self.input.payload[c] << (max_shift - v)) - with m.Default(): - m.d.sync += value_scaled[c].eq(self.input.payload[c] << (max_shift - min_shift)) - + with m.If(~self.output.valid | self.output.ready): m.d.comb += scaled_ready.eq(1) m.d.sync += self.output.valid.eq(scaled_valid) diff --git a/firmware/fpga/dsp/fir_mac16.py b/firmware/fpga/dsp/fir_mac16.py index 57da9605..84c59a89 100644 --- a/firmware/fpga/dsp/fir_mac16.py +++ b/firmware/fpga/dsp/fir_mac16.py @@ -464,23 +464,18 @@ class SerialMAC16(wiring.Component): class iCE40Multiplier(wiring.Component): def __init__(self, a_width=16, b_width=16, p_width=32, o_width=32, always_ready=False): - signature = { + super().__init__({ "a": In(signed(a_width)), "b": In(signed(b_width)), "valid_in": In(1), - "ready_in": Out(1), + "ready_in": In(1), + "p": In(signed(p_width)), + "p_load": In(1), "o": Out(signed(o_width)), "valid_out": Out(1), "ready_out": In(1), - } - if p_width > 0: - signature.update({ - "p": In(signed(p_width)), - "p_load": In(1), - }) - super().__init__(signature) + }) self.always_ready = always_ready - self.p_width = p_width self.o_width = o_width def elaborate(self, platform): @@ -492,17 +487,15 @@ class iCE40Multiplier(wiring.Component): m.d.sync += pipe[i+1].eq(pipe[i]) return pipe + p_load_v = Signal() valid_v = Signal() m.d.comb += valid_v.eq(self.valid_in & self.ready_in) dsp_delay = 3 valid_pipe = pipe(valid_v, dsp_delay) - - if self.p_width > 0: - p_load_v = Signal() - m.d.comb += p_load_v.eq(self.p_load & valid_v) - p_pipe = pipe(self.p, dsp_delay-1) - p_load_pipe = pipe(p_load_v, dsp_delay - 1) + m.d.comb += p_load_v.eq(self.p_load & valid_v) + p_pipe = pipe(self.p, dsp_delay-1) + p_load_pipe = pipe(p_load_v, dsp_delay - 1) # skid buffer if not self.always_ready: @@ -536,10 +529,10 @@ class iCE40Multiplier(wiring.Component): # Inputs. mac.CLK .eq(ClockSignal("sync")), mac.CE .eq(1), - mac.C.as_signed().eq(Mux(p_load_pipe[2], p_pipe[2][16:], mac.O[16:]) if self.p_width > 0 else 0), + mac.C.as_signed().eq(Mux(p_load_pipe[2], p_pipe[2][16:], mac.O[16:])), mac.A.as_signed().eq(self.a), mac.B.as_signed().eq(self.b), - mac.D.as_signed().eq(Mux(p_load_pipe[2], p_pipe[2][:16], mac.O[:16]) if self.p_width > 0 else 0), + mac.D.as_signed().eq(Mux(p_load_pipe[2], p_pipe[2][:16], mac.O[:16])), mac.AHOLD .eq(~valid_pipe[0]), # 0: load mac.BHOLD .eq(~valid_pipe[0]), mac.CHOLD .eq(0), diff --git a/firmware/fpga/dsp/mcm.py b/firmware/fpga/dsp/mcm.py index 820dfe4b..ce9bd978 100644 --- a/firmware/fpga/dsp/mcm.py +++ b/firmware/fpga/dsp/mcm.py @@ -24,7 +24,7 @@ class ShiftAddMCM(wiring.Component): "output": Out(stream.Signature( data.ArrayLayout( data.StructLayout({ - f"{i}": signed(width + bits_for(abs(term))) for i, term in enumerate(terms) + f"{i}": signed(width + bits_for(term)) for i, term in enumerate(terms) }), num_channels), always_ready=always_ready)), }) @@ -71,7 +71,7 @@ class ShiftAddMCM(wiring.Component): result += shifted_n # A single register can feed multiple outputs. - result_q = Signal(signed(self.width+bits_for(abs(term))), name=f"mul_{term}_{c}") + result_q = Signal(signed(self.width+bits_for(term-1)), name=f"mul_{term}_{c}") with m.If(self.input.ready & self.input.valid): m.d.sync += result_q.eq(result) diff --git a/firmware/fpga/dsp/mixer.py b/firmware/fpga/dsp/mixer.py deleted file mode 100644 index e5e599ae..00000000 --- a/firmware/fpga/dsp/mixer.py +++ /dev/null @@ -1,80 +0,0 @@ -# -# This file is part of HackRF. -# -# Copyright (c) 2025 Great Scott Gadgets -# SPDX-License-Identifier: BSD-3-Clause - -from amaranth import Module -from amaranth.lib import wiring, stream -from amaranth.lib.wiring import In, Out - -from dsp.fir_mac16 import iCE40Multiplier -from dsp.round import convergent_round - -from util import IQSample - - -class ComplexMultiplier(wiring.Component): - - def __init__(self, a_shape, b_shape, c_shape, always_ready=False): - super().__init__({ - "a": In(stream.Signature(a_shape, always_ready=always_ready)), - "b": In(stream.Signature(b_shape, always_ready=always_ready)), - "c": Out(stream.Signature(c_shape, always_ready=always_ready)), - }) - self.always_ready = always_ready - - def elaborate(self, platform): - m = Module() - - A = self.a.p.i - B = self.a.p.q - C = self.b.p.i - D = self.b.p.q - - a_width = A.shape().width - b_width = B.shape().width - c_width = C.shape().width - d_width = D.shape().width - - o_shape = (A * C).shape() - o_width = o_shape.width - - m.submodules.dsp1 = dsp1 = iCE40Multiplier(a_width=a_width, b_width=c_width, p_width=0, o_width=o_width, always_ready=self.always_ready) - m.submodules.dsp2 = dsp2 = iCE40Multiplier(a_width=a_width, b_width=d_width, p_width=0, o_width=o_width, always_ready=self.always_ready) - m.submodules.dsp3 = dsp3 = iCE40Multiplier(a_width=b_width, b_width=d_width, p_width=0, o_width=o_width, always_ready=self.always_ready) - m.submodules.dsp4 = dsp4 = iCE40Multiplier(a_width=b_width, b_width=c_width, p_width=0, o_width=o_width, always_ready=self.always_ready) - - valid_in = self.a.valid & self.b.valid - m.d.comb += [ - dsp1.a.eq(A), - dsp1.b.eq(C), - dsp1.valid_in.eq(valid_in), - dsp2.a.eq(A), - dsp2.b.eq(D), - dsp2.valid_in.eq(valid_in), - dsp3.a.eq(B), - dsp3.b.eq(D), - dsp3.valid_in.eq(valid_in), - dsp4.a.eq(B), - dsp4.b.eq(C), - dsp4.valid_in.eq(valid_in), - ] - - ready_in = dsp1.ready_in - if not self.always_ready: - m.d.comb += self.a.ready.eq(ready_in) - m.d.comb += self.b.ready.eq(ready_in) - - with m.If(~self.c.valid | self.c.ready): - m.d.sync += self.c.valid.eq(dsp1.valid_out) - with m.If(dsp1.valid_out): - m.d.sync += self.c.p.i.eq(convergent_round(dsp1.o - dsp3.o, o_width - self.c.p.i.shape().width - 1)) - m.d.sync += self.c.p.q.eq(convergent_round(dsp2.o + dsp4.o, o_width - self.c.p.q.shape().width - 1)) - m.d.comb += dsp1.ready_out.eq(1) - m.d.comb += dsp2.ready_out.eq(1) - m.d.comb += dsp3.ready_out.eq(1) - m.d.comb += dsp4.ready_out.eq(1) - - return m - diff --git a/firmware/fpga/dsp/nco.py b/firmware/fpga/dsp/nco.py index 38bae44b..e464399a 100755 --- a/firmware/fpga/dsp/nco.py +++ b/firmware/fpga/dsp/nco.py @@ -6,7 +6,7 @@ from math import pi, sin, cos -from amaranth import Module, Signal, DomainRenamer, Mux, Cat +from amaranth import Module, Signal, Mux, Cat from amaranth.lib import wiring, memory from amaranth.lib.wiring import In, Out @@ -38,10 +38,9 @@ class NCO(wiring.Component): Returned result for cos(phase), sin(phase). """ - def __init__(self, phase_width=24, output_width=10, domain="sync"): + def __init__(self, phase_width=24, output_width=10): self.phase_width = phase_width self.output_width = output_width - self._domain = domain super().__init__({ "phase": In(phase_width), "en": In(1), @@ -55,14 +54,14 @@ class NCO(wiring.Component): addr_width = (self.output_width + 1) - 3 lut_depth = 1 << addr_width lut_scale = (1 << (self.output_width-1)) - 1 - lut_phases = [ (n * pi / 4 + .5) / lut_depth for n in range(lut_depth) ] + lut_phases = [ i * pi / 4 / lut_depth for i in range(lut_depth) ] lut_data = memory.MemoryData( shape=IQSample(self.output_width), depth=lut_depth, init=({"i": round(lut_scale * cos(x)), "q": round(lut_scale * sin(x))} for x in lut_phases) ) m.submodules.table = table = memory.Memory(data=lut_data) - table_rd = table.read_port(domain=self._domain) + table_rd = table.read_port(domain="sync") # 3 MSBs of the phase word: sign, quadrant, octant. o, q, s = self.phase[-3:] @@ -100,8 +99,5 @@ class NCO(wiring.Component): e_s2.q .eq(Mux(neg_sin, -e_s1.q, e_s1.q)), ] m.d.sync += self.output.eq(e_s2) - - if self._domain != "sync": - m = DomainRenamer(self._domain)(m) return m diff --git a/firmware/fpga/interface/max586x.py b/firmware/fpga/interface/max586x.py index 8ffe1a5e..60ffade9 100644 --- a/firmware/fpga/interface/max586x.py +++ b/firmware/fpga/interface/max586x.py @@ -3,7 +3,7 @@ # Copyright (c) 2025 Great Scott Gadgets # SPDX-License-Identifier: BSD-3-Clause -from amaranth import Module, Signal, C, Cat, Mux +from amaranth import Module, Signal, C, Cat from amaranth.lib import io, stream, wiring from amaranth.lib.wiring import Out, In @@ -15,10 +15,9 @@ class MAX586xInterface(wiring.Component): dac_stream: In(stream.Signature(IQSample(8), always_ready=True)) q_invert: In(1) - def __init__(self, adc_domain, dac_domain): + def __init__(self, bb_domain): super().__init__() - self._adc_domain = adc_domain - self._dac_domain = dac_domain + self._bb_domain = bb_domain def elaborate(self, platform): m = Module() @@ -26,27 +25,30 @@ class MAX586xInterface(wiring.Component): dac_stream = self.dac_stream # Generate masks for inverting the Q component based on the q_invert signal. - q_invert_rx = Signal() - q_invert_tx = Signal() + q_invert = Signal() rx_q_mask = Signal(8) tx_q_mask = Signal(10) - m.d[self._adc_domain] += q_invert_rx.eq(self.q_invert) - m.d[self._dac_domain] += q_invert_tx.eq(self.q_invert) - - m.d.comb += [ - rx_q_mask.eq(Mux(q_invert_rx, 0x80, 0x7F)), - tx_q_mask.eq(Mux(q_invert_tx, 0x1FF, 0x200)), - ] + m.d[self._bb_domain] += q_invert.eq(self.q_invert) + with m.If(q_invert): + m.d.comb += [ + rx_q_mask.eq(0x80), + tx_q_mask.eq(0x1FF), + ] + with m.Else(): + m.d.comb += [ + rx_q_mask.eq(0x7F), + tx_q_mask.eq(0x200), + ] # Capture the ADC signals using a DDR input buffer. - m.submodules.adc_in = adc_in = io.DDRBuffer("i", platform.request("da", dir="-"), i_domain=self._adc_domain) + m.submodules.adc_in = adc_in = io.DDRBuffer("i", platform.request("da", dir="-"), i_domain=self._bb_domain) m.d.comb += [ adc_stream.p.i .eq(adc_in.i[0] ^ 0x80), # I: non-inverted between MAX2837 and MAX5864. adc_stream.p.q .eq(adc_in.i[1] ^ rx_q_mask), # Q: inverted between MAX2837 and MAX5864. ] # Output to the DAC using a DDR output buffer. - m.submodules.dac_out = dac_out = io.DDRBuffer("o", platform.request("dd", dir="-"), o_domain=self._dac_domain) + m.submodules.dac_out = dac_out = io.DDRBuffer("o", platform.request("dd", dir="-"), o_domain=self._bb_domain) with m.If(dac_stream.valid): m.d.comb += [ dac_out.o[0] .eq(Cat(C(0, 2), dac_stream.p.i) ^ 0x200), diff --git a/firmware/fpga/top/ext_precision_rx.py b/firmware/fpga/top/ext_precision_rx.py index 3d486519..3950458e 100644 --- a/firmware/fpga/top/ext_precision_rx.py +++ b/firmware/fpga/top/ext_precision_rx.py @@ -4,8 +4,7 @@ # Copyright (c) 2025 Great Scott Gadgets # SPDX-License-Identifier: BSD-3-Clause -from amaranth import Elaboratable, Module, Cat, DomainRenamer, Signal, Mux -from amaranth.lib import cdc +from amaranth import Elaboratable, Module, Cat, DomainRenamer from amaranth.lib.wiring import connect from amaranth_future import fixed @@ -16,9 +15,7 @@ from dsp.fir import FIRFilter from dsp.fir_mac16 import HalfBandDecimatorMAC16 from dsp.cic import CICDecimator from dsp.dc_block import DCBlock -from dsp.nco import NCO -from dsp.mixer import ComplexMultiplier - +from dsp.quarter_shift import QuarterShift from util import ClockConverter, IQSample @@ -28,24 +25,22 @@ class Top(Elaboratable): m = Module() m.submodules.clkgen = ClockDomainGenerator() - adc_clk = "adclk" - dac_clk = "daclk" # Submodules. - m.submodules.adcdac_intf = adcdac_intf = MAX586xInterface(adc_domain=adc_clk, dac_domain=dac_clk) + m.submodules.adcdac_intf = adcdac_intf = MAX586xInterface(bb_domain="gck1") m.submodules.mcu_intf = mcu_intf = SGPIOInterface( sample_width=24, rx_assignments=[ - lambda w: w[0:8], lambda w: Cat(w[8:12], w[11].replicate(4)), - lambda w: w[12:20], + lambda w: w[0:8], lambda w: Cat(w[20:24], w[23].replicate(4)), + lambda w: w[12:20], ], tx_assignments=[ - lambda w, v: w[0:8].eq(v), lambda w, v: w[8:12].eq(v), - lambda w, v: w[12:20].eq(v), + lambda w, v: w[0:8].eq(v), lambda w, v: w[20:24].eq(v), + lambda w, v: w[12:20].eq(v), ], domain="sync" ) @@ -59,32 +54,21 @@ class Top(Elaboratable): taps_hb2 = [ -6, 0, 19, 0, -44, 0, 89, 0, -163, 0, 278, 0, -452, 0, 711, 0, -1113, 0, 1800, 0, -3298, 0, 10370, 16384, 10370, 0, -3298, 0, 1800, 0, -1113, 0, 711, 0, -452, 0, 278, 0, -163, 0, 89, 0, -44, 0, 19, 0, -6] taps_hb2 = [ tap/16384/2 for tap in taps_hb2 ] - # NCO and mixer. - m.submodules.nco = nco = NCO(phase_width=16, output_width=10, domain=adc_clk) - mixer = DomainRenamer(adc_clk)(ComplexMultiplier(IQSample(8), IQSample(10), IQSample(8), always_ready=True)) - mixer.input = mixer.a - mixer.output = mixer.c - m.d.comb += [ - mixer.b.p.eq(nco.output), - mixer.b.valid.eq(1), - nco.en.eq(1), - ] - rx_chain = { - # DC block and mixer. - "dc_block": DCBlock(width=8, num_channels=2, domain=adc_clk), - "mixer": mixer, + # DC block and quarter shift. + "dc_block": DCBlock(width=8, num_channels=2, domain="gck1"), + "quarter_shift": DomainRenamer("gck1")(QuarterShift()), # CIC mandatory first stage with compensator. - "cic": CICDecimator(2, 4, (4,8,16,32), width_in=8, width_out=12, num_channels=2, always_ready=True, domain=adc_clk), - "cic_comp": DomainRenamer(adc_clk)(FIRFilter([-0.125, 0, 0.75, 0, -0.125], shape=fixed.SQ(11), shape_out=fixed.SQ(11), always_ready=True, num_channels=2)), + "cic": CICDecimator(2, 4, (4,8,16,32), width_in=8, width_out=12, num_channels=2, always_ready=True, domain="gck1"), + "cic_comp": DomainRenamer("gck1")(FIRFilter([-0.125, 0, 0.75, 0, -0.125], shape=fixed.SQ(11), shape_out=fixed.SQ(11), always_ready=True, num_channels=2)), # Final half-band decimator stages. - "hbfir1": HalfBandDecimatorMAC16(taps_hb1, data_shape=fixed.SQ(11), overclock_rate=4, always_ready=True, domain=adc_clk), - "hbfir2": HalfBandDecimatorMAC16(taps_hb2, data_shape=fixed.SQ(11), overclock_rate=8, always_ready=True, domain=adc_clk), + "hbfir1": HalfBandDecimatorMAC16(taps_hb1, data_shape=fixed.SQ(11), overclock_rate=4, always_ready=True, domain="gck1"), + "hbfir2": HalfBandDecimatorMAC16(taps_hb2, data_shape=fixed.SQ(11), overclock_rate=8, always_ready=True, domain="gck1"), # Clock domain conversion. - "clkconv": ClockConverter(IQSample(12), 8, adc_clk, "sync", always_ready=True), + "clkconv": ClockConverter(IQSample(12), 8, "gck1", "sync", always_ready=True), } for k,v in rx_chain.items(): m.submodules[f"rx_{k}"] = v @@ -101,37 +85,22 @@ class Top(Elaboratable): m.submodules.spi_regs = spi_regs = SPIRegisterInterface(spi_port) # Add control registers. - ctrl = spi_regs.add_register(0x01, init=0) - rx_decim = Signal(3, init=4) - rx_decim_new = Signal(3) - rx_decim_stb = Signal() - rx_decim_cic = Signal.like(rx_chain["cic"].factor) - spi_regs.add_sfr(0x02, read=rx_decim, write_signal=rx_decim_new, write_strobe=rx_decim_stb) - rx_nco = spi_regs.add_register(0x03, init=0) + ctrl = spi_regs.add_register(0x01, init=0) + rx_decim = spi_regs.add_register(0x02, init=0, size=3) + #tx_intrp = spi_regs.add_register(0x04, init=0, size=3) m.d.comb += [ # Trigger enable. mcu_intf.trigger_en .eq(ctrl[7]), + + # RX settings. + rx_chain["dc_block"].enable .eq(ctrl[0]), + rx_chain["quarter_shift"].enable .eq(ctrl[1]), + rx_chain["quarter_shift"].up .eq(ctrl[2]), + + # RX decimation rate. + rx_chain["cic"].factor .eq(rx_decim+2), ] - - # RX DC block. - m.submodules.dc_block_cdc = cdc.FFSynchronizer(ctrl[0], rx_chain["dc_block"].enable, o_domain=adc_clk) - - # RX decimation rate. - m.submodules.rx_decim_cdc = cdc.FFSynchronizer(rx_decim_cic, rx_chain["cic"].factor, o_domain=adc_clk) - - with m.If(rx_decim_stb): - with m.If(rx_decim_new < 4): - m.d.sync += rx_decim.eq(4) - m.d.sync += rx_decim_cic.eq(2) - with m.Else(): - m.d.sync += rx_decim.eq(rx_decim_new) - m.d.sync += rx_decim_cic.eq(rx_decim_new-2) - - # NCO control. - rx_nco_ad = Signal(8) - m.submodules.nco_phase_cdc = cdc.FFSynchronizer(rx_nco, rx_nco_ad, o_domain=adc_clk) - m.d[adc_clk] += nco.phase.eq(nco.phase - (rx_nco_ad << 8)) return m diff --git a/firmware/fpga/top/ext_precision_tx.py b/firmware/fpga/top/ext_precision_tx.py index 949a8ce5..6b55acc4 100644 --- a/firmware/fpga/top/ext_precision_tx.py +++ b/firmware/fpga/top/ext_precision_tx.py @@ -4,8 +4,7 @@ # Copyright (c) 2025 Great Scott Gadgets # SPDX-License-Identifier: BSD-3-Clause -from amaranth import Elaboratable, Module, Cat, DomainRenamer, Signal -from amaranth.lib import cdc +from amaranth import Elaboratable, Module, Cat, DomainRenamer from amaranth.lib.wiring import connect from amaranth_future import fixed @@ -24,24 +23,22 @@ class Top(Elaboratable): m = Module() m.submodules.clkgen = ClockDomainGenerator() - adc_clk = "adclk" - dac_clk = "daclk" # Submodules. - m.submodules.adcdac_intf = adcdac_intf = MAX586xInterface(adc_domain=adc_clk, dac_domain=dac_clk) + m.submodules.adcdac_intf = adcdac_intf = MAX586xInterface(bb_domain="gck1") m.submodules.mcu_intf = mcu_intf = SGPIOInterface( sample_width=24, rx_assignments=[ - lambda w: w[0:8], lambda w: Cat(w[8:12], w[11].replicate(4)), - lambda w: w[12:20], + lambda w: w[0:8], lambda w: Cat(w[20:24], w[23].replicate(4)), + lambda w: w[12:20], ], tx_assignments=[ - lambda w, v: w[0:8].eq(v), lambda w, v: w[8:12].eq(v), - lambda w, v: w[12:20].eq(v), + lambda w, v: w[0:8].eq(v), lambda w, v: w[20:24].eq(v), + lambda w, v: w[12:20].eq(v), ], domain="sync" ) @@ -58,20 +55,20 @@ class Top(Elaboratable): tx_chain = { # Clock domain conversion. - "clkconv": ClockConverter(IQSample(12), 8, "sync", dac_clk, always_ready=False), + "clkconv": ClockConverter(IQSample(12), 8, "sync", "gck1", always_ready=False), # Half-band interpolation stages (+ skid buffers for timing closure). "hbfir1": HalfBandInterpolatorMAC16(taps_hb1, data_shape=fixed.SQ(11), - overclock_rate=8, num_channels=2, always_ready=False, domain=dac_clk), - "skid1": DomainRenamer(dac_clk)(StreamSkidBuffer(IQSample(12), always_ready=False)), + overclock_rate=8, num_channels=2, always_ready=False, domain="gck1"), + "skid1": DomainRenamer("gck1")(StreamSkidBuffer(IQSample(12), always_ready=False)), "hbfir2": HalfBandInterpolatorMAC16(taps_hb2, data_shape=fixed.SQ(11), - overclock_rate=4, num_channels=2, always_ready=False, domain=dac_clk), - "skid2": DomainRenamer(dac_clk)(StreamSkidBuffer(IQSample(12), always_ready=False)), + overclock_rate=4, num_channels=2, always_ready=False, domain="gck1"), + "skid2": DomainRenamer("gck1")(StreamSkidBuffer(IQSample(12), always_ready=False)), # CIC interpolation stage. - "cic_comp": DomainRenamer(dac_clk)(FIRFilter([-0.125, 0, 0.75, 0, -0.125], shape=fixed.SQ(11), shape_out=fixed.SQ(11), always_ready=False, num_channels=2)), + "cic_comp": DomainRenamer("gck1")(FIRFilter([-0.125, 0, 0.75, 0, -0.125], shape=fixed.SQ(11), shape_out=fixed.SQ(11), always_ready=False, num_channels=2)), "cic_interpolator": CICInterpolator(2, 4, (4, 8, 16, 32), 12, 8, num_channels=2, - always_ready=False, domain=dac_clk), + always_ready=False, domain="gck1"), } for k,v in tx_chain.items(): m.submodules[f"tx_{k}"] = v @@ -89,27 +86,16 @@ class Top(Elaboratable): m.submodules.spi_regs = spi_regs = SPIRegisterInterface(spi_port) # Add control registers. - ctrl = spi_regs.add_register(0x01, init=0) - tx_intrp = Signal(3, init=4) - tx_intrp_new = Signal(3) - tx_intrp_stb = Signal() - tx_intrp_cic = Signal.like(tx_chain["cic_interpolator"].factor) - spi_regs.add_sfr(0x05, read=tx_intrp, write_signal=tx_intrp_new, write_strobe=tx_intrp_stb) + ctrl = spi_regs.add_register(0x01, init=0) + tx_intrp = spi_regs.add_register(0x02, init=0, size=3) m.d.comb += [ # Trigger enable. mcu_intf.trigger_en .eq(ctrl[7]), - ] - # TX interpolation rate. - m.submodules.rx_decim_cdc = cdc.FFSynchronizer(tx_intrp_cic, tx_chain["cic_interpolator"].factor, o_domain=dac_clk) - with m.If(tx_intrp_stb): - with m.If(tx_intrp_new < 4): - m.d.sync += tx_intrp.eq(4) - m.d.sync += tx_intrp_cic.eq(2) - with m.Else(): - m.d.sync += tx_intrp.eq(tx_intrp_new) - m.d.sync += tx_intrp_cic.eq(tx_intrp_new-2) + # TX interpolation rate. + tx_chain["cic_interpolator"].factor .eq(tx_intrp + 2), + ] return m diff --git a/firmware/fpga/top/half_precision.py b/firmware/fpga/top/half_precision.py index 64a23df6..974f68ee 100644 --- a/firmware/fpga/top/half_precision.py +++ b/firmware/fpga/top/half_precision.py @@ -54,19 +54,17 @@ class Top(Elaboratable): m = Module() m.submodules.clkgen = ClockDomainGenerator() - adc_clk = "adclk" - dac_clk = "daclk" # Submodules. - m.submodules.adcdac_intf = adcdac_intf = MAX586xInterface(adc_domain=adc_clk, dac_domain=dac_clk) + m.submodules.adcdac_intf = adcdac_intf = MAX586xInterface(bb_domain="gck1") m.submodules.mcu_intf = mcu_intf = SGPIOInterface(sample_width=8, domain="sync") m.d.comb += adcdac_intf.q_invert.eq(platform.request("q_invert").i) rx_chain = { - "dc_block": DCBlock(width=8, num_channels=2, domain=adc_clk), - "half_prec": DomainRenamer(adc_clk)(IQHalfPrecisionConverter()), - "clkconv": ClockConverter(IQSample(4), 16, adc_clk, "sync"), + "dc_block": DCBlock(width=8, num_channels=2, domain="gck1"), + "half_prec": DomainRenamer("gck1")(IQHalfPrecisionConverter()), + "clkconv": ClockConverter(IQSample(4), 16, "gck1", "sync"), } for k,v in rx_chain.items(): m.submodules[f"rx_{k}"] = v @@ -80,8 +78,8 @@ class Top(Elaboratable): tx_chain = { - "clkconv": ClockConverter(IQSample(4), 16, "sync", dac_clk, always_ready=False), - "half_prec": DomainRenamer(dac_clk)(IQHalfPrecisionConverterInv()), + "clkconv": ClockConverter(IQSample(4), 16, "sync", "gck1", always_ready=False), + "half_prec": DomainRenamer("gck1")(IQHalfPrecisionConverterInv()), } for k,v in tx_chain.items(): m.submodules[f"tx_{k}"] = v diff --git a/firmware/fpga/top/standard.py b/firmware/fpga/top/standard.py index f48e34c0..7f85925b 100644 --- a/firmware/fpga/top/standard.py +++ b/firmware/fpga/top/standard.py @@ -26,11 +26,9 @@ class Top(Elaboratable): m = Module() m.submodules.clkgen = ClockDomainGenerator() - adc_clk = "adclk" - dac_clk = "daclk" # Submodules. - m.submodules.adcdac_intf = adcdac_intf = MAX586xInterface(adc_domain=adc_clk, dac_domain=dac_clk) + m.submodules.adcdac_intf = adcdac_intf = MAX586xInterface(bb_domain="gck1") m.submodules.mcu_intf = mcu_intf = SGPIOInterface(sample_width=16, domain="sync") m.d.comb += adcdac_intf.q_invert.eq(platform.request("q_invert").i) @@ -54,13 +52,13 @@ class Top(Elaboratable): common_rx_filter_opts = dict( data_shape=fixed.SQ(7), always_ready=True, - domain=adc_clk, + domain="gck1", ) rx_chain = { # DC block and quarter shift. - "dc_block": DCBlock(width=8, num_channels=2, domain=adc_clk), - "quarter_shift": DomainRenamer(adc_clk)(QuarterShift()), + "dc_block": DCBlock(width=8, num_channels=2, domain="gck1"), + "quarter_shift": DomainRenamer("gck1")(QuarterShift()), # Half-band decimation stages. "hbfir5": HalfBandDecimator(taps5, **common_rx_filter_opts), @@ -70,7 +68,7 @@ class Top(Elaboratable): "hbfir1": HalfBandDecimator(taps, **common_rx_filter_opts), # Clock domain conversion. - "clkconv": ClockConverter(IQSample(8), 8, adc_clk, "sync"), + "clkconv": ClockConverter(IQSample(8), 8, "gck1", "sync"), } for k,v in rx_chain.items(): m.submodules[f"rx_{k}"] = v @@ -84,20 +82,20 @@ class Top(Elaboratable): tx_chain = { # Clock domain conversion. - "clkconv": ClockConverter(IQSample(8), 8, "sync", dac_clk, always_ready=False), + "clkconv": ClockConverter(IQSample(8), 8, "sync", "gck1", always_ready=False), # Half-band interpolation stages (+ skid buffers for timing closure). "hbfir1": HalfBandInterpolator(taps, data_shape=fixed.SQ(7), - num_channels=2, always_ready=False, domain=dac_clk), - "skid2": DomainRenamer(dac_clk)(StreamSkidBuffer(IQSample(8), always_ready=False)), + num_channels=2, always_ready=False, domain="gck1"), + "skid2": DomainRenamer("gck1")(StreamSkidBuffer(IQSample(8), always_ready=False)), "hbfir2": HalfBandInterpolator(taps2, data_shape=fixed.SQ(7), - num_channels=2, always_ready=False, domain=dac_clk), - "skid3": DomainRenamer(dac_clk)(StreamSkidBuffer(IQSample(8), always_ready=False)), + num_channels=2, always_ready=False, domain="gck1"), + "skid3": DomainRenamer("gck1")(StreamSkidBuffer(IQSample(8), always_ready=False)), # CIC interpolation stage. "cic_interpolator": CICInterpolator(1, 3, (1, 2, 4, 8), 8, 8, num_channels=2, - always_ready=False, domain=dac_clk), - "skid4": DomainRenamer(dac_clk)(StreamSkidBuffer(IQSample(8), always_ready=False)), + always_ready=False, domain="gck1"), + "skid4": DomainRenamer("gck1")(StreamSkidBuffer(IQSample(8), always_ready=False)), } for k,v in tx_chain.items(): m.submodules[f"tx_{k}"] = v @@ -108,7 +106,7 @@ class Top(Elaboratable): connect(m, last, block.input) last = block.output # DAC can also be driven with an internal NCO. - m.submodules.nco = nco = DomainRenamer(dac_clk)(NCO(phase_width=16, output_width=8)) + m.submodules.nco = nco = DomainRenamer("gck1")(NCO(phase_width=16, output_width=8)) with m.If(nco.en): m.d.comb += [ adcdac_intf.dac_stream.p.eq(nco.output), @@ -125,10 +123,9 @@ class Top(Elaboratable): # Add control registers. ctrl = spi_regs.add_register(0x01, init=0) rx_decim = spi_regs.add_register(0x02, init=0, size=3) - rx_pstep = spi_regs.add_register(0x03, init=0) - tx_ctrl = spi_regs.add_register(0x04, init=0, size=1) - tx_intrp = spi_regs.add_register(0x05, init=0, size=3) - tx_pstep = spi_regs.add_register(0x06, init=0) + tx_ctrl = spi_regs.add_register(0x03, init=0, size=1) + tx_intrp = spi_regs.add_register(0x04, init=0, size=3) + tx_pstep = spi_regs.add_register(0x05, init=0) m.d.sync += [ # Trigger enable. @@ -139,8 +136,8 @@ class Top(Elaboratable): # RX settings. rx_chain["dc_block"].enable .eq(ctrl[0]), - rx_chain["quarter_shift"].enable .eq(rx_pstep[-2]), - rx_chain["quarter_shift"].up .eq(rx_pstep[-1]), + rx_chain["quarter_shift"].enable .eq(ctrl[1]), + rx_chain["quarter_shift"].up .eq(ctrl[2]), # RX decimation rate. rx_chain["hbfir5"].enable .eq(rx_decim > 4), @@ -148,23 +145,19 @@ class Top(Elaboratable): rx_chain["hbfir3"].enable .eq(rx_decim > 2), rx_chain["hbfir2"].enable .eq(rx_decim > 1), rx_chain["hbfir1"].enable .eq(rx_decim > 0), - ] - # TX interpolation rate. - tx_intrp_dacclk = Signal.like(tx_intrp) - m.submodules.tx_intrp_cdc = cdc.FFSynchronizer(tx_intrp, tx_intrp_dacclk, o_domain=dac_clk) - m.d.comb += [ - tx_chain["cic_interpolator"].factor .eq(Mux(tx_intrp_dacclk > 2, tx_intrp_dacclk - 2, 0)), - tx_chain["hbfir1"].enable .eq(tx_intrp_dacclk > 0), - tx_chain["hbfir2"].enable .eq(tx_intrp_dacclk > 1), + # TX interpolation rate. + tx_chain["cic_interpolator"].factor .eq(Mux(tx_intrp > 2, tx_intrp - 2, 0)), + tx_chain["hbfir1"].enable .eq(tx_intrp > 0), + tx_chain["hbfir2"].enable .eq(tx_intrp > 1), ] # TX NCO control. - tx_pstep_dacclk = Signal(8) - m.submodules.nco_phase_cdc = cdc.FFSynchronizer(tx_pstep, tx_pstep_dacclk, o_domain=dac_clk) - m.d[dac_clk] += [ + tx_pstep_gck1 = Signal(8) + m.submodules.nco_phase_cdc = cdc.FFSynchronizer(tx_pstep, tx_pstep_gck1, o_domain="gck1") + m.d.gck1 += [ nco.en .eq(tx_ctrl[0]), - nco.phase .eq(nco.phase + (tx_pstep_dacclk << 6)), + nco.phase .eq(nco.phase + (tx_pstep_gck1 << 6)), ] return m diff --git a/firmware/hackrf-common.cmake b/firmware/hackrf-common.cmake index 8f6698da..877e8a85 100644 --- a/firmware/hackrf-common.cmake +++ b/firmware/hackrf-common.cmake @@ -64,7 +64,7 @@ if (NOT DEFINED VERSION) OUTPUT_STRIP_TRAILING_WHITESPACE ) if (GIT_VERSION_FOUND) - set(VERSION "2026.01.3+") + set(VERSION "2026.01.2+") else (GIT_VERSION_FOUND) set(VERSION "git-${GIT_VERSION}") endif (GIT_VERSION_FOUND) @@ -74,9 +74,7 @@ if(NOT DEFINED BOARD) set(BOARD HACKRF_ONE) endif() -include(${PATH_HACKRF_FIRMWARE}/platform-detect.cmake) - -if(BOARD STREQUAL "HACKRF_ONE" OR BOARD STREQUAL "PRALINE" OR BOARD STREQUAL "UNIVERSAL") +if(BOARD STREQUAL "HACKRF_ONE" OR BOARD STREQUAL "PRALINE") set(MCU_PARTNO LPC4320) else() set(MCU_PARTNO LPC4330) @@ -94,7 +92,7 @@ SET(LDSCRIPT_M4_RAM "-T${PATH_HACKRF_FIRMWARE_COMMON}/${MCU_PARTNO}_M4_memory.ld SET(LDSCRIPT_M0 "-T${PATH_HACKRF_FIRMWARE_COMMON}/LPC43xx_M0_memory.ld -Tlibopencm3_lpc43xx_m0.ld") -SET(CFLAGS_COMMON "-Os -g3 -Wall -Wextra -Wstrict-prototypes -Wold-style-definition ${HACKRF_OPTS} -fno-common -MD") +SET(CFLAGS_COMMON "-Os -g3 -Wall -Wextra ${HACKRF_OPTS} -fno-common -MD") SET(LDFLAGS_COMMON "-nostartfiles -Wl,--gc-sections") if(V STREQUAL "1") @@ -170,16 +168,10 @@ endmacro() macro(DeclareTargets) SET(SRC_M4 ${SRC_M4} - ${PATH_HACKRF_FIRMWARE_COMMON}/power.c - ${PATH_HACKRF_FIRMWARE_COMMON}/cpu_clock.c - ${PATH_HACKRF_FIRMWARE_COMMON}/delay.c - ${PATH_HACKRF_FIRMWARE_COMMON}/cpld_jtag.c - ${PATH_HACKRF_FIRMWARE_COMMON}/pins.c - ${PATH_HACKRF_FIRMWARE_COMMON}/leds.c + ${PATH_HACKRF_FIRMWARE_COMMON}/hackrf_core.c ${PATH_HACKRF_FIRMWARE_COMMON}/sgpio.c ${PATH_HACKRF_FIRMWARE_COMMON}/rf_path.c ${PATH_HACKRF_FIRMWARE_COMMON}/si5351c.c - ${PATH_HACKRF_FIRMWARE_COMMON}/clock_gen.c ${PATH_HACKRF_FIRMWARE_COMMON}/max5864.c ${PATH_HACKRF_FIRMWARE_COMMON}/max5864_target.c ${PATH_HACKRF_FIRMWARE_COMMON}/mixer.c @@ -192,19 +184,15 @@ macro(DeclareTargets) ${PATH_HACKRF_FIRMWARE_COMMON}/gpio_lpc.c ${PATH_HACKRF_FIRMWARE_COMMON}/hackrf_ui.c ${PATH_HACKRF_FIRMWARE_COMMON}/platform_detect.c - ${PATH_HACKRF_FIRMWARE_COMMON}/platform_gpio.c - ${PATH_HACKRF_FIRMWARE_COMMON}/platform_scu.c ${PATH_HACKRF_FIRMWARE_COMMON}/firmware_info.c - ${PATH_HACKRF_FIRMWARE_COMMON}/clock_io.c + ${PATH_HACKRF_FIRMWARE_COMMON}/clkin.c ${PATH_HACKRF_FIRMWARE_COMMON}/gpdma.c + ${PATH_HACKRF_FIRMWARE_COMMON}/user_config.c ${PATH_HACKRF_FIRMWARE_COMMON}/radio.c ${PATH_HACKRF_FIRMWARE_COMMON}/selftest.c ${PATH_HACKRF_FIRMWARE_COMMON}/m0_state.c ${PATH_HACKRF_FIRMWARE_COMMON}/adc.c - ${PATH_HACKRF_FIRMWARE_COMMON}/da7219.c - ${PATH_HACKRF_FIRMWARE_COMMON}/max283x.c - ${PATH_HACKRF_FIRMWARE_COMMON}/u128.c - ) + ) if(BOARD STREQUAL "RAD1O") SET(SRC_M4 @@ -231,20 +219,7 @@ macro(DeclareTargets) else() SET(SRC_M4 ${SRC_M4} - ${PATH_HACKRF_FIRMWARE_COMMON}/max2837.c - ${PATH_HACKRF_FIRMWARE_COMMON}/max2837_target.c - ${PATH_HACKRF_FIRMWARE_COMMON}/max2839.c - ${PATH_HACKRF_FIRMWARE_COMMON}/max2839_target.c - ) - endif() - - if(BOARD STREQUAL "UNIVERSAL") - SET(SRC_M4 - ${SRC_M4} - ${PATH_HACKRF_FIRMWARE_COMMON}/fpga.c - ${PATH_HACKRF_FIRMWARE_COMMON}/ice40_spi.c - ${PATH_HACKRF_FIRMWARE_COMMON}/max2831.c - ${PATH_HACKRF_FIRMWARE_COMMON}/max2831_target.c + ${PATH_HACKRF_FIRMWARE_COMMON}/max283x.c ${PATH_HACKRF_FIRMWARE_COMMON}/max2837.c ${PATH_HACKRF_FIRMWARE_COMMON}/max2837_target.c ${PATH_HACKRF_FIRMWARE_COMMON}/max2839.c @@ -272,9 +247,9 @@ macro(DeclareTargets) set_target_properties(${PROJECT_NAME}_m0.elf PROPERTIES COMPILE_FLAGS "${CFLAGS_M0}") set_target_properties(${PROJECT_NAME}_m0.elf PROPERTIES LINK_FLAGS "${LDFLAGS_M0}") - DeclareTarget("${PROJECT_NAME}" "" "${CFLAGS_M4}" "${LDFLAGS_M4}") - DeclareTarget("${PROJECT_NAME}" "_ram" "${CFLAGS_M4_RAM} -DRAM_MODE" "${LDFLAGS_M4_RAM}") - DeclareTarget("${PROJECT_NAME}" "_dfu" "${CFLAGS_M4_RAM} -DDFU_MODE" "${LDFLAGS_M4_RAM}") + DeclareTarget("${PROJECT_NAME}" "" "${CFLAGS_M4}" "${LDFLAGS_M4}") + DeclareTarget("${PROJECT_NAME}" "_ram" "${CFLAGS_M4_RAM} -DRAM_MODE" "${LDFLAGS_M4_RAM}") + DeclareTarget("${PROJECT_NAME}" "_dfu" "${CFLAGS_M4_RAM} -DDFU_MODE" "${LDFLAGS_M4_RAM}") add_custom_target( ${PROJECT_NAME}.dfu ${DFU_ALL} diff --git a/firmware/hackrf_usb/CMakeLists.txt b/firmware/hackrf_usb/CMakeLists.txt index 871e0909..2b797339 100644 --- a/firmware/hackrf_usb/CMakeLists.txt +++ b/firmware/hackrf_usb/CMakeLists.txt @@ -35,10 +35,9 @@ add_custom_command( OUTPUT ${PATH_PRALINE_FPGA_OBJ} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMAND ${CMAKE_COMMAND} -E copy ${PATH_PRALINE_FPGA_BIN} "fpga.bin" - COMMAND ${CMAKE_OBJCOPY} + COMMAND ${CMAKE_OBJCOPY} -I binary -O elf32-littlearm - -B arm --rename-section .data=.rom_only "fpga.bin" ${PATH_PRALINE_FPGA_OBJ} DEPENDS ${PATH_PRALINE_FPGA_BIN} @@ -66,6 +65,7 @@ set(SRC_M4 usb_api_adc.c "${PATH_HACKRF_FIRMWARE_COMMON}/usb_queue.c" "${PATH_HACKRF_FIRMWARE_COMMON}/fault_handler.c" + "${PATH_HACKRF_FIRMWARE_COMMON}/cpld_jtag.c" "${PATH_HACKRF_FIRMWARE_COMMON}/crc.c" "${PATH_HACKRF_FIRMWARE_COMMON}/rom_iap.c" "${PATH_HACKRF_FIRMWARE_COMMON}/operacake.c" @@ -74,26 +74,6 @@ set(SRC_M4 set(SRC_M0 sgpio_m0.s) -if(BOARD STREQUAL "UNIVERSAL") - SET(SRC_M4 - ${SRC_M4} - usb_api_cpld.c - "${PATH_HACKRF_FIRMWARE_COMMON}/cpld_xc2c.c" - "${PATH_HACKRF_CPLD_DATA_C}" - "${PATH_HACKRF_FIRMWARE_COMMON}/xapp058/lenval.c" - "${PATH_HACKRF_FIRMWARE_COMMON}/xapp058/micro.c" - "${PATH_HACKRF_FIRMWARE_COMMON}/xapp058/ports.c" - - "${PATH_HACKRF_FIRMWARE_COMMON}/lz4_blk.c" - "${PATH_HACKRF_FIRMWARE_COMMON}/fpga_image.c" - "${PATH_HACKRF_FIRMWARE_COMMON}/fpga_selftest.c" - usb_api_praline.c - ) - SET(OBJ_M4 - ${PATH_PRALINE_FPGA_OBJ} - ) -endif() - if(BOARD STREQUAL "PRALINE") SET(SRC_M4 ${SRC_M4} @@ -117,7 +97,7 @@ else() ) endif() -if(BOARD STREQUAL "PRALINE" OR BOARD STREQUAL "HACKRF_ONE" OR BOARD STREQUAL "UNIVERSAL") +if(BOARD STREQUAL "HACKRF_ONE" OR BOARD STREQUAL "PRALINE") SET(SRC_M4 ${SRC_M4} "${PATH_HACKRF_FIRMWARE_COMMON}/portapack.c" @@ -135,7 +115,6 @@ if(BOARD STREQUAL "RAD1O") "${PATH_HACKRF_FIRMWARE_COMMON}/rad1o/smallfonts.c" "${PATH_HACKRF_FIRMWARE_COMMON}/rad1o/draw.c" "${PATH_HACKRF_FIRMWARE_COMMON}/rad1o/ubuntu18.c" - "${PATH_HACKRF_FIRMWARE_COMMON}/picoprintf.c" "${PATH_HACKRF_FIRMWARE_COMMON}/ui_rad1o.c" ) endif() diff --git a/firmware/hackrf_usb/hackrf_usb.c b/firmware/hackrf_usb/hackrf_usb.c index 813a9453..0b5d303a 100644 --- a/firmware/hackrf_usb/hackrf_usb.c +++ b/firmware/hackrf_usb/hackrf_usb.c @@ -1,5 +1,5 @@ /* - * Copyright 2012-2026 Great Scott Gadgets + * Copyright 2012-2022 Great Scott Gadgets * Copyright 2012 Jared Boone * Copyright 2013 Benjamin Vernoux * @@ -21,75 +21,47 @@ * Boston, MA 02110-1301, USA. */ -#include -#include +#include #include -#include #include +#include +#include +#include + +#include + +#include "tuning.h" + +#include "usb.h" +#include "usb_standard_request.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef IS_EXPANSION_COMPATIBLE - #include -#endif -#ifdef IS_NOT_RAD1O - #include -#endif -#ifdef IS_PRALINE - #include - #if !(defined(DFU_MODE) || defined(RAM_MODE)) - #include - #include - #include - #endif -#endif +#include "usb_descriptor.h" -#include "usb_api_adc.h" +#include "usb_device.h" +#include "usb_endpoint.h" #include "usb_api_board_info.h" -#include "usb_api_m0_state.h" -#include "usb_api_operacake.h" +#include "usb_api_cpld.h" #include "usb_api_register.h" -#include "usb_api_selftest.h" #include "usb_api_spiflash.h" +#include "usb_api_operacake.h" +#include "usb_api_praline.h" +#include "usb_api_selftest.h" +#include "usb_api_adc.h" +#include "operacake.h" #include "usb_api_sweep.h" #include "usb_api_transceiver.h" #include "usb_api_ui.h" -#include "usb_descriptor.h" -#include "usb_device.h" -#include "usb_endpoint.h" -#ifdef IS_PRALINE - #include "usb_api_praline.h" -#endif -#ifdef IS_NOT_PRALINE - #include "usb_api_cpld.h" -#endif +#include "usb_bulk_buffer.h" +#include "usb_api_m0_state.h" +#include "cpld_xc2c.h" +#include "portapack.h" +#include "hackrf_ui.h" +#include "platform_detect.h" +#include "clkin.h" +#include "fpga.h" +#include "selftest.h" extern uint32_t __m0_start__; extern uint32_t __m0_end__; @@ -105,12 +77,12 @@ static usb_request_handler_fn vendor_request_handler[] = { usb_vendor_request_read_si5351c, usb_vendor_request_set_sample_rate_frac, usb_vendor_request_set_baseband_filter_bandwidth, -#ifdef IS_NOT_RAD1O - usb_vendor_request_write_rffc5071, - usb_vendor_request_read_rffc5071, -#else +#ifdef RAD1O NULL, // write_rffc5071 not used NULL, // read_rffc5071 not used +#else + usb_vendor_request_write_rffc5071, + usb_vendor_request_read_rffc5071, #endif usb_vendor_request_erase_spiflash, usb_vendor_request_write_spiflash, @@ -125,7 +97,7 @@ static usb_request_handler_fn vendor_request_handler[] = { usb_vendor_request_set_vga_gain, usb_vendor_request_set_txvga_gain, NULL, // was set_if_freq -#if defined(IS_HACKRF_ONE) || defined(IS_PRALINE) +#if (defined HACKRF_ONE || defined PRALINE) usb_vendor_request_set_antenna_enable, #else NULL, @@ -142,7 +114,7 @@ static usb_request_handler_fn vendor_request_handler[] = { usb_vendor_request_spiflash_status, usb_vendor_request_spiflash_clear_status, usb_vendor_request_operacake_gpio_test, -#ifdef IS_HACKRF_ONE +#ifdef HACKRF_ONE usb_vendor_request_cpld_checksum, #else NULL, @@ -159,7 +131,7 @@ static usb_request_handler_fn vendor_request_handler[] = { usb_vendor_request_read_supported_platform, usb_vendor_request_set_leds, usb_vendor_request_user_config_set_bias_t_opts, -#ifdef IS_PRALINE +#ifdef PRALINE usb_vendor_request_write_fpga_reg, usb_vendor_request_read_fpga_reg, usb_vendor_request_p2_ctrl, @@ -179,9 +151,6 @@ static usb_request_handler_fn vendor_request_handler[] = { usb_vendor_request_read_selftest, usb_vendor_request_adc_read, usb_vendor_request_test_rtc_osc, - usb_vendor_request_write_radio_reg, - usb_vendor_request_read_radio_reg, - usb_vendor_request_get_buffer_size, }; static const uint32_t vendor_request_handler_count = @@ -256,7 +225,21 @@ void usb_set_descriptor_by_serial_number(void) } } -static void m0_rom_to_ram(void) +#ifndef PRALINE +static bool cpld_jtag_sram_load(jtag_t* const jtag) +{ + cpld_jtag_take(jtag); + cpld_xc2c64a_jtag_sram_write(jtag, &cpld_hackrf_program_sram); + const bool success = cpld_xc2c64a_jtag_sram_verify( + jtag, + &cpld_hackrf_program_sram, + &cpld_hackrf_verify); + cpld_jtag_release(jtag); + return success; +} +#endif + +static void m0_rom_to_ram() { uint32_t* dest = &__ram_m0_start__; @@ -270,152 +253,6 @@ static void m0_rom_to_ram(void) memcpy(dest, (uint32_t*) (base + src), len); } -#if defined(IS_PRALINE) && !(defined(DFU_MODE) || defined(RAM_MODE)) -extern uint32_t _binary_fpga_bin_start; - -void fpga_loader_setup(void) -{ - w25q80bv_setup(&spi_flash); -} - -void fpga_loader_read(uint32_t addr, uint32_t size, uint8_t* buf) -{ - w25q80bv_read(&spi_flash, addr, size, buf); -} - -struct fpga_loader_t fpga_loader = { - .start_addr = (uint32_t) &_binary_fpga_bin_start, - .setup = fpga_loader_setup, - .read = fpga_loader_read, - .in_buffer = lz4_in_buf, - .out_buffer = lz4_out_buf, -}; -#endif - -void radio_changed(const uint32_t changed) -{ - const uint64_t opmode = radio_reg_read(&radio, RADIO_BANK_APPLIED, RADIO_OPMODE); - - if (changed & (1 << RADIO_OPMODE)) { - switch (opmode) { - case TRANSCEIVER_MODE_TX: - case TRANSCEIVER_MODE_SS: - sgpio_configure(&sgpio_config, SGPIO_DIRECTION_TX); - hackrf_ui()->set_direction(RF_PATH_DIRECTION_TX); - break; - case TRANSCEIVER_MODE_RX: - case TRANSCEIVER_MODE_RX_SWEEP: - sgpio_configure(&sgpio_config, SGPIO_DIRECTION_RX); - hackrf_ui()->set_direction(RF_PATH_DIRECTION_RX); - break; - default: - sgpio_configure(&sgpio_config, SGPIO_DIRECTION_RX); - hackrf_ui()->set_direction(RF_PATH_DIRECTION_OFF); - break; - } - } - if (changed & (1 << RADIO_SAMPLE_RATE)) { - const uint64_t rate = - radio_reg_read(&radio, RADIO_BANK_APPLIED, RADIO_SAMPLE_RATE); - hackrf_ui()->set_sample_rate(rate / SR_FP_ONE_HZ); - } - if (changed & (RADIO_REG_GROUP_FREQ)) { - const uint64_t img_reject = - radio_reg_read(&radio, RADIO_BANK_APPLIED, RADIO_IMAGE_REJECT); - const uint64_t freq_lo = - radio_reg_read(&radio, RADIO_BANK_APPLIED, RADIO_FREQUENCY_LO); - const uint64_t freq_if = - radio_reg_read(&radio, RADIO_BANK_APPLIED, RADIO_FREQUENCY_IF); - const bool invert_spectrum = - ((img_reject == RF_PATH_FILTER_LOW_PASS) && (freq_lo > freq_if)); - sgpio_cpld_set_mixer_invert(&sgpio_config, invert_spectrum); - } - if (changed & (1 << RADIO_FREQUENCY_RF)) { - const uint64_t freq = - radio_reg_read(&radio, RADIO_BANK_APPLIED, RADIO_FREQUENCY_RF); - if (opmode != TRANSCEIVER_MODE_RX_SWEEP) { - hackrf_ui()->set_frequency(freq / FP_ONE_HZ); - } -#ifdef IS_EXPANSION_COMPATIBLE - if (IS_EXPANSION_COMPATIBLE) { - operacake_set_range(freq / FP_ONE_MHZ); - } -#endif - } - if (changed & (1 << RADIO_IMAGE_REJECT)) { - if (opmode != TRANSCEIVER_MODE_RX_SWEEP) { - const uint64_t img_reject = radio_reg_read( - &radio, - RADIO_BANK_APPLIED, - RADIO_IMAGE_REJECT); - hackrf_ui()->set_filter(img_reject); - } - } - if (changed & - ((1 << RADIO_BB_BANDWIDTH_TX) | (1 << RADIO_BB_BANDWIDTH_RX) | - (1 << RADIO_OPMODE))) { - uint64_t bw; - - switch (opmode) { - case TRANSCEIVER_MODE_TX: - case TRANSCEIVER_MODE_SS: - bw = radio_reg_read( - &radio, - RADIO_BANK_APPLIED, - RADIO_BB_BANDWIDTH_TX); - break; - default: - bw = radio_reg_read( - &radio, - RADIO_BANK_APPLIED, - RADIO_BB_BANDWIDTH_RX); - } - hackrf_ui()->set_filter_bw(bw); - } - if (changed & - ((1 << RADIO_GAIN_TX_RF) | (1 << RADIO_GAIN_RX_RF) | (1 << RADIO_OPMODE))) { - const uint64_t tx_rf = - radio_reg_read(&radio, RADIO_BANK_APPLIED, RADIO_GAIN_TX_RF); - const uint64_t rx_rf = - radio_reg_read(&radio, RADIO_BANK_APPLIED, RADIO_GAIN_RX_RF); - bool enable; - - switch (opmode) { - case TRANSCEIVER_MODE_TX: - case TRANSCEIVER_MODE_SS: - enable = tx_rf; - break; - case TRANSCEIVER_MODE_RX: - case TRANSCEIVER_MODE_RX_SWEEP: - enable = rx_rf; - break; - default: - enable = false; - } - hackrf_ui()->set_lna_power(enable); - } - if (changed & (1 << RADIO_GAIN_TX_IF)) { - const uint64_t tx_if = - radio_reg_read(&radio, RADIO_BANK_APPLIED, RADIO_GAIN_TX_IF); - hackrf_ui()->set_bb_tx_vga_gain(tx_if); - } - if (changed & (1 << RADIO_GAIN_RX_IF)) { - const uint64_t rx_if = - radio_reg_read(&radio, RADIO_BANK_APPLIED, RADIO_GAIN_RX_IF); - hackrf_ui()->set_bb_lna_gain(rx_if); - } - if (changed & (1 << RADIO_GAIN_RX_BB)) { - const uint64_t rx_bb = - radio_reg_read(&radio, RADIO_BANK_APPLIED, RADIO_GAIN_RX_BB); - hackrf_ui()->set_bb_vga_gain(rx_bb); - } - if (changed & (1 << RADIO_BIAS_TEE)) { - const uint64_t enable = - radio_reg_read(&radio, RADIO_BANK_APPLIED, RADIO_BIAS_TEE); - hackrf_ui()->set_antenna_bias(enable); - } -} - int main(void) { // Copy M0 image from ROM before SPIFI is disabled @@ -424,108 +261,56 @@ int main(void) // This will be cleared if any self-test check fails. selftest.report.pass = true; - // Detect hardware platform before we do anything else. detect_hardware_platform(); - board_id_t board_id = detected_platform(); - - i2c_bus_start(&i2c0, &i2c_config_fast_clock); - - pins_shutdown(); - sgpio_pin_shutdown(&sgpio_config); - rf_path_pin_shutdown(); - if (board_id != BOARD_ID_RAD1O) { - clock_gen_shutdown(); - } - delay_ms(10); - pins_setup(); - cpld_jtag_pin_setup(); - mixer_bus_setup(&mixer); - sgpio_configure_pin_functions(&sgpio_config); - rf_path_pin_setup(&rf_path); -#ifdef IS_PRALINE - if (IS_PRALINE) { - enable_3v3aux_power(); + pin_shutdown(); +#ifndef RAD1O + clock_gen_shutdown(); +#endif + delay_us_at_mhz(10000, 96); + pin_setup(); +#ifndef PRALINE + enable_1v8_power(); + #ifndef RAD1O + clock_gen_init(); + #endif +#else + enable_3v3aux_power(); #if !defined(DFU_MODE) && !defined(RAM_MODE) - enable_1v2_power(); - enable_rf_power(); - /* - * On Praline, the clock generator power supply comes from 3V3FPGA - * which is enabled when 1V2FPGA is turned on. - */ - clock_gen_init(); + enable_1v2_power(); + enable_rf_power(); + clock_gen_init(); #endif - } #endif -#ifdef IS_NOT_PRALINE - if (IS_NOT_PRALINE) { - enable_1v8_power(); - #ifdef IS_NOT_RAD1O - if (IS_NOT_RAD1O) { - /* - * On rad1o, the clock generator power supply comes from the RF supply - * which is enabled later. On H1 and Jawbreaker, the clock generator is - * on the main 3V3 supply. - */ - clock_gen_init(); - } - #endif - } +#ifdef HACKRF_ONE + // Set up mixer before enabling RF power, because its + // GPO is used to control the antenna bias tee. + mixer_setup(&mixer); #endif - tuning_setup(); -#ifdef IS_HACKRF_ONE - if (IS_HACKRF_ONE) { - // Set up mixer before enabling RF power, because its - // GPO is used to control the antenna bias tee. - mixer_setup(&mixer, RFFC5071_VARIANT); - } +#if (defined HACKRF_ONE || defined RAD1O) + enable_rf_power(); #endif -#ifdef IS_H1_OR_RAD1O - if (IS_H1_OR_RAD1O) { - enable_rf_power(); - } -#endif -#ifdef IS_RAD1O - if (IS_RAD1O) { - clock_gen_init(); - } +#ifdef RAD1O + clock_gen_init(); #endif cpu_clock_init(); - /* Clock speed has changed, adjust I2C clock */ - i2c_bus_start(&i2c0, &i2c_config_fast_clock); - /* Wake the M0 */ ipc_halt_m0(); ipc_start_m0((uint32_t) &__ram_m0_start__); -#ifdef IS_NOT_PRALINE - if (IS_NOT_PRALINE) { - if (!cpld_jtag_sram_load(&jtag_cpld)) { - halt_and_flash(1000); - } - } -#endif -#ifdef IS_PRALINE - if (IS_PRALINE) { - #if defined(DFU_MODE) || defined(RAM_MODE) - selftest.fpga_image_load = SKIPPED; - selftest.report.pass = false; - #else - fpga_image_load(&fpga_loader, 0); - #endif - delay_us(100); - fpga_spi_selftest(); - fpga_sgpio_selftest(); +#ifndef PRALINE + if (!cpld_jtag_sram_load(&jtag_cpld)) { + halt_and_flash(6000000); } +#else + fpga_image_load(0); + delay_us_at_mhz(100, 204); + fpga_spi_selftest(); + fpga_sgpio_selftest(); #endif - radio.update_cb = radio_changed; - radio_init(&radio); - -#ifdef IS_EXPANSION_COMPATIBLE - if (IS_EXPANSION_COMPATIBLE) { - portapack_init(); - } +#if (defined HACKRF_ONE || defined PRALINE) + portapack_init(); #endif #ifndef DFU_MODE @@ -535,30 +320,6 @@ int main(void) usb_set_configuration_changed_cb(usb_configuration_changed); usb_peripheral_reset(); -#ifdef IS_HACKRF_ONE - if (IS_HACKRF_ONE) { - memcpy(&usb_device, - &usb_device_hackrf_one, - sizeof(usb_device_hackrf_one)); - } -#endif -#ifdef IS_JAWBREAKER - if (IS_JAWBREAKER) { - memcpy(&usb_device, - &usb_device_jawbreaker, - sizeof(usb_device_jawbreaker)); - } -#endif -#ifdef IS_RAD1O - if (IS_RAD1O) { - memcpy(&usb_device, &usb_device_rad1o, sizeof(usb_device_rad1o)); - } -#endif -#ifdef IS_PRALINE - if (IS_PRALINE) { - memcpy(&usb_device, &usb_device_praline, sizeof(usb_device_praline)); - } -#endif usb_device_init(0, &usb_device); usb_queue_init(&usb_endpoint_control_out_queue); @@ -577,19 +338,14 @@ int main(void) rf_path_init(&rf_path); -#ifdef IS_NOT_RAD1O - rffc5071_lock_test(&mixer.rffc5071); +#ifndef RAD1O + rffc5071_lock_test(&mixer); #endif -#ifdef IS_PRALINE - if (IS_PRALINE) { - fpga_if_xcvr_selftest(); - } +#ifdef PRALINE + fpga_if_xcvr_selftest(); #endif - if (da7219_detect()) { - operacake_skip_i2c_address(DA7219_ADDRESS); - } bool operacake_allow_gpio; if (hackrf_ui()->operacake_gpio_compatible()) { operacake_allow_gpio = true; @@ -616,7 +372,6 @@ int main(void) nvic_disable_irq(NVIC_USB0_IRQ); request = transceiver_request; nvic_enable_irq(NVIC_USB0_IRQ); - radio_update(&radio); switch (request.mode) { case TRANSCEIVER_MODE_OFF: @@ -631,13 +386,11 @@ int main(void) case TRANSCEIVER_MODE_RX_SWEEP: sweep_mode(request.seq); break; +#ifndef PRALINE case TRANSCEIVER_MODE_CPLD_UPDATE: -#ifdef IS_NOT_PRALINE - if (IS_NOT_PRALINE) { - cpld_update(); - } -#endif + cpld_update(); break; +#endif default: break; } diff --git a/firmware/hackrf_usb/usb_api_adc.c b/firmware/hackrf_usb/usb_api_adc.c index 30d33d30..ee1bc98e 100644 --- a/firmware/hackrf_usb/usb_api_adc.c +++ b/firmware/hackrf_usb/usb_api_adc.c @@ -19,16 +19,10 @@ * Boston, MA 02110-1301, USA. */ -#include "usb_api_adc.h" - #include -#include - #include -#include -#include - #include "adc.h" +#include "usb_api_adc.h" usb_request_status_t usb_vendor_request_adc_read( usb_endpoint_t* const endpoint, diff --git a/firmware/hackrf_usb/usb_api_adc.h b/firmware/hackrf_usb/usb_api_adc.h index ed4e7f93..8f4d2568 100644 --- a/firmware/hackrf_usb/usb_api_adc.h +++ b/firmware/hackrf_usb/usb_api_adc.h @@ -19,11 +19,14 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __USB_API_ADC_H__ +#define __USB_API_ADC_H__ -#include #include +#include usb_request_status_t usb_vendor_request_adc_read( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage); + +#endif // __USB_API_ADC_H__ diff --git a/firmware/hackrf_usb/usb_api_board_info.c b/firmware/hackrf_usb/usb_api_board_info.c index a5bad4d8..aeff83b8 100644 --- a/firmware/hackrf_usb/usb_api_board_info.c +++ b/firmware/hackrf_usb/usb_api_board_info.c @@ -20,25 +20,24 @@ * the Free Software Foundation, Inc., 51 Franklin Street, * Boston, MA 02110-1301, USA. */ + #include "usb_api_board_info.h" +#include "platform_detect.h" +#include "firmware_info.h" -#include - +#include +#include +#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef IS_HACKRF_ONE - #include - #include +#include +#include + +#ifdef HACKRF_ONE + #include "gpio_lpc.h" +static struct gpio_t gpio_h1r9_clkout_en = GPIO(0, 9); +static struct gpio_t gpio_h1r9_mcu_clk_en = GPIO(0, 8); +static struct gpio_t gpio_h1r9_rx = GPIO(0, 7); #endif usb_request_status_t usb_vendor_request_read_board_id( @@ -131,23 +130,19 @@ usb_request_status_t usb_vendor_request_reset( const usb_transfer_stage_t stage) { if (stage == USB_TRANSFER_STAGE_SETUP) { - pins_shutdown(); - sgpio_pin_shutdown(&sgpio_config); - rf_path_pin_shutdown(); + pin_shutdown(); clock_gen_shutdown(); -#ifdef IS_H1_R9 - if (IS_H1_R9) { - /* - * Set boot pins as inputs so that the bootloader reads them - * correctly after the reset. - */ - const platform_gpio_t* gpio = platform_gpio(); - gpio_input(gpio->h1r9_mcu_clk_en); - gpio_input(gpio->h1r9_clkout_en); - gpio_input(gpio->h1r9_rx); +#ifdef HACKRF_ONE + /* + * Set boot pins as inputs so that the bootloader reads them + * correctly after the reset. + */ + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + gpio_input(&gpio_h1r9_mcu_clk_en); + gpio_input(&gpio_h1r9_clkout_en); + gpio_input(&gpio_h1r9_rx); } #endif - wwdt_reset(100000); usb_transfer_schedule_ack(endpoint->in); diff --git a/firmware/hackrf_usb/usb_api_board_info.h b/firmware/hackrf_usb/usb_api_board_info.h index ec50d7ce..663d25d8 100644 --- a/firmware/hackrf_usb/usb_api_board_info.h +++ b/firmware/hackrf_usb/usb_api_board_info.h @@ -21,12 +21,13 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __USB_API_BOARD_INFO_H__ +#define __USB_API_BOARD_INFO_H__ #include -#include #include +#include typedef struct { uint32_t part_id[2]; @@ -51,3 +52,5 @@ usb_request_status_t usb_vendor_request_read_board_rev( usb_request_status_t usb_vendor_request_read_supported_platform( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage); + +#endif /* end of include guard: __USB_API_BOARD_INFO_H__ */ diff --git a/firmware/hackrf_usb/usb_api_cpld.c b/firmware/hackrf_usb/usb_api_cpld.c index 38103c81..19748a24 100644 --- a/firmware/hackrf_usb/usb_api_cpld.c +++ b/firmware/hackrf_usb/usb_api_cpld.c @@ -23,20 +23,18 @@ #include "usb_api_cpld.h" +#include +#include +#include +#include + +#include "usb_endpoint.h" + +#include #include #include #include -#include -#include -#include -#include -#include -#include -#include - -#include "usb_endpoint.h" - uint8_t cpld_xsvf_buffer[512]; volatile bool cpld_wait = false; @@ -76,7 +74,7 @@ void cpld_update(void) cpld_xsvf_buffer, refill_cpld_buffer); if (error == 0) { - halt_and_flash(1000); + halt_and_flash(6000000); } else { /* LED3 (Red) steady on error */ led_on(LED3); @@ -91,15 +89,6 @@ usb_request_status_t usb_vendor_request_cpld_checksum( static uint32_t cpld_crc; uint8_t length; - switch (detected_platform()) { - case BOARD_ID_HACKRF1_OG: - case BOARD_ID_HACKRF1_R9: - // supported - break; - default: - return USB_REQUEST_STATUS_STALL; - } - if (stage == USB_TRANSFER_STAGE_SETUP) { cpld_jtag_take(&jtag_cpld); const bool checksum_success = cpld_xc2c64a_jtag_checksum( diff --git a/firmware/hackrf_usb/usb_api_cpld.h b/firmware/hackrf_usb/usb_api_cpld.h index 786a9160..dfbdcfe6 100644 --- a/firmware/hackrf_usb/usb_api_cpld.h +++ b/firmware/hackrf_usb/usb_api_cpld.h @@ -21,13 +21,18 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __USB_API_CPLD_H__ +#define __USB_API_CPLD_H__ + +#include -#include #include +#include void cpld_update(void); usb_request_status_t usb_vendor_request_cpld_checksum( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage); + +#endif /* end of include guard: __USB_API_CPLD_H__ */ diff --git a/firmware/hackrf_usb/usb_api_m0_state.c b/firmware/hackrf_usb/usb_api_m0_state.c index f8679b83..678d8dee 100644 --- a/firmware/hackrf_usb/usb_api_m0_state.c +++ b/firmware/hackrf_usb/usb_api_m0_state.c @@ -21,12 +21,10 @@ #include "usb_api_m0_state.h" +#include #include - -#include -#include #include -#include +#include usb_request_status_t usb_vendor_request_get_m0_state( usb_endpoint_t* const endpoint, diff --git a/firmware/hackrf_usb/usb_api_m0_state.h b/firmware/hackrf_usb/usb_api_m0_state.h index a08188d7..32f40fcf 100644 --- a/firmware/hackrf_usb/usb_api_m0_state.h +++ b/firmware/hackrf_usb/usb_api_m0_state.h @@ -19,11 +19,14 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __M0_STATE_USB_H__ +#define __M0_STATE_USB_H__ #include -#include +#include "m0_state.h" usb_request_status_t usb_vendor_request_get_m0_state( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage); + +#endif /*__M0_STATE_USB_H__*/ diff --git a/firmware/hackrf_usb/usb_api_operacake.c b/firmware/hackrf_usb/usb_api_operacake.c index a9766086..81644ce1 100644 --- a/firmware/hackrf_usb/usb_api_operacake.c +++ b/firmware/hackrf_usb/usb_api_operacake.c @@ -21,17 +21,12 @@ */ #include "usb_api_operacake.h" +#include "usb_queue.h" -#include #include -#include - #include #include #include -#include -#include -#include usb_request_status_t usb_vendor_request_operacake_get_boards( usb_endpoint_t* const endpoint, diff --git a/firmware/hackrf_usb/usb_api_operacake.h b/firmware/hackrf_usb/usb_api_operacake.h index 824311aa..cc511bda 100644 --- a/firmware/hackrf_usb/usb_api_operacake.h +++ b/firmware/hackrf_usb/usb_api_operacake.h @@ -20,10 +20,11 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __USB_API_OPERACAKE_H__ +#define __USB_API_OPERACAKE_H__ -#include #include +#include usb_request_status_t usb_vendor_request_operacake_get_boards( usb_endpoint_t* const endpoint, @@ -52,3 +53,5 @@ usb_request_status_t usb_vendor_request_operacake_get_mode( usb_request_status_t usb_vendor_request_operacake_set_dwell_times( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage); + +#endif /* end of include guard: __USB_API_OPERACAKE_H__ */ diff --git a/firmware/hackrf_usb/usb_api_praline.c b/firmware/hackrf_usb/usb_api_praline.c index d889f5da..9fcde4b1 100644 --- a/firmware/hackrf_usb/usb_api_praline.c +++ b/firmware/hackrf_usb/usb_api_praline.c @@ -22,25 +22,15 @@ */ #include "usb_api_praline.h" +#include "usb_queue.h" +#include -#include -#include -#include -#include -#include -#include -#if !defined(DFU_MODE) && !defined(RAM_MODE) - #include -#endif +#include usb_request_status_t usb_vendor_request_p1_ctrl( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage) { - if (detected_platform() != BOARD_ID_PRALINE) { - return USB_REQUEST_STATUS_STALL; - } - if (stage == USB_TRANSFER_STAGE_SETUP) { p1_ctrl_set(endpoint->setup.value); usb_transfer_schedule_ack(endpoint->in); @@ -52,10 +42,6 @@ usb_request_status_t usb_vendor_request_p2_ctrl( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage) { - if (detected_platform() != BOARD_ID_PRALINE) { - return USB_REQUEST_STATUS_STALL; - } - if (stage == USB_TRANSFER_STAGE_SETUP) { p2_ctrl_set(endpoint->setup.value); usb_transfer_schedule_ack(endpoint->in); @@ -67,10 +53,6 @@ usb_request_status_t usb_vendor_request_clkin_ctrl( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage) { - if (detected_platform() != BOARD_ID_PRALINE) { - return USB_REQUEST_STATUS_STALL; - } - if (stage == USB_TRANSFER_STAGE_SETUP) { clkin_ctrl_set(endpoint->setup.value & 1); usb_transfer_schedule_ack(endpoint->in); @@ -82,10 +64,6 @@ usb_request_status_t usb_vendor_request_set_narrowband_filter( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage) { - if (detected_platform() != BOARD_ID_PRALINE) { - return USB_REQUEST_STATUS_STALL; - } - if (stage == USB_TRANSFER_STAGE_SETUP) { narrowband_filter_set(endpoint->setup.value); usb_transfer_schedule_ack(endpoint->in); @@ -93,27 +71,17 @@ usb_request_status_t usb_vendor_request_set_narrowband_filter( return USB_REQUEST_STATUS_OK; } +bool fpga_image_load(unsigned int index); + usb_request_status_t usb_vendor_request_set_fpga_bitstream( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage) { -#if defined(DFU_MODE) || defined(RAM_MODE) - (void) endpoint; - (void) stage; - return USB_REQUEST_STATUS_STALL; -#else - extern struct fpga_loader_t fpga_loader; - - if (detected_platform() != BOARD_ID_PRALINE) { - return USB_REQUEST_STATUS_STALL; - } - if (stage == USB_TRANSFER_STAGE_SETUP) { - if (!fpga_image_load(&fpga_loader, endpoint->setup.value)) { + if (!fpga_image_load(endpoint->setup.value)) { return USB_REQUEST_STATUS_STALL; } usb_transfer_schedule_ack(endpoint->in); } return USB_REQUEST_STATUS_OK; -#endif -} +} \ No newline at end of file diff --git a/firmware/hackrf_usb/usb_api_praline.h b/firmware/hackrf_usb/usb_api_praline.h index 97816373..2fb2bd48 100644 --- a/firmware/hackrf_usb/usb_api_praline.h +++ b/firmware/hackrf_usb/usb_api_praline.h @@ -19,10 +19,11 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __USB_API_PRALINE_H__ +#define __USB_API_PRALINE_H__ -#include #include +#include usb_request_status_t usb_vendor_request_p2_ctrl( usb_endpoint_t* const endpoint, @@ -43,3 +44,5 @@ usb_request_status_t usb_vendor_request_set_narrowband_filter( usb_request_status_t usb_vendor_request_set_fpga_bitstream( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage); + +#endif /* end of include guard: __USB_API_PRALINE_H__ */ diff --git a/firmware/hackrf_usb/usb_api_register.c b/firmware/hackrf_usb/usb_api_register.c index 626c7508..2cd57cb9 100644 --- a/firmware/hackrf_usb/usb_api_register.c +++ b/firmware/hackrf_usb/usb_api_register.c @@ -1,6 +1,5 @@ /* - * Copyright 2012-2026 Great Scott Gadgets - * Copyright 2023 Jonathan Suite (GitHub: @ai6aj) + * Copyright 2012-2022 Great Scott Gadgets * Copyright 2012 Jared Boone * Copyright 2013 Benjamin Vernoux * @@ -23,36 +22,27 @@ */ #include "usb_api_register.h" +#include +#include +#include +#include +#include +#include +#include -#include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef IS_PRALINE - #include -#endif -#ifdef IS_NOT_RAD1O - #include - #include -#endif +#include usb_request_status_t usb_vendor_request_write_max283x( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage) { if (stage == USB_TRANSFER_STAGE_SETUP) { - uint16_t num_regs = max283x_num_regs(&max283x); - uint16_t data_regs_max_value = max283x_data_regs_max_value(&max283x); - if (endpoint->setup.index < num_regs) { - if (endpoint->setup.value < data_regs_max_value) { +#ifndef PRALINE + if (endpoint->setup.index < MAX2837_NUM_REGS) { + if (endpoint->setup.value < MAX2837_DATA_REGS_MAX_VALUE) { max283x_reg_write( &max283x, endpoint->setup.index, @@ -61,6 +51,18 @@ usb_request_status_t usb_vendor_request_write_max283x( return USB_REQUEST_STATUS_OK; } } +#else + if (endpoint->setup.index < MAX2831_NUM_REGS) { + if (endpoint->setup.value < MAX2831_DATA_REGS_MAX_VALUE) { + max2831_reg_write( + &max283x, + endpoint->setup.index, + endpoint->setup.value); + usb_transfer_schedule_ack(endpoint->in); + return USB_REQUEST_STATUS_OK; + } + } +#endif return USB_REQUEST_STATUS_STALL; } else { return USB_REQUEST_STATUS_OK; @@ -72,8 +74,8 @@ usb_request_status_t usb_vendor_request_read_max283x( const usb_transfer_stage_t stage) { if (stage == USB_TRANSFER_STAGE_SETUP) { - uint16_t num_regs = max283x_num_regs(&max283x); - if (endpoint->setup.index < num_regs) { +#ifndef PRALINE + if (endpoint->setup.index < MAX2837_NUM_REGS) { const uint16_t value = max283x_reg_read(&max283x, endpoint->setup.index); endpoint->buffer[0] = value & 0xff; @@ -87,6 +89,22 @@ usb_request_status_t usb_vendor_request_read_max283x( usb_transfer_schedule_ack(endpoint->out); return USB_REQUEST_STATUS_OK; } +#else + if (endpoint->setup.index < MAX2831_NUM_REGS) { + const uint16_t value = + max2831_reg_read(&max283x, endpoint->setup.index); + endpoint->buffer[0] = value & 0xff; + endpoint->buffer[1] = value >> 8; + usb_transfer_schedule_block( + endpoint->in, + &endpoint->buffer, + 2, + NULL, + NULL); + usb_transfer_schedule_ack(endpoint->out); + return USB_REQUEST_STATUS_OK; + } +#endif return USB_REQUEST_STATUS_STALL; } else { return USB_REQUEST_STATUS_OK; @@ -101,7 +119,7 @@ usb_request_status_t usb_vendor_request_write_si5351c( if (endpoint->setup.index < 256) { if (endpoint->setup.value < 256) { si5351c_write_single( - &si5351c, + &clock_gen, endpoint->setup.index, endpoint->setup.value); usb_transfer_schedule_ack(endpoint->in); @@ -121,7 +139,7 @@ usb_request_status_t usb_vendor_request_read_si5351c( if (stage == USB_TRANSFER_STAGE_SETUP) { if (endpoint->setup.index < 256) { const uint8_t value = - si5351c_read_single(&si5351c, endpoint->setup.index); + si5351c_read_single(&clock_gen, endpoint->setup.index); endpoint->buffer[0] = value; usb_transfer_schedule_block( endpoint->in, @@ -138,80 +156,58 @@ usb_request_status_t usb_vendor_request_read_si5351c( } } +#ifndef RAD1O usb_request_status_t usb_vendor_request_write_rffc5071( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage) { -#ifdef IS_RAD1O - if (IS_RAD1O) { - (void) endpoint; - (void) stage; - return USB_REQUEST_STATUS_STALL; - } -#endif - -#ifdef IS_NOT_RAD1O - if (IS_NOT_RAD1O) { - if (stage == USB_TRANSFER_STAGE_SETUP) { - if (endpoint->setup.index < RFFC5071_NUM_REGS) { - rffc5071_reg_write( - &mixer.rffc5071, - endpoint->setup.index, - endpoint->setup.value); - usb_transfer_schedule_ack(endpoint->in); - return USB_REQUEST_STATUS_OK; - } - return USB_REQUEST_STATUS_STALL; + if (stage == USB_TRANSFER_STAGE_SETUP) { + if (endpoint->setup.index < RFFC5071_NUM_REGS) { + rffc5071_reg_write( + &mixer, + endpoint->setup.index, + endpoint->setup.value); + usb_transfer_schedule_ack(endpoint->in); + return USB_REQUEST_STATUS_OK; } + return USB_REQUEST_STATUS_STALL; + } else { return USB_REQUEST_STATUS_OK; } -#endif } usb_request_status_t usb_vendor_request_read_rffc5071( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage) { -#ifdef IS_RAD1O - if (IS_RAD1O) { - (void) endpoint; - (void) stage; - return USB_REQUEST_STATUS_STALL; - } -#endif - -#ifdef IS_NOT_RAD1O - if (IS_NOT_RAD1O) { - uint16_t value; - if (stage == USB_TRANSFER_STAGE_SETUP) { - if (endpoint->setup.index < RFFC5071_NUM_REGS) { - value = rffc5071_reg_read( - &mixer.rffc5071, - endpoint->setup.index); - endpoint->buffer[0] = value & 0xff; - endpoint->buffer[1] = value >> 8; - usb_transfer_schedule_block( - endpoint->in, - &endpoint->buffer, - 2, - NULL, - NULL); - usb_transfer_schedule_ack(endpoint->out); - return USB_REQUEST_STATUS_OK; - } - return USB_REQUEST_STATUS_STALL; + uint16_t value; + if (stage == USB_TRANSFER_STAGE_SETUP) { + if (endpoint->setup.index < RFFC5071_NUM_REGS) { + value = rffc5071_reg_read(&mixer, endpoint->setup.index); + endpoint->buffer[0] = value & 0xff; + endpoint->buffer[1] = value >> 8; + usb_transfer_schedule_block( + endpoint->in, + &endpoint->buffer, + 2, + NULL, + NULL); + usb_transfer_schedule_ack(endpoint->out); + return USB_REQUEST_STATUS_OK; } + return USB_REQUEST_STATUS_STALL; + } else { return USB_REQUEST_STATUS_OK; } -#endif } +#endif usb_request_status_t usb_vendor_request_set_clkout_enable( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage) { if (stage == USB_TRANSFER_STAGE_SETUP) { - si5351c_clkout_enable(&si5351c, endpoint->setup.value > 0); + si5351c_clkout_enable(&clock_gen, endpoint->setup.value); usb_transfer_schedule_ack(endpoint->in); } return USB_REQUEST_STATUS_OK; @@ -222,7 +218,7 @@ usb_request_status_t usb_vendor_request_get_clkin_status( const usb_transfer_stage_t stage) { if (stage == USB_TRANSFER_STAGE_SETUP) { - endpoint->buffer[0] = si5351c_clkin_signal_valid(&si5351c); + endpoint->buffer[0] = si5351c_clkin_signal_valid(&clock_gen); usb_transfer_schedule_block( endpoint->in, &endpoint->buffer, @@ -245,174 +241,45 @@ usb_request_status_t usb_vendor_request_set_leds( return USB_REQUEST_STATUS_OK; } -typedef enum { - BIAS_TEE_OPT_NOP = 0, // No OPeration / Ignore the thing - BIAS_TEE_OPT_RESERVED = 1, // Currently a NOP - BIAS_TEE_OPT_CLEAR = 2, // Clear/Disable the thing - BIAS_TEE_OPT_SET = 3, // Set/Enable the thing -} bias_tee_opt_t; - -static void set_bias_tee_opt(const uint8_t bank, const bias_tee_opt_t option) -{ - uint64_t value; - - switch (option) { - case BIAS_TEE_OPT_CLEAR: - value = (uint64_t) false; - break; - case BIAS_TEE_OPT_SET: - value = (uint64_t) true; - break; - default: - value = RADIO_UNSET; - } - - radio_reg_write(&radio, bank, RADIO_BIAS_TEE, value); -} - usb_request_status_t usb_vendor_request_user_config_set_bias_t_opts( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage) { if (stage == USB_TRANSFER_STAGE_SETUP) { - uint16_t value = endpoint->setup.value; - if (value & 0x4) { - set_bias_tee_opt(RADIO_BANK_IDLE, value & 0x3); - } - if (value & 0x20) { - set_bias_tee_opt(RADIO_BANK_RX, (value & 0x18) >> 3); - } - if (value & 0x100) { - set_bias_tee_opt(RADIO_BANK_TX, (value & 0xC0) >> 6); - } + user_config_set_bias_t_opts(endpoint->setup.value); usb_transfer_schedule_ack(endpoint->in); } return USB_REQUEST_STATUS_OK; } -#ifdef IS_PRALINE +#ifdef PRALINE usb_request_status_t usb_vendor_request_write_fpga_reg( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage) { - #ifdef IS_PRALINE - if (IS_PRALINE) { - if (stage == USB_TRANSFER_STAGE_SETUP) { - fpga_reg_write( - &fpga, - endpoint->setup.index, - endpoint->setup.value); - usb_transfer_schedule_ack(endpoint->in); - } + if (stage == USB_TRANSFER_STAGE_SETUP) { + fpga_reg_write(&fpga, endpoint->setup.index, endpoint->setup.value); + usb_transfer_schedule_ack(endpoint->in); return USB_REQUEST_STATUS_OK; } - #endif - - return USB_REQUEST_STATUS_STALL; + return USB_REQUEST_STATUS_OK; } usb_request_status_t usb_vendor_request_read_fpga_reg( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage) { - #ifdef IS_PRALINE - if (IS_PRALINE) { - if (stage == USB_TRANSFER_STAGE_SETUP) { - const uint8_t value = fpga_reg_read(&fpga, endpoint->setup.index); - endpoint->buffer[0] = value; - usb_transfer_schedule_block( - endpoint->in, - &endpoint->buffer, - 1, - NULL, - NULL); - usb_transfer_schedule_ack(endpoint->out); - } - return USB_REQUEST_STATUS_OK; - } - #endif - - return USB_REQUEST_STATUS_STALL; -} -#endif - -/* - * Each register is transferred as a uint8_t register number followed by a - * little-endian uint64_t value for a total of 9 bytes. - */ -static uint8_t radio_reg_buf[RADIO_NUM_REGS * 9]; - -usb_request_status_t usb_vendor_request_write_radio_reg( - usb_endpoint_t* const endpoint, - const usb_transfer_stage_t stage) -{ - uint8_t bank; if (stage == USB_TRANSFER_STAGE_SETUP) { - bank = endpoint->setup.index; - if (bank >= RADIO_NUM_BANKS) { - return USB_REQUEST_STATUS_STALL; - } - uint8_t num_regs = endpoint->setup.length / 9; - if ((num_regs == 0) || (num_regs > RADIO_NUM_REGS)) { - return USB_REQUEST_STATUS_STALL; - } - usb_transfer_schedule_block( - endpoint->out, - &radio_reg_buf, - endpoint->setup.length, - NULL, - NULL); - } else if (stage == USB_TRANSFER_STAGE_DATA) { - uint8_t address, i; - uint64_t value; - bank = endpoint->setup.index; - for (i = 0; i < endpoint->setup.length; i += 9) { - address = radio_reg_buf[i]; - value = radio_reg_buf[i + 1] | - ((uint64_t) radio_reg_buf[i + 2] << 8) | - ((uint64_t) radio_reg_buf[i + 3] << 16) | - ((uint64_t) radio_reg_buf[i + 4] << 24) | - ((uint64_t) radio_reg_buf[i + 5] << 32) | - ((uint64_t) radio_reg_buf[i + 6] << 40) | - ((uint64_t) radio_reg_buf[i + 7] << 48) | - ((uint64_t) radio_reg_buf[i + 8] << 56); - radio_error_t result = - radio_reg_write(&radio, bank, address, value); - if (result != RADIO_OK) { - return USB_REQUEST_STATUS_STALL; - } - } - usb_transfer_schedule_ack(endpoint->in); - } - return USB_REQUEST_STATUS_OK; -} - -usb_request_status_t usb_vendor_request_read_radio_reg( - usb_endpoint_t* const endpoint, - const usb_transfer_stage_t stage) -{ - if (stage == USB_TRANSFER_STAGE_SETUP) { - uint8_t bank = endpoint->setup.index; - uint8_t address = endpoint->setup.value; - if ((bank >= RADIO_NUM_BANKS) || (address >= RADIO_NUM_REGS)) { - return USB_REQUEST_STATUS_STALL; - } - uint64_t value = radio_reg_read(&radio, bank, address); - endpoint->buffer[0] = value & 0xff; - endpoint->buffer[1] = (value >> 8) & 0xff; - endpoint->buffer[2] = (value >> 16) & 0xff; - endpoint->buffer[3] = (value >> 24) & 0xff; - endpoint->buffer[4] = (value >> 32) & 0xff; - endpoint->buffer[5] = (value >> 40) & 0xff; - endpoint->buffer[6] = (value >> 48) & 0xff; - endpoint->buffer[7] = (value >> 56) & 0xff; + const uint8_t value = fpga_reg_read(&fpga, endpoint->setup.index); + endpoint->buffer[0] = value; usb_transfer_schedule_block( endpoint->in, &endpoint->buffer, - 8, + 1, NULL, NULL); usb_transfer_schedule_ack(endpoint->out); } return USB_REQUEST_STATUS_OK; } +#endif diff --git a/firmware/hackrf_usb/usb_api_register.h b/firmware/hackrf_usb/usb_api_register.h index a5a36550..8fc62c2c 100644 --- a/firmware/hackrf_usb/usb_api_register.h +++ b/firmware/hackrf_usb/usb_api_register.h @@ -1,5 +1,5 @@ /* - * Copyright 2012-2026 Great Scott Gadgets + * Copyright 2012-2022 Great Scott Gadgets * Copyright 2012 Jared Boone * Copyright 2013 Benjamin Vernoux * @@ -21,10 +21,11 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __USB_API_REGISTER_H__ +#define __USB_API_REGISTER_H__ -#include #include +#include usb_request_status_t usb_vendor_request_write_max283x( usb_endpoint_t* const endpoint, @@ -56,7 +57,7 @@ usb_request_status_t usb_vendor_request_set_leds( usb_request_status_t usb_vendor_request_user_config_set_bias_t_opts( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage); -#ifdef IS_PRALINE +#ifdef PRALINE usb_request_status_t usb_vendor_request_write_fpga_reg( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage); @@ -64,9 +65,5 @@ usb_request_status_t usb_vendor_request_read_fpga_reg( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage); #endif -usb_request_status_t usb_vendor_request_write_radio_reg( - usb_endpoint_t* const endpoint, - const usb_transfer_stage_t stage); -usb_request_status_t usb_vendor_request_read_radio_reg( - usb_endpoint_t* const endpoint, - const usb_transfer_stage_t stage); + +#endif /* end of include guard: __USB_API_REGISTER_H__ */ diff --git a/firmware/hackrf_usb/usb_api_selftest.c b/firmware/hackrf_usb/usb_api_selftest.c index 7fde6f68..16a1cff4 100644 --- a/firmware/hackrf_usb/usb_api_selftest.c +++ b/firmware/hackrf_usb/usb_api_selftest.c @@ -19,22 +19,14 @@ * Boston, MA 02110-1301, USA. */ -#include "usb_api_selftest.h" - +#include #include -#include -#ifdef IS_NOT_RAD1O - #include -#endif - -#include -#include - -#include -#include #include -#include -#include +#include +#include +#include "usb_api_selftest.h" +#include "selftest.h" +#include "platform_detect.h" static char* itoa(int val, int base) { @@ -61,7 +53,7 @@ void append(char** dest, size_t* capacity, const char* str) } } -#ifdef IS_PRALINE +#ifdef PRALINE static const char* test_result_to_str(test_result_t result) { switch (result) { @@ -82,112 +74,89 @@ void generate_selftest_report(void) { char* s = &selftest.report.msg[0]; size_t c = sizeof(selftest.report.msg); -#ifdef IS_RAD1O - if (IS_RAD1O) { - append(&s, &c, "Mixer: MAX2871, ID: "); - append(&s, &c, itoa(selftest.mixer_id, 10)); - append(&s, &c, "\n"); +#ifdef RAD1O + append(&s, &c, "Mixer: MAX2871, ID: "); + append(&s, &c, itoa(selftest.mixer_id, 10)); + append(&s, &c, "\n"); +#else + append(&s, &c, "Mixer: RFFC5072, ID: "); + append(&s, &c, itoa(selftest.mixer_id >> 3, 10)); + append(&s, &c, ", Rev: "); + append(&s, &c, itoa(selftest.mixer_id & 0x7, 10)); + append(&s, &c, ", Locks: "); + bool lock; + for (int i = 0; i < NUM_LOCK_ATTEMPTS; i++) { + lock = selftest.mixer_locks[i]; + append(&s, &c, itoa(lock, 2)); } -#endif -#ifdef IS_NOT_RAD1O - if (IS_NOT_RAD1O) { - append(&s, &c, "Mixer: RFFC5072, ID: "); - append(&s, &c, itoa(selftest.mixer_id >> 3, 10)); - append(&s, &c, ", Rev: "); - append(&s, &c, itoa(selftest.mixer_id & 0x7, 10)); - append(&s, &c, ", Locks: "); - bool lock; - for (int i = 0; i < NUM_LOCK_ATTEMPTS; i++) { - lock = selftest.mixer_locks[i]; - append(&s, &c, itoa(lock, 2)); - } - if (lock) { - append(&s, &c, " (PASS)"); - } else { - append(&s, &c, " (FAIL)"); - } - append(&s, &c, "\n"); + if (lock) { + append(&s, &c, " (PASS)"); + } else { + append(&s, &c, " (FAIL)"); } + append(&s, &c, "\n"); #endif - append(&s, &c, "Clock: Si5351"); append(&s, &c, ", Rev: "); append(&s, &c, itoa(selftest.si5351_rev_id, 10)); append(&s, &c, ", readback: "); append(&s, &c, selftest.si5351_readback_ok ? "OK" : "FAIL"); append(&s, &c, "\n"); - -#ifdef IS_PRALINE - if (IS_PRALINE) { - append(&s, &c, "Transceiver: MAX2831, RSSI mux test: "); - append(&s, &c, selftest.max2831_mux_test_ok ? "PASS" : "FAIL"); - append(&s, &c, "\n"); +#ifdef PRALINE + append(&s, &c, "Transceiver: MAX2831, RSSI mux test: "); + append(&s, &c, selftest.max2831_mux_test_ok ? "PASS" : "FAIL"); + append(&s, &c, "\n"); +#else + append(&s, &c, "Transceiver: "); + append(&s, + &c, + (detected_platform() == BOARD_ID_HACKRF1_R9 ? "MAX2839" : "MAX2837")); + append(&s, &c, ", readback success: "); + append(&s, &c, itoa(selftest.max283x_readback_register_count, 10)); + append(&s, &c, "/"); + append(&s, &c, itoa(selftest.max283x_readback_total_registers, 10)); + if (selftest.max283x_readback_register_count < + selftest.max283x_readback_total_registers) { + append(&s, &c, ", bad value: 0x"); + append(&s, &c, itoa(selftest.max283x_readback_bad_value, 10)); + append(&s, &c, ", expected: 0x"); + append(&s, &c, itoa(selftest.max283x_readback_expected_value, 10)); } + append(&s, &c, "\n"); #endif -#ifdef IS_NOT_PRALINE - if (IS_NOT_PRALINE) { - append(&s, &c, "Transceiver: "); - #ifdef IS_H1_R9 - if (IS_H1_R9) { - append(&s, &c, "MAX2839"); - } - #endif - #ifdef IS_NOT_H1_R9 - if (IS_NOT_H1_R9) { - append(&s, &c, "MAX2837"); - } - #endif - append(&s, &c, ", readback success: "); - append(&s, &c, itoa(selftest.max283x_readback_register_count, 10)); - append(&s, &c, "/"); - append(&s, &c, itoa(selftest.max283x_readback_total_registers, 10)); - if (selftest.max283x_readback_register_count < - selftest.max283x_readback_total_registers) { - append(&s, &c, ", bad value: 0x"); - append(&s, &c, itoa(selftest.max283x_readback_bad_value, 10)); - append(&s, &c, ", expected: 0x"); - append(&s, - &c, - itoa(selftest.max283x_readback_expected_value, 10)); - } +#ifdef PRALINE + append(&s, &c, "FPGA configuration: "); + append(&s, &c, test_result_to_str(selftest.fpga_image_load)); + append(&s, &c, "\n"); + append(&s, &c, "FPGA SPI: "); + append(&s, &c, test_result_to_str(selftest.fpga_spi)); + append(&s, &c, "\n"); + append(&s, &c, "SGPIO RX test: "); + append(&s, &c, test_result_to_str(selftest.sgpio_rx)); + append(&s, &c, "\n"); + append(&s, &c, "Loopback test: "); + append(&s, &c, test_result_to_str(selftest.xcvr_loopback)); + append(&s, &c, "\n"); + // Dump transceiver loopback measurements. + for (int i = 0; i < 4; ++i) { + struct xcvr_measurements* m = &selftest.xcvr_measurements[i]; + append(&s, &c, " "); + append(&s, &c, itoa(i, 10)); + append(&s, &c, ":"); + append(&s, &c, itoa(m->zcs_i, 10)); + append(&s, &c, ","); + append(&s, &c, itoa(m->zcs_q, 10)); + append(&s, &c, ","); + append(&s, &c, itoa(m->max_mag_i, 10)); + append(&s, &c, ","); + append(&s, &c, itoa(m->max_mag_q, 10)); + append(&s, &c, ","); + append(&s, &c, itoa(m->avg_mag_sq_i, 10)); + append(&s, &c, ","); + append(&s, &c, itoa(m->avg_mag_sq_q, 10)); append(&s, &c, "\n"); } #endif -#ifdef IS_PRALINE - if (IS_PRALINE) { - append(&s, &c, "FPGA configuration: "); - append(&s, &c, test_result_to_str(selftest.fpga_image_load)); - append(&s, &c, "\n"); - append(&s, &c, "FPGA SPI: "); - append(&s, &c, test_result_to_str(selftest.fpga_spi)); - append(&s, &c, "\n"); - append(&s, &c, "SGPIO RX test: "); - append(&s, &c, test_result_to_str(selftest.sgpio_rx)); - append(&s, &c, "\n"); - append(&s, &c, "Loopback test: "); - append(&s, &c, test_result_to_str(selftest.xcvr_loopback)); - append(&s, &c, "\n"); - // Dump transceiver loopback measurements. - for (int i = 0; i < 4; ++i) { - struct xcvr_measurements* m = &selftest.xcvr_measurements[i]; - append(&s, &c, " "); - append(&s, &c, itoa(i, 10)); - append(&s, &c, ":"); - append(&s, &c, itoa(m->zcs_i, 10)); - append(&s, &c, ","); - append(&s, &c, itoa(m->zcs_q, 10)); - append(&s, &c, ","); - append(&s, &c, itoa(m->max_mag_i, 10)); - append(&s, &c, ","); - append(&s, &c, itoa(m->max_mag_q, 10)); - append(&s, &c, ","); - append(&s, &c, itoa(m->avg_mag_sq_i, 10)); - append(&s, &c, ","); - append(&s, &c, itoa(m->avg_mag_sq_q, 10)); - append(&s, &c, "\n"); - } - } -#endif } usb_request_status_t usb_vendor_request_read_selftest( diff --git a/firmware/hackrf_usb/usb_api_selftest.h b/firmware/hackrf_usb/usb_api_selftest.h index 7f5af7da..453d0362 100644 --- a/firmware/hackrf_usb/usb_api_selftest.h +++ b/firmware/hackrf_usb/usb_api_selftest.h @@ -19,10 +19,11 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __USB_API_SELFTEST_H +#define __USB_API_SELFTEST_H -#include #include +#include usb_request_status_t usb_vendor_request_read_selftest( usb_endpoint_t* const endpoint, @@ -31,3 +32,5 @@ usb_request_status_t usb_vendor_request_read_selftest( usb_request_status_t usb_vendor_request_test_rtc_osc( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage); + +#endif // __USB_API_SELFTEST_H diff --git a/firmware/hackrf_usb/usb_api_spiflash.c b/firmware/hackrf_usb/usb_api_spiflash.c index 21370bd0..5133fa0c 100644 --- a/firmware/hackrf_usb/usb_api_spiflash.c +++ b/firmware/hackrf_usb/usb_api_spiflash.c @@ -23,12 +23,12 @@ #include "usb_api_spiflash.h" -#include -#include +#include "usb_queue.h" + +#include + +#include -#include -#include -#include #include /* Buffer size == spi_flash.page_len */ @@ -39,6 +39,7 @@ usb_request_status_t usb_vendor_request_erase_spiflash( const usb_transfer_stage_t stage) { if (stage == USB_TRANSFER_STAGE_SETUP) { + spi_bus_start(spi_flash.bus, &ssp_config_w25q80bv); w25q80bv_setup(&spi_flash); /* only chip erase is implemented */ w25q80bv_chip_erase(&spi_flash); @@ -67,6 +68,7 @@ usb_request_status_t usb_vendor_request_write_spiflash( len, NULL, NULL); + spi_bus_start(spi_flash.bus, &ssp_config_w25q80bv); w25q80bv_setup(&spi_flash); return USB_REQUEST_STATUS_OK; } @@ -108,7 +110,6 @@ usb_request_status_t usb_vendor_request_read_spiflash( len, NULL, NULL); - usb_transfer_schedule_ack(endpoint->out); return USB_REQUEST_STATUS_OK; } } else if (stage == USB_TRANSFER_STAGE_DATA) { @@ -119,6 +120,7 @@ usb_request_status_t usb_vendor_request_read_spiflash( ((addr + len) > spi_flash.num_bytes)) { return USB_REQUEST_STATUS_STALL; } else { + usb_transfer_schedule_ack(endpoint->out); return USB_REQUEST_STATUS_OK; } } else { @@ -138,9 +140,13 @@ usb_request_status_t usb_vendor_request_spiflash_status( 2, NULL, NULL); + return USB_REQUEST_STATUS_OK; + } else if (stage == USB_TRANSFER_STAGE_DATA) { usb_transfer_schedule_ack(endpoint->out); + return USB_REQUEST_STATUS_OK; + } else { + return USB_REQUEST_STATUS_OK; } - return USB_REQUEST_STATUS_OK; } usb_request_status_t usb_vendor_request_spiflash_clear_status( diff --git a/firmware/hackrf_usb/usb_api_spiflash.h b/firmware/hackrf_usb/usb_api_spiflash.h index f8e3209f..cd46b4aa 100644 --- a/firmware/hackrf_usb/usb_api_spiflash.h +++ b/firmware/hackrf_usb/usb_api_spiflash.h @@ -21,10 +21,11 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __USB_API_SPIFLASH_H__ +#define __USB_API_SPIFLASH_H__ -#include #include +#include usb_request_status_t usb_vendor_request_erase_spiflash( usb_endpoint_t* const endpoint, @@ -41,3 +42,5 @@ usb_request_status_t usb_vendor_request_spiflash_status( usb_request_status_t usb_vendor_request_spiflash_clear_status( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage); + +#endif /* end of include guard: __USB_API_SPIFLASH_H__ */ diff --git a/firmware/hackrf_usb/usb_api_sweep.c b/firmware/hackrf_usb/usb_api_sweep.c index 1bea5dd2..ae4e74b4 100644 --- a/firmware/hackrf_usb/usb_api_sweep.c +++ b/firmware/hackrf_usb/usb_api_sweep.c @@ -1,5 +1,5 @@ /* - * Copyright 2016-2026 Great Scott Gadgets + * Copyright 2016-2022 Great Scott Gadgets * Copyright 2016 Mike Walters, Dominic Spill * * This file is part of HackRF. @@ -20,33 +20,28 @@ * Boston, MA 02110-1301, USA. */ -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include "usb_api_sweep.h" +#include "usb_queue.h" +#include +#include #include "usb_api_transceiver.h" -#include "usb_buffer.h" +#include "usb_bulk_buffer.h" +#include "usb_api_m0_state.h" +#include "tuning.h" #include "usb_endpoint.h" +#include "streaming.h" + +#include #define MIN(x, y) ((x) < (y) ? (x) : (y)) #define MAX(x, y) ((x) > (y) ? (x) : (y)) #define FREQ_GRANULARITY 1000000 #define MAX_RANGES 10 +#ifndef PRALINE + #define THROWAWAY_BUFFERS 2 +#else + #define THROWAWAY_BUFFERS 1 +#endif static uint64_t sweep_freq; static uint16_t frequencies[MAX_RANGES * 2]; @@ -55,45 +50,13 @@ static uint16_t num_ranges = 0; static uint32_t dwell_blocks = 0; static uint32_t step_width = 0; static uint32_t offset = 0; -static uint32_t throwaway_buffers = 0; static enum sweep_style style = LINEAR; -static bool freq_ui_dirty = false; -static bool img_reject_ui_dirty = false; -static rf_path_filter_t img_reject; - -/* - * Opportunistic UI updates are made when time is available. Updates are - * prioritized to prevent a single update from taking too long. Lower priority - * changes to the image reject filter path display are done only if there is - * time remaining after the higher priority update to the frequency display. - */ -void update_ui(void) -{ - if (freq_ui_dirty) { - hackrf_ui()->set_frequency(sweep_freq + offset); - freq_ui_dirty = false; - } else if (img_reject_ui_dirty) { - const uint64_t new_img_reject = - radio_reg_read(&radio, RADIO_BANK_APPLIED, RADIO_IMAGE_REJECT); - if (new_img_reject != img_reject) { - img_reject = new_img_reject; - hackrf_ui()->set_filter(img_reject); - } - img_reject_ui_dirty = false; - } -} /* Do this before starting sweep mode with request_transceiver_mode(). */ usb_request_status_t usb_vendor_request_init_sweep( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage) { - if (detected_platform() == BOARD_ID_PRALINE) { - throwaway_buffers = 1; - } else { - throwaway_buffers = 2; - } - uint32_t num_bytes; int i; if (stage == USB_TRANSFER_STAGE_SETUP) { @@ -129,12 +92,11 @@ usb_request_status_t usb_vendor_request_init_sweep( ((uint16_t) (data[10 + i * 2]) << 8) + data[9 + i * 2]; } sweep_freq = (uint64_t) frequencies[0] * FREQ_GRANULARITY; - - radio_reg_write( + radio_set_frequency( &radio, - RADIO_BANK_REQUESTED, + RADIO_CHANNEL0, RADIO_FREQUENCY_RF, - (sweep_freq + offset) * FP_ONE_HZ); + (radio_frequency_t){.hz = sweep_freq + offset}); usb_transfer_schedule_ack(endpoint->in); } return USB_REQUEST_STATUS_OK; @@ -147,7 +109,7 @@ void sweep_bulk_transfer_complete(void* user_data, unsigned int bytes_transferre // For each buffer transferred, we need to bump the count to allow // for the buffer(s) that are to be discarded. - m0_state.m4_count += (throwaway_buffers + 1) * 0x4000; + m0_state.m4_count += (THROWAWAY_BUFFERS + 1) * 0x4000; } void sweep_mode(uint32_t seq) @@ -183,9 +145,6 @@ void sweep_mode(uint32_t seq) uint8_t* buffer; transceiver_startup(TRANSCEIVER_MODE_RX_SWEEP); - hackrf_ui()->set_frequency(sweep_freq + offset); - img_reject = radio_reg_read(&radio, RADIO_BANK_APPLIED, RADIO_IMAGE_REJECT); - hackrf_ui()->set_filter(img_reject); // Set M0 to RX first buffer, then wait. m0_state.threshold = 0x4000; @@ -203,11 +162,11 @@ void sweep_mode(uint32_t seq) // Set M0 to switch back to RX after we have received our // discard buffers. - m0_state.threshold += (0x4000 * throwaway_buffers); + m0_state.threshold += (0x4000 * THROWAWAY_BUFFERS); m0_state.next_mode = M0_MODE_RX; // Write metadata to buffer. - buffer = &usb_samp_buffer[phase * 0x4000]; + buffer = &usb_bulk_buffer[phase * 0x4000]; *buffer = 0x7f; *(buffer + 1) = 0x7f; *(buffer + 2) = sweep_freq & 0xff; @@ -228,7 +187,7 @@ void sweep_mode(uint32_t seq) NULL); // Use other buffer next time. - phase = (phase + 1) % throwaway_buffers; + phase = (phase + 1) % THROWAWAY_BUFFERS; if (++blocks_queued == dwell_blocks) { // Calculate next sweep frequency. @@ -261,15 +220,12 @@ void sweep_mode(uint32_t seq) } // Retune to new frequency. nvic_disable_irq(NVIC_USB0_IRQ); - radio_reg_write( + radio_set_frequency( &radio, - RADIO_BANK_REQUESTED, + RADIO_CHANNEL0, RADIO_FREQUENCY_RF, - (sweep_freq + offset) * FP_ONE_HZ); + (radio_frequency_t){.hz = sweep_freq + offset}); nvic_enable_irq(NVIC_USB0_IRQ); - radio_update(&radio); - freq_ui_dirty = true; - img_reject_ui_dirty = true; blocks_queued = 0; } @@ -278,7 +234,6 @@ void sweep_mode(uint32_t seq) if (transceiver_request.seq != seq) { goto end; } - update_ui(); } // Set M0 to switch back to WAIT after filling next buffer. diff --git a/firmware/hackrf_usb/usb_api_sweep.h b/firmware/hackrf_usb/usb_api_sweep.h index cf4c84ad..afae5f72 100644 --- a/firmware/hackrf_usb/usb_api_sweep.h +++ b/firmware/hackrf_usb/usb_api_sweep.h @@ -20,12 +20,12 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __USB_API_SWEEP_H__ +#define __USB_API_SWEEP_H__ -#include - -#include +#include #include +#include enum sweep_style { LINEAR = 0, @@ -37,3 +37,5 @@ usb_request_status_t usb_vendor_request_init_sweep( const usb_transfer_stage_t stage); void sweep_mode(uint32_t seq); + +#endif /* __USB_API_SWEEP_H__ */ diff --git a/firmware/hackrf_usb/usb_api_transceiver.c b/firmware/hackrf_usb/usb_api_transceiver.c index e72a408b..cbc8e293 100644 --- a/firmware/hackrf_usb/usb_api_transceiver.c +++ b/firmware/hackrf_usb/usb_api_transceiver.c @@ -23,43 +23,31 @@ #include "usb_api_transceiver.h" -#include +#include "hackrf_ui.h" +#include "operacake_sctimer.h" + +#include +#include "usb_bulk_buffer.h" +#include "usb_api_m0_state.h" + +#include "usb_api_cpld.h" // Remove when CPLD update is handled elsewhere + +#include "max2837.h" +#include "max2839.h" +#include "rf_path.h" +#include "tuning.h" +#include "streaming.h" +#include "usb.h" +#include "usb_queue.h" +#include "platform_detect.h" + #include +#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "usb_buffer.h" #include "usb_endpoint.h" +#include "usb_api_sweep.h" #define USB_TRANSFER_SIZE 0x4000 -#define DMA_TRANSFER_SIZE 0x2000 - -#define BUF_HALF_MASK (USB_SAMP_BUFFER_SIZE >> 1) - -// Unless we know the host knows our buffer size, we'll avoid leaving TX -// until we've transmitted all bytes sent by the host. This flag is cleared -// when the host requests our buffer size. -bool auto_tx_flush = true; - -volatile uint32_t dma_started, dma_pending, usb_started, usb_completed; typedef struct { uint32_t freq_mhz; @@ -83,8 +71,6 @@ typedef struct { set_sample_r_params_t set_sample_r_params; -void transceiver_dma_setup(void); - usb_request_status_t usb_vendor_request_set_baseband_filter_bandwidth( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage) @@ -92,19 +78,24 @@ usb_request_status_t usb_vendor_request_set_baseband_filter_bandwidth( if (stage == USB_TRANSFER_STAGE_SETUP) { const uint32_t bandwidth = (endpoint->setup.index << 16) | endpoint->setup.value; - radio_reg_write( + radio_error_t result = radio_set_filter( &radio, - RADIO_BANK_REQUESTED, - RADIO_BB_BANDWIDTH_TX, - bandwidth); - radio_reg_write( - &radio, - RADIO_BANK_REQUESTED, - RADIO_BB_BANDWIDTH_RX, - bandwidth); - usb_transfer_schedule_ack(endpoint->in); + RADIO_CHANNEL0, + RADIO_FILTER_BASEBAND, + (radio_filter_t){.hz = bandwidth}); + if (result == RADIO_OK) { + radio_filter_t real = radio_get_filter( + &radio, + RADIO_CHANNEL0, + RADIO_FILTER_BASEBAND); + hackrf_ui()->set_filter_bw(real.hz); + usb_transfer_schedule_ack(endpoint->in); + return USB_REQUEST_STATUS_OK; + } + return USB_REQUEST_STATUS_STALL; + } else { + return USB_REQUEST_STATUS_OK; } - return USB_REQUEST_STATUS_OK; } usb_request_status_t usb_vendor_request_set_freq( @@ -118,32 +109,23 @@ usb_request_status_t usb_vendor_request_set_freq( sizeof(set_freq_params_t), NULL, NULL); + return USB_REQUEST_STATUS_OK; } else if (stage == USB_TRANSFER_STAGE_DATA) { const uint64_t freq = set_freq_params.freq_mhz * 1000000ULL + set_freq_params.freq_hz; - radio_reg_write( + radio_error_t result = radio_set_frequency( &radio, - RADIO_BANK_REQUESTED, + RADIO_CHANNEL0, RADIO_FREQUENCY_RF, - freq * FP_ONE_HZ); - radio_reg_write( - &radio, - RADIO_BANK_REQUESTED, - RADIO_FREQUENCY_IF, - RADIO_UNSET); - radio_reg_write( - &radio, - RADIO_BANK_REQUESTED, - RADIO_FREQUENCY_LO, - RADIO_UNSET); - radio_reg_write( - &radio, - RADIO_BANK_REQUESTED, - RADIO_IMAGE_REJECT, - RADIO_UNSET); - usb_transfer_schedule_ack(endpoint->in); + (radio_frequency_t){.hz = freq}); + if (result == RADIO_OK) { + usb_transfer_schedule_ack(endpoint->in); + return USB_REQUEST_STATUS_OK; + } + return USB_REQUEST_STATUS_STALL; + } else { + return USB_REQUEST_STATUS_OK; } - return USB_REQUEST_STATUS_OK; } usb_request_status_t usb_vendor_request_set_freq_explicit( @@ -157,47 +139,24 @@ usb_request_status_t usb_vendor_request_set_freq_explicit( sizeof(struct set_freq_explicit_params), NULL, NULL); + return USB_REQUEST_STATUS_OK; } else if (stage == USB_TRANSFER_STAGE_DATA) { - radio_reg_write( + radio_error_t result = radio_set_frequency( &radio, - RADIO_BANK_REQUESTED, - RADIO_FREQUENCY_IF, - explicit_params.if_freq_hz * FP_ONE_HZ); - radio_reg_write( - &radio, - RADIO_BANK_REQUESTED, - RADIO_FREQUENCY_LO, - explicit_params.lo_freq_hz * FP_ONE_HZ); - radio_reg_write( - &radio, - RADIO_BANK_REQUESTED, - RADIO_IMAGE_REJECT, - explicit_params.path); - usb_transfer_schedule_ack(endpoint->in); + RADIO_CHANNEL0, + RADIO_FREQUENCY_RF, + (radio_frequency_t){ + .if_hz = explicit_params.if_freq_hz, + .lo_hz = explicit_params.lo_freq_hz, + .path = explicit_params.path}); + if (result == RADIO_OK) { + usb_transfer_schedule_ack(endpoint->in); + return USB_REQUEST_STATUS_OK; + } + return USB_REQUEST_STATUS_STALL; + } else { + return USB_REQUEST_STATUS_OK; } - return USB_REQUEST_STATUS_OK; -} - -/* - * Convert fractional sample rate to units of 1/(2**36) Hz. - */ -static inline fp_28_36_t round_sample_rate(uint64_t num, uint32_t denom) -{ - uint64_t q1, r1, q2, r2, q3; - - if (denom == 0) { - denom = 1; - } - - q1 = num / denom; - r1 = num % denom; - - q2 = (r1 << 32) / denom; - r2 = (r1 << 32) % denom; - - q3 = ((r2 << 4) + (denom >> 1)) / denom; - - return (q1 << 36) + (q2 << 4) + q3; } usb_request_status_t usb_vendor_request_set_sample_rate_frac( @@ -211,34 +170,49 @@ usb_request_status_t usb_vendor_request_set_sample_rate_frac( sizeof(set_sample_r_params_t), NULL, NULL); + return USB_REQUEST_STATUS_OK; } else if (stage == USB_TRANSFER_STAGE_DATA) { - uint32_t numerator = set_sample_r_params.freq_hz; - uint32_t denominator = set_sample_r_params.divider; - uint64_t value = round_sample_rate(numerator, denominator); - radio_reg_write(&radio, RADIO_BANK_REQUESTED, RADIO_SAMPLE_RATE, value); - usb_transfer_schedule_ack(endpoint->in); + radio_error_t result = radio_set_sample_rate( + &radio, + RADIO_CHANNEL0, + RADIO_SAMPLE_RATE_CLOCKGEN, + (radio_sample_rate_t){ + .num = set_sample_r_params.freq_hz * 2, + .div = set_sample_r_params.divider, + }); + if (result == RADIO_OK) { + usb_transfer_schedule_ack(endpoint->in); + return USB_REQUEST_STATUS_OK; + } + return USB_REQUEST_STATUS_STALL; + } else { + return USB_REQUEST_STATUS_OK; } - return USB_REQUEST_STATUS_OK; } usb_request_status_t usb_vendor_request_set_amp_enable( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage) { + radio_gain_t off = {.enable = false}; + radio_gain_t on = {.enable = true}; + if (stage == USB_TRANSFER_STAGE_SETUP) { - radio_reg_write( - &radio, - RADIO_BANK_REQUESTED, - RADIO_GAIN_TX_RF, - endpoint->setup.value); - radio_reg_write( - &radio, - RADIO_BANK_REQUESTED, - RADIO_GAIN_RX_RF, - endpoint->setup.value); - usb_transfer_schedule_ack(endpoint->in); + switch (endpoint->setup.value) { + case 0: + radio_set_gain(&radio, RADIO_CHANNEL0, RADIO_GAIN_RF_AMP, off); + usb_transfer_schedule_ack(endpoint->in); + return USB_REQUEST_STATUS_OK; + case 1: + radio_set_gain(&radio, RADIO_CHANNEL0, RADIO_GAIN_RF_AMP, on); + usb_transfer_schedule_ack(endpoint->in); + return USB_REQUEST_STATUS_OK; + default: + return USB_REQUEST_STATUS_STALL; + } + } else { + return USB_REQUEST_STATUS_OK; } - return USB_REQUEST_STATUS_OK; } usb_request_status_t usb_vendor_request_set_lna_gain( @@ -246,9 +220,13 @@ usb_request_status_t usb_vendor_request_set_lna_gain( const usb_transfer_stage_t stage) { if (stage == USB_TRANSFER_STAGE_SETUP) { - uint8_t gain = endpoint->setup.index; - radio_reg_write(&radio, RADIO_BANK_REQUESTED, RADIO_GAIN_RX_IF, gain); - endpoint->buffer[0] = RADIO_OK; + radio_gain_t gain = {.db = endpoint->setup.index}; + uint8_t value = + radio_set_gain(&radio, RADIO_CHANNEL0, RADIO_GAIN_RX_LNA, gain); + endpoint->buffer[0] = value; + if (value) { + hackrf_ui()->set_bb_lna_gain(endpoint->setup.index); + } usb_transfer_schedule_block( endpoint->in, &endpoint->buffer, @@ -256,6 +234,7 @@ usb_request_status_t usb_vendor_request_set_lna_gain( NULL, NULL); usb_transfer_schedule_ack(endpoint->out); + return USB_REQUEST_STATUS_OK; } return USB_REQUEST_STATUS_OK; } @@ -265,9 +244,13 @@ usb_request_status_t usb_vendor_request_set_vga_gain( const usb_transfer_stage_t stage) { if (stage == USB_TRANSFER_STAGE_SETUP) { - uint8_t gain = endpoint->setup.index; - radio_reg_write(&radio, RADIO_BANK_REQUESTED, RADIO_GAIN_RX_BB, gain); - endpoint->buffer[0] = RADIO_OK; + radio_gain_t gain = {.db = endpoint->setup.index}; + uint8_t value = + radio_set_gain(&radio, RADIO_CHANNEL0, RADIO_GAIN_RX_VGA, gain); + endpoint->buffer[0] = value; + if (value) { + hackrf_ui()->set_bb_vga_gain(endpoint->setup.index); + } usb_transfer_schedule_block( endpoint->in, &endpoint->buffer, @@ -275,6 +258,7 @@ usb_request_status_t usb_vendor_request_set_vga_gain( NULL, NULL); usb_transfer_schedule_ack(endpoint->out); + return USB_REQUEST_STATUS_OK; } return USB_REQUEST_STATUS_OK; } @@ -284,9 +268,13 @@ usb_request_status_t usb_vendor_request_set_txvga_gain( const usb_transfer_stage_t stage) { if (stage == USB_TRANSFER_STAGE_SETUP) { - uint8_t gain = endpoint->setup.index; - radio_reg_write(&radio, RADIO_BANK_REQUESTED, RADIO_GAIN_TX_IF, gain); - endpoint->buffer[0] = RADIO_OK; + radio_gain_t gain = {.db = endpoint->setup.index}; + uint8_t value = + radio_set_gain(&radio, RADIO_CHANNEL0, RADIO_GAIN_TX_VGA, gain); + endpoint->buffer[0] = value; + if (value) { + hackrf_ui()->set_bb_tx_vga_gain(endpoint->setup.index); + } usb_transfer_schedule_block( endpoint->in, &endpoint->buffer, @@ -294,6 +282,7 @@ usb_request_status_t usb_vendor_request_set_txvga_gain( NULL, NULL); usb_transfer_schedule_ack(endpoint->out); + return USB_REQUEST_STATUS_OK; } return USB_REQUEST_STATUS_OK; } @@ -302,25 +291,33 @@ usb_request_status_t usb_vendor_request_set_antenna_enable( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage) { - switch (detected_platform()) { - case BOARD_ID_HACKRF1_OG: - case BOARD_ID_HACKRF1_R9: - case BOARD_ID_PRALINE: - // supported - break; - default: - return USB_REQUEST_STATUS_STALL; - } + radio_antenna_t off = {.enable = false}; + radio_antenna_t on = {.enable = true}; if (stage == USB_TRANSFER_STAGE_SETUP) { - radio_reg_write( - &radio, - RADIO_BANK_REQUESTED, - RADIO_BIAS_TEE, - endpoint->setup.value); - usb_transfer_schedule_ack(endpoint->in); + switch (endpoint->setup.value) { + case 0: + radio_set_antenna( + &radio, + RADIO_CHANNEL0, + RADIO_ANTENNA_BIAS_TEE, + off); + usb_transfer_schedule_ack(endpoint->in); + return USB_REQUEST_STATUS_OK; + case 1: + radio_set_antenna( + &radio, + RADIO_CHANNEL0, + RADIO_ANTENNA_BIAS_TEE, + on); + usb_transfer_schedule_ack(endpoint->in); + return USB_REQUEST_STATUS_OK; + default: + return USB_REQUEST_STATUS_STALL; + } + } else { + return USB_REQUEST_STATUS_OK; } - return USB_REQUEST_STATUS_OK; } static volatile uint32_t _tx_underrun_limit; @@ -331,17 +328,6 @@ volatile transceiver_request_t transceiver_request = { .seq = 0, }; -void transceiver_usb_setup_complete(usb_endpoint_t* const endpoint) -{ - if (transceiver_request.mode == TRANSCEIVER_MODE_TX && - endpoint->setup.request == 1 && auto_tx_flush) { - // This is a request to leave TX mode. Do so but NAK for now. - request_transceiver_mode(endpoint->setup.value); - } else { - usb_setup_complete(endpoint); - } -} - // Must be called from an atomic context (normally USB ISR) void request_transceiver_mode(transceiver_mode_t mode) { @@ -362,20 +348,14 @@ void transceiver_shutdown(void) led_off(LED2); led_off(LED3); - radio_switch_opmode(&radio, TRANSCEIVER_MODE_OFF); + radio_switch_mode(&radio, RADIO_CHANNEL0, TRANSCEIVER_MODE_OFF); m0_set_mode(M0_MODE_IDLE); } void transceiver_startup(const transceiver_mode_t mode) { - dma_started = 0; - dma_pending = 0; - usb_started = 0; - usb_completed = 0; - - transceiver_dma_setup(); - - radio_switch_opmode(&radio, mode); + radio_switch_mode(&radio, RADIO_CHANNEL0, mode); + hackrf_ui()->set_transceiver_mode(mode); switch (mode) { case TRANSCEIVER_MODE_RX_SWEEP: @@ -396,6 +376,7 @@ void transceiver_startup(const transceiver_mode_t mode) } activate_best_clock_source(); + trigger_enable(radio_get_trigger_enable(&radio, RADIO_CHANNEL0)); } usb_request_status_t usb_vendor_request_set_transceiver_mode( @@ -425,14 +406,18 @@ usb_request_status_t usb_vendor_request_set_hw_sync_mode( const usb_transfer_stage_t stage) { if (stage == USB_TRANSFER_STAGE_SETUP) { - radio_reg_write( + radio_error_t result = radio_set_trigger_enable( &radio, - RADIO_BANK_REQUESTED, - RADIO_TRIGGER, - endpoint->setup.value); - usb_transfer_schedule_ack(endpoint->in); + RADIO_CHANNEL0, + endpoint->setup.value != 0); + if (result == RADIO_OK) { + usb_transfer_schedule_ack(endpoint->in); + return USB_REQUEST_STATUS_OK; + } + return USB_REQUEST_STATUS_STALL; + } else { + return USB_REQUEST_STATUS_OK; } - return USB_REQUEST_STATUS_OK; } usb_request_status_t usb_vendor_request_set_tx_underrun_limit( @@ -459,191 +444,30 @@ usb_request_status_t usb_vendor_request_set_rx_overrun_limit( return USB_REQUEST_STATUS_OK; } -usb_request_status_t usb_vendor_request_get_buffer_size( - usb_endpoint_t* const endpoint, - const usb_transfer_stage_t stage) -{ - if (stage == USB_TRANSFER_STAGE_SETUP) { - uint32_t value = USB_SAMP_BUFFER_SIZE + USB_BULK_BUFFER_SIZE; - endpoint->buffer[0] = value & 0xff; - endpoint->buffer[1] = (value & 0xff00) >> 8; - endpoint->buffer[2] = (value & 0xff0000) >> 16; - endpoint->buffer[3] = (value & 0xff000000) >> 24; - usb_transfer_schedule_block( - endpoint->in, - &endpoint->buffer, - 4, - NULL, - NULL); - usb_transfer_schedule_ack(endpoint->out); - - // We now know the host is aware of our buffer size, so it - // can make its own decisions about flushing the buffer. - auto_tx_flush = false; - - return USB_REQUEST_STATUS_OK; - } - return USB_REQUEST_STATUS_OK; -} - -/* clang-format off */ - -// Which GPDMA channel to use. -const uint32_t DMA_CHANNEL = 1; - -// GPDMA CCONFIG register setting. -const uint32_t DMA_CONFIG = - GPDMA_CCONFIG_FLOWCNTRL(0) // memory-to-memory - | GPDMA_CCONFIG_IE(0) // no error interrupt - | GPDMA_CCONFIG_ITC(1) // terminal count interrupt - | GPDMA_CCONFIG_L(0) // do not lock - | GPDMA_CCONFIG_H(0); // do not halt - -// GPDMA CCONTROL register setting (excluding TRANSFERSIZE field). -const uint32_t DMA_CONTROL = - GPDMA_CCONTROL_SBSIZE(7) // 256-transfer src bursts - | GPDMA_CCONTROL_DBSIZE(7) // 256-transfer dst bursts - | GPDMA_CCONTROL_SWIDTH(2) // 32-bit src transfers - | GPDMA_CCONTROL_DWIDTH(2) // 32-bit dst transfers - | GPDMA_CCONTROL_S(0) // AHB Master 0 - | GPDMA_CCONTROL_D(1) // AHB Master 1 - | GPDMA_CCONTROL_SI(1) // increment source - | GPDMA_CCONTROL_DI(1) // increment destination - | GPDMA_CCONTROL_PROT1(0) // user mode - | GPDMA_CCONTROL_PROT2(0) // not bufferable - | GPDMA_CCONTROL_PROT3(0) // not cacheable - | GPDMA_CCONTROL_I(1); // interrupt enabled - -/* clang-format on */ - -// Called before any sequence of DMA transfers. -void transceiver_dma_setup(void) -{ - gpdma_controller_enable(); - GPDMA_CCONFIG(DMA_CHANNEL) = DMA_CONFIG; - GPDMA_CCONTROL(DMA_CHANNEL) = DMA_CONTROL; - GPDMA_CLLI(DMA_CHANNEL) = 0; - GPDMA_INTTCCLEAR = (1 << DMA_CHANNEL); - nvic_enable_irq(NVIC_DMA_IRQ); -} - -// Called to start each DMA transfer. -void transceiver_start_dma(void* src, void* dest, size_t size) -{ - uint32_t num_transfers = size >> 2; - GPDMA_CCONTROL(DMA_CHANNEL) = DMA_CONTROL | num_transfers; - GPDMA_CSRCADDR(DMA_CHANNEL) = (uint32_t) src; - GPDMA_CDESTADDR(DMA_CHANNEL) = (uint32_t) dest; - dma_pending = size; - gpdma_channel_enable(DMA_CHANNEL); -} - -// Called when a DMA transfer completes. -void dma_isr(void) -{ - gpdma_channel_disable(DMA_CHANNEL); - GPDMA_INTTCCLEAR = (1 << DMA_CHANNEL); - m0_state.m4_count += dma_pending; - dma_pending = 0; -} - void transceiver_bulk_transfer_complete(void* user_data, unsigned int bytes_transferred) { (void) user_data; - usb_completed += bytes_transferred; -} - -typedef enum { - DIRECTION_RX, - DIRECTION_TX, -} direction_t; - -void start_dma_if_possible(direction_t direction, size_t size) -{ - if (dma_pending) { - return; - } - - uint32_t sampling_completed = m0_state.m0_count; - uint32_t dma_completed = m0_state.m4_count; - uint32_t samp_offset = dma_started & USB_SAMP_BUFFER_MASK; - uint32_t bulk_offset = dma_started & USB_BULK_BUFFER_MASK; - uint32_t data_available, space_in_use, space_available, samp_buf_margin; - uint8_t *dest, *src; - - if (direction == DIRECTION_RX) { - data_available = sampling_completed - dma_started; - space_in_use = usb_completed - dma_completed; - space_available = USB_BULK_BUFFER_SIZE - space_in_use; - samp_buf_margin = USB_SAMP_BUFFER_SIZE - data_available; - src = &usb_samp_buffer[samp_offset]; - dest = &usb_bulk_buffer[bulk_offset]; - } else { - data_available = usb_completed - dma_started; - space_in_use = dma_completed - sampling_completed; - space_available = USB_SAMP_BUFFER_SIZE - space_in_use; - samp_buf_margin = space_in_use; - src = &usb_bulk_buffer[bulk_offset]; - dest = &usb_samp_buffer[samp_offset]; - } - - if (data_available < size || size > space_available) { - return; - } - - uint32_t m0_buf_half = sampling_completed & BUF_HALF_MASK; - uint32_t dma_buf_half = dma_started & BUF_HALF_MASK; - bool same_buf_half = m0_buf_half == dma_buf_half; - - if (same_buf_half && samp_buf_margin >= (USB_SAMP_BUFFER_SIZE / 2)) { - return; - } - - transceiver_start_dma(src, dest, size); - - dma_started += size; -} - -void start_usb_if_possible(direction_t direction) -{ - uint32_t bulk_offset = usb_started & USB_BULK_BUFFER_MASK; - uint32_t dma_completed = m0_state.m4_count; - uint32_t bytes_available; - usb_endpoint_t* usb_endpoint; - - if (direction == DIRECTION_RX) { - bytes_available = dma_completed - usb_started; - usb_endpoint = &usb_endpoint_bulk_in; - } else { - uint32_t space_used = usb_started - dma_completed; - bytes_available = USB_BULK_BUFFER_SIZE - space_used; - usb_endpoint = &usb_endpoint_bulk_out; - } - - if (bytes_available < USB_TRANSFER_SIZE) { - return; - } - - usb_transfer_schedule_block( - usb_endpoint, - &usb_bulk_buffer[bulk_offset], - USB_TRANSFER_SIZE, - transceiver_bulk_transfer_complete, - NULL); - - usb_started += USB_TRANSFER_SIZE; + m0_state.m4_count += bytes_transferred; } void rx_mode(uint32_t seq) { + uint32_t usb_count = 0; + transceiver_startup(TRANSCEIVER_MODE_RX); baseband_streaming_enable(&sgpio_config); while (transceiver_request.seq == seq) { - start_dma_if_possible(DIRECTION_RX, DMA_TRANSFER_SIZE); - start_usb_if_possible(DIRECTION_RX); - radio_update(&radio); + if ((m0_state.m0_count - usb_count) >= USB_TRANSFER_SIZE) { + usb_transfer_schedule_block( + &usb_endpoint_bulk_in, + &usb_bulk_buffer[usb_count & USB_BULK_BUFFER_MASK], + USB_TRANSFER_SIZE, + transceiver_bulk_transfer_complete, + NULL); + usb_count += USB_TRANSFER_SIZE; + } } transceiver_shutdown(); @@ -651,118 +475,43 @@ void rx_mode(uint32_t seq) void tx_mode(uint32_t seq) { + unsigned int usb_count = 0; + bool started = false; + transceiver_startup(TRANSCEIVER_MODE_TX); - // First, make transfers directly into the sample buffer to fill it. - for (int i = 0; i < (USB_SAMP_BUFFER_SIZE / USB_TRANSFER_SIZE); i++) { - // Set up transfer. - usb_transfer_schedule_block( - &usb_endpoint_bulk_out, - &usb_samp_buffer[usb_started], - USB_TRANSFER_SIZE, - transceiver_bulk_transfer_complete, - NULL); - usb_started += USB_TRANSFER_SIZE; + // Set up OUT transfer of buffer 0. + usb_transfer_schedule_block( + &usb_endpoint_bulk_out, + &usb_bulk_buffer[0x0000], + USB_TRANSFER_SIZE, + transceiver_bulk_transfer_complete, + NULL); + usb_count += USB_TRANSFER_SIZE; - // Wait for the transfer to complete. - while (usb_completed < usb_started) { - // Handle the host switching modes before filling the buffer. - if (transceiver_request.seq != seq) { - transceiver_shutdown(); - return; - } - - radio_update(&radio); - } - } - - // Sample buffer is now full. Update DMA counters accordingly. - dma_started = USB_SAMP_BUFFER_SIZE; - m0_state.m4_count = USB_SAMP_BUFFER_SIZE; - - // Start transmitting samples. - baseband_streaming_enable(&sgpio_config); - - // Continue feeding samples to the sample buffer. while (transceiver_request.seq == seq) { - start_dma_if_possible(DIRECTION_TX, DMA_TRANSFER_SIZE); - start_usb_if_possible(DIRECTION_TX); - radio_update(&radio); - } - - // Host has now requested to stop TX. If we're not auto-flushing, we - // should now stop TX immediately. - - if (!auto_tx_flush) { - transceiver_shutdown(); - return; - } - - // Otherwise, we should now ensure all bytes sent by the host are - // transmitted before we leave TX. First, we should make sure all data - // currently in the USB bulk buffer reaches the sample buffer. - - if ((usb_started - usb_completed) > 0) { - // We were part way through a 16KB firmware-side transfer when - // the transceiver mode change request to stop TX was received. - // - // We want to include the contents of that partial transfer in - // the data we move to the sample buffer. - // - // The transfer was already stopped by usb_endpoint_flush(), - // which was called from request_transceiver_mode(). - // - // We will not have had a callback, and the transfer descriptor - // (dTD) will not have been updated, since the transfer did not - // complete. - // - // However, as long as we haven't started a new transfer, we - // can retrieve the partial byte count from the transfer - // overlay in the endpoint queue head (dQH) (UM10503 25.9.1). - - usb_queue_head_t* const qh = - usb_queue_head(usb_endpoint_bulk_out.address); - unsigned int bytes_remaining = - (qh->total_bytes & USB_TD_DTD_TOKEN_TOTAL_BYTES_MASK) >> - USB_TD_DTD_TOKEN_TOTAL_BYTES_SHIFT; - unsigned int bytes_transferred = USB_TRANSFER_SIZE - bytes_remaining; - usb_completed += bytes_transferred; - } - - // Feed the remaining data from the bulk buffer to the sample buffer. - // At this point, we also need to handle the case where there is less data - // to be transferred to the sample buffer than a full-sized DMA transfer. - - // Any remainder of less than 4 bytes will be ignored; this is the chunk - // size of our DMA transfers. - while ((usb_completed - m0_state.m4_count) >= 4) { - uint32_t data_available = usb_completed - dma_started; - if (data_available > DMA_TRANSFER_SIZE) { - start_dma_if_possible(DIRECTION_TX, DMA_TRANSFER_SIZE); - } else { - start_dma_if_possible(DIRECTION_TX, data_available); + if (!started && (m0_state.m4_count == USB_BULK_BUFFER_SIZE)) { + // Buffer is now full, start streaming. + baseband_streaming_enable(&sgpio_config); + started = true; + } + if ((usb_count - m0_state.m0_count) <= USB_TRANSFER_SIZE) { + usb_transfer_schedule_block( + &usb_endpoint_bulk_out, + &usb_bulk_buffer[usb_count & USB_BULK_BUFFER_MASK], + USB_TRANSFER_SIZE, + transceiver_bulk_transfer_complete, + NULL); + usb_count += USB_TRANSFER_SIZE; } - radio_update(&radio); } - // Wait for the data in the sample buffer to be transmitted. - - // Any remainder of less than 32 bytes will be ignored; this is - // the chunk size used by the M0 core to transfer samples to SGPIO. - while ((m0_state.m4_count - m0_state.m0_count) >= 32) { - radio_update(&radio); - } - - // All data received from the host has now been transmitted. - // Now we can ACK the control request that took us out of TX mode. - usb_transfer_schedule_ack(usb_endpoint_control_in.in); - transceiver_shutdown(); } void off_mode(uint32_t seq) { - while (transceiver_request.seq == seq) { - radio_update(&radio); - } + hackrf_ui()->set_transceiver_mode(TRANSCEIVER_MODE_OFF); + + while (transceiver_request.seq == seq) {} } diff --git a/firmware/hackrf_usb/usb_api_transceiver.h b/firmware/hackrf_usb/usb_api_transceiver.h index a29dec11..e06d6c16 100644 --- a/firmware/hackrf_usb/usb_api_transceiver.h +++ b/firmware/hackrf_usb/usb_api_transceiver.h @@ -21,11 +21,10 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __USB_API_TRANSCEIVER_H__ +#define __USB_API_TRANSCEIVER_H__ -#include - -#include +#include #include #include @@ -36,8 +35,6 @@ typedef struct { extern volatile transceiver_request_t transceiver_request; -void transceiver_usb_setup_complete(usb_endpoint_t* const endpoint); - usb_request_status_t usb_vendor_request_set_transceiver_mode( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage); @@ -77,9 +74,6 @@ usb_request_status_t usb_vendor_request_set_tx_underrun_limit( usb_request_status_t usb_vendor_request_set_rx_overrun_limit( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage); -usb_request_status_t usb_vendor_request_get_buffer_size( - usb_endpoint_t* const endpoint, - const usb_transfer_stage_t stage); void request_transceiver_mode(transceiver_mode_t mode); void transceiver_startup(transceiver_mode_t mode); @@ -87,3 +81,5 @@ void transceiver_shutdown(void); void rx_mode(uint32_t seq); void tx_mode(uint32_t seq); void off_mode(uint32_t seq); + +#endif /*__USB_API_TRANSCEIVER_H__*/ diff --git a/firmware/hackrf_usb/usb_api_ui.c b/firmware/hackrf_usb/usb_api_ui.c index 918a6e23..5fe1becb 100644 --- a/firmware/hackrf_usb/usb_api_ui.c +++ b/firmware/hackrf_usb/usb_api_ui.c @@ -22,10 +22,12 @@ #include "usb_api_ui.h" +#include #include #include -#include -#include + +#include +#include usb_request_status_t usb_vendor_request_set_ui_enable( usb_endpoint_t* const endpoint, diff --git a/firmware/hackrf_usb/usb_api_ui.h b/firmware/hackrf_usb/usb_api_ui.h index 56688ca1..f7f6996b 100644 --- a/firmware/hackrf_usb/usb_api_ui.h +++ b/firmware/hackrf_usb/usb_api_ui.h @@ -20,11 +20,14 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __USB_API_UI_H__ +#define __USB_API_UI_H__ -#include #include +#include usb_request_status_t usb_vendor_request_set_ui_enable( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage); + +#endif /* end of include guard: __USB_API_UI_H__ */ diff --git a/firmware/hackrf_usb/usb_buffer.h b/firmware/hackrf_usb/usb_bulk_buffer.h similarity index 73% rename from firmware/hackrf_usb/usb_buffer.h rename to firmware/hackrf_usb/usb_bulk_buffer.h index 07543025..3e284143 100644 --- a/firmware/hackrf_usb/usb_buffer.h +++ b/firmware/hackrf_usb/usb_bulk_buffer.h @@ -21,19 +21,19 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __USB_BULK_BUFFER_H__ +#define __USB_BULK_BUFFER_H__ +#include #include -#define USB_SAMP_BUFFER_SIZE 0x8000 -#define USB_SAMP_BUFFER_MASK 0x7FFF - #define USB_BULK_BUFFER_SIZE 0x8000 #define USB_BULK_BUFFER_MASK 0x7FFF -/* Addresses of usb_samp_buffer and usb_bulk_buffer are set in ldscripts. If - * you change the name of these variables, they won't be where they need to - * be in the processor's address space, unless you also adjust the ldscripts. +/* Address of usb_bulk_buffer is set in ldscripts. If you change the name of this + * variable, it won't be where it needs to be in the processor's address space, + * unless you also adjust the ldscripts. */ -extern uint8_t usb_samp_buffer[USB_SAMP_BUFFER_SIZE]; extern uint8_t usb_bulk_buffer[USB_BULK_BUFFER_SIZE]; + +#endif /*__USB_BULK_BUFFER_H__*/ diff --git a/firmware/hackrf_usb/usb_descriptor.c b/firmware/hackrf_usb/usb_descriptor.c index dde22e6e..70c4daf1 100644 --- a/firmware/hackrf_usb/usb_descriptor.c +++ b/firmware/hackrf_usb/usb_descriptor.c @@ -1,5 +1,5 @@ /* - * Copyright 2012-2026 Great Scott Gadgets + * Copyright 2012-2022 Great Scott Gadgets * Copyright 2012 Jared Boone * * This file is part of HackRF. @@ -20,15 +20,24 @@ * Boston, MA 02110-1301, USA. */ -#include "usb_descriptor.h" - #include -#include +#include "usb_type.h" +#include "usb_descriptor.h" #define USB_VENDOR_ID (0x1D50) -#define USB_API_VERSION (0x0113) +#if (defined HACKRF_ONE || defined PRALINE) + #define USB_PRODUCT_ID (0x6089) +#elif JAWBREAKER + #define USB_PRODUCT_ID (0x604B) +#elif RAD1O + #define USB_PRODUCT_ID (0xCC15) +#else + #define USB_PRODUCT_ID (0xFFFF) +#endif + +#define USB_API_VERSION (0x0109) #define USB_WORD(x) (x & 0xFF), ((x >> 8) & 0xFF) @@ -41,8 +50,7 @@ #define USB_STRING_LANGID (0x0409) -#if defined(IS_HACKRF_ONE) || defined(IS_PRALINE) -uint8_t usb_descriptor_device_hackrf[] = { +uint8_t usb_descriptor_device[] = { 18, // bLength USB_DESCRIPTOR_TYPE_DEVICE, // bDescriptorType USB_WORD(0x0200), // bcdUSB @@ -51,50 +59,13 @@ uint8_t usb_descriptor_device_hackrf[] = { 0x00, // bDeviceProtocol USB_MAX_PACKET0, // bMaxPacketSize0 USB_WORD(USB_VENDOR_ID), // idVendor - USB_WORD(0x6089), // idProduct + USB_WORD(USB_PRODUCT_ID), // idProduct USB_WORD(USB_API_VERSION), // bcdDevice 0x01, // iManufacturer 0x02, // iProduct 0x04, // iSerialNumber 0x01 // bNumConfigurations }; -#endif -#ifdef IS_JAWBREAKER -uint8_t usb_descriptor_device_jawbreaker[] = { - 18, // bLength - USB_DESCRIPTOR_TYPE_DEVICE, // bDescriptorType - USB_WORD(0x0200), // bcdUSB - 0x00, // bDeviceClass - 0x00, // bDeviceSubClass - 0x00, // bDeviceProtocol - USB_MAX_PACKET0, // bMaxPacketSize0 - USB_WORD(USB_VENDOR_ID), // idVendor - USB_WORD(0x604B), // idProduct - USB_WORD(USB_API_VERSION), // bcdDevice - 0x01, // iManufacturer - 0x02, // iProduct - 0x04, // iSerialNumber - 0x01 // bNumConfigurations -}; -#endif -#ifdef IS_RAD1O -uint8_t usb_descriptor_device_rad1o[] = { - 18, // bLength - USB_DESCRIPTOR_TYPE_DEVICE, // bDescriptorType - USB_WORD(0x0200), // bcdUSB - 0x00, // bDeviceClass - 0x00, // bDeviceSubClass - 0x00, // bDeviceProtocol - USB_MAX_PACKET0, // bMaxPacketSize0 - USB_WORD(USB_VENDOR_ID), // idVendor - USB_WORD(0xCC15), // idProduct - USB_WORD(USB_API_VERSION), // bcdDevice - 0x01, // iManufacturer - 0x02, // iProduct - 0x04, // iSerialNumber - 0x01 // bNumConfigurations -}; -#endif uint8_t usb_descriptor_device_qualifier[] = { 10, // bLength @@ -213,8 +184,8 @@ uint8_t usb_descriptor_string_manufacturer[] = { 's', 0x00, }; -#ifdef IS_HACKRF_ONE -uint8_t usb_descriptor_string_product_hackrf_one[] = { +uint8_t usb_descriptor_string_product[] = { +#ifdef HACKRF_ONE 22, // bLength USB_DESCRIPTOR_TYPE_STRING, // bDescriptorType 'H', 0x00, @@ -227,26 +198,7 @@ uint8_t usb_descriptor_string_product_hackrf_one[] = { 'O', 0x00, 'n', 0x00, 'e', 0x00, -}; -#endif -#ifdef IS_PRALINE -uint8_t usb_descriptor_string_product_praline[] = { - 22, // bLength - USB_DESCRIPTOR_TYPE_STRING, // bDescriptorType - 'H', 0x00, - 'a', 0x00, - 'c', 0x00, - 'k', 0x00, - 'R', 0x00, - 'F', 0x00, - ' ', 0x00, - 'P', 0x00, - 'r', 0x00, - 'o', 0x00, -}; -#endif -#ifdef IS_JAWBREAKER -uint8_t usb_descriptor_string_product_jawbreaker[] = { +#elif JAWBREAKER 36, // bLength USB_DESCRIPTOR_TYPE_STRING, // bDescriptorType 'H', 0x00, @@ -266,10 +218,7 @@ uint8_t usb_descriptor_string_product_jawbreaker[] = { 'k', 0x00, 'e', 0x00, 'r', 0x00, -}; -#endif -#ifdef IS_RAD1O -uint8_t usb_descriptor_string_product_rad1o[] = { +#elif RAD1O 12, // bLength USB_DESCRIPTOR_TYPE_STRING, // bDescriptorType 'r', 0x00, @@ -277,8 +226,30 @@ uint8_t usb_descriptor_string_product_rad1o[] = { 'd', 0x00, '1', 0x00, 'o', 0x00, -}; +#elif PRALINE + 22, // bLength + USB_DESCRIPTOR_TYPE_STRING, // bDescriptorType + 'H', 0x00, + 'a', 0x00, + 'c', 0x00, + 'k', 0x00, + 'R', 0x00, + 'F', 0x00, + ' ', 0x00, + 'P', 0x00, + 'r', 0x00, + 'o', 0x00, +#else + 14, // bLength + USB_DESCRIPTOR_TYPE_STRING, // bDescriptorType + 'H', 0x00, + 'a', 0x00, + 'c', 0x00, + 'k', 0x00, + 'R', 0x00, + 'F', 0x00, #endif +}; uint8_t usb_descriptor_string_config_description[] = { 24, // bLength @@ -319,46 +290,14 @@ uint8_t usb_descriptor_string_serial_number[] = { uint8_t usb_descriptor_string_serial_number[USB_DESCRIPTOR_STRING_SERIAL_BUF_LEN]; #endif -#ifdef IS_HACKRF_ONE -uint8_t* usb_descriptor_strings_hackrf_one[] = { +uint8_t* usb_descriptor_strings[] = { usb_descriptor_string_languages, usb_descriptor_string_manufacturer, - usb_descriptor_string_product_hackrf_one, + usb_descriptor_string_product, usb_descriptor_string_config_description, usb_descriptor_string_serial_number, 0, // TERMINATOR }; -#endif -#ifdef IS_PRALINE -uint8_t* usb_descriptor_strings_praline[] = { - usb_descriptor_string_languages, - usb_descriptor_string_manufacturer, - usb_descriptor_string_product_praline, - usb_descriptor_string_config_description, - usb_descriptor_string_serial_number, - 0, // TERMINATOR -}; -#endif -#ifdef IS_JAWBREAKER -uint8_t* usb_descriptor_strings_jawbreaker[] = { - usb_descriptor_string_languages, - usb_descriptor_string_manufacturer, - usb_descriptor_string_product_jawbreaker, - usb_descriptor_string_config_description, - usb_descriptor_string_serial_number, - 0, // TERMINATOR -}; -#endif -#ifdef IS_RAD1O -uint8_t* usb_descriptor_strings_rad1o[] = { - usb_descriptor_string_languages, - usb_descriptor_string_manufacturer, - usb_descriptor_string_product_rad1o, - usb_descriptor_string_config_description, - usb_descriptor_string_serial_number, - 0, // TERMINATOR -}; -#endif uint8_t wcid_string_descriptor[] = { 18, // bLength diff --git a/firmware/hackrf_usb/usb_descriptor.h b/firmware/hackrf_usb/usb_descriptor.h index bd43f4aa..2c2990e0 100644 --- a/firmware/hackrf_usb/usb_descriptor.h +++ b/firmware/hackrf_usb/usb_descriptor.h @@ -20,46 +20,22 @@ * Boston, MA 02110-1301, USA. */ -#pragma once - #include -#if defined(IS_HACKRF_ONE) || defined(IS_PRALINE) -extern uint8_t usb_descriptor_device_hackrf[]; -#endif -#ifdef IS_JAWBREAKER -extern uint8_t usb_descriptor_device_jawbreaker[]; -#endif -#ifdef IS_RAD1O -extern uint8_t usb_descriptor_device_rad1o[]; -#endif +extern uint8_t usb_descriptor_device[]; extern uint8_t usb_descriptor_device_qualifier[]; extern uint8_t usb_descriptor_configuration_full_speed[]; extern uint8_t usb_descriptor_configuration_high_speed[]; extern uint8_t usb_descriptor_string_languages[]; extern uint8_t usb_descriptor_string_manufacturer[]; -#ifdef IS_HACKRF_ONE -extern uint8_t usb_descriptor_string_product_hackrf_one[]; -#endif -#ifdef IS_PRALINE -extern uint8_t usb_descriptor_string_product_praline[]; -#endif -#ifdef IS_JAWBREAKER -extern uint8_t usb_descriptor_string_product_jawbreaker[]; -#endif -#ifdef IS_RAD1O -extern uint8_t usb_descriptor_string_product_rad1o[]; -#endif +extern uint8_t usb_descriptor_string_product[]; #define USB_DESCRIPTOR_STRING_SERIAL_LEN 32 #define USB_DESCRIPTOR_STRING_SERIAL_BUF_LEN \ (USB_DESCRIPTOR_STRING_SERIAL_LEN * 2 + 2) /* UTF-16LE */ extern uint8_t usb_descriptor_string_serial_number[]; -extern uint8_t* usb_descriptor_strings_hackrf_one[]; -extern uint8_t* usb_descriptor_strings_jawbreaker[]; -extern uint8_t* usb_descriptor_strings_rad1o[]; -extern uint8_t* usb_descriptor_strings_praline[]; +extern uint8_t* usb_descriptor_strings[]; #define USB_WCID_VENDOR_REQ 0x19 extern uint8_t wcid_string_descriptor[]; diff --git a/firmware/hackrf_usb/usb_device.c b/firmware/hackrf_usb/usb_device.c index 90347e17..b689ce9f 100644 --- a/firmware/hackrf_usb/usb_device.c +++ b/firmware/hackrf_usb/usb_device.c @@ -45,49 +45,12 @@ usb_configuration_t* usb_configurations[] = { 0, }; -usb_device_t usb_device; - -#ifdef IS_HACKRF_ONE -const usb_device_t usb_device_hackrf_one = { - .descriptor = usb_descriptor_device_hackrf, - .descriptor_strings = usb_descriptor_strings_hackrf_one, +usb_device_t usb_device = { + .descriptor = usb_descriptor_device, + .descriptor_strings = usb_descriptor_strings, .qualifier_descriptor = usb_descriptor_device_qualifier, .configurations = &usb_configurations, .configuration = 0, .wcid_string_descriptor = wcid_string_descriptor, .wcid_feature_descriptor = wcid_feature_descriptor, }; -#endif -#ifdef IS_PRALINE -const usb_device_t usb_device_praline = { - .descriptor = usb_descriptor_device_hackrf, - .descriptor_strings = usb_descriptor_strings_praline, - .qualifier_descriptor = usb_descriptor_device_qualifier, - .configurations = &usb_configurations, - .configuration = 0, - .wcid_string_descriptor = wcid_string_descriptor, - .wcid_feature_descriptor = wcid_feature_descriptor, -}; -#endif -#ifdef IS_JAWBREAKER -const usb_device_t usb_device_jawbreaker = { - .descriptor = usb_descriptor_device_jawbreaker, - .descriptor_strings = usb_descriptor_strings_jawbreaker, - .qualifier_descriptor = usb_descriptor_device_qualifier, - .configurations = &usb_configurations, - .configuration = 0, - .wcid_string_descriptor = wcid_string_descriptor, - .wcid_feature_descriptor = wcid_feature_descriptor, -}; -#endif -#ifdef IS_RAD1O -const usb_device_t usb_device_rad1o = { - .descriptor = usb_descriptor_device_rad1o, - .descriptor_strings = usb_descriptor_strings_rad1o, - .qualifier_descriptor = usb_descriptor_device_qualifier, - .configurations = &usb_configurations, - .configuration = 0, - .wcid_string_descriptor = wcid_string_descriptor, - .wcid_feature_descriptor = wcid_feature_descriptor, -}; -#endif diff --git a/firmware/hackrf_usb/usb_device.h b/firmware/hackrf_usb/usb_device.h index 5ef53360..05008dca 100644 --- a/firmware/hackrf_usb/usb_device.h +++ b/firmware/hackrf_usb/usb_device.h @@ -21,21 +21,11 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __USB_DEVICE_H__ +#define __USB_DEVICE_H__ #include extern usb_device_t usb_device; -#ifdef IS_HACKRF_ONE -extern const usb_device_t usb_device_hackrf_one; -#endif -#ifdef IS_PRALINE -extern const usb_device_t usb_device_praline; -#endif -#ifdef IS_JAWBREAKER -extern const usb_device_t usb_device_jawbreaker; -#endif -#ifdef IS_RAD1O -extern const usb_device_t usb_device_rad1o; -#endif +#endif /* end of include guard: __USB_DEVICE_H__ */ diff --git a/firmware/hackrf_usb/usb_endpoint.c b/firmware/hackrf_usb/usb_endpoint.c index 81251f1e..02832708 100644 --- a/firmware/hackrf_usb/usb_endpoint.c +++ b/firmware/hackrf_usb/usb_endpoint.c @@ -23,19 +23,16 @@ #include "usb_endpoint.h" -#include #include -#include #include "usb_device.h" -#include "usb_api_transceiver.h" usb_endpoint_t usb_endpoint_control_out = { .address = 0x00, .device = &usb_device, .in = &usb_endpoint_control_in, .out = &usb_endpoint_control_out, - .setup_complete = transceiver_usb_setup_complete, + .setup_complete = usb_setup_complete, .transfer_complete = usb_control_out_complete, }; USB_DEFINE_QUEUE(usb_endpoint_control_out, 4); diff --git a/firmware/hackrf_usb/usb_endpoint.h b/firmware/hackrf_usb/usb_endpoint.h index e96094f6..7a594cd5 100644 --- a/firmware/hackrf_usb/usb_endpoint.h +++ b/firmware/hackrf_usb/usb_endpoint.h @@ -21,10 +21,11 @@ * Boston, MA 02110-1301, USA. */ -#pragma once +#ifndef __USB_ENDPOINT_H__ +#define __USB_ENDPOINT_H__ -#include #include +#include extern usb_endpoint_t usb_endpoint_control_out; extern USB_DECLARE_QUEUE(usb_endpoint_control_out); @@ -37,3 +38,5 @@ extern USB_DECLARE_QUEUE(usb_endpoint_bulk_in); extern usb_endpoint_t usb_endpoint_bulk_out; extern USB_DECLARE_QUEUE(usb_endpoint_bulk_out); + +#endif /* end of include guard: __USB_ENDPOINT_H__ */ diff --git a/firmware/include-what-you-use.cmake b/firmware/include-what-you-use.cmake deleted file mode 100644 index 37e2a2a6..00000000 --- a/firmware/include-what-you-use.cmake +++ /dev/null @@ -1,54 +0,0 @@ -# Copyright 2026 Great Scott Gadgets -# -# This file is part of HackRF. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2, or (at your option) -# any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; see the file COPYING. If not, write to -# the Free Software Foundation, Inc., 51 Franklin Street, -# Boston, MA 02110-1301, USA. -# - -cmake_minimum_required(VERSION 3.10.0) - -find_program(IWYU_COMMAND NAMES include-what-you-use) -if(NOT IWYU_COMMAND) - message(FATAL_ERROR "Could not find the include-what-you-use executable.") -endif() - -# include-what-you-use arguments: -# -# --no_fwd_decls - Disable forward declaration suggestions. -# --keep - Always keep the specified include. -# --mapping_file - Specify mapping files for excluding suggestions. -# -w - Disable spurious clang warnings. -# -# NOTE: We specify '--keep platform_detect.h' due to iwyu 0.23 not -# being able to detect usage of symbols within preprocessor -# macros. This results in false positives for the removal of the -# include. -# -# The alternate solution is to use "// IWYU pragma: always-keep" -# within "platform_detect.h" itself but this triggers the -# angle-quote-curse on 0.23. (e.g. https://github.com/include-what-you-use/include-what-you-use/issues/1087) -# -# iwyu versions from at least 0.26 onwards do not suffer from these -# problems which will allow us to remove it in future. -# -list(APPEND IWYU_COMMAND - -Xiwyu --no_fwd_decls - -Xiwyu --keep=${CMAKE_SOURCE_DIR}/common/platform_detect.h - -Xiwyu --mapping_file=${CMAKE_SOURCE_DIR}/libopencm3.imp - -w) - -set(CMAKE_C_INCLUDE_WHAT_YOU_USE ${IWYU_COMMAND}) -set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE ${IWYU_COMMAND}) diff --git a/firmware/libopencm3 b/firmware/libopencm3 index a0bb9979..cfc2f345 160000 --- a/firmware/libopencm3 +++ b/firmware/libopencm3 @@ -1 +1 @@ -Subproject commit a0bb997968bf57c87f2aa4e389a63219580bb5c3 +Subproject commit cfc2f3451486f6f05cc5e05ff6b5308269980fe3 diff --git a/firmware/libopencm3.imp b/firmware/libopencm3.imp deleted file mode 100644 index 1cf19631..00000000 --- a/firmware/libopencm3.imp +++ /dev/null @@ -1,11 +0,0 @@ -# include-what-you-use mapping file for libopencm3/ -# -# Usage: include-what-you-use -Xiwyu;--mapping_file=libopencm3.imp - -[ - # allow libopencm3 to take responsibility for architecture-specific dispatch of nvic.h includes - { "include": ["", "private", "", "public"] }, - { "include": ["\"libopencm3/lpc43xx/m0/nvic.h\"", "private", "", "public"] }, - { "include": ["", "private", "", "public"] }, - { "include": ["\"libopencm3/lpc43xx/m4/nvic.h\"", "private", "", "public"] }, -] diff --git a/firmware/platform-detect.cmake b/firmware/platform-detect.cmake deleted file mode 100644 index dcaeba58..00000000 --- a/firmware/platform-detect.cmake +++ /dev/null @@ -1,87 +0,0 @@ -# Copyright 2026 Great Scott Gadgets -# -# This file is part of HackRF. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2, or (at your option) -# any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; see the file COPYING. If not, write to -# the Free Software Foundation, Inc., 51 Franklin Street, -# Boston, MA 02110-1301, USA. -# - -cmake_minimum_required(VERSION 3.12.0) - -if(BOARD STREQUAL "UNIVERSAL") - add_compile_definitions( - "IS_PRALINE=(detected_platform() == BOARD_ID_PRALINE)" - "IS_NOT_PRALINE=(!IS_PRALINE)" - "IS_HACKRF_ONE=( \ - detected_platform() == BOARD_ID_HACKRF1_OG || \ - detected_platform() == BOARD_ID_HACKRF1_R9 \ - )" - "IS_NOT_HACKRF_ONE=(!IS_HACKRF_ONE)" - "IS_H1_R9=(detected_platform() == BOARD_ID_HACKRF1_R9)" - "IS_NOT_H1_R9=(!IS_H1_R9)" - "IS_NOT_RAD1O=1" - "IS_NOT_JAWBREAKER=1" - "IS_H1_OR_PRALINE=1" - "IS_H1_OR_RAD1O=IS_HACKRF_ONE" - "IS_H1_OR_JAWBREAKER=IS_HACKRF_ONE" - "IS_FOUR_LEDS=IS_PRALINE" - "IS_EXPANSION_COMPATIBLE=1" - ) -elseif(BOARD STREQUAL "HACKRF_ONE") - add_compile_definitions( - "IS_NOT_PRALINE=1" - "IS_HACKRF_ONE=1" - "IS_H1_R9=(detected_platform() == BOARD_ID_HACKRF1_R9)" - "IS_NOT_H1_R9=(!IS_H1_R9)" - "IS_NOT_RAD1O=1" - "IS_NOT_JAWBREAKER=1" - "IS_H1_OR_PRALINE=1" - "IS_H1_OR_RAD1O=1" - "IS_H1_OR_JAWBREAKER=1" - "IS_EXPANSION_COMPATIBLE=1" - ) -elseif(BOARD STREQUAL "PRALINE") - add_compile_definitions( - "IS_PRALINE=1" - "IS_NOT_HACKRF_ONE=1" - "IS_NOT_H1_R9=1" - "IS_NOT_RAD1O=1" - "IS_NOT_JAWBREAKER=1" - "IS_H1_OR_PRALINE=1" - "IS_FOUR_LEDS=1" - "IS_EXPANSION_COMPATIBLE=1" - ) -elseif(BOARD STREQUAL "RAD1O") - add_compile_definitions( - "IS_NOT_PRALINE=1" - "IS_NOT_HACKRF_ONE=1" - "IS_NOT_H1_R9=1" - "IS_RAD1O=1" - "IS_NOT_JAWBREAKER=1" - "IS_H1_OR_RAD1O=1" - "IS_FOUR_LEDS=1" - ) -elseif(BOARD STREQUAL "JAWBREAKER") - add_compile_definitions( - "IS_NOT_PRALINE=1" - "IS_NOT_HACKRF_ONE=1" - "IS_NOT_H1_R9=1" - "IS_NOT_RAD1O=1" - "IS_JAWBREAKER=1" - "IS_H1_OR_JAWBREAKER=1" - ) -else() - message(FATAL_ERROR "No recognized platform defined: ${BOARD}") -endif() diff --git a/firmware/tools/edit-font.py b/firmware/tools/edit-font.py deleted file mode 100644 index 9e03467a..00000000 --- a/firmware/tools/edit-font.py +++ /dev/null @@ -1,107 +0,0 @@ -# Tool to extract font data, save to bitmap file, and apply modifications -# to source code after editing the bitmap. - -from __future__ import print_function -from matplotlib.pyplot import imread, imsave, imshow, show -import numpy as np -import sys -import re - -if len(sys.argv) != 3: - print("Usage: %s { show | extract | insert}" % sys.argv[0]) - sys.exit(1) - -font_name = sys.argv[1] -mode = sys.argv[2] - -# Where to find the font data - may need updated if code has changed. -source_file = 'firmware/common/ui_portapack.c' -data_marker = f'static const uint8_t {font_name}_glyph_data[] = {{' -data_offset = 1 # Data starts this number of lines after start marker. -end_pattern = '(.*)};$' # Indicates end of font data. -def_marker = f'static const ui_font_t {font_name} =' -def_offset = 1 -def_pattern = '^\t{{(?P\\d+), (?P\\d+)}' - -# Image filename used in extract and insert modes. -image_file = f'{font_name}.png' - -# Get the literals used to populate the font array in the source file -lines = [line.rstrip() for line in open(source_file).readlines()] -try: - start = lines.index(data_marker) + data_offset -except ValueError: - print(f"Could not find glyph data for font '{font_name}'") - sys.exit(1) - -data = str() -for line in lines[start:]: - if match := re.match(end_pattern, line): - data += match.group(1) - break - else: - data += line - -# Get the width and height from the font definition. -try: - def_start = lines.index(def_marker) -except ValueError: - print(f"Could not find definition for font '{font_name}'") - sys.exit(1) - -def_match = re.match(def_pattern, lines[def_start + def_offset]) - -if def_match is None: - print(f"Failed to parse definition of '{font_name}'") - -width = int(def_match.group('width')) -height = int(def_match.group('height')) - -# Eval the literals to get the values into a numpy array -packed = eval("np.array([%s], np.uint8)" % data) - -# Reorganise into a monochrome image. -chars_per_row = 5 -unpacked = np.unpackbits(packed) -bitmaps = (unpacked - .reshape(-1, height, width // 8, 8)[:,:,::-1,:] - .reshape(-1, height, width)[:,:,::-1] -) -indices = np.arange(len(bitmaps)).reshape(-1, chars_per_row) -image = np.block([[bitmaps[idx] for idx in row] for row in indices]) - -if mode == 'show': - # Display font image - imshow(image, cmap='binary') - show() - -elif mode == 'extract': - # Save font image - imsave(image_file, image, format='png', cmap='binary') - -elif mode == 'insert': - # Read in modified font image - image = imread(image_file)[:,:,0].astype(bool) - - # Reorganise back to original order - rows = image.reshape(-1, height, image.shape[1]) - single_row_image = np.hstack(rows) - num_chars = single_row_image.shape[1] // width - bitmaps = np.array(np.split(single_row_image, num_chars, 1)) - unpacked = (bitmaps - [:,:,::-1].reshape(-1, height, width // 8, 8) - [:,:,::-1,:].reshape(-1) - ) - packed = ~np.packbits(unpacked) - - # Replace lines of file in same format as used before - bytes_per_row = 13 - split_indices = np.arange(bytes_per_row, len(packed), bytes_per_row) - for i, group in enumerate(np.split(packed, split_indices)): - line = ("\t0x%02x," + " 0x%02x," * (len(group) - 1)) % tuple(group) - if len(group) < bytes_per_row: - line = line[:-1] + "};" - lines[start + i] = line - - # Write out modified source file - open(source_file, 'w').writelines([line + "\n" for line in lines]) diff --git a/host/cmake/set_release.cmake b/host/cmake/set_release.cmake index 60111b95..ecc0ad69 100644 --- a/host/cmake/set_release.cmake +++ b/host/cmake/set_release.cmake @@ -8,7 +8,7 @@ if(NOT DEFINED RELEASE) OUTPUT_STRIP_TRAILING_WHITESPACE ) if (GIT_EXIT_VALUE) - set(RELEASE "2026.01.3+") + set(RELEASE "2026.01.2+") else (GIT_EXIT_VALUE) execute_process( COMMAND git status -s --untracked-files=no diff --git a/host/hackrf-tools/src/hackrf_clock.c b/host/hackrf-tools/src/hackrf_clock.c index 01c2c800..36f066c1 100644 --- a/host/hackrf-tools/src/hackrf_clock.c +++ b/host/hackrf-tools/src/hackrf_clock.c @@ -103,19 +103,6 @@ int parse_p2_ctrl_signal(char* s, enum p2_ctrl_signal* const signal) return HACKRF_SUCCESS; } -int parse_clkin_ctrl_signal(char* s, enum clkin_ctrl_signal* const signal) -{ - if (strcasecmp("p1", s) == 0) { - *signal = CLKIN_SIGNAL_P1; - } else if (strcasecmp("p22", s) == 0) { - *signal = CLKIN_SIGNAL_P22; - } else { - fprintf(stderr, "Invalid signal '%s'\n", s); - return HACKRF_ERROR_INVALID_PARAM; - } - return HACKRF_SUCCESS; -} - int si5351c_read_register(hackrf_device* device, const uint16_t register_number) { uint16_t register_value; @@ -308,8 +295,6 @@ static void usage() printf("\tone of: clkin, trigger_in, trigger_out, p22_clkin, pps_out, aux_clk1, aux_clk2, off\n"); printf("\t-2, --p2 : select the signal for the HackRF Pro P2 SMA connector (default: clkout)\n"); printf("\tone of: clkout, trigger_in, trigger_out\n"); - printf("\t-c, --clkin-ctrl : select the HackRF Pro CLKIN signal (default: p1)\n"); - printf("\tone of: p1, p22\n"); printf("\t-d, --device : Serial number of desired HackRF.\n"); printf("\nExamples:\n"); printf("\thackrf_clock -r 3 : prints settings for CLKOUT\n"); @@ -323,7 +308,6 @@ static struct option long_options[] = { {"clkout", required_argument, 0, 'o'}, {"p1", required_argument, 0, '1'}, {"p2", required_argument, 0, '2'}, - {"clkin-ctrl", required_argument, 0, 'c'}, {"device", required_argument, 0, 'd'}, {0, 0, 0, 0}, }; @@ -340,10 +324,8 @@ int main(int argc, char** argv) uint8_t clkin_status; bool p1_ctrl = false; bool p2_ctrl = false; - bool clkin_ctrl = false; enum p1_ctrl_signal p1_signal = P1_SIGNAL_CLKIN; enum p2_ctrl_signal p2_signal = P2_SIGNAL_CLK3; - enum clkin_ctrl_signal clkin_signal = CLKIN_SIGNAL_P1; const char* serial_number = NULL; int result = hackrf_init(); @@ -357,7 +339,7 @@ int main(int argc, char** argv) while ((opt = getopt_long( argc, argv, - "r:aio:1:2:c:d:h?", + "r:aio:1:2:d:h?", long_options, &option_index)) != EOF) { switch (opt) { @@ -389,11 +371,6 @@ int main(int argc, char** argv) result = parse_p2_ctrl_signal(optarg, &p2_signal); break; - case 'c': - clkin_ctrl = true; - result = parse_clkin_ctrl_signal(optarg, &clkin_signal); - break; - case 'd': serial_number = optarg; break; @@ -417,7 +394,7 @@ int main(int argc, char** argv) } } - if (!clkin && !clkout && !read && !p1_ctrl && !p2_ctrl && !clkin_ctrl) { + if (!clkin && !clkout && !read && !p1_ctrl && !p2_ctrl) { fprintf(stderr, "An operation must be specified.\n"); usage(); return EXIT_FAILURE; @@ -483,16 +460,6 @@ int main(int argc, char** argv) } } - if (clkin_ctrl) { - result = hackrf_set_clkin_ctrl(device, clkin_signal); - if (result != HACKRF_SUCCESS) { - printf("hackrf_set_clkin_ctrl() failed: %s (%d)\n", - hackrf_error_name(result), - result); - return EXIT_FAILURE; - } - } - result = hackrf_close(device); if (result) { printf("hackrf_close() failed: %s (%d)\n", diff --git a/host/hackrf-tools/src/hackrf_debug.c b/host/hackrf-tools/src/hackrf_debug.c index 5f8785b5..b3045b18 100644 --- a/host/hackrf-tools/src/hackrf_debug.c +++ b/host/hackrf-tools/src/hackrf_debug.c @@ -1,5 +1,5 @@ /* - * Copyright 2012-2026 Great Scott Gadgets + * Copyright 2012-2022 Great Scott Gadgets * Copyright 2012 Jared Boone * Copyright 2013 Benjamin Vernoux * Copyright 2017 Dominic Spill @@ -29,7 +29,6 @@ #include #include #include -#include #define REGISTER_INVALID 32767 @@ -40,14 +39,13 @@ enum parts { PART_RFFC5072 = 3, PART_MAX2831 = 4, PART_GATEWARE = 5, - PART_RADIO = 6, }; -int parse_int(char* s, uint64_t* const value) +int parse_int(char* s, uint32_t* const value) { uint_fast8_t base = 10; char* s_end; - long long ll_value; + long long_value; if (strlen(s) > 2) { if (s[0] == '0') { @@ -62,9 +60,9 @@ int parse_int(char* s, uint64_t* const value) } s_end = s; - ll_value = strtoull(s, &s_end, base); + long_value = strtol(s, &s_end, base); if ((s != s_end) && (*s_end == 0)) { - *value = (uint64_t) ll_value; + *value = (uint32_t) long_value; return HACKRF_SUCCESS; } else { return HACKRF_ERROR_INVALID_PARAM; @@ -475,81 +473,7 @@ int fpga_write_register( return result; } -int radio_read_register( - hackrf_device* device, - const uint8_t bank, - const uint16_t register_number) -{ - uint64_t register_value; - int result = hackrf_radio_read_register( - device, - bank, - (uint8_t) register_number, - ®ister_value); - - if (result == HACKRF_SUCCESS) { - printf("bank %d register [%2d] -> 0x%016" PRIx64 "\n", - bank, - register_number, - register_value); - } else { - printf("hackrf_radio_read_register() failed: %s (%d)\n", - hackrf_error_name(result), - result); - } - - return result; -} - -#define RADIO_NUM_REGS (24) - -int radio_read_registers(hackrf_device* device, const uint8_t bank) -{ - uint16_t register_number; - int result = HACKRF_SUCCESS; - - for (register_number = 0; register_number < RADIO_NUM_REGS; register_number++) { - result = radio_read_register(device, bank, register_number); - if (result != HACKRF_SUCCESS) { - break; - } - } - - return result; -} - -int radio_write_register( - hackrf_device* device, - const uint8_t bank, - const uint16_t register_number, - const uint64_t register_value) -{ - int result = HACKRF_SUCCESS; - result = hackrf_radio_write_register( - device, - bank, - (uint8_t) register_number, - register_value); - - if (result == HACKRF_SUCCESS) { - printf("bank %d 0x%016" PRIx64 " -> [%2d]\n", - bank, - register_value, - register_number); - } else { - printf("hackrf_radio_write_register() failed: %s (%d)\n", - hackrf_error_name(result), - result); - } - - return result; -} - -int read_register( - hackrf_device* device, - uint8_t part, - const uint8_t bank, - const uint16_t register_number) +int read_register(hackrf_device* device, uint8_t part, const uint16_t register_number) { switch (part) { case PART_MAX2837: @@ -561,13 +485,11 @@ int read_register( return rffc5072_read_register(device, register_number); case PART_GATEWARE: return fpga_read_register(device, register_number); - case PART_RADIO: - return radio_read_register(device, bank, register_number); } return HACKRF_ERROR_INVALID_PARAM; } -int read_registers(hackrf_device* device, uint8_t part, const uint8_t bank) +int read_registers(hackrf_device* device, uint8_t part) { switch (part) { case PART_MAX2837: @@ -579,8 +501,6 @@ int read_registers(hackrf_device* device, uint8_t part, const uint8_t bank) return rffc5072_read_registers(device); case PART_GATEWARE: return fpga_read_registers(device); - case PART_RADIO: - return radio_read_registers(device, bank); } return HACKRF_ERROR_INVALID_PARAM; } @@ -588,9 +508,8 @@ int read_registers(hackrf_device* device, uint8_t part, const uint8_t bank) int write_register( hackrf_device* device, uint8_t part, - const uint8_t bank, const uint16_t register_number, - const uint64_t register_value) + const uint16_t register_value) { switch (part) { case PART_MAX2837: @@ -598,25 +517,14 @@ int write_register( return max283x_write_register( device, register_number, - (uint16_t) register_value, + register_value, part); case PART_SI5351C: - return si5351c_write_register( - device, - register_number, - (uint16_t) register_value); + return si5351c_write_register(device, register_number, register_value); case PART_RFFC5072: - return rffc5072_write_register( - device, - register_number, - (uint16_t) register_value); + return rffc5072_write_register(device, register_number, register_value); case PART_GATEWARE: - return fpga_write_register( - device, - register_number, - (uint16_t) register_value); - case PART_RADIO: - return radio_write_register(device, bank, register_number, register_value); + return fpga_write_register(device, register_number, register_value); } return HACKRF_ERROR_INVALID_PARAM; } @@ -671,7 +579,6 @@ static void usage() { printf("\nUsage:\n"); printf("\t-h, --help: this help\n"); - printf("\t-b, --bank : set register bank for read/write operations (default 0)\n"); printf("\t-n, --register : set register number for read/write operations\n"); printf("\t-r, --read: read register specified by last -n argument, or all registers\n"); printf("\t-w, --write : write register specified by last -n argument with value \n"); @@ -681,7 +588,6 @@ static void usage() printf("\t-s, --si5351c: target SI5351C\n"); printf("\t-f, --rffc5072: target RFFC5072\n"); printf("\t-g, --gateware: target gateware registers\n"); - printf("\t-i, --radio: target radio registers\n"); printf("\t-P, --fpga : load the n-th bitstream to the FPGA\n"); printf("\t-1, --p1 : P1 control\n"); printf("\t-2, --p2 : P2 control\n"); @@ -705,7 +611,6 @@ static void usage() static struct option long_options[] = { {"config", no_argument, 0, 'c'}, - {"bank", required_argument, 0, 'b'}, {"register", required_argument, 0, 'n'}, {"write", required_argument, 0, 'w'}, {"read", no_argument, 0, 'r'}, @@ -716,7 +621,6 @@ static struct option long_options[] = { {"si5351c", no_argument, 0, 's'}, {"rffc5072", no_argument, 0, 'f'}, {"gateware", no_argument, 0, 'g'}, - {"radio", no_argument, 0, 'i'}, {"fpga", required_argument, 0, 'P'}, {"p1", required_argument, 0, '1'}, {"p2", required_argument, 0, '2'}, @@ -737,9 +641,8 @@ int main(int argc, char** argv) { int opt; uint8_t board_id = BOARD_ID_UNDETECTED; - int bank = -1; - uint64_t register_number = REGISTER_INVALID; - uint64_t register_value; + uint32_t register_number = REGISTER_INVALID; + uint32_t register_value; hackrf_device* device = NULL; int option_index = 0; bool read = false; @@ -749,17 +652,17 @@ int main(int argc, char** argv) uint8_t part = PART_NONE; const char* serial_number = NULL; bool set_ui = false; - uint64_t ui_enable; + uint32_t ui_enable; bool set_leds = false; - uint64_t led_state; - uint64_t tx_limit; - uint64_t rx_limit; - uint64_t p1_state; - uint64_t p2_state; - uint64_t clkin_state; - uint64_t narrowband_state; - uint64_t bitstream_index; - uint64_t adc_channel; + uint32_t led_state; + uint32_t tx_limit; + uint32_t rx_limit; + uint32_t p1_state; + uint32_t p2_state; + uint32_t clkin_state; + uint32_t narrowband_state; + uint32_t bitstream_index; + uint32_t adc_channel; bool set_tx_limit = false; bool set_rx_limit = false; bool set_p1 = false; @@ -782,16 +685,10 @@ int main(int argc, char** argv) while ((opt = getopt_long( argc, argv, - "b:n:rw:d:cmsfgi1:2:C:N:P:ST:R:h?u:l:ta:o", + "n:rw:d:cmsfg1:2:C:N:P:ST:R:h?u:l:ta:o", long_options, &option_index)) != EOF) { switch (opt) { - case 'b': - uint64_t bank_arg; - result = parse_int(optarg, &bank_arg); - bank = (int) bank_arg; - break; - case 'n': result = parse_int(optarg, ®ister_number); break; @@ -858,14 +755,6 @@ int main(int argc, char** argv) part = PART_GATEWARE; break; - case 'i': - if (part != PART_NONE) { - fprintf(stderr, "Only one part can be specified.'\n"); - return EXIT_FAILURE; - } - part = PART_RADIO; - break; - case '1': set_p1 = true; result = parse_int(optarg, &p1_state); @@ -949,16 +838,6 @@ int main(int argc, char** argv) return EXIT_FAILURE; } - if ((bank > -1) && (part != PART_RADIO)) { - fprintf(stderr, "Bank valid only for radio.\n"); - usage(); - return EXIT_FAILURE; - } - - if ((bank == -1) && (part == PART_RADIO)) { - bank = 0; - } - if (!(write || read || dump_config || dump_state || set_tx_limit || set_rx_limit || set_ui || set_leds || set_p1 || set_p2 || set_clkin || set_narrowband || set_fpga_bitstream || read_selftest || test_rtc_osc || @@ -1000,19 +879,14 @@ int main(int argc, char** argv) } if (write) { - result = write_register( - device, - part, - bank, - register_number, - register_value); + result = write_register(device, part, register_number, register_value); } if (read) { if (register_number == REGISTER_INVALID) { - result = read_registers(device, part, bank); + result = read_registers(device, part); } else { - result = read_register(device, part, bank, register_number); + result = read_register(device, part, register_number); } } @@ -1151,8 +1025,8 @@ int main(int argc, char** argv) return EXIT_FAILURE; } printf("ADC0_%d (%s pin): %d\n", - ((uint8_t) adc_channel) & 0x7, - ((uint8_t) adc_channel) & 0x80 ? "alternate" : "dedicated", + adc_channel & 0x7, + adc_channel & 0x80 ? "alternate" : "dedicated", value); } diff --git a/host/hackrf-tools/src/hackrf_spiflash.c b/host/hackrf-tools/src/hackrf_spiflash.c index f6409280..46ad1cef 100644 --- a/host/hackrf-tools/src/hackrf_spiflash.c +++ b/host/hackrf-tools/src/hackrf_spiflash.c @@ -38,12 +38,8 @@ typedef int32_t ssize_t; #endif #endif -/* 32 Mbit flash */ -#define PRALINE_FLASH_LENGTH 0x400000 /* 8 Mbit flash */ -#define OTHER_FLASH_LENGTH 0x100000 - -#define MAX_LENGTH PRALINE_FLASH_LENGTH +#define MAX_LENGTH 0x100000 static struct option long_options[] = { {"address", required_argument, 0, 'a'}, @@ -65,15 +61,13 @@ static struct option long_options[] = { * If you're already running firmware that reports the wrong ID * I can't help you, but you can use the -i optionto ignore (or DFU) */ -int compatibility_check_og( - uint8_t* data, - int length, - hackrf_device* device, - uint8_t board_id) +int compatibility_check_og(uint8_t* data, int length, hackrf_device* device) { int str_len, i, j; bool match = false; + uint8_t board_id; char* dev_str; + hackrf_board_id_read(device, &board_id); switch (board_id) { case BOARD_ID_JAWBREAKER: dev_str = "HackRF Jawbreaker"; @@ -118,14 +112,17 @@ int compatibility_check_og( #define FROM_LE32(x) ((x)[0] | ((x)[1] << 8) | ((x)[2] << 16) | ((x)[3] << 24)) #define FROM_LE16(x) ((x)[0] | ((x)[1] << 8)) -int compatibility_check(uint8_t* data, int length, hackrf_device* device, uint8_t board_id) +int compatibility_check(uint8_t* data, int length, hackrf_device* device) { + uint8_t board_id; + hackrf_board_id_read(device, &board_id); + uint8_t* fw_info = data + FW_INFO_LOCATION; if (strncmp((char*) fw_info + FW_MAGIC_OFFSET, "HACKRFFW", 8) != 0) { // Couldn't find firmware info structure, // revert to old compatibility check method if possible. if (board_id != BOARD_ID_HACKRF1_R9) { - return compatibility_check_og(data, length, device, board_id); + return compatibility_check_og(data, length, device); } return EXIT_FAILURE; @@ -190,7 +187,7 @@ static void usage() printf("Usage:\n"); printf("\t-h, --help: this help\n"); printf("\t-a, --address : starting address (default: 0)\n"); - printf("\t-l, --length : number of bytes to read (default: all)\n"); + printf("\t-l, --length : number of bytes to read (default: %d)\n", MAX_LENGTH); printf("\t-r, --read : Read data into file.\n"); printf("\t-w, --write : Write data from file.\n"); printf("\t-i, --no-check: Skip check for firmware compatibility with target device.\n"); @@ -205,10 +202,8 @@ int main(int argc, char** argv) { int opt; uint8_t status[2]; - uint8_t board_id; uint32_t address = 0; - uint32_t length; - uint32_t flash_length; + uint32_t length = MAX_LENGTH; uint32_t tmp_length; uint16_t xfer_len = 0; const char* path = NULL; @@ -226,7 +221,6 @@ int main(int argc, char** argv) bool reset = false; bool read_status = false; bool clear_status = false; - bool length_specified = false; uint16_t usb_api; while ((opt = getopt_long( @@ -242,7 +236,6 @@ int main(int argc, char** argv) case 'l': result = parse_u32(optarg, &length); - length_specified = true; break; case 'r': @@ -323,12 +316,30 @@ int main(int argc, char** argv) 0, SEEK_END); /* Not really portable but work on major OS Linux/Win32 */ length = ftell(infile); - length_specified = true; /* Move to start */ rewind(infile); printf("File size %d bytes.\n", length); } + if (length == 0) { + fprintf(stderr, "Requested transfer of zero bytes.\n"); + if (infile != NULL) { + fclose(infile); + } + usage(); + return EXIT_FAILURE; + } + + if ((length > MAX_LENGTH) || (address > MAX_LENGTH) || + ((address + length) > MAX_LENGTH)) { + fprintf(stderr, "Request exceeds size of flash memory.\n"); + if (infile != NULL) { + fclose(infile); + } + usage(); + return EXIT_FAILURE; + } + if (read) { infile = fopen(path, "wb"); if (infile == NULL) { @@ -355,37 +366,6 @@ int main(int argc, char** argv) return EXIT_FAILURE; } - hackrf_board_id_read(device, &board_id); - - if (board_id == BOARD_ID_PRALINE) { - flash_length = PRALINE_FLASH_LENGTH; - } else { - flash_length = OTHER_FLASH_LENGTH; - } - - if (!length_specified) { - length = flash_length - address; - } - - if (length == 0) { - fprintf(stderr, "Requested transfer of zero bytes.\n"); - if (infile != NULL) { - fclose(infile); - } - usage(); - return EXIT_FAILURE; - } - - if ((length > flash_length) || (address > flash_length) || - ((address + length) > flash_length)) { - fprintf(stderr, "Request exceeds size of flash memory.\n"); - if (infile != NULL) { - fclose(infile); - } - usage(); - return EXIT_FAILURE; - } - if (read_status) { result = hackrf_spiflash_status(device, status); if (result != HACKRF_SUCCESS) { @@ -473,7 +453,7 @@ int main(int argc, char** argv) } if (!ignore_compat_check) { printf("Checking target device compatibility\n"); - result = compatibility_check(data, length, device, board_id); + result = compatibility_check(data, length, device); if (result) { printf("Compatibility test failed.\n"); fclose(infile); diff --git a/host/libhackrf/CMakeLists.txt b/host/libhackrf/CMakeLists.txt index 61ad494c..ccc7f89d 100644 --- a/host/libhackrf/CMakeLists.txt +++ b/host/libhackrf/CMakeLists.txt @@ -1,4 +1,3 @@ -# Copyright 2012-2026 Great Scott Gadgets # Copyright 2012 Jared Boone # Copyright 2013 Benjamin Vernoux # @@ -21,7 +20,7 @@ cmake_minimum_required(VERSION 3.10.0) project( libhackrf LANGUAGES C - VERSION 0.10.0) + VERSION 0.9.1) include(GNUInstallDirs) include(${PROJECT_SOURCE_DIR}/../cmake/set_release.cmake) set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/../cmake/modules) diff --git a/host/libhackrf/src/hackrf.c b/host/libhackrf/src/hackrf.c index 4018ac63..5aab1991 100644 --- a/host/libhackrf/src/hackrf.c +++ b/host/libhackrf/src/hackrf.c @@ -1,5 +1,5 @@ /* -Copyright (c) 2012-2026 Great Scott Gadgets +Copyright (c) 2012-2022 Great Scott Gadgets Copyright (c) 2012, Jared Boone Copyright (c) 2013, Benjamin Vernoux @@ -45,20 +45,13 @@ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSI #define TO_LE64(x) __builtin_bswap64(x) #define FROM_LE16(x) __builtin_bswap16(x) #define FROM_LE32(x) __builtin_bswap32(x) - #define FROM_LE64(x) __builtin_bswap64(x) #else #define TO_LE(x) x #define TO_LE64(x) x #define FROM_LE16(x) x #define FROM_LE32(x) x - #define FROM_LE64(x) x #endif -#define DEFAULT_REQUEST_TIMEOUT 100 -#define CPLD_WRITE_TIMEOUT 10000 -#define SPIFLASH_WRITE_TIMEOUT 50000 // W25Q32JV max chip erase time -#define FPGA_BITSTREAM_TIMEOUT 500 - // TODO: Factor this into a shared #include so that firmware can use // the same values. typedef enum { @@ -118,9 +111,6 @@ typedef enum { HACKRF_VENDOR_REQUEST_READ_SELFTEST = 56, HACKRF_VENDOR_REQUEST_READ_ADC = 57, HACKRF_VENDOR_REQUEST_TEST_RTC_OSC = 58, - HACKRF_VENDOR_REQUEST_RADIO_WRITE_REG = 59, - HACKRF_VENDOR_REQUEST_RADIO_READ_REG = 60, - HACKRF_VENDOR_REQUEST_GET_BUFFER_SIZE = 61, } hackrf_vendor_request; #define USB_CONFIG_STANDARD 0x1 @@ -144,11 +134,11 @@ typedef enum { #define TRANSFER_COUNT 4 #define TRANSFER_BUFFER_SIZE 262144 +#define DEVICE_BUFFER_SIZE 32768 #define USB_MAX_SERIAL_LENGTH 32 struct hackrf_device { libusb_device_handle* usb_device; - uint16_t usb_api_version; struct libusb_transfer** transfers; hackrf_sample_block_cb_fn callback; volatile bool @@ -168,7 +158,6 @@ struct hackrf_device { hackrf_flush_cb_fn flush_callback; hackrf_tx_block_complete_cb_fn tx_completion_callback; void* flush_ctx; - uint32_t buffer_size; }; typedef struct { @@ -194,8 +183,10 @@ static const max2837_ft_t max2837_ft[] = { {28000000}, {0}}; -#define USB_API_REQUIRED(device, version) \ - if (device->usb_api_version < version) \ +#define USB_API_REQUIRED(device, version) \ + uint16_t usb_version = 0; \ + hackrf_usb_api_version_read(device, &usb_version); \ + if (usb_version < version) \ return HACKRF_ERROR_USB_API_VERSION; static const uint16_t hackrf_usb_vid = 0x1d50; @@ -718,14 +709,6 @@ static int hackrf_open_setup(libusb_device_handle* usb_device, hackrf_device** d { int result; hackrf_device* lib_device; - uint32_t buffer_size; - struct libusb_device_descriptor device_descriptor; - libusb_device* dev = libusb_get_device(usb_device); - result = libusb_get_device_descriptor(dev, &device_descriptor); - if (result < 0) { - last_libusb_error = result; - return HACKRF_ERROR_LIBUSB; - } //int speed = libusb_get_device_speed(usb_device); // TODO: Error or warning if not high speed USB? @@ -759,7 +742,6 @@ static int hackrf_open_setup(libusb_device_handle* usb_device, hackrf_device** d #endif lib_device->usb_device = usb_device; - lib_device->usb_api_version = device_descriptor.bcdDevice; lib_device->transfers = NULL; lib_device->callback = NULL; lib_device->transfer_thread_started = false; @@ -772,30 +754,6 @@ static int hackrf_open_setup(libusb_device_handle* usb_device, hackrf_device** d lib_device->flush_ctx = NULL; lib_device->tx_completion_callback = NULL; - if (lib_device->usb_api_version >= 0x0112) { - // Fetch buffer size from device so we know how many bytes to flush TX with. - result = libusb_control_transfer( - lib_device->usb_device, - LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | - LIBUSB_RECIPIENT_DEVICE, - HACKRF_VENDOR_REQUEST_GET_BUFFER_SIZE, - 0, - 0, - (unsigned char*) &buffer_size, - 4, - DEFAULT_REQUEST_TIMEOUT); - - if (result < 4) { - last_libusb_error = result; - return HACKRF_ERROR_LIBUSB; - } - - lib_device->buffer_size = FROM_LE32(buffer_size); - } else { - // All older firmware uses a fixed 32KB buffer size. - lib_device->buffer_size = 32768; - } - result = pthread_mutex_init(&lib_device->transfer_lock, NULL); if (result != 0) { free(lib_device); @@ -953,7 +911,7 @@ int ADDCALL hackrf_set_transceiver_mode( 0, NULL, 0, - DEFAULT_REQUEST_TIMEOUT); + 0); if (result != 0) { last_libusb_error = result; @@ -982,7 +940,7 @@ int ADDCALL hackrf_max2837_read( register_number, (unsigned char*) value, 2, - DEFAULT_REQUEST_TIMEOUT); + 0); if (result < 2) { last_libusb_error = result; @@ -1011,7 +969,7 @@ int ADDCALL hackrf_max2831_read( register_number, (unsigned char*) value, 2, - DEFAULT_REQUEST_TIMEOUT); + 0); if (result < 2) { last_libusb_error = result; @@ -1044,7 +1002,7 @@ int ADDCALL hackrf_max2837_write( register_number, NULL, 0, - DEFAULT_REQUEST_TIMEOUT); + 0); if (result != 0) { last_libusb_error = result; @@ -1077,7 +1035,7 @@ int ADDCALL hackrf_max2831_write( register_number, NULL, 0, - DEFAULT_REQUEST_TIMEOUT); + 0); if (result != 0) { last_libusb_error = result; @@ -1108,7 +1066,7 @@ int ADDCALL hackrf_si5351c_read( register_number, (unsigned char*) &temp_value, 1, - DEFAULT_REQUEST_TIMEOUT); + 0); if (result < 1) { last_libusb_error = result; @@ -1142,7 +1100,7 @@ int ADDCALL hackrf_si5351c_write( register_number, NULL, 0, - DEFAULT_REQUEST_TIMEOUT); + 0); if (result != 0) { last_libusb_error = result; @@ -1166,7 +1124,7 @@ int ADDCALL hackrf_set_baseband_filter_bandwidth( bandwidth_hz >> 16, NULL, 0, - DEFAULT_REQUEST_TIMEOUT); + 0); if (result != 0) { last_libusb_error = result; @@ -1195,7 +1153,7 @@ int ADDCALL hackrf_rffc5071_read( register_number, (unsigned char*) value, 2, - DEFAULT_REQUEST_TIMEOUT); + 0); if (result < 2) { last_libusb_error = result; @@ -1225,7 +1183,7 @@ int ADDCALL hackrf_rffc5071_write( register_number, NULL, 0, - DEFAULT_REQUEST_TIMEOUT); + 0); if (result != 0) { last_libusb_error = result; @@ -1251,7 +1209,7 @@ int ADDCALL hackrf_fpga_read_register( register_number, (unsigned char*) value, 1, - DEFAULT_REQUEST_TIMEOUT); + 0); if (result < 1) { last_libusb_error = result; @@ -1278,7 +1236,7 @@ int ADDCALL hackrf_fpga_write_register( register_number, NULL, 0, - DEFAULT_REQUEST_TIMEOUT); + 0); if (result != 0) { last_libusb_error = result; @@ -1302,7 +1260,7 @@ int ADDCALL hackrf_read_selftest(hackrf_device* device, hackrf_selftest* selftes 0, (unsigned char*) selftest, sizeof(hackrf_selftest), - DEFAULT_REQUEST_TIMEOUT); + 0); if (result < 2) { last_libusb_error = result; @@ -1434,7 +1392,7 @@ int ADDCALL hackrf_read_adc(hackrf_device* device, uint8_t adc_channel, uint16_t adc_channel, (unsigned char*) value, 2, - DEFAULT_REQUEST_TIMEOUT); + 0); if (result < 2) { last_libusb_error = result; @@ -1458,7 +1416,7 @@ int ADDCALL hackrf_get_m0_state(hackrf_device* device, hackrf_m0_state* state) 0, (unsigned char*) state, sizeof(hackrf_m0_state), - DEFAULT_REQUEST_TIMEOUT); + 0); if (result < sizeof(hackrf_m0_state)) { last_libusb_error = result; @@ -1493,7 +1451,7 @@ int ADDCALL hackrf_set_tx_underrun_limit(hackrf_device* device, uint32_t value) value >> 16, NULL, 0, - DEFAULT_REQUEST_TIMEOUT); + 0); if (result != 0) { last_libusb_error = result; @@ -1517,7 +1475,7 @@ int ADDCALL hackrf_set_rx_overrun_limit(hackrf_device* device, uint32_t value) value >> 16, NULL, 0, - DEFAULT_REQUEST_TIMEOUT); + 0); if (result != 0) { last_libusb_error = result; @@ -1539,7 +1497,7 @@ int ADDCALL hackrf_spiflash_erase(hackrf_device* device) 0, NULL, 0, - SPIFLASH_WRITE_TIMEOUT); + 0); if (result != 0) { last_libusb_error = result; @@ -1557,7 +1515,7 @@ int ADDCALL hackrf_spiflash_write( { int result; - if ((address + length) > 0x400000) { + if (address > 0x0FFFFF) { return HACKRF_ERROR_INVALID_PARAM; } @@ -1570,7 +1528,7 @@ int ADDCALL hackrf_spiflash_write( address & 0xFFFF, data, length, - SPIFLASH_WRITE_TIMEOUT); + 0); if (result < length) { last_libusb_error = result; @@ -1588,7 +1546,7 @@ int ADDCALL hackrf_spiflash_read( { int result; - if ((address + length) > 0x400000) { + if (address > 0x0FFFFF) { return HACKRF_ERROR_INVALID_PARAM; } @@ -1600,7 +1558,7 @@ int ADDCALL hackrf_spiflash_read( address & 0xFFFF, data, length, - DEFAULT_REQUEST_TIMEOUT); + 0); if (result < length) { last_libusb_error = result; @@ -1623,7 +1581,7 @@ int ADDCALL hackrf_spiflash_status(hackrf_device* device, uint8_t* data) 0, data, 2, - DEFAULT_REQUEST_TIMEOUT); + 0); if (result < 1) { last_libusb_error = result; @@ -1646,7 +1604,7 @@ int ADDCALL hackrf_spiflash_clear_status(hackrf_device* device) 0, NULL, 0, - DEFAULT_REQUEST_TIMEOUT); + 0); if (result != 0) { last_libusb_error = result; @@ -1676,7 +1634,8 @@ int ADDCALL hackrf_cpld_write( &data[i], chunk_size, &transferred, - CPLD_WRITE_TIMEOUT); + 10000 // long timeout to allow for CPLD programming + ); if (result != LIBUSB_SUCCESS) { last_libusb_error = result; @@ -1698,7 +1657,7 @@ int ADDCALL hackrf_board_id_read(hackrf_device* device, uint8_t* value) 0, value, 1, - DEFAULT_REQUEST_TIMEOUT); + 0); if (result < 1) { last_libusb_error = result; @@ -1722,7 +1681,7 @@ int ADDCALL hackrf_version_string_read( 0, (unsigned char*) version, length, - DEFAULT_REQUEST_TIMEOUT); + 0); if (result < 0) { last_libusb_error = result; @@ -1737,7 +1696,17 @@ extern ADDAPI int ADDCALL hackrf_usb_api_version_read( hackrf_device* device, uint16_t* version) { - *version = device->usb_api_version; + int result; + libusb_device* dev; + struct libusb_device_descriptor desc; + dev = libusb_get_device(device->usb_device); + result = libusb_get_device_descriptor(dev, &desc); + if (result < 0) { + last_libusb_error = result; + return HACKRF_ERROR_LIBUSB; + } + + *version = desc.bcdDevice; return HACKRF_SUCCESS; } @@ -1773,7 +1742,7 @@ int ADDCALL hackrf_set_freq(hackrf_device* device, const uint64_t freq_hz) 0, (unsigned char*) &set_freq_params, length, - DEFAULT_REQUEST_TIMEOUT); + 0); if (result < length) { last_libusb_error = result; @@ -1833,7 +1802,7 @@ int ADDCALL hackrf_set_freq_explicit( 0, (unsigned char*) ¶ms, length, - DEFAULT_REQUEST_TIMEOUT); + 0); if (result < length) { last_libusb_error = result; @@ -1875,7 +1844,7 @@ int ADDCALL hackrf_set_sample_rate_manual( 0, (unsigned char*) &set_fracrate_params, length, - DEFAULT_REQUEST_TIMEOUT); + 0); if (result < length) { last_libusb_error = result; @@ -1947,7 +1916,7 @@ int ADDCALL hackrf_set_amp_enable(hackrf_device* device, const uint8_t value) 0, NULL, 0, - DEFAULT_REQUEST_TIMEOUT); + 0); if (result != 0) { last_libusb_error = result; @@ -1973,7 +1942,7 @@ int ADDCALL hackrf_board_partid_serialno_read( 0, (unsigned char*) read_partid_serialno, length, - DEFAULT_REQUEST_TIMEOUT); + 0); if (result < length) { last_libusb_error = result; @@ -2014,7 +1983,7 @@ int ADDCALL hackrf_set_lna_gain(hackrf_device* device, uint32_t value) value, &retval, 1, - DEFAULT_REQUEST_TIMEOUT); + 0); if (result != 1 || !retval) { return HACKRF_ERROR_INVALID_PARAM; @@ -2041,7 +2010,7 @@ int ADDCALL hackrf_set_vga_gain(hackrf_device* device, uint32_t value) value, &retval, 1, - DEFAULT_REQUEST_TIMEOUT); + 0); if (result != 1 || !retval) { return HACKRF_ERROR_INVALID_PARAM; @@ -2067,7 +2036,7 @@ int ADDCALL hackrf_set_txvga_gain(hackrf_device* device, uint32_t value) value, &retval, 1, - DEFAULT_REQUEST_TIMEOUT); + 0); if (result != 1 || !retval) { return HACKRF_ERROR_INVALID_PARAM; @@ -2088,7 +2057,7 @@ int ADDCALL hackrf_set_antenna_enable(hackrf_device* device, const uint8_t value 0, NULL, 0, - DEFAULT_REQUEST_TIMEOUT); + 0); if (result != 0) { last_libusb_error = result; @@ -2401,11 +2370,11 @@ ADDAPI int ADDCALL hackrf_enable_tx_flush( device->flush_transfer, device->usb_device, TX_ENDPOINT_ADDRESS, - calloc(1, device->buffer_size), - device->buffer_size, + calloc(1, DEVICE_BUFFER_SIZE), + DEVICE_BUFFER_SIZE, hackrf_libusb_flush_callback, device, - DEFAULT_REQUEST_TIMEOUT); + 0); device->flush_transfer->flags = LIBUSB_TRANSFER_FREE_BUFFER; @@ -2673,7 +2642,7 @@ int ADDCALL hackrf_set_hw_sync_mode(hackrf_device* device, const uint8_t value) 0, NULL, 0, - DEFAULT_REQUEST_TIMEOUT); + 0); if (result != 0) { last_libusb_error = result; @@ -2754,7 +2723,7 @@ int ADDCALL hackrf_init_sweep( (num_bytes >> 16) & 0xffff, data, size, - DEFAULT_REQUEST_TIMEOUT); + 0); if (result < size) { last_libusb_error = result; @@ -2788,7 +2757,7 @@ int ADDCALL hackrf_get_operacake_boards(hackrf_device* device, uint8_t* boards) 0, boards, 8, - DEFAULT_REQUEST_TIMEOUT); + 0); if (result < 8) { last_libusb_error = result; @@ -2827,7 +2796,7 @@ int ADDCALL hackrf_set_operacake_mode( (uint8_t) mode, NULL, 0, - DEFAULT_REQUEST_TIMEOUT); + 0); if (result != 0) { last_libusb_error = result; @@ -2866,7 +2835,7 @@ int ADDCALL hackrf_get_operacake_mode( 0, &buf, 1, - DEFAULT_REQUEST_TIMEOUT); + 0); if (result < 1) { last_libusb_error = result; @@ -2909,7 +2878,7 @@ int ADDCALL hackrf_set_operacake_ports( port_a | (port_b << 8), NULL, 0, - DEFAULT_REQUEST_TIMEOUT); + 0); if (result != 0) { last_libusb_error = result; @@ -2931,7 +2900,7 @@ int ADDCALL hackrf_reset(hackrf_device* device) 0, NULL, 0, - DEFAULT_REQUEST_TIMEOUT); + 0); if (result != 0) { last_libusb_error = result; @@ -2961,7 +2930,7 @@ int ADDCALL hackrf_set_operacake_ranges( 0, ranges, len_ranges, - DEFAULT_REQUEST_TIMEOUT); + 0); if (result < len_ranges) { last_libusb_error = result; @@ -3002,7 +2971,7 @@ int ADDCALL hackrf_set_operacake_freq_ranges( 0, range_bytes, len_ranges, - DEFAULT_REQUEST_TIMEOUT); + 0); if (result < len_ranges) { last_libusb_error = result; @@ -3044,7 +3013,7 @@ int ADDCALL hackrf_set_operacake_dwell_times( 0, dwell_data, data_len, - DEFAULT_REQUEST_TIMEOUT); + 0); if (result < data_len) { last_libusb_error = result; @@ -3067,7 +3036,7 @@ int ADDCALL hackrf_set_clkout_enable(hackrf_device* device, const uint8_t value) 0, NULL, 0, - DEFAULT_REQUEST_TIMEOUT); + 0); if (result != 0) { last_libusb_error = result; @@ -3089,7 +3058,7 @@ int ADDCALL hackrf_get_clkin_status(hackrf_device* device, uint8_t* status) 0, status, 1, - DEFAULT_REQUEST_TIMEOUT); + 0); if (result < 1) { last_libusb_error = result; return HACKRF_ERROR_LIBUSB; @@ -3118,7 +3087,7 @@ int ADDCALL hackrf_operacake_gpio_test( 0, (unsigned char*) test_result, 2, - DEFAULT_REQUEST_TIMEOUT); + 0); if (result < 1) { last_libusb_error = result; @@ -3144,7 +3113,7 @@ int ADDCALL hackrf_cpld_checksum(hackrf_device* device, uint32_t* crc) 0, (unsigned char*) crc, length, - DEFAULT_REQUEST_TIMEOUT); + 0); if (result < length) { last_libusb_error = result; @@ -3169,7 +3138,7 @@ int ADDCALL hackrf_set_ui_enable(hackrf_device* device, const uint8_t value) 0, NULL, 0, - DEFAULT_REQUEST_TIMEOUT); + 0); if (result != 0) { last_libusb_error = result; @@ -3227,7 +3196,7 @@ int ADDCALL hackrf_board_rev_read(hackrf_device* device, uint8_t* value) 0, value, 1, - DEFAULT_REQUEST_TIMEOUT); + 0); if (result < 1) { last_libusb_error = result; @@ -3311,7 +3280,7 @@ int ADDCALL hackrf_supported_platform_read(hackrf_device* device, uint32_t* valu 0, &data[0], 4, - DEFAULT_REQUEST_TIMEOUT); + 0); if (result < 1) { last_libusb_error = result; @@ -3334,7 +3303,7 @@ int ADDCALL hackrf_set_leds(hackrf_device* device, const uint8_t state) 0, NULL, 0, - DEFAULT_REQUEST_TIMEOUT); + 0); if (result != 0) { last_libusb_error = result; @@ -3380,7 +3349,7 @@ int ADDCALL hackrf_set_user_bias_t_opts( 0, NULL, 0, - DEFAULT_REQUEST_TIMEOUT); + 0); if (result != 0) { last_libusb_error = result; @@ -3403,7 +3372,7 @@ int ADDCALL hackrf_set_p1_ctrl(hackrf_device* device, const enum p1_ctrl_signal 0, NULL, 0, - DEFAULT_REQUEST_TIMEOUT); + 0); if (result != 0) { last_libusb_error = result; @@ -3426,7 +3395,7 @@ int ADDCALL hackrf_set_p2_ctrl(hackrf_device* device, const enum p2_ctrl_signal 0, NULL, 0, - DEFAULT_REQUEST_TIMEOUT); + 0); if (result != 0) { last_libusb_error = result; @@ -3451,7 +3420,7 @@ int ADDCALL hackrf_set_clkin_ctrl( 0, NULL, 0, - DEFAULT_REQUEST_TIMEOUT); + 0); if (result != 0) { last_libusb_error = result; @@ -3474,7 +3443,7 @@ int ADDCALL hackrf_set_narrowband_filter(hackrf_device* device, const uint8_t va 0, NULL, 0, - DEFAULT_REQUEST_TIMEOUT); + 0); if (result != 0) { last_libusb_error = result; @@ -3497,7 +3466,7 @@ int ADDCALL hackrf_set_fpga_bitstream(hackrf_device* device, const uint8_t index 0, NULL, 0, - FPGA_BITSTREAM_TIMEOUT); + 0); if (result != 0) { last_libusb_error = result; @@ -3507,74 +3476,6 @@ int ADDCALL hackrf_set_fpga_bitstream(hackrf_device* device, const uint8_t index } } -int ADDCALL hackrf_radio_read_register( - hackrf_device* device, - const uint8_t bank, - const uint8_t register_number, - uint64_t* const value) -{ - USB_API_REQUIRED(device, 0x0111); - int result; - - const uint8_t length = sizeof(value); - result = libusb_control_transfer( - device->usb_device, - LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, - HACKRF_VENDOR_REQUEST_RADIO_READ_REG, - register_number, - bank, - (unsigned char*) value, - length, - DEFAULT_REQUEST_TIMEOUT); - *value = FROM_LE64(*value); - - if (result < length) { - last_libusb_error = result; - return HACKRF_ERROR_LIBUSB; - } else { - return HACKRF_SUCCESS; - } -} - -int ADDCALL hackrf_radio_write_register( - hackrf_device* device, - const uint8_t bank, - const uint8_t register_number, - const uint64_t value) -{ - USB_API_REQUIRED(device, 0x0111); - int result; - - unsigned char data[9]; - data[0] = register_number; - data[1] = value & 0xff; - data[2] = (value >> 8) & 0xff; - data[3] = (value >> 16) & 0xff; - data[4] = (value >> 24) & 0xff; - data[5] = (value >> 32) & 0xff; - data[6] = (value >> 40) & 0xff; - data[7] = (value >> 48) & 0xff; - data[8] = (value >> 56) & 0xff; - - result = libusb_control_transfer( - device->usb_device, - LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | - LIBUSB_RECIPIENT_DEVICE, - HACKRF_VENDOR_REQUEST_RADIO_WRITE_REG, - 0, - bank, - &data[0], - sizeof(data), - DEFAULT_REQUEST_TIMEOUT); - - if (result < 9) { - last_libusb_error = result; - return HACKRF_ERROR_LIBUSB; - } else { - return HACKRF_SUCCESS; - } -} - #ifdef __cplusplus } // __cplusplus defined. #endif diff --git a/host/libhackrf/src/hackrf.h b/host/libhackrf/src/hackrf.h index eeca65e0..0247e6ca 100644 --- a/host/libhackrf/src/hackrf.h +++ b/host/libhackrf/src/hackrf.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2012-2026 Great Scott Gadgets +Copyright (c) 2012-2022 Great Scott Gadgets Copyright (c) 2012, Jared Boone Copyright (c) 2013, Benjamin Vernoux @@ -21,7 +21,8 @@ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#pragma once +#ifndef __HACKRF_H__ +#define __HACKRF_H__ #include #include @@ -2353,38 +2354,8 @@ extern ADDAPI int ADDCALL hackrf_set_fpga_bitstream( hackrf_device* device, const uint8_t index); -/** - * Read a radio configuration register - * - * @param[in] device device to query - * @param[in] bank bank number to read - * @param[in] register_number register number to read - * @param[out] value value of the specified register - * @return @ref HACKRF_SUCCESS on success or @ref hackrf_error variant - * @ingroup debug - */ -extern ADDAPI int ADDCALL hackrf_radio_read_register( - hackrf_device* device, - const uint8_t bank, - const uint8_t register_number, - uint64_t* const value); - -/** - * Write to a radio configuration register - * - * @param[in] device device to write - * @param[in] bank bank number to write - * @param[in] register_number register number to write - * @param[out] value value to write in the specified register - * @return @ref HACKRF_SUCCESS on success or @ref hackrf_error variant - * @ingroup debug - */ -extern ADDAPI int ADDCALL hackrf_radio_write_register( - hackrf_device* device, - const uint8_t bank, - const uint8_t register_number, - const uint64_t value); - #ifdef __cplusplus } // __cplusplus defined. #endif + +#endif /*__HACKRF_H__*/ diff --git a/tools/reformat-source.sh b/tools/reformat-source.sh index 525c9afc..754717c4 100755 --- a/tools/reformat-source.sh +++ b/tools/reformat-source.sh @@ -1,14 +1,12 @@ #!/bin/bash -REQUIRED_VERSION=14 - -VERSION=`clang-format --version | grep -o 'version [^ ]' | cut -d ' ' -f 2 | cut -d '.' -f 1` -if [ "$VERSION" -eq "$REQUIRED_VERSION" ]; then +VERSION=`clang-format --version | grep -o '[^ ]*$' | cut -d '.' -f 1` +if [ "$VERSION" -ge "14" ]; then CLANG_FORMAT=clang-format -elif command -v clang-format-$REQUIRED_VERSION > /dev/null; then - CLANG_FORMAT=clang-format-$REQUIRED_VERSION +elif clang-format-14 --version > /dev/null; then + CLANG_FORMAT=clang-format-14 else - echo "clang-format version $REQUIRED_VERSION is required." + echo "clang-format version 14 or higher is required." exit 1 fi