mirror of
https://github.com/AlexandreRouma/SDRPlusPlus.git
synced 2025-07-08 18:15:21 +02:00
Compare commits
13 Commits
5ab3428b90
...
debug
Author | SHA1 | Date | |
---|---|---|---|
15112c63b7 | |||
115cb23672 | |||
101f6777ee | |||
82a2a4c04a | |||
c4086f5719 | |||
5f77718d75 | |||
e613087e97 | |||
beb18972ea | |||
1b0a5ed88e | |||
b1ad7590cc | |||
9537ccf2d2 | |||
0ac1bd56bc | |||
936c99dc40 |
47
.github/workflows/build_all.yml
vendored
47
.github/workflows/build_all.yml
vendored
@ -36,13 +36,6 @@ jobs:
|
|||||||
working-directory: ${{runner.workspace}}
|
working-directory: ${{runner.workspace}}
|
||||||
run: 7z x libusb.7z -olibusb_old ; rm "C:/Program Files/PothosSDR/bin/libusb-1.0.dll" ; cp "libusb_old/MS64/dll/libusb-1.0.dll" "C:/Program Files/PothosSDR/bin/" ; rm "C:/Program Files/PothosSDR/lib/libusb-1.0.lib" ; cp "libusb_old/MS64/dll/libusb-1.0.lib" "C:/Program Files/PothosSDR/lib/"
|
run: 7z x libusb.7z -olibusb_old ; rm "C:/Program Files/PothosSDR/bin/libusb-1.0.dll" ; cp "libusb_old/MS64/dll/libusb-1.0.dll" "C:/Program Files/PothosSDR/bin/" ; rm "C:/Program Files/PothosSDR/lib/libusb-1.0.lib" ; cp "libusb_old/MS64/dll/libusb-1.0.lib" "C:/Program Files/PothosSDR/lib/"
|
||||||
|
|
||||||
- name: Download librtlsdr
|
|
||||||
run: Invoke-WebRequest -Uri "https://ftp.osmocom.org/binaries/windows/rtl-sdr/rtl-sdr-64bit-20240623.zip" -OutFile ${{runner.workspace}}/rtl-sdr.zip
|
|
||||||
|
|
||||||
- name: Patch Pothos with newer librtlsdr version
|
|
||||||
working-directory: ${{runner.workspace}}
|
|
||||||
run: 7z x rtl-sdr.zip ; rm "C:/Program Files/PothosSDR/bin/rtlsdr.dll" ; cp "rtl-sdr-64bit-20240623/librtlsdr.dll" "C:/Program Files/PothosSDR/bin/rtlsdr.dll"
|
|
||||||
|
|
||||||
- name: Download SDRPlay API
|
- name: Download SDRPlay API
|
||||||
run: Invoke-WebRequest -Uri "https://www.sdrpp.org/SDRplay.zip" -OutFile ${{runner.workspace}}/SDRplay.zip
|
run: Invoke-WebRequest -Uri "https://www.sdrpp.org/SDRplay.zip" -OutFile ${{runner.workspace}}/SDRplay.zip
|
||||||
|
|
||||||
@ -65,27 +58,25 @@ jobs:
|
|||||||
run: mkdir "C:/Program Files/codec2" ; mkdir "C:/Program Files/codec2/include" ; mkdir "C:/Program Files/codec2/include/codec2" ; mkdir "C:/Program Files/codec2/lib" ; cd "codec2" ; xcopy "src" "C:/Program Files/codec2/include" ; cd "build" ; xcopy "src" "C:/Program Files/codec2/lib" ; xcopy "codec2" "C:/Program Files/codec2/include/codec2"
|
run: mkdir "C:/Program Files/codec2" ; mkdir "C:/Program Files/codec2/include" ; mkdir "C:/Program Files/codec2/include/codec2" ; mkdir "C:/Program Files/codec2/lib" ; cd "codec2" ; xcopy "src" "C:/Program Files/codec2/include" ; cd "build" ; xcopy "src" "C:/Program Files/codec2/lib" ; xcopy "codec2" "C:/Program Files/codec2/include/codec2"
|
||||||
|
|
||||||
- name: Install vcpkg dependencies
|
- name: Install vcpkg dependencies
|
||||||
run: vcpkg install fftw3:x64-windows glfw3:x64-windows portaudio:x64-windows zstd:x64-windows libusb:x64-windows spdlog:x64-windows
|
run: vcpkg install fftw3:x64-windows glfw3:x64-windows portaudio:x64-windows zstd:x64-windows libusb:x64-windows
|
||||||
|
|
||||||
- name: Install rtaudio
|
- name: Install rtaudio
|
||||||
run: git clone https://github.com/thestk/rtaudio ; cd rtaudio ; git checkout 2f2fca4502d506abc50f6d4473b2836d24cfb1e3 ; mkdir build ; cd build ; cmake .. ; cmake --build . --config Release ; cmake --install .
|
run: git clone https://github.com/thestk/rtaudio ; cd rtaudio ; git checkout 2f2fca4502d506abc50f6d4473b2836d24cfb1e3 ; mkdir build ; cd build ; cmake .. ; cmake --build . --config Release ; cmake --install .
|
||||||
|
|
||||||
- name: Install libperseus-sdr
|
- 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
|
|
||||||
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 .
|
|
||||||
|
|
||||||
- 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: 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
|
run: cmake "$Env:GITHUB_WORKSPACE" "-DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake" -DCMAKE_BUILD_TYPE=Debug -DCOPY_MSVC_REDISTRIBUTABLES=ON -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_PERSEUS_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
working-directory: ${{runner.workspace}}/build
|
working-directory: ${{runner.workspace}}/build
|
||||||
run: cmake --build . --config Release --verbose
|
run: cmake --build . --config Debug --verbose
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
working-directory: ${{runner.workspace}}/build
|
||||||
|
run: ./Debug/min_broken.exe
|
||||||
|
|
||||||
- name: Create Archive
|
- name: Create Archive
|
||||||
working-directory: ${{runner.workspace}}
|
working-directory: ${{runner.workspace}}
|
||||||
@ -107,7 +98,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
|
run: brew install pkg-config libusb fftw glfw airspy airspyhf portaudio hackrf libbladerf codec2 zstd autoconf automake libtool && pip3 install mako
|
||||||
|
|
||||||
- name: Install volk
|
- name: Install volk
|
||||||
run: git clone --recursive https://github.com/gnuradio/volk && cd volk && mkdir build && cd build && cmake -DCMAKE_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 ../../
|
||||||
@ -125,20 +116,14 @@ jobs:
|
|||||||
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 ../../
|
||||||
|
|
||||||
- name: Install libperseus
|
- name: Install libperseus
|
||||||
run: git clone https://github.com/Microtelecom/libperseus-sdr && cd libperseus-sdr && autoreconf -i && ./configure --prefix=/usr/local && make && sudo make install && cd ..
|
run: git clone https://github.com/Microtelecom/libperseus-sdr && cd libperseus-sdr && autoreconf -i && ./configure --prefix=/usr/local && make && make install && cd ..
|
||||||
|
|
||||||
- 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 ..
|
|
||||||
|
|
||||||
- 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: Prepare CMake
|
- name: Prepare CMake
|
||||||
working-directory: ${{runner.workspace}}/build
|
working-directory: ${{runner.workspace}}/build
|
||||||
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 -DOPT_BUILD_FOBOSSDR_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 -DUSE_BUNDLE_DEFAULTS=ON -DCMAKE_BUILD_TYPE=Release
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
working-directory: ${{runner.workspace}}/build
|
working-directory: ${{runner.workspace}}/build
|
||||||
@ -164,7 +149,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 && pip3 install mako --break-system-packages
|
||||||
|
|
||||||
- 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 ../../
|
||||||
@ -184,18 +169,12 @@ jobs:
|
|||||||
# - name: Install libperseus
|
# - name: Install libperseus
|
||||||
# run: git clone https://github.com/Microtelecom/libperseus-sdr && cd libperseus-sdr && autoreconf -i && ./configure --prefix=/usr/local && make && make install && cd ..
|
# run: git clone https://github.com/Microtelecom/libperseus-sdr && cd libperseus-sdr && autoreconf -i && ./configure --prefix=/usr/local && make && make install && cd ..
|
||||||
|
|
||||||
- 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 ..
|
|
||||||
|
|
||||||
- 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: Prepare CMake
|
- name: Prepare CMake
|
||||||
working-directory: ${{runner.workspace}}/build
|
working-directory: ${{runner.workspace}}/build
|
||||||
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 -DOPT_BUILD_FOBOSSDR_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 -DUSE_BUNDLE_DEFAULTS=ON -DCMAKE_BUILD_TYPE=Release
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
working-directory: ${{runner.workspace}}/build
|
working-directory: ${{runner.workspace}}/build
|
||||||
|
@ -15,11 +15,8 @@ option(OPT_BUILD_AUDIO_SOURCE "Build Audio Source Module (Dependencies: rtaudio)
|
|||||||
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_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_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_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)
|
||||||
@ -45,14 +42,12 @@ option(OPT_BUILD_PORTAUDIO_SINK "Build PortAudio Sink Module (Dependencies: port
|
|||||||
|
|
||||||
# Decoders
|
# Decoders
|
||||||
option(OPT_BUILD_ATV_DECODER "Build ATV decoder (no dependencies required)" OFF)
|
option(OPT_BUILD_ATV_DECODER "Build ATV decoder (no dependencies required)" OFF)
|
||||||
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)
|
||||||
option(OPT_BUILD_METEOR_DEMODULATOR "Build the meteor demodulator module (no dependencies required)" ON)
|
option(OPT_BUILD_METEOR_DEMODULATOR "Build the meteor demodulator module (no dependencies required)" ON)
|
||||||
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_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
|
||||||
@ -145,26 +140,14 @@ 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)
|
||||||
|
|
||||||
if (OPT_BUILD_HAROGIC_SOURCE)
|
|
||||||
add_subdirectory("source_modules/harogic_source")
|
|
||||||
endif (OPT_BUILD_HAROGIC_SOURCE)
|
|
||||||
|
|
||||||
if (OPT_BUILD_HERMES_SOURCE)
|
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_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)
|
||||||
@ -253,10 +236,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)
|
||||||
@ -281,10 +260,6 @@ if (OPT_BUILD_RADIO)
|
|||||||
add_subdirectory("decoder_modules/radio")
|
add_subdirectory("decoder_modules/radio")
|
||||||
endif (OPT_BUILD_RADIO)
|
endif (OPT_BUILD_RADIO)
|
||||||
|
|
||||||
if (OPT_BUILD_RYFI_DECODER)
|
|
||||||
add_subdirectory("decoder_modules/ryfi_decoder")
|
|
||||||
endif (OPT_BUILD_RYFI_DECODER)
|
|
||||||
|
|
||||||
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)
|
||||||
@ -325,6 +300,7 @@ endif (OPT_BUILD_SCHEDULER)
|
|||||||
|
|
||||||
if (MSVC)
|
if (MSVC)
|
||||||
add_executable(sdrpp "src/main.cpp" "win32/resources.rc")
|
add_executable(sdrpp "src/main.cpp" "win32/resources.rc")
|
||||||
|
add_executable(min_broken "min_broken/main.cpp" "win32/resources.rc")
|
||||||
else ()
|
else ()
|
||||||
add_executable(sdrpp "src/main.cpp")
|
add_executable(sdrpp "src/main.cpp")
|
||||||
endif ()
|
endif ()
|
||||||
@ -333,12 +309,13 @@ target_link_libraries(sdrpp PRIVATE sdrpp_core)
|
|||||||
|
|
||||||
# Compiler arguments
|
# Compiler arguments
|
||||||
target_compile_options(sdrpp PRIVATE ${SDRPP_COMPILER_FLAGS})
|
target_compile_options(sdrpp PRIVATE ${SDRPP_COMPILER_FLAGS})
|
||||||
|
target_compile_options(min_broken PRIVATE ${SDRPP_COMPILER_FLAGS})
|
||||||
|
|
||||||
# Copy dynamic libs over
|
# Copy dynamic libs over
|
||||||
if (MSVC)
|
if (MSVC)
|
||||||
add_custom_target(do_always ALL xcopy /s \"$<TARGET_FILE_DIR:sdrpp_core>\\*.dll\" \"$<TARGET_FILE_DIR:sdrpp>\" /Y)
|
add_custom_target(do_always ALL xcopy /s \"$<TARGET_FILE_DIR:sdrpp_core>\\*.dll\" \"$<TARGET_FILE_DIR:sdrpp>\" /Y)
|
||||||
add_custom_target(do_always_volk ALL xcopy /s \"C:/Program Files/PothosSDR/bin\\volk.dll\" \"$<TARGET_FILE_DIR:sdrpp>\" /Y)
|
add_custom_target(do_always_volk ALL xcopy /s \"C:/Program Files/PothosSDR/bin\\volk.dll\" \"$<TARGET_FILE_DIR:sdrpp>\" /Y)
|
||||||
|
|
||||||
if (COPY_MSVC_REDISTRIBUTABLES)
|
if (COPY_MSVC_REDISTRIBUTABLES)
|
||||||
# Get the list of Visual C++ runtime DLLs
|
# Get the list of Visual C++ runtime DLLs
|
||||||
set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_SKIP True)
|
set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_SKIP True)
|
||||||
@ -355,7 +332,6 @@ if (MSVC)
|
|||||||
endif ()
|
endif ()
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
|
|
||||||
if (${CMAKE_SYSTEM_NAME} MATCHES "OpenBSD")
|
if (${CMAKE_SYSTEM_NAME} MATCHES "OpenBSD")
|
||||||
add_custom_target(do_always ALL cp \"$<TARGET_FILE_DIR:sdrpp_core>/libsdrpp_core.so\" \"$<TARGET_FILE_DIR:sdrpp>\")
|
add_custom_target(do_always ALL cp \"$<TARGET_FILE_DIR:sdrpp_core>/libsdrpp_core.so\" \"$<TARGET_FILE_DIR:sdrpp>\")
|
||||||
endif ()
|
endif ()
|
||||||
@ -393,6 +369,4 @@ 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
|
|
@ -173,24 +173,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"]["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"]["RFNM Source"]["module"] = "rfnm_source";
|
defConfig["moduleInstances"]["PerseusSDR Source"]["module"] = "perseus_source";
|
||||||
defConfig["moduleInstances"]["RFNM Source"]["enabled"] = true;
|
defConfig["moduleInstances"]["PerseusSDR Source"]["enabled"] = true;
|
||||||
defConfig["moduleInstances"]["RFspace Source"]["module"] = "rfspace_source";
|
defConfig["moduleInstances"]["RFspace Source"]["module"] = "rfspace_source";
|
||||||
defConfig["moduleInstances"]["RFspace Source"]["enabled"] = true;
|
defConfig["moduleInstances"]["RFspace Source"]["enabled"] = true;
|
||||||
defConfig["moduleInstances"]["RTL-SDR Source"]["module"] = "rtl_sdr_source";
|
defConfig["moduleInstances"]["RTL-SDR Source"]["module"] = "rtl_sdr_source";
|
||||||
@ -201,12 +193,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";
|
||||||
|
@ -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"
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <volk/volk.h>
|
#include <volk/volk.h>
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
namespace dsp::buffer {
|
namespace dsp::buffer {
|
||||||
template<class T>
|
template<class T>
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <volk/volk.h>
|
#include <volk/volk.h>
|
||||||
#include "../buffer/buffer.h"
|
|
||||||
|
|
||||||
namespace dsp {
|
namespace dsp {
|
||||||
template<class T>
|
template<class T>
|
||||||
|
@ -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;
|
||||||
|
@ -52,4 +52,15 @@ namespace ImGui {
|
|||||||
bufferMtx.unlock();
|
bufferMtx.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SymbolDiagram::setCount(int count) {
|
||||||
|
std::lock_guard<std::mutex> lck(bufferMtx);
|
||||||
|
delete[] buffer;
|
||||||
|
buffer = new float[count];
|
||||||
|
sampleCount = count;
|
||||||
|
memset(buffer, 0, sampleCount * sizeof(float));
|
||||||
|
}
|
||||||
|
|
||||||
|
int SymbolDiagram::getCount() {
|
||||||
|
return sampleCount;
|
||||||
|
}
|
||||||
}
|
}
|
@ -18,6 +18,10 @@ namespace ImGui {
|
|||||||
|
|
||||||
void releaseBuffer();
|
void releaseBuffer();
|
||||||
|
|
||||||
|
void setCount(int count);
|
||||||
|
|
||||||
|
int getCount();
|
||||||
|
|
||||||
std::vector<float> lines;
|
std::vector<float> lines;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -110,7 +110,7 @@ namespace ImGui {
|
|||||||
viewBandwidth = 1.0;
|
viewBandwidth = 1.0;
|
||||||
wholeBandwidth = 1.0;
|
wholeBandwidth = 1.0;
|
||||||
|
|
||||||
updatePallette(DEFAULT_COLOR_MAP, 13);
|
//updatePallette(DEFAULT_COLOR_MAP, 13);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WaterFall::init() {
|
void WaterFall::init() {
|
||||||
|
@ -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,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
|
|
@ -8,15 +8,15 @@
|
|||||||
#include "dsp.h"
|
#include "dsp.h"
|
||||||
#include "pocsag.h"
|
#include "pocsag.h"
|
||||||
|
|
||||||
#define BAUDRATE 2400
|
|
||||||
#define SAMPLERATE (BAUDRATE*10)
|
|
||||||
|
|
||||||
class POCSAGDecoder : public Decoder {
|
class POCSAGDecoder : public Decoder {
|
||||||
public:
|
public:
|
||||||
POCSAGDecoder(const std::string& name, VFOManager::VFO* vfo) : diag(0.6, BAUDRATE) {
|
POCSAGDecoder(const std::string& name, VFOManager::VFO* vfo) : diag(0.6, 2400) {
|
||||||
this->name = name;
|
this->name = name;
|
||||||
this->vfo = vfo;
|
this->vfo = vfo;
|
||||||
|
|
||||||
|
// Default baudrate (TODO: Load from config)
|
||||||
|
baudrate = 2400;
|
||||||
|
|
||||||
// Define baudrate options
|
// Define baudrate options
|
||||||
baudrates.define(512, "512 Baud", 512);
|
baudrates.define(512, "512 Baud", 512);
|
||||||
baudrates.define(1200, "1200 Baud", 1200);
|
baudrates.define(1200, "1200 Baud", 1200);
|
||||||
@ -24,9 +24,9 @@ public:
|
|||||||
|
|
||||||
// Init DSP
|
// Init DSP
|
||||||
vfo->setBandwidthLimits(12500, 12500, true);
|
vfo->setBandwidthLimits(12500, 12500, true);
|
||||||
vfo->setSampleRate(SAMPLERATE, 12500);
|
vfo->setSampleRate(baudrate*10.0, 12500);
|
||||||
dsp.init(vfo->output, SAMPLERATE, BAUDRATE);
|
dsp.init(vfo->output, baudrate*10.0, baudrate);
|
||||||
reshape.init(&dsp.soft, BAUDRATE, (BAUDRATE / 30.0) - BAUDRATE);
|
reshape.init(&dsp.soft, baudrate, (baudrate / 30.0) - baudrate);
|
||||||
dataHandler.init(&dsp.out, _dataHandler, this);
|
dataHandler.init(&dsp.out, _dataHandler, this);
|
||||||
diagHandler.init(&reshape.out, _diagHandler, this);
|
diagHandler.init(&reshape.out, _diagHandler, this);
|
||||||
|
|
||||||
@ -42,7 +42,7 @@ public:
|
|||||||
ImGui::LeftLabel("Baudrate");
|
ImGui::LeftLabel("Baudrate");
|
||||||
ImGui::FillWidth();
|
ImGui::FillWidth();
|
||||||
if (ImGui::Combo(("##pager_decoder_pocsag_br_" + name).c_str(), &brId, baudrates.txt)) {
|
if (ImGui::Combo(("##pager_decoder_pocsag_br_" + name).c_str(), &brId, baudrates.txt)) {
|
||||||
// TODO
|
setBaudrate(baudrates.value(brId));
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::FillWidth();
|
ImGui::FillWidth();
|
||||||
@ -79,7 +79,8 @@ private:
|
|||||||
static void _diagHandler(float* data, int count, void* ctx) {
|
static void _diagHandler(float* data, int count, void* ctx) {
|
||||||
POCSAGDecoder* _this = (POCSAGDecoder*)ctx;
|
POCSAGDecoder* _this = (POCSAGDecoder*)ctx;
|
||||||
float* buf = _this->diag.acquireBuffer();
|
float* buf = _this->diag.acquireBuffer();
|
||||||
memcpy(buf, data, count * sizeof(float));
|
int maxCount = std::min<int>(count, _this->diag.getCount());
|
||||||
|
memcpy(buf, data, maxCount * sizeof(float));
|
||||||
_this->diag.releaseBuffer();
|
_this->diag.releaseBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,6 +88,15 @@ private:
|
|||||||
flog::debug("[{}]: '{}'", (uint32_t)addr, msg);
|
flog::debug("[{}]: '{}'", (uint32_t)addr, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setBaudrate(double baudrate) {
|
||||||
|
vfo->setSampleRate(baudrate*10.0, 12500);
|
||||||
|
stop();
|
||||||
|
reshape.setKeep(baudrate);
|
||||||
|
reshape.setSkip((baudrate / 30.0) - baudrate);
|
||||||
|
diag.setCount(baudrate);
|
||||||
|
start();
|
||||||
|
}
|
||||||
|
|
||||||
std::string name;
|
std::string name;
|
||||||
VFOManager::VFO* vfo;
|
VFOManager::VFO* vfo;
|
||||||
|
|
||||||
@ -100,6 +110,7 @@ private:
|
|||||||
ImGui::SymbolDiagram diag;
|
ImGui::SymbolDiagram diag;
|
||||||
|
|
||||||
int brId = 2;
|
int brId = 2;
|
||||||
|
double baudrate = 2400;
|
||||||
|
|
||||||
OptionList<int, int> baudrates;
|
OptionList<int, int> baudrates;
|
||||||
};
|
};
|
@ -1,8 +0,0 @@
|
|||||||
cmake_minimum_required(VERSION 3.13)
|
|
||||||
project(ryfi_decoder)
|
|
||||||
|
|
||||||
file(GLOB_RECURSE SRC "src/*.cpp" "src/*.c")
|
|
||||||
|
|
||||||
include(${SDRPP_MODULE_CMAKE})
|
|
||||||
|
|
||||||
target_include_directories(ryfi_decoder PRIVATE "src/")
|
|
@ -1,139 +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/routing/splitter.h>
|
|
||||||
#include <dsp/buffer/reshaper.h>
|
|
||||||
#include <dsp/sink/handler_sink.h>
|
|
||||||
#include <gui/widgets/folder_select.h>
|
|
||||||
#include <gui/widgets/constellation_diagram.h>
|
|
||||||
#include "ryfi/receiver.h"
|
|
||||||
|
|
||||||
#define CONCAT(a, b) ((std::string(a) + b).c_str())
|
|
||||||
|
|
||||||
SDRPP_MOD_INFO{
|
|
||||||
/* Name: */ "ryfi_decoder",
|
|
||||||
/* Description: */ "RyFi decoder for SDR++",
|
|
||||||
/* Author: */ "Ryzerth",
|
|
||||||
/* Version: */ 0, 1, 0,
|
|
||||||
/* Max instances */ -1
|
|
||||||
};
|
|
||||||
|
|
||||||
#define INPUT_BANDWIDTH 600e3
|
|
||||||
#define INPUT_SAMPLE_RATE 1000e3
|
|
||||||
#define INPUT_BAUDRATE 500e3
|
|
||||||
|
|
||||||
#define SYMBOL_DIAG_RATE 30
|
|
||||||
#define SYMBOL_DIAG_COUNT 1024
|
|
||||||
|
|
||||||
class RyFiDecoderModule : public ModuleManager::Instance {
|
|
||||||
public:
|
|
||||||
RyFiDecoderModule(std::string name) {
|
|
||||||
this->name = name;
|
|
||||||
|
|
||||||
vfo = sigpath::vfoManager.createVFO(name, ImGui::WaterfallVFO::REF_CENTER, 0, INPUT_BANDWIDTH, INPUT_SAMPLE_RATE, INPUT_BANDWIDTH, INPUT_BANDWIDTH, true);
|
|
||||||
rx.init(vfo->output, INPUT_BAUDRATE, INPUT_SAMPLE_RATE);
|
|
||||||
reshape.init(rx.softOut, SYMBOL_DIAG_COUNT, (INPUT_BAUDRATE / SYMBOL_DIAG_RATE) - SYMBOL_DIAG_COUNT);
|
|
||||||
symSink.init(&reshape.out, symSinkHandler, this);
|
|
||||||
rx.onPacket.bind(&RyFiDecoderModule::packetHandler, this);
|
|
||||||
|
|
||||||
rx.start();
|
|
||||||
reshape.start();
|
|
||||||
symSink.start();
|
|
||||||
|
|
||||||
gui::menu.registerEntry(name, menuHandler, this, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
~RyFiDecoderModule() {
|
|
||||||
rx.stop();
|
|
||||||
reshape.stop();
|
|
||||||
symSink.stop();
|
|
||||||
sigpath::vfoManager.deleteVFO(vfo);
|
|
||||||
gui::menu.removeEntry(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), INPUT_BANDWIDTH, INPUT_SAMPLE_RATE, INPUT_BANDWIDTH, INPUT_BANDWIDTH, true);
|
|
||||||
|
|
||||||
rx.setInput(vfo->output);
|
|
||||||
|
|
||||||
rx.start();
|
|
||||||
reshape.start();
|
|
||||||
symSink.start();
|
|
||||||
|
|
||||||
enabled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void disable() {
|
|
||||||
rx.stop();
|
|
||||||
reshape.stop();
|
|
||||||
symSink.stop();
|
|
||||||
|
|
||||||
sigpath::vfoManager.deleteVFO(vfo);
|
|
||||||
enabled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isEnabled() {
|
|
||||||
return enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void packetHandler(ryfi::Packet pkt) {
|
|
||||||
flog::debug("Got a {} byte packet!", pkt.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
static void menuHandler(void* ctx) {
|
|
||||||
RyFiDecoderModule* _this = (RyFiDecoderModule*)ctx;
|
|
||||||
|
|
||||||
float menuWidth = ImGui::GetContentRegionAvail().x;
|
|
||||||
|
|
||||||
if (!_this->enabled) { style::beginDisabled(); }
|
|
||||||
|
|
||||||
ImGui::SetNextItemWidth(menuWidth);
|
|
||||||
_this->constDiagram.draw();
|
|
||||||
|
|
||||||
if (!_this->enabled) { style::endDisabled(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
static void symSinkHandler(dsp::complex_t* data, int count, void* ctx) {
|
|
||||||
RyFiDecoderModule* _this = (RyFiDecoderModule*)ctx;
|
|
||||||
|
|
||||||
dsp::complex_t* buf = _this->constDiagram.acquireBuffer();
|
|
||||||
memcpy(buf, data, 1024 * sizeof(dsp::complex_t));
|
|
||||||
_this->constDiagram.releaseBuffer();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string name;
|
|
||||||
bool enabled = true;
|
|
||||||
|
|
||||||
// DSP Chain
|
|
||||||
VFOManager::VFO* vfo;
|
|
||||||
ryfi::Receiver rx;
|
|
||||||
dsp::buffer::Reshaper<dsp::complex_t> reshape;
|
|
||||||
dsp::sink::Handler<dsp::complex_t> symSink;
|
|
||||||
|
|
||||||
ImGui::ConstellationDiagram constDiagram;
|
|
||||||
};
|
|
||||||
|
|
||||||
MOD_EXPORT void _INIT_() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
MOD_EXPORT ModuleManager::Instance* _CREATE_INSTANCE_(std::string name) {
|
|
||||||
return new RyFiDecoderModule(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
MOD_EXPORT void _DELETE_INSTANCE_(void* instance) {
|
|
||||||
delete (RyFiDecoderModule*)instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
MOD_EXPORT void _END_() {
|
|
||||||
|
|
||||||
}
|
|
@ -1,74 +0,0 @@
|
|||||||
#include "conv_codec.h"
|
|
||||||
|
|
||||||
namespace ryfi {
|
|
||||||
ConvEncoder::ConvEncoder(dsp::stream<uint8_t>* in) {
|
|
||||||
// Create the convolutional encoder instance
|
|
||||||
conv = correct_convolutional_create(2, 7, correct_conv_r12_7_polynomial);
|
|
||||||
|
|
||||||
// Init the base class
|
|
||||||
base_type::init(in);
|
|
||||||
}
|
|
||||||
|
|
||||||
ConvEncoder::~ConvEncoder() {
|
|
||||||
// Destroy the convolutional encoder instance
|
|
||||||
correct_convolutional_destroy(conv);
|
|
||||||
}
|
|
||||||
|
|
||||||
int ConvEncoder::encode(const uint8_t* in, uint8_t* out, int count) {
|
|
||||||
// Run convolutional encoder on the data
|
|
||||||
return correct_convolutional_encode(conv, in, count, out);
|
|
||||||
}
|
|
||||||
|
|
||||||
int ConvEncoder::run() {
|
|
||||||
int count = base_type::_in->read();
|
|
||||||
if (count < 0) { return -1; }
|
|
||||||
|
|
||||||
count = encode(base_type::_in->readBuf, base_type::out.writeBuf, count);
|
|
||||||
|
|
||||||
base_type::_in->flush();
|
|
||||||
if (!out.swap(count)) { return -1; }
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
ConvDecoder::ConvDecoder(dsp::stream<dsp::complex_t>* in) {
|
|
||||||
// Create the convolutional encoder instance
|
|
||||||
conv = correct_convolutional_create(2, 7, correct_conv_r12_7_polynomial);
|
|
||||||
|
|
||||||
// Allocate the soft symbol buffer
|
|
||||||
soft = dsp::buffer::alloc<uint8_t>(STREAM_BUFFER_SIZE);
|
|
||||||
|
|
||||||
// Init the base class
|
|
||||||
base_type::init(in);
|
|
||||||
}
|
|
||||||
|
|
||||||
ConvDecoder::~ConvDecoder() {
|
|
||||||
// Destroy the convolutional encoder instance
|
|
||||||
correct_convolutional_destroy(conv);
|
|
||||||
|
|
||||||
// Free the soft symbol buffer
|
|
||||||
dsp::buffer::free(soft);
|
|
||||||
}
|
|
||||||
|
|
||||||
int ConvDecoder::decode(const dsp::complex_t* in, uint8_t* out, int count) {
|
|
||||||
// Convert to uint8
|
|
||||||
const float* _in = (const float*)in;
|
|
||||||
count *= 2;
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
soft[i] = std::clamp<int>((_in[i] * 127.0f) + 128.0f, 0, 255);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run convolutional decoder on the data
|
|
||||||
return correct_convolutional_decode_soft(conv, soft, count, out);
|
|
||||||
}
|
|
||||||
|
|
||||||
int ConvDecoder::run() {
|
|
||||||
int count = base_type::_in->read();
|
|
||||||
if (count < 0) { return -1; }
|
|
||||||
|
|
||||||
count = decode(base_type::_in->readBuf, base_type::out.writeBuf, count);
|
|
||||||
|
|
||||||
base_type::_in->flush();
|
|
||||||
if (!out.swap(count)) { return -1; }
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,71 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
#include "dsp/processor.h"
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
#include "correct.h"
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace ryfi {
|
|
||||||
/**
|
|
||||||
* RyFi Convolutional Encoder.
|
|
||||||
*/
|
|
||||||
class ConvEncoder : public dsp::Processor<uint8_t, uint8_t> {
|
|
||||||
using base_type = dsp::Processor<uint8_t, uint8_t>;
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* Create a convolutional encoder specifying an input stream.
|
|
||||||
* @param in Input stream.
|
|
||||||
*/
|
|
||||||
ConvEncoder(dsp::stream<uint8_t>* in = NULL);
|
|
||||||
|
|
||||||
// Destructor
|
|
||||||
~ConvEncoder();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Encode data.
|
|
||||||
* @param in Input bytes.
|
|
||||||
* @param out Output bits.
|
|
||||||
* @param count Number of input bytes.
|
|
||||||
* @return Number of output bits.
|
|
||||||
*/
|
|
||||||
int encode(const uint8_t* in, uint8_t* out, int count);
|
|
||||||
|
|
||||||
private:
|
|
||||||
int run();
|
|
||||||
|
|
||||||
correct_convolutional* conv;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* RyFi Convolutional Decoder.
|
|
||||||
*/
|
|
||||||
class ConvDecoder : public dsp::Processor<dsp::complex_t, uint8_t> {
|
|
||||||
using base_type = dsp::Processor<dsp::complex_t, uint8_t>;
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* Create a convolutional encoder specifying an input stream.
|
|
||||||
* @param in Input stream.
|
|
||||||
*/
|
|
||||||
ConvDecoder(dsp::stream<dsp::complex_t>* in = NULL);
|
|
||||||
|
|
||||||
// Destructor
|
|
||||||
~ConvDecoder();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decode soft symbols.
|
|
||||||
* @param in Input soft symbols.
|
|
||||||
* @param out Output bytes.
|
|
||||||
* @param count Number of input bytes.
|
|
||||||
* @return Number of output bits.
|
|
||||||
*/
|
|
||||||
int decode(const dsp::complex_t* in, uint8_t* out, int count);
|
|
||||||
|
|
||||||
private:
|
|
||||||
int run();
|
|
||||||
|
|
||||||
correct_convolutional* conv;
|
|
||||||
uint8_t* soft = NULL;
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,37 +0,0 @@
|
|||||||
#include "frame.h"
|
|
||||||
|
|
||||||
namespace ryfi {
|
|
||||||
int Frame::serialize(uint8_t* bytes) const {
|
|
||||||
// Write the counter
|
|
||||||
bytes[0] = (counter >> 8) & 0xFF;
|
|
||||||
bytes[1] = counter & 0xFF;
|
|
||||||
|
|
||||||
// Write the first packet pointer
|
|
||||||
bytes[2] = (firstPacket >> 8) & 0xFF;
|
|
||||||
bytes[3] = firstPacket & 0xFF;
|
|
||||||
|
|
||||||
// Write the last packet pointer
|
|
||||||
bytes[4] = (lastPacket >> 8) & 0xFF;
|
|
||||||
bytes[5] = lastPacket & 0xFF;
|
|
||||||
|
|
||||||
// Write the data
|
|
||||||
memcpy(&bytes[6], content, FRAME_DATA_SIZE);
|
|
||||||
|
|
||||||
// Return the length of a serialized frame
|
|
||||||
return FRAME_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Frame::deserialize(const uint8_t* bytes, Frame& frame) {
|
|
||||||
// Read the counter
|
|
||||||
frame.counter = (((uint16_t)bytes[0]) << 8) | ((uint16_t)bytes[1]);
|
|
||||||
|
|
||||||
// Read the first packet pointer
|
|
||||||
frame.firstPacket = (((uint16_t)bytes[2]) << 8) | ((uint16_t)bytes[3]);
|
|
||||||
|
|
||||||
// Read the last packet pointer
|
|
||||||
frame.lastPacket = (((uint16_t)bytes[4]) << 8) | ((uint16_t)bytes[5]);
|
|
||||||
|
|
||||||
// Read the data
|
|
||||||
memcpy(frame.content, &bytes[6], FRAME_DATA_SIZE);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,42 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <stdint.h>
|
|
||||||
#include "rs_codec.h"
|
|
||||||
|
|
||||||
namespace ryfi {
|
|
||||||
enum PacketOffset {
|
|
||||||
PKT_OFFS_NONE = 0xFFFF
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Frame {
|
|
||||||
/**
|
|
||||||
* Serialize the frame to bytes.
|
|
||||||
* @param bytes Buffer to write the serialized frame to.
|
|
||||||
*/
|
|
||||||
int serialize(uint8_t* bytes) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deserialize a frame from bytes.
|
|
||||||
* @param bytes Buffer to deserialize the frame from.
|
|
||||||
* @param frame Object that will contain the deserialize frame.
|
|
||||||
*/
|
|
||||||
static void deserialize(const uint8_t* bytes, Frame& frame);
|
|
||||||
|
|
||||||
// Size of a serialized frame
|
|
||||||
static inline const int FRAME_SIZE = RS_BLOCK_DEC_SIZE*RS_BLOCK_COUNT;
|
|
||||||
|
|
||||||
// Size of the data area of the frame
|
|
||||||
static inline const int FRAME_DATA_SIZE = FRAME_SIZE - 6;
|
|
||||||
|
|
||||||
// Steadily increasing counter.
|
|
||||||
uint16_t counter = 0;
|
|
||||||
|
|
||||||
// Byte offset of the first packet in the frame.
|
|
||||||
uint16_t firstPacket = 0;
|
|
||||||
|
|
||||||
// Byte offset of the last packet in the frame.
|
|
||||||
uint16_t lastPacket = 0;
|
|
||||||
|
|
||||||
// Data area of the frame.
|
|
||||||
uint8_t content[FRAME_DATA_SIZE];
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,137 +0,0 @@
|
|||||||
#include "framing.h"
|
|
||||||
|
|
||||||
namespace ryfi {
|
|
||||||
dsp::complex_t QPSK_SYMBOLS[4] = {
|
|
||||||
{ -0.070710678118f, -0.070710678118f },
|
|
||||||
{ -0.070710678118f, 0.070710678118f },
|
|
||||||
{ 0.070710678118f, -0.070710678118f },
|
|
||||||
{ 0.070710678118f, 0.070710678118f },
|
|
||||||
};
|
|
||||||
|
|
||||||
Framer::Framer(dsp::stream<uint8_t>* in) {
|
|
||||||
// Generate the sync symbols
|
|
||||||
int k = 0;
|
|
||||||
for (int i = 62; i >= 0; i -= 2) {
|
|
||||||
syncSyms[k++] = QPSK_SYMBOLS[(SYNC_WORD >> i) & 0b11];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Initialize base class
|
|
||||||
base_type::init(in);
|
|
||||||
}
|
|
||||||
|
|
||||||
int Framer::encode(const uint8_t* in, dsp::complex_t* out, int count) {
|
|
||||||
// Copy sync symbols
|
|
||||||
memcpy(out, syncSyms, SYNC_SYMS*sizeof(dsp::complex_t));
|
|
||||||
|
|
||||||
// Modulate the rest of the bits
|
|
||||||
dsp::complex_t* dataOut = &out[SYNC_SYMS];
|
|
||||||
int dataSyms = count / 2;
|
|
||||||
for (int i = 0; i < dataSyms; i++) {
|
|
||||||
uint8_t bits = (in[i >> 2] >> (6 - 2*(i & 0b11))) & 0b11;
|
|
||||||
dataOut[i] = QPSK_SYMBOLS[bits];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compute and return the total number of symbols
|
|
||||||
return SYNC_SYMS + dataSyms;
|
|
||||||
}
|
|
||||||
|
|
||||||
int Framer::run() {
|
|
||||||
int count = base_type::_in->read();
|
|
||||||
if (count < 0) { return -1; }
|
|
||||||
|
|
||||||
count = encode(base_type::_in->readBuf, base_type::out.writeBuf, count);
|
|
||||||
|
|
||||||
base_type::_in->flush();
|
|
||||||
if (!out.swap(count)) { return -1; }
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
Deframer::Deframer(dsp::stream<dsp::complex_t> *in) {
|
|
||||||
// Compute sync word rotations
|
|
||||||
// 0: 00 01 11 10
|
|
||||||
// 90: 10 00 01 11
|
|
||||||
// 180: 11 10 00 01
|
|
||||||
// 270: 01 11 10 00
|
|
||||||
|
|
||||||
// For 0 and 180 it's the sync and its complement
|
|
||||||
syncRots[ROT_0_DEG] = SYNC_WORD;
|
|
||||||
syncRots[ROT_180_DEG] = ~SYNC_WORD;
|
|
||||||
|
|
||||||
// For 90 and 270 its the quadrature and its complement
|
|
||||||
uint64_t quad;
|
|
||||||
for (int i = 62; i >= 0; i -= 2) {
|
|
||||||
// Get the symbol
|
|
||||||
uint8_t sym = (SYNC_WORD >> i) & 0b11;
|
|
||||||
|
|
||||||
// Rotate it 90 degrees
|
|
||||||
uint8_t rsym;
|
|
||||||
switch (sym) {
|
|
||||||
case 0b00: rsym = 0b10; break;
|
|
||||||
case 0b01: rsym = 0b00; break;
|
|
||||||
case 0b11: rsym = 0b01; break;
|
|
||||||
case 0b10: rsym = 0b11; break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Push it into the quadrature
|
|
||||||
quad = (quad << 2) | rsym;
|
|
||||||
}
|
|
||||||
syncRots[ROT_90_DEG] = quad;
|
|
||||||
syncRots[ROT_270_DEG] = ~quad;
|
|
||||||
|
|
||||||
base_type::init(in);
|
|
||||||
}
|
|
||||||
|
|
||||||
int Deframer::run() {
|
|
||||||
int count = base_type::_in->read();
|
|
||||||
if (count < 0) { return -1; }
|
|
||||||
|
|
||||||
dsp::complex_t* in = base_type::_in->readBuf;
|
|
||||||
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
if (recv) {
|
|
||||||
// Copy the symbol to the output and rotate it approprieate
|
|
||||||
base_type::out.writeBuf[outCount++] = in[i] * symRot;
|
|
||||||
|
|
||||||
// Check if we're done receiving the frame, send it out
|
|
||||||
if (!(--recv)) {
|
|
||||||
if (!base_type::out.swap(outCount)) {
|
|
||||||
base_type::_in->flush();
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Get the raw symbol
|
|
||||||
dsp::complex_t fsym = in[i];
|
|
||||||
|
|
||||||
// Decode the symbol
|
|
||||||
uint8_t sym = ((fsym.re > 0) ? 0b10 : 0b00) | ((fsym.im > 0) ? 0b01 : 0b00);
|
|
||||||
|
|
||||||
// Push it to the shift register
|
|
||||||
shift = (shift << 2) | sym;
|
|
||||||
|
|
||||||
// Find the rotation starting with the last known one
|
|
||||||
for (int i = 0; i < 4; i++) {
|
|
||||||
// Get the test rotation
|
|
||||||
int testRot = (knownRot+i) & 0b11;
|
|
||||||
|
|
||||||
// Check if the hamming distance is close enough
|
|
||||||
int dist;
|
|
||||||
if (distance(shift, syncRots[testRot]) < 6) {
|
|
||||||
// Save the new rotation
|
|
||||||
knownRot = testRot;
|
|
||||||
|
|
||||||
// Start reading in symbols for the frame
|
|
||||||
symRot = symRots[knownRot];
|
|
||||||
recv = 8168; // TODO: Don't hardcode!
|
|
||||||
outCount = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
base_type::_in->flush();
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,87 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "dsp/processor.h"
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
namespace ryfi {
|
|
||||||
// Synchronization word.
|
|
||||||
inline const uint64_t SYNC_WORD = 0x341CC540819D8963;
|
|
||||||
|
|
||||||
// Number of synchronization bits.
|
|
||||||
inline const int SYNC_BITS = 64;
|
|
||||||
|
|
||||||
// Number of synchronization symbols.
|
|
||||||
inline const int SYNC_SYMS = SYNC_BITS / 2;
|
|
||||||
|
|
||||||
// Possible constellation rotations
|
|
||||||
enum {
|
|
||||||
ROT_0_DEG = 0,
|
|
||||||
ROT_90_DEG = 1,
|
|
||||||
ROT_180_DEG = 2,
|
|
||||||
ROT_270_DEG = 3
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* RyFi Framer.
|
|
||||||
*/
|
|
||||||
class Framer : public dsp::Processor<uint8_t, dsp::complex_t> {
|
|
||||||
using base_type = dsp::Processor<uint8_t, dsp::complex_t>;
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* Create a framer specifying an input stream.
|
|
||||||
* @param in Input stream.
|
|
||||||
*/
|
|
||||||
Framer(dsp::stream<uint8_t>* in = NULL);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Encode a frame to symbols adding a sync word.
|
|
||||||
*/
|
|
||||||
int encode(const uint8_t* in, dsp::complex_t* out, int count);
|
|
||||||
|
|
||||||
private:
|
|
||||||
int run();
|
|
||||||
|
|
||||||
dsp::complex_t syncSyms[SYNC_SYMS];
|
|
||||||
};
|
|
||||||
|
|
||||||
class Deframer : public dsp::Processor<dsp::complex_t, dsp::complex_t> {
|
|
||||||
using base_type = dsp::Processor<dsp::complex_t, dsp::complex_t>;
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* Create a deframer specifying an input stream.
|
|
||||||
* @param in Input stream.
|
|
||||||
*/
|
|
||||||
Deframer(dsp::stream<dsp::complex_t> *in = NULL);
|
|
||||||
|
|
||||||
private:
|
|
||||||
int run();
|
|
||||||
|
|
||||||
inline static constexpr int distance(uint64_t a, uint64_t b) {
|
|
||||||
int dist = 0;
|
|
||||||
for (int i = 0; i < 64; i++) {
|
|
||||||
dist += ((a & 1) != (b & 1));
|
|
||||||
a >>= 1;
|
|
||||||
b >>= 1;
|
|
||||||
}
|
|
||||||
return dist;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Frame reading counters
|
|
||||||
int recv = 0;
|
|
||||||
int outCount = 0;
|
|
||||||
|
|
||||||
// Rotation handling
|
|
||||||
int knownRot = 0;
|
|
||||||
uint64_t syncRots[4];
|
|
||||||
dsp::complex_t symRot;
|
|
||||||
const dsp::complex_t symRots[4] = {
|
|
||||||
{ 1.0f, 0.0f }, // 0 deg
|
|
||||||
{ 0.0f, -1.0f }, // 90 deg
|
|
||||||
{ -1.0f, 0.0f }, // 180 deg
|
|
||||||
{ 0.0f, 1.0f }, // 270 deg
|
|
||||||
};
|
|
||||||
|
|
||||||
// Shift register
|
|
||||||
uint64_t shift;
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,126 +0,0 @@
|
|||||||
#include "packet.h"
|
|
||||||
#include "string.h"
|
|
||||||
#include <stdexcept>
|
|
||||||
|
|
||||||
namespace ryfi {
|
|
||||||
Packet::Packet() {}
|
|
||||||
|
|
||||||
Packet::Packet(uint8_t* content, int size) {
|
|
||||||
// Check that the size isn't too large
|
|
||||||
if (size > MAX_CONTENT_SIZE) {
|
|
||||||
throw std::runtime_error("Content size is too large to fit in a packet");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Allocate the buffer
|
|
||||||
allocate(size);
|
|
||||||
|
|
||||||
// Copy over the content
|
|
||||||
memcpy(_content, content, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
Packet::Packet(const Packet& b) {
|
|
||||||
// Reallocate the buffer
|
|
||||||
allocate(b._size);
|
|
||||||
|
|
||||||
// Copy over the content
|
|
||||||
memcpy(_content, b._content, b._size);
|
|
||||||
}
|
|
||||||
|
|
||||||
Packet::Packet(Packet&& b) {
|
|
||||||
// Move members
|
|
||||||
_content = b._content;
|
|
||||||
_size = b._size;
|
|
||||||
|
|
||||||
// Destroy old object
|
|
||||||
b._content = NULL;
|
|
||||||
b._size = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Packet::~Packet() {
|
|
||||||
// Delete the content
|
|
||||||
if (_content) { delete[] _content; }
|
|
||||||
}
|
|
||||||
|
|
||||||
Packet& Packet::operator=(const Packet& b) {
|
|
||||||
// Reallocate the buffer
|
|
||||||
allocate(b._size);
|
|
||||||
|
|
||||||
// Copy over the content
|
|
||||||
memcpy(_content, b._content, b._size);
|
|
||||||
|
|
||||||
// Return self
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Packet& Packet::operator=(Packet&& b) {
|
|
||||||
// Move members
|
|
||||||
_content = b._content;
|
|
||||||
_size = b._size;
|
|
||||||
|
|
||||||
// Destroy old object
|
|
||||||
b._content = NULL;
|
|
||||||
b._size = 0;
|
|
||||||
|
|
||||||
// Return self
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Packet::operator bool() const {
|
|
||||||
return _size > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int Packet::size() const {
|
|
||||||
// Return the size
|
|
||||||
return _size;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint8_t* Packet::data() const {
|
|
||||||
// Return the size
|
|
||||||
return _content;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Packet::setContent(uint8_t* content, int size) {
|
|
||||||
// Check that the size isn't too large
|
|
||||||
if (size > MAX_CONTENT_SIZE) {
|
|
||||||
throw std::runtime_error("Content size is too large to fit in a packet");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reallocate the buffer
|
|
||||||
allocate(size);
|
|
||||||
|
|
||||||
// Copy over the content
|
|
||||||
memcpy(_content, content, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
int Packet::serializedSize() const {
|
|
||||||
// Two size bytes + Size of the content
|
|
||||||
return _size + 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
int Packet::serialize(uint8_t* bytes) const {
|
|
||||||
// Write the size in big-endian
|
|
||||||
bytes[0] = (_size >> 8) & 0xFF;
|
|
||||||
bytes[1] = _size & 0xFF;
|
|
||||||
|
|
||||||
// Copy the content of the packet
|
|
||||||
memcpy(&bytes[2], _content, _size);
|
|
||||||
|
|
||||||
// Return the serialized size
|
|
||||||
return serializedSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Packet::allocate(int newSize) {
|
|
||||||
// If the size hasn't changed, do nothing
|
|
||||||
if (newSize == _size) { return; }
|
|
||||||
|
|
||||||
// Free the old buffer
|
|
||||||
if (_content) { delete[] _content; };
|
|
||||||
|
|
||||||
// Update the size
|
|
||||||
_size = newSize;
|
|
||||||
|
|
||||||
// Allocate the buffer
|
|
||||||
_content = new uint8_t[newSize];
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,89 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
namespace ryfi {
|
|
||||||
/**
|
|
||||||
* RyFi Protocol Packet.
|
|
||||||
*/
|
|
||||||
class Packet {
|
|
||||||
public:
|
|
||||||
// Default constructor
|
|
||||||
Packet();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a packet from its content.
|
|
||||||
* @param content Content of the packet.
|
|
||||||
* @param size Number of bytes of content.
|
|
||||||
*/
|
|
||||||
Packet(uint8_t* content, int size);
|
|
||||||
|
|
||||||
// Copy constructor
|
|
||||||
Packet(const Packet& b);
|
|
||||||
|
|
||||||
// Move constructor
|
|
||||||
Packet(Packet&& b);
|
|
||||||
|
|
||||||
// Destructor
|
|
||||||
~Packet();
|
|
||||||
|
|
||||||
// Copy assignment operator
|
|
||||||
Packet& operator=(const Packet& b);
|
|
||||||
|
|
||||||
// Move assignment operator
|
|
||||||
Packet& operator=(Packet&& b);
|
|
||||||
|
|
||||||
// Cast to bool operator
|
|
||||||
operator bool() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the size of the content of the packet.
|
|
||||||
* @return Size of the content of the packet.
|
|
||||||
*/
|
|
||||||
int size() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the content of the packet. The pointer is only valid until reallocation or deletion.
|
|
||||||
* @return Content of the packet.
|
|
||||||
*/
|
|
||||||
const uint8_t* data() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the content of the packet.
|
|
||||||
* @param content Content of the packet.
|
|
||||||
* @param size Number of bytes of content.
|
|
||||||
*/
|
|
||||||
void setContent(uint8_t* content, int size);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the size of the serialized packet.
|
|
||||||
* @return Size of the serialized packet.
|
|
||||||
*/
|
|
||||||
int serializedSize() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Serialize the packet to bytes.
|
|
||||||
* @param bytes Buffer to which to write the serialized packet.
|
|
||||||
* @return Size of the serialized packet.
|
|
||||||
*/
|
|
||||||
int serialize(uint8_t* bytes) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deserialize a packet from bytes.
|
|
||||||
* TODO
|
|
||||||
*/
|
|
||||||
static bool deserialize(uint8_t* bytes, int size, Packet& pkt);
|
|
||||||
|
|
||||||
// Maximum size of the content of the packet.
|
|
||||||
static inline const int MAX_CONTENT_SIZE = 0xFFFF;
|
|
||||||
|
|
||||||
// Maximum size of the serialized packet.
|
|
||||||
static inline const int MAX_SERIALIZED_SIZE = MAX_CONTENT_SIZE + 2;
|
|
||||||
|
|
||||||
private:
|
|
||||||
void allocate(int newSize);
|
|
||||||
|
|
||||||
uint8_t* _content = NULL;
|
|
||||||
int _size = 0;
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,194 +0,0 @@
|
|||||||
#include "receiver.h"
|
|
||||||
|
|
||||||
#include "utils/flog.h"
|
|
||||||
|
|
||||||
namespace ryfi {
|
|
||||||
Receiver::Receiver() {}
|
|
||||||
|
|
||||||
Receiver::Receiver(dsp::stream<dsp::complex_t>* in, double baudrate, double samplerate) {
|
|
||||||
init(in, baudrate, samplerate);
|
|
||||||
}
|
|
||||||
|
|
||||||
Receiver::~Receiver() {
|
|
||||||
// Stop everything
|
|
||||||
stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Receiver::init(dsp::stream<dsp::complex_t>* in, double baudrate, double samplerate) {
|
|
||||||
// Initialize the DSP
|
|
||||||
demod.init(in, baudrate, samplerate, 31, 0.6, 0.1f, 0.005f, 1e-6, 0.01);
|
|
||||||
doubler.init(&demod.out);
|
|
||||||
softOut = &doubler.outA;
|
|
||||||
deframer.setInput(&doubler.outB);
|
|
||||||
conv.setInput(&deframer.out);
|
|
||||||
rs.setInput(&conv.out);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Receiver::setInput(dsp::stream<dsp::complex_t>* in) {
|
|
||||||
demod.setInput(in);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Receiver::start() {
|
|
||||||
// Do nothing if already running
|
|
||||||
if (running) { return; }
|
|
||||||
|
|
||||||
// Start the worker thread
|
|
||||||
workerThread = std::thread(&Receiver::worker, this);
|
|
||||||
|
|
||||||
// Start the DSP
|
|
||||||
demod.start();
|
|
||||||
doubler.start();
|
|
||||||
deframer.start();
|
|
||||||
conv.start();
|
|
||||||
rs.start();
|
|
||||||
|
|
||||||
// Update the running state
|
|
||||||
running = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Receiver::stop() {
|
|
||||||
// Do nothing if not running
|
|
||||||
if (!running) { return; }
|
|
||||||
|
|
||||||
// Stop the worker thread
|
|
||||||
rs.out.stopReader();
|
|
||||||
if (workerThread.joinable()) { workerThread.join(); }
|
|
||||||
rs.out.clearReadStop();
|
|
||||||
|
|
||||||
// Stop the DSP
|
|
||||||
demod.stop();
|
|
||||||
doubler.stop();
|
|
||||||
deframer.stop();
|
|
||||||
conv.stop();
|
|
||||||
rs.stop();
|
|
||||||
|
|
||||||
// Update the running state
|
|
||||||
running = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Receiver::worker() {
|
|
||||||
Frame frame;
|
|
||||||
uint16_t lastCounter = 0;
|
|
||||||
uint8_t* pktBuffer = new uint8_t[Packet::MAX_CONTENT_SIZE];
|
|
||||||
int pktExpected = 0;
|
|
||||||
int pktRead = 0;
|
|
||||||
int valid = 0;
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
// Read a frame
|
|
||||||
int count = rs.out.read();
|
|
||||||
if (count <= 0) { break; }
|
|
||||||
|
|
||||||
// Deserialize the frame
|
|
||||||
Frame::deserialize(rs.out.readBuf, frame);
|
|
||||||
valid++;
|
|
||||||
|
|
||||||
// Flush the stream
|
|
||||||
rs.out.flush();
|
|
||||||
|
|
||||||
//flog::info("Frame[{}]: FirstPacket={}, LastPacket={}", frame.counter, frame.firstPacket, frame.lastPacket);
|
|
||||||
|
|
||||||
// Compute the expected frame counter
|
|
||||||
uint16_t expectedCounter = lastCounter + 1;
|
|
||||||
lastCounter = frame.counter;
|
|
||||||
|
|
||||||
// If the frames aren't consecutive
|
|
||||||
int frameRead = 0;
|
|
||||||
if (frame.counter != expectedCounter) {
|
|
||||||
flog::warn("Lost at least {} frames after {} valid frames", ((int)frame.counter - (int)expectedCounter + 0x10000) % 0x10000, valid);
|
|
||||||
|
|
||||||
// Cancel the partial packet if there was one
|
|
||||||
pktExpected = 0;
|
|
||||||
pktRead = 0;
|
|
||||||
valid = 1;
|
|
||||||
|
|
||||||
// If this frame is not an idle frame or continuation frame
|
|
||||||
if (frame.firstPacket != PKT_OFFS_NONE) {
|
|
||||||
// If the offset of the first packet is not plausible
|
|
||||||
if (frame.firstPacket > Frame::FRAME_DATA_SIZE-2) {
|
|
||||||
flog::warn("Packet had non-plausible offset: {}", frameRead);
|
|
||||||
|
|
||||||
// Skip the frame
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Skip to the end of the packet
|
|
||||||
frameRead = frame.firstPacket;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there is no partial packet and the frame doesn't contain a packet start, skip it
|
|
||||||
if (!pktExpected && frame.firstPacket == PKT_OFFS_NONE) { continue; }
|
|
||||||
|
|
||||||
// Extract packets from the frame
|
|
||||||
bool firstPacket = true;
|
|
||||||
bool lastPacket = false;
|
|
||||||
while (frameRead < Frame::FRAME_DATA_SIZE) {
|
|
||||||
// If there is a partial packet read as much as possible from it
|
|
||||||
if (pktExpected) {
|
|
||||||
// Compute how many bytes of the packet are available in the frame
|
|
||||||
int readable = std::min<int>(pktExpected - pktRead, Frame::FRAME_DATA_SIZE - frameRead);
|
|
||||||
//flog::debug("Reading {} bytes", readable);
|
|
||||||
|
|
||||||
// Write them to the packet
|
|
||||||
memcpy(&pktBuffer[pktRead], &frame.content[frameRead], readable);
|
|
||||||
pktRead += readable;
|
|
||||||
frameRead += readable;
|
|
||||||
|
|
||||||
// If the packet is read entirely
|
|
||||||
if (pktRead >= pktExpected) {
|
|
||||||
// Create the packet object
|
|
||||||
Packet pkt(pktBuffer, pktExpected);
|
|
||||||
|
|
||||||
// Send off the packet
|
|
||||||
onPacket(pkt);
|
|
||||||
|
|
||||||
// Prepare for the next packet
|
|
||||||
pktRead = 0;
|
|
||||||
pktExpected = 0;
|
|
||||||
|
|
||||||
// If this was the last packet of the frame
|
|
||||||
if (lastPacket || frame.firstPacket == PKT_OFFS_NONE) {
|
|
||||||
// Skip the rest of the frame
|
|
||||||
frameRead = Frame::FRAME_DATA_SIZE;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Go to next packet
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the packet offset is not plausible
|
|
||||||
if (Frame::FRAME_DATA_SIZE - frameRead < 2) {
|
|
||||||
flog::warn("Packet had non-plausible offset: {}", frameRead);
|
|
||||||
|
|
||||||
// Skip the rest of the frame and the packet
|
|
||||||
frameRead = Frame::FRAME_DATA_SIZE;
|
|
||||||
pktExpected = 0;
|
|
||||||
pktRead = 0;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If this is the first packet, use the frame info to skip possible left over data
|
|
||||||
if (firstPacket) {
|
|
||||||
frameRead = frame.firstPacket;
|
|
||||||
firstPacket = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if this is the last packet
|
|
||||||
lastPacket = (frameRead == frame.lastPacket);
|
|
||||||
|
|
||||||
// Parse the packet size
|
|
||||||
pktExpected = ((uint16_t)frame.content[frameRead]) << 8;
|
|
||||||
pktExpected |= (uint16_t)frame.content[frameRead+1];
|
|
||||||
//flog::debug("Starting to read a {} byte packet at offset {}", pktExpected, frameRead);
|
|
||||||
|
|
||||||
// Skip to the packet content
|
|
||||||
frameRead += 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
delete[] pktBuffer;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,69 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "utils/new_event.h"
|
|
||||||
#include "dsp/demod/psk.h"
|
|
||||||
#include "dsp/routing/doubler.h"
|
|
||||||
#include "packet.h"
|
|
||||||
#include "frame.h"
|
|
||||||
#include "rs_codec.h"
|
|
||||||
#include "conv_codec.h"
|
|
||||||
#include "framing.h"
|
|
||||||
#include <mutex>
|
|
||||||
|
|
||||||
namespace ryfi {
|
|
||||||
class Receiver {
|
|
||||||
public:
|
|
||||||
Receiver();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a transmitter.
|
|
||||||
* @param in Baseband input.
|
|
||||||
* @param baudrate Baudrate to use over the air.
|
|
||||||
* @param samplerate Samplerate of the baseband.
|
|
||||||
*/
|
|
||||||
Receiver(dsp::stream<dsp::complex_t>* in, double baudrate, double samplerate);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a transmitter.
|
|
||||||
* @param in Baseband input.
|
|
||||||
* @param baudrate Baudrate to use over the air.
|
|
||||||
* @param samplerate Samplerate of the baseband.
|
|
||||||
*/
|
|
||||||
void init(dsp::stream<dsp::complex_t>* in, double baudrate, double samplerate);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the input stream.
|
|
||||||
* @param in Baseband input.
|
|
||||||
*/
|
|
||||||
void setInput(dsp::stream<dsp::complex_t>* in);
|
|
||||||
|
|
||||||
// Destructor
|
|
||||||
~Receiver();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start the transmitter's DSP.
|
|
||||||
*/
|
|
||||||
void start();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stop the transmitter's DSP.
|
|
||||||
*/
|
|
||||||
void stop();
|
|
||||||
|
|
||||||
dsp::stream<dsp::complex_t>* softOut;
|
|
||||||
|
|
||||||
NewEvent<Packet> onPacket;
|
|
||||||
|
|
||||||
private:
|
|
||||||
void worker();
|
|
||||||
|
|
||||||
// DSP
|
|
||||||
dsp::demod::PSK<4> demod;
|
|
||||||
dsp::routing::Doubler<dsp::complex_t> doubler;
|
|
||||||
Deframer deframer;
|
|
||||||
ConvDecoder conv;
|
|
||||||
RSDecoder rs;
|
|
||||||
|
|
||||||
bool running = false;
|
|
||||||
std::thread workerThread;
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,169 +0,0 @@
|
|||||||
#include "rs_codec.h"
|
|
||||||
|
|
||||||
namespace ryfi {
|
|
||||||
RSEncoder::RSEncoder(dsp::stream<uint8_t>* in) {
|
|
||||||
// Create the convolutional encoder instance
|
|
||||||
rs = correct_reed_solomon_create(correct_rs_primitive_polynomial_ccsds, 1, 1, 32);
|
|
||||||
|
|
||||||
// Init the base class
|
|
||||||
base_type::init(in);
|
|
||||||
}
|
|
||||||
|
|
||||||
RSEncoder::~RSEncoder() {
|
|
||||||
// Destroy the convolutional encoder instance
|
|
||||||
correct_reed_solomon_destroy(rs);
|
|
||||||
}
|
|
||||||
|
|
||||||
int RSEncoder::encode(const uint8_t* in, uint8_t* out, int count) {
|
|
||||||
// Check the size
|
|
||||||
assert(count == RS_BLOCK_COUNT*RS_BLOCK_DEC_SIZE);
|
|
||||||
|
|
||||||
// Go through each block
|
|
||||||
uint8_t block[RS_BLOCK_ENC_SIZE];
|
|
||||||
for (int i = 0; i < RS_BLOCK_COUNT; i++) {
|
|
||||||
// Encode block
|
|
||||||
correct_reed_solomon_encode(rs, &in[i*RS_BLOCK_DEC_SIZE], RS_BLOCK_DEC_SIZE, block);
|
|
||||||
|
|
||||||
// Interleave into the frame
|
|
||||||
int k = 0;
|
|
||||||
for (int j = i; j < RS_BLOCK_ENC_SIZE*RS_BLOCK_COUNT; j += RS_BLOCK_COUNT) {
|
|
||||||
out[j] = block[k++];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scramble
|
|
||||||
for (int i = 0; i < RS_BLOCK_COUNT*RS_BLOCK_ENC_SIZE; i++) {
|
|
||||||
out[i] ^= RS_SCRAMBLER_SEQ[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
return RS_BLOCK_COUNT*RS_BLOCK_ENC_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
int RSEncoder::run() {
|
|
||||||
int count = base_type::_in->read();
|
|
||||||
if (count < 0) { return -1; }
|
|
||||||
|
|
||||||
count = encode(base_type::_in->readBuf, base_type::out.writeBuf, count);
|
|
||||||
|
|
||||||
base_type::_in->flush();
|
|
||||||
if (!out.swap(count)) { return -1; }
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
RSDecoder::RSDecoder(dsp::stream<uint8_t>* in) {
|
|
||||||
// Create the convolutional encoder instance
|
|
||||||
rs = correct_reed_solomon_create(correct_rs_primitive_polynomial_ccsds, 1, 1, 32);
|
|
||||||
|
|
||||||
// Init the base class
|
|
||||||
base_type::init(in);
|
|
||||||
}
|
|
||||||
|
|
||||||
RSDecoder::~RSDecoder() {
|
|
||||||
// Destroy the convolutional encoder instance
|
|
||||||
correct_reed_solomon_destroy(rs);
|
|
||||||
}
|
|
||||||
|
|
||||||
int RSDecoder::decode(uint8_t* in, uint8_t* out, int count) {
|
|
||||||
// Check the size
|
|
||||||
assert(count == RS_BLOCK_COUNT*RS_BLOCK_ENC_SIZE);
|
|
||||||
|
|
||||||
// Descramble (TODO: Don't do it in-place)
|
|
||||||
for (int i = 0; i < RS_BLOCK_COUNT*RS_BLOCK_ENC_SIZE; i++) {
|
|
||||||
in[i] ^= RS_SCRAMBLER_SEQ[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Go through each block
|
|
||||||
uint8_t block[RS_BLOCK_ENC_SIZE];
|
|
||||||
for (int i = 0; i < RS_BLOCK_COUNT; i++) {
|
|
||||||
// Deinterleave out of the frame
|
|
||||||
int k = 0;
|
|
||||||
for (int j = i; j < count; j += RS_BLOCK_COUNT) {
|
|
||||||
block[k++] = in[j];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decode block and return if decoding fails
|
|
||||||
int res = correct_reed_solomon_decode(rs, block, RS_BLOCK_ENC_SIZE, &out[i*RS_BLOCK_DEC_SIZE]);
|
|
||||||
if (res < 0) { return 0; }
|
|
||||||
}
|
|
||||||
|
|
||||||
return RS_BLOCK_COUNT*RS_BLOCK_DEC_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
int RSDecoder::run() {
|
|
||||||
int count = base_type::_in->read();
|
|
||||||
if (count < 0) { return -1; }
|
|
||||||
|
|
||||||
count = decode(base_type::_in->readBuf, base_type::out.writeBuf, count);
|
|
||||||
|
|
||||||
base_type::_in->flush();
|
|
||||||
if (count && !out.swap(count)) { return -1; }
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint8_t RS_SCRAMBLER_SEQ[RS_BLOCK_ENC_SIZE*RS_BLOCK_COUNT] = {
|
|
||||||
0x75, 0x05, 0x7C, 0xCE, 0xF1, 0xD0, 0x6C, 0xF6, 0xFA, 0x65, 0xF6, 0xFC, 0xE0, 0x0A, 0x82, 0x17,
|
|
||||||
0x6C, 0xBE, 0x76, 0xA0, 0xD6, 0x46, 0x12, 0x2E, 0xDE, 0xB5, 0xF7, 0xAD, 0xCB, 0x51, 0x63, 0x47,
|
|
||||||
0x27, 0x30, 0x7E, 0x43, 0xD1, 0xA1, 0xCB, 0x10, 0x08, 0x49, 0xDF, 0x86, 0xD4, 0xC4, 0xD7, 0x3C,
|
|
||||||
0x6D, 0x03, 0x07, 0x37, 0x5B, 0xB3, 0xCD, 0x79, 0x6F, 0x1E, 0xBA, 0xC5, 0x6E, 0xC3, 0x8C, 0x7A,
|
|
||||||
0x25, 0x99, 0x61, 0x54, 0x5A, 0x96, 0x57, 0x9B, 0xE0, 0x60, 0x5B, 0x09, 0x6D, 0x8B, 0x2D, 0x9D,
|
|
||||||
0x15, 0x9D, 0x0E, 0xBF, 0x57, 0xFB, 0x9C, 0x49, 0x82, 0x2C, 0x48, 0x59, 0x92, 0x47, 0x79, 0x17,
|
|
||||||
0x16, 0x74, 0xEA, 0xEA, 0xBB, 0xC5, 0x72, 0x32, 0x17, 0xD1, 0xB3, 0xDE, 0xEB, 0x15, 0xC7, 0x55,
|
|
||||||
0x8A, 0xF2, 0x88, 0xC2, 0x33, 0xA6, 0x17, 0x8B, 0xD4, 0x77, 0x22, 0x00, 0x63, 0x47, 0x45, 0x5F,
|
|
||||||
0x36, 0x35, 0x58, 0x8B, 0x88, 0xEC, 0xCA, 0xC4, 0x60, 0x53, 0x9E, 0xBD, 0xB2, 0xF5, 0x51, 0x46,
|
|
||||||
0x34, 0x9A, 0x07, 0x25, 0x3F, 0xF5, 0x65, 0x63, 0x77, 0x3C, 0x5A, 0xFA, 0x4E, 0x0C, 0xF7, 0x1B,
|
|
||||||
0x82, 0xAB, 0x73, 0x06, 0x7F, 0xB7, 0xC6, 0x6B, 0xBF, 0xB1, 0x46, 0xF3, 0x01, 0x91, 0xB1, 0xFF,
|
|
||||||
0x5C, 0x6F, 0xF9, 0x43, 0x0E, 0x6A, 0x70, 0x89, 0x0B, 0xEA, 0x8C, 0xD4, 0x1B, 0x51, 0x01, 0x31,
|
|
||||||
0x71, 0x2E, 0xDF, 0x24, 0xC1, 0xD5, 0xDB, 0x0E, 0xF5, 0xEB, 0x78, 0x79, 0x39, 0x5B, 0xAD, 0xC3,
|
|
||||||
0xA9, 0xA6, 0x60, 0x30, 0xA2, 0x9A, 0x7B, 0xA0, 0xF4, 0xAA, 0xC5, 0x57, 0xB3, 0x16, 0xF9, 0xB5,
|
|
||||||
0x79, 0x20, 0xC1, 0x88, 0x9A, 0x00, 0x43, 0xB2, 0xC6, 0x84, 0x8D, 0x03, 0xF2, 0xD8, 0x90, 0x7A,
|
|
||||||
0x21, 0x37, 0x7E, 0xF7, 0x75, 0xE5, 0xFB, 0xC9, 0xDC, 0xAB, 0x4B, 0xBC, 0x35, 0x38, 0xB9, 0x3A,
|
|
||||||
0x53, 0x89, 0x7E, 0xD5, 0x94, 0x12, 0x2D, 0x9B, 0x91, 0x90, 0x1D, 0x4D, 0x0E, 0xE0, 0x93, 0xF3,
|
|
||||||
0xC1, 0xA1, 0x9B, 0x73, 0x27, 0x22, 0x41, 0x27, 0xEE, 0x2A, 0xD7, 0x45, 0xBC, 0x8F, 0x9B, 0xA2,
|
|
||||||
0x36, 0x11, 0x16, 0x37, 0x1A, 0xF1, 0x2E, 0x71, 0xCF, 0x86, 0x89, 0x83, 0x5A, 0xF1, 0x24, 0x6C,
|
|
||||||
0x56, 0x71, 0x53, 0xE4, 0xD2, 0xCB, 0xCA, 0x86, 0x1E, 0xA0, 0xD5, 0x83, 0x3B, 0xEF, 0x09, 0x09,
|
|
||||||
0xC2, 0x07, 0x53, 0x86, 0xE6, 0x8A, 0xC6, 0x70, 0xFB, 0x91, 0x43, 0xCB, 0x91, 0x6E, 0xA9, 0xBC,
|
|
||||||
0x31, 0x42, 0x61, 0x0C, 0x88, 0xB8, 0x2C, 0xED, 0xD8, 0xE6, 0xA3, 0xEC, 0xAC, 0xB9, 0x45, 0x5E,
|
|
||||||
0x2C, 0x73, 0x3F, 0x2E, 0x06, 0xE0, 0xBF, 0x73, 0xDD, 0x2E, 0x45, 0x50, 0x6C, 0x53, 0x55, 0xF0,
|
|
||||||
0x7F, 0x6E, 0x61, 0xFA, 0xA0, 0x7A, 0x1C, 0xF0, 0xBD, 0xAC, 0x48, 0x61, 0x03, 0x6B, 0xED, 0x54,
|
|
||||||
0x2A, 0x27, 0x94, 0xF6, 0xF9, 0x6A, 0x04, 0x08, 0x0B, 0x3C, 0xC3, 0x30, 0x66, 0x01, 0xFB, 0xDC,
|
|
||||||
0xC9, 0x65, 0x03, 0x83, 0x7D, 0x0A, 0xDF, 0xA5, 0x04, 0x14, 0xE4, 0xF2, 0x4C, 0x01, 0xDF, 0x04,
|
|
||||||
0xD2, 0x80, 0xB9, 0x9B, 0xD9, 0x5E, 0xF8, 0x2A, 0x93, 0x8D, 0x8C, 0x09, 0x9B, 0x38, 0xEC, 0x3B,
|
|
||||||
0xC4, 0x29, 0x90, 0x7C, 0x65, 0x3A, 0xF2, 0x4B, 0x69, 0xD3, 0x63, 0x9B, 0x40, 0x95, 0xC3, 0xFB,
|
|
||||||
0x67, 0x54, 0x40, 0x9B, 0x26, 0x9F, 0x52, 0xFE, 0xD8, 0xD0, 0x24, 0x9C, 0x5C, 0xD4, 0xEF, 0xDE,
|
|
||||||
0x28, 0x66, 0x75, 0x04, 0xCB, 0xA4, 0xC0, 0xB9, 0x4B, 0xC9, 0x20, 0x4B, 0x56, 0xC7, 0x86, 0xC5,
|
|
||||||
0x39, 0x45, 0x18, 0xA7, 0x48, 0x14, 0x1A, 0x51, 0xCA, 0xD0, 0xC0, 0x15, 0xDD, 0xC1, 0x28, 0x4A,
|
|
||||||
0x7A, 0xD2, 0x10, 0xEA, 0x83, 0xD3, 0x3A, 0xEF, 0x48, 0x29, 0x41, 0xA4, 0xD4, 0x57, 0xA6, 0x1D,
|
|
||||||
0x76, 0x24, 0x93, 0x58, 0x7E, 0xB7, 0xDD, 0x0B, 0xF2, 0xCE, 0x71, 0x55, 0xF5, 0xAB, 0x8C, 0xC8,
|
|
||||||
0x70, 0x59, 0x73, 0x69, 0x9D, 0x29, 0x5E, 0x59, 0xF4, 0xB2, 0xC4, 0x97, 0x75, 0xF0, 0x65, 0x1B,
|
|
||||||
0x66, 0x5F, 0xA4, 0x33, 0x5C, 0xC7, 0xBF, 0x45, 0xE6, 0x20, 0xC0, 0xBD, 0xAD, 0xAE, 0x9F, 0x97,
|
|
||||||
0x05, 0xD8, 0x04, 0x2B, 0x0A, 0x46, 0xE8, 0xB8, 0xCB, 0x00, 0xE2, 0x7C, 0x70, 0x1B, 0x49, 0xDE,
|
|
||||||
0x81, 0xEB, 0x24, 0xAC, 0x1B, 0x3E, 0x09, 0xFB, 0xAC, 0xB7, 0xF2, 0xD1, 0xB2, 0x78, 0xF3, 0xAC,
|
|
||||||
0xC7, 0x6A, 0xA2, 0x07, 0x4C, 0xED, 0x61, 0xAD, 0x04, 0x7F, 0x45, 0x83, 0x59, 0x31, 0x27, 0xF0,
|
|
||||||
0x16, 0x6B, 0x0C, 0xAA, 0xD4, 0xD1, 0xCB, 0x1C, 0x51, 0x41, 0x0D, 0x2F, 0x8F, 0xF9, 0xF9, 0x7F,
|
|
||||||
0x22, 0x89, 0x46, 0xF4, 0xB8, 0x93, 0x98, 0x9E, 0x3E, 0x23, 0xF1, 0x6E, 0x64, 0x08, 0xB6, 0xC9,
|
|
||||||
0x6E, 0x53, 0x53, 0xED, 0xAD, 0x21, 0xCD, 0x1A, 0xF0, 0x45, 0xFC, 0x14, 0x00, 0xEA, 0xF7, 0x42,
|
|
||||||
0xEE, 0xDA, 0x58, 0x0D, 0x85, 0xBC, 0x74, 0xFB, 0x73, 0x78, 0xB5, 0x5E, 0x5E, 0x6F, 0x6F, 0x7E,
|
|
||||||
0x39, 0xC2, 0x05, 0x50, 0xDB, 0x3D, 0xB8, 0xF3, 0x8F, 0x80, 0xEC, 0x46, 0x29, 0x39, 0x89, 0xF3,
|
|
||||||
0x55, 0x9C, 0x6A, 0x5F, 0x7C, 0xD9, 0x7C, 0x13, 0xE4, 0x56, 0x5E, 0xE9, 0x60, 0x19, 0xE2, 0x7D,
|
|
||||||
0xC4, 0x41, 0x92, 0x8D, 0xDA, 0x21, 0x58, 0x20, 0xE9, 0xA8, 0x4C, 0x16, 0x34, 0x99, 0xAC, 0xB7,
|
|
||||||
0x30, 0xBD, 0x39, 0x19, 0xAC, 0x9B, 0x4B, 0x27, 0xFA, 0x32, 0xC1, 0x48, 0xA1, 0x80, 0x34, 0x36,
|
|
||||||
0x1E, 0xFB, 0x92, 0x43, 0x35, 0x72, 0x2D, 0xEF, 0xD2, 0xF2, 0xFC, 0xC2, 0x85, 0xAB, 0x59, 0x40,
|
|
||||||
0x8D, 0x9D, 0x1A, 0x1F, 0xE2, 0x92, 0x87, 0xA2, 0xF9, 0x2C, 0x78, 0xE4, 0xC3, 0x26, 0x56, 0x07,
|
|
||||||
0xB3, 0x78, 0xAF, 0x79, 0x3D, 0x88, 0xF4, 0xAD, 0x66, 0x7C, 0x07, 0x58, 0x98, 0x82, 0x1A, 0x26,
|
|
||||||
0xF7, 0xFD, 0xCE, 0xFF, 0x75, 0xED, 0xAB, 0xBD, 0xAE, 0x6D, 0x5C, 0x28, 0x91, 0xF3, 0xB7, 0x5C,
|
|
||||||
0x27, 0x05, 0xEC, 0x3B, 0xE3, 0xDD, 0x93, 0x24, 0x7F, 0xAD, 0x14, 0xAA, 0x49, 0x61, 0x8F, 0x96,
|
|
||||||
0x1F, 0xAA, 0xB2, 0xEE, 0xA8, 0x24, 0x41, 0x7C, 0xDC, 0xF1, 0x28, 0x26, 0xE6, 0x7F, 0x98, 0x20,
|
|
||||||
0x50, 0x5F, 0x90, 0x21, 0x8A, 0x09, 0x26, 0x59, 0xD0, 0x07, 0x2F, 0xE1, 0x35, 0x4D, 0x0B, 0x20,
|
|
||||||
0xB2, 0xD5, 0xDD, 0xB5, 0xAC, 0x1B, 0xFE, 0xD9, 0xE3, 0x35, 0xF1, 0xB8, 0x3F, 0x3D, 0xFC, 0x0B,
|
|
||||||
0x5A, 0x57, 0xA9, 0x92, 0x2B, 0xC8, 0x3E, 0xC2, 0xAA, 0xEF, 0xB9, 0x98, 0x2C, 0xA8, 0xAB, 0xF6,
|
|
||||||
0xA1, 0xBF, 0xBC, 0x8D, 0x97, 0xA2, 0x74, 0xD9, 0xE5, 0x99, 0x85, 0x81, 0x15, 0xB0, 0xE7, 0x8B,
|
|
||||||
0x48, 0x86, 0xF4, 0x94, 0x9C, 0x62, 0x82, 0xD1, 0x2C, 0x24, 0x4B, 0xAC, 0x7A, 0xB8, 0x4E, 0x4A,
|
|
||||||
0xD2, 0xF6, 0xAA, 0xED, 0xE0, 0x9C, 0x98, 0xD2, 0xDF, 0xC1, 0xBC, 0xBF, 0x55, 0x7D, 0x40, 0xB5,
|
|
||||||
0xDE, 0xD4, 0x25, 0xBB, 0x81, 0xF4, 0x07, 0x1D, 0xE7, 0x3C, 0xB4, 0x62, 0xC9, 0x55, 0x0A, 0x3A,
|
|
||||||
0xD5, 0xCE, 0x97, 0xED, 0x30, 0x76, 0x76, 0x51, 0xBC, 0x8C, 0xE4, 0x54, 0xBE, 0xB7, 0xB5, 0xCD,
|
|
||||||
0xF8, 0x76, 0x37, 0x53, 0x2C, 0x9F, 0xE4, 0xC7, 0xEB, 0xF5, 0x8D, 0x23, 0x8A, 0xDA, 0xD1, 0xA9,
|
|
||||||
0xD8, 0x4C, 0x53, 0xF3, 0x49, 0xA7, 0x1A, 0x5D, 0xE5, 0x03, 0x49, 0x52, 0xD3, 0xE2, 0x1F, 0xA5,
|
|
||||||
0x35, 0x9C, 0xBB, 0x0B, 0xC7, 0x0D, 0xA4, 0x65, 0x54, 0x8B, 0x39, 0xF1, 0x3B, 0x67, 0x21, 0x71,
|
|
||||||
0x10, 0xE7, 0x76, 0xC4, 0xA8, 0xC2, 0x9D, 0x93, 0xC6, 0x51, 0xBA, 0x23
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,82 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
#include "dsp/processor.h"
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
#include "correct.h"
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace ryfi {
|
|
||||||
// Size of an encoded reed-solomon block.
|
|
||||||
inline const int RS_BLOCK_ENC_SIZE = 255;
|
|
||||||
|
|
||||||
// Size of a decoded reed-solomon block.
|
|
||||||
inline const int RS_BLOCK_DEC_SIZE = 223;
|
|
||||||
|
|
||||||
// Number of reed-solomon blocks.
|
|
||||||
inline const int RS_BLOCK_COUNT = 4;
|
|
||||||
|
|
||||||
// Scrambler sequence
|
|
||||||
extern const uint8_t RS_SCRAMBLER_SEQ[RS_BLOCK_ENC_SIZE*RS_BLOCK_COUNT];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* RyFi Reed-Solomon Encoder.
|
|
||||||
*/
|
|
||||||
class RSEncoder : public dsp::Processor<uint8_t, uint8_t> {
|
|
||||||
using base_type = dsp::Processor<uint8_t, uint8_t>;
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* Create a reed-solomon encoder specifying an input stream.
|
|
||||||
* @param in Input stream
|
|
||||||
*/
|
|
||||||
RSEncoder(dsp::stream<uint8_t>* in = NULL);
|
|
||||||
|
|
||||||
// Destructor
|
|
||||||
~RSEncoder();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Encode data.
|
|
||||||
* @param in Input bytes.
|
|
||||||
* @param out Output bytes.
|
|
||||||
* @param count Number of input bytes.
|
|
||||||
* @return Number of output bytes.
|
|
||||||
*/
|
|
||||||
int encode(const uint8_t* in, uint8_t* out, int count);
|
|
||||||
|
|
||||||
private:
|
|
||||||
int run();
|
|
||||||
|
|
||||||
correct_reed_solomon* rs;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* RyFi Reed-Solomon Decoder.
|
|
||||||
*/
|
|
||||||
class RSDecoder : public dsp::Processor<uint8_t, uint8_t> {
|
|
||||||
using base_type = dsp::Processor<uint8_t, uint8_t>;
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* Create a reed-solomon decoder specifying an input stream.
|
|
||||||
* @param in Input stream
|
|
||||||
*/
|
|
||||||
RSDecoder(dsp::stream<uint8_t>* in = NULL);
|
|
||||||
|
|
||||||
// Destructor
|
|
||||||
~RSDecoder();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decode data.
|
|
||||||
* @param in Input bytes.
|
|
||||||
* @param out Output bytes.
|
|
||||||
* @param count Number of input bytes.
|
|
||||||
* @return Number of output bytes.
|
|
||||||
*/
|
|
||||||
int decode(uint8_t* in, uint8_t* out, int count);
|
|
||||||
|
|
||||||
private:
|
|
||||||
int run();
|
|
||||||
|
|
||||||
correct_reed_solomon* rs;
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,177 +0,0 @@
|
|||||||
#include "transmitter.h"
|
|
||||||
|
|
||||||
namespace ryfi {
|
|
||||||
Transmitter::Transmitter(double baudrate, double samplerate) {
|
|
||||||
// Initialize the DSP
|
|
||||||
rs.setInput(&in);
|
|
||||||
conv.setInput(&rs.out);
|
|
||||||
framer.setInput(&conv.out);
|
|
||||||
resamp.init(&framer.out, baudrate, samplerate);
|
|
||||||
|
|
||||||
rrcTaps = dsp::taps::rootRaisedCosine<float>(511, 0.6, baudrate, samplerate);
|
|
||||||
// Normalize the taps
|
|
||||||
float tot = 0.0f;
|
|
||||||
for (int i = 0; i < rrcTaps.size; i++) {
|
|
||||||
tot += rrcTaps.taps[i];
|
|
||||||
}
|
|
||||||
for (int i = 0; i < rrcTaps.size; i++) {
|
|
||||||
rrcTaps.taps[i] /= tot;
|
|
||||||
}
|
|
||||||
|
|
||||||
rrc.init(&resamp.out, rrcTaps);
|
|
||||||
out = &rrc.out;
|
|
||||||
}
|
|
||||||
|
|
||||||
Transmitter::~Transmitter() {
|
|
||||||
// Stop everything
|
|
||||||
stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Transmitter::start() {
|
|
||||||
// Do nothing if already running
|
|
||||||
if (running) { return; }
|
|
||||||
|
|
||||||
// Start the worker thread
|
|
||||||
workerThread = std::thread(&Transmitter::worker, this);
|
|
||||||
|
|
||||||
// Start the DSP
|
|
||||||
rs.start();
|
|
||||||
conv.start();
|
|
||||||
framer.start();
|
|
||||||
resamp.start();
|
|
||||||
rrc.start();
|
|
||||||
|
|
||||||
// Update the running state
|
|
||||||
running = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Transmitter::stop() {
|
|
||||||
// Do nothing if not running
|
|
||||||
if (!running) { return; }
|
|
||||||
|
|
||||||
// Stop the worker thread
|
|
||||||
in.stopWriter();
|
|
||||||
if (workerThread.joinable()) { workerThread.join(); }
|
|
||||||
in.clearWriteStop();
|
|
||||||
|
|
||||||
// Stop the DSP
|
|
||||||
rs.stop();
|
|
||||||
conv.stop();
|
|
||||||
framer.stop();
|
|
||||||
resamp.stop();
|
|
||||||
rrc.stop();
|
|
||||||
|
|
||||||
// Update the running state
|
|
||||||
running = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Transmitter::send(const Packet& pkt) {
|
|
||||||
// Acquire the packet queue
|
|
||||||
std::lock_guard<std::mutex> lck(packetsMtx);
|
|
||||||
|
|
||||||
// If there are too many packets queued up, drop the packet
|
|
||||||
if (packets.size() >= MAX_QUEUE_SIZE) { return false; }
|
|
||||||
|
|
||||||
// Push the packet onto the queue
|
|
||||||
packets.push(pkt);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Transmitter::txFrame(const Frame& frame) {
|
|
||||||
// Serialize the frame
|
|
||||||
int count = frame.serialize(in.writeBuf);
|
|
||||||
|
|
||||||
// Send it off
|
|
||||||
return in.swap(count);
|
|
||||||
}
|
|
||||||
|
|
||||||
Packet Transmitter::popPacket() {
|
|
||||||
// Acquire the packet queue
|
|
||||||
std::unique_lock<std::mutex> lck(packetsMtx);
|
|
||||||
|
|
||||||
// If no packets are available, return empty packet
|
|
||||||
if (!packets.size()) { return Packet(); }
|
|
||||||
|
|
||||||
// Pop the front packet and return it
|
|
||||||
Packet pkt = packets.front();
|
|
||||||
packets.pop();
|
|
||||||
return pkt;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Transmitter::worker() {
|
|
||||||
Frame frame;
|
|
||||||
Packet pkt;
|
|
||||||
uint16_t counter = 0;
|
|
||||||
int pktToWrite = 0;
|
|
||||||
int pktWritten = 0;
|
|
||||||
uint8_t* pktBuffer = new uint8_t[Packet::MAX_SERIALIZED_SIZE];
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
// Initialize the frame
|
|
||||||
frame.counter = counter++;
|
|
||||||
frame.firstPacket = PKT_OFFS_NONE;
|
|
||||||
frame.lastPacket = PKT_OFFS_NONE;
|
|
||||||
int frameOffset = 0;
|
|
||||||
|
|
||||||
// Fill the frame with as much packet data as possible
|
|
||||||
while (frameOffset < sizeof(Frame::content)) {
|
|
||||||
// If there is no packet in the process of being sent
|
|
||||||
if (!pktWritten) {
|
|
||||||
// If there is not enough space for the size of the packet
|
|
||||||
if ((sizeof(Frame::content) - frameOffset) < 2) {
|
|
||||||
// Fill the rest of the frame with noise and send it
|
|
||||||
for (int i = frameOffset; i < sizeof(Frame::content); i++) { frame.content[i] = rand(); }
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the next packet
|
|
||||||
pkt = popPacket();
|
|
||||||
|
|
||||||
// If there was an available packet
|
|
||||||
if (pkt) {
|
|
||||||
// Serialize the packet
|
|
||||||
pktToWrite = pkt.serializedSize();
|
|
||||||
pkt.serialize(pktBuffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If none was available
|
|
||||||
if (!pkt) {
|
|
||||||
// Fill the rest of the frame with noise and send it
|
|
||||||
for (int i = frameOffset; i < sizeof(Frame::content); i++) { frame.content[i] = rand(); }
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If this is the beginning of the packet
|
|
||||||
if (!pktWritten) {
|
|
||||||
//flog::debug("Starting to write a {} byte packet at offset {}", pktToWrite-2, frameOffset);
|
|
||||||
|
|
||||||
// If this is the first packet of the frame, update its offset
|
|
||||||
if (frame.firstPacket == PKT_OFFS_NONE) { frame.firstPacket = frameOffset; }
|
|
||||||
|
|
||||||
// Update the last packet pointer
|
|
||||||
frame.lastPacket = frameOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compute the amount of data writeable to the frame
|
|
||||||
int writeable = std::min<int>(pktToWrite - pktWritten, sizeof(Frame::content) - frameOffset);
|
|
||||||
|
|
||||||
// Copy the data to the frame
|
|
||||||
memcpy(&frame.content[frameOffset], &pktBuffer[pktWritten], writeable);
|
|
||||||
pktWritten += writeable;
|
|
||||||
frameOffset += writeable;
|
|
||||||
|
|
||||||
// If the packet is done being sent
|
|
||||||
if (pktWritten >= pktToWrite) {
|
|
||||||
// Prepare for a new packet
|
|
||||||
pktToWrite = 0;
|
|
||||||
pktWritten = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send the frame
|
|
||||||
if (!txFrame(frame)) { break; }
|
|
||||||
}
|
|
||||||
|
|
||||||
delete[] pktBuffer;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,69 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "dsp/multirate/rational_resampler.h"
|
|
||||||
#include "dsp/taps/root_raised_cosine.h"
|
|
||||||
#include "dsp/filter/fir.h"
|
|
||||||
#include "packet.h"
|
|
||||||
#include "frame.h"
|
|
||||||
#include "rs_codec.h"
|
|
||||||
#include "conv_codec.h"
|
|
||||||
#include "framing.h"
|
|
||||||
#include <queue>
|
|
||||||
#include <mutex>
|
|
||||||
|
|
||||||
namespace ryfi {
|
|
||||||
class Transmitter {
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* Create a transmitter.
|
|
||||||
* @param baudrate Baudrate to use over the air.
|
|
||||||
* @param samplerate Samplerate of the baseband.
|
|
||||||
*/
|
|
||||||
Transmitter(double baudrate, double samplerate);
|
|
||||||
|
|
||||||
// Destructor
|
|
||||||
~Transmitter();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start the transmitter's DSP.
|
|
||||||
*/
|
|
||||||
void start();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stop the transmitter's DSP.
|
|
||||||
*/
|
|
||||||
void stop();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a packet.
|
|
||||||
* @param pkg Packet to send.
|
|
||||||
* @return True if the packet was send, false if it was dropped.
|
|
||||||
*/
|
|
||||||
bool send(const Packet& pkt);
|
|
||||||
|
|
||||||
// Baseband output
|
|
||||||
dsp::stream<dsp::complex_t>* out;
|
|
||||||
|
|
||||||
static inline const int MAX_QUEUE_SIZE = 32;
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool txFrame(const Frame& frame);
|
|
||||||
Packet popPacket();
|
|
||||||
void worker();
|
|
||||||
|
|
||||||
// Packet queue
|
|
||||||
std::mutex packetsMtx;
|
|
||||||
std::queue<Packet> packets;
|
|
||||||
|
|
||||||
// DSP
|
|
||||||
dsp::stream<uint8_t> in;
|
|
||||||
RSEncoder rs;
|
|
||||||
ConvEncoder conv;
|
|
||||||
Framer framer;
|
|
||||||
dsp::multirate::RationalResampler<dsp::complex_t> resamp;
|
|
||||||
dsp::tap<float> rrcTaps;
|
|
||||||
dsp::filter::FIR<dsp::complex_t, float> rrc;
|
|
||||||
|
|
||||||
bool running = false;
|
|
||||||
std::thread workerThread;
|
|
||||||
};
|
|
||||||
}
|
|
@ -6,7 +6,7 @@ cd /root
|
|||||||
apt update
|
apt update
|
||||||
apt install -y build-essential cmake git libfftw3-dev libglfw3-dev libvolk2-dev libzstd-dev libairspyhf-dev libairspy-dev \
|
apt install -y build-essential cmake git libfftw3-dev libglfw3-dev libvolk2-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 \
|
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
|
libcodec2-dev autoconf libtool xxd
|
||||||
|
|
||||||
# Install SDRPlay libraries
|
# Install SDRPlay libraries
|
||||||
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.1.run
|
||||||
@ -25,30 +25,10 @@ make install
|
|||||||
ldconfig
|
ldconfig
|
||||||
cd ..
|
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 ../../
|
|
||||||
|
|
||||||
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
|
cmake .. -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON -DOPT_BUILD_PERSEUS_SOURCE=ON
|
||||||
make VERBOSE=1 -j2
|
make VERBOSE=1 -j2
|
||||||
|
|
||||||
cd ..
|
cd ..
|
||||||
|
@ -6,7 +6,7 @@ cd /root
|
|||||||
apt update
|
apt update
|
||||||
apt install -y build-essential cmake git libfftw3-dev libglfw3-dev libvolk2-dev libzstd-dev libairspyhf-dev libairspy-dev \
|
apt install -y build-essential cmake git libfftw3-dev libglfw3-dev libvolk2-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 \
|
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
|
libcodec2-dev autoconf libtool xxd
|
||||||
|
|
||||||
# Install SDRPlay libraries
|
# Install SDRPlay libraries
|
||||||
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.1.run
|
||||||
@ -25,30 +25,10 @@ make install
|
|||||||
ldconfig
|
ldconfig
|
||||||
cd ..
|
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 ../../
|
|
||||||
|
|
||||||
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
|
cmake .. -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON -DOPT_BUILD_PERSEUS_SOURCE=ON
|
||||||
make VERBOSE=1 -j2
|
make VERBOSE=1 -j2
|
||||||
|
|
||||||
cd ..
|
cd ..
|
||||||
|
@ -6,7 +6,7 @@ cd /root
|
|||||||
apt update
|
apt update
|
||||||
apt install -y build-essential cmake git libfftw3-dev libglfw3-dev libvolk1-dev libzstd-dev libairspyhf-dev libairspy-dev \
|
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 \
|
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
|
libcodec2-dev autoconf libtool xxd
|
||||||
|
|
||||||
# Install SDRPlay libraries
|
# Install SDRPlay libraries
|
||||||
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.1.run
|
||||||
@ -25,30 +25,10 @@ make install
|
|||||||
ldconfig
|
ldconfig
|
||||||
cd ..
|
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 ../../
|
|
||||||
|
|
||||||
cd SDRPlusPlus
|
cd SDRPlusPlus
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
cmake .. -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_BLADERF_SOURCE=OFF -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON -DOPT_BUILD_PERSEUS_SOURCE=ON -DOPT_BUILD_RFNM_SOURCE=ON -DOPT_BUILD_FOBOSSDR_SOURCE=ON
|
cmake .. -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_BLADERF_SOURCE=OFF -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON -DOPT_BUILD_PERSEUS_SOURCE=ON
|
||||||
make VERBOSE=1 -j2
|
make VERBOSE=1 -j2
|
||||||
|
|
||||||
cd ..
|
cd ..
|
||||||
|
@ -6,7 +6,7 @@ cd /root
|
|||||||
apt update
|
apt update
|
||||||
apt install -y build-essential cmake git libfftw3-dev libglfw3-dev libvolk-dev libzstd-dev libairspyhf-dev libairspy-dev \
|
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 \
|
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
|
libcodec2-dev autoconf libtool xxd
|
||||||
|
|
||||||
# Install SDRPlay libraries
|
# Install SDRPlay libraries
|
||||||
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.1.run
|
||||||
@ -25,30 +25,10 @@ make install
|
|||||||
ldconfig
|
ldconfig
|
||||||
cd ..
|
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 ../../
|
|
||||||
|
|
||||||
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
|
cmake .. -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON -DOPT_BUILD_PERSEUS_SOURCE=ON
|
||||||
make VERBOSE=1 -j2
|
make VERBOSE=1 -j2
|
||||||
|
|
||||||
cd ..
|
cd ..
|
||||||
|
@ -12,7 +12,7 @@ apt update
|
|||||||
# Install dependencies and tools
|
# Install dependencies and tools
|
||||||
apt install -y build-essential cmake git libfftw3-dev libglfw3-dev libvolk1-dev libzstd-dev libairspy-dev \
|
apt install -y build-essential cmake git libfftw3-dev libglfw3-dev libvolk1-dev libzstd-dev libairspy-dev \
|
||||||
libiio-dev libad9361-dev librtaudio-dev libhackrf-dev librtlsdr-dev libbladerf-dev liblimesuite-dev p7zip-full wget portaudio19-dev \
|
libiio-dev libad9361-dev librtaudio-dev libhackrf-dev librtlsdr-dev libbladerf-dev liblimesuite-dev p7zip-full wget portaudio19-dev \
|
||||||
libcodec2-dev libudev-dev autoconf libtool xxd libspdlog-dev
|
libcodec2-dev libudev-dev autoconf libtool xxd
|
||||||
|
|
||||||
# Install SDRPlay libraries
|
# Install SDRPlay libraries
|
||||||
wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.15.1.run
|
wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.15.1.run
|
||||||
@ -51,26 +51,6 @@ make install
|
|||||||
ldconfig
|
ldconfig
|
||||||
cd ..
|
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 ../../
|
|
||||||
|
|
||||||
# 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
|
||||||
@ -86,9 +66,9 @@ echo 'Cflags: -I/usr/include/codec2' >> /usr/share/pkgconfig/codec2.pc
|
|||||||
cd SDRPlusPlus
|
cd SDRPlusPlus
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
cmake .. -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_BLADERF_SOURCE=OFF -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_OVERRIDE_STD_FILESYSTEM=ON -DOPT_BUILD_M17_DECODER=ON -DOPT_BUILD_PERSEUS_SOURCE=ON -DOPT_BUILD_RFNM_SOURCE=ON -DOPT_BUILD_FOBOSSDR_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
|
||||||
make VERBOSE=1 -j2
|
make VERBOSE=1 -j2
|
||||||
|
|
||||||
# Generate package
|
# Generate package
|
||||||
cd ..
|
cd ..
|
||||||
sh make_debian_package.sh ./build 'libfftw3-dev, libglfw3-dev, libvolk1-dev, librtaudio-dev, libzstd-dev'
|
sh make_debian_package.sh ./build 'libfftw3-bin, libglfw3, libvolk1-bin, librtaudio6, libzstd1'
|
@ -6,7 +6,7 @@ cd /root
|
|||||||
apt update
|
apt update
|
||||||
apt install -y build-essential cmake git libfftw3-dev libglfw3-dev libvolk2-dev libzstd-dev libairspyhf-dev libairspy-dev \
|
apt install -y build-essential cmake git libfftw3-dev libglfw3-dev libvolk2-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 \
|
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
|
libcodec2-dev autoconf libtool xxd
|
||||||
|
|
||||||
# Install SDRPlay libraries
|
# Install SDRPlay libraries
|
||||||
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.1.run
|
||||||
@ -25,31 +25,11 @@ make install
|
|||||||
ldconfig
|
ldconfig
|
||||||
cd ..
|
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 ../../
|
|
||||||
|
|
||||||
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
|
cmake .. -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON -DOPT_BUILD_PERSEUS_SOURCE=ON
|
||||||
make VERBOSE=1 -j2
|
make VERBOSE=1 -j2
|
||||||
|
|
||||||
cd ..
|
cd ..
|
||||||
sh make_debian_package.sh ./build 'libfftw3-dev, libglfw3-dev, libvolk2-dev, librtaudio-dev, libzstd-dev'
|
sh make_debian_package.sh ./build 'libfftw3-bin, libglfw3, libvolk2-bin, librtaudio6, libzstd1'
|
@ -6,7 +6,7 @@ cd /root
|
|||||||
apt update
|
apt update
|
||||||
apt install -y build-essential cmake git libfftw3-dev libglfw3-dev libvolk2-dev libzstd-dev libairspyhf-dev libairspy-dev \
|
apt install -y build-essential cmake git libfftw3-dev libglfw3-dev libvolk2-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 \
|
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
|
libcodec2-dev autoconf libtool xxd
|
||||||
|
|
||||||
# Install SDRPlay libraries
|
# Install SDRPlay libraries
|
||||||
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.1.run
|
||||||
@ -25,31 +25,11 @@ make install
|
|||||||
ldconfig
|
ldconfig
|
||||||
cd ..
|
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 ../../
|
|
||||||
|
|
||||||
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
|
cmake .. -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON -DOPT_BUILD_PERSEUS_SOURCE=ON
|
||||||
make VERBOSE=1 -j2
|
make VERBOSE=1 -j2
|
||||||
|
|
||||||
cd ..
|
cd ..
|
||||||
sh make_debian_package.sh ./build 'libfftw3-dev, libglfw3-dev, libvolk2-dev, librtaudio-dev, libzstd-dev'
|
sh make_debian_package.sh ./build 'libfftw3-bin, libglfw3, libvolk2-bin, librtaudio6, libzstd1'
|
@ -6,7 +6,7 @@ cd /root
|
|||||||
apt update
|
apt update
|
||||||
apt install -y build-essential cmake git libfftw3-dev libglfw3-dev libvolk-dev libzstd-dev libairspyhf-dev libairspy-dev \
|
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 \
|
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
|
libcodec2-dev autoconf libtool xxd
|
||||||
|
|
||||||
# Install SDRPlay libraries
|
# Install SDRPlay libraries
|
||||||
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.1.run
|
||||||
@ -25,31 +25,11 @@ make install
|
|||||||
ldconfig
|
ldconfig
|
||||||
cd ..
|
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 ../../
|
|
||||||
|
|
||||||
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
|
cmake .. -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON -DOPT_BUILD_PERSEUS_SOURCE=ON
|
||||||
make VERBOSE=1 -j2
|
make VERBOSE=1 -j2
|
||||||
|
|
||||||
cd ..
|
cd ..
|
||||||
sh make_debian_package.sh ./build 'libfftw3-dev, libglfw3-dev, libvolk-dev, librtaudio-dev, libzstd-dev'
|
sh make_debian_package.sh ./build 'libfftw3-bin, libglfw3, libvolk-bin, librtaudio6, libzstd1'
|
@ -6,7 +6,7 @@ cd /root
|
|||||||
apt update
|
apt update
|
||||||
apt install -y build-essential cmake git libfftw3-dev libglfw3-dev libvolk-dev libzstd-dev libairspyhf-dev libairspy-dev \
|
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 \
|
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
|
libcodec2-dev autoconf libtool xxd
|
||||||
|
|
||||||
# Install SDRPlay libraries
|
# Install SDRPlay libraries
|
||||||
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.1.run
|
||||||
@ -25,31 +25,11 @@ make install
|
|||||||
ldconfig
|
ldconfig
|
||||||
cd ..
|
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 ../../
|
|
||||||
|
|
||||||
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
|
cmake .. -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON -DOPT_BUILD_PERSEUS_SOURCE=ON
|
||||||
make VERBOSE=1 -j2
|
make VERBOSE=1 -j2
|
||||||
|
|
||||||
cd ..
|
cd ..
|
||||||
sh make_debian_package.sh ./build 'libfftw3-dev, libglfw3-dev, libvolk-dev, librtaudio-dev, libzstd-dev'
|
sh make_debian_package.sh ./build 'libfftw3-bin, libglfw3, libvolk-bin, librtaudio6, libzstd1'
|
@ -35,14 +35,11 @@ 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/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/rfspace_source/rfspace_source.dylib
|
bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/source_modules/rfspace_source/rfspace_source.dylib
|
||||||
bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/source_modules/rtl_sdr_source/rtl_sdr_source.dylib
|
bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/source_modules/rtl_sdr_source/rtl_sdr_source.dylib
|
||||||
bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/source_modules/rtl_tcp_source/rtl_tcp_source.dylib
|
bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/source_modules/rtl_tcp_source/rtl_tcp_source.dylib
|
||||||
|
@ -7,95 +7,86 @@ mkdir sdrpp_windows_x64
|
|||||||
cp -Recurse $root_dir/* sdrpp_windows_x64/
|
cp -Recurse $root_dir/* sdrpp_windows_x64/
|
||||||
|
|
||||||
# Copy core
|
# Copy core
|
||||||
cp $build_dir/Release/* sdrpp_windows_x64/
|
cp $build_dir/Debug/* sdrpp_windows_x64/
|
||||||
|
cp $build_dir/core/Debug/sdrpp_core.pdb sdrpp_windows_x64/
|
||||||
cp 'C:/Program Files/PothosSDR/bin/volk.dll' sdrpp_windows_x64/
|
cp 'C:/Program Files/PothosSDR/bin/volk.dll' sdrpp_windows_x64/
|
||||||
|
|
||||||
# Copy source modules
|
# Copy source modules
|
||||||
cp $build_dir/source_modules/airspy_source/Release/airspy_source.dll sdrpp_windows_x64/modules/
|
cp $build_dir/source_modules/airspy_source/Debug/airspy_source.dll sdrpp_windows_x64/modules/
|
||||||
cp 'C:/Program Files/PothosSDR/bin/airspy.dll' sdrpp_windows_x64/
|
cp 'C:/Program Files/PothosSDR/bin/airspy.dll' sdrpp_windows_x64/
|
||||||
|
|
||||||
cp $build_dir/source_modules/airspyhf_source/Release/airspyhf_source.dll sdrpp_windows_x64/modules/
|
cp $build_dir/source_modules/airspyhf_source/Debug/airspyhf_source.dll sdrpp_windows_x64/modules/
|
||||||
cp 'C:/Program Files/PothosSDR/bin/airspyhf.dll' sdrpp_windows_x64/
|
cp 'C:/Program Files/PothosSDR/bin/airspyhf.dll' sdrpp_windows_x64/
|
||||||
|
|
||||||
cp $build_dir/source_modules/audio_source/Release/audio_source.dll sdrpp_windows_x64/modules/
|
cp $build_dir/source_modules/audio_source/Debug/audio_source.dll sdrpp_windows_x64/modules/
|
||||||
|
|
||||||
cp $build_dir/source_modules/bladerf_source/Release/bladerf_source.dll sdrpp_windows_x64/modules/
|
cp $build_dir/source_modules/bladerf_source/Debug/bladerf_source.dll sdrpp_windows_x64/modules/
|
||||||
cp 'C:/Program Files/PothosSDR/bin/bladeRF.dll' sdrpp_windows_x64/
|
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/Debug/file_source.dll sdrpp_windows_x64/modules/
|
||||||
|
|
||||||
cp $build_dir/source_modules/fobossdr_source/Release/fobossdr_source.dll sdrpp_windows_x64/modules/
|
cp $build_dir/source_modules/hackrf_source/Debug/hackrf_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 '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/Debug/hermes_source.dll sdrpp_windows_x64/modules/
|
||||||
|
|
||||||
cp $build_dir/source_modules/limesdr_source/Release/limesdr_source.dll sdrpp_windows_x64/modules/
|
cp $build_dir/source_modules/limesdr_source/Debug/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/Debug/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/
|
||||||
|
|
||||||
cp $build_dir/source_modules/plutosdr_source/Release/plutosdr_source.dll sdrpp_windows_x64/modules/
|
cp $build_dir/source_modules/plutosdr_source/Debug/plutosdr_source.dll sdrpp_windows_x64/modules/
|
||||||
cp 'C:/Program Files/PothosSDR/bin/libiio.dll' sdrpp_windows_x64/
|
cp 'C:/Program Files/PothosSDR/bin/libiio.dll' sdrpp_windows_x64/
|
||||||
cp 'C:/Program Files/PothosSDR/bin/libad9361.dll' sdrpp_windows_x64/
|
cp 'C:/Program Files/PothosSDR/bin/libad9361.dll' sdrpp_windows_x64/
|
||||||
|
|
||||||
cp $build_dir/source_modules/rfnm_source/Release/rfnm_source.dll sdrpp_windows_x64/modules/
|
cp $build_dir/source_modules/rfspace_source/Debug/rfspace_source.dll sdrpp_windows_x64/modules/
|
||||||
cp 'C:/Program Files/RFNM/bin/rfnm.dll' sdrpp_windows_x64/
|
|
||||||
cp 'C:/Program Files/RFNM/bin/spdlog.dll' sdrpp_windows_x64/
|
|
||||||
cp 'C:/Program Files/RFNM/bin/fmt.dll' sdrpp_windows_x64/
|
|
||||||
|
|
||||||
cp $build_dir/source_modules/rfspace_source/Release/rfspace_source.dll sdrpp_windows_x64/modules/
|
cp $build_dir/source_modules/rtl_sdr_source/Debug/rtl_sdr_source.dll sdrpp_windows_x64/modules/
|
||||||
|
|
||||||
cp $build_dir/source_modules/rtl_sdr_source/Release/rtl_sdr_source.dll sdrpp_windows_x64/modules/
|
|
||||||
cp 'C:/Program Files/PothosSDR/bin/rtlsdr.dll' sdrpp_windows_x64/
|
cp 'C:/Program Files/PothosSDR/bin/rtlsdr.dll' sdrpp_windows_x64/
|
||||||
|
|
||||||
cp $build_dir/source_modules/rtl_tcp_source/Release/rtl_tcp_source.dll sdrpp_windows_x64/modules/
|
cp $build_dir/source_modules/rtl_tcp_source/Debug/rtl_tcp_source.dll sdrpp_windows_x64/modules/
|
||||||
|
|
||||||
cp $build_dir/source_modules/sdrplay_source/Release/sdrplay_source.dll sdrpp_windows_x64/modules/ -ErrorAction SilentlyContinue
|
cp $build_dir/source_modules/sdrplay_source/Debug/sdrplay_source.dll sdrpp_windows_x64/modules/ -ErrorAction SilentlyContinue
|
||||||
cp 'C:/Program Files/SDRplay/API/x64/sdrplay_api.dll' sdrpp_windows_x64/ -ErrorAction SilentlyContinue
|
cp 'C:/Program Files/SDRplay/API/x64/sdrplay_api.dll' sdrpp_windows_x64/ -ErrorAction SilentlyContinue
|
||||||
|
|
||||||
cp $build_dir/source_modules/sdrpp_server_source/Release/sdrpp_server_source.dll sdrpp_windows_x64/modules/
|
cp $build_dir/source_modules/sdrpp_server_source/Debug/sdrpp_server_source.dll sdrpp_windows_x64/modules/
|
||||||
|
|
||||||
cp $build_dir/source_modules/spyserver_source/Release/spyserver_source.dll sdrpp_windows_x64/modules/
|
cp $build_dir/source_modules/spyserver_source/Debug/spyserver_source.dll sdrpp_windows_x64/modules/
|
||||||
|
|
||||||
# cp $build_dir/source_modules/usrp_source/Release/usrp_source.dll sdrpp_windows_x64/modules/
|
# cp $build_dir/source_modules/usrp_source/Debug/usrp_source.dll sdrpp_windows_x64/modules/
|
||||||
|
|
||||||
|
|
||||||
# Copy sink modules
|
# Copy sink modules
|
||||||
cp $build_dir/sink_modules/audio_sink/Release/audio_sink.dll sdrpp_windows_x64/modules/
|
cp $build_dir/sink_modules/audio_sink/Debug/audio_sink.dll sdrpp_windows_x64/modules/
|
||||||
cp "C:/Program Files (x86)/RtAudio/bin/rtaudio.dll" sdrpp_windows_x64/
|
cp "C:/Program Files (x86)/RtAudio/bin/rtaudio.dll" sdrpp_windows_x64/
|
||||||
|
|
||||||
cp $build_dir/sink_modules/network_sink/Release/network_sink.dll sdrpp_windows_x64/modules/
|
cp $build_dir/sink_modules/network_sink/Debug/network_sink.dll sdrpp_windows_x64/modules/
|
||||||
|
|
||||||
|
|
||||||
# Copy decoder modules
|
# Copy decoder modules
|
||||||
cp $build_dir/decoder_modules/m17_decoder/Release/m17_decoder.dll sdrpp_windows_x64/modules/
|
cp $build_dir/decoder_modules/m17_decoder/Debug/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/
|
||||||
|
|
||||||
cp $build_dir/decoder_modules/meteor_demodulator/Release/meteor_demodulator.dll sdrpp_windows_x64/modules/
|
cp $build_dir/decoder_modules/meteor_demodulator/Debug/meteor_demodulator.dll sdrpp_windows_x64/modules/
|
||||||
|
|
||||||
cp $build_dir/decoder_modules/radio/Release/radio.dll sdrpp_windows_x64/modules/
|
cp $build_dir/decoder_modules/radio/Debug/radio.dll sdrpp_windows_x64/modules/
|
||||||
|
|
||||||
|
|
||||||
# Copy misc modules
|
# Copy misc modules
|
||||||
cp $build_dir/misc_modules/discord_integration/Release/discord_integration.dll sdrpp_windows_x64/modules/
|
cp $build_dir/misc_modules/discord_integration/Debug/discord_integration.dll sdrpp_windows_x64/modules/
|
||||||
|
|
||||||
cp $build_dir/misc_modules/frequency_manager/Release/frequency_manager.dll sdrpp_windows_x64/modules/
|
cp $build_dir/misc_modules/frequency_manager/Debug/frequency_manager.dll sdrpp_windows_x64/modules/
|
||||||
|
|
||||||
cp $build_dir/misc_modules/iq_exporter/Release/iq_exporter.dll sdrpp_windows_x64/modules/
|
cp $build_dir/misc_modules/iq_exporter/Debug/iq_exporter.dll sdrpp_windows_x64/modules/
|
||||||
|
|
||||||
cp $build_dir/misc_modules/recorder/Release/recorder.dll sdrpp_windows_x64/modules/
|
cp $build_dir/misc_modules/recorder/Debug/recorder.dll sdrpp_windows_x64/modules/
|
||||||
|
|
||||||
cp $build_dir/misc_modules/rigctl_client/Release/rigctl_client.dll sdrpp_windows_x64/modules/
|
cp $build_dir/misc_modules/rigctl_client/Debug/rigctl_client.dll sdrpp_windows_x64/modules/
|
||||||
|
|
||||||
cp $build_dir/misc_modules/rigctl_server/Release/rigctl_server.dll sdrpp_windows_x64/modules/
|
cp $build_dir/misc_modules/rigctl_server/Debug/rigctl_server.dll sdrpp_windows_x64/modules/
|
||||||
|
|
||||||
cp $build_dir/misc_modules/scanner/Release/scanner.dll sdrpp_windows_x64/modules/
|
cp $build_dir/misc_modules/scanner/Debug/scanner.dll sdrpp_windows_x64/modules/
|
||||||
|
|
||||||
|
|
||||||
# Copy supporting libs
|
# Copy supporting libs
|
||||||
|
12
min_broken/main.cpp
Normal file
12
min_broken/main.cpp
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
std::recursive_mutex mtx;
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
std::lock_guard<std::recursive_mutex> lck(mtx);
|
||||||
|
|
||||||
|
printf("Works just fine!\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
@ -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;
|
||||||
@ -248,6 +249,7 @@ private:
|
|||||||
}
|
}
|
||||||
ImGui::Columns(1, CONCAT("EndRecorderModeColumns##_", _this->name), false);
|
ImGui::Columns(1, CONCAT("EndRecorderModeColumns##_", _this->name), false);
|
||||||
ImGui::EndGroup();
|
ImGui::EndGroup();
|
||||||
|
if (_this->recording) { style::endDisabled(); }
|
||||||
|
|
||||||
// Recording path
|
// Recording path
|
||||||
if (_this->folderSelect.render("##_recorder_fold_" + _this->name)) {
|
if (_this->folderSelect.render("##_recorder_fold_" + _this->name)) {
|
||||||
@ -282,11 +284,8 @@ private:
|
|||||||
config.release(true);
|
config.release(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_this->recording) { style::endDisabled(); }
|
|
||||||
|
|
||||||
// Show additional audio options
|
// Show additional audio options
|
||||||
if (_this->recMode == RECORDER_MODE_AUDIO) {
|
if (_this->recMode == RECORDER_MODE_AUDIO) {
|
||||||
if (_this->recording) { style::beginDisabled(); }
|
|
||||||
ImGui::LeftLabel("Stream");
|
ImGui::LeftLabel("Stream");
|
||||||
ImGui::FillWidth();
|
ImGui::FillWidth();
|
||||||
if (ImGui::Combo(CONCAT("##_recorder_stream_", _this->name), &_this->streamId, _this->audioStreams.txt)) {
|
if (ImGui::Combo(CONCAT("##_recorder_stream_", _this->name), &_this->streamId, _this->audioStreams.txt)) {
|
||||||
@ -295,7 +294,6 @@ private:
|
|||||||
config.conf[_this->name]["audioStream"] = _this->audioStreams.key(_this->streamId);
|
config.conf[_this->name]["audioStream"] = _this->audioStreams.key(_this->streamId);
|
||||||
config.release(true);
|
config.release(true);
|
||||||
}
|
}
|
||||||
if (_this->recording) { style::endDisabled(); }
|
|
||||||
|
|
||||||
_this->updateAudioMeter(_this->audioLvl);
|
_this->updateAudioMeter(_this->audioLvl);
|
||||||
ImGui::FillWidth();
|
ImGui::FillWidth();
|
||||||
@ -451,7 +449,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 +459,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 +467,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);
|
||||||
|
27
readme.md
27
readme.md
@ -41,13 +41,14 @@ To create a desktop shortcut, rightclick the exe and select `Send to -> Desktop
|
|||||||
|
|
||||||
Download the latest release from [the Releases page](https://github.com/AlexandreRouma/SDRPlusPlus/releases) and extract to the directory of your choice.
|
Download the latest release from [the Releases page](https://github.com/AlexandreRouma/SDRPlusPlus/releases) and extract to the directory of your choice.
|
||||||
|
|
||||||
Then, use apt to install it:
|
Then, run:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
sudo apt install path/to/the/sdrpp_debian_amd64.deb
|
sudo apt install libfftw3-dev libglfw3-dev libvolk2-dev libzstd-dev libairspyhf-dev libiio-dev libad9361-dev librtaudio-dev libhackrf-dev
|
||||||
|
sudo dpkg -i sdrpp_debian_amd64.deb
|
||||||
```
|
```
|
||||||
|
|
||||||
**IMPORTANT: You must install the drivers for your SDR. Follow instructions from your manufacturer as to how to do this on your particular distro.**
|
If `libvolk2-dev` is not available, use `libvolk1-dev`.
|
||||||
|
|
||||||
### Arch-based
|
### Arch-based
|
||||||
|
|
||||||
@ -324,16 +325,13 @@ 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 | ⛔ | ⛔ | ✅ |
|
|
||||||
| 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 | ⛔ | ⛔ | ⛔ |
|
||||||
| rfspace_source | Working | - | OPT_BUILD_RFSPACE_SOURCE | ✅ | ✅ | ✅ |
|
| rfspace_source | Working | - | OPT_BUILD_RFSPACE_SOURCE | ✅ | ✅ | ✅ |
|
||||||
| rtl_sdr_source | Working | librtlsdr | OPT_BUILD_RTL_SDR_SOURCE | ✅ | ✅ | ✅ |
|
| rtl_sdr_source | Working | librtlsdr | OPT_BUILD_RTL_SDR_SOURCE | ✅ | ✅ | ✅ |
|
||||||
| rtl_tcp_source | Working | - | OPT_BUILD_RTL_TCP_SOURCE | ✅ | ✅ | ✅ |
|
| rtl_tcp_source | Working | - | OPT_BUILD_RTL_TCP_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,15 +350,14 @@ 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 | ⛔ | ✅ | ⛔ |
|
||||||
@ -419,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
|
||||||
|
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
"name": "France",
|
"name": "France",
|
||||||
"country_name": "France",
|
"country_name": "France",
|
||||||
"country_code": "FR",
|
"country_code": "FR",
|
||||||
"author_name": "Fred F4EED, Armand31",
|
"author_name": "Fred F4EED",
|
||||||
"author_url": "http://f4eed.wordpress.com, https://github.com/Armand31",
|
"author_url": "http://f4eed.wordpress.com",
|
||||||
"bands": [
|
"bands": [
|
||||||
{
|
{
|
||||||
"name": "137KHz - Radioamateur",
|
"name": "137KHz - Radioamateur",
|
||||||
@ -355,7 +355,7 @@
|
|||||||
"end": 54000000
|
"end": 54000000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Radiodiffusion - Bande FM",
|
"name": "Bande FM - Radiodif.",
|
||||||
"type": "broadcast",
|
"type": "broadcast",
|
||||||
"start": 80000000,
|
"start": 80000000,
|
||||||
"end": 108000000
|
"end": 108000000
|
||||||
@ -396,12 +396,6 @@
|
|||||||
"start": 162362500,
|
"start": 162362500,
|
||||||
"end": 162587500
|
"end": 162587500
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "Radiodiffusion - Bande DAB",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 174000000,
|
|
||||||
"end": 223000000
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "Military Aviation",
|
"name": "Military Aviation",
|
||||||
"type": "military",
|
"type": "military",
|
||||||
@ -414,12 +408,6 @@
|
|||||||
"start": 240000000,
|
"start": 240000000,
|
||||||
"end": 270000000
|
"end": 270000000
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "Police (TETRAPOL)",
|
|
||||||
"type": "military",
|
|
||||||
"start": 380000000,
|
|
||||||
"end": 400000000
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "70cm - Radioamateur",
|
"name": "70cm - Radioamateur",
|
||||||
"type": "amateur",
|
"type": "amateur",
|
||||||
@ -432,24 +420,12 @@
|
|||||||
"start": 446000000,
|
"start": 446000000,
|
||||||
"end": 446200000
|
"end": 446200000
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "TNT (DVB-T)",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 470000000,
|
|
||||||
"end": 694000000
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "23cm - Radioamateur",
|
"name": "23cm - Radioamateur",
|
||||||
"type": "amateur",
|
"type": "amateur",
|
||||||
"start": 1240000000,
|
"start": 1240000000,
|
||||||
"end": 1300000000
|
"end": 1300000000
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "Radiodiffusion - Bande DAB",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 1452000000,
|
|
||||||
"end": 1492000000
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "13cm - Radioamateur",
|
"name": "13cm - Radioamateur",
|
||||||
"type": "amateur",
|
"type": "amateur",
|
||||||
|
@ -1,117 +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": "120m SW broadcast",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 2300000,
|
|
||||||
"end": 2495000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "90m SW Broadcast",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 3200000,
|
|
||||||
"end": 3400000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "75m SW Broadcast",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 3900000,
|
|
||||||
"end": 4000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "60m SW Broadcast",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 4750000,
|
|
||||||
"end": 5060000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "49m SW Broadcast",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 5900000,
|
|
||||||
"end": 6200000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "40m SW Broadcast",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 7200000,
|
|
||||||
"end": 7450000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "31m SW Broadcast",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 9400000,
|
|
||||||
"end": 9900000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "25m SW Broadcast",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 11600000,
|
|
||||||
"end": 12100000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "22m SW Broadcast",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 13570000,
|
|
||||||
"end": 13870000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "19m SW Broadcast",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 15100000,
|
|
||||||
"end": 15800000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "16m SW Broadcast",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 17480000,
|
|
||||||
"end": 17900000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "15m SW Broadcast",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 18900000,
|
|
||||||
"end": 19020000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "13m SW Broadcast",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 21450000,
|
|
||||||
"end": 21850000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "11m SW Broadcast",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 25670000,
|
|
||||||
"end": 26100000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "FM Broadcast",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 87500000,
|
|
||||||
"end": 108000000
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
@ -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
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,285 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "Turkey",
|
|
||||||
"country_name": "Turkey",
|
|
||||||
"country_code": "TR",
|
|
||||||
"author_name": "Yunus TA2PEA",
|
|
||||||
"author_url": "https://github.com/ycanerol",
|
|
||||||
"bands": [
|
|
||||||
{
|
|
||||||
"name": "LW",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 135700,
|
|
||||||
"end": 137800
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "630m",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 472000,
|
|
||||||
"end": 479000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "160m",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 1810000,
|
|
||||||
"end": 1850000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "80m",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 3500000,
|
|
||||||
"end": 3800000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "60m",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 5351500,
|
|
||||||
"end": 5366500
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "40m",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 7000000,
|
|
||||||
"end": 7200000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "30m",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 10100000,
|
|
||||||
"end": 10150000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "20m",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 14000000,
|
|
||||||
"end": 14350000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "17m",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 18068000,
|
|
||||||
"end": 18168000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "15m",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 21000000,
|
|
||||||
"end": 21450000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "12m",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 24890000,
|
|
||||||
"end": 24990000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "CB",
|
|
||||||
"type": "other",
|
|
||||||
"start": 26565000,
|
|
||||||
"end": 27405000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Pagers",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 27750000,
|
|
||||||
"end": 28000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "10m",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 28000000,
|
|
||||||
"end": 29700000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "6m",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 50030000,
|
|
||||||
"end": 51000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "FM",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 87500000,
|
|
||||||
"end": 108000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Airband VOR/ILS",
|
|
||||||
"type": "aviation",
|
|
||||||
"start": 108000000,
|
|
||||||
"end": 117975000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Airband Voice",
|
|
||||||
"type": "aviation",
|
|
||||||
"start": 117975000,
|
|
||||||
"end": 137000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "2m",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 144000000,
|
|
||||||
"end": 146000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Sayac Okuma",
|
|
||||||
"type": "other",
|
|
||||||
"start": 169400000,
|
|
||||||
"end": 169475000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Pagers",
|
|
||||||
"type": "other",
|
|
||||||
"start": 167000000,
|
|
||||||
"end": 167100000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Public announcement systems",
|
|
||||||
"type": "other",
|
|
||||||
"start": 173882500,
|
|
||||||
"end": 174000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "DVB-T",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 174000000,
|
|
||||||
"end": 216000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "T-DAB",
|
|
||||||
"type": "broadcast",
|
|
||||||
"start": 216000000,
|
|
||||||
"end": 233000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "ILS-Glide Path",
|
|
||||||
"type": "aviation",
|
|
||||||
"start": 328600000,
|
|
||||||
"end": 335400000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Public Safety/Emergency",
|
|
||||||
"type": "other",
|
|
||||||
"start": 380000000,
|
|
||||||
"end": 385000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Public Safety/Emergency",
|
|
||||||
"type": "other",
|
|
||||||
"start": 390000000,
|
|
||||||
"end": 395000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "70cm",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 430200000,
|
|
||||||
"end": 430700000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "70cm-RepeaterRX",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 431550000,
|
|
||||||
"end": 431825000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "70cm",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 432000000,
|
|
||||||
"end": 432975000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "70cm",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 433400000,
|
|
||||||
"end": 434000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "70cm",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 435000000,
|
|
||||||
"end": 438000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "70cm-RepeaterTX",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 439150000,
|
|
||||||
"end": 439425000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Public announcement systems",
|
|
||||||
"type": "other",
|
|
||||||
"start": 445250000,
|
|
||||||
"end": 445462500
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "PMR446",
|
|
||||||
"type": "other",
|
|
||||||
"start": 446006250,
|
|
||||||
"end": 446196875
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "RFID",
|
|
||||||
"type": "other",
|
|
||||||
"start": 865000000,
|
|
||||||
"end": 868000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "RFID",
|
|
||||||
"type": "other",
|
|
||||||
"start": 916100000,
|
|
||||||
"end": 918900000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "23cm",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 1240000000,
|
|
||||||
"end": 1300000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "DECT",
|
|
||||||
"type": "other",
|
|
||||||
"start": 1880000000,
|
|
||||||
"end": 1900000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "5GHz",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 5650000000,
|
|
||||||
"end": 5670000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "5GHz",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 5820000000,
|
|
||||||
"end": 5850000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "3cm",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 104500000000,
|
|
||||||
"end": 104520000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "24GHz",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 24000000000,
|
|
||||||
"end": 24050000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "47GHz",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 47000000000,
|
|
||||||
"end": 47200000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "75GHz",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 75500000000,
|
|
||||||
"end": 7600000000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "134GHz",
|
|
||||||
"type": "amateur",
|
|
||||||
"start": 134000000000,
|
|
||||||
"end": 142000000000
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,25 +0,0 @@
|
|||||||
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 ()
|
|
@ -1,309 +0,0 @@
|
|||||||
#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);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,53 +0,0 @@
|
|||||||
#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);
|
|
||||||
}
|
|
@ -1,272 +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 <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
|
|
||||||
}
|
|
@ -1,622 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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);
|
|
||||||
}
|
|
@ -1,58 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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,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,17 +0,0 @@
|
|||||||
cmake_minimum_required(VERSION 3.13)
|
|
||||||
project(harogic_source)
|
|
||||||
|
|
||||||
file(GLOB SRC "src/*.cpp")
|
|
||||||
|
|
||||||
include(${SDRPP_MODULE_CMAKE})
|
|
||||||
|
|
||||||
if (MSVC)
|
|
||||||
# Lib path
|
|
||||||
target_link_directories(harogic_source PRIVATE "C:/radio/HTRA_API/x64/htra_api/")
|
|
||||||
target_include_directories(harogic_source PRIVATE "C:/radio/HTRA_API/x64/htra_api/")
|
|
||||||
target_link_libraries(harogic_source PRIVATE htra_api)
|
|
||||||
else (MSVC)
|
|
||||||
target_link_directories(harogic_source PRIVATE "/opt/htraapi/lib/${CMAKE_SYSTEM_PROCESSOR}/")
|
|
||||||
target_include_directories(harogic_source PRIVATE "/opt/htraapi/inc/")
|
|
||||||
target_link_libraries(harogic_source PRIVATE htraapi)
|
|
||||||
endif ()
|
|
@ -1,510 +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 <htra_api.h>
|
|
||||||
#include <atomic>
|
|
||||||
|
|
||||||
SDRPP_MOD_INFO{
|
|
||||||
/* Name: */ "harogic_source",
|
|
||||||
/* Description: */ "harogic Source Module",
|
|
||||||
/* Author: */ "Ryzerth",
|
|
||||||
/* Version: */ 0, 1, 0,
|
|
||||||
/* Max instances */ -1
|
|
||||||
};
|
|
||||||
|
|
||||||
#define CONCAT(a, b) ((std::string(a) + b).c_str())
|
|
||||||
|
|
||||||
class HarogicSourceModule : public ModuleManager::Instance {
|
|
||||||
public:
|
|
||||||
HarogicSourceModule(std::string name) {
|
|
||||||
this->name = name;
|
|
||||||
|
|
||||||
sampleRate = 61440000.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 devices
|
|
||||||
refresh();
|
|
||||||
|
|
||||||
// Select first (TODO: Select from config)
|
|
||||||
select("");
|
|
||||||
|
|
||||||
sigpath::sourceManager.registerSource("Harogic", &handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
~HarogicSourceModule() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void postInit() {}
|
|
||||||
|
|
||||||
void enable() {
|
|
||||||
enabled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void disable() {
|
|
||||||
enabled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isEnabled() {
|
|
||||||
return enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void refresh() {
|
|
||||||
devices.clear();
|
|
||||||
|
|
||||||
// Set up the device parameters
|
|
||||||
BootProfile_TypeDef profile = {};
|
|
||||||
profile.PhysicalInterface = PhysicalInterface_TypeDef::USB;
|
|
||||||
profile.DevicePowerSupply = DevicePowerSupply_TypeDef::USBPortOnly;
|
|
||||||
|
|
||||||
// Working variables
|
|
||||||
void* dev;
|
|
||||||
BootInfo_TypeDef binfo;
|
|
||||||
|
|
||||||
for (int i = 0; i < 128; i++) {
|
|
||||||
// Attempt to open the device with the given ID
|
|
||||||
int ret = Device_Open(&dev, i, &profile, &binfo);
|
|
||||||
if (ret < 0) { break; }
|
|
||||||
|
|
||||||
// Create serial string
|
|
||||||
char serial[64];
|
|
||||||
sprintf(serial, "%" PRIX64, binfo.DeviceInfo.DeviceUID);
|
|
||||||
|
|
||||||
// Add the device to the list
|
|
||||||
devices.define(serial, serial, i);
|
|
||||||
|
|
||||||
// Close the device
|
|
||||||
Device_Close(&dev);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 menu ID
|
|
||||||
devId = devices.keyId(serial);
|
|
||||||
selectedDevIndex = devices.value(devId);
|
|
||||||
|
|
||||||
// Set up the device parameters
|
|
||||||
BootProfile_TypeDef bprofile = {};
|
|
||||||
bprofile.PhysicalInterface = PhysicalInterface_TypeDef::USB;
|
|
||||||
bprofile.DevicePowerSupply = DevicePowerSupply_TypeDef::USBPortOnly;
|
|
||||||
|
|
||||||
// Working variables
|
|
||||||
BootInfo_TypeDef binfo;
|
|
||||||
|
|
||||||
// Attempt to open the device by ID
|
|
||||||
void* dev;
|
|
||||||
int ret = Device_Open(&dev, selectedDevIndex, &bprofile, &binfo);
|
|
||||||
if (ret < 0) {
|
|
||||||
flog::error("Could not open device: {}", ret);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the default streaming parameters to query some info
|
|
||||||
IQS_Profile_TypeDef profile;
|
|
||||||
IQS_ProfileDeInit(&dev, &profile);
|
|
||||||
|
|
||||||
// Compute all available samplerates
|
|
||||||
samplerates.clear();
|
|
||||||
for (int i = 0; i < 8; i++) {
|
|
||||||
double sr = profile.NativeIQSampleRate_SPS / (double)(1 << i);
|
|
||||||
char buf[128];
|
|
||||||
sprintf(buf, "%.02fMHz", sr / 1e6);
|
|
||||||
samplerates.define(1 << i, buf, sr);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Define RX ports
|
|
||||||
rxPorts.clear();
|
|
||||||
rxPorts.define("external", "External", ExternalPort);
|
|
||||||
rxPorts.define("internal", "Internal", InternalPort);
|
|
||||||
rxPorts.define("ant", "ANT", ANT_Port);
|
|
||||||
rxPorts.define("tr", "T/R", TR_Port);
|
|
||||||
rxPorts.define("swr", "SWR", SWR_Port);
|
|
||||||
rxPorts.define("int", "INT", INT_Port);
|
|
||||||
|
|
||||||
// Define gain strategies
|
|
||||||
gainStategies.clear();
|
|
||||||
gainStategies.define("lowNoise", "Low Noise", LowNoisePreferred);
|
|
||||||
gainStategies.define("highLinearity", "High Linearity", HighLinearityPreferred);
|
|
||||||
|
|
||||||
// Define preamplifier modes
|
|
||||||
preampModes.clear();
|
|
||||||
preampModes.define("auto", "Auto", AutoOn);
|
|
||||||
preampModes.define("off", "Off", ForcedOff);
|
|
||||||
|
|
||||||
// Define LO modes
|
|
||||||
loModes.clear();
|
|
||||||
loModes.define("auto", "Auto", LOOpt_Auto);
|
|
||||||
loModes.define("speed", "Speed", LOOpt_Speed);
|
|
||||||
loModes.define("spurs", "Spurs", LOOpt_Spur);
|
|
||||||
loModes.define("phaseNoise", "Phase Noise", LOOpt_PhaseNoise);
|
|
||||||
|
|
||||||
// Close the device
|
|
||||||
Device_Close(&dev);
|
|
||||||
|
|
||||||
// TODO: Load configuration
|
|
||||||
sampleRate = samplerates.value(0);
|
|
||||||
refLvl = 0;
|
|
||||||
portId = rxPorts.valueId(ExternalPort);
|
|
||||||
gainStratId = gainStategies.valueId(LowNoisePreferred);
|
|
||||||
preampModeId = preampModes.valueId(AutoOn);
|
|
||||||
ifAgc = false;
|
|
||||||
loModeId = loModes.valueId(LOOpt_Auto);
|
|
||||||
|
|
||||||
// Update the samplerate
|
|
||||||
core::setInputSampleRate(sampleRate);
|
|
||||||
|
|
||||||
// Save serial number
|
|
||||||
selectedSerial = serial;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void menuSelected(void* ctx) {
|
|
||||||
HarogicSourceModule* _this = (HarogicSourceModule*)ctx;
|
|
||||||
core::setInputSampleRate(_this->sampleRate);
|
|
||||||
flog::info("HarogicSourceModule '{0}': Menu Select!", _this->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void menuDeselected(void* ctx) {
|
|
||||||
HarogicSourceModule* _this = (HarogicSourceModule*)ctx;
|
|
||||||
flog::info("HarogicSourceModule '{0}': Menu Deselect!", _this->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void start(void* ctx) {
|
|
||||||
HarogicSourceModule* _this = (HarogicSourceModule*)ctx;
|
|
||||||
if (_this->running) { return; }
|
|
||||||
|
|
||||||
// Set up the device parameters
|
|
||||||
BootProfile_TypeDef bprofile = {};
|
|
||||||
bprofile.PhysicalInterface = PhysicalInterface_TypeDef::USB;
|
|
||||||
bprofile.DevicePowerSupply = DevicePowerSupply_TypeDef::USBPortAndPowerPort;
|
|
||||||
|
|
||||||
// Working variables
|
|
||||||
BootInfo_TypeDef binfo;
|
|
||||||
|
|
||||||
// Attempt to open the device by ID
|
|
||||||
int ret = Device_Open(&_this->openDev, _this->selectedDevIndex, &bprofile, &binfo);
|
|
||||||
if (ret < 0) {
|
|
||||||
flog::error("Could not open device: {}", ret);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the decimation amount
|
|
||||||
int dec = _this->samplerates.key(_this->samplerates.valueId(_this->sampleRate));
|
|
||||||
flog::debug("Using decimation factor: {}", dec);
|
|
||||||
|
|
||||||
// Decide to use either 8 or 16bit samples
|
|
||||||
_this->sampsInt8 = (_this->sampleRate > 64e6);
|
|
||||||
|
|
||||||
// Get the default configuration
|
|
||||||
IQS_ProfileDeInit(&_this->openDev, &_this->profile);
|
|
||||||
|
|
||||||
// Automatic configuration
|
|
||||||
_this->profile.Atten = -1;
|
|
||||||
_this->profile.BusTimeout_ms = 100;
|
|
||||||
_this->profile.TriggerSource = Bus;
|
|
||||||
_this->profile.TriggerMode = Adaptive;
|
|
||||||
_this->profile.DataFormat = _this->sampsInt8 ? Complex8bit : Complex16bit;
|
|
||||||
|
|
||||||
// User selectable config
|
|
||||||
_this->profile.CenterFreq_Hz = _this->freq;
|
|
||||||
_this->profile.RefLevel_dBm = _this->refLvl;
|
|
||||||
_this->profile.DecimateFactor = dec;
|
|
||||||
_this->profile.RxPort = _this->rxPorts.value(_this->portId);
|
|
||||||
_this->profile.GainStrategy = _this->gainStategies.value(_this->gainStratId);
|
|
||||||
_this->profile.Preamplifier = _this->preampModes.value(_this->preampModeId);
|
|
||||||
_this->profile.EnableIFAGC = _this->ifAgc;
|
|
||||||
_this->profile.LOOptimization = _this->loModes.value(_this->loModeId);
|
|
||||||
|
|
||||||
// Apply the configuration
|
|
||||||
IQS_StreamInfo_TypeDef info;
|
|
||||||
ret = IQS_Configuration(&_this->openDev, &_this->profile, &_this->profile, &info);
|
|
||||||
if (ret < 0) {
|
|
||||||
flog::error("Could not configure device: {}", ret);
|
|
||||||
Device_Close(&_this->openDev);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save the stream configuration
|
|
||||||
_this->bufferSize = info.PacketSamples;
|
|
||||||
flog::debug("Got buffer size: {}", _this->bufferSize);
|
|
||||||
|
|
||||||
// Start the stream
|
|
||||||
ret = IQS_BusTriggerStart(&_this->openDev);
|
|
||||||
if (ret < 0) {
|
|
||||||
flog::error("Could not start stream: {}", ret);
|
|
||||||
Device_Close(&_this->openDev);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start worker
|
|
||||||
_this->run = true;
|
|
||||||
_this->workerThread = std::thread(&HarogicSourceModule::worker, _this);
|
|
||||||
|
|
||||||
_this->running = true;
|
|
||||||
flog::info("HarogicSourceModule '{0}': Start!", _this->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void stop(void* ctx) {
|
|
||||||
HarogicSourceModule* _this = (HarogicSourceModule*)ctx;
|
|
||||||
if (!_this->running) { return; }
|
|
||||||
_this->running = false;
|
|
||||||
|
|
||||||
// Stop worker
|
|
||||||
_this->run = false;
|
|
||||||
_this->stream.stopWriter();
|
|
||||||
if (_this->workerThread.joinable()) { _this->workerThread.join(); }
|
|
||||||
_this->stream.clearWriteStop();
|
|
||||||
|
|
||||||
// Stop the stream
|
|
||||||
IQS_BusTriggerStop(&_this->openDev);
|
|
||||||
|
|
||||||
// Close the device
|
|
||||||
Device_Close(&_this->openDev);
|
|
||||||
|
|
||||||
flog::info("HarogicSourceModule '{0}': Stop!", _this->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void tune(double freq, void* ctx) {
|
|
||||||
HarogicSourceModule* _this = (HarogicSourceModule*)ctx;
|
|
||||||
if (_this->running) {
|
|
||||||
// Update the frequency in the configuration
|
|
||||||
_this->profile.CenterFreq_Hz = freq;
|
|
||||||
_this->applyProfile();
|
|
||||||
}
|
|
||||||
_this->freq = freq;
|
|
||||||
flog::info("HarogicSourceModule '{0}': Tune: {1}!", _this->name, freq);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void menuHandler(void* ctx) {
|
|
||||||
HarogicSourceModule* _this = (HarogicSourceModule*)ctx;
|
|
||||||
|
|
||||||
if (_this->running) { SmGui::BeginDisabled(); }
|
|
||||||
|
|
||||||
SmGui::FillWidth();
|
|
||||||
SmGui::ForceSync();
|
|
||||||
if (SmGui::Combo(CONCAT("##_harogic_dev_sel_", _this->name), &_this->devId, _this->devices.txt)) {
|
|
||||||
_this->select(_this->devices.key(_this->devId));
|
|
||||||
core::setInputSampleRate(_this->sampleRate);
|
|
||||||
// TODO: Save
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SmGui::Combo(CONCAT("##_harogic_sr_sel_", _this->name), &_this->srId, _this->samplerates.txt)) {
|
|
||||||
_this->sampleRate = _this->samplerates.value(_this->srId);
|
|
||||||
core::setInputSampleRate(_this->sampleRate);
|
|
||||||
// TODO: Save
|
|
||||||
}
|
|
||||||
|
|
||||||
SmGui::SameLine();
|
|
||||||
SmGui::FillWidth();
|
|
||||||
SmGui::ForceSync();
|
|
||||||
if (SmGui::Button(CONCAT("Refresh##_harogic_refr_", _this->name))) {
|
|
||||||
_this->refresh();
|
|
||||||
_this->select(_this->selectedSerial);
|
|
||||||
core::setInputSampleRate(_this->sampleRate);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_this->running) { SmGui::EndDisabled(); }
|
|
||||||
|
|
||||||
SmGui::LeftLabel("RX Port");
|
|
||||||
SmGui::FillWidth();
|
|
||||||
if (SmGui::Combo(CONCAT("##_harogic_port_", _this->name), &_this->portId, _this->rxPorts.txt)) {
|
|
||||||
if (_this->running) {
|
|
||||||
_this->profile.RxPort = _this->rxPorts.value(_this->portId);
|
|
||||||
_this->applyProfile();
|
|
||||||
}
|
|
||||||
// TODO: Save
|
|
||||||
}
|
|
||||||
|
|
||||||
SmGui::LeftLabel("LO Mode");
|
|
||||||
SmGui::FillWidth();
|
|
||||||
if (SmGui::Combo(CONCAT("##_lo_mode_", _this->name), &_this->loModeId, _this->loModes.txt)) {
|
|
||||||
if (_this->running) {
|
|
||||||
_this->profile.LOOptimization = _this->loModes.value(_this->loModeId);
|
|
||||||
_this->applyProfile();
|
|
||||||
}
|
|
||||||
// TODO: Save
|
|
||||||
}
|
|
||||||
|
|
||||||
SmGui::LeftLabel("Gain Mode");
|
|
||||||
SmGui::FillWidth();
|
|
||||||
if (SmGui::Combo(CONCAT("##_harogic_gain_mode_", _this->name), &_this->gainStratId, _this->gainStategies.txt)) {
|
|
||||||
if (_this->running) {
|
|
||||||
_this->profile.GainStrategy = _this->gainStategies.value(_this->gainStratId);
|
|
||||||
_this->applyProfile();
|
|
||||||
}
|
|
||||||
// TODO: Save
|
|
||||||
}
|
|
||||||
|
|
||||||
SmGui::LeftLabel("Preamp Mode");
|
|
||||||
SmGui::FillWidth();
|
|
||||||
if (SmGui::Combo(CONCAT("##_harogic_preamp_mode_", _this->name), &_this->preampModeId, _this->preampModes.txt)) {
|
|
||||||
if (_this->running) {
|
|
||||||
_this->profile.Preamplifier = _this->preampModes.value(_this->preampModeId);
|
|
||||||
_this->applyProfile();
|
|
||||||
}
|
|
||||||
// TODO: Save
|
|
||||||
}
|
|
||||||
|
|
||||||
SmGui::LeftLabel("Reference");
|
|
||||||
SmGui::FillWidth();
|
|
||||||
if (SmGui::SliderInt(CONCAT("##_harogic_ref_", _this->name), &_this->refLvl, _this->minRef, _this->maxRef)) {
|
|
||||||
if (_this->running) {
|
|
||||||
_this->profile.RefLevel_dBm = _this->refLvl;
|
|
||||||
_this->applyProfile();
|
|
||||||
}
|
|
||||||
// TODO: Save
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SmGui::Checkbox(CONCAT("IF AGC##_harogic_if_agc_", _this->name), &_this->ifAgc)) {
|
|
||||||
if (_this->running) {
|
|
||||||
_this->profile.EnableIFAGC = _this->ifAgc;
|
|
||||||
_this->applyProfile();
|
|
||||||
}
|
|
||||||
// TODO: Save
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void applyProfile() {
|
|
||||||
// Acquire device
|
|
||||||
std::lock_guard<std::mutex> lck(devMtx);
|
|
||||||
|
|
||||||
// Configure the device
|
|
||||||
IQS_StreamInfo_TypeDef info;
|
|
||||||
int ret = IQS_Configuration(&openDev, &profile, &profile, &info);
|
|
||||||
if (ret < 0) {
|
|
||||||
flog::error("Failed to apply tuning config: {}", ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Re-trigger the stream
|
|
||||||
ret = IQS_BusTriggerStart(&openDev);
|
|
||||||
if (ret < 0) {
|
|
||||||
flog::error("Could not start stream: {}", ret);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void worker() {
|
|
||||||
// Allocate sample buffer
|
|
||||||
int realSamps = bufferSize*2;
|
|
||||||
IQStream_TypeDef iqs;
|
|
||||||
|
|
||||||
// Define number of buffers per swap to maintain 200 fps
|
|
||||||
int maxBufCount = STREAM_BUFFER_SIZE / bufferSize;
|
|
||||||
int bufCount = (sampleRate / bufferSize) / 200;
|
|
||||||
if (bufCount <= 0) { bufCount = 1; }
|
|
||||||
if (bufCount > maxBufCount) { bufCount = maxBufCount; }
|
|
||||||
int count = 0;
|
|
||||||
|
|
||||||
flog::debug("Swapping will be done {} buffers at a time", bufCount);
|
|
||||||
|
|
||||||
// Worker loop
|
|
||||||
while (run) {
|
|
||||||
// Read samples
|
|
||||||
devMtx.lock();
|
|
||||||
int ret = IQS_GetIQStream_PM1(&openDev, &iqs);
|
|
||||||
devMtx.unlock();
|
|
||||||
if (ret < 0) {
|
|
||||||
if (ret == APIRETVAL_WARNING_BusTimeOut) {
|
|
||||||
flog::warn("Stream timed out");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else if (ret <= APIRETVAL_WARNING_IFOverflow && ret >= APIRETVAL_WARNING_ADCConfigError) {
|
|
||||||
// Just warnings, do nothing
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
flog::error("Streaming error: {}", ret);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert them to floating point
|
|
||||||
if (sampsInt8) {
|
|
||||||
volk_8i_s32f_convert_32f((float*)&stream.writeBuf[(count++)*bufferSize], (int8_t*)iqs.AlternIQStream, 128.0f, realSamps);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
volk_16i_s32f_convert_32f((float*)&stream.writeBuf[(count++)*bufferSize], (int16_t*)iqs.AlternIQStream, 32768.0f, realSamps);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send them off if we have enough
|
|
||||||
if (count >= bufCount) {
|
|
||||||
count = 0;
|
|
||||||
if (!stream.swap(bufferSize*bufCount)) { break; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string name;
|
|
||||||
bool enabled = true;
|
|
||||||
dsp::stream<dsp::complex_t> stream;
|
|
||||||
double sampleRate;
|
|
||||||
SourceManager::SourceHandler handler;
|
|
||||||
bool running = false;
|
|
||||||
double freq;
|
|
||||||
|
|
||||||
OptionList<std::string, int> devices;
|
|
||||||
OptionList<int, double> samplerates;
|
|
||||||
OptionList<std::string, RxPort_TypeDef> rxPorts;
|
|
||||||
OptionList<std::string, GainStrategy_TypeDef> gainStategies;
|
|
||||||
OptionList<std::string, PreamplifierState_TypeDef> preampModes;
|
|
||||||
OptionList<std::string, LOOptimization_TypeDef> loModes;
|
|
||||||
int devId = 0;
|
|
||||||
int srId = 0;
|
|
||||||
int refLvl = -30;
|
|
||||||
int minRef = -100;
|
|
||||||
int maxRef = 7;
|
|
||||||
int portId = 0;
|
|
||||||
int gainStratId = 0;
|
|
||||||
int preampModeId = 0;
|
|
||||||
int loModeId = 0;
|
|
||||||
bool ifAgc = false;
|
|
||||||
std::string selectedSerial;
|
|
||||||
int selectedDevIndex;
|
|
||||||
|
|
||||||
void* openDev;
|
|
||||||
IQS_Profile_TypeDef profile;
|
|
||||||
|
|
||||||
int bufferSize;
|
|
||||||
std::thread workerThread;
|
|
||||||
std::atomic<bool> run = false;
|
|
||||||
std::mutex devMtx;
|
|
||||||
bool sampsInt8;
|
|
||||||
};
|
|
||||||
|
|
||||||
MOD_EXPORT void _INIT_() {
|
|
||||||
// Nothing here
|
|
||||||
}
|
|
||||||
|
|
||||||
MOD_EXPORT ModuleManager::Instance* _CREATE_INSTANCE_(std::string name) {
|
|
||||||
return new HarogicSourceModule(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
MOD_EXPORT void _DELETE_INSTANCE_(void* instance) {
|
|
||||||
delete (HarogicSourceModule*)instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
MOD_EXPORT void _END_() {
|
|
||||||
// Nothing here
|
|
||||||
}
|
|
1
source_modules/kcsdr_source/.gitignore
vendored
1
source_modules/kcsdr_source/.gitignore
vendored
@ -1 +0,0 @@
|
|||||||
vendor/*
|
|
@ -1,10 +0,0 @@
|
|||||||
cmake_minimum_required(VERSION 3.13)
|
|
||||||
project(kcsdr_source)
|
|
||||||
|
|
||||||
file(GLOB SRC "src/*.cpp" "src/*.c")
|
|
||||||
|
|
||||||
include(${SDRPP_MODULE_CMAKE})
|
|
||||||
|
|
||||||
target_link_directories(kcsdr_source PRIVATE "vendor/FTD3XXLibrary_1.3.0.10/x64/DLL")
|
|
||||||
target_include_directories(kcsdr_source PRIVATE "vendor/FTD3XXLibrary_1.3.0.10")
|
|
||||||
target_link_libraries(kcsdr_source PRIVATE FTD3XX)
|
|
@ -1,209 +0,0 @@
|
|||||||
#include "kcsdr.h"
|
|
||||||
#include <string.h>
|
|
||||||
#include "../vendor/FTD3XXLibrary_1.3.0.10/FTD3XX.h"
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
#define KCSDR_PKT_EMPTY_LEN 0x0C
|
|
||||||
|
|
||||||
#define KCSDR_COMMAND_PIPE 0x02
|
|
||||||
#define KCSDR_RX_DATA_PIPE 0x83
|
|
||||||
#define KCSDR_TX_DATA_PIPE 0x03
|
|
||||||
|
|
||||||
struct kcsdr {
|
|
||||||
FT_HANDLE ft;
|
|
||||||
};
|
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
|
||||||
struct kcsdr_packet {
|
|
||||||
uint8_t zeros0[4];
|
|
||||||
uint8_t length;
|
|
||||||
uint8_t zeros1[2];
|
|
||||||
uint8_t hex_eighty;
|
|
||||||
uint32_t command;
|
|
||||||
uint8_t data[188];
|
|
||||||
};
|
|
||||||
typedef struct kcsdr_packet kcsdr_packet_t;
|
|
||||||
#pragma pack(pop)
|
|
||||||
|
|
||||||
enum kcsdr_command {
|
|
||||||
CMD_NOT_USED_0x00 = 0x00,
|
|
||||||
CMD_SET_PORT = 0x01,
|
|
||||||
CMD_SET_FREQUENCY = 0x02,
|
|
||||||
CMD_SET_ATTENUATION = 0x03,
|
|
||||||
CMD_SET_AMPLIFIER = 0x04,
|
|
||||||
CMD_SET_BANDWIDTH = 0x05,
|
|
||||||
CMD_START = 0x06,
|
|
||||||
CMD_STOP = 0x07,
|
|
||||||
CMD_SET_EXT_AMP = 0x08,
|
|
||||||
CMD_START_REMOTE = 0x09,
|
|
||||||
CMD_STOP_REMOTE = 0x0A
|
|
||||||
};
|
|
||||||
typedef enum kcsdr_command kcsdr_command_t;
|
|
||||||
|
|
||||||
int kcsdr_send_command(kcsdr_t* dev, kcsdr_direction_t dir, kcsdr_command_t cmd, const uint8_t* data, int len) {
|
|
||||||
Sleep(50);
|
|
||||||
|
|
||||||
// Create an empty packet
|
|
||||||
kcsdr_packet_t pkt;
|
|
||||||
memset(&pkt, 0, sizeof(kcsdr_packet_t));
|
|
||||||
|
|
||||||
// Fill out the packet info
|
|
||||||
pkt.length = len + KCSDR_PKT_EMPTY_LEN;
|
|
||||||
pkt.hex_eighty = 0x80; // Whatever the fuck that is
|
|
||||||
pkt.command = (uint32_t)cmd | (uint32_t)dir;
|
|
||||||
|
|
||||||
// Copy the data if there is some
|
|
||||||
if (len) { memcpy(pkt.data, data, len); }
|
|
||||||
|
|
||||||
// Dump the bytes
|
|
||||||
uint8_t* dump = (uint8_t*)&pkt;
|
|
||||||
printf("Sending:");
|
|
||||||
for (int i = 0; i < pkt.length; i++) {
|
|
||||||
printf(" %02X", dump[i]);
|
|
||||||
}
|
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
// Send the command to endpoint 0
|
|
||||||
int sent;
|
|
||||||
FT_STATUS err = FT_WritePipeEx(dev->ft, KCSDR_COMMAND_PIPE, (uint8_t*)&pkt, sizeof(kcsdr_packet_t), &sent, NULL);
|
|
||||||
if (err != FT_OK) {
|
|
||||||
return -err;
|
|
||||||
}
|
|
||||||
printf("Sent %d bytes (%d)\n", sent, err);
|
|
||||||
|
|
||||||
Sleep(50);
|
|
||||||
|
|
||||||
// Flush existing commands
|
|
||||||
FT_FlushPipe(dev->ft, KCSDR_COMMAND_PIPE);
|
|
||||||
|
|
||||||
return -(int)err;
|
|
||||||
}
|
|
||||||
|
|
||||||
int kcsdr_list_devices(kcsdr_info_t** devices) {
|
|
||||||
// Generate a list of FTDI devices
|
|
||||||
int ftdiDevCount = 0;
|
|
||||||
FT_STATUS err = FT_CreateDeviceInfoList(&ftdiDevCount);
|
|
||||||
if (err != FT_OK) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If no device was found, return nothing
|
|
||||||
if (!ftdiDevCount) {
|
|
||||||
*devices = NULL;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get said device list
|
|
||||||
FT_DEVICE_LIST_INFO_NODE* list = malloc(ftdiDevCount * sizeof(FT_DEVICE_LIST_INFO_NODE));
|
|
||||||
err = FT_GetDeviceInfoList(list, &ftdiDevCount);
|
|
||||||
if (err != FT_OK) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allocate the device info list
|
|
||||||
*devices = malloc(ftdiDevCount * sizeof(kcsdr_info_t));
|
|
||||||
|
|
||||||
// Find all KC908s
|
|
||||||
int kcCount = 0;
|
|
||||||
for (int i = 0; i < ftdiDevCount; i++) {
|
|
||||||
strcpy((*devices)[kcCount++].serial, list[i].SerialNumber);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Free the FTDI list
|
|
||||||
free(list);
|
|
||||||
|
|
||||||
return kcCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
void kcsdr_free_device_list(kcsdr_info_t* devices) {
|
|
||||||
// Free the list
|
|
||||||
if (devices) { free(devices); }
|
|
||||||
}
|
|
||||||
|
|
||||||
int kcsdr_open(kcsdr_t** dev, const char* serial) {
|
|
||||||
// Attempt to open the device using the serial number
|
|
||||||
FT_HANDLE ft;
|
|
||||||
FT_STATUS err = FT_Create(serial, FT_OPEN_BY_SERIAL_NUMBER, &ft);
|
|
||||||
if (err != FT_OK) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the timeouts for the data pipes
|
|
||||||
FT_SetPipeTimeout(ft, KCSDR_RX_DATA_PIPE, 1000);
|
|
||||||
FT_SetPipeTimeout(ft, KCSDR_TX_DATA_PIPE, 1000);
|
|
||||||
|
|
||||||
// Allocate the device object
|
|
||||||
*dev = malloc(sizeof(kcsdr_t));
|
|
||||||
|
|
||||||
// Fill out the device object
|
|
||||||
(*dev)->ft = ft;
|
|
||||||
|
|
||||||
// Put device into remote control mode
|
|
||||||
return kcsdr_send_command(*dev, KCSDR_DIR_RX, CMD_START_REMOTE, NULL, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void kcsdr_close(kcsdr_t* dev) {
|
|
||||||
// Put device back in normal mode
|
|
||||||
kcsdr_send_command(dev, KCSDR_DIR_RX, CMD_STOP_REMOTE, NULL, 0);
|
|
||||||
|
|
||||||
// Close the device
|
|
||||||
FT_Close(dev->ft);
|
|
||||||
|
|
||||||
// Free the device object
|
|
||||||
free(dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
int kcsdr_set_port(kcsdr_t* dev, kcsdr_direction_t dir, uint8_t port) {
|
|
||||||
// Send SET_PORT command
|
|
||||||
return kcsdr_send_command(dev, dir, CMD_SET_PORT, &port, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
int kcsdr_set_frequency(kcsdr_t* dev, kcsdr_direction_t dir, uint64_t freq) {
|
|
||||||
// Send SET_FREQUENCY command
|
|
||||||
return kcsdr_send_command(dev, dir, CMD_SET_FREQUENCY, (uint8_t*)&freq, 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
int kcsdr_set_attenuation(kcsdr_t* dev, kcsdr_direction_t dir, uint8_t att) {
|
|
||||||
// Send SET_ATTENUATION command
|
|
||||||
return kcsdr_send_command(dev, dir, CMD_SET_ATTENUATION, &att, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
int kcsdr_set_amp_gain(kcsdr_t* dev, kcsdr_direction_t dir, uint8_t gain) {
|
|
||||||
// Send SET_AMPLIFIER command
|
|
||||||
return kcsdr_send_command(dev, dir, CMD_SET_AMPLIFIER, &gain, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
int kcsdr_set_rx_ext_amp_gain(kcsdr_t* dev, uint8_t gain) {
|
|
||||||
// Send CMD_SET_EXT_AMP command
|
|
||||||
return kcsdr_send_command(dev, KCSDR_DIR_RX, CMD_SET_EXT_AMP, &gain, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
int kcsdr_set_samplerate(kcsdr_t* dev, kcsdr_direction_t dir, uint32_t samplerate) {
|
|
||||||
// Set SET_BANDWIDTH command
|
|
||||||
return kcsdr_send_command(dev, dir, CMD_SET_BANDWIDTH, (uint8_t*)&samplerate, 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
int kcsdr_start(kcsdr_t* dev, kcsdr_direction_t dir) {
|
|
||||||
// Send START command
|
|
||||||
return kcsdr_send_command(dev, dir, CMD_START, NULL, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int kcsdr_stop(kcsdr_t* dev, kcsdr_direction_t dir) {
|
|
||||||
// Send STOP command
|
|
||||||
return kcsdr_send_command(dev, dir, CMD_STOP, NULL, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int kcsdr_rx(kcsdr_t* dev, int16_t* samples, int count) {
|
|
||||||
// Receive samples (TODO: Endpoint might be 0x81)
|
|
||||||
int received;
|
|
||||||
FT_STATUS err = FT_ReadPipeEx(dev->ft, KCSDR_RX_DATA_PIPE, (uint8_t*)samples, count*2*sizeof(uint16_t), &received, NULL);
|
|
||||||
return (err == FT_OK) ? received / (2*sizeof(uint16_t)) : -(int)err;
|
|
||||||
}
|
|
||||||
|
|
||||||
int kcsdr_tx(kcsdr_t* dev, const int16_t* samples, int count) {
|
|
||||||
// Transmit samples
|
|
||||||
int sent;
|
|
||||||
FT_STATUS err = FT_WritePipeEx(dev->ft, KCSDR_TX_DATA_PIPE, (uint8_t*)samples, count*2*sizeof(uint16_t), &sent, NULL);
|
|
||||||
return (err == FT_OK) ? sent / (2*sizeof(uint16_t)) : -(int)err;
|
|
||||||
}
|
|
@ -1,150 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#define KCSDR_SERIAL_LEN 16
|
|
||||||
#define KCSDR_MAX_PORTS 6
|
|
||||||
|
|
||||||
// Detect C++
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* KCSDR Device.
|
|
||||||
*/
|
|
||||||
struct kcsdr;
|
|
||||||
typedef struct kcsdr kcsdr_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Device Information
|
|
||||||
*/
|
|
||||||
struct kcsdr_info {
|
|
||||||
char serial[KCSDR_SERIAL_LEN+1];
|
|
||||||
};
|
|
||||||
typedef struct kcsdr_info kcsdr_info_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* RF Direction.
|
|
||||||
*/
|
|
||||||
enum kcsdr_direction {
|
|
||||||
KCSDR_DIR_RX = 0x00,
|
|
||||||
KCSDR_DIR_TX = 0x80
|
|
||||||
};
|
|
||||||
typedef enum kcsdr_direction kcsdr_direction_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a list of KCSDR devices on the system.
|
|
||||||
* @param devices Pointer to an array of device info.
|
|
||||||
* @return Number of devices found or error code.
|
|
||||||
*/
|
|
||||||
int kcsdr_list_devices(kcsdr_info_t** devices);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Free a device list returned by `kcsdr_list_devices()`.
|
|
||||||
* @param devices Device list to free.
|
|
||||||
*/
|
|
||||||
void kcsdr_free_device_list(kcsdr_info_t* devices);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Open a KCSDR device.
|
|
||||||
* @param dev Newly open device.
|
|
||||||
* @param serial Serial number of the device to open as returned in the device list.
|
|
||||||
* @return 0 on success, error code otherwise.
|
|
||||||
*/
|
|
||||||
int kcsdr_open(kcsdr_t** dev, const char* serial);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Close a KCSDR device.
|
|
||||||
* @param dev Device to be closed.
|
|
||||||
*/
|
|
||||||
void kcsdr_close(kcsdr_t* dev);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Select the RF port.
|
|
||||||
* @param dev Device to control.
|
|
||||||
* @param dir Either KCSDR_DIR_RX or KCSDR_DIR_TX.
|
|
||||||
* @param port RF port number to select.
|
|
||||||
* @return 0 on success, error code otherwise.
|
|
||||||
*/
|
|
||||||
int kcsdr_set_port(kcsdr_t* dev, kcsdr_direction_t dir, uint8_t port);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the center frequency.
|
|
||||||
* @param dev Device to control.
|
|
||||||
* @param dir Either KCSDR_DIR_RX or KCSDR_DIR_TX
|
|
||||||
* @param freq Frequency in Hz.
|
|
||||||
* @return 0 on success, error code otherwise.
|
|
||||||
*/
|
|
||||||
int kcsdr_set_frequency(kcsdr_t* dev, kcsdr_direction_t dir, uint64_t freq);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the attenuation.
|
|
||||||
* @param dev Device to control.
|
|
||||||
* @param dir Either KCSDR_DIR_RX or KCSDR_DIR_TX
|
|
||||||
* @param samplerate Attenuation in dB.
|
|
||||||
* @return 0 on success, error code otherwise.
|
|
||||||
*/
|
|
||||||
int kcsdr_set_attenuation(kcsdr_t* dev, kcsdr_direction_t dir, uint8_t att);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the internal amplifier gain.
|
|
||||||
* @param dev Device to control.
|
|
||||||
* @param dir Either KCSDR_DIR_RX or KCSDR_DIR_TX
|
|
||||||
* @param gain Gain in dB.
|
|
||||||
* @return 0 on success, error code otherwise.
|
|
||||||
*/
|
|
||||||
int kcsdr_set_amp_gain(kcsdr_t* dev, kcsdr_direction_t dir, uint8_t gain);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the external amplifier gain.
|
|
||||||
* @param dev Device to control.
|
|
||||||
* @param gain Gain in dB.
|
|
||||||
* @return 0 on success, error code otherwise.
|
|
||||||
*/
|
|
||||||
int kcsdr_set_rx_ext_amp_gain(kcsdr_t* dev, uint8_t gain);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the samplerate.
|
|
||||||
* @param dev Device to control.
|
|
||||||
* @param dir Either KCSDR_DIR_RX or KCSDR_DIR_TX
|
|
||||||
* @param samplerate Samplerate in Hz.
|
|
||||||
* @return 0 on success, error code otherwise.
|
|
||||||
*/
|
|
||||||
int kcsdr_set_samplerate(kcsdr_t* dev, kcsdr_direction_t dir, uint32_t samplerate);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start streaming samples.
|
|
||||||
* @param dev Device to control.
|
|
||||||
* @param dir Either KCSDR_DIR_RX or KCSDR_DIR_TX.
|
|
||||||
* @return 0 on success, error code otherwise.
|
|
||||||
*/
|
|
||||||
int kcsdr_start(kcsdr_t* dev, kcsdr_direction_t dir);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stop streaming samples.
|
|
||||||
* @param dev Device to control.
|
|
||||||
* @param dir Either KCSDR_DIR_RX or KCSDR_DIR_TX.
|
|
||||||
* @return 0 on success, error code otherwise.
|
|
||||||
*/
|
|
||||||
int kcsdr_stop(kcsdr_t* dev, kcsdr_direction_t dir);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Receive a buffer of samples.
|
|
||||||
* @param samples Sample buffer.
|
|
||||||
* @param count Number of complex samples.
|
|
||||||
* @return Number of samples received.
|
|
||||||
*/
|
|
||||||
int kcsdr_rx(kcsdr_t* dev, int16_t* samples, int count);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Transmit a buffer of samples.
|
|
||||||
* @param samples Sample buffer.
|
|
||||||
* @param count Number of complex samples.
|
|
||||||
* @return Number of samples transmitted.
|
|
||||||
*/
|
|
||||||
int kcsdr_tx(kcsdr_t* dev, const int16_t* samples, int count);
|
|
||||||
|
|
||||||
// Detect C++
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
@ -1,324 +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 "kcsdr.h"
|
|
||||||
#include <atomic>
|
|
||||||
|
|
||||||
SDRPP_MOD_INFO{
|
|
||||||
/* Name: */ "kcsdr_source",
|
|
||||||
/* Description: */ "KCSDR Source Module",
|
|
||||||
/* Author: */ "Ryzerth",
|
|
||||||
/* Version: */ 0, 1, 0,
|
|
||||||
/* Max instances */ -1
|
|
||||||
};
|
|
||||||
|
|
||||||
#define CONCAT(a, b) ((std::string(a) + b).c_str())
|
|
||||||
|
|
||||||
class KCSDRSourceModule : public ModuleManager::Instance {
|
|
||||||
public:
|
|
||||||
KCSDRSourceModule(std::string name) {
|
|
||||||
this->name = name;
|
|
||||||
|
|
||||||
sampleRate = 2000000.0;
|
|
||||||
samplerates.define(40e6, "40MHz", 40e6);
|
|
||||||
samplerates.define(35e6, "35MHz", 35e6);
|
|
||||||
samplerates.define(30e6, "30MHz", 30e6);
|
|
||||||
samplerates.define(25e6, "25MHz", 25e6);
|
|
||||||
samplerates.define(20e6, "20MHz", 20e6);
|
|
||||||
samplerates.define(15e6, "15MHz", 15e6);
|
|
||||||
samplerates.define(10e6, "10MHz", 10e6);
|
|
||||||
samplerates.define(5e6, "5MHz", 5e6);
|
|
||||||
|
|
||||||
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("KCSDR", &handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
~KCSDRSourceModule() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void postInit() {}
|
|
||||||
|
|
||||||
void enable() {
|
|
||||||
enabled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void disable() {
|
|
||||||
enabled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isEnabled() {
|
|
||||||
return enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void refresh() {
|
|
||||||
devices.clear();
|
|
||||||
|
|
||||||
// Get device list
|
|
||||||
kcsdr_info_t* list;
|
|
||||||
int count = kcsdr_list_devices(&list);
|
|
||||||
if (count < 0) {
|
|
||||||
flog::error("Failed to list devices: {}", count);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create list
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
devices.define(list[i].serial, list[i].serial, list[i].serial);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Free the device list
|
|
||||||
kcsdr_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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the menu ID
|
|
||||||
devId = devices.keyId(serial);
|
|
||||||
|
|
||||||
// TODO
|
|
||||||
|
|
||||||
// Update the samplerate
|
|
||||||
core::setInputSampleRate(sampleRate);
|
|
||||||
|
|
||||||
// Save serial number
|
|
||||||
selectedSerial = serial;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void menuSelected(void* ctx) {
|
|
||||||
KCSDRSourceModule* _this = (KCSDRSourceModule*)ctx;
|
|
||||||
core::setInputSampleRate(_this->sampleRate);
|
|
||||||
flog::info("KCSDRSourceModule '{0}': Menu Select!", _this->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void menuDeselected(void* ctx) {
|
|
||||||
KCSDRSourceModule* _this = (KCSDRSourceModule*)ctx;
|
|
||||||
flog::info("KCSDRSourceModule '{0}': Menu Deselect!", _this->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void start(void* ctx) {
|
|
||||||
KCSDRSourceModule* _this = (KCSDRSourceModule*)ctx;
|
|
||||||
if (_this->running) { return; }
|
|
||||||
|
|
||||||
// If no serial is given, do nothing
|
|
||||||
if (_this->selectedSerial.empty()) { return; }
|
|
||||||
|
|
||||||
// Open the device
|
|
||||||
int err = kcsdr_open(&_this->openDev, _this->selectedSerial.c_str());
|
|
||||||
if (err) {
|
|
||||||
flog::error("Failed to open device: {}", err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Configure the device
|
|
||||||
kcsdr_set_port(_this->openDev, KCSDR_DIR_RX, 0);
|
|
||||||
kcsdr_set_frequency(_this->openDev, KCSDR_DIR_RX, _this->freq);
|
|
||||||
kcsdr_set_attenuation(_this->openDev, KCSDR_DIR_RX, _this->att);
|
|
||||||
kcsdr_set_amp_gain(_this->openDev, KCSDR_DIR_RX, _this->gain);
|
|
||||||
kcsdr_set_rx_ext_amp_gain(_this->openDev, _this->extGain);
|
|
||||||
kcsdr_set_samplerate(_this->openDev, KCSDR_DIR_RX, _this->sampleRate);
|
|
||||||
|
|
||||||
// Start the stream
|
|
||||||
kcsdr_start(_this->openDev, KCSDR_DIR_RX);
|
|
||||||
|
|
||||||
// Start worker
|
|
||||||
_this->run = true;
|
|
||||||
_this->workerThread = std::thread(&KCSDRSourceModule::worker, _this);
|
|
||||||
|
|
||||||
_this->running = true;
|
|
||||||
flog::info("KCSDRSourceModule '{0}': Start!", _this->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void stop(void* ctx) {
|
|
||||||
KCSDRSourceModule* _this = (KCSDRSourceModule*)ctx;
|
|
||||||
if (!_this->running) { return; }
|
|
||||||
_this->running = false;
|
|
||||||
|
|
||||||
// Stop worker
|
|
||||||
_this->run = false;
|
|
||||||
_this->stream.stopWriter();
|
|
||||||
if (_this->workerThread.joinable()) { _this->workerThread.join(); }
|
|
||||||
_this->stream.clearWriteStop();
|
|
||||||
|
|
||||||
// Stop streaming
|
|
||||||
kcsdr_stop(_this->openDev, KCSDR_DIR_RX);
|
|
||||||
|
|
||||||
// Close the device
|
|
||||||
kcsdr_close(_this->openDev);
|
|
||||||
|
|
||||||
flog::info("KCSDRSourceModule '{0}': Stop!", _this->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void tune(double freq, void* ctx) {
|
|
||||||
KCSDRSourceModule* _this = (KCSDRSourceModule*)ctx;
|
|
||||||
if (_this->running) {
|
|
||||||
kcsdr_set_frequency(_this->openDev, KCSDR_DIR_RX, freq);
|
|
||||||
}
|
|
||||||
_this->freq = freq;
|
|
||||||
flog::info("KCSDRSourceModule '{0}': Tune: {1}!", _this->name, freq);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void menuHandler(void* ctx) {
|
|
||||||
KCSDRSourceModule* _this = (KCSDRSourceModule*)ctx;
|
|
||||||
|
|
||||||
if (_this->running) { SmGui::BeginDisabled(); }
|
|
||||||
|
|
||||||
SmGui::FillWidth();
|
|
||||||
SmGui::ForceSync();
|
|
||||||
if (SmGui::Combo(CONCAT("##_kcsdr_dev_sel_", _this->name), &_this->devId, _this->devices.txt)) {
|
|
||||||
_this->select(_this->devices.key(_this->devId));
|
|
||||||
core::setInputSampleRate(_this->sampleRate);
|
|
||||||
// TODO: Save
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SmGui::Combo(CONCAT("##_kcsdr_sr_sel_", _this->name), &_this->srId, _this->samplerates.txt)) {
|
|
||||||
_this->sampleRate = _this->samplerates.value(_this->srId);
|
|
||||||
core::setInputSampleRate(_this->sampleRate);
|
|
||||||
// TODO: Save
|
|
||||||
}
|
|
||||||
|
|
||||||
SmGui::SameLine();
|
|
||||||
SmGui::FillWidth();
|
|
||||||
SmGui::ForceSync();
|
|
||||||
if (SmGui::Button(CONCAT("Refresh##_kcsdr_refr_", _this->name))) {
|
|
||||||
_this->refresh();
|
|
||||||
_this->select(_this->selectedSerial);
|
|
||||||
core::setInputSampleRate(_this->sampleRate);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_this->running) { SmGui::EndDisabled(); }
|
|
||||||
|
|
||||||
// SmGui::LeftLabel("RX Port");
|
|
||||||
// SmGui::FillWidth();
|
|
||||||
// if (SmGui::Combo(CONCAT("##_kcsdr_port_", _this->name), &_this->portId, _this->rxPorts.txt)) {
|
|
||||||
// if (_this->running) {
|
|
||||||
// // TODO
|
|
||||||
// }
|
|
||||||
// // TODO: Save
|
|
||||||
// }
|
|
||||||
|
|
||||||
SmGui::LeftLabel("Attenuation");
|
|
||||||
SmGui::FillWidth();
|
|
||||||
if (SmGui::SliderInt(CONCAT("##_kcsdr_att_", _this->name), &_this->att, 0, 31)) {
|
|
||||||
if (_this->running) {
|
|
||||||
kcsdr_set_attenuation(_this->openDev, KCSDR_DIR_RX, _this->att);
|
|
||||||
}
|
|
||||||
// TODO: Save
|
|
||||||
}
|
|
||||||
|
|
||||||
SmGui::LeftLabel("Gain");
|
|
||||||
SmGui::FillWidth();
|
|
||||||
if (SmGui::SliderInt(CONCAT("##_kcsdr_gain_", _this->name), &_this->gain, 0, 31)) {
|
|
||||||
if (_this->running) {
|
|
||||||
kcsdr_set_amp_gain(_this->openDev, KCSDR_DIR_RX, _this->gain);
|
|
||||||
}
|
|
||||||
// TODO: Save
|
|
||||||
}
|
|
||||||
|
|
||||||
SmGui::LeftLabel("External Gain");
|
|
||||||
SmGui::FillWidth();
|
|
||||||
if (SmGui::SliderInt(CONCAT("##_kcsdr_ext_gain_", _this->name), &_this->extGain, 0, 31)) {
|
|
||||||
if (_this->running) {
|
|
||||||
kcsdr_set_rx_ext_amp_gain(_this->openDev, _this->extGain);
|
|
||||||
}
|
|
||||||
// TODO: Save
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void worker() {
|
|
||||||
// Compute the buffer size
|
|
||||||
int bufferSize = 0x4000/4;//sampleRate / 200;
|
|
||||||
|
|
||||||
// Allocate the sample buffer
|
|
||||||
int16_t* samps = dsp::buffer::alloc<int16_t>(bufferSize*2);
|
|
||||||
|
|
||||||
// Loop
|
|
||||||
while (run) {
|
|
||||||
// Read samples
|
|
||||||
int count = kcsdr_rx(openDev, samps, bufferSize);
|
|
||||||
if (!count) { continue; }
|
|
||||||
if (count < 0) {
|
|
||||||
flog::debug("Failed to read samples: {}", count);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert the samples to float
|
|
||||||
volk_16i_s32f_convert_32f((float*)stream.writeBuf, samps, 8192.0f, count*2);
|
|
||||||
|
|
||||||
// Send out the samples
|
|
||||||
if (!stream.swap(count)) { break; }
|
|
||||||
}
|
|
||||||
|
|
||||||
// Free the sample buffer
|
|
||||||
dsp::buffer::free(samps);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string name;
|
|
||||||
bool enabled = true;
|
|
||||||
dsp::stream<dsp::complex_t> stream;
|
|
||||||
double sampleRate;
|
|
||||||
SourceManager::SourceHandler handler;
|
|
||||||
bool running = false;
|
|
||||||
double freq;
|
|
||||||
|
|
||||||
OptionList<std::string, std::string> devices;
|
|
||||||
OptionList<int, double> samplerates;
|
|
||||||
int devId = 0;
|
|
||||||
int srId = 0;
|
|
||||||
int att = 0;
|
|
||||||
int gain = 30;
|
|
||||||
int extGain = 1;
|
|
||||||
int portId = 0;
|
|
||||||
std::string selectedSerial;
|
|
||||||
|
|
||||||
kcsdr_t* openDev;
|
|
||||||
|
|
||||||
std::thread workerThread;
|
|
||||||
std::atomic<bool> run = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
MOD_EXPORT void _INIT_() {
|
|
||||||
// Nothing here
|
|
||||||
}
|
|
||||||
|
|
||||||
MOD_EXPORT ModuleManager::Instance* _CREATE_INSTANCE_(std::string name) {
|
|
||||||
return new KCSDRSourceModule(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
MOD_EXPORT void _DELETE_INSTANCE_(void* instance) {
|
|
||||||
delete (KCSDRSourceModule*)instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
MOD_EXPORT void _END_() {
|
|
||||||
// Nothing here
|
|
||||||
}
|
|
@ -36,10 +36,10 @@ enum SampleType {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const size_t SAMPLE_TYPE_SIZE[] {
|
const size_t SAMPLE_TYPE_SIZE[] {
|
||||||
2*sizeof(int8_t),
|
sizeof(int8_t)*2,
|
||||||
2*sizeof(int16_t),
|
sizeof(int16_t)*2,
|
||||||
2*sizeof(int32_t),
|
sizeof(int32_t)*2,
|
||||||
2*sizeof(float),
|
sizeof(float)*2,
|
||||||
};
|
};
|
||||||
|
|
||||||
class NetworkSourceModule : public ModuleManager::Instance {
|
class NetworkSourceModule : public ModuleManager::Instance {
|
||||||
@ -58,6 +58,20 @@ public:
|
|||||||
handler.tuneHandler = tune;
|
handler.tuneHandler = tune;
|
||||||
handler.stream = &stream;
|
handler.stream = &stream;
|
||||||
|
|
||||||
|
// Define samplerates
|
||||||
|
for (int i = 3000; i <= 192000; i <<= 1) {
|
||||||
|
samplerates.define(i, getSrScaled(i), i);
|
||||||
|
}
|
||||||
|
for (int i = 250000; i < 1000000; i += 250000) {
|
||||||
|
samplerates.define(i, getSrScaled(i), i);
|
||||||
|
}
|
||||||
|
for (int i = 1000000; i < 10000000; i += 500000) {
|
||||||
|
samplerates.define(i, getSrScaled(i), i);
|
||||||
|
}
|
||||||
|
for (int i = 10000000; i <= 100000000; i += 5000000) {
|
||||||
|
samplerates.define(i, getSrScaled(i), i);
|
||||||
|
}
|
||||||
|
|
||||||
// Define protocols
|
// Define protocols
|
||||||
// protocols.define("TCP (Server)", PROTOCOL_TCP_SERVER);
|
// protocols.define("TCP (Server)", PROTOCOL_TCP_SERVER);
|
||||||
protocols.define("TCP (Client)", PROTOCOL_TCP_CLIENT);
|
protocols.define("TCP (Client)", PROTOCOL_TCP_CLIENT);
|
||||||
@ -72,8 +86,8 @@ public:
|
|||||||
// Load config
|
// Load config
|
||||||
config.acquire();
|
config.acquire();
|
||||||
if (config.conf[name].contains("samplerate")) {
|
if (config.conf[name].contains("samplerate")) {
|
||||||
samplerate = config.conf[name]["samplerate"];
|
int sr = config.conf[name]["samplerate"];
|
||||||
tempSamplerate = samplerate;
|
if (samplerates.keyExists(sr)) { samplerate = samplerates.value(samplerates.keyId(sr)); }
|
||||||
}
|
}
|
||||||
if (config.conf[name].contains("protocol")) {
|
if (config.conf[name].contains("protocol")) {
|
||||||
std::string protoStr = config.conf[name]["protocol"];
|
std::string protoStr = config.conf[name]["protocol"];
|
||||||
@ -94,6 +108,7 @@ public:
|
|||||||
config.release();
|
config.release();
|
||||||
|
|
||||||
// Set menu IDs
|
// Set menu IDs
|
||||||
|
srId = samplerates.valueId(samplerate);
|
||||||
protoId = protocols.valueId(proto);
|
protoId = protocols.valueId(proto);
|
||||||
sampTypeId = sampleTypes.valueId(sampType);
|
sampTypeId = sampleTypes.valueId(sampType);
|
||||||
|
|
||||||
@ -213,24 +228,35 @@ private:
|
|||||||
if (_this->running) { SmGui::BeginDisabled(); }
|
if (_this->running) { SmGui::BeginDisabled(); }
|
||||||
|
|
||||||
// Hostname and port field
|
// Hostname and port field
|
||||||
if (SmGui::InputText(("##network_source_host_" + _this->name).c_str(), _this->hostname, sizeof(_this->hostname))) {
|
if (ImGui::InputText(("##iq_exporter_host_" + _this->name).c_str(), _this->hostname, sizeof(_this->hostname))) {
|
||||||
config.acquire();
|
config.acquire();
|
||||||
config.conf[_this->name]["host"] = _this->hostname;
|
config.conf[_this->name]["host"] = _this->hostname;
|
||||||
config.release(true);
|
config.release(true);
|
||||||
}
|
}
|
||||||
SmGui::SameLine();
|
ImGui::SameLine();
|
||||||
SmGui::FillWidth();
|
ImGui::FillWidth();
|
||||||
if (SmGui::InputInt(("##network_source_port_" + _this->name).c_str(), &_this->port, 0, 0)) {
|
if (ImGui::InputInt(("##iq_exporter_port_" + _this->name).c_str(), &_this->port, 0, 0)) {
|
||||||
_this->port = std::clamp<int>(_this->port, 1, 65535);
|
_this->port = std::clamp<int>(_this->port, 1, 65535);
|
||||||
config.acquire();
|
config.acquire();
|
||||||
config.conf[_this->name]["port"] = _this->port;
|
config.conf[_this->name]["port"] = _this->port;
|
||||||
config.release(true);
|
config.release(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Samplerate selector
|
||||||
|
ImGui::LeftLabel("Samplerate");
|
||||||
|
ImGui::FillWidth();
|
||||||
|
if (ImGui::Combo(("##iq_exporter_sr_" + _this->name).c_str(), &_this->srId, _this->samplerates.txt)) {
|
||||||
|
_this->samplerate = _this->samplerates.value(_this->srId);
|
||||||
|
core::setInputSampleRate(_this->samplerate);
|
||||||
|
config.acquire();
|
||||||
|
config.conf[_this->name]["samplerate"] = _this->samplerates.key(_this->srId);
|
||||||
|
config.release(true);
|
||||||
|
}
|
||||||
|
|
||||||
// Mode protocol selector
|
// Mode protocol selector
|
||||||
SmGui::LeftLabel("Protocol");
|
ImGui::LeftLabel("Protocol");
|
||||||
SmGui::FillWidth();
|
ImGui::FillWidth();
|
||||||
if (SmGui::Combo(("##network_source_proto_" + _this->name).c_str(), &_this->protoId, _this->protocols.txt)) {
|
if (ImGui::Combo(("##iq_exporter_proto_" + _this->name).c_str(), &_this->protoId, _this->protocols.txt)) {
|
||||||
_this->proto = _this->protocols.value(_this->protoId);
|
_this->proto = _this->protocols.value(_this->protoId);
|
||||||
config.acquire();
|
config.acquire();
|
||||||
config.conf[_this->name]["protocol"] = _this->protocols.key(_this->protoId);
|
config.conf[_this->name]["protocol"] = _this->protocols.key(_this->protoId);
|
||||||
@ -238,38 +264,15 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Sample type selector
|
// Sample type selector
|
||||||
SmGui::LeftLabel("Sample type");
|
ImGui::LeftLabel("Sample type");
|
||||||
SmGui::FillWidth();
|
ImGui::FillWidth();
|
||||||
if (SmGui::Combo(("##network_source_samp_" + _this->name).c_str(), &_this->sampTypeId, _this->sampleTypes.txt)) {
|
if (ImGui::Combo(("##iq_exporter_samp_" + _this->name).c_str(), &_this->sampTypeId, _this->sampleTypes.txt)) {
|
||||||
_this->sampType = _this->sampleTypes.value(_this->sampTypeId);
|
_this->sampType = _this->sampleTypes.value(_this->sampTypeId);
|
||||||
config.acquire();
|
config.acquire();
|
||||||
config.conf[_this->name]["sampleType"] = _this->sampleTypes.key(_this->sampTypeId);
|
config.conf[_this->name]["sampleType"] = _this->sampleTypes.key(_this->sampTypeId);
|
||||||
config.release(true);
|
config.release(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Samplerate selector
|
|
||||||
SmGui::LeftLabel("Samplerate");
|
|
||||||
SmGui::FillWidth();
|
|
||||||
if (SmGui::InputInt(("##network_source_sr_" + _this->name).c_str(), &_this->tempSamplerate)) {
|
|
||||||
// Prevent silly values from silly users
|
|
||||||
_this->tempSamplerate = std::max<int>(_this->tempSamplerate, 1000);
|
|
||||||
}
|
|
||||||
bool applyEn = (!_this->running && _this->tempSamplerate != _this->samplerate);
|
|
||||||
if (!applyEn) { SmGui::BeginDisabled(); }
|
|
||||||
SmGui::FillWidth();
|
|
||||||
if (SmGui::Button(("Apply##network_source_apply_" + _this->name).c_str())) {
|
|
||||||
_this->samplerate = _this->tempSamplerate;
|
|
||||||
core::setInputSampleRate(_this->samplerate);
|
|
||||||
config.acquire();
|
|
||||||
config.conf[_this->name]["samplerate"] = _this->samplerate;
|
|
||||||
config.release(true);
|
|
||||||
}
|
|
||||||
if (!applyEn) { SmGui::EndDisabled(); }
|
|
||||||
|
|
||||||
if (_this->tempSamplerate != _this->samplerate) {
|
|
||||||
SmGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), "Warning: Samplerate not applied yet");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_this->running) { SmGui::EndDisabled(); }
|
if (_this->running) { SmGui::EndDisabled(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -277,17 +280,14 @@ private:
|
|||||||
// Compute sizes
|
// Compute sizes
|
||||||
int blockSize = samplerate / 200;
|
int blockSize = samplerate / 200;
|
||||||
int sampleSize = SAMPLE_TYPE_SIZE[sampType];
|
int sampleSize = SAMPLE_TYPE_SIZE[sampType];
|
||||||
|
int frameSize = blockSize*sampleSize;
|
||||||
// Chose amount of bytes to attempt to read
|
|
||||||
bool forceSize = (proto != PROTOCOL_UDP);
|
|
||||||
int frameSize = sampleSize * (forceSize ? blockSize : STREAM_BUFFER_SIZE);
|
|
||||||
|
|
||||||
// Allocate receive buffer
|
// Allocate receive buffer
|
||||||
uint8_t* buffer = dsp::buffer::alloc<uint8_t>(frameSize);
|
uint8_t* buffer = dsp::buffer::alloc<uint8_t>(frameSize);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
// Read samples from socket
|
// Read samples from socket
|
||||||
int bytes = sock->recv(buffer, frameSize, forceSize);
|
int bytes = sock->recv(buffer, frameSize, true);
|
||||||
if (bytes <= 0) { break; }
|
if (bytes <= 0) { break; }
|
||||||
|
|
||||||
// Convert to CF32 (note: problem if partial sample)
|
// Convert to CF32 (note: problem if partial sample)
|
||||||
@ -325,7 +325,7 @@ private:
|
|||||||
double freq;
|
double freq;
|
||||||
|
|
||||||
int samplerate = 1000000;
|
int samplerate = 1000000;
|
||||||
int tempSamplerate = 1000000;
|
int srId;
|
||||||
Protocol proto = PROTOCOL_UDP;
|
Protocol proto = PROTOCOL_UDP;
|
||||||
int protoId;
|
int protoId;
|
||||||
SampleType sampType = SAMPLE_TYPE_INT16;
|
SampleType sampType = SAMPLE_TYPE_INT16;
|
||||||
@ -333,6 +333,7 @@ private:
|
|||||||
char hostname[1024] = "localhost";
|
char hostname[1024] = "localhost";
|
||||||
int port = 1234;
|
int port = 1234;
|
||||||
|
|
||||||
|
OptionList<int, int> samplerates;
|
||||||
OptionList<std::string, Protocol> protocols;
|
OptionList<std::string, Protocol> protocols;
|
||||||
OptionList<std::string, SampleType> sampleTypes;
|
OptionList<std::string, SampleType> sampleTypes;
|
||||||
|
|
||||||
|
@ -23,12 +23,6 @@ SDRPP_MOD_INFO{
|
|||||||
|
|
||||||
ConfigManager config;
|
ConfigManager config;
|
||||||
|
|
||||||
const std::vector<const char*> deviceWhiteList = {
|
|
||||||
"PlutoSDR",
|
|
||||||
"ANTSDR",
|
|
||||||
"LibreSDR"
|
|
||||||
};
|
|
||||||
|
|
||||||
class PlutoSDRSourceModule : public ModuleManager::Instance {
|
class PlutoSDRSourceModule : public ModuleManager::Instance {
|
||||||
public:
|
public:
|
||||||
PlutoSDRSourceModule(std::string name) {
|
PlutoSDRSourceModule(std::string name) {
|
||||||
@ -136,14 +130,7 @@ private:
|
|||||||
std::string duri = iio_context_info_get_uri(info);
|
std::string duri = iio_context_info_get_uri(info);
|
||||||
|
|
||||||
// If the device is not a plutosdr, don't include it
|
// If the device is not a plutosdr, don't include it
|
||||||
bool isPluto = false;
|
if (desc.find("PlutoSDR") == std::string::npos) {
|
||||||
for (const auto type : deviceWhiteList) {
|
|
||||||
if (desc.find(type) != std::string::npos) {
|
|
||||||
isPluto = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!isPluto) {
|
|
||||||
flog::warn("Ignored IIO device: [{}] {}", duri, desc);
|
flog::warn("Ignored IIO device: [{}] {}", duri, desc);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -5,17 +5,6 @@ file(GLOB SRC "src/*.cpp")
|
|||||||
|
|
||||||
include(${SDRPP_MODULE_CMAKE})
|
include(${SDRPP_MODULE_CMAKE})
|
||||||
|
|
||||||
if (MSVC)
|
target_include_directories(rfnm_source PRIVATE "C:/Users/ryzerth/Documents/Code/librfnm/include/librfnm")
|
||||||
# Lib path
|
target_link_directories(rfnm_source PRIVATE "C:/Users/ryzerth/Documents/Code/librfnm/build/Release")
|
||||||
target_link_directories(rfnm_source PRIVATE "C:/Program Files/RFNM/lib/")
|
target_link_libraries(rfnm_source PRIVATE librfnm)
|
||||||
target_include_directories(rfnm_source PUBLIC "C:/Program Files/RFNM/include/")
|
|
||||||
target_link_libraries(rfnm_source PRIVATE rfnm)
|
|
||||||
else (MSVC)
|
|
||||||
find_package(PkgConfig)
|
|
||||||
|
|
||||||
pkg_check_modules(LIBRFNM REQUIRED librfnm)
|
|
||||||
|
|
||||||
target_include_directories(rfnm_source PRIVATE ${LIBRFNM_INCLUDE_DIRS})
|
|
||||||
target_link_directories(rfnm_source PRIVATE ${LIBRFNM_LIBRARY_DIRS})
|
|
||||||
target_link_libraries(rfnm_source PRIVATE ${LIBRFNM_LIBRARIES})
|
|
||||||
endif ()
|
|
@ -3,10 +3,9 @@
|
|||||||
#include <gui/gui.h>
|
#include <gui/gui.h>
|
||||||
#include <gui/smgui.h>
|
#include <gui/smgui.h>
|
||||||
#include <signal_path/signal_path.h>
|
#include <signal_path/signal_path.h>
|
||||||
#include <librfnm/librfnm.h>
|
#include <librfnm.h>
|
||||||
#include <core.h>
|
#include <core.h>
|
||||||
#include <utils/optionlist.h>
|
#include <utils/optionlist.h>
|
||||||
#include <atomic>
|
|
||||||
|
|
||||||
SDRPP_MOD_INFO{
|
SDRPP_MOD_INFO{
|
||||||
/* Name: */ "rfnm_source",
|
/* Name: */ "rfnm_source",
|
||||||
@ -62,7 +61,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void refresh() {
|
void refresh() {
|
||||||
|
#ifndef __ANDROID__
|
||||||
devices.clear();
|
devices.clear();
|
||||||
auto list = librfnm::find(librfnm_transport::LIBRFNM_TRANSPORT_USB);
|
auto list = librfnm::find(librfnm_transport::LIBRFNM_TRANSPORT_USB);
|
||||||
for (const auto& info : list) {
|
for (const auto& info : list) {
|
||||||
@ -76,6 +76,16 @@ private:
|
|||||||
// Save device
|
// Save device
|
||||||
devices.define((char*)info.motherboard.serial_number, devName, (char*)info.motherboard.serial_number);
|
devices.define((char*)info.motherboard.serial_number, devName, (char*)info.motherboard.serial_number);
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
// Check for device presence
|
||||||
|
int vid, pid;
|
||||||
|
devFd = backend::getDeviceFD(vid, pid, backend::RFNM_VIDPIDS);
|
||||||
|
if (devFd < 0) { return; }
|
||||||
|
|
||||||
|
// Get device info
|
||||||
|
std::string fakeName = "RFNM USB";
|
||||||
|
devices.define(fakeName, fakeName, fakeName);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void select(const std::string& serial) {
|
void select(const std::string& serial) {
|
||||||
@ -91,131 +101,8 @@ private:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open the device
|
// // Open the device
|
||||||
librfnm* dev = new librfnm(librfnm_transport::LIBRFNM_TRANSPORT_USB, serial);
|
// librfnm* dev = new librfnm(librfnm_transport::LIBRFNM_TRANSPORT_USB, serial);
|
||||||
|
|
||||||
// Define samplerates
|
|
||||||
samplerates.clear();
|
|
||||||
samplerates.define(61440000, "61.44 MHz", 2);
|
|
||||||
samplerates.define(122880000, "122.88 MHz", 1);
|
|
||||||
|
|
||||||
// Define daughterboards
|
|
||||||
daughterboards.clear();
|
|
||||||
for (int i = 0; i < 2; i++) {
|
|
||||||
// If not present, skip
|
|
||||||
if (!dev->s->hwinfo.daughterboard[i].board_id) { continue; }
|
|
||||||
|
|
||||||
// Format the daughterboard name
|
|
||||||
std::string name = (i ? "[SEC] " : "[PRI] ") + std::string(dev->s->hwinfo.daughterboard[i].user_readable_name);
|
|
||||||
|
|
||||||
// Add the daughterboard to the list
|
|
||||||
daughterboards.define(name, name, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load options (TODO)
|
|
||||||
srId = samplerates.keyId(61440000);
|
|
||||||
dgbId = 0;
|
|
||||||
|
|
||||||
// Select the daughterboard
|
|
||||||
selectDaughterboard(dev, 0);
|
|
||||||
|
|
||||||
// Update samplerate
|
|
||||||
sampleRate = samplerates.key(srId);
|
|
||||||
|
|
||||||
// Close device
|
|
||||||
delete dev;
|
|
||||||
|
|
||||||
// Save serial number
|
|
||||||
selectedSerial = serial;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct PathConfig {
|
|
||||||
rfnm_rf_path path;
|
|
||||||
int chId;
|
|
||||||
uint16_t appliesCh;
|
|
||||||
|
|
||||||
bool operator==(const PathConfig& b) const {
|
|
||||||
return b.path == path;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void selectDaughterboard(librfnm* dev, int id) {
|
|
||||||
// If no daugherboard is populated, give up
|
|
||||||
if (!dev->s->hwinfo.daughterboard[0].board_id && !dev->s->hwinfo.daughterboard[1].board_id) {
|
|
||||||
flog::error("The selected device has no daughterboards");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the ID is not populated, select the other one
|
|
||||||
if (id >= 2 || !dev->s->hwinfo.daughterboard[id].board_id) {
|
|
||||||
selectDaughterboard(dev, 1 - id);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compute the channel offset
|
|
||||||
int offset = 0;
|
|
||||||
for (int i = 0; i < id; i++) {
|
|
||||||
offset += dev->s->hwinfo.daughterboard[i].rx_ch_cnt;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Define antenna paths by going through all channels
|
|
||||||
paths.clear();
|
|
||||||
int count = dev->s->hwinfo.daughterboard[id].rx_ch_cnt;
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
// Go through each possible path
|
|
||||||
for (int j = 0; j < 10; j++) {
|
|
||||||
// If it's the null path, stop searching
|
|
||||||
rfnm_rf_path path = dev->s->rx.ch[offset + i].path_possible[j];
|
|
||||||
if (path == RFNM_PATH_NULL) { continue; }
|
|
||||||
|
|
||||||
// Get the path
|
|
||||||
PathConfig pc = { path, offset + i, (uint16_t)(1 << (offset + i + 8))};
|
|
||||||
|
|
||||||
// If it's not in the list, add it
|
|
||||||
if (!paths.valueExists(pc)) {
|
|
||||||
std::string name = librfnm::rf_path_to_string(pc.path);
|
|
||||||
std::string capName = name;
|
|
||||||
if (std::islower(capName[0])) { capName[0] = std::toupper(capName[0]); }
|
|
||||||
paths.define(name, capName, pc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the preferred path
|
|
||||||
PathConfig preferred_pc = { dev->s->rx.ch[offset + i].path_preferred, 0, 0 };
|
|
||||||
|
|
||||||
// Make sure the path is accessible or give up
|
|
||||||
if (!paths.valueExists(preferred_pc)) { continue; }
|
|
||||||
|
|
||||||
// Set this channel as the channel of its prefered path (cursed af but lazy)
|
|
||||||
const PathConfig& pc = paths.value(paths.valueId(preferred_pc));
|
|
||||||
((PathConfig*)&pc)->chId = offset + i;
|
|
||||||
((PathConfig*)&pc)->appliesCh = (uint16_t)(1 << (offset + i + 8));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dump antenna paths
|
|
||||||
for (int i = 0; i < paths.size(); i++) {
|
|
||||||
flog::debug("PATH[{}]: Name={}, Ch={}, Path={}", i, paths.name(i), paths.value(i).chId, (int)paths.value(i).path);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load configuration (TODO)
|
|
||||||
selectedPath = paths.key(0);
|
|
||||||
|
|
||||||
// Select antenna path
|
|
||||||
selectPath(dev, id, selectedPath);
|
|
||||||
|
|
||||||
// Save selected daughterboard
|
|
||||||
dgbId = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
void selectPath(librfnm* dev, int dgbId, const std::string& path) {
|
|
||||||
// If the path doesn't exist, select the first path
|
|
||||||
if (!paths.keyExists(path)) {
|
|
||||||
selectPath(dev, dgbId, paths.key(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save selected path
|
|
||||||
selectedPath = path;
|
|
||||||
pathId = paths.keyId(path);
|
|
||||||
currentPath = paths.value(pathId);
|
|
||||||
|
|
||||||
// Define bandwidths
|
// Define bandwidths
|
||||||
bandwidths.clear();
|
bandwidths.clear();
|
||||||
@ -227,8 +114,27 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get gain range
|
// Get gain range
|
||||||
gainMin = dev->s->rx.ch[currentPath.chId].gain_range.min;
|
gainMin = -30;//dev->librfnm_s->rx.ch[0].gain_range.min;
|
||||||
gainMax = dev->s->rx.ch[currentPath.chId].gain_range.max;
|
gainMax = 60;//dev->librfnm_s->rx.ch[0].gain_range.max;
|
||||||
|
|
||||||
|
// // Close device
|
||||||
|
// delete dev;
|
||||||
|
|
||||||
|
// Define samplerates
|
||||||
|
samplerates.clear();
|
||||||
|
samplerates.define(61440000, "61.44 MHz", 2);
|
||||||
|
samplerates.define(122880000, "122.88 MHz", 1);
|
||||||
|
|
||||||
|
// TODO: Load options
|
||||||
|
srId = samplerates.keyId(61440000);
|
||||||
|
bwId = bandwidths.nameId("Auto");
|
||||||
|
gain = 0;
|
||||||
|
|
||||||
|
// Update samplerate
|
||||||
|
sampleRate = samplerates.key(srId);
|
||||||
|
|
||||||
|
// Save serial number
|
||||||
|
selectedSerial = serial;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void menuSelected(void* ctx) {
|
static void menuSelected(void* ctx) {
|
||||||
@ -247,7 +153,24 @@ private:
|
|||||||
if (_this->running) { return; }
|
if (_this->running) { return; }
|
||||||
|
|
||||||
// Open the device
|
// Open the device
|
||||||
|
#ifndef __ANDROID__
|
||||||
_this->openDev = new librfnm(librfnm_transport::LIBRFNM_TRANSPORT_USB, _this->selectedSerial);
|
_this->openDev = new librfnm(librfnm_transport::LIBRFNM_TRANSPORT_USB, _this->selectedSerial);
|
||||||
|
#else
|
||||||
|
_this->openDev = new librfnm(_this->devFd);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Configure the device
|
||||||
|
_this->openDev->librfnm_s->rx.ch[0].enable = RFNM_CH_ON;
|
||||||
|
_this->openDev->librfnm_s->rx.ch[0].samp_freq_div_n = _this->samplerates[_this->srId];
|
||||||
|
_this->openDev->librfnm_s->rx.ch[0].freq = _this->freq;
|
||||||
|
_this->openDev->librfnm_s->rx.ch[0].gain = _this->gain;
|
||||||
|
_this->openDev->librfnm_s->rx.ch[0].rfic_lpf_bw = 100;
|
||||||
|
_this->openDev->librfnm_s->rx.ch[0].fm_notch = _this->fmNotch ? rfnm_fm_notch::RFNM_FM_NOTCH_ON : rfnm_fm_notch::RFNM_FM_NOTCH_OFF;
|
||||||
|
_this->openDev->librfnm_s->rx.ch[0].path = _this->openDev->librfnm_s->rx.ch[0].path_preferred;
|
||||||
|
rfnm_api_failcode fail = _this->openDev->set(LIBRFNM_APPLY_CH0_RX);
|
||||||
|
if (fail != rfnm_api_failcode::RFNM_API_OK) {
|
||||||
|
flog::error("Failed to configure device: {}", (int)fail);
|
||||||
|
}
|
||||||
|
|
||||||
// Configure the stream
|
// Configure the stream
|
||||||
_this->bufferSize = -1;
|
_this->bufferSize = -1;
|
||||||
@ -263,24 +186,7 @@ private:
|
|||||||
_this->openDev->rx_qbuf(&_this->rxBuf[i]);
|
_this->openDev->rx_qbuf(&_this->rxBuf[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flush buffers
|
|
||||||
_this->openDev->rx_flush();
|
|
||||||
|
|
||||||
// Configure the device
|
|
||||||
_this->openDev->s->rx.ch[_this->currentPath.chId].enable = RFNM_CH_ON;
|
|
||||||
_this->openDev->s->rx.ch[_this->currentPath.chId].samp_freq_div_n = _this->samplerates[_this->srId];
|
|
||||||
_this->openDev->s->rx.ch[_this->currentPath.chId].freq = _this->freq;
|
|
||||||
_this->openDev->s->rx.ch[_this->currentPath.chId].gain = _this->gain;
|
|
||||||
_this->openDev->s->rx.ch[_this->currentPath.chId].rfic_lpf_bw = 100;
|
|
||||||
_this->openDev->s->rx.ch[_this->currentPath.chId].fm_notch = _this->fmNotch ? rfnm_fm_notch::RFNM_FM_NOTCH_ON : rfnm_fm_notch::RFNM_FM_NOTCH_OFF;
|
|
||||||
_this->openDev->s->rx.ch[_this->currentPath.chId].path = _this->currentPath.path;
|
|
||||||
rfnm_api_failcode fail = _this->openDev->set(_this->currentPath.appliesCh);
|
|
||||||
if (fail != rfnm_api_failcode::RFNM_API_OK) {
|
|
||||||
flog::error("Failed to configure device: {}", (int)fail);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start worker
|
// Start worker
|
||||||
_this->run = true;
|
|
||||||
_this->workerThread = std::thread(&RFNMSourceModule::worker, _this);
|
_this->workerThread = std::thread(&RFNMSourceModule::worker, _this);
|
||||||
|
|
||||||
_this->running = true;
|
_this->running = true;
|
||||||
@ -293,20 +199,13 @@ private:
|
|||||||
_this->running = false;
|
_this->running = false;
|
||||||
|
|
||||||
// Stop worker
|
// Stop worker
|
||||||
_this->run = false;
|
|
||||||
_this->stream.stopWriter();
|
_this->stream.stopWriter();
|
||||||
if (_this->workerThread.joinable()) { _this->workerThread.join(); }
|
if (_this->workerThread.joinable()) { _this->workerThread.join(); }
|
||||||
_this->stream.clearWriteStop();
|
_this->stream.clearWriteStop();
|
||||||
|
|
||||||
// Stop the RX streaming
|
|
||||||
_this->openDev->rx_stream_stop();
|
|
||||||
|
|
||||||
// Disable channel
|
// Disable channel
|
||||||
_this->openDev->s->rx.ch[_this->currentPath.chId].enable = RFNM_CH_OFF;
|
_this->openDev->librfnm_s->rx.ch[0].enable = RFNM_CH_ON;
|
||||||
_this->openDev->set(_this->currentPath.appliesCh);
|
_this->openDev->set(LIBRFNM_APPLY_CH0_RX);
|
||||||
|
|
||||||
// Flush buffers
|
|
||||||
_this->openDev->rx_flush();
|
|
||||||
|
|
||||||
// Close device
|
// Close device
|
||||||
delete _this->openDev;
|
delete _this->openDev;
|
||||||
@ -322,8 +221,8 @@ private:
|
|||||||
static void tune(double freq, void* ctx) {
|
static void tune(double freq, void* ctx) {
|
||||||
RFNMSourceModule* _this = (RFNMSourceModule*)ctx;
|
RFNMSourceModule* _this = (RFNMSourceModule*)ctx;
|
||||||
if (_this->running) {
|
if (_this->running) {
|
||||||
_this->openDev->s->rx.ch[_this->currentPath.chId].freq = freq;
|
_this->openDev->librfnm_s->rx.ch[0].freq = freq;
|
||||||
rfnm_api_failcode fail = _this->openDev->set(_this->currentPath.appliesCh);
|
rfnm_api_failcode fail = _this->openDev->set(LIBRFNM_APPLY_CH0_RX);
|
||||||
if (fail != rfnm_api_failcode::RFNM_API_OK) {
|
if (fail != rfnm_api_failcode::RFNM_API_OK) {
|
||||||
flog::error("Failed to tune: {}", (int)fail);
|
flog::error("Failed to tune: {}", (int)fail);
|
||||||
}
|
}
|
||||||
@ -360,48 +259,11 @@ private:
|
|||||||
core::setInputSampleRate(_this->sampleRate);
|
core::setInputSampleRate(_this->sampleRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_this->daughterboards.size() > 1) {
|
|
||||||
SmGui::LeftLabel("Daughterboard");
|
|
||||||
SmGui::FillWidth();
|
|
||||||
if (SmGui::Combo(CONCAT("##_rfnm_dgb_sel_", _this->name), &_this->dgbId, _this->daughterboards.txt)) {
|
|
||||||
// Open the device
|
|
||||||
librfnm* dev = new librfnm(librfnm_transport::LIBRFNM_TRANSPORT_USB, _this->selectedSerial);
|
|
||||||
|
|
||||||
// Select the daughterboard
|
|
||||||
_this->selectDaughterboard(dev, _this->dgbId);
|
|
||||||
|
|
||||||
// Close device
|
|
||||||
delete dev;
|
|
||||||
|
|
||||||
// TODO: Save
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_this->paths.size() > 1) {
|
|
||||||
SmGui::LeftLabel("Antenna Path");
|
|
||||||
SmGui::FillWidth();
|
|
||||||
if (SmGui::Combo(CONCAT("##_rfnm_path_sel_", _this->name), &_this->pathId, _this->paths.txt)) {
|
|
||||||
// Open the device
|
|
||||||
librfnm* dev = new librfnm(librfnm_transport::LIBRFNM_TRANSPORT_USB, _this->selectedSerial);
|
|
||||||
|
|
||||||
// Select the atennna path
|
|
||||||
_this->selectPath(dev, _this->dgbId, _this->paths.key(_this->pathId));
|
|
||||||
|
|
||||||
// Close device
|
|
||||||
delete dev;
|
|
||||||
|
|
||||||
// TODO: Save
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_this->running) { SmGui::EndDisabled(); }
|
if (_this->running) { SmGui::EndDisabled(); }
|
||||||
|
|
||||||
SmGui::LeftLabel("Bandwidth");
|
SmGui::LeftLabel("Bandwidth");
|
||||||
SmGui::FillWidth();
|
SmGui::FillWidth();
|
||||||
if (SmGui::Combo(CONCAT("##_rfnm_bw_sel_", _this->name), &_this->bwId, _this->bandwidths.txt)) {
|
if (SmGui::Combo(CONCAT("##_rfnm_bw_sel_", _this->name), &_this->bwId, _this->bandwidths.txt)) {
|
||||||
if (_this->running) {
|
|
||||||
// TODO: Set
|
|
||||||
}
|
|
||||||
// TODO: Save
|
// TODO: Save
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -409,16 +271,16 @@ private:
|
|||||||
SmGui::FillWidth();
|
SmGui::FillWidth();
|
||||||
if (SmGui::SliderInt(CONCAT("##_rfnm_gain_", _this->name), &_this->gain, _this->gainMin, _this->gainMax)) {
|
if (SmGui::SliderInt(CONCAT("##_rfnm_gain_", _this->name), &_this->gain, _this->gainMin, _this->gainMax)) {
|
||||||
if (_this->running) {
|
if (_this->running) {
|
||||||
_this->openDev->s->rx.ch[_this->currentPath.chId].gain = _this->gain;
|
_this->openDev->librfnm_s->rx.ch[0].gain = _this->gain;
|
||||||
rfnm_api_failcode fail = _this->openDev->set(_this->currentPath.appliesCh);
|
rfnm_api_failcode fail = _this->openDev->set(LIBRFNM_APPLY_CH0_RX);
|
||||||
}
|
}
|
||||||
// TODO: Save
|
// TODO: Save
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SmGui::Checkbox(CONCAT("FM Notch##_rfnm_", _this->name), &_this->fmNotch)) {
|
if (SmGui::Checkbox(CONCAT("FM Notch##_rfnm_", _this->name), &_this->fmNotch)) {
|
||||||
if (_this->running) {
|
if (_this->running) {
|
||||||
_this->openDev->s->rx.ch[_this->currentPath.chId].fm_notch = _this->fmNotch ? rfnm_fm_notch::RFNM_FM_NOTCH_ON : rfnm_fm_notch::RFNM_FM_NOTCH_OFF;
|
_this->openDev->librfnm_s->rx.ch[0].fm_notch = _this->fmNotch ? rfnm_fm_notch::RFNM_FM_NOTCH_ON : rfnm_fm_notch::RFNM_FM_NOTCH_OFF;
|
||||||
rfnm_api_failcode fail = _this->openDev->set(_this->currentPath.appliesCh);
|
rfnm_api_failcode fail = _this->openDev->set(LIBRFNM_APPLY_CH0_RX);
|
||||||
}
|
}
|
||||||
// TODO: Save
|
// TODO: Save
|
||||||
}
|
}
|
||||||
@ -427,18 +289,12 @@ private:
|
|||||||
void worker() {
|
void worker() {
|
||||||
librfnm_rx_buf* lrxbuf;
|
librfnm_rx_buf* lrxbuf;
|
||||||
int sampCount = bufferSize/4;
|
int sampCount = bufferSize/4;
|
||||||
uint8_t ch = (1 << currentPath.chId);
|
|
||||||
|
|
||||||
// Define number of buffers per swap to maintain 200 fps
|
// TODO: Define number of buffers per swap to maintain 200 fps
|
||||||
int maxBufCount = STREAM_BUFFER_SIZE / sampCount;
|
|
||||||
int bufCount = (sampleRate / sampCount) / 200;
|
|
||||||
if (bufCount <= 0) { bufCount = 1; }
|
|
||||||
if (bufCount > maxBufCount) { bufCount = maxBufCount; }
|
|
||||||
|
|
||||||
int count = 0;
|
while (true) {
|
||||||
while (run) {
|
|
||||||
// Receive a buffer
|
// Receive a buffer
|
||||||
auto fail = openDev->rx_dqbuf(&lrxbuf, ch, 1000);
|
auto fail = openDev->rx_dqbuf(&lrxbuf, LIBRFNM_CH0, 1000);
|
||||||
if (fail == rfnm_api_failcode::RFNM_API_DQBUF_NO_DATA) {
|
if (fail == rfnm_api_failcode::RFNM_API_DQBUF_NO_DATA) {
|
||||||
flog::error("Dequeue buffer didn't have any data");
|
flog::error("Dequeue buffer didn't have any data");
|
||||||
continue;
|
continue;
|
||||||
@ -446,17 +302,13 @@ private:
|
|||||||
else if (fail) { break; }
|
else if (fail) { break; }
|
||||||
|
|
||||||
// Convert buffer to CF32
|
// Convert buffer to CF32
|
||||||
volk_16i_s32f_convert_32f((float*)&stream.writeBuf[(count++)*sampCount], (int16_t*)lrxbuf->buf, 32768.0f, sampCount * 2);
|
volk_16i_s32f_convert_32f((float*)stream.writeBuf, (int16_t*)lrxbuf->buf, 32768.0f, sampCount * 2);
|
||||||
|
|
||||||
// Reque buffer
|
// Reque buffer
|
||||||
openDev->rx_qbuf(lrxbuf);
|
openDev->rx_qbuf(lrxbuf);
|
||||||
|
|
||||||
// Swap data
|
// Swap data
|
||||||
if (count >= bufCount) {
|
if (!stream.swap(sampCount)) { break; }
|
||||||
if (!stream.swap(count*sampCount)) { break; }
|
|
||||||
count = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
flog::debug("Worker exiting");
|
flog::debug("Worker exiting");
|
||||||
@ -471,15 +323,12 @@ private:
|
|||||||
double freq;
|
double freq;
|
||||||
|
|
||||||
OptionList<std::string, std::string> devices;
|
OptionList<std::string, std::string> devices;
|
||||||
OptionList<std::string, int> daughterboards;
|
|
||||||
OptionList<std::string, PathConfig> paths;
|
|
||||||
OptionList<int, int> bandwidths;
|
OptionList<int, int> bandwidths;
|
||||||
OptionList<int, int> samplerates;
|
OptionList<int, int> samplerates;
|
||||||
int gainMin = 0;
|
int gainMin = 0;
|
||||||
int gainMax = 0;
|
int gainMax = 0;
|
||||||
|
|
||||||
int devId = 0;
|
int devId = 0;
|
||||||
int dgbId = 0;
|
|
||||||
int pathId = 0;
|
|
||||||
int srId = 0;
|
int srId = 0;
|
||||||
int bwId = 0;
|
int bwId = 0;
|
||||||
int gain = 0;
|
int gain = 0;
|
||||||
@ -487,11 +336,12 @@ private:
|
|||||||
std::string selectedSerial;
|
std::string selectedSerial;
|
||||||
librfnm* openDev;
|
librfnm* openDev;
|
||||||
int bufferSize = -1;
|
int bufferSize = -1;
|
||||||
std::string selectedPath;
|
|
||||||
PathConfig currentPath;
|
|
||||||
librfnm_rx_buf rxBuf[LIBRFNM_MIN_RX_BUFCNT];
|
librfnm_rx_buf rxBuf[LIBRFNM_MIN_RX_BUFCNT];
|
||||||
|
|
||||||
std::atomic<bool> run = false;
|
#ifdef __ANDROID__
|
||||||
|
int devFd = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
std::thread workerThread;
|
std::thread workerThread;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -33,13 +33,10 @@ public:
|
|||||||
SpectranSourceModule(std::string name) {
|
SpectranSourceModule(std::string name) {
|
||||||
this->name = name;
|
this->name = name;
|
||||||
|
|
||||||
AARTSAAPI_Result res;
|
if (AARTSAAPI_Init(AARTSAAPI_MEMORY_MEDIUM) != AARTSAAPI_OK) {
|
||||||
if ((res = AARTSAAPI_Init(AARTSAAPI_MEMORY_MEDIUM)) != AARTSAAPI_OK) {
|
|
||||||
flog::error("Failed to initialize the RTSAAPI: {}", (uint32_t)res);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ((res = AARTSAAPI_Open(&api)) != AARTSAAPI_OK) {
|
if (AARTSAAPI_Open(&api) != AARTSAAPI_OK) {
|
||||||
flog::error("Failed to open the RTSAAPI: {}", (uint32_t)res);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -455,16 +452,13 @@ private:
|
|||||||
|
|
||||||
void updateRef() {
|
void updateRef() {
|
||||||
// Get and update bounds
|
// Get and update bounds
|
||||||
AARTSAAPI_Config config = {};
|
AARTSAAPI_Config config;
|
||||||
AARTSAAPI_ConfigInfo refInfo = {};
|
AARTSAAPI_ConfigInfo refInfo;
|
||||||
auto res = AARTSAAPI_ConfigFind(&dev, &croot, &config, L"main/reflevel");
|
AARTSAAPI_ConfigFind(&dev, &croot, &config, L"main/reflevel");
|
||||||
flog::debug("Res A: {}", res);
|
AARTSAAPI_ConfigGetInfo(&dev, &config, &refInfo);
|
||||||
res = AARTSAAPI_ConfigGetInfo(&dev, &config, &refInfo);
|
|
||||||
flog::debug("Res B: {}", res);
|
|
||||||
minRef = refInfo.minValue;
|
minRef = refInfo.minValue;
|
||||||
maxRef = refInfo.maxValue;
|
maxRef = refInfo.maxValue;
|
||||||
refStep = refInfo.stepValue;
|
refStep = refInfo.stepValue;
|
||||||
flog::debug("Gain: {} -> {}", refInfo.minValue, refInfo.maxValue);
|
|
||||||
refLevel = std::clamp<float>(refLevel, minRef, maxRef);
|
refLevel = std::clamp<float>(refLevel, minRef, maxRef);
|
||||||
|
|
||||||
// Apply new ref level
|
// Apply new ref level
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include <core.h>
|
#include <core.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
return sdrpp_main(argc, argv);
|
return sdrpp_main(argc, argv);
|
||||||
|
Reference in New Issue
Block a user