mirror of
https://github.com/AlexandreRouma/SDRPlusPlus.git
synced 2024-12-25 02:18:30 +01:00
enabled scanner
This commit is contained in:
parent
efcf26f0ac
commit
6d784dfe27
@ -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_FREQUENCY_MANAGER "Build the Frequency Manager module" ON)
|
||||||
option(OPT_BUILD_RECORDER "Audio and baseband recorder" 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_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)
|
option(OPT_BUILD_SCHEDULER "Build the scheduler" OFF)
|
||||||
|
|
||||||
# Other options
|
# Other options
|
||||||
|
@ -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/meteor_demodulator/meteor_demodulator.dylib
|
||||||
bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/decoder_modules/radio/radio.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/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/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/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/rigctl_server/rigctl_server.dylib
|
||||||
|
bundle_install_binary $BUNDLE $BUNDLE/Contents/Plugins $BUILD_DIR/misc_modules/scanner/scanner.dylib
|
||||||
|
|
||||||
# ========================= Finalize =========================
|
# ========================= Finalize =========================
|
||||||
|
|
||||||
|
@ -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/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/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/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
|
# Copy supporting libs
|
||||||
|
@ -9,7 +9,7 @@ SDRPP_MOD_INFO{
|
|||||||
/* Description: */ "Frequency scanner for SDR++",
|
/* Description: */ "Frequency scanner for SDR++",
|
||||||
/* Author: */ "Ryzerth",
|
/* Author: */ "Ryzerth",
|
||||||
/* Version: */ 0, 1, 0,
|
/* Version: */ 0, 1, 0,
|
||||||
/* Max instances */ -1
|
/* Max instances */ 1
|
||||||
};
|
};
|
||||||
|
|
||||||
class ScannerModule : public ModuleManager::Instance {
|
class ScannerModule : public ModuleManager::Instance {
|
||||||
@ -59,12 +59,45 @@ private:
|
|||||||
if (ImGui::InputDouble("##interval_scanner", &_this->interval, 100.0, 100000.0, "%0.0f")) {
|
if (ImGui::InputDouble("##interval_scanner", &_this->interval, 100.0, 100000.0, "%0.0f")) {
|
||||||
_this->interval = round(_this->interval);
|
_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<double>(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<int>(_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<int>(_this->lingerTime, 100, 10000.0);
|
||||||
|
}
|
||||||
if (_this->running) { ImGui::EndDisabled(); }
|
if (_this->running) { ImGui::EndDisabled(); }
|
||||||
|
|
||||||
ImGui::LeftLabel("Level");
|
ImGui::LeftLabel("Level");
|
||||||
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
|
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
|
||||||
ImGui::SliderFloat("##scanner_level", &_this->level, -150.0, 0.0);
|
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<std::mutex> 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<std::mutex> lck(_this->scanMtx);
|
||||||
|
_this->reverseLock = true;
|
||||||
|
_this->receiving = false;
|
||||||
|
_this->scanUp = true;
|
||||||
|
}
|
||||||
|
ImGui::EndTable();
|
||||||
|
|
||||||
if (!_this->running) {
|
if (!_this->running) {
|
||||||
if (ImGui::Button("Start##scanner_start", ImVec2(menuWidth, 0))) {
|
if (ImGui::Button("Start##scanner_start", ImVec2(menuWidth, 0))) {
|
||||||
_this->start();
|
_this->start();
|
||||||
@ -75,17 +108,6 @@ private:
|
|||||||
_this->stop();
|
_this->stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui::Button("<<##scanner_start", ImVec2(menuWidth, 0))) {
|
|
||||||
std::lock_guard<std::mutex> lck(_this->scanMtx);
|
|
||||||
_this->receiving = false;
|
|
||||||
_this->scanUp = false;
|
|
||||||
}
|
|
||||||
if (ImGui::Button(">>##scanner_start", ImVec2(menuWidth, 0))) {
|
|
||||||
std::lock_guard<std::mutex> lck(_this->scanMtx);
|
|
||||||
_this->receiving = false;
|
|
||||||
_this->scanUp = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void start() {
|
void start() {
|
||||||
@ -107,18 +129,21 @@ private:
|
|||||||
// 10Hz scan loop
|
// 10Hz scan loop
|
||||||
while (running) {
|
while (running) {
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||||
|
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lck(scanMtx);
|
std::lock_guard<std::mutex> lck(scanMtx);
|
||||||
auto now = std::chrono::high_resolution_clock::now();
|
auto now = std::chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
// Enforce tuning
|
// 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
|
// Check if we are waiting for a tune
|
||||||
if (tuning) {
|
if (tuning) {
|
||||||
spdlog::warn("Tuning");
|
spdlog::warn("Tuning");
|
||||||
if ((std::chrono::duration_cast<std::chrono::milliseconds>(now - lastTuneTime)).count() > 250.0) {
|
if ((std::chrono::duration_cast<std::chrono::milliseconds>(now - lastTuneTime)).count() > tuningTime) {
|
||||||
tuning = false;
|
tuning = false;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
@ -136,7 +161,7 @@ private:
|
|||||||
double wfEnd = wfCenter + (wfWidth / 2.0);
|
double wfEnd = wfCenter + (wfWidth / 2.0);
|
||||||
|
|
||||||
// Gather VFO data
|
// Gather VFO data
|
||||||
double vfoWidth = sigpath::vfoManager.getBandwidth(selectedVFO);
|
double vfoWidth = sigpath::vfoManager.getBandwidth(gui::waterfall.selectedVFO);
|
||||||
|
|
||||||
if (receiving) {
|
if (receiving) {
|
||||||
spdlog::warn("Receiving");
|
spdlog::warn("Receiving");
|
||||||
@ -145,26 +170,30 @@ private:
|
|||||||
if (maxLevel >= level) {
|
if (maxLevel >= level) {
|
||||||
lastSignalTime = now;
|
lastSignalTime = now;
|
||||||
}
|
}
|
||||||
else if ((std::chrono::duration_cast<std::chrono::milliseconds>(now - lastSignalTime)).count() > 1000.0) {
|
else if ((std::chrono::duration_cast<std::chrono::milliseconds>(now - lastSignalTime)).count() > lingerTime) {
|
||||||
receiving = false;
|
receiving = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
spdlog::warn("Seeking signal");
|
spdlog::warn("Seeking signal");
|
||||||
double bottomLimit = INFINITY;
|
double bottomLimit = current;
|
||||||
double topLimit = -INFINITY;
|
double topLimit = current;
|
||||||
|
|
||||||
// Search for a signal in scan direction
|
// 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();
|
gui::waterfall.releaseLatestFFT();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Search for signal in the inverse scan direction
|
// Search for signal in the inverse scan direction if direction isn't enforced
|
||||||
if (tuneIfAvailable(!scanUp, bottomLimit, topLimit, wfStart, wfEnd, wfWidth, vfoWidth, data, dataWidth)) {
|
if (!reverseLock) {
|
||||||
|
if (findSignal(!scanUp, bottomLimit, topLimit, wfStart, wfEnd, wfWidth, vfoWidth, data, dataWidth)) {
|
||||||
gui::waterfall.releaseLatestFFT();
|
gui::waterfall.releaseLatestFFT();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else { reverseLock = false; }
|
||||||
|
|
||||||
|
|
||||||
// There is no signal on the visible spectrum, tune in scan direction and retry
|
// There is no signal on the visible spectrum, tune in scan direction and retry
|
||||||
if (scanUp) {
|
if (scanUp) {
|
||||||
@ -172,7 +201,7 @@ private:
|
|||||||
if (current > stopFreq) { current = startFreq; }
|
if (current > stopFreq) { current = startFreq; }
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
current = topLimit - interval;
|
current = bottomLimit - interval;
|
||||||
if (current < startFreq) { current = stopFreq; }
|
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;
|
bool found = false;
|
||||||
double freq = current;
|
double freq = current;
|
||||||
for (freq += scanDir ? interval : -interval;
|
for (freq += scanDir ? interval : -interval;
|
||||||
@ -204,7 +233,7 @@ private:
|
|||||||
if (freq > topLimit) { topLimit = freq; }
|
if (freq > topLimit) { topLimit = freq; }
|
||||||
|
|
||||||
// Check signal level
|
// 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) {
|
if (maxLevel >= level) {
|
||||||
found = true;
|
found = true;
|
||||||
receiving = true;
|
receiving = true;
|
||||||
@ -231,15 +260,19 @@ private:
|
|||||||
bool enabled = true;
|
bool enabled = true;
|
||||||
|
|
||||||
bool running = false;
|
bool running = false;
|
||||||
std::string selectedVFO = "Radio";
|
//std::string selectedVFO = "Radio";
|
||||||
double startFreq = 93300000.0;
|
double startFreq = 88000000.0;
|
||||||
double stopFreq = 98700000.0;
|
double stopFreq = 108000000.0;
|
||||||
double interval = 100000.0;
|
double interval = 100000.0;
|
||||||
double current = 88000000.0;
|
double current = 88000000.0;
|
||||||
|
double passbandRatio = 10.0;
|
||||||
|
int tuningTime = 250;
|
||||||
|
int lingerTime = 1000.0;
|
||||||
float level = -50.0;
|
float level = -50.0;
|
||||||
bool receiving = true;
|
bool receiving = true;
|
||||||
bool tuning = false;
|
bool tuning = false;
|
||||||
bool scanUp = true;
|
bool scanUp = true;
|
||||||
|
bool reverseLock = false;
|
||||||
std::chrono::time_point<std::chrono::high_resolution_clock> lastSignalTime;
|
std::chrono::time_point<std::chrono::high_resolution_clock> lastSignalTime;
|
||||||
std::chrono::time_point<std::chrono::high_resolution_clock> lastTuneTime;
|
std::chrono::time_point<std::chrono::high_resolution_clock> lastTuneTime;
|
||||||
std::thread workerThread;
|
std::thread workerThread;
|
||||||
|
Loading…
Reference in New Issue
Block a user