diff --git a/firmware/application/app_settings.cpp b/firmware/application/app_settings.cpp index 3f62e204..0212fe68 100644 --- a/firmware/application/app_settings.cpp +++ b/firmware/application/app_settings.cpp @@ -2,6 +2,7 @@ * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. * Copyright (C) 2016 Furrtek * Copyright (C) 2022 Arjan Onwezen + * Copyright (C) 2023 Kyle Reed * * This file is part of PortaPack. * @@ -58,7 +59,7 @@ void BoundSetting::parse(std::string_view value) { parse_int(value, as()); break; case SettingType::String: - as() = std::string{value}; + as() = trim(value); break; case SettingType::Bool: { int parsed = 0; @@ -106,10 +107,18 @@ void BoundSetting::write(File& file) const { SettingsStore::SettingsStore(std::string_view store_name, SettingBindings bindings) : store_name_{store_name}, bindings_{bindings} { - load_settings(store_name_, bindings_); + reload(); } SettingsStore::~SettingsStore() { + save(); +} + +void SettingsStore::reload() { + load_settings(store_name_, bindings_); +} + +void SettingsStore::save() const { save_settings(store_name_, bindings_); } diff --git a/firmware/application/app_settings.hpp b/firmware/application/app_settings.hpp index fc455426..5ea78e17 100644 --- a/firmware/application/app_settings.hpp +++ b/firmware/application/app_settings.hpp @@ -94,6 +94,9 @@ class SettingsStore { SettingsStore(std::string_view store_name, SettingBindings bindings); ~SettingsStore(); + void reload(); + void save() const; + private: std::string_view store_name_; SettingBindings bindings_; diff --git a/firmware/application/apps/ui_recon.cpp b/firmware/application/apps/ui_recon.cpp index 1c5c8494..c2d3e4f9 100644 --- a/firmware/application/apps/ui_recon.cpp +++ b/firmware/application/apps/ui_recon.cpp @@ -176,85 +176,16 @@ bool ReconView::recon_save_freq(const fs::path& path, size_t freq_index, bool wa return true; } -bool ReconView::recon_load_config_from_sd() { - make_new_directory(u"SETTINGS"); - - File settings_file; - auto error = settings_file.open(RECON_CFG_FILE); - if (error) - return false; - - auto complete = false; - auto line_nb = 0; - auto reader = FileLineReader(settings_file); - for (const auto& line : reader) { - switch (line_nb) { - case 0: - input_file = trim(line); - break; - case 1: - output_file = trim(line); - break; - case 2: - parse_int(line, recon_lock_duration); - break; - case 3: - parse_int(line, recon_lock_nb_match); - break; - case 4: - parse_int(line, squelch); - break; - case 5: - parse_int(line, recon_match_mode); - break; - case 6: - parse_int(line, wait); - break; - case 7: - if (!update_ranges) { - parse_int(line, frequency_range.min); - button_manual_start.set_text(to_string_short_freq(frequency_range.min)); - } - break; - case 8: - if (!update_ranges) { - parse_int(line, frequency_range.max); - button_manual_end.set_text(to_string_short_freq(frequency_range.max)); - } - complete = true; // NB: Last entry. - break; - default: - complete = false; - break; - } - - if (complete) break; - - line_nb++; - } - - return complete; -} - -bool ReconView::recon_save_config_to_sd() { - File settings_file; - - make_new_directory(u"SETTINGS"); - - auto error = settings_file.create(RECON_CFG_FILE); - if (error) - return false; - settings_file.write_line(input_file); - settings_file.write_line(output_file); - settings_file.write_line(to_string_dec_uint(recon_lock_duration)); - settings_file.write_line(to_string_dec_uint(recon_lock_nb_match)); - settings_file.write_line(to_string_dec_int(squelch)); - settings_file.write_line(to_string_dec_uint(recon_match_mode)); - settings_file.write_line(to_string_dec_int(wait)); - settings_file.write_line(to_string_dec_uint(frequency_range.min)); - settings_file.write_line(to_string_dec_uint(frequency_range.max)); - - return true; +void ReconView::load_persisted_settings() { + autostart = persistent_memory::recon_autostart_recon(); + autosave = persistent_memory::recon_autosave_freqs(); + continuous = persistent_memory::recon_continuous(); + filedelete = persistent_memory::recon_clear_output(); + load_freqs = persistent_memory::recon_load_freqs(); + load_ranges = persistent_memory::recon_load_ranges(); + load_hamradios = persistent_memory::recon_load_hamradios(); + update_ranges = persistent_memory::recon_update_ranges_when_recon(); + auto_record_locked = persistent_memory::recon_auto_record_locked(); } void ReconView::audio_output_start() { @@ -337,7 +268,6 @@ void ReconView::focus() { ReconView::~ReconView() { recon_stop_recording(); - recon_save_config_to_sd(); if (field_mode.selected_index_value() != SPEC_MODULATION) audio::output::stop(); receiver_model.disable(); @@ -395,29 +325,17 @@ ReconView::ReconView(NavigationView& nav) }; def_step = 0; - // HELPER: Pre-setting a manual range, based on stored frequency - rf::Frequency stored_freq = receiver_model.target_frequency(); - if (stored_freq - OneMHz > 0) - frequency_range.min = stored_freq - OneMHz; - else - frequency_range.min = 0; - button_manual_start.set_text(to_string_short_freq(frequency_range.min)); - if (stored_freq + OneMHz < MAX_UFREQ) - frequency_range.max = stored_freq + OneMHz; - else - frequency_range.max = MAX_UFREQ; - button_manual_end.set_text(to_string_short_freq(frequency_range.max)); + load_persisted_settings(); - // Loading settings - autostart = persistent_memory::recon_autostart_recon(); - autosave = persistent_memory::recon_autosave_freqs(); - continuous = persistent_memory::recon_continuous(); - filedelete = persistent_memory::recon_clear_output(); - load_freqs = persistent_memory::recon_load_freqs(); - load_ranges = persistent_memory::recon_load_ranges(); - load_hamradios = persistent_memory::recon_load_hamradios(); - update_ranges = persistent_memory::recon_update_ranges_when_recon(); - auto_record_locked = persistent_memory::recon_auto_record_locked(); + // When update_ranges is set or range invalid, use the rx model frequency instead of the saved values. + if (update_ranges || frequency_range.max == 0) { + rf::Frequency stored_freq = receiver_model.target_frequency(); + frequency_range.min = clip(stored_freq - OneMHz, 0, MAX_UFREQ); + frequency_range.max = clip(stored_freq + OneMHz, 0, MAX_UFREQ); + } + + button_manual_start.set_text(to_string_short_freq(frequency_range.min)); + button_manual_end.set_text(to_string_short_freq(frequency_range.max)); button_manual_start.on_select = [this, &nav](ButtonWithEncoder& button) { clear_freqlist_for_ui_action(); @@ -717,16 +635,9 @@ ReconView::ReconView(NavigationView& nav) input_file = result[0]; output_file = result[1]; freq_file_path = get_freqman_path(output_file).string(); - recon_save_config_to_sd(); - autosave = persistent_memory::recon_autosave_freqs(); - autostart = persistent_memory::recon_autostart_recon(); - filedelete = persistent_memory::recon_clear_output(); - load_freqs = persistent_memory::recon_load_freqs(); - load_ranges = persistent_memory::recon_load_ranges(); - load_hamradios = persistent_memory::recon_load_hamradios(); - update_ranges = persistent_memory::recon_update_ranges_when_recon(); - auto_record_locked = persistent_memory::recon_auto_record_locked(); + load_persisted_settings(); + ui_settings.save(); frequency_file_load(false); freqlist_cleared_for_ui_action = false; @@ -774,7 +685,6 @@ ReconView::ReconView(NavigationView& nav) file_name.set("=>"); // Loading input and output file from settings - recon_load_config_from_sd(); freq_file_path = get_freqman_path(output_file).string(); field_recon_match_mode.set_selected_index(recon_match_mode); diff --git a/firmware/application/apps/ui_recon.hpp b/firmware/application/apps/ui_recon.hpp index 4c1b3f6f..c14bf917 100644 --- a/firmware/application/apps/ui_recon.hpp +++ b/firmware/application/apps/ui_recon.hpp @@ -68,7 +68,7 @@ class ReconView : public View { RxRadioState radio_state_{}; app_settings::SettingsManager settings_{ - "rx_recon", app_settings::Mode::RX}; + "rx_recon"sv, app_settings::Mode::RX}; void check_update_ranges_from_current(); void set_loop_config(bool v); @@ -90,8 +90,7 @@ class ReconView : public View { void handle_retune(); void handle_coded_squelch(const uint32_t value); void handle_remove_current_item(); - bool recon_load_config_from_sd(); - bool recon_save_config_to_sd(); + void load_persisted_settings(); bool recon_save_freq(const std::filesystem::path& path, size_t index, bool warn_if_exists); // placeholder for possible void recon_start_recording(); void recon_stop_recording(); @@ -164,6 +163,21 @@ class ReconView : public View { systime_t chrono_start{}; systime_t chrono_end{}; + // Persisted settings. + SettingsStore ui_settings{ + "recon"sv, + { + {"input_file"sv, &input_file}, + {"output_file"sv, &output_file}, + {"lock_duration"sv, &recon_lock_duration}, + {"lock_nb_match"sv, &recon_lock_nb_match}, + {"squelch_level"sv, &squelch}, + {"match_mode"sv, &recon_match_mode}, + {"match_wait"sv, &wait}, + {"range_min"sv, &frequency_range.min}, + {"range_max"sv, &frequency_range.max}, + }}; + std::unique_ptr record_view{}; Labels labels{ diff --git a/firmware/application/apps/ui_scanner.cpp b/firmware/application/apps/ui_scanner.cpp index d71abebb..04fc273d 100644 --- a/firmware/application/apps/ui_scanner.cpp +++ b/firmware/application/apps/ui_scanner.cpp @@ -319,7 +319,6 @@ ScannerView::ScannerView( field_step.set_by_value(receiver_model.frequency_step()); // Default step interval (Hz) change_mode((freqman_index_t)field_mode.selected_index_value()); - // FUTURE: perhaps additional settings should be stored in persistent memory vs using defaults rf::Frequency stored_freq = receiver_model.target_frequency(); frequency_range.min = stored_freq - 1000000; button_manual_start.set_text(to_string_short_freq(frequency_range.min)); @@ -522,13 +521,17 @@ ScannerView::ScannerView( // PRE-CONFIGURATION: field_browse_wait.on_change = [this](int32_t v) { browse_wait = v; }; - field_browse_wait.set_value(5); + field_browse_wait.set_value(browse_wait); field_lock_wait.on_change = [this](int32_t v) { lock_wait = v; }; - field_lock_wait.set_value(2); + field_lock_wait.set_value(lock_wait); field_squelch.on_change = [this](int32_t v) { squelch = v; }; - field_squelch.set_value(-30); + field_squelch.set_value(squelch); + + // Disable squelch on the model because RSSI handler is where the + // actual squelching is applied for this app. + receiver_model.set_squelch_level(0); // LOAD FREQUENCIES frequency_file_load(default_scan_file); @@ -726,9 +729,6 @@ void ScannerView::change_mode(freqman_index_t new_mod) { void ScannerView::start_scan_thread() { receiver_model.enable(); - // Disable squelch on the model because RSSI handler is where the - // actual squelching is applied for this app. - receiver_model.set_squelch_level(0); show_max_index(); // Start Scanner Thread diff --git a/firmware/application/apps/ui_scanner.hpp b/firmware/application/apps/ui_scanner.hpp index 555f54d3..1fd31ad8 100644 --- a/firmware/application/apps/ui_scanner.hpp +++ b/firmware/application/apps/ui_scanner.hpp @@ -111,8 +111,19 @@ class ScannerView : public View { private: RxRadioState radio_state_{}; + + // Settings + uint32_t browse_wait{5}; + uint32_t lock_wait{2}; + int32_t squelch{-30}; app_settings::SettingsManager settings_{ - "rx_scanner", app_settings::Mode::RX}; + "rx_scanner"sv, + app_settings::Mode::RX, + { + {"browse_wait"sv, &browse_wait}, + {"lock_wait"sv, &lock_wait}, + {"scanner_squelch"sv, &squelch}, + }}; NavigationView& nav_; @@ -132,14 +143,11 @@ class ScannerView : public View { std::string loaded_filename() const; scanner_range_t frequency_range{0, 0}; - int32_t squelch{0}; uint32_t browse_timer{0}; uint32_t lock_timer{0}; uint32_t color_timer{0}; int32_t bigdisplay_current_color{-2}; rf::Frequency bigdisplay_current_frequency{0}; - uint32_t browse_wait{0}; - uint32_t lock_wait{0}; std::filesystem::path loaded_path{}; std::vector entries{};