diff --git a/.github/workflows/build_all.yml b/.github/workflows/build_all.yml index a66c402d..9c6623e2 100644 --- a/.github/workflows/build_all.yml +++ b/.github/workflows/build_all.yml @@ -43,7 +43,7 @@ jobs: - name: Prepare CMake working-directory: ${{runner.workspace}}/build - run: cmake "$Env:GITHUB_WORKSPACE" "-DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake" -DOPT_BUILD_SDRPLAY_SOURCE=ON + run: cmake "$Env:GITHUB_WORKSPACE" "-DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake" -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON - name: Build working-directory: ${{runner.workspace}}/build diff --git a/CMakeLists.txt b/CMakeLists.txt index c66384bb..25834788 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,82 +7,101 @@ else() set(CMAKE_INSTALL_PREFIX "/usr") endif() - -option(OPT_BUILD_RTL_TCP_SOURCE "Build RTL-TCP Source Module (no dependencies required)" ON) -option(OPT_BUILD_SPYSERVER_SOURCE "Build SpyServer Source Module (no dependencies required)" OFF) -option(OPT_BUILD_SOAPY_SOURCE "Build SoapySDR Source Module (Depedencies: soapysdr)" ON) -option(OPT_BUILD_AIRSPYHF_SOURCE "Build Airspy HF+ Source Module (Depedencies: libairspyhf)" ON) +# Sources option(OPT_BUILD_AIRSPY_SOURCE "Build Airspy Source Module (Depedencies: libairspy)" ON) -option(OPT_BUILD_BLADERF_SOURCE "Build BladeRF Source Module (Depedencies: libbladeRF)" ON) -option(OPT_BUILD_SDRPLAY_SOURCE "Build SDRplay Source Module (Depedencies: libsdrplay)" OFF) -option(OPT_BUILD_PLUTOSDR_SOURCE "Build PlutoSDR Source Module (Depedencies: libiio, libad9361)" ON) +option(OPT_BUILD_AIRSPYHF_SOURCE "Build Airspy HF+ Source Module (Depedencies: libairspyhf)" ON) +option(OPT_BUILD_BLADERF_SOURCE "Build BladeRF Source Module (Depedencies: libbladeRF)" OFF) +option(OPT_BUILD_FILE_SOURCE "Wav file source" ON) option(OPT_BUILD_HACKRF_SOURCE "Build HackRF Source Module (Depedencies: libhackrf)" ON) -option(OPT_BUILD_RTL_SDR_SOURCE "Build RTL-SDR Source Module (Depedencies: librtlsdr)" ON) +option(OPT_BUILD_LIMESDR_SOURCE "Build LimeSDR Source Module (Depedencies: liblimesuite)" OFF) option(OPT_BUILD_SDDC_SOURCE "Build SDDC Source Module (Depedencies: libusb-1.0)" OFF) +option(OPT_BUILD_RTL_SDR_SOURCE "Build RTL-SDR Source Module (Depedencies: librtlsdr)" ON) +option(OPT_BUILD_RTL_TCP_SOURCE "Build RTL-TCP Source Module (no dependencies required)" ON) +option(OPT_BUILD_SDRPLAY_SOURCE "Build SDRplay Source Module (Depedencies: libsdrplay)" OFF) +option(OPT_BUILD_SOAPY_SOURCE "Build SoapySDR Source Module (Depedencies: soapysdr)" ON) +option(OPT_BUILD_SPYSERVER_SOURCE "Build SpyServer Source Module (no dependencies required)" OFF) +option(OPT_BUILD_PLUTOSDR_SOURCE "Build PlutoSDR Source Module (Depedencies: libiio, libad9361)" ON) + +# Sinks option(OPT_BUILD_AUDIO_SINK "Build Audio Sink Module (Depedencies: rtaudio)" ON) + +# Decoders option(OPT_BUILD_FALCON9_DECODER "Build the falcon9 live decoder (Dependencies: ffplay)" OFF) option(OPT_BUILD_METEOR_DEMODULATOR "Build the meteor demodulator module (no dependencies required)" ON) +option(OPT_BUILD_RADIO "Main audio modulation decoder (AM, FM, SSB, etc...)" ON) option(OPT_BUILD_WEATHER_SAT_DECODER "Build the HRPT decoder module (no dependencies required)" ON) + +# Misc option(OPT_BUILD_DISCORD_PRESENCE "Build the Discord Rich Presence module" ON) -option(OPT_BUILD_FREQUENCY_MANAGER "Build the Frequency Manager module" ON) +option(OPT_BUILD_FREQUENCY_MANAGER "Build the Frequency Manager module" OFF) +option(OPT_BUILD_RECORDER "Audio and baseband recorder" ON) + # Core of SDR++ add_subdirectory("core") -# Base modules -add_subdirectory("radio") -add_subdirectory("recorder") -add_subdirectory("file_source") # Source modules -if (OPT_BUILD_RTL_TCP_SOURCE) -add_subdirectory("rtl_tcp_source") -endif (OPT_BUILD_RTL_TCP_SOURCE) - -if (OPT_BUILD_SPYSERVER_SOURCE) -add_subdirectory("spyserver_source") -endif (OPT_BUILD_SPYSERVER_SOURCE) - -if (OPT_BUILD_SOAPY_SOURCE) -add_subdirectory("soapy_source") -endif (OPT_BUILD_SOAPY_SOURCE) +if (OPT_BUILD_AIRSPY_SOURCE) +add_subdirectory("airspy_source") +endif (OPT_BUILD_AIRSPY_SOURCE) if (OPT_BUILD_AIRSPYHF_SOURCE) add_subdirectory("airspyhf_source") endif (OPT_BUILD_AIRSPYHF_SOURCE) -if (OPT_BUILD_AIRSPY_SOURCE) -add_subdirectory("airspy_source") -endif (OPT_BUILD_AIRSPY_SOURCE) - if (OPT_BUILD_BLADERF_SOURCE) add_subdirectory("bladerf_source") -endif(OPT_BUILD_BLADERF_SOURCE) +endif (OPT_BUILD_BLADERF_SOURCE) -if (OPT_BUILD_SDRPLAY_SOURCE) -add_subdirectory("sdrplay_source") -endif (OPT_BUILD_SDRPLAY_SOURCE) - -if (OPT_BUILD_PLUTOSDR_SOURCE) -add_subdirectory("plutosdr_source") -endif (OPT_BUILD_PLUTOSDR_SOURCE) +if (OPT_BUILD_FILE_SOURCE) +add_subdirectory("file_source") +endif (OPT_BUILD_FILE_SOURCE) if (OPT_BUILD_HACKRF_SOURCE) add_subdirectory("hackrf_source") endif (OPT_BUILD_HACKRF_SOURCE) -if (OPT_BUILD_RTL_SDR_SOURCE) -add_subdirectory("rtl_sdr_source") -endif (OPT_BUILD_RTL_SDR_SOURCE) +if (OPT_BUILD_LIMESDR_SOURCE) +add_subdirectory("limesdr_source") +endif (OPT_BUILD_LIMESDR_SOURCE) if (OPT_BUILD_SDDC_SOURCE) add_subdirectory("sddc_source") endif (OPT_BUILD_SDDC_SOURCE) +if (OPT_BUILD_RTL_SDR_SOURCE) +add_subdirectory("rtl_sdr_source") +endif (OPT_BUILD_RTL_SDR_SOURCE) + +if (OPT_BUILD_RTL_TCP_SOURCE) +add_subdirectory("rtl_tcp_source") +endif (OPT_BUILD_RTL_TCP_SOURCE) + +if (OPT_BUILD_SDRPLAY_SOURCE) +add_subdirectory("sdrplay_source") +endif (OPT_BUILD_SDRPLAY_SOURCE) + +if (OPT_BUILD_SOAPY_SOURCE) +add_subdirectory("soapy_source") +endif (OPT_BUILD_SOAPY_SOURCE) + +if (OPT_BUILD_SPYSERVER_SOURCE) +add_subdirectory("spyserver_source") +endif (OPT_BUILD_SPYSERVER_SOURCE) + +if (OPT_BUILD_PLUTOSDR_SOURCE) +add_subdirectory("plutosdr_source") +endif (OPT_BUILD_PLUTOSDR_SOURCE) + + +# Sink modules if (OPT_BUILD_AUDIO_SINK) add_subdirectory("audio_sink") endif (OPT_BUILD_AUDIO_SINK) + +# Decoders if (OPT_BUILD_FALCON9_DECODER) add_subdirectory("falcon9_decoder") endif (OPT_BUILD_FALCON9_DECODER) @@ -91,10 +110,16 @@ if (OPT_BUILD_METEOR_DEMODULATOR) add_subdirectory("meteor_demodulator") endif (OPT_BUILD_METEOR_DEMODULATOR) +if (OPT_BUILD_RADIO) +add_subdirectory("radio") +endif (OPT_BUILD_RADIO) + if (OPT_BUILD_WEATHER_SAT_DECODER) add_subdirectory("weather_sat_decoder") endif (OPT_BUILD_WEATHER_SAT_DECODER) + +# Misc if (OPT_BUILD_DISCORD_PRESENCE) add_subdirectory("discord_integration") endif (OPT_BUILD_DISCORD_PRESENCE) @@ -103,6 +128,11 @@ if (OPT_BUILD_FREQUENCY_MANAGER) add_subdirectory("frequency_manager") endif (OPT_BUILD_FREQUENCY_MANAGER) +if (OPT_BUILD_RECORDER) +add_subdirectory("recorder") +endif (OPT_BUILD_RECORDER) + + if (MSVC) set(CMAKE_CXX_FLAGS "-O2 /std:c++17 /EHsc") elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang") diff --git a/bladerf_source/src/main.cpp b/bladerf_source/src/main.cpp index c644fe7c..bda4cddf 100644 --- a/bladerf_source/src/main.cpp +++ b/bladerf_source/src/main.cpp @@ -92,6 +92,7 @@ public: void selectFirst() { if (devCount > 0) { selectByInfo(&devInfoList[0]); } + else { selectedSerial = ""; } } void selectBySerial(std::string serial, bool reloadChannelId = true) { diff --git a/core/src/core.cpp b/core/src/core.cpp index 82e59fc9..5333f309 100644 --- a/core/src/core.cpp +++ b/core/src/core.cpp @@ -154,20 +154,25 @@ int sdrpp_main(int argc, char *argv[]) { defConfig["min"] = -120.0; // Module instances - defConfig["moduleInstances"]["Radio"] = "radio"; - defConfig["moduleInstances"]["Recorder"] = "recorder"; + defConfig["moduleInstances"]["Airspy Source"] = "airspy_source"; + defConfig["moduleInstances"]["AirspyHF+ Source"] = "airspyhf_source"; + defConfig["moduleInstances"]["BladeRF Source"] = "bladerf_source"; + defConfig["moduleInstances"]["File Source"] = "file_source"; + defConfig["moduleInstances"]["HackRF Source"] = "hackrf_source"; + defConfig["moduleInstances"]["LimeSDR Source"] = "limesdr_source"; + defConfig["moduleInstances"]["RTL-SDR Source"] = "rtl_sdr_source"; + defConfig["moduleInstances"]["RTL-TCP Source"] = "rtl_tcp_source"; + defConfig["moduleInstances"]["SDRplay Source"] = "sdrplay_source"; defConfig["moduleInstances"]["SoapySDR Source"] = "soapy_source"; defConfig["moduleInstances"]["PlutoSDR Source"] = "plutosdr_source"; - defConfig["moduleInstances"]["BladeRF Source"] = "bladerf_source"; - defConfig["moduleInstances"]["HackRF Source"] = "hackrf_source"; - defConfig["moduleInstances"]["RTL-TCP Source"] = "rtl_tcp_source"; - defConfig["moduleInstances"]["RTL-SDR Source"] = "rtl_sdr_source"; - defConfig["moduleInstances"]["AirspyHF+ Source"] = "airspyhf_source"; - defConfig["moduleInstances"]["Airspy Source"] = "airspy_source"; - defConfig["moduleInstances"]["File Source"] = "file_source"; - defConfig["moduleInstances"]["SDRplay Source"] = "sdrplay_source"; + defConfig["moduleInstances"]["Audio Sink"] = "audio_sink"; + defConfig["moduleInstances"]["Radio"] = "radio"; + + defConfig["moduleInstances"]["Recorder"] = "recorder"; + + // Themes defConfig["theme"] = "Dark"; diff --git a/docker_builds/debian_bullseye/do_build.sh b/docker_builds/debian_bullseye/do_build.sh index 9cef61c3..dcb196a5 100644 --- a/docker_builds/debian_bullseye/do_build.sh +++ b/docker_builds/debian_bullseye/do_build.sh @@ -4,7 +4,7 @@ cd /root # Install dependencies and tools apt update -apt install -y build-essential cmake git libfftw3-dev libglfw3-dev libglew-dev libvolk2-dev libsoapysdr-dev libairspyhf-dev libairspy-dev libiio-dev libad9361-dev librtaudio-dev libhackrf-dev librtlsdr-dev libbladerf-dev p7zip-full wget +apt install -y build-essential cmake git libfftw3-dev libglfw3-dev libglew-dev libvolk2-dev libsoapysdr-dev libairspyhf-dev libairspy-dev libiio-dev libad9361-dev librtaudio-dev libhackrf-dev librtlsdr-dev libbladerf-dev liblimesuite-dev p7zip-full wget # Install SDRPlay libraries wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.07.1.run @@ -18,7 +18,7 @@ git clone https://github.com/AlexandreRouma/SDRPlusPlus cd SDRPlusPlus mkdir build cd build -cmake .. -DOPT_BUILD_SDRPLAY_SOURCE=ON +cmake .. -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON make -j2 cd .. diff --git a/docker_builds/debian_buster/do_build.sh b/docker_builds/debian_buster/do_build.sh index 8f0af05b..c29d34e0 100644 --- a/docker_builds/debian_buster/do_build.sh +++ b/docker_builds/debian_buster/do_build.sh @@ -4,7 +4,7 @@ cd /root # Install dependencies and tools apt update -apt install -y build-essential cmake git libfftw3-dev libglfw3-dev libglew-dev libvolk1-dev libsoapysdr-dev libairspyhf-dev libairspy-dev libiio-dev libad9361-dev librtaudio-dev libhackrf-dev librtlsdr-dev libbladerf-dev p7zip-full wget +apt install -y build-essential cmake git libfftw3-dev libglfw3-dev libglew-dev libvolk1-dev libsoapysdr-dev libairspyhf-dev libairspy-dev libiio-dev libad9361-dev librtaudio-dev libhackrf-dev librtlsdr-dev libbladerf-dev liblimesuite-dev p7zip-full wget # Install SDRPlay libraries wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.07.1.run @@ -18,7 +18,7 @@ git clone https://github.com/AlexandreRouma/SDRPlusPlus cd SDRPlusPlus mkdir build cd build -cmake .. -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_BLADERF_SOURCE=OFF +cmake .. -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_BLADERF_SOURCE=OFF -DOPT_BUILD_LIMESDR_SOURCE=ON make -j2 cd .. diff --git a/docker_builds/debian_sid/do_build.sh b/docker_builds/debian_sid/do_build.sh index 9cef61c3..dcb196a5 100644 --- a/docker_builds/debian_sid/do_build.sh +++ b/docker_builds/debian_sid/do_build.sh @@ -4,7 +4,7 @@ cd /root # Install dependencies and tools apt update -apt install -y build-essential cmake git libfftw3-dev libglfw3-dev libglew-dev libvolk2-dev libsoapysdr-dev libairspyhf-dev libairspy-dev libiio-dev libad9361-dev librtaudio-dev libhackrf-dev librtlsdr-dev libbladerf-dev p7zip-full wget +apt install -y build-essential cmake git libfftw3-dev libglfw3-dev libglew-dev libvolk2-dev libsoapysdr-dev libairspyhf-dev libairspy-dev libiio-dev libad9361-dev librtaudio-dev libhackrf-dev librtlsdr-dev libbladerf-dev liblimesuite-dev p7zip-full wget # Install SDRPlay libraries wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.07.1.run @@ -18,7 +18,7 @@ git clone https://github.com/AlexandreRouma/SDRPlusPlus cd SDRPlusPlus mkdir build cd build -cmake .. -DOPT_BUILD_SDRPLAY_SOURCE=ON +cmake .. -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON make -j2 cd .. diff --git a/docker_builds/ubuntu_focal/do_build.sh b/docker_builds/ubuntu_focal/do_build.sh index 9cef61c3..dcb196a5 100644 --- a/docker_builds/ubuntu_focal/do_build.sh +++ b/docker_builds/ubuntu_focal/do_build.sh @@ -4,7 +4,7 @@ cd /root # Install dependencies and tools apt update -apt install -y build-essential cmake git libfftw3-dev libglfw3-dev libglew-dev libvolk2-dev libsoapysdr-dev libairspyhf-dev libairspy-dev libiio-dev libad9361-dev librtaudio-dev libhackrf-dev librtlsdr-dev libbladerf-dev p7zip-full wget +apt install -y build-essential cmake git libfftw3-dev libglfw3-dev libglew-dev libvolk2-dev libsoapysdr-dev libairspyhf-dev libairspy-dev libiio-dev libad9361-dev librtaudio-dev libhackrf-dev librtlsdr-dev libbladerf-dev liblimesuite-dev p7zip-full wget # Install SDRPlay libraries wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.07.1.run @@ -18,7 +18,7 @@ git clone https://github.com/AlexandreRouma/SDRPlusPlus cd SDRPlusPlus mkdir build cd build -cmake .. -DOPT_BUILD_SDRPLAY_SOURCE=ON +cmake .. -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON make -j2 cd .. diff --git a/docker_builds/ubuntu_groovy/do_build.sh b/docker_builds/ubuntu_groovy/do_build.sh index 9cef61c3..dcb196a5 100644 --- a/docker_builds/ubuntu_groovy/do_build.sh +++ b/docker_builds/ubuntu_groovy/do_build.sh @@ -4,7 +4,7 @@ cd /root # Install dependencies and tools apt update -apt install -y build-essential cmake git libfftw3-dev libglfw3-dev libglew-dev libvolk2-dev libsoapysdr-dev libairspyhf-dev libairspy-dev libiio-dev libad9361-dev librtaudio-dev libhackrf-dev librtlsdr-dev libbladerf-dev p7zip-full wget +apt install -y build-essential cmake git libfftw3-dev libglfw3-dev libglew-dev libvolk2-dev libsoapysdr-dev libairspyhf-dev libairspy-dev libiio-dev libad9361-dev librtaudio-dev libhackrf-dev librtlsdr-dev libbladerf-dev liblimesuite-dev p7zip-full wget # Install SDRPlay libraries wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.07.1.run @@ -18,7 +18,7 @@ git clone https://github.com/AlexandreRouma/SDRPlusPlus cd SDRPlusPlus mkdir build cd build -cmake .. -DOPT_BUILD_SDRPLAY_SOURCE=ON +cmake .. -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON make -j2 cd .. diff --git a/docker_builds/ubuntu_hirsute/do_build.sh b/docker_builds/ubuntu_hirsute/do_build.sh index 9cef61c3..38b418b1 100644 --- a/docker_builds/ubuntu_hirsute/do_build.sh +++ b/docker_builds/ubuntu_hirsute/do_build.sh @@ -4,7 +4,7 @@ cd /root # Install dependencies and tools apt update -apt install -y build-essential cmake git libfftw3-dev libglfw3-dev libglew-dev libvolk2-dev libsoapysdr-dev libairspyhf-dev libairspy-dev libiio-dev libad9361-dev librtaudio-dev libhackrf-dev librtlsdr-dev libbladerf-dev p7zip-full wget +apt install -y build-essential cmake git libfftw3-dev libglfw3-dev libglew-dev libvolk2-dev libsoapysdr-dev libairspyhf-dev libairspy-dev libiio-dev libad9361-dev librtaudio-dev libhackrf-dev librtlsdr-dev libbladerf-dev liblimesuit-dev p7zip-full wget # Install SDRPlay libraries wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.07.1.run @@ -18,7 +18,7 @@ git clone https://github.com/AlexandreRouma/SDRPlusPlus cd SDRPlusPlus mkdir build cd build -cmake .. -DOPT_BUILD_SDRPLAY_SOURCE=ON +cmake .. -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON make -j2 cd .. diff --git a/limesdr_source/CMakeLists.txt b/limesdr_source/CMakeLists.txt new file mode 100644 index 00000000..b40e5cbd --- /dev/null +++ b/limesdr_source/CMakeLists.txt @@ -0,0 +1,38 @@ +cmake_minimum_required(VERSION 3.13) +project(limesdr_source) + +if (MSVC) + set(CMAKE_CXX_FLAGS "-O2 /std:c++17 /EHsc") +elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang") + set(CMAKE_CXX_FLAGS "-O3 -std=c++17 -Wno-unused-command-line-argument -undefined dynamic_lookup") +else () + set(CMAKE_CXX_FLAGS "-O3 -std=c++17") +endif () + +include_directories("src/") + +file(GLOB SRC "src/*.cpp") + +add_library(limesdr_source SHARED ${SRC}) +target_link_libraries(limesdr_source PRIVATE sdrpp_core) +set_target_properties(limesdr_source PROPERTIES PREFIX "") + +if (MSVC) + # Lib path + target_link_directories(limesdr_source PUBLIC "C:/Program Files/PothosSDR/lib") + + target_link_libraries(limesdr_source PUBLIC LimeSuite) +else (MSVC) + find_package(PkgConfig) + + # Not in pkg-config + target_link_libraries(limesdr_source PUBLIC LimeSuite) + + # Include it because for some reason pkgconfig doesn't look here? + if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + target_include_directories(airspyhf_source PUBLIC "/usr/local/include") + endif() +endif () + +# Install directives +install(TARGETS limesdr_source DESTINATION lib/sdrpp/plugins) \ No newline at end of file diff --git a/limesdr_source/src/main.cpp b/limesdr_source/src/main.cpp new file mode 100644 index 00000000..0b41978d --- /dev/null +++ b/limesdr_source/src/main.cpp @@ -0,0 +1,538 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define CONCAT(a, b) ((std::string(a) + b).c_str()) + +SDRPP_MOD_INFO { + /* Name: */ "limesdr_source", + /* Description: */ "LimeSDR source module for SDR++", + /* Author: */ "Ryzerth", + /* Version: */ 0, 1, 0, + /* Max instances */ 1 +}; + +ConfigManager config; + +class LimeSDRSourceModule : public ModuleManager::Instance { +public: + LimeSDRSourceModule(std::string name) { + this->name = name; + + // Init limesuite if needed + + sampleRate = 10000000.0; + + handler.ctx = this; + handler.selectHandler = menuSelected; + handler.deselectHandler = menuDeselected; + handler.menuHandler = menuHandler; + handler.startHandler = start; + handler.stopHandler = stop; + handler.tuneHandler = tune; + handler.stream = &stream; + + refresh(); + + // Select device from config + selectFirst(); + core::setInputSampleRate(sampleRate); + + sigpath::sourceManager.registerSource("LimeSDR", &handler); + } + + ~LimeSDRSourceModule() { + // Exit limesuite if needed + } + + void enable() { + enabled = true; + } + + void disable() { + enabled = false; + } + + bool isEnabled() { + return enabled; + } + + void refresh() { + devCount = LMS_GetDeviceList(devList); + char buf[256]; + devListTxt = ""; + + for (int i = 0; i < devCount; i++) { + lms_device_t* dev = NULL; + LMS_Open(&dev, devList[i], NULL); + const lms_dev_info_t* info = LMS_GetDeviceInfo(dev); + sprintf(buf, "%s [%" PRIX64 "]", info->deviceName, info->boardSerialNumber); + LMS_Close(dev); + + devNames.push_back(buf); + devListTxt += buf; + devListTxt += '\0'; + } + } + + void selectFirst() { + if (devCount > 0) { + selectByInfoStr(devList[0]); + return; + } + selectedDevName = ""; + } + + void selectByName(std::string name) { + for (int i = 0; i < devCount; i++) { + if (devNames[i] == name) { + selectByInfoStr(devList[i]); + break; + } + } + selectFirst(); + } + + void selectByInfoStr(lms_info_str_t info) { + if (devCount == 0) { + selectedDevName = ""; + return; + } + + // Set devId and selectedDevNames + for (int i = 0; i < devCount; i++) { + if (info == devList[i]) { + devId = i; + selectedDevName = devNames[i]; + break; + } + } + + lms_device_t* dev = NULL; + LMS_Open(&dev, info, NULL); + + channelCount = LMS_GetNumChannels(dev, false); + char buf[32]; + for (int i = 0; i < channelCount; i++) { + sprintf(buf, "CH %d", i+1); + channelNamesTxt += buf; + channelNamesTxt += '\0'; + } + + config.aquire(); + if (config.conf["devices"].contains(selectedDevName)) { + if (config.conf["devices"][selectedDevName].contains("channel")) { + chanId = config.conf["devices"][selectedDevName]["channel"]; + } + else { chanId = 0; } + } + else { chanId = 0; } + config.release(); + + chanId = std::clamp(chanId, 0, channelCount - 1); + + // List antennas + lms_name_t antennaNames[16]; + antennaCount = LMS_GetAntennaList(dev, false, chanId, antennaNames); + for (int i = 0; i < antennaCount; i++) { + antennaNameList.push_back(antennaNames[i]); + antennaListTxt += antennaNames[i]; + antennaListTxt += '\0'; + } + + // List supported sample rates + lms_range_t srRange; + LMS_GetSampleRateRange(dev, false, &srRange); + sampleRates.push_back(srRange.min); + sampleRatesTxt += getBandwdithScaled(srRange.min); + sampleRatesTxt += '\0'; + for (int i = 1000000; i < srRange.max; i += 1000000) { + sampleRates.push_back(i); + sampleRatesTxt += getBandwdithScaled(i); + sampleRatesTxt += '\0'; + } + sampleRates.push_back(srRange.max); + sampleRatesTxt += getBandwdithScaled(srRange.max); + sampleRatesTxt += '\0'; + + // List supported bandwidths + lms_range_t bwRange; + LMS_GetLPFBWRange(dev, false, &bwRange); + spdlog::warn("bw step {0}", bwRange.step); + bandwidths.push_back(bwRange.min); + bandwidthsTxt += getBandwdithScaled(bwRange.min); + bandwidthsTxt += '\0'; + for (int i = 2000000; i < bwRange.max; i += 1000000) { + bandwidths.push_back(i); + bandwidthsTxt += getBandwdithScaled(i); + bandwidthsTxt += '\0'; + } + bandwidths.push_back(bwRange.max); + bandwidthsTxt += getBandwdithScaled(bwRange.max); + bandwidthsTxt += '\0'; + bandwidthsTxt += "Auto"; + bandwidthsTxt += '\0'; + + config.aquire(); + + if (!config.conf["devices"].contains(selectedDevName)) { + config.conf["devices"][selectedDevName]["sampleRate"] = sampleRates[0]; + config.conf["devices"][selectedDevName]["channel"] = 0; + config.conf["devices"][selectedDevName]["antenna"] = "LNAW"; + config.conf["devices"][selectedDevName]["bandwidth"] = bandwidths.size(); + config.conf["devices"][selectedDevName]["gain"] = 0; + } + + // Load sample rate + if (config.conf["devices"][selectedDevName].contains("sampleRate")) { + bool found = false; + int sr = config.conf["devices"][selectedDevName]["sampleRate"]; + for (int i = 0; i < sampleRates.size(); i++) { + if (sr == sampleRates[i]) { + srId = i; + sampleRate = sampleRates[i]; + found = true; + break; + } + } + if (!found) { + srId = 0; + sampleRate = sampleRates[0]; + } + } + else { + srId = 0; + sampleRate = sampleRates[0]; + } + + // Load antenna + if (config.conf["devices"][selectedDevName].contains("antenna")) { + std::string antName = config.conf["devices"][selectedDevName]["antenna"]; + bool found = false; + for (int i = 0; i < antennaCount; i++) { + if (antennaNames[i] == antName) { + antennaId = i; + found = true; + break; + } + } + if (!found) { + for (int i = 0; i < antennaCount; i++) { + if (antennaNames[i] == "LNAW") { + antennaId = i; + found = true; + break; + } + } + if (!found) { antennaId = 0; } + } + } + else { + bool found = false; + for (int i = 0; i < antennaCount; i++) { + if (antennaNames[i] == "LNAW") { + antennaId = i; + found = true; + break; + } + } + if (!found) { antennaId = 0; } + } + + // Load bandwidth + if (config.conf["devices"][selectedDevName].contains("bandwidth")) { + bwId = config.conf["devices"][selectedDevName]["bandwidth"]; + bwId = std::clamp(bwId, 0, bandwidths.size()); + } + else { + bwId = bandwidths.size(); + } + + // Load gain + if (config.conf["devices"][selectedDevName].contains("gain")) { + gain = config.conf["devices"][selectedDevName]["bandwidth"]; + gain = std::clamp(bwId, 0, 73); + } + else { + gain = 0; + } + + config.release(true); + + LMS_Close(dev); + } + +private: + std::string getBandwdithScaled(double bw) { + char buf[1024]; + if (bw >= 1000000.0) { + sprintf(buf, "%.1lfMHz", bw / 1000000.0); + } + else if (bw >= 1000.0) { + sprintf(buf, "%.1lfKHz", bw / 1000.0); + } + else { + sprintf(buf, "%.1lfHz", bw); + } + return std::string(buf); + } + + int getBestBandwidth(int sampleRate) { + for (int i = 0; i < bandwidths.size(); i++) { + if (bandwidths[i] >= sampleRate) { + spdlog::warn("Selected bandwidth is {0}", bandwidths[i]); + return bandwidths[i]; + } + } + return bandwidths[bandwidths.size()-1]; + } + + static void menuSelected(void* ctx) { + LimeSDRSourceModule* _this = (LimeSDRSourceModule*)ctx; + core::setInputSampleRate(_this->sampleRate); + spdlog::info("LimeSDRSourceModule '{0}': Menu Select!", _this->name); + } + + static void menuDeselected(void* ctx) { + LimeSDRSourceModule* _this = (LimeSDRSourceModule*)ctx; + spdlog::info("LimeSDRSourceModule '{0}': Menu Deselect!", _this->name); + } + + static void start(void* ctx) { + LimeSDRSourceModule* _this = (LimeSDRSourceModule*)ctx; + if (_this->running) { + return; + } + + // Open device + _this->openDev = NULL; + LMS_Open(&_this->openDev, _this->devList[_this->devId], NULL); + LMS_Init(_this->openDev); + + spdlog::warn("Channel count: {0}", LMS_GetNumChannels(_this->openDev, false)); + + // Set options + LMS_EnableChannel(_this->openDev, false, _this->chanId, true); + LMS_SetSampleRate(_this->openDev, _this->sampleRate, 0); + LMS_SetLOFrequency(_this->openDev, false, _this->chanId, _this->freq); + LMS_SetGaindB(_this->openDev, false, _this->chanId, _this->gain); + LMS_SetLPFBW(_this->openDev, false, _this->chanId, (_this->bwId == _this->bandwidths.size()) ? _this->getBestBandwidth(_this->sampleRate) : _this->bandwidths[_this->bwId]); + LMS_SetLPF(_this->openDev, false, _this->chanId, true); + + // Setup and start stream + int sampCount = _this->sampleRate / 200; + _this->devStream.isTx = false; + _this->devStream.channel = 0; + _this->devStream.fifoSize = sampCount; // TODO: Check what it's actually supposed to be + _this->devStream.throughputVsLatency = 0.5f; + _this->devStream.dataFmt = _this->devStream.LMS_FMT_F32; + LMS_SetupStream(_this->openDev, &_this->devStream); + + // Start stream + _this->streamRunning = true; + LMS_StartStream(&_this->devStream); + _this->workerThread = std::thread(&LimeSDRSourceModule::worker, _this); + + + _this->running = true; + spdlog::info("LimeSDRSourceModule '{0}': Start!", _this->name); + } + + static void stop(void* ctx) { + LimeSDRSourceModule* _this = (LimeSDRSourceModule*)ctx; + if (!_this->running) { + return; + } + _this->running = false; + + _this->streamRunning = false; + if (_this->workerThread.joinable()) { _this->workerThread.join(); } + + LMS_StopStream(&_this->devStream); + LMS_DestroyStream(_this->openDev, &_this->devStream); + + LMS_Close(_this->openDev); + + spdlog::info("LimeSDRSourceModule '{0}': Stop!", _this->name); + } + + static void tune(double freq, void* ctx) { + LimeSDRSourceModule* _this = (LimeSDRSourceModule*)ctx; + _this->freq = freq; + if (_this->running) { + LMS_SetLOFrequency(_this->openDev, false, _this->chanId, freq); + } + spdlog::info("LimeSDRSourceModule '{0}': Tune: {1}!", _this->name, freq); + } + + static void menuHandler(void* ctx) { + LimeSDRSourceModule* _this = (LimeSDRSourceModule*)ctx; + float menuWidth = ImGui::GetContentRegionAvailWidth(); + + if (_this->running) { style::beginDisabled(); } + + ImGui::SetNextItemWidth(menuWidth); + if (ImGui::Combo("##limesdr_dev_sel", &_this->devId, _this->devListTxt.c_str())) { + _this->selectByInfoStr(_this->devList[_this->devId]); + core::setInputSampleRate(_this->sampleRate); + config.aquire(); + config.conf["device"] = _this->selectedDevName; + config.release(true); + } + + if (ImGui::Combo(CONCAT("##_limesdr_sr_sel_", _this->name), &_this->srId, _this->sampleRatesTxt.c_str())) { + _this->sampleRate = _this->sampleRates[_this->srId]; + core::setInputSampleRate(_this->sampleRate); + if (_this->selectedDevName != "") { + config.aquire(); + config.conf["devices"][_this->selectedDevName]["sampleRate"] = _this->sampleRates[_this->srId]; + config.release(true); + } + } + + // Refresh button + ImGui::SameLine(); + float refreshBtnWdith = menuWidth - ImGui::GetCursorPosX(); + if (ImGui::Button(CONCAT("Refresh##_limesdr_refr_", _this->name), ImVec2(refreshBtnWdith, 0))) { + _this->refresh(); + _this->selectByName(_this->selectedDevName); + core::setInputSampleRate(_this->sampleRate); + } + + if (_this->channelCount > 1) { + ImGui::Text("RX Channel"); + ImGui::SameLine(); + ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); + ImGui::Combo("##limesdr_ch_sel", &_this->chanId, _this->channelNamesTxt.c_str()); + if (_this->selectedDevName != "") { + config.aquire(); + config.conf["devices"][_this->selectedDevName]["channel"] = _this->chanId; + config.release(true); + } + } + + if (_this->running) { style::endDisabled(); } + + ImGui::Text("Antenna"); + ImGui::SameLine(); + ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); + if (ImGui::Combo("##limesdr_ant_sel", &_this->antennaId, _this->antennaListTxt.c_str())) { + if (_this->running) { + LMS_SetAntenna(_this->openDev, false, _this->chanId, _this->antennaId); + } + if (_this->selectedDevName != "") { + config.aquire(); + config.conf["devices"][_this->selectedDevName]["antenna"] = _this->antennaNameList[_this->antennaId]; + config.release(true); + } + } + + ImGui::Text("Bandwidth"); + ImGui::SameLine(); + ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); + if (ImGui::Combo("##limesdr_bw_sel", &_this->bwId, _this->bandwidthsTxt.c_str())) { + if (_this->running) { + LMS_SetLPFBW(_this->openDev, false, _this->chanId, (_this->bwId == _this->bandwidths.size()) ? _this->getBestBandwidth(_this->sampleRate) : _this->bandwidths[_this->bwId]); + } + if (_this->selectedDevName != "") { + config.aquire(); + config.conf["devices"][_this->selectedDevName]["bandwidth"] = _this->bwId; + config.release(true); + } + } + + ImGui::Text("Gain"); + ImGui::SameLine(); + ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); + if (ImGui::SliderInt("##limesdr_gain_sel", &_this->gain, 0, 73, "%ddB")) { + if (_this->running) { + LMS_SetGaindB(_this->openDev, false, _this->chanId, _this->gain); + } + if (_this->selectedDevName != "") { + config.aquire(); + config.conf["devices"][_this->selectedDevName]["gain"] = _this->gain; + config.release(true); + } + } + } + + void worker() { + int sampCount = sampleRate / 200; + lms_stream_meta_t meta; + while (streamRunning) { + int ret = LMS_RecvStream(&devStream, stream.writeBuf, sampCount, &meta, 1000); + if (!stream.swap(sampCount) || ret < 0) { break; } + } + } + + std::string name; + dsp::stream stream; + double sampleRate; + SourceManager::SourceHandler handler; + bool running = false; + bool enabled = true; + bool streamRunning = false; + double freq; + + int channelCount = 0; + + int devId = 0; + int chanId = 0; + int srId = 0; + int bwId = 0; + int gain = 0; + + std::vector sampleRates; + std::string sampleRatesTxt; + std::vector bandwidths; + std::string bandwidthsTxt; + + lms_info_str_t devList[128]; + int devCount = 0; + std::string devListTxt; + std::vector devNames; + std::string selectedDevName; + + lms_device_t* openDev; + + lms_stream_t devStream; + + std::string channelNamesTxt; + + int antennaId = 0; + std::string antennaListTxt; + std::vector antennaNameList; + int antennaCount = 0; + + std::thread workerThread; +}; + +MOD_EXPORT void _INIT_() { + json def = json({}); + def["devices"] = json({}); + def["device"] = ""; + config.setPath(options::opts.root + "/limesdr_config.json"); + config.load(def); + config.enableAutoSave(); +} + +MOD_EXPORT ModuleManager::Instance* _CREATE_INSTANCE_(std::string name) { + return new LimeSDRSourceModule(name); +} + +MOD_EXPORT void _DELETE_INSTANCE_(ModuleManager::Instance* instance) { + delete (LimeSDRSourceModule*)instance; +} + +MOD_EXPORT void _END_() { + config.disableAutoSave(); + config.save(); +} \ No newline at end of file diff --git a/make_windows_package.ps1 b/make_windows_package.ps1 index 809fde94..da3ce581 100644 --- a/make_windows_package.ps1 +++ b/make_windows_package.ps1 @@ -24,6 +24,9 @@ cp 'C:/Program Files/PothosSDR/bin/airspy.dll' sdrpp_windows_x64/ cp $build_dir/hackrf_source/Release/hackrf_source.dll sdrpp_windows_x64/modules/ cp 'C:/Program Files/PothosSDR/bin/hackrf.dll' sdrpp_windows_x64/ +cp $build_dir/hackrf_source/Release/hackrf_source.dll sdrpp_windows_x64/modules/ +cp 'C:/Program Files/PothosSDR/bin/hackrf.dll' sdrpp_windows_x64/ + cp $build_dir/rtl_sdr_source/Release/rtl_sdr_source.dll sdrpp_windows_x64/modules/ cp 'C:/Program Files/PothosSDR/bin/rtlsdr.dll' sdrpp_windows_x64/ diff --git a/readme.md b/readme.md index d446bca2..17ca31d5 100644 --- a/readme.md +++ b/readme.md @@ -139,6 +139,16 @@ The modules built will be some of the following (Repeat the instructions above f # Building on Linux / BSD +## Select which modules you wish to build +Depending on which module you want to build, you will need to install some additional dependencies. +Here are listed every module that requires addition dependencies. If a module enabled by default and you do not wish to install a perticular dependency (or can't, eg. the BladeRF module on Debian Buster), +you can disable it using the module parameter listed in the table below + +* soapy_source: SoapySDR + drivers for each SDRs (see SoapySDR docs) +* airspyhf_source: libairspyhf +* plutosdr_source: libiio, libad9361 +* audio_sink: librtaudio-dev + ## Install dependencies * cmake * fftw3 @@ -146,11 +156,7 @@ The modules built will be some of the following (Repeat the instructions above f * glew * libvolk -Next install dependencies based on the modules you wish to build: -* soapy_source: SoapySDR + drivers for each SDRs (see SoapySDR docs) -* airspyhf_source: libairspyhf -* plutosdr_source: libiio, libad9361 -* audio_sink: librtaudio-dev +Next install dependencies based on the modules you wish to build (See previous step) Note: make sure you're using GCC 8 or later as older versions do not have `std::filesystem` built-in. @@ -221,6 +227,80 @@ To install SDR++, run the following command in your ``build`` folder: sudo make install ``` +# Module List + +Not all modules are built by default. I decided to disable the build of those with large libraries, libraries that can't be installed through the package manager (or pothos) and those that are still in beta. +Modules in beta are still included in releases for the most part but not enabled in SDR++ (need to be instantiated). + +## Sources + +| Name | Stage | Dependencies | Option | Built by default| Built in Release | Enabled in SDR++ by default | +|------------------|------------|-------------------|----------------------------|:---------------:|:-----------------------:|:---------------------------:| +| airspy_source | Working | libairspy | OPT_BUILD_AIRSPY_SOURCE | ✅ | ✅ | ✅ | +| airspyhf_source | Working | libairspyhf | OPT_BUILD_AIRSPYHF_SOURCE | ✅ | ✅ | ✅ | +| bladerf_source | Beta | libbladeRF | OPT_BUILD_BLADERF_SOURCE | ⛔ | ⚠️ (not Debian Buster) | ✅ | +| file_source | Working | - | OPT_BUILD_FILE_SOURCE | ✅ | ✅ | ✅ | +| hackrf_source | Working | libhackrf | OPT_BUILD_HACKRF_SOURCE | ✅ | ✅ | ✅ | +| limesdr_source | Beta | liblimesuite | OPT_BUILD_LIMESDR_SOURCE | ⛔ | ✅ | ✅ | +| sddc_source | Unfinished | - | OPT_BUILD_SDDC_SOURCE | ⛔ | ⛔ | ⛔ | +| rtl_sdr_source | Working | librtlsdr | OPT_BUILD_RTL_SDR_SOURCE | ✅ | ✅ | ✅ | +| rtl_tcp_source | Working | - | OPT_BUILD_RTL_TCP_SOURCE | ✅ | ✅ | ✅ | +| sdrplay_source | Working | SDRplay API | OPT_BUILD_SDRPLAY_SOURCE | ⛔ | ✅ | ✅ | +| soapy_source | Working | soapysdr | OPT_BUILD_SOAPY_SOURCE | ✅ | ✅ | ✅ | +| spyserver_source | Unfinished | - | OPT_BUILD_SPYSERVER_SOURCE | ⛔ | ⛔ | ⛔ | +| plutosdr_source | Working | libiio, libad9361 | OPT_BUILD_PLUTOSDR_SOURCE | ✅ | ✅ | ✅ | + +## Sinks + +| Name | Stage | Dependencies | Option | Built by default| Built in Release | Enabled in SDR++ by default | +|------------------|------------|-------------------|----------------------------|:---------------:|:-----------------------:|:---------------------------:| +| audio_sink | Working | rtaudio | OPT_BUILD_AUDIO_SINK | ✅ | ✅ | ✅ | + +## Decoders + +| Name | Stage | Dependencies | Option | Built by default| Built in Release | Enabled in SDR++ by default | +|---------------------|------------|--------------|-------------------------------|:---------------:|:-----------------------:|:---------------------------:| +| falcon9_decoder | Beta | ffplay | OPT_BUILD_FALCON9_DECODER | ⛔ | ⛔ | ⛔ | +| meteor_demodulator | Working | - | OPT_BUILD_METEOR_DEMODULATOR | ✅ | ✅ | ⛔ | +| radio | Working | - | OPT_BUILD_RADIO | ✅ | ✅ | ✅ | +| weather_sat_decoder | Unfinished | - | OPT_BUILD_WEATHER_SAT_DECODER | ⛔ | ⛔ | ⛔ | + +## Misc + +| Name | Stage | Dependencies | Option | Built by default| Built in Release | Enabled in SDR++ by default | +|---------------------|------------|--------------|-------------------------------|:---------------:|:-----------------------:|:---------------------------:| +| discord_integration | Working | - | OPT_BUILD_DISCORD_PRESENCE | ✅ | ✅ | ⛔ | +| frequency_manager | Unfinished | - | OPT_BUILD_FREQUENCY_MANAGER | ⛔ | ⛔ | ⛔ | +| recorder | Working | - | OPT_BUILD_RECORDER | ✅ | ✅ | ✅ | + +# Toubleshooting + +First, please make sure you're running the latest automated build. If your issue is linked to a bug it is likely that is has already been fixed in later releases + +## "hash collision" error when starting + +You likely installed the `soapysdr-module-all` package on Ubuntu/Debian. If not it's still a SoapySDR bug caused by multiple soapy modules comming in conflict. Uninstall anything related to SoapySDR then install soapysdr itself and only the soapy modules you actually need. + +## "I don't see -insert module name here-, what's going on?" + +If the module was included in a later update, it's not enabled in the config. The easiest way to fix this is just to delete the `config.json` file and let SDR++ recreate it (you will lose your setting relating to the main UI like VFO colors, zoom level and theme). +The best option however is to edit the config file to add an instance of the module you wish to hae enabled (see the Module List). + +## SDR++ crashes when stopping a RTL-SDR + +This is a bug recently introduced by libusb1.4 +To solve, this, simply downgrade to libusb1.3 + +## SDR++ crashes when starting a HackRF + +If you also have the SoapySDR module loaded (not necessarily enabled), this is a bug in libhackrf. It's caused by libhackrf not checking if it's already initialized. +The solution until a fixed libhackrf version is released is to completely remove the soapy_source module from SDR++. To do this, delete `modules/soapy_source.dll` on windows +or `/usr/share/sdrpp/plugins/soapy_source.so` on linux. + +## Issue not listed here? + +If you still have an issue, please open an issue about it or ask on the discord. I'll try to respond as quickly as I can. Please avoid trying to contact me on every platform imaginable thinking I'll respond faster though... + # Contributing Feel free to submit pull requests and report bugs via the GitHub issue tracker.