Added range file and range type to frequency manager (mainly for jammer)

Made MenuView use less widgets, hopefully preventing crashes with large
lists
Fixed M10 sonde crash on packet receive
Updated about screen
Updated binary
This commit is contained in:
furrtek 2017-12-08 18:58:46 +00:00
parent b38adf3769
commit 3d2dacaf29
18 changed files with 321 additions and 191 deletions

View File

@ -42,8 +42,9 @@ bool load_freqman_file(std::string& file_stem, freqman_db &db) {
char * line_start; char * line_start;
char * line_end; char * line_end;
std::string description; std::string description;
rf::Frequency value; rf::Frequency frequency_a, frequency_b;
char file_data[256]; char file_data[256];
freqman_entry_type type;
db.entries.clear(); db.entries.clear();
@ -63,18 +64,34 @@ bool load_freqman_file(std::string& file_stem, freqman_db &db) {
line_start = file_data; line_start = file_data;
pos = strstr(file_data, "f="); if (!strstr(file_data, "f=") && !strstr(file_data, "a="))
if (!pos) break; break;
// Look for complete lines in buffer // Look for complete lines in buffer
while ((line_end = strstr(line_start, "\x0A"))) { while ((line_end = strstr(line_start, "\x0A"))) {
// Read frequency // Read frequency
pos = strstr(line_start, "f="); pos = strstr(line_start, "f=");
frequency_b = 0;
type = SINGLE;
if (pos) { if (pos) {
pos += 2; pos += 2;
value = strtoll(pos, nullptr, 10); frequency_a = strtoll(pos, nullptr, 10);
} else } else {
value = 0; // ...or range
pos = strstr(line_start, "a=");
if (pos) {
pos += 2;
frequency_a = strtoll(pos, nullptr, 10);
type = RANGE;
pos = strstr(line_start, "b=");
if (pos) {
pos += 2;
frequency_b = strtoll(pos, nullptr, 10);
} else
frequency_b = 0;
} else
frequency_a = 0;
}
// Read description until , or LF // Read description until , or LF
pos = strstr(line_start, "d="); pos = strstr(line_start, "d=");
@ -85,7 +102,7 @@ bool load_freqman_file(std::string& file_stem, freqman_db &db) {
} else } else
description = "-"; description = "-";
db.entries.push_back({ value, "", description }); db.entries.push_back({ frequency_a, frequency_b, description, type });
n++; n++;
if (n >= FREQMAN_MAX_PER_FILE) return true; if (n >= FREQMAN_MAX_PER_FILE) return true;
@ -105,17 +122,33 @@ bool load_freqman_file(std::string& file_stem, freqman_db &db) {
bool save_freqman_file(std::string& file_stem, freqman_db &db) { bool save_freqman_file(std::string& file_stem, freqman_db &db) {
File freqman_file; File freqman_file;
std::string item_string; std::string item_string;
rf::Frequency f; rf::Frequency frequency_a, frequency_b;
if (!create_freqman_file(file_stem, freqman_file)) if (!create_freqman_file(file_stem, freqman_file))
return false; return false;
for (size_t n = 0; n < db.entries.size(); n++) { for (size_t n = 0; n < db.entries.size(); n++) {
f = db.entries[n].value; auto& entry = db.entries[n];
item_string = "f=" + to_string_dec_uint(f / 1000) + to_string_dec_uint(f % 1000UL, 3, '0'); // Please forgive me
frequency_a = entry.frequency_a;
if (db.entries[n].description.size()) if (entry.type == SINGLE) {
item_string += ",d=" + db.entries[n].description; // Single
// TODO: Make to_string_dec_uint be able to return uint64_t's
// Please forgive me...
item_string = "f=" + to_string_dec_uint(frequency_a / 1000) + to_string_dec_uint(frequency_a % 1000UL, 3, '0');
} else {
// Range
frequency_b = entry.frequency_b;
item_string = "a=" + to_string_dec_uint(frequency_a / 1000) + to_string_dec_uint(frequency_a % 1000UL, 3, '0');
item_string += ",b=" + to_string_dec_uint(frequency_b / 1000) + to_string_dec_uint(frequency_b % 1000UL, 3, '0');
}
if (entry.description.size())
item_string += ",d=" + entry.description;
freqman_file.write_line(item_string); freqman_file.write_line(item_string);
} }
@ -132,16 +165,15 @@ bool create_freqman_file(std::string& file_stem, File& freqman_file) {
} }
std::string freqman_item_string(freqman_entry &entry, size_t max_length) { std::string freqman_item_string(freqman_entry &entry, size_t max_length) {
std::string item_string, frequency_str, description; std::string item_string;
rf::Frequency value;
if (entry.type == SINGLE) {
item_string = to_string_short_freq(entry.frequency_a) + "M: " + entry.description;
} else {
item_string = "Range: " + entry.description;
}
value = entry.value; if (item_string.size() > max_length)
entry.frequency_str = to_string_dec_int(value / 1000000, 4) + "." +
to_string_dec_int((value / 100) % 10000, 4, '0');
item_string = entry.frequency_str + "M: " + entry.description;
if (entry.description.size() > max_length)
return item_string.substr(0, max_length - 3) + "..."; return item_string.substr(0, max_length - 3) + "...";
return item_string; return item_string;

View File

@ -43,10 +43,16 @@ enum freqman_error {
ERROR_DUPLICATE ERROR_DUPLICATE
}; };
enum freqman_entry_type {
SINGLE = 0,
RANGE
};
struct freqman_entry { struct freqman_entry {
rf::Frequency value { 0 }; rf::Frequency frequency_a { 0 };
std::string frequency_str { }; rf::Frequency frequency_b { 0 };
std::string description { }; std::string description { };
freqman_entry_type type { };
}; };
struct freqman_db { struct freqman_db {

View File

@ -33,6 +33,7 @@
//BUG: SCANNER Multiple slices //BUG: SCANNER Multiple slices
//TODO: Display file creation/modification date in FileLoadView //TODO: Display file creation/modification date in FileLoadView
//TODO: Super simple text file viewer
//TODO: Display recording frequency in Replay (from associated .txt file, if present) //TODO: Display recording frequency in Replay (from associated .txt file, if present)
//TODO: Clean up ReplayThread //TODO: Clean up ReplayThread
//TODO: Cap Wav viewer position //TODO: Cap Wav viewer position
@ -40,7 +41,6 @@
//TODO: Use unit_auto_scale //TODO: Use unit_auto_scale
//TODO: Remove make_bistream from encoders.cpp, too complex, stinks. bitstream_append should be enough. //TODO: Remove make_bistream from encoders.cpp, too complex, stinks. bitstream_append should be enough.
//TODO: Continue work on proc_afskrx_corr, see python script (it works !) //TODO: Continue work on proc_afskrx_corr, see python script (it works !)
//TODO: Super simple text file viewer
//TODO: De bruijn sequence scanner for encoders //TODO: De bruijn sequence scanner for encoders
//TODO: FILEMAN Rename folders //TODO: FILEMAN Rename folders
//TODO: FILEMAN Move files //TODO: FILEMAN Move files

View File

@ -82,7 +82,7 @@ void AboutView::update() {
std::array<Color, 240> pixel_row; std::array<Color, 240> pixel_row;
slow_down++; slow_down++;
if (slow_down & 1) return; if (slow_down % 3 < 2) return;
if (!timer) { if (!timer) {
if (loop) { if (loop) {

View File

@ -72,7 +72,7 @@ private:
int32_t delay; int32_t delay;
} credits_t; } credits_t;
const credits_t credits[24] = { const credits_t credits[25] = {
// 012345678901234567890123456789 // 012345678901234567890123456789
{ 60, "PortaPack|HAVOC", 0 }, { 60, "PortaPack|HAVOC", 0 },
{ 7 * 8, "Git hash " GIT_REVISION, 16 }, { 7 * 8, "Git hash " GIT_REVISION, 16 },
@ -90,12 +90,13 @@ private:
{ 0 * 8, "TouchTunes infos Notpike", 16 }, { 0 * 8, "TouchTunes infos Notpike", 16 },
{ 4 * 8, "Subaru infos Tom", 0 }, { 4 * 8, "Subaru infos Tom", 0 },
{ 18 * 8, "Wimmenhove", 24 }, { 18 * 8, "Wimmenhove", 24 },
{ 12 * 8, "Thanks", 16 }, { 6 * 8, "Thanks & donators", 16 },
{ 1 * 8, "Rainer Matla Keld Norman", 0 }, { 1 * 8, "Rainer Matla Keld Norman", 0 },
{ 1 * 8, " Giorgio C. DC1RDB", 0 }, { 1 * 8, " Giorgio C. DC1RDB", 0 },
{ 1 * 8, " Sigmounte Waax", 0 }, { 1 * 8, " Sigmounte Waax", 0 },
{ 1 * 8, " Windyoona Channels", 0 }, { 1 * 8, " Windyoona Channels", 0 },
{ 1 * 8, " F4GEV", 24 }, { 1 * 8, " F4GEV Pyr3x", 0 },
{ 1 * 8, " HB3YOE", 24 },
{ 12 * 8, "MMXVII", -1 } { 12 * 8, "MMXVII", -1 }
}; };

View File

@ -61,7 +61,7 @@ std::filesystem::path FileManBaseView::get_selected_path() {
if (selected_path_str.back() != '/') if (selected_path_str.back() != '/')
selected_path_str += '/'; selected_path_str += '/';
selected_path_str += (entry_list[menu_view.highlighted()].entry_path.string()); selected_path_str += (entry_list[menu_view.highlighted_index()].entry_path.string());
return selected_path_str; return selected_path_str;
} }
@ -225,13 +225,13 @@ FileLoadView::FileLoadView(
refresh_list(); refresh_list();
on_select_entry = [&nav, this]() { on_select_entry = [&nav, this]() {
if (entry_list[menu_view.highlighted()].is_directory) { if (entry_list[menu_view.highlighted_index()].is_directory) {
load_directory_contents(get_selected_path()); load_directory_contents(get_selected_path());
refresh_list(); refresh_list();
} else { } else {
nav_.pop(); nav_.pop();
if (on_changed) if (on_changed)
on_changed(entry_list[menu_view.highlighted()].entry_path); on_changed(entry_list[menu_view.highlighted_index()].entry_path);
} }
}; };
} }
@ -282,7 +282,7 @@ FileManagerView::FileManagerView(
refresh_list(); refresh_list();
on_select_entry = [this]() { on_select_entry = [this]() {
if (entry_list[menu_view.highlighted()].is_directory) { if (entry_list[menu_view.highlighted_index()].is_directory) {
load_directory_contents(get_selected_path()); load_directory_contents(get_selected_path());
refresh_list(); refresh_list();
} else } else
@ -302,13 +302,13 @@ FileManagerView::FileManagerView(
}; };
button_rename.on_select = [this, &nav](Button&) { button_rename.on_select = [this, &nav](Button&) {
name_buffer = entry_list[menu_view.highlighted()].entry_path.filename().string().substr(0, max_filename_length); name_buffer = entry_list[menu_view.highlighted_index()].entry_path.filename().string().substr(0, max_filename_length);
on_rename(nav); on_rename(nav);
}; };
button_delete.on_select = [this, &nav](Button&) { button_delete.on_select = [this, &nav](Button&) {
// Use display_modal ? // Use display_modal ?
nav.push<ModalMessageView>("Delete", "Delete " + entry_list[menu_view.highlighted()].entry_path.filename().string() + "\nAre you sure ?", YESNO, nav.push<ModalMessageView>("Delete", "Delete " + entry_list[menu_view.highlighted_index()].entry_path.filename().string() + "\nAre you sure ?", YESNO,
[this](bool choice) { [this](bool choice) {
if (choice) if (choice)
on_delete(); on_delete();

View File

@ -147,13 +147,13 @@ void FrequencySaveView::save_current_file() {
void FrequencySaveView::on_save_name() { void FrequencySaveView::on_save_name() {
text_prompt(nav_, &desc_buffer, 28, [this](std::string * buffer) { text_prompt(nav_, &desc_buffer, 28, [this](std::string * buffer) {
database.entries.push_back({ value_, "", *buffer }); database.entries.push_back({ value_, 0, *buffer, SINGLE });
save_current_file(); save_current_file();
}); });
} }
void FrequencySaveView::on_save_timestamp() { void FrequencySaveView::on_save_timestamp() {
database.entries.push_back({ value_, "", live_timestamp.string() }); database.entries.push_back({ value_, 0, live_timestamp.string(), SINGLE });
save_current_file(); save_current_file();
} }
@ -224,13 +224,26 @@ FrequencyLoadView::FrequencyLoadView(
on_select_frequency = [&nav, this]() { on_select_frequency = [&nav, this]() {
nav_.pop(); nav_.pop();
if (on_changed)
on_changed(database.entries[menu_view.highlighted()].value); auto& entry = database.entries[menu_view.highlighted()];
if (entry.type == RANGE) {
// User chose a frequency range entry
if (on_range_loaded)
on_range_loaded(entry.frequency_a, entry.frequency_b);
else if (on_frequency_loaded)
on_frequency_loaded(entry.frequency_a);
// TODO: Maybe return center of range if user choses a range when the app needs a unique frequency, instead of frequency_a ?
} else {
// User chose an unique frequency entry
if (on_frequency_loaded)
on_frequency_loaded(entry.frequency_a);
}
}; };
} }
void FrequencyManagerView::on_edit_freq(rf::Frequency f) { void FrequencyManagerView::on_edit_freq(rf::Frequency f) {
database.entries[menu_view.highlighted()].value = f; database.entries[menu_view.highlighted()].frequency_a = f;
save_freqman_file(file_list[current_category_id], database); save_freqman_file(file_list[current_category_id], database);
refresh_list(); refresh_list();
} }
@ -308,7 +321,7 @@ FrequencyManagerView::FrequencyManagerView(
}; };
button_edit_freq.on_select = [this, &nav](Button&) { button_edit_freq.on_select = [this, &nav](Button&) {
auto new_view = nav.push<FrequencyKeypadView>(database.entries[menu_view.highlighted()].value); auto new_view = nav.push<FrequencyKeypadView>(database.entries[menu_view.highlighted()].frequency_a);
new_view->on_changed = [this](rf::Frequency f) { new_view->on_changed = [this](rf::Frequency f) {
on_edit_freq(f); on_edit_freq(f);
}; };

View File

@ -121,7 +121,8 @@ private:
class FrequencyLoadView : public FreqManBaseView { class FrequencyLoadView : public FreqManBaseView {
public: public:
std::function<void(rf::Frequency)> on_changed { }; std::function<void(rf::Frequency)> on_frequency_loaded { };
std::function<void(rf::Frequency, rf::Frequency)> on_range_loaded { };
FrequencyLoadView(NavigationView& nav); FrequencyLoadView(NavigationView& nav);

View File

@ -22,6 +22,7 @@
#include "ui_jammer.hpp" #include "ui_jammer.hpp"
#include "ui_receiver.hpp" #include "ui_receiver.hpp"
#include "ui_freqman.hpp"
#include "baseband_api.hpp" #include "baseband_api.hpp"
#include "string_format.hpp" #include "string_format.hpp"
@ -34,13 +35,12 @@ void RangeView::focus() {
check_enabled.focus(); check_enabled.focus();
} }
extern constexpr jammer_range_t RangeView::range_presets[];
extern constexpr Style RangeView::style_info; extern constexpr Style RangeView::style_info;
void RangeView::update_min(rf::Frequency f) { void RangeView::update_start(rf::Frequency f) {
// Change everything except max // Change everything except max
frequency_range.min = f; frequency_range.min = f;
button_min.set_text(to_string_short_freq(f)); button_start.set_text(to_string_short_freq(f));
center = (frequency_range.min + frequency_range.max) / 2; center = (frequency_range.min + frequency_range.max) / 2;
width = abs(frequency_range.max - frequency_range.min); width = abs(frequency_range.max - frequency_range.min);
@ -49,10 +49,10 @@ void RangeView::update_min(rf::Frequency f) {
button_width.set_text(to_string_short_freq(width)); button_width.set_text(to_string_short_freq(width));
} }
void RangeView::update_max(rf::Frequency f) { void RangeView::update_stop(rf::Frequency f) {
// Change everything except min // Change everything except min
frequency_range.max = f; frequency_range.max = f;
button_max.set_text(to_string_short_freq(f)); button_stop.set_text(to_string_short_freq(f));
center = (frequency_range.min + frequency_range.max) / 2; center = (frequency_range.min + frequency_range.max) / 2;
width = abs(frequency_range.max - frequency_range.min); width = abs(frequency_range.max - frequency_range.min);
@ -70,10 +70,10 @@ void RangeView::update_center(rf::Frequency f) {
rf::Frequency max = min + width; rf::Frequency max = min + width;
frequency_range.min = min; frequency_range.min = min;
button_min.set_text(to_string_short_freq(min)); button_start.set_text(to_string_short_freq(min));
frequency_range.max = max; frequency_range.max = max;
button_max.set_text(to_string_short_freq(max)); button_stop.set_text(to_string_short_freq(max));
} }
void RangeView::update_width(uint32_t w) { void RangeView::update_width(uint32_t w) {
@ -86,10 +86,10 @@ void RangeView::update_width(uint32_t w) {
rf::Frequency max = min + width; rf::Frequency max = min + width;
frequency_range.min = min; frequency_range.min = min;
button_min.set_text(to_string_short_freq(min)); button_start.set_text(to_string_short_freq(min));
frequency_range.max = max; frequency_range.max = max;
button_max.set_text(to_string_short_freq(max)); button_stop.set_text(to_string_short_freq(max));
} }
void RangeView::paint(Painter&) { void RangeView::paint(Painter&) {
@ -123,9 +123,9 @@ RangeView::RangeView(NavigationView& nav) {
add_children({ add_children({
&labels, &labels,
&check_enabled, &check_enabled,
&options_preset, &button_load_range,
&button_min, &button_start,
&button_max, &button_stop,
&button_center, &button_center,
&button_width &button_width
}); });
@ -134,22 +134,18 @@ RangeView::RangeView(NavigationView& nav) {
frequency_range.enabled = v; frequency_range.enabled = v;
}; };
button_min.on_select = [this, &nav](Button& button) { button_start.on_select = [this, &nav](Button& button) {
auto new_view = nav.push<FrequencyKeypadView>(frequency_range.min); auto new_view = nav.push<FrequencyKeypadView>(frequency_range.min);
new_view->on_changed = [this, &button](rf::Frequency f) { new_view->on_changed = [this, &button](rf::Frequency f) {
update_min(f); update_start(f);
}; };
//update_button(button, f);
}; };
button_max.on_select = [this, &nav](Button& button) { button_stop.on_select = [this, &nav](Button& button) {
auto new_view = nav.push<FrequencyKeypadView>(frequency_range.max); auto new_view = nav.push<FrequencyKeypadView>(frequency_range.max);
new_view->on_changed = [this, &button](rf::Frequency f) { new_view->on_changed = [this, &button](rf::Frequency f) {
update_max(f); update_stop(f);
}; };
//update_button(button, f);
}; };
button_center.on_select = [this, &nav](Button& button) { button_center.on_select = [this, &nav](Button& button) {
@ -157,8 +153,6 @@ RangeView::RangeView(NavigationView& nav) {
new_view->on_changed = [this, &button](rf::Frequency f) { new_view->on_changed = [this, &button](rf::Frequency f) {
update_center(f); update_center(f);
}; };
//update_button(button, f);
}; };
button_width.on_select = [this, &nav](Button& button) { button_width.on_select = [this, &nav](Button& button) {
@ -166,16 +160,19 @@ RangeView::RangeView(NavigationView& nav) {
new_view->on_changed = [this, &button](rf::Frequency f) { new_view->on_changed = [this, &button](rf::Frequency f) {
update_width(f); update_width(f);
}; };
//update_button(button, f);
}; };
options_preset.on_change = [this](size_t, OptionsField::value_t v) { button_load_range.on_select = [this, &nav](Button&) {
update_min(range_presets[v].min); auto load_view = nav.push<FrequencyLoadView>();
update_max(range_presets[v].max); load_view->on_frequency_loaded = [this](rf::Frequency value) {
check_enabled.set_value(true); update_center(value);
update_width(100000); // 100kHz default jamming bandwidth when loading unique frequency
};
load_view->on_range_loaded = [this](rf::Frequency start, rf::Frequency stop) {
update_start(start);
update_stop(stop);
};
}; };
options_preset.set_selected_index(11); // ISM 868
check_enabled.set_value(false); check_enabled.set_value(false);
} }

View File

@ -43,8 +43,8 @@ public:
jammer_range_t frequency_range { false, 0, 0 }; jammer_range_t frequency_range { false, 0, 0 };
private: private:
void update_min(rf::Frequency f); void update_start(rf::Frequency f);
void update_max(rf::Frequency f); void update_stop(rf::Frequency f);
void update_center(rf::Frequency f); void update_center(rf::Frequency f);
void update_width(uint32_t w); void update_width(uint32_t w);
@ -57,7 +57,7 @@ private:
.foreground = Color::grey(), .foreground = Color::grey(),
}; };
static constexpr jammer_range_t range_presets[] = { /*static constexpr jammer_range_t range_presets[] = {
// GSM900 Orange // GSM900 Orange
{ true, 935000000, 945000000 }, // BW:10M { true, 935000000, 945000000 }, // BW:10M
// GSM1800 Orange // GSM1800 Orange
@ -122,10 +122,9 @@ private:
{ true, 2467000000 - 11000000, 2467000000 + 11000000}, // BW: 22MHz { true, 2467000000 - 11000000, 2467000000 + 11000000}, // BW: 22MHz
// WLAN 2.4G CH13 // WLAN 2.4G CH13
{ true, 2472000000 - 11000000, 2472000000 + 11000000}, // BW: 22MHz { true, 2472000000 - 11000000, 2472000000 + 11000000}, // BW: 22MHz
}; };*/
Labels labels { Labels labels {
{ { 1 * 8, 4 * 8 }, "Preset:", Color::light_grey() },
{ { 2 * 8, 9 * 8 + 4 }, "Start", Color::light_grey() }, { { 2 * 8, 9 * 8 + 4 }, "Start", Color::light_grey() },
{ { 23 * 8, 9 * 8 + 4 }, "Stop", Color::light_grey() }, { { 23 * 8, 9 * 8 + 4 }, "Stop", Color::light_grey() },
{ { 12 * 8, 6 * 8 }, "Center", Color::light_grey() }, { { 12 * 8, 6 * 8 }, "Center", Color::light_grey() },
@ -133,51 +132,21 @@ private:
}; };
Checkbox check_enabled { Checkbox check_enabled {
{ 7 * 8, 4 }, { 1 * 8, 4 },
12, 12,
"Enable range", "Enable range"
false
}; };
OptionsField options_preset { Button button_load_range {
{ 9 * 8, 4 * 8 }, { 18 * 8, 4, 12 * 8, 24 },
19, "Load range"
{
{ "GSM900 Orange FR", 0 },
{ "GSM1800 Orange FR", 1 },
{ "GSM900 SFR FR", 2 },
{ "GSM1800 SFR FR", 3 },
{ "GSM900 Bouygues FR", 4 },
{ "GSM1800 Bouygues FR", 5 },
{ "GSM Free FR", 6 },
{ "GSM-R FR", 7 },
{ "DECT", 8 },
{ "Optifib", 9 },
{ "ISM 433", 10 },
{ "ISM 868", 11 },
{ "GPS L1", 12 },
{ "GPS L2", 13 },
{ "WLAN 2.4G CH1", 14 },
{ "WLAN 2.4G CH2", 15 },
{ "WLAN 2.4G CH3", 16 },
{ "WLAN 2.4G CH4", 17 },
{ "WLAN 2.4G CH5", 18 },
{ "WLAN 2.4G CH6", 19 },
{ "WLAN 2.4G CH7", 20 },
{ "WLAN 2.4G CH8", 21 },
{ "WLAN 2.4G CH9", 22 },
{ "WLAN 2.4G CH10", 23 },
{ "WLAN 2.4G CH11", 24 },
{ "WLAN 2.4G CH12", 25 },
{ "WLAN 2.4G CH13", 26 }
}
}; };
Button button_min { Button button_start {
{ 0 * 8, 6 * 16, 11 * 8, 28 }, { 0 * 8, 6 * 16, 11 * 8, 28 },
"" ""
}; };
Button button_max { Button button_stop {
{ 19 * 8, 6 * 16, 11 * 8, 28 }, { 19 * 8, 6 * 16, 11 * 8, 28 },
"" ""
}; };

View File

@ -27,9 +27,15 @@ namespace ui {
/* MenuItemView **********************************************************/ /* MenuItemView **********************************************************/
void MenuItemView::set_item(MenuItem* item_) {
item = item_;
}
void MenuItemView::select() { void MenuItemView::select() {
if( item.on_select ) { if (!item) return;
item.on_select();
if( item->on_select ) {
item->on_select();
} }
} }
@ -46,14 +52,16 @@ void MenuItemView::unhighlight() {
void MenuItemView::paint(Painter& painter) { void MenuItemView::paint(Painter& painter) {
Coord offset_x; Coord offset_x;
if (!item) return;
const auto r = screen_rect(); const auto r = screen_rect();
const auto paint_style = (highlighted() && (parent()->has_focus() || keep_highlight_)) ? style().invert() : style(); const auto paint_style = (highlighted() && (parent()->has_focus() || keep_highlight)) ? style().invert() : style();
const auto font_height = paint_style.font.line_height(); const auto font_height = paint_style.font.line_height();
ui::Color final_item_color = (highlighted() && (parent()->has_focus() || keep_highlight_)) ? paint_style.foreground : item.color; ui::Color final_item_color = (highlighted() && (parent()->has_focus() || keep_highlight)) ? paint_style.foreground : item->color;
ui::Color final_bg_color = (highlighted() && (parent()->has_focus() || keep_highlight_)) ? item.color : paint_style.background; ui::Color final_bg_color = (highlighted() && (parent()->has_focus() || keep_highlight)) ? item->color : paint_style.background;
if (final_item_color.v == final_bg_color.v) final_item_color = paint_style.foreground; if (final_item_color.v == final_bg_color.v) final_item_color = paint_style.foreground;
@ -62,10 +70,10 @@ void MenuItemView::paint(Painter& painter) {
final_bg_color final_bg_color
); );
if (item.bitmap) { if (item->bitmap) {
painter.draw_bitmap( painter.draw_bitmap(
{ r.location().x() + 4, r.location().y() + 4 }, { r.location().x() + 4, r.location().y() + 4 },
*item.bitmap, *item->bitmap,
final_item_color, final_item_color,
final_bg_color final_bg_color
); );
@ -82,7 +90,7 @@ void MenuItemView::paint(Painter& painter) {
painter.draw_string( painter.draw_string(
{ r.location().x() + offset_x, r.location().y() + (r.size().height() - font_height) / 2 }, { r.location().x() + offset_x, r.location().y() + (r.size().height() - font_height) / 2 },
text_style, text_style,
item.text item->text
); );
} }
@ -91,7 +99,7 @@ void MenuItemView::paint(Painter& painter) {
MenuView::MenuView( MenuView::MenuView(
Rect new_parent_rect, Rect new_parent_rect,
bool keep_highlight bool keep_highlight
) : keep_highlight_ { keep_highlight } ) : keep_highlight { keep_highlight }
{ {
set_parent_rect(new_parent_rect); set_parent_rect(new_parent_rect);
@ -108,45 +116,65 @@ MenuView::MenuView(
MenuView::~MenuView() { MenuView::~MenuView() {
rtc_time::signal_tick_second -= signal_token_tick_second; rtc_time::signal_tick_second -= signal_token_tick_second;
for (auto item : menu_items_) {
for (auto item : menu_item_views) {
delete item; delete item;
} }
} }
void MenuView::set_parent_rect(const Rect new_parent_rect) { void MenuView::set_parent_rect(const Rect new_parent_rect) {
View::set_parent_rect(new_parent_rect); View::set_parent_rect(new_parent_rect);
displayed_max_ = (parent_rect().size().height() / 24); displayed_max = (parent_rect().size().height() / item_height);
arrow_more.set_parent_rect( { 228, (Coord)(displayed_max_ * item_height), 8, 8 } ); arrow_more.set_parent_rect( { 228, (Coord)(displayed_max * item_height), 8, 8 } );
// TODO: Clean this up :(
if (menu_item_views.size()) {
for (auto item : menu_item_views) {
remove_child(item);
delete item;
}
}
menu_item_views.clear();
for (size_t c = 0; c < displayed_max; c++) {
auto item = new MenuItemView { keep_highlight };
menu_item_views.push_back(item);
add_child(item);
auto y_pos = c * item_height;
item->set_parent_rect({
{ 0, y_pos },
{ size().width(), (Coord)item_height }
});
}
update_items();
} }
void MenuView::on_tick_second() { void MenuView::on_tick_second() {
if (more_ && blink_) if (more && blink)
arrow_more.set_foreground(Color::white()); arrow_more.set_foreground(Color::white());
else else
arrow_more.set_foreground(Color::black()); arrow_more.set_foreground(Color::black());
blink_ = !blink_; blink = !blink;
arrow_more.set_dirty(); arrow_more.set_dirty();
} }
void MenuView::clear() { void MenuView::clear() {
for (auto item : menu_items_) { for (auto item : menu_item_views) {
remove_child(item); item->set_item(nullptr);
delete item;
} }
menu_items_.clear();
update_items(); menu_items.clear();
} }
void MenuView::add_item(MenuItem new_item) { void MenuView::add_item(MenuItem new_item) {
auto item = new MenuItemView { new_item, keep_highlight_ }; menu_items.push_back(new_item);
menu_items_.push_back(item);
add_child(item);
update_items(); update_items();
} }
@ -161,38 +189,34 @@ void MenuView::update_items() {
size_t i = 0; size_t i = 0;
int32_t y_pos; int32_t y_pos;
if (menu_items_.size() > displayed_max_ + offset_) { if (menu_items.size() > displayed_max + offset) {
more_ = true; more = true;
blink_ = true; blink = true;
} else } else
more_ = false; more = false;
for (auto item : menu_items_) { for (auto item : menu_item_views) {
y_pos = (i - offset_) * item_height; if (i + offset >= menu_items.size()) break;
item->set_parent_rect({
{ 0, y_pos }, // Assign item data to MenuItemViews according to offset
{ size().width(), (Coord)item_height } item->set_item(&menu_items[i + offset]);
}); item->set_dirty();
if ((y_pos < 0) || (y_pos > (Coord)(screen_rect().size().height() - item_height)))
item->hidden(true); if (highlighted_item == (i + offset)) {
else item->highlight();
item->hidden(false); } else
item->unhighlight();
i++; i++;
} }
set_dirty();
} }
MenuItemView* MenuView::item_view(size_t index) const { MenuItemView* MenuView::item_view(size_t index) const {
return menu_items_[index]; return menu_item_views[index];
}
size_t MenuView::highlighted() const {
return highlighted_;
} }
bool MenuView::set_highlighted(int32_t new_value) { bool MenuView::set_highlighted(int32_t new_value) {
int32_t item_count = (int32_t)menu_items_.size(); int32_t item_count = (int32_t)menu_items.size();
if (new_value < 0) if (new_value < 0)
return false; return false;
@ -200,42 +224,49 @@ bool MenuView::set_highlighted(int32_t new_value) {
if (new_value >= item_count) if (new_value >= item_count)
new_value = item_count - 1; new_value = item_count - 1;
if (((uint32_t)new_value > offset_) && ((new_value - offset_) >= displayed_max_)) { if (((uint32_t)new_value > offset) && ((new_value - offset) >= displayed_max)) {
// Shift MenuView up // Shift MenuView up
offset_ = new_value - displayed_max_ + 1; highlighted_item = new_value;
offset = new_value - displayed_max + 1;
update_items(); update_items();
} else if ((uint32_t)new_value < offset_) { } else if ((uint32_t)new_value < offset) {
// Shift MenuView down // Shift MenuView down
offset_ = new_value; highlighted_item = new_value;
offset = new_value;
update_items(); update_items();
} else {
// Just update highlight
item_view(highlighted_item - offset)->unhighlight();
highlighted_item = new_value;
item_view(highlighted_item - offset)->highlight();
} }
item_view(highlighted_)->unhighlight();
highlighted_ = new_value;
item_view(highlighted_)->highlight();
return true; return true;
} }
uint32_t MenuView::highlighted_index() {
return highlighted_item;
}
void MenuView::on_focus() { void MenuView::on_focus() {
item_view(highlighted())->highlight(); item_view(highlighted_item)->highlight();
} }
void MenuView::on_blur() { void MenuView::on_blur() {
if (!keep_highlight_) item_view(highlighted())->unhighlight(); if (!keep_highlight) item_view(highlighted_item)->unhighlight();
} }
bool MenuView::on_key(const KeyEvent key) { bool MenuView::on_key(const KeyEvent key) {
switch(key) { switch(key) {
case KeyEvent::Up: case KeyEvent::Up:
return set_highlighted(highlighted() - 1); return set_highlighted(highlighted_item - 1);
case KeyEvent::Down: case KeyEvent::Down:
return set_highlighted(highlighted() + 1); return set_highlighted(highlighted_item + 1);
case KeyEvent::Select: case KeyEvent::Select:
case KeyEvent::Right: case KeyEvent::Right:
item_view(highlighted())->select(); item_view(highlighted_item - offset)->select();
return true; return true;
case KeyEvent::Left: case KeyEvent::Left:
@ -250,7 +281,7 @@ bool MenuView::on_key(const KeyEvent key) {
} }
bool MenuView::on_encoder(const EncoderEvent event) { bool MenuView::on_encoder(const EncoderEvent event) {
set_highlighted(highlighted() + event); set_highlighted(highlighted_item + event);
return true; return true;
} }

View File

@ -49,22 +49,27 @@ struct MenuItem {
class MenuItemView : public Widget { class MenuItemView : public Widget {
public: public:
MenuItemView( MenuItemView(
MenuItem item,
bool keep_highlight bool keep_highlight
) : item { item }, ) : keep_highlight { keep_highlight }
keep_highlight_ { keep_highlight }
{ {
} }
MenuItemView(const MenuItemView&) = delete;
MenuItemView(MenuItemView&&) = delete;
MenuItemView& operator=(const MenuItemView&) = delete;
MenuItemView& operator=(MenuItemView&&) = delete;
void paint(Painter& painter) override; void paint(Painter& painter) override;
void set_item(MenuItem* item_);
void select(); void select();
void highlight(); void highlight();
void unhighlight(); void unhighlight();
private: private:
const MenuItem item; MenuItem* item { nullptr };
bool keep_highlight_ = false; bool keep_highlight = false;
}; };
class MenuView : public View { class MenuView : public View {
@ -81,8 +86,8 @@ public:
MenuItemView* item_view(size_t index) const; MenuItemView* item_view(size_t index) const;
size_t highlighted() const;
bool set_highlighted(int32_t new_value); bool set_highlighted(int32_t new_value);
uint32_t highlighted_index();
void set_parent_rect(const Rect new_parent_rect) override; void set_parent_rect(const Rect new_parent_rect) override;
void on_focus() override; void on_focus() override;
@ -94,10 +99,11 @@ private:
void update_items(); void update_items();
void on_tick_second(); void on_tick_second();
bool keep_highlight_ { false }; bool keep_highlight { false };
SignalToken signal_token_tick_second { }; SignalToken signal_token_tick_second { };
std::vector<MenuItemView*> menu_items_ { }; std::vector<MenuItem> menu_items { };
std::vector<MenuItemView*> menu_item_views { };
Image arrow_more { Image arrow_more {
{ 228, 320 - 8, 8, 8 }, { 228, 320 - 8, 8, 8 },
@ -107,11 +113,11 @@ private:
}; };
const size_t item_height = 24; const size_t item_height = 24;
bool blink_ = false; bool blink = false;
bool more_ = false; bool more = false;
size_t displayed_max_ { 0 }; size_t displayed_max { 0 };
size_t highlighted_ { 0 }; size_t highlighted_item { 0 };
size_t offset_ { 0 }; size_t offset { 0 };
}; };
} /* namespace ui */ } /* namespace ui */

View File

@ -364,10 +364,10 @@ SystemMenuView::SystemMenuView(NavigationView& nav) {
{ "Receivers", ui::Color::cyan(), &bitmap_icon_receivers, [&nav](){ nav.push<ReceiversMenuView>(); } }, { "Receivers", ui::Color::cyan(), &bitmap_icon_receivers, [&nav](){ nav.push<ReceiversMenuView>(); } },
{ "Transmitters", ui::Color::green(), &bitmap_icon_transmit, [&nav](){ nav.push<TransmittersMenuView>(); } }, { "Transmitters", ui::Color::green(), &bitmap_icon_transmit, [&nav](){ nav.push<TransmittersMenuView>(); } },
{ "Capture", ui::Color::blue(), &bitmap_icon_capture, [&nav](){ nav.push<CaptureAppView>(); } }, { "Capture", ui::Color::blue(), &bitmap_icon_capture, [&nav](){ nav.push<CaptureAppView>(); } },
{ "Replay", ui::Color::grey(), &bitmap_icon_replay, [&nav](){ nav.push<ReplayAppView>(); } }, { "Replay", ui::Color::purple(), &bitmap_icon_replay, [&nav](){ nav.push<ReplayAppView>(); } },
{ "Scanner/search", ui::Color::orange(), &bitmap_icon_closecall, [&nav](){ nav.push<ScannerView>(); } }, { "Scanner/search", ui::Color::orange(), &bitmap_icon_closecall, [&nav](){ nav.push<ScannerView>(); } },
{ "Wave file viewer", ui::Color::blue(), nullptr, [&nav](){ nav.push<ViewWavView>(); } }, { "Wave file viewer", ui::Color::blue(), nullptr, [&nav](){ nav.push<ViewWavView>(); } },
{ "Utilities", ui::Color::purple(), &bitmap_icon_utilities, [&nav](){ nav.push<UtilitiesMenuView>(); } }, { "Utilities", ui::Color::light_grey(), &bitmap_icon_utilities, [&nav](){ nav.push<UtilitiesMenuView>(); } },
{ "Setup", ui::Color::white(), &bitmap_icon_setup, [&nav](){ nav.push<SetupMenuView>(); } }, { "Setup", ui::Color::white(), &bitmap_icon_setup, [&nav](){ nav.push<SetupMenuView>(); } },
//{ "Debug", ui::Color::white(), nullptr, [&nav](){ nav.push<DebugMenuView>(); } }, //{ "Debug", ui::Color::white(), nullptr, [&nav](){ nav.push<DebugMenuView>(); } },
{ "HackRF mode", ui::Color::white(), &bitmap_icon_hackrf, [this, &nav](){ hackrf_mode(nav); } }, { "HackRF mode", ui::Color::white(), &bitmap_icon_hackrf, [this, &nav](){ hackrf_mode(nav); } },

View File

@ -149,7 +149,7 @@ FrequencyKeypadView::FrequencyKeypadView(
}; };
button_load.on_select = [this, &nav](Button&) { button_load.on_select = [this, &nav](Button&) {
auto load_view = nav.push<FrequencyLoadView>(); auto load_view = nav.push<FrequencyLoadView>();
load_view->on_changed = [this](rf::Frequency value) { load_view->on_frequency_loaded = [this](rf::Frequency value) {
set_value(value); set_value(value);
}; };
}; };

View File

@ -97,7 +97,7 @@ private:
}; };
Checkbox check_log { Checkbox check_log {
{ 22 * 8, 2 * 16 + 12 }, { 22 * 8, 3 * 16 },
3, 3,
"Log" "Log"
}; };

View File

@ -35,7 +35,7 @@ Packet::Packet(
{ {
if (type_ == Type::Meteomodem_unknown) { if (type_ == Type::Meteomodem_unknown) {
// Right now we're just sure that the sync is from a Meteomodem sonde, differentiate between models now // Right now we're just sure that the sync is from a Meteomodem sonde, differentiate between models now
const uint32_t id_byte = reader_bi_m.read(1 * 8, 16); const uint32_t id_byte = reader_bi_m.read(0 * 8, 16);
if (id_byte == 0x649F) if (id_byte == 0x649F)
type_ = Type::Meteomodem_M10; type_ = Type::Meteomodem_M10;
@ -128,7 +128,7 @@ std::string Packet::serial_number() const {
to_string_dec_uint(reader_bi_m.read(93 * 8 + 27, 13), 4, '0'); to_string_dec_uint(reader_bi_m.read(93 * 8 + 27, 13), 4, '0');
} else } else
return 0; return "?";
} }
FormattedSymbols Packet::symbols_formatted() const { FormattedSymbols Packet::symbols_formatted() const {

Binary file not shown.

74
sdcard/FREQMAN/JAMMER.TXT Normal file
View File

@ -0,0 +1,74 @@
a=935000000,b=945000000,d=GSM900 Orange FR
a=1808000000,b=1832000000,d=GSM1800 Orange FR
a=950000000,b=960000000,d=GSM900 SFR FR
a=1832000000,b=1853000000,d=GSM1800 SFR FR
a=925000000,b=935000000,d=GSM900 Bouygues FR
a=1858000000,b=1880000000,d=GSM1800 Bouygues FR
a=945000000,b=950000000,d=GSM Free FR
a=921000000,b=925000000,d=GSM-R FR
a=1880000000,b=1900000000,d=DECT
a=162930000,b=162970000,d=PMV AFSK
a=433050000,b=434790000,d=ISM 433
a=868000000,b=868200000,d=ISM 868
a=1574920000,b=1575920000,d=GPS L1
a=1226600000,b=1228600000,d=GPS L2
a=2401000000,b=2423000000,d=WLAN 2.4G CH1
a=2406000000,b=2428000000,d=WLAN 2.4G CH2
a=2411000000,b=2433000000,d=WLAN 2.4G CH3
a=2416000000,b=2438000000,d=WLAN 2.4G CH4
a=2421000000,b=2443000000,d=WLAN 2.4G CH5
a=2426000000,b=2448000000,d=WLAN 2.4G CH6
a=2431000000,b=2453000000,d=WLAN 2.4G CH7
a=2436000000,b=2458000000,d=WLAN 2.4G CH8
a=2441000000,b=2463000000,d=WLAN 2.4G CH9
a=2446000000,b=2468000000,d=WLAN 2.4G CH10
a=2451000000,b=2473000000,d=WLAN 2.4G CH11
a=2456000000,b=2478000000,d=WLAN 2.4G CH12
a=2461000000,b=2483000000,d=WLAN 2.4G CH13
a=5170000000,b=5190000000,d=WLAN 5G CH36
a=5170000000,b=5210000000,d=WLAN 5G CH38
a=5190000000,b=5210000000,d=WLAN 5G CH40
a=5170000000,b=5250000000,d=WLAN 5G CH42
a=5210000000,b=5230000000,d=WLAN 5G CH44
a=5210000000,b=5250000000,d=WLAN 5G CH46
a=5230000000,b=5250000000,d=WLAN 5G CH48
a=5170000000,b=5330000000,d=WLAN 5G CH50
a=5250000000,b=5270000000,d=WLAN 5G CH52
a=5250000000,b=5290000000,d=WLAN 5G CH54
a=5270000000,b=5290000000,d=WLAN 5G CH56
a=5250000000,b=5330000000,d=WLAN 5G CH58
a=5290000000,b=5310000000,d=WLAN 5G CH60
a=5290000000,b=5330000000,d=WLAN 5G CH62
a=5310000000,b=5330000000,d=WLAN 5G CH64
a=5490000000,b=5510000000,d=WLAN 5G CH100
a=5490000000,b=5530000000,d=WLAN 5G CH102
a=5510000000,b=5530000000,d=WLAN 5G CH104
a=5490000000,b=5570000000,d=WLAN 5G CH106
a=5530000000,b=5550000000,d=WLAN 5G CH108
a=5530000000,b=5570000000,d=WLAN 5G CH110
a=5550000000,b=5570000000,d=WLAN 5G CH112
a=5490000000,b=5650000000,d=WLAN 5G CH114
a=5570000000,b=5590000000,d=WLAN 5G CH116
a=5570000000,b=5610000000,d=WLAN 5G CH118
a=5590000000,b=5610000000,d=WLAN 5G CH120
a=5570000000,b=5650000000,d=WLAN 5G CH122
a=5610000000,b=5630000000,d=WLAN 5G CH124
a=5610000000,b=5650000000,d=WLAN 5G CH126
a=5630000000,b=5650000000,d=WLAN 5G CH128
a=5650000000,b=5670000000,d=WLAN 5G CH132
a=5650000000,b=5690000000,d=WLAN 5G CH134
a=5670000000,b=5690000000,d=WLAN 5G CH136
a=5650000000,b=5730000000,d=WLAN 5G CH138
a=5690000000,b=5710000000,d=WLAN 5G CH140
a=5690000000,b=5730000000,d=WLAN 5G CH142
a=5710000000,b=5730000000,d=WLAN 5G CH144
a=5735000000,b=5755000000,d=WLAN 5G CH149
a=5735000000,b=5775000000,d=WLAN 5G CH151
a=5755000000,b=5775000000,d=WLAN 5G CH153
a=5735000000,b=5815000000,d=WLAN 5G CH155
a=5775000000,b=5795000000,d=WLAN 5G CH157
a=5775000000,b=5815000000,d=WLAN 5G CH159
a=5795000000,b=5815000000,d=WLAN 5G CH161
a=5815000000,b=5835000000,d=WLAN 5G CH165
a=5835000000,b=5855000000,d=WLAN 5G CH169
a=5855000000,b=5875000000,d=WLAN 5G CH173