mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2025-01-07 16:07:42 +00:00
Scanner cleanup (#1320)
* FreqmanDB in Scanner * Format * Add comment on squelch(0)
This commit is contained in:
parent
5ca74db2f9
commit
0a3aa706ef
@ -487,7 +487,7 @@ void FrequencyEditView::populate_bandwidth_options() {
|
|||||||
|
|
||||||
if (entry_.modulation < std::size(freqman_bandwidths)) {
|
if (entry_.modulation < std::size(freqman_bandwidths)) {
|
||||||
auto& bandwidths = freqman_bandwidths[entry_.modulation];
|
auto& bandwidths = freqman_bandwidths[entry_.modulation];
|
||||||
for (auto i = 1u; i < bandwidths.size(); ++i) {
|
for (auto i = 0u; i < bandwidths.size(); ++i) {
|
||||||
auto& item = bandwidths[i];
|
auto& item = bandwidths[i];
|
||||||
options.push_back({item.first, (OptionsField::value_t)i});
|
options.push_back({item.first, (OptionsField::value_t)i});
|
||||||
}
|
}
|
||||||
@ -500,7 +500,7 @@ void FrequencyEditView::populate_step_options() {
|
|||||||
OptionsField::options_t options;
|
OptionsField::options_t options;
|
||||||
options.push_back({"None", -1});
|
options.push_back({"None", -1});
|
||||||
|
|
||||||
for (auto i = 1u; i < freqman_steps.size(); ++i) {
|
for (auto i = 0u; i < freqman_steps.size(); ++i) {
|
||||||
auto& item = freqman_steps[i];
|
auto& item = freqman_steps[i];
|
||||||
options.push_back({item.first, (OptionsField::value_t)i});
|
options.push_back({item.first, (OptionsField::value_t)i});
|
||||||
}
|
}
|
||||||
@ -513,7 +513,7 @@ void FrequencyEditView::populate_tone_options() {
|
|||||||
OptionsField::options_t options;
|
OptionsField::options_t options;
|
||||||
options.push_back({"None", -1});
|
options.push_back({"None", -1});
|
||||||
|
|
||||||
for (auto i = 1u; i < tone_keys.size(); ++i) {
|
for (auto i = 0u; i < tone_keys.size(); ++i) {
|
||||||
auto& item = tone_keys[i];
|
auto& item = tone_keys[i];
|
||||||
options.push_back({fx100_string(item.second), (OptionsField::value_t)i});
|
options.push_back({fx100_string(item.second), (OptionsField::value_t)i});
|
||||||
}
|
}
|
||||||
|
@ -219,12 +219,15 @@ class FrequencyEditView : public View {
|
|||||||
{{0 * 8, 10 * 16}, "Description:", Color::light_grey()},
|
{{0 * 8, 10 * 16}, "Description:", Color::light_grey()},
|
||||||
};
|
};
|
||||||
|
|
||||||
OptionsField field_type{{13 * 8, 3 * 16}, 8, {
|
OptionsField field_type{
|
||||||
{"Single", 0},
|
{13 * 8, 3 * 16},
|
||||||
{"Range", 1},
|
8,
|
||||||
{"HamRadio", 2},
|
{
|
||||||
{"Raw", 3},
|
{"Single", 0},
|
||||||
}};
|
{"Range", 1},
|
||||||
|
{"HamRadio", 2},
|
||||||
|
{"Raw", 3},
|
||||||
|
}};
|
||||||
|
|
||||||
FrequencyField field_freq_a{{13 * 8, 4 * 16}};
|
FrequencyField field_freq_a{{13 * 8, 4 * 16}};
|
||||||
|
|
||||||
|
@ -21,20 +21,25 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ui_scanner.hpp"
|
#include "ui_scanner.hpp"
|
||||||
|
|
||||||
|
#include "optional.hpp"
|
||||||
#include "ui_fileman.hpp"
|
#include "ui_fileman.hpp"
|
||||||
#include "ui_freqman.hpp"
|
#include "ui_freqman.hpp"
|
||||||
|
|
||||||
using namespace portapack;
|
using namespace portapack;
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
namespace ui {
|
namespace ui {
|
||||||
|
|
||||||
|
static const fs::path default_scan_file{u"FREQMAN/SCANNER.TXT"};
|
||||||
|
|
||||||
ScannerThread::ScannerThread(std::vector<rf::Frequency> frequency_list)
|
ScannerThread::ScannerThread(std::vector<rf::Frequency> frequency_list)
|
||||||
: frequency_list_{std::move(frequency_list)} {
|
: frequency_list_{std::move(frequency_list)} {
|
||||||
_manual_search = false;
|
_manual_search = false;
|
||||||
create_thread();
|
create_thread();
|
||||||
}
|
}
|
||||||
|
|
||||||
ScannerThread::ScannerThread(const jammer::jammer_range_t& frequency_range, size_t def_step_hz)
|
ScannerThread::ScannerThread(const scanner_range_t& frequency_range, size_t def_step_hz)
|
||||||
: frequency_range_(frequency_range), def_step_hz_(def_step_hz) {
|
: frequency_range_(frequency_range), def_step_hz_(def_step_hz) {
|
||||||
_manual_search = true;
|
_manual_search = true;
|
||||||
create_thread();
|
create_thread();
|
||||||
@ -80,7 +85,7 @@ void ScannerThread::set_freq_del(const rf::Frequency v) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Force a one-time forward or reverse frequency index change; OK to do this without pausing scan thread
|
// Force a one-time forward or reverse frequency index change; OK to do this without pausing scan thread
|
||||||
//(used when rotary encoder is turned)
|
// (used when rotary encoder is turned)
|
||||||
void ScannerThread::set_index_stepper(const int32_t v) {
|
void ScannerThread::set_index_stepper(const int32_t v) {
|
||||||
_index_stepper = v;
|
_index_stepper = v;
|
||||||
}
|
}
|
||||||
@ -228,17 +233,26 @@ void ScannerView::handle_retune(int64_t freq, uint32_t freq_idx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!manual_search) {
|
if (!manual_search) {
|
||||||
if (frequency_list.size() > 0) {
|
if (entries.size() > 0)
|
||||||
text_current_index.set(to_string_dec_uint(freq_idx + 1, 3));
|
text_current_index.set(to_string_dec_uint(freq_idx + 1, 3));
|
||||||
}
|
|
||||||
|
|
||||||
if (freq_idx < description_list.size() && description_list[freq_idx].size() > 1)
|
if (freq_idx < entries.size() && entries[freq_idx].description.size() > 1)
|
||||||
desc_current_index.set(description_list[freq_idx]); // Show description from file
|
text_current_desc.set(entries[freq_idx].description); // Show description from file
|
||||||
else
|
else
|
||||||
desc_current_index.set(desc_freq_list_scan); // Show Scan file name (no description in file)
|
text_current_desc.set(loaded_filename()); // Show Scan file name (no description in file)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string ScannerView::loaded_filename() const {
|
||||||
|
auto filename = loaded_path.filename().string();
|
||||||
|
if (filename.length() > 23) { // Truncate and add ellipses if long file name
|
||||||
|
filename.resize(22);
|
||||||
|
filename = filename + "+";
|
||||||
|
}
|
||||||
|
|
||||||
|
return filename;
|
||||||
|
}
|
||||||
|
|
||||||
void ScannerView::focus() {
|
void ScannerView::focus() {
|
||||||
button_load.focus();
|
button_load.focus();
|
||||||
}
|
}
|
||||||
@ -254,46 +268,46 @@ ScannerView::~ScannerView() {
|
|||||||
void ScannerView::show_max_index() { // show total number of freqs to scan
|
void ScannerView::show_max_index() { // show total number of freqs to scan
|
||||||
text_current_index.set("---");
|
text_current_index.set("---");
|
||||||
|
|
||||||
if (frequency_list.size() == FREQMAN_MAX_PER_FILE) {
|
if (entries.size() == FREQMAN_MAX_PER_FILE) {
|
||||||
text_max_index.set_style(&Styles::red);
|
text_max_index.set_style(&Styles::red);
|
||||||
text_max_index.set("/ " + to_string_dec_uint(FREQMAN_MAX_PER_FILE) + " (DB MAX!)");
|
text_max_index.set("/ " + to_string_dec_uint(FREQMAN_MAX_PER_FILE) + " (DB MAX!)");
|
||||||
} else {
|
} else {
|
||||||
text_max_index.set_style(&Styles::grey);
|
text_max_index.set_style(&Styles::grey);
|
||||||
text_max_index.set("/ " + to_string_dec_uint(frequency_list.size()));
|
text_max_index.set("/ " + to_string_dec_uint(entries.size()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ScannerView::ScannerView(
|
ScannerView::ScannerView(
|
||||||
NavigationView& nav)
|
NavigationView& nav)
|
||||||
: nav_{nav}, loaded_file_name{"SCANNER"} {
|
: nav_{nav} {
|
||||||
add_children({&labels,
|
add_children({
|
||||||
&field_lna,
|
&labels,
|
||||||
&field_vga,
|
&field_lna,
|
||||||
&field_rf_amp,
|
&field_vga,
|
||||||
&field_volume,
|
&field_rf_amp,
|
||||||
&field_bw,
|
&field_volume,
|
||||||
&field_squelch,
|
&field_bw,
|
||||||
&field_browse_wait,
|
&field_squelch,
|
||||||
&field_lock_wait,
|
&field_browse_wait,
|
||||||
&button_load,
|
&field_lock_wait,
|
||||||
&button_clear,
|
&button_load,
|
||||||
&rssi,
|
&button_clear,
|
||||||
&text_current_index,
|
&rssi,
|
||||||
&text_max_index,
|
&text_current_index,
|
||||||
&desc_current_index,
|
&text_max_index,
|
||||||
&big_display,
|
&text_current_desc,
|
||||||
&button_manual_start,
|
&big_display,
|
||||||
&button_manual_end,
|
&button_manual_start,
|
||||||
&field_mode,
|
&button_manual_end,
|
||||||
&field_step,
|
&field_mode,
|
||||||
&button_manual_search,
|
&field_step,
|
||||||
&button_pause,
|
&button_manual_search,
|
||||||
&button_dir,
|
&button_pause,
|
||||||
&button_audio_app,
|
&button_dir,
|
||||||
&button_mic_app,
|
&button_audio_app,
|
||||||
&button_add,
|
&button_mic_app,
|
||||||
&button_remove
|
&button_add,
|
||||||
|
&button_remove,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Populate option text for these fields
|
// Populate option text for these fields
|
||||||
@ -312,14 +326,14 @@ ScannerView::ScannerView(
|
|||||||
frequency_range.max = stored_freq + 1000000;
|
frequency_range.max = stored_freq + 1000000;
|
||||||
button_manual_end.set_text(to_string_short_freq(frequency_range.max));
|
button_manual_end.set_text(to_string_short_freq(frequency_range.max));
|
||||||
|
|
||||||
// Button to load txt files from the FREQMAN folder
|
// Button to load a Freqman file.
|
||||||
button_load.on_select = [this, &nav](Button&) {
|
button_load.on_select = [this, &nav](Button&) {
|
||||||
auto open_view = nav.push<FileLoadView>(".TXT");
|
auto open_view = nav.push<FileLoadView>(".TXT");
|
||||||
open_view->push_dir(freqman_dir);
|
open_view->push_dir(freqman_dir);
|
||||||
open_view->on_changed = [this, &nav](std::filesystem::path new_file_path) {
|
open_view->on_changed = [this, &nav](std::filesystem::path new_file_path) {
|
||||||
if (new_file_path.native().find(freqman_dir.native()) == 0) {
|
if (new_file_path.native().find(freqman_dir.native()) == 0) {
|
||||||
scan_pause();
|
scan_pause();
|
||||||
frequency_file_load(new_file_path.stem().string(), true);
|
frequency_file_load(new_file_path);
|
||||||
} else {
|
} else {
|
||||||
nav.display_modal("LOAD ERROR", "A valid file from\nFREQMAN directory is\nrequired.");
|
nav.display_modal("LOAD ERROR", "A valid file from\nFREQMAN directory is\nrequired.");
|
||||||
}
|
}
|
||||||
@ -328,14 +342,13 @@ ScannerView::ScannerView(
|
|||||||
|
|
||||||
// Button to clear in-memory frequency list
|
// Button to clear in-memory frequency list
|
||||||
button_clear.on_select = [this, &nav](Button&) {
|
button_clear.on_select = [this, &nav](Button&) {
|
||||||
if (scan_thread && frequency_list.size()) {
|
if (scan_thread && entries.size()) {
|
||||||
scan_thread->stop(); // STOP SCANNER THREAD
|
scan_thread->stop(); // STOP SCANNER THREAD
|
||||||
frequency_list.clear();
|
entries.clear();
|
||||||
description_list.clear();
|
|
||||||
|
|
||||||
show_max_index(); // UPDATE new list size on screen
|
show_max_index(); // UPDATE new list size on screen
|
||||||
text_current_index.set("");
|
text_current_index.set("");
|
||||||
desc_current_index.set(desc_freq_list_scan);
|
text_current_desc.set(loaded_filename());
|
||||||
scan_thread->set_freq_lock(0); // Reset the scanner lock
|
scan_thread->set_freq_lock(0); // Reset the scanner lock
|
||||||
|
|
||||||
// FUTURE: Consider switching to manual search mode automatically after clear (but would need to validate freq range)
|
// FUTURE: Consider switching to manual search mode automatically after clear (but would need to validate freq range)
|
||||||
@ -404,16 +417,15 @@ ScannerView::ScannerView(
|
|||||||
|
|
||||||
// Button to delete current frequency from scan Freq List
|
// Button to delete current frequency from scan Freq List
|
||||||
button_remove.on_select = [this](Button&) {
|
button_remove.on_select = [this](Button&) {
|
||||||
if (scan_thread && (frequency_list.size() > current_index)) {
|
if (scan_thread && (entries.size() > current_index)) {
|
||||||
scan_thread->set_scanning(false); // PAUSE Scanning if necessary
|
scan_thread->set_scanning(false); // PAUSE Scanning if necessary
|
||||||
|
|
||||||
// Remove frequency from the Freq List in memory (it is not removed from the file)
|
// Remove frequency from the Freq List in memory (it is not removed from the file).
|
||||||
scan_thread->set_freq_del(frequency_list[current_index]);
|
scan_thread->set_freq_del(entries[current_index].freq);
|
||||||
description_list.erase(description_list.begin() + current_index);
|
entries.erase(entries.begin() + current_index);
|
||||||
frequency_list.erase(frequency_list.begin() + current_index);
|
|
||||||
|
|
||||||
show_max_index(); // UPDATE new list size on screen
|
show_max_index(); // UPDATE new list size on screen
|
||||||
desc_current_index.set(""); // Clean up description (cosmetic detail)
|
text_current_desc.set(""); // Clean up description (cosmetic detail)
|
||||||
scan_thread->set_freq_lock(0); // Reset the scanner lock
|
scan_thread->set_freq_lock(0); // Reset the scanner lock
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -432,15 +444,7 @@ ScannerView::ScannerView(
|
|||||||
manual_search = false; // Switch to List Scan mode
|
manual_search = false; // Switch to List Scan mode
|
||||||
}
|
}
|
||||||
|
|
||||||
audio::output::stop();
|
restart_scan();
|
||||||
|
|
||||||
if (scan_thread)
|
|
||||||
scan_thread->stop(); // STOP SCANNER THREAD
|
|
||||||
|
|
||||||
if (userpause) // If user-paused, resume
|
|
||||||
user_resume();
|
|
||||||
|
|
||||||
start_scan_thread(); // RESTART SCANNER THREAD in selected mode
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Mode field was changed (AM/NFM/WFM)
|
// Mode field was changed (AM/NFM/WFM)
|
||||||
@ -467,17 +471,8 @@ ScannerView::ScannerView(
|
|||||||
field_step.on_change = [this](size_t, OptionsField::value_t v) {
|
field_step.on_change = [this](size_t, OptionsField::value_t v) {
|
||||||
receiver_model.set_frequency_step(v);
|
receiver_model.set_frequency_step(v);
|
||||||
|
|
||||||
if (manual_search && scan_thread) {
|
if (manual_search && scan_thread)
|
||||||
// Restart scan thread with new step value
|
restart_scan();
|
||||||
scan_thread->stop(); // STOP SCANNER THREAD
|
|
||||||
|
|
||||||
// Resuming pause automatically
|
|
||||||
// FUTURE: Consider whether we should stay in Pause mode...
|
|
||||||
if (userpause) // If user-paused, resume
|
|
||||||
user_resume();
|
|
||||||
|
|
||||||
start_scan_thread(); // RESTART SCANNER THREAD in Manual Search mode
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Button to toggle Forward/Reverse
|
// Button to toggle Forward/Reverse
|
||||||
@ -491,68 +486,37 @@ ScannerView::ScannerView(
|
|||||||
bigdisplay_update(BDC_GREY); // Back to grey color
|
bigdisplay_update(BDC_GREY); // Back to grey color
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: remove this parsing?
|
|
||||||
// Button to add current frequency (found during Search) to the Scan Frequency List
|
// Button to add current frequency (found during Search) to the Scan Frequency List
|
||||||
button_add.on_select = [this](Button&) {
|
button_add.on_select = [this](Button&) {
|
||||||
File scanner_file;
|
FreqmanDB db;
|
||||||
const std::string freq_file_path = "FREQMAN/" + loaded_file_name + ".TXT";
|
if (db.open(loaded_path, /*create*/ true)) {
|
||||||
auto result = scanner_file.open(freq_file_path); // First search if freq is already in txt
|
freqman_entry entry{
|
||||||
|
.frequency_a = current_frequency,
|
||||||
|
.type = freqman_type::Single,
|
||||||
|
};
|
||||||
|
|
||||||
if (!result.is_valid()) {
|
// Look for existing entry with same frequency.
|
||||||
const std::string frequency_to_add = "f=" + to_string_dec_uint(current_frequency / 1000) + to_string_dec_uint(current_frequency % 1000UL, 3, '0');
|
auto it = db.find_entry([&entry](const auto& e) {
|
||||||
|
return e.frequency_a == entry.frequency_a;
|
||||||
bool found = false;
|
});
|
||||||
constexpr size_t buffer_size = 1024;
|
auto found = (it != db.end());
|
||||||
char buffer[buffer_size];
|
|
||||||
|
|
||||||
for (size_t pointer = 0, freq_str_idx = 0; pointer < scanner_file.size(); pointer += buffer_size) {
|
|
||||||
size_t adjusted_buffer_size;
|
|
||||||
if (pointer + buffer_size >= scanner_file.size()) {
|
|
||||||
memset(buffer, 0, sizeof(buffer));
|
|
||||||
adjusted_buffer_size = scanner_file.size() - pointer;
|
|
||||||
} else {
|
|
||||||
adjusted_buffer_size = buffer_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
scanner_file.seek(pointer);
|
|
||||||
scanner_file.read(buffer, adjusted_buffer_size);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < adjusted_buffer_size; ++i) {
|
|
||||||
if (buffer[i] == frequency_to_add.data()[freq_str_idx]) {
|
|
||||||
++freq_str_idx;
|
|
||||||
if (freq_str_idx >= frequency_to_add.size()) {
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
freq_str_idx = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (found) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (found) {
|
if (found) {
|
||||||
nav_.display_modal("Error", "Frequency already exists");
|
nav_.display_modal("Error", "Frequency already exists");
|
||||||
bigdisplay_update(-1); // After showing an error
|
bigdisplay_update(-1); // Need to poke this control after displaying modal?
|
||||||
} else {
|
} else {
|
||||||
scanner_file.append(freq_file_path); // Second: append if it is not there
|
db.append_entry(entry);
|
||||||
scanner_file.write_line(frequency_to_add);
|
|
||||||
|
|
||||||
// Add to frequency_list in memory too, since we can now switch back from manual mode
|
// Add to frequency_list in memory too, since we can now switch back from manual mode
|
||||||
// Note that we are allowing freqs to be added to file (code above) that exceed the max count we can load into memory
|
// Note that we are allowing freqs to be added to file (code above) that exceed the
|
||||||
if (frequency_list.size() < FREQMAN_MAX_PER_FILE) {
|
// max count we can load into memory.
|
||||||
frequency_list.push_back(current_frequency);
|
if (entries.size() < FREQMAN_MAX_PER_FILE) {
|
||||||
description_list.push_back("");
|
entries.push_back({current_frequency, ""});
|
||||||
|
|
||||||
show_max_index(); // Display updated frequency list size
|
show_max_index(); // Display updated frequency list size
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
nav_.display_modal("Error", "Cannot open " + loaded_file_name + ".TXT\nfor appending freq.");
|
nav_.display_modal("Error", "Cannot open " + loaded_path.filename().string() + "\nfor appending freq.");
|
||||||
bigdisplay_update(-1); // After showing an error
|
bigdisplay_update(-1); // Need to poke this control after displaying modal?
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -566,106 +530,76 @@ ScannerView::ScannerView(
|
|||||||
field_squelch.on_change = [this](int32_t v) { squelch = v; };
|
field_squelch.on_change = [this](int32_t v) { squelch = v; };
|
||||||
field_squelch.set_value(-30);
|
field_squelch.set_value(-30);
|
||||||
|
|
||||||
// LEARN FREQUENCIES
|
// LOAD FREQUENCIES
|
||||||
std::string scanner_txt = "SCANNER";
|
frequency_file_load(default_scan_file);
|
||||||
frequency_file_load(scanner_txt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScannerView::frequency_file_load(std::string file_name, bool stop_all_before) {
|
void ScannerView::frequency_file_load(const fs::path& path) {
|
||||||
bool found_range{false};
|
|
||||||
bool found_single{false};
|
|
||||||
freqman_index_t def_mod_index{freqman_invalid_index};
|
freqman_index_t def_mod_index{freqman_invalid_index};
|
||||||
freqman_index_t def_bw_index{freqman_invalid_index};
|
freqman_index_t def_bw_index{freqman_invalid_index};
|
||||||
freqman_index_t def_step_index{freqman_invalid_index};
|
freqman_index_t def_step_index{freqman_invalid_index};
|
||||||
|
|
||||||
// stop everything running now if required
|
FreqmanDB db;
|
||||||
if (stop_all_before) {
|
if (!db.open(path)) {
|
||||||
scan_thread->stop();
|
text_current_desc.set("NO " + path.filename().string());
|
||||||
frequency_list.clear(); // clear the existing frequency list (expected behavior)
|
loaded_path = default_scan_file;
|
||||||
description_list.clear();
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (load_freqman_file(file_name, database, {})) {
|
entries.clear();
|
||||||
loaded_file_name = file_name;
|
loaded_path = path;
|
||||||
for (auto& entry_ptr : database) {
|
Optional<scanner_range_t> range;
|
||||||
if (frequency_list.size() >= FREQMAN_MAX_PER_FILE)
|
|
||||||
|
for (auto entry : db) {
|
||||||
|
if (is_invalid(def_mod_index))
|
||||||
|
def_mod_index = entry.modulation;
|
||||||
|
|
||||||
|
if (is_invalid(def_bw_index))
|
||||||
|
def_bw_index = entry.bandwidth;
|
||||||
|
|
||||||
|
if (is_invalid(def_step_index))
|
||||||
|
def_step_index = entry.step;
|
||||||
|
|
||||||
|
switch (entry.type) {
|
||||||
|
case freqman_type::Single:
|
||||||
|
entries.push_back({entry.frequency_a, entry.description});
|
||||||
|
break;
|
||||||
|
case freqman_type::HamRadio:
|
||||||
|
entries.push_back({entry.frequency_a, "R: " + entry.description});
|
||||||
|
entries.push_back({entry.frequency_b, "T: " + entry.description});
|
||||||
|
break;
|
||||||
|
case freqman_type::Range:
|
||||||
|
// NB: Only the first range will be loaded.
|
||||||
|
if (!range)
|
||||||
|
range = {entry.frequency_a, entry.frequency_b};
|
||||||
|
break;
|
||||||
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
auto& entry = *entry_ptr;
|
|
||||||
|
|
||||||
// Get modulation & bw & step from file if specified
|
|
||||||
// Note these values could be different for each line in the file, but we only look at the first one
|
|
||||||
//
|
|
||||||
// Note that freqman requires a very specific string for these parameters,
|
|
||||||
// so check syntax in frequency file if specified value isn't being loaded
|
|
||||||
//
|
|
||||||
if (is_invalid(def_mod_index))
|
|
||||||
def_mod_index = entry.modulation;
|
|
||||||
|
|
||||||
if (is_invalid(def_bw_index))
|
|
||||||
def_bw_index = entry.bandwidth;
|
|
||||||
|
|
||||||
if (is_invalid(def_step_index))
|
|
||||||
def_step_index = entry.step;
|
|
||||||
|
|
||||||
// Get frequency
|
|
||||||
if (entry.type == freqman_type::Range) {
|
|
||||||
if (!found_range) {
|
|
||||||
// Set Start & End Search Range instead of populating the small in-memory frequency table
|
|
||||||
// NOTE: There may be multiple single frequencies in file, but only one search range is supported.
|
|
||||||
found_range = true;
|
|
||||||
frequency_range.min = entry.frequency_a;
|
|
||||||
button_manual_start.set_text(to_string_short_freq(frequency_range.min));
|
|
||||||
frequency_range.max = entry.frequency_b;
|
|
||||||
button_manual_end.set_text(to_string_short_freq(frequency_range.max));
|
|
||||||
}
|
|
||||||
} else if (entry.type == freqman_type::Single) {
|
|
||||||
found_single = true;
|
|
||||||
frequency_list.push_back(entry.frequency_a);
|
|
||||||
description_list.push_back(entry.description);
|
|
||||||
} else if (entry.type == freqman_type::HamRadio) {
|
|
||||||
// For HAM repeaters, add both receive & transmit frequencies to scan list and modify description
|
|
||||||
// (FUTURE fw versions might handle these differently)
|
|
||||||
found_single = true;
|
|
||||||
frequency_list.push_back(entry.frequency_a);
|
|
||||||
description_list.push_back("R:" + entry.description);
|
|
||||||
|
|
||||||
if ((entry.frequency_a != entry.frequency_b) &&
|
|
||||||
(frequency_list.size() < FREQMAN_MAX_PER_FILE)) {
|
|
||||||
frequency_list.push_back(entry.frequency_b);
|
|
||||||
description_list.push_back("T:" + entry.description);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
loaded_file_name = "SCANNER"; // back to the default frequency file
|
|
||||||
desc_current_index.set(" NO " + file_name + ".TXT FILE ...");
|
|
||||||
}
|
|
||||||
|
|
||||||
desc_freq_list_scan = loaded_file_name + ".TXT";
|
if (entries.size() >= FREQMAN_MAX_PER_FILE)
|
||||||
if (desc_freq_list_scan.length() > 23) { // Truncate description and add ellipses if long file name
|
break;
|
||||||
desc_freq_list_scan.resize(20);
|
|
||||||
desc_freq_list_scan = desc_freq_list_scan + "...";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_valid(def_mod_index) && def_mod_index != (freqman_index_t)field_mode.selected_index_value())
|
if (is_valid(def_mod_index) && def_mod_index != (freqman_index_t)field_mode.selected_index_value())
|
||||||
field_mode.set_by_value(def_mod_index); // Update mode (also triggers a change callback that disables & reenables RF background)
|
field_mode.set_by_value(def_mod_index);
|
||||||
|
|
||||||
if (is_valid(def_bw_index)) // Update BW if specified in file
|
if (is_valid(def_bw_index))
|
||||||
field_bw.set_selected_index(def_bw_index);
|
field_bw.set_selected_index(def_bw_index);
|
||||||
|
|
||||||
if (is_valid(def_step_index)) // Update step if specified in file
|
if (is_valid(def_step_index))
|
||||||
field_step.set_selected_index(def_step_index);
|
field_step.set_selected_index(def_step_index);
|
||||||
|
|
||||||
audio::output::stop();
|
// Found range, set it and update UI.
|
||||||
|
if (range) {
|
||||||
|
frequency_range = *range;
|
||||||
|
button_manual_start.set_text(to_string_short_freq(frequency_range.min));
|
||||||
|
button_manual_end.set_text(to_string_short_freq(frequency_range.max));
|
||||||
|
}
|
||||||
|
|
||||||
if (userpause) // If user-paused, resume
|
// Scan entries if any, otherwise do manual range search.
|
||||||
user_resume();
|
manual_search = entries.empty();
|
||||||
|
restart_scan();
|
||||||
// Scan list if we found one, otherwise do manual range search
|
|
||||||
manual_search = !found_single;
|
|
||||||
|
|
||||||
start_scan_thread();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScannerView::update_squelch_while_paused(int32_t max_db) {
|
void ScannerView::update_squelch_while_paused(int32_t max_db) {
|
||||||
@ -754,7 +688,8 @@ void ScannerView::user_resume() {
|
|||||||
userpause = false; // Resume scanning
|
userpause = false; // Resume scanning
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScannerView::change_mode(freqman_index_t new_mod) { // Before this, do a scan_thread->stop(); After this do a start_scan_thread()
|
// Before this, do a scan_thread->stop(); After this do a start_scan_thread()
|
||||||
|
void ScannerView::change_mode(freqman_index_t new_mod) {
|
||||||
using option_t = std::pair<std::string, int32_t>;
|
using option_t = std::pair<std::string, int32_t>;
|
||||||
using options_t = std::vector<option_t>;
|
using options_t = std::vector<option_t>;
|
||||||
options_t bw;
|
options_t bw;
|
||||||
@ -791,22 +726,41 @@ void ScannerView::change_mode(freqman_index_t new_mod) { // Before this, do a s
|
|||||||
|
|
||||||
void ScannerView::start_scan_thread() {
|
void ScannerView::start_scan_thread() {
|
||||||
receiver_model.enable();
|
receiver_model.enable();
|
||||||
|
// Disable squelch on the model because RSSI handler is where the
|
||||||
|
// actual squelching is applied for this app.
|
||||||
receiver_model.set_squelch_level(0);
|
receiver_model.set_squelch_level(0);
|
||||||
show_max_index();
|
show_max_index();
|
||||||
|
|
||||||
// Start Scanner Thread
|
// Start Scanner Thread
|
||||||
// FUTURE: Consider passing additional control flags (fwd,userpause,etc) to scanner thread at start (perhaps in a data structure)
|
|
||||||
if (manual_search) {
|
if (manual_search) {
|
||||||
button_manual_search.set_text("SCAN"); // Update meaning of Manual Scan button
|
button_manual_search.set_text("SCAN"); // Update meaning of Manual Scan button
|
||||||
desc_current_index.set(desc_freq_range_search);
|
text_current_desc.set("SEARCHING...");
|
||||||
scan_thread = std::make_unique<ScannerThread>(frequency_range, field_step.selected_index_value());
|
scan_thread = std::make_unique<ScannerThread>(frequency_range, field_step.selected_index_value());
|
||||||
} else {
|
} else {
|
||||||
button_manual_search.set_text("SRCH"); // Update meaning of Manual Scan button
|
button_manual_search.set_text("SRCH"); // Update meaning of Manual Scan button
|
||||||
desc_current_index.set(desc_freq_list_scan);
|
text_current_desc.set(loaded_filename());
|
||||||
scan_thread = std::make_unique<ScannerThread>(frequency_list);
|
|
||||||
|
// TODO: just pass ref to the thread?
|
||||||
|
std::vector<rf::Frequency> frequency_list;
|
||||||
|
frequency_list.reserve(entries.size());
|
||||||
|
for (const auto& entry : entries)
|
||||||
|
frequency_list.push_back(entry.freq);
|
||||||
|
|
||||||
|
scan_thread = std::make_unique<ScannerThread>(std::move(frequency_list));
|
||||||
}
|
}
|
||||||
|
|
||||||
scan_thread->set_scanning_direction(fwd);
|
scan_thread->set_scanning_direction(fwd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ScannerView::restart_scan() {
|
||||||
|
audio::output::stop();
|
||||||
|
if (scan_thread) // STOP SCANNER THREAD
|
||||||
|
scan_thread->stop();
|
||||||
|
|
||||||
|
if (userpause) // If user-paused, resume
|
||||||
|
user_resume();
|
||||||
|
|
||||||
|
start_scan_thread(); // RESTART SCANNER THREAD in selected mode
|
||||||
|
}
|
||||||
|
|
||||||
} /* namespace ui */
|
} /* namespace ui */
|
||||||
|
@ -20,19 +20,20 @@
|
|||||||
* Boston, MA 02110-1301, USA.
|
* Boston, MA 02110-1301, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ui.hpp"
|
#include "audio.hpp"
|
||||||
#include "receiver_model.hpp"
|
#include "analog_audio_app.hpp"
|
||||||
|
#include "baseband_api.hpp"
|
||||||
|
#include "file.hpp"
|
||||||
|
#include "freqman.hpp"
|
||||||
|
#include "freqman_db.hpp"
|
||||||
|
#include "portapack_persistent_memory.hpp"
|
||||||
#include "radio_state.hpp"
|
#include "radio_state.hpp"
|
||||||
|
#include "receiver_model.hpp"
|
||||||
|
#include "string_format.hpp"
|
||||||
|
#include "ui.hpp"
|
||||||
|
#include "ui_mictx.hpp"
|
||||||
#include "ui_receiver.hpp"
|
#include "ui_receiver.hpp"
|
||||||
#include "ui_styles.hpp"
|
#include "ui_styles.hpp"
|
||||||
#include "freqman.hpp"
|
|
||||||
#include "analog_audio_app.hpp"
|
|
||||||
#include "audio.hpp"
|
|
||||||
#include "ui_mictx.hpp"
|
|
||||||
#include "portapack_persistent_memory.hpp"
|
|
||||||
#include "baseband_api.hpp"
|
|
||||||
#include "string_format.hpp"
|
|
||||||
#include "file.hpp"
|
|
||||||
|
|
||||||
#define SCANNER_SLEEP_MS 50 // ms that Scanner Thread sleeps per loop
|
#define SCANNER_SLEEP_MS 50 // ms that Scanner Thread sleeps per loop
|
||||||
#define STATISTICS_UPDATES_PER_SEC 10
|
#define STATISTICS_UPDATES_PER_SEC 10
|
||||||
@ -40,10 +41,28 @@
|
|||||||
|
|
||||||
namespace ui {
|
namespace ui {
|
||||||
|
|
||||||
|
// TODO: There is too much duplicated data in these classes.
|
||||||
|
// ScannerThread should just use more from the View.
|
||||||
|
// Or perhaps ScannerThread should just be in the View.
|
||||||
|
|
||||||
|
// TODO: Too many functions mix work and UI update.
|
||||||
|
// Consolidate UI fixup to a single function.
|
||||||
|
|
||||||
|
// TODO: Just use freqman_entry.
|
||||||
|
struct scanner_entry_t {
|
||||||
|
rf::Frequency freq;
|
||||||
|
std::string description;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct scanner_range_t {
|
||||||
|
int64_t min;
|
||||||
|
int64_t max;
|
||||||
|
};
|
||||||
|
|
||||||
class ScannerThread {
|
class ScannerThread {
|
||||||
public:
|
public:
|
||||||
ScannerThread(std::vector<rf::Frequency> frequency_list);
|
ScannerThread(std::vector<rf::Frequency> frequency_list);
|
||||||
ScannerThread(const jammer::jammer_range_t& frequency_range, size_t def_step_hz);
|
ScannerThread(const scanner_range_t& frequency_range, size_t def_step_hz);
|
||||||
~ScannerThread();
|
~ScannerThread();
|
||||||
|
|
||||||
void set_scanning(const bool v);
|
void set_scanning(const bool v);
|
||||||
@ -65,7 +84,7 @@ class ScannerThread {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<rf::Frequency> frequency_list_{};
|
std::vector<rf::Frequency> frequency_list_{};
|
||||||
jammer::jammer_range_t frequency_range_{false, 0, 0};
|
scanner_range_t frequency_range_{0, 0};
|
||||||
size_t def_step_hz_{0};
|
size_t def_step_hz_{0};
|
||||||
Thread* thread{nullptr};
|
Thread* thread{nullptr};
|
||||||
|
|
||||||
@ -89,10 +108,6 @@ class ScannerView : public View {
|
|||||||
void focus() override;
|
void focus() override;
|
||||||
|
|
||||||
std::string title() const override { return "Scanner"; };
|
std::string title() const override { return "Scanner"; };
|
||||||
std::vector<rf::Frequency> frequency_list{};
|
|
||||||
std::vector<std::string> description_list{};
|
|
||||||
|
|
||||||
// void set_parent_rect(const Rect new_parent_rect) override;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
app_settings::SettingsManager settings_{
|
app_settings::SettingsManager settings_{
|
||||||
@ -102,18 +117,21 @@ class ScannerView : public View {
|
|||||||
RxRadioState radio_state_{};
|
RxRadioState radio_state_{};
|
||||||
|
|
||||||
void start_scan_thread();
|
void start_scan_thread();
|
||||||
|
void restart_scan();
|
||||||
void change_mode(freqman_index_t mod_type);
|
void change_mode(freqman_index_t mod_type);
|
||||||
void show_max_index();
|
void show_max_index();
|
||||||
void scan_pause();
|
void scan_pause();
|
||||||
void scan_resume();
|
void scan_resume();
|
||||||
void user_resume();
|
void user_resume();
|
||||||
void frequency_file_load(std::string file_name, bool stop_all_before = false);
|
void frequency_file_load(const std::filesystem::path& path);
|
||||||
void bigdisplay_update(int32_t);
|
void bigdisplay_update(int32_t);
|
||||||
void update_squelch_while_paused(int32_t max_db);
|
void update_squelch_while_paused(int32_t max_db);
|
||||||
void on_statistics_update(const ChannelStatistics& statistics);
|
void on_statistics_update(const ChannelStatistics& statistics);
|
||||||
void handle_retune(int64_t freq, uint32_t freq_idx);
|
void handle_retune(int64_t freq, uint32_t freq_idx);
|
||||||
|
|
||||||
jammer::jammer_range_t frequency_range{false, 0, 0}; // perfect for manual scan task too...
|
std::string loaded_filename() const;
|
||||||
|
|
||||||
|
scanner_range_t frequency_range{0, 0};
|
||||||
int32_t squelch{0};
|
int32_t squelch{0};
|
||||||
uint32_t browse_timer{0};
|
uint32_t browse_timer{0};
|
||||||
uint32_t lock_timer{0};
|
uint32_t lock_timer{0};
|
||||||
@ -122,10 +140,12 @@ class ScannerView : public View {
|
|||||||
rf::Frequency bigdisplay_current_frequency{0};
|
rf::Frequency bigdisplay_current_frequency{0};
|
||||||
uint32_t browse_wait{0};
|
uint32_t browse_wait{0};
|
||||||
uint32_t lock_wait{0};
|
uint32_t lock_wait{0};
|
||||||
freqman_db database{};
|
|
||||||
std::string loaded_file_name;
|
std::filesystem::path loaded_path{};
|
||||||
|
std::vector<scanner_entry_t> entries{};
|
||||||
uint32_t current_index{0};
|
uint32_t current_index{0};
|
||||||
rf::Frequency current_frequency{0};
|
rf::Frequency current_frequency{0};
|
||||||
|
|
||||||
bool userpause{false};
|
bool userpause{false};
|
||||||
bool manual_search{false};
|
bool manual_search{false};
|
||||||
bool fwd{true}; // to preserve direction setting even if scan_thread restarted
|
bool fwd{true}; // to preserve direction setting even if scan_thread restarted
|
||||||
@ -137,9 +157,6 @@ class ScannerView : public View {
|
|||||||
BDC_RED
|
BDC_RED
|
||||||
};
|
};
|
||||||
|
|
||||||
std::string desc_freq_range_search = "SEARCHING...";
|
|
||||||
std::string desc_freq_list_scan = "";
|
|
||||||
|
|
||||||
Labels labels{
|
Labels labels{
|
||||||
{{0 * 8, 0 * 16}, "LNA: VGA: AMP: VOL:", Color::light_grey()},
|
{{0 * 8, 0 * 16}, "LNA: VGA: AMP: VOL:", Color::light_grey()},
|
||||||
{{0 * 8, 1 * 16}, "BW: SQ: Wsa: Wsl:", Color::light_grey()},
|
{{0 * 8, 1 * 16}, "BW: SQ: Wsa: Wsl:", Color::light_grey()},
|
||||||
@ -204,7 +221,7 @@ class ScannerView : public View {
|
|||||||
{4 * 8, 3 * 16, 18 * 8, 16},
|
{4 * 8, 3 * 16, 18 * 8, 16},
|
||||||
};
|
};
|
||||||
|
|
||||||
Text desc_current_index{
|
Text text_current_desc{
|
||||||
{0, 4 * 16, 240 - 6 * 8, 16},
|
{0, 4 * 16, 240 - 6 * 8, 16},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user