diff --git a/firmware/application/apps/ui_mictx.cpp b/firmware/application/apps/ui_mictx.cpp index ce5514e1..d70e724f 100644 --- a/firmware/application/apps/ui_mictx.cpp +++ b/firmware/application/apps/ui_mictx.cpp @@ -37,7 +37,17 @@ using namespace portapack; namespace ui { void MicTXView::focus() { - field_frequency.focus(); + switch(focused_ui) { + case 0: + field_frequency.focus(); + break; + case 1: + field_rxfrequency.focus(); + break; + default: + field_va.focus(); + break; + } } void MicTXView::update_vumeter() { @@ -65,6 +75,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); transmitter_model.set_tx_gain(tx_gain); transmitter_model.set_rf_amp(rf_amp); transmitter_model.enable(); @@ -115,16 +126,18 @@ void MicTXView::do_timing() { } else { // Check for PTT release const auto switches_state = get_switches_state(); - if (!switches_state[0] && transmitting) // Right button + if (!switches_state[4] && transmitting && !button_touch) // Select button set_tx(false); } } +/* 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) { @@ -134,7 +147,8 @@ void MicTXView::rxaudio(bool is_on) { receiver_model.set_modulation(ReceiverModel::Mode::NarrowbandFMAudio); 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_tuning_frequency(field_frequency.value()); //probably this too can be commented out. + receiver_model.set_tuning_frequency(rx_frequency); // Now with seperate controls! receiver_model.set_lna(rx_lna); receiver_model.set_vga(rx_vga); receiver_model.set_rf_amp(rx_amp); @@ -150,8 +164,6 @@ void MicTXView::rxaudio(bool is_on) { // transmitting = false; configure_baseband(); // transmitter_model.disable(); - transmitter_model.set_tx_gain(transmitter_model.tx_gain()); - transmitter_model.set_rf_amp(transmitter_model.rf_amp()); } } @@ -163,9 +175,7 @@ void MicTXView::on_headphone_volume_changed(int32_t v) { } void MicTXView::set_ptt_visibility(bool v) { - text_ptt_1.hidden(!v); - text_ptt_2.hidden(!v); - text_ptt_3.hidden(!v); + tx_button.hidden(!v); } MicTXView::MicTXView( @@ -194,12 +204,11 @@ MicTXView::MicTXView( &check_rxactive, &field_volume, &field_squelch, + &field_rxfrequency, &field_rxlna, &field_rxvga, &field_rxamp, - &text_ptt_1, - &text_ptt_2, - &text_ptt_3 + &tx_button }); tone_keys_populate(options_tone_key); @@ -214,16 +223,22 @@ MicTXView::MicTXView( }; options_gain.set_selected_index(1); // x1.0 + tx_frequency = transmitter_model.tuning_frequency(); field_frequency.set_value(transmitter_model.tuning_frequency()); field_frequency.set_step(receiver_model.frequency_step()); field_frequency.on_change = [this](rf::Frequency f) { - this->on_tuning_frequency_changed(f); + tx_frequency = f; + if(!rx_enabled) + transmitter_model.set_tuning_frequency(f); }; field_frequency.on_edit = [this, &nav]() { + focused_ui = 0; // TODO: Provide separate modal method/scheme? - auto new_view = nav.push(receiver_model.tuning_frequency()); + auto new_view = nav.push(tx_frequency); new_view->on_changed = [this](rf::Frequency f) { - this->on_tuning_frequency_changed(f); + tx_frequency = f; + if(!rx_enabled) + transmitter_model.set_tuning_frequency(f); this->field_frequency.set_value(f); set_dirty(); }; @@ -322,6 +337,27 @@ MicTXView::MicTXView( field_squelch.set_value(0); receiver_model.set_squelch_level(0); + rx_frequency = receiver_model.tuning_frequency(); + field_rxfrequency.set_value(rx_frequency); + field_rxfrequency.set_step(receiver_model.frequency_step()); + field_rxfrequency.on_change = [this](rf::Frequency f) { + rx_frequency = f; + if(rx_enabled) + receiver_model.set_tuning_frequency(f); + }; + field_rxfrequency.on_edit = [this, &nav]() { + focused_ui = 1; + // TODO: Provide separate modal method/scheme? + auto new_view = nav.push(rx_frequency); + new_view->on_changed = [this](rf::Frequency f) { + rx_frequency = f; + if(rx_enabled) + receiver_model.set_tuning_frequency(f); + this->field_rxfrequency.set_value(f); + set_dirty(); + }; + }; + rx_lna = receiver_model.lna(); field_rxlna.on_change = [this](int32_t v) { @@ -339,10 +375,30 @@ MicTXView::MicTXView( rx_amp = receiver_model.rf_amp(); field_rxamp.on_change = [this](int32_t v) { - rx_amp = (bool)v; + rx_amp = v; receiver_model.set_rf_amp(rx_amp); }; - field_rxamp.set_value(rx_amp ? 14 : 0); + field_rxamp.set_value(rx_amp); + + tx_button.on_select = [this](TxButton&) { + if(ptt_enabled && !transmitting) { + button_touch = true; + set_tx(true); + } + }; + + tx_button.on_release = [this](TxButton&) { + if(button_touch) { + button_touch = false; + set_tx(false); + } + }; + + tx_button.on_buttonpress = [this](TxButton&) { + if(ptt_enabled && !transmitting) { + set_tx(true); + } + }; transmitter_model.set_sampling_rate(sampling_rate); transmitter_model.set_baseband_bandwidth(1750000); @@ -355,6 +411,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.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 159bfbac..cb735503 100644 --- a/firmware/application/apps/ui_mictx.hpp +++ b/firmware/application/apps/ui_mictx.hpp @@ -47,6 +47,8 @@ public: void focus() override; // PTT: Enable through KeyEvent (only works with presses), disable by polling :( + // This is the old "RIGHT BUTTON" method. + /* bool on_key(const KeyEvent key) { if ((key == KeyEvent::Right) && (!va_enabled) && ptt_enabled) { set_tx(true); @@ -54,7 +56,8 @@ public: } else return false; }; - + */ + std::string title() const override { return "Mic TX RX"; }; private: @@ -64,7 +67,7 @@ private: void update_vumeter(); void do_timing(); void set_tx(bool enable); - void on_tuning_frequency_changed(rf::Frequency f); +// void on_tuning_frequency_changed(rf::Frequency f); void on_tx_progress(const bool done); void configure_baseband(); @@ -91,24 +94,29 @@ private: int32_t rx_lna { 32 }; int32_t rx_vga { 32 }; bool rx_amp { false }; + rf::Frequency tx_frequency { 0 }; + rf::Frequency rx_frequency { 0 }; + int32_t focused_ui { 2 }; + bool button_touch { true }; Labels labels { { { 3 * 8, 1 * 8 }, "MIC. GAIN:", Color::light_grey() }, - { { 3 * 8, 3 * 8 }, "FREQUENCY:", Color::light_grey() }, - { { 3 * 8, 5 * 8 }, "BANDWIDTH: kHz", Color::light_grey() }, - { { 3 * 8, 7 * 8 }, "RFGAIN:", Color::light_grey() }, - { {13 * 8, 7 * 8 }, "Amp:", Color::light_grey() }, - { { 3 * 8, 10 * 8 }, "TX Activation:", Color::light_grey() }, - { { 7 * 8, 12 * 8 }, "LEVEL: /255", Color::light_grey() }, - { { 6 * 8, 14 * 8 }, "ATTACK: ms", Color::light_grey() }, - { { 7 * 8, 16 * 8 }, "DECAY: ms", Color::light_grey() }, - { { 4 * 8, ( 19 * 8 ) - 2 }, "TONE KEY:", Color::light_grey() }, - { { 9 * 8, 30 * 8 }, "VOL:", Color::light_grey() }, - { { 5 * 8, 32 * 8 }, "SQUELCH:", Color::light_grey() }, - { { 5 * 8, 34 * 8 }, "LNA:", Color::light_grey()}, - { {12 * 8, 34 * 8 }, "VGA:", Color::light_grey()}, - { {19 * 8, 34 * 8 }, "AMP:", Color::light_grey()} + { { 3 * 8, 3 * 8 }, "F:", Color::light_grey() }, + { { 15 * 8, 3 * 8 }, "BW: kHz", Color::light_grey() }, + { { 3 * 8, 5 * 8 }, "GAIN:", Color::light_grey() }, + { {11 * 8, 5 * 8 }, "Amp:", Color::light_grey() }, + { { 3 * 8, 8 * 8 }, "TX Activation:", Color::light_grey() }, + { { 4 * 8, 10 * 8 }, "LVL:", Color::light_grey() }, + { {12 * 8, 10 * 8 }, "ATT:", Color::light_grey() }, + { {20 * 8, 10 * 8 }, "DEC:", Color::light_grey() }, + { { 4 * 8, ( 13 * 8 ) - 2 }, "TONE KEY:", Color::light_grey() }, + { { 9 * 8, 23 * 8 }, "VOL:", Color::light_grey() }, + { {17 * 8, 25 * 8 }, "SQ:", Color::light_grey() }, + { { 5 * 8, 25 * 8 }, "F:", Color::light_grey() }, + { { 5 * 8, 27 * 8 }, "LNA:", Color::light_grey()}, + { {12 * 8, 27 * 8 }, "VGA:", Color::light_grey()}, + { {19 * 8, 27 * 8 }, "AMP:", Color::light_grey()} }; VuMeter vumeter { @@ -116,6 +124,7 @@ private: 12, true }; + OptionsField options_gain { { 13 * 8, 1 * 8 }, @@ -129,10 +138,10 @@ private: }; FrequencyField field_frequency { - { 13 * 8, 3 * 8 }, + { 5 * 8, 3 * 8 }, }; NumberField field_bw { - { 13 * 8, 5 * 8 }, + { 18 * 8, 3 * 8 }, 3, { 0, 150 }, 1, @@ -140,14 +149,14 @@ private: }; NumberField field_rfgain { - { 10 * 8, 7 * 8 }, + { 8 * 8, 5 * 8 }, 2, { 0, 47 }, 1, ' ' }; NumberField field_rfamp { - { 17 * 8, 7 * 8 }, + { 15 * 8, 5 * 8 }, 2, { 0, 14 }, 14, @@ -163,7 +172,7 @@ private: */ OptionsField field_va { - { 17 * 8, 10 * 8 }, + { 17 * 8, 8 * 8 }, 3, { {" OFF", 0}, @@ -173,21 +182,21 @@ private: }; NumberField field_va_level { - { 13 * 8, 12 * 8 }, + { 8 * 8, 10 * 8 }, 3, { 0, 255 }, 2, ' ' }; NumberField field_va_attack { - { 13 * 8, 14 * 8 }, + { 16 * 8, 10 * 8 }, 3, { 0, 999 }, 20, ' ' }; NumberField field_va_decay { - { 13 * 8, 16 * 8 }, + { 24 * 8, 10 * 8 }, 4, { 0, 9999 }, 100, @@ -195,27 +204,27 @@ private: }; OptionsField options_tone_key { - { 10 * 8, ( 21 * 8 ) - 2 }, + { 10 * 8, ( 15 * 8 ) - 2 }, 23, { } }; Checkbox check_rogerbeep { - { 3 * 8, 23 * 8 }, + { 3 * 8, ( 16 * 8 ) + 4 }, 10, "Roger beep", false }; Checkbox check_rxactive { - { 3 * 8, (27 * 8) + 4 }, + { 3 * 8, ( 21 * 8 ) - 4 }, 8, "RX audio listening", false }; NumberField field_volume { - { 13 * 8, 30 * 8 }, + { 13 * 8, 23 * 8 }, 2, { 0, 99 }, 1, @@ -223,15 +232,19 @@ private: }; NumberField field_squelch { - { 13 * 8, 32 * 8 }, + { 20 * 8, 25 * 8 }, 2, { 0, 99 }, 1, ' ', }; + FrequencyField field_rxfrequency { + { 7 * 8, 25 * 8 }, + }; + NumberField field_rxlna { - { 9 * 8, 34 * 8 }, + { 9 * 8, 27 * 8 }, 2, { 0, 40 }, 8, @@ -239,7 +252,7 @@ private: }; NumberField field_rxvga { - { 16 * 8, 34 * 8 }, + { 16 * 8, 27 * 8 }, 2, { 0, 62 }, 2, @@ -247,24 +260,16 @@ private: }; NumberField field_rxamp { - { 23 * 8, 34 * 8 }, - 2, - { 0, 14 }, - 14, + { 23 * 8, 27 * 8 }, + 1, + { 0, 1 }, + 1, ' ', }; - Text text_ptt_1 { - { 22 * 8, 13 * 8, 7 * 8, 8 }, - "PTT: " - }; - Text text_ptt_2 { - { 22 * 8, 15 * 8, 7 * 8, 8 }, - "RIGHT " - }; - Text text_ptt_3 { - { 22 * 8, 17 * 8, 7 * 8, 8 }, - "BUTTON" + TxButton tx_button { + { 10 * 8, 30 * 8, 10 * 8, 5 * 8 }, + "TX" }; diff --git a/firmware/application/radio.cpp b/firmware/application/radio.cpp index 60981c70..ccd9bf7e 100644 --- a/firmware/application/radio.cpp +++ b/firmware/application/radio.cpp @@ -157,13 +157,14 @@ bool set_tuning_frequency(const rf::Frequency frequency) { void set_rf_amp(const bool rf_amp) { rf_path.set_rf_amp(rf_amp); - + /* if (direction == rf::Direction::Transmit) { if (rf_amp) led_tx.on(); else led_tx.off(); } + */ } void set_lna_gain(const int_fast8_t db) { diff --git a/firmware/common/ui_widget.cpp b/firmware/common/ui_widget.cpp index a9333eae..af20b152 100644 --- a/firmware/common/ui_widget.cpp +++ b/firmware/common/ui_widget.cpp @@ -946,6 +946,101 @@ bool Button::on_touch(const TouchEvent event) { #endif } +/* TxButton ****************************************************************/ + +TxButton::TxButton( + Rect parent_rect, + std::string text +) : Widget { parent_rect }, + text_ { text } +{ + set_focusable(true); +} + +void TxButton::set_text(const std::string value) { + text_ = value; + set_dirty(); +} + +std::string TxButton::text() const { + return text_; +} + +void TxButton::paint(Painter& painter) { + Color bg, fg; + const auto r = screen_rect(); + + if (has_focus() || highlighted()) { + bg = style().foreground; + fg = Color::black(); + } else { + bg = Color::grey(); + fg = style().foreground; + } + + const Style paint_style = { style().font, bg, fg }; + + painter.draw_rectangle({r.location(), {r.size().width(), 1}}, Color::light_grey()); + painter.draw_rectangle({r.location().x(), r.location().y() + r.size().height() - 1, r.size().width(), 1}, Color::dark_grey()); + painter.draw_rectangle({r.location().x() + r.size().width() - 1, r.location().y(), 1, r.size().height()}, Color::dark_grey()); + + painter.fill_rectangle( + { r.location().x(), r.location().y() + 1, r.size().width() - 1, r.size().height() - 2 }, + paint_style.background + ); + + const auto label_r = paint_style.font.size_of(text_); + painter.draw_string( + { r.location().x() + (r.size().width() - label_r.width()) / 2, r.location().y() + (r.size().height() - label_r.height()) / 2 }, + paint_style, + text_ + ); +} + +void TxButton::on_focus() { + if( on_highlight ) + on_highlight(*this); +} + +bool TxButton::on_key(const KeyEvent key) { + if( key == KeyEvent::Select ) { + if( on_buttonpress ) { + on_buttonpress(*this); + return true; + } + } else { + if( on_dir ) { + return on_dir(*this, key); + } + } + + return false; +} + +bool TxButton::on_touch(const TouchEvent event) { + switch(event.type) { + case TouchEvent::Type::Start: + set_highlighted(true); + set_dirty(); + if( on_select ) { + on_select(*this); + } + return true; + + + case TouchEvent::Type::End: + set_highlighted(false); + set_dirty(); + if( on_release ) { + on_release(*this); + } + return true; + + default: + return false; + } +} + /* NewButton ****************************************************************/ NewButton::NewButton( diff --git a/firmware/common/ui_widget.hpp b/firmware/common/ui_widget.hpp index 51de4277..6bca547f 100644 --- a/firmware/common/ui_widget.hpp +++ b/firmware/common/ui_widget.hpp @@ -401,6 +401,34 @@ private: std::string text_; }; +class TxButton : public Widget { +public: + std::function on_select { }; // Touch only. + std::function on_release { }; // Touch only. There's no way (or complicated) for detecting a button's release :( + std::function on_buttonpress { }; + std::function on_dir { }; + std::function on_highlight { }; + + TxButton(Rect parent_rect, std::string text); + + TxButton( + ) : TxButton { { }, { } } + { + } + + void set_text(const std::string value); + std::string text() const; + + void paint(Painter& painter) override; + + void on_focus() override; + bool on_key(const KeyEvent key) override; + bool on_touch(const TouchEvent event) override; + +private: + std::string text_; +}; + class NewButton : public Widget { public: std::function on_select { };