App Settings w/out radio settings, Settings UI cleanup (#1443)

* Make app settings more consistent

* Allow app settings to always work for custom settings
This commit is contained in:
Kyle Reed 2023-09-10 17:04:20 -07:00 committed by GitHub
parent b28283271b
commit 70e0f2913f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 305 additions and 232 deletions

View File

@ -244,55 +244,64 @@ SettingsManager::SettingsManager(
: app_name_{app_name}, : app_name_{app_name},
settings_{}, settings_{},
bindings_{}, bindings_{},
loaded_{false} { loaded_{false},
radio_loaded_{false} {
settings_.mode = mode; settings_.mode = mode;
settings_.options = options; settings_.options = options;
if (!portapack::persistent_memory::load_app_settings())
return;
// Pre-alloc enough for app settings and additional settings. // Pre-alloc enough for app settings and additional settings.
additional_settings.reserve(17 + additional_settings.size()); additional_settings.reserve(17 + additional_settings.size());
bindings_ = std::move(additional_settings); bindings_ = std::move(additional_settings);
// Transmitter model settings. // Additional settings should always be loaded because apps now rely
if (flags_enabled(mode, Mode::TX)) { // on being able to store UI settings, config, etc. The radio settings
bindings_.emplace_back("tx_frequency"sv, &settings_.tx_frequency); // are only loaded if the global option has been enabled.
bindings_.emplace_back("tx_amp"sv, &settings_.tx_amp); // Add the radio setting bindings if either load or save are enabled.
bindings_.emplace_back("tx_gain"sv, &settings_.tx_gain); if (portapack::persistent_memory::load_app_settings() ||
bindings_.emplace_back("channel_bandwidth"sv, &settings_.channel_bandwidth); 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. // Receiver model settings.
if (flags_enabled(mode, Mode::RX)) { if (flags_enabled(mode, Mode::RX)) {
bindings_.emplace_back("rx_frequency"sv, &settings_.rx_frequency); bindings_.emplace_back("rx_frequency"sv, &settings_.rx_frequency);
bindings_.emplace_back("lna"sv, &settings_.lna); bindings_.emplace_back("lna"sv, &settings_.lna);
bindings_.emplace_back("vga"sv, &settings_.vga); bindings_.emplace_back("vga"sv, &settings_.vga);
bindings_.emplace_back("rx_amp"sv, &settings_.rx_amp); bindings_.emplace_back("rx_amp"sv, &settings_.rx_amp);
bindings_.emplace_back("modulation"sv, &settings_.modulation); bindings_.emplace_back("modulation"sv, &settings_.modulation);
bindings_.emplace_back("am_config_index"sv, &settings_.am_config_index); 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("nbfm_config_index"sv, &settings_.nbfm_config_index);
bindings_.emplace_back("wfm_config_index"sv, &settings_.wfm_config_index); bindings_.emplace_back("wfm_config_index"sv, &settings_.wfm_config_index);
bindings_.emplace_back("squelch"sv, &settings_.squelch); bindings_.emplace_back("squelch"sv, &settings_.squelch);
} }
// Common model settings. // Common model settings.
bindings_.emplace_back("baseband_bandwidth"sv, &settings_.baseband_bandwidth); bindings_.emplace_back("baseband_bandwidth"sv, &settings_.baseband_bandwidth);
bindings_.emplace_back("sampling_rate"sv, &settings_.sampling_rate); bindings_.emplace_back("sampling_rate"sv, &settings_.sampling_rate);
bindings_.emplace_back("step"sv, &settings_.step); bindings_.emplace_back("step"sv, &settings_.step);
bindings_.emplace_back("volume"sv, &settings_.volume); bindings_.emplace_back("volume"sv, &settings_.volume);
}
loaded_ = load_settings(app_name_, bindings_); 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_); 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 } // namespace app_settings

View File

@ -150,7 +150,9 @@ void copy_to_radio_model(const AppSettings& settings);
/* Copies common values from the receiver/transmitter models. */ /* Copies common values from the receiver/transmitter models. */
void copy_from_radio_model(AppSettings& settings); 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 * 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. */ * the receiver/transmitter models are set before the control ctors run. */
class SettingsManager { class SettingsManager {
@ -167,6 +169,9 @@ class SettingsManager {
/* True if settings were successfully loaded from file. */ /* True if settings were successfully loaded from file. */
bool loaded() const { return loaded_; } 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; } Mode mode() const { return settings_.mode; }
AppSettings& raw() { return settings_; } AppSettings& raw() { return settings_; }
@ -176,6 +181,7 @@ class SettingsManager {
AppSettings settings_; AppSettings settings_;
SettingBindings bindings_; SettingBindings bindings_;
bool loaded_; bool loaded_;
bool radio_loaded_;
}; };
} // namespace app_settings } // namespace app_settings

View File

@ -382,7 +382,7 @@ AISAppView::AISAppView(NavigationView& nav)
recent_entry_detail_view.hidden(true); recent_entry_detail_view.hidden(true);
if (!settings_.loaded()) if (!settings_.radio_loaded())
receiver_model.set_target_frequency(initial_target_frequency); receiver_model.set_target_frequency(initial_target_frequency);
receiver_model.enable(); receiver_model.enable();

View File

@ -110,7 +110,7 @@ ERTAppView::ERTAppView(NavigationView&) {
&recent_entries_view, &recent_entries_view,
}); });
if (!settings_.loaded()) if (!settings_.radio_loaded())
receiver_model.set_target_frequency(initial_target_frequency); receiver_model.set_target_frequency(initial_target_frequency);
receiver_model.enable(); receiver_model.enable();

