mirror of
https://github.com/AlexandreRouma/SDRPlusPlus.git
synced 2026-04-20 07:12:43 +00:00
Compare commits
6 Commits
6fa945333c
...
better_ins
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eb19f193bc | ||
|
|
7336b19bee | ||
|
|
f9feec0abf | ||
|
|
4113e92759 | ||
|
|
d905d19020 | ||
|
|
d5bc0fa3c3 |
277
.github/workflows/build_all.yml
vendored
277
.github/workflows/build_all.yml
vendored
@@ -50,7 +50,7 @@ jobs:
|
|||||||
run: 7z x ${{runner.workspace}}/SDRplay.zip -o"C:/Program Files/"
|
run: 7z x ${{runner.workspace}}/SDRplay.zip -o"C:/Program Files/"
|
||||||
|
|
||||||
- name: Download codec2
|
- name: Download codec2
|
||||||
run: git clone https://github.com/drowe67/codec2
|
run: git clone https://github.com/AlexandreRouma/codec2
|
||||||
|
|
||||||
- name: Prepare MinGW
|
- name: Prepare MinGW
|
||||||
run: C:/msys64/msys2_shell.cmd -defterm -here -no-start -mingw64 -c "pacman --noconfirm -S --needed base-devel mingw-w64-x86_64-toolchain mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja"
|
run: C:/msys64/msys2_shell.cmd -defterm -here -no-start -mingw64 -c "pacman --noconfirm -S --needed base-devel mingw-w64-x86_64-toolchain mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja"
|
||||||
@@ -71,20 +71,14 @@ jobs:
|
|||||||
run: git clone https://github.com/thestk/rtaudio ; cd rtaudio ; git checkout 2f2fca4502d506abc50f6d4473b2836d24cfb1e3 ; mkdir build ; cd build ; cmake .. ; cmake --build . --config Release ; cmake --install .
|
run: git clone https://github.com/thestk/rtaudio ; cd rtaudio ; git checkout 2f2fca4502d506abc50f6d4473b2836d24cfb1e3 ; mkdir build ; cd build ; cmake .. ; cmake --build . --config Release ; cmake --install .
|
||||||
|
|
||||||
- name: Install libperseus-sdr
|
- name: Install libperseus-sdr
|
||||||
run: git clone https://github.com/AlexandreRouma/libperseus-sdr ; cd libperseus-sdr ; mkdir build ; cd build ; cmake -DCMAKE_BUILD_TYPE=Release "-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"
|
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: Install librfnm
|
- name: Install librfnm
|
||||||
run: git clone https://github.com/AlexandreRouma/librfnm ; cd librfnm ; mkdir build ; cd build ; cmake .. -DCMAKE_BUILD_TYPE=Release "-DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake" ; cmake --build . --config Release ; cmake --install .
|
run: git clone https://github.com/AlexandreRouma/librfnm ; cd librfnm ; mkdir build ; cd build ; cmake .. "-DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake" ; cmake --build . --config Release ; cmake --install .
|
||||||
|
|
||||||
- name: Install libfobos
|
|
||||||
run: git clone https://github.com/AlexandreRouma/libfobos ; cd libfobos ; mkdir build ; cd build ; cmake .. -DCMAKE_BUILD_TYPE=Release "-DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake" ; cmake --build . --config Release ; cmake --install .
|
|
||||||
|
|
||||||
- name: Install libhydrasdr
|
|
||||||
run: git clone https://github.com/hydrasdr/rfone_host; cd rfone_host/ ; mkdir build ; cd build ; cmake .. -DCMAKE_BUILD_TYPE=Release "-DLIBUSB_LIBRARIES=C:\Program Files\PothosSDR\lib\libusb-1.0.lib" "-DLIBUSB_INCLUDE_DIR=C:\Program Files\PothosSDR\include\libusb-1.0" "-DTHREADS_PTHREADS_WIN32_LIBRARY=C:\Program Files\PothosSDR\lib\pthreadVC2.lib" "-DTHREADS_PTHREADS_INCLUDE_DIR=C:\Program Files\PothosSDR\include" ; cmake --build . --config Release ; cmake --install .
|
|
||||||
|
|
||||||
- name: Prepare CMake
|
- name: Prepare CMake
|
||||||
working-directory: ${{runner.workspace}}/build
|
working-directory: ${{runner.workspace}}/build
|
||||||
run: cmake -DCOPY_MSVC_REDISTRIBUTABLES=ON "$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 -DOPT_BUILD_RFNM_SOURCE=ON -DOPT_BUILD_FOBOSSDR_SOURCE=ON -DOPT_BUILD_HYDRASDR_SOURCE=ON
|
run: cmake -DCOPY_MSVC_REDISTRIBUTABLES=ON "$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 -DOPT_BUILD_RFNM_SOURCE=ON
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
working-directory: ${{runner.workspace}}/build
|
working-directory: ${{runner.workspace}}/build
|
||||||
@@ -101,7 +95,7 @@ jobs:
|
|||||||
path: ${{runner.workspace}}/sdrpp_windows_x64.zip
|
path: ${{runner.workspace}}/sdrpp_windows_x64.zip
|
||||||
|
|
||||||
build_macos_intel:
|
build_macos_intel:
|
||||||
runs-on: macos-15-intel
|
runs-on: macos-12
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
@@ -110,7 +104,7 @@ jobs:
|
|||||||
run: cmake -E make_directory ${{runner.workspace}}/build
|
run: cmake -E make_directory ${{runner.workspace}}/build
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: brew install pkg-config libusb fftw glfw airspy airspyhf portaudio hackrf libbladerf codec2 zstd autoconf automake libtool spdlog && pip3 install mako --break-system-packages
|
run: brew install pkg-config libusb fftw glfw airspy airspyhf portaudio hackrf libbladerf codec2 zstd autoconf automake libtool spdlog && pip3 install mako
|
||||||
|
|
||||||
- name: Install volk
|
- name: Install volk
|
||||||
run: git clone --recursive https://github.com/gnuradio/volk && cd volk && mkdir build && cd build && cmake -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15 -DCMAKE_BUILD_TYPE=Release .. && make -j3 && sudo make install && cd ../../
|
run: git clone --recursive https://github.com/gnuradio/volk && cd volk && mkdir build && cd build && cmake -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15 -DCMAKE_BUILD_TYPE=Release .. && make -j3 && sudo make install && cd ../../
|
||||||
@@ -122,7 +116,7 @@ jobs:
|
|||||||
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_OSX_DEPLOYMENT_TARGET=10.15 -DCMAKE_BUILD_TYPE=Release .. && make -j3 && sudo make install && cd ../../
|
run: wget https://github.com/analogdevicesinc/libiio/archive/refs/tags/v0.25.zip && 7z x v0.25.zip && cd libiio-0.25 && mkdir build && cd build && cmake -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15 -DCMAKE_BUILD_TYPE=Release .. && make -j3 && sudo make install && cd ../../
|
||||||
|
|
||||||
- name: Install libad9361
|
- name: Install libad9361
|
||||||
run: git clone https://github.com/analogdevicesinc/libad9361-iio && cd libad9361-iio && mkdir build && cd build && cmake -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15 -DCMAKE_BUILD_TYPE=Release -DCMAKE_POLICY_VERSION_MINIMUM=3.5 .. && make -j3 && sudo make install && cd ../../
|
run: git clone https://github.com/analogdevicesinc/libad9361-iio && cd libad9361-iio && mkdir build && cd build && cmake -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15 -DCMAKE_BUILD_TYPE=Release .. && make -j3 && sudo make install && cd ../../
|
||||||
|
|
||||||
- name: Install LimeSuite
|
- name: Install LimeSuite
|
||||||
run: git clone https://github.com/myriadrf/LimeSuite && cd LimeSuite && mkdir builddir && cd builddir && cmake -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15 -DCMAKE_BUILD_TYPE=Release .. && make -j3 && sudo make install && cd ../../
|
run: git clone https://github.com/myriadrf/LimeSuite && cd LimeSuite && mkdir builddir && cd builddir && cmake -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15 -DCMAKE_BUILD_TYPE=Release .. && make -j3 && sudo make install && cd ../../
|
||||||
@@ -133,18 +127,12 @@ jobs:
|
|||||||
- name: Install librfnm
|
- name: Install librfnm
|
||||||
run: git clone https://github.com/AlexandreRouma/librfnm && cd librfnm && mkdir build && cd build && cmake .. -DCMAKE_BUILD_TYPE=Release && make && sudo make install && cd ..
|
run: git clone https://github.com/AlexandreRouma/librfnm && cd librfnm && mkdir build && cd build && cmake .. -DCMAKE_BUILD_TYPE=Release && make && sudo make install && cd ..
|
||||||
|
|
||||||
- name: Install libfobos
|
|
||||||
run: git clone https://github.com/AlexandreRouma/libfobos && cd libfobos && mkdir build && cd build && cmake .. -DCMAKE_BUILD_TYPE=Release && make && sudo make install && cd ..
|
|
||||||
|
|
||||||
- name: Install more recent librtlsdr
|
- name: Install more recent librtlsdr
|
||||||
run: git clone https://github.com/osmocom/rtl-sdr && cd rtl-sdr && mkdir build && cd build && cmake -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15 -DCMAKE_BUILD_TYPE=Release .. && make -j3 LIBRARY_PATH=$(pkg-config --libs-only-L libusb-1.0 | sed 's/\-L//') && sudo make install && cd ../../
|
run: git clone https://github.com/osmocom/rtl-sdr && cd rtl-sdr && mkdir build && cd build && cmake -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15 -DCMAKE_BUILD_TYPE=Release .. && make -j3 LIBRARY_PATH=$(pkg-config --libs-only-L libusb-1.0 | sed 's/\-L//') && sudo make install && cd ../../
|
||||||
|
|
||||||
- name: Install libhydrasdr
|
|
||||||
run: git clone https://github.com/hydrasdr/rfone_host && cd rfone_host && mkdir build && cd build && cmake -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15 -DCMAKE_BUILD_TYPE=Release .. && make -j3 && sudo make install && cd ../../
|
|
||||||
|
|
||||||
- name: Prepare CMake
|
- name: Prepare CMake
|
||||||
working-directory: ${{runner.workspace}}/build
|
working-directory: ${{runner.workspace}}/build
|
||||||
run: cmake -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15 $GITHUB_WORKSPACE -DOPT_BUILD_PLUTOSDR_SOURCE=ON -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 -DOPT_BUILD_RFNM_SOURCE=ON -DOPT_BUILD_FOBOSSDR_SOURCE=ON -DOPT_BUILD_HYDRASDR_SOURCE=ON -DUSE_BUNDLE_DEFAULTS=ON -DCMAKE_BUILD_TYPE=Release
|
run: cmake -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15 $GITHUB_WORKSPACE -DOPT_BUILD_PLUTOSDR_SOURCE=ON -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 -DOPT_BUILD_RFNM_SOURCE=ON -DUSE_BUNDLE_DEFAULTS=ON -DCMAKE_BUILD_TYPE=Release
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
working-directory: ${{runner.workspace}}/build
|
working-directory: ${{runner.workspace}}/build
|
||||||
@@ -161,7 +149,7 @@ jobs:
|
|||||||
path: ${{runner.workspace}}/sdrpp_macos_intel.zip
|
path: ${{runner.workspace}}/sdrpp_macos_intel.zip
|
||||||
|
|
||||||
build_macos_arm:
|
build_macos_arm:
|
||||||
runs-on: macos-15
|
runs-on: macos-14
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
@@ -182,7 +170,7 @@ jobs:
|
|||||||
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_OSX_DEPLOYMENT_TARGET=10.15 -DCMAKE_BUILD_TYPE=Release .. && make -j3 && sudo make install && cd ../../
|
run: wget https://github.com/analogdevicesinc/libiio/archive/refs/tags/v0.25.zip && 7z x v0.25.zip && cd libiio-0.25 && mkdir build && cd build && cmake -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15 -DCMAKE_BUILD_TYPE=Release .. && make -j3 && sudo make install && cd ../../
|
||||||
|
|
||||||
- name: Install libad9361
|
- name: Install libad9361
|
||||||
run: git clone https://github.com/analogdevicesinc/libad9361-iio && cd libad9361-iio && mkdir build && cd build && cmake -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15 -DCMAKE_BUILD_TYPE=Release -DCMAKE_POLICY_VERSION_MINIMUM=3.5 .. && make -j3 && sudo make install && cd ../../
|
run: git clone https://github.com/analogdevicesinc/libad9361-iio && cd libad9361-iio && mkdir build && cd build && cmake -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15 -DCMAKE_BUILD_TYPE=Release .. && make -j3 && sudo make install && cd ../../
|
||||||
|
|
||||||
- name: Install LimeSuite
|
- name: Install LimeSuite
|
||||||
run: git clone https://github.com/myriadrf/LimeSuite && cd LimeSuite && mkdir builddir && cd builddir && cmake -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15 -DCMAKE_BUILD_TYPE=Release .. && make -j3 && sudo make install && cd ../../
|
run: git clone https://github.com/myriadrf/LimeSuite && cd LimeSuite && mkdir builddir && cd builddir && cmake -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15 -DCMAKE_BUILD_TYPE=Release .. && make -j3 && sudo make install && cd ../../
|
||||||
@@ -193,18 +181,12 @@ jobs:
|
|||||||
- name: Install librfnm
|
- name: Install librfnm
|
||||||
run: git clone https://github.com/AlexandreRouma/librfnm && cd librfnm && mkdir build && cd build && cmake .. -DCMAKE_BUILD_TYPE=Release && make && sudo make install && cd ..
|
run: git clone https://github.com/AlexandreRouma/librfnm && cd librfnm && mkdir build && cd build && cmake .. -DCMAKE_BUILD_TYPE=Release && make && sudo make install && cd ..
|
||||||
|
|
||||||
- name: Install libfobos
|
|
||||||
run: git clone https://github.com/AlexandreRouma/libfobos && cd libfobos && mkdir build && cd build && cmake .. -DCMAKE_BUILD_TYPE=Release && make && sudo make install && cd ..
|
|
||||||
|
|
||||||
- name: Install more recent librtlsdr
|
- name: Install more recent librtlsdr
|
||||||
run: git clone https://github.com/osmocom/rtl-sdr && cd rtl-sdr && mkdir build && cd build && cmake -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15 -DCMAKE_BUILD_TYPE=Release .. && make -j3 LIBRARY_PATH=$(pkg-config --libs-only-L libusb-1.0 | sed 's/\-L//') && sudo make install && cd ../../
|
run: git clone https://github.com/osmocom/rtl-sdr && cd rtl-sdr && mkdir build && cd build && cmake -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15 -DCMAKE_BUILD_TYPE=Release .. && make -j3 LIBRARY_PATH=$(pkg-config --libs-only-L libusb-1.0 | sed 's/\-L//') && sudo make install && cd ../../
|
||||||
|
|
||||||
- name: Install libhydrasdr
|
|
||||||
run: git clone https://github.com/hydrasdr/rfone_host && cd rfone_host && mkdir build && cd build && cmake -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15 -DCMAKE_BUILD_TYPE=Release .. && make -j3 && sudo make install && cd ../../
|
|
||||||
|
|
||||||
- name: Prepare CMake
|
- name: Prepare CMake
|
||||||
working-directory: ${{runner.workspace}}/build
|
working-directory: ${{runner.workspace}}/build
|
||||||
run: cmake -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15 $GITHUB_WORKSPACE -DOPT_BUILD_PLUTOSDR_SOURCE=ON -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=OFF -DOPT_BUILD_PERSEUS_SOURCE=OFF -DOPT_BUILD_AUDIO_SOURCE=OFF -DOPT_BUILD_RFNM_SOURCE=ON -DOPT_BUILD_FOBOSSDR_SOURCE=ON -DOPT_BUILD_HYDRASDR_SOURCE=ON -DUSE_BUNDLE_DEFAULTS=ON -DCMAKE_BUILD_TYPE=Release
|
run: cmake -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15 $GITHUB_WORKSPACE -DOPT_BUILD_PLUTOSDR_SOURCE=ON -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=OFF -DOPT_BUILD_PERSEUS_SOURCE=OFF -DOPT_BUILD_AUDIO_SOURCE=OFF -DOPT_BUILD_RFNM_SOURCE=ON -DUSE_BUNDLE_DEFAULTS=ON -DCMAKE_BUILD_TYPE=Release
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
working-directory: ${{runner.workspace}}/build
|
working-directory: ${{runner.workspace}}/build
|
||||||
@@ -220,7 +202,29 @@ jobs:
|
|||||||
name: sdrpp_macos_arm
|
name: sdrpp_macos_arm
|
||||||
path: ${{runner.workspace}}/sdrpp_macos_arm.zip
|
path: ${{runner.workspace}}/sdrpp_macos_arm.zip
|
||||||
|
|
||||||
build_debian_bullseye_amd64:
|
build_debian_buster:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Create Docker Image
|
||||||
|
run: cd $GITHUB_WORKSPACE/docker_builds/debian_buster && 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@v4
|
||||||
|
with:
|
||||||
|
name: sdrpp_debian_buster_amd64
|
||||||
|
path: ${{runner.workspace}}/sdrpp_debian_amd64.deb
|
||||||
|
|
||||||
|
build_debian_bullseye:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
@@ -242,29 +246,7 @@ jobs:
|
|||||||
name: sdrpp_debian_bullseye_amd64
|
name: sdrpp_debian_bullseye_amd64
|
||||||
path: ${{runner.workspace}}/sdrpp_debian_amd64.deb
|
path: ${{runner.workspace}}/sdrpp_debian_amd64.deb
|
||||||
|
|
||||||
build_debian_bullseye_aarch64:
|
build_debian_bookworm:
|
||||||
runs-on: ubuntu-24.04-arm
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Create Docker Image
|
|
||||||
run: cd $GITHUB_WORKSPACE/docker_builds/debian_bullseye && 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@v4
|
|
||||||
with:
|
|
||||||
name: sdrpp_debian_bullseye_aarch64
|
|
||||||
path: ${{runner.workspace}}/sdrpp_debian_amd64.deb
|
|
||||||
|
|
||||||
build_debian_bookworm_amd64:
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
@@ -286,73 +268,7 @@ jobs:
|
|||||||
name: sdrpp_debian_bookworm_amd64
|
name: sdrpp_debian_bookworm_amd64
|
||||||
path: ${{runner.workspace}}/sdrpp_debian_amd64.deb
|
path: ${{runner.workspace}}/sdrpp_debian_amd64.deb
|
||||||
|
|
||||||
build_debian_bookworm_aarch64:
|
build_debian_sid:
|
||||||
runs-on: ubuntu-24.04-arm
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- 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@v4
|
|
||||||
with:
|
|
||||||
name: sdrpp_debian_bookworm_aarch64
|
|
||||||
path: ${{runner.workspace}}/sdrpp_debian_amd64.deb
|
|
||||||
|
|
||||||
build_debian_trixie_amd64:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Create Docker Image
|
|
||||||
run: cd $GITHUB_WORKSPACE/docker_builds/debian_trixie && 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@v4
|
|
||||||
with:
|
|
||||||
name: sdrpp_debian_trixie_amd64
|
|
||||||
path: ${{runner.workspace}}/sdrpp_debian_amd64.deb
|
|
||||||
|
|
||||||
build_debian_trixie_aarch64:
|
|
||||||
runs-on: ubuntu-24.04-arm
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Create Docker Image
|
|
||||||
run: cd $GITHUB_WORKSPACE/docker_builds/debian_trixie && 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@v4
|
|
||||||
with:
|
|
||||||
name: sdrpp_debian_trixie_aarch64
|
|
||||||
path: ${{runner.workspace}}/sdrpp_debian_amd64.deb
|
|
||||||
|
|
||||||
build_debian_sid_amd64:
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
@@ -374,29 +290,7 @@ jobs:
|
|||||||
name: sdrpp_debian_sid_amd64
|
name: sdrpp_debian_sid_amd64
|
||||||
path: ${{runner.workspace}}/sdrpp_debian_amd64.deb
|
path: ${{runner.workspace}}/sdrpp_debian_amd64.deb
|
||||||
|
|
||||||
build_debian_sid_aarch64:
|
build_ubuntu_focal:
|
||||||
runs-on: ubuntu-24.04-arm
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Create Docker Image
|
|
||||||
run: cd $GITHUB_WORKSPACE/docker_builds/debian_sid && 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@v4
|
|
||||||
with:
|
|
||||||
name: sdrpp_debian_sid_aarch64
|
|
||||||
path: ${{runner.workspace}}/sdrpp_debian_amd64.deb
|
|
||||||
|
|
||||||
build_ubuntu_focal_amd64:
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
@@ -418,29 +312,7 @@ jobs:
|
|||||||
name: sdrpp_ubuntu_focal_amd64
|
name: sdrpp_ubuntu_focal_amd64
|
||||||
path: ${{runner.workspace}}/sdrpp_debian_amd64.deb
|
path: ${{runner.workspace}}/sdrpp_debian_amd64.deb
|
||||||
|
|
||||||
build_ubuntu_focal_aarch64:
|
build_ubuntu_jammy:
|
||||||
runs-on: ubuntu-24.04-arm
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Create Docker Image
|
|
||||||
run: cd $GITHUB_WORKSPACE/docker_builds/ubuntu_focal && 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@v4
|
|
||||||
with:
|
|
||||||
name: sdrpp_ubuntu_focal_aarch64
|
|
||||||
path: ${{runner.workspace}}/sdrpp_debian_amd64.deb
|
|
||||||
|
|
||||||
build_ubuntu_jammy_amd64:
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
@@ -461,15 +333,15 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
name: sdrpp_ubuntu_jammy_amd64
|
name: sdrpp_ubuntu_jammy_amd64
|
||||||
path: ${{runner.workspace}}/sdrpp_debian_amd64.deb
|
path: ${{runner.workspace}}/sdrpp_debian_amd64.deb
|
||||||
|
|
||||||
build_ubuntu_jammy_aarch64:
|
build_ubuntu_mantic:
|
||||||
runs-on: ubuntu-24.04-arm
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Create Docker Image
|
- name: Create Docker Image
|
||||||
run: cd $GITHUB_WORKSPACE/docker_builds/ubuntu_jammy && docker build . --tag sdrpp_build
|
run: cd $GITHUB_WORKSPACE/docker_builds/ubuntu_mantic && docker build . --tag sdrpp_build
|
||||||
|
|
||||||
- name: Run Container
|
- 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
|
run: docker run --name build -v $GITHUB_WORKSPACE:/root/SDRPlusPlus --env BUILD_NO="-$GITHUB_RUN_NUMBER" sdrpp_build /root/do_build.sh
|
||||||
@@ -481,10 +353,10 @@ jobs:
|
|||||||
- name: Save Deb Archive
|
- name: Save Deb Archive
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: sdrpp_ubuntu_jammy_aarch64
|
name: sdrpp_ubuntu_mantic_amd64
|
||||||
path: ${{runner.workspace}}/sdrpp_debian_amd64.deb
|
path: ${{runner.workspace}}/sdrpp_debian_amd64.deb
|
||||||
|
|
||||||
build_ubuntu_noble_amd64:
|
build_ubuntu_noble:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
@@ -506,27 +378,32 @@ jobs:
|
|||||||
name: sdrpp_ubuntu_noble_amd64
|
name: sdrpp_ubuntu_noble_amd64
|
||||||
path: ${{runner.workspace}}/sdrpp_debian_amd64.deb
|
path: ${{runner.workspace}}/sdrpp_debian_amd64.deb
|
||||||
|
|
||||||
build_ubuntu_noble_aarch64:
|
build_raspios_bullseye_armhf:
|
||||||
runs-on: ubuntu-24.04-arm
|
runs-on: ARM
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Create Build Environment
|
||||||
|
run: rm -rf ${{runner.workspace}}/build && cmake -E make_directory ${{runner.workspace}}/build
|
||||||
|
|
||||||
- name: Create Docker Image
|
- name: Prepare CMake
|
||||||
run: cd $GITHUB_WORKSPACE/docker_builds/ubuntu_noble && docker build . --tag sdrpp_build
|
working-directory: ${{runner.workspace}}/build
|
||||||
|
run: cmake $GITHUB_WORKSPACE -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON -DOPT_BUILD_USRP_SOURCE=ON -DOPT_BUILD_PERSEUS_SOURCE=ON
|
||||||
|
|
||||||
- name: Run Container
|
- name: Build
|
||||||
run: docker run --name build -v $GITHUB_WORKSPACE:/root/SDRPlusPlus --env BUILD_NO="-$GITHUB_RUN_NUMBER" sdrpp_build /root/do_build.sh
|
working-directory: ${{runner.workspace}}/build
|
||||||
|
run: make VERBOSE=1 -j3
|
||||||
|
|
||||||
- name: Recover Deb Archive
|
- name: Create Dev Archive
|
||||||
working-directory: ${{runner.workspace}}
|
working-directory: ${{runner.workspace}}
|
||||||
run: docker cp build:/root/SDRPlusPlus/sdrpp_debian_amd64.deb ./
|
run: sh $GITHUB_WORKSPACE/make_debian_package.sh ./build 'libfftw3-dev, libglfw3-dev, libvolk2-dev, librtaudio-dev' && mv sdrpp_debian_amd64.deb sdrpp_debian_armhf.deb
|
||||||
|
|
||||||
- name: Save Deb Archive
|
- name: Save Deb Archive
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: sdrpp_ubuntu_noble_aarch64
|
name: sdrpp_raspios_bullseye_armhf
|
||||||
path: ${{runner.workspace}}/sdrpp_debian_amd64.deb
|
path: ${{runner.workspace}}/sdrpp_debian_armhf.deb
|
||||||
|
|
||||||
build_android:
|
build_android:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -556,26 +433,7 @@ jobs:
|
|||||||
path: ${{runner.workspace}}/sdrpp.apk
|
path: ${{runner.workspace}}/sdrpp.apk
|
||||||
|
|
||||||
create_full_archive:
|
create_full_archive:
|
||||||
needs: [
|
needs: ['build_windows', 'build_macos_intel', 'build_macos_arm', 'build_debian_buster', 'build_debian_bullseye', 'build_debian_bookworm', 'build_debian_sid', 'build_ubuntu_focal', 'build_ubuntu_jammy', 'build_ubuntu_mantic', 'build_ubuntu_noble', 'build_raspios_bullseye_armhf', 'build_android']
|
||||||
'build_windows',
|
|
||||||
'build_macos_intel',
|
|
||||||
'build_macos_arm',
|
|
||||||
'build_debian_bullseye_amd64',
|
|
||||||
'build_debian_bullseye_aarch64',
|
|
||||||
'build_debian_bookworm_amd64',
|
|
||||||
'build_debian_bookworm_aarch64',
|
|
||||||
'build_debian_trixie_amd64',
|
|
||||||
'build_debian_trixie_aarch64',
|
|
||||||
'build_debian_sid_amd64',
|
|
||||||
'build_debian_sid_aarch64',
|
|
||||||
'build_ubuntu_focal_amd64',
|
|
||||||
'build_ubuntu_focal_aarch64',
|
|
||||||
'build_ubuntu_jammy_amd64',
|
|
||||||
'build_ubuntu_jammy_aarch64',
|
|
||||||
'build_ubuntu_noble_amd64',
|
|
||||||
'build_ubuntu_noble_aarch64',
|
|
||||||
'build_android'
|
|
||||||
]
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
@@ -588,20 +446,15 @@ jobs:
|
|||||||
mv sdrpp_windows_x64/sdrpp_windows_x64.zip sdrpp_all/ &&
|
mv sdrpp_windows_x64/sdrpp_windows_x64.zip sdrpp_all/ &&
|
||||||
mv sdrpp_macos_intel/sdrpp_macos_intel.zip sdrpp_all/ &&
|
mv sdrpp_macos_intel/sdrpp_macos_intel.zip sdrpp_all/ &&
|
||||||
mv sdrpp_macos_arm/sdrpp_macos_arm.zip sdrpp_all/ &&
|
mv sdrpp_macos_arm/sdrpp_macos_arm.zip sdrpp_all/ &&
|
||||||
mv sdrpp_debian_bullseye_amd64/sdrpp_debian_amd64.deb sdrpp_all/sdrpp_debian_bullseye_amd64.deb &&
|
mv sdrpp_debian_buster_amd64/sdrpp_debian_amd64.deb sdrpp_all/sdrpp_debian_buster_amd64.deb &&
|
||||||
mv sdrpp_debian_bullseye_aarch64/sdrpp_debian_amd64.deb sdrpp_all/sdrpp_debian_bullseye_aarch64.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_bookworm_amd64/sdrpp_debian_amd64.deb sdrpp_all/sdrpp_debian_bookworm_amd64.deb &&
|
||||||
mv sdrpp_debian_bookworm_aarch64/sdrpp_debian_amd64.deb sdrpp_all/sdrpp_debian_bookworm_aarch64.deb &&
|
|
||||||
mv sdrpp_debian_trixie_amd64/sdrpp_debian_amd64.deb sdrpp_all/sdrpp_debian_trixie_amd64.deb &&
|
|
||||||
mv sdrpp_debian_trixie_aarch64/sdrpp_debian_amd64.deb sdrpp_all/sdrpp_debian_trixie_aarch64.deb &&
|
|
||||||
mv sdrpp_debian_sid_amd64/sdrpp_debian_amd64.deb sdrpp_all/sdrpp_debian_sid_amd64.deb &&
|
mv sdrpp_debian_sid_amd64/sdrpp_debian_amd64.deb sdrpp_all/sdrpp_debian_sid_amd64.deb &&
|
||||||
mv sdrpp_debian_sid_aarch64/sdrpp_debian_amd64.deb sdrpp_all/sdrpp_debian_sid_aarch64.deb &&
|
|
||||||
mv sdrpp_ubuntu_focal_amd64/sdrpp_debian_amd64.deb sdrpp_all/sdrpp_ubuntu_focal_amd64.deb &&
|
mv sdrpp_ubuntu_focal_amd64/sdrpp_debian_amd64.deb sdrpp_all/sdrpp_ubuntu_focal_amd64.deb &&
|
||||||
mv sdrpp_ubuntu_focal_aarch64/sdrpp_debian_amd64.deb sdrpp_all/sdrpp_ubuntu_focal_aarch64.deb &&
|
|
||||||
mv sdrpp_ubuntu_jammy_amd64/sdrpp_debian_amd64.deb sdrpp_all/sdrpp_ubuntu_jammy_amd64.deb &&
|
mv sdrpp_ubuntu_jammy_amd64/sdrpp_debian_amd64.deb sdrpp_all/sdrpp_ubuntu_jammy_amd64.deb &&
|
||||||
mv sdrpp_ubuntu_jammy_aarch64/sdrpp_debian_amd64.deb sdrpp_all/sdrpp_ubuntu_jammy_aarch64.deb &&
|
mv sdrpp_ubuntu_mantic_amd64/sdrpp_debian_amd64.deb sdrpp_all/sdrpp_ubuntu_mantic_amd64.deb &&
|
||||||
mv sdrpp_ubuntu_noble_amd64/sdrpp_debian_amd64.deb sdrpp_all/sdrpp_ubuntu_noble_amd64.deb &&
|
mv sdrpp_ubuntu_noble_amd64/sdrpp_debian_amd64.deb sdrpp_all/sdrpp_ubuntu_noble_amd64.deb &&
|
||||||
mv sdrpp_ubuntu_noble_aarch64/sdrpp_debian_amd64.deb sdrpp_all/sdrpp_ubuntu_noble_aarch64.deb &&
|
mv sdrpp_raspios_bullseye_armhf/sdrpp_debian_armhf.deb sdrpp_all/sdrpp_raspios_bullseye_armhf.deb &&
|
||||||
mv sdrpp_android/sdrpp.apk sdrpp_all/sdrpp.apk
|
mv sdrpp_android/sdrpp.apk sdrpp_all/sdrpp.apk
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v4
|
- uses: actions/upload-artifact@v4
|
||||||
|
|||||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -16,8 +16,4 @@ poggers_decoder
|
|||||||
m17_decoder/libcorrect
|
m17_decoder/libcorrect
|
||||||
SDR++.app
|
SDR++.app
|
||||||
android/deps
|
android/deps
|
||||||
android/app/assets
|
android/app/assets
|
||||||
source_modules/badgesdr_source
|
|
||||||
decoder_modules/mystery_decoder
|
|
||||||
decoder_modules/tetra_decoder
|
|
||||||
misc_modules/modulation_monitor
|
|
||||||
100
CMakeLists.txt
100
CMakeLists.txt
@@ -14,14 +14,10 @@ option(OPT_BUILD_AIRSPYHF_SOURCE "Build Airspy HF+ Source Module (Dependencies:
|
|||||||
option(OPT_BUILD_AUDIO_SOURCE "Build Audio Source Module (Dependencies: rtaudio)" ON)
|
option(OPT_BUILD_AUDIO_SOURCE "Build Audio Source Module (Dependencies: rtaudio)" ON)
|
||||||
option(OPT_BUILD_BADGESDR_SOURCE "Build BadgeSDR Source Module (Dependencies: libusb)" OFF)
|
option(OPT_BUILD_BADGESDR_SOURCE "Build BadgeSDR Source Module (Dependencies: libusb)" OFF)
|
||||||
option(OPT_BUILD_BLADERF_SOURCE "Build BladeRF Source Module (Dependencies: libbladeRF)" OFF)
|
option(OPT_BUILD_BLADERF_SOURCE "Build BladeRF Source Module (Dependencies: libbladeRF)" OFF)
|
||||||
option(OPT_BUILD_DRAGONLABS_SOURCE "Build Dragon Labs Source Module (Dependencies: libdlcr)" OFF)
|
|
||||||
option(OPT_BUILD_FILE_SOURCE "Wav file source" ON)
|
option(OPT_BUILD_FILE_SOURCE "Wav file source" ON)
|
||||||
option(OPT_BUILD_FOBOSSDR_SOURCE "Build FobosSDR Source Module (Dependencies: libfobos)" OFF)
|
|
||||||
option(OPT_BUILD_HACKRF_SOURCE "Build HackRF Source Module (Dependencies: libhackrf)" ON)
|
option(OPT_BUILD_HACKRF_SOURCE "Build HackRF Source Module (Dependencies: libhackrf)" ON)
|
||||||
option(OPT_BUILD_HAROGIC_SOURCE "Build Harogic Source Module (Dependencies: htra_api)" OFF)
|
option(OPT_BUILD_HAROGIC_SOURCE "Build Harogic Source Module (Dependencies: htra_api)" OFF)
|
||||||
option(OPT_BUILD_HERMES_SOURCE "Build Hermes Source Module (no dependencies required)" ON)
|
option(OPT_BUILD_HERMES_SOURCE "Build Hermes Source Module (no dependencies required)" ON)
|
||||||
option(OPT_BUILD_HYDRASDR_SOURCE "Build HydraSDR Source Module (Dependencies: libhydrasdr)" OFF)
|
|
||||||
option(OPT_BUILD_KCSDR_SOURCE "Build KCSDR Source Module (Dependencies: libkcsdr)" OFF)
|
|
||||||
option(OPT_BUILD_LIMESDR_SOURCE "Build LimeSDR Source Module (Dependencies: liblimesuite)" OFF)
|
option(OPT_BUILD_LIMESDR_SOURCE "Build LimeSDR Source Module (Dependencies: liblimesuite)" OFF)
|
||||||
option(OPT_BUILD_NETWORK_SOURCE "Build Network Source Module (no dependencies required)" ON)
|
option(OPT_BUILD_NETWORK_SOURCE "Build Network Source Module (no dependencies required)" ON)
|
||||||
option(OPT_BUILD_PERSEUS_SOURCE "Build Perseus Source Module (Dependencies: libperseus-sdr)" OFF)
|
option(OPT_BUILD_PERSEUS_SOURCE "Build Perseus Source Module (Dependencies: libperseus-sdr)" OFF)
|
||||||
@@ -46,8 +42,7 @@ option(OPT_BUILD_NEW_PORTAUDIO_SINK "Build the new PortAudio Sink Module (Depend
|
|||||||
option(OPT_BUILD_PORTAUDIO_SINK "Build PortAudio Sink Module (Dependencies: portaudio)" OFF)
|
option(OPT_BUILD_PORTAUDIO_SINK "Build PortAudio Sink Module (Dependencies: portaudio)" OFF)
|
||||||
|
|
||||||
# Decoders
|
# Decoders
|
||||||
option(OPT_BUILD_ATV_DECODER "Build ATV decoder (no dependencies required)" ON)
|
option(OPT_BUILD_ATV_DECODER "Build ATV decoder (no dependencies required)" OFF)
|
||||||
option(OPT_BUILD_DAB_DECODER "Build the DAB/DAB+ decoder (no dependencies required)" OFF)
|
|
||||||
option(OPT_BUILD_FALCON9_DECODER "Build the falcon9 live decoder (Dependencies: ffplay)" OFF)
|
option(OPT_BUILD_FALCON9_DECODER "Build the falcon9 live decoder (Dependencies: ffplay)" OFF)
|
||||||
option(OPT_BUILD_KG_SSTV_DECODER "Build the KG SSTV (KG-STV) decoder module (no dependencies required)" OFF)
|
option(OPT_BUILD_KG_SSTV_DECODER "Build the KG SSTV (KG-STV) decoder module (no dependencies required)" OFF)
|
||||||
option(OPT_BUILD_M17_DECODER "Build the M17 decoder module (Dependencies: codec2)" OFF)
|
option(OPT_BUILD_M17_DECODER "Build the M17 decoder module (Dependencies: codec2)" OFF)
|
||||||
@@ -55,7 +50,6 @@ option(OPT_BUILD_METEOR_DEMODULATOR "Build the meteor demodulator module (no dep
|
|||||||
option(OPT_BUILD_PAGER_DECODER "Build the pager decoder module (no dependencies required)" ON)
|
option(OPT_BUILD_PAGER_DECODER "Build the pager decoder module (no dependencies required)" ON)
|
||||||
option(OPT_BUILD_RADIO "Main audio modulation decoder (AM, FM, SSB, etc...)" ON)
|
option(OPT_BUILD_RADIO "Main audio modulation decoder (AM, FM, SSB, etc...)" ON)
|
||||||
option(OPT_BUILD_RYFI_DECODER "RyFi data link decoder" OFF)
|
option(OPT_BUILD_RYFI_DECODER "RyFi data link decoder" OFF)
|
||||||
option(OPT_BUILD_VOR_RECEIVER "VOR beacon receiver" OFF)
|
|
||||||
option(OPT_BUILD_WEATHER_SAT_DECODER "Build the HRPT decoder module (no dependencies required)" OFF)
|
option(OPT_BUILD_WEATHER_SAT_DECODER "Build the HRPT decoder module (no dependencies required)" OFF)
|
||||||
|
|
||||||
# Misc
|
# Misc
|
||||||
@@ -103,13 +97,56 @@ set(SDRPP_MODULE_COMPILER_FLAGS ${SDRPP_COMPILER_FLAGS})
|
|||||||
|
|
||||||
# Set a default install prefix
|
# Set a default install prefix
|
||||||
if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
|
if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
|
||||||
if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
if (MSVC)
|
||||||
|
set(CMAKE_INSTALL_PREFIX "C:/Program Files/SDR++/" CACHE PATH "..." FORCE)
|
||||||
|
elseif (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||||
set(CMAKE_INSTALL_PREFIX "/usr/local" CACHE PATH "..." FORCE)
|
set(CMAKE_INSTALL_PREFIX "/usr/local" CACHE PATH "..." FORCE)
|
||||||
else()
|
else()
|
||||||
set(CMAKE_INSTALL_PREFIX "/usr" CACHE PATH "..." FORCE)
|
set(CMAKE_INSTALL_PREFIX "/usr" CACHE PATH "..." FORCE)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# Include standard install directory definitions
|
||||||
|
include(GNUInstallDirs)
|
||||||
|
|
||||||
|
# Set up SDR++ directory load paths
|
||||||
|
if (MSVC)
|
||||||
|
set(SDRPP_MODULES_LOAD_DIR "./modules")
|
||||||
|
set(SDRPP_RES_LOAD_DIR "./res")
|
||||||
|
elseif (USE_BUNDLE_DEFAULTS)
|
||||||
|
set(SDRPP_MODULES_LOAD_DIR "../Plugins")
|
||||||
|
set(SDRPP_RES_LOAD_DIR "../Resources")
|
||||||
|
elseif (ANDROID)
|
||||||
|
set(SDRPP_MODULES_LOAD_DIR "/modules")
|
||||||
|
set(SDRPP_RES_LOAD_DIR "/res")
|
||||||
|
else()
|
||||||
|
set(SDRPP_MODULES_LOAD_DIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/sdrpp/plugins")
|
||||||
|
set(SDRPP_RES_LOAD_DIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATAROOTDIR}/sdrpp")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Set up SDR++ directory install paths
|
||||||
|
if (MSVC)
|
||||||
|
set(SDRPP_BIN_INSTALL_DIR "/")
|
||||||
|
set(SDRPP_LIB_INSTALL_DIR "/")
|
||||||
|
set(SDRPP_MODULES_INSTALL_DIR "modules")
|
||||||
|
set(SDRPP_RES_INSTALL_DIR "res")
|
||||||
|
elseif (USE_BUNDLE_DEFAULTS)
|
||||||
|
set(SDRPP_BIN_INSTALL_DIR "Contents/MacOS")
|
||||||
|
set(SDRPP_LIB_INSTALL_DIR "Contents/Frameworks")
|
||||||
|
set(SDRPP_MODULES_INSTALL_DIR "Contents/Plugins")
|
||||||
|
set(SDRPP_RES_INSTALL_DIR "Contents/Resources")
|
||||||
|
elseif (ANDROID)
|
||||||
|
set(SDRPP_BIN_INSTALL_DIR "${CMAKE_INSTALL_BINDIR}")
|
||||||
|
set(SDRPP_LIB_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}")
|
||||||
|
set(SDRPP_MODULES_INSTALL_DIR "/modules")
|
||||||
|
set(SDRPP_RES_INSTALL_DIR "/res")
|
||||||
|
else()
|
||||||
|
set(SDRPP_BIN_INSTALL_DIR "${CMAKE_INSTALL_BINDIR}")
|
||||||
|
set(SDRPP_LIB_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}")
|
||||||
|
set(SDRPP_MODULES_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}/sdrpp/plugins")
|
||||||
|
set(SDRPP_RES_INSTALL_DIR "${CMAKE_INSTALL_DATAROOTDIR}/sdrpp")
|
||||||
|
endif()
|
||||||
|
|
||||||
# Configure toolchain for android
|
# Configure toolchain for android
|
||||||
if (ANDROID)
|
if (ANDROID)
|
||||||
set(CMAKE_SHARED_LINKER_FLAGS
|
set(CMAKE_SHARED_LINKER_FLAGS
|
||||||
@@ -144,18 +181,10 @@ if (OPT_BUILD_BLADERF_SOURCE)
|
|||||||
add_subdirectory("source_modules/bladerf_source")
|
add_subdirectory("source_modules/bladerf_source")
|
||||||
endif (OPT_BUILD_BLADERF_SOURCE)
|
endif (OPT_BUILD_BLADERF_SOURCE)
|
||||||
|
|
||||||
if (OPT_BUILD_DRAGONLABS_SOURCE)
|
|
||||||
add_subdirectory("source_modules/dragonlabs_source")
|
|
||||||
endif (OPT_BUILD_DRAGONLABS_SOURCE)
|
|
||||||
|
|
||||||
if (OPT_BUILD_FILE_SOURCE)
|
if (OPT_BUILD_FILE_SOURCE)
|
||||||
add_subdirectory("source_modules/file_source")
|
add_subdirectory("source_modules/file_source")
|
||||||
endif (OPT_BUILD_FILE_SOURCE)
|
endif (OPT_BUILD_FILE_SOURCE)
|
||||||
|
|
||||||
if (OPT_BUILD_FOBOSSDR_SOURCE)
|
|
||||||
add_subdirectory("source_modules/fobossdr_source")
|
|
||||||
endif (OPT_BUILD_FOBOSSDR_SOURCE)
|
|
||||||
|
|
||||||
if (OPT_BUILD_HACKRF_SOURCE)
|
if (OPT_BUILD_HACKRF_SOURCE)
|
||||||
add_subdirectory("source_modules/hackrf_source")
|
add_subdirectory("source_modules/hackrf_source")
|
||||||
endif (OPT_BUILD_HACKRF_SOURCE)
|
endif (OPT_BUILD_HACKRF_SOURCE)
|
||||||
@@ -168,14 +197,6 @@ if (OPT_BUILD_HERMES_SOURCE)
|
|||||||
add_subdirectory("source_modules/hermes_source")
|
add_subdirectory("source_modules/hermes_source")
|
||||||
endif (OPT_BUILD_HERMES_SOURCE)
|
endif (OPT_BUILD_HERMES_SOURCE)
|
||||||
|
|
||||||
if (OPT_BUILD_HYDRASDR_SOURCE)
|
|
||||||
add_subdirectory("source_modules/hydrasdr_source")
|
|
||||||
endif (OPT_BUILD_HYDRASDR_SOURCE)
|
|
||||||
|
|
||||||
if (OPT_BUILD_KCSDR_SOURCE)
|
|
||||||
add_subdirectory("source_modules/kcsdr_source")
|
|
||||||
endif (OPT_BUILD_KCSDR_SOURCE)
|
|
||||||
|
|
||||||
if (OPT_BUILD_LIMESDR_SOURCE)
|
if (OPT_BUILD_LIMESDR_SOURCE)
|
||||||
add_subdirectory("source_modules/limesdr_source")
|
add_subdirectory("source_modules/limesdr_source")
|
||||||
endif (OPT_BUILD_LIMESDR_SOURCE)
|
endif (OPT_BUILD_LIMESDR_SOURCE)
|
||||||
@@ -208,10 +229,6 @@ if (OPT_BUILD_RTL_TCP_SOURCE)
|
|||||||
add_subdirectory("source_modules/rtl_tcp_source")
|
add_subdirectory("source_modules/rtl_tcp_source")
|
||||||
endif (OPT_BUILD_RTL_TCP_SOURCE)
|
endif (OPT_BUILD_RTL_TCP_SOURCE)
|
||||||
|
|
||||||
if (OPT_BUILD_SDDC_SOURCE)
|
|
||||||
add_subdirectory("source_modules/sddc_source")
|
|
||||||
endif (OPT_BUILD_SDDC_SOURCE)
|
|
||||||
|
|
||||||
if (OPT_BUILD_SDRPP_SERVER_SOURCE)
|
if (OPT_BUILD_SDRPP_SERVER_SOURCE)
|
||||||
add_subdirectory("source_modules/sdrpp_server_source")
|
add_subdirectory("source_modules/sdrpp_server_source")
|
||||||
endif (OPT_BUILD_SDRPP_SERVER_SOURCE)
|
endif (OPT_BUILD_SDRPP_SERVER_SOURCE)
|
||||||
@@ -268,10 +285,6 @@ if (OPT_BUILD_ATV_DECODER)
|
|||||||
add_subdirectory("decoder_modules/atv_decoder")
|
add_subdirectory("decoder_modules/atv_decoder")
|
||||||
endif (OPT_BUILD_ATV_DECODER)
|
endif (OPT_BUILD_ATV_DECODER)
|
||||||
|
|
||||||
if (OPT_BUILD_DAB_DECODER)
|
|
||||||
add_subdirectory("decoder_modules/dab_decoder")
|
|
||||||
endif (OPT_BUILD_DAB_DECODER)
|
|
||||||
|
|
||||||
if (OPT_BUILD_FALCON9_DECODER)
|
if (OPT_BUILD_FALCON9_DECODER)
|
||||||
add_subdirectory("decoder_modules/falcon9_decoder")
|
add_subdirectory("decoder_modules/falcon9_decoder")
|
||||||
endif (OPT_BUILD_FALCON9_DECODER)
|
endif (OPT_BUILD_FALCON9_DECODER)
|
||||||
@@ -300,10 +313,6 @@ if (OPT_BUILD_RYFI_DECODER)
|
|||||||
add_subdirectory("decoder_modules/ryfi_decoder")
|
add_subdirectory("decoder_modules/ryfi_decoder")
|
||||||
endif (OPT_BUILD_RYFI_DECODER)
|
endif (OPT_BUILD_RYFI_DECODER)
|
||||||
|
|
||||||
if (OPT_BUILD_VOR_RECEIVER)
|
|
||||||
add_subdirectory("decoder_modules/vor_receiver")
|
|
||||||
endif (OPT_BUILD_VOR_RECEIVER)
|
|
||||||
|
|
||||||
if (OPT_BUILD_WEATHER_SAT_DECODER)
|
if (OPT_BUILD_WEATHER_SAT_DECODER)
|
||||||
add_subdirectory("decoder_modules/weather_sat_decoder")
|
add_subdirectory("decoder_modules/weather_sat_decoder")
|
||||||
endif (OPT_BUILD_WEATHER_SAT_DECODER)
|
endif (OPT_BUILD_WEATHER_SAT_DECODER)
|
||||||
@@ -397,21 +406,22 @@ endif ()
|
|||||||
# Create module cmake file
|
# Create module cmake file
|
||||||
configure_file(${CMAKE_SOURCE_DIR}/sdrpp_module.cmake ${CMAKE_CURRENT_BINARY_DIR}/sdrpp_module.cmake @ONLY)
|
configure_file(${CMAKE_SOURCE_DIR}/sdrpp_module.cmake ${CMAKE_CURRENT_BINARY_DIR}/sdrpp_module.cmake @ONLY)
|
||||||
|
|
||||||
# Install directives
|
# Create desktop entry file
|
||||||
install(TARGETS sdrpp DESTINATION bin)
|
|
||||||
install(DIRECTORY ${CMAKE_SOURCE_DIR}/root/res/bandplans DESTINATION share/sdrpp)
|
|
||||||
install(DIRECTORY ${CMAKE_SOURCE_DIR}/root/res/colormaps DESTINATION share/sdrpp)
|
|
||||||
install(DIRECTORY ${CMAKE_SOURCE_DIR}/root/res/fonts DESTINATION share/sdrpp)
|
|
||||||
install(DIRECTORY ${CMAKE_SOURCE_DIR}/root/res/icons DESTINATION share/sdrpp)
|
|
||||||
install(DIRECTORY ${CMAKE_SOURCE_DIR}/root/res/themes DESTINATION share/sdrpp)
|
|
||||||
configure_file(${CMAKE_SOURCE_DIR}/sdrpp.desktop ${CMAKE_CURRENT_BINARY_DIR}/sdrpp.desktop @ONLY)
|
configure_file(${CMAKE_SOURCE_DIR}/sdrpp.desktop ${CMAKE_CURRENT_BINARY_DIR}/sdrpp.desktop @ONLY)
|
||||||
|
|
||||||
|
# Install directives
|
||||||
|
install(TARGETS sdrpp DESTINATION ${SDRPP_BIN_INSTALL_DIR})
|
||||||
|
install(DIRECTORY ${CMAKE_SOURCE_DIR}/root/res/bandplans DESTINATION ${SDRPP_RES_INSTALL_DIR})
|
||||||
|
install(DIRECTORY ${CMAKE_SOURCE_DIR}/root/res/colormaps DESTINATION ${SDRPP_RES_INSTALL_DIR})
|
||||||
|
install(DIRECTORY ${CMAKE_SOURCE_DIR}/root/res/fonts DESTINATION ${SDRPP_RES_INSTALL_DIR})
|
||||||
|
install(DIRECTORY ${CMAKE_SOURCE_DIR}/root/res/icons DESTINATION ${SDRPP_RES_INSTALL_DIR})
|
||||||
|
install(DIRECTORY ${CMAKE_SOURCE_DIR}/root/res/themes DESTINATION ${SDRPP_RES_INSTALL_DIR})
|
||||||
if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/sdrpp.desktop DESTINATION share/applications)
|
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/sdrpp.desktop DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/applications)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
# Create uninstall target
|
# Create uninstall target
|
||||||
configure_file(${CMAKE_SOURCE_DIR}/cmake_uninstall.cmake ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake @ONLY)
|
configure_file(${CMAKE_SOURCE_DIR}/cmake_uninstall.cmake ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake @ONLY)
|
||||||
add_custom_target(uninstall ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
|
add_custom_target(uninstall ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
|
||||||
|
|
||||||
# Create headers target
|
# Create headers target
|
||||||
@@ -10,11 +10,11 @@ android {
|
|||||||
minSdkVersion 28
|
minSdkVersion 28
|
||||||
targetSdkVersion 28
|
targetSdkVersion 28
|
||||||
versionCode 1
|
versionCode 1
|
||||||
versionName "1.2.1"
|
versionName "1.2.0"
|
||||||
|
|
||||||
externalNativeBuild {
|
externalNativeBuild {
|
||||||
cmake {
|
cmake {
|
||||||
arguments "-DOPT_BACKEND_GLFW=OFF", "-DOPT_BACKEND_ANDROID=ON", "-DOPT_BUILD_SOAPY_SOURCE=OFF", "-DOPT_BUILD_ANDROID_AUDIO_SINK=ON", "-DOPT_BUILD_AUDIO_SINK=OFF", "-DOPT_BUILD_DISCORD_PRESENCE=OFF", "-DOPT_BUILD_M17_DECODER=ON", "-DOPT_BUILD_PLUTOSDR_SOURCE=ON", "-DOPT_BUILD_AUDIO_SOURCE=OFF", "-DOPT_BUILD_HYDRASDR_SOURCE=ON"
|
arguments "-DOPT_BACKEND_GLFW=OFF", "-DOPT_BACKEND_ANDROID=ON", "-DOPT_BUILD_SOAPY_SOURCE=OFF", "-DOPT_BUILD_ANDROID_AUDIO_SINK=ON", "-DOPT_BUILD_AUDIO_SINK=OFF", "-DOPT_BUILD_DISCORD_PRESENCE=OFF", "-DOPT_BUILD_M17_DECODER=ON", "-DOPT_BUILD_PLUTOSDR_SOURCE=ON", "-DOPT_BUILD_AUDIO_SOURCE=OFF"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,3 @@
|
|||||||
# AI USE IS FORBIDDEN
|
|
||||||
|
|
||||||
Use of AI for the creation of code, pull requests or issues is forbidden.
|
|
||||||
|
|
||||||
Submitting code, pull requests or issues generated by AI will result in a permanent ban from all of my (Alexandre Rouma) repositories.
|
|
||||||
|
|
||||||
# Pull Requests
|
# Pull Requests
|
||||||
|
|
||||||
Code pull requests are **NOT welcome**. Please open an issue discussing potential bugfixes or feature requests instead.
|
Code pull requests are **NOT welcome**. Please open an issue discussing potential bugfixes or feature requests instead.
|
||||||
@@ -70,4 +64,4 @@ Please follow this guide to properly format the JSON files for custom color maps
|
|||||||
|
|
||||||
The ability to add new radio band allocation identifiers and color maps relies on JSON files. Proper formatting of these JSON files is important for reference and readability. The following guides will show you how to properly format the JSON files for their respective uses.
|
The ability to add new radio band allocation identifiers and color maps relies on JSON files. Proper formatting of these JSON files is important for reference and readability. The following guides will show you how to properly format the JSON files for their respective uses.
|
||||||
|
|
||||||
**IMPORTANT: JSON File cannot contain comments, there are only in this example for clarity**
|
**IMPORTANT: JSON File cannot contain comments, there are only in this example for clarity**
|
||||||
@@ -18,6 +18,10 @@ if (MSVC)
|
|||||||
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
|
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
|
# Add compiler definitions for the directories
|
||||||
|
add_definitions(-DSDRPP_MODULES_LOAD_DIR="${SDRPP_MODULES_LOAD_DIR}")
|
||||||
|
add_definitions(-DSDRPP_RES_LOAD_DIR="${SDRPP_RES_LOAD_DIR}")
|
||||||
|
|
||||||
# Configure backend sources
|
# Configure backend sources
|
||||||
if (OPT_BACKEND_GLFW)
|
if (OPT_BACKEND_GLFW)
|
||||||
file(GLOB_RECURSE BACKEND_SRC "backends/glfw/*.cpp" "backends/glfw/*.c")
|
file(GLOB_RECURSE BACKEND_SRC "backends/glfw/*.cpp" "backends/glfw/*.c")
|
||||||
@@ -33,9 +37,6 @@ add_library(sdrpp_core SHARED ${SRC} ${BACKEND_SRC})
|
|||||||
# Set compiler options
|
# Set compiler options
|
||||||
target_compile_options(sdrpp_core PRIVATE ${SDRPP_COMPILER_FLAGS})
|
target_compile_options(sdrpp_core PRIVATE ${SDRPP_COMPILER_FLAGS})
|
||||||
|
|
||||||
# Set the install prefix
|
|
||||||
target_compile_definitions(sdrpp_core PUBLIC INSTALL_PREFIX="${CMAKE_INSTALL_PREFIX}")
|
|
||||||
|
|
||||||
# Include core headers
|
# Include core headers
|
||||||
target_include_directories(sdrpp_core PUBLIC "src/")
|
target_include_directories(sdrpp_core PUBLIC "src/")
|
||||||
target_include_directories(sdrpp_core PUBLIC "src/imgui")
|
target_include_directories(sdrpp_core PUBLIC "src/imgui")
|
||||||
@@ -167,4 +168,4 @@ set(CORE_FILES ${RUNTIME_OUTPUT_DIRECTORY} PARENT_SCOPE)
|
|||||||
# cmake .. "-DCMAKE_TOOLCHAIN_FILE=C:/dev/vcpkg/scripts/buildsystems/vcpkg.cmake"
|
# cmake .. "-DCMAKE_TOOLCHAIN_FILE=C:/dev/vcpkg/scripts/buildsystems/vcpkg.cmake"
|
||||||
|
|
||||||
# Install directives
|
# Install directives
|
||||||
install(TARGETS sdrpp_core DESTINATION lib)
|
install(TARGETS sdrpp_core DESTINATION ${SDRPP_LIB_INSTALL_DIR})
|
||||||
@@ -11,7 +11,6 @@ namespace backend {
|
|||||||
extern const std::vector<DevVIDPID> AIRSPY_VIDPIDS;
|
extern const std::vector<DevVIDPID> AIRSPY_VIDPIDS;
|
||||||
extern const std::vector<DevVIDPID> AIRSPYHF_VIDPIDS;
|
extern const std::vector<DevVIDPID> AIRSPYHF_VIDPIDS;
|
||||||
extern const std::vector<DevVIDPID> HACKRF_VIDPIDS;
|
extern const std::vector<DevVIDPID> HACKRF_VIDPIDS;
|
||||||
extern const std::vector<DevVIDPID> HYDRASDR_VIDPIDS;
|
|
||||||
extern const std::vector<DevVIDPID> RTL_SDR_VIDPIDS;
|
extern const std::vector<DevVIDPID> RTL_SDR_VIDPIDS;
|
||||||
|
|
||||||
int getDeviceFD(int& vid, int& pid, const std::vector<DevVIDPID>& allowedVidPids);
|
int getDeviceFD(int& vid, int& pid, const std::vector<DevVIDPID>& allowedVidPids);
|
||||||
|
|||||||
@@ -408,11 +408,6 @@ namespace backend {
|
|||||||
{ 0x1d50, 0xcc15 }
|
{ 0x1d50, 0xcc15 }
|
||||||
};
|
};
|
||||||
|
|
||||||
const std::vector<DevVIDPID> HYDRASDR_VIDPIDS = {
|
|
||||||
{ 0x1d50, 0x60a1 },
|
|
||||||
{ 0x38af, 0x0001 }
|
|
||||||
};
|
|
||||||
|
|
||||||
const std::vector<DevVIDPID> RTL_SDR_VIDPIDS = {
|
const std::vector<DevVIDPID> RTL_SDR_VIDPIDS = {
|
||||||
{ 0x0bda, 0x2832 },
|
{ 0x0bda, 0x2832 },
|
||||||
{ 0x0bda, 0x2838 },
|
{ 0x0bda, 0x2838 },
|
||||||
|
|||||||
@@ -99,10 +99,7 @@ namespace backend {
|
|||||||
glfwWindowHint(GLFW_CLIENT_API, OPENGL_VERSIONS_IS_ES[i] ? GLFW_OPENGL_ES_API : GLFW_OPENGL_API);
|
glfwWindowHint(GLFW_CLIENT_API, OPENGL_VERSIONS_IS_ES[i] ? GLFW_OPENGL_ES_API : GLFW_OPENGL_API);
|
||||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, OPENGL_VERSIONS_MAJOR[i]);
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, OPENGL_VERSIONS_MAJOR[i]);
|
||||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, OPENGL_VERSIONS_MINOR[i]);
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, OPENGL_VERSIONS_MINOR[i]);
|
||||||
#if GLFW_VERSION_MAJOR > 3 || (GLFW_VERSION_MAJOR == 3 && GLFW_VERSION_MINOR >= 4)
|
|
||||||
glfwWindowHintString(GLFW_WAYLAND_APP_ID, "sdrpp");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Create window with graphics context
|
// Create window with graphics context
|
||||||
monitor = glfwGetPrimaryMonitor();
|
monitor = glfwGetPrimaryMonitor();
|
||||||
window = glfwCreateWindow(winWidth, winHeight, "SDR++ v" VERSION_STR " (Built at " __TIME__ ", " __DATE__ ")", NULL, NULL);
|
window = glfwCreateWindow(winWidth, winHeight, "SDR++ v" VERSION_STR " (Built at " __TIME__ ", " __DATE__ ")", NULL, NULL);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
cmake_minimum_required(VERSION 3.13)
|
cmake_minimum_required(VERSION 2.8)
|
||||||
project(Correct C)
|
project(Correct C)
|
||||||
include(CheckLibraryExists)
|
include(CheckLibraryExists)
|
||||||
include(CheckIncludeFiles)
|
include(CheckIncludeFiles)
|
||||||
|
|||||||
@@ -24,14 +24,16 @@
|
|||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef INSTALL_PREFIX
|
|
||||||
#ifdef __APPLE__
|
// Default install dirs to make the IDE happy
|
||||||
#define INSTALL_PREFIX "/usr/local"
|
#ifndef SDRPP_MODULES_LOAD_DIR
|
||||||
#else
|
#define SDRPP_MODULES_LOAD_DIR ""
|
||||||
#define INSTALL_PREFIX "/usr"
|
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef SDRPP_RES_LOAD_DIR
|
||||||
|
#define SDRPP_RES_LOAD_DIR ""
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
namespace core {
|
namespace core {
|
||||||
ConfigManager configManager;
|
ConfigManager configManager;
|
||||||
ModuleManager moduleManager;
|
ModuleManager moduleManager;
|
||||||
@@ -147,11 +149,11 @@ int sdrpp_main(int argc, char* argv[]) {
|
|||||||
defConfig["menuElements"][3]["name"] = "Sinks";
|
defConfig["menuElements"][3]["name"] = "Sinks";
|
||||||
defConfig["menuElements"][3]["open"] = true;
|
defConfig["menuElements"][3]["open"] = true;
|
||||||
|
|
||||||
defConfig["menuElements"][4]["name"] = "Frequency Manager";
|
defConfig["menuElements"][3]["name"] = "Frequency Manager";
|
||||||
defConfig["menuElements"][4]["open"] = true;
|
defConfig["menuElements"][3]["open"] = true;
|
||||||
|
|
||||||
defConfig["menuElements"][5]["name"] = "VFO Color";
|
defConfig["menuElements"][4]["name"] = "VFO Color";
|
||||||
defConfig["menuElements"][5]["open"] = true;
|
defConfig["menuElements"][4]["open"] = true;
|
||||||
|
|
||||||
defConfig["menuElements"][6]["name"] = "Band Plan";
|
defConfig["menuElements"][6]["name"] = "Band Plan";
|
||||||
defConfig["menuElements"][6]["open"] = true;
|
defConfig["menuElements"][6]["open"] = true;
|
||||||
@@ -173,24 +175,16 @@ int sdrpp_main(int argc, char* argv[]) {
|
|||||||
defConfig["moduleInstances"]["BladeRF Source"]["enabled"] = true;
|
defConfig["moduleInstances"]["BladeRF Source"]["enabled"] = true;
|
||||||
defConfig["moduleInstances"]["File Source"]["module"] = "file_source";
|
defConfig["moduleInstances"]["File Source"]["module"] = "file_source";
|
||||||
defConfig["moduleInstances"]["File Source"]["enabled"] = true;
|
defConfig["moduleInstances"]["File Source"]["enabled"] = true;
|
||||||
defConfig["moduleInstances"]["FobosSDR Source"]["module"] = "fobossdr_source";
|
|
||||||
defConfig["moduleInstances"]["FobosSDR Source"]["enabled"] = true;
|
|
||||||
defConfig["moduleInstances"]["HackRF Source"]["module"] = "hackrf_source";
|
defConfig["moduleInstances"]["HackRF Source"]["module"] = "hackrf_source";
|
||||||
defConfig["moduleInstances"]["HackRF Source"]["enabled"] = true;
|
defConfig["moduleInstances"]["HackRF Source"]["enabled"] = true;
|
||||||
defConfig["moduleInstances"]["Harogic Source"]["module"] = "harogic_source";
|
|
||||||
defConfig["moduleInstances"]["Harogic Source"]["enabled"] = true;
|
|
||||||
defConfig["moduleInstances"]["Hermes Source"]["module"] = "hermes_source";
|
defConfig["moduleInstances"]["Hermes Source"]["module"] = "hermes_source";
|
||||||
defConfig["moduleInstances"]["Hermes Source"]["enabled"] = true;
|
defConfig["moduleInstances"]["Hermes Source"]["enabled"] = true;
|
||||||
defConfig["moduleInstances"]["HydraSDR Source"]["module"] = "hydrasdr_source";
|
|
||||||
defConfig["moduleInstances"]["HydraSDR Source"]["enabled"] = true;
|
|
||||||
defConfig["moduleInstances"]["LimeSDR Source"]["module"] = "limesdr_source";
|
defConfig["moduleInstances"]["LimeSDR Source"]["module"] = "limesdr_source";
|
||||||
defConfig["moduleInstances"]["LimeSDR Source"]["enabled"] = true;
|
defConfig["moduleInstances"]["LimeSDR Source"]["enabled"] = true;
|
||||||
defConfig["moduleInstances"]["Network Source"]["module"] = "network_source";
|
|
||||||
defConfig["moduleInstances"]["Network Source"]["enabled"] = true;
|
|
||||||
defConfig["moduleInstances"]["PerseusSDR Source"]["module"] = "perseus_source";
|
|
||||||
defConfig["moduleInstances"]["PerseusSDR Source"]["enabled"] = true;
|
|
||||||
defConfig["moduleInstances"]["PlutoSDR Source"]["module"] = "plutosdr_source";
|
defConfig["moduleInstances"]["PlutoSDR Source"]["module"] = "plutosdr_source";
|
||||||
defConfig["moduleInstances"]["PlutoSDR Source"]["enabled"] = true;
|
defConfig["moduleInstances"]["PlutoSDR Source"]["enabled"] = true;
|
||||||
|
defConfig["moduleInstances"]["PerseusSDR Source"]["module"] = "perseus_source";
|
||||||
|
defConfig["moduleInstances"]["PerseusSDR Source"]["enabled"] = true;
|
||||||
defConfig["moduleInstances"]["RFNM Source"]["module"] = "rfnm_source";
|
defConfig["moduleInstances"]["RFNM Source"]["module"] = "rfnm_source";
|
||||||
defConfig["moduleInstances"]["RFNM Source"]["enabled"] = true;
|
defConfig["moduleInstances"]["RFNM Source"]["enabled"] = true;
|
||||||
defConfig["moduleInstances"]["RFspace Source"]["module"] = "rfspace_source";
|
defConfig["moduleInstances"]["RFspace Source"]["module"] = "rfspace_source";
|
||||||
@@ -203,12 +197,8 @@ int sdrpp_main(int argc, char* argv[]) {
|
|||||||
defConfig["moduleInstances"]["SDRplay Source"]["enabled"] = true;
|
defConfig["moduleInstances"]["SDRplay Source"]["enabled"] = true;
|
||||||
defConfig["moduleInstances"]["SDR++ Server Source"]["module"] = "sdrpp_server_source";
|
defConfig["moduleInstances"]["SDR++ Server Source"]["module"] = "sdrpp_server_source";
|
||||||
defConfig["moduleInstances"]["SDR++ Server Source"]["enabled"] = true;
|
defConfig["moduleInstances"]["SDR++ Server Source"]["enabled"] = true;
|
||||||
defConfig["moduleInstances"]["Spectran HTTP Source"]["module"] = "spectran_http_source";
|
|
||||||
defConfig["moduleInstances"]["Spectran HTTP Source"]["enabled"] = true;
|
|
||||||
defConfig["moduleInstances"]["SpyServer Source"]["module"] = "spyserver_source";
|
defConfig["moduleInstances"]["SpyServer Source"]["module"] = "spyserver_source";
|
||||||
defConfig["moduleInstances"]["SpyServer Source"]["enabled"] = true;
|
defConfig["moduleInstances"]["SpyServer Source"]["enabled"] = true;
|
||||||
defConfig["moduleInstances"]["USRP Source"]["module"] = "usrp_source";
|
|
||||||
defConfig["moduleInstances"]["USRP Source"]["enabled"] = true;
|
|
||||||
|
|
||||||
defConfig["moduleInstances"]["Audio Sink"] = "audio_sink";
|
defConfig["moduleInstances"]["Audio Sink"] = "audio_sink";
|
||||||
defConfig["moduleInstances"]["Network Sink"] = "network_sink";
|
defConfig["moduleInstances"]["Network Sink"] = "network_sink";
|
||||||
@@ -234,19 +224,12 @@ int sdrpp_main(int argc, char* argv[]) {
|
|||||||
|
|
||||||
defConfig["modules"] = json::array();
|
defConfig["modules"] = json::array();
|
||||||
|
|
||||||
defConfig["offsets"]["SpyVerter"] = 120000000.0;
|
defConfig["offsetMode"] = (int)0; // Off
|
||||||
defConfig["offsets"]["Ham-It-Up"] = 125000000.0;
|
defConfig["offset"] = 0.0;
|
||||||
defConfig["offsets"]["MMDS S-band (1998MHz)"] = -1998000000.0;
|
|
||||||
defConfig["offsets"]["DK5AV X-Band"] = -6800000000.0;
|
|
||||||
defConfig["offsets"]["Ku LNB (9750MHz)"] = -9750000000.0;
|
|
||||||
defConfig["offsets"]["Ku LNB (10700MHz)"] = -10700000000.0;
|
|
||||||
|
|
||||||
defConfig["selectedOffset"] = "None";
|
|
||||||
defConfig["manualOffset"] = 0.0;
|
|
||||||
defConfig["showMenu"] = true;
|
defConfig["showMenu"] = true;
|
||||||
defConfig["showWaterfall"] = true;
|
defConfig["showWaterfall"] = true;
|
||||||
defConfig["source"] = "";
|
defConfig["source"] = "";
|
||||||
defConfig["decimation"] = 1;
|
defConfig["decimationPower"] = 0;
|
||||||
defConfig["iqCorrection"] = false;
|
defConfig["iqCorrection"] = false;
|
||||||
defConfig["invertIQ"] = false;
|
defConfig["invertIQ"] = false;
|
||||||
|
|
||||||
@@ -267,19 +250,14 @@ int sdrpp_main(int argc, char* argv[]) {
|
|||||||
defConfig["lockMenuOrder"] = false;
|
defConfig["lockMenuOrder"] = false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#ifdef __ANDROID__
|
||||||
defConfig["modulesDirectory"] = "./modules";
|
defConfig["modulesDirectory"] = root + SDRPP_MODULES_LOAD_DIR;
|
||||||
defConfig["resourcesDirectory"] = "./res";
|
defConfig["resourcesDirectory"] = root + SDRPP_RES_LOAD_DIR;
|
||||||
#elif defined(IS_MACOS_BUNDLE)
|
|
||||||
defConfig["modulesDirectory"] = "../Plugins";
|
|
||||||
defConfig["resourcesDirectory"] = "../Resources";
|
|
||||||
#elif defined(__ANDROID__)
|
|
||||||
defConfig["modulesDirectory"] = root + "/modules";
|
|
||||||
defConfig["resourcesDirectory"] = root + "/res";
|
|
||||||
#else
|
#else
|
||||||
defConfig["modulesDirectory"] = INSTALL_PREFIX "/lib/sdrpp/plugins";
|
defConfig["modulesDirectory"] = SDRPP_MODULES_LOAD_DIR;
|
||||||
defConfig["resourcesDirectory"] = INSTALL_PREFIX "/share/sdrpp";
|
defConfig["resourcesDirectory"] = SDRPP_RES_LOAD_DIR;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// Load config
|
// Load config
|
||||||
flog::info("Loading config");
|
flog::info("Loading config");
|
||||||
@@ -297,7 +275,6 @@ int sdrpp_main(int argc, char* argv[]) {
|
|||||||
core::configManager.conf["modules"][modCount++] = "airspyhf_source.so";
|
core::configManager.conf["modules"][modCount++] = "airspyhf_source.so";
|
||||||
core::configManager.conf["modules"][modCount++] = "hackrf_source.so";
|
core::configManager.conf["modules"][modCount++] = "hackrf_source.so";
|
||||||
core::configManager.conf["modules"][modCount++] = "hermes_source.so";
|
core::configManager.conf["modules"][modCount++] = "hermes_source.so";
|
||||||
core::configManager.conf["modules"][modCount++] = "hydrasdr_source.so";
|
|
||||||
core::configManager.conf["modules"][modCount++] = "plutosdr_source.so";
|
core::configManager.conf["modules"][modCount++] = "plutosdr_source.so";
|
||||||
core::configManager.conf["modules"][modCount++] = "rfspace_source.so";
|
core::configManager.conf["modules"][modCount++] = "rfspace_source.so";
|
||||||
core::configManager.conf["modules"][modCount++] = "rtl_sdr_source.so";
|
core::configManager.conf["modules"][modCount++] = "rtl_sdr_source.so";
|
||||||
@@ -328,18 +305,12 @@ int sdrpp_main(int argc, char* argv[]) {
|
|||||||
|
|
||||||
// Remove unused elements
|
// Remove unused elements
|
||||||
auto items = core::configManager.conf.items();
|
auto items = core::configManager.conf.items();
|
||||||
auto newConf = core::configManager.conf;
|
|
||||||
bool configCorrected = false;
|
|
||||||
for (auto const& item : items) {
|
for (auto const& item : items) {
|
||||||
if (!defConfig.contains(item.key())) {
|
if (!defConfig.contains(item.key())) {
|
||||||
flog::info("Unused key in config {0}, repairing", item.key());
|
flog::info("Unused key in config {0}, repairing", item.key());
|
||||||
newConf.erase(item.key());
|
core::configManager.conf.erase(item.key());
|
||||||
configCorrected = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (configCorrected) {
|
|
||||||
core::configManager.conf = newConf;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update to new module representation in config if needed
|
// Update to new module representation in config if needed
|
||||||
for (auto [_name, inst] : core::configManager.conf["moduleInstances"].items()) {
|
for (auto [_name, inst] : core::configManager.conf["moduleInstances"].items()) {
|
||||||
|
|||||||
@@ -37,12 +37,9 @@ namespace sdrpp_credits {
|
|||||||
const char* hardwareDonators[] = {
|
const char* hardwareDonators[] = {
|
||||||
"Aaronia AG",
|
"Aaronia AG",
|
||||||
"Airspy",
|
"Airspy",
|
||||||
"Alex 4Z5LV",
|
|
||||||
"Analog Devices",
|
"Analog Devices",
|
||||||
"CaribouLabs",
|
"CaribouLabs",
|
||||||
"Deepace",
|
|
||||||
"Ettus Research",
|
"Ettus Research",
|
||||||
"Harogic",
|
|
||||||
"Howard Su",
|
"Howard Su",
|
||||||
"MicroPhase",
|
"MicroPhase",
|
||||||
"Microtelecom",
|
"Microtelecom",
|
||||||
@@ -50,7 +47,6 @@ namespace sdrpp_credits {
|
|||||||
"Nuand",
|
"Nuand",
|
||||||
"RFNM",
|
"RFNM",
|
||||||
"RFspace",
|
"RFspace",
|
||||||
"RigExpert",
|
|
||||||
"RTL-SDRblog",
|
"RTL-SDRblog",
|
||||||
"SDRplay"
|
"SDRplay"
|
||||||
};
|
};
|
||||||
@@ -70,18 +66,15 @@ namespace sdrpp_credits {
|
|||||||
"Flinger Films",
|
"Flinger Films",
|
||||||
"Frank Werner (HB9FXQ)",
|
"Frank Werner (HB9FXQ)",
|
||||||
"gringogrigio",
|
"gringogrigio",
|
||||||
"Jandro",
|
|
||||||
"Jeff Moe",
|
"Jeff Moe",
|
||||||
"Joe Cupano",
|
"Joe Cupano",
|
||||||
"KD1SQ",
|
"KD1SQ",
|
||||||
"Kezza",
|
"Kezza",
|
||||||
"Krys Kamieniecki",
|
"Krys Kamieniecki",
|
||||||
"Lee Donaghy",
|
"Lee Donaghy",
|
||||||
"Lee (KD1SQ)",
|
"Lee KD1SQ",
|
||||||
".lozenge. (Hank Hill)",
|
".lozenge. (Hank Hill)",
|
||||||
"Martin Herren (HB9FXX)",
|
"Martin Herren (HB9FXX)",
|
||||||
"NeoVilsonWong",
|
|
||||||
"Nitin (VU2JEK)",
|
|
||||||
"ON4MU",
|
"ON4MU",
|
||||||
"Passion-Radio.com",
|
"Passion-Radio.com",
|
||||||
"Paul Maine",
|
"Paul Maine",
|
||||||
|
|||||||
@@ -163,10 +163,10 @@ namespace dsp {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
Processor<T, T>* blockBefore(Processor<T, T>* block) {
|
Processor<T, T>* blockBefore(Processor<T, T>* block) {
|
||||||
Processor<T, T>* prev = NULL;
|
// TODO: This is wrong and must be fixed when I get more time
|
||||||
for (auto& ln : links) {
|
for (auto& ln : links) {
|
||||||
if (ln == block) { return prev; }
|
if (ln == block) { return NULL; }
|
||||||
if (states[ln]) { prev = ln; }
|
if (states[ln]) { return ln; }
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,17 +22,18 @@ namespace dsp::demod {
|
|||||||
dsp::taps::free(filterTaps);
|
dsp::taps::free(filterTaps);
|
||||||
}
|
}
|
||||||
|
|
||||||
void init(dsp::stream<dsp::complex_t>* in, double samplerate, double bandwidth, bool lowPass) {
|
void init(dsp::stream<dsp::complex_t>* in, double samplerate, double bandwidth, bool lowPass, bool highPass) {
|
||||||
_samplerate = samplerate;
|
_samplerate = samplerate;
|
||||||
_bandwidth = bandwidth;
|
_bandwidth = bandwidth;
|
||||||
_lowPass = lowPass;
|
_lowPass = lowPass;
|
||||||
|
_highPass = highPass;
|
||||||
|
|
||||||
demod.init(NULL, bandwidth / 2.0, _samplerate);
|
demod.init(NULL, bandwidth / 2.0, _samplerate);
|
||||||
loadDummyTaps();
|
loadDummyTaps();
|
||||||
fir.init(NULL, filterTaps);
|
fir.init(NULL, filterTaps);
|
||||||
|
|
||||||
// Initialize taps
|
// Initialize taps
|
||||||
updateFilter(lowPass);
|
updateFilter(lowPass, highPass);
|
||||||
|
|
||||||
if constexpr (std::is_same_v<T, float>) {
|
if constexpr (std::is_same_v<T, float>) {
|
||||||
demod.out.free();
|
demod.out.free();
|
||||||
@@ -48,7 +49,7 @@ namespace dsp::demod {
|
|||||||
base_type::tempStop();
|
base_type::tempStop();
|
||||||
_samplerate = samplerate;
|
_samplerate = samplerate;
|
||||||
demod.setDeviation(_bandwidth / 2.0, _samplerate);
|
demod.setDeviation(_bandwidth / 2.0, _samplerate);
|
||||||
updateFilter(_lowPass);
|
updateFilter(_lowPass, _highPass);
|
||||||
base_type::tempStart();
|
base_type::tempStart();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,13 +59,19 @@ namespace dsp::demod {
|
|||||||
if (bandwidth == _bandwidth) { return; }
|
if (bandwidth == _bandwidth) { return; }
|
||||||
_bandwidth = bandwidth;
|
_bandwidth = bandwidth;
|
||||||
demod.setDeviation(_bandwidth / 2.0, _samplerate);
|
demod.setDeviation(_bandwidth / 2.0, _samplerate);
|
||||||
updateFilter(_lowPass);
|
updateFilter(_lowPass, _highPass);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setLowPass(bool lowPass) {
|
void setLowPass(bool lowPass) {
|
||||||
assert(base_type::_block_init);
|
assert(base_type::_block_init);
|
||||||
std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
|
std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
|
||||||
updateFilter(lowPass);
|
updateFilter(lowPass, _highPass);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setHighPass(bool highPass) {
|
||||||
|
assert(base_type::_block_init);
|
||||||
|
std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
|
||||||
|
updateFilter(_lowPass, highPass);
|
||||||
}
|
}
|
||||||
|
|
||||||
void reset() {
|
void reset() {
|
||||||
@@ -79,14 +86,14 @@ namespace dsp::demod {
|
|||||||
inline int process(int count, dsp::complex_t* in, T* out) {
|
inline int process(int count, dsp::complex_t* in, T* out) {
|
||||||
if constexpr (std::is_same_v<T, float>) {
|
if constexpr (std::is_same_v<T, float>) {
|
||||||
demod.process(count, in, out);
|
demod.process(count, in, out);
|
||||||
if (_lowPass) {
|
if (filtering) {
|
||||||
std::lock_guard<std::mutex> lck(filterMtx);
|
std::lock_guard<std::mutex> lck(filterMtx);
|
||||||
fir.process(count, out, out);
|
fir.process(count, out, out);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if constexpr (std::is_same_v<T, stereo_t>) {
|
if constexpr (std::is_same_v<T, stereo_t>) {
|
||||||
demod.process(count, in, demod.out.writeBuf);
|
demod.process(count, in, demod.out.writeBuf);
|
||||||
if (_lowPass) {
|
if (filtering) {
|
||||||
std::lock_guard<std::mutex> lck(filterMtx);
|
std::lock_guard<std::mutex> lck(filterMtx);
|
||||||
fir.process(count, demod.out.writeBuf, demod.out.writeBuf);
|
fir.process(count, demod.out.writeBuf, demod.out.writeBuf);
|
||||||
}
|
}
|
||||||
@@ -107,17 +114,25 @@ namespace dsp::demod {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void updateFilter(bool lowPass) {
|
void updateFilter(bool lowPass, bool highPass) {
|
||||||
std::lock_guard<std::mutex> lck(filterMtx);
|
std::lock_guard<std::mutex> lck(filterMtx);
|
||||||
|
|
||||||
// Update values
|
// Update values
|
||||||
_lowPass = lowPass;
|
_lowPass = lowPass;
|
||||||
|
_highPass = highPass;
|
||||||
|
filtering = (lowPass || highPass);
|
||||||
|
|
||||||
// Free filter taps
|
// Free filter taps
|
||||||
dsp::taps::free(filterTaps);
|
dsp::taps::free(filterTaps);
|
||||||
|
|
||||||
// Generate filter depending on the low pass settings
|
// Generate filter depending on low and high pass settings
|
||||||
if (_lowPass) {
|
if (_lowPass && _highPass) {
|
||||||
|
filterTaps = dsp::taps::bandPass<float>(300.0, _bandwidth / 2.0, 100.0, _samplerate);
|
||||||
|
}
|
||||||
|
else if (_highPass) {
|
||||||
|
filterTaps = dsp::taps::highPass(300.0, 100.0, _samplerate);
|
||||||
|
}
|
||||||
|
else if (_lowPass) {
|
||||||
filterTaps = dsp::taps::lowPass(_bandwidth / 2.0, (_bandwidth / 2.0) * 0.1, _samplerate);
|
filterTaps = dsp::taps::lowPass(_bandwidth / 2.0, (_bandwidth / 2.0) * 0.1, _samplerate);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -137,6 +152,7 @@ namespace dsp::demod {
|
|||||||
double _samplerate;
|
double _samplerate;
|
||||||
double _bandwidth;
|
double _bandwidth;
|
||||||
bool _lowPass;
|
bool _lowPass;
|
||||||
|
bool _highPass;
|
||||||
bool filtering;
|
bool filtering;
|
||||||
|
|
||||||
Quadrature demod;
|
Quadrature demod;
|
||||||
|
|||||||
@@ -1,303 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "../channel/rx_vfo.h"
|
|
||||||
#include "../demod/quadrature.h"
|
|
||||||
#include "../filter/fir.h"
|
|
||||||
#include "../taps/high_pass.h"
|
|
||||||
#include <fftw3.h>
|
|
||||||
#include <map>
|
|
||||||
#include <atomic>
|
|
||||||
|
|
||||||
#define CTCSS_DECODE_SAMPLERATE 500//250.0
|
|
||||||
#define CTCSS_DECODE_BANDWIDTH 200.0
|
|
||||||
#define CTCSS_DECODE_OFFSET 160.55
|
|
||||||
|
|
||||||
namespace dsp::noise_reduction {
|
|
||||||
enum CTCSSTone {
|
|
||||||
/**
|
|
||||||
* Indicates that any valid tone will let audio through.
|
|
||||||
*/
|
|
||||||
CTCSS_TONE_ANY = -2,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates that no tone is being received, or to act as a decoder only, letting audio through continuously.
|
|
||||||
*/
|
|
||||||
CTCSS_TONE_NONE = -1,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* CTCSS Tone Frequency.
|
|
||||||
*/
|
|
||||||
CTCSS_TONE_67Hz,
|
|
||||||
CTCSS_TONE_69_3Hz,
|
|
||||||
CTCSS_TONE_71_9Hz,
|
|
||||||
CTCSS_TONE_74_4Hz,
|
|
||||||
CTCSS_TONE_77Hz,
|
|
||||||
CTCSS_TONE_79_7Hz,
|
|
||||||
CTCSS_TONE_82_5Hz,
|
|
||||||
CTCSS_TONE_85_4Hz,
|
|
||||||
CTCSS_TONE_88_5Hz,
|
|
||||||
CTCSS_TONE_91_5Hz,
|
|
||||||
CTCSS_TONE_94_8Hz,
|
|
||||||
CTCSS_TONE_97_4Hz,
|
|
||||||
CTCSS_TONE_100Hz,
|
|
||||||
CTCSS_TONE_103_5Hz,
|
|
||||||
CTCSS_TONE_107_2Hz,
|
|
||||||
CTCSS_TONE_110_9Hz,
|
|
||||||
CTCSS_TONE_114_8Hz,
|
|
||||||
CTCSS_TONE_118_8Hz,
|
|
||||||
CTCSS_TONE_123Hz,
|
|
||||||
CTCSS_TONE_127_3Hz,
|
|
||||||
CTCSS_TONE_131_8Hz,
|
|
||||||
CTCSS_TONE_136_5Hz,
|
|
||||||
CTCSS_TONE_141_3Hz,
|
|
||||||
CTCSS_TONE_146_2Hz,
|
|
||||||
CTCSS_TONE_150Hz,
|
|
||||||
CTCSS_TONE_151_4Hz,
|
|
||||||
CTCSS_TONE_156_7Hz,
|
|
||||||
CTCSS_TONE_159_8Hz,
|
|
||||||
CTCSS_TONE_162_2Hz,
|
|
||||||
CTCSS_TONE_165_5Hz,
|
|
||||||
CTCSS_TONE_167_9Hz,
|
|
||||||
CTCSS_TONE_171_3Hz,
|
|
||||||
CTCSS_TONE_173_8Hz,
|
|
||||||
CTCSS_TONE_177_3Hz,
|
|
||||||
CTCSS_TONE_179_9Hz,
|
|
||||||
CTCSS_TONE_183_5Hz,
|
|
||||||
CTCSS_TONE_186_2Hz,
|
|
||||||
CTCSS_TONE_189_9Hz,
|
|
||||||
CTCSS_TONE_192_8Hz,
|
|
||||||
CTCSS_TONE_196_6Hz,
|
|
||||||
CTCSS_TONE_199_5Hz,
|
|
||||||
CTCSS_TONE_203_5Hz,
|
|
||||||
CTCSS_TONE_206_5Hz,
|
|
||||||
CTCSS_TONE_210_7Hz,
|
|
||||||
CTCSS_TONE_218_1Hz,
|
|
||||||
CTCSS_TONE_225_7Hz,
|
|
||||||
CTCSS_TONE_229_1Hz,
|
|
||||||
CTCSS_TONE_233_6Hz,
|
|
||||||
CTCSS_TONE_241_8Hz,
|
|
||||||
CTCSS_TONE_250_3Hz,
|
|
||||||
CTCSS_TONE_254_1Hz,
|
|
||||||
_CTCSS_TONE_COUNT
|
|
||||||
};
|
|
||||||
|
|
||||||
const float CTCSS_TONES[_CTCSS_TONE_COUNT] = {
|
|
||||||
67.0f,
|
|
||||||
69.3f,
|
|
||||||
71.9f,
|
|
||||||
74.4f,
|
|
||||||
77.0f,
|
|
||||||
79.7f,
|
|
||||||
82.5f,
|
|
||||||
85.4f,
|
|
||||||
88.5f,
|
|
||||||
91.5f,
|
|
||||||
94.8f,
|
|
||||||
97.4f,
|
|
||||||
100.0f,
|
|
||||||
103.5f,
|
|
||||||
107.2f,
|
|
||||||
110.9f,
|
|
||||||
114.8f,
|
|
||||||
118.8f,
|
|
||||||
123.0f,
|
|
||||||
127.3f,
|
|
||||||
131.8f,
|
|
||||||
136.5f,
|
|
||||||
141.3f,
|
|
||||||
146.2f,
|
|
||||||
150.0f,
|
|
||||||
151.4f,
|
|
||||||
156.7f,
|
|
||||||
159.8f,
|
|
||||||
162.2f,
|
|
||||||
165.5f,
|
|
||||||
167.9f,
|
|
||||||
171.3f,
|
|
||||||
173.8f,
|
|
||||||
177.3f,
|
|
||||||
179.9f,
|
|
||||||
183.5f,
|
|
||||||
186.2f,
|
|
||||||
189.9f,
|
|
||||||
192.8f,
|
|
||||||
196.6f,
|
|
||||||
199.5f,
|
|
||||||
203.5f,
|
|
||||||
206.5f,
|
|
||||||
210.7f,
|
|
||||||
218.1f,
|
|
||||||
225.7f,
|
|
||||||
229.1f,
|
|
||||||
233.6f,
|
|
||||||
241.8f,
|
|
||||||
250.3f,
|
|
||||||
254.1f
|
|
||||||
};
|
|
||||||
|
|
||||||
class CTCSSSquelch : public Processor<stereo_t, stereo_t> {
|
|
||||||
using base_type = Processor<stereo_t, stereo_t>;
|
|
||||||
public:
|
|
||||||
CTCSSSquelch() {}
|
|
||||||
|
|
||||||
CTCSSSquelch(stream<stereo_t>* in, double samplerate) { init(in, samplerate); }
|
|
||||||
|
|
||||||
~CTCSSSquelch() {
|
|
||||||
// If not initialized, do nothing
|
|
||||||
if (!base_type::_block_init) { return; }
|
|
||||||
|
|
||||||
// Stop the DSP thread
|
|
||||||
base_type::stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
void init(stream<stereo_t>* in, double samplerate) {
|
|
||||||
// Save settings
|
|
||||||
_samplerate = samplerate;
|
|
||||||
|
|
||||||
// Create dummy taps just for initialization
|
|
||||||
float dummy[1] = { 1.0f };
|
|
||||||
auto dummyTaps = dsp::taps::fromArray(1, dummy);
|
|
||||||
|
|
||||||
// Initialize the DDC and FM demod
|
|
||||||
ddc.init(NULL, samplerate, CTCSS_DECODE_SAMPLERATE, CTCSS_DECODE_BANDWIDTH, CTCSS_DECODE_OFFSET);
|
|
||||||
fm.init(NULL, 1.0, CTCSS_DECODE_SAMPLERATE);
|
|
||||||
|
|
||||||
// Initilize the base block class
|
|
||||||
base_type::init(in);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setSamplerate(double samplerate) {
|
|
||||||
assert(base_type::_block_init);
|
|
||||||
std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
|
|
||||||
base_type::tempStop();
|
|
||||||
_samplerate = samplerate;
|
|
||||||
ddc.setInSamplerate(samplerate);
|
|
||||||
base_type::tempStart();
|
|
||||||
}
|
|
||||||
|
|
||||||
void setRequiredTone(CTCSSTone tone) {
|
|
||||||
assert(base_type::_block_init);
|
|
||||||
requiredTone = tone;
|
|
||||||
}
|
|
||||||
|
|
||||||
CTCSSTone getCurrentTone() {
|
|
||||||
assert(base_type::_block_init);
|
|
||||||
return currentTone;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int process(int count, const stereo_t* in, stereo_t* out) {
|
|
||||||
// Shift and resample to the correct samplerate
|
|
||||||
int ddcOutCount = ddc.process(count, (complex_t*)in, ddc.out.writeBuf);
|
|
||||||
|
|
||||||
// FM Demod the CTCSS tone
|
|
||||||
fm.process(ddcOutCount, ddc.out.writeBuf, fm.out.writeBuf);
|
|
||||||
|
|
||||||
// Get the required tone
|
|
||||||
const CTCSSTone rtone = requiredTone;
|
|
||||||
|
|
||||||
// Detect the tone frequency
|
|
||||||
for (int i = 0; i < ddcOutCount; i++) {
|
|
||||||
// Compute the running mean
|
|
||||||
const float val = fm.out.writeBuf[i];
|
|
||||||
mean = 0.95f*mean + 0.05f*val;
|
|
||||||
|
|
||||||
// Compute the running variance
|
|
||||||
const float err = val - mean;
|
|
||||||
var = 0.95f*var + 0.05f*err*err;
|
|
||||||
|
|
||||||
// Run a schmitt trigger on the variance
|
|
||||||
bool nvarOk = varOk ? (var < 1100.0f) : (var < 1000.0f);
|
|
||||||
|
|
||||||
// Check if the tone has to be rematched
|
|
||||||
if (nvarOk && (!varOk || mean < minFreq || mean > maxFreq)) {
|
|
||||||
// Compute the absolute frequency
|
|
||||||
float freq = mean + CTCSS_DECODE_OFFSET;
|
|
||||||
|
|
||||||
// Check it against the known tones
|
|
||||||
if (freq < CTCSS_TONES[0] - 2.5) {
|
|
||||||
currentTone = CTCSS_TONE_NONE;
|
|
||||||
}
|
|
||||||
else if (freq > CTCSS_TONES[_CTCSS_TONE_COUNT-1] + 2.5) {
|
|
||||||
currentTone = CTCSS_TONE_NONE;
|
|
||||||
}
|
|
||||||
else if (freq < CTCSS_TONES[0]) {
|
|
||||||
currentTone = (CTCSSTone)0;
|
|
||||||
}
|
|
||||||
else if (freq > CTCSS_TONES[_CTCSS_TONE_COUNT-1]) {
|
|
||||||
currentTone = (CTCSSTone)(_CTCSS_TONE_COUNT-1);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
int a = 0;
|
|
||||||
int b = _CTCSS_TONE_COUNT-1;
|
|
||||||
while (b - a > 1) {
|
|
||||||
int c = (a + b) >> 1;
|
|
||||||
((CTCSS_TONES[c] < freq) ? a : b) = c;
|
|
||||||
}
|
|
||||||
currentTone = (CTCSSTone)((freq - CTCSS_TONES[a] < CTCSS_TONES[b] - freq) ? a : b);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the mute status
|
|
||||||
mute = !(currentTone == rtone || (currentTone != CTCSS_TONE_NONE && rtone == CTCSS_TONE_ANY));
|
|
||||||
|
|
||||||
// Unmuted the audio if needed
|
|
||||||
// TODO
|
|
||||||
|
|
||||||
// Recompute min and max freq if a valid tone is detected
|
|
||||||
if (currentTone != CTCSS_TONE_NONE) {
|
|
||||||
float c = CTCSS_TONES[currentTone];
|
|
||||||
float l = (currentTone > CTCSS_TONE_67Hz) ? CTCSS_TONES[currentTone - 1] : c - 2.5f;
|
|
||||||
float r = (currentTone < CTCSS_TONE_254_1Hz) ? CTCSS_TONES[currentTone + 1] : c + 2.5f;
|
|
||||||
minFreq = (l+c) / 2.0f;
|
|
||||||
maxFreq = (r+c) / 2.0f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for a rising edge on the variance
|
|
||||||
if (!nvarOk && varOk) {
|
|
||||||
// Mute the audio
|
|
||||||
// TODO
|
|
||||||
mute = true;
|
|
||||||
currentTone = CTCSS_TONE_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save the new variance state
|
|
||||||
varOk = nvarOk;
|
|
||||||
}
|
|
||||||
|
|
||||||
// DEBUG ONLY
|
|
||||||
if ((rtone != CTCSS_TONE_NONE) && mute) {
|
|
||||||
memset(out, 0, count * sizeof(stereo_t));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
memcpy(out, in, count * sizeof(stereo_t));
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
base_type::_in->flush();
|
|
||||||
if (!base_type::out.swap(count)) { return -1; }
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private:
|
|
||||||
double _samplerate;
|
|
||||||
std::atomic<CTCSSTone> requiredTone = CTCSS_TONE_ANY;
|
|
||||||
|
|
||||||
float mean = 0.0f;
|
|
||||||
float var = 0.0f;
|
|
||||||
bool varOk = false;
|
|
||||||
float minFreq = 0.0f;
|
|
||||||
float maxFreq = 0.0f;
|
|
||||||
bool mute = true;
|
|
||||||
std::atomic<CTCSSTone> currentTone = CTCSS_TONE_NONE;
|
|
||||||
|
|
||||||
channel::RxVFO ddc;
|
|
||||||
demod::Quadrature fm;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -3,14 +3,14 @@
|
|||||||
|
|
||||||
// TODO: Rewrite better!!!!!
|
// TODO: Rewrite better!!!!!
|
||||||
namespace dsp::noise_reduction {
|
namespace dsp::noise_reduction {
|
||||||
class PowerSquelch : public Processor<complex_t, complex_t> {
|
class Squelch : public Processor<complex_t, complex_t> {
|
||||||
using base_type = Processor<complex_t, complex_t>;
|
using base_type = Processor<complex_t, complex_t>;
|
||||||
public:
|
public:
|
||||||
PowerSquelch() {}
|
Squelch() {}
|
||||||
|
|
||||||
PowerSquelch(stream<complex_t>* in, double level) {}
|
Squelch(stream<complex_t>* in, double level) {}
|
||||||
|
|
||||||
~PowerSquelch() {
|
~Squelch() {
|
||||||
if (!base_type::_block_init) { return; }
|
if (!base_type::_block_init) { return; }
|
||||||
base_type::stop();
|
base_type::stop();
|
||||||
buffer::free(normBuffer);
|
buffer::free(normBuffer);
|
||||||
@@ -31,11 +31,8 @@ namespace dsp::noise_reduction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline int process(int count, const complex_t* in, complex_t* out) {
|
inline int process(int count, const complex_t* in, complex_t* out) {
|
||||||
// Compute the amplitude of each sample
|
float sum;
|
||||||
volk_32fc_magnitude_32f(normBuffer, (lv_32fc_t*)in, count);
|
volk_32fc_magnitude_32f(normBuffer, (lv_32fc_t*)in, count);
|
||||||
|
|
||||||
// Compute the mean amplitude
|
|
||||||
float sum = 0.0f;
|
|
||||||
volk_32f_accumulator_s32f(&sum, normBuffer, count);
|
volk_32f_accumulator_s32f(&sum, normBuffer, count);
|
||||||
sum /= (float)count;
|
sum /= (float)count;
|
||||||
|
|
||||||
@@ -49,6 +46,8 @@ namespace dsp::noise_reduction {
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//DEFAULT_PROC_RUN();
|
||||||
|
|
||||||
int run() {
|
int run() {
|
||||||
int count = base_type::_in->read();
|
int count = base_type::_in->read();
|
||||||
if (count < 0) { return -1; }
|
if (count < 0) { return -1; }
|
||||||
@@ -5,6 +5,8 @@ namespace dsp {
|
|||||||
template <class T>
|
template <class T>
|
||||||
class Source : public block {
|
class Source : public block {
|
||||||
public:
|
public:
|
||||||
|
Source() {}
|
||||||
|
|
||||||
Source() { init(); }
|
Source() { init(); }
|
||||||
|
|
||||||
virtual ~Source() {}
|
virtual ~Source() {}
|
||||||
|
|||||||
@@ -5,120 +5,113 @@
|
|||||||
#include <gui/main_window.h>
|
#include <gui/main_window.h>
|
||||||
#include <gui/style.h>
|
#include <gui/style.h>
|
||||||
#include <signal_path/signal_path.h>
|
#include <signal_path/signal_path.h>
|
||||||
#include <utils/optionlist.h>
|
|
||||||
#include <gui/dialogs/dialog_box.h>
|
|
||||||
|
|
||||||
namespace sourcemenu {
|
namespace sourcemenu {
|
||||||
|
int offsetMode = 0;
|
||||||
int sourceId = 0;
|
int sourceId = 0;
|
||||||
EventHandler<std::string> sourcesChangedHandler;
|
double customOffset = 0.0;
|
||||||
EventHandler<std::string> sourceUnregisterHandler;
|
double effectiveOffset = 0.0;
|
||||||
OptionList<std::string, std::string> sources;
|
int decimationPower = 0;
|
||||||
std::string selectedSource;
|
|
||||||
|
|
||||||
int decimId = 0;
|
|
||||||
OptionList<int, int> decimations;
|
|
||||||
|
|
||||||
bool iqCorrection = false;
|
bool iqCorrection = false;
|
||||||
bool invertIQ = false;
|
bool invertIQ = false;
|
||||||
|
|
||||||
int offsetId = 0;
|
EventHandler<std::string> sourceRegisteredHandler;
|
||||||
double manualOffset = 0.0;
|
EventHandler<std::string> sourceUnregisterHandler;
|
||||||
std::string selectedOffset;
|
EventHandler<std::string> sourceUnregisteredHandler;
|
||||||
double effectiveOffset = 0.0;
|
|
||||||
OptionList<std::string, double> offsets;
|
|
||||||
std::map<std::string, double> namedOffsets;
|
|
||||||
|
|
||||||
bool showAddOffsetDialog = false;
|
std::vector<std::string> sourceNames;
|
||||||
char newOffsetName[1024];
|
std::string sourceNamesTxt;
|
||||||
double newOffset = 0.0;
|
std::string selectedSource;
|
||||||
|
|
||||||
bool showDelOffsetDialog = false;
|
|
||||||
std::string delOffsetName = "";
|
|
||||||
|
|
||||||
// Offset IDs
|
|
||||||
enum {
|
enum {
|
||||||
OFFSET_ID_NONE,
|
OFFSET_MODE_NONE,
|
||||||
OFFSET_ID_MANUAL,
|
OFFSET_MODE_CUSTOM,
|
||||||
OFFSET_ID_CUSTOM_BASE
|
OFFSET_MODE_SPYVERTER,
|
||||||
|
OFFSET_MODE_HAM_IT_UP,
|
||||||
|
OFFSET_MODE_MMDS_SB_1998,
|
||||||
|
OFFSET_MODE_DK5AV_XB,
|
||||||
|
OFFSET_MODE_KU_LNB_9750,
|
||||||
|
OFFSET_MODE_KU_LNB_10700,
|
||||||
|
_OFFSET_MODE_COUNT
|
||||||
};
|
};
|
||||||
|
|
||||||
void updateOffset() {
|
const char* offsetModesTxt = "None\0"
|
||||||
// Compute the effective offset
|
"Custom\0"
|
||||||
switch (offsetId) {
|
"SpyVerter\0"
|
||||||
case OFFSET_ID_NONE:
|
"Ham-It-Up\0"
|
||||||
effectiveOffset = 0;
|
"MMDS S-band (1998MHz)\0"
|
||||||
break;
|
"DK5AV X-Band\0"
|
||||||
case OFFSET_ID_MANUAL:
|
"Ku LNB (9750MHz)\0"
|
||||||
effectiveOffset = manualOffset;
|
"Ku LNB (10700MHz)\0";
|
||||||
break;
|
|
||||||
default:
|
|
||||||
effectiveOffset = namedOffsets[offsets.name(offsetId)];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply it
|
const char* decimationStages = "None\0"
|
||||||
|
"2\0"
|
||||||
|
"4\0"
|
||||||
|
"8\0"
|
||||||
|
"16\0"
|
||||||
|
"32\0"
|
||||||
|
"64\0";
|
||||||
|
|
||||||
|
void updateOffset() {
|
||||||
|
if (offsetMode == OFFSET_MODE_CUSTOM) { effectiveOffset = customOffset; }
|
||||||
|
else if (offsetMode == OFFSET_MODE_SPYVERTER) {
|
||||||
|
effectiveOffset = 120000000;
|
||||||
|
} // 120MHz Up-conversion
|
||||||
|
else if (offsetMode == OFFSET_MODE_HAM_IT_UP) {
|
||||||
|
effectiveOffset = 125000000;
|
||||||
|
} // 125MHz Up-conversion
|
||||||
|
else if (offsetMode == OFFSET_MODE_MMDS_SB_1998) {
|
||||||
|
effectiveOffset = -1998000000;
|
||||||
|
} // 1.998GHz Down-conversion
|
||||||
|
else if (offsetMode == OFFSET_MODE_DK5AV_XB) {
|
||||||
|
effectiveOffset = -6800000000;
|
||||||
|
} // 6.8GHz Down-conversion
|
||||||
|
else if (offsetMode == OFFSET_MODE_KU_LNB_9750) {
|
||||||
|
effectiveOffset = -9750000000;
|
||||||
|
} // 9.750GHz Down-conversion
|
||||||
|
else if (offsetMode == OFFSET_MODE_KU_LNB_10700) {
|
||||||
|
effectiveOffset = -10700000000;
|
||||||
|
} // 10.7GHz Down-conversion
|
||||||
|
else {
|
||||||
|
effectiveOffset = 0;
|
||||||
|
}
|
||||||
sigpath::sourceManager.setTuningOffset(effectiveOffset);
|
sigpath::sourceManager.setTuningOffset(effectiveOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
void selectOffsetById(int id) {
|
|
||||||
// Update the offset mode
|
|
||||||
offsetId = id;
|
|
||||||
selectedOffset = offsets.name(id);
|
|
||||||
|
|
||||||
// Update the offset
|
|
||||||
updateOffset();
|
|
||||||
}
|
|
||||||
|
|
||||||
void selectOffsetByName(const std::string& name) {
|
|
||||||
// If the name doesn't exist, select 'None'
|
|
||||||
if (!offsets.nameExists(name)) {
|
|
||||||
selectOffsetById(OFFSET_ID_NONE);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Select using the ID associated with the name
|
|
||||||
selectOffsetById(offsets.nameId(name));
|
|
||||||
}
|
|
||||||
|
|
||||||
void refreshSources() {
|
void refreshSources() {
|
||||||
// Get sources
|
sourceNames = sigpath::sourceManager.getSourceNames();
|
||||||
auto sourceNames = sigpath::sourceManager.getSourceNames();
|
sourceNamesTxt.clear();
|
||||||
|
|
||||||
// Define source options
|
|
||||||
sources.clear();
|
|
||||||
for (auto name : sourceNames) {
|
for (auto name : sourceNames) {
|
||||||
sources.define(name, name, name);
|
sourceNamesTxt += name;
|
||||||
|
sourceNamesTxt += '\0';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void selectSource(std::string name) {
|
void selectSource(std::string name) {
|
||||||
// If there is no source, give up
|
if (sourceNames.empty()) {
|
||||||
if (sources.empty()) {
|
|
||||||
sourceId = 0;
|
|
||||||
selectedSource.clear();
|
selectedSource.clear();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
auto it = std::find(sourceNames.begin(), sourceNames.end(), name);
|
||||||
|
if (it == sourceNames.end()) {
|
||||||
|
selectSource(sourceNames[0]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sourceId = std::distance(sourceNames.begin(), it);
|
||||||
|
selectedSource = sourceNames[sourceId];
|
||||||
|
sigpath::sourceManager.selectSource(sourceNames[sourceId]);
|
||||||
|
}
|
||||||
|
|
||||||
// If a source with the given name doesn't exist, select the first source instead
|
void onSourceRegistered(std::string name, void* ctx) {
|
||||||
if (!sources.valueExists(name)) {
|
refreshSources();
|
||||||
selectSource(sources.value(0));
|
|
||||||
|
if (selectedSource.empty()) {
|
||||||
|
sourceId = 0;
|
||||||
|
selectSource(sourceNames[0]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the GUI variables
|
sourceId = std::distance(sourceNames.begin(), std::find(sourceNames.begin(), sourceNames.end(), selectedSource));
|
||||||
sourceId = sources.valueId(name);
|
|
||||||
selectedSource = name;
|
|
||||||
|
|
||||||
// Select the source module
|
|
||||||
sigpath::sourceManager.selectSource(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
void onSourcesChanged(std::string name, void* ctx) {
|
|
||||||
// Update the source list
|
|
||||||
refreshSources();
|
|
||||||
|
|
||||||
// Reselect the current source
|
|
||||||
selectSource(selectedSource);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void onSourceUnregister(std::string name, void* ctx) {
|
void onSourceUnregister(std::string name, void* ctx) {
|
||||||
@@ -127,173 +120,60 @@ namespace sourcemenu {
|
|||||||
// TODO: Stop everything
|
// TODO: Stop everything
|
||||||
}
|
}
|
||||||
|
|
||||||
void reloadOffsets() {
|
void onSourceUnregistered(std::string name, void* ctx) {
|
||||||
// Clear list
|
refreshSources();
|
||||||
offsets.clear();
|
|
||||||
namedOffsets.clear();
|
|
||||||
|
|
||||||
// Define special offset modes
|
if (sourceNames.empty()) {
|
||||||
offsets.define("None", OFFSET_ID_NONE);
|
selectedSource = "";
|
||||||
offsets.define("Manual", OFFSET_ID_MANUAL);
|
return;
|
||||||
|
|
||||||
// Acquire the config file
|
|
||||||
core::configManager.acquire();
|
|
||||||
|
|
||||||
// Load custom offsets
|
|
||||||
auto ofs = core::configManager.conf["offsets"].items();
|
|
||||||
for (auto& o : ofs) {
|
|
||||||
namedOffsets[o.key()] = (double)o.value();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Define custom offsets
|
if (name == selectedSource) {
|
||||||
for (auto& [name, offset] : namedOffsets) {
|
sourceId = std::clamp<int>(sourceId, 0, sourceNames.size() - 1);
|
||||||
offsets.define(name, offsets.size());
|
selectSource(sourceNames[sourceId]);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Release the config file
|
sourceId = std::distance(sourceNames.begin(), std::find(sourceNames.begin(), sourceNames.end(), selectedSource));
|
||||||
core::configManager.release();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void init() {
|
void init() {
|
||||||
// Load offset modes
|
|
||||||
reloadOffsets();
|
|
||||||
|
|
||||||
// Define decimation values
|
|
||||||
decimations.define(1, "None", 1);
|
|
||||||
decimations.define(2, "2x", 2);
|
|
||||||
decimations.define(4, "4x", 4);
|
|
||||||
decimations.define(8, "8x", 8);
|
|
||||||
decimations.define(16, "16x", 16);
|
|
||||||
decimations.define(32, "32x", 32);
|
|
||||||
decimations.define(64, "64x", 64);
|
|
||||||
|
|
||||||
// Acquire the config file
|
|
||||||
core::configManager.acquire();
|
core::configManager.acquire();
|
||||||
|
std::string selected = core::configManager.conf["source"];
|
||||||
// Load other settings
|
customOffset = core::configManager.conf["offset"];
|
||||||
std::string selectedSource = core::configManager.conf["source"];
|
offsetMode = core::configManager.conf["offsetMode"];
|
||||||
manualOffset = core::configManager.conf["manualOffset"];
|
decimationPower = core::configManager.conf["decimationPower"];
|
||||||
std::string selectedOffset = core::configManager.conf["selectedOffset"];
|
|
||||||
iqCorrection = core::configManager.conf["iqCorrection"];
|
iqCorrection = core::configManager.conf["iqCorrection"];
|
||||||
invertIQ = core::configManager.conf["invertIQ"];
|
invertIQ = core::configManager.conf["invertIQ"];
|
||||||
int decimation = core::configManager.conf["decimation"];
|
|
||||||
if (decimations.keyExists(decimation)) {
|
|
||||||
decimId = decimations.keyId(decimation);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Release the config file
|
|
||||||
core::configManager.release();
|
|
||||||
|
|
||||||
// Select the source module
|
|
||||||
refreshSources();
|
|
||||||
selectSource(selectedSource);
|
|
||||||
|
|
||||||
// Update frontend settings
|
|
||||||
sigpath::iqFrontEnd.setDCBlocking(iqCorrection);
|
sigpath::iqFrontEnd.setDCBlocking(iqCorrection);
|
||||||
sigpath::iqFrontEnd.setInvertIQ(invertIQ);
|
sigpath::iqFrontEnd.setInvertIQ(invertIQ);
|
||||||
sigpath::iqFrontEnd.setDecimation(decimations.value(decimId));
|
updateOffset();
|
||||||
selectOffsetByName(selectedOffset);
|
|
||||||
|
|
||||||
// Register handlers
|
refreshSources();
|
||||||
sourcesChangedHandler.handler = onSourcesChanged;
|
selectSource(selected);
|
||||||
|
sigpath::iqFrontEnd.setDecimation(1 << decimationPower);
|
||||||
|
|
||||||
|
sourceRegisteredHandler.handler = onSourceRegistered;
|
||||||
sourceUnregisterHandler.handler = onSourceUnregister;
|
sourceUnregisterHandler.handler = onSourceUnregister;
|
||||||
sigpath::sourceManager.onSourceRegistered.bindHandler(&sourcesChangedHandler);
|
sourceUnregisteredHandler.handler = onSourceUnregistered;
|
||||||
|
sigpath::sourceManager.onSourceRegistered.bindHandler(&sourceRegisteredHandler);
|
||||||
sigpath::sourceManager.onSourceUnregister.bindHandler(&sourceUnregisterHandler);
|
sigpath::sourceManager.onSourceUnregister.bindHandler(&sourceUnregisterHandler);
|
||||||
sigpath::sourceManager.onSourceUnregistered.bindHandler(&sourcesChangedHandler);
|
sigpath::sourceManager.onSourceUnregistered.bindHandler(&sourceUnregisteredHandler);
|
||||||
}
|
|
||||||
|
|
||||||
void addOffset(const std::string& name, double offset) {
|
core::configManager.release();
|
||||||
// Acquire the config file
|
|
||||||
core::configManager.acquire();
|
|
||||||
|
|
||||||
// Define a new offset
|
|
||||||
core::configManager.conf["offsets"][name] = offset;
|
|
||||||
|
|
||||||
// Acquire the config file
|
|
||||||
core::configManager.release(true);
|
|
||||||
|
|
||||||
// Reload the offsets
|
|
||||||
reloadOffsets();
|
|
||||||
|
|
||||||
// Attempt to re-select the same one
|
|
||||||
selectOffsetByName(selectedOffset);
|
|
||||||
}
|
|
||||||
|
|
||||||
void delOffset(const std::string& name) {
|
|
||||||
// Acquire the config file
|
|
||||||
core::configManager.acquire();
|
|
||||||
|
|
||||||
// Define a new offset
|
|
||||||
core::configManager.conf["offsets"].erase(name);
|
|
||||||
|
|
||||||
// Acquire the config file
|
|
||||||
core::configManager.release(true);
|
|
||||||
|
|
||||||
// Reload the offsets
|
|
||||||
reloadOffsets();
|
|
||||||
|
|
||||||
// Attempt to re-select the same one
|
|
||||||
selectOffsetByName(selectedOffset);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool addOffsetDialog() {
|
|
||||||
bool open = true;
|
|
||||||
gui::mainWindow.lockWaterfallControls = true;
|
|
||||||
|
|
||||||
float menuWidth = ImGui::GetContentRegionAvail().x;
|
|
||||||
|
|
||||||
const char* id = "Add offset##sdrpp_add_offset_dialog_";
|
|
||||||
ImGui::OpenPopup(id);
|
|
||||||
|
|
||||||
if (ImGui::BeginPopup(id, ImGuiWindowFlags_NoResize)) {
|
|
||||||
ImGui::LeftLabel("Name");
|
|
||||||
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
|
|
||||||
ImGui::InputText("##sdrpp_add_offset_name", newOffsetName, 1023);
|
|
||||||
|
|
||||||
ImGui::LeftLabel("Offset");
|
|
||||||
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
|
|
||||||
ImGui::InputDouble("##sdrpp_add_offset_offset", &newOffset);
|
|
||||||
|
|
||||||
bool nameExists = offsets.nameExists(newOffsetName);
|
|
||||||
bool reservedName = !strcmp(newOffsetName, "None") || !strcmp(newOffsetName, "Manual");
|
|
||||||
bool denyApply = !newOffsetName[0] || nameExists || reservedName;
|
|
||||||
|
|
||||||
if (nameExists) {
|
|
||||||
ImGui::TextColored(ImVec4(1.0f, 0.0f, 0.0f, 1.0f), "An offset with the given name already exists.");
|
|
||||||
}
|
|
||||||
else if (reservedName) {
|
|
||||||
ImGui::TextColored(ImVec4(1.0f, 0.0f, 0.0f, 1.0f), "The given name is reserved.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (denyApply) { style::beginDisabled(); }
|
|
||||||
if (ImGui::Button("Apply")) {
|
|
||||||
addOffset(newOffsetName, newOffset);
|
|
||||||
open = false;
|
|
||||||
}
|
|
||||||
if (denyApply) { style::endDisabled(); }
|
|
||||||
ImGui::SameLine();
|
|
||||||
if (ImGui::Button("Cancel")) {
|
|
||||||
open = false;
|
|
||||||
}
|
|
||||||
ImGui::EndPopup();
|
|
||||||
}
|
|
||||||
return open;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void draw(void* ctx) {
|
void draw(void* ctx) {
|
||||||
float itemWidth = ImGui::GetContentRegionAvail().x;
|
float itemWidth = ImGui::GetContentRegionAvail().x;
|
||||||
float lineHeight = ImGui::GetTextLineHeightWithSpacing();
|
|
||||||
float spacing = lineHeight - ImGui::GetTextLineHeight();
|
|
||||||
bool running = gui::mainWindow.sdrIsRunning();
|
bool running = gui::mainWindow.sdrIsRunning();
|
||||||
|
|
||||||
if (running) { style::beginDisabled(); }
|
if (running) { style::beginDisabled(); }
|
||||||
|
|
||||||
ImGui::SetNextItemWidth(itemWidth);
|
ImGui::SetNextItemWidth(itemWidth);
|
||||||
if (ImGui::Combo("##source", &sourceId, sources.txt)) {
|
if (ImGui::Combo("##source", &sourceId, sourceNamesTxt.c_str())) {
|
||||||
std::string newSource = sources.value(sourceId);
|
selectSource(sourceNames[sourceId]);
|
||||||
selectSource(newSource);
|
|
||||||
core::configManager.acquire();
|
core::configManager.acquire();
|
||||||
core::configManager.conf["source"] = newSource;
|
core::configManager.conf["source"] = sourceNames[sourceId];
|
||||||
core::configManager.release(true);
|
core::configManager.release(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -316,45 +196,21 @@ namespace sourcemenu {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ImGui::LeftLabel("Offset mode");
|
ImGui::LeftLabel("Offset mode");
|
||||||
ImGui::SetNextItemWidth(itemWidth - ImGui::GetCursorPosX() - 2.0f*(lineHeight + 1.5f*spacing));
|
ImGui::SetNextItemWidth(itemWidth - ImGui::GetCursorPosX());
|
||||||
if (ImGui::Combo("##_sdrpp_offset", &offsetId, offsets.txt)) {
|
if (ImGui::Combo("##_sdrpp_offset_mode", &offsetMode, offsetModesTxt)) {
|
||||||
selectOffsetById(offsetId);
|
updateOffset();
|
||||||
core::configManager.acquire();
|
core::configManager.acquire();
|
||||||
core::configManager.conf["selectedOffset"] = offsets.key(offsetId);
|
core::configManager.conf["offsetMode"] = offsetMode;
|
||||||
core::configManager.release(true);
|
core::configManager.release(true);
|
||||||
}
|
}
|
||||||
ImGui::SameLine();
|
|
||||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX() - spacing);
|
|
||||||
if (offsetId < OFFSET_ID_CUSTOM_BASE) { ImGui::BeginDisabled(); }
|
|
||||||
if (ImGui::Button("-##_sdrpp_offset_del_", ImVec2(lineHeight + 0.5f*spacing, 0))) {
|
|
||||||
delOffsetName = selectedOffset;
|
|
||||||
showDelOffsetDialog = true;
|
|
||||||
}
|
|
||||||
if (offsetId < OFFSET_ID_CUSTOM_BASE) { ImGui::EndDisabled(); }
|
|
||||||
ImGui::SameLine();
|
|
||||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX() - spacing);
|
|
||||||
if (ImGui::Button("+##_sdrpp_offset_add_", ImVec2(lineHeight + 0.5f*spacing, 0))) {
|
|
||||||
strcpy(newOffsetName, "New Offset");
|
|
||||||
showAddOffsetDialog = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Offset delete confirmation
|
|
||||||
if (ImGui::GenericDialog("sdrpp_del_offset_confirm", showDelOffsetDialog, GENERIC_DIALOG_BUTTONS_YES_NO, []() {
|
|
||||||
ImGui::Text("Deleting offset named \"%s\". Are you sure?", delOffsetName.c_str());
|
|
||||||
}) == GENERIC_DIALOG_BUTTON_YES) {
|
|
||||||
delOffset(delOffsetName);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Offset add diaglog
|
|
||||||
if (showAddOffsetDialog) { showAddOffsetDialog = addOffsetDialog(); }
|
|
||||||
|
|
||||||
ImGui::LeftLabel("Offset");
|
ImGui::LeftLabel("Offset");
|
||||||
ImGui::FillWidth();
|
ImGui::SetNextItemWidth(itemWidth - ImGui::GetCursorPosX());
|
||||||
if (offsetId == OFFSET_ID_MANUAL) {
|
if (offsetMode == OFFSET_MODE_CUSTOM) {
|
||||||
if (ImGui::InputDouble("##freq_offset", &manualOffset, 1.0, 100.0)) {
|
if (ImGui::InputDouble("##freq_offset", &customOffset, 1.0, 100.0)) {
|
||||||
updateOffset();
|
updateOffset();
|
||||||
core::configManager.acquire();
|
core::configManager.acquire();
|
||||||
core::configManager.conf["manualOffset"] = manualOffset;
|
core::configManager.conf["offset"] = customOffset;
|
||||||
core::configManager.release(true);
|
core::configManager.release(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -366,11 +222,11 @@ namespace sourcemenu {
|
|||||||
|
|
||||||
if (running) { style::beginDisabled(); }
|
if (running) { style::beginDisabled(); }
|
||||||
ImGui::LeftLabel("Decimation");
|
ImGui::LeftLabel("Decimation");
|
||||||
ImGui::FillWidth();
|
ImGui::SetNextItemWidth(itemWidth - ImGui::GetCursorPosX());
|
||||||
if (ImGui::Combo("##source_decim", &decimId, decimations.txt)) {
|
if (ImGui::Combo("##source_decim", &decimationPower, decimationStages)) {
|
||||||
sigpath::iqFrontEnd.setDecimation(decimations.value(decimId));
|
sigpath::iqFrontEnd.setDecimation(1 << decimationPower);
|
||||||
core::configManager.acquire();
|
core::configManager.acquire();
|
||||||
core::configManager.conf["decimation"] = decimations.key(decimId);
|
core::configManager.conf["decimationPower"] = decimationPower;
|
||||||
core::configManager.release(true);
|
core::configManager.release(true);
|
||||||
}
|
}
|
||||||
if (running) { style::endDisabled(); }
|
if (running) { style::endDisabled(); }
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
#include <gui/style.h>
|
#include <gui/style.h>
|
||||||
#include <gui/gui.h>
|
#include <gui/gui.h>
|
||||||
#include <backend.h>
|
#include <backend.h>
|
||||||
#include <utils/hrfreq.h>
|
|
||||||
|
|
||||||
#ifndef IMGUI_DEFINE_MATH_OPERATORS
|
#ifndef IMGUI_DEFINE_MATH_OPERATORS
|
||||||
#define IMGUI_DEFINE_MATH_OPERATORS
|
#define IMGUI_DEFINE_MATH_OPERATORS
|
||||||
@@ -91,7 +90,6 @@ void FrequencySelect::moveCursorToDigit(int i) {
|
|||||||
|
|
||||||
void FrequencySelect::draw() {
|
void FrequencySelect::draw() {
|
||||||
auto window = ImGui::GetCurrentWindow();
|
auto window = ImGui::GetCurrentWindow();
|
||||||
auto io = ImGui::GetIO();
|
|
||||||
widgetPos = ImGui::GetWindowContentRegionMin();
|
widgetPos = ImGui::GetWindowContentRegionMin();
|
||||||
ImVec2 cursorPos = ImGui::GetCursorPos();
|
ImVec2 cursorPos = ImGui::GetCursorPos();
|
||||||
widgetPos.x += window->Pos.x + cursorPos.x;
|
widgetPos.x += window->Pos.x + cursorPos.x;
|
||||||
@@ -134,7 +132,7 @@ void FrequencySelect::draw() {
|
|||||||
ImVec2 mousePos = ImGui::GetMousePos();
|
ImVec2 mousePos = ImGui::GetMousePos();
|
||||||
bool leftClick = ImGui::IsMouseClicked(ImGuiMouseButton_Left);
|
bool leftClick = ImGui::IsMouseClicked(ImGuiMouseButton_Left);
|
||||||
bool rightClick = ImGui::IsMouseClicked(ImGuiMouseButton_Right);
|
bool rightClick = ImGui::IsMouseClicked(ImGuiMouseButton_Right);
|
||||||
int mw = io.MouseWheel;
|
int mw = ImGui::GetIO().MouseWheel;
|
||||||
bool onDigit = false;
|
bool onDigit = false;
|
||||||
bool hovered = false;
|
bool hovered = false;
|
||||||
|
|
||||||
@@ -176,7 +174,7 @@ void FrequencySelect::draw() {
|
|||||||
moveCursorToDigit(i + 1);
|
moveCursorToDigit(i + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto chars = io.InputQueueCharacters;
|
auto chars = ImGui::GetIO().InputQueueCharacters;
|
||||||
|
|
||||||
// For each keyboard characters, type it
|
// For each keyboard characters, type it
|
||||||
for (int j = 0; j < chars.Size; j++) {
|
for (int j = 0; j < chars.Size; j++) {
|
||||||
@@ -196,34 +194,6 @@ void FrequencySelect::draw() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
digitHovered = hovered;
|
digitHovered = hovered;
|
||||||
|
|
||||||
if (isInArea(mousePos, digitTopMins[0], digitBottomMaxs[11])) {
|
|
||||||
bool shortcutKey = io.ConfigMacOSXBehaviors ? (io.KeyMods == ImGuiKeyModFlags_Super) : (io.KeyMods == ImGuiKeyModFlags_Ctrl);
|
|
||||||
bool ctrlOnly = (io.KeyMods == ImGuiKeyModFlags_Ctrl);
|
|
||||||
bool shiftOnly = (io.KeyMods == ImGuiKeyModFlags_Shift);
|
|
||||||
bool copy = ((shortcutKey && ImGui::IsKeyPressed(ImGuiKey_C)) || (ctrlOnly && ImGui::IsKeyPressed(ImGuiKey_Insert)));
|
|
||||||
bool paste = ((shortcutKey && ImGui::IsKeyPressed(ImGuiKey_V)) || (shiftOnly && ImGui::IsKeyPressed(ImGuiKey_Insert)));
|
|
||||||
if (copy) {
|
|
||||||
// Convert the freqency to a string
|
|
||||||
std::string freqStr = hrfreq::toString(frequency);
|
|
||||||
|
|
||||||
// Write it to the clipboard
|
|
||||||
ImGui::SetClipboardText(freqStr.c_str());
|
|
||||||
}
|
|
||||||
if (paste) {
|
|
||||||
// Attempt to parse the clipboard as a number
|
|
||||||
const char* clip = ImGui::GetClipboardText();
|
|
||||||
|
|
||||||
// If the clipboard is not empty, attempt to parse it
|
|
||||||
if (clip) {
|
|
||||||
double newFreq;
|
|
||||||
if (hrfreq::fromString(clip, newFreq)) {
|
|
||||||
setFrequency(abs(newFreq));
|
|
||||||
frequencyChanged = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t freq = 0;
|
uint64_t freq = 0;
|
||||||
|
|||||||
@@ -85,8 +85,8 @@ void SourceManager::tune(double freq) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// TODO: No need to always retune the hardware in Panadapter mode
|
// TODO: No need to always retune the hardware in Panadapter mode
|
||||||
selectedHandler->tuneHandler(abs(((tuneMode == TuningMode::NORMAL) ? (freq + tuneOffset) : ifFreq)), selectedHandler->ctx);
|
selectedHandler->tuneHandler(((tuneMode == TuningMode::NORMAL) ? freq : ifFreq) + tuneOffset, selectedHandler->ctx);
|
||||||
onRetune.emit(freq + tuneOffset);
|
onRetune.emit(freq);
|
||||||
currentFreq = freq;
|
currentFreq = freq;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,120 +0,0 @@
|
|||||||
#include "hrfreq.h"
|
|
||||||
#include <utils/flog.h>
|
|
||||||
|
|
||||||
namespace hrfreq {
|
|
||||||
|
|
||||||
|
|
||||||
std::string toString(double freq) {
|
|
||||||
// Determine the scale
|
|
||||||
int maxDecimals = 0;
|
|
||||||
const char* suffix = "Hz";
|
|
||||||
if (freq >= 1e9) {
|
|
||||||
freq /= 1e9;
|
|
||||||
maxDecimals = 9;
|
|
||||||
suffix = "GHz";
|
|
||||||
}
|
|
||||||
else if (freq >= 1e6) {
|
|
||||||
freq /= 1e6;
|
|
||||||
maxDecimals = 6;
|
|
||||||
suffix = "MHz";
|
|
||||||
}
|
|
||||||
else if (freq >= 1e3) {
|
|
||||||
freq /= 1e3;
|
|
||||||
maxDecimals = 3;
|
|
||||||
suffix = "KHz";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert to string (TODO: Not sure if limiting the decimals rounds)
|
|
||||||
char numBuf[128];
|
|
||||||
int numLen = sprintf(numBuf, "%0.*lf", maxDecimals, freq);
|
|
||||||
|
|
||||||
// If there is a decimal point, remove the useless zeros
|
|
||||||
if (maxDecimals) {
|
|
||||||
for (int i = numLen-1; i >= 0; i--) {
|
|
||||||
bool dot = (numBuf[i] == '.');
|
|
||||||
if (numBuf[i] != '0' && !dot) { break; }
|
|
||||||
numBuf[i] = 0;
|
|
||||||
if (dot) { break; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Concat the suffix
|
|
||||||
char finalBuf[128];
|
|
||||||
sprintf(finalBuf, "%s%s", numBuf, suffix);
|
|
||||||
|
|
||||||
// Return the final string
|
|
||||||
return finalBuf;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isNumeric(char c) {
|
|
||||||
return std::isdigit(c) || c == '+' || c == '-' || c == '.' || c == ',';
|
|
||||||
}
|
|
||||||
|
|
||||||
bool fromString(const std::string& str, double& freq) {
|
|
||||||
// Skip non-numeric characters
|
|
||||||
int i = 0;
|
|
||||||
char c;
|
|
||||||
for (; i < str.size(); i++) {
|
|
||||||
if (isNumeric(str[i])) { break; }
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extract the numeric part
|
|
||||||
std::string numeric;
|
|
||||||
for (; i < str.size(); i++) {
|
|
||||||
// Get the character
|
|
||||||
c = str[i];
|
|
||||||
|
|
||||||
// If it's a letter, stop
|
|
||||||
if (std::isalpha(c)) { break; }
|
|
||||||
|
|
||||||
// If isn't numeric, skip it
|
|
||||||
if (!isNumeric(c)) { continue; }
|
|
||||||
|
|
||||||
// If it's a comma, skip it for now. This enforces a dot as a decimal point
|
|
||||||
if (c == ',') { continue; }
|
|
||||||
|
|
||||||
// Add the character to the numeric string
|
|
||||||
numeric += c;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Attempt to parse the numeric part
|
|
||||||
double num;
|
|
||||||
try {
|
|
||||||
num = std::stod(numeric);
|
|
||||||
}
|
|
||||||
catch (const std::exception& e) {
|
|
||||||
flog::error("Failed to parse numeric part: '{}'", numeric);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If no more text is available, assume the numeric part gives a frequency in Hz
|
|
||||||
if (i == str.size()) {
|
|
||||||
flog::warn("No unit given, assuming it's Hz");
|
|
||||||
freq = num;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scale the numeric value depending on the first scale character
|
|
||||||
char scale = std::toupper(str[i]);
|
|
||||||
switch (scale) {
|
|
||||||
case 'G':
|
|
||||||
num *= 1e9;
|
|
||||||
break;
|
|
||||||
case 'M':
|
|
||||||
num *= 1e6;
|
|
||||||
break;
|
|
||||||
case 'K':
|
|
||||||
num *= 1e3;
|
|
||||||
break;
|
|
||||||
case 'H':
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
flog::warn("Unknown frequency scale: '{}'", scale);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the frequency
|
|
||||||
freq = num;
|
|
||||||
return true; // TODO
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace hrfreq {
|
|
||||||
/**
|
|
||||||
* Convert a frequency to a human-readable string.
|
|
||||||
* @param freq Frequency in Hz.
|
|
||||||
* @return Human-readable representation of the frequency.
|
|
||||||
*/
|
|
||||||
std::string toString(double freq);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert a human-readable representation of a frequency to a frequency value.
|
|
||||||
* @param str String containing the human-readable frequency.
|
|
||||||
* @param freq Value to write the decoded frequency to.
|
|
||||||
* @return True on success, false otherwise.
|
|
||||||
*/
|
|
||||||
bool fromString(const std::string& str, double& freq);
|
|
||||||
}
|
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define VERSION_STR "1.3.0"
|
#define VERSION_STR "1.2.0"
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <dsp/processor.h>
|
|
||||||
#include <dsp/math/fast_atan2.h>
|
|
||||||
#include <dsp/math/hz_to_rads.h>
|
|
||||||
#include <dsp/math/normalize_phase.h>
|
|
||||||
|
|
||||||
namespace dsp::demod {
|
|
||||||
class Amplitude : public Processor<complex_t, float> {
|
|
||||||
using base_type = Processor<complex_t, float>;
|
|
||||||
public:
|
|
||||||
Amplitude() {}
|
|
||||||
|
|
||||||
Amplitude(stream<complex_t>* in, double deviation) { init(in, deviation); }
|
|
||||||
|
|
||||||
Amplitude(stream<complex_t>* in, double deviation, double samplerate) { init(in, deviation, samplerate); }
|
|
||||||
|
|
||||||
|
|
||||||
virtual void init(stream<complex_t>* in, double deviation) {
|
|
||||||
_invDeviation = 1.0 / deviation;
|
|
||||||
base_type::init(in);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void init(stream<complex_t>* in, double deviation, double samplerate) {
|
|
||||||
init(in, math::hzToRads(deviation, samplerate));
|
|
||||||
}
|
|
||||||
|
|
||||||
void setDeviation(double deviation) {
|
|
||||||
assert(base_type::_block_init);
|
|
||||||
std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
|
|
||||||
_invDeviation = 1.0 / deviation;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setDeviation(double deviation, double samplerate) {
|
|
||||||
assert(base_type::_block_init);
|
|
||||||
std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
|
|
||||||
_invDeviation = 1.0 / math::hzToRads(deviation, samplerate);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int process(int count, complex_t* in, float* out) {
|
|
||||||
volk_32fc_magnitude_32f(out, (lv_32fc_t*)in, count);
|
|
||||||
volk_32f_s32f_multiply_32f(out, out, -1.0f, count);
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
void reset() {
|
|
||||||
assert(base_type::_block_init);
|
|
||||||
std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
|
|
||||||
phase = 0.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
int run() {
|
|
||||||
int count = base_type::_in->read();
|
|
||||||
if (count < 0) { return -1; }
|
|
||||||
|
|
||||||
process(count, base_type::_in->readBuf, base_type::out.writeBuf);
|
|
||||||
|
|
||||||
base_type::_in->flush();
|
|
||||||
if (!base_type::out.swap(count)) { return -1; }
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
float _invDeviation;
|
|
||||||
float phase = 0.0f;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,176 +0,0 @@
|
|||||||
617 + 6 -> I
|
|
||||||
|
|
||||||
304 + 6 -> II
|
|
||||||
|
|
||||||
616 + 6 -> III
|
|
||||||
|
|
||||||
305 + 6 -> IV
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
304
|
|
||||||
305
|
|
||||||
306
|
|
||||||
307
|
|
||||||
308
|
|
||||||
309
|
|
||||||
310
|
|
||||||
311
|
|
||||||
312
|
|
||||||
|
|
||||||
616
|
|
||||||
617
|
|
||||||
618
|
|
||||||
619
|
|
||||||
620
|
|
||||||
621
|
|
||||||
622
|
|
||||||
623
|
|
||||||
624
|
|
||||||
|
|
||||||
305
|
|
||||||
306
|
|
||||||
307
|
|
||||||
308
|
|
||||||
309
|
|
||||||
310
|
|
||||||
311
|
|
||||||
312
|
|
||||||
313
|
|
||||||
|
|
||||||
617
|
|
||||||
618
|
|
||||||
619
|
|
||||||
620
|
|
||||||
621
|
|
||||||
622
|
|
||||||
623
|
|
||||||
624
|
|
||||||
0
|
|
||||||
|
|
||||||
304
|
|
||||||
305
|
|
||||||
306
|
|
||||||
307
|
|
||||||
308
|
|
||||||
309
|
|
||||||
310
|
|
||||||
311
|
|
||||||
312
|
|
||||||
616
|
|
||||||
617
|
|
||||||
618
|
|
||||||
619
|
|
||||||
620
|
|
||||||
621
|
|
||||||
622
|
|
||||||
623
|
|
||||||
624
|
|
||||||
305
|
|
||||||
306
|
|
||||||
307
|
|
||||||
308
|
|
||||||
309
|
|
||||||
310
|
|
||||||
311
|
|
||||||
312
|
|
||||||
313
|
|
||||||
617
|
|
||||||
618
|
|
||||||
619
|
|
||||||
620
|
|
||||||
621
|
|
||||||
622
|
|
||||||
623
|
|
||||||
624
|
|
||||||
0
|
|
||||||
304
|
|
||||||
305
|
|
||||||
306
|
|
||||||
307
|
|
||||||
308
|
|
||||||
309
|
|
||||||
310
|
|
||||||
311
|
|
||||||
312
|
|
||||||
616
|
|
||||||
617
|
|
||||||
618
|
|
||||||
619
|
|
||||||
620
|
|
||||||
621
|
|
||||||
622
|
|
||||||
623
|
|
||||||
624
|
|
||||||
305
|
|
||||||
306
|
|
||||||
307
|
|
||||||
308
|
|
||||||
309
|
|
||||||
310
|
|
||||||
311
|
|
||||||
312
|
|
||||||
313
|
|
||||||
617
|
|
||||||
618
|
|
||||||
619
|
|
||||||
620
|
|
||||||
621
|
|
||||||
622
|
|
||||||
623
|
|
||||||
624
|
|
||||||
0
|
|
||||||
304
|
|
||||||
305
|
|
||||||
306
|
|
||||||
307
|
|
||||||
308
|
|
||||||
309
|
|
||||||
310
|
|
||||||
311
|
|
||||||
312
|
|
||||||
616
|
|
||||||
617
|
|
||||||
618
|
|
||||||
619
|
|
||||||
620
|
|
||||||
621
|
|
||||||
622
|
|
||||||
623
|
|
||||||
624
|
|
||||||
305
|
|
||||||
306
|
|
||||||
307
|
|
||||||
308
|
|
||||||
309
|
|
||||||
310
|
|
||||||
311
|
|
||||||
312
|
|
||||||
313
|
|
||||||
617
|
|
||||||
618
|
|
||||||
619
|
|
||||||
620
|
|
||||||
621
|
|
||||||
622
|
|
||||||
623
|
|
||||||
624
|
|
||||||
0
|
|
||||||
304
|
|
||||||
305
|
|
||||||
306
|
|
||||||
307
|
|
||||||
308
|
|
||||||
309
|
|
||||||
310
|
|
||||||
311
|
|
||||||
312
|
|
||||||
616
|
|
||||||
617
|
|
||||||
618
|
|
||||||
619
|
|
||||||
620
|
|
||||||
621
|
|
||||||
622
|
|
||||||
623
|
|
||||||
624
|
|
||||||
63
decoder_modules/atv_decoder/src/chroma_pll.h
Normal file
63
decoder_modules/atv_decoder/src/chroma_pll.h
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <dsp/loop/pll.h>
|
||||||
|
#include "chrominance_filter.h"
|
||||||
|
|
||||||
|
// TODO: Should be 60 but had to try something
|
||||||
|
#define BURST_START (63+CHROMA_FIR_DELAY)
|
||||||
|
#define BURST_END (BURST_START+28)
|
||||||
|
|
||||||
|
#define A_PHASE ((135.0/180.0)*FL_M_PI)
|
||||||
|
#define B_PHASE ((-135.0/180.0)*FL_M_PI)
|
||||||
|
|
||||||
|
namespace dsp::loop {
|
||||||
|
class ChromaPLL : public PLL {
|
||||||
|
using base_type = PLL;
|
||||||
|
public:
|
||||||
|
ChromaPLL() {}
|
||||||
|
|
||||||
|
ChromaPLL(stream<complex_t>* in, double bandwidth, double initPhase = 0.0, double initFreq = 0.0, double minFreq = -FL_M_PI, double maxFreq = FL_M_PI) {
|
||||||
|
base_type::init(in, bandwidth, initFreq, initPhase, minFreq, maxFreq);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int process(int count, complex_t* in, complex_t* out, bool aphase = false) {
|
||||||
|
// Process the pre-burst section
|
||||||
|
for (int i = 0; i < BURST_START; i++) {
|
||||||
|
out[i] = in[i] * math::phasor(-pcl.phase);
|
||||||
|
pcl.advancePhase();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process the burst itself
|
||||||
|
if (aphase) {
|
||||||
|
for (int i = BURST_START; i < BURST_END; i++) {
|
||||||
|
complex_t outVal = in[i] * math::phasor(-pcl.phase);
|
||||||
|
out[i] = outVal;
|
||||||
|
pcl.advance(math::normalizePhase(outVal.phase() - A_PHASE));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (int i = BURST_START; i < BURST_END; i++) {
|
||||||
|
complex_t outVal = in[i] * math::phasor(-pcl.phase);
|
||||||
|
out[i] = outVal;
|
||||||
|
pcl.advance(math::normalizePhase(outVal.phase() - B_PHASE));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Process the post-burst section
|
||||||
|
for (int i = BURST_END; i < count; i++) {
|
||||||
|
out[i] = in[i] * math::phasor(-pcl.phase);
|
||||||
|
pcl.advancePhase();
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int processBlank(int count, complex_t* in, complex_t* out) {
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
out[i] = in[i] * math::phasor(-pcl.phase);
|
||||||
|
pcl.advancePhase();
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
239
decoder_modules/atv_decoder/src/chrominance_filter.h
Normal file
239
decoder_modules/atv_decoder/src/chrominance_filter.h
Normal file
@@ -0,0 +1,239 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <dsp/types.h>
|
||||||
|
|
||||||
|
inline const dsp::complex_t CHROMA_FIR[] = {
|
||||||
|
{-0.000005461290583903, -0.000011336784355655},
|
||||||
|
{ 0.000020060944485414, 0.000009851315045203},
|
||||||
|
{-0.000034177222729438, 0.000007245841504981},
|
||||||
|
{ 0.000027694034878705, -0.000033114740542635},
|
||||||
|
{-0.000001217597841648, 0.000039141482370942},
|
||||||
|
{-0.000008324593371228, -0.000011315001355976},
|
||||||
|
{-0.000038085228233509, -0.000010585909953738},
|
||||||
|
{ 0.000114833396071141, -0.000047778708840608},
|
||||||
|
{-0.000115428390169113, 0.000205816198882814},
|
||||||
|
{-0.000055467806072871, -0.000356692479491626},
|
||||||
|
{ 0.000349316846854190, 0.000326162940234916},
|
||||||
|
{-0.000558465829929114, -0.000048001521408724},
|
||||||
|
{ 0.000488176200631416, -0.000319593757302922},
|
||||||
|
{-0.000169437838021935, 0.000501610900725908},
|
||||||
|
{-0.000131793335799502, -0.000373003580727547},
|
||||||
|
{ 0.000166817395492786, 0.000105930895534474},
|
||||||
|
{ 0.000030499908326112, -0.000003048682668943},
|
||||||
|
{-0.000174999505027919, 0.000168008090089458},
|
||||||
|
{ 0.000054431163395030, -0.000385174790951272},
|
||||||
|
{ 0.000215876012859739, 0.000372695852521209},
|
||||||
|
{-0.000325534912280750, -0.000130173041693966},
|
||||||
|
{ 0.000154951430569290, -0.000045395998708328},
|
||||||
|
{ 0.000054324657659002, -0.000076028700470037},
|
||||||
|
{ 0.000015664427565764, 0.000348002612845696},
|
||||||
|
{-0.000345943017888332, -0.000402175417043307},
|
||||||
|
{ 0.000568731727879741, 0.000112347863435682},
|
||||||
|
{-0.000416485880859085, 0.000211750352828909},
|
||||||
|
{ 0.000087462353623011, -0.000188197153014309},
|
||||||
|
{-0.000032082305030264, -0.000136804226080664},
|
||||||
|
{ 0.000379089999045955, 0.000303466839685362},
|
||||||
|
{-0.000726760198519770, -0.000007022279302816},
|
||||||
|
{ 0.000619888661818195, -0.000476871323359809},
|
||||||
|
{-0.000151885493742993, 0.000595641190573181},
|
||||||
|
{-0.000100626407015494, -0.000227947144491108},
|
||||||
|
{-0.000201935458823941, -0.000107628631934340},
|
||||||
|
{ 0.000680260922139900, -0.000120771182888852},
|
||||||
|
{-0.000666108629277491, 0.000744775901128973},
|
||||||
|
{ 0.000067236591919755, -0.001044125966364420},
|
||||||
|
{ 0.000447037274751822, 0.000651912509450913},
|
||||||
|
{-0.000262675893448686, -0.000082499729563337},
|
||||||
|
{-0.000349821460486320, 0.000132102793530818},
|
||||||
|
{ 0.000507024815168287, -0.000837598610490618},
|
||||||
|
{ 0.000163814255478652, 0.001346530693477834},
|
||||||
|
{-0.000970457632383793, -0.000968411010101160},
|
||||||
|
{ 0.000974834882891140, 0.000116507082762032},
|
||||||
|
{-0.000225464280571542, 0.000137131865995708},
|
||||||
|
{-0.000211542240694642, 0.000563783548428947},
|
||||||
|
{-0.000414412310798766, -0.001309793399193736},
|
||||||
|
{ 0.001497010004594478, 0.001021907858926259},
|
||||||
|
{-0.001752019159639658, 0.000116536066154131},
|
||||||
|
{ 0.000872822027879430, -0.000783952720205569},
|
||||||
|
{-0.000032439446797970, 0.000184988059956734},
|
||||||
|
{ 0.000446259382722895, 0.000833040920509238},
|
||||||
|
{-0.001741577737284306, -0.000764423771425237},
|
||||||
|
{ 0.002306569133792772, -0.000593352416441601},
|
||||||
|
{-0.001336084746214192, 0.001744394557524181},
|
||||||
|
{-0.000015810020735495, -0.001342809547658260},
|
||||||
|
{ 0.000007636494885364, 0.000009498318627546},
|
||||||
|
{ 0.001403876768349702, 0.000326101441888391},
|
||||||
|
{-0.002351020828600226, 0.001098649819278302},
|
||||||
|
{ 0.001389314639579544, -0.002746943712072884},
|
||||||
|
{ 0.000526319899588909, 0.002635084366837732},
|
||||||
|
{-0.001109526585744687, -0.000950323796527721},
|
||||||
|
{-0.000307792427984886, -0.000013203419520794},
|
||||||
|
{ 0.001737955094951111, -0.001247368808692850},
|
||||||
|
{-0.000974502437588420, 0.003352512117661680},
|
||||||
|
{-0.001462571137390936, -0.003635296917435679},
|
||||||
|
{ 0.002783459090201693, 0.001604420226187745},
|
||||||
|
{-0.001471518558760170, 0.000211117948702137},
|
||||||
|
{-0.000575340825070194, 0.000601820846100026},
|
||||||
|
{ 0.000302090333345692, -0.003088058972305493},
|
||||||
|
{ 0.002496092353182990, 0.003912508340989065},
|
||||||
|
{-0.004645661091012423, -0.001630427298020200},
|
||||||
|
{ 0.003556824805628799, -0.001209822327859352},
|
||||||
|
{-0.000744999556260706, 0.001143238699138109},
|
||||||
|
{ 0.000144278726929409, 0.001638049051599065},
|
||||||
|
{-0.003025291044450178, -0.003226370992887968},
|
||||||
|
{ 0.006047866290490120, 0.000927406808799887},
|
||||||
|
{-0.005338456415106141, 0.003008811999350399},
|
||||||
|
{ 0.001642959659014839, -0.003972384205231079},
|
||||||
|
{ 0.000273874932822212, 0.000977326273749033},
|
||||||
|
{ 0.002315022846573390, 0.001695671268241410},
|
||||||
|
{-0.006240953957978884, 0.000207330368698293},
|
||||||
|
{ 0.006164252120861735, -0.005177351717451013},
|
||||||
|
{-0.001560310257561104, 0.007437030759707700},
|
||||||
|
{-0.002131333814462852, -0.004317129694157112},
|
||||||
|
{ 0.000280518918541908, 0.000134405998842553},
|
||||||
|
{ 0.004612116481180659, -0.001024468120657814},
|
||||||
|
{-0.005599300279638699, 0.006828277067771868},
|
||||||
|
{ 0.000228879728552504, -0.010675998154712657},
|
||||||
|
{ 0.005692081512980654, 0.007582243186569848},
|
||||||
|
{-0.005100500569859509, -0.001364751685737153},
|
||||||
|
{-0.000902490398043454, 0.000385770160220703},
|
||||||
|
{ 0.003673858819546609, -0.006701685283451640},
|
||||||
|
{ 0.002079056046131593, 0.012568579063417429},
|
||||||
|
{-0.010730008156911677, -0.009826454574016218},
|
||||||
|
{ 0.012092401380903161, 0.000921764172237851},
|
||||||
|
{-0.004714530989129091, 0.003151948807627123},
|
||||||
|
{-0.001055930168838909, 0.003228576712467020},
|
||||||
|
{-0.004343270165991213, -0.011924332879354394},
|
||||||
|
{ 0.016499994418955999, 0.010255324919126899},
|
||||||
|
{-0.021047239750251585, 0.002309419513135448},
|
||||||
|
{ 0.011855513874047341, -0.011604071033866310},
|
||||||
|
{-0.000777842281358575, 0.005916341648175263},
|
||||||
|
{ 0.004380939277688377, 0.007397670455730446},
|
||||||
|
{-0.021891594662401131, -0.008509480947490166},
|
||||||
|
{ 0.032787638290674201, -0.009950745850861956},
|
||||||
|
{-0.021022579272463194, 0.030030850567389102},
|
||||||
|
{-0.001508145650189953, -0.027571914870304640},
|
||||||
|
{ 0.004056649693022923, 0.004624901687718579},
|
||||||
|
{ 0.025728742586666287, 0.004824671348397606},
|
||||||
|
{-0.058002700931665603, 0.030198618296813803},
|
||||||
|
{ 0.043631619628438784, -0.096308304333327280},
|
||||||
|
{ 0.033451363423624300, 0.136687079396426990},
|
||||||
|
{-0.129387018420204200, -0.101540513046619400},
|
||||||
|
{ 0.172881344826560730, -0.000000000000005297},
|
||||||
|
{-0.129387018420198010, 0.101540513046627330},
|
||||||
|
{ 0.033451363423615862, -0.136687079396429050},
|
||||||
|
{ 0.043631619628444723, 0.096308304333324601},
|
||||||
|
{-0.058002700931667456, -0.030198618296810247},
|
||||||
|
{ 0.025728742586665992, -0.004824671348399184},
|
||||||
|
{ 0.004056649693022639, -0.004624901687718827},
|
||||||
|
{-0.001508145650188251, 0.027571914870304734},
|
||||||
|
{-0.021022579272465047, -0.030030850567387805},
|
||||||
|
{ 0.032787638290674812, 0.009950745850859947},
|
||||||
|
{-0.021891594662400610, 0.008509480947491507},
|
||||||
|
{ 0.004380939277687923, -0.007397670455730714},
|
||||||
|
{-0.000777842281358940, -0.005916341648175215},
|
||||||
|
{ 0.011855513874048058, 0.011604071033865578},
|
||||||
|
{-0.021047239750251731, -0.002309419513134139},
|
||||||
|
{ 0.016499994418955360, -0.010255324919127926},
|
||||||
|
{-0.004343270165990471, 0.011924332879354665},
|
||||||
|
{-0.001055930168839110, -0.003228576712466955},
|
||||||
|
{-0.004714530989129287, -0.003151948807626830},
|
||||||
|
{ 0.012092401380903103, -0.000921764172238603},
|
||||||
|
{-0.010730008156911072, 0.009826454574016881},
|
||||||
|
{ 0.002079056046130817, -0.012568579063417559},
|
||||||
|
{ 0.003673858819547020, 0.006701685283451416},
|
||||||
|
{-0.000902490398043478, -0.000385770160220647},
|
||||||
|
{-0.005100500569859424, 0.001364751685737466},
|
||||||
|
{ 0.005692081512980187, -0.007582243186570198},
|
||||||
|
{ 0.000228879728553163, 0.010675998154712643},
|
||||||
|
{-0.005599300279639117, -0.006828277067771524},
|
||||||
|
{ 0.004612116481180722, 0.001024468120657532},
|
||||||
|
{ 0.000280518918541900, -0.000134405998842571},
|
||||||
|
{-0.002131333814462586, 0.004317129694157243},
|
||||||
|
{-0.001560310257561563, -0.007437030759707604},
|
||||||
|
{ 0.006164252120862052, 0.005177351717450635},
|
||||||
|
{-0.006240953957978898, -0.000207330368697911},
|
||||||
|
{ 0.002315022846573286, -0.001695671268241552},
|
||||||
|
{ 0.000273874932822152, -0.000977326273749050},
|
||||||
|
{ 0.001642959659015084, 0.003972384205230976},
|
||||||
|
{-0.005338456415106324, -0.003008811999350072},
|
||||||
|
{ 0.006047866290490063, -0.000927406808800258},
|
||||||
|
{-0.003025291044449980, 0.003226370992888153},
|
||||||
|
{ 0.000144278726929308, -0.001638049051599074},
|
||||||
|
{-0.000744999556260777, -0.001143238699138063},
|
||||||
|
{ 0.003556824805628873, 0.001209822327859134},
|
||||||
|
{-0.004645661091012323, 0.001630427298020484},
|
||||||
|
{ 0.002496092353182751, -0.003912508340989219},
|
||||||
|
{ 0.000302090333345882, 0.003088058972305475},
|
||||||
|
{-0.000575340825070231, -0.000601820846099991},
|
||||||
|
{-0.001471518558760183, -0.000211117948702046},
|
||||||
|
{ 0.002783459090201593, -0.001604420226187919},
|
||||||
|
{-0.001462571137390710, 0.003635296917435769},
|
||||||
|
{-0.000974502437588628, -0.003352512117661619},
|
||||||
|
{ 0.001737955094951189, 0.001247368808692742},
|
||||||
|
{-0.000307792427984885, 0.000013203419520814},
|
||||||
|
{-0.001109526585744628, 0.000950323796527789},
|
||||||
|
{ 0.000526319899588746, -0.002635084366837765},
|
||||||
|
{ 0.001389314639579712, 0.002746943712072799},
|
||||||
|
{-0.002351020828600294, -0.001098649819278158},
|
||||||
|
{ 0.001403876768349682, -0.000326101441888477},
|
||||||
|
{ 0.000007636494885364, -0.000009498318627546},
|
||||||
|
{-0.000015810020735412, 0.001342809547658261},
|
||||||
|
{-0.001336084746214299, -0.001744394557524099},
|
||||||
|
{ 0.002306569133792808, 0.000593352416441460},
|
||||||
|
{-0.001741577737284259, 0.000764423771425344},
|
||||||
|
{ 0.000446259382722843, -0.000833040920509266},
|
||||||
|
{-0.000032439446797982, -0.000184988059956732},
|
||||||
|
{ 0.000872822027879478, 0.000783952720205515},
|
||||||
|
{-0.001752019159639665, -0.000116536066154024},
|
||||||
|
{ 0.001497010004594416, -0.001021907858926351},
|
||||||
|
{-0.000414412310798685, 0.001309793399193761},
|
||||||
|
{-0.000211542240694677, -0.000563783548428934},
|
||||||
|
{-0.000225464280571550, -0.000137131865995694},
|
||||||
|
{ 0.000974834882891133, -0.000116507082762092},
|
||||||
|
{-0.000970457632383734, 0.000968411010101219},
|
||||||
|
{ 0.000163814255478569, -0.001346530693477844},
|
||||||
|
{ 0.000507024815168339, 0.000837598610490586},
|
||||||
|
{-0.000349821460486328, -0.000132102793530797},
|
||||||
|
{-0.000262675893448681, 0.000082499729563353},
|
||||||
|
{ 0.000447037274751782, -0.000651912509450940},
|
||||||
|
{ 0.000067236591919819, 0.001044125966364416},
|
||||||
|
{-0.000666108629277537, -0.000744775901128932},
|
||||||
|
{ 0.000680260922139908, 0.000120771182888810},
|
||||||
|
{-0.000201935458823935, 0.000107628631934352},
|
||||||
|
{-0.000100626407015480, 0.000227947144491114},
|
||||||
|
{-0.000151885493743030, -0.000595641190573172},
|
||||||
|
{ 0.000619888661818225, 0.000476871323359771},
|
||||||
|
{-0.000726760198519770, 0.000007022279302861},
|
||||||
|
{ 0.000379089999045936, -0.000303466839685386},
|
||||||
|
{-0.000032082305030256, 0.000136804226080666},
|
||||||
|
{ 0.000087462353623023, 0.000188197153014303},
|
||||||
|
{-0.000416485880859098, -0.000211750352828883},
|
||||||
|
{ 0.000568731727879734, -0.000112347863435717},
|
||||||
|
{-0.000345943017888307, 0.000402175417043329},
|
||||||
|
{ 0.000015664427565742, -0.000348002612845697},
|
||||||
|
{ 0.000054324657659007, 0.000076028700470034},
|
||||||
|
{ 0.000154951430569292, 0.000045395998708319},
|
||||||
|
{-0.000325534912280742, 0.000130173041693986},
|
||||||
|
{ 0.000215876012859716, -0.000372695852521222},
|
||||||
|
{ 0.000054431163395054, 0.000385174790951269},
|
||||||
|
{-0.000174999505027930, -0.000168008090089447},
|
||||||
|
{ 0.000030499908326113, 0.000003048682668941},
|
||||||
|
{ 0.000166817395492779, -0.000105930895534485},
|
||||||
|
{-0.000131793335799479, 0.000373003580727555},
|
||||||
|
{-0.000169437838021966, -0.000501610900725898},
|
||||||
|
{ 0.000488176200631435, 0.000319593757302892},
|
||||||
|
{-0.000558465829929111, 0.000048001521408758},
|
||||||
|
{ 0.000349316846854170, -0.000326162940234938},
|
||||||
|
{-0.000055467806072849, 0.000356692479491629},
|
||||||
|
{-0.000115428390169126, -0.000205816198882806},
|
||||||
|
{ 0.000114833396071144, 0.000047778708840601},
|
||||||
|
{-0.000038085228233508, 0.000010585909953741},
|
||||||
|
{-0.000008324593371228, 0.000011315001355977},
|
||||||
|
{-0.000001217597841650, -0.000039141482370942},
|
||||||
|
{ 0.000027694034878707, 0.000033114740542633},
|
||||||
|
{-0.000034177222729439, -0.000007245841504979},
|
||||||
|
{ 0.000020060944485413, -0.000009851315045204},
|
||||||
|
{-0.000005461290583903, 0.000011336784355656},
|
||||||
|
};
|
||||||
|
|
||||||
|
#define CHROMA_FIR_SIZE (sizeof(CHROMA_FIR)/sizeof(dsp::complex_t))
|
||||||
|
#define CHROMA_FIR_DELAY ((CHROMA_FIR_SIZE-1)/2)
|
||||||
@@ -1,131 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <dsp/types.h>
|
|
||||||
|
|
||||||
const dsp::complex_t CHROMA_BANDPASS[123] = {
|
|
||||||
{ -0.000007675039564594f, -0.000017362992335168f },
|
|
||||||
{ 0.000050180791439308f, -0.000005054021864311f },
|
|
||||||
{ -0.000022529111707761f, 0.000102942513429095f },
|
|
||||||
{ -0.000157609487484146f, -0.000092618697641464f },
|
|
||||||
{ 0.000205649042029007f, -0.000181710515677257f },
|
|
||||||
{ 0.000143445458895462f, 0.000331994546004200f },
|
|
||||||
{ -0.000414693079508517f, 0.000038265188132615f },
|
|
||||||
{ 0.000090081630021837f, -0.000395731646002122f },
|
|
||||||
{ 0.000257705918065856f, 0.000154354504676150f },
|
|
||||||
{ -0.000064051192147575f, 0.000055648228186439f },
|
|
||||||
{ 0.000089938060647145f, 0.000213032074676941f },
|
|
||||||
{ -0.000604775098099200f, 0.000050706635726124f },
|
|
||||||
{ 0.000223309865890358f, -0.000944433958755193f },
|
|
||||||
{ 0.001049943574694384f, 0.000640863688898729f },
|
|
||||||
{ -0.000983491651119595f, 0.000840133365053179f },
|
|
||||||
{ -0.000417178588714773f, -0.001011686459999295f },
|
|
||||||
{ 0.000616677332283103f, -0.000046513429902547f },
|
|
||||||
{ 0.000018549463752019f, -0.000075619948809012f },
|
|
||||||
{ 0.000734408386201158f, 0.000456742966201638f },
|
|
||||||
{ -0.001192460562555901f, 0.001001510577200253f },
|
|
||||||
{ -0.000729137747758392f, -0.001811046261815935f },
|
|
||||||
{ 0.001878272869910273f, -0.000125879189667096f },
|
|
||||||
{ -0.000312873903977849f, 0.001230889889574772f },
|
|
||||||
{ -0.000142534831707354f, -0.000090307321579771f },
|
|
||||||
{ -0.000942796972567241f, 0.000778470227412111f },
|
|
||||||
{ -0.000945381510920278f, -0.002406055808135091f },
|
|
||||||
{ 0.003537159230775561f, -0.000207350791625892f },
|
|
||||||
{ -0.000956199555190230f, 0.003634225577771235f },
|
|
||||||
{ -0.002543835202533561f, -0.001641705037372486f },
|
|
||||||
{ 0.001064108471592447f, -0.000863770138941644f },
|
|
||||||
{ -0.000335799601479829f, -0.000876091753216939f },
|
|
||||||
{ 0.003390761989356699f, -0.000170321604912419f },
|
|
||||||
{ -0.001408130728751909f, 0.005175554625981795f },
|
|
||||||
{ -0.005203055300834108f, -0.003419861284250694f },
|
|
||||||
{ 0.004342719678657084f, -0.003465264906764298f },
|
|
||||||
{ 0.001143432997855297f, 0.003059520699490539f },
|
|
||||||
{ 0.000304096484476364f, -0.000012725974706621f },
|
|
||||||
{ -0.001193870642975282f, 0.004247469277548632f },
|
|
||||||
{ -0.006681021498855877f, -0.004471771356204969f },
|
|
||||||
{ 0.007965721969864534f, -0.006247895626072559f },
|
|
||||||
{ 0.003365883969059717f, 0.009241201835481184f },
|
|
||||||
{ -0.006835562188141396f, 0.000228798228738161f },
|
|
||||||
{ 0.000409900284971528f, -0.001412838961851673f },
|
|
||||||
{ -0.004331406608345981f, -0.002951876085350234f },
|
|
||||||
{ 0.009290089917766562f, -0.007161958719089258f },
|
|
||||||
{ 0.005418326020709935f, 0.015272361365960607f },
|
|
||||||
{ -0.017077565432843410f, 0.000428641984774326f },
|
|
||||||
{ 0.003850771342644978f, -0.012869517593577566f },
|
|
||||||
{ 0.004380859690202961f, 0.003039552423897447f },
|
|
||||||
{ 0.004761181766399753f, -0.003607421240356480f },
|
|
||||||
{ 0.005926935731028822f, 0.017160134858844222f },
|
|
||||||
{ -0.028153584885925551f, 0.000471042980325370f },
|
|
||||||
{ 0.009655944938035437f, -0.031314555422639050f },
|
|
||||||
{ 0.023930146568136038f, 0.016901617811072800f },
|
|
||||||
{ -0.012998853255109976f, 0.009678807314399702f },
|
|
||||||
{ 0.002043176559434885f, 0.006079907699564680f },
|
|
||||||
{ -0.036686455817128191f, 0.000306882557812233f },
|
|
||||||
{ 0.021529138474771701f, -0.067800343150283604f },
|
|
||||||
{ 0.085421344938160879f, 0.061409588050754214f },
|
|
||||||
{ -0.108166660998898100f, 0.079141989828113088f },
|
|
||||||
{ -0.047617308971534079f, -0.145721049254261960f },
|
|
||||||
{ 0.160079041453427080f, -0.000000000000000427f },
|
|
||||||
{ -0.047617308971533295f, 0.145721049254262240f },
|
|
||||||
{ -0.108166660998898530f, -0.079141989828112505f },
|
|
||||||
{ 0.085421344938160546f, -0.061409588050754672f },
|
|
||||||
{ 0.021529138474772065f, 0.067800343150283493f },
|
|
||||||
{ -0.036686455817128191f, -0.000306882557812037f },
|
|
||||||
{ 0.002043176559434853f, -0.006079907699564691f },
|
|
||||||
{ -0.012998853255110026f, -0.009678807314399631f },
|
|
||||||
{ 0.023930146568135951f, -0.016901617811072928f },
|
|
||||||
{ 0.009655944938035604f, 0.031314555422638994f },
|
|
||||||
{ -0.028153584885925554f, -0.000471042980325220f },
|
|
||||||
{ 0.005926935731028730f, -0.017160134858844253f },
|
|
||||||
{ 0.004761181766399772f, 0.003607421240356455f },
|
|
||||||
{ 0.004380859690202943f, -0.003039552423897470f },
|
|
||||||
{ 0.003850771342645046f, 0.012869517593577545f },
|
|
||||||
{ -0.017077565432843413f, -0.000428641984774235f },
|
|
||||||
{ 0.005418326020709854f, -0.015272361365960637f },
|
|
||||||
{ 0.009290089917766600f, 0.007161958719089209f },
|
|
||||||
{ -0.004331406608345964f, 0.002951876085350257f },
|
|
||||||
{ 0.000409900284971536f, 0.001412838961851670f },
|
|
||||||
{ -0.006835562188141398f, -0.000228798228738125f },
|
|
||||||
{ 0.003365883969059667f, -0.009241201835481201f },
|
|
||||||
{ 0.007965721969864567f, 0.006247895626072517f },
|
|
||||||
{ -0.006681021498855855f, 0.004471771356205005f },
|
|
||||||
{ -0.001193870642975304f, -0.004247469277548626f },
|
|
||||||
{ 0.000304096484476364f, 0.000012725974706619f },
|
|
||||||
{ 0.001143432997855281f, -0.003059520699490545f },
|
|
||||||
{ 0.004342719678657102f, 0.003465264906764274f },
|
|
||||||
{ -0.005203055300834089f, 0.003419861284250722f },
|
|
||||||
{ -0.001408130728751936f, -0.005175554625981787f },
|
|
||||||
{ 0.003390761989356700f, 0.000170321604912401f },
|
|
||||||
{ -0.000335799601479825f, 0.000876091753216940f },
|
|
||||||
{ 0.001064108471592452f, 0.000863770138941638f },
|
|
||||||
{ -0.002543835202533552f, 0.001641705037372499f },
|
|
||||||
{ -0.000956199555190250f, -0.003634225577771230f },
|
|
||||||
{ 0.003537159230775563f, 0.000207350791625874f },
|
|
||||||
{ -0.000945381510920265f, 0.002406055808135096f },
|
|
||||||
{ -0.000942796972567245f, -0.000778470227412106f },
|
|
||||||
{ -0.000142534831707354f, 0.000090307321579771f },
|
|
||||||
{ -0.000312873903977856f, -0.001230889889574770f },
|
|
||||||
{ 0.001878272869910274f, 0.000125879189667086f },
|
|
||||||
{ -0.000729137747758382f, 0.001811046261815939f },
|
|
||||||
{ -0.001192460562555906f, -0.001001510577200246f },
|
|
||||||
{ 0.000734408386201156f, -0.000456742966201642f },
|
|
||||||
{ 0.000018549463752019f, 0.000075619948809012f },
|
|
||||||
{ 0.000616677332283103f, 0.000046513429902543f },
|
|
||||||
{ -0.000417178588714767f, 0.001011686459999298f },
|
|
||||||
{ -0.000983491651119600f, -0.000840133365053174f },
|
|
||||||
{ 0.001049943574694380f, -0.000640863688898734f },
|
|
||||||
{ 0.000223309865890363f, 0.000944433958755192f },
|
|
||||||
{ -0.000604775098099200f, -0.000050706635726121f },
|
|
||||||
{ 0.000089938060647144f, -0.000213032074676941f },
|
|
||||||
{ -0.000064051192147576f, -0.000055648228186438f },
|
|
||||||
{ 0.000257705918065856f, -0.000154354504676151f },
|
|
||||||
{ 0.000090081630021839f, 0.000395731646002121f },
|
|
||||||
{ -0.000414693079508517f, -0.000038265188132613f },
|
|
||||||
{ 0.000143445458895461f, -0.000331994546004200f },
|
|
||||||
{ 0.000205649042029008f, 0.000181710515677256f },
|
|
||||||
{ -0.000157609487484145f, 0.000092618697641465f },
|
|
||||||
{ -0.000022529111707761f, -0.000102942513429094f },
|
|
||||||
{ 0.000050180791439308f, 0.000005054021864311f },
|
|
||||||
{ -0.000007675039564594f, 0.000017362992335168f }
|
|
||||||
};
|
|
||||||
|
|
||||||
#define CHROMA_BANDPASS_SIZE (sizeof(CHROMA_BANDPASS)/sizeof(dsp::complex_t))
|
|
||||||
#define CHROMA_BANDPASS_DELAY (CHROMA_BANDPASS_SIZE/2)
|
|
||||||
@@ -5,33 +5,6 @@
|
|||||||
#include <dsp/multirate/polyphase_bank.h>
|
#include <dsp/multirate/polyphase_bank.h>
|
||||||
#include <dsp/math/step.h>
|
#include <dsp/math/step.h>
|
||||||
|
|
||||||
#define LINE_SIZE 945
|
|
||||||
|
|
||||||
#define SYNC_LEN 70
|
|
||||||
#define SYNC_SIDE_LEN 17
|
|
||||||
#define SYNC_L_START (LINE_SIZE - SYNC_SIDE_LEN)
|
|
||||||
#define SYNC_R_START (SYNC_LEN/2)
|
|
||||||
#define SYNC_R_END (SYNC_R_START + (SYNC_LEN/2) + SYNC_SIDE_LEN)
|
|
||||||
#define SYNC_HALF_LEN ((SYNC_LEN/2) + SYNC_SIDE_LEN)
|
|
||||||
|
|
||||||
#define EQUAL_LEN 35
|
|
||||||
|
|
||||||
#define HBLANK_START SYNC_LEN
|
|
||||||
#define HBLANK_END 155
|
|
||||||
#define HBLANK_LEN (HBLANK_END - HBLANK_START + 1)
|
|
||||||
|
|
||||||
#define SYNC_LEVEL (-0.428)
|
|
||||||
|
|
||||||
#define COLORBURST_START 84
|
|
||||||
#define COLORBURST_LEN 33
|
|
||||||
|
|
||||||
#define MAX_LOCK 1000
|
|
||||||
|
|
||||||
dsp::complex_t PHASE_REF[2] = {
|
|
||||||
{ -0.707106781186547f, 0.707106781186547f },
|
|
||||||
{ -0.707106781186547f, -0.707106781186547f }
|
|
||||||
};
|
|
||||||
|
|
||||||
class LineSync : public dsp::Processor<float, float> {
|
class LineSync : public dsp::Processor<float, float> {
|
||||||
using base_type = dsp::Processor<float, float>;
|
using base_type = dsp::Processor<float, float>;
|
||||||
public:
|
public:
|
||||||
@@ -54,17 +27,41 @@ public:
|
|||||||
_interpPhaseCount = interpPhaseCount;
|
_interpPhaseCount = interpPhaseCount;
|
||||||
_interpTapCount = interpTapCount;
|
_interpTapCount = interpTapCount;
|
||||||
|
|
||||||
|
pcl.init(_muGain, _omegaGain, 0.0, 0.0, 1.0, _omega, _omega * (1.0 - omegaRelLimit), _omega * (1.0 + omegaRelLimit));
|
||||||
generateInterpTaps();
|
generateInterpTaps();
|
||||||
buffer = dsp::buffer::alloc<float>(STREAM_BUFFER_SIZE + _interpTapCount);
|
buffer = dsp::buffer::alloc<float>(STREAM_BUFFER_SIZE + _interpTapCount);
|
||||||
bufStart = &buffer[_interpTapCount - 1];
|
bufStart = &buffer[_interpTapCount - 1];
|
||||||
|
|
||||||
// TODO: Needs tuning, so do the gains
|
|
||||||
maxPeriod = (int32_t)(1.0001 * (float)(1 << 30));
|
|
||||||
minPeriod = (int32_t)(0.9999 * (float)(1 << 30));
|
|
||||||
|
|
||||||
base_type::init(in);
|
base_type::init(in);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setOmegaGain(double omegaGain) {
|
||||||
|
assert(base_type::_block_init);
|
||||||
|
std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
|
||||||
|
_omegaGain = omegaGain;
|
||||||
|
pcl.setCoefficients(_muGain, _omegaGain);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setMuGain(double muGain) {
|
||||||
|
assert(base_type::_block_init);
|
||||||
|
std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
|
||||||
|
_muGain = muGain;
|
||||||
|
pcl.setCoefficients(_muGain, _omegaGain);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setOmegaRelLimit(double omegaRelLimit) {
|
||||||
|
assert(base_type::_block_init);
|
||||||
|
std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
|
||||||
|
_omegaRelLimit = omegaRelLimit;
|
||||||
|
pcl.setFreqLimits(_omega * (1.0 - _omegaRelLimit), _omega * (1.0 + _omegaRelLimit));
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSyncLevel(float level) {
|
||||||
|
assert(base_type::_block_init);
|
||||||
|
std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
|
||||||
|
syncLevel = level;
|
||||||
|
}
|
||||||
|
|
||||||
void setInterpParams(int interpPhaseCount, int interpTapCount) {
|
void setInterpParams(int interpPhaseCount, int interpTapCount) {
|
||||||
assert(base_type::_block_init);
|
assert(base_type::_block_init);
|
||||||
std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
|
std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
|
||||||
@@ -84,7 +81,8 @@ public:
|
|||||||
std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
|
std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
|
||||||
base_type::tempStop();
|
base_type::tempStop();
|
||||||
offset = 0;
|
offset = 0;
|
||||||
phase = 0;
|
pcl.phase = 0.0f;
|
||||||
|
pcl.freq = _omega;
|
||||||
base_type::tempStart();
|
base_type::tempStart();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,120 +93,61 @@ public:
|
|||||||
// Copy data to work buffer
|
// Copy data to work buffer
|
||||||
memcpy(bufStart, base_type::_in->readBuf, count * sizeof(float));
|
memcpy(bufStart, base_type::_in->readBuf, count * sizeof(float));
|
||||||
|
|
||||||
// Process samples while they are available
|
if (test2) {
|
||||||
|
test2 = false;
|
||||||
|
offset += 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process all samples
|
||||||
while (offset < count) {
|
while (offset < count) {
|
||||||
// While the offset is negative, out put zeros
|
// Calculate new output value
|
||||||
while (offset < 0 && pixel < LINE_SIZE) {
|
int phase = std::clamp<int>(floorf(pcl.phase * (float)_interpPhaseCount), 0, _interpPhaseCount - 1);
|
||||||
// Output a zero
|
float outVal;
|
||||||
base_type::out.writeBuf[pixel++] = 0.0f;
|
volk_32f_x2_dot_prod_32f(&outVal, &buffer[offset], interpBank.phases[phase], _interpTapCount);
|
||||||
|
base_type::out.writeBuf[outCount++] = outVal;
|
||||||
|
|
||||||
// Increment the phase
|
// If the end of the line is reached, process it and determin error
|
||||||
phase += period;
|
float error = 0;
|
||||||
offset += (phase >> 30);
|
if (outCount >= 720) {
|
||||||
phase &= 0x3FFFFFFF;
|
// Compute averages.
|
||||||
}
|
|
||||||
|
|
||||||
// Process as much of a line as possible
|
|
||||||
while (offset < count && pixel < LINE_SIZE) {
|
|
||||||
// Compute the output sample
|
|
||||||
volk_32f_x2_dot_prod_32f(&base_type::out.writeBuf[pixel++], &buffer[offset], interpBank.phases[(phase >> 23) & 0x7F], _interpTapCount);
|
|
||||||
|
|
||||||
// Increment the phase
|
|
||||||
phase += period;
|
|
||||||
offset += (phase >> 30);
|
|
||||||
phase &= 0x3FFFFFFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the line is done, process it
|
|
||||||
if (pixel == LINE_SIZE) {
|
|
||||||
// Compute averages. (TODO: Try faster method)
|
|
||||||
float left = 0.0f, right = 0.0f;
|
float left = 0.0f, right = 0.0f;
|
||||||
int lc = 0, rc = 0;
|
for (int i = (720-17); i < 720; i++) {
|
||||||
for (int i = SYNC_L_START; i < LINE_SIZE; i++) {
|
|
||||||
left += base_type::out.writeBuf[i];
|
left += base_type::out.writeBuf[i];
|
||||||
lc++;
|
|
||||||
}
|
}
|
||||||
for (int i = 0; i < SYNC_R_START; i++) {
|
for (int i = 0; i < 27; i++) {
|
||||||
left += base_type::out.writeBuf[i];
|
left += base_type::out.writeBuf[i];
|
||||||
lc++;
|
|
||||||
}
|
}
|
||||||
for (int i = SYNC_R_START; i < SYNC_R_END; i++) {
|
for (int i = 27; i < (54+17); i++) {
|
||||||
right += base_type::out.writeBuf[i];
|
right += base_type::out.writeBuf[i];
|
||||||
rc++;
|
}
|
||||||
|
left *= (1.0f/44.0f);
|
||||||
|
right *= (1.0f/44.0f);
|
||||||
|
|
||||||
|
// If the sync is present, compute error
|
||||||
|
if ((left < syncLevel && right < syncLevel) && !forceLock) {
|
||||||
|
error = (left + syncBias - right);
|
||||||
|
locked = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
locked = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute the error
|
if (++counter >= 100) {
|
||||||
float error = (left - right) * (1.0f/((float)SYNC_HALF_LEN));
|
counter = 0;
|
||||||
|
//flog::warn("Left: {}, Right: {}, Error: {}, Freq: {}, Phase: {}", left, right, error, pcl.freq, pcl.phase);
|
||||||
// Compute the change in phase and frequency due to the error
|
|
||||||
float periodDelta = error * _omegaGain;
|
|
||||||
float phaseDelta = error * _muGain;
|
|
||||||
|
|
||||||
// Normalize the phase delta (TODO: Make faster)
|
|
||||||
while (phaseDelta <= -1.0f) {
|
|
||||||
phaseDelta += 1.0f;
|
|
||||||
offset--;
|
|
||||||
}
|
|
||||||
while (phaseDelta >= 1.0f) {
|
|
||||||
phaseDelta -= 1.0f;
|
|
||||||
offset++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the period (TODO: Clamp error*omegaGain to prevent weird shit with corrupt samples)
|
|
||||||
period += (int32_t)(periodDelta * (float)(1 << 30));
|
|
||||||
period = std::clamp<uint32_t>(period, minPeriod, maxPeriod);
|
|
||||||
|
|
||||||
// Update the phase
|
|
||||||
phase += (int32_t)(phaseDelta * (float)(1 << 30));
|
|
||||||
|
|
||||||
// Normalize the phase
|
|
||||||
uint32_t overflow = phase >> 30;
|
|
||||||
if (overflow) {
|
|
||||||
if (error < 0) {
|
|
||||||
offset -= 4 - overflow;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
offset += overflow;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
phase &= 0x3FFFFFFF;
|
|
||||||
|
|
||||||
// Find the lowest value
|
|
||||||
float lowest = INFINITY;
|
|
||||||
int lowestId = -1;
|
|
||||||
for (int i = 0; i < LINE_SIZE; i++) {
|
|
||||||
float val = base_type::out.writeBuf[i];
|
|
||||||
if (val < lowest) {
|
|
||||||
lowest = val;
|
|
||||||
lowestId = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check the the line is in lock
|
|
||||||
bool lineLocked = (lowestId < SYNC_R_END || lowestId >= SYNC_L_START);
|
|
||||||
|
|
||||||
// Update the lock status based on the line lock
|
|
||||||
if (!lineLocked && locked) {
|
|
||||||
locked--;
|
|
||||||
}
|
|
||||||
else if (lineLocked && locked < MAX_LOCK) {
|
|
||||||
locked++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If not locked, attempt to lock by forcing the sync to happen at the right spot
|
|
||||||
// TODO: This triggers waaaay too easily at low SNR
|
|
||||||
if (!locked && fastLock) {
|
|
||||||
offset += lowestId - SYNC_R_START;
|
|
||||||
locked = MAX_LOCK / 2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Output line
|
// Output line
|
||||||
if (!base_type::out.swap(LINE_SIZE)) { break; }
|
if (!base_type::out.swap(outCount)) { break; }
|
||||||
pixel = 0;
|
outCount = 0;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Get the offset ready for the next buffer
|
// Advance symbol offset and phase
|
||||||
|
pcl.advance(error);
|
||||||
|
float delta = floorf(pcl.phase);
|
||||||
|
offset += delta;
|
||||||
|
pcl.phase -= delta;
|
||||||
|
}
|
||||||
offset -= count;
|
offset -= count;
|
||||||
|
|
||||||
// Update delay buffer
|
// Update delay buffer
|
||||||
@@ -216,15 +155,16 @@ public:
|
|||||||
|
|
||||||
// Swap if some data was generated
|
// Swap if some data was generated
|
||||||
base_type::_in->flush();
|
base_type::_in->flush();
|
||||||
return 0;
|
return outCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
float syncBias = 0;
|
bool locked = false;
|
||||||
|
bool test2 = false;
|
||||||
|
|
||||||
uint32_t period = (0x800072F3 >> 1);//(1 << 31) + 1;
|
float syncBias = 0.0f;
|
||||||
|
bool forceLock = false;
|
||||||
|
|
||||||
int locked = 0;
|
int counter = 0;
|
||||||
bool fastLock = true;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void generateInterpTaps() {
|
void generateInterpTaps() {
|
||||||
@@ -235,6 +175,7 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
dsp::multirate::PolyphaseBank<float> interpBank;
|
dsp::multirate::PolyphaseBank<float> interpBank;
|
||||||
|
dsp::loop::PhaseControlLoop<double, false> pcl;
|
||||||
|
|
||||||
double _omega;
|
double _omega;
|
||||||
double _omegaGain;
|
double _omegaGain;
|
||||||
@@ -242,14 +183,11 @@ protected:
|
|||||||
double _omegaRelLimit;
|
double _omegaRelLimit;
|
||||||
int _interpPhaseCount;
|
int _interpPhaseCount;
|
||||||
int _interpTapCount;
|
int _interpTapCount;
|
||||||
float* buffer;
|
|
||||||
float* bufStart;
|
|
||||||
|
|
||||||
uint32_t phase = 0;
|
|
||||||
uint32_t maxPeriod;
|
|
||||||
uint32_t minPeriod;
|
|
||||||
float syncLevel = -0.03f;
|
|
||||||
|
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
int pixel = 0;
|
int outCount = 0;
|
||||||
|
float* buffer;
|
||||||
|
float* bufStart;
|
||||||
|
|
||||||
|
float syncLevel = -0.03f;
|
||||||
};
|
};
|
||||||
@@ -16,13 +16,9 @@
|
|||||||
#include <dsp/filter/fir.h>
|
#include <dsp/filter/fir.h>
|
||||||
#include <dsp/taps/from_array.h>
|
#include <dsp/taps/from_array.h>
|
||||||
|
|
||||||
#include "amplitude.h"
|
#include "chrominance_filter.h"
|
||||||
#include <dsp/demod/am.h>
|
|
||||||
#include <dsp/loop/fast_agc.h>
|
|
||||||
|
|
||||||
#include "filters.h"
|
#include "chroma_pll.h"
|
||||||
#include <dsp/math/normalize_phase.h>
|
|
||||||
#include <fstream>
|
|
||||||
|
|
||||||
#define CONCAT(a, b) ((std::string(a) + b).c_str())
|
#define CONCAT(a, b) ((std::string(a) + b).c_str())
|
||||||
|
|
||||||
@@ -33,25 +29,24 @@ SDRPP_MOD_INFO{/* Name: */ "atv_decoder",
|
|||||||
/* Max instances */ -1
|
/* Max instances */ -1
|
||||||
};
|
};
|
||||||
|
|
||||||
#define SAMPLE_RATE (625.0f * (float)LINE_SIZE * 25.0f)
|
#define SAMPLE_RATE (625.0f * 720.0f * 25.0f)
|
||||||
|
|
||||||
class ATVDecoderModule : public ModuleManager::Instance {
|
class ATVDecoderModule : public ModuleManager::Instance {
|
||||||
public:
|
public:
|
||||||
ATVDecoderModule(std::string name) : img(768, 576) {
|
ATVDecoderModule(std::string name) : img(720, 625) {
|
||||||
this->name = name;
|
this->name = name;
|
||||||
|
|
||||||
vfo = sigpath::vfoManager.createVFO(name, ImGui::WaterfallVFO::REF_CENTER, 0, 7000000.0f, SAMPLE_RATE, SAMPLE_RATE, SAMPLE_RATE, true);
|
vfo = sigpath::vfoManager.createVFO(name, ImGui::WaterfallVFO::REF_CENTER, 0, 8000000.0f, SAMPLE_RATE, SAMPLE_RATE, SAMPLE_RATE, true);
|
||||||
|
|
||||||
agc.init(vfo->output, 1.0f, 1e6, 0.001f, 1.0f);
|
demod.init(vfo->output, SAMPLE_RATE, SAMPLE_RATE / 2.0f);
|
||||||
demod.init(&agc.out, SAMPLE_RATE, SAMPLE_RATE / 2.0f);
|
|
||||||
// demod.init(vfo->output, dsp::demod::AM<float>::CARRIER, 8000000.0f, 50.0 / SAMPLE_RATE, 50.0 / SAMPLE_RATE, 0.0f, SAMPLE_RATE);
|
|
||||||
// demod.init(vfo->output, SAMPLE_RATE, SAMPLE_RATE / 2.0f);
|
|
||||||
sync.init(&demod.out, 1.0f, 1e-6, 1.0, 0.05);
|
sync.init(&demod.out, 1.0f, 1e-6, 1.0, 0.05);
|
||||||
sink.init(&sync.out, handler, this);
|
sink.init(&sync.out, handler, this);
|
||||||
|
|
||||||
r2c.init(NULL);
|
r2c.init(NULL);
|
||||||
|
chromaTaps = dsp::taps::fromArray(CHROMA_FIR_SIZE, CHROMA_FIR);
|
||||||
|
fir.init(NULL, chromaTaps);
|
||||||
|
pll.init(NULL, 0.01, 0.0, dsp::math::hzToRads(4433618.75, SAMPLE_RATE), dsp::math::hzToRads(4433618.75*0.90, SAMPLE_RATE), dsp::math::hzToRads(4433618.75*1.1, SAMPLE_RATE));
|
||||||
|
|
||||||
agc.start();
|
|
||||||
demod.start();
|
demod.start();
|
||||||
sync.start();
|
sync.start();
|
||||||
sink.start();
|
sink.start();
|
||||||
@@ -63,10 +58,7 @@ class ATVDecoderModule : public ModuleManager::Instance {
|
|||||||
if (vfo) {
|
if (vfo) {
|
||||||
sigpath::vfoManager.deleteVFO(vfo);
|
sigpath::vfoManager.deleteVFO(vfo);
|
||||||
}
|
}
|
||||||
agc.stop();
|
|
||||||
demod.stop();
|
demod.stop();
|
||||||
sync.stop();
|
|
||||||
sink.stop();
|
|
||||||
gui::menu.removeEntry(name);
|
gui::menu.removeEntry(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,218 +82,142 @@ class ATVDecoderModule : public ModuleManager::Instance {
|
|||||||
style::beginDisabled();
|
style::beginDisabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ideal width for testing: 750pixels
|
||||||
|
|
||||||
ImGui::FillWidth();
|
ImGui::FillWidth();
|
||||||
_this->img.draw();
|
_this->img.draw();
|
||||||
|
|
||||||
ImGui::TextUnformatted("Horizontal Sync:");
|
ImGui::LeftLabel("Sync");
|
||||||
ImGui::SameLine();
|
ImGui::FillWidth();
|
||||||
if (_this->sync.locked > 750) {
|
ImGui::SliderFloat("##syncLvl", &_this->sync_level, -2, 2);
|
||||||
|
|
||||||
|
ImGui::LeftLabel("Min");
|
||||||
|
ImGui::FillWidth();
|
||||||
|
ImGui::SliderFloat("##minLvl", &_this->minLvl, -1.0, 1.0);
|
||||||
|
|
||||||
|
ImGui::LeftLabel("Span");
|
||||||
|
ImGui::FillWidth();
|
||||||
|
ImGui::SliderFloat("##spanLvl", &_this->spanLvl, 0, 1.0);
|
||||||
|
|
||||||
|
ImGui::LeftLabel("Sync Bias");
|
||||||
|
ImGui::FillWidth();
|
||||||
|
ImGui::SliderFloat("##syncBias", &_this->sync.syncBias,-0.1, 0.1);
|
||||||
|
|
||||||
|
if (ImGui::Button("Test2")) {
|
||||||
|
_this->sync.test2 = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::Button("Switch frame")) {
|
||||||
|
std::lock_guard<std::mutex> lck(_this->evenFrameMtx);
|
||||||
|
_this->evenFrame = !_this->evenFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_this->sync.locked) {
|
||||||
ImGui::TextColored(ImVec4(0, 1, 0, 1), "Locked");
|
ImGui::TextColored(ImVec4(0, 1, 0, 1), "Locked");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ImGui::TextUnformatted("Not locked");
|
ImGui::TextUnformatted("Not locked");
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::TextUnformatted("Vertical Sync:");
|
ImGui::Checkbox("Force Lock", &_this->sync.forceLock);
|
||||||
ImGui::SameLine();
|
|
||||||
if (_this->vlock > 15) {
|
|
||||||
ImGui::TextColored(ImVec4(0, 1, 0, 1), "Locked");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ImGui::TextUnformatted("Not locked");
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::Checkbox("Fast Lock", &_this->sync.fastLock);
|
|
||||||
ImGui::Checkbox("Color Mode", &_this->colorMode);
|
|
||||||
|
|
||||||
if (!_this->enabled) {
|
if (!_this->enabled) {
|
||||||
style::endDisabled();
|
style::endDisabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::Text("Gain: %f", _this->gain);
|
|
||||||
ImGui::Text("Offset: %f", _this->offset);
|
|
||||||
ImGui::Text("Subcarrier: %f", _this->subcarrierFreq);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t pp = 0;
|
|
||||||
|
|
||||||
static void handler(float *data, int count, void *ctx) {
|
static void handler(float *data, int count, void *ctx) {
|
||||||
ATVDecoderModule *_this = (ATVDecoderModule *)ctx;
|
ATVDecoderModule *_this = (ATVDecoderModule *)ctx;
|
||||||
|
|
||||||
// Correct the offset
|
// Convert line to complex
|
||||||
#if VOLK_VERSION_MAJOR > 2 || (VOLK_VERSION_MAJOR == 2 && VOLK_VERSION_MINOR >= 3)
|
_this->r2c.process(720, data, _this->r2c.out.writeBuf);
|
||||||
volk_32f_s32f_add_32f(data, data, _this->offset, count);
|
|
||||||
#else
|
// Isolate the chroma subcarrier
|
||||||
const float ofs = _this->offset;
|
_this->fir.process(720, _this->r2c.out.writeBuf, _this->fir.out.writeBuf);
|
||||||
|
|
||||||
|
// Run chroma carrier through the PLL
|
||||||
|
_this->pll.process(720, _this->fir.out.writeBuf, _this->pll.out.writeBuf, ((_this->ypos%2)==1) ^ _this->evenFrame);
|
||||||
|
|
||||||
|
// Render line to the image without color
|
||||||
|
int lypos = _this->ypos - 1;
|
||||||
|
if (lypos < 0) { lypos = 624; }
|
||||||
|
uint32_t* lastLine = &((uint32_t *)_this->img.buffer)[(lypos < 313) ? (lypos*720*2) : ((((lypos - 313)*2)+1)*720) ];
|
||||||
|
uint32_t* currentLine = &((uint32_t *)_this->img.buffer)[(_this->ypos < 313) ? (_this->ypos*720*2) : ((((_this->ypos - 313)*2)+1)*720) ];
|
||||||
|
|
||||||
|
//uint32_t* currentLine = &((uint32_t *)_this->img.buffer)[_this->ypos*720];
|
||||||
|
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
data[i] += ofs;
|
int imval = std::clamp<float>((data[i] - _this->minLvl) * 255.0 / _this->spanLvl, 0, 255);
|
||||||
|
// uint32_t re = std::clamp<float>((_this->pll.out.writeBuf[i].re - _this->minLvl) * 255.0 / _this->spanLvl, 0, 255);
|
||||||
|
// uint32_t im = std::clamp<float>((_this->pll.out.writeBuf[i].im - _this->minLvl) * 255.0 / _this->spanLvl, 0, 255);
|
||||||
|
// currentLine[i] = 0xFF000000 | (im << 8) | re;
|
||||||
|
currentLine[i] = 0xFF000000 | (imval << 16) | (imval << 8) | imval;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
// Vertical scan logic
|
||||||
// Correct the gain
|
_this->ypos++;
|
||||||
volk_32f_s32f_multiply_32f(data, data, _this->gain, count);
|
bool rollover = _this->ypos >= 625;
|
||||||
|
if (rollover) {
|
||||||
// Compute the sync levels
|
{
|
||||||
float syncLLevel = 0.0f;
|
std::lock_guard<std::mutex> lck(_this->evenFrameMtx);
|
||||||
float syncRLevel = 0.0f;
|
_this->evenFrame = !_this->evenFrame;
|
||||||
volk_32f_accumulator_s32f(&syncLLevel, data, EQUAL_LEN);
|
|
||||||
volk_32f_accumulator_s32f(&syncRLevel, &data[EQUAL_LEN], SYNC_LEN - EQUAL_LEN);
|
|
||||||
syncLLevel *= 1.0f / EQUAL_LEN;
|
|
||||||
syncRLevel *= 1.0f / (SYNC_LEN - EQUAL_LEN);
|
|
||||||
float syncLevel = (syncLLevel + syncRLevel) * 0.5f; // TODO: It's technically correct but if the sizes were different it wouldn't be
|
|
||||||
|
|
||||||
// Compute the blanking level
|
|
||||||
float blankLevel = 0.0f;
|
|
||||||
volk_32f_accumulator_s32f(&blankLevel, &data[HBLANK_START], HBLANK_LEN);
|
|
||||||
blankLevel /= (float)HBLANK_LEN;
|
|
||||||
|
|
||||||
// Run the offset control loop
|
|
||||||
_this->offset -= (blankLevel / _this->gain)*0.001;
|
|
||||||
_this->offset = std::clamp<float>(_this->offset, -1.0f, 1.0f);
|
|
||||||
_this->gain -= (blankLevel - syncLevel + SYNC_LEVEL)*0.01f;
|
|
||||||
_this->gain = std::clamp<float>(_this->gain, 0.1f, 10.0f);
|
|
||||||
|
|
||||||
// Detect the sync type
|
|
||||||
uint16_t shortSync = (syncLLevel < 0.5f*SYNC_LEVEL) && (syncRLevel > 0.5f*SYNC_LEVEL) && (blankLevel > 0.5f*SYNC_LEVEL);
|
|
||||||
uint16_t longSync = (syncLLevel < 0.5f*SYNC_LEVEL) && (syncRLevel < 0.5f*SYNC_LEVEL) && (blankLevel < 0.5f*SYNC_LEVEL);
|
|
||||||
|
|
||||||
// Save sync type to history
|
|
||||||
_this->syncHistory = (_this->syncHistory << 2) | (longSync << 1) | shortSync;
|
|
||||||
|
|
||||||
// // If the line has a colorburst, decode it
|
|
||||||
// dsp::complex_t* buf1 = _this->r2c.out.readBuf;
|
|
||||||
// dsp::complex_t* buf2 = _this->r2c.out.writeBuf;
|
|
||||||
// if (true) {
|
|
||||||
// // Convert the line into complex
|
|
||||||
// _this->r2c.process(count, data, buf1);
|
|
||||||
|
|
||||||
// // Extract the chroma subcarrier (TODO: Optimise by running only where needed)
|
|
||||||
// for (int i = COLORBURST_START; i < count-(CHROMA_BANDPASS_DELAY+1); i++) {
|
|
||||||
// volk_32fc_x2_dot_prod_32fc((lv_32fc_t*)&buf2[i], (lv_32fc_t*)&buf1[i - CHROMA_BANDPASS_DELAY], (lv_32fc_t*)CHROMA_BANDPASS, CHROMA_BANDPASS_SIZE);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Down convert the chroma subcarrier (TODO: Optimise by running only where needed)
|
|
||||||
// lv_32fc_t startPhase = { 1.0f, 0.0f };
|
|
||||||
// lv_32fc_t phaseDelta = { sinf(_this->subcarrierFreq), cosf(_this->subcarrierFreq) };
|
|
||||||
// #if VOLK_VERSION >= 030100
|
|
||||||
// volk_32fc_s32fc_x2_rotator2_32fc((lv_32fc_t*)&buf2[COLORBURST_START], (lv_32fc_t*)&buf2[COLORBURST_START], &phaseDelta, &startPhase, count - COLORBURST_START);
|
|
||||||
// #else
|
|
||||||
// volk_32fc_s32fc_x2_rotator_32fc((lv_32fc_t*)&buf2[COLORBURST_START], (lv_32fc_t*)&buf2[COLORBURST_START], phaseDelta, &startPhase, count - COLORBURST_START);
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
// // Compute the phase of the burst
|
|
||||||
// dsp::complex_t burstAvg = { 0.0f, 0.0f };
|
|
||||||
// volk_32fc_accumulator_s32fc((lv_32fc_t*)&burstAvg, (lv_32fc_t*)&buf2[COLORBURST_START], COLORBURST_LEN);
|
|
||||||
// float burstAmp = burstAvg.amplitude();
|
|
||||||
// if (burstAmp*(1.0f/(float)COLORBURST_LEN) < 0.02f) {
|
|
||||||
// printf("%d\n", _this->line);
|
|
||||||
// }
|
|
||||||
// burstAvg *= (1.0f / (burstAmp*burstAmp));
|
|
||||||
// burstAvg = burstAvg.conj();
|
|
||||||
|
|
||||||
// // Normalize the chroma data (TODO: Optimise by running only where needed)
|
|
||||||
// volk_32fc_s32fc_multiply_32fc((lv_32fc_t*)&buf2[COLORBURST_START], (lv_32fc_t*)&buf2[COLORBURST_START], *((lv_32fc_t*)&burstAvg), count - COLORBURST_START);
|
|
||||||
|
|
||||||
// // Compute the frequency error of the burst
|
|
||||||
// float phase = buf2[COLORBURST_START].phase();
|
|
||||||
// float error = 0.0f;
|
|
||||||
// for (int i = COLORBURST_START+1; i < COLORBURST_START+COLORBURST_LEN; i++) {
|
|
||||||
// float cphase = buf2[i].phase();
|
|
||||||
// error += dsp::math::normalizePhase(cphase - phase);
|
|
||||||
// phase = cphase;
|
|
||||||
// }
|
|
||||||
// error *= (1.0f / (float)(COLORBURST_LEN-1));
|
|
||||||
|
|
||||||
// // Update the subcarrier freq
|
|
||||||
// _this->subcarrierFreq += error*0.0001f;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Render the line if it's visible
|
|
||||||
if (_this->ypos >= 34 && _this->ypos <= 34+576-1) {
|
|
||||||
uint32_t* currentLine = &((uint32_t *)_this->img.buffer)[(_this->ypos - 34)*768];
|
|
||||||
if (_this->colorMode) {
|
|
||||||
// for (int i = 155; i < (155+768); i++) {
|
|
||||||
// int imval1 = std::clamp<float>(fabsf(buf2[i-155+COLORBURST_START].re*5.0f) * 255.0f, 0, 255);
|
|
||||||
// int imval2 = std::clamp<float>(fabsf(buf2[i-155+COLORBURST_START].im*5.0f) * 255.0f, 0, 255);
|
|
||||||
// currentLine[i-155] = 0xFF000000 | (imval2 << 8) | imval1;
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
for (int i = 155; i < (155+768); i++) {
|
|
||||||
int imval = std::clamp<float>(data[i] * 255.0f, 0, 255);
|
|
||||||
currentLine[i-155] = 0xFF000000 | (imval << 16) | (imval << 8) | imval;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compute whether to rollover
|
|
||||||
bool rollToOdd = (_this->ypos == 624);
|
|
||||||
bool rollToEven = (_this->ypos == 623);
|
|
||||||
|
|
||||||
// Compute the field sync
|
|
||||||
bool syncToOdd = (_this->syncHistory == 0b0101011010010101);
|
|
||||||
bool syncToEven = (_this->syncHistory == 0b0001011010100101);
|
|
||||||
|
|
||||||
// Process the sync (NOTE: should start with 0b01, but for some reason I don't see a sync?)
|
|
||||||
if (rollToOdd || syncToOdd) {
|
|
||||||
// Update the vertical lock state
|
|
||||||
bool disagree = (rollToOdd ^ syncToOdd);
|
|
||||||
if (disagree && _this->vlock > 0) {
|
|
||||||
_this->vlock--;
|
|
||||||
}
|
|
||||||
else if (!disagree && _this->vlock < 20) {
|
|
||||||
_this->vlock++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start the odd field
|
|
||||||
_this->ypos = 1;
|
|
||||||
_this->line++;
|
|
||||||
}
|
|
||||||
else if (rollToEven || syncToEven) {
|
|
||||||
// Update the vertical lock state
|
|
||||||
bool disagree = (rollToEven ^ syncToEven);
|
|
||||||
if (disagree && _this->vlock > 0) {
|
|
||||||
_this->vlock--;
|
|
||||||
}
|
|
||||||
else if (!disagree && _this->vlock < 20) {
|
|
||||||
_this->vlock++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start the even field
|
|
||||||
_this->ypos = 0;
|
_this->ypos = 0;
|
||||||
_this->line = 0;
|
|
||||||
|
|
||||||
// Swap the video buffer
|
|
||||||
_this->img.swap();
|
_this->img.swap();
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
_this->ypos += 2;
|
// Measure vsync levels
|
||||||
_this->line++;
|
float sync0 = 0.0f, sync1 = 0.0f;
|
||||||
|
for (int i = 0; i < 306; i++) {
|
||||||
|
sync0 += data[i];
|
||||||
|
}
|
||||||
|
for (int i = (720/2); i < ((720/2)+306); i++) {
|
||||||
|
sync1 += data[i];
|
||||||
|
}
|
||||||
|
sync0 *= (1.0f/305.0f);
|
||||||
|
sync1 *= (1.0f/305.0f);
|
||||||
|
|
||||||
|
// Save sync detection to history
|
||||||
|
_this->syncHistory >>= 2;
|
||||||
|
_this->syncHistory |= (((uint16_t)(sync1 < _this->sync_level)) << 9) | (((uint16_t)(sync0 < _this->sync_level)) << 8);
|
||||||
|
|
||||||
|
// Trigger vsync in case one is detected
|
||||||
|
// TODO: Also sync with odd field
|
||||||
|
if (!rollover && _this->syncHistory == 0b0000011111) {
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lck(_this->evenFrameMtx);
|
||||||
|
_this->evenFrame = !_this->evenFrame;
|
||||||
|
}
|
||||||
|
_this->ypos = 0;
|
||||||
|
_this->img.swap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NEW SYNC:
|
|
||||||
float offset = 0.0f;
|
|
||||||
float gain = 1.0f;
|
|
||||||
uint16_t syncHistory = 0;
|
|
||||||
int line = 0;
|
|
||||||
int ypos = 0;
|
|
||||||
int vlock = 0;
|
|
||||||
float subcarrierFreq = 0.0f;
|
|
||||||
|
|
||||||
std::string name;
|
std::string name;
|
||||||
bool enabled = true;
|
bool enabled = true;
|
||||||
|
|
||||||
VFOManager::VFO *vfo = NULL;
|
VFOManager::VFO *vfo = NULL;
|
||||||
// dsp::demod::Quadrature demod;
|
dsp::demod::Quadrature demod;
|
||||||
dsp::loop::FastAGC<dsp::complex_t> agc;
|
|
||||||
dsp::demod::Amplitude demod;
|
|
||||||
//dsp::demod::AM<float> demod;
|
|
||||||
LineSync sync;
|
LineSync sync;
|
||||||
dsp::sink::Handler<float> sink;
|
dsp::sink::Handler<float> sink;
|
||||||
dsp::convert::RealToComplex r2c;
|
dsp::convert::RealToComplex r2c;
|
||||||
|
dsp::tap<dsp::complex_t> chromaTaps;
|
||||||
|
dsp::filter::FIR<dsp::complex_t, dsp::complex_t> fir;
|
||||||
|
dsp::loop::ChromaPLL pll;
|
||||||
|
int ypos = 0;
|
||||||
|
|
||||||
bool colorMode = false;
|
bool evenFrame = false;
|
||||||
|
std::mutex evenFrameMtx;
|
||||||
|
|
||||||
|
float sync_level = -0.06f;
|
||||||
|
int sync_count = 0;
|
||||||
|
int short_sync = 0;
|
||||||
|
|
||||||
|
float minLvl = 0.0f;
|
||||||
|
float spanLvl = 1.0f;
|
||||||
|
|
||||||
|
bool lockedLines = 0;
|
||||||
|
uint16_t syncHistory = 0;
|
||||||
|
|
||||||
ImGui::ImageDisplay img;
|
ImGui::ImageDisplay img;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,37 +0,0 @@
|
|||||||
cmake_minimum_required(VERSION 3.13)
|
|
||||||
project(dab_decoder)
|
|
||||||
|
|
||||||
file(GLOB_RECURSE SRC "src/*.cpp" "src/*.c")
|
|
||||||
|
|
||||||
include(${SDRPP_MODULE_CMAKE})
|
|
||||||
|
|
||||||
target_include_directories(dab_decoder PRIVATE "src/")
|
|
||||||
|
|
||||||
if (MSVC)
|
|
||||||
# Lib path
|
|
||||||
target_include_directories(dab_decoder PRIVATE "C:/Program Files/codec2/include/")
|
|
||||||
target_link_directories(dab_decoder PRIVATE "C:/Program Files/codec2/lib")
|
|
||||||
|
|
||||||
target_link_libraries(dab_decoder PRIVATE libcodec2)
|
|
||||||
elseif (ANDROID)
|
|
||||||
target_include_directories(dab_decoder PUBLIC
|
|
||||||
/sdr-kit/${ANDROID_ABI}/include/codec2
|
|
||||||
)
|
|
||||||
|
|
||||||
target_link_libraries(dab_decoder PUBLIC
|
|
||||||
/sdr-kit/${ANDROID_ABI}/lib/libcodec2.so
|
|
||||||
)
|
|
||||||
else ()
|
|
||||||
find_package(PkgConfig)
|
|
||||||
|
|
||||||
pkg_check_modules(LIBCODEC2 REQUIRED codec2)
|
|
||||||
|
|
||||||
target_include_directories(dab_decoder PRIVATE ${LIBCODEC2_INCLUDE_DIRS})
|
|
||||||
target_link_directories(dab_decoder PRIVATE ${LIBCODEC2_LIBRARY_DIRS})
|
|
||||||
target_link_libraries(dab_decoder PRIVATE ${LIBCODEC2_LIBRARIES})
|
|
||||||
|
|
||||||
# Include it because for some reason pkgconfig doesn't look here?
|
|
||||||
if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
|
||||||
target_include_directories(dab_decoder PRIVATE "/usr/local/include")
|
|
||||||
endif()
|
|
||||||
endif ()
|
|
||||||
@@ -1,280 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <dsp/processor.h>
|
|
||||||
#include <utils/flog.h>
|
|
||||||
#include <fftw3.h>
|
|
||||||
#include "dab_phase_sym.h"
|
|
||||||
|
|
||||||
namespace dab {
|
|
||||||
class CyclicSync : public dsp::Processor<dsp::complex_t, dsp::complex_t> {
|
|
||||||
using base_type = dsp::Processor<dsp::complex_t, dsp::complex_t>;
|
|
||||||
public:
|
|
||||||
CyclicSync() {}
|
|
||||||
|
|
||||||
// TODO: The default AGC rate is probably way too fast, plot out the avgCorr to see how much it moves
|
|
||||||
CyclicSync(dsp::stream<dsp::complex_t>* in, double symbolLength, double cyclicPrefixLength, double samplerate, float agcRate = 1e-3) { init(in, symbolLength, cyclicPrefixLength, samplerate, agcRate); }
|
|
||||||
|
|
||||||
void init(dsp::stream<dsp::complex_t>* in, double symbolLength, double cyclicPrefixLength, double samplerate, float agcRate = 1e-3) {
|
|
||||||
// Computer the number of samples for the symbol and its cyclic prefix
|
|
||||||
symbolSamps = round(samplerate * symbolLength);
|
|
||||||
prefixSamps = round(samplerate * cyclicPrefixLength);
|
|
||||||
|
|
||||||
// Allocate and clear the delay buffer
|
|
||||||
delayBuf = dsp::buffer::alloc<dsp::complex_t>(STREAM_BUFFER_SIZE + 64000);
|
|
||||||
dsp::buffer::clear(delayBuf, symbolSamps);
|
|
||||||
|
|
||||||
// Allocate and clear the history buffer
|
|
||||||
histBuf = dsp::buffer::alloc<dsp::complex_t>(prefixSamps);
|
|
||||||
dsp::buffer::clear(histBuf, prefixSamps);
|
|
||||||
|
|
||||||
// Compute the delay input addresses
|
|
||||||
delayBufInput = &delayBuf[symbolSamps];
|
|
||||||
|
|
||||||
// Compute the correlation AGC configuration
|
|
||||||
this->agcRate = agcRate;
|
|
||||||
agcRateInv = 1.0f - agcRate;
|
|
||||||
|
|
||||||
base_type::init(in);
|
|
||||||
}
|
|
||||||
|
|
||||||
void reset() {
|
|
||||||
assert(base_type::_block_init);
|
|
||||||
std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
|
|
||||||
base_type::tempStop();
|
|
||||||
|
|
||||||
base_type::tempStart();
|
|
||||||
}
|
|
||||||
|
|
||||||
int run() {
|
|
||||||
int count = base_type::_in->read();
|
|
||||||
if (count < 0) { return -1; }
|
|
||||||
|
|
||||||
// Copy the data into the normal delay buffer
|
|
||||||
memcpy(delayBufInput, base_type::_in->readBuf, count * sizeof(dsp::complex_t));
|
|
||||||
|
|
||||||
// Flush the input stream
|
|
||||||
base_type::_in->flush();
|
|
||||||
|
|
||||||
// Do cross-correlation
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
// Get the current history slot
|
|
||||||
dsp::complex_t* slot = &histBuf[histId++];
|
|
||||||
|
|
||||||
// Wrap around the history slot index (TODO: Check that the history buffer's length is correct)
|
|
||||||
histId %= prefixSamps;
|
|
||||||
|
|
||||||
// Kick out last value from the correlation
|
|
||||||
corr -= *slot;
|
|
||||||
|
|
||||||
// Save input value and compute the new prodct
|
|
||||||
dsp::complex_t val = delayBuf[i];
|
|
||||||
dsp::complex_t prod = val.conj()*delayBuf[i+symbolSamps];
|
|
||||||
|
|
||||||
// Add the new value to the correlation
|
|
||||||
*slot = prod;
|
|
||||||
|
|
||||||
// Add the new value to the history buffer
|
|
||||||
corr += prod;
|
|
||||||
|
|
||||||
// Compute sample amplitude
|
|
||||||
float rcorr = corr.amplitude();
|
|
||||||
|
|
||||||
// If a high enough peak is reached, reset the symbol counter
|
|
||||||
if (rcorr > avgCorr && rcorr > peakCorr) { // Note keeping an average level might not be needed
|
|
||||||
peakCorr = rcorr;
|
|
||||||
peakLCorr = lastCorr;
|
|
||||||
samplesSincePeak = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If this is the sample right after the peak, save it
|
|
||||||
if (samplesSincePeak == 1) {
|
|
||||||
peakRCorr = rcorr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write the sample to the output
|
|
||||||
out.writeBuf[samplesSincePeak++] = val;
|
|
||||||
|
|
||||||
// If the end of the symbol is reached, send it off
|
|
||||||
if (samplesSincePeak >= symbolSamps) {
|
|
||||||
if (!out.swap(symbolSamps)) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
samplesSincePeak = 0;
|
|
||||||
peakCorr = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the average correlation
|
|
||||||
lastCorr = rcorr;
|
|
||||||
|
|
||||||
// Update the average correlation value
|
|
||||||
avgCorr = agcRate*rcorr + agcRateInv*avgCorr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Move unused data
|
|
||||||
memmove(delayBuf, &delayBuf[count], symbolSamps * sizeof(dsp::complex_t));
|
|
||||||
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
int symbolSamps;
|
|
||||||
int prefixSamps;
|
|
||||||
|
|
||||||
int histId = 0;
|
|
||||||
dsp::complex_t* histBuf;
|
|
||||||
|
|
||||||
dsp::complex_t* delayBuf;
|
|
||||||
dsp::complex_t* delayBufInput;
|
|
||||||
|
|
||||||
dsp::complex_t corr = { 0.0f, 0.0f };
|
|
||||||
|
|
||||||
int samplesSincePeak = 0;
|
|
||||||
float lastCorr = 0.0f;
|
|
||||||
float peakCorr = 0.0f;
|
|
||||||
float peakLCorr = 0.0f;
|
|
||||||
float peakRCorr = 0.0f;
|
|
||||||
|
|
||||||
// Note only required for DAB
|
|
||||||
float avgCorr = 0.0f;
|
|
||||||
float agcRate;
|
|
||||||
float agcRateInv;
|
|
||||||
};
|
|
||||||
|
|
||||||
class FrameFreqSync : public dsp::Processor<dsp::complex_t, dsp::complex_t> {
|
|
||||||
using base_type = dsp::Processor<dsp::complex_t, dsp::complex_t>;
|
|
||||||
public:
|
|
||||||
FrameFreqSync() {}
|
|
||||||
|
|
||||||
FrameFreqSync(dsp::stream<dsp::complex_t>* in, float agcRate = 0.01f) { init(in, agcRate); }
|
|
||||||
|
|
||||||
void init(dsp::stream<dsp::complex_t>* in, float agcRate = 0.01f) {
|
|
||||||
// Allocate buffers
|
|
||||||
amps = dsp::buffer::alloc<float>(2048);
|
|
||||||
conjRef = dsp::buffer::alloc<dsp::complex_t>(2048);
|
|
||||||
corrIn = (dsp::complex_t*)fftwf_alloc_complex(2048);
|
|
||||||
corrOut = (dsp::complex_t*)fftwf_alloc_complex(2048);
|
|
||||||
|
|
||||||
// Copy the phase reference
|
|
||||||
memcpy(conjRef, DAB_PHASE_SYM_CONJ, 2048 * sizeof(dsp::complex_t));
|
|
||||||
|
|
||||||
// Plan the FFT computation
|
|
||||||
plan = fftwf_plan_dft_1d(2048, (fftwf_complex*)corrIn, (fftwf_complex*)corrOut, FFTW_FORWARD, FFTW_ESTIMATE);
|
|
||||||
|
|
||||||
// Compute the correlation AGC configuration
|
|
||||||
this->agcRate = agcRate;
|
|
||||||
agcRateInv = 1.0f - agcRate;
|
|
||||||
|
|
||||||
base_type::init(in);
|
|
||||||
}
|
|
||||||
|
|
||||||
void reset() {
|
|
||||||
assert(base_type::_block_init);
|
|
||||||
std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
|
|
||||||
base_type::tempStop();
|
|
||||||
|
|
||||||
base_type::tempStart();
|
|
||||||
}
|
|
||||||
|
|
||||||
int run() {
|
|
||||||
int count = base_type::_in->read();
|
|
||||||
if (count < 0) { return -1; }
|
|
||||||
|
|
||||||
// Apply frequency shift
|
|
||||||
lv_32fc_t phase = lv_cmake(1.0f, 0.0f);
|
|
||||||
lv_32fc_t phaseDelta = lv_cmake(cos(offset), sin(offset));
|
|
||||||
#if VOLK_VERSION >= 030100
|
|
||||||
volk_32fc_s32fc_x2_rotator2_32fc((lv_32fc_t*)_in->readBuf, (lv_32fc_t*)_in->readBuf, phaseDelta, &phase, count);
|
|
||||||
#else
|
|
||||||
volk_32fc_s32fc_x2_rotator_32fc((lv_32fc_t*)_in->readBuf, (lv_32fc_t*)_in->readBuf, phaseDelta, &phase, count);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Compute the amplitude amplitude of all samples
|
|
||||||
volk_32fc_magnitude_32f(amps, (lv_32fc_t*)_in->readBuf, 2048);
|
|
||||||
|
|
||||||
// Compute the average signal level by adding up all values
|
|
||||||
float level = 0.0f;
|
|
||||||
volk_32f_accumulator_s32f(&level, amps, 2048);
|
|
||||||
|
|
||||||
// Detect a frame sync condition
|
|
||||||
if (level < avgLvl * 0.5f) {
|
|
||||||
// Reset symbol counter
|
|
||||||
sym = 1;
|
|
||||||
|
|
||||||
// Update the average level
|
|
||||||
avgLvl = agcRate*level + agcRateInv*avgLvl;
|
|
||||||
|
|
||||||
// Flush the input stream and return
|
|
||||||
base_type::_in->flush();
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the average level
|
|
||||||
avgLvl = agcRate*level + agcRateInv*avgLvl;
|
|
||||||
|
|
||||||
// Handle phase reference
|
|
||||||
if (sym == 1) {
|
|
||||||
// Output the symbols (DEBUG ONLY)
|
|
||||||
memcpy(corrIn, _in->readBuf, 2048 * sizeof(dsp::complex_t));
|
|
||||||
fftwf_execute(plan);
|
|
||||||
volk_32fc_magnitude_32f(amps, (lv_32fc_t*)corrOut, 2048);
|
|
||||||
int outCount = 0;
|
|
||||||
dsp::complex_t pi4 = { cos(3.1415926535*0.25), sin(3.1415926535*0.25) };
|
|
||||||
for (int i = -767; i < 768; i++) {
|
|
||||||
if (!i) { continue; }
|
|
||||||
int cid0 = ((i-1) >= 0) ? (i-1) : 2048+(i-1);
|
|
||||||
int cid1 = (i >= 0) ? i : 2048+i;;
|
|
||||||
out.writeBuf[outCount++] = pi4 * (corrOut[cid1] * corrOut[cid0].conj()) * (1.0f/(amps[cid0]*amps[cid0]));
|
|
||||||
}
|
|
||||||
out.swap(outCount);
|
|
||||||
|
|
||||||
// Multiply the samples with the conjugated phase reference signal
|
|
||||||
volk_32fc_x2_multiply_32fc((lv_32fc_t*)corrIn, (lv_32fc_t*)_in->readBuf, (lv_32fc_t*)conjRef, 2048);
|
|
||||||
|
|
||||||
// Compute the FFT of the product
|
|
||||||
fftwf_execute(plan);
|
|
||||||
|
|
||||||
// Compute the amplitude of the bins
|
|
||||||
volk_32fc_magnitude_32f(amps, (lv_32fc_t*)corrOut, 2048);
|
|
||||||
|
|
||||||
// Locate highest power bin
|
|
||||||
uint32_t peakId;
|
|
||||||
volk_32f_index_max_32u(&peakId, amps, 2048);
|
|
||||||
|
|
||||||
// Obtain the value of the bins next to the peak
|
|
||||||
float peakL = amps[(peakId + 2047) % 2048];
|
|
||||||
float peakR = amps[(peakId + 1) % 2048];
|
|
||||||
|
|
||||||
// Compute the integer frequency offset
|
|
||||||
float offInt = (peakId < 1024) ? (float)peakId : ((float)peakId - 2048.0f);
|
|
||||||
|
|
||||||
// Compute the frequency offset in rad/samp
|
|
||||||
float off = 3.1415926535f * (offInt + ((peakR - peakL) / (peakR + peakL))) * (1.0f / 1024.0f);
|
|
||||||
|
|
||||||
// Run control loop
|
|
||||||
offset -= 0.1f*off;
|
|
||||||
flog::debug("Offset: {} Hz, Error: {} Hz, Avg Level: {}", offset * (0.5f/3.1415926535f)*2.048e6, off * (0.5f/3.1415926535f)*2.048e6, avgLvl);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Increment the symbol counter
|
|
||||||
sym++;
|
|
||||||
|
|
||||||
// Flush the input stream and return
|
|
||||||
base_type::_in->flush();
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
fftwf_plan plan;
|
|
||||||
|
|
||||||
float* amps;
|
|
||||||
dsp::complex_t* conjRef;
|
|
||||||
dsp::complex_t* corrIn;
|
|
||||||
dsp::complex_t* corrOut;
|
|
||||||
|
|
||||||
int sym;
|
|
||||||
float offset = 0.0f;
|
|
||||||
|
|
||||||
float avgLvl = 0.0f;
|
|
||||||
float agcRate;
|
|
||||||
float agcRateInv;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,163 +0,0 @@
|
|||||||
#include <imgui.h>
|
|
||||||
#include <config.h>
|
|
||||||
#include <core.h>
|
|
||||||
#include <gui/style.h>
|
|
||||||
#include <gui/gui.h>
|
|
||||||
#include <signal_path/signal_path.h>
|
|
||||||
#include <module.h>
|
|
||||||
#include <filesystem>
|
|
||||||
#include <dsp/stream.h>
|
|
||||||
#include <dsp/buffer/reshaper.h>
|
|
||||||
#include <dsp/multirate/rational_resampler.h>
|
|
||||||
#include <dsp/sink/handler_sink.h>
|
|
||||||
#include <fstream>
|
|
||||||
#include <chrono>
|
|
||||||
#include "dab_dsp.h"
|
|
||||||
#include <gui/widgets/constellation_diagram.h>
|
|
||||||
|
|
||||||
#define CONCAT(a, b) ((std::string(a) + b).c_str())
|
|
||||||
|
|
||||||
SDRPP_MOD_INFO{
|
|
||||||
/* Name: */ "dab_decoder",
|
|
||||||
/* Description: */ "DAB/DAB+ Decoder for SDR++",
|
|
||||||
/* Author: */ "Ryzerth",
|
|
||||||
/* Version: */ 0, 1, 0,
|
|
||||||
/* Max instances */ -1
|
|
||||||
};
|
|
||||||
|
|
||||||
ConfigManager config;
|
|
||||||
|
|
||||||
#define INPUT_SAMPLE_RATE 2.048e6
|
|
||||||
#define VFO_BANDWIDTH 1.6e6
|
|
||||||
|
|
||||||
class M17DecoderModule : public ModuleManager::Instance {
|
|
||||||
public:
|
|
||||||
M17DecoderModule(std::string name) {
|
|
||||||
this->name = name;
|
|
||||||
|
|
||||||
file = std::ofstream("sync4.f32", std::ios::out | std::ios::binary);
|
|
||||||
|
|
||||||
// Load config
|
|
||||||
config.acquire();
|
|
||||||
|
|
||||||
config.release(true);
|
|
||||||
|
|
||||||
// Initialize VFO
|
|
||||||
vfo = sigpath::vfoManager.createVFO(name, ImGui::WaterfallVFO::REF_CENTER, 0, VFO_BANDWIDTH, INPUT_SAMPLE_RATE, VFO_BANDWIDTH, VFO_BANDWIDTH, true);
|
|
||||||
vfo->setSnapInterval(250);
|
|
||||||
|
|
||||||
// Initialize DSP here
|
|
||||||
csync.init(vfo->output, 1e-3, 246e-6, INPUT_SAMPLE_RATE);
|
|
||||||
ffsync.init(&csync.out);
|
|
||||||
ns.init(&ffsync.out, handler, this);
|
|
||||||
|
|
||||||
// Start DSO Here
|
|
||||||
csync.start();
|
|
||||||
ffsync.start();
|
|
||||||
ns.start();
|
|
||||||
|
|
||||||
gui::menu.registerEntry(name, menuHandler, this, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
~M17DecoderModule() {
|
|
||||||
gui::menu.removeEntry(name);
|
|
||||||
// Stop DSP Here
|
|
||||||
if (enabled) {
|
|
||||||
csync.stop();
|
|
||||||
ffsync.stop();
|
|
||||||
ns.stop();
|
|
||||||
sigpath::vfoManager.deleteVFO(vfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
sigpath::sinkManager.unregisterStream(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
void postInit() {}
|
|
||||||
|
|
||||||
void enable() {
|
|
||||||
double bw = gui::waterfall.getBandwidth();
|
|
||||||
vfo = sigpath::vfoManager.createVFO(name, ImGui::WaterfallVFO::REF_CENTER, std::clamp<double>(0, -bw / 2.0, bw / 2.0), VFO_BANDWIDTH, INPUT_SAMPLE_RATE, VFO_BANDWIDTH, VFO_BANDWIDTH, true);
|
|
||||||
vfo->setSnapInterval(250);
|
|
||||||
|
|
||||||
// Set Input of demod here
|
|
||||||
csync.setInput(vfo->output);
|
|
||||||
|
|
||||||
// Start DSP here
|
|
||||||
csync.start();
|
|
||||||
ffsync.start();
|
|
||||||
ns.start();
|
|
||||||
|
|
||||||
enabled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void disable() {
|
|
||||||
// Stop DSP here
|
|
||||||
csync.stop();
|
|
||||||
ffsync.stop();
|
|
||||||
ns.stop();
|
|
||||||
|
|
||||||
sigpath::vfoManager.deleteVFO(vfo);
|
|
||||||
enabled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isEnabled() {
|
|
||||||
return enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
static void menuHandler(void* ctx) {
|
|
||||||
M17DecoderModule* _this = (M17DecoderModule*)ctx;
|
|
||||||
|
|
||||||
float menuWidth = ImGui::GetContentRegionAvail().x;
|
|
||||||
|
|
||||||
if (!_this->enabled) { style::beginDisabled(); }
|
|
||||||
|
|
||||||
_this->constDiagram.draw();
|
|
||||||
|
|
||||||
if (!_this->enabled) { style::endDisabled(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
std::ofstream file;
|
|
||||||
|
|
||||||
static void handler(dsp::complex_t* data, int count, void* ctx) {
|
|
||||||
M17DecoderModule* _this = (M17DecoderModule*)ctx;
|
|
||||||
//_this->file.write((char*)data, count * sizeof(dsp::complex_t));
|
|
||||||
|
|
||||||
dsp::complex_t* buf = _this->constDiagram.acquireBuffer();
|
|
||||||
memcpy(buf, data, 1024 * sizeof(dsp::complex_t));
|
|
||||||
_this->constDiagram.releaseBuffer();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string name;
|
|
||||||
bool enabled = true;
|
|
||||||
|
|
||||||
dab::CyclicSync csync;
|
|
||||||
dab::FrameFreqSync ffsync;
|
|
||||||
dsp::sink::Handler<dsp::complex_t> ns;
|
|
||||||
|
|
||||||
ImGui::ConstellationDiagram constDiagram;
|
|
||||||
|
|
||||||
// DSP Chain
|
|
||||||
VFOManager::VFO* vfo;
|
|
||||||
};
|
|
||||||
|
|
||||||
MOD_EXPORT void _INIT_() {
|
|
||||||
// Create default recording directory
|
|
||||||
json def = json({});
|
|
||||||
config.setPath(core::args["root"].s() + "/dab_decoder_config.json");
|
|
||||||
config.load(def);
|
|
||||||
config.enableAutoSave();
|
|
||||||
}
|
|
||||||
|
|
||||||
MOD_EXPORT ModuleManager::Instance* _CREATE_INSTANCE_(std::string name) {
|
|
||||||
return new M17DecoderModule(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
MOD_EXPORT void _DELETE_INSTANCE_(void* instance) {
|
|
||||||
delete (M17DecoderModule*)instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
MOD_EXPORT void _END_() {
|
|
||||||
config.disableAutoSave();
|
|
||||||
config.save();
|
|
||||||
}
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
0123456789
|
|
||||||
--- ---
|
|
||||||
|
|
||||||
0*4
|
|
||||||
1*5
|
|
||||||
2*6
|
|
||||||
|
|
||||||
1*5
|
|
||||||
2*6 = L + 3*7 - 0*4
|
|
||||||
3*7
|
|
||||||
|
|
||||||
2*6
|
|
||||||
3*7 = L + 4*8 - 1*5
|
|
||||||
4*8
|
|
||||||
|
|
||||||
3*7
|
|
||||||
4*8 = L + 5*9 - 2*6
|
|
||||||
5*9
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
0*5
|
|
||||||
1*6
|
|
||||||
2*7
|
|
||||||
|
|
||||||
1*6
|
|
||||||
2*7
|
|
||||||
3*8
|
|
||||||
|
|
||||||
2*7
|
|
||||||
3*8
|
|
||||||
4*9
|
|
||||||
|
|
||||||
=> Use same technique to cache the interpolation results
|
|
||||||
@@ -20,16 +20,6 @@ enum IFNRPreset {
|
|||||||
IFNR_PRESET_BROADCAST
|
IFNR_PRESET_BROADCAST
|
||||||
};
|
};
|
||||||
|
|
||||||
enum SquelchMode {
|
|
||||||
SQUELCH_MODE_OFF,
|
|
||||||
SQUELCH_MODE_POWER,
|
|
||||||
SQUELCH_MODE_SNR,
|
|
||||||
SQUELCH_MODE_CTCSS_MUTE,
|
|
||||||
SQUELCH_MODE_CTCSS_DECODE,
|
|
||||||
SQUELCH_MODE_DCS_MUTE,
|
|
||||||
SQUELCH_MODE_DCS_DECODE,
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace demod {
|
namespace demod {
|
||||||
class Demodulator {
|
class Demodulator {
|
||||||
public:
|
public:
|
||||||
@@ -55,8 +45,6 @@ namespace demod {
|
|||||||
virtual int getDefaultDeemphasisMode() = 0;
|
virtual int getDefaultDeemphasisMode() = 0;
|
||||||
virtual bool getFMIFNRAllowed() = 0;
|
virtual bool getFMIFNRAllowed() = 0;
|
||||||
virtual bool getNBAllowed() = 0;
|
virtual bool getNBAllowed() = 0;
|
||||||
virtual bool getHighPassAllowed() = 0;
|
|
||||||
virtual bool getSquelchAllowed() = 0;
|
|
||||||
virtual dsp::stream<dsp::stereo_t>* getOutput() = 0;
|
virtual dsp::stream<dsp::stereo_t>* getOutput() = 0;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,12 +40,6 @@ namespace demod {
|
|||||||
|
|
||||||
void showMenu() {
|
void showMenu() {
|
||||||
float menuWidth = ImGui::GetContentRegionAvail().x;
|
float menuWidth = ImGui::GetContentRegionAvail().x;
|
||||||
if (ImGui::Checkbox(("Carrier AGC##_radio_am_carrier_agc_" + name).c_str(), &carrierAgc)) {
|
|
||||||
demod.setAGCMode(carrierAgc ? dsp::demod::AM<dsp::stereo_t>::AGCMode::CARRIER : dsp::demod::AM<dsp::stereo_t>::AGCMode::AUDIO);
|
|
||||||
_config->acquire();
|
|
||||||
_config->conf[name][getName()]["carrierAgc"] = carrierAgc;
|
|
||||||
_config->release(true);
|
|
||||||
}
|
|
||||||
ImGui::LeftLabel("AGC Attack");
|
ImGui::LeftLabel("AGC Attack");
|
||||||
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
|
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
|
||||||
if (ImGui::SliderFloat(("##_radio_am_agc_attack_" + name).c_str(), &agcAttack, 1.0f, 200.0f)) {
|
if (ImGui::SliderFloat(("##_radio_am_agc_attack_" + name).c_str(), &agcAttack, 1.0f, 200.0f)) {
|
||||||
@@ -62,6 +56,12 @@ namespace demod {
|
|||||||
_config->conf[name][getName()]["agcDecay"] = agcDecay;
|
_config->conf[name][getName()]["agcDecay"] = agcDecay;
|
||||||
_config->release(true);
|
_config->release(true);
|
||||||
}
|
}
|
||||||
|
if (ImGui::Checkbox(("Carrier AGC##_radio_am_carrier_agc_" + name).c_str(), &carrierAgc)) {
|
||||||
|
demod.setAGCMode(carrierAgc ? dsp::demod::AM<dsp::stereo_t>::AGCMode::CARRIER : dsp::demod::AM<dsp::stereo_t>::AGCMode::AUDIO);
|
||||||
|
_config->acquire();
|
||||||
|
_config->conf[name][getName()]["carrierAgc"] = carrierAgc;
|
||||||
|
_config->release(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setBandwidth(double bandwidth) { demod.setBandwidth(bandwidth); }
|
void setBandwidth(double bandwidth) { demod.setBandwidth(bandwidth); }
|
||||||
@@ -86,8 +86,6 @@ namespace demod {
|
|||||||
int getDefaultDeemphasisMode() { return DEEMP_MODE_NONE; }
|
int getDefaultDeemphasisMode() { return DEEMP_MODE_NONE; }
|
||||||
bool getFMIFNRAllowed() { return false; }
|
bool getFMIFNRAllowed() { return false; }
|
||||||
bool getNBAllowed() { return false; }
|
bool getNBAllowed() { return false; }
|
||||||
bool getHighPassAllowed() { return true; }
|
|
||||||
bool getSquelchAllowed() { return true; }
|
|
||||||
dsp::stream<dsp::stereo_t>* getOutput() { return &demod.out; }
|
dsp::stream<dsp::stereo_t>* getOutput() { return &demod.out; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -92,8 +92,6 @@ namespace demod {
|
|||||||
int getDefaultDeemphasisMode() { return DEEMP_MODE_NONE; }
|
int getDefaultDeemphasisMode() { return DEEMP_MODE_NONE; }
|
||||||
bool getFMIFNRAllowed() { return false; }
|
bool getFMIFNRAllowed() { return false; }
|
||||||
bool getNBAllowed() { return false; }
|
bool getNBAllowed() { return false; }
|
||||||
bool getHighPassAllowed() { return false; }
|
|
||||||
bool getSquelchAllowed() { return false; }
|
|
||||||
dsp::stream<dsp::stereo_t>* getOutput() { return &demod.out; }
|
dsp::stream<dsp::stereo_t>* getOutput() { return &demod.out; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -79,8 +79,6 @@ namespace demod {
|
|||||||
int getDefaultDeemphasisMode() { return DEEMP_MODE_NONE; }
|
int getDefaultDeemphasisMode() { return DEEMP_MODE_NONE; }
|
||||||
bool getFMIFNRAllowed() { return false; }
|
bool getFMIFNRAllowed() { return false; }
|
||||||
bool getNBAllowed() { return true; }
|
bool getNBAllowed() { return true; }
|
||||||
bool getHighPassAllowed() { return true; }
|
|
||||||
bool getSquelchAllowed() { return true; }
|
|
||||||
dsp::stream<dsp::stereo_t>* getOutput() { return &demod.out; }
|
dsp::stream<dsp::stereo_t>* getOutput() { return &demod.out; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -79,8 +79,6 @@ namespace demod {
|
|||||||
int getDefaultDeemphasisMode() { return DEEMP_MODE_NONE; }
|
int getDefaultDeemphasisMode() { return DEEMP_MODE_NONE; }
|
||||||
bool getFMIFNRAllowed() { return false; }
|
bool getFMIFNRAllowed() { return false; }
|
||||||
bool getNBAllowed() { return true; }
|
bool getNBAllowed() { return true; }
|
||||||
bool getHighPassAllowed() { return true; }
|
|
||||||
bool getSquelchAllowed() { return true; }
|
|
||||||
dsp::stream<dsp::stereo_t>* getOutput() { return &demod.out; }
|
dsp::stream<dsp::stereo_t>* getOutput() { return &demod.out; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -22,11 +22,14 @@ namespace demod {
|
|||||||
if (config->conf[name][getName()].contains("lowPass")) {
|
if (config->conf[name][getName()].contains("lowPass")) {
|
||||||
_lowPass = config->conf[name][getName()]["lowPass"];
|
_lowPass = config->conf[name][getName()]["lowPass"];
|
||||||
}
|
}
|
||||||
|
if (config->conf[name][getName()].contains("highPass")) {
|
||||||
|
_highPass = config->conf[name][getName()]["highPass"];
|
||||||
|
}
|
||||||
_config->release();
|
_config->release();
|
||||||
|
|
||||||
|
|
||||||
// Define structure
|
// Define structure
|
||||||
demod.init(input, getIFSampleRate(), bandwidth, _lowPass);
|
demod.init(input, getIFSampleRate(), bandwidth, _lowPass, _highPass);
|
||||||
}
|
}
|
||||||
|
|
||||||
void start() { demod.start(); }
|
void start() { demod.start(); }
|
||||||
@@ -40,6 +43,12 @@ namespace demod {
|
|||||||
_config->conf[name][getName()]["lowPass"] = _lowPass;
|
_config->conf[name][getName()]["lowPass"] = _lowPass;
|
||||||
_config->release(true);
|
_config->release(true);
|
||||||
}
|
}
|
||||||
|
if (ImGui::Checkbox(("High Pass##_radio_wfm_highpass_" + name).c_str(), &_highPass)) {
|
||||||
|
demod.setHighPass(_highPass);
|
||||||
|
_config->acquire();
|
||||||
|
_config->conf[name][getName()]["highPass"] = _highPass;
|
||||||
|
_config->release(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setBandwidth(double bandwidth) {
|
void setBandwidth(double bandwidth) {
|
||||||
@@ -66,8 +75,6 @@ namespace demod {
|
|||||||
int getDefaultDeemphasisMode() { return DEEMP_MODE_NONE; }
|
int getDefaultDeemphasisMode() { return DEEMP_MODE_NONE; }
|
||||||
bool getFMIFNRAllowed() { return true; }
|
bool getFMIFNRAllowed() { return true; }
|
||||||
bool getNBAllowed() { return false; }
|
bool getNBAllowed() { return false; }
|
||||||
bool getHighPassAllowed() { return true; }
|
|
||||||
bool getSquelchAllowed() { return true; }
|
|
||||||
dsp::stream<dsp::stereo_t>* getOutput() { return &demod.out; }
|
dsp::stream<dsp::stereo_t>* getOutput() { return &demod.out; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -76,6 +83,7 @@ namespace demod {
|
|||||||
ConfigManager* _config = NULL;
|
ConfigManager* _config = NULL;
|
||||||
|
|
||||||
bool _lowPass = true;
|
bool _lowPass = true;
|
||||||
|
bool _highPass = false;
|
||||||
|
|
||||||
std::string name;
|
std::string name;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -59,8 +59,6 @@ namespace demod {
|
|||||||
int getDefaultDeemphasisMode() { return DEEMP_MODE_NONE; }
|
int getDefaultDeemphasisMode() { return DEEMP_MODE_NONE; }
|
||||||
bool getFMIFNRAllowed() { return false; }
|
bool getFMIFNRAllowed() { return false; }
|
||||||
bool getNBAllowed() { return true; }
|
bool getNBAllowed() { return true; }
|
||||||
bool getHighPassAllowed() { return false; }
|
|
||||||
bool getSquelchAllowed() { return false; }
|
|
||||||
dsp::stream<dsp::stereo_t>* getOutput() { return &c2s.out; }
|
dsp::stream<dsp::stereo_t>* getOutput() { return &c2s.out; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -80,8 +80,6 @@ namespace demod {
|
|||||||
int getDefaultDeemphasisMode() { return DEEMP_MODE_NONE; }
|
int getDefaultDeemphasisMode() { return DEEMP_MODE_NONE; }
|
||||||
bool getFMIFNRAllowed() { return false; }
|
bool getFMIFNRAllowed() { return false; }
|
||||||
bool getNBAllowed() { return true; }
|
bool getNBAllowed() { return true; }
|
||||||
bool getHighPassAllowed() { return true; }
|
|
||||||
bool getSquelchAllowed() { return true; }
|
|
||||||
dsp::stream<dsp::stereo_t>* getOutput() { return &demod.out; }
|
dsp::stream<dsp::stereo_t>* getOutput() { return &demod.out; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -100,18 +100,18 @@ namespace demod {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void showMenu() {
|
void showMenu() {
|
||||||
if (ImGui::Checkbox(("Low Pass##_radio_wfm_lowpass_" + name).c_str(), &_lowPass)) {
|
|
||||||
demod.setLowPass(_lowPass);
|
|
||||||
_config->acquire();
|
|
||||||
_config->conf[name][getName()]["lowPass"] = _lowPass;
|
|
||||||
_config->release(true);
|
|
||||||
}
|
|
||||||
if (ImGui::Checkbox(("Stereo##_radio_wfm_stereo_" + name).c_str(), &_stereo)) {
|
if (ImGui::Checkbox(("Stereo##_radio_wfm_stereo_" + name).c_str(), &_stereo)) {
|
||||||
setStereo(_stereo);
|
setStereo(_stereo);
|
||||||
_config->acquire();
|
_config->acquire();
|
||||||
_config->conf[name][getName()]["stereo"] = _stereo;
|
_config->conf[name][getName()]["stereo"] = _stereo;
|
||||||
_config->release(true);
|
_config->release(true);
|
||||||
}
|
}
|
||||||
|
if (ImGui::Checkbox(("Low Pass##_radio_wfm_lowpass_" + name).c_str(), &_lowPass)) {
|
||||||
|
demod.setLowPass(_lowPass);
|
||||||
|
_config->acquire();
|
||||||
|
_config->conf[name][getName()]["lowPass"] = _lowPass;
|
||||||
|
_config->release(true);
|
||||||
|
}
|
||||||
if (ImGui::Checkbox(("Decode RDS##_radio_wfm_rds_" + name).c_str(), &_rds)) {
|
if (ImGui::Checkbox(("Decode RDS##_radio_wfm_rds_" + name).c_str(), &_rds)) {
|
||||||
demod.setRDSOut(_rds);
|
demod.setRDSOut(_rds);
|
||||||
_config->acquire();
|
_config->acquire();
|
||||||
@@ -270,8 +270,6 @@ namespace demod {
|
|||||||
int getDefaultDeemphasisMode() { return DEEMP_MODE_50US; }
|
int getDefaultDeemphasisMode() { return DEEMP_MODE_50US; }
|
||||||
bool getFMIFNRAllowed() { return true; }
|
bool getFMIFNRAllowed() { return true; }
|
||||||
bool getNBAllowed() { return false; }
|
bool getNBAllowed() { return false; }
|
||||||
bool getHighPassAllowed() { return true; }
|
|
||||||
bool getSquelchAllowed() { return true; }
|
|
||||||
dsp::stream<dsp::stereo_t>* getOutput() { return &demod.out; }
|
dsp::stream<dsp::stereo_t>* getOutput() { return &demod.out; }
|
||||||
|
|
||||||
// ============= DEDICATED FUNCTIONS =============
|
// ============= DEDICATED FUNCTIONS =============
|
||||||
|
|||||||
@@ -5,14 +5,10 @@ enum {
|
|||||||
RADIO_IFACE_CMD_SET_MODE,
|
RADIO_IFACE_CMD_SET_MODE,
|
||||||
RADIO_IFACE_CMD_GET_BANDWIDTH,
|
RADIO_IFACE_CMD_GET_BANDWIDTH,
|
||||||
RADIO_IFACE_CMD_SET_BANDWIDTH,
|
RADIO_IFACE_CMD_SET_BANDWIDTH,
|
||||||
RADIO_IFACE_CMD_GET_SQUELCH_MODE,
|
RADIO_IFACE_CMD_GET_SQUELCH_ENABLED,
|
||||||
RADIO_IFACE_CMD_SET_SQUELCH_MODE,
|
RADIO_IFACE_CMD_SET_SQUELCH_ENABLED,
|
||||||
RADIO_IFACE_CMD_GET_SQUELCH_LEVEL,
|
RADIO_IFACE_CMD_GET_SQUELCH_LEVEL,
|
||||||
RADIO_IFACE_CMD_SET_SQUELCH_LEVEL,
|
RADIO_IFACE_CMD_SET_SQUELCH_LEVEL,
|
||||||
RADIO_IFACE_CMD_GET_CTCSS_TONE,
|
|
||||||
RADIO_IFACE_CMD_SET_CTCSS_TONE,
|
|
||||||
RADIO_IFACE_CMD_GET_HIGHPASS,
|
|
||||||
RADIO_IFACE_CMD_SET_HIGHPASS
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
|||||||
@@ -8,8 +8,7 @@
|
|||||||
#include <dsp/chain.h>
|
#include <dsp/chain.h>
|
||||||
#include <dsp/noise_reduction/noise_blanker.h>
|
#include <dsp/noise_reduction/noise_blanker.h>
|
||||||
#include <dsp/noise_reduction/fm_if.h>
|
#include <dsp/noise_reduction/fm_if.h>
|
||||||
#include <dsp/noise_reduction/power_squelch.h>
|
#include <dsp/noise_reduction/squelch.h>
|
||||||
#include <dsp/noise_reduction/ctcss_squelch.h>
|
|
||||||
#include <dsp/multirate/rational_resampler.h>
|
#include <dsp/multirate/rational_resampler.h>
|
||||||
#include <dsp/filter/deephasis.h>
|
#include <dsp/filter/deephasis.h>
|
||||||
#include <core.h>
|
#include <core.h>
|
||||||
@@ -50,22 +49,6 @@ public:
|
|||||||
ifnrPresets.define("Voice", IFNR_PRESET_VOICE);
|
ifnrPresets.define("Voice", IFNR_PRESET_VOICE);
|
||||||
ifnrPresets.define("Narrow Band", IFNR_PRESET_NARROW_BAND);
|
ifnrPresets.define("Narrow Band", IFNR_PRESET_NARROW_BAND);
|
||||||
|
|
||||||
squelchModes.define("off", "Off", SQUELCH_MODE_OFF);
|
|
||||||
squelchModes.define("power", "Power", SQUELCH_MODE_POWER);
|
|
||||||
//squelchModes.define("snr", "SNR", SQUELCH_MODE_SNR);
|
|
||||||
squelchModes.define("ctcss_mute", "CTCSS (Mute)", SQUELCH_MODE_CTCSS_MUTE);
|
|
||||||
squelchModes.define("ctcss_decode", "CTCSS (Decode Only)", SQUELCH_MODE_CTCSS_DECODE);
|
|
||||||
//squelchModes.define("dcs_mute", "DCS (Mute)", SQUELCH_MODE_DCS_MUTE);
|
|
||||||
//squelchModes.define("dcs_decode", "DCS (Decode Only)", SQUELCH_MODE_DCS_DECODE);
|
|
||||||
|
|
||||||
for (int i = 0; i < dsp::noise_reduction::_CTCSS_TONE_COUNT; i++) {
|
|
||||||
float tone = dsp::noise_reduction::CTCSS_TONES[i];
|
|
||||||
char buf[64];
|
|
||||||
sprintf(buf, "%.1fHz", tone);
|
|
||||||
ctcssTones.define((int)round(tone) * 10, buf, (dsp::noise_reduction::CTCSSTone)i);
|
|
||||||
}
|
|
||||||
ctcssTones.define(-1, "Any", dsp::noise_reduction::CTCSS_TONE_ANY);
|
|
||||||
|
|
||||||
// Initialize the config if it doesn't exist
|
// Initialize the config if it doesn't exist
|
||||||
bool created = false;
|
bool created = false;
|
||||||
config.acquire();
|
config.acquire();
|
||||||
@@ -89,24 +72,19 @@ public:
|
|||||||
|
|
||||||
nb.init(NULL, 500.0 / 24000.0, 10.0);
|
nb.init(NULL, 500.0 / 24000.0, 10.0);
|
||||||
fmnr.init(NULL, 32);
|
fmnr.init(NULL, 32);
|
||||||
powerSquelch.init(NULL, MIN_SQUELCH);
|
squelch.init(NULL, MIN_SQUELCH);
|
||||||
|
|
||||||
ifChain.addBlock(&nb, false);
|
ifChain.addBlock(&nb, false);
|
||||||
ifChain.addBlock(&powerSquelch, false);
|
ifChain.addBlock(&squelch, false);
|
||||||
ifChain.addBlock(&fmnr, false);
|
ifChain.addBlock(&fmnr, false);
|
||||||
|
|
||||||
// Initialize audio DSP chain
|
// Initialize audio DSP chain
|
||||||
afChain.init(&dummyAudioStream);
|
afChain.init(&dummyAudioStream);
|
||||||
|
|
||||||
ctcss.init(NULL, 50000.0);
|
|
||||||
resamp.init(NULL, 250000.0, 48000.0);
|
resamp.init(NULL, 250000.0, 48000.0);
|
||||||
hpTaps = dsp::taps::highPass(300.0, 100.0, 48000.0);
|
|
||||||
hpf.init(NULL, hpTaps);
|
|
||||||
deemp.init(NULL, 50e-6, 48000.0);
|
deemp.init(NULL, 50e-6, 48000.0);
|
||||||
|
|
||||||
afChain.addBlock(&ctcss, false);
|
|
||||||
afChain.addBlock(&resamp, true);
|
afChain.addBlock(&resamp, true);
|
||||||
afChain.addBlock(&hpf, false);
|
|
||||||
afChain.addBlock(&deemp, false);
|
afChain.addBlock(&deemp, false);
|
||||||
|
|
||||||
// Initialize the sink
|
// Initialize the sink
|
||||||
@@ -255,33 +233,6 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Squelch
|
|
||||||
if (_this->squelchAllowed) {
|
|
||||||
ImGui::LeftLabel("Squelch Mode");
|
|
||||||
ImGui::FillWidth();
|
|
||||||
if (ImGui::Combo(("##_radio_sqelch_mode_" + _this->name).c_str(), &_this->squelchModeId, _this->squelchModes.txt)) {
|
|
||||||
_this->setSquelchMode(_this->squelchModes[_this->squelchModeId]);
|
|
||||||
}
|
|
||||||
switch (_this->squelchModes[_this->squelchModeId]) {
|
|
||||||
case SQUELCH_MODE_POWER:
|
|
||||||
ImGui::LeftLabel("Squelch Level");
|
|
||||||
ImGui::FillWidth();
|
|
||||||
if (ImGui::SliderFloat(("##_radio_sqelch_lvl_" + _this->name).c_str(), &_this->squelchLevel, _this->MIN_SQUELCH, _this->MAX_SQUELCH, "%.3fdB")) {
|
|
||||||
_this->setSquelchLevel(_this->squelchLevel);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SQUELCH_MODE_CTCSS_MUTE:
|
|
||||||
if (_this->squelchModes[_this->squelchModeId] == SQUELCH_MODE_CTCSS_MUTE) {
|
|
||||||
ImGui::LeftLabel("CTCSS Tone");
|
|
||||||
ImGui::FillWidth();
|
|
||||||
if (ImGui::Combo(("##_radio_ctcss_tone_" + _this->name).c_str(), &_this->ctcssToneId, _this->ctcssTones.txt)) {
|
|
||||||
_this->setCTCSSTone(_this->ctcssTones[_this->ctcssToneId]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Noise blanker
|
// Noise blanker
|
||||||
if (_this->nbAllowed) {
|
if (_this->nbAllowed) {
|
||||||
if (ImGui::Checkbox(("Noise blanker (W.I.P.)##_radio_nb_ena_" + _this->name).c_str(), &_this->nbEnabled)) {
|
if (ImGui::Checkbox(("Noise blanker (W.I.P.)##_radio_nb_ena_" + _this->name).c_str(), &_this->nbEnabled)) {
|
||||||
@@ -295,6 +246,19 @@ private:
|
|||||||
}
|
}
|
||||||
if (!_this->nbEnabled && _this->enabled) { style::endDisabled(); }
|
if (!_this->nbEnabled && _this->enabled) { style::endDisabled(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Squelch
|
||||||
|
if (ImGui::Checkbox(("Squelch##_radio_sqelch_ena_" + _this->name).c_str(), &_this->squelchEnabled)) {
|
||||||
|
_this->setSquelchEnabled(_this->squelchEnabled);
|
||||||
|
}
|
||||||
|
if (!_this->squelchEnabled && _this->enabled) { style::beginDisabled(); }
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
|
||||||
|
if (ImGui::SliderFloat(("##_radio_sqelch_lvl_" + _this->name).c_str(), &_this->squelchLevel, _this->MIN_SQUELCH, _this->MAX_SQUELCH, "%.3fdB")) {
|
||||||
|
_this->setSquelchLevel(_this->squelchLevel);
|
||||||
|
}
|
||||||
|
if (!_this->squelchEnabled && _this->enabled) { style::endDisabled(); }
|
||||||
|
|
||||||
// FM IF Noise Reduction
|
// FM IF Noise Reduction
|
||||||
if (_this->FMIFNRAllowed) {
|
if (_this->FMIFNRAllowed) {
|
||||||
@@ -312,53 +276,9 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// High pass
|
|
||||||
if (_this->highPassAllowed) {
|
|
||||||
if (ImGui::Checkbox(("High Pass##_radio_hpf_" + _this->name).c_str(), &_this->highPass)) {
|
|
||||||
_this->setHighPass(_this->highPass);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Demodulator specific menu
|
// Demodulator specific menu
|
||||||
_this->selectedDemod->showMenu();
|
_this->selectedDemod->showMenu();
|
||||||
|
|
||||||
// Display the squelch diagnostics
|
|
||||||
switch (_this->squelchModes[_this->squelchModeId]) {
|
|
||||||
case SQUELCH_MODE_CTCSS_MUTE:
|
|
||||||
ImGui::TextUnformatted("Received Tone:");
|
|
||||||
ImGui::SameLine();
|
|
||||||
{
|
|
||||||
auto ctone = _this->ctcss.getCurrentTone();
|
|
||||||
auto dtone = _this->ctcssTones[_this->ctcssToneId];
|
|
||||||
if (ctone != dsp::noise_reduction::CTCSS_TONE_NONE) {
|
|
||||||
if (dtone == dsp::noise_reduction::CTCSS_TONE_ANY || ctone == dtone) {
|
|
||||||
ImGui::TextColored(ImVec4(0, 1, 0, 1), "%.1fHz", dsp::noise_reduction::CTCSS_TONES[_this->ctcss.getCurrentTone()]);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ImGui::TextColored(ImVec4(1, 0, 0, 1), "%.1fHz", dsp::noise_reduction::CTCSS_TONES[_this->ctcss.getCurrentTone()]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ImGui::TextUnformatted("None");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SQUELCH_MODE_CTCSS_DECODE:
|
|
||||||
ImGui::TextUnformatted("Received Tone:");
|
|
||||||
ImGui::SameLine();
|
|
||||||
{
|
|
||||||
auto ctone = _this->ctcss.getCurrentTone();
|
|
||||||
if (ctone != dsp::noise_reduction::CTCSS_TONE_NONE) {
|
|
||||||
ImGui::TextColored(ImVec4(0, 1, 0, 1), "%.1fHz", dsp::noise_reduction::CTCSS_TONES[_this->ctcss.getCurrentTone()]);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ImGui::TextUnformatted("None");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_this->enabled) { style::endDisabled(); }
|
if (!_this->enabled) { style::endDisabled(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -367,13 +287,13 @@ private:
|
|||||||
switch (id) {
|
switch (id) {
|
||||||
case DemodID::RADIO_DEMOD_NFM: demod = new demod::NFM(); break;
|
case DemodID::RADIO_DEMOD_NFM: demod = new demod::NFM(); break;
|
||||||
case DemodID::RADIO_DEMOD_WFM: demod = new demod::WFM(); break;
|
case DemodID::RADIO_DEMOD_WFM: demod = new demod::WFM(); break;
|
||||||
case DemodID::RADIO_DEMOD_AM: demod = new demod::AM(); break;
|
case DemodID::RADIO_DEMOD_AM: demod = new demod::AM(); break;
|
||||||
case DemodID::RADIO_DEMOD_DSB: demod = new demod::DSB(); break;
|
case DemodID::RADIO_DEMOD_DSB: demod = new demod::DSB(); break;
|
||||||
case DemodID::RADIO_DEMOD_USB: demod = new demod::USB(); break;
|
case DemodID::RADIO_DEMOD_USB: demod = new demod::USB(); break;
|
||||||
case DemodID::RADIO_DEMOD_CW: demod = new demod::CW(); break;
|
case DemodID::RADIO_DEMOD_CW: demod = new demod::CW(); break;
|
||||||
case DemodID::RADIO_DEMOD_LSB: demod = new demod::LSB(); break;
|
case DemodID::RADIO_DEMOD_LSB: demod = new demod::LSB(); break;
|
||||||
case DemodID::RADIO_DEMOD_RAW: demod = new demod::RAW(); break;
|
case DemodID::RADIO_DEMOD_RAW: demod = new demod::RAW(); break;
|
||||||
default: demod = NULL; break;
|
default: demod = NULL; break;
|
||||||
}
|
}
|
||||||
if (!demod) { return NULL; }
|
if (!demod) { return NULL; }
|
||||||
|
|
||||||
@@ -440,20 +360,15 @@ private:
|
|||||||
maxBandwidth = selectedDemod->getMaxBandwidth();
|
maxBandwidth = selectedDemod->getMaxBandwidth();
|
||||||
bandwidthLocked = selectedDemod->getBandwidthLocked();
|
bandwidthLocked = selectedDemod->getBandwidthLocked();
|
||||||
snapInterval = selectedDemod->getDefaultSnapInterval();
|
snapInterval = selectedDemod->getDefaultSnapInterval();
|
||||||
|
squelchLevel = MIN_SQUELCH;
|
||||||
deempAllowed = selectedDemod->getDeempAllowed();
|
deempAllowed = selectedDemod->getDeempAllowed();
|
||||||
deempId = deempModes.valueId((DeemphasisMode)selectedDemod->getDefaultDeemphasisMode());
|
deempId = deempModes.valueId((DeemphasisMode)selectedDemod->getDefaultDeemphasisMode());
|
||||||
squelchModeId = squelchModes.valueId(SQUELCH_MODE_OFF);
|
squelchEnabled = false;
|
||||||
squelchLevel = MIN_SQUELCH;
|
|
||||||
ctcssToneId = ctcssTones.valueId(dsp::noise_reduction::CTCSS_TONE_67Hz);
|
|
||||||
highPass = false;
|
|
||||||
|
|
||||||
postProcEnabled = selectedDemod->getPostProcEnabled();
|
postProcEnabled = selectedDemod->getPostProcEnabled();
|
||||||
FMIFNRAllowed = selectedDemod->getFMIFNRAllowed();
|
FMIFNRAllowed = selectedDemod->getFMIFNRAllowed();
|
||||||
FMIFNREnabled = false;
|
FMIFNREnabled = false;
|
||||||
fmIFPresetId = ifnrPresets.valueId(IFNR_PRESET_VOICE);
|
fmIFPresetId = ifnrPresets.valueId(IFNR_PRESET_VOICE);
|
||||||
nbAllowed = selectedDemod->getNBAllowed();
|
nbAllowed = selectedDemod->getNBAllowed();
|
||||||
squelchAllowed = selectedDemod->getSquelchAllowed();
|
|
||||||
highPassAllowed = selectedDemod->getHighPassAllowed();
|
|
||||||
nbEnabled = false;
|
nbEnabled = false;
|
||||||
nbLevel = 0.0f;
|
nbLevel = 0.0f;
|
||||||
double ifSamplerate = selectedDemod->getIFSampleRate();
|
double ifSamplerate = selectedDemod->getIFSampleRate();
|
||||||
@@ -465,24 +380,11 @@ private:
|
|||||||
if (config.conf[name][selectedDemod->getName()].contains("snapInterval")) {
|
if (config.conf[name][selectedDemod->getName()].contains("snapInterval")) {
|
||||||
snapInterval = config.conf[name][selectedDemod->getName()]["snapInterval"];
|
snapInterval = config.conf[name][selectedDemod->getName()]["snapInterval"];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.conf[name][selectedDemod->getName()].contains("squelchMode")) {
|
|
||||||
std::string squelchModeStr = config.conf[name][selectedDemod->getName()]["squelchMode"];
|
|
||||||
if (squelchModes.keyExists(squelchModeStr)) {
|
|
||||||
squelchModeId = squelchModes.keyId(squelchModeStr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (config.conf[name][selectedDemod->getName()].contains("squelchLevel")) {
|
if (config.conf[name][selectedDemod->getName()].contains("squelchLevel")) {
|
||||||
squelchLevel = config.conf[name][selectedDemod->getName()]["squelchLevel"];
|
squelchLevel = config.conf[name][selectedDemod->getName()]["squelchLevel"];
|
||||||
}
|
}
|
||||||
if (config.conf[name][selectedDemod->getName()].contains("ctcssTone")) {
|
if (config.conf[name][selectedDemod->getName()].contains("squelchEnabled")) {
|
||||||
int ctcssToneX10 = config.conf[name][selectedDemod->getName()]["ctcssTone"];
|
squelchEnabled = config.conf[name][selectedDemod->getName()]["squelchEnabled"];
|
||||||
if (ctcssTones.keyExists(ctcssToneX10)) {
|
|
||||||
ctcssToneId = ctcssTones.keyId(ctcssToneX10);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (config.conf[name][selectedDemod->getName()].contains("highPass")) {
|
|
||||||
highPass = config.conf[name][selectedDemod->getName()]["highPass"];
|
|
||||||
}
|
}
|
||||||
if (config.conf[name][selectedDemod->getName()].contains("deempMode")) {
|
if (config.conf[name][selectedDemod->getName()].contains("deempMode")) {
|
||||||
if (!config.conf[name][selectedDemod->getName()]["deempMode"].is_string()) {
|
if (!config.conf[name][selectedDemod->getName()]["deempMode"].is_string()) {
|
||||||
@@ -532,22 +434,16 @@ private:
|
|||||||
setFMIFNREnabled(FMIFNRAllowed ? FMIFNREnabled : false);
|
setFMIFNREnabled(FMIFNRAllowed ? FMIFNREnabled : false);
|
||||||
|
|
||||||
// Configure squelch
|
// Configure squelch
|
||||||
setSquelchMode(squelchAllowed ? squelchModes[squelchModeId] : SQUELCH_MODE_OFF);
|
|
||||||
setSquelchLevel(squelchLevel);
|
setSquelchLevel(squelchLevel);
|
||||||
setCTCSSTone(ctcssTones[ctcssToneId]);
|
setSquelchEnabled(squelchEnabled);
|
||||||
|
|
||||||
// Configure AF chain
|
// Configure AF chain
|
||||||
if (postProcEnabled) {
|
if (postProcEnabled) {
|
||||||
// Configure resampler
|
// Configure resampler
|
||||||
afChain.stop();
|
afChain.stop();
|
||||||
double afsr = selectedDemod->getAFSampleRate();
|
resamp.setInSamplerate(selectedDemod->getAFSampleRate());
|
||||||
ctcss.setSamplerate(afsr);
|
|
||||||
resamp.setInSamplerate(afsr);
|
|
||||||
afChain.enableBlock(&resamp, [=](dsp::stream<dsp::stereo_t>* out){ stream.setInput(out); });
|
|
||||||
setAudioSampleRate(audioSampleRate);
|
setAudioSampleRate(audioSampleRate);
|
||||||
|
afChain.enableBlock(&resamp, [=](dsp::stream<dsp::stereo_t>* out){ stream.setInput(out); });
|
||||||
// Configure the HPF
|
|
||||||
setHighPass(highPass && highPassAllowed);
|
|
||||||
|
|
||||||
// Configure deemphasis
|
// Configure deemphasis
|
||||||
setDeemphasisMode(deempModes[deempId]);
|
setDeemphasisMode(deempModes[deempId]);
|
||||||
@@ -593,32 +489,12 @@ private:
|
|||||||
// Configure resampler
|
// Configure resampler
|
||||||
resamp.setOutSamplerate(audioSampleRate);
|
resamp.setOutSamplerate(audioSampleRate);
|
||||||
|
|
||||||
// Configure the HPF sample rate
|
|
||||||
hpTaps = dsp::taps::highPass(300.0, 100.0, audioSampleRate);
|
|
||||||
hpf.setTaps(hpTaps);
|
|
||||||
|
|
||||||
// Configure deemphasis sample rate
|
// Configure deemphasis sample rate
|
||||||
deemp.setSamplerate(audioSampleRate);
|
deemp.setSamplerate(audioSampleRate);
|
||||||
|
|
||||||
afChain.start();
|
afChain.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void setHighPass(bool enabled) {
|
|
||||||
// Update the state
|
|
||||||
highPass = enabled;
|
|
||||||
|
|
||||||
// Check if post-processing is enabled and that a demodulator is selected
|
|
||||||
if (!postProcEnabled || !selectedDemod) { return; }
|
|
||||||
|
|
||||||
// Set the state of the HPF in the AF chain
|
|
||||||
afChain.setBlockEnabled(&hpf, enabled, [=](dsp::stream<dsp::stereo_t>* out){ stream.setInput(out); });
|
|
||||||
|
|
||||||
// Save config
|
|
||||||
config.acquire();
|
|
||||||
config.conf[name][selectedDemod->getName()]["highPass"] = enabled;
|
|
||||||
config.release(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setDeemphasisMode(DeemphasisMode mode) {
|
void setDeemphasisMode(DeemphasisMode mode) {
|
||||||
deempId = deempModes.valueId(mode);
|
deempId = deempModes.valueId(mode);
|
||||||
if (!postProcEnabled || !selectedDemod) { return; }
|
if (!postProcEnabled || !selectedDemod) { return; }
|
||||||
@@ -646,7 +522,6 @@ private:
|
|||||||
void setNBLevel(float level) {
|
void setNBLevel(float level) {
|
||||||
nbLevel = std::clamp<float>(level, MIN_NB, MAX_NB);
|
nbLevel = std::clamp<float>(level, MIN_NB, MAX_NB);
|
||||||
nb.setLevel(nbLevel);
|
nb.setLevel(nbLevel);
|
||||||
if (!selectedDemod) { return; }
|
|
||||||
|
|
||||||
// Save config
|
// Save config
|
||||||
config.acquire();
|
config.acquire();
|
||||||
@@ -654,59 +529,20 @@ private:
|
|||||||
config.release(true);
|
config.release(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setSquelchMode(SquelchMode mode) {
|
void setSquelchEnabled(bool enable) {
|
||||||
squelchModeId = squelchModes.valueId(mode);
|
squelchEnabled = enable;
|
||||||
if (!selectedDemod) { return; }
|
if (!selectedDemod) { return; }
|
||||||
|
ifChain.setBlockEnabled(&squelch, squelchEnabled, [=](dsp::stream<dsp::complex_t>* out){ selectedDemod->setInput(out); });
|
||||||
// Disable all squelch blocks
|
|
||||||
ifChain.disableBlock(&powerSquelch, [=](dsp::stream<dsp::complex_t>* out){ selectedDemod->setInput(out); });
|
|
||||||
afChain.disableBlock(&ctcss, [=](dsp::stream<dsp::stereo_t>* out){ stream.setInput(out); });
|
|
||||||
|
|
||||||
// Enable the block depending on the mode
|
|
||||||
switch (mode) {
|
|
||||||
case SQUELCH_MODE_OFF:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SQUELCH_MODE_POWER:
|
|
||||||
// Enable the power squelch block
|
|
||||||
ifChain.enableBlock(&powerSquelch, [=](dsp::stream<dsp::complex_t>* out){ selectedDemod->setInput(out); });
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SQUELCH_MODE_SNR:
|
|
||||||
// TODO
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SQUELCH_MODE_CTCSS_MUTE:
|
|
||||||
// Set the required tone and enable the CTCSS squelch block
|
|
||||||
ctcss.setRequiredTone(ctcssTones[ctcssToneId]);
|
|
||||||
afChain.enableBlock(&ctcss, [=](dsp::stream<dsp::stereo_t>* out){ stream.setInput(out); });
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SQUELCH_MODE_CTCSS_DECODE:
|
|
||||||
// Set the required tone to none and enable the CTCSS squelch block
|
|
||||||
ctcss.setRequiredTone(dsp::noise_reduction::CTCSS_TONE_NONE);
|
|
||||||
afChain.enableBlock(&ctcss, [=](dsp::stream<dsp::stereo_t>* out){ stream.setInput(out); });
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SQUELCH_MODE_DCS_MUTE:
|
|
||||||
// TODO
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SQUELCH_MODE_DCS_DECODE:
|
|
||||||
// TODO
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save config
|
// Save config
|
||||||
config.acquire();
|
config.acquire();
|
||||||
config.conf[name][selectedDemod->getName()]["squelchMode"] = squelchModes.key(squelchModeId);
|
config.conf[name][selectedDemod->getName()]["squelchEnabled"] = squelchEnabled;
|
||||||
config.release(true);
|
config.release(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setSquelchLevel(float level) {
|
void setSquelchLevel(float level) {
|
||||||
squelchLevel = std::clamp<float>(level, MIN_SQUELCH, MAX_SQUELCH);
|
squelchLevel = std::clamp<float>(level, MIN_SQUELCH, MAX_SQUELCH);
|
||||||
powerSquelch.setLevel(squelchLevel);
|
squelch.setLevel(squelchLevel);
|
||||||
if (!selectedDemod) { return; }
|
|
||||||
|
|
||||||
// Save config
|
// Save config
|
||||||
config.acquire();
|
config.acquire();
|
||||||
@@ -714,24 +550,6 @@ private:
|
|||||||
config.release(true);
|
config.release(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setCTCSSTone(dsp::noise_reduction::CTCSSTone tone) {
|
|
||||||
// Check for an invalid value
|
|
||||||
if (tone == dsp::noise_reduction::CTCSS_TONE_NONE) { return; }
|
|
||||||
|
|
||||||
// If not in CTCSS mute mode, do nothing
|
|
||||||
if (squelchModes[squelchModeId] != SQUELCH_MODE_CTCSS_MUTE) { return; }
|
|
||||||
|
|
||||||
// Set the tone
|
|
||||||
ctcssToneId = ctcssTones.valueId(tone);
|
|
||||||
ctcss.setRequiredTone(tone);
|
|
||||||
if (!selectedDemod) { return; }
|
|
||||||
|
|
||||||
// Save config
|
|
||||||
config.acquire();
|
|
||||||
config.conf[name][selectedDemod->getName()]["ctcssTone"] = ctcssTones.key(ctcssToneId);
|
|
||||||
config.release(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setFMIFNREnabled(bool enabled) {
|
void setFMIFNREnabled(bool enabled) {
|
||||||
FMIFNREnabled = enabled;
|
FMIFNREnabled = enabled;
|
||||||
if (!selectedDemod) { return; }
|
if (!selectedDemod) { return; }
|
||||||
@@ -801,13 +619,13 @@ private:
|
|||||||
if (_this->bandwidthLocked) { return; }
|
if (_this->bandwidthLocked) { return; }
|
||||||
_this->setBandwidth(*_in);
|
_this->setBandwidth(*_in);
|
||||||
}
|
}
|
||||||
else if (code == RADIO_IFACE_CMD_GET_SQUELCH_MODE && out) {
|
else if (code == RADIO_IFACE_CMD_GET_SQUELCH_ENABLED && out) {
|
||||||
SquelchMode* _out = (SquelchMode*)out;
|
bool* _out = (bool*)out;
|
||||||
*_out = _this->squelchModes[_this->squelchModeId];
|
*_out = _this->squelchEnabled;
|
||||||
}
|
}
|
||||||
else if (code == RADIO_IFACE_CMD_SET_SQUELCH_MODE && in && _this->enabled) {
|
else if (code == RADIO_IFACE_CMD_SET_SQUELCH_ENABLED && in && _this->enabled) {
|
||||||
SquelchMode* _in = (SquelchMode*)in;
|
bool* _in = (bool*)in;
|
||||||
_this->setSquelchMode(*_in);
|
_this->setSquelchEnabled(*_in);
|
||||||
}
|
}
|
||||||
else if (code == RADIO_IFACE_CMD_GET_SQUELCH_LEVEL && out) {
|
else if (code == RADIO_IFACE_CMD_GET_SQUELCH_LEVEL && out) {
|
||||||
float* _out = (float*)out;
|
float* _out = (float*)out;
|
||||||
@@ -817,22 +635,6 @@ private:
|
|||||||
float* _in = (float*)in;
|
float* _in = (float*)in;
|
||||||
_this->setSquelchLevel(*_in);
|
_this->setSquelchLevel(*_in);
|
||||||
}
|
}
|
||||||
else if (code == RADIO_IFACE_CMD_GET_CTCSS_TONE && out) {
|
|
||||||
dsp::noise_reduction::CTCSSTone* _out = (dsp::noise_reduction::CTCSSTone*)out;
|
|
||||||
*_out = _this->ctcssTones[_this->ctcssToneId];
|
|
||||||
}
|
|
||||||
else if (code == RADIO_IFACE_CMD_SET_CTCSS_TONE && in && _this->enabled) {
|
|
||||||
dsp::noise_reduction::CTCSSTone* _in = (dsp::noise_reduction::CTCSSTone*)in;
|
|
||||||
_this->setCTCSSTone(*_in);
|
|
||||||
}
|
|
||||||
else if (code == RADIO_IFACE_CMD_GET_HIGHPASS && out) {
|
|
||||||
bool* _out = (bool*)out;
|
|
||||||
*_out = _this->highPass;
|
|
||||||
}
|
|
||||||
else if (code == RADIO_IFACE_CMD_SET_HIGHPASS && in && _this->enabled) {
|
|
||||||
bool* _in = (bool*)in;
|
|
||||||
_this->setHighPass(*_in);
|
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -853,15 +655,12 @@ private:
|
|||||||
dsp::chain<dsp::complex_t> ifChain;
|
dsp::chain<dsp::complex_t> ifChain;
|
||||||
dsp::noise_reduction::NoiseBlanker nb;
|
dsp::noise_reduction::NoiseBlanker nb;
|
||||||
dsp::noise_reduction::FMIF fmnr;
|
dsp::noise_reduction::FMIF fmnr;
|
||||||
dsp::noise_reduction::PowerSquelch powerSquelch;
|
dsp::noise_reduction::Squelch squelch;
|
||||||
|
|
||||||
// Audio chain
|
// Audio chain
|
||||||
dsp::stream<dsp::stereo_t> dummyAudioStream;
|
dsp::stream<dsp::stereo_t> dummyAudioStream;
|
||||||
dsp::chain<dsp::stereo_t> afChain;
|
dsp::chain<dsp::stereo_t> afChain;
|
||||||
dsp::noise_reduction::CTCSSSquelch ctcss;
|
|
||||||
dsp::multirate::RationalResampler<dsp::stereo_t> resamp;
|
dsp::multirate::RationalResampler<dsp::stereo_t> resamp;
|
||||||
dsp::tap<float> hpTaps;
|
|
||||||
dsp::filter::FIR<dsp::stereo_t, float> hpf;
|
|
||||||
dsp::filter::Deemphasis<dsp::stereo_t> deemp;
|
dsp::filter::Deemphasis<dsp::stereo_t> deemp;
|
||||||
|
|
||||||
SinkManager::Stream stream;
|
SinkManager::Stream stream;
|
||||||
@@ -870,8 +669,6 @@ private:
|
|||||||
|
|
||||||
OptionList<std::string, DeemphasisMode> deempModes;
|
OptionList<std::string, DeemphasisMode> deempModes;
|
||||||
OptionList<std::string, IFNRPreset> ifnrPresets;
|
OptionList<std::string, IFNRPreset> ifnrPresets;
|
||||||
OptionList<std::string, SquelchMode> squelchModes;
|
|
||||||
OptionList<int, dsp::noise_reduction::CTCSSTone> ctcssTones;
|
|
||||||
|
|
||||||
double audioSampleRate = 48000.0;
|
double audioSampleRate = 48000.0;
|
||||||
float minBandwidth;
|
float minBandwidth;
|
||||||
@@ -882,13 +679,8 @@ private:
|
|||||||
int selectedDemodID = 1;
|
int selectedDemodID = 1;
|
||||||
bool postProcEnabled;
|
bool postProcEnabled;
|
||||||
|
|
||||||
int squelchModeId = 0;
|
bool squelchEnabled = false;
|
||||||
float squelchLevel;
|
float squelchLevel;
|
||||||
int ctcssToneId = 0;
|
|
||||||
bool squelchAllowed = false;
|
|
||||||
|
|
||||||
bool highPass = false;
|
|
||||||
bool highPassAllowed = false;
|
|
||||||
|
|
||||||
int deempId = 0;
|
int deempId = 0;
|
||||||
bool deempAllowed;
|
bool deempAllowed;
|
||||||
|
|||||||
@@ -23,9 +23,9 @@ SDRPP_MOD_INFO{
|
|||||||
/* Max instances */ -1
|
/* Max instances */ -1
|
||||||
};
|
};
|
||||||
|
|
||||||
#define INPUT_BANDWIDTH 600e3
|
#define INPUT_BANDWIDTH 138e3
|
||||||
#define INPUT_SAMPLE_RATE 1000e3
|
#define INPUT_SAMPLE_RATE 250e3
|
||||||
#define INPUT_BAUDRATE 500e3
|
#define INPUT_BAUDRATE 125e3
|
||||||
|
|
||||||
#define SYMBOL_DIAG_RATE 30
|
#define SYMBOL_DIAG_RATE 30
|
||||||
#define SYMBOL_DIAG_COUNT 1024
|
#define SYMBOL_DIAG_COUNT 1024
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stddef.h>
|
|
||||||
#include "dsp/processor.h"
|
#include "dsp/processor.h"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "dsp/processor.h"
|
#include "dsp/processor.h"
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
namespace ryfi {
|
namespace ryfi {
|
||||||
// Synchronization word.
|
// Synchronization word.
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
namespace ryfi {
|
namespace ryfi {
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -72,7 +72,6 @@ namespace ryfi {
|
|||||||
uint8_t* pktBuffer = new uint8_t[Packet::MAX_CONTENT_SIZE];
|
uint8_t* pktBuffer = new uint8_t[Packet::MAX_CONTENT_SIZE];
|
||||||
int pktExpected = 0;
|
int pktExpected = 0;
|
||||||
int pktRead = 0;
|
int pktRead = 0;
|
||||||
int valid = 0;
|
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
// Read a frame
|
// Read a frame
|
||||||
@@ -81,7 +80,6 @@ namespace ryfi {
|
|||||||
|
|
||||||
// Deserialize the frame
|
// Deserialize the frame
|
||||||
Frame::deserialize(rs.out.readBuf, frame);
|
Frame::deserialize(rs.out.readBuf, frame);
|
||||||
valid++;
|
|
||||||
|
|
||||||
// Flush the stream
|
// Flush the stream
|
||||||
rs.out.flush();
|
rs.out.flush();
|
||||||
@@ -95,12 +93,11 @@ namespace ryfi {
|
|||||||
// If the frames aren't consecutive
|
// If the frames aren't consecutive
|
||||||
int frameRead = 0;
|
int frameRead = 0;
|
||||||
if (frame.counter != expectedCounter) {
|
if (frame.counter != expectedCounter) {
|
||||||
flog::warn("Lost at least {} frames after {} valid frames", ((int)frame.counter - (int)expectedCounter + 0x10000) % 0x10000, valid);
|
flog::warn("Lost at least {} frames", ((int)frame.counter - (int)expectedCounter + 0x10000) % 0x10000);
|
||||||
|
|
||||||
// Cancel the partial packet if there was one
|
// Cancel the partial packet if there was one
|
||||||
pktExpected = 0;
|
pktExpected = 0;
|
||||||
pktRead = 0;
|
pktRead = 0;
|
||||||
valid = 1;
|
|
||||||
|
|
||||||
// If this frame is not an idle frame or continuation frame
|
// If this frame is not an idle frame or continuation frame
|
||||||
if (frame.firstPacket != PKT_OFFS_NONE) {
|
if (frame.firstPacket != PKT_OFFS_NONE) {
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stddef.h>
|
|
||||||
#include "dsp/processor.h"
|
#include "dsp/processor.h"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
cmake_minimum_required(VERSION 3.13)
|
|
||||||
project(vor_receiver)
|
|
||||||
|
|
||||||
file(GLOB_RECURSE SRC "src/*.cpp")
|
|
||||||
|
|
||||||
include(${SDRPP_MODULE_CMAKE})
|
|
||||||
|
|
||||||
target_include_directories(vor_receiver PRIVATE "src/")
|
|
||||||
@@ -1,128 +0,0 @@
|
|||||||
#include <imgui.h>
|
|
||||||
#include <config.h>
|
|
||||||
#include <core.h>
|
|
||||||
#include <gui/style.h>
|
|
||||||
#include <gui/gui.h>
|
|
||||||
#include <signal_path/signal_path.h>
|
|
||||||
#include <module.h>
|
|
||||||
#include <filesystem>
|
|
||||||
#include <dsp/buffer/reshaper.h>
|
|
||||||
#include <dsp/sink/handler_sink.h>
|
|
||||||
#include <gui/widgets/constellation_diagram.h>
|
|
||||||
#include "vor_decoder.h"
|
|
||||||
#include <fstream>
|
|
||||||
|
|
||||||
#define CONCAT(a, b) ((std::string(a) + b).c_str())
|
|
||||||
|
|
||||||
SDRPP_MOD_INFO{
|
|
||||||
/* Name: */ "vor_receiver",
|
|
||||||
/* Description: */ "VOR Receiver for SDR++",
|
|
||||||
/* Author: */ "Ryzerth",
|
|
||||||
/* Version: */ 0, 1, 0,
|
|
||||||
/* Max instances */ -1
|
|
||||||
};
|
|
||||||
|
|
||||||
ConfigManager config;
|
|
||||||
|
|
||||||
#define INPUT_SAMPLE_RATE VOR_IN_SR
|
|
||||||
|
|
||||||
class VORReceiverModule : public ModuleManager::Instance {
|
|
||||||
public:
|
|
||||||
VORReceiverModule(std::string name) {
|
|
||||||
this->name = name;
|
|
||||||
|
|
||||||
// Load config
|
|
||||||
config.acquire();
|
|
||||||
// TODO: Load config
|
|
||||||
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);
|
|
||||||
decoder = new vor::Decoder(vfo->output, 1);
|
|
||||||
decoder->onBearing.bind(&VORReceiverModule::onBearing, this);
|
|
||||||
|
|
||||||
decoder->start();
|
|
||||||
|
|
||||||
gui::menu.registerEntry(name, menuHandler, this, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
~VORReceiverModule() {
|
|
||||||
decoder->stop();
|
|
||||||
sigpath::vfoManager.deleteVFO(vfo);
|
|
||||||
gui::menu.removeEntry(name);
|
|
||||||
delete decoder;
|
|
||||||
}
|
|
||||||
|
|
||||||
void postInit() {}
|
|
||||||
|
|
||||||
void enable() {
|
|
||||||
double bw = gui::waterfall.getBandwidth();
|
|
||||||
vfo = sigpath::vfoManager.createVFO(name, ImGui::WaterfallVFO::REF_CENTER, 0, INPUT_SAMPLE_RATE, INPUT_SAMPLE_RATE, INPUT_SAMPLE_RATE, INPUT_SAMPLE_RATE, true);
|
|
||||||
|
|
||||||
decoder->setInput(vfo->output);
|
|
||||||
|
|
||||||
decoder->start();
|
|
||||||
|
|
||||||
enabled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void disable() {
|
|
||||||
decoder->stop();
|
|
||||||
|
|
||||||
sigpath::vfoManager.deleteVFO(vfo);
|
|
||||||
enabled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isEnabled() {
|
|
||||||
return enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
static void menuHandler(void* ctx) {
|
|
||||||
VORReceiverModule* _this = (VORReceiverModule*)ctx;
|
|
||||||
|
|
||||||
float menuWidth = ImGui::GetContentRegionAvail().x;
|
|
||||||
|
|
||||||
if (!_this->enabled) { style::beginDisabled(); }
|
|
||||||
|
|
||||||
ImGui::Text("Bearing: %f°", _this->bearing);
|
|
||||||
ImGui::Text("Quality: %0.1f%%", _this->quality);
|
|
||||||
|
|
||||||
if (!_this->enabled) { style::endDisabled(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
void onBearing(float nbearing, float nquality) {
|
|
||||||
bearing = (180.0f * nbearing / FL_M_PI);
|
|
||||||
quality = nquality * 100.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string name;
|
|
||||||
bool enabled = true;
|
|
||||||
|
|
||||||
// DSP Chain
|
|
||||||
VFOManager::VFO* vfo;
|
|
||||||
vor::Decoder* decoder;
|
|
||||||
|
|
||||||
float bearing = 0.0f, quality = 0.0f;
|
|
||||||
};
|
|
||||||
|
|
||||||
MOD_EXPORT void _INIT_() {
|
|
||||||
// Create default recording directory
|
|
||||||
std::string root = (std::string)core::args["root"];
|
|
||||||
json def = json({});
|
|
||||||
config.setPath(root + "/vor_receiver_config.json");
|
|
||||||
config.load(def);
|
|
||||||
config.enableAutoSave();
|
|
||||||
}
|
|
||||||
|
|
||||||
MOD_EXPORT ModuleManager::Instance* _CREATE_INSTANCE_(std::string name) {
|
|
||||||
return new VORReceiverModule(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
MOD_EXPORT void _DELETE_INSTANCE_(void* instance) {
|
|
||||||
delete (VORReceiverModule*)instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
MOD_EXPORT void _END_() {
|
|
||||||
config.disableAutoSave();
|
|
||||||
config.save();
|
|
||||||
}
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
#include "vor_decoder.h"
|
|
||||||
|
|
||||||
#define STDDEV_NORM_FACTOR 1.813799364234218f // 2.0f * FL_M_PI / sqrt(12)
|
|
||||||
|
|
||||||
namespace vor {
|
|
||||||
Decoder::Decoder(dsp::stream<dsp::complex_t>* in, double integrationTime) {
|
|
||||||
rx.init(in);
|
|
||||||
reshape.init(&rx.out, round(1000.0 * integrationTime), 0);
|
|
||||||
symSink.init(&reshape.out, dataHandler, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
Decoder::~Decoder() {
|
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
void Decoder::setInput(dsp::stream<dsp::complex_t>* in) {
|
|
||||||
rx.setInput(in);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Decoder::start() {
|
|
||||||
rx.start();
|
|
||||||
reshape.start();
|
|
||||||
symSink.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Decoder::stop() {
|
|
||||||
rx.stop();
|
|
||||||
reshape.stop();
|
|
||||||
symSink.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Decoder::dataHandler(float* data, int count, void* ctx) {
|
|
||||||
// Get the instance from context
|
|
||||||
Decoder* _this = (Decoder*)ctx;
|
|
||||||
|
|
||||||
// Compute the mean and standard deviation of the
|
|
||||||
float mean, stddev;
|
|
||||||
volk_32f_stddev_and_mean_32f_x2(&stddev, &mean, data, count);
|
|
||||||
|
|
||||||
// Compute the signal quality
|
|
||||||
float quality = std::max<float>(1.0f - (stddev / STDDEV_NORM_FACTOR), 0.0f);
|
|
||||||
|
|
||||||
// Convert the phase difference to a compass heading
|
|
||||||
mean = -mean;
|
|
||||||
if (mean < 0) { mean = 2.0f*FL_M_PI + mean; }
|
|
||||||
|
|
||||||
// Call the handler
|
|
||||||
_this->onBearing(mean, quality);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
#include "vor_receiver.h"
|
|
||||||
#include <dsp/buffer/reshaper.h>
|
|
||||||
#include <dsp/sink/handler_sink.h>
|
|
||||||
#include <utils/new_event.h>
|
|
||||||
|
|
||||||
namespace vor {
|
|
||||||
// Note: hard coded to 22KHz samplerate
|
|
||||||
class Decoder {
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* Create an instance of a VOR decoder.
|
|
||||||
* @param in Input IQ stream at 22 KHz sampling rate.
|
|
||||||
* @param integrationTime Integration time of the bearing data in seconds.
|
|
||||||
*/
|
|
||||||
Decoder(dsp::stream<dsp::complex_t>* in, double integrationTime);
|
|
||||||
|
|
||||||
// Destructor
|
|
||||||
~Decoder();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the input stream.
|
|
||||||
* @param in Input IQ stream at 22 KHz sampling rate.
|
|
||||||
*/
|
|
||||||
void setInput(dsp::stream<dsp::complex_t>* in);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start the decoder.
|
|
||||||
*/
|
|
||||||
void start();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stop the decoder.
|
|
||||||
*/
|
|
||||||
void stop();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* handler(bearing, signalQuality);
|
|
||||||
*/
|
|
||||||
NewEvent<float, float> onBearing;
|
|
||||||
|
|
||||||
private:
|
|
||||||
static void dataHandler(float* data, int count, void* ctx);
|
|
||||||
|
|
||||||
// DSP
|
|
||||||
Receiver rx;
|
|
||||||
dsp::buffer::Reshaper<float> reshape;
|
|
||||||
dsp::sink::Handler<float> symSink;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,106 +0,0 @@
|
|||||||
#include <dsp/sink.h>
|
|
||||||
#include <dsp/types.h>
|
|
||||||
#include <dsp/demod/am.h>
|
|
||||||
#include <dsp/demod/quadrature.h>
|
|
||||||
#include <dsp/convert/real_to_complex.h>
|
|
||||||
#include <dsp/channel/frequency_xlator.h>
|
|
||||||
#include <dsp/filter/fir.h>
|
|
||||||
#include <dsp/math/delay.h>
|
|
||||||
#include <dsp/math/conjugate.h>
|
|
||||||
#include <dsp/channel/rx_vfo.h>
|
|
||||||
#include "vor_fm_filter.h"
|
|
||||||
#include <utils/wav.h>
|
|
||||||
|
|
||||||
#define VOR_IN_SR 25e3
|
|
||||||
|
|
||||||
namespace vor {
|
|
||||||
class Receiver : public dsp::Processor<dsp::complex_t, float> {
|
|
||||||
using base_type = dsp::Processor<dsp::complex_t, float>;
|
|
||||||
public:
|
|
||||||
Receiver() {}
|
|
||||||
|
|
||||||
Receiver(dsp::stream<dsp::complex_t>* in) { init(in); }
|
|
||||||
|
|
||||||
~Receiver() {
|
|
||||||
if (!base_type::_block_init) { return; }
|
|
||||||
base_type::stop();
|
|
||||||
dsp::taps::free(fmfTaps);
|
|
||||||
}
|
|
||||||
|
|
||||||
void init(dsp::stream<dsp::complex_t>* in) {
|
|
||||||
amd.init(NULL, dsp::demod::AM<float>::CARRIER, VOR_IN_SR, 50.0f / VOR_IN_SR, 5.0f / VOR_IN_SR, 100.0f / VOR_IN_SR, VOR_IN_SR);
|
|
||||||
amr2c.init(NULL);
|
|
||||||
fmr2c.init(NULL);
|
|
||||||
fmx.init(NULL, -9960, VOR_IN_SR);
|
|
||||||
fmfTaps = dsp::taps::fromArray(FM_TAPS_COUNT, fm_taps);
|
|
||||||
fmf.init(NULL, fmfTaps);
|
|
||||||
fmd.init(NULL, 600, VOR_IN_SR);
|
|
||||||
amde.init(NULL, FM_TAPS_COUNT / 2);
|
|
||||||
amv.init(NULL, VOR_IN_SR, 1000, 30, 30);
|
|
||||||
fmv.init(NULL, VOR_IN_SR, 1000, 30, 30);
|
|
||||||
|
|
||||||
base_type::init(in);
|
|
||||||
}
|
|
||||||
|
|
||||||
int process(dsp::complex_t* in, float* out, int count) {
|
|
||||||
// Demodulate the AM outer modulation
|
|
||||||
volk_32fc_magnitude_32f(amd.out.writeBuf, (lv_32fc_t*)in, count);
|
|
||||||
amr2c.process(count, amd.out.writeBuf, amr2c.out.writeBuf);
|
|
||||||
|
|
||||||
// Isolate the FM subcarrier
|
|
||||||
fmx.process(count, amr2c.out.writeBuf, fmx.out.writeBuf);
|
|
||||||
fmf.process(count, fmx.out.writeBuf, fmx.out.writeBuf);
|
|
||||||
|
|
||||||
// Demodulate the FM subcarrier
|
|
||||||
fmd.process(count, fmx.out.writeBuf, fmd.out.writeBuf);
|
|
||||||
fmr2c.process(count, fmd.out.writeBuf, fmr2c.out.writeBuf);
|
|
||||||
|
|
||||||
// Delay the AM signal by the same amount as the FM one
|
|
||||||
amde.process(count, amr2c.out.writeBuf, amr2c.out.writeBuf);
|
|
||||||
|
|
||||||
// Isolate the 30Hz component on both the AM and FM channels
|
|
||||||
int rcount = amv.process(count, amr2c.out.writeBuf, amv.out.writeBuf);
|
|
||||||
fmv.process(count, fmr2c.out.writeBuf, fmv.out.writeBuf);
|
|
||||||
|
|
||||||
// If no data was returned, we're done for this round
|
|
||||||
if (!rcount) { return 0; }
|
|
||||||
|
|
||||||
// Conjugate FM reference
|
|
||||||
volk_32fc_conjugate_32fc((lv_32fc_t*)fmv.out.writeBuf, (lv_32fc_t*)fmv.out.writeBuf, rcount);
|
|
||||||
|
|
||||||
// Multiply both together
|
|
||||||
volk_32fc_x2_multiply_32fc((lv_32fc_t*)amv.out.writeBuf, (lv_32fc_t*)amv.out.writeBuf, (lv_32fc_t*)fmv.out.writeBuf, rcount);
|
|
||||||
|
|
||||||
// Compute angle
|
|
||||||
volk_32fc_s32f_atan2_32f(out, (lv_32fc_t*)amv.out.writeBuf, 1.0f, rcount);
|
|
||||||
|
|
||||||
return rcount;
|
|
||||||
}
|
|
||||||
|
|
||||||
int run() {
|
|
||||||
int count = base_type::_in->read();
|
|
||||||
if (count < 0) { return -1; }
|
|
||||||
|
|
||||||
int outCount = process(base_type::_in->readBuf, base_type::out.writeBuf, count);
|
|
||||||
|
|
||||||
// Swap if some data was generated
|
|
||||||
base_type::_in->flush();
|
|
||||||
if (outCount) {
|
|
||||||
if (!base_type::out.swap(outCount)) { return -1; }
|
|
||||||
}
|
|
||||||
return outCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
dsp::demod::AM<float> amd;
|
|
||||||
dsp::convert::RealToComplex amr2c;
|
|
||||||
dsp::convert::RealToComplex fmr2c;
|
|
||||||
dsp::channel::FrequencyXlator fmx;
|
|
||||||
dsp::tap<float> fmfTaps;
|
|
||||||
dsp::filter::FIR<dsp::complex_t, float> fmf;
|
|
||||||
dsp::demod::Quadrature fmd;
|
|
||||||
dsp::math::Delay<dsp::complex_t> amde;
|
|
||||||
dsp::channel::RxVFO amv;
|
|
||||||
dsp::channel::RxVFO fmv;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -9,11 +9,10 @@ apt install -y build-essential cmake git libfftw3-dev libglfw3-dev libvolk2-dev
|
|||||||
libcodec2-dev autoconf libtool xxd libspdlog-dev
|
libcodec2-dev autoconf libtool xxd libspdlog-dev
|
||||||
|
|
||||||
# Install SDRPlay libraries
|
# Install SDRPlay libraries
|
||||||
SDRPLAY_ARCH=$(dpkg --print-architecture)
|
wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.15.1.run
|
||||||
wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.15.2.run
|
7z x ./SDRplay_RSP_API-Linux-3.15.1.run
|
||||||
7z x ./SDRplay_RSP_API-Linux-3.15.2.run
|
7z x ./SDRplay_RSP_API-Linux-3.15.1
|
||||||
7z x ./SDRplay_RSP_API-Linux-3.15.2
|
cp x86_64/libsdrplay_api.so.3.15 /usr/lib/libsdrplay_api.so
|
||||||
cp $SDRPLAY_ARCH/libsdrplay_api.so.3.15 /usr/lib/libsdrplay_api.so
|
|
||||||
cp inc/* /usr/include/
|
cp inc/* /usr/include/
|
||||||
|
|
||||||
# Install libperseus
|
# Install libperseus
|
||||||
@@ -36,42 +35,10 @@ make -j2
|
|||||||
make install
|
make install
|
||||||
cd ../../
|
cd ../../
|
||||||
|
|
||||||
# Install libfobos
|
|
||||||
git clone https://github.com/AlexandreRouma/libfobos
|
|
||||||
cd libfobos
|
|
||||||
mkdir build
|
|
||||||
cd build
|
|
||||||
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr
|
|
||||||
make -j2
|
|
||||||
make install
|
|
||||||
cd ../../
|
|
||||||
|
|
||||||
# Install libhydrasdr
|
|
||||||
git clone https://github.com/hydrasdr/rfone_host
|
|
||||||
cd rfone_host
|
|
||||||
mkdir build
|
|
||||||
cd build
|
|
||||||
cmake ..
|
|
||||||
make -j2
|
|
||||||
make install
|
|
||||||
cd ../../
|
|
||||||
|
|
||||||
# Install libdlcr
|
|
||||||
wget https://dragnlabs.com/host-tools/dlcr_host_v0.3.0.zip
|
|
||||||
mkdir dlcr_host
|
|
||||||
cd dlcr_host
|
|
||||||
7z x ../dlcr_host_v0.3.0.zip
|
|
||||||
mkdir build
|
|
||||||
cd build
|
|
||||||
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr
|
|
||||||
make -j2
|
|
||||||
make install
|
|
||||||
cd ../../
|
|
||||||
|
|
||||||
cd SDRPlusPlus
|
cd SDRPlusPlus
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
cmake .. -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON -DOPT_BUILD_PERSEUS_SOURCE=ON -DOPT_BUILD_RFNM_SOURCE=ON -DOPT_BUILD_FOBOSSDR_SOURCE=ON -DOPT_BUILD_HYDRASDR_SOURCE=ON -DOPT_BUILD_DRAGONLABS_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 -DOPT_BUILD_PERSEUS_SOURCE=ON -DOPT_BUILD_RFNM_SOURCE=ON
|
||||||
make VERBOSE=1 -j2
|
make VERBOSE=1 -j2
|
||||||
|
|
||||||
cd ..
|
cd ..
|
||||||
|
|||||||
@@ -9,11 +9,10 @@ apt install -y build-essential cmake git libfftw3-dev libglfw3-dev libvolk2-dev
|
|||||||
libcodec2-dev autoconf libtool xxd libspdlog-dev
|
libcodec2-dev autoconf libtool xxd libspdlog-dev
|
||||||
|
|
||||||
# Install SDRPlay libraries
|
# Install SDRPlay libraries
|
||||||
SDRPLAY_ARCH=$(dpkg --print-architecture)
|
wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.15.1.run
|
||||||
wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.15.2.run
|
7z x ./SDRplay_RSP_API-Linux-3.15.1.run
|
||||||
7z x ./SDRplay_RSP_API-Linux-3.15.2.run
|
7z x ./SDRplay_RSP_API-Linux-3.15.1
|
||||||
7z x ./SDRplay_RSP_API-Linux-3.15.2
|
cp x86_64/libsdrplay_api.so.3.15 /usr/lib/libsdrplay_api.so
|
||||||
cp $SDRPLAY_ARCH/libsdrplay_api.so.3.15 /usr/lib/libsdrplay_api.so
|
|
||||||
cp inc/* /usr/include/
|
cp inc/* /usr/include/
|
||||||
|
|
||||||
# Install libperseus
|
# Install libperseus
|
||||||
@@ -36,42 +35,10 @@ make -j2
|
|||||||
make install
|
make install
|
||||||
cd ../../
|
cd ../../
|
||||||
|
|
||||||
# Install libfobos
|
|
||||||
git clone https://github.com/AlexandreRouma/libfobos
|
|
||||||
cd libfobos
|
|
||||||
mkdir build
|
|
||||||
cd build
|
|
||||||
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr
|
|
||||||
make -j2
|
|
||||||
make install
|
|
||||||
cd ../../
|
|
||||||
|
|
||||||
# Install libhydrasdr
|
|
||||||
git clone https://github.com/hydrasdr/rfone_host
|
|
||||||
cd rfone_host
|
|
||||||
mkdir build
|
|
||||||
cd build
|
|
||||||
cmake ..
|
|
||||||
make -j2
|
|
||||||
make install
|
|
||||||
cd ../../
|
|
||||||
|
|
||||||
# Install libdlcr
|
|
||||||
wget https://dragnlabs.com/host-tools/dlcr_host_v0.3.0.zip
|
|
||||||
mkdir dlcr_host
|
|
||||||
cd dlcr_host
|
|
||||||
7z x ../dlcr_host_v0.3.0.zip
|
|
||||||
mkdir build
|
|
||||||
cd build
|
|
||||||
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr
|
|
||||||
make -j2
|
|
||||||
make install
|
|
||||||
cd ../../
|
|
||||||
|
|
||||||
cd SDRPlusPlus
|
cd SDRPlusPlus
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
cmake .. -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON -DOPT_BUILD_PERSEUS_SOURCE=ON -DOPT_BUILD_RFNM_SOURCE=ON -DOPT_BUILD_FOBOSSDR_SOURCE=ON -DOPT_BUILD_HYDRASDR_SOURCE=ON -DOPT_BUILD_DRAGONLABS_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 -DOPT_BUILD_PERSEUS_SOURCE=ON -DOPT_BUILD_RFNM_SOURCE=ON
|
||||||
make VERBOSE=1 -j2
|
make VERBOSE=1 -j2
|
||||||
|
|
||||||
cd ..
|
cd ..
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM debian:trixie
|
FROM debian:buster
|
||||||
ENV DEBIAN_FRONTEND=noninteractive
|
ENV DEBIAN_FRONTEND=noninteractive
|
||||||
COPY do_build.sh /root
|
COPY do_build.sh /root
|
||||||
RUN chmod +x /root/do_build.sh
|
RUN chmod +x /root/do_build.sh
|
||||||
45
docker_builds/debian_buster/do_build.sh
Normal file
45
docker_builds/debian_buster/do_build.sh
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
cd /root
|
||||||
|
|
||||||
|
# Install dependencies and tools
|
||||||
|
apt update
|
||||||
|
apt install -y build-essential cmake git libfftw3-dev libglfw3-dev libvolk1-dev libzstd-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 libspdlog-dev
|
||||||
|
|
||||||
|
# Install SDRPlay libraries
|
||||||
|
wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.15.1.run
|
||||||
|
7z x ./SDRplay_RSP_API-Linux-3.15.1.run
|
||||||
|
7z x ./SDRplay_RSP_API-Linux-3.15.1
|
||||||
|
cp x86_64/libsdrplay_api.so.3.15 /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 ..
|
||||||
|
|
||||||
|
# Install librfnm
|
||||||
|
git clone https://github.com/AlexandreRouma/librfnm
|
||||||
|
cd librfnm
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr
|
||||||
|
make -j2
|
||||||
|
make install
|
||||||
|
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 -DOPT_BUILD_RFNM_SOURCE=ON
|
||||||
|
make VERBOSE=1 -j2
|
||||||
|
|
||||||
|
cd ..
|
||||||
|
sh make_debian_package.sh ./build 'libfftw3-dev, libglfw3-dev, libvolk1-dev, librtaudio-dev, libzstd-dev'
|
||||||
@@ -9,11 +9,10 @@ apt install -y build-essential cmake git libfftw3-dev libglfw3-dev libvolk-dev l
|
|||||||
libcodec2-dev autoconf libtool xxd libspdlog-dev
|
libcodec2-dev autoconf libtool xxd libspdlog-dev
|
||||||
|
|
||||||
# Install SDRPlay libraries
|
# Install SDRPlay libraries
|
||||||
SDRPLAY_ARCH=$(dpkg --print-architecture)
|
wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.15.1.run
|
||||||
wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.15.2.run
|
7z x ./SDRplay_RSP_API-Linux-3.15.1.run
|
||||||
7z x ./SDRplay_RSP_API-Linux-3.15.2.run
|
7z x ./SDRplay_RSP_API-Linux-3.15.1
|
||||||
7z x ./SDRplay_RSP_API-Linux-3.15.2
|
cp x86_64/libsdrplay_api.so.3.15 /usr/lib/libsdrplay_api.so
|
||||||
cp $SDRPLAY_ARCH/libsdrplay_api.so.3.15 /usr/lib/libsdrplay_api.so
|
|
||||||
cp inc/* /usr/include/
|
cp inc/* /usr/include/
|
||||||
|
|
||||||
# Install libperseus
|
# Install libperseus
|
||||||
@@ -36,42 +35,10 @@ make -j2
|
|||||||
make install
|
make install
|
||||||
cd ../../
|
cd ../../
|
||||||
|
|
||||||
# Install libfobos
|
|
||||||
git clone https://github.com/AlexandreRouma/libfobos
|
|
||||||
cd libfobos
|
|
||||||
mkdir build
|
|
||||||
cd build
|
|
||||||
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr
|
|
||||||
make -j2
|
|
||||||
make install
|
|
||||||
cd ../../
|
|
||||||
|
|
||||||
# Install libhydrasdr
|
|
||||||
git clone https://github.com/hydrasdr/rfone_host
|
|
||||||
cd rfone_host
|
|
||||||
mkdir build
|
|
||||||
cd build
|
|
||||||
cmake ..
|
|
||||||
make -j2
|
|
||||||
make install
|
|
||||||
cd ../../
|
|
||||||
|
|
||||||
# Install libdlcr
|
|
||||||
wget https://dragnlabs.com/host-tools/dlcr_host_v0.3.0.zip
|
|
||||||
mkdir dlcr_host
|
|
||||||
cd dlcr_host
|
|
||||||
7z x ../dlcr_host_v0.3.0.zip
|
|
||||||
mkdir build
|
|
||||||
cd build
|
|
||||||
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr
|
|
||||||
make -j2
|
|
||||||
make install
|
|
||||||
cd ../../
|
|
||||||
|
|
||||||
cd SDRPlusPlus
|
cd SDRPlusPlus
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
cmake .. -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON -DOPT_BUILD_PERSEUS_SOURCE=ON -DOPT_BUILD_RFNM_SOURCE=ON -DOPT_BUILD_FOBOSSDR_SOURCE=ON -DOPT_BUILD_HYDRASDR_SOURCE=ON -DOPT_BUILD_DRAGONLABS_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 -DOPT_BUILD_PERSEUS_SOURCE=ON -DOPT_BUILD_RFNM_SOURCE=ON
|
||||||
make VERBOSE=1 -j2
|
make VERBOSE=1 -j2
|
||||||
|
|
||||||
cd ..
|
cd ..
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM ubuntu:oracular
|
FROM fedora:40
|
||||||
ENV DEBIAN_FRONTEND=noninteractive
|
ENV DEBIAN_FRONTEND=noninteractive
|
||||||
COPY do_build.sh /root
|
COPY do_build.sh /root
|
||||||
RUN chmod +x /root/do_build.sh
|
RUN chmod +x /root/do_build.sh
|
||||||
31
docker_builds/fedora_40/do_build.sh
Normal file
31
docker_builds/fedora_40/do_build.sh
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
cd /root
|
||||||
|
|
||||||
|
# Install dependencies and tools
|
||||||
|
dnf update -y
|
||||||
|
dnf install -y make gcc g++ cmake git wget p7zip fftw-devel glfw-devel volk-devel libzstd-devel codec2-devel airspyone_host-devel rtaudio-devel \
|
||||||
|
hackrf-devel rtl-sdr-devel portaudio-devel spdlog-devel libusbg-devel
|
||||||
|
|
||||||
|
# Install SDRPlay libraries
|
||||||
|
wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.15.1.run
|
||||||
|
7za x ./SDRplay_RSP_API-Linux-3.15.1.run
|
||||||
|
7za x ./SDRplay_RSP_API-Linux-3.15.1
|
||||||
|
cp x86_64/libsdrplay_api.so.3.15 /usr/lib/libsdrplay_api.so
|
||||||
|
cp inc/* /usr/include/
|
||||||
|
|
||||||
|
# Install librfnm
|
||||||
|
git clone https://github.com/AlexandreRouma/librfnm
|
||||||
|
cd librfnm
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr
|
||||||
|
make -j2
|
||||||
|
make install
|
||||||
|
cd ../../
|
||||||
|
|
||||||
|
cd SDRPlusPlus
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake .. -DOPT_BUILD_AIRSPYHF_SOURCE=OFF -DOPT_BUILD_PLUTOSDR_SOURCE=OFF -DOPT_BUILD_RFNM_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON
|
||||||
|
make VERBOSE=1 -j2
|
||||||
@@ -15,11 +15,10 @@ apt install -y build-essential cmake git libfftw3-dev libglfw3-dev libvolk1-dev
|
|||||||
libcodec2-dev libudev-dev autoconf libtool xxd libspdlog-dev
|
libcodec2-dev libudev-dev autoconf libtool xxd libspdlog-dev
|
||||||
|
|
||||||
# Install SDRPlay libraries
|
# Install SDRPlay libraries
|
||||||
SDRPLAY_ARCH=$(dpkg --print-architecture)
|
wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.15.1.run
|
||||||
wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.15.2.run
|
7z x ./SDRplay_RSP_API-Linux-3.15.1.run
|
||||||
7z x ./SDRplay_RSP_API-Linux-3.15.2.run
|
7z x ./SDRplay_RSP_API-Linux-3.15.1
|
||||||
7z x ./SDRplay_RSP_API-Linux-3.15.2
|
cp x86_64/libsdrplay_api.so.3.15 /usr/lib/libsdrplay_api.so
|
||||||
cp $SDRPLAY_ARCH/libsdrplay_api.so.3.15 /usr/lib/libsdrplay_api.so
|
|
||||||
cp inc/* /usr/include/
|
cp inc/* /usr/include/
|
||||||
|
|
||||||
# Install a more recent libusb version
|
# Install a more recent libusb version
|
||||||
@@ -62,16 +61,6 @@ make -j2
|
|||||||
make install
|
make install
|
||||||
cd ../../
|
cd ../../
|
||||||
|
|
||||||
# Install libfobos
|
|
||||||
git clone https://github.com/AlexandreRouma/libfobos
|
|
||||||
cd libfobos
|
|
||||||
mkdir build
|
|
||||||
cd build
|
|
||||||
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr
|
|
||||||
make -j2
|
|
||||||
make install
|
|
||||||
cd ../../
|
|
||||||
|
|
||||||
# Fix missing .pc file for codec2
|
# Fix missing .pc file for codec2
|
||||||
echo 'prefix=/usr/' >> /usr/share/pkgconfig/codec2.pc
|
echo 'prefix=/usr/' >> /usr/share/pkgconfig/codec2.pc
|
||||||
echo 'libdir=/usr/include/x86_64-linux-gnu/' >> /usr/share/pkgconfig/codec2.pc
|
echo 'libdir=/usr/include/x86_64-linux-gnu/' >> /usr/share/pkgconfig/codec2.pc
|
||||||
@@ -83,33 +72,11 @@ echo 'Version: 0.7' >> /usr/share/pkgconfig/codec2.pc
|
|||||||
echo 'Libs: -L/usr/include/x86_64-linux-gnu/ -lcodec2' >> /usr/share/pkgconfig/codec2.pc
|
echo 'Libs: -L/usr/include/x86_64-linux-gnu/ -lcodec2' >> /usr/share/pkgconfig/codec2.pc
|
||||||
echo 'Cflags: -I/usr/include/codec2' >> /usr/share/pkgconfig/codec2.pc
|
echo 'Cflags: -I/usr/include/codec2' >> /usr/share/pkgconfig/codec2.pc
|
||||||
|
|
||||||
# Install libhydrasdr
|
|
||||||
git clone https://github.com/hydrasdr/rfone_host
|
|
||||||
cd rfone_host
|
|
||||||
mkdir build
|
|
||||||
cd build
|
|
||||||
cmake ..
|
|
||||||
make -j2
|
|
||||||
make install
|
|
||||||
cd ../../
|
|
||||||
|
|
||||||
# Install libdlcr
|
|
||||||
wget https://dragnlabs.com/host-tools/dlcr_host_v0.3.0.zip
|
|
||||||
mkdir dlcr_host
|
|
||||||
cd dlcr_host
|
|
||||||
7z x ../dlcr_host_v0.3.0.zip
|
|
||||||
mkdir build
|
|
||||||
cd build
|
|
||||||
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr
|
|
||||||
make -j2
|
|
||||||
make install
|
|
||||||
cd ../../
|
|
||||||
|
|
||||||
# Build SDR++ Itself
|
# Build SDR++ Itself
|
||||||
cd SDRPlusPlus
|
cd SDRPlusPlus
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
cmake .. -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_BLADERF_SOURCE=OFF -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_OVERRIDE_STD_FILESYSTEM=ON -DOPT_BUILD_M17_DECODER=ON -DOPT_BUILD_PERSEUS_SOURCE=ON -DOPT_BUILD_RFNM_SOURCE=ON -DOPT_BUILD_FOBOSSDR_SOURCE=ON -DOPT_BUILD_HYDRASDR_SOURCE=ON -DOPT_BUILD_DRAGONLABS_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 -DOPT_BUILD_PERSEUS_SOURCE=ON -DOPT_BUILD_RFNM_SOURCE=ON
|
||||||
make VERBOSE=1 -j2
|
make VERBOSE=1 -j2
|
||||||
|
|
||||||
# Generate package
|
# Generate package
|
||||||
|
|||||||
@@ -9,11 +9,10 @@ apt install -y build-essential cmake git libfftw3-dev libglfw3-dev libvolk2-dev
|
|||||||
libcodec2-dev autoconf libtool xxd libspdlog-dev
|
libcodec2-dev autoconf libtool xxd libspdlog-dev
|
||||||
|
|
||||||
# Install SDRPlay libraries
|
# Install SDRPlay libraries
|
||||||
SDRPLAY_ARCH=$(dpkg --print-architecture)
|
wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.15.1.run
|
||||||
wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.15.2.run
|
7z x ./SDRplay_RSP_API-Linux-3.15.1.run
|
||||||
7z x ./SDRplay_RSP_API-Linux-3.15.2.run
|
7z x ./SDRplay_RSP_API-Linux-3.15.1
|
||||||
7z x ./SDRplay_RSP_API-Linux-3.15.2
|
cp x86_64/libsdrplay_api.so.3.15 /usr/lib/libsdrplay_api.so
|
||||||
cp $SDRPLAY_ARCH/libsdrplay_api.so.3.15 /usr/lib/libsdrplay_api.so
|
|
||||||
cp inc/* /usr/include/
|
cp inc/* /usr/include/
|
||||||
|
|
||||||
# Install libperseus
|
# Install libperseus
|
||||||
@@ -36,42 +35,10 @@ make -j2
|
|||||||
make install
|
make install
|
||||||
cd ../../
|
cd ../../
|
||||||
|
|
||||||
# Install libfobos
|
|
||||||
git clone https://github.com/AlexandreRouma/libfobos
|
|
||||||
cd libfobos
|
|
||||||
mkdir build
|
|
||||||
cd build
|
|
||||||
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr
|
|
||||||
make -j2
|
|
||||||
make install
|
|
||||||
cd ../../
|
|
||||||
|
|
||||||
# Install libhydrasdr
|
|
||||||
git clone https://github.com/hydrasdr/rfone_host
|
|
||||||
cd rfone_host
|
|
||||||
mkdir build
|
|
||||||
cd build
|
|
||||||
cmake ..
|
|
||||||
make -j2
|
|
||||||
make install
|
|
||||||
cd ../../
|
|
||||||
|
|
||||||
# Install libdlcr
|
|
||||||
wget https://dragnlabs.com/host-tools/dlcr_host_v0.3.0.zip
|
|
||||||
mkdir dlcr_host
|
|
||||||
cd dlcr_host
|
|
||||||
7z x ../dlcr_host_v0.3.0.zip
|
|
||||||
mkdir build
|
|
||||||
cd build
|
|
||||||
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr
|
|
||||||
make -j2
|
|
||||||
make install
|
|
||||||
cd ../../
|
|
||||||
|
|
||||||
cd SDRPlusPlus
|
cd SDRPlusPlus
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
cmake .. -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON -DOPT_BUILD_PERSEUS_SOURCE=ON -DOPT_BUILD_RFNM_SOURCE=ON -DOPT_BUILD_FOBOSSDR_SOURCE=ON -DOPT_BUILD_HYDRASDR_SOURCE=ON -DOPT_BUILD_DRAGONLABS_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 -DOPT_BUILD_PERSEUS_SOURCE=ON -DOPT_BUILD_RFNM_SOURCE=ON
|
||||||
make VERBOSE=1 -j2
|
make VERBOSE=1 -j2
|
||||||
|
|
||||||
cd ..
|
cd ..
|
||||||
|
|||||||
@@ -9,11 +9,10 @@ apt install -y build-essential cmake git libfftw3-dev libglfw3-dev libvolk2-dev
|
|||||||
libcodec2-dev autoconf libtool xxd libspdlog-dev
|
libcodec2-dev autoconf libtool xxd libspdlog-dev
|
||||||
|
|
||||||
# Install SDRPlay libraries
|
# Install SDRPlay libraries
|
||||||
SDRPLAY_ARCH=$(dpkg --print-architecture)
|
wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.15.1.run
|
||||||
wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.15.2.run
|
7z x ./SDRplay_RSP_API-Linux-3.15.1.run
|
||||||
7z x ./SDRplay_RSP_API-Linux-3.15.2.run
|
7z x ./SDRplay_RSP_API-Linux-3.15.1
|
||||||
7z x ./SDRplay_RSP_API-Linux-3.15.2
|
cp x86_64/libsdrplay_api.so.3.15 /usr/lib/libsdrplay_api.so
|
||||||
cp $SDRPLAY_ARCH/libsdrplay_api.so.3.15 /usr/lib/libsdrplay_api.so
|
|
||||||
cp inc/* /usr/include/
|
cp inc/* /usr/include/
|
||||||
|
|
||||||
# Install libperseus
|
# Install libperseus
|
||||||
@@ -36,42 +35,10 @@ make -j2
|
|||||||
make install
|
make install
|
||||||
cd ../../
|
cd ../../
|
||||||
|
|
||||||
# Install libfobos
|
|
||||||
git clone https://github.com/AlexandreRouma/libfobos
|
|
||||||
cd libfobos
|
|
||||||
mkdir build
|
|
||||||
cd build
|
|
||||||
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr
|
|
||||||
make -j2
|
|
||||||
make install
|
|
||||||
cd ../../
|
|
||||||
|
|
||||||
# Install libhydrasdr
|
|
||||||
git clone https://github.com/hydrasdr/rfone_host
|
|
||||||
cd rfone_host
|
|
||||||
mkdir build
|
|
||||||
cd build
|
|
||||||
cmake ..
|
|
||||||
make -j2
|
|
||||||
make install
|
|
||||||
cd ../../
|
|
||||||
|
|
||||||
# Install libdlcr
|
|
||||||
wget https://dragnlabs.com/host-tools/dlcr_host_v0.3.0.zip
|
|
||||||
mkdir dlcr_host
|
|
||||||
cd dlcr_host
|
|
||||||
7z x ../dlcr_host_v0.3.0.zip
|
|
||||||
mkdir build
|
|
||||||
cd build
|
|
||||||
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr
|
|
||||||
make -j2
|
|
||||||
make install
|
|
||||||
cd ../../
|
|
||||||
|
|
||||||
cd SDRPlusPlus
|
cd SDRPlusPlus
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
cmake .. -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON -DOPT_BUILD_PERSEUS_SOURCE=ON -DOPT_BUILD_RFNM_SOURCE=ON -DOPT_BUILD_FOBOSSDR_SOURCE=ON -DOPT_BUILD_HYDRASDR_SOURCE=ON -DOPT_BUILD_DRAGONLABS_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 -DOPT_BUILD_PERSEUS_SOURCE=ON -DOPT_BUILD_RFNM_SOURCE=ON
|
||||||
make VERBOSE=1 -j2
|
make VERBOSE=1 -j2
|
||||||
|
|
||||||
cd ..
|
cd ..
|
||||||
|
|||||||
4
docker_builds/ubuntu_mantic/Dockerfile
Normal file
4
docker_builds/ubuntu_mantic/Dockerfile
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
FROM ubuntu:mantic
|
||||||
|
ENV DEBIAN_FRONTEND=noninteractive
|
||||||
|
COPY do_build.sh /root
|
||||||
|
RUN chmod +x /root/do_build.sh
|
||||||
@@ -9,11 +9,10 @@ apt install -y build-essential cmake git libfftw3-dev libglfw3-dev libvolk-dev l
|
|||||||
libcodec2-dev autoconf libtool xxd libspdlog-dev
|
libcodec2-dev autoconf libtool xxd libspdlog-dev
|
||||||
|
|
||||||
# Install SDRPlay libraries
|
# Install SDRPlay libraries
|
||||||
SDRPLAY_ARCH=$(dpkg --print-architecture)
|
wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.15.1.run
|
||||||
wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.15.2.run
|
7z x ./SDRplay_RSP_API-Linux-3.15.1.run
|
||||||
7z x ./SDRplay_RSP_API-Linux-3.15.2.run
|
7z x ./SDRplay_RSP_API-Linux-3.15.1
|
||||||
7z x ./SDRplay_RSP_API-Linux-3.15.2
|
cp x86_64/libsdrplay_api.so.3.15 /usr/lib/libsdrplay_api.so
|
||||||
cp $SDRPLAY_ARCH/libsdrplay_api.so.3.15 /usr/lib/libsdrplay_api.so
|
|
||||||
cp inc/* /usr/include/
|
cp inc/* /usr/include/
|
||||||
|
|
||||||
# Install libperseus
|
# Install libperseus
|
||||||
@@ -36,42 +35,10 @@ make -j2
|
|||||||
make install
|
make install
|
||||||
cd ../../
|
cd ../../
|
||||||
|
|
||||||
# Install libfobos
|
|
||||||
git clone https://github.com/AlexandreRouma/libfobos
|
|
||||||
cd libfobos
|
|
||||||
mkdir build
|
|
||||||
cd build
|
|
||||||
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr
|
|
||||||
make -j2
|
|
||||||
make install
|
|
||||||
cd ../../
|
|
||||||
|
|
||||||
# Install libhydrasdr
|
|
||||||
git clone https://github.com/hydrasdr/rfone_host
|
|
||||||
cd rfone_host
|
|
||||||
mkdir build
|
|
||||||
cd build
|
|
||||||
cmake ..
|
|
||||||
make -j2
|
|
||||||
make install
|
|
||||||
cd ../../
|
|
||||||
|
|
||||||
# Install libdlcr
|
|
||||||
wget https://dragnlabs.com/host-tools/dlcr_host_v0.3.0.zip
|
|
||||||
mkdir dlcr_host
|
|
||||||
cd dlcr_host
|
|
||||||
7z x ../dlcr_host_v0.3.0.zip
|
|
||||||
mkdir build
|
|
||||||
cd build
|
|
||||||
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr
|
|
||||||
make -j2
|
|
||||||
make install
|
|
||||||
cd ../../
|
|
||||||
|
|
||||||
cd SDRPlusPlus
|
cd SDRPlusPlus
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
cmake .. -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON -DOPT_BUILD_PERSEUS_SOURCE=ON -DOPT_BUILD_RFNM_SOURCE=ON -DOPT_BUILD_FOBOSSDR_SOURCE=ON -DOPT_BUILD_HYDRASDR_SOURCE=ON -DOPT_BUILD_DRAGONLABS_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 -DOPT_BUILD_PERSEUS_SOURCE=ON -DOPT_BUILD_RFNM_SOURCE=ON
|
||||||
make VERBOSE=1 -j2
|
make VERBOSE=1 -j2
|
||||||
|
|
||||||
cd ..
|
cd ..
|
||||||
@@ -9,11 +9,10 @@ apt install -y build-essential cmake git libfftw3-dev libglfw3-dev libvolk-dev l
|
|||||||
libcodec2-dev autoconf libtool xxd libspdlog-dev
|
libcodec2-dev autoconf libtool xxd libspdlog-dev
|
||||||
|
|
||||||
# Install SDRPlay libraries
|
# Install SDRPlay libraries
|
||||||
SDRPLAY_ARCH=$(dpkg --print-architecture)
|
wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.15.1.run
|
||||||
wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.15.2.run
|
7z x ./SDRplay_RSP_API-Linux-3.15.1.run
|
||||||
7z x ./SDRplay_RSP_API-Linux-3.15.2.run
|
7z x ./SDRplay_RSP_API-Linux-3.15.1
|
||||||
7z x ./SDRplay_RSP_API-Linux-3.15.2
|
cp x86_64/libsdrplay_api.so.3.15 /usr/lib/libsdrplay_api.so
|
||||||
cp $SDRPLAY_ARCH/libsdrplay_api.so.3.15 /usr/lib/libsdrplay_api.so
|
|
||||||
cp inc/* /usr/include/
|
cp inc/* /usr/include/
|
||||||
|
|
||||||
# Install libperseus
|
# Install libperseus
|
||||||
@@ -36,42 +35,10 @@ make -j2
|
|||||||
make install
|
make install
|
||||||
cd ../../
|
cd ../../
|
||||||
|
|
||||||
# Install libfobos
|
|
||||||
git clone https://github.com/AlexandreRouma/libfobos
|
|
||||||
cd libfobos
|
|
||||||
mkdir build
|
|
||||||
cd build
|
|
||||||
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr
|
|
||||||
make -j2
|
|
||||||
make install
|
|
||||||
cd ../../
|
|
||||||
|
|
||||||
# Install libhydrasdr
|
|
||||||
git clone https://github.com/hydrasdr/rfone_host
|
|
||||||
cd rfone_host
|
|
||||||
mkdir build
|
|
||||||
cd build
|
|
||||||
cmake ..
|
|
||||||
make -j2
|
|
||||||
make install
|
|
||||||
cd ../../
|
|
||||||
|
|
||||||
# Install libdlcr
|
|
||||||
wget https://dragnlabs.com/host-tools/dlcr_host_v0.3.0.zip
|
|
||||||
mkdir dlcr_host
|
|
||||||
cd dlcr_host
|
|
||||||
7z x ../dlcr_host_v0.3.0.zip
|
|
||||||
mkdir build
|
|
||||||
cd build
|
|
||||||
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr
|
|
||||||
make -j2
|
|
||||||
make install
|
|
||||||
cd ../../
|
|
||||||
|
|
||||||
cd SDRPlusPlus
|
cd SDRPlusPlus
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
cmake .. -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON -DOPT_BUILD_PERSEUS_SOURCE=ON -DOPT_BUILD_RFNM_SOURCE=ON -DOPT_BUILD_FOBOSSDR_SOURCE=ON -DOPT_BUILD_HYDRASDR_SOURCE=ON -DOPT_BUILD_DRAGONLABS_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 -DOPT_BUILD_PERSEUS_SOURCE=ON -DOPT_BUILD_RFNM_SOURCE=ON
|
||||||
make VERBOSE=1 -j2
|
make VERBOSE=1 -j2
|
||||||
|
|
||||||
cd ..
|
cd ..
|
||||||
|
|||||||
@@ -1,78 +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 libvolk-dev libzstd-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 libspdlog-dev
|
|
||||||
|
|
||||||
# Install SDRPlay libraries
|
|
||||||
SDRPLAY_ARCH=$(dpkg --print-architecture)
|
|
||||||
wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.15.2.run
|
|
||||||
7z x ./SDRplay_RSP_API-Linux-3.15.2.run
|
|
||||||
7z x ./SDRplay_RSP_API-Linux-3.15.2
|
|
||||||
cp $SDRPLAY_ARCH/libsdrplay_api.so.3.15 /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 ..
|
|
||||||
|
|
||||||
# Install librfnm
|
|
||||||
git clone https://github.com/AlexandreRouma/librfnm
|
|
||||||
cd librfnm
|
|
||||||
mkdir build
|
|
||||||
cd build
|
|
||||||
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr
|
|
||||||
make -j2
|
|
||||||
make install
|
|
||||||
cd ../../
|
|
||||||
|
|
||||||
# Install libfobos
|
|
||||||
git clone https://github.com/AlexandreRouma/libfobos
|
|
||||||
cd libfobos
|
|
||||||
mkdir build
|
|
||||||
cd build
|
|
||||||
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr
|
|
||||||
make -j2
|
|
||||||
make install
|
|
||||||
cd ../../
|
|
||||||
|
|
||||||
# Install libhydrasdr
|
|
||||||
git clone https://github.com/hydrasdr/rfone_host
|
|
||||||
cd rfone_host
|
|
||||||
mkdir build
|
|
||||||
cd build
|
|
||||||
cmake ..
|
|
||||||
make -j2
|
|
||||||
make install
|
|
||||||
cd ../../
|
|
||||||
|
|
||||||
# Install libdlcr
|
|
||||||
wget https://dragnlabs.com/host-tools/dlcr_host_v0.3.0.zip
|
|
||||||
mkdir dlcr_host
|
|
||||||
cd dlcr_host
|
|
||||||
7z x ../dlcr_host_v0.3.0.zip
|
|
||||||
mkdir build
|
|
||||||
cd build
|
|
||||||
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr
|
|
||||||
make -j2
|
|
||||||
make install
|
|
||||||
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 -DOPT_BUILD_RFNM_SOURCE=ON -DOPT_BUILD_FOBOSSDR_SOURCE=ON -DOPT_BUILD_HYDRASDR_SOURCE=ON -DOPT_BUILD_DRAGONLABS_SOURCE=ON
|
|
||||||
make VERBOSE=1 -j2
|
|
||||||
|
|
||||||
cd ..
|
|
||||||
sh make_debian_package.sh ./build 'libfftw3-dev, libglfw3-dev, libvolk-dev, librtaudio-dev, libzstd-dev'
|
|
||||||
@@ -28,8 +28,6 @@ bundle_is_not_to_be_installed() {
|
|||||||
if [ "$1" = "Security" ]; then echo 1; fi
|
if [ "$1" = "Security" ]; then echo 1; fi
|
||||||
if [ "$1" = "AppleFSCompression" ]; then echo 1; fi
|
if [ "$1" = "AppleFSCompression" ]; then echo 1; fi
|
||||||
if [ "$1" = "libsdrplay_api.so.3.14" ]; then echo 1; fi
|
if [ "$1" = "libsdrplay_api.so.3.14" ]; then echo 1; fi
|
||||||
if [ "$1" = "libsdrplay_api.so.3.15" ]; then echo 1; fi
|
|
||||||
if [ "$1" = "libxml2.2.dylib" ]; then echo 1; fi
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# ========================= FOR INTERNAL USE ONLY =========================
|
# ========================= FOR INTERNAL USE ONLY =========================
|
||||||
@@ -228,4 +226,4 @@ bundle_sign() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
codesign --force --deep -s - $1
|
codesign --force --deep -s - $1
|
||||||
}
|
}
|
||||||
@@ -8,7 +8,7 @@ mkdir sdrpp_debian_amd64/DEBIAN
|
|||||||
# Create package info
|
# Create package info
|
||||||
echo Create package info
|
echo Create package info
|
||||||
echo Package: sdrpp >> sdrpp_debian_amd64/DEBIAN/control
|
echo Package: sdrpp >> sdrpp_debian_amd64/DEBIAN/control
|
||||||
echo Version: 1.2.1$BUILD_NO >> sdrpp_debian_amd64/DEBIAN/control
|
echo Version: 1.2.0$BUILD_NO >> sdrpp_debian_amd64/DEBIAN/control
|
||||||
echo Maintainer: Ryzerth >> sdrpp_debian_amd64/DEBIAN/control
|
echo Maintainer: Ryzerth >> sdrpp_debian_amd64/DEBIAN/control
|
||||||
echo Architecture: all >> sdrpp_debian_amd64/DEBIAN/control
|
echo Architecture: all >> sdrpp_debian_amd64/DEBIAN/control
|
||||||
echo Description: Bloat-free SDR receiver software >> sdrpp_debian_amd64/DEBIAN/control
|
echo Description: Bloat-free SDR receiver software >> sdrpp_debian_amd64/DEBIAN/control
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ cp -R root/res/* $BUNDLE/Contents/Resources/
|
|||||||
bundle_create_icns root/res/icons/sdrpp.macos.png $BUNDLE/Contents/Resources/sdrpp
|
bundle_create_icns root/res/icons/sdrpp.macos.png $BUNDLE/Contents/Resources/sdrpp
|
||||||
|
|
||||||
# Create the property list
|
# Create the property list
|
||||||
bundle_create_plist sdrpp SDR++ org.sdrpp.sdrpp 1.2.1 sdrp sdrpp sdrpp $BUNDLE/Contents/Info.plist
|
bundle_create_plist sdrpp SDR++ org.sdrpp.sdrpp 1.2.0 sdrp sdrpp sdrpp $BUNDLE/Contents/Info.plist
|
||||||
|
|
||||||
# ========================= Install binaries =========================
|
# ========================= Install binaries =========================
|
||||||
|
|
||||||
@@ -35,12 +35,9 @@ bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/source_modules
|
|||||||
bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/source_modules/airspyhf_source/airspyhf_source.dylib
|
bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/source_modules/airspyhf_source/airspyhf_source.dylib
|
||||||
bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/source_modules/bladerf_source/bladerf_source.dylib
|
bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/source_modules/bladerf_source/bladerf_source.dylib
|
||||||
bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/source_modules/file_source/file_source.dylib
|
bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/source_modules/file_source/file_source.dylib
|
||||||
bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/source_modules/fobossdr_source/fobossdr_source.dylib
|
|
||||||
bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/source_modules/hackrf_source/hackrf_source.dylib
|
bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/source_modules/hackrf_source/hackrf_source.dylib
|
||||||
bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/source_modules/hermes_source/hermes_source.dylib
|
bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/source_modules/hermes_source/hermes_source.dylib
|
||||||
bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/source_modules/hydrasdr_source/hydrasdr_source.dylib
|
|
||||||
bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/source_modules/limesdr_source/limesdr_source.dylib
|
bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/source_modules/limesdr_source/limesdr_source.dylib
|
||||||
bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/source_modules/network_source/network_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/perseus_source/perseus_source.dylib
|
||||||
bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/source_modules/plutosdr_source/plutosdr_source.dylib
|
bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/source_modules/plutosdr_source/plutosdr_source.dylib
|
||||||
bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/source_modules/rfnm_source/rfnm_source.dylib
|
bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/source_modules/rfnm_source/rfnm_source.dylib
|
||||||
@@ -58,7 +55,6 @@ bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/sink_modules/n
|
|||||||
bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/sink_modules/new_portaudio_sink/new_portaudio_sink.dylib
|
bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/sink_modules/new_portaudio_sink/new_portaudio_sink.dylib
|
||||||
|
|
||||||
# Decoder modules
|
# Decoder modules
|
||||||
bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/decoder_modules/atv_decoder/atv_decoder.dylib
|
|
||||||
bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/decoder_modules/m17_decoder/m17_decoder.dylib
|
bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/decoder_modules/m17_decoder/m17_decoder.dylib
|
||||||
bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/decoder_modules/meteor_demodulator/meteor_demodulator.dylib
|
bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/decoder_modules/meteor_demodulator/meteor_demodulator.dylib
|
||||||
bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/decoder_modules/radio/radio.dylib
|
bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/decoder_modules/radio/radio.dylib
|
||||||
|
|||||||
@@ -24,22 +24,14 @@ cp 'C:/Program Files/PothosSDR/bin/bladeRF.dll' sdrpp_windows_x64/
|
|||||||
|
|
||||||
cp $build_dir/source_modules/file_source/Release/file_source.dll sdrpp_windows_x64/modules/
|
cp $build_dir/source_modules/file_source/Release/file_source.dll sdrpp_windows_x64/modules/
|
||||||
|
|
||||||
cp $build_dir/source_modules/fobossdr_source/Release/fobossdr_source.dll sdrpp_windows_x64/modules/
|
|
||||||
cp 'C:/Program Files/RigExpert/Fobos/bin/fobos.dll' sdrpp_windows_x64/
|
|
||||||
|
|
||||||
cp $build_dir/source_modules/hackrf_source/Release/hackrf_source.dll sdrpp_windows_x64/modules/
|
cp $build_dir/source_modules/hackrf_source/Release/hackrf_source.dll sdrpp_windows_x64/modules/
|
||||||
cp 'C:/Program Files/PothosSDR/bin/hackrf.dll' sdrpp_windows_x64/
|
cp 'C:/Program Files/PothosSDR/bin/hackrf.dll' sdrpp_windows_x64/
|
||||||
|
|
||||||
cp $build_dir/source_modules/hermes_source/Release/hermes_source.dll sdrpp_windows_x64/modules/
|
cp $build_dir/source_modules/hermes_source/Release/hermes_source.dll sdrpp_windows_x64/modules/
|
||||||
|
|
||||||
cp $build_dir/source_modules/hydrasdr_source/Release/hydrasdr_source.dll sdrpp_windows_x64/modules/
|
|
||||||
cp 'C:/Program Files/hydrasdr-host/bin/hydrasdr.dll' sdrpp_windows_x64/
|
|
||||||
|
|
||||||
cp $build_dir/source_modules/limesdr_source/Release/limesdr_source.dll sdrpp_windows_x64/modules/
|
cp $build_dir/source_modules/limesdr_source/Release/limesdr_source.dll sdrpp_windows_x64/modules/
|
||||||
cp 'C:/Program Files/PothosSDR/bin/LimeSuite.dll' sdrpp_windows_x64/
|
cp 'C:/Program Files/PothosSDR/bin/LimeSuite.dll' sdrpp_windows_x64/
|
||||||
|
|
||||||
cp $build_dir/source_modules/network_source/Release/network_source.dll sdrpp_windows_x64/modules/
|
|
||||||
|
|
||||||
cp $build_dir/source_modules/perseus_source/Release/perseus_source.dll sdrpp_windows_x64/modules/
|
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 'C:/Program Files/PothosSDR/bin/perseus-sdr.dll' sdrpp_windows_x64/
|
||||||
|
|
||||||
@@ -77,8 +69,6 @@ cp $build_dir/sink_modules/network_sink/Release/network_sink.dll sdrpp_windows_x
|
|||||||
|
|
||||||
|
|
||||||
# Copy decoder modules
|
# Copy decoder modules
|
||||||
cp $build_dir/decoder_modules/atv_decoder/Release/atv_decoder.dll sdrpp_windows_x64/modules/
|
|
||||||
|
|
||||||
cp $build_dir/decoder_modules/m17_decoder/Release/m17_decoder.dll sdrpp_windows_x64/modules/
|
cp $build_dir/decoder_modules/m17_decoder/Release/m17_decoder.dll sdrpp_windows_x64/modules/
|
||||||
cp "C:/Program Files/codec2/lib/libcodec2.dll" sdrpp_windows_x64/
|
cp "C:/Program Files/codec2/lib/libcodec2.dll" sdrpp_windows_x64/
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
cmake_minimum_required (VERSION 3.13.0)
|
cmake_minimum_required (VERSION 3.2.0)
|
||||||
project (DiscordRPC)
|
project (DiscordRPC)
|
||||||
|
|
||||||
include(GNUInstallDirs)
|
include(GNUInstallDirs)
|
||||||
|
|||||||
@@ -168,9 +168,10 @@ public:
|
|||||||
writer.setSamplerate(samplerate);
|
writer.setSamplerate(samplerate);
|
||||||
|
|
||||||
// Open file
|
// 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) ? selectedStreamName : "";
|
||||||
std::string extension = ".wav";
|
std::string extension = ".wav";
|
||||||
std::string expandedPath = expandString(folderSelect.path + "/" + genFileName(nameTemplate, recMode, vfoName) + extension);
|
std::string expandedPath = expandString(folderSelect.path + "/" + genFileName(nameTemplate, type, vfoName) + extension);
|
||||||
if (!writer.open(expandedPath)) {
|
if (!writer.open(expandedPath)) {
|
||||||
flog::error("Failed to open file for recording: {0}", expandedPath);
|
flog::error("Failed to open file for recording: {0}", expandedPath);
|
||||||
return;
|
return;
|
||||||
@@ -451,7 +452,7 @@ private:
|
|||||||
{ RADIO_IFACE_MODE_RAW, "RAW" }
|
{ RADIO_IFACE_MODE_RAW, "RAW" }
|
||||||
};
|
};
|
||||||
|
|
||||||
std::string genFileName(std::string templ, int mode, std::string name) {
|
std::string genFileName(std::string templ, std::string type, std::string name) {
|
||||||
// Get data
|
// Get data
|
||||||
time_t now = time(0);
|
time_t now = time(0);
|
||||||
tm* ltm = localtime(&now);
|
tm* ltm = localtime(&now);
|
||||||
@@ -461,9 +462,6 @@ private:
|
|||||||
freq += gui::waterfall.vfos[name]->generalOffset;
|
freq += gui::waterfall.vfos[name]->generalOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Select the recording type string
|
|
||||||
std::string type = (recMode == RECORDER_MODE_AUDIO) ? "audio" : "baseband";
|
|
||||||
|
|
||||||
// Format to string
|
// Format to string
|
||||||
char freqStr[128];
|
char freqStr[128];
|
||||||
char hourStr[128];
|
char hourStr[128];
|
||||||
@@ -472,7 +470,7 @@ private:
|
|||||||
char dayStr[128];
|
char dayStr[128];
|
||||||
char monStr[128];
|
char monStr[128];
|
||||||
char yearStr[128];
|
char yearStr[128];
|
||||||
const char* modeStr = (recMode == RECORDER_MODE_AUDIO) ? "Unknown" : "IQ";
|
const char* modeStr = "Unknown";
|
||||||
sprintf(freqStr, "%.0lfHz", freq);
|
sprintf(freqStr, "%.0lfHz", freq);
|
||||||
sprintf(hourStr, "%02d", ltm->tm_hour);
|
sprintf(hourStr, "%02d", ltm->tm_hour);
|
||||||
sprintf(minStr, "%02d", ltm->tm_min);
|
sprintf(minStr, "%02d", ltm->tm_min);
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
#include <gui/gui.h>
|
#include <gui/gui.h>
|
||||||
#include <gui/style.h>
|
#include <gui/style.h>
|
||||||
#include <signal_path/signal_path.h>
|
#include <signal_path/signal_path.h>
|
||||||
#include <chrono>
|
|
||||||
|
|
||||||
SDRPP_MOD_INFO{
|
SDRPP_MOD_INFO{
|
||||||
/* Name: */ "scanner",
|
/* Name: */ "scanner",
|
||||||
|
|||||||
25
readme.md
25
readme.md
@@ -324,13 +324,11 @@ Modules in beta are still included in releases for the most part but not enabled
|
|||||||
| audio_source | Working | rtaudio | OPT_BUILD_AUDIO_SOURCE | ✅ | ✅ | ✅ |
|
| audio_source | Working | rtaudio | OPT_BUILD_AUDIO_SOURCE | ✅ | ✅ | ✅ |
|
||||||
| bladerf_source | Working | libbladeRF | OPT_BUILD_BLADERF_SOURCE | ⛔ | ✅ (not Debian Buster) | ✅ |
|
| bladerf_source | Working | libbladeRF | OPT_BUILD_BLADERF_SOURCE | ⛔ | ✅ (not Debian Buster) | ✅ |
|
||||||
| file_source | Working | - | OPT_BUILD_FILE_SOURCE | ✅ | ✅ | ✅ |
|
| file_source | Working | - | OPT_BUILD_FILE_SOURCE | ✅ | ✅ | ✅ |
|
||||||
| fobossdr_source | Working | libfobos | OPT_BUILD_FOBOSSDR_SOURCE | ✅ | ✅ | ✅ |
|
|
||||||
| hackrf_source | Working | libhackrf | OPT_BUILD_HACKRF_SOURCE | ✅ | ✅ | ✅ |
|
| hackrf_source | Working | libhackrf | OPT_BUILD_HACKRF_SOURCE | ✅ | ✅ | ✅ |
|
||||||
| harogic_source | Beta | htra_api | OPT_BUILD_HAROGIC_SOURCE | ⛔ | ⛔ | ✅ |
|
| harogic_source | Unfinished | htra_api | OPT_BUILD_HAROGIC_SOURCE | ⛔ | ⛔ | ⛔ |
|
||||||
| hermes_source | Beta | - | OPT_BUILD_HERMES_SOURCE | ✅ | ✅ | ✅ |
|
| hermes_source | Beta | - | OPT_BUILD_HERMES_SOURCE | ✅ | ✅ | ✅ |
|
||||||
| kcsdr_source | Unfinished | libkcsdr | OPT_BUILD_KCSDR_SOURCE | ⛔ | ⛔ | ⛔ |
|
|
||||||
| limesdr_source | Working | liblimesuite | OPT_BUILD_LIMESDR_SOURCE | ⛔ | ✅ | ✅ |
|
| limesdr_source | Working | liblimesuite | OPT_BUILD_LIMESDR_SOURCE | ⛔ | ✅ | ✅ |
|
||||||
| network_source | Beta | - | OPT_BUILD_NETWORK_SOURCE | ✅ | ✅ | ✅ |
|
| network_source | Unfinished | - | OPT_BUILD_NETWORK_SOURCE | ✅ | ✅ | ⛔ |
|
||||||
| perseus_source | Beta | libperseus-sdr | OPT_BUILD_PERSEUS_SOURCE | ⛔ | ✅ | ✅ |
|
| perseus_source | Beta | libperseus-sdr | OPT_BUILD_PERSEUS_SOURCE | ⛔ | ✅ | ✅ |
|
||||||
| plutosdr_source | Working | libiio, libad9361 | OPT_BUILD_PLUTOSDR_SOURCE | ✅ | ✅ | ✅ |
|
| plutosdr_source | Working | libiio, libad9361 | OPT_BUILD_PLUTOSDR_SOURCE | ✅ | ✅ | ✅ |
|
||||||
| rfnm_source | Beta | librfnm | OPT_BUILD_RFNM_SOURCE | ⛔ | ✅ | ✅ |
|
| rfnm_source | Beta | librfnm | OPT_BUILD_RFNM_SOURCE | ⛔ | ✅ | ✅ |
|
||||||
@@ -341,9 +339,9 @@ Modules in beta are still included in releases for the most part but not enabled
|
|||||||
| sdrpp_server_source | Working | - | OPT_BUILD_SDRPP_SERVER_SOURCE | ✅ | ✅ | ✅ |
|
| sdrpp_server_source | Working | - | OPT_BUILD_SDRPP_SERVER_SOURCE | ✅ | ✅ | ✅ |
|
||||||
| soapy_source | Deprecated | soapysdr | OPT_BUILD_SOAPY_SOURCE | ⛔ | ⛔ | ⛔ |
|
| soapy_source | Deprecated | soapysdr | OPT_BUILD_SOAPY_SOURCE | ⛔ | ⛔ | ⛔ |
|
||||||
| spectran_source | Unfinished | RTSA Suite | OPT_BUILD_SPECTRAN_SOURCE | ⛔ | ⛔ | ⛔ |
|
| spectran_source | Unfinished | RTSA Suite | OPT_BUILD_SPECTRAN_SOURCE | ⛔ | ⛔ | ⛔ |
|
||||||
| spectran_http_source | Beta | - | OPT_BUILD_SPECTRAN_HTTP_SOURCE | ✅ | ✅ | ✅ |
|
| spectran_http_source | Beta | - | OPT_BUILD_SPECTRAN_HTTP_SOURCE | ✅ | ✅ | ⛔ |
|
||||||
| spyserver_source | Working | - | OPT_BUILD_SPYSERVER_SOURCE | ✅ | ✅ | ✅ |
|
| spyserver_source | Working | - | OPT_BUILD_SPYSERVER_SOURCE | ✅ | ✅ | ✅ |
|
||||||
| usrp_source | Beta | libuhd | OPT_BUILD_USRP_SOURCE | ⛔ | ⛔ | ✅ |
|
| usrp_source | Beta | libuhd | OPT_BUILD_USRP_SOURCE | ⛔ | ⛔ | ⛔ |
|
||||||
|
|
||||||
## Sinks
|
## Sinks
|
||||||
|
|
||||||
@@ -352,22 +350,20 @@ Modules in beta are still included in releases for the most part but not enabled
|
|||||||
| android_audio_sink | Working | - | OPT_BUILD_ANDROID_AUDIO_SINK | ⛔ | ✅ | ✅ (Android only) |
|
| android_audio_sink | Working | - | OPT_BUILD_ANDROID_AUDIO_SINK | ⛔ | ✅ | ✅ (Android only) |
|
||||||
| audio_sink | Working | rtaudio | OPT_BUILD_AUDIO_SINK | ✅ | ✅ | ✅ |
|
| audio_sink | Working | rtaudio | OPT_BUILD_AUDIO_SINK | ✅ | ✅ | ✅ |
|
||||||
| network_sink | Working | - | OPT_BUILD_NETWORK_SINK | ✅ | ✅ | ✅ |
|
| network_sink | Working | - | OPT_BUILD_NETWORK_SINK | ✅ | ✅ | ✅ |
|
||||||
| new_portaudio_sink | Working | portaudio | OPT_BUILD_NEW_PORTAUDIO_SINK | ⛔ | ✅ | ⛔ |
|
| new_portaudio_sink | Beta | portaudio | OPT_BUILD_NEW_PORTAUDIO_SINK | ⛔ | ✅ | ⛔ |
|
||||||
| portaudio_sink | Working | portaudio | OPT_BUILD_PORTAUDIO_SINK | ⛔ | ✅ | ⛔ |
|
| portaudio_sink | Beta | portaudio | OPT_BUILD_PORTAUDIO_SINK | ⛔ | ✅ | ⛔ |
|
||||||
|
|
||||||
## Decoders
|
## Decoders
|
||||||
|
|
||||||
| Name | Stage | Dependencies | Option | Built by default| Built in Release | Enabled in SDR++ by default |
|
| Name | Stage | Dependencies | Option | Built by default| Built in Release | Enabled in SDR++ by default |
|
||||||
|---------------------|------------|--------------|-------------------------------|:---------------:|:----------------:|:---------------------------:|
|
|---------------------|------------|--------------|-------------------------------|:---------------:|:----------------:|:---------------------------:|
|
||||||
| atv_decoder | Unfinished | - | OPT_BUILD_ATV_DECODER | ⛔ | ⛔ | ⛔ |
|
| atv_decoder | Unfinished | - | OPT_BUILD_ATV_DECODER | ⛔ | ⛔ | ⛔ |
|
||||||
| dab_decoder | Unfinished | - | OPT_BUILD_DAB_DECODER | ⛔ | ⛔ | ⛔ |
|
|
||||||
| falcon9_decoder | Unfinished | ffplay | OPT_BUILD_FALCON9_DECODER | ⛔ | ⛔ | ⛔ |
|
| falcon9_decoder | Unfinished | ffplay | OPT_BUILD_FALCON9_DECODER | ⛔ | ⛔ | ⛔ |
|
||||||
| kgsstv_decoder | Unfinished | - | OPT_BUILD_KGSSTV_DECODER | ⛔ | ⛔ | ⛔ |
|
| kgsstv_decoder | Unfinished | - | OPT_BUILD_KGSSTV_DECODER | ⛔ | ⛔ | ⛔ |
|
||||||
| m17_decoder | Working | - | OPT_BUILD_M17_DECODER | ⛔ | ✅ | ⛔ |
|
| m17_decoder | Working | - | OPT_BUILD_M17_DECODER | ⛔ | ✅ | ⛔ |
|
||||||
| meteor_demodulator | Working | - | OPT_BUILD_METEOR_DEMODULATOR | ✅ | ✅ | ⛔ |
|
| meteor_demodulator | Working | - | OPT_BUILD_METEOR_DEMODULATOR | ✅ | ✅ | ⛔ |
|
||||||
| pager_decoder | Unfinished | - | OPT_BUILD_PAGER_DECODER | ⛔ | ⛔ | ⛔ |
|
| pager_decoder | Unfinished | - | OPT_BUILD_PAGER_DECODER | ⛔ | ⛔ | ⛔ |
|
||||||
| radio | Working | - | OPT_BUILD_RADIO | ✅ | ✅ | ✅ |
|
| radio | Working | - | OPT_BUILD_RADIO | ✅ | ✅ | ✅ |
|
||||||
| radio | Unfinished | - | OPT_BUILD_VOR_RECEIVER | ⛔ | ⛔ | ⛔ |
|
|
||||||
| weather_sat_decoder | Unfinished | - | OPT_BUILD_WEATHER_SAT_DECODER | ⛔ | ⛔ | ⛔ |
|
| weather_sat_decoder | Unfinished | - | OPT_BUILD_WEATHER_SAT_DECODER | ⛔ | ⛔ | ⛔ |
|
||||||
|
|
||||||
## Misc
|
## Misc
|
||||||
@@ -420,8 +416,8 @@ If you still have an issue, please open an issue about it or ask on the discord.
|
|||||||
|
|
||||||
# Contributing
|
# Contributing
|
||||||
|
|
||||||
Feel free to submit band plans via the GitHub issue tracker.
|
Feel free to submit pull requests and report bugs via the GitHub issue tracker.
|
||||||
For code changes, please create a feature request instead.
|
I will soon publish a contributing.md listing the code style to use.
|
||||||
|
|
||||||
# Credits
|
# Credits
|
||||||
|
|
||||||
@@ -441,18 +437,15 @@ For code changes, please create a feature request instead.
|
|||||||
* Flinger Films
|
* Flinger Films
|
||||||
* [Frank Werner (HB9FXQ)](https://twitter.com/HB9FXQ)
|
* [Frank Werner (HB9FXQ)](https://twitter.com/HB9FXQ)
|
||||||
* gringogrigio
|
* gringogrigio
|
||||||
* Jandro
|
|
||||||
* Jeff Moe
|
* Jeff Moe
|
||||||
* Joe Cupano
|
* Joe Cupano
|
||||||
* KD1SQ
|
* KD1SQ
|
||||||
* Kezza
|
* Kezza
|
||||||
* Krys Kamieniecki
|
* Krys Kamieniecki
|
||||||
* Lee Donaghy
|
* Lee Donaghy
|
||||||
* Lee (KD1SQ)
|
* Lee KD1SQ
|
||||||
* .lozenge. (Hank Hill)
|
* .lozenge. (Hank Hill)
|
||||||
* Martin Herren (HB9FXX)
|
* Martin Herren (HB9FXX)
|
||||||
* NeoVilsonWong
|
|
||||||
* Nitin (VU2JEK)
|
|
||||||
* ON4MU
|
* ON4MU
|
||||||
* [Passion-Radio.com](https://passion-radio.com/)
|
* [Passion-Radio.com](https://passion-radio.com/)
|
||||||
* Paul Maine
|
* Paul Maine
|
||||||
|
|||||||
@@ -1,231 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "Ireland",
|
|
||||||
"country_name": "Republic Of Ireland",
|
|
||||||
"country_code": "IE",
|
|
||||||
"author_name": "Oskar Dudek",
|
|
||||||
"author_url": "",
|
|
||||||
"bands": [
|
|
||||||
{
|
|
||||||
"name": "2200m Ham Band",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 135700,
|
|
||||||
"end": 137800
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Long wave",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 148500,
|
|
||||||
"end": 282500
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "AM broadcast",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 531000,
|
|
||||||
"end": 1602000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "160m ham band",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 1810000,
|
|
||||||
"end": 2000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "120m SW broadcast",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 2300000,
|
|
||||||
"end": 2495000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "90m SW Broadcast",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 3200000,
|
|
||||||
"end": 3400000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "80m ham band",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 3500000,
|
|
||||||
"end": 3800000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "75m SW Broadcast",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 3900000,
|
|
||||||
"end": 4000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "60m SW Broadcast",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 4750000,
|
|
||||||
"end": 5060000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "60m ham band",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 5351500,
|
|
||||||
"end": 5366500
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "49m SW Broadcast",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 5900000,
|
|
||||||
"end": 6200000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "40m ham band",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 7000000,
|
|
||||||
"end": 7200000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "40m SW Broadcast",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 7200000,
|
|
||||||
"end": 7450000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "31m SW Broadcast",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 9400000,
|
|
||||||
"end": 9900000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "30m ham band",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 10100000,
|
|
||||||
"end": 10150000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "25m SW Broadcast",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 11600000,
|
|
||||||
"end": 12100000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "22m SW Broadcast",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 13570000,
|
|
||||||
"end": 13870000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "20m ham band",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 14000000,
|
|
||||||
"end": 14350000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "19m SW Broadcast",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 15100000,
|
|
||||||
"end": 15800000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "17m ham band",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 18068000,
|
|
||||||
"end": 18168000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "16m SW Broadcast",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 17480000,
|
|
||||||
"end": 17900000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "15m SW Broadcast",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 18900000,
|
|
||||||
"end": 19020000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "15m ham band",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 21000000,
|
|
||||||
"end": 21450000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "13m SW Broadcast",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 21450000,
|
|
||||||
"end": 21850000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "12m ham band",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 24890000,
|
|
||||||
"end": 24990000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "11m SW Broadcast",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 25670000,
|
|
||||||
"end": 26100000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "CB",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 26965000,
|
|
||||||
"end": 27405000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "10m ham band",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 28000000,
|
|
||||||
"end": 29700000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "FM Broadcast",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 87500000,
|
|
||||||
"end": 108000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Airband VOR/ILS",
|
|
||||||
"type": "aviation",
|
|
||||||
"start": 108000000,
|
|
||||||
"end": 117900000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Airband Voice",
|
|
||||||
"type": "aviation",
|
|
||||||
"start": 118000000,
|
|
||||||
"end": 137000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Polar orbiting satellites",
|
|
||||||
"type": "satellite",
|
|
||||||
"start": 137000000,
|
|
||||||
"end": 138000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "6m ham band",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 50000000,
|
|
||||||
"end": 52000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "4m ham band",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 70000000,
|
|
||||||
"end": 70500000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "2m ham band",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 144000000,
|
|
||||||
"end": 146000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "70cm ham band",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 430000000,
|
|
||||||
"end": 440000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "ADS-B",
|
|
||||||
"type": "aviation",
|
|
||||||
"start": 1089000000,
|
|
||||||
"end": 1091000000
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
"name": "Radionavigazione",
|
"name": "Radionavigazione",
|
||||||
"type": "marine",
|
"type": "marine",
|
||||||
"start": 11300,
|
"start": 11300,
|
||||||
"end": 148500
|
"end": 135500
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Radioamatori 137kHz",
|
"name": "Radioamatori 137kHz",
|
||||||
@@ -47,7 +47,7 @@
|
|||||||
"end": 520000
|
"end": 520000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Radioamatori 472kHz",
|
"name": "Radioamatori 472 kHz",
|
||||||
"type": "amateur",
|
"type": "amateur",
|
||||||
"start": 472000,
|
"start": 472000,
|
||||||
"end": 479000
|
"end": 479000
|
||||||
@@ -65,7 +65,7 @@
|
|||||||
"end": 1830000
|
"end": 1830000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Radioamatori 160m",
|
"name": "Radioamatori 160 m",
|
||||||
"type": "amateur",
|
"type": "amateur",
|
||||||
"start": 1830000,
|
"start": 1830000,
|
||||||
"end": 1850000
|
"end": 1850000
|
||||||
@@ -77,7 +77,7 @@
|
|||||||
"end": 2300000
|
"end": 2300000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Radiodiffusione OC 120m",
|
"name": "Radiodiffusione OC 120 m",
|
||||||
"type": "broadcast",
|
"type": "broadcast",
|
||||||
"start": 2300000,
|
"start": 2300000,
|
||||||
"end": 2500000
|
"end": 2500000
|
||||||
@@ -107,7 +107,7 @@
|
|||||||
"end": 3200000
|
"end": 3200000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Radiodiffusione OC 90m",
|
"name": "Radiodiffusione OC 90 m",
|
||||||
"type": "broadcast",
|
"type": "broadcast",
|
||||||
"start": 3200000,
|
"start": 3200000,
|
||||||
"end": 3400000
|
"end": 3400000
|
||||||
@@ -125,13 +125,13 @@
|
|||||||
"end": 3600000
|
"end": 3600000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Radioamatori 80m",
|
"name": "Radioamatori 80 m",
|
||||||
"type": "amateur",
|
"type": "amateur",
|
||||||
"start": 3500000,
|
"start": 3600000,
|
||||||
"end": 3800000
|
"end": 3800000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Radiodiffusione OC 75m",
|
"name": "Radiodiffusione OC 75 m",
|
||||||
"type": "broadcast",
|
"type": "broadcast",
|
||||||
"start": 3900000,
|
"start": 3900000,
|
||||||
"end": 4000000
|
"end": 4000000
|
||||||
@@ -150,19 +150,19 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
"name": "Radiodiffusione OC 60m",
|
"name": "Radiodiffusione OC 60 m",
|
||||||
"type": "broadcast",
|
"type": "broadcast",
|
||||||
"start": 4750000,
|
"start": 4750000,
|
||||||
"end": 4995000
|
"end": 4995000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Radiodiffusione OC 60m",
|
"name": "Radiodiffusione OC 60 m",
|
||||||
"type": "broadcast",
|
"type": "broadcast",
|
||||||
"start": 5005000,
|
"start": 5005000,
|
||||||
"end": 5060000
|
"end": 5060000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Radioamatori 60m",
|
"name": "Radioamatori 60 m",
|
||||||
"type": "amateur",
|
"type": "amateur",
|
||||||
"start": 5351500,
|
"start": 5351500,
|
||||||
"end": 5366500
|
"end": 5366500
|
||||||
@@ -174,7 +174,7 @@
|
|||||||
"end": 5730000
|
"end": 5730000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Radiodiffusione OC 49m",
|
"name": "Radiodiffusione OC 49 m",
|
||||||
"type": "broadcast",
|
"type": "broadcast",
|
||||||
"start": 5900000,
|
"start": 5900000,
|
||||||
"end": 6200000
|
"end": 6200000
|
||||||
@@ -192,13 +192,13 @@
|
|||||||
"end": 6765000
|
"end": 6765000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Radioamatori 40m",
|
"name": "Radioamatori 40 m",
|
||||||
"type": "amateur",
|
"type": "amateur",
|
||||||
"start": 7000000,
|
"start": 7000000,
|
||||||
"end": 7200000
|
"end": 7200000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Radiodiffusione OC 41m",
|
"name": "Radiodiffusione OC 41 m",
|
||||||
"type": "broadcast",
|
"type": "broadcast",
|
||||||
"start": 7200000,
|
"start": 7200000,
|
||||||
"end": 7450000
|
"end": 7450000
|
||||||
@@ -216,7 +216,7 @@
|
|||||||
"end": 9040000
|
"end": 9040000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Radiodiffusione OC 31m",
|
"name": "Radiodiffusione OC 31 m",
|
||||||
"type": "broadcast",
|
"type": "broadcast",
|
||||||
"start": 9400000,
|
"start": 9400000,
|
||||||
"end": 9900000
|
"end": 9900000
|
||||||
@@ -228,7 +228,7 @@
|
|||||||
"end": 10100000
|
"end": 10100000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Radioamatori 30m",
|
"name": "30m - Radioamateur",
|
||||||
"type": "amateur",
|
"type": "amateur",
|
||||||
"start": 10100000,
|
"start": 10100000,
|
||||||
"end": 10150000
|
"end": 10150000
|
||||||
@@ -282,7 +282,7 @@
|
|||||||
"end": 15100000
|
"end": 15100000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Radiodiffusione OC 19m",
|
"name": "Radiodiffusione OC 19 m",
|
||||||
"type": "broadcast",
|
"type": "broadcast",
|
||||||
"start": 15100000,
|
"start": 15100000,
|
||||||
"end": 15800000
|
"end": 15800000
|
||||||
@@ -294,7 +294,7 @@
|
|||||||
"end": 17410000
|
"end": 17410000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Radiodiffusione OC 16m",
|
"name": "Radiodiffusione OC 16 m",
|
||||||
"type": "broadcast",
|
"type": "broadcast",
|
||||||
"start": 17480000,
|
"start": 17480000,
|
||||||
"end": 17900000
|
"end": 17900000
|
||||||
@@ -306,9 +306,9 @@
|
|||||||
"end": 18030000
|
"end": 18030000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Radioamatori 17m",
|
"name": "Radioamatori 17 m",
|
||||||
"type": "amateur",
|
"type": "amateur",
|
||||||
"start": 18069000,
|
"start": 18068000,
|
||||||
"end": 18168000
|
"end": 18168000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -318,7 +318,7 @@
|
|||||||
"end": 18900000
|
"end": 18900000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Radiodiffusione OC 15m",
|
"name": "Radiodiffusione OC 15 m",
|
||||||
"type": "broadcast",
|
"type": "broadcast",
|
||||||
"start": 18900000,
|
"start": 18900000,
|
||||||
"end": 19020000
|
"end": 19020000
|
||||||
@@ -336,13 +336,13 @@
|
|||||||
"end": 20010000
|
"end": 20010000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Radioamatori 15m",
|
"name": "Radioamatori 15 m",
|
||||||
"type": "amateur",
|
"type": "amateur",
|
||||||
"start": 21000000,
|
"start": 21000000,
|
||||||
"end": 21450000
|
"end": 21450000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Radiodiffusione OC 13m",
|
"name": "Radiodiffusione OC 13 m",
|
||||||
"type": "broadcast",
|
"type": "broadcast",
|
||||||
"start": 21450000,
|
"start": 21450000,
|
||||||
"end": 21850000
|
"end": 21850000
|
||||||
@@ -366,7 +366,7 @@
|
|||||||
"end": 23350000
|
"end": 23350000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Radioamatori 12m",
|
"name": "Radioamatori 12 m",
|
||||||
"type": "amateur",
|
"type": "amateur",
|
||||||
"start": 24890000,
|
"start": 24890000,
|
||||||
"end": 24990000
|
"end": 24990000
|
||||||
@@ -390,7 +390,7 @@
|
|||||||
"end": 25670000
|
"end": 25670000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Radiodiffusione OC 11m",
|
"name": "Radiodiffusione OC 11 m",
|
||||||
"type": "broadcast",
|
"type": "broadcast",
|
||||||
"start": 25670000,
|
"start": 25670000,
|
||||||
"end": 26100000
|
"end": 26100000
|
||||||
@@ -408,7 +408,7 @@
|
|||||||
"end": 27230000
|
"end": 27230000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Radioamatori 10m",
|
"name": "Radioamatori 10 m",
|
||||||
"type": "amateur",
|
"type": "amateur",
|
||||||
"start": 28000000,
|
"start": 28000000,
|
||||||
"end": 29700000
|
"end": 29700000
|
||||||
@@ -420,10 +420,10 @@
|
|||||||
"end": 47000000
|
"end": 47000000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Radioamatori 6m",
|
"name": "Radioamatori 9 m",
|
||||||
"type": "amateur",
|
"type": "amateur",
|
||||||
"start": 50000000,
|
"start": 47000000,
|
||||||
"end": 51000000
|
"end": 52500000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Wind profiler",
|
"name": "Wind profiler",
|
||||||
@@ -438,7 +438,7 @@
|
|||||||
"end": 74800000
|
"end": 74800000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Radiofari 75MHz",
|
"name": "Radiofari 75 MHz",
|
||||||
"type": "aviation",
|
"type": "aviation",
|
||||||
"start": 74800000,
|
"start": 74800000,
|
||||||
"end": 75200000
|
"end": 75200000
|
||||||
@@ -446,19 +446,19 @@
|
|||||||
{
|
{
|
||||||
"name": "Radiodiffusione FM",
|
"name": "Radiodiffusione FM",
|
||||||
"type": "broadcast",
|
"type": "broadcast",
|
||||||
"start": 87500000,
|
"start": 80000000,
|
||||||
"end": 108000000
|
"end": 108000000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "VOR/ILS",
|
"name": "VOR/ILS",
|
||||||
"type": "aviation",
|
"type": "aviation",
|
||||||
"start": 108000000,
|
"start": 108000000,
|
||||||
"end": 117975000
|
"end": 118000000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Mobile aeronautico",
|
"name": "Mobile aeronautico",
|
||||||
"type": "aviation",
|
"type": "aviation",
|
||||||
"start": 117975000,
|
"start": 118000000,
|
||||||
"end": 137000000
|
"end": 137000000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -468,10 +468,10 @@
|
|||||||
"end": 138000000
|
"end": 138000000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Radioamatori 2m",
|
"name": "Radioamatori 2 m",
|
||||||
"type": "amateur",
|
"type": "amateur",
|
||||||
"start": 144000000,
|
"start": 144000000,
|
||||||
"end": 146000000
|
"end": 148000000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Telefonia satellitare",
|
"name": "Telefonia satellitare",
|
||||||
@@ -552,7 +552,7 @@
|
|||||||
"end": 430000000
|
"end": 430000000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Radioamatori 70cm",
|
"name": "Radioamatori 70 cm",
|
||||||
"type": "amateur",
|
"type": "amateur",
|
||||||
"start": 430000000,
|
"start": 430000000,
|
||||||
"end": 434000000
|
"end": 434000000
|
||||||
@@ -564,10 +564,10 @@
|
|||||||
"end": 435000000
|
"end": 435000000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Radioamatori 70cm",
|
"name": "Radioamatori 70 cm",
|
||||||
"type": "amateur",
|
"type": "amateur",
|
||||||
"start": 435000000,
|
"start": 435000000,
|
||||||
"end": 438000000
|
"end": 436000000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Mobile o fisso privato",
|
"name": "Mobile o fisso privato",
|
||||||
@@ -642,16 +642,10 @@
|
|||||||
"end": 124000000
|
"end": 124000000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Radioamatori 23cm",
|
"name": "Radioamatori 23 cm",
|
||||||
"type": "amateur",
|
"type": "amateur",
|
||||||
"start": 1240000000,
|
"start": 1240000000,
|
||||||
"end": 1245000000
|
"end": 1270000000
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Radioamatori 23cm",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 1267000000,
|
|
||||||
"end": 1298000000
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Wind profiler",
|
"name": "Wind profiler",
|
||||||
@@ -798,10 +792,10 @@
|
|||||||
"end": 2300000000
|
"end": 2300000000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Radioamatori 13cm",
|
"name": "Radioamatori 13 cm",
|
||||||
"type": "amateur",
|
"type": "amateur",
|
||||||
"start": 2300000000,
|
"start": 2300000000,
|
||||||
"end": 2450000000
|
"end": 2400000000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "ISM, SAP/SAB, 802.11",
|
"name": "ISM, SAP/SAB, 802.11",
|
||||||
@@ -833,6 +827,12 @@
|
|||||||
"start": 2900000000,
|
"start": 2900000000,
|
||||||
"end": 3400000000
|
"end": 3400000000
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "Radioamatori 9 cm",
|
||||||
|
"type": "amateur",
|
||||||
|
"start": 3400000000,
|
||||||
|
"end": 3475000000
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "Reti numeriche",
|
"name": "Reti numeriche",
|
||||||
"type": "comms",
|
"type": "comms",
|
||||||
@@ -858,21 +858,9 @@
|
|||||||
"end": 5650000000
|
"end": 5650000000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Radioamatori 5cm",
|
"name": "Radioamatori 6 cm",
|
||||||
"type": "amateur",
|
"type": "amateur",
|
||||||
"start": 5650000000,
|
"start": 5650000000,
|
||||||
"end": 5670000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Radioamatori 5cm",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 5760000000,
|
|
||||||
"end": 5770000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Radioamatori 5cm",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 5830000000,
|
|
||||||
"end": 5850000000
|
"end": 5850000000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -924,9 +912,9 @@
|
|||||||
"end": 10000000000
|
"end": 10000000000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Radioamatori 3cm",
|
"name": "Radioamatori 3 cm",
|
||||||
"type": "amateur",
|
"type": "amateur",
|
||||||
"start": 10300000000,
|
"start": 10000000000,
|
||||||
"end": 10500000000
|
"end": 10500000000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -1013,16 +1001,10 @@
|
|||||||
"start": 23150000000,
|
"start": 23150000000,
|
||||||
"end": 23338000000
|
"end": 23338000000
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "Radioamatori 1,5cm",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 24000000000,
|
|
||||||
"end": 24050000000
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "ISM, SRD e LPR",
|
"name": "ISM, SRD e LPR",
|
||||||
"type": "ism",
|
"type": "ism",
|
||||||
"start": 24050000000,
|
"start": 24000000000,
|
||||||
"end": 24450000000
|
"end": 24450000000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -1104,7 +1086,7 @@
|
|||||||
"end": 43500000000
|
"end": 43500000000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Radioamatori 7mm",
|
"name": "Radioamatori 6 mm",
|
||||||
"type": "amateur",
|
"type": "amateur",
|
||||||
"start": 47000000000,
|
"start": 47000000000,
|
||||||
"end": 47200000000
|
"end": 47200000000
|
||||||
@@ -1146,9 +1128,9 @@
|
|||||||
"end": 76500000000
|
"end": 76500000000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Radioamatori 4mm",
|
"name": "Radioamatori 4 mm",
|
||||||
"type": "amateur",
|
"type": "amateur",
|
||||||
"start": 75500000000,
|
"start": 76500000000,
|
||||||
"end": 81500000000
|
"end": 81500000000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -1164,25 +1146,19 @@
|
|||||||
"end": 122250000000
|
"end": 122250000000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Radioamatori 2,4mm",
|
"name": "Radioamatori 2,5 mm",
|
||||||
"type": "amateur",
|
"type": "amateur",
|
||||||
"start": 122500000000,
|
"start": 122250000000,
|
||||||
"end": 123000000000
|
"end": 123000000000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Radioamatori 2,23mm",
|
"name": "Radioamatori 2 mm",
|
||||||
"type": "amateur",
|
"type": "amateur",
|
||||||
"start": 134000000000,
|
"start": 134000000000,
|
||||||
"end": 141000000000
|
"end": 141000000000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Radioamatori 2,1mm",
|
"name": "Radioamatori 1 mm",
|
||||||
"type": "amateur",
|
|
||||||
"start": 142000000000,
|
|
||||||
"end": 144000000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Radioamatori 1mm",
|
|
||||||
"type": "amateur",
|
"type": "amateur",
|
||||||
"start": 241000000000,
|
"start": 241000000000,
|
||||||
"end": 250000000000
|
"end": 250000000000
|
||||||
|
|||||||
@@ -1,549 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "Republic of Korea",
|
|
||||||
"country_name": "Republic of Korea",
|
|
||||||
"country_code": "KR",
|
|
||||||
"author_name": "SeoyeonBae",
|
|
||||||
"author_url": "https://github.com/bsy0317",
|
|
||||||
"bands": [
|
|
||||||
{
|
|
||||||
"name": "Radio Navigation",
|
|
||||||
"type": "aviation",
|
|
||||||
"start": 8300,
|
|
||||||
"end": 14000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Coastal Telegraph",
|
|
||||||
"type": "marine",
|
|
||||||
"start": 14000,
|
|
||||||
"end": 19950
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Standard Frequency Time Signal",
|
|
||||||
"type": "utility",
|
|
||||||
"start": 19950,
|
|
||||||
"end": 20250
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Coastal Telegraph",
|
|
||||||
"type": "marine",
|
|
||||||
"start": 20250,
|
|
||||||
"end": 70000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Radio Navigation",
|
|
||||||
"type": "navigation",
|
|
||||||
"start": 70000,
|
|
||||||
"end": 160000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Aviation Radio Navigation",
|
|
||||||
"type": "aviation",
|
|
||||||
"start": 160000,
|
|
||||||
"end": 285000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Aviation Maritime Radiobeacon",
|
|
||||||
"type": "aviation",
|
|
||||||
"start": 285000,
|
|
||||||
"end": 325000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Aviation Radio Navigation",
|
|
||||||
"type": "aviation",
|
|
||||||
"start": 325000,
|
|
||||||
"end": 472000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Amateur",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 472000,
|
|
||||||
"end": 479000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "International Distress Safety Call",
|
|
||||||
"type": "marine",
|
|
||||||
"start": 479000,
|
|
||||||
"end": 505000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Maritime Telegraph",
|
|
||||||
"type": "marine",
|
|
||||||
"start": 505000,
|
|
||||||
"end": 526500
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Standard Broadcast",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 526500,
|
|
||||||
"end": 1606500
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Radiobuoy",
|
|
||||||
"type": "navigation",
|
|
||||||
"start": 1606500,
|
|
||||||
"end": 1800000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Amateur Station",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 1800000,
|
|
||||||
"end": 1825000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Radiobuoy Control LORAN",
|
|
||||||
"type": "radiolocation",
|
|
||||||
"start": 1825000,
|
|
||||||
"end": 2000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Radiobuoy",
|
|
||||||
"type": "fixed",
|
|
||||||
"start": 2000000,
|
|
||||||
"end": 2065000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Distress Call",
|
|
||||||
"type": "marine",
|
|
||||||
"start": 2065000,
|
|
||||||
"end": 2107000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "International Distress Search and Rescue",
|
|
||||||
"type": "mobile",
|
|
||||||
"start": 2173500,
|
|
||||||
"end": 2190500
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Road Management",
|
|
||||||
"type": "fixed",
|
|
||||||
"start": 2194000,
|
|
||||||
"end": 2495000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Standard Frequency Time Signal",
|
|
||||||
"type": "utility",
|
|
||||||
"start": 2495000,
|
|
||||||
"end": 2505000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Ship Station Telephone",
|
|
||||||
"type": "fixed",
|
|
||||||
"start": 2505000,
|
|
||||||
"end": 2850000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Aviation Mobile R",
|
|
||||||
"type": "aviation",
|
|
||||||
"start": 2850000,
|
|
||||||
"end": 3025000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Aviation Mobile OR",
|
|
||||||
"type": "aviation",
|
|
||||||
"start": 3025000,
|
|
||||||
"end": 3155000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Aviation Mobile R",
|
|
||||||
"type": "aviation",
|
|
||||||
"start": 3400000,
|
|
||||||
"end": 3500000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Amateur Station",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 3500000,
|
|
||||||
"end": 3550000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Experimental Station",
|
|
||||||
"type": "fixed",
|
|
||||||
"start": 3550000,
|
|
||||||
"end": 3790000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Amateur Station",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 3790000,
|
|
||||||
"end": 3800000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Shortwave Broadcast",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 3900000,
|
|
||||||
"end": 3950000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Standard Frequency Time Signal",
|
|
||||||
"type": "utility",
|
|
||||||
"start": 3995000,
|
|
||||||
"end": 4005000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Ship Station Telephone",
|
|
||||||
"type": "marine",
|
|
||||||
"start": 4005000,
|
|
||||||
"end": 4063000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Oceanographic Data",
|
|
||||||
"type": "marine",
|
|
||||||
"start": 4063000,
|
|
||||||
"end": 4065000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Ship Station Duplex Telephone",
|
|
||||||
"type": "marine",
|
|
||||||
"start": 4065000,
|
|
||||||
"end": 4146000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Ship Station Simplex Telephone",
|
|
||||||
"type": "marine",
|
|
||||||
"start": 4146000,
|
|
||||||
"end": 4152000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Ship Station Wideband Telegraph Fax",
|
|
||||||
"type": "marine",
|
|
||||||
"start": 4152000,
|
|
||||||
"end": 4172000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Ship Station Narrowband",
|
|
||||||
"type": "marine",
|
|
||||||
"start": 4172000,
|
|
||||||
"end": 4181750
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Ship Station A1A Morse Code Communication",
|
|
||||||
"type": "marine",
|
|
||||||
"start": 4186750,
|
|
||||||
"end": 4202250
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Radiolocation",
|
|
||||||
"type": "radiolocation",
|
|
||||||
"start": 4438000,
|
|
||||||
"end": 4488000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Calling Response",
|
|
||||||
"type": "fixed",
|
|
||||||
"start": 4488000,
|
|
||||||
"end": 4650000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Aviation Mobile R",
|
|
||||||
"type": "aviation",
|
|
||||||
"start": 4650000,
|
|
||||||
"end": 4850000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Standard Frequency Time Signal",
|
|
||||||
"type": "utility",
|
|
||||||
"start": 4995000,
|
|
||||||
"end": 5005000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Search Rescue",
|
|
||||||
"type": "aviation",
|
|
||||||
"start": 5480000,
|
|
||||||
"end": 5730000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Broadcast",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 5900000,
|
|
||||||
"end": 5950000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Shortwave Broadcast",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 5950000,
|
|
||||||
"end": 6200000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Amateur Station",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 7000000,
|
|
||||||
"end": 7100000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Amateur Station",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 7100000,
|
|
||||||
"end": 7200000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Shortwave Broadcast",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 7200000,
|
|
||||||
"end": 7450000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Standard Frequency Time Signal",
|
|
||||||
"type": "utility",
|
|
||||||
"start": 7995000,
|
|
||||||
"end": 8005000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Broadcast",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 9400000,
|
|
||||||
"end": 9500000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Shortwave Broadcast",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 9500000,
|
|
||||||
"end": 9900000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Standard Frequency Time Signal",
|
|
||||||
"type": "utility",
|
|
||||||
"start": 9995000,
|
|
||||||
"end": 10005000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Amateur Station",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 10100000,
|
|
||||||
"end": 10150000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Aviation Mobile",
|
|
||||||
"type": "aviation",
|
|
||||||
"start": 10150000,
|
|
||||||
"end": 11600000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Broadcast",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 11600000,
|
|
||||||
"end": 11650000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Shortwave Broadcast",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 11650000,
|
|
||||||
"end": 12050000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Broadcast",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 12050000,
|
|
||||||
"end": 12100000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Aviation Mobile",
|
|
||||||
"type": "aviation",
|
|
||||||
"start": 13260000,
|
|
||||||
"end": 13360000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Radio Astronomy",
|
|
||||||
"type": "astronomy",
|
|
||||||
"start": 13360000,
|
|
||||||
"end": 13410000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Broadcast",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 13570000,
|
|
||||||
"end": 13600000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Shortwave Broadcast",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 13600000,
|
|
||||||
"end": 13800000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Broadcast",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 13800000,
|
|
||||||
"end": 13870000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Amateur Station",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 14000000,
|
|
||||||
"end": 14350000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Aviation Mobile",
|
|
||||||
"type": "aviation",
|
|
||||||
"start": 15010000,
|
|
||||||
"end": 15100000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Shortwave Broadcast",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 15100000,
|
|
||||||
"end": 15600000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Shortwave Broadcast",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 15600000,
|
|
||||||
"end": 15800000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Shortwave Broadcast",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 15800000,
|
|
||||||
"end": 15995000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Standard Frequency Time Signal",
|
|
||||||
"type": "utility",
|
|
||||||
"start": 15995000,
|
|
||||||
"end": 16005000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Broadcast",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 18900000,
|
|
||||||
"end": 19020000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Amateur Station",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 21000000,
|
|
||||||
"end": 21450000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Shortwave Broadcast",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 21450000,
|
|
||||||
"end": 21850000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Amateur Station",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 24890000,
|
|
||||||
"end": 24990000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Shortwave Broadcast",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 25670000,
|
|
||||||
"end": 26100000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Amateur Station",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 28000000,
|
|
||||||
"end": 29700000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Amateur Station",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 50000000,
|
|
||||||
"end": 54000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "TV Broadcast",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 54000000,
|
|
||||||
"end": 72000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Flood Warning",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 72000000,
|
|
||||||
"end": 74800000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "TV Broadcast",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 76000000,
|
|
||||||
"end": 88000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "FM Broadcast",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 88000000,
|
|
||||||
"end": 100000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "FM Broadcast",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 100000000,
|
|
||||||
"end": 108000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "ILS Localizer VOR",
|
|
||||||
"type": "fixed",
|
|
||||||
"start": 108000000,
|
|
||||||
"end": 117975000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Amateur Station",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 144000000,
|
|
||||||
"end": 146000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "General Communication",
|
|
||||||
"type": "fixed",
|
|
||||||
"start": 146000000,
|
|
||||||
"end": 148000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Low Power Device",
|
|
||||||
"type": "fixed",
|
|
||||||
"start": 162037500,
|
|
||||||
"end": 174000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "TV Broadcast",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 174000000,
|
|
||||||
"end": 216000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Low Power Device",
|
|
||||||
"type": "fixed",
|
|
||||||
"start": 216000000,
|
|
||||||
"end": 230000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Low Power Device",
|
|
||||||
"type": "fixed",
|
|
||||||
"start": 273000000,
|
|
||||||
"end": 322000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Personal Radio",
|
|
||||||
"type": "fixed",
|
|
||||||
"start": 420000000,
|
|
||||||
"end": 470000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Public Network",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 698000000,
|
|
||||||
"end": 806000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Low Power Device",
|
|
||||||
"type": "fixed",
|
|
||||||
"start": 942000000,
|
|
||||||
"end": 960000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Satellite Mobile Communication",
|
|
||||||
"type": "fixed",
|
|
||||||
"start": 15250000000,
|
|
||||||
"end": 16605000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Mobile Communication",
|
|
||||||
"type": "mobile",
|
|
||||||
"start": 25000000000,
|
|
||||||
"end": 37000000000
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -3,7 +3,7 @@ Encoding=UTF-8
|
|||||||
Version=1.0
|
Version=1.0
|
||||||
Type=Application
|
Type=Application
|
||||||
Terminal=false
|
Terminal=false
|
||||||
Exec=@CMAKE_INSTALL_PREFIX@/bin/sdrpp
|
Exec=@SDRPP_BIN_INSTALL_DIR@/sdrpp
|
||||||
Name=SDR++
|
Name=SDR++
|
||||||
Icon=@CMAKE_INSTALL_PREFIX@/share/sdrpp/icons/sdrpp.png
|
Icon=@SDRPP_RES_INSTALL_DIR@/icons/sdrpp.png
|
||||||
Categories=HamRadio
|
Categories=HamRadio
|
||||||
@@ -6,6 +6,10 @@ if (NOT SDRPP_MODULE_COMPILER_FLAGS)
|
|||||||
set(SDRPP_MODULE_COMPILER_FLAGS @SDRPP_MODULE_COMPILER_FLAGS@)
|
set(SDRPP_MODULE_COMPILER_FLAGS @SDRPP_MODULE_COMPILER_FLAGS@)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
|
# Add compiler definitions for the directories
|
||||||
|
add_definitions(-DSDRPP_MODULES_LOAD_DIR="${SDRPP_MODULES_LOAD_DIR}")
|
||||||
|
add_definitions(-DSDRPP_RES_LOAD_DIR="${SDRPP_RES_LOAD_DIR}")
|
||||||
|
|
||||||
# Created shared lib and link to core
|
# Created shared lib and link to core
|
||||||
add_library(${PROJECT_NAME} SHARED ${SRC})
|
add_library(${PROJECT_NAME} SHARED ${SRC})
|
||||||
target_link_libraries(${PROJECT_NAME} PRIVATE sdrpp_core)
|
target_link_libraries(${PROJECT_NAME} PRIVATE sdrpp_core)
|
||||||
@@ -16,4 +20,4 @@ set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "")
|
|||||||
target_compile_options(${PROJECT_NAME} PRIVATE ${SDRPP_MODULE_COMPILER_FLAGS})
|
target_compile_options(${PROJECT_NAME} PRIVATE ${SDRPP_MODULE_COMPILER_FLAGS})
|
||||||
|
|
||||||
# Install directives
|
# Install directives
|
||||||
install(TARGETS ${PROJECT_NAME} DESTINATION lib/sdrpp/plugins)
|
install(TARGETS ${PROJECT_NAME} DESTINATION ${SDRPP_MODULES_INSTALL_DIR})
|
||||||
@@ -217,19 +217,14 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void startServer() {
|
void startServer() {
|
||||||
try {
|
if (modeId == SINK_MODE_TCP) {
|
||||||
if (modeId == SINK_MODE_TCP) {
|
listener = net::listen(hostname, port);
|
||||||
listener = net::listen(hostname, port);
|
if (listener) {
|
||||||
if (listener) {
|
listener->acceptAsync(clientHandler, this);
|
||||||
listener->acceptAsync(clientHandler, this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
conn = net::openUDP("0.0.0.0", port, hostname, port, false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (const std::exception& e) {
|
else {
|
||||||
flog::error("Failed to open socket: {}", e.what());
|
conn = net::openUDP("0.0.0.0", port, hostname, port, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -183,9 +183,6 @@ private:
|
|||||||
static void start(void* ctx) {
|
static void start(void* ctx) {
|
||||||
AudioSourceModule* _this = (AudioSourceModule*)ctx;
|
AudioSourceModule* _this = (AudioSourceModule*)ctx;
|
||||||
if (_this->running) { return; }
|
if (_this->running) { return; }
|
||||||
|
|
||||||
// If no device is selected, give up
|
|
||||||
if (_this->selectedDevice.empty()) { return; }
|
|
||||||
|
|
||||||
// Stream options
|
// Stream options
|
||||||
RtAudio::StreamParameters parameters;
|
RtAudio::StreamParameters parameters;
|
||||||
|
|||||||
25
source_modules/badgesdr_source/CMakeLists.txt
Normal file
25
source_modules/badgesdr_source/CMakeLists.txt
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.13)
|
||||||
|
project(badgesdr_source)
|
||||||
|
|
||||||
|
file(GLOB SRC "src/*.cpp")
|
||||||
|
|
||||||
|
include(${SDRPP_MODULE_CMAKE})
|
||||||
|
|
||||||
|
if (MSVC)
|
||||||
|
find_package(libusb CONFIG REQUIRED)
|
||||||
|
target_include_directories(badgesdr_source PRIVATE ${LIBUSB_INCLUDE_DIRS})
|
||||||
|
target_link_libraries(badgesdr_source PRIVATE ${LIBUSB_LIBRARIES})
|
||||||
|
elseif (ANDROID)
|
||||||
|
target_link_libraries(badgesdr_source PUBLIC
|
||||||
|
/sdr-kit/${ANDROID_ABI}/lib/libusb1.0.so
|
||||||
|
/sdr-kit/${ANDROID_ABI}/lib/librtlsdr.so
|
||||||
|
)
|
||||||
|
else (MSVC)
|
||||||
|
find_package(PkgConfig)
|
||||||
|
|
||||||
|
pkg_check_modules(LIBUSB REQUIRED libusb-1.0)
|
||||||
|
|
||||||
|
target_include_directories(badgesdr_source PRIVATE ${LIBUSB_INCLUDE_DIRS})
|
||||||
|
target_link_directories(badgesdr_source PRIVATE ${LIBUSB_LIBRARY_DIRS})
|
||||||
|
target_link_libraries(badgesdr_source PRIVATE ${LIBUSB_LIBRARIES})
|
||||||
|
endif ()
|
||||||
309
source_modules/badgesdr_source/src/badgesdr.cpp
Normal file
309
source_modules/badgesdr_source/src/badgesdr.cpp
Normal file
@@ -0,0 +1,309 @@
|
|||||||
|
#include "badgesdr.h"
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <utils/flog.h>
|
||||||
|
|
||||||
|
#define R820T_I2C_ADDR 0x1A
|
||||||
|
|
||||||
|
namespace BadgeSDR {
|
||||||
|
enum Commands {
|
||||||
|
CMD_I2C_RW,
|
||||||
|
CMD_I2C_STATUS,
|
||||||
|
CMD_ADC_START,
|
||||||
|
CMD_ADC_STOP,
|
||||||
|
CMD_ADC_GET_SAMP_COUNT
|
||||||
|
};
|
||||||
|
|
||||||
|
libusb_context* ctx = NULL;
|
||||||
|
|
||||||
|
bool DeviceInfo::operator==(const DeviceInfo& b) const {
|
||||||
|
return serialNumber == b.serialNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Device::write_reg(uint8_t reg, uint8_t value, void* ctx) {
|
||||||
|
Device* dev = (Device*)ctx;
|
||||||
|
dev->writeR820TReg(reg, value);
|
||||||
|
dev->writeR820TReg(0x1F, 0); // TODO: Figure out why this is needed
|
||||||
|
}
|
||||||
|
|
||||||
|
void Device::read_reg(uint8_t* data, int len, void* ctx) {
|
||||||
|
Device* dev = (Device*)ctx;
|
||||||
|
dev->readI2C(R820T_I2C_ADDR, data, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
Device::Device(libusb_device_handle* dev) {
|
||||||
|
// Save device handle
|
||||||
|
this->dev = dev;
|
||||||
|
|
||||||
|
// Init tuner
|
||||||
|
r820t = {
|
||||||
|
16000000, // xtal_freq => 16MHz
|
||||||
|
3000000, // Set at boot to airspy_m0_m4_conf_t conf0 -> r820t_if_freq
|
||||||
|
100000000, /* Default Freq 100Mhz */
|
||||||
|
{
|
||||||
|
/* 05 */ 0x9F, // LNA manual gain mode, init to 0
|
||||||
|
/* 06 */ 0x80,
|
||||||
|
/* 07 */ 0x60,
|
||||||
|
/* 08 */ 0x80, // Image Gain Adjustment
|
||||||
|
/* 09 */ 0x40, // Image Phase Adjustment
|
||||||
|
/* 0A */ 0xA8, // Channel filter [0..3]: 0 = widest, f = narrowest - Optimal. Don't touch!
|
||||||
|
/* 0B */ 0x0F, // High pass filter - Optimal. Don't touch!
|
||||||
|
/* 0C */ 0x4F, // VGA control by code, init at 0
|
||||||
|
/* 0D */ 0x63, // LNA AGC settings: [0..3]: Lower threshold; [4..7]: High threshold
|
||||||
|
/* 0E */ 0x75,
|
||||||
|
/* 0F */ 0xE8, // Filter Widest, LDO_5V OFF, clk out ON,
|
||||||
|
/* 10 */ 0x7C,
|
||||||
|
/* 11 */ 0x42,
|
||||||
|
/* 12 */ 0x06,
|
||||||
|
/* 13 */ 0x00,
|
||||||
|
/* 14 */ 0x0F,
|
||||||
|
/* 15 */ 0x00,
|
||||||
|
/* 16 */ 0xC0,
|
||||||
|
/* 17 */ 0xA0,
|
||||||
|
/* 18 */ 0x48,
|
||||||
|
/* 19 */ 0xCC,
|
||||||
|
/* 1A */ 0x60,
|
||||||
|
/* 1B */ 0x00,
|
||||||
|
/* 1C */ 0x54,
|
||||||
|
/* 1D */ 0xAE,
|
||||||
|
/* 1E */ 0x0A,
|
||||||
|
/* 1F */ 0xC0
|
||||||
|
},
|
||||||
|
0 /* uint16_t padding */
|
||||||
|
};
|
||||||
|
r820t_init(&r820t, 3000000, write_reg, read_reg, this);
|
||||||
|
r820t_set_mixer_gain(&r820t, 15);
|
||||||
|
r820t_set_vga_gain(&r820t, 15);
|
||||||
|
}
|
||||||
|
|
||||||
|
Device::~Device() {
|
||||||
|
// Release the bulk interface
|
||||||
|
libusb_release_interface(dev, 0);
|
||||||
|
|
||||||
|
// Close device
|
||||||
|
libusb_close(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Device::setFrequency(double freq) {
|
||||||
|
r820t_set_freq(&r820t, freq - 2125000);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Device::setLNAGain(int gain) {
|
||||||
|
r820t_set_lna_gain(&r820t, gain);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Device::setMixerGain(int gain) {
|
||||||
|
r820t_set_mixer_gain(&r820t, gain);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Device::setVGAGain(int gain) {
|
||||||
|
r820t_set_vga_gain(&r820t, gain);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Device::start(void (*callback)(const uint8_t* samples, int count, void* ctx), void* ctx, int minBufferSize) {
|
||||||
|
// Do nothing if already running
|
||||||
|
if (run) { return; }
|
||||||
|
|
||||||
|
// Save handler
|
||||||
|
this->callback = callback;
|
||||||
|
this->ctx = ctx;
|
||||||
|
|
||||||
|
// Compute buffer size
|
||||||
|
int bufCount = minBufferSize / 64;
|
||||||
|
if (minBufferSize % 64) { bufCount++; }
|
||||||
|
bufferSize = bufCount * 64;
|
||||||
|
|
||||||
|
// Mark as running
|
||||||
|
run = true;
|
||||||
|
|
||||||
|
// Start the ADC
|
||||||
|
startADC();
|
||||||
|
|
||||||
|
// Start worker thread
|
||||||
|
workerThread = std::thread(&Device::worker, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Device::stop() {
|
||||||
|
// Do nothing if already stopped
|
||||||
|
if (!run) { return; }
|
||||||
|
|
||||||
|
// Mark as stopped
|
||||||
|
run = false;
|
||||||
|
|
||||||
|
// Wait for the worker to exit
|
||||||
|
if (workerThread.joinable()) { workerThread.join(); }
|
||||||
|
|
||||||
|
// Stop the ADC
|
||||||
|
stopADC();
|
||||||
|
}
|
||||||
|
|
||||||
|
int Device::getI2CStatus() {
|
||||||
|
int status;
|
||||||
|
int ret = libusb_control_transfer(dev, (1 << 7) | (2 << 5), CMD_I2C_STATUS, 0, 0, (uint8_t*)&status, sizeof(status), 1000);
|
||||||
|
if (ret <= 0 || status < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Device::readI2C(uint8_t addr, uint8_t* data, int len) {
|
||||||
|
// Do read
|
||||||
|
int bytes = libusb_control_transfer(dev, (1 << 7) | (2 << 5), CMD_I2C_RW, 0, addr, data, len, 1000);
|
||||||
|
if (bytes < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get status (TODO: Use function)
|
||||||
|
int status;
|
||||||
|
int ret = libusb_control_transfer(dev, (1 << 7) | (2 << 5), CMD_I2C_STATUS, 0, 0, (uint8_t*)&status, sizeof(status), 1000);
|
||||||
|
if (ret <= 0 || status < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Device::writeI2C(uint8_t addr, const uint8_t* data, int len) {
|
||||||
|
// Do write
|
||||||
|
int bytes = libusb_control_transfer(dev, (2 << 5), CMD_I2C_RW, 0, addr, (uint8_t*)data, len, 1000);
|
||||||
|
if (bytes < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get status (TODO: Use function)
|
||||||
|
int status;
|
||||||
|
int ret = libusb_control_transfer(dev, (1 << 7) | (2 << 5), CMD_I2C_STATUS, 0, 0, (uint8_t*)&status, sizeof(status), 1000);
|
||||||
|
if (ret <= 0 || status < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t bitrev(uint8_t val) {
|
||||||
|
return ((val & 0x01) << 7) | ((val & 0x02) << 5) | ((val & 0x04) << 3) | ((val & 0x08) << 1) | ((val & 0x10) >> 1) | ((val & 0x20) >> 3) | ((val & 0x40) >> 5) | ((val & 0x80) >> 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t Device::readR820TReg(uint8_t reg) {
|
||||||
|
// Read registers up to it (can't read single)
|
||||||
|
uint8_t regs[0x20];
|
||||||
|
readI2C(R820T_I2C_ADDR, regs, reg+1);
|
||||||
|
|
||||||
|
// Invert bit order
|
||||||
|
return bitrev(regs[reg]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Device::writeR820TReg(uint8_t reg, uint8_t val) {
|
||||||
|
// Write register id then value
|
||||||
|
uint8_t cmd[2] = { reg, val };
|
||||||
|
writeI2C(R820T_I2C_ADDR, cmd, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Device::startADC() {
|
||||||
|
return libusb_control_transfer(dev, (2 << 5), CMD_ADC_START, 0, 0, NULL, 0, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Device::stopADC() {
|
||||||
|
return libusb_control_transfer(dev, (2 << 5), CMD_ADC_STOP, 0, 0, NULL, 0, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Device::worker() {
|
||||||
|
// Allocate sample buffer
|
||||||
|
uint8_t* buffer = new uint8_t[bufferSize];
|
||||||
|
int sampleCount = 0;
|
||||||
|
|
||||||
|
while (run) {
|
||||||
|
// Receive data with bulk transfer
|
||||||
|
int recvLen = 0;
|
||||||
|
int val = libusb_bulk_transfer(dev, LIBUSB_ENDPOINT_IN | 1, &buffer[sampleCount], bufferSize - sampleCount, &recvLen, 1000);
|
||||||
|
|
||||||
|
// If timed out, try again. Otherwise, if an error occur, stop the thread
|
||||||
|
if (val == LIBUSB_ERROR_TIMEOUT) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (val) {
|
||||||
|
flog::error("USB Error: {}", val);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Increment sample count
|
||||||
|
if (recvLen) { sampleCount += recvLen; }
|
||||||
|
|
||||||
|
// If the buffer is full, call handler and reset sample count
|
||||||
|
if (sampleCount >= bufferSize) {
|
||||||
|
callback(buffer, sampleCount, ctx);
|
||||||
|
sampleCount = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Free buffer
|
||||||
|
delete[] buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<DeviceInfo> list() {
|
||||||
|
// Init libusb if done yet
|
||||||
|
if (!ctx) {
|
||||||
|
libusb_init(&ctx);
|
||||||
|
libusb_set_debug(ctx, LIBUSB_LOG_LEVEL_WARNING);
|
||||||
|
}
|
||||||
|
|
||||||
|
// List devices
|
||||||
|
std::vector<DeviceInfo> devList;
|
||||||
|
libusb_device** devices;
|
||||||
|
int devCount = libusb_get_device_list(ctx, &devices);
|
||||||
|
for (int i = 0; i < devCount; i++) {
|
||||||
|
// Get device info
|
||||||
|
DeviceInfo devInfo;
|
||||||
|
devInfo.dev = devices[i];
|
||||||
|
libusb_device_descriptor desc;
|
||||||
|
libusb_get_device_descriptor(devInfo.dev, &desc);
|
||||||
|
|
||||||
|
// Check the VID/PID and give up if not the right ones
|
||||||
|
if (desc.idVendor != 0xCAFE || desc.idProduct != 0x4010) {
|
||||||
|
libusb_unref_device(devInfo.dev);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open devices
|
||||||
|
libusb_device_handle* openDev;
|
||||||
|
int err = libusb_open(devInfo.dev, &openDev);
|
||||||
|
if (err) {
|
||||||
|
libusb_unref_device(devInfo.dev);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get serial number
|
||||||
|
char serial[128];
|
||||||
|
libusb_get_string_descriptor_ascii(openDev, desc.iSerialNumber, (uint8_t*)serial, sizeof(serial));
|
||||||
|
devInfo.serialNumber = serial;
|
||||||
|
|
||||||
|
// TODO: The libusb device should be unreffed but would need to know when the list disappears
|
||||||
|
|
||||||
|
// Close device
|
||||||
|
libusb_close(openDev);
|
||||||
|
|
||||||
|
// Add to list
|
||||||
|
devList.push_back(devInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return devices
|
||||||
|
return devList;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Device> open(const DeviceInfo& dev) {
|
||||||
|
// Open device
|
||||||
|
libusb_device_handle* openDev;
|
||||||
|
int err = libusb_open(dev.dev, &openDev);
|
||||||
|
if (err) {
|
||||||
|
throw std::runtime_error("Failed to open device");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Claim the bulk transfer interface
|
||||||
|
if (libusb_claim_interface(openDev, 0)) {
|
||||||
|
throw std::runtime_error("Failed to claim bulk interface");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create device
|
||||||
|
return std::make_shared<Device>(openDev);
|
||||||
|
}
|
||||||
|
}
|
||||||
53
source_modules/badgesdr_source/src/badgesdr.h
Normal file
53
source_modules/badgesdr_source/src/badgesdr.h
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
#include <thread>
|
||||||
|
#include <libusb.h>
|
||||||
|
#include "r820t.h"
|
||||||
|
|
||||||
|
namespace BadgeSDR {
|
||||||
|
struct DeviceInfo {
|
||||||
|
std::string serialNumber;
|
||||||
|
libusb_device* dev;
|
||||||
|
bool operator==(const DeviceInfo& b) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Device {
|
||||||
|
public:
|
||||||
|
Device(libusb_device_handle* dev);
|
||||||
|
~Device();
|
||||||
|
|
||||||
|
void setFrequency(double freq);
|
||||||
|
void setLNAGain(int gain);
|
||||||
|
void setMixerGain(int gain);
|
||||||
|
void setVGAGain(int gain);
|
||||||
|
|
||||||
|
void start(void (*callback)(const uint8_t* samples, int count, void* ctx), void* ctx = NULL, int minBufferSize = 2500);
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
private:
|
||||||
|
int getI2CStatus();
|
||||||
|
int readI2C(uint8_t addr, uint8_t* data, int len);
|
||||||
|
int writeI2C(uint8_t addr, const uint8_t* data, int len);
|
||||||
|
uint8_t readR820TReg(uint8_t reg);
|
||||||
|
void writeR820TReg(uint8_t reg, uint8_t val);
|
||||||
|
int startADC();
|
||||||
|
int stopADC();
|
||||||
|
void worker();
|
||||||
|
|
||||||
|
libusb_device_handle* dev;
|
||||||
|
std::thread workerThread;
|
||||||
|
bool run = false;
|
||||||
|
int bufferSize = 0; // Must be multiple of 64 for best performance
|
||||||
|
void* ctx = NULL;
|
||||||
|
void (*callback)(const uint8_t* samples, int count, void* ctx);
|
||||||
|
|
||||||
|
static void write_reg(uint8_t reg, uint8_t value, void* ctx);
|
||||||
|
static void read_reg(uint8_t* data, int len, void* ctx);
|
||||||
|
r820t_priv_t r820t;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<DeviceInfo> list();
|
||||||
|
std::shared_ptr<Device> open(const DeviceInfo& dev);
|
||||||
|
}
|
||||||
272
source_modules/badgesdr_source/src/main.cpp
Normal file
272
source_modules/badgesdr_source/src/main.cpp
Normal file
@@ -0,0 +1,272 @@
|
|||||||
|
#include <imgui.h>
|
||||||
|
#include <module.h>
|
||||||
|
#include <gui/gui.h>
|
||||||
|
#include <gui/smgui.h>
|
||||||
|
#include <signal_path/signal_path.h>
|
||||||
|
#include <core.h>
|
||||||
|
#include <utils/optionlist.h>
|
||||||
|
#include <dsp/channel/rx_vfo.h>
|
||||||
|
#include <dsp/correction/dc_blocker.h>
|
||||||
|
#include "badgesdr.h"
|
||||||
|
|
||||||
|
SDRPP_MOD_INFO{
|
||||||
|
/* Name: */ "badgesdr_source",
|
||||||
|
/* Description: */ "BadgeSDR Source Module",
|
||||||
|
/* Author: */ "Ryzerth",
|
||||||
|
/* Version: */ 0, 1, 0,
|
||||||
|
/* Max instances */ -1
|
||||||
|
};
|
||||||
|
|
||||||
|
#define CONCAT(a, b) ((std::string(a) + b).c_str())
|
||||||
|
|
||||||
|
class BadgeSDRSourceModule : public ModuleManager::Instance {
|
||||||
|
public:
|
||||||
|
BadgeSDRSourceModule(std::string name) {
|
||||||
|
this->name = name;
|
||||||
|
|
||||||
|
sampleRate = 250000.0;
|
||||||
|
|
||||||
|
// Initialize DSP
|
||||||
|
dcBlock.init(&input, 0.001);
|
||||||
|
ddc.init(&dcBlock.out, 500000, 250000, 250000, 125000);
|
||||||
|
|
||||||
|
handler.ctx = this;
|
||||||
|
handler.selectHandler = menuSelected;
|
||||||
|
handler.deselectHandler = menuDeselected;
|
||||||
|
handler.menuHandler = menuHandler;
|
||||||
|
handler.startHandler = start;
|
||||||
|
handler.stopHandler = stop;
|
||||||
|
handler.tuneHandler = tune;
|
||||||
|
handler.stream = &ddc.out;
|
||||||
|
|
||||||
|
// Refresh devices
|
||||||
|
refresh();
|
||||||
|
|
||||||
|
// Select first (TODO: Select from config)
|
||||||
|
select("");
|
||||||
|
|
||||||
|
sigpath::sourceManager.registerSource("BadgeSDR", &handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
~BadgeSDRSourceModule() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void postInit() {}
|
||||||
|
|
||||||
|
void enable() {
|
||||||
|
enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void disable() {
|
||||||
|
enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isEnabled() {
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void refresh() {
|
||||||
|
devices.clear();
|
||||||
|
auto list = BadgeSDR::list();
|
||||||
|
for (const auto& info : list) {
|
||||||
|
// Format device name
|
||||||
|
std::string devName = "BadgeSDR ";
|
||||||
|
devName += " [";
|
||||||
|
devName += info.serialNumber;
|
||||||
|
devName += ']';
|
||||||
|
|
||||||
|
// Save device
|
||||||
|
devices.define(info.serialNumber, devName, info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void select(const std::string& serial) {
|
||||||
|
// If there are no devices, give up
|
||||||
|
if (devices.empty()) {
|
||||||
|
selectedSerial.clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the serial was not found, select the first available serial
|
||||||
|
if (!devices.keyExists(serial)) {
|
||||||
|
select(devices.key(0));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save serial number
|
||||||
|
selectedSerial = serial;
|
||||||
|
selectedDev = devices.value(devices.keyId(serial));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void menuSelected(void* ctx) {
|
||||||
|
BadgeSDRSourceModule* _this = (BadgeSDRSourceModule*)ctx;
|
||||||
|
core::setInputSampleRate(_this->sampleRate);
|
||||||
|
flog::info("BadgeSDRSourceModule '{0}': Menu Select!", _this->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void menuDeselected(void* ctx) {
|
||||||
|
BadgeSDRSourceModule* _this = (BadgeSDRSourceModule*)ctx;
|
||||||
|
flog::info("BadgeSDRSourceModule '{0}': Menu Deselect!", _this->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void start(void* ctx) {
|
||||||
|
BadgeSDRSourceModule* _this = (BadgeSDRSourceModule*)ctx;
|
||||||
|
if (_this->running) { return; }
|
||||||
|
|
||||||
|
// Open the device
|
||||||
|
_this->openDev = BadgeSDR::open(_this->selectedDev);
|
||||||
|
|
||||||
|
// Configure the device
|
||||||
|
_this->openDev->setFrequency(_this->freq);
|
||||||
|
_this->openDev->setLNAGain(_this->lnaGain);
|
||||||
|
_this->openDev->setMixerGain(_this->mixerGain);
|
||||||
|
_this->openDev->setVGAGain(_this->vgaGain);
|
||||||
|
|
||||||
|
// Start DSP
|
||||||
|
_this->dcBlock.start();
|
||||||
|
_this->ddc.start();
|
||||||
|
|
||||||
|
// Start device
|
||||||
|
_this->openDev->start(callback, _this, 500000/200);
|
||||||
|
|
||||||
|
_this->running = true;
|
||||||
|
flog::info("BadgeSDRSourceModule '{0}': Start!", _this->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void stop(void* ctx) {
|
||||||
|
BadgeSDRSourceModule* _this = (BadgeSDRSourceModule*)ctx;
|
||||||
|
if (!_this->running) { return; }
|
||||||
|
_this->running = false;
|
||||||
|
|
||||||
|
// Stop worker
|
||||||
|
_this->openDev->stop();
|
||||||
|
|
||||||
|
// Stop DSP
|
||||||
|
_this->dcBlock.stop();
|
||||||
|
_this->ddc.stop();
|
||||||
|
|
||||||
|
// Close device
|
||||||
|
_this->openDev.reset();
|
||||||
|
|
||||||
|
flog::info("BadgeSDRSourceModule '{0}': Stop!", _this->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tune(double freq, void* ctx) {
|
||||||
|
BadgeSDRSourceModule* _this = (BadgeSDRSourceModule*)ctx;
|
||||||
|
if (_this->running) {
|
||||||
|
_this->openDev->setFrequency(freq);
|
||||||
|
}
|
||||||
|
_this->freq = freq;
|
||||||
|
flog::info("BadgeSDRSourceModule '{0}': Tune: {1}!", _this->name, freq);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void menuHandler(void* ctx) {
|
||||||
|
BadgeSDRSourceModule* _this = (BadgeSDRSourceModule*)ctx;
|
||||||
|
|
||||||
|
if (_this->running) { SmGui::BeginDisabled(); }
|
||||||
|
|
||||||
|
SmGui::FillWidth();
|
||||||
|
SmGui::ForceSync();
|
||||||
|
if (SmGui::Combo(CONCAT("##_badgesdr_dev_sel_", _this->name), &_this->devId, _this->devices.txt)) {
|
||||||
|
_this->select(_this->devices.key(_this->devId));
|
||||||
|
core::setInputSampleRate(_this->sampleRate);
|
||||||
|
// TODO: Save
|
||||||
|
}
|
||||||
|
|
||||||
|
SmGui::FillWidth();
|
||||||
|
SmGui::ForceSync();
|
||||||
|
if (SmGui::Button(CONCAT("Refresh##_badgesdr_refr_", _this->name))) {
|
||||||
|
_this->refresh();
|
||||||
|
_this->select(_this->selectedSerial);
|
||||||
|
core::setInputSampleRate(_this->sampleRate);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_this->running) { SmGui::EndDisabled(); }
|
||||||
|
|
||||||
|
SmGui::LeftLabel("LNA Gain");
|
||||||
|
SmGui::FillWidth();
|
||||||
|
if (SmGui::SliderInt(CONCAT("##_badgesdr_lna_gain_", _this->name), &_this->lnaGain, 0, 15)) {
|
||||||
|
if (_this->running) {
|
||||||
|
_this->openDev->setLNAGain(_this->lnaGain);
|
||||||
|
}
|
||||||
|
// TODO: Save
|
||||||
|
}
|
||||||
|
|
||||||
|
SmGui::LeftLabel("Mixer Gain");
|
||||||
|
SmGui::FillWidth();
|
||||||
|
if (SmGui::SliderInt(CONCAT("##_badgesdr_mixer_gain_", _this->name), &_this->mixerGain, 0, 15)) {
|
||||||
|
if (_this->running) {
|
||||||
|
_this->openDev->setMixerGain(_this->mixerGain);
|
||||||
|
}
|
||||||
|
// TODO: Save
|
||||||
|
}
|
||||||
|
|
||||||
|
SmGui::LeftLabel("VGA Gain");
|
||||||
|
SmGui::FillWidth();
|
||||||
|
if (SmGui::SliderInt(CONCAT("##_badgesdr_vga_gain_", _this->name), &_this->vgaGain, 0, 15)) {
|
||||||
|
if (_this->running) {
|
||||||
|
_this->openDev->setVGAGain(_this->vgaGain);
|
||||||
|
}
|
||||||
|
// TODO: Save
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void callback(const uint8_t* samples, int count, void* ctx) {
|
||||||
|
BadgeSDRSourceModule* _this = (BadgeSDRSourceModule*)ctx;
|
||||||
|
|
||||||
|
// Convert samples to float
|
||||||
|
dsp::complex_t* out = _this->input.writeBuf;
|
||||||
|
int min = 255, max = 0;
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
if (samples[i] < min) { min = samples[i]; }
|
||||||
|
if (samples[i] > max) { max = samples[i]; }
|
||||||
|
|
||||||
|
out[i].re = ((float)samples[i] - 127.5f) * (1.0f/127.0f);
|
||||||
|
out[i].im = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send out samples
|
||||||
|
_this->input.swap(count);
|
||||||
|
|
||||||
|
flog::debug("Amplitudes: {} -> {}", min, max);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string name;
|
||||||
|
bool enabled = true;
|
||||||
|
double sampleRate;
|
||||||
|
SourceManager::SourceHandler handler;
|
||||||
|
bool running = false;
|
||||||
|
double freq;
|
||||||
|
|
||||||
|
OptionList<std::string, BadgeSDR::DeviceInfo> devices;
|
||||||
|
|
||||||
|
int devId = 0;
|
||||||
|
int lnaGain = 0;
|
||||||
|
int mixerGain = 0;
|
||||||
|
int vgaGain = 0;
|
||||||
|
std::string selectedSerial;
|
||||||
|
BadgeSDR::DeviceInfo selectedDev;
|
||||||
|
std::shared_ptr<BadgeSDR::Device> openDev;
|
||||||
|
|
||||||
|
dsp::stream<dsp::complex_t> input;
|
||||||
|
dsp::correction::DCBlocker<dsp::complex_t> dcBlock;
|
||||||
|
dsp::channel::RxVFO ddc;
|
||||||
|
};
|
||||||
|
|
||||||
|
MOD_EXPORT void _INIT_() {
|
||||||
|
// Nothing here
|
||||||
|
}
|
||||||
|
|
||||||
|
MOD_EXPORT ModuleManager::Instance* _CREATE_INSTANCE_(std::string name) {
|
||||||
|
return new BadgeSDRSourceModule(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
MOD_EXPORT void _DELETE_INSTANCE_(void* instance) {
|
||||||
|
delete (BadgeSDRSourceModule*)instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
MOD_EXPORT void _END_() {
|
||||||
|
// Nothing here
|
||||||
|
}
|
||||||
622
source_modules/badgesdr_source/src/r820t.cpp
Normal file
622
source_modules/badgesdr_source/src/r820t.cpp
Normal file
@@ -0,0 +1,622 @@
|
|||||||
|
/*
|
||||||
|
* Rafael Micro R820T driver for AIRSPY
|
||||||
|
*
|
||||||
|
* Copyright 2013 Youssef Touil <youssef@airspy.com>
|
||||||
|
* Copyright 2014-2016 Benjamin Vernoux <bvernoux@airspy.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "r820t.h"
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
static int r820t_read_cache_reg(r820t_priv_t *priv, int reg);
|
||||||
|
|
||||||
|
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||||
|
|
||||||
|
/* Tuner frequency ranges */
|
||||||
|
struct r820t_freq_range
|
||||||
|
{
|
||||||
|
uint8_t open_d;
|
||||||
|
uint8_t rf_mux_ploy;
|
||||||
|
uint8_t tf_c;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define R820T_READ_MAX_DATA 32
|
||||||
|
#define R820T_INIT_NB_REGS (32-5)
|
||||||
|
uint8_t r820t_read_data[R820T_READ_MAX_DATA]; /* Buffer for data read from I2C */
|
||||||
|
uint8_t r820t_state_standby = 1; /* 1=standby/power off 0=r820t initialized/power on */
|
||||||
|
|
||||||
|
/* Tuner frequency ranges
|
||||||
|
"Copyright (C) 2013 Mauro Carvalho Chehab"
|
||||||
|
https://stuff.mit.edu/afs/sipb/contrib/linux/drivers/media/tuners/r820t.c
|
||||||
|
part of freq_ranges()
|
||||||
|
*/
|
||||||
|
const struct r820t_freq_range freq_ranges[] =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
/* 0 MHz */
|
||||||
|
/* .open_d = */ 0x08, /* low */
|
||||||
|
/* .rf_mux_ploy = */ 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
|
||||||
|
/* .tf_c = */ 0xdf, /* R27[7:0] band2,band0 */
|
||||||
|
}, {
|
||||||
|
/* 50 MHz */
|
||||||
|
/* .open_d = */ 0x08, /* low */
|
||||||
|
/* .rf_mux_ploy = */ 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
|
||||||
|
/* .tf_c = */ 0xbe, /* R27[7:0] band4,band1 */
|
||||||
|
}, {
|
||||||
|
/* 55 MHz */
|
||||||
|
/* .open_d = */ 0x08, /* low */
|
||||||
|
/* .rf_mux_ploy = */ 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
|
||||||
|
/* .tf_c = */ 0x8b, /* R27[7:0] band7,band4 */
|
||||||
|
}, {
|
||||||
|
/* 60 MHz */
|
||||||
|
/* .open_d = */ 0x08, /* low */
|
||||||
|
/* .rf_mux_ploy = */ 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
|
||||||
|
/* .tf_c = */ 0x7b, /* R27[7:0] band8,band4 */
|
||||||
|
}, {
|
||||||
|
/* 65 MHz */
|
||||||
|
/* .open_d = */ 0x08, /* low */
|
||||||
|
/* .rf_mux_ploy = */ 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
|
||||||
|
/* .tf_c = */ 0x69, /* R27[7:0] band9,band6 */
|
||||||
|
}, {
|
||||||
|
/* 70 MHz */
|
||||||
|
/* .open_d = */ 0x08, /* low */
|
||||||
|
/* .rf_mux_ploy = */ 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
|
||||||
|
/* .tf_c = */ 0x58, /* R27[7:0] band10,band7 */
|
||||||
|
}, {
|
||||||
|
/* 75 MHz */
|
||||||
|
/* .open_d = */ 0x00, /* high */
|
||||||
|
/* .rf_mux_ploy = */ 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
|
||||||
|
/* .tf_c = */ 0x44, /* R27[7:0] band11,band11 */
|
||||||
|
}, {
|
||||||
|
/* 80 MHz */
|
||||||
|
/* .open_d = */ 0x00, /* high */
|
||||||
|
/* .rf_mux_ploy = */ 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
|
||||||
|
/* .tf_c = */ 0x44, /* R27[7:0] band11,band11 */
|
||||||
|
}, {
|
||||||
|
/* 90 MHz */
|
||||||
|
/* .open_d = */ 0x00, /* high */
|
||||||
|
/* .rf_mux_ploy = */ 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
|
||||||
|
/* .tf_c = */ 0x34, /* R27[7:0] band12,band11 */
|
||||||
|
}, {
|
||||||
|
/* 100 MHz */
|
||||||
|
/* .open_d = */ 0x00, /* high */
|
||||||
|
/* .rf_mux_ploy = */ 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
|
||||||
|
/* .tf_c = */ 0x34, /* R27[7:0] band12,band11 */
|
||||||
|
}, {
|
||||||
|
/* 110 MHz */
|
||||||
|
/* .open_d = */ 0x00, /* high */
|
||||||
|
/* .rf_mux_ploy = */ 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
|
||||||
|
/* .tf_c = */ 0x24, /* R27[7:0] band13,band11 */
|
||||||
|
}, {
|
||||||
|
/* 120 MHz */
|
||||||
|
/* .open_d = */ 0x00, /* high */
|
||||||
|
/* .rf_mux_ploy = */ 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
|
||||||
|
/* .tf_c = */ 0x24, /* R27[7:0] band13,band11 */
|
||||||
|
}, {
|
||||||
|
/* 140 MHz */
|
||||||
|
/* .open_d = */ 0x00, /* high */
|
||||||
|
/* .rf_mux_ploy = */ 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
|
||||||
|
/* .tf_c = */ 0x14, /* R27[7:0] band14,band11 */
|
||||||
|
}, {
|
||||||
|
/* 180 MHz */
|
||||||
|
/* .open_d = */ 0x00, /* high */
|
||||||
|
/* .rf_mux_ploy = */ 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
|
||||||
|
/* .tf_c = */ 0x13, /* R27[7:0] band14,band12 */
|
||||||
|
}, {
|
||||||
|
/* 220 MHz */
|
||||||
|
/* .open_d = */ 0x00, /* high */
|
||||||
|
/* .rf_mux_ploy = */ 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
|
||||||
|
/* .tf_c = */ 0x13, /* R27[7:0] band14,band12 */
|
||||||
|
}, {
|
||||||
|
/* 250 MHz */
|
||||||
|
/* .open_d = */ 0x00, /* high */
|
||||||
|
/* .rf_mux_ploy = */ 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
|
||||||
|
/* .tf_c = */ 0x11, /* R27[7:0] highest,highest */
|
||||||
|
}, {
|
||||||
|
/* 280 MHz */
|
||||||
|
/* .open_d = */ 0x00, /* high */
|
||||||
|
/* .rf_mux_ploy = */ 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
|
||||||
|
/* .tf_c = */ 0x00, /* R27[7:0] highest,highest */
|
||||||
|
}, {
|
||||||
|
/* 310 MHz */
|
||||||
|
/* .open_d = */ 0x00, /* high */
|
||||||
|
/* .rf_mux_ploy = */ 0x41, /* R26[7:6]=1 (bypass) R26[1:0]=1 (middle) */
|
||||||
|
/* .tf_c = */ 0x00, /* R27[7:0] highest,highest */
|
||||||
|
}, {
|
||||||
|
/* 450 MHz */
|
||||||
|
/* .open_d = */ 0x00, /* high */
|
||||||
|
/* .rf_mux_ploy = */ 0x41, /* R26[7:6]=1 (bypass) R26[1:0]=1 (middle) */
|
||||||
|
/* .tf_c = */ 0x00, /* R27[7:0] highest,highest */
|
||||||
|
}, {
|
||||||
|
/* 588 MHz */
|
||||||
|
/* .open_d = */ 0x00, /* high */
|
||||||
|
/* .rf_mux_ploy = */ 0x40, /* R26[7:6]=1 (bypass) R26[1:0]=0 (highest) */
|
||||||
|
/* .tf_c = */ 0x00, /* R27[7:0] highest,highest */
|
||||||
|
}, {
|
||||||
|
/* 650 MHz */
|
||||||
|
/* .open_d = */ 0x00, /* high */
|
||||||
|
/* .rf_mux_ploy = */ 0x40, /* R26[7:6]=1 (bypass) R26[1:0]=0 (highest) */
|
||||||
|
/* .tf_c = */ 0x00, /* R27[7:0] highest,highest */
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#define FREQ_TO_IDX_SIZE (600)
|
||||||
|
const uint8_t freq_to_idx[FREQ_TO_IDX_SIZE]=
|
||||||
|
{
|
||||||
|
/* 50 */ 1,/* 51 */ 1,/* 52 */ 1,/* 53 */ 1,/* 54 */ 1,
|
||||||
|
/* 55 */ 2,/* 56 */ 2,/* 57 */ 2,/* 58 */ 2,/* 59 */ 2,
|
||||||
|
/* 60 */ 3,/* 61 */ 3,/* 62 */ 3,/* 63 */ 3,/* 64 */ 3,
|
||||||
|
/* 65 */ 4,/* 66 */ 4,/* 67 */ 4,/* 68 */ 4,/* 69 */ 4,
|
||||||
|
/* 70 */ 5,/* 71 */ 5,/* 72 */ 5,/* 73 */ 5,/* 74 */ 5,
|
||||||
|
/* 75 */ 6,/* 76 */ 6,/* 77 */ 6,/* 78 */ 6,/* 79 */ 6,
|
||||||
|
/* 80 */ 7,/* 81 */ 7,/* 82 */ 7,/* 83 */ 7,/* 84 */ 7,/* 85 */ 7,/* 86 */ 7,/* 87 */ 7,/* 88 */ 7,/* 89 */ 7,
|
||||||
|
/* 90 */ 8,/* 91 */ 8,/* 92 */ 8,/* 93 */ 8,/* 94 */ 8,/* 95 */ 8,/* 96 */ 8,/* 97 */ 8,/* 98 */ 8,/* 99 */ 8,
|
||||||
|
/* 100 */ 9,/* 101 */ 9,/* 102 */ 9,/* 103 */ 9,/* 104 */ 9,/* 105 */ 9,/* 106 */ 9,/* 107 */ 9,/* 108 */ 9,/* 109 */ 9,
|
||||||
|
/* 110 */ 10,/* 111 */ 10,/* 112 */ 10,/* 113 */ 10,/* 114 */ 10,/* 115 */ 10,/* 116 */ 10,/* 117 */ 10,/* 118 */ 10,/* 119 */ 10,
|
||||||
|
/* 120 */ 11,/* 121 */ 11,/* 122 */ 11,/* 123 */ 11,/* 124 */ 11,/* 125 */ 11,/* 126 */ 11,/* 127 */ 11,/* 128 */ 11,/* 129 */ 11,
|
||||||
|
/* 130 */ 11,/* 131 */ 11,/* 132 */ 11,/* 133 */ 11,/* 134 */ 11,/* 135 */ 11,/* 136 */ 11,/* 137 */ 11,/* 138 */ 11,/* 139 */ 11,
|
||||||
|
/* 140 */ 12,/* 141 */ 12,/* 142 */ 12,/* 143 */ 12,/* 144 */ 12,/* 145 */ 12,/* 146 */ 12,/* 147 */ 12,/* 148 */ 12,/* 149 */ 12,
|
||||||
|
/* 150 */ 12,/* 151 */ 12,/* 152 */ 12,/* 153 */ 12,/* 154 */ 12,/* 155 */ 12,/* 156 */ 12,/* 157 */ 12,/* 158 */ 12,/* 159 */ 12,
|
||||||
|
/* 160 */ 12,/* 161 */ 12,/* 162 */ 12,/* 163 */ 12,/* 164 */ 12,/* 165 */ 12,/* 166 */ 12,/* 167 */ 12,/* 168 */ 12,/* 169 */ 12,
|
||||||
|
/* 170 */ 12,/* 171 */ 12,/* 172 */ 12,/* 173 */ 12,/* 174 */ 12,/* 175 */ 12,/* 176 */ 12,/* 177 */ 12,/* 178 */ 12,/* 179 */ 12,
|
||||||
|
/* 180 */ 13,/* 181 */ 13,/* 182 */ 13,/* 183 */ 13,/* 184 */ 13,/* 185 */ 13,/* 186 */ 13,/* 187 */ 13,/* 188 */ 13,/* 189 */ 13,
|
||||||
|
/* 190 */ 13,/* 191 */ 13,/* 192 */ 13,/* 193 */ 13,/* 194 */ 13,/* 195 */ 13,/* 196 */ 13,/* 197 */ 13,/* 198 */ 13,/* 199 */ 13,
|
||||||
|
/* 200 */ 13,/* 201 */ 13,/* 202 */ 13,/* 203 */ 13,/* 204 */ 13,/* 205 */ 13,/* 206 */ 13,/* 207 */ 13,/* 208 */ 13,/* 209 */ 13,
|
||||||
|
/* 210 */ 13,/* 211 */ 13,/* 212 */ 13,/* 213 */ 13,/* 214 */ 13,/* 215 */ 13,/* 216 */ 13,/* 217 */ 13,/* 218 */ 13,/* 219 */ 13,
|
||||||
|
/* 220 */ 14,/* 221 */ 14,/* 222 */ 14,/* 223 */ 14,/* 224 */ 14,/* 225 */ 14,/* 226 */ 14,/* 227 */ 14,/* 228 */ 14,/* 229 */ 14,
|
||||||
|
/* 230 */ 14,/* 231 */ 14,/* 232 */ 14,/* 233 */ 14,/* 234 */ 14,/* 235 */ 14,/* 236 */ 14,/* 237 */ 14,/* 238 */ 14,/* 239 */ 14,
|
||||||
|
/* 240 */ 14,/* 241 */ 14,/* 242 */ 14,/* 243 */ 14,/* 244 */ 14,/* 245 */ 14,/* 246 */ 14,/* 247 */ 14,/* 248 */ 14,/* 249 */ 14,
|
||||||
|
/* 250 */ 15,/* 251 */ 15,/* 252 */ 15,/* 253 */ 15,/* 254 */ 15,/* 255 */ 15,/* 256 */ 15,/* 257 */ 15,/* 258 */ 15,/* 259 */ 15,
|
||||||
|
/* 260 */ 15,/* 261 */ 15,/* 262 */ 15,/* 263 */ 15,/* 264 */ 15,/* 265 */ 15,/* 266 */ 15,/* 267 */ 15,/* 268 */ 15,/* 269 */ 15,
|
||||||
|
/* 270 */ 15,/* 271 */ 15,/* 272 */ 15,/* 273 */ 15,/* 274 */ 15,/* 275 */ 15,/* 276 */ 15,/* 277 */ 15,/* 278 */ 15,/* 279 */ 15,
|
||||||
|
/* 280 */ 16,/* 281 */ 16,/* 282 */ 16,/* 283 */ 16,/* 284 */ 16,/* 285 */ 16,/* 286 */ 16,/* 287 */ 16,/* 288 */ 16,/* 289 */ 16,
|
||||||
|
/* 290 */ 16,/* 291 */ 16,/* 292 */ 16,/* 293 */ 16,/* 294 */ 16,/* 295 */ 16,/* 296 */ 16,/* 297 */ 16,/* 298 */ 16,/* 299 */ 16,
|
||||||
|
/* 300 */ 16,/* 301 */ 16,/* 302 */ 16,/* 303 */ 16,/* 304 */ 16,/* 305 */ 16,/* 306 */ 16,/* 307 */ 16,/* 308 */ 16,/* 309 */ 16,
|
||||||
|
/* 310 */ 17,/* 311 */ 17,/* 312 */ 17,/* 313 */ 17,/* 314 */ 17,/* 315 */ 17,/* 316 */ 17,/* 317 */ 17,/* 318 */ 17,/* 319 */ 17,
|
||||||
|
/* 320 */ 17,/* 321 */ 17,/* 322 */ 17,/* 323 */ 17,/* 324 */ 17,/* 325 */ 17,/* 326 */ 17,/* 327 */ 17,/* 328 */ 17,/* 329 */ 17,
|
||||||
|
/* 330 */ 17,/* 331 */ 17,/* 332 */ 17,/* 333 */ 17,/* 334 */ 17,/* 335 */ 17,/* 336 */ 17,/* 337 */ 17,/* 338 */ 17,/* 339 */ 17,
|
||||||
|
/* 340 */ 17,/* 341 */ 17,/* 342 */ 17,/* 343 */ 17,/* 344 */ 17,/* 345 */ 17,/* 346 */ 17,/* 347 */ 17,/* 348 */ 17,/* 349 */ 17,
|
||||||
|
/* 350 */ 17,/* 351 */ 17,/* 352 */ 17,/* 353 */ 17,/* 354 */ 17,/* 355 */ 17,/* 356 */ 17,/* 357 */ 17,/* 358 */ 17,/* 359 */ 17,
|
||||||
|
/* 360 */ 17,/* 361 */ 17,/* 362 */ 17,/* 363 */ 17,/* 364 */ 17,/* 365 */ 17,/* 366 */ 17,/* 367 */ 17,/* 368 */ 17,/* 369 */ 17,
|
||||||
|
/* 370 */ 17,/* 371 */ 17,/* 372 */ 17,/* 373 */ 17,/* 374 */ 17,/* 375 */ 17,/* 376 */ 17,/* 377 */ 17,/* 378 */ 17,/* 379 */ 17,
|
||||||
|
/* 380 */ 17,/* 381 */ 17,/* 382 */ 17,/* 383 */ 17,/* 384 */ 17,/* 385 */ 17,/* 386 */ 17,/* 387 */ 17,/* 388 */ 17,/* 389 */ 17,
|
||||||
|
/* 390 */ 17,/* 391 */ 17,/* 392 */ 17,/* 393 */ 17,/* 394 */ 17,/* 395 */ 17,/* 396 */ 17,/* 397 */ 17,/* 398 */ 17,/* 399 */ 17,
|
||||||
|
/* 400 */ 17,/* 401 */ 17,/* 402 */ 17,/* 403 */ 17,/* 404 */ 17,/* 405 */ 17,/* 406 */ 17,/* 407 */ 17,/* 408 */ 17,/* 409 */ 17,
|
||||||
|
/* 410 */ 17,/* 411 */ 17,/* 412 */ 17,/* 413 */ 17,/* 414 */ 17,/* 415 */ 17,/* 416 */ 17,/* 417 */ 17,/* 418 */ 17,/* 419 */ 17,
|
||||||
|
/* 420 */ 17,/* 421 */ 17,/* 422 */ 17,/* 423 */ 17,/* 424 */ 17,/* 425 */ 17,/* 426 */ 17,/* 427 */ 17,/* 428 */ 17,/* 429 */ 17,
|
||||||
|
/* 430 */ 17,/* 431 */ 17,/* 432 */ 17,/* 433 */ 17,/* 434 */ 17,/* 435 */ 17,/* 436 */ 17,/* 437 */ 17,/* 438 */ 17,/* 439 */ 17,
|
||||||
|
/* 440 */ 17,/* 441 */ 17,/* 442 */ 17,/* 443 */ 17,/* 444 */ 17,/* 445 */ 17,/* 446 */ 17,/* 447 */ 17,/* 448 */ 17,/* 449 */ 17,
|
||||||
|
/* 450 */ 18,/* 451 */ 18,/* 452 */ 18,/* 453 */ 18,/* 454 */ 18,/* 455 */ 18,/* 456 */ 18,/* 457 */ 18,/* 458 */ 18,/* 459 */ 18,
|
||||||
|
/* 460 */ 18,/* 461 */ 18,/* 462 */ 18,/* 463 */ 18,/* 464 */ 18,/* 465 */ 18,/* 466 */ 18,/* 467 */ 18,/* 468 */ 18,/* 469 */ 18,
|
||||||
|
/* 470 */ 18,/* 471 */ 18,/* 472 */ 18,/* 473 */ 18,/* 474 */ 18,/* 475 */ 18,/* 476 */ 18,/* 477 */ 18,/* 478 */ 18,/* 479 */ 18,
|
||||||
|
/* 480 */ 18,/* 481 */ 18,/* 482 */ 18,/* 483 */ 18,/* 484 */ 18,/* 485 */ 18,/* 486 */ 18,/* 487 */ 18,/* 488 */ 18,/* 489 */ 18,
|
||||||
|
/* 490 */ 18,/* 491 */ 18,/* 492 */ 18,/* 493 */ 18,/* 494 */ 18,/* 495 */ 18,/* 496 */ 18,/* 497 */ 18,/* 498 */ 18,/* 499 */ 18,
|
||||||
|
/* 500 */ 18,/* 501 */ 18,/* 502 */ 18,/* 503 */ 18,/* 504 */ 18,/* 505 */ 18,/* 506 */ 18,/* 507 */ 18,/* 508 */ 18,/* 509 */ 18,
|
||||||
|
/* 510 */ 18,/* 511 */ 18,/* 512 */ 18,/* 513 */ 18,/* 514 */ 18,/* 515 */ 18,/* 516 */ 18,/* 517 */ 18,/* 518 */ 18,/* 519 */ 18,
|
||||||
|
/* 520 */ 18,/* 521 */ 18,/* 522 */ 18,/* 523 */ 18,/* 524 */ 18,/* 525 */ 18,/* 526 */ 18,/* 527 */ 18,/* 528 */ 18,/* 529 */ 18,
|
||||||
|
/* 530 */ 18,/* 531 */ 18,/* 532 */ 18,/* 533 */ 18,/* 534 */ 18,/* 535 */ 18,/* 536 */ 18,/* 537 */ 18,/* 538 */ 18,/* 539 */ 18,
|
||||||
|
/* 540 */ 18,/* 541 */ 18,/* 542 */ 18,/* 543 */ 18,/* 544 */ 18,/* 545 */ 18,/* 546 */ 18,/* 547 */ 18,/* 548 */ 18,/* 549 */ 18,
|
||||||
|
/* 550 */ 18,/* 551 */ 18,/* 552 */ 18,/* 553 */ 18,/* 554 */ 18,/* 555 */ 18,/* 556 */ 18,/* 557 */ 18,/* 558 */ 18,/* 559 */ 18,
|
||||||
|
/* 560 */ 18,/* 561 */ 18,/* 562 */ 18,/* 563 */ 18,/* 564 */ 18,/* 565 */ 18,/* 566 */ 18,/* 567 */ 18,/* 568 */ 18,/* 569 */ 18,
|
||||||
|
/* 570 */ 18,/* 571 */ 18,/* 572 */ 18,/* 573 */ 18,/* 574 */ 18,/* 575 */ 18,/* 576 */ 18,/* 577 */ 18,/* 578 */ 18,/* 579 */ 18,
|
||||||
|
/* 580 */ 18,/* 581 */ 18,/* 582 */ 18,/* 583 */ 18,/* 584 */ 18,/* 585 */ 18,/* 586 */ 18,/* 587 */ 18,
|
||||||
|
/* 588 */ 19,/* 589 */ 19,/* 590 */ 19,/* 591 */ 19,/* 592 */ 19,/* 593 */ 19,/* 594 */ 19,/* 595 */ 19,/* 596 */ 19,/* 597 */ 19,
|
||||||
|
/* 598 */ 19,/* 599 */ 19,/* 600 */ 19,/* 601 */ 19,/* 602 */ 19,/* 603 */ 19,/* 604 */ 19,/* 605 */ 19,/* 606 */ 19,/* 607 */ 19,
|
||||||
|
/* 608 */ 19,/* 609 */ 19,/* 610 */ 19,/* 611 */ 19,/* 612 */ 19,/* 613 */ 19,/* 614 */ 19,/* 615 */ 19,/* 616 */ 19,/* 617 */ 19,
|
||||||
|
/* 618 */ 19,/* 619 */ 19,/* 620 */ 19,/* 621 */ 19,/* 622 */ 19,/* 623 */ 19,/* 624 */ 19,/* 625 */ 19,/* 626 */ 19,/* 627 */ 19,
|
||||||
|
/* 628 */ 19,/* 629 */ 19,/* 630 */ 19,/* 631 */ 19,/* 632 */ 19,/* 633 */ 19,/* 634 */ 19,/* 635 */ 19,/* 636 */ 19,/* 637 */ 19,
|
||||||
|
/* 638 */ 19,/* 639 */ 19,/* 640 */ 19,/* 641 */ 19,/* 642 */ 19,/* 643 */ 19,/* 644 */ 19,/* 645 */ 19,/* 646 */ 19,/* 647 */ 19,
|
||||||
|
/* 648 */ 19,/* 649 */ 19
|
||||||
|
};
|
||||||
|
|
||||||
|
#define FREQ_50MHZ (50)
|
||||||
|
#define FREQ_TO_IDX_0_TO_49MHZ (0)
|
||||||
|
#define FREQ_TO_IDX_650_TO_1800MHZ (20)
|
||||||
|
|
||||||
|
int r820t_freq_get_idx(uint32_t freq_mhz)
|
||||||
|
{
|
||||||
|
uint32_t freq_mhz_fix;
|
||||||
|
|
||||||
|
if(freq_mhz < FREQ_50MHZ)
|
||||||
|
{
|
||||||
|
/* Frequency Less than 50MHz */
|
||||||
|
return FREQ_TO_IDX_0_TO_49MHZ;
|
||||||
|
}else
|
||||||
|
{
|
||||||
|
/* Frequency Between 50 to 649MHz use table */
|
||||||
|
/* Fix the frequency for the table */
|
||||||
|
freq_mhz_fix = freq_mhz - FREQ_50MHZ;
|
||||||
|
if(freq_mhz_fix < FREQ_TO_IDX_SIZE)
|
||||||
|
{
|
||||||
|
|
||||||
|
return freq_to_idx[freq_mhz_fix];
|
||||||
|
}else
|
||||||
|
{
|
||||||
|
/* Frequency Between 650 to 1800MHz */
|
||||||
|
return FREQ_TO_IDX_650_TO_1800MHZ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool r820t_is_power_enabled(void)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write regs 5 to 32 (R820T_INIT_NB_REGS values) using data parameter and write last reg to 0
|
||||||
|
*/
|
||||||
|
void airspy_r820t_write_init(r820t_priv_t *priv, const uint8_t* data)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < R820T_INIT_NB_REGS; i++) {
|
||||||
|
priv->write_reg(i+REG_SHADOW_START, data[i], priv->ctx);
|
||||||
|
}
|
||||||
|
priv->write_reg(0x1F, 0, priv->ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read from one or more contiguous registers. data[0] should be the first
|
||||||
|
* register number, one or more values follow.
|
||||||
|
*/
|
||||||
|
const uint8_t lut[16] = { 0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe,
|
||||||
|
0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf };
|
||||||
|
|
||||||
|
static uint8_t r82xx_bitrev(uint8_t byte)
|
||||||
|
{
|
||||||
|
return (lut[byte & 0xf] << 4) | lut[byte >> 4];
|
||||||
|
}
|
||||||
|
|
||||||
|
static int r820t_write_reg(r820t_priv_t *priv, uint8_t reg, uint8_t val)
|
||||||
|
{
|
||||||
|
if (r820t_read_cache_reg(priv, reg) == val)
|
||||||
|
return 0;
|
||||||
|
priv->write_reg(reg, val, priv->ctx);
|
||||||
|
priv->regs[reg - REG_SHADOW_START] = val;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int r820t_read_cache_reg(r820t_priv_t *priv, int reg)
|
||||||
|
{
|
||||||
|
reg -= REG_SHADOW_START;
|
||||||
|
|
||||||
|
if (reg >= 0 && reg < NUM_REGS)
|
||||||
|
return priv->regs[reg];
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int r820t_write_reg_mask(r820t_priv_t *priv, uint8_t reg, uint8_t val, uint8_t bit_mask)
|
||||||
|
{
|
||||||
|
int rc = r820t_read_cache_reg(priv, reg);
|
||||||
|
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
val = (rc & ~bit_mask) | (val & bit_mask);
|
||||||
|
|
||||||
|
return r820t_write_reg(priv, reg, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int r820t_read(r820t_priv_t *priv, uint8_t *val, int len)
|
||||||
|
{
|
||||||
|
/* reg not used and assumed to be always 0 because start from reg0 to reg0+len */
|
||||||
|
priv->read_reg(val, len, priv->ctx);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* r820t tuning logic
|
||||||
|
*/
|
||||||
|
#ifdef OPTIM_SET_MUX
|
||||||
|
int r820t_set_mux_freq_idx = -1; /* Default set to invalid value in order to force set_mux */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
"inspired by Mauro Carvalho Chehab set_mux technique"
|
||||||
|
https://stuff.mit.edu/afs/sipb/contrib/linux/drivers/media/tuners/r820t.c
|
||||||
|
part of r820t_set_mux() (set tracking filter)
|
||||||
|
*/
|
||||||
|
static int r820t_set_tf(r820t_priv_t *priv, uint32_t freq)
|
||||||
|
{
|
||||||
|
const struct r820t_freq_range *range;
|
||||||
|
int freq_idx;
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
/* Get the proper frequency range in MHz instead of Hz */
|
||||||
|
/* Fast divide freq by 1000000 */
|
||||||
|
freq = (uint32_t)((uint64_t)freq * 4295 >> 32);
|
||||||
|
|
||||||
|
freq_idx = r820t_freq_get_idx(freq);
|
||||||
|
range = &freq_ranges[freq_idx];
|
||||||
|
|
||||||
|
/* Only reconfigure mux freq if modified vs previous range */
|
||||||
|
#ifdef OPTIM_SET_MUX
|
||||||
|
if(freq_idx != r820t_set_mux_freq_idx)
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
/* Open Drain */
|
||||||
|
rc = r820t_write_reg_mask(priv, 0x17, range->open_d, 0x08);
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
/* RF_MUX,Polymux */
|
||||||
|
rc = r820t_write_reg_mask(priv, 0x1a, range->rf_mux_ploy, 0xc3);
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
/* TF BAND */
|
||||||
|
rc = r820t_write_reg(priv, 0x1b, range->tf_c);
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
/* XTAL CAP & Drive */
|
||||||
|
rc = r820t_write_reg_mask(priv, 0x10, 0x08, 0x0b);
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
rc = r820t_write_reg_mask(priv, 0x08, 0x00, 0x3f);
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
rc = r820t_write_reg_mask(priv, 0x09, 0x00, 0x3f);
|
||||||
|
#ifdef OPTIM_SET_MUX
|
||||||
|
}
|
||||||
|
r820t_set_mux_freq_idx = freq_idx;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int r820t_set_pll(r820t_priv_t *priv, uint32_t freq)
|
||||||
|
{
|
||||||
|
const uint32_t vco_min = 1770000000;
|
||||||
|
const uint32_t vco_max = 3900000000;
|
||||||
|
uint32_t ref = priv->xtal_freq >> 1;
|
||||||
|
|
||||||
|
int rc;
|
||||||
|
uint32_t div_num;
|
||||||
|
uint32_t vco;
|
||||||
|
uint32_t rem;
|
||||||
|
uint32_t mask;
|
||||||
|
uint16_t sdm;
|
||||||
|
uint8_t nint;
|
||||||
|
uint8_t ni;
|
||||||
|
uint8_t si;
|
||||||
|
uint8_t div_found;
|
||||||
|
|
||||||
|
/* Find a suitable divider */
|
||||||
|
div_found = 0;
|
||||||
|
for (div_num = 0; div_num <= 5; div_num++)
|
||||||
|
{
|
||||||
|
vco = freq << (div_num + 1);
|
||||||
|
if (vco >= vco_min && vco <= vco_max)
|
||||||
|
{
|
||||||
|
div_found = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!div_found)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
vco += ref >> 16;
|
||||||
|
ref <<= 8;
|
||||||
|
mask = 1 << 23;
|
||||||
|
rem = 0;
|
||||||
|
while (mask > 0 && vco > 0)
|
||||||
|
{
|
||||||
|
if (vco >= ref)
|
||||||
|
{
|
||||||
|
rem |= mask;
|
||||||
|
vco -= ref;
|
||||||
|
}
|
||||||
|
ref >>= 1;
|
||||||
|
mask >>= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
nint = rem >> 16;
|
||||||
|
sdm = rem & 0xffff;
|
||||||
|
|
||||||
|
nint -= 13;
|
||||||
|
ni = nint >> 2;
|
||||||
|
si = nint & 3;
|
||||||
|
|
||||||
|
/* Set the phase splitter */
|
||||||
|
rc = r820t_write_reg_mask(priv, 0x10, (uint8_t) (div_num << 5), 0xe0);
|
||||||
|
if(rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
/* Set the integer part of the PLL */
|
||||||
|
rc = r820t_write_reg(priv, 0x14, (uint8_t) (ni + (si << 6)));
|
||||||
|
if(rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
if (sdm == 0)
|
||||||
|
{
|
||||||
|
/* Disable SDM */
|
||||||
|
rc = r820t_write_reg_mask(priv, 0x12, 0x08, 0x08);
|
||||||
|
if(rc < 0)
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Write SDM */
|
||||||
|
rc = r820t_write_reg(priv, 0x15, (uint8_t)(sdm & 0xff));
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
rc = r820t_write_reg(priv, 0x16, (uint8_t)(sdm >> 8));
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
/* Enable SDM */
|
||||||
|
rc = r820t_write_reg_mask(priv, 0x12, 0x00, 0x08);
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int r820t_set_freq(r820t_priv_t *priv, uint32_t freq)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
uint32_t lo_freq = freq + priv->if_freq;
|
||||||
|
|
||||||
|
rc = r820t_set_tf(priv, freq);
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
rc = r820t_set_pll(priv, lo_freq);
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
priv->freq = freq;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int r820t_set_lna_gain(r820t_priv_t *priv, uint8_t gain_index)
|
||||||
|
{
|
||||||
|
return r820t_write_reg_mask(priv, 0x05, gain_index, 0x0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
int r820t_set_mixer_gain(r820t_priv_t *priv, uint8_t gain_index)
|
||||||
|
{
|
||||||
|
return r820t_write_reg_mask(priv, 0x07, gain_index, 0x0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
int r820t_set_vga_gain(r820t_priv_t *priv, uint8_t gain_index)
|
||||||
|
{
|
||||||
|
return r820t_write_reg_mask(priv, 0x0c, gain_index, 0x0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
int r820t_set_lna_agc(r820t_priv_t *priv, uint8_t value)
|
||||||
|
{
|
||||||
|
value = value != 0 ? 0x00 : 0x10;
|
||||||
|
return r820t_write_reg_mask(priv, 0x05, value, 0x10);
|
||||||
|
}
|
||||||
|
|
||||||
|
int r820t_set_mixer_agc(r820t_priv_t *priv, uint8_t value)
|
||||||
|
{
|
||||||
|
value = value != 0 ? 0x10 : 0x00;
|
||||||
|
return r820t_write_reg_mask(priv, 0x07, value, 0x10);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
"inspired by Mauro Carvalho Chehab calibration technique"
|
||||||
|
https://stuff.mit.edu/afs/sipb/contrib/linux/drivers/media/tuners/r820t.c
|
||||||
|
part of r820t_set_tv_standard()
|
||||||
|
*/
|
||||||
|
int r820t_calibrate(r820t_priv_t *priv)
|
||||||
|
{
|
||||||
|
int i, rc, cal_code;
|
||||||
|
uint8_t data[5];
|
||||||
|
|
||||||
|
for (i = 0; i < 5; i++)
|
||||||
|
{
|
||||||
|
/* Set filt_cap */
|
||||||
|
rc = r820t_write_reg_mask(priv, 0x0b, 0x08, 0x60);
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
/* set cali clk =on */
|
||||||
|
rc = r820t_write_reg_mask(priv, 0x0f, 0x04, 0x04);
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
/* X'tal cap 0pF for PLL */
|
||||||
|
rc = r820t_write_reg_mask(priv, 0x10, 0x00, 0x03);
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
rc = r820t_set_pll(priv, CALIBRATION_LO * 1000);
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
/* Start Trigger */
|
||||||
|
rc = r820t_write_reg_mask(priv, 0x0b, 0x10, 0x10);
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||||
|
|
||||||
|
/* Stop Trigger */
|
||||||
|
rc = r820t_write_reg_mask(priv, 0x0b, 0x00, 0x10);
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
/* set cali clk =off */
|
||||||
|
rc = r820t_write_reg_mask(priv, 0x0f, 0x00, 0x04);
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
/* Check if calibration worked */
|
||||||
|
rc = r820t_read(priv, data, sizeof(data));
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
cal_code = data[4] & 0x0f;
|
||||||
|
if (cal_code && cal_code != 0x0f)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int r820t_init(r820t_priv_t *priv, const uint32_t if_freq, r820t_write_reg_f write_reg, r820t_read_f read_reg, void* ctx)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
uint32_t saved_freq;
|
||||||
|
|
||||||
|
r820t_state_standby = 0;
|
||||||
|
priv->if_freq = if_freq;
|
||||||
|
priv->write_reg = write_reg;
|
||||||
|
priv->read_reg = read_reg;
|
||||||
|
priv->ctx = ctx;
|
||||||
|
/* Initialize registers */
|
||||||
|
airspy_r820t_write_init(priv, priv->regs);
|
||||||
|
|
||||||
|
r820t_set_freq(priv, priv->freq);
|
||||||
|
|
||||||
|
/* Calibrate the IF filter */
|
||||||
|
saved_freq = priv->freq;
|
||||||
|
rc = r820t_calibrate(priv);
|
||||||
|
priv->freq = saved_freq;
|
||||||
|
if (rc < 0)
|
||||||
|
{
|
||||||
|
saved_freq = priv->freq;
|
||||||
|
r820t_calibrate(priv);
|
||||||
|
priv->freq = saved_freq;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Restore freq as it has been modified by r820t_calibrate() */
|
||||||
|
rc = r820t_set_freq(priv, priv->freq);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void r820t_set_if_bandwidth(r820t_priv_t *priv, uint8_t bw)
|
||||||
|
{
|
||||||
|
const uint8_t modes[] = { 0xE0, 0x80, 0x60, 0x00 };
|
||||||
|
const uint8_t opt[] = { 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
|
||||||
|
uint8_t a = 0xB0 | opt[bw & 0x0F];
|
||||||
|
uint8_t b = 0x0F | modes[bw >> 4];
|
||||||
|
r820t_write_reg(priv, 0x0A, a);
|
||||||
|
r820t_write_reg(priv, 0x0B, b);
|
||||||
|
}
|
||||||
58
source_modules/badgesdr_source/src/r820t.h
Normal file
58
source_modules/badgesdr_source/src/r820t.h
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013-2016 Benjamin Vernoux <bvernoux@airspy.com>
|
||||||
|
*
|
||||||
|
* This file is part of AirSpy.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; see the file COPYING. If not, write to
|
||||||
|
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define REG_SHADOW_START 5
|
||||||
|
#define NUM_REGS 30
|
||||||
|
|
||||||
|
/* R820T Clock */
|
||||||
|
#define CALIBRATION_LO 88000
|
||||||
|
|
||||||
|
typedef void (*r820t_write_reg_f)(uint8_t reg, uint8_t value, void* ctx);
|
||||||
|
typedef void (*r820t_read_f)(uint8_t* data, int len, void* ctx);
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint32_t xtal_freq; /* XTAL_FREQ_HZ */
|
||||||
|
uint32_t freq;
|
||||||
|
uint32_t if_freq;
|
||||||
|
uint8_t regs[NUM_REGS];
|
||||||
|
uint16_t padding;
|
||||||
|
|
||||||
|
r820t_write_reg_f write_reg;
|
||||||
|
r820t_read_f read_reg;
|
||||||
|
void* ctx;
|
||||||
|
|
||||||
|
} r820t_priv_t;
|
||||||
|
|
||||||
|
void airspy_r820t_write_single(r820t_priv_t *priv, uint8_t reg, uint8_t val);
|
||||||
|
uint8_t airspy_r820t_read_single(r820t_priv_t *priv, uint8_t reg);
|
||||||
|
|
||||||
|
int r820t_init(r820t_priv_t *priv, const uint32_t if_freq, r820t_write_reg_f write_reg, r820t_read_f read_reg, void* ctx);
|
||||||
|
int r820t_set_freq(r820t_priv_t *priv, uint32_t freq);
|
||||||
|
int r820t_set_lna_gain(r820t_priv_t *priv, uint8_t gain_index);
|
||||||
|
int r820t_set_mixer_gain(r820t_priv_t *priv, uint8_t gain_index);
|
||||||
|
int r820t_set_vga_gain(r820t_priv_t *priv, uint8_t gain_index);
|
||||||
|
int r820t_set_lna_agc(r820t_priv_t *priv, uint8_t value);
|
||||||
|
int r820t_set_mixer_agc(r820t_priv_t *priv, uint8_t value);
|
||||||
|
void r820t_set_if_bandwidth(r820t_priv_t *priv, uint8_t bw);
|
||||||
@@ -10,7 +10,6 @@
|
|||||||
#include <libbladeRF.h>
|
#include <libbladeRF.h>
|
||||||
#include <gui/smgui.h>
|
#include <gui/smgui.h>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <utils/optionlist.h>
|
|
||||||
|
|
||||||
#define CONCAT(a, b) ((std::string(a) + b).c_str())
|
#define CONCAT(a, b) ((std::string(a) + b).c_str())
|
||||||
|
|
||||||
@@ -38,10 +37,6 @@ public:
|
|||||||
BladeRFSourceModule(std::string name) {
|
BladeRFSourceModule(std::string name) {
|
||||||
this->name = name;
|
this->name = name;
|
||||||
|
|
||||||
// Define clocks
|
|
||||||
clocks.define("onboard", "On-Board", CLOCK_SELECT_ONBOARD);
|
|
||||||
clocks.define("external", "External", CLOCK_SELECT_EXTERNAL);
|
|
||||||
|
|
||||||
sampleRate = 1000000.0;
|
sampleRate = 1000000.0;
|
||||||
|
|
||||||
handler.ctx = this;
|
handler.ctx = this;
|
||||||
@@ -272,15 +267,6 @@ public:
|
|||||||
}
|
}
|
||||||
config.release(true);
|
config.release(true);
|
||||||
|
|
||||||
// Load clock source
|
|
||||||
clkId = clocks.keyId("onboard");
|
|
||||||
if (config.conf["devices"][selectedSerial].contains("clock")) {
|
|
||||||
std::string clkStr = config.conf["devices"][selectedSerial]["clock"];
|
|
||||||
if (clocks.keyExists(clkStr)) {
|
|
||||||
clkId = clocks.keyId(clkStr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load gain mode
|
// Load gain mode
|
||||||
if (config.conf["devices"][selectedSerial].contains("gainMode")) {
|
if (config.conf["devices"][selectedSerial].contains("gainMode")) {
|
||||||
std::string gm = config.conf["devices"][selectedSerial]["gainMode"];
|
std::string gm = config.conf["devices"][selectedSerial]["gainMode"];
|
||||||
@@ -378,7 +364,6 @@ private:
|
|||||||
if (_this->bufferSize < 1024) { _this->bufferSize = 1024; }
|
if (_this->bufferSize < 1024) { _this->bufferSize = 1024; }
|
||||||
|
|
||||||
// Setup device parameters
|
// Setup device parameters
|
||||||
_this->setClockSource(_this->clocks[_this->clkId]);
|
|
||||||
bladerf_set_sample_rate(_this->openDev, BLADERF_CHANNEL_RX(_this->chanId), _this->sampleRate, NULL);
|
bladerf_set_sample_rate(_this->openDev, BLADERF_CHANNEL_RX(_this->chanId), _this->sampleRate, NULL);
|
||||||
bladerf_set_frequency(_this->openDev, BLADERF_CHANNEL_RX(_this->chanId), _this->freq);
|
bladerf_set_frequency(_this->openDev, BLADERF_CHANNEL_RX(_this->chanId), _this->freq);
|
||||||
bladerf_set_bandwidth(_this->openDev, BLADERF_CHANNEL_RX(_this->chanId), (_this->bwId == _this->bandwidths.size()) ? std::clamp<uint64_t>(_this->sampleRate, _this->bwRange->min, _this->bwRange->max) : _this->bandwidths[_this->bwId], NULL);
|
bladerf_set_bandwidth(_this->openDev, BLADERF_CHANNEL_RX(_this->chanId), (_this->bwId == _this->bandwidths.size()) ? std::clamp<uint64_t>(_this->sampleRate, _this->bwRange->min, _this->bwRange->max) : _this->bandwidths[_this->bwId], NULL);
|
||||||
@@ -501,19 +486,6 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SmGui::LeftLabel("Clock Source");
|
|
||||||
SmGui::FillWidth();
|
|
||||||
if (SmGui::Combo(CONCAT("##_balderf_clk_sel_", _this->name), &_this->clkId, _this->clocks.txt)) {
|
|
||||||
if (_this->running) {
|
|
||||||
_this->setClockSource(_this->clocks[_this->clkId]);
|
|
||||||
}
|
|
||||||
if (_this->selectedSerial != "") {
|
|
||||||
config.acquire();
|
|
||||||
config.conf["devices"][_this->selectedSerial]["clock"] = _this->clocks.key(_this->clkId);
|
|
||||||
config.release(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// General config BS
|
// General config BS
|
||||||
SmGui::LeftLabel("Gain control mode");
|
SmGui::LeftLabel("Gain control mode");
|
||||||
SmGui::FillWidth();
|
SmGui::FillWidth();
|
||||||
@@ -565,15 +537,6 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setClockSource(bladerf_clock_select clk) {
|
|
||||||
if (selectedBladeType == BLADERF_TYPE_V1) {
|
|
||||||
bladerf_set_smb_mode(openDev, (clk == CLOCK_SELECT_EXTERNAL) ? BLADERF_SMB_MODE_INPUT : BLADERF_SMB_MODE_DISABLED);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
bladerf_set_clock_select(openDev, clk);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void worker() {
|
void worker() {
|
||||||
int16_t* buffer = new int16_t[bufferSize * 2];
|
int16_t* buffer = new int16_t[bufferSize * 2];
|
||||||
bladerf_metadata meta;
|
bladerf_metadata meta;
|
||||||
@@ -602,7 +565,6 @@ private:
|
|||||||
int devId = 0;
|
int devId = 0;
|
||||||
int srId = 0;
|
int srId = 0;
|
||||||
int bwId = 0;
|
int bwId = 0;
|
||||||
int clkId = 0;
|
|
||||||
int chanId = 0;
|
int chanId = 0;
|
||||||
int gainMode = 0;
|
int gainMode = 0;
|
||||||
bool streamingEnabled = false;
|
bool streamingEnabled = false;
|
||||||
@@ -618,8 +580,8 @@ private:
|
|||||||
std::string sampleRatesTxt;
|
std::string sampleRatesTxt;
|
||||||
std::vector<uint64_t> bandwidths;
|
std::vector<uint64_t> bandwidths;
|
||||||
std::string bandwidthsTxt;
|
std::string bandwidthsTxt;
|
||||||
|
|
||||||
std::string channelNamesTxt;
|
std::string channelNamesTxt;
|
||||||
OptionList<std::string, bladerf_clock_select> clocks;
|
|
||||||
|
|
||||||
int bufferSize;
|
int bufferSize;
|
||||||
struct bladerf_stream* rxStream;
|
struct bladerf_stream* rxStream;
|
||||||
|
|||||||
@@ -1,28 +0,0 @@
|
|||||||
cmake_minimum_required(VERSION 3.13)
|
|
||||||
project(dragonlabs_source)
|
|
||||||
|
|
||||||
file(GLOB SRC "src/*.cpp")
|
|
||||||
|
|
||||||
include(${SDRPP_MODULE_CMAKE})
|
|
||||||
|
|
||||||
if (MSVC)
|
|
||||||
# Debugging only
|
|
||||||
find_package(PkgConfig REQUIRED)
|
|
||||||
pkg_check_modules(libusb REQUIRED IMPORTED_TARGET libusb-1.0)
|
|
||||||
target_link_libraries(dragonlabs_source PRIVATE PkgConfig::libusb)
|
|
||||||
target_include_directories(dragonlabs_source PRIVATE "C:/Users/ryzerth/Documents/DragonLabs/products/KrakenSlayer/host/src")
|
|
||||||
|
|
||||||
target_include_directories(dragonlabs_source PRIVATE "C:/Program Files/DragonLabs/CR/include")
|
|
||||||
target_link_directories(dragonlabs_source PRIVATE "C:/Program Files/DragonLabs/CR/lib")
|
|
||||||
target_link_libraries(dragonlabs_source PRIVATE dlcr)
|
|
||||||
elseif (ANDROID)
|
|
||||||
# Not supported yet...
|
|
||||||
else (MSVC)
|
|
||||||
find_package(PkgConfig)
|
|
||||||
|
|
||||||
pkg_check_modules(LIBDLCR REQUIRED libdlcr)
|
|
||||||
|
|
||||||
target_include_directories(dragonlabs_source PRIVATE ${LIBDLCR_INCLUDE_DIRS})
|
|
||||||
target_link_directories(dragonlabs_source PRIVATE ${LIBDLCR_LIBRARY_DIRS})
|
|
||||||
target_link_libraries(dragonlabs_source PRIVATE ${LIBDLCR_LIBRARIES})
|
|
||||||
endif ()
|
|
||||||
@@ -1,453 +0,0 @@
|
|||||||
#include <imgui.h>
|
|
||||||
#include <module.h>
|
|
||||||
#include <gui/gui.h>
|
|
||||||
#include <gui/smgui.h>
|
|
||||||
#include <signal_path/signal_path.h>
|
|
||||||
#include <core.h>
|
|
||||||
#include <utils/optionlist.h>
|
|
||||||
#include <fstream>
|
|
||||||
#include <dlcr.h>
|
|
||||||
|
|
||||||
#ifdef DRAGONLABS_SOURCE_ENABLE_DEBUG
|
|
||||||
#include <dlcr_internal.h>
|
|
||||||
#include <lmx2572.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
SDRPP_MOD_INFO{
|
|
||||||
/* Name: */ "dragonlabs_source",
|
|
||||||
/* Description: */ "Dragon Labs Source Module",
|
|
||||||
/* Author: */ "Ryzerth",
|
|
||||||
/* Version: */ 0, 1, 0,
|
|
||||||
/* Max instances */ -1
|
|
||||||
};
|
|
||||||
|
|
||||||
#define CONCAT(a, b) ((std::string(a) + b).c_str())
|
|
||||||
|
|
||||||
class DragonLabsSourceModule : public ModuleManager::Instance {
|
|
||||||
public:
|
|
||||||
DragonLabsSourceModule(std::string name) {
|
|
||||||
this->name = name;
|
|
||||||
|
|
||||||
// Load the register debugging values
|
|
||||||
strcpy(clkRegStr, "00");
|
|
||||||
strcpy(clkValStr, "--");
|
|
||||||
strcpy(synRegStr, "00");
|
|
||||||
strcpy(synValStr, "--");
|
|
||||||
strcpy(adcRegStr, "00");
|
|
||||||
strcpy(adcValStr, "--");
|
|
||||||
strcpy(tunRegStr, "00");
|
|
||||||
strcpy(tunValStr, "--");
|
|
||||||
|
|
||||||
// Define the clock sources
|
|
||||||
clockSources.define("internal", "Internal", DLCR_CLOCK_INTERNAL);
|
|
||||||
clockSources.define("external", "External", DLCR_CLOCK_EXTERNAL);
|
|
||||||
|
|
||||||
// Define the channels
|
|
||||||
channels.define("chan1", "Channel 1", 0);
|
|
||||||
channels.define("chan2", "Channel 2", 1);
|
|
||||||
channels.define("chan3", "Channel 3", 2);
|
|
||||||
channels.define("chan4", "Channel 4", 3);
|
|
||||||
channels.define("chan5", "Channel 5", 4);
|
|
||||||
channels.define("chan6", "Channel 6", 5);
|
|
||||||
channels.define("chan7", "Channel 7", 6);
|
|
||||||
channels.define("chan8", "Channel 8", 7);
|
|
||||||
|
|
||||||
// Hardcode the samplerate
|
|
||||||
sampleRate = 12.5e6;
|
|
||||||
|
|
||||||
// Fill out the source handler
|
|
||||||
handler.ctx = this;
|
|
||||||
handler.selectHandler = menuSelected;
|
|
||||||
handler.deselectHandler = menuDeselected;
|
|
||||||
handler.menuHandler = menuHandler;
|
|
||||||
handler.startHandler = start;
|
|
||||||
handler.stopHandler = stop;
|
|
||||||
handler.tuneHandler = tune;
|
|
||||||
handler.stream = &stream;
|
|
||||||
|
|
||||||
// Refresh devices
|
|
||||||
refresh();
|
|
||||||
|
|
||||||
// Select first (TODO: Select from config)
|
|
||||||
select("");
|
|
||||||
|
|
||||||
sigpath::sourceManager.registerSource("Dragon Labs", &handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
~DragonLabsSourceModule() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void postInit() {}
|
|
||||||
|
|
||||||
void enable() {
|
|
||||||
enabled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void disable() {
|
|
||||||
enabled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isEnabled() {
|
|
||||||
return enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void refresh() {
|
|
||||||
devices.clear();
|
|
||||||
|
|
||||||
// Get the list of devices
|
|
||||||
dlcr_info_t* list;
|
|
||||||
int count = dlcr_list_devices(&list);
|
|
||||||
if (count < 0) {
|
|
||||||
flog::error("Failed to list devices");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate the menu list
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
// Format device name
|
|
||||||
std::string devName = "CR8-1725 ";
|
|
||||||
devName += " [";
|
|
||||||
devName += list[i].serial;
|
|
||||||
devName += ']';
|
|
||||||
|
|
||||||
// Save device
|
|
||||||
devices.define(list[i].serial, devName, list[i].serial);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Free the device list
|
|
||||||
dlcr_free_device_list(list);
|
|
||||||
}
|
|
||||||
|
|
||||||
void select(const std::string& serial) {
|
|
||||||
// If there are no devices, give up
|
|
||||||
if (devices.empty()) {
|
|
||||||
selectedSerial.clear();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the serial was not found, select the first available serial
|
|
||||||
if (!devices.keyExists(serial)) {
|
|
||||||
select(devices.key(0));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save serial number
|
|
||||||
selectedSerial = serial;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void menuSelected(void* ctx) {
|
|
||||||
DragonLabsSourceModule* _this = (DragonLabsSourceModule*)ctx;
|
|
||||||
core::setInputSampleRate(_this->sampleRate);
|
|
||||||
flog::info("DragonLabsSourceModule '{0}': Menu Select!", _this->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void menuDeselected(void* ctx) {
|
|
||||||
DragonLabsSourceModule* _this = (DragonLabsSourceModule*)ctx;
|
|
||||||
flog::info("DragonLabsSourceModule '{0}': Menu Deselect!", _this->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::chrono::high_resolution_clock::time_point last;
|
|
||||||
|
|
||||||
static void start(void* ctx) {
|
|
||||||
DragonLabsSourceModule* _this = (DragonLabsSourceModule*)ctx;
|
|
||||||
if (_this->running) { return; }
|
|
||||||
|
|
||||||
// Open the device
|
|
||||||
int err = dlcr_open(&_this->openDev, _this->selectedSerial.c_str());
|
|
||||||
if (err) {
|
|
||||||
flog::error("Failed to open device '{}': {}", _this->selectedSerial, err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
flog::debug("Device open");
|
|
||||||
|
|
||||||
// Configure the device
|
|
||||||
dlcr_set_freq(_this->openDev, DLCR_CHAN_ALL, _this->freq, true);
|
|
||||||
dlcr_set_lna_gain(_this->openDev, DLCR_CHAN_ALL, _this->lnaGain);
|
|
||||||
dlcr_set_mixer_gain(_this->openDev, DLCR_CHAN_ALL, _this->mixerGain);
|
|
||||||
dlcr_set_vga_gain(_this->openDev, DLCR_CHAN_ALL, _this->vgaGain);
|
|
||||||
|
|
||||||
// Start device
|
|
||||||
dlcr_start(_this->openDev, 0/*TODO*/, callback, _this);
|
|
||||||
|
|
||||||
_this->running = true;
|
|
||||||
flog::info("DragonLabsSourceModule '{0}': Start!", _this->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void stop(void* ctx) {
|
|
||||||
DragonLabsSourceModule* _this = (DragonLabsSourceModule*)ctx;
|
|
||||||
if (!_this->running) { return; }
|
|
||||||
_this->running = false;
|
|
||||||
|
|
||||||
// Stop device
|
|
||||||
dlcr_stop(_this->openDev);
|
|
||||||
|
|
||||||
// Close device
|
|
||||||
dlcr_close(_this->openDev);
|
|
||||||
|
|
||||||
flog::info("DragonLabsSourceModule '{0}': Stop!", _this->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void tune(double freq, void* ctx) {
|
|
||||||
DragonLabsSourceModule* _this = (DragonLabsSourceModule*)ctx;
|
|
||||||
if (_this->running) {
|
|
||||||
dlcr_set_freq(_this->openDev, DLCR_CHAN_ALL, freq, _this->docal);
|
|
||||||
}
|
|
||||||
_this->calibrated = false;
|
|
||||||
_this->freq = freq;
|
|
||||||
flog::info("DragonLabsSourceModule '{0}': Tune: {1}!", _this->name, freq);
|
|
||||||
}
|
|
||||||
|
|
||||||
double lmxFreq = 100e6;
|
|
||||||
|
|
||||||
static void menuHandler(void* ctx) {
|
|
||||||
DragonLabsSourceModule* _this = (DragonLabsSourceModule*)ctx;
|
|
||||||
|
|
||||||
if (_this->running) { SmGui::BeginDisabled(); }
|
|
||||||
|
|
||||||
SmGui::FillWidth();
|
|
||||||
SmGui::ForceSync();
|
|
||||||
if (SmGui::Combo(CONCAT("##_dlcr_dev_sel_", _this->name), &_this->devId, _this->devices.txt)) {
|
|
||||||
_this->select(_this->devices.key(_this->devId));
|
|
||||||
core::setInputSampleRate(_this->sampleRate);
|
|
||||||
// TODO: Save
|
|
||||||
}
|
|
||||||
|
|
||||||
SmGui::FillWidth();
|
|
||||||
SmGui::ForceSync();
|
|
||||||
if (SmGui::Button(CONCAT("Refresh##_dlcr_refr_", _this->name))) {
|
|
||||||
_this->refresh();
|
|
||||||
_this->select(_this->selectedSerial);
|
|
||||||
core::setInputSampleRate(_this->sampleRate);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_this->running) { SmGui::EndDisabled(); }
|
|
||||||
|
|
||||||
SmGui::LeftLabel("Clock Source");
|
|
||||||
SmGui::FillWidth();
|
|
||||||
if (SmGui::Combo(CONCAT("##_dlcr_clock_", _this->name), &_this->clockSourceId, _this->clockSources.txt)) {
|
|
||||||
if (_this->running) {
|
|
||||||
dlcr_set_clock_source(_this->openDev, _this->clockSources[_this->clockSourceId]);
|
|
||||||
}
|
|
||||||
// TODO: Save
|
|
||||||
}
|
|
||||||
|
|
||||||
SmGui::LeftLabel("Channel");
|
|
||||||
SmGui::FillWidth();
|
|
||||||
SmGui::Combo(CONCAT("##_dlcr_chan_", _this->name), &_this->channelId, _this->channels.txt);
|
|
||||||
|
|
||||||
SmGui::LeftLabel("LNA Gain");
|
|
||||||
SmGui::FillWidth();
|
|
||||||
if (SmGui::SliderInt(CONCAT("##_dlcr_lna_gain_", _this->name), &_this->lnaGain, 0, 14)) {
|
|
||||||
if (_this->running) {
|
|
||||||
dlcr_set_lna_gain(_this->openDev, DLCR_CHAN_ALL, _this->lnaGain);
|
|
||||||
}
|
|
||||||
// TODO: Save
|
|
||||||
}
|
|
||||||
|
|
||||||
SmGui::LeftLabel("Mixer Gain");
|
|
||||||
SmGui::FillWidth();
|
|
||||||
if (SmGui::SliderInt(CONCAT("##_dlcr_mixer_gain_", _this->name), &_this->mixerGain, 0, 15)) {
|
|
||||||
if (_this->running) {
|
|
||||||
dlcr_set_mixer_gain(_this->openDev, DLCR_CHAN_ALL, _this->mixerGain);
|
|
||||||
}
|
|
||||||
// TODO: Save
|
|
||||||
}
|
|
||||||
|
|
||||||
SmGui::LeftLabel("VGA Gain");
|
|
||||||
SmGui::FillWidth();
|
|
||||||
if (SmGui::SliderInt(CONCAT("##_dlcr_vga_gain_", _this->name), &_this->vgaGain, 0, 15)) {
|
|
||||||
if (_this->running) {
|
|
||||||
dlcr_set_vga_gain(_this->openDev, DLCR_CHAN_ALL, _this->vgaGain);
|
|
||||||
}
|
|
||||||
// TODO: Save
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DRAGONLABS_SOURCE_ENABLE_DEBUG
|
|
||||||
SmGui::Checkbox(CONCAT("Debug##_dlcr_debug_", _this->name), &_this->debug);
|
|
||||||
|
|
||||||
if (_this->debug) {
|
|
||||||
ImGui::Separator();
|
|
||||||
|
|
||||||
SmGui::LeftLabel("Clockgen Reg");
|
|
||||||
SmGui::FillWidth();
|
|
||||||
SmGui::InputText(CONCAT("##_dlcr_clk_reg_", _this->name), _this->clkRegStr, 256);
|
|
||||||
SmGui::LeftLabel("Clockgen Value");
|
|
||||||
SmGui::FillWidth();
|
|
||||||
SmGui::InputText(CONCAT("##_dlcr_clk_val_", _this->name), _this->clkValStr, 256);
|
|
||||||
SmGui::FillWidth();
|
|
||||||
if (SmGui::Button(CONCAT("Read##_dlcr_clk_rd_", _this->name))) {
|
|
||||||
if (_this->running) {
|
|
||||||
uint8_t val;
|
|
||||||
dlcr_si5351c_read_reg(_this->openDev, std::stoi(_this->clkRegStr, NULL, 16), &val);
|
|
||||||
sprintf(_this->clkValStr, "%02X", val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SmGui::FillWidth();
|
|
||||||
if (SmGui::Button(CONCAT("Write##_dlcr_clk_wr_", _this->name))) {
|
|
||||||
if (_this->running) {
|
|
||||||
dlcr_si5351c_write_reg(_this->openDev, std::stoi(_this->clkRegStr, NULL, 16), std::stoi(_this->clkValStr, NULL, 16));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::Separator();
|
|
||||||
|
|
||||||
SmGui::LeftLabel("Synth Reg");
|
|
||||||
SmGui::FillWidth();
|
|
||||||
SmGui::InputText(CONCAT("##_dlcr_syn_reg_", _this->name), _this->synRegStr, 256);
|
|
||||||
SmGui::LeftLabel("Synth Value");
|
|
||||||
SmGui::FillWidth();
|
|
||||||
SmGui::InputText(CONCAT("##_dlcr_syn_val_", _this->name), _this->synValStr, 256);
|
|
||||||
SmGui::FillWidth();
|
|
||||||
if (SmGui::Button(CONCAT("Read##_dlcr_syn_rd_", _this->name))) {
|
|
||||||
if (_this->running) {
|
|
||||||
uint16_t val;
|
|
||||||
dlcr_lmx2572_read_reg(_this->openDev, std::stoi(_this->synRegStr, NULL, 16), &val);
|
|
||||||
sprintf(_this->synValStr, "%02X", val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SmGui::FillWidth();
|
|
||||||
if (SmGui::Button(CONCAT("Write##_dlcr_syn_wr_", _this->name))) {
|
|
||||||
if (_this->running) {
|
|
||||||
dlcr_lmx2572_write_reg(_this->openDev, std::stoi(_this->synRegStr, NULL, 16), std::stoi(_this->synValStr, NULL, 16));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::Separator();
|
|
||||||
|
|
||||||
SmGui::LeftLabel("ADC Reg");
|
|
||||||
SmGui::FillWidth();
|
|
||||||
SmGui::InputText(CONCAT("##_dlcr_adc_reg_", _this->name), _this->adcRegStr, 256);
|
|
||||||
SmGui::LeftLabel("ADC Value");
|
|
||||||
SmGui::FillWidth();
|
|
||||||
SmGui::InputText(CONCAT("##_dlcr_adc_val_", _this->name), _this->adcValStr, 256);
|
|
||||||
SmGui::FillWidth();
|
|
||||||
if (SmGui::Button(CONCAT("Read##_dlcr_adc_rd_", _this->name))) {
|
|
||||||
if (_this->running) {
|
|
||||||
uint8_t val;
|
|
||||||
dlcr_mcp37211_read_reg(_this->openDev, std::stoi(_this->adcRegStr, NULL, 16), &val);
|
|
||||||
sprintf(_this->adcValStr, "%02X", val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SmGui::FillWidth();
|
|
||||||
if (SmGui::Button(CONCAT("Write##_dlcr_adc_wr_", _this->name))) {
|
|
||||||
if (_this->running) {
|
|
||||||
dlcr_mcp37211_write_reg(_this->openDev, std::stoi(_this->adcRegStr, NULL, 16), std::stoi(_this->adcValStr, NULL, 16));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::Separator();
|
|
||||||
|
|
||||||
SmGui::LeftLabel("Tuner Reg");
|
|
||||||
SmGui::FillWidth();
|
|
||||||
SmGui::InputText(CONCAT("##_dlcr_tun_reg_", _this->name), _this->tunRegStr, 256);
|
|
||||||
SmGui::LeftLabel("Tuner Value");
|
|
||||||
SmGui::FillWidth();
|
|
||||||
SmGui::InputText(CONCAT("##_dlcr_tun_val_", _this->name), _this->tunValStr, 256);
|
|
||||||
SmGui::FillWidth();
|
|
||||||
if (SmGui::Button(CONCAT("Read##_dlcr_tun_rd_", _this->name))) {
|
|
||||||
if (_this->running) {
|
|
||||||
uint8_t val[8];
|
|
||||||
dlcr_r860_read_reg(_this->openDev, DLCR_TUNER_ALL, std::stoi(_this->tunRegStr, NULL, 16), val);
|
|
||||||
sprintf(_this->tunValStr, "%02X", val[0]);
|
|
||||||
for (int i = 0; i < 8; i++) {
|
|
||||||
printf("TUNER[%d][0x%02X] = 0x%02X\n", i, std::stoi(_this->tunRegStr, NULL, 16), val[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SmGui::FillWidth();
|
|
||||||
if (SmGui::Button(CONCAT("Write##_dlcr_tun_wr_", _this->name))) {
|
|
||||||
if (_this->running) {
|
|
||||||
dlcr_r860_write_reg(_this->openDev, DLCR_TUNER_ALL, std::stoi(_this->tunRegStr, NULL, 16), std::stoi(_this->tunValStr, NULL, 16));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::Separator();
|
|
||||||
|
|
||||||
SmGui::LeftLabel("Synth Freq");
|
|
||||||
SmGui::FillWidth();
|
|
||||||
ImGui::InputDouble("##_dlcr_synth_freq", &_this->synthFreq);
|
|
||||||
SmGui::FillWidth();
|
|
||||||
if (SmGui::Button(CONCAT("Tune##_dlcr_synth_freq", _this->name))) {
|
|
||||||
if (_this->running) {
|
|
||||||
lmx2572_tune(_this->openDev, _this->synthFreq);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SmGui::FillWidth();
|
|
||||||
if (SmGui::Button(CONCAT("Shutdown##_dlcr_synth_freq", _this->name))) {
|
|
||||||
if (_this->running) {
|
|
||||||
lmx2572_shutdown(_this->openDev);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::Separator();
|
|
||||||
|
|
||||||
SmGui::Checkbox("Calibrate##_dlcr_cal", &_this->docal);
|
|
||||||
|
|
||||||
ImGui::Separator();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static void callback(dlcr_complex_t* samples[DLCR_CHANNEL_COUNT], size_t count, size_t drops, void* ctx) {
|
|
||||||
DragonLabsSourceModule* _this = (DragonLabsSourceModule*)ctx;
|
|
||||||
|
|
||||||
// Copy the data to the stream
|
|
||||||
memcpy(_this->stream.writeBuf, samples[_this->channelId], count * sizeof(dsp::complex_t));
|
|
||||||
|
|
||||||
// Send the samples
|
|
||||||
_this->stream.swap(count);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string name;
|
|
||||||
bool enabled = true;
|
|
||||||
double sampleRate;
|
|
||||||
SourceManager::SourceHandler handler;
|
|
||||||
bool running = false;
|
|
||||||
double freq = 100e6;
|
|
||||||
|
|
||||||
OptionList<std::string, std::string> devices;
|
|
||||||
|
|
||||||
bool debug = false;
|
|
||||||
char clkRegStr[256];
|
|
||||||
char clkValStr[256];
|
|
||||||
char synRegStr[256];
|
|
||||||
char synValStr[256];
|
|
||||||
char adcRegStr[256];
|
|
||||||
char adcValStr[256];
|
|
||||||
char tunRegStr[256];
|
|
||||||
char tunValStr[256];
|
|
||||||
double synthFreq = 100e6;
|
|
||||||
bool docal = false;
|
|
||||||
int devId = 0;
|
|
||||||
int clockSourceId = 0;
|
|
||||||
int channelId = 0;
|
|
||||||
int lnaGain = 0;
|
|
||||||
int mixerGain = 0;
|
|
||||||
int vgaGain = 0;
|
|
||||||
std::string selectedSerial;
|
|
||||||
dlcr_t* openDev = NULL;
|
|
||||||
|
|
||||||
bool calibrated = false;
|
|
||||||
|
|
||||||
dsp::stream<dsp::complex_t> stream;
|
|
||||||
OptionList<std::string, dlcr_clock_t> clockSources;
|
|
||||||
OptionList<std::string, int> channels;
|
|
||||||
};
|
|
||||||
|
|
||||||
MOD_EXPORT void _INIT_() {
|
|
||||||
// Nothing here
|
|
||||||
}
|
|
||||||
|
|
||||||
MOD_EXPORT ModuleManager::Instance* _CREATE_INSTANCE_(std::string name) {
|
|
||||||
return new DragonLabsSourceModule(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
MOD_EXPORT void _DELETE_INSTANCE_(void* instance) {
|
|
||||||
delete (DragonLabsSourceModule*)instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
MOD_EXPORT void _END_() {
|
|
||||||
// Nothing here
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
cmake_minimum_required(VERSION 3.13)
|
|
||||||
project(fobossdr_source)
|
|
||||||
|
|
||||||
file(GLOB SRC "src/*.cpp")
|
|
||||||
|
|
||||||
include(${SDRPP_MODULE_CMAKE})
|
|
||||||
|
|
||||||
if (MSVC)
|
|
||||||
# Lib path
|
|
||||||
target_link_directories(fobossdr_source PRIVATE "C:/Program Files/RigExpert/Fobos/lib/")
|
|
||||||
target_include_directories(fobossdr_source PRIVATE "C:/Program Files/RigExpert/Fobos/include/")
|
|
||||||
target_link_libraries(fobossdr_source PRIVATE fobos)
|
|
||||||
else (MSVC)
|
|
||||||
find_package(PkgConfig)
|
|
||||||
|
|
||||||
pkg_check_modules(LIBFOBOS REQUIRED libfobos)
|
|
||||||
|
|
||||||
target_include_directories(fobossdr_source PRIVATE ${LIBFOBOS_INCLUDE_DIRS})
|
|
||||||
target_link_directories(fobossdr_source PRIVATE ${LIBFOBOS_LIBRARY_DIRS})
|
|
||||||
target_link_libraries(fobossdr_source PRIVATE ${LIBFOBOS_LIBRARIES})
|
|
||||||
endif ()
|
|
||||||
@@ -1,560 +0,0 @@
|
|||||||
#include <imgui.h>
|
|
||||||
#include <module.h>
|
|
||||||
#include <gui/gui.h>
|
|
||||||
#include <gui/smgui.h>
|
|
||||||
#include <signal_path/signal_path.h>
|
|
||||||
#include <core.h>
|
|
||||||
#include <utils/optionlist.h>
|
|
||||||
#include <atomic>
|
|
||||||
#include <fobos.h>
|
|
||||||
|
|
||||||
SDRPP_MOD_INFO{
|
|
||||||
/* Name: */ "fobossdr_source",
|
|
||||||
/* Description: */ "FobosSDR Source Module",
|
|
||||||
/* Author: */ "Ryzerth",
|
|
||||||
/* Version: */ 0, 1, 0,
|
|
||||||
/* Max instances */ -1
|
|
||||||
};
|
|
||||||
|
|
||||||
ConfigManager config;
|
|
||||||
|
|
||||||
#define CONCAT(a, b) ((std::string(a) + b).c_str())
|
|
||||||
|
|
||||||
// Work around for the fobos API not including
|
|
||||||
#define FOBOS_LNA_GAIN_MIN 1
|
|
||||||
#define FOBOS_LNA_GAIN_MAX 3
|
|
||||||
#define FOBOS_VGA_GAIN_MIN 0
|
|
||||||
#define FOBOS_VGA_GAIN_MAX 31
|
|
||||||
|
|
||||||
class FobosSDRSourceModule : public ModuleManager::Instance {
|
|
||||||
public:
|
|
||||||
FobosSDRSourceModule(std::string name) {
|
|
||||||
this->name = name;
|
|
||||||
|
|
||||||
sampleRate = 50000000.0;
|
|
||||||
|
|
||||||
// Initialize the DDC
|
|
||||||
ddc.init(&ddcIn, 50e6, 50e6, 50e6, 0.0);
|
|
||||||
|
|
||||||
handler.ctx = this;
|
|
||||||
handler.selectHandler = menuSelected;
|
|
||||||
handler.deselectHandler = menuDeselected;
|
|
||||||
handler.menuHandler = menuHandler;
|
|
||||||
handler.startHandler = start;
|
|
||||||
handler.stopHandler = stop;
|
|
||||||
handler.tuneHandler = tune;
|
|
||||||
handler.stream = &ddc.out;
|
|
||||||
|
|
||||||
// Refresh devices
|
|
||||||
refresh();
|
|
||||||
|
|
||||||
// Select device from config
|
|
||||||
config.acquire();
|
|
||||||
std::string devSerial = config.conf["device"];
|
|
||||||
config.release();
|
|
||||||
select(devSerial);
|
|
||||||
|
|
||||||
sigpath::sourceManager.registerSource("FobosSDR", &handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
~FobosSDRSourceModule() {
|
|
||||||
// Nothing to do
|
|
||||||
}
|
|
||||||
|
|
||||||
void postInit() {}
|
|
||||||
|
|
||||||
void enable() {
|
|
||||||
enabled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void disable() {
|
|
||||||
enabled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isEnabled() {
|
|
||||||
return enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum Port {
|
|
||||||
PORT_RF,
|
|
||||||
PORT_HF1,
|
|
||||||
PORT_HF2
|
|
||||||
};
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
void refresh() {
|
|
||||||
devices.clear();
|
|
||||||
|
|
||||||
// Get device list
|
|
||||||
char serials[1024];
|
|
||||||
memset(serials, 0, sizeof(serials));
|
|
||||||
int devCount = fobos_rx_list_devices(serials);
|
|
||||||
if (devCount < 0) {
|
|
||||||
flog::error("Failed to get device list: {}", devCount);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If no device, give up
|
|
||||||
if (!devCount) { return; }
|
|
||||||
|
|
||||||
// Generate device entries
|
|
||||||
const char* _serials = serials;
|
|
||||||
int index = 0;
|
|
||||||
while (*_serials) {
|
|
||||||
// Read serial until space
|
|
||||||
std::string serial = "";
|
|
||||||
while (*_serials) {
|
|
||||||
// Get a character
|
|
||||||
char c = *(_serials++);
|
|
||||||
|
|
||||||
// If it's a space, we're done
|
|
||||||
if (c == ' ') { break; }
|
|
||||||
|
|
||||||
// Otherwise, add it to the string
|
|
||||||
serial += c;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create entry
|
|
||||||
devices.define(serial, serial, index++);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void select(const std::string& serial) {
|
|
||||||
// If there are no devices, give up
|
|
||||||
if (devices.empty()) {
|
|
||||||
selectedSerial.clear();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the serial was not found, select the first available serial
|
|
||||||
if (!devices.keyExists(serial)) {
|
|
||||||
select(devices.key(0));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the ID in the list
|
|
||||||
int id = devices.keyId(serial);
|
|
||||||
selectedDevId = devices[id];
|
|
||||||
|
|
||||||
// Open the device
|
|
||||||
fobos_dev_t* dev;
|
|
||||||
int err = fobos_rx_open(&dev, selectedDevId);
|
|
||||||
if (err) {
|
|
||||||
flog::error("Failed to open device: {}", err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get a list of supported samplerates
|
|
||||||
double srList[128];
|
|
||||||
unsigned int srCount;
|
|
||||||
err = fobos_rx_get_samplerates(dev, srList, &srCount);
|
|
||||||
if (err) {
|
|
||||||
flog::error("Failed to get samplerate list: {}", err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate samplerate list
|
|
||||||
samplerates.clear();
|
|
||||||
for (int i = 0; i < srCount; i++) {
|
|
||||||
std::string str = getBandwdithScaled(srList[i]);
|
|
||||||
samplerates.define(srList[i], str, srList[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add some custom samplerates
|
|
||||||
samplerates.define(5e6, "5.0MHz", 5e6);
|
|
||||||
samplerates.define(2.5e6, "2.5MHz", 2.5e6);
|
|
||||||
samplerates.define(1.25e6, "1.25MHz", 1.25e6);
|
|
||||||
|
|
||||||
// Define the ports
|
|
||||||
ports.clear();
|
|
||||||
ports.define("rf", "RF", PORT_RF);
|
|
||||||
ports.define("hf1", "HF1", PORT_HF1);
|
|
||||||
ports.define("hf2", "HF2", PORT_HF2);
|
|
||||||
|
|
||||||
// Define clock sources
|
|
||||||
clockSources.clear();
|
|
||||||
clockSources.define("internal", "Internal", 0);
|
|
||||||
clockSources.define("external", "External", 1);
|
|
||||||
|
|
||||||
// Close the device
|
|
||||||
fobos_rx_close(dev);
|
|
||||||
|
|
||||||
// Save serial number
|
|
||||||
selectedSerial = serial;
|
|
||||||
devId = id;
|
|
||||||
|
|
||||||
// Load default options
|
|
||||||
sampleRate = 50e6;
|
|
||||||
srId = samplerates.valueId(sampleRate);
|
|
||||||
port = PORT_RF;
|
|
||||||
portId = ports.valueId(port);
|
|
||||||
clkSrcId = clockSources.nameId("Internal");
|
|
||||||
lnaGain = 0;
|
|
||||||
vgaGain = 0;
|
|
||||||
|
|
||||||
// Load config
|
|
||||||
config.acquire();
|
|
||||||
if (config.conf["devices"][selectedSerial].contains("samplerate")) {
|
|
||||||
int desiredSr = config.conf["devices"][selectedSerial]["samplerate"];
|
|
||||||
if (samplerates.keyExists(desiredSr)) {
|
|
||||||
srId = samplerates.keyId(desiredSr);
|
|
||||||
sampleRate = samplerates[srId];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (config.conf["devices"][selectedSerial].contains("port")) {
|
|
||||||
std::string desiredPort = config.conf["devices"][selectedSerial]["port"];
|
|
||||||
if (ports.keyExists(desiredPort)) {
|
|
||||||
portId = ports.keyId(desiredPort);
|
|
||||||
port = ports[portId];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (config.conf["devices"][selectedSerial].contains("clkSrc")) {
|
|
||||||
std::string desiredClkSrc = config.conf["devices"][selectedSerial]["clkSrc"];
|
|
||||||
if (clockSources.keyExists(desiredClkSrc)) {
|
|
||||||
clkSrcId = clockSources.keyId(desiredClkSrc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (config.conf["devices"][selectedSerial].contains("lnaGain")) {
|
|
||||||
lnaGain = std::clamp<int>(config.conf["devices"][selectedSerial]["lnaGain"], FOBOS_LNA_GAIN_MIN, FOBOS_LNA_GAIN_MAX);
|
|
||||||
}
|
|
||||||
if (config.conf["devices"][selectedSerial].contains("vgaGain")) {
|
|
||||||
vgaGain = std::clamp<int>(config.conf["devices"][selectedSerial]["vgaGain"], FOBOS_VGA_GAIN_MIN, FOBOS_VGA_GAIN_MAX);
|
|
||||||
}
|
|
||||||
config.release();
|
|
||||||
|
|
||||||
// Update the samplerate
|
|
||||||
core::setInputSampleRate(sampleRate);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void menuSelected(void* ctx) {
|
|
||||||
FobosSDRSourceModule* _this = (FobosSDRSourceModule*)ctx;
|
|
||||||
core::setInputSampleRate(_this->sampleRate);
|
|
||||||
flog::info("FobosSDRSourceModule '{0}': Menu Select!", _this->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void menuDeselected(void* ctx) {
|
|
||||||
FobosSDRSourceModule* _this = (FobosSDRSourceModule*)ctx;
|
|
||||||
flog::info("FobosSDRSourceModule '{0}': Menu Deselect!", _this->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void start(void* ctx) {
|
|
||||||
FobosSDRSourceModule* _this = (FobosSDRSourceModule*)ctx;
|
|
||||||
if (_this->running) { return; }
|
|
||||||
|
|
||||||
// Open the device
|
|
||||||
int err = fobos_rx_open(&_this->openDev, _this->selectedDevId);
|
|
||||||
if (err) {
|
|
||||||
flog::error("Failed to open device: {}", err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the selected port
|
|
||||||
_this->port = _this->ports[_this->portId];
|
|
||||||
|
|
||||||
// Configure the device
|
|
||||||
double actualSr, actualFreq;
|
|
||||||
fobos_rx_set_samplerate(_this->openDev, (_this->sampleRate >= 50e6) ? _this->sampleRate : 50e6, &actualSr);
|
|
||||||
fobos_rx_set_frequency(_this->openDev, _this->freq, &actualFreq);
|
|
||||||
fobos_rx_set_direct_sampling(_this->openDev, _this->port != PORT_RF);
|
|
||||||
fobos_rx_set_clk_source(_this->openDev, _this->clockSources[_this->clkSrcId]);
|
|
||||||
fobos_rx_set_lna_gain(_this->openDev, _this->lnaGain);
|
|
||||||
fobos_rx_set_vga_gain(_this->openDev, _this->vgaGain);
|
|
||||||
|
|
||||||
// Configure the DDC
|
|
||||||
if (_this->port == PORT_RF && _this->sampleRate >= 50e6) {
|
|
||||||
// Set the frequency
|
|
||||||
fobos_rx_set_frequency(_this->openDev, _this->freq, &actualFreq);
|
|
||||||
}
|
|
||||||
else if (_this->port == PORT_RF) {
|
|
||||||
// Set the frequency
|
|
||||||
fobos_rx_set_frequency(_this->openDev, _this->freq, &actualFreq);
|
|
||||||
|
|
||||||
// Configure and start the DDC for decimation only
|
|
||||||
_this->ddc.setInSamplerate(actualSr);
|
|
||||||
_this->ddc.setOutSamplerate(_this->sampleRate, _this->sampleRate);
|
|
||||||
_this->ddc.setOffset(0.0);
|
|
||||||
_this->ddc.start();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Configure and start the DDC
|
|
||||||
_this->ddc.setInSamplerate(actualSr);
|
|
||||||
_this->ddc.setOutSamplerate(_this->sampleRate, _this->sampleRate);
|
|
||||||
_this->ddc.setOffset(_this->freq);
|
|
||||||
_this->ddc.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compute buffer size (Lower than usual, but it's a workaround for their API having broken streaming)
|
|
||||||
_this->bufferSize = _this->sampleRate / 400.0;
|
|
||||||
|
|
||||||
// Start streaming
|
|
||||||
err = fobos_rx_start_sync(_this->openDev, _this->bufferSize);
|
|
||||||
if (err) {
|
|
||||||
flog::error("Failed to start stream: {}", err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start worker
|
|
||||||
_this->run = true;
|
|
||||||
_this->workerThread = std::thread(&FobosSDRSourceModule::worker, _this);
|
|
||||||
|
|
||||||
_this->running = true;
|
|
||||||
flog::info("FobosSDRSourceModule '{0}': Start!", _this->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void stop(void* ctx) {
|
|
||||||
FobosSDRSourceModule* _this = (FobosSDRSourceModule*)ctx;
|
|
||||||
if (!_this->running) { return; }
|
|
||||||
_this->running = false;
|
|
||||||
|
|
||||||
// Stop worker
|
|
||||||
_this->run = false;
|
|
||||||
if (_this->port == PORT_RF && _this->sampleRate >= 50e6) {
|
|
||||||
_this->ddc.out.stopWriter();
|
|
||||||
if (_this->workerThread.joinable()) { _this->workerThread.join(); }
|
|
||||||
_this->ddc.out.clearWriteStop();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
_this->ddcIn.stopWriter();
|
|
||||||
if (_this->workerThread.joinable()) { _this->workerThread.join(); }
|
|
||||||
_this->ddcIn.clearWriteStop();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stop streaming
|
|
||||||
fobos_rx_stop_sync(_this->openDev);
|
|
||||||
|
|
||||||
// Stop the DDC
|
|
||||||
_this->ddc.stop();
|
|
||||||
|
|
||||||
// Close the device
|
|
||||||
fobos_rx_close(_this->openDev);
|
|
||||||
|
|
||||||
flog::info("FobosSDRSourceModule '{0}': Stop!", _this->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void tune(double freq, void* ctx) {
|
|
||||||
FobosSDRSourceModule* _this = (FobosSDRSourceModule*)ctx;
|
|
||||||
if (_this->running) {
|
|
||||||
if (_this->port == PORT_RF) {
|
|
||||||
double actual; // Dummy, don't care
|
|
||||||
fobos_rx_set_frequency(_this->openDev, freq, &actual);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
_this->ddc.setOffset(freq);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_this->freq = freq;
|
|
||||||
flog::info("FobosSDRSourceModule '{0}': Tune: {1}!", _this->name, freq);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void menuHandler(void* ctx) {
|
|
||||||
FobosSDRSourceModule* _this = (FobosSDRSourceModule*)ctx;
|
|
||||||
|
|
||||||
if (_this->running) { SmGui::BeginDisabled(); }
|
|
||||||
|
|
||||||
SmGui::FillWidth();
|
|
||||||
SmGui::ForceSync();
|
|
||||||
if (SmGui::Combo(CONCAT("##_fobossdr_dev_sel_", _this->name), &_this->devId, _this->devices.txt)) {
|
|
||||||
_this->select(_this->devices.key(_this->devId));
|
|
||||||
core::setInputSampleRate(_this->sampleRate);
|
|
||||||
config.acquire();
|
|
||||||
config.conf["device"] = _this->selectedSerial;
|
|
||||||
config.release(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SmGui::Combo(CONCAT("##_fobossdr_sr_sel_", _this->name), &_this->srId, _this->samplerates.txt)) {
|
|
||||||
_this->sampleRate = _this->samplerates.value(_this->srId);
|
|
||||||
core::setInputSampleRate(_this->sampleRate);
|
|
||||||
if (!_this->selectedSerial.empty()) {
|
|
||||||
config.acquire();
|
|
||||||
config.conf["devices"][_this->selectedSerial]["samplerate"] = _this->samplerates.key(_this->srId);
|
|
||||||
config.release(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SmGui::SameLine();
|
|
||||||
SmGui::FillWidth();
|
|
||||||
SmGui::ForceSync();
|
|
||||||
if (SmGui::Button(CONCAT("Refresh##_fobossdr_refr_", _this->name))) {
|
|
||||||
_this->refresh();
|
|
||||||
_this->select(_this->selectedSerial);
|
|
||||||
core::setInputSampleRate(_this->sampleRate);
|
|
||||||
}
|
|
||||||
|
|
||||||
SmGui::LeftLabel("Antenna Port");
|
|
||||||
SmGui::FillWidth();
|
|
||||||
if (SmGui::Combo(CONCAT("##_fobossdr_port_", _this->name), &_this->portId, _this->ports.txt)) {
|
|
||||||
if (!_this->selectedSerial.empty()) {
|
|
||||||
config.acquire();
|
|
||||||
config.conf["devices"][_this->selectedSerial]["port"] = _this->ports.key(_this->portId);
|
|
||||||
config.release(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_this->running) { SmGui::EndDisabled(); }
|
|
||||||
|
|
||||||
SmGui::LeftLabel("Clock Source");
|
|
||||||
SmGui::FillWidth();
|
|
||||||
if (SmGui::Combo(CONCAT("##_fobossdr_clk_", _this->name), &_this->clkSrcId, _this->clockSources.txt)) {
|
|
||||||
if (_this->running) {
|
|
||||||
fobos_rx_set_clk_source(_this->openDev, _this->clockSources[_this->clkSrcId]);
|
|
||||||
}
|
|
||||||
if (!_this->selectedSerial.empty()) {
|
|
||||||
config.acquire();
|
|
||||||
config.conf["devices"][_this->selectedSerial]["clkSrc"] = _this->clockSources.key(_this->clkSrcId);
|
|
||||||
config.release(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_this->port == PORT_RF) {
|
|
||||||
SmGui::LeftLabel("LNA Gain");
|
|
||||||
SmGui::FillWidth();
|
|
||||||
if (SmGui::SliderInt(CONCAT("##_fobossdr_lna_gain_", _this->name), &_this->lnaGain, FOBOS_LNA_GAIN_MIN, FOBOS_LNA_GAIN_MAX)) {
|
|
||||||
if (_this->running) {
|
|
||||||
fobos_rx_set_lna_gain(_this->openDev, _this->lnaGain);
|
|
||||||
}
|
|
||||||
if (!_this->selectedSerial.empty()) {
|
|
||||||
config.acquire();
|
|
||||||
config.conf["devices"][_this->selectedSerial]["lnaGain"] = _this->lnaGain;
|
|
||||||
config.release(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SmGui::LeftLabel("VGA Gain");
|
|
||||||
SmGui::FillWidth();
|
|
||||||
if (SmGui::SliderInt(CONCAT("##_fobossdr_vga_gain_", _this->name), &_this->vgaGain, FOBOS_VGA_GAIN_MIN, FOBOS_VGA_GAIN_MAX)) {
|
|
||||||
if (_this->running) {
|
|
||||||
fobos_rx_set_vga_gain(_this->openDev, _this->vgaGain);
|
|
||||||
}
|
|
||||||
if (!_this->selectedSerial.empty()) {
|
|
||||||
config.acquire();
|
|
||||||
config.conf["devices"][_this->selectedSerial]["vgaGain"] = _this->vgaGain;
|
|
||||||
config.release(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void worker() {
|
|
||||||
// Select different processing depending on the mode
|
|
||||||
if (port == PORT_RF && sampleRate >= 50e6) {
|
|
||||||
while (run) {
|
|
||||||
// Read samples
|
|
||||||
unsigned int sampCount = 0;
|
|
||||||
int err = fobos_rx_read_sync(openDev, (float*)ddc.out.writeBuf, &sampCount);
|
|
||||||
if (err) { break; }
|
|
||||||
|
|
||||||
// Send out samples to the core
|
|
||||||
if (!ddc.out.swap(sampCount)) { break; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (port == PORT_RF) {
|
|
||||||
while (run) {
|
|
||||||
// Read samples
|
|
||||||
unsigned int sampCount = 0;
|
|
||||||
int err = fobos_rx_read_sync(openDev, (float*)ddcIn.writeBuf, &sampCount);
|
|
||||||
if (err) { break; }
|
|
||||||
|
|
||||||
// Send samples to the DDC
|
|
||||||
if (!ddcIn.swap(sampCount)) { break; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (port == PORT_HF1) {
|
|
||||||
while (run) {
|
|
||||||
// Read samples
|
|
||||||
unsigned int sampCount = 0;
|
|
||||||
int err = fobos_rx_read_sync(openDev, (float*)ddcIn.writeBuf, &sampCount);
|
|
||||||
if (err) { break; }
|
|
||||||
|
|
||||||
// Null out the HF2 samples
|
|
||||||
for (int i = 0; i < sampCount; i++) {
|
|
||||||
ddcIn.writeBuf[i].im = 0.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send samples to the DDC
|
|
||||||
if (!ddcIn.swap(sampCount)) { break; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (port == PORT_HF2) {
|
|
||||||
while (run) {
|
|
||||||
// Read samples
|
|
||||||
unsigned int sampCount = 0;
|
|
||||||
int err = fobos_rx_read_sync(openDev, (float*)ddcIn.writeBuf, &sampCount);
|
|
||||||
if (err) { break; }
|
|
||||||
|
|
||||||
// Null out the HF2 samples
|
|
||||||
for (int i = 0; i < sampCount; i++) {
|
|
||||||
ddcIn.writeBuf[i].re = 0.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send samples to the DDC
|
|
||||||
if (!ddcIn.swap(sampCount)) { break; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string name;
|
|
||||||
bool enabled = true;
|
|
||||||
double sampleRate;
|
|
||||||
SourceManager::SourceHandler handler;
|
|
||||||
bool running = false;
|
|
||||||
double freq;
|
|
||||||
|
|
||||||
OptionList<std::string, int> devices;
|
|
||||||
OptionList<int, double> samplerates;
|
|
||||||
OptionList<std::string, Port> ports;
|
|
||||||
OptionList<std::string, int> clockSources;
|
|
||||||
int devId = 0;
|
|
||||||
int srId = 0;
|
|
||||||
int portId = 0;
|
|
||||||
int clkSrcId = 0;
|
|
||||||
Port port;
|
|
||||||
int lnaGain = 0;
|
|
||||||
int vgaGain = 0;
|
|
||||||
std::string selectedSerial;
|
|
||||||
int selectedDevId;
|
|
||||||
|
|
||||||
fobos_dev_t* openDev;
|
|
||||||
|
|
||||||
int bufferSize;
|
|
||||||
std::thread workerThread;
|
|
||||||
std::atomic<bool> run = false;
|
|
||||||
|
|
||||||
dsp::stream<dsp::complex_t> ddcIn;
|
|
||||||
dsp::channel::RxVFO ddc;
|
|
||||||
};
|
|
||||||
|
|
||||||
MOD_EXPORT void _INIT_() {
|
|
||||||
json def = json({});
|
|
||||||
def["devices"] = json({});
|
|
||||||
def["device"] = "";
|
|
||||||
config.setPath(core::args["root"].s() + "/fobossdr_config.json");
|
|
||||||
config.load(def);
|
|
||||||
config.enableAutoSave();
|
|
||||||
}
|
|
||||||
|
|
||||||
MOD_EXPORT ModuleManager::Instance* _CREATE_INSTANCE_(std::string name) {
|
|
||||||
return new FobosSDRSourceModule(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
MOD_EXPORT void _DELETE_INSTANCE_(void* instance) {
|
|
||||||
delete (FobosSDRSourceModule*)instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
MOD_EXPORT void _END_() {
|
|
||||||
config.disableAutoSave();
|
|
||||||
config.save();
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
cmake_minimum_required(VERSION 3.13)
|
|
||||||
project(hydrasdr_source)
|
|
||||||
|
|
||||||
file(GLOB SRC "src/*.cpp")
|
|
||||||
|
|
||||||
include(${SDRPP_MODULE_CMAKE})
|
|
||||||
|
|
||||||
if (MSVC)
|
|
||||||
target_link_directories(hydrasdr_source PRIVATE "C:/Program Files/hydrasdr-host/lib/")
|
|
||||||
|
|
||||||
target_include_directories(hydrasdr_source PUBLIC "C:/Program Files/hydrasdr-host/include/libhydrasdr")
|
|
||||||
|
|
||||||
target_link_libraries(hydrasdr_source PRIVATE hydrasdr)
|
|
||||||
elseif (ANDROID)
|
|
||||||
target_include_directories(hydrasdr_source PUBLIC
|
|
||||||
/sdr-kit/${ANDROID_ABI}/include/libhydrasdr
|
|
||||||
)
|
|
||||||
|
|
||||||
target_link_libraries(hydrasdr_source PUBLIC
|
|
||||||
/sdr-kit/${ANDROID_ABI}/lib/libusb1.0.so
|
|
||||||
/sdr-kit/${ANDROID_ABI}/lib/libhydrasdr.so
|
|
||||||
)
|
|
||||||
else (MSVC)
|
|
||||||
find_package(PkgConfig)
|
|
||||||
|
|
||||||
pkg_check_modules(LIBHYDRASDR REQUIRED libhydrasdr)
|
|
||||||
|
|
||||||
target_include_directories(hydrasdr_source PRIVATE ${LIBHYDRASDR_INCLUDE_DIRS})
|
|
||||||
target_link_directories(hydrasdr_source PRIVATE ${LIBHYDRASDR_LIBRARY_DIRS})
|
|
||||||
target_link_libraries(hydrasdr_source PRIVATE ${LIBHYDRASDR_LIBRARIES})
|
|
||||||
|
|
||||||
# Include it because for some reason pkgconfig doesn't look here?
|
|
||||||
if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
|
||||||
target_include_directories(hydrasdr_source PRIVATE "/usr/local/include")
|
|
||||||
endif()
|
|
||||||
endif ()
|
|
||||||
@@ -1,639 +0,0 @@
|
|||||||
#include <imgui.h>
|
|
||||||
#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 <hydrasdr.h>
|
|
||||||
#include <utils/optionlist.h>
|
|
||||||
|
|
||||||
#ifdef __ANDROID__
|
|
||||||
#include <android_backend.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define CONCAT(a, b) ((std::string(a) + b).c_str())
|
|
||||||
|
|
||||||
SDRPP_MOD_INFO{
|
|
||||||
/* Name: */ "hydrasdr_source",
|
|
||||||
/* Description: */ "HydraSDR source module for SDR++",
|
|
||||||
/* Author: */ "Ryzerth",
|
|
||||||
/* Version: */ 0, 1, 0,
|
|
||||||
/* Max instances */ 1
|
|
||||||
};
|
|
||||||
|
|
||||||
ConfigManager config;
|
|
||||||
|
|
||||||
class HydraSDRSourceModule : public ModuleManager::Instance {
|
|
||||||
public:
|
|
||||||
HydraSDRSourceModule(std::string name) {
|
|
||||||
this->name = name;
|
|
||||||
|
|
||||||
// Define the ports
|
|
||||||
ports.define("rx0", "RX0", HYDRASDR_RF_PORT_RX0);
|
|
||||||
ports.define("rx1", "RX1", HYDRASDR_RF_PORT_RX1);
|
|
||||||
ports.define("rx2", "RX2", HYDRASDR_RF_PORT_RX2);
|
|
||||||
|
|
||||||
regStr[0] = 0;
|
|
||||||
valStr[0] = 0;
|
|
||||||
|
|
||||||
sampleRate = 10000000.0;
|
|
||||||
|
|
||||||
handler.ctx = this;
|
|
||||||
handler.selectHandler = menuSelected;
|
|
||||||
handler.deselectHandler = menuDeselected;
|
|
||||||
handler.menuHandler = menuHandler;
|
|
||||||
handler.startHandler = start;
|
|
||||||
handler.stopHandler = stop;
|
|
||||||
handler.tuneHandler = tune;
|
|
||||||
handler.stream = &stream;
|
|
||||||
|
|
||||||
refresh();
|
|
||||||
|
|
||||||
// Select device from config
|
|
||||||
config.acquire();
|
|
||||||
std::string devSerial = config.conf["device"];
|
|
||||||
config.release();
|
|
||||||
selectByString(devSerial);
|
|
||||||
|
|
||||||
sigpath::sourceManager.registerSource("HydraSDR", &handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
~HydraSDRSourceModule() {
|
|
||||||
stop(this);
|
|
||||||
sigpath::sourceManager.unregisterSource("HydraSDR");;
|
|
||||||
}
|
|
||||||
|
|
||||||
void postInit() {}
|
|
||||||
|
|
||||||
void enable() {
|
|
||||||
enabled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void disable() {
|
|
||||||
enabled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isEnabled() {
|
|
||||||
return enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
void refresh() {
|
|
||||||
#ifndef __ANDROID__
|
|
||||||
devices.clear();
|
|
||||||
|
|
||||||
uint64_t serials[256];
|
|
||||||
int n = hydrasdr_list_devices(serials, 256);
|
|
||||||
|
|
||||||
char buf[1024];
|
|
||||||
for (int i = 0; i < n; i++) {
|
|
||||||
sprintf(buf, "%016" PRIX64, serials[i]);
|
|
||||||
devices.define(buf, buf, serials[i]);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
// Check for device presence
|
|
||||||
int vid, pid;
|
|
||||||
devFd = backend::getDeviceFD(vid, pid, backend::HYDRASDR_VIDPIDS);
|
|
||||||
if (devFd < 0) { return; }
|
|
||||||
|
|
||||||
// Get device info
|
|
||||||
std::string fakeName = "HydraSDR USB";
|
|
||||||
devices.define(fakeName, 0);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void selectFirst() {
|
|
||||||
if (!devices.empty()) {
|
|
||||||
selectBySerial(devices.value(0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void selectByString(std::string serial) {
|
|
||||||
if (devices.keyExists(serial)) {
|
|
||||||
selectBySerial(devices.value(devices.keyId(serial)));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
selectFirst();
|
|
||||||
}
|
|
||||||
|
|
||||||
void selectBySerial(uint64_t serial) {
|
|
||||||
hydrasdr_device* dev;
|
|
||||||
try {
|
|
||||||
#ifndef __ANDROID__
|
|
||||||
int err = hydrasdr_open_sn(&dev, serial);
|
|
||||||
#else
|
|
||||||
int err = hydrasdr_open_fd(&dev, devFd);
|
|
||||||
#endif
|
|
||||||
if (err != 0) {
|
|
||||||
char buf[1024];
|
|
||||||
sprintf(buf, "%016" PRIX64, serial);
|
|
||||||
flog::error("Could not open HydraSDR {0}", buf);
|
|
||||||
selectedSerial = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (const std::exception& e) {
|
|
||||||
char buf[1024];
|
|
||||||
sprintf(buf, "%016" PRIX64, serial);
|
|
||||||
flog::error("Could not open HydraSDR {}", buf);
|
|
||||||
}
|
|
||||||
devId = devices.valueId(serial);
|
|
||||||
selectedSerial = serial;
|
|
||||||
selectedSerStr = devices.key(devId);
|
|
||||||
|
|
||||||
uint32_t sampleRates[256];
|
|
||||||
hydrasdr_get_samplerates(dev, sampleRates, 0);
|
|
||||||
int n = sampleRates[0];
|
|
||||||
hydrasdr_get_samplerates(dev, sampleRates, n);
|
|
||||||
samplerates.clear();
|
|
||||||
for (int i = 0; i < n; i++) {
|
|
||||||
samplerates.define(sampleRates[i], getBandwdithScaled(sampleRates[i]), sampleRates[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load config here
|
|
||||||
config.acquire();
|
|
||||||
bool created = false;
|
|
||||||
if (!config.conf["devices"].contains(selectedSerStr)) {
|
|
||||||
created = true;
|
|
||||||
config.conf["devices"][selectedSerStr]["sampleRate"] = 10000000;
|
|
||||||
config.conf["devices"][selectedSerStr]["gainMode"] = 0;
|
|
||||||
config.conf["devices"][selectedSerStr]["sensitiveGain"] = 0;
|
|
||||||
config.conf["devices"][selectedSerStr]["linearGain"] = 0;
|
|
||||||
config.conf["devices"][selectedSerStr]["lnaGain"] = 0;
|
|
||||||
config.conf["devices"][selectedSerStr]["mixerGain"] = 0;
|
|
||||||
config.conf["devices"][selectedSerStr]["vgaGain"] = 0;
|
|
||||||
config.conf["devices"][selectedSerStr]["lnaAgc"] = false;
|
|
||||||
config.conf["devices"][selectedSerStr]["mixerAgc"] = false;
|
|
||||||
config.conf["devices"][selectedSerStr]["biasT"] = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load sample rate
|
|
||||||
srId = 0;
|
|
||||||
sampleRate = samplerates.value(0);
|
|
||||||
if (config.conf["devices"][selectedSerStr].contains("sampleRate")) {
|
|
||||||
int selectedSr = config.conf["devices"][selectedSerStr]["sampleRate"];
|
|
||||||
if (samplerates.keyExists(selectedSr)) {
|
|
||||||
srId = samplerates.keyId(selectedSr);
|
|
||||||
sampleRate = samplerates[srId];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load port
|
|
||||||
if (config.conf["devices"][selectedSerStr].contains("port")) {
|
|
||||||
std::string portStr = config.conf["devices"][selectedSerStr]["port"];
|
|
||||||
if (ports.keyExists(portStr)) {
|
|
||||||
portId = ports.keyId(portStr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load gains
|
|
||||||
if (config.conf["devices"][selectedSerStr].contains("gainMode")) {
|
|
||||||
gainMode = config.conf["devices"][selectedSerStr]["gainMode"];
|
|
||||||
}
|
|
||||||
if (config.conf["devices"][selectedSerStr].contains("sensitiveGain")) {
|
|
||||||
sensitiveGain = config.conf["devices"][selectedSerStr]["sensitiveGain"];
|
|
||||||
}
|
|
||||||
if (config.conf["devices"][selectedSerStr].contains("linearGain")) {
|
|
||||||
linearGain = config.conf["devices"][selectedSerStr]["linearGain"];
|
|
||||||
}
|
|
||||||
if (config.conf["devices"][selectedSerStr].contains("lnaGain")) {
|
|
||||||
lnaGain = config.conf["devices"][selectedSerStr]["lnaGain"];
|
|
||||||
}
|
|
||||||
if (config.conf["devices"][selectedSerStr].contains("mixerGain")) {
|
|
||||||
mixerGain = config.conf["devices"][selectedSerStr]["mixerGain"];
|
|
||||||
}
|
|
||||||
if (config.conf["devices"][selectedSerStr].contains("vgaGain")) {
|
|
||||||
vgaGain = config.conf["devices"][selectedSerStr]["vgaGain"];
|
|
||||||
}
|
|
||||||
if (config.conf["devices"][selectedSerStr].contains("lnaAgc")) {
|
|
||||||
lnaAgc = config.conf["devices"][selectedSerStr]["lnaAgc"];
|
|
||||||
}
|
|
||||||
if (config.conf["devices"][selectedSerStr].contains("mixerAgc")) {
|
|
||||||
mixerAgc = config.conf["devices"][selectedSerStr]["mixerAgc"];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load Bias-T
|
|
||||||
if (config.conf["devices"][selectedSerStr].contains("biasT")) {
|
|
||||||
biasT = config.conf["devices"][selectedSerStr]["biasT"];
|
|
||||||
}
|
|
||||||
|
|
||||||
config.release(created);
|
|
||||||
|
|
||||||
hydrasdr_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) {
|
|
||||||
HydraSDRSourceModule* _this = (HydraSDRSourceModule*)ctx;
|
|
||||||
core::setInputSampleRate(_this->sampleRate);
|
|
||||||
flog::info("HydraSDRSourceModule '{0}': Menu Select!", _this->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void menuDeselected(void* ctx) {
|
|
||||||
HydraSDRSourceModule* _this = (HydraSDRSourceModule*)ctx;
|
|
||||||
flog::info("HydraSDRSourceModule '{0}': Menu Deselect!", _this->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void start(void* ctx) {
|
|
||||||
HydraSDRSourceModule* _this = (HydraSDRSourceModule*)ctx;
|
|
||||||
if (_this->running) { return; }
|
|
||||||
if (_this->selectedSerial == 0) {
|
|
||||||
flog::error("Tried to start HydraSDR source with null serial");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef __ANDROID__
|
|
||||||
int err = hydrasdr_open_sn(&_this->openDev, _this->selectedSerial);
|
|
||||||
#else
|
|
||||||
int err = hydrasdr_open_fd(&_this->openDev, _this->devFd);
|
|
||||||
#endif
|
|
||||||
if (err != 0) {
|
|
||||||
char buf[1024];
|
|
||||||
sprintf(buf, "%016" PRIX64, _this->selectedSerial);
|
|
||||||
flog::error("Could not open HydraSDR {0}", buf);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
hydrasdr_set_samplerate(_this->openDev, _this->samplerates[_this->srId]);
|
|
||||||
hydrasdr_set_freq(_this->openDev, _this->freq);
|
|
||||||
|
|
||||||
hydrasdr_set_rf_port(_this->openDev, _this->ports[_this->portId]);
|
|
||||||
|
|
||||||
if (_this->gainMode == 0) {
|
|
||||||
hydrasdr_set_lna_agc(_this->openDev, 0);
|
|
||||||
hydrasdr_set_mixer_agc(_this->openDev, 0);
|
|
||||||
hydrasdr_set_sensitivity_gain(_this->openDev, _this->sensitiveGain);
|
|
||||||
}
|
|
||||||
else if (_this->gainMode == 1) {
|
|
||||||
hydrasdr_set_lna_agc(_this->openDev, 0);
|
|
||||||
hydrasdr_set_mixer_agc(_this->openDev, 0);
|
|
||||||
hydrasdr_set_linearity_gain(_this->openDev, _this->linearGain);
|
|
||||||
}
|
|
||||||
else if (_this->gainMode == 2) {
|
|
||||||
if (_this->lnaAgc) {
|
|
||||||
hydrasdr_set_lna_agc(_this->openDev, 1);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
hydrasdr_set_lna_agc(_this->openDev, 0);
|
|
||||||
hydrasdr_set_lna_gain(_this->openDev, _this->lnaGain);
|
|
||||||
}
|
|
||||||
if (_this->mixerAgc) {
|
|
||||||
hydrasdr_set_mixer_agc(_this->openDev, 1);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
hydrasdr_set_mixer_agc(_this->openDev, 0);
|
|
||||||
hydrasdr_set_mixer_gain(_this->openDev, _this->mixerGain);
|
|
||||||
}
|
|
||||||
hydrasdr_set_vga_gain(_this->openDev, _this->vgaGain);
|
|
||||||
}
|
|
||||||
|
|
||||||
hydrasdr_set_rf_bias(_this->openDev, _this->biasT);
|
|
||||||
|
|
||||||
hydrasdr_start_rx(_this->openDev, callback, _this);
|
|
||||||
|
|
||||||
_this->running = true;
|
|
||||||
flog::info("HydraSDRSourceModule '{0}': Start!", _this->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void stop(void* ctx) {
|
|
||||||
HydraSDRSourceModule* _this = (HydraSDRSourceModule*)ctx;
|
|
||||||
if (!_this->running) { return; }
|
|
||||||
_this->running = false;
|
|
||||||
_this->stream.stopWriter();
|
|
||||||
hydrasdr_close(_this->openDev);
|
|
||||||
_this->stream.clearWriteStop();
|
|
||||||
flog::info("HydraSDRSourceModule '{0}': Stop!", _this->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void tune(double freq, void* ctx) {
|
|
||||||
HydraSDRSourceModule* _this = (HydraSDRSourceModule*)ctx;
|
|
||||||
if (_this->running) {
|
|
||||||
hydrasdr_set_freq(_this->openDev, freq);
|
|
||||||
}
|
|
||||||
_this->freq = freq;
|
|
||||||
flog::info("HydraSDRSourceModule '{0}': Tune: {1}!", _this->name, freq);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void menuHandler(void* ctx) {
|
|
||||||
HydraSDRSourceModule* _this = (HydraSDRSourceModule*)ctx;
|
|
||||||
|
|
||||||
if (_this->running) { SmGui::BeginDisabled(); }
|
|
||||||
|
|
||||||
SmGui::FillWidth();
|
|
||||||
SmGui::ForceSync();
|
|
||||||
if (SmGui::Combo(CONCAT("##_hydrasdr_dev_sel_", _this->name), &_this->devId, _this->devices.txt)) {
|
|
||||||
_this->selectBySerial(_this->devices[_this->devId]);
|
|
||||||
core::setInputSampleRate(_this->sampleRate);
|
|
||||||
if (_this->selectedSerStr != "") {
|
|
||||||
config.acquire();
|
|
||||||
config.conf["device"] = _this->selectedSerStr;
|
|
||||||
config.release(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SmGui::Combo(CONCAT("##_hydrasdr_sr_sel_", _this->name), &_this->srId, _this->samplerates.txt)) {
|
|
||||||
_this->sampleRate = _this->samplerates[_this->srId];
|
|
||||||
core::setInputSampleRate(_this->sampleRate);
|
|
||||||
if (_this->selectedSerStr != "") {
|
|
||||||
config.acquire();
|
|
||||||
config.conf["devices"][_this->selectedSerStr]["sampleRate"] = _this->samplerates.key(_this->srId);
|
|
||||||
config.release(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SmGui::SameLine();
|
|
||||||
SmGui::FillWidth();
|
|
||||||
SmGui::ForceSync();
|
|
||||||
if (SmGui::Button(CONCAT("Refresh##_hydrasdr_refr_", _this->name))) {
|
|
||||||
_this->refresh();
|
|
||||||
config.acquire();
|
|
||||||
std::string devSerial = config.conf["device"];
|
|
||||||
config.release();
|
|
||||||
_this->selectByString(devSerial);
|
|
||||||
core::setInputSampleRate(_this->sampleRate);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_this->running) { SmGui::EndDisabled(); }
|
|
||||||
|
|
||||||
SmGui::LeftLabel("Antenna Port");
|
|
||||||
SmGui::FillWidth();
|
|
||||||
if (SmGui::Combo(CONCAT("##_hydrasdr_port_", _this->name), &_this->portId, _this->ports.txt)) {
|
|
||||||
if (_this->running) {
|
|
||||||
hydrasdr_set_rf_port(_this->openDev, _this->ports[_this->portId]);
|
|
||||||
}
|
|
||||||
if (_this->selectedSerStr != "") {
|
|
||||||
config.acquire();
|
|
||||||
config.conf["devices"][_this->selectedSerStr]["port"] = _this->ports.key(_this->portId);
|
|
||||||
config.release(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SmGui::BeginGroup();
|
|
||||||
SmGui::Columns(3, CONCAT("HydraSDRGainModeColumns##_", _this->name), false);
|
|
||||||
SmGui::ForceSync();
|
|
||||||
if (SmGui::RadioButton(CONCAT("Sensitive##_hydrasdr_gm_", _this->name), _this->gainMode == 0)) {
|
|
||||||
_this->gainMode = 0;
|
|
||||||
if (_this->running) {
|
|
||||||
hydrasdr_set_lna_agc(_this->openDev, 0);
|
|
||||||
hydrasdr_set_mixer_agc(_this->openDev, 0);
|
|
||||||
hydrasdr_set_sensitivity_gain(_this->openDev, _this->sensitiveGain);
|
|
||||||
}
|
|
||||||
if (_this->selectedSerStr != "") {
|
|
||||||
config.acquire();
|
|
||||||
config.conf["devices"][_this->selectedSerStr]["gainMode"] = 0;
|
|
||||||
config.release(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SmGui::NextColumn();
|
|
||||||
SmGui::ForceSync();
|
|
||||||
if (SmGui::RadioButton(CONCAT("Linear##_hydrasdr_gm_", _this->name), _this->gainMode == 1)) {
|
|
||||||
_this->gainMode = 1;
|
|
||||||
if (_this->running) {
|
|
||||||
hydrasdr_set_lna_agc(_this->openDev, 0);
|
|
||||||
hydrasdr_set_mixer_agc(_this->openDev, 0);
|
|
||||||
hydrasdr_set_linearity_gain(_this->openDev, _this->linearGain);
|
|
||||||
}
|
|
||||||
if (_this->selectedSerStr != "") {
|
|
||||||
config.acquire();
|
|
||||||
config.conf["devices"][_this->selectedSerStr]["gainMode"] = 1;
|
|
||||||
config.release(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SmGui::NextColumn();
|
|
||||||
SmGui::ForceSync();
|
|
||||||
if (SmGui::RadioButton(CONCAT("Free##_hydrasdr_gm_", _this->name), _this->gainMode == 2)) {
|
|
||||||
_this->gainMode = 2;
|
|
||||||
if (_this->running) {
|
|
||||||
if (_this->lnaAgc) {
|
|
||||||
hydrasdr_set_lna_agc(_this->openDev, 1);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
hydrasdr_set_lna_agc(_this->openDev, 0);
|
|
||||||
hydrasdr_set_lna_gain(_this->openDev, _this->lnaGain);
|
|
||||||
}
|
|
||||||
if (_this->mixerAgc) {
|
|
||||||
hydrasdr_set_mixer_agc(_this->openDev, 1);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
hydrasdr_set_mixer_agc(_this->openDev, 0);
|
|
||||||
hydrasdr_set_mixer_gain(_this->openDev, _this->mixerGain);
|
|
||||||
}
|
|
||||||
hydrasdr_set_vga_gain(_this->openDev, _this->vgaGain);
|
|
||||||
}
|
|
||||||
if (_this->selectedSerStr != "") {
|
|
||||||
config.acquire();
|
|
||||||
config.conf["devices"][_this->selectedSerStr]["gainMode"] = 2;
|
|
||||||
config.release(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SmGui::Columns(1, CONCAT("EndHydraSDRGainModeColumns##_", _this->name), false);
|
|
||||||
SmGui::EndGroup();
|
|
||||||
|
|
||||||
// Gain menus
|
|
||||||
|
|
||||||
if (_this->gainMode == 0) {
|
|
||||||
SmGui::LeftLabel("Gain");
|
|
||||||
SmGui::FillWidth();
|
|
||||||
if (SmGui::SliderInt(CONCAT("##_hydrasdr_sens_gain_", _this->name), &_this->sensitiveGain, 0, 21)) {
|
|
||||||
if (_this->running) {
|
|
||||||
hydrasdr_set_sensitivity_gain(_this->openDev, _this->sensitiveGain);
|
|
||||||
}
|
|
||||||
if (_this->selectedSerStr != "") {
|
|
||||||
config.acquire();
|
|
||||||
config.conf["devices"][_this->selectedSerStr]["sensitiveGain"] = _this->sensitiveGain;
|
|
||||||
config.release(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (_this->gainMode == 1) {
|
|
||||||
SmGui::LeftLabel("Gain");
|
|
||||||
SmGui::FillWidth();
|
|
||||||
if (SmGui::SliderInt(CONCAT("##_hydrasdr_lin_gain_", _this->name), &_this->linearGain, 0, 21)) {
|
|
||||||
if (_this->running) {
|
|
||||||
hydrasdr_set_linearity_gain(_this->openDev, _this->linearGain);
|
|
||||||
}
|
|
||||||
if (_this->selectedSerStr != "") {
|
|
||||||
config.acquire();
|
|
||||||
config.conf["devices"][_this->selectedSerStr]["linearGain"] = _this->linearGain;
|
|
||||||
config.release(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (_this->gainMode == 2) {
|
|
||||||
// TODO: Switch to a table for alignment
|
|
||||||
if (_this->lnaAgc) { SmGui::BeginDisabled(); }
|
|
||||||
SmGui::LeftLabel("LNA Gain");
|
|
||||||
SmGui::FillWidth();
|
|
||||||
if (SmGui::SliderInt(CONCAT("##_hydrasdr_lna_gain_", _this->name), &_this->lnaGain, 0, 15)) {
|
|
||||||
if (_this->running) {
|
|
||||||
hydrasdr_set_lna_gain(_this->openDev, _this->lnaGain);
|
|
||||||
}
|
|
||||||
if (_this->selectedSerStr != "") {
|
|
||||||
config.acquire();
|
|
||||||
config.conf["devices"][_this->selectedSerStr]["lnaGain"] = _this->lnaGain;
|
|
||||||
config.release(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (_this->lnaAgc) { SmGui::EndDisabled(); }
|
|
||||||
|
|
||||||
if (_this->mixerAgc) { SmGui::BeginDisabled(); }
|
|
||||||
SmGui::LeftLabel("Mixer Gain");
|
|
||||||
SmGui::FillWidth();
|
|
||||||
if (SmGui::SliderInt(CONCAT("##_hydrasdr_mix_gain_", _this->name), &_this->mixerGain, 0, 15)) {
|
|
||||||
if (_this->running) {
|
|
||||||
hydrasdr_set_mixer_gain(_this->openDev, _this->mixerGain);
|
|
||||||
}
|
|
||||||
if (_this->selectedSerStr != "") {
|
|
||||||
config.acquire();
|
|
||||||
config.conf["devices"][_this->selectedSerStr]["mixerGain"] = _this->mixerGain;
|
|
||||||
config.release(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (_this->mixerAgc) { SmGui::EndDisabled(); }
|
|
||||||
|
|
||||||
SmGui::LeftLabel("VGA Gain");
|
|
||||||
SmGui::FillWidth();
|
|
||||||
if (SmGui::SliderInt(CONCAT("##_hydrasdr_vga_gain_", _this->name), &_this->vgaGain, 0, 15)) {
|
|
||||||
if (_this->running) {
|
|
||||||
hydrasdr_set_vga_gain(_this->openDev, _this->vgaGain);
|
|
||||||
}
|
|
||||||
if (_this->selectedSerStr != "") {
|
|
||||||
config.acquire();
|
|
||||||
config.conf["devices"][_this->selectedSerStr]["vgaGain"] = _this->vgaGain;
|
|
||||||
config.release(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// AGC Control
|
|
||||||
SmGui::ForceSync();
|
|
||||||
if (SmGui::Checkbox(CONCAT("LNA AGC##_hydrasdr_", _this->name), &_this->lnaAgc)) {
|
|
||||||
if (_this->running) {
|
|
||||||
if (_this->lnaAgc) {
|
|
||||||
hydrasdr_set_lna_agc(_this->openDev, 1);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
hydrasdr_set_lna_agc(_this->openDev, 0);
|
|
||||||
hydrasdr_set_lna_gain(_this->openDev, _this->lnaGain);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (_this->selectedSerStr != "") {
|
|
||||||
config.acquire();
|
|
||||||
config.conf["devices"][_this->selectedSerStr]["lnaAgc"] = _this->lnaAgc;
|
|
||||||
config.release(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SmGui::ForceSync();
|
|
||||||
if (SmGui::Checkbox(CONCAT("Mixer AGC##_hydrasdr_", _this->name), &_this->mixerAgc)) {
|
|
||||||
if (_this->running) {
|
|
||||||
if (_this->mixerAgc) {
|
|
||||||
hydrasdr_set_mixer_agc(_this->openDev, 1);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
hydrasdr_set_mixer_agc(_this->openDev, 0);
|
|
||||||
hydrasdr_set_mixer_gain(_this->openDev, _this->mixerGain);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (_this->selectedSerStr != "") {
|
|
||||||
config.acquire();
|
|
||||||
config.conf["devices"][_this->selectedSerStr]["mixerAgc"] = _this->mixerAgc;
|
|
||||||
config.release(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bias T
|
|
||||||
if (SmGui::Checkbox(CONCAT("Bias T##_hydrasdr_", _this->name), &_this->biasT)) {
|
|
||||||
if (_this->running) {
|
|
||||||
hydrasdr_set_rf_bias(_this->openDev, _this->biasT);
|
|
||||||
}
|
|
||||||
if (_this->selectedSerStr != "") {
|
|
||||||
config.acquire();
|
|
||||||
config.conf["devices"][_this->selectedSerStr]["biasT"] = _this->biasT;
|
|
||||||
config.release(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
char valStr[256];
|
|
||||||
char regStr[256];
|
|
||||||
|
|
||||||
static int callback(hydrasdr_transfer_t* transfer) {
|
|
||||||
HydraSDRSourceModule* _this = (HydraSDRSourceModule*)transfer->ctx;
|
|
||||||
memcpy(_this->stream.writeBuf, transfer->samples, transfer->sample_count * sizeof(dsp::complex_t));
|
|
||||||
if (!_this->stream.swap(transfer->sample_count)) { return -1; }
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string name;
|
|
||||||
hydrasdr_device* openDev;
|
|
||||||
bool enabled = true;
|
|
||||||
dsp::stream<dsp::complex_t> stream;
|
|
||||||
double sampleRate;
|
|
||||||
SourceManager::SourceHandler handler;
|
|
||||||
bool running = false;
|
|
||||||
double freq;
|
|
||||||
uint64_t selectedSerial = 0;
|
|
||||||
std::string selectedSerStr = "";
|
|
||||||
int devId = 0;
|
|
||||||
int srId = 0;
|
|
||||||
int portId = 0;
|
|
||||||
|
|
||||||
bool biasT = false;
|
|
||||||
|
|
||||||
int lnaGain = 0;
|
|
||||||
int vgaGain = 0;
|
|
||||||
int mixerGain = 0;
|
|
||||||
int linearGain = 0;
|
|
||||||
int sensitiveGain = 0;
|
|
||||||
|
|
||||||
int gainMode = 0;
|
|
||||||
|
|
||||||
bool lnaAgc = false;
|
|
||||||
bool mixerAgc = false;
|
|
||||||
|
|
||||||
#ifdef __ANDROID__
|
|
||||||
int devFd = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
OptionList<std::string, uint64_t> devices;
|
|
||||||
OptionList<uint32_t, uint32_t> samplerates;
|
|
||||||
OptionList<std::string, hydrasdr_rf_port_t> ports;
|
|
||||||
};
|
|
||||||
|
|
||||||
MOD_EXPORT void _INIT_() {
|
|
||||||
json def = json({});
|
|
||||||
def["devices"] = json({});
|
|
||||||
def["device"] = "";
|
|
||||||
config.setPath(core::args["root"].s() + "/hydrasdr_config.json");
|
|
||||||
config.load(def);
|
|
||||||
config.enableAutoSave();
|
|
||||||
}
|
|
||||||
|
|
||||||
MOD_EXPORT ModuleManager::Instance* _CREATE_INSTANCE_(std::string name) {
|
|
||||||
return new HydraSDRSourceModule(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
MOD_EXPORT void _DELETE_INSTANCE_(ModuleManager::Instance* instance) {
|
|
||||||
delete (HydraSDRSourceModule*)instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
MOD_EXPORT void _END_() {
|
|
||||||
config.disableAutoSave();
|
|
||||||
config.save();
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user