diff --git a/firmware/application/apps/ui_mictx.cpp b/firmware/application/apps/ui_mictx.cpp index 8145b28e..e8fc8ce9 100644 --- a/firmware/application/apps/ui_mictx.cpp +++ b/firmware/application/apps/ui_mictx.cpp @@ -61,22 +61,22 @@ void MicTXView::configure_baseband() { void MicTXView::set_tx(bool enable) { if (enable) { + if (rx_enabled) //If audio RX is enabled + rxaudio(false); //Then turn off audio RX transmitting = true; configure_baseband(); 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 - //gpio_tx.write(1); - //led_tx.on(); } else { if (transmitting && rogerbeep_enabled) { - baseband::request_beep(); - transmitting = false; - } else { + baseband::request_beep(); //Transmit the roger beep + transmitting = false; //And flag the end of the transmission so ... + } else { // (if roger beep was enabled, this will be executed after the beep ends transmitting. transmitting = false; configure_baseband(); transmitter_model.disable(); - //gpio_tx.write(0); - //led_tx.off(); + if (rx_enabled) //If audio RX is enabled and we've been transmitting + rxaudio(true); //Turn back on audio RX } } } @@ -120,6 +120,39 @@ void MicTXView::do_timing() { 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) { + baseband::shutdown(); + baseband::run_image(portapack::spi_flash::image_tag_nfm_audio); + receiver_model.set_modulation(ReceiverModel::Mode::NarrowbandFMAudio); + //receiver_model.set_sampling_rate(sampling_rate); //** + //receiver_model.set_baseband_bandwidth(1750000); //** + receiver_model.enable(); + receiver_model.set_tuning_frequency(field_frequency.value()); //probably this too can be commented out. + audio::output::start(); + + } else { //These incredibly convoluted steps are required for the vumeter to reappear when stopping RX. + receiver_model.disable(); + baseband::shutdown(); + baseband::run_image(portapack::spi_flash::image_tag_mic_tx); + audio::input::start(); + transmitter_model.enable(); + portapack::pin_i2s0_rx_sda.mode(3); + transmitting = false; + configure_baseband(); + transmitter_model.disable(); + } +} + +void MicTXView::on_headphone_volume_changed(int32_t v) { + //if (rx_enabled) { + const auto new_volume = volume_t::decibel(v - 99) + audio::headphone::volume_range().max; + receiver_model.set_headphone_volume(new_volume); + //} } MicTXView::MicTXView( @@ -142,9 +175,12 @@ MicTXView::MicTXView( &field_frequency, &options_tone_key, &check_rogerbeep, + &check_rxactive, + &field_volume, + &field_squelch, &text_ptt }); - + tone_keys_populate(options_tone_key); options_tone_key.on_change = [this](size_t i, int32_t) { tone_key_index = i; @@ -168,6 +204,7 @@ MicTXView::MicTXView( new_view->on_changed = [this](rf::Frequency f) { this->on_tuning_frequency_changed(f); this->field_frequency.set_value(f); + set_dirty(); }; }; @@ -178,16 +215,15 @@ MicTXView::MicTXView( check_va.on_select = [this](Checkbox&, bool v) { va_enabled = v; - text_ptt.hidden(v); - set_dirty(); + text_ptt.hidden(v); //hide / show PTT text + check_rxactive.hidden(v); //hide / show the RX AUDIO + set_dirty(); //Refresh display }; - check_va.set_value(false); check_rogerbeep.on_select = [this](Checkbox&, bool v) { rogerbeep_enabled = v; }; - check_rogerbeep.set_value(false); - + field_va_level.on_change = [this](int32_t v) { va_level = v; vumeter.set_mark(v); @@ -203,7 +239,23 @@ MicTXView::MicTXView( decay_ms = v; }; field_va_decay.set_value(1000); - + + check_rxactive.on_select = [this](Checkbox&, bool v) { + //vumeter.set_value(0); //Start with a clean vumeter + rx_enabled = v; + check_va.hidden(v); //Hide or show voice activation + rxaudio(v); //Activate-Deactivate audio rx accordingly + set_dirty(); //Refresh interface + }; + + field_volume.set_value((receiver_model.headphone_volume() - audio::headphone::volume_range().max).decibel() + 99); + field_volume.on_change = [this](int32_t v) { this->on_headphone_volume_changed(v); }; + + field_squelch.on_change = [this](int32_t v) { + receiver_model.set_squelch_level(100 - v); + }; + field_squelch.set_value(0); + transmitter_model.set_sampling_rate(sampling_rate); transmitter_model.set_baseband_bandwidth(1750000); @@ -216,6 +268,8 @@ MicTXView::MicTXView( MicTXView::~MicTXView() { audio::input::stop(); transmitter_model.disable(); + if (rx_enabled) //Also turn off audio rx if enabled + rxaudio(false); baseband::shutdown(); } diff --git a/firmware/application/apps/ui_mictx.hpp b/firmware/application/apps/ui_mictx.hpp index 4cebe343..f439b895 100644 --- a/firmware/application/apps/ui_mictx.hpp +++ b/firmware/application/apps/ui_mictx.hpp @@ -24,12 +24,14 @@ #define __UI_MICTX_H__ #include "ui.hpp" +#include "ui_painter.hpp" #include "ui_widget.hpp" #include "ui_navigation.hpp" #include "ui_receiver.hpp" #include "transmitter_model.hpp" #include "tone_key.hpp" #include "message.hpp" +#include "receiver_model.hpp" namespace ui { @@ -54,11 +56,11 @@ public: return false; }; - std::string title() const override { return "Microphone TX"; }; + std::string title() const override { return "Mic TX RX"; }; private: static constexpr uint32_t sampling_rate = 1536000U; - static constexpr uint32_t lcd_frame_duration = (256 * 1000UL) / 60; // 1 frame @ 60fps in ms .8 fixed point + static constexpr uint32_t lcd_frame_duration = (256 * 1000UL) / 60; // 1 frame @ 60fps in ms .8 fixed point /60 void update_vumeter(); void do_timing(); @@ -66,10 +68,14 @@ private: 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); bool transmitting { false }; - bool va_enabled { }; - bool rogerbeep_enabled { }; + bool va_enabled { false }; + bool rogerbeep_enabled { false }; + bool rx_enabled { false }; uint32_t tone_key_index { }; float mic_gain { 1.0 }; uint32_t audio_level { 0 }; @@ -80,23 +86,25 @@ private: uint32_t decay_timer { 0 }; Labels labels { - { { 7 * 8, 1 * 8 }, "Mic. gain:", Color::light_grey() }, - { { 7 * 8, 4 * 8 }, "Frequency:", Color::light_grey() }, - { { 7 * 8, 6 * 8 }, "Bandwidth: kHz", Color::light_grey() }, - { { 9 * 8, 13 * 8 }, "Level: /255", Color::light_grey() }, - { { 9 * 8, 15 * 8 }, "Attack: ms", Color::light_grey() }, - { { 9 * 8, 17 * 8 }, "Decay: ms", Color::light_grey() }, - { { 7 * 8, 21 * 8 }, "Tone key:", Color::light_grey() } + { { 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() } }; VuMeter vumeter { - { 1 * 8, 2 * 8, 5 * 8, 32 * 8 }, - 20, - false + { 0 * 8, 1 * 8, 2 * 8, 33 * 8 }, + 12, + true }; OptionsField options_gain { - { 17 * 8, 1 * 8 }, + { 13 * 8, 1 * 8 }, 4, { { "x0.5", 5 }, @@ -107,10 +115,10 @@ private: }; FrequencyField field_frequency { - { 17 * 8, 4 * 8 }, + { 13 * 8, 3 * 8 }, }; NumberField field_bw { - { 17 * 8, 6 * 8 }, + { 13 * 8, 5 * 8 }, 3, { 0, 150 }, 1, @@ -118,28 +126,28 @@ private: }; Checkbox check_va { - { 7 * 8, 10 * 8 }, + { 3 * 8, (9 * 8) - 4 }, 7, "Voice activation", false }; NumberField field_va_level { - { 15 * 8, 13 * 8 }, + { 13 * 8, 11 * 8 }, 3, { 0, 255 }, 2, ' ' }; NumberField field_va_attack { - { 16 * 8, 15 * 8 }, + { 13 * 8, 13 * 8 }, 3, { 0, 999 }, 20, ' ' }; NumberField field_va_decay { - { 15 * 8, 17 * 8 }, + { 13 * 8, 15 * 8 }, 4, { 0, 9999 }, 100, @@ -147,28 +155,52 @@ private: }; OptionsField options_tone_key { - { 7 * 8, 23 * 8 }, + { 10 * 8, 20 * 8 }, 23, { } }; Checkbox check_rogerbeep { - { 7 * 8, 26 * 8 }, + { 3 * 8, 23 * 8 }, 10, "Roger beep", false }; - - Text text_ptt { - { 7 * 8, 17 * 16, 16 * 8, 16 }, - "PTT: RIGHT BUTTON" + + Checkbox check_rxactive { + { 3 * 8, (27 * 8) + 4 }, + 8, + "RX audio listening", + false + }; + + NumberField field_volume { + { 13 * 8, 30 * 8 }, + 2, + { 0, 99 }, + 1, + ' ', }; + NumberField field_squelch { + { 13 * 8, 32 * 8 }, + 2, + { 0, 99 }, + 1, + ' ', + }; + + Text text_ptt { + { 7 * 8, 35 * 8, 16 * 8, 16 }, + "PTT: RIGHT BUTTON" + }; + + MessageHandlerRegistration message_handler_lcd_sync { Message::ID::DisplayFrameSync, [this](const Message* const) { - this->update_vumeter(); this->do_timing(); + this->update_vumeter(); } }; diff --git a/firmware/common/ui_widget.cpp b/firmware/common/ui_widget.cpp index 01639e0c..9ba90180 100644 --- a/firmware/common/ui_widget.cpp +++ b/firmware/common/ui_widget.cpp @@ -1759,13 +1759,13 @@ void VuMeter::paint(Painter& painter) { lit = true; if (bar == 0) - color = lit ? Color::red() : Color::dark_red(); + color = lit ? Color::red() : Color::dark_grey(); else if (bar == 1) - color = lit ? Color::orange() : Color::dark_orange(); + color = lit ? Color::orange() : Color::dark_grey(); else if ((bar == 2) || (bar == 3)) - color = lit ? Color::yellow() : Color::dark_yellow(); + color = lit ? Color::yellow() : Color::dark_grey(); else - color = lit ? Color::green() : Color::dark_green(); + color = lit ? Color::green() : Color::dark_grey(); painter.fill_rectangle({ pos.x(), pos.y() + (Coord)(bar * (LED_height + 1)), width, (Coord)LED_height }, color); }