From ed601608b2e670810e6df3b651c21b3da43b6162 Mon Sep 17 00:00:00 2001 From: wyc <1104749580@qq.com> Date: Mon, 3 Aug 2026 11:22:23 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B1=95=E7=A4=BA=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- module/radio/BackEnd/BackEnd.cpp | 31 ++++++- module/radio/BackEnd/BackEnd.h | 19 +--- module/radio/BackEnd/BackEnd_Mock.cpp | 125 ++++++++++++++++++++------ 3 files changed, 132 insertions(+), 43 deletions(-) diff --git a/module/radio/BackEnd/BackEnd.cpp b/module/radio/BackEnd/BackEnd.cpp index 11940b4..8a2c6e9 100644 --- a/module/radio/BackEnd/BackEnd.cpp +++ b/module/radio/BackEnd/BackEnd.cpp @@ -1,2 +1,31 @@ #include "BackEnd.h" - +#include +Back_End::~Back_End() { + stop_mock_thread(); +} +void Back_End::stop_mock_thread() { + ++mock_generation; + QTimer* timer = mock_timer; + mock_timer = nullptr; + if (timer) { + if (timer->thread() == QThread::currentThread()) { + timer->stop(); + delete timer; + } + else if (mock_thread && mock_thread->isRunning()) { + QMetaObject::invokeMethod(timer, [timer]() { + timer->stop(); + delete timer; + }, Qt::BlockingQueuedConnection); + } + else { + delete timer; + } + } + if (!mock_thread) + return; + mock_thread->quit(); + mock_thread->wait(); + delete mock_thread; + mock_thread = nullptr; +} diff --git a/module/radio/BackEnd/BackEnd.h b/module/radio/BackEnd/BackEnd.h index 1574cd8..cea5573 100644 --- a/module/radio/BackEnd/BackEnd.h +++ b/module/radio/BackEnd/BackEnd.h @@ -25,28 +25,13 @@ public: QString get_screenshot_save_dir_path(); QString get_screenshot_save_file_name(); QString get_audio_file_location(); - void stop_mock_thread() { - ++mock_generation; - if (mock_timer) { - mock_timer->stop(); - mock_timer->disconnect(this); - mock_timer->deleteLater(); - mock_timer = nullptr; - } - if (mock_thread) { - mock_thread->quit(); - mock_thread->wait(); - mock_thread = nullptr; - } - } + void stop_mock_thread(); Back_End(const Back_End&) = delete; Back_End& operator=(const Back_End&) = delete; void call_back_data_func(int channel, void *pData, int i_length); protected: Back_End(); - ~Back_End() override { - stop_mock_thread(); - } + ~Back_End() override; QTimer* mock_timer{}; std::uint64_t mock_generation{}; QThread* mock_thread{}; diff --git a/module/radio/BackEnd/BackEnd_Mock.cpp b/module/radio/BackEnd/BackEnd_Mock.cpp index 9834124..18f5d09 100644 --- a/module/radio/BackEnd/BackEnd_Mock.cpp +++ b/module/radio/BackEnd/BackEnd_Mock.cpp @@ -8,9 +8,12 @@ #include "SweepFrequencyWidget.h" #include #include +#include #include +#include #include #include +#include #include #include #include @@ -99,26 +102,59 @@ void push_radio_data(Radio_Widget* rw, Trace_Mode trace_mode) { } rw->progress_bar2->setValue(make_random_value({1, 5})); } -void push_radio_data_perf(Radio_Widget* rw, Trace_Mode trace_mode) { +struct Mock_Performance_Frame { + std::pmr::vector spectrum; + double spectrum_middle_power{}; + renderive::Time_Of_Day waterfall_time; + std::pmr::vector waterfall; + renderive::Time_Of_Day trace_time; + double trace_value{}; + std::pmr::vector audio; + double progress_value{}; +}; +struct Mock_Performance_Batch { + std::vector frames; +}; +struct Mock_Delivery_State { + std::mutex mutex; + std::shared_ptr latest; + bool delivery_posted{}; +}; +std::shared_ptr make_performance_batch(const Mock_Config& config) { + auto batch = std::make_shared(); + batch->frames.reserve(static_cast(config.batch_count)); + for (int i = 0; i < config.batch_count; ++i) { + auto spectrum = make_random_data({40, 120}, 1024, renderive::Memory_Domain::Spectrum); + double middle_power = spectrum.empty() ? 80.0 : spectrum[spectrum.size() / 2]; + auto waterfall_time = current_render_time(); + auto waterfall = make_random_data({0, 160}, 1024, renderive::Memory_Domain::Waterfall); + auto trace_time = current_render_time(); + double trace_value = make_trace_value({-6000, 6000}, config.trace_mode); + auto audio = make_random_data({-6000, 6000}, 512, renderive::Memory_Domain::Spectrum); + batch->frames.push_back(Mock_Performance_Frame{ + std::move(spectrum), + middle_power, + waterfall_time, + std::move(waterfall), + trace_time, + trace_value, + std::move(audio), + make_random_value({1, 5}) + }); + } + return batch; +} +void apply_performance_batch(Radio_Widget* rw, Mock_Performance_Batch& batch) { if (!rw || !rw->spectrogram_line || !rw->water_fall || !rw->time_power || !rw->audio_spectrogram_plot || !rw->progress_bar1 || !rw->progress_bar2) return; - { - renderive::Range nr = {40, 120}; - auto data = make_random_data(nr, 1024, renderive::Memory_Domain::Spectrum); - double middle_power = data.empty() ? nr.center() : data[data.size() / 2]; - rw->spectrogram_line->update_samples(std::move(data)); - rw->progress_bar1->setValue(middle_power); + for (auto& frame : batch.frames) { + rw->spectrogram_line->update_samples(std::move(frame.spectrum)); + rw->progress_bar1->setValue(frame.spectrum_middle_power); + rw->water_fall->append_row(frame.waterfall_time, std::move(frame.waterfall)); + rw->time_power->append_sample(frame.trace_time, frame.trace_value); + rw->audio_spectrogram_plot->update_samples(std::move(frame.audio)); + rw->progress_bar2->setValue(frame.progress_value); } - { - rw->water_fall->append_row(current_render_time(), make_random_data({0, 160}, 1024, renderive::Memory_Domain::Waterfall)); - } - { - rw->time_power->append_sample(current_render_time(), make_trace_value({-6000, 6000}, trace_mode)); - } - { - rw->audio_spectrogram_plot->update_samples(make_random_data({-6000, 6000}, 512, renderive::Memory_Domain::Spectrum)); - } - rw->progress_bar2->setValue(make_random_value({1, 5})); } } void Back_End::play(const QString& fileName) { @@ -194,16 +230,55 @@ Back_End::Back_End() { QPointer rw = Main_Widget::instance()->radio_widget; if (!rw) return; - mock_timer = new QTimer(this); + if (!config.performance) { + mock_timer = new QTimer(this); + mock_timer->setTimerType(Qt::PreciseTimer); + QObject::connect(mock_timer, &QTimer::timeout, this, [config, rw]() { + for (int i = 0; i < config.batch_count; ++i) { + if (!rw) + return; + push_radio_data(rw.data(), config.trace_mode); + } + }); + mock_timer->start(config.interval_ms); + return; + } + auto delivery_state = std::make_shared(); + mock_thread = new QThread(this); + mock_timer = new QTimer; mock_timer->setTimerType(Qt::PreciseTimer); - QObject::connect(mock_timer, &QTimer::timeout, this, [config, rw]() { - for (int i = 0; i < config.batch_count; ++i) { - if (!rw) - return; - config.performance ? push_radio_data_perf(rw.data(), config.trace_mode) : push_radio_data(rw.data(), config.trace_mode); - } + mock_timer->setInterval(config.interval_ms); + mock_timer->moveToThread(mock_thread); + QTimer* timer = mock_timer; + QObject::connect(mock_thread, &QThread::started, timer, [timer]() { + timer->start(); }); - mock_timer->start(config.interval_ms); + QObject::connect(timer, &QTimer::timeout, timer, [this, config, rw, delivery_state, start_generation]() { + auto batch = make_performance_batch(config); + bool post_delivery = false; + { + std::lock_guard lock(delivery_state->mutex); + delivery_state->latest = std::move(batch); + if (!delivery_state->delivery_posted) { + delivery_state->delivery_posted = true; + post_delivery = true; + } + } + if (!post_delivery) + return; + QMetaObject::invokeMethod(this, [this, rw, delivery_state, start_generation]() { + std::shared_ptr latest; + { + std::lock_guard lock(delivery_state->mutex); + latest = std::move(delivery_state->latest); + delivery_state->delivery_posted = false; + } + if (start_generation != mock_generation || !rw || !latest) + return; + apply_performance_batch(rw.data(), *latest); + }, Qt::QueuedConnection); + }); + mock_thread->start(); }); } #endif