mirror of
https://github.com/AlexandreRouma/SDRPlusPlus.git
synced 2025-07-09 18:45:22 +02:00
Compare commits
2 Commits
nightly
...
noise_redu
Author | SHA1 | Date | |
---|---|---|---|
87da47f53d | |||
75050347de |
75
.github/workflows/build_all.yml
vendored
75
.github/workflows/build_all.yml
vendored
@ -34,10 +34,10 @@ jobs:
|
|||||||
|
|
||||||
- name: Patch Pothos with earlier libusb version
|
- name: Patch Pothos with earlier libusb version
|
||||||
working-directory: ${{runner.workspace}}
|
working-directory: ${{runner.workspace}}
|
||||||
run: 7z x libusb.7z -olibusb_old ; rm "C:/Program Files/PothosSDR/bin/libusb-1.0.dll" ; cp "libusb_old/MS64/dll/libusb-1.0.dll" "C:/Program Files/PothosSDR/bin/" ; rm "C:/Program Files/PothosSDR/lib/libusb-1.0.lib" ; cp "libusb_old/MS64/dll/libusb-1.0.lib" "C:/Program Files/PothosSDR/lib/"
|
run: 7z x libusb.7z -olibusb_old ; rm "C:/Program Files/PothosSDR/bin/libusb-1.0.dll" ; cp "libusb_old/MS64/dll/libusb-1.0.dll" "C:/Program Files/PothosSDR/bin/"
|
||||||
|
|
||||||
- name: Download SDRPlay API
|
- name: Download SDRPlay API
|
||||||
run: Invoke-WebRequest -Uri "https://drive.google.com/uc?id=12UHPMwkfa67A11QZDmpCT4iwHnyJHWuu&confirm=t" -OutFile ${{runner.workspace}}/SDRPlay.zip
|
run: Invoke-WebRequest -Uri "https://drive.google.com/uc?id=12UHPMwkfa67A11QZDmpCT4iwHnyJHWuu" -OutFile ${{runner.workspace}}/SDRPlay.zip
|
||||||
|
|
||||||
- name: Install SDRPlay API
|
- name: Install SDRPlay API
|
||||||
run: 7z x ${{runner.workspace}}/SDRPlay.zip -o"C:/Program Files/"
|
run: 7z x ${{runner.workspace}}/SDRPlay.zip -o"C:/Program Files/"
|
||||||
@ -58,17 +58,14 @@ jobs:
|
|||||||
run: mkdir "C:/Program Files/codec2" ; mkdir "C:/Program Files/codec2/include" ; mkdir "C:/Program Files/codec2/include/codec2" ; mkdir "C:/Program Files/codec2/lib" ; cd "codec2" ; xcopy "src" "C:/Program Files/codec2/include" ; cd "build" ; xcopy "src" "C:/Program Files/codec2/lib" ; xcopy "codec2" "C:/Program Files/codec2/include/codec2"
|
run: mkdir "C:/Program Files/codec2" ; mkdir "C:/Program Files/codec2/include" ; mkdir "C:/Program Files/codec2/include/codec2" ; mkdir "C:/Program Files/codec2/lib" ; cd "codec2" ; xcopy "src" "C:/Program Files/codec2/include" ; cd "build" ; xcopy "src" "C:/Program Files/codec2/lib" ; xcopy "codec2" "C:/Program Files/codec2/include/codec2"
|
||||||
|
|
||||||
- name: Install vcpkg dependencies
|
- name: Install vcpkg dependencies
|
||||||
run: vcpkg install fftw3:x64-windows glfw3:x64-windows portaudio:x64-windows zstd:x64-windows libusb:x64-windows
|
run: vcpkg install fftw3:x64-windows glfw3:x64-windows portaudio:x64-windows zstd:x64-windows
|
||||||
|
|
||||||
- name: Install rtaudio
|
- name: Install rtaudio
|
||||||
run: git clone https://github.com/thestk/rtaudio ; cd rtaudio ; git checkout 2f2fca4502d506abc50f6d4473b2836d24cfb1e3 ; mkdir build ; cd build ; cmake .. ; cmake --build . --config Release ; cmake --install .
|
run: git clone https://github.com/thestk/rtaudio ; cd rtaudio ; git checkout 2f2fca4502d506abc50f6d4473b2836d24cfb1e3 ; mkdir build ; cd build ; cmake .. ; cmake --build . --config Release ; cmake --install .
|
||||||
|
|
||||||
- name: Install libperseus-sdr
|
|
||||||
run: git clone https://github.com/AlexandreRouma/libperseus-sdr ; cd libperseus-sdr ; mkdir build ; cd build ; cmake "-DLIBUSB_LIBRARIES=C:/Program Files/PothosSDR/lib/libusb-1.0.lib" "-DLIBUSB_INCLUDE_DIRS=C:/Program Files/PothosSDR/include/libusb-1.0" .. "-DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake" ; cmake --build . --config Release ; mkdir "C:/Program Files/PothosSDR/include/perseus-sdr" ; cp Release/perseus-sdr.dll "C:/Program Files/PothosSDR/bin" ; cp Release/perseus-sdr.lib "C:/Program Files/PothosSDR/bin" ; cd .. ; xcopy "src" "C:/Program Files/PothosSDR/include/perseus-sdr"
|
|
||||||
|
|
||||||
- name: Prepare CMake
|
- name: Prepare CMake
|
||||||
working-directory: ${{runner.workspace}}/build
|
working-directory: ${{runner.workspace}}/build
|
||||||
run: cmake "$Env:GITHUB_WORKSPACE" "-DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake" -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_PERSEUS_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON
|
run: cmake "$Env:GITHUB_WORKSPACE" "-DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake" -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
working-directory: ${{runner.workspace}}/build
|
working-directory: ${{runner.workspace}}/build
|
||||||
@ -96,8 +93,11 @@ jobs:
|
|||||||
- name: Update brew repositories
|
- name: Update brew repositories
|
||||||
run: brew update
|
run: brew update
|
||||||
|
|
||||||
|
- name: Fix stuff
|
||||||
|
run: rm -f /usr/local/bin/2to3* /usr/local/bin/idle3* /usr/local/bin/pydoc3* /usr/local/bin/python3* /usr/local/bin/python3-config* && brew reinstall gettext
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: brew install pkg-config libusb fftw glfw airspy airspyhf portaudio hackrf libbladerf codec2 zstd autoconf automake libtool && pip3 install mako
|
run: brew install pkg-config libusb fftw glfw airspy airspyhf portaudio hackrf rtl-sdr libbladerf codec2 zstd && pip3 install mako
|
||||||
|
|
||||||
- name: Install volk
|
- name: Install volk
|
||||||
run: git clone --recursive https://github.com/gnuradio/volk && cd volk && mkdir build && cd build && cmake -DCMAKE_BUILD_TYPE=Release .. && make -j3 && sudo make install && cd ../../
|
run: git clone --recursive https://github.com/gnuradio/volk && cd volk && mkdir build && cd build && cmake -DCMAKE_BUILD_TYPE=Release .. && make -j3 && sudo make install && cd ../../
|
||||||
@ -106,7 +106,7 @@ jobs:
|
|||||||
run: wget https://www.sdrplay.com/software/SDRplay_RSP_API-MacOSX-3.07.3.pkg && sudo installer -pkg SDRplay_RSP_API-MacOSX-3.07.3.pkg -target /
|
run: wget https://www.sdrplay.com/software/SDRplay_RSP_API-MacOSX-3.07.3.pkg && sudo installer -pkg SDRplay_RSP_API-MacOSX-3.07.3.pkg -target /
|
||||||
|
|
||||||
- name: Install libiio
|
- name: Install libiio
|
||||||
run: wget https://github.com/analogdevicesinc/libiio/archive/refs/tags/v0.25.zip && 7z x v0.25.zip && cd libiio-0.25 && mkdir build && cd build && cmake -DCMAKE_BUILD_TYPE=Release .. && make -j3 && sudo make install && cd ../../
|
run: git clone https://github.com/analogdevicesinc/libiio && cd libiio && mkdir build && cd build && cmake -DCMAKE_BUILD_TYPE=Release .. && make -j3 && sudo make install && cd ../../
|
||||||
|
|
||||||
- name: Install libad9361
|
- name: Install libad9361
|
||||||
run: git clone https://github.com/analogdevicesinc/libad9361-iio && cd libad9361-iio && mkdir build && cd build && cmake -DCMAKE_BUILD_TYPE=Release .. && make -j3 && sudo make install && cd ../../
|
run: git clone https://github.com/analogdevicesinc/libad9361-iio && cd libad9361-iio && mkdir build && cd build && cmake -DCMAKE_BUILD_TYPE=Release .. && make -j3 && sudo make install && cd ../../
|
||||||
@ -114,15 +114,9 @@ jobs:
|
|||||||
- name: Install LimeSuite
|
- name: Install LimeSuite
|
||||||
run: git clone https://github.com/myriadrf/LimeSuite && cd LimeSuite && mkdir builddir && cd builddir && cmake -DCMAKE_BUILD_TYPE=Release .. && make -j3 && sudo make install && cd ../../
|
run: git clone https://github.com/myriadrf/LimeSuite && cd LimeSuite && mkdir builddir && cd builddir && cmake -DCMAKE_BUILD_TYPE=Release .. && make -j3 && sudo make install && cd ../../
|
||||||
|
|
||||||
- name: Install libperseus
|
|
||||||
run: git clone https://github.com/Microtelecom/libperseus-sdr && cd libperseus-sdr && autoreconf -i && ./configure --prefix=/usr/local && make && make install && cd ..
|
|
||||||
|
|
||||||
- name: Install more recent librtlsdr
|
|
||||||
run: git clone https://github.com/osmocom/rtl-sdr && cd rtl-sdr && mkdir build && cd build && cmake -DCMAKE_BUILD_TYPE=Release .. && make -j3 LIBRARY_PATH=$(pkg-config --libs-only-L libusb-1.0 | sed 's/\-L//') && sudo make install && cd ../../
|
|
||||||
|
|
||||||
- name: Prepare CMake
|
- name: Prepare CMake
|
||||||
working-directory: ${{runner.workspace}}/build
|
working-directory: ${{runner.workspace}}/build
|
||||||
run: cmake $GITHUB_WORKSPACE -DOPT_BUILD_PLUTOSDR_SOURCE=ON -DOPT_BUILD_SOAPY_SOURCE=OFF -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_AUDIO_SINK=OFF -DOPT_BUILD_PORTAUDIO_SINK=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON -DOPT_BUILD_PERSEUS_SOURCE=ON -DOPT_BUILD_AUDIO_SOURCE=OFF -DUSE_BUNDLE_DEFAULTS=ON -DCMAKE_BUILD_TYPE=Release
|
run: cmake $GITHUB_WORKSPACE -DOPT_BUILD_PLUTOSDR_SOURCE=ON -DOPT_BUILD_SOAPY_SOURCE=OFF -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_AUDIO_SINK=OFF -DOPT_BUILD_PORTAUDIO_SINK=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON -DOPT_BUILD_AUDIO_SOURCE=OFF -DUSE_BUNDLE_DEFAULTS=ON -DCMAKE_BUILD_TYPE=Release
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
working-directory: ${{runner.workspace}}/build
|
working-directory: ${{runner.workspace}}/build
|
||||||
@ -182,28 +176,6 @@ jobs:
|
|||||||
name: sdrpp_debian_bullseye_amd64
|
name: sdrpp_debian_bullseye_amd64
|
||||||
path: ${{runner.workspace}}/sdrpp_debian_amd64.deb
|
path: ${{runner.workspace}}/sdrpp_debian_amd64.deb
|
||||||
|
|
||||||
build_debian_bookworm:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
|
|
||||||
- name: Create Docker Image
|
|
||||||
run: cd $GITHUB_WORKSPACE/docker_builds/debian_bookworm && docker build . --tag sdrpp_build
|
|
||||||
|
|
||||||
- name: Run Container
|
|
||||||
run: docker run --name build -v $GITHUB_WORKSPACE:/root/SDRPlusPlus --env BUILD_NO="-$GITHUB_RUN_NUMBER" sdrpp_build /root/do_build.sh
|
|
||||||
|
|
||||||
- name: Recover Deb Archive
|
|
||||||
working-directory: ${{runner.workspace}}
|
|
||||||
run: docker cp build:/root/SDRPlusPlus/sdrpp_debian_amd64.deb ./
|
|
||||||
|
|
||||||
- name: Save Deb Archive
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: sdrpp_debian_bookworm_amd64
|
|
||||||
path: ${{runner.workspace}}/sdrpp_debian_amd64.deb
|
|
||||||
|
|
||||||
build_debian_sid:
|
build_debian_sid:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
@ -226,6 +198,28 @@ jobs:
|
|||||||
name: sdrpp_debian_sid_amd64
|
name: sdrpp_debian_sid_amd64
|
||||||
path: ${{runner.workspace}}/sdrpp_debian_amd64.deb
|
path: ${{runner.workspace}}/sdrpp_debian_amd64.deb
|
||||||
|
|
||||||
|
# build_ubuntu_bionic:
|
||||||
|
# runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
# steps:
|
||||||
|
# - uses: actions/checkout@v3
|
||||||
|
|
||||||
|
# - name: Create Docker Image
|
||||||
|
# run: cd $GITHUB_WORKSPACE/docker_builds/ubuntu_bionic && docker build . --tag sdrpp_build
|
||||||
|
|
||||||
|
# - name: Run Container
|
||||||
|
# run: docker run --name build -v $GITHUB_WORKSPACE:/root/SDRPlusPlus --env BUILD_NO="-$GITHUB_RUN_NUMBER" sdrpp_build /root/do_build.sh
|
||||||
|
|
||||||
|
# - name: Recover Deb Archive
|
||||||
|
# working-directory: ${{runner.workspace}}
|
||||||
|
# run: docker cp build:/root/SDRPlusPlus/sdrpp_debian_amd64.deb ./
|
||||||
|
|
||||||
|
# - name: Save Deb Archive
|
||||||
|
# uses: actions/upload-artifact@v3
|
||||||
|
# with:
|
||||||
|
# name: sdrpp_ubuntu_bionic_amd64
|
||||||
|
# path: ${{runner.workspace}}/sdrpp_debian_amd64.deb
|
||||||
|
|
||||||
build_ubuntu_focal:
|
build_ubuntu_focal:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
@ -281,7 +275,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Prepare CMake
|
- name: Prepare CMake
|
||||||
working-directory: ${{runner.workspace}}/build
|
working-directory: ${{runner.workspace}}/build
|
||||||
run: cmake $GITHUB_WORKSPACE -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON -DOPT_BUILD_USRP_SOURCE=ON -DOPT_BUILD_PERSEUS_SOURCE=ON
|
run: cmake $GITHUB_WORKSPACE -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON -DOPT_BUILD_USRP_SOURCE=ON
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
working-directory: ${{runner.workspace}}/build
|
working-directory: ${{runner.workspace}}/build
|
||||||
@ -325,7 +319,7 @@ jobs:
|
|||||||
path: ${{runner.workspace}}/sdrpp.apk
|
path: ${{runner.workspace}}/sdrpp.apk
|
||||||
|
|
||||||
create_full_archive:
|
create_full_archive:
|
||||||
needs: ['build_windows', 'build_macos', 'build_debian_buster', 'build_debian_bullseye', 'build_debian_bookworm', 'build_debian_sid', 'build_ubuntu_focal', 'build_ubuntu_jammy', 'build_raspios_bullseye_armhf', 'build_android']
|
needs: ['build_windows', 'build_macos', 'build_debian_buster', 'build_debian_bullseye', 'build_debian_sid', 'build_ubuntu_focal', 'build_ubuntu_jammy', 'build_raspios_bullseye_armhf', 'build_android']
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
@ -339,7 +333,6 @@ jobs:
|
|||||||
mv sdrpp_macos_intel/sdrpp_macos_intel.zip sdrpp_all/ &&
|
mv sdrpp_macos_intel/sdrpp_macos_intel.zip sdrpp_all/ &&
|
||||||
mv sdrpp_debian_buster_amd64/sdrpp_debian_amd64.deb sdrpp_all/sdrpp_debian_buster_amd64.deb &&
|
mv sdrpp_debian_buster_amd64/sdrpp_debian_amd64.deb sdrpp_all/sdrpp_debian_buster_amd64.deb &&
|
||||||
mv sdrpp_debian_bullseye_amd64/sdrpp_debian_amd64.deb sdrpp_all/sdrpp_debian_bullseye_amd64.deb &&
|
mv sdrpp_debian_bullseye_amd64/sdrpp_debian_amd64.deb sdrpp_all/sdrpp_debian_bullseye_amd64.deb &&
|
||||||
mv sdrpp_debian_bookworm_amd64/sdrpp_debian_amd64.deb sdrpp_all/sdrpp_debian_bookworm_amd64.deb &&
|
|
||||||
mv sdrpp_debian_sid_amd64/sdrpp_debian_amd64.deb sdrpp_all/sdrpp_debian_sid_amd64.deb &&
|
mv sdrpp_debian_sid_amd64/sdrpp_debian_amd64.deb sdrpp_all/sdrpp_debian_sid_amd64.deb &&
|
||||||
mv sdrpp_ubuntu_focal_amd64/sdrpp_debian_amd64.deb sdrpp_all/sdrpp_ubuntu_focal_amd64.deb &&
|
mv sdrpp_ubuntu_focal_amd64/sdrpp_debian_amd64.deb sdrpp_all/sdrpp_ubuntu_focal_amd64.deb &&
|
||||||
mv sdrpp_ubuntu_jammy_amd64/sdrpp_debian_amd64.deb sdrpp_all/sdrpp_ubuntu_jammy_amd64.deb &&
|
mv sdrpp_ubuntu_jammy_amd64/sdrpp_debian_amd64.deb sdrpp_all/sdrpp_ubuntu_jammy_amd64.deb &&
|
||||||
|
@ -17,25 +17,24 @@ option(OPT_BUILD_FILE_SOURCE "Wav file source" ON)
|
|||||||
option(OPT_BUILD_HACKRF_SOURCE "Build HackRF Source Module (Dependencies: libhackrf)" ON)
|
option(OPT_BUILD_HACKRF_SOURCE "Build HackRF Source Module (Dependencies: libhackrf)" ON)
|
||||||
option(OPT_BUILD_HERMES_SOURCE "Build Hermes Source Module (no dependencies required)" ON)
|
option(OPT_BUILD_HERMES_SOURCE "Build Hermes Source Module (no dependencies required)" ON)
|
||||||
option(OPT_BUILD_LIMESDR_SOURCE "Build LimeSDR Source Module (Dependencies: liblimesuite)" OFF)
|
option(OPT_BUILD_LIMESDR_SOURCE "Build LimeSDR Source Module (Dependencies: liblimesuite)" OFF)
|
||||||
option(OPT_BUILD_PERSEUS_SOURCE "Build Perseus Source Module (Dependencies: libperseus-sdr)" OFF)
|
option(OPT_BUILD_SDRPP_SERVER_SOURCE "Build SDR++ Server Source Module (no dependencies required)" ON)
|
||||||
option(OPT_BUILD_PLUTOSDR_SOURCE "Build PlutoSDR Source Module (Dependencies: libiio, libad9361)" ON)
|
|
||||||
option(OPT_BUILD_RFSPACE_SOURCE "Build RFspace Source Module (no dependencies required)" ON)
|
option(OPT_BUILD_RFSPACE_SOURCE "Build RFspace Source Module (no dependencies required)" ON)
|
||||||
option(OPT_BUILD_RTL_SDR_SOURCE "Build RTL-SDR Source Module (Dependencies: librtlsdr)" ON)
|
option(OPT_BUILD_RTL_SDR_SOURCE "Build RTL-SDR Source Module (Dependencies: librtlsdr)" ON)
|
||||||
option(OPT_BUILD_RTL_TCP_SOURCE "Build RTL-TCP Source Module (no dependencies required)" ON)
|
option(OPT_BUILD_RTL_TCP_SOURCE "Build RTL-TCP Source Module (no dependencies required)" ON)
|
||||||
option(OPT_BUILD_SDRPP_SERVER_SOURCE "Build SDR++ Server Source Module (no dependencies required)" ON)
|
|
||||||
option(OPT_BUILD_SDRPLAY_SOURCE "Build SDRplay Source Module (Dependencies: libsdrplay)" OFF)
|
option(OPT_BUILD_SDRPLAY_SOURCE "Build SDRplay Source Module (Dependencies: libsdrplay)" OFF)
|
||||||
option(OPT_BUILD_SOAPY_SOURCE "Build SoapySDR Source Module (Dependencies: soapysdr)" ON)
|
option(OPT_BUILD_SOAPY_SOURCE "Build SoapySDR Source Module (Dependencies: soapysdr)" ON)
|
||||||
option(OPT_BUILD_SPECTRAN_SOURCE "Build Spectran Source Module (Dependencies: Aaronia RTSA Suite)" OFF)
|
option(OPT_BUILD_SPECTRAN_SOURCE "Build Spectran Source Module (Dependencies: Aaronia RTSA Suite)" OFF)
|
||||||
option(OPT_BUILD_SPECTRAN_HTTP_SOURCE "Build Spectran HTTP Source Module (no dependencies required)" ON)
|
option(OPT_BUILD_SPECTRAN_HTTP_SOURCE "Build Spectran HTTP Source Module (no dependencies required)" ON)
|
||||||
option(OPT_BUILD_SPYSERVER_SOURCE "Build SpyServer Source Module (no dependencies required)" ON)
|
option(OPT_BUILD_SPYSERVER_SOURCE "Build SpyServer Source Module (no dependencies required)" ON)
|
||||||
|
option(OPT_BUILD_PLUTOSDR_SOURCE "Build PlutoSDR Source Module (Dependencies: libiio, libad9361)" ON)
|
||||||
option(OPT_BUILD_USRP_SOURCE "Build USRP Source Module (libuhd)" OFF)
|
option(OPT_BUILD_USRP_SOURCE "Build USRP Source Module (libuhd)" OFF)
|
||||||
|
|
||||||
# Sinks
|
# Sinks
|
||||||
option(OPT_BUILD_ANDROID_AUDIO_SINK "Build Android Audio Sink Module (Dependencies: AAudio, only for android)" OFF)
|
option(OPT_BUILD_ANDROID_AUDIO_SINK "Build Android Audio Sink Module (Dependencies: AAudio, only for android)" OFF)
|
||||||
option(OPT_BUILD_AUDIO_SINK "Build Audio Sink Module (Dependencies: rtaudio)" ON)
|
option(OPT_BUILD_AUDIO_SINK "Build Audio Sink Module (Dependencies: rtaudio)" ON)
|
||||||
|
option(OPT_BUILD_PORTAUDIO_SINK "Build PortAudio Sink Module (Dependencies: portaudio)" OFF)
|
||||||
option(OPT_BUILD_NETWORK_SINK "Build Audio Sink Module (no dependencies required)" ON)
|
option(OPT_BUILD_NETWORK_SINK "Build Audio Sink Module (no dependencies required)" ON)
|
||||||
option(OPT_BUILD_NEW_PORTAUDIO_SINK "Build the new PortAudio Sink Module (Dependencies: portaudio)" OFF)
|
option(OPT_BUILD_NEW_PORTAUDIO_SINK "Build the new PortAudio Sink Module (Dependencies: portaudio)" OFF)
|
||||||
option(OPT_BUILD_PORTAUDIO_SINK "Build PortAudio Sink Module (Dependencies: portaudio)" OFF)
|
|
||||||
|
|
||||||
# Decoders
|
# Decoders
|
||||||
option(OPT_BUILD_ATV_DECODER "Build ATV decoder (no dependencies required)" OFF)
|
option(OPT_BUILD_ATV_DECODER "Build ATV decoder (no dependencies required)" OFF)
|
||||||
@ -142,13 +141,9 @@ if (OPT_BUILD_LIMESDR_SOURCE)
|
|||||||
add_subdirectory("source_modules/limesdr_source")
|
add_subdirectory("source_modules/limesdr_source")
|
||||||
endif (OPT_BUILD_LIMESDR_SOURCE)
|
endif (OPT_BUILD_LIMESDR_SOURCE)
|
||||||
|
|
||||||
if (OPT_BUILD_PERSEUS_SOURCE)
|
if (OPT_BUILD_SDRPP_SERVER_SOURCE)
|
||||||
add_subdirectory("source_modules/perseus_source")
|
add_subdirectory("source_modules/sdrpp_server_source")
|
||||||
endif (OPT_BUILD_PERSEUS_SOURCE)
|
endif (OPT_BUILD_SDRPP_SERVER_SOURCE)
|
||||||
|
|
||||||
if (OPT_BUILD_PLUTOSDR_SOURCE)
|
|
||||||
add_subdirectory("source_modules/plutosdr_source")
|
|
||||||
endif (OPT_BUILD_PLUTOSDR_SOURCE)
|
|
||||||
|
|
||||||
if (OPT_BUILD_RFSPACE_SOURCE)
|
if (OPT_BUILD_RFSPACE_SOURCE)
|
||||||
add_subdirectory("source_modules/rfspace_source")
|
add_subdirectory("source_modules/rfspace_source")
|
||||||
@ -162,10 +157,6 @@ if (OPT_BUILD_RTL_TCP_SOURCE)
|
|||||||
add_subdirectory("source_modules/rtl_tcp_source")
|
add_subdirectory("source_modules/rtl_tcp_source")
|
||||||
endif (OPT_BUILD_RTL_TCP_SOURCE)
|
endif (OPT_BUILD_RTL_TCP_SOURCE)
|
||||||
|
|
||||||
if (OPT_BUILD_SDRPP_SERVER_SOURCE)
|
|
||||||
add_subdirectory("source_modules/sdrpp_server_source")
|
|
||||||
endif (OPT_BUILD_SDRPP_SERVER_SOURCE)
|
|
||||||
|
|
||||||
if (OPT_BUILD_SDRPLAY_SOURCE)
|
if (OPT_BUILD_SDRPLAY_SOURCE)
|
||||||
add_subdirectory("source_modules/sdrplay_source")
|
add_subdirectory("source_modules/sdrplay_source")
|
||||||
endif (OPT_BUILD_SDRPLAY_SOURCE)
|
endif (OPT_BUILD_SDRPLAY_SOURCE)
|
||||||
@ -186,6 +177,10 @@ if (OPT_BUILD_SPYSERVER_SOURCE)
|
|||||||
add_subdirectory("source_modules/spyserver_source")
|
add_subdirectory("source_modules/spyserver_source")
|
||||||
endif (OPT_BUILD_SPYSERVER_SOURCE)
|
endif (OPT_BUILD_SPYSERVER_SOURCE)
|
||||||
|
|
||||||
|
if (OPT_BUILD_PLUTOSDR_SOURCE)
|
||||||
|
add_subdirectory("source_modules/plutosdr_source")
|
||||||
|
endif (OPT_BUILD_PLUTOSDR_SOURCE)
|
||||||
|
|
||||||
if (OPT_BUILD_USRP_SOURCE)
|
if (OPT_BUILD_USRP_SOURCE)
|
||||||
add_subdirectory("source_modules/usrp_source")
|
add_subdirectory("source_modules/usrp_source")
|
||||||
endif (OPT_BUILD_USRP_SOURCE)
|
endif (OPT_BUILD_USRP_SOURCE)
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
# Pull Requests
|
# Pull Requests
|
||||||
|
|
||||||
**I DO NOT ACCEPT PULL-REQUEST FOR FEATURES OR BUGFIXES REQUIRING SIGNIFICANT CODE/STRUCTURE CHANGES.**
|
TODO
|
||||||
**SUCH PULL REQUESTS WILL BE CLOSED AUTOMATICALLY. OPEN AN ISSUE DETAILING FEATURE REQUESTS OR POTENTIAL BUGFIX INSTEAD.**
|
|
||||||
|
|
||||||
# Code Style
|
# Code Style
|
||||||
|
|
||||||
|
@ -108,6 +108,7 @@ elseif (ANDROID)
|
|||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(sdrpp_core PUBLIC
|
target_link_libraries(sdrpp_core PUBLIC
|
||||||
|
/sdr-kit/${ANDROID_ABI}/lib/libcpu_features.a
|
||||||
/sdr-kit/${ANDROID_ABI}/lib/libvolk.so
|
/sdr-kit/${ANDROID_ABI}/lib/libvolk.so
|
||||||
/sdr-kit/${ANDROID_ABI}/lib/libfftw3f.so
|
/sdr-kit/${ANDROID_ABI}/lib/libfftw3f.so
|
||||||
/sdr-kit/${ANDROID_ABI}/lib/libzstd.so
|
/sdr-kit/${ANDROID_ABI}/lib/libzstd.so
|
||||||
|
@ -117,10 +117,6 @@ int sdrpp_main(int argc, char* argv[]) {
|
|||||||
defConfig["colorMap"] = "Classic";
|
defConfig["colorMap"] = "Classic";
|
||||||
defConfig["fftHold"] = false;
|
defConfig["fftHold"] = false;
|
||||||
defConfig["fftHoldSpeed"] = 60;
|
defConfig["fftHoldSpeed"] = 60;
|
||||||
defConfig["fftSmoothing"] = false;
|
|
||||||
defConfig["fftSmoothingSpeed"] = 100;
|
|
||||||
defConfig["snrSmoothing"] = false;
|
|
||||||
defConfig["snrSmoothingSpeed"] = 20;
|
|
||||||
defConfig["fastFFT"] = false;
|
defConfig["fastFFT"] = false;
|
||||||
defConfig["fftHeight"] = 300;
|
defConfig["fftHeight"] = 300;
|
||||||
defConfig["fftRate"] = 20;
|
defConfig["fftRate"] = 20;
|
||||||
@ -181,8 +177,6 @@ int sdrpp_main(int argc, char* argv[]) {
|
|||||||
defConfig["moduleInstances"]["LimeSDR Source"]["enabled"] = true;
|
defConfig["moduleInstances"]["LimeSDR Source"]["enabled"] = true;
|
||||||
defConfig["moduleInstances"]["PlutoSDR Source"]["module"] = "plutosdr_source";
|
defConfig["moduleInstances"]["PlutoSDR Source"]["module"] = "plutosdr_source";
|
||||||
defConfig["moduleInstances"]["PlutoSDR Source"]["enabled"] = true;
|
defConfig["moduleInstances"]["PlutoSDR Source"]["enabled"] = true;
|
||||||
defConfig["moduleInstances"]["PerseusSDR Source"]["module"] = "perseus_source";
|
|
||||||
defConfig["moduleInstances"]["PerseusSDR Source"]["enabled"] = true;
|
|
||||||
defConfig["moduleInstances"]["RFspace Source"]["module"] = "rfspace_source";
|
defConfig["moduleInstances"]["RFspace Source"]["module"] = "rfspace_source";
|
||||||
defConfig["moduleInstances"]["RFspace Source"]["enabled"] = true;
|
defConfig["moduleInstances"]["RFspace Source"]["enabled"] = true;
|
||||||
defConfig["moduleInstances"]["RTL-SDR Source"]["module"] = "rtl_sdr_source";
|
defConfig["moduleInstances"]["RTL-SDR Source"]["module"] = "rtl_sdr_source";
|
||||||
|
@ -12,7 +12,6 @@ namespace sdrpp_credits {
|
|||||||
"Howard0su",
|
"Howard0su",
|
||||||
"John Donkersley",
|
"John Donkersley",
|
||||||
"Joshua Kimsey",
|
"Joshua Kimsey",
|
||||||
"Manawyrm",
|
|
||||||
"Martin Hauke",
|
"Martin Hauke",
|
||||||
"Marvin Sinister",
|
"Marvin Sinister",
|
||||||
"Maxime Biette",
|
"Maxime Biette",
|
||||||
@ -22,6 +21,7 @@ namespace sdrpp_credits {
|
|||||||
"Shuyuan Liu",
|
"Shuyuan Liu",
|
||||||
"Syne Ardwin (WI9SYN)",
|
"Syne Ardwin (WI9SYN)",
|
||||||
"Szymon Zakrent",
|
"Szymon Zakrent",
|
||||||
|
"Tobias Mädel",
|
||||||
"Youssef Touil",
|
"Youssef Touil",
|
||||||
"Zimm"
|
"Zimm"
|
||||||
};
|
};
|
||||||
|
@ -9,7 +9,7 @@ namespace dsp::convert {
|
|||||||
|
|
||||||
StereoToMono(stream<stereo_t>* in) { base_type::init(in); }
|
StereoToMono(stream<stereo_t>* in) { base_type::init(in); }
|
||||||
|
|
||||||
inline int process(int count, const stereo_t* in, float* out) {
|
static inline int process(int count, const stereo_t* in, float* out) {
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
out[i] = (in[i].l + in[i].r) / 2.0f;
|
out[i] = (in[i].l + in[i].r) / 2.0f;
|
||||||
}
|
}
|
||||||
|
183
core/src/dsp/noise_reduction/audio.h
Normal file
183
core/src/dsp/noise_reduction/audio.h
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "../processor.h"
|
||||||
|
#include "../window/nuttall.h"
|
||||||
|
#include <fftw3.h>
|
||||||
|
#include "../convert/stereo_to_mono.h"
|
||||||
|
|
||||||
|
namespace dsp::noise_reduction {
|
||||||
|
class Audio : public Processor<stereo_t, stereo_t> {
|
||||||
|
using base_type = Processor<stereo_t, stereo_t>;
|
||||||
|
public:
|
||||||
|
Audio() {}
|
||||||
|
|
||||||
|
Audio(stream<stereo_t>* in, int bins) { init(in, bins); }
|
||||||
|
|
||||||
|
~Audio() {
|
||||||
|
if (!base_type::_block_init) { return; }
|
||||||
|
base_type::stop();
|
||||||
|
destroyBuffers();
|
||||||
|
}
|
||||||
|
|
||||||
|
void init(stream<stereo_t>* in, int bins) {
|
||||||
|
_bins = bins;
|
||||||
|
complexBins = (bins / 2) + 1;
|
||||||
|
normFactor = 1.0f / (float)_bins;
|
||||||
|
initBuffers();
|
||||||
|
base_type::init(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setBins(int bins) {
|
||||||
|
assert(base_type::_block_init);
|
||||||
|
std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
|
||||||
|
base_type::tempStop();
|
||||||
|
_bins = bins;
|
||||||
|
complexBins = (bins / 2) + 1;
|
||||||
|
normFactor = 1.0f / (float)_bins;
|
||||||
|
destroyBuffers();
|
||||||
|
initBuffers();
|
||||||
|
base_type::tempStart();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setLevel(float level) {
|
||||||
|
_level = powf(10.0f, level * 0.1f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset() {
|
||||||
|
assert(base_type::_block_init);
|
||||||
|
std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
|
||||||
|
base_type::tempStop();
|
||||||
|
buffer::clear(buffer, _bins - 1);
|
||||||
|
buffer::clear(backFFTIn, _bins);
|
||||||
|
buffer::clear(noisePrint, _bins);
|
||||||
|
base_type::tempStart();
|
||||||
|
}
|
||||||
|
|
||||||
|
int process(int count, const stereo_t* in, stereo_t* out) {
|
||||||
|
// Write new input data to buffer
|
||||||
|
convert::StereoToMono::process(count, in, bufferStart);
|
||||||
|
|
||||||
|
// Iterate the FFT
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
// Apply windows
|
||||||
|
volk_32f_x2_multiply_32f(forwFFTIn, &buffer[i], fftWin, _bins);
|
||||||
|
|
||||||
|
// Do forward FFT
|
||||||
|
fftwf_execute(forwardPlan);
|
||||||
|
|
||||||
|
// Get bin amplitude and square to get power
|
||||||
|
volk_32fc_magnitude_32f(ampBuf, (lv_32fc_t*)forwFFTOut, complexBins);
|
||||||
|
|
||||||
|
// Update noise print using a running average
|
||||||
|
volk_32f_s32f_multiply_32f(scaledAmps, ampBuf, alpha, complexBins);
|
||||||
|
volk_32f_s32f_multiply_32f(noisePrint, noisePrint, beta, complexBins);
|
||||||
|
volk_32f_x2_add_32f(noisePrint, noisePrint, scaledAmps, complexBins);
|
||||||
|
|
||||||
|
// Clamp amplitudes
|
||||||
|
volk_32f_x2_max_32f(ampBuf, ampBuf, noisePrint, complexBins);
|
||||||
|
|
||||||
|
// Compute Wiener (funny) filter
|
||||||
|
volk_32f_x2_subtract_32f(scaledAmps, ampBuf, noisePrint, complexBins);
|
||||||
|
volk_32f_x2_divide_32f(scaledAmps, scaledAmps, ampBuf, complexBins);
|
||||||
|
|
||||||
|
// Apply wiener filter to bins
|
||||||
|
volk_32fc_32f_multiply_32fc((lv_32fc_t*)backFFTIn, (lv_32fc_t*)forwFFTOut, scaledAmps, complexBins);
|
||||||
|
|
||||||
|
// Do reverse FFT and get first element
|
||||||
|
fftwf_execute(backwardPlan);
|
||||||
|
out[i].l = backFFTOut[_bins / 2];
|
||||||
|
out[i].r = backFFTOut[_bins / 2];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Correct amplitude
|
||||||
|
volk_32f_s32f_multiply_32f((float*)out, (float*)out, normFactor, count*2);
|
||||||
|
|
||||||
|
// Move buffer buffer
|
||||||
|
memmove(buffer, &buffer[count], (_bins - 1) * sizeof(float));
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
int run() {
|
||||||
|
int count = base_type::_in->read();
|
||||||
|
if (count < 0) { return -1; }
|
||||||
|
|
||||||
|
process(count, base_type::_in->readBuf, base_type::out.writeBuf);
|
||||||
|
|
||||||
|
// Swap if some data was generated
|
||||||
|
base_type::_in->flush();
|
||||||
|
if (!base_type::out.swap(count)) { return -1; }
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void initBuffers() {
|
||||||
|
// Allocate FFT buffers
|
||||||
|
forwFFTIn = (float*)fftwf_malloc(_bins * sizeof(float));
|
||||||
|
forwFFTOut = (complex_t*)fftwf_malloc(_bins * sizeof(complex_t));
|
||||||
|
backFFTIn = (complex_t*)fftwf_malloc(_bins * sizeof(complex_t));
|
||||||
|
backFFTOut = (float*)fftwf_malloc(_bins * sizeof(float));
|
||||||
|
|
||||||
|
// Allocate and clear delay buffer
|
||||||
|
buffer = buffer::alloc<float>(STREAM_BUFFER_SIZE + 64000);
|
||||||
|
bufferStart = &buffer[_bins - 1];
|
||||||
|
buffer::clear(buffer, _bins - 1);
|
||||||
|
|
||||||
|
// Clear backward FFT input
|
||||||
|
buffer::clear(backFFTIn, _bins);
|
||||||
|
|
||||||
|
// Allocate amplitude buffer
|
||||||
|
ampBuf = buffer::alloc<float>(_bins);
|
||||||
|
scaledAmps = buffer::alloc<float>(_bins);
|
||||||
|
noisePrint = buffer::alloc<float>(_bins);
|
||||||
|
buffer::clear(noisePrint, _bins);
|
||||||
|
|
||||||
|
// Allocate and generate Window
|
||||||
|
fftWin = buffer::alloc<float>(_bins);
|
||||||
|
for (int i = 0; i < _bins; i++) { fftWin[i] = window::nuttall(i, _bins - 1); }
|
||||||
|
|
||||||
|
// Plan FFTs
|
||||||
|
forwardPlan = fftwf_plan_dft_r2c_1d(_bins, forwFFTIn, (fftwf_complex*)forwFFTOut, FFTW_ESTIMATE);
|
||||||
|
backwardPlan = fftwf_plan_dft_c2r_1d(_bins, (fftwf_complex*)backFFTIn, backFFTOut, FFTW_ESTIMATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroyBuffers() {
|
||||||
|
fftwf_destroy_plan(forwardPlan);
|
||||||
|
fftwf_destroy_plan(backwardPlan);
|
||||||
|
fftwf_free(forwFFTIn);
|
||||||
|
fftwf_free(forwFFTOut);
|
||||||
|
fftwf_free(backFFTIn);
|
||||||
|
fftwf_free(backFFTOut);
|
||||||
|
buffer::free(buffer);
|
||||||
|
buffer::free(ampBuf);
|
||||||
|
buffer::free(scaledAmps);
|
||||||
|
buffer::free(noisePrint);
|
||||||
|
buffer::free(fftWin);
|
||||||
|
}
|
||||||
|
|
||||||
|
float _level = 0.0f;
|
||||||
|
|
||||||
|
float* forwFFTIn;
|
||||||
|
complex_t* forwFFTOut;
|
||||||
|
complex_t* backFFTIn;
|
||||||
|
float* backFFTOut;
|
||||||
|
|
||||||
|
fftwf_plan forwardPlan;
|
||||||
|
fftwf_plan backwardPlan;
|
||||||
|
|
||||||
|
float* buffer;
|
||||||
|
float* bufferStart;
|
||||||
|
|
||||||
|
float* fftWin;
|
||||||
|
|
||||||
|
float* ampBuf;
|
||||||
|
float* scaledAmps;
|
||||||
|
float* noisePrint;
|
||||||
|
|
||||||
|
int _bins;
|
||||||
|
int complexBins;
|
||||||
|
float normFactor = 1.0f;
|
||||||
|
|
||||||
|
float alpha = 0.0001f;
|
||||||
|
float beta = 0.9999f;
|
||||||
|
};
|
||||||
|
}
|
@ -37,21 +37,17 @@ namespace dsp::noise_reduction {
|
|||||||
|
|
||||||
inline int process(int count, complex_t* in, complex_t* out) {
|
inline int process(int count, complex_t* in, complex_t* out) {
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
// Get signal amplitude
|
// Get signal amplitude and pass value if null
|
||||||
float inAmp = in[i].amplitude();
|
float inAmp = in[i].amplitude();
|
||||||
|
if (!inAmp) {
|
||||||
// Update average amplitude
|
out[i] = in[i];
|
||||||
float gain = 1.0f;
|
|
||||||
if (inAmp != 0.0f) {
|
|
||||||
amp = (amp * _invRate) + (inAmp * _rate);
|
|
||||||
float excess = inAmp / amp;
|
|
||||||
if (excess > _level) {
|
|
||||||
gain = 1.0f / excess;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scale output by gain
|
// Update running average of amplitude
|
||||||
out[i] = in[i] * gain;
|
amp = (_rate*inAmp) + (_invRate*amp);
|
||||||
|
|
||||||
|
// Null out if spike (Note: ideally, it should try to guess the real data)
|
||||||
|
out[i] = (inAmp > _level*amp) ? complex_t{0.0f,0.0f} : in[i];
|
||||||
}
|
}
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
@ -82,7 +82,7 @@ namespace dsp {
|
|||||||
|
|
||||||
inline float fastAmplitude() {
|
inline float fastAmplitude() {
|
||||||
float re_abs = fabsf(re);
|
float re_abs = fabsf(re);
|
||||||
float im_abs = fabsf(im);
|
float im_abs = fabsf(re);
|
||||||
if (re_abs > im_abs) { return re_abs + 0.4f * im_abs; }
|
if (re_abs > im_abs) { return re_abs + 0.4f * im_abs; }
|
||||||
return im_abs + 0.4f * re_abs;
|
return im_abs + 0.4f * re_abs;
|
||||||
}
|
}
|
||||||
|
@ -574,22 +574,10 @@ void MainWindow::draw() {
|
|||||||
// Handle scrollwheel
|
// Handle scrollwheel
|
||||||
int wheel = ImGui::GetIO().MouseWheel;
|
int wheel = ImGui::GetIO().MouseWheel;
|
||||||
if (wheel != 0 && (gui::waterfall.mouseInFFT || gui::waterfall.mouseInWaterfall)) {
|
if (wheel != 0 && (gui::waterfall.mouseInFFT || gui::waterfall.mouseInWaterfall)) {
|
||||||
// Select factor depending on modifier keys
|
|
||||||
double interval;
|
|
||||||
if (ImGui::IsKeyDown(ImGuiKey_LeftShift)) {
|
|
||||||
interval = vfo->snapInterval * 10.0;
|
|
||||||
}
|
|
||||||
else if (ImGui::IsKeyDown(ImGuiKey_LeftAlt)) {
|
|
||||||
interval = vfo->snapInterval * 0.1;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
interval = vfo->snapInterval;
|
|
||||||
}
|
|
||||||
|
|
||||||
double nfreq;
|
double nfreq;
|
||||||
if (vfo != NULL) {
|
if (vfo != NULL) {
|
||||||
nfreq = gui::waterfall.getCenterFrequency() + vfo->generalOffset + (interval * wheel);
|
nfreq = gui::waterfall.getCenterFrequency() + vfo->generalOffset + (vfo->snapInterval * wheel);
|
||||||
nfreq = roundl(nfreq / interval) * interval;
|
nfreq = roundl(nfreq / vfo->snapInterval) * vfo->snapInterval;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
nfreq = gui::waterfall.getCenterFrequency() - (gui::waterfall.getViewBandwidth() * wheel / 20.0);
|
nfreq = gui::waterfall.getCenterFrequency() - (gui::waterfall.getViewBandwidth() * wheel / 20.0);
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
#include <signal_path/signal_path.h>
|
#include <signal_path/signal_path.h>
|
||||||
#include <gui/style.h>
|
#include <gui/style.h>
|
||||||
#include <utils/optionlist.h>
|
#include <utils/optionlist.h>
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
namespace displaymenu {
|
namespace displaymenu {
|
||||||
bool showWaterfall;
|
bool showWaterfall;
|
||||||
@ -23,10 +22,6 @@ namespace displaymenu {
|
|||||||
bool restartRequired = false;
|
bool restartRequired = false;
|
||||||
bool fftHold = false;
|
bool fftHold = false;
|
||||||
int fftHoldSpeed = 60;
|
int fftHoldSpeed = 60;
|
||||||
bool fftSmoothing = false;
|
|
||||||
int fftSmoothingSpeed = 100;
|
|
||||||
bool snrSmoothing = false;
|
|
||||||
int snrSmoothingSpeed = 20;
|
|
||||||
|
|
||||||
OptionList<float, float> uiScales;
|
OptionList<float, float> uiScales;
|
||||||
|
|
||||||
@ -62,10 +57,8 @@ namespace displaymenu {
|
|||||||
IQFrontEnd::FFTWindow::NUTTALL
|
IQFrontEnd::FFTWindow::NUTTALL
|
||||||
};
|
};
|
||||||
|
|
||||||
void updateFFTSpeeds() {
|
void updateFFTHoldSpeed() {
|
||||||
gui::waterfall.setFFTHoldSpeed((float)fftHoldSpeed / ((float)fftRate * 10.0f));
|
gui::waterfall.setFFTHoldSpeed(fftHoldSpeed / (fftRate * 10.0f));
|
||||||
gui::waterfall.setFFTSmoothingSpeed(std::min<float>((float)fftSmoothingSpeed / (float)(fftRate * 10.0f), 1.0f));
|
|
||||||
gui::waterfall.setSNRSmoothingSpeed(std::min<float>((float)snrSmoothingSpeed / (float)(fftRate * 10.0f), 1.0f));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void init() {
|
void init() {
|
||||||
@ -111,13 +104,7 @@ namespace displaymenu {
|
|||||||
fftHold = core::configManager.conf["fftHold"];
|
fftHold = core::configManager.conf["fftHold"];
|
||||||
fftHoldSpeed = core::configManager.conf["fftHoldSpeed"];
|
fftHoldSpeed = core::configManager.conf["fftHoldSpeed"];
|
||||||
gui::waterfall.setFFTHold(fftHold);
|
gui::waterfall.setFFTHold(fftHold);
|
||||||
fftSmoothing = core::configManager.conf["fftSmoothing"];
|
updateFFTHoldSpeed();
|
||||||
fftSmoothingSpeed = core::configManager.conf["fftSmoothingSpeed"];
|
|
||||||
gui::waterfall.setFFTSmoothing(fftSmoothing);
|
|
||||||
snrSmoothing = core::configManager.conf["snrSmoothing"];
|
|
||||||
snrSmoothingSpeed = core::configManager.conf["snrSmoothingSpeed"];
|
|
||||||
gui::waterfall.setSNRSmoothing(snrSmoothing);
|
|
||||||
updateFFTSpeeds();
|
|
||||||
|
|
||||||
// Define and load UI scales
|
// Define and load UI scales
|
||||||
uiScales.define(1.0f, "100%", 1.0f);
|
uiScales.define(1.0f, "100%", 1.0f);
|
||||||
@ -157,47 +144,16 @@ namespace displaymenu {
|
|||||||
core::configManager.conf["fftHold"] = fftHold;
|
core::configManager.conf["fftHold"] = fftHold;
|
||||||
core::configManager.release(true);
|
core::configManager.release(true);
|
||||||
}
|
}
|
||||||
ImGui::SameLine();
|
|
||||||
|
ImGui::LeftLabel("FFT Hold Speed");
|
||||||
ImGui::FillWidth();
|
ImGui::FillWidth();
|
||||||
if (ImGui::InputInt("##sdrpp_fft_hold_speed", &fftHoldSpeed)) {
|
if (ImGui::InputInt("##sdrpp_fft_hold_speed", &fftHoldSpeed)) {
|
||||||
updateFFTSpeeds();
|
updateFFTHoldSpeed();
|
||||||
core::configManager.acquire();
|
core::configManager.acquire();
|
||||||
core::configManager.conf["fftHoldSpeed"] = fftHoldSpeed;
|
core::configManager.conf["fftHoldSpeed"] = fftHoldSpeed;
|
||||||
core::configManager.release(true);
|
core::configManager.release(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui::Checkbox("FFT Smoothing##_sdrpp", &fftSmoothing)) {
|
|
||||||
gui::waterfall.setFFTSmoothing(fftSmoothing);
|
|
||||||
core::configManager.acquire();
|
|
||||||
core::configManager.conf["fftSmoothing"] = fftSmoothing;
|
|
||||||
core::configManager.release(true);
|
|
||||||
}
|
|
||||||
ImGui::SameLine();
|
|
||||||
ImGui::FillWidth();
|
|
||||||
if (ImGui::InputInt("##sdrpp_fft_smoothing_speed", &fftSmoothingSpeed)) {
|
|
||||||
fftSmoothingSpeed = std::max<int>(fftSmoothingSpeed, 1);
|
|
||||||
updateFFTSpeeds();
|
|
||||||
core::configManager.acquire();
|
|
||||||
core::configManager.conf["fftSmoothingSpeed"] = fftSmoothingSpeed;
|
|
||||||
core::configManager.release(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui::Checkbox("SNR Smoothing##_sdrpp", &snrSmoothing)) {
|
|
||||||
gui::waterfall.setSNRSmoothing(snrSmoothing);
|
|
||||||
core::configManager.acquire();
|
|
||||||
core::configManager.conf["snrSmoothing"] = snrSmoothing;
|
|
||||||
core::configManager.release(true);
|
|
||||||
}
|
|
||||||
ImGui::SameLine();
|
|
||||||
ImGui::FillWidth();
|
|
||||||
if (ImGui::InputInt("##sdrpp_snr_smoothing_speed", &snrSmoothingSpeed)) {
|
|
||||||
snrSmoothingSpeed = std::max<int>(snrSmoothingSpeed, 1);
|
|
||||||
updateFFTSpeeds();
|
|
||||||
core::configManager.acquire();
|
|
||||||
core::configManager.conf["snrSmoothingSpeed"] = snrSmoothingSpeed;
|
|
||||||
core::configManager.release(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::LeftLabel("High-DPI Scaling");
|
ImGui::LeftLabel("High-DPI Scaling");
|
||||||
ImGui::FillWidth();
|
ImGui::FillWidth();
|
||||||
if (ImGui::Combo("##sdrpp_ui_scale", &uiScaleId, uiScales.txt)) {
|
if (ImGui::Combo("##sdrpp_ui_scale", &uiScaleId, uiScales.txt)) {
|
||||||
@ -212,7 +168,7 @@ namespace displaymenu {
|
|||||||
if (ImGui::InputInt("##sdrpp_fft_rate", &fftRate, 1, 10)) {
|
if (ImGui::InputInt("##sdrpp_fft_rate", &fftRate, 1, 10)) {
|
||||||
fftRate = std::max<int>(1, fftRate);
|
fftRate = std::max<int>(1, fftRate);
|
||||||
sigpath::iqFrontEnd.setFFTRate(fftRate);
|
sigpath::iqFrontEnd.setFFTRate(fftRate);
|
||||||
updateFFTSpeeds();
|
updateFFTHoldSpeed();
|
||||||
core::configManager.acquire();
|
core::configManager.acquire();
|
||||||
core::configManager.conf["fftRate"] = fftRate;
|
core::configManager.conf["fftRate"] = fftRate;
|
||||||
core::configManager.release(true);
|
core::configManager.release(true);
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <stdint.h>
|
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -689,7 +689,6 @@ namespace ImGui {
|
|||||||
|
|
||||||
void WaterFall::onResize() {
|
void WaterFall::onResize() {
|
||||||
std::lock_guard<std::recursive_mutex> lck(latestFFTMtx);
|
std::lock_guard<std::recursive_mutex> lck(latestFFTMtx);
|
||||||
std::lock_guard<std::mutex> lck2(smoothingBufMtx);
|
|
||||||
// return if widget is too small
|
// return if widget is too small
|
||||||
if (widgetSize.x < 100 || widgetSize.y < 100) {
|
if (widgetSize.x < 100 || widgetSize.y < 100) {
|
||||||
return;
|
return;
|
||||||
@ -741,23 +740,14 @@ namespace ImGui {
|
|||||||
}
|
}
|
||||||
latestFFTHold = new float[dataWidth];
|
latestFFTHold = new float[dataWidth];
|
||||||
|
|
||||||
// Reallocate smoothing buffer
|
|
||||||
if (fftSmoothing) {
|
|
||||||
if (smoothingBuf) { delete[] smoothingBuf; }
|
|
||||||
smoothingBuf = new float[dataWidth];
|
|
||||||
for (int i = 0; i < dataWidth; i++) {
|
|
||||||
smoothingBuf[i] = -1000.0f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (waterfallVisible) {
|
if (waterfallVisible) {
|
||||||
delete[] waterfallFb;
|
delete[] waterfallFb;
|
||||||
waterfallFb = new uint32_t[dataWidth * waterfallHeight];
|
waterfallFb = new uint32_t[dataWidth * waterfallHeight];
|
||||||
memset(waterfallFb, 0, dataWidth * waterfallHeight * sizeof(uint32_t));
|
memset(waterfallFb, 0, dataWidth * waterfallHeight * sizeof(uint32_t));
|
||||||
}
|
}
|
||||||
for (int i = 0; i < dataWidth; i++) {
|
for (int i = 0; i < dataWidth; i++) {
|
||||||
latestFFT[i] = -1000.0f; // Hide everything
|
latestFFT[i] = -1000.0; // Hide everything
|
||||||
latestFFTHold[i] = -1000.0f;
|
latestFFTHold[i] = -1000.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
fftAreaMin = ImVec2(widgetPos.x + (50.0f * style::uiScale), widgetPos.y + (9.0f * style::uiScale));
|
fftAreaMin = ImVec2(widgetPos.x + (50.0f * style::uiScale), widgetPos.y + (9.0f * style::uiScale));
|
||||||
@ -883,26 +873,10 @@ namespace ImGui {
|
|||||||
fftLines = 1;
|
fftLines = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply smoothing if enabled
|
|
||||||
if (fftSmoothing && latestFFT != NULL && smoothingBuf != NULL && fftLines != 0) {
|
|
||||||
std::lock_guard<std::mutex> lck2(smoothingBufMtx);
|
|
||||||
volk_32f_s32f_multiply_32f(latestFFT, latestFFT, fftSmoothingAlpha, dataWidth);
|
|
||||||
volk_32f_s32f_multiply_32f(smoothingBuf, smoothingBuf, fftSmoothingBeta, dataWidth);
|
|
||||||
volk_32f_x2_add_32f(smoothingBuf, latestFFT, smoothingBuf, dataWidth);
|
|
||||||
memcpy(latestFFT, smoothingBuf, dataWidth * sizeof(float));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (selectedVFO != "" && vfos.size() > 0) {
|
if (selectedVFO != "" && vfos.size() > 0) {
|
||||||
float dummy;
|
float dummy;
|
||||||
if (snrSmoothing) {
|
|
||||||
float newSNR = 0.0f;
|
|
||||||
calculateVFOSignalInfo(waterfallVisible ? &rawFFTs[currentFFTLine * rawFFTSize] : rawFFTs, vfos[selectedVFO], dummy, newSNR);
|
|
||||||
selectedVFOSNR = (snrSmoothingBeta*selectedVFOSNR) + (snrSmoothingAlpha*newSNR);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
calculateVFOSignalInfo(waterfallVisible ? &rawFFTs[currentFFTLine * rawFFTSize] : rawFFTs, vfos[selectedVFO], dummy, selectedVFOSNR);
|
calculateVFOSignalInfo(waterfallVisible ? &rawFFTs[currentFFTLine * rawFFTSize] : rawFFTs, vfos[selectedVFO], dummy, selectedVFOSNR);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// If FFT hold is enabled, update it
|
// If FFT hold is enabled, update it
|
||||||
if (fftHold && latestFFT != NULL && latestFFTHold != NULL && fftLines != 0) {
|
if (fftHold && latestFFT != NULL && latestFFTHold != NULL && fftLines != 0) {
|
||||||
@ -1136,45 +1110,6 @@ namespace ImGui {
|
|||||||
fftHoldSpeed = speed;
|
fftHoldSpeed = speed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WaterFall::setFFTSmoothing(bool enabled) {
|
|
||||||
std::lock_guard<std::mutex> lck(smoothingBufMtx);
|
|
||||||
fftSmoothing = enabled;
|
|
||||||
|
|
||||||
// Free buffer if not null
|
|
||||||
if (smoothingBuf) {delete[] smoothingBuf; }
|
|
||||||
|
|
||||||
// If disabled, stop here
|
|
||||||
if (!enabled) {
|
|
||||||
smoothingBuf = NULL;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allocate and copy existing FFT into it
|
|
||||||
smoothingBuf = new float[dataWidth];
|
|
||||||
if (latestFFT) {
|
|
||||||
std::lock_guard<std::recursive_mutex> lck2(latestFFTMtx);
|
|
||||||
memcpy(smoothingBuf, latestFFT, dataWidth * sizeof(float));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
memset(smoothingBuf, 0, dataWidth * sizeof(float));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WaterFall::setFFTSmoothingSpeed(float speed) {
|
|
||||||
std::lock_guard<std::mutex> lck(smoothingBufMtx);
|
|
||||||
fftSmoothingAlpha = speed;
|
|
||||||
fftSmoothingBeta = 1.0f - speed;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WaterFall::setSNRSmoothing(bool enabled) {
|
|
||||||
snrSmoothing = enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WaterFall::setSNRSmoothingSpeed(float speed) {
|
|
||||||
snrSmoothingAlpha = speed;
|
|
||||||
snrSmoothingBeta = 1.0f - speed;
|
|
||||||
}
|
|
||||||
|
|
||||||
float* WaterFall::acquireLatestFFT(int& width) {
|
float* WaterFall::acquireLatestFFT(int& width) {
|
||||||
latestFFTMtx.lock();
|
latestFFTMtx.lock();
|
||||||
if (!latestFFT) {
|
if (!latestFFT) {
|
||||||
|
@ -169,12 +169,6 @@ namespace ImGui {
|
|||||||
void setFFTHold(bool hold);
|
void setFFTHold(bool hold);
|
||||||
void setFFTHoldSpeed(float speed);
|
void setFFTHoldSpeed(float speed);
|
||||||
|
|
||||||
void setFFTSmoothing(bool enabled);
|
|
||||||
void setFFTSmoothingSpeed(float speed);
|
|
||||||
|
|
||||||
void setSNRSmoothing(bool enabled);
|
|
||||||
void setSNRSmoothingSpeed(float speed);
|
|
||||||
|
|
||||||
float* acquireLatestFFT(int& width);
|
float* acquireLatestFFT(int& width);
|
||||||
void releaseLatestFFT();
|
void releaseLatestFFT();
|
||||||
|
|
||||||
@ -188,7 +182,7 @@ namespace ImGui {
|
|||||||
bool mouseInFFT = false;
|
bool mouseInFFT = false;
|
||||||
bool mouseInWaterfall = false;
|
bool mouseInWaterfall = false;
|
||||||
|
|
||||||
float selectedVFOSNR = 0.0f;
|
float selectedVFOSNR = NAN;
|
||||||
|
|
||||||
bool centerFrequencyLocked = false;
|
bool centerFrequencyLocked = false;
|
||||||
|
|
||||||
@ -276,7 +270,6 @@ namespace ImGui {
|
|||||||
std::recursive_mutex buf_mtx;
|
std::recursive_mutex buf_mtx;
|
||||||
std::recursive_mutex latestFFTMtx;
|
std::recursive_mutex latestFFTMtx;
|
||||||
std::mutex texMtx;
|
std::mutex texMtx;
|
||||||
std::mutex smoothingBufMtx;
|
|
||||||
|
|
||||||
float vRange;
|
float vRange;
|
||||||
|
|
||||||
@ -311,9 +304,8 @@ namespace ImGui {
|
|||||||
//std::vector<std::vector<float>> rawFFTs;
|
//std::vector<std::vector<float>> rawFFTs;
|
||||||
int rawFFTSize;
|
int rawFFTSize;
|
||||||
float* rawFFTs = NULL;
|
float* rawFFTs = NULL;
|
||||||
float* latestFFT = NULL;
|
float* latestFFT;
|
||||||
float* latestFFTHold = NULL;
|
float* latestFFTHold;
|
||||||
float* smoothingBuf = NULL;
|
|
||||||
int currentFFTLine = 0;
|
int currentFFTLine = 0;
|
||||||
int fftLines = 0;
|
int fftLines = 0;
|
||||||
|
|
||||||
@ -333,14 +325,6 @@ namespace ImGui {
|
|||||||
bool fftHold = false;
|
bool fftHold = false;
|
||||||
float fftHoldSpeed = 0.3f;
|
float fftHoldSpeed = 0.3f;
|
||||||
|
|
||||||
bool fftSmoothing = false;
|
|
||||||
float fftSmoothingAlpha = 0.5;
|
|
||||||
float fftSmoothingBeta = 0.5;
|
|
||||||
|
|
||||||
bool snrSmoothing = false;
|
|
||||||
float snrSmoothingAlpha = 0.5;
|
|
||||||
float snrSmoothingBeta = 0.5;
|
|
||||||
|
|
||||||
// UI Select elements
|
// UI Select elements
|
||||||
bool fftResizeSelect = false;
|
bool fftResizeSelect = false;
|
||||||
bool freqScaleSelect = false;
|
bool freqScaleSelect = false;
|
||||||
|
@ -33,7 +33,7 @@ ModuleManager::Module_t ModuleManager::loadModule(std::string path) {
|
|||||||
#else
|
#else
|
||||||
mod.handle = dlopen(path.c_str(), RTLD_LAZY | RTLD_LOCAL);
|
mod.handle = dlopen(path.c_str(), RTLD_LAZY | RTLD_LOCAL);
|
||||||
if (mod.handle == NULL) {
|
if (mod.handle == NULL) {
|
||||||
flog::error("Couldn't load {0}: {1}", path, dlerror());
|
flog::error("Couldn't load {0}.", path);
|
||||||
mod.handle = NULL;
|
mod.handle = NULL;
|
||||||
return mod;
|
return mod;
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
#include <utils/flog.h>
|
#include <utils/flog.h>
|
||||||
|
|
||||||
bool ModuleComManager::registerInterface(std::string moduleName, std::string name, void (*handler)(int code, void* in, void* out, void* ctx), void* ctx) {
|
bool ModuleComManager::registerInterface(std::string moduleName, std::string name, void (*handler)(int code, void* in, void* out, void* ctx), void* ctx) {
|
||||||
std::lock_guard<std::recursive_mutex> lck(mtx);
|
std::lock_guard<std::mutex> lck(mtx);
|
||||||
if (interfaces.find(name) != interfaces.end()) {
|
if (interfaces.find(name) != interfaces.end()) {
|
||||||
flog::error("Tried creating module interface with an existing name: {0}", name);
|
flog::error("Tried creating module interface with an existing name: {0}", name);
|
||||||
return false;
|
return false;
|
||||||
@ -16,7 +16,7 @@ bool ModuleComManager::registerInterface(std::string moduleName, std::string nam
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool ModuleComManager::unregisterInterface(std::string name) {
|
bool ModuleComManager::unregisterInterface(std::string name) {
|
||||||
std::lock_guard<std::recursive_mutex> lck(mtx);
|
std::lock_guard<std::mutex> lck(mtx);
|
||||||
if (interfaces.find(name) == interfaces.end()) {
|
if (interfaces.find(name) == interfaces.end()) {
|
||||||
flog::error("Tried to erase module interface with unknown name: {0}", name);
|
flog::error("Tried to erase module interface with unknown name: {0}", name);
|
||||||
return false;
|
return false;
|
||||||
@ -26,13 +26,13 @@ bool ModuleComManager::unregisterInterface(std::string name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool ModuleComManager::interfaceExists(std::string name) {
|
bool ModuleComManager::interfaceExists(std::string name) {
|
||||||
std::lock_guard<std::recursive_mutex> lck(mtx);
|
std::lock_guard<std::mutex> lck(mtx);
|
||||||
if (interfaces.find(name) == interfaces.end()) { return false; }
|
if (interfaces.find(name) == interfaces.end()) { return false; }
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ModuleComManager::getModuleName(std::string name) {
|
std::string ModuleComManager::getModuleName(std::string name) {
|
||||||
std::lock_guard<std::recursive_mutex> lck(mtx);
|
std::lock_guard<std::mutex> lck(mtx);
|
||||||
if (interfaces.find(name) == interfaces.end()) {
|
if (interfaces.find(name) == interfaces.end()) {
|
||||||
flog::error("Tried to call unknown module interface: {0}", name);
|
flog::error("Tried to call unknown module interface: {0}", name);
|
||||||
return "";
|
return "";
|
||||||
@ -41,7 +41,7 @@ std::string ModuleComManager::getModuleName(std::string name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool ModuleComManager::callInterface(std::string name, int code, void* in, void* out) {
|
bool ModuleComManager::callInterface(std::string name, int code, void* in, void* out) {
|
||||||
std::lock_guard<std::recursive_mutex> lck(mtx);
|
std::lock_guard<std::mutex> lck(mtx);
|
||||||
if (interfaces.find(name) == interfaces.end()) {
|
if (interfaces.find(name) == interfaces.end()) {
|
||||||
flog::error("Tried to call unknown module interface: {0}", name);
|
flog::error("Tried to call unknown module interface: {0}", name);
|
||||||
return false;
|
return false;
|
||||||
|
@ -18,6 +18,6 @@ public:
|
|||||||
bool callInterface(std::string name, int code, void* in, void* out);
|
bool callInterface(std::string name, int code, void* in, void* out);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::recursive_mutex mtx;
|
std::mutex mtx;
|
||||||
std::map<std::string, ModuleComInterface> interfaces;
|
std::map<std::string, ModuleComInterface> interfaces;
|
||||||
};
|
};
|
@ -1,7 +1,6 @@
|
|||||||
#include "net.h"
|
#include "net.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <codecvt>
|
#include <codecvt>
|
||||||
#include <stdexcept>
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#define WOULD_BLOCK (WSAGetLastError() == WSAEWOULDBLOCK)
|
#define WOULD_BLOCK (WSAGetLastError() == WSAEWOULDBLOCK)
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string>
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
@ -1,52 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <functional>
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <mutex>
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
typedef int HandlerID;
|
|
||||||
|
|
||||||
template <typename... Args>
|
|
||||||
class NewEvent {
|
|
||||||
public:
|
|
||||||
using Handler = std::function<void(Args...)>;
|
|
||||||
|
|
||||||
HandlerID bind(const Handler& handler) {
|
|
||||||
std::lock_guard<std::mutex> lck(mtx);
|
|
||||||
HandlerID id = genID();
|
|
||||||
handlers[id] = handler;
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename MHandler, class T>
|
|
||||||
HandlerID bind(MHandler handler, T* ctx) {
|
|
||||||
return bind([=](Args... args){
|
|
||||||
(ctx->*handler)(args...);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void unbind(HandlerID id) {
|
|
||||||
std::lock_guard<std::mutex> lck(mtx);
|
|
||||||
if (handlers.find(id) == handlers.end()) {
|
|
||||||
throw std::runtime_error("Could not unbind handler, unknown ID");
|
|
||||||
}
|
|
||||||
handlers.erase(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
void operator()(Args... args) {
|
|
||||||
std::lock_guard<std::mutex> lck(mtx);
|
|
||||||
for (const auto& [desc, handler] : handlers) {
|
|
||||||
handler(args...);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
HandlerID genID() {
|
|
||||||
int id;
|
|
||||||
for (id = 1; handlers.find(id) != handlers.end(); id++);
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::map<HandlerID, Handler> handlers;
|
|
||||||
std::mutex mtx;
|
|
||||||
};
|
|
@ -91,9 +91,9 @@ namespace riff {
|
|||||||
file.write((char*)&desc.hdr.size, sizeof(desc.hdr.size));
|
file.write((char*)&desc.hdr.size, sizeof(desc.hdr.size));
|
||||||
file.seekp(pos);
|
file.seekp(pos);
|
||||||
|
|
||||||
// If parent chunk, increment its size by the size of the sub-chunk plus the size of its header)
|
// If parent chunk, increment its size
|
||||||
if (!chunks.empty()) {
|
if (!chunks.empty()) {
|
||||||
chunks.top().hdr.size += desc.hdr.size + sizeof(ChunkHeader);
|
chunks.top().hdr.size += desc.hdr.size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,13 +57,10 @@ public:
|
|||||||
if (config.conf[name].contains("brokenModulation")) {
|
if (config.conf[name].contains("brokenModulation")) {
|
||||||
brokenModulation = config.conf[name]["brokenModulation"];
|
brokenModulation = config.conf[name]["brokenModulation"];
|
||||||
}
|
}
|
||||||
if (config.conf[name].contains("oqpsk")) {
|
|
||||||
oqpsk = config.conf[name]["oqpsk"];
|
|
||||||
}
|
|
||||||
config.release();
|
config.release();
|
||||||
|
|
||||||
vfo = sigpath::vfoManager.createVFO(name, ImGui::WaterfallVFO::REF_CENTER, 0, INPUT_SAMPLE_RATE, INPUT_SAMPLE_RATE, INPUT_SAMPLE_RATE, INPUT_SAMPLE_RATE, true);
|
vfo = sigpath::vfoManager.createVFO(name, ImGui::WaterfallVFO::REF_CENTER, 0, 150000, INPUT_SAMPLE_RATE, 150000, 150000, true);
|
||||||
demod.init(vfo->output, 72000.0f, INPUT_SAMPLE_RATE, 33, 0.6f, 0.1f, 0.005f, brokenModulation, oqpsk, 1e-6, 0.01);
|
demod.init(vfo->output, 72000.0f, INPUT_SAMPLE_RATE, 33, 0.6f, 0.1f, 0.005f, brokenModulation, 1e-6, 0.01);
|
||||||
split.init(&demod.out);
|
split.init(&demod.out);
|
||||||
split.bindStream(&symSinkStream);
|
split.bindStream(&symSinkStream);
|
||||||
split.bindStream(&sinkStream);
|
split.bindStream(&sinkStream);
|
||||||
@ -102,7 +99,6 @@ public:
|
|||||||
double bw = gui::waterfall.getBandwidth();
|
double bw = gui::waterfall.getBandwidth();
|
||||||
vfo = sigpath::vfoManager.createVFO(name, ImGui::WaterfallVFO::REF_CENTER, std::clamp<double>(0, -bw / 2.0, bw / 2.0), 150000, INPUT_SAMPLE_RATE, 150000, 150000, true);
|
vfo = sigpath::vfoManager.createVFO(name, ImGui::WaterfallVFO::REF_CENTER, std::clamp<double>(0, -bw / 2.0, bw / 2.0), 150000, INPUT_SAMPLE_RATE, 150000, 150000, true);
|
||||||
|
|
||||||
demod.setBrokenModulation(brokenModulation);
|
|
||||||
demod.setInput(vfo->output);
|
demod.setInput(vfo->output);
|
||||||
|
|
||||||
demod.start();
|
demod.start();
|
||||||
@ -155,13 +151,6 @@ private:
|
|||||||
config.release(true);
|
config.release(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui::Checkbox(CONCAT("OQPSK##oqpsk", _this->name), &_this->oqpsk)) {
|
|
||||||
_this->demod.setOQPSK(_this->oqpsk);
|
|
||||||
config.acquire();
|
|
||||||
config.conf[_this->name]["oqpsk"] = _this->oqpsk;
|
|
||||||
config.release(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_this->folderSelect.pathIsValid() && _this->enabled) { style::beginDisabled(); }
|
if (!_this->folderSelect.pathIsValid() && _this->enabled) { style::beginDisabled(); }
|
||||||
|
|
||||||
if (_this->recording) {
|
if (_this->recording) {
|
||||||
@ -256,7 +245,7 @@ private:
|
|||||||
uint64_t dataWritten = 0;
|
uint64_t dataWritten = 0;
|
||||||
std::ofstream recFile;
|
std::ofstream recFile;
|
||||||
bool brokenModulation = false;
|
bool brokenModulation = false;
|
||||||
bool oqpsk = false;
|
|
||||||
int8_t* writeBuffer;
|
int8_t* writeBuffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -11,8 +11,8 @@ namespace dsp::demod {
|
|||||||
public:
|
public:
|
||||||
Meteor() {}
|
Meteor() {}
|
||||||
|
|
||||||
Meteor(stream<complex_t>* in, double symbolrate, double samplerate, int rrcTapCount, double rrcBeta, double agcRate, double costasBandwidth, bool brokenModulation, bool oqpsk, double omegaGain, double muGain, double omegaRelLimit = 0.01) {
|
Meteor(stream<complex_t>* in, double symbolrate, double samplerate, int rrcTapCount, double rrcBeta, double agcRate, double costasBandwidth, bool brokenModulation, double omegaGain, double muGain, double omegaRelLimit = 0.01) {
|
||||||
init(in, symbolrate, samplerate, rrcTapCount, rrcBeta, agcRate, costasBandwidth, brokenModulation, oqpsk, omegaGain, muGain);
|
init(in, symbolrate, samplerate, rrcTapCount, rrcBeta, agcRate, costasBandwidth, brokenModulation, omegaGain, muGain);
|
||||||
}
|
}
|
||||||
|
|
||||||
~Meteor() {
|
~Meteor() {
|
||||||
@ -21,12 +21,11 @@ namespace dsp::demod {
|
|||||||
taps::free(rrcTaps);
|
taps::free(rrcTaps);
|
||||||
}
|
}
|
||||||
|
|
||||||
void init(stream<complex_t>* in, double symbolrate, double samplerate, int rrcTapCount, double rrcBeta, double agcRate, double costasBandwidth, bool brokenModulation, bool oqpsk, double omegaGain, double muGain, double omegaRelLimit = 0.01) {
|
void init(stream<complex_t>* in, double symbolrate, double samplerate, int rrcTapCount, double rrcBeta, double agcRate, double costasBandwidth, bool brokenModulation, double omegaGain, double muGain, double omegaRelLimit = 0.01) {
|
||||||
_symbolrate = symbolrate;
|
_symbolrate = symbolrate;
|
||||||
_samplerate = samplerate;
|
_samplerate = samplerate;
|
||||||
_rrcTapCount = rrcTapCount;
|
_rrcTapCount = rrcTapCount;
|
||||||
_rrcBeta = rrcBeta;
|
_rrcBeta = rrcBeta;
|
||||||
_oqpsk = oqpsk;
|
|
||||||
|
|
||||||
rrcTaps = taps::rootRaisedCosine<float>(_rrcTapCount, _rrcBeta, _symbolrate, _samplerate);
|
rrcTaps = taps::rootRaisedCosine<float>(_rrcTapCount, _rrcBeta, _symbolrate, _samplerate);
|
||||||
rrc.init(NULL, rrcTaps);
|
rrc.init(NULL, rrcTaps);
|
||||||
@ -130,12 +129,6 @@ namespace dsp::demod {
|
|||||||
costas.setBrokenModulation(enabled);
|
costas.setBrokenModulation(enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setOQPSK(bool enabled) {
|
|
||||||
assert(base_type::_block_init);
|
|
||||||
std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
|
|
||||||
_oqpsk = enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
void reset() {
|
void reset() {
|
||||||
assert(base_type::_block_init);
|
assert(base_type::_block_init);
|
||||||
std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
|
std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
|
||||||
@ -151,18 +144,6 @@ namespace dsp::demod {
|
|||||||
rrc.process(count, in, out);
|
rrc.process(count, in, out);
|
||||||
agc.process(count, out, out);
|
agc.process(count, out, out);
|
||||||
costas.process(count, out, out);
|
costas.process(count, out, out);
|
||||||
|
|
||||||
if (_oqpsk) {
|
|
||||||
// Single sample delay + deinterleave
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
float tmp = out[i].im;
|
|
||||||
out[i].im = lastI;
|
|
||||||
lastI = tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Additional 1/24th sample delay
|
|
||||||
}
|
|
||||||
|
|
||||||
return recov.process(count, out, out);
|
return recov.process(count, out, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,8 +166,6 @@ namespace dsp::demod {
|
|||||||
double _samplerate;
|
double _samplerate;
|
||||||
int _rrcTapCount;
|
int _rrcTapCount;
|
||||||
double _rrcBeta;
|
double _rrcBeta;
|
||||||
float lastI = 0.0f;
|
|
||||||
bool _oqpsk = false;
|
|
||||||
|
|
||||||
tap<float> rrcTaps;
|
tap<float> rrcTaps;
|
||||||
filter::FIR<complex_t, float> rrc;
|
filter::FIR<complex_t, float> rrc;
|
||||||
|
@ -45,6 +45,7 @@ namespace demod {
|
|||||||
virtual int getDefaultDeemphasisMode() = 0;
|
virtual int getDefaultDeemphasisMode() = 0;
|
||||||
virtual bool getFMIFNRAllowed() = 0;
|
virtual bool getFMIFNRAllowed() = 0;
|
||||||
virtual bool getNBAllowed() = 0;
|
virtual bool getNBAllowed() = 0;
|
||||||
|
virtual bool getAFNRAllowed() = 0;
|
||||||
virtual dsp::stream<dsp::stereo_t>* getOutput() = 0;
|
virtual dsp::stream<dsp::stereo_t>* getOutput() = 0;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -86,6 +86,7 @@ namespace demod {
|
|||||||
int getDefaultDeemphasisMode() { return DEEMP_MODE_NONE; }
|
int getDefaultDeemphasisMode() { return DEEMP_MODE_NONE; }
|
||||||
bool getFMIFNRAllowed() { return false; }
|
bool getFMIFNRAllowed() { return false; }
|
||||||
bool getNBAllowed() { return false; }
|
bool getNBAllowed() { return false; }
|
||||||
|
bool getAFNRAllowed() { return false; }
|
||||||
dsp::stream<dsp::stereo_t>* getOutput() { return &demod.out; }
|
dsp::stream<dsp::stereo_t>* getOutput() { return &demod.out; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -92,6 +92,7 @@ namespace demod {
|
|||||||
int getDefaultDeemphasisMode() { return DEEMP_MODE_NONE; }
|
int getDefaultDeemphasisMode() { return DEEMP_MODE_NONE; }
|
||||||
bool getFMIFNRAllowed() { return false; }
|
bool getFMIFNRAllowed() { return false; }
|
||||||
bool getNBAllowed() { return false; }
|
bool getNBAllowed() { return false; }
|
||||||
|
bool getAFNRAllowed() { return false; }
|
||||||
dsp::stream<dsp::stereo_t>* getOutput() { return &demod.out; }
|
dsp::stream<dsp::stereo_t>* getOutput() { return &demod.out; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -79,6 +79,7 @@ namespace demod {
|
|||||||
int getDefaultDeemphasisMode() { return DEEMP_MODE_NONE; }
|
int getDefaultDeemphasisMode() { return DEEMP_MODE_NONE; }
|
||||||
bool getFMIFNRAllowed() { return false; }
|
bool getFMIFNRAllowed() { return false; }
|
||||||
bool getNBAllowed() { return true; }
|
bool getNBAllowed() { return true; }
|
||||||
|
bool getAFNRAllowed() { return false; }
|
||||||
dsp::stream<dsp::stereo_t>* getOutput() { return &demod.out; }
|
dsp::stream<dsp::stereo_t>* getOutput() { return &demod.out; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -79,6 +79,7 @@ namespace demod {
|
|||||||
int getDefaultDeemphasisMode() { return DEEMP_MODE_NONE; }
|
int getDefaultDeemphasisMode() { return DEEMP_MODE_NONE; }
|
||||||
bool getFMIFNRAllowed() { return false; }
|
bool getFMIFNRAllowed() { return false; }
|
||||||
bool getNBAllowed() { return true; }
|
bool getNBAllowed() { return true; }
|
||||||
|
bool getAFNRAllowed() { return false; }
|
||||||
dsp::stream<dsp::stereo_t>* getOutput() { return &demod.out; }
|
dsp::stream<dsp::stereo_t>* getOutput() { return &demod.out; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -75,6 +75,7 @@ namespace demod {
|
|||||||
int getDefaultDeemphasisMode() { return DEEMP_MODE_NONE; }
|
int getDefaultDeemphasisMode() { return DEEMP_MODE_NONE; }
|
||||||
bool getFMIFNRAllowed() { return true; }
|
bool getFMIFNRAllowed() { return true; }
|
||||||
bool getNBAllowed() { return false; }
|
bool getNBAllowed() { return false; }
|
||||||
|
bool getAFNRAllowed() { return false; }
|
||||||
dsp::stream<dsp::stereo_t>* getOutput() { return &demod.out; }
|
dsp::stream<dsp::stereo_t>* getOutput() { return &demod.out; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -59,6 +59,7 @@ namespace demod {
|
|||||||
int getDefaultDeemphasisMode() { return DEEMP_MODE_NONE; }
|
int getDefaultDeemphasisMode() { return DEEMP_MODE_NONE; }
|
||||||
bool getFMIFNRAllowed() { return false; }
|
bool getFMIFNRAllowed() { return false; }
|
||||||
bool getNBAllowed() { return true; }
|
bool getNBAllowed() { return true; }
|
||||||
|
bool getAFNRAllowed() { return false; }
|
||||||
dsp::stream<dsp::stereo_t>* getOutput() { return &c2s.out; }
|
dsp::stream<dsp::stereo_t>* getOutput() { return &c2s.out; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -80,6 +80,7 @@ namespace demod {
|
|||||||
int getDefaultDeemphasisMode() { return DEEMP_MODE_NONE; }
|
int getDefaultDeemphasisMode() { return DEEMP_MODE_NONE; }
|
||||||
bool getFMIFNRAllowed() { return false; }
|
bool getFMIFNRAllowed() { return false; }
|
||||||
bool getNBAllowed() { return true; }
|
bool getNBAllowed() { return true; }
|
||||||
|
bool getAFNRAllowed() { return true; }
|
||||||
dsp::stream<dsp::stereo_t>* getOutput() { return &demod.out; }
|
dsp::stream<dsp::stereo_t>* getOutput() { return &demod.out; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -130,6 +130,7 @@ namespace demod {
|
|||||||
int getDefaultDeemphasisMode() { return DEEMP_MODE_50US; }
|
int getDefaultDeemphasisMode() { return DEEMP_MODE_50US; }
|
||||||
bool getFMIFNRAllowed() { return true; }
|
bool getFMIFNRAllowed() { return true; }
|
||||||
bool getNBAllowed() { return false; }
|
bool getNBAllowed() { return false; }
|
||||||
|
bool getAFNRAllowed() { return false; }
|
||||||
dsp::stream<dsp::stereo_t>* getOutput() { return &demod.out; }
|
dsp::stream<dsp::stereo_t>* getOutput() { return &demod.out; }
|
||||||
|
|
||||||
// ============= DEDICATED FUNCTIONS =============
|
// ============= DEDICATED FUNCTIONS =============
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include <dsp/noise_reduction/noise_blanker.h>
|
#include <dsp/noise_reduction/noise_blanker.h>
|
||||||
#include <dsp/noise_reduction/fm_if.h>
|
#include <dsp/noise_reduction/fm_if.h>
|
||||||
#include <dsp/noise_reduction/squelch.h>
|
#include <dsp/noise_reduction/squelch.h>
|
||||||
|
#include <dsp/noise_reduction/audio.h>
|
||||||
#include <dsp/multirate/rational_resampler.h>
|
#include <dsp/multirate/rational_resampler.h>
|
||||||
#include <dsp/filter/deephasis.h>
|
#include <dsp/filter/deephasis.h>
|
||||||
#include <core.h>
|
#include <core.h>
|
||||||
@ -83,9 +84,11 @@ public:
|
|||||||
|
|
||||||
resamp.init(NULL, 250000.0, 48000.0);
|
resamp.init(NULL, 250000.0, 48000.0);
|
||||||
deemp.init(NULL, 50e-6, 48000.0);
|
deemp.init(NULL, 50e-6, 48000.0);
|
||||||
|
afNR.init(NULL, 1024);
|
||||||
|
|
||||||
afChain.addBlock(&resamp, true);
|
afChain.addBlock(&resamp, true);
|
||||||
afChain.addBlock(&deemp, false);
|
afChain.addBlock(&deemp, false);
|
||||||
|
afChain.addBlock(&afNR, false);
|
||||||
|
|
||||||
// Initialize the sink
|
// Initialize the sink
|
||||||
srChangeHandler.ctx = this;
|
srChangeHandler.ctx = this;
|
||||||
@ -247,6 +250,12 @@ private:
|
|||||||
if (!_this->nbEnabled && _this->enabled) { style::endDisabled(); }
|
if (!_this->nbEnabled && _this->enabled) { style::endDisabled(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Noise reduction
|
||||||
|
if (_this->afNRAllowed) {
|
||||||
|
if (ImGui::Checkbox(("Audio Noise Reduction##_radio_afnr_ena_" + _this->name).c_str(), &_this->afNREnabled)) {
|
||||||
|
_this->setAFNREnabled(_this->afNREnabled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Squelch
|
// Squelch
|
||||||
if (ImGui::Checkbox(("Squelch##_radio_sqelch_ena_" + _this->name).c_str(), &_this->squelchEnabled)) {
|
if (ImGui::Checkbox(("Squelch##_radio_sqelch_ena_" + _this->name).c_str(), &_this->squelchEnabled)) {
|
||||||
@ -370,6 +379,8 @@ private:
|
|||||||
fmIFPresetId = ifnrPresets.valueId(IFNR_PRESET_VOICE);
|
fmIFPresetId = ifnrPresets.valueId(IFNR_PRESET_VOICE);
|
||||||
nbAllowed = selectedDemod->getNBAllowed();
|
nbAllowed = selectedDemod->getNBAllowed();
|
||||||
nbEnabled = false;
|
nbEnabled = false;
|
||||||
|
afNRAllowed = selectedDemod->getAFNRAllowed();
|
||||||
|
afNREnabled = false;
|
||||||
nbLevel = 0.0f;
|
nbLevel = 0.0f;
|
||||||
double ifSamplerate = selectedDemod->getIFSampleRate();
|
double ifSamplerate = selectedDemod->getIFSampleRate();
|
||||||
config.acquire();
|
config.acquire();
|
||||||
@ -411,6 +422,9 @@ private:
|
|||||||
if (config.conf[name][selectedDemod->getName()].contains("noiseBlankerLevel")) {
|
if (config.conf[name][selectedDemod->getName()].contains("noiseBlankerLevel")) {
|
||||||
nbLevel = config.conf[name][selectedDemod->getName()]["noiseBlankerLevel"];
|
nbLevel = config.conf[name][selectedDemod->getName()]["noiseBlankerLevel"];
|
||||||
}
|
}
|
||||||
|
if (config.conf[name][selectedDemod->getName()].contains("audioNoiseReductionEnabled")) {
|
||||||
|
nbEnabled = config.conf[name][selectedDemod->getName()]["audioNoiseReductionEnabled"];
|
||||||
|
}
|
||||||
config.release();
|
config.release();
|
||||||
|
|
||||||
// Configure VFO
|
// Configure VFO
|
||||||
@ -446,7 +460,10 @@ private:
|
|||||||
afChain.enableBlock(&resamp, [=](dsp::stream<dsp::stereo_t>* out){ stream.setInput(out); });
|
afChain.enableBlock(&resamp, [=](dsp::stream<dsp::stereo_t>* out){ stream.setInput(out); });
|
||||||
|
|
||||||
// Configure deemphasis
|
// Configure deemphasis
|
||||||
setDeemphasisMode(deempModes[deempId]);
|
setDeemphasisMode(deempAllowed ? deempModes[deempId] : DEEMP_MODE_NONE);
|
||||||
|
|
||||||
|
// Configure AF NR
|
||||||
|
setAFNREnabled(afNRAllowed && afNREnabled);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Disable everything if post processing is disabled
|
// Disable everything if post processing is disabled
|
||||||
@ -508,6 +525,17 @@ private:
|
|||||||
config.release(true);
|
config.release(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setAFNREnabled(bool enable) {
|
||||||
|
afNREnabled = enable;
|
||||||
|
if (!postProcEnabled || !selectedDemod) { return; }
|
||||||
|
afChain.setBlockEnabled(&afNR, afNREnabled, [=](dsp::stream<dsp::stereo_t>* out){ stream.setInput(out); });
|
||||||
|
|
||||||
|
// Save config
|
||||||
|
config.acquire();
|
||||||
|
config.conf[name][selectedDemod->getName()]["audioNoiseReductionEnabled"] = nbEnabled;
|
||||||
|
config.release(true);
|
||||||
|
}
|
||||||
|
|
||||||
void setNBEnabled(bool enable) {
|
void setNBEnabled(bool enable) {
|
||||||
nbEnabled = enable;
|
nbEnabled = enable;
|
||||||
if (!selectedDemod) { return; }
|
if (!selectedDemod) { return; }
|
||||||
@ -660,6 +688,7 @@ private:
|
|||||||
dsp::chain<dsp::stereo_t> afChain;
|
dsp::chain<dsp::stereo_t> afChain;
|
||||||
dsp::multirate::RationalResampler<dsp::stereo_t> resamp;
|
dsp::multirate::RationalResampler<dsp::stereo_t> resamp;
|
||||||
dsp::filter::Deemphasis<dsp::stereo_t> deemp;
|
dsp::filter::Deemphasis<dsp::stereo_t> deemp;
|
||||||
|
dsp::noise_reduction::Audio afNR;
|
||||||
|
|
||||||
SinkManager::Stream stream;
|
SinkManager::Stream stream;
|
||||||
|
|
||||||
@ -683,6 +712,9 @@ private:
|
|||||||
int deempId = 0;
|
int deempId = 0;
|
||||||
bool deempAllowed;
|
bool deempAllowed;
|
||||||
|
|
||||||
|
bool afNREnabled = false;
|
||||||
|
bool afNRAllowed;
|
||||||
|
|
||||||
bool FMIFNRAllowed;
|
bool FMIFNRAllowed;
|
||||||
bool FMIFNREnabled = false;
|
bool FMIFNREnabled = false;
|
||||||
int fmIFPresetId;
|
int fmIFPresetId;
|
||||||
|
@ -1,4 +0,0 @@
|
|||||||
FROM debian:bookworm
|
|
||||||
ENV DEBIAN_FRONTEND=noninteractive
|
|
||||||
COPY do_build.sh /root
|
|
||||||
RUN chmod +x /root/do_build.sh
|
|
@ -1,35 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
set -e
|
|
||||||
cd /root
|
|
||||||
|
|
||||||
# Install dependencies and tools
|
|
||||||
apt update
|
|
||||||
apt install -y build-essential cmake git libfftw3-dev libglfw3-dev libvolk2-dev libzstd-dev libsoapysdr-dev libairspyhf-dev libairspy-dev \
|
|
||||||
libiio-dev libad9361-dev librtaudio-dev libhackrf-dev librtlsdr-dev libbladerf-dev liblimesuite-dev p7zip-full wget portaudio19-dev \
|
|
||||||
libcodec2-dev autoconf libtool xxd
|
|
||||||
|
|
||||||
# Install SDRPlay libraries
|
|
||||||
wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.07.1.run
|
|
||||||
7z x ./SDRplay_RSP_API-Linux-3.07.1.run
|
|
||||||
7z x ./SDRplay_RSP_API-Linux-3.07.1
|
|
||||||
cp x86_64/libsdrplay_api.so.3.07 /usr/lib/libsdrplay_api.so
|
|
||||||
cp inc/* /usr/include/
|
|
||||||
|
|
||||||
# Install libperseus
|
|
||||||
git clone https://github.com/Microtelecom/libperseus-sdr
|
|
||||||
cd libperseus-sdr
|
|
||||||
autoreconf -i
|
|
||||||
./configure
|
|
||||||
make
|
|
||||||
make install
|
|
||||||
ldconfig
|
|
||||||
cd ..
|
|
||||||
|
|
||||||
cd SDRPlusPlus
|
|
||||||
mkdir build
|
|
||||||
cd build
|
|
||||||
cmake .. -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON -DOPT_BUILD_PERSEUS_SOURCE=ON
|
|
||||||
make VERBOSE=1 -j2
|
|
||||||
|
|
||||||
cd ..
|
|
||||||
sh make_debian_package.sh ./build 'libfftw3-dev, libglfw3-dev, libvolk2-dev, librtaudio-dev, libzstd-dev'
|
|
@ -6,7 +6,7 @@ cd /root
|
|||||||
apt update
|
apt update
|
||||||
apt install -y build-essential cmake git libfftw3-dev libglfw3-dev libvolk2-dev libzstd-dev libsoapysdr-dev libairspyhf-dev libairspy-dev \
|
apt install -y build-essential cmake git libfftw3-dev libglfw3-dev libvolk2-dev libzstd-dev libsoapysdr-dev libairspyhf-dev libairspy-dev \
|
||||||
libiio-dev libad9361-dev librtaudio-dev libhackrf-dev librtlsdr-dev libbladerf-dev liblimesuite-dev p7zip-full wget portaudio19-dev \
|
libiio-dev libad9361-dev librtaudio-dev libhackrf-dev librtlsdr-dev libbladerf-dev liblimesuite-dev p7zip-full wget portaudio19-dev \
|
||||||
libcodec2-dev autoconf libtool xxd
|
libcodec2-dev
|
||||||
|
|
||||||
# Install SDRPlay libraries
|
# Install SDRPlay libraries
|
||||||
wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.07.1.run
|
wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.07.1.run
|
||||||
@ -15,20 +15,10 @@ wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.07.1.run
|
|||||||
cp x86_64/libsdrplay_api.so.3.07 /usr/lib/libsdrplay_api.so
|
cp x86_64/libsdrplay_api.so.3.07 /usr/lib/libsdrplay_api.so
|
||||||
cp inc/* /usr/include/
|
cp inc/* /usr/include/
|
||||||
|
|
||||||
# Install libperseus
|
|
||||||
git clone https://github.com/Microtelecom/libperseus-sdr
|
|
||||||
cd libperseus-sdr
|
|
||||||
autoreconf -i
|
|
||||||
./configure
|
|
||||||
make
|
|
||||||
make install
|
|
||||||
ldconfig
|
|
||||||
cd ..
|
|
||||||
|
|
||||||
cd SDRPlusPlus
|
cd SDRPlusPlus
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
cmake .. -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON -DOPT_BUILD_PERSEUS_SOURCE=ON
|
cmake .. -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON
|
||||||
make VERBOSE=1 -j2
|
make VERBOSE=1 -j2
|
||||||
|
|
||||||
cd ..
|
cd ..
|
||||||
|
@ -6,7 +6,7 @@ cd /root
|
|||||||
apt update
|
apt update
|
||||||
apt install -y build-essential cmake git libfftw3-dev libglfw3-dev libvolk1-dev libzstd-dev libsoapysdr-dev libairspyhf-dev libairspy-dev \
|
apt install -y build-essential cmake git libfftw3-dev libglfw3-dev libvolk1-dev libzstd-dev libsoapysdr-dev libairspyhf-dev libairspy-dev \
|
||||||
libiio-dev libad9361-dev librtaudio-dev libhackrf-dev librtlsdr-dev libbladerf-dev liblimesuite-dev p7zip-full wget portaudio19-dev \
|
libiio-dev libad9361-dev librtaudio-dev libhackrf-dev librtlsdr-dev libbladerf-dev liblimesuite-dev p7zip-full wget portaudio19-dev \
|
||||||
libcodec2-dev autoconf libtool xxd
|
libcodec2-dev
|
||||||
|
|
||||||
# Install SDRPlay libraries
|
# Install SDRPlay libraries
|
||||||
wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.07.1.run
|
wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.07.1.run
|
||||||
@ -15,20 +15,10 @@ wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.07.1.run
|
|||||||
cp x86_64/libsdrplay_api.so.3.07 /usr/lib/libsdrplay_api.so
|
cp x86_64/libsdrplay_api.so.3.07 /usr/lib/libsdrplay_api.so
|
||||||
cp inc/* /usr/include/
|
cp inc/* /usr/include/
|
||||||
|
|
||||||
# Install libperseus
|
|
||||||
git clone https://github.com/Microtelecom/libperseus-sdr
|
|
||||||
cd libperseus-sdr
|
|
||||||
autoreconf -i
|
|
||||||
./configure
|
|
||||||
make
|
|
||||||
make install
|
|
||||||
ldconfig
|
|
||||||
cd ..
|
|
||||||
|
|
||||||
cd SDRPlusPlus
|
cd SDRPlusPlus
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
cmake .. -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_BLADERF_SOURCE=OFF -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON -DOPT_BUILD_PERSEUS_SOURCE=ON
|
cmake .. -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_BLADERF_SOURCE=OFF -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON
|
||||||
make VERBOSE=1 -j2
|
make VERBOSE=1 -j2
|
||||||
|
|
||||||
cd ..
|
cd ..
|
||||||
|
@ -4,9 +4,9 @@ cd /root
|
|||||||
|
|
||||||
# Install dependencies and tools
|
# Install dependencies and tools
|
||||||
apt update
|
apt update
|
||||||
apt install -y build-essential cmake git libfftw3-dev libglfw3-dev libvolk-dev libzstd-dev libsoapysdr-dev libairspyhf-dev libairspy-dev \
|
apt install -y build-essential cmake git libfftw3-dev libglfw3-dev libvolk2-dev libzstd-dev libsoapysdr-dev libairspyhf-dev libairspy-dev \
|
||||||
libiio-dev libad9361-dev librtaudio-dev libhackrf-dev librtlsdr-dev libbladerf-dev liblimesuite-dev p7zip-full wget portaudio19-dev \
|
libiio-dev libad9361-dev librtaudio-dev libhackrf-dev librtlsdr-dev libbladerf-dev liblimesuite-dev p7zip-full wget portaudio19-dev \
|
||||||
libcodec2-dev autoconf libtool xxd
|
libcodec2-dev
|
||||||
|
|
||||||
# Install SDRPlay libraries
|
# Install SDRPlay libraries
|
||||||
wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.07.1.run
|
wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.07.1.run
|
||||||
@ -15,21 +15,11 @@ wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.07.1.run
|
|||||||
cp x86_64/libsdrplay_api.so.3.07 /usr/lib/libsdrplay_api.so
|
cp x86_64/libsdrplay_api.so.3.07 /usr/lib/libsdrplay_api.so
|
||||||
cp inc/* /usr/include/
|
cp inc/* /usr/include/
|
||||||
|
|
||||||
# Install libperseus
|
|
||||||
git clone https://github.com/Microtelecom/libperseus-sdr
|
|
||||||
cd libperseus-sdr
|
|
||||||
autoreconf -i
|
|
||||||
./configure
|
|
||||||
make
|
|
||||||
make install
|
|
||||||
ldconfig
|
|
||||||
cd ..
|
|
||||||
|
|
||||||
cd SDRPlusPlus
|
cd SDRPlusPlus
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
cmake .. -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON -DOPT_BUILD_PERSEUS_SOURCE=ON
|
cmake .. -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON
|
||||||
make VERBOSE=1 -j2
|
make VERBOSE=1 -j2
|
||||||
|
|
||||||
cd ..
|
cd ..
|
||||||
sh make_debian_package.sh ./build 'libfftw3-dev, libglfw3-dev, libvolk-dev, librtaudio-dev, libzstd-dev'
|
sh make_debian_package.sh ./build 'libfftw3-dev, libglfw3-dev, libvolk2-dev, librtaudio-dev, libzstd-dev'
|
@ -12,7 +12,7 @@ apt update
|
|||||||
# Install dependencies and tools
|
# Install dependencies and tools
|
||||||
apt install -y build-essential cmake git libfftw3-dev libglfw3-dev libvolk1-dev libzstd-dev libsoapysdr-dev libairspy-dev \
|
apt install -y build-essential cmake git libfftw3-dev libglfw3-dev libvolk1-dev libzstd-dev libsoapysdr-dev libairspy-dev \
|
||||||
libiio-dev libad9361-dev librtaudio-dev libhackrf-dev librtlsdr-dev libbladerf-dev liblimesuite-dev p7zip-full wget portaudio19-dev \
|
libiio-dev libad9361-dev librtaudio-dev libhackrf-dev librtlsdr-dev libbladerf-dev liblimesuite-dev p7zip-full wget portaudio19-dev \
|
||||||
libcodec2-dev libudev-dev autoconf libtool xxd
|
libcodec2-dev libudev-dev
|
||||||
|
|
||||||
# Install SDRPlay libraries
|
# Install SDRPlay libraries
|
||||||
wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.07.1.run
|
wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.07.1.run
|
||||||
@ -41,16 +41,6 @@ make install
|
|||||||
ldconfig
|
ldconfig
|
||||||
cd ../../
|
cd ../../
|
||||||
|
|
||||||
# Install libperseus
|
|
||||||
git clone https://github.com/Microtelecom/libperseus-sdr
|
|
||||||
cd libperseus-sdr
|
|
||||||
autoreconf -i
|
|
||||||
./configure
|
|
||||||
make
|
|
||||||
make install
|
|
||||||
ldconfig
|
|
||||||
cd ..
|
|
||||||
|
|
||||||
# Fix missing .pc file for codec2
|
# Fix missing .pc file for codec2
|
||||||
echo 'prefix=/usr/' >> /usr/share/pkgconfig/codec2.pc
|
echo 'prefix=/usr/' >> /usr/share/pkgconfig/codec2.pc
|
||||||
echo 'libdir=/usr/include/x86_64-linux-gnu/' >> /usr/share/pkgconfig/codec2.pc
|
echo 'libdir=/usr/include/x86_64-linux-gnu/' >> /usr/share/pkgconfig/codec2.pc
|
||||||
@ -66,7 +56,7 @@ echo 'Cflags: -I/usr/include/codec2' >> /usr/share/pkgconfig/codec2.pc
|
|||||||
cd SDRPlusPlus
|
cd SDRPlusPlus
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
cmake .. -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_BLADERF_SOURCE=OFF -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_OVERRIDE_STD_FILESYSTEM=ON -DOPT_BUILD_M17_DECODER=ON -DOPT_BUILD_PERSEUS_SOURCE=ON
|
cmake .. -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_BLADERF_SOURCE=OFF -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_OVERRIDE_STD_FILESYSTEM=ON -DOPT_BUILD_M17_DECODER=ON
|
||||||
make VERBOSE=1 -j2
|
make VERBOSE=1 -j2
|
||||||
|
|
||||||
# Generate package
|
# Generate package
|
||||||
|
@ -6,7 +6,7 @@ cd /root
|
|||||||
apt update
|
apt update
|
||||||
apt install -y build-essential cmake git libfftw3-dev libglfw3-dev libvolk2-dev libzstd-dev libsoapysdr-dev libairspyhf-dev libairspy-dev \
|
apt install -y build-essential cmake git libfftw3-dev libglfw3-dev libvolk2-dev libzstd-dev libsoapysdr-dev libairspyhf-dev libairspy-dev \
|
||||||
libiio-dev libad9361-dev librtaudio-dev libhackrf-dev librtlsdr-dev libbladerf-dev liblimesuite-dev p7zip-full wget portaudio19-dev \
|
libiio-dev libad9361-dev librtaudio-dev libhackrf-dev librtlsdr-dev libbladerf-dev liblimesuite-dev p7zip-full wget portaudio19-dev \
|
||||||
libcodec2-dev autoconf libtool xxd
|
libcodec2-dev
|
||||||
|
|
||||||
# Install SDRPlay libraries
|
# Install SDRPlay libraries
|
||||||
wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.07.1.run
|
wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.07.1.run
|
||||||
@ -15,20 +15,10 @@ wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.07.1.run
|
|||||||
cp x86_64/libsdrplay_api.so.3.07 /usr/lib/libsdrplay_api.so
|
cp x86_64/libsdrplay_api.so.3.07 /usr/lib/libsdrplay_api.so
|
||||||
cp inc/* /usr/include/
|
cp inc/* /usr/include/
|
||||||
|
|
||||||
# Install libperseus
|
|
||||||
git clone https://github.com/Microtelecom/libperseus-sdr
|
|
||||||
cd libperseus-sdr
|
|
||||||
autoreconf -i
|
|
||||||
./configure
|
|
||||||
make
|
|
||||||
make install
|
|
||||||
ldconfig
|
|
||||||
cd ..
|
|
||||||
|
|
||||||
cd SDRPlusPlus
|
cd SDRPlusPlus
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
cmake .. -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON -DOPT_BUILD_PERSEUS_SOURCE=ON
|
cmake .. -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON
|
||||||
make VERBOSE=1 -j2
|
make VERBOSE=1 -j2
|
||||||
|
|
||||||
cd ..
|
cd ..
|
||||||
|
@ -6,7 +6,7 @@ cd /root
|
|||||||
apt update
|
apt update
|
||||||
apt install -y build-essential cmake git libfftw3-dev libglfw3-dev libvolk2-dev libzstd-dev libsoapysdr-dev libairspyhf-dev libairspy-dev \
|
apt install -y build-essential cmake git libfftw3-dev libglfw3-dev libvolk2-dev libzstd-dev libsoapysdr-dev libairspyhf-dev libairspy-dev \
|
||||||
libiio-dev libad9361-dev librtaudio-dev libhackrf-dev librtlsdr-dev libbladerf-dev liblimesuite-dev p7zip-full wget portaudio19-dev \
|
libiio-dev libad9361-dev librtaudio-dev libhackrf-dev librtlsdr-dev libbladerf-dev liblimesuite-dev p7zip-full wget portaudio19-dev \
|
||||||
libcodec2-dev autoconf libtool xxd
|
libcodec2-dev
|
||||||
|
|
||||||
# Install SDRPlay libraries
|
# Install SDRPlay libraries
|
||||||
wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.07.1.run
|
wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.07.1.run
|
||||||
@ -15,20 +15,10 @@ wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.07.1.run
|
|||||||
cp x86_64/libsdrplay_api.so.3.07 /usr/lib/libsdrplay_api.so
|
cp x86_64/libsdrplay_api.so.3.07 /usr/lib/libsdrplay_api.so
|
||||||
cp inc/* /usr/include/
|
cp inc/* /usr/include/
|
||||||
|
|
||||||
# Install libperseus
|
|
||||||
git clone https://github.com/Microtelecom/libperseus-sdr
|
|
||||||
cd libperseus-sdr
|
|
||||||
autoreconf -i
|
|
||||||
./configure
|
|
||||||
make
|
|
||||||
make install
|
|
||||||
ldconfig
|
|
||||||
cd ..
|
|
||||||
|
|
||||||
cd SDRPlusPlus
|
cd SDRPlusPlus
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
cmake .. -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON -DOPT_BUILD_PERSEUS_SOURCE=ON
|
cmake .. -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON
|
||||||
make VERBOSE=1 -j2
|
make VERBOSE=1 -j2
|
||||||
|
|
||||||
cd ..
|
cd ..
|
||||||
|
@ -81,7 +81,7 @@ bundle_find_full_path() {
|
|||||||
|
|
||||||
# Correct dep path
|
# Correct dep path
|
||||||
echo $RPATH/$RPATH_NEXT
|
echo $RPATH/$RPATH_NEXT
|
||||||
return -1
|
return
|
||||||
done
|
done
|
||||||
|
|
||||||
# Search other common paths
|
# Search other common paths
|
||||||
|
@ -38,7 +38,6 @@ bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/source_modules
|
|||||||
bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/source_modules/hackrf_source/hackrf_source.dylib
|
bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/source_modules/hackrf_source/hackrf_source.dylib
|
||||||
bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/source_modules/hermes_source/hermes_source.dylib
|
bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/source_modules/hermes_source/hermes_source.dylib
|
||||||
bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/source_modules/limesdr_source/limesdr_source.dylib
|
bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/source_modules/limesdr_source/limesdr_source.dylib
|
||||||
bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/source_modules/perseus_source/perseus_source.dylib
|
|
||||||
bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/source_modules/plutosdr_source/plutosdr_source.dylib
|
bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/source_modules/plutosdr_source/plutosdr_source.dylib
|
||||||
bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/source_modules/rfspace_source/rfspace_source.dylib
|
bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/source_modules/rfspace_source/rfspace_source.dylib
|
||||||
bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/source_modules/rtl_sdr_source/rtl_sdr_source.dylib
|
bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/source_modules/rtl_sdr_source/rtl_sdr_source.dylib
|
||||||
@ -63,7 +62,6 @@ bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/decoder_module
|
|||||||
bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/misc_modules/discord_integration/discord_integration.dylib
|
bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/misc_modules/discord_integration/discord_integration.dylib
|
||||||
bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/misc_modules/frequency_manager/frequency_manager.dylib
|
bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/misc_modules/frequency_manager/frequency_manager.dylib
|
||||||
bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/misc_modules/recorder/recorder.dylib
|
bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/misc_modules/recorder/recorder.dylib
|
||||||
bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/misc_modules/rigctl_client/rigctl_client.dylib
|
|
||||||
bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/misc_modules/rigctl_server/rigctl_server.dylib
|
bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/misc_modules/rigctl_server/rigctl_server.dylib
|
||||||
bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/misc_modules/scanner/scanner.dylib
|
bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/misc_modules/scanner/scanner.dylib
|
||||||
|
|
||||||
|
@ -32,9 +32,6 @@ cp $build_dir/source_modules/hermes_source/Release/hermes_source.dll sdrpp_windo
|
|||||||
cp $build_dir/source_modules/limesdr_source/Release/limesdr_source.dll sdrpp_windows_x64/modules/
|
cp $build_dir/source_modules/limesdr_source/Release/limesdr_source.dll sdrpp_windows_x64/modules/
|
||||||
cp 'C:/Program Files/PothosSDR/bin/LimeSuite.dll' sdrpp_windows_x64/
|
cp 'C:/Program Files/PothosSDR/bin/LimeSuite.dll' sdrpp_windows_x64/
|
||||||
|
|
||||||
cp $build_dir/source_modules/perseus_source/Release/perseus_source.dll sdrpp_windows_x64/modules/
|
|
||||||
cp 'C:/Program Files/PothosSDR/bin/perseus-sdr.dll' sdrpp_windows_x64/
|
|
||||||
|
|
||||||
cp $build_dir/source_modules/plutosdr_source/Release/plutosdr_source.dll sdrpp_windows_x64/modules/
|
cp $build_dir/source_modules/plutosdr_source/Release/plutosdr_source.dll sdrpp_windows_x64/modules/
|
||||||
cp 'C:/Program Files/PothosSDR/bin/libiio.dll' sdrpp_windows_x64/
|
cp 'C:/Program Files/PothosSDR/bin/libiio.dll' sdrpp_windows_x64/
|
||||||
cp 'C:/Program Files/PothosSDR/bin/libad9361.dll' sdrpp_windows_x64/
|
cp 'C:/Program Files/PothosSDR/bin/libad9361.dll' sdrpp_windows_x64/
|
||||||
|
@ -6,4 +6,3 @@ file(GLOB SRC "src/*.cpp")
|
|||||||
include(${SDRPP_MODULE_CMAKE})
|
include(${SDRPP_MODULE_CMAKE})
|
||||||
|
|
||||||
target_include_directories(recorder PRIVATE "src/")
|
target_include_directories(recorder PRIVATE "src/")
|
||||||
target_include_directories(recorder PRIVATE "../../decoder_modules/radio/src")
|
|
@ -21,7 +21,6 @@
|
|||||||
#include <core.h>
|
#include <core.h>
|
||||||
#include <utils/optionlist.h>
|
#include <utils/optionlist.h>
|
||||||
#include <utils/wav.h>
|
#include <utils/wav.h>
|
||||||
#include <radio_interface.h>
|
|
||||||
|
|
||||||
#define CONCAT(a, b) ((std::string(a) + b).c_str())
|
#define CONCAT(a, b) ((std::string(a) + b).c_str())
|
||||||
|
|
||||||
@ -169,7 +168,7 @@ public:
|
|||||||
|
|
||||||
// Open file
|
// Open file
|
||||||
std::string type = (recMode == RECORDER_MODE_AUDIO) ? "audio" : "baseband";
|
std::string type = (recMode == RECORDER_MODE_AUDIO) ? "audio" : "baseband";
|
||||||
std::string vfoName = (recMode == RECORDER_MODE_AUDIO) ? selectedStreamName : "";
|
std::string vfoName = (recMode == RECORDER_MODE_AUDIO) ? gui::waterfall.selectedVFO : "";
|
||||||
std::string extension = ".wav";
|
std::string extension = ".wav";
|
||||||
std::string expandedPath = expandString(folderSelect.path + "/" + genFileName(nameTemplate, type, vfoName) + extension);
|
std::string expandedPath = expandString(folderSelect.path + "/" + genFileName(nameTemplate, type, vfoName) + extension);
|
||||||
if (!writer.open(expandedPath)) {
|
if (!writer.open(expandedPath)) {
|
||||||
@ -438,17 +437,6 @@ private:
|
|||||||
if (dbLvl.r > lvl.r) { lvl.r = dbLvl.r; }
|
if (dbLvl.r > lvl.r) { lvl.r = dbLvl.r; }
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<int, const char*> radioModeToString = {
|
|
||||||
{ RADIO_IFACE_MODE_NFM, "NFM" },
|
|
||||||
{ RADIO_IFACE_MODE_WFM, "WFM" },
|
|
||||||
{ RADIO_IFACE_MODE_AM, "AM" },
|
|
||||||
{ RADIO_IFACE_MODE_DSB, "DSB" },
|
|
||||||
{ RADIO_IFACE_MODE_USB, "USB" },
|
|
||||||
{ RADIO_IFACE_MODE_CW, "CW" },
|
|
||||||
{ RADIO_IFACE_MODE_LSB, "LSB" },
|
|
||||||
{ RADIO_IFACE_MODE_RAW, "RAW" }
|
|
||||||
};
|
|
||||||
|
|
||||||
std::string genFileName(std::string templ, std::string type, std::string name) {
|
std::string genFileName(std::string templ, std::string type, std::string name) {
|
||||||
// Get data
|
// Get data
|
||||||
time_t now = time(0);
|
time_t now = time(0);
|
||||||
@ -467,7 +455,6 @@ private:
|
|||||||
char dayStr[128];
|
char dayStr[128];
|
||||||
char monStr[128];
|
char monStr[128];
|
||||||
char yearStr[128];
|
char yearStr[128];
|
||||||
const char* modeStr = "Unknown";
|
|
||||||
sprintf(freqStr, "%.0lfHz", freq);
|
sprintf(freqStr, "%.0lfHz", freq);
|
||||||
sprintf(hourStr, "%02d", ltm->tm_hour);
|
sprintf(hourStr, "%02d", ltm->tm_hour);
|
||||||
sprintf(minStr, "%02d", ltm->tm_min);
|
sprintf(minStr, "%02d", ltm->tm_min);
|
||||||
@ -475,11 +462,6 @@ private:
|
|||||||
sprintf(dayStr, "%02d", ltm->tm_mday);
|
sprintf(dayStr, "%02d", ltm->tm_mday);
|
||||||
sprintf(monStr, "%02d", ltm->tm_mon + 1);
|
sprintf(monStr, "%02d", ltm->tm_mon + 1);
|
||||||
sprintf(yearStr, "%02d", ltm->tm_year + 1900);
|
sprintf(yearStr, "%02d", ltm->tm_year + 1900);
|
||||||
if (core::modComManager.getModuleName(name) == "radio") {
|
|
||||||
int mode;
|
|
||||||
core::modComManager.callInterface(name, RADIO_IFACE_CMD_GET_MODE, NULL, &mode);
|
|
||||||
modeStr = radioModeToString[mode];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Replace in template
|
// Replace in template
|
||||||
templ = std::regex_replace(templ, std::regex("\\$t"), type);
|
templ = std::regex_replace(templ, std::regex("\\$t"), type);
|
||||||
@ -490,7 +472,6 @@ private:
|
|||||||
templ = std::regex_replace(templ, std::regex("\\$d"), dayStr);
|
templ = std::regex_replace(templ, std::regex("\\$d"), dayStr);
|
||||||
templ = std::regex_replace(templ, std::regex("\\$M"), monStr);
|
templ = std::regex_replace(templ, std::regex("\\$M"), monStr);
|
||||||
templ = std::regex_replace(templ, std::regex("\\$y"), yearStr);
|
templ = std::regex_replace(templ, std::regex("\\$y"), yearStr);
|
||||||
templ = std::regex_replace(templ, std::regex("\\$r"), modeStr);
|
|
||||||
return templ;
|
return templ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -333,17 +333,6 @@ private:
|
|||||||
_this->client->readAsync(1024, _this->dataBuf, dataHandler, _this, false);
|
_this->client->readAsync(1024, _this->dataBuf, dataHandler, _this, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<int, const char*> radioModeToString = {
|
|
||||||
{ RADIO_IFACE_MODE_NFM, "NFM" },
|
|
||||||
{ RADIO_IFACE_MODE_WFM, "WFM" },
|
|
||||||
{ RADIO_IFACE_MODE_AM, "AM" },
|
|
||||||
{ RADIO_IFACE_MODE_DSB, "DSB" },
|
|
||||||
{ RADIO_IFACE_MODE_USB, "USB" },
|
|
||||||
{ RADIO_IFACE_MODE_CW, "CW" },
|
|
||||||
{ RADIO_IFACE_MODE_LSB, "LSB" },
|
|
||||||
{ RADIO_IFACE_MODE_RAW, "RAW" }
|
|
||||||
};
|
|
||||||
|
|
||||||
void commandHandler(std::string cmd) {
|
void commandHandler(std::string cmd) {
|
||||||
std::string corr = "";
|
std::string corr = "";
|
||||||
std::vector<std::string> parts;
|
std::vector<std::string> parts;
|
||||||
@ -453,18 +442,38 @@ private:
|
|||||||
pos++;
|
pos++;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string& newModeStr = parts[1];
|
|
||||||
float newBandwidth = std::atoi(parts[2].c_str());
|
float newBandwidth = std::atoi(parts[2].c_str());
|
||||||
|
|
||||||
auto it = std::find_if(radioModeToString.begin(), radioModeToString.end(), [&newModeStr](const auto& e) {
|
int newMode;
|
||||||
return e.second == newModeStr;
|
if (parts[1] == "FM") {
|
||||||
});
|
newMode = RADIO_IFACE_MODE_NFM;
|
||||||
if (it == radioModeToString.end()) {
|
}
|
||||||
|
else if (parts[1] == "WFM") {
|
||||||
|
newMode = RADIO_IFACE_MODE_WFM;
|
||||||
|
}
|
||||||
|
else if (parts[1] == "AM") {
|
||||||
|
newMode = RADIO_IFACE_MODE_AM;
|
||||||
|
}
|
||||||
|
else if (parts[1] == "DSB") {
|
||||||
|
newMode = RADIO_IFACE_MODE_DSB;
|
||||||
|
}
|
||||||
|
else if (parts[1] == "USB") {
|
||||||
|
newMode = RADIO_IFACE_MODE_USB;
|
||||||
|
}
|
||||||
|
else if (parts[1] == "CW") {
|
||||||
|
newMode = RADIO_IFACE_MODE_CW;
|
||||||
|
}
|
||||||
|
else if (parts[1] == "LSB") {
|
||||||
|
newMode = RADIO_IFACE_MODE_LSB;
|
||||||
|
}
|
||||||
|
else if (parts[1] == "RAW") {
|
||||||
|
newMode = RADIO_IFACE_MODE_RAW;
|
||||||
|
}
|
||||||
|
else {
|
||||||
resp = "RPRT 1\n";
|
resp = "RPRT 1\n";
|
||||||
client->write(resp.size(), (uint8_t*)resp.c_str());
|
client->write(resp.size(), (uint8_t*)resp.c_str());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int newMode = it->first;
|
|
||||||
|
|
||||||
// If tuning is enabled, set the mode and optionally the bandwidth
|
// If tuning is enabled, set the mode and optionally the bandwidth
|
||||||
if (!selectedVfo.empty() && core::modComManager.getModuleName(selectedVfo) == "radio" && tuningEnabled) {
|
if (!selectedVfo.empty() && core::modComManager.getModuleName(selectedVfo) == "radio" && tuningEnabled) {
|
||||||
@ -483,9 +492,31 @@ private:
|
|||||||
if (!selectedVfo.empty() && core::modComManager.getModuleName(selectedVfo) == "radio") {
|
if (!selectedVfo.empty() && core::modComManager.getModuleName(selectedVfo) == "radio") {
|
||||||
int mode;
|
int mode;
|
||||||
core::modComManager.callInterface(selectedVfo, RADIO_IFACE_CMD_GET_MODE, NULL, &mode);
|
core::modComManager.callInterface(selectedVfo, RADIO_IFACE_CMD_GET_MODE, NULL, &mode);
|
||||||
resp = std::string(radioModeToString[mode]) + "\n";
|
|
||||||
|
if (mode == RADIO_IFACE_MODE_NFM) {
|
||||||
|
resp = "FM\n";
|
||||||
}
|
}
|
||||||
else if (!selectedVfo.empty()) {
|
else if (mode == RADIO_IFACE_MODE_WFM) {
|
||||||
|
resp = "WFM\n";
|
||||||
|
}
|
||||||
|
else if (mode == RADIO_IFACE_MODE_AM) {
|
||||||
|
resp = "AM\n";
|
||||||
|
}
|
||||||
|
else if (mode == RADIO_IFACE_MODE_DSB) {
|
||||||
|
resp = "DSB\n";
|
||||||
|
}
|
||||||
|
else if (mode == RADIO_IFACE_MODE_USB) {
|
||||||
|
resp = "USB\n";
|
||||||
|
}
|
||||||
|
else if (mode == RADIO_IFACE_MODE_CW) {
|
||||||
|
resp = "CW\n";
|
||||||
|
}
|
||||||
|
else if (mode == RADIO_IFACE_MODE_LSB) {
|
||||||
|
resp = "LSB\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!selectedVfo.empty()) {
|
||||||
resp += std::to_string((int)sigpath::vfoManager.getBandwidth(selectedVfo)) + "\n";
|
resp += std::to_string((int)sigpath::vfoManager.getBandwidth(selectedVfo)) + "\n";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -659,11 +690,6 @@ private:
|
|||||||
"0\n" /* RIG_PARM_NONE */;
|
"0\n" /* RIG_PARM_NONE */;
|
||||||
client->write(resp.size(), (uint8_t*)resp.c_str());
|
client->write(resp.size(), (uint8_t*)resp.c_str());
|
||||||
}
|
}
|
||||||
// This get_powerstat stuff is a wordaround for WSJT-X 2.7.0
|
|
||||||
else if (parts[0] == "\\get_powerstat") {
|
|
||||||
resp = "1\n";
|
|
||||||
client->write(resp.size(), (uint8_t*)resp.c_str());
|
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
// If command is not recognized, return error
|
// If command is not recognized, return error
|
||||||
flog::error("Rigctl client sent invalid command: '{0}'", cmd);
|
flog::error("Rigctl client sent invalid command: '{0}'", cmd);
|
||||||
|
29
readme.md
29
readme.md
@ -44,7 +44,7 @@ Download the latest release from [the Releases page](https://github.com/Alexandr
|
|||||||
Then, run:
|
Then, run:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
sudo apt install libfftw3-dev libglfw3-dev libvolk2-dev libzstd-dev libsoapysdr-dev libairspyhf-dev libiio-dev libad9361-dev librtaudio-dev libhackrf-dev
|
sudo apt install libfftw3-dev libglfw3-dev libvolk2-dev libsoapysdr-dev libairspyhf-dev libiio-dev libad9361-dev librtaudio-dev libhackrf-dev
|
||||||
sudo dpkg -i sdrpp_debian_amd64.deb
|
sudo dpkg -i sdrpp_debian_amd64.deb
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -52,9 +52,7 @@ If `libvolk2-dev` is not available, use `libvolk1-dev`.
|
|||||||
|
|
||||||
### Arch-based
|
### Arch-based
|
||||||
|
|
||||||
Install from source following the instructions below.
|
Install the latest release from the [sdrpp-git](https://aur.archlinux.org/packages/sdrpp-git/) AUR package
|
||||||
|
|
||||||
**WARNING: The sdrpp-git AUR package is no longer official, it is not recommended to use it.**
|
|
||||||
|
|
||||||
### Other
|
### Other
|
||||||
|
|
||||||
@ -76,7 +74,7 @@ The preferred IDE is [VS Code](https://code.visualstudio.com/) in order to have
|
|||||||
|
|
||||||
* [cmake](https://cmake.org)
|
* [cmake](https://cmake.org)
|
||||||
* [vcpkg](https://vcpkg.io)
|
* [vcpkg](https://vcpkg.io)
|
||||||
* [PothosSDR](https://github.com/pothosware/PothosSDR) (This will install libraries for most SDRs. You have to install it in `C:/Program Files/PothosSDR`)
|
* [PothosSDR](https://github.com/pothosware/PothosSDR) (This will install libraries for most SDRs)
|
||||||
* [RtAudio](https://www.music.mcgill.ca/~gary/rtaudio/) (You have to build and install it in `C:/Program Files (x86)/RtAudio/`)
|
* [RtAudio](https://www.music.mcgill.ca/~gary/rtaudio/) (You have to build and install it in `C:/Program Files (x86)/RtAudio/`)
|
||||||
|
|
||||||
After this, install the following dependencies using vcpkg:
|
After this, install the following dependencies using vcpkg:
|
||||||
@ -115,16 +113,16 @@ You will next need to edit the `root_dev/config.json` file to point to the modul
|
|||||||
From the top directory, you can simply run:
|
From the top directory, you can simply run:
|
||||||
|
|
||||||
```bat
|
```bat
|
||||||
./build/Release/sdrpp.exe -r root_dev -c
|
./build/Release/sdrpp.exe -r root_dev -s
|
||||||
```
|
```
|
||||||
|
|
||||||
Or, if you wish to run from the build directory e.g. `build/Release` and adapt the relative path to the `root_dev` folder:
|
Or, if you wish to run from the build directory e.g. `build/Release` and adapt the relative path to the `root_dev` folder:
|
||||||
|
|
||||||
```bat
|
```bat
|
||||||
./sdrpp.exe -r ../../root_dev -c
|
./sdrpp.exe -r ../../root_dev -s
|
||||||
```
|
```
|
||||||
|
|
||||||
The optional `-c` argument is for keeping the console active in order to see the error messages.
|
The optional `-s` argument is for keeping the console active in order to see the error messages.
|
||||||
|
|
||||||
Because all the paths are relative, for the rest of the command line instructions we are going to assume you are running from the top directory using the former command.
|
Because all the paths are relative, for the rest of the command line instructions we are going to assume you are running from the top directory using the former command.
|
||||||
As mentioned previously you need to edit `root_dev/config.json` to add the modules that were built. From the default configuration file you need to add the paths in the `modules` section. Add to this list all the modules you wish to use.
|
As mentioned previously you need to edit `root_dev/config.json` to add the modules that were built. From the default configuration file you need to add the paths in the `modules` section. Add to this list all the modules you wish to use.
|
||||||
@ -304,7 +302,7 @@ Here is an example of build commands that will build almost all modules at the t
|
|||||||
```sh
|
```sh
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
cmake .. -DOPT_BUILD_SOAPY_SOURCE=OFF -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_AUDIO_SOURCE=OFF -DOPT_BUILD_AUDIO_SINK=OFF -DOPT_BUILD_PORTAUDIO_SINK=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON -DUSE_BUNDLE_DEFAULTS=ON -DCMAKE_BUILD_TYPE=Release
|
cmake .. -DOPT_BUILD_SOAPY_SOURCE=OFF -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_AUDIO_SINK=OFF -DOPT_BUILD_PORTAUDIO_SINK=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON -DUSE_BUNDLE_DEFAULTS=ON -DCMAKE_BUILD_TYPE=Release
|
||||||
make -j<N>
|
make -j<N>
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -329,12 +327,11 @@ Modules in beta are still included in releases for the most part but not enabled
|
|||||||
|----------------------|------------|-------------------|--------------------------------|:---------------:|:-----------------------:|:---------------------------:|
|
|----------------------|------------|-------------------|--------------------------------|:---------------:|:-----------------------:|:---------------------------:|
|
||||||
| airspy_source | Working | libairspy | OPT_BUILD_AIRSPY_SOURCE | ✅ | ✅ | ✅ |
|
| airspy_source | Working | libairspy | OPT_BUILD_AIRSPY_SOURCE | ✅ | ✅ | ✅ |
|
||||||
| airspyhf_source | Working | libairspyhf | OPT_BUILD_AIRSPYHF_SOURCE | ✅ | ✅ | ✅ |
|
| airspyhf_source | Working | libairspyhf | OPT_BUILD_AIRSPYHF_SOURCE | ✅ | ✅ | ✅ |
|
||||||
| bladerf_source | Working | libbladeRF | OPT_BUILD_BLADERF_SOURCE | ⛔ | ✅ (not Debian Buster) | ✅ |
|
| bladerf_source | Working | libbladeRF | OPT_BUILD_BLADERF_SOURCE | ⛔ | ⚠️ (not Debian Buster) | ✅ |
|
||||||
| file_source | Working | - | OPT_BUILD_FILE_SOURCE | ✅ | ✅ | ✅ |
|
| file_source | Working | - | OPT_BUILD_FILE_SOURCE | ✅ | ✅ | ✅ |
|
||||||
| hackrf_source | Working | libhackrf | OPT_BUILD_HACKRF_SOURCE | ✅ | ✅ | ✅ |
|
| hackrf_source | Working | libhackrf | OPT_BUILD_HACKRF_SOURCE | ✅ | ✅ | ✅ |
|
||||||
| hermes_source | Beta | - | OPT_BUILD_HERMES_SOURCE | ✅ | ✅ | ✅ |
|
| hermes_source | Beta | - | OPT_BUILD_HERMES_SOURCE | ✅ | ✅ | ⛔ |
|
||||||
| limesdr_source | Working | liblimesuite | OPT_BUILD_LIMESDR_SOURCE | ⛔ | ✅ | ✅ |
|
| limesdr_source | Working | liblimesuite | OPT_BUILD_LIMESDR_SOURCE | ⛔ | ✅ | ✅ |
|
||||||
| perseus_source | Beta | libperseus-sdr | OPT_BUILD_PERSEUS_SOURCE | ⛔ | ⛔ | ⛔ |
|
|
||||||
| plutosdr_source | Working | libiio, libad9361 | OPT_BUILD_PLUTOSDR_SOURCE | ✅ | ✅ | ✅ |
|
| plutosdr_source | Working | libiio, libad9361 | OPT_BUILD_PLUTOSDR_SOURCE | ✅ | ✅ | ✅ |
|
||||||
| rfspace_source | Working | - | OPT_BUILD_RFSPACE_SOURCE | ✅ | ✅ | ✅ |
|
| rfspace_source | Working | - | OPT_BUILD_RFSPACE_SOURCE | ✅ | ✅ | ✅ |
|
||||||
| rtl_sdr_source | Working | librtlsdr | OPT_BUILD_RTL_SDR_SOURCE | ✅ | ✅ | ✅ |
|
| rtl_sdr_source | Working | librtlsdr | OPT_BUILD_RTL_SDR_SOURCE | ✅ | ✅ | ✅ |
|
||||||
@ -351,7 +348,7 @@ Modules in beta are still included in releases for the most part but not enabled
|
|||||||
|
|
||||||
| Name | Stage | Dependencies | Option | Built by default| Built in Release | Enabled in SDR++ by default |
|
| Name | Stage | Dependencies | Option | Built by default| Built in Release | Enabled in SDR++ by default |
|
||||||
|--------------------|------------|--------------|------------------------------|:---------------:|:----------------:|:---------------------------:|
|
|--------------------|------------|--------------|------------------------------|:---------------:|:----------------:|:---------------------------:|
|
||||||
| android_audio_sink | Working | - | OPT_BUILD_ANDROID_AUDIO_SINK | ⛔ | ✅ | ✅ (Android only) |
|
| android_audio_sink | Working | - | OPT_BUILD_ANDROID_AUDIO_SINK | ⛔ | ✅ | ⛔ |
|
||||||
| audio_sink | Working | rtaudio | OPT_BUILD_AUDIO_SINK | ✅ | ✅ | ✅ |
|
| audio_sink | Working | rtaudio | OPT_BUILD_AUDIO_SINK | ✅ | ✅ | ✅ |
|
||||||
| network_sink | Working | - | OPT_BUILD_NETWORK_SINK | ✅ | ✅ | ✅ |
|
| network_sink | Working | - | OPT_BUILD_NETWORK_SINK | ✅ | ✅ | ✅ |
|
||||||
| new_portaudio_sink | Beta | portaudio | OPT_BUILD_NEW_PORTAUDIO_SINK | ⛔ | ✅ | ⛔ |
|
| new_portaudio_sink | Beta | portaudio | OPT_BUILD_NEW_PORTAUDIO_SINK | ⛔ | ✅ | ⛔ |
|
||||||
@ -377,9 +374,9 @@ Modules in beta are still included in releases for the most part but not enabled
|
|||||||
| discord_integration | Working | - | OPT_BUILD_DISCORD_PRESENCE | ✅ | ✅ | ⛔ |
|
| discord_integration | Working | - | OPT_BUILD_DISCORD_PRESENCE | ✅ | ✅ | ⛔ |
|
||||||
| frequency_manager | Working | - | OPT_BUILD_FREQUENCY_MANAGER | ✅ | ✅ | ✅ |
|
| frequency_manager | Working | - | OPT_BUILD_FREQUENCY_MANAGER | ✅ | ✅ | ✅ |
|
||||||
| recorder | Working | - | OPT_BUILD_RECORDER | ✅ | ✅ | ✅ |
|
| recorder | Working | - | OPT_BUILD_RECORDER | ✅ | ✅ | ✅ |
|
||||||
| rigctl_client | Unfinished | - | OPT_BUILD_RIGCTL_CLIENT | ✅ | ✅ | ⛔ |
|
| rigctl_client | Unfinished | - | OPT_BUILD_RIGCTL_CLIENT | ⛔ | ⛔ | ⛔ |
|
||||||
| rigctl_server | Working | - | OPT_BUILD_RIGCTL_SERVER | ✅ | ✅ | ✅ |
|
| rigctl_server | Working | - | OPT_BUILD_RIGCTL_SERVER | ✅ | ✅ | ✅ |
|
||||||
| scanner | Beta | - | OPT_BUILD_SCANNER | ✅ | ✅ | ⛔ |
|
| scanner | Beta | - | OPT_BUILD_SCANNER | ✅ | ✅ | ✅ |
|
||||||
| scheduler | Unfinished | - | OPT_BUILD_SCHEDULER | ⛔ | ⛔ | ⛔ |
|
| scheduler | Unfinished | - | OPT_BUILD_SCHEDULER | ⛔ | ⛔ | ⛔ |
|
||||||
|
|
||||||
# Troubleshooting
|
# Troubleshooting
|
||||||
@ -473,7 +470,6 @@ I will soon publish a contributing.md listing the code style to use.
|
|||||||
* [Howard0su](https://github.com/howard0su)
|
* [Howard0su](https://github.com/howard0su)
|
||||||
* John Donkersley
|
* John Donkersley
|
||||||
* [Joshua Kimsey](https://github.com/JoshuaKimsey)
|
* [Joshua Kimsey](https://github.com/JoshuaKimsey)
|
||||||
* [Manawyrm](https://github.com/Manawyrm)
|
|
||||||
* [Martin Hauke](https://github.com/mnhauke)
|
* [Martin Hauke](https://github.com/mnhauke)
|
||||||
* [Marvin Sinister](https://github.com/marvin-sinister)
|
* [Marvin Sinister](https://github.com/marvin-sinister)
|
||||||
* [Maxime Biette](https://github.com/mbiette)
|
* [Maxime Biette](https://github.com/mbiette)
|
||||||
@ -483,6 +479,7 @@ I will soon publish a contributing.md listing the code style to use.
|
|||||||
* [Shuyuan Liu](https://github.com/shuyuan-liu)
|
* [Shuyuan Liu](https://github.com/shuyuan-liu)
|
||||||
* [Syne Ardwin (WI9SYN)](https://esaille.me/)
|
* [Syne Ardwin (WI9SYN)](https://esaille.me/)
|
||||||
* [Szymon Zakrent](https://github.com/zakrent)
|
* [Szymon Zakrent](https://github.com/zakrent)
|
||||||
|
* [Tobias Mädel](https://github.com/Manawyrm)
|
||||||
* Youssef Touil
|
* Youssef Touil
|
||||||
* [Zimm](https://github.com/invader-zimm)
|
* [Zimm](https://github.com/invader-zimm)
|
||||||
|
|
||||||
|
@ -149,12 +149,6 @@
|
|||||||
"start": 28000000,
|
"start": 28000000,
|
||||||
"end": 29700000
|
"end": 29700000
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "8m - Amateur",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 40660000,
|
|
||||||
"end": 40690000
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "6m - Amateur",
|
"name": "6m - Amateur",
|
||||||
"type": "amateur",
|
"type": "amateur",
|
||||||
|
@ -340,7 +340,7 @@
|
|||||||
"name": "11m - CB",
|
"name": "11m - CB",
|
||||||
"type": "amateur",
|
"type": "amateur",
|
||||||
"start": 26960000,
|
"start": 26960000,
|
||||||
"end": 27410000
|
"end": 27230000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "10m - Radioamateur",
|
"name": "10m - Radioamateur",
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
"name": "Germany",
|
"name": "Germany",
|
||||||
"country_name": "Germany",
|
"country_name": "Germany",
|
||||||
"country_code": "DE",
|
"country_code": "DE",
|
||||||
"author_name": "Manawyrm",
|
"author_name": "Tobias Mädel",
|
||||||
"author_url": "https://tbspace.de",
|
"author_url": "https://tbspace.de",
|
||||||
"bands": [
|
"bands": [
|
||||||
{
|
{
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -529,9 +529,9 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Train communications",
|
"name": "Train communications",
|
||||||
"type": "railway",
|
"type": "aviation",
|
||||||
"start": 151712500,
|
"start": 151775000,
|
||||||
"end": 156012500
|
"end": 151875000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Marine",
|
"name": "Marine",
|
||||||
@ -557,6 +557,12 @@
|
|||||||
"start": 270000000,
|
"start": 270000000,
|
||||||
"end": 380000000
|
"end": 380000000
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "Train communications",
|
||||||
|
"type": "aviation",
|
||||||
|
"start": 299999000,
|
||||||
|
"end": 300001000
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "70cm",
|
"name": "70cm",
|
||||||
"type": "amateur",
|
"type": "amateur",
|
||||||
|
@ -5,12 +5,6 @@
|
|||||||
"author_name": "John Donkersley",
|
"author_name": "John Donkersley",
|
||||||
"author_url": "",
|
"author_url": "",
|
||||||
"bands": [
|
"bands": [
|
||||||
{
|
|
||||||
"name": "2200m Ham Band",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 135700,
|
|
||||||
"end": 137800
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "Long Wave",
|
"name": "Long Wave",
|
||||||
"type": "broadcast",
|
"type": "broadcast",
|
||||||
@ -215,18 +209,18 @@
|
|||||||
"start": 15010000,
|
"start": 15010000,
|
||||||
"end": 15100000
|
"end": 15100000
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "19m Broadcast",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 15100000,
|
|
||||||
"end": 15800000
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "Maritime",
|
"name": "Maritime",
|
||||||
"type": "marine",
|
"type": "marine",
|
||||||
"start": 16360000,
|
"start": 16360000,
|
||||||
"end": 17410000
|
"end": 17410000
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "19m Broadcast",
|
||||||
|
"type": "broadcast",
|
||||||
|
"start": 15100000,
|
||||||
|
"end": 15800000
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "16m Broadcast",
|
"name": "16m Broadcast",
|
||||||
"type": "broadcast",
|
"type": "broadcast",
|
||||||
@ -351,7 +345,7 @@
|
|||||||
"name": "Air Band TACAN/ILS",
|
"name": "Air Band TACAN/ILS",
|
||||||
"type": "aviation",
|
"type": "aviation",
|
||||||
"start": 108000000,
|
"start": 108000000,
|
||||||
"end": 117975000
|
"end": 118000000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Air Band Voice",
|
"name": "Air Band Voice",
|
||||||
@ -377,12 +371,6 @@
|
|||||||
"start": 147343750,
|
"start": 147343750,
|
||||||
"end": 147500000
|
"end": 147500000
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "Satellites",
|
|
||||||
"type": "satellite",
|
|
||||||
"start": 148000000,
|
|
||||||
"end": 150050000
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "Pagers - Flex/POCSAG",
|
"name": "Pagers - Flex/POCSAG",
|
||||||
"type": "PMR",
|
"type": "PMR",
|
||||||
@ -437,18 +425,6 @@
|
|||||||
"start": 230000000,
|
"start": 230000000,
|
||||||
"end": 400000000
|
"end": 400000000
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "Satellites",
|
|
||||||
"type": "satellite",
|
|
||||||
"start": 399900000,
|
|
||||||
"end": 401000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Weather Balloons",
|
|
||||||
"type": "aviation",
|
|
||||||
"start": 401000000,
|
|
||||||
"end": 406000000
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "Private Mobile Radio inc trams",
|
"name": "Private Mobile Radio inc trams",
|
||||||
"type": "PMR",
|
"type": "PMR",
|
||||||
@ -486,34 +462,22 @@
|
|||||||
"end": 455000000
|
"end": 455000000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Private Mobile Radio inc OB",
|
"name": "Private Mobile Radio",
|
||||||
"type": "PMR",
|
"type": "PMR",
|
||||||
"start": 455000000,
|
"start": 455000000,
|
||||||
"end": 470000000
|
"end": 467200000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Outside Broadcast Talkback",
|
||||||
|
"type": "PMR",
|
||||||
|
"start": 467200000,
|
||||||
|
"end": 468600000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Digital TV Broadcast",
|
"name": "Digital TV Broadcast",
|
||||||
"type": "broadcast",
|
"type": "broadcast",
|
||||||
"start": 470000000,
|
"start": 470000000,
|
||||||
"end": 700000000
|
"end": 790000000
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Cell phones",
|
|
||||||
"type": "cellular",
|
|
||||||
"start": 703000000,
|
|
||||||
"end": 788000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Band 20 Cell phone downlink",
|
|
||||||
"type": "cellular",
|
|
||||||
"start": 791000000,
|
|
||||||
"end": 821000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Band 20 Cell phone uplink",
|
|
||||||
"type": "cellular",
|
|
||||||
"start": 832000000,
|
|
||||||
"end": 862000000
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Licence Exempt Short Range",
|
"name": "Licence Exempt Short Range",
|
||||||
@ -521,84 +485,12 @@
|
|||||||
"start": 862000000,
|
"start": 862000000,
|
||||||
"end": 875800000
|
"end": 875800000
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "Band 8 Cell phone uplink",
|
|
||||||
"type": "cellular",
|
|
||||||
"start": 880100000,
|
|
||||||
"end": 914900000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Band 8 Cell phone downlink",
|
|
||||||
"type": "cellular",
|
|
||||||
"start": 925100000,
|
|
||||||
"end": 929500000
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "23cm Ham Band",
|
"name": "23cm Ham Band",
|
||||||
"type": "amateur",
|
"type": "amateur",
|
||||||
"start": 1240000000,
|
"start": 1240000000,
|
||||||
"end": 1325000000
|
"end": 1325000000
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "Band 32 Cell phone",
|
|
||||||
"type": "cellular",
|
|
||||||
"start": 1452000000,
|
|
||||||
"end": 1492000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Satellite L-band",
|
|
||||||
"type": "satellite",
|
|
||||||
"start": 1518000000,
|
|
||||||
"end": 1559000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Satellite L-band",
|
|
||||||
"type": "satellite",
|
|
||||||
"start": 1626500000,
|
|
||||||
"end": 1660500000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Satellite L-band",
|
|
||||||
"type": "satellite",
|
|
||||||
"start": 1668000000,
|
|
||||||
"end": 1675000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Band 3 Cell phone uplink",
|
|
||||||
"type": "cellular",
|
|
||||||
"start": 1710000000,
|
|
||||||
"end": 1785000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Band 3 Cell phone downlink",
|
|
||||||
"type": "cellular",
|
|
||||||
"start": 1805100000,
|
|
||||||
"end": 1880000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "DECT cordless phones",
|
|
||||||
"type": "cellular",
|
|
||||||
"start": 1880000000,
|
|
||||||
"end": 1900000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Band 3 Cell phones",
|
|
||||||
"type": "cellular",
|
|
||||||
"start": 1900000000,
|
|
||||||
"end": 1920000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Band 1 Cell phone uplink",
|
|
||||||
"type": "cellular",
|
|
||||||
"start": 1920000000,
|
|
||||||
"end": 1979700000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Band 1 Cell phone downlink",
|
|
||||||
"type": "cellular",
|
|
||||||
"start": 2110300000,
|
|
||||||
"end": 2169700000
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "13cm Ham Band",
|
"name": "13cm Ham Band",
|
||||||
"type": "amateur",
|
"type": "amateur",
|
||||||
@ -606,28 +498,10 @@
|
|||||||
"end": 2302000000
|
"end": 2302000000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "ISM - wifi and bluettoth",
|
"name": "13cm Ham Band",
|
||||||
"type": "ISM",
|
"type": "amateur",
|
||||||
"start": 2400000000,
|
"start": 2310000000,
|
||||||
"end": 2483000000
|
"end": 2450000000
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Band 38 Cell phones",
|
|
||||||
"type": "cellular",
|
|
||||||
"start": 2500000000,
|
|
||||||
"end": 269000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Band 42 5G Cell phones",
|
|
||||||
"type": "cellular",
|
|
||||||
"start": 3410000000,
|
|
||||||
"end": 3720000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "ISM - wifi",
|
|
||||||
"type": "ISM",
|
|
||||||
"start": 5150000000,
|
|
||||||
"end": 5850000000
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
@ -227,18 +227,6 @@
|
|||||||
"start": 144000000,
|
"start": 144000000,
|
||||||
"end": 148000000
|
"end": 148000000
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "MURS (lower)",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 151820000,
|
|
||||||
"end": 151940000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "MURS (upper)",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 154570000,
|
|
||||||
"end": 154600000
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "Marine",
|
"name": "Marine",
|
||||||
"type": "marine",
|
"type": "marine",
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "Smoke",
|
|
||||||
"author": "Yaroslav Andrianov",
|
|
||||||
"map": [
|
|
||||||
"#FFFFFF",
|
|
||||||
"#EEEEEE",
|
|
||||||
"#CCCCCC",
|
|
||||||
"#777777",
|
|
||||||
"#555555",
|
|
||||||
"#333333",
|
|
||||||
"#111111",
|
|
||||||
"#000000"
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,28 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "Temper Colors",
|
|
||||||
"author": "Yaroslav Andrianov",
|
|
||||||
"map": [
|
|
||||||
"#000000",
|
|
||||||
"#05011f",
|
|
||||||
"#0f0836",
|
|
||||||
"#2f1436",
|
|
||||||
"#3d114d",
|
|
||||||
"#4e186f",
|
|
||||||
"#592a8f",
|
|
||||||
"#5e43a5",
|
|
||||||
"#5f5eb3",
|
|
||||||
"#6276ba",
|
|
||||||
"#6b8cbf",
|
|
||||||
"#7ba1c2",
|
|
||||||
"#95b5c7",
|
|
||||||
"#b3c6ce",
|
|
||||||
"#d4bcac",
|
|
||||||
"#cca389",
|
|
||||||
"#c68a6d",
|
|
||||||
"#be6f5b",
|
|
||||||
"#b25652",
|
|
||||||
"#a24050",
|
|
||||||
"#8e2c50",
|
|
||||||
"#741e4f"
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,29 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "Vivid",
|
|
||||||
"author": "Yaroslav Andrianov",
|
|
||||||
"map": [
|
|
||||||
"#000000",
|
|
||||||
"#06001c",
|
|
||||||
"#090028",
|
|
||||||
"#12002c",
|
|
||||||
"#230039",
|
|
||||||
"#360143",
|
|
||||||
"#440154",
|
|
||||||
"#472c7a",
|
|
||||||
"#3b518b",
|
|
||||||
"#2c718e",
|
|
||||||
"#21908d",
|
|
||||||
"#27ad81",
|
|
||||||
"#5cc863",
|
|
||||||
"#aadc32",
|
|
||||||
"#f6fd25",
|
|
||||||
"#fdde17",
|
|
||||||
"#fecb31",
|
|
||||||
"#FE9029",
|
|
||||||
"#F56918",
|
|
||||||
"#DC3B07",
|
|
||||||
"#CE2D04",
|
|
||||||
"#AC1701",
|
|
||||||
"#980E01"
|
|
||||||
]
|
|
||||||
}
|
|
22
rpi_install.sh
Normal file
22
rpi_install.sh
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
[ $(id -u) = 0 ] && echo "Please do not run this script as root" && exit 100
|
||||||
|
|
||||||
|
echo "Installing dependencies"
|
||||||
|
sudo apt update
|
||||||
|
sudo apt install -y build-essential cmake git libfftw3-dev libglfw3-dev libvolk1-dev libzstd-dev libsoapysdr-dev libairspyhf-dev libairspy-dev \
|
||||||
|
libiio-dev libad9361-dev librtaudio-dev libhackrf-dev librtlsdr-dev libbladerf-dev liblimesuite-dev p7zip-full wget
|
||||||
|
|
||||||
|
echo "Preparing build"
|
||||||
|
mkdir -p build
|
||||||
|
cd build
|
||||||
|
cmake .. -DOPT_BUILD_LIMESDR_SOURCE=ON
|
||||||
|
|
||||||
|
echo "Building"
|
||||||
|
make
|
||||||
|
|
||||||
|
echo "Installing"
|
||||||
|
sudo make install
|
||||||
|
|
||||||
|
echo "Done!"
|
@ -45,7 +45,6 @@ public:
|
|||||||
int count = audio.getDeviceCount();
|
int count = audio.getDeviceCount();
|
||||||
RtAudio::DeviceInfo info;
|
RtAudio::DeviceInfo info;
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
try {
|
|
||||||
info = audio.getDeviceInfo(i);
|
info = audio.getDeviceInfo(i);
|
||||||
if (!info.probed) { continue; }
|
if (!info.probed) { continue; }
|
||||||
if (info.outputChannels == 0) { continue; }
|
if (info.outputChannels == 0) { continue; }
|
||||||
@ -55,10 +54,7 @@ public:
|
|||||||
txtDevList += info.name;
|
txtDevList += info.name;
|
||||||
txtDevList += '\0';
|
txtDevList += '\0';
|
||||||
}
|
}
|
||||||
catch (std::exception e) {
|
|
||||||
flog::error("AudioSinkModule Error getting audio device info: {0}", e.what());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
selectByName(device);
|
selectByName(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
#define NOMINMAX
|
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
#include <utils/flog.h>
|
#include <utils/flog.h>
|
||||||
#include <module.h>
|
#include <module.h>
|
||||||
@ -10,8 +9,6 @@
|
|||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <regex>
|
#include <regex>
|
||||||
#include <gui/tuner.h>
|
#include <gui/tuner.h>
|
||||||
#include <algorithm>
|
|
||||||
#include <stdexcept>
|
|
||||||
|
|
||||||
#define CONCAT(a, b) ((std::string(a) + b).c_str())
|
#define CONCAT(a, b) ((std::string(a) + b).c_str())
|
||||||
|
|
||||||
@ -124,12 +121,6 @@ private:
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
_this->reader = new WavReader(_this->fileSelect.path);
|
_this->reader = new WavReader(_this->fileSelect.path);
|
||||||
if (_this->reader->getSampleRate() == 0) {
|
|
||||||
_this->reader->close();
|
|
||||||
delete _this->reader;
|
|
||||||
_this->reader = NULL;
|
|
||||||
throw std::runtime_error("Sample rate may not be zero");
|
|
||||||
}
|
|
||||||
_this->sampleRate = _this->reader->getSampleRate();
|
_this->sampleRate = _this->reader->getSampleRate();
|
||||||
core::setInputSampleRate(_this->sampleRate);
|
core::setInputSampleRate(_this->sampleRate);
|
||||||
std::string filename = std::filesystem::path(_this->fileSelect.path).filename().string();
|
std::string filename = std::filesystem::path(_this->fileSelect.path).filename().string();
|
||||||
@ -139,7 +130,7 @@ private:
|
|||||||
//gui::freqSelect.maxFreq = _this->centerFreq + (_this->sampleRate/2);
|
//gui::freqSelect.maxFreq = _this->centerFreq + (_this->sampleRate/2);
|
||||||
//gui::freqSelect.limitFreq = true;
|
//gui::freqSelect.limitFreq = true;
|
||||||
}
|
}
|
||||||
catch (std::exception& e) {
|
catch (std::exception e) {
|
||||||
flog::error("Error: {0}", e.what());
|
flog::error("Error: {0}", e.what());
|
||||||
}
|
}
|
||||||
config.acquire();
|
config.acquire();
|
||||||
@ -153,8 +144,8 @@ private:
|
|||||||
|
|
||||||
static void worker(void* ctx) {
|
static void worker(void* ctx) {
|
||||||
FileSourceModule* _this = (FileSourceModule*)ctx;
|
FileSourceModule* _this = (FileSourceModule*)ctx;
|
||||||
double sampleRate = std::max(_this->reader->getSampleRate(), (uint32_t)1);
|
double sampleRate = _this->reader->getSampleRate();
|
||||||
int blockSize = std::min((int)(sampleRate / 200.0f), (int)STREAM_BUFFER_SIZE);
|
int blockSize = sampleRate / 200.0f;
|
||||||
int16_t* inBuf = new int16_t[blockSize * 2];
|
int16_t* inBuf = new int16_t[blockSize * 2];
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
@ -168,8 +159,8 @@ private:
|
|||||||
|
|
||||||
static void floatWorker(void* ctx) {
|
static void floatWorker(void* ctx) {
|
||||||
FileSourceModule* _this = (FileSourceModule*)ctx;
|
FileSourceModule* _this = (FileSourceModule*)ctx;
|
||||||
double sampleRate = std::max(_this->reader->getSampleRate(), (uint32_t)1);
|
double sampleRate = _this->reader->getSampleRate();
|
||||||
int blockSize = std::min((int)(sampleRate / 200.0f), (int)STREAM_BUFFER_SIZE);
|
int blockSize = sampleRate / 200.0f;
|
||||||
dsp::complex_t* inBuf = new dsp::complex_t[blockSize];
|
dsp::complex_t* inBuf = new dsp::complex_t[blockSize];
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
|
@ -137,10 +137,6 @@ public:
|
|||||||
hackrf_device_list_t* _devList = hackrf_device_list();
|
hackrf_device_list_t* _devList = hackrf_device_list();
|
||||||
|
|
||||||
for (int i = 0; i < _devList->devicecount; i++) {
|
for (int i = 0; i < _devList->devicecount; i++) {
|
||||||
// Skip devices that are in use
|
|
||||||
if (_devList->serial_numbers[i] == NULL) { continue; }
|
|
||||||
|
|
||||||
// Save the device serial number
|
|
||||||
devList.push_back(_devList->serial_numbers[i]);
|
devList.push_back(_devList->serial_numbers[i]);
|
||||||
devListTxt += (char*)(_devList->serial_numbers[i] + 16);
|
devListTxt += (char*)(_devList->serial_numbers[i] + 16);
|
||||||
devListTxt += '\0';
|
devListTxt += '\0';
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
cmake_minimum_required(VERSION 3.13)
|
|
||||||
project(perseus_source)
|
|
||||||
|
|
||||||
file(GLOB SRC "src/*.cpp")
|
|
||||||
|
|
||||||
include(${SDRPP_MODULE_CMAKE})
|
|
||||||
|
|
||||||
if (MSVC)
|
|
||||||
# Lib path
|
|
||||||
target_link_directories(perseus_source PRIVATE "C:/Program Files/PothosSDR/bin/")
|
|
||||||
|
|
||||||
target_include_directories(perseus_source PUBLIC "C:/Program Files/PothosSDR/include/perseus-sdr")
|
|
||||||
|
|
||||||
target_link_libraries(perseus_source PRIVATE perseus-sdr)
|
|
||||||
else (MSVC)
|
|
||||||
find_package(PkgConfig)
|
|
||||||
|
|
||||||
pkg_check_modules(LIBPERSEUSSDR REQUIRED libperseus-sdr)
|
|
||||||
|
|
||||||
target_include_directories(perseus_source PRIVATE ${LIBPERSEUSSDR_INCLUDE_DIRS})
|
|
||||||
target_link_directories(perseus_source PRIVATE ${LIBPERSEUSSDR_LIBRARY_DIRS})
|
|
||||||
target_link_libraries(perseus_source PRIVATE ${LIBPERSEUSSDR_LIBRARIES})
|
|
||||||
|
|
||||||
# Include it because for some reason pkgconfig doesn't look here?
|
|
||||||
if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
|
||||||
target_include_directories(perseus_source PRIVATE "/usr/local/include")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
endif ()
|
|
@ -1,468 +0,0 @@
|
|||||||
#include <utils/flog.h>
|
|
||||||
#include <module.h>
|
|
||||||
#include <gui/gui.h>
|
|
||||||
#include <signal_path/signal_path.h>
|
|
||||||
#include <core.h>
|
|
||||||
#include <gui/style.h>
|
|
||||||
#include <config.h>
|
|
||||||
#include <gui/smgui.h>
|
|
||||||
#include <gui/widgets/stepped_slider.h>
|
|
||||||
#include <perseus-sdr.h>
|
|
||||||
#include <utils/optionlist.h>
|
|
||||||
|
|
||||||
#define CONCAT(a, b) ((std::string(a) + b).c_str())
|
|
||||||
|
|
||||||
SDRPP_MOD_INFO{
|
|
||||||
/* Name: */ "perseus_source",
|
|
||||||
/* Description: */ "Perseus SDR source module for SDR++",
|
|
||||||
/* Author: */ "Ryzerth",
|
|
||||||
/* Version: */ 0, 1, 0,
|
|
||||||
/* Max instances */ 1
|
|
||||||
};
|
|
||||||
|
|
||||||
#define MAX_SAMPLERATE_COUNT 128
|
|
||||||
|
|
||||||
ConfigManager config;
|
|
||||||
|
|
||||||
class PerseusSourceModule : public ModuleManager::Instance {
|
|
||||||
public:
|
|
||||||
PerseusSourceModule(std::string name) {
|
|
||||||
this->name = name;
|
|
||||||
|
|
||||||
sampleRate = 768000;
|
|
||||||
|
|
||||||
handler.ctx = this;
|
|
||||||
handler.selectHandler = menuSelected;
|
|
||||||
handler.deselectHandler = menuDeselected;
|
|
||||||
handler.menuHandler = menuHandler;
|
|
||||||
handler.startHandler = start;
|
|
||||||
handler.stopHandler = stop;
|
|
||||||
handler.tuneHandler = tune;
|
|
||||||
handler.stream = &stream;
|
|
||||||
|
|
||||||
perseus_set_debug(9);
|
|
||||||
|
|
||||||
refresh();
|
|
||||||
|
|
||||||
config.acquire();
|
|
||||||
std::string serial = config.conf["device"];
|
|
||||||
config.release();
|
|
||||||
select(serial);
|
|
||||||
|
|
||||||
sigpath::sourceManager.registerSource("Perseus", &handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
~PerseusSourceModule() {
|
|
||||||
stop(this);
|
|
||||||
sigpath::sourceManager.unregisterSource("Perseus");
|
|
||||||
if (libInit) { perseus_exit(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
void postInit() {}
|
|
||||||
|
|
||||||
void enable() {
|
|
||||||
enabled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void disable() {
|
|
||||||
enabled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isEnabled() {
|
|
||||||
return enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
void refresh() {
|
|
||||||
// Re-initialize driver
|
|
||||||
if (libInit) { perseus_exit(); }
|
|
||||||
int devCount = perseus_init();
|
|
||||||
if (devCount < 0) {
|
|
||||||
libInit = false;
|
|
||||||
flog::error("Could not initialize libperseus: {}", perseus_errorstr());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
libInit = true;
|
|
||||||
|
|
||||||
// Open each device to get the serial number
|
|
||||||
for (int i = 0; i < devCount; i++) {
|
|
||||||
// Open device
|
|
||||||
perseus_descr* dev = perseus_open(i);
|
|
||||||
if (!dev) {
|
|
||||||
flog::error("Failed to open Perseus device with ID {}: {}", i, perseus_errorstr());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load firmware
|
|
||||||
int err = perseus_firmware_download(dev, NULL);
|
|
||||||
if (err) {
|
|
||||||
flog::error("Could not upload firmware to device {}: {}", i, perseus_errorstr());
|
|
||||||
perseus_close(dev);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get info
|
|
||||||
eeprom_prodid prodId;
|
|
||||||
err = perseus_get_product_id(dev, &prodId);
|
|
||||||
if (err) {
|
|
||||||
flog::error("Could not getproduct info from device {}: {}", i, perseus_errorstr());
|
|
||||||
perseus_close(dev);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create entry
|
|
||||||
char serial[128];
|
|
||||||
char buf[128];
|
|
||||||
sprintf(serial, "%05d", (int)prodId.sn);
|
|
||||||
sprintf(buf, "Perseus %d.%d [%s]", (int)prodId.hwver, (int)prodId.hwrel, serial);
|
|
||||||
devList.define(serial, buf, i);
|
|
||||||
|
|
||||||
// Close device
|
|
||||||
perseus_close(dev);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void select(const std::string& serial) {
|
|
||||||
// If there are no devices, give up
|
|
||||||
if (devList.empty()) {
|
|
||||||
selectedSerial.clear();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the serial number is not available, select first instead
|
|
||||||
if (!devList.keyExists(serial)) {
|
|
||||||
select(devList.key(0));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Open device
|
|
||||||
selectedSerial = serial;
|
|
||||||
selectedPerseusId = devList.value(devList.keyId(serial));
|
|
||||||
perseus_descr* dev = perseus_open(selectedPerseusId);
|
|
||||||
if (!dev) {
|
|
||||||
flog::error("Failed to open device {}: {}", selectedPerseusId, perseus_errorstr());
|
|
||||||
selectedSerial.clear();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load firmware
|
|
||||||
int err = perseus_firmware_download(dev, NULL);
|
|
||||||
if (err) {
|
|
||||||
flog::error("Could not upload firmware to device: {}", perseus_errorstr());
|
|
||||||
perseus_close(dev);
|
|
||||||
selectedSerial.clear();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get info
|
|
||||||
eeprom_prodid prodId;
|
|
||||||
err = perseus_get_product_id(dev, &prodId);
|
|
||||||
if (err) {
|
|
||||||
flog::error("Could not getproduct info from device: {}", perseus_errorstr());
|
|
||||||
perseus_close(dev);
|
|
||||||
selectedSerial.clear();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// List samplerates
|
|
||||||
srList.clear();
|
|
||||||
int samplerates[MAX_SAMPLERATE_COUNT];
|
|
||||||
memset(samplerates, 0, sizeof(int)*MAX_SAMPLERATE_COUNT);
|
|
||||||
err = perseus_get_sampling_rates(dev, samplerates, MAX_SAMPLERATE_COUNT);
|
|
||||||
if (err) {
|
|
||||||
flog::error("Could not get samplerate list: {}", perseus_errorstr());
|
|
||||||
perseus_close(dev);
|
|
||||||
selectedSerial.clear();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (int i = 0; i < MAX_SAMPLERATE_COUNT; i++) {
|
|
||||||
if (!samplerates[i]) { break; }
|
|
||||||
srList.define(samplerates[i], getBandwdithScaled(samplerates[i]), samplerates[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: List attenuator values
|
|
||||||
|
|
||||||
// Load options
|
|
||||||
srId = 0;
|
|
||||||
dithering = false;
|
|
||||||
preamp = false;
|
|
||||||
preselector = true;
|
|
||||||
atten = 0;
|
|
||||||
config.acquire();
|
|
||||||
if (config.conf["devices"][selectedSerial].contains("samplerate")) {
|
|
||||||
int sr = config.conf["devices"][selectedSerial]["samplerate"];
|
|
||||||
if (srList.keyExists(sr)) {
|
|
||||||
srId = srList.keyId(sr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (config.conf["devices"][selectedSerial].contains("dithering")) {
|
|
||||||
dithering = config.conf["devices"][selectedSerial]["dithering"];
|
|
||||||
}
|
|
||||||
if (config.conf["devices"][selectedSerial].contains("preamp")) {
|
|
||||||
preamp = config.conf["devices"][selectedSerial]["preamp"];
|
|
||||||
}
|
|
||||||
if (config.conf["devices"][selectedSerial].contains("preselector")) {
|
|
||||||
preselector = config.conf["devices"][selectedSerial]["preselector"];
|
|
||||||
}
|
|
||||||
if (config.conf["devices"][selectedSerial].contains("attenuation")) {
|
|
||||||
atten = config.conf["devices"][selectedSerial]["attenuation"];
|
|
||||||
}
|
|
||||||
config.release();
|
|
||||||
|
|
||||||
// Update samplerate
|
|
||||||
sampleRate = srList[srId];
|
|
||||||
core::setInputSampleRate(sampleRate);
|
|
||||||
|
|
||||||
// Close device
|
|
||||||
perseus_close(dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string getBandwdithScaled(double bw) {
|
|
||||||
char buf[1024];
|
|
||||||
if (bw >= 1000000.0) {
|
|
||||||
sprintf(buf, "%.1lfMHz", bw / 1000000.0);
|
|
||||||
}
|
|
||||||
else if (bw >= 1000.0) {
|
|
||||||
sprintf(buf, "%.1lfKHz", bw / 1000.0);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
sprintf(buf, "%.1lfHz", bw);
|
|
||||||
}
|
|
||||||
return std::string(buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void menuSelected(void* ctx) {
|
|
||||||
PerseusSourceModule* _this = (PerseusSourceModule*)ctx;
|
|
||||||
core::setInputSampleRate(_this->sampleRate);
|
|
||||||
flog::info("PerseusSourceModule '{0}': Menu Select!", _this->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void menuDeselected(void* ctx) {
|
|
||||||
PerseusSourceModule* _this = (PerseusSourceModule*)ctx;
|
|
||||||
flog::info("PerseusSourceModule '{0}': Menu Deselect!", _this->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void start(void* ctx) {
|
|
||||||
PerseusSourceModule* _this = (PerseusSourceModule*)ctx;
|
|
||||||
if (_this->running) { return; }
|
|
||||||
if (_this->selectedSerial.empty()) {
|
|
||||||
flog::error("No device is selected");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Open device
|
|
||||||
_this->openDev = perseus_open(_this->selectedPerseusId);
|
|
||||||
if (!_this->openDev) {
|
|
||||||
flog::error("Failed to open device {}: {}", _this->selectedPerseusId, perseus_errorstr());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load firmware
|
|
||||||
int err = perseus_firmware_download(_this->openDev, NULL);
|
|
||||||
if (err) {
|
|
||||||
flog::error("Could not upload firmware to device: {}", perseus_errorstr());
|
|
||||||
perseus_close(_this->openDev);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set samplerate
|
|
||||||
err = perseus_set_sampling_rate(_this->openDev, _this->sampleRate);
|
|
||||||
if (err) {
|
|
||||||
flog::error("Could not set samplerate: {}", perseus_errorstr());
|
|
||||||
perseus_close(_this->openDev);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set options
|
|
||||||
perseus_set_adc(_this->openDev, _this->dithering, _this->preamp);
|
|
||||||
perseus_set_attenuator_in_db(_this->openDev, _this->atten);
|
|
||||||
perseus_set_ddc_center_freq(_this->openDev, _this->freq, _this->preselector);
|
|
||||||
|
|
||||||
// Start stream
|
|
||||||
int idealBufferSize = _this->sampleRate / 200;
|
|
||||||
int multipleOf1024 = std::clamp<int>(idealBufferSize / 1024, 1, 2);
|
|
||||||
int bufferSize = multipleOf1024 * 1024;
|
|
||||||
int bufferBytes = bufferSize*6;
|
|
||||||
err = perseus_start_async_input(_this->openDev, bufferBytes, callback, _this);
|
|
||||||
if (err) {
|
|
||||||
flog::error("Could not start stream: {}", perseus_errorstr());
|
|
||||||
perseus_close(_this->openDev);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_this->running = true;
|
|
||||||
flog::info("PerseusSourceModule '{0}': Start!", _this->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void stop(void* ctx) {
|
|
||||||
PerseusSourceModule* _this = (PerseusSourceModule*)ctx;
|
|
||||||
if (!_this->running) { return; }
|
|
||||||
_this->running = false;
|
|
||||||
|
|
||||||
// Stop stream
|
|
||||||
_this->stream.stopWriter();
|
|
||||||
perseus_stop_async_input(_this->openDev);
|
|
||||||
_this->stream.clearWriteStop();
|
|
||||||
|
|
||||||
// Close device
|
|
||||||
perseus_close(_this->openDev);
|
|
||||||
|
|
||||||
flog::info("PerseusSourceModule '{0}': Stop!", _this->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void tune(double freq, void* ctx) {
|
|
||||||
PerseusSourceModule* _this = (PerseusSourceModule*)ctx;
|
|
||||||
if (_this->running) {
|
|
||||||
perseus_set_ddc_center_freq(_this->openDev, freq, _this->preselector);
|
|
||||||
}
|
|
||||||
_this->freq = freq;
|
|
||||||
flog::info("PerseusSourceModule '{0}': Tune: {1}!", _this->name, freq);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void menuHandler(void* ctx) {
|
|
||||||
PerseusSourceModule* _this = (PerseusSourceModule*)ctx;
|
|
||||||
|
|
||||||
if (_this->running) { SmGui::BeginDisabled(); }
|
|
||||||
|
|
||||||
SmGui::FillWidth();
|
|
||||||
SmGui::ForceSync();
|
|
||||||
if (SmGui::Combo(CONCAT("##_airspyhf_dev_sel_", _this->name), &_this->devId, _this->devList.txt)) {
|
|
||||||
std::string serial = _this->devList.key(_this->devId);
|
|
||||||
_this->select(serial);
|
|
||||||
config.acquire();
|
|
||||||
config.conf["device"] = serial;
|
|
||||||
config.release(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SmGui::Combo(CONCAT("##_airspyhf_sr_sel_", _this->name), &_this->srId, _this->srList.txt)) {
|
|
||||||
_this->sampleRate = _this->srList[_this->srId];
|
|
||||||
core::setInputSampleRate(_this->sampleRate);
|
|
||||||
if (!_this->selectedSerial.empty()) {
|
|
||||||
config.acquire();
|
|
||||||
config.conf["devices"][_this->selectedSerial]["samplerate"] = _this->sampleRate;
|
|
||||||
config.release(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SmGui::SameLine();
|
|
||||||
SmGui::FillWidth();
|
|
||||||
SmGui::ForceSync();
|
|
||||||
if (SmGui::Button(CONCAT("Refresh##_airspyhf_refr_", _this->name))) {
|
|
||||||
_this->refresh();
|
|
||||||
_this->select(_this->selectedSerial);
|
|
||||||
core::setInputSampleRate(_this->sampleRate);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_this->running) { SmGui::EndDisabled(); }
|
|
||||||
|
|
||||||
SmGui::LeftLabel("Attenuation");
|
|
||||||
SmGui::FillWidth();
|
|
||||||
if (SmGui::SliderFloatWithSteps(CONCAT("##_airspyhf_atten_", _this->name), &_this->atten, 0, 30, 10, SmGui::FMT_STR_FLOAT_DB_NO_DECIMAL)) {
|
|
||||||
if (_this->running) {
|
|
||||||
perseus_set_attenuator_in_db(_this->openDev, _this->atten);
|
|
||||||
}
|
|
||||||
if (!_this->selectedSerial.empty()) {
|
|
||||||
config.acquire();
|
|
||||||
config.conf["devices"][_this->selectedSerial]["attenuation"] = _this->atten;
|
|
||||||
config.release(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SmGui::Checkbox(CONCAT("Preamp##_airspyhf_preamp_", _this->name), &_this->preamp)) {
|
|
||||||
if (_this->running) {
|
|
||||||
perseus_set_adc(_this->openDev, _this->dithering, _this->preamp);
|
|
||||||
}
|
|
||||||
if (!_this->selectedSerial.empty()) {
|
|
||||||
config.acquire();
|
|
||||||
config.conf["devices"][_this->selectedSerial]["preamp"] = _this->preamp;
|
|
||||||
config.release(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SmGui::Checkbox(CONCAT("Dithering##_airspyhf_dither_", _this->name), &_this->dithering)) {
|
|
||||||
if (_this->running) {
|
|
||||||
perseus_set_adc(_this->openDev, _this->dithering, _this->preamp);
|
|
||||||
}
|
|
||||||
if (!_this->selectedSerial.empty()) {
|
|
||||||
config.acquire();
|
|
||||||
config.conf["devices"][_this->selectedSerial]["dithering"] = _this->dithering;
|
|
||||||
config.release(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SmGui::Checkbox(CONCAT("Preselector##_airspyhf_presel_", _this->name), &_this->preselector)) {
|
|
||||||
if (_this->running) {
|
|
||||||
perseus_set_ddc_center_freq(_this->openDev, _this->freq, _this->preselector);
|
|
||||||
}
|
|
||||||
if (!_this->selectedSerial.empty()) {
|
|
||||||
config.acquire();
|
|
||||||
config.conf["devices"][_this->selectedSerial]["preselector"] = _this->preselector;
|
|
||||||
config.release(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int callback(void* buf, int bufferSize, void* ctx) {
|
|
||||||
PerseusSourceModule* _this = (PerseusSourceModule*)ctx;
|
|
||||||
uint8_t* samples = (uint8_t*)buf;
|
|
||||||
int sampleCount = bufferSize / 6;
|
|
||||||
for (int i = 0; i < sampleCount; i++) {
|
|
||||||
int32_t re, im;
|
|
||||||
re = *(samples++);
|
|
||||||
re |= *(samples++) << 8;
|
|
||||||
re |= *(samples++) << 16;
|
|
||||||
re |= (re >> 23) * (0xFF << 24); // Sign extend
|
|
||||||
im = *(samples++);
|
|
||||||
im |= *(samples++) << 8;
|
|
||||||
im |= *(samples++) << 16;
|
|
||||||
im |= (im >> 23) * (0xFF << 24); // Sign extend
|
|
||||||
_this->stream.writeBuf[i].re = ((float)re / (float)0x7FFFFF);
|
|
||||||
_this->stream.writeBuf[i].im = ((float)im / (float)0x7FFFFF);
|
|
||||||
}
|
|
||||||
_this->stream.swap(sampleCount);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string name;
|
|
||||||
bool enabled = true;
|
|
||||||
dsp::stream<dsp::complex_t> stream;
|
|
||||||
int sampleRate;
|
|
||||||
SourceManager::SourceHandler handler;
|
|
||||||
bool running = false;
|
|
||||||
double freq;
|
|
||||||
int devId = 0;
|
|
||||||
int srId = 0;
|
|
||||||
bool libInit = false;
|
|
||||||
perseus_descr* openDev;
|
|
||||||
std::string selectedSerial = "";
|
|
||||||
int selectedPerseusId;
|
|
||||||
float atten = 0;
|
|
||||||
bool preamp = false;
|
|
||||||
bool dithering = false;
|
|
||||||
bool preselector = true;
|
|
||||||
|
|
||||||
OptionList<std::string, int> devList;
|
|
||||||
OptionList<int, int> srList;
|
|
||||||
};
|
|
||||||
|
|
||||||
MOD_EXPORT void _INIT_() {
|
|
||||||
json def = json({});
|
|
||||||
def["devices"] = json({});
|
|
||||||
def["device"] = "";
|
|
||||||
config.setPath(core::args["root"].s() + "/perseus_config.json");
|
|
||||||
config.load(def);
|
|
||||||
config.enableAutoSave();
|
|
||||||
}
|
|
||||||
|
|
||||||
MOD_EXPORT ModuleManager::Instance* _CREATE_INSTANCE_(std::string name) {
|
|
||||||
return new PerseusSourceModule(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
MOD_EXPORT void _DELETE_INSTANCE_(ModuleManager::Instance* instance) {
|
|
||||||
delete (PerseusSourceModule*)instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
MOD_EXPORT void _END_() {
|
|
||||||
config.disableAutoSave();
|
|
||||||
config.save();
|
|
||||||
}
|
|
@ -171,7 +171,7 @@ public:
|
|||||||
#ifndef __ANDROID__
|
#ifndef __ANDROID__
|
||||||
int oret = rtlsdr_open(&openDev, id);
|
int oret = rtlsdr_open(&openDev, id);
|
||||||
#else
|
#else
|
||||||
int oret = rtlsdr_open_sys_dev(&openDev, devFd);
|
int oret = rtlsdr_open_fd(&openDev, devFd);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (oret < 0) {
|
if (oret < 0) {
|
||||||
@ -285,7 +285,7 @@ private:
|
|||||||
#ifndef __ANDROID__
|
#ifndef __ANDROID__
|
||||||
int oret = rtlsdr_open(&_this->openDev, _this->devId);
|
int oret = rtlsdr_open(&_this->openDev, _this->devId);
|
||||||
#else
|
#else
|
||||||
int oret = rtlsdr_open_sys_dev(&_this->openDev, _this->devFd);
|
int oret = rtlsdr_open_fd(&_this->openDev, _this->devFd);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (oret < 0) {
|
if (oret < 0) {
|
||||||
@ -523,8 +523,8 @@ private:
|
|||||||
RTLSDRSourceModule* _this = (RTLSDRSourceModule*)ctx;
|
RTLSDRSourceModule* _this = (RTLSDRSourceModule*)ctx;
|
||||||
int sampCount = len / 2;
|
int sampCount = len / 2;
|
||||||
for (int i = 0; i < sampCount; i++) {
|
for (int i = 0; i < sampCount; i++) {
|
||||||
_this->stream.writeBuf[i].re = ((float)buf[i * 2] - 127.4) / 128.0f;
|
_this->stream.writeBuf[i].re = (float)(buf[i * 2] - 127) / 128.0f;
|
||||||
_this->stream.writeBuf[i].im = ((float)buf[(i * 2) + 1] - 127.4) / 128.0f;
|
_this->stream.writeBuf[i].im = (float)(buf[(i * 2) + 1] - 127) / 128.0f;
|
||||||
}
|
}
|
||||||
if (!_this->stream.swap(sampCount)) { return; }
|
if (!_this->stream.swap(sampCount)) { return; }
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ public:
|
|||||||
this->name = name;
|
this->name = name;
|
||||||
|
|
||||||
strcpy(hostname, "localhost");
|
strcpy(hostname, "localhost");
|
||||||
sampleRate = 5750000.0;
|
sampleRate = 41000000.0;
|
||||||
|
|
||||||
handler.ctx = this;
|
handler.ctx = this;
|
||||||
handler.selectHandler = menuSelected;
|
handler.selectHandler = menuSelected;
|
||||||
@ -103,14 +103,8 @@ private:
|
|||||||
|
|
||||||
static void tune(double freq, void* ctx) {
|
static void tune(double freq, void* ctx) {
|
||||||
SpectranHTTPSourceModule* _this = (SpectranHTTPSourceModule*)ctx;
|
SpectranHTTPSourceModule* _this = (SpectranHTTPSourceModule*)ctx;
|
||||||
bool connected = (_this->client && _this->client->isOpen());
|
if (_this->running) {
|
||||||
if (connected) {
|
// TODO
|
||||||
int64_t newfreq = round(freq);
|
|
||||||
if (newfreq != _this->lastReportedFreq && _this->gotReport) {
|
|
||||||
flog::debug("Sending tuning command");
|
|
||||||
_this->lastReportedFreq = newfreq;
|
|
||||||
_this->client->setCenterFrequency(newfreq);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_this->freq = freq;
|
_this->freq = freq;
|
||||||
flog::info("SpectranHTTPSourceModule '{0}': Tune: {1}!", _this->name, freq);
|
flog::info("SpectranHTTPSourceModule '{0}': Tune: {1}!", _this->name, freq);
|
||||||
@ -144,8 +138,6 @@ private:
|
|||||||
_this->tryConnect();
|
_this->tryConnect();
|
||||||
}
|
}
|
||||||
else if (connected && SmGui::Button("Disconnect##spectran_http_source")) {
|
else if (connected && SmGui::Button("Disconnect##spectran_http_source")) {
|
||||||
_this->client->onCenterFrequencyChanged.unbind(_this->onFreqChangedId);
|
|
||||||
_this->client->onCenterFrequencyChanged.unbind(_this->onSamplerateChangedId);
|
|
||||||
_this->client->close();
|
_this->client->close();
|
||||||
}
|
}
|
||||||
if (_this->running) { style::endDisabled(); }
|
if (_this->running) { style::endDisabled(); }
|
||||||
@ -162,28 +154,13 @@ private:
|
|||||||
|
|
||||||
void tryConnect() {
|
void tryConnect() {
|
||||||
try {
|
try {
|
||||||
gotReport = false;
|
|
||||||
client = std::make_shared<SpectranHTTPClient>(hostname, port, &stream);
|
client = std::make_shared<SpectranHTTPClient>(hostname, port, &stream);
|
||||||
onFreqChangedId = client->onCenterFrequencyChanged.bind(&SpectranHTTPSourceModule::onFreqChanged, this);
|
|
||||||
onSamplerateChangedId = client->onSamplerateChanged.bind(&SpectranHTTPSourceModule::onSamplerateChanged, this);
|
|
||||||
client->startWorker();
|
|
||||||
}
|
}
|
||||||
catch (std::runtime_error e) {
|
catch (std::runtime_error e) {
|
||||||
flog::error("Could not connect: {0}", e.what());
|
flog::error("Could not connect: {0}", e.what());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void onFreqChanged(double newFreq) {
|
|
||||||
if (lastReportedFreq == newFreq) { return; }
|
|
||||||
lastReportedFreq = newFreq;
|
|
||||||
tuner::tune(tuner::TUNER_MODE_IQ_ONLY, "", newFreq);
|
|
||||||
gotReport = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void onSamplerateChanged(double newSr) {
|
|
||||||
core::setInputSampleRate(newSr);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string name;
|
std::string name;
|
||||||
bool enabled = true;
|
bool enabled = true;
|
||||||
double sampleRate;
|
double sampleRate;
|
||||||
@ -191,16 +168,11 @@ private:
|
|||||||
bool running = false;
|
bool running = false;
|
||||||
|
|
||||||
std::shared_ptr<SpectranHTTPClient> client;
|
std::shared_ptr<SpectranHTTPClient> client;
|
||||||
HandlerID onFreqChangedId;
|
|
||||||
HandlerID onSamplerateChangedId;
|
|
||||||
|
|
||||||
double freq;
|
double freq;
|
||||||
|
|
||||||
int64_t lastReportedFreq = 0;
|
|
||||||
bool gotReport;
|
|
||||||
|
|
||||||
char hostname[1024];
|
char hostname[1024];
|
||||||
int port = 54664;
|
int port = 80;
|
||||||
dsp::stream<dsp::complex_t> stream;
|
dsp::stream<dsp::complex_t> stream;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -5,8 +5,6 @@ SpectranHTTPClient::SpectranHTTPClient(std::string host, int port, dsp::stream<d
|
|||||||
this->stream = stream;
|
this->stream = stream;
|
||||||
|
|
||||||
// Connect to server
|
// Connect to server
|
||||||
this->host = host;
|
|
||||||
this->port = port;
|
|
||||||
sock = net::connect(host, port);
|
sock = net::connect(host, port);
|
||||||
http = net::http::Client(sock);
|
http = net::http::Client(sock);
|
||||||
|
|
||||||
@ -16,13 +14,6 @@ SpectranHTTPClient::SpectranHTTPClient(std::string host, int port, dsp::stream<d
|
|||||||
net::http::ResponseHeader rshdr;
|
net::http::ResponseHeader rshdr;
|
||||||
http.recvResponseHeader(rshdr, 5000);
|
http.recvResponseHeader(rshdr, 5000);
|
||||||
|
|
||||||
if (rshdr.getStatusCode() != net::http::STATUS_CODE_OK) {
|
|
||||||
flog::error("HTTP request did not return ok: {}", rshdr.getStatusString());
|
|
||||||
throw std::runtime_error("HTTP request did not return ok");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SpectranHTTPClient::startWorker() {
|
|
||||||
// Start chunk worker
|
// Start chunk worker
|
||||||
workerThread = std::thread(&SpectranHTTPClient::worker, this);
|
workerThread = std::thread(&SpectranHTTPClient::worker, this);
|
||||||
}
|
}
|
||||||
@ -42,27 +33,6 @@ void SpectranHTTPClient::close() {
|
|||||||
stream->clearWriteStop();
|
stream->clearWriteStop();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpectranHTTPClient::setCenterFrequency(uint64_t freq) {
|
|
||||||
// Connect to control endpoint (TODO: Switch to an always connected endpoint)
|
|
||||||
auto controlSock = net::connect(host, port);
|
|
||||||
auto controlHttp = net::http::Client(controlSock);
|
|
||||||
|
|
||||||
// Make request
|
|
||||||
net::http::RequestHeader rqhdr(net::http::METHOD_PUT, "/control", host);
|
|
||||||
char buf[1024];
|
|
||||||
sprintf(buf, "{\"frequencyCenter\":%d,\"frequencySpan\":%d,\"type\":\"capture\"}", freq, _samplerate);
|
|
||||||
std::string data = buf;
|
|
||||||
char lenBuf[16];
|
|
||||||
sprintf(lenBuf, "%d", data.size());
|
|
||||||
rqhdr.setField("Content-Length", lenBuf);
|
|
||||||
controlHttp.sendRequestHeader(rqhdr);
|
|
||||||
controlSock->sendstr(data);
|
|
||||||
net::http::ResponseHeader rshdr;
|
|
||||||
controlHttp.recvResponseHeader(rshdr, 5000);
|
|
||||||
|
|
||||||
flog::debug("Response: {}", rshdr.getStatusString());
|
|
||||||
}
|
|
||||||
|
|
||||||
void SpectranHTTPClient::worker() {
|
void SpectranHTTPClient::worker() {
|
||||||
while (sock->isOpen()) {
|
while (sock->isOpen()) {
|
||||||
// Get chunk header
|
// Get chunk header
|
||||||
@ -82,41 +52,6 @@ void SpectranHTTPClient::worker() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decode JSON (yes, this is hacky, but it must be extremely fast)
|
|
||||||
auto startFreqBegin = jsonData.find("\"startFrequency\":");
|
|
||||||
auto startFreqEnd = jsonData.find(',', startFreqBegin);
|
|
||||||
std::string startFreqStr = jsonData.substr(startFreqBegin + 17, startFreqEnd - startFreqBegin - 17);
|
|
||||||
int64_t startFreq = std::stoll(startFreqStr);
|
|
||||||
|
|
||||||
auto endFreqBegin = jsonData.find("\"endFrequency\":");
|
|
||||||
auto endFreqEnd = jsonData.find(',', endFreqBegin);
|
|
||||||
std::string endFreqStr = jsonData.substr(endFreqBegin + 15, endFreqEnd - endFreqBegin - 15);
|
|
||||||
int64_t endFreq = std::stoll(endFreqStr);
|
|
||||||
|
|
||||||
auto sampleFreqBegin = jsonData.find("\"sampleFrequency\":");
|
|
||||||
bool sampleFreqReceived = (sampleFreqBegin != -1);
|
|
||||||
int64_t sampleFreq;
|
|
||||||
if (sampleFreqReceived) {
|
|
||||||
auto sampleFreqEnd = jsonData.find(',', sampleFreqBegin);
|
|
||||||
std::string sampleFreqStr = jsonData.substr(sampleFreqBegin + 18, sampleFreqEnd - sampleFreqBegin - 18);
|
|
||||||
sampleFreq = std::stoll(sampleFreqStr);
|
|
||||||
//flog::debug("{}", jsonData);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate and update center freq
|
|
||||||
int64_t samplerate = /* sampleFreqReceived ? sampleFreq : */(endFreq - startFreq);
|
|
||||||
int64_t centerFreq = round(((double)endFreq + (double)startFreq) / 2.0);
|
|
||||||
if (centerFreq != _centerFreq) {
|
|
||||||
flog::debug("New center freq: {}", centerFreq);
|
|
||||||
_centerFreq = centerFreq;
|
|
||||||
onCenterFrequencyChanged(centerFreq);
|
|
||||||
}
|
|
||||||
if (samplerate != _samplerate) {
|
|
||||||
flog::debug("New samplerate: {}", samplerate);
|
|
||||||
_samplerate = samplerate;
|
|
||||||
onSamplerateChanged(samplerate);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read (and check for) record separator
|
// Read (and check for) record separator
|
||||||
uint8_t rs;
|
uint8_t rs;
|
||||||
int rslen = sock->recv(&rs, 1, true, 5000);
|
int rslen = sock->recv(&rs, 1, true, 5000);
|
||||||
@ -137,11 +72,10 @@ void SpectranHTTPClient::worker() {
|
|||||||
i += read;
|
i += read;
|
||||||
sampLen += read;
|
sampLen += read;
|
||||||
}
|
}
|
||||||
int sampCount = sampLen / 8;
|
|
||||||
|
|
||||||
// Swap to stream
|
// Swap to stream
|
||||||
if (streamingEnabled) {
|
if (streamingEnabled) {
|
||||||
if (!stream->swap(sampCount)) { return; }
|
if (!stream->swap(sampLen / 8)) { return; }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read trailing CRLF
|
// Read trailing CRLF
|
||||||
|
@ -4,35 +4,22 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <utils/proto/http.h>
|
#include <utils/proto/http.h>
|
||||||
#include <utils/new_event.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
class SpectranHTTPClient {
|
class SpectranHTTPClient {
|
||||||
public:
|
public:
|
||||||
SpectranHTTPClient(std::string host, int port, dsp::stream<dsp::complex_t>* stream);
|
SpectranHTTPClient(std::string host, int port, dsp::stream<dsp::complex_t>* stream);
|
||||||
|
|
||||||
void startWorker();
|
|
||||||
void streaming(bool enabled);
|
void streaming(bool enabled);
|
||||||
bool isOpen();
|
bool isOpen();
|
||||||
void close();
|
void close();
|
||||||
|
|
||||||
void setCenterFrequency(uint64_t freq);
|
|
||||||
|
|
||||||
NewEvent<uint64_t> onCenterFrequencyChanged;
|
|
||||||
NewEvent<uint64_t> onSamplerateChanged;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void worker();
|
void worker();
|
||||||
|
|
||||||
std::string host;
|
|
||||||
int port;
|
|
||||||
|
|
||||||
std::shared_ptr<net::Socket> sock;
|
std::shared_ptr<net::Socket> sock;
|
||||||
net::http::Client http;
|
net::http::Client http;
|
||||||
dsp::stream<dsp::complex_t>* stream;
|
dsp::stream<dsp::complex_t>* stream;
|
||||||
std::thread workerThread;
|
std::thread workerThread;
|
||||||
|
|
||||||
bool streamingEnabled = false;
|
bool streamingEnabled = false;
|
||||||
int64_t _centerFreq = 0;
|
|
||||||
uint64_t _samplerate = 0;
|
|
||||||
};
|
};
|
Reference in New Issue
Block a user