12 Commits

Author SHA1 Message Date
f8078ac3f0 more work on DAB decoding
Some checks failed
Build Binaries / build_debian_buster (push) Failing after 4s
Build Binaries / build_debian_bullseye (push) Failing after 5s
Build Binaries / build_debian_bookworm (push) Failing after 4s
Build Binaries / build_debian_sid (push) Failing after 4s
Build Binaries / build_ubuntu_focal (push) Failing after 4s
Build Binaries / build_ubuntu_jammy (push) Failing after 4s
Build Binaries / build_ubuntu_mantic (push) Failing after 4s
Build Binaries / build_ubuntu_noble (push) Failing after 5s
Build Binaries / build_android (push) Failing after 5s
Build Binaries / check_spelling (push) Failing after 3s
Build Binaries / check_formatting (push) Successful in 3s
Build Binaries / build_windows (push) Has been cancelled
Build Binaries / build_macos_intel (push) Has been cancelled
Build Binaries / build_macos_arm (push) Has been cancelled
Build Binaries / build_raspios_bullseye_armhf (push) Has been cancelled
Build Binaries / create_full_archive (push) Has been cancelled
Build Binaries / update_nightly_release (push) Has been cancelled
2024-09-23 00:51:06 +02:00
064f25ee73 work on the time sync algo
Some checks failed
Build Binaries / build_debian_buster (push) Failing after 5s
Build Binaries / build_debian_bullseye (push) Failing after 4s
Build Binaries / build_debian_bookworm (push) Failing after 4s
Build Binaries / build_debian_sid (push) Failing after 5s
Build Binaries / build_ubuntu_focal (push) Failing after 4s
Build Binaries / build_ubuntu_jammy (push) Failing after 4s
Build Binaries / build_ubuntu_mantic (push) Failing after 5s
Build Binaries / build_ubuntu_noble (push) Failing after 5s
Build Binaries / build_android (push) Failing after 5s
Build Binaries / check_spelling (push) Failing after 4s
Build Binaries / check_formatting (push) Successful in 4s
Build Binaries / build_windows (push) Has been cancelled
Build Binaries / build_macos_intel (push) Has been cancelled
Build Binaries / build_macos_arm (push) Has been cancelled
Build Binaries / build_raspios_bullseye_armhf (push) Has been cancelled
Build Binaries / create_full_archive (push) Has been cancelled
Build Binaries / update_nightly_release (push) Has been cancelled
2024-09-19 17:28:03 +02:00
d87ae23560 beginning of cleaner OFDM demod code 2024-09-19 05:47:58 +02:00
17eccf5156 enabled fobos source on windows 2024-09-14 15:05:12 +02:00
acb1be121c enable fobossdr source 2024-09-14 14:48:37 +02:00
0fa89614bb disabled problematic fobossdr source 2024-09-14 14:47:10 +02:00
256affd918 fixed fobossdr CI 2024-09-14 02:06:34 +02:00
e80cdbf248 fix CI + fix fobossdr_source cmakelist + prepare for fobos source on windows 2024-09-14 00:18:31 +02:00
75e66226c3 finish fobossdr source + add rigexpert to hardware donor list + fix source module default instantiation 2024-09-13 23:02:30 +02:00
c2f0e756a5 add fobossdr_source module and fix network sink crash when the given hostname is invalid 2024-09-11 21:57:12 +02:00
79dd5bdcbb add beginning of DAB decoder and add missing hardware donors to the credits 2024-09-10 15:33:22 +02:00
6dce28345c add missing stddef includes 2024-08-26 22:37:18 +02:00
38 changed files with 4070 additions and 144 deletions

View File

@ -71,14 +71,17 @@ jobs:
run: git clone https://github.com/thestk/rtaudio ; cd rtaudio ; git checkout 2f2fca4502d506abc50f6d4473b2836d24cfb1e3 ; mkdir build ; cd build ; cmake .. ; cmake --build . --config Release ; cmake --install .
- name: Install libperseus-sdr
run: git clone https://github.com/AlexandreRouma/libperseus-sdr ; cd libperseus-sdr ; mkdir build ; cd build ; cmake "-DLIBUSB_LIBRARIES=C:/Program Files/PothosSDR/lib/libusb-1.0.lib" "-DLIBUSB_INCLUDE_DIRS=C:/Program Files/PothosSDR/include/libusb-1.0" .. "-DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake" ; cmake --build . --config Release ; mkdir "C:/Program Files/PothosSDR/include/perseus-sdr" ; cp Release/perseus-sdr.dll "C:/Program Files/PothosSDR/bin" ; cp Release/perseus-sdr.lib "C:/Program Files/PothosSDR/bin" ; cd .. ; xcopy "src" "C:/Program Files/PothosSDR/include/perseus-sdr"
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"
- name: Install librfnm
run: git clone https://github.com/AlexandreRouma/librfnm ; cd librfnm ; mkdir build ; cd build ; cmake .. "-DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake" ; cmake --build . --config Release ; cmake --install .
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
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
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
- name: Build
working-directory: ${{runner.workspace}}/build
@ -127,12 +130,15 @@ jobs:
- 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
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
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 -DUSE_BUNDLE_DEFAULTS=ON -DCMAKE_BUILD_TYPE=Release
run: cmake -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15 $GITHUB_WORKSPACE -DOPT_BUILD_PLUTOSDR_SOURCE=ON -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_AUDIO_SINK=OFF -DOPT_BUILD_PORTAUDIO_SINK=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON -DOPT_BUILD_PERSEUS_SOURCE=ON -DOPT_BUILD_AUDIO_SOURCE=OFF -DOPT_BUILD_RFNM_SOURCE=ON -DOPT_BUILD_FOBOSSDR_SOURCE=ON -DUSE_BUNDLE_DEFAULTS=ON -DCMAKE_BUILD_TYPE=Release
- name: Build
working-directory: ${{runner.workspace}}/build
@ -181,12 +187,15 @@ jobs:
- 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
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
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 -DUSE_BUNDLE_DEFAULTS=ON -DCMAKE_BUILD_TYPE=Release
run: cmake -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15 $GITHUB_WORKSPACE -DOPT_BUILD_PLUTOSDR_SOURCE=ON -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_AUDIO_SINK=OFF -DOPT_BUILD_PORTAUDIO_SINK=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=OFF -DOPT_BUILD_PERSEUS_SOURCE=OFF -DOPT_BUILD_AUDIO_SOURCE=OFF -DOPT_BUILD_RFNM_SOURCE=ON -DOPT_BUILD_FOBOSSDR_SOURCE=ON -DUSE_BUNDLE_DEFAULTS=ON -DCMAKE_BUILD_TYPE=Release
- name: Build
working-directory: ${{runner.workspace}}/build

