diff --git a/firmware/application/apps/ui_settings.cpp b/firmware/application/apps/ui_settings.cpp index 3f5708b3b..3d919bbe9 100644 --- a/firmware/application/apps/ui_settings.cpp +++ b/firmware/application/apps/ui_settings.cpp @@ -144,6 +144,7 @@ SetRadioView::SetRadioView( } add_children({ + &check_clkout, &labels_bias, &check_bias, &button_done, @@ -156,6 +157,14 @@ SetRadioView::SetRadioView( form_init(model); + check_clkout.set_value(portapack::persistent_memory::clkout_enabled()); + check_clkout.on_select = [this](Checkbox&, bool v) { + clock_manager.enable_clock_output(v); + portapack::persistent_memory::set_clkout_enabled(v); + StatusRefreshMessage message { }; + EventDispatcher::send_message(message); + }; + check_bias.set_value(portapack::get_antenna_bias()); check_bias.on_select = [this](Checkbox&, bool v) { portapack::set_antenna_bias(v); diff --git a/firmware/application/apps/ui_settings.hpp b/firmware/application/apps/ui_settings.hpp index 076ede036..4b9f99d43 100644 --- a/firmware/application/apps/ui_settings.hpp +++ b/firmware/application/apps/ui_settings.hpp @@ -147,8 +147,14 @@ private: }; Labels labels_correction { - { { 2 * 8, 4 * 16 }, "Frequency correction:", Color::light_grey() }, - { { 6 * 8, 5 * 16 }, "PPM", Color::light_grey() }, + { { 2 * 8, 3 * 16 }, "Frequency correction:", Color::light_grey() }, + { { 6 * 8, 4 * 16 }, "PPM", Color::light_grey() }, + }; + + Checkbox check_clkout { + { 28, (6 * 16 - 4) }, + 4, + "Enable 10MHz CLKOUT" }; Labels labels_bias { @@ -159,7 +165,7 @@ private: }; NumberField field_ppm { - { 2 * 8, 5 * 16 }, + { 2 * 8, 4 * 16 }, 3, { -50, 50 }, 1, diff --git a/firmware/application/clock_manager.cpp b/firmware/application/clock_manager.cpp index 088cf17fb..ec08452b6 100644 --- a/firmware/application/clock_manager.cpp +++ b/firmware/application/clock_manager.cpp @@ -463,3 +463,17 @@ void ClockManager::stop_audio_pll() { cgu::pll0audio::power_down(); while( cgu::pll0audio::is_locked() ); } + +void ClockManager::enable_clock_output(bool enable) { + if(enable) { + clock_generator.enable_output(clock_generator_output_clkout); + clock_generator.set_ms_frequency(clock_generator_output_clkout, 10000000, si5351_vco_f, 0); + } else { + clock_generator.disable_output(clock_generator_output_clkout); + } + + if(enable) + clock_generator.set_clock_control(clock_generator_output_clkout, si5351_clock_control_common[clock_generator_output_clkout].ms_src(get_reference_clock_generator_pll(reference.source)).clk_pdn(ClockControl::ClockPowerDown::Power_On)); + else + clock_generator.set_clock_control(clock_generator_output_clkout, ClockControl::power_off()); +} diff --git a/firmware/application/clock_manager.hpp b/firmware/application/clock_manager.hpp index 98af620af..0c88bab58 100644 --- a/firmware/application/clock_manager.hpp +++ b/firmware/application/clock_manager.hpp @@ -79,6 +79,8 @@ public: Reference get_reference() const; + void enable_clock_output(bool enable); + private: I2C& i2c0; si5351::Si5351& clock_generator; diff --git a/firmware/application/ui_navigation.cpp b/firmware/application/ui_navigation.cpp index ca6a63347..57ffd4039 100644 --- a/firmware/application/ui_navigation.cpp +++ b/firmware/application/ui_navigation.cpp @@ -113,7 +113,7 @@ SystemStatusView::SystemStatusView( &button_camera, &button_sleep, &button_bias_tee, - &image_clock_status, + &button_clock_status, &sd_card_status_view, }); @@ -168,6 +168,10 @@ SystemStatusView::SystemStatusView( DisplaySleepMessage message; EventDispatcher::send_message(message); }; + + button_clock_status.on_select = [this](ImageButton&) { + this->on_clk(); + }; } void SystemStatusView::refresh() { @@ -188,11 +192,16 @@ void SystemStatusView::refresh() { } if (portapack::clock_manager.get_reference().source == ClockManager::ReferenceSource::External) { - image_clock_status.set_bitmap(&bitmap_icon_clk_ext); - button_bias_tee.set_foreground(ui::Color::green()); + button_clock_status.set_bitmap(&bitmap_icon_clk_ext); +// button_bias_tee.set_foreground(ui::Color::green()); Typo? } else { - image_clock_status.set_bitmap(&bitmap_icon_clk_int); - button_bias_tee.set_foreground(ui::Color::light_grey()); + button_clock_status.set_bitmap(&bitmap_icon_clk_int); +// button_bias_tee.set_foreground(ui::Color::green()); + } + if(portapack::persistent_memory::clkout_enabled()) { + button_clock_status.set_foreground(ui::Color::green()); + } else { + button_clock_status.set_foreground(ui::Color::light_grey()); } set_dirty(); @@ -302,6 +311,18 @@ void SystemStatusView::on_camera() { } } +void SystemStatusView::on_clk() { + bool v = portapack::persistent_memory::clkout_enabled(); + if(v) { + v = false; + } else { + v = true; + } + portapack::clock_manager.enable_clock_output(v); + portapack::persistent_memory::set_clkout_enabled(v); + refresh(); +} + void SystemStatusView::on_title() { if(nav_.is_top()) nav_.push(); diff --git a/firmware/application/ui_navigation.hpp b/firmware/application/ui_navigation.hpp index 7edf6a9db..1537ce4e3 100644 --- a/firmware/application/ui_navigation.hpp +++ b/firmware/application/ui_navigation.hpp @@ -180,7 +180,7 @@ private: Color::dark_grey() }; - Image image_clock_status { + ImageButton button_clock_status { { 27 * 8, 0 * 16, 2 * 8, 1 * 16 }, &bitmap_icon_clk_int, Color::light_grey(), @@ -198,6 +198,7 @@ private: void on_camera(); void on_title(); void refresh(); + void on_clk(); MessageHandlerRegistration message_handler_refresh { Message::ID::StatusRefresh, diff --git a/firmware/common/portapack_persistent_memory.cpp b/firmware/common/portapack_persistent_memory.cpp index 1ee81ffa3..97b9e006e 100644 --- a/firmware/common/portapack_persistent_memory.cpp +++ b/firmware/common/portapack_persistent_memory.cpp @@ -63,6 +63,10 @@ using modem_repeat_range_t = range_t; constexpr modem_repeat_range_t modem_repeat_range { 1, 99 }; constexpr int32_t modem_repeat_reset_value { 5 }; +using clkout_config_range_t = range_t; +constexpr clkout_config_range_t clkout_config_range { 0, 1 }; +constexpr uint32_t clkout_config_reset_value { 0 }; + /* struct must pack the same way on M4 and M0 cores. */ struct data_t { int64_t tuned_frequency; @@ -91,6 +95,8 @@ struct data_t { uint32_t pocsag_ignore_address; int32_t tone_mix; + + uint32_t clkout_config; // TODO: Add custom frequency output? }; static_assert(sizeof(data_t) <= backup_ram.size(), "Persistent memory structure too large for VBAT-maintained region"); @@ -287,5 +293,14 @@ void set_pocsag_ignore_address(uint32_t address) { data->pocsag_ignore_address = address; } +bool clkout_enabled() { + clkout_config_range.reset_if_outside(data->clkout_config, clkout_config_reset_value); + return (bool)(data->clkout_config & 1); +} + +void set_clkout_enabled(bool enable) { + data->clkout_config = (uint32_t)enable; +} + } /* namespace persistent_memory */ } /* namespace portapack */ diff --git a/firmware/common/portapack_persistent_memory.hpp b/firmware/common/portapack_persistent_memory.hpp index be740edb7..6422567a7 100644 --- a/firmware/common/portapack_persistent_memory.hpp +++ b/firmware/common/portapack_persistent_memory.hpp @@ -93,6 +93,9 @@ void set_pocsag_last_address(uint32_t address); uint32_t pocsag_ignore_address(); void set_pocsag_ignore_address(uint32_t address); +bool clkout_enabled(); +void set_clkout_enabled(bool enable); + } /* namespace persistent_memory */ } /* namespace portapack */