Skip to content

Commit

Permalink
IQ Trim app and Capture auto-trim (portapack-mayhem#1456)
Browse files Browse the repository at this point in the history
* Add IQ Trim app WIP
* Add 'trim' checkbox to capture
* Implement trimming
* Finish auto-trim
* Stray //
  • Loading branch information
kallanreed authored Sep 21, 2023
1 parent 070eb40 commit ef03f02
Show file tree
Hide file tree
Showing 11 changed files with 536 additions and 50 deletions.
57 changes: 29 additions & 28 deletions firmware/application/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -238,70 +238,71 @@ set(CPPSRC
ui/ui_textentry.cpp
ui/ui_tone_key.cpp
ui/ui_transmitter.cpp
apps/acars_app.cpp
apps/ais_app.cpp
apps/analog_audio_app.cpp
apps/analog_tv_app.cpp
apps/capture_app.cpp
apps/ert_app.cpp
apps/gps_sim_app.cpp
apps/lge_app.cpp
apps/lge_app.cpp
apps/pocsag_app.cpp
# apps/replay_app.cpp
apps/soundboard_app.cpp
apps/tpms_app.cpp
apps/tpms_app.cpp
apps/ui_about_simple.cpp
apps/ui_adsb_rx.cpp
apps/ui_adsb_tx.cpp
apps/ui_afsk_rx.cpp
apps/ui_aprs_rx.cpp
apps/ui_btle_rx.cpp
apps/ui_nrf_rx.cpp
apps/ui_aprs_tx.cpp
apps/ui_bht_tx.cpp
apps/ui_dfu_menu.cpp
apps/ui_btle_rx.cpp
apps/ui_coasterp.cpp
apps/ui_debug.cpp
apps/ui_dfu_menu.cpp
apps/ui_encoders.cpp
apps/ui_fileman.cpp
apps/ui_flash_utility.cpp
apps/ui_sd_over_usb.cpp
apps/ui_freqman.cpp
apps/ui_iq_trim.cpp
apps/ui_jammer.cpp
#apps/ui_keyfob.cpp
# apps/ui_keyfob.cpp
apps/ui_lcr.cpp
apps/lge_app.cpp
apps/ui_level.cpp
apps/ui_looking_glass_app.cpp
apps/ui_mictx.cpp
apps/ui_modemsetup.cpp
apps/ui_morse.cpp
apps/ui_nrf_rx.cpp
# apps/ui_nuoptix.cpp
apps/ui_playlist.cpp
apps/ui_pocsag_tx.cpp
apps/ui_rds.cpp
apps/ui_recon_settings.cpp
apps/ui_recon.cpp
apps/ui_remote.cpp
apps/ui_scanner.cpp
apps/ui_search.cpp
apps/ui_sd_over_usb.cpp
apps/ui_sd_wipe.cpp
apps/ui_search.cpp
apps/ui_settings.cpp
apps/ui_siggen.cpp
apps/ui_sonde.cpp
apps/ui_sstvtx.cpp
apps/ui_spectrum_painter_image.cpp
apps/ui_spectrum_painter_text.cpp
apps/ui_spectrum_painter.cpp
apps/ui_ss_viewer.cpp
apps/ui_sstvtx.cpp
# apps/ui_test.cpp
apps/ui_text_editor.cpp
apps/ui_tone_search.cpp
apps/ui_touch_calibration.cpp
apps/ui_touchtunes.cpp
apps/ui_view_wav.cpp
apps/ui_whipcalc.cpp
apps/acars_app.cpp
apps/ais_app.cpp
apps/analog_audio_app.cpp
apps/analog_tv_app.cpp
apps/capture_app.cpp
apps/ert_app.cpp
apps/lge_app.cpp
apps/pocsag_app.cpp
# apps/replay_app.cpp
apps/ui_playlist.cpp
apps/gps_sim_app.cpp
apps/soundboard_app.cpp
apps/ui_recon.cpp
apps/ui_recon_settings.cpp
apps/ui_level.cpp
apps/tpms_app.cpp
apps/tpms_app.cpp
apps/ui_spectrum_painter.cpp
apps/ui_spectrum_painter_image.cpp
apps/ui_spectrum_painter_text.cpp
protocols/aprs.cpp
protocols/ax25.cpp
protocols/bht.cpp
Expand Down
7 changes: 6 additions & 1 deletion firmware/application/apps/capture_app.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ CaptureAppView::CaptureAppView(NavigationView& nav)
&field_vga,
&option_bandwidth,
&option_format,
&check_trim,
&record_view,
&waterfall,
});
Expand All @@ -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
Expand Down Expand Up @@ -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);
Expand Down
6 changes: 6 additions & 0 deletions firmware/application/apps/capture_app.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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_????.*",
Expand Down
118 changes: 118 additions & 0 deletions firmware/application/apps/ui_iq_trim.cpp
Original file line number Diff line number Diff line change
@@ -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 changes: 108 additions & 0 deletions firmware/application/apps/ui_iq_trim.hpp
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit ef03f02

Please sign in to comment.