Skip to content
This repository was archived by the owner on Mar 29, 2026. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 10 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,18 +66,18 @@ jobs:
elif [[ $OS == mac* ]]
then
brew install airspy hackrf librtlsdr libbladerf limesuite portaudio uhd

wget -nv https://github.com/analogdevicesinc/libiio/releases/download/v0.23/macOS-10.15.pkg
sudo installer -pkg macOS-10.15.pkg -target /
sudo cp /Library/Frameworks/iio.framework/iio /usr/local/lib/libiio.dylib
sudo install_name_tool -id "/usr/local/lib/libiio.dylib" /usr/local/lib/libiio.dylib
file /usr/local/lib/libiio.dylib
otool -L /usr/local/lib/libiio.dylib
sudo cp /Library/Frameworks/iio.framework/Versions/0.23/Headers/iio.h /usr/local/include
wget -nv https://www.sdrplay.com/software/SDRplay_RSP_API-MacOSX-2.13.2.pkg
sudo installer -pkg SDRplay_RSP_API-MacOSX-2.13.2.pkg -target /

wget -nv https://www.sdrplay.com/software/SDRplayAPI-macos-installer-universal-3.15.1.pkg
sudo installer -pkg SDRplayAPI-macos-installer-universal-3.15.1.pkg -target /

pip install pyaudio
pip install pillow
fi
Expand All @@ -97,6 +97,11 @@ jobs:
- run: python setup.py bdist_wheel
if: ${{ !startsWith(matrix.os, 'ubuntu') }}

- name: Build manylinux Docker image
if: startsWith(matrix.os, 'ubuntu')
run: |
docker build -t urh_manylinux2_28 -f data/manylinux.Dockerfile .

- name: Build manylinux wheels
if: startsWith(matrix.os, 'ubuntu')
run: |
Expand Down
13 changes: 7 additions & 6 deletions data/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,14 @@ RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone \
gr-osmosdr \
libhackrf-dev liblimesuite-dev libbladerf-dev librtlsdr-dev libairspy-dev libuhd-dev libiio-dev \
&& python3 -m pip install setuptools cython \
&& wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.15.2.run -O /tmp/sdrplay.run \
&& mkdir /tmp/sdrplay \
&& wget http://www.sdrplay.com/software/SDRplay_RSP_API-Linux-2.13.1.run -O /tmp/sdrplay/sdrplay.run \
&& cd /tmp/sdrplay && bash sdrplay.run --tar xf \
&& cp mirsdrapi-rsp.h /usr/local/include \
&& cp x86_64/libmirsdrapi-rsp.so.2.13 /usr/lib/x86_64-linux-gnu/ \
&& ln -s /usr/lib/x86_64-linux-gnu/libmirsdrapi-rsp.so.2.13 /usr/lib/x86_64-linux-gnu/libmirsdrapi-rsp.so \
&& rm -rf /tmp/sdrplay \
&& bash /tmp/sdrplay.run --tar xf -C /tmp/sdrplay \
&& mv /tmp/sdrplay/inc/sdrplay_*.h /usr/local/include \
&& mv /tmp/sdrplay/amd64/libsdrplay_api.so.3.15 /usr/local/lib \
&& ln -s /usr/local/lib/libsdrplay_api.so.3.15 /usr/local/lib/libsdrplay_api.so.3 \
&& ln -s /usr/local/lib/libsdrplay_api.so.3 /usr/local/lib/libsdrplay_api.so \
&& rm -rf /tmp/sdrplay* \
\
&& cd /tmp && git clone --depth=1 https://github.com/jopohl/urh \
&& cd /tmp/urh \
Expand Down
140 changes: 89 additions & 51 deletions data/manylinux.Dockerfile
Original file line number Diff line number Diff line change
@@ -1,53 +1,91 @@
FROM quay.io/pypa/manylinux_2_34_x86_64:2025.12.07-1

