2025-03-22 16:24:29 +01:00
|
|
|
#include "newrec.h"
|
|
|
|
|
#include "common/widgets/stepped_slider.h"
|
2025-06-07 15:50:30 +02:00
|
|
|
#include "core/config.h"
|
2025-05-10 13:33:28 +02:00
|
|
|
#include "core/style.h"
|
2025-04-14 19:03:42 +01:00
|
|
|
#include "dsp/block.h"
|
2025-04-22 19:56:59 +02:00
|
|
|
#include "dsp/device/dev.h"
|
2025-07-23 17:11:59 +02:00
|
|
|
#include "dsp/displays/const_disp.h"
|
2025-06-07 15:50:30 +02:00
|
|
|
#include "dsp/io/iq_sink.h"
|
2025-05-10 13:33:28 +02:00
|
|
|
#include "imgui/imgui.h"
|
2025-03-22 16:24:29 +01:00
|
|
|
#include "logger.h"
|
2025-06-07 15:50:30 +02:00
|
|
|
#include "utils/time.h"
|
2025-06-06 08:12:02 +02:00
|
|
|
#include <memory>
|
2025-03-22 16:24:29 +01:00
|
|
|
|
|
|
|
|
namespace satdump
|
|
|
|
|
{
|
2025-05-19 22:26:32 +02:00
|
|
|
namespace handlers
|
2025-03-22 16:24:29 +01:00
|
|
|
{
|
|
|
|
|
NewRecHandler::NewRecHandler()
|
|
|
|
|
{
|
2025-05-10 13:33:28 +02:00
|
|
|
auto devs = foundDevices = ndsp::getDeviceList(ndsp::DeviceBlock::MODE_SINGLE_RX);
|
|
|
|
|
|
|
|
|
|
// for (auto &d : devs)
|
|
|
|
|
// {
|
|
|
|
|
// if (d.type == "rtlsdr")
|
|
|
|
|
// {
|
|
|
|
|
// dev = ndsp::getDeviceInstanceFromInfo(d, ndsp::DeviceBlock::MODE_SINGLE_RX);
|
|
|
|
|
// options_displayer_test.add_options(dev->get_cfg_list());
|
|
|
|
|
// options_displayer_test.set_values(dev->get_cfg());
|
|
|
|
|
// break;
|
|
|
|
|
// }
|
|
|
|
|
// }
|
2025-03-22 16:24:29 +01:00
|
|
|
|
2025-06-06 08:12:02 +02:00
|
|
|
splitter = std::make_shared<ndsp::SplitterBlock<complex_t>>();
|
|
|
|
|
|
2025-03-22 16:24:29 +01:00
|
|
|
fftp = std::make_shared<ndsp::FFTPanBlock>();
|
2025-06-06 08:12:02 +02:00
|
|
|
fftp->set_input(splitter->add_output("main_fft"), 0);
|
2025-03-22 16:24:29 +01:00
|
|
|
fftp->avg_num = 1;
|
|
|
|
|
|
|
|
|
|
fft_plot = std::make_shared<widgets::FFTPlot>(fftp->output_fft_buff, 65536, -150, 150, 10);
|
|
|
|
|
fft_plot->frequency = 431.8e6;
|
|
|
|
|
fft_plot->enable_freq_scale = true;
|
|
|
|
|
|
|
|
|
|
waterfall_plot = std::make_shared<widgets::WaterfallPlot>(65536, 500);
|
|
|
|
|
waterfall_plot->set_size(65536);
|
|
|
|
|
waterfall_plot->set_rate(30, 20);
|
|
|
|
|
|
2025-04-14 19:03:42 +01:00
|
|
|
fftp->on_fft = [this](float *p) { waterfall_plot->push_fft(p); };
|
2025-06-06 08:12:02 +02:00
|
|
|
|
|
|
|
|
// TMP
|
|
|
|
|
const_disp = std::make_shared<ndsp::ConstellationDisplayBlock>();
|
2025-06-07 15:50:30 +02:00
|
|
|
iq_sink = std::make_shared<ndsp::IQSinkBlock>();
|
2025-03-22 16:24:29 +01:00
|
|
|
}
|
|
|
|
|
|
2025-04-14 19:03:42 +01:00
|
|
|
NewRecHandler::~NewRecHandler() {}
|
2025-03-22 16:24:29 +01:00
|
|
|
|
|
|
|
|
void NewRecHandler::drawMenu()
|
|
|
|
|
{
|
|
|
|
|
if (ImGui::CollapsingHeader("Device", ImGuiTreeNodeFlags_DefaultOpen))
|
|
|
|
|
{
|
2025-05-10 13:33:28 +02:00
|
|
|
if (deviceRunning)
|
|
|
|
|
style::beginDisabled();
|
|
|
|
|
if (ImGui::BeginCombo("Device##devicebox", curDeviceI.name.c_str()))
|
|
|
|
|
{
|
|
|
|
|
for (auto &d : foundDevices)
|
|
|
|
|
{
|
|
|
|
|
if (ImGui::Selectable(d.name.c_str(), d == curDeviceI))
|
|
|
|
|
{
|
|
|
|
|
curDeviceI = d;
|
|
|
|
|
|
|
|
|
|
dev = ndsp::getDeviceInstanceFromInfo(curDeviceI, ndsp::DeviceBlock::MODE_SINGLE_RX);
|
|
|
|
|
options_displayer_test.clear();
|
|
|
|
|
options_displayer_test.add_options(dev->get_cfg_list());
|
|
|
|
|
options_displayer_test.set_values(dev->get_cfg());
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ImGui::EndCombo();
|
|
|
|
|
}
|
|
|
|
|
if (deviceRunning)
|
|
|
|
|
style::endDisabled();
|
|
|
|
|
|
2025-04-12 09:56:37 +02:00
|
|
|
nlohmann::json changed = options_displayer_test.draw();
|
2025-03-22 16:24:29 +01:00
|
|
|
|
2025-04-12 09:56:37 +02:00
|
|
|
if (changed.size() > 0)
|
2025-03-22 16:24:29 +01:00
|
|
|
{
|
2025-04-12 09:56:37 +02:00
|
|
|
logger->trace("\n%s\n", changed.dump(4).c_str());
|
2025-04-14 19:03:42 +01:00
|
|
|
auto r = dev->set_cfg(changed);
|
|
|
|
|
if (r >= ndsp::Block::RES_LISTUPD)
|
|
|
|
|
{
|
|
|
|
|
options_displayer_test.clear();
|
2025-04-15 19:06:12 +01:00
|
|
|
logger->trace("\n%s\n", dev->get_cfg_list().dump(4).c_str());
|
2025-04-14 19:03:42 +01:00
|
|
|
options_displayer_test.add_options(dev->get_cfg_list());
|
2025-04-15 19:06:12 +01:00
|
|
|
options_displayer_test.set_values(dev->get_cfg());
|
2025-04-14 19:03:42 +01:00
|
|
|
}
|
|
|
|
|
|
2025-04-12 09:07:02 +02:00
|
|
|
// dev->init();
|
2025-03-22 16:24:29 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ImGui::Separator();
|
|
|
|
|
|
2025-05-10 13:33:28 +02:00
|
|
|
if (!deviceRunning)
|
2025-03-22 16:24:29 +01:00
|
|
|
{
|
2025-05-10 13:33:28 +02:00
|
|
|
if (ImGui::Button("Start"))
|
|
|
|
|
{
|
2025-06-07 15:50:30 +02:00
|
|
|
taskq.push(
|
|
|
|
|
[this]()
|
|
|
|
|
{
|
|
|
|
|
fftp->set_fft_settings(65536, dev->getStreamSamplerate(0, false), 30);
|
|
|
|
|
fftp->avg_num = 1;
|
2025-03-22 16:24:29 +01:00
|
|
|
|
2025-06-07 15:50:30 +02:00
|
|
|
splitter->link(dev.get(), 0, 0, 100); // fftp->inputs[0] = dev->outputs[0];
|
2025-03-22 16:24:29 +01:00
|
|
|
|
2025-06-07 15:50:30 +02:00
|
|
|
dev->start();
|
|
|
|
|
splitter->start();
|
|
|
|
|
fftp->start();
|
2025-04-15 19:06:12 +01:00
|
|
|
|
2025-06-07 15:50:30 +02:00
|
|
|
options_displayer_test.clear();
|
|
|
|
|
options_displayer_test.add_options(dev->get_cfg_list());
|
|
|
|
|
options_displayer_test.set_values(dev->get_cfg());
|
|
|
|
|
});
|
2025-03-22 16:24:29 +01:00
|
|
|
|
2025-05-10 13:33:28 +02:00
|
|
|
deviceRunning = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
2025-03-22 16:24:29 +01:00
|
|
|
{
|
2025-04-15 19:06:12 +01:00
|
|
|
|
2025-05-10 13:33:28 +02:00
|
|
|
if (ImGui::Button("Stop"))
|
|
|
|
|
{
|
2025-06-07 15:50:30 +02:00
|
|
|
taskq.push(
|
|
|
|
|
[this]()
|
|
|
|
|
{
|
|
|
|
|
dev->stop(true);
|
|
|
|
|
splitter->stop();
|
|
|
|
|
fftp->stop();
|
2025-05-10 13:33:28 +02:00
|
|
|
|
2025-06-07 15:50:30 +02:00
|
|
|
options_displayer_test.clear();
|
|
|
|
|
options_displayer_test.add_options(dev->get_cfg_list());
|
|
|
|
|
options_displayer_test.set_values(dev->get_cfg());
|
|
|
|
|
});
|
2025-05-10 13:33:28 +02:00
|
|
|
|
|
|
|
|
deviceRunning = false;
|
|
|
|
|
}
|
2025-03-22 16:24:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ImGui::Separator();
|
|
|
|
|
|
|
|
|
|
widgets::SteppedSliderFloat("FFT Max", &fft_plot->scale_max, -160, 150);
|
|
|
|
|
widgets::SteppedSliderFloat("FFT Min", &fft_plot->scale_min, -160, 150);
|
|
|
|
|
|
|
|
|
|
if (fft_plot->scale_max < fft_plot->scale_min)
|
|
|
|
|
{
|
|
|
|
|
fft_plot->scale_min = waterfall_plot->scale_min;
|
|
|
|
|
fft_plot->scale_max = waterfall_plot->scale_max;
|
|
|
|
|
}
|
|
|
|
|
else if (fft_plot->scale_min > fft_plot->scale_max)
|
|
|
|
|
{
|
|
|
|
|
fft_plot->scale_min = waterfall_plot->scale_min;
|
|
|
|
|
fft_plot->scale_max = waterfall_plot->scale_max;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
waterfall_plot->scale_min = fft_plot->scale_min;
|
|
|
|
|
waterfall_plot->scale_max = fft_plot->scale_max;
|
|
|
|
|
}
|
2025-06-06 08:12:02 +02:00
|
|
|
|
|
|
|
|
ImGui::Separator();
|
|
|
|
|
const_disp->constel.draw();
|
|
|
|
|
|
2025-06-07 15:50:30 +02:00
|
|
|
if (!const_present)
|
2025-06-06 08:12:02 +02:00
|
|
|
{
|
2025-06-07 15:50:30 +02:00
|
|
|
if (ImGui::Button("Add Const"))
|
|
|
|
|
{
|
|
|
|
|
taskq.push(
|
|
|
|
|
[this]()
|
|
|
|
|
{
|
|
|
|
|
const_disp->set_input(splitter->add_output("tmp_const", false), 0);
|
|
|
|
|
const_disp->start();
|
|
|
|
|
});
|
|
|
|
|
const_present = true;
|
|
|
|
|
}
|
2025-06-06 08:12:02 +02:00
|
|
|
}
|
2025-06-07 15:50:30 +02:00
|
|
|
else
|
2025-06-06 08:12:02 +02:00
|
|
|
{
|
2025-06-07 15:50:30 +02:00
|
|
|
if (ImGui::Button("Del Const"))
|
|
|
|
|
{
|
|
|
|
|
taskq.push(
|
|
|
|
|
[this]()
|
|
|
|
|
{
|
|
|
|
|
splitter->del_output("tmp_const", true);
|
|
|
|
|
const_disp->stop();
|
|
|
|
|
});
|
|
|
|
|
const_present = false;
|
|
|
|
|
}
|
2025-06-06 08:12:02 +02:00
|
|
|
}
|
|
|
|
|
|
2025-06-07 15:50:30 +02:00
|
|
|
float ratio = 0;
|
2025-06-06 08:12:02 +02:00
|
|
|
if (deviceRunning)
|
2025-06-07 15:50:30 +02:00
|
|
|
ratio = (float)dev->get_outputs()[0].fifo->size_approx() / (float)dev->get_outputs()[0].fifo->max_capacity();
|
|
|
|
|
ImGui::ProgressBar(ratio);
|
|
|
|
|
|
2025-06-17 00:12:53 +02:00
|
|
|
if (recording)
|
|
|
|
|
style::beginDisabled();
|
|
|
|
|
rec_type.draw_combo();
|
|
|
|
|
if (recording)
|
2025-07-23 17:11:59 +02:00
|
|
|
style::endDisabled();
|
2025-06-17 00:12:53 +02:00
|
|
|
|
2025-06-07 15:50:30 +02:00
|
|
|
if (!recording)
|
2025-06-06 08:12:02 +02:00
|
|
|
{
|
2025-06-07 15:50:30 +02:00
|
|
|
if (ImGui::Button("Rec Start"))
|
|
|
|
|
{
|
|
|
|
|
taskq.push(
|
|
|
|
|
[this]()
|
|
|
|
|
{
|
2025-06-08 16:57:37 +02:00
|
|
|
std::string recording_path = satdump_cfg.main_cfg["satdump_directories"]["recording_path"]["value"].get<std::string>();
|
2025-06-07 15:50:30 +02:00
|
|
|
iq_sink->set_cfg("filepath", recording_path);
|
|
|
|
|
iq_sink->set_cfg("autogen", true);
|
|
|
|
|
iq_sink->set_cfg("samplerate", dev->getStreamSamplerate(0, false));
|
|
|
|
|
iq_sink->set_cfg("frequency", dev->getStreamFrequency(0, false));
|
|
|
|
|
iq_sink->set_cfg("timestamp", getTime());
|
2025-06-17 00:12:53 +02:00
|
|
|
iq_sink->set_cfg("format", rec_type);
|
2025-06-07 15:50:30 +02:00
|
|
|
iq_sink->set_input(splitter->add_output("tmp_record", false), 0);
|
|
|
|
|
iq_sink->start();
|
|
|
|
|
});
|
|
|
|
|
recording = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ImGui::Text("Size : %lu", iq_sink->total_written_raw);
|
|
|
|
|
|
|
|
|
|
if (ImGui::Button("Rec Stop"))
|
|
|
|
|
{
|
|
|
|
|
taskq.push(
|
|
|
|
|
[this]()
|
|
|
|
|
{
|
|
|
|
|
splitter->del_output("tmp_record", true);
|
|
|
|
|
iq_sink->stop();
|
|
|
|
|
});
|
|
|
|
|
recording = false;
|
|
|
|
|
}
|
2025-06-06 08:12:02 +02:00
|
|
|
}
|
2025-03-22 16:24:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void NewRecHandler::drawContents(ImVec2 win_size)
|
|
|
|
|
{
|
|
|
|
|
float right_width = win_size.x;
|
|
|
|
|
float wf_size = win_size.y;
|
|
|
|
|
bool show_waterfall = true;
|
|
|
|
|
float waterfall_ratio = 0.3;
|
|
|
|
|
float left_width = ImGui::GetCursorPosX() - 9;
|
|
|
|
|
|
2025-04-15 19:06:12 +01:00
|
|
|
ImGui::BeginChild("RecorderFFT", {right_width, wf_size}, false, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse);
|
2025-03-22 16:24:29 +01:00
|
|
|
{
|
|
|
|
|
float fft_height = wf_size * (show_waterfall ? waterfall_ratio : 1.0);
|
|
|
|
|
float wf_height = wf_size * (1 - waterfall_ratio) + 15 * ui_scale;
|
|
|
|
|
float wfft_widht = right_width - 9 * ui_scale;
|
|
|
|
|
bool t = true;
|
|
|
|
|
#ifdef __ANDROID__
|
|
|
|
|
int offset = 8;
|
|
|
|
|
#else
|
|
|
|
|
int offset = 30;
|
|
|
|
|
#endif
|
2025-04-15 19:06:12 +01:00
|
|
|
ImGui::SetNextWindowSizeConstraints(ImVec2((right_width + offset * ui_scale), 50), ImVec2((right_width + offset * ui_scale), wf_size));
|
|
|
|
|
ImGui::SetNextWindowSize(ImVec2((right_width + offset * ui_scale), show_waterfall ? waterfall_ratio * wf_size : wf_size));
|
2025-03-22 16:24:29 +01:00
|
|
|
ImGui::SetNextWindowPos(ImVec2(left_width, 25 * ui_scale));
|
2025-04-14 19:03:42 +01:00
|
|
|
if (ImGui::Begin("#fft", &t,
|
2025-04-15 19:06:12 +01:00
|
|
|
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_NoScrollbar |
|
2025-04-14 19:03:42 +01:00
|
|
|
ImGuiWindowFlags_NoScrollWithMouse))
|
2025-03-22 16:24:29 +01:00
|
|
|
{
|
|
|
|
|
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 9 * ui_scale);
|
|
|
|
|
fft_plot->draw({float(wfft_widht), fft_height});
|
|
|
|
|
if (show_waterfall && ImGui::IsMouseDragging(ImGuiMouseButton_Left))
|
|
|
|
|
waterfall_ratio = ImGui::GetWindowHeight() / wf_size;
|
|
|
|
|
}
|
|
|
|
|
ImGui::EndChild();
|
|
|
|
|
if (show_waterfall)
|
|
|
|
|
{
|
|
|
|
|
ImGui::SetCursorPosY(ImGui::GetCursorPosY() - 15 * ui_scale);
|
|
|
|
|
waterfall_plot->draw({wfft_widht, wf_height}, true);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ImGui::EndChild();
|
|
|
|
|
}
|
2025-05-19 22:26:32 +02:00
|
|
|
} // namespace handlers
|
2025-04-14 19:03:42 +01:00
|
|
|
} // namespace satdump
|