From 93799bde6d82f77e4cb5b4fc27233ecb8083afe1 Mon Sep 17 00:00:00 2001 From: Harin Lee Date: Wed, 7 Jan 2026 13:29:56 +0900 Subject: [PATCH] New approach to support RX-only mode more cleanly (#2908) * Add enabled checks in ReceiverModel and TransmitterModel * Move TX limit logic to TransmitterModel from radio API * Add TX disable functionality and UI --- firmware/application/apps/ui_settings.cpp | 7 +++-- firmware/application/apps/ui_settings.hpp | 19 +++++++----- firmware/application/radio.cpp | 14 +++------ firmware/application/receiver_model.cpp | 25 +++++++++++----- firmware/application/transmitter_model.cpp | 30 ++++++++++++++----- firmware/application/ui_navigation.cpp | 8 +++++ firmware/application/ui_navigation.hpp | 8 +++++ firmware/common/message.hpp | 8 +++++ .../common/portapack_persistent_memory.cpp | 17 ++++++++--- .../common/portapack_persistent_memory.hpp | 6 ++-- 10 files changed, 103 insertions(+), 39 deletions(-) diff --git a/firmware/application/apps/ui_settings.cpp b/firmware/application/apps/ui_settings.cpp index f697db0d0..e9072b309 100644 --- a/firmware/application/apps/ui_settings.cpp +++ b/firmware/application/apps/ui_settings.cpp @@ -315,17 +315,20 @@ SetTXLimitView::SetTXLimitView(NavigationView& nav) { add_children({ &labels, &tx_gain_max_db, + &tx_disable_switch, &tx_amp_disable_switch, &button_save, &button_cancel, }); - tx_gain_max_db.set_value(pmem::config_tx_gain_max_db()); + tx_disable_switch.set_value(pmem::config_tx_disabled()); tx_amp_disable_switch.set_value(pmem::config_tx_amp_disabled()); + tx_gain_max_db.set_value(pmem::config_tx_gain_max_db()); button_save.on_select = [&nav, this](Button&) { - pmem::set_config_tx_gain_max_db(tx_gain_max_db.value()); + pmem::set_config_tx_disabled(tx_disable_switch.value()); pmem::set_config_tx_amp_disabled(tx_amp_disable_switch.value()); + pmem::set_config_tx_gain_max_db(tx_gain_max_db.value()); send_system_refresh(); nav.pop(); }; diff --git a/firmware/application/apps/ui_settings.hpp b/firmware/application/apps/ui_settings.hpp index a2f12307d..72d22c908 100644 --- a/firmware/application/apps/ui_settings.hpp +++ b/firmware/application/apps/ui_settings.hpp @@ -277,23 +277,28 @@ class SetTXLimitView : public View { {{1 * 8, 1 * 16}, "Limits RF TX Gain", Theme::getInstance()->fg_light->foreground}, {{1 * 8, 2 * 16}, "(This may affect", Theme::getInstance()->fg_light->foreground}, {{1 * 8, 3 * 16}, "all applications.)", Theme::getInstance()->fg_light->foreground}, - {{2 * 8, 8 * 16}, "TX Gain (Max):", Theme::getInstance()->fg_light->foreground}, + {{2 * 8, 12 * 16}, "TX Max Gain:", Theme::getInstance()->fg_light->foreground}, }; + Checkbox tx_disable_switch{ + {1 * 8, 6 * 16}, + 23, + "Disable TX"}; + + Checkbox tx_amp_disable_switch{ + {1 * 8, 8 * 16}, + 23, + "Disable TX Amp"}; + NumberField tx_gain_max_db{ - {20 * 8, 8 * 16}, + {20 * 8, 12 * 16}, 6, {0, 47}, 1, ' ', }; - Checkbox tx_amp_disable_switch{ - {1 * 8, 12 * 16}, - 23, - "Disable TX Amp"}; - Button button_save{ {UI_POS_X_CENTER(12) - UI_POS_WIDTH(8), UI_POS_Y_BOTTOM(4), UI_POS_WIDTH(12), UI_POS_HEIGHT(2)}, "Save"}; diff --git a/firmware/application/radio.cpp b/firmware/application/radio.cpp index 782e23b20..ea96050a1 100644 --- a/firmware/application/radio.cpp +++ b/firmware/application/radio.cpp @@ -42,8 +42,6 @@ using namespace hackrf::one; #include "portapack.hpp" #include "portapack_persistent_memory.hpp" -#include - /* Direct access to the radio. Setting values incorrectly can damage * the device. Applications should use ReceiverModel or TransmitterModel * instead of calling these functions directly. */ @@ -152,14 +150,10 @@ void set_direction(const rf::Direction new_direction) { baseband_codec.set_mode((direction == rf::Direction::Transmit) ? max5864::Mode::Transmit : max5864::Mode::Receive); - if (direction == rf::Direction::Receive) { + if (direction == rf::Direction::Receive) led_rx.on(); - } else { - if (portapack::persistent_memory::config_tx_amp_disabled()) - rf_path.set_rf_amp(false); - + else led_tx.on(); - } } bool set_tuning_frequency(const rf::Frequency frequency) { @@ -211,7 +205,7 @@ bool set_tuning_frequency(const rf::Frequency frequency) { } void set_rf_amp(const bool rf_amp) { - rf_path.set_rf_amp(rf_amp && (direction != rf::Direction::Transmit || !portapack::persistent_memory::config_tx_amp_disabled())); + rf_path.set_rf_amp(rf_amp); } void set_lna_gain(const int_fast8_t db) { @@ -223,7 +217,7 @@ void set_vga_gain(const int_fast8_t db) { } void set_tx_gain(const int_fast8_t db) { - second_if->set_tx_vga_gain(std::min(static_cast(db), portapack::persistent_memory::config_tx_gain_max_db())); + second_if->set_tx_vga_gain(db); } void set_baseband_filter_bandwidth_rx(const uint32_t bandwidth_minimum) { diff --git a/firmware/application/receiver_model.cpp b/firmware/application/receiver_model.cpp index 8bc3b0695..c96ef6f23 100644 --- a/firmware/application/receiver_model.cpp +++ b/firmware/application/receiver_model.cpp @@ -303,7 +303,8 @@ int32_t ReceiverModel::tuning_offset() { void ReceiverModel::update_tuning_frequency() { // TODO: use positive offset if freq < offset. - radio::set_tuning_frequency(target_frequency() + hidden_offset + tuning_offset()); + if (enabled_) + radio::set_tuning_frequency(target_frequency() + hidden_offset + tuning_offset()); } void ReceiverModel::set_hidden_offset(rf::Frequency offset) { @@ -312,7 +313,8 @@ void ReceiverModel::set_hidden_offset(rf::Frequency offset) { } void ReceiverModel::update_baseband_bandwidth() { - radio::set_baseband_filter_bandwidth_rx(baseband_bandwidth()); + if (enabled_) + radio::set_baseband_filter_bandwidth_rx(baseband_bandwidth()); } void ReceiverModel::update_sampling_rate() { @@ -321,23 +323,31 @@ void ReceiverModel::update_sampling_rate() { // protocols that need quick RX/TX turn-around. // Disabling baseband while changing sampling rates seems like a good idea... - radio::set_baseband_rate(sampling_rate()); + if (enabled_) + radio::set_baseband_rate(sampling_rate()); + update_tuning_frequency(); } void ReceiverModel::update_lna() { - radio::set_lna_gain(lna()); + if (enabled_) + radio::set_lna_gain(lna()); } void ReceiverModel::update_vga() { - radio::set_vga_gain(vga()); + if (enabled_) + radio::set_vga_gain(vga()); } void ReceiverModel::update_rf_amp() { - radio::set_rf_amp(rf_amp()); + if (enabled_) + radio::set_rf_amp(rf_amp()); } void ReceiverModel::update_modulation() { + if (!enabled_) + return; + switch (modulation()) { default: case Mode::AMAudio: @@ -392,5 +402,6 @@ void ReceiverModel::update_antenna_bias() { } void ReceiverModel::update_headphone_volume() { - audio::headphone::set_volume(headphone_volume()); + if (enabled_) + audio::headphone::set_volume(headphone_volume()); } diff --git a/firmware/application/transmitter_model.cpp b/firmware/application/transmitter_model.cpp index 9706a9eda..00d19e97d 100644 --- a/firmware/application/transmitter_model.cpp +++ b/firmware/application/transmitter_model.cpp @@ -31,6 +31,8 @@ #include "portapack_persistent_memory.hpp" #include "radio.hpp" +#include + using namespace hackrf::one; using namespace portapack; @@ -70,7 +72,7 @@ void TransmitterModel::set_channel_bandwidth(uint32_t v) { } uint8_t TransmitterModel::tx_gain() const { - return settings_.tx_gain_db; + return std::min(settings_.tx_gain_db, portapack::persistent_memory::config_tx_gain_max_db()); } void TransmitterModel::set_tx_gain(uint8_t v_db) { @@ -79,7 +81,7 @@ void TransmitterModel::set_tx_gain(uint8_t v_db) { } bool TransmitterModel::rf_amp() const { - return settings_.rf_amp; + return settings_.rf_amp && !portapack::persistent_memory::config_tx_amp_disabled(); } void TransmitterModel::set_rf_amp(bool enabled) { @@ -92,6 +94,15 @@ void TransmitterModel::set_antenna_bias() { } void TransmitterModel::enable() { + if (portapack::persistent_memory::config_tx_disabled()) { + radio::disable(); + + TXDisabledMessage message; + EventDispatcher::send_message(message); + + return; + } + enabled_ = true; radio::set_direction(rf::Direction::Transmit); update_tuning_frequency(); @@ -133,11 +144,13 @@ void TransmitterModel::configure_from_app_settings( } void TransmitterModel::update_tuning_frequency() { - radio::set_tuning_frequency(target_frequency()); + if (enabled_) + radio::set_tuning_frequency(target_frequency()); } void TransmitterModel::update_baseband_bandwidth() { - radio::set_baseband_filter_bandwidth_tx(baseband_bandwidth()); + if (enabled_) + radio::set_baseband_filter_bandwidth_tx(baseband_bandwidth()); } void TransmitterModel::update_sampling_rate() { @@ -146,17 +159,20 @@ void TransmitterModel::update_sampling_rate() { // protocols that need quick RX/TX turn-around. // Disabling baseband while changing sampling rates seems like a good idea... + if (enabled_) + radio::set_baseband_rate(sampling_rate()); - radio::set_baseband_rate(sampling_rate()); update_tuning_frequency(); } void TransmitterModel::update_tx_gain() { - radio::set_tx_gain(tx_gain()); + if (enabled_) + radio::set_tx_gain(tx_gain()); } void TransmitterModel::update_rf_amp() { - radio::set_rf_amp(rf_amp()); + if (enabled_) + radio::set_rf_amp(rf_amp()); } void TransmitterModel::update_antenna_bias() { diff --git a/firmware/application/ui_navigation.cpp b/firmware/application/ui_navigation.cpp index a88506a1a..580628a54 100644 --- a/firmware/application/ui_navigation.cpp +++ b/firmware/application/ui_navigation.cpp @@ -320,6 +320,14 @@ SystemStatusView::SystemStatusView( refresh(); } +void SystemStatusView::on_tx_disabled() { + if (!nav_.is_valid()) + return; + + nav_.pop(); + nav_.display_modal("Error", "RF transmit disabled.\nApplication closed."); +} + // when battery icon / text is clicked void SystemStatusView::on_battery_details() { if (!nav_.is_valid()) return; diff --git a/firmware/application/ui_navigation.hpp b/firmware/application/ui_navigation.hpp index 33d0e6358..3f9ee5ebf 100644 --- a/firmware/application/ui_navigation.hpp +++ b/firmware/application/ui_navigation.hpp @@ -303,6 +303,7 @@ class SystemStatusView : public View { void on_title(); void refresh(); void on_clk(); + void on_tx_disabled(); void rtc_battery_workaround(); void on_battery_data(const BatteryStateMessage* msg); void on_battery_details(); @@ -314,6 +315,13 @@ class SystemStatusView : public View { this->refresh(); }}; + MessageHandlerRegistration message_handler_tx_disabled{ + Message::ID::TXDisabled, + [this](const Message* const p) { + (void)p; + this->on_tx_disabled(); + }}; + MessageHandlerRegistration message_handler_battery{ Message::ID::BatteryStateData, [this](const Message* const p) { diff --git a/firmware/common/message.hpp b/firmware/common/message.hpp index f9b774908..49f2a6818 100644 --- a/firmware/common/message.hpp +++ b/firmware/common/message.hpp @@ -146,6 +146,7 @@ class Message { SSTVRXPhaseSlant = 88, SSTVRXCalibration = 89, SubCarData = 90, + TXDisabled = 91, MAX }; @@ -1699,4 +1700,11 @@ class SubCarDataMessage : public Message { uint64_t data2 = 0; }; +class TXDisabledMessage : public Message { + public: + constexpr TXDisabledMessage() + : Message{ID::TXDisabled} { + } +}; + #endif /*__MESSAGE_H__*/ diff --git a/firmware/common/portapack_persistent_memory.cpp b/firmware/common/portapack_persistent_memory.cpp index eef2706df..103ee6d7a 100644 --- a/firmware/common/portapack_persistent_memory.cpp +++ b/firmware/common/portapack_persistent_memory.cpp @@ -152,10 +152,10 @@ struct misc_config_t { bool config_sdcard_high_speed_io : 1; bool config_disable_config_mode : 1; bool beep_on_packets : 1; + bool tx_disabled : 1; bool tx_amp_disabled : 1; - bool UNUSED_7 : 1; - int8_t tx_gain_max_db; + uint8_t tx_gain_max_db; uint8_t PLACEHOLDER_1; uint8_t PLACEHOLDER_2; }; @@ -442,6 +442,7 @@ void defaults() { set_config_sdcard_high_speed_io(false, true); + set_config_tx_disabled(false); set_config_tx_amp_disabled(false); set_config_tx_gain_max_db(47); } @@ -652,11 +653,15 @@ bool config_sdcard_high_speed_io() { return data->misc_config.config_sdcard_high_speed_io; } +bool config_tx_disabled() { + return data->misc_config.tx_disabled; +} + bool config_tx_amp_disabled() { return data->misc_config.tx_amp_disabled; } -int8_t config_tx_gain_max_db() { +uint8_t config_tx_gain_max_db() { return data->misc_config.tx_gain_max_db; } @@ -754,11 +759,15 @@ void set_config_sdcard_high_speed_io(bool v, bool save) { data->misc_config.config_sdcard_high_speed_io = v; } +void set_config_tx_disabled(bool v) { + data->misc_config.tx_disabled = v; +} + void set_config_tx_amp_disabled(bool v) { data->misc_config.tx_amp_disabled = v; } -void set_config_tx_gain_max_db(int8_t v) { +void set_config_tx_gain_max_db(uint8_t v) { data->misc_config.tx_gain_max_db = v; } diff --git a/firmware/common/portapack_persistent_memory.hpp b/firmware/common/portapack_persistent_memory.hpp index b500552f5..cdac91a15 100644 --- a/firmware/common/portapack_persistent_memory.hpp +++ b/firmware/common/portapack_persistent_memory.hpp @@ -203,8 +203,9 @@ bool config_disable_external_tcxo(); bool config_sdcard_high_speed_io(); bool config_disable_config_mode(); bool beep_on_packets(); +bool config_tx_disabled(); bool config_tx_amp_disabled(); -int8_t config_tx_gain_max_db(); +uint8_t config_tx_gain_max_db(); bool config_splash(); bool config_converter(); @@ -228,8 +229,9 @@ void set_config_disable_external_tcxo(bool v); void set_config_sdcard_high_speed_io(bool v, bool save); void set_config_disable_config_mode(bool v); void set_beep_on_packets(bool v); +void set_config_tx_disabled(bool v); void set_config_tx_amp_disabled(bool v); -void set_config_tx_gain_max_db(int8_t v); +void set_config_tx_gain_max_db(uint8_t v); void set_config_splash(bool v); bool config_converter();