mirror of
https://github.com/slsdetectorgroup/slsDetectorPackage.git
synced 2026-08-07 18:32:25 +02:00
* alignedData now uses std::align_alloc * imagedata is now allocated on the heap * m3 server fix for trimbits and badchannels that are shifted by 1 * formatting * binary in * added check for proper memory allocation * commenting out the example in receiver data call back changing size as it affects users using debugging mode to print out headers * fixed warnings * commenting out the example in receiver data call back changing size as it affects users using debugging mode to print out headers * got rid of cast to uint64 * got rid of Reorder function * added sanity check to only enable for chipttestboard and xilinx * removed Gotthard stuff * update the comment about how to modify data on a data call back from the receiver * autogenerated commands and make format * changed font size in GUI * clang-format with clang-format version 17 * updated update_image_size in xilinx * version number automated for python build * mistakenly set version back to 0.0.0 * updated github workflow scripts to support automatic version numbering with environment variable * managed to load VERSION file in yaml file - simplifies things * saving changes in git workflow failed * got typo in github workflow * updatet regex pattern to support postfix * normalized version to PEP 440 specification in update_version.py * bug did not support version 0.0.0 * upgrading to c++17 from c++11 and patch command has to be found before applying patch on libzmq (#1195) * Dev/allow localhost for virtual tests (#1190) * remove the check for localhost being used in rx_hostname for python test for simulators, run rx_arping test only if hostname is not 'localhost' * fix tests for fpath: cannot set back to empty anymore (empty is default) * default rx_hostname arg = localhost, and default settings path =../../settingsdir * changed virtual tests script for better printout on exceptions * fix for catching generaltests exceptions and exiting instead of continuing * fix minor * fixed shared memeory tests to include current env and fixed prints for errors --------- Co-authored-by: Erik Fröjdh <erik.frojdh@gmail.com> * added regex pattern matching to version in toml file * Dev/gitea docker (#1194) * gitea workflows for RH8 and RH9 * using our docker images * version now supports . before postfix * rough draft of test acquire of all detectors for frames caught and file size. ctb not included yet * moved dbitoffset, dbitreorder and dbitlist to GeneralData * added error message on receiver side, throw error * removed log as error already printed * added tests to check file size and frames caught with an acquire (virtual) for every detector * minor printout removed * typo fixed * removed minor printout * incorrect counter mask tested * fix 10g adc enable mask, switched with 1g * fixed hardcoded values of nchip nchan etc from detPArameters * fixed ctb tests, need to fix in develoepr (if digital modfe not enabled, should not take into accoutn dbitlist or dbitoffset or dbitreorder * only reorder bits if some sort of digital readout mode enabled * trying to fix acquire for xilinx * fix for xilinx ctb virtual * alloweing all tests * typo * fix for slsreceiver killed but complaining for virtual tests with script * fixed bug found by @AliceMazzoleni99 that for ctb server is still shown in pgrep -f if xilinx server running, so now the pid is killed and looking for any DetectorServer_virtual instead. also reset color coding after Log * check if process running for kill -9 slsReceiver fail * removed -9 to kill with cleanup * frame synchonrizer fixes: typo of iterator for loop and zmg_msg_t list cleaned up before sending multi part zmq; test written for the frame synchronizer, test_simulator.py rewritten for more robustness and refactoring commonality between both scripts * better error messageS * minor * typo * moving the erasure of the fnum to after sending the zmg packets and also deleteing all old frames when end of acquisition * fix bug in blackfin read access to firmware registers * updates api version based on version file & converted shell script files to python * updated all makefiles * refactoring code and compiling binary * formatting * rewrote end() for StaticVector * rearranged receiver topics, differentiated btween receiver variants and added info about slsFrameSynchronizer * typo * minor aesthetics * minor * added extra fs link and fixed execute_program warning * and now with link * updating pmods * adresses review comments * dummy commit for versionAPI * formatted and updated versionAPI.h * added expat to host section * updated documentation for pip installation as well * Dev/add numpy (#1227) * added numpy dependency * added build specifications for python version and platform * updates files/variants for pmods for 9.2.0 (#1233) * tests for bool in ToString/StringTo (#1230) - Added tests for ToString/StringTo<bool> - Added overload for ToString of bool (previously went through int) * added docs for SLSDETNAME (#1228) * added docs for SLSDETNAME * clarification on hostname * added examples on module index * fixes * fixed typo * Dev/update test framesynchronizer (#1221) * raise an exception if the pull socket python script had errors at startup (for eg if pyzmq was not installed) * minor changes that got lost in the merge of automate_version_part 2 PR --------- Co-authored-by: Erik Fröjdh <erik.frojdh@gmail.com> * added workflow for python wheels * wip * formatting * wip * wip to parse vector of rois at command line * wip * first level test * can get individual rois, but not connected to command yet * rois shoudl work. left to implement tests for individual rois, create multiple datasets (1 for each roi) in the virutal data file. currently virutal dataset with roi is not implemented and a warning is given instead. wonder why since the inviduviaual roi files are clipped * all tests pased * minor * fixed rx_roi for multi modules jungfrau , tests for eiger, multi modules jungfrau in x and 2 interfaces * works for eiger as well * switched to vector instead of std::array<ROI, 2>>, which prints extra [-1, -1] when theres only 1 udp interface * wip * fix for empty roi vectors (which shouldnt be) as you cant know if its all or not in roi * wip: to map roi to virutal * fix for eiger, added python test for testig roi in different module and detector type configurations * wip, fails with master and virtual * works for complete roi * wip, works for a single roi * works for all rois * wip to fix tests * 1d fixes * rois test work on 1d as well * check master file creation as well in rx_roi tests * get rx_roi from metadata from rxr, cant reconstruct. fixed clear roi should give 1 roi min * gui shows roi now * format * updated python bindings * updated master file versions * cmd generation and formatting * minor fixes in command line and help * minor * doesnt happen anymore * comment * minor * redundant getRxROI in Detector class for multi level and module level * refactor cmd parsing (detid can be parsed directly) * refactor cmd line * refactor command line parsing of roi * modified comments about ctb and xilinx not using roi * refactoring * refactorign * refactoring wip * wip refactoring * formattin * to avoid confusion, moved default initialized, single sized declared vector of roi to be created at setDetectorType * pybind only 1 function for getRxROI * command line help * specified number of receiver error message * minor comment * refactored to take out repetitive code, need to adjust for slsMulti and slsFrameSync * wip * works, need to add tests * made Commadnlineoptions into a class * wip test * fixed tests * cleaning up properly , semaphore leaks, child process/thread throwing handled * getuid issue on github workflow * constexpr and checking if options object type is same * unnecessary capture * remove testing code, minor * fixed help, -t for multi should not be supported as it never had it * Formatting * hdf5 definitions in test when not compiled with hdf5 * typo * moved optstring and long options to the constructor * raising a SIGINT when the child thread has an exception so that the parent thread can exit all the threads and clean up gracefully * minor test typo * check status of child exiting and use that to send sigint to all the child processes from the parent * fixed validation in network_utils, added a tests to throw for port 65535 in test mode (option on for sls_use_tests), multi:parent process checks child process exit status to send sigint to others * moving set signal handler to network utils * readoutspeed in rx master file and other master file inconsistencies (#1245) readout speed added to json and h5 master files. Also fixed master file inconsistencies Sserver binaries - update server binaries because readoutspeed needs to be sent to receiver with rx_hostname command API - added const to Detector class set/getburstmode Python - updated python bindings (burstmode const and roi arguments) Cmd generation - added pragma once in Caller.in.h as Caller is included in test files m3: num channels due to #counters < 3 * workaround for m3 for messed up num channels (client always assumes all counters enabled and adds them to num channels), fix for hdf5 g2: exptime master file inconsistency - exptime didnt match because of round of when setting burst mode (sets to a different clk divider) - so updating actual time for all timers (exptime, period, subexptime etc, ) in Module class, get timer values from detector when setting it and then send to receiver to write in master file ctb image size incorrect: - write actual size into master file and not the reserved size (digital reduces depending on dbit list and dbit offset) - added a calculate ctb image size free function in generalData.h that is used there as well as for the tests. master file inconsistencies - refactored master attributes writing using templates - names changed to keep it consistent between json and hdf5 master file (Version, Pixels, Exposure Times, GateDelays, Acquisition Period, etc.) - datatypes changed to keep it simple where possible: imageSize, dynamicRange, tengiga, quad, readnrows, analog, analogsamples, digital, digitalsamples, dbitreorder, dbitoffset, transceivermask, transeiver, transceiversamples, countermask, gates =>int - replacing "toString" with arrays, objects etc for eg for scan, rois, etc. - json header always written (empty dataset or empty brackets) - hdf5 needs const char* so have to convert strings to it, but taking care that strings exist prior to push_back - master attributes (redundant string literals->error prone tests for master file - suppressed deprecated functions in rapidjson warnings just for the tests - added slsREceiverSoftware/src to allow access to receiver_defs.h to test binary/hdf5 version - refactored acquire tests by moving all the acquire tests from individual detector type files to a single one=test-Caller-acquire.cpp - set some default settings (loadBasicSettings) for a basic acquire at load config part for the test_simulator python scripts. so minimum number of settings for detector to be set for any acquire tests. - added tests to test master files for json and hdf5= test-Caller-master-attributes.cpp - added option to add '-m' markers for tests using test_simulator python script * doc: added inst on how to set persistentn NIC changes after reboot for each ethernet interface such as rx 4096, rx-usecs, adaptive-rx and gro etc. * added permanent ethtool settings also for fedora or modern rhel * troubleshooting doc: permanent changes for 10g pc tuning (#1247) * doc: added inst on how to set persistentn NIC changes after reboot for each ethernet interface such as rx 4096, rx-usecs, adaptive-rx and gro etc. * added permanent ethtool settings also for fedora or modern rhel * ifcfg scripts still work on rhel8, just not preferred * added dataformat for jungfrau * eiger basic mod * eiger doc done * added moench * done * free shm exposed in python as free function and detector function * minimum change * added quad and updated about 1gbe/10gbe * more info * remove arguments info * replacing commands with links * minor * detail explanation of eiger * fixed imagesize ctb issue (out values not transferred, setting any dbit values was not recalculatign image size in generaldata) * fixed ctb dbit clock changing period in tests as it was setting run clock instead * python accessing freed shared memory object (#1253) * added a 'isValid' member in shared memory (also updated shm version) with default true, any access to shared memory() checks also for validity. any free will set this to false and then unmap shm. Any access to shm will then check validity in python. * fixed tests for shm * added tests in python as well --------- Co-authored-by: Alice <alice.mazzoleni@psi.ch> * updated error message * made markers argument in ParseArguments a boolean instead of an int * removed relative path compared to where executable run in test script for settingsdir * fix roi test * updating versions (#1258) * updating package version, client version, server versions. Renaming server versions, using hardlinks in serverBin. Removing ctb servers in serverBin. (#1259) * fixed no interpolation mode for moench (#1262) Co-authored-by: Anna Bergamaschi <anna.bergamaschi@psi.ch> * fixed multi receiver and frames sync help throw of bad variant access (#1265) * 1000/doc c standard (#1267) * updated c++11 to c++17 * more about c++11 and updating readme * updated documentation for receiver arguments and also making receiver constructor explicit * minor fix for rxr err message * fixed doc about gcc version * 1000/release notes (#1269) * updated firmware and server version in release notes * release notes wip * updated notes(prs done) * updated release notes. wip * Release notes * minor * minor fix * 1000/doc architecture commands (#1271) * sw architecture and setup commands * 1000/shm free obsolete (#1273) * freeing obsolete shm withoua a 'isValid' should access raw pointers. Need to move this all into the shm class * fixed obsolete shm free issue * minor * ensuring the test works platform independent for size of int * removed verify, update, fixed getUser to be a free function, generated commands, python bindings yet to do * python bindings * fixed tests * minor * minor * format * userdetails refinedg * fixed caller test * updated client api version (#1277) * one doesnt need to open shared memory to call removesharedmemory, and calling hasMemoryvalid without opening will cause segfault (not used now, but could in the future) * fix test on shm * minor * added image source files from draw.io to create the images (#1280) * 1000/fix_actual_tests (#1282) - fix acquire fail in tests (adcreg test) - roi tests fail after overlapping invalid test and acquire after - print udp dest mac in server properly - fixed udp dst list get (server was not sending entry proper size to match proper struct size in client) - updated server binaries and updated hard links in serverBin - added documentation regarding gui: zmqport and zmqip in terms of gui, rx_zmqstream - removed print - probably ended there for debuggung --------- Co-authored-by: Alice <alice.mazzoleni@psi.ch> * 1000/fix_m3_tests (#1286) * testing clkdiv one must ensure the exptime delay etc all are reset to the exact values for tests * change dac max values for vth values for m3 in client side (set module * 1000/doc_cmake (#1289) * more detail documentation in installation * more detail documentation in installation * added links to api examples * reverted back that vthreshold dacs in m3 have min and max as 200 and 2400 (#1294) * update release notes and date (#1298) --------- Co-authored-by: Mazzoleni Alice Francesca <mazzol_a@pc17378.psi.ch> Co-authored-by: Erik Fröjdh <erik.frojdh@gmail.com> Co-authored-by: AliceMazzoleni99 <alice.mazzoleni@psi.ch> Co-authored-by: Martin Mueller <martin.mueller@psi.ch> Co-authored-by: froejdh_e <erik.frojdh@psi.ch> Co-authored-by: Anna Bergamaschi <anna.bergamaschi@psi.ch>
1440 lines
53 KiB
C++
1440 lines
53 KiB
C++
#include "Caller.h"
|
|
#include "sls/ZmqSocket.h"
|
|
#include "sls/bit_utils.h"
|
|
#include "sls/file_utils.h"
|
|
#include "sls/logger.h"
|
|
#include "sls/string_utils.h"
|
|
#include <iostream>
|
|
#include <thread>
|
|
namespace sls {
|
|
// some helper functions to print
|
|
|
|
std::vector<std::string> Caller::getAllCommands() {
|
|
std::vector<std::string> ret;
|
|
for (auto it : functions)
|
|
ret.push_back(it.first);
|
|
return ret;
|
|
}
|
|
|
|
std::map<std::string, std::string> Caller::GetDeprecatedCommands() {
|
|
return deprecated_functions;
|
|
}
|
|
|
|
void Caller::call(const std::string &command,
|
|
const std::vector<std::string> &arguments, int detector_id,
|
|
int action, std::ostream &os, int receiver_id) {
|
|
cmd = command;
|
|
args = arguments; // copy args before replacing
|
|
std::string temp;
|
|
while (temp != cmd) {
|
|
temp = cmd;
|
|
ReplaceIfDeprecated(cmd);
|
|
}
|
|
|
|
det_id = detector_id;
|
|
rx_id = receiver_id;
|
|
auto it = functions.find(cmd);
|
|
if (it != functions.end()) {
|
|
auto ret = ((*this).*(it->second))(action);
|
|
os << cmd << ' ' << ret;
|
|
} else {
|
|
throw RuntimeError(cmd +
|
|
" Unknown command, use list to list all commands");
|
|
}
|
|
}
|
|
|
|
bool Caller::ReplaceIfDeprecated(std::string &command) {
|
|
auto d_it = deprecated_functions.find(command);
|
|
if (d_it != deprecated_functions.end()) {
|
|
|
|
// insert old command into arguments (for dacs)
|
|
if (d_it->second == "dac") {
|
|
args.insert(args.begin(), command);
|
|
LOG(logWARNING)
|
|
<< command
|
|
<< " is deprecated and will be removed. Please migrate to: "
|
|
<< d_it->second << " " << command;
|
|
} else {
|
|
LOG(logWARNING)
|
|
<< command
|
|
<< " is deprecated and will be removed. Please migrate to: "
|
|
<< d_it->second;
|
|
}
|
|
command = d_it->second;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
std::string Caller::list(int action) {
|
|
if (action == defs::HELP_ACTION) {
|
|
return "[deprecated(optional)]\n\tlists all available commands, list "
|
|
"deprecated - list deprecated commands\n";
|
|
}
|
|
if (args.empty()) {
|
|
std::string ret = "free\n";
|
|
ret += "user\n";
|
|
for (auto &f : functions) {
|
|
ret += f.first + "\n";
|
|
}
|
|
return ret;
|
|
} else if (args.size() == 1) {
|
|
if (args[0] == "deprecated") {
|
|
std::ostringstream os;
|
|
os << "The following " << deprecated_functions.size()
|
|
<< " commands are deprecated\n";
|
|
const size_t field_width = 20;
|
|
for (const auto &it : deprecated_functions) {
|
|
os << std::right << std::setw(field_width) << it.first << " -> "
|
|
<< it.second << '\n';
|
|
}
|
|
return os.str();
|
|
} else {
|
|
throw RuntimeError(
|
|
"Could not decode argument. Possible options: deprecated");
|
|
}
|
|
} else {
|
|
WrongNumberOfParameters(0);
|
|
return "";
|
|
}
|
|
}
|
|
|
|
/* Network Configuration (Detector<->Receiver) */
|
|
|
|
IpAddr Caller::getDstIpFromAuto() {
|
|
std::string rxHostname =
|
|
det->getRxHostname(std::vector<int>{det_id}).squash("none");
|
|
// Hostname could be ip try to decode otherwise look up the hostname
|
|
auto val = IpAddr{rxHostname};
|
|
if (val == 0) {
|
|
val = HostnameToIp(rxHostname.c_str());
|
|
}
|
|
return val;
|
|
}
|
|
|
|
IpAddr Caller::getSrcIpFromAuto() {
|
|
std::string hostname =
|
|
det->getHostname(std::vector<int>{det_id}).squash("none");
|
|
// Hostname could be ip try to decode otherwise look up the hostname
|
|
auto val = IpAddr{hostname};
|
|
if (val == 0) {
|
|
val = HostnameToIp(hostname.c_str());
|
|
}
|
|
return val;
|
|
}
|
|
|
|
UdpDestination Caller::getUdpEntry() {
|
|
UdpDestination udpDestination{};
|
|
udpDestination.entry = rx_id;
|
|
|
|
for (auto it : args) {
|
|
size_t pos = it.find('=');
|
|
std::string key = it.substr(0, pos);
|
|
std::string value = it.substr(pos + 1);
|
|
if (key == "ip") {
|
|
if (value == "auto") {
|
|
auto val = getDstIpFromAuto();
|
|
LOG(logINFO) << "Setting udp_dstip of detector " << det_id
|
|
<< " to " << val;
|
|
udpDestination.ip = val;
|
|
} else {
|
|
udpDestination.ip = IpAddr(value);
|
|
}
|
|
} else if (key == "ip2") {
|
|
if (value == "auto") {
|
|
auto val = getDstIpFromAuto();
|
|
LOG(logINFO) << "Setting udp_dstip2 of detector " << det_id
|
|
<< " to " << val;
|
|
udpDestination.ip2 = val;
|
|
} else {
|
|
udpDestination.ip2 = IpAddr(value);
|
|
}
|
|
} else if (key == "mac") {
|
|
udpDestination.mac = MacAddr(value);
|
|
} else if (key == "mac2") {
|
|
udpDestination.mac2 = MacAddr(value);
|
|
} else if (key == "port") {
|
|
udpDestination.port = StringTo<uint32_t>(value);
|
|
} else if (key == "port2") {
|
|
udpDestination.port2 = StringTo<uint32_t>(value);
|
|
}
|
|
}
|
|
return udpDestination;
|
|
}
|
|
void Caller::WrongNumberOfParameters(size_t expected) {
|
|
if (expected == 0) {
|
|
throw RuntimeError("Command " + cmd +
|
|
" expected no parameter/s but got " +
|
|
std::to_string(args.size()) + "\n");
|
|
}
|
|
throw RuntimeError("Command " + cmd + " expected (or >=) " +
|
|
std::to_string(expected) + " parameter/s but got " +
|
|
std::to_string(args.size()) + "\n");
|
|
}
|
|
|
|
int Caller::GetLevelAndInsertIntoArgs(std::string levelSeparatedCommand) {
|
|
if (cmd != levelSeparatedCommand) {
|
|
LOG(logWARNING) << "This command is deprecated and will be removed. "
|
|
"Please migrate to "
|
|
<< levelSeparatedCommand;
|
|
int level = cmd[cmd.find_first_of("012")] - '0';
|
|
args.insert(args.begin(), std::to_string(level));
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
std::string Caller::free(int action) {
|
|
// This function is purely for help, actual functionality is in the caller
|
|
return "free\n\tFree detector shared memory\n";
|
|
}
|
|
|
|
std::string Caller::user(int action) {
|
|
// This function is purely for help, actual functionality is in the caller
|
|
return "user\n\tUser details from shared memory (hostname, type, PID, "
|
|
"User, Date).\n";
|
|
}
|
|
|
|
std::string Caller::hostname(int action) {
|
|
std::ostringstream os;
|
|
if (action == defs::HELP_ACTION) {
|
|
os << "\n\tFrees shared memory and sets hostname (or IP address) of "
|
|
"all modules concatenated by +.\n\t Virtual servers can already "
|
|
"use the port in hostname separated by ':' and ports incremented "
|
|
"by 2 to accomodate the stop server as well. The row and column "
|
|
"values in the udp/zmq header are affected by the order in this "
|
|
"command and the detsize command. The modules are stacked row by "
|
|
"row until they reach the y-axis limit set by detsize (if "
|
|
"specified). Then, stacking continues in the next column and so "
|
|
"on. This only affects row and column in udp/zmq header."
|
|
<< '\n';
|
|
} else if (action == defs::GET_ACTION) {
|
|
if (!args.empty()) {
|
|
WrongNumberOfParameters(0);
|
|
}
|
|
auto t = det->getHostname(std::vector<int>{det_id});
|
|
os << OutString(t) << '\n';
|
|
} else if (action == defs::PUT_ACTION) {
|
|
if (args.empty()) {
|
|
WrongNumberOfParameters(1);
|
|
}
|
|
if (det_id != -1) {
|
|
throw RuntimeError("Cannot execute this at module level");
|
|
}
|
|
// only args[0], but many hostames concatenated with +
|
|
if (args[0].find('+') != std::string::npos) {
|
|
auto t = split(args[0], '+');
|
|
det->setHostname(t);
|
|
os << ToString(t) << '\n';
|
|
}
|
|
// either hostnames separated by space, or single hostname
|
|
else {
|
|
det->setHostname(args);
|
|
os << ToString(args) << '\n';
|
|
}
|
|
} else {
|
|
throw RuntimeError("Unknown action");
|
|
}
|
|
return os.str();
|
|
}
|
|
|
|
void Caller::EmptyDataCallBack(detectorData *data, uint64_t frameIndex,
|
|
uint32_t subFrameIndex, void *this_pointer) {
|
|
LOG(logDEBUG) << "EmptyDataCallBack to start up zmq sockets";
|
|
}
|
|
|
|
std::string Caller::acquire(int action) {
|
|
std::ostringstream os;
|
|
if (action == defs::HELP_ACTION) {
|
|
os << "\n\tAcquire the number of frames set up.\n\tBlocking command, "
|
|
"where control server is blocked and cannot accept other "
|
|
"commands until acquisition is done. \n\t- sets acquiring "
|
|
"flag\n\t- starts the receiver listener (if enabled)\n\t- starts "
|
|
"detector acquisition for number of frames set\n\t- monitors "
|
|
"detector status from running to idle\n\t- stops the receiver "
|
|
"listener (if enabled)\n\t- increments file index if file write "
|
|
"enabled\n\t- resets acquiring flag"
|
|
<< '\n';
|
|
} else {
|
|
if (det->empty()) {
|
|
throw RuntimeError("This shared memory has no detectors added.");
|
|
}
|
|
if (det_id >= 0) {
|
|
throw RuntimeError("Individual detectors not allowed for readout.");
|
|
}
|
|
if (action == defs::READOUT_ZMQ_ACTION) {
|
|
det->registerDataCallback(&(EmptyDataCallBack), this);
|
|
}
|
|
det->acquire();
|
|
|
|
if (det->getUseReceiverFlag().squash(false)) {
|
|
os << "\nAcquired ";
|
|
os << det->getFramesCaught() << '\n';
|
|
}
|
|
}
|
|
return os.str();
|
|
}
|
|
std::string Caller::versions(int action) {
|
|
std::ostringstream os;
|
|
if (action == defs::HELP_ACTION) {
|
|
os << "\n\tPrint all versions and detector type" << '\n';
|
|
} else if (action == defs::GET_ACTION) {
|
|
if (!args.empty()) {
|
|
WrongNumberOfParameters(0);
|
|
}
|
|
|
|
std::string vType = "Unknown";
|
|
std::string vFirmware = "Unknown";
|
|
std::string vServer = "Unknown";
|
|
std::string vKernel = "Unknown";
|
|
std::string vHardware = "Unknown";
|
|
bool eiger = false;
|
|
std::string vBebFirmware = "Unknown";
|
|
std::string vFeblFirmware = "Unknown";
|
|
std::string vFebrFirmware = "Unknown";
|
|
bool receiver = false;
|
|
std::string vReceiver = "Unknown";
|
|
|
|
std::string vRelease = det->getPackageVersion();
|
|
std::string vClient = det->getClientVersion();
|
|
|
|
if (det->size() != 0) {
|
|
// shared memory has detectors
|
|
vType = OutString(det->getDetectorType());
|
|
eiger = (det->getDetectorType().squash() == defs::EIGER);
|
|
receiver = det->getUseReceiverFlag().squash(false);
|
|
if (receiver) {
|
|
// cannot connect to receiver
|
|
try {
|
|
vReceiver = OutString(
|
|
det->getReceiverVersion(std::vector<int>{det_id}));
|
|
} catch (const std::exception &e) {
|
|
}
|
|
}
|
|
// cannot connect to Detector
|
|
try {
|
|
auto firmwareVersion =
|
|
det->getFirmwareVersion(std::vector<int>{det_id});
|
|
vFirmware = OutStringHex(firmwareVersion);
|
|
vServer = OutString(
|
|
det->getDetectorServerVersion(std::vector<int>{det_id}));
|
|
vKernel = OutString(
|
|
det->getKernelVersion({std::vector<int>{det_id}}));
|
|
vHardware = OutString(
|
|
det->getHardwareVersion(std::vector<int>{det_id}));
|
|
if (eiger) {
|
|
vBebFirmware = OutString(firmwareVersion);
|
|
vFeblFirmware = OutString(det->getFrontEndFirmwareVersion(
|
|
defs::FRONT_LEFT, std::vector<int>{det_id}));
|
|
vFebrFirmware = OutString(det->getFrontEndFirmwareVersion(
|
|
defs::FRONT_RIGHT, std::vector<int>{det_id}));
|
|
}
|
|
} catch (const std::exception &e) {
|
|
}
|
|
}
|
|
|
|
os << "\nType : " << vType
|
|
<< "\nRelease : " << vRelease
|
|
<< "\nClient : " << vClient;
|
|
if (eiger) {
|
|
os << "\nFirmware (Beb) : " << vBebFirmware
|
|
<< "\nFirmware (Febl) : " << vFeblFirmware
|
|
<< "\nFirmware (Febr) : " << vFebrFirmware;
|
|
} else {
|
|
os << "\nFirmware : " << vFirmware;
|
|
}
|
|
os << "\nServer : " << vServer
|
|
<< "\nKernel : " << vKernel
|
|
<< "\nHardware : " << vHardware;
|
|
if (receiver)
|
|
os << "\nReceiver : " << vReceiver;
|
|
os << std::dec << '\n';
|
|
|
|
} else if (action == defs::PUT_ACTION) {
|
|
throw RuntimeError("cannot put");
|
|
} else {
|
|
throw RuntimeError("Unknown action");
|
|
}
|
|
return os.str();
|
|
}
|
|
std::string Caller::threshold(int action) {
|
|
std::ostringstream os;
|
|
if (action == defs::HELP_ACTION) {
|
|
os << "[eV] [(optinal settings)"
|
|
"\n\t[Eiger][Mythen3] Threshold in eV. It loads trim files from "
|
|
"settingspath.";
|
|
if (cmd == "thresholdnotb") {
|
|
os << "Trimbits are not loaded.";
|
|
}
|
|
os << "\n\t" << cmd
|
|
<< " [eV1] [eV2] [eV3] [(optional settings)]"
|
|
"\n\t[Mythen3] Threshold in eV for each counter. It loads trim "
|
|
"files from settingspath. An energy of -1 will pick up values "
|
|
" from detector.";
|
|
if (cmd == "thresholdnotb") {
|
|
os << "Trimbits are not loaded.";
|
|
}
|
|
os << '\n';
|
|
} else if (action == defs::GET_ACTION) {
|
|
if (cmd == "thresholdnotb") {
|
|
throw RuntimeError("cannot get");
|
|
}
|
|
if (!args.empty()) {
|
|
WrongNumberOfParameters(0);
|
|
}
|
|
defs::detectorType type = det->getDetectorType().squash();
|
|
if (type == defs::EIGER) {
|
|
auto t = det->getThresholdEnergy(std::vector<int>{det_id});
|
|
os << OutString(t) << '\n';
|
|
} else if (type == defs::MYTHEN3) {
|
|
auto t = det->getAllThresholdEnergy(std::vector<int>{det_id});
|
|
os << OutString(t) << '\n';
|
|
} else {
|
|
throw RuntimeError("Not implemented for this detector\n");
|
|
}
|
|
} else if (action == defs::PUT_ACTION) {
|
|
defs::detectorType type = det->getDetectorType().squash();
|
|
if (type == defs::EIGER && args.size() != 1 && args.size() != 2) {
|
|
WrongNumberOfParameters(1);
|
|
}
|
|
if (type == defs::MYTHEN3 && (args.size() < 1 || args.size() > 4)) {
|
|
WrongNumberOfParameters(1);
|
|
}
|
|
|
|
bool trimbits = (cmd == "thresholdnotb") ? false : true;
|
|
std::array<int, 3> energy = {StringTo<int>(args[0]), 0, 0};
|
|
energy[1] = energy[0];
|
|
energy[2] = energy[0];
|
|
defs::detectorSettings sett = defs::STANDARD;
|
|
|
|
// check if argument has settings or get it
|
|
if (args.size() == 2 || args.size() == 4) {
|
|
sett = StringTo<defs::detectorSettings>(args[args.size() - 1]);
|
|
} else {
|
|
sett = det->getSettings(std::vector<int>{det_id})
|
|
.tsquash("Inconsistent settings between detectors");
|
|
}
|
|
|
|
// get other threshold values
|
|
if (args.size() > 2) {
|
|
energy[1] = StringTo<int>(args[1]);
|
|
energy[2] = StringTo<int>(args[2]);
|
|
}
|
|
switch (type) {
|
|
case defs::EIGER:
|
|
det->setThresholdEnergy(energy[0], sett, trimbits,
|
|
std::vector<int>{det_id});
|
|
break;
|
|
case defs::MYTHEN3:
|
|
det->setThresholdEnergy(energy, sett, trimbits,
|
|
std::vector<int>{det_id});
|
|
break;
|
|
default:
|
|
throw RuntimeError("Not implemented for this detector\n");
|
|
}
|
|
os << ToString(args) << '\n';
|
|
} else {
|
|
throw RuntimeError("Unknown action");
|
|
}
|
|
return os.str();
|
|
}
|
|
|
|
std::string Caller::trimen(int action) {
|
|
std::ostringstream os;
|
|
if (action == defs::HELP_ACTION) {
|
|
os << "[trim_ev1] [trim_Ev2 (optional)] [trim_ev3 (optional)] "
|
|
"...\n\t[Eiger][Mythen3] list of trim energies, where "
|
|
"corresponding default trim files exist in corresponding trim "
|
|
"folders."
|
|
<< '\n';
|
|
} else if (action == defs::GET_ACTION) {
|
|
if (!args.empty()) {
|
|
WrongNumberOfParameters(0);
|
|
}
|
|
auto t = det->getTrimEnergies(std::vector<int>{det_id});
|
|
os << OutString(t) << '\n';
|
|
} else if (action == defs::PUT_ACTION) {
|
|
std::vector<int> t(args.size());
|
|
if (!args.empty()) {
|
|
for (size_t i = 0; i < t.size(); ++i) {
|
|
t[i] = StringTo<int>(args[i]);
|
|
}
|
|
}
|
|
det->setTrimEnergies(t, std::vector<int>{det_id});
|
|
os << ToString(args) << '\n';
|
|
} else {
|
|
throw RuntimeError("Unknown action");
|
|
}
|
|
return os.str();
|
|
}
|
|
std::string Caller::badchannels(int action) {
|
|
std::ostringstream os;
|
|
if (action == defs::HELP_ACTION) {
|
|
os << "[fname|none|0]\n\t[Gotthard2][Mythen3] Sets the bad channels "
|
|
"(from file of bad channel numbers) to be masked out. None or 0 "
|
|
"unsets all the badchannels.\n\t[Mythen3] Also does trimming"
|
|
<< '\n';
|
|
} else if (action == defs::GET_ACTION) {
|
|
if (args.size() != 1) {
|
|
WrongNumberOfParameters(1);
|
|
}
|
|
det->getBadChannels(args[0], std::vector<int>{det_id});
|
|
os << "successfully retrieved" << '\n';
|
|
} else if (action == defs::PUT_ACTION) {
|
|
bool parse = false;
|
|
if (args.size() == 0) {
|
|
WrongNumberOfParameters(1);
|
|
} else if (args.size() == 1) {
|
|
if (args[0] == "none" || args[0] == "0") {
|
|
det->setBadChannels(std::vector<int>{},
|
|
std::vector<int>{det_id});
|
|
} else if (args[0].find(".") != std::string::npos) {
|
|
det->setBadChannels(args[0], std::vector<int>{det_id});
|
|
} else {
|
|
parse = true;
|
|
}
|
|
}
|
|
// parse multi args or single one with range or single value
|
|
if (parse || args.size() > 1) {
|
|
// get channels
|
|
auto list = getChannelsFromStringList(args);
|
|
det->setBadChannels(list, std::vector<int>{det_id});
|
|
}
|
|
os << "successfully loaded" << '\n';
|
|
} else {
|
|
throw RuntimeError("Unknown action");
|
|
}
|
|
return os.str();
|
|
}
|
|
std::string Caller::udp_srcip(int action) {
|
|
std::ostringstream os;
|
|
if (action == defs::HELP_ACTION) {
|
|
os << "[x.x.x.x] or auto\n\tIp address of the detector (source) udp "
|
|
"interface. Must be same subnet as destination udp "
|
|
"ip.\n\t[Eiger] Set only for 10G. For 1G, detector will replace "
|
|
"with its own DHCP IP address. \n\tOne can also set this to "
|
|
"'auto' for 1 GbE data and virtual detectors. It will set to IP "
|
|
"of detector."
|
|
<< '\n';
|
|
} else if (action == defs::GET_ACTION) {
|
|
auto t = det->getSourceUDPIP(std::vector<int>{det_id});
|
|
if (!args.empty()) {
|
|
WrongNumberOfParameters(0);
|
|
}
|
|
os << OutString(t) << '\n';
|
|
} else if (action == defs::PUT_ACTION) {
|
|
if (args.size() != 1) {
|
|
WrongNumberOfParameters(1);
|
|
}
|
|
IpAddr val;
|
|
if (args[0] == "auto") {
|
|
val = getSrcIpFromAuto();
|
|
LOG(logINFO) << "Setting udp_srcip of detector " << det_id << " to "
|
|
<< val;
|
|
} else {
|
|
val = IpAddr(args[0]);
|
|
}
|
|
det->setSourceUDPIP(val, std::vector<int>{det_id});
|
|
os << val << '\n';
|
|
|
|
} else {
|
|
throw RuntimeError("Unknown action");
|
|
}
|
|
return os.str();
|
|
}
|
|
std::string Caller::udp_srcip2(int action) {
|
|
std::ostringstream os;
|
|
if (action == defs::HELP_ACTION) {
|
|
os << "[x.x.x.x] or auto\n\t[Jungfrau][Moench][Gotthard2] Ip address "
|
|
"of the "
|
|
"detector (source) udp interface 2. Must be same subnet as "
|
|
"destination udp ip2.\n\t [Jungfrau][Moench] top half or inner "
|
|
"interface\n\t [Gotthard2] veto debugging. \n\tOne can also set "
|
|
"this to 'auto' for 1 GbE data and virtual detectors. It will "
|
|
"set to IP of detector."
|
|
<< '\n';
|
|
} else if (action == defs::GET_ACTION) {
|
|
auto t = det->getSourceUDPIP2(std::vector<int>{det_id});
|
|
if (!args.empty()) {
|
|
WrongNumberOfParameters(0);
|
|
}
|
|
os << OutString(t) << '\n';
|
|
} else if (action == defs::PUT_ACTION) {
|
|
if (args.size() != 1) {
|
|
WrongNumberOfParameters(1);
|
|
}
|
|
IpAddr val;
|
|
if (args[0] == "auto") {
|
|
val = getSrcIpFromAuto();
|
|
LOG(logINFO) << "Setting udp_srcip2 of detector " << det_id
|
|
<< " to " << val;
|
|
} else {
|
|
val = IpAddr(args[0]);
|
|
}
|
|
det->setSourceUDPIP2(val, std::vector<int>{det_id});
|
|
os << val << '\n';
|
|
|
|
} else {
|
|
throw RuntimeError("Unknown action");
|
|
}
|
|
return os.str();
|
|
}
|
|
std::string Caller::udp_dstip(int action) {
|
|
std::ostringstream os;
|
|
if (action == defs::HELP_ACTION) {
|
|
os << "[x.x.x.x] or auto\n\tIp address of the receiver (destination) "
|
|
"udp interface. If 'auto' used, then ip is set to ip of "
|
|
"rx_hostname."
|
|
<< '\n';
|
|
} else if (action == defs::GET_ACTION) {
|
|
auto t = det->getDestinationUDPIP(std::vector<int>{det_id});
|
|
if (!args.empty()) {
|
|
WrongNumberOfParameters(0);
|
|
}
|
|
os << OutString(t) << '\n';
|
|
} else if (action == defs::PUT_ACTION) {
|
|
if (args.size() != 1) {
|
|
WrongNumberOfParameters(1);
|
|
}
|
|
if (args[0] == "auto") {
|
|
auto val = getDstIpFromAuto();
|
|
LOG(logINFO) << "Setting udp_dstip of detector " << det_id << " to "
|
|
<< val;
|
|
det->setDestinationUDPIP(val, std::vector<int>{det_id});
|
|
os << val << '\n';
|
|
} else {
|
|
auto val = IpAddr(args[0]);
|
|
det->setDestinationUDPIP(val, std::vector<int>{det_id});
|
|
os << args.front() << '\n';
|
|
}
|
|
} else {
|
|
throw RuntimeError("Unknown action");
|
|
}
|
|
return os.str();
|
|
}
|
|
std::string Caller::udp_dstip2(int action) {
|
|
std::ostringstream os;
|
|
if (action == defs::HELP_ACTION) {
|
|
os << "[x.x.x.x] or auto\n\t[Jungfrau][Moench][Gotthard2] Ip address "
|
|
"of the "
|
|
"receiver (destination) udp interface 2. If 'auto' used, then ip "
|
|
"is set to ip of rx_hostname.\n\t[Jungfrau][Moench] bottom half "
|
|
"\n\t[Gotthard2] veto debugging. "
|
|
<< '\n';
|
|
} else if (action == defs::GET_ACTION) {
|
|
auto t = det->getDestinationUDPIP2(std::vector<int>{det_id});
|
|
if (!args.empty()) {
|
|
WrongNumberOfParameters(0);
|
|
}
|
|
os << OutString(t) << '\n';
|
|
} else if (action == defs::PUT_ACTION) {
|
|
if (args.size() != 1) {
|
|
WrongNumberOfParameters(1);
|
|
}
|
|
if (args[0] == "auto") {
|
|
auto val = getDstIpFromAuto();
|
|
LOG(logINFO) << "Setting udp_dstip2 of detector " << det_id
|
|
<< " to " << val;
|
|
det->setDestinationUDPIP2(val, std::vector<int>{det_id});
|
|
os << val << '\n';
|
|
} else {
|
|
auto val = IpAddr(args[0]);
|
|
det->setDestinationUDPIP2(val, std::vector<int>{det_id});
|
|
os << args.front() << '\n';
|
|
}
|
|
} else {
|
|
throw RuntimeError("Unknown action");
|
|
}
|
|
return os.str();
|
|
}
|
|
std::string Caller::rx_hostname(int action) {
|
|
std::ostringstream os;
|
|
if (action == defs::HELP_ACTION) {
|
|
os << "[hostname or ip address]\n\t"
|
|
"[hostname or ip address]:[tcp port]\n\t"
|
|
"[hostname1]:[tcp_port1]+[hostname2]:[tcp_port2]+\n\t"
|
|
"Receiver hostname or IP. If port included, then the receiver "
|
|
"tcp port.\n\t"
|
|
"Used for TCP control communication between client and receiver "
|
|
"to configure receiver. Also updates receiver with detector "
|
|
"parameters. Also resets any prior receiver property (not on "
|
|
"detector). "
|
|
<< '\n';
|
|
} else if (action == defs::GET_ACTION) {
|
|
if (!args.empty()) {
|
|
WrongNumberOfParameters(0);
|
|
}
|
|
auto t = det->getRxHostname(std::vector<int>{det_id});
|
|
os << OutString(t) << '\n';
|
|
} else if (action == defs::PUT_ACTION) {
|
|
if (args.size() < 1) {
|
|
WrongNumberOfParameters(1);
|
|
}
|
|
// multiple arguments
|
|
if (args.size() > 1) {
|
|
// multiple in mulitple
|
|
if (args[0].find('+') != std::string::npos) {
|
|
throw RuntimeError(
|
|
"Cannot add multiple receivers at module level");
|
|
}
|
|
if (det_id != -1) {
|
|
throw RuntimeError(
|
|
"Cannot add multiple receivers at module level");
|
|
}
|
|
det->setRxHostname(args);
|
|
os << ToString(args) << '\n';
|
|
}
|
|
// single argument
|
|
else {
|
|
// multiple receivers concatenated with +
|
|
if (args[0].find('+') != std::string::npos) {
|
|
if (det_id != -1) {
|
|
throw RuntimeError(
|
|
"Cannot add multiple receivers at module level");
|
|
}
|
|
auto t = split(args[0], '+');
|
|
det->setRxHostname(t);
|
|
os << ToString(t) << '\n';
|
|
}
|
|
// single receiver
|
|
else {
|
|
det->setRxHostname(args[0], std::vector<int>{det_id});
|
|
os << ToString(args) << '\n';
|
|
}
|
|
}
|
|
} else {
|
|
throw RuntimeError("Unknown action");
|
|
}
|
|
return os.str();
|
|
}
|
|
std::string Caller::rx_zmqip(int action) {
|
|
std::string helpMessage =
|
|
"\n\t[deprecated] The receiver zmq socket (publisher) will "
|
|
"listen to all interfaces ('tcp://0.0.0.0:[port]'to all interfaces "
|
|
"(from v9.0.0). This command does nothing and will be removed "
|
|
"(from v10.0.0). This change makes no difference to the user.\n";
|
|
std::ostringstream os;
|
|
if (action == defs::HELP_ACTION) {
|
|
os << helpMessage << '\n';
|
|
} else if (action == defs::GET_ACTION) {
|
|
os << ZMQ_PUBLISHER_IP << '\n';
|
|
} else if (action == defs::PUT_ACTION) {
|
|
LOG(logWARNING) << helpMessage << '\n';
|
|
os << ZMQ_PUBLISHER_IP << '\n';
|
|
} else {
|
|
throw RuntimeError("Unknown action");
|
|
}
|
|
return os.str();
|
|
}
|
|
|
|
std::string Caller::rx_roi(int action) {
|
|
std::ostringstream os;
|
|
std::string helpMessage =
|
|
std::string("[xmin] [xmax] [ymin] [ymax]\n") +
|
|
"\tDefines a single region of interest (ROI) in the receiver.\n"
|
|
"\tFor example, to set a single ROI: 0 100 20 30\n\n"
|
|
|
|
"\tTo specify multiple ROIs, use square brackets between ROIs and "
|
|
"commas inside for each ROI. \n"
|
|
"\tInside each bracket, no spaces allowed.\n\n"
|
|
|
|
"\tIf you use semicolon (along with '['and ']' to separate rois), \n"
|
|
"\tenclose the entire list in quotes.\n"
|
|
"\tExamples:\n"
|
|
"\t [0,100,0,100] [200,300,0,100]\n"
|
|
"\t \"[0,100,0,100];[200,300,0,100]\"\n\n"
|
|
|
|
"\tNotes:\n"
|
|
"\t- ROIs can only be set at the multi-module level.\n"
|
|
"\t- If multi module ROIs ends up with more then 1 ROI per UDP "
|
|
"port or if they overlap each other, it will throw an error.\n"
|
|
"\t- ROIs coordinates assume no gap pixels, even if they are enabled "
|
|
"in gui.\n"
|
|
"\t- To retrieve ROIs per port, specify the module ID when using the "
|
|
"get command.\n"
|
|
"\t- Use the command 'rx_clearroi' to clear all ROIs.\n"
|
|
"\t- Changing the number of UDP interfaces will automatically clear "
|
|
"the current ROIs.\n\n"
|
|
"\t- Cannot be set for CTB or Xilinx CTB.\n";
|
|
|
|
if (action == defs::HELP_ACTION) {
|
|
os << helpMessage;
|
|
} else if (action == defs::GET_ACTION) {
|
|
if (!args.empty()) {
|
|
WrongNumberOfParameters(0);
|
|
}
|
|
auto t = det->getRxROI(det_id);
|
|
os << ToString(t) << '\n';
|
|
} else if (action == defs::PUT_ACTION) {
|
|
if (det_id != -1) {
|
|
throw RuntimeError("Cannot set receiver ROI at module level");
|
|
}
|
|
// Support multiple args with bracketed ROIs, or single arg with
|
|
// semicolon-separated vector in quotes
|
|
bool isVectorInput =
|
|
std::all_of(args.begin(), args.end(), [](const std::string &a) {
|
|
return a.find('[') != std::string::npos &&
|
|
a.find(']') != std::string::npos;
|
|
});
|
|
std::vector<defs::ROI> rois;
|
|
try {
|
|
// single roi in previous format: [xmin,xmax,ymin,ymax]
|
|
if (!isVectorInput) {
|
|
auto t = parseRoi(args);
|
|
rois.emplace_back(t);
|
|
}
|
|
// multiple roi or single roi with brackets
|
|
// multiple roi: multiple args with bracketed ROIs, or single arg
|
|
// with semicolon-bracketed Rois in quotes
|
|
else {
|
|
for (const auto &arg : args) {
|
|
auto subRois = parseRoiVector(arg);
|
|
rois.insert(rois.end(), subRois.begin(), subRois.end());
|
|
}
|
|
}
|
|
} catch (const std::exception &e) {
|
|
throw RuntimeError("Could not parse ROI: Did you use spaces inside "
|
|
"the brackets? Use sls_detector_help " +
|
|
cmd + " to get the right syntax expected.");
|
|
}
|
|
|
|
det->setRxROI(rois);
|
|
os << ToString(rois) << '\n';
|
|
} else {
|
|
throw RuntimeError("Unknown action");
|
|
}
|
|
return os.str();
|
|
}
|
|
|
|
std::vector<defs::ROI> Caller::parseRoiVector(const std::string &input) {
|
|
std::vector<defs::ROI> rois;
|
|
std::stringstream ss(input);
|
|
std::string token;
|
|
|
|
while (std::getline(ss, token, ']')) {
|
|
// remove spaces and semicolons
|
|
token.erase(
|
|
std::remove_if(token.begin(), token.end(),
|
|
[](char c) { return std::isspace(c) || c == ';'; }),
|
|
token.end());
|
|
if (token.empty())
|
|
continue;
|
|
if (token.front() != '[') {
|
|
throw RuntimeError("Each ROI must be enclosed in square brackets: "
|
|
"[xmin,xmax,ymin,ymax]");
|
|
}
|
|
token = token.substr(1, token.size() - 1); // remove brackets
|
|
std::vector<std::string> parts;
|
|
std::stringstream inner(token);
|
|
std::string num;
|
|
while (std::getline(inner, num, ',')) {
|
|
parts.push_back(num);
|
|
}
|
|
|
|
auto roi = parseRoi(parts);
|
|
rois.emplace_back(roi);
|
|
}
|
|
return rois;
|
|
}
|
|
|
|
defs::ROI Caller::parseRoi(const std::vector<std::string> &parts) {
|
|
if (parts.size() != 2 && parts.size() != 4) {
|
|
throw RuntimeError(
|
|
"Could not parse ROI. A ROI must have 2 or 4 integers");
|
|
}
|
|
|
|
defs::ROI roi;
|
|
roi.xmin = StringTo<int>(parts[0]);
|
|
roi.xmax = StringTo<int>(parts[1]);
|
|
if (parts.size() == 4) {
|
|
roi.ymin = StringTo<int>(parts[2]);
|
|
roi.ymax = StringTo<int>(parts[3]);
|
|
}
|
|
return roi;
|
|
}
|
|
|
|
std::string Caller::ratecorr(int action) {
|
|
std::ostringstream os;
|
|
if (action == defs::HELP_ACTION) {
|
|
os << "[n_rate (in ns)]\n\t[Eiger] Dead time correction constant in "
|
|
"ns. -1 will set to default tau of settings from trimbit file. 0 "
|
|
"will unset rate correction."
|
|
<< '\n';
|
|
} else if (action == defs::GET_ACTION) {
|
|
if (!args.empty()) {
|
|
WrongNumberOfParameters(0);
|
|
}
|
|
auto t = det->getRateCorrection(std::vector<int>{det_id});
|
|
os << OutString(t) << '\n';
|
|
} else if (action == defs::PUT_ACTION) {
|
|
if (args.size() != 1) {
|
|
WrongNumberOfParameters(1);
|
|
}
|
|
int tau = StringTo<int>(args[0]);
|
|
if (tau == -1) {
|
|
det->setDefaultRateCorrection(std::vector<int>{det_id});
|
|
auto t = det->getRateCorrection(std::vector<int>{det_id});
|
|
os << OutString(t) << '\n';
|
|
} else {
|
|
auto t = StringTo<time::ns>(args[0], "ns");
|
|
det->setRateCorrection(t, std::vector<int>{det_id});
|
|
os << args.front() << "ns\n";
|
|
}
|
|
} else {
|
|
throw RuntimeError("Unknown action");
|
|
}
|
|
return os.str();
|
|
}
|
|
std::string Caller::burstmode(int action) {
|
|
std::ostringstream os;
|
|
if (action == defs::HELP_ACTION) {
|
|
os << "[burst_internal or 0, burst_external or 1, cw_internal or 2, "
|
|
"cw_external or 3]\n\t[Gotthard2] Default is burst_internal "
|
|
"type. Also changes clkdiv 2, 3, 4"
|
|
<< '\n';
|
|
} else {
|
|
if (action == defs::GET_ACTION) {
|
|
if (!args.empty()) {
|
|
WrongNumberOfParameters(0);
|
|
}
|
|
auto t = det->getBurstMode(std::vector<int>{det_id});
|
|
os << OutString(t) << '\n';
|
|
} else if (action == defs::PUT_ACTION) {
|
|
if (args.size() != 1) {
|
|
WrongNumberOfParameters(1);
|
|
}
|
|
defs::burstMode t;
|
|
try {
|
|
int ival = StringTo<int>(args[0]);
|
|
switch (ival) {
|
|
case 0:
|
|
t = defs::BURST_INTERNAL;
|
|
break;
|
|
case 1:
|
|
t = defs::BURST_EXTERNAL;
|
|
break;
|
|
case 2:
|
|
t = defs::CONTINUOUS_INTERNAL;
|
|
break;
|
|
case 3:
|
|
t = defs::CONTINUOUS_EXTERNAL;
|
|
break;
|
|
default:
|
|
throw RuntimeError("Unknown burst mode " + args[0]);
|
|
}
|
|
} catch (...) {
|
|
t = StringTo<defs::burstMode>(args[0]);
|
|
}
|
|
det->setBurstMode(t, std::vector<int>{det_id});
|
|
os << ToString(t) << '\n'; // no args to convert 0,1,2 as well
|
|
} else {
|
|
throw RuntimeError("Unknown action");
|
|
}
|
|
}
|
|
return os.str();
|
|
}
|
|
std::string Caller::vetostream(int action) {
|
|
std::ostringstream os;
|
|
if (action == defs::HELP_ACTION) {
|
|
os << "[none|lll|10gbe|...]\n\t[Gotthard2] Enable or disable the 2 "
|
|
"veto streaming interfaces available. Can include more than one "
|
|
"interface. \n\tDefault: none. lll (low latency link) is the "
|
|
"default interface to work with. \n\t10GbE is for debugging and "
|
|
"also enables second interface in receiver for listening to veto "
|
|
"packets (writes a separate file if writing enabled). Also "
|
|
"restarts client and receiver zmq sockets if zmq streaming "
|
|
"enabled."
|
|
<< '\n';
|
|
} else if (action == defs::GET_ACTION) {
|
|
if (!args.empty()) {
|
|
WrongNumberOfParameters(0);
|
|
}
|
|
auto t = det->getVetoStream(std::vector<int>{det_id});
|
|
os << OutString(t) << '\n';
|
|
} else if (action == defs::PUT_ACTION) {
|
|
if (args.empty()) {
|
|
WrongNumberOfParameters(1);
|
|
}
|
|
defs::streamingInterface interface = defs::streamingInterface::NONE;
|
|
for (const auto &arg : args) {
|
|
if (arg == "none") {
|
|
if (args.size() > 1) {
|
|
throw RuntimeError(
|
|
std::string(
|
|
"cannot have other arguments with 'none'. args: ") +
|
|
ToString(args));
|
|
}
|
|
break;
|
|
}
|
|
interface = interface | (StringTo<defs::streamingInterface>(arg));
|
|
}
|
|
det->setVetoStream(interface, std::vector<int>{det_id});
|
|
os << ToString(interface) << '\n';
|
|
} else {
|
|
throw RuntimeError("Unknown action");
|
|
}
|
|
return os.str();
|
|
}
|
|
std::string Caller::counters(int action) {
|
|
std::ostringstream os;
|
|
if (action == defs::HELP_ACTION) {
|
|
os << "[i0] [i1] [i2]... \n\t[Mythen3] List of counters indices "
|
|
"enabled. Each element in list can be 0 - 2 and must be non "
|
|
"repetitive. Enabling counters sets vth dacs to remembered "
|
|
"values and disabling sets them to disabled values."
|
|
<< '\n';
|
|
} else if (action == defs::GET_ACTION) {
|
|
if (!args.empty()) {
|
|
WrongNumberOfParameters(0);
|
|
}
|
|
auto mask = det->getCounterMask(std::vector<int>{det_id}).squash(-1);
|
|
os << ToString(getSetBits(mask)) << '\n';
|
|
} else if (action == defs::PUT_ACTION) {
|
|
if (args.empty()) {
|
|
WrongNumberOfParameters(1);
|
|
}
|
|
if (std::any_of(args.cbegin(), args.cend(), [](std::string s) {
|
|
return (StringTo<int>(s) < 0 || StringTo<int>(s) > 2);
|
|
})) {
|
|
throw RuntimeError("Invalid counter indices list. Example: 0 1 2");
|
|
}
|
|
// convert vector to counter enable mask
|
|
uint32_t mask = 0;
|
|
for (size_t i = 0; i < args.size(); ++i) {
|
|
int val = StringTo<int>(args[i]);
|
|
// already enabled earlier
|
|
if (mask & (1 << val)) {
|
|
std::ostringstream oss;
|
|
oss << "Duplicate counter values (" << val << ") in arguments";
|
|
throw RuntimeError(oss.str());
|
|
}
|
|
mask |= (1 << val);
|
|
}
|
|
det->setCounterMask(mask, std::vector<int>{det_id});
|
|
os << ToString(args) << '\n';
|
|
} else {
|
|
throw RuntimeError("Unknown action");
|
|
}
|
|
return os.str();
|
|
}
|
|
std::string Caller::samples(int action) {
|
|
std::ostringstream os;
|
|
if (action == defs::HELP_ACTION) {
|
|
os << "[n_samples]\n\t[Ctb][Xilinx_Ctb] Number of samples (analog, "
|
|
"digitial and "
|
|
"transceiver) expected.\n"
|
|
<< '\n';
|
|
} else if (action == defs::GET_ACTION) {
|
|
if (!args.empty()) {
|
|
WrongNumberOfParameters(0);
|
|
}
|
|
auto a = det->getNumberOfAnalogSamples(std::vector<int>{det_id});
|
|
// get also digital samples for ctb and compare with analog
|
|
auto det_type = det->getDetectorType().squash(defs::GENERIC);
|
|
if (det_type == defs::CHIPTESTBOARD ||
|
|
det_type == defs::XILINX_CHIPTESTBOARD) {
|
|
auto d = det->getNumberOfDigitalSamples(std::vector<int>{det_id});
|
|
auto t =
|
|
det->getNumberOfTransceiverSamples(std::vector<int>{det_id});
|
|
int as = a.squash(-1);
|
|
int ds = d.squash(-1);
|
|
int ts = t.squash(-1);
|
|
if (as == -1 || ds == -1 || ts == -1 || as != ds ||
|
|
as != ts) { // check if a == d?
|
|
throw RuntimeError(
|
|
"Different samples. Use asamples, dsamples or tsamples.");
|
|
}
|
|
}
|
|
os << OutString(a) << '\n';
|
|
} else if (action == defs::PUT_ACTION) {
|
|
if (args.size() != 1) {
|
|
WrongNumberOfParameters(1);
|
|
}
|
|
det->setNumberOfAnalogSamples(StringTo<int>(args[0]),
|
|
std::vector<int>{det_id});
|
|
// set also digital samples for ctb
|
|
auto det_type = det->getDetectorType().squash(defs::GENERIC);
|
|
if (det_type == defs::CHIPTESTBOARD ||
|
|
det_type == defs::XILINX_CHIPTESTBOARD) {
|
|
det->setNumberOfDigitalSamples(StringTo<int>(args[0]),
|
|
std::vector<int>{det_id});
|
|
det->setNumberOfTransceiverSamples(StringTo<int>(args[0]),
|
|
std::vector<int>{det_id});
|
|
}
|
|
os << args.front() << '\n';
|
|
} else {
|
|
throw RuntimeError("Unknown action");
|
|
}
|
|
return os.str();
|
|
}
|
|
std::string Caller::slowadc(int action) {
|
|
std::ostringstream os;
|
|
if (action == defs::HELP_ACTION) {
|
|
os << "[n_channel (0-7 for channel]\n\t[Ctb] Slow "
|
|
"ADC channel in mV"
|
|
<< '\n';
|
|
} else if (action == defs::GET_ACTION) {
|
|
if (args.size() != 1) {
|
|
WrongNumberOfParameters(0);
|
|
}
|
|
int nchan = StringTo<int>(args[0]);
|
|
if (nchan < 0 || nchan > 7) {
|
|
throw RuntimeError("Unknown adc argument " + args[0]);
|
|
}
|
|
auto t = det->getSlowADC(
|
|
static_cast<defs::dacIndex>(nchan + defs::SLOW_ADC0),
|
|
std::vector<int>{det_id});
|
|
Result<double> result(t.size());
|
|
for (unsigned int i = 0; i < t.size(); ++i) {
|
|
result[i] = t[i] / 1000.00;
|
|
}
|
|
os << OutString(result) << " mV\n";
|
|
|
|
} else if (action == defs::PUT_ACTION) {
|
|
throw RuntimeError("cannot put");
|
|
} else {
|
|
throw RuntimeError("Unknown action");
|
|
}
|
|
return os.str();
|
|
}
|
|
std::string Caller::patwaittime(int action) {
|
|
std::ostringstream os;
|
|
|
|
if (action == defs::HELP_ACTION) {
|
|
os << "[0-6] [n_clk] \n\t[Ctb][Mythen3][Xilinx Ctb] Wait time in clock "
|
|
"cycles for the loop provided.\n\t[Mythen3] Level options: 0-3 "
|
|
"only."
|
|
<< '\n';
|
|
return os.str();
|
|
}
|
|
|
|
// parse level
|
|
bool deprecated_cmd = GetLevelAndInsertIntoArgs("patwaittime");
|
|
int level = 0;
|
|
try {
|
|
if (args.size() > 0)
|
|
level = StringTo<int>(args[0]);
|
|
} catch (const std::exception &e) {
|
|
LOG(logERROR) << "Could not scan level.";
|
|
throw;
|
|
}
|
|
if (!deprecated_cmd && args.size() >= 1)
|
|
os << args[0] << ' ';
|
|
|
|
if (action == defs::GET_ACTION) {
|
|
if (args.size() != 1 && args.size() != 2)
|
|
WrongNumberOfParameters(1);
|
|
// with time unit
|
|
if (args.size() == 2) {
|
|
auto t =
|
|
det->getPatternWaitInterval(level, std::vector<int>{det_id});
|
|
os << OutString(t, args[1]) << '\n';
|
|
}
|
|
// in clocks
|
|
else {
|
|
auto t = det->getPatternWaitClocks(level, std::vector<int>{det_id});
|
|
os << OutString(t) << '\n';
|
|
}
|
|
} else if (action == defs::PUT_ACTION) {
|
|
if (args.size() != 2 && args.size() != 3)
|
|
WrongNumberOfParameters(2);
|
|
// clocks (all digits)
|
|
if (args.size() == 2 &&
|
|
std::all_of(args[1].begin(), args[1].end(), ::isdigit)) {
|
|
uint64_t waittime = StringTo<uint64_t>(args[1]);
|
|
det->setPatternWaitClocks(level, waittime,
|
|
std::vector<int>{det_id});
|
|
os << waittime << '\n';
|
|
}
|
|
// time
|
|
else {
|
|
time::ns converted_time{0};
|
|
try {
|
|
if (args.size() == 2) {
|
|
std::string tmp_time(args[1]);
|
|
std::string unit = RemoveUnit(tmp_time);
|
|
converted_time = StringTo<time::ns>(tmp_time, unit);
|
|
} else {
|
|
converted_time = StringTo<time::ns>(args[1], args[2]);
|
|
}
|
|
} catch (...) {
|
|
throw RuntimeError("Could not convert argument to time::ns");
|
|
}
|
|
det->setPatternWaitInterval(level, converted_time,
|
|
std::vector<int>{det_id});
|
|
os << args[1];
|
|
if (args.size() == 3)
|
|
os << ' ' << args[2];
|
|
os << '\n';
|
|
}
|
|
} else {
|
|
throw RuntimeError("Unknown action");
|
|
}
|
|
return os.str();
|
|
}
|
|
std::string Caller::rx_dbitlist(int action) {
|
|
std::ostringstream os;
|
|
if (action == defs::HELP_ACTION) {
|
|
os << "[all] or [none] or [i0] [i1] [i2]... \n\t[Ctb] List of digital "
|
|
"signal bits enabled and rearranged according to the signals "
|
|
"(all samples of each signal is put together). If 'all' is used "
|
|
"instead of a list, all digital bits (64) enabled. Each element "
|
|
"in list can be 0 - 63 and must be non repetitive. The option "
|
|
"'none' will still spit out all data as is from the detector, "
|
|
"but without rearranging it. Please note that when using the "
|
|
"receiver list, the data size will be bigger if the number of "
|
|
"samples is not divisible by 8 as every signal bit is padded to "
|
|
"the next byte when combining all the samples in the receiver."
|
|
<< '\n';
|
|
} else if (action == defs::GET_ACTION) {
|
|
if (!args.empty()) {
|
|
WrongNumberOfParameters(0);
|
|
}
|
|
auto t = det->getRxDbitList(std::vector<int>{det_id});
|
|
os << OutString(t) << '\n';
|
|
} else if (action == defs::PUT_ACTION) {
|
|
if (args.empty()) {
|
|
WrongNumberOfParameters(1);
|
|
}
|
|
std::vector<int> t;
|
|
if (args[0] == "all") {
|
|
t.resize(64);
|
|
for (unsigned int i = 0; i < 64; ++i) {
|
|
t[i] = i;
|
|
}
|
|
}
|
|
// 'none' option already covered as t is empty by default
|
|
else if (args[0] != "none") {
|
|
unsigned int ntrim = args.size();
|
|
t.resize(ntrim);
|
|
for (unsigned int i = 0; i < ntrim; ++i) {
|
|
t[i] = StringTo<int>(args[i]);
|
|
}
|
|
}
|
|
det->setRxDbitList(t, std::vector<int>{det_id});
|
|
os << ToString(args) << '\n';
|
|
} else {
|
|
throw RuntimeError("Unknown action");
|
|
}
|
|
return os.str();
|
|
}
|
|
std::string Caller::rx_jsonaddheader(int action) {
|
|
std::ostringstream os;
|
|
if (action == defs::HELP_ACTION) {
|
|
os << "[key1] [value1] [key2] [value2]...[keyn] [valuen]\n\tAdditional "
|
|
"json header to be streamed out from receiver via zmq. Default "
|
|
"is empty. Max 20 characters for each key/value. Use only if to "
|
|
"be processed by an intermediate user process listening to "
|
|
"receiver zmq packets. Empty value deletes header. "
|
|
<< '\n';
|
|
} else if (action == defs::GET_ACTION) {
|
|
if (!args.empty()) {
|
|
WrongNumberOfParameters(0);
|
|
}
|
|
auto t = det->getAdditionalJsonHeader(std::vector<int>{det_id});
|
|
os << OutString(t) << '\n';
|
|
} else if (action == defs::PUT_ACTION) {
|
|
// arguments can be empty
|
|
std::map<std::string, std::string> json;
|
|
for (size_t i = 0; i < args.size(); i = i + 2) {
|
|
// last value is empty
|
|
if (i + 1 >= args.size()) {
|
|
json[args[i]] = "";
|
|
} else {
|
|
json[args[i]] = args[i + 1];
|
|
}
|
|
}
|
|
det->setAdditionalJsonHeader(json, std::vector<int>{det_id});
|
|
os << ToString(json) << '\n';
|
|
} else {
|
|
throw RuntimeError("Unknown action");
|
|
}
|
|
return os.str();
|
|
}
|
|
std::string Caller::execcommand(int action) {
|
|
std::ostringstream os;
|
|
if (action == defs::HELP_ACTION) {
|
|
os << "[command]\n\tExecutes command on detector server console."
|
|
<< '\n';
|
|
} else if (action == defs::GET_ACTION) {
|
|
throw RuntimeError("Cannot get.");
|
|
} else if (action == defs::PUT_ACTION) {
|
|
std::string command;
|
|
for (auto &i : args) {
|
|
command += (i + ' ');
|
|
}
|
|
auto t = det->executeCommand(command, std::vector<int>{det_id});
|
|
os << OutString(t) << '\n';
|
|
} else {
|
|
throw RuntimeError("Unknown action");
|
|
}
|
|
return os.str();
|
|
}
|
|
std::string Caller::dacvalues(int action) {
|
|
std::ostringstream os;
|
|
if (action == defs::HELP_ACTION) {
|
|
os << "[(optional unit) mV] \n\tGets the values for every "
|
|
"dac for this detector."
|
|
<< '\n';
|
|
} else if (action == defs::GET_ACTION) {
|
|
bool mv = false;
|
|
if (args.size() == 1) {
|
|
if ((args[0] != "mv") && (args[0] != "mV")) {
|
|
throw RuntimeError("Unknown argument " + args[0] +
|
|
". Did you mean mV?");
|
|
}
|
|
mv = true;
|
|
} else if (args.size() > 1) {
|
|
WrongNumberOfParameters(1);
|
|
}
|
|
auto t = det->getDacList();
|
|
auto names = det->getDacNames();
|
|
auto name_it = names.begin();
|
|
os << '[';
|
|
auto it = t.cbegin();
|
|
os << ToString(*name_it++) << ' ';
|
|
os << OutString(det->getDAC(*it++, mv, std::vector<int>{det_id}))
|
|
<< (!args.empty() ? " mV" : "");
|
|
while (it != t.cend()) {
|
|
os << ", " << ToString(*name_it++) << ' ';
|
|
os << OutString(det->getDAC(*it++, mv, std::vector<int>{det_id}))
|
|
<< (!args.empty() ? " mV" : "");
|
|
}
|
|
os << "]\n";
|
|
} else if (action == defs::PUT_ACTION) {
|
|
throw RuntimeError("Cannot put");
|
|
} else {
|
|
throw RuntimeError("Unknown action");
|
|
}
|
|
return os.str();
|
|
}
|
|
std::string Caller::currentsource(int action) {
|
|
std::ostringstream os;
|
|
if (action == defs::HELP_ACTION) {
|
|
os << "\n\t[0|1]\n\t\t[Gotthard2] Enable or disable current source. "
|
|
"Default "
|
|
"is disabled.\n\t[0|1] [fix|nofix] [select source] [(only for "
|
|
"chipv1.1)normal|low]\n\t\t[Jungfrau] Disable or enable current "
|
|
"source with some parameters. The select source is 0-63 for "
|
|
"chipv1.0 and a 64 bit mask for chipv1.1. To disable, one needs "
|
|
"only one argument '0'."
|
|
<< '\n';
|
|
} else if (action == defs::GET_ACTION) {
|
|
if (args.size() != 0) {
|
|
WrongNumberOfParameters(0);
|
|
}
|
|
auto t = det->getCurrentSource(std::vector<int>{det_id});
|
|
os << OutString(t) << '\n';
|
|
} else if (action == defs::PUT_ACTION) {
|
|
if (args.size() == 1) {
|
|
det->setCurrentSource(
|
|
defs::currentSrcParameters(StringTo<bool>(args[0])));
|
|
} else if (args.size() >= 3) {
|
|
// scan fix
|
|
bool fix = false;
|
|
if (args[1] == "fix") {
|
|
fix = true;
|
|
} else if (args[1] == "nofix") {
|
|
fix = false;
|
|
} else {
|
|
throw RuntimeError("Invalid argument: " + args[1] +
|
|
". Did you mean fix or nofix?");
|
|
}
|
|
if (args.size() == 3) {
|
|
det->setCurrentSource(defs::currentSrcParameters(
|
|
fix, StringTo<uint64_t>(args[2])));
|
|
} else if (args.size() == 4) {
|
|
bool normalCurrent = false;
|
|
if (args[3] == "normal") {
|
|
normalCurrent = true;
|
|
} else if (args[3] == "low") {
|
|
normalCurrent = false;
|
|
} else {
|
|
throw RuntimeError("Invalid argument: " + args[3] +
|
|
". Did you mean normal or low?");
|
|
}
|
|
det->setCurrentSource(defs::currentSrcParameters(
|
|
fix, StringTo<uint64_t>(args[2]), normalCurrent));
|
|
} else {
|
|
throw RuntimeError(
|
|
"Invalid number of parareters for this command.");
|
|
}
|
|
} else {
|
|
throw RuntimeError(
|
|
"Invalid number of parareters for this command.");
|
|
}
|
|
os << ToString(args) << '\n';
|
|
} else {
|
|
throw RuntimeError("Unknown action");
|
|
}
|
|
return os.str();
|
|
}
|
|
std::string Caller::gaincaps(int action) {
|
|
std::ostringstream os;
|
|
if (action == defs::HELP_ACTION) {
|
|
os << "[cap1, cap2, ...]\n\t[Mythen3] gain, options: C10pre, C15sh, "
|
|
"C30sh, C50sh, C225ACsh, C15pre"
|
|
<< '\n';
|
|
} else if (action == defs::GET_ACTION) {
|
|
if (!args.empty())
|
|
WrongNumberOfParameters(0);
|
|
|
|
auto tmp = det->getGainCaps();
|
|
Result<defs::M3_GainCaps> csr;
|
|
for (auto val : tmp) {
|
|
if (val)
|
|
csr.push_back(static_cast<defs::M3_GainCaps>(val));
|
|
}
|
|
|
|
os << OutString(csr) << '\n';
|
|
} else if (action == defs::PUT_ACTION) {
|
|
if (args.size() < 1) {
|
|
WrongNumberOfParameters(1);
|
|
}
|
|
int caps = 0;
|
|
for (const auto &arg : args) {
|
|
if (arg != "0")
|
|
caps |= StringTo<defs::M3_GainCaps>(arg);
|
|
}
|
|
|
|
det->setGainCaps(caps);
|
|
os << OutString(args) << '\n';
|
|
} else {
|
|
throw RuntimeError("Unknown action");
|
|
}
|
|
return os.str();
|
|
}
|
|
std::string Caller::sleep(int action) {
|
|
std::ostringstream os;
|
|
if (action == defs::HELP_ACTION) {
|
|
os << "[duration] [(optional unit) ns|us|ms|s]\n\tSleep for duration. "
|
|
"Mainly for config files for firmware developers."
|
|
"Default unit is s."
|
|
<< '\n';
|
|
} else if (action == defs::GET_ACTION) {
|
|
throw RuntimeError("Cannot get.");
|
|
} else if (action == defs::PUT_ACTION) {
|
|
if (args.size() != 1 && args.size() != 2) {
|
|
WrongNumberOfParameters(1);
|
|
}
|
|
time::ns converted_time{0};
|
|
try {
|
|
if (args.size() == 1) {
|
|
std::string tmp_time(args[0]);
|
|
std::string unit = RemoveUnit(tmp_time);
|
|
converted_time = StringTo<time::ns>(tmp_time, unit);
|
|
} else {
|
|
converted_time = StringTo<time::ns>(args[0], args[1]);
|
|
}
|
|
} catch (...) {
|
|
throw RuntimeError("Could not convert argument to time::ns");
|
|
}
|
|
std::this_thread::sleep_for(converted_time);
|
|
os << "for " << ToString(converted_time) << " completed" << '\n';
|
|
} else {
|
|
throw RuntimeError("Unknown action");
|
|
}
|
|
return os.str();
|
|
}
|
|
|
|
} // namespace sls
|