mirror of
https://github.com/eried/portapack-mayhem.git
synced 2024-10-01 01:26:06 -04:00
Rebased code from new eried repo commits. Changed to to reflect strijar implementation. Fixed previous issue with old ssb-am-tx ui_mictx code.
This commit is contained in:
parent
603b7fb1ab
commit
f65852ff05
@ -110,7 +110,11 @@ void SoundBoardView::start_tx(const uint32_t id) {
|
|||||||
1536000 / 20, // Update vu-meter at 20Hz
|
1536000 / 20, // Update vu-meter at 20Hz
|
||||||
transmitter_model.channel_bandwidth(),
|
transmitter_model.channel_bandwidth(),
|
||||||
0, // Gain is unused
|
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);
|
baseband::set_sample_rate(sample_rate);
|
||||||
|
|
||||||
|
@ -65,8 +65,13 @@ void MicTXView::configure_baseband() {
|
|||||||
sampling_rate / 20, // Update vu-meter at 20Hz
|
sampling_rate / 20, // Update vu-meter at 20Hz
|
||||||
transmitting ? transmitter_model.channel_bandwidth() : 0,
|
transmitting ? transmitter_model.channel_bandwidth() : 0,
|
||||||
mic_gain,
|
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) {
|
void MicTXView::set_tx(bool enable) {
|
||||||
@ -143,8 +148,20 @@ void MicTXView::rxaudio(bool is_on) {
|
|||||||
if (is_on) {
|
if (is_on) {
|
||||||
audio::input::stop();
|
audio::input::stop();
|
||||||
baseband::shutdown();
|
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_sampling_rate(3072000);
|
||||||
receiver_model.set_baseband_bandwidth(1750000);
|
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.
|
||||||
@ -155,15 +172,15 @@ void MicTXView::rxaudio(bool is_on) {
|
|||||||
receiver_model.enable();
|
receiver_model.enable();
|
||||||
audio::output::start();
|
audio::output::start();
|
||||||
} else { //These incredibly convoluted steps are required for the vumeter to reappear when stopping RX.
|
} 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();
|
receiver_model.disable();
|
||||||
baseband::shutdown();
|
baseband::shutdown();
|
||||||
|
|
||||||
baseband::run_image(portapack::spi_flash::image_tag_mic_tx);
|
baseband::run_image(portapack::spi_flash::image_tag_mic_tx);
|
||||||
audio::input::start();
|
audio::output::stop();
|
||||||
// transmitter_model.enable();
|
audio::input::start();
|
||||||
portapack::pin_i2s0_rx_sda.mode(3);
|
portapack::pin_i2s0_rx_sda.mode(3);
|
||||||
// transmitting = false;
|
|
||||||
configure_baseband();
|
configure_baseband();
|
||||||
// transmitter_model.disable();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,11 +215,13 @@ MicTXView::MicTXView(
|
|||||||
&field_bw,
|
&field_bw,
|
||||||
&field_rfgain,
|
&field_rfgain,
|
||||||
&field_rfamp,
|
&field_rfamp,
|
||||||
|
&options_mode,
|
||||||
&field_frequency,
|
&field_frequency,
|
||||||
&options_tone_key,
|
&options_tone_key,
|
||||||
&check_rogerbeep,
|
&check_rogerbeep,
|
||||||
&check_rxactive,
|
&check_rxactive,
|
||||||
&field_volume,
|
&field_volume,
|
||||||
|
&field_rxbw,
|
||||||
&field_squelch,
|
&field_squelch,
|
||||||
&field_rxfrequency,
|
&field_rxfrequency,
|
||||||
&field_rxlna,
|
&field_rxlna,
|
||||||
@ -262,6 +281,42 @@ MicTXView::MicTXView(
|
|||||||
};
|
};
|
||||||
field_rfamp.set_value(rf_amp ? 14 : 0);
|
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) {
|
check_va.on_select = [this](Checkbox&, bool v) {
|
||||||
va_enabled = 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.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_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) {
|
field_squelch.on_change = [this](int32_t v) {
|
||||||
receiver_model.set_squelch_level(100 - v);
|
receiver_model.set_squelch_level(100 - v);
|
||||||
};
|
};
|
||||||
|
526
firmware/application/apps/ui_mictx.cpp.1
Normal file
526
firmware/application/apps/ui_mictx.cpp.1
Normal file
@ -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 <cstring>
|
||||||
|
|
||||||
|
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<FrequencyKeypadView>(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<FrequencyKeypadView>(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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -99,19 +99,27 @@ private:
|
|||||||
int32_t focused_ui { 2 };
|
int32_t focused_ui { 2 };
|
||||||
bool button_touch { false };
|
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 {
|
Labels labels {
|
||||||
{ { 3 * 8, 1 * 8 }, "MIC. GAIN:", Color::light_grey() },
|
{ { 3 * 8, 1 * 8 }, "MIC. GAIN:", Color::light_grey() },
|
||||||
{ { 3 * 8, 3 * 8 }, "F:", 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() },
|
{ { 3 * 8, 5 * 8 }, "GAIN:", Color::light_grey() },
|
||||||
{ {11 * 8, 5 * 8 }, "Amp:", 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() },
|
{ { 3 * 8, 8 * 8 }, "TX Activation:", Color::light_grey() },
|
||||||
{ { 4 * 8, 10 * 8 }, "LVL:", Color::light_grey() },
|
{ { 4 * 8, 10 * 8 }, "LVL:", Color::light_grey() },
|
||||||
{ {12 * 8, 10 * 8 }, "ATT:", Color::light_grey() },
|
{ {12 * 8, 10 * 8 }, "ATT:", Color::light_grey() },
|
||||||
{ {20 * 8, 10 * 8 }, "DEC:", Color::light_grey() },
|
{ {20 * 8, 10 * 8 }, "DEC:", Color::light_grey() },
|
||||||
{ { 4 * 8, ( 13 * 8 ) - 2 }, "TONE KEY:", Color::light_grey() },
|
{ { 4 * 8, ( 13 * 8 ) - 2 }, "TONE KEY:", Color::light_grey() },
|
||||||
{ { 9 * 8, 23 * 8 }, "VOL:", 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() },
|
{ {17 * 8, 25 * 8 }, "SQ:", Color::light_grey() },
|
||||||
{ { 5 * 8, 25 * 8 }, "F:", Color::light_grey() },
|
{ { 5 * 8, 25 * 8 }, "F:", Color::light_grey() },
|
||||||
{ { 5 * 8, 27 * 8 }, "LNA:", Color::light_grey()},
|
{ { 5 * 8, 27 * 8 }, "LNA:", Color::light_grey()},
|
||||||
@ -162,6 +170,18 @@ private:
|
|||||||
14,
|
14,
|
||||||
' '
|
' '
|
||||||
};
|
};
|
||||||
|
|
||||||
|
OptionsField options_mode {
|
||||||
|
{ 24 * 8, 5 * 8 },
|
||||||
|
3,
|
||||||
|
{
|
||||||
|
{ "FM", 0 },
|
||||||
|
{ "AM", 1 },
|
||||||
|
{ "USB", 2 },
|
||||||
|
{ "LSB", 3 },
|
||||||
|
{ "DSB", 4 }
|
||||||
|
}
|
||||||
|
};
|
||||||
/*
|
/*
|
||||||
Checkbox check_va {
|
Checkbox check_va {
|
||||||
{ 3 * 8, (10 * 8) - 4 },
|
{ 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 {
|
NumberField field_squelch {
|
||||||
{ 20 * 8, 25 * 8 },
|
{ 20 * 8, 25 * 8 },
|
||||||
2,
|
2,
|
||||||
|
344
firmware/application/apps/ui_mictx.hpp.1
Normal file
344
firmware/application/apps/ui_mictx.hpp.1
Normal file
@ -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<const AudioLevelReportMessage*>(p);
|
||||||
|
this->audio_level = message->value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
MessageHandlerRegistration message_handler_tx_progress {
|
||||||
|
Message::ID::TXProgress,
|
||||||
|
[this](const Message* const p) {
|
||||||
|
const auto message = *reinterpret_cast<const TXProgressMessage*>(p);
|
||||||
|
this->on_tx_progress(message.done);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
} /* namespace ui */
|
||||||
|
|
||||||
|
#endif/*__UI_MICTX_H__*/
|
@ -176,13 +176,18 @@ void kill_afsk() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void set_audiotx_config(const uint32_t divider, const float deviation_hz, const float audio_gain,
|
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 {
|
const AudioTXConfigMessage message {
|
||||||
divider,
|
divider,
|
||||||
deviation_hz,
|
deviation_hz,
|
||||||
audio_gain,
|
audio_gain,
|
||||||
tone_key_delta,
|
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);
|
send_message(&message);
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,8 @@ void set_tones_config(const uint32_t bw, const uint32_t pre_silence, const uint1
|
|||||||
void kill_tone();
|
void kill_tone();
|
||||||
void set_sstv_data(const uint8_t vis_code, const uint32_t pixel_duration);
|
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,
|
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_fifo_data(const int8_t * data);
|
||||||
void set_pitch_rssi(int32_t avg, bool enabled);
|
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,
|
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,
|
||||||
|
@ -113,6 +113,8 @@ set(CPPSRC
|
|||||||
baseband_stats_collector.cpp
|
baseband_stats_collector.cpp
|
||||||
dsp_decimate.cpp
|
dsp_decimate.cpp
|
||||||
dsp_demodulate.cpp
|
dsp_demodulate.cpp
|
||||||
|
dsp_hilbert.cpp
|
||||||
|
dsp_modulate.cpp
|
||||||
dsp_goertzel.cpp
|
dsp_goertzel.cpp
|
||||||
matched_filter.cpp
|
matched_filter.cpp
|
||||||
spectrum_collector.cpp
|
spectrum_collector.cpp
|
||||||
@ -125,6 +127,7 @@ set(CPPSRC
|
|||||||
${COMMON}/dsp_fft.cpp
|
${COMMON}/dsp_fft.cpp
|
||||||
${COMMON}/dsp_fir_taps.cpp
|
${COMMON}/dsp_fir_taps.cpp
|
||||||
${COMMON}/dsp_iir.cpp
|
${COMMON}/dsp_iir.cpp
|
||||||
|
${COMMON}/dsp_sos.cpp
|
||||||
fxpt_atan2.cpp
|
fxpt_atan2.cpp
|
||||||
rssi.cpp
|
rssi.cpp
|
||||||
rssi_dma.cpp
|
rssi_dma.cpp
|
||||||
|
57
firmware/baseband/dsp_hilbert.cpp
Normal file
57
firmware/baseband/dsp_hilbert.cpp
Normal file
@ -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 */
|
44
firmware/baseband/dsp_hilbert.hpp
Normal file
44
firmware/baseband/dsp_hilbert.hpp
Normal file
@ -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__*/
|
137
firmware/baseband/dsp_modulate.cpp
Normal file
137
firmware/baseband/dsp_modulate.cpp
Normal file
@ -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 };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
96
firmware/baseband/dsp_modulate.hpp
Normal file
96
firmware/baseband/dsp_modulate.hpp
Normal file
@ -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__*/
|
@ -35,6 +35,7 @@ void MicTXProcessor::execute(const buffer_c8_t& buffer){
|
|||||||
if (!configured) return;
|
if (!configured) return;
|
||||||
|
|
||||||
audio_input.read_audio_buffer(audio_buffer);
|
audio_input.read_audio_buffer(audio_buffer);
|
||||||
|
modulator->execute(audio_buffer, buffer);
|
||||||
|
|
||||||
for (size_t i = 0; i < buffer.count; i++) {
|
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 = beep_gen.process(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
sample = tone_gen.process(sample);
|
sample = tone_gen.process(sample);
|
||||||
|
|
||||||
// FM
|
// FM
|
||||||
@ -87,6 +89,7 @@ void MicTXProcessor::execute(const buffer_c8_t& buffer){
|
|||||||
}
|
}
|
||||||
|
|
||||||
buffer.p[i] = { re, im };
|
buffer.p[i] = { re, im };
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,7 +99,40 @@ void MicTXProcessor::on_message(const Message* const msg) {
|
|||||||
|
|
||||||
switch(msg->id) {
|
switch(msg->id) {
|
||||||
case Message::ID::AudioTXConfig:
|
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;
|
audio_gain = config_message.audio_gain;
|
||||||
divider = config_message.divider;
|
divider = config_message.divider;
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
#include "baseband_thread.hpp"
|
#include "baseband_thread.hpp"
|
||||||
#include "audio_input.hpp"
|
#include "audio_input.hpp"
|
||||||
#include "tone_gen.hpp"
|
#include "tone_gen.hpp"
|
||||||
|
#include "dsp_modulate.hpp"
|
||||||
|
|
||||||
class MicTXProcessor : public BasebandProcessor {
|
class MicTXProcessor : public BasebandProcessor {
|
||||||
public:
|
public:
|
||||||
@ -50,7 +51,14 @@ private:
|
|||||||
AudioInput audio_input { };
|
AudioInput audio_input { };
|
||||||
ToneGen tone_gen { };
|
ToneGen tone_gen { };
|
||||||
ToneGen beep_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 { };
|
uint32_t divider { };
|
||||||
float audio_gain { };
|
float audio_gain { };
|
||||||
uint64_t power_acc { 0 };
|
uint64_t power_acc { 0 };
|
||||||
|
@ -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) {
|
void IIRBiquadFilter::execute_in_place(const buffer_f32_t& buffer) {
|
||||||
execute(buffer, 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;
|
||||||
|
}
|
||||||
|
@ -31,6 +31,9 @@ struct iir_biquad_config_t {
|
|||||||
std::array<float, 3> a;
|
std::array<float, 3> a;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 0..2 - b, 3..5 - a
|
||||||
|
typedef std::array<float, 6> iir_biquad_df2_config_t;
|
||||||
|
|
||||||
constexpr iir_biquad_config_t iir_config_passthrough {
|
constexpr iir_biquad_config_t iir_config_passthrough {
|
||||||
{ { 1.0f, 0.0f, 0.0f } },
|
{ { 1.0f, 0.0f, 0.0f } },
|
||||||
{ { 0.0f, 0.0f, 0.0f } },
|
{ { 0.0f, 0.0f, 0.0f } },
|
||||||
@ -67,4 +70,21 @@ private:
|
|||||||
std::array<float, 3> y { { 0.0f, 0.0f, 0.0f } };
|
std::array<float, 3> 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__*/
|
#endif/*__DSP_IIR_H__*/
|
||||||
|
22
firmware/common/dsp_sos.cpp
Normal file
22
firmware/common/dsp_sos.cpp
Normal file
@ -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"
|
51
firmware/common/dsp_sos.hpp
Normal file
51
firmware/common/dsp_sos.hpp
Normal file
@ -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 <cstdint>
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
template <size_t N>
|
||||||
|
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__*/
|
37
firmware/common/dsp_sos_config.hpp
Normal file
37
firmware/common/dsp_sos_config.hpp
Normal file
@ -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__*/
|
@ -856,13 +856,21 @@ public:
|
|||||||
const float deviation_hz,
|
const float deviation_hz,
|
||||||
const float audio_gain,
|
const float audio_gain,
|
||||||
const uint32_t tone_key_delta,
|
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 },
|
) : Message { ID::AudioTXConfig },
|
||||||
divider(divider),
|
divider(divider),
|
||||||
deviation_hz(deviation_hz),
|
deviation_hz(deviation_hz),
|
||||||
audio_gain(audio_gain),
|
audio_gain(audio_gain),
|
||||||
tone_key_delta(tone_key_delta),
|
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 float audio_gain;
|
||||||
const uint32_t tone_key_delta;
|
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;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SigGenConfigMessage : public Message {
|
class SigGenConfigMessage : public Message {
|
||||||
|
Loading…
Reference in New Issue
Block a user