diff --git a/firmware/application/apps/ui_freqman.cpp b/firmware/application/apps/ui_freqman.cpp index 07a19fdb..75c26fca 100644 --- a/firmware/application/apps/ui_freqman.cpp +++ b/firmware/application/apps/ui_freqman.cpp @@ -81,14 +81,11 @@ void FreqManBaseView::change_category(int32_t category_id) { if (file_list.empty()) return; - std::vector().swap(database); - if (!load_freqman_file(file_list[categories[category_id].second], database)) { error_ = ERROR_ACCESS; } - menu_view.set_db(database); + freqlist_view.set_db(database); text_empty.hidden(!database.empty()); - menu_view.set_dirty(); set_dirty(); } @@ -162,10 +159,14 @@ FrequencySaveView::FrequencySaveView( }; } +FrequencyLoadView::~FrequencyLoadView() { + std::vector().swap(database); +} + void FrequencyLoadView::refresh_widgets(const bool v) { - menu_view.hidden(v); + freqlist_view.hidden(v); text_empty.hidden(!v); - // display.fill_rectangle(menu_view.screen_rect(), Color::black()); + // display.fill_rectangle(freqlist_view.screen_rect(), Color::black()); set_dirty(); } @@ -176,17 +177,14 @@ FrequencyLoadView::FrequencyLoadView( refresh_widgets(v); }; - add_children({&menu_view, + add_children({&freqlist_view, &text_empty}); // Resize menu view to fill screen - menu_view.set_parent_rect({0, 3 * 8, 240, 30 * 8}); - - menu_view.on_select = [&nav, this](FreqManUIList&) { - nav_.pop(); - - auto& entry = database[menu_view.get_index()]; + freqlist_view.set_parent_rect({0, 3 * 8, 240, 30 * 8}); + freqlist_view.on_select = [&nav, this](FreqManUIList&) { + auto& entry = database[freqlist_view.get_index()]; if (entry.type == RANGE) { // User chose a frequency range entry if (on_range_loaded) @@ -199,18 +197,21 @@ FrequencyLoadView::FrequencyLoadView( if (on_frequency_loaded) on_frequency_loaded(entry.frequency_a); } + // swap with empty vector to ensure memory is immediately released + std::vector().swap(database); + nav_.pop(); }; } void FrequencyManagerView::on_edit_freq(rf::Frequency f) { - database[menu_view.get_index()].frequency_a = f; + database[freqlist_view.get_index()].frequency_a = f; save_freqman_file(file_list[categories[current_category_id].second], database); change_category(current_category_id); } void FrequencyManagerView::on_edit_desc(NavigationView& nav) { text_prompt(nav, desc_buffer, 28, [this](std::string& buffer) { - database[menu_view.get_index()].description = buffer; + database[freqlist_view.get_index()].description = buffer; save_freqman_file(file_list[categories[current_category_id].second], database); change_category(current_category_id); }); @@ -230,7 +231,7 @@ void FrequencyManagerView::on_delete() { delete_freqman_file(file_list[categories[current_category_id].second]); refresh_list(); } else { - database.erase(database.begin() + menu_view.get_index()); + database.erase(database.begin() + freqlist_view.get_index()); save_freqman_file(file_list[categories[current_category_id].second], database); } change_category(current_category_id); @@ -241,10 +242,9 @@ void FrequencyManagerView::refresh_widgets(const bool v) { button_edit_desc.hidden(v); button_delete.hidden(v); text_empty.hidden(!v); - menu_view.hidden(v); - menu_view.set_dirty(); + freqlist_view.hidden(v); labels.hidden(v); - // display.fill_rectangle(menu_view.screen_rect(), Color::black()); + // display.fill_rectangle(freqlist_view.screen_rect(), Color::black()); set_dirty(); } @@ -261,13 +261,13 @@ FrequencyManagerView::FrequencyManagerView( add_children({&labels, &button_new_category, - &menu_view, + &freqlist_view, &text_empty, &button_edit_freq, &button_edit_desc, &button_delete}); - menu_view.on_select = [this](FreqManUIList&) { + freqlist_view.on_select = [this](FreqManUIList&) { button_edit_freq.focus(); }; @@ -280,7 +280,7 @@ FrequencyManagerView::FrequencyManagerView( if (database.empty()) { database.push_back({0, 0, "", SINGLE}); } - auto new_view = nav.push(database[menu_view.get_index()].frequency_a); + auto new_view = nav.push(database[freqlist_view.get_index()].frequency_a); new_view->on_changed = [this](rf::Frequency f) { on_edit_freq(f); }; @@ -290,7 +290,7 @@ FrequencyManagerView::FrequencyManagerView( if (database.empty()) { database.push_back({0, 0, "", SINGLE}); } - desc_buffer = database[menu_view.get_index()].description; + desc_buffer = database[freqlist_view.get_index()].description; on_edit_desc(nav); }; diff --git a/firmware/application/apps/ui_freqman.hpp b/firmware/application/apps/ui_freqman.hpp index 3a18c742..0c1eeea3 100644 --- a/firmware/application/apps/ui_freqman.hpp +++ b/firmware/application/apps/ui_freqman.hpp @@ -64,7 +64,7 @@ class FreqManBaseView : public View { 14, {}}; - FreqManUIList menu_view{ + FreqManUIList freqlist_view{ {0, 3 * 8, 240, 23 * 8}}; Text text_empty{ @@ -116,6 +116,7 @@ class FrequencyLoadView : public FreqManBaseView { std::function on_range_loaded{}; FrequencyLoadView(NavigationView& nav); + ~FrequencyLoadView(); std::string title() const override { return "Load freq."; }; diff --git a/firmware/application/apps/ui_recon.cpp b/firmware/application/apps/ui_recon.cpp index 42997096..c6325928 100644 --- a/firmware/application/apps/ui_recon.cpp +++ b/firmware/application/apps/ui_recon.cpp @@ -39,15 +39,13 @@ void ReconView::set_loop_config(bool v) { void ReconView::clear_freqlist_for_ui_action() { audio::output::stop(); // flag to detect and reload frequency_list - freqlist_cleared_for_ui_action = true; - // if in manual mode, there is enough memory to load freqman files, else we have to unload/reload if (!manual_mode) { // clear and shrink_to_fit are not enough to really start with a new, clean, empty vector // swap is the only way to achieve a perfect memory liberation std::vector().swap(frequency_list); - } else { + } else frequency_list.shrink_to_fit(); - } + freqlist_cleared_for_ui_action = true; } void ReconView::reset_indexes() { @@ -683,7 +681,6 @@ ReconView::ReconView(NavigationView& nav) nav_.display_modal("Error", "END freq\nis lower than START"); } else { audio::output::stop(); - // clear and shrink_to_fit are not enough to really start with a new, clean, empty vector // swap is the only way to achieve a perfect memory liberation std::vector().swap(frequency_list); @@ -802,7 +799,6 @@ ReconView::ReconView(NavigationView& nav) auto open_view = nav.push(input_file, output_file); open_view->on_changed = [this](std::vector result) { - freqlist_cleared_for_ui_action = false; input_file = result[0]; output_file = result[1]; freq_file_path = "/FREQMAN/" + output_file + ".TXT"; @@ -817,6 +813,7 @@ ReconView::ReconView(NavigationView& nav) update_ranges = persistent_memory::recon_update_ranges_when_recon(); frequency_file_load(false); + freqlist_cleared_for_ui_action = false; if (autostart) { recon_resume(); @@ -894,10 +891,7 @@ void ReconView::frequency_file_load(bool stop_all_before) { audio::output::stop(); def_step = step_mode.selected_index(); // use def_step from manual selector - // clear and shrink_to_fit are not enough to really start with a new, clean, empty vector - // swap is the only way to achieve a perfect memory liberation - std::vector().swap(frequency_list); // clear the existing frequency list (expected behavior) - std::string file_input = input_file; // default recon mode + std::string file_input = input_file; // default recon mode if (scanner_mode) { file_input = output_file; file_name.set_style(&Styles::red); @@ -909,7 +903,7 @@ void ReconView::frequency_file_load(bool stop_all_before) { button_scanner_mode.set_text("RECON"); } desc_cycle.set_style(&Styles::white); - if (!load_freqman_file_ex(file_input, frequency_list, load_freqs, load_ranges, load_hamradios, RECON_FREQMAN_MAX_PER_FILE)) { + if (!load_freqman_file(file_input, frequency_list, load_freqs, load_ranges, load_hamradios)) { file_name.set_style(&Styles::red); desc_cycle.set_style(&Styles::red); desc_cycle.set(" NO " + file_input + ".TXT FILE ..."); @@ -922,7 +916,7 @@ void ReconView::frequency_file_load(bool stop_all_before) { desc_cycle.set("/0 no entries in list"); file_name.set("BadOrEmpty " + file_input); } else { - if (frequency_list.size() > RECON_FREQMAN_MAX_PER_FILE) { + if (frequency_list.size() > FREQMAN_MAX_PER_FILE) { file_name.set_style(&Styles::yellow); desc_cycle.set_style(&Styles::yellow); } diff --git a/firmware/application/apps/ui_recon.hpp b/firmware/application/apps/ui_recon.hpp index fb6c2d0f..8b2fcc63 100644 --- a/firmware/application/apps/ui_recon.hpp +++ b/firmware/application/apps/ui_recon.hpp @@ -45,7 +45,6 @@ namespace ui { #define RECON_CFG_FILE "SETTINGS/recon.cfg" -#define RECON_FREQMAN_MAX_PER_FILE 99 // maximum tested limit for load frequency from freqman to work class ReconView : public View { public: diff --git a/firmware/application/freqman.cpp b/firmware/application/freqman.cpp index d70719a5..d8325b36 100644 --- a/firmware/application/freqman.cpp +++ b/firmware/application/freqman.cpp @@ -86,27 +86,22 @@ options_t freqman_entry_steps_short = { {"500kHz", 500000}, {"1MHz", 1000000}}; -bool load_freqman_file(std::string& file_stem, freqman_db& db) { - return load_freqman_file_ex(file_stem, db, true, true, true, FREQMAN_MAX_PER_FILE); -} - -bool load_freqman_file_ex(std::string& file_stem, freqman_db& db, bool load_freqs, bool load_ranges, bool load_hamradios, uint8_t max_num_freqs = FREQMAN_MAX_PER_FILE) { +bool load_freqman_file(std::string& file_stem, freqman_db& db, bool load_freqs, bool load_ranges, bool load_hamradios, uint8_t max_num_freqs) { // swap with empty vector to ensure memory is immediately released std::vector().swap(db); - - File freqman_file; - size_t length, n = 0, file_position = 0; - char* pos; - char* line_start; - char* line_end; - std::string description; - rf::Frequency frequency_a, frequency_b; - char file_data[FREQMAN_READ_BUF_SIZE + 1]; - freqman_entry_type type; - freqman_index_t modulation = 0; - freqman_index_t bandwidth = 0; - freqman_index_t step = 0; - freqman_index_t tone = 0; + File freqman_file{}; + size_t length = 0, n = 0, file_position = 0; + char* pos = NULL; + char* line_start = NULL; + char* line_end = NULL; + std::string description{NULL}; + rf::Frequency frequency_a = 0, frequency_b = 0; + char file_data[FREQMAN_READ_BUF_SIZE + 1] = {0}; + freqman_entry_type type = NOTYPE; + freqman_index_t modulation = -1; + freqman_index_t bandwidth = -1; + freqman_index_t step = -1; + freqman_index_t tone = -1; auto result = freqman_file.open("FREQMAN/" + file_stem + ".TXT"); if (result.is_valid()) @@ -137,7 +132,7 @@ bool load_freqman_file_ex(std::string& file_stem, freqman_db& db, bool load_freq bandwidth = -1; step = -1; tone = -1; - type = ERROR_TYPE; + type = NOTYPE; frequency_a = frequency_b = 0; // Read frequency @@ -207,6 +202,7 @@ bool load_freqman_file_ex(std::string& file_stem, freqman_db& db, bool load_freq pos += 2; length = std::min(strcspn(pos, ",\x0A"), (size_t)FREQMAN_DESC_MAX_LEN); description = string(pos, length); + description.shrink_to_fit(); } if ((type == SINGLE && load_freqs) || (type == RANGE && load_ranges) || (type == HAMRADIO && load_hamradios)) { db.push_back({frequency_a, frequency_b, description, type, modulation, bandwidth, step, tone}); @@ -243,6 +239,7 @@ bool load_freqman_file_ex(std::string& file_stem, freqman_db& db, bool load_freq } } } + db.shrink_to_fit(); return true; } diff --git a/firmware/application/freqman.hpp b/firmware/application/freqman.hpp index 1262ea0a..c4cd2c17 100644 --- a/firmware/application/freqman.hpp +++ b/firmware/application/freqman.hpp @@ -32,11 +32,11 @@ #include "string_format.hpp" #include "ui_widget.hpp" -#define FREQMAN_DESC_MAX_LEN 24 // This is the number of characters that can be drawn in front of "R: TEXT..." before taking a full screen line -#define FREQMAN_MAX_PER_FILE 100 // Maximum of entries we can read. This is a hardware limit - // It was tested and lowered to leave a bit of space to the caller +#define FREQMAN_DESC_MAX_LEN 24 // This is the number of characters that can be drawn in front of "R: TEXT..." before taking a full screen line +#define FREQMAN_MAX_PER_FILE 90 // Maximum of entries we can read. This is a hardware limit + // It was tested and lowered to leave a bit of space to the caller -#define FREQMAN_READ_BUF_SIZE 96 // max freqman line size including desc is 90, +6 for a bit of space +#define FREQMAN_READ_BUF_SIZE 96 // max freqman line size including desc is 90, + a bit of space using namespace ui; using namespace std; @@ -45,58 +45,53 @@ using namespace tonekey; // needs to be signed as -1 means not set typedef int8_t freqman_index_t; -enum freqman_error { +enum freqman_error : int8_t { NO_ERROR = 0, ERROR_ACCESS, ERROR_NOFILES, ERROR_DUPLICATE }; -enum freqman_entry_type : uint8_t { +enum freqman_entry_type : int8_t { SINGLE = 0, // f= RANGE, // a=,b= HAMRADIO, // r=,t= - ERROR_TYPE + NOTYPE // undetected }; -enum freqman_entry_modulation { +enum freqman_entry_modulation : int8_t { AM_MODULATION = 0, NFM_MODULATION, WFM_MODULATION, - MODULATION_DEF, - ERROR_MODULATION }; // Entry step placed for AlainD freqman version (or any other enhanced version) -enum freqman_entry_step { - STEP_DEF = -1, // default - AM_US, // 10 kHz AM/CB - AM_EUR, // 9 kHz LW/MW - NFM_1, // 12,5 kHz (Analogic PMR 446) - NFM_2, // 6,25 kHz (Digital PMR 446) - FM_1, // 100 kHz - FM_2, // 50 kHz - N_1, // 25 kHz - N_2, // 250 kHz - AIRBAND, // AIRBAND 8,33 kHz - ERROR_STEP +enum freqman_entry_step : int8_t { + AM_US, // 10 kHz AM/CB + AM_EUR, // 9 kHz LW/MW + NFM_1, // 12,5 kHz (Analogic PMR 446) + NFM_2, // 6,25 kHz (Digital PMR 446) + FM_1, // 100 kHz + FM_2, // 50 kHz + N_1, // 25 kHz + N_2, // 250 kHz + AIRBAND, // AIRBAND 8,33 kHz }; struct freqman_entry { - rf::Frequency frequency_a{0}; // 'f=freq' or 'a=freq_start' or 'r=recv_freq' - rf::Frequency frequency_b{0}; // 'b=freq_end' or 't=tx_freq' - std::string description{}; // 'd=desc' - freqman_entry_type type{}; // SINGLE,RANGE,HAMRADIO - freqman_index_t modulation{}; // AM,NFM,WFM - freqman_index_t bandwidth{}; // AM_DSB, ... - freqman_index_t step{}; // 5khz (SA AM,... - tone_index tone{}; // 0XZ, 11 1ZB,... + rf::Frequency frequency_a{0}; // 'f=freq' or 'a=freq_start' or 'r=recv_freq' + rf::Frequency frequency_b{0}; // 'b=freq_end' or 't=tx_freq' + std::string description{NULL}; // 'd=desc' + freqman_entry_type type{SINGLE}; // SINGLE,RANGE,HAMRADIO + freqman_index_t modulation{AM_MODULATION}; // AM,NFM,WFM + freqman_index_t bandwidth{0}; // AM_DSB, ... + freqman_index_t step{0}; // 5khz (SA AM,... + tone_index tone{0}; // 0XZ, 11 1ZB,... }; using freqman_db = std::vector; -bool load_freqman_file(std::string& file_stem, freqman_db& db); -bool load_freqman_file_ex(std::string& file_stem, freqman_db& db, bool load_freqs, bool load_ranges, bool load_hamradios, uint8_t limit); +bool load_freqman_file(std::string& file_stem, freqman_db& db, bool load_freqs = true, bool load_ranges = true, bool load_hamradios = true, uint8_t max_num_freqs = FREQMAN_MAX_PER_FILE); bool get_freq_string(freqman_entry& entry, std::string& item_string); bool delete_freqman_file(std::string& file_stem); bool save_freqman_file(std::string& file_stem, freqman_db& db);