mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2026-09-11 09:09:29 +00:00
Make detector use freqman (#3119)
* make detector list a freqman file * add file loading ability, autoscan/pause, step in on pause on range, frequency value display * Update firmware/application/external/detector_rx/ui_detector_rx.hpp * Update firmware/application/external/detector_rx/ui_detector_rx.cpp * add 750 kHz step * revamp UI and add auto advance, auto scan, and only display 'RANGE SCAN...' when auto scan is on on ranges to avoid flicker of the hell. * adjust as I can the ranges as they where before * Update sdcard/FREQMAN/DETECTOR.TXT * fix instance related copilot remark
This commit is contained in:
+177
-46
@@ -26,6 +26,7 @@
|
|||||||
#include "ui_freqman.hpp"
|
#include "ui_freqman.hpp"
|
||||||
#include "baseband_api.hpp"
|
#include "baseband_api.hpp"
|
||||||
#include "file.hpp"
|
#include "file.hpp"
|
||||||
|
#include "file_path.hpp"
|
||||||
#include "oversample.hpp"
|
#include "oversample.hpp"
|
||||||
#include "ui_font_fixed_8x16.hpp"
|
#include "ui_font_fixed_8x16.hpp"
|
||||||
|
|
||||||
@@ -35,36 +36,112 @@ using portapack::memory::map::backup_ram;
|
|||||||
|
|
||||||
namespace ui::external_app::detector_rx {
|
namespace ui::external_app::detector_rx {
|
||||||
|
|
||||||
// Function to map the value from one range to another
|
|
||||||
int32_t DetectorRxView::map(int32_t value, int32_t fromLow, int32_t fromHigh, int32_t toLow, int32_t toHigh) {
|
int32_t DetectorRxView::map(int32_t value, int32_t fromLow, int32_t fromHigh, int32_t toLow, int32_t toHigh) {
|
||||||
return toLow + (value - fromLow) * (toHigh - toLow) / (fromHigh - fromLow);
|
return toLow + (value - fromLow) * (toHigh - toLow) / (fromHigh - fromLow);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DetectorRxView::focus() {
|
void DetectorRxView::focus() {
|
||||||
field_lna.focus();
|
button_index.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
DetectorRxView::~DetectorRxView() {
|
DetectorRxView::~DetectorRxView() {
|
||||||
// reset performance counters request to default
|
|
||||||
shared_memory.request_m4_performance_counter = 0;
|
shared_memory.request_m4_performance_counter = 0;
|
||||||
receiver_model.disable();
|
receiver_model.disable();
|
||||||
audio::output::stop();
|
audio::output::stop();
|
||||||
baseband::shutdown();
|
baseband::shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DetectorRxView::on_timer() {
|
std::string DetectorRxView::format_freq_mhz(int64_t freq_hz) {
|
||||||
freq_index++;
|
int64_t mhz = freq_hz / 1000000;
|
||||||
if (freq_mode == 0 && freq_index >= tetra_uplink_monitoring_frequencies_hz.size()) freq_index = 0; // TETRA UP
|
int64_t khz_frac = (freq_hz % 1000000) / 1000;
|
||||||
if (freq_mode == 1 && freq_index >= lora_monitoring_frequencies_hz.size()) freq_index = 0; // Lora
|
return "< " + to_string_dec_uint(mhz) + "." + to_string_dec_uint(khz_frac, 3, '0') + " MHz >";
|
||||||
if (freq_mode == 2 && freq_index >= remotes_monitoring_frequencies_hz.size()) freq_index = 0; // Remotes
|
}
|
||||||
|
|
||||||
if (freq_mode == 2)
|
void DetectorRxView::load_freqman() {
|
||||||
freq_ = remotes_monitoring_frequencies_hz[freq_index];
|
freqman_load_options options{};
|
||||||
else if (freq_mode == 1)
|
options.load_freqs = true;
|
||||||
freq_ = lora_monitoring_frequencies_hz[freq_index];
|
options.load_ranges = true;
|
||||||
else
|
options.load_hamradios = false;
|
||||||
freq_ = tetra_uplink_monitoring_frequencies_hz[freq_index];
|
options.load_repeaters = false;
|
||||||
receiver_model.set_target_frequency(freq_);
|
|
||||||
|
if (!load_freqman_file(freq_file_stem, frequency_list, options) || frequency_list.empty()) {
|
||||||
|
button_file.set_text("No file!");
|
||||||
|
button_index.set_text("");
|
||||||
|
text_entry_desc.set("");
|
||||||
|
button_freq.set_text("");
|
||||||
|
frequency_list.clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
current_index = 0;
|
||||||
|
init_current_entry();
|
||||||
|
button_file.set_text(freq_file_stem);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DetectorRxView::init_current_entry() {
|
||||||
|
if (frequency_list.empty()) return;
|
||||||
|
|
||||||
|
auto& entry = *frequency_list[current_index];
|
||||||
|
if (entry.type == freqman_type::Range) {
|
||||||
|
minfreq = entry.frequency_a;
|
||||||
|
maxfreq = entry.frequency_b;
|
||||||
|
current_freq = minfreq;
|
||||||
|
current_step = is_valid(entry.step) ? freqman_entry_get_step_value(entry.step) : DETECTOR_BW;
|
||||||
|
} else {
|
||||||
|
current_freq = entry.frequency_a;
|
||||||
|
minfreq = current_freq;
|
||||||
|
maxfreq = current_freq;
|
||||||
|
current_step = DETECTOR_BW;
|
||||||
|
}
|
||||||
|
|
||||||
|
update_entry_display();
|
||||||
|
update_freq_display();
|
||||||
|
receiver_model.set_target_frequency(current_freq);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DetectorRxView::update_entry_display() {
|
||||||
|
if (frequency_list.empty()) return;
|
||||||
|
|
||||||
|
auto& entry = *frequency_list[current_index];
|
||||||
|
button_index.set_text(
|
||||||
|
to_string_dec_uint(current_index + 1) + "/" +
|
||||||
|
to_string_dec_uint(frequency_list.size()));
|
||||||
|
text_entry_desc.set(entry.description);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DetectorRxView::update_freq_display() {
|
||||||
|
if (auto_scan && (minfreq != maxfreq)) {
|
||||||
|
if (last_update_was_auto_range_type != 1) {
|
||||||
|
button_freq.set_text("RANGE SCAN...");
|
||||||
|
last_update_was_auto_range_type = 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
button_freq.set_text(format_freq_mhz(current_freq));
|
||||||
|
last_update_was_auto_range_type = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DetectorRxView::on_timer() {
|
||||||
|
if (frequency_list.empty() || !auto_scan) return;
|
||||||
|
|
||||||
|
auto& entry = *frequency_list[current_index];
|
||||||
|
if (entry.type == freqman_type::Range) {
|
||||||
|
current_freq += current_step;
|
||||||
|
if (current_freq > maxfreq) {
|
||||||
|
if (auto_advance) {
|
||||||
|
current_index = (current_index + 1) % frequency_list.size();
|
||||||
|
init_current_entry();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
current_freq = minfreq;
|
||||||
|
}
|
||||||
|
receiver_model.set_target_frequency(current_freq);
|
||||||
|
update_freq_display();
|
||||||
|
} else if (auto_advance) {
|
||||||
|
// Single frequency: advance to next entry
|
||||||
|
current_index = (current_index + 1) % frequency_list.size();
|
||||||
|
init_current_entry();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DetectorRxView::DetectorRxView(NavigationView& nav)
|
DetectorRxView::DetectorRxView(NavigationView& nav)
|
||||||
@@ -75,21 +152,22 @@ DetectorRxView::DetectorRxView(NavigationView& nav)
|
|||||||
&field_vga,
|
&field_vga,
|
||||||
&field_rf_amp,
|
&field_rf_amp,
|
||||||
&field_volume,
|
&field_volume,
|
||||||
&text_frequency,
|
&button_file,
|
||||||
&freq_stats_rssi,
|
&button_index,
|
||||||
&freq_stats_db,
|
&text_entry_desc,
|
||||||
&text_beep_squelch,
|
&text_beep_squelch,
|
||||||
&field_beep_squelch,
|
&field_beep_squelch,
|
||||||
|
&freq_stats_db,
|
||||||
|
&freq_stats_rssi,
|
||||||
|
&button_freq,
|
||||||
|
&button_auto_scan,
|
||||||
|
&button_auto_advance,
|
||||||
&rssi,
|
&rssi,
|
||||||
&rssi_graph,
|
&rssi_graph,
|
||||||
&field_mode,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// activate vertical bar mode
|
|
||||||
rssi.set_vertical_rssi(true);
|
rssi.set_vertical_rssi(true);
|
||||||
|
|
||||||
freq_ = receiver_model.target_frequency();
|
|
||||||
|
|
||||||
field_beep_squelch.set_value(beep_squelch);
|
field_beep_squelch.set_value(beep_squelch);
|
||||||
field_beep_squelch.on_change = [this](int32_t v) {
|
field_beep_squelch.on_change = [this](int32_t v) {
|
||||||
beep_squelch = v;
|
beep_squelch = v;
|
||||||
@@ -97,29 +175,85 @@ DetectorRxView::DetectorRxView(NavigationView& nav)
|
|||||||
|
|
||||||
rssi_graph.set_nb_columns(256);
|
rssi_graph.set_nb_columns(256);
|
||||||
|
|
||||||
|
// FILE button opens file picker
|
||||||
|
button_file.on_select = [this](Button&) {
|
||||||
|
auto open_view = nav_.push<FileLoadView>(".TXT");
|
||||||
|
open_view->push_dir(freqman_dir);
|
||||||
|
open_view->on_changed = [this](std::filesystem::path new_file_path) {
|
||||||
|
if (new_file_path.native().find((u"/" / freqman_dir).native()) != 0) {
|
||||||
|
button_file.set_text("Invalid file");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
freq_file_stem = new_file_path.stem().string();
|
||||||
|
load_freqman();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// Index encoder: rotate to change entry, click does nothing
|
||||||
|
button_index.on_change = [this]() {
|
||||||
|
if (frequency_list.empty()) return;
|
||||||
|
int32_t delta = button_index.get_encoder_delta();
|
||||||
|
button_index.set_encoder_delta(0);
|
||||||
|
if (delta == 0) return;
|
||||||
|
|
||||||
|
// Use signed arithmetic for index wraparound to avoid unsigned promotion issues.
|
||||||
|
const int32_t list_size = static_cast<int32_t>(frequency_list.size());
|
||||||
|
int32_t idx = static_cast<int32_t>(current_index);
|
||||||
|
if (delta > 0) {
|
||||||
|
idx = (idx + 1) % list_size;
|
||||||
|
} else {
|
||||||
|
idx = (idx - 1 + list_size) % list_size;
|
||||||
|
}
|
||||||
|
current_index = static_cast<size_t>(idx);
|
||||||
|
init_current_entry();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Frequency encoder: rotate to step within range
|
||||||
|
button_freq.on_change = [this]() {
|
||||||
|
if (frequency_list.empty()) return;
|
||||||
|
auto& entry = *frequency_list[current_index];
|
||||||
|
if (entry.type != freqman_type::Range) {
|
||||||
|
button_freq.set_encoder_delta(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t delta = button_freq.get_encoder_delta();
|
||||||
|
button_freq.set_encoder_delta(0);
|
||||||
|
if (delta == 0) return;
|
||||||
|
|
||||||
|
if (delta > 0) {
|
||||||
|
current_freq += current_step;
|
||||||
|
if (current_freq > maxfreq) current_freq = minfreq;
|
||||||
|
} else {
|
||||||
|
current_freq -= current_step;
|
||||||
|
if (current_freq < minfreq) current_freq = maxfreq;
|
||||||
|
}
|
||||||
|
receiver_model.set_target_frequency(current_freq);
|
||||||
|
update_freq_display();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Auto-scan toggle
|
||||||
|
button_auto_scan.on_select = [this](Button&) {
|
||||||
|
auto_scan = !auto_scan;
|
||||||
|
button_auto_scan.set_text(auto_scan ? "AUTOSCAN" : "NO SCAN");
|
||||||
|
update_freq_display();
|
||||||
|
};
|
||||||
|
button_auto_scan.set_text(auto_scan ? "AUTOSCAN" : "NO SCAN");
|
||||||
|
|
||||||
|
// Auto-advance toggle
|
||||||
|
button_auto_advance.on_select = [this](Button&) {
|
||||||
|
auto_advance = !auto_advance;
|
||||||
|
button_auto_advance.set_text(auto_advance ? "AUTOADV" : "NO ADV");
|
||||||
|
};
|
||||||
|
button_auto_advance.set_text(auto_advance ? "AUTOADV" : "NO ADV");
|
||||||
|
|
||||||
change_mode();
|
change_mode();
|
||||||
rssi.set_peak(true, 3000);
|
rssi.set_peak(true, 3000);
|
||||||
|
|
||||||
// FILL STEP OPTIONS
|
|
||||||
freq_stats_rssi.set_style(Theme::getInstance()->bg_darkest);
|
freq_stats_rssi.set_style(Theme::getInstance()->bg_darkest);
|
||||||
freq_stats_db.set_style(Theme::getInstance()->bg_darkest);
|
freq_stats_db.set_style(Theme::getInstance()->bg_darkest);
|
||||||
|
|
||||||
field_mode.on_change = [this](size_t, int32_t value) {
|
load_freqman();
|
||||||
freq_mode = value;
|
|
||||||
freq_index = 0;
|
|
||||||
switch (value) {
|
|
||||||
case 1: // Lora
|
|
||||||
text_frequency.set(" 433, 868, 915 Mhz");
|
|
||||||
break;
|
|
||||||
case 2: // Remotes
|
|
||||||
text_frequency.set(" 433, 315 Mhz");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
case 0: // TETRA UP
|
|
||||||
text_frequency.set(" 380-390 Mhz");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DetectorRxView::on_statistics_update(const ChannelStatistics& statistics) {
|
void DetectorRxView::on_statistics_update(const ChannelStatistics& statistics) {
|
||||||
@@ -130,25 +264,23 @@ void DetectorRxView::on_statistics_update(const ChannelStatistics& statistics) {
|
|||||||
|
|
||||||
rssi_graph.add_values(rssi.get_min(), rssi.get_avg(), rssi.get_max(), statistics.max_db);
|
rssi_graph.add_values(rssi.get_min(), rssi.get_avg(), rssi.get_max(), statistics.max_db);
|
||||||
|
|
||||||
// refresh db
|
|
||||||
if (last_max_db != statistics.max_db) {
|
if (last_max_db != statistics.max_db) {
|
||||||
last_max_db = statistics.max_db;
|
last_max_db = statistics.max_db;
|
||||||
freq_stats_db.set("Power: " + to_string_dec_int(statistics.max_db) + " db");
|
freq_stats_db.set("Power: " + to_string_dec_int(statistics.max_db) + " db");
|
||||||
rssi.set_db(statistics.max_db);
|
rssi.set_db(statistics.max_db);
|
||||||
}
|
}
|
||||||
// refresh rssi
|
|
||||||
if (last_min_rssi != rssi_graph.get_graph_min() || last_avg_rssi != rssi_graph.get_graph_avg() || last_max_rssi != rssi_graph.get_graph_max()) {
|
if (last_min_rssi != rssi_graph.get_graph_min() || last_avg_rssi != rssi_graph.get_graph_avg() || last_max_rssi != rssi_graph.get_graph_max()) {
|
||||||
last_min_rssi = rssi_graph.get_graph_min();
|
last_min_rssi = rssi_graph.get_graph_min();
|
||||||
last_avg_rssi = rssi_graph.get_graph_avg();
|
last_avg_rssi = rssi_graph.get_graph_avg();
|
||||||
last_max_rssi = rssi_graph.get_graph_max();
|
last_max_rssi = rssi_graph.get_graph_max();
|
||||||
freq_stats_rssi.set("RSSI: " + to_string_dec_uint(last_min_rssi) + "/" + to_string_dec_uint(last_avg_rssi) + "/" + to_string_dec_uint(last_max_rssi));
|
freq_stats_rssi.set("RSSI:" + to_string_dec_uint(last_min_rssi) + "/" + to_string_dec_uint(last_avg_rssi) + "/" + to_string_dec_uint(last_max_rssi));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (statistics.max_db > beep_squelch) {
|
if (statistics.max_db > beep_squelch) {
|
||||||
baseband::request_audio_beep(map(statistics.max_db, -100, 20, 400, 2600), 24000, 150);
|
baseband::request_audio_beep(map(statistics.max_db, -100, 20, 400, 2600), 24000, 150);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} /* on_statistic_updates */
|
|
||||||
|
|
||||||
size_t DetectorRxView::change_mode() {
|
size_t DetectorRxView::change_mode() {
|
||||||
audio::output::stop();
|
audio::output::stop();
|
||||||
@@ -160,14 +292,13 @@ size_t DetectorRxView::change_mode() {
|
|||||||
receiver_model.set_modulation(ReceiverModel::Mode::Capture);
|
receiver_model.set_modulation(ReceiverModel::Mode::Capture);
|
||||||
|
|
||||||
baseband::set_sample_rate(DETECTOR_BW, get_oversample_rate(DETECTOR_BW));
|
baseband::set_sample_rate(DETECTOR_BW, get_oversample_rate(DETECTOR_BW));
|
||||||
// The radio needs to know the effective sampling rate.
|
|
||||||
auto actual_sampling_rate = get_actual_sample_rate(DETECTOR_BW);
|
auto actual_sampling_rate = get_actual_sample_rate(DETECTOR_BW);
|
||||||
receiver_model.set_sampling_rate(actual_sampling_rate);
|
receiver_model.set_sampling_rate(actual_sampling_rate);
|
||||||
receiver_model.set_baseband_bandwidth(filter_bandwidth_for_sampling_rate(actual_sampling_rate));
|
receiver_model.set_baseband_bandwidth(filter_bandwidth_for_sampling_rate(actual_sampling_rate));
|
||||||
|
|
||||||
audio::set_rate(audio_sampling_rate);
|
audio::set_rate(audio_sampling_rate);
|
||||||
audio::output::start();
|
audio::output::start();
|
||||||
receiver_model.set_headphone_volume(receiver_model.headphone_volume()); // WM8731 hack.
|
receiver_model.set_headphone_volume(receiver_model.headphone_volume());
|
||||||
|
|
||||||
receiver_model.enable();
|
receiver_model.enable();
|
||||||
|
|
||||||
|
|||||||
+53
-72
@@ -29,6 +29,7 @@
|
|||||||
#include "audio.hpp"
|
#include "audio.hpp"
|
||||||
#include "baseband_api.hpp"
|
#include "baseband_api.hpp"
|
||||||
#include "file.hpp"
|
#include "file.hpp"
|
||||||
|
#include "freqman.hpp"
|
||||||
#include "freqman_db.hpp"
|
#include "freqman_db.hpp"
|
||||||
#include "portapack_persistent_memory.hpp"
|
#include "portapack_persistent_memory.hpp"
|
||||||
#include "radio_state.hpp"
|
#include "radio_state.hpp"
|
||||||
@@ -60,20 +61,35 @@ class DetectorRxView : public View {
|
|||||||
int32_t map(int32_t value, int32_t fromLow, int32_t fromHigh, int32_t toLow, int32_t toHigh);
|
int32_t map(int32_t value, int32_t fromLow, int32_t fromHigh, int32_t toLow, int32_t toHigh);
|
||||||
size_t change_mode();
|
size_t change_mode();
|
||||||
void on_statistics_update(const ChannelStatistics& statistics);
|
void on_statistics_update(const ChannelStatistics& statistics);
|
||||||
void set_display_freq(int64_t freq);
|
|
||||||
void on_timer();
|
void on_timer();
|
||||||
|
void load_freqman();
|
||||||
|
void init_current_entry();
|
||||||
|
void update_entry_display();
|
||||||
|
void update_freq_display();
|
||||||
|
std::string format_freq_mhz(int64_t freq_hz);
|
||||||
|
|
||||||
|
freqman_db frequency_list{};
|
||||||
|
size_t current_index{0};
|
||||||
|
int64_t current_freq{0};
|
||||||
|
int64_t minfreq{0};
|
||||||
|
int64_t maxfreq{0};
|
||||||
|
int32_t current_step{DETECTOR_BW};
|
||||||
|
std::string freq_file_stem{"DETECTOR"};
|
||||||
|
bool auto_scan{true};
|
||||||
|
bool auto_advance{false};
|
||||||
|
uint8_t last_update_was_auto_range_type = -1;
|
||||||
|
|
||||||
uint8_t freq_index = 0;
|
|
||||||
rf::Frequency freq_ = {433920000};
|
|
||||||
int32_t beep_squelch = 0;
|
int32_t beep_squelch = 0;
|
||||||
audio::Rate audio_sampling_rate = audio::Rate::Hz_48000;
|
audio::Rate audio_sampling_rate = audio::Rate::Hz_48000;
|
||||||
uint8_t freq_mode = 0;
|
|
||||||
|
|
||||||
app_settings::SettingsManager settings_{
|
app_settings::SettingsManager settings_{
|
||||||
"rx_detector",
|
"rx_detector",
|
||||||
app_settings::Mode::RX,
|
app_settings::Mode::RX,
|
||||||
{
|
{
|
||||||
{"beep_squelch"sv, &beep_squelch},
|
{"beep_squelch"sv, &beep_squelch},
|
||||||
|
{"freq_file"sv, &freq_file_stem},
|
||||||
|
{"auto_scan"sv, &auto_scan},
|
||||||
|
{"auto_advance"sv, &auto_advance},
|
||||||
}};
|
}};
|
||||||
|
|
||||||
Labels labels{
|
Labels labels{
|
||||||
@@ -93,41 +109,55 @@ class DetectorRxView : public View {
|
|||||||
AudioVolumeField field_volume{
|
AudioVolumeField field_volume{
|
||||||
{UI_POS_X_RIGHT(2), UI_POS_Y(0)}};
|
{UI_POS_X_RIGHT(2), UI_POS_Y(0)}};
|
||||||
|
|
||||||
OptionsField field_mode{
|
// Row 1: filename + auto advance
|
||||||
{UI_POS_X(0), UI_POS_Y(1)},
|
Button button_file{
|
||||||
9,
|
{UI_POS_X(0), UI_POS_Y(1), UI_POS_WIDTH(20), UI_POS_DEFAULT_HEIGHT},
|
||||||
{
|
""};
|
||||||
{"TETRA UP", 0},
|
|
||||||
{"Lora", 1},
|
|
||||||
{"Remotes", 2},
|
|
||||||
}};
|
|
||||||
|
|
||||||
Text text_frequency{
|
Button button_auto_advance{
|
||||||
{UI_POS_X_RIGHT(20), UI_POS_Y(1), UI_POS_WIDTH(20), UI_POS_DEFAULT_HEIGHT},
|
{UI_POS_X_RIGHT(9), UI_POS_Y(1), UI_POS_WIDTH(9), UI_POS_DEFAULT_HEIGHT},
|
||||||
|
"NO ADV"};
|
||||||
|
|
||||||
|
// Row 2: index encoder + description + auto scan
|
||||||
|
ButtonWithEncoder button_index{
|
||||||
|
{UI_POS_X(0), UI_POS_Y(2), UI_POS_WIDTH(4), UI_POS_DEFAULT_HEIGHT},
|
||||||
|
""};
|
||||||
|
|
||||||
|
Text text_entry_desc{
|
||||||
|
{UI_POS_X(4), UI_POS_Y(2), UI_POS_WIDTH(17), UI_POS_DEFAULT_HEIGHT},
|
||||||
|
""};
|
||||||
|
|
||||||
|
Button button_auto_scan{
|
||||||
|
{UI_POS_X_RIGHT(9), UI_POS_Y(2), UI_POS_WIDTH(9), UI_POS_DEFAULT_HEIGHT},
|
||||||
|
"AUTO SCAN"};
|
||||||
|
|
||||||
|
// Row 3: frequency encoder + bip level
|
||||||
|
ButtonWithEncoder button_freq{
|
||||||
|
{UI_POS_X(0), UI_POS_Y(3), UI_POS_WIDTH(20), UI_POS_DEFAULT_HEIGHT},
|
||||||
""};
|
""};
|
||||||
|
|
||||||
Text text_beep_squelch{
|
Text text_beep_squelch{
|
||||||
{UI_POS_X_RIGHT(9), UI_POS_Y(2), UI_POS_WIDTH(4), UI_POS_DEFAULT_HEIGHT},
|
{UI_POS_X_RIGHT(9), UI_POS_Y(3), UI_POS_WIDTH(4), UI_POS_DEFAULT_HEIGHT},
|
||||||
"Bip>"};
|
"Bip>"};
|
||||||
|
|
||||||
NumberField field_beep_squelch{
|
NumberField field_beep_squelch{
|
||||||
{UI_POS_X_RIGHT(5), UI_POS_Y(2)},
|
{UI_POS_X_RIGHT(5), UI_POS_Y(3)},
|
||||||
4,
|
4,
|
||||||
{-100, 20},
|
{-100, 20},
|
||||||
1,
|
1,
|
||||||
' ',
|
' ',
|
||||||
};
|
};
|
||||||
|
|
||||||
// RSSI: XX/XX/XXX
|
// Row 4: Power + RSSI on same line
|
||||||
Text freq_stats_rssi{
|
|
||||||
{UI_POS_X(0), UI_POS_Y(2), UI_POS_WIDTH(15), UI_POS_DEFAULT_HEIGHT},
|
|
||||||
};
|
|
||||||
|
|
||||||
// Power: -XXX db
|
|
||||||
Text freq_stats_db{
|
Text freq_stats_db{
|
||||||
{UI_POS_X(0), UI_POS_Y(3), UI_POS_WIDTH(15), UI_POS_DEFAULT_HEIGHT},
|
{UI_POS_X(0), UI_POS_Y(4), UI_POS_WIDTH(15), UI_POS_DEFAULT_HEIGHT},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Text freq_stats_rssi{
|
||||||
|
{UI_POS_X(15), UI_POS_Y(4), UI_POS_WIDTH(15), UI_POS_DEFAULT_HEIGHT},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Row 5+: RSSI graph + vertical bar
|
||||||
RSSIGraph rssi_graph{
|
RSSIGraph rssi_graph{
|
||||||
{UI_POS_X(0), UI_POS_Y(5), UI_POS_WIDTH_REMAINING(5), UI_POS_HEIGHT_REMAINING(6)},
|
{UI_POS_X(0), UI_POS_Y(5), UI_POS_WIDTH_REMAINING(5), UI_POS_HEIGHT_REMAINING(6)},
|
||||||
};
|
};
|
||||||
@@ -147,55 +177,6 @@ class DetectorRxView : public View {
|
|||||||
[this](const Message* const) {
|
[this](const Message* const) {
|
||||||
this->on_timer();
|
this->on_timer();
|
||||||
}};
|
}};
|
||||||
|
|
||||||
const std::vector<uint32_t> remotes_monitoring_frequencies_hz = {
|
|
||||||
// Around 315 MHz (common for older remotes, key fobs in some regions)
|
|
||||||
// Window centered on 315 MHz, covers 314.625 - 315.375 MHz
|
|
||||||
315000000,
|
|
||||||
|
|
||||||
// Around 433.92 MHz (very common for remotes, sensors, key fobs globally)
|
|
||||||
// Window centered on 433.92 MHz, covers 433.545 - 434.295 MHz
|
|
||||||
433920000,
|
|
||||||
};
|
|
||||||
const std::vector<uint32_t> lora_monitoring_frequencies_hz = {
|
|
||||||
// EU433 Band (Europe, typically 433.05 MHz to 434.79 MHz)
|
|
||||||
// Scanning the approximate range 433.0 MHz to 434.8 MHz with 750kHz steps
|
|
||||||
433375000, // Covers 433.000 - 433.750 MHz
|
|
||||||
434125000, // Covers 433.750 - 434.500 MHz (includes 433.92 MHz)
|
|
||||||
434875000, // Covers 434.500 - 435.250 MHz (covers up to 434.79 MHz)
|
|
||||||
|
|
||||||
// EU868 Band (Europe, typically 863 MHz to 870 MHz, specific channels around 868 MHz)
|
|
||||||
// Targeting common LoRaWAN channel groups (approx 867.0 - 868.6 MHz) with 750kHz steps
|
|
||||||
867375000, // Covers 867.000 - 867.750 MHz
|
|
||||||
868125000, // Covers 867.750 - 868.500 MHz
|
|
||||||
868875000, // Covers 868.500 - 869.250 MHz (covers up to 868.6 MHz)
|
|
||||||
|
|
||||||
// US915 Band (North America, typically 902 MHz to 928 MHz, specific channels around 915 MHz)
|
|
||||||
// Providing a few sample windows around the 915 MHz area with 750kHz steps.
|
|
||||||
// This band is wide; a full scan would require many more frequencies.
|
|
||||||
914250000, // Covers 913.875 - 914.625 MHz
|
|
||||||
915000000, // Covers 914.625 - 915.375 MHz (Centered on 915 MHz)
|
|
||||||
915750000, // Covers 915.375 - 916.125 MHz
|
|
||||||
};
|
|
||||||
const std::vector<uint32_t> tetra_uplink_monitoring_frequencies_hz = {
|
|
||||||
// Band starts at 380,000,000 Hz, ends at 390,000,000 Hz.
|
|
||||||
// First center: 380,000,000 + 375,000 = 380,375,000 Hz
|
|
||||||
// Last center: 380,375,000 + 13 * 750,000 = 390,125,000 Hz (14 frequencies total for this band)
|
|
||||||
380375000, // Covers 380.000 - 380.750 MHz
|
|
||||||
381125000, // Covers 380.750 - 381.500 MHz
|
|
||||||
381875000, // Covers 381.500 - 382.250 MHz
|
|
||||||
382625000, // Covers 382.250 - 383.000 MHz
|
|
||||||
383375000, // Covers 383.000 - 383.750 MHz
|
|
||||||
384125000, // Covers 383.750 - 384.500 MHz
|
|
||||||
384875000, // Covers 384.500 - 385.250 MHz
|
|
||||||
385625000, // Covers 385.250 - 386.000 MHz
|
|
||||||
386375000, // Covers 386.000 - 386.750 MHz
|
|
||||||
387125000, // Covers 386.750 - 387.500 MHz
|
|
||||||
387875000, // Covers 387.500 - 388.250 MHz
|
|
||||||
388625000, // Covers 388.250 - 389.000 MHz
|
|
||||||
389375000, // Covers 389.000 - 389.750 MHz
|
|
||||||
390125000, // Covers 389.750 - 390.500 MHz
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ui::external_app::detector_rx
|
} // namespace ui::external_app::detector_rx
|
||||||
|
|||||||
@@ -134,6 +134,7 @@ options_t freqman_steps = {
|
|||||||
{"100kHz (FM2)", 100000},
|
{"100kHz (FM2)", 100000},
|
||||||
{"250kHz (N2)", 250000},
|
{"250kHz (N2)", 250000},
|
||||||
{"500kHz (WFM)", 500000},
|
{"500kHz (WFM)", 500000},
|
||||||
|
{"750kHz ", 750000},
|
||||||
{"1MHz ", 1000000},
|
{"1MHz ", 1000000},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -156,6 +157,7 @@ options_t freqman_steps_short = {
|
|||||||
{"100kHz", 100000},
|
{"100kHz", 100000},
|
||||||
{"250kHz", 250000},
|
{"250kHz", 250000},
|
||||||
{"500kHz", 500000},
|
{"500kHz", 500000},
|
||||||
|
{"750kHz", 750000},
|
||||||
{"1MHz", 1000000},
|
{"1MHz", 1000000},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -102,6 +102,7 @@ enum class freqman_type : uint8_t {
|
|||||||
_100kHz,
|
_100kHz,
|
||||||
_250kHz,
|
_250kHz,
|
||||||
_500kHz,
|
_500kHz,
|
||||||
|
_750kHz,
|
||||||
_1MHz,
|
_1MHz,
|
||||||
Unknown,
|
Unknown,
|
||||||
* };
|
* };
|
||||||
@@ -130,6 +131,7 @@ enum class freqman_type : uint8_t {
|
|||||||
freqman_step_info{ freqman_step::_100kHz, "100kHz", "100kHz (FM2)", 100'000 },
|
freqman_step_info{ freqman_step::_100kHz, "100kHz", "100kHz (FM2)", 100'000 },
|
||||||
freqman_step_info{ freqman_step::_250kHz, "250kHz", "250kHz (N2)", 250'000 },
|
freqman_step_info{ freqman_step::_250kHz, "250kHz", "250kHz (N2)", 250'000 },
|
||||||
freqman_step_info{ freqman_step::_500kHz, "500kHz", "500kHz (WFM)", 500'000 },
|
freqman_step_info{ freqman_step::_500kHz, "500kHz", "500kHz (WFM)", 500'000 },
|
||||||
|
freqman_step_info{ freqman_step::_750kHz, "750kHz", "750kHz ", 750'000 },
|
||||||
freqman_step_info{ freqman_step::_1MHz, "1MHz", "1MHz ", 1'000'000 },
|
freqman_step_info{ freqman_step::_1MHz, "1MHz", "1MHz ", 1'000'000 },
|
||||||
freqman_step_info{ freqman_step::Unknown, "Unknown", "Unknown ", 0 },
|
freqman_step_info{ freqman_step::Unknown, "Unknown", "Unknown ", 0 },
|
||||||
* };
|
* };
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
# Around 315 MHz (common for older remotes, key fobs in some regions)
|
||||||
|
# Window centered on 315 MHz, covers 314.625 - 315.375 MHz
|
||||||
|
f=315000000,d=Remotes 315M
|
||||||
|
|
||||||
|
# Around 433.92 MHz (very common for remotes, sensors, key fobs globally)
|
||||||
|
# Window centered on 433.92 MHz, covers 433.545 - 434.295 MHz
|
||||||
|
f=433920000,d=Remotes 433.92M
|
||||||
|
|
||||||
|
# EU433 Band (Europe, typically 433.05 MHz to 434.79 MHz)
|
||||||
|
# Scanning the approximate range 433.0 MHz to 434.8 MHz with 750kHz steps
|
||||||
|
a=433375000,b=434875000,s=750kHz,d=LoRa EU433
|
||||||
|
|
||||||
|
# EU868 Band (Europe, typically 863 MHz to 870 MHz, specific channels around 868 MHz)
|
||||||
|
# Targeting common LoRaWAN channel groups (approx 867.0 - 868.6 MHz) with 750kHz steps
|
||||||
|
a=867375000,b=868875000,s=750kHz,d=LoRa EU868
|
||||||
|
|
||||||
|
# US915 Band (North America, typically 902 MHz to 928 MHz, specific channels around 915 MHz)
|
||||||
|
a=902000000,b=928250000,s=750kHz,d=LoRa US915
|
||||||
|
|
||||||
|
# TETRA Band starts at 380,000,000 Hz, ends at 390,000,000 Hz.
|
||||||
|
a=380375000,b=390125000,s=750kHz,d=TETRA UP
|
||||||
Reference in New Issue
Block a user