View File

@ -15,6 +15,7 @@ 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_BLADERF_SOURCE "Build BladeRF Source Module (Dependencies: libbladeRF)" OFF)
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_HAROGIC_SOURCE "Build Harogic Source Module (Dependencies: htra_api)" OFF)
option(OPT_BUILD_HERMES_SOURCE "Build Hermes Source Module (no dependencies required)" ON)
@ -43,6 +44,7 @@ option(OPT_BUILD_PORTAUDIO_SINK "Build PortAudio Sink Module (Dependencies: port
# Decoders
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_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)
@ -97,56 +99,13 @@ set(SDRPP_MODULE_COMPILER_FLAGS ${SDRPP_COMPILER_FLAGS})
# Set a default install prefix
if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
if (MSVC)
set(CMAKE_INSTALL_PREFIX "C:/Program Files/SDR++/" CACHE PATH "..." FORCE)
elseif (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
set(CMAKE_INSTALL_PREFIX "/usr/local" CACHE PATH "..." FORCE)
else()
set(CMAKE_INSTALL_PREFIX "/usr" CACHE PATH "..." FORCE)
endif()
endif()
# Include standard install directory definitions
include(GNUInstallDirs)
# Set up SDR++ directory load paths
if (MSVC)
set(SDRPP_MODULES_LOAD_DIR "./modules")
set(SDRPP_RES_LOAD_DIR "./res")
elseif (USE_BUNDLE_DEFAULTS)
set(SDRPP_MODULES_LOAD_DIR "../Plugins")
set(SDRPP_RES_LOAD_DIR "../Resources")
elseif (ANDROID)
set(SDRPP_MODULES_LOAD_DIR "/modules")
set(SDRPP_RES_LOAD_DIR "/res")
else()
set(SDRPP_MODULES_LOAD_DIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/sdrpp/plugins")
set(SDRPP_RES_LOAD_DIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATAROOTDIR}/sdrpp")
endif()
# Set up SDR++ directory install paths
if (MSVC)
set(SDRPP_BIN_INSTALL_DIR "/")
set(SDRPP_LIB_INSTALL_DIR "/")
set(SDRPP_MODULES_INSTALL_DIR "modules")
set(SDRPP_RES_INSTALL_DIR "res")
elseif (USE_BUNDLE_DEFAULTS)
set(SDRPP_BIN_INSTALL_DIR "Contents/MacOS")
set(SDRPP_LIB_INSTALL_DIR "Contents/Frameworks")
set(SDRPP_MODULES_INSTALL_DIR "Contents/Plugins")
set(SDRPP_RES_INSTALL_DIR "Contents/Resources")
elseif (ANDROID)
set(SDRPP_BIN_INSTALL_DIR "${CMAKE_INSTALL_BINDIR}")
set(SDRPP_LIB_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}")
set(SDRPP_MODULES_INSTALL_DIR "/modules")
set(SDRPP_RES_INSTALL_DIR "/res")
else()
set(SDRPP_BIN_INSTALL_DIR "${CMAKE_INSTALL_BINDIR}")
set(SDRPP_LIB_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}")
set(SDRPP_MODULES_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}/sdrpp/plugins")
set(SDRPP_RES_INSTALL_DIR "${CMAKE_INSTALL_DATAROOTDIR}/sdrpp")
endif()
# Configure toolchain for android
if (ANDROID)
set(CMAKE_SHARED_LINKER_FLAGS
@ -185,6 +144,10 @@ if (OPT_BUILD_FILE_SOURCE)
add_subdirectory("source_modules/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)
add_subdirectory("source_modules/hackrf_source")
endif (OPT_BUILD_HACKRF_SOURCE)
@ -285,6 +248,10 @@ if (OPT_BUILD_ATV_DECODER)
add_subdirectory("decoder_modules/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)
add_subdirectory("decoder_modules/falcon9_decoder")
endif (OPT_BUILD_FALCON9_DECODER)
@ -406,18 +373,17 @@ endif ()
# Create module cmake file
configure_file(${CMAKE_SOURCE_DIR}/sdrpp_module.cmake ${CMAKE_CURRENT_BINARY_DIR}/sdrpp_module.cmake @ONLY)
# Create desktop entry file
# Install directives
install(TARGETS sdrpp DESTINATION bin)
install(DIRECTORY ${CMAKE_SOURCE_DIR}/root/res/bandplans DESTINATION share/sdrpp)
install(DIRECTORY ${CMAKE_SOURCE_DIR}/root/res/colormaps DESTINATION share/sdrpp)
install(DIRECTORY ${CMAKE_SOURCE_DIR}/root/res/fonts DESTINATION share/sdrpp)
install(DIRECTORY ${CMAKE_SOURCE_DIR}/root/res/icons DESTINATION share/sdrpp)
install(DIRECTORY ${CMAKE_SOURCE_DIR}/root/res/themes DESTINATION share/sdrpp)
configure_file(${CMAKE_SOURCE_DIR}/sdrpp.desktop ${CMAKE_CURRENT_BINARY_DIR}/sdrpp.desktop @ONLY)
# Install directives
install(TARGETS sdrpp DESTINATION ${SDRPP_BIN_INSTALL_DIR})
install(DIRECTORY ${CMAKE_SOURCE_DIR}/root/res/bandplans DESTINATION ${SDRPP_RES_INSTALL_DIR})
install(DIRECTORY ${CMAKE_SOURCE_DIR}/root/res/colormaps DESTINATION ${SDRPP_RES_INSTALL_DIR})
install(DIRECTORY ${CMAKE_SOURCE_DIR}/root/res/fonts DESTINATION ${SDRPP_RES_INSTALL_DIR})
install(DIRECTORY ${CMAKE_SOURCE_DIR}/root/res/icons DESTINATION ${SDRPP_RES_INSTALL_DIR})
install(DIRECTORY ${CMAKE_SOURCE_DIR}/root/res/themes DESTINATION ${SDRPP_RES_INSTALL_DIR})
if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/sdrpp.desktop DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/applications)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/sdrpp.desktop DESTINATION share/applications)
endif ()
# Create uninstall target

View File

@ -18,10 +18,6 @@ if (MSVC)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
endif ()
# Add compiler definitions for the directories
add_definitions(-DSDRPP_MODULES_LOAD_DIR="${SDRPP_MODULES_LOAD_DIR}")
add_definitions(-DSDRPP_RES_LOAD_DIR="${SDRPP_RES_LOAD_DIR}")
# Configure backend sources
if (OPT_BACKEND_GLFW)
file(GLOB_RECURSE BACKEND_SRC "backends/glfw/*.cpp" "backends/glfw/*.c")
@ -37,6 +33,9 @@ add_library(sdrpp_core SHARED ${SRC} ${BACKEND_SRC})
# Set compiler options
target_compile_options(sdrpp_core PRIVATE ${SDRPP_COMPILER_FLAGS})
# Set the install prefix
target_compile_definitions(sdrpp_core PUBLIC INSTALL_PREFIX="${CMAKE_INSTALL_PREFIX}")
# Include core headers
target_include_directories(sdrpp_core PUBLIC "src/")
target_include_directories(sdrpp_core PUBLIC "src/imgui")
@ -168,4 +167,4 @@ set(CORE_FILES ${RUNTIME_OUTPUT_DIRECTORY} PARENT_SCOPE)
# cmake .. "-DCMAKE_TOOLCHAIN_FILE=C:/dev/vcpkg/scripts/buildsystems/vcpkg.cmake"
# Install directives
install(TARGETS sdrpp_core DESTINATION ${SDRPP_LIB_INSTALL_DIR})
install(TARGETS sdrpp_core DESTINATION lib)

View File

@ -24,16 +24,14 @@
#include <Windows.h>
#endif
// Default install dirs to make the IDE happy
#ifndef SDRPP_MODULES_LOAD_DIR
#define SDRPP_MODULES_LOAD_DIR ""
#ifndef INSTALL_PREFIX
#ifdef __APPLE__
#define INSTALL_PREFIX "/usr/local"
#else
#define INSTALL_PREFIX "/usr"
#endif
#ifndef SDRPP_RES_LOAD_DIR
#define SDRPP_RES_LOAD_DIR ""
#endif
namespace core {
ConfigManager configManager;
ModuleManager moduleManager;
@ -175,16 +173,20 @@ int sdrpp_main(int argc, char* argv[]) {
defConfig["moduleInstances"]["BladeRF Source"]["enabled"] = true;
defConfig["moduleInstances"]["File Source"]["module"] = "file_source";
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"]["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"]["enabled"] = true;
defConfig["moduleInstances"]["LimeSDR Source"]["module"] = "limesdr_source";
defConfig["moduleInstances"]["LimeSDR Source"]["enabled"] = true;
defConfig["moduleInstances"]["PlutoSDR Source"]["module"] = "plutosdr_source";
defConfig["moduleInstances"]["PlutoSDR Source"]["enabled"] = true;
defConfig["moduleInstances"]["PerseusSDR Source"]["module"] = "perseus_source";
defConfig["moduleInstances"]["PerseusSDR Source"]["enabled"] = true;
defConfig["moduleInstances"]["PlutoSDR Source"]["module"] = "plutosdr_source";
defConfig["moduleInstances"]["PlutoSDR Source"]["enabled"] = true;
defConfig["moduleInstances"]["RFNM Source"]["module"] = "rfnm_source";
defConfig["moduleInstances"]["RFNM Source"]["enabled"] = true;
defConfig["moduleInstances"]["RFspace Source"]["module"] = "rfspace_source";
@ -197,8 +199,12 @@ int sdrpp_main(int argc, char* argv[]) {
defConfig["moduleInstances"]["SDRplay Source"]["enabled"] = true;
defConfig["moduleInstances"]["SDR++ Server Source"]["module"] = "sdrpp_server_source";
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"]["enabled"] = true;
defConfig["moduleInstances"]["USRP Source"]["module"] = "usrp_source";
defConfig["moduleInstances"]["USRP Source"]["enabled"] = true;
defConfig["moduleInstances"]["Audio Sink"] = "audio_sink";
defConfig["moduleInstances"]["Network Sink"] = "network_sink";
@ -250,14 +256,19 @@ int sdrpp_main(int argc, char* argv[]) {
defConfig["lockMenuOrder"] = false;
#endif
#ifdef __ANDROID__
defConfig["modulesDirectory"] = root + SDRPP_MODULES_LOAD_DIR;
defConfig["resourcesDirectory"] = root + SDRPP_RES_LOAD_DIR;
#if defined(_WIN32)
defConfig["modulesDirectory"] = "./modules";
defConfig["resourcesDirectory"] = "./res";
#elif defined(IS_MACOS_BUNDLE)
defConfig["modulesDirectory"] = "../Plugins";
defConfig["resourcesDirectory"] = "../Resources";
#elif defined(__ANDROID__)
defConfig["modulesDirectory"] = root + "/modules";
defConfig["resourcesDirectory"] = root + "/res";
#else
defConfig["modulesDirectory"] = SDRPP_MODULES_LOAD_DIR;
defConfig["resourcesDirectory"] = SDRPP_RES_LOAD_DIR;
defConfig["modulesDirectory"] = INSTALL_PREFIX "/lib/sdrpp/plugins";
defConfig["resourcesDirectory"] = INSTALL_PREFIX "/share/sdrpp";
#endif
// Load config
flog::info("Loading config");

View File

@ -37,9 +37,12 @@ namespace sdrpp_credits {
const char* hardwareDonators[] = {
"Aaronia AG",
"Airspy",
"Alex 4Z5LV",
"Analog Devices",
"CaribouLabs",
"Deepace",
"Ettus Research",
"Harogic",
"Howard Su",
"MicroPhase",
"Microtelecom",
@ -47,6 +50,7 @@ namespace sdrpp_credits {
"Nuand",
"RFNM",
"RFspace",
"RigExpert",
"RTL-SDRblog",
"SDRplay"
};

View File

@ -0,0 +1,37 @@
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 ()

View File

@ -0,0 +1,280 @@
#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

View File

@ -0,0 +1,165 @@
#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>
#include "ofdm.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("sync5.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, 2048, 504, 1e-3, INPUT_SAMPLE_RATE, 1e-6, 0.01, 0.005);
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::ofdm::CyclicTimeSync csync;
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();
}

View File

@ -0,0 +1,324 @@
#pragma once
#include <dsp/processor.h>
#include <dsp/loop/phase_control_loop.h>
#include <dsp/taps/windowed_sinc.h>
#include <dsp/multirate/polyphase_bank.h>
#include <dsp/math/step.h>
namespace dsp::ofdm {
class CyclicTimeSync : public Processor<complex_t, complex_t> {
using base_type = Processor<complex_t, complex_t> ;
public:
CyclicTimeSync() {}
CyclicTimeSync(stream<complex_t>* in, int fftSize, int cpSize, double usefulSymbolTime, double samplerate,
double omegaGain, double muGain, double omegaRelLimit, int interpPhaseCount = 128, int interpTapCount = 8) {
init(in, fftSize, cpSize, usefulSymbolTime, samplerate, omegaGain, muGain, omegaRelLimit, interpPhaseCount, interpTapCount);
}
~CyclicTimeSync() {
if (!base_type::_block_init) { return; }
base_type::stop();
dsp::multirate::freePolyphaseBank(interpBank);
buffer::free(corrSampCache);
buffer::free(corrProdCache);
buffer::free(buffer);
}
void init(stream<complex_t>* in, int fftSize, int cpSize, double usefulSymbolTime, double samplerate,
double omegaGain, double muGain, double omegaRelLimit, int interpPhaseCount = 128, int interpTapCount = 8) {
// Save parameters
this->fftSize = fftSize;
this->cpSize = cpSize;
period = fftSize + cpSize;
// Compute the interpolator settings
omega = (usefulSymbolTime * samplerate) / (double)fftSize;
this->omegaGain = omegaGain;
this->muGain = muGain;
this->omegaRelLimit = omegaRelLimit;
this->interpPhaseCount = interpPhaseCount;
this->interpTapCount = interpTapCount;
// Compute the correlator AGC settings
// TODO: Compute it using he FFT and CP sizes
this->corrAgcRate = 1e-4;
corrAgcInvRate = 1.0f - corrAgcRate;
// Initialize the control loop
pcl.init(muGain, omegaGain, 0.0, 0.0, 1.0, omega, omega * (1.0 - omegaRelLimit), omega * (1.0 + omegaRelLimit));
// Generate the interpolation taps
generateInterpTaps();
// Allocate the buffers
corrSampCache = buffer::alloc<complex_t>(fftSize);
corrProdCache = buffer::alloc<complex_t>(cpSize);
buffer = buffer::alloc<complex_t>(STREAM_BUFFER_SIZE + interpTapCount);
bufStart = &buffer[interpTapCount - 1];
// Clear the buffers
buffer::clear(corrSampCache, fftSize);
buffer::clear(corrProdCache, cpSize);
buffer::clear(buffer, interpTapCount - 1);
base_type::init(in);
}
void setOmegaGain(double omegaGain) {
assert(base_type::_block_init);
std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
this->omegaGain = omegaGain;
pcl.setCoefficients(muGain, omegaGain);
}
void setMuGain(double muGain) {
assert(base_type::_block_init);
std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
this->muGain = muGain;
pcl.setCoefficients(muGain, omegaGain);
}
void setOmegaRelLimit(double omegaRelLimit) {
assert(base_type::_block_init);
std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
this->omegaRelLimit = omegaRelLimit;
pcl.setFreqLimits(omega * (1.0 - omegaRelLimit), omega * (1.0 + omegaRelLimit));
}
void setInterpParams(int interpPhaseCount, int interpTapCount) {
assert(base_type::_block_init);
std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
base_type::tempStop();
this->interpPhaseCount = interpPhaseCount;
this->interpTapCount = interpTapCount;
dsp::multirate::freePolyphaseBank(interpBank);
buffer::free(buffer);
generateInterpTaps();
buffer = buffer::alloc<complex_t>(STREAM_BUFFER_SIZE + interpTapCount);
bufStart = &buffer[interpTapCount - 1];
base_type::tempStart();
}
void reset() {
assert(base_type::_block_init);
std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
base_type::tempStop();
offset = 0;
pcl.phase = 0.0f;
pcl.freq = omega;
// TODO: The rest
base_type::tempStart();
}
int run() {
int count = base_type::_in->read();
if (count < 0) { return -1; }
// Copy data to work buffer
memcpy(bufStart, base_type::_in->readBuf, count * sizeof(complex_t));
// Process all samples
while (offset < count) {
// Get the cache slots
complex_t* sampSlot = &corrSampCache[corrSampCacheId++];
complex_t* prodSlot = &corrProdCache[corrProdCacheId++];
corrSampCacheId %= fftSize;
corrProdCacheId %= cpSize;
// Compute the interpolated sample
complex_t sample;
int phase = std::clamp<int>(floorf(pcl.phase * (float)interpPhaseCount), 0, interpPhaseCount - 1);
volk_32fc_32f_dot_prod_32fc((lv_32fc_t*)&sample, (lv_32fc_t*)&buffer[offset], interpBank.phases[phase], interpTapCount);
// Write the sample to the output
if (outCount >= cpSize) {
out.writeBuf[outCount - cpSize] = sample;
}
// Send out a symbol when it's fully received
if ((++outCount) >= fftSize+cpSize) {
if (!out.swap(outCount)) { break; }
outCount = 0;
}
// Run autocorrelation
complex_t prod = sample.conj()*(*sampSlot);
corr += prod;
corr -= *prodSlot;
// Write back the new sample and product value to the cache
*sampSlot = sample;
*prodSlot = prod;
// Compute the correlation level
float corrLvl = corr.amplitude();
// Detect peak in autocorrelation (TODO: level check maybe not needed now that corrPeak is reset to corrLvl)
if (corrLvl > corrAvg && corrLvl > corrPeak) {
// Save the current correlation as the peak
corrPeak = corrLvl;
// Save the value of the previous correlation as the left side of the peak
corrPeakL = corrLast;
// Reset the peak distance counter
sincePeak = 0;
}
// The first sample after a peak is the right-side sample
if (sincePeak == 1) {
corrPeakR = corrLvl;
}
else if (sincePeak == cpSize) {
// Start the useful symbol counter
sinceCp = 0;
// Compute the fractional error (TODO: Probably very inaccurate with noise, use real slopes instead)
if (corrPeakL > corrPeakR) {
float maxSlope = corrPeakR - corrPeak;
float slope = corrPeak - corrPeakL;
fracErr = std::clamp<float>(0.5f * (1.0f + slope / maxSlope), -0.5f, 0.5f);
}
else {
float maxSlope = corrPeak - corrPeakL;
float slope = corrPeakR - corrPeak;
fracErr = std::clamp<float>(-0.5f * (1.0f + slope / maxSlope), -0.5f, 0.5f);
}
}
else if (sincePeak == fftSize) {
// Reset the peak detector
corrPeak = corrAvg;
}
// NOTE: THIS IS ONLY NEEDED FOR DAB
// Detect a wider-than-normal distance to adapt the output counter
else if (sincePeak == 2656) {
// Reset the output counter
outCount = 50;
}
// Last sample of useful symbol
if (sinceCp == fftSize) {
// If the fractional error is valid, run closed-loop
float err = 0.0f;
if (!std::isnan(fracErr)) {
// Compute the measured period using the distance to the last symbol
float measuredPeriod = (float)sinceLastSym - fracErr;
// NOTE: THIS IS ONLY NEEDED FOR DAB
if (measuredPeriod > 3828.0f) {
// Null symbol
err = measuredPeriod - (2552.0f+2656.0f);
}
else {
// Regular symbol
err = measuredPeriod - period;
}
err = std::clamp<float>(err, -10.0f, 10.0f);
// Run the control loop in closed-loop mode
pcl.advance(err);
}
else {
// Otherwise, run open-loop
pcl.advancePhase();
}
// printf("%d\n", outCount);
// Nudge the symbol window if it's too out of sync
if (outCount > 100) {
// TODO: MOVE THE LAST SAMPLES OR THE SYMBOL WILL BE CORRUPTED!
outCount = 50;
flog::debug("NUDGE!");
}
// Reset the period counter
sinceLastSym = 0;
}
else {
// Run the control loop in open-loop mode
pcl.advancePhase();
}
// Update the offset and phase
float delta = floorf(pcl.phase);
offset += delta;
pcl.phase -= delta;
// Update the last correlation level
corrLast = corrLvl;
// Update correlation AGC
corrAvg = corrAvg*corrAgcInvRate + corrLvl*corrAgcRate;
// Increment the distance counters (TODO: Check if they happen at the right point, eg. after being reset to zero)
sincePeak++;
sinceLastSym++;
sinceCp++;
}
// Prepare offset for next buffer of samples
offset -= count;
// Update delay buffer
memmove(buffer, &buffer[count], (interpTapCount - 1) * sizeof(complex_t));
// Swap if some data was generated
base_type::_in->flush();
return count;
}
protected:
void generateInterpTaps() {
double bw = 0.5 / (double)interpPhaseCount;
dsp::tap<float> lp = dsp::taps::windowedSinc<float>(interpPhaseCount * interpTapCount, dsp::math::hzToRads(bw, 1.0), dsp::window::nuttall, interpPhaseCount);
interpBank = dsp::multirate::buildPolyphaseBank<float>(interpPhaseCount, lp);
taps::free(lp);
}
// OFDM Configuration
int fftSize;
int cpSize;
float period;
// Interpolator
dsp::multirate::PolyphaseBank<float> interpBank;
int interpPhaseCount;
int interpTapCount;
int offset = 0;
complex_t* buffer = NULL;
complex_t* bufStart;
// Control loop
loop::PhaseControlLoop<float, false> pcl;
double omega;
double omegaGain;
double muGain;
double omegaRelLimit;
float fracErr = 0.0f;
// Autocorrelator
complex_t corr = {0.0f, 0.0f};
complex_t* corrSampCache = NULL;
complex_t* corrProdCache = NULL;
int corrSampCacheId = 0;
int corrProdCacheId = 0;
float corrAgcRate;
float corrAgcInvRate;
float corrAvg = 0;
float corrLast = 0;
float corrPeakR = 0;
float corrPeak = 0;
float corrPeakL = 0;
// Peak detection
int sincePeak = 0;
int sinceLastSym = 0;
int sinceCp = 0;
// Other shit to categorize
int outCount = 0;
};
};

View File

@ -0,0 +1,31 @@
cyclicLen = 4
usefulLen = 12
A = 0*12 + 1*13 + 2*14 + 3*15
B = 1*13 + 2*14 + 3*15 + 4*16 = A - 0*12 + 4*16
C = 2*14 + 3*15 + 4*16 + 5*17 = B - 1*13 + 5*17
D = 3*15 + 4*16 + 5*17 + 6*18 = C - 2*14 + 6*18
E = 4*16 + 5*17 + 6*18 + 7*19 = D - 3*15 + 7*19
F = 5*17 + 6*18 + 7*19 + 8*20 = E - 4*16 + 8*20
G = 6*18 + 7*19 + 8*20 + 9*21 = F - 5*17 + 9*21
H = 7*19 + 8*20 + 9*21 + 10*22 = G - 6*18 + 10*22
I = 8*20 + 9*21 + 10*22 + 11*23 = H - 7*19 + 11*23
J = 9*21 + 10*22 + 11*23 + 12*24 = I - 8*20 + 12*24
K = 10*22 + 11*23 + 12*24 + 13*25 = J - 9*21 + 13*25
L = 11*23 + 12*24 + 13*25 + 14*26 = K - 10*22 + 14*26
M = 12*24 + 13*25 + 14*26 + 15*27 = L - 11*23 + 15*27
N = 13*25 + 14*26 + 15*27 + 16*28 = M - 12*24 + 16*28
O = 14*26 + 15*27 + 16*28 + 17*29 = N - 13*25 + 17*29
P = 15*27 + 16*28 + 17*29 + 18*30 = O - 14*26 + 18*30
Q = 16*28 + 17*29 + 18*30 + 19*31 = P - 15*27 + 19*31
R = 17*29 + 18*30 + 19*31 + 20*32 = Q - 16*28 + 20*32
S = 18*30 + 19*31 + 20*32 + 21*33 = R - 17*29 + 21*33
T = 19*31 + 20*32 + 21*33 + 22*34 = S - 18*30 + 22*34
U = 20*32 + 21*33 + 22*34 + 23*35 = T - 19*31 + 23*35
Conclusion:
sampCacheLen = usefulLen
prodCacheLen = cyclicLen
Peak correlation occurs when the current interpolated value is the last FFT sample

View File

@ -0,0 +1,397 @@
5209
2553
2551
2551
2552
2551
2553
2555
2549
2552
2552
2554
2550
2553
2553
2550
2553
2552
2550
2552
2548
2558
2551
2546
2559
2551
2552
2552
2551
2554
2555
2549
2550
2549
2557
2551
2554
2550
2552
2546
2559
2551
2554
2550
2550
2557
2550
2556
2543
2556
2551
2554
2551
2553
2554
2550
2551
2552
2552
2553
2550
2553
2546
2558
2552
2552
2552
2550
2555
2551
2551
2554
2553
2553
2549
2552
5208
2554
2550
2552
2551
2553
2551
2553
2551
2553
2550
2554
2553
2551
2553
2552
2546
2557
2551
2553
2552
2551
2553
2551
2548
2557
2553
2551
2562
2539
2559
2548
2551
2551
2550
2556
2551
2554
2550
2552
2552
2548
2556
2550
2554
2553
2553
2550
2552
2552
2550
2555
2558
2545
2552
2553
2548
2555
2552
2552
2557
2550
2548
2553
2554
2550
2552
2547
2558
2551
2552
2552
2552
2555
2549
2552
5208
2552
2552
2552
2550
2555
2550
2553
2553
2551
2552
2547
2557
2552
2552
2552
2552
2552
2552
2552
2546
2558
2551
2552
2553
2551
2553
2553
2552
2551
2552
2552
2551
2553
2552
2552
2552
2552
2552
2552
2556
2548
2551
2555
2550
2552
2555
2549
2552
2552
2550
2553
2551
2554
2552
2551
2553
2553
2551
2548
2550
2555
2554
2553
2556
2547
2552
2554
2552
2550
2552
2552
2553
2552
2551
2552
5209
2553
2551
2551
2547
2558
2550
2553
2552
2553
2552
2549
2551
2557
2549
2554
2551
2554
2550
2553
2553
2551
2551
2548
2559
2549
2552
2552
2552
2551
2551
2550
2557
2551
2552
2555
2549
2557
2549
2550
2553
2549
2554
2553
2553
2550
2552
2553
2550
2553
2553
2551
2547
2557
2552
2552
2551
2553
2549
2555
2556
2550
2550
2553
2551
2552
2553
2551
2552
2552
2552
2553
2551
2541
2563
2552
5210
2550
2551
2552
2553
2553
2551
2552
2552
2552
2552
2558
2547
2551
2552
2552
2552
2552
2550
2554
2551
2553
2552
2551
2553
2551
2553
2553
2550
2551
2555
2550
2552
2552
2553
2553
2550
2552
2553
2550
2553
2558
2546
2553
2554
2550
2552
2553
2548
2554
2552
2552
2552
2551
2554
2550
2553
2553
2550
2551
2552
2554
2553
2551
2551
2555
2550
2553
2552
2550
2554
2550
2553
2553
2553
2550
5210
2553
2549
2553
2551
2552
2552
2556
2548
2549
2555
2551
2557
2548
2552
2552
2552

View File

@ -23,9 +23,9 @@ SDRPP_MOD_INFO{
/* Max instances */ -1
};
#define INPUT_BANDWIDTH 138e3
#define INPUT_SAMPLE_RATE 250e3
#define INPUT_BAUDRATE 125e3
#define INPUT_BANDWIDTH 600e3
#define INPUT_SAMPLE_RATE 1000e3
#define INPUT_BAUDRATE 500e3
#define SYMBOL_DIAG_RATE 30
#define SYMBOL_DIAG_COUNT 1024

View File

@ -1,5 +1,6 @@
#pragma once
#include <stdint.h>
#include <stddef.h>
#include "dsp/processor.h"
extern "C" {

View File

@ -1,6 +1,7 @@
#pragma once
#include "dsp/processor.h"
#include <stdint.h>
#include <stddef.h>
namespace ryfi {
// Synchronization word.

View File

@ -1,5 +1,6 @@
#pragma once
#include <stdint.h>
#include <stddef.h>
namespace ryfi {
/**

View File

@ -72,6 +72,7 @@ namespace ryfi {
uint8_t* pktBuffer = new uint8_t[Packet::MAX_CONTENT_SIZE];
int pktExpected = 0;
int pktRead = 0;
int valid = 0;
while (true) {
// Read a frame
@ -80,6 +81,7 @@ namespace ryfi {
// Deserialize the frame
Frame::deserialize(rs.out.readBuf, frame);
valid++;
// Flush the stream
rs.out.flush();
@ -93,11 +95,12 @@ namespace ryfi {
// If the frames aren't consecutive
int frameRead = 0;
if (frame.counter != expectedCounter) {
flog::warn("Lost at least {} frames", ((int)frame.counter - (int)expectedCounter + 0x10000) % 0x10000);
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) {

View File

@ -1,5 +1,6 @@
#pragma once
#include <stdint.h>
#include <stddef.h>
#include "dsp/processor.h"
extern "C" {

View File

@ -35,10 +35,20 @@ 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
mkdir build
cd build
cmake .. -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON -DOPT_BUILD_PERSEUS_SOURCE=ON -DOPT_BUILD_RFNM_SOURCE=ON
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
make VERBOSE=1 -j2
cd ..

View File

@ -35,10 +35,20 @@ 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
mkdir build
cd build
cmake .. -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON -DOPT_BUILD_PERSEUS_SOURCE=ON -DOPT_BUILD_RFNM_SOURCE=ON
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
make VERBOSE=1 -j2
cd ..

View File

@ -35,10 +35,20 @@ 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
mkdir build
cd build
cmake .. -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_BLADERF_SOURCE=OFF -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON -DOPT_BUILD_PERSEUS_SOURCE=ON -DOPT_BUILD_RFNM_SOURCE=ON
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
make VERBOSE=1 -j2
cd ..

View File

@ -35,10 +35,20 @@ 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
mkdir build
cd build
cmake .. -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON -DOPT_BUILD_PERSEUS_SOURCE=ON -DOPT_BUILD_RFNM_SOURCE=ON
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
make VERBOSE=1 -j2
cd ..

View File

@ -1,4 +0,0 @@
FROM fedora:40
ENV DEBIAN_FRONTEND=noninteractive
COPY do_build.sh /root
RUN chmod +x /root/do_build.sh

View File

@ -1,31 +0,0 @@
#!/bin/bash
set -e
cd /root
# Install dependencies and tools
dnf update -y
dnf install -y make gcc g++ cmake git wget p7zip fftw-devel glfw-devel volk-devel libzstd-devel codec2-devel airspyone_host-devel rtaudio-devel \
hackrf-devel rtl-sdr-devel portaudio-devel spdlog-devel libusbg-devel
# Install SDRPlay libraries
wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.15.1.run
7za x ./SDRplay_RSP_API-Linux-3.15.1.run
7za x ./SDRplay_RSP_API-Linux-3.15.1
cp x86_64/libsdrplay_api.so.3.15 /usr/lib/libsdrplay_api.so
cp inc/* /usr/include/
# Install librfnm
git clone https://github.com/AlexandreRouma/librfnm
cd librfnm
mkdir build
cd build
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr
make -j2
make install
cd ../../
cd SDRPlusPlus
mkdir build
cd build
cmake .. -DOPT_BUILD_AIRSPYHF_SOURCE=OFF -DOPT_BUILD_PLUTOSDR_SOURCE=OFF -DOPT_BUILD_RFNM_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON
make VERBOSE=1 -j2

View File

@ -61,6 +61,16 @@ 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
echo 'prefix=/usr/' >> /usr/share/pkgconfig/codec2.pc
echo 'libdir=/usr/include/x86_64-linux-gnu/' >> /usr/share/pkgconfig/codec2.pc
@ -76,7 +86,7 @@ echo 'Cflags: -I/usr/include/codec2' >> /usr/share/pkgconfig/codec2.pc
cd SDRPlusPlus
mkdir build
cd build
cmake .. -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_BLADERF_SOURCE=OFF -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_OVERRIDE_STD_FILESYSTEM=ON -DOPT_BUILD_M17_DECODER=ON -DOPT_BUILD_PERSEUS_SOURCE=ON -DOPT_BUILD_RFNM_SOURCE=ON
cmake .. -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_BLADERF_SOURCE=OFF -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_OVERRIDE_STD_FILESYSTEM=ON -DOPT_BUILD_M17_DECODER=ON -DOPT_BUILD_PERSEUS_SOURCE=ON -DOPT_BUILD_RFNM_SOURCE=ON -DOPT_BUILD_FOBOSSDR_SOURCE=ON
make VERBOSE=1 -j2
# Generate package

View File

@ -35,10 +35,20 @@ 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
mkdir build
cd build
cmake .. -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON -DOPT_BUILD_PERSEUS_SOURCE=ON -DOPT_BUILD_RFNM_SOURCE=ON
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
make VERBOSE=1 -j2
cd ..

View File

@ -35,10 +35,20 @@ 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
mkdir build
cd build
cmake .. -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON -DOPT_BUILD_PERSEUS_SOURCE=ON -DOPT_BUILD_RFNM_SOURCE=ON
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
make VERBOSE=1 -j2
cd ..

View File

@ -35,10 +35,20 @@ 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
mkdir build
cd build
cmake .. -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON -DOPT_BUILD_PERSEUS_SOURCE=ON -DOPT_BUILD_RFNM_SOURCE=ON
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
make VERBOSE=1 -j2
cd ..

View File

@ -35,10 +35,20 @@ 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
mkdir build
cd build
cmake .. -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON -DOPT_BUILD_PERSEUS_SOURCE=ON -DOPT_BUILD_RFNM_SOURCE=ON
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
make VERBOSE=1 -j2
cd ..

View File

@ -35,6 +35,7 @@ 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/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/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/hermes_source/hermes_source.dylib
bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/source_modules/limesdr_source/limesdr_source.dylib

View File

@ -24,6 +24,9 @@ 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/fobossdr_source/Release/fobossdr_source.dll sdrpp_windows_x64/modules/
cp 'C:/Program Files/RigExpert/Fobos/bin/fobos.dll' sdrpp_windows_x64/
cp $build_dir/source_modules/hackrf_source/Release/hackrf_source.dll sdrpp_windows_x64/modules/
cp 'C:/Program Files/PothosSDR/bin/hackrf.dll' sdrpp_windows_x64/

View File

@ -324,8 +324,9 @@ Modules in beta are still included in releases for the most part but not enabled
| audio_source | Working | rtaudio | OPT_BUILD_AUDIO_SOURCE | ✅ | ✅ | ✅ |
| bladerf_source | Working | libbladeRF | OPT_BUILD_BLADERF_SOURCE | ⛔ | ✅ (not Debian Buster) | ✅ |
| file_source | Working | - | OPT_BUILD_FILE_SOURCE | ✅ | ✅ | ✅ |
| fobossdr_source | Beta | libfobos | OPT_BUILD_FOBOSSDR_SOURCE | ✅ | ✅ | ✅ |
| hackrf_source | Working | libhackrf | OPT_BUILD_HACKRF_SOURCE | ✅ | ✅ | ✅ |
| harogic_source | Unfinished | htra_api | OPT_BUILD_HAROGIC_SOURCE | ⛔ | ⛔ | |
| harogic_source | Beta | htra_api | OPT_BUILD_HAROGIC_SOURCE | ⛔ | ⛔ | |
| hermes_source | Beta | - | OPT_BUILD_HERMES_SOURCE | ✅ | ✅ | ✅ |
| limesdr_source | Working | liblimesuite | OPT_BUILD_LIMESDR_SOURCE | ⛔ | ✅ | ✅ |
| network_source | Unfinished | - | OPT_BUILD_NETWORK_SOURCE | ✅ | ✅ | ⛔ |
@ -339,9 +340,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 | ✅ | ✅ | ✅ |
| soapy_source | Deprecated | soapysdr | OPT_BUILD_SOAPY_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 | ✅ | ✅ | ✅ |
| usrp_source | Beta | libuhd | OPT_BUILD_USRP_SOURCE | ⛔ | ⛔ | |
| usrp_source | Beta | libuhd | OPT_BUILD_USRP_SOURCE | ⛔ | ⛔ | |
## Sinks
@ -358,6 +359,7 @@ Modules in beta are still included in releases for the most part but not enabled
| Name | Stage | Dependencies | Option | Built by default| Built in Release | Enabled in SDR++ by default |
|---------------------|------------|--------------|-------------------------------|:---------------:|:----------------:|:---------------------------:|
| atv_decoder | Unfinished | - | OPT_BUILD_ATV_DECODER | ⛔ | ⛔ | ⛔ |
| dab_decoder | Unfinished | - | OPT_BUILD_DAB_DECODER | ⛔ | ⛔ | ⛔ |
| falcon9_decoder | Unfinished | ffplay | OPT_BUILD_FALCON9_DECODER | ⛔ | ⛔ | ⛔ |
| kgsstv_decoder | Unfinished | - | OPT_BUILD_KGSSTV_DECODER | ⛔ | ⛔ | ⛔ |
| m17_decoder | Working | - | OPT_BUILD_M17_DECODER | ⛔ | ✅ | ⛔ |

View File

@ -3,7 +3,7 @@ Encoding=UTF-8
Version=1.0
Type=Application
Terminal=false
Exec=@SDRPP_BIN_INSTALL_DIR@/sdrpp
Exec=@CMAKE_INSTALL_PREFIX@/bin/sdrpp
Name=SDR++
Icon=@SDRPP_RES_INSTALL_DIR@/icons/sdrpp.png
Icon=@CMAKE_INSTALL_PREFIX@/share/sdrpp/icons/sdrpp.png
Categories=HamRadio

View File

@ -6,10 +6,6 @@ if (NOT SDRPP_MODULE_COMPILER_FLAGS)
set(SDRPP_MODULE_COMPILER_FLAGS @SDRPP_MODULE_COMPILER_FLAGS@)
endif ()
# Add compiler definitions for the directories
add_definitions(-DSDRPP_MODULES_LOAD_DIR="${SDRPP_MODULES_LOAD_DIR}")
add_definitions(-DSDRPP_RES_LOAD_DIR="${SDRPP_RES_LOAD_DIR}")
# Created shared lib and link to core
add_library(${PROJECT_NAME} SHARED ${SRC})
target_link_libraries(${PROJECT_NAME} PRIVATE sdrpp_core)
@ -20,4 +16,4 @@ set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "")
target_compile_options(${PROJECT_NAME} PRIVATE ${SDRPP_MODULE_COMPILER_FLAGS})
# Install directives
install(TARGETS ${PROJECT_NAME} DESTINATION ${SDRPP_MODULES_INSTALL_DIR})
install(TARGETS ${PROJECT_NAME} DESTINATION lib/sdrpp/plugins)

View File

@ -217,14 +217,19 @@ private:
}
void startServer() {
if (modeId == SINK_MODE_TCP) {
listener = net::listen(hostname, port);
if (listener) {
listener->acceptAsync(clientHandler, this);
try {
if (modeId == SINK_MODE_TCP) {
listener = net::listen(hostname, port);
if (listener) {
listener->acceptAsync(clientHandler, this);
}
}
else {
conn = net::openUDP("0.0.0.0", port, hostname, port, false);
}
}
else {
conn = net::openUDP("0.0.0.0", port, hostname, port, false);
catch (const std::exception& e) {
flog::error("Failed to open socket: {}", e.what());
}
}

View File

@ -0,0 +1,21 @@
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 ()

View File

@ -0,0 +1,560 @@
#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();
}

View File

@ -523,8 +523,8 @@ private:
RTLSDRSourceModule* _this = (RTLSDRSourceModule*)ctx;
int sampCount = len / 2;
for (int i = 0; i < sampCount; i++) {
_this->stream.writeBuf[i].re = ((float)buf[i * 2] - 127.4f) / 128.0f;
_this->stream.writeBuf[i].im = ((float)buf[(i * 2) + 1] - 127.4f) / 128.0f;
_this->stream.writeBuf[i].re = ((float)buf[i * 2] - 127.4) / 128.0f;
_this->stream.writeBuf[i].im = ((float)buf[(i * 2) + 1] - 127.4) / 128.0f;
}
if (!_this->stream.swap(sampCount)) { return; }
}