mirror of
https://github.com/eried/portapack-mayhem.git
synced 2025-08-02 03:26:40 -04:00
IQ Trim app and Capture auto-trim (#1456)
* Add IQ Trim app WIP * Add 'trim' checkbox to capture * Implement trimming * Finish auto-trim * Stray //
This commit is contained in:
parent
070eb4003e
commit
ef03f020ce
11 changed files with 537 additions and 51 deletions
|
@ -44,6 +44,7 @@ CaptureAppView::CaptureAppView(NavigationView& nav)
|
|||
&field_vga,
|
||||
&option_bandwidth,
|
||||
&option_format,
|
||||
&check_trim,
|
||||
&record_view,
|
||||
&waterfall,
|
||||
});
|
||||
|
@ -59,6 +60,10 @@ CaptureAppView::CaptureAppView(NavigationView& nav)
|
|||
record_view.set_file_type((RecordView::FileType)file_type);
|
||||
};
|
||||
|
||||
check_trim.on_select = [this](Checkbox&, bool v) {
|
||||
record_view.set_auto_trim(v);
|
||||
};
|
||||
|
||||
freqman_set_bandwidth_option(SPEC_MODULATION, option_bandwidth);
|
||||
option_bandwidth.on_change = [this](size_t, uint32_t bandwidth) {
|
||||
/* Nyquist would imply a sample rate of 2x bandwidth, but because the ADC
|
||||
|
@ -92,7 +97,7 @@ CaptureAppView::CaptureAppView(NavigationView& nav)
|
|||
};
|
||||
|
||||
receiver_model.enable();
|
||||
option_bandwidth.set_by_value(500000); // better by_value than by option_bandwidth.set_selected_index(4), Preselected default option 500kHz.
|
||||
option_bandwidth.set_by_value(500000);
|
||||
|
||||
record_view.on_error = [&nav](std::string message) {
|
||||
nav.display_modal("Error", message);
|
||||
|
|
|
@ -92,6 +92,12 @@ class CaptureAppView : public View {
|
|||
{{"C16", RecordView::FileType::RawS16},
|
||||
{"C8", RecordView::FileType::RawS8}}};
|
||||
|
||||
Checkbox check_trim{
|
||||
{23 * 8, 1 * 16},
|
||||
4,
|
||||
"Trim",
|
||||
/*small*/ true};
|
||||
|
||||
RecordView record_view{
|
||||
{0 * 8, 2 * 16, 30 * 8, 1 * 16},
|
||||
u"BBD_????.*",
|
||||
|
|
118
firmware/application/apps/ui_iq_trim.cpp
Normal file
118
firmware/application/apps/ui_iq_trim.cpp
Normal file
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* Copyright (C) 2023 Kyle Reed
|
||||
*
|
||||
* 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_iq_trim.hpp"
|
||||
|
||||
#include "complex.hpp"
|
||||
#include "portapack.hpp"
|
||||
#include "ui_fileman.hpp"
|
||||
|
||||
using namespace portapack;
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
namespace ui {
|
||||
|
||||
IQTrimView::IQTrimView(NavigationView& nav) {
|
||||
add_children({
|
||||
&labels,
|
||||
&field_path,
|
||||
&text_range,
|
||||
&button_trim,
|
||||
});
|
||||
|
||||
field_path.on_select = [this, &nav](TextField&) {
|
||||
auto open_view = nav.push<FileLoadView>(".C*");
|
||||
open_view->push_dir(u"CAPTURES");
|
||||
open_view->on_changed = [this](fs::path path) {
|
||||
read_capture(path);
|
||||
path_ = std::move(path);
|
||||
refresh_ui();
|
||||
};
|
||||
};
|
||||
|
||||
button_trim.on_select = [this, &nav](Button&) {
|
||||
if (!path_.empty() && trim_range_.file_size > 0) {
|
||||
progress_ui.show_trimming();
|
||||
TrimFile(path_, trim_range_);
|
||||
read_capture(path_);
|
||||
refresh_ui();
|
||||
} else {
|
||||
nav.display_modal("Error", "Select a file first.");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void IQTrimView::paint(Painter& painter) {
|
||||
if (!path_.empty()) {
|
||||
// Draw power buckets.
|
||||
for (size_t i = 0; i < power_buckets_.size(); ++i) {
|
||||
auto amp = power_buckets_[i].power;
|
||||
painter.draw_vline(
|
||||
pos_lines + Point{(int)i, 0},
|
||||
height_lines,
|
||||
Color(amp, amp, amp));
|
||||
}
|
||||
|
||||
// Draw trim range edges.
|
||||
int start_x = screen_width * trim_range_.start / trim_range_.file_size;
|
||||
int end_x = screen_width * trim_range_.end / trim_range_.file_size;
|
||||
|
||||
painter.draw_vline(
|
||||
pos_lines + Point{start_x, 0},
|
||||
height_lines,
|
||||
Color::dark_green());
|
||||
painter.draw_vline(
|
||||
pos_lines + Point{end_x, 0},
|
||||
height_lines,
|
||||
Color::dark_red());
|
||||
}
|
||||
}
|
||||
|
||||
void IQTrimView::focus() {
|
||||
field_path.focus();
|
||||
}
|
||||
|
||||
void IQTrimView::refresh_ui() {
|
||||
field_path.set_text(path_.filename().string());
|
||||
text_range.set(to_string_dec_uint(trim_range_.start) + "-" + to_string_dec_uint(trim_range_.end));
|
||||
set_dirty();
|
||||
}
|
||||
|
||||
bool IQTrimView::read_capture(const fs::path& path) {
|
||||
power_buckets_ = {};
|
||||
PowerBuckets buckets{
|
||||
.p = power_buckets_.data(),
|
||||
.size = power_buckets_.size()};
|
||||
|
||||
progress_ui.show_reading();
|
||||
auto range = ComputeTrimRange(path, amp_threshold, &buckets, progress_ui.get_callback());
|
||||
progress_ui.clear();
|
||||
|
||||
if (range) {
|
||||
trim_range_ = *range;
|
||||
return true;
|
||||
} else {
|
||||
trim_range_ = {};
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ui
|
108
firmware/application/apps/ui_iq_trim.hpp
Normal file
108
firmware/application/apps/ui_iq_trim.hpp
Normal file
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* Copyright (C) 2023 Kyle Reed
|
||||
*
|
||||
* 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_IQ_TRIM_H__
|
||||
#define __UI_IQ_TRIM_H__
|
||||
|
||||
#include "file.hpp"
|
||||
#include "iq_trim.hpp"
|
||||
#include "ui.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
#include "ui_styles.hpp"
|
||||
#include "ui_widget.hpp"
|
||||
|
||||
#include <array>
|
||||
|
||||
namespace ui {
|
||||
|
||||
/* Helper for drawing progress related to IQ trimming. */
|
||||
/* TODO: Ideally this would all be done on second thread. */
|
||||
class TrimProgressUI {
|
||||
public:
|
||||
void show_reading() {
|
||||
clear();
|
||||
p.draw_string({6 * 8, 5 * 16}, Styles::yellow, "Reading Capture...");
|
||||
}
|
||||
|
||||
void show_trimming() {
|
||||
clear();
|
||||
p.draw_string({5 * 8, 5 * 16}, Styles::yellow, "Trimming Capture...");
|
||||
}
|
||||
|
||||
void show_progress(uint8_t percent) {
|
||||
auto width = percent * screen_width / 100;
|
||||
p.draw_hline({0, 6 * 16}, width, Color::yellow());
|
||||
}
|
||||
|
||||
void clear() {
|
||||
p.fill_rectangle({0 * 8, 4 * 16, screen_width, 3 * 16}, Color::black());
|
||||
}
|
||||
|
||||
auto get_callback() {
|
||||
return [this](uint8_t percent) { show_progress(percent); };
|
||||
}
|
||||
|
||||
private:
|
||||
Painter p{};
|
||||
};
|
||||
|
||||
class IQTrimView : public View {
|
||||
public:
|
||||
IQTrimView(NavigationView& nav);
|
||||
|
||||
std::string title() const override { return "IQ Trim"; }
|
||||
void paint(Painter& painter) override;
|
||||
void focus() override;
|
||||
|
||||
private:
|
||||
void refresh_ui();
|
||||
bool read_capture(const std::filesystem::path& path);
|
||||
|
||||
std::filesystem::path path_{};
|
||||
TrimRange trim_range_{};
|
||||
std::array<PowerBuckets::Bucket, screen_width> power_buckets_{};
|
||||
uint8_t amp_threshold = 5;
|
||||
TrimProgressUI progress_ui{};
|
||||
|
||||
Labels labels{
|
||||
{{0 * 8, 0 * 16}, "Capture File:", Color::light_grey()},
|
||||
{{0 * 8, 6 * 16}, "Range:", Color::light_grey()},
|
||||
};
|
||||
|
||||
TextField field_path{
|
||||
{0 * 8, 1 * 16, 30 * 8, 1 * 16},
|
||||
"Open File..."};
|
||||
|
||||
Point pos_lines{0 * 8, 4 * 16};
|
||||
Dim height_lines{2 * 16};
|
||||
|
||||
Text text_range{
|
||||
{7 * 8, 6 * 16, 20 * 8, 1 * 16},
|
||||
{}};
|
||||
|
||||
Button button_trim{
|
||||
{11 * 8, 9 * 16, 8 * 8, 3 * 16},
|
||||
"Trim"};
|
||||
};
|
||||
|
||||
} /* namespace ui */
|
||||
|
||||
#endif /*__UI_IQ_TRIM_H__*/
|
Loading…
Add table
Add a link
Reference in a new issue