From c078bac0e7d3e2ed6e61ce167a54bc01b849fda6 Mon Sep 17 00:00:00 2001 From: gullradriel <3157857+gullradriel@users.noreply.github.com> Date: Sun, 24 Mar 2024 22:32:13 +0100 Subject: [PATCH] Looking glass beep (#2036) * first draft of looking beep * fixed beep squelch range in percent * took out steps * gui adjustements * uniformize calculation and beep squelch in db * uniformisation, fix 24/48 error --- firmware/application/apps/ui_level.cpp | 7 +- firmware/application/apps/ui_level.hpp | 3 +- .../application/apps/ui_looking_glass_app.cpp | 71 +++++++++++++++++-- .../application/apps/ui_looking_glass_app.hpp | 25 +++++-- firmware/baseband/proc_wideband_spectrum.cpp | 24 ++++++- firmware/baseband/proc_wideband_spectrum.hpp | 3 + 6 files changed, 121 insertions(+), 12 deletions(-) diff --git a/firmware/application/apps/ui_level.cpp b/firmware/application/apps/ui_level.cpp index 3922d9d0..62bf6865 100644 --- a/firmware/application/apps/ui_level.cpp +++ b/firmware/application/apps/ui_level.cpp @@ -35,6 +35,11 @@ using portapack::memory::map::backup_ram; namespace ui { +// Function to map the value from one range to another +int32_t LevelView::map(int32_t value, int32_t fromLow, int32_t fromHigh, int32_t toLow, int32_t toHigh) { + return toLow + (value - fromLow) * (toHigh - toLow) / (fromHigh - fromLow); +} + void LevelView::m4_manage_stat_update() { if (audio_mode) { if (radio_mode == WFM_MODULATION || radio_mode == SPEC_MODULATION) { @@ -192,7 +197,7 @@ void LevelView::on_statistics_update(const ChannelStatistics& statistics) { } if (beep && statistics.max_db > beep_squelch) { - baseband::request_audio_beep(((132 + statistics.max_db) * 2000) / 120, 24000, 250); + baseband::request_audio_beep(map(statistics.max_db, -100, 20, 400, 2600), 24000, 150); } // refresh sat diff --git a/firmware/application/apps/ui_level.hpp b/firmware/application/apps/ui_level.hpp index 51bfc5c6..3ce79bfa 100644 --- a/firmware/application/apps/ui_level.hpp +++ b/firmware/application/apps/ui_level.hpp @@ -56,6 +56,7 @@ class LevelView : public View { RxRadioState radio_state_{}; + int32_t map(int32_t value, int32_t fromLow, int32_t fromHigh, int32_t toLow, int32_t toHigh); size_t change_mode(freqman_index_t mod_type); void on_statistics_update(const ChannelStatistics& statistics); void set_display_freq(int64_t freq); @@ -128,7 +129,7 @@ class LevelView : public View { NumberField field_beep_squelch{ {25 * 8, 3 * 16 + 4}, 4, - {-120, 12}, + {-100, 20}, 1, ' ', }; diff --git a/firmware/application/apps/ui_looking_glass_app.cpp b/firmware/application/apps/ui_looking_glass_app.cpp index 62a2b03a..0f2f8aa8 100644 --- a/firmware/application/apps/ui_looking_glass_app.cpp +++ b/firmware/application/apps/ui_looking_glass_app.cpp @@ -25,6 +25,7 @@ #include "convert.hpp" #include "file_reader.hpp" #include "string_format.hpp" +#include "audio.hpp" using namespace portapack; @@ -34,11 +35,39 @@ void GlassView::focus() { } GlassView::~GlassView() { + audio::output::stop(); receiver_model.set_sampling_rate(3072000); // Just a hack to avoid hanging other apps receiver_model.disable(); baseband::shutdown(); } +// Function to map the value from one range to another +int32_t GlassView::map(int32_t value, int32_t fromLow, int32_t fromHigh, int32_t toLow, int32_t toHigh) { + return toLow + (value - fromLow) * (toHigh - toLow) / (fromHigh - fromLow); +} + +void GlassView::update_display_beep() { + if (beep_enabled) { + button_beep_squelch.set_style(&Styles::green); + // + button_beep_squelch.set_text("[bip>" + to_string_dec_int(beep_squelch, 4) + "db]"); + receiver_model.set_headphone_volume(receiver_model.headphone_volume()); // WM8731 hack. + } else { + button_beep_squelch.set_style(&Styles::white); + button_beep_squelch.set_text("[ beep OFF ["); + } +} + +void GlassView::manage_beep_audio() { + if (beep_enabled) { + audio::set_rate(audio::Rate::Hz_24000); + audio::output::start(); + } else { + baseband::request_beep_stop(); + audio::output::stop(); + } +} + void GlassView::get_max_power(const ChannelSpectrum& spectrum, uint8_t bin, uint8_t& max_power) { if (mode == LOOKING_GLASS_SINGLEPASS) { // <20MHz spectrum mode @@ -173,6 +202,8 @@ void GlassView::on_channel_spectrum(const ChannelSpectrum& spectrum) { // we actually need SCREEN_W (240) of those bins for (uint8_t bin = 0; bin < bin_length; bin++) { get_max_power(spectrum, bin, max_power); + if (max_power > range_max_power) + range_max_power = max_power; // process dc spike if enable if (bin == 119) { uint8_t next_max_power = 0; @@ -184,14 +215,21 @@ void GlassView::on_channel_spectrum(const ChannelSpectrum& spectrum) { } } // process actual bin - if (process_bins(&max_power) == true) + if (process_bins(&max_power)) { + int8_t power = map(range_max_power, 0, 255, -100, 20); + if (power >= beep_squelch) { + baseband::request_audio_beep(map(range_max_power, 0, 256, 400, 2600), 24000, 250); + } + range_max_power = 0; return; // new line signaled, return + } } if (mode != LOOKING_GLASS_SINGLEPASS) { f_center += looking_glass_step; retune(); - } else + } else { baseband::spectrum_streaming_start(); + } } void GlassView::on_hide() { @@ -327,13 +365,15 @@ GlassView::GlassView( &field_lna, &field_vga, &field_range, - &steps_config, + //&steps_config, &scan_type, &view_config, &level_integration, + &field_volume, &filter_config, &field_rf_amp, &range_presets, + &button_beep_squelch, &field_marker, &field_trigger, &button_jump, @@ -370,12 +410,12 @@ GlassView::GlassView( }; }; - steps_config.on_change = [this](size_t, OptionsField::value_t v) { + /*steps_config.on_change = [this](size_t, OptionsField::value_t v) { field_frequency_min.set_step(v); field_frequency_max.set_step(v); steps = v; }; - steps_config.set_selected_index(0); // 1 Mhz step. + steps_config.set_selected_index(0); // 1 Mhz step.*/ scan_type.on_change = [this](size_t, OptionsField::value_t v) { mode = v; @@ -497,6 +537,27 @@ GlassView::GlassView( receiver_model.set_baseband_bandwidth(looking_glass_bandwidth); // possible values: 1.75/2.5/3.5/5/5.5/6/7/8/9/10/12/14/15/20/24/28MHz receiver_model.set_squelch_level(0); receiver_model.enable(); + + button_beep_squelch.on_select = [this](ButtonWithEncoder& button) { + (void)button; + beep_enabled = 1 - beep_enabled; + manage_beep_audio(); + update_display_beep(); + }; + + button_beep_squelch.on_change = [this]() { + int new_beep_squelch = beep_squelch + button_beep_squelch.get_encoder_delta(); + if (new_beep_squelch < -100) + new_beep_squelch = -100; + if (new_beep_squelch > 20) + new_beep_squelch = 20; + beep_squelch = new_beep_squelch; + button_beep_squelch.set_encoder_delta(0); + update_display_beep(); + }; + + manage_beep_audio(); + update_display_beep(); } uint8_t GlassView::get_spec_iq_phase_calibration_value() { // define accessor functions inside AnalogAudioView to read & write real iq_phase_calibration_value diff --git a/firmware/application/apps/ui_looking_glass_app.hpp b/firmware/application/apps/ui_looking_glass_app.hpp index d3052c6f..a19dd1e9 100644 --- a/firmware/application/apps/ui_looking_glass_app.hpp +++ b/firmware/application/apps/ui_looking_glass_app.hpp @@ -85,6 +85,8 @@ class GlassView : public View { uint8_t live_frequency_view = 0; // Spectrum uint8_t live_frequency_integrate = 3; // Default (3 * old value + new_value) / 4 uint8_t iq_phase_calibration_value{15}; // initial default RX IQ phase calibration value , used for both max2837 & max2839 + int32_t beep_squelch = 20; // range from -100 to +20, >=20 disabled + bool beep_enabled = false; // activate on bip button click app_settings::SettingsManager settings_{ "rx_glass"sv, app_settings::Mode::RX, @@ -98,6 +100,8 @@ class GlassView : public View { {"freq_view"sv, &live_frequency_view}, {"freq_integrate"sv, &live_frequency_integrate}, {"iq_phase_calibration"sv, &iq_phase_calibration_value}, // we are saving and restoring that CAL from Settings. + {"beep_squelch"sv, &beep_squelch}, + {"beep_enabled"sv, &beep_enabled}, }}; struct preset_entry { @@ -106,7 +110,10 @@ class GlassView : public View { std::string label{}; }; + int32_t map(int32_t value, int32_t fromLow, int32_t fromHigh, int32_t toLow, int32_t toHigh); std::vector presets_db{}; + void manage_beep_audio(); + void update_display_beep(); void update_min(int32_t v); void update_max(int32_t v); void update_range_field(); @@ -153,6 +160,8 @@ class GlassView : public View { int32_t steps = 1; bool locked_range = false; + uint8_t range_max_power = 0; + uint8_t range_max_power_counter = 0; uint8_t max_power = 0; rf::Frequency max_freq_hold = 0; rf::Frequency last_max_freq = 0; @@ -166,7 +175,8 @@ class GlassView : public View { {{0, 1 * 16}, "RANGE: FILTER: AMP:", Color::light_grey()}, {{0, 2 * 16}, "PRESET:", Color::light_grey()}, {{0, 3 * 16}, "MARKER: MHz RXIQCAL", Color::light_grey()}, - {{0, 4 * 16}, "RES: STEP:", Color::light_grey()}}; + //{{0, 4 * 16}, "RES: STEPS:", Color::light_grey()}}; + {{0, 4 * 16}, "RES: VOL:", Color::light_grey()}}; NumberField field_frequency_min{ {4 * 8, 0 * 16}, @@ -206,9 +216,13 @@ class GlassView : public View { OptionsField range_presets{ {7 * 8, 2 * 16}, - 20, + 10, {}}; + ButtonWithEncoder button_beep_squelch{ + {18 * 8, 2 * 16 + 4, 12 * 8, 1 * 8}, + ""}; + TextField field_marker{ {7 * 8, 3 * 16, 9 * 8, 16}, ""}; @@ -228,7 +242,10 @@ class GlassView : public View { 2, ' '}; - OptionsField steps_config{ + AudioVolumeField field_volume{ + {13 * 8, 4 * 16}}; + + /*OptionsField steps_config{ {13 * 8, 4 * 16}, 3, { @@ -238,7 +255,7 @@ class GlassView : public View { {"100", 100}, {"250", 250}, {"500", 500}, - }}; + }};*/ OptionsField scan_type{ {17 * 8, 4 * 16}, diff --git a/firmware/baseband/proc_wideband_spectrum.cpp b/firmware/baseband/proc_wideband_spectrum.cpp index 35aef2ee..a327caf1 100644 --- a/firmware/baseband/proc_wideband_spectrum.cpp +++ b/firmware/baseband/proc_wideband_spectrum.cpp @@ -60,7 +60,30 @@ void WidebandSpectrum::execute(const buffer_c8_t& buffer) { } } +void WidebandSpectrum::on_signal_message(const RequestSignalMessage& message) { + if (message.signal == RequestSignalMessage::Signal::BeepStopRequest) { + audio::dma::beep_stop(); + } +} + +void WidebandSpectrum::on_beep_message(const AudioBeepMessage& message) { + audio::dma::beep_start(message.freq, message.sample_rate, message.duration_ms); +} + void WidebandSpectrum::on_message(const Message* const msg) { + switch (msg->id) { + case Message::ID::RequestSignal: + on_signal_message(*reinterpret_cast(msg)); + return; + + case Message::ID::AudioBeep: + on_beep_message(*reinterpret_cast(msg)); + return; + + default: + break; + } + const WidebandSpectrumConfigMessage message = *reinterpret_cast(msg); switch (msg->id) { @@ -84,7 +107,6 @@ void WidebandSpectrum::on_message(const Message* const msg) { int main() { audio::dma::init_audio_out(); // for AudioRX app (enables audio output while this baseband image is running) - EventDispatcher event_dispatcher{std::make_unique()}; event_dispatcher.run(); return 0; diff --git a/firmware/baseband/proc_wideband_spectrum.hpp b/firmware/baseband/proc_wideband_spectrum.hpp index ed17a556..f8858fff 100644 --- a/firmware/baseband/proc_wideband_spectrum.hpp +++ b/firmware/baseband/proc_wideband_spectrum.hpp @@ -43,6 +43,9 @@ class WidebandSpectrum : public BasebandProcessor { bool configured = false; size_t baseband_fs = 20000000; + void on_beep_message(const AudioBeepMessage& message); + void on_signal_message(const RequestSignalMessage& message); + SpectrumCollector channel_spectrum{}; std::array spectrum{};