diff --git a/firmware/application/external/jammer/ui_jammer.cpp b/firmware/application/external/jammer/ui_jammer.cpp index b26c1f670..148150525 100644 --- a/firmware/application/external/jammer/ui_jammer.cpp +++ b/firmware/application/external/jammer/ui_jammer.cpp @@ -1,6 +1,7 @@ /* * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. * Copyright (C) 2016 Furrtek + * Copyright (C) 2025 RocketGod - Added modes from my Flipper Zero RF Jammer App - https://betaskynet.com * * This file is part of PortaPack. * @@ -36,7 +37,6 @@ void RangeView::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)); @@ -48,7 +48,6 @@ void RangeView::update_start(rf::Frequency f) { } void RangeView::update_stop(rf::Frequency f) { - // Change everything except min frequency_range.max = f; button_stop.set_text(to_string_short_freq(f)); @@ -60,7 +59,6 @@ void RangeView::update_stop(rf::Frequency f) { } void RangeView::update_center(rf::Frequency f) { - // Change min/max/center, keep width center = f; button_center.set_text(to_string_short_freq(center)); @@ -75,7 +73,6 @@ void RangeView::update_center(rf::Frequency f) { } void RangeView::update_width(uint32_t w) { - // Change min/max/width, keep center width = w; button_width.set_text(to_string_short_freq(width)); @@ -91,7 +88,6 @@ void RangeView::update_width(uint32_t w) { } void RangeView::paint(Painter&) { - // Draw lines and arrows Rect r; Point p; Coord c; @@ -162,7 +158,7 @@ RangeView::RangeView(NavigationView& nav) { auto load_view = nav.push(); load_view->on_frequency_loaded = [this](rf::Frequency value) { update_center(value); - update_width(100000); // 100kHz default jamming bandwidth when loading unique frequency + update_width(100000); }; load_view->on_range_loaded = [this](rf::Frequency start, rf::Frequency stop) { update_start(start); @@ -193,10 +189,37 @@ void JammerView::set_jammer_channel(uint32_t i, uint32_t width, uint64_t center, jammer_channels[i].enabled = true; jammer_channels[i].width = (width * 0xFFFFFFULL) / 1536000; jammer_channels[i].center = center; - jammer_channels[i].duration = 30720 * duration; + jammer_channels[i].duration = duration ? 30720 * duration : 0xFFFFFFFF; } void JammerView::start_tx() { + if (update_config()) { + 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); + transmitter_model.enable(); + + baseband::set_jammer(true, (JammerType)options_type.selected_index(), options_speed.selected_index_value()); + mscounter = 0; + } +} + +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; + seconds = 0; + mscounter = 0; +} + +bool JammerView::update_config() { uint32_t c, i = 0; size_t num_channels; rf::Frequency start_freq, range_bw, range_bw_sub, ch_width; @@ -204,24 +227,19 @@ void JammerView::start_tx() { 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; @@ -241,7 +259,6 @@ void JammerView::start_tx() { i++; } } else { - // Range fits in a single channel if (i >= JAMMER_MAX_CH) { out_of_ranges = true; } else { @@ -254,43 +271,24 @@ void JammerView::start_tx() { 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() + return true; } 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."); + return false; } } -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) { + if (++mscounter >= 60) { mscounter = 0; if (jamming) { + int32_t timepause = field_timepause.value(); 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 . + if (timepause == 0 || ++seconds >= timepause) { + transmitter_model.set_baseband_bandwidth(28'000'000); transmitter_model.enable(); button_transmit.set_text("STOP"); baseband::set_jammer(true, (JammerType)options_type.selected_index(), options_speed.selected_index_value()); @@ -306,8 +304,7 @@ void JammerView::on_timer() { seconds = 0; } } else { - if (++seconds >= field_timetx.value()) // Start cooling period: - { + if (timepause && ++seconds >= field_timetx.value()) { transmitter_model.disable(); button_transmit.set_text("PAUSED"); baseband::set_jammer(false, JammerType::TYPE_FSK, 0); @@ -327,11 +324,9 @@ void JammerView::on_timer() { } } -JammerView::JammerView( - NavigationView& nav) +JammerView::JammerView(NavigationView& nav) : nav_{nav} { Rect view_rect = {0, 3 * 8, screen_width, 80}; - // baseband::run_image(portapack::spi_flash::image_tag_jammer); baseband::run_prepared_image(portapack::memory::map::m4_code.base()); add_children({&tab_view, @@ -355,15 +350,101 @@ JammerView::JammerView( 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); + view_range_a.check_enabled.set_value(true); + view_range_a.frequency_range.enabled = true; + view_range_a.update_center(315'000'000); + view_range_a.update_width(1'000'000); + options_type.set_selected_index(3); + options_speed.set_selected_index(3); + options_hop.set_selected_index(0); field_timetx.set_value(30); - field_timepause.set_value(1); + field_timepause.set_value(0); + field_jitter.set_value(0); field_gain.set_value(transmitter_model.tx_gain()); field_amp.set_value(transmitter_model.rf_amp()); + button_transmit.set_style(&style_val); + + options_type.on_change = [this](size_t, OptionsField::value_t) { + if (jamming) update_config(); + if (jamming && !cooling) baseband::set_jammer(true, (JammerType)options_type.selected_index(), options_speed.selected_index_value()); + }; + + options_speed.on_change = [this](size_t, OptionsField::value_t) { + if (jamming) update_config(); + if (jamming && !cooling) baseband::set_jammer(true, (JammerType)options_type.selected_index(), options_speed.selected_index_value()); + }; + + options_hop.on_change = [this](size_t, OptionsField::value_t) { + if (jamming) update_config(); + }; + + field_timetx.on_change = [this](int32_t) { + if (jamming) update_config(); + }; + + field_timepause.on_change = [this](int32_t) { + if (jamming) update_config(); + }; + + field_jitter.on_change = [this](int32_t) { + if (jamming) update_config(); + }; + + field_gain.on_change = [this](int32_t v) { + if (jamming) transmitter_model.set_tx_gain(v); + }; + + field_amp.on_change = [this](int32_t v) { + if (jamming) transmitter_model.set_rf_amp(v); + }; + + for (auto range_view : range_views) { + range_view->check_enabled.on_select = [this](Checkbox&, bool) { + if (jamming) update_config(); + }; + range_view->button_start.on_select = [this, range_view](Button&) { + auto new_view = nav_.push(range_view->frequency_range.min); + new_view->on_changed = [this, range_view](rf::Frequency f) { + range_view->update_start(f); + if (jamming) update_config(); + }; + }; + range_view->button_stop.on_select = [this, range_view](Button&) { + auto new_view = nav_.push(range_view->frequency_range.max); + new_view->on_changed = [this, range_view](rf::Frequency f) { + range_view->update_stop(f); + if (jamming) update_config(); + }; + }; + range_view->button_center.on_select = [this, range_view](Button&) { + auto new_view = nav_.push(range_view->center); + new_view->on_changed = [this, range_view](rf::Frequency f) { + range_view->update_center(f); + if (jamming) update_config(); + }; + }; + range_view->button_width.on_select = [this, range_view](Button&) { + auto new_view = nav_.push(range_view->width); + new_view->on_changed = [this, range_view](rf::Frequency f) { + range_view->update_width(f); + if (jamming) update_config(); + }; + }; + range_view->button_load_range.on_select = [this, range_view](Button&) { + auto load_view = nav_.push(); + load_view->on_frequency_loaded = [this, range_view](rf::Frequency value) { + range_view->update_center(value); + range_view->update_width(100000); + if (jamming) update_config(); + }; + load_view->on_range_loaded = [this, range_view](rf::Frequency start, rf::Frequency stop) { + range_view->update_start(start); + range_view->update_stop(stop); + if (jamming) update_config(); + }; + }; + } button_transmit.on_select = [this](Button&) { if (jamming || cooling) diff --git a/firmware/application/external/jammer/ui_jammer.hpp b/firmware/application/external/jammer/ui_jammer.hpp index 73b2d9dcd..b338cdd47 100644 --- a/firmware/application/external/jammer/ui_jammer.hpp +++ b/firmware/application/external/jammer/ui_jammer.hpp @@ -41,27 +41,12 @@ class RangeView : public View { RangeView(NavigationView& nav); void focus() override; - void paint(Painter&) override; + void paint(Painter& 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 = *Theme::getInstance()->fg_medium; - - Labels labels{ - {{2 * 8, 8 * 8 + 4}, LanguageHelper::currentMessages[LANG_START], Theme::getInstance()->fg_light->foreground}, - {{23 * 8, 8 * 8 + 4}, LanguageHelper::currentMessages[LANG_STOP], Theme::getInstance()->fg_light->foreground}, - {{12 * 8, 5 * 8 - 4}, "Center", Theme::getInstance()->fg_light->foreground}, - {{12 * 8 + 4, 13 * 8}, "Width", Theme::getInstance()->fg_light->foreground}}; - Checkbox check_enabled{ {1 * 8, 4}, 12, @@ -74,15 +59,32 @@ class RangeView : public View { 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}, ""}; + + void update_start(rf::Frequency f); + void update_stop(rf::Frequency f); + void update_center(rf::Frequency f); + void update_width(uint32_t w); + + private: + const Style& style_info = *Theme::getInstance()->fg_medium; + + Labels labels{ + {{2 * 8, 8 * 8 + 4}, LanguageHelper::currentMessages[LANG_START], Theme::getInstance()->fg_light->foreground}, + {{23 * 8, 8 * 8 + 4}, LanguageHelper::currentMessages[LANG_STOP], Theme::getInstance()->fg_light->foreground}, + {{12 * 8, 5 * 8 - 4}, "Center", Theme::getInstance()->fg_light->foreground}, + {{12 * 8 + 4, 13 * 8}, "Width", Theme::getInstance()->fg_light->foreground}}; }; class JammerView : public View { @@ -110,15 +112,16 @@ class JammerView : public View { void start_tx(); void on_timer(); void stop_tx(); + bool update_config(); 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 + bool cooling{false}; + uint16_t seconds{0}; + int16_t mscounter{0}; + lfsr_word_t lfsr_v{1}; const Style& style_val = *Theme::getInstance()->fg_green; const Style& style_cancel = *Theme::getInstance()->fg_red; @@ -140,8 +143,8 @@ class JammerView : public View { {{1 * 8, 25 * 8}, "Speed:", Theme::getInstance()->fg_light->foreground}, {{3 * 8, 27 * 8}, "Hop:", Theme::getInstance()->fg_light->foreground}, {{4 * 8, 29 * 8}, "TX:", Theme::getInstance()->fg_light->foreground}, - {{1 * 8, 31 * 8}, "Sle3p:", Theme::getInstance()->fg_light->foreground}, // euquiq: Token of appreciation to TheSle3p, which made this ehnancement a reality with his bounty. - {{0 * 8, 33 * 8}, "Jitter:", Theme::getInstance()->fg_light->foreground}, // Maybe the repository curator can keep the "mystype" for some versions. + {{1 * 8, 31 * 8}, "Sleep:", Theme::getInstance()->fg_light->foreground}, + {{0 * 8, 33 * 8}, "Jitter:", Theme::getInstance()->fg_light->foreground}, {{11 * 8, 29 * 8}, "Secs.", Theme::getInstance()->fg_light->foreground}, {{11 * 8, 31 * 8}, "Secs.", Theme::getInstance()->fg_light->foreground}, {{11 * 8, 33 * 8}, "/60", Theme::getInstance()->fg_light->foreground}, @@ -182,7 +185,8 @@ class JammerView : public View { OptionsField options_hop{ {7 * 8, 27 * 8}, 5, - {{"10ms ", 1}, + {{"Off ", 0}, + {"10ms ", 1}, {"50ms ", 5}, {"100ms", 10}, {"1s ", 100}, @@ -201,7 +205,7 @@ class JammerView : public View { NumberField field_timepause{ {8 * 8, 31 * 8}, 2, - {1, 60}, + {0, 60}, 1, ' ', }; @@ -209,7 +213,7 @@ class JammerView : public View { NumberField field_jitter{ {8 * 8, 33 * 8}, 2, - {1, 60}, + {0, 60}, 1, ' ', };