Compare commits

...

10 Commits

Author SHA1 Message Date
Mark Thompson a60f4ce9a8 Add SPLASH folder to SD Card (#1247)
* Add SPLASH folder and README file

* Sample splash screen files
2023-07-06 23:02:58 +02:00
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
55 changed files with 1007 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;
+15
View File
@@ -0,0 +1,15 @@
Splash screen images files must be 24-bit BMP files of size 240x304 or 240x300 pixels.
The current splash screen image is the one stored in the root directory of the SD card
and named "splash.bmp". Images stored in the SPLASH folder can be made the current
splash image by clicking on the BMP file in File Manager to view it, and then pressing
the Right button (this will cause the file to be copied to the root folder and renamed
"splash.bmp", overwriting any existing "splash.bmp" file in that location). In order
for the current splash screen to appear at power up, the "Show splash screen" option
must also be enabled under Settings->UserInterface.
For more information on Splash Screens, see the following Wiki pages:
https://github.com/eried/portapack-mayhem/wiki/Create-a-custom-splash-screen
https://github.com/eried/portapack-mayhem/wiki/File-manager
Many additional Mayhem splash screens that users have shared online may be found in
the Mayhem #splash-screens channel on Discord.
Binary file not shown.

After

Width:  |  Height:  |  Size: 214 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 211 KiB