/* * Copyright (C) 2023 Bernd Herzog * * 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_spectrum_painter.hpp" #include "bmp.hpp" #include "baseband_api.hpp" #include "file.hpp" #include "io_file.hpp" #include "portapack_persistent_memory.hpp" #include "ui_fileman.hpp" #include "ui_freqman.hpp" using namespace portapack; namespace ui { SpectrumPainterView::SpectrumPainterView( NavigationView& nav) : nav_(nav) { baseband::run_image(spi_flash::image_tag_spectrum_painter); add_children({ &labels, &tab_view, &input_image, &input_text, &progressbar, &field_frequency, &field_rfgain, &field_rfamp, &check_loop, &button_play, &option_bandwidth, &field_duration, &field_pause, }); Rect view_rect = {0, 3 * 8, 240, 80}; input_image.set_parent_rect(view_rect); input_text.set_parent_rect(view_rect); freqman_set_bandwidth_option(SPEC_MODULATION, option_bandwidth); field_frequency.set_step(5000); tx_gain = transmitter_model.tx_gain(); field_rfgain.set_value(tx_gain); // Initial default value (-12 dB's max ). field_rfgain.on_change = [this](int32_t v) { // allow initial value change just after opened file. tx_gain = v; transmitter_model.set_tx_gain(tx_gain); }; field_rfamp.set_value(rf_amp ? 14 : 0); // Initial default value True. (TX RF amp on , +14dB's) field_rfamp.on_change = [this](int32_t v) { // allow initial value change just after opened file. rf_amp = (bool)v; transmitter_model.set_rf_amp(rf_amp); }; input_image.on_input_avaliable = [this]() { image_input_avaliable = true; }; button_play.on_select = [this](ImageButton&) { if (tx_active == false) { tx_mode = tab_view.selected(); if (tx_mode == 0 && image_input_avaliable == false) return; /* By experimental test measurement, we got a good painted spectrum quality when selecting a BW GUI App range from 100k ... 2M aprox. In that range , the best TX LPF filter = 1M75 (the min) With this min TX LPF filter , we minimized the harmonics aliasing multipicture overlapped. So original fw 1.7.4., was already selecting the best setting (1M75) */ transmitter_model.set_baseband_bandwidth(1'750'000); // Already tested, is the best setting for this App. transmitter_model.enable(); if (persistent_memory::stealth_mode()) { DisplaySleepMessage message; EventDispatcher::send_message(message); } button_play.set_bitmap(&bitmap_stop); if (tx_mode == 0) { tx_current_max_lines = input_image.get_height(); tx_current_width = input_image.get_width(); } else { tx_current_max_lines = input_text.get_height(); tx_current_width = input_text.get_width(); } progressbar.set_max(tx_current_max_lines); progressbar.set_value(0); baseband::set_spectrum_painter_config(tx_current_width, tx_current_max_lines, false, option_bandwidth.selected_index_value()); } else { stop_tx(); } }; option_bandwidth.on_change = [this](size_t, ui::OptionsField::value_t value) { baseband::set_spectrum_painter_config(tx_current_width, tx_current_max_lines, true, value); }; field_duration.set_value(10); field_pause.set_value(5); } void SpectrumPainterView::start_tx() { tx_current_line = 0; tx_active = true; tx_timestamp_start = chTimeNow(); } void SpectrumPainterView::stop_tx() { button_play.set_bitmap(&bitmap_play); transmitter_model.disable(); tx_active = false; tx_current_line = 0; } void SpectrumPainterView::frame_sync() { if (tx_active) { if (fifo->is_empty()) { int32_t sequence_duration = (field_duration.value() + (check_loop.value() ? field_pause.value() : 0)) * 1000; int32_t sequence_time = tx_time_elapsed() % sequence_duration; bool is_pausing = sequence_time > field_duration.value() * 1000; if (is_pausing) { fifo->in(std::vector<uint8_t>(tx_current_width)); } else { auto current_time_line = sequence_time * tx_current_max_lines / (field_duration.value() * 1000); if (tx_current_line > current_time_line && !check_loop.value()) { fifo->in(std::vector<uint8_t>(tx_current_width)); stop_tx(); return; } tx_current_line = current_time_line; progressbar.set_value(current_time_line); if (tx_mode == 0) { std::vector<uint8_t> line = input_image.get_line(current_time_line); fifo->in(line); } else { std::vector<uint8_t> line = input_text.get_line(current_time_line); fifo->in(line); } } } } } SpectrumPainterView::~SpectrumPainterView() { transmitter_model.disable(); baseband::shutdown(); } void SpectrumPainterView::focus() { tab_view.focus(); } void SpectrumPainterView::paint(Painter& painter) { View::paint(painter); size_t c; Point pos = {0, screen_pos().y() + 8 + footer_location}; for (c = 0; c < 20; c++) { painter.draw_bitmap( pos, bitmap_stripes, ui::Color(191, 191, 0), ui::Color::black()); if (c != 9) pos += {24, 0}; else pos = {0, screen_pos().y() + 8 + footer_location + 32 + 8}; } } } // namespace ui