mirror of
https://github.com/eried/portapack-mayhem.git
synced 2025-08-22 04:59:39 -04:00
Merge remote-tracking branch 'upstream/master'
Conflicts: firmware/application/Makefile firmware/application/analog_audio_app.cpp firmware/application/analog_audio_app.hpp firmware/application/event.cpp firmware/application/irq_ipc.hpp firmware/application/portapack.hpp firmware/application/receiver_model.cpp firmware/application/receiver_model.hpp firmware/application/recent_entries.cpp firmware/application/string_format.hpp firmware/application/ui_debug.cpp firmware/application/ui_debug.hpp firmware/application/ui_menu.cpp firmware/application/ui_navigation.cpp firmware/application/ui_navigation.hpp firmware/application/ui_receiver.cpp firmware/application/ui_receiver.hpp firmware/application/ui_sd_card_status_view.cpp firmware/application/ui_sd_card_status_view.hpp firmware/application/ui_setup.cpp firmware/application/ui_setup.hpp firmware/application/ui_spectrum.hpp firmware/baseband-tx/dsp_fir_taps.cpp firmware/baseband-tx/dsp_fir_taps.hpp firmware/baseband-tx/irq_ipc_m4.cpp firmware/baseband-tx/irq_ipc_m4.hpp firmware/baseband-tx/proc_audiotx.cpp firmware/baseband/Makefile firmware/baseband/audio_output.cpp firmware/baseband/audio_output.hpp firmware/baseband/block_decimator.hpp firmware/baseband/dsp_decimate.cpp firmware/baseband/dsp_decimate.hpp firmware/baseband/dsp_demodulate.cpp firmware/baseband/dsp_demodulate.hpp firmware/baseband/dsp_fir_taps.cpp firmware/baseband/irq_ipc_m4.cpp firmware/baseband/irq_ipc_m4.hpp firmware/baseband/proc_am_audio.cpp firmware/baseband/proc_am_audio.hpp firmware/baseband/proc_nfm_audio.cpp firmware/baseband/proc_nfm_audio.hpp firmware/baseband/proc_wfm_audio.cpp firmware/baseband/proc_wfm_audio.hpp firmware/baseband/spectrum_collector.hpp firmware/common/dsp_fir_taps.cpp firmware/common/dsp_fir_taps.hpp firmware/common/event.hpp firmware/common/message.hpp firmware/common/ui_painter.cpp firmware/common/ui_painter.hpp
This commit is contained in:
commit
8009a9b543
45 changed files with 1148 additions and 877 deletions
|
@ -27,58 +27,273 @@ using namespace portapack;
|
|||
|
||||
#include "utility.hpp"
|
||||
|
||||
AnalogAudioModel::AnalogAudioModel(ReceiverModel::Mode mode) {
|
||||
receiver_model.set_baseband_configuration({
|
||||
.mode = toUType(mode),
|
||||
.sampling_rate = 3072000,
|
||||
.decimation_factor = 1,
|
||||
});
|
||||
receiver_model.set_baseband_bandwidth(1750000);
|
||||
namespace ui {
|
||||
|
||||
switch(mode) {
|
||||
case ReceiverModel::Mode::NarrowbandFMAudio:
|
||||
configure_nbfm();
|
||||
break;
|
||||
/* AMOptionsView *********************************************************/
|
||||
|
||||
case ReceiverModel::Mode::WidebandFMAudio:
|
||||
configure_wfm();
|
||||
break;
|
||||
AMOptionsView::AMOptionsView(
|
||||
const Rect parent_rect, const Style* const style
|
||||
) : View { parent_rect }
|
||||
{
|
||||
set_style(style);
|
||||
|
||||
case ReceiverModel::Mode::AMAudio:
|
||||
configure_am();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
add_children({ {
|
||||
&label_config,
|
||||
&options_config,
|
||||
} });
|
||||
|
||||
options_config.set_selected_index(receiver_model.am_configuration());
|
||||
options_config.on_change = [this](size_t n, OptionsField::value_t) {
|
||||
receiver_model.set_am_configuration(n);
|
||||
};
|
||||
}
|
||||
|
||||
/* NBFMOptionsView *******************************************************/
|
||||
|
||||
NBFMOptionsView::NBFMOptionsView(
|
||||
const Rect parent_rect, const Style* const style
|
||||
) : View { parent_rect }
|
||||
{
|
||||
set_style(style);
|
||||
|
||||
add_children({ {
|
||||
&label_config,
|
||||
&options_config,
|
||||
} });
|
||||
|
||||
options_config.set_selected_index(receiver_model.nbfm_configuration());
|
||||
options_config.on_change = [this](size_t n, OptionsField::value_t) {
|
||||
receiver_model.set_nbfm_configuration(n);
|
||||
};
|
||||
}
|
||||
|
||||
/* AnalogAudioView *******************************************************/
|
||||
|
||||
AnalogAudioView::AnalogAudioView(
|
||||
NavigationView& nav
|
||||
) {
|
||||
add_children({ {
|
||||
&rssi,
|
||||
&channel,
|
||||
&audio,
|
||||
&field_frequency,
|
||||
&field_lna,
|
||||
&field_vga,
|
||||
&options_modulation,
|
||||
&field_volume,
|
||||
&waterfall,
|
||||
} });
|
||||
|
||||
field_frequency.set_value(receiver_model.tuning_frequency());
|
||||
field_frequency.set_step(receiver_model.frequency_step());
|
||||
field_frequency.on_change = [this](rf::Frequency f) {
|
||||
this->on_tuning_frequency_changed(f);
|
||||
};
|
||||
field_frequency.on_edit = [this, &nav]() {
|
||||
// TODO: Provide separate modal method/scheme?
|
||||
auto new_view = nav.push<FrequencyKeypadView>(receiver_model.tuning_frequency());
|
||||
new_view->on_changed = [this](rf::Frequency f) {
|
||||
this->on_tuning_frequency_changed(f);
|
||||
this->field_frequency.set_value(f);
|
||||
};
|
||||
};
|
||||
|
||||
field_frequency.on_show_options = [this]() {
|
||||
this->on_show_options_frequency();
|
||||
};
|
||||
|
||||
field_lna.set_value(receiver_model.lna());
|
||||
field_lna.on_change = [this](int32_t v) {
|
||||
this->on_lna_changed(v);
|
||||
};
|
||||
|
||||
field_lna.on_show_options = [this]() {
|
||||
this->on_show_options_rf_gain();
|
||||
};
|
||||
|
||||
field_vga.set_value(receiver_model.vga());
|
||||
field_vga.on_change = [this](int32_t v_db) {
|
||||
this->on_vga_changed(v_db);
|
||||
};
|
||||
|
||||
const auto modulation = receiver_model.modulation();
|
||||
options_modulation.set_by_value(modulation);
|
||||
options_modulation.on_change = [this](size_t, OptionsField::value_t v) {
|
||||
this->on_modulation_changed(static_cast<ReceiverModel::Mode>(v));
|
||||
};
|
||||
options_modulation.on_show_options = [this]() {
|
||||
this->on_show_options_modulation();
|
||||
};
|
||||
|
||||
field_volume.set_value((receiver_model.headphone_volume() - wolfson::wm8731::headphone_gain_range.max).decibel() + 99);
|
||||
field_volume.on_change = [this](int32_t v) {
|
||||
this->on_headphone_volume_changed(v);
|
||||
};
|
||||
|
||||
update_modulation(static_cast<ReceiverModel::Mode>(modulation));
|
||||
}
|
||||
|
||||
AnalogAudioView::~AnalogAudioView() {
|
||||
// TODO: Manipulating audio codec here, and in ui_receiver.cpp. Good to do
|
||||
// both?
|
||||
audio_codec.headphone_mute();
|
||||
|
||||
receiver_model.disable();
|
||||
}
|
||||
|
||||
void AnalogAudioView::on_hide() {
|
||||
// TODO: Terrible kludge because widget system doesn't notify Waterfall that
|
||||
// it's being shown or hidden.
|
||||
waterfall.on_hide();
|
||||
View::on_hide();
|
||||
}
|
||||
|
||||
void AnalogAudioView::set_parent_rect(const Rect new_parent_rect) {
|
||||
View::set_parent_rect(new_parent_rect);
|
||||
|
||||
const ui::Rect waterfall_rect { 0, header_height, new_parent_rect.width(), static_cast<ui::Dim>(new_parent_rect.height() - header_height) };
|
||||
waterfall.set_parent_rect(waterfall_rect);
|
||||
}
|
||||
|
||||
void AnalogAudioView::focus() {
|
||||
field_frequency.focus();
|
||||
}
|
||||
|
||||
void AnalogAudioView::on_tuning_frequency_changed(rf::Frequency f) {
|
||||
receiver_model.set_tuning_frequency(f);
|
||||
}
|
||||
|
||||
void AnalogAudioView::on_baseband_bandwidth_changed(uint32_t bandwidth_hz) {
|
||||
receiver_model.set_baseband_bandwidth(bandwidth_hz);
|
||||
}
|
||||
|
||||
void AnalogAudioView::on_rf_amp_changed(bool v) {
|
||||
receiver_model.set_rf_amp(v);
|
||||
}
|
||||
|
||||
void AnalogAudioView::on_lna_changed(int32_t v_db) {
|
||||
receiver_model.set_lna(v_db);
|
||||
}
|
||||
|
||||
void AnalogAudioView::on_vga_changed(int32_t v_db) {
|
||||
receiver_model.set_vga(v_db);
|
||||
}
|
||||
|
||||
void AnalogAudioView::on_modulation_changed(const ReceiverModel::Mode modulation) {
|
||||
// TODO: Terrible kludge because widget system doesn't notify Waterfall that
|
||||
// it's being shown or hidden.
|
||||
waterfall.on_hide();
|
||||
update_modulation(modulation);
|
||||
on_show_options_modulation();
|
||||
waterfall.on_show();
|
||||
}
|
||||
|
||||
void AnalogAudioView::remove_options_widget() {
|
||||
if( options_widget ) {
|
||||
remove_child(options_widget.get());
|
||||
options_widget.reset();
|
||||
}
|
||||
|
||||
field_lna.set_style(nullptr);
|
||||
options_modulation.set_style(nullptr);
|
||||
field_frequency.set_style(nullptr);
|
||||
}
|
||||
|
||||
void AnalogAudioModel::configure_nbfm() {
|
||||
const NBFMConfigureMessage message {
|
||||
taps_4k25_decim_0,
|
||||
taps_4k25_decim_1,
|
||||
taps_4k25_channel,
|
||||
2500,
|
||||
};
|
||||
shared_memory.baseband_queue.push(message);
|
||||
void AnalogAudioView::set_options_widget(std::unique_ptr<Widget> new_widget) {
|
||||
if( new_widget ) {
|
||||
options_widget = std::move(new_widget);
|
||||
add_child(options_widget.get());
|
||||
}
|
||||
}
|
||||
|
||||
void AnalogAudioModel::configure_wfm() {
|
||||
const WFMConfigureMessage message {
|
||||
taps_200k_wfm_decim_0,
|
||||
taps_200k_wfm_decim_1,
|
||||
taps_64_lp_156_198,
|
||||
75000,
|
||||
void AnalogAudioView::on_show_options_frequency() {
|
||||
// TODO: This approach of managing options views is error-prone and unsustainable!
|
||||
remove_options_widget();
|
||||
|
||||
field_frequency.set_style(&style_options_group);
|
||||
|
||||
auto widget = std::make_unique<FrequencyOptionsView>(
|
||||
Rect { 0 * 8, 1 * 16, 30 * 8, 1 * 16 },
|
||||
&style_options_group
|
||||
);
|
||||
|
||||
widget->set_step(receiver_model.frequency_step());
|
||||
widget->on_change_step = [this](rf::Frequency f) {
|
||||
this->on_frequency_step_changed(f);
|
||||
};
|
||||
shared_memory.baseband_queue.push(message);
|
||||
widget->set_reference_ppm_correction(receiver_model.reference_ppm_correction());
|
||||
widget->on_change_reference_ppm_correction = [this](int32_t v) {
|
||||
this->on_reference_ppm_correction_changed(v);
|
||||
};
|
||||
|
||||
set_options_widget(std::move(widget));
|
||||
}
|
||||
|
||||
void AnalogAudioModel::configure_am() {
|
||||
const AMConfigureMessage message {
|
||||
taps_6k0_decim_0,
|
||||
taps_6k0_decim_1,
|
||||
taps_6k0_channel,
|
||||
void AnalogAudioView::on_show_options_rf_gain() {
|
||||
// TODO: This approach of managing options views is error-prone and unsustainable!
|
||||
remove_options_widget();
|
||||
|
||||
field_lna.set_style(&style_options_group);
|
||||
|
||||
auto widget = std::make_unique<RadioGainOptionsView>(
|
||||
Rect { 0 * 8, 1 * 16, 30 * 8, 1 * 16 },
|
||||
&style_options_group
|
||||
);
|
||||
|
||||
widget->set_rf_amp(receiver_model.rf_amp());
|
||||
widget->on_change_rf_amp = [this](bool enable) {
|
||||
this->on_rf_amp_changed(enable);
|
||||
};
|
||||
shared_memory.baseband_queue.push(message);
|
||||
|
||||
set_options_widget(std::move(widget));
|
||||
}
|
||||
|
||||
void AnalogAudioView::on_show_options_modulation() {
|
||||
// TODO: This approach of managing options views is error-prone and unsustainable!
|
||||
remove_options_widget();
|
||||
|
||||
const auto modulation = static_cast<ReceiverModel::Mode>(receiver_model.modulation());
|
||||
if( modulation == ReceiverModel::Mode::AMAudio ) {
|
||||
options_modulation.set_style(&style_options_group);
|
||||
auto widget = std::make_unique<AMOptionsView>(
|
||||
Rect { 0 * 8, 1 * 16, 30 * 8, 1 * 16 },
|
||||
&style_options_group
|
||||
);
|
||||
set_options_widget(std::move(widget));
|
||||
}
|
||||
if( modulation == ReceiverModel::Mode::NarrowbandFMAudio ) {
|
||||
options_modulation.set_style(&style_options_group);
|
||||
auto widget = std::make_unique<NBFMOptionsView>(
|
||||
Rect { 0 * 8, 1 * 16, 30 * 8, 1 * 16 },
|
||||
&style_options_group
|
||||
);
|
||||
set_options_widget(std::move(widget));
|
||||
}
|
||||
}
|
||||
|
||||
void AnalogAudioView::on_frequency_step_changed(rf::Frequency f) {
|
||||
receiver_model.set_frequency_step(f);
|
||||
field_frequency.set_step(f);
|
||||
}
|
||||
|
||||
void AnalogAudioView::on_reference_ppm_correction_changed(int32_t v) {
|
||||
receiver_model.set_reference_ppm_correction(v);
|
||||
}
|
||||
|
||||
void AnalogAudioView::on_headphone_volume_changed(int32_t v) {
|
||||
const auto new_volume = volume_t::decibel(v - 99) + wolfson::wm8731::headphone_gain_range.max;
|
||||
receiver_model.set_headphone_volume(new_volume);
|
||||
}
|
||||
|
||||
void AnalogAudioView::update_modulation(const ReceiverModel::Mode modulation) {
|
||||
const auto is_wideband_spectrum_mode = (modulation == ReceiverModel::Mode::SpectrumAnalysis);
|
||||
receiver_model.set_baseband_configuration({
|
||||
.mode = toUType(modulation),
|
||||
.sampling_rate = is_wideband_spectrum_mode ? 20000000U : 3072000U,
|
||||
.decimation_factor = 1,
|
||||
});
|
||||
receiver_model.set_baseband_bandwidth(is_wideband_spectrum_mode ? 12000000 : 1750000);
|
||||
receiver_model.enable();
|
||||
}
|
||||
|
||||
} /* namespace ui */
|
||||
|
|
|
@ -23,30 +23,145 @@
|
|||
#define __ANALOG_AUDIO_APP_H__
|
||||
|
||||
#include "receiver_model.hpp"
|
||||
|
||||
#include "ui_receiver.hpp"
|
||||
#include "ui_spectrum.hpp"
|
||||
|
||||
class AnalogAudioModel {
|
||||
public:
|
||||
AnalogAudioModel(ReceiverModel::Mode mode);
|
||||
|
||||
private:
|
||||
void configure_nbfm();
|
||||
void configure_wfm();
|
||||
void configure_am();
|
||||
};
|
||||
#include "ui_font_fixed_8x16.hpp"
|
||||
|
||||
namespace ui {
|
||||
|
||||
class AnalogAudioView : public spectrum::WaterfallWidget {
|
||||
constexpr Style style_options_group {
|
||||
.font = font::fixed_8x16,
|
||||
.background = Color::blue(),
|
||||
.foreground = Color::white(),
|
||||
};
|
||||
|
||||
class AMOptionsView : public View {
|
||||
public:
|
||||
AnalogAudioView(
|
||||
ReceiverModel::Mode mode
|
||||
) : model { mode }
|
||||
{
|
||||
}
|
||||
AMOptionsView(const Rect parent_rect, const Style* const style);
|
||||
|
||||
private:
|
||||
AnalogAudioModel model;
|
||||
Text label_config {
|
||||
{ 0 * 8, 0 * 16, 2 * 8, 1 * 16 },
|
||||
"BW",
|
||||
};
|
||||
|
||||
OptionsField options_config {
|
||||
{ 3 * 8, 0 * 16 },
|
||||
4,
|
||||
{
|
||||
{ "DSB ", 0 },
|
||||
{ "USB ", 0 },
|
||||
{ "LSB ", 0 },
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
class NBFMOptionsView : public View {
|
||||
public:
|
||||
NBFMOptionsView(const Rect parent_rect, const Style* const style);
|
||||
|
||||
private:
|
||||
Text label_config {
|
||||
{ 0 * 8, 0 * 16, 2 * 8, 1 * 16 },
|
||||
"BW",
|
||||
};
|
||||
|
||||
OptionsField options_config {
|
||||
{ 3 * 8, 0 * 16 },
|
||||
4,
|
||||
{
|
||||
{ " 8k5", 0 },
|
||||
{ "11k ", 0 },
|
||||
{ "16k ", 0 },
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
class AnalogAudioView : public View {
|
||||
public:
|
||||
AnalogAudioView(NavigationView& nav);
|
||||
~AnalogAudioView();
|
||||
|
||||
void on_hide() override;
|
||||
|
||||
void set_parent_rect(const Rect new_parent_rect) override;
|
||||
|
||||
void focus() override;
|
||||
|
||||
private:
|
||||
static constexpr ui::Dim header_height = 2 * 16;
|
||||
|
||||
RSSI rssi {
|
||||
{ 21 * 8, 0, 6 * 8, 4 },
|
||||
};
|
||||
|
||||
Channel channel {
|
||||
{ 21 * 8, 5, 6 * 8, 4 },
|
||||
};
|
||||
|
||||
Audio audio {
|
||||
{ 21 * 8, 10, 6 * 8, 4 },
|
||||
};
|
||||
|
||||
FrequencyField field_frequency {
|
||||
{ 5 * 8, 0 * 16 },
|
||||
};
|
||||
|
||||
LNAGainField field_lna {
|
||||
{ 15 * 8, 0 * 16 }
|
||||
};
|
||||
|
||||
NumberField field_vga {
|
||||
{ 18 * 8, 0 * 16},
|
||||
2,
|
||||
{ max2837::vga::gain_db_range.minimum, max2837::vga::gain_db_range.maximum },
|
||||
max2837::vga::gain_db_step,
|
||||
' ',
|
||||
};
|
||||
|
||||
OptionsField options_modulation {
|
||||
{ 0 * 8, 0 * 16 },
|
||||
4,
|
||||
{
|
||||
{ " AM ", toUType(ReceiverModel::Mode::AMAudio) },
|
||||
{ "NFM ", toUType(ReceiverModel::Mode::NarrowbandFMAudio) },
|
||||
{ "WFM ", toUType(ReceiverModel::Mode::WidebandFMAudio) },
|
||||
{ "SPEC", toUType(ReceiverModel::Mode::SpectrumAnalysis) },
|
||||
}
|
||||
};
|
||||
|
||||
NumberField field_volume {
|
||||
{ 28 * 8, 0 * 16 },
|
||||
2,
|
||||
{ 0, 99 },
|
||||
1,
|
||||
' ',
|
||||
};
|
||||
|
||||
std::unique_ptr<Widget> options_widget;
|
||||
|
||||
spectrum::WaterfallWidget waterfall;
|
||||
|
||||
void on_tuning_frequency_changed(rf::Frequency f);
|
||||
void on_baseband_bandwidth_changed(uint32_t bandwidth_hz);
|
||||
void on_rf_amp_changed(bool v);
|
||||
void on_lna_changed(int32_t v_db);
|
||||
void on_vga_changed(int32_t v_db);
|
||||
void on_modulation_changed(const 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 on_headphone_volume_changed(int32_t v);
|
||||
void on_edit_frequency();
|
||||
|
||||
void remove_options_widget();
|
||||
void set_options_widget(std::unique_ptr<Widget> new_widget);
|
||||
|
||||
void update_modulation(const ReceiverModel::Mode modulation);
|
||||
};
|
||||
|
||||
} /* namespace ui */
|
||||
|
|
|
@ -516,7 +516,17 @@ void ClockManager::start_audio_pll() {
|
|||
while( !cgu::pll0audio::is_locked() );
|
||||
cgu::pll0audio::clock_enable();
|
||||
|
||||
set_clock(LPC_CGU->BASE_AUDIO_CLK, cgu::CLK_SEL::PLL0AUDIO);
|
||||
set_base_audio_clock_divider(1);
|
||||
set_clock(LPC_CGU->BASE_AUDIO_CLK, cgu::CLK_SEL::IDIVC);
|
||||
}
|
||||
|
||||
void ClockManager::set_base_audio_clock_divider(const size_t divisor) {
|
||||
LPC_CGU->IDIVC_CTRL =
|
||||
(0 << 1)
|
||||
| ((divisor - 1) << 2)
|
||||
| (1 << 11)
|
||||
| (toUType(cgu::CLK_SEL::PLL0AUDIO) << 24)
|
||||
;
|
||||
}
|
||||
|
||||
void ClockManager::stop_audio_pll() {
|
||||
|
|
|
@ -51,6 +51,8 @@ public:
|
|||
void start_audio_pll();
|
||||
void stop_audio_pll();
|
||||
|
||||
void set_base_audio_clock_divider(const size_t divisor);
|
||||
|
||||
void enable_codec_clocks();
|
||||
void disable_codec_clocks();
|
||||
|
||||
|
|
|
@ -61,9 +61,9 @@ ClockManager clock_manager {
|
|||
i2c0, clock_generator
|
||||
};
|
||||
|
||||
ReceiverModel receiver_model {
|
||||
clock_manager
|
||||
};
|
||||
ReceiverModel receiver_model;
|
||||
|
||||
TemperatureLogger temperature_logger;
|
||||
|
||||
TemperatureLogger temperature_logger;
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "lcd_ili9341.hpp"
|
||||
|
||||
#include "radio.hpp"
|
||||
#include "clock_manager.hpp"
|
||||
#include "temperature_logger.hpp"
|
||||
|
||||
namespace portapack {
|
||||
|
@ -44,6 +45,7 @@ extern SPI ssp1;
|
|||
extern wolfson::wm8731::WM8731 audio_codec;
|
||||
|
||||
extern si5351::Si5351 clock_generator;
|
||||
extern ClockManager clock_manager;
|
||||
|
||||
extern ReceiverModel receiver_model;
|
||||
extern TransmitterModel transmitter_model;
|
||||
|
|
|
@ -26,6 +26,90 @@
|
|||
#include "portapack.hpp"
|
||||
using namespace portapack;
|
||||
|
||||
#include "dsp_fir_taps.hpp"
|
||||
#include "dsp_iir.hpp"
|
||||
#include "dsp_iir_config.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
struct AMConfig {
|
||||
const fir_taps_complex<64> channel;
|
||||
const AMConfigureMessage::Modulation modulation;
|
||||
|
||||
void apply() const;
|
||||
};
|
||||
|
||||
struct NBFMConfig {
|
||||
const fir_taps_real<24> decim_0;
|
||||
const fir_taps_real<32> decim_1;
|
||||
const fir_taps_real<32> channel;
|
||||
const size_t deviation;
|
||||
|
||||
void apply() const;
|
||||
};
|
||||
|
||||
struct WFMConfig {
|
||||
void apply() const;
|
||||
};
|
||||
|
||||
void AMConfig::apply() const {
|
||||
const AMConfigureMessage message {
|
||||
taps_6k0_decim_0,
|
||||
taps_6k0_decim_1,
|
||||
taps_6k0_decim_2,
|
||||
channel,
|
||||
modulation,
|
||||
audio_12k_hpf_300hz_config
|
||||
};
|
||||
shared_memory.baseband_queue.push(message);
|
||||
clock_manager.set_base_audio_clock_divider(4);
|
||||
}
|
||||
|
||||
void NBFMConfig::apply() const {
|
||||
const NBFMConfigureMessage message {
|
||||
decim_0,
|
||||
decim_1,
|
||||
channel,
|
||||
2,
|
||||
deviation,
|
||||
audio_24k_hpf_300hz_config,
|
||||
audio_24k_deemph_300_6_config
|
||||
};
|
||||
shared_memory.baseband_queue.push(message);
|
||||
clock_manager.set_base_audio_clock_divider(2);
|
||||
}
|
||||
|
||||
void WFMConfig::apply() const {
|
||||
const WFMConfigureMessage message {
|
||||
taps_200k_wfm_decim_0,
|
||||
taps_200k_wfm_decim_1,
|
||||
taps_64_lp_156_198,
|
||||
75000,
|
||||
audio_48k_hpf_30hz_config,
|
||||
audio_48k_deemph_2122_6_config
|
||||
};
|
||||
shared_memory.baseband_queue.push(message);
|
||||
clock_manager.set_base_audio_clock_divider(1);
|
||||
}
|
||||
|
||||
static constexpr std::array<AMConfig, 3> am_configs { {
|
||||
{ taps_6k0_dsb_channel, AMConfigureMessage::Modulation::DSB },
|
||||
{ taps_2k8_usb_channel, AMConfigureMessage::Modulation::SSB },
|
||||
{ taps_2k8_lsb_channel, AMConfigureMessage::Modulation::SSB },
|
||||
} };
|
||||
|
||||
static constexpr std::array<NBFMConfig, 3> nbfm_configs { {
|
||||
{ taps_4k25_decim_0, taps_4k25_decim_1, taps_4k25_channel, 2500 },
|
||||
{ taps_11k0_decim_0, taps_11k0_decim_1, taps_11k0_channel, 2500 },
|
||||
{ taps_16k0_decim_0, taps_16k0_decim_1, taps_16k0_channel, 5000 },
|
||||
} };
|
||||
|
||||
static constexpr std::array<WFMConfig, 1> wfm_configs { {
|
||||
{ },
|
||||
} };
|
||||
|
||||
} /* namespace */
|
||||
|
||||
rf::Frequency ReceiverModel::tuning_frequency() const {
|
||||
return persistent_memory::tuned_frequency();
|
||||
}
|
||||
|
@ -129,7 +213,7 @@ void ReceiverModel::enable() {
|
|||
update_vga();
|
||||
update_baseband_bandwidth();
|
||||
update_baseband_configuration();
|
||||
|
||||
update_modulation_configuration();
|
||||
update_headphone_volume();
|
||||
}
|
||||
|
||||
|
@ -189,6 +273,27 @@ void ReceiverModel::set_baseband_configuration(const BasebandConfiguration confi
|
|||
update_baseband_configuration();
|
||||
}
|
||||
|
||||
void ReceiverModel::set_am_configuration(const size_t n) {
|
||||
if( n < am_configs.size() ) {
|
||||
am_config_index = n;
|
||||
update_modulation_configuration();
|
||||
}
|
||||
}
|
||||
|
||||
void ReceiverModel::set_nbfm_configuration(const size_t n) {
|
||||
if( n < nbfm_configs.size() ) {
|
||||
nbfm_config_index = n;
|
||||
update_modulation_configuration();
|
||||
}
|
||||
}
|
||||
|
||||
void ReceiverModel::set_wfm_configuration(const size_t n) {
|
||||
if( n < wfm_configs.size() ) {
|
||||
wfm_config_index = n;
|
||||
update_modulation_configuration();
|
||||
}
|
||||
}
|
||||
|
||||
void ReceiverModel::update_baseband_configuration() {
|
||||
// TODO: Move more low-level radio control stuff to M4. It'll enable tighter
|
||||
// synchronization for things like wideband (sweeping) spectrum analysis, and
|
||||
|
@ -211,3 +316,47 @@ void ReceiverModel::update_headphone_volume() {
|
|||
|
||||
audio_codec.set_headphone_volume(headphone_volume_);
|
||||
}
|
||||
|
||||
void ReceiverModel::update_modulation_configuration() {
|
||||
switch(static_cast<Mode>(modulation())) {
|
||||
default:
|
||||
case Mode::AMAudio:
|
||||
update_am_configuration();
|
||||
break;
|
||||
|
||||
case Mode::NarrowbandFMAudio:
|
||||
update_nbfm_configuration();
|
||||
break;
|
||||
|
||||
case Mode::WidebandFMAudio:
|
||||
update_wfm_configuration();
|
||||
break;
|
||||
|
||||
case Mode::SpectrumAnalysis:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void ReceiverModel::update_nbfm_configuration() {
|
||||
nbfm_configs[nbfm_config_index].apply();
|
||||
}
|
||||
|
||||
size_t ReceiverModel::wfm_configuration() const {
|
||||
return wfm_config_index;
|
||||
}
|
||||
|
||||
void ReceiverModel::update_wfm_configuration() {
|
||||
wfm_configs[wfm_config_index].apply();
|
||||
}
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
|
||||
#include "clock_manager.hpp"
|
||||
#include "message.hpp"
|
||||
#include "rf_path.hpp"
|
||||
#include "max2837.hpp"
|
||||
|
@ -43,12 +42,6 @@ public:
|
|||
ERT = 6,
|
||||
};
|
||||
|
||||
constexpr ReceiverModel(
|
||||
ClockManager& clock_manager
|
||||
) : clock_manager(clock_manager)
|
||||
{
|
||||
}
|
||||
|
||||
rf::Frequency tuning_frequency() const;
|
||||
void set_tuning_frequency(rf::Frequency f);
|
||||
|
||||
|
@ -87,6 +80,15 @@ public:
|
|||
|
||||
void set_baseband_configuration(const BasebandConfiguration config);
|
||||
|
||||
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);
|
||||
|
||||
private:
|
||||
rf::Frequency frequency_step_ { 25000 };
|
||||
bool enabled_ { false };
|
||||
|
@ -100,8 +102,10 @@ private:
|
|||
.sampling_rate = 3072000,
|
||||
.decimation_factor = 1,
|
||||
};
|
||||
size_t am_config_index = 0;
|
||||
size_t nbfm_config_index = 0;
|
||||
size_t wfm_config_index = 0;
|
||||
volume_t headphone_volume_ { -43.0_dB };
|
||||
ClockManager& clock_manager;
|
||||
|
||||
int32_t tuning_offset();
|
||||
|
||||
|
@ -114,6 +118,11 @@ private:
|
|||
void update_baseband_configuration();
|
||||
void update_headphone_volume();
|
||||
|
||||
void update_modulation_configuration();
|
||||
void update_am_configuration();
|
||||
void update_nbfm_configuration();
|
||||
void update_wfm_configuration();
|
||||
|
||||
void baseband_disable();
|
||||
};
|
||||
|
||||
|
|
|
@ -23,11 +23,6 @@
|
|||
|
||||
#include "ch.h"
|
||||
|
||||
#include "ff.h"
|
||||
#include "hackrf_gpio.hpp"
|
||||
#include "portapack.hpp"
|
||||
#include "portapack_shared_memory.hpp"
|
||||
|
||||
#include "radio.hpp"
|
||||
#include "string_format.hpp"
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#include "ui_sigfrx.hpp"
|
||||
#include "ui_numbers.hpp"
|
||||
|
||||
#include "analog_audio_app.hpp"
|
||||
#include "ais_app.hpp"
|
||||
#include "ert_app.hpp"
|
||||
#include "tpms_app.hpp"
|
||||
|
@ -65,7 +66,6 @@ SystemStatusView::SystemStatusView() {
|
|||
&button_sleep,
|
||||
&sd_card_status_view,
|
||||
} });
|
||||
sd_card_status_view.set_parent_rect({ 28 * 8, 0 * 16, 2 * 8, 1 * 16 });
|
||||
|
||||
button_back.on_select = [this](Button&){
|
||||
if( this->on_back ) {
|
||||
|
@ -73,7 +73,7 @@ SystemStatusView::SystemStatusView() {
|
|||
}
|
||||
};
|
||||
|
||||
button_sleep.on_select = [this](Button&) {
|
||||
button_sleep.on_select = [this](ImageButton&) {
|
||||
DisplaySleepMessage message;
|
||||
EventDispatcher::message_map().send(&message);
|
||||
};
|
||||
|
|
|
@ -37,6 +37,29 @@
|
|||
|
||||
namespace ui {
|
||||
|
||||
static constexpr uint8_t bitmap_sleep_data[] = {
|
||||
0x00, 0x00,
|
||||
0x00, 0x00,
|
||||
0x00, 0x04,
|
||||
0x00, 0x08,
|
||||
0x00, 0x18,
|
||||
0x00, 0x18,
|
||||
0x00, 0x38,
|
||||
0x00, 0x3c,
|
||||
0x00, 0x3c,
|
||||
0x00, 0x3e,
|
||||
0x84, 0x1f,
|
||||
0xf8, 0x1f,
|
||||
0xf0, 0x0f,
|
||||
0xc0, 0x03,
|
||||
0x00, 0x00,
|
||||
0x00, 0x00,
|
||||
};
|
||||
|
||||
static constexpr Bitmap bitmap_sleep {
|
||||
{ 16, 16 }, bitmap_sleep_data
|
||||
};
|
||||
|
||||
class SystemStatusView : public View {
|
||||
public:
|
||||
std::function<void(void)> on_back;
|
||||
|
@ -47,7 +70,7 @@ public:
|
|||
void set_title(const std::string new_value);
|
||||
|
||||
private:
|
||||
static constexpr auto default_title = "PortaPack/HAVOC";
|
||||
static constexpr auto default_title = "PortaPack";
|
||||
|
||||
Button button_back {
|
||||
{ 0 * 8, 0 * 16, 3 * 8, 16 },
|
||||
|
@ -59,12 +82,16 @@ private:
|
|||
default_title,
|
||||
};
|
||||
|
||||
Button button_sleep {
|
||||
ImageButton button_sleep {
|
||||
{ 25 * 8, 0, 2 * 8, 1 * 16 },
|
||||
"ZZ",
|
||||
&bitmap_sleep,
|
||||
Color::white(),
|
||||
Color::black()
|
||||
};
|
||||
|
||||
SDCardStatusView sd_card_status_view;
|
||||
SDCardStatusView sd_card_status_view {
|
||||
{ 28 * 8, 0 * 16, 2 * 8, 1 * 16 }
|
||||
};
|
||||
};
|
||||
|
||||
class NavigationView : public View {
|
||||
|
|
|
@ -26,11 +26,7 @@ using namespace portapack;
|
|||
|
||||
#include "string_format.hpp"
|
||||
|
||||
#include "analog_audio_app.hpp"
|
||||
#include "ais_app.hpp"
|
||||
#include "tpms_app.hpp"
|
||||
#include "ert_app.hpp"
|
||||
#include "spectrum_analysis_app.hpp"
|
||||
#include "max2837.hpp"
|
||||
|
||||
namespace ui {
|
||||
|
||||
|
@ -322,184 +318,4 @@ void LNAGainField::on_focus() {
|
|||
}
|
||||
}
|
||||
|
||||
/* ReceiverView **********************************************************/
|
||||
|
||||
ReceiverView::ReceiverView(
|
||||
NavigationView& nav
|
||||
) {
|
||||
add_children({ {
|
||||
&rssi,
|
||||
&channel,
|
||||
&audio,
|
||||
&field_frequency,
|
||||
&field_lna,
|
||||
&field_vga,
|
||||
&options_modulation,
|
||||
&field_volume,
|
||||
&view_frequency_options,
|
||||
&view_rf_gain_options,
|
||||
} });
|
||||
|
||||
field_frequency.set_value(receiver_model.tuning_frequency());
|
||||
field_frequency.set_step(receiver_model.frequency_step());
|
||||
field_frequency.on_change = [this](rf::Frequency f) {
|
||||
this->on_tuning_frequency_changed(f);
|
||||
};
|
||||
field_frequency.on_edit = [this, &nav]() {
|
||||
// TODO: Provide separate modal method/scheme?
|
||||
auto new_view = nav.push<FrequencyKeypadView>(receiver_model.tuning_frequency());
|
||||
new_view->on_changed = [this](rf::Frequency f) {
|
||||
this->on_tuning_frequency_changed(f);
|
||||
this->field_frequency.set_value(f);
|
||||
};
|
||||
};
|
||||
field_frequency.on_show_options = [this]() {
|
||||
this->on_show_options_frequency();
|
||||
};
|
||||
|
||||
field_lna.set_value(receiver_model.lna());
|
||||
field_lna.on_change = [this](int32_t v) {
|
||||
this->on_lna_changed(v);
|
||||
};
|
||||
field_lna.on_show_options = [this]() {
|
||||
this->on_show_options_rf_gain();
|
||||
};
|
||||
|
||||
field_vga.set_value(receiver_model.vga());
|
||||
field_vga.on_change = [this](int32_t v_db) {
|
||||
this->on_vga_changed(v_db);
|
||||
};
|
||||
|
||||
options_modulation.set_by_value(receiver_model.modulation());
|
||||
options_modulation.on_change = [this](size_t n, OptionsField::value_t v) {
|
||||
(void)n;
|
||||
this->on_modulation_changed(static_cast<ReceiverModel::Mode>(v));
|
||||
};
|
||||
|
||||
field_volume.set_value((receiver_model.headphone_volume() - wolfson::wm8731::headphone_gain_range.max).decibel() + 99);
|
||||
field_volume.on_change = [this](int32_t v) {
|
||||
this->on_headphone_volume_changed(v);
|
||||
};
|
||||
|
||||
view_frequency_options.hidden(true);
|
||||
view_frequency_options.set_step(receiver_model.frequency_step());
|
||||
view_frequency_options.on_change_step = [this](rf::Frequency f) {
|
||||
this->on_frequency_step_changed(f);
|
||||
};
|
||||
view_frequency_options.set_reference_ppm_correction(receiver_model.reference_ppm_correction());
|
||||
view_frequency_options.on_change_reference_ppm_correction = [this](int32_t v) {
|
||||
this->on_reference_ppm_correction_changed(v);
|
||||
};
|
||||
|
||||
view_rf_gain_options.hidden(true);
|
||||
view_rf_gain_options.set_rf_amp(receiver_model.rf_amp());
|
||||
view_rf_gain_options.on_change_rf_amp = [this](bool enable) {
|
||||
this->on_rf_amp_changed(enable);
|
||||
};
|
||||
|
||||
receiver_model.enable();
|
||||
}
|
||||
|
||||
ReceiverView::~ReceiverView() {
|
||||
|
||||
// TODO: Manipulating audio codec here, and in ui_receiver.cpp. Good to do
|
||||
// both?
|
||||
audio_codec.headphone_mute();
|
||||
|
||||
receiver_model.disable();
|
||||
}
|
||||
|
||||
void ReceiverView::on_show() {
|
||||
View::on_show();
|
||||
|
||||
// TODO: Separate concepts of baseband "modulation" and receiver "mode".
|
||||
on_modulation_changed(static_cast<ReceiverModel::Mode>(receiver_model.modulation()));
|
||||
}
|
||||
|
||||
void ReceiverView::on_hide() {
|
||||
on_modulation_changed(static_cast<ReceiverModel::Mode>(-1));
|
||||
|
||||
View::on_hide();
|
||||
}
|
||||
|
||||
void ReceiverView::focus() {
|
||||
field_frequency.focus();
|
||||
}
|
||||
|
||||
void ReceiverView::on_tuning_frequency_changed(rf::Frequency f) {
|
||||
receiver_model.set_tuning_frequency(f);
|
||||
}
|
||||
|
||||
void ReceiverView::on_baseband_bandwidth_changed(uint32_t bandwidth_hz) {
|
||||
receiver_model.set_baseband_bandwidth(bandwidth_hz);
|
||||
}
|
||||
|
||||
void ReceiverView::on_rf_amp_changed(bool v) {
|
||||
receiver_model.set_rf_amp(v);
|
||||
}
|
||||
|
||||
void ReceiverView::on_lna_changed(int32_t v_db) {
|
||||
receiver_model.set_lna(v_db);
|
||||
}
|
||||
|
||||
void ReceiverView::on_vga_changed(int32_t v_db) {
|
||||
receiver_model.set_vga(v_db);
|
||||
}
|
||||
|
||||
void ReceiverView::on_modulation_changed(ReceiverModel::Mode mode) {
|
||||
remove_child(widget_content.get());
|
||||
widget_content.reset();
|
||||
|
||||
switch(mode) {
|
||||
case ReceiverModel::Mode::AMAudio:
|
||||
case ReceiverModel::Mode::NarrowbandFMAudio:
|
||||
case ReceiverModel::Mode::WidebandFMAudio:
|
||||
widget_content = std::make_unique<AnalogAudioView>(mode);
|
||||
break;
|
||||
|
||||
case ReceiverModel::Mode::SpectrumAnalysis:
|
||||
widget_content = std::make_unique<SpectrumAnalysisView>();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if( widget_content ) {
|
||||
add_child(widget_content.get());
|
||||
const ui::Rect rect { 0, header_height, parent_rect.width(), static_cast<ui::Dim>(parent_rect.height() - header_height) };
|
||||
widget_content->set_parent_rect(rect);
|
||||
}
|
||||
}
|
||||
|
||||
void ReceiverView::on_show_options_frequency() {
|
||||
view_rf_gain_options.hidden(true);
|
||||
field_lna.set_style(nullptr);
|
||||
|
||||
view_frequency_options.hidden(false);
|
||||
field_frequency.set_style(&view_frequency_options.style());
|
||||
}
|
||||
|
||||
void ReceiverView::on_show_options_rf_gain() {
|
||||
view_frequency_options.hidden(true);
|
||||
field_frequency.set_style(nullptr);
|
||||
|
||||
view_rf_gain_options.hidden(false);
|
||||
field_lna.set_style(&view_frequency_options.style());
|
||||
}
|
||||
|
||||
void ReceiverView::on_frequency_step_changed(rf::Frequency f) {
|
||||
receiver_model.set_frequency_step(f);
|
||||
field_frequency.set_step(f);
|
||||
}
|
||||
|
||||
void ReceiverView::on_reference_ppm_correction_changed(int32_t v) {
|
||||
receiver_model.set_reference_ppm_correction(v);
|
||||
}
|
||||
|
||||
void ReceiverView::on_headphone_volume_changed(int32_t v) {
|
||||
const auto new_volume = volume_t::decibel(v - 99) + wolfson::wm8731::headphone_gain_range.max;
|
||||
receiver_model.set_headphone_volume(new_volume);
|
||||
}
|
||||
|
||||
} /* namespace ui */
|
||||
|
|
|
@ -23,19 +23,11 @@
|
|||
#define __UI_RECEIVER_H__
|
||||
|
||||
#include "ui.hpp"
|
||||
#include "ui_font_fixed_8x16.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
#include "ui_painter.hpp"
|
||||
#include "ui_widget.hpp"
|
||||
|
||||
#include "utility.hpp"
|
||||
|
||||
#include "max2837.hpp"
|
||||
#include "rf_path.hpp"
|
||||
#include "volume.hpp"
|
||||
#include "wm8731.hpp"
|
||||
|
||||
#include "receiver_model.hpp"
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
@ -323,98 +315,6 @@ public:
|
|||
void on_focus() override;
|
||||
};
|
||||
|
||||
constexpr Style style_options_group {
|
||||
.font = font::fixed_8x16,
|
||||
.background = Color::blue(),
|
||||
.foreground = Color::white(),
|
||||
};
|
||||
|
||||
class ReceiverView : public View {
|
||||
public:
|
||||
ReceiverView(NavigationView& nav);
|
||||
~ReceiverView();
|
||||
|
||||
void on_show() override;
|
||||
void on_hide() override;
|
||||
|
||||
void focus() override;
|
||||
|
||||
private:
|
||||
static constexpr ui::Dim header_height = 2 * 16;
|
||||
|
||||
RSSI rssi {
|
||||
{ 21 * 8, 0, 6 * 8, 4 },
|
||||
};
|
||||
|
||||
Channel channel {
|
||||
{ 21 * 8, 5, 6 * 8, 4 },
|
||||
};
|
||||
|
||||
Audio audio {
|
||||
{ 21 * 8, 10, 6 * 8, 4 },
|
||||
};
|
||||
|
||||
FrequencyField field_frequency {
|
||||
{ 5 * 8, 0 * 16 },
|
||||
};
|
||||
|
||||
LNAGainField field_lna {
|
||||
{ 15 * 8, 0 * 16 }
|
||||
};
|
||||
|
||||
NumberField field_vga {
|
||||
{ 18 * 8, 0 * 16},
|
||||
2,
|
||||
{ max2837::vga::gain_db_range.minimum, max2837::vga::gain_db_range.maximum },
|
||||
max2837::vga::gain_db_step,
|
||||
' ',
|
||||
};
|
||||
|
||||
OptionsField options_modulation {
|
||||
{ 0 * 8, 0 * 16 },
|
||||
4,
|
||||
{
|
||||
{ " AM ", toUType(ReceiverModel::Mode::AMAudio) },
|
||||
{ "NFM ", toUType(ReceiverModel::Mode::NarrowbandFMAudio) },
|
||||
{ "WFM ", toUType(ReceiverModel::Mode::WidebandFMAudio) },
|
||||
{ "SPEC", toUType(ReceiverModel::Mode::SpectrumAnalysis) },
|
||||
}
|
||||
};
|
||||
|
||||
NumberField field_volume {
|
||||
{ 28 * 8, 0 * 16 },
|
||||
2,
|
||||
{ 0, 99 },
|
||||
1,
|
||||
' ',
|
||||
};
|
||||
|
||||
FrequencyOptionsView view_frequency_options {
|
||||
{ 0 * 8, 1 * 16, 30 * 8, 1 * 16 },
|
||||
&style_options_group
|
||||
};
|
||||
|
||||
RadioGainOptionsView view_rf_gain_options {
|
||||
{ 0 * 8, 1 * 16, 30 * 8, 1 * 16 },
|
||||
&style_options_group
|
||||
};
|
||||
|
||||
std::unique_ptr<Widget> widget_content;
|
||||
|
||||
void on_tuning_frequency_changed(rf::Frequency f);
|
||||
void on_baseband_bandwidth_changed(uint32_t bandwidth_hz);
|
||||
void on_rf_amp_changed(bool v);
|
||||
void on_lna_changed(int32_t v_db);
|
||||
void on_vga_changed(int32_t v_db);
|
||||
void on_modulation_changed(ReceiverModel::Mode mode);
|
||||
void on_show_options_frequency();
|
||||
void on_show_options_rf_gain();
|
||||
void on_frequency_step_changed(rf::Frequency f);
|
||||
void on_reference_ppm_correction_changed(int32_t v);
|
||||
void on_headphone_volume_changed(int32_t v);
|
||||
void on_edit_frequency();
|
||||
};
|
||||
|
||||
} /* namespace ui */
|
||||
|
||||
#endif/*__UI_RECEIVER_H__*/
|
||||
|
|
|
@ -28,12 +28,93 @@ namespace ui {
|
|||
|
||||
/* SDCardStatusView *****************************************************/
|
||||
|
||||
SDCardStatusView::SDCardStatusView() {
|
||||
add_children({ {
|
||||
&text_status,
|
||||
} });
|
||||
namespace detail {
|
||||
|
||||
on_status(sd_card::status());
|
||||
static constexpr uint8_t bitmap_sd_card_ok_data[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0xe0, 0x1f, 0xf0, 0x1f,
|
||||
0xf8, 0x1f, 0xf8, 0x1f, 0xf8, 0x1f, 0xf8, 0x1f,
|
||||
0xf8, 0x1f, 0xf8, 0x1f, 0xf8, 0x1f, 0xf8, 0x1f,
|
||||
0xf8, 0x1f, 0xf8, 0x1f, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
static constexpr Bitmap bitmap_sd_card_ok {
|
||||
{ 16, 16 }, bitmap_sd_card_ok_data
|
||||
};
|
||||
|
||||
static constexpr uint8_t bitmap_sd_card_unknown_data[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0xe0, 0x1f, 0xf0, 0x1f,
|
||||
0x38, 0x1c, 0x98, 0x19, 0xf8, 0x19, 0xf8, 0x1c,
|
||||
0x78, 0x1e, 0x78, 0x1e, 0xf8, 0x1f, 0x78, 0x1e,
|
||||
0xf8, 0x1f, 0xf8, 0x1f, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
static constexpr Bitmap bitmap_sd_card_unknown {
|
||||
{ 16, 16 }, bitmap_sd_card_unknown_data
|
||||
};
|
||||
|
||||
static constexpr uint8_t bitmap_sd_card_error_data[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0xe0, 0x1f, 0xf0, 0x1f,
|
||||
0xf8, 0x1f, 0xf8, 0x1b, 0xf8, 0x19, 0xf8, 0x1c,
|
||||
0xf8, 0x1e, 0xf8, 0x1c, 0xf8, 0x19, 0xf8, 0x1b,
|
||||
0xf8, 0x1f, 0xf8, 0x1f, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
static constexpr Bitmap bitmap_sd_card_error {
|
||||
{ 16, 16 }, bitmap_sd_card_error_data
|
||||
};
|
||||
|
||||
const Bitmap& bitmap_sd_card(const sd_card::Status status) {
|
||||
switch(status) {
|
||||
case sd_card::Status::IOError:
|
||||
case sd_card::Status::MountError:
|
||||
case sd_card::Status::ConnectError:
|
||||
return bitmap_sd_card_error;
|
||||
|
||||
case sd_card::Status::NotPresent:
|
||||
return bitmap_sd_card_unknown;
|
||||
|
||||
case sd_card::Status::Present:
|
||||
return bitmap_sd_card_unknown;
|
||||
|
||||
case sd_card::Status::Mounted:
|
||||
return bitmap_sd_card_ok;
|
||||
|
||||
default:
|
||||
return bitmap_sd_card_unknown;
|
||||
}
|
||||
}
|
||||
|
||||
static constexpr Color color_sd_card_error = Color::red();
|
||||
static constexpr Color color_sd_card_unknown = Color::yellow();
|
||||
static constexpr Color color_sd_card_ok = Color::green();
|
||||
|
||||
const Color color_sd_card(const sd_card::Status status) {
|
||||
switch(status) {
|
||||
case sd_card::Status::IOError:
|
||||
case sd_card::Status::MountError:
|
||||
case sd_card::Status::ConnectError:
|
||||
return color_sd_card_error;
|
||||
|
||||
case sd_card::Status::NotPresent:
|
||||
return color_sd_card_unknown;
|
||||
|
||||
case sd_card::Status::Present:
|
||||
return color_sd_card_unknown;
|
||||
|
||||
case sd_card::Status::Mounted:
|
||||
return color_sd_card_ok;
|
||||
|
||||
default:
|
||||
return color_sd_card_unknown;
|
||||
}
|
||||
}
|
||||
|
||||
} /* namespace detail */
|
||||
|
||||
SDCardStatusView::SDCardStatusView(
|
||||
const Rect parent_rect
|
||||
) : Image { parent_rect, &detail::bitmap_sd_card_unknown, detail::color_sd_card_unknown, Color::black() }
|
||||
{
|
||||
}
|
||||
|
||||
void SDCardStatusView::on_show() {
|
||||
|
@ -46,40 +127,17 @@ void SDCardStatusView::on_hide() {
|
|||
sd_card::status_signal -= sd_card_status_signal_token;
|
||||
}
|
||||
|
||||
void SDCardStatusView::on_status(const sd_card::Status status) {
|
||||
std::string msg("??");
|
||||
void SDCardStatusView::paint(Painter& painter) {
|
||||
const auto status = sd_card::status();
|
||||
set_bitmap(&detail::bitmap_sd_card(status));
|
||||
set_foreground(detail::color_sd_card(status));
|
||||
|
||||
switch(status) {
|
||||
case sd_card::Status::IOError:
|
||||
msg = "IO";
|
||||
break;
|
||||
Image::paint(painter);
|
||||
}
|
||||
|
||||
case sd_card::Status::MountError:
|
||||
msg = "MT";
|
||||
break;
|
||||
|
||||
case sd_card::Status::ConnectError:
|
||||
msg = "CN";
|
||||
break;
|
||||
|
||||
case sd_card::Status::NotPresent:
|
||||
msg = "XX";
|
||||
break;
|
||||
|
||||
case sd_card::Status::Present:
|
||||
msg = "OO";
|
||||
break;
|
||||
|
||||
case sd_card::Status::Mounted:
|
||||
msg = "OK";
|
||||
break;
|
||||
|
||||
default:
|
||||
msg = "--";
|
||||
break;
|
||||
}
|
||||
|
||||
text_status.set(msg);
|
||||
void SDCardStatusView::on_status(const sd_card::Status) {
|
||||
// Don't update image properties here, they might change. Wait until paint.
|
||||
set_dirty();
|
||||
}
|
||||
|
||||
} /* namespace ui */
|
||||
|
|
|
@ -27,19 +27,16 @@
|
|||
|
||||
namespace ui {
|
||||
|
||||
class SDCardStatusView : public View {
|
||||
class SDCardStatusView : public Image {
|
||||
public:
|
||||
SDCardStatusView();
|
||||
|
||||
SDCardStatusView(const Rect parent_rect);
|
||||
|
||||
void on_show() override;
|
||||
void on_hide() override;
|
||||
|
||||
private:
|
||||
Text text_status {
|
||||
{ 0 * 8, 0, 2 * 8, 1 * 16 },
|
||||
"",
|
||||
};
|
||||
void paint(Painter& painter) override;
|
||||
|
||||
private:
|
||||
SignalToken sd_card_status_signal_token;
|
||||
|
||||
void on_status(const sd_card::Status status);
|
||||
|
|
|
@ -170,7 +170,19 @@ void AntennaBiasSetupView::focus() {
|
|||
button_done.focus();
|
||||
}
|
||||
|
||||
void SetTouchCalibView::focus() {
|
||||
AboutView::AboutView(NavigationView& nav) {
|
||||
add_children({ {
|
||||
&text_title,
|
||||
&text_firmware,
|
||||
&text_cpld_hackrf,
|
||||
&text_cpld_portapack,
|
||||
&button_ok,
|
||||
} });
|
||||
|
||||
button_ok.on_select = [&nav](Button&){ nav.pop(); };
|
||||
}
|
||||
|
||||
void AboutView::focus() {
|
||||
button_ok.focus();
|
||||
}
|
||||
|
||||
|
|
|
@ -84,7 +84,7 @@ public:
|
|||
private:
|
||||
WaterfallView waterfall_view;
|
||||
FrequencyScale frequency_scale;
|
||||
ChannelSpectrumFIFO* fifo;
|
||||
ChannelSpectrumFIFO* fifo { nullptr };
|
||||
|
||||
void on_channel_spectrum(const ChannelSpectrum& spectrum);
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue