diff --git a/firmware/application/app_settings.cpp b/firmware/application/app_settings.cpp index 020f4bb0e..7d662dbd2 100644 --- a/firmware/application/app_settings.cpp +++ b/firmware/application/app_settings.cpp @@ -189,10 +189,17 @@ ResultCode save_settings(const std::string& app_name, AppSettings& settings) { 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)) + if (flags_enabled(settings.mode, Mode::TX)) { + if (!flags_enabled(settings.options, Options::UseGlobalTargetFrequency)) + transmitter_model.set_target_frequency(settings.tx_frequency); + transmitter_model.configure_from_app_settings(settings); + } if (flags_enabled(settings.mode, Mode::RX)) { + if (!flags_enabled(settings.options, Options::UseGlobalTargetFrequency)) + transmitter_model.set_target_frequency(settings.rx_frequency); + receiver_model.configure_from_app_settings(settings); receiver_model.set_configuration_without_init( static_cast(settings.modulation), @@ -241,11 +248,15 @@ void copy_from_radio_model(AppSettings& settings) { } /* SettingsManager *************************************************/ -SettingsManager::SettingsManager(std::string app_name, Mode mode) +SettingsManager::SettingsManager( + std::string app_name, + Mode mode, + Options options) : app_name_{std::move(app_name)}, settings_{}, loaded_{false} { settings_.mode = mode; + settings_.options = options; auto result = load_settings(app_name_, settings_); if (result == ResultCode::Ok) { diff --git a/firmware/application/app_settings.hpp b/firmware/application/app_settings.hpp index bf03af972..b92f6476e 100644 --- a/firmware/application/app_settings.hpp +++ b/firmware/application/app_settings.hpp @@ -30,6 +30,7 @@ #include #include "file.hpp" +#include "max283x.hpp" #include "string_format.hpp" namespace app_settings { @@ -47,25 +48,34 @@ enum class Mode : uint8_t { RX_TX = 0x03, // Both TX/RX }; +enum class Options { + None = 0x0000, + + /* Don't use target frequency from app settings. */ + UseGlobalTargetFrequency = 0x0001, +}; + // TODO: separate types for TX/RX or union? +/* NB: See RX/TX model headers for default values. */ 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; + Mode mode = Mode::RX; + Options options = Options::None; + uint32_t baseband_bandwidth = max283x::filter::bandwidth_minimum; + uint32_t sampling_rate = 3072000; // Good for 48k audio. + uint8_t lna = 32; + uint8_t vga = 32; + uint8_t rx_amp = 0; + uint8_t tx_amp = 0; + uint8_t tx_gain = 35; + uint32_t channel_bandwidth = 1; 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; + uint32_t step = 25000; + uint8_t modulation = 1; // NFM + uint8_t am_config_index = 0; + uint8_t nbfm_config_index = 0; + uint8_t wfm_config_index = 0; + uint8_t squelch = 80; uint8_t volume; }; @@ -84,7 +94,7 @@ void copy_from_radio_model(AppSettings& settings); * the receiver/transmitter models are set before the control ctors run. */ class SettingsManager { public: - SettingsManager(std::string app_name, Mode mode); + SettingsManager(std::string app_name, Mode mode, Options options = Options::None); ~SettingsManager(); SettingsManager(const SettingsManager&) = delete; @@ -106,4 +116,7 @@ class SettingsManager { } // namespace app_settings +ENABLE_FLAGS_OPERATORS(app_settings::Mode); +ENABLE_FLAGS_OPERATORS(app_settings::Options); + #endif /*__APP_SETTINGS_H__*/ diff --git a/firmware/application/apps/analog_audio_app.hpp b/firmware/application/apps/analog_audio_app.hpp index f20944dcd..35e3dc7fb 100644 --- a/firmware/application/apps/analog_audio_app.hpp +++ b/firmware/application/apps/analog_audio_app.hpp @@ -156,7 +156,8 @@ class AnalogAudioView : public View { static constexpr ui::Dim header_height = 3 * 16; app_settings::SettingsManager settings_{ - "rx_audio", app_settings::Mode::RX}; + "rx_audio", app_settings::Mode::RX, + app_settings::Options::UseGlobalTargetFrequency}; 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}; diff --git a/firmware/application/apps/ui_mictx.hpp b/firmware/application/apps/ui_mictx.hpp index bc8b7ab9f..e35bebdb8 100644 --- a/firmware/application/apps/ui_mictx.hpp +++ b/firmware/application/apps/ui_mictx.hpp @@ -81,7 +81,8 @@ class MicTXView : public View { void set_ptt_visibility(bool v); app_settings::SettingsManager settings_{ - "tx_mic", app_settings::Mode::RX_TX}; + "tx_mic", app_settings::Mode::RX_TX, + app_settings::Options::UseGlobalTargetFrequency}; bool transmitting{false}; bool va_enabled{false}; diff --git a/firmware/application/receiver_model.cpp b/firmware/application/receiver_model.cpp index a7be1b082..e4559829f 100644 --- a/firmware/application/receiver_model.cpp +++ b/firmware/application/receiver_model.cpp @@ -265,7 +265,6 @@ void ReceiverModel::set_configuration_without_init( 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; diff --git a/firmware/application/transmitter_model.cpp b/firmware/application/transmitter_model.cpp index 1bd597adb..e626f3531 100644 --- a/firmware/application/transmitter_model.cpp +++ b/firmware/application/transmitter_model.cpp @@ -149,8 +149,6 @@ void TransmitterModel::disable() { 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; @@ -163,7 +161,7 @@ void TransmitterModel::configure_from_app_settings( } void TransmitterModel::update_tuning_frequency() { - radio::set_tuning_frequency(persistent_memory::target_frequency()); + radio::set_tuning_frequency(target_frequency()); } void TransmitterModel::update_antenna_bias() { diff --git a/firmware/application/ui/ui_transmitter.cpp b/firmware/application/ui/ui_transmitter.cpp index 3b6a29583..bd47da546 100644 --- a/firmware/application/ui/ui_transmitter.cpp +++ b/firmware/application/ui/ui_transmitter.cpp @@ -104,7 +104,6 @@ void TransmitterView::set_transmitting(const bool transmitting) { void TransmitterView::on_show() { 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()); field_amp.set_value(transmitter_model.rf_amp() ? 14 : 0); @@ -152,7 +151,6 @@ TransmitterView::TransmitterView( } } - field_frequency.set_step(frequency_step); field_frequency.on_change = [this](rf::Frequency f) { on_target_frequency_changed(f); }; @@ -162,8 +160,11 @@ TransmitterView::TransmitterView( }; field_frequency_step.on_change = [this](size_t, OptionsField::value_t v) { + receiver_model.set_frequency_step(v); this->field_frequency.set_step(v); }; + // TODO: Shouldn't be a ctor parameter because it doesn't work with app settings. + field_frequency_step.set_by_value(frequency_step); field_gain.on_change = [this](uint32_t tx_gain) { on_tx_gain_changed(tx_gain); diff --git a/firmware/common/utility.hpp b/firmware/common/utility.hpp index 007776ec6..b3bf394cd 100644 --- a/firmware/common/utility.hpp +++ b/firmware/common/utility.hpp @@ -95,7 +95,25 @@ int int_atan2(int y, int x); int32_t int16_sin_s4(int32_t x); template -bool flags_enabled(TEnum value, TEnum flags) { +struct is_flags_type { + static constexpr bool value = false; +}; + +template +constexpr bool is_flags_type_v = is_flags_type::value; + +#define ENABLE_FLAGS_OPERATORS(type) \ + template <> \ + struct is_flags_type { static constexpr bool value = true; }; + +template +constexpr std::enable_if_t, TEnum> operator|(TEnum a, TEnum b) { + using under_t = std::underlying_type_t; + return static_cast(static_cast(a) | static_cast(b)); +} + +template +constexpr std::enable_if_t, bool> flags_enabled(TEnum value, TEnum flags) { auto i_value = static_cast>(value); auto i_flags = static_cast>(flags); diff --git a/firmware/test/application/test_utility.cpp b/firmware/test/application/test_utility.cpp index eb946992e..e3197fe1e 100644 --- a/firmware/test/application/test_utility.cpp +++ b/firmware/test/application/test_utility.cpp @@ -22,7 +22,7 @@ #include "doctest.h" #include "utility.hpp" -TEST_SUITE_BEGIN("flags_enabled"); +TEST_SUITE_BEGIN("Flags operators"); enum class Flags : uint8_t { A = 0x1, @@ -30,14 +30,21 @@ enum class Flags : uint8_t { C = 0x4, }; +ENABLE_FLAGS_OPERATORS(Flags); + +TEST_CASE("operator| should combine flags.") { + constexpr Flags f = Flags::A | Flags::C; + static_assert(static_cast(f) == 5); +} + TEST_CASE("When flag set, flags_enabled should be true.") { - Flags f = Flags::A; - CHECK(flags_enabled(f, Flags::A)); + constexpr Flags f = Flags::A; + static_assert(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); + constexpr Flags f = Flags::B; + static_assert(flags_enabled(f, Flags::A) == false); } TEST_SUITE_END(); \ No newline at end of file