diff --git a/src-core/module.cpp b/src-core/module.cpp index 17008ea67..485675bec 100644 --- a/src-core/module.cpp +++ b/src-core/module.cpp @@ -24,6 +24,10 @@ void ProcessingModule::setOutputType(ModuleDataType type) output_data_type = type; } +void ProcessingModule::init() +{ +} + void ProcessingModule::drawUI() { } diff --git a/src-core/module.h b/src-core/module.h index a84037d22..ff009fac3 100644 --- a/src-core/module.h +++ b/src-core/module.h @@ -8,6 +8,7 @@ #include #include "imgui/imgui_flags.h" #include "dll_export.h" +#include "modules/buffer.h" #define WRITE_IMAGE(image, path) \ image.save_png(std::string(path).c_str()); \ @@ -15,9 +16,9 @@ enum ModuleDataType { - DATA_STREAM, // Generic data, for which a circular buffer will be used + DATA_STREAM, // Generic data, for which a circular buffer will be used DATA_DSP_STREAM, // DSP Data using the specialized buffer and complex floats - DATA_FILE, // Just generic data from a file + DATA_FILE, // Just generic data from a file }; class ProcessingModule @@ -26,7 +27,7 @@ protected: const std::string d_input_file; const std::string d_output_file_hint; std::vector d_output_files; - const std::map d_parameters; + std::map d_parameters; ModuleDataType input_data_type, output_data_type; public: @@ -35,6 +36,7 @@ public: virtual std::vector getOutputTypes() { return {DATA_FILE}; } void setInputType(ModuleDataType type); void setOutputType(ModuleDataType type); + virtual void init(); virtual void process() = 0; virtual void drawUI() = 0; std::vector getOutputs(); @@ -42,6 +44,8 @@ public: public: //std::shared_ptr input_fifo; //std::shared_ptr output_fifo; + std::shared_ptr>> input_stream; + std::shared_ptr>> output_stream; std::atomic input_active; public: diff --git a/src-core/modules/module_qpsk_demod.cpp b/src-core/modules/module_qpsk_demod.cpp index 25d3f4653..4cb2cec56 100644 --- a/src-core/modules/module_qpsk_demod.cpp +++ b/src-core/modules/module_qpsk_demod.cpp @@ -21,18 +21,22 @@ QPSKDemodModule::QPSKDemodModule(std::string input_file, std::string output_file d_loop_bw(std::stof(parameters["costas_bw"])), d_buffer_size(std::stoi(parameters["buffer_size"])), d_dc_block(parameters.count("dc_block") > 0 ? std::stoi(parameters["dc_block"]) : 0) +{ + // Buffers + sym_buffer = new int8_t[d_buffer_size * 2]; +} + +void QPSKDemodModule::init() { // Init DSP blocks - file_source = std::make_shared(d_input_file, dsp::BasebandTypeFromString(parameters["baseband_format"]), d_buffer_size); + if (input_data_type == DATA_FILE) + file_source = std::make_shared(d_input_file, dsp::BasebandTypeFromString(d_parameters["baseband_format"]), d_buffer_size); if (d_dc_block) - dcb = std::make_shared(file_source->output_stream, 1024, true); - agc = std::make_shared(d_dc_block ? dcb->output_stream : file_source->output_stream, d_agc_rate, 1.0f, 1.0f, 65536); + dcb = std::make_shared(input_data_type == DATA_DSP_STREAM ? input_stream : file_source->output_stream, 1024, true); + agc = std::make_shared(d_dc_block ? dcb->output_stream : (input_data_type == DATA_DSP_STREAM ? input_stream : file_source->output_stream), d_agc_rate, 1.0f, 1.0f, 65536); rrc = std::make_shared(agc->output_stream, 1, libdsp::firgen::root_raised_cosine(1, d_samplerate, d_symbolrate, d_rrc_alpha, d_rrc_taps)); pll = std::make_shared(rrc->output_stream, d_loop_bw, 4); rec = std::make_shared(pll->output_stream, (float)d_samplerate / (float)d_symbolrate, pow(8.7e-3, 2) / 4.0, 0.5f, 8.7e-3, 0.005f); - - // Buffers - sym_buffer = new int8_t[d_buffer_size * 2]; } std::vector QPSKDemodModule::getInputTypes() @@ -57,9 +61,6 @@ void QPSKDemodModule::process() else filesize = 0; - //if (input_data_type == DATA_FILE) - // data_in = std::ifstream(d_input_file, std::ios::binary); - data_out = std::ofstream(d_output_file_hint + ".soft", std::ios::binary); d_output_files.push_back(d_output_file_hint + ".soft"); @@ -70,7 +71,8 @@ void QPSKDemodModule::process() time_t lastTime = 0; // Start - file_source->start(); + if (input_data_type == DATA_FILE) + file_source->start(); if (d_dc_block) dcb->start(); agc->start(); @@ -79,7 +81,7 @@ void QPSKDemodModule::process() rec->start(); int dat_size = 0; - while (/*input_data_type == DATA_STREAM ? input_active.load() : */ !file_source->eof()) + while (input_data_type == DATA_FILE ? !file_source->eof() : input_active.load()) { dat_size = rec->output_stream->read(); @@ -96,7 +98,8 @@ void QPSKDemodModule::process() data_out.write((char *)sym_buffer, dat_size * 2); - progress = file_source->getPosition(); + if (input_data_type == DATA_FILE) + progress = file_source->getPosition(); if (time(NULL) % 10 == 0 && lastTime != time(NULL)) { lastTime = time(NULL); @@ -107,7 +110,8 @@ void QPSKDemodModule::process() logger->info("Demodulation finished"); // Stop - file_source->stop(); + if (input_data_type == DATA_FILE) + file_source->stop(); if (d_dc_block) dcb->stop(); agc->stop(); diff --git a/src-core/modules/module_qpsk_demod.h b/src-core/modules/module_qpsk_demod.h index c3b38ad80..0147dfabc 100644 --- a/src-core/modules/module_qpsk_demod.h +++ b/src-core/modules/module_qpsk_demod.h @@ -50,6 +50,7 @@ protected: public: QPSKDemodModule(std::string input_file, std::string output_file_hint, std::map parameters); ~QPSKDemodModule(); + void init(); void process(); void drawUI(); std::vector getInputTypes(); diff --git a/src-core/pipeline.cpp b/src-core/pipeline.cpp index ec2734837..dbd8794cc 100644 --- a/src-core/pipeline.cpp +++ b/src-core/pipeline.cpp @@ -54,6 +54,8 @@ void Pipeline::run(std::string input_file, module->setInputType(DATA_FILE); module->setOutputType(DATA_FILE); + module->init(); + if (ui) { uiCallListMutex->lock(); diff --git a/src-ui/live.cpp b/src-ui/live.cpp new file mode 100644 index 000000000..c93fe4e32 --- /dev/null +++ b/src-ui/live.cpp @@ -0,0 +1,194 @@ +#include "live.h" +#include "imgui/imgui.h" +#include "global.h" +#include "pipeline.h" +#include +#include "logger.h" +#include "portable-file-dialogs.h" +#include "processing.h" +#include + +#ifdef BUILD_LIVE + +int device_id = 0; + +void renderLiveProcessing() +{ + ImGui::BeginGroup(); + { + std::string names; + + std::map id_table; + + for (int i = 0, y = 0; i < pipelines.size(); i++) + { + if (pipelines[i].live) + { + names += pipelines[i].readable_name + '\0'; + id_table.insert({y++, pipelines[i].name}); + } + } + + ImGui::Text("Pipeline : "); + ImGui::SameLine(); + + if (ImGui::Combo("##pipeline", &pipeline_id, names.c_str())) + { + downlink_pipeline = id_table[pipeline_id]; + std::vector::iterator it = std::find_if(pipelines.begin(), + pipelines.end(), + [](const Pipeline &e) { + return e.name == downlink_pipeline; + }); + std::memcpy(samplerate, std::to_string(it->default_samplerate).c_str(), std::to_string(it->default_samplerate).length()); + frequency = it->frequencies[frequency_id]; + } + // ImGui::EndCombo(); + } + ImGui::EndGroup(); + + ImGui::BeginGroup(); + { + ImGui::Text("Output dir : "); + ImGui::SameLine(); + + if (ImGui::Button("Select Output")) + { + logger->debug("Opening file dialog"); + auto result = pfd::select_folder("Open output directory", "."); + while (result.ready(1000)) + { + } + + if (result.result().size() > 0) + output_file = result.result(); + + logger->debug("Dir " + output_file); + } + + ImGui::SameLine(); + ImGui::Text(output_file.c_str()); + } + ImGui::EndGroup(); + + ImGui::Separator(); + + ImGui::BeginGroup(); + { + ImGui::Text("Device : "); + ImGui::SameLine(); + { + std::string names = ""; // = "baseband\0"; + //std::vector::iterator it = std::find_if(pipelines.begin(), + // pipelines.end(), + /// [](const Pipeline &e) { + // return e.name == downlink_pipeline; + // }); + + //if (it != pipelines.end()) + // for (int i = 0; i < it->frequencies.size(); i++) + // { + // names += std::to_string(it->frequencies[i]) + " Mhz" + '\0'; + // } + + if (ImGui::Combo("##device", &device_id, names.c_str())) + { + //frequency = it->frequencies[frequency_id]; + } + } + + ImGui::Text("Frequency : "); + ImGui::SameLine(); + { + std::string names; // = "baseband\0"; + std::vector::iterator it = std::find_if(pipelines.begin(), + pipelines.end(), + [](const Pipeline &e) { + return e.name == downlink_pipeline; + }); + + if (it != pipelines.end()) + for (int i = 0; i < it->frequencies.size(); i++) + { + names += std::to_string(it->frequencies[i]) + " Mhz" + '\0'; + } + + if (ImGui::Combo("##frequency", &frequency_id, names.c_str())) + { + frequency = it->frequencies[frequency_id]; + } + } + + ImGui::Checkbox("DC Block", &dc_block); + + ImGui::Text("Samplerate (Hz / SPS)"); + ImGui::SameLine(); + ImGui::InputText("##samplerate", samplerate, 100); + + if (ImGui::Button("Start")) + { + logger->debug("Starting livedemod..."); + + if (output_file == "") + { + sprintf(error_message, "Please select an output file!"); + } + else if (downlink_pipeline == "") + { + sprintf(error_message, "Please select a pipeline!"); + } + else if (frequency <= 0) + { + sprintf(error_message, "Please select a frequency!"); + } + else if (std::stoi(samplerate) <= 0) + { + sprintf(error_message, "Please select a samplerate!"); + } + else + { + if (!std::filesystem::exists(output_file)) + std::filesystem::create_directory(output_file); + + logger->info(downlink_pipeline); + + std::vector::iterator it = std::find_if(pipelines.begin(), + pipelines.end(), + [](const Pipeline &e) { + return e.name == downlink_pipeline; + }); + + if (it != pipelines.end()) + { + + parameters.emplace("samplerate", std::string(samplerate)); + + parameters.emplace("baseband_format", "f32"); + + parameters.emplace("dc_block", dc_block ? "1" : "0"); + + std::map final_parameters = it->steps[1].modules[0].parameters; + for (const std::pair ¶m : parameters) + if (final_parameters.count(param.first) > 0) + final_parameters[param.first] = param.second; + else + final_parameters.emplace(param.first, param.second); + + logger->debug("Parameters :"); + for (const std::pair ¶m : final_parameters) + logger->debug(" - " + param.first + " : " + param.second); + } + else + { + logger->critical("Pipeline " + downlink_pipeline + " does not exist!"); + } + } + } + + ImGui::SameLine(); + + ImGui::TextColored(ImColor::HSV(0 / 360.0, 1, 1, 1.0), error_message); + } + ImGui::EndGroup(); +} +#endif \ No newline at end of file diff --git a/src-ui/live.h b/src-ui/live.h new file mode 100644 index 000000000..c9b855887 --- /dev/null +++ b/src-ui/live.h @@ -0,0 +1,6 @@ +#pragma once +//#define BUILD_LIVE + +#ifdef BUILD_LIVE +void renderLiveProcessing(); +#endif \ No newline at end of file diff --git a/src-ui/main.cpp b/src-ui/main.cpp index 0e54b3c57..2508de673 100644 --- a/src-ui/main.cpp +++ b/src-ui/main.cpp @@ -10,6 +10,7 @@ #include "init.h" #include "processing.h" #include "offline.h" +#include "live.h" static void glfw_error_callback(int error, const char *description) { @@ -163,7 +164,11 @@ int main(int argc, char *argv[]) } if (ImGui::BeginTabItem("Live processing")) { +#ifdef BUILD_LIVE + renderLiveProcessing(); +#else ImGui::Text("Live support is currently being rewritten, and does not work on Windows yet. If you really need it, please stick to an older version."); +#endif ImGui::EndTabItem(); } if (ImGui::BeginTabItem("Credits")) diff --git a/src-ui/offline.cpp b/src-ui/offline.cpp index 14d46e293..4bb341fd3 100644 --- a/src-ui/offline.cpp +++ b/src-ui/offline.cpp @@ -1,3 +1,4 @@ +#include "offline.h" #include "imgui/imgui.h" #include "global.h" #include "pipeline.h"