From d45669875f4e7fdf013cc2f5f802f04d2609d944 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89rico=20Nogueira?= Date: Tue, 19 Apr 2022 14:18:24 -0300 Subject: [PATCH] Replace docopt with argparse. Doesn't suffer from bugs found in docopt (at least [1] and [2]), has more active development and a better API. [1] https://github.com/docopt/docopt.cpp/issues/147 [2] https://github.com/docopt/docopt.cpp/issues/148 --- .gitmodules | 3 - decode-reg.cc | 175 ++++++++++++++++++++++---------------- meson.build | 3 +- subprojects/argparse.wrap | 12 +++ third_party/docopt.cpp | 1 - third_party/meson.build | 4 - 6 files changed, 117 insertions(+), 81 deletions(-) create mode 100644 subprojects/argparse.wrap delete mode 160000 third_party/docopt.cpp diff --git a/.gitmodules b/.gitmodules index 306eeca..5796b68 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ -[submodule "docopt.cpp"] - path = third_party/docopt.cpp - url = https://github.com/docopt/docopt.cpp.git [submodule "third_party/fpga-config-space"] path = third_party/fpga-config-space url = https://ohwr.org/project/fpga-config-space.git diff --git a/decode-reg.cc b/decode-reg.cc index f540c65..0d37822 100644 --- a/decode-reg.cc +++ b/decode-reg.cc @@ -13,109 +13,140 @@ #include #include - -#include "docopt.h" +#include #include "decoders.h" #include "pcie.h" #include "acq.h" #include "lamp.h" -static const char usage[] = -R"(Simple FPGA Register Reader - -Usage: - decode-reg [-hv] -q -b -a - decode-reg [-hv] -r -b -a -c -n -p -s [-t ] [-e ] [-l] [-z ] [-i ] [-C ] [-d ] - decode-reg [-hv] -x -b -a [-e] -c -m -k -t -s [-d ] - - -h Display this usage information - -v Verbose output - -r Perform read acquisition - -l Use negative edge data trigger - -b Device number as used in /dev/fpga-N - -a Base address to start reads from (in hex) - -c Channel to be used for acquisition - -x Set RTM LAMP parameters - -e Enable amplifier for channel - for RTM LAMP - -m Choose output mode for RTM LAMP. Should be "none" if using -d argument -)"; - - -static void try_long(unsigned &dest, const docopt::Options &args, const char *flag, const char *parameter) +static void try_unsigned(unsigned &dest, const argparse::ArgumentParser &args, const char *flag) { - if (args.at(flag)) - dest = args.at(parameter).asLong(); + if (auto v = args.present(flag)) + dest = *v; } int main(int argc, char *argv[]) { - const docopt::Options args = docopt::docopt(usage, {argv+1, argv+argc}, true); + /* argparse doesn't support subcommands, so we simulate them here */ + if (argc < 2) { + fputs("Usage: decode-reg mode \n\nPositional arguments:\nmode mode of operation ('decode', 'acq' or 'lamp')\n", stderr); + return 1; + } + std::string mode = argv[1]; + + argparse::ArgumentParser parent_args("decode-reg", "1.0", argparse::default_arguments::none); + parent_args.add_argument("-b").help("device number").required().scan<'d', int>(); + parent_args.add_argument("-a").help("base address").required().scan<'x', size_t>().default_value((size_t)0); + parent_args.add_argument("-v").help("verbose output").implicit_value(true); + + argparse::ArgumentParser decode_args("decode-reg decode", "2.0"); + decode_args.add_parents(parent_args); + decode_args.add_argument("-q").help("type of registers").required(); + + argparse::ArgumentParser acq_args("decode-reg acq"); + acq_args.add_parents(parent_args); + acq_args.add_argument("-c").help("channel number").required().scan<'d', unsigned>(); + acq_args.add_argument("-n").help("number of pre samples").required().scan<'d', unsigned>(); + acq_args.add_argument("-p").help("number of post samples").scan<'d', unsigned>(); + acq_args.add_argument("-s").help("number of shots").scan<'d', unsigned>(); + acq_args.add_argument("-t").help("trigger type"); + acq_args.add_argument("-e").help("data trigger threshold").scan<'d', unsigned>(); + acq_args.add_argument("-l").help("use negative edge data trigger").implicit_value(true); + acq_args.add_argument("-z").help("data trigger selection").scan<'d', unsigned>(); + acq_args.add_argument("-i").help("data trigger filter").scan<'d', unsigned>(); + acq_args.add_argument("-C").help("data trigger channel").scan<'d', unsigned>(); + acq_args.add_argument("-d").help("trigger delay").scan<'d', unsigned>(); + + argparse::ArgumentParser lamp_args("decode-reg lamp"); + lamp_args.add_parents(parent_args); + lamp_args.add_argument("-e").help("enable amplifier for channel").implicit_value(true); + lamp_args.add_argument("-c").help("channel number").required().scan<'d', unsigned>(); + lamp_args.add_argument("-m").help("choose output mode. should be 'none' if using -d").required(); + lamp_args.add_argument("-k").help("pi_kp value").required().scan<'d', unsigned>(); + lamp_args.add_argument("-t").help("pi_ti value").required().scan<'d', unsigned>(); + lamp_args.add_argument("-s").help("pi_sp value").required().scan<'d', unsigned>(); + lamp_args.add_argument("-d").help("DAC value").scan<'d', unsigned>(); + + argparse::ArgumentParser *pargs; + if (mode == "decode") { + pargs = &decode_args; + } else if (mode == "acq") { + pargs = &acq_args; + } else if (mode == "lamp") { + pargs = &lamp_args; + } else { + fprintf(stderr, "Unsupported type: '%s'\n", mode.c_str()); + return 1; + } + argparse::ArgumentParser &args = *pargs; - bool verbose = args.at("-v").asBool(); - std::string address_str = args.at("").asString(); - size_t address = std::stol(address_str, nullptr, 16); - int device_number = args.at("").asLong(); + try { + args.parse_args(argc-1, argv+1); + } catch (const std::runtime_error &err) { + fprintf(stderr, "argparse error: %s\n", err.what()); + return 1; + } + + auto device_number = args.get("-b"); + auto address = args.get("-a"); + auto verbose = args.is_used("-v"); pciDriver::PciDevice dev{device_number}; dev.open(); struct pcie_bars bars = {dev.mapBAR(0), dev.mapBAR(2), dev.mapBAR(4)}; - if (verbose) { - fprintf (stdout, "BAR 0 host address = %p\n", bars.bar0); - fprintf (stdout, "BAR 4 host address = %p\n", bars.bar4); + if (mode == "decode") { + auto type = args.get("-q"); + std::unique_ptr dec; + if (type == "acq") { + dec = std::make_unique(); + } else if (type == "lamp") { + dec = std::make_unique(); + } else { + fprintf(stderr, "Unknown type: '%s'\n", type.c_str()); + return 1; + } + dec->read(&bars, address); + dec->print(stdout, verbose); } - - if (args.at("-r").asBool()) { + if (mode == "acq") { LnlsBpmAcqCoreController ctl{&bars, address}; - ctl.channel = args.at("").asLong(); - ctl.pre_samples = args.at("").asLong(); - ctl.post_samples = args.at("").asLong(); - ctl.number_shots = args.at("").asLong(); - if (args.at("-t")) ctl.trigger_type = args.at("").asString(); - try_long(ctl.data_trigger_threshold, args, "-e", ""); - ctl.data_trigger_polarity_neg = args.at("-l").asBool(); - try_long(ctl.data_trigger_sel, args, "-z", ""); - try_long(ctl.data_trigger_filt, args, "-i", ""); - try_long(ctl.data_trigger_channel, args, "-C", ""); - try_long(ctl.trigger_delay, args, "-d", ""); + ctl.channel = args.get("-c"); + ctl.pre_samples = args.get("-n"); + try_unsigned(ctl.post_samples, args, "-p"); + try_unsigned(ctl.number_shots, args, "-s"); + if (auto v = args.present("-t")) ctl.trigger_type = *v; + + try_unsigned(ctl.data_trigger_threshold, args, "-e"); + ctl.data_trigger_polarity_neg = args.is_used("-l"); + try_unsigned(ctl.data_trigger_sel, args, "-z"); + try_unsigned(ctl.data_trigger_filt, args, "-i"); + try_unsigned(ctl.data_trigger_channel, args, "-C"); + try_unsigned(ctl.trigger_delay, args, "-d"); ctl.device = &dev; auto res = std::get>(ctl.result(data_sign::d_signed)); for (auto &v: res) fprintf(stdout, "%d\n", (int)v); - } else if (args.at("-x").asBool()) { + } + if (mode == "lamp") { LnlsRtmLampController ctl(&bars, address); - - ctl.amp_enable = args.at("-e").asBool(); - ctl.mode = args.at("").asString(); - ctl.channel = args.at("").asLong(); - ctl.pi_kp = args.at("").asLong(); - ctl.pi_ti = args.at("").asLong(); - ctl.pi_sp = args.at("").asLong(); - - if (args.at("-d").asBool()) { + ctl.amp_enable = args.is_used("-e"); + ctl.mode = args.get("-m"); + ctl.channel = args.get("-c"); + ctl.pi_kp = args.get("-p"); + ctl.pi_ti = args.get("-t"); + ctl.pi_sp = args.get("-s"); + + if (auto v = args.present("-d")) { ctl.dac_data = true; - ctl.dac = args.at("").asLong(); + ctl.dac = *v; } ctl.write_params(); - } else { - std::string device_type = args.at("").asString(); - - std::unique_ptr dec; - if (device_type == "acq") { - dec = std::make_unique(); - } else if (device_type == "lamp") { - dec = std::make_unique(); - } else { - fprintf(stderr, "Unknown device: '%s'\n", device_type.c_str()); - return 1; - } - dec->read(&bars, address); - dec->print(stdout, verbose); } return 0; diff --git a/meson.build b/meson.build index 363887c..8ccc488 100644 --- a/meson.build +++ b/meson.build @@ -10,10 +10,11 @@ subdir('third_party') cc = meson.get_compiler('c') pcidevice = cc.find_library('pcidriver', required: true) thread_dep = dependency('threads') +argparse = dependency('argparse', fallback: ['argparse', 'argparse_dep']) executable( 'decode-reg', ['decode-reg.cc', 'pcie.c', 'decoders.cc', 'printer.cc', 'acq.cc', 'lamp.cc', 'util.cc'], - dependencies: [pcidevice, thread_dep, docopt, sdbfs], + dependencies: [pcidevice, thread_dep, argparse, sdbfs], install: true, ) diff --git a/subprojects/argparse.wrap b/subprojects/argparse.wrap new file mode 100644 index 0000000..d5a7c7e --- /dev/null +++ b/subprojects/argparse.wrap @@ -0,0 +1,12 @@ +[wrap-file] +directory = argparse-2.4 +source_url = https://github.com/p-ranav/argparse/archive/refs/tags/v2.4.tar.gz +source_filename = argparse-2.4.tar.gz +source_hash = 3589559f115bfedfef2edffb3e7b61d88657ba7b70a0b1f47352ff3043abc825 +patch_filename = argparse_2.4-1_patch.zip +patch_url = https://wrapdb.mesonbuild.com/v2/argparse_2.4-1/get_patch +patch_hash = faa95d9f8f5f5792b1cebc2325cea63557eb46d7e06d51bbb8fa49534ac8a9f8 + +[provide] +argparse = argparse_dep + diff --git a/third_party/docopt.cpp b/third_party/docopt.cpp deleted file mode 160000 index 6f5de76..0000000 --- a/third_party/docopt.cpp +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 6f5de76970be94a6f1e4556d1716593100e285d2 diff --git a/third_party/meson.build b/third_party/meson.build index c6c2b06..48eda5b 100644 --- a/third_party/meson.build +++ b/third_party/meson.build @@ -1,7 +1,3 @@ -docopt_lib = static_library('docopt', 'docopt.cpp/docopt.cpp') -docopt_inc = include_directories('docopt.cpp') -docopt = declare_dependency(link_with: docopt_lib, include_directories: docopt_inc) - sdbfs_inc = include_directories(['sdbfs/lib', 'sdbfs/include/linux']) sdbfs_lib = static_library( 'sdbfs',