View File

@ -173,7 +173,7 @@ GpsSimAppView::GpsSimAppView(
&waterfall, &waterfall,
}); });
if (!settings_.loaded()) { if (!settings_.radio_loaded()) {
field_frequency.set_value(initial_target_frequency); field_frequency.set_value(initial_target_frequency);
transmitter_model.set_sampling_rate(2600000); transmitter_model.set_sampling_rate(2600000);
} }

View File

@ -112,12 +112,14 @@ POCSAGAppView::POCSAGAppView(NavigationView& nav)
&button_config, &button_config,
&console}); &console});
// No app settings, use fallbacks. // No app settings, use fallbacks from pmem.
if (!app_settings_.loaded()) { if (!app_settings_.loaded()) {
field_frequency.set_value(initial_target_frequency);
settings_.address_to_ignore = pmem::pocsag_ignore_address(); settings_.address_to_ignore = pmem::pocsag_ignore_address();
settings_.enable_ignore = settings_.address_to_ignore > 0; 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"); logger.append(LOG_ROOT_DIR "/POCSAG.TXT");
@ -151,7 +153,7 @@ POCSAGAppView::~POCSAGAppView() {
receiver_model.disable(); receiver_model.disable();
baseband::shutdown(); baseband::shutdown();
// Save pmem settings. TODO: Even needed anymore? // Save pmem settings.
pmem::set_pocsag_ignore_address(settings_.address_to_ignore); pmem::set_pocsag_ignore_address(settings_.address_to_ignore);
pmem::set_pocsag_last_address(pocsag_state.address); // For POCSAG TX. pmem::set_pocsag_last_address(pocsag_state.address); // For POCSAG TX.
} }

View File

@ -157,7 +157,7 @@ TPMSAppView::TPMSAppView(NavigationView&) {
&field_vga, &field_vga,
&recent_entries_view}); &recent_entries_view});
if (!settings_.loaded()) if (!settings_.radio_loaded())
receiver_model.set_target_frequency(initial_target_frequency); receiver_model.set_target_frequency(initial_target_frequency);
receiver_model.enable(); receiver_model.enable();

View File

