From 6d784dfe2750a486af24a6c2a63b538e43d2aa21 Mon Sep 17 00:00:00 2001 From: AlexandreRouma Date: Tue, 30 Aug 2022 16:07:49 +0200 Subject: [PATCH] enabled scanner --- CMakeLists.txt | 2 +- make_macos_bundle.sh | 2 + make_windows_package.ps1 | 1 + misc_modules/scanner/src/main.cpp | 93 +++++++++++++++++++++---------- 4 files changed, 67 insertions(+), 31 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d4d89434..3b0455f1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -60,7 +60,7 @@ 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_RECORDER "Audio and baseband recorder" ON) option(OPT_BUILD_RIGCTL_SERVER "Rigctl backend for controlling SDR++ with software like gpredict" ON) -option(OPT_BUILD_SCANNER "Frequency scanner" OFF) +option(OPT_BUILD_SCANNER "Frequency scanner" ON) option(OPT_BUILD_SCHEDULER "Build the scheduler" OFF) # Other options diff --git a/make_macos_bundle.sh b/make_macos_bundle.sh index a60bc659..99cb5c88 100644 --- a/make_macos_bundle.sh +++ b/make_macos_bundle.sh @@ -56,10 +56,12 @@ bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/decoder_module bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/decoder_modules/meteor_demodulator/meteor_demodulator.dylib bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/decoder_modules/radio/radio.dylib +# Misc modules bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/misc_modules/discord_integration/discord_integration.dylib bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/misc_modules/frequency_manager/frequency_manager.dylib bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/misc_modules/recorder/recorder.dylib bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/misc_modules/rigctl_server/rigctl_server.dylib +bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/misc_modules/scanner/scanner.dylib # ========================= Finalize ========================= diff --git a/make_windows_package.ps1 b/make_windows_package.ps1 index f6de9490..9ad8c2f9 100644 --- a/make_windows_package.ps1 +++ b/make_windows_package.ps1 @@ -68,6 +68,7 @@ cp $build_dir/misc_modules/discord_integration/Release/discord_integration.dll s cp $build_dir/misc_modules/frequency_manager/Release/frequency_manager.dll sdrpp_windows_x64/modules/ cp $build_dir/misc_modules/recorder/Release/recorder.dll sdrpp_windows_x64/modules/ cp $build_dir/misc_modules/rigctl_server/Release/rigctl_server.dll sdrpp_windows_x64/modules/ +cp $build_dir/misc_modules/scanner/Release/scanner.dll sdrpp_windows_x64/modules/ # Copy supporting libs diff --git a/misc_modules/scanner/src/main.cpp b/misc_modules/scanner/src/main.cpp index 20edd70d..8421a652 100644 --- a/misc_modules/scanner/src/main.cpp +++ b/misc_modules/scanner/src/main.cpp @@ -9,7 +9,7 @@ SDRPP_MOD_INFO{ /* Description: */ "Frequency scanner for SDR++", /* Author: */ "Ryzerth", /* Version: */ 0, 1, 0, - /* Max instances */ -1 + /* Max instances */ 1 }; class ScannerModule : public ModuleManager::Instance { @@ -59,12 +59,45 @@ private: if (ImGui::InputDouble("##interval_scanner", &_this->interval, 100.0, 100000.0, "%0.0f")) { _this->interval = round(_this->interval); } + ImGui::LeftLabel("Passband Ratio (%)"); + ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); + if (ImGui::InputDouble("##pb_ratio_scanner", &_this->passbandRatio, 1.0, 10.0, "%0.0f")) { + _this->passbandRatio = std::clamp(round(_this->passbandRatio), 1.0, 100.0); + } + ImGui::LeftLabel("Tuning Time (ms)"); + ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); + if (ImGui::InputInt("##tuning_time_scanner", &_this->tuningTime, 100, 1000)) { + _this->tuningTime = std::clamp(_this->tuningTime, 100, 10000.0); + } + ImGui::LeftLabel("Linger Time (ms)"); + ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); + if (ImGui::InputInt("##linger_time_scanner", &_this->lingerTime, 100, 1000)) { + _this->lingerTime = std::clamp(_this->lingerTime, 100, 10000.0); + } if (_this->running) { ImGui::EndDisabled(); } ImGui::LeftLabel("Level"); ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); ImGui::SliderFloat("##scanner_level", &_this->level, -150.0, 0.0); + ImGui::BeginTable(("scanner_bottom_btn_table" + _this->name).c_str(), 2); + ImGui::TableNextRow(); + ImGui::TableSetColumnIndex(0); + if (ImGui::Button(("<<##scanner_back_" + _this->name).c_str(), ImVec2(ImGui::GetContentRegionAvail().x, 0))) { + std::lock_guard lck(_this->scanMtx); + _this->reverseLock = true; + _this->receiving = false; + _this->scanUp = false; + } + ImGui::TableSetColumnIndex(1); + if (ImGui::Button((">>##scanner_forw_" + _this->name).c_str(), ImVec2(ImGui::GetContentRegionAvail().x, 0))) { + std::lock_guard lck(_this->scanMtx); + _this->reverseLock = true; + _this->receiving = false; + _this->scanUp = true; + } + ImGui::EndTable(); + if (!_this->running) { if (ImGui::Button("Start##scanner_start", ImVec2(menuWidth, 0))) { _this->start(); @@ -75,17 +108,6 @@ private: _this->stop(); } } - - if (ImGui::Button("<<##scanner_start", ImVec2(menuWidth, 0))) { - std::lock_guard lck(_this->scanMtx); - _this->receiving = false; - _this->scanUp = false; - } - if (ImGui::Button(">>##scanner_start", ImVec2(menuWidth, 0))) { - std::lock_guard lck(_this->scanMtx); - _this->receiving = false; - _this->scanUp = true; - } } void start() { @@ -107,18 +129,21 @@ private: // 10Hz scan loop while (running) { std::this_thread::sleep_for(std::chrono::milliseconds(100)); - { std::lock_guard lck(scanMtx); auto now = std::chrono::high_resolution_clock::now(); // Enforce tuning - tuner::normalTuning(selectedVFO, current); + if (gui::waterfall.selectedVFO.empty()) { + running = false; + return; + } + tuner::normalTuning(gui::waterfall.selectedVFO, current); // Check if we are waiting for a tune if (tuning) { spdlog::warn("Tuning"); - if ((std::chrono::duration_cast(now - lastTuneTime)).count() > 250.0) { + if ((std::chrono::duration_cast(now - lastTuneTime)).count() > tuningTime) { tuning = false; } continue; @@ -136,7 +161,7 @@ private: double wfEnd = wfCenter + (wfWidth / 2.0); // Gather VFO data - double vfoWidth = sigpath::vfoManager.getBandwidth(selectedVFO); + double vfoWidth = sigpath::vfoManager.getBandwidth(gui::waterfall.selectedVFO); if (receiving) { spdlog::warn("Receiving"); @@ -145,26 +170,30 @@ private: if (maxLevel >= level) { lastSignalTime = now; } - else if ((std::chrono::duration_cast(now - lastSignalTime)).count() > 1000.0) { + else if ((std::chrono::duration_cast(now - lastSignalTime)).count() > lingerTime) { receiving = false; } } else { spdlog::warn("Seeking signal"); - double bottomLimit = INFINITY; - double topLimit = -INFINITY; + double bottomLimit = current; + double topLimit = current; // Search for a signal in scan direction - if (tuneIfAvailable(scanUp, bottomLimit, topLimit, wfStart, wfEnd, wfWidth, vfoWidth, data, dataWidth)) { + if (findSignal(scanUp, bottomLimit, topLimit, wfStart, wfEnd, wfWidth, vfoWidth, data, dataWidth)) { gui::waterfall.releaseLatestFFT(); continue; } - // Search for signal in the inverse scan direction - if (tuneIfAvailable(!scanUp, bottomLimit, topLimit, wfStart, wfEnd, wfWidth, vfoWidth, data, dataWidth)) { - gui::waterfall.releaseLatestFFT(); - continue; + // Search for signal in the inverse scan direction if direction isn't enforced + if (!reverseLock) { + if (findSignal(!scanUp, bottomLimit, topLimit, wfStart, wfEnd, wfWidth, vfoWidth, data, dataWidth)) { + gui::waterfall.releaseLatestFFT(); + continue; + } } + else { reverseLock = false; } + // There is no signal on the visible spectrum, tune in scan direction and retry if (scanUp) { @@ -172,7 +201,7 @@ private: if (current > stopFreq) { current = startFreq; } } else { - current = topLimit - interval; + current = bottomLimit - interval; if (current < startFreq) { current = stopFreq; } } @@ -189,7 +218,7 @@ private: } } - bool tuneIfAvailable(bool scanDir, double& bottomLimit, double& topLimit, double wfStart, double wfEnd, double wfWidth, double vfoWidth, float* data, int dataWidth) { + bool findSignal(bool scanDir, double& bottomLimit, double& topLimit, double wfStart, double wfEnd, double wfWidth, double vfoWidth, float* data, int dataWidth) { bool found = false; double freq = current; for (freq += scanDir ? interval : -interval; @@ -204,7 +233,7 @@ private: if (freq > topLimit) { topLimit = freq; } // Check signal level - float maxLevel = getMaxLevel(data, freq, vfoWidth *0.2, dataWidth, wfStart, wfWidth); + float maxLevel = getMaxLevel(data, freq, vfoWidth * (passbandRatio * 0.01f), dataWidth, wfStart, wfWidth); if (maxLevel >= level) { found = true; receiving = true; @@ -231,15 +260,19 @@ private: bool enabled = true; bool running = false; - std::string selectedVFO = "Radio"; - double startFreq = 93300000.0; - double stopFreq = 98700000.0; + //std::string selectedVFO = "Radio"; + double startFreq = 88000000.0; + double stopFreq = 108000000.0; double interval = 100000.0; double current = 88000000.0; + double passbandRatio = 10.0; + int tuningTime = 250; + int lingerTime = 1000.0; float level = -50.0; bool receiving = true; bool tuning = false; bool scanUp = true; + bool reverseLock = false; std::chrono::time_point lastSignalTime; std::chrono::time_point lastTuneTime; std::thread workerThread;