Compare commits

...

9 Commits

Author SHA1 Message Date
Mark Thompson fcb681f4ae Support for viewing BMP files in File Manager and setting as Splash screen (#1242)
* Use filesystem::path type vs string for BMP file name

* Use filesystem::path type vs string for BMP files

* Use a global const file path string for "/splash.bmp"

* Support for viewing BMP files and setting as Splash screen

* Support for viewing BMP files and setting as Splash screen

* Support for viewing BMP files and setting as Splash screen

* Update ui_ss_viewer.cpp

* Update ui_ss_viewer.hpp
2023-07-05 15:45:43 -05:00
gullradriel 8530fa8194 Recon unleashed SPEC mode (#1240)
* added quick recon optimized for spec mode
* fix bug going from spec to audio mode
2023-07-05 21:54:28 +02:00
Erwin Ried 89e8956df1 Merge pull request #1239 from gullradriel/recon-gui-fix
fix gui glitches
2023-07-05 12:09:04 +02:00
GullCode 82ba35c162 fix gui glitches 2023-07-05 11:08:29 +02:00
Mark Thompson d750afe38f Use ImageToggle widget for 3 icons (no functional change) (#1237)
* Use ImageToggle button type for 3 icons
2023-07-05 09:12:40 +02:00
Kyle Reed 9b665a43c5 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>
2023-07-04 18:26:26 -05:00
Mark Thompson 80c769b97d Display CTCSS tone freq in Audio, Recon, and Level apps (#1231)
* Generate CTCSS messages at fixed rate regardless of tone freq

* Generate CTCSS messages at fixed rate regardless of tone freq

* Function for generating CTCSS description strings

* Function for generating CTCSS description strings

* Increase width of CTCSS text to include tone freq

* Increase width of CTCSS text field to include frequency

* Use CTCSS tone freq when saving HAM freqs to freq file

* Use function in tone_key.cpp for displaying CTCSS string

* Use function in tone_key.cpp for CTCSS descr strings

* Use function in tone_key.cpp for CTCSS descr strings

* Clang test

* Clang

* Clang

* Support for reading CTCSS tones from FreqMan file

* Clang

* Clean up and eliminate floating point

* Clean up and eliminate floating point

* Corrected CTCSS field length

* Corrected CTCSS field length

* Clang
2023-07-02 16:53:51 -07:00
Kyle Reed 44dd8fd083 Pmem cleanup (#1230)
* WIP pmem cleanup

* Finish pmem refactor

* Fix dump order

* Set defaults for splash and backlight

* Fix break

---------

Co-authored-by: kallanreed <kallanreed@noreply.github.com>
2023-07-02 09:35:34 -07:00
Mark Thompson 4e128e8930 Fixed CTCSS tone detection (#1226)
* Fixed erroneous rounding code

* Fixed CTCSS tone detection

* Correct tone index for XZ/WZ and sort table by tone freq
2023-07-01 15:36:07 +02:00
52 changed files with 992 additions and 1037 deletions
+6 -9
View File
@@ -114,6 +114,8 @@ ResultCode load_settings(const std::string& app_name, AppSettings& settings) {
if (flags_enabled(settings.mode, Mode::RX)) {
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::modulation, settings.modulation);
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::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::volume, settings.volume);
@@ -153,6 +153,8 @@ ResultCode save_settings(const std::string& app_name, AppSettings& settings) {
if (flags_enabled(settings.mode, Mode::RX)) {
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::modulation, settings.modulation);
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::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::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) {
// 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.options, Options::UseGlobalTargetFrequency))
@@ -203,14 +204,10 @@ void copy_from_radio_model(AppSettings& settings) {
if (flags_enabled(settings.mode, Mode::TX)) {
settings.tx_frequency = transmitter_model.target_frequency();
settings.baseband_bandwidth = transmitter_model.baseband_bandwidth();
settings.sampling_rate = transmitter_model.sampling_rate();
settings.tx_amp = transmitter_model.rf_amp();
settings.tx_gain = transmitter_model.tx_gain();
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)) {
+11 -9
View File
@@ -31,8 +31,6 @@
#include "string_format.hpp"
#include "utility.hpp"
#include "debug.hpp"
using namespace portapack;
using namespace tonekey;
@@ -135,8 +133,7 @@ SPECOptionsView::SPECOptionsView(
AnalogAudioView::AnalogAudioView(
NavigationView& nav)
: nav_(nav) {
// A baseband image _must_ be running before
// interacting with the waterfall view.
// A baseband image _must_ be running before add waterfall view.
baseband::run_image(portapack::spi_flash::image_tag_wideband_spectrum);
add_children({&rssi,
@@ -194,6 +191,15 @@ AnalogAudioView::AnalogAudioView(
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() {
return spec_bw_index;
}
@@ -404,11 +410,7 @@ void AnalogAudioView::update_modulation(ReceiverModel::Mode modulation) {
}
void AnalogAudioView::handle_coded_squelch(uint32_t value) {
tone_index idx = tone_key_index_by_value(value);
if (idx >= 0)
text_ctcss.set("CTCSS " + tone_key_string(idx));
else
text_ctcss.set("???");
text_ctcss.set(tone_key_string_by_value(value, text_ctcss.parent_rect().width() / 8));
}
} /* namespace ui */
@@ -71,10 +71,10 @@ class NBFMOptionsView : public View {
}};
Text text_squelch{
{9 * 8, 0 * 16, 8 * 8, 1 * 16},
{7 * 8, 0 * 16, 8 * 8, 1 * 16},
"SQ /99"};
NumberField field_squelch{
{12 * 8, 0 * 16},
{10 * 8, 0 * 16},
2,
{0, 99},
1,
@@ -138,6 +138,7 @@ class SPECOptionsView : public View {
class AnalogAudioView : public View {
public:
AnalogAudioView(NavigationView& nav);
AnalogAudioView(NavigationView& nav, ReceiverModel::settings_t override);
~AnalogAudioView();
void set_parent_rect(Rect new_parent_rect) override;
@@ -200,7 +201,7 @@ class AnalogAudioView : public View {
{28 * 8, 0 * 16}};
Text text_ctcss{
{19 * 8, 1 * 16, 11 * 8, 1 * 16},
{16 * 8, 1 * 16, 14 * 8, 1 * 16},
""};
std::unique_ptr<Widget> options_widget{};
@@ -71,8 +71,6 @@ CaptureAppView::CaptureAppView(NavigationView& nav)
};
option_bandwidth.set_selected_index(7); // Preselected default option 500kHz.
receiver_model.set_modulation(ReceiverModel::Mode::Capture);
receiver_model.enable();
record_view.on_error = [&nav](std::string message) {
@@ -81,8 +79,6 @@ CaptureAppView::CaptureAppView(NavigationView& nav)
}
CaptureAppView::~CaptureAppView() {
// Most other apps can't handle "Capture" mode, set to something standard.
receiver_model.set_modulation(ReceiverModel::Mode::WidebandFMAudio);
receiver_model.disable();
baseband::shutdown();
}
+1 -1
View File
@@ -50,7 +50,7 @@ class CaptureAppView : public View {
static constexpr ui::Dim header_height = 3 * 16;
NavigationView& nav_;
RxRadioState radio_state_{};
RxRadioState radio_state_{ReceiverModel::Mode::Capture};
app_settings::SettingsManager settings_{
"rx_capture", app_settings::Mode::RX,
app_settings::Options::UseGlobalTargetFrequency};
+1 -2
View File
@@ -130,8 +130,7 @@ class ERTAppView : public View {
RxRadioState radio_state_{
2500000 /* bandwidth */,
4194304 /* sampling rate */
};
4194304 /* sampling rate */};
app_settings::SettingsManager settings_{
"rx_ert", app_settings::Mode::RX};
-1
View File
@@ -71,7 +71,6 @@ POCSAGAppView::POCSAGAppView(NavigationView& nav)
if (!settings_.loaded())
field_frequency.set_value(initial_target_frequency);
receiver_model.set_modulation(ReceiverModel::Mode::NarrowbandFMAudio);
receiver_model.enable();
// TODO: app setting instead?
+1 -2
View File
@@ -106,8 +106,7 @@ class TPMSAppView : public View {
RxRadioState radio_state_{
1750000 /* bandwidth */,
2457600 /* sampling rate */
};
2457600 /* sampling rate */};
app_settings::SettingsManager settings_{
"rx_tpms", app_settings::Mode::RX};
+1 -2
View File
@@ -513,8 +513,7 @@ ADSBRxView::ADSBRxView(NavigationView& nav) {
baseband::set_adsb();
receiver_model.set_target_frequency(1090000000);
receiver_model.set_modulation(ReceiverModel::Mode::SpectrumAnalysis);
receiver_model.set_target_frequency(1'090'000'000);
receiver_model.enable();
}
+2 -2
View File
@@ -343,8 +343,8 @@ class ADSBRxView : public View {
private:
RxRadioState radio_state_{
2500000 /* bandwidth */,
2000000 /* sampling rate */
};
2000000 /* sampling rate */,
ReceiverModel::Mode::SpectrumAnalysis};
app_settings::SettingsManager settings_{
"rx_adsb", app_settings::Mode::RX};
-1
View File
@@ -91,7 +91,6 @@ AFSKRxView::AFSKRxView(NavigationView& nav)
audio::set_rate(audio::Rate::Hz_24000);
audio::output::start();
receiver_model.set_modulation(ReceiverModel::Mode::NarrowbandFMAudio);
receiver_model.enable();
}
-1
View File
@@ -119,7 +119,6 @@ APRSRxView::APRSRxView(NavigationView& nav, Rect parent_rect)
audio::set_rate(audio::Rate::Hz_24000);
audio::output::start();
receiver_model.set_modulation(ReceiverModel::Mode::NarrowbandFMAudio);
receiver_model.enable();
}
-1
View File
@@ -76,7 +76,6 @@ BTLERxView::BTLERxView(NavigationView& nav)
audio::set_rate(audio::Rate::Hz_24000);
audio::output::start();
receiver_model.set_modulation(ReceiverModel::Mode::WidebandFMAudio);
receiver_model.enable();
}
+2 -2
View File
@@ -51,8 +51,8 @@ class BTLERxView : public View {
NavigationView& nav_;
RxRadioState radio_state_{
4000000 /* bandwidth */,
4000000 /* sampling rate */
};
4000000 /* sampling rate */,
ReceiverModel::Mode::WidebandFMAudio};
app_settings::SettingsManager settings_{
"rx_btle", app_settings::Mode::RX};
+5
View File
@@ -41,6 +41,7 @@ static const fs::path txt_ext{u".TXT"};
static const fs::path ppl_ext{u".PPL"};
static const fs::path c16_ext{u".C16"};
static const fs::path png_ext{u".PNG"};
static const fs::path bmp_ext{u".BMP"};
} // namespace ui
namespace {
@@ -503,6 +504,10 @@ bool FileManagerView::handle_file_open() {
} else if (path_iequal(png_ext, ext)) {
nav_.push<ScreenshotViewer>(path);
return true;
} else if (path_iequal(bmp_ext, ext)) {
nav_.push<SplashViewer>(path);
reload_current();
return true;
}
return false;
+4 -17
View File
@@ -216,23 +216,10 @@ size_t LevelView::change_mode(freqman_index_t new_mod) {
}
void LevelView::handle_coded_squelch(const uint32_t value) {
static tone_index last_squelch_index = -1;
if (field_mode.selected_index() == NFM_MODULATION) {
tone_index idx = tone_key_index_by_value(value);
if ((last_squelch_index < 0) || (last_squelch_index != idx)) {
last_squelch_index = idx;
if (idx >= 0) {
text_ctcss.set("T: " + tone_key_string(idx));
return;
}
} else {
return;
}
}
text_ctcss.set(" ");
if (field_mode.selected_index() == NFM_MODULATION)
text_ctcss.set(tone_key_string_by_value(value, text_ctcss.parent_rect().width() / 8));
else
text_ctcss.set(" ");
}
} /* namespace ui */
+1 -1
View File
@@ -114,7 +114,7 @@ class LevelView : public View {
}};
Text text_ctcss{
{22 * 8, 3 * 16 + 4, 14 * 8, 1 * 8},
{22 * 8, 3 * 16 + 4, 8 * 8, 1 * 8},
""};
// RSSI: XX/XX/XXX,dt: XX
@@ -471,9 +471,9 @@ GlassView::GlassView(
button_marker.on_select = [this](ButtonWithEncoder&) {
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
nav_.pop();
nav_.push<AnalogAudioView>(); // Jump into audio view
auto settings = receiver_model.settings();
settings.frequency_step = MHZ_DIV; // Preset a 1 MHz frequency step into RX -> AUDIO
nav_.replace<AnalogAudioView>(settings); // Jump into audio view
};
field_trigger.on_change = [this](int32_t v) {
@@ -495,9 +495,9 @@ GlassView::GlassView(
button_jump.on_select = [this](Button&) {
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
nav_.pop();
nav_.push<AnalogAudioView>(); // Jump into audio view
auto settings = receiver_model.settings();
settings.frequency_step = MHZ_DIV; // Preset a 1 MHz frequency step into RX -> AUDIO
nav_.replace<AnalogAudioView>(settings); // Jump into audio view
};
button_rst.on_select = [this](Button&) {
@@ -513,7 +513,6 @@ GlassView::GlassView(
marker_pixel_index = 120;
on_range_changed();
receiver_model.set_modulation(ReceiverModel::Mode::SpectrumAnalysis);
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_squelch_level(0);
@@ -71,7 +71,7 @@ class GlassView : public View {
private:
NavigationView& nav_;
RxRadioState radio_state_{};
RxRadioState radio_state_{ReceiverModel::Mode::SpectrumAnalysis};
app_settings::SettingsManager settings_{
"rx_glass", app_settings::Mode::RX};
+81 -51
View File
@@ -145,25 +145,25 @@ void MicTXView::rxaudio(bool is_on) {
audio::input::stop();
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);
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).
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)
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),
} 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);
receiver_model.set_modulation(ReceiverModel::Mode::WidebandFMAudio);
// receiver_model.set_wfm_configuration(n); // it is called above , depending user's selection (200k, 180k,40k).
} else { // NFM BW:8k5 or 11k / FM BW 16k
// 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
baseband::run_image(portapack::spi_flash::image_tag_nfm_audio);
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
else
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);
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,
&options_gain, // MIC GAIN float factor on the GUI.
&options_wm8731_boost_mode,
@@ -260,7 +260,7 @@ MicTXView::MicTXView(
mic_gain = v / 10.0;
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") {
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),
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;
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.
break;
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.
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.
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.
}
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
configure_baseband(); // to update in real time, sending msg , var-parameters >>shift_bits FM msg ,to audio_tx from M0 to M4 Proc -
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_off
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 {
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) {
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
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) {
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_usb = false;
enable_lsb = false;
@@ -342,7 +342,7 @@ MicTXView::MicTXView(
using option_t = std::pair<std::string, int32_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) {
case 0: //{ "FM", 0 }
@@ -354,15 +354,15 @@ MicTXView::MicTXView(
// field_bw.set_value(transmitter_model.channel_bandwidth() / 1000);
// if (rx_enabled)
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(" NFM2:11k ", 1);
rxbw.emplace_back(" FM :16k ", 2);
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_bw.hidden(0); // we are in FM mode, we need to allow FM deviation parameter , in non FM mode.
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.
break;
case 1: //{ "WFM", 1 }
enable_am = false;
@@ -374,38 +374,38 @@ MicTXView::MicTXView(
// field_bw.set_value(transmitter_model.channel_bandwidth() / 1000);
// if (rx_enabled)
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(" 40k-WFM ", 2);
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_bw.hidden(0); // we are in WFM mode, we need to allow WFM deviation parameter , in non FM mode.
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.
break;
case 2: //{ "AM", 2 }
enable_am = true;
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
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);
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_bw.hidden(1); // we hide the FM TX deviation parameter , in non FM mode.
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.
check_rogerbeep.hidden(0); // make visible again the "rogerbeep" selection.
break;
case 3: //{ "USB", 3 }
enable_usb = true;
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.
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.
set_dirty(); // Refresh display
@@ -413,10 +413,10 @@ MicTXView::MicTXView(
case 4: //{ "LSB", 4 }
enable_lsb = true;
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.
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.
set_dirty(); // Refresh display
@@ -426,7 +426,7 @@ MicTXView::MicTXView(
rxaudio(rx_enabled); // Update now if we have RX audio on
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);
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) {
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
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) {
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)
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)
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),
// 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)
} 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)
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)
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_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),
}
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.
}
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() {
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.
+19 -15
View File
@@ -20,6 +20,8 @@
* Boston, MA 02110-1301, USA.
*/
// TODO: Consolidate Modulation/Bandwidth modes/settings with freqman/receiver_model.
#ifndef __UI_MICTX_H__
#define __UI_MICTX_H__
@@ -43,6 +45,7 @@ namespace ui {
class MicTXView : public View {
public:
MicTXView(NavigationView& nav);
MicTXView(NavigationView& nav, ReceiverModel::settings_t override);
~MicTXView();
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.
// AM TX Stuff
// TODO: Some of this stuff is mutually exclusive. Need a better representation.
bool enable_am{false};
bool enable_dsb{false};
bool enable_usb{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{
{{3 * 8, 1 * 8}, "MIC-GAIN:", Color::light_grey()},
{{17 * 8, 1 * 8}, "Boost", 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
{{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() },
{{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()},
@@ -147,7 +151,7 @@ class MicTXView : public View {
{{17 * 8, 1 * 8}, "ALC", Color::light_grey()},
{{3 * 8, 3 * 8}, "F:", 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() },
{{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()},
@@ -176,15 +180,15 @@ class MicTXView : public View {
{"x2.0", 20}}};
OptionsField options_ak4951_alc_mode{
{20 * 8, 1 * 8}, // Coordinates are: int:x (px), int:y (px)
{20 * 8, 1 * 8},
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)
{"+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)
{"+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-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-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)
{"-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{
{22 * 8, 1 * 8}, // Coordinates are: int:x (px), int:y (px)
{22 * 8, 1 * 8},
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 +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-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)
{"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
{"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-08dB", 4}, // WM8731 Mic Boost OFF to avoid ADC sat in high voice, relative G = -12 dB's (respect ref level)
}};
// TODO: Use TxFrequencyField
@@ -227,7 +231,7 @@ class MicTXView : public View {
{
{"NFM/FM", 0},
{" 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},
{" 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).
@@ -269,7 +273,7 @@ class MicTXView : public View {
OptionsField options_tone_key{
{12 * 8, (13 * 8) - 5},
23,
18,
{}};
Checkbox check_rogerbeep{
-1
View File
@@ -76,7 +76,6 @@ NRFRxView::NRFRxView(NavigationView& nav)
audio::set_rate(audio::Rate::Hz_24000);
audio::output::start();
receiver_model.set_modulation(ReceiverModel::Mode::WidebandFMAudio);
receiver_model.enable();
}
+2 -2
View File
@@ -51,8 +51,8 @@ class NRFRxView : public View {
NavigationView& nav_;
RxRadioState radio_state_{
4000000 /* bandwidth */,
4000000 /* sampling rate */
};
4000000 /* sampling rate */,
ReceiverModel::Mode::WidebandFMAudio};
app_settings::SettingsManager settings_{
"rx_nrf", app_settings::Mode::RX};
+1 -2
View File
@@ -80,8 +80,7 @@ bool POCSAGTXView::start_tx() {
progressbar.set_max(total_frames);
transmitter_model.set_rf_amp(true);
transmitter_model.set_lna(40);
transmitter_model.set_vga(40);
transmitter_model.set_tx_gain(40);
transmitter_model.enable();
uint8_t* data_ptr = shared_memory.bb_data.data;
+36 -30
View File
@@ -366,7 +366,6 @@ ReconView::~ReconView() {
recon_save_config_to_sd();
if (field_mode.selected_index_value() != SPEC_MODULATION)
audio::output::stop();
receiver_model.set_modulation(ReceiverModel::Mode::WidebandFMAudio);
receiver_model.disable();
baseband::shutdown();
}
@@ -549,8 +548,9 @@ ReconView::ReconView(NavigationView& nav)
};
button_audio_app.on_select = [this](Button&) {
nav_.pop();
nav_.push<AnalogAudioView>();
auto settings = receiver_model.settings();
settings.frequency_step = step_mode.selected_index_value();
nav_.replace<AnalogAudioView>(settings);
};
button_loop_config.on_select = [this](Button&) {
@@ -569,9 +569,9 @@ ReconView::ReconView(NavigationView& nav)
button_mic_app.on_select = [this](Button&) {
if (frequency_list.size() > 0 && current_index >= 0 && (unsigned)current_index < frequency_list.size()) {
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);
// 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);
} else {
// 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);
}
}
// there is no way yet to set modulation and bandwidth from Recon to MicApp
nav_.pop();
nav_.push<MicTXView>();
// MicTX wants Modulation and Bandwidth overrides, but that's only stored on the RX model.
nav_.replace<MicTXView>(receiver_model.settings());
};
button_remove.on_select = [this](ButtonWithEncoder&) {
@@ -731,7 +731,7 @@ ReconView::ReconView(NavigationView& nav)
text_cycle.set_text("1");
text_max.set("/1");
button_scanner_mode.set_style(&Styles::white);
button_scanner_mode.set_text("MSEARCH");
button_scanner_mode.set_text("MANUAL");
file_name.set_style(&Styles::white);
file_name.set("MANUAL RANGE RECON");
desc_cycle.set_style(&Styles::white);
@@ -776,7 +776,7 @@ ReconView::ReconView(NavigationView& nav)
if (scanner_mode) {
file_name.set_style(&Styles::red);
button_scanner_mode.set_style(&Styles::red);
button_scanner_mode.set_text("SCANNER");
button_scanner_mode.set_text("SCAN");
} else {
file_name.set_style(&Styles::blue);
button_scanner_mode.set_style(&Styles::blue);
@@ -808,7 +808,7 @@ ReconView::ReconView(NavigationView& nav)
} else {
scanner_mode = true;
button_scanner_mode.set_style(&Styles::red);
button_scanner_mode.set_text("SCANNER");
button_scanner_mode.set_text("SCAN");
button_scanner_mode.set_text("REMOVE");
}
frequency_file_load(true);
@@ -930,7 +930,7 @@ void ReconView::frequency_file_load(bool stop_all_before) {
file_name.set_style(&Styles::red);
button_scanner_mode.set_style(&Styles::red);
desc_cycle.set_style(&Styles::red);
button_scanner_mode.set_text("SCANNER");
button_scanner_mode.set_text("SCAN");
} else {
file_name.set_style(&Styles::blue);
button_scanner_mode.set_style(&Styles::blue);
@@ -1024,12 +1024,23 @@ void ReconView::frequency_file_load(bool stop_all_before) {
void ReconView::on_statistics_update(const ChannelStatistics& statistics) {
systime_t time_interval = 100;
uint32_t local_recon_lock_duration = recon_lock_duration;
chrono_end = chTimeNow();
if (field_mode.selected_index_value() == SPEC_MODULATION) {
chrono_end = chTimeNow();
time_interval = chrono_end - chrono_start;
chrono_start = chrono_end;
// capping here to avoid double check a frequency because time_interval is more than exactly 100 by a few units
// this is because we are making a measurement and not using a fixed value
if (time_interval > 100)
time_interval = 100;
if (field_lock_wait.value() == 0) {
if (time_interval <= 1) // capping here to avoid freeze because too quick
local_recon_lock_duration = 2; // minimum working tested value
else
local_recon_lock_duration = time_interval;
}
}
chrono_start = chrono_end;
// hack to reload the list if it was cleared by going into CONFIG
if (freqlist_cleared_for_ui_action) {
@@ -1049,7 +1060,7 @@ void ReconView::on_statistics_update(const ChannelStatistics& statistics) {
status = 0;
continuous_lock = false;
freq_lock = 0;
timer = recon_lock_duration;
timer = local_recon_lock_duration;
big_display.set_style(&Styles::white);
}
if (freq_lock < recon_lock_nb_match) // LOCKING
@@ -1409,8 +1420,13 @@ size_t ReconView::change_mode(freqman_index_t new_mod) {
default:
break;
}
if (new_mod != SPEC_MODULATION)
if (new_mod != SPEC_MODULATION) {
record_view->set_sampling_rate(recording_sampling_rate);
// reset receiver model to fix bug when going from SPEC to audio, the sound is distorded
receiver_model.set_sampling_rate(3072000);
receiver_model.set_baseband_bandwidth(1750000);
}
field_mode.set_selected_index(new_mod);
field_mode.on_change = [this](size_t, OptionsField::value_t v) {
if (v != -1) {
@@ -1426,20 +1442,10 @@ size_t ReconView::change_mode(freqman_index_t new_mod) {
}
void ReconView::handle_coded_squelch(const uint32_t value) {
if (field_mode.selected_index() == NFM_MODULATION) {
tone_index idx = tone_key_index_by_value(value);
if ((last_squelch_index < 0) || (last_squelch_index != idx)) {
last_squelch_index = idx;
if (idx >= 0) {
text_ctcss.set("T: " + tone_key_string(idx));
return;
}
} else {
return;
}
}
text_ctcss.set(" ");
if (field_mode.selected_index() == NFM_MODULATION)
text_ctcss.set(tone_key_string_by_value(value, text_ctcss.parent_rect().width() / 8));
else
text_ctcss.set(" ");
}
} /* namespace ui */
+1 -2
View File
@@ -139,7 +139,6 @@ class ReconView : public View {
int8_t last_rssi_med{-127};
int8_t last_rssi_max{-127};
int32_t last_index{-1};
tone_index last_squelch_index{-1};
int64_t last_freq{0};
std::string freq_file_path{};
systime_t chrono_start{};
@@ -270,7 +269,7 @@ class ReconView : public View {
NumberField field_lock_wait{
{25 * 8, 24 * 8 + 4},
4,
{RECON_MIN_LOCK_DURATION, RECON_MAX_LOCK_DURATION},
{0, RECON_MAX_LOCK_DURATION},
STATS_UPDATE_INTERVAL,
' ',
};
@@ -135,7 +135,7 @@ class ReconSetupViewMore : public View {
Checkbox checkbox_auto_record_locked{
{1 * 8, 132},
3,
"auto record locked periods"};
"record locked periods"};
};
class ReconSetupView : public View {
+5 -4
View File
@@ -392,16 +392,17 @@ ScannerView::ScannerView(
button_audio_app.on_select = [this](Button&) {
if (scan_thread)
scan_thread->stop();
nav_.pop();
nav_.push<AnalogAudioView>();
auto settings = receiver_model.settings();
settings.frequency_step = field_step.selected_index_value();
nav_.replace<AnalogAudioView>(settings);
};
// Button to switch to Mic app
button_mic_app.on_select = [this](Button&) {
if (scan_thread)
scan_thread->stop();
nav_.pop();
nav_.push<MicTXView>();
// MicTX wants Modulation and Bandwidth overrides, but that's only stored on the RX model.
nav_.replace<MicTXView>(receiver_model.settings());
};
// Button to delete current frequency from scan Freq List
+1 -12
View File
@@ -122,17 +122,7 @@ void SearchView::do_detection() {
locked = true;
locked_bin = bin_max;
// TODO
/*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>();
*/
// TODO: open Audio.
} else
text_infos.set("Out of range");
}
@@ -414,7 +404,6 @@ SearchView::SearchView(
on_range_changed();
receiver_model.set_modulation(ReceiverModel::Mode::SpectrumAnalysis);
receiver_model.enable();
}
+2 -2
View File
@@ -92,8 +92,8 @@ class SearchView : public View {
NavigationView& nav_;
RxRadioState radio_state_{
2500000 /* bandwidth */,
SEARCH_SLICE_WIDTH /* sampling rate */
};
SEARCH_SLICE_WIDTH /* sampling rate */,
ReceiverModel::Mode::SpectrumAnalysis};
struct slice_t {
rf::Frequency center_frequency;
+15 -17
View File
@@ -35,6 +35,9 @@ using namespace lpc43xx;
#include "portapack.hpp"
using namespace portapack;
#include "file.hpp"
namespace fs = std::filesystem;
#include "string_format.hpp"
#include "ui_styles.hpp"
#include "cpld_update.hpp"
@@ -489,35 +492,30 @@ SetPersistentMemoryView::SetPersistentMemoryView(NavigationView& nav) {
check_use_sdcard_for_pmem.set_value(pmem::should_use_sdcard_for_pmem());
check_use_sdcard_for_pmem.on_select = [this](Checkbox&, bool v) {
File pmem_flag_file_handle;
std::string pmem_flag_file = PMEM_FILEFLAG;
if (v) {
auto result = pmem_flag_file_handle.open(pmem_flag_file);
if (result.is_valid()) {
auto result = pmem_flag_file_handle.create(pmem_flag_file); // third: create if it is not there
if (!result.is_valid()) {
text_pmem_status.set("pmem flag file created");
} else {
text_pmem_status.set("!err. creating pmem flagfile!");
}
} else {
if (fs::file_exists(PMEM_FILEFLAG)) {
text_pmem_status.set("pmem flag already present");
} else {
auto error = pmem_flag_file_handle.create(PMEM_FILEFLAG);
if (error)
text_pmem_status.set("!err. creating pmem flagfile!");
else
text_pmem_status.set("pmem flag file created");
}
} else {
auto result = delete_file(pmem_flag_file);
if (result.code() != FR_OK) {
auto result = delete_file(PMEM_FILEFLAG);
if (result.code() != FR_OK)
text_pmem_status.set("!err. deleting pmem flagfile!");
} else {
else
text_pmem_status.set("pmem flag file deleted");
}
}
};
button_save_mem_to_file.on_select = [&nav, this](Button&) {
if (!pmem::save_persistent_settings_to_file()) {
if (!pmem::save_persistent_settings_to_file())
text_pmem_status.set("!problem saving settings!");
} else {
else
text_pmem_status.set("settings saved");
}
};
button_load_mem_from_file.on_select = [&nav, this](Button&) {
+42 -8
View File
@@ -26,6 +26,8 @@ namespace fs = std::filesystem;
namespace ui {
const std::filesystem::path splash_dot_bmp{u"/splash.bmp"};
ScreenshotViewer::ScreenshotViewer(
NavigationView& nav,
const std::filesystem::path& path)
@@ -40,11 +42,9 @@ bool ScreenshotViewer::on_key(KeyEvent) {
}
void ScreenshotViewer::paint(Painter& painter) {
constexpr size_t pixel_width = 240;
constexpr size_t pixel_height = 320;
File file{};
painter.fill_rectangle({0, 0, pixel_width, pixel_height}, Color::black());
painter.fill_rectangle({0, 0, screen_width, screen_height}, Color::black());
auto show_invalid = [&]() {
painter.draw_string({10, 160}, Styles::white, "Not a valid screenshot.");
@@ -65,19 +65,19 @@ void ScreenshotViewer::paint(Painter& painter) {
constexpr size_t read_chunk = 80; // NB: must be a factor of pixel_width.
constexpr size_t buffer_size = sizeof(ColorRGB888) * read_chunk;
uint8_t buffer[buffer_size];
std::array<Color, pixel_width> pixel_data;
std::array<Color, screen_width> pixel_data;
// Seek past all the headers.
file.seek(43);
for (auto line = 0u; line < pixel_height; ++line) {
for (auto line = 0u; line < screen_height; ++line) {
// Seek past the per-line header.
file.seek(file.tell() + 6);
// Per comment in PNGWriter, read in chunks of 80.
// NB: Reading in one large chunk caused corruption so there's
// likely a bug lurking in the SD Card/FatFs layer.
for (auto offset = 0u; offset < pixel_width; offset += read_chunk) {
for (auto offset = 0u; offset < screen_width; offset += read_chunk) {
auto read = file.read(buffer, buffer_size);
if (!read || *read != buffer_size) {
@@ -92,8 +92,42 @@ void ScreenshotViewer::paint(Painter& painter) {
}
}
display.draw_pixels({0, (int)line, pixel_width, 1}, pixel_data);
display.draw_pixels({0, (int)line, screen_width, 1}, pixel_data);
}
}
} // namespace ui
SplashViewer::SplashViewer(
NavigationView& nav,
const std::filesystem::path& path)
: nav_{nav},
path_{path} {
valid_image = false;
set_focusable(true);
}
bool SplashViewer::on_key(const KeyEvent key) {
if (valid_image && key == KeyEvent::Right) {
delete_file(splash_dot_bmp);
copy_file(path_, splash_dot_bmp);
}
nav_.pop();
return true;
}
void SplashViewer::paint(Painter& painter) {
painter.fill_rectangle({0, 0, screen_width, screen_height}, Color::black());
if (!portapack::display.drawBMP2({0, 0}, path_)) {
painter.draw_string({10, 160}, Styles::white, "Not a valid splash image.");
return;
}
// Show option to set splash screen if it's not already the splash screen
if (!path_iequal(path_, splash_dot_bmp)) {
painter.draw_string({0, 0}, Styles::white, "*RIGHT BUTTON UPDATES SPLASH*");
valid_image = true;
}
}
} // namespace ui
@@ -31,6 +31,8 @@
namespace ui {
extern const std::filesystem::path splash_dot_bmp;
class ScreenshotViewer : public View {
public:
ScreenshotViewer(NavigationView& nav, const std::filesystem::path& path);
@@ -42,6 +44,19 @@ class ScreenshotViewer : public View {
std::filesystem::path path_{};
};
class SplashViewer : public View {
public:
SplashViewer(NavigationView& nav, const std::filesystem::path& path);
bool on_key(KeyEvent key) override;
void paint(Painter& painter) override;
void update_ss(void);
private:
NavigationView& nav_;
std::filesystem::path path_{};
bool valid_image{};
};
} // namespace ui
#endif // __UI_SS_VIEWER_H__
+25 -7
View File
@@ -27,6 +27,8 @@
using option_t = std::pair<std::string, int32_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 = {
{"AM", 0},
{"NFM", 1},
@@ -122,6 +124,8 @@ bool load_freqman_file(std::string& file_stem, freqman_db& db, bool load_freqs,
freqman_index_t bandwidth = -1;
freqman_index_t step = -1;
freqman_index_t tone = -1;
uint32_t tone_freq;
char c;
auto result = freqman_file.open("FREQMAN/" + file_stem + ".TXT");
if (result.is_valid())
@@ -210,12 +214,26 @@ bool load_freqman_file(std::string& file_stem, freqman_db& db, bool load_freqs,
step = freqman_entry_get_step_from_str_short(pos);
}
// ctcss tone if any
/* disabled until better form
pos = strstr(line_start, "c=");
if (pos) {
pos += 2;
tone = tone_key_index_by_value( strtoll( pos , nullptr , 10 ) );
} */
pos = strstr(line_start, "c=");
if (pos) {
pos += 2;
// find decimal point and replace with 0 if there is one, for strtoll
length = strcspn(pos, ".,\x0A");
if (pos + length <= line_end) {
c = *(pos + length);
*(pos + length) = 0;
// ASCII Hz to integer Hz x 100
tone_freq = strtoll(pos, nullptr, 10) * 100;
// stuff saved character back into string in case it was not a decimal point
*(pos + length) = c;
// now get first digit after decimal point (10ths of Hz)
pos += length + 1;
if (c == '.' && *pos >= '0' && *pos <= '9')
tone_freq += (*pos - '0') * 10;
// convert tone_freq (100x the freq in Hz) to a tone_key index
tone = tone_key_index_by_value(tone_freq);
}
}
// Read description until , or LF
pos = strstr(line_start, "d=");
if (pos) {
@@ -284,7 +302,7 @@ bool get_freq_string(freqman_entry& entry, std::string& item_string) {
item_string = "r=" + to_string_dec_uint(frequency_a / 1000) + to_string_dec_uint(frequency_a % 1000UL, 3, '0');
item_string += ",t=" + to_string_dec_uint(frequency_b / 1000) + to_string_dec_uint(frequency_b % 1000UL, 3, '0');
if (entry.tone >= 0) {
item_string += ",c=" + tone_key_string(entry.tone);
item_string += ",c=" + tone_key_value_string(entry.tone);
}
}
if (entry.modulation >= 0 && (unsigned)entry.modulation < freqman_entry_modulations.size()) {
+29 -20
View File
@@ -28,38 +28,47 @@
#include "receiver_model.hpp"
#include "transmitter_model.hpp"
/* Stashes current radio bandwidth and sampling rate.
* Inits to defaults, and restores previous when destroyed.
* The idea here is that an app will eventually call enable
* on the model which will sync all of the model state into
* the radio. We tried lazily setting these using the
* set_configuration_without_update function, but there are
* still various UI components (mainly Waterfall) that need
* the radio set in order to load properly.
/* Reinitialized model with defaults so each app can start
* with a clean, default model instance. We tried lazily
* setting these using the set_configuration_without_update
* function, but there are still various UI components
* (e.g. Waterfall) that need the radio set in order to load.
* NB: This member must be added before SettingsManager. */
template <typename TModel, TModel* model>
class RadioState {
public:
RadioState()
: RadioState(max2837::filter::bandwidth_minimum, 3072000) {
RadioState() {
model->initialize();
}
RadioState(uint32_t new_bandwidth, uint32_t new_sampling_rate)
: prev_bandwidth_{model->baseband_bandwidth()},
prev_sampling_rate_{model->sampling_rate()} {
// Update the new settings in the radio.
RadioState(uint32_t new_bandwidth, uint32_t new_sampling_rate) {
model->initialize();
model->set_sampling_rate(new_sampling_rate);
model->set_baseband_bandwidth(new_bandwidth);
}
~RadioState() {
model->set_configuration_without_update(
prev_bandwidth_, prev_sampling_rate_);
// NB: only enabled for RX model.
template <
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:
const uint32_t prev_bandwidth_;
const uint32_t prev_sampling_rate_;
// NB: only enabled for RX model.
template <
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>;
+154 -156
View File
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2023 Kyle Reed
*
* This file is part of PortaPack.
*
@@ -39,9 +40,9 @@ using namespace portapack;
namespace {
static constexpr std::array<baseband::AMConfig, 5> am_configs{{
// 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_6k0_decim_2, taps_6k0_dsb_channel, AMConfigureMessage::Modulation::DSB}, // AM DSB-C BW 6khz (+-3k0) narrow AM , ham equipments.
// 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_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_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
@@ -70,72 +71,114 @@ void ReceiverModel::set_target_frequency(rf::Frequency f) {
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 {
return frequency_step_;
return settings_.frequency_step;
}
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() {
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 {
return persistent_memory::headphone_volume();
}
@@ -157,15 +200,6 @@ void ReceiverModel::set_normalized_headphone_volume(uint8_t v) {
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() {
enabled_ = true;
radio::set_direction(rf::Direction::Receive);
@@ -193,6 +227,35 @@ void ReceiverModel::disable() {
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() {
if ((modulation() == Mode::SpectrumAnalysis)) {
return 0;
@@ -206,78 +269,8 @@ void ReceiverModel::update_tuning_frequency() {
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() {
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;
radio::set_baseband_filter_bandwidth(baseband_bandwidth());
}
void ReceiverModel::update_sampling_rate() {
@@ -290,8 +283,16 @@ void ReceiverModel::update_sampling_rate() {
update_tuning_frequency();
}
void ReceiverModel::update_headphone_volume() {
audio::headphone::set_volume(headphone_volume());
void ReceiverModel::update_lna() {
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() {
@@ -315,26 +316,23 @@ void ReceiverModel::update_modulation() {
}
}
size_t ReceiverModel::am_configuration() const {
return am_config_index;
}
void ReceiverModel::update_am_configuration() {
am_configs[am_config_index].apply();
}
size_t ReceiverModel::nbfm_configuration() const {
return nbfm_config_index;
am_configs[am_configuration()].apply();
}
void ReceiverModel::update_nbfm_configuration() {
nbfm_configs[nbfm_config_index].apply(squelch_level_);
}
size_t ReceiverModel::wfm_configuration() const {
return wfm_config_index;
nbfm_configs[nbfm_configuration()].apply(squelch_level());
}
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());
}
+57 -49
View File
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2023 Kyle Reed
*
* This file is part of PortaPack.
*
@@ -26,16 +27,16 @@
#include <cstddef>
#include "app_settings.hpp"
#include "max283x.hpp"
#include "message.hpp"
#include "rf_path.hpp"
#include "max283x.hpp"
#include "volume.hpp"
// TODO: consider a base class for ReceiverModel & TransmitterModel.
// There are multiple values that are actually shared by both.
class ReceiverModel {
public:
enum class Mode {
enum class Mode : uint8_t {
AMAudio = 0,
NarrowbandFMAudio = 1,
WidebandFMAudio = 2,
@@ -43,33 +44,59 @@ class ReceiverModel {
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). */
rf::Frequency target_frequency() const;
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;
void set_baseband_bandwidth(uint32_t v);
int32_t vga() const;
void set_vga(int32_t v_db);
uint32_t sampling_rate() const;
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;
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;
void set_headphone_volume(volume_t v);
@@ -77,25 +104,11 @@ class ReceiverModel {
uint8_t normalized_headphone_volume() const;
void set_normalized_headphone_volume(uint8_t v);
uint8_t squelch_level() const;
void set_squelch_level(uint8_t v);
void enable();
void disable();
size_t am_configuration() const;
void set_am_configuration(const size_t n);
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);
/* Resets some members back to default. */
void initialize();
void set_configuration_without_update(
Mode new_mode,
@@ -107,35 +120,30 @@ class ReceiverModel {
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:
rf::Frequency frequency_step_{25000};
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};
settings_t settings_{};
bool enabled_ = false;
int32_t tuning_offset();
void update_tuning_frequency();
void update_antenna_bias();
void update_rf_amp();
void update_lna();
void update_baseband_bandwidth();
void update_vga();
void update_sampling_rate();
void update_headphone_volume();
void update_lna();
void update_vga();
void update_rf_amp();
void update_modulation();
void update_am_configuration();
void update_nbfm_configuration();
void update_wfm_configuration();
void update_antenna_bias();
void update_headphone_volume();
};
#endif /*__RECEIVER_MODEL_H__*/
+119 -70
View File
@@ -25,63 +25,68 @@
namespace tonekey {
// Keep list in ascending order by tone frequency
const tone_key_t tone_keys = {
{"None", 0.0},
{"0 XZ", 67.000},
{"1 WZ", 69.400},
{"2 XA", 71.900},
{"3 WA", 74.400},
{"4 XB", 77.000},
{"5 WB", 79.700},
{"6 YZ", 82.500},
{"7 YA", 85.400},
{"8 YB", 88.500},
{"9 ZZ", 91.500},
{"10 ZA", 94.800},
{"11 ZB", 97.400},
{"12 1Z", 100.000},
{"13 1A", 103.500},
{"14 1B", 107.200},
{"15 2Z", 110.900},
{"16 2A", 114.800},
{"17 2B", 118.800},
{"18 3Z", 123.000},
{"19 3A", 127.300},
{"20 3B", 131.800},
{"21 4Z", 136.500},
{"22 4A", 141.300},
{"23 4B", 146.200},
{"24 5Z", 151.400},
{"25 5A", 156.700},
{"40 --", 159.800},
{"26 5B", 162.200},
{"41 --", 165.500},
{"27 6Z", 167.900},
{"42 --", 171.300},
{"28 6A", 173.800},
{"43 --", 177.300},
{"29 6B", 179.900},
{"44 --", 183.500},
{"30 7Z", 186.200},
{"45 --", 189.900},
{"31 7A", 192.800},
{"46 --", 196.600},
{"47 --", 199.500},
{"32 M1", 203.500},
{"48 8Z", 206.500},
{"33 M2", 210.700},
{"34 M3", 218.100},
{"35 M4", 225.700},
{"49 9Z", 229.100},
{"36 M5", 233.600},
{"37 M6", 241.800},
{"38 M7", 250.300},
{"50 0Z", 254.100},
{"Axient 28kHz", 28000.0},
{"Senn. 32.768k", 32768.0},
{"Senn. 32.000k", 32000.0},
{"Sony 32.382k", 32382.0},
{"Shure 19kHz", 19000.0}};
{"None", F2Ix100(0.0)},
{"1 XZ", F2Ix100(67.0)},
{"39 WZ", F2Ix100(69.3)},
{"2 XA", F2Ix100(71.9)},
{"3 WA", F2Ix100(74.4)},
{"4 XB", F2Ix100(77.0)},
{"5 WB", F2Ix100(79.7)},
{"6 YZ", F2Ix100(82.5)},
{"7 YA", F2Ix100(85.4)},
{"8 YB", F2Ix100(88.5)},
{"9 ZZ", F2Ix100(91.5)},
{"10 ZA", F2Ix100(94.8)},
{"11 ZB", F2Ix100(97.4)},
{"12 1Z", F2Ix100(100.0)},
{"13 1A", F2Ix100(103.5)},
{"14 1B", F2Ix100(107.2)},
{"15 2Z", F2Ix100(110.9)},
{"16 2A", F2Ix100(114.8)},
{"17 2B", F2Ix100(118.8)},
{"18 3Z", F2Ix100(123.0)},
{"19 3A", F2Ix100(127.3)},
{"20 3B", F2Ix100(131.8)},
{"21 4Z", F2Ix100(136.5)},
{"22 4A", F2Ix100(141.3)},
{"23 4B", F2Ix100(146.2)},
{"24 5Z", F2Ix100(151.4)},
{"25 5A", F2Ix100(156.7)},
{"40 --", F2Ix100(159.8)},
{"26 5B", F2Ix100(162.2)},
{"41 --", F2Ix100(165.5)},
{"27 6Z", F2Ix100(167.9)},
{"42 --", F2Ix100(171.3)},
{"28 6A", F2Ix100(173.8)},
{"43 --", F2Ix100(177.3)},
{"29 6B", F2Ix100(179.9)},
{"44 --", F2Ix100(183.5)},
{"30 7Z", F2Ix100(186.2)},
{"45 --", F2Ix100(189.9)},
{"31 7A", F2Ix100(192.8)},
{"46 --", F2Ix100(196.6)},
{"47 --", F2Ix100(199.5)},
{"32 M1", F2Ix100(203.5)},
{"48 8Z", F2Ix100(206.5)},
{"33 M2", F2Ix100(210.7)},
{"34 M3", F2Ix100(218.1)},
{"35 M4", F2Ix100(225.7)},
{"49 9Z", F2Ix100(229.1)},
{"36 M5", F2Ix100(233.6)},
{"37 M6", F2Ix100(241.8)},
{"38 M7", F2Ix100(250.3)},
{"50 0Z", F2Ix100(254.1)},
{"Shure 19kHz", F2Ix100(19000.0)},
{"Axient 28kHz", F2Ix100(28000.0)},
{"Senn. 32.000k", F2Ix100(32000.0)},
{"Sony 32.382k", F2Ix100(32382.0)},
{"Senn. 32.768k", F2Ix100(32768.0)}};
std::string fx100_string(uint32_t f) {
return to_string_dec_uint(f / 100) + "." + to_string_dec_uint((f / 10) % 10);
}
void tone_keys_populate(OptionsField& field) {
using option_t = std::pair<std::string, int32_t>;
@@ -90,12 +95,11 @@ void tone_keys_populate(OptionsField& field) {
std::string tone_name;
for (size_t c = 0; c < tone_keys.size(); c++) {
if (c && c < 51) {
auto f = tone_keys[c].second;
tone_name = "CTCSS " + tone_keys[c].first + " " + to_string_dec_uint(f) + "." + to_string_dec_uint((uint32_t)(f * 10) % 10);
} else {
auto f = tone_keys[c].second;
if ((c != 0) && (f < 1000 * 100))
tone_name = "CTCSS " + fx100_string(f) + " #" + tone_keys[c].first;
else
tone_name = tone_keys[c].first;
}
tone_key_options.emplace_back(tone_name, c);
}
@@ -103,8 +107,8 @@ void tone_keys_populate(OptionsField& field) {
field.set_options(tone_key_options);
}
float tone_key_frequency(const tone_index index) {
return tone_keys[index].second;
float tone_key_frequency(tone_index index) {
return float(tone_keys[index].second) / 100.0;
}
std::string tone_key_string(tone_index index) {
@@ -113,20 +117,65 @@ std::string tone_key_string(tone_index index) {
return tone_keys[index].first;
}
std::string tone_key_string_by_value(uint32_t value) {
return tone_key_string(tone_key_index_by_value(value));
// Return string showing frequency only from specific table index
std::string tone_key_value_string(tone_index index) {
if (index < 0 || (unsigned)index >= tone_keys.size())
return std::string("");
return fx100_string(tone_keys[index].second);
}
// Return variable-length string showing CTCSS tone from tone frequency
// Value is in 0.01 Hz units
std::string tone_key_string_by_value(uint32_t value, size_t max_length) {
static uint8_t tone_display_toggle{0};
static uint32_t last_value;
tone_index idx;
std::string freq_str;
// If >10Hz difference between consecutive samples, it's probably noise, so ignore
if (abs(value - last_value) > 10 * 100) {
last_value = value;
tone_display_toggle = 0;
return " ";
}
last_value = value;
// Only display 1/10 Hz accuracy if <1000 Hz; max 5 characters
if (value < 1000 * 100)
freq_str = "T:" + fx100_string(value);
else
freq_str = "T:" + to_string_dec_uint(value / 100);
// Check field length is enough for character counts in the string below
if (max_length >= 7 + 2 + 5) {
idx = tone_key_index_by_value(value);
if (idx != -1)
return freq_str + " #" + tone_key_string(idx);
} else {
// Not enough space; toggle between display of tone received and tone code #
if (tone_display_toggle++ >= TONE_DISPLAY_TOGGLE_COUNTER) {
if (tone_display_toggle >= TONE_DISPLAY_TOGGLE_COUNTER * 2) tone_display_toggle = 0;
// Look for a match in the table (otherwise just display frequency)
idx = tone_key_index_by_value(value);
if (idx != -1)
return "T:" + tone_key_string(idx);
}
}
return freq_str;
}
// Search tone_key table for tone frequency value
// Value is in 0.01 Hz units
tone_index tone_key_index_by_value(uint32_t value) {
float diff;
float min_diff{(float)value};
float fvalue{(float)((min_diff + 50.0) / 100.0)};
uint32_t diff;
uint32_t min_diff{value * 2};
tone_index min_idx{-1};
tone_index idx;
// Find nearest match
for (idx = 0; idx < (tone_index)tone_keys.size(); idx++) {
diff = abs(fvalue - tone_keys[idx].second);
diff = abs(value - tone_keys[idx].second);
if (diff < min_diff) {
min_idx = idx;
min_diff = diff;
@@ -137,7 +186,7 @@ tone_index tone_key_index_by_value(uint32_t value) {
}
// Arbitrary confidence threshold
if (min_diff < 40.0)
if (min_diff < TONE_FREQ_TOLERANCE_CENTIHZ)
return min_idx;
else
return -1;
+9 -4
View File
@@ -30,17 +30,22 @@ using namespace ui;
namespace tonekey {
#define TONE_FREQ_TOLERANCE_CENTIHZ (4 * 100)
#define TONE_DISPLAY_TOGGLE_COUNTER 3
#define F2Ix100(x) (int32_t)(x * 100.0)
typedef int32_t tone_index;
using tone_key_t = std::vector<std::pair<std::string, float>>;
using tone_key_t = std::vector<std::pair<std::string, uint32_t>>;
extern const tone_key_t tone_keys;
void tone_keys_populate(OptionsField& field);
float tone_key_frequency(const tone_index index);
float tone_key_frequency(tone_index index);
std::string tone_key_string(const tone_index index);
std::string tone_key_string_by_value(uint32_t value);
std::string tone_key_string(tone_index index);
std::string tone_key_value_string(tone_index index);
std::string tone_key_string_by_value(uint32_t value, size_t max_length);
tone_index tone_key_index_by_value(uint32_t value);
} // namespace tonekey
+57 -93
View File
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2016 Furrtek
* Copyright (C) 2023 Kyle Reed
*
* This file is part of PortaPack.
*
@@ -22,15 +23,13 @@
#include "transmitter_model.hpp"
#include "audio.hpp"
#include "baseband_api.hpp"
#include "portapack_persistent_memory.hpp"
#include "event_m0.hpp"
#include "hackrf_gpio.hpp"
#include "portapack.hpp"
#include "rtc_time.hpp"
#include "event_m0.hpp"
#include "portapack_persistent_memory.hpp"
#include "radio.hpp"
#include "audio.hpp"
using namespace hackrf::one;
using namespace portapack;
@@ -44,75 +43,52 @@ void TransmitterModel::set_target_frequency(rf::Frequency f) {
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 {
return baseband_bandwidth_;
return settings_.baseband_bandwidth;
}
void TransmitterModel::set_baseband_bandwidth(uint32_t v) {
baseband_bandwidth_ = v;
settings_.baseband_bandwidth = v;
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 {
return sampling_rate_;
return settings_.sampling_rate;
}
void TransmitterModel::set_sampling_rate(uint32_t v) {
sampling_rate_ = v;
settings_.sampling_rate = v;
update_sampling_rate();
}
int32_t TransmitterModel::tx_gain() const {
return tx_gain_db_;
uint32_t TransmitterModel::channel_bandwidth() const {
return settings_.channel_bandwidth;
}
void TransmitterModel::set_tx_gain(int32_t v_db) {
tx_gain_db_ = v_db;
void TransmitterModel::set_channel_bandwidth(uint32_t v) {
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();
}
void TransmitterModel::on_tick_second() {
if (portapack::persistent_memory::stealth_mode())
led_tx.toggle();
bool TransmitterModel::rf_amp() const {
return settings_.rf_amp;
}
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() {
@@ -121,8 +97,6 @@ void TransmitterModel::enable() {
update_tuning_frequency();
update_antenna_bias();
update_rf_amp();
update_lna();
update_vga();
update_baseband_bandwidth();
update_sampling_rate();
update_tx_gain();
@@ -147,53 +121,25 @@ void TransmitterModel::disable() {
led_tx.off();
}
void TransmitterModel::set_configuration_without_update(
uint32_t baseband_bandwidth,
uint32_t sampling_rate) {
baseband_bandwidth_ = baseband_bandwidth;
sampling_rate_ = sampling_rate;
void TransmitterModel::initialize() {
settings_ = settings_t{};
}
void TransmitterModel::configure_from_app_settings(
const app_settings::AppSettings& settings) {
baseband_bandwidth_ = settings.baseband_bandwidth;
channel_bandwidth_ = settings.channel_bandwidth;
tx_gain_db_ = settings.tx_gain;
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;
settings_.baseband_bandwidth = settings.baseband_bandwidth;
settings_.sampling_rate = settings.sampling_rate;
settings_.channel_bandwidth = settings.channel_bandwidth;
settings_.tx_gain_db = settings.tx_gain;
settings_.rf_amp = settings.tx_amp;
}
void TransmitterModel::update_tuning_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() {
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_);
radio::set_baseband_filter_bandwidth(baseband_bandwidth());
}
void TransmitterModel::update_sampling_rate() {
@@ -206,3 +152,21 @@ void TransmitterModel::update_sampling_rate() {
radio::set_baseband_rate(sampling_rate());
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();
}
+31 -39
View File
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2016 Furrtek
* Copyright (C) 2023 Kyle Reed
*
* This file is part of PortaPack.
*
@@ -26,77 +27,68 @@
#include <cstdint>
#include <cstddef>
#include "receiver_model.hpp"
#include "app_settings.hpp"
#include "message.hpp"
#include "rf_path.hpp"
#include "max2837.hpp"
#include "volume.hpp"
#include "message.hpp"
#include "receiver_model.hpp"
#include "rf_path.hpp"
#include "signal.hpp"
class TransmitterModel {
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. */
rf::Frequency target_frequency() const;
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;
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.
uint32_t channel_bandwidth() const;
void set_channel_bandwidth(uint32_t v);
// TODO: does this make sense on TX?
uint32_t sampling_rate() const;
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 disable();
/* Sets the model values without updating the radio. */
void set_configuration_without_update(
uint32_t baseband_bandwidth,
uint32_t sampling_rate);
void initialize();
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:
bool enabled_{false};
bool rf_amp_{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};
settings_t settings_{};
bool enabled_ = false;
SignalToken signal_token_tick_second{};
void update_tuning_frequency();
void update_antenna_bias();
void update_rf_amp();
void update_lna();
void update_baseband_bandwidth();
void update_vga();
void update_tx_gain();
void update_sampling_rate();
void update_tx_gain();
void update_rf_amp();
void update_antenna_bias();
void on_tick_second();
};
+1 -1
View File
@@ -280,7 +280,7 @@ FrequencyOptionsView::FrequencyOptionsView(
}
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) {
+23 -55
View File
@@ -77,6 +77,7 @@
#include "ui_flash_utility.hpp"
#include "ui_sd_over_usb.hpp"
#include "ui_spectrum_painter.hpp"
#include "ui_ss_viewer.hpp"
// #include "acars_app.hpp"
#include "ais_app.hpp"
@@ -179,16 +180,21 @@ SystemStatusView::SystemStatusView(
this->on_converter();
};
button_speaker.on_select = [this](ImageButton&) {
this->on_speaker();
toggle_speaker.on_change = [this](bool v) {
pmem::set_config_speaker_disable(v);
audio::output::update_audio_mute();
refresh();
};
button_mute.on_select = [this](ImageButton&) {
this->on_mute();
toggle_mute.on_change = [this](bool v) {
pmem::set_config_audio_mute(v);
audio::output::update_audio_mute();
refresh();
};
button_stealth.on_select = [this](ImageButton&) {
this->on_stealth();
toggle_stealth.on_change = [this](bool v) {
pmem::set_stealth_mode(v);
refresh();
};
button_bias_tee.on_select = [this](ImageButton&) {
@@ -208,6 +214,11 @@ SystemStatusView::SystemStatusView(
this->on_clk();
};
// Initialize toggle buttons
toggle_speaker.set_value(pmem::config_speaker_disable());
toggle_mute.set_value(pmem::config_audio_mute());
toggle_stealth.set_value(pmem::stealth_mode());
audio::output::update_audio_mute();
refresh();
}
@@ -218,43 +229,22 @@ void SystemStatusView::refresh() {
status_icons.clear();
if (!pmem::ui_hide_camera()) status_icons.add(&button_camera);
if (!pmem::ui_hide_sleep()) status_icons.add(&button_sleep);
if (!pmem::ui_hide_stealth()) status_icons.add(&button_stealth);
if (!pmem::ui_hide_stealth()) status_icons.add(&toggle_stealth);
if (!pmem::ui_hide_converter()) status_icons.add(&button_converter);
if (!pmem::ui_hide_bias_tee()) status_icons.add(&button_bias_tee);
if (!pmem::ui_hide_clock()) status_icons.add(&button_clock_status);
if (!pmem::ui_hide_mute()) status_icons.add(&button_mute);
if (!pmem::ui_hide_mute()) status_icons.add(&toggle_mute);
// Display "Disable speaker" icon only if AK4951 Codec which has separate speaker/headphone control
if (audio::speaker_disable_supported() && !pmem::ui_hide_speaker())
status_icons.add(&button_speaker);
if (audio::speaker_disable_supported() && !pmem::ui_hide_speaker()) status_icons.add(&toggle_speaker);
if (!pmem::ui_hide_sd_card()) status_icons.add(&sd_card_status_view);
status_icons.update_layout();
// Update icon display (try to keep all in on place).
// Speaker Enable/Disable (AK4951 boards only)
if (pmem::config_speaker_disable()) {
button_speaker.set_foreground(Color::light_grey());
button_speaker.set_bitmap(&bitmap_icon_speaker_mute);
} else {
button_speaker.set_foreground(Color::green());
button_speaker.set_bitmap(&bitmap_icon_speaker);
}
// Audio Mute (both headphones & speaker)
if (pmem::config_audio_mute()) {
button_mute.set_foreground(Color::light_grey());
button_mute.set_bitmap(&bitmap_icon_speaker_and_headphones_mute);
} else {
button_mute.set_foreground(Color::green());
button_mute.set_bitmap(&bitmap_icon_speaker_and_headphones);
}
// Clock status
bool external_clk = portapack::clock_manager.get_reference().source == ClockManager::ReferenceSource::External;
button_clock_status.set_bitmap(external_clk ? &bitmap_icon_clk_ext : &bitmap_icon_clk_int);
button_clock_status.set_foreground(
pmem::clkout_enabled() ? Color::green() : Color::light_grey());
button_clock_status.set_foreground(pmem::clkout_enabled() ? Color::green() : Color::light_grey());
// Antenna DC Bias
if (portapack::get_antenna_bias()) {
@@ -266,14 +256,9 @@ void SystemStatusView::refresh() {
}
// Converter
button_converter.set_bitmap(
pmem::config_updown_converter() ? &bitmap_icon_downconvert : &bitmap_icon_upconvert);
button_converter.set_bitmap(pmem::config_updown_converter() ? &bitmap_icon_downconvert : &bitmap_icon_upconvert);
button_converter.set_foreground(pmem::config_converter() ? Color::red() : Color::light_grey());
// Stealth
button_stealth.set_foreground(
pmem::stealth_mode() ? Color::green() : Color::light_grey());
set_dirty();
}
@@ -314,23 +299,6 @@ void SystemStatusView::on_converter() {
refresh();
}
void SystemStatusView::on_speaker() {
pmem::set_config_speaker_disable(!pmem::config_speaker_disable());
audio::output::update_audio_mute();
refresh();
}
void SystemStatusView::on_mute() {
pmem::set_config_audio_mute(!pmem::config_audio_mute());
audio::output::update_audio_mute();
refresh();
}
void SystemStatusView::on_stealth() {
pmem::set_stealth_mode(!pmem::stealth_mode());
refresh();
}
void SystemStatusView::on_bias_tee() {
if (!portapack::get_antenna_bias()) {
nav_.display_modal("Bias voltage",
@@ -767,7 +735,7 @@ BMPView::BMPView(NavigationView& nav) {
}
void BMPView::paint(Painter&) {
if (!portapack::display.drawBMP2({0, 0}, "splash.bmp"))
if (!portapack::display.drawBMP2({0, 0}, splash_dot_bmp))
portapack::display.drawBMP({(240 - 230) / 2, (320 - 50) / 2 - 10}, splash_bmp, false);
}
+10 -10
View File
@@ -184,17 +184,22 @@ class SystemStatusView : public View {
StatusTray status_icons{{screen_width, 0}};
// TODO: Convert to ImageToggle buttons.
ImageButton button_speaker{
ImageToggle toggle_speaker{
{0, 0, 2 * 8, 1 * 16},
&bitmap_icon_speaker_mute,
&bitmap_icon_speaker,
Color::light_grey(),
Color::dark_grey(),
Color::green(),
Color::dark_grey()};
ImageButton button_mute{
ImageToggle toggle_mute{
{0, 0, 2 * 8, 1 * 16},
&bitmap_icon_speaker_and_headphones_mute,
&bitmap_icon_speaker_and_headphones,
Color::light_grey(),
Color::dark_grey(),
Color::green(),
Color::dark_grey()};
ImageButton button_converter{
@@ -203,11 +208,9 @@ class SystemStatusView : public View {
Color::light_grey(),
Color::dark_grey()};
ImageButton button_stealth{
ImageToggle toggle_stealth{
{0, 0, 2 * 8, 1 * 16},
&bitmap_icon_stealth,
Color::light_grey(),
Color::dark_grey()};
&bitmap_icon_stealth};
ImageButton button_camera{
{0, 0, 2 * 8, 1 * 16},
@@ -237,9 +240,6 @@ class SystemStatusView : public View {
{0, 0 * 16, 2 * 8, 1 * 16}};
void on_converter();
void on_speaker();
void on_mute();
void on_stealth();
void on_bias_tee();
void on_camera();
void on_title();
+7 -3
View File
@@ -53,7 +53,9 @@ void NarrowbandFMAudio::execute(const buffer_c8_t& buffer) {
if (ctcss_detect_enabled) {
/* 24kHz int16_t[16]
* -> FIR filter, <300Hz pass, >300Hz stop, gain of 1
* -> 12kHz int16_t[8] */
* -> 12kHz int16_t[8]
*
* Note we're only processing a small section of the wave each time this fn is called */
auto audio_ctcss = ctcss_filter.execute(audio, work_audio_buffer);
// s16 to f32 for hpf
@@ -72,16 +74,18 @@ void NarrowbandFMAudio::execute(const buffer_c8_t& buffer) {
cur_sample = audio_f[c];
if (cur_sample * prev_sample < 0.0) {
z_acc += z_timer;
z_timer = 0;
z_timer = 1;
z_count++;
} else
z_timer++;
prev_sample = cur_sample;
}
if (z_count >= 30) {
z_filter_count++;
if ((z_filter_count >= Z_MIN_FILTER_COUNT) && (z_count >= Z_MIN_ZERO_CROSSINGS)) {
ctcss_message.value = (100 * 12000 / 2 * z_count) / z_acc;
shared_memory.application_queue.push(ctcss_message);
z_filter_count = 0;
z_count = 0;
z_acc = 0;
}
+4 -1
View File
@@ -36,6 +36,9 @@
#include <cstdint>
#define Z_MIN_FILTER_COUNT 224
#define Z_MIN_ZERO_CROSSINGS 20
class NarrowbandFMAudio : public BasebandProcessor {
public:
void execute(const buffer_c8_t& buffer) override;
@@ -88,7 +91,7 @@ class NarrowbandFMAudio : public BasebandProcessor {
bool pitch_rssi_enabled{false};
float cur_sample{}, prev_sample{};
uint32_t z_acc{0}, z_timer{0}, z_count{0};
uint32_t z_acc{0}, z_timer{0}, z_count{0}, z_filter_count{0};
bool ctcss_detect_enabled{true};
static constexpr float k = 32768.0f;
static constexpr float ki = 1.0f / k;
+1 -1
View File
@@ -412,7 +412,7 @@ void ILI9341::drawBMP(const ui::Point p, const uint8_t* bitmap, const bool trans
24bpp RGB
32bpp ARGB
*/
bool ILI9341::drawBMP2(const ui::Point p, const std::string file) {
bool ILI9341::drawBMP2(const ui::Point p, const std::filesystem::path& file) {
File bmpimage;
size_t file_pos = 0;
uint16_t pointer = 0;
+2 -1
View File
@@ -25,6 +25,7 @@
#include "ui.hpp"
#include "ui_text.hpp"
#include "file.hpp"
#include <cstdint>
#include <array>
@@ -58,7 +59,7 @@ class ILI9341 {
void draw_pixel(const ui::Point p, const ui::Color color);
void drawBMP(const ui::Point p, const uint8_t* bitmap, const bool transparency);
bool drawBMP2(const ui::Point p, const std::string file);
bool drawBMP2(const ui::Point p, const std::filesystem::path& file);
void render_line(const ui::Point p, const uint8_t count, const ui::Color* line_buffer);
void render_box(const ui::Point p, const ui::Size s, const ui::Color* line_buffer);
+172 -310
View File
@@ -23,27 +23,21 @@
#include "portapack_persistent_memory.hpp"
#include "audio.hpp"
#include "portapack.hpp"
#include "hal.h"
#include "utility.hpp"
#include "memory_map.hpp"
#include "crc.hpp"
#include <algorithm>
#include <utility>
#include <string>
#include <fstream>
#include "file.hpp"
#include "hal.h"
#include "irq_controls.hpp"
#include "memory_map.hpp"
#include "portapack.hpp"
#include "string_format.hpp"
#include "ui_styles.hpp"
#include "ui_painter.hpp"
#include "utility.hpp"
#include <algorithm>
#include <string>
#include <fstream>
#include <utility>
#include <ch.h>
@@ -71,9 +65,11 @@ using modem_baudrate_range_t = range_t<int32_t>;
constexpr modem_baudrate_range_t modem_baudrate_range{50, 9600};
constexpr int32_t modem_baudrate_reset_value{1200};
/*using modem_bw_range_t = range_t<int32_t>;
constexpr modem_bw_range_t modem_bw_range { 1000, 50000 };
constexpr int32_t modem_bw_reset_value { 15000 };*/
/*
using modem_bw_range_t = range_t<int32_t>;
constexpr modem_bw_range_t modem_bw_range { 1000, 50000 };
constexpr int32_t modem_bw_reset_value { 15000 };
*/
using modem_repeat_range_t = range_t<int32_t>;
constexpr modem_repeat_range_t modem_repeat_range{1, 99};
@@ -81,176 +77,38 @@ constexpr int32_t modem_repeat_reset_value{5};
using clkout_freq_range_t = range_t<uint32_t>;
constexpr clkout_freq_range_t clkout_freq_range{10, 60000};
constexpr uint32_t clkout_freq_reset_value{10000};
constexpr uint16_t clkout_freq_reset_value{10000};
enum data_structure_version_enum : uint32_t {
VERSION_CURRENT = 0x10000003,
VERSION_CURRENT = 0x10000004,
};
static const uint32_t TOUCH_CALIBRATION_MAGIC = 0x074af82f;
/* UI config.
* NB: Will be default init - override in defaults(). */
struct ui_config_t {
private:
enum bits_t {
BacklightTimeoutLSB = 0,
BacklightTimeoutEnable = 3,
ClkoutFreqLSB = 4,
ShowGUIReturnIcon = 20,
LoadAppSettings = 21,
SaveAppSettings = 22,
ShowBiggerQRCode = 23,
DisableTouchscreen = 24,
HideClock = 25,
ClockWithDate = 26,
ClkOutEnabled = 27,
UNUSED = 28,
StealthMode = 29,
ConfigLogin = 30,
ConfigSplash = 31,
};
uint16_t clkout_freq;
enum bits_mask_t : uint32_t {
BacklightTimeoutMask = ((1 << 3) - 1) << bits_t::BacklightTimeoutLSB,
ClkoutFreqMask = ((1 << 16) - 1) << bits_t::ClkoutFreqLSB,
};
// NB: bitsfields have to be the same type or the compiler will
// split into a new byte hence uint8_t for these booleans.
uint8_t backlight_timeout : 3;
uint8_t enable_backlight_timeout : 1;
uint8_t show_gui_return_icon : 1;
uint8_t load_app_settings : 1;
uint8_t save_app_settings : 1;
uint8_t show_large_qr_code : 1;
uint32_t values;
constexpr bool bit_read(const bits_t n) const {
return ((values >> n) & 1) != 0;
}
constexpr void bit_write(const bits_t n, const bool v) {
if (bit_read(n) != v) {
values ^= 1 << n;
}
}
public:
backlight_config_t config_backlight_timer() {
const auto timeout_enum = (backlight_timeout_t)((values & bits_mask_t::BacklightTimeoutMask) >> bits_t::BacklightTimeoutLSB);
const bool timeout_enabled = bit_read(bits_t::BacklightTimeoutEnable);
return backlight_config_t(timeout_enum, timeout_enabled);
}
void set_config_backlight_timer(const backlight_config_t& new_value) {
values = (values & ~bits_mask_t::BacklightTimeoutMask) | ((new_value.timeout_enum() << bits_t::BacklightTimeoutLSB) & bits_mask_t::BacklightTimeoutMask);
bit_write(bits_t::BacklightTimeoutEnable, new_value.timeout_enabled());
}
constexpr uint32_t clkout_freq() {
uint32_t freq = (values & bits_mask_t::ClkoutFreqMask) >> bits_t::ClkoutFreqLSB;
if (freq < clkout_freq_range.minimum || freq > clkout_freq_range.maximum) {
values = (values & ~bits_mask_t::ClkoutFreqMask) | (clkout_freq_reset_value << bits_t::ClkoutFreqLSB);
return clkout_freq_reset_value;
} else {
return freq;
}
}
constexpr void set_clkout_freq(uint32_t freq) {
values = (values & ~bits_mask_t::ClkoutFreqMask) | (clkout_freq_range.clip(freq) << bits_t::ClkoutFreqLSB);
}
// ui_config is an uint32_t var storing information bitwise
// bits 0-2 store the backlight timer
// bits 4-19 (16 bits) store the clkout frequency
// bits 21-31 store the different single bit configs depicted below
// bit 20 store the display state of the gui return icon, hidden (0) or shown (1)
constexpr bool show_gui_return_icon() const { // add return icon in touchscreen menue
return bit_read(bits_t::ShowGUIReturnIcon);
}
constexpr void set_gui_return_icon(bool v) {
bit_write(bits_t::ShowGUIReturnIcon, v);
}
constexpr bool load_app_settings() const { // load (last saved) app settings on startup of app
return bit_read(bits_t::LoadAppSettings);
}
constexpr void set_load_app_settings(bool v) {
bit_write(bits_t::LoadAppSettings, v);
}
constexpr bool save_app_settings() const { // save app settings when closing app
return bit_read(bits_t::SaveAppSettings);
}
constexpr void set_save_app_settings(bool v) {
bit_write(bits_t::SaveAppSettings, v);
}
constexpr bool show_bigger_qr_code() const { // show bigger QR code
return bit_read(bits_t::ShowBiggerQRCode);
}
constexpr void set_show_bigger_qr_code(bool v) {
bit_write(bits_t::ShowBiggerQRCode, v);
}
constexpr bool disable_touchscreen() const { // Option to disable touch screen
return bit_read(bits_t::DisableTouchscreen);
}
constexpr void set_disable_touchscreen(bool v) {
bit_write(bits_t::DisableTouchscreen, v);
}
constexpr bool hide_clock() const { // clock hidden from main menu
return bit_read(bits_t::HideClock);
}
constexpr void set_clock_hidden(bool v) {
bit_write(bits_t::HideClock, v);
}
constexpr bool clock_with_date() const { // show clock with date, if not hidden
return bit_read(bits_t::ClockWithDate);
}
constexpr void set_clock_with_date(bool v) {
bit_write(bits_t::ClockWithDate, v);
}
constexpr bool clkout_enabled() const {
return bit_read(bits_t::ClkOutEnabled);
}
constexpr void set_clkout_enabled(bool v) {
bit_write(bits_t::ClkOutEnabled, v);
}
constexpr bool stealth_mode() const {
return bit_read(bits_t::StealthMode);
}
constexpr void set_stealth_mode(bool v) {
bit_write(bits_t::StealthMode, v);
}
constexpr bool config_login() const {
return bit_read(bits_t::ConfigLogin);
}
constexpr void set_config_login(bool v) {
bit_write(bits_t::ConfigLogin, v);
}
constexpr bool config_splash() const {
return bit_read(bits_t::ConfigSplash);
}
constexpr void set_config_splash(bool v) {
bit_write(bits_t::ConfigSplash, v);
}
constexpr ui_config_t()
: values(
(1 << ConfigSplash) | (clkout_freq_reset_value << ClkoutFreqLSB) | (7 << BacklightTimeoutLSB)) {
}
bool disable_touchscreen : 1;
bool hide_clock : 1;
bool clock_show_date : 1;
bool clkout_enabled : 1;
bool UNUSED_1 : 1;
bool stealth_mode : 1;
bool config_login : 1;
bool config_splash : 1;
};
static_assert(sizeof(ui_config_t) == sizeof(uint32_t));
/* Additional UI config.
* NB: Will be default init - override in defaults(). */
@@ -266,67 +124,48 @@ struct ui_config2_t {
bool hide_sd_card : 1;
bool hide_mute : 1;
bool UNUSED : 7;
bool UNUSED_1 : 1;
bool UNUSED_2 : 1;
bool UNUSED_3 : 1;
bool UNUSED_4 : 1;
bool UNUSED_5 : 1;
bool UNUSED_6 : 1;
bool UNUSED_7 : 1;
uint8_t placeholder_1;
uint8_t placeholder_2;
uint8_t PLACEHOLDER_2;
uint8_t PLACEHOLDER_3;
};
static_assert(sizeof(ui_config2_t) == sizeof(uint32_t));
/* Additional config.
* NB: Will be default init - override in defaults(). */
struct misc_config_t {
private:
enum bits_t {
ConfigAudioMute = 0,
ConfigSpeakerDisable = 1,
};
bool mute_audio : 1;
bool disable_speaker : 1;
bool UNUSED_2 : 1;
bool UNUSED_3 : 1;
bool UNUSED_4 : 1;
bool UNUSED_5 : 1;
bool UNUSED_6 : 1;
bool UNUSED_7 : 1;
// misc_config_t bits:
// ConfigAudioMute = set to mute all audio output (speakers & headphones)
// ConfigSpeakerDisable = set to disable only the speaker and leave headphones enabled (only supported on AK4951 codec)
uint32_t values;
constexpr bool bit_read(const bits_t n) const {
return ((values >> n) & 1) != 0;
}
constexpr void bit_write(const bits_t n, const bool v) {
if (bit_read(n) != v) {
values ^= 1 << n;
}
}
public:
constexpr bool config_audio_mute() const {
return bit_read(bits_t::ConfigAudioMute);
}
constexpr void set_config_audio_mute(bool v) {
bit_write(bits_t::ConfigAudioMute, v);
}
constexpr bool config_speaker_disable() const {
return bit_read(bits_t::ConfigSpeakerDisable);
}
constexpr void set_config_speaker_disable(bool v) {
bit_write(bits_t::ConfigSpeakerDisable, v);
}
constexpr misc_config_t()
: values(0) {
}
uint8_t PLACEHOLDER_1;
uint8_t PLACEHOLDER_2;
uint8_t PLACEHOLDER_3;
};
static_assert(sizeof(misc_config_t) == sizeof(uint32_t));
/* IMPORTANT: Report your changes here in the dump_persistent_memory function a few lines later !! */
/* IMPORTANT: Update dump_persistent_memory (below) when changing data_t. */
/* Struct must pack the same way on M4 and M0 cores.
* NB: When adding new members, keep 32bit-aligned.*/
/* struct must pack the same way on M4 and M0 cores. */
struct data_t {
data_structure_version_enum structure_version;
int64_t target_frequency;
int32_t correction_ppb;
uint32_t touch_calibration_magic;
touch::Calibration touch_calibration;
touch::Calibration touch_calibration; // 7 * 32 bits.
// Modem
uint32_t modem_def_index;
@@ -337,7 +176,7 @@ struct data_t {
int32_t modem_baudrate;
int32_t modem_repeat;
// Play dead unlock
// Play dead unlock (Used?)
uint32_t playdead_magic;
uint32_t playing_dead;
uint32_t playdead_sequence;
@@ -356,26 +195,30 @@ struct data_t {
// Recon App
uint64_t recon_config;
bool placeholder_0;
// enable or disable converter
bool converter;
// set up converter (false) or down converter (true) converter
bool updown_converter;
bool updown_frequency_rx_correction;
bool updown_frequency_tx_correction;
bool UNUSED_4 : 1;
bool UNUSED_5 : 1;
bool UNUSED_6 : 1;
bool UNUSED_7 : 1;
// up/down converter offset
int64_t converter_frequency_offset;
// frequency correction
uint32_t frequency_rx_correction;
bool updown_frequency_rx_correction;
uint32_t frequency_tx_correction;
bool updown_frequency_tx_correction;
// Rotary encoder dial sensitivity (encoder.cpp/hpp)
uint8_t encoder_dial_sensitivity;
uint16_t encoder_dial_sensitivity : 4;
uint16_t UNUSED_8 : 12;
// Headphone volume in centibels. (Only really needs 10 bits)
int32_t headphone_volume_cb;
// Headphone volume in centibels.
int16_t headphone_volume_cb;
// Misc flags
misc_config_t misc_config;
@@ -411,15 +254,23 @@ struct data_t {
hardware_config(0),
recon_config(0),
placeholder_0(0),
converter(0),
updown_converter(0),
converter(false),
updown_converter(false),
updown_frequency_rx_correction(false),
updown_frequency_tx_correction(false),
UNUSED_4(false),
UNUSED_5(false),
UNUSED_6(false),
UNUSED_7(false),
converter_frequency_offset(0),
frequency_rx_correction(0),
updown_frequency_rx_correction(0),
frequency_tx_correction(0),
updown_frequency_tx_correction(0),
encoder_dial_sensitivity(0),
UNUSED_8(0),
headphone_volume_cb(-600),
misc_config(),
ui_config2() {
@@ -510,7 +361,10 @@ namespace cache {
void defaults() {
cached_backup_ram = backup_ram_t();
// defaults values for recon app
set_config_backlight_timer(backlight_config_t{});
set_config_splash(true);
// Default values for recon app.
set_recon_autosave_freqs(false);
set_recon_autostart_recon(true);
set_recon_continuous(true);
@@ -626,14 +480,16 @@ void set_modem_baudrate(const int32_t new_value) {
data->modem_baudrate = modem_baudrate_range.clip(new_value);
}
/*int32_t modem_bw() {
modem_bw_range.reset_if_outside(data->modem_bw, modem_bw_reset_value);
return data->modem_bw;
}
/*
int32_t modem_bw() {
modem_bw_range.reset_if_outside(data->modem_bw, modem_bw_reset_value);
return data->modem_bw;
}
void set_modem_bw(const int32_t new_value) {
data->modem_bw = modem_bw_range.clip(new_value);
}*/
void set_modem_bw(const int32_t new_value) {
data->modem_bw = modem_bw_range.clip(new_value);
}
*/
uint8_t modem_repeat() {
modem_repeat_range.reset_if_outside(data->modem_repeat, modem_repeat_reset_value);
@@ -652,56 +508,56 @@ void set_serial_format(const serial_format_t new_value) {
data->serial_format = new_value;
}
bool show_gui_return_icon() { // add return icon in touchscreen menue
return data->ui_config.show_gui_return_icon();
bool show_gui_return_icon() { // add return icon in touchscreen menu
return data->ui_config.show_gui_return_icon != 0;
}
bool load_app_settings() { // load (last saved) app settings on startup of app
return data->ui_config.load_app_settings();
return data->ui_config.load_app_settings != 0;
}
bool save_app_settings() { // save app settings when closing app
return data->ui_config.save_app_settings();
return data->ui_config.save_app_settings != 0;
}
bool show_bigger_qr_code() { // show bigger QR code
return data->ui_config.show_bigger_qr_code();
return data->ui_config.show_large_qr_code != 0;
}
bool disable_touchscreen() { // Option to disable touch screen
return data->ui_config.disable_touchscreen();
return data->ui_config.disable_touchscreen;
}
bool hide_clock() { // clock hidden from main menu
return data->ui_config.hide_clock();
bool hide_clock() { // Hide clock from main menu
return data->ui_config.hide_clock;
}
bool clock_with_date() { // show clock with date, if not hidden
return data->ui_config.clock_with_date();
bool clock_with_date() { // Show clock with date, if not hidden
return data->ui_config.clock_show_date;
}
bool clkout_enabled() {
return data->ui_config.clkout_enabled();
return data->ui_config.clkout_enabled;
}
bool config_audio_mute() {
return data->misc_config.config_audio_mute();
return data->misc_config.mute_audio;
}
bool config_speaker_disable() {
return data->misc_config.config_speaker_disable();
return data->misc_config.disable_speaker;
}
bool stealth_mode() {
return data->ui_config.stealth_mode();
return data->ui_config.stealth_mode;
}
bool config_login() {
return data->ui_config.config_login();
return data->ui_config.config_login;
}
bool config_splash() {
return data->ui_config.config_splash();
return data->ui_config.config_splash;
}
uint8_t config_cpld() {
@@ -709,59 +565,60 @@ uint8_t config_cpld() {
}
backlight_config_t config_backlight_timer() {
return data->ui_config.config_backlight_timer();
return {static_cast<backlight_timeout_t>(data->ui_config.backlight_timeout),
data->ui_config.enable_backlight_timeout == 1};
}
void set_gui_return_icon(bool v) {
data->ui_config.set_gui_return_icon(v);
data->ui_config.show_gui_return_icon = v ? 1 : 0;
}
void set_load_app_settings(bool v) {
data->ui_config.set_load_app_settings(v);
data->ui_config.load_app_settings = v ? 1 : 0;
}
void set_save_app_settings(bool v) {
data->ui_config.set_save_app_settings(v);
data->ui_config.save_app_settings = v ? 1 : 0;
}
void set_show_bigger_qr_code(bool v) {
data->ui_config.set_show_bigger_qr_code(v);
data->ui_config.show_large_qr_code = v ? 1 : 0;
}
void set_disable_touchscreen(bool v) {
data->ui_config.set_disable_touchscreen(v);
data->ui_config.disable_touchscreen = v;
}
void set_clock_hidden(bool v) {
data->ui_config.set_clock_hidden(v);
data->ui_config.hide_clock = v;
}
void set_clock_with_date(bool v) {
data->ui_config.set_clock_with_date(v);
data->ui_config.clock_show_date = v;
}
void set_clkout_enabled(bool v) {
data->ui_config.set_clkout_enabled(v);
data->ui_config.clkout_enabled = v;
}
void set_config_audio_mute(bool v) {
data->misc_config.set_config_audio_mute(v);
data->misc_config.mute_audio = v;
}
void set_config_speaker_disable(bool v) {
data->misc_config.set_config_speaker_disable(v);
data->misc_config.disable_speaker = v;
}
void set_stealth_mode(bool v) {
data->ui_config.set_stealth_mode(v);
data->ui_config.stealth_mode = v;
}
void set_config_login(bool v) {
data->ui_config.set_config_login(v);
data->ui_config.config_login = v;
}
void set_config_splash(bool v) {
data->ui_config.set_config_splash(v);
data->ui_config.config_splash = v;
}
void set_config_cpld(uint8_t i) {
@@ -769,7 +626,8 @@ void set_config_cpld(uint8_t i) {
}
void set_config_backlight_timer(const backlight_config_t& new_value) {
data->ui_config.set_config_backlight_timer(new_value);
data->ui_config.backlight_timeout = static_cast<uint8_t>(new_value.timeout_enum());
data->ui_config.enable_backlight_timeout = static_cast<uint8_t>(new_value.timeout_enabled());
}
uint32_t pocsag_last_address() {
@@ -788,12 +646,17 @@ void set_pocsag_ignore_address(uint32_t address) {
data->pocsag_ignore_address = address;
}
uint32_t clkout_freq() {
return data->ui_config.clkout_freq();
uint16_t clkout_freq() {
auto freq = data->ui_config.clkout_freq;
if (freq < clkout_freq_range.minimum || freq > clkout_freq_range.maximum)
set_clkout_freq(clkout_freq_reset_value);
return data->ui_config.clkout_freq;
}
void set_clkout_freq(uint32_t freq) {
data->ui_config.set_clkout_freq(freq);
void set_clkout_freq(uint16_t freq) {
data->ui_config.clkout_freq = freq;
}
/* Recon app */
@@ -982,26 +845,23 @@ bool should_use_sdcard_for_pmem() {
}
int save_persistent_settings_to_file() {
std::string filename = PMEM_SETTING_FILE;
delete_file(filename);
File outfile;
auto result = outfile.create(filename);
if (result.is_valid()) {
auto error = outfile.create(PMEM_SETTING_FILE);
if (error)
return false;
}
outfile.write(reinterpret_cast<char*>(&cached_backup_ram), sizeof(backup_ram_t));
return true;
}
int load_persistent_settings_from_file() {
std::string filename = PMEM_SETTING_FILE;
File infile;
auto result = infile.open(filename);
if (!result.is_valid()) {
infile.read(reinterpret_cast<char*>(&cached_backup_ram), sizeof(backup_ram_t));
return true;
}
return false;
auto error = infile.open(PMEM_SETTING_FILE);
if (error)
return false;
infile.read(reinterpret_cast<char*>(&cached_backup_ram), sizeof(backup_ram_t));
return true;
}
// Pmem size helper
@@ -1057,33 +917,37 @@ bool debug_dump() {
pmem_dump_file.write_line("tone_mix: " + to_string_dec_uint(data->tone_mix));
pmem_dump_file.write_line("hardware_config: " + to_string_dec_uint(data->hardware_config));
pmem_dump_file.write_line("recon_config: 0x" + to_string_hex(data->recon_config, 16));
pmem_dump_file.write_line("placeholder_0: " + to_string_dec_int(data->placeholder_0));
pmem_dump_file.write_line("converter: " + to_string_dec_int(data->converter));
pmem_dump_file.write_line("updown_converter: " + to_string_dec_int(data->updown_converter));
pmem_dump_file.write_line("updown_frequency_rx_correction: " + to_string_dec_int(data->updown_frequency_rx_correction));
pmem_dump_file.write_line("updown_frequency_tx_correction: " + to_string_dec_int(data->updown_frequency_tx_correction));
// pmem_dump_file.write_line("UNUSED_4: " + to_string_dec_int(data->UNUSED_4));
// pmem_dump_file.write_line("UNUSED_5: " + to_string_dec_int(data->UNUSED_5));
// pmem_dump_file.write_line("UNUSED_6: " + to_string_dec_int(data->UNUSED_6));
// pmem_dump_file.write_line("UNUSED_7: " + to_string_dec_int(data->UNUSED_7));
pmem_dump_file.write_line("converter_frequency_offset: " + to_string_dec_int(data->converter_frequency_offset));
pmem_dump_file.write_line("frequency_rx_correction: " + to_string_dec_uint(data->frequency_rx_correction));
pmem_dump_file.write_line("updown_frequency_rx_correction: " + to_string_dec_int(data->updown_frequency_rx_correction));
pmem_dump_file.write_line("frequency_tx_correction: " + to_string_dec_uint(data->frequency_tx_correction));
pmem_dump_file.write_line("updown_frequency_tx_correction: " + to_string_dec_int(data->updown_frequency_tx_correction));
pmem_dump_file.write_line("encoder_dial_sensitivity: " + to_string_dec_uint(data->encoder_dial_sensitivity));
// pmem_dump_file.write_line("UNUSED_8: " + to_string_dec_uint(data->UNUSED_8));
pmem_dump_file.write_line("headphone_volume_cb: " + to_string_dec_int(data->headphone_volume_cb));
// ui_config bits
const auto backlight_timer = portapack::persistent_memory::config_backlight_timer();
pmem_dump_file.write_line("ui_config clkout_freq: " + to_string_dec_uint(clkout_freq()));
pmem_dump_file.write_line("ui_config backlight_timer.timeout_enabled: " + to_string_dec_uint(backlight_timer.timeout_enabled()));
pmem_dump_file.write_line("ui_config backlight_timer.timeout_seconds: " + to_string_dec_uint(backlight_timer.timeout_seconds()));
pmem_dump_file.write_line("ui_config clkout_freq: " + to_string_dec_uint(clkout_freq()));
pmem_dump_file.write_line("ui_config show_gui_return_icon: " + to_string_dec_uint(data->ui_config.show_gui_return_icon()));
pmem_dump_file.write_line("ui_config load_app_settings: " + to_string_dec_uint(data->ui_config.load_app_settings()));
pmem_dump_file.write_line("ui_config save_app_settings: " + to_string_dec_uint(data->ui_config.save_app_settings()));
pmem_dump_file.write_line("ui_config show_bigger_qr_code: " + to_string_dec_uint(data->ui_config.show_bigger_qr_code()));
pmem_dump_file.write_line("ui_config disable_touchscreen: " + to_string_dec_uint(data->ui_config.disable_touchscreen()));
pmem_dump_file.write_line("ui_config hide_clock: " + to_string_dec_uint(data->ui_config.hide_clock()));
pmem_dump_file.write_line("ui_config clock_with_date: " + to_string_dec_uint(data->ui_config.clock_with_date()));
pmem_dump_file.write_line("ui_config clkout_enabled: " + to_string_dec_uint(data->ui_config.clkout_enabled()));
pmem_dump_file.write_line("ui_config stealth_mode: " + to_string_dec_uint(data->ui_config.stealth_mode()));
pmem_dump_file.write_line("ui_config config_login: " + to_string_dec_uint(data->ui_config.config_login()));
pmem_dump_file.write_line("ui_config config_splash: " + to_string_dec_uint(data->ui_config.config_splash()));
pmem_dump_file.write_line("ui_config show_gui_return_icon: " + to_string_dec_uint(data->ui_config.show_gui_return_icon));
pmem_dump_file.write_line("ui_config load_app_settings: " + to_string_dec_uint(data->ui_config.load_app_settings));
pmem_dump_file.write_line("ui_config save_app_settings: " + to_string_dec_uint(data->ui_config.save_app_settings));
pmem_dump_file.write_line("ui_config show_bigger_qr_code: " + to_string_dec_uint(data->ui_config.show_large_qr_code));
pmem_dump_file.write_line("ui_config disable_touchscreen: " + to_string_dec_uint(data->ui_config.disable_touchscreen));
pmem_dump_file.write_line("ui_config hide_clock: " + to_string_dec_uint(data->ui_config.hide_clock));
pmem_dump_file.write_line("ui_config clock_with_date: " + to_string_dec_uint(data->ui_config.clock_show_date));
pmem_dump_file.write_line("ui_config clkout_enabled: " + to_string_dec_uint(data->ui_config.clkout_enabled));
pmem_dump_file.write_line("ui_config stealth_mode: " + to_string_dec_uint(data->ui_config.stealth_mode));
pmem_dump_file.write_line("ui_config config_login: " + to_string_dec_uint(data->ui_config.config_login));
pmem_dump_file.write_line("ui_config config_splash: " + to_string_dec_uint(data->ui_config.config_splash));
// ui_config2 bits
pmem_dump_file.write_line("ui_config2 hide_speaker: " + to_string_dec_uint(data->ui_config2.hide_speaker));
@@ -1137,8 +1001,6 @@ bool debug_dump() {
// 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("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("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()));
@@ -34,9 +34,10 @@
#include "volume.hpp"
// persistant memory from/to sdcard flag file
#define PMEM_FILEFLAG "/SETTINGS/PMEM_FILEFLAG"
#define PMEM_FILEFLAG u"/SETTINGS/PMEM_FILEFLAG"
// persistant memory from/to sdcard flag file
#define PMEM_SETTING_FILE "/SETTINGS/pmem_settings"
#define PMEM_SETTING_FILE u"/SETTINGS/pmem_settings"
using namespace modems;
using namespace serializer;
@@ -225,8 +226,8 @@ void set_pocsag_ignore_address(uint32_t address);
bool clkout_enabled();
void set_clkout_enabled(bool v);
uint32_t clkout_freq();
void set_clkout_freq(uint32_t freq);
uint16_t clkout_freq();
void set_clkout_freq(uint16_t freq);
/* Recon app */
bool recon_autosave_freqs();
+18
View File
@@ -1524,6 +1524,24 @@ void OptionsField::set_by_value(value_t v) {
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) {
options = new_options;
+1
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_by_value(value_t v);
void set_by_nearest_value(value_t v);
void paint(Painter& painter) override;