@ -2,6 +2,7 @@
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2016 Furrtek * Copyright (C) 2016 Furrtek
* Copyright (C) 2023 gullradriel, Nilorea Studio Inc. * Copyright (C) 2023 gullradriel, Nilorea Studio Inc.
* Copyright (C) 2023 Kyle Reed
* *
* This file is part of PortaPack. * This file is part of PortaPack.
* *
@ -125,8 +126,30 @@ SetRadioView::SetRadioView(
nav.pop(); 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(); const auto reference = clock_manager.get_reference();
if (reference.source == ClockManager::ReferenceSource::Xtal) {
add_children({
&labels_correction,
&field_ppm,
});
}
std::string source_name("---"); std::string source_name("---");
switch (reference.source) { switch (reference.source) {
case ClockManager::ReferenceSource::Xtal: case ClockManager::ReferenceSource::Xtal:
@ -141,36 +164,15 @@ SetRadioView::SetRadioView(
} }
value_source.set(source_name); 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); label_source.set_style(&Styles::light_grey);
value_source.set_style(&Styles::light_grey); value_source.set_style(&Styles::light_grey);
value_source_frequency.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{ SetFrequencyCorrectionModel model{
static_cast<int8_t>(pmem::correction_ppb() / 1000), 0}; static_cast<int8_t>(pmem::correction_ppb() / 1000), 0};
@ -344,10 +346,13 @@ void SetUIView::focus() {
/* SetAppSettingsView ************************************/ /* SetAppSettingsView ************************************/
SetAppSettingsView::SetAppSettingsView(NavigationView& nav) { SetAppSettingsView::SetAppSettingsView(NavigationView& nav) {
add_children({&checkbox_load_app_settings, add_children({
&checkbox_save_app_settings, &labels,
&button_save, &checkbox_load_app_settings,
&button_cancel}); &checkbox_save_app_settings,
&button_save,
&button_cancel,
});
checkbox_load_app_settings.set_value(pmem::load_app_settings()); checkbox_load_app_settings.set_value(pmem::load_app_settings());
checkbox_save_app_settings.set_value(pmem::save_app_settings()); checkbox_save_app_settings.set_value(pmem::save_app_settings());
@ -369,11 +374,14 @@ void SetAppSettingsView::focus() {
/* SetConverterSettingsView ******************************/ /* SetConverterSettingsView ******************************/
SetConverterSettingsView::SetConverterSettingsView(NavigationView& nav) { SetConverterSettingsView::SetConverterSettingsView(NavigationView& nav) {
add_children({&check_show_converter, add_children({
&check_converter, &labels,
&converter_mode, &check_show_converter,
&button_converter_freq, &check_converter,
&button_return}); &opt_converter_mode,
&field_converter_freq,
&button_return,
});
check_show_converter.set_value(!pmem::ui_hide_converter()); check_show_converter.set_value(!pmem::ui_hide_converter());
check_show_converter.on_select = [this](Checkbox&, bool v) { check_show_converter.on_select = [this](Checkbox&, bool v) {
@ -383,7 +391,7 @@ SetConverterSettingsView::SetConverterSettingsView(NavigationView& nav) {
} }
// Retune to take converter change in account. // Retune to take converter change in account.
receiver_model.set_target_frequency(receiver_model.target_frequency()); receiver_model.set_target_frequency(receiver_model.target_frequency());
// Refresh status bar with/out converter // Refresh status bar converter icon.
send_system_refresh(); send_system_refresh();
}; };
@ -394,27 +402,30 @@ SetConverterSettingsView::SetConverterSettingsView(NavigationView& nav) {
pmem::set_ui_hide_converter(false); pmem::set_ui_hide_converter(false);
} }
pmem::set_config_converter(v); 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()); receiver_model.set_target_frequency(receiver_model.target_frequency());
// Refresh status bar with/out converter // Refresh status bar converter icon.
send_system_refresh(); send_system_refresh();
}; };
converter_mode.set_by_value(pmem::config_updown_converter()); opt_converter_mode.set_by_value(pmem::config_updown_converter());
converter_mode.on_change = [this](size_t, OptionsField::value_t v) { opt_converter_mode.on_change = [this](size_t, OptionsField::value_t v) {
pmem::set_config_updown_converter(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(); send_system_refresh();
}; };
button_converter_freq.set_text(to_string_short_freq(pmem::config_converter_freq()) + "MHz"); field_converter_freq.set_step(1'000'000);
button_converter_freq.on_select = [this, &nav](Button& button) { field_converter_freq.set_value(pmem::config_converter_freq());
auto new_view = nav.push<FrequencyKeypadView>(pmem::config_converter_freq()); field_converter_freq.on_change = [this](rf::Frequency f) {
new_view->on_changed = [this, &button](rf::Frequency f) { pmem::set_config_converter_freq(f);
pmem::set_config_converter_freq(f); // Retune to take converter change in account.
// Retune to take converter change in account receiver_model.set_target_frequency(receiver_model.target_frequency());
receiver_model.set_target_frequency(receiver_model.target_frequency()); };
button_converter_freq.set_text("<" + to_string_short_freq(f) + " MHz>"); field_converter_freq.on_edit = [this, &nav]() {
auto new_view = nav.push<FrequencyKeypadView>(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::SetFrequencyCorrectionView(NavigationView& nav) { SetFrequencyCorrectionView::SetFrequencyCorrectionView(NavigationView& nav) {
add_children({&text_freqCorrection_about, add_children({
&frequency_rx_correction_mode, &labels,
&frequency_tx_correction_mode, &opt_rx_correction_mode,
&button_freq_rx_correction, &field_rx_correction,
&button_freq_tx_correction, &opt_tx_correction_mode,
&button_return}); &field_tx_correction,
&button_return,
});
frequency_rx_correction_mode.set_by_value(pmem::config_freq_rx_correction_updown()); opt_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.on_change = [this](size_t, OptionsField::value_t v) {
pmem::set_freq_rx_correction_updown(v); pmem::set_freq_rx_correction_updown(v);
}; };
frequency_tx_correction_mode.set_by_value(pmem::config_freq_rx_correction_updown()); opt_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.on_change = [this](size_t, OptionsField::value_t v) {
pmem::set_freq_tx_correction_updown(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)"); field_rx_correction.set_step(100'000);
button_freq_rx_correction.on_select = [this, &nav](Button& button) { field_rx_correction.set_value(pmem::config_freq_rx_correction());
auto new_view = nav.push<FrequencyKeypadView>(pmem::config_converter_freq()); field_rx_correction.on_change = [this](rf::Frequency f) {
new_view->on_changed = [this, &button](rf::Frequency f) { pmem::set_config_freq_rx_correction(f);
if (f >= MAX_FREQ_CORRECTION) // Retune to take converter change in account.
f = MAX_FREQ_CORRECTION; receiver_model.set_target_frequency(receiver_model.target_frequency());
pmem::set_config_freq_rx_correction(f); };
// Retune to take converter change in account field_rx_correction.on_edit = [this, &nav]() {
receiver_model.set_target_frequency(receiver_model.target_frequency()); auto new_view = nav.push<FrequencyKeypadView>(field_rx_correction.value());
button_freq_rx_correction.set_text("<" + to_string_short_freq(f) + " MHz>"); 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)"); field_tx_correction.set_step(100'000);
button_freq_tx_correction.on_select = [this, &nav](Button& button) { field_tx_correction.set_value(pmem::config_freq_tx_correction());
auto new_view = nav.push<FrequencyKeypadView>(pmem::config_converter_freq()); field_tx_correction.on_change = [this](rf::Frequency f) {
new_view->on_changed = [this, &button](rf::Frequency f) { pmem::set_config_freq_tx_correction(f);
if (f >= MAX_FREQ_CORRECTION) // Retune to take converter change in account. NB: receiver_model.
f = MAX_FREQ_CORRECTION; receiver_model.set_target_frequency(receiver_model.target_frequency());
pmem::set_config_freq_tx_correction(f); };
// Retune to take converter change in account field_tx_correction.on_edit = [this, &nav]() {
receiver_model.set_target_frequency(receiver_model.target_frequency()); auto new_view = nav.push<FrequencyKeypadView>(field_tx_correction.value());
button_freq_tx_correction.set_text("<" + to_string_short_freq(f) + " MHz>"); new_view->on_changed = [this](rf::Frequency f) {
field_tx_correction.set_value(f);
}; };
}; };
@ -485,49 +500,52 @@ void SetFrequencyCorrectionView::focus() {
/* SetPersistentMemoryView *******************************/ /* SetPersistentMemoryView *******************************/
SetPersistentMemoryView::SetPersistentMemoryView(NavigationView& nav) { SetPersistentMemoryView::SetPersistentMemoryView(NavigationView& nav) {
add_children({&text_pmem_about, add_children({
&text_pmem_informations, &labels,
&text_pmem_status, &text_pmem_status,
&check_use_sdcard_for_pmem, &check_use_sdcard_for_pmem,
&button_save_mem_to_file, &button_save_mem_to_file,
&button_load_mem_from_file, &button_load_mem_from_file,
&button_load_mem_defaults, &button_load_mem_defaults,
&button_return}); &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.set_value(pmem::should_use_sdcard_for_pmem());
check_use_sdcard_for_pmem.on_select = [this](Checkbox&, bool v) { check_use_sdcard_for_pmem.on_select = [this](Checkbox&, bool v) {
File pmem_flag_file_handle; File pmem_flag_file_handle;
if (v) { if (v) {
if (fs::file_exists(PMEM_FILEFLAG)) { if (fs::file_exists(PMEM_FILEFLAG)) {
text_pmem_status.set("pmem flag already present"); text_pmem_status.set("P.Mem flag file present.");
} else { } else {
auto error = pmem_flag_file_handle.create(PMEM_FILEFLAG); auto error = pmem_flag_file_handle.create(PMEM_FILEFLAG);
if (error) if (error)
text_pmem_status.set("!err. creating pmem flagfile!"); text_pmem_status.set("Error creating P.Mem File!");
else else
text_pmem_status.set("pmem flag file created"); text_pmem_status.set("P.Mem flag file created.");
} }
} else { } else {
auto result = delete_file(PMEM_FILEFLAG); auto result = delete_file(PMEM_FILEFLAG);
if (result.code() != FR_OK) if (result.code() != FR_OK)
text_pmem_status.set("!err. deleting pmem flagfile!"); text_pmem_status.set("Error deleting P.Mem flag!");
else 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&) { button_save_mem_to_file.on_select = [&nav, this](Button&) {
if (!pmem::save_persistent_settings_to_file()) if (!pmem::save_persistent_settings_to_file())
text_pmem_status.set("!problem saving settings!"); text_pmem_status.set("Error saving settings!");
else else
text_pmem_status.set("settings saved"); text_pmem_status.set("Settings saved.");
}; };
button_load_mem_from_file.on_select = [&nav, this](Button&) { button_load_mem_from_file.on_select = [&nav, this](Button&) {
if (!pmem::load_persistent_settings_from_file()) { if (!pmem::load_persistent_settings_from_file()) {
text_pmem_status.set("!problem loading settings!"); text_pmem_status.set("Error loading settings!");
} else { } else {
text_pmem_status.set("settings loaded"); text_pmem_status.set("Settings loaded.");
// Refresh status bar with icon up or down // Refresh status bar with icon up or down
send_system_refresh(); send_system_refresh();
} }
@ -536,7 +554,7 @@ SetPersistentMemoryView::SetPersistentMemoryView(NavigationView& nav) {
button_load_mem_defaults.on_select = [&nav, this](Button&) { button_load_mem_defaults.on_select = [&nav, this](Button&) {
nav.push<ModalMessageView>( nav.push<ModalMessageView>(
"Warning!", "Warning!",
"This will reset the p.mem\nand set the default settings", "This will reset the P.Mem\nto default settings.",
YESNO, YESNO,
[this](bool choice) { [this](bool choice) {
if (choice) { if (choice) {
@ -582,9 +600,12 @@ void SetAudioView::focus() {
/* SetQRCodeView *****************************************/ /* SetQRCodeView *****************************************/
SetQRCodeView::SetQRCodeView(NavigationView& nav) { SetQRCodeView::SetQRCodeView(NavigationView& nav) {
add_children({&checkbox_bigger_qr, add_children({
&button_save, &labels,
&button_cancel}); &checkbox_bigger_qr,
&button_save,
&button_cancel,
});
checkbox_bigger_qr.set_value(pmem::show_bigger_qr_code()); 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<TouchCalibrationView>(); }}, {"Calibration", ui::Color::dark_cyan(), &bitmap_icon_options_touch, [&nav]() { nav.push<TouchCalibrationView>(); }},
{"App Settings", ui::Color::dark_cyan(), &bitmap_icon_setup, [&nav]() { nav.push<SetAppSettingsView>(); }}, {"App Settings", ui::Color::dark_cyan(), &bitmap_icon_setup, [&nav]() { nav.push<SetAppSettingsView>(); }},
{"Converter", ui::Color::dark_cyan(), &bitmap_icon_options_radio, [&nav]() { nav.push<SetConverterSettingsView>(); }}, {"Converter", ui::Color::dark_cyan(), &bitmap_icon_options_radio, [&nav]() { nav.push<SetConverterSettingsView>(); }},
{"FreqCorrection", ui::Color::dark_cyan(), &bitmap_icon_options_radio, [&nav]() { nav.push<SetFrequencyCorrectionView>(); }}, {"Freq. Correct", ui::Color::dark_cyan(), &bitmap_icon_options_radio, [&nav]() { nav.push<SetFrequencyCorrectionView>(); }},
{"QR Code", ui::Color::dark_cyan(), &bitmap_icon_qr_code, [&nav]() { nav.push<SetQRCodeView>(); }}, {"QR Code", ui::Color::dark_cyan(), &bitmap_icon_qr_code, [&nav]() { nav.push<SetQRCodeView>(); }},
{"P.Memory Mgmt", ui::Color::dark_cyan(), &bitmap_icon_memory, [&nav]() { nav.push<SetPersistentMemoryView>(); }}, {"P.Memory Mgmt", ui::Color::dark_cyan(), &bitmap_icon_memory, [&nav]() { nav.push<SetPersistentMemoryView>(); }},
{"Encoder Dial", ui::Color::dark_cyan(), &bitmap_icon_setup, [&nav]() { nav.push<SetEncoderDialView>(); }}, {"Encoder Dial", ui::Color::dark_cyan(), &bitmap_icon_setup, [&nav]() { nav.push<SetEncoderDialView>(); }},

View File

@ -2,6 +2,7 @@
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2016 Furrtek * Copyright (C) 2016 Furrtek
* Copyright (C) 2023 gullradriel, Nilorea Studio Inc. * Copyright (C) 2023 gullradriel, Nilorea Studio Inc.
* Copyright (C) 2023 Kyle Reed
* *
* This file is part of PortaPack. * This file is part of PortaPack.
* *
@ -26,6 +27,7 @@
#include "ui_widget.hpp" #include "ui_widget.hpp"
#include "ui_menu.hpp" #include "ui_menu.hpp"
#include "ui_receiver.hpp"
#include "ui_navigation.hpp" #include "ui_navigation.hpp"
#include "bitmap.hpp" #include "bitmap.hpp"
#include "ff.h" #include "ff.h"
@ -35,8 +37,6 @@
namespace ui { namespace ui {
#define MAX_FREQ_CORRECTION INT32_MAX
struct SetDateTimeModel { struct SetDateTimeModel {
uint16_t year; uint16_t year;
uint8_t month; uint8_t month;
@ -56,25 +56,28 @@ class SetDateTimeView : public View {
private: private:
Labels labels{ Labels labels{
{{6 * 8, 7 * 16}, "YYYY-MM-DD HH:MM:SS", Color::grey()}, {{1 * 8, 1 * 16}, "Adjust the RTC clock date &", Color::light_grey()},
{{10 * 8, 9 * 16}, "- - : :", 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{ NumberField field_year{
{6 * 8, 9 * 16}, {5 * 8, 9 * 16},
4, 4,
{2015, 2099}, {2015, 2099},
1, 1,
'0', '0',
}; };
NumberField field_month{ NumberField field_month{
{11 * 8, 9 * 16}, {10 * 8, 9 * 16},
2, 2,
{1, 12}, {1, 12},
1, 1,
'0', '0',
}; };
NumberField field_day{ NumberField field_day{
{14 * 8, 9 * 16}, {13 * 8, 9 * 16},
2, 2,
{1, 31}, {1, 31},
1, 1,
@ -82,21 +85,21 @@ class SetDateTimeView : public View {
}; };
NumberField field_hour{ NumberField field_hour{
{17 * 8, 9 * 16}, {16 * 8, 9 * 16},
2, 2,
{0, 23}, {0, 23},
1, 1,
'0', '0',
}; };
NumberField field_minute{ NumberField field_minute{
{20 * 8, 9 * 16}, {19 * 8, 9 * 16},
2, 2,
{0, 59}, {0, 59},
1, 1,
'0', '0',
}; };
NumberField field_second{ NumberField field_second{
{23 * 8, 9 * 16}, {22 * 8, 9 * 16},
2, 2,
{0, 59}, {0, 59},
1, 1,
@ -131,22 +134,30 @@ class SetRadioView : public View {
uint8_t freq_step_khz = 3; uint8_t freq_step_khz = 3;
Text label_source{ Text label_source{
{0, 1 * 16, 17 * 8, 16}, {1 * 8, 1 * 16, 17 * 8, 16},
"Reference Source:"}; "Reference Source:"};
Text value_source{ Text value_source{
{(240 - 11 * 8), 1 * 16, 11 * 8, 16}, {18 * 8, 1 * 16, 11 * 8, 16},
"---"}; ""};
Text value_source_frequency{ Text value_source_frequency{
{(240 - 11 * 8), 2 * 16, 11 * 8, 16}, {18 * 8, 2 * 16, 11 * 8, 16},
"---"}; ""};
Labels labels_correction{ Labels labels_correction{
{{2 * 8, 3 * 16}, "Frequency correction:", Color::light_grey()}, {{2 * 8, 3 * 16}, "Frequency correction:", Color::light_grey()},
{{6 * 8, 4 * 16}, "PPM", 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{ Checkbox check_clkout{
{18, (6 * 16 - 4)}, {18, (6 * 16 - 4)},
13, 13,
@ -167,23 +178,15 @@ class SetRadioView : public View {
"| "}; "| "};
Labels labels_bias{ Labels labels_bias{
{{24, 8 * 16}, "CAUTION: Ensure that all", Color::red()}, {{4 * 8 + 4, 8 * 16}, "CAUTION: Ensure that all", Color::red()},
{{28, 9 * 16}, "devices attached to the", Color::red()}, {{5 * 8 + 0, 9 * 16}, "devices attached to the", Color::red()},
{{8, 10 * 16}, "antenna connector can accept", Color::red()}, {{6 * 8 + 0, 10 * 16}, "antenna connector can", Color::red()},
{{68, 11 * 16}, "a DC voltage!", Color::red()}}; {{6 * 8 + 4, 11 * 16}, "accept a DC voltage!", Color::red()}};
NumberField field_ppm{
{2 * 8, 4 * 16},
3,
{-50, 50},
1,
'0',
};
Checkbox check_bias{ Checkbox check_bias{
{18, 12 * 16}, {18, 12 * 16},
5, 5,
"Turn on bias voltage"}; "Enable DC bias voltage"};
Checkbox disable_external_tcxo{ Checkbox disable_external_tcxo{
{18, 14 * 16}, {18, 14 * 16},
@ -312,19 +315,25 @@ class SetAppSettingsView : public View {
SetAppSettingsView(NavigationView& nav); SetAppSettingsView(NavigationView& nav);
void focus() override; void focus() override;
std::string title() const override { return "App Settings"; };
std::string title() const override { return "AppSettings"; };
private: 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{ Checkbox checkbox_load_app_settings{
{3 * 8, 2 * 16}, {3 * 8, 6 * 16},
25, 25,
"Load app settings"}; "Load radio settings"};
Checkbox checkbox_save_app_settings{ Checkbox checkbox_save_app_settings{
{3 * 8, 4 * 16}, {3 * 8, 8 * 16},
25, 25,
"Save app settings"}; "Save radio settings"};
Button button_save{ Button button_save{
{2 * 8, 16 * 16, 12 * 8, 32}, {2 * 8, 16 * 16, 12 * 8, 32},
@ -345,28 +354,34 @@ class SetConverterSettingsView : public View {
std::string title() const override { return "Converter"; }; std::string title() const override { return "Converter"; };
private: 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{ Checkbox check_show_converter{
{18, 4 * 16}, {2 * 8, 5 * 16},
19, 19,
"show/hide converter"}; "Show converter icon"};
Checkbox check_converter{ Checkbox check_converter{
{18, 6 * 16}, {2 * 8, 7 * 16},
7, 16,
"enable/disable converter"}; "Enable converter"};
OptionsField converter_mode{ OptionsField opt_converter_mode{
{18, 8 * 16 + 4}, {5 * 8, 10 * 16},
0, 3,
{ {
{" + ", 0}, // up converter {" + ", 0}, // up converter
{" - ", 1} // down converter {" - ", 1}, // down converter
}}; }};
Button button_converter_freq{ FrequencyField field_converter_freq{
{18 + 4 * 8, 8 * 16, 16 * 8, 24}, {8 * 8, 10 * 16}};
"",
};
Button button_return{ Button button_return{
{16 * 8, 16 * 16, 12 * 8, 32}, {16 * 8, 16 * 16, 12 * 8, 32},
@ -380,33 +395,36 @@ class SetFrequencyCorrectionView : public View {
void focus() override; void focus() override;
std::string title() const override { return "FreqCorrect"; }; std::string title() const override { return "Freq Correct"; };
private: private:
Text text_freqCorrection_about{ Labels labels{
{0, 2 * 16, 240, 16}, {{1 * 8, 1 * 16}, "Frequency correction allows", Color::light_grey()},
"Set Frequency correction:"}; {{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{ OptionsField opt_rx_correction_mode{
{18, 5 * 16 + 4}, {5 * 8, 7 * 16},
0, 3,
{{" + ", 0}, {{" + ", 0},
{" - ", 1}}}; {" - ", 1}}};
OptionsField frequency_tx_correction_mode{ FrequencyField field_rx_correction{
{18, 9 * 16 + 4}, {8 * 8, 7 * 16}};
0,
OptionsField opt_tx_correction_mode{
{5 * 8, 10 * 16},
3,
{{" + ", 0}, {{" + ", 0},
{" - ", 1}}}; {" - ", 1}}};
Button button_freq_rx_correction{ FrequencyField field_tx_correction{
{18 + 4 * 8, 5 * 16, 20 * 8, 24}, {8 * 8, 10 * 16}};
"",
};
Button button_freq_tx_correction{
{18 + 4 * 8, 9 * 16, 20 * 8, 24},
"",
};
Button button_return{ Button button_return{
{16 * 8, 16 * 16, 12 * 8, 32}, {16 * 8, 16 * 16, 12 * 8, 32},
@ -424,11 +442,14 @@ class SetAudioView : public View {
private: private:
Labels labels{ 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{ NumberField field_tone_mix{
{16 * 8, 3 * 16}, {16 * 8, 5 * 16},
2, 2,
{10, 99}, {10, 99},
1, 1,
@ -453,8 +474,13 @@ class SetQRCodeView : public View {
std::string title() const override { return "QR Code"; }; std::string title() const override { return "QR Code"; };
private: 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{ Checkbox checkbox_bigger_qr{
{3 * 8, 9 * 16}, {3 * 8, 4 * 16},
20, 20,
"Show large QR code"}; "Show large QR code"};
@ -480,11 +506,13 @@ class SetEncoderDialView : public View {
private: private:
Labels labels{ 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{ OptionsField field_encoder_dial_sensitivity{
{20 * 8, 3 * 16}, {20 * 8, 4 * 16},
6, 6,
{{"LOW", encoder_dial_sensitivity::DIAL_SENSITIVITY_LOW}, {{"LOW", encoder_dial_sensitivity::DIAL_SENSITIVITY_LOW},
{"NORMAL", encoder_dial_sensitivity::DIAL_SENSITIVITY_NORMAL}, {"NORMAL", encoder_dial_sensitivity::DIAL_SENSITIVITY_NORMAL},
@ -509,34 +537,32 @@ class SetPersistentMemoryView : public View {
std::string title() const override { return "P.Mem Mgmt"; }; std::string title() const override { return "P.Mem Mgmt"; };
private: private:
Text text_pmem_about{ Labels labels{
{0, 1 * 16, 240, 16}, {{1 * 8, 1 * 16}, "Save persistent memory on SD", Color::light_grey()},
"Persistent Memory from/to SD"}; {{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_informations{ };
{0, 2 * 16, 240, 16},
"use: when no/dead coin bat."};
Text text_pmem_status{ Text text_pmem_status{
{0, 3 * 16, 240, 16}, {1 * 8, 4 * 16 + 8, 28 * 8, 16},
""}; ""};
Checkbox check_use_sdcard_for_pmem{ Checkbox check_use_sdcard_for_pmem{
{18, 6 * 16}, {2 * 8, 6 * 16},
19, 21,
"use sdcard for p.mem"}; "Use SD card for P.Mem"};
Button button_save_mem_to_file{ Button button_save_mem_to_file{
{0, 8 * 16, 240, 32}, {1 * 8, 8 * 16, 28 * 8, 2 * 16},
"save p.mem to sdcard"}; "Save P.Mem to SD card"};
Button button_load_mem_from_file{ Button button_load_mem_from_file{
{0, 10 * 16 + 4, 240, 32}, {1 * 8, 10 * 16 + 2, 28 * 8, 2 * 16},
"load p.mem from sdcard"}; "Load P.Mem from SD Card"};
Button button_load_mem_defaults{ Button button_load_mem_defaults{
{0, 12 * 16 + 8, 240, 32}, {1 * 8, 12 * 16 + 4, 28 * 8, 2 * 16},
"! reset p.mem, load defaults !"}; "Reset P.Mem to defaults"};
Button button_return{ Button button_return{
{16 * 8, 16 * 16, 12 * 8, 32}, {16 * 8, 16 * 16, 12 * 8, 32},

View File

@ -66,7 +66,7 @@ SondeView::SondeView(NavigationView& nav)
&button_see_qr, &button_see_qr,
&button_see_map}); &button_see_map});
if (!settings_.loaded()) if (!settings_.radio_loaded())
field_frequency.set_value(initial_target_frequency); field_frequency.set_value(initial_target_frequency);
field_frequency.set_step(500); // euquiq: was 10000, but we are using this for fine-tunning field_frequency.set_step(500); // euquiq: was 10000, but we are using this for fine-tunning

View File

@ -189,7 +189,16 @@ void kill_afsk() {
send_message(&message); 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{ const AudioTXConfigMessage message{
divider, divider,
deviation_hz, deviation_hz,