mirror of
https://github.com/AlexandreRouma/SDRPlusPlus.git
synced 2025-07-09 10:35:21 +02:00
Compare commits
92 Commits
noise_redu
...
nightly
Author | SHA1 | Date | |
---|---|---|---|
052167962d | |||
6fc41a81a7 | |||
e710b6c6dc | |||
a91434c5fe | |||
ead2ac6128 | |||
505cbb0ba2 | |||
b1030cbdfb | |||
f3c5b2c31f | |||
794d6ff5ac | |||
4803271115 | |||
78daed7879 | |||
5f297b1a69 | |||
7c5d4226eb | |||
ec086ebbdf | |||
d10d420467 | |||
5bf989f49d | |||
4b3b6976d6 | |||
55ddd383d2 | |||
a043ab2dd3 | |||
d270e1c5e8 | |||
e41f24a95e | |||
766b3db363 | |||
0632342bb7 | |||
27b07ed0e8 | |||
a824c83848 | |||
0e50ee0e67 | |||
a55d1d9c06 | |||
97187b790f | |||
9c1361a8a9 | |||
4d0d14856b | |||
365ab2325e | |||
4da7e686f3 | |||
c1d9ab64f8 | |||
ea33135bf1 | |||
2081384905 | |||
6b31134af2 | |||
99d2786c25 | |||
320f4459ed | |||
de5816f79f | |||
7b9c01ec73 | |||
f06eccd97c | |||
88baa8a48e | |||
b436fd0745 | |||
6fa4299136 | |||
220dcbcc76 | |||
15ad065feb | |||
dddf84510e | |||
acd9ad9781 | |||
168e28cc44 | |||
3b9867c1d7 | |||
ff7ef78b8f | |||
87add9ad83 | |||
6cd09f9b60 | |||
8d05c1e181 | |||
1c081cad78 | |||
aa929a1e79 | |||
5acdab0d22 | |||
3e3846daa1 | |||
47617e1acd | |||
1df51020aa | |||
aa1fd9e573 | |||
21816fb438 | |||
3a06612ff5 | |||
a53bf05ed3 | |||
78c57db116 | |||
c16281f68a | |||
32c580ba57 | |||
664b5d85e2 | |||
6bcb62bfb2 | |||
0e7c754b8b | |||
71327cd695 | |||
f296730302 | |||
b89fdba433 | |||
2c3b522787 | |||
528763d10e | |||
582aeed640 | |||
9c0b57a036 | |||
604f95fd96 | |||
c892e51000 | |||
3336ae4aa5 | |||
190cea8e4e | |||
13a268a3e1 | |||
800a8b22c7 | |||
2eb030dd83 | |||
365fe1930c | |||
342a677c3f | |||
b5c41bcb3a | |||
f578adceef | |||
1e01313612 | |||
e64c343645 | |||
b9effce7d6 | |||
45a13227de |
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/"
|
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/"
|
||||||
|
|
||||||
- name: Download SDRPlay API
|
- name: Download SDRPlay API
|
||||||
run: Invoke-WebRequest -Uri "https://drive.google.com/uc?id=12UHPMwkfa67A11QZDmpCT4iwHnyJHWuu" -OutFile ${{runner.workspace}}/SDRPlay.zip
|
run: Invoke-WebRequest -Uri "https://drive.google.com/uc?id=12UHPMwkfa67A11QZDmpCT4iwHnyJHWuu&confirm=t" -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,14 +58,17 @@ 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
|
run: vcpkg install fftw3:x64-windows glfw3:x64-windows portaudio:x64-windows zstd:x64-windows libusb: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_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_PERSEUS_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
|
||||||
@ -93,11 +96,8 @@ 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 rtl-sdr libbladerf codec2 zstd && pip3 install mako
|
run: brew install pkg-config libusb fftw glfw airspy airspyhf portaudio hackrf libbladerf codec2 zstd autoconf automake libtool && 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: git clone https://github.com/analogdevicesinc/libiio && cd libiio && mkdir build && cd build && cmake -DCMAKE_BUILD_TYPE=Release .. && make -j3 && sudo make install && cd ../../
|
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 ../../
|
||||||
|
|
||||||
- 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,9 +114,15 @@ 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_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_PERSEUS_SOURCE=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
|
||||||
@ -176,6 +182,28 @@ 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
|
||||||
|
|
||||||
@ -198,28 +226,6 @@ 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
|
||||||
|
|
||||||
@ -275,7 +281,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
|
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
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
working-directory: ${{runner.workspace}}/build
|
working-directory: ${{runner.workspace}}/build
|
||||||
@ -319,7 +325,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_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_bookworm', '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:
|
||||||
@ -333,6 +339,7 @@ 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,24 +17,25 @@ 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_SDRPP_SERVER_SOURCE "Build SDR++ Server Source Module (no dependencies required)" ON)
|
option(OPT_BUILD_PERSEUS_SOURCE "Build Perseus Source Module (Dependencies: libperseus-sdr)" OFF)
|
||||||
|
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)
|
||||||
@ -141,9 +142,13 @@ 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_SDRPP_SERVER_SOURCE)
|
if (OPT_BUILD_PERSEUS_SOURCE)
|
||||||
add_subdirectory("source_modules/sdrpp_server_source")
|
add_subdirectory("source_modules/perseus_source")
|
||||||
endif (OPT_BUILD_SDRPP_SERVER_SOURCE)
|
endif (OPT_BUILD_PERSEUS_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")
|
||||||
@ -157,6 +162,10 @@ 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)
|
||||||
@ -177,10 +186,6 @@ 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,6 +1,7 @@
|
|||||||
# Pull Requests
|
# Pull Requests
|
||||||
|
|
||||||
TODO
|
**I DO NOT ACCEPT PULL-REQUEST FOR FEATURES OR BUGFIXES REQUIRING SIGNIFICANT CODE/STRUCTURE CHANGES.**
|
||||||
|
**SUCH PULL REQUESTS WILL BE CLOSED AUTOMATICALLY. OPEN AN ISSUE DETAILING FEATURE REQUESTS OR POTENTIAL BUGFIX INSTEAD.**
|
||||||
|
|
||||||
# Code Style
|
# Code Style
|
||||||
|
|
||||||
|
@ -108,7 +108,6 @@ 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,6 +117,10 @@ 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;
|
||||||
@ -177,6 +181,8 @@ 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,6 +12,7 @@ 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",
|
||||||
@ -21,7 +22,6 @@ 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); }
|
||||||
|
|
||||||
static inline int process(int count, const stereo_t* in, float* out) {
|
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;
|
||||||
}
|
}
|
||||||
|
@ -1,183 +0,0 @@
|
|||||||
#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,17 +37,21 @@ 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 and pass value if null
|
// Get signal amplitude
|
||||||
float inAmp = in[i].amplitude();
|
float inAmp = in[i].amplitude();
|
||||||
if (!inAmp) {
|
|
||||||
out[i] = in[i];
|
// Update average amplitude
|
||||||
|
float gain = 1.0f;
|
||||||
|
if (inAmp != 0.0f) {
|
||||||
|
amp = (amp * _invRate) + (inAmp * _rate);
|
||||||
|
float excess = inAmp / amp;
|
||||||
|
if (excess > _level) {
|
||||||
|
gain = 1.0f / excess;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update running average of amplitude
|
// Scale output by gain
|
||||||
amp = (_rate*inAmp) + (_invRate*amp);
|
out[i] = in[i] * gain;
|
||||||
|
|
||||||
// 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(re);
|
float im_abs = fabsf(im);
|
||||||
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,10 +574,22 @@ 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 + (vfo->snapInterval * wheel);
|
nfreq = gui::waterfall.getCenterFrequency() + vfo->generalOffset + (interval * wheel);
|
||||||
nfreq = roundl(nfreq / vfo->snapInterval) * vfo->snapInterval;
|
nfreq = roundl(nfreq / interval) * interval;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
nfreq = gui::waterfall.getCenterFrequency() - (gui::waterfall.getViewBandwidth() * wheel / 20.0);
|
nfreq = gui::waterfall.getCenterFrequency() - (gui::waterfall.getViewBandwidth() * wheel / 20.0);
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#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;
|
||||||
@ -22,6 +23,10 @@ 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;
|
||||||
|
|
||||||
@ -57,8 +62,10 @@ namespace displaymenu {
|
|||||||
IQFrontEnd::FFTWindow::NUTTALL
|
IQFrontEnd::FFTWindow::NUTTALL
|
||||||
};
|
};
|
||||||
|
|
||||||
void updateFFTHoldSpeed() {
|
void updateFFTSpeeds() {
|
||||||
gui::waterfall.setFFTHoldSpeed(fftHoldSpeed / (fftRate * 10.0f));
|
gui::waterfall.setFFTHoldSpeed((float)fftHoldSpeed / ((float)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() {
|
||||||
@ -104,7 +111,13 @@ 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);
|
||||||
updateFFTHoldSpeed();
|
fftSmoothing = core::configManager.conf["fftSmoothing"];
|
||||||
|
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);
|
||||||
@ -144,16 +157,47 @@ 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)) {
|
||||||
updateFFTHoldSpeed();
|
updateFFTSpeeds();
|
||||||
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)) {
|
||||||
@ -168,7 +212,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);
|
||||||
updateFFTHoldSpeed();
|
updateFFTSpeeds();
|
||||||
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,4 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include <stdint.h>
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -689,6 +689,7 @@ 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;
|
||||||
@ -740,14 +741,23 @@ 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.0; // Hide everything
|
latestFFT[i] = -1000.0f; // Hide everything
|
||||||
latestFFTHold[i] = -1000.0;
|
latestFFTHold[i] = -1000.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
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));
|
||||||
@ -873,9 +883,25 @@ 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;
|
||||||
calculateVFOSignalInfo(waterfallVisible ? &rawFFTs[currentFFTLine * rawFFTSize] : rawFFTs, vfos[selectedVFO], dummy, selectedVFOSNR);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If FFT hold is enabled, update it
|
// If FFT hold is enabled, update it
|
||||||
@ -1110,6 +1136,45 @@ 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,6 +169,12 @@ 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();
|
||||||
|
|
||||||
@ -182,7 +188,7 @@ namespace ImGui {
|
|||||||
bool mouseInFFT = false;
|
bool mouseInFFT = false;
|
||||||
bool mouseInWaterfall = false;
|
bool mouseInWaterfall = false;
|
||||||
|
|
||||||
float selectedVFOSNR = NAN;
|
float selectedVFOSNR = 0.0f;
|
||||||
|
|
||||||
bool centerFrequencyLocked = false;
|
bool centerFrequencyLocked = false;
|
||||||
|
|
||||||
@ -270,6 +276,7 @@ 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;
|
||||||
|
|
||||||
@ -304,8 +311,9 @@ 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;
|
float* latestFFT = NULL;
|
||||||
float* latestFFTHold;
|
float* latestFFTHold = NULL;
|
||||||
|
float* smoothingBuf = NULL;
|
||||||
int currentFFTLine = 0;
|
int currentFFTLine = 0;
|
||||||
int fftLines = 0;
|
int fftLines = 0;
|
||||||
|
|
||||||
@ -325,6 +333,14 @@ 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}.", path);
|
flog::error("Couldn't load {0}: {1}", path, dlerror());
|
||||||
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::mutex> lck(mtx);
|
std::lock_guard<std::recursive_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::mutex> lck(mtx);
|
std::lock_guard<std::recursive_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::mutex> lck(mtx);
|
std::lock_guard<std::recursive_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::mutex> lck(mtx);
|
std::lock_guard<std::recursive_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::mutex> lck(mtx);
|
std::lock_guard<std::recursive_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::mutex mtx;
|
std::recursive_mutex mtx;
|
||||||
std::map<std::string, ModuleComInterface> interfaces;
|
std::map<std::string, ModuleComInterface> interfaces;
|
||||||
};
|
};
|
@ -1,6 +1,7 @@
|
|||||||
#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,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <string>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
52
core/src/utils/new_event.h
Normal file
52
core/src/utils/new_event.h
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
#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
|
// If parent chunk, increment its size by the size of the sub-chunk plus the size of its header)
|
||||||
if (!chunks.empty()) {
|
if (!chunks.empty()) {
|
||||||
chunks.top().hdr.size += desc.hdr.size;
|
chunks.top().hdr.size += desc.hdr.size + sizeof(ChunkHeader);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,10 +57,13 @@ 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, 150000, INPUT_SAMPLE_RATE, 150000, 150000, true);
|
vfo = sigpath::vfoManager.createVFO(name, ImGui::WaterfallVFO::REF_CENTER, 0, INPUT_SAMPLE_RATE, INPUT_SAMPLE_RATE, INPUT_SAMPLE_RATE, INPUT_SAMPLE_RATE, true);
|
||||||
demod.init(vfo->output, 72000.0f, INPUT_SAMPLE_RATE, 33, 0.6f, 0.1f, 0.005f, brokenModulation, 1e-6, 0.01);
|
demod.init(vfo->output, 72000.0f, INPUT_SAMPLE_RATE, 33, 0.6f, 0.1f, 0.005f, brokenModulation, oqpsk, 1e-6, 0.01);
|
||||||
split.init(&demod.out);
|
split.init(&demod.out);
|
||||||
split.bindStream(&symSinkStream);
|
split.bindStream(&symSinkStream);
|
||||||
split.bindStream(&sinkStream);
|
split.bindStream(&sinkStream);
|
||||||
@ -99,6 +102,7 @@ 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();
|
||||||
@ -151,6 +155,13 @@ 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) {
|
||||||
@ -245,7 +256,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, 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, bool oqpsk, double omegaGain, double muGain, double omegaRelLimit = 0.01) {
|
||||||
init(in, symbolrate, samplerate, rrcTapCount, rrcBeta, agcRate, costasBandwidth, brokenModulation, omegaGain, muGain);
|
init(in, symbolrate, samplerate, rrcTapCount, rrcBeta, agcRate, costasBandwidth, brokenModulation, oqpsk, omegaGain, muGain);
|
||||||
}
|
}
|
||||||
|
|
||||||
~Meteor() {
|
~Meteor() {
|
||||||
@ -21,11 +21,12 @@ 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, 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, bool oqpsk, 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);
|
||||||
@ -129,6 +130,12 @@ 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);
|
||||||
@ -144,6 +151,18 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,6 +185,8 @@ 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,7 +45,6 @@ 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,7 +86,6 @@ 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,7 +92,6 @@ 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,7 +79,6 @@ 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,7 +79,6 @@ 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,7 +75,6 @@ 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,7 +59,6 @@ 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,7 +80,6 @@ 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,7 +130,6 @@ 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,7 +9,6 @@
|
|||||||
#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>
|
||||||
@ -84,11 +83,9 @@ 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;
|
||||||
@ -250,12 +247,6 @@ 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)) {
|
||||||
@ -379,8 +370,6 @@ 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();
|
||||||
@ -422,9 +411,6 @@ 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
|
||||||
@ -460,10 +446,7 @@ 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(deempAllowed ? deempModes[deempId] : DEEMP_MODE_NONE);
|
setDeemphasisMode(deempModes[deempId]);
|
||||||
|
|
||||||
// Configure AF NR
|
|
||||||
setAFNREnabled(afNRAllowed && afNREnabled);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Disable everything if post processing is disabled
|
// Disable everything if post processing is disabled
|
||||||
@ -525,17 +508,6 @@ 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; }
|
||||||
@ -688,7 +660,6 @@ 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;
|
||||||
|
|
||||||
@ -712,9 +683,6 @@ 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;
|
||||||
|
4
docker_builds/debian_bookworm/Dockerfile
Normal file
4
docker_builds/debian_bookworm/Dockerfile
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
FROM debian:bookworm
|
||||||
|
ENV DEBIAN_FRONTEND=noninteractive
|
||||||
|
COPY do_build.sh /root
|
||||||
|
RUN chmod +x /root/do_build.sh
|
35
docker_builds/debian_bookworm/do_build.sh
Normal file
35
docker_builds/debian_bookworm/do_build.sh
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#!/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
|
libcodec2-dev autoconf libtool xxd
|
||||||
|
|
||||||
# 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,10 +15,20 @@ 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
|
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
|
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
|
libcodec2-dev autoconf libtool xxd
|
||||||
|
|
||||||
# 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,10 +15,20 @@ 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
|
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
|
||||||
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 libvolk2-dev libzstd-dev libsoapysdr-dev libairspyhf-dev libairspy-dev \
|
apt install -y build-essential cmake git libfftw3-dev libglfw3-dev libvolk-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
|
libcodec2-dev autoconf libtool xxd
|
||||||
|
|
||||||
# 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,11 +15,21 @@ 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
|
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
|
make VERBOSE=1 -j2
|
||||||
|
|
||||||
cd ..
|
cd ..
|
||||||
sh make_debian_package.sh ./build 'libfftw3-dev, libglfw3-dev, libvolk2-dev, librtaudio-dev, libzstd-dev'
|
sh make_debian_package.sh ./build 'libfftw3-dev, libglfw3-dev, libvolk-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
|
libcodec2-dev libudev-dev autoconf libtool xxd
|
||||||
|
|
||||||
# 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,6 +41,16 @@ 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
|
||||||
@ -56,7 +66,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
|
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
|
||||||
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
|
libcodec2-dev autoconf libtool xxd
|
||||||
|
|
||||||
# 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,10 +15,20 @@ 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
|
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
|
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
|
libcodec2-dev autoconf libtool xxd
|
||||||
|
|
||||||
# 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,10 +15,20 @@ 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
|
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
|
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
|
return -1
|
||||||
done
|
done
|
||||||
|
|
||||||
# Search other common paths
|
# Search other common paths
|
||||||
|
@ -38,6 +38,7 @@ 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
|
||||||
@ -62,6 +63,7 @@ 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,6 +32,9 @@ 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,3 +6,4 @@ 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,6 +21,7 @@
|
|||||||
#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())
|
||||||
|
|
||||||
@ -168,7 +169,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) ? gui::waterfall.selectedVFO : "";
|
std::string vfoName = (recMode == RECORDER_MODE_AUDIO) ? selectedStreamName : "";
|
||||||
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)) {
|
||||||
@ -437,6 +438,17 @@ 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);
|
||||||
@ -455,6 +467,7 @@ 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);
|
||||||
@ -462,6 +475,11 @@ 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);
|
||||||
@ -472,6 +490,7 @@ 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,6 +333,17 @@ 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;
|
||||||
@ -442,38 +453,18 @@ 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());
|
||||||
|
|
||||||
int newMode;
|
auto it = std::find_if(radioModeToString.begin(), radioModeToString.end(), [&newModeStr](const auto& e) {
|
||||||
if (parts[1] == "FM") {
|
return e.second == newModeStr;
|
||||||
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) {
|
||||||
@ -492,31 +483,9 @@ 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 (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";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else if (!selectedVfo.empty()) {
|
||||||
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 {
|
||||||
@ -690,6 +659,11 @@ 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 libsoapysdr-dev libairspyhf-dev libiio-dev libad9361-dev librtaudio-dev libhackrf-dev
|
sudo apt install libfftw3-dev libglfw3-dev libvolk2-dev libzstd-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,7 +52,9 @@ If `libvolk2-dev` is not available, use `libvolk1-dev`.
|
|||||||
|
|
||||||
### Arch-based
|
### Arch-based
|
||||||
|
|
||||||
Install the latest release from the [sdrpp-git](https://aur.archlinux.org/packages/sdrpp-git/) AUR package
|
Install from source following the instructions below.
|
||||||
|
|
||||||
|
**WARNING: The sdrpp-git AUR package is no longer official, it is not recommended to use it.**
|
||||||
|
|
||||||
### Other
|
### Other
|
||||||
|
|
||||||
@ -74,7 +76,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)
|
* [PothosSDR](https://github.com/pothosware/PothosSDR) (This will install libraries for most SDRs. You have to install it in `C:/Program Files/PothosSDR`)
|
||||||
* [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:
|
||||||
@ -113,16 +115,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 -s
|
./build/Release/sdrpp.exe -r root_dev -c
|
||||||
```
|
```
|
||||||
|
|
||||||
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 -s
|
./sdrpp.exe -r ../../root_dev -c
|
||||||
```
|
```
|
||||||
|
|
||||||
The optional `-s` argument is for keeping the console active in order to see the error messages.
|
The optional `-c` 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.
|
||||||
@ -302,7 +304,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_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_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
|
||||||
make -j<N>
|
make -j<N>
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -327,11 +329,12 @@ 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 | ✅ | ✅ | ✅ |
|
||||||
@ -348,7 +351,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_audio_sink | Working | - | OPT_BUILD_ANDROID_AUDIO_SINK | ⛔ | ✅ | ✅ (Android only) |
|
||||||
| 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 | ⛔ | ✅ | ⛔ |
|
||||||
@ -374,9 +377,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
|
||||||
@ -470,6 +473,7 @@ 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)
|
||||||
@ -479,7 +483,6 @@ 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,6 +149,12 @@
|
|||||||
"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",
|
||||||
|
@ -115,7 +115,7 @@
|
|||||||
"end": 4995000
|
"end": 4995000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "60m - radiodiffusion",
|
"name": "60m - radiodiffusion",
|
||||||
"type": "broadcast",
|
"type": "broadcast",
|
||||||
"start": 5005000,
|
"start": 5005000,
|
||||||
"end": 5060000
|
"end": 5060000
|
||||||
@ -340,7 +340,7 @@
|
|||||||
"name": "11m - CB",
|
"name": "11m - CB",
|
||||||
"type": "amateur",
|
"type": "amateur",
|
||||||
"start": 26960000,
|
"start": 26960000,
|
||||||
"end": 27230000
|
"end": 27410000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"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": "Tobias Mädel",
|
"author_name": "Manawyrm",
|
||||||
"author_url": "https://tbspace.de",
|
"author_url": "https://tbspace.de",
|
||||||
"bands": [
|
"bands": [
|
||||||
{
|
{
|
||||||
|
3177
root/res/bandplans/netherlands.json
Normal file
3177
root/res/bandplans/netherlands.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -529,9 +529,9 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Train communications",
|
"name": "Train communications",
|
||||||
"type": "aviation",
|
"type": "railway",
|
||||||
"start": 151775000,
|
"start": 151712500,
|
||||||
"end": 151875000
|
"end": 156012500
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Marine",
|
"name": "Marine",
|
||||||
@ -557,12 +557,6 @@
|
|||||||
"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,6 +5,12 @@
|
|||||||
"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",
|
||||||
@ -209,18 +215,18 @@
|
|||||||
"start": 15010000,
|
"start": 15010000,
|
||||||
"end": 15100000
|
"end": 15100000
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "Maritime",
|
|
||||||
"type": "marine",
|
|
||||||
"start": 16360000,
|
|
||||||
"end": 17410000
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "19m Broadcast",
|
"name": "19m Broadcast",
|
||||||
"type": "broadcast",
|
"type": "broadcast",
|
||||||
"start": 15100000,
|
"start": 15100000,
|
||||||
"end": 15800000
|
"end": 15800000
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "Maritime",
|
||||||
|
"type": "marine",
|
||||||
|
"start": 16360000,
|
||||||
|
"end": 17410000
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "16m Broadcast",
|
"name": "16m Broadcast",
|
||||||
"type": "broadcast",
|
"type": "broadcast",
|
||||||
@ -345,7 +351,7 @@
|
|||||||
"name": "Air Band TACAN/ILS",
|
"name": "Air Band TACAN/ILS",
|
||||||
"type": "aviation",
|
"type": "aviation",
|
||||||
"start": 108000000,
|
"start": 108000000,
|
||||||
"end": 118000000
|
"end": 117975000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Air Band Voice",
|
"name": "Air Band Voice",
|
||||||
@ -371,6 +377,12 @@
|
|||||||
"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",
|
||||||
@ -425,6 +437,18 @@
|
|||||||
"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",
|
||||||
@ -462,22 +486,34 @@
|
|||||||
"end": 455000000
|
"end": 455000000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Private Mobile Radio",
|
"name": "Private Mobile Radio inc OB",
|
||||||
"type": "PMR",
|
"type": "PMR",
|
||||||
"start": 455000000,
|
"start": 455000000,
|
||||||
"end": 467200000
|
"end": 470000000
|
||||||
},
|
|
||||||
{
|
|
||||||
"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": 790000000
|
"end": 700000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"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",
|
||||||
@ -485,12 +521,84 @@
|
|||||||
"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",
|
||||||
@ -498,10 +606,28 @@
|
|||||||
"end": 2302000000
|
"end": 2302000000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "13cm Ham Band",
|
"name": "ISM - wifi and bluettoth",
|
||||||
"type": "amateur",
|
"type": "ISM",
|
||||||
"start": 2310000000,
|
"start": 2400000000,
|
||||||
"end": 2450000000
|
"end": 2483000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"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,6 +227,18 @@
|
|||||||
"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",
|
||||||
|
14
root/res/colormaps/smoke.json
Normal file
14
root/res/colormaps/smoke.json
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"name": "Smoke",
|
||||||
|
"author": "Yaroslav Andrianov",
|
||||||
|
"map": [
|
||||||
|
"#FFFFFF",
|
||||||
|
"#EEEEEE",
|
||||||
|
"#CCCCCC",
|
||||||
|
"#777777",
|
||||||
|
"#555555",
|
||||||
|
"#333333",
|
||||||
|
"#111111",
|
||||||
|
"#000000"
|
||||||
|
]
|
||||||
|
}
|
28
root/res/colormaps/temper_colors.json
Normal file
28
root/res/colormaps/temper_colors.json
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"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"
|
||||||
|
]
|
||||||
|
}
|
29
root/res/colormaps/vivid.json
Normal file
29
root/res/colormaps/vivid.json
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"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"
|
||||||
|
]
|
||||||
|
}
|
@ -1,22 +0,0 @@
|
|||||||
#!/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,16 +45,20 @@ 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++) {
|
||||||
info = audio.getDeviceInfo(i);
|
try {
|
||||||
if (!info.probed) { continue; }
|
info = audio.getDeviceInfo(i);
|
||||||
if (info.outputChannels == 0) { continue; }
|
if (!info.probed) { continue; }
|
||||||
if (info.isDefaultOutput) { defaultDevId = devList.size(); }
|
if (info.outputChannels == 0) { continue; }
|
||||||
devList.push_back(info);
|
if (info.isDefaultOutput) { defaultDevId = devList.size(); }
|
||||||
deviceIds.push_back(i);
|
devList.push_back(info);
|
||||||
txtDevList += info.name;
|
deviceIds.push_back(i);
|
||||||
txtDevList += '\0';
|
txtDevList += info.name;
|
||||||
|
txtDevList += '\0';
|
||||||
|
}
|
||||||
|
catch (std::exception e) {
|
||||||
|
flog::error("AudioSinkModule Error getting audio device info: {0}", e.what());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
selectByName(device);
|
selectByName(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
#define NOMINMAX
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
#include <utils/flog.h>
|
#include <utils/flog.h>
|
||||||
#include <module.h>
|
#include <module.h>
|
||||||
@ -9,6 +10,8 @@
|
|||||||
#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())
|
||||||
|
|
||||||
@ -121,6 +124,12 @@ 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();
|
||||||
@ -130,7 +139,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();
|
||||||
@ -144,8 +153,8 @@ private:
|
|||||||
|
|
||||||
static void worker(void* ctx) {
|
static void worker(void* ctx) {
|
||||||
FileSourceModule* _this = (FileSourceModule*)ctx;
|
FileSourceModule* _this = (FileSourceModule*)ctx;
|
||||||
double sampleRate = _this->reader->getSampleRate();
|
double sampleRate = std::max(_this->reader->getSampleRate(), (uint32_t)1);
|
||||||
int blockSize = sampleRate / 200.0f;
|
int blockSize = std::min((int)(sampleRate / 200.0f), (int)STREAM_BUFFER_SIZE);
|
||||||
int16_t* inBuf = new int16_t[blockSize * 2];
|
int16_t* inBuf = new int16_t[blockSize * 2];
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
@ -159,8 +168,8 @@ private:
|
|||||||
|
|
||||||
static void floatWorker(void* ctx) {
|
static void floatWorker(void* ctx) {
|
||||||
FileSourceModule* _this = (FileSourceModule*)ctx;
|
FileSourceModule* _this = (FileSourceModule*)ctx;
|
||||||
double sampleRate = _this->reader->getSampleRate();
|
double sampleRate = std::max(_this->reader->getSampleRate(), (uint32_t)1);
|
||||||
int blockSize = sampleRate / 200.0f;
|
int blockSize = std::min((int)(sampleRate / 200.0f), (int)STREAM_BUFFER_SIZE);
|
||||||
dsp::complex_t* inBuf = new dsp::complex_t[blockSize];
|
dsp::complex_t* inBuf = new dsp::complex_t[blockSize];
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
|
@ -137,6 +137,10 @@ 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';
|
||||||
|
29
source_modules/perseus_source/CMakeLists.txt
Normal file
29
source_modules/perseus_source/CMakeLists.txt
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
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 ()
|
468
source_modules/perseus_source/src/main.cpp
Normal file
468
source_modules/perseus_source/src/main.cpp
Normal file
@ -0,0 +1,468 @@
|
|||||||
|
#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_fd(&openDev, devFd);
|
int oret = rtlsdr_open_sys_dev(&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_fd(&_this->openDev, _this->devFd);
|
int oret = rtlsdr_open_sys_dev(&_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) / 128.0f;
|
_this->stream.writeBuf[i].re = ((float)buf[i * 2] - 127.4) / 128.0f;
|
||||||
_this->stream.writeBuf[i].im = (float)(buf[(i * 2) + 1] - 127) / 128.0f;
|
_this->stream.writeBuf[i].im = ((float)buf[(i * 2) + 1] - 127.4) / 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 = 41000000.0;
|
sampleRate = 5750000.0;
|
||||||
|
|
||||||
handler.ctx = this;
|
handler.ctx = this;
|
||||||
handler.selectHandler = menuSelected;
|
handler.selectHandler = menuSelected;
|
||||||
@ -103,8 +103,14 @@ private:
|
|||||||
|
|
||||||
static void tune(double freq, void* ctx) {
|
static void tune(double freq, void* ctx) {
|
||||||
SpectranHTTPSourceModule* _this = (SpectranHTTPSourceModule*)ctx;
|
SpectranHTTPSourceModule* _this = (SpectranHTTPSourceModule*)ctx;
|
||||||
if (_this->running) {
|
bool connected = (_this->client && _this->client->isOpen());
|
||||||
// TODO
|
if (connected) {
|
||||||
|
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);
|
||||||
@ -138,6 +144,8 @@ 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(); }
|
||||||
@ -154,13 +162,28 @@ 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;
|
||||||
@ -168,11 +191,16 @@ 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 = 80;
|
int port = 54664;
|
||||||
dsp::stream<dsp::complex_t> stream;
|
dsp::stream<dsp::complex_t> stream;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -5,6 +5,8 @@ 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);
|
||||||
|
|
||||||
@ -14,6 +16,13 @@ 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);
|
||||||
}
|
}
|
||||||
@ -33,6 +42,27 @@ 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
|
||||||
@ -52,6 +82,41 @@ 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);
|
||||||
@ -72,10 +137,11 @@ 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(sampLen / 8)) { return; }
|
if (!stream->swap(sampCount)) { return; }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read trailing CRLF
|
// Read trailing CRLF
|
||||||
|
@ -4,22 +4,35 @@
|
|||||||
#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