Compare commits

...
Sign in to create a new pull request.

26 commits

Author SHA1 Message Date
antoinevg
7593b15dbd
Merge pull request #1801 from greatscottgadgets/antoinevg/fpga-control-timeout
Some checks failed
Build / firmware (UNIVERSAL, latest, ubuntu) (push) Failing after 5s
Check code style / clang-format (push) Failing after 5s
Check code style / clang-format-1 (push) Failing after 5s
Check code style / clang-format-2 (push) Failing after 4s
Check code style / clang-format-3 (push) Failing after 4s
Check includes / includes-check (JAWBREAKER, 3.12.0) (push) Failing after 6s
Check includes / includes-check (HACKRF_ONE, 3.12.0) (push) Failing after 8s
Check includes / includes-check (HACKRF_ONE, latest) (push) Failing after 10s
Check includes / includes-check (JAWBREAKER, latest) (push) Failing after 5s
Check includes / includes-check (PRALINE, 3.12.0) (push) Failing after 4s
Check includes / includes-check (PRALINE, latest) (push) Failing after 3s
Check includes / includes-check (RAD1O, 3.12.0) (push) Failing after 3s
Check includes / includes-check (UNIVERSAL, 3.12.0) (push) Failing after 3s
Check includes / includes-check (RAD1O, latest) (push) Failing after 3s
Check includes / includes-check (UNIVERSAL, latest) (push) Failing after 4s
Build / host (3.21.7, -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, msvc, Visual Studio 17 2022, --install, 17.1… (push) Has been cancelled
Build / host (4.2.6, -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, msvc, Visual Studio 18 2026, --install, lates… (push) Has been cancelled
Build / host (latest, --install-prefix=/usr/local, gcc, MSYS Makefiles, --install, latest, windows, msys2) (push) Has been cancelled
Build / firmware (HACKRF_ONE, latest, windows) (push) Has been cancelled
Build / firmware (JAWBREAKER, latest, windows) (push) Has been cancelled
Build / host (3.10.0, gcc, Unix Makefiles, --target install, --build, macos, bash, sudo) (push) Has been cancelled
Build / host (latest, -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, msvc, Visual Studio 18 2026, --install, late… (push) Has been cancelled
Build / host (latest, gcc, Unix Makefiles, --install, latest, macos, bash, sudo) (push) Has been cancelled
Build / firmware (UNIVERSAL, latest, macos) (push) Has been cancelled
Build / firmware (UNIVERSAL, latest, windows) (push) Has been cancelled
Build / firmware (PRALINE, 3.12.0, macos) (push) Has been cancelled
Build / firmware (PRALINE, latest, macos) (push) Has been cancelled
Build / firmware (PRALINE, latest, windows) (push) Has been cancelled
Build / firmware (RAD1O, latest, windows) (push) Has been cancelled
Build / firmware (UNIVERSAL, 3.12.0, macos) (push) Has been cancelled
libhackrf: Set a 500ms timeout for changing fpga bitstream
2026-07-22 17:58:57 +02:00
antoinevg
912c0fd20a
Merge pull request #1798 from greatscottgadgets/antoinevg/rename-radio-bank-active
Rename RADIO_BANK_ACTIVE to RADIO_BANK_REQUESTED
2026-07-22 17:58:51 +02:00
Antoine van Gelder
6259086c96
libhackrf: set a 500ms timeout for changing fpga bitstream 2026-07-21 11:44:26 +02:00
Antoine van Gelder
2b7ba8d7ab
radio: rename RADIO_BANK_ACTIVE to RADIO_BANK_REQUESTED 2026-07-16 12:31:31 +02:00
Michael Ossmann
5da69aa411
Merge pull request #1790 from martinling/radio-clock-correction
Add radio clock correction register
2026-07-09 12:10:40 -04:00
Martin Ling
8bfbd716da Add RADIO_CLOCK_CORRECTION register, bump USB API to 1.13. 2026-06-30 14:20:31 +01:00
Martin Ling
dda161cb1f Add multiply & divide implementations for 128-bit unsigned integers. 2026-06-30 12:00:52 +01:00
Martin Ling
74c3b730fa Add 1.63 fixed point type. 2026-06-30 08:44:40 +01:00
Michael Ossmann
8dbb3475da
Merge pull request #1760 from greatscottgadgets/hil-locks
HIL resource locks
2026-06-26 14:14:43 -04:00
Jacob Graves
d6548b1f46
Merge pull request #1784 from greatscottgadgets/win-ci-fix
CI: Adjust CMake generators to supported Visual Studio versions
2026-06-25 11:34:40 -07:00
Martin Ling
95a30a9840
Merge pull request #1781 from martinling/portapack-detection
Simplify PortaPack detection and init API
2026-06-17 19:07:53 +01:00
Martin Ling
57fc841ddb
Merge pull request #1783 from martinling/i2c-khz
Make I2C startup & clock speed consistent
2026-06-17 10:26:55 +01:00
Michael Ossmann
be669ce370
Merge pull request #1776 from mndza/cic-default-factor
gateware: CIC defaults to the minimum resampling factor
2026-06-16 10:02:49 -04:00
Martin Ling
1dfa0742d6
Merge pull request #1780 from martinling/r9-mcu-clk
Fix management of CLKOUT/MCU_CLK synth sharing on H1R9
2026-06-16 12:54:56 +01:00
Martin Ling
eb8bc546a8 CI: Build with more CMake and Visual Studio versions. 2026-06-15 18:21:29 +01:00
Martin Ling
3e274a881d CI: Simplify install steps. 2026-06-15 16:40:55 +01:00
Martin Ling
73562ded31 CI: Simplify host build matrix and specify CMake generators. 2026-06-15 14:45:04 +01:00
Martin Ling
aa76109b6a CI: Bump actions/checkout to v6. 2026-06-15 13:31:22 +01:00
Martin Ling
d6913807a6 Specify I2C clock in kHz, and adjust for CPU clock changes. 2026-06-15 11:58:33 +01:00
Martin Ling
3afd5d2acd Move i2c_bus_start calls out of clock_gen_init and clock_gen_shutdown. 2026-06-15 11:56:10 +01:00
Martin Ling
092d034d80 Simplify PortaPack detection and init API.
Some checks failed
Check code style / clang-format-2 (push) Failing after 12s
Check code style / clang-format-3 (push) Failing after 10s
Check includes / includes-check (HACKRF_ONE, latest) (push) Failing after 7s
Check includes / includes-check (JAWBREAKER, 3.12.0) (push) Failing after 7s
Check includes / includes-check (JAWBREAKER, latest) (push) Failing after 6s
Check includes / includes-check (HACKRF_ONE, 3.12.0) (push) Failing after 5s
Check includes / includes-check (PRALINE, 3.12.0) (push) Failing after 7s
Check includes / includes-check (PRALINE, latest) (push) Failing after 7s
Check includes / includes-check (RAD1O, 3.12.0) (push) Failing after 8s
Check includes / includes-check (RAD1O, latest) (push) Failing after 6s
Check includes / includes-check (UNIVERSAL, 3.12.0) (push) Failing after 7s
Check includes / includes-check (UNIVERSAL, latest) (push) Failing after 4s
Build / host (3.10.0, map[os:macos shell:bash]) (push) Has been cancelled
Build / host (3.16.0, map[os:macos shell:bash]) (push) Has been cancelled
Build / host (3.21.0, -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, map[os:windows shell:pwsh]) (push) Has been cancelled
Build / host (3.21.0, map[os:macos shell:bash]) (push) Has been cancelled
Build / host (4.0.0, -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, map[os:windows shell:pwsh]) (push) Has been cancelled
Build / host (4.0.0, map[os:macos shell:bash]) (push) Has been cancelled
Build / firmware (UNIVERSAL, 3.12.0, macos) (push) Has been cancelled
Build / firmware (UNIVERSAL, latest, macos) (push) Has been cancelled
Build / host (latest, --install-prefix=/usr/local, map[os:windows shell:msys2]) (push) Has been cancelled
Build / host (latest, -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, map[os:windows shell:pwsh]) (push) Has been cancelled
Build / host (latest, map[os:macos shell:bash]) (push) Has been cancelled
Build / firmware (HACKRF_ONE, latest, windows) (push) Has been cancelled
Build / firmware (JAWBREAKER, latest, windows) (push) Has been cancelled
Build / firmware (PRALINE, 3.12.0, macos) (push) Has been cancelled
Build / firmware (PRALINE, latest, macos) (push) Has been cancelled
Build / firmware (PRALINE, latest, windows) (push) Has been cancelled
Build / firmware (RAD1O, latest, windows) (push) Has been cancelled
Build / firmware (UNIVERSAL, latest, windows) (push) Has been cancelled
2026-06-12 17:09:49 +01:00
Martin Ling
42b7f7703d Fix management of CLKOUT/MCU_CLK synth sharing on H1R9. 2026-06-12 16:00:48 +01:00
Martin Ling
bb1f835403
Merge pull request #1779 from martinling/mcu-pll-b
Use PLL B for MCU_CLKIN on Praline
2026-06-12 09:59:44 +01:00
mndza
e32695e24f
gateware: CIC defaults to the minimum resampling factor 2026-06-03 10:12:36 +02:00
grvvy
6c01a078d5 Jenkinsfile: ensure device resets occur between test runs 2026-05-19 15:27:11 -06:00
grvvy
62cdff3448 Jenkinsfile: add resource locks to HIL USB hubs to allow for concurrent builds 2026-05-19 15:26:51 -06:00
24 changed files with 479 additions and 228 deletions

View file

@ -17,70 +17,127 @@ jobs:
host:
strategy:
matrix:
sys:
- {os: 'macos', shell: 'bash'}
- {os: 'ubuntu', shell: 'bash'}
- {os: 'windows', shell: 'pwsh'}
- {os: 'windows', shell: 'msys2'}
cmake: ['3.10.0', '3.16.0', '3.21.0', '4.0.0', 'latest']
os: ['macos', 'ubuntu', 'windows']
cmake: ['3.10.0', '3.21.7', '4.2.6', 'latest']
compiler: ['gcc', 'msvc']
exclude:
# GitHub runners use Visual Studio 2022. Support added in CMake 3.21.
- sys: {os: 'windows', shell: 'pwsh'}
# 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'
cmake: '3.10.0'
- sys: {os: 'windows', shell: 'pwsh'}
cmake: '3.16.0'
# MSYS2 always supplies the latest cmake.
- sys: {os: 'windows', shell: 'msys2'}
cmake: '3.10.0'
- sys: {os: 'windows', shell: 'msys2'}
cmake: '3.16.0'
- sys: {os: 'windows', shell: 'msys2'}
cmake: '3.21.0'
- sys: {os: 'windows', shell: 'msys2'}
cmake: '4.0.0'
# The in-between CMake versions aren't so intersting with GCC.
- compiler: 'gcc'
cmake: '3.21.7'
- compiler: 'gcc'
cmake: '4.2.6'
include:
- sys: {os: 'windows', shell: 'pwsh'}
# 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'
cmake_args: >-
-DPKG_CONFIG_EXECUTABLE=C:/vcpkg/installed/x64-windows/tools/pkgconf/pkgconf.exe
-DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake
--install-prefix=$env:GITHUB_WORKSPACE/install
- sys: {os: 'windows', shell: 'msys2'}
- os: 'windows'
compiler: 'gcc'
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.sys.os }}-latest
runs-on: ${{ matrix.os }}-latest
defaults:
run:
shell: '${{ matrix.sys.shell }} {0}'
shell: '${{ matrix.shell }} {0}'
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Setup cmake
uses: lukka/get-cmake@latest
with:
cmakeVersion: ${{ matrix.cmake }}
if: matrix.sys.shell != 'msys2'
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'
- name: Install dependencies (macOS)
run: brew install fftw
if: matrix.sys.os == 'macos'
if: matrix.os == 'macos'
- name: Install dependencies (Ubuntu)
run: |
sudo apt update
sudo apt install libfftw3-dev libusb-1.0-0-dev
if: matrix.sys.os == 'ubuntu'
if: matrix.os == 'ubuntu'
- name: Install dependencies (Windows)
run: vcpkg install --triplet=x64-windows libusb fftw3 pthreads pkgconf
if: matrix.sys.os == 'windows' && matrix.sys.shell != 'msys2'
if: matrix.os == 'windows' && matrix.shell != 'msys2'
- name: Setup MSYS (Windows)
if: matrix.sys.os == 'windows' && matrix.sys.shell == 'msys2'
if: matrix.os == 'windows' && matrix.shell == 'msys2'
uses: msys2/setup-msys2@v2
with:
msystem: UCRT64
@ -98,7 +155,7 @@ jobs:
run: |
cmake -E make_directory host/build
cd host/build
cmake .. -DCMAKE_BUILD_TYPE=Release ${{matrix.cmake_args}}
cmake .. -G "${{ matrix.generator }}" -DCMAKE_BUILD_TYPE=Release ${{matrix.cmake_args}}
cmake --build . --config Release
# Build libhackrf ONLY
@ -107,22 +164,12 @@ jobs:
run: |
cmake -E make_directory host/libhackrf/build
cd host/libhackrf/build
cmake .. -DCMAKE_BUILD_TYPE=Release ${{ matrix.cmake_args }}
cmake .. -G "${{ matrix.generator }}" -DCMAKE_BUILD_TYPE=Release ${{ matrix.cmake_args }}
cmake --build . --config Release
- name: Install (libhackrf)
run: |
sudo cmake --install host/libhackrf/build --config Release
if: matrix.sys.os != 'windows' && matrix.cmake != '3.10.0'
- name: Install (libhackrf, CMake 3.10)
run: |
sudo cmake --build host/libhackrf/build --target install --config Release
if: matrix.sys.os != 'windows' && matrix.cmake == '3.10.0'
- name: Install (libhackrf, Windows)
run: cmake --install host/libhackrf/build --config Release
if: matrix.sys.os == 'windows'
${{ matrix.sudo }} cmake ${{ matrix.install_cmd }} host/libhackrf/build ${{ matrix.install_args }} --config Release
# Build hackrf-tools ONLY
@ -130,22 +177,12 @@ jobs:
run: |
cmake -E make_directory host/hackrf-tools/build
cd host/hackrf-tools/build
cmake .. -DCMAKE_BUILD_TYPE=Release ${{ matrix.cmake_args }}
cmake .. -G "${{ matrix.generator }}" -DCMAKE_BUILD_TYPE=Release ${{ matrix.cmake_args }}
cmake --build . --config Release
- name: Install (hackrf-tools)
run: |
sudo cmake --install host/hackrf-tools/build --config Release
if: matrix.sys.os != 'windows' && matrix.cmake != '3.10.0'
- name: Install (hackrf-tools, CMake 3.10)
run: |
sudo cmake --build host/hackrf-tools/build --target install --config Release
if: matrix.sys.os != 'windows' && matrix.cmake == '3.10.0'
- name: Install (hackrf-tools, Windows)
run: cmake --install host/hackrf-tools/build --config Release
if: matrix.sys.os == 'windows'
${{ matrix.sudo }} cmake ${{ matrix.install_cmd }} host/hackrf-tools/build ${{ matrix.install_args }}
# Publish the contents of install/bin (which should be the combination libhackrf and host-tools) for Windows
- name: Publish Artifacts (Windows)
@ -153,7 +190,7 @@ jobs:
with:
name: hackrf-tools-windows
path: ${{github.workspace}}/install/bin
if: matrix.sys.os == 'windows' && matrix.cmake == 'latest' && matrix.sys.shell == 'pwsh'
if: matrix.os == 'windows' && matrix.cmake == 'latest' && matrix.shell == 'pwsh'
firmware:
strategy:
@ -179,7 +216,7 @@ jobs:
runs-on: ${{ matrix.os }}-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
with:
submodules: true

View file

@ -16,7 +16,7 @@ jobs:
- check: 'firmware/hackrf_usb'
exclude: ''
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Run clang-format-action
uses: jidicula/clang-format-action@v4.6.2
with:

135
Jenkinsfile vendored
View file

@ -39,31 +39,15 @@ pipeline {
timeout(time: 20, unit: 'MINUTES')
}
steps {
sh './ci-scripts/install_host.sh'
sh './ci-scripts/build_firmware.sh HACKRF_ONE'
script {
allOff()
reset('h1_eut')
}
sh 'sleep 1s'
retry(3) {
sh './ci-scripts/test_host.sh'
}
script {
reset('h1_tester h1_eut')
}
sh 'sleep 1s'
script {
// Allow up to 3 retries 5 minutes each for the HIL test
runCommand(3, 5, 'MINUTES', "HackRF One Test", h1_test)
}
script {
allOff()
reset('h1_eut')
}
sh 'sleep 1s'
retry(3) {
sh 'python3 ci-scripts/test_sgpio_debug.py'
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')
}
}
}
}
@ -79,32 +63,17 @@ pipeline {
timeout(time: 20, unit: 'MINUTES')
}
steps {
sh './ci-scripts/install_host.sh'
sh './ci-scripts/build_firmware.sh UNIVERSAL'
script {
allOff()
reset('h1_eut')
}
sh 'sleep 1s'
retry(3) {
sh './ci-scripts/test_host.sh'
}
script {
reset('h1_tester h1_eut')
}
sh 'sleep 1s'
script {
// Allow up to 3 retries 5 minutes each for the HIL test
runCommand(3, 5, 'MINUTES', "HackRF One Test", h1_test)
}
script {
allOff()
reset('h1_eut')
}
sh 'sleep 1s'
retry(3) {
sh 'python3 ci-scripts/test_sgpio_debug.py'
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') {
@ -119,23 +88,14 @@ pipeline {
timeout(time: 20, unit: 'MINUTES')
}
steps {
sh './ci-scripts/install_host.sh'
sh './ci-scripts/build_firmware.sh PRALINE'
script {
allOff()
reset('hpro_eut')
}
sh 'sleep 1s'
retry(3) {
sh './ci-scripts/test_host.sh'
}
script {
reset('hpro_tester hpro_eut')
}
sh 'sleep 1s'
script {
// Allow up to 3 retries 5 minutes each for the HIL test
runCommand(3, 5, 'MINUTES', "HackRF Pro Test", hpro_test)
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)
}
}
}
}
@ -151,23 +111,14 @@ pipeline {
timeout(time: 20, unit: 'MINUTES')
}
steps {
sh './ci-scripts/install_host.sh'
sh './ci-scripts/build_firmware.sh UNIVERSAL'
script {
allOff()
reset('hpro_eut')
}
sh 'sleep 1s'
retry(3) {
sh './ci-scripts/test_host.sh'
}
script {
reset('hpro_tester hpro_eut')
}
sh 'sleep 1s'
script {
// Allow up to 3 retries 5 minutes each for the HIL test
runCommand(3, 5, 'MINUTES', "HackRF Pro Test", hpro_test)
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)
}
}
}
}
@ -184,15 +135,15 @@ pipeline {
def allOff() {
// Allow up to 3 retries, 20 seconds each, for the USB hub port power server to respond appropriately
runCommand(3, 20, 'SECONDS', 'USB hub port power server command', "hubs all off")
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(3, 20, 'SECONDS', 'USB hub port power server command', "hubs ${devices} reset")
runCommand('USB hub port power server command', "hubs ${devices} reset", 3, 20, 'SECONDS')
}
def runCommand(retries, time, unit, title, cmd) {
def runCommand(title, cmd, retries, time, unit) {
retry(retries) {
try {
timeout(time: time, unit: unit) {
@ -214,3 +165,13 @@ def runCommand(retries, time, unit, title, cmd) {
}
}
}
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')
}
}

View file

@ -24,8 +24,6 @@
#include <stdint.h>
#include "hackrf_ui.h"
#include "i2c_bus.h"
#include "i2c_lpc.h"
#include "platform_detect.h"
#include "sgpio.h"
#include "si5351c.h"
@ -36,8 +34,6 @@
void clock_gen_init(void)
{
i2c_bus_start(si5351c.bus, &i2c_config_fast_clock);
si5351c_init(&si5351c);
si5351c_disable_all_outputs(&si5351c);
si5351c_disable_oeb_pin_control(&si5351c);
@ -120,7 +116,6 @@ void clock_gen_init(void)
void clock_gen_shutdown(void)
{
i2c_bus_start(si5351c.bus, &i2c_config_fast_clock);
si5351c_disable_all_outputs(&si5351c);
si5351c_disable_oeb_pin_control(&si5351c);
si5351c_power_down_all_clocks(&si5351c);
@ -131,7 +126,7 @@ 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_reference_oscillator && portapack()) {
if (portapack_present()) {
portapack_reference_oscillator(false);
}
}
@ -146,7 +141,7 @@ clock_source_t activate_best_clock_source(void)
#ifdef IS_EXPANSION_COMPATIBLE
if (IS_EXPANSION_COMPATIBLE) {
/* Enable PortaPack reference oscillator (if present), and check for valid clock. */
if (portapack_reference_oscillator && portapack()) {
if (portapack_present()) {
portapack_reference_oscillator(true);
delay_ms(18); // for oscillator to enable.
if (si5351c_clkin_signal_valid(&si5351c)) {

View file

@ -54,3 +54,20 @@ typedef uint64_t fp_28_36_t;
#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))

View file

@ -25,6 +25,8 @@
#include <libopencm3/lpc43xx/i2c.h>
#include <libopencm3/lpc43xx/memorymap.h>
#include "cpu_clock.h"
/* Driver instances. */
i2c_bus_t i2c0 = {
.obj = (void*) I2C0_BASE,
@ -41,7 +43,7 @@ i2c_bus_t i2c1 = {
};
const i2c_lpc_config_t i2c_config_fast_clock = {
.duty_cycle_count = 255,
.clock_khz = 400,
};
/* FIXME return i2c0 status from each function */
@ -51,7 +53,9 @@ 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;
i2c_init(port, config->duty_cycle_count);
const uint16_t duty_cycle_count =
(cpu_clock_mhz * (2000 / config->clock_khz)) / 4;
i2c_init(port, duty_cycle_count);
}
void i2c_lpc_stop(i2c_bus_t* const bus)

View file

@ -29,7 +29,7 @@
#include "i2c_bus.h"
typedef struct {
const uint16_t duty_cycle_count;
const uint16_t clock_khz;
} i2c_lpc_config_t;
void i2c_lpc_start(i2c_bus_t* const bus, const void* const config);

View file

@ -610,23 +610,23 @@ static bool portapack_detect(void)
return idcode == 0x020A50DD || idcode == 0x00025610;
}
static const portapack_t portapack_instance = {};
static bool portapack_detected = false;
static const portapack_t* portapack_pointer = NULL;
const portapack_t* portapack(void)
bool portapack_present(void)
{
return portapack_pointer;
return portapack_detected;
}
void portapack_init(void)
bool portapack_init(void)
{
if (portapack_detect()) {
portapack_if_init();
portapack_lcd_reset();
portapack_lcd_init();
portapack_pointer = &portapack_instance;
portapack_detected = true;
} else {
portapack_pointer = NULL;
portapack_detected = false;
}
return portapack_detected;
}

View file

@ -63,15 +63,13 @@ typedef struct {
typedef struct {
} portapack_t;
void portapack_init(void);
bool portapack_init(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));
bool portapack_present(void);
void portapack_backlight(const bool on);
void portapack_reference_oscillator(const bool on) __attribute__((weak));
void portapack_reference_oscillator(const bool on);
void portapack_fill_rectangle(const ui_rect_t rect, const ui_color_t color);

View file

@ -34,6 +34,7 @@
#include "rf_path.h"
#include "transceiver_mode.h"
#include "tuning.h"
#include "u128.h"
#ifdef IS_PRALINE
#include "fpga.h"
#include "tune_config.h"
@ -53,7 +54,7 @@ void radio_init(radio_t* const radio)
}
}
radio->config[RADIO_BANK_APPLIED][RADIO_OPMODE] = TRANSCEIVER_MODE_OFF;
radio->config[RADIO_BANK_ACTIVE][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;
@ -77,7 +78,7 @@ radio_error_t radio_reg_write(
}
switch (bank) {
case RADIO_BANK_ACTIVE:
case RADIO_BANK_REQUESTED:
mark_dirty(radio, reg);
/* fall through */
case RADIO_BANK_IDLE:
@ -132,6 +133,75 @@ static uint32_t radio_update_direction(radio_t* const radio, uint64_t* bank)
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)
@ -183,6 +253,9 @@ static uint32_t radio_update_sample_rate(radio_t* const radio, uint64_t* bank)
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);
@ -236,7 +309,7 @@ static uint32_t radio_update_sample_rate(radio_t* const radio, uint64_t* bank)
new_n = (n != previous_n);
afe_rate = rate << n;
afe_rate = sample_rate_set(afe_rate, false);
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;
@ -245,7 +318,7 @@ static uint32_t radio_update_sample_rate(radio_t* const radio, uint64_t* bank)
}
new_afe_rate = (afe_rate != previous_afe_rate);
if (new_afe_rate) {
afe_rate = sample_rate_set(afe_rate, true);
afe_rate = set_afe_rate(afe_rate, correction, true);
}
rate = afe_rate >> n;
@ -373,6 +446,7 @@ static uint32_t radio_update_frequency(radio_t* const radio, uint64_t* bank)
#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];
@ -381,6 +455,8 @@ static uint32_t radio_update_frequency(radio_t* const radio, uint64_t* bank)
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;
@ -388,6 +464,7 @@ static uint32_t radio_update_frequency(radio_t* const radio, uint64_t* bank)
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) {
@ -405,11 +482,12 @@ static uint32_t radio_update_frequency(radio_t* const radio, uint64_t* bank)
img_reject = RF_PATH_FILTER_BYPASS;
}
}
correction = restrict_correction(requested_correction);
if (requested_if != RADIO_UNSET) {
freq_if = max283x_set_frequency(&max283x, requested_if, false);
freq_if = set_if(requested_if, correction, false);
}
if (requested_lo != RADIO_UNSET) {
freq_lo = mixer_set_frequency(&mixer, freq_lo, false);
freq_lo = set_lo(requested_lo, correction, false);
}
#ifdef IS_PRALINE
if (IS_PRALINE) {
@ -491,7 +569,7 @@ static uint32_t radio_update_frequency(radio_t* const radio, uint64_t* bank)
freq_lo = RADIO_UNSET;
}
if (freq_lo != RADIO_UNSET) {
freq_lo = mixer_set_frequency(&mixer, freq_lo, false);
freq_lo = set_lo(freq_lo, correction, false);
}
}
@ -513,12 +591,12 @@ static uint32_t radio_update_frequency(radio_t* const radio, uint64_t* bank)
/* Apply settings. */
if ((freq_if != applied_if) && (freq_if != RADIO_UNSET)) {
freq_if = max283x_set_frequency(&max283x, freq_if, true);
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 = mixer_set_frequency(&mixer, freq_lo, true);
freq_lo = set_lo(freq_lo, correction, true);
radio->config[RADIO_BANK_APPLIED][RADIO_FREQUENCY_LO] = freq_lo;
changed |= (1 << RADIO_FREQUENCY_LO);
}
@ -561,6 +639,10 @@ static uint32_t radio_update_frequency(radio_t* const radio, uint64_t* bank)
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;
}
@ -855,7 +937,7 @@ bool radio_update(radio_t* const radio)
return false;
}
radio->regs_dirty = 0;
memcpy(&tmp_bank[0], &(radio->config[RADIO_BANK_ACTIVE][0]), sizeof(tmp_bank));
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) ||
@ -916,14 +998,14 @@ void radio_switch_opmode(radio_t* const radio, const transceiver_mode_t mode)
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_ACTIVE][reg];
previous = radio->config[RADIO_BANK_REQUESTED][reg];
if ((value != RADIO_UNSET) && (value != previous)) {
radio->config[RADIO_BANK_ACTIVE][reg] = value;
radio->config[RADIO_BANK_REQUESTED][reg] = value;
mark_dirty(radio, reg);
}
}
radio->config[RADIO_BANK_ACTIVE][RADIO_OPMODE] = mode;
radio->config[RADIO_BANK_REQUESTED][RADIO_OPMODE] = mode;
mark_dirty(radio, RADIO_OPMODE);
nvic_enable_irq(NVIC_USB0_IRQ);
radio_update(radio);

