diff options
Diffstat (limited to 'src/DabMod.cpp')
-rw-r--r-- | src/DabMod.cpp | 470 |
1 files changed, 6 insertions, 464 deletions
diff --git a/src/DabMod.cpp b/src/DabMod.cpp index 7d6cf8f..a298fbe 100644 --- a/src/DabMod.cpp +++ b/src/DabMod.cpp @@ -48,14 +48,12 @@ #include "TimestampDecoder.h" #include "FIRFilter.h" #include "RemoteControl.h" +#include "ConfigParser.h" #include <memory> -#include <boost/property_tree/ptree.hpp> -#include <boost/property_tree/ini_parser.hpp> #include <complex> #include <string> #include <stdlib.h> -#include <unistd.h> #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> @@ -72,8 +70,6 @@ # define memalign(a, b) malloc(b) #endif -#define ZMQ_INPUT_MAX_FRAME_QUEUE 500 - /* UHD requires the input I and Q samples to be in the interval * [-1.0,1.0], otherwise they get truncated, which creates very @@ -125,56 +121,6 @@ enum class run_modulator_state_t { run_modulator_state_t run_modulator(modulator_data& m); -static GainMode parse_gainmode(const std::string &gainMode_setting) -{ - string gainMode_minuscule(gainMode_setting); - std::transform(gainMode_minuscule.begin(), gainMode_minuscule.end(), gainMode_minuscule.begin(), ::tolower); - - if (gainMode_minuscule == "0" or gainMode_minuscule == "fix") { return GainMode::GAIN_FIX; } - else if (gainMode_minuscule == "1" or gainMode_minuscule == "max") { return GainMode::GAIN_MAX; } - else if (gainMode_minuscule == "2" or gainMode_minuscule == "var") { return GainMode::GAIN_VAR; } - - cerr << "Modulator gainmode setting '" << gainMode_setting << "' not recognised." << endl; - throw std::runtime_error("Configuration error"); -} - -struct mod_settings_t { - std::string outputName; - int useZeroMQOutput = 0; - std::string zmqOutputSocketType = ""; - int useFileOutput = 0; - std::string fileOutputFormat = "complexf"; - int useUHDOutput = 0; - int useSoapyOutput = 0; - - size_t outputRate = 2048000; - size_t clockRate = 0; - unsigned dabMode = 0; - float digitalgain = 1.0f; - float normalise = 1.0f; - GainMode gainMode = GainMode::GAIN_VAR; - - bool loop = false; - std::string inputName = ""; - std::string inputTransport = "file"; - unsigned inputMaxFramesQueued = ZMQ_INPUT_MAX_FRAME_QUEUE; - float edi_max_delay_ms = 0.0f; - - tii_config_t tiiConfig; - - std::string filterTapsFilename = ""; - - -#if defined(HAVE_OUTPUT_UHD) - OutputUHDConfig outputuhd_conf; -#endif - -#if defined(HAVE_SOAPYSDR) - OutputSoapyConfig outputsoapy_conf; -#endif - -}; - static shared_ptr<ModOutput> prepare_output( mod_settings_t& s) { @@ -232,18 +178,9 @@ static shared_ptr<ModOutput> prepare_output( int launch_modulator(int argc, char* argv[]) { int ret = 0; - mod_settings_t mod_settings; - - // Two configuration sources exist: command line and (new) INI file - bool use_configuration_cmdline = false; - bool use_configuration_file = false; - std::string configuration_file; modulator_data m; - // To handle the timestamp offset of the modulator - unsigned tist_delay_stages = 0; - double tist_offset_s = 0.0; auto flowgraph = make_shared<Flowgraph>(); shared_ptr<FormatConverter> format_converter; @@ -273,97 +210,8 @@ int launch_modulator(int argc, char* argv[]) setenv("TZ", "", 1); tzset(); - while (true) { - int c = getopt(argc, argv, "a:C:c:f:F:g:G:hlm:o:O:r:T:u:V"); - if (c == -1) { - break; - } - - if (c != 'C') { - use_configuration_cmdline = true; - } - - switch (c) { - case 'C': - use_configuration_file = true; - configuration_file = optarg; - break; - - case 'a': - mod_settings.digitalgain = strtof(optarg, NULL); - break; - case 'c': - mod_settings.clockRate = strtol(optarg, NULL, 0); - break; - case 'f': -#if defined(HAVE_OUTPUT_UHD) - if (mod_settings.useUHDOutput) { - fprintf(stderr, "Options -u and -f are mutually exclusive\n"); - throw std::invalid_argument("Invalid command line options"); - } -#endif - mod_settings.outputName = optarg; - mod_settings.useFileOutput = 1; - break; - case 'F': -#if defined(HAVE_OUTPUT_UHD) - mod_settings.outputuhd_conf.frequency = strtof(optarg, NULL); -#endif - break; - case 'g': - mod_settings.gainMode = parse_gainmode(optarg); - break; - case 'G': -#if defined(HAVE_OUTPUT_UHD) - mod_settings.outputuhd_conf.txgain = strtod(optarg, NULL); -#endif - break; - case 'l': - mod_settings.loop = true; - break; - case 'o': - tist_offset_s = strtod(optarg, NULL); -#if defined(HAVE_OUTPUT_UHD) - mod_settings.outputuhd_conf.enableSync = true; -#endif - break; - case 'm': - mod_settings.dabMode = strtol(optarg, NULL, 0); - break; - case 'r': - mod_settings.outputRate = strtol(optarg, NULL, 0); - break; - case 'T': - mod_settings.filterTapsFilename = optarg; - break; - case 'u': -#if defined(HAVE_OUTPUT_UHD) - if (mod_settings.useFileOutput) { - fprintf(stderr, "Options -u and -f are mutually exclusive\n"); - throw std::invalid_argument("Invalid command line options"); - } - mod_settings.outputuhd_conf.device = optarg; - mod_settings.outputuhd_conf.refclk_src = "internal"; - mod_settings.outputuhd_conf.pps_src = "none"; - mod_settings.outputuhd_conf.pps_polarity = "pos"; - mod_settings.useUHDOutput = 1; -#endif - break; - case 'V': - printVersion(); - throw std::invalid_argument(""); - break; - case '?': - case 'h': - printUsage(argv[0]); - throw std::invalid_argument(""); - break; - default: - fprintf(stderr, "Option '%c' not coded yet!\n", c); - ret = -1; - throw std::invalid_argument("Invalid command line options"); - } - } + mod_settings_t mod_settings; + parse_args(argc, argv, mod_settings); std::cerr << "ODR-DabMod version " << #if defined(GITVERSION) @@ -388,277 +236,6 @@ int launch_modulator(int argc, char* argv[]) #endif "\n"; - if (use_configuration_file && use_configuration_cmdline) { - fprintf(stderr, "Warning: configuration file and command line parameters are defined:\n\t" - "Command line parameters override settings in the configuration file !\n"); - } - - // No argument given ? You can't be serious ! Show usage. - if (argc == 1) { - printUsage(argv[0]); - throw std::invalid_argument("Invalid command line options"); - } - - // If only one argument is given, interpret as configuration file name - if (argc == 2) { - use_configuration_file = true; - configuration_file = argv[1]; - } - - if (use_configuration_file) { - // First read parameters from the file - using boost::property_tree::ptree; - ptree pt; - - try { - read_ini(configuration_file, pt); - } - catch (boost::property_tree::ini_parser::ini_parser_error &e) - { - std::cerr << "Error, cannot read configuration file '" << configuration_file.c_str() << "'" << std::endl; - std::cerr << " " << e.what() << std::endl; - throw std::runtime_error("Cannot read configuration file"); - } - - // remote controller: - if (pt.get("remotecontrol.telnet", 0) == 1) { - try { - int telnetport = pt.get<int>("remotecontrol.telnetport"); - auto telnetrc = make_shared<RemoteControllerTelnet>(telnetport); - rcs.add_controller(telnetrc); - } - catch (std::exception &e) { - std::cerr << "Error: " << e.what() << "\n"; - std::cerr << " telnet remote control enabled, but no telnetport defined.\n"; - throw std::runtime_error("Configuration error"); - } - } - -#if defined(HAVE_ZEROMQ) - if (pt.get("remotecontrol.zmqctrl", 0) == 1) { - try { - std::string zmqCtrlEndpoint = pt.get("remotecontrol.zmqctrlendpoint", ""); - std::cerr << "ZmqCtrlEndpoint: " << zmqCtrlEndpoint << std::endl; - auto zmqrc = make_shared<RemoteControllerZmq>(zmqCtrlEndpoint); - rcs.add_controller(zmqrc); - } - catch (std::exception &e) { - std::cerr << "Error: " << e.what() << "\n"; - std::cerr << " zmq remote control enabled, but no endpoint defined.\n"; - throw std::runtime_error("Configuration error"); - } - } -#endif - - // input params: - if (pt.get("input.loop", 0) == 1) { - mod_settings.loop = true; - } - - mod_settings.inputTransport = pt.get("input.transport", "file"); - mod_settings.inputMaxFramesQueued = pt.get("input.max_frames_queued", - ZMQ_INPUT_MAX_FRAME_QUEUE); - - mod_settings.edi_max_delay_ms = pt.get("input.edi_max_delay", 0.0f); - - mod_settings.inputName = pt.get("input.source", "/dev/stdin"); - - // log parameters: - if (pt.get("log.syslog", 0) == 1) { - LogToSyslog* log_syslog = new LogToSyslog(); - etiLog.register_backend(log_syslog); - } - - if (pt.get("log.filelog", 0) == 1) { - std::string logfilename; - try { - logfilename = pt.get<std::string>("log.filename"); - } - catch (std::exception &e) { - std::cerr << "Error: " << e.what() << "\n"; - std::cerr << " Configuration enables file log, but does not specify log filename\n"; - throw std::runtime_error("Configuration error"); - } - - LogToFile* log_file = new LogToFile(logfilename); - etiLog.register_backend(log_file); - } - - auto trace_filename = pt.get<std::string>("log.trace", ""); - if (not trace_filename.empty()) { - LogTracer* tracer = new LogTracer(trace_filename); - etiLog.register_backend(tracer); - } - - - // modulator parameters: - const string gainMode_setting = pt.get("modulator.gainmode", "var"); - mod_settings.gainMode = parse_gainmode(gainMode_setting); - - mod_settings.dabMode = pt.get("modulator.mode", mod_settings.dabMode); - mod_settings.clockRate = pt.get("modulator.dac_clk_rate", (size_t)0); - mod_settings.digitalgain = pt.get("modulator.digital_gain", mod_settings.digitalgain); - mod_settings.outputRate = pt.get("modulator.rate", mod_settings.outputRate); - - // FIR Filter parameters: - if (pt.get("firfilter.enabled", 0) == 1) { - mod_settings.filterTapsFilename = - pt.get<std::string>("firfilter.filtertapsfile", "default"); - } - - // Output options - std::string output_selected; - try { - output_selected = pt.get<std::string>("output.output"); - } - catch (std::exception &e) { - std::cerr << "Error: " << e.what() << "\n"; - std::cerr << " Configuration does not specify output\n"; - throw std::runtime_error("Configuration error"); - } - - if (output_selected == "file") { - try { - mod_settings.outputName = pt.get<std::string>("fileoutput.filename"); - } - catch (std::exception &e) { - std::cerr << "Error: " << e.what() << "\n"; - std::cerr << " Configuration does not specify file name for file output\n"; - throw std::runtime_error("Configuration error"); - } - mod_settings.useFileOutput = 1; - - mod_settings.fileOutputFormat = pt.get("fileoutput.format", mod_settings.fileOutputFormat); - } -#if defined(HAVE_OUTPUT_UHD) - else if (output_selected == "uhd") { - OutputUHDConfig outputuhd_conf; - - outputuhd_conf.device = pt.get("uhdoutput.device", ""); - outputuhd_conf.usrpType = pt.get("uhdoutput.type", ""); - outputuhd_conf.subDevice = pt.get("uhdoutput.subdevice", ""); - outputuhd_conf.masterClockRate = pt.get<long>("uhdoutput.master_clock_rate", 0); - - if (outputuhd_conf.device.find("master_clock_rate") != std::string::npos) { - std::cerr << "Warning:" - "setting master_clock_rate in [uhd] device is deprecated !\n"; - } - - if (outputuhd_conf.device.find("type=") != std::string::npos) { - std::cerr << "Warning:" - "setting type in [uhd] device is deprecated !\n"; - } - - outputuhd_conf.txgain = pt.get("uhdoutput.txgain", 0.0); - outputuhd_conf.frequency = pt.get<double>("uhdoutput.frequency", 0); - std::string chan = pt.get<std::string>("uhdoutput.channel", ""); - outputuhd_conf.dabMode = mod_settings.dabMode; - - if (outputuhd_conf.frequency == 0 && chan == "") { - std::cerr << " UHD output enabled, but neither frequency nor channel defined.\n"; - throw std::runtime_error("Configuration error"); - } - else if (outputuhd_conf.frequency == 0) { - outputuhd_conf.frequency = parseChannel(chan); - } - else if (outputuhd_conf.frequency != 0 && chan != "") { - std::cerr << " UHD output: cannot define both frequency and channel.\n"; - throw std::runtime_error("Configuration error"); - } - - - outputuhd_conf.refclk_src = pt.get("uhdoutput.refclk_source", "internal"); - outputuhd_conf.pps_src = pt.get("uhdoutput.pps_source", "none"); - outputuhd_conf.pps_polarity = pt.get("uhdoutput.pps_polarity", "pos"); - - std::string behave = pt.get("uhdoutput.behaviour_refclk_lock_lost", "ignore"); - - if (behave == "crash") { - outputuhd_conf.refclk_lock_loss_behaviour = CRASH; - } - else if (behave == "ignore") { - outputuhd_conf.refclk_lock_loss_behaviour = IGNORE; - } - else { - std::cerr << "Error: UHD output: behaviour_refclk_lock_lost invalid." << std::endl; - throw std::runtime_error("Configuration error"); - } - - outputuhd_conf.maxGPSHoldoverTime = pt.get("uhdoutput.max_gps_holdover_time", 0); - - mod_settings.outputuhd_conf = outputuhd_conf; - mod_settings.useUHDOutput = 1; - } -#endif -#if defined(HAVE_SOAPYSDR) - else if (output_selected == "soapysdr") { - auto& outputsoapy_conf = mod_settings.outputsoapy_conf; - outputsoapy_conf.device = pt.get("soapyoutput.device", ""); - outputsoapy_conf.masterClockRate = pt.get<long>("soapyoutput.master_clock_rate", 0); - - outputsoapy_conf.txgain = pt.get("soapyoutput.txgain", 0.0); - outputsoapy_conf.frequency = pt.get<double>("soapyoutput.frequency", 0); - std::string chan = pt.get<std::string>("soapyoutput.channel", ""); - outputsoapy_conf.dabMode = mod_settings.dabMode; - - if (outputsoapy_conf.frequency == 0 && chan == "") { - std::cerr << " soapy output enabled, but neither frequency nor channel defined.\n"; - throw std::runtime_error("Configuration error"); - } - else if (outputsoapy_conf.frequency == 0) { - outputsoapy_conf.frequency = parseChannel(chan); - } - else if (outputsoapy_conf.frequency != 0 && chan != "") { - std::cerr << " soapy output: cannot define both frequency and channel.\n"; - throw std::runtime_error("Configuration error"); - } - - mod_settings.useSoapyOutput = 1; - } -#endif -#if defined(HAVE_ZEROMQ) - else if (output_selected == "zmq") { - mod_settings.outputName = pt.get<std::string>("zmqoutput.listen"); - mod_settings.zmqOutputSocketType = pt.get<std::string>("zmqoutput.socket_type"); - mod_settings.useZeroMQOutput = 1; - } -#endif - else { - std::cerr << "Error: Invalid output defined.\n"; - throw std::runtime_error("Configuration error"); - } - -#if defined(HAVE_OUTPUT_UHD) - mod_settings.outputuhd_conf.enableSync = (pt.get("delaymanagement.synchronous", 0) == 1); - mod_settings.outputuhd_conf.muteNoTimestamps = (pt.get("delaymanagement.mutenotimestamps", 0) == 1); - if (mod_settings.outputuhd_conf.enableSync) { - std::string delay_mgmt = pt.get<std::string>("delaymanagement.management", ""); - std::string fixedoffset = pt.get<std::string>("delaymanagement.fixedoffset", ""); - std::string offset_filename = pt.get<std::string>("delaymanagement.dynamicoffsetfile", ""); - - if (not(delay_mgmt.empty() and fixedoffset.empty() and offset_filename.empty())) { - std::cerr << "Warning: you are using the old config syntax for the offset management.\n"; - std::cerr << " Please see the example.ini configuration for the new settings.\n"; - } - - try { - tist_offset_s = pt.get<double>("delaymanagement.offset"); - } - catch (std::exception &e) { - std::cerr << "Error: delaymanagement: synchronous is enabled, but no offset defined!\n"; - throw std::runtime_error("Configuration error"); - } - } - -#endif - - /* Read TII parameters from config file */ - mod_settings.tiiConfig.enable = pt.get("tii.enable", 0); - mod_settings.tiiConfig.comb = pt.get("tii.comb", 0); - mod_settings.tiiConfig.pattern = pt.get("tii.pattern", 0); - mod_settings.tiiConfig.old_variant = pt.get("tii.old_variant", 0); - } - etiLog.level(info) << "Starting up version " << #if defined(GITVERSION) GITVERSION; @@ -670,42 +247,7 @@ int launch_modulator(int argc, char* argv[]) // When using the FIRFilter, increase the modulator offset pipelining delay // by the correct amount if (not mod_settings.filterTapsFilename.empty()) { - tist_delay_stages += FIRFILTER_PIPELINE_DELAY; - } - - // Setting ETI input filename - if (use_configuration_cmdline && mod_settings.inputName == "") { - if (optind < argc) { - mod_settings.inputName = argv[optind++]; - - if (mod_settings.inputName.substr(0, 4) == "zmq+" && - mod_settings.inputName.find("://") != std::string::npos) { - // if the name starts with zmq+XYZ://somewhere:port - mod_settings.inputTransport = "zeromq"; - } - else if (mod_settings.inputName.substr(0, 6) == "tcp://") { - mod_settings.inputTransport = "tcp"; - } - else if (mod_settings.inputName.substr(0, 6) == "udp://") { - mod_settings.inputTransport = "edi"; - } - } - else { - mod_settings.inputName = "/dev/stdin"; - } - } - - // Checking unused arguments - if (use_configuration_cmdline && optind != argc) { - fprintf(stderr, "Invalid arguments:"); - while (optind != argc) { - fprintf(stderr, " %s", argv[optind++]); - } - fprintf(stderr, "\n"); - printUsage(argv[0]); - ret = -1; - etiLog.level(error) << "Received invalid command line arguments"; - throw std::invalid_argument("Invalid command line options"); + mod_settings.tist_delay_stages += FIRFILTER_PIPELINE_DELAY; } if (not (mod_settings.useFileOutput or @@ -770,7 +312,7 @@ int launch_modulator(int argc, char* argv[]) } - EdiReader ediReader(tist_offset_s, tist_delay_stages); + EdiReader ediReader(mod_settings.tist_offset_s, mod_settings.tist_delay_stages); EdiDecoder::ETIDecoder ediInput(ediReader, false); if (mod_settings.edi_max_delay_ms > 0.0f) { // setMaxDelay wants number of AF packets, which correspond to 24ms ETI frames @@ -890,7 +432,7 @@ int launch_modulator(int argc, char* argv[]) m.flowgraph = &flowgraph; m.data.setLength(6144); - EtiReader etiReader(tist_offset_s, tist_delay_stages); + EtiReader etiReader(mod_settings.tist_offset_s, mod_settings.tist_delay_stages); m.etiReader = &etiReader; auto input = make_shared<InputMemory>(&m.data); |