RUN yum -y install wget blas libusb-devel fftw-devel cmake3 boost-devel https://github.com/analogdevicesinc/libiio/releases/download/v0.26/libiio-0.26.ga0eca0d-Linux-Fedora-28.rpm
RUN export AIRSPY_VERSION="1.0.9" \
&& export BLADERF_VERSION="2022.11" \
&& export LIMESUITE_VERSION="23.11.0" \
&& export HACKRF_VERSION="v2023.01.1" \
&& export SDRPLAY_VERSION="2.13" \
&& export RTLSDR_VERSION="0.6.0" \
&& export UHD_VERSION="4.5.0.0" \
# HackRF
&& git clone --branch $HACKRF_VERSION --depth 1 https://github.com/greatscottgadgets/hackrf /tmp/hackrf-$HACKRF_VERSION \
&& cmake3 -Wno-dev -S /tmp/hackrf-$HACKRF_VERSION/host -B /tmp/build_hackrf \
&& make -j$(nproc) -C /tmp/build_hackrf \
&& make -C /tmp/build_hackrf install \
# UHD
&& wget https://github.com/EttusResearch/uhd/archive/v$UHD_VERSION.tar.gz -O /tmp/uhd.tar.gz \
&& tar xf /tmp/uhd.tar.gz -C /tmp \
&& python3.12 -m pip install mako requests numpy ruamel.yaml \
&& cmake3 -DBOOST_INCLUDEDIR=/usr/include/boost/ -DBOOST_LIBRARYDIR=/usr/lib64/boost/ -DENABLE_EXAMPLES=OFF -DENABLE_UTILS=OFF -DENABLE_C_API=ON -DENABLE_TESTS=OFF -DENABLE_MAN_PAGES=OFF -S /tmp/uhd-$UHD_VERSION/host -B /tmp/build_uhd \
&& make -j$(nproc) -C /tmp/build_uhd \
&& make -C /tmp/build_uhd install \
# AirSpy
&& wget https://github.com/airspy/airspyone_host/archive/v$AIRSPY_VERSION.tar.gz -O /tmp/airspy.tar.gz \
&& tar xf /tmp/airspy.tar.gz -C /tmp \
&& cmake3 -Wno-dev -S /tmp/airspyone_host-$AIRSPY_VERSION -B /tmp/build_airspy \
&& make -j$(nproc) -C /tmp/build_airspy \
&& make -C /tmp/build_airspy install \
# BladeRF
&& git clone --branch $BLADERF_VERSION --recursive https://github.com/Nuand/bladeRF /tmp/bladeRF-$BLADERF_VERSION \
&& cmake -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -DCMAKE_C_FLAGS="-Wno-maybe-uninitialized -Wno-calloc-transposed-args" -S /tmp/bladeRF-$BLADERF_VERSION/host -B /tmp/build_blade \
&& make -j$(nproc) -C /tmp/build_blade \
&& make -C /tmp/build_blade install \
# Lime
&& wget https://github.com/myriadrf/LimeSuite/archive/v$LIMESUITE_VERSION.tar.gz -O /tmp/lime.tar.gz \
&& tar xf /tmp/lime.tar.gz -C /tmp \
&& cmake -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -S /tmp/LimeSuite-$LIMESUITE_VERSION -B /tmp/build_lime \
&& make -j$(nproc) -C /tmp/build_lime \
&& make -C /tmp/build_lime install \
# RTLSDR
&& wget https://github.com/osmocom/rtl-sdr/archive/$RTLSDR_VERSION.tar.gz -O /tmp/rtlsdr.tar.gz \
&& tar xf /tmp/rtlsdr.tar.gz -C /tmp \
&& cmake -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -DDETACH_KERNEL_DRIVER=ON -S /tmp/rtl-sdr-$RTLSDR_VERSION -B /tmp/build_rtlsdr \
&& make -j$(nproc) -C /tmp/build_rtlsdr \
&& make -C /tmp/build_rtlsdr install \
# SDRPLAY
&& wget http://www.sdrplay.com/software/SDRplay_RSP_API-Linux-$SDRPLAY_VERSION.1.run -O /tmp/sdrplay.run \
&& bash /tmp/sdrplay.run --tar xf -C /tmp \
&& mv /tmp/mirsdrapi-rsp.h /usr/include \
&& mv /tmp/x86_64/* /usr/lib64 \
&& ln -s /usr/lib64/libmirsdrapi-rsp.so.$SDRPLAY_VERSION /usr/lib64/libmirsdrapi-rsp.so \
&& rm -rf /tmp/* \
&& yum clean all
# Define SDR library versions
ARG AIRSPY_VERSION="1.0.9"
ARG BLADERF_VERSION="2022.11"
ARG LIMESUITE_VERSION="23.11.0"
ARG HACKRF_VERSION="v2023.01.1"
ARG SDRPLAY_VERSION="3.15"
ARG RTLSDR_VERSION="0.6.0"
ARG UHD_VERSION="4.5.0.0"
ARG LIBIIO_VERSION="0.26"

# Install system dependencies and libiio
RUN yum -y install \
wget \
blas \
libusb-devel \
fftw-devel \
cmake3 \
boost-devel \
python3-pip \
https://github.com/analogdevicesinc/libiio/releases/download/v${LIBIIO_VERSION}/libiio-${LIBIIO_VERSION}.ga0eca0d-Linux-Fedora-28.rpm \
&& yum clean all

# Build and install HackRF
RUN git clone --branch ${HACKRF_VERSION} --depth 1 \
https://github.com/greatscottgadgets/hackrf /tmp/hackrf \
&& cmake3 -Wno-dev -S /tmp/hackrf/host -B /tmp/build_hackrf \
&& make -j$(nproc) -C /tmp/build_hackrf \
&& make -C /tmp/build_hackrf install \
&& rm -rf /tmp/hackrf /tmp/build_hackrf

# Build and install UHD
RUN wget -nv https://github.com/EttusResearch/uhd/archive/v${UHD_VERSION}.tar.gz -O /tmp/uhd.tar.gz \
&& tar xf /tmp/uhd.tar.gz -C /tmp \
&& python3.12 -m pip install --no-cache-dir mako==1.1.3 requests numpy ruamel.yaml \
&& cmake3 \
-DBOOST_INCLUDEDIR=/usr/include/boost/ \
-DBOOST_LIBRARYDIR=/usr/lib64/boost/ \
-DENABLE_EXAMPLES=OFF \
-DENABLE_UTILS=OFF \
-DENABLE_C_API=ON \
-DENABLE_TESTS=OFF \
-DENABLE_MAN_PAGES=OFF \
-S /tmp/uhd-${UHD_VERSION}/host \
-B /tmp/build_uhd \
&& make -j$(nproc) -C /tmp/build_uhd \
&& make -C /tmp/build_uhd install \
&& rm -rf /tmp/uhd* /tmp/build_uhd

# Build and install AirSpy
RUN wget -nv https://github.com/airspy/airspyone_host/archive/v${AIRSPY_VERSION}.tar.gz -O /tmp/airspy.tar.gz \
&& tar xf /tmp/airspy.tar.gz -C /tmp \
&& cmake3 -Wno-dev -S /tmp/airspyone_host-${AIRSPY_VERSION} -B /tmp/build_airspy \
&& make -j$(nproc) -C /tmp/build_airspy \
&& make -C /tmp/build_airspy install \
&& rm -rf /tmp/airspy* /tmp/build_airspy

# Build and install BladeRF
RUN git clone --branch ${BLADERF_VERSION} --recursive \
https://github.com/Nuand/bladeRF /tmp/bladeRF \
&& cmake3 -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -DCMAKE_C_FLAGS="-Wno-maybe-uninitialized -Wno-calloc-transposed-args" -S /tmp/bladeRF/host -B /tmp/build_blade -DCMAKE_C_FLAGS="-Wno-error=calloc-transposed-args" \
&& make -j$(nproc) -C /tmp/build_blade \
&& make -C /tmp/build_blade install \
&& rm -rf /tmp/bladeRF /tmp/build_blade

# Build and install LimeSuite
RUN wget -nv https://github.com/myriadrf/LimeSuite/archive/v${LIMESUITE_VERSION}.tar.gz -O /tmp/lime.tar.gz \
&& tar xf /tmp/lime.tar.gz -C /tmp \
&& cmake3 -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -S /tmp/LimeSuite-${LIMESUITE_VERSION} -B /tmp/build_lime \
&& make -j$(nproc) -C /tmp/build_lime \
&& make -C /tmp/build_lime install \
&& rm -rf /tmp/lime* /tmp/build_lime

# Build and install RTL-SDR
RUN wget -nv https://github.com/osmocom/rtl-sdr/archive/${RTLSDR_VERSION}.tar.gz -O /tmp/rtlsdr.tar.gz \
&& tar xf /tmp/rtlsdr.tar.gz -C /tmp \
&& cmake3 -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -DDETACH_KERNEL_DRIVER=ON -S /tmp/rtl-sdr-${RTLSDR_VERSION} -B /tmp/build_rtlsdr \
&& make -j$(nproc) -C /tmp/build_rtlsdr \
&& make -C /tmp/build_rtlsdr install \
&& rm -rf /tmp/rtlsdr* /tmp/build_rtlsdr

# Install SDRplay API
RUN wget -nv https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-${SDRPLAY_VERSION}.2.run -O /tmp/sdrplay.run \
&& mkdir /tmp/sdrplay \
&& bash /tmp/sdrplay.run --tar xf -C /tmp/sdrplay \
&& mv /tmp/sdrplay/inc/sdrplay_*.h /usr/local/include \
&& mv /tmp/sdrplay/amd64/libsdrplay_api.so.${SDRPLAY_VERSION} /usr/local/lib \
&& ln -s /usr/local/lib/libsdrplay_api.so.${SDRPLAY_VERSION} /usr/local/lib/libsdrplay_api.so.3 \
&& ln -s /usr/local/lib/libsdrplay_api.so.3 /usr/local/lib/libsdrplay_api.so \
&& rm -rf /tmp/sdrplay*
12 changes: 6 additions & 6 deletions data/snapcraft.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -186,14 +186,14 @@ parts:
sdrplay:
plugin: dump
source: /lib
stage: [libmirsdrapi-rsp.so.2.13]
stage: [libsdrplay_api.so.3.15]
override-build: |
wget http://www.sdrplay.com/software/SDRplay_RSP_API-Linux-2.13.1.run -O sdrplay.run
wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.15.2.run -O sdrplay.run
bash sdrplay.run --tar xf
cp mirsdrapi-rsp.h /usr/include
cp x86_64/* /lib
cp x86_64/* .
ln -sf /lib/libmirsdrapi-rsp.so.2.13 /lib/libmirsdrapi-rsp.so
cp inc/sdrplay_*.h /usr/include
cp amd64/* /lib
cp amd64/* .
ln -sf /lib/libsdrplay_api.so.3.15 /lib/libsdrplay_api.so.3
snapcraftctl build

bladerf-fpga:
Expand Down
8 changes: 7 additions & 1 deletion src/urh/dev/native/Device.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@


class Device(object):
JOIN_TIMEOUT = 1.0
JOIN_TIMEOUT = 3.0

SYNC_TX_CHUNK_SIZE = 0
CONTINUOUS_TX_CHUNK_SIZE = 0
Expand Down Expand Up @@ -701,7 +701,13 @@ def stop_rx_mode(self, msg):
logger.info("{0}: Stopping RX Mode: {1}".format(self.__class__.__name__, msg))

if hasattr(self, "receive_process") and self.receive_process.is_alive():
start_time = time.time()
self.receive_process.join(self.JOIN_TIMEOUT)
logger.debug(
"{0}: Joined receive process after {1:.2f} seconds".format(
self.__class__.__name__, time.time() - start_time
)
)
if self.receive_process.is_alive():
logger.warning(
"{0}: Receive process is still alive, terminating it".format(
Expand Down
4 changes: 2 additions & 2 deletions src/urh/dev/native/ExtensionHelper.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@
# Use C only for USRP to avoid boost dependency
"usrp": {"lib": "uhd", "test_function": "uhd_usrp_find", "language": "c"},
"sdrplay": {
"lib": "mir_sdr_api" if sys.platform == "win32" else "mirsdrapi-rsp",
"test_function": "mir_sdr_ApiVersion",
"lib": "sdrplay_api",
"test_function": "sdrplay_api_ApiVersion",
},
}

Expand Down
35 changes: 34 additions & 1 deletion src/urh/dev/native/SDRPlay.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from collections import OrderedDict
from multiprocessing.connection import Connection

import time
import numpy as np

from urh.dev.native.Device import Device
Expand Down Expand Up @@ -81,7 +82,10 @@ def has_multi_device_support(self):

@classmethod
def get_device_list(cls):
return [cls.device_dict_to_string(d) for d in sdrplay.get_devices()]
sdrplay.open_api()
devs = [cls.device_dict_to_string(d) for d in sdrplay.get_devices()]
sdrplay.close_api()
return devs

@classmethod
def enter_async_receive_mode(
Expand Down Expand Up @@ -115,6 +119,13 @@ def init_device(
) -> bool:
identifier = parameters["identifier"]

# Open the API session first
ret = sdrplay.open_api()
if ret != 0:
ctrl_connection.send("FAILED TO OPEN SDRPLAY API: {}".format(ret))
return False
ctrl_connection.send("OPENED SDRPLAY API: SUCCESS")

try:
device_list = sdrplay.get_devices()
device_number = int(identifier)
Expand All @@ -127,8 +138,12 @@ def init_device(
ctrl_connection.send(
"SET DEVICE NUMBER to {}:{}".format(device_number, ret)
)
if ret != 0:
sdrplay.close_api()
return False
except (TypeError, ValueError) as e:
logger.exception(e)
sdrplay.close_api()
return False

device_model = device_list[device_number]["hw_version"]
Expand All @@ -154,13 +169,31 @@ def init_device(
@classmethod
def shutdown_device(cls, ctrl_connection, is_tx: bool):
logger.debug("SDRPLAY: closing device")
start_time = time.time()
ret = sdrplay.close_stream()
logger.debug(
"SDRPLAY: closed stream after {:.2f} seconds".format(
time.time() - start_time
)
)
ctrl_connection.send("CLOSE STREAM:" + str(ret))

if cls.sdrplay_device_index is not None:
ret = sdrplay.release_device_index()
ctrl_connection.send("RELEASE DEVICE:" + str(ret))

logger.debug(
"SDRPLAY: closed device after {:.2f} seconds".format(
time.time() - start_time
)
)
ret = sdrplay.close_api()
ctrl_connection.send("CLOSE API:" + str(ret))

logger.debug(
"SDRPLAY: closed API after {:.2f} seconds".format(time.time() - start_time)
)

@staticmethod
def bytes_to_iq(buffer):
return np.frombuffer(buffer, dtype=np.int16).reshape((-1, 2), order="C")
Loading
Loading