diff --git a/plugins/sdr_sources/rtlsdr_sdr_support/rtlsdr_dev.cpp b/plugins/sdr_sources/rtlsdr_sdr_support/rtlsdr_dev.cpp index 716dee133..ebd5910d1 100644 --- a/plugins/sdr_sources/rtlsdr_sdr_support/rtlsdr_dev.cpp +++ b/plugins/sdr_sources/rtlsdr_sdr_support/rtlsdr_dev.cpp @@ -213,7 +213,6 @@ namespace satdump for (int i = 0; i < c; i++) { - const char *name = rtlsdr_get_device_name(i); char manufact[256], product[256], serial[256]; std::string _name; diff --git a/src-cli2/main.cpp b/src-cli2/main.cpp index decf9a548..504685a95 100644 --- a/src-cli2/main.cpp +++ b/src-cli2/main.cpp @@ -1,19 +1,14 @@ #include "CLI11.hpp" -#include "common/detect_header.h" -#include "core/config.h" #include "init.h" #include "logger.h" -#include "nlohmann/json.hpp" -#include "pipeline/module.h" -#include "pipeline/pipeline.h" +#include "module.h" +#include "pipeline.h" #include "probe.h" #include "process.h" -#include "satdump_vars.h" - -#include -#include - #include "run_as.h" +#include "satdump_vars.h" +#include "subcommand.h" +#include int main(int argc, char *argv[]) { @@ -26,7 +21,7 @@ int main(int argc, char *argv[]) if (std::string(argv[i]) == "-v" || std::string(argv[i]) == "--verbose") verbose = true; - // Init SatDump, silent (TODOREWORK, a verbose flag?) + // Init SatDump, silent or verbose as requested if (!verbose) logger->set_level(slog::LOG_WARN); satdump::initSatdump(); @@ -34,89 +29,23 @@ int main(int argc, char *argv[]) if (!verbose) logger->set_level(slog::LOG_TRACE); - // TODOREWORK + // Command basics CLI::App app("SatDump v" + satdump::SATDUMP_VERSION); app.set_help_all_flag("--help-all", "Expand all help"); app.add_flag("-v,--verbose", verbose, "Make the logger more verbose"); app.require_subcommand(); - CLI::App *sub_run = app.add_subcommand("run", "Run a script"); - sub_run->add_option("script", "The script to run")->required(); - // auto sub_run_group = sub_run->add_option_group("--lua,--as"); - // sub_run_group->add_flag("--lua", "Run a Lua script"); - // sub_run_group->add_flag("--as", "Run an AngelScript script"); - // sub_run_group->require_option(1); TODOREWORK - sub_run->add_flag("--lint", "Lint the script, without executing it"); - sub_run->add_flag("--predef", "Dump as.predefined"); - sub_run->require_option(1, 3); + // All possible subcommands + std::vector> cmd_handlers; - std::map>> modules_opts; - CLI::App *sub_module = app.add_subcommand("module", "Run a single module"); - for (auto &p : satdump::pipeline::modules_registry) - { - CLI::App *sub_p = sub_module->add_subcommand(p.id); - sub_p->add_option("input_file"); - sub_p->add_option("output_hint"); - modules_opts.emplace(p.id, std::map>()); - for (auto &ep : p.params.items()) - { - auto opt = std::make_shared(); - auto f = sub_p->add_flag("--" + ep.key(), *opt, ""); - if (ep.value().is_string()) - f->default_val(ep.value().get()); - else - f->default_val(ep.value().dump()); - modules_opts[p.id].emplace(ep.key(), opt); - } - } + cmd_handlers.push_back(std::make_shared()); + cmd_handlers.push_back(std::make_shared()); + cmd_handlers.push_back(std::make_shared()); + cmd_handlers.push_back(std::make_shared()); + cmd_handlers.push_back(std::make_shared()); - CLI::App *sub_probe = app.add_subcommand("probe", "Probe for SDR Devices"); - auto sub_probe_group = sub_probe->add_option_group("--tx,--rx"); - sub_probe_group->add_flag("--tx", "Only list devices with at least 1 TX Channel"); - sub_probe_group->add_flag("--rx", "Only list devices with at least 1 RX Channel"); - sub_probe_group->require_option(0, 1); - sub_probe->add_flag("--params", "Dump full device parameters"); - - std::map>> pipeline_opts; - CLI::App *sub_pipeline = app.add_subcommand("pipeline", "Run a pipeline"); - for (auto &p : satdump::pipeline::pipelines) - { - CLI::App *sub_p = sub_pipeline->add_subcommand(p.id); - - sub_p->add_option("level", "Level of the input file. Can be cadu, file, baseband...")->required(); - sub_p->add_option("input_file", "Actual input file (eg. metop_ahrpt.cadu, a baseband, etc)")->required(); - sub_p->add_option("output_folder", "Output folder for processed data")->required(); - - nlohmann::json common = satdump::satdump_cfg.main_cfg["user_interface"]["default_offline_parameters"]; - - for (auto &ep : p.editable_parameters.items()) - for (auto &e : ep.value().items()) - common[ep.key()][e.key()] = p.editable_parameters[ep.key()][e.key()]; - - pipeline_opts.emplace(p.id, std::map>()); - - for (auto &ep : common.items()) - { - auto opt = std::make_shared(); - CLI::Option *f; - if (ep.value().contains("description")) - f = sub_p->add_flag("--" + ep.key(), *opt, (const std::string)ep.value()["description"].get()); - else - f = sub_p->add_flag("--" + ep.key(), *opt, ""); - if (ep.value().contains("value")) - { - if (ep.value()["value"].is_string()) - f->default_val(ep.value()["value"].get()); - else - f->default_val(ep.value()["value"].dump()); - } - pipeline_opts[p.id].emplace(ep.key(), opt); - } - } - - CLI::App *sub_process = app.add_subcommand("process", "Process products/dataset automatically"); - sub_process->add_option("product", "Product to process")->required(); - sub_process->add_option("directory", "Output folder")->required(); + for (auto &c : cmd_handlers) + c->reg(&app); CLI11_PARSE(app, argc, argv); @@ -124,107 +53,8 @@ int main(int argc, char *argv[]) { // std::cout << "Subcommand: " << subcom->get_name() << '\n'; - if (subcom->get_name() == "pipeline") - { - for (auto *s2 : subcom->get_subcommands()) - { - std::string level = s2->get_option("level")->as(); - std::string input = s2->get_option("input_file")->as(); - std::string output = s2->get_option("output_folder")->as(); - - auto pipeline = satdump::pipeline::getPipelineFromID(s2->get_name()); - - nlohmann::json params; - - try_get_params_from_input_file(params, input); - - for (auto *s33 : s2->get_options()) - { - if (s2->count(s33->get_name())) - { - // logger->critical(s33->get_name().substr(2)); - auto optname = s33->get_name().substr(2); - if (pipeline_opts[pipeline.id].count(optname)) - { - try - { - params[optname] = nlohmann::json::parse(s33->as()); - } - catch (std::exception &e) - { - params[optname] = s33->as(); - } - } - } - } - - // logger->critical(params.dump()); - - // Create output dir - if (!std::filesystem::exists(output)) - std::filesystem::create_directories(output); - - pipeline.run(input, output, params, level); - } - } - else if (subcom->get_name() == "run") - { - std::string script = subcom->get_option("script")->as(); - satdump::runAngelScript(script, subcom->count("--lint"), subcom->count("--predef")); - } - else if (subcom->get_name() == "probe") - { - bool tx = subcom->count("--tx"); - bool rx = subcom->count("--rx"); - bool pa = subcom->count("--params"); - satdump::probeDevices(tx, rx, pa); - } - else if (subcom->get_name() == "process") - { - std::string pro = subcom->get_option("product")->as(); - std::string dir = subcom->get_option("directory")->as(); - satdump::processProductsOrDataset(pro, dir); - } - else if (subcom->get_name() == "module") - { - for (auto *s2 : subcom->get_subcommands()) - { - std::string mod_id = s2->get_name(); - std::string in = s2->get_option("input_file")->as(); - std::string out = s2->get_option("output_hint")->as(); - - nlohmann::json params; - - for (auto *s33 : s2->get_options()) - { - if (s2->count(s33->get_name())) - { - // logger->critical(s33->get_name().substr(2)); - auto optname = s33->get_name().substr(2); - if (modules_opts[mod_id].count(optname)) - { - try - { - params[optname] = nlohmann::json::parse(s33->as()); - } - catch (std::exception &e) - { - params[optname] = s33->as(); - } - } - } - } - - auto inst = satdump::pipeline::getModuleInstance(mod_id, in, out, params); - - inst->setInputType(satdump::pipeline::DATA_FILE); - inst->setOutputType(satdump::pipeline::DATA_FILE); - - inst->init(); - - // TODOREWORK show stats - inst->process(); - } - } + for (auto &c : cmd_handlers) + if (subcom->get_name() == c->cmd) + c->reg(&app); } } diff --git a/src-cli2/module.cpp b/src-cli2/module.cpp new file mode 100644 index 000000000..c7a3753d6 --- /dev/null +++ b/src-cli2/module.cpp @@ -0,0 +1,69 @@ +#include "module.h" +#include "pipeline/module.h" + +namespace satdump +{ + void ModuleCmdHandler::reg(CLI::App *app) + { + CLI::App *sub_module = app->add_subcommand("module", "Run a single module"); + for (auto &p : satdump::pipeline::modules_registry) + { + CLI::App *sub_p = sub_module->add_subcommand(p.id); + sub_p->add_option("input_file"); + sub_p->add_option("output_hint"); + modules_opts.emplace(p.id, std::map>()); + for (auto &ep : p.params.items()) + { + auto opt = std::make_shared(); + auto f = sub_p->add_flag("--" + ep.key(), *opt, ""); + if (ep.value().is_string()) + f->default_val(ep.value().get()); + else + f->default_val(ep.value().dump()); + modules_opts[p.id].emplace(ep.key(), opt); + } + } + } + + void ModuleCmdHandler::run(CLI::App *app, CLI::App *subcom) + { + for (auto *s2 : subcom->get_subcommands()) + { + std::string mod_id = s2->get_name(); + std::string in = s2->get_option("input_file")->as(); + std::string out = s2->get_option("output_hint")->as(); + + nlohmann::json params; + + for (auto *s33 : s2->get_options()) + { + if (s2->count(s33->get_name())) + { + // logger->critical(s33->get_name().substr(2)); + auto optname = s33->get_name().substr(2); + if (modules_opts[mod_id].count(optname)) + { + try + { + params[optname] = nlohmann::json::parse(s33->as()); + } + catch (std::exception &e) + { + params[optname] = s33->as(); + } + } + } + } + + auto inst = satdump::pipeline::getModuleInstance(mod_id, in, out, params); + + inst->setInputType(satdump::pipeline::DATA_FILE); + inst->setOutputType(satdump::pipeline::DATA_FILE); + + inst->init(); + + // TODOREWORK show stats + inst->process(); + } + } +} // namespace satdump \ No newline at end of file diff --git a/src-cli2/module.h b/src-cli2/module.h new file mode 100644 index 000000000..a54f50e60 --- /dev/null +++ b/src-cli2/module.h @@ -0,0 +1,18 @@ +#pragma once + +#include "subcommand.h" + +namespace satdump +{ + class ModuleCmdHandler : public CmdHandler + { + private: + std::map>> modules_opts; + + public: + ModuleCmdHandler() : CmdHandler("module") {} + + void reg(CLI::App *app); + void run(CLI::App *app, CLI::App *subcom); + }; +} // namespace satdump \ No newline at end of file diff --git a/src-cli2/pipeline.cpp b/src-cli2/pipeline.cpp new file mode 100644 index 000000000..c47e0be04 --- /dev/null +++ b/src-cli2/pipeline.cpp @@ -0,0 +1,90 @@ +#include "pipeline.h" +#include "common/detect_header.h" +#include "core/config.h" +#include "pipeline/pipeline.h" + +namespace satdump +{ + void PipelineCmdHandler::reg(CLI::App *app) + { + CLI::App *sub_pipeline = app->add_subcommand("pipeline", "Run a pipeline"); + for (auto &p : satdump::pipeline::pipelines) + { + CLI::App *sub_p = sub_pipeline->add_subcommand(p.id); + + sub_p->add_option("level", "Level of the input file. Can be cadu, file, baseband...")->required(); + sub_p->add_option("input_file", "Actual input file (eg. metop_ahrpt.cadu, a baseband, etc)")->required(); + sub_p->add_option("output_folder", "Output folder for processed data")->required(); + + nlohmann::json common = satdump::satdump_cfg.main_cfg["user_interface"]["default_offline_parameters"]; + + for (auto &ep : p.editable_parameters.items()) + for (auto &e : ep.value().items()) + common[ep.key()][e.key()] = p.editable_parameters[ep.key()][e.key()]; + + pipeline_opts.emplace(p.id, std::map>()); + + for (auto &ep : common.items()) + { + auto opt = std::make_shared(); + CLI::Option *f; + if (ep.value().contains("description")) + f = sub_p->add_flag("--" + ep.key(), *opt, (const std::string)ep.value()["description"].get()); + else + f = sub_p->add_flag("--" + ep.key(), *opt, ""); + if (ep.value().contains("value")) + { + if (ep.value()["value"].is_string()) + f->default_val(ep.value()["value"].get()); + else + f->default_val(ep.value()["value"].dump()); + } + pipeline_opts[p.id].emplace(ep.key(), opt); + } + } + } + + void PipelineCmdHandler::run(CLI::App *app, CLI::App *subcom) + { + for (auto *s2 : subcom->get_subcommands()) + { + std::string level = s2->get_option("level")->as(); + std::string input = s2->get_option("input_file")->as(); + std::string output = s2->get_option("output_folder")->as(); + + auto pipeline = satdump::pipeline::getPipelineFromID(s2->get_name()); + + nlohmann::json params; + + try_get_params_from_input_file(params, input); + + for (auto *s33 : s2->get_options()) + { + if (s2->count(s33->get_name())) + { + // logger->critical(s33->get_name().substr(2)); + auto optname = s33->get_name().substr(2); + if (pipeline_opts[pipeline.id].count(optname)) + { + try + { + params[optname] = nlohmann::json::parse(s33->as()); + } + catch (std::exception &e) + { + params[optname] = s33->as(); + } + } + } + } + + // logger->critical(params.dump()); + + // Create output dir + if (!std::filesystem::exists(output)) + std::filesystem::create_directories(output); + + pipeline.run(input, output, params, level); + } + } +} // namespace satdump \ No newline at end of file diff --git a/src-cli2/pipeline.h b/src-cli2/pipeline.h new file mode 100644 index 000000000..fd01c55e2 --- /dev/null +++ b/src-cli2/pipeline.h @@ -0,0 +1,18 @@ +#pragma once + +#include "subcommand.h" + +namespace satdump +{ + class PipelineCmdHandler : public CmdHandler + { + private: + std::map>> pipeline_opts; + + public: + PipelineCmdHandler() : CmdHandler("pipeline") {} + + void reg(CLI::App *app); + void run(CLI::App *app, CLI::App *subcom); + }; +} // namespace satdump \ No newline at end of file diff --git a/src-cli2/probe.cpp b/src-cli2/probe.cpp index e77247f29..5d28725eb 100644 --- a/src-cli2/probe.cpp +++ b/src-cli2/probe.cpp @@ -4,7 +4,25 @@ namespace satdump { - void probeDevices(bool tx, bool rx, bool params) + void ProbeCmdHandler::reg(CLI::App *app) + { + CLI::App *sub_probe = app->add_subcommand("probe", "Probe for SDR Devices"); + auto sub_probe_group = sub_probe->add_option_group("--tx,--rx"); + sub_probe_group->add_flag("--tx", "Only list devices with at least 1 TX Channel"); + sub_probe_group->add_flag("--rx", "Only list devices with at least 1 RX Channel"); + sub_probe_group->require_option(0, 1); + sub_probe->add_flag("--params", "Dump full device parameters"); + } + + void ProbeCmdHandler::run(CLI::App *app, CLI::App *subcom) + { + bool tx = subcom->count("--tx"); + bool rx = subcom->count("--rx"); + bool pa = subcom->count("--params"); + probeDevices(tx, rx, pa); + } + + void ProbeCmdHandler::probeDevices(bool tx, bool rx, bool params) { ndsp::DeviceBlock::device_mode_t m = ndsp::DeviceBlock::MODE_NORMAL; if (tx) diff --git a/src-cli2/probe.h b/src-cli2/probe.h index d2c78c0d4..0733f5c11 100644 --- a/src-cli2/probe.h +++ b/src-cli2/probe.h @@ -1,6 +1,17 @@ #pragma once +#include "subcommand.h" + namespace satdump { - void probeDevices(bool tx, bool rx, bool params); -} \ No newline at end of file + class ProbeCmdHandler : public CmdHandler + { + public: + ProbeCmdHandler() : CmdHandler("probe") {} + + void reg(CLI::App *app); + void run(CLI::App *app, CLI::App *subcom); + + void probeDevices(bool tx, bool rx, bool params); + }; +} // namespace satdump \ No newline at end of file diff --git a/src-cli2/process.cpp b/src-cli2/process.cpp index 962307ea6..986be8d8a 100644 --- a/src-cli2/process.cpp +++ b/src-cli2/process.cpp @@ -5,7 +5,21 @@ namespace satdump { - void processProductsOrDataset(std::string product, std::string directory) + void ProcessCmdHandler::reg(CLI::App *app) + { + CLI::App *sub_process = app->add_subcommand("process", "Process products/dataset automatically"); + sub_process->add_option("product", "Product to process")->required(); + sub_process->add_option("directory", "Output folder")->required(); + } + + void ProcessCmdHandler::run(CLI::App *app, CLI::App *subcom) + { + std::string pro = subcom->get_option("product")->as(); + std::string dir = subcom->get_option("directory")->as(); + processProductsOrDataset(pro, dir); + } + + void ProcessCmdHandler::processProductsOrDataset(std::string product, std::string directory) { if (!std::filesystem::exists(directory)) std::filesystem::create_directories(directory); diff --git a/src-cli2/process.h b/src-cli2/process.h index b0fa55ba1..6adfd813c 100644 --- a/src-cli2/process.h +++ b/src-cli2/process.h @@ -1,8 +1,17 @@ #pragma once -#include +#include "subcommand.h" namespace satdump { - void processProductsOrDataset(std::string product, std::string directory); -} \ No newline at end of file + class ProcessCmdHandler : public CmdHandler + { + public: + ProcessCmdHandler() : CmdHandler("process") {} + + void reg(CLI::App *app); + void run(CLI::App *app, CLI::App *subcom); + + void processProductsOrDataset(std::string product, std::string directory); + }; +} // namespace satdump \ No newline at end of file diff --git a/src-cli2/run_as.cpp b/src-cli2/run_as.cpp index b82d08f02..7e7106ea2 100644 --- a/src-cli2/run_as.cpp +++ b/src-cli2/run_as.cpp @@ -62,7 +62,26 @@ namespace satdump } } - int runAngelScript(std::string file, bool lint, bool predef) + void ScriptCmdHandler::reg(CLI::App *app) + { + CLI::App *sub_run = app->add_subcommand("run", "Run a script"); + sub_run->add_option("script", "The script to run")->required(); + // auto sub_run_group = sub_run->add_option_group("--lua,--as"); + // sub_run_group->add_flag("--lua", "Run a Lua script"); + // sub_run_group->add_flag("--as", "Run an AngelScript script"); + // sub_run_group->require_option(1); TODOREWORK + sub_run->add_flag("--lint", "Lint the script, without executing it"); + sub_run->add_flag("--predef", "Dump as.predefined"); + sub_run->require_option(1, 3); + } + + void ScriptCmdHandler::run(CLI::App *app, CLI::App *subcom) + { + std::string script = subcom->get_option("script")->as(); + runAngelScript(script, subcom->count("--lint"), subcom->count("--predef")); + } + + int ScriptCmdHandler::runAngelScript(std::string file, bool lint, bool predef) { // Create the script engine asIScriptEngine *engine = asCreateScriptEngine(); diff --git a/src-cli2/run_as.h b/src-cli2/run_as.h index e41ffaf77..83aedeccb 100644 --- a/src-cli2/run_as.h +++ b/src-cli2/run_as.h @@ -1,8 +1,17 @@ #pragma once -#include +#include "subcommand.h" namespace satdump { - int runAngelScript(std::string file, bool lint, bool predef); -} \ No newline at end of file + class ScriptCmdHandler : public CmdHandler + { + public: + ScriptCmdHandler() : CmdHandler("run") {} + + void reg(CLI::App *app); + void run(CLI::App *app, CLI::App *subcom); + + int runAngelScript(std::string file, bool lint, bool predef); + }; +} // namespace satdump \ No newline at end of file diff --git a/src-cli2/subcommand.h b/src-cli2/subcommand.h new file mode 100644 index 000000000..e13a58808 --- /dev/null +++ b/src-cli2/subcommand.h @@ -0,0 +1,18 @@ +#pragma once + +#include "CLI11.hpp" + +namespace satdump +{ + class CmdHandler + { + public: + const std::string cmd; + + public: + CmdHandler(std::string cmd) : cmd(cmd) {} + + virtual void reg(CLI::App *app) = 0; + virtual void run(CLI::App *app, CLI::App *subcom) = 0; + }; +} // namespace satdump \ No newline at end of file