From f65852ff05b1b4ba22ad0536c263afb04a662032 Mon Sep 17 00:00:00 2001 From: "DESKTOP-R56EVJP\\Alex" Date: Sun, 21 Mar 2021 20:11:40 -0500 Subject: [PATCH 1/3] Rebased code from new eried repo commits. Changed to to reflect strijar implementation. Fixed previous issue with old ssb-am-tx ui_mictx code. --- firmware/application/apps/soundboard_app.cpp | 6 +- firmware/application/apps/ui_mictx.cpp | 84 ++- firmware/application/apps/ui_mictx.cpp.1 | 526 +++++++++++++++++++ firmware/application/apps/ui_mictx.hpp | 32 +- firmware/application/apps/ui_mictx.hpp.1 | 344 ++++++++++++ firmware/application/baseband_api.cpp | 9 +- firmware/application/baseband_api.hpp | 3 +- firmware/baseband/CMakeLists.txt | 3 + firmware/baseband/dsp_hilbert.cpp | 57 ++ firmware/baseband/dsp_hilbert.hpp | 44 ++ firmware/baseband/dsp_modulate.cpp | 137 +++++ firmware/baseband/dsp_modulate.hpp | 96 ++++ firmware/baseband/proc_mictx.cpp | 38 +- firmware/baseband/proc_mictx.hpp | 10 +- firmware/common/dsp_iir.cpp | 26 + firmware/common/dsp_iir.hpp | 20 + firmware/common/dsp_sos.cpp | 22 + firmware/common/dsp_sos.hpp | 51 ++ firmware/common/dsp_sos_config.hpp | 37 ++ firmware/common/message.hpp | 16 +- 20 files changed, 1545 insertions(+), 16 deletions(-) create mode 100644 firmware/application/apps/ui_mictx.cpp.1 create mode 100644 firmware/application/apps/ui_mictx.hpp.1 create mode 100644 firmware/baseband/dsp_hilbert.cpp create mode 100644 firmware/baseband/dsp_hilbert.hpp create mode 100644 firmware/baseband/dsp_modulate.cpp create mode 100644 firmware/baseband/dsp_modulate.hpp create mode 100644 firmware/common/dsp_sos.cpp create mode 100644 firmware/common/dsp_sos.hpp create mode 100644 firmware/common/dsp_sos_config.hpp diff --git a/firmware/application/apps/soundboard_app.cpp b/firmware/application/apps/soundboard_app.cpp index 4682d985b..2c93822f2 100644 --- a/firmware/application/apps/soundboard_app.cpp +++ b/firmware/application/apps/soundboard_app.cpp @@ -110,7 +110,11 @@ void SoundBoardView::start_tx(const uint32_t id) { 1536000 / 20, // Update vu-meter at 20Hz transmitter_model.channel_bandwidth(), 0, // Gain is unused - TONES_F2D(tone_key_frequency(tone_key_index), 1536000) + TONES_F2D(tone_key_frequency(tone_key_index), 1536000), + 0, //AM + 0, //DSB + 0, //USB + 0 //LSB ); baseband::set_sample_rate(sample_rate); diff --git a/firmware/application/apps/ui_mictx.cpp b/firmware/application/apps/ui_mictx.cpp index 82e66408a..0e2c9c470 100644 --- a/firmware/application/apps/ui_mictx.cpp +++ b/firmware/application/apps/ui_mictx.cpp @@ -65,8 +65,13 @@ void MicTXView::configure_baseband() { sampling_rate / 20, // Update vu-meter at 20Hz transmitting ? transmitter_model.channel_bandwidth() : 0, mic_gain, - TONES_F2D(tone_key_frequency(tone_key_index), sampling_rate) + TONES_F2D(tone_key_frequency(tone_key_index), sampling_rate), + enable_am, + enable_dsb, + enable_usb, + enable_lsb ); + } void MicTXView::set_tx(bool enable) { @@ -143,8 +148,20 @@ void MicTXView::rxaudio(bool is_on) { if (is_on) { audio::input::stop(); baseband::shutdown(); - baseband::run_image(portapack::spi_flash::image_tag_nfm_audio); - receiver_model.set_modulation(ReceiverModel::Mode::NarrowbandFMAudio); + + if (enable_am || enable_usb || enable_lsb || enable_dsb) { + baseband::run_image(portapack::spi_flash::image_tag_am_audio); + receiver_model.set_modulation(ReceiverModel::Mode::AMAudio); + if (options_mode.selected_index() < 4) + receiver_model.set_am_configuration(options_mode.selected_index() - 1); + else + receiver_model.set_am_configuration(0); + } + else { + baseband::run_image(portapack::spi_flash::image_tag_nfm_audio); + 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. @@ -155,15 +172,15 @@ void MicTXView::rxaudio(bool is_on) { receiver_model.enable(); audio::output::start(); } else { //These incredibly convoluted steps are required for the vumeter to reappear when stopping RX. + receiver_model.set_modulation(ReceiverModel::Mode::NarrowbandFMAudio); //This fixes something with AM RX... receiver_model.disable(); baseband::shutdown(); + baseband::run_image(portapack::spi_flash::image_tag_mic_tx); - audio::input::start(); -// transmitter_model.enable(); + audio::output::stop(); + audio::input::start(); portapack::pin_i2s0_rx_sda.mode(3); -// transmitting = false; configure_baseband(); -// transmitter_model.disable(); } } @@ -198,11 +215,13 @@ MicTXView::MicTXView( &field_bw, &field_rfgain, &field_rfamp, + &options_mode, &field_frequency, &options_tone_key, &check_rogerbeep, &check_rxactive, &field_volume, + &field_rxbw, &field_squelch, &field_rxfrequency, &field_rxlna, @@ -262,6 +281,42 @@ MicTXView::MicTXView( }; field_rfamp.set_value(rf_amp ? 14 : 0); + options_mode.on_change = [this](size_t, int32_t v) { + enable_am = false; + enable_usb = false; + enable_lsb = false; + enable_dsb = false; + switch(v) { + case 0: + enable_am = false; + enable_usb = false; + enable_lsb = false; + enable_dsb = false; + field_bw.set_value(transmitter_model.channel_bandwidth() / 1000); + //if (rx_enabled) + rxaudio(rx_enabled); //Update now if we have RX audio on + break; + case 1: + enable_am = true; + rxaudio(rx_enabled); //Update now if we have RX audio on + break; + case 2: + enable_usb = true; + rxaudio(rx_enabled); //Update now if we have RX audio on + break; + case 3: + enable_lsb = true; + rxaudio(rx_enabled); //Update now if we have RX audio on + break; + case 4: + enable_dsb = true; + rxaudio(rx_enabled); //Update now if we have RX audio on + break; + } + //configure_baseband(); + }; + + /* check_va.on_select = [this](Checkbox&, bool v) { va_enabled = v; @@ -331,6 +386,21 @@ MicTXView::MicTXView( 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_rxbw.on_change = [this](size_t, int32_t v) { + switch(v) { + case 0: + receiver_model.set_nbfm_configuration(0); + break; + case 1: + receiver_model.set_nbfm_configuration(1); + break; + case 2: + receiver_model.set_nbfm_configuration(2); + break; + } + }; + field_rxbw.set_selected_index(2); + field_squelch.on_change = [this](int32_t v) { receiver_model.set_squelch_level(100 - v); }; diff --git a/firmware/application/apps/ui_mictx.cpp.1 b/firmware/application/apps/ui_mictx.cpp.1 new file mode 100644 index 000000000..9476584b1 --- /dev/null +++ b/firmware/application/apps/ui_mictx.cpp.1 @@ -0,0 +1,526 @@ +/* + * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2016 Furrtek + * + * This file is part of PortaPack. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "ui_mictx.hpp" + +#include "baseband_api.hpp" +#include "audio.hpp" +#include "tonesets.hpp" +#include "portapack_hal.hpp" +#include "string_format.hpp" +#include "irq_controls.hpp" + + +#include + +using namespace tonekey; +using namespace portapack; + +namespace ui { + +void MicTXView::focus() { + switch(focused_ui) { + case 0: + field_frequency.focus(); + break; + case 1: + field_rxfrequency.focus(); + break; + default: + //field_va.focus(); + tx_button.focus(); + break; + } +} + +void MicTXView::update_vumeter() { + vumeter.set_value(audio_level); +} + +void MicTXView::on_tx_progress(const bool done) { + // Roger beep played, stop transmitting + if (done) + set_tx(false); +} + +void MicTXView::configure_baseband() { + baseband::set_audiotx_config( + sampling_rate / 20, // Update vu-meter at 20Hz + transmitting ? transmitter_model.channel_bandwidth() : 0, + mic_gain, + TONES_F2D(tone_key_frequency(tone_key_index), sampling_rate), + enable_am, + am_carrier_lvl, + 0, + enable_usb, + enable_lsb + ); + +} + +void MicTXView::set_tx(bool enable) { + if (enable) { + if (rx_enabled) //If audio RX is enabled + rxaudio(false); //Then turn off audio RX + receiver_model.set_modulation(ReceiverModel::Mode::NarrowbandFMAudio); // Weird workaround for FM TX + 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 { + if (transmitting && rogerbeep_enabled) { + 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(); + if (rx_enabled) //If audio RX is enabled and we've been transmitting + rxaudio(true); //Turn back on audio RX + } + } +} + +void MicTXView::do_timing() { + if (va_enabled) { + if (!transmitting) { + // Attack + if (audio_level >= va_level) { + if ((attack_timer >> 8) >= attack_ms) { + decay_timer = 0; + attack_timer = 0; + set_tx(true); + } else { + attack_timer += lcd_frame_duration; + } + } else { + attack_timer = 0; + } + } else { + // Decay + if (audio_level < va_level) { + if ((decay_timer >> 8) >= decay_ms) { + decay_timer = 0; + attack_timer = 0; + set_tx(false); + } else { + decay_timer += lcd_frame_duration; + } + } else { + decay_timer = 0; + } + } + } else { + // Check for PTT release + const auto switches_state = get_switches_state(); + 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) { + audio::input::stop(); + baseband::shutdown(); + + if (enable_am || enable_usb || enable_lsb) { + baseband::run_image(portapack::spi_flash::image_tag_am_audio); + receiver_model.set_modulation(ReceiverModel::Mode::AMAudio); + if (options_mode.selected_index() < 4) + receiver_model.set_am_configuration(options_mode.selected_index() - 1); + else + receiver_model.set_am_configuration(0); + } + else { + baseband::run_image(portapack::spi_flash::image_tag_nfm_audio); + 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(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. + //baseband::run_image(portapack::spi_flash::image_tag_nfm_audio); //There is something seriously wrong if these two lines fixes the issue with AM TX... + receiver_model.set_modulation(ReceiverModel::Mode::NarrowbandFMAudio); + receiver_model.disable(); + baseband::shutdown(); + + baseband::run_image(portapack::spi_flash::image_tag_mic_tx); + audio::output::stop(); + 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); + //} +} + +void MicTXView::set_ptt_visibility(bool v) { + tx_button.hidden(!v); +} + +MicTXView::MicTXView( + NavigationView& nav +) +{ + portapack::pin_i2s0_rx_sda.mode(3); // This is already done in audio::init but gets changed by the CPLD overlay reprogramming + + baseband::run_image(portapack::spi_flash::image_tag_mic_tx); + + + + add_children({ + &labels, + &vumeter, + &options_gain, +// &check_va, + &field_va, + &field_rxbw, + &field_va_level, + &field_va_attack, + &field_va_decay, +// &field_carrier, + &field_bw, + &field_rfgain, + &field_rfamp, + &field_frequency, + &options_tone_key, + &options_mode, + &check_rogerbeep, + &check_rxactive, + &field_volume, + &field_squelch, + &field_rxfrequency, + &field_rxlna, + &field_rxvga, + &field_rxamp, + &tx_button + }); + + + + tone_keys_populate(options_tone_key); + options_tone_key.on_change = [this](size_t i, int32_t) { + tone_key_index = i; + }; + options_tone_key.set_selected_index(0); + + options_gain.on_change = [this](size_t, int32_t v) { + mic_gain = v / 10.0; + configure_baseband(); + }; + options_gain.set_selected_index(1); // x1.0 + + options_mode.on_change = [this](size_t, int32_t v) { + enable_am = false; + enable_usb = false; + enable_lsb = false; + switch(v) { + case 0: + enable_am = false; + enable_usb = false; + enable_lsb = false; + field_bw.set_value(transmitter_model.channel_bandwidth() / 1000); + //if (rx_enabled) + rxaudio(rx_enabled); + break; + case 1: + enable_am = true; + am_carrier_lvl = 20; + //if (rx_enabled) + rxaudio(rx_enabled); + break; + case 2: + enable_am = true; + enable_usb = true; + //if (rx_enabled) + rxaudio(rx_enabled); + break; + case 3: + enable_am = true; + enable_lsb = true; + + //if (rx_enabled) + rxaudio(rx_enabled); + break; + case 4: + enable_usb = false; + enable_lsb = false; + enable_am = true; + am_carrier_lvl = 0; + //if (rx_enabled) + rxaudio(rx_enabled); + break; + } + //configure_baseband(); + }; + + 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) { + 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(tx_frequency); + new_view->on_changed = [this](rf::Frequency f) { + tx_frequency = f; + if(!rx_enabled) + transmitter_model.set_tuning_frequency(f); + this->field_frequency.set_value(f); + set_dirty(); + }; + }; + + field_rxbw.on_change = [this](size_t, int32_t v) { + switch(v) { + case 0: + receiver_model.set_nbfm_configuration(0); + break; + case 1: + receiver_model.set_nbfm_configuration(1); + break; + case 2: + receiver_model.set_nbfm_configuration(2); + break; + } + }; + field_rxbw.set_selected_index(2); + + field_bw.on_change = [this](uint32_t v) { + transmitter_model.set_channel_bandwidth(v * 1000); + }; + field_bw.set_value(10); + +// field_carrier.on_change = [this](uint32_t v) { +// am_carrier_lvl = v; +// }; +// field_carrier.set_value(am_carrier_lvl); + 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; + }; + + field_va_level.on_change = [this](int32_t v) { + va_level = v; + vumeter.set_mark(v); + }; + field_va_level.set_value(40); + + field_va_attack.on_change = [this](int32_t v) { + attack_ms = v; + }; + field_va_attack.set_value(500); + + field_va_decay.on_change = [this](int32_t v) { + 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.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); + 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); + receiver_model.set_rf_amp(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); + + set_tx(false); + + audio::set_rate(audio::Rate::Hz_24000); + audio::input::start(); +} + +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); + baseband::shutdown(); +} + +} diff --git a/firmware/application/apps/ui_mictx.hpp b/firmware/application/apps/ui_mictx.hpp index 2b7853daa..9084047a3 100644 --- a/firmware/application/apps/ui_mictx.hpp +++ b/firmware/application/apps/ui_mictx.hpp @@ -99,19 +99,27 @@ private: int32_t focused_ui { 2 }; bool button_touch { false }; + //AM TX Stuff + bool enable_am { false }; + bool enable_dsb { false }; + bool enable_usb { false }; + bool enable_lsb { false }; + Labels labels { { { 3 * 8, 1 * 8 }, "MIC. GAIN:", Color::light_grey() }, { { 3 * 8, 3 * 8 }, "F:", Color::light_grey() }, - { { 15 * 8, 3 * 8 }, "BW: kHz", Color::light_grey() }, + { { 15 * 8, 3 * 8 }, "BW: FM kHz", Color::light_grey() }, { { 3 * 8, 5 * 8 }, "GAIN:", Color::light_grey() }, { {11 * 8, 5 * 8 }, "Amp:", Color::light_grey() }, + { { 18 * 8, (5 * 8) }, "Mode:", 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, 23 * 8 }, "FM RXBW:", 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()}, @@ -162,6 +170,18 @@ private: 14, ' ' }; + + OptionsField options_mode { + { 24 * 8, 5 * 8 }, + 3, + { + { "FM", 0 }, + { "AM", 1 }, + { "USB", 2 }, + { "LSB", 3 }, + { "DSB", 4 } + } + }; /* Checkbox check_va { { 3 * 8, (10 * 8) - 4 }, @@ -231,6 +251,16 @@ private: ' ', }; + OptionsField field_rxbw { + { 25 * 8, 23 * 8}, + 3, + { + {"8k5", 0}, + {"11k", 1}, + {"16k", 2} + } + }; + NumberField field_squelch { { 20 * 8, 25 * 8 }, 2, diff --git a/firmware/application/apps/ui_mictx.hpp.1 b/firmware/application/apps/ui_mictx.hpp.1 new file mode 100644 index 000000000..3761c4014 --- /dev/null +++ b/firmware/application/apps/ui_mictx.hpp.1 @@ -0,0 +1,344 @@ +/* + * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2016 Furrtek + * + * This file is part of PortaPack. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __UI_MICTX_H__ +#define __UI_MICTX_H__ + +#include "ui.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 { + +class MicTXView : public View { +public: + MicTXView(NavigationView& nav); + ~MicTXView(); + + MicTXView(const MicTXView&) = delete; + MicTXView(MicTXView&&) = delete; + MicTXView& operator=(const MicTXView&) = delete; + MicTXView& operator=(MicTXView&&) = delete; + + 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); + return true; + } else + return false; + }; */ + + + 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 /60 + + void update_vumeter(); + void do_timing(); + void set_tx(bool enable); +// 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 { }; + float mic_gain { 1.0 }; + uint32_t audio_level { 0 }; + uint32_t va_level { }; + uint32_t attack_ms { }; + 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 }; + + //AM TX Stuff + bool enable_usb { false }; + bool enable_lsb { false }; + bool enable_am { false }; + uint32_t am_carrier_lvl { 20 }; +// uint32_t am_mod_div { 1 }; + + + Labels labels { + { { 3 * 8, 1 * 8 }, "MIC. GAIN:", Color::light_grey() }, + { { 3 * 8, 3 * 8 }, "F:", Color::light_grey() }, + { { 15 * 8, 3 * 8 }, "BW: FM kHz", Color::light_grey() }, + { { 3 * 8, 5 * 8 }, "GAIN:", Color::light_grey() }, + { {11 * 8, 5 * 8 }, "Amp:", Color::light_grey() }, + { { 18 * 8, (5 * 8) }, "Mode:", Color::light_grey() }, +// { { 21 * 8, (1 * 8) }, "AM Car:", Color::light_grey() }, +// { { 20 * 8, (16 * 8) + 2 }, "AMCAR:", 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() }, + { { 5 * 8, 23 * 8 }, "VOL:", Color::light_grey() }, + { {17 * 8, 23 * 8 }, "FM RXBW:", 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 { + { 0 * 8, 1 * 8, 2 * 8, 33 * 8 }, + 12, + true + }; + + + OptionsField options_gain { + { 13 * 8, 1 * 8 }, + 4, + { + { "x0.5", 5 }, + { "x1.0", 10 }, + { "x1.5", 15 }, + { "x2.0", 20 } + } + }; + OptionsField options_mode { + { 24 * 8, 5 * 8 }, + 3, + { + { "FM", 0 }, + { "AM", 1 }, + { "USB", 2 }, + { "LSB", 3 }, + { "DSB", 4 } + } + }; + + FrequencyField field_frequency { + { 5 * 8, 3 * 8 }, + }; + NumberField field_bw { + { 18 * 8, 3 * 8 }, + 3, + { 0, 150 }, + 1, + ' ' + }; + +/* NumberField field_carrier { + { 28 * 8, 1 * 8}, + 2, + { 0, 99}, + 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, (10 * 8) - 4 }, + 7, + "Voice activation", + false + };*/ + + + OptionsField field_va { + { 17 * 8, 8 * 8 }, + 3, + { + {" OFF", 0}, + {" PTT", 1}, + {"AUTO", 2} + } + }; + + OptionsField field_rxbw { + { 25 * 8, 23 * 8}, + 3, + { + {"8k5", 0}, + {"11k", 1}, + {"16k", 2} + } + }; + + NumberField field_va_level { + { 8 * 8, 10 * 8 }, + 3, + { 0, 255 }, + 2, + ' ' + }; + NumberField field_va_attack { + { 16 * 8, 10 * 8 }, + 3, + { 0, 999 }, + 20, + ' ' + }; + NumberField field_va_decay { + { 24 * 8, 10 * 8 }, + 4, + { 0, 9999 }, + 100, + ' ' + }; + + OptionsField options_tone_key { + { 10 * 8, ( 15 * 8 ) - 2 }, + 23, + { } + }; + + Checkbox check_rogerbeep { + { 3 * 8, ( 16 * 8 ) + 4 }, + 10, + "Roger beep", + false + }; + + Checkbox check_rxactive { + { 3 * 8, ( 21 * 8 ) - 4 }, + 8, + "RX audio listening", + true + }; + + NumberField field_volume { + { 10 * 8, 23 * 8 }, + 2, + { 0, 99 }, + 1, + ' ', + }; + + NumberField field_squelch { + { 20 * 8, 25 * 8 }, + 2, + { 0, 99 }, + 1, + ' ', + }; + + 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 + }; + + + MessageHandlerRegistration message_handler_lcd_sync { + Message::ID::DisplayFrameSync, + [this](const Message* const) { + this->do_timing(); + this->update_vumeter(); + } + }; + + MessageHandlerRegistration message_handler_audio_level { + Message::ID::AudioLevelReport, + [this](const Message* const p) { + const auto message = static_cast(p); + this->audio_level = message->value; + } + }; + + MessageHandlerRegistration message_handler_tx_progress { + Message::ID::TXProgress, + [this](const Message* const p) { + const auto message = *reinterpret_cast(p); + this->on_tx_progress(message.done); + } + }; +}; + +} /* namespace ui */ + +#endif/*__UI_MICTX_H__*/ diff --git a/firmware/application/baseband_api.cpp b/firmware/application/baseband_api.cpp index 2bff3c537..a3e1cab36 100644 --- a/firmware/application/baseband_api.cpp +++ b/firmware/application/baseband_api.cpp @@ -176,13 +176,18 @@ void kill_afsk() { } void set_audiotx_config(const uint32_t divider, const float deviation_hz, const float audio_gain, - const uint32_t tone_key_delta) { + const uint32_t tone_key_delta, const bool am_enabled, const bool dsb_enabled, + const bool usb_enabled, const bool lsb_enabled) { const AudioTXConfigMessage message { divider, deviation_hz, audio_gain, tone_key_delta, - (float)persistent_memory::tone_mix() / 100.0f + (float)persistent_memory::tone_mix() / 100.0f, + am_enabled, + dsb_enabled, + usb_enabled, + lsb_enabled }; send_message(&message); } diff --git a/firmware/application/baseband_api.hpp b/firmware/application/baseband_api.hpp index 43d0eebe5..8a50782b6 100644 --- a/firmware/application/baseband_api.hpp +++ b/firmware/application/baseband_api.hpp @@ -61,7 +61,8 @@ void set_tones_config(const uint32_t bw, const uint32_t pre_silence, const uint1 void kill_tone(); void set_sstv_data(const uint8_t vis_code, const uint32_t pixel_duration); void set_audiotx_config(const uint32_t divider, const float deviation_hz, const float audio_gain, - const uint32_t tone_key_delta); + const uint32_t tone_key_delta, const bool am_enabled, const bool dsb_enabled, + const bool usb_enabled, const bool lsb_enabled); void set_fifo_data(const int8_t * data); void set_pitch_rssi(int32_t avg, bool enabled); void set_afsk_data(const uint32_t afsk_samples_per_bit, const uint32_t afsk_phase_inc_mark, const uint32_t afsk_phase_inc_space, diff --git a/firmware/baseband/CMakeLists.txt b/firmware/baseband/CMakeLists.txt index c4aafa564..227e59fb6 100644 --- a/firmware/baseband/CMakeLists.txt +++ b/firmware/baseband/CMakeLists.txt @@ -113,6 +113,8 @@ set(CPPSRC baseband_stats_collector.cpp dsp_decimate.cpp dsp_demodulate.cpp + dsp_hilbert.cpp + dsp_modulate.cpp dsp_goertzel.cpp matched_filter.cpp spectrum_collector.cpp @@ -125,6 +127,7 @@ set(CPPSRC ${COMMON}/dsp_fft.cpp ${COMMON}/dsp_fir_taps.cpp ${COMMON}/dsp_iir.cpp + ${COMMON}/dsp_sos.cpp fxpt_atan2.cpp rssi.cpp rssi_dma.cpp diff --git a/firmware/baseband/dsp_hilbert.cpp b/firmware/baseband/dsp_hilbert.cpp new file mode 100644 index 000000000..ff9e793c4 --- /dev/null +++ b/firmware/baseband/dsp_hilbert.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2020 Belousov Oleg + * + * This file is part of PortaPack. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "dsp_hilbert.hpp" +#include "dsp_sos_config.hpp" + +namespace dsp { + +HilbertTransform::HilbertTransform() { + n = 0; + + sos_i.configure(half_band_lpf_config); + sos_q.configure(half_band_lpf_config); +} + +void HilbertTransform::execute(float in, float &out_i, float &out_q) { + float a = 0, b = 0; + + switch (n) { + case 0: a = in; b = 0; break; + case 1: a = 0; b = -in; break; + case 2: a = -in; b = 0; break; + case 3: a = 0; b = in; break; + } + + float i = sos_i.execute(a) * 2.0f; + float q = sos_q.execute(b) * 2.0f; + + switch (n) { + case 0: out_i = i; out_q = q; break; + case 1: out_i = -q; out_q = i; break; + case 2: out_i = -i; out_q = -q; break; + case 3: out_i = q; out_q = -i; break; + } + + n = (n + 1) % 4; +} + +} /* namespace dsp */ diff --git a/firmware/baseband/dsp_hilbert.hpp b/firmware/baseband/dsp_hilbert.hpp new file mode 100644 index 000000000..a4b56cd5d --- /dev/null +++ b/firmware/baseband/dsp_hilbert.hpp @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2020 Belousov Oleg + * + * This file is part of PortaPack. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __DSP_HILBERT_H__ +#define __DSP_HILBERT_H__ + +#include "dsp_sos.hpp" +#include "dsp_types.hpp" + +namespace dsp { + +class HilbertTransform { +public: + + HilbertTransform(); + void execute(float in, float &out_i, float &out_q); + +private: + uint8_t n = 0; + SOSFilter<5> sos_i; + SOSFilter<5> sos_q; +}; + +} /* namespace dsp */ + +#endif/*__DSP_HILBERT_H__*/ diff --git a/firmware/baseband/dsp_modulate.cpp b/firmware/baseband/dsp_modulate.cpp new file mode 100644 index 000000000..d59c7e3e1 --- /dev/null +++ b/firmware/baseband/dsp_modulate.cpp @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2020 Belousov Oleg + * + * This file is part of PortaPack. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "dsp_modulate.hpp" +#include "sine_table_int8.hpp" + +namespace dsp { +namespace modulate { + +Modulator::~Modulator() { +} + +Mode Modulator::get_mode() { + return mode; +} + +void Modulator::set_mode(Mode new_mode) { + mode = new_mode; +} + +void Modulator::set_over(uint32_t new_over) { + over = new_over; +} + +/// + +SSB::SSB() : hilbert() { + mode = Mode::LSB; +} + +void SSB::execute(const buffer_s16_t& audio, const buffer_c8_t& buffer) { + int32_t sample = 0; + int8_t re = 0, im = 0; + + for (size_t counter = 0; counter < buffer.count; counter++) { + if (counter % 128 == 0) { + float i = 0.0, q = 0.0; + + sample = audio.p[counter / over] >> 2; + //switch (mode) { + //case Mode::LSB: + hilbert.execute(sample / 32768.0f, i, q); + //case Mode::USB: hilbert.execute(sample / 32768.0f, q, i); + //default: break; + //} + + i *= 64.0f; + q *= 64.0f; + switch (mode) { + case Mode::LSB: re = q; im = i; break; + case Mode::USB: re = i; im = q; break; + default: re = 0; im = 0; break; + } + //re = q; + //im = i; + //break; + } + + buffer.p[counter] = { re, im }; + } +} + +/// + +FM::FM() { + mode = Mode::FM; +} + +void FM::set_fm_delta(uint32_t new_delta) { + fm_delta = new_delta; +} + +void FM::execute(const buffer_s16_t& audio, const buffer_c8_t& buffer) { + int32_t sample = 0; + int8_t re, im; + + for (size_t counter = 0; counter < buffer.count; counter++) { + if (counter % over == 0) { + sample = audio.p[counter / over] >> 8; + delta = sample * fm_delta; + } + + phase += delta; + sphase = phase >> 24; + + re = (sine_table_i8[(sphase + 64) & 255]); + im = (sine_table_i8[sphase]); + + buffer.p[counter] = { re, im }; + } +} + +AM::AM() { + mode = Mode::AM; +} + +void AM::execute(const buffer_s16_t& audio, const buffer_c8_t& buffer) { + int32_t sample = 0; + int8_t re, im; + float q = 0.0; + + for (size_t counter = 0; counter < buffer.count; counter++) { + if (counter % 128 == 0) { + sample = audio.p[counter / over] >> 2; + } + + q = sample / 32768.0f; + q *= 64.0f; + switch (mode) { + case Mode::AM: re = q + 20; im = q + 20; + case Mode::DSB: re = q; im = q; + default: break; + } + buffer.p[counter] = { re, im }; + } +} + +} +} diff --git a/firmware/baseband/dsp_modulate.hpp b/firmware/baseband/dsp_modulate.hpp new file mode 100644 index 000000000..fdc6e95f4 --- /dev/null +++ b/firmware/baseband/dsp_modulate.hpp @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2020 Belousov Oleg + * + * This file is part of PortaPack. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __DSP_MODULATE_H__ +#define __DSP_MODULATE_H__ + +#include "dsp_types.hpp" +#include "dsp_hilbert.hpp" + +namespace dsp { +namespace modulate { + +enum class Mode { + None, + AM, + DSB, + LSB, + USB, + FM +}; + +/// + +class Modulator { +public: + virtual void execute(const buffer_s16_t& audio, const buffer_c8_t& buffer) = 0; + virtual ~Modulator(); + + Mode get_mode(); + void set_mode(Mode new_mode); + + void set_over(uint32_t new_over); + +protected: + uint32_t over = 1; + Mode mode = Mode::None; +}; + +/// + +class SSB : public Modulator { +public: + SSB(); + + virtual void execute(const buffer_s16_t& audio, const buffer_c8_t& buffer); + +private: + dsp::HilbertTransform hilbert; +}; + +/// + +class FM : public Modulator { +public: + FM(); + + virtual void execute(const buffer_s16_t& audio, const buffer_c8_t& buffer); + void set_fm_delta(uint32_t new_delta); + +/// + +private: + uint32_t fm_delta { 0 }; + uint32_t phase { 0 }, sphase { 0 }; + int32_t sample { 0 }, delta { }; +}; + +class AM : public Modulator { +public: + AM(); + + virtual void execute(const buffer_s16_t& audio, const buffer_c8_t& buffer); +}; + +} /* namespace modulate */ +} /* namespace dsp */ + +#endif/*__DSP_MODULATE_H__*/ diff --git a/firmware/baseband/proc_mictx.cpp b/firmware/baseband/proc_mictx.cpp index 0a45df781..d5c0040c2 100644 --- a/firmware/baseband/proc_mictx.cpp +++ b/firmware/baseband/proc_mictx.cpp @@ -35,6 +35,7 @@ void MicTXProcessor::execute(const buffer_c8_t& buffer){ if (!configured) return; audio_input.read_audio_buffer(audio_buffer); + modulator->execute(audio_buffer, buffer); for (size_t i = 0; i < buffer.count; i++) { @@ -70,6 +71,7 @@ void MicTXProcessor::execute(const buffer_c8_t& buffer){ sample = beep_gen.process(0); } + /* sample = tone_gen.process(sample); // FM @@ -87,6 +89,7 @@ void MicTXProcessor::execute(const buffer_c8_t& buffer){ } buffer.p[i] = { re, im }; + */ } } @@ -96,7 +99,40 @@ void MicTXProcessor::on_message(const Message* const msg) { switch(msg->id) { case Message::ID::AudioTXConfig: - fm_delta = config_message.deviation_hz * (0xFFFFFFUL / baseband_fs); + if (fm_enabled) { + dsp::modulate::FM *fm = new dsp::modulate::FM(); + + fm->set_fm_delta(config_message.deviation_hz * (0xFFFFFFUL / baseband_fs)); + modulator = fm; + } + + if (usb_enabled) { + modulator = new dsp::modulate::SSB(); + modulator->set_mode(dsp::modulate::Mode::USB); + } + + if (lsb_enabled) { + modulator = new dsp::modulate::SSB(); + modulator->set_mode(dsp::modulate::Mode::LSB); + } + if (am_enabled) { + modulator = new dsp::modulate::AM(); + modulator->set_mode(dsp::modulate::Mode::AM); + } + if (dsb_enabled) { + modulator = new dsp::modulate::AM(); + modulator->set_mode(dsp::modulate::Mode::DSB); + } + + modulator->set_over(baseband_fs / 24000); + + am_enabled = config_message.am_enabled; + usb_enabled = config_message.usb_enabled; + lsb_enabled = config_message.lsb_enabled; + dsb_enabled = config_message.dsb_enabled; + if (!am_enabled || !usb_enabled || !lsb_enabled || !dsb_enabled) { + fm_enabled = true; + } audio_gain = config_message.audio_gain; divider = config_message.divider; diff --git a/firmware/baseband/proc_mictx.hpp b/firmware/baseband/proc_mictx.hpp index 986b10177..6220835cd 100644 --- a/firmware/baseband/proc_mictx.hpp +++ b/firmware/baseband/proc_mictx.hpp @@ -27,6 +27,7 @@ #include "baseband_thread.hpp" #include "audio_input.hpp" #include "tone_gen.hpp" +#include "dsp_modulate.hpp" class MicTXProcessor : public BasebandProcessor { public: @@ -50,7 +51,14 @@ private: AudioInput audio_input { }; ToneGen tone_gen { }; ToneGen beep_gen { }; - + dsp::modulate::Modulator *modulator; + + bool am_enabled { false }; + bool fm_enabled { true }; + bool usb_enabled { false }; + bool lsb_enabled { false }; + bool dsb_enabled { false }; + uint32_t divider { }; float audio_gain { }; uint64_t power_acc { 0 }; diff --git a/firmware/common/dsp_iir.cpp b/firmware/common/dsp_iir.cpp index 443183ba4..98e627ff2 100644 --- a/firmware/common/dsp_iir.cpp +++ b/firmware/common/dsp_iir.cpp @@ -55,3 +55,29 @@ void IIRBiquadFilter::execute(const buffer_f32_t& buffer_in, const buffer_f32_t& void IIRBiquadFilter::execute_in_place(const buffer_f32_t& buffer) { execute(buffer, buffer); } + +void IIRBiquadDF2Filter::configure(const iir_biquad_df2_config_t& config) { + b0 = config[0] / config[3]; + b1 = config[1] / config[3]; + b2 = config[2] / config[3]; + a1 = config[4] / config[3]; + a2 = config[5] / config[3]; +} + +// scipy.signal.sosfilt +// +// x_n = x[i, n] # make a temporary copy +// # Use direct II transposed structure: +// x[i, n] = b[s, 0] * x_n + zi[i, s, 0] +// zi[i, s, 0] = (b[s, 1] * x_n - a[s, 0] * x[i, n] + zi[i, s, 1]) +// zi[i, s, 1] = (b[s, 2] * x_n - a[s, 1] * x[i, n]) + +float IIRBiquadDF2Filter::execute(float x) { + float y; + + y = b0 * x + z0; + z0 = b1 * x - a1 * y + z1; + z1 = b2 * x - a2 * y; + + return y; +} diff --git a/firmware/common/dsp_iir.hpp b/firmware/common/dsp_iir.hpp index 0ecc996a0..9929c31c2 100644 --- a/firmware/common/dsp_iir.hpp +++ b/firmware/common/dsp_iir.hpp @@ -31,6 +31,9 @@ struct iir_biquad_config_t { std::array a; }; +// 0..2 - b, 3..5 - a +typedef std::array iir_biquad_df2_config_t; + constexpr iir_biquad_config_t iir_config_passthrough { { { 1.0f, 0.0f, 0.0f } }, { { 0.0f, 0.0f, 0.0f } }, @@ -67,4 +70,21 @@ private: std::array y { { 0.0f, 0.0f, 0.0f } }; }; +class IIRBiquadDF2Filter { +public: + + void configure(const iir_biquad_df2_config_t& config); + float execute(float z); + +private: + float b0 = 0; + float b1 = 0; + float b2 = 0; + float a1 = 0; + float a2 = 0; + + float z0 = 0; + float z1 = 0; +}; + #endif/*__DSP_IIR_H__*/ diff --git a/firmware/common/dsp_sos.cpp b/firmware/common/dsp_sos.cpp new file mode 100644 index 000000000..cf0ccfa53 --- /dev/null +++ b/firmware/common/dsp_sos.cpp @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2020 Belousov Oleg + * + * This file is part of PortaPack. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "dsp_sos.hpp" diff --git a/firmware/common/dsp_sos.hpp b/firmware/common/dsp_sos.hpp new file mode 100644 index 000000000..b74466369 --- /dev/null +++ b/firmware/common/dsp_sos.hpp @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2020 Belousov Oleg + * + * This file is part of PortaPack. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __DSP_SOS_H__ +#define __DSP_SOS_H__ + +#include "dsp_iir.hpp" + +#include +#include + +template +class SOSFilter { + +public: + + void configure(const iir_biquad_df2_config_t config[N]) { + for (size_t i = 0; i < N; i++) + filters[i].configure(config[i]); + } + + float execute(float value) { + for (auto &filter : filters) + value = filter.execute(value); + return value; + } + +private: + + IIRBiquadDF2Filter filters[N]; +}; + +#endif/*__DSP_SOS_H__*/ diff --git a/firmware/common/dsp_sos_config.hpp b/firmware/common/dsp_sos_config.hpp new file mode 100644 index 000000000..23c366223 --- /dev/null +++ b/firmware/common/dsp_sos_config.hpp @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2020 Belousov Oleg + * + * This file is part of PortaPack. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __DSP_SOS_CONFIG_H__ +#define __DSP_SOS_CONFIG_H__ + +#include "dsp_iir.hpp" + +// scipy.signal.iirfilter(ftype="ellip", N = 10, rp = 0.5, rs = 60.0, Wn = 0.5, btype = 'lowpass', output="sos") + +constexpr iir_biquad_df2_config_t half_band_lpf_config[5] = { + { 0.02339042f, 0.0411599f, 0.02339042f, 1.0f, -0.95317621f, 0.33446485f }, + { 1.0f, 0.82196114f, 1.0f, 1.0f, -0.50327735f, 0.63611027f }, + { 1.0f, 0.32515305f, 1.0f, 1.0f, -0.18144446f, 0.85269598f }, + { 1.0f, 0.14394122f, 1.0f, 1.0f, -0.04368236f, 0.94798064f }, + { 1.0f, 0.08720754, 1.0f, 1.0f, 0.00220944f, 0.98743139f } +}; + +#endif/*__DSP_SOS_CONFIG_H__*/ diff --git a/firmware/common/message.hpp b/firmware/common/message.hpp index 32a8fc7b0..3d288d7c3 100644 --- a/firmware/common/message.hpp +++ b/firmware/common/message.hpp @@ -856,13 +856,21 @@ public: const float deviation_hz, const float audio_gain, const uint32_t tone_key_delta, - const float tone_key_mix_weight + const float tone_key_mix_weight, + const bool am_enabled, + const bool dsb_enabled, + const bool usb_enabled, + const bool lsb_enabled ) : Message { ID::AudioTXConfig }, divider(divider), deviation_hz(deviation_hz), audio_gain(audio_gain), tone_key_delta(tone_key_delta), - tone_key_mix_weight(tone_key_mix_weight) + tone_key_mix_weight(tone_key_mix_weight), + am_enabled(am_enabled), + dsb_enabled(dsb_enabled), + usb_enabled(usb_enabled), + lsb_enabled(lsb_enabled) { } @@ -871,6 +879,10 @@ public: const float audio_gain; const uint32_t tone_key_delta; const float tone_key_mix_weight; + const bool am_enabled; + const bool dsb_enabled; + const bool usb_enabled; + const bool lsb_enabled; }; class SigGenConfigMessage : public Message { From 133bfbf07b482a0d9c7793246ad2149c473c53e6 Mon Sep 17 00:00:00 2001 From: Erwin Ried <1091420+eried@users.noreply.github.com> Date: Mon, 22 Mar 2021 10:09:41 +0100 Subject: [PATCH 2/3] Delete ui_mictx.hpp.1 --- firmware/application/apps/ui_mictx.hpp.1 | 344 ----------------------- 1 file changed, 344 deletions(-) delete mode 100644 firmware/application/apps/ui_mictx.hpp.1 diff --git a/firmware/application/apps/ui_mictx.hpp.1 b/firmware/application/apps/ui_mictx.hpp.1 deleted file mode 100644 index 3761c4014..000000000 --- a/firmware/application/apps/ui_mictx.hpp.1 +++ /dev/null @@ -1,344 +0,0 @@ -/* - * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. - * Copyright (C) 2016 Furrtek - * - * This file is part of PortaPack. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#ifndef __UI_MICTX_H__ -#define __UI_MICTX_H__ - -#include "ui.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 { - -class MicTXView : public View { -public: - MicTXView(NavigationView& nav); - ~MicTXView(); - - MicTXView(const MicTXView&) = delete; - MicTXView(MicTXView&&) = delete; - MicTXView& operator=(const MicTXView&) = delete; - MicTXView& operator=(MicTXView&&) = delete; - - 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); - return true; - } else - return false; - }; */ - - - 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 /60 - - void update_vumeter(); - void do_timing(); - void set_tx(bool enable); -// 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 { }; - float mic_gain { 1.0 }; - uint32_t audio_level { 0 }; - uint32_t va_level { }; - uint32_t attack_ms { }; - 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 }; - - //AM TX Stuff - bool enable_usb { false }; - bool enable_lsb { false }; - bool enable_am { false }; - uint32_t am_carrier_lvl { 20 }; -// uint32_t am_mod_div { 1 }; - - - Labels labels { - { { 3 * 8, 1 * 8 }, "MIC. GAIN:", Color::light_grey() }, - { { 3 * 8, 3 * 8 }, "F:", Color::light_grey() }, - { { 15 * 8, 3 * 8 }, "BW: FM kHz", Color::light_grey() }, - { { 3 * 8, 5 * 8 }, "GAIN:", Color::light_grey() }, - { {11 * 8, 5 * 8 }, "Amp:", Color::light_grey() }, - { { 18 * 8, (5 * 8) }, "Mode:", Color::light_grey() }, -// { { 21 * 8, (1 * 8) }, "AM Car:", Color::light_grey() }, -// { { 20 * 8, (16 * 8) + 2 }, "AMCAR:", 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() }, - { { 5 * 8, 23 * 8 }, "VOL:", Color::light_grey() }, - { {17 * 8, 23 * 8 }, "FM RXBW:", 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 { - { 0 * 8, 1 * 8, 2 * 8, 33 * 8 }, - 12, - true - }; - - - OptionsField options_gain { - { 13 * 8, 1 * 8 }, - 4, - { - { "x0.5", 5 }, - { "x1.0", 10 }, - { "x1.5", 15 }, - { "x2.0", 20 } - } - }; - OptionsField options_mode { - { 24 * 8, 5 * 8 }, - 3, - { - { "FM", 0 }, - { "AM", 1 }, - { "USB", 2 }, - { "LSB", 3 }, - { "DSB", 4 } - } - }; - - FrequencyField field_frequency { - { 5 * 8, 3 * 8 }, - }; - NumberField field_bw { - { 18 * 8, 3 * 8 }, - 3, - { 0, 150 }, - 1, - ' ' - }; - -/* NumberField field_carrier { - { 28 * 8, 1 * 8}, - 2, - { 0, 99}, - 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, (10 * 8) - 4 }, - 7, - "Voice activation", - false - };*/ - - - OptionsField field_va { - { 17 * 8, 8 * 8 }, - 3, - { - {" OFF", 0}, - {" PTT", 1}, - {"AUTO", 2} - } - }; - - OptionsField field_rxbw { - { 25 * 8, 23 * 8}, - 3, - { - {"8k5", 0}, - {"11k", 1}, - {"16k", 2} - } - }; - - NumberField field_va_level { - { 8 * 8, 10 * 8 }, - 3, - { 0, 255 }, - 2, - ' ' - }; - NumberField field_va_attack { - { 16 * 8, 10 * 8 }, - 3, - { 0, 999 }, - 20, - ' ' - }; - NumberField field_va_decay { - { 24 * 8, 10 * 8 }, - 4, - { 0, 9999 }, - 100, - ' ' - }; - - OptionsField options_tone_key { - { 10 * 8, ( 15 * 8 ) - 2 }, - 23, - { } - }; - - Checkbox check_rogerbeep { - { 3 * 8, ( 16 * 8 ) + 4 }, - 10, - "Roger beep", - false - }; - - Checkbox check_rxactive { - { 3 * 8, ( 21 * 8 ) - 4 }, - 8, - "RX audio listening", - true - }; - - NumberField field_volume { - { 10 * 8, 23 * 8 }, - 2, - { 0, 99 }, - 1, - ' ', - }; - - NumberField field_squelch { - { 20 * 8, 25 * 8 }, - 2, - { 0, 99 }, - 1, - ' ', - }; - - 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 - }; - - - MessageHandlerRegistration message_handler_lcd_sync { - Message::ID::DisplayFrameSync, - [this](const Message* const) { - this->do_timing(); - this->update_vumeter(); - } - }; - - MessageHandlerRegistration message_handler_audio_level { - Message::ID::AudioLevelReport, - [this](const Message* const p) { - const auto message = static_cast(p); - this->audio_level = message->value; - } - }; - - MessageHandlerRegistration message_handler_tx_progress { - Message::ID::TXProgress, - [this](const Message* const p) { - const auto message = *reinterpret_cast(p); - this->on_tx_progress(message.done); - } - }; -}; - -} /* namespace ui */ - -#endif/*__UI_MICTX_H__*/ From 41864f06e72eeba73fc3085a2e57a659c44f446c Mon Sep 17 00:00:00 2001 From: Erwin Ried <1091420+eried@users.noreply.github.com> Date: Mon, 22 Mar 2021 10:10:01 +0100 Subject: [PATCH 3/3] Delete ui_mictx.cpp.1 --- firmware/application/apps/ui_mictx.cpp.1 | 526 ----------------------- 1 file changed, 526 deletions(-) delete mode 100644 firmware/application/apps/ui_mictx.cpp.1 diff --git a/firmware/application/apps/ui_mictx.cpp.1 b/firmware/application/apps/ui_mictx.cpp.1 deleted file mode 100644 index 9476584b1..000000000 --- a/firmware/application/apps/ui_mictx.cpp.1 +++ /dev/null @@ -1,526 +0,0 @@ -/* - * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. - * Copyright (C) 2016 Furrtek - * - * This file is part of PortaPack. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#include "ui_mictx.hpp" - -#include "baseband_api.hpp" -#include "audio.hpp" -#include "tonesets.hpp" -#include "portapack_hal.hpp" -#include "string_format.hpp" -#include "irq_controls.hpp" - - -#include - -using namespace tonekey; -using namespace portapack; - -namespace ui { - -void MicTXView::focus() { - switch(focused_ui) { - case 0: - field_frequency.focus(); - break; - case 1: - field_rxfrequency.focus(); - break; - default: - //field_va.focus(); - tx_button.focus(); - break; - } -} - -void MicTXView::update_vumeter() { - vumeter.set_value(audio_level); -} - -void MicTXView::on_tx_progress(const bool done) { - // Roger beep played, stop transmitting - if (done) - set_tx(false); -} - -void MicTXView::configure_baseband() { - baseband::set_audiotx_config( - sampling_rate / 20, // Update vu-meter at 20Hz - transmitting ? transmitter_model.channel_bandwidth() : 0, - mic_gain, - TONES_F2D(tone_key_frequency(tone_key_index), sampling_rate), - enable_am, - am_carrier_lvl, - 0, - enable_usb, - enable_lsb - ); - -} - -void MicTXView::set_tx(bool enable) { - if (enable) { - if (rx_enabled) //If audio RX is enabled - rxaudio(false); //Then turn off audio RX - receiver_model.set_modulation(ReceiverModel::Mode::NarrowbandFMAudio); // Weird workaround for FM TX - 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 { - if (transmitting && rogerbeep_enabled) { - 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(); - if (rx_enabled) //If audio RX is enabled and we've been transmitting - rxaudio(true); //Turn back on audio RX - } - } -} - -void MicTXView::do_timing() { - if (va_enabled) { - if (!transmitting) { - // Attack - if (audio_level >= va_level) { - if ((attack_timer >> 8) >= attack_ms) { - decay_timer = 0; - attack_timer = 0; - set_tx(true); - } else { - attack_timer += lcd_frame_duration; - } - } else { - attack_timer = 0; - } - } else { - // Decay - if (audio_level < va_level) { - if ((decay_timer >> 8) >= decay_ms) { - decay_timer = 0; - attack_timer = 0; - set_tx(false); - } else { - decay_timer += lcd_frame_duration; - } - } else { - decay_timer = 0; - } - } - } else { - // Check for PTT release - const auto switches_state = get_switches_state(); - 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) { - audio::input::stop(); - baseband::shutdown(); - - if (enable_am || enable_usb || enable_lsb) { - baseband::run_image(portapack::spi_flash::image_tag_am_audio); - receiver_model.set_modulation(ReceiverModel::Mode::AMAudio); - if (options_mode.selected_index() < 4) - receiver_model.set_am_configuration(options_mode.selected_index() - 1); - else - receiver_model.set_am_configuration(0); - } - else { - baseband::run_image(portapack::spi_flash::image_tag_nfm_audio); - 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(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. - //baseband::run_image(portapack::spi_flash::image_tag_nfm_audio); //There is something seriously wrong if these two lines fixes the issue with AM TX... - receiver_model.set_modulation(ReceiverModel::Mode::NarrowbandFMAudio); - receiver_model.disable(); - baseband::shutdown(); - - baseband::run_image(portapack::spi_flash::image_tag_mic_tx); - audio::output::stop(); - 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); - //} -} - -void MicTXView::set_ptt_visibility(bool v) { - tx_button.hidden(!v); -} - -MicTXView::MicTXView( - NavigationView& nav -) -{ - portapack::pin_i2s0_rx_sda.mode(3); // This is already done in audio::init but gets changed by the CPLD overlay reprogramming - - baseband::run_image(portapack::spi_flash::image_tag_mic_tx); - - - - add_children({ - &labels, - &vumeter, - &options_gain, -// &check_va, - &field_va, - &field_rxbw, - &field_va_level, - &field_va_attack, - &field_va_decay, -// &field_carrier, - &field_bw, - &field_rfgain, - &field_rfamp, - &field_frequency, - &options_tone_key, - &options_mode, - &check_rogerbeep, - &check_rxactive, - &field_volume, - &field_squelch, - &field_rxfrequency, - &field_rxlna, - &field_rxvga, - &field_rxamp, - &tx_button - }); - - - - tone_keys_populate(options_tone_key); - options_tone_key.on_change = [this](size_t i, int32_t) { - tone_key_index = i; - }; - options_tone_key.set_selected_index(0); - - options_gain.on_change = [this](size_t, int32_t v) { - mic_gain = v / 10.0; - configure_baseband(); - }; - options_gain.set_selected_index(1); // x1.0 - - options_mode.on_change = [this](size_t, int32_t v) { - enable_am = false; - enable_usb = false; - enable_lsb = false; - switch(v) { - case 0: - enable_am = false; - enable_usb = false; - enable_lsb = false; - field_bw.set_value(transmitter_model.channel_bandwidth() / 1000); - //if (rx_enabled) - rxaudio(rx_enabled); - break; - case 1: - enable_am = true; - am_carrier_lvl = 20; - //if (rx_enabled) - rxaudio(rx_enabled); - break; - case 2: - enable_am = true; - enable_usb = true; - //if (rx_enabled) - rxaudio(rx_enabled); - break; - case 3: - enable_am = true; - enable_lsb = true; - - //if (rx_enabled) - rxaudio(rx_enabled); - break; - case 4: - enable_usb = false; - enable_lsb = false; - enable_am = true; - am_carrier_lvl = 0; - //if (rx_enabled) - rxaudio(rx_enabled); - break; - } - //configure_baseband(); - }; - - 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) { - 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(tx_frequency); - new_view->on_changed = [this](rf::Frequency f) { - tx_frequency = f; - if(!rx_enabled) - transmitter_model.set_tuning_frequency(f); - this->field_frequency.set_value(f); - set_dirty(); - }; - }; - - field_rxbw.on_change = [this](size_t, int32_t v) { - switch(v) { - case 0: - receiver_model.set_nbfm_configuration(0); - break; - case 1: - receiver_model.set_nbfm_configuration(1); - break; - case 2: - receiver_model.set_nbfm_configuration(2); - break; - } - }; - field_rxbw.set_selected_index(2); - - field_bw.on_change = [this](uint32_t v) { - transmitter_model.set_channel_bandwidth(v * 1000); - }; - field_bw.set_value(10); - -// field_carrier.on_change = [this](uint32_t v) { -// am_carrier_lvl = v; -// }; -// field_carrier.set_value(am_carrier_lvl); - 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; - }; - - field_va_level.on_change = [this](int32_t v) { - va_level = v; - vumeter.set_mark(v); - }; - field_va_level.set_value(40); - - field_va_attack.on_change = [this](int32_t v) { - attack_ms = v; - }; - field_va_attack.set_value(500); - - field_va_decay.on_change = [this](int32_t v) { - 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.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); - 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); - receiver_model.set_rf_amp(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); - - set_tx(false); - - audio::set_rate(audio::Rate::Hz_24000); - audio::input::start(); -} - -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); - baseband::shutdown(); -} - -}