/* SPDX-License-Identifier: Apache-2.0 */ /* * Copyright 2021 XIA LLC, All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** @file example_pixie16api.cpp * @brief Demonstrates how to use the Pixie16Api functions to communicate with Pixie-16 modules. * * We demonstrate both the PixieSDK implementation using `Pixie16Api.so` and the Legacy C * implementation using `Pixie16App.so`. The only difference between using one library over the * other is in the header definitions. * * The `Pixie16Api.so` includes all the goodness that comes with using the C++ implementation * just with a convenient C wrapper. Users don't have as much control over the nitty-gritty details * of the PixieSDK. We've intentionally limited this to prevent this backward compatible API from * growing out of hand. We **really** recommend that you link your code directly with `PixieSDK.a`. */ #include #include #include #include #include #include #include #include #include #include #include #include struct LOG { explicit LOG(const std::string& type) { type_ = type; std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); std::time_t currentTime = std::chrono::system_clock::to_time_t(now); std::chrono::milliseconds now2 = std::chrono::duration_cast(now.time_since_epoch()); char timeBuffer[80]; std::strftime(timeBuffer, 80, "%FT%T", gmtime(¤tTime)); std::stringstream tmp; tmp << timeBuffer << "." << std::setfill('0') << std::setw(3) << now2.count() % 1000 << "Z"; datetime_ = tmp.str(); } friend std::ostream& operator<<(std::ostream& os, const LOG& log) { os << log.datetime_ << " - " << log.type_ << " - "; return os; } std::string type_; std::string datetime_; }; struct module_config { unsigned short slot; unsigned short number; std::string com_fpga_config; std::string sp_fpga_config; std::string dsp_code; std::string dsp_par; std::string dsp_var; }; typedef std::vector module_configs; struct configuration { module_configs modules; std::vector slot_def; unsigned short num_modules() const { return static_cast(modules.size()); } }; std::string generate_filename(const unsigned int& module_number, const std::string& type, const std::string& ext) { #ifndef LEGACY_EXAMPLE static const std::string file_prefix = "pixie16api-module"; #else static const std::string file_prefix = "pixie16app-module"; #endif return file_prefix + std::to_string(module_number) + "-" + type + "." + ext; } void verify_json_module(const nlohmann::json& mod) { if (!mod.contains("slot")) { throw std::invalid_argument("Missing slot definition in configuration element."); } if (!mod.contains("dsp")) { throw std::invalid_argument("Missing dsp object in configuration element."); } if (!mod["dsp"].contains("ldr") || !mod["dsp"].contains("var") || !mod["dsp"].contains("par")) { throw std::invalid_argument( "Missing dsp object in configuration element: ldr, dsp, or par."); } if (!mod.contains("fpga")) { throw std::invalid_argument("Missing fpga object in configuration element."); } if (!mod["fpga"].contains("fippi") || !mod["fpga"].contains("sys")) { throw std::invalid_argument("Missing fpga firmware definition (fippi or sys)."); } } void read_config(const std::string& config_file_name, configuration& cfg) { std::ifstream input(config_file_name, std::ios::in); if (input.fail()) { throw std::ios_base::failure("open: " + config_file_name + ": " + std::strerror(errno)); } nlohmann::json jf = nlohmann::json::parse(input); input.close(); if (jf.empty() || jf.size() > SYS_MAX_NUM_MODULES) { throw std::invalid_argument("invalid number of modules"); } cfg.slot_def.clear(); for (const auto& module : jf) { verify_json_module(module); cfg.slot_def.push_back(module["slot"]); module_config mod_cfg; mod_cfg.slot = module["slot"]; mod_cfg.number = static_cast(cfg.slot_def.size() - 1); mod_cfg.com_fpga_config = module["fpga"]["sys"]; mod_cfg.sp_fpga_config = module["fpga"]["fippi"]; mod_cfg.dsp_code = module["dsp"]["ldr"]; mod_cfg.dsp_par = module["dsp"]["par"]; mod_cfg.dsp_var = module["dsp"]["var"]; cfg.modules.push_back(mod_cfg); } } bool verify_api_return_value(const int& val, const std::string& func_name, const bool& print_success = true) { if (val < 0) { std::cout << LOG("ERROR") << func_name << " failed with Error Code " << val << std::endl; return false; } if (print_success) std::cout << LOG("INFO") << func_name << " finished successfully." << std::endl; return true; } bool output_statistics_data(const unsigned short& mod_num, const std::string& type) { #ifndef LEGACY_EXAMPLE std::vector stats(Pixie16GetStatisticsSize(), 0); #else std::vector stats(N_DSP_PAR - DSP_IO_BORDER, 0); #endif if (!verify_api_return_value(Pixie16ReadStatisticsFromModule(stats.data(), mod_num), "Pixie16ReadStatisticsFromModule", false)) return false; std::ofstream bin_output(generate_filename(mod_num, type, "bin"), std::ios::binary | std::ios::out); bin_output.write(reinterpret_cast(stats.data()), sizeof(unsigned int) * stats.size()); bin_output.close(); std::ofstream csv_output(generate_filename(mod_num, type, "csv"), std::ios::out); csv_output << "channel,real_time,live_time,input_count_rate,output_count_rate" << std::endl; auto real_time = Pixie16ComputeRealTime(stats.data(), mod_num); std::cout << LOG("INFO") << "Begin Statistics for Module " << mod_num << std::endl; std::cout << LOG("INFO") << "Real Time: " << real_time << std::endl; for (unsigned int chan = 0; chan < NUMBER_OF_CHANNELS; chan++) { auto live_time = Pixie16ComputeLiveTime(stats.data(), mod_num, chan); auto icr = Pixie16ComputeInputCountRate(stats.data(), mod_num, chan); auto ocr = Pixie16ComputeOutputCountRate(stats.data(), mod_num, chan); std::cout << LOG("INFO") << "Channel " << chan << " LiveTime: " << live_time << std::endl; std::cout << LOG("INFO") << "Channel " << chan << " Input Count Rate: " << icr << std::endl; std::cout << LOG("INFO") << "Channel " << chan << " Output Count Rate: " << ocr << std::endl; csv_output << chan << "," << real_time << "," << live_time << "," << icr << "," << ocr << std::endl; } std::cout << LOG("INFO") << "End Statistics for Module " << mod_num << std::endl; csv_output.close(); return true; } bool save_dsp_pars(const std::string& filename) { std::cout << LOG("INFO") << "Saving DSP Parameters to " << filename << "." << std::endl; if (!verify_api_return_value(Pixie16SaveDSPParametersToFile(filename.c_str()), "Pixie16SaveDSPParametersToFile")) return false; return true; } bool execute_adjust_offsets(const module_config& module) { std::cout << LOG("INFO") << "Adjusting baseline offset for Module " << module.number << "." << std::endl; if (!verify_api_return_value(Pixie16AdjustOffsets(module.number), "Pixie16AdjustOffsets for Module " + std::to_string(module.number))) return false; if (!save_dsp_pars(module.dsp_par)) return false; return true; } bool execute_baseline_capture(const unsigned short& module_number) { std::cout << LOG("INFO") << "Starting baseline capture for Module " << module_number << std::endl; if (!verify_api_return_value(Pixie16AcquireBaselines(module_number), "Pixie16AcquireBaselines")) return false; double baselines[NUMBER_OF_CHANNELS][MAX_NUM_BASELINES]; double timestamps[MAX_NUM_BASELINES]; for (unsigned int i = 0; i < NUMBER_OF_CHANNELS; i++) { std::cout << LOG("INFO") << "Acquiring baselines for Channel " << i << std::endl; if (!verify_api_return_value(Pixie16ReadSglChanBaselines(baselines[i], timestamps, MAX_NUM_BASELINES, module_number, i), "Pixie16ReadsglChanBaselines")) return false; } std::ofstream ofstream1(generate_filename(module_number, "baselines", "csv")); ofstream1 << "bin,timestamp,"; for (unsigned int i = 0; i < NUMBER_OF_CHANNELS; i++) { if (i != NUMBER_OF_CHANNELS - 1) ofstream1 << "Chan" << i << ","; else ofstream1 << "Chan" << i; } ofstream1 << std::endl; for (unsigned int i = 0; i < MAX_NUM_BASELINES; i++) { ofstream1 << i << "," << timestamps[i] << ","; for (unsigned int k = 0; k < NUMBER_OF_CHANNELS; k++) { if (k != NUMBER_OF_CHANNELS - 1) ofstream1 << baselines[k][i] << ","; else ofstream1 << baselines[k][i]; } ofstream1 << std::endl; } return true; } bool execute_list_mode_run(const configuration& cfg, const double& runtime_in_seconds) { std::cout << LOG("INFO") << "Starting list mode data run for " << runtime_in_seconds << " s." << std::endl; std::cout << LOG("INFO") << "Calling Pixie16WriteSglModPar to read SYNCH_WAIT in Module 0." << std::endl; unsigned int parData; if (!verify_api_return_value(Pixie16ReadSglModPar("SYNCH_WAIT", &parData, 0), "Pixie16ReadSglModPar - SYNC_WAIT")) return false; std::cout << LOG("INFO") << "SYNCH_WAIT in Module 0. = " << parData << std::endl; std::cout << LOG("INFO") << "Calling Pixie16ReadSglModPar to read IN_SYNCH in Module 0." << std::endl; if (!verify_api_return_value(Pixie16ReadSglModPar("IN_SYNCH", &parData, 0), "Pixie16ReadSglModPar - IN_SYNC")) return false; std::cout << LOG("INFO") << "IN_SYNCH in Module 0. = " << parData << std::endl; std::cout << LOG("INFO") << "Calling Pixie16WriteSglModPar to write SYNCH_WAIT = 1 in Module 0." << std::endl; if (!verify_api_return_value(Pixie16WriteSglModPar("SYNCH_WAIT", 1, 0), "Pixie16WriteSglModPar - SYNC_WAIT")) return false; std::cout << LOG("INFO") << "Calling Pixie16WriteSglModPar to write IN_SYNCH = 0 in Module 0." << std::endl; if (!verify_api_return_value(Pixie16WriteSglModPar("IN_SYNCH", 0, 0), "Pixie16WriteSglModPar - IN_SYNC")) return false; std::cout << LOG("INFO") << "Calling Pixie16StartListModeRun." << std::endl; if (!verify_api_return_value(Pixie16StartListModeRun(cfg.num_modules(), LIST_MODE_RUN, NEW_RUN), "Pixie16StartListModeRun")) return false; std::vector output_streams(cfg.num_modules()); for (unsigned short i = 0; i < cfg.num_modules(); i++) { output_streams[i] = new std::ofstream(generate_filename(i, "list-mode", "evt"), std::ios::out | std::ios::binary); } std::vector data(EXTERNAL_FIFO_LENGTH, 0); unsigned int num_fifo_words = 0; std::cout << LOG("INFO") << "Collecting data for " << runtime_in_seconds << " s." << std::endl; std::chrono::steady_clock::time_point run_start_time = std::chrono::steady_clock::now(); while (std::chrono::duration_cast>( std::chrono::steady_clock::now() - run_start_time) .count() < runtime_in_seconds) { // for (unsigned short mod_num = 0; mod_num < cfg.num_modules(); mod_num++) { for (unsigned short mod_num = 0; mod_num < 1; mod_num++) { if (Pixie16CheckRunStatus(mod_num) == 1) { if (!verify_api_return_value( Pixie16CheckExternalFIFOStatus(&num_fifo_words, mod_num), "Pixie16CheckExternalFIFOStatus", false)) return false; if (double(num_fifo_words) / EXTERNAL_FIFO_LENGTH > 0.2) { std::cout << LOG("INFO") << "External FIFO has " << num_fifo_words << " words." << std::endl; if (!verify_api_return_value( Pixie16ReadDataFromExternalFIFO(data.data(), num_fifo_words, mod_num), "Pixie16ReadDataFromExternalFIFO", false)) return false; output_streams[mod_num]->write(reinterpret_cast(data.data()), num_fifo_words * sizeof(uint32_t)); } else { continue; } } else { std::cout << LOG("INFO") << "Module " << mod_num << " has no active run!" << std::endl; } } /* Check the run status of the Director module (module #0) to see if the run has been stopped. This is possible in a multi-chassis system where modules in one chassis can stop the run in all chassis. */ if (Pixie16CheckRunStatus(0) == 0) { std::cout << LOG("INFO") << "Run was stopped by the director module. Stopping data collection." << std::endl; break; } } /* Stop run in the Director module (module #0) - a SYNC interrupt should be generated to stop run in all modules simultaneously */ std::cout << LOG("INFO") << "Stopping List Mode Run." << std::endl; if (!verify_api_return_value(Pixie16EndRun(0), "Pixie16EndRun")) return false; std::cout << LOG("INFO") << "Checking that the run is finalized in all the modules." << std::endl; bool all_modules_finished = false; const unsigned int max_finalize_attempts = 50; for (unsigned int counter = 0; counter < max_finalize_attempts; counter++) { for (unsigned short k = 0; k < cfg.num_modules(); k++) { if (Pixie16CheckRunStatus(k) == 1) { all_modules_finished = false; } else { all_modules_finished = true; } } if (all_modules_finished) { break; } std::this_thread::sleep_for(std::chrono::milliseconds(100)); } if (!all_modules_finished) { std::cout << LOG("ERROR") << "All modules did not stop their runs properly!" << std::endl; return false; } std::cout << LOG("INFO") << "List-mode run finished in " << std::chrono::duration_cast>( std::chrono::steady_clock::now() - run_start_time) .count() << " s" << std::endl; std::cout << LOG("INFO") << "Reading the final words from the External FIFO and the run statistics." << std::endl; for (unsigned short mod_num = 0; mod_num < cfg.num_modules(); mod_num++) { if (!verify_api_return_value(Pixie16CheckExternalFIFOStatus(&num_fifo_words, mod_num), "Pixie16CheckExternalFIFOStatus", false)) return false; if (num_fifo_words > 0) { std::cout << LOG("INFO") << "External FIFO has " << num_fifo_words << " words." << std::endl; if (!verify_api_return_value( Pixie16ReadDataFromExternalFIFO(data.data(), num_fifo_words, mod_num), "Pixie16ReadDataFromExternalFIFO", false)) return false; output_streams[mod_num]->write(reinterpret_cast(data.data()), num_fifo_words * sizeof(uint32_t)); } if (!output_statistics_data(mod_num, "list-mode-stats")) { return false; } } return true; } bool execute_mca_run(const unsigned int& mod, const double& runtime_in_seconds) { std::cout << LOG("INFO") << "Calling Pixie16WriteSglModPar to write HOST_RT_PRESET to " << runtime_in_seconds << std::endl; if (!verify_api_return_value( Pixie16WriteSglModPar("HOST_RT_PRESET", Decimal2IEEEFloating(runtime_in_seconds), mod), "Pixie16WriteSglModPar - HOST_RT_PRESET")) return false; std::cout << LOG("INFO") << "Calling Pixie16WriteSglModPar to write SYNCH_WAIT = 1 in Module 0." << std::endl; if (!verify_api_return_value(Pixie16WriteSglModPar("SYNCH_WAIT", 1, mod), "Pixie16WriteSglModPar - SYNC_WAIT")) return false; std::cout << LOG("INFO") << "Calling Pixie16WriteSglModPar to write IN_SYNCH = 0 in Module 0." << std::endl; if (!verify_api_return_value(Pixie16WriteSglModPar("IN_SYNCH", 0, mod), "Pixie16WriteSglModPar - IN_SYNC")) return false; std::cout << LOG("INFO") << "Starting MCA data run for " << runtime_in_seconds << " s." << std::endl; if (!verify_api_return_value(Pixie16StartHistogramRun(mod, NEW_RUN), "Pixie16StartHistogramRun")) return false; std::chrono::steady_clock::time_point run_start_time = std::chrono::steady_clock::now(); while (std::chrono::duration_cast>( std::chrono::steady_clock::now() - run_start_time) .count() < runtime_in_seconds) { //do nothing } std::cout << LOG("INFO") << "Stopping MCA data run after " << std::chrono::duration_cast>( std::chrono::steady_clock::now() - run_start_time) .count() << " s." << std::endl; if (!verify_api_return_value(Pixie16EndRun(mod), "Pixie16EndRun")) return false; std::string name = generate_filename(mod, "mca", "csv"); std::ofstream out(name); out << "bin,"; std::vector> hists; for (unsigned int i = 0; i < NUMBER_OF_CHANNELS; i++) { std::vector hist(MAX_HISTOGRAM_LENGTH, 0); Pixie16ReadHistogramFromModule(hist.data(), MAX_HISTOGRAM_LENGTH, mod, i); hists.push_back(hist); if (i < NUMBER_OF_CHANNELS - 1) out << "Chan" << i << ","; else out << "Chan" << i; } out << std::endl; for (unsigned int bin = 0; bin < MAX_HISTOGRAM_LENGTH; bin++) { out << bin << ","; for (auto& hist : hists) { if (&hist != &hists.back()) out << hist[bin] << ","; else out << hist[bin]; } out << std::endl; } if (!output_statistics_data(mod, "mca-stats")) { return false; } return true; } bool execute_parameter_read(args::ValueFlag& parameter, args::ValueFlag& crate, args::ValueFlag& module, args::ValueFlag& channel) { if (channel) { double result; std::cout << LOG("INFO") << "Pixie16ReadSglChanPar" << " reading " << parameter.Get() << " from Crate " << crate.Get() << " Module " << module.Get() << " Channel " << channel.Get() << "." << std::endl; if (!verify_api_return_value(Pixie16ReadSglChanPar(parameter.Get().c_str(), &result, module.Get(), channel.Get()), "Pixie16ReadSglChanPar", false)) return false; std::cout << LOG("INFO") << result << std::endl; } else { unsigned int result; std::cout << LOG("INFO") << "Pixie16ReadSglModPar reading " << parameter.Get() << " from Crate " << crate.Get() << " Module " << module.Get() << "." << std::endl; if (!verify_api_return_value( Pixie16ReadSglModPar(parameter.Get().c_str(), &result, module.Get()), "Pixie16ReadSglModPar", false)) return false; std::cout << LOG("INFO") << result << std::endl; } return true; } bool execute_parameter_write(args::ValueFlag& parameter, args::ValueFlag& value, args::ValueFlag& crate, const module_config& module, args::ValueFlag& channel) { if (channel) { std::cout << LOG("INFO") << "Pixie16WriteSglChanPar setting " << parameter.Get() << " to " << value.Get() << " for Crate " << crate.Get() << " Module " << module.number << " Channel " << channel.Get() << "." << std::endl; if (!verify_api_return_value(Pixie16WriteSglChanPar(parameter.Get().c_str(), value.Get(), module.number, channel.Get()), "Pixie16WriteSglChanPar")) return false; } else { std::cout << LOG("INFO") << "Pixie16WriteSglModPar" << " setting " << parameter.Get() << " to " << value.Get() << " for Crate " << crate.Get() << " Module " << module.number << "." << std::endl; if (!verify_api_return_value( Pixie16WriteSglModPar(parameter.Get().c_str(), value, module.number), "Pixie16WriteSglModPar")) return false; } if (!save_dsp_pars(module.dsp_par)) return false; return true; } bool execute_trace_capture(const unsigned short& module_number) { std::cout << LOG("INFO") << "Pixie16AcquireADCTrace acquiring traces for Module " << module_number << "." << std::endl; if (!verify_api_return_value(Pixie16AcquireADCTrace(module_number), "Pixie16AcquireADCTrace")) return false; unsigned short trace[NUMBER_OF_CHANNELS][MAX_ADC_TRACE_LEN]; for (unsigned int i = 0; i < NUMBER_OF_CHANNELS; i++) { if (!verify_api_return_value( Pixie16ReadSglChanADCTrace(trace[i], MAX_ADC_TRACE_LEN, module_number, i), "Pixie16AcquireADCTrace", false)) return false; } std::ofstream ofstream1(generate_filename(module_number, "adc", "csv")); ofstream1 << "bin,"; for (unsigned int i = 0; i < NUMBER_OF_CHANNELS; i++) { if (i != NUMBER_OF_CHANNELS - 1) ofstream1 << "Chan" << i << ","; else ofstream1 << "Chan" << i; } ofstream1 << std::endl; for (unsigned int i = 0; i < MAX_ADC_TRACE_LEN; i++) { ofstream1 << i << ","; for (unsigned int k = 0; k < NUMBER_OF_CHANNELS; k++) { if (k != NUMBER_OF_CHANNELS - 1) ofstream1 << trace[k][i] << ","; else ofstream1 << trace[k][i]; } ofstream1 << std::endl; } return true; } bool execute_blcut(args::ValueFlag& module, args::ValueFlag& channel) { if (!module) return false; std::cout << LOG("INFO") << "Executing Pixie16BLcutFinder for Module" << module.Get() << "." << std::endl; unsigned int blcut = 0; if (!verify_api_return_value(Pixie16BLcutFinder(module.Get(), channel.Get(), &blcut), "Pixie16BLcutFinder", false)) return false; std::cout << LOG("INFO") << "BLCut for Module " << module.Get() << " Channel " << channel.Get() << " is " << blcut << std::endl; return true; } bool execute_set_dacs(args::ValueFlag& module) { if (!module) return false; std::cout << LOG("INFO") << "Executing Pixie16SetDACs for Module" << module.Get() << "." << std::endl; if (!verify_api_return_value(Pixie16SetDACs(module.Get()), "Pixie16SetDACs", false)) return false; return true; } bool execute_close_module_connection(const int& numModules) { std::cout << LOG("INFO") << "Closing out connection to Modules." << std::endl; verify_api_return_value(Pixie16ExitSystem(numModules),"Pixie16ExitSystem"); return true; } double calculate_duration_in_seconds(const std::chrono::system_clock::time_point& start, const std::chrono::system_clock::time_point& end) { return std::chrono::duration(end - start).count(); } void output_module_info(const configuration& cfg) { unsigned short rev; unsigned int serial_number; unsigned short adc_bits; unsigned short adc_msps; for (const auto& mod : cfg.modules) { if (!verify_api_return_value( Pixie16ReadModuleInfo(mod.number, &rev, &serial_number, &adc_bits, &adc_msps), "Pixie16ReadModuleInfo", false)) throw std::runtime_error("Could not get module information for Module " + std::to_string(mod.number)); std::cout << LOG("INFO") << "Begin module information for Module " << mod.number << std::endl; std::cout << LOG("INFO") << "Serial Number: " << serial_number << std::endl; std::cout << LOG("INFO") << "Revision: " << rev << std::endl; std::cout << LOG("INFO") << "ADC Bits: " << adc_bits << std::endl; std::cout << LOG("INFO") << "ADC MSPS: " << adc_msps << std::endl; std::cout << LOG("INFO") << "End module information for Module " << mod.number << std::endl; } } int main(int argc, char** argv) { auto start = std::chrono::system_clock::now(); args::ArgumentParser parser( "Sample code that interfaces with a Pixie system through the User API."); parser.LongSeparator("="); args::Group commands(parser, "commands"); args::Command boot(commands, "boot", "Boots the crate of modules."); args::Command copy(commands, "copy", "Copies DSP parameters from source to destination."); args::Command export_settings( commands, "export-settings", "Boots the system and dumps the settings to the file defined in the config."); args::Command histogram(commands, "histogram", "Save histograms from the module."); args::Command init(commands, "init", "Initializes the system without going any farther."); args::Command list_mode(commands, "list-mode", "Starts a list mode data run"); args::Command read(commands, "read", "Read a parameter from the module."); args::Command write(commands, "write", "Write a parameter to the module."); args::Command trace(commands, "trace", "Captures traces from the modules."); args::Command adjust_offsets(commands, "adjust_offsets", "Adjusts the DC offsets for all modules in the config file."); args::Command baseline(commands, "baseline", "Acquire and print baselines from the module"); args::Command mca(commands, "mca", "Starts an MCA data run."); args::Command blcut(commands, "blcut", "Starts a control task to find the BLCut for a channel."); args::Command dacs(commands, "dacs", "Starts a control task to set the module's DACs"); args::Command tau_finder(commands, "tau_finder", "Executes the Tau Finder control task and returns the values."); args::Group arguments(parser, "arguments", args::Group::Validators::AtLeastOne, args::Options::Global); args::ValueFlag conf_flag(arguments, "cfg", "The configuration file to load.", {'c', "config"}, args::Options::Required); args::ValueFlag additional_cfg_flag( arguments, "cfg", "The configuration file to load.", {"additional-config"}); args::HelpFlag help_flag(arguments, "help", "Displays this message", {'h', "help"}); args::Flag is_fast_boot(boot, "fast-boot", "Performs a partial boot of the system.", {'f', "fast-boot"}); args::Flag is_offline(arguments, "Offline Mode", "Tells the API to use Offline mode when running.", {'o', "offline"}); args::ValueFlag boot_pattern_flag(arguments, "boot_pattern", "The boot pattern used for booting.", {'b', "boot_pattern"}, "0x7F"); args::ValueFlag run_time( list_mode, "time", "The amount of time that a list mode run will take in seconds.", {'t', "run-time"}, 10.); args::ValueFlag parameter( arguments, "parameter", "The parameter we want to read from the system.", {'n', "name"}); args::ValueFlag channel(arguments, "channel", "The channel to operate on.", {"chan"}); args::ValueFlag crate(arguments, "crate", "The crate", {"crate"}, 0); args::ValueFlag copy_mask( copy, "copy_mask", "An integer representing the set of parameters to copy", {"copy-mask"}); args::ValueFlag dest_mask( copy, "dest_mask", "An integer representing the destination channels", {"dest-mask"}); args::ValueFlag dest_channel(copy, "dest_channel", "The channel that we'll copy to", {"dest-chan"}); args::ValueFlag dest_module(copy, "dest_module", "The module that we'll copy to.", {"dest-mod"}); args::ValueFlag module(arguments, "module", "The module to operate on.", {"mod"}); args::ValueFlag parameter_value( write, "parameter_value", "The value of the parameter we want to write.", {'v', "value"}); adjust_offsets.Add(conf_flag); adjust_offsets.Add(boot_pattern_flag); adjust_offsets.Add(module); baseline.Add(is_fast_boot); baseline.Add(boot_pattern_flag); baseline.Add(module); blcut.Add(module); blcut.Add(channel); boot.Add(conf_flag); boot.Add(boot_pattern_flag); copy.Add(boot_pattern_flag); copy.Add(module); copy.Add(channel); dacs.Add(module); mca.Add(module); mca.Add(boot_pattern_flag); read.Add(conf_flag); read.Add(crate); read.Add(module); read.Add(channel); read.Add(parameter); tau_finder.Add(module); trace.Add(conf_flag); trace.Add(module); trace.Add(boot_pattern_flag); write.Add(conf_flag); write.Add(parameter); write.Add(crate); write.Add(module); write.Add(channel); try { parser.ParseCLI(argc, argv); } catch (args::Help& help) { std::cout << LOG("INFO") << help.what() << std::endl; std::cout << parser; return EXIT_SUCCESS; } catch (args::Error& e) { std::cout << LOG("ERROR") << e.what() << std::endl; std::cout << parser; return EXIT_FAILURE; } configuration cfg; try { read_config(conf_flag.Get(), cfg); } catch (std::exception& e) { std::cout << LOG("ERROR") << e.what() << std::endl; return EXIT_FAILURE; } std::cout << LOG("INFO") << "Finished reading config in " << calculate_duration_in_seconds(start, std::chrono::system_clock::now()) << " s." << std::endl; int offline_mode = 0; if (is_offline) offline_mode = 1; start = std::chrono::system_clock::now(); std::cout << LOG("INFO") << "Calling Pixie16InitSystem." << std::endl; if (!verify_api_return_value( Pixie16InitSystem(cfg.num_modules(), cfg.slot_def.data(), offline_mode), "Pixie16InitSystem", false)) return EXIT_FAILURE; std::cout << LOG("INFO") << "Finished Pixie16InitSystem in " << calculate_duration_in_seconds(start, std::chrono::system_clock::now()) << " s." << std::endl; try { output_module_info(cfg); } catch (std::runtime_error& error) { std::cout << LOG("ERROR") << error.what() << std::endl; return EXIT_FAILURE; } if (init) { execute_close_module_connection(cfg.num_modules()); return EXIT_SUCCESS; } unsigned int boot_pattern = stoul(args::get(boot_pattern_flag), nullptr, 0); if (is_fast_boot || additional_cfg_flag) boot_pattern = 0x70; for (const auto& mod : cfg.modules) { start = std::chrono::system_clock::now(); std::cout << LOG("INFO") << "Calling Pixie16BootModule for Module " << mod.number << " with boot pattern: " << std::showbase << std::hex << boot_pattern << std::dec << std::endl; if (!verify_api_return_value( Pixie16BootModule(mod.com_fpga_config.c_str(), mod.sp_fpga_config.c_str(), nullptr, mod.dsp_code.c_str(), mod.dsp_par.c_str(), mod.dsp_var.c_str(), mod.number, boot_pattern), "Pixie16BootModule", "Finished booting!")) return EXIT_FAILURE; std::cout << LOG("INFO") << "Finished Pixie16BootModule for Module " << mod.number << " in " << calculate_duration_in_seconds(start, std::chrono::system_clock::now()) << " s." << std::endl; } if (boot) { execute_close_module_connection(cfg.num_modules()); return EXIT_SUCCESS; } if (additional_cfg_flag) { if (!verify_api_return_value( Pixie16LoadDSPParametersFromFile(additional_cfg_flag.Get().c_str()), "Pixie16LoadDSPParametersFromFile", true)) return EXIT_FAILURE; } if (copy) { if (!module || !channel || !copy_mask || !dest_channel || !dest_module) { std::cout << LOG("ERROR") << "Pixie16CopyDSPParameters requires the source/destination module and channel " "and the destination mask to execute!" << std::endl; } std::vector dest_mask; for(size_t mod = 0; mod < cfg.num_modules(); mod++) { for(size_t chan = 0; chan < NUMBER_OF_CHANNELS; chan++) { if (mod == dest_module.Get() && chan == dest_channel.Get()) dest_mask.push_back(1); else dest_mask.push_back(0); } } if (!verify_api_return_value( Pixie16CopyDSPParameters(copy_mask.Get(), module.Get(), channel.Get(), dest_mask.data()), "Pixie16CopyDSPParameters", true)) { return EXIT_FAILURE; } } if (tau_finder) { if (!module) { std::cout << LOG("ERROR") << "Pixie16TauFinder requires the module flag to execute!" << std::endl; } std::vector taus(NUMBER_OF_CHANNELS); if (!verify_api_return_value(Pixie16TauFinder(module.Get(), taus.data()), "Pixie16TauFinder", true)) { return EXIT_FAILURE; } for (unsigned int i = 0; i < taus.size(); i++) { std::cout << "Channel " << i << ": " << taus.at(i) << std::endl; } } if (read) { if (!execute_parameter_read(parameter, crate, module, channel)) return EXIT_FAILURE; } if (write) { if (!execute_parameter_write(parameter, parameter_value, crate, cfg.modules[module.Get()], channel)) return EXIT_FAILURE; } if (adjust_offsets) { if (!execute_adjust_offsets(cfg.modules[module.Get()])) return EXIT_FAILURE; } if (trace) { if (!execute_trace_capture(module.Get())) return EXIT_FAILURE; } if (list_mode) { if (!execute_list_mode_run(cfg, run_time.Get())) return EXIT_FAILURE; } if (export_settings) { if (!save_dsp_pars(cfg.modules.front().dsp_par)) return EXIT_FAILURE; } if (baseline) { if (!execute_baseline_capture(module.Get())) return EXIT_FAILURE; } if (mca) { if (!execute_mca_run(module.Get(), run_time.Get())) return EXIT_FAILURE; } if (blcut) { if (!execute_blcut(module, channel)) return EXIT_FAILURE; } if (dacs) { if (!execute_set_dacs(module)) return EXIT_FAILURE; } execute_close_module_connection(cfg.num_modules()); return EXIT_SUCCESS; }