diff --git a/firmware/application/freqman.cpp b/firmware/application/freqman.cpp index 0ec47d5da..e7daa0a60 100644 --- a/firmware/application/freqman.cpp +++ b/firmware/application/freqman.cpp @@ -42,8 +42,9 @@ bool load_freqman_file(std::string& file_stem, freqman_db &db) { char * line_start; char * line_end; std::string description; - rf::Frequency value; + rf::Frequency frequency_a, frequency_b; char file_data[256]; + freqman_entry_type type; db.entries.clear(); @@ -63,18 +64,34 @@ bool load_freqman_file(std::string& file_stem, freqman_db &db) { line_start = file_data; - pos = strstr(file_data, "f="); - if (!pos) break; + if (!strstr(file_data, "f=") && !strstr(file_data, "a=")) + break; // Look for complete lines in buffer while ((line_end = strstr(line_start, "\x0A"))) { // Read frequency pos = strstr(line_start, "f="); + frequency_b = 0; + type = SINGLE; if (pos) { pos += 2; - value = strtoll(pos, nullptr, 10); - } else - value = 0; + frequency_a = strtoll(pos, nullptr, 10); + } else { + // ...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 pos = strstr(line_start, "d="); @@ -85,7 +102,7 @@ bool load_freqman_file(std::string& file_stem, freqman_db &db) { } else description = "-"; - db.entries.push_back({ value, "", description }); + db.entries.push_back({ frequency_a, frequency_b, description, type }); n++; 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) { File freqman_file; std::string item_string; - rf::Frequency f; + rf::Frequency frequency_a, frequency_b; if (!create_freqman_file(file_stem, freqman_file)) return false; for (size_t n = 0; n < db.entries.size(); n++) { - f = db.entries[n].value; - item_string = "f=" + to_string_dec_uint(f / 1000) + to_string_dec_uint(f % 1000UL, 3, '0'); // Please forgive me + auto& entry = db.entries[n]; + + frequency_a = entry.frequency_a; - if (db.entries[n].description.size()) - item_string += ",d=" + db.entries[n].description; + if (entry.type == SINGLE) { + // 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); } @@ -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 item_string, frequency_str, description; - rf::Frequency value; + std::string item_string; + + 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; - 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) + if (item_string.size() > max_length) return item_string.substr(0, max_length - 3) + "..."; return item_string; diff --git a/firmware/application/freqman.hpp b/firmware/application/freqman.hpp index 527d2089b..3da0cbb65 100644 --- a/firmware/application/freqman.hpp +++ b/firmware/application/freqman.hpp @@ -43,10 +43,16 @@ enum freqman_error { ERROR_DUPLICATE }; +enum freqman_entry_type { + SINGLE = 0, + RANGE +}; + struct freqman_entry { - rf::Frequency value { 0 }; - std::string frequency_str { }; + rf::Frequency frequency_a { 0 }; + rf::Frequency frequency_b { 0 }; std::string description { }; + freqman_entry_type type { }; }; struct freqman_db { diff --git a/firmware/application/main.cpp b/firmware/application/main.cpp index 32eeadede..ebea5fcde 100755 --- a/firmware/application/main.cpp +++ b/firmware/application/main.cpp @@ -33,6 +33,7 @@ //BUG: SCANNER Multiple slices //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: Clean up ReplayThread //TODO: Cap Wav viewer position @@ -40,7 +41,6 @@ //TODO: Use unit_auto_scale //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: Super simple text file viewer //TODO: De bruijn sequence scanner for encoders //TODO: FILEMAN Rename folders //TODO: FILEMAN Move files diff --git a/firmware/application/ui_about.cpp b/firmware/application/ui_about.cpp index 5b9182b53..faecaa0a0 100644 --- a/firmware/application/ui_about.cpp +++ b/firmware/application/ui_about.cpp @@ -82,7 +82,7 @@ void AboutView::update() { std::array pixel_row; slow_down++; - if (slow_down & 1) return; + if (slow_down % 3 < 2) return; if (!timer) { if (loop) { diff --git a/firmware/application/ui_about.hpp b/firmware/application/ui_about.hpp index dd304b816..3e138c005 100644 --- a/firmware/application/ui_about.hpp +++ b/firmware/application/ui_about.hpp @@ -72,7 +72,7 @@ private: int32_t delay; } credits_t; - const credits_t credits[24] = { + const credits_t credits[25] = { // 012345678901234567890123456789 { 60, "PortaPack|HAVOC", 0 }, { 7 * 8, "Git hash " GIT_REVISION, 16 }, @@ -90,12 +90,13 @@ private: { 0 * 8, "TouchTunes infos Notpike", 16 }, { 4 * 8, "Subaru infos Tom", 0 }, { 18 * 8, "Wimmenhove", 24 }, - { 12 * 8, "Thanks", 16 }, + { 6 * 8, "Thanks & donators", 16 }, { 1 * 8, "Rainer Matla Keld Norman", 0 }, { 1 * 8, " Giorgio C. DC1RDB", 0 }, { 1 * 8, " Sigmounte Waax", 0 }, { 1 * 8, " Windyoona Channels", 0 }, - { 1 * 8, " F4GEV", 24 }, + { 1 * 8, " F4GEV Pyr3x", 0 }, + { 1 * 8, " HB3YOE", 24 }, { 12 * 8, "MMXVII", -1 } }; diff --git a/firmware/application/ui_fileman.cpp b/firmware/application/ui_fileman.cpp index 46c9c0b6d..2123bcbd4 100644 --- a/firmware/application/ui_fileman.cpp +++ b/firmware/application/ui_fileman.cpp @@ -61,7 +61,7 @@ std::filesystem::path FileManBaseView::get_selected_path() { if (selected_path_str.back() != '/') 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; } @@ -225,13 +225,13 @@ FileLoadView::FileLoadView( refresh_list(); 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()); refresh_list(); } else { nav_.pop(); 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(); 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()); refresh_list(); } else @@ -302,13 +302,13 @@ FileManagerView::FileManagerView( }; 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); }; button_delete.on_select = [this, &nav](Button&) { // Use display_modal ? - nav.push("Delete", "Delete " + entry_list[menu_view.highlighted()].entry_path.filename().string() + "\nAre you sure ?", YESNO, + nav.push("Delete", "Delete " + entry_list[menu_view.highlighted_index()].entry_path.filename().string() + "\nAre you sure ?", YESNO, [this](bool choice) { if (choice) on_delete(); diff --git a/firmware/application/ui_freqman.cpp b/firmware/application/ui_freqman.cpp index e91bfa392..fca5d94e6 100644 --- a/firmware/application/ui_freqman.cpp +++ b/firmware/application/ui_freqman.cpp @@ -147,13 +147,13 @@ void FrequencySaveView::save_current_file() { void FrequencySaveView::on_save_name() { 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(); }); } 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(); } @@ -224,13 +224,26 @@ FrequencyLoadView::FrequencyLoadView( on_select_frequency = [&nav, this]() { 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) { - database.entries[menu_view.highlighted()].value = f; + database.entries[menu_view.highlighted()].frequency_a = f; save_freqman_file(file_list[current_category_id], database); refresh_list(); } @@ -308,7 +321,7 @@ FrequencyManagerView::FrequencyManagerView( }; button_edit_freq.on_select = [this, &nav](Button&) { - auto new_view = nav.push(database.entries[menu_view.highlighted()].value); + auto new_view = nav.push(database.entries[menu_view.highlighted()].frequency_a); new_view->on_changed = [this](rf::Frequency f) { on_edit_freq(f); }; diff --git a/firmware/application/ui_freqman.hpp b/firmware/application/ui_freqman.hpp index 3fc80a47b..280182537 100644 --- a/firmware/application/ui_freqman.hpp +++ b/firmware/application/ui_freqman.hpp @@ -121,7 +121,8 @@ private: class FrequencyLoadView : public FreqManBaseView { public: - std::function on_changed { }; + std::function on_frequency_loaded { }; + std::function on_range_loaded { }; FrequencyLoadView(NavigationView& nav); diff --git a/firmware/application/ui_jammer.cpp b/firmware/application/ui_jammer.cpp index 0ee7016fb..18be141f8 100644 --- a/firmware/application/ui_jammer.cpp +++ b/firmware/application/ui_jammer.cpp @@ -22,6 +22,7 @@ #include "ui_jammer.hpp" #include "ui_receiver.hpp" +#include "ui_freqman.hpp" #include "baseband_api.hpp" #include "string_format.hpp" @@ -34,13 +35,12 @@ void RangeView::focus() { check_enabled.focus(); } -extern constexpr jammer_range_t RangeView::range_presets[]; extern constexpr Style RangeView::style_info; -void RangeView::update_min(rf::Frequency f) { +void RangeView::update_start(rf::Frequency f) { // Change everything except max 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; 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)); } -void RangeView::update_max(rf::Frequency f) { +void RangeView::update_stop(rf::Frequency f) { // Change everything except min 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; width = abs(frequency_range.max - frequency_range.min); @@ -70,10 +70,10 @@ void RangeView::update_center(rf::Frequency f) { rf::Frequency max = min + width; 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; - 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) { @@ -86,10 +86,10 @@ void RangeView::update_width(uint32_t w) { rf::Frequency max = min + width; 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; - button_max.set_text(to_string_short_freq(max)); + button_stop.set_text(to_string_short_freq(max)); } void RangeView::paint(Painter&) { @@ -123,9 +123,9 @@ RangeView::RangeView(NavigationView& nav) { add_children({ &labels, &check_enabled, - &options_preset, - &button_min, - &button_max, + &button_load_range, + &button_start, + &button_stop, &button_center, &button_width }); @@ -134,22 +134,18 @@ RangeView::RangeView(NavigationView& nav) { 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(frequency_range.min); 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(frequency_range.max); 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) { @@ -157,8 +153,6 @@ RangeView::RangeView(NavigationView& nav) { new_view->on_changed = [this, &button](rf::Frequency f) { update_center(f); }; - - //update_button(button, f); }; 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) { update_width(f); }; - - //update_button(button, f); }; - options_preset.on_change = [this](size_t, OptionsField::value_t v) { - update_min(range_presets[v].min); - update_max(range_presets[v].max); - check_enabled.set_value(true); + button_load_range.on_select = [this, &nav](Button&) { + auto load_view = nav.push(); + load_view->on_frequency_loaded = [this](rf::Frequency value) { + 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); } diff --git a/firmware/application/ui_jammer.hpp b/firmware/application/ui_jammer.hpp index 448ec0a4c..6efb3a7a0 100644 --- a/firmware/application/ui_jammer.hpp +++ b/firmware/application/ui_jammer.hpp @@ -43,8 +43,8 @@ public: jammer_range_t frequency_range { false, 0, 0 }; private: - void update_min(rf::Frequency f); - void update_max(rf::Frequency f); + void update_start(rf::Frequency f); + void update_stop(rf::Frequency f); void update_center(rf::Frequency f); void update_width(uint32_t w); @@ -57,7 +57,7 @@ private: .foreground = Color::grey(), }; - static constexpr jammer_range_t range_presets[] = { + /*static constexpr jammer_range_t range_presets[] = { // GSM900 Orange { true, 935000000, 945000000 }, // BW:10M // GSM1800 Orange @@ -122,10 +122,9 @@ private: { true, 2467000000 - 11000000, 2467000000 + 11000000}, // BW: 22MHz // WLAN 2.4G CH13 { true, 2472000000 - 11000000, 2472000000 + 11000000}, // BW: 22MHz - }; + };*/ Labels labels { - { { 1 * 8, 4 * 8 }, "Preset:", Color::light_grey() }, { { 2 * 8, 9 * 8 + 4 }, "Start", Color::light_grey() }, { { 23 * 8, 9 * 8 + 4 }, "Stop", Color::light_grey() }, { { 12 * 8, 6 * 8 }, "Center", Color::light_grey() }, @@ -133,51 +132,21 @@ private: }; Checkbox check_enabled { - { 7 * 8, 4 }, + { 1 * 8, 4 }, 12, - "Enable range", - false + "Enable range" }; - OptionsField options_preset { - { 9 * 8, 4 * 8 }, - 19, - { - { "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_load_range { + { 18 * 8, 4, 12 * 8, 24 }, + "Load range" }; - Button button_min { + Button button_start { { 0 * 8, 6 * 16, 11 * 8, 28 }, "" }; - Button button_max { + Button button_stop { { 19 * 8, 6 * 16, 11 * 8, 28 }, "" }; diff --git a/firmware/application/ui_menu.cpp b/firmware/application/ui_menu.cpp index 128a44a53..c7a23a53f 100644 --- a/firmware/application/ui_menu.cpp +++ b/firmware/application/ui_menu.cpp @@ -27,9 +27,15 @@ namespace ui { /* MenuItemView **********************************************************/ +void MenuItemView::set_item(MenuItem* item_) { + item = item_; +} + void MenuItemView::select() { - if( item.on_select ) { - item.on_select(); + if (!item) return; + + if( item->on_select ) { + item->on_select(); } } @@ -46,14 +52,16 @@ void MenuItemView::unhighlight() { void MenuItemView::paint(Painter& painter) { Coord offset_x; + if (!item) return; + 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(); - 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_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; 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 ); - if (item.bitmap) { + if (item->bitmap) { painter.draw_bitmap( { r.location().x() + 4, r.location().y() + 4 }, - *item.bitmap, + *item->bitmap, final_item_color, final_bg_color ); @@ -82,7 +90,7 @@ void MenuItemView::paint(Painter& painter) { painter.draw_string( { r.location().x() + offset_x, r.location().y() + (r.size().height() - font_height) / 2 }, text_style, - item.text + item->text ); } @@ -91,7 +99,7 @@ void MenuItemView::paint(Painter& painter) { MenuView::MenuView( Rect new_parent_rect, bool keep_highlight -) : keep_highlight_ { keep_highlight } +) : keep_highlight { keep_highlight } { set_parent_rect(new_parent_rect); @@ -108,45 +116,65 @@ MenuView::MenuView( MenuView::~MenuView() { rtc_time::signal_tick_second -= signal_token_tick_second; - for (auto item : menu_items_) { + + for (auto item : menu_item_views) { delete item; } } void MenuView::set_parent_rect(const Rect new_parent_rect) { - View::set_parent_rect(new_parent_rect); - displayed_max_ = (parent_rect().size().height() / 24); - arrow_more.set_parent_rect( { 228, (Coord)(displayed_max_ * item_height), 8, 8 } ); + displayed_max = (parent_rect().size().height() / item_height); + 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() { - if (more_ && blink_) + if (more && blink) arrow_more.set_foreground(Color::white()); else arrow_more.set_foreground(Color::black()); - blink_ = !blink_; + blink = !blink; arrow_more.set_dirty(); } void MenuView::clear() { - for (auto item : menu_items_) { - remove_child(item); - delete item; + for (auto item : menu_item_views) { + item->set_item(nullptr); } - menu_items_.clear(); - update_items(); + menu_items.clear(); } void MenuView::add_item(MenuItem new_item) { - auto item = new MenuItemView { new_item, keep_highlight_ }; - - menu_items_.push_back(item); - add_child(item); + menu_items.push_back(new_item); update_items(); } @@ -161,38 +189,34 @@ void MenuView::update_items() { size_t i = 0; int32_t y_pos; - if (menu_items_.size() > displayed_max_ + offset_) { - more_ = true; - blink_ = true; + if (menu_items.size() > displayed_max + offset) { + more = true; + blink = true; } else - more_ = false; + more = false; - for (auto item : menu_items_) { - y_pos = (i - offset_) * item_height; - item->set_parent_rect({ - { 0, y_pos }, - { size().width(), (Coord)item_height } - }); - if ((y_pos < 0) || (y_pos > (Coord)(screen_rect().size().height() - item_height))) - item->hidden(true); - else - item->hidden(false); + for (auto item : menu_item_views) { + if (i + offset >= menu_items.size()) break; + + // Assign item data to MenuItemViews according to offset + item->set_item(&menu_items[i + offset]); + item->set_dirty(); + + if (highlighted_item == (i + offset)) { + item->highlight(); + } else + item->unhighlight(); + i++; } - - set_dirty(); } MenuItemView* MenuView::item_view(size_t index) const { - return menu_items_[index]; -} - -size_t MenuView::highlighted() const { - return highlighted_; + return menu_item_views[index]; } 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) return false; @@ -200,42 +224,49 @@ bool MenuView::set_highlighted(int32_t new_value) { if (new_value >= item_count) 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 - offset_ = new_value - displayed_max_ + 1; + highlighted_item = new_value; + offset = new_value - displayed_max + 1; update_items(); - } else if ((uint32_t)new_value < offset_) { + } else if ((uint32_t)new_value < offset) { // Shift MenuView down - offset_ = new_value; + highlighted_item = new_value; + offset = new_value; 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; } +uint32_t MenuView::highlighted_index() { + return highlighted_item; +} + void MenuView::on_focus() { - item_view(highlighted())->highlight(); + item_view(highlighted_item)->highlight(); } 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) { switch(key) { case KeyEvent::Up: - return set_highlighted(highlighted() - 1); + return set_highlighted(highlighted_item - 1); case KeyEvent::Down: - return set_highlighted(highlighted() + 1); + return set_highlighted(highlighted_item + 1); case KeyEvent::Select: case KeyEvent::Right: - item_view(highlighted())->select(); + item_view(highlighted_item - offset)->select(); return true; case KeyEvent::Left: @@ -250,7 +281,7 @@ bool MenuView::on_key(const KeyEvent key) { } bool MenuView::on_encoder(const EncoderEvent event) { - set_highlighted(highlighted() + event); + set_highlighted(highlighted_item + event); return true; } diff --git a/firmware/application/ui_menu.hpp b/firmware/application/ui_menu.hpp index 5e9e8f88e..c73cdc72e 100644 --- a/firmware/application/ui_menu.hpp +++ b/firmware/application/ui_menu.hpp @@ -49,22 +49,27 @@ struct MenuItem { class MenuItemView : public Widget { public: MenuItemView( - MenuItem item, 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 set_item(MenuItem* item_); void select(); void highlight(); void unhighlight(); private: - const MenuItem item; - bool keep_highlight_ = false; + MenuItem* item { nullptr }; + bool keep_highlight = false; }; class MenuView : public View { @@ -81,8 +86,8 @@ public: MenuItemView* item_view(size_t index) const; - size_t highlighted() const; bool set_highlighted(int32_t new_value); + uint32_t highlighted_index(); void set_parent_rect(const Rect new_parent_rect) override; void on_focus() override; @@ -94,10 +99,11 @@ private: void update_items(); void on_tick_second(); - bool keep_highlight_ { false }; + bool keep_highlight { false }; SignalToken signal_token_tick_second { }; - std::vector menu_items_ { }; + std::vector menu_items { }; + std::vector menu_item_views { }; Image arrow_more { { 228, 320 - 8, 8, 8 }, @@ -107,11 +113,11 @@ private: }; const size_t item_height = 24; - bool blink_ = false; - bool more_ = false; - size_t displayed_max_ { 0 }; - size_t highlighted_ { 0 }; - size_t offset_ { 0 }; + bool blink = false; + bool more = false; + size_t displayed_max { 0 }; + size_t highlighted_item { 0 }; + size_t offset { 0 }; }; } /* namespace ui */ diff --git a/firmware/application/ui_navigation.cpp b/firmware/application/ui_navigation.cpp index 04cb114d3..82a5af20d 100644 --- a/firmware/application/ui_navigation.cpp +++ b/firmware/application/ui_navigation.cpp @@ -364,10 +364,10 @@ SystemMenuView::SystemMenuView(NavigationView& nav) { { "Receivers", ui::Color::cyan(), &bitmap_icon_receivers, [&nav](){ nav.push(); } }, { "Transmitters", ui::Color::green(), &bitmap_icon_transmit, [&nav](){ nav.push(); } }, { "Capture", ui::Color::blue(), &bitmap_icon_capture, [&nav](){ nav.push(); } }, - { "Replay", ui::Color::grey(), &bitmap_icon_replay, [&nav](){ nav.push(); } }, + { "Replay", ui::Color::purple(), &bitmap_icon_replay, [&nav](){ nav.push(); } }, { "Scanner/search", ui::Color::orange(), &bitmap_icon_closecall, [&nav](){ nav.push(); } }, { "Wave file viewer", ui::Color::blue(), nullptr, [&nav](){ nav.push(); } }, - { "Utilities", ui::Color::purple(), &bitmap_icon_utilities, [&nav](){ nav.push(); } }, + { "Utilities", ui::Color::light_grey(), &bitmap_icon_utilities, [&nav](){ nav.push(); } }, { "Setup", ui::Color::white(), &bitmap_icon_setup, [&nav](){ nav.push(); } }, //{ "Debug", ui::Color::white(), nullptr, [&nav](){ nav.push(); } }, { "HackRF mode", ui::Color::white(), &bitmap_icon_hackrf, [this, &nav](){ hackrf_mode(nav); } }, diff --git a/firmware/application/ui_receiver.cpp b/firmware/application/ui_receiver.cpp index 6552a84e4..6e75d7cc8 100644 --- a/firmware/application/ui_receiver.cpp +++ b/firmware/application/ui_receiver.cpp @@ -149,7 +149,7 @@ FrequencyKeypadView::FrequencyKeypadView( }; button_load.on_select = [this, &nav](Button&) { auto load_view = nav.push(); - load_view->on_changed = [this](rf::Frequency value) { + load_view->on_frequency_loaded = [this](rf::Frequency value) { set_value(value); }; }; diff --git a/firmware/application/ui_sonde.hpp b/firmware/application/ui_sonde.hpp index f31ac8235..5dc7fe86a 100644 --- a/firmware/application/ui_sonde.hpp +++ b/firmware/application/ui_sonde.hpp @@ -97,7 +97,7 @@ private: }; Checkbox check_log { - { 22 * 8, 2 * 16 + 12 }, + { 22 * 8, 3 * 16 }, 3, "Log" }; diff --git a/firmware/common/sonde_packet.cpp b/firmware/common/sonde_packet.cpp index eb23508c2..22f547938 100644 --- a/firmware/common/sonde_packet.cpp +++ b/firmware/common/sonde_packet.cpp @@ -35,7 +35,7 @@ Packet::Packet( { if (type_ == Type::Meteomodem_unknown) { // 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) 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'); } else - return 0; + return "?"; } FormattedSymbols Packet::symbols_formatted() const { diff --git a/firmware/portapack-h1-havoc.bin b/firmware/portapack-h1-havoc.bin index 828f1d811..ba82a120b 100644 Binary files a/firmware/portapack-h1-havoc.bin and b/firmware/portapack-h1-havoc.bin differ diff --git a/sdcard/FREQMAN/JAMMER.TXT b/sdcard/FREQMAN/JAMMER.TXT new file mode 100644 index 000000000..5f314de80 --- /dev/null +++ b/sdcard/FREQMAN/JAMMER.TXT @@ -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