mirror of
https://github.com/eried/portapack-mayhem.git
synced 2024-12-25 07:19:28 -05:00
Analog tv app (#334)
* Analog TV app (PAL) * Icon on main menu * Analog TV should be yellow Works for PAL only know, it would be nice to add NTSC in the future, or some customizable sync
This commit is contained in:
parent
40531e9230
commit
e43f814861
@ -209,6 +209,7 @@ set(CPPSRC
|
|||||||
ui/ui_btngrid.cpp
|
ui/ui_btngrid.cpp
|
||||||
ui/ui_receiver.cpp
|
ui/ui_receiver.cpp
|
||||||
ui/ui_rssi.cpp
|
ui/ui_rssi.cpp
|
||||||
|
ui/ui_tv.cpp
|
||||||
ui/ui_spectrum.cpp
|
ui/ui_spectrum.cpp
|
||||||
ui/ui_tabview.cpp
|
ui/ui_tabview.cpp
|
||||||
ui/ui_textentry.cpp
|
ui/ui_textentry.cpp
|
||||||
@ -253,6 +254,7 @@ set(CPPSRC
|
|||||||
apps/acars_app.cpp
|
apps/acars_app.cpp
|
||||||
apps/ais_app.cpp
|
apps/ais_app.cpp
|
||||||
apps/analog_audio_app.cpp
|
apps/analog_audio_app.cpp
|
||||||
|
apps/analog_tv_app.cpp
|
||||||
apps/capture_app.cpp
|
apps/capture_app.cpp
|
||||||
apps/ert_app.cpp
|
apps/ert_app.cpp
|
||||||
apps/lge_app.cpp
|
apps/lge_app.cpp
|
||||||
|
238
firmware/application/apps/analog_tv_app.cpp
Normal file
238
firmware/application/apps/analog_tv_app.cpp
Normal file
@ -0,0 +1,238 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
|
||||||
|
* Copyright (C) 2018 Furrtek
|
||||||
|
* Copyright (C) 2020 Shao
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "analog_tv_app.hpp"
|
||||||
|
|
||||||
|
#include "baseband_api.hpp"
|
||||||
|
|
||||||
|
#include "portapack.hpp"
|
||||||
|
#include "portapack_persistent_memory.hpp"
|
||||||
|
using namespace portapack;
|
||||||
|
using namespace tonekey;
|
||||||
|
|
||||||
|
#include "audio.hpp"
|
||||||
|
#include "file.hpp"
|
||||||
|
|
||||||
|
#include "utility.hpp"
|
||||||
|
|
||||||
|
#include "string_format.hpp"
|
||||||
|
|
||||||
|
namespace ui {
|
||||||
|
|
||||||
|
/* AnalogTvView *******************************************************/
|
||||||
|
|
||||||
|
AnalogTvView::AnalogTvView(
|
||||||
|
NavigationView& nav
|
||||||
|
) : nav_ (nav)
|
||||||
|
{
|
||||||
|
add_children({
|
||||||
|
&rssi,
|
||||||
|
&channel,
|
||||||
|
&audio,
|
||||||
|
&field_frequency,
|
||||||
|
&field_lna,
|
||||||
|
&field_vga,
|
||||||
|
&options_modulation,
|
||||||
|
&field_volume,
|
||||||
|
&tv
|
||||||
|
});
|
||||||
|
|
||||||
|
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.on_show_options = [this]() {
|
||||||
|
this->on_show_options_rf_gain();
|
||||||
|
};
|
||||||
|
|
||||||
|
field_vga.on_show_options = [this]() {
|
||||||
|
this->on_show_options_rf_gain();
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto modulation = receiver_model.modulation();
|
||||||
|
options_modulation.set_by_value(toUType(ReceiverModel::Mode::WidebandFMAudio));
|
||||||
|
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(0);
|
||||||
|
field_volume.on_change = [this](int32_t v) {
|
||||||
|
this->on_headphone_volume_changed(v);
|
||||||
|
};
|
||||||
|
|
||||||
|
tv.on_select = [this](int32_t offset) {
|
||||||
|
field_frequency.set_value(receiver_model.tuning_frequency() + offset);
|
||||||
|
};
|
||||||
|
|
||||||
|
update_modulation(static_cast<ReceiverModel::Mode>(modulation));
|
||||||
|
on_modulation_changed(ReceiverModel::Mode::WidebandFMAudio);
|
||||||
|
}
|
||||||
|
|
||||||
|
AnalogTvView::~AnalogTvView() {
|
||||||
|
// TODO: Manipulating audio codec here, and in ui_receiver.cpp. Good to do
|
||||||
|
// both?
|
||||||
|
audio::output::stop();
|
||||||
|
|
||||||
|
receiver_model.disable();
|
||||||
|
|
||||||
|
baseband::shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnalogTvView::on_hide() {
|
||||||
|
// TODO: Terrible kludge because widget system doesn't notify Waterfall that
|
||||||
|
// it's being shown or hidden.
|
||||||
|
tv.on_hide();
|
||||||
|
View::on_hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnalogTvView::set_parent_rect(const Rect new_parent_rect) {
|
||||||
|
View::set_parent_rect(new_parent_rect);
|
||||||
|
|
||||||
|
const ui::Rect tv_rect { 0, header_height, new_parent_rect.width(), new_parent_rect.height() - header_height };
|
||||||
|
tv.set_parent_rect(tv_rect);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnalogTvView::focus() {
|
||||||
|
field_frequency.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnalogTvView::on_tuning_frequency_changed(rf::Frequency f) {
|
||||||
|
receiver_model.set_tuning_frequency(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnalogTvView::on_baseband_bandwidth_changed(uint32_t bandwidth_hz) {
|
||||||
|
receiver_model.set_baseband_bandwidth(bandwidth_hz);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnalogTvView::on_modulation_changed(const ReceiverModel::Mode modulation) {
|
||||||
|
// TODO: Terrible kludge because widget system doesn't notify Waterfall that
|
||||||
|
// it's being shown or hidden.
|
||||||
|
tv.on_hide();
|
||||||
|
update_modulation(modulation);
|
||||||
|
on_show_options_modulation();
|
||||||
|
tv.on_show();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnalogTvView::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 AnalogTvView::set_options_widget(std::unique_ptr<Widget> new_widget) {
|
||||||
|
remove_options_widget();
|
||||||
|
|
||||||
|
if( new_widget ) {
|
||||||
|
options_widget = std::move(new_widget);
|
||||||
|
} else {
|
||||||
|
// TODO: Lame hack to hide options view due to my bad paint/damage algorithm.
|
||||||
|
options_widget = std::make_unique<Rectangle>(options_view_rect, style_options_group_new.background);
|
||||||
|
}
|
||||||
|
add_child(options_widget.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnalogTvView::on_show_options_frequency() {
|
||||||
|
auto widget = std::make_unique<FrequencyOptionsView>(options_view_rect, &style_options_group_new);
|
||||||
|
|
||||||
|
widget->set_step(receiver_model.frequency_step());
|
||||||
|
widget->on_change_step = [this](rf::Frequency f) {
|
||||||
|
this->on_frequency_step_changed(f);
|
||||||
|
};
|
||||||
|
widget->set_reference_ppm_correction(persistent_memory::correction_ppb() / 1000);
|
||||||
|
widget->on_change_reference_ppm_correction = [this](int32_t v) {
|
||||||
|
this->on_reference_ppm_correction_changed(v);
|
||||||
|
};
|
||||||
|
|
||||||
|
set_options_widget(std::move(widget));
|
||||||
|
field_frequency.set_style(&style_options_group_new);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnalogTvView::on_show_options_rf_gain() {
|
||||||
|
auto widget = std::make_unique<RadioGainOptionsView>(options_view_rect, &style_options_group_new);
|
||||||
|
|
||||||
|
set_options_widget(std::move(widget));
|
||||||
|
field_lna.set_style(&style_options_group_new);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnalogTvView::on_show_options_modulation() {
|
||||||
|
std::unique_ptr<Widget> widget;
|
||||||
|
|
||||||
|
const auto modulation = static_cast<ReceiverModel::Mode>(receiver_model.modulation());
|
||||||
|
tv.show_audio_spectrum_view(true);
|
||||||
|
|
||||||
|
set_options_widget(std::move(widget));
|
||||||
|
options_modulation.set_style(&style_options_group_new);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnalogTvView::on_frequency_step_changed(rf::Frequency f) {
|
||||||
|
receiver_model.set_frequency_step(f);
|
||||||
|
field_frequency.set_step(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnalogTvView::on_reference_ppm_correction_changed(int32_t v) {
|
||||||
|
persistent_memory::set_correction_ppb(v * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnalogTvView::on_headphone_volume_changed(int32_t v) {
|
||||||
|
//tv::TVView::set_headphone_volume(this,v);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnalogTvView::update_modulation(const ReceiverModel::Mode modulation) {
|
||||||
|
audio::output::mute();
|
||||||
|
|
||||||
|
baseband::shutdown();
|
||||||
|
|
||||||
|
portapack::spi_flash::image_tag_t image_tag;
|
||||||
|
image_tag = portapack::spi_flash::image_tag_am_tv;
|
||||||
|
|
||||||
|
baseband::run_image(image_tag);
|
||||||
|
|
||||||
|
receiver_model.set_modulation(modulation);
|
||||||
|
receiver_model.set_sampling_rate(2000000);
|
||||||
|
receiver_model.set_baseband_bandwidth(2000000);
|
||||||
|
receiver_model.enable();
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* namespace ui */
|
133
firmware/application/apps/analog_tv_app.hpp
Normal file
133
firmware/application/apps/analog_tv_app.hpp
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
|
||||||
|
* Copyright (C) 2018 Furrtek
|
||||||
|
* Copyright (C) 2020 Shao
|
||||||
|
*
|
||||||
|
* 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_TV_APP_H__
|
||||||
|
#define __ANALOG_TV_APP_H__
|
||||||
|
|
||||||
|
#include "receiver_model.hpp"
|
||||||
|
|
||||||
|
#include "ui_receiver.hpp"
|
||||||
|
#include "ui_tv.hpp"
|
||||||
|
#include "ui_record_view.hpp"
|
||||||
|
|
||||||
|
#include "ui_font_fixed_8x16.hpp"
|
||||||
|
|
||||||
|
#include "tone_key.hpp"
|
||||||
|
|
||||||
|
namespace ui {
|
||||||
|
|
||||||
|
constexpr Style style_options_group_new {
|
||||||
|
.font = font::fixed_8x16,
|
||||||
|
.background = Color::blue(),
|
||||||
|
.foreground = Color::white(),
|
||||||
|
};
|
||||||
|
|
||||||
|
class AnalogTvView : public View {
|
||||||
|
public:
|
||||||
|
AnalogTvView(NavigationView& nav);
|
||||||
|
~AnalogTvView();
|
||||||
|
|
||||||
|
void on_hide() override;
|
||||||
|
|
||||||
|
void set_parent_rect(const Rect new_parent_rect) override;
|
||||||
|
|
||||||
|
void focus() override;
|
||||||
|
|
||||||
|
std::string title() const override { return "Analog TV"; };
|
||||||
|
|
||||||
|
private:
|
||||||
|
static constexpr ui::Dim header_height = 3 * 16;
|
||||||
|
|
||||||
|
const Rect options_view_rect { 0 * 8, 1 * 16, 30 * 8, 1 * 16 };
|
||||||
|
const Rect nbfm_view_rect { 0 * 8, 1 * 16, 18 * 8, 1 * 16 };
|
||||||
|
|
||||||
|
NavigationView& nav_;
|
||||||
|
|
||||||
|
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 }
|
||||||
|
};
|
||||||
|
|
||||||
|
VGAGainField field_vga {
|
||||||
|
{ 18 * 8, 0 * 16 }
|
||||||
|
};
|
||||||
|
|
||||||
|
OptionsField options_modulation {
|
||||||
|
{ 0 * 8, 0 * 16 },
|
||||||
|
4,
|
||||||
|
{
|
||||||
|
{ "TV ", toUType(ReceiverModel::Mode::WidebandFMAudio) },
|
||||||
|
{ "TV ", toUType(ReceiverModel::Mode::WidebandFMAudio) },
|
||||||
|
{ "TV ", toUType(ReceiverModel::Mode::WidebandFMAudio) },
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
NumberField field_volume {
|
||||||
|
{ 27 * 8, 0 * 16 },
|
||||||
|
3,
|
||||||
|
{ 0, 255 },
|
||||||
|
1,
|
||||||
|
' ',
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<Widget> options_widget { };
|
||||||
|
|
||||||
|
tv::TVWidget tv { true };
|
||||||
|
|
||||||
|
void on_tuning_frequency_changed(rf::Frequency f);
|
||||||
|
void on_baseband_bandwidth_changed(uint32_t bandwidth_hz);
|
||||||
|
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 */
|
||||||
|
|
||||||
|
#endif/*__ANALOG_TV_APP_H__*/
|
@ -538,3 +538,262 @@ const std::array<ui::Color, 256> spectrum_rgb3_lut { {
|
|||||||
{ 252, 3, 0 },
|
{ 252, 3, 0 },
|
||||||
{ 255, 0, 0 },
|
{ 255, 0, 0 },
|
||||||
} };
|
} };
|
||||||
|
|
||||||
|
const std::array<ui::Color, 256> spectrum_rgb4_lut { {
|
||||||
|
{ 0, 0, 0 },
|
||||||
|
{ 1, 1, 1 },
|
||||||
|
{ 2, 2, 2 },
|
||||||
|
{ 3, 3, 3 },
|
||||||
|
{ 4, 4, 4 },
|
||||||
|
{ 5, 5, 5 },
|
||||||
|
{ 6, 6, 6 },
|
||||||
|
{ 7, 7, 7 },
|
||||||
|
{ 8, 8, 8 },
|
||||||
|
{ 9, 9, 9 },
|
||||||
|
{ 10, 10, 10 },
|
||||||
|
{ 11, 11, 11 },
|
||||||
|
{ 12, 12, 12 },
|
||||||
|
{ 13, 13, 13 },
|
||||||
|
{ 14, 14, 14 },
|
||||||
|
{ 15, 15, 15 },
|
||||||
|
{ 16, 16, 16 },
|
||||||
|
{ 17, 17, 17 },
|
||||||
|
{ 18, 18, 18 },
|
||||||
|
{ 19, 19, 19 },
|
||||||
|
{ 20, 20, 20 },
|
||||||
|
{ 21, 21, 21 },
|
||||||
|
{ 22, 22, 22 },
|
||||||
|
{ 23, 23, 23 },
|
||||||
|
{ 24, 24, 24 },
|
||||||
|
{ 25, 25, 25 },
|
||||||
|
{ 26, 26, 26 },
|
||||||
|
{ 27, 27, 27 },
|
||||||
|
{ 28, 28, 28 },
|
||||||
|
{ 29, 29, 29 },
|
||||||
|
{ 30, 30, 30 },
|
||||||
|
{ 31, 31, 31 },
|
||||||
|
{ 32, 32, 32 },
|
||||||
|
{ 33, 33, 33 },
|
||||||
|
{ 34, 34, 34 },
|
||||||
|
{ 35, 35, 35 },
|
||||||
|
{ 36, 36, 36 },
|
||||||
|
{ 37, 37, 37 },
|
||||||
|
{ 38, 38, 38 },
|
||||||
|
{ 39, 39, 39 },
|
||||||
|
{ 40, 40, 40 },
|
||||||
|
{ 41, 41, 41 },
|
||||||
|
{ 42, 42, 42 },
|
||||||
|
{ 43, 43, 43 },
|
||||||
|
{ 44, 44, 44 },
|
||||||
|
{ 45, 45, 45 },
|
||||||
|
{ 46, 46, 46 },
|
||||||
|
{ 47, 47, 47 },
|
||||||
|
{ 48, 48, 48 },
|
||||||
|
{ 49, 49, 49 },
|
||||||
|
{ 50, 50, 50 },
|
||||||
|
{ 51, 51, 51 },
|
||||||
|
{ 52, 52, 52 },
|
||||||
|
{ 53, 53, 53 },
|
||||||
|
{ 54, 54, 54 },
|
||||||
|
{ 55, 55, 55 },
|
||||||
|
{ 56, 56, 56 },
|
||||||
|
{ 57, 57, 57 },
|
||||||
|
{ 58, 58, 58 },
|
||||||
|
{ 59, 59, 59 },
|
||||||
|
{ 60, 60, 60 },
|
||||||
|
{ 61, 61, 61 },
|
||||||
|
{ 62, 62, 62 },
|
||||||
|
{ 63, 63, 63 },
|
||||||
|
{ 64, 64, 64 },
|
||||||
|
{ 65, 65, 65 },
|
||||||
|
{ 66, 66, 66 },
|
||||||
|
{ 67, 67, 67 },
|
||||||
|
{ 68, 68, 68 },
|
||||||
|
{ 69, 69, 69 },
|
||||||
|
{ 70, 70, 70 },
|
||||||
|
{ 71, 71, 71 },
|
||||||
|
{ 72, 72, 72 },
|
||||||
|
{ 73, 73, 73 },
|
||||||
|
{ 74, 74, 74 },
|
||||||
|
{ 75, 75, 75 },
|
||||||
|
{ 76, 76, 76 },
|
||||||
|
{ 77, 77, 77 },
|
||||||
|
{ 78, 78, 78 },
|
||||||
|
{ 79, 79, 79 },
|
||||||
|
{ 80, 80, 80 },
|
||||||
|
{ 81, 81, 81 },
|
||||||
|
{ 82, 82, 82 },
|
||||||
|
{ 83, 83, 83 },
|
||||||
|
{ 84, 84, 84 },
|
||||||
|
{ 85, 85, 85 },
|
||||||
|
{ 86, 86, 86 },
|
||||||
|
{ 87, 87, 87 },
|
||||||
|
{ 88, 88, 88 },
|
||||||
|
{ 89, 89, 89 },
|
||||||
|
{ 90, 90, 90 },
|
||||||
|
{ 91, 91, 91 },
|
||||||
|
{ 92, 92, 92 },
|
||||||
|
{ 93, 93, 93 },
|
||||||
|
{ 94, 94, 94 },
|
||||||
|
{ 95, 95, 95 },
|
||||||
|
{ 96, 96, 96 },
|
||||||
|
{ 97, 97, 97 },
|
||||||
|
{ 98, 98, 98 },
|
||||||
|
{ 99, 99, 99 },
|
||||||
|
{ 100, 100, 100 },
|
||||||
|
{ 101, 101, 101 },
|
||||||
|
{ 102, 102, 102 },
|
||||||
|
{ 103, 103, 103 },
|
||||||
|
{ 104, 104, 104 },
|
||||||
|
{ 105, 105, 105 },
|
||||||
|
{ 106, 106, 106 },
|
||||||
|
{ 107, 107, 107 },
|
||||||
|
{ 108, 108, 108 },
|
||||||
|
{ 109, 109, 109 },
|
||||||
|
{ 110, 110, 110 },
|
||||||
|
{ 111, 111, 111 },
|
||||||
|
{ 112, 112, 112 },
|
||||||
|
{ 113, 113, 113 },
|
||||||
|
{ 114, 114, 114 },
|
||||||
|
{ 115, 115, 115 },
|
||||||
|
{ 116, 116, 116 },
|
||||||
|
{ 117, 117, 117 },
|
||||||
|
{ 118, 118, 118 },
|
||||||
|
{ 119, 119, 119 },
|
||||||
|
{ 120, 120, 120 },
|
||||||
|
{ 121, 121, 121 },
|
||||||
|
{ 122, 122, 122 },
|
||||||
|
{ 123, 123, 123 },
|
||||||
|
{ 124, 124, 124 },
|
||||||
|
{ 125, 125, 125 },
|
||||||
|
{ 126, 126, 126 },
|
||||||
|
{ 127, 127, 127 },
|
||||||
|
{ 128, 128, 128 },
|
||||||
|
{ 129, 129, 129 },
|
||||||
|
{ 130, 130, 130 },
|
||||||
|
{ 131, 131, 131 },
|
||||||
|
{ 132, 132, 132 },
|
||||||
|
{ 133, 133, 133 },
|
||||||
|
{ 134, 134, 134 },
|
||||||
|
{ 135, 135, 135 },
|
||||||
|
{ 136, 136, 136 },
|
||||||
|
{ 137, 137, 137 },
|
||||||
|
{ 138, 138, 138 },
|
||||||
|
{ 139, 139, 139 },
|
||||||
|
{ 140, 140, 140 },
|
||||||
|
{ 141, 141, 141 },
|
||||||
|
{ 142, 142, 142 },
|
||||||
|
{ 143, 143, 143 },
|
||||||
|
{ 144, 144, 144 },
|
||||||
|
{ 145, 145, 145 },
|
||||||
|
{ 146, 146, 146 },
|
||||||
|
{ 147, 147, 147 },
|
||||||
|
{ 148, 148, 148 },
|
||||||
|
{ 149, 149, 149 },
|
||||||
|
{ 150, 150, 150 },
|
||||||
|
{ 151, 151, 151 },
|
||||||
|
{ 152, 152, 152 },
|
||||||
|
{ 153, 153, 153 },
|
||||||
|
{ 154, 154, 154 },
|
||||||
|
{ 155, 155, 155 },
|
||||||
|
{ 156, 156, 156 },
|
||||||
|
{ 157, 157, 157 },
|
||||||
|
{ 158, 158, 158 },
|
||||||
|
{ 159, 159, 159 },
|
||||||
|
{ 160, 160, 160 },
|
||||||
|
{ 161, 161, 161 },
|
||||||
|
{ 162, 162, 162 },
|
||||||
|
{ 163, 163, 163 },
|
||||||
|
{ 164, 164, 164 },
|
||||||
|
{ 165, 165, 165 },
|
||||||
|
{ 166, 166, 166 },
|
||||||
|
{ 167, 167, 167 },
|
||||||
|
{ 168, 168, 168 },
|
||||||
|
{ 169, 169, 169 },
|
||||||
|
{ 170, 170, 170 },
|
||||||
|
{ 171, 171, 171 },
|
||||||
|
{ 172, 172, 172 },
|
||||||
|
{ 173, 173, 173 },
|
||||||
|
{ 174, 174, 174 },
|
||||||
|
{ 175, 175, 175 },
|
||||||
|
{ 176, 176, 176 },
|
||||||
|
{ 177, 177, 177 },
|
||||||
|
{ 178, 178, 178 },
|
||||||
|
{ 179, 179, 179 },
|
||||||
|
{ 180, 180, 180 },
|
||||||
|
{ 181, 181, 181 },
|
||||||
|
{ 182, 182, 182 },
|
||||||
|
{ 183, 183, 183 },
|
||||||
|
{ 184, 184, 184 },
|
||||||
|
{ 185, 185, 185 },
|
||||||
|
{ 186, 186, 186 },
|
||||||
|
{ 187, 187, 187 },
|
||||||
|
{ 188, 188, 188 },
|
||||||
|
{ 189, 189, 189 },
|
||||||
|
{ 190, 190, 190 },
|
||||||
|
{ 191, 191, 191 },
|
||||||
|
{ 192, 192, 192 },
|
||||||
|
{ 193, 193, 193 },
|
||||||
|
{ 194, 194, 194 },
|
||||||
|
{ 195, 195, 195 },
|
||||||
|
{ 196, 196, 196 },
|
||||||
|
{ 197, 197, 197 },
|
||||||
|
{ 198, 198, 198 },
|
||||||
|
{ 199, 199, 199 },
|
||||||
|
{ 200, 200, 200 },
|
||||||
|
{ 201, 201, 201 },
|
||||||
|
{ 202, 202, 202 },
|
||||||
|
{ 203, 203, 203 },
|
||||||
|
{ 204, 204, 204 },
|
||||||
|
{ 205, 205, 205 },
|
||||||
|
{ 206, 206, 206 },
|
||||||
|
{ 207, 207, 207 },
|
||||||
|
{ 208, 208, 208 },
|
||||||
|
{ 209, 209, 209 },
|
||||||
|
{ 210, 210, 210 },
|
||||||
|
{ 211, 211, 211 },
|
||||||
|
{ 212, 212, 212 },
|
||||||
|
{ 213, 213, 213 },
|
||||||
|
{ 214, 214, 214 },
|
||||||
|
{ 215, 215, 215 },
|
||||||
|
{ 216, 216, 216 },
|
||||||
|
{ 217, 217, 217 },
|
||||||
|
{ 218, 218, 218 },
|
||||||
|
{ 219, 219, 219 },
|
||||||
|
{ 220, 220, 220 },
|
||||||
|
{ 221, 221, 221 },
|
||||||
|
{ 222, 222, 222 },
|
||||||
|
{ 223, 223, 223 },
|
||||||
|
{ 224, 224, 224 },
|
||||||
|
{ 225, 225, 225 },
|
||||||
|
{ 226, 226, 226 },
|
||||||
|
{ 227, 227, 227 },
|
||||||
|
{ 228, 228, 228 },
|
||||||
|
{ 229, 229, 229 },
|
||||||
|
{ 230, 230, 230 },
|
||||||
|
{ 231, 231, 231 },
|
||||||
|
{ 232, 232, 232 },
|
||||||
|
{ 233, 233, 233 },
|
||||||
|
{ 234, 234, 234 },
|
||||||
|
{ 235, 235, 235 },
|
||||||
|
{ 236, 236, 236 },
|
||||||
|
{ 237, 237, 237 },
|
||||||
|
{ 238, 238, 238 },
|
||||||
|
{ 239, 239, 239 },
|
||||||
|
{ 240, 240, 240 },
|
||||||
|
{ 241, 241, 241 },
|
||||||
|
{ 242, 242, 242 },
|
||||||
|
{ 243, 243, 243 },
|
||||||
|
{ 244, 244, 244 },
|
||||||
|
{ 245, 245, 245 },
|
||||||
|
{ 246, 246, 246 },
|
||||||
|
{ 247, 247, 247 },
|
||||||
|
{ 248, 248, 248 },
|
||||||
|
{ 249, 249, 249 },
|
||||||
|
{ 250, 250, 250 },
|
||||||
|
{ 251, 251, 251 },
|
||||||
|
{ 252, 252, 252 },
|
||||||
|
{ 253, 253, 253 },
|
||||||
|
{ 254, 254, 254 },
|
||||||
|
{ 255, 255, 255 },
|
||||||
|
} };
|
||||||
|
@ -28,5 +28,6 @@
|
|||||||
|
|
||||||
extern const std::array<ui::Color, 256> spectrum_rgb2_lut;
|
extern const std::array<ui::Color, 256> spectrum_rgb2_lut;
|
||||||
extern const std::array<ui::Color, 256> spectrum_rgb3_lut;
|
extern const std::array<ui::Color, 256> spectrum_rgb3_lut;
|
||||||
|
extern const std::array<ui::Color, 256> spectrum_rgb4_lut;
|
||||||
|
|
||||||
#endif/*__SPECTRUM_COLOR_LUT_H__*/
|
#endif/*__SPECTRUM_COLOR_LUT_H__*/
|
||||||
|
251
firmware/application/ui/ui_tv.cpp
Normal file
251
firmware/application/ui/ui_tv.cpp
Normal file
@ -0,0 +1,251 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||||
|
* Copyright (C) 2020 Shao
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ui_tv.hpp"
|
||||||
|
|
||||||
|
#include "spectrum_color_lut.hpp"
|
||||||
|
|
||||||
|
#include "portapack.hpp"
|
||||||
|
using namespace portapack;
|
||||||
|
|
||||||
|
#include "baseband_api.hpp"
|
||||||
|
|
||||||
|
#include "string_format.hpp"
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
namespace ui {
|
||||||
|
namespace tv {
|
||||||
|
|
||||||
|
/* TimeScopeView******************************************************/
|
||||||
|
|
||||||
|
TimeScopeView::TimeScopeView(
|
||||||
|
const Rect parent_rect
|
||||||
|
) : View { parent_rect }
|
||||||
|
{
|
||||||
|
set_focusable(true);
|
||||||
|
|
||||||
|
add_children({
|
||||||
|
//&labels,
|
||||||
|
//&field_frequency,
|
||||||
|
&waveform
|
||||||
|
});
|
||||||
|
|
||||||
|
/*field_frequency.on_change = [this](int32_t) {
|
||||||
|
set_dirty();
|
||||||
|
};
|
||||||
|
field_frequency.set_value(10);*/
|
||||||
|
}
|
||||||
|
|
||||||
|
void TimeScopeView::paint(Painter& painter) {
|
||||||
|
const auto r = screen_rect();
|
||||||
|
|
||||||
|
painter.fill_rectangle(r, Color::black());
|
||||||
|
|
||||||
|
// Cursor
|
||||||
|
/*
|
||||||
|
const Rect r_cursor {
|
||||||
|
field_frequency.value() / (48000 / 240), r.bottom() - 32 - cursor_band_height,
|
||||||
|
1, cursor_band_height
|
||||||
|
};
|
||||||
|
painter.fill_rectangle(
|
||||||
|
r_cursor,
|
||||||
|
Color::red()
|
||||||
|
);*/
|
||||||
|
}
|
||||||
|
|
||||||
|
void TimeScopeView::on_audio_spectrum(const AudioSpectrum* spectrum) {
|
||||||
|
for (size_t i = 0; i < spectrum->db.size(); i++)
|
||||||
|
audio_spectrum[i] = ((int16_t)spectrum->db[i] - 127) * 256;
|
||||||
|
waveform.set_dirty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TVView *********************************************************/
|
||||||
|
|
||||||
|
void TVView::on_show() {
|
||||||
|
clear();
|
||||||
|
|
||||||
|
const auto screen_r = screen_rect();
|
||||||
|
display.scroll_set_area(screen_r.top(), screen_r.bottom());
|
||||||
|
}
|
||||||
|
|
||||||
|
void TVView::on_hide() {
|
||||||
|
/* TODO: Clear region to eliminate brief flash of content at un-shifted
|
||||||
|
* position?
|
||||||
|
*/
|
||||||
|
display.scroll_disable();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TVView::paint(Painter& painter) {
|
||||||
|
// Do nothing.
|
||||||
|
(void)painter;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TVView::on_adjust_xcorr(uint8_t xcorr){
|
||||||
|
x_correction = xcorr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TVView::on_channel_spectrum(
|
||||||
|
const ChannelSpectrum& spectrum
|
||||||
|
) {
|
||||||
|
//portapack has limitations
|
||||||
|
// 1.screen resolution (less than 240x320) 2.samples each call back (128 or 256)
|
||||||
|
// 3.memory size (for ui::Color, the buffer size
|
||||||
|
//spectrum.db[i] is 256 long
|
||||||
|
//768x625 ->128x625 ->128x312 -> 128x104
|
||||||
|
//originally @6MHz sample rate, the PAL should be 768x625
|
||||||
|
//I reduced sample rate to 2MHz(3 times less samples), then calculate mag (effectively decimate by 2)
|
||||||
|
//the resolution is now changed to 128x625. The total decimation factor is 6, which changes how many samples in a line
|
||||||
|
//However 625 is too large for the screen, also interlaced scanning is harder to realize in portapack than normal computer.
|
||||||
|
//So I decided to simply drop half of the lines, once y is larger than 625/2=312.5 or 312, I recognize it as a new frame.
|
||||||
|
//then the resolution is changed to 128x312
|
||||||
|
//128x312 is now able to put into a 240x320 screen, but the buffer for a whole frame is 128x312=39936, which is too large
|
||||||
|
//according to my test, I can only make a buffer with a length of 13312 of type ui::Color. which is 1/3 of what I wanted.
|
||||||
|
//So now the resolution is changed to 128x104, the height is shrinked to 1/3 of the original height.
|
||||||
|
//I was expecting to see 1/3 height of original video.
|
||||||
|
|
||||||
|
//Look how nice is that! I am now able to meet the requirements of 1 and 3 for portapack. Also the length of a line is 128
|
||||||
|
//Each call back gives me 256 samples which is exactly 2 lines. What a coincidence!
|
||||||
|
|
||||||
|
//After some experiment, I did some improvements.
|
||||||
|
//1.I found that instead of 1/3 of the frame is shown, I got 3 whole frames shrinked into one window.
|
||||||
|
//So I made the height twice simply by painting 2 identical lines in the place of original lines
|
||||||
|
//2.I found sometimes there is an horizontal offset, so I added x_correction to move the frame back to center manually
|
||||||
|
//3.I changed video_buffer's type, from ui::Color to uint_8, since I don't need 3 digit to represent a grey scale value.
|
||||||
|
//I was hoping that by doing this, I can have a longer buffer like 39936, then the frame will looks better vertically
|
||||||
|
//however this is useless until now.
|
||||||
|
|
||||||
|
for(size_t i=0; i<256; i++)
|
||||||
|
{
|
||||||
|
//video_buffer[i+count*256] = spectrum_rgb4_lut[spectrum.db[i]];
|
||||||
|
video_buffer_int[i+count*256] = 255 - spectrum.db[i];
|
||||||
|
}
|
||||||
|
count = count + 1;
|
||||||
|
if (count == 52 -1)
|
||||||
|
{
|
||||||
|
ui::Color line_buffer[128];
|
||||||
|
Coord line;
|
||||||
|
uint32_t bmp_px;
|
||||||
|
|
||||||
|
/*for (line = 0; line < 104; line++)
|
||||||
|
{
|
||||||
|
for (bmp_px = 0; bmp_px < 128; bmp_px++)
|
||||||
|
{
|
||||||
|
//line_buffer[bmp_px] = video_buffer[bmp_px+line*128];
|
||||||
|
line_buffer[bmp_px] = spectrum_rgb4_lut[video_buffer_int[bmp_px+line*128 + x_correction]];
|
||||||
|
}
|
||||||
|
|
||||||
|
display.render_line({ 0, line + 100 }, 128, line_buffer);
|
||||||
|
}*/
|
||||||
|
for (line = 0; line < 208; line=line+2)
|
||||||
|
{
|
||||||
|
for (bmp_px = 0; bmp_px < 128; bmp_px++)
|
||||||
|
{
|
||||||
|
//line_buffer[bmp_px] = video_buffer[bmp_px+line*128];
|
||||||
|
line_buffer[bmp_px] = spectrum_rgb4_lut[video_buffer_int[bmp_px+line/2*128 + x_correction]];
|
||||||
|
}
|
||||||
|
|
||||||
|
display.render_line({ 0, line + 100 }, 128, line_buffer);
|
||||||
|
display.render_line({ 0, line + 101 }, 128, line_buffer);
|
||||||
|
}
|
||||||
|
count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TVView::clear() {
|
||||||
|
display.fill_rectangle(
|
||||||
|
screen_rect(),
|
||||||
|
Color::black()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TVWidget *******************************************************/
|
||||||
|
|
||||||
|
TVWidget::TVWidget(const bool cursor) {
|
||||||
|
add_children({
|
||||||
|
&tv_view,
|
||||||
|
&field_xcorr
|
||||||
|
});
|
||||||
|
field_xcorr.set_value(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TVWidget::on_show() {
|
||||||
|
baseband::spectrum_streaming_start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TVWidget::on_hide() {
|
||||||
|
baseband::spectrum_streaming_stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TVWidget::show_audio_spectrum_view(const bool show) {
|
||||||
|
if ((audio_spectrum_view && show) || (!audio_spectrum_view && !show)) return;
|
||||||
|
|
||||||
|
if (show) {
|
||||||
|
audio_spectrum_view = std::make_unique<TimeScopeView>(audio_spectrum_view_rect);
|
||||||
|
add_child(audio_spectrum_view.get());
|
||||||
|
update_widgets_rect();
|
||||||
|
} else {
|
||||||
|
audio_spectrum_update = false;
|
||||||
|
remove_child(audio_spectrum_view.get());
|
||||||
|
audio_spectrum_view.reset();
|
||||||
|
update_widgets_rect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TVWidget::update_widgets_rect() {
|
||||||
|
if (audio_spectrum_view) {
|
||||||
|
tv_view.set_parent_rect(tv_reduced_rect);
|
||||||
|
} else {
|
||||||
|
tv_view.set_parent_rect(tv_normal_rect);
|
||||||
|
}
|
||||||
|
tv_view.on_show();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TVWidget::set_parent_rect(const Rect new_parent_rect) {
|
||||||
|
View::set_parent_rect(new_parent_rect);
|
||||||
|
|
||||||
|
tv_normal_rect = { 0, scale_height, new_parent_rect.width(), new_parent_rect.height() - scale_height};
|
||||||
|
tv_reduced_rect = { 0, audio_spectrum_height + scale_height, new_parent_rect.width(), new_parent_rect.height() - scale_height - audio_spectrum_height };
|
||||||
|
|
||||||
|
update_widgets_rect();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TVWidget::paint(Painter& painter) {
|
||||||
|
// TODO:
|
||||||
|
(void)painter;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TVWidget::on_channel_spectrum(const ChannelSpectrum& spectrum) {
|
||||||
|
tv_view.on_channel_spectrum(spectrum);
|
||||||
|
tv_view.on_adjust_xcorr(field_xcorr.value());
|
||||||
|
sampling_rate = spectrum.sampling_rate;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TVWidget::on_audio_spectrum() {
|
||||||
|
audio_spectrum_view->on_audio_spectrum(audio_spectrum_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* namespace tv */
|
||||||
|
} /* namespace ui */
|
176
firmware/application/ui/ui_tv.hpp
Normal file
176
firmware/application/ui/ui_tv.hpp
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||||
|
* Copyright (C) 2020 Shao
|
||||||
|
*
|
||||||
|
* 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 __UI_TV_H__
|
||||||
|
#define __UI_TV_H__
|
||||||
|
|
||||||
|
#include "ui.hpp"
|
||||||
|
#include "ui_widget.hpp"
|
||||||
|
|
||||||
|
#include "event_m0.hpp"
|
||||||
|
|
||||||
|
#include "message.hpp"
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
namespace ui {
|
||||||
|
namespace tv {
|
||||||
|
|
||||||
|
class TimeScopeView : public View {
|
||||||
|
public:
|
||||||
|
TimeScopeView(const Rect parent_rect);
|
||||||
|
|
||||||
|
void paint(Painter& painter) override;
|
||||||
|
|
||||||
|
void on_audio_spectrum(const AudioSpectrum* spectrum);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static constexpr int cursor_band_height = 4;
|
||||||
|
|
||||||
|
int16_t audio_spectrum[128] { 0 };
|
||||||
|
|
||||||
|
/*Labels labels {
|
||||||
|
{ { 6 * 8, 0 * 16 }, "Hz", Color::light_grey() }
|
||||||
|
};*/
|
||||||
|
/*
|
||||||
|
NumberField field_frequency {
|
||||||
|
{ 0 * 8, 0 * 16 },
|
||||||
|
5,
|
||||||
|
{ 0, 48000 },
|
||||||
|
48000 / 240,
|
||||||
|
' '
|
||||||
|
};*/
|
||||||
|
|
||||||
|
Waveform waveform {
|
||||||
|
{ 0, 1 * 16 + cursor_band_height, 30 * 8, 2 * 16 },
|
||||||
|
audio_spectrum,
|
||||||
|
128,
|
||||||
|
0,
|
||||||
|
false,
|
||||||
|
Color::white()
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
class TVView : public Widget {
|
||||||
|
public:
|
||||||
|
void on_show() override;
|
||||||
|
void on_hide() override;
|
||||||
|
|
||||||
|
void paint(Painter& painter) override;
|
||||||
|
void on_channel_spectrum(const ChannelSpectrum& spectrum);
|
||||||
|
void on_adjust_xcorr(uint8_t xcorr);
|
||||||
|
//ui::Color video_buffer[13312];
|
||||||
|
uint8_t video_buffer_int[13312+128] { 0 }; //128 is for the over length caused by x_correction
|
||||||
|
uint32_t count=0;
|
||||||
|
uint8_t x_correction=0;
|
||||||
|
private:
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class TVWidget : public View {
|
||||||
|
public:
|
||||||
|
std::function<void(int32_t offset)> on_select { };
|
||||||
|
|
||||||
|
TVWidget(const bool cursor = false);
|
||||||
|
|
||||||
|
TVWidget(const TVWidget&) = delete;
|
||||||
|
TVWidget(TVWidget&&) = delete;
|
||||||
|
TVWidget& operator=(const TVWidget&) = delete;
|
||||||
|
TVWidget& operator=(TVWidget&&) = delete;
|
||||||
|
|
||||||
|
void on_show() override;
|
||||||
|
void on_hide() override;
|
||||||
|
|
||||||
|
void set_parent_rect(const Rect new_parent_rect) override;
|
||||||
|
|
||||||
|
void show_audio_spectrum_view(const bool show);
|
||||||
|
|
||||||
|
void paint(Painter& painter) override;
|
||||||
|
NumberField field_xcorr {
|
||||||
|
{ 0 * 8, 0 * 16 },
|
||||||
|
5,
|
||||||
|
{ 0, 128 },
|
||||||
|
1,
|
||||||
|
' '
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
void update_widgets_rect();
|
||||||
|
|
||||||
|
const Rect audio_spectrum_view_rect { 0 * 8, 0 * 16, 30 * 8, 2 * 16 + 20 };
|
||||||
|
static constexpr Dim audio_spectrum_height = 16 * 2 + 20;
|
||||||
|
static constexpr Dim scale_height = 20;
|
||||||
|
|
||||||
|
TVView tv_view { };
|
||||||
|
|
||||||
|
ChannelSpectrumFIFO* channel_fifo { nullptr };
|
||||||
|
AudioSpectrum* audio_spectrum_data { nullptr };
|
||||||
|
bool audio_spectrum_update { false };
|
||||||
|
|
||||||
|
std::unique_ptr<TimeScopeView> audio_spectrum_view { };
|
||||||
|
|
||||||
|
int sampling_rate { 0 };
|
||||||
|
int32_t cursor_position { 0 };
|
||||||
|
ui::Rect tv_normal_rect { };
|
||||||
|
ui::Rect tv_reduced_rect { };
|
||||||
|
|
||||||
|
MessageHandlerRegistration message_handler_channel_spectrum_config {
|
||||||
|
Message::ID::ChannelSpectrumConfig,
|
||||||
|
[this](const Message* const p) {
|
||||||
|
const auto message = *reinterpret_cast<const ChannelSpectrumConfigMessage*>(p);
|
||||||
|
this->channel_fifo = message.fifo;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
MessageHandlerRegistration message_handler_audio_spectrum {
|
||||||
|
Message::ID::AudioSpectrum,
|
||||||
|
[this](const Message* const p) {
|
||||||
|
const auto message = *reinterpret_cast<const AudioSpectrumMessage*>(p);
|
||||||
|
this->audio_spectrum_data = message.data;
|
||||||
|
this->audio_spectrum_update = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
MessageHandlerRegistration message_handler_frame_sync {
|
||||||
|
Message::ID::DisplayFrameSync,
|
||||||
|
[this](const Message* const) {
|
||||||
|
if( this->channel_fifo ) {
|
||||||
|
ChannelSpectrum channel_spectrum;
|
||||||
|
while( channel_fifo->out(channel_spectrum) ) {
|
||||||
|
this->on_channel_spectrum(channel_spectrum);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this->audio_spectrum_update) {
|
||||||
|
this->audio_spectrum_update = false;
|
||||||
|
this->on_audio_spectrum();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void on_channel_spectrum(const ChannelSpectrum& spectrum);
|
||||||
|
void on_audio_spectrum();
|
||||||
|
};
|
||||||
|
|
||||||
|
} /* namespace tv */
|
||||||
|
} /* namespace ui */
|
||||||
|
|
||||||
|
#endif/*__UI_TV_H__*/
|
@ -70,6 +70,7 @@
|
|||||||
#include "acars_app.hpp"
|
#include "acars_app.hpp"
|
||||||
#include "ais_app.hpp"
|
#include "ais_app.hpp"
|
||||||
#include "analog_audio_app.hpp"
|
#include "analog_audio_app.hpp"
|
||||||
|
#include "analog_tv_app.hpp"
|
||||||
#include "capture_app.hpp"
|
#include "capture_app.hpp"
|
||||||
#include "ert_app.hpp"
|
#include "ert_app.hpp"
|
||||||
#include "lge_app.hpp"
|
#include "lge_app.hpp"
|
||||||
@ -352,6 +353,7 @@ ReceiversMenuView::ReceiversMenuView(NavigationView& nav) {
|
|||||||
{ "BTLE", ui::Color::yellow(), &bitmap_icon_btle, [&nav](){ nav.push<BTLERxView>(); } },
|
{ "BTLE", ui::Color::yellow(), &bitmap_icon_btle, [&nav](){ nav.push<BTLERxView>(); } },
|
||||||
{ "NRF", ui::Color::yellow(), &bitmap_icon_nrf, [&nav](){ nav.push<NRFRxView>(); } },
|
{ "NRF", ui::Color::yellow(), &bitmap_icon_nrf, [&nav](){ nav.push<NRFRxView>(); } },
|
||||||
{ "Audio", ui::Color::green(), &bitmap_icon_speaker, [&nav](){ nav.push<AnalogAudioView>(); } },
|
{ "Audio", ui::Color::green(), &bitmap_icon_speaker, [&nav](){ nav.push<AnalogAudioView>(); } },
|
||||||
|
{ "Analog TV", ui::Color::yellow(), &bitmap_icon_sstv, [&nav](){ nav.push<AnalogTvView>(); } },
|
||||||
{ "ERT Meter", ui::Color::green(), &bitmap_icon_ert, [&nav](){ nav.push<ERTAppView>(); } },
|
{ "ERT Meter", ui::Color::green(), &bitmap_icon_ert, [&nav](){ nav.push<ERTAppView>(); } },
|
||||||
{ "POCSAG", ui::Color::green(), &bitmap_icon_pocsag, [&nav](){ nav.push<POCSAGAppView>(); } },
|
{ "POCSAG", ui::Color::green(), &bitmap_icon_pocsag, [&nav](){ nav.push<POCSAGAppView>(); } },
|
||||||
{ "Radiosnde", ui::Color::yellow(), &bitmap_icon_sonde, [&nav](){ nav.push<SondeView>(); } },
|
{ "Radiosnde", ui::Color::yellow(), &bitmap_icon_sonde, [&nav](){ nav.push<SondeView>(); } },
|
||||||
|
@ -116,6 +116,7 @@ set(CPPSRC
|
|||||||
dsp_goertzel.cpp
|
dsp_goertzel.cpp
|
||||||
matched_filter.cpp
|
matched_filter.cpp
|
||||||
spectrum_collector.cpp
|
spectrum_collector.cpp
|
||||||
|
tv_collector.cpp
|
||||||
stream_input.cpp
|
stream_input.cpp
|
||||||
stream_output.cpp
|
stream_output.cpp
|
||||||
dsp_squelch.cpp
|
dsp_squelch.cpp
|
||||||
@ -338,6 +339,13 @@ set(MODE_CPPSRC
|
|||||||
)
|
)
|
||||||
DeclareTargets(PAMA am_audio)
|
DeclareTargets(PAMA am_audio)
|
||||||
|
|
||||||
|
### AM TV
|
||||||
|
|
||||||
|
set(MODE_CPPSRC
|
||||||
|
proc_am_tv.cpp
|
||||||
|
)
|
||||||
|
DeclareTargets(PAMT am_tv)
|
||||||
|
|
||||||
### Audio transmit
|
### Audio transmit
|
||||||
|
|
||||||
set(MODE_CPPSRC
|
set(MODE_CPPSRC
|
||||||
|
86
firmware/baseband/proc_am_tv.cpp
Normal file
86
firmware/baseband/proc_am_tv.cpp
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
|
||||||
|
* Copyright (C) 2016 Furrtek
|
||||||
|
* Copyright (C) 2020 Shao
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "proc_am_tv.hpp"
|
||||||
|
|
||||||
|
#include "portapack_shared_memory.hpp"
|
||||||
|
#include "dsp_fft.hpp"
|
||||||
|
#include "event_m4.hpp"
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
void WidebandFMAudio::execute(const buffer_c8_t& buffer) {
|
||||||
|
if( !configured ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::fill(spectrum.begin(), spectrum.end(), 0);
|
||||||
|
|
||||||
|
for(size_t i=0; i<spectrum.size(); i++) {
|
||||||
|
spectrum[i] += buffer.p[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
const buffer_c16_t buffer_c16 {spectrum.data(),spectrum.size(),buffer.sampling_rate};
|
||||||
|
channel_spectrum.feed(buffer_c16);
|
||||||
|
|
||||||
|
int8_t re, im;
|
||||||
|
int8_t mag;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < 128; i++)
|
||||||
|
{
|
||||||
|
re = buffer.p[i].real();
|
||||||
|
im = buffer.p[i].imag();
|
||||||
|
mag = __builtin_sqrtf((re * re) + (im * im)) ;
|
||||||
|
const unsigned int v = re + 127.0f; //timescope
|
||||||
|
audio_spectrum.db[i] = std::max(0U, std::min(255U, v));
|
||||||
|
}
|
||||||
|
AudioSpectrumMessage message { &audio_spectrum };
|
||||||
|
shared_memory.application_queue.push(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WidebandFMAudio::on_message(const Message* const message) {
|
||||||
|
switch(message->id) {
|
||||||
|
case Message::ID::UpdateSpectrum:
|
||||||
|
case Message::ID::SpectrumStreamingConfig:
|
||||||
|
channel_spectrum.on_message(message);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Message::ID::WFMConfigure:
|
||||||
|
configure(*reinterpret_cast<const WFMConfigureMessage*>(message));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WidebandFMAudio::configure(const WFMConfigureMessage& message) {
|
||||||
|
configured = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
EventDispatcher event_dispatcher { std::make_unique<WidebandFMAudio>() };
|
||||||
|
event_dispatcher.run();
|
||||||
|
return 0;
|
||||||
|
}
|
65
firmware/baseband/proc_am_tv.hpp
Normal file
65
firmware/baseband/proc_am_tv.hpp
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
|
||||||
|
* Copyright (C) 2016 Furrtek
|
||||||
|
* Copyright (C) 2020 Shao
|
||||||
|
*
|
||||||
|
* 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 __PROC_AM_TV_H__
|
||||||
|
#define __PROC_AM_TV_H__
|
||||||
|
|
||||||
|
#include "baseband_processor.hpp"
|
||||||
|
#include "baseband_thread.hpp"
|
||||||
|
#include "rssi_thread.hpp"
|
||||||
|
|
||||||
|
#include "dsp_types.hpp"
|
||||||
|
#include "dsp_decimate.hpp"
|
||||||
|
#include "dsp_demodulate.hpp"
|
||||||
|
#include "block_decimator.hpp"
|
||||||
|
|
||||||
|
#include "tv_collector.hpp"
|
||||||
|
|
||||||
|
class WidebandFMAudio : public BasebandProcessor {
|
||||||
|
public:
|
||||||
|
void execute(const buffer_c8_t& buffer) override;
|
||||||
|
|
||||||
|
void on_message(const Message* const message) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static constexpr size_t baseband_fs = 2000000;
|
||||||
|
|
||||||
|
BasebandThread baseband_thread { baseband_fs, this, NORMALPRIO + 20, baseband::Direction::Receive };
|
||||||
|
RSSIThread rssi_thread { NORMALPRIO + 10 };
|
||||||
|
|
||||||
|
std::array<complex16_t, 512> dst { };
|
||||||
|
const buffer_c16_t dst_buffer {
|
||||||
|
dst.data(),
|
||||||
|
dst.size()
|
||||||
|
};
|
||||||
|
|
||||||
|
AudioSpectrum audio_spectrum { };
|
||||||
|
TvCollector channel_spectrum { };
|
||||||
|
std::array<complex16_t, 256> spectrum { };
|
||||||
|
|
||||||
|
bool configured { false };
|
||||||
|
void configure(const WFMConfigureMessage& message);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif/*__PROC_AM_TV_H__*/
|
122
firmware/baseband/tv_collector.cpp
Normal file
122
firmware/baseband/tv_collector.cpp
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||||
|
* Copyright (C) 2020 Shao
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "tv_collector.hpp"
|
||||||
|
|
||||||
|
#include "dsp_fft.hpp"
|
||||||
|
|
||||||
|
#include "utility.hpp"
|
||||||
|
#include "event_m4.hpp"
|
||||||
|
#include "portapack_shared_memory.hpp"
|
||||||
|
|
||||||
|
#include "event_m4.hpp"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
void TvCollector::on_message(const Message* const message) {
|
||||||
|
switch(message->id) {
|
||||||
|
case Message::ID::UpdateSpectrum:
|
||||||
|
update();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Message::ID::SpectrumStreamingConfig:
|
||||||
|
set_state(*reinterpret_cast<const SpectrumStreamingConfigMessage*>(message));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TvCollector::set_state(const SpectrumStreamingConfigMessage& message) {
|
||||||
|
if( message.mode == SpectrumStreamingConfigMessage::Mode::Running ) {
|
||||||
|
start();
|
||||||
|
} else {
|
||||||
|
stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TvCollector::start() {
|
||||||
|
streaming = true;
|
||||||
|
ChannelSpectrumConfigMessage message { &fifo };
|
||||||
|
shared_memory.application_queue.push(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TvCollector::stop() {
|
||||||
|
streaming = false;
|
||||||
|
fifo.reset_in();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TvCollector::set_decimation_factor(
|
||||||
|
const size_t decimation_factor
|
||||||
|
) {
|
||||||
|
channel_spectrum_decimator.set_factor(decimation_factor);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: Refactor to register task with idle thread?
|
||||||
|
* It's sad that the idle thread has to call all the way back here just to
|
||||||
|
* perform the deferred task on the buffer of data we prepared.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void TvCollector::feed(
|
||||||
|
const buffer_c16_t& channel
|
||||||
|
) {
|
||||||
|
// Called from baseband processing thread.
|
||||||
|
channel_spectrum_decimator.feed(channel,[this](const buffer_c16_t& data) {this->post_message(data);});
|
||||||
|
}
|
||||||
|
|
||||||
|
void TvCollector::post_message(const buffer_c16_t& data) {
|
||||||
|
// Called from baseband processing thread.
|
||||||
|
float re, im;
|
||||||
|
float mag;
|
||||||
|
float max;
|
||||||
|
if( streaming && !channel_spectrum_request_update ) {
|
||||||
|
for(size_t i=0; i<256; i++)
|
||||||
|
{
|
||||||
|
const auto s = data.p[i];
|
||||||
|
re = (float)(data.p[i].real());
|
||||||
|
im = (float)(data.p[i].imag());
|
||||||
|
mag = __builtin_sqrtf((re * re) + (im * im)) ;
|
||||||
|
channel_spectrum[i] = {mag, mag};
|
||||||
|
}
|
||||||
|
channel_spectrum_sampling_rate = data.sampling_rate;
|
||||||
|
channel_spectrum_request_update = true;
|
||||||
|
EventDispatcher::events_flag(EVT_MASK_SPECTRUM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void TvCollector::update() {
|
||||||
|
// Called from idle thread (after EVT_MASK_SPECTRUM is flagged)
|
||||||
|
if( streaming && channel_spectrum_request_update ) {
|
||||||
|
ChannelSpectrum spectrum;
|
||||||
|
spectrum.sampling_rate = channel_spectrum_sampling_rate;
|
||||||
|
for(size_t i=0; i<spectrum.db.size(); i++) {
|
||||||
|
const auto corrected_sample = channel_spectrum[i].real();
|
||||||
|
const unsigned int v = corrected_sample + 127.0f;
|
||||||
|
spectrum.db[i] = std::max(0U, std::min(255U, v));
|
||||||
|
}
|
||||||
|
fifo.in(spectrum);
|
||||||
|
}
|
||||||
|
|
||||||
|
channel_spectrum_request_update = false;
|
||||||
|
}
|
66
firmware/baseband/tv_collector.hpp
Normal file
66
firmware/baseband/tv_collector.hpp
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||||
|
* Copyright (C) 2020 Shao
|
||||||
|
*
|
||||||
|
* 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 __TV_COLLECTOR_H__
|
||||||
|
#define __TV_COLLECTOR_H__
|
||||||
|
|
||||||
|
#include "dsp_types.hpp"
|
||||||
|
#include "complex.hpp"
|
||||||
|
|
||||||
|
#include "block_decimator.hpp"
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
#include "message.hpp"
|
||||||
|
|
||||||
|
class TvCollector {
|
||||||
|
public:
|
||||||
|
void on_message(const Message* const message);
|
||||||
|
|
||||||
|
void set_decimation_factor(const size_t decimation_factor);
|
||||||
|
|
||||||
|
void feed(
|
||||||
|
const buffer_c16_t& channel
|
||||||
|
);
|
||||||
|
|
||||||
|
private:
|
||||||
|
BlockDecimator<complex16_t, 256> channel_spectrum_decimator { 1 };
|
||||||
|
ChannelSpectrum fifo_data[1 << ChannelSpectrumConfigMessage::fifo_k] { };
|
||||||
|
ChannelSpectrumFIFO fifo { fifo_data, ChannelSpectrumConfigMessage::fifo_k };
|
||||||
|
|
||||||
|
volatile bool channel_spectrum_request_update { false };
|
||||||
|
bool streaming { false };
|
||||||
|
std::array<std::complex<float>, 256> channel_spectrum { };
|
||||||
|
uint32_t channel_spectrum_sampling_rate { 0 };
|
||||||
|
|
||||||
|
void post_message(const buffer_c16_t& data);
|
||||||
|
|
||||||
|
void set_state(const SpectrumStreamingConfigMessage& message);
|
||||||
|
void start();
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
void update();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif/*__TV_COLLECTOR_H__*/
|
@ -72,6 +72,7 @@ constexpr image_tag_t image_tag_btle_rx { 'P', 'B', 'T', 'R' };
|
|||||||
constexpr image_tag_t image_tag_nrf_rx { 'P', 'N', 'R', 'R' };
|
constexpr image_tag_t image_tag_nrf_rx { 'P', 'N', 'R', 'R' };
|
||||||
constexpr image_tag_t image_tag_ais { 'P', 'A', 'I', 'S' };
|
constexpr image_tag_t image_tag_ais { 'P', 'A', 'I', 'S' };
|
||||||
constexpr image_tag_t image_tag_am_audio { 'P', 'A', 'M', 'A' };
|
constexpr image_tag_t image_tag_am_audio { 'P', 'A', 'M', 'A' };
|
||||||
|
constexpr image_tag_t image_tag_am_tv { 'P', 'A', 'M', 'T' };
|
||||||
constexpr image_tag_t image_tag_capture { 'P', 'C', 'A', 'P' };
|
constexpr image_tag_t image_tag_capture { 'P', 'C', 'A', 'P' };
|
||||||
constexpr image_tag_t image_tag_ert { 'P', 'E', 'R', 'T' };
|
constexpr image_tag_t image_tag_ert { 'P', 'E', 'R', 'T' };
|
||||||
constexpr image_tag_t image_tag_nfm_audio { 'P', 'N', 'F', 'M' };
|
constexpr image_tag_t image_tag_nfm_audio { 'P', 'N', 'F', 'M' };
|
||||||
|
Loading…
Reference in New Issue
Block a user