diff --git a/firmware/application/app_settings.cpp b/firmware/application/app_settings.cpp index 1e1870f19..058c668b0 100644 --- a/firmware/application/app_settings.cpp +++ b/firmware/application/app_settings.cpp @@ -26,86 +26,232 @@ #include "file.hpp" #include "portapack.hpp" #include "portapack_persistent_memory.hpp" -#include +#include "utility.hpp" + #include +#include +#include -namespace std { +namespace fs = std::filesystem; +using namespace portapack; +using namespace std::literals; -int app_settings::load(std::string application, AppSettings* settings) { - if (portapack::persistent_memory::load_app_settings()) { - file_path = folder + "/" + application + ".ini"; - - auto error = settings_file.open(file_path); - if (!error.is_valid()) { - auto error = settings_file.read(file_content, std::min((int)settings_file.size(), MAX_FILE_CONTENT_SIZE)); - - settings->baseband_bandwidth = std::app_settings::read_long_long(file_content, "baseband_bandwidth="); - settings->channel_bandwidth = std::app_settings::read_long_long(file_content, "channel_bandwidth="); - settings->lna = std::app_settings::read_long_long(file_content, "lna="); - settings->modulation = std::app_settings::read_long_long(file_content, "modulation="); - settings->rx_amp = std::app_settings::read_long_long(file_content, "rx_amp="); - settings->rx_frequency = std::app_settings::read_long_long(file_content, "rx_frequency="); - settings->sampling_rate = std::app_settings::read_long_long(file_content, "sampling_rate="); - settings->vga = std::app_settings::read_long_long(file_content, "vga="); - settings->tx_amp = std::app_settings::read_long_long(file_content, "tx_amp="); - settings->tx_frequency = std::app_settings::read_long_long(file_content, "tx_frequency="); - settings->tx_gain = std::app_settings::read_long_long(file_content, "tx_gain="); - settings->step = std::app_settings::read_long_long(file_content, "step="); - settings->modulation = std::app_settings::read_long_long(file_content, "modulation="); - settings->am_config_index = std::app_settings::read_long_long(file_content, "am_config_index="); - settings->nbfm_config_index = std::app_settings::read_long_long(file_content, "nbfm_config_index="); - settings->wfm_config_index = std::app_settings::read_long_long(file_content, "wfm_config_index="); - settings->squelch = std::app_settings::read_long_long(file_content, "squelch="); - - rc = SETTINGS_OK; - } else - rc = SETTINGS_UNABLE_TO_LOAD; - } else - rc = SETTINGS_DISABLED; - return (rc); -} - -int app_settings::save(std::string application, AppSettings* settings) { - if (portapack::persistent_memory::save_app_settings()) { - file_path = folder + "/" + application + ".ini"; - make_new_directory(folder); - - auto error = settings_file.create(file_path); - if (!error.is_valid()) { - // Save common setting - settings_file.write_line("baseband_bandwidth=" + to_string_dec_uint(portapack::receiver_model.baseband_bandwidth())); - settings_file.write_line("channel_bandwidth=" + to_string_dec_uint(portapack::transmitter_model.channel_bandwidth())); - settings_file.write_line("lna=" + to_string_dec_uint(portapack::receiver_model.lna())); - settings_file.write_line("rx_amp=" + to_string_dec_uint(portapack::receiver_model.rf_amp())); - settings_file.write_line("sampling_rate=" + to_string_dec_uint(portapack::receiver_model.sampling_rate())); - settings_file.write_line("tx_amp=" + to_string_dec_uint(portapack::transmitter_model.rf_amp())); - settings_file.write_line("tx_gain=" + to_string_dec_uint(portapack::transmitter_model.tx_gain())); - settings_file.write_line("vga=" + to_string_dec_uint(portapack::receiver_model.vga())); - // Save other settings from struct - settings_file.write_line("rx_frequency=" + to_string_dec_uint(settings->rx_frequency)); - settings_file.write_line("tx_frequency=" + to_string_dec_uint(settings->tx_frequency)); - settings_file.write_line("step=" + to_string_dec_uint(settings->step)); - settings_file.write_line("modulation=" + to_string_dec_uint(settings->modulation)); - settings_file.write_line("am_config_index=" + to_string_dec_uint(settings->am_config_index)); - settings_file.write_line("nbfm_config_index=" + to_string_dec_uint(settings->nbfm_config_index)); - settings_file.write_line("wfm_config_index=" + to_string_dec_uint(settings->wfm_config_index)); - settings_file.write_line("squelch=" + to_string_dec_uint(settings->squelch)); - - rc = SETTINGS_OK; - } else - rc = SETTINGS_UNABLE_TO_SAVE; - } else - rc = SETTINGS_DISABLED; - return (rc); -} - -long long int app_settings::read_long_long(char* file_content, const char* setting_text) { - auto position = strstr(file_content, (char*)setting_text); - if (position) { - position += strlen((char*)setting_text); - setting_value = strtoll(position, nullptr, 10); +/*#include "log_file.hpp" +LogFile* g_pLog = nullptr; +static void log_it(const std::string& msg) { + static LogFile s_log; + if (g_pLog == nullptr) { + delete_file("appset.txt"); + s_log.append("appset.txt"); + g_pLog = &s_log; + } + + g_pLog->write_entry(msg); +}*/ + +namespace app_settings { + +template +static void read_setting( + std::string_view file_content, + std::string_view setting_name, + T& value) { + auto pos = file_content.find(setting_name); + + if (pos != file_content.npos) { + pos += setting_name.length(); + value = strtoll(&file_content[pos], nullptr, 10); } - return (setting_value); } -} /* namespace std */ +template +static void write_setting(File& file, std::string_view setting_name, const T& value) { + file.write_line(std::string{setting_name} + to_string_dec_uint(value)); +} + +static fs::path get_settings_path(const std::string& app_name) { + return fs::path{u"/SETTINGS"} / app_name + u".ini"; +} + +namespace setting { +constexpr std::string_view baseband_bandwidth = "baseband_bandwidth="sv; +constexpr std::string_view sampling_rate = "sampling_rate="sv; +constexpr std::string_view lna = "lna="sv; +constexpr std::string_view vga = "vga="sv; +constexpr std::string_view rx_amp = "rx_amp="sv; +constexpr std::string_view tx_amp = "tx_amp="sv; +constexpr std::string_view tx_gain = "tx_gain="sv; +constexpr std::string_view channel_bandwidth = "channel_bandwidth="sv; +constexpr std::string_view rx_frequency = "rx_frequency="sv; +constexpr std::string_view tx_frequency = "tx_frequency="sv; +constexpr std::string_view step = "step="sv; +constexpr std::string_view modulation = "modulation="sv; +constexpr std::string_view am_config_index = "am_config_index="sv; +constexpr std::string_view nbfm_config_index = "nbfm_config_index="sv; +constexpr std::string_view wfm_config_index = "wfm_config_index="sv; +constexpr std::string_view squelch = "squelch="sv; +constexpr std::string_view volume = "volume="sv; +} // namespace setting + +// TODO: Only load/save values that are declared used. +// This will prevent switching apps from changing setting unnecessarily. +// TODO: Track which values are actually read. +// TODO: Maybe just use a dictionary which would allow for custom settings. +// TODO: Create a control value binding which will allow controls to +// be declaratively bound to a setting and persistence will be magic. +// TODO: radio settings should be pushed and popped to prevent cross-app +// radio bugs caused by sharing a global model. +// TODO: save is slow because of all of the allocations for File.write_line. + +ResultCode load_settings(const std::string& app_name, AppSettings& settings) { + if (!portapack::persistent_memory::load_app_settings()) + return ResultCode::SettingsDisabled; + + auto file_path = get_settings_path(app_name); + auto data = File::read_file(file_path); + + if (!data) + return ResultCode::LoadFailed; + + if (flags_enabled(settings.mode, Mode::TX)) { + read_setting(*data, setting::tx_frequency, settings.tx_frequency); + read_setting(*data, setting::tx_amp, settings.tx_amp); + read_setting(*data, setting::tx_gain, settings.tx_gain); + read_setting(*data, setting::channel_bandwidth, settings.channel_bandwidth); + } + + if (flags_enabled(settings.mode, Mode::RX)) { + read_setting(*data, setting::rx_frequency, settings.rx_frequency); + read_setting(*data, setting::rx_amp, settings.rx_amp); + read_setting(*data, setting::modulation, settings.modulation); + read_setting(*data, setting::am_config_index, settings.am_config_index); + read_setting(*data, setting::nbfm_config_index, settings.nbfm_config_index); + read_setting(*data, setting::wfm_config_index, settings.wfm_config_index); + read_setting(*data, setting::squelch, settings.squelch); + } + + read_setting(*data, setting::baseband_bandwidth, settings.baseband_bandwidth); + read_setting(*data, setting::sampling_rate, settings.sampling_rate); + read_setting(*data, setting::lna, settings.lna); + read_setting(*data, setting::vga, settings.vga); + read_setting(*data, setting::step, settings.step); + read_setting(*data, setting::volume, settings.volume); + + return ResultCode::Ok; +} + +ResultCode save_settings(const std::string& app_name, AppSettings& settings) { + if (!portapack::persistent_memory::save_app_settings()) + return ResultCode::SettingsDisabled; + + File settings_file; + auto file_path = get_settings_path(app_name); + ensure_directory(file_path.parent_path()); + + auto error = settings_file.create(file_path); + if (error) + return ResultCode::SaveFailed; + + if (flags_enabled(settings.mode, Mode::TX)) { + write_setting(settings_file, setting::tx_frequency, settings.tx_frequency); + write_setting(settings_file, setting::tx_amp, settings.tx_amp); + write_setting(settings_file, setting::tx_gain, settings.tx_gain); + write_setting(settings_file, setting::channel_bandwidth, settings.channel_bandwidth); + } + + if (flags_enabled(settings.mode, Mode::RX)) { + write_setting(settings_file, setting::rx_frequency, settings.rx_frequency); + write_setting(settings_file, setting::rx_amp, settings.rx_amp); + write_setting(settings_file, setting::modulation, settings.modulation); + write_setting(settings_file, setting::am_config_index, settings.am_config_index); + write_setting(settings_file, setting::nbfm_config_index, settings.nbfm_config_index); + write_setting(settings_file, setting::wfm_config_index, settings.wfm_config_index); + write_setting(settings_file, setting::squelch, settings.squelch); + } + + write_setting(settings_file, setting::baseband_bandwidth, settings.baseband_bandwidth); + write_setting(settings_file, setting::sampling_rate, settings.sampling_rate); + write_setting(settings_file, setting::lna, settings.lna); + write_setting(settings_file, setting::vga, settings.vga); + write_setting(settings_file, setting::step, settings.step); + write_setting(settings_file, setting::volume, settings.volume); + + return ResultCode::Ok; +} + +void copy_to_radio_model(const AppSettings& settings) { + // NB: Don't actually adjust the radio here or it will hang. + + if (flags_enabled(settings.mode, Mode::TX)) + transmitter_model.configure_from_app_settings(settings); + + if (flags_enabled(settings.mode, Mode::RX)) { + receiver_model.configure_from_app_settings(settings); + receiver_model.set_configuration_without_init( + static_cast(settings.modulation), + settings.step, + settings.am_config_index, + settings.nbfm_config_index, + settings.wfm_config_index, + settings.squelch); + } + + receiver_model.set_frequency_step(settings.volume); + receiver_model.set_normalized_headphone_volume(settings.volume); +} + +void copy_from_radio_model(AppSettings& settings) { + if (flags_enabled(settings.mode, Mode::TX)) { + settings.tx_frequency = transmitter_model.target_frequency(); + settings.baseband_bandwidth = transmitter_model.baseband_bandwidth(); + settings.tx_amp = transmitter_model.rf_amp(); + settings.tx_gain = transmitter_model.tx_gain(); + settings.channel_bandwidth = transmitter_model.channel_bandwidth(); + + // TODO: Do these make sense for TX? + settings.sampling_rate = transmitter_model.sampling_rate(); + settings.lna = transmitter_model.lna(); + settings.vga = transmitter_model.vga(); + } + + if (flags_enabled(settings.mode, Mode::RX)) { + settings.rx_frequency = receiver_model.target_frequency(); + settings.baseband_bandwidth = receiver_model.baseband_bandwidth(); + settings.sampling_rate = receiver_model.sampling_rate(); + settings.lna = receiver_model.lna(); + settings.vga = receiver_model.vga(); + settings.rx_amp = receiver_model.rf_amp(); + settings.squelch = receiver_model.squelch_level(); + + settings.modulation = static_cast(receiver_model.modulation()); + settings.am_config_index = receiver_model.am_configuration(); + settings.nbfm_config_index = receiver_model.nbfm_configuration(); + settings.wfm_config_index = receiver_model.wfm_configuration(); + } + + settings.step = receiver_model.frequency_step(); + settings.volume = receiver_model.normalized_headphone_volume(); +} + +/* SettingsManager *************************************************/ +SettingsManager::SettingsManager(std::string app_name, Mode mode) + : app_name_{std::move(app_name)}, + settings_{}, + loaded_{false} { + settings_.mode = mode; + auto result = load_settings(app_name_, settings_); + + if (result == ResultCode::Ok) { + 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_, settings_); + } +} + +} // namespace app_settings diff --git a/firmware/application/app_settings.hpp b/firmware/application/app_settings.hpp index a620600ef..bf03af972 100644 --- a/firmware/application/app_settings.hpp +++ b/firmware/application/app_settings.hpp @@ -27,53 +27,83 @@ #include #include #include +#include #include "file.hpp" #include "string_format.hpp" -namespace std { -class app_settings { +namespace app_settings { + +enum class ResultCode : uint8_t { + Ok, // settings found + LoadFailed, // settings (file) not found + SaveFailed, // unable to save settings + SettingsDisabled, // load/save disabled in settings +}; + +enum class Mode : uint8_t { + RX = 0x01, + TX = 0x02, + RX_TX = 0x03, // Both TX/RX +}; + +// TODO: separate types for TX/RX or union? +struct AppSettings { + Mode mode; + uint32_t baseband_bandwidth; + uint32_t sampling_rate; + uint8_t lna; + uint8_t vga; + uint8_t rx_amp; + uint8_t tx_amp; + uint8_t tx_gain; + uint32_t channel_bandwidth; + uint32_t rx_frequency; + uint32_t tx_frequency; + uint32_t step; + uint8_t modulation; + uint8_t am_config_index; + uint8_t nbfm_config_index; + uint8_t wfm_config_index; + uint8_t squelch; + + uint8_t volume; +}; + +ResultCode load_settings(const std::string& app_name, AppSettings& settings); +ResultCode save_settings(const std::string& app_name, AppSettings& settings); + +/* Copies common values to the receiver/transmitter models. */ +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 settings for an app. + * 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 { public: -#define SETTINGS_OK 0 // settings found -#define SETTINGS_UNABLE_TO_LOAD -1 // settings (file) not found -#define SETTINGS_UNABLE_TO_SAVE -2 // unable to save settings -#define SETTINGS_DISABLED -3 // load/save settings disabled in settings + SettingsManager(std::string app_name, Mode mode); + ~SettingsManager(); - struct AppSettings { - uint32_t baseband_bandwidth; - uint32_t channel_bandwidth; - uint8_t lna; - uint8_t modulation; - uint8_t rx_amp; - uint32_t rx_frequency; - uint32_t sampling_rate; - uint8_t tx_amp; - uint32_t tx_frequency; - uint8_t tx_gain; - uint8_t vga; - uint32_t step; - uint8_t am_config_index; - uint8_t nbfm_config_index; - uint8_t wfm_config_index; - uint8_t squelch; - }; + SettingsManager(const SettingsManager&) = delete; + SettingsManager& operator=(const SettingsManager&) = delete; + SettingsManager(SettingsManager&&) = delete; + SettingsManager& operator=(SettingsManager&&) = delete; - int load(std::string application, AppSettings* settings); - int save(std::string application, AppSettings* settings); + /* True if settings were successfully loaded from file. */ + bool loaded() const { return loaded_; } + Mode mode() const { return settings_.mode; } + + AppSettings& raw() { return settings_; } private: -#define MAX_FILE_CONTENT_SIZE 1000 + std::string app_name_; + AppSettings settings_; + bool loaded_; +}; - char file_content[MAX_FILE_CONTENT_SIZE] = {}; - std::string file_path = ""; - std::string folder = "SETTINGS"; - int rc = SETTINGS_OK; - File settings_file{}; - long long int setting_value{}; - - long long int read_long_long(char* file_content, const char* setting_text); - -}; // class app_settings -} // namespace std +} // namespace app_settings #endif /*__APP_SETTINGS_H__*/ diff --git a/firmware/application/apps/acars_app.cpp b/firmware/application/apps/acars_app.cpp index d69dccb4b..6ac83a65d 100644 --- a/firmware/application/apps/acars_app.cpp +++ b/firmware/application/apps/acars_app.cpp @@ -55,11 +55,6 @@ void ACARSLogger::log_raw_data(const acars::Packet& packet, const uint32_t frequ namespace ui { -void ACARSAppView::update_freq(rf::Frequency f) { - set_target_frequency(f); - portapack::persistent_memory::set_tuned_frequency(f); // Maybe not ? -} - ACARSAppView::ACARSAppView(NavigationView& nav) { baseband::run_image(portapack::spi_flash::image_tag_acars); @@ -76,17 +71,15 @@ ACARSAppView::ACARSAppView(NavigationView& nav) { receiver_model.set_baseband_bandwidth(1750000); receiver_model.enable(); - field_frequency.set_value(receiver_model.tuning_frequency()); - update_freq(receiver_model.tuning_frequency()); + field_frequency.set_value(receiver_model.target_frequency()); field_frequency.set_step(receiver_model.frequency_step()); field_frequency.on_change = [this](rf::Frequency f) { - update_freq(f); + receiver_model.set_target_frequency(f); }; field_frequency.on_edit = [this, &nav]() { // TODO: Provide separate modal method/scheme? - auto new_view = nav.push(receiver_model.tuning_frequency()); + auto new_view = nav.push(receiver_model.target_frequency()); new_view->on_changed = [this](rf::Frequency f) { - update_freq(f); field_frequency.set_value(f); }; }; @@ -132,16 +125,7 @@ void ACARSAppView::on_packet(const acars::Packet& packet) { // Log raw data whatever it contains if (logger && logging) - logger->log_raw_data(packet, target_frequency()); -} - -void ACARSAppView::set_target_frequency(const uint32_t new_value) { - target_frequency_ = new_value; - receiver_model.set_tuning_frequency(new_value); -} - -uint32_t ACARSAppView::target_frequency() const { - return target_frequency_; + logger->log_raw_data(packet, receiver_model.target_frequency()); } } /* namespace ui */ diff --git a/firmware/application/apps/acars_app.hpp b/firmware/application/apps/acars_app.hpp index 2075f4c46..fc597d4bf 100644 --- a/firmware/application/apps/acars_app.hpp +++ b/firmware/application/apps/acars_app.hpp @@ -23,10 +23,10 @@ #ifndef __ACARS_APP_H__ #define __ACARS_APP_H__ +#include "app_settings.hpp" #include "ui_widget.hpp" #include "ui_receiver.hpp" #include "ui_rssi.hpp" - #include "log_file.hpp" #include "acars_packet.hpp" @@ -56,6 +56,9 @@ class ACARSAppView : public View { std::string title() const override { return "ACARS (WIP)"; }; private: + app_settings::SettingsManager settings_{ + "rx_acars.hpp", app_settings::Mode::RX}; + bool logging{false}; uint32_t packet_counter{0}; @@ -86,15 +89,8 @@ class ACARSAppView : public View { std::unique_ptr logger{}; - uint32_t target_frequency_{}; - - void update_freq(rf::Frequency f); - void on_packet(const acars::Packet& packet); - uint32_t target_frequency() const; - void set_target_frequency(const uint32_t new_value); - MessageHandlerRegistration message_handler_packet{ Message::ID::ACARSPacket, [this](Message* const p) { diff --git a/firmware/application/apps/ais_app.cpp b/firmware/application/apps/ais_app.cpp index 4e18d5fd6..cc5130476 100644 --- a/firmware/application/apps/ais_app.cpp +++ b/firmware/application/apps/ais_app.cpp @@ -283,8 +283,8 @@ AISRecentEntryDetailView::AISRecentEntryDetailView(NavigationView& nav) { }); button_done.on_select = [this](const ui::Button&) { - if (this->on_close) { - this->on_close(); + if (on_close) { + on_close(); } }; @@ -380,33 +380,25 @@ AISAppView::AISAppView(NavigationView& nav) &recent_entry_detail_view, }); - // load app settings - auto rc = settings.load("rx_ais", &app_settings); - if (rc == SETTINGS_OK) { - field_lna.set_value(app_settings.lna); - field_vga.set_value(app_settings.vga); - field_rf_amp.set_value(app_settings.rx_amp); - target_frequency_ = app_settings.rx_frequency; - } else - target_frequency_ = initial_target_frequency; - recent_entry_detail_view.hidden(true); - receiver_model.set_tuning_frequency(tuning_frequency()); + if (!settings_.loaded()) + receiver_model.set_target_frequency(initial_target_frequency); + receiver_model.set_sampling_rate(sampling_rate); receiver_model.set_baseband_bandwidth(baseband_bandwidth); receiver_model.enable(); options_channel.on_change = [this](size_t, OptionsField::value_t v) { - this->on_frequency_changed(v); + receiver_model.set_target_frequency(v); }; - options_channel.set_by_value(target_frequency()); + options_channel.set_by_value(receiver_model.target_frequency()); recent_entries_view.on_select = [this](const AISRecentEntry& entry) { - this->on_show_detail(entry); + on_show_detail(entry); }; recent_entry_detail_view.on_close = [this]() { - this->on_show_list(); + on_show_list(); }; logger = std::make_unique(); @@ -416,12 +408,7 @@ AISAppView::AISAppView(NavigationView& nav) } AISAppView::~AISAppView() { - // save app settings - app_settings.rx_frequency = target_frequency_; - settings.save("rx_ais", &app_settings); - receiver_model.disable(); - baseband::shutdown(); } @@ -465,21 +452,4 @@ void AISAppView::on_show_detail(const AISRecentEntry& entry) { recent_entry_detail_view.focus(); } -void AISAppView::on_frequency_changed(const uint32_t new_target_frequency) { - set_target_frequency(new_target_frequency); -} - -void AISAppView::set_target_frequency(const uint32_t new_value) { - target_frequency_ = new_value; - receiver_model.set_tuning_frequency(tuning_frequency()); -} - -uint32_t AISAppView::target_frequency() const { - return target_frequency_; -} - -uint32_t AISAppView::tuning_frequency() const { - return target_frequency() - (sampling_rate / 4); -} - } /* namespace ui */ diff --git a/firmware/application/apps/ais_app.hpp b/firmware/application/apps/ais_app.hpp index 8b119f641..8d8e10493 100644 --- a/firmware/application/apps/ais_app.hpp +++ b/firmware/application/apps/ais_app.hpp @@ -154,9 +154,6 @@ class AISAppView : public View { ~AISAppView(); void set_parent_rect(const Rect new_parent_rect) override; - - // Prevent painting of region covered entirely by a child. - // TODO: Add flag to View that specifies view does not need to be cleared before painting. void paint(Painter&) override{}; void focus() override; @@ -168,9 +165,8 @@ class AISAppView : public View { static constexpr uint32_t sampling_rate = 2457600; static constexpr uint32_t baseband_bandwidth = 1750000; - // app save settings - std::app_settings settings{}; - std::app_settings::AppSettings app_settings{}; + app_settings::SettingsManager settings_{ + "rx_ais", app_settings::Mode::RX}; NavigationView& nav_; @@ -225,18 +221,9 @@ class AISAppView : public View { } }}; - uint32_t target_frequency_ = initial_target_frequency; - void on_packet(const ais::Packet& packet); void on_show_list(); void on_show_detail(const AISRecentEntry& entry); - - void on_frequency_changed(const uint32_t new_target_frequency); - - uint32_t target_frequency() const; - void set_target_frequency(const uint32_t new_value); - - uint32_t tuning_frequency() const; }; } /* namespace ui */ diff --git a/firmware/application/apps/analog_audio_app.cpp b/firmware/application/apps/analog_audio_app.cpp index 82224a454..879f96048 100644 --- a/firmware/application/apps/analog_audio_app.cpp +++ b/firmware/application/apps/analog_audio_app.cpp @@ -149,32 +149,19 @@ AnalogAudioView::AnalogAudioView( &record_view, &waterfall}); - // Set on_change before initialising the field - field_frequency.on_change = [this](rf::Frequency f) { - this->on_tuning_frequency_changed(f); - }; - - // load app settings - auto rc = settings.load("rx_audio", &app_settings); - if (rc == SETTINGS_OK) { - field_lna.set_value(app_settings.lna); - field_vga.set_value(app_settings.vga); - receiver_model.set_rf_amp(app_settings.rx_amp); - // field_frequency.set_value(app_settings.rx_frequency); - receiver_model.set_configuration_without_init(static_cast(app_settings.modulation), app_settings.step, app_settings.am_config_index, app_settings.nbfm_config_index, app_settings.wfm_config_index, app_settings.squelch); - } - field_frequency.set_value(receiver_model.tuning_frequency()); - // Filename Datetime and Frequency record_view.set_filename_date_frequency(true); + field_frequency.set_value(receiver_model.target_frequency()); + field_frequency.on_change = [this](rf::Frequency f) { + receiver_model.set_target_frequency(f); + }; field_frequency.set_step(receiver_model.frequency_step()); field_frequency.on_edit = [this, &nav]() { // TODO: Provide separate modal method/scheme? - auto new_view = nav.push(receiver_model.tuning_frequency()); + auto new_view = nav.push(receiver_model.target_frequency()); new_view->on_changed = [this](rf::Frequency f) { - this->on_tuning_frequency_changed(f); - this->field_frequency.set_value(f); + field_frequency.set_value(f); }; }; @@ -205,7 +192,7 @@ AnalogAudioView::AnalogAudioView( }; waterfall.on_select = [this](int32_t offset) { - field_frequency.set_value(receiver_model.tuning_frequency() + offset); + field_frequency.set_value(receiver_model.target_frequency() + offset); }; audio::output::start(); @@ -238,18 +225,18 @@ void AnalogAudioView::set_spec_trigger(uint16_t trigger) { } AnalogAudioView::~AnalogAudioView() { - // save app settings - app_settings.rx_frequency = field_frequency.value(); - app_settings.lna = receiver_model.lna(); - app_settings.vga = receiver_model.vga(); - app_settings.rx_amp = receiver_model.rf_amp(); - app_settings.step = receiver_model.frequency_step(); - app_settings.modulation = (uint8_t)receiver_model.modulation(); - app_settings.am_config_index = receiver_model.am_configuration(); - app_settings.nbfm_config_index = receiver_model.nbfm_configuration(); - app_settings.wfm_config_index = receiver_model.wfm_configuration(); - app_settings.squelch = receiver_model.squelch_level(); - settings.save("rx_audio", &app_settings); + // // save app settings + // app_settings.rx_frequency = field_frequency.value(); + // app_settings.lna = receiver_model.lna(); + // app_settings.vga = receiver_model.vga(); + // app_settings.rx_amp = receiver_model.rf_amp(); + // app_settings.step = receiver_model.frequency_step(); + // app_settings.modulation = (uint8_t)receiver_model.modulation(); + // app_settings.am_config_index = receiver_model.am_configuration(); + // app_settings.nbfm_config_index = receiver_model.nbfm_configuration(); + // app_settings.wfm_config_index = receiver_model.wfm_configuration(); + // app_settings.squelch = receiver_model.squelch_level(); + // settings.save("rx_audio", &app_settings); // TODO: Manipulating audio codec here, and in ui_receiver.cpp. Good to do // both? @@ -279,10 +266,6 @@ void AnalogAudioView::focus() { field_frequency.focus(); } -void AnalogAudioView::on_tuning_frequency_changed(rf::Frequency f) { - receiver_model.set_tuning_frequency(f); -} - void AnalogAudioView::on_baseband_bandwidth_changed(uint32_t bandwidth_hz) { receiver_model.set_baseband_bandwidth(bandwidth_hz); } diff --git a/firmware/application/apps/analog_audio_app.hpp b/firmware/application/apps/analog_audio_app.hpp index f5c2de6a0..f20944dcd 100644 --- a/firmware/application/apps/analog_audio_app.hpp +++ b/firmware/application/apps/analog_audio_app.hpp @@ -155,9 +155,8 @@ class AnalogAudioView : public View { private: static constexpr ui::Dim header_height = 3 * 16; - // app save settings - std::app_settings settings{}; - std::app_settings::AppSettings app_settings{}; + app_settings::SettingsManager settings_{ + "rx_audio", app_settings::Mode::RX}; const Rect options_view_rect{0 * 8, 1 * 16, 30 * 8, 1 * 16}; const Rect nbfm_view_rect{0 * 8, 1 * 16, 18 * 8, 1 * 16}; @@ -220,7 +219,6 @@ class AnalogAudioView : public View { spectrum::WaterfallWidget waterfall{true}; - void on_tuning_frequency_changed(rf::Frequency f); void on_baseband_bandwidth_changed(uint32_t bandwidth_hz); void on_modulation_changed(const ReceiverModel::Mode modulation); void on_show_options_frequency(); diff --git a/firmware/application/apps/analog_tv_app.cpp b/firmware/application/apps/analog_tv_app.cpp index 918644120..9ed6b5bce 100644 --- a/firmware/application/apps/analog_tv_app.cpp +++ b/firmware/application/apps/analog_tv_app.cpp @@ -58,25 +58,16 @@ AnalogTvView::AnalogTvView( // Set on_change before initialising the field field_frequency.on_change = [this](rf::Frequency f) { - this->on_tuning_frequency_changed(f); + this->on_target_frequency_changed(f); }; - // load app settings - auto rc = settings.load("rx_tv", &app_settings); - if (rc == SETTINGS_OK) { - field_lna.set_value(app_settings.lna); - field_vga.set_value(app_settings.vga); - receiver_model.set_rf_amp(app_settings.rx_amp); - field_frequency.set_value(app_settings.rx_frequency); - } else - field_frequency.set_value(receiver_model.tuning_frequency()); - + field_frequency.set_value(receiver_model.target_frequency()); field_frequency.set_step(receiver_model.frequency_step()); field_frequency.on_edit = [this, &nav]() { // TODO: Provide separate modal method/scheme? - auto new_view = nav.push(receiver_model.tuning_frequency()); + auto new_view = nav.push(receiver_model.target_frequency()); new_view->on_changed = [this](rf::Frequency f) { - this->on_tuning_frequency_changed(f); + this->on_target_frequency_changed(f); this->field_frequency.set_value(f); }; }; @@ -103,7 +94,7 @@ AnalogTvView::AnalogTvView( }; tv.on_select = [this](int32_t offset) { - field_frequency.set_value(receiver_model.tuning_frequency() + offset); + field_frequency.set_value(receiver_model.target_frequency() + offset); }; update_modulation(static_cast(modulation)); @@ -111,12 +102,6 @@ AnalogTvView::AnalogTvView( } AnalogTvView::~AnalogTvView() { - // save app settings - app_settings.rx_frequency = field_frequency.value(); - settings.save("rx_tv", &app_settings); - - // TODO: Manipulating audio codec here, and in ui_receiver.cpp. Good to do - // both? audio::output::stop(); receiver_model.disable(); baseband::shutdown(); @@ -140,8 +125,8 @@ void AnalogTvView::focus() { field_frequency.focus(); } -void AnalogTvView::on_tuning_frequency_changed(rf::Frequency f) { - receiver_model.set_tuning_frequency(f); +void AnalogTvView::on_target_frequency_changed(rf::Frequency f) { + receiver_model.set_target_frequency(f); } void AnalogTvView::on_baseband_bandwidth_changed(uint32_t bandwidth_hz) { diff --git a/firmware/application/apps/analog_tv_app.hpp b/firmware/application/apps/analog_tv_app.hpp index 7a0a63d8f..79b11302d 100644 --- a/firmware/application/apps/analog_tv_app.hpp +++ b/firmware/application/apps/analog_tv_app.hpp @@ -52,9 +52,8 @@ class AnalogTvView : public View { private: static constexpr ui::Dim header_height = 3 * 16; - // app save settings - std::app_settings settings{}; - std::app_settings::AppSettings app_settings{}; + app_settings::SettingsManager settings_{ + "rx_tv", app_settings::Mode::RX}; const Rect options_view_rect{0 * 8, 1 * 16, 30 * 8, 1 * 16}; const Rect nbfm_view_rect{0 * 8, 1 * 16, 18 * 8, 1 * 16}; @@ -99,7 +98,7 @@ class AnalogTvView : public View { tv::TVWidget tv{}; - void on_tuning_frequency_changed(rf::Frequency f); + void on_target_frequency_changed(rf::Frequency f); void on_baseband_bandwidth_changed(uint32_t bandwidth_hz); void on_modulation_changed(const ReceiverModel::Mode modulation); void on_show_options_frequency(); diff --git a/firmware/application/apps/capture_app.cpp b/firmware/application/apps/capture_app.cpp index 24ac2d54a..537825488 100644 --- a/firmware/application/apps/capture_app.cpp +++ b/firmware/application/apps/capture_app.cpp @@ -52,16 +52,16 @@ CaptureAppView::CaptureAppView(NavigationView& nav) { receiver_model.set_baseband_bandwidth(1750000); //------------------- - field_frequency.set_value(receiver_model.tuning_frequency()); + field_frequency.set_value(receiver_model.target_frequency()); field_frequency.set_step(receiver_model.frequency_step()); field_frequency.on_change = [this](rf::Frequency f) { - this->on_tuning_frequency_changed(f); + this->on_target_frequency_changed(f); }; field_frequency.on_edit = [this, &nav]() { // TODO: Provide separate modal method/scheme? - auto new_view = nav.push(receiver_model.tuning_frequency()); + auto new_view = nav.push(receiver_model.target_frequency()); new_view->on_changed = [this](rf::Frequency f) { - this->on_tuning_frequency_changed(f); + this->on_target_frequency_changed(f); this->field_frequency.set_value(f); }; }; @@ -162,8 +162,8 @@ void CaptureAppView::focus() { record_view.focus(); } -void CaptureAppView::on_tuning_frequency_changed(rf::Frequency f) { - receiver_model.set_tuning_frequency(f); +void CaptureAppView::on_target_frequency_changed(rf::Frequency f) { + receiver_model.set_target_frequency(f); } } /* namespace ui */ diff --git a/firmware/application/apps/capture_app.hpp b/firmware/application/apps/capture_app.hpp index 8dab7dffe..8f43d7354 100644 --- a/firmware/application/apps/capture_app.hpp +++ b/firmware/application/apps/capture_app.hpp @@ -67,7 +67,7 @@ class CaptureAppView : public View { uint32_t sampling_rate = 0; uint32_t anti_alias_baseband_bandwidth_filter = 2500000; // we rename the previous var , and change type static constexpr to normal var. - void on_tuning_frequency_changed(rf::Frequency f); + void on_target_frequency_changed(rf::Frequency f); Labels labels{ {{0 * 8, 1 * 16}, "Rate:", Color::light_grey()}, diff --git a/firmware/application/apps/ert_app.cpp b/firmware/application/apps/ert_app.cpp index 70a84e06b..ce663a997 100644 --- a/firmware/application/apps/ert_app.cpp +++ b/firmware/application/apps/ert_app.cpp @@ -110,15 +110,7 @@ ERTAppView::ERTAppView(NavigationView&) { &recent_entries_view, }); - // load app settings - auto rc = settings.load("rx_ert", &app_settings); - if (rc == SETTINGS_OK) { - field_lna.set_value(app_settings.lna); - field_vga.set_value(app_settings.vga); - field_rf_amp.set_value(app_settings.rx_amp); - } - - receiver_model.set_tuning_frequency(initial_target_frequency); + receiver_model.set_target_frequency(initial_target_frequency); receiver_model.set_sampling_rate(sampling_rate); receiver_model.set_baseband_bandwidth(baseband_bandwidth); receiver_model.enable(); @@ -130,11 +122,7 @@ ERTAppView::ERTAppView(NavigationView&) { } ERTAppView::~ERTAppView() { - // save app settings - settings.save("rx_ert", &app_settings); - receiver_model.disable(); - baseband::shutdown(); } diff --git a/firmware/application/apps/ert_app.hpp b/firmware/application/apps/ert_app.hpp index 7b9dae938..94a5e84e6 100644 --- a/firmware/application/apps/ert_app.hpp +++ b/firmware/application/apps/ert_app.hpp @@ -129,9 +129,8 @@ class ERTAppView : public View { ERTRecentEntries recent{}; std::unique_ptr logger{}; - // app save settings - std::app_settings settings{}; - std::app_settings::AppSettings app_settings{}; + app_settings::SettingsManager settings_{ + "rx_ert", app_settings::Mode::RX}; const RecentEntriesColumns columns{{ {"ID", 10}, diff --git a/firmware/application/apps/gps_sim_app.cpp b/firmware/application/apps/gps_sim_app.cpp index d7a905e4a..60347d7ca 100644 --- a/firmware/application/apps/gps_sim_app.cpp +++ b/firmware/application/apps/gps_sim_app.cpp @@ -183,28 +183,25 @@ GpsSimAppView::GpsSimAppView( &text_duration, &progressbar, &field_frequency, - &tx_view, // now it handles previous rfgain , rfamp. + &tx_view, // now it handles previous rfgain, rfamp. &check_loop, &button_play, &waterfall, }); - field_frequency.set_value(target_frequency()); - field_frequency.set_step(receiver_model.frequency_step()); + field_frequency.set_value(transmitter_model.target_frequency()); + field_frequency.set_step(5000); field_frequency.on_change = [this](rf::Frequency f) { - this->on_target_frequency_changed(f); + transmitter_model.set_target_frequency(f); }; field_frequency.on_edit = [this, &nav]() { // TODO: Provide separate modal method/scheme? - auto new_view = nav.push(this->target_frequency()); + auto new_view = nav.push(transmitter_model.target_frequency()); new_view->on_changed = [this](rf::Frequency f) { - this->on_target_frequency_changed(f); this->field_frequency.set_value(f); }; }; - field_frequency.set_step(5000); - button_play.on_select = [this](ImageButton&) { this->toggle(); }; @@ -239,17 +236,4 @@ void GpsSimAppView::set_parent_rect(const Rect new_parent_rect) { waterfall.set_parent_rect(waterfall_rect); } -void GpsSimAppView::on_target_frequency_changed(rf::Frequency f) { - set_target_frequency(f); -} - -void GpsSimAppView::set_target_frequency(const rf::Frequency new_value) { - persistent_memory::set_tuned_frequency(new_value); - ; -} - -rf::Frequency GpsSimAppView::target_frequency() const { - return persistent_memory::tuned_frequency(); -} - } /* namespace ui */ diff --git a/firmware/application/apps/gps_sim_app.hpp b/firmware/application/apps/gps_sim_app.hpp index 3c4af9240..f800c0626 100644 --- a/firmware/application/apps/gps_sim_app.hpp +++ b/firmware/application/apps/gps_sim_app.hpp @@ -27,15 +27,16 @@ #define SHORT_UI true #define NORMAL_UI false +#include "app_settings.hpp" #include "ui_widget.hpp" #include "ui_navigation.hpp" #include "ui_receiver.hpp" #include "replay_thread.hpp" #include "ui_spectrum.hpp" +#include "ui_transmitter.hpp" #include #include -#include "ui_transmitter.hpp" namespace ui { @@ -52,6 +53,8 @@ class GpsSimAppView : public View { private: NavigationView& nav_; + app_settings::SettingsManager settings_{ + "tx_gps", app_settings::Mode::TX}; static constexpr ui::Dim header_height = 3 * 16; @@ -63,12 +66,8 @@ class GpsSimAppView : public View { const size_t buffer_count{3}; void on_file_changed(std::filesystem::path new_file_path); - void on_target_frequency_changed(rf::Frequency f); void on_tx_progress(const uint32_t progress); - void set_target_frequency(const rf::Frequency new_value); - rf::Frequency target_frequency() const; - void toggle(); void start(); void stop(const bool do_loop); diff --git a/firmware/application/apps/lge_app.cpp b/firmware/application/apps/lge_app.cpp index 62fe0931f..1f2346094 100644 --- a/firmware/application/apps/lge_app.cpp +++ b/firmware/application/apps/lge_app.cpp @@ -44,10 +44,6 @@ void LGEView::focus() { } LGEView::~LGEView() { - // save app settings - app_settings.tx_frequency = transmitter_model.tuning_frequency(); - settings.save("tx_lge", &app_settings); - transmitter_model.disable(); hackrf::cpld::load_sram_no_verify(); // to leave all RX ok, without ghost signal problem at the exit . baseband::shutdown(); // better this function at the end, not load_sram() that sometimes produces hang up. @@ -243,7 +239,7 @@ void LGEView::generate_frame_collier() { void LGEView::start_tx() { if (tx_mode == ALL) { - transmitter_model.set_tuning_frequency(channels[channel_index]); + transmitter_model.set_target_frequency(channels[channel_index]); tx_view.on_show(); // Refresh tuning frequency display tx_view.set_dirty(); } @@ -306,15 +302,6 @@ LGEView::LGEView(NavigationView& nav) { &console, &tx_view}); - // load app settings - auto rc = settings.load("tx_lge", &app_settings); - if (rc == SETTINGS_OK) { - transmitter_model.set_rf_amp(app_settings.tx_amp); - transmitter_model.set_channel_bandwidth(app_settings.channel_bandwidth); - transmitter_model.set_tuning_frequency(app_settings.tx_frequency); - transmitter_model.set_tx_gain(app_settings.tx_gain); - } - field_room.set_value(1); field_team.set_value(1); field_player.set_value(1); @@ -333,9 +320,9 @@ LGEView::LGEView(NavigationView& nav) { }; tx_view.on_edit_frequency = [this, &nav]() { - auto new_view = nav.push(receiver_model.tuning_frequency()); + auto new_view = nav.push(transmitter_model.target_frequency()); new_view->on_changed = [this](rf::Frequency f) { - receiver_model.set_tuning_frequency(f); + transmitter_model.set_target_frequency(f); }; }; diff --git a/firmware/application/apps/lge_app.hpp b/firmware/application/apps/lge_app.hpp index 1520acde8..e6d8c8197 100644 --- a/firmware/application/apps/lge_app.hpp +++ b/firmware/application/apps/lge_app.hpp @@ -49,9 +49,8 @@ class LGEView : public View { ALL }; - // app save settings - std::app_settings settings{}; - std::app_settings::AppSettings app_settings{}; + app_settings::SettingsManager settings_{ + "tx_lge", app_settings::Mode::TX}; tx_modes tx_mode = IDLE; diff --git a/firmware/application/apps/pocsag_app.cpp b/firmware/application/apps/pocsag_app.cpp index 1ae94f2c8..2c7730c62 100644 --- a/firmware/application/apps/pocsag_app.cpp +++ b/firmware/application/apps/pocsag_app.cpp @@ -51,11 +51,6 @@ void POCSAGLogger::log_decoded( namespace ui { -void POCSAGAppView::update_freq(rf::Frequency f) { - set_target_frequency(f); - portapack::persistent_memory::set_tuned_frequency(f); // Maybe not ? -} - POCSAGAppView::POCSAGAppView(NavigationView& nav) { uint32_t ignore_address; @@ -74,36 +69,20 @@ POCSAGAppView::POCSAGAppView(NavigationView& nav) { &sym_ignore, &console}); - // Set on_change before initialising the field - field_frequency.on_change = [this](rf::Frequency f) { - update_freq(f); - }; - - // load app settings TODO: needed? - auto rc = settings.load("rx_pocsag", &app_settings); - if (rc == SETTINGS_OK) { - field_lna.set_value(app_settings.lna); - field_vga.set_value(app_settings.vga); - field_rf_amp.set_value(app_settings.rx_amp); - field_frequency.set_value(app_settings.rx_frequency); - } else { - field_lna.set_value(receiver_model.lna()); - field_vga.set_value(receiver_model.vga()); - field_rf_amp.set_value(receiver_model.rf_amp()); - field_frequency.set_value(receiver_model.tuning_frequency()); - } - receiver_model.set_modulation(ReceiverModel::Mode::NarrowbandFMAudio); receiver_model.set_sampling_rate(3072000); receiver_model.set_baseband_bandwidth(1750000); receiver_model.enable(); + field_frequency.set_value(receiver_model.target_frequency()); + field_frequency.on_change = [this](rf::Frequency f) { + receiver_model.set_target_frequency(f); + }; field_frequency.set_step(receiver_model.frequency_step()); field_frequency.on_edit = [this, &nav]() { // TODO: Provide separate modal method/scheme? - auto new_view = nav.push(receiver_model.tuning_frequency()); + auto new_view = nav.push(receiver_model.target_frequency()); new_view->on_changed = [this](rf::Frequency f) { - update_freq(f); field_frequency.set_value(f); }; }; @@ -127,11 +106,11 @@ POCSAGAppView::POCSAGAppView(NavigationView& nav) { baseband::set_pocsag(); } -POCSAGAppView::~POCSAGAppView() { - // save app settings - app_settings.rx_frequency = field_frequency.value(); - settings.save("rx_pocsag", &app_settings); +void POCSAGAppView::focus() { + check_log.focus(); +} +POCSAGAppView::~POCSAGAppView() { audio::output::stop(); // Save ignored address @@ -205,16 +184,7 @@ void POCSAGAppView::on_packet(const POCSAGPacketMessage* message) { // TODO: make setting. // Log raw data whatever it contains if (logger && logging()) - logger->log_raw_data(message->packet, target_frequency()); -} - -void POCSAGAppView::set_target_frequency(const uint32_t new_value) { - target_frequency_ = new_value; - receiver_model.set_tuning_frequency(new_value); -} - -uint32_t POCSAGAppView::target_frequency() const { - return target_frequency_; + logger->log_raw_data(message->packet, receiver_model.target_frequency()); } } /* namespace ui */ diff --git a/firmware/application/apps/pocsag_app.hpp b/firmware/application/apps/pocsag_app.hpp index 74ebe6560..cf73075f7 100644 --- a/firmware/application/apps/pocsag_app.hpp +++ b/firmware/application/apps/pocsag_app.hpp @@ -53,16 +53,14 @@ class POCSAGAppView : public View { ~POCSAGAppView(); std::string title() const override { return "POCSAG RX"; }; + void focus() override; private: - static constexpr uint32_t initial_target_frequency = 466175000; - bool logging() const { return check_log.value(); }; bool ignore() const { return check_ignore.value(); }; - // app save settings - std::app_settings settings{}; - std::app_settings::AppSettings app_settings{}; + app_settings::SettingsManager settings_{ + "rx_pocsag", app_settings::Mode::RX}; uint32_t last_address = 0xFFFFFFFF; pocsag::POCSAGState pocsag_state{}; @@ -111,15 +109,8 @@ class POCSAGAppView : public View { std::unique_ptr logger{}; - uint32_t target_frequency_ = initial_target_frequency; - - void update_freq(rf::Frequency f); - void on_packet(const POCSAGPacketMessage* message); - uint32_t target_frequency() const; - void set_target_frequency(const uint32_t new_value); - MessageHandlerRegistration message_handler_packet{ Message::ID::POCSAGPacket, [this](Message* const p) { diff --git a/firmware/application/apps/replay_app.cpp b/firmware/application/apps/replay_app.cpp index 9e79a581a..fd77d72fc 100644 --- a/firmware/application/apps/replay_app.cpp +++ b/firmware/application/apps/replay_app.cpp @@ -194,17 +194,16 @@ ReplayAppView::ReplayAppView( &waterfall, }); - field_frequency.set_value(target_frequency()); + field_frequency.set_value(transmitter_model.target_frequency()); field_frequency.set_step(receiver_model.frequency_step()); field_frequency.on_change = [this](rf::Frequency f) { - this->on_target_frequency_changed(f); + transmitter_model.set_target_frequency(f); }; field_frequency.on_edit = [this, &nav]() { // TODO: Provide separate modal method/scheme? - auto new_view = nav.push(this->target_frequency()); + auto new_view = nav.push(transmitter_model.target_frequency()); new_view->on_changed = [this](rf::Frequency f) { - this->on_target_frequency_changed(f); - this->field_frequency.set_value(f); + field_frequency.set_value(f); }; }; @@ -247,16 +246,4 @@ void ReplayAppView::set_parent_rect(const Rect new_parent_rect) { waterfall.set_parent_rect(waterfall_rect); } -void ReplayAppView::on_target_frequency_changed(rf::Frequency f) { - set_target_frequency(f); -} - -void ReplayAppView::set_target_frequency(const rf::Frequency new_value) { - persistent_memory::set_tuned_frequency(new_value); -} - -rf::Frequency ReplayAppView::target_frequency() const { - return persistent_memory::tuned_frequency(); -} - } /* namespace ui */ diff --git a/firmware/application/apps/replay_app.hpp b/firmware/application/apps/replay_app.hpp index c9fa098a0..a99083459 100644 --- a/firmware/application/apps/replay_app.hpp +++ b/firmware/application/apps/replay_app.hpp @@ -26,15 +26,16 @@ #define SHORT_UI true #define NORMAL_UI false +#include "app_settings.hpp" #include "ui_widget.hpp" #include "ui_navigation.hpp" #include "ui_receiver.hpp" #include "replay_thread.hpp" #include "ui_spectrum.hpp" +#include "ui_transmitter.hpp" #include #include -#include "ui_transmitter.hpp" namespace ui { @@ -51,6 +52,8 @@ class ReplayAppView : public View { private: NavigationView& nav_; + app_settings::SettingsManager settings_{ + "tx_replay", app_settings::Mode::TX}; static constexpr ui::Dim header_height = 3 * 16; @@ -62,12 +65,8 @@ class ReplayAppView : public View { const size_t buffer_count{3}; void on_file_changed(std::filesystem::path new_file_path); - void on_target_frequency_changed(rf::Frequency f); void on_tx_progress(const uint32_t progress); - void set_target_frequency(const rf::Frequency new_value); - rf::Frequency target_frequency() const; - void toggle(); void start(); void stop(const bool do_loop); diff --git a/firmware/application/apps/soundboard_app.cpp b/firmware/application/apps/soundboard_app.cpp index 6ece0ce9d..79d569f68 100644 --- a/firmware/application/apps/soundboard_app.cpp +++ b/firmware/application/apps/soundboard_app.cpp @@ -235,15 +235,6 @@ SoundBoardView::SoundBoardView( &button_next_page, &tx_view}); - // load app settings - auto rc = settings.load("tx_soundboard", &app_settings); - if (rc == SETTINGS_OK) { - transmitter_model.set_rf_amp(app_settings.tx_amp); - transmitter_model.set_channel_bandwidth(app_settings.channel_bandwidth); - transmitter_model.set_tuning_frequency(app_settings.tx_frequency); - transmitter_model.set_tx_gain(app_settings.tx_gain); - } - refresh_list(); button_next_page.on_select = [this](Button&) { @@ -266,9 +257,9 @@ SoundBoardView::SoundBoardView( check_random.set_value(false); tx_view.on_edit_frequency = [this, &nav]() { - auto new_view = nav.push(receiver_model.tuning_frequency()); + auto new_view = nav.push(transmitter_model.target_frequency()); new_view->on_changed = [this](rf::Frequency f) { - transmitter_model.set_tuning_frequency(f); + transmitter_model.set_target_frequency(f); }; }; @@ -283,10 +274,6 @@ SoundBoardView::SoundBoardView( } SoundBoardView::~SoundBoardView() { - // save app settings - app_settings.tx_frequency = transmitter_model.tuning_frequency(); - settings.save("tx_soundboard", &app_settings); - stop(); transmitter_model.disable(); hackrf::cpld::load_sram_no_verify(); // to leave all RX ok, without ghost signal problem at the exit. diff --git a/firmware/application/apps/soundboard_app.hpp b/firmware/application/apps/soundboard_app.hpp index b946f80e3..47c4903f3 100644 --- a/firmware/application/apps/soundboard_app.hpp +++ b/firmware/application/apps/soundboard_app.hpp @@ -49,11 +49,10 @@ class SoundBoardView : public View { std::string title() const override { return "Soundbrd TX"; }; private: - NavigationView& nav_; + app_settings::SettingsManager settings_{ + "tx_soundboard", app_settings::Mode::TX}; - // app save settings - std::app_settings settings{}; - std::app_settings::AppSettings app_settings{}; + NavigationView& nav_; enum tx_modes { NORMAL = 0, diff --git a/firmware/application/apps/tpms_app.cpp b/firmware/application/apps/tpms_app.cpp index e026b0e7e..c1af8bc6a 100644 --- a/firmware/application/apps/tpms_app.cpp +++ b/firmware/application/apps/tpms_app.cpp @@ -78,9 +78,9 @@ void TPMSLogger::on_packet(const tpms::Packet& packet, const uint32_t target_fre const auto hex_formatted = packet.symbols_formatted(); // TODO: function doesn't take uint64_t, so when >= 1<<32, weirdness will ensue! - const auto tuning_frequency_str = to_string_dec_uint(target_frequency, 10); + const auto target_frequency_str = to_string_dec_uint(target_frequency, 10); - std::string entry = tuning_frequency_str + " " + tpms::format::signal_type(packet.signal_type()) + " " + hex_formatted.data + "/" + hex_formatted.errors; + std::string entry = target_frequency_str + " " + tpms::format::signal_type(packet.signal_type()) + " " + hex_formatted.data + "/" + hex_formatted.errors; log_file.write_entry(packet.received_at(), entry); } @@ -157,25 +157,17 @@ TPMSAppView::TPMSAppView(NavigationView&) { &field_vga, &recent_entries_view}); - // load app settings - auto rc = settings.load("rx_tpms", &app_settings); - if (rc == SETTINGS_OK) { - field_lna.set_value(app_settings.lna); - field_vga.set_value(app_settings.vga); - field_rf_amp.set_value(app_settings.rx_amp); - options_band.set_by_value(app_settings.rx_frequency); - } else - options_band.set_by_value(receiver_model.tuning_frequency()); + if (!settings_.loaded()) + receiver_model.set_sampling_rate(initial_target_frequency); - receiver_model.set_tuning_frequency(tuning_frequency()); receiver_model.set_sampling_rate(sampling_rate); receiver_model.set_baseband_bandwidth(baseband_bandwidth); receiver_model.enable(); options_band.on_change = [this](size_t, OptionsField::value_t v) { - this->on_band_changed(v); + receiver_model.set_target_frequency(v); }; - options_band.set_by_value(target_frequency()); + options_band.set_by_value(receiver_model.target_frequency()); options_pressure.on_change = [this](size_t, int32_t i) { tpms::format::use_kpa = !i; @@ -198,10 +190,6 @@ TPMSAppView::TPMSAppView(NavigationView&) { } TPMSAppView::~TPMSAppView() { - // save app settings - app_settings.rx_frequency = target_frequency_; - settings.save("rx_tpms", &app_settings); - receiver_model.disable(); baseband::shutdown(); } @@ -224,7 +212,7 @@ void TPMSAppView::set_parent_rect(const Rect new_parent_rect) { void TPMSAppView::on_packet(const tpms::Packet& packet) { if (logger) { - logger->on_packet(packet, target_frequency()); + logger->on_packet(packet, receiver_model.target_frequency()); } const auto reading_opt = packet.reading(); @@ -241,21 +229,4 @@ void TPMSAppView::on_show_list() { recent_entries_view.focus(); } -void TPMSAppView::on_band_changed(const uint32_t new_band_frequency) { - set_target_frequency(new_band_frequency); -} - -void TPMSAppView::set_target_frequency(const uint32_t new_value) { - target_frequency_ = new_value; - receiver_model.set_tuning_frequency(tuning_frequency()); -} - -uint32_t TPMSAppView::target_frequency() const { - return target_frequency_; -} - -uint32_t TPMSAppView::tuning_frequency() const { - return target_frequency() - (sampling_rate / 4); -} - } /* namespace ui */ diff --git a/firmware/application/apps/tpms_app.hpp b/firmware/application/apps/tpms_app.hpp index eef618462..85c171885 100644 --- a/firmware/application/apps/tpms_app.hpp +++ b/firmware/application/apps/tpms_app.hpp @@ -105,9 +105,8 @@ class TPMSAppView : public View { static constexpr uint32_t sampling_rate = 2457600; static constexpr uint32_t baseband_bandwidth = 1750000; - // app save settings - std::app_settings settings{}; - std::app_settings::AppSettings app_settings{}; + app_settings::SettingsManager settings_{ + "rx_tpms", app_settings::Mode::RX}; MessageHandlerRegistration message_handler_packet{ Message::ID::TPMSPacket, @@ -171,18 +170,9 @@ class TPMSAppView : public View { }}; TPMSRecentEntriesView recent_entries_view{columns, recent}; - uint32_t target_frequency_ = initial_target_frequency; - void on_packet(const tpms::Packet& packet); void on_show_list(); void update_view(); - - void on_band_changed(const uint32_t new_band_frequency); - - uint32_t target_frequency() const; - void set_target_frequency(const uint32_t new_value); - - uint32_t tuning_frequency() const; }; } /* namespace ui */ diff --git a/firmware/application/apps/ui_about_demo.cpp b/firmware/application/apps/ui_about_demo.cpp index 94880e494..d02831d55 100644 --- a/firmware/application/apps/ui_about_demo.cpp +++ b/firmware/application/apps/ui_about_demo.cpp @@ -47,7 +47,7 @@ using namespace portapack; namespace ui { void AboutView::on_show() { - transmitter_model.set_tuning_frequency(1337000000); // TODO: Change + transmitter_model.set_target_frequency(1337000000); // TODO: Change transmitter_model.set_baseband_configuration({ .mode = 0, .sampling_rate = 1536000, diff --git a/firmware/application/apps/ui_adsb_rx.cpp b/firmware/application/apps/ui_adsb_rx.cpp index d6240b273..6756da550 100644 --- a/firmware/application/apps/ui_adsb_rx.cpp +++ b/firmware/application/apps/ui_adsb_rx.cpp @@ -288,13 +288,6 @@ void ADSBRxView::focus() { } ADSBRxView::~ADSBRxView() { - receiver_model.set_tuning_frequency(prevFreq); // Restore previous frequency on exit - - // save app settings - settings.save("rx_adsb", &app_settings); - - // TODO: once all apps keep there own settin previous frequency logic can be removed - receiver_model.set_tuning_frequency(prevFreq); rtc_time::signal_tick_second -= signal_token_tick_second; receiver_model.disable(); baseband::shutdown(); @@ -502,17 +495,6 @@ ADSBRxView::ADSBRxView(NavigationView& nav) { &rssi, &recent_entries_view}); - // load app settings - auto rc = settings.load("rx_adsb", &app_settings); - if (rc == SETTINGS_OK) { - field_lna.set_value(app_settings.lna); - field_vga.set_value(app_settings.vga); - field_rf_amp.set_value(app_settings.rx_amp); - } else { - field_lna.set_value(40); - field_vga.set_value(40); - } - recent_entries_view.set_parent_rect({0, 16, 240, 272}); recent_entries_view.on_select = [this, &nav](const AircraftRecentEntry& entry) { detailed_entry_key = entry.key(); @@ -528,11 +510,9 @@ ADSBRxView::ADSBRxView(NavigationView& nav) { on_tick_second(); }; - prevFreq = receiver_model.tuning_frequency(); // Store previous frequency on creation - baseband::set_adsb(); - receiver_model.set_tuning_frequency(1090000000); + receiver_model.set_target_frequency(1090000000); receiver_model.set_modulation(ReceiverModel::Mode::SpectrumAnalysis); receiver_model.set_sampling_rate(2000000); receiver_model.set_baseband_bandwidth(2500000); diff --git a/firmware/application/apps/ui_adsb_rx.hpp b/firmware/application/apps/ui_adsb_rx.hpp index 975d85005..d69bb4692 100644 --- a/firmware/application/apps/ui_adsb_rx.hpp +++ b/firmware/application/apps/ui_adsb_rx.hpp @@ -340,7 +340,9 @@ class ADSBRxView : public View { void sort_entries_by_state(); private: - rf::Frequency prevFreq = {0}; + app_settings::SettingsManager settings_{ + "rx_adsb", app_settings::Mode::RX}; + std::unique_ptr logger{}; void on_frame(const ADSBFrameMessage* message); void on_tick_second(); @@ -350,9 +352,6 @@ class ADSBRxView : public View { #define MARKER_UPDATE_SECONDS (5) int ticksSinceMarkerRefresh{MARKER_UPDATE_SECONDS - 1}; - // app save settings - std::app_settings settings{}; - std::app_settings::AppSettings app_settings{}; const RecentEntriesColumns columns{{{"ICAO/Call", 9}, {"Lvl", 3}, diff --git a/firmware/application/apps/ui_adsb_tx.cpp b/firmware/application/apps/ui_adsb_tx.cpp index 646c836ad..cb51a077a 100644 --- a/firmware/application/apps/ui_adsb_tx.cpp +++ b/firmware/application/apps/ui_adsb_tx.cpp @@ -273,12 +273,8 @@ void ADSBTxView::focus() { } ADSBTxView::~ADSBTxView() { - // save app settings - app_settings.tx_frequency = transmitter_model.tuning_frequency(); - settings.save("tx_adsb", &app_settings); - transmitter_model.disable(); - hackrf::cpld::load_sram_no_verify(); // to leave all RX ok, withouth ghost signal problem at the exit . + hackrf::cpld::load_sram_no_verify(); // to leave all RX ok, withouth ghost signal problem at the exit. baseband::shutdown(); // better this function at the end, not load_sram() that sometimes produces hang up. } @@ -327,18 +323,10 @@ ADSBTxView::ADSBTxView( &text_frame, &tx_view}); - // load app settings - auto rc = settings.load("tx_adsb", &app_settings); - if (rc == SETTINGS_OK) { - transmitter_model.set_tuning_frequency(app_settings.tx_frequency); - transmitter_model.set_rf_amp(app_settings.tx_amp); - transmitter_model.set_tx_gain(app_settings.tx_gain); - } - tx_view.on_edit_frequency = [this, &nav]() { - auto new_view = nav.push(receiver_model.tuning_frequency()); + auto new_view = nav.push(transmitter_model.target_frequency()); new_view->on_changed = [this](rf::Frequency f) { - transmitter_model.set_tuning_frequency(f); + transmitter_model.set_target_frequency(f); }; }; diff --git a/firmware/application/apps/ui_adsb_tx.hpp b/firmware/application/apps/ui_adsb_tx.hpp index 28e4702ae..6d1a4c6e7 100644 --- a/firmware/application/apps/ui_adsb_tx.hpp +++ b/firmware/application/apps/ui_adsb_tx.hpp @@ -201,9 +201,8 @@ class ADSBTxView : public View { -1 };*/ - // app save settings - std::app_settings settings{}; - std::app_settings::AppSettings app_settings{}; + app_settings::SettingsManager settings_{ + "tx_adsb", app_settings::Mode::TX}; // tx_modes tx_mode = IDLE; NavigationView& nav_; diff --git a/firmware/application/apps/ui_afsk_rx.cpp b/firmware/application/apps/ui_afsk_rx.cpp index 45f6177c2..dbfee1425 100644 --- a/firmware/application/apps/ui_afsk_rx.cpp +++ b/firmware/application/apps/ui_afsk_rx.cpp @@ -44,7 +44,7 @@ void AFSKRxView::focus() { } void AFSKRxView::update_freq(rf::Frequency f) { - receiver_model.set_tuning_frequency(f); + receiver_model.set_target_frequency(f); } AFSKRxView::AFSKRxView(NavigationView& nav) { @@ -62,14 +62,6 @@ AFSKRxView::AFSKRxView(NavigationView& nav) { &button_modem_setup, &console}); - // load app settings - auto rc = settings.load("rx_afsk", &app_settings); - if (rc == SETTINGS_OK) { - field_lna.set_value(app_settings.lna); - field_vga.set_value(app_settings.vga); - field_rf_amp.set_value(app_settings.rx_amp); - } - // Auto-configure modem for LCR RX (will be removed later) update_freq(467225500); // 462713300 auto def_bell202 = &modem_defs[0]; @@ -81,15 +73,14 @@ AFSKRxView::AFSKRxView(NavigationView& nav) { serial_format.bit_order = LSB_FIRST; persistent_memory::set_serial_format(serial_format); - field_frequency.set_value(receiver_model.tuning_frequency()); + field_frequency.set_value(receiver_model.target_frequency()); field_frequency.set_step(100); field_frequency.on_change = [this](rf::Frequency f) { update_freq(f); }; field_frequency.on_edit = [this, &nav]() { - auto new_view = nav.push(receiver_model.tuning_frequency()); + auto new_view = nav.push(receiver_model.target_frequency()); new_view->on_changed = [this](rf::Frequency f) { - update_freq(f); field_frequency.set_value(f); }; }; @@ -167,10 +158,6 @@ void AFSKRxView::on_data(uint32_t value, bool is_data) { } AFSKRxView::~AFSKRxView() { - // save app settings - app_settings.rx_frequency = field_frequency.value(); - settings.save("rx_afsk", &app_settings); - audio::output::stop(); receiver_model.disable(); baseband::shutdown(); diff --git a/firmware/application/apps/ui_afsk_rx.hpp b/firmware/application/apps/ui_afsk_rx.hpp index 9673714b7..8d747bf3b 100644 --- a/firmware/application/apps/ui_afsk_rx.hpp +++ b/firmware/application/apps/ui_afsk_rx.hpp @@ -57,9 +57,8 @@ class AFSKRxView : public View { private: void on_data(uint32_t value, bool is_data); - // app save settings - std::app_settings settings{}; - std::app_settings::AppSettings app_settings{}; + app_settings::SettingsManager settings_{ + "rx_afsk", app_settings::Mode::RX}; uint8_t console_color{0}; uint32_t prev_value{0}; diff --git a/firmware/application/apps/ui_aprs_rx.cpp b/firmware/application/apps/ui_aprs_rx.cpp index 324b8f195..302a7f02e 100644 --- a/firmware/application/apps/ui_aprs_rx.cpp +++ b/firmware/application/apps/ui_aprs_rx.cpp @@ -74,7 +74,7 @@ void APRSRxView::focus() { } void APRSRxView::update_freq(rf::Frequency f) { - receiver_model.set_tuning_frequency(f); + receiver_model.set_target_frequency(f); } APRSRxView::APRSRxView(NavigationView& nav, Rect parent_rect) @@ -92,14 +92,6 @@ APRSRxView::APRSRxView(NavigationView& nav, Rect parent_rect) &record_view, &console}); - // load app settings - auto rc = settings.load("rx_aprs", &app_settings); - if (rc == SETTINGS_OK) { - field_lna.set_value(app_settings.lna); - field_vga.set_value(app_settings.vga); - field_rf_amp.set_value(app_settings.rx_amp); - } - // DEBUG record_view.on_error = [&nav](std::string message) { nav.display_modal("Error", message); @@ -119,15 +111,14 @@ APRSRxView::APRSRxView(NavigationView& nav, Rect parent_rect) } }; - field_frequency.set_value(receiver_model.tuning_frequency()); + field_frequency.set_value(receiver_model.target_frequency()); field_frequency.set_step(100); field_frequency.on_change = [this](rf::Frequency f) { update_freq(f); }; field_frequency.on_edit = [this, &nav]() { - auto new_view = nav.push(receiver_model.tuning_frequency()); + auto new_view = nav.push(receiver_model.target_frequency()); new_view->on_changed = [this](rf::Frequency f) { - update_freq(f); field_frequency.set_value(f); }; }; @@ -211,9 +202,6 @@ void APRSRxView::on_show() { } APRSRxView::~APRSRxView() { - // save app settings - settings.save("rx_aprs", &app_settings); - audio::output::stop(); receiver_model.disable(); baseband::shutdown(); diff --git a/firmware/application/apps/ui_aprs_rx.hpp b/firmware/application/apps/ui_aprs_rx.hpp index 2fc6b56a7..7d2f29b8c 100644 --- a/firmware/application/apps/ui_aprs_rx.hpp +++ b/firmware/application/apps/ui_aprs_rx.hpp @@ -187,9 +187,8 @@ class APRSRxView : public View { void on_data(uint32_t value, bool is_data); bool reset_console = false; - // app save settings - std::app_settings settings{}; - std::app_settings::AppSettings app_settings{}; + app_settings::SettingsManager settings_{ + "rx_aprs", app_settings::Mode::RX}; uint8_t console_color{0}; std::string str_log{""}; diff --git a/firmware/application/apps/ui_aprs_tx.cpp b/firmware/application/apps/ui_aprs_tx.cpp index 783d7865b..0620d5aea 100644 --- a/firmware/application/apps/ui_aprs_tx.cpp +++ b/firmware/application/apps/ui_aprs_tx.cpp @@ -44,10 +44,6 @@ void APRSTXView::focus() { } APRSTXView::~APRSTXView() { - // save app settings - app_settings.tx_frequency = transmitter_model.tuning_frequency(); - settings.save("tx_aprs", &app_settings); - transmitter_model.disable(); hackrf::cpld::load_sram_no_verify(); // to leave all RX ok, without ghost signal problem at the exit. baseband::shutdown(); // better this function at the end, not load_sram() that sometimes produces hang up. @@ -62,7 +58,6 @@ void APRSTXView::start_tx() { // uint8_t * bb_data_ptr = shared_memory.bb_data.data; // text_payload.set(to_string_hex_array(bb_data_ptr + 56, 15)); - transmitter_model.set_tuning_frequency(persistent_memory::tuned_frequency()); transmitter_model.set_sampling_rate(AFSK_TX_SAMPLERATE); transmitter_model.set_baseband_bandwidth(1750000); transmitter_model.enable(); @@ -97,14 +92,6 @@ APRSTXView::APRSTXView(NavigationView& nav) { &button_set, &tx_view}); - // load app settings - auto rc = settings.load("tx_aprs", &app_settings); - if (rc == SETTINGS_OK) { - transmitter_model.set_rf_amp(app_settings.tx_amp); - transmitter_model.set_tuning_frequency(app_settings.tx_frequency); - transmitter_model.set_tx_gain(app_settings.tx_gain); - } - button_set.on_select = [this, &nav](Button&) { text_prompt( nav, @@ -116,9 +103,9 @@ APRSTXView::APRSTXView(NavigationView& nav) { }; tx_view.on_edit_frequency = [this, &nav]() { - auto new_view = nav.push(receiver_model.tuning_frequency()); + auto new_view = nav.push(transmitter_model.target_frequency()); new_view->on_changed = [this](rf::Frequency f) { - receiver_model.set_tuning_frequency(f); + transmitter_model.set_target_frequency(f); }; }; diff --git a/firmware/application/apps/ui_aprs_tx.hpp b/firmware/application/apps/ui_aprs_tx.hpp index f62b3aac3..801d99bb9 100644 --- a/firmware/application/apps/ui_aprs_tx.hpp +++ b/firmware/application/apps/ui_aprs_tx.hpp @@ -43,9 +43,8 @@ class APRSTXView : public View { std::string title() const override { return "APRS TX"; }; private: - // app save settings - std::app_settings settings{}; - std::app_settings::AppSettings app_settings{}; + app_settings::SettingsManager settings_{ + "tx_aprs", app_settings::Mode::TX}; std::string payload{""}; diff --git a/firmware/application/apps/ui_bht_tx.cpp b/firmware/application/apps/ui_bht_tx.cpp index da5e73fbd..821439713 100644 --- a/firmware/application/apps/ui_bht_tx.cpp +++ b/firmware/application/apps/ui_bht_tx.cpp @@ -137,10 +137,6 @@ void BHTView::on_tx_progress(const uint32_t progress, const bool done) { } BHTView::~BHTView() { - // save app settings - app_settings.tx_frequency = transmitter_model.tuning_frequency(); - settings.save("tx_bht", &app_settings); - transmitter_model.disable(); hackrf::cpld::load_sram_no_verify(); // to leave all RX ok, without ghost signal problem at the exit . baseband::shutdown(); // better this function at the end, not load_sram() that sometimes produces hang up. @@ -157,21 +153,12 @@ BHTView::BHTView(NavigationView& nav) { &progressbar, &tx_view}); - // load app settings - auto rc = settings.load("tx_bht", &app_settings); - if (rc == SETTINGS_OK) { - transmitter_model.set_rf_amp(app_settings.tx_amp); - transmitter_model.set_channel_bandwidth(app_settings.channel_bandwidth); - transmitter_model.set_tuning_frequency(app_settings.tx_frequency); - transmitter_model.set_tx_gain(app_settings.tx_gain); - } - field_speed.set_value(1); tx_view.on_edit_frequency = [this, &nav]() { - auto new_view = nav.push(receiver_model.tuning_frequency()); + auto new_view = nav.push(transmitter_model.target_frequency()); new_view->on_changed = [this](rf::Frequency f) { - transmitter_model.set_tuning_frequency(f); + transmitter_model.set_target_frequency(f); }; }; diff --git a/firmware/application/apps/ui_bht_tx.hpp b/firmware/application/apps/ui_bht_tx.hpp index a3282b1e3..18a121a6d 100644 --- a/firmware/application/apps/ui_bht_tx.hpp +++ b/firmware/application/apps/ui_bht_tx.hpp @@ -165,9 +165,8 @@ class BHTView : public View { std::string title() const override { return "BHT TX"; }; private: - // app save settings - std::app_settings settings{}; - std::app_settings::AppSettings app_settings{}; + app_settings::SettingsManager settings_{ + "tx_bht", app_settings::Mode::TX}; void on_tx_progress(const uint32_t progress, const bool done); void start_tx(); diff --git a/firmware/application/apps/ui_btle_rx.cpp b/firmware/application/apps/ui_btle_rx.cpp index 9a31ceb84..03eaa7cfc 100644 --- a/firmware/application/apps/ui_btle_rx.cpp +++ b/firmware/application/apps/ui_btle_rx.cpp @@ -41,7 +41,7 @@ void BTLERxView::focus() { } void BTLERxView::update_freq(rf::Frequency f) { - receiver_model.set_tuning_frequency(f); + receiver_model.set_target_frequency(f); } BTLERxView::BTLERxView(NavigationView& nav) { @@ -56,14 +56,6 @@ BTLERxView::BTLERxView(NavigationView& nav) { &button_modem_setup, &console}); - // load app settings - auto rc = settings.load("rx_btle", &app_settings); - if (rc == SETTINGS_OK) { - field_lna.set_value(app_settings.lna); - field_vga.set_value(app_settings.vga); - field_rf_amp.set_value(app_settings.rx_amp); - } - // Auto-configure modem for LCR RX (will be removed later) update_freq(2426000000); auto def_bell202 = &modem_defs[0]; @@ -75,15 +67,14 @@ BTLERxView::BTLERxView(NavigationView& nav) { serial_format.bit_order = LSB_FIRST; persistent_memory::set_serial_format(serial_format); - field_frequency.set_value(receiver_model.tuning_frequency()); + field_frequency.set_value(receiver_model.target_frequency()); field_frequency.set_step(100); field_frequency.on_change = [this](rf::Frequency f) { update_freq(f); }; field_frequency.on_edit = [this, &nav]() { - auto new_view = nav.push(receiver_model.tuning_frequency()); + auto new_view = nav.push(receiver_model.target_frequency()); new_view->on_changed = [this](rf::Frequency f) { - update_freq(f); field_frequency.set_value(f); }; }; @@ -148,10 +139,6 @@ void BTLERxView::on_data(uint32_t value, bool is_data) { } BTLERxView::~BTLERxView() { - // save app settings - app_settings.rx_frequency = field_frequency.value(); - settings.save("rx_btle", &app_settings); - audio::output::stop(); receiver_model.disable(); baseband::shutdown(); diff --git a/firmware/application/apps/ui_btle_rx.hpp b/firmware/application/apps/ui_btle_rx.hpp index 0eb2b6d14..aac58712c 100644 --- a/firmware/application/apps/ui_btle_rx.hpp +++ b/firmware/application/apps/ui_btle_rx.hpp @@ -46,9 +46,8 @@ class BTLERxView : public View { private: void on_data(uint32_t value, bool is_data); - // app save settings - std::app_settings settings{}; - std::app_settings::AppSettings app_settings{}; + app_settings::SettingsManager settings_{ + "rx_btle", app_settings::Mode::RX}; uint8_t console_color{0}; uint32_t prev_value{0}; diff --git a/firmware/application/apps/ui_coasterp.cpp b/firmware/application/apps/ui_coasterp.cpp index f1f1ff505..fe2d3d841 100644 --- a/firmware/application/apps/ui_coasterp.cpp +++ b/firmware/application/apps/ui_coasterp.cpp @@ -38,10 +38,6 @@ void CoasterPagerView::focus() { } CoasterPagerView::~CoasterPagerView() { - // save app settings - app_settings.tx_frequency = transmitter_model.tuning_frequency(); - settings.save("tx_coaster", &app_settings); - transmitter_model.disable(); hackrf::cpld::load_sram_no_verify(); // to leave all RX ok, without ghost signal problem at the exit . baseband::shutdown(); // better this function at the end, not load_sram() that sometimes produces hang up. @@ -123,15 +119,6 @@ CoasterPagerView::CoasterPagerView(NavigationView& nav) { &text_message, &tx_view}); - // load app settings - auto rc = settings.load("tx_coaster", &app_settings); - if (rc == SETTINGS_OK) { - transmitter_model.set_rf_amp(app_settings.tx_amp); - transmitter_model.set_channel_bandwidth(app_settings.channel_bandwidth); - transmitter_model.set_tuning_frequency(app_settings.tx_frequency); - transmitter_model.set_tx_gain(app_settings.tx_gain); - } - // Bytes to nibbles for (c = 0; c < 16; c++) sym_data.set_sym(c, (data_init[c >> 1] >> ((c & 1) ? 0 : 4)) & 0x0F); @@ -141,9 +128,9 @@ CoasterPagerView::CoasterPagerView(NavigationView& nav) { generate_frame(); tx_view.on_edit_frequency = [this, &nav]() { - auto new_view = nav.push(receiver_model.tuning_frequency()); + auto new_view = nav.push(transmitter_model.target_frequency()); new_view->on_changed = [this](rf::Frequency f) { - receiver_model.set_tuning_frequency(f); + transmitter_model.set_target_frequency(f); }; }; diff --git a/firmware/application/apps/ui_coasterp.hpp b/firmware/application/apps/ui_coasterp.hpp index 09633ceb2..12a23641e 100644 --- a/firmware/application/apps/ui_coasterp.hpp +++ b/firmware/application/apps/ui_coasterp.hpp @@ -51,8 +51,8 @@ class CoasterPagerView : public View { tx_modes tx_mode = IDLE; // app save settings - std::app_settings settings{}; - std::app_settings::AppSettings app_settings{}; + app_settings::SettingsManager settings_{ + "tx_coaster", app_settings::Mode::TX}; void start_tx(); void generate_frame(); diff --git a/firmware/application/apps/ui_encoders.cpp b/firmware/application/apps/ui_encoders.cpp index c28c67ccf..e4af6bfb3 100644 --- a/firmware/application/apps/ui_encoders.cpp +++ b/firmware/application/apps/ui_encoders.cpp @@ -200,10 +200,6 @@ void EncodersView::focus() { } EncodersView::~EncodersView() { - // save app settings - app_settings.tx_frequency = transmitter_model.tuning_frequency(); - settings.save("tx_ook", &app_settings); - transmitter_model.disable(); hackrf::cpld::load_sram_no_verify(); // ghost signal c/m to the problem at the exit . baseband::shutdown(); // better this function after load_sram() @@ -290,19 +286,10 @@ EncodersView::EncodersView( &progressbar, &tx_view}); - // load app settings - auto rc = settings.load("tx_ook", &app_settings); - if (rc == SETTINGS_OK) { - transmitter_model.set_rf_amp(app_settings.tx_amp); - transmitter_model.set_channel_bandwidth(app_settings.channel_bandwidth); - transmitter_model.set_tuning_frequency(app_settings.tx_frequency); - transmitter_model.set_tx_gain(app_settings.tx_gain); - } - tx_view.on_edit_frequency = [this, &nav]() { - auto new_view = nav.push(transmitter_model.tuning_frequency()); + auto new_view = nav.push(transmitter_model.target_frequency()); new_view->on_changed = [this](rf::Frequency f) { - transmitter_model.set_tuning_frequency(f); + transmitter_model.set_target_frequency(f); }; }; diff --git a/firmware/application/apps/ui_encoders.hpp b/firmware/application/apps/ui_encoders.hpp index f257f5c99..62ba8aa34 100644 --- a/firmware/application/apps/ui_encoders.hpp +++ b/firmware/application/apps/ui_encoders.hpp @@ -184,8 +184,8 @@ class EncodersView : public View { }; // app save settings - std::app_settings settings{}; - std::app_settings::AppSettings app_settings{}; + app_settings::SettingsManager settings_{ + "tx_ook", app_settings::Mode::TX}; tx_modes tx_mode = IDLE; uint32_t repeat_index{0}; diff --git a/firmware/application/apps/ui_jammer.cpp b/firmware/application/apps/ui_jammer.cpp index 9e6eecb9f..9d8d8813c 100644 --- a/firmware/application/apps/ui_jammer.cpp +++ b/firmware/application/apps/ui_jammer.cpp @@ -186,7 +186,7 @@ JammerView::~JammerView() { void JammerView::on_retune(const rf::Frequency freq, const uint32_t range) { if (freq) { - transmitter_model.set_tuning_frequency(freq); + transmitter_model.set_target_frequency(freq); text_range_number.set(to_string_dec_uint(range, 2)); } } diff --git a/firmware/application/apps/ui_keyfob.cpp b/firmware/application/apps/ui_keyfob.cpp index 47c223bb7..2dbd5cf2e 100644 --- a/firmware/application/apps/ui_keyfob.cpp +++ b/firmware/application/apps/ui_keyfob.cpp @@ -236,12 +236,12 @@ KeyfobView::KeyfobView( options_make.set_selected_index(0); - transmitter_model.set_tuning_frequency(433920000); // Fixed 433.92MHz + transmitter_model.set_target_frequency(433920000); // Fixed 433.92MHz tx_view.on_edit_frequency = [this, &nav]() { - auto new_view = nav.push(transmitter_model.tuning_frequency()); + auto new_view = nav.push(transmitter_model.target_frequency()); new_view->on_changed = [this](rf::Frequency f) { - transmitter_model.set_tuning_frequency(f); + transmitter_model.set_target_frequency(f); }; }; diff --git a/firmware/application/apps/ui_keyfob.hpp b/firmware/application/apps/ui_keyfob.hpp index e571339ca..5627cbbdc 100644 --- a/firmware/application/apps/ui_keyfob.hpp +++ b/firmware/application/apps/ui_keyfob.hpp @@ -43,8 +43,8 @@ class KeyfobView : public View { NavigationView& nav_; // app save settings - std::app_settings settings{}; - std::app_settings::AppSettings app_settings{}; + app_settings::SettingsManager settings_{ + "tx_keyfob", , app_settings::Mode::TX}; // 1013210ns / bit static constexpr uint32_t subaru_samples_per_bit = (OOK_SAMPLERATE * 0.00101321); diff --git a/firmware/application/apps/ui_lcr.cpp b/firmware/application/apps/ui_lcr.cpp index 0141ad2ef..4c547eb71 100644 --- a/firmware/application/apps/ui_lcr.cpp +++ b/firmware/application/apps/ui_lcr.cpp @@ -40,10 +40,6 @@ void LCRView::focus() { } LCRView::~LCRView() { - // save app settings - app_settings.tx_frequency = transmitter_model.tuning_frequency(); - settings.save("tx_lcr", &app_settings); - transmitter_model.disable(); hackrf::cpld::load_sram_no_verify(); // to leave all RX ok, without ghost signal problem at the exit. baseband::shutdown(); // better this function at the end, not load_sram() that sometimes produces hang up. @@ -134,7 +130,6 @@ void LCRView::start_tx(const bool scan) { modems::generate_data(lcr::generate_message(rgsb, litterals_list, options_ec.selected_index()), lcr_message_data); - transmitter_model.set_tuning_frequency(persistent_memory::tuned_frequency()); transmitter_model.set_sampling_rate(AFSK_TX_SAMPLERATE); transmitter_model.set_baseband_bandwidth(1750000); transmitter_model.enable(); @@ -176,15 +171,6 @@ LCRView::LCRView(NavigationView& nav) { &button_clear, &tx_view}); - // load app settings - auto rc = settings.load("tx_lcr", &app_settings); - if (rc == SETTINGS_OK) { - transmitter_model.set_rf_amp(app_settings.tx_amp); - transmitter_model.set_channel_bandwidth(app_settings.channel_bandwidth); - transmitter_model.set_tuning_frequency(app_settings.tx_frequency); - transmitter_model.set_tx_gain(app_settings.tx_gain); - } - options_scanlist.set_selected_index(0); const auto button_set_am_fn = [this, &nav](Button& button) { @@ -251,9 +237,9 @@ LCRView::LCRView(NavigationView& nav) { }; tx_view.on_edit_frequency = [this, &nav]() { - auto new_view = nav.push(transmitter_model.tuning_frequency()); + auto new_view = nav.push(transmitter_model.target_frequency()); new_view->on_changed = [this](rf::Frequency f) { - transmitter_model.set_tuning_frequency(f); + transmitter_model.set_target_frequency(f); }; }; diff --git a/firmware/application/apps/ui_lcr.hpp b/firmware/application/apps/ui_lcr.hpp index 7ae63c55b..fa3610aac 100644 --- a/firmware/application/apps/ui_lcr.hpp +++ b/firmware/application/apps/ui_lcr.hpp @@ -79,9 +79,8 @@ class LCRView : public View { SCAN }; - // app save settings - std::app_settings settings{}; - std::app_settings::AppSettings app_settings{}; + app_settings::SettingsManager settings_{ + "tx_lcr", app_settings::Mode::TX}; tx_modes tx_mode = IDLE; uint8_t scan_count{0}, scan_index{0}; diff --git a/firmware/application/apps/ui_level.cpp b/firmware/application/apps/ui_level.cpp index 4a01be3cb..8a6590c66 100644 --- a/firmware/application/apps/ui_level.cpp +++ b/firmware/application/apps/ui_level.cpp @@ -35,13 +35,6 @@ void LevelView::focus() { } LevelView::~LevelView() { - // save app settings - app_settings.lna = field_lna.value(); - app_settings.vga = field_vga.value(); - app_settings.rx_amp = field_rf_amp.value(); - - settings.save("level", &app_settings); - receiver_model.disable(); baseband::shutdown(); } @@ -71,42 +64,31 @@ LevelView::LevelView(NavigationView& nav) change_mode(NFM_MODULATION); // Start on AM field_mode.set_by_value(NFM_MODULATION); // Reflect the mode into the manual selector - // HELPER: Pre-setting a manual range, based on stored frequency - freq = persistent_memory::tuned_frequency(); - receiver_model.set_tuning_frequency(freq); - button_frequency.set_text("<" + to_string_short_freq(freq) + " MHz>"); - - // load auto common app settings - auto rc = settings.load("level", &app_settings); - if (rc == SETTINGS_OK) { - field_lna.set_value(app_settings.lna); - field_vga.set_value(app_settings.vga); - field_rf_amp.set_value(app_settings.rx_amp); - receiver_model.set_rf_amp(app_settings.rx_amp); - } + freq_ = receiver_model.target_frequency(); + button_frequency.set_text("<" + to_string_short_freq(freq_) + " MHz>"); button_frequency.on_select = [this, &nav](ButtonWithEncoder& button) { - auto new_view = nav_.push(freq); + auto new_view = nav_.push(freq_); new_view->on_changed = [this, &button](rf::Frequency f) { - freq = f; - receiver_model.set_tuning_frequency(f); // Retune to actual freq - button_frequency.set_text("<" + to_string_short_freq(freq) + " MHz>"); + freq_ = f; + receiver_model.set_target_frequency(f); // Retune to actual freq + button_frequency.set_text("<" + to_string_short_freq(freq_) + " MHz>"); }; }; button_frequency.on_change = [this]() { int64_t def_step = freqman_entry_get_step_value(step_mode.selected_index()); - freq = freq + (button_frequency.get_encoder_delta() * def_step); - if (freq < 1) { - freq = 1; + freq_ = freq_ + (button_frequency.get_encoder_delta() * def_step); + if (freq_ < 1) { + freq_ = 1; } - if (freq > (MAX_UFREQ - def_step)) { - freq = MAX_UFREQ; + if (freq_ > (MAX_UFREQ - def_step)) { + freq_ = MAX_UFREQ; } button_frequency.set_encoder_delta(0); - receiver_model.set_tuning_frequency(freq); // Retune to actual freq - button_frequency.set_text("<" + to_string_short_freq(freq) + " MHz>"); + receiver_model.set_target_frequency(freq_); // Retune to actual freq + button_frequency.set_text("<" + to_string_short_freq(freq_) + " MHz>"); }; field_mode.on_change = [this](size_t, OptionsField::value_t v) { diff --git a/firmware/application/apps/ui_level.hpp b/firmware/application/apps/ui_level.hpp index 9c4c3eb49..7f44eb5f2 100644 --- a/firmware/application/apps/ui_level.hpp +++ b/firmware/application/apps/ui_level.hpp @@ -53,13 +53,17 @@ class LevelView : public View { private: NavigationView& nav_; + app_settings::SettingsManager settings_{ + "rx_level", app_settings::Mode::RX}; + size_t change_mode(freqman_index_t mod_type); void on_statistics_update(const ChannelStatistics& statistics); void set_display_freq(int64_t freq); + // TODO: needed? int32_t db{0}; long long int MAX_UFREQ = {7200000000}; // maximum usable freq - rf::Frequency freq = {0}; + rf::Frequency freq_ = {0}; Labels labels{ {{0 * 8, 0 * 16}, "LNA: VGA: AMP: VOL: ", Color::light_grey()}, @@ -104,7 +108,7 @@ class LevelView : public View { {"audio off", 0}, {"audio on", 1} //{"tone on", 2}, - //{"tone off", 2}, + //{"tone off", 3}, }}; Text text_ctcss{ @@ -168,9 +172,6 @@ class LevelView : public View { [this](const Message* const p) { this->on_statistics_update(static_cast(p)->statistics); }}; - // app save settings - std::app_settings settings{}; - std::app_settings::AppSettings app_settings{}; }; } /* namespace ui */ diff --git a/firmware/application/apps/ui_looking_glass_app.cpp b/firmware/application/apps/ui_looking_glass_app.cpp index 5d99c2cc8..e16dcdb3c 100644 --- a/firmware/application/apps/ui_looking_glass_app.cpp +++ b/firmware/application/apps/ui_looking_glass_app.cpp @@ -271,7 +271,7 @@ void GlassView::on_range_changed() { receiver_model.set_squelch_level(0); f_center = f_center_ini; // Reset sweep into first slice baseband::set_spectrum(looking_glass_bandwidth, field_trigger.value()); - receiver_model.set_tuning_frequency(f_center); // tune rx for this slice + receiver_model.set_target_frequency(f_center); // tune rx for this slice } void GlassView::PlotMarker(uint8_t pos) { @@ -467,7 +467,7 @@ GlassView::GlassView( }; button_marker.on_select = [this](ButtonWithEncoder&) { - receiver_model.set_tuning_frequency(marker); // Center tune rx in marker freq. + receiver_model.set_target_frequency(marker); // Center tune rx in marker freq. receiver_model.set_frequency_step(MHZ_DIV); // Preset a 1 MHz frequency step into RX -> AUDIO nav_.pop(); nav_.push(); // Jump into audio view @@ -491,7 +491,7 @@ GlassView::GlassView( }; button_jump.on_select = [this](Button&) { - receiver_model.set_tuning_frequency(max_freq_hold); // Center tune rx in marker freq. + receiver_model.set_target_frequency(max_freq_hold); // Center tune rx in marker freq. receiver_model.set_frequency_step(MHZ_DIV); // Preset a 1 MHz frequency step into RX -> AUDIO nav_.pop(); nav_.push(); // Jump into audio view diff --git a/firmware/application/apps/ui_mictx.cpp b/firmware/application/apps/ui_mictx.cpp index cfb36a8d0..40e77b4d9 100644 --- a/firmware/application/apps/ui_mictx.cpp +++ b/firmware/application/apps/ui_mictx.cpp @@ -68,6 +68,7 @@ void MicTXView::on_tx_progress(const bool done) { } void MicTXView::configure_baseband() { + // TODO: Can this use the transmitter model instead? baseband::set_audiotx_config( sampling_rate / 20, // Update vu-meter at 20Hz transmitting ? transmitter_model.channel_bandwidth() : 0, @@ -86,7 +87,7 @@ void MicTXView::set_tx(bool enable) { rxaudio(false); // Then turn off audio RX transmitting = true; configure_baseband(); - transmitter_model.set_tuning_frequency(tx_frequency); // Now,no need: transmitter_model.set_tx_gain(tx_gain), nor (rf_amp); + transmitter_model.set_target_frequency(tx_frequency); // Now, no need: transmitter_model.set_tx_gain(tx_gain), nor (rf_amp); transmitter_model.enable(); portapack::pin_i2s0_rx_sda.mode(3); // This is already done in audio::init but gets changed by the CPLD overlay reprogramming } else { @@ -140,14 +141,6 @@ void MicTXView::do_timing() { } } -/* Hmmmm. Maybe useless now. -void MicTXView::on_tuning_frequency_changed(rf::Frequency f) { - transmitter_model.set_tuning_frequency(f); - //if ( rx_enabled ) - receiver_model.set_tuning_frequency(f); //Update freq also for RX -} -*/ - void MicTXView::rxaudio(bool is_on) { if (is_on) { audio::input::stop(); @@ -172,11 +165,11 @@ void MicTXView::rxaudio(bool is_on) { } receiver_model.set_sampling_rate(3072000); receiver_model.set_baseband_bandwidth(1750000); - // receiver_model.set_tuning_frequency(field_frequency.value()); //probably this too can be commented out. + // receiver_model.set_target_frequency(field_frequency.value()); //probably this too can be commented out. if (bool_same_F_tx_rx_enabled) // when stop TX ,define to which freq RX we return - receiver_model.set_tuning_frequency(tx_frequency); // Update freq also for RX = TX + receiver_model.set_target_frequency(tx_frequency); // Update freq also for RX = TX else - receiver_model.set_tuning_frequency(rx_frequency); // Now with seperate freq controls! + receiver_model.set_target_frequency(rx_frequency); // Now with separate freq controls! receiver_model.set_lna(rx_lna); receiver_model.set_vga(rx_vga); receiver_model.set_rf_amp(rx_amp); @@ -294,11 +287,11 @@ MicTXView::MicTXView( } ak4951_alc_and_wm8731_boost_GUI = v; // 0,..4 WM8731_boost dB's options, (combination boost on/off , and effective gain in captured data >>x) audio::input::start(ak4951_alc_and_wm8731_boost_GUI); // Detected (WM8731) , set up the proper wm_boost on/off , 0..4 (0,1) boost_on , (2,3,4) boost_0ff - configure_baseband(); // to update in real timme,sending msg , var-parameters >>shift_bits FM msg ,to audio_tx from M0 to M4 Proc - + configure_baseband(); // to update in real time, sending msg , var-parameters >>shift_bits FM msg ,to audio_tx from M0 to M4 Proc - }; options_wm8731_boost_mode.set_selected_index(3); // preset GUI index 3 as default WM -> -02 dB's . } else { - shift_bits_s16 = 8; // Initialized default fixed >>8_FM for FM tx mod , shift audio data for AK4951 ,using top 8 bits s16 data (>>8) + shift_bits_s16 = 8; // Initialized default fixed >>8_FM for FM tx mod , shift audio data for AK4951 ,using top 8 bits s16 data (>>8) options_ak4951_alc_mode.on_change = [this](size_t, int8_t v) { ak4951_alc_and_wm8731_boost_GUI = v; // 0,..11, AK4951 Mic -Automatic volume Level Control options, audio::input::start(ak4951_alc_and_wm8731_boost_GUI); // Detected (AK4951) ==> Set up proper ALC mode from 0..11 options @@ -308,16 +301,16 @@ MicTXView::MicTXView( // options_ak4951_alc_mode.set_selected_index(0); - tx_frequency = transmitter_model.tuning_frequency(); - field_frequency.set_value(transmitter_model.tuning_frequency()); + tx_frequency = transmitter_model.target_frequency(); + field_frequency.set_value(transmitter_model.target_frequency()); field_frequency.set_step(receiver_model.frequency_step()); field_frequency.on_change = [this](rf::Frequency f) { tx_frequency = f; if (!rx_enabled) { // not activated receiver. just update freq TX - transmitter_model.set_tuning_frequency(f); + transmitter_model.set_target_frequency(f); } else { // activated receiver. if (bool_same_F_tx_rx_enabled) // user selected common freq- TX = RX - receiver_model.set_tuning_frequency(f); // Update common freq also for RX + receiver_model.set_target_frequency(f); // Update common freq also for RX } }; field_frequency.on_edit = [this, &nav]() { @@ -327,10 +320,10 @@ MicTXView::MicTXView( new_view->on_changed = [this](rf::Frequency f) { tx_frequency = f; if (!rx_enabled) { - transmitter_model.set_tuning_frequency(f); + transmitter_model.set_target_frequency(f); } else { if (bool_same_F_tx_rx_enabled) - receiver_model.set_tuning_frequency(f); // Update freq also for RX + receiver_model.set_target_frequency(f); // Update freq also for RX } this->field_frequency.set_value(f); set_dirty(); @@ -492,7 +485,7 @@ MicTXView::MicTXView( bool_same_F_tx_rx_enabled = v; field_rxfrequency.hidden(v); // Hide or show separated freq RX field . (When no hide user can enter down indep. freq for RX) set_dirty(); // Refresh GUI interface - receiver_model.set_tuning_frequency(v ? tx_frequency : rx_frequency); // To go to the proper tuned freq. when toggling it + receiver_model.set_target_frequency(v ? tx_frequency : rx_frequency); // To go to the proper tuned freq. when toggling it }; field_va_level.on_change = [this](int32_t v) { @@ -542,13 +535,13 @@ MicTXView::MicTXView( field_squelch.set_value(0); receiver_model.set_squelch_level(0); - rx_frequency = receiver_model.tuning_frequency(); + rx_frequency = receiver_model.target_frequency(); field_rxfrequency.set_value(rx_frequency); field_rxfrequency.set_step(receiver_model.frequency_step()); field_rxfrequency.on_change = [this](rf::Frequency f) { // available when field rxfrequency not hidden => user selected separated freq RX/TX- rx_frequency = f; if (rx_enabled) - receiver_model.set_tuning_frequency(f); + receiver_model.set_target_frequency(f); }; field_rxfrequency.on_edit = [this, &nav]() { // available when field rxfrequency not hidden => user selected separated freq RX/TX- focused_ui = 1; @@ -557,7 +550,7 @@ MicTXView::MicTXView( new_view->on_changed = [this](rf::Frequency f) { rx_frequency = f; if (rx_enabled) - receiver_model.set_tuning_frequency(f); + receiver_model.set_target_frequency(f); this->field_rxfrequency.set_value(f); set_dirty(); }; @@ -617,7 +610,7 @@ MicTXView::MicTXView( MicTXView::~MicTXView() { audio::input::stop(); - transmitter_model.set_tuning_frequency(tx_frequency); // Save Tx frequency instead of Rx. Or maybe we need some "System Wide" changes to seperate Tx and Rx frequency. + transmitter_model.set_target_frequency(tx_frequency); // Save Tx frequency instead of Rx. Or maybe we need some "System Wide" changes to seperate Tx and Rx frequency. transmitter_model.disable(); if (rx_enabled) // Also turn off audio rx if enabled rxaudio(false); diff --git a/firmware/application/apps/ui_mictx.hpp b/firmware/application/apps/ui_mictx.hpp index 372326cd9..bc8b7ab9f 100644 --- a/firmware/application/apps/ui_mictx.hpp +++ b/firmware/application/apps/ui_mictx.hpp @@ -26,6 +26,7 @@ #define SHORT_UI true #define NORMAL_UI false +#include "app_settings.hpp" #include "ui.hpp" #include "ui_widget.hpp" #include "ui_navigation.hpp" @@ -71,7 +72,7 @@ class MicTXView : public View { void update_vumeter(); void do_timing(); void set_tx(bool enable); - // void on_tuning_frequency_changed(rf::Frequency f); + // void on_target_frequency_changed(rf::Frequency f); void on_tx_progress(const bool done); void configure_baseband(); @@ -79,6 +80,9 @@ class MicTXView : public View { void set_ptt_visibility(bool v); + app_settings::SettingsManager settings_{ + "tx_mic", app_settings::Mode::RX_TX}; + bool transmitting{false}; bool va_enabled{false}; bool ptt_enabled{true}; diff --git a/firmware/application/apps/ui_morse.cpp b/firmware/application/apps/ui_morse.cpp index c0f3dc70d..e997bfd34 100644 --- a/firmware/application/apps/ui_morse.cpp +++ b/firmware/application/apps/ui_morse.cpp @@ -98,10 +98,6 @@ void MorseView::focus() { } MorseView::~MorseView() { - // save app settings - app_settings.tx_frequency = transmitter_model.tuning_frequency(); - settings.save("tx_morse", &app_settings); - transmitter_model.disable(); hackrf::cpld::load_sram_no_verify(); // to leave all RX ok, without ghost signal problem at the exit . baseband::shutdown(); // better this function at the end, not load_sram() that sometimes produces hang up. @@ -206,15 +202,6 @@ MorseView::MorseView( &progressbar, &tx_view}); - // load app settings - auto rc = settings.load("tx_morse", &app_settings); - if (rc == SETTINGS_OK) { - transmitter_model.set_rf_amp(app_settings.tx_amp); - transmitter_model.set_channel_bandwidth(app_settings.channel_bandwidth); - transmitter_model.set_tuning_frequency(app_settings.tx_frequency); - transmitter_model.set_tx_gain(app_settings.tx_gain); - } - // Default settings field_speed.set_value(15); // 15wps field_tone.set_value(700); // 700Hz FM tone @@ -251,9 +238,9 @@ MorseView::MorseView( }; tx_view.on_edit_frequency = [this, &nav]() { - auto new_view = nav.push(receiver_model.tuning_frequency()); + auto new_view = nav.push(transmitter_model.target_frequency()); new_view->on_changed = [this](rf::Frequency f) { - receiver_model.set_tuning_frequency(f); + transmitter_model.set_target_frequency(f); }; }; diff --git a/firmware/application/apps/ui_morse.hpp b/firmware/application/apps/ui_morse.hpp index 8999aedd7..ddee152fe 100644 --- a/firmware/application/apps/ui_morse.hpp +++ b/firmware/application/apps/ui_morse.hpp @@ -68,9 +68,8 @@ class MorseView : public View { std::string message{}; uint32_t time_units{0}; - // app save settings - std::app_settings settings{}; - std::app_settings::AppSettings app_settings{}; + app_settings::SettingsManager settings_{ + "tx_morse", app_settings::Mode::TX}; enum modulation_t { CW = 0, diff --git a/firmware/application/apps/ui_nrf_rx.cpp b/firmware/application/apps/ui_nrf_rx.cpp index 0d0753fb7..122404f71 100644 --- a/firmware/application/apps/ui_nrf_rx.cpp +++ b/firmware/application/apps/ui_nrf_rx.cpp @@ -41,7 +41,7 @@ void NRFRxView::focus() { } void NRFRxView::update_freq(rf::Frequency f) { - receiver_model.set_tuning_frequency(f); + receiver_model.set_target_frequency(f); } NRFRxView::NRFRxView(NavigationView& nav) { @@ -56,14 +56,6 @@ NRFRxView::NRFRxView(NavigationView& nav) { &button_modem_setup, &console}); - // load app settings - auto rc = settings.load("rx_nrf", &app_settings); - if (rc == SETTINGS_OK) { - field_lna.set_value(app_settings.lna); - field_vga.set_value(app_settings.vga); - field_rf_amp.set_value(app_settings.rx_amp); - } - // Auto-configure modem for LCR RX (will be removed later) update_freq(2480000000); auto def_bell202 = &modem_defs[0]; @@ -75,15 +67,14 @@ NRFRxView::NRFRxView(NavigationView& nav) { serial_format.bit_order = LSB_FIRST; persistent_memory::set_serial_format(serial_format); - field_frequency.set_value(receiver_model.tuning_frequency()); + field_frequency.set_value(receiver_model.target_frequency()); field_frequency.set_step(100); field_frequency.on_change = [this](rf::Frequency f) { update_freq(f); }; field_frequency.on_edit = [this, &nav]() { - auto new_view = nav.push(receiver_model.tuning_frequency()); + auto new_view = nav.push(receiver_model.target_frequency()); new_view->on_changed = [this](rf::Frequency f) { - update_freq(f); field_frequency.set_value(f); }; }; @@ -151,10 +142,6 @@ void NRFRxView::on_data(uint32_t value, bool is_data) { } NRFRxView::~NRFRxView() { - // save app settings - app_settings.rx_frequency = field_frequency.value(); - settings.save("rx_nrf", &app_settings); - audio::output::stop(); receiver_model.disable(); baseband::shutdown(); diff --git a/firmware/application/apps/ui_nrf_rx.hpp b/firmware/application/apps/ui_nrf_rx.hpp index c2a1de130..6eb0f6d63 100644 --- a/firmware/application/apps/ui_nrf_rx.hpp +++ b/firmware/application/apps/ui_nrf_rx.hpp @@ -46,9 +46,8 @@ class NRFRxView : public View { private: void on_data(uint32_t value, bool is_data); - // app save settings - std::app_settings settings{}; - std::app_settings::AppSettings app_settings{}; + app_settings::SettingsManager settings_{ + "rx_nrf", app_settings::Mode::RX}; uint8_t console_color{0}; uint32_t prev_value{0}; diff --git a/firmware/application/apps/ui_nuoptix.cpp b/firmware/application/apps/ui_nuoptix.cpp index 6378a9433..edf87f46a 100644 --- a/firmware/application/apps/ui_nuoptix.cpp +++ b/firmware/application/apps/ui_nuoptix.cpp @@ -156,9 +156,9 @@ NuoptixView::NuoptixView( number_timecode.set_value(1); tx_view.on_edit_frequency = [this, &nav]() { - auto new_view = nav.push(receiver_model.tuning_frequency()); + auto new_view = nav.push(transmitter_model.target_frequency()); new_view->on_changed = [this](rf::Frequency f) { - receiver_model.set_tuning_frequency(f); + transmitter_model.target_frequency(f); }; }; diff --git a/firmware/application/apps/ui_nuoptix.hpp b/firmware/application/apps/ui_nuoptix.hpp index c64e40e95..528935179 100644 --- a/firmware/application/apps/ui_nuoptix.hpp +++ b/firmware/application/apps/ui_nuoptix.hpp @@ -56,7 +56,6 @@ class NuoptixView : public View { tx_modes tx_mode{IDLE}; - void on_tuning_frequency_changed(rf::Frequency f); void transmit(bool setup); void on_tx_progress(const uint32_t progress, const bool done); diff --git a/firmware/application/apps/ui_playlist.cpp b/firmware/application/apps/ui_playlist.cpp index b7bc3915d..910e04f7a 100644 --- a/firmware/application/apps/ui_playlist.cpp +++ b/firmware/application/apps/ui_playlist.cpp @@ -184,7 +184,7 @@ void PlaylistView::start() { playlist_entry item = playlist_db.front(); playlist_db.pop_front(); on_file_changed(item.replay_file, item.replay_frequency, item.sample_rate, item.next_delay); - on_target_frequency_changed(item.replay_frequency); + transmitter_model.set_target_frequency(item.replay_frequency); std::unique_ptr reader; @@ -293,16 +293,15 @@ PlaylistView::PlaylistView( &waterfall, }); - field_frequency.set_value(target_frequency()); + field_frequency.set_value(transmitter_model.target_frequency()); field_frequency.set_step(receiver_model.frequency_step()); field_frequency.on_change = [this](rf::Frequency f) { - this->on_target_frequency_changed(f); + transmitter_model.set_target_frequency(f); }; field_frequency.on_edit = [this, &nav]() { // TODO: Provide separate modal method/scheme? - auto new_view = nav.push(this->target_frequency()); + auto new_view = nav.push(transmitter_model.target_frequency()); new_view->on_changed = [this](rf::Frequency f) { - this->on_target_frequency_changed(f); this->field_frequency.set_value(f); }; }; @@ -344,16 +343,4 @@ void PlaylistView::set_parent_rect(const Rect new_parent_rect) { waterfall.set_parent_rect(waterfall_rect); } -void PlaylistView::on_target_frequency_changed(rf::Frequency f) { - set_target_frequency(f); -} - -void PlaylistView::set_target_frequency(const rf::Frequency new_value) { - persistent_memory::set_tuned_frequency(new_value); -} - -rf::Frequency PlaylistView::target_frequency() const { - return persistent_memory::tuned_frequency(); -} - } /* namespace ui */ diff --git a/firmware/application/apps/ui_playlist.hpp b/firmware/application/apps/ui_playlist.hpp index 042898871..98148039d 100644 --- a/firmware/application/apps/ui_playlist.hpp +++ b/firmware/application/apps/ui_playlist.hpp @@ -23,16 +23,17 @@ #define SHORT_UI true #define NORMAL_UI false +#include "app_settings.hpp" #include "ui_widget.hpp" #include "ui_navigation.hpp" #include "ui_receiver.hpp" #include "replay_thread.hpp" #include "ui_spectrum.hpp" +#include "ui_transmitter.hpp" #include #include #include -#include "ui_transmitter.hpp" namespace ui { @@ -52,6 +53,8 @@ class PlaylistView : public View { private: NavigationView& nav_; + app_settings::SettingsManager settings_{ + "tx_playlist", app_settings::Mode::TX}; static constexpr ui::Dim header_height = 3 * 16; @@ -73,7 +76,6 @@ class PlaylistView : public View { void load_file(std::filesystem::path playlist_path); void txtline_process(std::string&); void on_file_changed(std::filesystem::path new_file_path, rf::Frequency replay_frequency, uint32_t replay_sample_rate, uint32_t next_delay); - void on_target_frequency_changed(rf::Frequency f); void on_tx_progress(const uint32_t progress); void set_target_frequency(const rf::Frequency new_value); rf::Frequency target_frequency() const; diff --git a/firmware/application/apps/ui_pocsag_tx.cpp b/firmware/application/apps/ui_pocsag_tx.cpp index 73513a460..a36697ed7 100644 --- a/firmware/application/apps/ui_pocsag_tx.cpp +++ b/firmware/application/apps/ui_pocsag_tx.cpp @@ -39,10 +39,6 @@ void POCSAGTXView::focus() { } POCSAGTXView::~POCSAGTXView() { - // save app settings - app_settings.tx_frequency = transmitter_model.tuning_frequency(); - settings.save("tx_pocsag", &app_settings); - transmitter_model.disable(); hackrf::cpld::load_sram_no_verify(); // to leave all RX ok, without ghost signal problem at the exit baseband::shutdown(); // better this function at the end, not load_sram() that sometimes produces hang up. @@ -143,15 +139,6 @@ POCSAGTXView::POCSAGTXView( &progressbar, &tx_view}); - // load app settings - auto rc = settings.load("tx_pocsag", &app_settings); - if (rc == SETTINGS_OK) { - transmitter_model.set_rf_amp(app_settings.tx_amp); - transmitter_model.set_channel_bandwidth(app_settings.channel_bandwidth); - transmitter_model.set_tuning_frequency(app_settings.tx_frequency); - transmitter_model.set_tx_gain(app_settings.tx_gain); - } - options_bitrate.set_selected_index(1); // 1200bps options_type.set_selected_index(0); // Address only @@ -172,9 +159,9 @@ POCSAGTXView::POCSAGTXView( }; tx_view.on_edit_frequency = [this, &nav]() { - auto new_view = nav.push(transmitter_model.tuning_frequency()); + auto new_view = nav.push(transmitter_model.target_frequency()); new_view->on_changed = [this](rf::Frequency f) { - transmitter_model.set_tuning_frequency(f); + transmitter_model.set_target_frequency(f); }; }; diff --git a/firmware/application/apps/ui_pocsag_tx.hpp b/firmware/application/apps/ui_pocsag_tx.hpp index 4fa9a1702..6b946e972 100644 --- a/firmware/application/apps/ui_pocsag_tx.hpp +++ b/firmware/application/apps/ui_pocsag_tx.hpp @@ -58,6 +58,9 @@ class POCSAGTXView : public View { std::string message{}; NavigationView& nav_; + app_settings::SettingsManager settings_{ + "tx_pocsag", app_settings::Mode::TX}; + BCHCode BCH_code{ {1, 0, 1, 0, 0, 1}, 5, @@ -65,10 +68,6 @@ class POCSAGTXView : public View { 21, 2}; - // app save settings - std::app_settings settings{}; - std::app_settings::AppSettings app_settings{}; - void on_set_text(NavigationView& nav); void on_tx_progress(const uint32_t progress, const bool done); bool start_tx(); diff --git a/firmware/application/apps/ui_rds.cpp b/firmware/application/apps/ui_rds.cpp index 2091c48f4..bf989ec25 100644 --- a/firmware/application/apps/ui_rds.cpp +++ b/firmware/application/apps/ui_rds.cpp @@ -160,10 +160,6 @@ void RDSView::focus() { } RDSView::~RDSView() { - // save app settings - app_settings.tx_frequency = transmitter_model.tuning_frequency(); - settings.save("tx_rds", &app_settings); - transmitter_model.disable(); hackrf::cpld::load_sram_no_verify(); // to leave all RX ok, without ghost signal problem at the exit. baseband::shutdown(); // better this function at the end, not load_sram() that sometimes produces hang up. @@ -218,14 +214,6 @@ RDSView::RDSView( &tx_view, }); - // load app settings - auto rc = settings.load("tx_rds", &app_settings); - if (rc == SETTINGS_OK) { - transmitter_model.set_rf_amp(app_settings.tx_amp); - transmitter_model.set_channel_bandwidth(app_settings.channel_bandwidth); - transmitter_model.set_tuning_frequency(app_settings.tx_frequency); - transmitter_model.set_tx_gain(app_settings.tx_gain); - } check_TP.set_value(true); sym_pi_code.set_sym(0, 0xF); @@ -239,9 +227,9 @@ RDSView::RDSView( options_pty.set_selected_index(0); // None tx_view.on_edit_frequency = [this, &nav]() { - auto new_view = nav.push(receiver_model.tuning_frequency()); + auto new_view = nav.push(transmitter_model.target_frequency()); new_view->on_changed = [this](rf::Frequency f) { - receiver_model.set_tuning_frequency(f); + transmitter_model.set_target_frequency(f); }; }; diff --git a/firmware/application/apps/ui_rds.hpp b/firmware/application/apps/ui_rds.hpp index 09798187d..e0f44682e 100644 --- a/firmware/application/apps/ui_rds.hpp +++ b/firmware/application/apps/ui_rds.hpp @@ -140,9 +140,8 @@ class RDSView : public View { NavigationView& nav_; RDS_flags rds_flags{}; - // app save settings - std::app_settings settings{}; - std::app_settings::AppSettings app_settings{}; + app_settings::SettingsManager settings_{ + "tx_rds", app_settings::Mode::TX}; std::vector frame_psn{}; std::vector frame_radiotext{}; diff --git a/firmware/application/apps/ui_recon.cpp b/firmware/application/apps/ui_recon.cpp index 00dd94dcf..92782a596 100644 --- a/firmware/application/apps/ui_recon.cpp +++ b/firmware/application/apps/ui_recon.cpp @@ -291,7 +291,7 @@ void ReconView::recon_redraw() { void ReconView::handle_retune() { if (last_freq != freq) { last_freq = freq; - receiver_model.set_tuning_frequency(freq); // Retune + receiver_model.set_target_frequency(freq); // Retune } if (frequency_list.size() > 0) { if (last_entry.modulation != frequency_list[current_index].modulation && frequency_list[current_index].modulation >= 0) { @@ -361,10 +361,8 @@ void ReconView::focus() { } ReconView::~ReconView() { - // save app config + // Save recon config. recon_save_config_to_sd(); - // save app common settings - settings.save("recon", &app_settings); audio::output::stop(); receiver_model.disable(); @@ -412,8 +410,7 @@ ReconView::ReconView(NavigationView& nav) def_step = 0; // HELPER: Pre-setting a manual range, based on stored frequency - rf::Frequency stored_freq = persistent_memory::tuned_frequency(); - receiver_model.set_tuning_frequency(stored_freq); + rf::Frequency stored_freq = receiver_model.target_frequency(); if (stored_freq - OneMHz > 0) frequency_range.min = stored_freq - OneMHz; else @@ -424,6 +421,7 @@ ReconView::ReconView(NavigationView& nav) else frequency_range.max = MAX_UFREQ; button_manual_end.set_text(to_string_short_freq(frequency_range.max)); + // Loading settings autostart = persistent_memory::recon_autostart_recon(); autosave = persistent_memory::recon_autosave_freqs(); @@ -433,16 +431,6 @@ ReconView::ReconView(NavigationView& nav) load_ranges = persistent_memory::recon_load_ranges(); load_hamradios = persistent_memory::recon_load_hamradios(); update_ranges = persistent_memory::recon_update_ranges_when_recon(); - if (sd_card_mounted) { - // load auto common app settings - auto rc = settings.load("recon", &app_settings); - if (rc == SETTINGS_OK) { - field_lna.set_value(app_settings.lna); - field_vga.set_value(app_settings.vga); - field_rf_amp.set_value(app_settings.rx_amp); - receiver_model.set_rf_amp(app_settings.rx_amp); - } - } button_manual_start.on_select = [this, &nav](ButtonWithEncoder& button) { clear_freqlist_for_ui_action(); @@ -563,17 +551,18 @@ ReconView::ReconView(NavigationView& nav) nav_.push(); }; + // TODO: *BUG* Both transmitter_model and receiver_model share the same pmem setting for target_frequency. button_mic_app.on_select = [this](Button&) { if (frequency_list.size() > 0 && current_index >= 0 && (unsigned)current_index < frequency_list.size()) { if (frequency_list[current_index].type == HAMRADIO) { // if it's a HAMRADIO entry, then frequency_a is the freq at which the repeater reveive, so we have to set it in transmit in mic app - transmitter_model.set_tuning_frequency(frequency_list[current_index].frequency_a); + transmitter_model.set_target_frequency(frequency_list[current_index].frequency_a); // if it's a HAMRADIO entry, then frequency_b is the freq at which the repeater transmit, so we have to set it in receive in mic app - receiver_model.set_tuning_frequency(frequency_list[current_index].frequency_b); + receiver_model.set_target_frequency(frequency_list[current_index].frequency_b); } else { // it's single or range so we us actual tuned frequency - transmitter_model.set_tuning_frequency(freq); - receiver_model.set_tuning_frequency(freq); + transmitter_model.set_target_frequency(freq); + receiver_model.set_target_frequency(freq); } } // there is no way yet to set modulation and bandwidth from Recon to MicApp @@ -672,7 +661,7 @@ ReconView::ReconView(NavigationView& nav) } } } - receiver_model.set_tuning_frequency(frequency_list[current_index].frequency_a); // retune + receiver_model.set_target_frequency(frequency_list[current_index].frequency_a); // retune } if (frequency_list.size() == 0) { text_cycle.set_text(" "); @@ -890,9 +879,8 @@ ReconView::ReconView(NavigationView& nav) freqman_set_step_option(step_mode); // set radio - change_mode(AM_MODULATION); // start on AM. - field_mode.set_by_value(AM_MODULATION); // reflect the mode into the manual selector - receiver_model.set_tuning_frequency(portapack::persistent_memory::tuned_frequency()); // first tune + change_mode(AM_MODULATION); // start on AM. + field_mode.set_by_value(AM_MODULATION); // reflect the mode into the manual selector if (filedelete) { delete_file(freq_file_path); diff --git a/firmware/application/apps/ui_recon.hpp b/firmware/application/apps/ui_recon.hpp index 7a040185e..cabcd60c5 100644 --- a/firmware/application/apps/ui_recon.hpp +++ b/firmware/application/apps/ui_recon.hpp @@ -60,6 +60,9 @@ class ReconView : public View { private: NavigationView& nav_; + app_settings::SettingsManager settings_{ + "rx_recon", app_settings::Mode::RX}; + void clear_freqlist_for_ui_action(); void reset_indexes(); void audio_output_start(); @@ -322,9 +325,6 @@ class ReconView : public View { [this](const Message* const p) { this->on_statistics_update(static_cast(p)->statistics); }}; - // app save settings - std::app_settings settings{}; - std::app_settings::AppSettings app_settings{}; }; } /* namespace ui */ diff --git a/firmware/application/apps/ui_scanner.cpp b/firmware/application/apps/ui_scanner.cpp index db3d5b65b..8289668e2 100644 --- a/firmware/application/apps/ui_scanner.cpp +++ b/firmware/application/apps/ui_scanner.cpp @@ -122,7 +122,7 @@ void ScannerThread::run() { if (force_one_step) _index_stepper = 0; - receiver_model.set_tuning_frequency(frequency_list_[frequency_index]); // Retune + receiver_model.set_target_frequency(frequency_list_[frequency_index]); // Retune } message.freq = frequency_list_[frequency_index]; message.range = frequency_index; // Inform freq (for coloring purposes also!) @@ -160,7 +160,7 @@ void ScannerThread::run() { if (force_one_step) _index_stepper = 0; - receiver_model.set_tuning_frequency(frequency_range_.min + frequency_index * def_step_hz_); // Retune + receiver_model.set_target_frequency(frequency_range_.min + frequency_index * def_step_hz_); // Retune } message.freq = frequency_range_.min + frequency_index * def_step_hz_; message.range = 0; // Inform freq (for coloring purposes also!) @@ -305,8 +305,7 @@ ScannerView::ScannerView( field_step.set_by_value(9000); // Default step interval (Hz) // FUTURE: perhaps additional settings should be stored in persistent memory vs using defaults - // HELPER: Pre-setting a manual range, based on stored frequency - rf::Frequency stored_freq = persistent_memory::tuned_frequency(); + 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)); frequency_range.max = stored_freq + 1000000; diff --git a/firmware/application/apps/ui_search.cpp b/firmware/application/apps/ui_search.cpp index a91f407ce..4650c3c91 100644 --- a/firmware/application/apps/ui_search.cpp +++ b/firmware/application/apps/ui_search.cpp @@ -221,7 +221,7 @@ void SearchView::on_channel_spectrum(const ChannelSpectrum& spectrum) { slice_counter = 0; } else slice_counter++; - receiver_model.set_tuning_frequency(slices[slice_counter].center_frequency); + receiver_model.set_target_frequency(slices[slice_counter].center_frequency); baseband::set_spectrum(SEARCH_SLICE_WIDTH, 31); // Clear } else { // Unique slice @@ -271,7 +271,7 @@ void SearchView::on_range_changed() { } } else { slices[0].center_frequency = (f_max + f_min) / 2; - receiver_model.set_tuning_frequency(slices[0].center_frequency); + receiver_model.set_target_frequency(slices[0].center_frequency); slices_nb = 1; text_slices.set(" 1"); @@ -376,25 +376,25 @@ SearchView::SearchView( power_threshold = value; }; - field_frequency_min.set_value(receiver_model.tuning_frequency() - 1000000); + field_frequency_min.set_value(receiver_model.target_frequency() - 1000000); field_frequency_min.set_step(100000); field_frequency_min.on_change = [this](rf::Frequency) { this->on_range_changed(); }; field_frequency_min.on_edit = [this, &nav]() { - auto new_view = nav.push(receiver_model.tuning_frequency()); + auto new_view = nav.push(receiver_model.target_frequency()); new_view->on_changed = [this](rf::Frequency f) { this->field_frequency_min.set_value(f); }; }; - field_frequency_max.set_value(receiver_model.tuning_frequency() + 1000000); + field_frequency_max.set_value(receiver_model.target_frequency() + 1000000); field_frequency_max.set_step(100000); field_frequency_max.on_change = [this](rf::Frequency) { this->on_range_changed(); }; field_frequency_max.on_edit = [this, &nav]() { - auto new_view = nav.push(receiver_model.tuning_frequency()); + auto new_view = nav.push(receiver_model.target_frequency()); new_view->on_changed = [this](rf::Frequency f) { this->field_frequency_max.set_value(f); }; diff --git a/firmware/application/apps/ui_settings.cpp b/firmware/application/apps/ui_settings.cpp index 4e36ecccb..bf7335d73 100644 --- a/firmware/application/apps/ui_settings.cpp +++ b/firmware/application/apps/ui_settings.cpp @@ -334,8 +334,8 @@ SetConverterSettingsView::SetConverterSettingsView(NavigationView& nav) { if (!v) { check_converter.set_value(false); } - // Retune to take converter change in account - receiver_model.set_tuning_frequency(portapack::persistent_memory::tuned_frequency()); + // Retune to take converter change in account. + receiver_model.set_target_frequency(receiver_model.target_frequency()); // Refresh status bar with/out converter StatusRefreshMessage message{}; EventDispatcher::send_message(message); @@ -349,7 +349,7 @@ SetConverterSettingsView::SetConverterSettingsView(NavigationView& nav) { } portapack::persistent_memory::set_config_converter(v); // Retune to take converter change in account - receiver_model.set_tuning_frequency(portapack::persistent_memory::tuned_frequency()); + receiver_model.set_target_frequency(receiver_model.target_frequency()); // Refresh status bar with/out converter StatusRefreshMessage message{}; EventDispatcher::send_message(message); @@ -369,7 +369,7 @@ SetConverterSettingsView::SetConverterSettingsView(NavigationView& nav) { new_view->on_changed = [this, &button](rf::Frequency f) { portapack::persistent_memory::set_config_converter_freq(f); // Retune to take converter change in account - receiver_model.set_tuning_frequency(portapack::persistent_memory::tuned_frequency()); + receiver_model.set_target_frequency(receiver_model.target_frequency()); button_converter_freq.set_text("<" + to_string_short_freq(f) + " MHz>"); }; }; @@ -412,7 +412,7 @@ SetFrequencyCorrectionView::SetFrequencyCorrectionView(NavigationView& nav) { f = MAX_FREQ_CORRECTION; portapack::persistent_memory::set_config_freq_rx_correction(f); // Retune to take converter change in account - receiver_model.set_tuning_frequency(portapack::persistent_memory::tuned_frequency()); + receiver_model.set_target_frequency(receiver_model.target_frequency()); button_freq_rx_correction.set_text("<" + to_string_short_freq(f) + " MHz>"); }; }; @@ -425,7 +425,7 @@ SetFrequencyCorrectionView::SetFrequencyCorrectionView(NavigationView& nav) { f = MAX_FREQ_CORRECTION; portapack::persistent_memory::set_config_freq_tx_correction(f); // Retune to take converter change in account - receiver_model.set_tuning_frequency(portapack::persistent_memory::tuned_frequency()); + receiver_model.set_target_frequency(receiver_model.target_frequency()); button_freq_tx_correction.set_text("<" + to_string_short_freq(f) + " MHz>"); }; }; diff --git a/firmware/application/apps/ui_sigfrx.cpp b/firmware/application/apps/ui_sigfrx.cpp index a5978cb13..d4e138975 100644 --- a/firmware/application/apps/ui_sigfrx.cpp +++ b/firmware/application/apps/ui_sigfrx.cpp @@ -119,9 +119,9 @@ SIGFRXView::SIGFRXView( .sampling_rate = 3072000, .decimation_factor = 4, }); + // TODO: use settings. receiver_model.set_baseband_bandwidth(1750000); - - receiver_model.set_tuning_frequency(868110000); + receiver_model.set_target_frequency(868110000); receiver_model.set_lna(0); receiver_model.set_vga(0); diff --git a/firmware/application/apps/ui_siggen.cpp b/firmware/application/apps/ui_siggen.cpp index f9bb230ab..4f378524a 100644 --- a/firmware/application/apps/ui_siggen.cpp +++ b/firmware/application/apps/ui_siggen.cpp @@ -55,7 +55,6 @@ void SigGenView::update_tone() { void SigGenView::start_tx() { transmitter_model.set_sampling_rate(1536000); - // transmitter_model.set_rf_amp(true); transmitter_model.set_baseband_bandwidth(1750000); transmitter_model.enable(); @@ -116,9 +115,9 @@ SigGenView::SigGenView( }; tx_view.on_edit_frequency = [this, &nav]() { - auto new_view = nav.push(receiver_model.tuning_frequency()); + auto new_view = nav.push(transmitter_model.target_frequency()); new_view->on_changed = [this](rf::Frequency f) { - receiver_model.set_tuning_frequency(f); + transmitter_model.set_target_frequency(f); }; }; diff --git a/firmware/application/apps/ui_siggen.hpp b/firmware/application/apps/ui_siggen.hpp index fc25f09d3..8de87d142 100644 --- a/firmware/application/apps/ui_siggen.hpp +++ b/firmware/application/apps/ui_siggen.hpp @@ -23,6 +23,7 @@ #ifndef __SIGGEN_H__ #define __SIGGEN_H__ +#include "app_settings.hpp" #include "ui.hpp" #include "ui_widget.hpp" #include "ui_navigation.hpp" @@ -48,6 +49,9 @@ class SigGenView : public View { void update_tone(); void on_tx_progress(const uint32_t progress, const bool done); + app_settings::SettingsManager settings_{ + "tx_siggen", app_settings::Mode::TX}; + const std::string shape_strings[7] = { "CW-just carrier", "Sine signal ", diff --git a/firmware/application/apps/ui_sonde.cpp b/firmware/application/apps/ui_sonde.cpp index 7bcc812da..6daadd4dc 100644 --- a/firmware/application/apps/ui_sonde.cpp +++ b/firmware/application/apps/ui_sonde.cpp @@ -65,27 +65,15 @@ SondeView::SondeView(NavigationView& nav) { &button_see_qr, &button_see_map}); - // load app settings - auto rc = settings.load("rx_sonde", &app_settings); - if (rc == SETTINGS_OK) { - field_lna.set_value(app_settings.lna); - field_vga.set_value(app_settings.vga); - field_rf_amp.set_value(app_settings.rx_amp); - target_frequency_ = app_settings.rx_frequency; - } else - target_frequency_ = receiver_model.tuning_frequency(); - - field_frequency.set_value(target_frequency_); + field_frequency.set_value(receiver_model.target_frequency()); field_frequency.set_step(500); // euquiq: was 10000, but we are using this for fine-tunning field_frequency.on_change = [this](rf::Frequency f) { - set_target_frequency(f); - field_frequency.set_value(f); + receiver_model.set_target_frequency(f); }; field_frequency.on_edit = [this, &nav]() { // TODO: Provide separate modal method/scheme? - auto new_view = nav.push(receiver_model.tuning_frequency()); + auto new_view = nav.push(receiver_model.target_frequency()); new_view->on_changed = [this](rf::Frequency f) { - set_target_frequency(f); field_frequency.set_value(f); }; }; @@ -104,7 +92,6 @@ SondeView::SondeView(NavigationView& nav) { use_crc = v; }; - receiver_model.set_tuning_frequency(tuning_frequency()); receiver_model.set_sampling_rate(sampling_rate); receiver_model.set_baseband_bandwidth(baseband_bandwidth); receiver_model.enable(); @@ -142,10 +129,6 @@ SondeView::SondeView(NavigationView& nav) { } SondeView::~SondeView() { - // save app settings - app_settings.rx_frequency = target_frequency_; - settings.save("rx_sonde", &app_settings); - baseband::set_pitch_rssi(0, false); receiver_model.disable(); @@ -216,15 +199,11 @@ void SondeView::on_packet(const sonde::Packet& packet) { temp_humid_info = packet.get_temp_humid(); if (temp_humid_info.humid != 0) { double decimals = abs(get_decimals(temp_humid_info.humid, 10, true)); - // if (decimals < 0) - // decimals = -decimals; text_humid.set(to_string_dec_int((int)temp_humid_info.humid) + "." + to_string_dec_uint(decimals, 1) + "%"); } if (temp_humid_info.temp != 0) { double decimals = abs(get_decimals(temp_humid_info.temp, 10, true)); - // if (decimals < 0) - // decimals = -decimals; text_temp.set(to_string_dec_int((int)temp_humid_info.temp) + "." + to_string_dec_uint(decimals, 1) + "C"); } @@ -244,13 +223,4 @@ void SondeView::on_packet(const sonde::Packet& packet) { } } -void SondeView::set_target_frequency(const uint32_t new_value) { - target_frequency_ = new_value; - receiver_model.set_tuning_frequency(target_frequency_); -} - -uint32_t SondeView::tuning_frequency() const { - return target_frequency_ - (sampling_rate / 4); -} - } /* namespace ui */ diff --git a/firmware/application/apps/ui_sonde.hpp b/firmware/application/apps/ui_sonde.hpp index b64bb36c5..704911c21 100644 --- a/firmware/application/apps/ui_sonde.hpp +++ b/firmware/application/apps/ui_sonde.hpp @@ -65,6 +65,9 @@ class SondeView : public View { std::string title() const override { return "Radiosnd RX"; }; private: + app_settings::SettingsManager settings_{ + "rx_sonde", app_settings::Mode::RX}; + std::unique_ptr logger{}; uint32_t target_frequency_{402700000}; bool logging{false}; @@ -72,9 +75,6 @@ class SondeView : public View { bool beep{false}; char geo_uri[32] = {}; - // app save settings - std::app_settings settings{}; - std::app_settings::AppSettings app_settings{}; sonde::GPS_data gps_info{}; sonde::temp_humid temp_humid_info{}; @@ -177,9 +177,6 @@ class SondeView : public View { void on_packet(const sonde::Packet& packet); char* float_to_char(float x, char* p); - void set_target_frequency(const uint32_t new_value); - - uint32_t tuning_frequency() const; }; } /* namespace ui */ diff --git a/firmware/application/apps/ui_spectrum_painter.cpp b/firmware/application/apps/ui_spectrum_painter.cpp index ca92ec15b..0b708dd25 100644 --- a/firmware/application/apps/ui_spectrum_painter.cpp +++ b/firmware/application/apps/ui_spectrum_painter.cpp @@ -29,12 +29,14 @@ #include "file.hpp" #include "portapack_persistent_memory.hpp" +using namespace portapack; + namespace ui { SpectrumPainterView::SpectrumPainterView( NavigationView& nav) : nav_(nav) { - baseband::run_image(portapack::spi_flash::image_tag_spectrum_painter); + baseband::run_image(spi_flash::image_tag_spectrum_painter); add_children({ &labels, @@ -56,30 +58,29 @@ SpectrumPainterView::SpectrumPainterView( input_image.set_parent_rect(view_rect); input_text.set_parent_rect(view_rect); - field_frequency.set_value(target_frequency()); + field_frequency.set_value(transmitter_model.target_frequency()); field_frequency.set_step(5000); field_frequency.on_change = [this](rf::Frequency f) { - this->on_target_frequency_changed(f); + transmitter_model.set_target_frequency(f); }; field_frequency.on_edit = [this, &nav]() { - auto new_view = nav.push(this->target_frequency()); + auto new_view = nav.push(transmitter_model.target_frequency()); new_view->on_changed = [this](rf::Frequency f) { - this->on_target_frequency_changed(f); - this->field_frequency.set_value(f); + field_frequency.set_value(f); }; }; - tx_gain = portapack::transmitter_model.tx_gain(); + tx_gain = transmitter_model.tx_gain(); field_rfgain.set_value(tx_gain); // Initial default value (-12 dB's max ). field_rfgain.on_change = [this](int32_t v) { // allow initial value change just after opened file. tx_gain = v; - portapack::transmitter_model.set_tx_gain(tx_gain); + transmitter_model.set_tx_gain(tx_gain); }; field_rfamp.set_value(rf_amp ? 14 : 0); // Initial default value True. (TX RF amp on , +14dB's) field_rfamp.on_change = [this](int32_t v) { // allow initial value change just after opened file. rf_amp = (bool)v; - portapack::transmitter_model.set_rf_amp(rf_amp); + transmitter_model.set_rf_amp(rf_amp); }; input_image.on_input_avaliable = [this]() { @@ -93,11 +94,11 @@ SpectrumPainterView::SpectrumPainterView( if (tx_mode == 0 && image_input_avaliable == false) return; - portapack::transmitter_model.set_sampling_rate(3072000U); - portapack::transmitter_model.set_baseband_bandwidth(1750000); - portapack::transmitter_model.enable(); + transmitter_model.set_sampling_rate(3072000U); + transmitter_model.set_baseband_bandwidth(1750000); + transmitter_model.enable(); - if (portapack::persistent_memory::stealth_mode()) { + if (persistent_memory::stealth_mode()) { DisplaySleepMessage message; EventDispatcher::send_message(message); } @@ -137,7 +138,7 @@ void SpectrumPainterView::start_tx() { void SpectrumPainterView::stop_tx() { button_play.set_bitmap(&bitmap_play); - portapack::transmitter_model.disable(); + transmitter_model.disable(); tx_active = false; tx_current_line = 0; } @@ -176,7 +177,7 @@ void SpectrumPainterView::frame_sync() { } SpectrumPainterView::~SpectrumPainterView() { - portapack::transmitter_model.disable(); + transmitter_model.disable(); hackrf::cpld::load_sram_no_verify(); baseband::shutdown(); } @@ -185,18 +186,6 @@ void SpectrumPainterView::focus() { tab_view.focus(); } -void SpectrumPainterView::on_target_frequency_changed(rf::Frequency f) { - set_target_frequency(f); -} - -void SpectrumPainterView::set_target_frequency(const rf::Frequency new_value) { - portapack::persistent_memory::set_tuned_frequency(new_value); -} - -rf::Frequency SpectrumPainterView::target_frequency() const { - return portapack::persistent_memory::tuned_frequency(); -} - void SpectrumPainterView::paint(Painter& painter) { View::paint(painter); diff --git a/firmware/application/apps/ui_spectrum_painter.hpp b/firmware/application/apps/ui_spectrum_painter.hpp index 1c7ebc7d5..562941606 100644 --- a/firmware/application/apps/ui_spectrum_painter.hpp +++ b/firmware/application/apps/ui_spectrum_painter.hpp @@ -29,6 +29,7 @@ #include "capture_app.hpp" #include "baseband_api.hpp" +#include "app_settings.hpp" #include "portapack.hpp" #include "message.hpp" @@ -53,11 +54,10 @@ class SpectrumPainterView : public View { std::string title() const override { return "Spec.Painter"; }; private: - void on_target_frequency_changed(rf::Frequency f); - void set_target_frequency(const rf::Frequency new_value); - rf::Frequency target_frequency() const; - NavigationView& nav_; + app_settings::SettingsManager settings_{ + "tx_painter", app_settings::Mode::TX}; + bool image_input_avaliable{false}; bool tx_active{false}; uint32_t tx_mode{0}; diff --git a/firmware/application/apps/ui_sstvtx.cpp b/firmware/application/apps/ui_sstvtx.cpp index 32f1133d0..04a200aa5 100644 --- a/firmware/application/apps/ui_sstvtx.cpp +++ b/firmware/application/apps/ui_sstvtx.cpp @@ -88,19 +88,11 @@ void SSTVTXView::paint(Painter&) { } SSTVTXView::~SSTVTXView() { - // save app settings - app_settings.tx_frequency = transmitter_model.tuning_frequency(); - settings.save("tx_sstv", &app_settings); - transmitter_model.disable(); hackrf::cpld::load_sram_no_verify(); // to leave all RX ok, without ghost signal problem at the exit. baseband::shutdown(); // better this function at the end, not load_sram() that sometimes produces hang up. } -void SSTVTXView::on_tuning_frequency_changed(rf::Frequency f) { - transmitter_model.set_tuning_frequency(f); -} - void SSTVTXView::prepare_scanline() { sstv_scanline scanline_buffer; uint32_t component, pixel_idx; @@ -218,15 +210,6 @@ SSTVTXView::SSTVTXView( options_t mode_options; uint32_t c; - // load app settings - auto rc = settings.load("tx_sstv", &app_settings); - if (rc == SETTINGS_OK) { - transmitter_model.set_rf_amp(app_settings.tx_amp); - transmitter_model.set_channel_bandwidth(app_settings.channel_bandwidth); - transmitter_model.set_tuning_frequency(app_settings.tx_frequency); - transmitter_model.set_tx_gain(app_settings.tx_gain); - } - // Search for valid bitmaps file_list = scan_root_files(u"/sstv", u"*.bmp"); if (!file_list.size()) { @@ -284,9 +267,10 @@ SSTVTXView::SSTVTXView( on_mode_changed(1); tx_view.on_edit_frequency = [this, &nav]() { - auto new_view = nav.push(receiver_model.tuning_frequency()); + auto new_view = nav.push(transmitter_model.target_frequency()); new_view->on_changed = [this](rf::Frequency f) { - receiver_model.set_tuning_frequency(f); + transmitter_model.set_target_frequency(f); + // NB: The freq field is only updated because TXView's on_show runs again. }; }; diff --git a/firmware/application/apps/ui_sstvtx.hpp b/firmware/application/apps/ui_sstvtx.hpp index e57af0991..ea41f6fc7 100644 --- a/firmware/application/apps/ui_sstvtx.hpp +++ b/firmware/application/apps/ui_sstvtx.hpp @@ -56,11 +56,10 @@ class SSTVTXView : public View { private: NavigationView& nav_; + app_settings::SettingsManager settings_{ + "tx_sstv", app_settings::Mode::TX}; sstv_scanline scanline_buffer{}; - // app save settings - std::app_settings settings{}; - std::app_settings::AppSettings app_settings{}; bool file_error{false}; File bmp_file{}; @@ -75,7 +74,6 @@ class SSTVTXView : public View { void read_boundary(uint8_t* buffer, uint32_t position, uint32_t length); void on_bitmap_changed(const size_t index); void on_mode_changed(const size_t index); - void on_tuning_frequency_changed(rf::Frequency f); void start_tx(); void prepare_scanline(); diff --git a/firmware/application/apps/ui_test.cpp b/firmware/application/apps/ui_test.cpp index f2f1bf839..878930806 100644 --- a/firmware/application/apps/ui_test.cpp +++ b/firmware/application/apps/ui_test.cpp @@ -54,17 +54,15 @@ TestView::TestView(NavigationView& nav) { &button_cal, &check_log}); - field_frequency.set_value(target_frequency_); + field_frequency.set_value(receiver_model.target_frequency()); field_frequency.set_step(10000); field_frequency.on_change = [this](rf::Frequency f) { - set_target_frequency(f); - field_frequency.set_value(f); + receiver_model.set_target_frequency(f); }; field_frequency.on_edit = [this, &nav]() { // TODO: Provide separate modal method/scheme? - auto new_view = nav.push(receiver_model.tuning_frequency()); + auto new_view = nav.push(receiver_model.target_frequency()); new_view->on_changed = [this](rf::Frequency f) { - set_target_frequency(f); field_frequency.set_value(f); }; }; @@ -81,7 +79,6 @@ TestView::TestView(NavigationView& nav) { if (logger) logger->append("saucepan.txt"); - receiver_model.set_tuning_frequency(tuning_frequency()); receiver_model.set_sampling_rate(sampling_rate); receiver_model.set_baseband_bandwidth(baseband_bandwidth); receiver_model.enable(); @@ -130,13 +127,4 @@ void TestView::on_packet(const testapp::Packet& packet) { longitude = packet.GPS_longitude();*/ } -void TestView::set_target_frequency(const uint32_t new_value) { - target_frequency_ = new_value; - receiver_model.set_tuning_frequency(tuning_frequency()); -} - -uint32_t TestView::tuning_frequency() const { - return target_frequency_ - (sampling_rate / 4); -} - } /* namespace ui */ diff --git a/firmware/application/apps/ui_test.hpp b/firmware/application/apps/ui_test.hpp index bd70bb8f0..bf391fd88 100644 --- a/firmware/application/apps/ui_test.hpp +++ b/firmware/application/apps/ui_test.hpp @@ -62,7 +62,6 @@ class TestView : public View { std::string title() const override { return "Test app"; }; private: - uint32_t target_frequency_{439206000}; Coord cur_x{0}; uint32_t packet_count{0}; uint32_t packets_lost{0}; @@ -112,12 +111,10 @@ class TestView : public View { [this](Message* const p) { const auto message = static_cast(p); const testapp::Packet packet{message->packet}; - this->on_packet(packet); + on_packet(packet); }}; void on_packet(const testapp::Packet& packet); - void set_target_frequency(const uint32_t new_value); - uint32_t tuning_frequency() const; }; } /* namespace ui */ diff --git a/firmware/application/apps/ui_touchtunes.cpp b/firmware/application/apps/ui_touchtunes.cpp index 7fb66d9d5..5dd39a670 100644 --- a/firmware/application/apps/ui_touchtunes.cpp +++ b/firmware/application/apps/ui_touchtunes.cpp @@ -87,7 +87,7 @@ void TouchTunesView::on_tx_progress(const uint32_t progress, const bool done) { // transmission events. void TouchTunesView::start_ew() { // Radio - transmitter_model.set_tuning_frequency(433920000); + transmitter_model.set_target_frequency(433920000); transmitter_model.set_sampling_rate(3072000U); transmitter_model.set_rf_amp(true); transmitter_model.set_baseband_bandwidth(3500000U); @@ -155,7 +155,7 @@ void TouchTunesView::start_tx(const uint32_t button_index) { size_t bitstream_length = make_bitstream(fragments); - transmitter_model.set_tuning_frequency(433920000); + transmitter_model.set_target_frequency(433920000); transmitter_model.set_sampling_rate(OOK_SAMPLERATE); transmitter_model.set_rf_amp(true); transmitter_model.set_baseband_bandwidth(1750000); diff --git a/firmware/application/apps/ui_whipcalc.cpp b/firmware/application/apps/ui_whipcalc.cpp index 69abbc03a..68c605758 100644 --- a/firmware/application/apps/ui_whipcalc.cpp +++ b/firmware/application/apps/ui_whipcalc.cpp @@ -147,7 +147,7 @@ WhipCalcView::WhipCalcView(NavigationView& nav) { }; field_frequency.on_edit = [this, &nav]() { // TODO: Provide separate modal method/scheme? - auto new_view = nav.push(transmitter_model.tuning_frequency()); + auto new_view = nav.push(transmitter_model.target_frequency()); new_view->on_changed = [this](rf::Frequency f) { this->field_frequency.set_value(f); this->update_result(); @@ -158,7 +158,7 @@ WhipCalcView::WhipCalcView(NavigationView& nav) { nav.pop(); }; - field_frequency.set_value(transmitter_model.tuning_frequency()); + field_frequency.set_value(transmitter_model.target_frequency()); } void ui::WhipCalcView::txtline_process(std::string& line) { diff --git a/firmware/application/file.cpp b/firmware/application/file.cpp index 2982e1de4..e6ff99139 100644 --- a/firmware/application/file.cpp +++ b/firmware/application/file.cpp @@ -23,8 +23,9 @@ #include "file.hpp" #include -#include #include +#include +#include Optional File::open_fatfs(const std::filesystem::path& filename, BYTE mode) { auto result = f_open(&f, reinterpret_cast(filename.c_str()), mode); @@ -138,6 +139,37 @@ Optional File::sync() { } } +File::Result File::read_file(const std::filesystem::path& filename) { + constexpr size_t buffer_size = 0x80; + char* buffer[buffer_size]; + + File f; + auto error = f.open(filename); + if (error) + return *error; + + std::string content; + content.resize(f.size()); + auto str = &content[0]; + auto total_read = 0u; + + while (true) { + auto read = f.read(buffer, buffer_size); + if (!read) + return read.error(); + + memcpy(str, buffer, *read); + str += *read; + total_read += *read; + + if (*read < buffer_size) + break; + } + + content.resize(total_read); + return content; +} + /* Range used for filename matching. * Start and end are inclusive positions of "???" */ struct pattern_range { diff --git a/firmware/application/file.hpp b/firmware/application/file.hpp index 67a70cb8b..4c33a4392 100644 --- a/firmware/application/file.hpp +++ b/firmware/application/file.hpp @@ -26,6 +26,7 @@ #include "ff.h" #include "optional.hpp" +#include "result.hpp" #include #include @@ -256,6 +257,7 @@ struct FATTimestamp { std::filesystem::filesystem_error delete_file(const std::filesystem::path& file_path); std::filesystem::filesystem_error rename_file(const std::filesystem::path& file_path, const std::filesystem::path& new_name); std::filesystem::filesystem_error copy_file(const std::filesystem::path& file_path, const std::filesystem::path& dest_path); + FATTimestamp file_created_date(const std::filesystem::path& file_path); std::filesystem::filesystem_error make_new_file(const std::filesystem::path& file_path); std::filesystem::filesystem_error make_new_directory(const std::filesystem::path& dir_path); @@ -288,65 +290,8 @@ class File { using Timestamp = uint32_t; using Error = std::filesystem::filesystem_error; - // TODO: move to common. template - struct Result { - enum class Type { - Success, - Error, - } type; - union { - T value_; - Error error_; - }; - - bool is_ok() const { - return type == Type::Success; - } - - operator bool() const { - return is_ok(); - } - - bool is_error() const { - return type == Type::Error; - } - - const T& value() const& { - return value_; - } - - const T& operator*() const& { - return value_; - } - - T&& operator*() && { - return std::move(value_); - } - - Error error() const { - return error_; - } - - Result() = delete; - - constexpr Result( - T&& value) - : type{Type::Success}, - value_{std::forward(value)} { - } - - constexpr Result( - Error error) - : type{Type::Error}, - error_{error} { - } - - ~Result() { - if (is_ok()) - value_.~T(); - } - }; + using Result = Result; File(){}; ~File(); @@ -374,7 +319,6 @@ class File { Offset tell() const; Result seek(uint64_t Offset); Result truncate(); - // Timestamp created_date() const; Size size() const; template @@ -387,6 +331,10 @@ class File { // TODO: Return Result<>. Optional sync(); + /* Reads the entire file contents to a string. + * NB: This will likely fail for files larger than ~10kB. */ + static Result read_file(const std::filesystem::path& filename); + private: FIL f{}; diff --git a/firmware/application/log_file.cpp b/firmware/application/log_file.cpp index c1126cc05..61c6bbd22 100644 --- a/firmware/application/log_file.cpp +++ b/firmware/application/log_file.cpp @@ -33,7 +33,7 @@ Optional LogFile::write_entry(const rtc::RTC& datetime, const std:: Optional LogFile::write_line(const std::string& message) { auto error = file.write_line(message); - if (!error.is_valid()) { + if (!error) { file.sync(); } return error; diff --git a/firmware/application/receiver_model.cpp b/firmware/application/receiver_model.cpp index 204615d98..a7be1b082 100644 --- a/firmware/application/receiver_model.cpp +++ b/firmware/application/receiver_model.cpp @@ -26,17 +26,16 @@ #include "portapack_persistent_memory.hpp" #include "hackrf_gpio.hpp" #include "portapack.hpp" -using namespace hackrf::one; -using namespace portapack; - #include "radio.hpp" #include "audio.hpp" - #include "dsp_fir_taps.hpp" #include "dsp_iir.hpp" #include "dsp_iir_config.hpp" #include "utility.hpp" +using namespace hackrf::one; +using namespace portapack; + namespace { static constexpr std::array am_configs{{ @@ -62,12 +61,12 @@ static constexpr std::array wfm_configs{{ } /* namespace */ -rf::Frequency ReceiverModel::tuning_frequency() const { - return persistent_memory::tuned_frequency(); +rf::Frequency ReceiverModel::target_frequency() const { + return persistent_memory::target_frequency(); } -void ReceiverModel::set_tuning_frequency(rf::Frequency f) { - persistent_memory::set_tuned_frequency(f); +void ReceiverModel::set_target_frequency(rf::Frequency f) { + persistent_memory::set_target_frequency(f); update_tuning_frequency(); } @@ -146,13 +145,14 @@ void ReceiverModel::set_headphone_volume(volume_t v) { update_headphone_volume(); } -int32_t ReceiverModel::normalized_headphone_volume() const { - return (headphone_volume() - audio::headphone::volume_range().max).decibel() + 99; +uint8_t ReceiverModel::normalized_headphone_volume() const { + auto db = (headphone_volume() - audio::headphone::volume_range().max).decibel(); + return clip(db + 99, 0, 99); } -void ReceiverModel::set_normalized_headphone_volume(int32_t v) { +void ReceiverModel::set_normalized_headphone_volume(uint8_t v) { // TODO: Linear map instead to ensure 0 is minimal value or fix volume_range_t::normalize. - v = clip(v, 0, 99); + v = clip(v, 0, 99); auto new_volume = volume_t::decibel(v - 99) + audio::headphone::volume_range().max; set_headphone_volume(new_volume); } @@ -190,10 +190,6 @@ void ReceiverModel::disable() { // TODO: Responsibility for enabling/disabling the radio is muddy. // Some happens in ReceiverModel, some inside radio namespace. radio::disable(); - - // TODO: we are doing this repeatedly in different levels of the - // call stack. Keeping it for now, but there seem to be too many - // redundant calls: led_rx.off(); } @@ -206,7 +202,8 @@ int32_t ReceiverModel::tuning_offset() { } void ReceiverModel::update_tuning_frequency() { - radio::set_tuning_frequency(persistent_memory::tuned_frequency() + tuning_offset()); + // TODO: use positive offset if freq < offset. + radio::set_tuning_frequency(target_frequency() + tuning_offset()); } void ReceiverModel::update_antenna_bias() { @@ -251,6 +248,32 @@ void ReceiverModel::set_wfm_configuration(const size_t n) { } } +void ReceiverModel::set_configuration_without_init( + const Mode new_mode, + const rf::Frequency new_frequency_step, + const size_t new_am_config_index, + const size_t new_nbfm_config_index, + const size_t new_wfm_config_index, + uint8_t new_squelch_level) { + mode_ = new_mode; + frequency_step_ = new_frequency_step; + am_config_index = new_am_config_index; + nbfm_config_index = new_nbfm_config_index; + wfm_config_index = new_wfm_config_index; + squelch_level_ = new_squelch_level; +} + +void ReceiverModel::configure_from_app_settings( + const app_settings::AppSettings& settings) { + set_target_frequency(settings.rx_frequency); + baseband_bandwidth_ = settings.baseband_bandwidth; + sampling_rate_ = settings.sampling_rate; + lna_gain_db_ = settings.lna; + vga_gain_db_ = settings.vga; + rf_amp_ = settings.rx_amp; + squelch_level_ = settings.squelch; +} + void ReceiverModel::update_sampling_rate() { // TODO: Move more low-level radio control stuff to M4. It'll enable tighter // synchronization for things like wideband (sweeping) spectrum analysis, and @@ -309,12 +332,3 @@ size_t ReceiverModel::wfm_configuration() const { void ReceiverModel::update_wfm_configuration() { wfm_configs[wfm_config_index].apply(); } - -void ReceiverModel::set_configuration_without_init(const Mode new_mode, const rf::Frequency new_frequency_step, const size_t new_am_config_index, const size_t new_nbfm_config_index, const size_t new_wfm_config_index, uint8_t new_squelch_level) { - mode_ = new_mode; - frequency_step_ = new_frequency_step; - am_config_index = new_am_config_index; - nbfm_config_index = new_nbfm_config_index; - wfm_config_index = new_wfm_config_index; - squelch_level_ = new_squelch_level; -} diff --git a/firmware/application/receiver_model.hpp b/firmware/application/receiver_model.hpp index b5e4b6613..d3cc19ee2 100644 --- a/firmware/application/receiver_model.hpp +++ b/firmware/application/receiver_model.hpp @@ -25,12 +25,14 @@ #include #include +#include "app_settings.hpp" #include "message.hpp" #include "rf_path.hpp" #include "max283x.hpp" #include "volume.hpp" // TODO: consider a base class for ReceiverModel & TransmitterModel. +// There are multiple values that are actually shared by both. class ReceiverModel { public: enum class Mode { @@ -41,8 +43,9 @@ class ReceiverModel { Capture = 4 }; - rf::Frequency tuning_frequency() const; - void set_tuning_frequency(rf::Frequency f); + /* The frequency to receive (no offset). */ + rf::Frequency target_frequency() const; + void set_target_frequency(rf::Frequency f); rf::Frequency frequency_step() const; void set_frequency_step(rf::Frequency f); @@ -71,8 +74,8 @@ class ReceiverModel { void set_headphone_volume(volume_t v); /* Volume range 0-99, normalized for audio HW. */ - int32_t normalized_headphone_volume() const; - void set_normalized_headphone_volume(int32_t v); + uint8_t normalized_headphone_volume() const; + void set_normalized_headphone_volume(uint8_t v); uint8_t squelch_level() const; void set_squelch_level(uint8_t v); @@ -97,6 +100,8 @@ class ReceiverModel { const size_t new_wfm_config_index, uint8_t new_squelch_level); + void configure_from_app_settings(const app_settings::AppSettings& settings); + private: rf::Frequency frequency_step_{25000}; bool enabled_{false}; @@ -119,7 +124,6 @@ class ReceiverModel { void update_lna(); void update_baseband_bandwidth(); void update_vga(); - // void update_tx_gain(); void update_sampling_rate(); void update_headphone_volume(); diff --git a/firmware/application/transmitter_model.cpp b/firmware/application/transmitter_model.cpp index ebc73c05d..1bd597adb 100644 --- a/firmware/application/transmitter_model.cpp +++ b/firmware/application/transmitter_model.cpp @@ -27,20 +27,20 @@ #include "portapack_persistent_memory.hpp" #include "hackrf_gpio.hpp" #include "portapack.hpp" -using namespace hackrf::one; -using namespace portapack; - #include "rtc_time.hpp" #include "event_m0.hpp" #include "radio.hpp" #include "audio.hpp" -rf::Frequency TransmitterModel::tuning_frequency() const { - return persistent_memory::tuned_frequency(); +using namespace hackrf::one; +using namespace portapack; + +rf::Frequency TransmitterModel::target_frequency() const { + return persistent_memory::target_frequency(); } -void TransmitterModel::set_tuning_frequency(rf::Frequency f) { - persistent_memory::set_tuned_frequency(f); +void TransmitterModel::set_target_frequency(rf::Frequency f) { + persistent_memory::set_target_frequency(f); update_tuning_frequency(); } @@ -131,6 +131,7 @@ void TransmitterModel::enable() { signal_token_tick_second = rtc_time::signal_tick_second += [this]() { this->on_tick_second(); }; + if (portapack::persistent_memory::stealth_mode()) { DisplaySleepMessage message; EventDispatcher::send_message(message); @@ -140,16 +141,29 @@ void TransmitterModel::enable() { void TransmitterModel::disable() { enabled_ = false; - // TODO: Responsibility for enabling/disabling the radio is muddy. - // Some happens in ReceiverModel, some inside radio namespace. radio::disable(); rtc_time::signal_tick_second -= signal_token_tick_second; led_tx.off(); } +void TransmitterModel::configure_from_app_settings( + const app_settings::AppSettings& settings) { + set_target_frequency(settings.tx_frequency); + + baseband_bandwidth_ = settings.baseband_bandwidth; + channel_bandwidth_ = settings.channel_bandwidth; + tx_gain_db_ = settings.tx_gain; + rf_amp_ = settings.tx_amp; + + // TODO: Do these make sense for TX? + lna_gain_db_ = settings.lna; + vga_gain_db_ = settings.vga; + sampling_rate_ = settings.sampling_rate; +} + void TransmitterModel::update_tuning_frequency() { - radio::set_tuning_frequency(persistent_memory::tuned_frequency()); + radio::set_tuning_frequency(persistent_memory::target_frequency()); } void TransmitterModel::update_antenna_bias() { diff --git a/firmware/application/transmitter_model.hpp b/firmware/application/transmitter_model.hpp index fc4688744..77b46acc6 100644 --- a/firmware/application/transmitter_model.hpp +++ b/firmware/application/transmitter_model.hpp @@ -27,6 +27,7 @@ #include #include "receiver_model.hpp" +#include "app_settings.hpp" #include "message.hpp" #include "rf_path.hpp" #include "max2837.hpp" @@ -35,35 +36,42 @@ class TransmitterModel { public: - rf::Frequency tuning_frequency() const; - void set_tuning_frequency(rf::Frequency f); + /* The frequency to transmit on. */ + rf::Frequency target_frequency() const; + void set_target_frequency(rf::Frequency f); void set_antenna_bias(); bool rf_amp() const; void set_rf_amp(bool enabled); + // TODO: does this make sense on TX? int32_t lna() const; void set_lna(int32_t v_db); uint32_t baseband_bandwidth() const; void set_baseband_bandwidth(uint32_t v); + // TODO: does this make sense on TX? int32_t vga() const; void set_vga(int32_t v_db); int32_t tx_gain() const; void set_tx_gain(int32_t v_db); + // TODO: Doesn't actually affect radio. uint32_t channel_bandwidth() const; void set_channel_bandwidth(uint32_t v); + // TODO: does this make sense on TX? uint32_t sampling_rate() const; void set_sampling_rate(uint32_t v); void enable(); void disable(); + void configure_from_app_settings(const app_settings::AppSettings& settings); + private: bool enabled_{false}; bool rf_amp_{false}; diff --git a/firmware/application/ui/ui_receiver.cpp b/firmware/application/ui/ui_receiver.cpp index 1614769aa..918bb5205 100644 --- a/firmware/application/ui/ui_receiver.cpp +++ b/firmware/application/ui/ui_receiver.cpp @@ -350,7 +350,6 @@ LNAGainField::LNAGainField( } void LNAGainField::on_focus() { - // Widget::on_focus(); if (on_show_options) { on_show_options(); } @@ -375,7 +374,6 @@ VGAGainField::VGAGainField( } void VGAGainField::on_focus() { - // Widget::on_focus(); if (on_show_options) { on_show_options(); } diff --git a/firmware/application/ui/ui_receiver.hpp b/firmware/application/ui/ui_receiver.hpp index a9ae5ad05..b331cab9d 100644 --- a/firmware/application/ui/ui_receiver.hpp +++ b/firmware/application/ui/ui_receiver.hpp @@ -36,6 +36,7 @@ namespace ui { +// TODO: build in support for editing. class FrequencyField : public Widget { public: std::function on_change{}; diff --git a/firmware/application/ui/ui_transmitter.cpp b/firmware/application/ui/ui_transmitter.cpp index b0218e4ca..3b6a29583 100644 --- a/firmware/application/ui/ui_transmitter.cpp +++ b/firmware/application/ui/ui_transmitter.cpp @@ -20,17 +20,18 @@ * Boston, MA 02110-1301, USA. */ +// TODO: Consolidate and make TX Widgets instead like ui_receiver. + #include "ui_transmitter.hpp" #include "audio.hpp" #include "baseband_api.hpp" #include "portapack.hpp" -using namespace portapack; - #include "string_format.hpp" - #include "max2837.hpp" +using namespace portapack; + namespace ui { /* TransmitterView *******************************************************/ @@ -52,11 +53,12 @@ void TransmitterView::paint(Painter& painter) { } } -void TransmitterView::on_tuning_frequency_changed(rf::Frequency f) { - transmitter_model.set_tuning_frequency(f); +void TransmitterView::on_target_frequency_changed(rf::Frequency f) { + transmitter_model.set_target_frequency(f); } void TransmitterView::on_channel_bandwidth_changed(uint32_t channel_bandwidth) { + // TODO: this doesn't actually affect the radio through the model. transmitter_model.set_channel_bandwidth(channel_bandwidth); } @@ -101,7 +103,7 @@ void TransmitterView::set_transmitting(const bool transmitting) { } void TransmitterView::on_show() { - field_frequency.set_value(transmitter_model.tuning_frequency()); + field_frequency.set_value(transmitter_model.target_frequency()); field_frequency_step.set_by_value(receiver_model.frequency_step()); field_gain.set_value(transmitter_model.tx_gain()); @@ -138,6 +140,7 @@ TransmitterView::TransmitterView( field_frequency.set_focusable(false); field_frequency.set_style(&style_locked); } else { + // TODO: Make a widget. if (channel_bandwidth) { add_children({&text_bw, &field_bw}); @@ -149,10 +152,9 @@ TransmitterView::TransmitterView( } } - // field_frequency.set_value(transmitter_model.tuning_frequency()); field_frequency.set_step(frequency_step); field_frequency.on_change = [this](rf::Frequency f) { - on_tuning_frequency_changed(f); + on_target_frequency_changed(f); }; field_frequency.on_edit = [this]() { if (on_edit_frequency) @@ -189,14 +191,10 @@ TransmitterView::~TransmitterView() { } /* TransmitterView2 *******************************************************/ -// Derivative from TransmitterView (that handles many param. freq, fre_step, start_button, gain, amp, used in the majority of the TX App's. -// This one ,is a simple version , it is only handling 2 x param (TX GAIN and AMP ) in one line . -// We use normal character lines , in Mic App, called (x pos, y pos, NORMAL_UI) -// We use short compact char lines , in Replay / GPS Simul / Playlist App , called (x pos , y pos,SHORT_UI ) - -void TransmitterView2::paint(Painter& painter) { - // Not using TransmitterView2, but if we delete it,we got , top line 1 a blanking rect. - (void)painter; // Avoid warning: unused parameter . +/* Simpler transmitter view that only renders TX Gain and Amp. + * There are two modes, NORMAL_UI and SHORT_UI. SHORT_UI abbreviates control labels. */ +void TransmitterView2::paint(Painter&) { + // All widgets paint themselves. Don't let base paint. } void TransmitterView2::on_tx_gain_changed(int32_t tx_gain) { @@ -241,7 +239,7 @@ void TransmitterView2::on_show() { } TransmitterView2::TransmitterView2(const Coord x, const Coord y, bool short_UI) { - set_parent_rect({x, y, 20 * 8, 1 * 8}); // set_parent_rect({ 0, y, 30 * 8, 6 * 8 }); + set_parent_rect({x, y, 20 * 8, 1 * 8}); add_children({ &(short_UI ? text_gain_amp_short_UI : text_gain_amp), diff --git a/firmware/application/ui/ui_transmitter.hpp b/firmware/application/ui/ui_transmitter.hpp index 9de7f79d6..d023058ca 100644 --- a/firmware/application/ui/ui_transmitter.hpp +++ b/firmware/application/ui/ui_transmitter.hpp @@ -126,7 +126,7 @@ class TransmitterView : public View { {10 * 8 - 4, 1 * 8}, }; - void on_tuning_frequency_changed(rf::Frequency f); + void on_target_frequency_changed(rf::Frequency f); void on_channel_bandwidth_changed(uint32_t channel_bandwidth); void on_tx_gain_changed(int32_t tx_gain); void on_tx_amp_changed(bool rf_amp); diff --git a/firmware/application/ui_navigation.cpp b/firmware/application/ui_navigation.cpp index 0c422a2ae..9166cd5ab 100644 --- a/firmware/application/ui_navigation.cpp +++ b/firmware/application/ui_navigation.cpp @@ -217,9 +217,9 @@ void SystemStatusView::refresh() { button_converter.set_foreground(Color::light_grey()); } } - // Retune to take converter change in account - receiver_model.set_tuning_frequency(portapack::persistent_memory::tuned_frequency()); - transmitter_model.set_tuning_frequency(portapack::persistent_memory::tuned_frequency()); + // Poke tunings to take converter change in account. + receiver_model.set_target_frequency(receiver_model.target_frequency()); + transmitter_model.set_target_frequency(transmitter_model.target_frequency()); if (!portapack::persistent_memory::config_speaker()) { button_speaker.set_foreground(Color::light_grey()); @@ -284,7 +284,9 @@ void SystemStatusView::on_converter() { portapack::persistent_memory::set_config_converter(false); button_converter.set_foreground(Color::light_grey()); } - receiver_model.set_tuning_frequency(portapack::persistent_memory::tuned_frequency()); // Retune + + // Poke to update tuning. + receiver_model.set_target_frequency(receiver_model.target_frequency()); } void SystemStatusView::on_speaker() { diff --git a/firmware/application/ui_record_view.cpp b/firmware/application/ui_record_view.cpp index eaf9fc524..2de67e932 100644 --- a/firmware/application/ui_record_view.cpp +++ b/firmware/application/ui_record_view.cpp @@ -168,7 +168,7 @@ void RecordView::start() { to_string_dec_uint(datetime.second()); base_path = filename_stem_pattern.string() + "_" + date_time + "_" + - trim(to_string_freq(receiver_model.tuning_frequency())) + "Hz"; + trim(to_string_freq(receiver_model.target_frequency())) + "Hz"; base_path = folder / base_path; } else { base_path = next_filename_matching_pattern(folder / filename_stem_pattern); @@ -185,7 +185,7 @@ void RecordView::start() { auto create_error = p->create( base_path.replace_extension(u".WAV"), sampling_rate, - to_string_dec_uint(receiver_model.tuning_frequency()) + "Hz"); + to_string_dec_uint(receiver_model.target_frequency()) + "Hz"); if (create_error.is_valid()) { handle_error(create_error.value()); } else { @@ -256,7 +256,7 @@ Optional RecordView::write_metadata_file(const std::filesystem::pat if (error_line1.is_valid()) { return error_line1; } - const auto error_line2 = file.write_line("center_frequency=" + to_string_dec_uint(receiver_model.tuning_frequency())); + const auto error_line2 = file.write_line("center_frequency=" + to_string_dec_uint(receiver_model.target_frequency())); if (error_line2.is_valid()) { return error_line2; } diff --git a/firmware/common/portapack_persistent_memory.cpp b/firmware/common/portapack_persistent_memory.cpp index 97d3bfc76..54fd1cc0b 100644 --- a/firmware/common/portapack_persistent_memory.cpp +++ b/firmware/common/portapack_persistent_memory.cpp @@ -46,7 +46,7 @@ using namespace std; namespace portapack { namespace persistent_memory { -constexpr rf::Frequency tuned_frequency_reset_value{100000000}; +constexpr rf::Frequency target_frequency_reset_value{100000000}; using ppb_range_t = range_t; constexpr ppb_range_t ppb_range{-99000, 99000}; @@ -257,7 +257,7 @@ struct ui_config_t { /* struct must pack the same way on M4 and M0 cores. */ struct data_t { data_structure_version_enum structure_version; - int64_t tuned_frequency; + int64_t target_frequency; int32_t correction_ppb; uint32_t touch_calibration_magic; touch::Calibration touch_calibration; @@ -313,7 +313,7 @@ struct data_t { constexpr data_t() : structure_version(data_structure_version_enum::VERSION_CURRENT), - tuned_frequency(tuned_frequency_reset_value), + target_frequency(target_frequency_reset_value), correction_ppb(ppb_reset_value), touch_calibration_magic(TOUCH_CALIBRATION_MAGIC), touch_calibration(touch::Calibration()), @@ -471,13 +471,13 @@ void persist() { } /* namespace cache */ -rf::Frequency tuned_frequency() { - rf::tuning_range.reset_if_outside(data->tuned_frequency, tuned_frequency_reset_value); - return data->tuned_frequency; +rf::Frequency target_frequency() { + rf::tuning_range.reset_if_outside(data->target_frequency, target_frequency_reset_value); + return data->target_frequency; } -void set_tuned_frequency(const rf::Frequency new_value) { - data->tuned_frequency = rf::tuning_range.clip(new_value); +void set_target_frequency(const rf::Frequency new_value) { + data->target_frequency = rf::tuning_range.clip(new_value); } volume_t headphone_volume() { diff --git a/firmware/common/portapack_persistent_memory.hpp b/firmware/common/portapack_persistent_memory.hpp index d1eb3990a..7d4d47542 100644 --- a/firmware/common/portapack_persistent_memory.hpp +++ b/firmware/common/portapack_persistent_memory.hpp @@ -130,8 +130,8 @@ void persist(); using ppb_t = int32_t; -rf::Frequency tuned_frequency(); -void set_tuned_frequency(const rf::Frequency new_value); +rf::Frequency target_frequency(); +void set_target_frequency(const rf::Frequency new_value); volume_t headphone_volume(); void set_headphone_volume(volume_t new_value); diff --git a/firmware/common/result.hpp b/firmware/common/result.hpp new file mode 100644 index 000000000..0c87c6cb8 --- /dev/null +++ b/firmware/common/result.hpp @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2023 Kyle Reed + * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2016 Furrtek + * + * This file is part of PortaPack. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include + +template +struct Result { + enum class Type { + Success, + Error, + } type; + + union { + TValue value_; + TError error_; + }; + + bool is_ok() const { + return type == Type::Success; + } + + operator bool() const { + return is_ok(); + } + + bool is_error() const { + return type == Type::Error; + } + + const TValue& value() const& { + return value_; + } + + const TValue& operator*() const& { + return value_; + } + + TValue&& operator*() && { + return std::move(value_); + } + + const TError& error() const& { + return error_; + } + + Result() = delete; + + constexpr Result(TValue&& value) + : type{Type::Success}, + value_{std::forward(value)} { + } + + constexpr Result(TError error) + : type{Type::Error}, + error_{error} { + } + + ~Result() { + if (is_ok()) + value_.~TValue(); + else + error_.~TError(); + } +}; \ No newline at end of file diff --git a/firmware/common/ui_widget.cpp b/firmware/common/ui_widget.cpp index 8db0e4f8a..7b17a83aa 100644 --- a/firmware/common/ui_widget.cpp +++ b/firmware/common/ui_widget.cpp @@ -1362,14 +1362,21 @@ void ImageOptionsField::set_by_value(value_t v) { for (const auto& option : options) { if (option.second == v) { set_selected_index(new_index); - break; + return; } + new_index++; } + + // No exact match was found, default to 0. + set_selected_index(0); } void ImageOptionsField::set_options(options_t new_options) { options = new_options; + + // Set an invalid index to force on_change. + selected_index_ = (size_t)-1; set_by_value(0); set_dirty(); } @@ -1440,19 +1447,25 @@ void OptionsField::set_selected_index(const size_t new_index, bool trigger_chang } void OptionsField::set_by_value(value_t v) { - size_t new_index{0}; + size_t new_index = 0; for (const auto& option : options) { if (option.second == v) { set_selected_index(new_index); - break; + return; } new_index++; } + + // No exact match was found, default to 0. + set_selected_index(0); } void OptionsField::set_options(options_t new_options) { options = new_options; - set_by_value(0); + + // Set an invalid index to force on_change. + selected_index_ = (size_t)-1; + set_selected_index(0); set_dirty(); } diff --git a/firmware/common/utility.hpp b/firmware/common/utility.hpp index 6e29eebd1..007776ec6 100644 --- a/firmware/common/utility.hpp +++ b/firmware/common/utility.hpp @@ -94,6 +94,14 @@ int fast_int_magnitude(int y, int x); int int_atan2(int y, int x); int32_t int16_sin_s4(int32_t x); +template +bool flags_enabled(TEnum value, TEnum flags) { + auto i_value = static_cast>(value); + auto i_flags = static_cast>(flags); + + return (i_value & i_flags) == i_flags; +} + /* Returns value constrained to min and max. */ template constexpr const T& clip(const T& value, const T& minimum, const T& maximum) { diff --git a/firmware/test/application/CMakeLists.txt b/firmware/test/application/CMakeLists.txt index d11bd4735..082922226 100644 --- a/firmware/test/application/CMakeLists.txt +++ b/firmware/test/application/CMakeLists.txt @@ -38,6 +38,7 @@ add_executable(application_test EXCLUDE_FROM_ALL ${PROJECT_SOURCE_DIR}/test_circular_buffer.cpp ${PROJECT_SOURCE_DIR}/test_file_wrapper.cpp ${PROJECT_SOURCE_DIR}/test_optional.cpp + ${PROJECT_SOURCE_DIR}/test_utility.cpp ) target_include_directories(application_test PRIVATE diff --git a/firmware/test/application/test_utility.cpp b/firmware/test/application/test_utility.cpp new file mode 100644 index 000000000..eb946992e --- /dev/null +++ b/firmware/test/application/test_utility.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2023 + * + * This file is part of PortaPack. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "doctest.h" +#include "utility.hpp" + +TEST_SUITE_BEGIN("flags_enabled"); + +enum class Flags : uint8_t { + A = 0x1, + B = 0x2, + C = 0x4, +}; + +TEST_CASE("When flag set, flags_enabled should be true.") { + Flags f = Flags::A; + CHECK(flags_enabled(f, Flags::A)); +} + +TEST_CASE("When flag not set, flags_enabled should be false.") { + Flags f = Flags::B; + CHECK(flags_enabled(f, Flags::A) == false); +} + +TEST_SUITE_END(); \ No newline at end of file