View file

@ -165,17 +165,23 @@ typedef enum {
* 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 (23)
#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))
#define RADIO_REG_GROUP_FREQ \
((1 << RADIO_FREQUENCY_RF) | (1 << RADIO_FREQUENCY_IF) | \
(1 << RADIO_FREQUENCY_LO) | (1 << RADIO_IMAGE_REJECT) | (1 << RADIO_ROTATION))
#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) | \
@ -185,7 +191,7 @@ typedef enum {
(1 << RADIO_GAIN_RX_IF) | (1 << RADIO_GAIN_RX_BB))
/**
* Register bank RADIO_BANK_ACTIVE stores the active configuration. Active
* 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
@ -196,7 +202,7 @@ typedef enum {
*/
typedef enum {
RADIO_BANK_APPLIED = 0,
RADIO_BANK_ACTIVE = 1,
RADIO_BANK_REQUESTED = 1,
RADIO_BANK_IDLE = 2,
RADIO_BANK_RX = 3,
RADIO_BANK_TX = 4,
@ -231,7 +237,7 @@ typedef struct {
void radio_init(radio_t* const radio);
/**
* Write to one or more registers. Writes to RADIO_BANK_ACTIVE are applied at
* 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.
*/
radio_error_t radio_reg_write(
@ -249,7 +255,7 @@ uint64_t radio_reg_read(
const radio_register_t reg);
/**
* Apply changes requested in RADIO_BANK_ACTIVE.
* Apply changes requested in RADIO_BANK_REQUESTED.
* Return true if any changes were applied.
*/
bool radio_update(radio_t* const radio);

View file

@ -274,17 +274,6 @@ void si5351c_enable_clock_outputs(si5351c_driver_t* const drv)
SI5351C_OUTPUT_DISABLE);
}
si5351c_regs_commit(drv);
#ifdef IS_H1_R9
if (IS_H1_R9) {
const platform_gpio_t* gpio = platform_gpio();
if (drv->clk[drv->clkout_id].output_enable) {
gpio_set(gpio->h1r9_clkout_en);
} else {
gpio_clear(gpio->h1r9_clkout_en);
}
}
#endif
}
void si5351c_set_int_mode(
@ -339,7 +328,7 @@ bool si5351c_clkin_signal_valid(si5351c_driver_t* const drv)
}
}
void si5351c_clkout_enable(si5351c_driver_t* const drv, bool enable)
static void si5351c_clkout_ms_enable(si5351c_driver_t* const drv, bool enable)
{
drv->clk[drv->clkout_id].output_enable = enable;
drv->clk[drv->clkout_id].power_down = !enable;
@ -351,12 +340,42 @@ void si5351c_clkout_enable(si5351c_driver_t* const drv, bool enable)
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) {
/* MCU clock is shared with CLKOUT. */
si5351c_clkout_enable(drv, enable);
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

88
firmware/common/u128.c Normal file
View file

@ -0,0 +1,88 @@
/*
* Copyright 2026 Great Scott Gadgets <info@greatscottgadgets.com>
*
* 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<cy, t2=t1<t0, cy=cy+t2, t1-t0)
#define SUBcc(a,b,cy,t0,t1) \
(t0=(b), t1=(a), cy=t1<t0, t1-t0)
#define SUBC(a,b,cy,t0,t1) \
(t0=(b)+cy, t1=(a), t1-t0)
#define ADDCcc(a,b,cy,t0,t1) \
(t0=(b)+cy, t1=(a), cy=t0<cy, t0=t0+t1, t1=t0<t1, cy=cy+t1, t0=t0)
#define ADDcc(a,b,cy,t0,t1) \
(t0=(b), t1=(a), t0=t0+t1, cy=t0<t1, t0=t0)
#define ADDC(a,b,cy,t0,t1) \
(t0=(b)+cy, t1=(a), t0+t1)
/* clang-format on */
u128 u128_divide(u128 dvnd, u128 dvsr)
{
u128 quot, rem, tmp;
uint64_t cy, t0, t1, t2;
quot.hi = dvnd.hi;
quot.lo = dvnd.lo;
rem.hi = 0;
rem.lo = 0;
for (int i = 0; i < 128; i++) {
quot.lo = ADDcc(quot.lo, quot.lo, cy, t0, t1);
quot.hi = ADDCcc(quot.hi, quot.hi, cy, t0, t1);
rem.lo = ADDCcc(rem.lo, rem.lo, cy, t0, t1);
rem.hi = ADDC(rem.hi, rem.hi, cy, t0, t1);
tmp.lo = SUBcc(rem.lo, dvsr.lo, cy, t0, t1);
tmp.hi = SUBCcc(rem.hi, dvsr.hi, cy, t0, t1, t2);
if (!cy) { // remainder >= divisor
rem.lo = tmp.lo;
rem.hi = tmp.hi;
quot.lo |= 1;
}
}
return quot;
}

32
firmware/common/u128.h Normal file
View file

@ -0,0 +1,32 @@
/*
* Copyright 2026 Great Scott Gadgets <info@greatscottgadgets.com>
*
* 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 <stdint.h>
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);

View file

@ -760,7 +760,7 @@ const hackrf_ui_t portapack_hackrf_ui = {
const hackrf_ui_t* portapack_hackrf_ui_init(void)
{
if (portapack()) {
if (portapack_present()) {
return &portapack_hackrf_ui;
} else {
return NULL;

Binary file not shown.

View file

@ -240,6 +240,7 @@ 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()
@ -255,7 +256,9 @@ 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)

View file

@ -203,6 +203,7 @@ macro(DeclareTargets)
${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")

View file

@ -36,6 +36,8 @@
#include <delay.h>
#include <fixed_point.h>
#include <hackrf_ui.h>
#include <i2c_bus.h>
#include <i2c_lpc.h>
#include <leds.h>
#include <operacake.h>
#include <mixer.h>
@ -426,6 +428,8 @@ int main(void)
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();
@ -487,6 +491,9 @@ int main(void)
#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__);

View file

@ -132,7 +132,7 @@ usb_request_status_t usb_vendor_request_init_sweep(
radio_reg_write(
&radio,
RADIO_BANK_ACTIVE,
RADIO_BANK_REQUESTED,
RADIO_FREQUENCY_RF,
(sweep_freq + offset) * FP_ONE_HZ);
usb_transfer_schedule_ack(endpoint->in);
@ -263,7 +263,7 @@ void sweep_mode(uint32_t seq)
nvic_disable_irq(NVIC_USB0_IRQ);
radio_reg_write(
&radio,
RADIO_BANK_ACTIVE,
RADIO_BANK_REQUESTED,
RADIO_FREQUENCY_RF,
(sweep_freq + offset) * FP_ONE_HZ);
nvic_enable_irq(NVIC_USB0_IRQ);

View file

@ -94,12 +94,12 @@ usb_request_status_t usb_vendor_request_set_baseband_filter_bandwidth(
(endpoint->setup.index << 16) | endpoint->setup.value;
radio_reg_write(
&radio,
RADIO_BANK_ACTIVE,
RADIO_BANK_REQUESTED,
RADIO_BB_BANDWIDTH_TX,
bandwidth);
radio_reg_write(
&radio,
RADIO_BANK_ACTIVE,
RADIO_BANK_REQUESTED,
RADIO_BB_BANDWIDTH_RX,
bandwidth);
usb_transfer_schedule_ack(endpoint->in);
@ -123,22 +123,22 @@ usb_request_status_t usb_vendor_request_set_freq(
set_freq_params.freq_mhz * 1000000ULL + set_freq_params.freq_hz;
radio_reg_write(
&radio,
RADIO_BANK_ACTIVE,
RADIO_BANK_REQUESTED,
RADIO_FREQUENCY_RF,
freq * FP_ONE_HZ);
radio_reg_write(
&radio,
RADIO_BANK_ACTIVE,
RADIO_BANK_REQUESTED,
RADIO_FREQUENCY_IF,
RADIO_UNSET);
radio_reg_write(
&radio,
RADIO_BANK_ACTIVE,
RADIO_BANK_REQUESTED,
RADIO_FREQUENCY_LO,
RADIO_UNSET);
radio_reg_write(
&radio,
RADIO_BANK_ACTIVE,
RADIO_BANK_REQUESTED,
RADIO_IMAGE_REJECT,
RADIO_UNSET);
usb_transfer_schedule_ack(endpoint->in);
@ -160,17 +160,17 @@ usb_request_status_t usb_vendor_request_set_freq_explicit(
} else if (stage == USB_TRANSFER_STAGE_DATA) {
radio_reg_write(
&radio,
RADIO_BANK_ACTIVE,
RADIO_BANK_REQUESTED,
RADIO_FREQUENCY_IF,
explicit_params.if_freq_hz * FP_ONE_HZ);
radio_reg_write(
&radio,
RADIO_BANK_ACTIVE,
RADIO_BANK_REQUESTED,
RADIO_FREQUENCY_LO,
explicit_params.lo_freq_hz * FP_ONE_HZ);
radio_reg_write(
&radio,
RADIO_BANK_ACTIVE,
RADIO_BANK_REQUESTED,
RADIO_IMAGE_REJECT,
explicit_params.path);
usb_transfer_schedule_ack(endpoint->in);
@ -215,7 +215,7 @@ usb_request_status_t usb_vendor_request_set_sample_rate_frac(
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_ACTIVE, RADIO_SAMPLE_RATE, value);
radio_reg_write(&radio, RADIO_BANK_REQUESTED, RADIO_SAMPLE_RATE, value);
usb_transfer_schedule_ack(endpoint->in);
}
return USB_REQUEST_STATUS_OK;
@ -228,12 +228,12 @@ usb_request_status_t usb_vendor_request_set_amp_enable(
if (stage == USB_TRANSFER_STAGE_SETUP) {
radio_reg_write(
&radio,
RADIO_BANK_ACTIVE,
RADIO_BANK_REQUESTED,
RADIO_GAIN_TX_RF,
endpoint->setup.value);
radio_reg_write(
&radio,
RADIO_BANK_ACTIVE,
RADIO_BANK_REQUESTED,
RADIO_GAIN_RX_RF,
endpoint->setup.value);
usb_transfer_schedule_ack(endpoint->in);
@ -247,7 +247,7 @@ usb_request_status_t usb_vendor_request_set_lna_gain(
{
if (stage == USB_TRANSFER_STAGE_SETUP) {
uint8_t gain = endpoint->setup.index;
radio_reg_write(&radio, RADIO_BANK_ACTIVE, RADIO_GAIN_RX_IF, gain);
radio_reg_write(&radio, RADIO_BANK_REQUESTED, RADIO_GAIN_RX_IF, gain);
endpoint->buffer[0] = RADIO_OK;
usb_transfer_schedule_block(
endpoint->in,
@ -266,7 +266,7 @@ usb_request_status_t usb_vendor_request_set_vga_gain(
{
if (stage == USB_TRANSFER_STAGE_SETUP) {
uint8_t gain = endpoint->setup.index;
radio_reg_write(&radio, RADIO_BANK_ACTIVE, RADIO_GAIN_RX_BB, gain);
radio_reg_write(&radio, RADIO_BANK_REQUESTED, RADIO_GAIN_RX_BB, gain);
endpoint->buffer[0] = RADIO_OK;
usb_transfer_schedule_block(
endpoint->in,
@ -285,7 +285,7 @@ usb_request_status_t usb_vendor_request_set_txvga_gain(
{
if (stage == USB_TRANSFER_STAGE_SETUP) {
uint8_t gain = endpoint->setup.index;
radio_reg_write(&radio, RADIO_BANK_ACTIVE, RADIO_GAIN_TX_IF, gain);
radio_reg_write(&radio, RADIO_BANK_REQUESTED, RADIO_GAIN_TX_IF, gain);
endpoint->buffer[0] = RADIO_OK;
usb_transfer_schedule_block(
endpoint->in,
@ -315,7 +315,7 @@ usb_request_status_t usb_vendor_request_set_antenna_enable(
if (stage == USB_TRANSFER_STAGE_SETUP) {
radio_reg_write(
&radio,
RADIO_BANK_ACTIVE,
RADIO_BANK_REQUESTED,
RADIO_BIAS_TEE,
endpoint->setup.value);
usb_transfer_schedule_ack(endpoint->in);
@ -427,7 +427,7 @@ usb_request_status_t usb_vendor_request_set_hw_sync_mode(
if (stage == USB_TRANSFER_STAGE_SETUP) {
radio_reg_write(
&radio,
RADIO_BANK_ACTIVE,
RADIO_BANK_REQUESTED,
RADIO_TRIGGER,
endpoint->setup.value);
usb_transfer_schedule_ack(endpoint->in);

View file

@ -28,7 +28,7 @@
#define USB_VENDOR_ID (0x1D50)
#define USB_API_VERSION (0x0112)
#define USB_API_VERSION (0x0113)
#define USB_WORD(x) (x & 0xFF), ((x >> 8) & 0xFF)

View file

@ -501,7 +501,7 @@ int radio_read_register(
return result;
}
#define RADIO_NUM_REGS (23)
#define RADIO_NUM_REGS (24)
int radio_read_registers(hackrf_device* device, const uint8_t bank)
{

View file

@ -57,6 +57,7 @@ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSI
#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.
@ -3496,7 +3497,7 @@ int ADDCALL hackrf_set_fpga_bitstream(hackrf_device* device, const uint8_t index
0,
NULL,
0,
DEFAULT_REQUEST_TIMEOUT);
FPGA_BITSTREAM_TIMEOUT);
if (result != 0) {
last_libusb_error = result;