Radio state initialization (#1236)

* WIP RadioState init

* TX/RX cleanup

* Update all apps using RadioState and setting modulation mode

* Set apps to use AM mode

* Don't push modulation update in RadioState.

* Support passing overrides to Audio and MicTX

* Support set_nearest on OptionsField, fix recon step

* Fix audio, typo

---------

Co-authored-by: kallanreed <kylereed@manzana.lan>
Co-authored-by: kallanreed <kallanreed@noreply.github.com>
This commit is contained in:
Kyle Reed 2023-07-04 16:26:26 -07:00 committed by GitHub
parent 80c769b97d
commit 9b665a43c5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 500 additions and 496 deletions

View File

@ -114,6 +114,8 @@ ResultCode load_settings(const std::string& app_name, AppSettings& settings) {
if (flags_enabled(settings.mode, Mode::RX)) { if (flags_enabled(settings.mode, Mode::RX)) {
read_setting(*data, setting::rx_frequency, settings.rx_frequency); read_setting(*data, setting::rx_frequency, settings.rx_frequency);
read_setting(*data, setting::lna, settings.lna);
read_setting(*data, setting::vga, settings.vga);
read_setting(*data, setting::rx_amp, settings.rx_amp); read_setting(*data, setting::rx_amp, settings.rx_amp);
read_setting(*data, setting::modulation, settings.modulation); read_setting(*data, setting::modulation, settings.modulation);
read_setting(*data, setting::am_config_index, settings.am_config_index); read_setting(*data, setting::am_config_index, settings.am_config_index);
@ -124,8 +126,6 @@ ResultCode load_settings(const std::string& app_name, AppSettings& settings) {
read_setting(*data, setting::baseband_bandwidth, settings.baseband_bandwidth); read_setting(*data, setting::baseband_bandwidth, settings.baseband_bandwidth);
read_setting(*data, setting::sampling_rate, settings.sampling_rate); read_setting(*data, setting::sampling_rate, settings.sampling_rate);
read_setting(*data, setting::lna, settings.lna);
read_setting(*data, setting::vga, settings.vga);
read_setting(*data, setting::step, settings.step); read_setting(*data, setting::step, settings.step);
read_setting(*data, setting::volume, settings.volume); read_setting(*data, setting::volume, settings.volume);
@ -153,6 +153,8 @@ ResultCode save_settings(const std::string& app_name, AppSettings& settings) {
if (flags_enabled(settings.mode, Mode::RX)) { if (flags_enabled(settings.mode, Mode::RX)) {
write_setting(settings_file, setting::rx_frequency, settings.rx_frequency); write_setting(settings_file, setting::rx_frequency, settings.rx_frequency);
write_setting(settings_file, setting::lna, settings.lna);
write_setting(settings_file, setting::vga, settings.vga);
write_setting(settings_file, setting::rx_amp, settings.rx_amp); write_setting(settings_file, setting::rx_amp, settings.rx_amp);
write_setting(settings_file, setting::modulation, settings.modulation); write_setting(settings_file, setting::modulation, settings.modulation);
write_setting(settings_file, setting::am_config_index, settings.am_config_index); write_setting(settings_file, setting::am_config_index, settings.am_config_index);
@ -163,8 +165,6 @@ ResultCode save_settings(const std::string& app_name, AppSettings& settings) {
write_setting(settings_file, setting::baseband_bandwidth, settings.baseband_bandwidth); write_setting(settings_file, setting::baseband_bandwidth, settings.baseband_bandwidth);
write_setting(settings_file, setting::sampling_rate, settings.sampling_rate); write_setting(settings_file, setting::sampling_rate, settings.sampling_rate);
write_setting(settings_file, setting::lna, settings.lna);
write_setting(settings_file, setting::vga, settings.vga);
write_setting(settings_file, setting::step, settings.step); write_setting(settings_file, setting::step, settings.step);
write_setting(settings_file, setting::volume, settings.volume); write_setting(settings_file, setting::volume, settings.volume);
@ -173,6 +173,7 @@ ResultCode save_settings(const std::string& app_name, AppSettings& settings) {
void copy_to_radio_model(const AppSettings& settings) { void copy_to_radio_model(const AppSettings& settings) {
// NB: Don't actually adjust the radio here or it will hang. // NB: Don't actually adjust the radio here or it will hang.
// Specifically 'modulation' which requires a running baseband.
if (flags_enabled(settings.mode, Mode::TX)) { if (flags_enabled(settings.mode, Mode::TX)) {
if (!flags_enabled(settings.options, Options::UseGlobalTargetFrequency)) if (!flags_enabled(settings.options, Options::UseGlobalTargetFrequency))
@ -203,14 +204,10 @@ void copy_from_radio_model(AppSettings& settings) {
if (flags_enabled(settings.mode, Mode::TX)) { if (flags_enabled(settings.mode, Mode::TX)) {
settings.tx_frequency = transmitter_model.target_frequency(); settings.tx_frequency = transmitter_model.target_frequency();
settings.baseband_bandwidth = transmitter_model.baseband_bandwidth(); settings.baseband_bandwidth = transmitter_model.baseband_bandwidth();
settings.sampling_rate = transmitter_model.sampling_rate();
settings.tx_amp = transmitter_model.rf_amp(); settings.tx_amp = transmitter_model.rf_amp();
settings.tx_gain = transmitter_model.tx_gain(); settings.tx_gain = transmitter_model.tx_gain();
settings.channel_bandwidth = transmitter_model.channel_bandwidth(); settings.channel_bandwidth = transmitter_model.channel_bandwidth();
// TODO: Do these make sense for TX?
settings.sampling_rate = transmitter_model.sampling_rate();
settings.lna = transmitter_model.lna();
settings.vga = transmitter_model.vga();
} }
if (flags_enabled(settings.mode, Mode::RX)) { if (flags_enabled(settings.mode, Mode::RX)) {

View File

@ -31,8 +31,6 @@
#include "string_format.hpp" #include "string_format.hpp"
#include "utility.hpp" #include "utility.hpp"
#include "debug.hpp"
using namespace portapack; using namespace portapack;
using namespace tonekey; using namespace tonekey;
@ -135,8 +133,7 @@ SPECOptionsView::SPECOptionsView(
AnalogAudioView::AnalogAudioView( AnalogAudioView::AnalogAudioView(
NavigationView& nav) NavigationView& nav)
: nav_(nav) { : nav_(nav) {
// A baseband image _must_ be running before // A baseband image _must_ be running before add waterfall view.
// interacting with the waterfall view.
baseband::run_image(portapack::spi_flash::image_tag_wideband_spectrum); baseband::run_image(portapack::spi_flash::image_tag_wideband_spectrum);
add_children({&rssi, add_children({&rssi,
@ -194,6 +191,15 @@ AnalogAudioView::AnalogAudioView(
on_modulation_changed(modulation); on_modulation_changed(modulation);
} }
AnalogAudioView::AnalogAudioView(
NavigationView& nav,
ReceiverModel::settings_t override)
: AnalogAudioView(nav) {
// TODO: Which other settings make sense to override?
on_frequency_step_changed(override.frequency_step);
options_modulation.set_by_value(toUType(override.mode));
}
size_t AnalogAudioView::get_spec_bw_index() { size_t AnalogAudioView::get_spec_bw_index() {
return spec_bw_index; return spec_bw_index;
} }

View File

@ -138,6 +138,7 @@ class SPECOptionsView : public View {
class AnalogAudioView : public View { class AnalogAudioView : public View {
public: public:
AnalogAudioView(NavigationView& nav); AnalogAudioView(NavigationView& nav);
AnalogAudioView(NavigationView& nav, ReceiverModel::settings_t override);
~AnalogAudioView(); ~AnalogAudioView();
void set_parent_rect(Rect new_parent_rect) override; void set_parent_rect(Rect new_parent_rect) override;

View File

@ -71,8 +71,6 @@ CaptureAppView::CaptureAppView(NavigationView& nav)
}; };
option_bandwidth.set_selected_index(7); // Preselected default option 500kHz. option_bandwidth.set_selected_index(7); // Preselected default option 500kHz.
receiver_model.set_modulation(ReceiverModel::Mode::Capture);
receiver_model.enable(); receiver_model.enable();
record_view.on_error = [&nav](std::string message) { record_view.on_error = [&nav](std::string message) {
@ -81,8 +79,6 @@ CaptureAppView::CaptureAppView(NavigationView& nav)
} }
CaptureAppView::~CaptureAppView() { CaptureAppView::~CaptureAppView() {
// Most other apps can't handle "Capture" mode, set to something standard.
receiver_model.set_modulation(ReceiverModel::Mode::WidebandFMAudio);
receiver_model.disable(); receiver_model.disable();
baseband::shutdown(); baseband::shutdown();
} }

View File

@ -50,7 +50,7 @@ class CaptureAppView : public View {
static constexpr ui::Dim header_height = 3 * 16; static constexpr ui::Dim header_height = 3 * 16;
NavigationView& nav_; NavigationView& nav_;
RxRadioState radio_state_{}; RxRadioState radio_state_{ReceiverModel::Mode::Capture};
app_settings::SettingsManager settings_{ app_settings::SettingsManager settings_{
"rx_capture", app_settings::Mode::RX, "rx_capture", app_settings::Mode::RX,
app_settings::Options::UseGlobalTargetFrequency}; app_settings::Options::UseGlobalTargetFrequency};

View File

@ -130,8 +130,7 @@ class ERTAppView : public View {
RxRadioState radio_state_{ RxRadioState radio_state_{
2500000 /* bandwidth */, 2500000 /* bandwidth */,
4194304 /* sampling rate */ 4194304 /* sampling rate */};
};
app_settings::SettingsManager settings_{ app_settings::SettingsManager settings_{
"rx_ert", app_settings::Mode::RX}; "rx_ert", app_settings::Mode::RX};

View File

@ -71,7 +71,6 @@ POCSAGAppView::POCSAGAppView(NavigationView& nav)
if (!settings_.loaded()) if (!settings_.loaded())
field_frequency.set_value(initial_target_frequency); field_frequency.set_value(initial_target_frequency);
receiver_model.set_modulation(ReceiverModel::Mode::NarrowbandFMAudio);
receiver_model.enable(); receiver_model.enable();
// TODO: app setting instead? // TODO: app setting instead?

View File

@ -106,8 +106,7 @@ class TPMSAppView : public View {
RxRadioState radio_state_{ RxRadioState radio_state_{
1750000 /* bandwidth */, 1750000 /* bandwidth */,
2457600 /* sampling rate */ 2457600 /* sampling rate */};
};
app_settings::SettingsManager settings_{ app_settings::SettingsManager settings_{
"rx_tpms", app_settings::Mode::RX}; "rx_tpms", app_settings::Mode::RX};

View File

@ -513,8 +513,7 @@ ADSBRxView::ADSBRxView(NavigationView& nav) {
baseband::set_adsb(); baseband::set_adsb();
receiver_model.set_target_frequency(1090000000); receiver_model.set_target_frequency(1'090'000'000);
receiver_model.set_modulation(ReceiverModel::Mode::SpectrumAnalysis);
receiver_model.enable(); receiver_model.enable();
} }

View File

@ -343,8 +343,8 @@ class ADSBRxView : public View {
private: private:
RxRadioState radio_state_{ RxRadioState radio_state_{
2500000 /* bandwidth */, 2500000 /* bandwidth */,
2000000 /* sampling rate */ 2000000 /* sampling rate */,
}; ReceiverModel::Mode::SpectrumAnalysis};
app_settings::SettingsManager settings_{ app_settings::SettingsManager settings_{
"rx_adsb", app_settings::Mode::RX}; "rx_adsb", app_settings::Mode::RX};

View File

@ -91,7 +91,6 @@ AFSKRxView::AFSKRxView(NavigationView& nav)
audio::set_rate(audio::Rate::Hz_24000); audio::set_rate(audio::Rate::Hz_24000);
audio::output::start(); audio::output::start();
receiver_model.set_modulation(ReceiverModel::Mode::NarrowbandFMAudio);
receiver_model.enable(); receiver_model.enable();
} }

View File

@ -119,7 +119,6 @@ APRSRxView::APRSRxView(NavigationView& nav, Rect parent_rect)
audio::set_rate(audio::Rate::Hz_24000); audio::set_rate(audio::Rate::Hz_24000);
audio::output::start(); audio::output::start();
receiver_model.set_modulation(ReceiverModel::Mode::NarrowbandFMAudio);
receiver_model.enable(); receiver_model.enable();
} }

View File

@ -76,7 +76,6 @@ BTLERxView::BTLERxView(NavigationView& nav)
audio::set_rate(audio::Rate::Hz_24000); audio::set_rate(audio::Rate::Hz_24000);
audio::output::start(); audio::output::start();
receiver_model.set_modulation(ReceiverModel::Mode::WidebandFMAudio);
receiver_model.enable(); receiver_model.enable();
} }

View File

@ -51,8 +51,8 @@ class BTLERxView : public View {
NavigationView& nav_; NavigationView& nav_;
RxRadioState radio_state_{ RxRadioState radio_state_{
4000000 /* bandwidth */, 4000000 /* bandwidth */,
4000000 /* sampling rate */ 4000000 /* sampling rate */,
}; ReceiverModel::Mode::WidebandFMAudio};
app_settings::SettingsManager settings_{ app_settings::SettingsManager settings_{
"rx_btle", app_settings::Mode::RX}; "rx_btle", app_settings::Mode::RX};

View File

@ -471,9 +471,9 @@ GlassView::GlassView(
button_marker.on_select = [this](ButtonWithEncoder&) { button_marker.on_select = [this](ButtonWithEncoder&) {
receiver_model.set_target_frequency(marker); // Center tune rx in marker freq. receiver_model.set_target_frequency(marker); // Center tune rx in marker freq.
receiver_model.set_frequency_step(MHZ_DIV); // Preset a 1 MHz frequency step into RX -> AUDIO auto settings = receiver_model.settings();
nav_.pop(); settings.frequency_step = MHZ_DIV; // Preset a 1 MHz frequency step into RX -> AUDIO
nav_.push<AnalogAudioView>(); // Jump into audio view nav_.replace<AnalogAudioView>(settings); // Jump into audio view
}; };
field_trigger.on_change = [this](int32_t v) { field_trigger.on_change = [this](int32_t v) {
@ -495,9 +495,9 @@ GlassView::GlassView(
button_jump.on_select = [this](Button&) { button_jump.on_select = [this](Button&) {
receiver_model.set_target_frequency(max_freq_hold); // Center tune rx in marker freq. receiver_model.set_target_frequency(max_freq_hold); // Center tune rx in marker freq.
receiver_model.set_frequency_step(MHZ_DIV); // Preset a 1 MHz frequency step into RX -> AUDIO auto settings = receiver_model.settings();
nav_.pop(); settings.frequency_step = MHZ_DIV; // Preset a 1 MHz frequency step into RX -> AUDIO
nav_.push<AnalogAudioView>(); // Jump into audio view nav_.replace<AnalogAudioView>(settings); // Jump into audio view
}; };
button_rst.on_select = [this](Button&) { button_rst.on_select = [this](Button&) {
@ -513,7 +513,6 @@ GlassView::GlassView(
marker_pixel_index = 120; marker_pixel_index = 120;
on_range_changed(); on_range_changed();
receiver_model.set_modulation(ReceiverModel::Mode::SpectrumAnalysis);
receiver_model.set_sampling_rate(looking_glass_sampling_rate); // 20mhz receiver_model.set_sampling_rate(looking_glass_sampling_rate); // 20mhz
receiver_model.set_baseband_bandwidth(looking_glass_bandwidth); // possible values: 1.75/2.5/3.5/5/5.5/6/7/8/9/10/12/14/15/20/24/28MHz receiver_model.set_baseband_bandwidth(looking_glass_bandwidth); // possible values: 1.75/2.5/3.5/5/5.5/6/7/8/9/10/12/14/15/20/24/28MHz
receiver_model.set_squelch_level(0); receiver_model.set_squelch_level(0);

View File

@ -71,7 +71,7 @@ class GlassView : public View {
private: private:
NavigationView& nav_; NavigationView& nav_;
RxRadioState radio_state_{}; RxRadioState radio_state_{ReceiverModel::Mode::SpectrumAnalysis};
app_settings::SettingsManager settings_{ app_settings::SettingsManager settings_{
"rx_glass", app_settings::Mode::RX}; "rx_glass", app_settings::Mode::RX};

View File

@ -145,25 +145,25 @@ void MicTXView::rxaudio(bool is_on) {
audio::input::stop(); audio::input::stop();
baseband::shutdown(); baseband::shutdown();
if (enable_am || enable_usb || enable_lsb || enable_dsb) { // "NFM/FM",0 ," WFM ",1 , " AM ",2, " USB ", 3, " LSB ",4, " DSB-SC", 5 if (enable_am || enable_usb || enable_lsb || enable_dsb) { // "NFM/FM", 0, " WFM ", 1, " AM ", 2, " USB ", 3, " LSB ", 4, " DSB-SC", 5
baseband::run_image(portapack::spi_flash::image_tag_am_audio); baseband::run_image(portapack::spi_flash::image_tag_am_audio);
receiver_model.set_modulation(ReceiverModel::Mode::AMAudio); // that AM demodulation engine is common to all Amplitude mod : AM/USB/LSB/DSB (2,3,4,5) receiver_model.set_modulation(ReceiverModel::Mode::AMAudio); // that AM demodulation engine is common to all Amplitude mod : AM/USB/LSB/DSB (2,3,4,5)
if (options_mode.selected_index() < 5) // We will be called here with 2,3,4,5 . We treat here demod. filter 2,3,4; (excluding DSB-C case (5) it is treated more down). if (options_mode.selected_index() < 5) // We will be called here with 2,3,4,5. We treat here demod. filter 2,3,4; (excluding DSB-C case (5) it is treated more down).
receiver_model.set_am_configuration(options_mode.selected_index() - 1); // selecting proper filter(2,3,4). 2-1=1=>6k-AM(1) , 3-1=2=>+3k-USB(2), 4-1=3=>-3K-LSB(3), receiver_model.set_am_configuration(options_mode.selected_index() - 1); // selecting proper filter(2,3,4). 2-1=1=>6k-AM(1), 3-1=2=>+3k-USB(2), 4-1=3=>-3K-LSB(3),
} else { // We are in NFM/FM or WFM (NFM BW:8k5 or 11k / FM BW 16k / WFM BW:200k) } else { // We are in NFM/FM or WFM (NFM BW:8k5 or 11k / FM BW 16k / WFM BW:200k)
if (enable_wfm) { // WFM , BW 200Khz aprox , or the two new addional BW filters (180k, 40k) if (enable_wfm) { // WFM, BW 200Khz aprox, or the two new addional BW filters (180k, 40k)
baseband::run_image(portapack::spi_flash::image_tag_wfm_audio); baseband::run_image(portapack::spi_flash::image_tag_wfm_audio);
receiver_model.set_modulation(ReceiverModel::Mode::WidebandFMAudio); receiver_model.set_modulation(ReceiverModel::Mode::WidebandFMAudio);
// receiver_model.set_wfm_configuration(n); // it is called above , depending user's selection (200k, 180k,40k). // receiver_model.set_wfm_configuration(n); // it is called above, depending user's selection (200k, 180k, 0k).
} else { // NFM BW:8k5 or 11k / FM BW 16k } else { // NFM BW:8k5 or 11k / FM BW 16k
baseband::run_image(portapack::spi_flash::image_tag_nfm_audio); baseband::run_image(portapack::spi_flash::image_tag_nfm_audio);
receiver_model.set_modulation(ReceiverModel::Mode::NarrowbandFMAudio); // receiver_model.set_modulation(ReceiverModel::Mode::NarrowbandFMAudio); //
// receiver_model.set_nbfm_configuration(n); is called above , depending user's selection (8k5, 11k, 16k). // receiver_model.set_nbfm_configuration(n); is called above, depending user's selection (8k5, 11k, 16k).
} }
} }
if (bool_same_F_tx_rx_enabled) // when stop TX ,define to which freq RX we return if (bool_same_F_tx_rx_enabled) // when stop TX, define to which freq RX we return
receiver_model.set_target_frequency(tx_frequency); // Update freq also for RX = TX receiver_model.set_target_frequency(tx_frequency); // Update freq also for RX = TX
else else
receiver_model.set_target_frequency(rx_frequency); // Now with separate freq controls! receiver_model.set_target_frequency(rx_frequency); // Now with separate freq controls!
@ -196,7 +196,7 @@ MicTXView::MicTXView(
baseband::run_image(portapack::spi_flash::image_tag_mic_tx); baseband::run_image(portapack::spi_flash::image_tag_mic_tx);
if (audio::debug::codec_name() == "WM8731") { if (audio::debug::codec_name() == "WM8731") {
add_children({&labels_WM8731, // we have audio codec WM8731, same MIC menu as original. add_children({&labels_WM8731, // we have audio codec WM8731, same MIC menu as original.
&vumeter, &vumeter,
&options_gain, // MIC GAIN float factor on the GUI. &options_gain, // MIC GAIN float factor on the GUI.
&options_wm8731_boost_mode, &options_wm8731_boost_mode,
@ -260,7 +260,7 @@ MicTXView::MicTXView(
mic_gain = v / 10.0; mic_gain = v / 10.0;
configure_baseband(); configure_baseband();
}; };
options_gain.set_selected_index(1); // x1.0 preselected default. options_gain.set_selected_index(1); // x1.0 preselected default.
if (audio::debug::codec_name() == "WM8731") { if (audio::debug::codec_name() == "WM8731") {
options_wm8731_boost_mode.on_change = [this](size_t, int8_t v) { options_wm8731_boost_mode.on_change = [this](size_t, int8_t v) {
@ -268,30 +268,30 @@ MicTXView::MicTXView(
case 0: // +12 dBs respect reference level orig fw 1.5.x fw FM : when +20dB's boost ON) and shift bits (>>8), case 0: // +12 dBs respect reference level orig fw 1.5.x fw FM : when +20dB's boost ON) and shift bits (>>8),
shift_bits_s16 = 6; // now mic-boost on (+20dBs) and shift bits (>>6), +20+12=32 dBs (orig fw +20 dBs+ 0dBs)=> +12dB's respect ref. shift_bits_s16 = 6; // now mic-boost on (+20dBs) and shift bits (>>6), +20+12=32 dBs (orig fw +20 dBs+ 0dBs)=> +12dB's respect ref.
break; break;
case 1: // +06 dBs reference level , (when +20dB's boost ON) case 1: // +06 dBs reference level, (when +20dB's boost ON)
shift_bits_s16 = 7; // now mic-boost on (+20dBs) and shift bits (>>7), +20+06=26 dBs (orig fw +20 dBs+ 0dBs) => +06dB's respect ref. shift_bits_s16 = 7; // now mic-boost on (+20dBs) and shift bits (>>7), +20+06=26 dBs (orig fw +20 dBs+ 0dBs) => +06dB's respect ref.
break; break;
case 2: case 2:
shift_bits_s16 = 4; // +04 dBs respect ref level , (when +20dB's boost OFF) shift_bits_s16 = 4; // +04 dBs respect ref level, (when +20dB's boost OFF)
break; // now mic-boost off (+00dBs) shift bits (4) (+0+24dB's)=24 dBs => +04dB's respect ref. break; // now mic-boost off (+00dBs) shift bits (4) (+0+24dB's)=24 dBs => +04dB's respect ref.
case 3: case 3:
shift_bits_s16 = 5; // -02 dBs respect ref level , (when +20dB's boost OFF) shift_bits_s16 = 5; // -02 dBs respect ref level, (when +20dB's boost OFF)
break; // now mic-boost off (+00dBs) shift bits (5) (+0+18dB's)=18 dBs => -02dB's respect ref. break; // now mic-boost off (+00dBs) shift bits (5) (+0+18dB's)=18 dBs => -02dB's respect ref.
case 4: case 4:
shift_bits_s16 = 6; // -08 dBs respect ref level , (when +20dB's boost OFF) shift_bits_s16 = 6; // -08 dBs respect ref level, (when +20dB's boost OFF)
break; // now mic-boost off (+00dBs) shift bits (6) (+0+12dB's)=12 dBs => -08dB's respect ref. break; // now mic-boost off (+00dBs) shift bits (6) (+0+12dB's)=12 dBs => -08dB's respect ref.
} }
ak4951_alc_and_wm8731_boost_GUI = v; // 0,..4 WM8731_boost dB's options, (combination boost on/off , and effective gain in captured data >>x) ak4951_alc_and_wm8731_boost_GUI = v; // 0..4, WM8731_boost dB's options, (combination boost on/off, and effective gain in captured data >>x)
audio::input::start(ak4951_alc_and_wm8731_boost_GUI); // Detected (WM8731) , set up the proper wm_boost on/off , 0..4 (0,1) boost_on , (2,3,4) boost_0ff audio::input::start(ak4951_alc_and_wm8731_boost_GUI); // Detected (WM8731), set up the proper wm_boost on/off, 0..4 (0,1) boost_on, (2,3,4) boost_off
configure_baseband(); // to update in real time, sending msg , var-parameters >>shift_bits FM msg ,to audio_tx from M0 to M4 Proc - configure_baseband(); // to update in real time, sending msg, var-parameters >>shift_bits FM msg, to audio_tx from M0 to M4 Proc -
}; };
options_wm8731_boost_mode.set_selected_index(3); // preset GUI index 3 as default WM -> -02 dB's . options_wm8731_boost_mode.set_selected_index(3); // preset GUI index 3 as default WM -> -02 dB's.
} else { } else {
shift_bits_s16 = 8; // Initialized default fixed >>8_FM for FM tx mod , shift audio data for AK4951 ,using top 8 bits s16 data (>>8) shift_bits_s16 = 8; // Initialized default fixed >>8_FM for FM tx mod, shift audio data for AK4951, using top 8 bits s16 data (>>8)
options_ak4951_alc_mode.on_change = [this](size_t, int8_t v) { options_ak4951_alc_mode.on_change = [this](size_t, int8_t v) {
ak4951_alc_and_wm8731_boost_GUI = v; // 0,..11, AK4951 Mic -Automatic volume Level Control options, ak4951_alc_and_wm8731_boost_GUI = v; // 0..11, AK4951 Mic -Automatic volume Level Control options,
audio::input::start(ak4951_alc_and_wm8731_boost_GUI); // Detected (AK4951) ==> Set up proper ALC mode from 0..11 options audio::input::start(ak4951_alc_and_wm8731_boost_GUI); // Detected (AK4951) ==> Set up proper ALC mode from 0..11 options
configure_baseband(); // sending fixed >>8_FM , var-parameters msg , to audiotx from this M0 to M4 process. configure_baseband(); // sending fixed >>8_FM, var-parameters msg, to audiotx from this M0 to M4 process.
}; };
} }
@ -329,11 +329,11 @@ MicTXView::MicTXView(
field_bw.on_change = [this](uint32_t v) { field_bw.on_change = [this](uint32_t v) {
transmitter_model.set_channel_bandwidth(v * 1000); transmitter_model.set_channel_bandwidth(v * 1000);
}; };
field_bw.set_value(10); // pre-default first time, TX deviation FM for NFM / FM field_bw.set_value(10); // pre-default first time, TX deviation FM for NFM / FM
// now , no need direct update , field_rfgain , field_rfamp (it is done in ui_transmitter.cpp) // now, no need direct update, field_rfgain, field_rfamp (it is done in ui_transmitter.cpp)
options_mode.on_change = [this](size_t, int32_t v) { //{ "NFM/FM", 0 }, { " WFM ", 1 },{ "AM", 2 },{ "USB", 3 },{ "LSB", 4 },{ "DSB", 5 } options_mode.on_change = [this](size_t, int32_t v) { // { "NFM/FM", 0 }, { " WFM ", 1 }, { "AM", 2 }, { "USB", 3 }, { "LSB", 4 }, { "DSB", 5 }
enable_am = false; enable_am = false;
enable_usb = false; enable_usb = false;
enable_lsb = false; enable_lsb = false;
@ -342,7 +342,7 @@ MicTXView::MicTXView(
using option_t = std::pair<std::string, int32_t>; using option_t = std::pair<std::string, int32_t>;
using options_t = std::vector<option_t>; using options_t = std::vector<option_t>;
options_t rxbw; // Aux structure to change dynamically field_rxbw contents, options_t rxbw; // Aux structure to change dynamically field_rxbw contents,
switch (v) { switch (v) {
case 0: //{ "FM", 0 } case 0: //{ "FM", 0 }
@ -354,15 +354,15 @@ MicTXView::MicTXView(
// field_bw.set_value(transmitter_model.channel_bandwidth() / 1000); // field_bw.set_value(transmitter_model.channel_bandwidth() / 1000);
// if (rx_enabled) // if (rx_enabled)
rxaudio(rx_enabled); // Update now if we have RX audio on rxaudio(rx_enabled); // Update now if we have RX audio on
options_tone_key.hidden(0); // we are in FM mode , we should have active the Key-tones & CTCSS option. options_tone_key.hidden(0); // we are in FM mode, we should have active the Key-tones & CTCSS option.
rxbw.emplace_back(" NFM1:8k5 ", 0); // restore the original dynamic field_rxbw value. rxbw.emplace_back(" NFM1:8k5 ", 0); // restore the original dynamic field_rxbw value.
rxbw.emplace_back(" NFM2:11k ", 1); rxbw.emplace_back(" NFM2:11k ", 1);
rxbw.emplace_back(" FM :16k ", 2); rxbw.emplace_back(" FM :16k ", 2);
field_rxbw.set_options(rxbw); // store that aux GUI option to the field_rxbw. field_rxbw.set_options(rxbw); // store that aux GUI option to the field_rxbw.
field_rxbw.hidden(0); // we are in FM mode, we need to allow the user set up of the RX NFM BW selection (8K5, 11K, 16K) field_rxbw.hidden(0); // we are in FM mode, we need to allow the user set up of the RX NFM BW selection (8K5, 11K, 16K)
field_bw.hidden(0); // we are in FM mode, we need to allow FM deviation parameter , in non FM mode. field_bw.hidden(0); // we are in FM mode, we need to allow FM deviation parameter, in non FM mode.
break; break;
case 1: //{ "WFM", 1 } case 1: //{ "WFM", 1 }
enable_am = false; enable_am = false;
@ -374,38 +374,38 @@ MicTXView::MicTXView(
// field_bw.set_value(transmitter_model.channel_bandwidth() / 1000); // field_bw.set_value(transmitter_model.channel_bandwidth() / 1000);
// if (rx_enabled) // if (rx_enabled)
rxaudio(rx_enabled); // Update now if we have RX audio on rxaudio(rx_enabled); // Update now if we have RX audio on
options_tone_key.hidden(0); // we are in WFM mode , we should have active the Key-tones & CTCSS option. options_tone_key.hidden(0); // we are in WFM mode, we should have active the Key-tones & CTCSS option.
rxbw.emplace_back(" 200k-WFM ", 0); // We allow the user selection of the 3 x WFM BW filters, (0) WFM-200K, (1) WFM-180K , (2) WFM-40K . rxbw.emplace_back(" 200k-WFM ", 0); // We allow the user selection of the 3 x WFM BW filters, (0) WFM-200K, (1) WFM-180K, (2) WFM-40K.
rxbw.emplace_back(" 180k-WFM ", 1); rxbw.emplace_back(" 180k-WFM ", 1);
rxbw.emplace_back(" 40k-WFM ", 2); rxbw.emplace_back(" 40k-WFM ", 2);
field_rxbw.set_options(rxbw); // store that aux GUI option to the field_rxbw. field_rxbw.set_options(rxbw); // store that aux GUI option to the field_rxbw.
field_rxbw.hidden(0); // we are in WFM mode, we need to show to the user the selected BW WFM filter . field_rxbw.hidden(0); // we are in WFM mode, we need to show to the user the selected BW WFM filter.
field_bw.hidden(0); // we are in WFM mode, we need to allow WFM deviation parameter , in non FM mode. field_bw.hidden(0); // we are in WFM mode, we need to allow WFM deviation parameter, in non FM mode.
break; break;
case 2: //{ "AM", 2 } case 2: //{ "AM", 2 }
enable_am = true; enable_am = true;
rxaudio(rx_enabled); // Update now if we have RX audio on rxaudio(rx_enabled); // Update now if we have RX audio on
options_tone_key.set_selected_index(0); // we are NOT in FM mode , we reset the possible previous key-tones &CTCSS selection. options_tone_key.set_selected_index(0); // we are NOT in FM mode, we reset the possible previous key-tones &CTCSS selection.
set_dirty(); // Refresh display set_dirty(); // Refresh display
options_tone_key.hidden(1); // we hide that Key-tones & CTCSS input selecction, (no meaning in AM/DSB/SSB). options_tone_key.hidden(1); // we hide that Key-tones & CTCSS input selecction, (no meaning in AM/DSB/SSB).
rxbw.emplace_back(" DSB1-9k ", 0); // we offer in AM DSB two audio BW 9k / 6k . rxbw.emplace_back(" DSB1-9k ", 0); // we offer in AM DSB two audio BW 9k / 6k.
rxbw.emplace_back(" DSB2-6k ", 1); rxbw.emplace_back(" DSB2-6k ", 1);
field_rxbw.set_options(rxbw); // store that aux GUI option to the field_rxbw. field_rxbw.set_options(rxbw); // store that aux GUI option to the field_rxbw.
field_rxbw.hidden(0); // we show fixed RX AM BW 6Khz field_rxbw.hidden(0); // we show fixed RX AM BW 6Khz
field_bw.hidden(1); // we hide the FM TX deviation parameter , in non FM mode. field_bw.hidden(1); // we hide the FM TX deviation parameter, in non FM mode.
check_rogerbeep.hidden(0); // make visible again the "rogerbeep" selection. check_rogerbeep.hidden(0); // make visible again the "rogerbeep" selection.
break; break;
case 3: //{ "USB", 3 } case 3: //{ "USB", 3 }
enable_usb = true; enable_usb = true;
rxaudio(rx_enabled); // Update now if we have RX audio on rxaudio(rx_enabled); // Update now if we have RX audio on
check_rogerbeep.set_value(false); // reset the possible activation of roger beep, because it is not compatible with SSB , by now. check_rogerbeep.set_value(false); // reset the possible activation of roger beep, because it is not compatible with SSB, by now.
check_rogerbeep.hidden(1); // hide that roger beep selection. check_rogerbeep.hidden(1); // hide that roger beep selection.
rxbw.emplace_back(" USB+3k ", 0); // locked a fixed option , to display it . rxbw.emplace_back(" USB+3k ", 0); // locked a fixed option, to display it.
field_rxbw.set_options(rxbw); // store that aux GUI option to the field_rxbw. field_rxbw.set_options(rxbw); // store that aux GUI option to the field_rxbw.
set_dirty(); // Refresh display set_dirty(); // Refresh display
@ -413,10 +413,10 @@ MicTXView::MicTXView(
case 4: //{ "LSB", 4 } case 4: //{ "LSB", 4 }
enable_lsb = true; enable_lsb = true;
rxaudio(rx_enabled); // Update now if we have RX audio on rxaudio(rx_enabled); // Update now if we have RX audio on
check_rogerbeep.set_value(false); // reset the possible activation of roger beep, because it is not compatible with SSB , by now. check_rogerbeep.set_value(false); // reset the possible activation of roger beep, because it is not compatible with SSB, by now.
check_rogerbeep.hidden(1); // hide that roger beep selection. check_rogerbeep.hidden(1); // hide that roger beep selection.
rxbw.emplace_back(" LSB-3k ", 0); // locked a fixed option , to display it . rxbw.emplace_back(" LSB-3k ", 0); // locked a fixed option, to display it.
field_rxbw.set_options(rxbw); // store that aux GUI option to the field_rxbw. field_rxbw.set_options(rxbw); // store that aux GUI option to the field_rxbw.
set_dirty(); // Refresh display set_dirty(); // Refresh display
@ -426,7 +426,7 @@ MicTXView::MicTXView(
rxaudio(rx_enabled); // Update now if we have RX audio on rxaudio(rx_enabled); // Update now if we have RX audio on
check_rogerbeep.hidden(0); // make visible again the "rogerbeep" selection. check_rogerbeep.hidden(0); // make visible again the "rogerbeep" selection.
rxbw.emplace_back("SSB1:USB+3k", 0); // added dynamically two options (index 0,1) to that DSB-C case to the field_rxbw value. rxbw.emplace_back("SSB1:USB+3k", 0); // added dynamically two options (index 0,1) to that DSB-C case to the field_rxbw value.
rxbw.emplace_back("SSB2:LSB-3k", 1); rxbw.emplace_back("SSB2:LSB-3k", 1);
field_rxbw.set_options(rxbw); // store that aux GUI option to the field_rxbw. field_rxbw.set_options(rxbw); // store that aux GUI option to the field_rxbw.
@ -479,7 +479,7 @@ MicTXView::MicTXView(
check_common_freq_tx_rx.on_select = [this](Checkbox&, bool v) { check_common_freq_tx_rx.on_select = [this](Checkbox&, bool v) {
bool_same_F_tx_rx_enabled = v; bool_same_F_tx_rx_enabled = v;
field_rxfrequency.hidden(v); // Hide or show separated freq RX field . (When no hide user can enter down indep. freq for RX) field_rxfrequency.hidden(v); // Hide or show separated freq RX field. (When no hide user can enter down indep. freq for RX)
set_dirty(); // Refresh GUI interface set_dirty(); // Refresh GUI interface
receiver_model.set_target_frequency(v ? tx_frequency : rx_frequency); // To go to the proper tuned freq. when toggling it receiver_model.set_target_frequency(v ? tx_frequency : rx_frequency); // To go to the proper tuned freq. when toggling it
}; };
@ -510,17 +510,17 @@ MicTXView::MicTXView(
field_rxbw.on_change = [this](size_t, int32_t v) { field_rxbw.on_change = [this](size_t, int32_t v) {
if (!(enable_am || enable_usb || enable_lsb || enable_dsb || enable_wfm)) { if (!(enable_am || enable_usb || enable_lsb || enable_dsb || enable_wfm)) {
// In Previous fw versions, that nbfm_configuration(n) was done in any mode (FM/AM/SSB/DSB)...strictly speaking only need it in (NFM/FM) // In Previous fw versions, that nbfm_configuration(n) was done in any mode (FM/AM/SSB/DSB)...strictly speaking only need it in (NFM/FM)
receiver_model.set_nbfm_configuration(v); // we are in NFM/FM case, we need to select proper NFM/FM RX channel filter , NFM BW 8K5(0), NFM BW 11K(1) , FM BW 16K (2) receiver_model.set_nbfm_configuration(v); // we are in NFM/FM case, we need to select proper NFM/FM RX channel filter, NFM BW 8K5(0), NFM BW 11K(1), FM BW 16K (2)
} else { // we are not in NFM/FM mode .(we could be in any of the rest : AM /USB/LSB/DSB-SC) } else { // we are not in NFM/FM mode. (we could be in any of the rest : AM /USB/LSB/DSB-SC)
if (enable_am) { // we are in AM TX mode , we will allow both independent RX audio BW : AM 9K (9K00AE3 / AM 6K (6K00AE3). (In AM option v can be 0 (9k) , 1 (6k) if (enable_am) { // we are in AM TX mode, we will allow both independent RX audio BW : AM 9K (9K00AE3 / AM 6K (6K00AE3). (In AM option v can be 0 (9k), 1 (6k)
receiver_model.set_am_configuration(v); // we are in AM TX mode , we need to select proper AM full path config AM-9K filter. 0+0 =>AM-9K(0), 0+1=1 =>AM-6K(1), receiver_model.set_am_configuration(v); // we are in AM TX mode, we need to select proper AM full path config AM-9K filter. 0+0 =>AM-9K(0), 0+1=1 =>AM-6K(1),
} }
if (enable_dsb) { // we are in DSB-SC in TX mode , we will allow both independent RX SSB demodulation (USB / LSB side band). in that submenu, v is 0 (SSB1 USB) or 1 (SSB2 LSB) if (enable_dsb) { // we are in DSB-SC in TX mode, we will allow both independent RX SSB demodulation (USB / LSB side band). in that submenu, v is 0 (SSB1 USB) or 1 (SSB2 LSB)
receiver_model.set_am_configuration(v + 2); // we are in DSB-SC TX mode , we need to select proper SSB filter. 0+2 =>usb(2), 1+2=3 =>lsb(3), receiver_model.set_am_configuration(v + 2); // we are in DSB-SC TX mode, we need to select proper SSB filter. 0+2 =>usb(2), 1+2=3 =>lsb(3),
} }
if (enable_wfm) { if (enable_wfm) {
receiver_model.set_wfm_configuration(v); // we are in WFM case, we need to select proper WFB RX BW filter , WFM BW 200K(0), WFM BW 180K(1) , WFM BW 40K(2) receiver_model.set_wfm_configuration(v); // we are in WFM case, we need to select proper WFB RX BW filter, WFM BW 200K(0), WFM BW 180K(1), WFM BW 40K(2)
} }
} }
}; };
@ -607,6 +607,36 @@ MicTXView::MicTXView(
audio::input::start(ak4951_alc_and_wm8731_boost_GUI); // When detected AK4951 => set up ALC mode; when detected WM8731 => set up mic_boost ON/OFF. audio::input::start(ak4951_alc_and_wm8731_boost_GUI); // When detected AK4951 => set up ALC mode; when detected WM8731 => set up mic_boost ON/OFF.
} }
MicTXView::MicTXView(
NavigationView& nav,
ReceiverModel::settings_t override)
: MicTXView(nav) {
// Try to use the modulation/bandwidth from RX settings.
// TODO: These concepts should be merged so there's only one.
// TODO: enums/constants for these indexes.
switch (override.mode) {
case ReceiverModel::Mode::AMAudio:
options_mode.set_selected_index(2);
break;
case ReceiverModel::Mode::NarrowbandFMAudio:
options_mode.set_selected_index(0);
break;
case ReceiverModel::Mode::WidebandFMAudio:
options_mode.set_selected_index(1);
break;
// Unsupported modulations.
case ReceiverModel::Mode::SpectrumAnalysis:
case ReceiverModel::Mode::Capture:
default:
break;
}
// TODO: bandwidth selection is tied too tightly to the UI
// controls. It's not possible to set the bandwidth here without
// refactoring. Also options_mode seems to have a category error.
}
MicTXView::~MicTXView() { MicTXView::~MicTXView() {
audio::input::stop(); audio::input::stop();
transmitter_model.set_target_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.set_target_frequency(tx_frequency); // Save Tx frequency instead of Rx. Or maybe we need some "System Wide" changes to seperate Tx and Rx frequency.

View File

@ -20,6 +20,8 @@
* Boston, MA 02110-1301, USA. * Boston, MA 02110-1301, USA.
*/ */
// TODO: Consolidate Modulation/Bandwidth modes/settings with freqman/receiver_model.
#ifndef __UI_MICTX_H__ #ifndef __UI_MICTX_H__
#define __UI_MICTX_H__ #define __UI_MICTX_H__
@ -43,6 +45,7 @@ namespace ui {
class MicTXView : public View { class MicTXView : public View {
public: public:
MicTXView(NavigationView& nav); MicTXView(NavigationView& nav);
MicTXView(NavigationView& nav, ReceiverModel::settings_t override);
~MicTXView(); ~MicTXView();
MicTXView(const MicTXView&) = delete; MicTXView(const MicTXView&) = delete;
@ -117,18 +120,19 @@ class MicTXView : public View {
uint8_t shift_bits_s16{4}; // shift bits factor to the captured ADC S16 audio sample. uint8_t shift_bits_s16{4}; // shift bits factor to the captured ADC S16 audio sample.
// AM TX Stuff // AM TX Stuff
// TODO: Some of this stuff is mutually exclusive. Need a better representation.
bool enable_am{false}; bool enable_am{false};
bool enable_dsb{false}; bool enable_dsb{false};
bool enable_usb{false}; bool enable_usb{false};
bool enable_lsb{false}; bool enable_lsb{false};
bool enable_wfm{false}; // added to distinguish in the FM mode , RX BW : NFM (8K5, 11K), FM (16K), WFM(200K) bool enable_wfm{false}; // added to distinguish in the FM mode, RX BW : NFM (8K5, 11K), FM (16K), WFM(200K)
Labels labels_WM8731{ Labels labels_WM8731{
{{3 * 8, 1 * 8}, "MIC-GAIN:", Color::light_grey()}, {{3 * 8, 1 * 8}, "MIC-GAIN:", Color::light_grey()},
{{17 * 8, 1 * 8}, "Boost", Color::light_grey()}, {{17 * 8, 1 * 8}, "Boost", Color::light_grey()},
{{3 * 8, 3 * 8}, "F:", Color::light_grey()}, {{3 * 8, 3 * 8}, "F:", Color::light_grey()},
{{15 * 8, 3 * 8}, "FM TXBW: kHz", Color::light_grey()}, // to be more symetric and consistent to the below FM RXBW {{15 * 8, 3 * 8}, "FM TXBW: kHz", Color::light_grey()}, // to be more symetric and consistent to the below FM RXBW
{{18 * 8, (5 * 8)}, "Mode:", Color::light_grey()}, // now , no need to handle GAIN , Amp here It is handled by ui_transmitter.cpp {{18 * 8, (5 * 8)}, "Mode:", Color::light_grey()}, // now, no need to handle GAIN, Amp here It is handled by ui_transmitter.cpp
{{3 * 8, 8 * 8}, "TX Activation:", Color::light_grey()}, // we delete { { 3 * 8, 5 * 8 }, "GAIN:", Color::light_grey() }, {{3 * 8, 8 * 8}, "TX Activation:", Color::light_grey()}, // we delete { { 3 * 8, 5 * 8 }, "GAIN:", Color::light_grey() },
{{4 * 8, 10 * 8}, "LVL:", Color::light_grey()}, // we delete { {11 * 8, 5 * 8 }, "Amp:", Color::light_grey() }, {{4 * 8, 10 * 8}, "LVL:", Color::light_grey()}, // we delete { {11 * 8, 5 * 8 }, "Amp:", Color::light_grey() },
{{12 * 8, 10 * 8}, "ATT:", Color::light_grey()}, {{12 * 8, 10 * 8}, "ATT:", Color::light_grey()},
@ -147,7 +151,7 @@ class MicTXView : public View {
{{17 * 8, 1 * 8}, "ALC", Color::light_grey()}, {{17 * 8, 1 * 8}, "ALC", Color::light_grey()},
{{3 * 8, 3 * 8}, "F:", Color::light_grey()}, {{3 * 8, 3 * 8}, "F:", Color::light_grey()},
{{15 * 8, 3 * 8}, "FM TXBW: kHz", Color::light_grey()}, {{15 * 8, 3 * 8}, "FM TXBW: kHz", Color::light_grey()},
{{18 * 8, (5 * 8)}, "Mode:", Color::light_grey()}, // now , no need to handle GAIN , Amp here It is handled by ui_transmitter.cpp {{18 * 8, (5 * 8)}, "Mode:", Color::light_grey()}, // now, no need to handle GAIN, Amp here It is handled by ui_transmitter.cpp
{{3 * 8, 8 * 8}, "TX Activation:", Color::light_grey()}, // we delete { { 3 * 8, 5 * 8 }, "GAIN:", Color::light_grey() }, {{3 * 8, 8 * 8}, "TX Activation:", Color::light_grey()}, // we delete { { 3 * 8, 5 * 8 }, "GAIN:", Color::light_grey() },
{{4 * 8, 10 * 8}, "LVL:", Color::light_grey()}, // we delete { {11 * 8, 5 * 8 }, "Amp:", Color::light_grey() }, {{4 * 8, 10 * 8}, "LVL:", Color::light_grey()}, // we delete { {11 * 8, 5 * 8 }, "Amp:", Color::light_grey() },
{{12 * 8, 10 * 8}, "ATT:", Color::light_grey()}, {{12 * 8, 10 * 8}, "ATT:", Color::light_grey()},
@ -176,15 +180,15 @@ class MicTXView : public View {
{"x2.0", 20}}}; {"x2.0", 20}}};
OptionsField options_ak4951_alc_mode{ OptionsField options_ak4951_alc_mode{
{20 * 8, 1 * 8}, // Coordinates are: int:x (px), int:y (px) {20 * 8, 1 * 8},
11, 11,
{ {
{" OFF-12kHz", 0}, // Nothing changed from ORIGINAL,keeping ALL programmable AK4951 Digital Block->OFF, sampling 24Khz) {" OFF-12kHz", 0}, // Nothing changed from ORIGINAL, keeping ALL programmable AK4951 Digital Block->OFF, sampling 24Khz)
{"+12dB-6kHz", 1}, // ALC-> on, (+12dB's) Auto Vol max + Wind Noise cancel + LPF 6kHz + Pre-amp Mic (+21dB=original) {"+12dB-6kHz", 1}, // ALC-> on, (+12dB's) Auto Vol max + Wind Noise cancel + LPF 6kHz + Pre-amp Mic (+21dB=original)
{"+09dB-6kHz", 2}, // ALC-> on, (+09dB's) Auto Vol max + Wind Noise cancel + LPF 6kHz + Pre-amp Mic (+21dB=original) {"+09dB-6kHz", 2}, // ALC-> on, (+09dB's) Auto Vol max + Wind Noise cancel + LPF 6kHz + Pre-amp Mic (+21dB=original)
{"+06dB-6kHz", 3}, // ALC-> on, (+06dB's) Auto Vol max + Wind Noise cancel + LPF 6kHz + Pre-amp Mic (+21dB=original) {"+06dB-6kHz", 3}, // ALC-> on, (+06dB's) Auto Vol max + Wind Noise cancel + LPF 6kHz + Pre-amp Mic (+21dB=original)
{"+03dB-2kHz", 4}, // ALC-> on, (+03dB's) Auto Vol max + Wind Noise cancel + LPF 3,5k + Pre-amp Mic (+21dB=original)+ EQ boosting ~<2kHz (f0~1k1,fb:1,7K, k=1,8) {"+03dB-2kHz", 4}, // ALC-> on, (+03dB's) Auto Vol max + Wind Noise cancel + LPF 3,5k + Pre-amp Mic (+21dB=original)+ EQ boosting ~<2kHz (f0~1k1, fb:1,7K, k=1,8)
{"+03dB-4kHz", 5}, // ALC-> on, (+03dB's) Auto Vol max + Wind Noise cancel + LPF 4kHz + Pre-amp Mic (+21dB=original)+ EQ boosting ~<3kHz (f0~1k4,fb~2,4k, k=1,8) {"+03dB-4kHz", 5}, // ALC-> on, (+03dB's) Auto Vol max + Wind Noise cancel + LPF 4kHz + Pre-amp Mic (+21dB=original)+ EQ boosting ~<3kHz (f0~1k4, fb~2,4k, k=1,8)
{"+03dB-6kHz", 6}, // ALC-> on, (+03dB's) Auto Vol max + Wind Noise cancel + LPF 6kHz + Pre-amp Mic (+21dB=original) {"+03dB-6kHz", 6}, // ALC-> on, (+03dB's) Auto Vol max + Wind Noise cancel + LPF 6kHz + Pre-amp Mic (+21dB=original)
{"+00dB-6kHz", 7}, // ALC-> on, (+00dB's) Auto Vol max + Wind Noise cancel + LPF 6kHz + Pre-amp Mic (+21dB=original) {"+00dB-6kHz", 7}, // ALC-> on, (+00dB's) Auto Vol max + Wind Noise cancel + LPF 6kHz + Pre-amp Mic (+21dB=original)
{"-03dB-6kHz", 8}, // ALC-> on, (-03dB's) Auto Vol max + Wind Noise cancel + LPF 6kHz + Pre-amp Mic (+21dB=original) {"-03dB-6kHz", 8}, // ALC-> on, (-03dB's) Auto Vol max + Wind Noise cancel + LPF 6kHz + Pre-amp Mic (+21dB=original)
@ -194,14 +198,14 @@ class MicTXView : public View {
}}; }};
OptionsField options_wm8731_boost_mode{ OptionsField options_wm8731_boost_mode{
{22 * 8, 1 * 8}, // Coordinates are: int:x (px), int:y (px) {22 * 8, 1 * 8},
5, 5,
{ {
{"ON +12dB", 0}, // WM8731 Mic Boost ON ,original+12dBs condition, easy to saturate ADC sat in high voice ,relative G = +12 dB's respect ref level {"ON +12dB", 0}, // WM8731 Mic Boost ON, original+12dBs condition, easy to saturate ADC sat in high voice, relative G = +12 dB's respect ref level
{"ON +06dB", 1}, // WM8731 Mic Boost ON ,original+6 dBs condition, easy to saturate ADC sat in high voice ,relative G = +06 dB's respect ref level {"ON +06dB", 1}, // WM8731 Mic Boost ON, original+6 dBs condition, easy to saturate ADC sat in high voice, relative G = +06 dB's respect ref level
{"OFF+04dB", 2}, // WM8731 Mic Boost OFF to avoid ADC sat in high voice ,relative G = +04 dB's (respect ref level) , always effective sampling 24khz {"OFF+04dB", 2}, // WM8731 Mic Boost OFF to avoid ADC sat in high voice, relative G = +04 dB's (respect ref level), always effective sampling 24khz
{"OFF-02dB", 3}, // WM8731 Mic Boost OFF to avoid ADC sat in high voice ,relative G = -02 dB's (respect ref level) {"OFF-02dB", 3}, // WM8731 Mic Boost OFF to avoid ADC sat in high voice, relative G = -02 dB's (respect ref level)
{"OFF-08dB", 4}, // WM8731 Mic Boost OFF to avoid ADC sat in high voice ,relative G = -12 dB's (respect ref level) {"OFF-08dB", 4}, // WM8731 Mic Boost OFF to avoid ADC sat in high voice, relative G = -12 dB's (respect ref level)
}}; }};
// TODO: Use TxFrequencyField // TODO: Use TxFrequencyField
@ -227,7 +231,7 @@ class MicTXView : public View {
{ {
{"NFM/FM", 0}, {"NFM/FM", 0},
{" WFM ", 1}, {" WFM ", 1},
{" AM ", 2}, // in fact that TX mode = AM -DSB with carrier . {" AM ", 2}, // in fact that TX mode = AM -DSB with carrier.
{" USB ", 3}, {" USB ", 3},
{" LSB ", 4}, {" LSB ", 4},
{"DSB-SC", 5} // We are TX Double Side AM Band with suppressed carrier, and allowing in RX both indep SSB lateral band (USB/LSB). {"DSB-SC", 5} // We are TX Double Side AM Band with suppressed carrier, and allowing in RX both indep SSB lateral band (USB/LSB).

View File

@ -76,7 +76,6 @@ NRFRxView::NRFRxView(NavigationView& nav)
audio::set_rate(audio::Rate::Hz_24000); audio::set_rate(audio::Rate::Hz_24000);
audio::output::start(); audio::output::start();
receiver_model.set_modulation(ReceiverModel::Mode::WidebandFMAudio);
receiver_model.enable(); receiver_model.enable();
} }

View File

@ -51,8 +51,8 @@ class NRFRxView : public View {
NavigationView& nav_; NavigationView& nav_;
RxRadioState radio_state_{ RxRadioState radio_state_{
4000000 /* bandwidth */, 4000000 /* bandwidth */,
4000000 /* sampling rate */ 4000000 /* sampling rate */,
}; ReceiverModel::Mode::WidebandFMAudio};
app_settings::SettingsManager settings_{ app_settings::SettingsManager settings_{
"rx_nrf", app_settings::Mode::RX}; "rx_nrf", app_settings::Mode::RX};

View File

@ -80,8 +80,7 @@ bool POCSAGTXView::start_tx() {
progressbar.set_max(total_frames); progressbar.set_max(total_frames);
transmitter_model.set_rf_amp(true); transmitter_model.set_rf_amp(true);
transmitter_model.set_lna(40); transmitter_model.set_tx_gain(40);
transmitter_model.set_vga(40);
transmitter_model.enable(); transmitter_model.enable();
uint8_t* data_ptr = shared_memory.bb_data.data; uint8_t* data_ptr = shared_memory.bb_data.data;

View File

@ -366,7 +366,6 @@ ReconView::~ReconView() {
recon_save_config_to_sd(); recon_save_config_to_sd();
if (field_mode.selected_index_value() != SPEC_MODULATION) if (field_mode.selected_index_value() != SPEC_MODULATION)
audio::output::stop(); audio::output::stop();
receiver_model.set_modulation(ReceiverModel::Mode::WidebandFMAudio);
receiver_model.disable(); receiver_model.disable();
baseband::shutdown(); baseband::shutdown();
} }
@ -549,8 +548,9 @@ ReconView::ReconView(NavigationView& nav)
}; };
button_audio_app.on_select = [this](Button&) { button_audio_app.on_select = [this](Button&) {
nav_.pop(); auto settings = receiver_model.settings();
nav_.push<AnalogAudioView>(); settings.frequency_step = step_mode.selected_index_value();
nav_.replace<AnalogAudioView>(settings);
}; };
button_loop_config.on_select = [this](Button&) { button_loop_config.on_select = [this](Button&) {
@ -569,9 +569,9 @@ ReconView::ReconView(NavigationView& nav)
button_mic_app.on_select = [this](Button&) { button_mic_app.on_select = [this](Button&) {
if (frequency_list.size() > 0 && current_index >= 0 && (unsigned)current_index < frequency_list.size()) { if (frequency_list.size() > 0 && current_index >= 0 && (unsigned)current_index < frequency_list.size()) {
if (frequency_list[current_index].type == HAMRADIO) { if (frequency_list[current_index].type == HAMRADIO) {
// if it's a HAMRADIO entry, then frequency_a is the freq at which the repeater reveive, so we have to set it in transmit in mic app // if it's a HAMRADIO entry, then frequency_a is the freq at which the repeater receives, so we have to set it in transmit in mic app
transmitter_model.set_target_frequency(frequency_list[current_index].frequency_a); transmitter_model.set_target_frequency(frequency_list[current_index].frequency_a);
// if it's a HAMRADIO entry, then frequency_b is the freq at which the repeater transmit, so we have to set it in receive in mic app // if it's a HAMRADIO entry, then frequency_b is the freq at which the repeater transmits, so we have to set it in receive in mic app
receiver_model.set_target_frequency(frequency_list[current_index].frequency_b); receiver_model.set_target_frequency(frequency_list[current_index].frequency_b);
} else { } else {
// it's single or range so we us actual tuned frequency // it's single or range so we us actual tuned frequency
@ -579,9 +579,9 @@ ReconView::ReconView(NavigationView& nav)
receiver_model.set_target_frequency(freq); receiver_model.set_target_frequency(freq);
} }
} }
// there is no way yet to set modulation and bandwidth from Recon to MicApp
nav_.pop(); // MicTX wants Modulation and Bandwidth overrides, but that's only stored on the RX model.
nav_.push<MicTXView>(); nav_.replace<MicTXView>(receiver_model.settings());
}; };
button_remove.on_select = [this](ButtonWithEncoder&) { button_remove.on_select = [this](ButtonWithEncoder&) {

View File

@ -392,16 +392,17 @@ ScannerView::ScannerView(
button_audio_app.on_select = [this](Button&) { button_audio_app.on_select = [this](Button&) {
if (scan_thread) if (scan_thread)
scan_thread->stop(); scan_thread->stop();
nav_.pop(); auto settings = receiver_model.settings();
nav_.push<AnalogAudioView>(); settings.frequency_step = field_step.selected_index_value();
nav_.replace<AnalogAudioView>(settings);
}; };
// Button to switch to Mic app // Button to switch to Mic app
button_mic_app.on_select = [this](Button&) { button_mic_app.on_select = [this](Button&) {
if (scan_thread) if (scan_thread)
scan_thread->stop(); scan_thread->stop();
nav_.pop(); // MicTX wants Modulation and Bandwidth overrides, but that's only stored on the RX model.
nav_.push<MicTXView>(); nav_.replace<MicTXView>(receiver_model.settings());
}; };
// Button to delete current frequency from scan Freq List // Button to delete current frequency from scan Freq List

View File

@ -122,17 +122,7 @@ void SearchView::do_detection() {
locked = true; locked = true;
locked_bin = bin_max; locked_bin = bin_max;
// TODO // TODO: open Audio.
/*nav_.pop();
receiver_model.disable();
baseband::shutdown();
nav_.pop();*/
/*if (options_goto.selected_index() == 1)
nav_.push<AnalogAudioView>(false);
else if (options_goto.selected_index() == 2)
nav_.push<POCSAGAppView>();
*/
} else } else
text_infos.set("Out of range"); text_infos.set("Out of range");
} }
@ -414,7 +404,6 @@ SearchView::SearchView(
on_range_changed(); on_range_changed();
receiver_model.set_modulation(ReceiverModel::Mode::SpectrumAnalysis);
receiver_model.enable(); receiver_model.enable();
} }

View File

@ -92,8 +92,8 @@ class SearchView : public View {
NavigationView& nav_; NavigationView& nav_;
RxRadioState radio_state_{ RxRadioState radio_state_{
2500000 /* bandwidth */, 2500000 /* bandwidth */,
SEARCH_SLICE_WIDTH /* sampling rate */ SEARCH_SLICE_WIDTH /* sampling rate */,
}; ReceiverModel::Mode::SpectrumAnalysis};
struct slice_t { struct slice_t {
rf::Frequency center_frequency; rf::Frequency center_frequency;

View File

@ -27,6 +27,8 @@
using option_t = std::pair<std::string, int32_t>; using option_t = std::pair<std::string, int32_t>;
using options_t = std::vector<option_t>; using options_t = std::vector<option_t>;
// TODO: Consolidate with receiver_model.
// These definitions are spread all over and stiched together with indices.
options_t freqman_entry_modulations = { options_t freqman_entry_modulations = {
{"AM", 0}, {"AM", 0},
{"NFM", 1}, {"NFM", 1},

View File

@ -28,38 +28,47 @@
#include "receiver_model.hpp" #include "receiver_model.hpp"
#include "transmitter_model.hpp" #include "transmitter_model.hpp"
/* Stashes current radio bandwidth and sampling rate. /* Reinitialized model with defaults so each app can start
* Inits to defaults, and restores previous when destroyed. * with a clean, default model instance. We tried lazily
* The idea here is that an app will eventually call enable * setting these using the set_configuration_without_update
* on the model which will sync all of the model state into * function, but there are still various UI components
* the radio. We tried lazily setting these using the * (e.g. Waterfall) that need the radio set in order to load.
* set_configuration_without_update function, but there are
* still various UI components (mainly Waterfall) that need
* the radio set in order to load properly.
* NB: This member must be added before SettingsManager. */ * NB: This member must be added before SettingsManager. */
template <typename TModel, TModel* model> template <typename TModel, TModel* model>
class RadioState { class RadioState {
public: public:
RadioState() RadioState() {
: RadioState(max2837::filter::bandwidth_minimum, 3072000) { model->initialize();
} }
RadioState(uint32_t new_bandwidth, uint32_t new_sampling_rate) RadioState(uint32_t new_bandwidth, uint32_t new_sampling_rate) {
: prev_bandwidth_{model->baseband_bandwidth()}, model->initialize();
prev_sampling_rate_{model->sampling_rate()} {
// Update the new settings in the radio.
model->set_sampling_rate(new_sampling_rate); model->set_sampling_rate(new_sampling_rate);
model->set_baseband_bandwidth(new_bandwidth); model->set_baseband_bandwidth(new_bandwidth);
} }
~RadioState() { // NB: only enabled for RX model.
model->set_configuration_without_update( template <
prev_bandwidth_, prev_sampling_rate_); typename U = TModel,
typename Mode = std::enable_if_t<sizeof(typename U::Mode), typename U::Mode> >
RadioState(Mode new_mode) {
model->initialize();
model->settings().mode = new_mode;
} }
private: // NB: only enabled for RX model.
const uint32_t prev_bandwidth_; template <
const uint32_t prev_sampling_rate_; typename U = TModel,
typename Mode = std::enable_if_t<sizeof(typename U::Mode), typename U::Mode> >
RadioState(
uint32_t new_bandwidth,
uint32_t new_sampling_rate,
Mode new_mode) {
model->initialize();
model->set_sampling_rate(new_sampling_rate);
model->set_baseband_bandwidth(new_bandwidth);
model->settings().mode = new_mode;
}
}; };
using RxRadioState = RadioState<ReceiverModel, &portapack::receiver_model>; using RxRadioState = RadioState<ReceiverModel, &portapack::receiver_model>;

View File

@ -1,5 +1,6 @@
/* /*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc. * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2023 Kyle Reed
* *
* This file is part of PortaPack. * This file is part of PortaPack.
* *
@ -39,9 +40,9 @@ using namespace portapack;
namespace { namespace {
static constexpr std::array<baseband::AMConfig, 5> am_configs{{ static constexpr std::array<baseband::AMConfig, 5> am_configs{{
// we config here all the non COMMON parameters to each AM modulation type in RX. // we config here all the non COMMON parameters to each AM modulation type in RX.
{taps_9k0_decim_2, taps_9k0_dsb_channel, AMConfigureMessage::Modulation::DSB}, // AM DSB-C BW 9khz (+-4k5) commercial EU bandwidth . {taps_9k0_decim_2, taps_9k0_dsb_channel, AMConfigureMessage::Modulation::DSB}, // AM DSB-C BW 9khz (+-4k5) commercial EU bandwidth .
{taps_6k0_decim_2, taps_6k0_dsb_channel, AMConfigureMessage::Modulation::DSB}, // AM DSB-C BW 6khz (+-3k0) narrow AM , ham equipments. {taps_6k0_decim_2, taps_6k0_dsb_channel, AMConfigureMessage::Modulation::DSB}, // AM DSB-C BW 6khz (+-3k0) narrow AM , ham equipments.
{taps_6k0_decim_2, taps_2k8_usb_channel, AMConfigureMessage::Modulation::SSB}, // SSB USB BW 2K8 (+ 2K8) {taps_6k0_decim_2, taps_2k8_usb_channel, AMConfigureMessage::Modulation::SSB}, // SSB USB BW 2K8 (+ 2K8)
{taps_6k0_decim_2, taps_2k8_lsb_channel, AMConfigureMessage::Modulation::SSB}, // SSB LSB BW 2K8 (- 2K8) {taps_6k0_decim_2, taps_2k8_lsb_channel, AMConfigureMessage::Modulation::SSB}, // SSB LSB BW 2K8 (- 2K8)
{taps_6k0_decim_2, taps_0k7_usb_channel, AMConfigureMessage::Modulation::SSB}, // SSB USB BW 0K7 (+ 0K7) used to get audio tone from CW Morse, assuming tx shifted +700hz aprox {taps_6k0_decim_2, taps_0k7_usb_channel, AMConfigureMessage::Modulation::SSB}, // SSB USB BW 0K7 (+ 0K7) used to get audio tone from CW Morse, assuming tx shifted +700hz aprox
@ -70,72 +71,114 @@ void ReceiverModel::set_target_frequency(rf::Frequency f) {
update_tuning_frequency(); update_tuning_frequency();
} }
uint32_t ReceiverModel::baseband_bandwidth() const {
return settings_.baseband_bandwidth;
}
void ReceiverModel::set_baseband_bandwidth(uint32_t v) {
settings_.baseband_bandwidth = v;
update_baseband_bandwidth();
}
uint32_t ReceiverModel::sampling_rate() const {
return settings_.sampling_rate;
}
void ReceiverModel::set_sampling_rate(uint32_t v) {
settings_.sampling_rate = v;
update_sampling_rate();
}
rf::Frequency ReceiverModel::frequency_step() const { rf::Frequency ReceiverModel::frequency_step() const {
return frequency_step_; return settings_.frequency_step;
} }
void ReceiverModel::set_frequency_step(rf::Frequency f) { void ReceiverModel::set_frequency_step(rf::Frequency f) {
frequency_step_ = f; settings_.frequency_step = f;
}
uint8_t ReceiverModel::lna() const {
return settings_.lna_gain_db;
}
void ReceiverModel::set_lna(uint8_t v_db) {
settings_.lna_gain_db = v_db;
update_lna();
}
uint8_t ReceiverModel::vga() const {
return settings_.vga_gain_db;
}
void ReceiverModel::set_vga(uint8_t v_db) {
settings_.vga_gain_db = v_db;
update_vga();
}
bool ReceiverModel::rf_amp() const {
return settings_.rf_amp;
}
void ReceiverModel::set_rf_amp(bool enabled) {
settings_.rf_amp = enabled;
update_rf_amp();
}
ReceiverModel::Mode ReceiverModel::modulation() const {
return settings_.mode;
}
void ReceiverModel::set_modulation(Mode v) {
settings_.mode = v;
update_modulation();
}
uint8_t ReceiverModel::am_configuration() const {
return settings_.am_config_index;
}
void ReceiverModel::set_am_configuration(uint8_t n) {
if (n < am_configs.size()) {
settings_.am_config_index = n;
update_modulation();
}
}
uint8_t ReceiverModel::nbfm_configuration() const {
return settings_.nbfm_config_index;
}
void ReceiverModel::set_nbfm_configuration(uint8_t n) {
if (n < nbfm_configs.size()) {
settings_.nbfm_config_index = n;
update_modulation();
}
}
uint8_t ReceiverModel::wfm_configuration() const {
return settings_.wfm_config_index;
}
void ReceiverModel::set_wfm_configuration(uint8_t n) {
if (n < wfm_configs.size()) {
settings_.wfm_config_index = n;
update_modulation();
}
}
uint8_t ReceiverModel::squelch_level() const {
return settings_.squelch_level;
}
void ReceiverModel::set_squelch_level(uint8_t v) {
settings_.squelch_level = v;
update_modulation();
} }
void ReceiverModel::set_antenna_bias() { void ReceiverModel::set_antenna_bias() {
update_antenna_bias(); update_antenna_bias();
} }
bool ReceiverModel::rf_amp() const {
return rf_amp_;
}
void ReceiverModel::set_rf_amp(bool enabled) {
rf_amp_ = enabled;
update_rf_amp();
}
int32_t ReceiverModel::lna() const {
return lna_gain_db_;
}
void ReceiverModel::set_lna(int32_t v_db) {
lna_gain_db_ = v_db;
update_lna();
}
uint32_t ReceiverModel::baseband_bandwidth() const {
return baseband_bandwidth_;
}
void ReceiverModel::set_baseband_bandwidth(uint32_t v) {
baseband_bandwidth_ = v;
update_baseband_bandwidth();
}
int32_t ReceiverModel::vga() const {
return vga_gain_db_;
}
void ReceiverModel::set_vga(int32_t v_db) {
vga_gain_db_ = v_db;
update_vga();
}
uint32_t ReceiverModel::sampling_rate() const {
return sampling_rate_;
}
void ReceiverModel::set_sampling_rate(uint32_t v) {
sampling_rate_ = v;
update_sampling_rate();
}
ReceiverModel::Mode ReceiverModel::modulation() const {
return mode_;
}
void ReceiverModel::set_modulation(const Mode v) {
mode_ = v;
update_modulation();
}
volume_t ReceiverModel::headphone_volume() const { volume_t ReceiverModel::headphone_volume() const {
return persistent_memory::headphone_volume(); return persistent_memory::headphone_volume();
} }
@ -157,15 +200,6 @@ void ReceiverModel::set_normalized_headphone_volume(uint8_t v) {
set_headphone_volume(new_volume); set_headphone_volume(new_volume);
} }
uint8_t ReceiverModel::squelch_level() const {
return squelch_level_;
}
void ReceiverModel::set_squelch_level(uint8_t v) {
squelch_level_ = v;
update_modulation();
}
void ReceiverModel::enable() { void ReceiverModel::enable() {
enabled_ = true; enabled_ = true;
radio::set_direction(rf::Direction::Receive); radio::set_direction(rf::Direction::Receive);
@ -193,6 +227,35 @@ void ReceiverModel::disable() {
led_rx.off(); led_rx.off();
} }
void ReceiverModel::initialize() {
settings_ = settings_t{};
}
void ReceiverModel::set_configuration_without_update(
Mode new_mode,
rf::Frequency new_frequency_step,
size_t new_am_config_index,
size_t new_nbfm_config_index,
size_t new_wfm_config_index,
uint8_t new_squelch_level) {
settings_.mode = new_mode;
settings_.frequency_step = new_frequency_step;
settings_.am_config_index = new_am_config_index;
settings_.nbfm_config_index = new_nbfm_config_index;
settings_.wfm_config_index = new_wfm_config_index;
settings_.squelch_level = new_squelch_level;
}
void ReceiverModel::configure_from_app_settings(
const app_settings::AppSettings& settings) {
settings_.baseband_bandwidth = settings.baseband_bandwidth;
settings_.sampling_rate = settings.sampling_rate;
settings_.lna_gain_db = settings.lna;
settings_.vga_gain_db = settings.vga;
settings_.rf_amp = settings.rx_amp;
settings_.squelch_level = settings.squelch;
}
int32_t ReceiverModel::tuning_offset() { int32_t ReceiverModel::tuning_offset() {
if ((modulation() == Mode::SpectrumAnalysis)) { if ((modulation() == Mode::SpectrumAnalysis)) {
return 0; return 0;
@ -206,78 +269,8 @@ void ReceiverModel::update_tuning_frequency() {
radio::set_tuning_frequency(target_frequency() + tuning_offset()); radio::set_tuning_frequency(target_frequency() + tuning_offset());
} }
void ReceiverModel::update_antenna_bias() {
if (enabled_)
radio::set_antenna_bias(portapack::get_antenna_bias());
}
void ReceiverModel::update_rf_amp() {
radio::set_rf_amp(rf_amp_);
}
void ReceiverModel::update_lna() {
radio::set_lna_gain(lna_gain_db_);
}
void ReceiverModel::update_baseband_bandwidth() { void ReceiverModel::update_baseband_bandwidth() {
radio::set_baseband_filter_bandwidth(baseband_bandwidth_); radio::set_baseband_filter_bandwidth(baseband_bandwidth());
}
void ReceiverModel::update_vga() {
radio::set_vga_gain(vga_gain_db_);
}
void ReceiverModel::set_am_configuration(const size_t n) {
if (n < am_configs.size()) {
am_config_index = n;
update_modulation();
}
}
void ReceiverModel::set_nbfm_configuration(const size_t n) {
if (n < nbfm_configs.size()) {
nbfm_config_index = n;
update_modulation();
}
}
void ReceiverModel::set_wfm_configuration(const size_t n) {
if (n < wfm_configs.size()) {
wfm_config_index = n;
update_modulation();
}
}
void ReceiverModel::set_configuration_without_update(
uint32_t baseband_bandwidth,
uint32_t sampling_rate) {
baseband_bandwidth_ = baseband_bandwidth;
sampling_rate_ = sampling_rate;
}
void ReceiverModel::set_configuration_without_update(
Mode new_mode,
rf::Frequency new_frequency_step,
size_t new_am_config_index,
size_t new_nbfm_config_index,
size_t new_wfm_config_index,
uint8_t new_squelch_level) {
mode_ = new_mode;
frequency_step_ = new_frequency_step;
am_config_index = new_am_config_index;
nbfm_config_index = new_nbfm_config_index;
wfm_config_index = new_wfm_config_index;
squelch_level_ = new_squelch_level;
}
void ReceiverModel::configure_from_app_settings(
const app_settings::AppSettings& settings) {
baseband_bandwidth_ = settings.baseband_bandwidth;
sampling_rate_ = settings.sampling_rate;
lna_gain_db_ = settings.lna;
vga_gain_db_ = settings.vga;
rf_amp_ = settings.rx_amp;
squelch_level_ = settings.squelch;
} }
void ReceiverModel::update_sampling_rate() { void ReceiverModel::update_sampling_rate() {
@ -290,8 +283,16 @@ void ReceiverModel::update_sampling_rate() {
update_tuning_frequency(); update_tuning_frequency();
} }
void ReceiverModel::update_headphone_volume() { void ReceiverModel::update_lna() {
audio::headphone::set_volume(headphone_volume()); radio::set_lna_gain(lna());
}
void ReceiverModel::update_vga() {
radio::set_vga_gain(vga());
}
void ReceiverModel::update_rf_amp() {
radio::set_rf_amp(rf_amp());
} }
void ReceiverModel::update_modulation() { void ReceiverModel::update_modulation() {
@ -315,26 +316,23 @@ void ReceiverModel::update_modulation() {
} }
} }
size_t ReceiverModel::am_configuration() const {
return am_config_index;
}
void ReceiverModel::update_am_configuration() { void ReceiverModel::update_am_configuration() {
am_configs[am_config_index].apply(); am_configs[am_configuration()].apply();
}
size_t ReceiverModel::nbfm_configuration() const {
return nbfm_config_index;
} }
void ReceiverModel::update_nbfm_configuration() { void ReceiverModel::update_nbfm_configuration() {
nbfm_configs[nbfm_config_index].apply(squelch_level_); nbfm_configs[nbfm_configuration()].apply(squelch_level());
}
size_t ReceiverModel::wfm_configuration() const {
return wfm_config_index;
} }
void ReceiverModel::update_wfm_configuration() { void ReceiverModel::update_wfm_configuration() {
wfm_configs[wfm_config_index].apply(); wfm_configs[wfm_configuration()].apply();
}
void ReceiverModel::update_antenna_bias() {
if (enabled_)
radio::set_antenna_bias(portapack::get_antenna_bias());
}
void ReceiverModel::update_headphone_volume() {
audio::headphone::set_volume(headphone_volume());
} }

View File

@ -1,5 +1,6 @@
/* /*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2023 Kyle Reed
* *
* This file is part of PortaPack. * This file is part of PortaPack.
* *
@ -26,16 +27,16 @@
#include <cstddef> #include <cstddef>
#include "app_settings.hpp" #include "app_settings.hpp"
#include "max283x.hpp"
#include "message.hpp" #include "message.hpp"
#include "rf_path.hpp" #include "rf_path.hpp"
#include "max283x.hpp"
#include "volume.hpp" #include "volume.hpp"
// TODO: consider a base class for ReceiverModel & TransmitterModel. // TODO: consider a base class for ReceiverModel & TransmitterModel.
// There are multiple values that are actually shared by both. // There are multiple values that are actually shared by both.
class ReceiverModel { class ReceiverModel {
public: public:
enum class Mode { enum class Mode : uint8_t {
AMAudio = 0, AMAudio = 0,
NarrowbandFMAudio = 1, NarrowbandFMAudio = 1,
WidebandFMAudio = 2, WidebandFMAudio = 2,
@ -43,33 +44,59 @@ class ReceiverModel {
Capture = 4 Capture = 4
}; };
struct settings_t {
uint32_t baseband_bandwidth = max283x::filter::bandwidth_minimum;
uint32_t sampling_rate = 3'072'000;
rf::Frequency frequency_step = 25'000;
uint8_t lna_gain_db = 32;
uint8_t vga_gain_db = 32;
bool rf_amp = false;
Mode mode = Mode::NarrowbandFMAudio;
uint8_t am_config_index = 0;
uint8_t nbfm_config_index = 0;
uint8_t wfm_config_index = 0;
uint8_t squelch_level = 80;
};
/* The frequency to receive (no offset). */ /* The frequency to receive (no offset). */
rf::Frequency target_frequency() const; rf::Frequency target_frequency() const;
void set_target_frequency(rf::Frequency f); void set_target_frequency(rf::Frequency f);
rf::Frequency frequency_step() const;
void set_frequency_step(rf::Frequency f);
void set_antenna_bias();
bool rf_amp() const;
void set_rf_amp(bool enabled);
int32_t lna() const;
void set_lna(int32_t v_db);
uint32_t baseband_bandwidth() const; uint32_t baseband_bandwidth() const;
void set_baseband_bandwidth(uint32_t v); void set_baseband_bandwidth(uint32_t v);
int32_t vga() const;
void set_vga(int32_t v_db);
uint32_t sampling_rate() const; uint32_t sampling_rate() const;
void set_sampling_rate(uint32_t v); void set_sampling_rate(uint32_t v);
rf::Frequency frequency_step() const;
void set_frequency_step(rf::Frequency f);
uint8_t lna() const;
void set_lna(uint8_t v_db);
uint8_t vga() const;
void set_vga(uint8_t v_db);
bool rf_amp() const;
void set_rf_amp(bool enabled);
Mode modulation() const; Mode modulation() const;
void set_modulation(Mode v); void set_modulation(Mode v);
uint8_t am_configuration() const;
void set_am_configuration(uint8_t n);
uint8_t nbfm_configuration() const;
void set_nbfm_configuration(uint8_t n);
uint8_t wfm_configuration() const;
void set_wfm_configuration(uint8_t n);
uint8_t squelch_level() const;
void set_squelch_level(uint8_t v);
void set_antenna_bias();
volume_t headphone_volume() const; volume_t headphone_volume() const;
void set_headphone_volume(volume_t v); void set_headphone_volume(volume_t v);
@ -77,25 +104,11 @@ class ReceiverModel {
uint8_t normalized_headphone_volume() const; uint8_t normalized_headphone_volume() const;
void set_normalized_headphone_volume(uint8_t v); void set_normalized_headphone_volume(uint8_t v);
uint8_t squelch_level() const;
void set_squelch_level(uint8_t v);
void enable(); void enable();
void disable(); void disable();
size_t am_configuration() const; /* Resets some members back to default. */
void set_am_configuration(const size_t n); void initialize();
size_t nbfm_configuration() const;
void set_nbfm_configuration(const size_t n);
size_t wfm_configuration() const;
void set_wfm_configuration(const size_t n);
/* Sets the model values without updating the radio. */
void set_configuration_without_update(
uint32_t baseband_bandwidth,
uint32_t sampling_rate);
void set_configuration_without_update( void set_configuration_without_update(
Mode new_mode, Mode new_mode,
@ -107,35 +120,30 @@ class ReceiverModel {
void configure_from_app_settings(const app_settings::AppSettings& settings); void configure_from_app_settings(const app_settings::AppSettings& settings);
/* Get access to the underlying settings to allow
* values to be set directly without calling update. */
settings_t& settings() { return settings_; }
private: private:
rf::Frequency frequency_step_{25000}; settings_t settings_{};
bool enabled_{false}; bool enabled_ = false;
bool rf_amp_{false};
int32_t lna_gain_db_{32};
uint32_t baseband_bandwidth_{max283x::filter::bandwidth_minimum};
int32_t vga_gain_db_{32};
Mode mode_{Mode::NarrowbandFMAudio};
uint32_t sampling_rate_{3072000};
size_t am_config_index = 0;
size_t nbfm_config_index = 0;
size_t wfm_config_index = 0;
uint8_t squelch_level_{80};
int32_t tuning_offset(); int32_t tuning_offset();
void update_tuning_frequency(); void update_tuning_frequency();
void update_antenna_bias();
void update_rf_amp();
void update_lna();
void update_baseband_bandwidth(); void update_baseband_bandwidth();
void update_vga();
void update_sampling_rate(); void update_sampling_rate();
void update_headphone_volume(); void update_lna();
void update_vga();
void update_rf_amp();
void update_modulation(); void update_modulation();
void update_am_configuration(); void update_am_configuration();
void update_nbfm_configuration(); void update_nbfm_configuration();
void update_wfm_configuration(); void update_wfm_configuration();
void update_antenna_bias();
void update_headphone_volume();
}; };
#endif /*__RECEIVER_MODEL_H__*/ #endif /*__RECEIVER_MODEL_H__*/

View File

@ -1,6 +1,7 @@
/* /*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc. * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2016 Furrtek * Copyright (C) 2016 Furrtek
* Copyright (C) 2023 Kyle Reed
* *
* This file is part of PortaPack. * This file is part of PortaPack.
* *
@ -22,15 +23,13 @@
#include "transmitter_model.hpp" #include "transmitter_model.hpp"
#include "audio.hpp"
#include "baseband_api.hpp" #include "baseband_api.hpp"
#include "event_m0.hpp"
#include "portapack_persistent_memory.hpp"
#include "hackrf_gpio.hpp" #include "hackrf_gpio.hpp"
#include "portapack.hpp" #include "portapack.hpp"
#include "rtc_time.hpp" #include "portapack_persistent_memory.hpp"
#include "event_m0.hpp"
#include "radio.hpp" #include "radio.hpp"
#include "audio.hpp"
using namespace hackrf::one; using namespace hackrf::one;
using namespace portapack; using namespace portapack;
@ -44,75 +43,52 @@ void TransmitterModel::set_target_frequency(rf::Frequency f) {
update_tuning_frequency(); update_tuning_frequency();
} }
void TransmitterModel::set_antenna_bias() {
update_antenna_bias();
}
bool TransmitterModel::rf_amp() const {
return rf_amp_;
}
void TransmitterModel::set_rf_amp(bool enabled) {
rf_amp_ = enabled;
update_rf_amp();
}
int32_t TransmitterModel::lna() const {
return lna_gain_db_;
}
void TransmitterModel::set_lna(int32_t v_db) {
lna_gain_db_ = v_db;
update_lna();
}
uint32_t TransmitterModel::baseband_bandwidth() const { uint32_t TransmitterModel::baseband_bandwidth() const {
return baseband_bandwidth_; return settings_.baseband_bandwidth;
} }
void TransmitterModel::set_baseband_bandwidth(uint32_t v) { void TransmitterModel::set_baseband_bandwidth(uint32_t v) {
baseband_bandwidth_ = v; settings_.baseband_bandwidth = v;
update_baseband_bandwidth(); update_baseband_bandwidth();
} }
int32_t TransmitterModel::vga() const {
return vga_gain_db_;
}
void TransmitterModel::set_vga(int32_t v_db) {
vga_gain_db_ = v_db;
update_vga();
}
uint32_t TransmitterModel::channel_bandwidth() const {
return channel_bandwidth_;
}
void TransmitterModel::set_channel_bandwidth(uint32_t v) {
channel_bandwidth_ = v;
}
uint32_t TransmitterModel::sampling_rate() const { uint32_t TransmitterModel::sampling_rate() const {
return sampling_rate_; return settings_.sampling_rate;
} }
void TransmitterModel::set_sampling_rate(uint32_t v) { void TransmitterModel::set_sampling_rate(uint32_t v) {
sampling_rate_ = v; settings_.sampling_rate = v;
update_sampling_rate(); update_sampling_rate();
} }
int32_t TransmitterModel::tx_gain() const { uint32_t TransmitterModel::channel_bandwidth() const {
return tx_gain_db_; return settings_.channel_bandwidth;
} }
void TransmitterModel::set_tx_gain(int32_t v_db) { void TransmitterModel::set_channel_bandwidth(uint32_t v) {
tx_gain_db_ = v_db; settings_.channel_bandwidth = v;
}
uint8_t TransmitterModel::tx_gain() const {
return settings_.tx_gain_db;
}
void TransmitterModel::set_tx_gain(uint8_t v_db) {
settings_.tx_gain_db = v_db;
update_tx_gain(); update_tx_gain();
} }
void TransmitterModel::on_tick_second() { bool TransmitterModel::rf_amp() const {
if (portapack::persistent_memory::stealth_mode()) return settings_.rf_amp;
led_tx.toggle(); }
void TransmitterModel::set_rf_amp(bool enabled) {
settings_.rf_amp = enabled;
update_rf_amp();
}
void TransmitterModel::set_antenna_bias() {
update_antenna_bias();
} }
void TransmitterModel::enable() { void TransmitterModel::enable() {
@ -121,8 +97,6 @@ void TransmitterModel::enable() {
update_tuning_frequency(); update_tuning_frequency();
update_antenna_bias(); update_antenna_bias();
update_rf_amp(); update_rf_amp();
update_lna();
update_vga();
update_baseband_bandwidth(); update_baseband_bandwidth();
update_sampling_rate(); update_sampling_rate();
update_tx_gain(); update_tx_gain();
@ -147,53 +121,25 @@ void TransmitterModel::disable() {
led_tx.off(); led_tx.off();
} }
void TransmitterModel::set_configuration_without_update( void TransmitterModel::initialize() {
uint32_t baseband_bandwidth, settings_ = settings_t{};
uint32_t sampling_rate) {
baseband_bandwidth_ = baseband_bandwidth;
sampling_rate_ = sampling_rate;
} }
void TransmitterModel::configure_from_app_settings( void TransmitterModel::configure_from_app_settings(
const app_settings::AppSettings& settings) { const app_settings::AppSettings& settings) {
baseband_bandwidth_ = settings.baseband_bandwidth; settings_.baseband_bandwidth = settings.baseband_bandwidth;
channel_bandwidth_ = settings.channel_bandwidth; settings_.sampling_rate = settings.sampling_rate;
tx_gain_db_ = settings.tx_gain; settings_.channel_bandwidth = settings.channel_bandwidth;
rf_amp_ = settings.tx_amp; settings_.tx_gain_db = settings.tx_gain;
settings_.rf_amp = settings.tx_amp;
// TODO: Do these make sense for TX?
lna_gain_db_ = settings.lna;
vga_gain_db_ = settings.vga;
sampling_rate_ = settings.sampling_rate;
} }
void TransmitterModel::update_tuning_frequency() { void TransmitterModel::update_tuning_frequency() {
radio::set_tuning_frequency(target_frequency()); radio::set_tuning_frequency(target_frequency());
} }
void TransmitterModel::update_antenna_bias() {
if (enabled_)
radio::set_antenna_bias(portapack::get_antenna_bias());
}
void TransmitterModel::update_rf_amp() {
radio::set_rf_amp(rf_amp_);
}
void TransmitterModel::update_lna() {
radio::set_lna_gain(lna_gain_db_);
}
void TransmitterModel::update_baseband_bandwidth() { void TransmitterModel::update_baseband_bandwidth() {
radio::set_baseband_filter_bandwidth(baseband_bandwidth_); radio::set_baseband_filter_bandwidth(baseband_bandwidth());
}
void TransmitterModel::update_vga() {
radio::set_vga_gain(vga_gain_db_);
}
void TransmitterModel::update_tx_gain() {
radio::set_tx_gain(tx_gain_db_);
} }
void TransmitterModel::update_sampling_rate() { void TransmitterModel::update_sampling_rate() {
@ -206,3 +152,21 @@ void TransmitterModel::update_sampling_rate() {
radio::set_baseband_rate(sampling_rate()); radio::set_baseband_rate(sampling_rate());
update_tuning_frequency(); update_tuning_frequency();
} }
void TransmitterModel::update_tx_gain() {
radio::set_tx_gain(tx_gain());
}
void TransmitterModel::update_rf_amp() {
radio::set_rf_amp(rf_amp());
}
void TransmitterModel::update_antenna_bias() {
if (enabled_)
radio::set_antenna_bias(portapack::get_antenna_bias());
}
void TransmitterModel::on_tick_second() {
if (portapack::persistent_memory::stealth_mode())
led_tx.toggle();
}

View File

@ -1,6 +1,7 @@
/* /*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2016 Furrtek * Copyright (C) 2016 Furrtek
* Copyright (C) 2023 Kyle Reed
* *
* This file is part of PortaPack. * This file is part of PortaPack.
* *
@ -26,77 +27,68 @@
#include <cstdint> #include <cstdint>
#include <cstddef> #include <cstddef>
#include "receiver_model.hpp"
#include "app_settings.hpp" #include "app_settings.hpp"
#include "message.hpp"
#include "rf_path.hpp"
#include "max2837.hpp" #include "max2837.hpp"
#include "volume.hpp" #include "message.hpp"
#include "receiver_model.hpp"
#include "rf_path.hpp"
#include "signal.hpp" #include "signal.hpp"
class TransmitterModel { class TransmitterModel {
public: public:
struct settings_t {
uint32_t baseband_bandwidth = max283x::filter::bandwidth_minimum;
uint32_t sampling_rate = 3'072'000;
uint32_t channel_bandwidth = 1;
/* 35 should give approx 1m transmission range. */
uint8_t tx_gain_db = 35;
bool rf_amp = false;
};
/* The frequency to transmit on. */ /* The frequency to transmit on. */
rf::Frequency target_frequency() const; rf::Frequency target_frequency() const;
void set_target_frequency(rf::Frequency f); void set_target_frequency(rf::Frequency f);
void set_antenna_bias();
bool rf_amp() const;
void set_rf_amp(bool enabled);
// TODO: does this make sense on TX?
int32_t lna() const;
void set_lna(int32_t v_db);
uint32_t baseband_bandwidth() const; uint32_t baseband_bandwidth() const;
void set_baseband_bandwidth(uint32_t v); void set_baseband_bandwidth(uint32_t v);
// TODO: does this make sense on TX?
int32_t vga() const;
void set_vga(int32_t v_db);
int32_t tx_gain() const;
void set_tx_gain(int32_t v_db);
// TODO: Doesn't actually affect radio. // TODO: Doesn't actually affect radio.
uint32_t channel_bandwidth() const; uint32_t channel_bandwidth() const;
void set_channel_bandwidth(uint32_t v); void set_channel_bandwidth(uint32_t v);
// TODO: does this make sense on TX?
uint32_t sampling_rate() const; uint32_t sampling_rate() const;
void set_sampling_rate(uint32_t v); void set_sampling_rate(uint32_t v);
uint8_t tx_gain() const;
void set_tx_gain(uint8_t v_db);
bool rf_amp() const;
void set_rf_amp(bool enabled);
void set_antenna_bias();
void enable(); void enable();
void disable(); void disable();
/* Sets the model values without updating the radio. */ void initialize();
void set_configuration_without_update(
uint32_t baseband_bandwidth,
uint32_t sampling_rate);
void configure_from_app_settings(const app_settings::AppSettings& settings); void configure_from_app_settings(const app_settings::AppSettings& settings);
/* Get access to the underlying settings to allow
* values to be set directly without calling update. */
settings_t& settings() { return settings_; }
private: private:
bool enabled_{false}; settings_t settings_{};
bool rf_amp_{false}; bool enabled_ = false;
int32_t lna_gain_db_{0};
uint32_t channel_bandwidth_{1};
uint32_t baseband_bandwidth_{max2837::filter::bandwidth_minimum};
int32_t vga_gain_db_{8};
/* 35 should give approx 1m transmission range. */
int32_t tx_gain_db_{35};
uint32_t sampling_rate_{3072000};
SignalToken signal_token_tick_second{}; SignalToken signal_token_tick_second{};
void update_tuning_frequency(); void update_tuning_frequency();
void update_antenna_bias();
void update_rf_amp();
void update_lna();
void update_baseband_bandwidth(); void update_baseband_bandwidth();
void update_vga();
void update_tx_gain();
void update_sampling_rate(); void update_sampling_rate();
void update_tx_gain();
void update_rf_amp();
void update_antenna_bias();
void on_tick_second(); void on_tick_second();
}; };

View File

@ -280,7 +280,7 @@ FrequencyOptionsView::FrequencyOptionsView(
} }
void FrequencyOptionsView::set_step(rf::Frequency f) { void FrequencyOptionsView::set_step(rf::Frequency f) {
field_step.set_by_value(f); field_step.set_by_nearest_value(f);
} }
void FrequencyOptionsView::set_reference_ppm_correction(int32_t v) { void FrequencyOptionsView::set_reference_ppm_correction(int32_t v) {

View File

@ -1001,8 +1001,6 @@ bool debug_dump() {
// transmitter_model // transmitter_model
pmem_dump_file.write_line("\n[Transmitter Model]"); pmem_dump_file.write_line("\n[Transmitter Model]");
pmem_dump_file.write_line("target_frequency: " + to_string_dec_uint(transmitter_model.target_frequency())); pmem_dump_file.write_line("target_frequency: " + to_string_dec_uint(transmitter_model.target_frequency()));
pmem_dump_file.write_line("lna: " + to_string_dec_int(transmitter_model.lna()));
pmem_dump_file.write_line("vga: " + to_string_dec_int(transmitter_model.vga()));
pmem_dump_file.write_line("rf_amp: " + to_string_dec_int(transmitter_model.rf_amp())); pmem_dump_file.write_line("rf_amp: " + to_string_dec_int(transmitter_model.rf_amp()));
pmem_dump_file.write_line("baseband_bandwidth: " + to_string_dec_uint(transmitter_model.baseband_bandwidth())); pmem_dump_file.write_line("baseband_bandwidth: " + to_string_dec_uint(transmitter_model.baseband_bandwidth()));
pmem_dump_file.write_line("sampling_rate: " + to_string_dec_uint(transmitter_model.sampling_rate())); pmem_dump_file.write_line("sampling_rate: " + to_string_dec_uint(transmitter_model.sampling_rate()));

View File

@ -1524,6 +1524,24 @@ void OptionsField::set_by_value(value_t v) {
set_selected_index(0); set_selected_index(0);
} }
void OptionsField::set_by_nearest_value(value_t v) {
size_t new_index = 0;
size_t curr_index = 0;
int32_t min_diff = INT32_MAX;
for (const auto& option : options) {
auto diff = abs(v - option.second);
if (diff < min_diff) {
min_diff = diff;
new_index = curr_index;
}
curr_index++;
}
set_selected_index(new_index);
}
void OptionsField::set_options(options_t new_options) { void OptionsField::set_options(options_t new_options) {
options = new_options; options = new_options;

View File

@ -624,6 +624,7 @@ class OptionsField : public Widget {
void set_selected_index(const size_t new_index, bool trigger_change = true); void set_selected_index(const size_t new_index, bool trigger_change = true);
void set_by_value(value_t v); void set_by_value(value_t v);
void set_by_nearest_value(value_t v);
void paint(Painter& painter) override; void paint(Painter& painter) override;