// CVS Spam app by RocketGod (@rocketgod-git) https://betaskynet.com // Original .cu8 files by @jimilinuxguy https://github.com/jimilinuxguy/customer-assistance-buttons-sdr // If you can read this, you're a nerd. :P // Come join us at https://discord.gg/thepiratesreborn #pragma once #include "ui_widget.hpp" #include "ui_transmitter.hpp" #include "replay_thread.hpp" #include "baseband_api.hpp" #include "ui_language.hpp" #include "file_path.hpp" using namespace portapack; namespace ui::external_app::cvs_spam { constexpr uint32_t SAMPLE_RATE = 250000; constexpr uint64_t TARGET_FREQUENCY = 433920000; class CVSSpamView : public View { public: explicit CVSSpamView(NavigationView& nav); ~CVSSpamView(); void focus() override; std::string title() const override { return "CVS Spam"; }; private: static constexpr size_t read_size = 0x4000; static constexpr size_t buffer_count = 3; lfsr_word_t lfsr_v = 1; bool chaos_mode{false}; NavigationView& nav_; std::unique_ptr replay_thread{}; bool ready_signal{false}; bool thread_sync_complete{false}; std::filesystem::path current_file; bool is_active() const; void stop_tx(); void file_error(const std::filesystem::path& path, const std::string& error_details); void refresh_list(); void start_tx(const uint32_t id); void start_random_tx(); void on_tx_progress(const uint32_t progress); uint32_t page = 1; uint32_t current_page = 1; std::vector file_list{}; MenuView menu_view{ {0, 0, screen_width, UI_POS_HEIGHT_REMAINING(12)}, true}; Text text_empty{ {UI_POS_X_CENTER(16), 12 * 8, UI_POS_WIDTH(16), UI_POS_HEIGHT(1)}, "Empty directory!"}; Button button_prev_page{ {0, UI_POS_Y_BOTTOM(10), UI_POS_WIDTH(4), UI_POS_HEIGHT(2)}, "<"}; Button button_next_page{ {UI_POS_X_RIGHT(3), UI_POS_Y_BOTTOM(10), UI_POS_WIDTH(4), UI_POS_HEIGHT(2)}, ">"}; Text page_info{ {UI_POS_X_CENTER(7), UI_POS_Y_BOTTOM(9.5), UI_POS_WIDTH(7), UI_POS_HEIGHT(1)}}; Button button_send{ {0, UI_POS_Y_BOTTOM(8), UI_POS_WIDTH(9), UI_POS_HEIGHT(2)}, "CALL"}; Button button_chaos{ {UI_POS_X_CENTER(9), UI_POS_Y_BOTTOM(8), UI_POS_WIDTH(9), UI_POS_HEIGHT(2)}, "CHAOS"}; Button button_stop{ {UI_POS_X_RIGHT(9), UI_POS_Y_BOTTOM(8), UI_POS_WIDTH(9), UI_POS_HEIGHT(2)}, LanguageHelper::currentMessages[LANG_STOP]}; ProgressBar progressbar{ {0, UI_POS_Y_BOTTOM(6), screen_width, UI_POS_HEIGHT(5)}}; MessageHandlerRegistration message_handler_fifo_signal{ Message::ID::RequestSignal, [this](const Message* const p) { const auto message = static_cast(p); if (message->signal == RequestSignalMessage::Signal::FillRequest) { ready_signal = true; } }}; MessageHandlerRegistration message_handler_tx_progress{ Message::ID::TXProgress, [this](const Message* const p) { const auto message = *reinterpret_cast(p); this->on_tx_progress(message.progress); }}; MessageHandlerRegistration message_handler_replay_thread_done{ Message::ID::ReplayThreadDone, [this](const Message* const p) { const auto message = *reinterpret_cast(p); if (message.return_code == ReplayThread::END_OF_FILE) { if (chaos_mode) { replay_thread.reset(); transmitter_model.disable(); ready_signal = false; lfsr_v = lfsr_iterate(lfsr_v); size_t random_index = lfsr_v % file_list.size(); menu_view.set_highlighted(random_index); chThdSleepMilliseconds(100); start_tx(random_index); } else { thread_sync_complete = true; stop_tx(); } } else if (message.return_code == ReplayThread::READ_ERROR) { file_error(file_list[menu_view.highlighted_index()], "Read error during playback"); if (chaos_mode) { replay_thread.reset(); transmitter_model.disable(); ready_signal = false; lfsr_v = lfsr_iterate(lfsr_v); size_t random_index = lfsr_v % file_list.size(); menu_view.set_highlighted(random_index); chThdSleepMilliseconds(100); start_tx(random_index); } } }}; }; } // namespace ui::external_app::cvs_spam