mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2026-08-18 13:44:00 +00:00
584587d814
* Updated PRALINE audio processing methods to account for potential slip in 25MHz reference clock. Moved all clocks to PLLB except for CLK0 to isolate the ADC from potential EMI and clock spills from the other clocks to CLK0. Added PLL reference to Clock ui_debug display and added debug view for PLLA and PLLB. Updated PRO menu in analog_audio_app to allow for 100Hz resolution in sample rate for finer control of samplerate debugging of crackling noise artifacts. Updated ppb method and set it for account for a potential 49 Hz shift in the PRALINE crystal. Started instatiating methods for synchronized DMA transfers for the spectrogram since the FFT calculations and the LCD data updates appear to be related to the crackling noise. * Added firmware/flash.h to .gitignore. * Changed reference clock for start_audio_pll to 40MHz instead of ~12MHz xtal. Moved clocks around to reflect best audio quality in analog_audio_app at 3.072 MHz sample frequency. * Ran format-code.sh. * Removed ppb in set_sampling_frequency since it created aliasing in analog_audio_app. * Expanded baseband_bandwidth back to 1750000 after testing since audio quality was retained. * Updated comments to address copilot recommendations where acceptable. * Removed firmware/flashsize.h from .gitignore as coordinated with @gullradriel.
376 lines
12 KiB
C++
376 lines
12 KiB
C++
/*
|
|
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
|
|
* Copyright (C) 2018 Furrtek
|
|
*
|
|
* This file is part of PortaPack.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; see the file COPYING. If not, write to
|
|
* the Free Software Foundation, Inc., 51 Franklin Street,
|
|
* Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#ifndef __ANALOG_AUDIO_APP_H__
|
|
#define __ANALOG_AUDIO_APP_H__
|
|
|
|
#include "receiver_model.hpp"
|
|
|
|
#include "ui_receiver.hpp"
|
|
#include "ui_freq_field.hpp"
|
|
#include "ui_spectrum.hpp"
|
|
#include "ui_record_view.hpp"
|
|
#include "app_settings.hpp"
|
|
#include "radio_state.hpp"
|
|
#include "tone_key.hpp"
|
|
|
|
namespace ui {
|
|
|
|
class AnalogAudioView;
|
|
|
|
#ifdef PRALINE
|
|
class PralineOptionsView : public View {
|
|
public:
|
|
PralineOptionsView(Rect parent_rect, const Style* style);
|
|
|
|
private:
|
|
// Layout: SR (Sample Rate), DC (DC Block), QI (Q-Invert), QS (Quarter Shift), D (Decim)
|
|
Text label_sr{{UI_POS_X(0), UI_POS_Y(0), UI_POS_WIDTH(2), UI_POS_HEIGHT(1)}, "SR"};
|
|
|
|
// Parameters: Position, Length (in chars), Range, Step, and default value
|
|
NumberField options_sr{
|
|
{UI_POS_X(3), UI_POS_Y(0)},
|
|
8, // Number of digits to show
|
|
{0, 40000000}, // Range: 0 to 40,000 kHz
|
|
100, // Step: 100 Hz
|
|
' ' // Fix: Single quotes for char
|
|
};
|
|
|
|
Text label_dc{{UI_POS_X(14), UI_POS_Y(0), UI_POS_WIDTH(2), UI_POS_HEIGHT(1)}, "DC"};
|
|
OptionsField options_dc{{UI_POS_X(16), UI_POS_Y(0)}, 2, {{"Of", 0}, {"On", 1}}};
|
|
|
|
Text label_qi{{UI_POS_X(20), UI_POS_Y(0), UI_POS_WIDTH(2), UI_POS_HEIGHT(1)}, "QI"};
|
|
OptionsField options_qi{{UI_POS_X(22), UI_POS_Y(0)}, 2, {{"Of", 0}, {"On", 1}}};
|
|
|
|
Text label_qs{{UI_POS_X(26), UI_POS_Y(0), UI_POS_WIDTH(2), UI_POS_HEIGHT(1)}, "QS"};
|
|
OptionsField options_qs{{UI_POS_X(28), UI_POS_Y(0)}, 2, {{"Of", 0}, {"On", 1}}};
|
|
|
|
uint8_t fpga_reg_1{0x00}; // Tracks DC, QI, QS bits
|
|
void update_fpga_ctrl();
|
|
};
|
|
#endif
|
|
|
|
class AMOptionsView : public View {
|
|
public:
|
|
AMOptionsView(AnalogAudioView* view, Rect parent_rect, const Style* style);
|
|
|
|
private:
|
|
Text label_config{
|
|
{UI_POS_X(0), UI_POS_Y(0), UI_POS_WIDTH(2), UI_POS_HEIGHT(1)},
|
|
"BW",
|
|
};
|
|
|
|
OptionsField options_config{
|
|
{UI_POS_X(3), UI_POS_Y(0)},
|
|
6, // Max option length
|
|
{
|
|
// Using common messages from freqman_ui.cpp
|
|
}};
|
|
|
|
OptionsField zoom_config{
|
|
{UI_POS_X_RIGHT(7), UI_POS_Y(0)},
|
|
7,
|
|
{{"ZOOM x1", 0},
|
|
{"ZOOM x2", 6}} // offset index AM modes array FIR filters.
|
|
};
|
|
};
|
|
|
|
class AMFMAptOptionsView : public View {
|
|
public:
|
|
AMFMAptOptionsView(AnalogAudioView* view, Rect parent_rect, const Style* style);
|
|
|
|
private:
|
|
Text label_config{
|
|
{UI_POS_X(0), UI_POS_Y(0), UI_POS_WIDTH(2), UI_POS_HEIGHT(1)},
|
|
"BW",
|
|
};
|
|
|
|
OptionsField options_config{
|
|
{UI_POS_X(3), UI_POS_Y(0)},
|
|
17, // Max option length chars "USB+FM(Wefax Apt)"
|
|
{
|
|
// Using common messages from freqman_ui.cpp In HF USB , Here we only need USB Audio demod, + post-FM demod fsubcarrier FM tone to get APT signal.
|
|
}};
|
|
|
|
OptionsField zoom_config{
|
|
{UI_POS_X_RIGHT(7), UI_POS_Y(0)},
|
|
7,
|
|
{{"ZOOM x1", 0},
|
|
{"ZOOM x2", 6}} // offset index array filters.
|
|
};
|
|
};
|
|
|
|
class NBFMOptionsView : public View {
|
|
public:
|
|
NBFMOptionsView(Rect parent_rect, const Style* style);
|
|
|
|
private:
|
|
Text label_config{
|
|
{UI_POS_X(0), UI_POS_Y(0), UI_POS_WIDTH(2), UI_POS_HEIGHT(1)},
|
|
"BW",
|
|
};
|
|
OptionsField options_config{
|
|
{UI_POS_X(3), UI_POS_Y(0)},
|
|
3, // Max option length
|
|
{
|
|
// Using common messages from freqman_ui.cpp
|
|
}};
|
|
|
|
Text text_squelch{
|
|
{UI_POS_X(7), UI_POS_Y(0), UI_POS_WIDTH(8), UI_POS_HEIGHT(1)},
|
|
"SQ /99"};
|
|
NumberField field_squelch{
|
|
{UI_POS_X(10), UI_POS_Y(0)},
|
|
2,
|
|
{0, 99},
|
|
1,
|
|
' ',
|
|
};
|
|
};
|
|
|
|
class WFMOptionsView : public View {
|
|
public:
|
|
WFMOptionsView(Rect parent_rect, const Style* style);
|
|
|
|
private:
|
|
Text label_config{
|
|
{UI_POS_X(0), UI_POS_Y(0), UI_POS_WIDTH(2), UI_POS_HEIGHT(1)},
|
|
"BW",
|
|
};
|
|
OptionsField options_config{
|
|
{UI_POS_X(3), UI_POS_Y(0)},
|
|
4, // Max option length
|
|
{
|
|
// Using common messages from freqman_ui.cpp
|
|
}};
|
|
};
|
|
|
|
class WFMAMAptOptionsView : public View {
|
|
public:
|
|
WFMAMAptOptionsView(Rect parent_rect, const Style* style);
|
|
|
|
private:
|
|
Text label_config{
|
|
{UI_POS_X(0), UI_POS_Y(0), UI_POS_WIDTH(2), UI_POS_HEIGHT(1)},
|
|
"BW",
|
|
};
|
|
OptionsField options_config{
|
|
{UI_POS_X(3), UI_POS_Y(0)},
|
|
16, // Max option char length "80k-NOAA Apt LPF" , example.
|
|
{
|
|
// Using common messages from freqman_ui.cpp
|
|
}};
|
|
};
|
|
|
|
class SPECOptionsView : public View {
|
|
public:
|
|
SPECOptionsView(AnalogAudioView* view, Rect parent_rect, const Style* style);
|
|
|
|
private:
|
|
Text label_config{
|
|
{UI_POS_X(0), UI_POS_Y(0), UI_POS_WIDTH(2), UI_POS_HEIGHT(1)},
|
|
"BW",
|
|
};
|
|
OptionsField options_config{
|
|
{UI_POS_X(3), UI_POS_Y(0)},
|
|
4,
|
|
{
|
|
{"20m ", 20000000},
|
|
{"10m ", 10000000},
|
|
{" 5m ", 5000000},
|
|
{" 2m ", 2000000},
|
|
{" 1m ", 1000000},
|
|
{"500k", 500000},
|
|
{"100k", 100000},
|
|
}};
|
|
|
|
Text text_speed{
|
|
{UI_POS_X(9), UI_POS_Y(0), UI_POS_WIDTH(8), UI_POS_HEIGHT(1)},
|
|
"SP /63"};
|
|
NumberField field_speed{
|
|
{UI_POS_X(12), UI_POS_Y(0)},
|
|
2,
|
|
{0, 63},
|
|
1,
|
|
' ',
|
|
};
|
|
Text text_rx_cal{
|
|
{UI_POS_X(19), UI_POS_Y(0), UI_POS_WIDTH(11), UI_POS_HEIGHT(1)}, // 18 (x col.) x char_size, 12 (length) x 8 blanking space to delete previous chars.
|
|
"Rx_IQ_CAL "};
|
|
NumberField field_rx_iq_phase_cal{
|
|
{screen_width - 2 * 8, UI_POS_Y(0)},
|
|
2,
|
|
{0, 63}, // 5 or 6 bits IQ CAL phase adjustment (range updated later)
|
|
1,
|
|
' ',
|
|
};
|
|
};
|
|
|
|
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;
|
|
void focus() override;
|
|
|
|
std::string title() const override { return "Audio RX"; };
|
|
|
|
size_t get_spec_bw_index();
|
|
void set_spec_bw(size_t index, uint32_t bw);
|
|
|
|
uint16_t get_spec_trigger();
|
|
void set_spec_trigger(uint16_t trigger);
|
|
|
|
uint8_t get_spec_iq_phase_calibration_value();
|
|
void set_spec_iq_phase_calibration_value(uint8_t cal_value);
|
|
|
|
uint8_t get_zoom_factor(uint8_t mode);
|
|
void set_zoom_factor(uint8_t mode, uint8_t zoom);
|
|
|
|
uint8_t get_previous_AM_mode_option();
|
|
void set_previous_AM_mode_option(uint8_t mode);
|
|
|
|
uint8_t get_previous_zoom_option();
|
|
void set_previous_zoom_option(uint8_t zoom);
|
|
|
|
#ifdef PRALINE
|
|
Button button_pro{{UI_POS_X(12), UI_POS_Y(2), UI_POS_WIDTH(3), UI_POS_HEIGHT(1)}, "PRO"};
|
|
void on_show_options_praline();
|
|
#endif
|
|
|
|
private:
|
|
static constexpr ui::Dim header_height = 3 * 16;
|
|
|
|
NavigationView& nav_;
|
|
RxRadioState radio_state_{};
|
|
uint8_t iq_phase_calibration_value{15}; // initial default RX IQ phase calibration value , used for both max2837 & max2839
|
|
uint8_t zoom_factor_am{0}; // initial zoom factor in AM mode
|
|
uint8_t zoom_factor_amfm{0}; // initial zoom factor in AMFM mode
|
|
uint8_t previous_AM_mode_option{0}; // GUI 5 AM modes : (0..4 ) (DSB9K, DSB6K, USB,LSB, CW). Used to select proper FIR filter (0..11) AM mode + offset 0 (zoom+1) or +6 (if zoom+2)
|
|
uint8_t previous_zoom{0}; // GUI ZOOM+1, ZOOM+2 , equivalent to two values offset 0 (zoom+1) or +6 (if zoom+2)
|
|
|
|
app_settings::SettingsManager settings_{
|
|
"rx_audio",
|
|
app_settings::Mode::RX,
|
|
{
|
|
{"iq_phase_calibration"sv, &iq_phase_calibration_value}, // we are saving and restoring that CAL from Settings.
|
|
{"zoom_factor_am"sv, &zoom_factor_am}, // we are saving and restoring AM ZOOM factor from Settings.
|
|
{"zoom_factor_amfm"sv, &zoom_factor_amfm}, // we are saving and restoring AMFM ZOOM factor from Settings.
|
|
{"previous_AM_mode_option"sv, &previous_AM_mode_option}, // we are saving and restoring AMFM ZOOM factor from Settings.
|
|
{"previous_zoom"sv, &previous_zoom}, // we are saving and restoring AMFM ZOOM factor from Settings.
|
|
}};
|
|
|
|
const Rect options_view_rect{UI_POS_X(0), UI_POS_Y(1), UI_POS_MAXWIDTH, UI_POS_HEIGHT(1)};
|
|
const Rect nbfm_view_rect{UI_POS_X(0), UI_POS_Y(1), UI_POS_WIDTH(18), UI_POS_HEIGHT(1)};
|
|
|
|
size_t spec_bw_index = 0;
|
|
uint32_t spec_bw = 20000000;
|
|
uint16_t spec_trigger = 63;
|
|
|
|
RSSI rssi{
|
|
{UI_POS_X(21), 0, UI_POS_WIDTH_REMAINING(21) - UI_POS_WIDTH(2), 4}};
|
|
|
|
Channel channel{
|
|
{UI_POS_X(21), 5, UI_POS_WIDTH_REMAINING(21) - UI_POS_WIDTH(2), 4}};
|
|
|
|
Audio audio{
|
|
{UI_POS_X(21), 10, UI_POS_WIDTH_REMAINING(21) - UI_POS_WIDTH(2), 4}};
|
|
|
|
RxFrequencyField field_frequency{
|
|
{UI_POS_X(5), UI_POS_Y(0)},
|
|
nav_};
|
|
|
|
LNAGainField field_lna{
|
|
{UI_POS_X(15), UI_POS_Y(0)}};
|
|
|
|
VGAGainField field_vga{
|
|
{UI_POS_X(18), UI_POS_Y(0)}};
|
|
|
|
OptionsField options_modulation{
|
|
{UI_POS_X(0), UI_POS_Y(0)},
|
|
4,
|
|
{
|
|
{" AM ", toUType(ReceiverModel::Mode::AMAudio)},
|
|
{"NFM ", toUType(ReceiverModel::Mode::NarrowbandFMAudio)},
|
|
{"WFM ", toUType(ReceiverModel::Mode::WidebandFMAudio)},
|
|
{"SPEC", toUType(ReceiverModel::Mode::SpectrumAnalysis)},
|
|
{"AMFM", toUType(ReceiverModel::Mode::AMAudioFMApt)}, // Added to handle HF WeatherFax , SSB (USB demod) + Tone_Subcarrier FM demod
|
|
{"FMAM", toUType(ReceiverModel::Mode::WFMAudioAMApt)} // Added to handle SAT NOAA APT
|
|
}};
|
|
|
|
AudioVolumeField field_volume{
|
|
{screen_width - 2 * 8, UI_POS_Y(0)}};
|
|
|
|
Text text_ctcss{
|
|
{UI_POS_X(16), UI_POS_Y(1), UI_POS_WIDTH(14), UI_POS_HEIGHT(1)},
|
|
""};
|
|
|
|
std::unique_ptr<Widget> options_widget{};
|
|
|
|
RecordView record_view{
|
|
{UI_POS_X(0), UI_POS_Y(2), UI_POS_MAXWIDTH, UI_POS_HEIGHT(1)},
|
|
u"AUD",
|
|
u"AUDIO",
|
|
RecordView::FileType::WAV,
|
|
4096,
|
|
4};
|
|
|
|
spectrum::WaterfallView waterfall{true};
|
|
|
|
void on_baseband_bandwidth_changed(uint32_t bandwidth_hz);
|
|
void on_modulation_changed(ReceiverModel::Mode modulation);
|
|
void on_show_options_frequency();
|
|
void on_show_options_rf_gain();
|
|
void on_show_options_modulation();
|
|
void on_frequency_step_changed(rf::Frequency f);
|
|
void on_reference_ppm_correction_changed(int32_t v);
|
|
|
|
void remove_options_widget();
|
|
void set_options_widget(std::unique_ptr<Widget> new_widget);
|
|
|
|
void update_modulation(ReceiverModel::Mode modulation);
|
|
|
|
void handle_coded_squelch(uint32_t value);
|
|
|
|
void on_freqchg(int64_t freq);
|
|
|
|
MessageHandlerRegistration message_handler_coded_squelch{
|
|
Message::ID::CodedSquelch,
|
|
[this](const Message* p) {
|
|
const auto message = *reinterpret_cast<const CodedSquelchMessage*>(p);
|
|
this->handle_coded_squelch(message.value);
|
|
}};
|
|
|
|
MessageHandlerRegistration message_handler_freqchg{
|
|
Message::ID::FreqChangeCommand,
|
|
[this](Message* const p) {
|
|
const auto message = static_cast<const FreqChangeCommandMessage*>(p);
|
|
this->on_freqchg(message->freq);
|
|
}};
|
|
};
|
|
|
|
} /* namespace ui */
|
|
|
|
#endif /*__ANALOG_AUDIO_APP_H__*/
|