mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2025-01-09 14:53:38 +00:00
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
This commit is contained in:
parent
6177b08632
commit
c078bac0e7
@ -35,6 +35,11 @@ using portapack::memory::map::backup_ram;
|
|||||||
|
|
||||||
namespace ui {
|
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() {
|
void LevelView::m4_manage_stat_update() {
|
||||||
if (audio_mode) {
|
if (audio_mode) {
|
||||||
if (radio_mode == WFM_MODULATION || radio_mode == SPEC_MODULATION) {
|
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) {
|
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
|
// refresh sat
|
||||||
|
@ -56,6 +56,7 @@ class LevelView : public View {
|
|||||||
|
|
||||||
RxRadioState radio_state_{};
|
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);
|
size_t change_mode(freqman_index_t mod_type);
|
||||||
void on_statistics_update(const ChannelStatistics& statistics);
|
void on_statistics_update(const ChannelStatistics& statistics);
|
||||||
void set_display_freq(int64_t freq);
|
void set_display_freq(int64_t freq);
|
||||||
@ -128,7 +129,7 @@ class LevelView : public View {
|
|||||||
NumberField field_beep_squelch{
|
NumberField field_beep_squelch{
|
||||||
{25 * 8, 3 * 16 + 4},
|
{25 * 8, 3 * 16 + 4},
|
||||||
4,
|
4,
|
||||||
{-120, 12},
|
{-100, 20},
|
||||||
1,
|
1,
|
||||||
' ',
|
' ',
|
||||||
};
|
};
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#include "convert.hpp"
|
#include "convert.hpp"
|
||||||
#include "file_reader.hpp"
|
#include "file_reader.hpp"
|
||||||
#include "string_format.hpp"
|
#include "string_format.hpp"
|
||||||
|
#include "audio.hpp"
|
||||||
|
|
||||||
using namespace portapack;
|
using namespace portapack;
|
||||||
|
|
||||||
@ -34,11 +35,39 @@ void GlassView::focus() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
GlassView::~GlassView() {
|
GlassView::~GlassView() {
|
||||||
|
audio::output::stop();
|
||||||
receiver_model.set_sampling_rate(3072000); // Just a hack to avoid hanging other apps
|
receiver_model.set_sampling_rate(3072000); // Just a hack to avoid hanging other apps
|
||||||
receiver_model.disable();
|
receiver_model.disable();
|
||||||
baseband::shutdown();
|
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);
|
||||||
|
// <bip:-XXXdb>
|
||||||
|
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) {
|
void GlassView::get_max_power(const ChannelSpectrum& spectrum, uint8_t bin, uint8_t& max_power) {
|
||||||
if (mode == LOOKING_GLASS_SINGLEPASS) {
|
if (mode == LOOKING_GLASS_SINGLEPASS) {
|
||||||
// <20MHz spectrum mode
|
// <20MHz spectrum mode
|
||||||
@ -173,6 +202,8 @@ void GlassView::on_channel_spectrum(const ChannelSpectrum& spectrum) {
|
|||||||
// we actually need SCREEN_W (240) of those bins
|
// we actually need SCREEN_W (240) of those bins
|
||||||
for (uint8_t bin = 0; bin < bin_length; bin++) {
|
for (uint8_t bin = 0; bin < bin_length; bin++) {
|
||||||
get_max_power(spectrum, bin, max_power);
|
get_max_power(spectrum, bin, max_power);
|
||||||
|
if (max_power > range_max_power)
|
||||||
|
range_max_power = max_power;
|
||||||
// process dc spike if enable
|
// process dc spike if enable
|
||||||
if (bin == 119) {
|
if (bin == 119) {
|
||||||
uint8_t next_max_power = 0;
|
uint8_t next_max_power = 0;
|
||||||
@ -184,14 +215,21 @@ void GlassView::on_channel_spectrum(const ChannelSpectrum& spectrum) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// process actual bin
|
// 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
|
return; // new line signaled, return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (mode != LOOKING_GLASS_SINGLEPASS) {
|
if (mode != LOOKING_GLASS_SINGLEPASS) {
|
||||||
f_center += looking_glass_step;
|
f_center += looking_glass_step;
|
||||||
retune();
|
retune();
|
||||||
} else
|
} else {
|
||||||
baseband::spectrum_streaming_start();
|
baseband::spectrum_streaming_start();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GlassView::on_hide() {
|
void GlassView::on_hide() {
|
||||||
@ -327,13 +365,15 @@ GlassView::GlassView(
|
|||||||
&field_lna,
|
&field_lna,
|
||||||
&field_vga,
|
&field_vga,
|
||||||
&field_range,
|
&field_range,
|
||||||
&steps_config,
|
//&steps_config,
|
||||||
&scan_type,
|
&scan_type,
|
||||||
&view_config,
|
&view_config,
|
||||||
&level_integration,
|
&level_integration,
|
||||||
|
&field_volume,
|
||||||
&filter_config,
|
&filter_config,
|
||||||
&field_rf_amp,
|
&field_rf_amp,
|
||||||
&range_presets,
|
&range_presets,
|
||||||
|
&button_beep_squelch,
|
||||||
&field_marker,
|
&field_marker,
|
||||||
&field_trigger,
|
&field_trigger,
|
||||||
&button_jump,
|
&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_min.set_step(v);
|
||||||
field_frequency_max.set_step(v);
|
field_frequency_max.set_step(v);
|
||||||
steps = 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) {
|
scan_type.on_change = [this](size_t, OptionsField::value_t v) {
|
||||||
mode = 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_baseband_bandwidth(looking_glass_bandwidth); // possible values: 1.75/2.5/3.5/5/5.5/6/7/8/9/10/12/14/15/20/24/28MHz
|
||||||
receiver_model.set_squelch_level(0);
|
receiver_model.set_squelch_level(0);
|
||||||
receiver_model.enable();
|
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
|
uint8_t GlassView::get_spec_iq_phase_calibration_value() { // define accessor functions inside AnalogAudioView to read & write real iq_phase_calibration_value
|
||||||
|
@ -85,6 +85,8 @@ class GlassView : public View {
|
|||||||
uint8_t live_frequency_view = 0; // Spectrum
|
uint8_t live_frequency_view = 0; // Spectrum
|
||||||
uint8_t live_frequency_integrate = 3; // Default (3 * old value + new_value) / 4
|
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
|
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_{
|
app_settings::SettingsManager settings_{
|
||||||
"rx_glass"sv,
|
"rx_glass"sv,
|
||||||
app_settings::Mode::RX,
|
app_settings::Mode::RX,
|
||||||
@ -98,6 +100,8 @@ class GlassView : public View {
|
|||||||
{"freq_view"sv, &live_frequency_view},
|
{"freq_view"sv, &live_frequency_view},
|
||||||
{"freq_integrate"sv, &live_frequency_integrate},
|
{"freq_integrate"sv, &live_frequency_integrate},
|
||||||
{"iq_phase_calibration"sv, &iq_phase_calibration_value}, // we are saving and restoring that CAL from Settings.
|
{"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 {
|
struct preset_entry {
|
||||||
@ -106,7 +110,10 @@ class GlassView : public View {
|
|||||||
std::string label{};
|
std::string label{};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
int32_t map(int32_t value, int32_t fromLow, int32_t fromHigh, int32_t toLow, int32_t toHigh);
|
||||||
std::vector<preset_entry> presets_db{};
|
std::vector<preset_entry> presets_db{};
|
||||||
|
void manage_beep_audio();
|
||||||
|
void update_display_beep();
|
||||||
void update_min(int32_t v);
|
void update_min(int32_t v);
|
||||||
void update_max(int32_t v);
|
void update_max(int32_t v);
|
||||||
void update_range_field();
|
void update_range_field();
|
||||||
@ -153,6 +160,8 @@ class GlassView : public View {
|
|||||||
int32_t steps = 1;
|
int32_t steps = 1;
|
||||||
bool locked_range = false;
|
bool locked_range = false;
|
||||||
|
|
||||||
|
uint8_t range_max_power = 0;
|
||||||
|
uint8_t range_max_power_counter = 0;
|
||||||
uint8_t max_power = 0;
|
uint8_t max_power = 0;
|
||||||
rf::Frequency max_freq_hold = 0;
|
rf::Frequency max_freq_hold = 0;
|
||||||
rf::Frequency last_max_freq = 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, 1 * 16}, "RANGE: FILTER: AMP:", Color::light_grey()},
|
||||||
{{0, 2 * 16}, "PRESET:", Color::light_grey()},
|
{{0, 2 * 16}, "PRESET:", Color::light_grey()},
|
||||||
{{0, 3 * 16}, "MARKER: MHz RXIQCAL", 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{
|
NumberField field_frequency_min{
|
||||||
{4 * 8, 0 * 16},
|
{4 * 8, 0 * 16},
|
||||||
@ -206,9 +216,13 @@ class GlassView : public View {
|
|||||||
|
|
||||||
OptionsField range_presets{
|
OptionsField range_presets{
|
||||||
{7 * 8, 2 * 16},
|
{7 * 8, 2 * 16},
|
||||||
20,
|
10,
|
||||||
{}};
|
{}};
|
||||||
|
|
||||||
|
ButtonWithEncoder button_beep_squelch{
|
||||||
|
{18 * 8, 2 * 16 + 4, 12 * 8, 1 * 8},
|
||||||
|
""};
|
||||||
|
|
||||||
TextField field_marker{
|
TextField field_marker{
|
||||||
{7 * 8, 3 * 16, 9 * 8, 16},
|
{7 * 8, 3 * 16, 9 * 8, 16},
|
||||||
""};
|
""};
|
||||||
@ -228,7 +242,10 @@ class GlassView : public View {
|
|||||||
2,
|
2,
|
||||||
' '};
|
' '};
|
||||||
|
|
||||||
OptionsField steps_config{
|
AudioVolumeField field_volume{
|
||||||
|
{13 * 8, 4 * 16}};
|
||||||
|
|
||||||
|
/*OptionsField steps_config{
|
||||||
{13 * 8, 4 * 16},
|
{13 * 8, 4 * 16},
|
||||||
3,
|
3,
|
||||||
{
|
{
|
||||||
@ -238,7 +255,7 @@ class GlassView : public View {
|
|||||||
{"100", 100},
|
{"100", 100},
|
||||||
{"250", 250},
|
{"250", 250},
|
||||||
{"500", 500},
|
{"500", 500},
|
||||||
}};
|
}};*/
|
||||||
|
|
||||||
OptionsField scan_type{
|
OptionsField scan_type{
|
||||||
{17 * 8, 4 * 16},
|
{17 * 8, 4 * 16},
|
||||||
|
@ -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) {
|
void WidebandSpectrum::on_message(const Message* const msg) {
|
||||||
|
switch (msg->id) {
|
||||||
|
case Message::ID::RequestSignal:
|
||||||
|
on_signal_message(*reinterpret_cast<const RequestSignalMessage*>(msg));
|
||||||
|
return;
|
||||||
|
|
||||||
|
case Message::ID::AudioBeep:
|
||||||
|
on_beep_message(*reinterpret_cast<const AudioBeepMessage*>(msg));
|
||||||
|
return;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
const WidebandSpectrumConfigMessage message = *reinterpret_cast<const WidebandSpectrumConfigMessage*>(msg);
|
const WidebandSpectrumConfigMessage message = *reinterpret_cast<const WidebandSpectrumConfigMessage*>(msg);
|
||||||
|
|
||||||
switch (msg->id) {
|
switch (msg->id) {
|
||||||
@ -84,7 +107,6 @@ void WidebandSpectrum::on_message(const Message* const msg) {
|
|||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
audio::dma::init_audio_out(); // for AudioRX app (enables audio output while this baseband image is running)
|
audio::dma::init_audio_out(); // for AudioRX app (enables audio output while this baseband image is running)
|
||||||
|
|
||||||
EventDispatcher event_dispatcher{std::make_unique<WidebandSpectrum>()};
|
EventDispatcher event_dispatcher{std::make_unique<WidebandSpectrum>()};
|
||||||
event_dispatcher.run();
|
event_dispatcher.run();
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -43,6 +43,9 @@ class WidebandSpectrum : public BasebandProcessor {
|
|||||||
bool configured = false;
|
bool configured = false;
|
||||||
size_t baseband_fs = 20000000;
|
size_t baseband_fs = 20000000;
|
||||||
|
|
||||||
|
void on_beep_message(const AudioBeepMessage& message);
|
||||||
|
void on_signal_message(const RequestSignalMessage& message);
|
||||||
|
|
||||||
SpectrumCollector channel_spectrum{};
|
SpectrumCollector channel_spectrum{};
|
||||||
|
|
||||||
std::array<complex16_t, 256> spectrum{};
|
std::array<complex16_t, 256> spectrum{};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user