diff --git a/firmware/application/apps/ui_mictx.cpp b/firmware/application/apps/ui_mictx.cpp index 0d7b23672..82e66408a 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,9 @@ 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(); portapack::pin_i2s0_rx_sda.mode(3); // This is already done in audio::init but gets changed by the CPLD overlay reprogramming } else { @@ -113,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) { @@ -132,7 +147,11 @@ 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); receiver_model.enable(); audio::output::start(); } else { //These incredibly convoluted steps are required for the vumeter to reappear when stopping RX. @@ -140,11 +159,11 @@ void MicTXView::rxaudio(bool is_on) { baseband::shutdown(); baseband::run_image(portapack::spi_flash::image_tag_mic_tx); audio::input::start(); - transmitter_model.enable(); +// transmitter_model.enable(); portapack::pin_i2s0_rx_sda.mode(3); - transmitting = false; +// transmitting = false; configure_baseband(); - transmitter_model.disable(); +// transmitter_model.disable(); } } @@ -155,6 +174,10 @@ void MicTXView::on_headphone_volume_changed(int32_t v) { //} } +void MicTXView::set_ptt_visibility(bool v) { + tx_button.hidden(!v); +} + MicTXView::MicTXView( NavigationView& nav ) @@ -167,18 +190,25 @@ MicTXView::MicTXView( &labels, &vumeter, &options_gain, - &check_va, +// &check_va, + &field_va, &field_va_level, &field_va_attack, &field_va_decay, &field_bw, + &field_rfgain, + &field_rfamp, &field_frequency, &options_tone_key, &check_rogerbeep, &check_rxactive, &field_volume, &field_squelch, - &text_ptt + &field_rxfrequency, + &field_rxlna, + &field_rxvga, + &field_rxamp, + &tx_button }); tone_keys_populate(options_tone_key); @@ -193,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(); }; @@ -213,13 +249,57 @@ MicTXView::MicTXView( }; field_bw.set_value(10); + tx_gain = transmitter_model.tx_gain(); + field_rfgain.on_change = [this](int32_t v) { + tx_gain = v; + + }; + field_rfgain.set_value(tx_gain); + + rf_amp = transmitter_model.rf_amp(); + field_rfamp.on_change = [this](int32_t v) { + rf_amp = (bool)v; + }; + field_rfamp.set_value(rf_amp ? 14 : 0); + + /* check_va.on_select = [this](Checkbox&, bool v) { va_enabled = v; text_ptt.hidden(v); //hide / show PTT text check_rxactive.hidden(v); //hide / show the RX AUDIO set_dirty(); //Refresh display }; + */ + field_va.set_selected_index(1); + field_va.on_change = [this](size_t, int32_t v) { + switch(v) { + case 0: + va_enabled = 0; + this->set_ptt_visibility(0); + check_rxactive.hidden(0); + ptt_enabled = 0; + break; + case 1: + va_enabled = 0; + this->set_ptt_visibility(1); + check_rxactive.hidden(0); + ptt_enabled = 1; + break; + case 2: + if (!rx_enabled) { + va_enabled = 1; + this->set_ptt_visibility(0); + check_rxactive.hidden(1); + ptt_enabled = 0; + } else { + field_va.set_selected_index(1); + } + break; + } + set_dirty(); + }; + check_rogerbeep.on_select = [this](Checkbox&, bool v) { rogerbeep_enabled = v; }; @@ -241,9 +321,9 @@ MicTXView::MicTXView( field_va_decay.set_value(1000); check_rxactive.on_select = [this](Checkbox&, bool v) { - //vumeter.set_value(0); //Start with a clean vumeter +// vumeter.set_value(0); //Start with a clean vumeter rx_enabled = v; - check_va.hidden(v); //Hide or show voice activation +// check_va.hidden(v); //Hide or show voice activation rxaudio(v); //Activate-Deactivate audio rx accordingly set_dirty(); //Refresh interface }; @@ -257,6 +337,71 @@ 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) { + rx_lna = v; + if(rx_enabled) + receiver_model.set_lna(v); + }; + field_rxlna.set_value(rx_lna); + + rx_vga = receiver_model.vga(); + field_rxvga.on_change = [this](int32_t v) { + rx_vga = v; + if(rx_enabled) + receiver_model.set_vga(v); + }; + field_rxvga.set_value(rx_vga); + + rx_amp = receiver_model.rf_amp(); + field_rxamp.on_change = [this](int32_t v) { + rx_amp = v; + if(rx_enabled) + receiver_model.set_rf_amp(rx_amp); + }; + field_rxamp.set_value(rx_amp); + + tx_button.on_select = [this](Button&) { + if(ptt_enabled && !transmitting) { + set_tx(true); + } + }; + + tx_button.on_touch_release = [this](Button&) { + if(button_touch) { + button_touch = false; + set_tx(false); + } + }; + + tx_button.on_touch_press = [this](Button&) { + if(!transmitting) { + button_touch = true; + } + }; + transmitter_model.set_sampling_rate(sampling_rate); transmitter_model.set_baseband_bandwidth(1750000); @@ -268,6 +413,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 0f27206c2..2b7853daa 100644 --- a/firmware/application/apps/ui_mictx.hpp +++ b/firmware/application/apps/ui_mictx.hpp @@ -47,14 +47,17 @@ 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)) { + if ((key == KeyEvent::Right) && (!va_enabled) && ptt_enabled) { set_tx(true); return true; } else return false; }; - + */ + std::string title() const override { return "Mic TX RX"; }; private: @@ -64,15 +67,18 @@ 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(); void rxaudio(bool is_on); void on_headphone_volume_changed(int32_t v); + + void set_ptt_visibility(bool v); bool transmitting { false }; bool va_enabled { false }; + bool ptt_enabled { true }; bool rogerbeep_enabled { false }; bool rx_enabled { false }; uint32_t tone_key_index { }; @@ -83,17 +89,34 @@ private: uint32_t decay_ms { }; uint32_t attack_timer { 0 }; uint32_t decay_timer { 0 }; + int32_t tx_gain { 47 }; + bool rf_amp { false }; + 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 { false }; + 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() }, - { { 7 * 8, 11 * 8 }, "LEVEL: /255", Color::light_grey() }, - { { 6 * 8, 13 * 8 }, "ATTACK: ms", Color::light_grey() }, - { { 7 * 8, 15 * 8 }, "DECAY: ms", Color::light_grey() }, - { { 4 * 8, 18 * 8 }, "TONE KEY:", Color::light_grey() }, - { { 9 * 8, 30 * 8 }, "VOL:", Color::light_grey() }, - { { 5 * 8, 32 * 8 }, "SQUELCH:", 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 { @@ -101,6 +124,7 @@ private: 12, true }; + OptionsField options_gain { { 13 * 8, 1 * 8 }, @@ -114,39 +138,65 @@ 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, ' ' }; + NumberField field_rfgain { + { 8 * 8, 5 * 8 }, + 2, + { 0, 47 }, + 1, + ' ' + }; + NumberField field_rfamp { + { 15 * 8, 5 * 8 }, + 2, + { 0, 14 }, + 14, + ' ' + }; + /* Checkbox check_va { - { 3 * 8, (9 * 8) - 4 }, + { 3 * 8, (10 * 8) - 4 }, 7, "Voice activation", false }; - + */ + + OptionsField field_va { + { 17 * 8, 8 * 8 }, + 3, + { + {" OFF", 0}, + {" PTT", 1}, + {"AUTO", 2} + } + }; + NumberField field_va_level { - { 13 * 8, 11 * 8 }, + { 8 * 8, 10 * 8 }, 3, { 0, 255 }, 2, ' ' }; NumberField field_va_attack { - { 13 * 8, 13 * 8 }, + { 16 * 8, 10 * 8 }, 3, { 0, 999 }, 20, ' ' }; NumberField field_va_decay { - { 13 * 8, 15 * 8 }, + { 24 * 8, 10 * 8 }, 4, { 0, 9999 }, 100, @@ -154,27 +204,27 @@ private: }; OptionsField options_tone_key { - { 10 * 8, 20 * 8 }, + { 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, @@ -182,16 +232,45 @@ private: }; NumberField field_squelch { - { 13 * 8, 32 * 8 }, + { 20 * 8, 25 * 8 }, 2, { 0, 99 }, 1, ' ', }; - Text text_ptt { - { 7 * 8, 35 * 8, 16 * 8, 16 }, - "PTT: RIGHT BUTTON" + FrequencyField field_rxfrequency { + { 7 * 8, 25 * 8 }, + }; + + NumberField field_rxlna { + { 9 * 8, 27 * 8 }, + 2, + { 0, 40 }, + 8, + ' ', + }; + + NumberField field_rxvga { + { 16 * 8, 27 * 8 }, + 2, + { 0, 62 }, + 2, + ' ', + }; + + NumberField field_rxamp { + { 23 * 8, 27 * 8 }, + 1, + { 0, 1 }, + 1, + ' ', + }; + + Button tx_button { + { 10 * 8, 30 * 8, 10 * 8, 5 * 8 }, + "TX", + true }; diff --git a/firmware/common/ui_widget.cpp b/firmware/common/ui_widget.cpp index a9333eae3..90c544fec 100644 --- a/firmware/common/ui_widget.cpp +++ b/firmware/common/ui_widget.cpp @@ -827,9 +827,11 @@ bool Checkbox::on_touch(const TouchEvent event) { Button::Button( Rect parent_rect, - std::string text + std::string text, + bool instant_exec ) : Widget { parent_rect }, - text_ { text } + text_ { text }, + instant_exec_ { instant_exec } { set_focusable(true); } @@ -899,15 +901,24 @@ bool Button::on_touch(const TouchEvent event) { case TouchEvent::Type::Start: set_highlighted(true); set_dirty(); + if( on_touch_press) { + on_touch_press(*this); + } + if( on_select && instant_exec_ ) { + on_select(*this); + } return true; case TouchEvent::Type::End: set_highlighted(false); set_dirty(); - if( on_select ) { + if( on_select && !instant_exec_ ) { on_select(*this); } + if( on_touch_release) { + on_touch_release(*this); + } return true; default: diff --git a/firmware/common/ui_widget.hpp b/firmware/common/ui_widget.hpp index 51de42773..f66da710c 100644 --- a/firmware/common/ui_widget.hpp +++ b/firmware/common/ui_widget.hpp @@ -378,10 +378,18 @@ private: class Button : public Widget { public: std::function on_select { }; + std::function on_touch_release { }; // Executed when releasing touch, after on_select. + std::function on_touch_press { }; // Executed when touching, before on_select. std::function on_dir { }; std::function on_highlight { }; - Button(Rect parent_rect, std::string text); + Button(Rect parent_rect, std::string text, bool instant_exec); // instant_exec: Execute on_select when you touching instead of releasing + Button( + Rect parent_rect, + std::string text + ) : Button { parent_rect, text, false } + { + } Button( ) : Button { { }, { } } @@ -399,6 +407,7 @@ public: private: std::string text_; + bool instant_exec_ { false }; }; class NewButton : public Widget {