diff --git a/.github/workflows/build_all.yml b/.github/workflows/build_all.yml index 3c00b7aa..dbab4a32 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 -DOPT_BUILD_BLADERF_SOURCE=ON + run: cmake "$Env:GITHUB_WORKSPACE" "-DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake" -DOPT_BUILD_SDRPLAY_SOURCE=ON - name: Build working-directory: ${{runner.workspace}}/build @@ -73,7 +73,7 @@ jobs: - name: Prepare CMake working-directory: ${{runner.workspace}}/build - run: cmake $GITHUB_WORKSPACE -DOPT_BUILD_AIRSPYHF_SOURCE=OFF -DOPT_BUILD_PLUTOSDR_SOURCE=OFF -DOPT_BUILD_SOAPY_SOURCE=OFF -DOPT_BUILD_BLADERF_SOURCE=ON + run: cmake $GITHUB_WORKSPACE -DOPT_BUILD_AIRSPYHF_SOURCE=OFF -DOPT_BUILD_PLUTOSDR_SOURCE=OFF -DOPT_BUILD_SOAPY_SOURCE=OFF - name: Build working-directory: ${{runner.workspace}}/build diff --git a/bladerf_source/CMakeLists.txt b/bladerf_source/CMakeLists.txt index 4c19fbea..2dfe9ebe 100644 --- a/bladerf_source/CMakeLists.txt +++ b/bladerf_source/CMakeLists.txt @@ -25,6 +25,11 @@ if (MSVC) else (MSVC) # Not in pkg-config target_link_libraries(bladerf_source PUBLIC bladeRF) + + # 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 diff --git a/core/src/core.cpp b/core/src/core.cpp index 9ad8e132..c94f9471 100644 --- a/core/src/core.cpp +++ b/core/src/core.cpp @@ -171,7 +171,11 @@ int sdrpp_main(int argc, char *argv[]) { defConfig["showMenu"] = true; defConfig["showWaterfall"] = true; defConfig["source"] = ""; - defConfig["streams"] = json::object(); + + defConfig["streams"]["Radio"]["muted"] = false; + defConfig["streams"]["Radio"]["sink"] = "Audio"; + defConfig["streams"]["Radio"]["volume"] = 1.0f; + defConfig["windowSize"]["h"] = 720; defConfig["windowSize"]["w"] = 1280; diff --git a/core/src/gui/main_window.cpp b/core/src/gui/main_window.cpp index 383d65e6..cf3b0953 100644 --- a/core/src/gui/main_window.cpp +++ b/core/src/gui/main_window.cpp @@ -25,6 +25,8 @@ #include #include #include +#include +#include #include #include #include @@ -32,7 +34,6 @@ #include #include #include -#include int fftSize = 8192 * 8; @@ -102,6 +103,19 @@ bool demoWindow = false; float testSNR = 50; +EventHandler vfoCreatedHandler; +void vfoAddedHandler(VFOManager::VFO* vfo, void* ctx) { + std::string name = vfo->getName(); + core::configManager.aquire(); + if (!core::configManager.conf["vfoOffsets"].contains(name)) { + core::configManager.release(); + return; + } + double offset = core::configManager.conf["vfoOffsets"][name]; + core::configManager.release(); + sigpath::vfoManager.setOffset(name, std::clamp(offset, -bw/2.0, bw/2.0)); +} + void windowInit() { LoadingScreen::show("Initializing UI"); gui::waterfall.init(); @@ -137,6 +151,7 @@ void windowInit() { gui::menu.registerEntry("Band Plan", bandplanmenu::draw, NULL); gui::menu.registerEntry("Display", displaymenu::draw, NULL); gui::menu.registerEntry("VFO Color", vfo_color_menu::draw, NULL); + gui::menu.registerEntry("Module Manager", module_manager_menu::draw, NULL); gui::freqSelect.init(); @@ -151,6 +166,9 @@ void windowInit() { sigpath::signalPath.init(8000000, 20, fftSize, &dummyStream, (dsp::complex_t*)fft_in, fftHandler); sigpath::signalPath.start(); + vfoCreatedHandler.handler = vfoAddedHandler; + sigpath::vfoManager.vfoCreatedEvent.bindHandler(vfoCreatedHandler); + spdlog::info("Loading modules"); // Load modules from /module directory @@ -217,6 +235,7 @@ void windowInit() { bandplanmenu::init(); displaymenu::init(); vfo_color_menu::init(); + module_manager_menu::init(); // TODO for 0.2.5 // Add "select file" option for the file source @@ -259,15 +278,6 @@ void windowInit() { centerTuning = core::configManager.conf["centerTuning"]; - // Load each VFO's offset - for (auto const& [name, _vfo] : gui::waterfall.vfos) { - if (!core::configManager.conf["vfoOffsets"].contains(name)) { - continue; - } - double offset = core::configManager.conf["vfoOffsets"][name]; - sigpath::vfoManager.setOffset(name, std::clamp(offset, -bw/2.0, bw/2.0)); - } - core::configManager.release(); } diff --git a/core/src/gui/menus/module_manager.cpp b/core/src/gui/menus/module_manager.cpp new file mode 100644 index 00000000..a15630ab --- /dev/null +++ b/core/src/gui/menus/module_manager.cpp @@ -0,0 +1,79 @@ +#include +#include +#include +#include +#include + +namespace module_manager_menu { + char modName[1024]; + std::vector modTypes; + std::string modTypesTxt; + int modTypeId; + + void init() { + modName[0] = 0; + + modTypes.clear(); + modTypesTxt = ""; + for (auto& [name, mod] : core::moduleManager.modules) { + // TEMPORARY EXCLUSION FOR SOURCES AND SINKS + if (name.find("source") != std::string::npos) { continue; } + if (name.find("sink") != std::string::npos) { continue; } + if (name.find("recorder") != std::string::npos) { continue; } + if (name.find("discord") != std::string::npos) { continue; } + modTypes.push_back(name); + modTypesTxt += name; + modTypesTxt += '\0'; + } + modTypeId = 0; + } + + void draw(void* ctx) { + ImGui::BeginTable("Module Manager Table", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg); + ImGui::TableSetupColumn("Name"); + ImGui::TableSetupColumn("Type"); + ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, 16); + ImGui::TableHeadersRow(); + for (auto& [name, inst] : core::moduleManager.instances) { + // TEMPORARY EXCLUSION FOR SOURCES AND SINKS + std::string type = inst.module.info->name; + if (type.find("source") != std::string::npos) { continue; } + if (type.find("sink") != std::string::npos) { continue; } + if (type.find("recorder") != std::string::npos) { continue; } + if (type.find("discord") != std::string::npos) { continue; } + + ImGui::TableNextRow(); + + ImGui::TableSetColumnIndex(0); + ImGui::Text(name.c_str()); + + ImGui::TableSetColumnIndex(1); + ImGui::Text(inst.module.info->name); + + ImGui::TableSetColumnIndex(2); + if (ImGui::Button(("-##module_mgr_"+name).c_str(), ImVec2(16,0))) { + core::moduleManager.deleteInstance(name); + } + } + + // Add module row + ImGui::TableNextRow(); + + ImGui::TableSetColumnIndex(0); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvailWidth()); + ImGui::InputText("##module_mod_name", modName, 1000); + + ImGui::TableSetColumnIndex(1); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvailWidth()); + ImGui::Combo("##module_mgr_type", &modTypeId, modTypesTxt.c_str()); + + ImGui::TableSetColumnIndex(2); + if (strlen(modName) == 0) { style::beginDisabled(); } + if (ImGui::Button("+##module_mgr_add_btn", ImVec2(16,0))) { + core::moduleManager.createInstance(modName, modTypes[modTypeId]); + } + if (strlen(modName) == 0) { style::endDisabled(); } + + ImGui::EndTable(); + } +} \ No newline at end of file diff --git a/core/src/gui/menus/module_manager.h b/core/src/gui/menus/module_manager.h new file mode 100644 index 00000000..fcd0072c --- /dev/null +++ b/core/src/gui/menus/module_manager.h @@ -0,0 +1,6 @@ +#pragma once + +namespace module_manager_menu { + void init(); + void draw(void* ctx); +} \ No newline at end of file diff --git a/core/src/module.cpp b/core/src/module.cpp index 71923266..b04c839b 100644 --- a/core/src/module.cpp +++ b/core/src/module.cpp @@ -100,11 +100,17 @@ void ModuleManager::createInstance(std::string name, std::string module) { } void ModuleManager::deleteInstance(std::string name) { - spdlog::error("DELETE INSTANCE NOT IMPLEMENTED"); + if (instances.find(name) == instances.end()) { + spdlog::error("Tried to remove non-existant instance '{0}'", name); + return; + } + Instance_t inst = instances[name]; + inst.module.deleteInstance(inst.instance); + instances.erase(name); } void ModuleManager::deleteInstance(ModuleManager::Instance* instance) { - spdlog::error("DELETE INSTANCE NOT IMPLEMENTED"); + spdlog::error("Delete instance not implemented"); } void ModuleManager::enableInstance(std::string name) { diff --git a/core/src/module.h b/core/src/module.h index 7a95f519..fdb0ba48 100644 --- a/core/src/module.h +++ b/core/src/module.h @@ -86,7 +86,6 @@ public: int countModuleInstances(std::string module); -private: std::map modules; std::map instances; diff --git a/core/src/signal_path/sink.cpp b/core/src/signal_path/sink.cpp index cf930054..544cf7fd 100644 --- a/core/src/signal_path/sink.cpp +++ b/core/src/signal_path/sink.cpp @@ -108,6 +108,14 @@ void SinkManager::registerStream(std::string name, SinkManager::Stream* stream) streams[name] = stream; streamNames.push_back(name); + + // Load config + core::configManager.aquire(); + bool available = core::configManager.conf["streams"].contains(name); + core::configManager.release(); + if (available) { loadStreamConfig(name); } + + streamRegisteredEvnt.emit(name); } void SinkManager::unregisterStream(std::string name) { @@ -115,10 +123,12 @@ void SinkManager::unregisterStream(std::string name) { spdlog::error("Cannot unregister stream '{0}', this stream doesn't exist", name); return; } - spdlog::error("unregisterStream NOT IMPLEMENTED!!!!!!!"); + streamUnregisteredEvnt.emit(name); SinkManager::Stream* stream = streams[name]; + stream->stop(); delete stream->sink; - delete stream; + streams.erase(name); + streamNames.erase(std::remove(streamNames.begin(), streamNames.end(), name), streamNames.end()); } void SinkManager::startStream(std::string name) { diff --git a/core/src/signal_path/sink.h b/core/src/signal_path/sink.h index 50bb4be7..774b9d5f 100644 --- a/core/src/signal_path/sink.h +++ b/core/src/signal_path/sink.h @@ -110,6 +110,9 @@ public: std::vector getStreamNames(); + Event streamRegisteredEvnt; + Event streamUnregisteredEvnt; + private: void loadStreamConfig(std::string name); void saveStreamConfig(std::string name); diff --git a/docker_builds/debian_bullseye/do_build.sh b/docker_builds/debian_bullseye/do_build.sh index e9ced6e4..9cef61c3 100644 --- a/docker_builds/debian_bullseye/do_build.sh +++ b/docker_builds/debian_bullseye/do_build.sh @@ -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=ON +cmake .. -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 39e2f549..769c7bc3 100644 --- a/docker_builds/debian_buster/do_build.sh +++ b/docker_builds/debian_buster/do_build.sh @@ -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=ON +cmake .. -DOPT_BUILD_SDRPLAY_SOURCE=ON make -j2 cd .. diff --git a/docker_builds/debian_sid/do_build.sh b/docker_builds/debian_sid/do_build.sh index e9ced6e4..9cef61c3 100644 --- a/docker_builds/debian_sid/do_build.sh +++ b/docker_builds/debian_sid/do_build.sh @@ -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=ON +cmake .. -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 e9ced6e4..9cef61c3 100644 --- a/docker_builds/ubuntu_focal/do_build.sh +++ b/docker_builds/ubuntu_focal/do_build.sh @@ -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=ON +cmake .. -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 e9ced6e4..9cef61c3 100644 --- a/docker_builds/ubuntu_groovy/do_build.sh +++ b/docker_builds/ubuntu_groovy/do_build.sh @@ -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=ON +cmake .. -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 e9ced6e4..9cef61c3 100644 --- a/docker_builds/ubuntu_hirsute/do_build.sh +++ b/docker_builds/ubuntu_hirsute/do_build.sh @@ -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=ON +cmake .. -DOPT_BUILD_SDRPLAY_SOURCE=ON make -j2 cd .. diff --git a/file_source/src/main.cpp b/file_source/src/main.cpp index 526d899a..429ef707 100644 --- a/file_source/src/main.cpp +++ b/file_source/src/main.cpp @@ -43,6 +43,7 @@ public: } ~FileSourceModule() { + spdlog::info("FileSourceModule '{0}': Instance deleted!", name); } diff --git a/meteor_demodulator/src/main.cpp b/meteor_demodulator/src/main.cpp index bec68010..b0ccf920 100644 --- a/meteor_demodulator/src/main.cpp +++ b/meteor_demodulator/src/main.cpp @@ -78,12 +78,23 @@ public: } ~MeteorDemodulatorModule() { - + if (recording) { + std::lock_guard lck(recMtx); + recording = false; + recFile.close(); + } + demod.stop(); + split.stop(); + reshape.stop(); + symSink.stop(); + sink.stop(); + sigpath::vfoManager.deleteVFO(vfo); + gui::menu.removeEntry(name); } void enable() { double bw = gui::waterfall.getBandwidth(); - vfo = sigpath::vfoManager.createVFO(name, ImGui::WaterfallVFO::REF_CENTER, std::clamp(savedOffset, -bw/2.0, bw/2.0), 150000, INPUT_SAMPLE_RATE, 150000, 150000, true); + vfo = sigpath::vfoManager.createVFO(name, ImGui::WaterfallVFO::REF_CENTER, std::clamp(0, -bw/2.0, bw/2.0), 150000, INPUT_SAMPLE_RATE, 150000, 150000, true); demod.setInput(vfo->output); @@ -103,7 +114,6 @@ public: symSink.stop(); sink.stop(); - savedOffset = vfo->getOffset(); sigpath::vfoManager.deleteVFO(vfo); enabled = false; } @@ -186,8 +196,6 @@ private: std::string name; bool enabled = true; - double savedOffset = 0; - // DSP Chain VFOManager::VFO* vfo; diff --git a/radio/src/main.cpp b/radio/src/main.cpp index 0c283c44..d6888450 100644 --- a/radio/src/main.cpp +++ b/radio/src/main.cpp @@ -68,12 +68,19 @@ public: } ~RadioModule() { - + core::modComManager.unregisterInterface(name); + gui::menu.removeEntry(name); + stream.stop(); + if (enabled) { + currentDemod->stop(); + sigpath::vfoManager.deleteVFO(vfo); + } + sigpath::sinkManager.unregisterStream(name); } void enable() { double bw = gui::waterfall.getBandwidth(); - vfo = sigpath::vfoManager.createVFO(name, ImGui::WaterfallVFO::REF_CENTER, std::clamp(savedOffset, -bw/2.0, bw/2.0), 200000, 200000, 50000, 200000, false); + vfo = sigpath::vfoManager.createVFO(name, ImGui::WaterfallVFO::REF_CENTER, std::clamp(0, -bw/2.0, bw/2.0), 200000, 200000, 50000, 200000, false); wfmDemod.setVFO(vfo); fmDemod.setVFO(vfo); @@ -91,7 +98,6 @@ public: void disable() { currentDemod->stop(); - savedOffset = vfo->getOffset(); sigpath::vfoManager.deleteVFO(vfo); enabled = false; } @@ -197,7 +203,6 @@ private: bool enabled = true; int demodId = 0; float audioSampRate = 48000; - double savedOffset = 0; Demodulator* currentDemod = NULL; VFOManager::VFO* vfo; diff --git a/recorder/src/main.cpp b/recorder/src/main.cpp index 66068af6..594b20c6 100644 --- a/recorder/src/main.cpp +++ b/recorder/src/main.cpp @@ -88,6 +88,28 @@ public: } ~RecorderModule() { + // Stop recording + if (recording) { + if (recMode == 1) { + audioSplit.unbindStream(&audioHandlerStream); + audioHandler.stop(); + audioWriter->close(); + delete audioWriter; + } + else { + sigpath::signalPath.unbindIQStream(&basebandStream); + basebandHandler.stop(); + basebandWriter->close(); + delete basebandWriter; + } + } + + vol.stop(); + audioSplit.stop(); + meter.stop(); + + gui::menu.removeEntry(name); + delete[] wavSampleBuf; }