mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2025-08-13 23:27:40 +00:00
Move Jammer ext app (with baseband image too) (#1647)
This commit is contained in:
5
firmware/application/external/external.cmake
vendored
5
firmware/application/external/external.cmake
vendored
@@ -40,6 +40,10 @@ set(EXTCPPSRC
|
||||
external/lcr/main.cpp
|
||||
external/lcr/ui_lcr.cpp
|
||||
|
||||
|
||||
#lcr
|
||||
external/jammer/main.cpp
|
||||
external/jammer/ui_jammer.cpp
|
||||
)
|
||||
|
||||
set(EXTAPPLIST
|
||||
@@ -53,4 +57,5 @@ set(EXTAPPLIST
|
||||
coasterp
|
||||
lge
|
||||
lcr
|
||||
jammer
|
||||
)
|
||||
|
9
firmware/application/external/external.ld
vendored
9
firmware/application/external/external.ld
vendored
@@ -27,6 +27,7 @@ MEMORY
|
||||
ram_external_app_coasterp(rwx) : org = 0xEEF00000, len = 32k
|
||||
ram_external_app_lge(rwx) : org = 0xEEF10000, len = 32k
|
||||
ram_external_app_lcr(rwx) : org = 0xEEF20000, len = 32k
|
||||
ram_external_app_jammer(rwx) : org = 0xEEF30000, len = 32k
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
@@ -93,4 +94,12 @@ SECTIONS
|
||||
*(*ui*external_app*lcr*);
|
||||
} > ram_external_app_lcr
|
||||
|
||||
|
||||
.external_app_jammer : ALIGN(4) SUBALIGN(4)
|
||||
{
|
||||
KEEP(*(.external_app.app_jammer.application_information));
|
||||
*(*ui*external_app*jammer*);
|
||||
} > ram_external_app_jammer
|
||||
|
||||
|
||||
}
|
||||
|
82
firmware/application/external/jammer/main.cpp
vendored
Normal file
82
firmware/application/external/jammer/main.cpp
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* 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.hpp"
|
||||
#include "ui_jammer.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
#include "external_app.hpp"
|
||||
|
||||
namespace ui::external_app::jammer {
|
||||
void initialize_app(ui::NavigationView& nav) {
|
||||
nav.push<JammerView>();
|
||||
}
|
||||
} // namespace ui::external_app::jammer
|
||||
|
||||
extern "C" {
|
||||
|
||||
__attribute__((section(".external_app.app_jammer.application_information"), used)) application_information_t _application_information_jammer = {
|
||||
/*.memory_location = */ (uint8_t*)0x00000000,
|
||||
/*.externalAppEntry = */ ui::external_app::jammer::initialize_app,
|
||||
/*.header_version = */ CURRENT_HEADER_VERSION,
|
||||
/*.app_version = */ VERSION_MD5,
|
||||
|
||||
/*.app_name = */ "Jammer",
|
||||
/*.bitmap_data = */ {
|
||||
0xE0,
|
||||
0x07,
|
||||
0xF8,
|
||||
0x1F,
|
||||
0x1C,
|
||||
0x38,
|
||||
0x0E,
|
||||
0x78,
|
||||
0x06,
|
||||
0x7C,
|
||||
0x03,
|
||||
0xCE,
|
||||
0x03,
|
||||
0xC7,
|
||||
0x83,
|
||||
0xC3,
|
||||
0xC3,
|
||||
0xC1,
|
||||
0xE3,
|
||||
0xC0,
|
||||
0x73,
|
||||
0xC0,
|
||||
0x3E,
|
||||
0x60,
|
||||
0x1E,
|
||||
0x70,
|
||||
0x1C,
|
||||
0x38,
|
||||
0xF8,
|
||||
0x1F,
|
||||
0xE0,
|
||||
0x07,
|
||||
},
|
||||
/*.icon_color = */ ui::Color::green().v,
|
||||
/*.menu_location = */ app_location_t::TX,
|
||||
|
||||
/*.m4_app_tag = portapack::spi_flash::image_tag_jammer */ {'P', 'J', 'A', 'M'},
|
||||
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
|
||||
};
|
||||
}
|
376
firmware/application/external/jammer/ui_jammer.cpp
vendored
Normal file
376
firmware/application/external/jammer/ui_jammer.cpp
vendored
Normal file
@@ -0,0 +1,376 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2016 Furrtek
|
||||
*
|
||||
* 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_jammer.hpp"
|
||||
#include "ui_receiver.hpp"
|
||||
#include "ui_freqman.hpp"
|
||||
|
||||
#include "baseband_api.hpp"
|
||||
#include "string_format.hpp"
|
||||
|
||||
using namespace portapack;
|
||||
|
||||
namespace ui::external_app::jammer {
|
||||
|
||||
void RangeView::focus() {
|
||||
check_enabled.focus();
|
||||
}
|
||||
|
||||
void RangeView::update_start(rf::Frequency f) {
|
||||
// Change everything except max
|
||||
frequency_range.min = f;
|
||||
button_start.set_text(to_string_short_freq(f));
|
||||
|
||||
center = (frequency_range.min + frequency_range.max) / 2;
|
||||
width = abs(frequency_range.max - frequency_range.min);
|
||||
|
||||
button_center.set_text(to_string_short_freq(center));
|
||||
button_width.set_text(to_string_short_freq(width));
|
||||
}
|
||||
|
||||
void RangeView::update_stop(rf::Frequency f) {
|
||||
// Change everything except min
|
||||
frequency_range.max = f;
|
||||
button_stop.set_text(to_string_short_freq(f));
|
||||
|
||||
center = (frequency_range.min + frequency_range.max) / 2;
|
||||
width = abs(frequency_range.max - frequency_range.min);
|
||||
|
||||
button_center.set_text(to_string_short_freq(center));
|
||||
button_width.set_text(to_string_short_freq(width));
|
||||
}
|
||||
|
||||
void RangeView::update_center(rf::Frequency f) {
|
||||
// Change min/max/center, keep width
|
||||
center = f;
|
||||
button_center.set_text(to_string_short_freq(center));
|
||||
|
||||
rf::Frequency min = center - (width / 2);
|
||||
rf::Frequency max = min + width;
|
||||
|
||||
frequency_range.min = min;
|
||||
button_start.set_text(to_string_short_freq(min));
|
||||
|
||||
frequency_range.max = max;
|
||||
button_stop.set_text(to_string_short_freq(max));
|
||||
}
|
||||
|
||||
void RangeView::update_width(uint32_t w) {
|
||||
// Change min/max/width, keep center
|
||||
width = w;
|
||||
|
||||
button_width.set_text(to_string_short_freq(width));
|
||||
|
||||
rf::Frequency min = center - (width / 2);
|
||||
rf::Frequency max = min + width;
|
||||
|
||||
frequency_range.min = min;
|
||||
button_start.set_text(to_string_short_freq(min));
|
||||
|
||||
frequency_range.max = max;
|
||||
button_stop.set_text(to_string_short_freq(max));
|
||||
}
|
||||
|
||||
void RangeView::paint(Painter&) {
|
||||
// Draw lines and arrows
|
||||
Rect r;
|
||||
Point p;
|
||||
Coord c;
|
||||
|
||||
r = button_center.screen_rect();
|
||||
p = r.center() + Point(0, r.height() / 2);
|
||||
|
||||
display.draw_line(p, p + Point(0, 10), Color::grey());
|
||||
|
||||
r = button_width.screen_rect();
|
||||
c = r.top() + (r.height() / 2);
|
||||
|
||||
p = {r.left() - 64, c};
|
||||
display.draw_line({r.left(), c}, p, Color::grey());
|
||||
display.draw_line(p, p + Point(10, -10), Color::grey());
|
||||
display.draw_line(p, p + Point(10, 10), Color::grey());
|
||||
|
||||
p = {r.right() + 64, c};
|
||||
display.draw_line({r.right(), c}, p, Color::grey());
|
||||
display.draw_line(p, p + Point(-10, -10), Color::grey());
|
||||
display.draw_line(p, p + Point(-10, 10), Color::grey());
|
||||
}
|
||||
|
||||
RangeView::RangeView(NavigationView& nav) {
|
||||
hidden(true);
|
||||
|
||||
add_children({&labels,
|
||||
&check_enabled,
|
||||
&button_load_range,
|
||||
&button_start,
|
||||
&button_stop,
|
||||
&button_center,
|
||||
&button_width});
|
||||
|
||||
check_enabled.on_select = [this](Checkbox&, bool v) {
|
||||
frequency_range.enabled = v;
|
||||
};
|
||||
|
||||
button_start.on_select = [this, &nav](Button& button) {
|
||||
auto new_view = nav.push<FrequencyKeypadView>(frequency_range.min);
|
||||
new_view->on_changed = [this, &button](rf::Frequency f) {
|
||||
update_start(f);
|
||||
};
|
||||
};
|
||||
|
||||
button_stop.on_select = [this, &nav](Button& button) {
|
||||
auto new_view = nav.push<FrequencyKeypadView>(frequency_range.max);
|
||||
new_view->on_changed = [this, &button](rf::Frequency f) {
|
||||
update_stop(f);
|
||||
};
|
||||
};
|
||||
|
||||
button_center.on_select = [this, &nav](Button& button) {
|
||||
auto new_view = nav.push<FrequencyKeypadView>(center);
|
||||
new_view->on_changed = [this, &button](rf::Frequency f) {
|
||||
update_center(f);
|
||||
};
|
||||
};
|
||||
|
||||
button_width.on_select = [this, &nav](Button& button) {
|
||||
auto new_view = nav.push<FrequencyKeypadView>(width);
|
||||
new_view->on_changed = [this, &button](rf::Frequency f) {
|
||||
update_width(f);
|
||||
};
|
||||
};
|
||||
|
||||
button_load_range.on_select = [this, &nav](Button&) {
|
||||
auto load_view = nav.push<FrequencyLoadView>();
|
||||
load_view->on_frequency_loaded = [this](rf::Frequency value) {
|
||||
update_center(value);
|
||||
update_width(100000); // 100kHz default jamming bandwidth when loading unique frequency
|
||||
};
|
||||
load_view->on_range_loaded = [this](rf::Frequency start, rf::Frequency stop) {
|
||||
update_start(start);
|
||||
update_stop(stop);
|
||||
};
|
||||
};
|
||||
|
||||
check_enabled.set_value(false);
|
||||
}
|
||||
|
||||
void JammerView::focus() {
|
||||
tab_view.focus();
|
||||
}
|
||||
|
||||
JammerView::~JammerView() {
|
||||
transmitter_model.disable();
|
||||
baseband::shutdown();
|
||||
}
|
||||
|
||||
void JammerView::on_retune(const rf::Frequency freq, const uint32_t range) {
|
||||
if (freq) {
|
||||
transmitter_model.set_target_frequency(freq);
|
||||
text_range_number.set(to_string_dec_uint(range, 2));
|
||||
}
|
||||
}
|
||||
|
||||
void JammerView::set_jammer_channel(uint32_t i, uint32_t width, uint64_t center, uint32_t duration) {
|
||||
jammer_channels[i].enabled = true;
|
||||
jammer_channels[i].width = (width * 0xFFFFFFULL) / 1536000;
|
||||
jammer_channels[i].center = center;
|
||||
jammer_channels[i].duration = 30720 * duration;
|
||||
}
|
||||
|
||||
void JammerView::start_tx() {
|
||||
uint32_t c, i = 0;
|
||||
size_t num_channels;
|
||||
rf::Frequency start_freq, range_bw, range_bw_sub, ch_width;
|
||||
bool out_of_ranges = false;
|
||||
|
||||
size_t hop_value = options_hop.selected_index_value();
|
||||
|
||||
// Disable all channels by default
|
||||
for (c = 0; c < JAMMER_MAX_CH; c++)
|
||||
jammer_channels[c].enabled = false;
|
||||
|
||||
// Generate jamming channels with JAMMER_MAX_CH maximum width
|
||||
// Convert ranges min/max to center/bw
|
||||
for (size_t r = 0; r < 3; r++) {
|
||||
if (range_views[r]->frequency_range.enabled) {
|
||||
range_bw = abs(range_views[r]->frequency_range.max - range_views[r]->frequency_range.min);
|
||||
|
||||
// Get lower bound
|
||||
if (range_views[r]->frequency_range.min < range_views[r]->frequency_range.max)
|
||||
start_freq = range_views[r]->frequency_range.min;
|
||||
else
|
||||
start_freq = range_views[r]->frequency_range.max;
|
||||
|
||||
if (range_bw >= JAMMER_CH_WIDTH) {
|
||||
// Split range in multiple channels
|
||||
num_channels = 0;
|
||||
range_bw_sub = range_bw;
|
||||
|
||||
do {
|
||||
range_bw_sub -= JAMMER_CH_WIDTH;
|
||||
num_channels++;
|
||||
} while (range_bw_sub >= JAMMER_CH_WIDTH);
|
||||
|
||||
ch_width = range_bw / num_channels;
|
||||
|
||||
for (c = 0; c < num_channels; c++) {
|
||||
if (i >= JAMMER_MAX_CH) {
|
||||
out_of_ranges = true;
|
||||
break;
|
||||
}
|
||||
set_jammer_channel(i, ch_width, start_freq + (ch_width / 2) + (ch_width * c), hop_value);
|
||||
i++;
|
||||
}
|
||||
} else {
|
||||
// Range fits in a single channel
|
||||
if (i >= JAMMER_MAX_CH) {
|
||||
out_of_ranges = true;
|
||||
} else {
|
||||
set_jammer_channel(i, range_bw, start_freq + (range_bw / 2), hop_value);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!out_of_ranges && i) {
|
||||
text_range_total.set("/" + to_string_dec_uint(i, 2));
|
||||
|
||||
jamming = true;
|
||||
button_transmit.set_style(&style_cancel);
|
||||
button_transmit.set_text("STOP");
|
||||
|
||||
transmitter_model.set_rf_amp(field_amp.value());
|
||||
transmitter_model.set_tx_gain(field_gain.value());
|
||||
transmitter_model.set_baseband_bandwidth(28'000'000); // Although tx is narrowband , let's use Max TX LPF .
|
||||
transmitter_model.enable();
|
||||
|
||||
baseband::set_jammer(true, (JammerType)options_type.selected_index(), options_speed.selected_index_value());
|
||||
mscounter = 0; // euquiq: Reset internal ms counter for do_timer()
|
||||
} else {
|
||||
if (out_of_ranges)
|
||||
nav_.display_modal("Error", "Jamming bandwidth too large.\nMust be less than 24MHz.");
|
||||
else
|
||||
nav_.display_modal("Error", "No range enabled.");
|
||||
}
|
||||
}
|
||||
|
||||
void JammerView::stop_tx() {
|
||||
button_transmit.set_style(&style_val);
|
||||
button_transmit.set_text("START");
|
||||
transmitter_model.disable();
|
||||
baseband::set_jammer(false, JammerType::TYPE_FSK, 0);
|
||||
jamming = false;
|
||||
cooling = false;
|
||||
}
|
||||
|
||||
// called each 1/60th of second
|
||||
void JammerView::on_timer() {
|
||||
if (++mscounter == 60) {
|
||||
mscounter = 0;
|
||||
if (jamming) {
|
||||
if (cooling) {
|
||||
if (++seconds >= field_timepause.value()) { // Re-start TX
|
||||
transmitter_model.set_baseband_bandwidth(28'000'000); // Although tx is narrowband , let's use Max TX LPF .
|
||||
transmitter_model.enable();
|
||||
button_transmit.set_text("STOP");
|
||||
baseband::set_jammer(true, (JammerType)options_type.selected_index(), options_speed.selected_index_value());
|
||||
|
||||
int32_t jitter_amount = field_jitter.value();
|
||||
if (jitter_amount) {
|
||||
lfsr_v = lfsr_iterate(lfsr_v);
|
||||
jitter_amount = (jitter_amount / 2) - (lfsr_v & jitter_amount);
|
||||
mscounter += jitter_amount;
|
||||
}
|
||||
|
||||
cooling = false;
|
||||
seconds = 0;
|
||||
}
|
||||
} else {
|
||||
if (++seconds >= field_timetx.value()) // Start cooling period:
|
||||
{
|
||||
transmitter_model.disable();
|
||||
button_transmit.set_text("PAUSED");
|
||||
baseband::set_jammer(false, JammerType::TYPE_FSK, 0);
|
||||
|
||||
int32_t jitter_amount = field_jitter.value();
|
||||
if (jitter_amount) {
|
||||
lfsr_v = lfsr_iterate(lfsr_v);
|
||||
jitter_amount = (jitter_amount / 2) - (lfsr_v & jitter_amount);
|
||||
mscounter += jitter_amount;
|
||||
}
|
||||
|
||||
cooling = true;
|
||||
seconds = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JammerView::JammerView(
|
||||
NavigationView& nav)
|
||||
: nav_{nav} {
|
||||
Rect view_rect = {0, 3 * 8, 240, 80};
|
||||
// baseband::run_image(portapack::spi_flash::image_tag_jammer);
|
||||
baseband::run_prepared_image(portapack::memory::map::m4_code.base());
|
||||
|
||||
add_children({&tab_view,
|
||||
&view_range_a,
|
||||
&view_range_b,
|
||||
&view_range_c,
|
||||
&labels,
|
||||
&options_type,
|
||||
&text_range_number,
|
||||
&text_range_total,
|
||||
&options_speed,
|
||||
&options_hop,
|
||||
&field_timetx,
|
||||
&field_timepause,
|
||||
&field_jitter,
|
||||
&field_gain,
|
||||
&field_amp,
|
||||
&button_transmit});
|
||||
|
||||
view_range_a.set_parent_rect(view_rect);
|
||||
view_range_b.set_parent_rect(view_rect);
|
||||
view_range_c.set_parent_rect(view_rect);
|
||||
|
||||
options_type.set_selected_index(3); // Rand CW
|
||||
options_speed.set_selected_index(3); // 10kHz
|
||||
options_hop.set_selected_index(1); // 50ms
|
||||
button_transmit.set_style(&style_val);
|
||||
|
||||
field_timetx.set_value(30);
|
||||
field_timepause.set_value(1);
|
||||
field_gain.set_value(transmitter_model.tx_gain());
|
||||
field_amp.set_value(transmitter_model.rf_amp());
|
||||
|
||||
button_transmit.on_select = [this](Button&) {
|
||||
if (jamming || cooling)
|
||||
stop_tx();
|
||||
else
|
||||
start_tx();
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace ui::external_app::jammer
|
245
firmware/application/external/jammer/ui_jammer.hpp
vendored
Normal file
245
firmware/application/external/jammer/ui_jammer.hpp
vendored
Normal file
@@ -0,0 +1,245 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2016 Furrtek
|
||||
*
|
||||
* 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.hpp"
|
||||
#include "ui_widget.hpp"
|
||||
#include "ui_styles.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
#include "ui_tabview.hpp"
|
||||
#include "transmitter_model.hpp"
|
||||
#include "message.hpp"
|
||||
#include "jammer.hpp"
|
||||
#include "lfsr_random.hpp"
|
||||
#include "radio_state.hpp"
|
||||
|
||||
using namespace jammer;
|
||||
|
||||
namespace ui::external_app::jammer {
|
||||
|
||||
class RangeView : public View {
|
||||
public:
|
||||
RangeView(NavigationView& nav);
|
||||
|
||||
void focus() override;
|
||||
void paint(Painter&) override;
|
||||
|
||||
jammer_range_t frequency_range{false, 0, 0};
|
||||
|
||||
private:
|
||||
void update_start(rf::Frequency f);
|
||||
void update_stop(rf::Frequency f);
|
||||
void update_center(rf::Frequency f);
|
||||
void update_width(uint32_t w);
|
||||
|
||||
uint32_t width{};
|
||||
rf::Frequency center{};
|
||||
|
||||
const Style& style_info = Styles::grey;
|
||||
|
||||
Labels labels{
|
||||
{{2 * 8, 8 * 8 + 4}, "Start", Color::light_grey()},
|
||||
{{23 * 8, 8 * 8 + 4}, "Stop", Color::light_grey()},
|
||||
{{12 * 8, 5 * 8 - 4}, "Center", Color::light_grey()},
|
||||
{{12 * 8 + 4, 13 * 8}, "Width", Color::light_grey()}};
|
||||
|
||||
Checkbox check_enabled{
|
||||
{1 * 8, 4},
|
||||
12,
|
||||
"Enable range"};
|
||||
|
||||
Button button_load_range{
|
||||
{18 * 8, 4, 12 * 8, 24},
|
||||
"Load range"};
|
||||
|
||||
Button button_start{
|
||||
{0 * 8, 11 * 8, 11 * 8, 28},
|
||||
""};
|
||||
Button button_stop{
|
||||
{19 * 8, 11 * 8, 11 * 8, 28},
|
||||
""};
|
||||
Button button_center{
|
||||
{76, 4 * 15 - 4, 11 * 8, 28},
|
||||
""};
|
||||
Button button_width{
|
||||
{76, 8 * 15, 11 * 8, 28},
|
||||
""};
|
||||
};
|
||||
|
||||
class JammerView : public View {
|
||||
public:
|
||||
JammerView(NavigationView& nav);
|
||||
~JammerView();
|
||||
|
||||
JammerView(const JammerView&) = delete;
|
||||
JammerView(JammerView&&) = delete;
|
||||
JammerView& operator=(const JammerView&) = delete;
|
||||
JammerView& operator=(JammerView&&) = delete;
|
||||
|
||||
void focus() override;
|
||||
|
||||
std::string title() const override { return "Jammer TX"; };
|
||||
|
||||
private:
|
||||
NavigationView& nav_;
|
||||
TxRadioState radio_state_{
|
||||
0 /* frequency */,
|
||||
3500000 /* bandwidth */,
|
||||
3072000 /* sampling rate */
|
||||
};
|
||||
|
||||
void start_tx();
|
||||
void on_timer();
|
||||
void stop_tx();
|
||||
void set_jammer_channel(uint32_t i, uint32_t width, uint64_t center, uint32_t duration);
|
||||
void on_retune(const rf::Frequency freq, const uint32_t range);
|
||||
|
||||
JammerChannel* jammer_channels = (JammerChannel*)shared_memory.bb_data.data;
|
||||
bool jamming{false};
|
||||
bool cooling{false}; // euquiq: Indicates jammer in cooldown
|
||||
uint16_t seconds = 0; // euquiq: seconds counter for toggling tx / cooldown
|
||||
int16_t mscounter = 0; // euquiq: Internal ms counter for do_timer()
|
||||
lfsr_word_t lfsr_v = 1; // euquiq: Used to generate "random" Jitter
|
||||
|
||||
const Style& style_val = Styles::green;
|
||||
const Style& style_cancel = Styles::red;
|
||||
|
||||
RangeView view_range_a{nav_};
|
||||
RangeView view_range_b{nav_};
|
||||
RangeView view_range_c{nav_};
|
||||
|
||||
std::array<RangeView*, 3> range_views{{&view_range_a, &view_range_b, &view_range_c}};
|
||||
|
||||
TabView tab_view{
|
||||
{"Range 1", Color::white(), range_views[0]},
|
||||
{"Range 2", Color::white(), range_views[1]},
|
||||
{"Range 3", Color::white(), range_views[2]},
|
||||
};
|
||||
|
||||
Labels labels{
|
||||
{{2 * 8, 23 * 8}, "Type:", Color::light_grey()},
|
||||
{{1 * 8, 25 * 8}, "Speed:", Color::light_grey()},
|
||||
{{3 * 8, 27 * 8}, "Hop:", Color::light_grey()},
|
||||
{{4 * 8, 29 * 8}, "TX:", Color::light_grey()},
|
||||
{{1 * 8, 31 * 8}, "Sle3p:", Color::light_grey()}, // euquiq: Token of appreciation to TheSle3p, which made this ehnancement a reality with his bounty.
|
||||
{{0 * 8, 33 * 8}, "Jitter:", Color::light_grey()}, // Maybe the repository curator can keep the "mystype" for some versions.
|
||||
{{11 * 8, 29 * 8}, "Secs.", Color::light_grey()},
|
||||
{{11 * 8, 31 * 8}, "Secs.", Color::light_grey()},
|
||||
{{11 * 8, 33 * 8}, "/60", Color::light_grey()},
|
||||
{{2 * 8, 35 * 8}, "Gain:", Color::light_grey()},
|
||||
{{11 * 8, 35 * 8}, "A:", Color::light_grey()}};
|
||||
|
||||
OptionsField options_type{
|
||||
{7 * 8, 23 * 8},
|
||||
8,
|
||||
{
|
||||
{"Rand FSK", 0},
|
||||
{"FM tone", 1},
|
||||
{"CW sweep", 2},
|
||||
{"Rand CW", 3},
|
||||
}};
|
||||
|
||||
Text text_range_number{
|
||||
{16 * 8, 23 * 8, 2 * 8, 16},
|
||||
"--"};
|
||||
Text text_range_total{
|
||||
{18 * 8, 23 * 8, 3 * 8, 16},
|
||||
"/--"};
|
||||
|
||||
OptionsField options_speed{
|
||||
{7 * 8, 25 * 8},
|
||||
6,
|
||||
{{"10Hz ", 10},
|
||||
{"100Hz ", 100},
|
||||
{"1kHz ", 1000},
|
||||
{"10kHz ", 10000},
|
||||
{"100kHz", 100000}}};
|
||||
|
||||
OptionsField options_hop{
|
||||
{7 * 8, 27 * 8},
|
||||
5,
|
||||
{{"10ms ", 1},
|
||||
{"50ms ", 5},
|
||||
{"100ms", 10},
|
||||
{"1s ", 100},
|
||||
{"2s ", 200},
|
||||
{"5s ", 500},
|
||||
{"10s ", 1000}}};
|
||||
|
||||
NumberField field_timetx{
|
||||
{7 * 8, 29 * 8},
|
||||
3,
|
||||
{1, 180},
|
||||
1,
|
||||
' ',
|
||||
};
|
||||
|
||||
NumberField field_timepause{
|
||||
{8 * 8, 31 * 8},
|
||||
2,
|
||||
{1, 60},
|
||||
1,
|
||||
' ',
|
||||
};
|
||||
|
||||
NumberField field_jitter{
|
||||
{8 * 8, 33 * 8},
|
||||
2,
|
||||
{1, 60},
|
||||
1,
|
||||
' ',
|
||||
};
|
||||
|
||||
NumberField field_gain{
|
||||
{8 * 8, 35 * 8},
|
||||
2,
|
||||
{0, 47},
|
||||
1,
|
||||
' ',
|
||||
};
|
||||
|
||||
NumberField field_amp{
|
||||
{13 * 8, 35 * 8},
|
||||
1,
|
||||
{0, 1},
|
||||
1,
|
||||
' ',
|
||||
};
|
||||
|
||||
Button button_transmit{
|
||||
{148, 216, 80, 80},
|
||||
"START"};
|
||||
|
||||
MessageHandlerRegistration message_handler_retune{
|
||||
Message::ID::Retune,
|
||||
[this](Message* const p) {
|
||||
const auto message = static_cast<const RetuneMessage*>(p);
|
||||
this->on_retune(message->freq, message->range);
|
||||
}};
|
||||
|
||||
MessageHandlerRegistration message_handler_frame_sync{
|
||||
Message::ID::DisplayFrameSync,
|
||||
[this](const Message* const) {
|
||||
this->on_timer();
|
||||
}};
|
||||
};
|
||||
|
||||
} // namespace ui::external_app::jammer
|
Reference in New Issue
Block a user