Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 24 additions & 4 deletions sources/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <config_migrator.h>
#include <logger.h>
#include <radio/sdr_device_reader.h>
#include <utils/radio_utils.h>
#include <utils/utils.h>

#include <fstream>
Expand All @@ -24,7 +25,11 @@ spdlog::level::level_enum parseLogLevel(const std::string& level) {
return spdlog::level::level_enum::off;
}

Config::Config(const ArgConfig& argConfig, const FileConfig& fileConfig) : m_id(!argConfig.id.empty() ? argConfig.id : randomHex(8)), m_argConfig(argConfig), m_fileConfig(fileConfig) {}
Config::Config(const ArgConfig& argConfig, const FileConfig& fileConfig)
: m_id(!argConfig.id.empty() ? argConfig.id : randomHex(8)),
m_argConfig(argConfig),
m_fileConfig(fileConfig),
m_ignoredRanges(buildIgnoredRanges(fileConfig)) {}
std::string Config::mqtt() const { return fmt::format("{}@{}", m_argConfig.mqttUser, m_argConfig.mqttUrl); };

std::string Config::getId() const { return m_id; }
Expand All @@ -34,13 +39,28 @@ bool Config::isColorLogEnabled() const { return m_fileConfig.output.color_log_en
spdlog::level::level_enum Config::consoleLogLevel() const { return parseLogLevel(m_fileConfig.output.console_log_level); }
spdlog::level::level_enum Config::fileLogLevel() const { return parseLogLevel(m_fileConfig.output.file_log_level); }

std::vector<FrequencyRange> Config::ignoredRanges() const {
std::vector<FrequencyRange> Config::buildIgnoredRanges(const FileConfig& fileConfig) {
std::vector<FrequencyRange> scanRanges;
for (const auto& device : fileConfig.devices) {
if (!device.enabled) {
continue;
}
scanRanges.insert(scanRanges.end(), device.ranges.begin(), device.ranges.end());
}

std::vector<FrequencyRange> ranges;
for (const auto& range : m_fileConfig.ignored_frequencies) {
ranges.reserve(fileConfig.ignored_frequencies.size());
for (const auto& range : fileConfig.ignored_frequencies) {
ranges.emplace_back(range.frequency - range.bandwidth / 2, range.frequency + range.bandwidth / 2);
}
return ranges;
return mergeOverlappingRanges(filterRangesOverlapping(ranges, scanRanges));
}

std::size_t Config::ignoredFrequencyCount() const { return m_fileConfig.ignored_frequencies.size(); }

const std::vector<FrequencyRange>& Config::ignoredRanges() const { return m_ignoredRanges; }

bool Config::isFrequencyIgnored(Frequency frequency) const { return isFrequencyInRanges(m_ignoredRanges, frequency); }
int Config::recordersCount() const {
const auto max_workers = static_cast<int>(std::thread::hardware_concurrency());
const auto auto_workers = max_workers / 2;
Expand Down
8 changes: 7 additions & 1 deletion sources/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <radio/help_structures.h>

#include <chrono>
#include <cstddef>
#include <nlohmann/json.hpp>
#include <string>

Expand Down Expand Up @@ -53,7 +54,9 @@ class Config {
spdlog::level::level_enum consoleLogLevel() const;
spdlog::level::level_enum fileLogLevel() const;

std::vector<FrequencyRange> ignoredRanges() const;
std::size_t ignoredFrequencyCount() const;
const std::vector<FrequencyRange>& ignoredRanges() const;
bool isFrequencyIgnored(Frequency frequency) const;
int recordersCount() const;
Frequency recordingBandwidth() const;
std::chrono::milliseconds recordingMinTime() const;
Expand All @@ -73,7 +76,10 @@ class Config {
bool dumpRecording() const;

private:
static std::vector<FrequencyRange> buildIgnoredRanges(const FileConfig& fileConfig);

const std::string m_id;
const ArgConfig& m_argConfig;
const FileConfig& m_fileConfig;
const std::vector<FrequencyRange> m_ignoredRanges;
};
13 changes: 4 additions & 9 deletions sources/radio/blocks/transmission.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ void Transmission::addSignals(const float* avgPower, const float* rawPower, cons
for (const auto& index : indexes) {
if (!containsWithMargin(m_signals, index, m_groupSize)) {
const auto bestIndex = getBestIndex(index);
if (isIndexIgnored(bestIndex)) {
continue;
}
const auto bestTunedFrequency = getTunedFrequency(m_indexToFrequency(bestIndex), m_config.recordingTuningStep());
Logger::info(
LABEL,
Expand Down Expand Up @@ -140,15 +143,7 @@ Transmission::Index Transmission::getBestIndex(Index index) const {
return mostFrequentIndex;
}

bool Transmission::isIndexIgnored(const Index& index) const {
const auto frequency = m_indexToFrequency(index);
for (const auto& range : m_config.ignoredRanges()) {
if (range.contains(frequency)) {
return true;
}
}
return false;
}
bool Transmission::isIndexIgnored(const Index& index) const { return m_config.isFrequencyIgnored(m_indexToFrequency(index)); }

std::vector<Recording> Transmission::getSortedTransmissions(const std::chrono::milliseconds now) const {
std::vector<Index> indexes;
Expand Down
2 changes: 1 addition & 1 deletion sources/scanner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Scanner::Scanner(const Config& config, const Device& device, RemoteController& r
m_isRunning(true),
m_thread([this]() { worker(); }) {
Logger::info(LABEL, "starting");
Logger::info(LABEL, "ignored ranges: {}", colored(GREEN, "{}", config.ignoredRanges().size()));
Logger::info(LABEL, "ignored frequencies: {}, active ranges: {}", colored(GREEN, "{}", config.ignoredFrequencyCount()), colored(GREEN, "{}", config.ignoredRanges().size()));
for (const auto& range : config.ignoredRanges()) {
Logger::info(LABEL, "ignored range: {}", formatFrequencyRange(range));
}
Expand Down
56 changes: 55 additions & 1 deletion sources/utils/radio_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
#include <logger.h>
#include <utils/utils.h>

#include <algorithm>
#include <filesystem>
#include <iterator>
#include <numeric>

namespace {
Expand Down Expand Up @@ -208,4 +210,56 @@ std::vector<FrequencyRange> splitRanges(const std::vector<FrequencyRange>& range
}
}
return results;
}
}

std::vector<FrequencyRange> filterRangesOverlapping(const std::vector<FrequencyRange>& ranges, const std::vector<FrequencyRange>& bounds) {
if (bounds.empty()) {
return ranges;
}
std::vector<FrequencyRange> results;
results.reserve(ranges.size());
for (const auto& range : ranges) {
for (const auto& bound : bounds) {
if (range.start <= bound.stop && bound.start <= range.stop) {
results.push_back(range);
break;
}
}
}
return results;
}

std::vector<FrequencyRange> mergeOverlappingRanges(std::vector<FrequencyRange> ranges) {
if (ranges.size() <= 1) {
return ranges;
}
std::sort(ranges.begin(), ranges.end(), [](const FrequencyRange& a, const FrequencyRange& b) {
if (a.start != b.start) {
return a.start < b.start;
}
return a.stop < b.stop;
});
std::vector<FrequencyRange> merged;
merged.reserve(ranges.size());
merged.push_back(ranges.front());
for (size_t i = 1; i < ranges.size(); ++i) {
auto& last = merged.back();
if (ranges[i].start <= last.stop) {
last.stop = std::max(last.stop, ranges[i].stop);
} else {
merged.push_back(ranges[i]);
}
}
return merged;
}

bool isFrequencyInRanges(const std::vector<FrequencyRange>& ranges, Frequency frequency) {
if (ranges.empty()) {
return false;
}
const auto it = std::upper_bound(ranges.begin(), ranges.end(), frequency, [](Frequency value, const FrequencyRange& range) { return value < range.start; });
if (it == ranges.begin()) {
return false;
}
return std::prev(it)->contains(frequency);
}
8 changes: 7 additions & 1 deletion sources/utils/radio_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,10 @@ Frequency getRangeSplitSampleRate(Frequency sampleRate);

std::vector<FrequencyRange> splitRange(const FrequencyRange& range, Frequency sampleRate);

std::vector<FrequencyRange> splitRanges(const std::vector<FrequencyRange>& ranges, Frequency sampleRate);
std::vector<FrequencyRange> splitRanges(const std::vector<FrequencyRange>& ranges, Frequency sampleRate);

std::vector<FrequencyRange> filterRangesOverlapping(const std::vector<FrequencyRange>& ranges, const std::vector<FrequencyRange>& bounds);

std::vector<FrequencyRange> mergeOverlappingRanges(std::vector<FrequencyRange> ranges);

bool isFrequencyInRanges(const std::vector<FrequencyRange>& ranges, Frequency frequency);
29 changes: 29 additions & 0 deletions tests/test_radio_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,3 +130,32 @@ TEST(RadioUtils, SplitRanges) {
EXPECT_EQ(splitRange({140000000, 145000000}, 2000000), Ranges({{140000000, 142000000}, {142000000, 144000000}, {144000000, 146000000}}));
EXPECT_EQ(splitRange({140000000, 150000000}, 2000000), Ranges({{140000000, 142000000}, {142000000, 144000000}, {144000000, 146000000}, {146000000, 148000000}, {148000000, 150000000}}));
}

TEST(RadioUtils, FilterRangesOverlapping) {
using Ranges = std::vector<FrequencyRange>;
const Ranges scan({{432000000, 440000000}});
EXPECT_EQ(filterRangesOverlapping(Ranges({{100000000, 100025000}, {432350000, 432375000}, {450000000, 450025000}}), scan), Ranges({{432350000, 432375000}}));
EXPECT_EQ(filterRangesOverlapping(Ranges({{431990000, 432010000}}), scan), Ranges({{431990000, 432010000}}));
EXPECT_EQ(filterRangesOverlapping(Ranges({{432350000, 432375000}}), Ranges{}), Ranges({{432350000, 432375000}}));
}

TEST(RadioUtils, MergeOverlappingRanges) {
using Ranges = std::vector<FrequencyRange>;
EXPECT_EQ(mergeOverlappingRanges(Ranges({{100, 200}, {200, 300}, {400, 500}})), Ranges({{100, 300}, {400, 500}}));
EXPECT_EQ(mergeOverlappingRanges(Ranges({{150, 180}, {100, 160}, {170, 190}})), Ranges({{100, 190}}));
EXPECT_EQ(mergeOverlappingRanges(Ranges({{100, 120}, {130, 140}})), Ranges({{100, 120}, {130, 140}}));
}

TEST(RadioUtils, IsFrequencyInRanges) {
using Ranges = std::vector<FrequencyRange>;
const Ranges ranges({{100, 200}, {400, 500}});
EXPECT_FALSE(isFrequencyInRanges(ranges, 99));
EXPECT_TRUE(isFrequencyInRanges(ranges, 100));
EXPECT_TRUE(isFrequencyInRanges(ranges, 200));
EXPECT_FALSE(isFrequencyInRanges(ranges, 201));
EXPECT_FALSE(isFrequencyInRanges(ranges, 399));
EXPECT_TRUE(isFrequencyInRanges(ranges, 400));
EXPECT_TRUE(isFrequencyInRanges(ranges, 500));
EXPECT_FALSE(isFrequencyInRanges(ranges, 501));
EXPECT_FALSE(isFrequencyInRanges(Ranges{}, 100));
}