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