diff --git a/firmware/application/app_settings.cpp b/firmware/application/app_settings.cpp index 0212fe68..3d9d5f7b 100644 --- a/firmware/application/app_settings.cpp +++ b/firmware/application/app_settings.cpp @@ -244,55 +244,64 @@ SettingsManager::SettingsManager( : app_name_{app_name}, settings_{}, bindings_{}, - loaded_{false} { + loaded_{false}, + radio_loaded_{false} { settings_.mode = mode; settings_.options = options; - if (!portapack::persistent_memory::load_app_settings()) - return; - // Pre-alloc enough for app settings and additional settings. additional_settings.reserve(17 + additional_settings.size()); bindings_ = std::move(additional_settings); - // Transmitter model settings. - if (flags_enabled(mode, Mode::TX)) { - bindings_.emplace_back("tx_frequency"sv, &settings_.tx_frequency); - bindings_.emplace_back("tx_amp"sv, &settings_.tx_amp); - bindings_.emplace_back("tx_gain"sv, &settings_.tx_gain); - bindings_.emplace_back("channel_bandwidth"sv, &settings_.channel_bandwidth); - } + // Additional settings should always be loaded because apps now rely + // on being able to store UI settings, config, etc. The radio settings + // are only loaded if the global option has been enabled. + // Add the radio setting bindings if either load or save are enabled. + if (portapack::persistent_memory::load_app_settings() || + portapack::persistent_memory::save_app_settings()) { + // Transmitter model settings. + if (flags_enabled(mode, Mode::TX)) { + bindings_.emplace_back("tx_frequency"sv, &settings_.tx_frequency); + bindings_.emplace_back("tx_amp"sv, &settings_.tx_amp); + bindings_.emplace_back("tx_gain"sv, &settings_.tx_gain); + bindings_.emplace_back("channel_bandwidth"sv, &settings_.channel_bandwidth); + } - // Receiver model settings. - if (flags_enabled(mode, Mode::RX)) { - bindings_.emplace_back("rx_frequency"sv, &settings_.rx_frequency); - bindings_.emplace_back("lna"sv, &settings_.lna); - bindings_.emplace_back("vga"sv, &settings_.vga); - bindings_.emplace_back("rx_amp"sv, &settings_.rx_amp); - bindings_.emplace_back("modulation"sv, &settings_.modulation); - bindings_.emplace_back("am_config_index"sv, &settings_.am_config_index); - bindings_.emplace_back("nbfm_config_index"sv, &settings_.nbfm_config_index); - bindings_.emplace_back("wfm_config_index"sv, &settings_.wfm_config_index); - bindings_.emplace_back("squelch"sv, &settings_.squelch); - } + // Receiver model settings. + if (flags_enabled(mode, Mode::RX)) { + bindings_.emplace_back("rx_frequency"sv, &settings_.rx_frequency); + bindings_.emplace_back("lna"sv, &settings_.lna); + bindings_.emplace_back("vga"sv, &settings_.vga); + bindings_.emplace_back("rx_amp"sv, &settings_.rx_amp); + bindings_.emplace_back("modulation"sv, &settings_.modulation); + bindings_.emplace_back("am_config_index"sv, &settings_.am_config_index); + bindings_.emplace_back("nbfm_config_index"sv, &settings_.nbfm_config_index); + bindings_.emplace_back("wfm_config_index"sv, &settings_.wfm_config_index); + bindings_.emplace_back("squelch"sv, &settings_.squelch); + } - // Common model settings. - bindings_.emplace_back("baseband_bandwidth"sv, &settings_.baseband_bandwidth); - bindings_.emplace_back("sampling_rate"sv, &settings_.sampling_rate); - bindings_.emplace_back("step"sv, &settings_.step); - bindings_.emplace_back("volume"sv, &settings_.volume); + // Common model settings. + bindings_.emplace_back("baseband_bandwidth"sv, &settings_.baseband_bandwidth); + bindings_.emplace_back("sampling_rate"sv, &settings_.sampling_rate); + bindings_.emplace_back("step"sv, &settings_.step); + bindings_.emplace_back("volume"sv, &settings_.volume); + } loaded_ = load_settings(app_name_, bindings_); - if (loaded_) + // Only copy to the radio if load was successful. + if (loaded_ && portapack::persistent_memory::load_app_settings()) { + radio_loaded_ = true; copy_to_radio_model(settings_); -} - -SettingsManager::~SettingsManager() { - if (portapack::persistent_memory::save_app_settings()) { - copy_from_radio_model(settings_); - save_settings(app_name_, bindings_); } } +SettingsManager::~SettingsManager() { + // Only save radio settings when the option is enabled. + if (portapack::persistent_memory::save_app_settings()) + copy_from_radio_model(settings_); + + save_settings(app_name_, bindings_); +} + } // namespace app_settings diff --git a/firmware/application/app_settings.hpp b/firmware/application/app_settings.hpp index 5ea78e17..9ce4f6c2 100644 --- a/firmware/application/app_settings.hpp +++ b/firmware/application/app_settings.hpp @@ -150,7 +150,9 @@ void copy_to_radio_model(const AppSettings& settings); /* Copies common values from the receiver/transmitter models. */ void copy_from_radio_model(AppSettings& settings); -/* RAII wrapper for automatically loading and saving radio settings for an app. +/* RAII wrapper for automatically loading and saving settings for an app. + * "Additional" settings are always loaded, but radio settings are conditionally + * saved/loaded if the global app settings options are enabled. * NB: This should be added to a class before any LNA/VGA controls so that * the receiver/transmitter models are set before the control ctors run. */ class SettingsManager { @@ -167,6 +169,9 @@ class SettingsManager { /* True if settings were successfully loaded from file. */ bool loaded() const { return loaded_; } + + /* True if radio settings were successfully loaded from file. */ + bool radio_loaded() const { return radio_loaded_; } Mode mode() const { return settings_.mode; } AppSettings& raw() { return settings_; } @@ -176,6 +181,7 @@ class SettingsManager { AppSettings settings_; SettingBindings bindings_; bool loaded_; + bool radio_loaded_; }; } // namespace app_settings diff --git a/firmware/application/apps/ais_app.cpp b/firmware/application/apps/ais_app.cpp index e928d5dd..578ed808 100644 --- a/firmware/application/apps/ais_app.cpp +++ b/firmware/application/apps/ais_app.cpp @@ -382,7 +382,7 @@ AISAppView::AISAppView(NavigationView& nav) recent_entry_detail_view.hidden(true); - if (!settings_.loaded()) + if (!settings_.radio_loaded()) receiver_model.set_target_frequency(initial_target_frequency); receiver_model.enable(); diff --git a/firmware/application/apps/ert_app.cpp b/firmware/application/apps/ert_app.cpp index f4292d80..688eed47 100644 --- a/firmware/application/apps/ert_app.cpp +++ b/firmware/application/apps/ert_app.cpp @@ -110,7 +110,7 @@ ERTAppView::ERTAppView(NavigationView&) { &recent_entries_view, }); - if (!settings_.loaded()) + if (!settings_.radio_loaded()) receiver_model.set_target_frequency(initial_target_frequency); receiver_model.enable(); diff --git a/firmware/application/apps/gps_sim_app.cpp b/firmware/application/apps/gps_sim_app.cpp index 61ccdd1d..09267203 100644 --- a/firmware/application/apps/gps_sim_app.cpp +++ b/firmware/application/apps/gps_sim_app.cpp @@ -173,7 +173,7 @@ GpsSimAppView::GpsSimAppView( &waterfall, }); - if (!settings_.loaded()) { + if (!settings_.radio_loaded()) { field_frequency.set_value(initial_target_frequency); transmitter_model.set_sampling_rate(2600000); } diff --git a/firmware/application/apps/pocsag_app.cpp b/firmware/application/apps/pocsag_app.cpp index 6fcd21ec..20af8ab5 100644 --- a/firmware/application/apps/pocsag_app.cpp +++ b/firmware/application/apps/pocsag_app.cpp @@ -112,12 +112,14 @@ POCSAGAppView::POCSAGAppView(NavigationView& nav) &button_config, &console}); - // No app settings, use fallbacks. + // No app settings, use fallbacks from pmem. if (!app_settings_.loaded()) { - field_frequency.set_value(initial_target_frequency); settings_.address_to_ignore = pmem::pocsag_ignore_address(); settings_.enable_ignore = settings_.address_to_ignore > 0; } + if (!app_settings_.radio_loaded()) { + field_frequency.set_value(initial_target_frequency); + } logger.append(LOG_ROOT_DIR "/POCSAG.TXT"); @@ -151,7 +153,7 @@ POCSAGAppView::~POCSAGAppView() { receiver_model.disable(); baseband::shutdown(); - // Save pmem settings. TODO: Even needed anymore? + // Save pmem settings. pmem::set_pocsag_ignore_address(settings_.address_to_ignore); pmem::set_pocsag_last_address(pocsag_state.address); // For POCSAG TX. } diff --git a/firmware/application/apps/tpms_app.cpp b/firmware/application/apps/tpms_app.cpp index a9ce0e93..3bf25d2a 100644 --- a/firmware/application/apps/tpms_app.cpp +++ b/firmware/application/apps/tpms_app.cpp @@ -157,7 +157,7 @@ TPMSAppView::TPMSAppView(NavigationView&) { &field_vga, &recent_entries_view}); - if (!settings_.loaded()) + if (!settings_.radio_loaded()) receiver_model.set_target_frequency(initial_target_frequency); receiver_model.enable(); diff --git a/firmware/application/apps/ui_settings.cpp b/firmware/application/apps/ui_settings.cpp index 51cc3bb5..94b7bd4d 100644 --- a/firmware/application/apps/ui_settings.cpp +++ b/firmware/application/apps/ui_settings.cpp @@ -2,6 +2,7 @@ * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. * Copyright (C) 2016 Furrtek * Copyright (C) 2023 gullradriel, Nilorea Studio Inc. + * Copyright (C) 2023 Kyle Reed * * This file is part of PortaPack. * @@ -125,8 +126,30 @@ SetRadioView::SetRadioView( nav.pop(); }; + add_children({ + &label_source, + &value_source, + &value_source_frequency, + &check_clkout, + &field_clkout_freq, + &labels_clkout_khz, + &value_freq_step, + &labels_bias, + &check_bias, + &disable_external_tcxo, // TODO: always show? + &button_save, + &button_cancel, + }); + const auto reference = clock_manager.get_reference(); + if (reference.source == ClockManager::ReferenceSource::Xtal) { + add_children({ + &labels_correction, + &field_ppm, + }); + } + std::string source_name("---"); switch (reference.source) { case ClockManager::ReferenceSource::Xtal: @@ -141,36 +164,15 @@ SetRadioView::SetRadioView( } value_source.set(source_name); - value_source_frequency.set(to_string_dec_uint(reference.frequency / 1000000, 2) + "." + to_string_dec_uint((reference.frequency % 1000000) / 100, 4, '0') + " MHz"); + value_source_frequency.set( + to_string_dec_uint(reference.frequency / 1000000, 2) + "." + + to_string_dec_uint((reference.frequency % 1000000) / 100, 4, '0') + " MHz"); + // Make these Text controls look like Labels. label_source.set_style(&Styles::light_grey); value_source.set_style(&Styles::light_grey); value_source_frequency.set_style(&Styles::light_grey); - add_children({ - &label_source, - &value_source, - &value_source_frequency, - }); - - if (reference.source == ClockManager::ReferenceSource::Xtal) { - add_children({ - &labels_correction, - &field_ppm, - }); - } - - add_children({&check_clkout, - &field_clkout_freq, - &labels_clkout_khz, - &value_freq_step, - &labels_bias, - &check_bias, - &button_save, - &button_cancel}); - - add_children({&disable_external_tcxo}); - SetFrequencyCorrectionModel model{ static_cast(pmem::correction_ppb() / 1000), 0}; @@ -344,10 +346,13 @@ void SetUIView::focus() { /* SetAppSettingsView ************************************/ SetAppSettingsView::SetAppSettingsView(NavigationView& nav) { - add_children({&checkbox_load_app_settings, - &checkbox_save_app_settings, - &button_save, - &button_cancel}); + add_children({ + &labels, + &checkbox_load_app_settings, + &checkbox_save_app_settings, + &button_save, + &button_cancel, + }); checkbox_load_app_settings.set_value(pmem::load_app_settings()); checkbox_save_app_settings.set_value(pmem::save_app_settings()); @@ -369,11 +374,14 @@ void SetAppSettingsView::focus() { /* SetConverterSettingsView ******************************/ SetConverterSettingsView::SetConverterSettingsView(NavigationView& nav) { - add_children({&check_show_converter, - &check_converter, - &converter_mode, - &button_converter_freq, - &button_return}); + add_children({ + &labels, + &check_show_converter, + &check_converter, + &opt_converter_mode, + &field_converter_freq, + &button_return, + }); check_show_converter.set_value(!pmem::ui_hide_converter()); check_show_converter.on_select = [this](Checkbox&, bool v) { @@ -383,7 +391,7 @@ SetConverterSettingsView::SetConverterSettingsView(NavigationView& nav) { } // Retune to take converter change in account. receiver_model.set_target_frequency(receiver_model.target_frequency()); - // Refresh status bar with/out converter + // Refresh status bar converter icon. send_system_refresh(); }; @@ -394,27 +402,30 @@ SetConverterSettingsView::SetConverterSettingsView(NavigationView& nav) { pmem::set_ui_hide_converter(false); } pmem::set_config_converter(v); - // Retune to take converter change in account + // Retune to take converter change in account. receiver_model.set_target_frequency(receiver_model.target_frequency()); - // Refresh status bar with/out converter + // Refresh status bar converter icon. send_system_refresh(); }; - converter_mode.set_by_value(pmem::config_updown_converter()); - converter_mode.on_change = [this](size_t, OptionsField::value_t v) { + opt_converter_mode.set_by_value(pmem::config_updown_converter()); + opt_converter_mode.on_change = [this](size_t, OptionsField::value_t v) { pmem::set_config_updown_converter(v); - // Refresh status bar with icon up or down + // Refresh status bar with up or down icon. send_system_refresh(); }; - button_converter_freq.set_text(to_string_short_freq(pmem::config_converter_freq()) + "MHz"); - button_converter_freq.on_select = [this, &nav](Button& button) { - auto new_view = nav.push(pmem::config_converter_freq()); - new_view->on_changed = [this, &button](rf::Frequency f) { - pmem::set_config_converter_freq(f); - // Retune to take converter change in account - receiver_model.set_target_frequency(receiver_model.target_frequency()); - button_converter_freq.set_text("<" + to_string_short_freq(f) + " MHz>"); + field_converter_freq.set_step(1'000'000); + field_converter_freq.set_value(pmem::config_converter_freq()); + field_converter_freq.on_change = [this](rf::Frequency f) { + pmem::set_config_converter_freq(f); + // Retune to take converter change in account. + receiver_model.set_target_frequency(receiver_model.target_frequency()); + }; + field_converter_freq.on_edit = [this, &nav]() { + auto new_view = nav.push(field_converter_freq.value()); + new_view->on_changed = [this](rf::Frequency f) { + field_converter_freq.set_value(f); }; }; @@ -430,46 +441,50 @@ void SetConverterSettingsView::focus() { /* SetFrequencyCorrectionView ****************************/ SetFrequencyCorrectionView::SetFrequencyCorrectionView(NavigationView& nav) { - add_children({&text_freqCorrection_about, - &frequency_rx_correction_mode, - &frequency_tx_correction_mode, - &button_freq_rx_correction, - &button_freq_tx_correction, - &button_return}); + add_children({ + &labels, + &opt_rx_correction_mode, + &field_rx_correction, + &opt_tx_correction_mode, + &field_tx_correction, + &button_return, + }); - frequency_rx_correction_mode.set_by_value(pmem::config_freq_rx_correction_updown()); - frequency_rx_correction_mode.on_change = [this](size_t, OptionsField::value_t v) { + opt_rx_correction_mode.set_by_value(pmem::config_freq_rx_correction_updown()); + opt_rx_correction_mode.on_change = [this](size_t, OptionsField::value_t v) { pmem::set_freq_rx_correction_updown(v); }; - frequency_tx_correction_mode.set_by_value(pmem::config_freq_rx_correction_updown()); - frequency_tx_correction_mode.on_change = [this](size_t, OptionsField::value_t v) { + opt_tx_correction_mode.set_by_value(pmem::config_freq_rx_correction_updown()); + opt_tx_correction_mode.on_change = [this](size_t, OptionsField::value_t v) { pmem::set_freq_tx_correction_updown(v); }; - button_freq_rx_correction.set_text(to_string_short_freq(pmem::config_freq_rx_correction()) + "MHz (Rx)"); - button_freq_rx_correction.on_select = [this, &nav](Button& button) { - auto new_view = nav.push(pmem::config_converter_freq()); - new_view->on_changed = [this, &button](rf::Frequency f) { - if (f >= MAX_FREQ_CORRECTION) - f = MAX_FREQ_CORRECTION; - pmem::set_config_freq_rx_correction(f); - // Retune to take converter change in account - receiver_model.set_target_frequency(receiver_model.target_frequency()); - button_freq_rx_correction.set_text("<" + to_string_short_freq(f) + " MHz>"); + field_rx_correction.set_step(100'000); + field_rx_correction.set_value(pmem::config_freq_rx_correction()); + field_rx_correction.on_change = [this](rf::Frequency f) { + pmem::set_config_freq_rx_correction(f); + // Retune to take converter change in account. + receiver_model.set_target_frequency(receiver_model.target_frequency()); + }; + field_rx_correction.on_edit = [this, &nav]() { + auto new_view = nav.push(field_rx_correction.value()); + new_view->on_changed = [this](rf::Frequency f) { + field_rx_correction.set_value(f); }; }; - button_freq_tx_correction.set_text(to_string_short_freq(pmem::config_freq_tx_correction()) + "MHz (Tx)"); - button_freq_tx_correction.on_select = [this, &nav](Button& button) { - auto new_view = nav.push(pmem::config_converter_freq()); - new_view->on_changed = [this, &button](rf::Frequency f) { - if (f >= MAX_FREQ_CORRECTION) - f = MAX_FREQ_CORRECTION; - pmem::set_config_freq_tx_correction(f); - // Retune to take converter change in account - receiver_model.set_target_frequency(receiver_model.target_frequency()); - button_freq_tx_correction.set_text("<" + to_string_short_freq(f) + " MHz>"); + field_tx_correction.set_step(100'000); + field_tx_correction.set_value(pmem::config_freq_tx_correction()); + field_tx_correction.on_change = [this](rf::Frequency f) { + pmem::set_config_freq_tx_correction(f); + // Retune to take converter change in account. NB: receiver_model. + receiver_model.set_target_frequency(receiver_model.target_frequency()); + }; + field_tx_correction.on_edit = [this, &nav]() { + auto new_view = nav.push(field_tx_correction.value()); + new_view->on_changed = [this](rf::Frequency f) { + field_tx_correction.set_value(f); }; }; @@ -485,49 +500,52 @@ void SetFrequencyCorrectionView::focus() { /* SetPersistentMemoryView *******************************/ SetPersistentMemoryView::SetPersistentMemoryView(NavigationView& nav) { - add_children({&text_pmem_about, - &text_pmem_informations, - &text_pmem_status, - &check_use_sdcard_for_pmem, - &button_save_mem_to_file, - &button_load_mem_from_file, - &button_load_mem_defaults, - &button_return}); + add_children({ + &labels, + &text_pmem_status, + &check_use_sdcard_for_pmem, + &button_save_mem_to_file, + &button_load_mem_from_file, + &button_load_mem_defaults, + &button_return, + }); + + text_pmem_status.set_style(&Styles::yellow); check_use_sdcard_for_pmem.set_value(pmem::should_use_sdcard_for_pmem()); check_use_sdcard_for_pmem.on_select = [this](Checkbox&, bool v) { File pmem_flag_file_handle; if (v) { if (fs::file_exists(PMEM_FILEFLAG)) { - text_pmem_status.set("pmem flag already present"); + text_pmem_status.set("P.Mem flag file present."); } else { auto error = pmem_flag_file_handle.create(PMEM_FILEFLAG); if (error) - text_pmem_status.set("!err. creating pmem flagfile!"); + text_pmem_status.set("Error creating P.Mem File!"); else - text_pmem_status.set("pmem flag file created"); + text_pmem_status.set("P.Mem flag file created."); } } else { auto result = delete_file(PMEM_FILEFLAG); if (result.code() != FR_OK) - text_pmem_status.set("!err. deleting pmem flagfile!"); + text_pmem_status.set("Error deleting P.Mem flag!"); else - text_pmem_status.set("pmem flag file deleted"); + text_pmem_status.set("P.Mem flag file deleted."); } }; button_save_mem_to_file.on_select = [&nav, this](Button&) { if (!pmem::save_persistent_settings_to_file()) - text_pmem_status.set("!problem saving settings!"); + text_pmem_status.set("Error saving settings!"); else - text_pmem_status.set("settings saved"); + text_pmem_status.set("Settings saved."); }; button_load_mem_from_file.on_select = [&nav, this](Button&) { if (!pmem::load_persistent_settings_from_file()) { - text_pmem_status.set("!problem loading settings!"); + text_pmem_status.set("Error loading settings!"); } else { - text_pmem_status.set("settings loaded"); + text_pmem_status.set("Settings loaded."); // Refresh status bar with icon up or down send_system_refresh(); } @@ -536,7 +554,7 @@ SetPersistentMemoryView::SetPersistentMemoryView(NavigationView& nav) { button_load_mem_defaults.on_select = [&nav, this](Button&) { nav.push( "Warning!", - "This will reset the p.mem\nand set the default settings", + "This will reset the P.Mem\nto default settings.", YESNO, [this](bool choice) { if (choice) { @@ -582,9 +600,12 @@ void SetAudioView::focus() { /* SetQRCodeView *****************************************/ SetQRCodeView::SetQRCodeView(NavigationView& nav) { - add_children({&checkbox_bigger_qr, - &button_save, - &button_cancel}); + add_children({ + &labels, + &checkbox_bigger_qr, + &button_save, + &button_cancel, + }); checkbox_bigger_qr.set_value(pmem::show_bigger_qr_code()); @@ -640,7 +661,7 @@ SettingsMenuView::SettingsMenuView(NavigationView& nav) { {"Calibration", ui::Color::dark_cyan(), &bitmap_icon_options_touch, [&nav]() { nav.push(); }}, {"App Settings", ui::Color::dark_cyan(), &bitmap_icon_setup, [&nav]() { nav.push(); }}, {"Converter", ui::Color::dark_cyan(), &bitmap_icon_options_radio, [&nav]() { nav.push(); }}, - {"FreqCorrection", ui::Color::dark_cyan(), &bitmap_icon_options_radio, [&nav]() { nav.push(); }}, + {"Freq. Correct", ui::Color::dark_cyan(), &bitmap_icon_options_radio, [&nav]() { nav.push(); }}, {"QR Code", ui::Color::dark_cyan(), &bitmap_icon_qr_code, [&nav]() { nav.push(); }}, {"P.Memory Mgmt", ui::Color::dark_cyan(), &bitmap_icon_memory, [&nav]() { nav.push(); }}, {"Encoder Dial", ui::Color::dark_cyan(), &bitmap_icon_setup, [&nav]() { nav.push(); }}, diff --git a/firmware/application/apps/ui_settings.hpp b/firmware/application/apps/ui_settings.hpp index 6168e159..61c69375 100644 --- a/firmware/application/apps/ui_settings.hpp +++ b/firmware/application/apps/ui_settings.hpp @@ -2,6 +2,7 @@ * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. * Copyright (C) 2016 Furrtek * Copyright (C) 2023 gullradriel, Nilorea Studio Inc. + * Copyright (C) 2023 Kyle Reed * * This file is part of PortaPack. * @@ -26,6 +27,7 @@ #include "ui_widget.hpp" #include "ui_menu.hpp" +#include "ui_receiver.hpp" #include "ui_navigation.hpp" #include "bitmap.hpp" #include "ff.h" @@ -35,8 +37,6 @@ namespace ui { -#define MAX_FREQ_CORRECTION INT32_MAX - struct SetDateTimeModel { uint16_t year; uint8_t month; @@ -56,25 +56,28 @@ class SetDateTimeView : public View { private: Labels labels{ - {{6 * 8, 7 * 16}, "YYYY-MM-DD HH:MM:SS", Color::grey()}, - {{10 * 8, 9 * 16}, "- - : :", Color::light_grey()}}; + {{1 * 8, 1 * 16}, "Adjust the RTC clock date &", Color::light_grey()}, + {{1 * 8, 2 * 16}, "time. If clock resets after", Color::light_grey()}, + {{1 * 8, 3 * 16}, "reboot, coin batt. is dead. ", Color::light_grey()}, + {{5 * 8, 8 * 16 - 2}, "YYYY-MM-DD HH:MM:SS", Color::grey()}, + {{9 * 8, 9 * 16}, "- - : :", Color::light_grey()}}; NumberField field_year{ - {6 * 8, 9 * 16}, + {5 * 8, 9 * 16}, 4, {2015, 2099}, 1, '0', }; NumberField field_month{ - {11 * 8, 9 * 16}, + {10 * 8, 9 * 16}, 2, {1, 12}, 1, '0', }; NumberField field_day{ - {14 * 8, 9 * 16}, + {13 * 8, 9 * 16}, 2, {1, 31}, 1, @@ -82,21 +85,21 @@ class SetDateTimeView : public View { }; NumberField field_hour{ - {17 * 8, 9 * 16}, + {16 * 8, 9 * 16}, 2, {0, 23}, 1, '0', }; NumberField field_minute{ - {20 * 8, 9 * 16}, + {19 * 8, 9 * 16}, 2, {0, 59}, 1, '0', }; NumberField field_second{ - {23 * 8, 9 * 16}, + {22 * 8, 9 * 16}, 2, {0, 59}, 1, @@ -131,22 +134,30 @@ class SetRadioView : public View { uint8_t freq_step_khz = 3; Text label_source{ - {0, 1 * 16, 17 * 8, 16}, + {1 * 8, 1 * 16, 17 * 8, 16}, "Reference Source:"}; Text value_source{ - {(240 - 11 * 8), 1 * 16, 11 * 8, 16}, - "---"}; + {18 * 8, 1 * 16, 11 * 8, 16}, + ""}; Text value_source_frequency{ - {(240 - 11 * 8), 2 * 16, 11 * 8, 16}, - "---"}; + {18 * 8, 2 * 16, 11 * 8, 16}, + ""}; Labels labels_correction{ {{2 * 8, 3 * 16}, "Frequency correction:", Color::light_grey()}, {{6 * 8, 4 * 16}, "PPM", Color::light_grey()}, }; + NumberField field_ppm{ + {2 * 8, 4 * 16}, + 3, + {-50, 50}, + 1, + '0', + }; + Checkbox check_clkout{ {18, (6 * 16 - 4)}, 13, @@ -167,23 +178,15 @@ class SetRadioView : public View { "| "}; Labels labels_bias{ - {{24, 8 * 16}, "CAUTION: Ensure that all", Color::red()}, - {{28, 9 * 16}, "devices attached to the", Color::red()}, - {{8, 10 * 16}, "antenna connector can accept", Color::red()}, - {{68, 11 * 16}, "a DC voltage!", Color::red()}}; - - NumberField field_ppm{ - {2 * 8, 4 * 16}, - 3, - {-50, 50}, - 1, - '0', - }; + {{4 * 8 + 4, 8 * 16}, "CAUTION: Ensure that all", Color::red()}, + {{5 * 8 + 0, 9 * 16}, "devices attached to the", Color::red()}, + {{6 * 8 + 0, 10 * 16}, "antenna connector can", Color::red()}, + {{6 * 8 + 4, 11 * 16}, "accept a DC voltage!", Color::red()}}; Checkbox check_bias{ {18, 12 * 16}, 5, - "Turn on bias voltage"}; + "Enable DC bias voltage"}; Checkbox disable_external_tcxo{ {18, 14 * 16}, @@ -312,19 +315,25 @@ class SetAppSettingsView : public View { SetAppSettingsView(NavigationView& nav); void focus() override; - - std::string title() const override { return "AppSettings"; }; + std::string title() const override { return "App Settings"; }; private: + Labels labels{ + {{1 * 8, 1 * 16}, "App settings are saved to", Color::light_grey()}, + {{1 * 8, 2 * 16}, "the SD card in /SETTINGS.", Color::light_grey()}, + {{1 * 8, 3 * 16}, "Radio settings may also be", Color::light_grey()}, + {{1 * 8, 4 * 16}, "loaded or saved per app.", Color::light_grey()}, + }; + Checkbox checkbox_load_app_settings{ - {3 * 8, 2 * 16}, + {3 * 8, 6 * 16}, 25, - "Load app settings"}; + "Load radio settings"}; Checkbox checkbox_save_app_settings{ - {3 * 8, 4 * 16}, + {3 * 8, 8 * 16}, 25, - "Save app settings"}; + "Save radio settings"}; Button button_save{ {2 * 8, 16 * 16, 12 * 8, 32}, @@ -345,28 +354,34 @@ class SetConverterSettingsView : public View { std::string title() const override { return "Converter"; }; private: + Labels labels{ + {{1 * 8, 1 * 16}, "Options for working with", Color::light_grey()}, + {{1 * 8, 2 * 16}, "up/down converter hardware", Color::light_grey()}, + {{1 * 8, 3 * 16}, "like a Ham It Up.", Color::light_grey()}, + {{2 * 8, 9 * 16 - 2}, "Conversion frequency:", Color::light_grey()}, + {{18 * 8, 10 * 16}, "MHz", Color::light_grey()}, + }; + Checkbox check_show_converter{ - {18, 4 * 16}, + {2 * 8, 5 * 16}, 19, - "show/hide converter"}; + "Show converter icon"}; Checkbox check_converter{ - {18, 6 * 16}, - 7, - "enable/disable converter"}; + {2 * 8, 7 * 16}, + 16, + "Enable converter"}; - OptionsField converter_mode{ - {18, 8 * 16 + 4}, - 0, + OptionsField opt_converter_mode{ + {5 * 8, 10 * 16}, + 3, { {" + ", 0}, // up converter - {" - ", 1} // down converter + {" - ", 1}, // down converter }}; - Button button_converter_freq{ - {18 + 4 * 8, 8 * 16, 16 * 8, 24}, - "", - }; + FrequencyField field_converter_freq{ + {8 * 8, 10 * 16}}; Button button_return{ {16 * 8, 16 * 16, 12 * 8, 32}, @@ -380,33 +395,36 @@ class SetFrequencyCorrectionView : public View { void focus() override; - std::string title() const override { return "FreqCorrect"; }; + std::string title() const override { return "Freq Correct"; }; private: - Text text_freqCorrection_about{ - {0, 2 * 16, 240, 16}, - "Set Frequency correction:"}; + Labels labels{ + {{1 * 8, 1 * 16}, "Frequency correction allows", Color::light_grey()}, + {{1 * 8, 2 * 16}, "RX and TX frequencies to be", Color::light_grey()}, + {{1 * 8, 3 * 16}, "adjusted for all apps.", Color::light_grey()}, + {{2 * 8, 6 * 16}, "RX Adjustment Frequency", Color::light_grey()}, + {{18 * 8, 7 * 16}, "MHz", Color::light_grey()}, + {{2 * 8, 9 * 16}, "TX Adjustment Frequency", Color::light_grey()}, + {{18 * 8, 10 * 16}, "MHz", Color::light_grey()}, + }; - OptionsField frequency_rx_correction_mode{ - {18, 5 * 16 + 4}, - 0, + OptionsField opt_rx_correction_mode{ + {5 * 8, 7 * 16}, + 3, {{" + ", 0}, {" - ", 1}}}; - OptionsField frequency_tx_correction_mode{ - {18, 9 * 16 + 4}, - 0, + FrequencyField field_rx_correction{ + {8 * 8, 7 * 16}}; + + OptionsField opt_tx_correction_mode{ + {5 * 8, 10 * 16}, + 3, {{" + ", 0}, {" - ", 1}}}; - Button button_freq_rx_correction{ - {18 + 4 * 8, 5 * 16, 20 * 8, 24}, - "", - }; - Button button_freq_tx_correction{ - {18 + 4 * 8, 9 * 16, 20 * 8, 24}, - "", - }; + FrequencyField field_tx_correction{ + {8 * 8, 10 * 16}}; Button button_return{ {16 * 8, 16 * 16, 12 * 8, 32}, @@ -424,11 +442,14 @@ class SetAudioView : public View { private: Labels labels{ - {{2 * 8, 3 * 16}, "Tone key mix: %", Color::light_grey()}, + {{1 * 8, 1 * 16}, "Controls the volume of the", Color::light_grey()}, + {{1 * 8, 2 * 16}, "tone when transmitting in", Color::light_grey()}, + {{1 * 8, 3 * 16}, "Soundboard or Mic apps.", Color::light_grey()}, + {{2 * 8, 5 * 16}, "Tone key mix: %", Color::light_grey()}, }; NumberField field_tone_mix{ - {16 * 8, 3 * 16}, + {16 * 8, 5 * 16}, 2, {10, 99}, 1, @@ -453,8 +474,13 @@ class SetQRCodeView : public View { std::string title() const override { return "QR Code"; }; private: + Labels labels{ + {{1 * 8, 1 * 16}, "Change the size of the QR", Color::light_grey()}, + {{1 * 8, 2 * 16}, "code shown in Radiosonde.", Color::light_grey()}, + }; + Checkbox checkbox_bigger_qr{ - {3 * 8, 9 * 16}, + {3 * 8, 4 * 16}, 20, "Show large QR code"}; @@ -480,11 +506,13 @@ class SetEncoderDialView : public View { private: Labels labels{ - {{2 * 8, 3 * 16}, "Dial sensitivity:", Color::light_grey()}, + {{1 * 8, 1 * 16}, "Adjusts how many steps to", Color::light_grey()}, + {{1 * 8, 2 * 16}, "change the encoder value.", Color::light_grey()}, + {{2 * 8, 4 * 16}, "Dial sensitivity:", Color::light_grey()}, }; OptionsField field_encoder_dial_sensitivity{ - {20 * 8, 3 * 16}, + {20 * 8, 4 * 16}, 6, {{"LOW", encoder_dial_sensitivity::DIAL_SENSITIVITY_LOW}, {"NORMAL", encoder_dial_sensitivity::DIAL_SENSITIVITY_NORMAL}, @@ -509,34 +537,32 @@ class SetPersistentMemoryView : public View { std::string title() const override { return "P.Mem Mgmt"; }; private: - Text text_pmem_about{ - {0, 1 * 16, 240, 16}, - "Persistent Memory from/to SD"}; - - Text text_pmem_informations{ - {0, 2 * 16, 240, 16}, - "use: when no/dead coin bat."}; + Labels labels{ + {{1 * 8, 1 * 16}, "Save persistent memory on SD", Color::light_grey()}, + {{1 * 8, 2 * 16}, "card. Needed when device has", Color::light_grey()}, + {{1 * 8, 3 * 16}, "dead/missing coin battery.", Color::light_grey()}, + }; Text text_pmem_status{ - {0, 3 * 16, 240, 16}, + {1 * 8, 4 * 16 + 8, 28 * 8, 16}, ""}; Checkbox check_use_sdcard_for_pmem{ - {18, 6 * 16}, - 19, - "use sdcard for p.mem"}; + {2 * 8, 6 * 16}, + 21, + "Use SD card for P.Mem"}; Button button_save_mem_to_file{ - {0, 8 * 16, 240, 32}, - "save p.mem to sdcard"}; + {1 * 8, 8 * 16, 28 * 8, 2 * 16}, + "Save P.Mem to SD card"}; Button button_load_mem_from_file{ - {0, 10 * 16 + 4, 240, 32}, - "load p.mem from sdcard"}; + {1 * 8, 10 * 16 + 2, 28 * 8, 2 * 16}, + "Load P.Mem from SD Card"}; Button button_load_mem_defaults{ - {0, 12 * 16 + 8, 240, 32}, - "! reset p.mem, load defaults !"}; + {1 * 8, 12 * 16 + 4, 28 * 8, 2 * 16}, + "Reset P.Mem to defaults"}; Button button_return{ {16 * 8, 16 * 16, 12 * 8, 32}, diff --git a/firmware/application/apps/ui_sonde.cpp b/firmware/application/apps/ui_sonde.cpp index 3ce5fffa..ddb2d99d 100644 --- a/firmware/application/apps/ui_sonde.cpp +++ b/firmware/application/apps/ui_sonde.cpp @@ -66,7 +66,7 @@ SondeView::SondeView(NavigationView& nav) &button_see_qr, &button_see_map}); - if (!settings_.loaded()) + if (!settings_.radio_loaded()) field_frequency.set_value(initial_target_frequency); field_frequency.set_step(500); // euquiq: was 10000, but we are using this for fine-tunning diff --git a/firmware/application/baseband_api.cpp b/firmware/application/baseband_api.cpp index 3ae12c5b..fe5bd9ba 100644 --- a/firmware/application/baseband_api.cpp +++ b/firmware/application/baseband_api.cpp @@ -189,7 +189,16 @@ void kill_afsk() { send_message(&message); } -void set_audiotx_config(const uint32_t divider, const float deviation_hz, const float audio_gain, uint8_t audio_shift_bits_s16, const uint32_t tone_key_delta, const bool am_enabled, const bool dsb_enabled, const bool usb_enabled, const bool lsb_enabled) { +void set_audiotx_config( + const uint32_t divider, + const float deviation_hz, + const float audio_gain, + uint8_t audio_shift_bits_s16, + const uint32_t tone_key_delta, + const bool am_enabled, + const bool dsb_enabled, + const bool usb_enabled, + const bool lsb_enabled) { const AudioTXConfigMessage message{ divider, deviation_hz,