mirror of
https://github.com/slsdetectorgroup/slsDetectorPackage.git
synced 2026-01-22 09:22:54 +01:00
10.0.0.rc (#1260)
* 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>
This commit is contained in:
@@ -13,6 +13,7 @@ set(SOURCES
|
||||
src/Arping.cpp
|
||||
src/MasterAttributes.cpp
|
||||
src/MasterFileUtility.cpp
|
||||
src/CommandLineOptions.cpp
|
||||
)
|
||||
|
||||
set(PUBLICHEADERS
|
||||
@@ -51,6 +52,10 @@ target_link_libraries(slsReceiverObject
|
||||
slsProjectWarnings #don't propagate warnigns
|
||||
)
|
||||
|
||||
target_compile_definitions(slsReceiverObject
|
||||
PRIVATE $<$<BOOL:${SLS_USE_TESTS}>:SLS_USE_TESTS>
|
||||
)
|
||||
|
||||
# HDF5
|
||||
if (SLS_USE_HDF5)
|
||||
if (HDF5_FOUND)
|
||||
@@ -86,6 +91,7 @@ set_target_properties(slsReceiverStatic PROPERTIES
|
||||
ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
|
||||
PUBLIC_HEADER "${PUBLICHEADERS}"
|
||||
)
|
||||
|
||||
list(APPEND RECEIVER_LIBRARY_TARGETS slsReceiverStatic)
|
||||
|
||||
|
||||
|
||||
@@ -13,22 +13,12 @@ class Receiver : private virtual slsDetectorDefs {
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
* Starts up a Receiver server. Reads configuration file, options, and
|
||||
* assembles a Receiver using TCP and UDP detector interfaces
|
||||
* Starts up a Receiver server.
|
||||
* Assembles a Receiver using TCP and UDP detector interfaces
|
||||
* throws an exception in case of failure
|
||||
* @param argc from command line
|
||||
* @param argv from command line
|
||||
* @param port TCP/IP port number
|
||||
*/
|
||||
Receiver(int argc, char *argv[]);
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* Starts up a Receiver server. Reads configuration file, options, and
|
||||
* assembles a Receiver using TCP and UDP detector interfaces
|
||||
* throws an exception in case of failure
|
||||
* @param tcpip_port_no TCP/IP port number
|
||||
*/
|
||||
Receiver(uint16_t tcpip_port_no = 1954);
|
||||
explicit Receiver(uint16_t port = 1954);
|
||||
|
||||
~Receiver();
|
||||
|
||||
@@ -45,9 +35,8 @@ class Receiver : private virtual slsDetectorDefs {
|
||||
* Call back arguments are:
|
||||
* - startCallbackHeader metadata
|
||||
*/
|
||||
void registerCallBackStartAcquisition(int (*func)(const startCallbackHeader,
|
||||
void *),
|
||||
void *arg);
|
||||
void registerCallBackStartAcquisition(
|
||||
void (*func)(const startCallbackHeader, void *), void *arg);
|
||||
|
||||
/**
|
||||
* Call back for acquisition finished
|
||||
|
||||
@@ -44,7 +44,7 @@ ClientInterface::~ClientInterface() {
|
||||
}
|
||||
|
||||
ClientInterface::ClientInterface(uint16_t portNumber)
|
||||
: detType(GOTTHARD), portNumber(portNumber), server(portNumber) {
|
||||
: detType(GENERIC), portNumber(portNumber), server(portNumber) {
|
||||
validatePortNumber(portNumber);
|
||||
functionTable();
|
||||
parentThreadId = gettid();
|
||||
@@ -56,7 +56,7 @@ std::string ClientInterface::getReceiverVersion() { return APIRECEIVER; }
|
||||
|
||||
/***callback functions***/
|
||||
void ClientInterface::registerCallBackStartAcquisition(
|
||||
int (*func)(const startCallbackHeader, void *), void *arg) {
|
||||
void (*func)(const startCallbackHeader, void *), void *arg) {
|
||||
std::lock_guard<std::mutex> lock(callbackMutex);
|
||||
startAcquisitionCallBack = func;
|
||||
pStartAcquisition = arg;
|
||||
@@ -120,7 +120,6 @@ int ClientInterface::functionTable(){
|
||||
flist[F_GET_LAST_RECEIVER_CLIENT_IP] = &ClientInterface::get_last_client_ip;
|
||||
flist[F_GET_RECEIVER_VERSION] = &ClientInterface::get_version;
|
||||
flist[F_SETUP_RECEIVER] = &ClientInterface::setup_receiver;
|
||||
flist[F_RECEIVER_SET_DETECTOR_ROI] = &ClientInterface::set_detector_roi;
|
||||
flist[F_RECEIVER_SET_NUM_FRAMES] = &ClientInterface::set_num_frames;
|
||||
flist[F_SET_RECEIVER_NUM_TRIGGERS] = &ClientInterface::set_num_triggers;
|
||||
flist[F_SET_RECEIVER_NUM_BURSTS] = &ClientInterface::set_num_bursts;
|
||||
@@ -219,7 +218,10 @@ int ClientInterface::functionTable(){
|
||||
flist[F_RECEIVER_SET_TRANSCEIVER_MASK] = &ClientInterface::set_transceiver_mask;
|
||||
flist[F_RECEIVER_SET_ROW] = &ClientInterface::set_row;
|
||||
flist[F_RECEIVER_SET_COLUMN] = &ClientInterface::set_column;
|
||||
|
||||
flist[F_GET_RECEIVER_DBIT_REORDER] = &ClientInterface::get_dbit_reorder;
|
||||
flist[F_SET_RECEIVER_DBIT_REORDER] = &ClientInterface::set_dbit_reorder;
|
||||
flist[F_RECEIVER_GET_ROI_METADATA] = &ClientInterface::get_roi_metadata;
|
||||
flist[F_SET_RECEIVER_READOUT_SPEED] = &ClientInterface::set_readout_speed;
|
||||
|
||||
for (int i = NUM_DET_FUNCTIONS + 1; i < NUM_REC_FUNCTIONS ; i++) {
|
||||
LOG(logDEBUG1) << "function fnum: " << i << " (" <<
|
||||
@@ -409,13 +411,12 @@ int ClientInterface::setup_receiver(Interface &socket) {
|
||||
impl()->setReadoutMode(arg.roMode);
|
||||
impl()->setTenGigaADCEnableMask(arg.adc10gMask);
|
||||
impl()->setTransceiverEnableMask(arg.transceiverMask);
|
||||
} else {
|
||||
impl()->setReadoutSpeed(arg.readoutSpeed);
|
||||
}
|
||||
if (detType == CHIPTESTBOARD) {
|
||||
impl()->setADCEnableMask(arg.adcMask);
|
||||
}
|
||||
if (detType == GOTTHARD) {
|
||||
impl()->setDetectorROI(arg.roi);
|
||||
}
|
||||
if (detType == MYTHEN3) {
|
||||
impl()->setCounterMask(arg.countermask);
|
||||
impl()->setAcquisitionTime1(
|
||||
@@ -443,7 +444,6 @@ int ClientInterface::setup_receiver(Interface &socket) {
|
||||
|
||||
void ClientInterface::setDetectorType(detectorType arg) {
|
||||
switch (arg) {
|
||||
case GOTTHARD:
|
||||
case EIGER:
|
||||
case CHIPTESTBOARD:
|
||||
case XILINX_CHIPTESTBOARD:
|
||||
@@ -482,22 +482,6 @@ void ClientInterface::setDetectorType(detectorType arg) {
|
||||
impl()->setThreadIds(parentThreadId, tcpThreadId);
|
||||
}
|
||||
|
||||
int ClientInterface::set_detector_roi(Interface &socket) {
|
||||
auto arg = socket.Receive<ROI>();
|
||||
LOG(logDEBUG1) << "Set Detector ROI: " << ToString(arg);
|
||||
|
||||
if (detType != GOTTHARD)
|
||||
functionNotImplemented();
|
||||
|
||||
verifyIdle(socket);
|
||||
try {
|
||||
impl()->setDetectorROI(arg);
|
||||
} catch (const std::exception &e) {
|
||||
throw RuntimeError("Could not set ROI [" + std::string(e.what()) + ']');
|
||||
}
|
||||
return socket.Send(OK);
|
||||
}
|
||||
|
||||
int ClientInterface::set_num_frames(Interface &socket) {
|
||||
auto value = socket.Receive<int64_t>();
|
||||
if (value <= 0) {
|
||||
@@ -1712,19 +1696,37 @@ int ClientInterface::set_arping(Interface &socket) {
|
||||
}
|
||||
|
||||
int ClientInterface::get_receiver_roi(Interface &socket) {
|
||||
auto retval = impl()->getReceiverROI();
|
||||
LOG(logDEBUG1) << "Receiver roi retval:" << ToString(retval);
|
||||
return socket.sendResult(retval);
|
||||
auto retvals = impl()->getPortROIs();
|
||||
LOG(logDEBUG1) << "Receiver roi retval:" << ToString(retvals);
|
||||
auto size = static_cast<int>(retvals.size());
|
||||
if (size != impl()->getNumberofUDPInterfaces()) {
|
||||
throw RuntimeError("Invalid number of ROIs received: " +
|
||||
std::to_string(size) + ". Expected: " +
|
||||
std::to_string(impl()->getNumberofUDPInterfaces()));
|
||||
}
|
||||
socket.Send(size);
|
||||
if (size > 0)
|
||||
socket.Send(retvals);
|
||||
return OK;
|
||||
}
|
||||
|
||||
int ClientInterface::set_receiver_roi(Interface &socket) {
|
||||
auto arg = socket.Receive<ROI>();
|
||||
auto roiSize = socket.Receive<int>();
|
||||
std::vector<ROI> args(roiSize);
|
||||
if (roiSize > 0) {
|
||||
socket.Receive(args);
|
||||
}
|
||||
if (roiSize != impl()->getNumberofUDPInterfaces()) {
|
||||
throw RuntimeError("Invalid number of ROIs received: " +
|
||||
std::to_string(roiSize) + ". Expected: " +
|
||||
std::to_string(impl()->getNumberofUDPInterfaces()));
|
||||
}
|
||||
if (detType == CHIPTESTBOARD || detType == XILINX_CHIPTESTBOARD)
|
||||
functionNotImplemented();
|
||||
LOG(logDEBUG1) << "Set Receiver ROI: " << ToString(arg);
|
||||
LOG(logDEBUG1) << "Set Receiver ROI: " << ToString(args);
|
||||
verifyIdle(socket);
|
||||
try {
|
||||
impl()->setReceiverROI(arg);
|
||||
impl()->setPortROIs(args);
|
||||
} catch (const std::exception &e) {
|
||||
throw RuntimeError("Could not set Receiver ROI [" +
|
||||
std::string(e.what()) + ']');
|
||||
@@ -1734,18 +1736,26 @@ int ClientInterface::set_receiver_roi(Interface &socket) {
|
||||
}
|
||||
|
||||
int ClientInterface::set_receiver_roi_metadata(Interface &socket) {
|
||||
auto arg = socket.Receive<ROI>();
|
||||
auto roiSize = socket.Receive<int>();
|
||||
LOG(logDEBUG1) << "Number of ReceiverROI metadata: " << roiSize;
|
||||
if (roiSize < 1) {
|
||||
throw RuntimeError("Invalid number of ROIs received: " +
|
||||
std::to_string(roiSize) + ". Min: 1.");
|
||||
}
|
||||
std::vector<ROI> rois(roiSize);
|
||||
if (roiSize > 0) {
|
||||
socket.Receive(rois);
|
||||
}
|
||||
if (detType == CHIPTESTBOARD || detType == XILINX_CHIPTESTBOARD)
|
||||
functionNotImplemented();
|
||||
LOG(logDEBUG1) << "Set Receiver ROI Metadata: " << ToString(arg);
|
||||
verifyIdle(socket);
|
||||
LOG(logINFO) << "Setting ReceiverROI metadata[" << roiSize << ']';
|
||||
try {
|
||||
impl()->setReceiverROIMetadata(arg);
|
||||
impl()->setMultiROIMetadata(rois);
|
||||
} catch (const std::exception &e) {
|
||||
throw RuntimeError("Could not set ReceiverROI metadata [" +
|
||||
std::string(e.what()) + ']');
|
||||
}
|
||||
|
||||
return socket.Send(OK);
|
||||
}
|
||||
|
||||
@@ -1810,4 +1820,66 @@ int ClientInterface::set_column(Interface &socket) {
|
||||
return socket.Send(OK);
|
||||
}
|
||||
|
||||
int ClientInterface::get_dbit_reorder(Interface &socket) {
|
||||
if (detType != CHIPTESTBOARD && detType != XILINX_CHIPTESTBOARD)
|
||||
functionNotImplemented();
|
||||
int retval = impl()->getDbitReorder();
|
||||
LOG(logDEBUG1) << "Dbit reorder retval: " << retval;
|
||||
return socket.sendResult(retval);
|
||||
}
|
||||
|
||||
int ClientInterface::set_dbit_reorder(Interface &socket) {
|
||||
auto arg = socket.Receive<int>();
|
||||
if (detType != CHIPTESTBOARD && detType != XILINX_CHIPTESTBOARD)
|
||||
functionNotImplemented();
|
||||
if (arg < 0) {
|
||||
throw RuntimeError("Invalid dbit reorder: " + std::to_string(arg));
|
||||
}
|
||||
verifyIdle(socket);
|
||||
LOG(logDEBUG1) << "Setting Dbit reorder: " << arg;
|
||||
impl()->setDbitReorder(arg);
|
||||
return socket.Send(OK);
|
||||
}
|
||||
|
||||
int ClientInterface::get_roi_metadata(Interface &socket) {
|
||||
if (detType == CHIPTESTBOARD || detType == XILINX_CHIPTESTBOARD)
|
||||
functionNotImplemented();
|
||||
auto retvals = impl()->getMultiROIMetadata();
|
||||
LOG(logDEBUG1) << "Receiver ROI metadata retval:" << ToString(retvals);
|
||||
auto size = static_cast<int>(retvals.size());
|
||||
socket.Send(size);
|
||||
if (size > 0)
|
||||
socket.Send(retvals);
|
||||
return OK;
|
||||
}
|
||||
|
||||
int ClientInterface::set_readout_speed(Interface &socket) {
|
||||
auto value = socket.Receive<int>();
|
||||
verifyIdle(socket);
|
||||
switch (detType) {
|
||||
case GOTTHARD2:
|
||||
if (value != G2_108MHZ && value != G2_144MHZ)
|
||||
throw RuntimeError("Invalid readout speed for GOTTHARD2: " +
|
||||
std::to_string(value));
|
||||
break;
|
||||
|
||||
case EIGER:
|
||||
case JUNGFRAU:
|
||||
case MYTHEN3:
|
||||
case MOENCH:
|
||||
if (value < 0 || value > QUARTER_SPEED) {
|
||||
throw RuntimeError("Invalid readout speed: " +
|
||||
std::to_string(value));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
functionNotImplemented();
|
||||
}
|
||||
|
||||
LOG(logDEBUG1) << "Setting readout speed to " << value;
|
||||
impl()->setReadoutSpeed(static_cast<speedLevel>(value));
|
||||
return socket.Send(OK);
|
||||
}
|
||||
|
||||
} // namespace sls
|
||||
|
||||
@@ -34,9 +34,8 @@ class ClientInterface : private virtual slsDetectorDefs {
|
||||
|
||||
//***callback functions***
|
||||
/** params: file path, file name, file index, image size */
|
||||
void registerCallBackStartAcquisition(int (*func)(const startCallbackHeader,
|
||||
void *),
|
||||
void *arg);
|
||||
void registerCallBackStartAcquisition(
|
||||
void (*func)(const startCallbackHeader, void *), void *arg);
|
||||
|
||||
/** params: total frames caught */
|
||||
void registerCallBackAcquisitionFinished(
|
||||
@@ -64,7 +63,6 @@ class ClientInterface : private virtual slsDetectorDefs {
|
||||
int get_version(ServerInterface &socket);
|
||||
int setup_receiver(ServerInterface &socket);
|
||||
void setDetectorType(detectorType arg);
|
||||
int set_detector_roi(ServerInterface &socket);
|
||||
int set_num_frames(ServerInterface &socket);
|
||||
int set_num_triggers(ServerInterface &socket);
|
||||
int set_num_bursts(ServerInterface &socket);
|
||||
@@ -166,6 +164,10 @@ class ClientInterface : private virtual slsDetectorDefs {
|
||||
int set_transceiver_mask(ServerInterface &socket);
|
||||
int set_row(ServerInterface &socket);
|
||||
int set_column(ServerInterface &socket);
|
||||
int get_dbit_reorder(ServerInterface &socket);
|
||||
int set_dbit_reorder(ServerInterface &socket);
|
||||
int get_roi_metadata(ServerInterface &socket);
|
||||
int set_readout_speed(ServerInterface &socket);
|
||||
|
||||
Implementation *impl() {
|
||||
if (receiver != nullptr) {
|
||||
@@ -180,8 +182,8 @@ class ClientInterface : private virtual slsDetectorDefs {
|
||||
|
||||
//***callback parameters***
|
||||
|
||||
int (*startAcquisitionCallBack)(const startCallbackHeader,
|
||||
void *) = nullptr;
|
||||
void (*startAcquisitionCallBack)(const startCallbackHeader,
|
||||
void *) = nullptr;
|
||||
void *pStartAcquisition{nullptr};
|
||||
void (*acquisitionFinishedCallBack)(const endCallbackHeader,
|
||||
void *) = nullptr;
|
||||
|
||||
352
slsReceiverSoftware/src/CommandLineOptions.cpp
Normal file
352
slsReceiverSoftware/src/CommandLineOptions.cpp
Normal file
@@ -0,0 +1,352 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-other
|
||||
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||
|
||||
#include "CommandLineOptions.h"
|
||||
#include "sls/ToString.h"
|
||||
#include "sls/logger.h"
|
||||
#include "sls/sls_detector_defs.h"
|
||||
#include "sls/versionAPI.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <unistd.h>
|
||||
|
||||
CommandLineOptions::CommandLineOptions(AppType app)
|
||||
: appType_(app), optString_(buildOptString()),
|
||||
longOptions_(buildOptionList()) {}
|
||||
|
||||
/** for testing */
|
||||
ParsedOptions CommandLineOptions::parse(const std::vector<std::string> &args) {
|
||||
std::vector<char *> argv;
|
||||
argv.reserve(args.size());
|
||||
for (const auto &arg : args) {
|
||||
argv.push_back(const_cast<char *>(arg.c_str()));
|
||||
}
|
||||
int argc = static_cast<int>(argv.size());
|
||||
return parse(argc, argv.data());
|
||||
}
|
||||
|
||||
ParsedOptions CommandLineOptions::parse(int argc, char *argv[]) {
|
||||
CommonOptions base;
|
||||
MultiReceiverOptions multi;
|
||||
FrameSyncOptions frame;
|
||||
base.port = DEFAULT_TCP_RX_PORTNO;
|
||||
|
||||
optind = 0; // reset getopt
|
||||
int opt, option_index = 0;
|
||||
|
||||
bool help_or_version_requested = false;
|
||||
|
||||
while ((opt = getopt_long(argc, argv, optString_.c_str(),
|
||||
longOptions_.data(), &option_index)) != -1) {
|
||||
switch (opt) {
|
||||
case 'v':
|
||||
case 'h':
|
||||
handleCommonOption(opt, optarg, base);
|
||||
help_or_version_requested = true;
|
||||
break;
|
||||
case 'p':
|
||||
case 'u':
|
||||
handleCommonOption(opt, optarg, base);
|
||||
break;
|
||||
case 'c':
|
||||
case 'n':
|
||||
case 't':
|
||||
handleAppSpecificOption(opt, optarg, base, multi, frame);
|
||||
break;
|
||||
default:
|
||||
throw sls::RuntimeError("Invalid arguments." + getHelpMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// remaining arguments
|
||||
if (!help_or_version_requested && optind < argc) {
|
||||
|
||||
// deprecated and current options => invalid
|
||||
if (base.port != DEFAULT_TCP_RX_PORTNO || multi.numReceivers != 1 ||
|
||||
frame.numReceivers != 1 || multi.callbackEnabled != false ||
|
||||
frame.printHeaders != false) {
|
||||
LOG(sls::logWARNING) << "Cannot use both deprecated options and "
|
||||
"the valid options simultaneously. Please "
|
||||
"move away from the deprecated options.\n";
|
||||
}
|
||||
|
||||
// unsupported deprecated arguments
|
||||
if (appType_ == AppType::SingleReceiver) {
|
||||
throw sls::RuntimeError("Invalid arguments." + getHelpMessage());
|
||||
}
|
||||
|
||||
// parse deprecated arguments
|
||||
std::vector<std::string> args(argv, argv + argc);
|
||||
auto [p, n, o] = ParseDeprecated(args);
|
||||
// set options
|
||||
base.port = p;
|
||||
if (appType_ == AppType::MultiReceiver) {
|
||||
multi.numReceivers = n;
|
||||
multi.callbackEnabled = o;
|
||||
} else if (appType_ == AppType::FrameSynchronizer) {
|
||||
frame.numReceivers = n;
|
||||
frame.printHeaders = o;
|
||||
}
|
||||
}
|
||||
|
||||
// Logging
|
||||
if (!help_or_version_requested) {
|
||||
LOG(sls::logINFO) << "TCP Port: " << base.port;
|
||||
if (appType_ == AppType::MultiReceiver) {
|
||||
LOG(sls::logINFO) << "Number of receivers: " << multi.numReceivers;
|
||||
LOG(sls::logINFO) << "Callback enabled: " << multi.callbackEnabled;
|
||||
} else if (appType_ == AppType::FrameSynchronizer) {
|
||||
LOG(sls::logINFO) << "Number of receivers: " << frame.numReceivers;
|
||||
LOG(sls::logINFO) << "Print headers: " << frame.printHeaders;
|
||||
}
|
||||
}
|
||||
|
||||
switch (appType_) {
|
||||
case AppType::SingleReceiver:
|
||||
return base;
|
||||
case AppType::MultiReceiver:
|
||||
static_cast<CommonOptions &>(multi) = base;
|
||||
return multi;
|
||||
case AppType::FrameSynchronizer:
|
||||
static_cast<CommonOptions &>(frame) = base;
|
||||
return frame;
|
||||
default:
|
||||
throw sls::RuntimeError("Unknown AppType in CommandLineOptions::parse");
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<option> CommandLineOptions::buildOptionList() const {
|
||||
std::vector<option> opts = {
|
||||
{"version", no_argument, nullptr, 'v'},
|
||||
{"help", no_argument, nullptr, 'h'},
|
||||
{"port", required_argument, nullptr, 'p'},
|
||||
{"uid", required_argument, nullptr, 'u'},
|
||||
};
|
||||
switch (appType_) {
|
||||
case AppType::SingleReceiver:
|
||||
opts.push_back({"rx_tcpport", required_argument, nullptr, 't'});
|
||||
break;
|
||||
case AppType::MultiReceiver:
|
||||
opts.push_back({"num-receivers", required_argument, nullptr, 'n'});
|
||||
opts.push_back({"callback", no_argument, nullptr, 'c'});
|
||||
break;
|
||||
case AppType::FrameSynchronizer:
|
||||
opts.push_back({"num-receivers", required_argument, nullptr, 'n'});
|
||||
opts.push_back({"print-headers", no_argument, nullptr, 'c'});
|
||||
break;
|
||||
}
|
||||
opts.push_back({nullptr, 0, nullptr, 0}); // null-terminator for getopt
|
||||
return opts;
|
||||
}
|
||||
|
||||
std::string CommandLineOptions::buildOptString() const {
|
||||
std::string optstr = "vhp:u:";
|
||||
if (appType_ == AppType::MultiReceiver ||
|
||||
appType_ == AppType::FrameSynchronizer)
|
||||
optstr += "cn:";
|
||||
if (appType_ == AppType::SingleReceiver)
|
||||
optstr += "t:";
|
||||
return optstr;
|
||||
}
|
||||
|
||||
uint16_t CommandLineOptions::parsePort(const char *optarg) {
|
||||
uint16_t val = 0;
|
||||
try {
|
||||
val = sls::StringTo<uint16_t>(optarg);
|
||||
} catch (...) {
|
||||
throw sls::RuntimeError("Could not parse port number " +
|
||||
std::string(optarg));
|
||||
}
|
||||
if (val < 1024) {
|
||||
throw sls::RuntimeError(
|
||||
"Invalid/ privileged port number parsed. Min: 1024.");
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
uint16_t CommandLineOptions::parseNumReceivers(const char *optarg) {
|
||||
uint16_t val = 0;
|
||||
try {
|
||||
val = sls::StringTo<uint16_t>(optarg);
|
||||
} catch (...) {
|
||||
throw sls::RuntimeError("Could not parse number of receivers " +
|
||||
std::string(optarg));
|
||||
}
|
||||
if (val == 0 || val > MAX_RECEIVERS) {
|
||||
throw sls::RuntimeError(
|
||||
"Invalid number of receivers parsed. Options: 1 - " +
|
||||
std::to_string(MAX_RECEIVERS));
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
uid_t CommandLineOptions::parseUID(const char *optarg) {
|
||||
uid_t val = -1;
|
||||
try {
|
||||
val = sls::StringTo<uid_t>(optarg);
|
||||
} catch (...) {
|
||||
throw sls::RuntimeError("Could not parse UID " + std::string(optarg));
|
||||
}
|
||||
if (val == static_cast<uid_t>(-1)) {
|
||||
throw sls::RuntimeError(
|
||||
"Could not parse UID. Expected a valid user ID." +
|
||||
std::string(optarg));
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
void CommandLineOptions::handleCommonOption(int opt, const char *optarg,
|
||||
CommonOptions &base) {
|
||||
switch (opt) {
|
||||
case 'v':
|
||||
base.versionRequested = true;
|
||||
std::cout << getVersion() << std::endl;
|
||||
break;
|
||||
case 'h':
|
||||
base.helpRequested = true;
|
||||
std::cout << getHelpMessage() << std::endl;
|
||||
break;
|
||||
case 'p':
|
||||
base.port = parsePort(optarg);
|
||||
break;
|
||||
case 'u':
|
||||
base.userid = parseUID(optarg);
|
||||
setEffectiveUID(base.userid);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CommandLineOptions::handleAppSpecificOption(int opt, const char *optarg,
|
||||
CommonOptions &base,
|
||||
MultiReceiverOptions &multi,
|
||||
FrameSyncOptions &frame) {
|
||||
switch (opt) {
|
||||
|
||||
case 'c':
|
||||
if (appType_ == AppType::MultiReceiver)
|
||||
multi.callbackEnabled = true;
|
||||
else if (appType_ == AppType::FrameSynchronizer)
|
||||
frame.printHeaders = true;
|
||||
break;
|
||||
|
||||
case 'n': {
|
||||
auto val = parseNumReceivers(optarg);
|
||||
if (appType_ == AppType::MultiReceiver)
|
||||
multi.numReceivers = val;
|
||||
else if (appType_ == AppType::FrameSynchronizer)
|
||||
frame.numReceivers = val;
|
||||
break;
|
||||
}
|
||||
|
||||
case 't':
|
||||
LOG(sls::logWARNING) << "Deprecated option '-t' and '--rx_tcport'. Use "
|
||||
"'--p' or '--port' instead.";
|
||||
base.port = parsePort(optarg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* maintain backward compatibility of [start port] [num receivers] [optional
|
||||
* arg] */
|
||||
std::tuple<uint16_t, uint16_t, bool>
|
||||
CommandLineOptions::ParseDeprecated(const std::vector<std::string> &args) {
|
||||
|
||||
size_t nargs = args.size();
|
||||
if (nargs != 1 && nargs != 3 && nargs != 4) {
|
||||
throw sls::RuntimeError("Invalid number of arguments.");
|
||||
}
|
||||
|
||||
LOG(sls::logWARNING)
|
||||
<< "Deprecated options will be removed in future versions. "
|
||||
"Please use the new options.\n";
|
||||
|
||||
// default deprecated values
|
||||
if (nargs == 1) {
|
||||
return std::make_tuple(DEFAULT_TCP_RX_PORTNO, 1, false);
|
||||
}
|
||||
|
||||
// parse deprecated arguments
|
||||
uint16_t p = parsePort(args[1].c_str());
|
||||
uint16_t n = parseNumReceivers(args[2].c_str());
|
||||
bool o = false;
|
||||
if (nargs == 4) {
|
||||
try {
|
||||
o = sls::StringTo<bool>(args[3].c_str());
|
||||
} catch (...) {
|
||||
throw sls::RuntimeError("Invalid optional argument "
|
||||
"parsed. Expected 1 (true) or "
|
||||
"0 (false).");
|
||||
}
|
||||
}
|
||||
return std::make_tuple(p, n, o);
|
||||
}
|
||||
|
||||
std::string CommandLineOptions::getTypeString() const {
|
||||
switch (appType_) {
|
||||
case AppType::SingleReceiver:
|
||||
return "slsReceiver";
|
||||
case AppType::MultiReceiver:
|
||||
return "slsMultiReceiver";
|
||||
case AppType::FrameSynchronizer:
|
||||
return "slsFrameSynchronizer";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
std::string CommandLineOptions::getVersion() const {
|
||||
return getTypeString() + " Version: " + APIRECEIVER;
|
||||
}
|
||||
|
||||
std::string CommandLineOptions::getHelpMessage() const {
|
||||
switch (appType_) {
|
||||
case AppType::SingleReceiver:
|
||||
return std::string("\nUsage: ") + getTypeString() + " Options:\n" +
|
||||
"\t-v, --version : Version.\n" +
|
||||
"\t-p, --port : TCP port to communicate with client "
|
||||
"for "
|
||||
"configuration. Non-zero and 16 bit.\n" +
|
||||
"\t-u, --uid : Set effective user id if receiver "
|
||||
"started "
|
||||
"with privileges. \n\n";
|
||||
|
||||
case AppType::MultiReceiver:
|
||||
return std::string("\nUsage: " + getTypeString() + " Options:\n") +
|
||||
"\t-v, --version : Version.\n" +
|
||||
"\t-n, --num-receivers : Number of receivers.\n" +
|
||||
"\t-p, --port : TCP port to communicate with client "
|
||||
"for "
|
||||
"configuration. Non-zero and 16 bit.\n" +
|
||||
"\t-c, --callback : Enable dummy callbacks for debugging. "
|
||||
"Disabled by default. \n" +
|
||||
"\t-u, --uid : Set effective user id if receiver "
|
||||
"started "
|
||||
"with privileges. \n\n";
|
||||
|
||||
case AppType::FrameSynchronizer:
|
||||
return std::string("\nUsage: " + getTypeString() + " Options:\n") +
|
||||
"\t-v, --version : Version.\n" +
|
||||
"\t-n, --num-receivers : Number of receivers.\n" +
|
||||
"\t-p, --port : TCP port to communicate with client "
|
||||
"for "
|
||||
"configuration. Non-zero and 16 bit.\n" +
|
||||
"\t-c, --print-headers : Print callback headers for debugging. "
|
||||
"Disabled by default.\n" +
|
||||
"\t-u, --uid : Set effective user id if receiver "
|
||||
"started "
|
||||
"with privileges. \n\n";
|
||||
}
|
||||
throw sls::RuntimeError("Unknown AppType for help message");
|
||||
}
|
||||
|
||||
void CommandLineOptions::setEffectiveUID(uid_t uid) {
|
||||
if (geteuid() == uid) {
|
||||
LOG(sls::logINFO) << "Process already has the same Effective UID "
|
||||
<< uid;
|
||||
} else {
|
||||
if (seteuid(uid) != 0 || geteuid() != uid) {
|
||||
throw sls::RuntimeError("Could not set Effective UID");
|
||||
}
|
||||
LOG(sls::logINFO) << "Process Effective UID changed to " << uid;
|
||||
}
|
||||
}
|
||||
63
slsReceiverSoftware/src/CommandLineOptions.h
Normal file
63
slsReceiverSoftware/src/CommandLineOptions.h
Normal file
@@ -0,0 +1,63 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-other
|
||||
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <getopt.h>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
enum class AppType { MultiReceiver, SingleReceiver, FrameSynchronizer };
|
||||
|
||||
struct CommonOptions {
|
||||
uint16_t port = -1;
|
||||
uid_t userid = -1;
|
||||
bool versionRequested = false;
|
||||
bool helpRequested = false;
|
||||
};
|
||||
|
||||
struct MultiReceiverOptions : CommonOptions {
|
||||
uint16_t numReceivers = 1;
|
||||
bool callbackEnabled = false;
|
||||
};
|
||||
|
||||
struct FrameSyncOptions : CommonOptions {
|
||||
uint16_t numReceivers = 1;
|
||||
bool printHeaders = false;
|
||||
};
|
||||
|
||||
using ParsedOptions =
|
||||
std::variant<CommonOptions, MultiReceiverOptions, FrameSyncOptions>;
|
||||
|
||||
class CommandLineOptions {
|
||||
public:
|
||||
explicit CommandLineOptions(AppType app);
|
||||
ParsedOptions parse(const std::vector<std::string> &args); // for testing
|
||||
ParsedOptions parse(int argc, char *argv[]);
|
||||
std::string getTypeString() const;
|
||||
std::string getVersion() const;
|
||||
std::string getHelpMessage() const;
|
||||
static void setEffectiveUID(uid_t uid);
|
||||
static std::tuple<uint16_t, uint16_t, bool>
|
||||
ParseDeprecated(const std::vector<std::string> &args);
|
||||
|
||||
private:
|
||||
AppType appType_;
|
||||
std::string optString_;
|
||||
std::vector<option> longOptions_;
|
||||
std::vector<option> buildOptionList() const;
|
||||
std::string buildOptString() const;
|
||||
|
||||
static uint16_t parsePort(const char *optarg);
|
||||
static uint16_t parseNumReceivers(const char *optarg);
|
||||
static uid_t parseUID(const char *optarg);
|
||||
void handleCommonOption(int opt, const char *optarg, CommonOptions &base);
|
||||
void handleAppSpecificOption(int opt, const char *optarg,
|
||||
CommonOptions &base,
|
||||
MultiReceiverOptions &multi,
|
||||
FrameSyncOptions &frame);
|
||||
|
||||
static constexpr uint16_t MAX_RECEIVERS = 1000;
|
||||
};
|
||||
@@ -3,7 +3,7 @@
|
||||
/************************************************
|
||||
* @file DataProcessor.cpp
|
||||
* @short creates data processor thread that
|
||||
* pulls pointers to memory addresses from fifos
|
||||
* pulls pointers to memory addresses from fifos
|
||||
* and processes data stored in them & writes them to file
|
||||
***********************************************/
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <numeric>
|
||||
|
||||
namespace sls {
|
||||
|
||||
@@ -47,10 +48,15 @@ void DataProcessor::SetUdpPortNumber(const uint16_t portNumber) {
|
||||
|
||||
void DataProcessor::SetActivate(bool enable) { activated = enable; }
|
||||
|
||||
void DataProcessor::SetReceiverROI(ROI roi) {
|
||||
receiverRoi = roi;
|
||||
receiverRoiEnabled = receiverRoi.completeRoi() ? false : true;
|
||||
receiverNoRoi = receiverRoi.noRoi();
|
||||
void DataProcessor::SetPortROI(ROI roi) {
|
||||
portRoi = roi;
|
||||
isPartiallyInRoi = portRoi.completeRoi() ? false : true;
|
||||
isOutsideRoi = portRoi.noRoi();
|
||||
}
|
||||
|
||||
void DataProcessor::setMultiROIMetadata(
|
||||
const std::vector<slsDetectorDefs::ROI> &args) {
|
||||
multiRoiMetadata = args;
|
||||
}
|
||||
|
||||
void DataProcessor::SetDataStreamEnable(bool enable) {
|
||||
@@ -71,12 +77,6 @@ void DataProcessor::SetStreamingStartFnum(uint32_t value) {
|
||||
|
||||
void DataProcessor::SetFramePadding(bool enable) { framePadding = enable; }
|
||||
|
||||
void DataProcessor::SetCtbDbitList(std::vector<int> value) {
|
||||
ctbDbitList = value;
|
||||
}
|
||||
|
||||
void DataProcessor::SetCtbDbitOffset(int value) { ctbDbitOffset = value; }
|
||||
|
||||
void DataProcessor::SetQuadEnable(bool value) { quadEnable = value; }
|
||||
|
||||
void DataProcessor::SetFlipRows(bool fd) {
|
||||
@@ -159,17 +159,17 @@ void DataProcessor::CreateFirstFiles(const std::string &fileNamePrefix,
|
||||
CloseFiles();
|
||||
|
||||
// deactivated (half module/ single port or no roi), dont write file
|
||||
if (!activated || !detectorDataStream || receiverNoRoi) {
|
||||
if (!activated || !detectorDataStream || isOutsideRoi) {
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef HDF5C
|
||||
int nx = generalData->nPixelsX;
|
||||
int ny = generalData->nPixelsY;
|
||||
if (receiverRoiEnabled) {
|
||||
nx = receiverRoi.xmax - receiverRoi.xmin + 1;
|
||||
ny = receiverRoi.ymax - receiverRoi.ymin + 1;
|
||||
if (receiverRoi.ymax == -1 || receiverRoi.ymin == -1) {
|
||||
if (isPartiallyInRoi) {
|
||||
nx = portRoi.xmax - portRoi.xmin + 1;
|
||||
ny = portRoi.ymax - portRoi.ymin + 1;
|
||||
if (portRoi.ymax == -1 || portRoi.ymin == -1) {
|
||||
ny = 1;
|
||||
}
|
||||
}
|
||||
@@ -206,16 +206,11 @@ std::string DataProcessor::CreateVirtualFile(
|
||||
const std::string &filePath, const std::string &fileNamePrefix,
|
||||
const uint64_t fileIndex, const bool overWriteEnable, const bool silentMode,
|
||||
const int modulePos, const int numModX, const int numModY,
|
||||
std::mutex *hdf5LibMutex) {
|
||||
std::mutex *hdf5LibMutex, bool gotthard25um) {
|
||||
|
||||
if (receiverRoiEnabled) {
|
||||
throw std::runtime_error(
|
||||
"Skipping virtual hdf5 file since rx_roi is enabled.");
|
||||
}
|
||||
|
||||
bool gotthard25um = ((generalData->detType == GOTTHARD ||
|
||||
generalData->detType == GOTTHARD2) &&
|
||||
(numModX * numModY) == 2);
|
||||
int ny = generalData->nPixelsY;
|
||||
if (generalData->dynamicRange == 4)
|
||||
ny /= 2;
|
||||
|
||||
// 0 for infinite files
|
||||
uint32_t framesPerFile =
|
||||
@@ -229,10 +224,10 @@ std::string DataProcessor::CreateVirtualFile(
|
||||
return masterFileUtility::CreateVirtualHDF5File(
|
||||
filePath, fileNamePrefix, fileIndex, overWriteEnable, silentMode,
|
||||
modulePos, generalData->numUDPInterfaces, framesPerFile,
|
||||
generalData->nPixelsX, generalData->nPixelsY, generalData->dynamicRange,
|
||||
numFramesCaught, numModX, numModY, dataFile->GetPDataType(),
|
||||
generalData->nPixelsX, ny, generalData->dynamicRange, numFramesCaught,
|
||||
numModX, numModY, dataFile->GetPDataType(),
|
||||
dataFile->GetParameterNames(), dataFile->GetParameterDataTypes(),
|
||||
hdf5LibMutex, gotthard25um);
|
||||
hdf5LibMutex, gotthard25um, multiRoiMetadata);
|
||||
}
|
||||
|
||||
void DataProcessor::LinkFileInMaster(const std::string &masterFileName,
|
||||
@@ -240,18 +235,14 @@ void DataProcessor::LinkFileInMaster(const std::string &masterFileName,
|
||||
const bool silentMode,
|
||||
std::mutex *hdf5LibMutex) {
|
||||
|
||||
if (receiverRoiEnabled) {
|
||||
throw std::runtime_error(
|
||||
"Should not be here, roi with hdf5 virtual should throw.");
|
||||
}
|
||||
std::string fname{virtualFileName}, masterfname{masterFileName};
|
||||
// if no virtual file, link data file
|
||||
if (virtualFileName.empty()) {
|
||||
fname = dataFile->GetFileName();
|
||||
}
|
||||
masterFileUtility::LinkHDF5FileInMaster(masterfname, fname,
|
||||
dataFile->GetParameterNames(),
|
||||
silentMode, hdf5LibMutex);
|
||||
masterFileUtility::LinkHDF5FileInMaster(
|
||||
masterfname, fname, dataFile->GetParameterNames(), silentMode,
|
||||
hdf5LibMutex, multiRoiMetadata.size());
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -300,13 +291,13 @@ void DataProcessor::ThreadExecution() {
|
||||
memImage->data);
|
||||
} catch (const std::exception &e) {
|
||||
fifo->FreeAddress(buffer);
|
||||
return;
|
||||
throw RuntimeError(e.what());
|
||||
}
|
||||
|
||||
// stream (if time/freq to stream) or free
|
||||
if (streamCurrentFrame) {
|
||||
// copy the complete image back if roi enabled
|
||||
if (receiverRoiEnabled) {
|
||||
if (isPartiallyInRoi) {
|
||||
memImage->size = generalData->imageSize;
|
||||
memcpy(memImage->data, &completeImageToStreamBeforeCropping[0],
|
||||
generalData->imageSize);
|
||||
@@ -333,6 +324,7 @@ void DataProcessor::StopProcessing(char *buf) {
|
||||
|
||||
void DataProcessor::ProcessAnImage(sls_receiver_header &header, size_t &size,
|
||||
size_t &firstImageIndex, char *data) {
|
||||
|
||||
uint64_t fnum = header.detHeader.frameNumber;
|
||||
LOG(logDEBUG1) << "DataProcessing " << index << ": fnum:" << fnum;
|
||||
currentFrameIndex = fnum;
|
||||
@@ -356,9 +348,20 @@ void DataProcessor::ProcessAnImage(sls_receiver_header &header, size_t &size,
|
||||
if (framePadding && nump < generalData->packetsPerFrame)
|
||||
PadMissingPackets(header, data);
|
||||
|
||||
// rearrange ctb digital bits (if ctbDbitlist is not empty)
|
||||
if (!ctbDbitList.empty()) {
|
||||
RearrangeDbitData(size, data);
|
||||
if (generalData->readoutType == slsDetectorDefs::DIGITAL_ONLY ||
|
||||
generalData->readoutType == slsDetectorDefs::ANALOG_AND_DIGITAL ||
|
||||
generalData->readoutType == slsDetectorDefs::DIGITAL_AND_TRANSCEIVER) {
|
||||
// rearrange ctb digital bits
|
||||
if (!generalData->ctbDbitList.empty()) {
|
||||
ArrangeDbitData(size, data);
|
||||
} else if (generalData->ctbDbitReorder) {
|
||||
std::vector<int> ctbDbitList(64);
|
||||
std::iota(ctbDbitList.begin(), ctbDbitList.end(), 0);
|
||||
generalData->SetctbDbitList(ctbDbitList);
|
||||
ArrangeDbitData(size, data);
|
||||
} else if (generalData->ctbDbitOffset > 0) {
|
||||
RemoveTrailingBits(size, data);
|
||||
}
|
||||
}
|
||||
|
||||
// 'stream Image' check has to be done here before crop image
|
||||
@@ -374,7 +377,7 @@ void DataProcessor::ProcessAnImage(sls_receiver_header &header, size_t &size,
|
||||
streamCurrentFrame = false;
|
||||
}
|
||||
|
||||
if (receiverRoiEnabled) {
|
||||
if (isPartiallyInRoi) {
|
||||
// copy the complete image to stream before cropping
|
||||
if (streamCurrentFrame) {
|
||||
memcpy(&completeImageToStreamBeforeCropping[0], data,
|
||||
@@ -505,16 +508,6 @@ void DataProcessor::PadMissingPackets(sls_receiver_header header, char *data) {
|
||||
|
||||
// missing packet
|
||||
switch (generalData->detType) {
|
||||
// for gotthard, 1st packet: 4 bytes fnum, CACA + CACA, 639*2 bytes
|
||||
// data
|
||||
// 2nd packet: 4 bytes fnum, previous 1*2 bytes data +
|
||||
// 640*2 bytes data !!
|
||||
case GOTTHARD:
|
||||
if (pnum == 0u)
|
||||
memset(data + (pnum * dsize), 0xFF, dsize - 2);
|
||||
else
|
||||
memset(data + (pnum * dsize), 0xFF, dsize + 2);
|
||||
break;
|
||||
case CHIPTESTBOARD:
|
||||
case XILINX_CHIPTESTBOARD:
|
||||
if (pnum == (pperFrame - 1))
|
||||
@@ -530,11 +523,53 @@ void DataProcessor::PadMissingPackets(sls_receiver_header header, char *data) {
|
||||
}
|
||||
}
|
||||
|
||||
void DataProcessor::RemoveTrailingBits(size_t &size, char *data) {
|
||||
|
||||
if (!(generalData->detType == slsDetectorDefs::CHIPTESTBOARD ||
|
||||
generalData->detType == slsDetectorDefs::XILINX_CHIPTESTBOARD)) {
|
||||
throw std::runtime_error("behavior undefined for detector " +
|
||||
std::to_string(generalData->detType));
|
||||
}
|
||||
|
||||
const size_t nAnalogDataBytes = generalData->GetNumberOfAnalogDatabytes();
|
||||
const size_t nDigitalDataBytes = generalData->GetNumberOfDigitalDatabytes();
|
||||
const size_t nTransceiverDataBytes =
|
||||
generalData->GetNumberOfTransceiverDatabytes();
|
||||
const size_t ctbDbitOffset = generalData->ctbDbitOffset;
|
||||
|
||||
const size_t ctbDigitalDataBytes = nDigitalDataBytes - ctbDbitOffset;
|
||||
|
||||
// no digital data
|
||||
if (ctbDigitalDataBytes == 0) {
|
||||
LOG(logWARNING)
|
||||
<< "No digital data for call back, yet ctbDbitOffset is non zero.";
|
||||
return;
|
||||
}
|
||||
|
||||
// update size and copy data
|
||||
memmove(data + nAnalogDataBytes, data + nAnalogDataBytes + ctbDbitOffset,
|
||||
ctbDigitalDataBytes + nTransceiverDataBytes);
|
||||
|
||||
size = nAnalogDataBytes + ctbDigitalDataBytes + nTransceiverDataBytes;
|
||||
}
|
||||
|
||||
/** ctb specific */
|
||||
void DataProcessor::RearrangeDbitData(size_t &size, char *data) {
|
||||
int nAnalogDataBytes = generalData->GetNumberOfAnalogDatabytes();
|
||||
int nDigitalDataBytes = generalData->GetNumberOfDigitalDatabytes();
|
||||
int nTransceiverDataBytes = generalData->GetNumberOfTransceiverDatabytes();
|
||||
void DataProcessor::ArrangeDbitData(size_t &size, char *data) {
|
||||
|
||||
if (!(generalData->detType == slsDetectorDefs::CHIPTESTBOARD ||
|
||||
generalData->detType == slsDetectorDefs::XILINX_CHIPTESTBOARD)) {
|
||||
throw std::runtime_error("behavior undefined for detector " +
|
||||
std::to_string(generalData->detType));
|
||||
}
|
||||
|
||||
const size_t nAnalogDataBytes = generalData->GetNumberOfAnalogDatabytes();
|
||||
const size_t nDigitalDataBytes = generalData->GetNumberOfDigitalDatabytes();
|
||||
const size_t nTransceiverDataBytes =
|
||||
generalData->GetNumberOfTransceiverDatabytes();
|
||||
const size_t ctbDbitOffset = generalData->ctbDbitOffset;
|
||||
const bool ctbDbitReorder = generalData->ctbDbitReorder;
|
||||
const auto ctbDbitList = generalData->ctbDbitList;
|
||||
|
||||
// TODO! (Erik) Refactor and add tests
|
||||
int ctbDigitalDataBytes = nDigitalDataBytes - ctbDbitOffset;
|
||||
|
||||
@@ -545,61 +580,115 @@ void DataProcessor::RearrangeDbitData(size_t &size, char *data) {
|
||||
return;
|
||||
}
|
||||
|
||||
char *source = (data + nAnalogDataBytes + ctbDbitOffset);
|
||||
|
||||
const int numDigitalSamples = (ctbDigitalDataBytes / sizeof(uint64_t));
|
||||
|
||||
// const int numResult8Bits = ceil((numDigitalSamples * ctbDbitList.size())
|
||||
// / 8.00);
|
||||
int numBitsPerDbit = numDigitalSamples;
|
||||
if ((numBitsPerDbit % 8) != 0)
|
||||
numBitsPerDbit += (8 - (numDigitalSamples % 8));
|
||||
const int totalNumBytes = (numBitsPerDbit / 8) * ctbDbitList.size();
|
||||
std::vector<uint8_t> result(totalNumBytes);
|
||||
int totalNumBytes =
|
||||
0; // number of bytes for selected digital data given by dtbDbitList
|
||||
|
||||
// store each selected bit from all samples consecutively
|
||||
if (ctbDbitReorder) {
|
||||
size_t numBitsPerDbit =
|
||||
numDigitalSamples; // num bits per selected digital
|
||||
// Bit for all samples
|
||||
if ((numBitsPerDbit % 8) != 0)
|
||||
numBitsPerDbit += (8 - (numDigitalSamples % 8));
|
||||
totalNumBytes = (numBitsPerDbit / 8) * ctbDbitList.size();
|
||||
}
|
||||
// store all selected bits from one sample consecutively
|
||||
else {
|
||||
size_t numBitsPerSample =
|
||||
ctbDbitList.size(); // num bits for all selected bits per sample
|
||||
if ((numBitsPerSample % 8) != 0)
|
||||
numBitsPerSample += (8 - (numBitsPerSample % 8));
|
||||
totalNumBytes = (numBitsPerSample / 8) * numDigitalSamples;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> result(totalNumBytes, 0);
|
||||
uint8_t *dest = &result[0];
|
||||
|
||||
auto *source = (uint64_t *)(data + nAnalogDataBytes + ctbDbitOffset);
|
||||
|
||||
// loop through digital bit enable vector
|
||||
int bitoffset = 0;
|
||||
for (auto bi : ctbDbitList) {
|
||||
// where numbits * numDigitalSamples is not a multiple of 8
|
||||
if (bitoffset != 0) {
|
||||
bitoffset = 0;
|
||||
++dest;
|
||||
}
|
||||
|
||||
// loop through the frame digital data
|
||||
for (auto *ptr = source; ptr < (source + numDigitalSamples);) {
|
||||
// get selected bit from each 8 bit
|
||||
uint8_t bit = (*ptr++ >> bi) & 1;
|
||||
*dest |= bit << bitoffset;
|
||||
++bitoffset;
|
||||
// extract destination in 8 bit batches
|
||||
if (bitoffset == 8) {
|
||||
if (ctbDbitReorder) {
|
||||
// loop through digital bit enable vector
|
||||
int bitoffset = 0;
|
||||
for (auto bi : ctbDbitList) {
|
||||
// where numbits * numDigitalSamples is not a multiple of 8
|
||||
if (bitoffset != 0) {
|
||||
bitoffset = 0;
|
||||
++dest;
|
||||
}
|
||||
|
||||
uint8_t byte_index = bi / 8;
|
||||
|
||||
// loop through the frame digital data
|
||||
for (auto *ptr = source + byte_index;
|
||||
ptr < (source + 8 * numDigitalSamples); ptr += 8) {
|
||||
// get selected bit from each 8 bit
|
||||
uint8_t bit = (*ptr >> bi % 8) & 1;
|
||||
*dest |= bit << bitoffset; // stored as least significant
|
||||
++bitoffset;
|
||||
// extract destination in 8 bit batches
|
||||
if (bitoffset == 8) {
|
||||
bitoffset = 0;
|
||||
++dest;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// loop through the digital data
|
||||
int bitoffset = 0;
|
||||
for (auto *ptr = source; ptr < (source + 8 * numDigitalSamples);
|
||||
ptr += 8) {
|
||||
// where bit enable vector size is not a multiple of 8
|
||||
if (bitoffset != 0) {
|
||||
bitoffset = 0;
|
||||
++dest;
|
||||
}
|
||||
|
||||
// loop through digital bit enable vector
|
||||
for (auto bi : ctbDbitList) {
|
||||
// get selected bit from each 64 bit
|
||||
uint8_t byte_index = bi / 8;
|
||||
|
||||
uint8_t bit = (*(ptr + byte_index) >> (bi % 8)) & 1;
|
||||
*dest |= bit << bitoffset;
|
||||
++bitoffset;
|
||||
// extract destination in 8 bit batches
|
||||
if (bitoffset == 8) {
|
||||
bitoffset = 0;
|
||||
++dest;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size = totalNumBytes * sizeof(uint8_t) + nAnalogDataBytes +
|
||||
nTransceiverDataBytes;
|
||||
|
||||
// check if size changed, if so move transceiver data to avoid gap in memory
|
||||
if (size != nAnalogDataBytes + nDigitalDataBytes + nTransceiverDataBytes)
|
||||
memmove(data + nAnalogDataBytes + totalNumBytes * sizeof(uint8_t),
|
||||
data + nAnalogDataBytes + nDigitalDataBytes,
|
||||
nTransceiverDataBytes);
|
||||
|
||||
// copy back to memory and update size
|
||||
memcpy(data + nAnalogDataBytes, result.data(),
|
||||
totalNumBytes * sizeof(uint8_t));
|
||||
size = totalNumBytes * sizeof(uint8_t) + nAnalogDataBytes + ctbDbitOffset +
|
||||
nTransceiverDataBytes;
|
||||
LOG(logDEBUG1) << "totalNumBytes: " << totalNumBytes
|
||||
|
||||
LOG(logDEBUG1) << "nDigitalDataBytes: " << totalNumBytes
|
||||
<< " nAnalogDataBytes:" << nAnalogDataBytes
|
||||
<< " ctbDbitOffset:" << ctbDbitOffset
|
||||
<< " nTransceiverDataBytes:" << nTransceiverDataBytes
|
||||
<< " size:" << size;
|
||||
<< " toal size:" << size;
|
||||
}
|
||||
|
||||
void DataProcessor::CropImage(size_t &size, char *data) {
|
||||
LOG(logDEBUG) << "Cropping Image to ROI " << ToString(receiverRoi);
|
||||
LOG(logDEBUG1) << "Cropping Image to ROI " << ToString(portRoi);
|
||||
int nPixelsX = generalData->nPixelsX;
|
||||
int xmin = receiverRoi.xmin;
|
||||
int xmax = receiverRoi.xmax;
|
||||
int ymin = receiverRoi.ymin;
|
||||
int ymax = receiverRoi.ymax;
|
||||
int xmin = portRoi.xmin;
|
||||
int xmax = portRoi.xmax;
|
||||
int ymin = portRoi.ymin;
|
||||
int ymax = portRoi.ymax;
|
||||
int xwidth = xmax - xmin + 1;
|
||||
int ywidth = ymax - ymin + 1;
|
||||
if (ymin == -1 || ymax == -1) {
|
||||
|
||||
@@ -39,14 +39,13 @@ class DataProcessor : private virtual slsDetectorDefs, public ThreadObject {
|
||||
|
||||
void SetUdpPortNumber(const uint16_t portNumber);
|
||||
void SetActivate(bool enable);
|
||||
void SetReceiverROI(ROI roi);
|
||||
void SetPortROI(const ROI arg);
|
||||
void setMultiROIMetadata(const std::vector<slsDetectorDefs::ROI> &args);
|
||||
void SetDataStreamEnable(bool enable);
|
||||
void SetStreamingFrequency(uint32_t value);
|
||||
void SetStreamingTimerInMs(uint32_t value);
|
||||
void SetStreamingStartFnum(uint32_t value);
|
||||
void SetFramePadding(bool enable);
|
||||
void SetCtbDbitList(std::vector<int> value);
|
||||
void SetCtbDbitOffset(int value);
|
||||
void SetQuadEnable(bool value);
|
||||
void SetFlipRows(bool fd);
|
||||
void SetNumberofTotalFrames(uint64_t value);
|
||||
@@ -71,7 +70,7 @@ class DataProcessor : private virtual slsDetectorDefs, public ThreadObject {
|
||||
const bool overWriteEnable,
|
||||
const bool silentMode, const int modulePos,
|
||||
const int numModX, const int numModY,
|
||||
std::mutex *hdf5LibMutex);
|
||||
std::mutex *hdf5LibMutex, bool gotthard25um);
|
||||
void LinkFileInMaster(const std::string &masterFileName,
|
||||
const std::string &virtualFileName,
|
||||
const bool silentMode, std::mutex *hdf5LibMutex);
|
||||
@@ -91,6 +90,20 @@ class DataProcessor : private virtual slsDetectorDefs, public ThreadObject {
|
||||
size_t &, void *),
|
||||
void *arg);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Align corresponding digital bits together (CTB only if ctbDbitlist is not
|
||||
* empty)
|
||||
* set variable reorder to true if data should be rearranged such that
|
||||
* it groups each signal (0-63) from all the different samples together
|
||||
*/
|
||||
void ArrangeDbitData(size_t &size, char *data);
|
||||
|
||||
/**
|
||||
* remove trailing bits in digital data stream
|
||||
*/
|
||||
void RemoveTrailingBits(size_t &size, char *data);
|
||||
|
||||
private:
|
||||
void RecordFirstIndex(uint64_t fnum);
|
||||
|
||||
@@ -137,12 +150,6 @@ class DataProcessor : private virtual slsDetectorDefs, public ThreadObject {
|
||||
|
||||
void PadMissingPackets(sls_receiver_header header, char *data);
|
||||
|
||||
/**
|
||||
* Align corresponding digital bits together (CTB only if ctbDbitlist is not
|
||||
* empty)
|
||||
*/
|
||||
void RearrangeDbitData(size_t &size, char *data);
|
||||
|
||||
void CropImage(size_t &size, char *data);
|
||||
|
||||
static const std::string typeName;
|
||||
@@ -153,9 +160,11 @@ class DataProcessor : private virtual slsDetectorDefs, public ThreadObject {
|
||||
uint16_t udpPortNumber{0};
|
||||
bool dataStreamEnable;
|
||||
bool activated{false};
|
||||
ROI receiverRoi{};
|
||||
bool receiverRoiEnabled{false};
|
||||
bool receiverNoRoi{false};
|
||||
ROI portRoi{};
|
||||
bool isPartiallyInRoi{false};
|
||||
bool isOutsideRoi{false};
|
||||
std::vector<ROI> multiRoiMetadata{};
|
||||
|
||||
std::unique_ptr<char[]> completeImageToStreamBeforeCropping;
|
||||
/** if 0, sending random images with a timer */
|
||||
uint32_t streamingFrequency;
|
||||
@@ -164,8 +173,6 @@ class DataProcessor : private virtual slsDetectorDefs, public ThreadObject {
|
||||
uint32_t currentFreqCount{0};
|
||||
struct timespec timerbegin {};
|
||||
bool framePadding;
|
||||
std::vector<int> ctbDbitList;
|
||||
int ctbDbitOffset;
|
||||
std::atomic<bool> startedFlag{false};
|
||||
std::atomic<uint64_t> firstIndex{0};
|
||||
bool quadEnable{false};
|
||||
|
||||
@@ -22,10 +22,7 @@ DataStreamer::DataStreamer(int index) : ThreadObject(index, TypeName) {
|
||||
LOG(logDEBUG) << "DataStreamer " << index << " created";
|
||||
}
|
||||
|
||||
DataStreamer::~DataStreamer() {
|
||||
CloseZmqSocket();
|
||||
delete[] completeBuffer;
|
||||
}
|
||||
DataStreamer::~DataStreamer() { CloseZmqSocket(); }
|
||||
|
||||
void DataStreamer::SetFifo(Fifo *f) { fifo = f; }
|
||||
|
||||
@@ -56,25 +53,20 @@ void DataStreamer::SetAdditionalJsonHeader(
|
||||
isAdditionalJsonUpdated = true;
|
||||
}
|
||||
|
||||
void DataStreamer::SetReceiverROI(ROI roi) { receiverRoi = roi; }
|
||||
void DataStreamer::SetPortROI(ROI roi) {
|
||||
if (roi.completeRoi()) { // TODO: just not send zmq if not in roi?
|
||||
portRoi =
|
||||
ROI(0, generalData->nPixelsX - 1, 0, generalData->nPixelsY - 1);
|
||||
} else {
|
||||
portRoi = roi;
|
||||
}
|
||||
}
|
||||
|
||||
void DataStreamer::ResetParametersforNewAcquisition(const std::string &fname) {
|
||||
StopRunning();
|
||||
startedFlag = false;
|
||||
firstIndex = 0;
|
||||
|
||||
fileNametoStream = fname;
|
||||
if (completeBuffer) {
|
||||
delete[] completeBuffer;
|
||||
completeBuffer = nullptr;
|
||||
}
|
||||
if (generalData->detType == GOTTHARD &&
|
||||
generalData->detectorRoi.xmin != -1) {
|
||||
adcConfigured =
|
||||
generalData->GetAdcConfigured(index, generalData->detectorRoi);
|
||||
completeBuffer = new char[generalData->imageSizeComplete];
|
||||
memset(completeBuffer, 0, generalData->imageSizeComplete);
|
||||
}
|
||||
}
|
||||
|
||||
void DataStreamer::RecordFirstIndex(uint64_t fnum, size_t firstImageIndex) {
|
||||
@@ -160,40 +152,15 @@ void DataStreamer::ProcessAnImage(sls_detector_header header, size_t size,
|
||||
uint64_t fnum = header.frameNumber;
|
||||
LOG(logDEBUG1) << "DataStreamer " << index << ": fnum:" << fnum;
|
||||
|
||||
// shortframe gotthard
|
||||
if (completeBuffer) {
|
||||
// disregarding the size modified from callback (always using
|
||||
// imageSizeComplete instead of size because gui needs
|
||||
// imagesizecomplete and listener writes imagesize to size
|
||||
|
||||
if (!SendDataHeader(header, generalData->imageSizeComplete,
|
||||
generalData->nPixelsXComplete,
|
||||
generalData->nPixelsYComplete)) {
|
||||
LOG(logERROR) << "Could not send zmq header for fnum " << fnum
|
||||
<< " and streamer " << index;
|
||||
}
|
||||
memcpy(completeBuffer + ((generalData->imageSize) * adcConfigured),
|
||||
data, size);
|
||||
|
||||
if (!zmqSocket->SendData(completeBuffer,
|
||||
generalData->imageSizeComplete)) {
|
||||
LOG(logERROR) << "Could not send zmq data for fnum " << fnum
|
||||
<< " and streamer " << index;
|
||||
}
|
||||
if (!SendDataHeader(header, size, generalData->nPixelsX,
|
||||
generalData->nPixelsY)) {
|
||||
LOG(logERROR) << "Could not send zmq header for fnum " << fnum
|
||||
<< " and streamer " << index;
|
||||
}
|
||||
|
||||
// normal
|
||||
else {
|
||||
|
||||
if (!SendDataHeader(header, size, generalData->nPixelsX,
|
||||
generalData->nPixelsY)) {
|
||||
LOG(logERROR) << "Could not send zmq header for fnum " << fnum
|
||||
<< " and streamer " << index;
|
||||
}
|
||||
if (!zmqSocket->SendData(data, size)) {
|
||||
LOG(logERROR) << "Could not send zmq data for fnum " << fnum
|
||||
<< " and streamer " << index;
|
||||
}
|
||||
if (!zmqSocket->SendData(data, size)) {
|
||||
LOG(logERROR) << "Could not send zmq data for fnum " << fnum
|
||||
<< " and streamer " << index;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -250,7 +217,7 @@ int DataStreamer::SendDataHeader(sls_detector_header header, uint32_t size,
|
||||
isAdditionalJsonUpdated = false;
|
||||
}
|
||||
zHeader.addJsonHeader = localAdditionalJsonHeader;
|
||||
zHeader.rx_roi = receiverRoi.getIntArray();
|
||||
zHeader.rx_roi = portRoi.getIntArray();
|
||||
|
||||
return zmqSocket->SendHeader(index, zHeader);
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ class DataStreamer : private virtual slsDetectorDefs, public ThreadObject {
|
||||
void SetNumberofTotalFrames(uint64_t value);
|
||||
void
|
||||
SetAdditionalJsonHeader(const std::map<std::string, std::string> &json);
|
||||
void SetReceiverROI(ROI roi);
|
||||
void SetPortROI(ROI roi);
|
||||
|
||||
void ResetParametersforNewAcquisition(const std::string &fname);
|
||||
/**
|
||||
@@ -88,11 +88,10 @@ class DataStreamer : private virtual slsDetectorDefs, public ThreadObject {
|
||||
const GeneralData *generalData{nullptr};
|
||||
Fifo *fifo{nullptr};
|
||||
ZmqSocket *zmqSocket{nullptr};
|
||||
int adcConfigured{-1};
|
||||
uint64_t fileIndex{0};
|
||||
bool flipRows{false};
|
||||
std::map<std::string, std::string> additionalJsonHeader;
|
||||
ROI receiverRoi{};
|
||||
ROI portRoi{};
|
||||
|
||||
/** Used by streamer thread to update local copy (reduce number of locks
|
||||
* during streaming) */
|
||||
@@ -107,8 +106,6 @@ class DataStreamer : private virtual slsDetectorDefs, public ThreadObject {
|
||||
bool startedFlag{false};
|
||||
uint64_t firstIndex{0};
|
||||
std::string fileNametoStream;
|
||||
/** Complete buffer used for detectorRoi, eg. shortGotthard */
|
||||
char *completeBuffer{nullptr};
|
||||
|
||||
xy numPorts{1, 1};
|
||||
bool quadEnable{false};
|
||||
|
||||
@@ -5,17 +5,17 @@
|
||||
* reconstructing image. Sample python script for pull socket for this combiner
|
||||
* in python/scripts folder. TODO: Not handling empty frames from one socket
|
||||
*/
|
||||
#include "CommandLineOptions.h"
|
||||
#include "sls/Receiver.h"
|
||||
#include "sls/ToString.h"
|
||||
#include "sls/container_utils.h"
|
||||
#include "sls/logger.h"
|
||||
#include "sls/network_utils.h"
|
||||
#include "sls/sls_detector_defs.h"
|
||||
#include "sls/versionAPI.h"
|
||||
|
||||
#include <csignal> //SIGINT
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <mutex>
|
||||
#include <ostream>
|
||||
#include <semaphore.h>
|
||||
@@ -29,9 +29,14 @@
|
||||
#include <zmq.h>
|
||||
|
||||
std::vector<std::thread> threads;
|
||||
std::vector<sem_t *> semaphores;
|
||||
sls::TLogLevel printHeadersLevel = sls::logDEBUG;
|
||||
|
||||
// gettid added in glibc 2.30
|
||||
#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 30
|
||||
#include <sys/syscall.h>
|
||||
#define gettid() syscall(SYS_gettid)
|
||||
#endif
|
||||
|
||||
/** Define Colors to print data call back in different colors for different
|
||||
* recievers */
|
||||
#define PRINT_IN_COLOR(c, f, ...) \
|
||||
@@ -58,16 +63,6 @@ struct FrameStatus {
|
||||
};
|
||||
FrameStatus *global_frame_status = nullptr;
|
||||
|
||||
/**
|
||||
* Control+C Interrupt Handler
|
||||
* to let all the processes know to exit properly
|
||||
*/
|
||||
void sigInterruptHandler(int p) {
|
||||
for (size_t i = 0; i != semaphores.size(); ++i) {
|
||||
sem_post(semaphores[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void cleanup() {
|
||||
if (global_frame_status) {
|
||||
std::lock_guard<std::mutex> lock(global_frame_status->mtx);
|
||||
@@ -87,21 +82,6 @@ void cleanup() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* prints usage of this example program
|
||||
*/
|
||||
std::string getHelpMessage() {
|
||||
std::ostringstream os;
|
||||
os << "\nUsage:\n"
|
||||
<< "./slsFrameSynchronizer --version or -v\n"
|
||||
<< "\t - Gets the slsFrameSynchronizer version\n\n"
|
||||
<< "./slsFrameSynchronizer [start tcp port] [num recevers] [print "
|
||||
"callback headers (optional)]\n"
|
||||
<< "\t - tcp port has to be non-zero and 16 bit\n"
|
||||
<< "\t - print callback headers option is 0 (disabled) by default\n";
|
||||
return os.str();
|
||||
}
|
||||
|
||||
void zmq_free(void *data, void *hint) { delete[] static_cast<char *>(data); }
|
||||
|
||||
void print_frames(const PortFrameMap &frame_port_map) {
|
||||
@@ -282,7 +262,7 @@ void Correlate(FrameStatus *stat) {
|
||||
zmq_ctx_destroy(context);
|
||||
}
|
||||
|
||||
int StartAcquisitionCallback(
|
||||
void StartAcquisitionCallback(
|
||||
const slsDetectorDefs::startCallbackHeader callbackHeader,
|
||||
void *objectPointer) {
|
||||
LOG(printHeadersLevel)
|
||||
@@ -354,7 +334,6 @@ int StartAcquisitionCallback(
|
||||
}
|
||||
}
|
||||
sem_post(&stat->available);
|
||||
return slsDetectorDefs::OK; // TODO: change return to void
|
||||
}
|
||||
|
||||
void AcquisitionFinishedCallback(
|
||||
@@ -516,93 +495,46 @@ void GetDataCallback(slsDetectorDefs::sls_receiver_header &header,
|
||||
sem_post(&stat->available);
|
||||
}
|
||||
|
||||
std::vector<sem_t> semaphores;
|
||||
|
||||
/**
|
||||
* Example of main program using the Receiver class
|
||||
*
|
||||
* - Defines in file for:
|
||||
* - Default Number of receivers is 1
|
||||
* - Default Start TCP port is 1954
|
||||
* Control+C Interrupt Handler
|
||||
* to let all the processes know to exit properly
|
||||
* Only the main thread will call this handler
|
||||
*/
|
||||
void sigInterruptHandler(int p) {
|
||||
(void)signal; // suppress unused warning if needed
|
||||
for (auto &s : semaphores) {
|
||||
sem_post(&s);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
// version
|
||||
if (argc == 2) {
|
||||
std::string sargv1 = std::string(argv[1]);
|
||||
if (sargv1 == "--version" || sargv1 == "-v") {
|
||||
std::cout << "slsFrameSynchronizer Version: " << APIRECEIVER
|
||||
<< std::endl;
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
CommandLineOptions cli(AppType::FrameSynchronizer);
|
||||
ParsedOptions opts;
|
||||
try {
|
||||
opts = cli.parse(argc, argv);
|
||||
} catch (sls::RuntimeError &e) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
auto &f = std::get<FrameSyncOptions>(opts);
|
||||
if (f.versionRequested || f.helpRequested) {
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
/** - set default values */
|
||||
int numReceivers = 1;
|
||||
uint16_t startTCPPort = DEFAULT_TCP_RX_PORTNO;
|
||||
bool printHeaders = false;
|
||||
LOG(sls::logINFOBLUE) << "Current Process [ Tid: " << gettid() << ']';
|
||||
|
||||
/** - get number of receivers and start tcp port from command line
|
||||
* arguments */
|
||||
if (argc > 1) {
|
||||
try {
|
||||
if (argc == 3 || argc == 4) {
|
||||
startTCPPort = sls::StringTo<uint16_t>(argv[1]);
|
||||
if (startTCPPort == 0) {
|
||||
throw std::runtime_error("Invalid start tcp port");
|
||||
}
|
||||
numReceivers = std::stoi(argv[2]);
|
||||
if (numReceivers > 1024) {
|
||||
cprintf(RED,
|
||||
"Did you mix up the order of the arguments?\n%s\n",
|
||||
getHelpMessage().c_str());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (numReceivers == 0) {
|
||||
cprintf(RED, "Invalid number of receivers.\n%s\n",
|
||||
getHelpMessage().c_str());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (argc == 4) {
|
||||
printHeaders = sls::StringTo<bool>(argv[3]);
|
||||
if (printHeaders) {
|
||||
printHeadersLevel = sls::logINFOBLUE;
|
||||
}
|
||||
}
|
||||
} else
|
||||
throw std::runtime_error("Invalid number of arguments");
|
||||
} catch (const std::exception &e) {
|
||||
cprintf(RED, "Error: %s\n%s\n", e.what(), getHelpMessage().c_str());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
// close files on ctrl+c
|
||||
sls::setupSignalHandler(SIGINT, sigInterruptHandler);
|
||||
// handle locally on socket crash
|
||||
sls::setupSignalHandler(SIGPIPE, SIG_IGN);
|
||||
|
||||
semaphores.resize(f.numReceivers);
|
||||
for (auto &s : semaphores) {
|
||||
sem_init(&s, 0, 0);
|
||||
}
|
||||
|
||||
cprintf(RESET, "Number of Receivers: %d\n", numReceivers);
|
||||
cprintf(RESET, "Start TCP Port: %hu\n", startTCPPort);
|
||||
cprintf(RESET, "Print Callback Headers: %s\n\n",
|
||||
(printHeaders ? "Enabled" : "Disabled"));
|
||||
|
||||
/** - Catch signal SIGINT to close files and call destructors properly */
|
||||
struct sigaction sa;
|
||||
sa.sa_flags = 0; // no flags
|
||||
sa.sa_handler = sigInterruptHandler; // handler function
|
||||
sigemptyset(&sa.sa_mask); // dont block additional signals during invocation
|
||||
// of handler
|
||||
if (sigaction(SIGINT, &sa, nullptr) == -1) {
|
||||
cprintf(RED, "Could not set handler function for SIGINT\n");
|
||||
}
|
||||
|
||||
/** - Ignore SIG_PIPE, prevents global signal handler, handle locally,
|
||||
instead of a server crashing due to client crash when writing, it just
|
||||
gives error */
|
||||
struct sigaction asa;
|
||||
asa.sa_flags = 0; // no flags
|
||||
asa.sa_handler = SIG_IGN; // handler function
|
||||
sigemptyset(&asa.sa_mask); // dont block additional signals during
|
||||
// invocation of handler
|
||||
if (sigaction(SIGPIPE, &asa, nullptr) == -1) {
|
||||
cprintf(RED, "Could not set handler function for SIGPIPE\n");
|
||||
}
|
||||
|
||||
FrameStatus stat{true, false, numReceivers};
|
||||
FrameStatus stat{true, false, f.numReceivers};
|
||||
// store pointer for signal handler
|
||||
global_frame_status = &stat;
|
||||
|
||||
@@ -610,34 +542,44 @@ int main(int argc, char *argv[]) {
|
||||
void *user_data = static_cast<void *>(&stat);
|
||||
std::thread combinerThread(Correlate, &stat);
|
||||
|
||||
for (int i = 0; i != numReceivers; ++i) {
|
||||
sem_t *semaphore = new sem_t;
|
||||
sem_init(semaphore, 1, 0);
|
||||
semaphores.push_back(semaphore);
|
||||
std::exception_ptr threadException = nullptr;
|
||||
for (int i = 0; i != f.numReceivers; ++i) {
|
||||
uint16_t port = f.port + i;
|
||||
sem_t *semaphore = &semaphores[i];
|
||||
threads.emplace_back(
|
||||
[i, semaphore, port, user_data, &threadException]() {
|
||||
LOG(sls::logINFOBLUE)
|
||||
<< "Thread " << i << " [ Tid: " << gettid() << ']';
|
||||
try {
|
||||
sls::Receiver receiver(port);
|
||||
receiver.registerCallBackStartAcquisition(
|
||||
StartAcquisitionCallback, user_data);
|
||||
receiver.registerCallBackAcquisitionFinished(
|
||||
AcquisitionFinishedCallback, user_data);
|
||||
receiver.registerCallBackRawDataReady(GetDataCallback,
|
||||
user_data);
|
||||
|
||||
uint16_t port = startTCPPort + i;
|
||||
threads.emplace_back([i, semaphore, port, user_data]() {
|
||||
sls::Receiver receiver(port);
|
||||
receiver.registerCallBackStartAcquisition(StartAcquisitionCallback,
|
||||
user_data);
|
||||
receiver.registerCallBackAcquisitionFinished(
|
||||
AcquisitionFinishedCallback, user_data);
|
||||
receiver.registerCallBackRawDataReady(GetDataCallback, user_data);
|
||||
/** - as long as no Ctrl+C */
|
||||
sem_wait(semaphore);
|
||||
sem_destroy(semaphore);
|
||||
delete semaphore;
|
||||
|
||||
// clean up frames
|
||||
if (i == 0)
|
||||
cleanup();
|
||||
});
|
||||
/** - as long as no Ctrl+C */
|
||||
// each child shares the common semaphore
|
||||
sem_wait(semaphore);
|
||||
} catch (...) {
|
||||
// capture exception and raise SIGINT to exit gracefully
|
||||
threadException = std::current_exception();
|
||||
raise(SIGINT);
|
||||
}
|
||||
LOG(sls::logINFOBLUE)
|
||||
<< "Exiting Thread " << i << " [ Tid: " << gettid() << " ]";
|
||||
});
|
||||
}
|
||||
|
||||
for (auto &thread : threads) {
|
||||
thread.join();
|
||||
for (auto &t : threads) {
|
||||
t.join();
|
||||
}
|
||||
|
||||
for (auto &s : semaphores)
|
||||
sem_destroy(&s);
|
||||
cleanup();
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(stat.mtx);
|
||||
stat.terminate = true;
|
||||
@@ -646,6 +588,19 @@ int main(int argc, char *argv[]) {
|
||||
combinerThread.join();
|
||||
sem_destroy(&stat.available);
|
||||
|
||||
if (threadException) {
|
||||
try {
|
||||
std::rethrow_exception(threadException);
|
||||
} catch (const std::exception &e) {
|
||||
LOG(sls::logERROR)
|
||||
<< "Unhandled exception from thread: " << e.what();
|
||||
return EXIT_FAILURE;
|
||||
} catch (...) {
|
||||
LOG(sls::logERROR) << "Unknown exception occurred in thread";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
LOG(sls::logINFOBLUE) << "Goodbye!";
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -18,6 +18,135 @@
|
||||
|
||||
namespace sls {
|
||||
|
||||
struct CtbImageInputs {
|
||||
slsDetectorDefs::readoutMode mode{slsDetectorDefs::ANALOG_ONLY};
|
||||
int nAnalogSamples{};
|
||||
uint32_t adcMask{};
|
||||
int nTransceiverSamples{};
|
||||
uint32_t transceiverMask{};
|
||||
int nDigitalSamples{};
|
||||
int dbitOffset{};
|
||||
bool dbitReorder{};
|
||||
std::vector<int> dbitList{};
|
||||
|
||||
inline void print() const {
|
||||
LOG(logINFO) << "CTB Image Inputs: "
|
||||
<< "Readout Mode:" << ToString(mode)
|
||||
<< "\n\tNumber of Analog Samples:" << nAnalogSamples
|
||||
<< "\n\tADC Enable 1G:" << std::hex << adcMask << std::dec
|
||||
<< "\n\tNumber of Transceiver Samples:"
|
||||
<< nTransceiverSamples
|
||||
<< "\n\tTransceiver Mask:" << std::hex << transceiverMask
|
||||
<< std::dec
|
||||
<< "\n\tNumber of Digital Samples:" << nDigitalSamples
|
||||
<< "\n\tDBIT Offset:" << dbitOffset
|
||||
<< "\n\tDBIT Reorder:" << dbitReorder
|
||||
<< "\n\tDBIT List:" << ToString(dbitList);
|
||||
}
|
||||
};
|
||||
|
||||
struct CtbImageOutputs {
|
||||
int nAnalogBytes{};
|
||||
int nDigitalBytes{};
|
||||
int nDigitalBytesReserved{}; // including dbit offset and for 64 bits
|
||||
int nTransceiverBytes{};
|
||||
int nPixelsX{};
|
||||
|
||||
inline void print() const {
|
||||
LOG(logINFO) << "CTB Image Outputs: "
|
||||
<< "\n\tNumber of Analog Bytes:" << nAnalogBytes
|
||||
<< "\n\tNumber of Actual Digital Bytes:" << nDigitalBytes
|
||||
<< "\n\tNumber of Digital Bytes Reserved:"
|
||||
<< nDigitalBytesReserved
|
||||
<< "\n\tNumber of Transceiver Bytes:" << nTransceiverBytes
|
||||
<< "\n\tNumber of Pixels in X:" << nPixelsX;
|
||||
}
|
||||
};
|
||||
|
||||
inline CtbImageOutputs computeCtbImageSize(const CtbImageInputs &in) {
|
||||
CtbImageOutputs out{};
|
||||
constexpr int num_bytes_per_analog_channel = 2;
|
||||
constexpr int num_bytes_per_transceiver_channel = 8;
|
||||
constexpr int max_digital_channels = 64;
|
||||
|
||||
// in.print(); // for debugging
|
||||
|
||||
// analog channels (normal, analog/digital readout)
|
||||
if (in.mode == slsDetectorDefs::ANALOG_ONLY ||
|
||||
in.mode == slsDetectorDefs::ANALOG_AND_DIGITAL) {
|
||||
int nAnalogChans = __builtin_popcount(in.adcMask);
|
||||
|
||||
out.nPixelsX += nAnalogChans;
|
||||
out.nAnalogBytes =
|
||||
nAnalogChans * num_bytes_per_analog_channel * in.nAnalogSamples;
|
||||
LOG(logDEBUG1) << " Number of Analog Channels:" << nAnalogChans
|
||||
<< " Databytes: " << out.nAnalogBytes;
|
||||
}
|
||||
|
||||
// digital channels
|
||||
if (in.mode == slsDetectorDefs::DIGITAL_ONLY ||
|
||||
in.mode == slsDetectorDefs::ANALOG_AND_DIGITAL ||
|
||||
in.mode == slsDetectorDefs::DIGITAL_AND_TRANSCEIVER) {
|
||||
|
||||
int nSamples = in.nDigitalSamples;
|
||||
{
|
||||
// allocate enought for 64 bits and dbit offset for now
|
||||
// TODO: to be replaced in the future with the actual reserved and
|
||||
// used
|
||||
int32_t num_bytes_per_bit =
|
||||
(nSamples % 8 == 0) ? (nSamples / 8) : (nSamples / 8 + 1);
|
||||
out.nDigitalBytesReserved =
|
||||
max_digital_channels * num_bytes_per_bit;
|
||||
LOG(logDEBUG1) << "Number of Digital Channels:"
|
||||
<< max_digital_channels << " Databytes reserved: "
|
||||
<< out.nDigitalBytesReserved;
|
||||
}
|
||||
|
||||
// remove offset
|
||||
if (in.dbitOffset > 0) {
|
||||
int nBytesReserved = out.nDigitalBytesReserved - in.dbitOffset;
|
||||
nSamples = nBytesReserved / sizeof(uint64_t);
|
||||
}
|
||||
// calculate channels
|
||||
int nChans = in.dbitList.size();
|
||||
if (nChans == 0) {
|
||||
nChans = max_digital_channels;
|
||||
}
|
||||
out.nPixelsX += nChans;
|
||||
|
||||
// calculate actual bytes
|
||||
if (!in.dbitReorder) {
|
||||
uint32_t nBitsPerSample = nChans;
|
||||
if (nBitsPerSample % 8 != 0) {
|
||||
nBitsPerSample += (8 - (nBitsPerSample % 8));
|
||||
}
|
||||
out.nDigitalBytes = (nBitsPerSample / 8) * nSamples;
|
||||
} else {
|
||||
uint32_t nBitsPerSignal = nSamples;
|
||||
if (nBitsPerSignal % 8 != 0) {
|
||||
nBitsPerSignal += (8 - (nBitsPerSignal % 8));
|
||||
}
|
||||
out.nDigitalBytes = nChans * (nBitsPerSignal / 8);
|
||||
}
|
||||
LOG(logDEBUG1) << "Number of Actual Digital Channels:" << nChans
|
||||
<< " Databytes: " << out.nDigitalBytes;
|
||||
}
|
||||
|
||||
// transceiver channels
|
||||
if (in.mode == slsDetectorDefs::TRANSCEIVER_ONLY ||
|
||||
in.mode == slsDetectorDefs::DIGITAL_AND_TRANSCEIVER) {
|
||||
int nTransceiverChans = __builtin_popcount(in.transceiverMask);
|
||||
|
||||
out.nPixelsX += nTransceiverChans;
|
||||
out.nTransceiverBytes = nTransceiverChans *
|
||||
num_bytes_per_transceiver_channel *
|
||||
in.nTransceiverSamples;
|
||||
LOG(logDEBUG1) << "Number of Transceiver Channels:" << nTransceiverChans
|
||||
<< " Databytes: " << out.nTransceiverBytes;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
class GeneralData {
|
||||
|
||||
public:
|
||||
@@ -40,13 +169,6 @@ class GeneralData {
|
||||
uint32_t fifoDepth{0};
|
||||
int numUDPInterfaces{1};
|
||||
uint32_t headerPacketSize{0};
|
||||
/** Streaming (for ROI - mainly short Gotthard) */
|
||||
uint32_t nPixelsXComplete{0};
|
||||
/** Streaming (for ROI - mainly short Gotthard) */
|
||||
uint32_t nPixelsYComplete{0};
|
||||
/** Streaming (for ROI - mainly short Gotthard) - Image size (in bytes) */
|
||||
uint32_t imageSizeComplete{0};
|
||||
/** if standard header implemented in firmware */
|
||||
bool standardheader{false};
|
||||
uint32_t udpSocketBufferSize{RECEIVE_SOCKET_BUFFER_SIZE};
|
||||
uint32_t vetoDataSize{0};
|
||||
@@ -59,15 +181,18 @@ class GeneralData {
|
||||
uint32_t nAnalogSamples{0};
|
||||
uint32_t nDigitalSamples{0};
|
||||
uint32_t nTransceiverSamples{0};
|
||||
std::vector<int> ctbDbitList{};
|
||||
int ctbDbitOffset{0};
|
||||
bool ctbDbitReorder{false};
|
||||
slsDetectorDefs::readoutMode readoutType{slsDetectorDefs::ANALOG_ONLY};
|
||||
uint32_t adcEnableMaskOneGiga{BIT32_MASK};
|
||||
uint32_t adcEnableMaskTenGiga{BIT32_MASK};
|
||||
slsDetectorDefs::ROI detectorRoi{};
|
||||
uint32_t counterMask{0};
|
||||
uint32_t transceiverMask{0};
|
||||
slsDetectorDefs::frameDiscardPolicy frameDiscardMode{
|
||||
slsDetectorDefs::NO_DISCARD};
|
||||
|
||||
/* actual image size after ctboffset and ctbreorder */
|
||||
uint32_t actualImageSize{0};
|
||||
GeneralData(){};
|
||||
virtual ~GeneralData(){};
|
||||
|
||||
@@ -84,14 +209,12 @@ class GeneralData {
|
||||
* Get Header Infomation (frame number, packet number)
|
||||
* @param index thread index for debugging purposes
|
||||
* @param packetData pointer to data
|
||||
* @param oddStartingPacket odd starting packet (gotthard)
|
||||
* @param frameNumber frame number
|
||||
* @param packetNumber packet number
|
||||
* @param bunchId bunch Id
|
||||
*/
|
||||
virtual void GetHeaderInfo(int index, char *packetData,
|
||||
bool oddStartingPacket, uint64_t &frameNumber,
|
||||
uint32_t &packetNumber,
|
||||
uint64_t &frameNumber, uint32_t &packetNumber,
|
||||
uint64_t &bunchId) const {
|
||||
frameNumber = ((uint32_t)(*((uint32_t *)(packetData))));
|
||||
frameNumber++;
|
||||
@@ -100,16 +223,6 @@ class GeneralData {
|
||||
bunchId = -1;
|
||||
}
|
||||
|
||||
virtual void SetDetectorROI(slsDetectorDefs::ROI i) {
|
||||
ThrowGenericError("SetDetectorROI");
|
||||
};
|
||||
|
||||
/**@returns adc configured */
|
||||
virtual int GetAdcConfigured(int index, slsDetectorDefs::ROI i) const {
|
||||
ThrowGenericError("GetAdcConfigured");
|
||||
return 0;
|
||||
};
|
||||
|
||||
virtual void SetDynamicRange(int dr) {
|
||||
ThrowGenericError("SetDynamicRange");
|
||||
};
|
||||
@@ -118,11 +231,6 @@ class GeneralData {
|
||||
ThrowGenericError("SetTenGigaEnable");
|
||||
};
|
||||
|
||||
virtual bool SetOddStartingPacket(int index, char *packetData) {
|
||||
ThrowGenericError("SetOddStartingPacket");
|
||||
return false;
|
||||
};
|
||||
|
||||
virtual void SetNumberofInterfaces(const int n) {
|
||||
ThrowGenericError("SetNumberofInterfaces");
|
||||
};
|
||||
@@ -173,138 +281,17 @@ class GeneralData {
|
||||
virtual void SetTransceiverEnableMask(int n) {
|
||||
ThrowGenericError("SetTransceiverEnableMask");
|
||||
};
|
||||
};
|
||||
|
||||
class GotthardData : public GeneralData {
|
||||
|
||||
private:
|
||||
const int nChan = 128;
|
||||
const int nChipsPerAdc = 2;
|
||||
|
||||
public:
|
||||
GotthardData() {
|
||||
detType = slsDetectorDefs::GOTTHARD;
|
||||
nPixelsY = 1;
|
||||
headerSizeinPacket = 6;
|
||||
framesPerFile = MAX_FRAMES_PER_FILE;
|
||||
UpdateImageSize();
|
||||
virtual void SetctbDbitOffset(const int n) {
|
||||
ThrowGenericError("SetctbDbitOffset");
|
||||
};
|
||||
|
||||
/**
|
||||
* Get Header Infomation (frame number, packet number)
|
||||
* @param index thread index for debugging purposes
|
||||
* @param packetData pointer to data
|
||||
* @param oddStartingPacket odd starting packet (gotthard)
|
||||
* @param frameNumber frame number
|
||||
* @param packetNumber packet number
|
||||
* @param bunchId bunch Id
|
||||
*/
|
||||
void GetHeaderInfo(int index, char *packetData, bool oddStartingPacket,
|
||||
uint64_t &frameNumber, uint32_t &packetNumber,
|
||||
uint64_t &bunchId) const {
|
||||
if (nPixelsX == 1280) {
|
||||
frameNumber = *reinterpret_cast<uint32_t *>(packetData);
|
||||
if (oddStartingPacket)
|
||||
frameNumber++;
|
||||
packetNumber = frameNumber & packetIndexMask;
|
||||
frameNumber = (frameNumber & frameIndexMask) >> frameIndexOffset;
|
||||
} else {
|
||||
frameNumber = *reinterpret_cast<uint32_t *>(packetData);
|
||||
packetNumber = 0;
|
||||
}
|
||||
bunchId = -1;
|
||||
}
|
||||
|
||||
/** @returns adc configured */
|
||||
int GetAdcConfigured(int index, slsDetectorDefs::ROI i) const {
|
||||
int adc = -1;
|
||||
// single adc
|
||||
if (i.xmin != -1) {
|
||||
// gotthard can have only one adc per detector enabled (or all)
|
||||
// adc = mid value/numchans also for only 1 roi
|
||||
adc = ((((i.xmax) + (i.xmin)) / 2) / (nChan * nChipsPerAdc));
|
||||
if ((adc < 0) || (adc > 4)) {
|
||||
LOG(logWARNING) << index
|
||||
<< ": Deleting ROI. "
|
||||
"Adc value should be between 0 and 4";
|
||||
adc = -1;
|
||||
}
|
||||
}
|
||||
LOG(logINFO) << "Adc Configured: " << adc;
|
||||
return adc;
|
||||
virtual void SetctbDbitList(const std::vector<int> &value) {
|
||||
ThrowGenericError("SetctbDbitList");
|
||||
};
|
||||
|
||||
/**
|
||||
* Set odd starting packet (gotthard)
|
||||
* @param index thread index for debugging purposes
|
||||
* @param packetData pointer to data
|
||||
* @returns true or false for odd starting packet number
|
||||
*/
|
||||
bool SetOddStartingPacket(int index, char *packetData) {
|
||||
bool oddStartingPacket = true;
|
||||
// care only if no roi
|
||||
if (nPixelsX == 1280) {
|
||||
uint32_t fnum = ((uint32_t)(*((uint32_t *)(packetData))));
|
||||
uint32_t firstData = ((uint32_t)(*((uint32_t *)(packetData + 4))));
|
||||
// first packet
|
||||
if (firstData == 0xCACACACA) {
|
||||
// packet number should be 0, but is 1 => so odd starting packet
|
||||
if (fnum & packetIndexMask) {
|
||||
oddStartingPacket = true;
|
||||
} else {
|
||||
oddStartingPacket = false;
|
||||
}
|
||||
}
|
||||
// second packet
|
||||
else {
|
||||
// packet number should be 1, but is 0 => so odd starting packet
|
||||
if (!(fnum & packetIndexMask)) {
|
||||
oddStartingPacket = true;
|
||||
} else {
|
||||
oddStartingPacket = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return oddStartingPacket;
|
||||
};
|
||||
|
||||
void SetDetectorROI(slsDetectorDefs::ROI i) {
|
||||
detectorRoi = i;
|
||||
UpdateImageSize();
|
||||
};
|
||||
|
||||
private:
|
||||
void UpdateImageSize() {
|
||||
|
||||
// all adcs
|
||||
if (detectorRoi.xmin == -1) {
|
||||
nPixelsX = 1280;
|
||||
dataSize = 1280;
|
||||
packetsPerFrame = 2;
|
||||
frameIndexMask = 0xFFFFFFFE;
|
||||
frameIndexOffset = 1;
|
||||
packetIndexMask = 1;
|
||||
framesPerFile = MAX_FRAMES_PER_FILE;
|
||||
nPixelsXComplete = 0;
|
||||
nPixelsYComplete = 0;
|
||||
imageSizeComplete = 0;
|
||||
fifoDepth = 50000;
|
||||
} else {
|
||||
nPixelsX = 256;
|
||||
dataSize = 512;
|
||||
packetsPerFrame = 1;
|
||||
frameIndexMask = 0xFFFFFFFF;
|
||||
frameIndexOffset = 0;
|
||||
packetIndexMask = 0;
|
||||
framesPerFile = SHORT_MAX_FRAMES_PER_FILE;
|
||||
nPixelsXComplete = 1280;
|
||||
nPixelsYComplete = 1;
|
||||
imageSizeComplete = 1280 * 2;
|
||||
fifoDepth = 75000;
|
||||
}
|
||||
imageSize = int(nPixelsX * nPixelsY * GetPixelDepth());
|
||||
packetSize = headerSizeinPacket + dataSize;
|
||||
packetsPerFrame = imageSize / dataSize;
|
||||
virtual void SetctbDbitReorder(const bool reorder) {
|
||||
ThrowGenericError("SetctbDbitReorder");
|
||||
};
|
||||
};
|
||||
|
||||
@@ -339,6 +326,7 @@ class EigerData : public GeneralData {
|
||||
dataSize = (tengigaEnable ? 4096 : 1024);
|
||||
packetSize = headerSizeinPacket + dataSize;
|
||||
imageSize = int(nPixelsX * nPixelsY * GetPixelDepth());
|
||||
actualImageSize = imageSize;
|
||||
packetsPerFrame = imageSize / dataSize;
|
||||
fifoDepth = (dynamicRange == 32 ? 100 : 1000);
|
||||
};
|
||||
@@ -369,6 +357,7 @@ class JungfrauData : public GeneralData {
|
||||
nPixelsX = (256 * 4);
|
||||
nPixelsY = (256 * 2) / numUDPInterfaces;
|
||||
imageSize = int(nPixelsX * nPixelsY * GetPixelDepth());
|
||||
actualImageSize = imageSize;
|
||||
packetsPerFrame = imageSize / dataSize;
|
||||
udpSocketBufferSize = (1000 * 1024 * 1024) / numUDPInterfaces;
|
||||
};
|
||||
@@ -400,6 +389,7 @@ class MoenchData : public GeneralData {
|
||||
nPixelsX = (400);
|
||||
nPixelsY = (400) / numUDPInterfaces;
|
||||
imageSize = int(nPixelsX * nPixelsY * GetPixelDepth());
|
||||
actualImageSize = imageSize;
|
||||
packetsPerFrame = imageSize / dataSize;
|
||||
udpSocketBufferSize = (1000 * 1024 * 1024) / numUDPInterfaces;
|
||||
};
|
||||
@@ -451,6 +441,7 @@ class Mythen3Data : public GeneralData {
|
||||
nPixelsX = (NCHAN * ncounters); // max 1280 channels x 3 counters
|
||||
LOG(logINFO) << "nPixelsX: " << nPixelsX;
|
||||
imageSize = nPixelsX * nPixelsY * GetPixelDepth();
|
||||
actualImageSize = imageSize;
|
||||
|
||||
// 10g
|
||||
if (tengigaEnable) {
|
||||
@@ -502,14 +493,12 @@ class Gotthard2Data : public GeneralData {
|
||||
* Get Header Infomation (frame number, packet number) for veto packets
|
||||
* @param index thread index for debugging purposes
|
||||
* @param packetData pointer to data
|
||||
* @param oddStartingPacket odd starting packet (gotthard)
|
||||
* @param frameNumber frame number
|
||||
* @param packetNumber packet number
|
||||
* @param bunchId bunch Id
|
||||
*/
|
||||
void GetHeaderInfo(int index, char *packetData, bool oddStartingPacket,
|
||||
uint64_t &frameNumber, uint32_t &packetNumber,
|
||||
uint64_t &bunchId) const {
|
||||
void GetHeaderInfo(int index, char *packetData, uint64_t &frameNumber,
|
||||
uint32_t &packetNumber, uint64_t &bunchId) const {
|
||||
frameNumber = *reinterpret_cast<uint64_t *>(packetData);
|
||||
bunchId = *reinterpret_cast<uint64_t *>(packetData + 8);
|
||||
packetNumber = 0;
|
||||
@@ -519,6 +508,7 @@ class Gotthard2Data : public GeneralData {
|
||||
void UpdateImageSize() {
|
||||
packetSize = headerSizeinPacket + dataSize;
|
||||
imageSize = int(nPixelsX * nPixelsY * GetPixelDepth());
|
||||
actualImageSize = imageSize;
|
||||
packetsPerFrame = imageSize / dataSize;
|
||||
vetoPacketSize = vetoHsize + vetoDataSize;
|
||||
vetoImageSize = vetoDataSize * packetsPerFrame;
|
||||
@@ -529,8 +519,6 @@ class Gotthard2Data : public GeneralData {
|
||||
class ChipTestBoardData : public GeneralData {
|
||||
private:
|
||||
const int NCHAN_DIGITAL = 64;
|
||||
const int NUM_BYTES_PER_ANALOG_CHANNEL = 2;
|
||||
const int NUM_BYTES_PER_TRANSCEIVER_CHANNEL = 8;
|
||||
int nAnalogBytes = 0;
|
||||
int nDigitalBytes = 0;
|
||||
int nTransceiverBytes = 0;
|
||||
@@ -539,7 +527,7 @@ class ChipTestBoardData : public GeneralData {
|
||||
/** Constructor */
|
||||
ChipTestBoardData() {
|
||||
detType = slsDetectorDefs::CHIPTESTBOARD;
|
||||
nPixelsY = 1; // number of samples
|
||||
nPixelsY = 1;
|
||||
headerSizeinPacket = sizeof(slsDetectorDefs::sls_detector_header);
|
||||
frameIndexMask = 0xFFFFFF; // 10g
|
||||
frameIndexOffset = 8; // 10g
|
||||
@@ -547,105 +535,110 @@ class ChipTestBoardData : public GeneralData {
|
||||
framesPerFile = CTB_MAX_FRAMES_PER_FILE;
|
||||
fifoDepth = 2500;
|
||||
standardheader = true;
|
||||
ctbDbitReorder = true;
|
||||
UpdateImageSize();
|
||||
};
|
||||
}
|
||||
|
||||
public:
|
||||
int GetNumberOfAnalogDatabytes() { return nAnalogBytes; };
|
||||
int GetNumberOfAnalogDatabytes() { return nAnalogBytes; }
|
||||
|
||||
int GetNumberOfDigitalDatabytes() { return nDigitalBytes; };
|
||||
int GetNumberOfDigitalDatabytes() { return nDigitalBytes; }
|
||||
|
||||
int GetNumberOfTransceiverDatabytes() { return nTransceiverBytes; };
|
||||
int GetNumberOfTransceiverDatabytes() { return nTransceiverBytes; }
|
||||
|
||||
void SetNumberOfAnalogSamples(int n) {
|
||||
nAnalogSamples = n;
|
||||
UpdateImageSize();
|
||||
};
|
||||
}
|
||||
|
||||
void SetNumberOfDigitalSamples(int n) {
|
||||
nDigitalSamples = n;
|
||||
UpdateImageSize();
|
||||
};
|
||||
}
|
||||
|
||||
void SetNumberOfTransceiverSamples(int n) {
|
||||
nTransceiverSamples = n;
|
||||
UpdateImageSize();
|
||||
};
|
||||
}
|
||||
|
||||
void SetctbDbitOffset(const int value) {
|
||||
ctbDbitOffset = value;
|
||||
UpdateImageSize();
|
||||
}
|
||||
|
||||
void SetctbDbitList(const std::vector<int> &value) {
|
||||
ctbDbitList = std::move(value);
|
||||
UpdateImageSize();
|
||||
}
|
||||
|
||||
void SetctbDbitReorder(const bool value) {
|
||||
ctbDbitReorder = value;
|
||||
UpdateImageSize();
|
||||
}
|
||||
|
||||
void SetOneGigaAdcEnableMask(int n) {
|
||||
adcEnableMaskOneGiga = n;
|
||||
UpdateImageSize();
|
||||
};
|
||||
}
|
||||
|
||||
void SetTenGigaAdcEnableMask(int n) {
|
||||
adcEnableMaskTenGiga = n;
|
||||
UpdateImageSize();
|
||||
};
|
||||
}
|
||||
|
||||
void SetTransceiverEnableMask(int n) {
|
||||
transceiverMask = n;
|
||||
UpdateImageSize();
|
||||
};
|
||||
}
|
||||
|
||||
void SetReadoutMode(slsDetectorDefs::readoutMode r) {
|
||||
readoutType = r;
|
||||
UpdateImageSize();
|
||||
};
|
||||
}
|
||||
|
||||
void SetTenGigaEnable(bool tg) {
|
||||
tengigaEnable = tg;
|
||||
UpdateImageSize();
|
||||
};
|
||||
}
|
||||
|
||||
private:
|
||||
void UpdateImageSize() {
|
||||
nAnalogBytes = 0;
|
||||
nDigitalBytes = 0;
|
||||
nTransceiverBytes = 0;
|
||||
int nAnalogChans = 0, nDigitalChans = 0, nTransceiverChans = 0;
|
||||
// used in calculations so cant remove now - TODO: remove later
|
||||
nDigitalBytes = sizeof(uint64_t) * nDigitalSamples;
|
||||
|
||||
// analog channels (normal, analog/digital readout)
|
||||
if (readoutType == slsDetectorDefs::ANALOG_ONLY ||
|
||||
readoutType == slsDetectorDefs::ANALOG_AND_DIGITAL) {
|
||||
uint32_t adcEnableMask =
|
||||
(tengigaEnable ? adcEnableMaskTenGiga : adcEnableMaskOneGiga);
|
||||
nAnalogChans = __builtin_popcount(adcEnableMask);
|
||||
// calculate image size
|
||||
CtbImageInputs inputs{};
|
||||
inputs.mode = readoutType;
|
||||
inputs.nAnalogSamples = nAnalogSamples;
|
||||
inputs.adcMask =
|
||||
tengigaEnable ? adcEnableMaskTenGiga : adcEnableMaskOneGiga;
|
||||
inputs.nTransceiverSamples = nTransceiverSamples;
|
||||
inputs.transceiverMask = transceiverMask;
|
||||
inputs.nDigitalSamples = nDigitalSamples;
|
||||
inputs.dbitOffset = ctbDbitOffset;
|
||||
inputs.dbitList = ctbDbitList;
|
||||
inputs.dbitReorder = ctbDbitReorder;
|
||||
|
||||
nAnalogBytes =
|
||||
nAnalogChans * NUM_BYTES_PER_ANALOG_CHANNEL * nAnalogSamples;
|
||||
LOG(logDEBUG1) << " Number of Analog Channels:" << nAnalogChans
|
||||
<< " Databytes: " << nAnalogBytes;
|
||||
}
|
||||
// digital channels
|
||||
if (readoutType == slsDetectorDefs::DIGITAL_ONLY ||
|
||||
readoutType == slsDetectorDefs::ANALOG_AND_DIGITAL ||
|
||||
readoutType == slsDetectorDefs::DIGITAL_AND_TRANSCEIVER) {
|
||||
nDigitalChans = NCHAN_DIGITAL;
|
||||
nDigitalBytes = (sizeof(uint64_t) * nDigitalSamples);
|
||||
LOG(logDEBUG1) << "Number of Digital Channels:" << nDigitalChans
|
||||
<< " Databytes: " << nDigitalBytes;
|
||||
}
|
||||
// transceiver channels
|
||||
if (readoutType == slsDetectorDefs::TRANSCEIVER_ONLY ||
|
||||
readoutType == slsDetectorDefs::DIGITAL_AND_TRANSCEIVER) {
|
||||
nTransceiverChans = __builtin_popcount(transceiverMask);
|
||||
;
|
||||
nTransceiverBytes = nTransceiverChans *
|
||||
NUM_BYTES_PER_TRANSCEIVER_CHANNEL *
|
||||
nTransceiverSamples;
|
||||
LOG(logDEBUG1) << "Number of Transceiver Channels:"
|
||||
<< nTransceiverChans
|
||||
<< " Databytes: " << nTransceiverBytes;
|
||||
}
|
||||
nPixelsX = nAnalogChans + nDigitalChans + nTransceiverChans;
|
||||
auto out = computeCtbImageSize(inputs);
|
||||
|
||||
nPixelsX = out.nPixelsX;
|
||||
nAnalogBytes = out.nAnalogBytes;
|
||||
nTransceiverBytes = out.nTransceiverBytes;
|
||||
|
||||
imageSize = out.nAnalogBytes + out.nDigitalBytesReserved +
|
||||
out.nTransceiverBytes;
|
||||
// to write to file: after ctb offset and reorder
|
||||
actualImageSize =
|
||||
out.nAnalogBytes + out.nDigitalBytes + out.nTransceiverBytes;
|
||||
LOG(logDEBUG1) << "Actual image size: " << actualImageSize;
|
||||
|
||||
// calculate network parameters
|
||||
dataSize = tengigaEnable ? 8144 : UDP_PACKET_DATA_BYTES;
|
||||
packetSize = headerSizeinPacket + dataSize;
|
||||
imageSize = nAnalogBytes + nDigitalBytes + nTransceiverBytes;
|
||||
packetsPerFrame = ceil((double)imageSize / (double)dataSize);
|
||||
|
||||
LOG(logDEBUG1) << "Total Number of Channels:" << nPixelsX
|
||||
<< " Databytes: " << imageSize;
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
class XilinxChipTestBoardData : public GeneralData {
|
||||
@@ -672,6 +665,7 @@ class XilinxChipTestBoardData : public GeneralData {
|
||||
dataSize = 8144;
|
||||
packetSize = headerSizeinPacket + dataSize;
|
||||
tengigaEnable = true;
|
||||
ctbDbitReorder = true;
|
||||
UpdateImageSize();
|
||||
};
|
||||
|
||||
@@ -697,10 +691,20 @@ class XilinxChipTestBoardData : public GeneralData {
|
||||
UpdateImageSize();
|
||||
};
|
||||
|
||||
void SetOneGigaAdcEnableMask(int n) {
|
||||
adcEnableMaskOneGiga = n;
|
||||
void SetctbDbitOffset(const int value) {
|
||||
ctbDbitOffset = value;
|
||||
UpdateImageSize();
|
||||
};
|
||||
}
|
||||
|
||||
void SetctbDbitList(const std::vector<int> &value) {
|
||||
ctbDbitList = std::move(value);
|
||||
UpdateImageSize();
|
||||
}
|
||||
|
||||
void SetctbDbitReorder(const bool value) {
|
||||
ctbDbitReorder = value;
|
||||
UpdateImageSize();
|
||||
}
|
||||
|
||||
void SetTenGigaAdcEnableMask(int n) {
|
||||
adcEnableMaskTenGiga = n;
|
||||
@@ -719,48 +723,36 @@ class XilinxChipTestBoardData : public GeneralData {
|
||||
|
||||
private:
|
||||
void UpdateImageSize() {
|
||||
nAnalogBytes = 0;
|
||||
nDigitalBytes = 0;
|
||||
nTransceiverBytes = 0;
|
||||
int nAnalogChans = 0, nDigitalChans = 0, nTransceiverChans = 0;
|
||||
// used in calculations so cant remove now - TODO: remove later
|
||||
nDigitalBytes = sizeof(uint64_t) * nDigitalSamples;
|
||||
|
||||
// analog channels (normal, analog/digital readout)
|
||||
if (readoutType == slsDetectorDefs::ANALOG_ONLY ||
|
||||
readoutType == slsDetectorDefs::ANALOG_AND_DIGITAL) {
|
||||
uint32_t adcEnableMask = adcEnableMaskTenGiga;
|
||||
nAnalogChans = __builtin_popcount(adcEnableMask);
|
||||
// calculate image size
|
||||
CtbImageInputs inputs{};
|
||||
inputs.mode = readoutType;
|
||||
inputs.nAnalogSamples = nAnalogSamples;
|
||||
inputs.adcMask = adcEnableMaskTenGiga;
|
||||
inputs.nTransceiverSamples = nTransceiverSamples;
|
||||
inputs.transceiverMask = transceiverMask;
|
||||
inputs.nDigitalSamples = nDigitalSamples;
|
||||
inputs.dbitOffset = ctbDbitOffset;
|
||||
inputs.dbitList = ctbDbitList;
|
||||
inputs.dbitReorder = ctbDbitReorder;
|
||||
|
||||
nAnalogBytes =
|
||||
nAnalogChans * NUM_BYTES_PER_ANALOG_CHANNEL * nAnalogSamples;
|
||||
LOG(logDEBUG1) << " Number of Analog Channels:" << nAnalogChans
|
||||
<< " Databytes: " << nAnalogBytes;
|
||||
}
|
||||
// digital channels
|
||||
if (readoutType == slsDetectorDefs::DIGITAL_ONLY ||
|
||||
readoutType == slsDetectorDefs::ANALOG_AND_DIGITAL ||
|
||||
readoutType == slsDetectorDefs::DIGITAL_AND_TRANSCEIVER) {
|
||||
nDigitalChans = NCHAN_DIGITAL;
|
||||
nDigitalBytes = (sizeof(uint64_t) * nDigitalSamples);
|
||||
LOG(logDEBUG1) << "Number of Digital Channels:" << nDigitalChans
|
||||
<< " Databytes: " << nDigitalBytes;
|
||||
}
|
||||
// transceiver channels
|
||||
if (readoutType == slsDetectorDefs::TRANSCEIVER_ONLY ||
|
||||
readoutType == slsDetectorDefs::DIGITAL_AND_TRANSCEIVER) {
|
||||
nTransceiverChans = __builtin_popcount(transceiverMask);
|
||||
;
|
||||
nTransceiverBytes = nTransceiverChans *
|
||||
NUM_BYTES_PER_TRANSCEIVER_CHANNEL *
|
||||
nTransceiverSamples;
|
||||
LOG(logDEBUG1) << "Number of Transceiver Channels:"
|
||||
<< nTransceiverChans
|
||||
<< " Databytes: " << nTransceiverBytes;
|
||||
}
|
||||
nPixelsX = nAnalogChans + nDigitalChans + nTransceiverChans;
|
||||
auto out = computeCtbImageSize(inputs);
|
||||
|
||||
imageSize = nAnalogBytes + nDigitalBytes + nTransceiverBytes;
|
||||
nPixelsX = out.nPixelsX;
|
||||
nAnalogBytes = out.nAnalogBytes;
|
||||
nTransceiverBytes = out.nTransceiverBytes;
|
||||
|
||||
imageSize = out.nAnalogBytes + out.nDigitalBytesReserved +
|
||||
out.nTransceiverBytes;
|
||||
// to write to file: after ctb offset and reorder
|
||||
actualImageSize =
|
||||
out.nAnalogBytes + out.nDigitalBytes + out.nTransceiverBytes;
|
||||
LOG(logDEBUG1) << "Actual image size: " << actualImageSize;
|
||||
|
||||
// calculate network parameters
|
||||
packetsPerFrame = ceil((double)imageSize / (double)dataSize);
|
||||
|
||||
LOG(logDEBUG1) << "Total Number of Channels:" << nPixelsX
|
||||
<< " Databytes: " << imageSize;
|
||||
};
|
||||
|
||||
@@ -111,7 +111,6 @@ void Implementation::SetupFifoStructure() {
|
||||
void Implementation::setDetectorType(const detectorType d) {
|
||||
|
||||
switch (d) {
|
||||
case GOTTHARD:
|
||||
case EIGER:
|
||||
case JUNGFRAU:
|
||||
case MOENCH:
|
||||
@@ -131,9 +130,6 @@ void Implementation::setDetectorType(const detectorType d) {
|
||||
|
||||
// set detector specific variables
|
||||
switch (d) {
|
||||
case GOTTHARD:
|
||||
generalData = new GotthardData();
|
||||
break;
|
||||
case EIGER:
|
||||
generalData = new EigerData();
|
||||
break;
|
||||
@@ -159,6 +155,9 @@ void Implementation::setDetectorType(const detectorType d) {
|
||||
break;
|
||||
}
|
||||
|
||||
// number of portrois should be equal to number of interfaces
|
||||
ResetRois();
|
||||
|
||||
SetLocalNetworkParameters();
|
||||
SetupFifoStructure();
|
||||
|
||||
@@ -188,7 +187,7 @@ void Implementation::SetupListener(int i) {
|
||||
listener[i]->SetUdpPortNumber(udpPortNum[i]);
|
||||
listener[i]->SetEthernetInterface(eth[i]);
|
||||
listener[i]->SetActivate(activated);
|
||||
listener[i]->SetNoRoi(portRois[i].noRoi());
|
||||
listener[i]->SetIsOutsideRoi(portRois[i].noRoi());
|
||||
listener[i]->SetDetectorDatastream(detectorDataStream[i]);
|
||||
listener[i]->SetSilentMode(silentMode);
|
||||
}
|
||||
@@ -198,14 +197,14 @@ void Implementation::SetupDataProcessor(int i) {
|
||||
dataProcessor[i]->SetGeneralData(generalData);
|
||||
dataProcessor[i]->SetUdpPortNumber(udpPortNum[i]);
|
||||
dataProcessor[i]->SetActivate(activated);
|
||||
dataProcessor[i]->SetReceiverROI(portRois[i]);
|
||||
dataProcessor[i]->SetPortROI(portRois[i]);
|
||||
if (i == 0)
|
||||
dataProcessor[0]->setMultiROIMetadata(multiRoiMetadata);
|
||||
dataProcessor[i]->SetDataStreamEnable(dataStreamEnable);
|
||||
dataProcessor[i]->SetStreamingFrequency(streamingFrequency);
|
||||
dataProcessor[i]->SetStreamingTimerInMs(streamingTimerInMs);
|
||||
dataProcessor[i]->SetStreamingStartFnum(streamingStartFnum);
|
||||
dataProcessor[i]->SetFramePadding(framePadding);
|
||||
dataProcessor[i]->SetCtbDbitList(ctbDbitList);
|
||||
dataProcessor[i]->SetCtbDbitOffset(ctbDbitOffset);
|
||||
dataProcessor[i]->SetQuadEnable(quadEnable);
|
||||
dataProcessor[i]->SetFlipRows(flipRows);
|
||||
dataProcessor[i]->SetNumberofTotalFrames(numberOfTotalFrames);
|
||||
@@ -222,8 +221,7 @@ void Implementation::SetupDataStreamer(int i) {
|
||||
dataStreamer[i]->SetFlipRows(flipRows);
|
||||
dataStreamer[i]->SetNumberofPorts(numPorts);
|
||||
dataStreamer[i]->SetNumberofTotalFrames(numberOfTotalFrames);
|
||||
dataStreamer[i]->SetReceiverROI(
|
||||
portRois[i].completeRoi() ? GetMaxROIPerPort() : portRois[i]);
|
||||
dataStreamer[i]->SetPortROI(portRois[i]);
|
||||
}
|
||||
|
||||
slsDetectorDefs::xy Implementation::getDetectorSize() const {
|
||||
@@ -239,18 +237,13 @@ const slsDetectorDefs::xy Implementation::GetPortGeometry() const {
|
||||
return portGeometry;
|
||||
}
|
||||
|
||||
const slsDetectorDefs::ROI Implementation::GetMaxROIPerPort() const {
|
||||
return slsDetectorDefs::ROI{0, (int)generalData->nPixelsX - 1, 0,
|
||||
(int)generalData->nPixelsY - 1};
|
||||
}
|
||||
|
||||
void Implementation::setDetectorSize(const slsDetectorDefs::xy size) {
|
||||
xy portGeometry = GetPortGeometry();
|
||||
|
||||
std::string log_message = "Detector Size (ports): (";
|
||||
numModules = size;
|
||||
numPorts.x = portGeometry.x * size.x;
|
||||
numPorts.y = portGeometry.y * size.y;
|
||||
numPorts.x = portGeometry.x * numModules.x;
|
||||
numPorts.y = portGeometry.y * numModules.y;
|
||||
if (quadEnable) {
|
||||
numPorts.x = 1;
|
||||
numPorts.y = 2;
|
||||
@@ -407,97 +400,57 @@ void Implementation::setArping(const bool i,
|
||||
}
|
||||
}
|
||||
|
||||
slsDetectorDefs::ROI Implementation::getReceiverROI() const {
|
||||
return receiverRoi;
|
||||
std::vector<slsDetectorDefs::ROI> Implementation::getPortROIs() const {
|
||||
return portRois;
|
||||
}
|
||||
|
||||
void Implementation::setReceiverROI(const slsDetectorDefs::ROI arg) {
|
||||
receiverRoi = arg;
|
||||
void Implementation::ResetRois() {
|
||||
int numports = generalData->numUDPInterfaces;
|
||||
std::vector<ROI> rois(numports);
|
||||
std::vector<ROI> multiRoi(1);
|
||||
setPortROIs(rois);
|
||||
setMultiROIMetadata(multiRoi);
|
||||
}
|
||||
|
||||
if (generalData->numUDPInterfaces == 1 ||
|
||||
generalData->detType == slsDetectorDefs::GOTTHARD2) {
|
||||
portRois[0] = arg;
|
||||
} else {
|
||||
slsDetectorDefs::xy nPortDim(generalData->nPixelsX,
|
||||
generalData->nPixelsY);
|
||||
|
||||
for (int iPort = 0; iPort != generalData->numUDPInterfaces; ++iPort) {
|
||||
// default init = complete roi
|
||||
slsDetectorDefs::ROI portRoi{};
|
||||
|
||||
// no roi
|
||||
if (arg.noRoi()) {
|
||||
portRoi.setNoRoi();
|
||||
}
|
||||
|
||||
// incomplete roi
|
||||
else if (!arg.completeRoi()) {
|
||||
// get port limits
|
||||
slsDetectorDefs::ROI portFullRoi{0, nPortDim.x - 1, 0,
|
||||
nPortDim.y - 1};
|
||||
if (iPort == 1) {
|
||||
// left right (eiger)
|
||||
if (GetPortGeometry().x == 2) {
|
||||
portFullRoi.xmin += nPortDim.x;
|
||||
portFullRoi.xmax += nPortDim.x;
|
||||
}
|
||||
// top bottom (jungfrau or moench)
|
||||
else {
|
||||
portFullRoi.ymin += nPortDim.y;
|
||||
portFullRoi.ymax += nPortDim.y;
|
||||
}
|
||||
}
|
||||
LOG(logDEBUG)
|
||||
<< iPort << ": portfullroi:" << ToString(portFullRoi);
|
||||
|
||||
// no roi
|
||||
if (arg.xmin > portFullRoi.xmax ||
|
||||
arg.xmax < portFullRoi.xmin ||
|
||||
arg.ymin > portFullRoi.ymax ||
|
||||
arg.ymax < portFullRoi.ymin) {
|
||||
portRoi.setNoRoi();
|
||||
}
|
||||
|
||||
// incomplete module roi
|
||||
else if (arg.xmin > portFullRoi.xmin ||
|
||||
arg.xmax < portFullRoi.xmax ||
|
||||
arg.ymin > portFullRoi.ymin ||
|
||||
arg.ymax < portFullRoi.ymax) {
|
||||
portRoi.xmin = (arg.xmin <= portFullRoi.xmin)
|
||||
? 0
|
||||
: (arg.xmin % nPortDim.x);
|
||||
portRoi.xmax = (arg.xmax >= portFullRoi.xmax)
|
||||
? nPortDim.x - 1
|
||||
: (arg.xmax % nPortDim.x);
|
||||
portRoi.ymin = (arg.ymin <= portFullRoi.ymin)
|
||||
? 0
|
||||
: (arg.ymin % nPortDim.y);
|
||||
portRoi.ymax = (arg.ymax >= portFullRoi.ymax)
|
||||
? nPortDim.y - 1
|
||||
: (arg.ymax % nPortDim.y);
|
||||
}
|
||||
}
|
||||
portRois[iPort] = portRoi;
|
||||
void Implementation::setPortROIs(const std::vector<defs::ROI> &args) {
|
||||
int nx = static_cast<int>(generalData->nPixelsX);
|
||||
int ny = static_cast<int>(generalData->nPixelsY);
|
||||
// validate rois
|
||||
for (auto &it : args) {
|
||||
if (it.completeRoi() || it.noRoi()) {
|
||||
continue; // valid
|
||||
}
|
||||
if (it.xmin < 0 || it.xmax < 0 || it.xmin >= nx || it.xmax >= nx) {
|
||||
throw RuntimeError("Invalid ROI x coordinates: " + ToString(it));
|
||||
}
|
||||
if (ny > 1 &&
|
||||
(it.ymin < 0 || it.ymax < 0 || it.ymin >= ny || it.ymax >= ny)) {
|
||||
throw RuntimeError("Invalid ROI y coordinates: " + ToString(it));
|
||||
}
|
||||
}
|
||||
portRois = args;
|
||||
|
||||
for (size_t i = 0; i != listener.size(); ++i)
|
||||
listener[i]->SetNoRoi(portRois[i].noRoi());
|
||||
for (size_t i = 0; i != dataProcessor.size(); ++i)
|
||||
dataProcessor[i]->SetReceiverROI(portRois[i]);
|
||||
listener[i]->SetIsOutsideRoi(portRois[i].noRoi());
|
||||
for (size_t i = 0; i != dataProcessor.size(); ++i) {
|
||||
dataProcessor[i]->SetPortROI(portRois[i]);
|
||||
}
|
||||
for (size_t i = 0; i != dataStreamer.size(); ++i) {
|
||||
dataStreamer[i]->SetReceiverROI(
|
||||
portRois[i].completeRoi() ? GetMaxROIPerPort() : portRois[i]);
|
||||
}
|
||||
LOG(logINFO) << "receiver roi: " << ToString(receiverRoi);
|
||||
if (generalData->numUDPInterfaces == 2 &&
|
||||
generalData->detType != slsDetectorDefs::GOTTHARD2) {
|
||||
LOG(logINFO) << "port rois: " << ToString(portRois);
|
||||
dataStreamer[i]->SetPortROI(portRois[i]);
|
||||
}
|
||||
LOG(logINFO) << "Rois (per port): " << ToString(portRois);
|
||||
}
|
||||
|
||||
void Implementation::setReceiverROIMetadata(const ROI arg) {
|
||||
receiverRoiMetadata = arg;
|
||||
LOG(logINFO) << "receiver roi Metadata: " << ToString(receiverRoiMetadata);
|
||||
void Implementation::setMultiROIMetadata(
|
||||
const std::vector<slsDetectorDefs::ROI> &args) {
|
||||
multiRoiMetadata = args;
|
||||
if (dataProcessor.size() > 0)
|
||||
dataProcessor[0]->setMultiROIMetadata(multiRoiMetadata);
|
||||
LOG(logINFO) << "Multi ROI Metadata: " << ToString(multiRoiMetadata);
|
||||
}
|
||||
|
||||
std::vector<slsDetectorDefs::ROI> Implementation::getMultiROIMetadata() const {
|
||||
return multiRoiMetadata;
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
@@ -793,8 +746,7 @@ void Implementation::stopReceiver() {
|
||||
summary = (i == 0 ? "\n\tDeactivated Left Port"
|
||||
: "\n\tDeactivated Right Port");
|
||||
} else if (portRois[i].noRoi()) {
|
||||
summary = (i == 0 ? "\n\tNo Roi on Left Port"
|
||||
: "\n\tNo Roi on Right Port");
|
||||
summary = "\n\tNo Roi on Port[" + std::to_string(i) + ']';
|
||||
} else {
|
||||
std::ostringstream os;
|
||||
os << "\n\tMissing Packets\t\t: " << mpMessage
|
||||
@@ -919,7 +871,12 @@ void Implementation::CreateUDPSockets() {
|
||||
}
|
||||
|
||||
void Implementation::SetupWriter() {
|
||||
|
||||
try {
|
||||
// check if filePath empty and throw error
|
||||
if (filePath.empty()) {
|
||||
throw ReceiverError("File path cannot be empty");
|
||||
}
|
||||
// check if folder exists and throw if it cant create
|
||||
mkdir_p(filePath);
|
||||
// create first files
|
||||
@@ -951,7 +908,7 @@ void Implementation::StartMasterWriter() {
|
||||
masterAttributes.detType = generalData->detType;
|
||||
masterAttributes.timingMode = timingMode;
|
||||
masterAttributes.geometry = numPorts;
|
||||
masterAttributes.imageSize = generalData->imageSize;
|
||||
masterAttributes.imageSize = generalData->actualImageSize;
|
||||
masterAttributes.nPixels =
|
||||
xy(generalData->nPixelsX, generalData->nPixelsY);
|
||||
masterAttributes.maxFramesPerFile = generalData->framesPerFile;
|
||||
@@ -959,7 +916,20 @@ void Implementation::StartMasterWriter() {
|
||||
masterAttributes.framePadding = framePadding;
|
||||
masterAttributes.scanParams = scanParams;
|
||||
masterAttributes.totalFrames = numberOfTotalFrames;
|
||||
masterAttributes.receiverRoi = receiverRoiMetadata;
|
||||
// complete ROI (for each port TODO?)
|
||||
if (multiRoiMetadata.size() == 1 &&
|
||||
multiRoiMetadata[0].completeRoi()) {
|
||||
int nTotalPixelsX = (generalData->nPixelsX * numPorts.x);
|
||||
int nTotalPixelsY = (generalData->nPixelsY * numPorts.y);
|
||||
if (nTotalPixelsY == 1) {
|
||||
masterAttributes.rois.push_back(ROI{0, nTotalPixelsX - 1});
|
||||
} else {
|
||||
masterAttributes.rois.push_back(
|
||||
ROI{0, nTotalPixelsX - 1, 0, nTotalPixelsY - 1});
|
||||
}
|
||||
} else {
|
||||
masterAttributes.rois = multiRoiMetadata;
|
||||
}
|
||||
masterAttributes.exptime = acquisitionTime;
|
||||
masterAttributes.period = acquisitionPeriod;
|
||||
masterAttributes.burstMode = burstMode;
|
||||
@@ -973,7 +943,7 @@ void Implementation::StartMasterWriter() {
|
||||
masterAttributes.quad = quadEnable;
|
||||
masterAttributes.readNRows = readNRows;
|
||||
masterAttributes.ratecorr = rateCorrections;
|
||||
masterAttributes.adcmask = generalData->tengigaEnable
|
||||
masterAttributes.adcMask = generalData->tengigaEnable
|
||||
? generalData->adcEnableMaskTenGiga
|
||||
: generalData->adcEnableMaskOneGiga;
|
||||
masterAttributes.analog =
|
||||
@@ -989,10 +959,12 @@ void Implementation::StartMasterWriter() {
|
||||
? 1
|
||||
: 0;
|
||||
masterAttributes.digitalSamples = generalData->nDigitalSamples;
|
||||
masterAttributes.dbitoffset = ctbDbitOffset;
|
||||
masterAttributes.dbitlist = 0;
|
||||
for (auto &i : ctbDbitList) {
|
||||
masterAttributes.dbitlist |= (static_cast<uint64_t>(1) << i);
|
||||
masterAttributes.dbitOffset = generalData->ctbDbitOffset;
|
||||
masterAttributes.dbitReorder = generalData->ctbDbitReorder;
|
||||
masterAttributes.dbitList = 0;
|
||||
|
||||
for (auto &i : generalData->ctbDbitList) {
|
||||
masterAttributes.dbitList |= (static_cast<uint64_t>(1) << i);
|
||||
}
|
||||
masterAttributes.transceiverSamples =
|
||||
generalData->nTransceiverSamples;
|
||||
@@ -1002,7 +974,6 @@ void Implementation::StartMasterWriter() {
|
||||
generalData->readoutType == DIGITAL_AND_TRANSCEIVER)
|
||||
? 1
|
||||
: 0;
|
||||
masterAttributes.detectorRoi = generalData->detectorRoi;
|
||||
masterAttributes.counterMask = generalData->counterMask;
|
||||
masterAttributes.exptimeArray[0] = acquisitionTime1;
|
||||
masterAttributes.exptimeArray[1] = acquisitionTime2;
|
||||
@@ -1012,6 +983,7 @@ void Implementation::StartMasterWriter() {
|
||||
masterAttributes.gateDelayArray[2] = gateDelay3;
|
||||
masterAttributes.gates = numberOfGates;
|
||||
masterAttributes.additionalJsonHeader = additionalJsonHeader;
|
||||
masterAttributes.readoutSpeed = readoutSpeed;
|
||||
|
||||
// create master file
|
||||
masterFileName = dataProcessor[0]->CreateMasterFile(
|
||||
@@ -1019,14 +991,36 @@ void Implementation::StartMasterWriter() {
|
||||
fileFormatType, &masterAttributes, &hdf5LibMutex);
|
||||
}
|
||||
#ifdef HDF5C
|
||||
// create virtual and master file
|
||||
if (fileFormatType == HDF5) {
|
||||
|
||||
bool gotthard25um = ((generalData->detType == GOTTHARD ||
|
||||
generalData->detType == GOTTHARD2) &&
|
||||
(numPorts.x * numPorts.y) == 2);
|
||||
|
||||
// virtual hdf5 not allowed with roi for the following cases in hdf5
|
||||
if (multiRoiMetadata.size() > 1 ||
|
||||
(!multiRoiMetadata[0].completeRoi())) {
|
||||
if (generalData->dynamicRange == 4) {
|
||||
throw std::runtime_error(
|
||||
"Skipping virtual hdf5 file since rx_roi is enabled "
|
||||
"and it is in 4 bit mode.");
|
||||
}
|
||||
if (gotthard25um && (numPorts.x * numPorts.y) == 2) {
|
||||
throw std::runtime_error(
|
||||
"Skipping virtual hdf5 file since rx_roi is "
|
||||
"enabled and there are 2 Gotthard 25um modules.");
|
||||
}
|
||||
}
|
||||
|
||||
std::string virtualFileName;
|
||||
// create virtual hdf5 file (if multiple files)
|
||||
if (dataProcessor[0]->GetFilesInAcquisition() > 1 ||
|
||||
(numPorts.x * numPorts.y) > 1) {
|
||||
virtualFileName = dataProcessor[0]->CreateVirtualFile(
|
||||
filePath, fileName, fileIndex, overwriteEnable, silentMode,
|
||||
modulePos, numPorts.x, numPorts.y, &hdf5LibMutex);
|
||||
modulePos, numPorts.x, numPorts.y, &hdf5LibMutex,
|
||||
gotthard25um);
|
||||
}
|
||||
// link file in master
|
||||
if (masterFileWriteEnable) {
|
||||
@@ -1087,8 +1081,9 @@ void Implementation::setNumberofUDPInterfaces(const int n) {
|
||||
|
||||
// fifo
|
||||
SetupFifoStructure();
|
||||
// recalculate port rois
|
||||
setReceiverROI(receiverRoi);
|
||||
|
||||
// number of portrois should be equal to number of interfaces
|
||||
ResetRois();
|
||||
|
||||
// create threads
|
||||
for (int i = 0; i < generalData->numUDPInterfaces; ++i) {
|
||||
@@ -1595,22 +1590,6 @@ void Implementation::setDynamicRange(const uint32_t i) {
|
||||
LOG(logINFO) << "Dynamic Range: " << generalData->dynamicRange;
|
||||
}
|
||||
|
||||
slsDetectorDefs::ROI Implementation::getROI() const {
|
||||
return generalData->detectorRoi;
|
||||
}
|
||||
|
||||
void Implementation::setDetectorROI(slsDetectorDefs::ROI arg) {
|
||||
if (generalData->detectorRoi.xmin != arg.xmin ||
|
||||
generalData->detectorRoi.xmax != arg.xmax) {
|
||||
// only for gotthard
|
||||
generalData->SetDetectorROI(arg);
|
||||
SetupFifoStructure();
|
||||
}
|
||||
|
||||
LOG(logINFO) << "Detector ROI: " << ToString(generalData->detectorRoi);
|
||||
LOG(logINFO) << "Packets per Frame: " << (generalData->packetsPerFrame);
|
||||
}
|
||||
|
||||
bool Implementation::getTenGigaEnable() const {
|
||||
return generalData->tengigaEnable;
|
||||
}
|
||||
@@ -1764,22 +1743,29 @@ void Implementation::setTenGigaADCEnableMask(uint32_t mask) {
|
||||
LOG(logINFO) << "Packets per Frame: " << (generalData->packetsPerFrame);
|
||||
}
|
||||
|
||||
std::vector<int> Implementation::getDbitList() const { return ctbDbitList; }
|
||||
|
||||
void Implementation::setDbitList(const std::vector<int> &v) {
|
||||
ctbDbitList = v;
|
||||
for (const auto &it : dataProcessor)
|
||||
it->SetCtbDbitList(ctbDbitList);
|
||||
LOG(logINFO) << "Dbit list: " << ToString(ctbDbitList);
|
||||
std::vector<int> Implementation::getDbitList() const {
|
||||
return generalData->ctbDbitList;
|
||||
}
|
||||
|
||||
int Implementation::getDbitOffset() const { return ctbDbitOffset; }
|
||||
void Implementation::setDbitList(const std::vector<int> &v) {
|
||||
generalData->SetctbDbitList(v);
|
||||
LOG(logINFO) << "Dbit list: " << ToString(v);
|
||||
}
|
||||
|
||||
int Implementation::getDbitOffset() const { return generalData->ctbDbitOffset; }
|
||||
|
||||
void Implementation::setDbitOffset(const int s) {
|
||||
ctbDbitOffset = s;
|
||||
for (const auto &it : dataProcessor)
|
||||
it->SetCtbDbitOffset(ctbDbitOffset);
|
||||
LOG(logINFO) << "Dbit offset: " << ctbDbitOffset;
|
||||
generalData->SetctbDbitOffset(s);
|
||||
LOG(logINFO) << "Dbit offset: " << s;
|
||||
}
|
||||
|
||||
bool Implementation::getDbitReorder() const {
|
||||
return generalData->ctbDbitReorder;
|
||||
}
|
||||
|
||||
void Implementation::setDbitReorder(const bool reorder) {
|
||||
generalData->SetctbDbitReorder(reorder);
|
||||
LOG(logINFO) << "Dbit reorder: " << reorder;
|
||||
}
|
||||
|
||||
uint32_t Implementation::getTransceiverEnableMask() const {
|
||||
@@ -1796,13 +1782,22 @@ void Implementation::setTransceiverEnableMask(uint32_t mask) {
|
||||
LOG(logINFO) << "Packets per Frame: " << (generalData->packetsPerFrame);
|
||||
}
|
||||
|
||||
slsDetectorDefs::speedLevel Implementation::getReadoutSpeed() const {
|
||||
return readoutSpeed;
|
||||
}
|
||||
|
||||
void Implementation::setReadoutSpeed(const slsDetectorDefs::speedLevel i) {
|
||||
readoutSpeed = i;
|
||||
LOG(logINFO) << "Readout Speed: " << ToString(readoutSpeed);
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
* *
|
||||
* Callbacks *
|
||||
* *
|
||||
* ************************************************/
|
||||
void Implementation::registerCallBackStartAcquisition(
|
||||
int (*func)(const startCallbackHeader, void *), void *arg) {
|
||||
void (*func)(const startCallbackHeader, void *), void *arg) {
|
||||
startAcquisitionCallBack = func;
|
||||
pStartAcquisition = arg;
|
||||
}
|
||||
|
||||
@@ -58,9 +58,10 @@ class Implementation : private virtual slsDetectorDefs {
|
||||
bool getArping() const;
|
||||
pid_t getArpingProcessId() const;
|
||||
void setArping(const bool i, const std::vector<std::string> ips);
|
||||
ROI getReceiverROI() const;
|
||||
void setReceiverROI(const ROI arg);
|
||||
void setReceiverROIMetadata(const ROI arg);
|
||||
std::vector<defs::ROI> getPortROIs() const;
|
||||
void setPortROIs(const std::vector<defs::ROI> &args);
|
||||
void setMultiROIMetadata(const std::vector<slsDetectorDefs::ROI> &args);
|
||||
std::vector<slsDetectorDefs::ROI> getMultiROIMetadata() const;
|
||||
|
||||
/**************************************************
|
||||
* *
|
||||
@@ -211,9 +212,6 @@ class Implementation : private virtual slsDetectorDefs {
|
||||
void setCounterMask(const uint32_t i);
|
||||
uint32_t getDynamicRange() const;
|
||||
void setDynamicRange(const uint32_t i);
|
||||
ROI getROI() const;
|
||||
/* [Gotthard] */
|
||||
void setDetectorROI(ROI arg);
|
||||
bool getTenGigaEnable() const;
|
||||
/* [Eiger][Ctb] */
|
||||
void setTenGigaEnable(const bool b);
|
||||
@@ -255,9 +253,15 @@ class Implementation : private virtual slsDetectorDefs {
|
||||
int getDbitOffset() const;
|
||||
/* [Ctb] */
|
||||
void setDbitOffset(const int s);
|
||||
bool getDbitReorder() const;
|
||||
/* [Ctb] */
|
||||
void setDbitReorder(const bool reorder);
|
||||
uint32_t getTransceiverEnableMask() const;
|
||||
/* [Ctb] */
|
||||
void setTransceiverEnableMask(const uint32_t mask);
|
||||
speedLevel getReadoutSpeed() const;
|
||||
/* [Eiger][Jungfrau][Moench][Mythen3][Gotthard2]*/
|
||||
void setReadoutSpeed(const speedLevel i);
|
||||
|
||||
/**************************************************
|
||||
* *
|
||||
@@ -265,9 +269,8 @@ class Implementation : private virtual slsDetectorDefs {
|
||||
* *
|
||||
* ************************************************/
|
||||
/** params: file path, file name, file index, image size */
|
||||
void registerCallBackStartAcquisition(int (*func)(const startCallbackHeader,
|
||||
void *),
|
||||
void *arg);
|
||||
void registerCallBackStartAcquisition(
|
||||
void (*func)(const startCallbackHeader, void *), void *arg);
|
||||
/** params: total frames caught */
|
||||
void registerCallBackAcquisitionFinished(
|
||||
void (*func)(const endCallbackHeader, void *), void *arg);
|
||||
@@ -283,7 +286,7 @@ class Implementation : private virtual slsDetectorDefs {
|
||||
void SetupFifoStructure();
|
||||
|
||||
const xy GetPortGeometry() const;
|
||||
const ROI GetMaxROIPerPort() const;
|
||||
void ResetRois();
|
||||
void ResetParametersforNewAcquisition();
|
||||
void CreateUDPSockets();
|
||||
void SetupWriter();
|
||||
@@ -308,14 +311,12 @@ class Implementation : private virtual slsDetectorDefs {
|
||||
bool framePadding{true};
|
||||
pid_t parentThreadId;
|
||||
pid_t tcpThreadId;
|
||||
ROI receiverRoi{};
|
||||
std::array<ROI, 2> portRois{};
|
||||
// receiver roi for complete detector for metadata
|
||||
ROI receiverRoiMetadata{};
|
||||
std::vector<slsDetectorDefs::ROI> portRois;
|
||||
std::vector<slsDetectorDefs::ROI> multiRoiMetadata;
|
||||
|
||||
// file parameters
|
||||
fileFormat fileFormatType{BINARY};
|
||||
std::string filePath{"/"};
|
||||
std::string filePath{};
|
||||
std::string fileName{"run"};
|
||||
uint64_t fileIndex{0};
|
||||
bool fileWriteEnable{false};
|
||||
@@ -370,11 +371,11 @@ class Implementation : private virtual slsDetectorDefs {
|
||||
int thresholdEnergyeV{-1};
|
||||
std::array<int, 3> thresholdAllEnergyeV = {{-1, -1, -1}};
|
||||
std::vector<int64_t> rateCorrections;
|
||||
std::vector<int> ctbDbitList;
|
||||
int ctbDbitOffset{0};
|
||||
speedLevel readoutSpeed{FULL_SPEED};
|
||||
|
||||
// callbacks
|
||||
int (*startAcquisitionCallBack)(const startCallbackHeader, void *){nullptr};
|
||||
void (*startAcquisitionCallBack)(const startCallbackHeader,
|
||||
void *){nullptr};
|
||||
void *pStartAcquisition{nullptr};
|
||||
void (*acquisitionFinishedCallBack)(const endCallbackHeader,
|
||||
void *){nullptr};
|
||||
|
||||
@@ -85,17 +85,17 @@ void Listener::SetEthernetInterface(const std::string e) {
|
||||
|
||||
void Listener::SetActivate(bool enable) {
|
||||
activated = enable;
|
||||
disabledPort = (!activated || !detectorDataStream || noRoi);
|
||||
disabledPort = (!activated || !detectorDataStream || isOutsideRoi);
|
||||
}
|
||||
|
||||
void Listener::SetDetectorDatastream(bool enable) {
|
||||
detectorDataStream = enable;
|
||||
disabledPort = (!activated || !detectorDataStream || noRoi);
|
||||
disabledPort = (!activated || !detectorDataStream || isOutsideRoi);
|
||||
}
|
||||
|
||||
void Listener::SetNoRoi(bool enable) {
|
||||
noRoi = enable;
|
||||
disabledPort = (!activated || !detectorDataStream || noRoi);
|
||||
void Listener::SetIsOutsideRoi(bool enable) {
|
||||
isOutsideRoi = enable;
|
||||
disabledPort = (!activated || !detectorDataStream || isOutsideRoi);
|
||||
}
|
||||
|
||||
void Listener::SetSilentMode(bool enable) { silentMode = enable; }
|
||||
@@ -350,8 +350,6 @@ uint32_t Listener::ListenToAnImage(sls_receiver_header &dstHeader,
|
||||
carryOverFlag = false;
|
||||
}
|
||||
|
||||
// until last packet isHeaderEmpty to account for gotthard short frame, else
|
||||
// never entering this loop)
|
||||
while (numpackets < pperFrame) {
|
||||
// listen to new packet
|
||||
if (!udpSocketAlive || !udpSocket->ReceivePacket(&listeningPacket[0])) {
|
||||
@@ -463,15 +461,6 @@ void Listener::CopyPacket(char *dst, char *src, uint32_t dataSize,
|
||||
|
||||
// copy packet data
|
||||
switch (generalData->detType) {
|
||||
// for gotthard,
|
||||
// 1st packet: 4 bytes fnum, CACA + CACA, 639*2 bytes data
|
||||
// 2nd packet: 4 bytes fnum, previous 1*2 bytes data + 640*2 bytes data
|
||||
case GOTTHARD:
|
||||
if (!pnum)
|
||||
memcpy(dst, &src[detHeaderSize + 2], dataSize - 2);
|
||||
else
|
||||
memcpy(dst + dataSize - 2, &src[detHeaderSize - 2], dataSize + 2);
|
||||
break;
|
||||
case CHIPTESTBOARD:
|
||||
case XILINX_CHIPTESTBOARD:
|
||||
if (pnum == (generalData->packetsPerFrame - 1))
|
||||
@@ -517,14 +506,7 @@ void Listener::GetPacketIndices(uint64_t &fnum, uint32_t &pnum, uint64_t &bnum,
|
||||
fnum = header->frameNumber;
|
||||
pnum = header->packetNumber;
|
||||
} else {
|
||||
// set first packet to be odd or even (check required when switching
|
||||
// from roi to no roi)
|
||||
if (generalData->detType == GOTTHARD && !startedFlag) {
|
||||
oddStartingPacket =
|
||||
generalData->SetOddStartingPacket(index, &packet[0]);
|
||||
}
|
||||
generalData->GetHeaderInfo(index, &packet[0], oddStartingPacket, fnum,
|
||||
pnum, bnum);
|
||||
generalData->GetHeaderInfo(index, &packet[0], fnum, pnum, bnum);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ class Listener : private virtual slsDetectorDefs, public ThreadObject {
|
||||
void SetEthernetInterface(const std::string e);
|
||||
void SetActivate(bool enable);
|
||||
void SetDetectorDatastream(bool enable);
|
||||
void SetNoRoi(bool enable);
|
||||
void SetIsOutsideRoi(bool enable);
|
||||
void SetSilentMode(bool enable);
|
||||
|
||||
void ResetParametersforNewAcquisition();
|
||||
@@ -116,7 +116,7 @@ class Listener : private virtual slsDetectorDefs, public ThreadObject {
|
||||
std::string eth;
|
||||
bool activated{false};
|
||||
bool detectorDataStream{true};
|
||||
bool noRoi{false};
|
||||
bool isOutsideRoi{false};
|
||||
bool silentMode;
|
||||
bool disabledPort{false};
|
||||
|
||||
@@ -156,12 +156,6 @@ class Listener : private virtual slsDetectorDefs, public ThreadObject {
|
||||
// for print progress during acquisition*/
|
||||
uint32_t numPacketsStatistic{0};
|
||||
uint32_t numFramesStatistic{0};
|
||||
|
||||
/**
|
||||
* starting packet number is odd or even, accordingly increment frame number
|
||||
* to get first packet number as 0
|
||||
* (pecific to gotthard, can vary between modules, hence defined here) */
|
||||
bool oddStartingPacket{true};
|
||||
};
|
||||
|
||||
} // namespace sls
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4,12 +4,14 @@
|
||||
|
||||
#include "receiver_defs.h"
|
||||
#include "sls/ToString.h"
|
||||
#include "sls/TypeTraits.h"
|
||||
#include "sls/logger.h"
|
||||
#include "sls/sls_detector_defs.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <rapidjson/prettywriter.h>
|
||||
#include <rapidjson/stringbuffer.h>
|
||||
#include <string_view>
|
||||
|
||||
#ifdef HDF5C
|
||||
#include "H5Cpp.h"
|
||||
@@ -18,6 +20,7 @@
|
||||
namespace sls {
|
||||
|
||||
using ns = std::chrono::nanoseconds;
|
||||
using writer = rapidjson::PrettyWriter<rapidjson::StringBuffer>;
|
||||
|
||||
class MasterAttributes {
|
||||
public:
|
||||
@@ -25,7 +28,7 @@ class MasterAttributes {
|
||||
slsDetectorDefs::detectorType detType{slsDetectorDefs::GENERIC};
|
||||
slsDetectorDefs::timingMode timingMode{slsDetectorDefs::AUTO_TIMING};
|
||||
slsDetectorDefs::xy geometry{};
|
||||
uint32_t imageSize{0};
|
||||
int imageSize{0};
|
||||
slsDetectorDefs::xy nPixels{};
|
||||
uint32_t maxFramesPerFile{0};
|
||||
slsDetectorDefs::frameDiscardPolicy frameDiscardMode{
|
||||
@@ -37,127 +40,413 @@ class MasterAttributes {
|
||||
ns period{0};
|
||||
slsDetectorDefs::burstMode burstMode{slsDetectorDefs::BURST_INTERNAL};
|
||||
int numUDPInterfaces{0};
|
||||
uint32_t dynamicRange{0};
|
||||
uint32_t tenGiga{0};
|
||||
int dynamicRange{0};
|
||||
int tenGiga{0};
|
||||
int thresholdEnergyeV{0};
|
||||
std::array<int, 3> thresholdAllEnergyeV = {{0, 0, 0}};
|
||||
ns subExptime{0};
|
||||
ns subPeriod{0};
|
||||
uint32_t quad{0};
|
||||
uint32_t readNRows;
|
||||
int quad{0};
|
||||
int readNRows;
|
||||
std::vector<int64_t> ratecorr;
|
||||
uint32_t adcmask{0};
|
||||
uint32_t analog{0};
|
||||
uint32_t analogSamples{0};
|
||||
uint32_t digital{0};
|
||||
uint32_t digitalSamples{0};
|
||||
uint32_t dbitoffset{0};
|
||||
uint64_t dbitlist{0};
|
||||
uint32_t transceiverMask{0};
|
||||
uint32_t transceiver{0};
|
||||
uint32_t transceiverSamples{0};
|
||||
slsDetectorDefs::ROI detectorRoi{};
|
||||
slsDetectorDefs::ROI receiverRoi{};
|
||||
uint32_t counterMask{0};
|
||||
uint32_t adcMask{0};
|
||||
int analog{0};
|
||||
int analogSamples{0};
|
||||
int digital{0};
|
||||
int digitalSamples{0};
|
||||
int dbitReorder{1};
|
||||
int dbitOffset{0};
|
||||
uint64_t dbitList{0};
|
||||
int transceiverMask{0};
|
||||
int transceiver{0};
|
||||
int transceiverSamples{0};
|
||||
std::vector<slsDetectorDefs::ROI> rois{};
|
||||
int counterMask{0};
|
||||
std::array<ns, 3> exptimeArray{};
|
||||
std::array<ns, 3> gateDelayArray{};
|
||||
uint32_t gates;
|
||||
int gates;
|
||||
std::map<std::string, std::string> additionalJsonHeader;
|
||||
uint64_t framesInFile{0};
|
||||
slsDetectorDefs::speedLevel readoutSpeed{slsDetectorDefs::FULL_SPEED};
|
||||
|
||||
inline static const std::string_view N_DETECTOR_TYPE = "Detector Type";
|
||||
inline static const std::string_view N_TIMING_MODE = "Timing Mode";
|
||||
inline static const std::string_view N_GEOMETRY = "Geometry";
|
||||
inline static const std::string_view N_IMAGE_SIZE = "Image Size";
|
||||
inline static const std::string_view N_PIXELS = "Pixels";
|
||||
inline static const std::string_view N_MAX_FRAMES_PER_FILE =
|
||||
"Max Frames Per File";
|
||||
inline static const std::string_view N_FRAME_DISCARD_POLICY =
|
||||
"Frame Discard Policy";
|
||||
inline static const std::string_view N_FRAME_PADDING = "Frame Padding";
|
||||
inline static const std::string_view N_TOTAL_FRAMES = "Total Frames";
|
||||
inline static const std::string_view N_FRAMES_IN_FILE = "Frames in File";
|
||||
inline static const std::string_view N_EXPOSURE_TIME = "Exposure Time";
|
||||
inline static const std::string_view N_ACQUISITION_PERIOD =
|
||||
"Acquisition Period";
|
||||
inline static const std::string_view N_NUM_UDP_INTERFACES =
|
||||
"Number of UDP Interfaces";
|
||||
inline static const std::string_view N_NUMBER_OF_ROWS = "Number of Rows";
|
||||
inline static const std::string_view N_READOUT_SPEED = "Readout Speed";
|
||||
inline static const std::string_view N_DYNAMIC_RANGE = "Dynamic Range";
|
||||
inline static const std::string_view N_TEN_GIGA = "Ten Giga";
|
||||
inline static const std::string_view N_THRESHOLD_ENERGY =
|
||||
"Threshold Energy";
|
||||
inline static const std::string_view N_SUB_EXPOSURE_TIME =
|
||||
"Sub Exposure Time";
|
||||
inline static const std::string_view N_SUB_ACQUISITION_PERIOD =
|
||||
"Sub Acquisition Period";
|
||||
inline static const std::string_view N_QUAD = "Quad";
|
||||
inline static const std::string_view N_RATE_CORRECTIONS =
|
||||
"Rate Corrections";
|
||||
inline static const std::string_view N_COUNTER_MASK = "Counter Mask";
|
||||
inline static const std::string_view N_EXPOSURE_TIMES = "Exposure Times";
|
||||
inline static const std::string_view N_GATE_DELAYS = "Gate Delays";
|
||||
inline static const std::string_view N_GATES = "Gates";
|
||||
inline static const std::string_view N_THRESHOLD_ENERGIES =
|
||||
"Threshold Energies";
|
||||
inline static const std::string_view N_BURST_MODE = "Burst Mode";
|
||||
inline static const std::string_view N_ADC_MASK = "ADC Mask";
|
||||
inline static const std::string_view N_ANALOG = "Analog Flag";
|
||||
inline static const std::string_view N_ANALOG_SAMPLES = "Analog Samples";
|
||||
inline static const std::string_view N_DIGITAL = "Digital Flag";
|
||||
inline static const std::string_view N_DIGITAL_SAMPLES = "Digital Samples";
|
||||
inline static const std::string_view N_DBIT_REORDER = "Dbit Reorder";
|
||||
inline static const std::string_view N_DBIT_OFFSET = "Dbit Offset";
|
||||
inline static const std::string_view N_DBIT_BITSET = "Dbit Bitset";
|
||||
inline static const std::string_view N_TRANSCEIVER_MASK =
|
||||
"Transceiver Mask";
|
||||
inline static const std::string_view N_TRANSCEIVER = "Transceiver Flag";
|
||||
inline static const std::string_view N_TRANSCEIVER_SAMPLES =
|
||||
"Transceiver Samples";
|
||||
inline static const std::string_view N_VERSION = "Version";
|
||||
inline static const std::string_view N_TIMESTAMP = "Timestamp";
|
||||
inline static const std::string_view N_RECEIVER_ROIS = "Receiver Rois";
|
||||
inline static const std::string_view N_SCAN_PARAMETERS = "Scan Parameters";
|
||||
inline static const std::string_view N_ADDITIONAL_JSON_HEADER =
|
||||
"Additional JSON Header";
|
||||
|
||||
MasterAttributes() = default;
|
||||
~MasterAttributes() = default;
|
||||
|
||||
void
|
||||
GetBinaryAttributes(rapidjson::PrettyWriter<rapidjson::StringBuffer> *w);
|
||||
void GetBinaryAttributes(writer *w);
|
||||
#ifdef HDF5C
|
||||
void WriteHDF5Attributes(H5::H5File *fd, H5::Group *group);
|
||||
#endif
|
||||
|
||||
void GetCommonBinaryAttributes(
|
||||
rapidjson::PrettyWriter<rapidjson::StringBuffer> *w);
|
||||
void GetFinalBinaryAttributes(
|
||||
rapidjson::PrettyWriter<rapidjson::StringBuffer> *w);
|
||||
void GetCommonBinaryAttributes(writer *w);
|
||||
void GetFinalBinaryAttributes(writer *w);
|
||||
|
||||
#ifdef HDF5C
|
||||
void WriteCommonHDF5Attributes(H5::H5File *fd, H5::Group *group);
|
||||
void WriteFinalHDF5Attributes(H5::H5File *fd, H5::Group *group);
|
||||
void WriteHDF5Exptime(H5::H5File *fd, H5::Group *group);
|
||||
void WriteHDF5Period(H5::H5File *fd, H5::Group *group);
|
||||
void WriteHDF5DynamicRange(H5::H5File *fd, H5::Group *group);
|
||||
void WriteHDF5TenGiga(H5::H5File *fd, H5::Group *group);
|
||||
void WriteHDF5ROI(H5::H5File *fd, H5::Group *group);
|
||||
void WriteHDF5NumUDPInterfaces(H5::H5File *fd, H5::Group *group);
|
||||
void WriteHDF5ReadNRows(H5::H5File *fd, H5::Group *group);
|
||||
void WriteHDF5ThresholdEnergy(H5::H5File *fd, H5::Group *group);
|
||||
void WriteHDF5ThresholdEnergies(H5::H5File *fd, H5::Group *group);
|
||||
void WriteHDF5SubExpTime(H5::H5File *fd, H5::Group *group);
|
||||
void WriteHDF5SubPeriod(H5::H5File *fd, H5::Group *group);
|
||||
void WriteHDF5SubQuad(H5::H5File *fd, H5::Group *group);
|
||||
void WriteHDF5RateCorrections(H5::H5File *fd, H5::Group *group);
|
||||
void WriteHDF5CounterMask(H5::H5File *fd, H5::Group *group);
|
||||
void WriteHDF5ExptimeArray(H5::H5File *fd, H5::Group *group);
|
||||
void WriteHDF5GateDelayArray(H5::H5File *fd, H5::Group *group);
|
||||
void WriteHDF5Gates(H5::H5File *fd, H5::Group *group);
|
||||
void WriteHDF5BurstMode(H5::H5File *fd, H5::Group *group);
|
||||
void WriteHDF5AdcMask(H5::H5File *fd, H5::Group *group);
|
||||
void WriteHDF5AnalogFlag(H5::H5File *fd, H5::Group *group);
|
||||
void WriteHDF5AnalogSamples(H5::H5File *fd, H5::Group *group);
|
||||
void WriteHDF5DigitalFlag(H5::H5File *fd, H5::Group *group);
|
||||
void WriteHDF5DigitalSamples(H5::H5File *fd, H5::Group *group);
|
||||
void WriteHDF5DbitOffset(H5::H5File *fd, H5::Group *group);
|
||||
void WriteHDF5DbitList(H5::H5File *fd, H5::Group *group);
|
||||
void WriteHDF5TransceiverMask(H5::H5File *fd, H5::Group *group);
|
||||
void WriteHDF5TransceiverFlag(H5::H5File *fd, H5::Group *group);
|
||||
void WriteHDF5TransceiverSamples(H5::H5File *fd, H5::Group *group);
|
||||
void WriteFinalHDF5Attributes(H5::Group *group);
|
||||
#endif
|
||||
|
||||
void GetGotthardBinaryAttributes(
|
||||
rapidjson::PrettyWriter<rapidjson::StringBuffer> *w);
|
||||
void GetJungfrauBinaryAttributes(writer *w);
|
||||
#ifdef HDF5C
|
||||
void WriteGotthardHDF5Attributes(H5::H5File *fd, H5::Group *group);
|
||||
void WriteJungfrauHDF5Attributes(H5::Group *group);
|
||||
#endif
|
||||
|
||||
void GetJungfrauBinaryAttributes(
|
||||
rapidjson::PrettyWriter<rapidjson::StringBuffer> *w);
|
||||
void GetEigerBinaryAttributes(writer *w);
|
||||
#ifdef HDF5C
|
||||
void WriteJungfrauHDF5Attributes(H5::H5File *fd, H5::Group *group);
|
||||
void WriteEigerHDF5Attributes(H5::Group *group);
|
||||
#endif
|
||||
|
||||
void GetEigerBinaryAttributes(
|
||||
rapidjson::PrettyWriter<rapidjson::StringBuffer> *w);
|
||||
void GetMythen3BinaryAttributes(writer *w);
|
||||
#ifdef HDF5C
|
||||
void WriteEigerHDF5Attributes(H5::H5File *fd, H5::Group *group);
|
||||
void WriteMythen3HDF5Attributes(H5::Group *group);
|
||||
#endif
|
||||
|
||||
void GetMythen3BinaryAttributes(
|
||||
rapidjson::PrettyWriter<rapidjson::StringBuffer> *w);
|
||||
void GetGotthard2BinaryAttributes(writer *w);
|
||||
#ifdef HDF5C
|
||||
void WriteMythen3HDF5Attributes(H5::H5File *fd, H5::Group *group);
|
||||
void WriteGotthard2HDF5Attributes(H5::Group *group);
|
||||
#endif
|
||||
|
||||
void GetGotthard2BinaryAttributes(
|
||||
rapidjson::PrettyWriter<rapidjson::StringBuffer> *w);
|
||||
void GetMoenchBinaryAttributes(writer *w);
|
||||
#ifdef HDF5C
|
||||
void WriteGotthard2HDF5Attributes(H5::H5File *fd, H5::Group *group);
|
||||
void WriteMoenchHDF5Attributes(H5::Group *group);
|
||||
#endif
|
||||
|
||||
void GetMoenchBinaryAttributes(
|
||||
rapidjson::PrettyWriter<rapidjson::StringBuffer> *w);
|
||||
void GetCtbBinaryAttributes(writer *w);
|
||||
#ifdef HDF5C
|
||||
void WriteMoenchHDF5Attributes(H5::H5File *fd, H5::Group *group);
|
||||
void WriteCtbHDF5Attributes(H5::Group *group);
|
||||
#endif
|
||||
|
||||
void
|
||||
GetCtbBinaryAttributes(rapidjson::PrettyWriter<rapidjson::StringBuffer> *w);
|
||||
void GetXilinxCtbBinaryAttributes(writer *w);
|
||||
#ifdef HDF5C
|
||||
void WriteCtbHDF5Attributes(H5::H5File *fd, H5::Group *group);
|
||||
void WriteXilinxCtbHDF5Attributes(H5::Group *group);
|
||||
#endif
|
||||
|
||||
void GetXilinxCtbBinaryAttributes(
|
||||
rapidjson::PrettyWriter<rapidjson::StringBuffer> *w);
|
||||
void WriteBinaryDetectorType(writer *w);
|
||||
#ifdef HDF5C
|
||||
void WriteXilinxCtbHDF5Attributes(H5::H5File *fd, H5::Group *group);
|
||||
void WriteHDF5DetectorType(H5::Group *group);
|
||||
#endif
|
||||
void WriteBinaryTimingMode(writer *w);
|
||||
#ifdef HDF5C
|
||||
void WriteHDF5TimingMode(H5::Group *group);
|
||||
#endif
|
||||
void WriteBinaryGeometry(writer *w);
|
||||
#ifdef HDF5C
|
||||
void WriteHDF5Geometry(H5::Group *group);
|
||||
#endif
|
||||
void WriteBinaryImageSize(writer *w);
|
||||
#ifdef HDF5C
|
||||
void WriteHDF5ImageSize(H5::Group *group);
|
||||
#endif
|
||||
void WriteBinaryPixels(writer *w);
|
||||
#ifdef HDF5C
|
||||
void WriteHDF5Pixels(H5::Group *group);
|
||||
#endif
|
||||
void WriteBinaryMaxFramesPerFile(writer *w);
|
||||
#ifdef HDF5C
|
||||
void WriteHDF5MaxFramesPerFile(H5::Group *group);
|
||||
#endif
|
||||
void WriteBinaryFrameDiscardPolicy(writer *w);
|
||||
#ifdef HDF5C
|
||||
void WriteHDF5FrameDiscardPolicy(H5::Group *group);
|
||||
#endif
|
||||
void WriteBinaryFramePadding(writer *w);
|
||||
#ifdef HDF5C
|
||||
void WriteHDF5FramePadding(H5::Group *group);
|
||||
#endif
|
||||
void WriteBinaryTotalFrames(writer *w);
|
||||
#ifdef HDF5C
|
||||
void WriteHDF5TotalFrames(H5::Group *group);
|
||||
#endif
|
||||
void WriteBinaryFramesInFile(writer *w);
|
||||
#ifdef HDF5C
|
||||
void WriteHDF5FramesInFile(H5::Group *group);
|
||||
#endif
|
||||
|
||||
void WriteBinaryExposureTme(writer *w);
|
||||
#ifdef HDF5C
|
||||
void WriteHDF5ExposureTime(H5::Group *group);
|
||||
#endif
|
||||
void WriteBinaryAcquisitionPeriod(writer *w);
|
||||
#ifdef HDF5C
|
||||
void WriteHDF5AcquisitionPeriod(H5::Group *group);
|
||||
#endif
|
||||
void WriteBinaryNumberOfUDPInterfaces(writer *w);
|
||||
#ifdef HDF5C
|
||||
void WriteHDF5NumberOfUDPInterfaces(H5::Group *group);
|
||||
#endif
|
||||
void WriteBinaryNumberOfRows(writer *w);
|
||||
#ifdef HDF5C
|
||||
void WriteHDF5NumberOfRows(H5::Group *group);
|
||||
#endif
|
||||
void WriteBinaryReadoutSpeed(writer *w);
|
||||
#ifdef HDF5C
|
||||
void WriteHDF5ReadoutSpeed(H5::Group *group);
|
||||
#endif
|
||||
void WriteBinaryDynamicRange(writer *w);
|
||||
#ifdef HDF5C
|
||||
void WriteHDF5DynamicRange(H5::Group *group);
|
||||
#endif
|
||||
void WriteBinaryTenGiga(writer *w);
|
||||
#ifdef HDF5C
|
||||
void WriteHDF5TenGiga(H5::Group *group);
|
||||
#endif
|
||||
void WriteBinaryThresholdEnergy(writer *w);
|
||||
#ifdef HDF5C
|
||||
void WriteHDF5ThresholdEnergy(H5::Group *group);
|
||||
#endif
|
||||
void WriteBinarySubExposureTime(writer *w);
|
||||
#ifdef HDF5C
|
||||
void WriteHDF5SubExposureTime(H5::Group *group);
|
||||
#endif
|
||||
void WriteBinarySubAcquisitionPeriod(writer *w);
|
||||
#ifdef HDF5C
|
||||
void WriteHDF5SubAcquisitionPeriod(H5::Group *group);
|
||||
#endif
|
||||
void WriteBinaryQuad(writer *w);
|
||||
#ifdef HDF5C
|
||||
void WriteHDF5Quad(H5::Group *group);
|
||||
#endif
|
||||
void WriteBinaryRateCorrections(writer *w);
|
||||
#ifdef HDF5C
|
||||
void WriteHDF5RateCorrections(H5::Group *group);
|
||||
#endif
|
||||
void WriteBinaryCounterMask(writer *w);
|
||||
#ifdef HDF5C
|
||||
void WriteHDF5CounterMask(H5::Group *group);
|
||||
#endif
|
||||
void WriteBinaryExptimeArray(writer *w);
|
||||
#ifdef HDF5C
|
||||
void WriteHDF5ExptimeArray(H5::Group *group);
|
||||
#endif
|
||||
void WriteBinaryGateDelayArray(writer *w);
|
||||
#ifdef HDF5C
|
||||
void WriteHDF5GateDelayArray(H5::Group *group);
|
||||
#endif
|
||||
void WriteBinaryGates(writer *w);
|
||||
#ifdef HDF5C
|
||||
void WriteHDF5Gates(H5::Group *group);
|
||||
#endif
|
||||
void WriteBinaryThresholdAllEnergy(writer *w);
|
||||
#ifdef HDF5C
|
||||
void WriteHDF5ThresholdAllEnergy(H5::Group *group);
|
||||
#endif
|
||||
void WriteBinaryBurstMode(writer *w);
|
||||
#ifdef HDF5C
|
||||
void WriteHDF5BurstMode(H5::Group *group);
|
||||
#endif
|
||||
void WriteBinaryAdcMask(writer *w);
|
||||
#ifdef HDF5C
|
||||
void WriteHDF5AdcMask(H5::Group *group);
|
||||
#endif
|
||||
void WriteBinaryAnalogFlag(writer *w);
|
||||
#ifdef HDF5C
|
||||
void WriteHDF5AnalogFlag(H5::Group *group);
|
||||
#endif
|
||||
void WriteBinaryAnalogSamples(writer *w);
|
||||
#ifdef HDF5C
|
||||
void WriteHDF5AnalogSamples(H5::Group *group);
|
||||
#endif
|
||||
void WriteBinaryDigitalFlag(writer *w);
|
||||
#ifdef HDF5C
|
||||
void WriteHDF5DigitalFlag(H5::Group *group);
|
||||
#endif
|
||||
void WriteBinaryDigitalSamples(writer *w);
|
||||
#ifdef HDF5C
|
||||
void WriteHDF5DigitalSamples(H5::Group *group);
|
||||
#endif
|
||||
void WriteBinaryDBitReorder(writer *w);
|
||||
#ifdef HDF5C
|
||||
void WriteHDF5DBitReorder(H5::Group *group);
|
||||
#endif
|
||||
void WriteBinaryDBitOffset(writer *w);
|
||||
#ifdef HDF5C
|
||||
void WriteHDF5DBitOffset(H5::Group *group);
|
||||
#endif
|
||||
void WriteBinaryDBitBitset(writer *w);
|
||||
#ifdef HDF5C
|
||||
void WriteHDF5DBitBitset(H5::Group *group);
|
||||
#endif
|
||||
void WriteBinaryTransceiverMask(writer *w);
|
||||
#ifdef HDF5C
|
||||
void WriteHDF5TransceiverMask(H5::Group *group);
|
||||
#endif
|
||||
void WriteBinaryTransceiverFlag(writer *w);
|
||||
#ifdef HDF5C
|
||||
void WriteHDF5TransceiverFlag(H5::Group *group);
|
||||
#endif
|
||||
void WriteBinaryTransceiverSamples(writer *w);
|
||||
#ifdef HDF5C
|
||||
void WriteHDF5TransceiverSamples(H5::Group *group);
|
||||
#endif
|
||||
|
||||
/** writes according to type */
|
||||
template <typename T> void WriteBinaryValue(writer *w, const T &value) {
|
||||
if constexpr (std::is_same_v<T, int>) {
|
||||
w->Int(value);
|
||||
} else if constexpr (std::is_same_v<T, uint64_t>) {
|
||||
w->Uint64(value);
|
||||
} else if constexpr (std::is_same_v<T, int64_t>) {
|
||||
w->Int64(value);
|
||||
} else if constexpr (std::is_same_v<T, uint32_t>) {
|
||||
w->Uint(value);
|
||||
} else if constexpr (std::is_same_v<T, std::string>) {
|
||||
w->String(value.c_str());
|
||||
} else if constexpr (is_duration<T>::value) {
|
||||
w->String(ToString(value).c_str());
|
||||
} else {
|
||||
throw RuntimeError("Unsupported type for Binary write: " +
|
||||
std::string(typeid(T).name()));
|
||||
}
|
||||
}
|
||||
|
||||
/** For non-arrays */
|
||||
template <typename T>
|
||||
std::enable_if_t<(!std::is_class_v<T> || std::is_same_v<T, std::string>),
|
||||
void>
|
||||
WriteBinary(writer *w, const std::string &name, const T &value) {
|
||||
w->Key(name.c_str());
|
||||
WriteBinaryValue(w, value);
|
||||
}
|
||||
|
||||
/** For arrays */
|
||||
template <typename T>
|
||||
std::enable_if_t<(std::is_class_v<T> && !std::is_same_v<T, std::string>),
|
||||
void>
|
||||
WriteBinary(writer *w, const std::string &name, const T &value) {
|
||||
w->Key(name.c_str());
|
||||
w->StartArray();
|
||||
for (const auto &v : value) {
|
||||
WriteBinaryValue(w, v);
|
||||
}
|
||||
w->EndArray();
|
||||
}
|
||||
|
||||
#ifdef HDF5C
|
||||
void WriteHDF5String(H5::Group *group, const std::string &name,
|
||||
const std::string &value);
|
||||
void WriteHDF5StringArray(H5::Group *group, const std::string &name,
|
||||
const std::vector<std::string> &value);
|
||||
|
||||
/** get type */
|
||||
template <typename T> H5::PredType const *GetHDF5Type() {
|
||||
if constexpr (std::is_same_v<T, int>) {
|
||||
return &H5::PredType::NATIVE_INT;
|
||||
} else if constexpr (std::is_same_v<T, uint64_t>) {
|
||||
return &H5::PredType::STD_U64LE;
|
||||
} else if constexpr (std::is_same_v<T, int64_t>) {
|
||||
return &H5::PredType::STD_I64LE;
|
||||
} else if constexpr (std::is_same_v<T, uint32_t>) {
|
||||
return &H5::PredType::STD_U32LE;
|
||||
} else {
|
||||
throw RuntimeError("Unsupported type for HDF5");
|
||||
}
|
||||
}
|
||||
|
||||
/** For non-arrays */
|
||||
template <typename T>
|
||||
typename std::enable_if<!std::is_class<T>::value, void>::type
|
||||
WriteHDF5Int(H5::Group *group, const std::string &name, const T &value) {
|
||||
H5::DataSpace dataspace(H5S_SCALAR);
|
||||
auto h5type = GetHDF5Type<T>();
|
||||
H5::DataSet dataset = group->createDataSet(name, *h5type, dataspace);
|
||||
dataset.write(&value, *h5type);
|
||||
}
|
||||
|
||||
/** For arrays */
|
||||
template <typename T>
|
||||
typename std::enable_if<std::is_class<T>::value, void>::type
|
||||
WriteHDF5Int(H5::Group *group, const std::string &name, const T &value) {
|
||||
using ElemT = typename T::value_type;
|
||||
auto h5type = GetHDF5Type<ElemT>();
|
||||
hsize_t dims[1] = {value.size()};
|
||||
H5::DataSpace dataspace(1, dims);
|
||||
H5::DataSet dataset = group->createDataSet(name, *h5type, dataspace);
|
||||
dataset.write(value.data(), *h5type);
|
||||
}
|
||||
|
||||
#endif
|
||||
void WriteBinaryXY(writer *w, const std::string &name, const defs::xy &xy);
|
||||
#ifdef HDF5C
|
||||
void WriteHDF5XY(H5::Group *group, const std::string &name,
|
||||
const defs::xy &xy);
|
||||
#endif
|
||||
void WriteBinaryVersion(writer *w);
|
||||
#ifdef HDF5C
|
||||
void WriteHDF5Version(H5::H5File *fd);
|
||||
#endif
|
||||
void WriteBinaryTimestamp(writer *w);
|
||||
#ifdef HDF5C
|
||||
void WriteHDF5Timestamp(H5::Group *group);
|
||||
#endif
|
||||
void WriteBinaryRois(writer *w);
|
||||
#ifdef HDF5C
|
||||
void WriteHDF5ROIs(H5::Group *group);
|
||||
#endif
|
||||
void WriteBinaryScanParameters(writer *w);
|
||||
#ifdef HDF5C
|
||||
void WriteHDF5ScanParameters(H5::Group *group);
|
||||
#endif
|
||||
void WriteBinaryJsonHeader(writer *w);
|
||||
#ifdef HDF5C
|
||||
void WriteHDF5JsonHeader(H5::Group *group);
|
||||
#endif
|
||||
void WriteBinaryFrameHeaderFormat(writer *w);
|
||||
};
|
||||
|
||||
} // namespace sls
|
||||
|
||||
@@ -49,7 +49,8 @@ std::string CreateMasterBinaryFile(const std::string &filePath,
|
||||
void LinkHDF5FileInMaster(std::string &masterFileName,
|
||||
std::string &dataFilename,
|
||||
std::vector<std::string> parameterNames,
|
||||
const bool silentMode, std::mutex *hdf5LibMutex) {
|
||||
const bool silentMode, std::mutex *hdf5LibMutex,
|
||||
size_t multiRoiSize) {
|
||||
|
||||
std::lock_guard<std::mutex> lock(*hdf5LibMutex);
|
||||
std::unique_ptr<H5::H5File> fd{nullptr};
|
||||
@@ -67,27 +68,35 @@ void LinkHDF5FileInMaster(std::string &masterFileName,
|
||||
fd = make_unique<H5::H5File>(dataFilename.c_str(), H5F_ACC_RDONLY,
|
||||
H5::FileCreatPropList::DEFAULT, flist);
|
||||
|
||||
// create link for data dataset
|
||||
H5::DataSet dset = fd->openDataSet(DATASET_NAME);
|
||||
std::string linkname =
|
||||
std::string("/entry/data/") + std::string(DATASET_NAME);
|
||||
if (H5Lcreate_external(dataFilename.c_str(), DATASET_NAME,
|
||||
masterfd.getLocId(), linkname.c_str(),
|
||||
H5P_DEFAULT, H5P_DEFAULT) < 0) {
|
||||
throw RuntimeError(
|
||||
"Could not create link to data dataset in master");
|
||||
}
|
||||
for (size_t iRoi = 0; iRoi != multiRoiSize; ++iRoi) {
|
||||
|
||||
// create link for parameter datasets
|
||||
for (unsigned int i = 0; i < parameterNames.size(); ++i) {
|
||||
H5::DataSet pDset = fd->openDataSet(parameterNames[i].c_str());
|
||||
linkname = std::string("/entry/data/") + parameterNames[i];
|
||||
if (H5Lcreate_external(dataFilename.c_str(),
|
||||
parameterNames[i].c_str(),
|
||||
// create link for data dataset
|
||||
std::string datasetname = std::string(DATASET_NAME);
|
||||
if (multiRoiSize > 1)
|
||||
datasetname += ('_' + std::to_string(iRoi));
|
||||
H5::DataSet dset = fd->openDataSet(datasetname);
|
||||
std::string linkname = std::string("/entry/data/") + datasetname;
|
||||
if (H5Lcreate_external(dataFilename.c_str(), datasetname.c_str(),
|
||||
masterfd.getLocId(), linkname.c_str(),
|
||||
H5P_DEFAULT, H5P_DEFAULT) < 0) {
|
||||
throw RuntimeError(
|
||||
"Could not create link to parameter dataset in master");
|
||||
"Could not create link to data dataset in master");
|
||||
}
|
||||
|
||||
// create link for parameter datasets
|
||||
for (unsigned int i = 0; i < parameterNames.size(); ++i) {
|
||||
std::string parameterDsetName = parameterNames[i];
|
||||
if (multiRoiSize > 1)
|
||||
parameterDsetName += ('_' + std::to_string(iRoi));
|
||||
H5::DataSet pDset = fd->openDataSet(parameterDsetName.c_str());
|
||||
linkname = std::string("/entry/data/") + parameterDsetName;
|
||||
if (H5Lcreate_external(dataFilename.c_str(),
|
||||
parameterDsetName.c_str(),
|
||||
masterfd.getLocId(), linkname.c_str(),
|
||||
H5P_DEFAULT, H5P_DEFAULT) < 0) {
|
||||
throw RuntimeError(
|
||||
"Could not create link to parameter dataset in master");
|
||||
}
|
||||
}
|
||||
}
|
||||
fd->close();
|
||||
@@ -131,13 +140,6 @@ std::string CreateMasterHDF5File(const std::string &filePath,
|
||||
fd = make_unique<H5::H5File>(fileName.c_str(), createFlags,
|
||||
H5::FileCreatPropList::DEFAULT, flist);
|
||||
|
||||
// attributes - version
|
||||
double dValue = HDF5_WRITER_VERSION;
|
||||
H5::DataSpace dataspace_attr = H5::DataSpace(H5S_SCALAR);
|
||||
H5::Attribute attribute = fd->createAttribute(
|
||||
"version", H5::PredType::NATIVE_DOUBLE, dataspace_attr);
|
||||
attribute.write(H5::PredType::NATIVE_DOUBLE, &dValue);
|
||||
|
||||
// Create a group in the file
|
||||
H5::Group group1(fd->createGroup("entry"));
|
||||
H5::Group group2(group1.createGroup("data"));
|
||||
@@ -160,33 +162,56 @@ std::string CreateMasterHDF5File(const std::string &filePath,
|
||||
return fileName;
|
||||
}
|
||||
|
||||
defs::ROI GetGlobalPortRoi(const int iPort, const defs::xy portSize,
|
||||
const int numPortsY) {
|
||||
defs::xy portPos = {(iPort / numPortsY), (iPort % numPortsY)};
|
||||
const int xmin = portSize.x * portPos.x;
|
||||
const int xmax = xmin + portSize.x - 1;
|
||||
const int ymin = portSize.y * portPos.y;
|
||||
const int ymax = ymin + portSize.y - 1;
|
||||
return defs::ROI{xmin, xmax, ymin, ymax};
|
||||
}
|
||||
|
||||
int GetNumPortsInRoi(const defs::ROI roi, const defs::xy portSize) {
|
||||
if (portSize.x == 0 || portSize.y == 0) {
|
||||
throw RuntimeError("Port width or height cannot be zero");
|
||||
}
|
||||
int iPortXMin = roi.xmin / portSize.x;
|
||||
int iPortXMax = roi.xmax / portSize.x;
|
||||
int iPortYMin = roi.ymin / portSize.y;
|
||||
int iPortYMax = roi.ymax / portSize.y;
|
||||
return ((iPortXMax - iPortXMin + 1) * (iPortYMax - iPortYMin + 1));
|
||||
}
|
||||
|
||||
/** Will not be called if dynamic range is 4 and roi enabled */
|
||||
std::string CreateVirtualHDF5File(
|
||||
const std::string &filePath, const std::string &fileNamePrefix,
|
||||
const uint64_t fileIndex, const bool overWriteEnable, const bool silentMode,
|
||||
const int modulePos, const int numUnitsPerReadout,
|
||||
const uint32_t maxFramesPerFile, const uint32_t nPixelsX,
|
||||
const uint32_t nPixelsY, const uint32_t dynamicRange,
|
||||
const uint64_t numImagesCaught, const int numModX, const int numModY,
|
||||
const H5::DataType dataType, const std::vector<std::string> parameterNames,
|
||||
const uint32_t maxFramesPerFile, const int nPixelsX, const int nPixelsY,
|
||||
const uint32_t dynamicRange, const uint64_t numImagesCaught,
|
||||
const int numModX, const int numModY, const H5::DataType dataType,
|
||||
const std::vector<std::string> parameterNames,
|
||||
const std::vector<H5::DataType> parameterDataTypes,
|
||||
std::mutex *hdf5LibMutex, bool gotthard25um) {
|
||||
std::mutex *hdf5LibMutex, bool gotthard25um,
|
||||
std::vector<defs::ROI> multiRoi) {
|
||||
|
||||
bool completeRoi = false;
|
||||
if (multiRoi.size() == 1 && multiRoi[0].completeRoi()) {
|
||||
completeRoi = true;
|
||||
}
|
||||
|
||||
// virtual file name
|
||||
std::ostringstream osfn;
|
||||
osfn << filePath << "/" << fileNamePrefix << "_virtual"
|
||||
<< "_" << fileIndex << ".h5";
|
||||
std::string fileName = osfn.str();
|
||||
|
||||
unsigned int paraSize = parameterNames.size();
|
||||
uint64_t numModZ = numModX;
|
||||
uint32_t nDimy = nPixelsY;
|
||||
uint32_t nDimz = ((dynamicRange == 4) ? (nPixelsX / 2) : nPixelsX);
|
||||
|
||||
std::lock_guard<std::mutex> lock(*hdf5LibMutex);
|
||||
|
||||
std::unique_ptr<H5::H5File> fd{nullptr};
|
||||
try {
|
||||
H5::Exception::dontPrint(); // to handle errors
|
||||
H5Eset_auto(H5E_DEFAULT, (H5E_auto2_t)H5Eprint, stderr);
|
||||
|
||||
// file
|
||||
H5::FileAccPropList fapl;
|
||||
@@ -198,141 +223,172 @@ std::string CreateVirtualHDF5File(
|
||||
fd = make_unique<H5::H5File>(fileName.c_str(), H5F_ACC_TRUNC,
|
||||
H5::FileCreatPropList::DEFAULT, fapl);
|
||||
|
||||
// attributes - version
|
||||
double dValue = HDF5_WRITER_VERSION;
|
||||
H5::DataSpace dataspace_attr = H5::DataSpace(H5S_SCALAR);
|
||||
H5::Attribute attribute = fd->createAttribute(
|
||||
"version", H5::PredType::NATIVE_DOUBLE, dataspace_attr);
|
||||
attribute.write(H5::PredType::NATIVE_DOUBLE, &dValue);
|
||||
for (size_t iRoi = 0; iRoi != multiRoi.size(); ++iRoi) {
|
||||
|
||||
// dataspace
|
||||
hsize_t vdsDims[DATA_RANK] = {numImagesCaught, numModY * nDimy,
|
||||
numModZ * nDimz};
|
||||
hsize_t vdsDimsPara[VDS_PARA_RANK] = {numImagesCaught,
|
||||
numModY * numModZ};
|
||||
H5::DataSpace vdsDataSpace(DATA_RANK, vdsDims, nullptr);
|
||||
H5::DataSpace vdsDataSpacePara(VDS_PARA_RANK, vdsDimsPara, nullptr);
|
||||
auto currentRoi = multiRoi[iRoi];
|
||||
defs::xy detectorSize = {nPixelsX * numModX, nPixelsY * numModY};
|
||||
if (completeRoi) {
|
||||
currentRoi =
|
||||
defs::ROI{0, detectorSize.x - 1, 0, detectorSize.y - 1};
|
||||
}
|
||||
if (multiRoi[iRoi].completeRoi() && iRoi != 0)
|
||||
throw RuntimeError(
|
||||
"Cannot have complete roi and multiple rois");
|
||||
|
||||
// property list
|
||||
H5::DSetCreatPropList plist;
|
||||
uint64_t fill_value = -1;
|
||||
plist.setFillValue(dataType, &fill_value);
|
||||
std::vector<H5::DSetCreatPropList> plistPara(paraSize);
|
||||
// ignoring last fill (string)
|
||||
for (unsigned int i = 0; i != plistPara.size() - 1; ++i) {
|
||||
plistPara[i].setFillValue(parameterDataTypes[i], &fill_value);
|
||||
}
|
||||
|
||||
// hyperslab (files)
|
||||
int numFiles = numImagesCaught / maxFramesPerFile;
|
||||
if (numImagesCaught % maxFramesPerFile)
|
||||
++numFiles;
|
||||
uint64_t framesSaved = 0;
|
||||
for (int iFile = 0; iFile < numFiles; ++iFile) {
|
||||
|
||||
uint64_t nDimx =
|
||||
((numImagesCaught - framesSaved) > maxFramesPerFile)
|
||||
? maxFramesPerFile
|
||||
: (numImagesCaught - framesSaved);
|
||||
|
||||
hsize_t startLocation[DATA_RANK] = {framesSaved, 0, 0};
|
||||
hsize_t strideBetweenBlocks[DATA_RANK] = {1, 1, 1};
|
||||
hsize_t numBlocks[DATA_RANK] = {nDimx, nDimy, nDimz};
|
||||
hsize_t blockSize[DATA_RANK] = {1, 1, 1};
|
||||
|
||||
hsize_t startLocationPara[VDS_PARA_RANK] = {framesSaved, 0};
|
||||
hsize_t strideBetweenBlocksPara[VDS_PARA_RANK] = {1, 1};
|
||||
hsize_t numBlocksPara[VDS_PARA_RANK] = {nDimx, 1};
|
||||
hsize_t blockSizePara[VDS_PARA_RANK] = {1, 1};
|
||||
|
||||
// interleaving for g2
|
||||
if (gotthard25um) {
|
||||
strideBetweenBlocks[2] = 2;
|
||||
// get detector shape and number of ports in roi
|
||||
defs::xy portSize{nPixelsX, nPixelsY};
|
||||
uint32_t nTotalPorts = numModX * numModY;
|
||||
hsize_t roiWidth = detectorSize.x;
|
||||
hsize_t roiHeight = detectorSize.y;
|
||||
hsize_t nPortsInRoi = nTotalPorts;
|
||||
if (!completeRoi) {
|
||||
roiWidth = multiRoi[iRoi].width();
|
||||
roiHeight = multiRoi[iRoi].height();
|
||||
nPortsInRoi = GetNumPortsInRoi(multiRoi[iRoi], portSize);
|
||||
}
|
||||
|
||||
for (unsigned int iReadout = 0; iReadout < numModY * numModZ;
|
||||
++iReadout) {
|
||||
// dataspace
|
||||
uint64_t nImages = numImagesCaught;
|
||||
int numFiles = numImagesCaught / maxFramesPerFile;
|
||||
if (numImagesCaught % maxFramesPerFile)
|
||||
++numFiles;
|
||||
|
||||
// interleaving for g2 (startLocation is 0 and 1)
|
||||
hsize_t vdsDims[DATA_RANK] = {nImages, roiHeight, roiWidth};
|
||||
hsize_t vdsDimsPara[VDS_PARA_RANK] = {nImages, nPortsInRoi};
|
||||
H5::DataSpace vdsDataSpace(DATA_RANK, vdsDims, nullptr);
|
||||
H5::DataSpace vdsDataSpacePara(VDS_PARA_RANK, vdsDimsPara, nullptr);
|
||||
|
||||
// property list
|
||||
H5::DSetCreatPropList plist;
|
||||
uint64_t fill_value = -1;
|
||||
plist.setFillValue(dataType, &fill_value);
|
||||
std::vector<H5::DSetCreatPropList> plistPara(paraSize);
|
||||
// ignoring last fill (string)
|
||||
for (unsigned int i = 0; i != plistPara.size() - 1; ++i) {
|
||||
plistPara[i].setFillValue(parameterDataTypes[i], &fill_value);
|
||||
}
|
||||
|
||||
// hyperslab (files)
|
||||
uint64_t framesSaved = 0;
|
||||
for (int iFile = 0; iFile != numFiles; ++iFile) {
|
||||
|
||||
// images in src file
|
||||
uint64_t nSrcFileImages = numImagesCaught - framesSaved;
|
||||
if ((numImagesCaught - framesSaved) > maxFramesPerFile)
|
||||
nSrcFileImages = maxFramesPerFile;
|
||||
|
||||
hsize_t strideBetweenBlocks[DATA_RANK] = {1, 1, 1};
|
||||
hsize_t numBlocks[DATA_RANK] = {1, 1, 1};
|
||||
hsize_t strideBetweenBlocksPara[VDS_PARA_RANK] = {1, 1};
|
||||
hsize_t numBlocksPara[VDS_PARA_RANK] = {1, 1};
|
||||
hsize_t blockSizePara[VDS_PARA_RANK] = {nSrcFileImages, 1};
|
||||
|
||||
// following recalculated for every readout
|
||||
hsize_t blockSize[DATA_RANK] = {nSrcFileImages,
|
||||
static_cast<hsize_t>(nPixelsY),
|
||||
static_cast<hsize_t>(nPixelsX)};
|
||||
hsize_t startLocation[DATA_RANK] = {framesSaved, 0, 0};
|
||||
hsize_t startLocationPara[VDS_PARA_RANK] = {framesSaved, 0};
|
||||
|
||||
// interleaving for g2
|
||||
if (gotthard25um) {
|
||||
startLocation[2] = iReadout;
|
||||
strideBetweenBlocks[2] = 2;
|
||||
}
|
||||
|
||||
vdsDataSpace.selectHyperslab(H5S_SELECT_SET, numBlocks,
|
||||
startLocation, strideBetweenBlocks,
|
||||
blockSize);
|
||||
for (unsigned int iReadout = 0; iReadout < nTotalPorts;
|
||||
++iReadout) {
|
||||
auto globalPortRoi =
|
||||
GetGlobalPortRoi(iReadout, portSize, numModY);
|
||||
if (!globalPortRoi.overlap(currentRoi))
|
||||
continue;
|
||||
|
||||
vdsDataSpacePara.selectHyperslab(
|
||||
H5S_SELECT_SET, numBlocksPara, startLocationPara,
|
||||
strideBetweenBlocksPara, blockSizePara);
|
||||
// calculate start location (special for roi)
|
||||
int xmin = std::max(currentRoi.xmin, globalPortRoi.xmin);
|
||||
int xmax = std::min(currentRoi.xmax, globalPortRoi.xmax);
|
||||
int ymin = std::max(currentRoi.ymin, globalPortRoi.ymin);
|
||||
int ymax = std::min(currentRoi.ymax, globalPortRoi.ymax);
|
||||
hsize_t portRoiHeight = ymax - ymin + 1;
|
||||
hsize_t portRoiWidth = xmax - xmin + 1;
|
||||
|
||||
// source file name
|
||||
std::ostringstream os;
|
||||
os << filePath << "/" << fileNamePrefix << "_d"
|
||||
<< (modulePos * numUnitsPerReadout + iReadout) << "_f"
|
||||
<< iFile << '_' << fileIndex << ".h5";
|
||||
std::string srcFileName = os.str();
|
||||
LOG(logDEBUG1) << srcFileName;
|
||||
|
||||
// find relative path
|
||||
std::string relative_srcFileName = srcFileName;
|
||||
{
|
||||
size_t p = srcFileName.rfind('/', srcFileName.length());
|
||||
if (p != std::string::npos)
|
||||
relative_srcFileName = (srcFileName.substr(
|
||||
p + 1, srcFileName.length() - p));
|
||||
}
|
||||
|
||||
// source dataspace
|
||||
hsize_t srcDims[DATA_RANK] = {nDimx, nDimy, nDimz};
|
||||
hsize_t srcDimsMax[DATA_RANK] = {H5S_UNLIMITED, nDimy, nDimz};
|
||||
H5::DataSpace srcDataSpace(DATA_RANK, srcDims, srcDimsMax);
|
||||
hsize_t srcDimsPara[PARA_RANK] = {nDimx};
|
||||
hsize_t srcDimsMaxPara[PARA_RANK] = {H5S_UNLIMITED};
|
||||
H5::DataSpace srcDataSpacePara(PARA_RANK, srcDimsPara,
|
||||
srcDimsMaxPara);
|
||||
// temporary fixfor corner case bug:
|
||||
// (framescaught not multiple of framesperfile,
|
||||
// virtual parameter datasets error loading (bad scalar value))
|
||||
if (nDimx != maxFramesPerFile) {
|
||||
hsize_t count[1] = {nDimx};
|
||||
hsize_t start[1] = {0};
|
||||
srcDataSpacePara.selectHyperslab(
|
||||
H5S_SELECT_SET, count, start, strideBetweenBlocksPara,
|
||||
blockSizePara);
|
||||
}
|
||||
|
||||
// mapping of property list
|
||||
plist.setVirtual(vdsDataSpace, relative_srcFileName.c_str(),
|
||||
DATASET_NAME, srcDataSpace);
|
||||
for (unsigned int p = 0; p < paraSize; ++p) {
|
||||
plistPara[p].setVirtual(
|
||||
vdsDataSpacePara, relative_srcFileName.c_str(),
|
||||
parameterNames[p].c_str(), srcDataSpacePara);
|
||||
}
|
||||
|
||||
// H5Sclose(srcDataspace);
|
||||
// H5Sclose(srcDataspace_para);
|
||||
|
||||
if (!gotthard25um) {
|
||||
startLocation[2] += nDimz;
|
||||
if (startLocation[2] >= (numModZ * nDimz)) {
|
||||
startLocation[2] = 0;
|
||||
startLocation[1] += nDimy;
|
||||
// recalculating start location and block size
|
||||
if (!gotthard25um) {
|
||||
startLocation[1] = ymin - currentRoi.ymin;
|
||||
startLocation[2] = xmin - currentRoi.xmin;
|
||||
blockSize[1] = portRoiHeight;
|
||||
blockSize[2] = portRoiWidth;
|
||||
}
|
||||
// interleaving for g2 (startLocation is 0 and 1) (g2 had no
|
||||
// roi)
|
||||
else {
|
||||
++startLocation[2];
|
||||
}
|
||||
}
|
||||
++startLocationPara[1];
|
||||
}
|
||||
framesSaved += nDimx;
|
||||
}
|
||||
// datasets
|
||||
H5::DataSet vdsDataSet(
|
||||
fd->createDataSet(DATASET_NAME, dataType, vdsDataSpace, plist));
|
||||
|
||||
for (unsigned int p = 0; p < paraSize; ++p) {
|
||||
H5::DataSet vdsDataSetPara(fd->createDataSet(
|
||||
parameterNames[p].c_str(), parameterDataTypes[p],
|
||||
vdsDataSpacePara, plistPara[p]));
|
||||
vdsDataSpace.selectHyperslab(
|
||||
H5S_SELECT_SET, numBlocks, startLocation,
|
||||
strideBetweenBlocks, blockSize);
|
||||
|
||||
vdsDataSpacePara.selectHyperslab(
|
||||
H5S_SELECT_SET, numBlocksPara, startLocationPara,
|
||||
strideBetweenBlocksPara, blockSizePara);
|
||||
|
||||
// source file name
|
||||
std::ostringstream os;
|
||||
os << filePath << "/" << fileNamePrefix << "_d"
|
||||
<< (modulePos * numUnitsPerReadout + iReadout) << "_f"
|
||||
<< iFile << '_' << fileIndex << ".h5";
|
||||
std::string srcFileName = os.str();
|
||||
LOG(logDEBUG1) << srcFileName;
|
||||
|
||||
// find relative path
|
||||
std::string relative_srcFileName = srcFileName;
|
||||
{
|
||||
size_t p = srcFileName.rfind('/', srcFileName.length());
|
||||
if (p != std::string::npos)
|
||||
relative_srcFileName = (srcFileName.substr(
|
||||
p + 1, srcFileName.length() - p));
|
||||
}
|
||||
|
||||
// source dataspace
|
||||
hsize_t srcDims[DATA_RANK] = {nSrcFileImages, portRoiHeight,
|
||||
portRoiWidth};
|
||||
hsize_t srcDimsMax[DATA_RANK] = {
|
||||
H5S_UNLIMITED, portRoiHeight, portRoiWidth};
|
||||
H5::DataSpace srcDataSpace(DATA_RANK, srcDims, srcDimsMax);
|
||||
hsize_t srcDimsPara[PARA_RANK] = {nSrcFileImages};
|
||||
hsize_t srcDimsMaxPara[PARA_RANK] = {H5S_UNLIMITED};
|
||||
H5::DataSpace srcDataSpacePara(PARA_RANK, srcDimsPara,
|
||||
srcDimsMaxPara);
|
||||
|
||||
// mapping of property list
|
||||
plist.setVirtual(vdsDataSpace, relative_srcFileName.c_str(),
|
||||
DATASET_NAME, srcDataSpace);
|
||||
for (unsigned int p = 0; p < paraSize; ++p) {
|
||||
plistPara[p].setVirtual(
|
||||
vdsDataSpacePara, relative_srcFileName.c_str(),
|
||||
parameterNames[p].c_str(), srcDataSpacePara);
|
||||
}
|
||||
|
||||
// map next readout
|
||||
++startLocationPara[1];
|
||||
}
|
||||
framesSaved += nSrcFileImages;
|
||||
}
|
||||
// datasets
|
||||
std::string datasetname = std::string(DATASET_NAME);
|
||||
// suffix '_[iRoi]' for multiple rois
|
||||
if (multiRoi.size() > 1)
|
||||
datasetname += ('_' + std::to_string(iRoi));
|
||||
H5::DataSet vdsDataSet(
|
||||
fd->createDataSet(datasetname, dataType, vdsDataSpace, plist));
|
||||
for (unsigned int p = 0; p < paraSize; ++p) {
|
||||
std::string parameterDsetName = parameterNames[p];
|
||||
// suffix '_[iRoi]' for multiple rois
|
||||
if (multiRoi.size() > 1)
|
||||
parameterDsetName += ('_' + std::to_string(iRoi));
|
||||
H5::DataSet vdsDataSetPara(fd->createDataSet(
|
||||
parameterDsetName.c_str(), parameterDataTypes[p],
|
||||
vdsDataSpacePara, plistPara[p]));
|
||||
}
|
||||
}
|
||||
|
||||
fd->close();
|
||||
|
||||
@@ -21,7 +21,8 @@ std::string CreateMasterBinaryFile(const std::string &filePath,
|
||||
void LinkHDF5FileInMaster(std::string &masterFileName,
|
||||
std::string &dataFilename,
|
||||
std::vector<std::string> parameterNames,
|
||||
const bool silentMode, std::mutex *hdf5LibMutex);
|
||||
const bool silentMode, std::mutex *hdf5LibMutex,
|
||||
size_t multiRoiSize);
|
||||
|
||||
std::string CreateMasterHDF5File(const std::string &filePath,
|
||||
const std::string &fileNamePrefix,
|
||||
@@ -29,17 +30,21 @@ std::string CreateMasterHDF5File(const std::string &filePath,
|
||||
const bool overWriteEnable,
|
||||
const bool silentMode, MasterAttributes *attr,
|
||||
std::mutex *hdf5LibMutex);
|
||||
defs::ROI GetGlobalPortRoi(const int iPort, const defs::xy portSize,
|
||||
const int numPortsY);
|
||||
int GetNumPortsInRoi(const defs::ROI roi, const defs::xy portSize);
|
||||
|
||||
std::string CreateVirtualHDF5File(
|
||||
const std::string &filePath, const std::string &fileNamePrefix,
|
||||
const uint64_t fileIndex, const bool overWriteEnable, const bool silentMode,
|
||||
const int modulePos, const int numUnitsPerReadout,
|
||||
const uint32_t maxFramesPerFile, const uint32_t nPixelsX,
|
||||
const uint32_t nPixelsY, const uint32_t dynamicRange,
|
||||
const uint64_t numImagesCaught, const int numModX, const int numModY,
|
||||
const H5::DataType dataType, const std::vector<std::string> parameterNames,
|
||||
const uint32_t maxFramesPerFile, const int nPixelsX, const int nPixelsY,
|
||||
const uint32_t dynamicRange, const uint64_t numImagesCaught,
|
||||
const int numModX, const int numModY, const H5::DataType dataType,
|
||||
const std::vector<std::string> parameterNames,
|
||||
const std::vector<H5::DataType> parameterDataTypes,
|
||||
std::mutex *hdf5LibMutex, bool gotthard25um);
|
||||
std::mutex *hdf5LibMutex, bool gotthard25um,
|
||||
std::vector<defs::ROI> multiRoi);
|
||||
#endif
|
||||
} // namespace masterFileUtility
|
||||
|
||||
|
||||
@@ -2,16 +2,16 @@
|
||||
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||
/* Creates the slsMultiReceiver for running multiple receivers form a single
|
||||
* binary */
|
||||
#include "CommandLineOptions.h"
|
||||
#include "sls/Receiver.h"
|
||||
#include "sls/ToString.h"
|
||||
#include "sls/container_utils.h"
|
||||
#include "sls/logger.h"
|
||||
#include "sls/network_utils.h"
|
||||
#include "sls/sls_detector_defs.h"
|
||||
#include "sls/versionAPI.h"
|
||||
|
||||
#include <csignal> //SIGINT
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <semaphore.h>
|
||||
#include <sys/wait.h> //wait
|
||||
#include <unistd.h>
|
||||
@@ -27,37 +27,13 @@
|
||||
#define PRINT_IN_COLOR(c, f, ...) \
|
||||
printf("\033[%dm" f RESET, 30 + c + 1, ##__VA_ARGS__)
|
||||
|
||||
sem_t semaphore;
|
||||
|
||||
/**
|
||||
* Control+C Interrupt Handler
|
||||
* to let all the processes know to exit properly
|
||||
*/
|
||||
void sigInterruptHandler(int p) { sem_post(&semaphore); }
|
||||
|
||||
/**
|
||||
* prints usage of this example program
|
||||
*/
|
||||
std::string getHelpMessage() {
|
||||
std::ostringstream os;
|
||||
os << "\nUsage:\n\n"
|
||||
<< "./slsMultiReceiver --version or -v\n"
|
||||
<< "\t - Gets the slsMultiReceiver version\n\n"
|
||||
<< "./slsMultiReceiver [start tcp port] [num recevers] [call back "
|
||||
"option (optional)]\n"
|
||||
<< "\t - tcp port has to be non-zero and 16 bit\n"
|
||||
<< "\t - call back option is 0 (disabled) by default, 1 prints frame "
|
||||
"header for debugging\n";
|
||||
return os.str();
|
||||
}
|
||||
|
||||
/**
|
||||
* Start Acquisition Call back (slsMultiReceiver writes data if file write
|
||||
* enabled) if registerCallBackRawDataReady or
|
||||
* registerCallBackRawDataModifyReady registered, users get data
|
||||
*/
|
||||
int StartAcq(const slsDetectorDefs::startCallbackHeader callbackHeader,
|
||||
void *objectPointer) {
|
||||
void StartAcq(const slsDetectorDefs::startCallbackHeader callbackHeader,
|
||||
void *objectPointer) {
|
||||
LOG(sls::logINFOBLUE) << "#### Start Acquisition:"
|
||||
<< "\n\t["
|
||||
<< "\n\tUDP Port : "
|
||||
@@ -74,7 +50,6 @@ int StartAcq(const slsDetectorDefs::startCallbackHeader callbackHeader,
|
||||
<< "\n\tAdditional Json Header : "
|
||||
<< sls::ToString(callbackHeader.addJsonHeader)
|
||||
<< "\n\t]";
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Acquisition Finished Call back */
|
||||
@@ -150,109 +125,48 @@ void GetData(slsDetectorDefs::sls_receiver_header &header,
|
||||
// header->packetsMask.to_string().c_str(),
|
||||
((uint8_t)(*((uint8_t *)(dataPointer)))), imageSize);
|
||||
|
||||
// // example of how to use roi or modify data that is later written to file
|
||||
// slsDetectorDefs::ROI roi{0, 10, 0, 20};
|
||||
// int width = roi.xmax - roi.xmin;
|
||||
// int height = roi.ymax - roi.ymin;
|
||||
// uint8_t *destPtr = (uint8_t *)dataPointer;
|
||||
// for (int irow = roi.ymin; irow < roi.ymax; ++irow) {
|
||||
// memcpy(destPtr,
|
||||
// ((uint8_t *)(dataPointer + irow * callbackHeader.shape.x +
|
||||
// roi.xmin)),
|
||||
// width);
|
||||
// destPtr += width;
|
||||
// }
|
||||
// memcpy((uint8_t*)dataPointer, (uint8_t*)dataPointer
|
||||
// // setting roi for eg. changes size
|
||||
// imageSize = width * height;
|
||||
// if data is modified, can affect size
|
||||
// only reduction in size allowed, not increase
|
||||
// imageSize = 26000;
|
||||
}
|
||||
|
||||
sem_t semaphore;
|
||||
|
||||
/**
|
||||
* Example of main program using the Receiver class
|
||||
*
|
||||
* - Defines in file for:
|
||||
* - Default Number of receivers is 1
|
||||
* - Default Start TCP port is 1954
|
||||
* Control+C Interrupt Handler
|
||||
* to let all the processes know to exit properly
|
||||
* All child processes will call the handler (parent process set to ignore)
|
||||
*/
|
||||
void sigInterruptHandler(int signal) {
|
||||
(void)signal; // suppress unused warning if needed
|
||||
sem_post(&semaphore);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
// version
|
||||
if (argc == 2) {
|
||||
std::string sargv1 = std::string(argv[1]);
|
||||
if (sargv1 == "--version" || sargv1 == "-v") {
|
||||
std::cout << "slsMultiReceiver Version: " << APIRECEIVER
|
||||
<< std::endl;
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
CommandLineOptions cli(AppType::MultiReceiver);
|
||||
ParsedOptions opts;
|
||||
try {
|
||||
opts = cli.parse(argc, argv);
|
||||
} catch (sls::RuntimeError &e) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
auto &m = std::get<MultiReceiverOptions>(opts);
|
||||
if (m.versionRequested || m.helpRequested) {
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
/** - set default values */
|
||||
int numReceivers = 1;
|
||||
uint16_t startTCPPort = DEFAULT_TCP_RX_PORTNO;
|
||||
int withCallback = 0;
|
||||
LOG(sls::logINFOBLUE) << "Current Process [ Tid: " << gettid() << ']';
|
||||
|
||||
// close files on ctrl+c
|
||||
sls::setupSignalHandler(SIGINT, sigInterruptHandler);
|
||||
// handle locally on socket crash
|
||||
sls::setupSignalHandler(SIGPIPE, SIG_IGN);
|
||||
|
||||
sem_init(&semaphore, 1, 0);
|
||||
|
||||
/** - get number of receivers and start tcp port from command line
|
||||
* arguments */
|
||||
if (argc > 1) {
|
||||
try {
|
||||
if (argc == 3 || argc == 4) {
|
||||
startTCPPort = sls::StringTo<uint16_t>(argv[1]);
|
||||
if (startTCPPort == 0) {
|
||||
throw std::runtime_error("Invalid start tcp port");
|
||||
}
|
||||
numReceivers = std::stoi(argv[2]);
|
||||
if (numReceivers > 1024) {
|
||||
cprintf(RED,
|
||||
"Did you mix up the order of the arguments?\n%s\n",
|
||||
getHelpMessage().c_str());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (numReceivers == 0) {
|
||||
cprintf(RED, "Invalid number of receivers.\n%s\n",
|
||||
getHelpMessage().c_str());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (argc == 4) {
|
||||
withCallback = std::stoi(argv[3]);
|
||||
}
|
||||
} else
|
||||
throw std::runtime_error("Invalid number of arguments");
|
||||
} catch (const std::exception &e) {
|
||||
cprintf(RED, "Error: %s\n%s\n", e.what(), getHelpMessage().c_str());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
cprintf(BLUE, "Parent Process Created [ Tid: %ld ]\n", (long)gettid());
|
||||
cprintf(RESET, "Number of Receivers: %d\n", numReceivers);
|
||||
cprintf(RESET, "Start TCP Port: %hu\n", startTCPPort);
|
||||
cprintf(RESET, "Callback Enable: %d\n", withCallback);
|
||||
|
||||
/** - Catch signal SIGINT to close files and call destructors properly */
|
||||
struct sigaction sa;
|
||||
sa.sa_flags = 0; // no flags
|
||||
sa.sa_handler = sigInterruptHandler; // handler function
|
||||
sigemptyset(&sa.sa_mask); // dont block additional signals during invocation
|
||||
// of handler
|
||||
if (sigaction(SIGINT, &sa, nullptr) == -1) {
|
||||
cprintf(RED, "Could not set handler function for SIGINT\n");
|
||||
}
|
||||
|
||||
/** - Ignore SIG_PIPE, prevents global signal handler, handle locally,
|
||||
instead of a server crashing due to client crash when writing, it just
|
||||
gives error */
|
||||
struct sigaction asa;
|
||||
asa.sa_flags = 0; // no flags
|
||||
asa.sa_handler = SIG_IGN; // handler function
|
||||
sigemptyset(&asa.sa_mask); // dont block additional signals during
|
||||
// invocation of handler
|
||||
if (sigaction(SIGPIPE, &asa, nullptr) == -1) {
|
||||
cprintf(RED, "Could not set handler function for SIGPIPE\n");
|
||||
}
|
||||
|
||||
/** - loop over number of receivers */
|
||||
for (int i = 0; i < numReceivers; ++i) {
|
||||
/** - loop over receivers */
|
||||
for (int i = 0; i < m.numReceivers; ++i) {
|
||||
|
||||
/** - fork process to create child process */
|
||||
pid_t pid = fork();
|
||||
@@ -260,89 +174,89 @@ int main(int argc, char *argv[]) {
|
||||
/** - if fork failed, raise SIGINT and properly destroy all child
|
||||
* processes */
|
||||
if (pid < 0) {
|
||||
cprintf(RED, "fork() failed. Killing all the receiver objects\n");
|
||||
LOG(sls::logERROR)
|
||||
<< "fork() failed. Killing all the receiver objects";
|
||||
raise(SIGINT);
|
||||
}
|
||||
|
||||
/** - if child process */
|
||||
else if (pid == 0) {
|
||||
cprintf(BLUE, "Child process %d [ Tid: %ld ]\n", i, (long)gettid());
|
||||
LOG(sls::logINFOBLUE)
|
||||
<< "Child process " << i << " [ Tid: " << gettid() << ']';
|
||||
|
||||
try {
|
||||
uint16_t port = startTCPPort + i;
|
||||
uint16_t port = m.port + i;
|
||||
sls::Receiver receiver(port);
|
||||
|
||||
/** - register callbacks. remember to set file write enable
|
||||
* to 0 (using the client) if we should not write files and you
|
||||
* will write data using the callbacks */
|
||||
if (withCallback) {
|
||||
if (m.callbackEnabled) {
|
||||
|
||||
/** - Call back for start acquisition */
|
||||
cprintf(BLUE, "Registering StartAcq()\n");
|
||||
LOG(sls::logINFOBLUE) << "Registering StartAcq()";
|
||||
receiver.registerCallBackStartAcquisition(StartAcq,
|
||||
nullptr);
|
||||
|
||||
/** - Call back for acquisition finished */
|
||||
cprintf(BLUE, "Registering AcquisitionFinished()\n");
|
||||
LOG(sls::logINFOBLUE)
|
||||
<< "Registering AcquisitionFinished()";
|
||||
receiver.registerCallBackAcquisitionFinished(
|
||||
AcquisitionFinished, nullptr);
|
||||
|
||||
/* - Call back for raw data */
|
||||
cprintf(BLUE, "Registering GetData() \n");
|
||||
LOG(sls::logINFOBLUE) << "Registering GetData()";
|
||||
receiver.registerCallBackRawDataReady(GetData, nullptr);
|
||||
}
|
||||
|
||||
/** - as long as no Ctrl+C */
|
||||
// each child process gets a copy of the semaphore
|
||||
sem_wait(&semaphore);
|
||||
sem_destroy(&semaphore);
|
||||
|
||||
LOG(sls::logINFOBLUE)
|
||||
<< "Exiting Child Process [ Tid: " << gettid() << ']';
|
||||
exit(EXIT_SUCCESS);
|
||||
} catch (...) {
|
||||
sem_destroy(&semaphore);
|
||||
LOG(sls::logINFOBLUE)
|
||||
<< "Exiting Child Process [ Tid: " << gettid() << " ]";
|
||||
throw;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
cprintf(BLUE, "Exiting Child Process [ Tid: %ld ]\n",
|
||||
(long)gettid());
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
/** - Parent process ignores SIGINT (exits only when all child process
|
||||
* exits) */
|
||||
sa.sa_flags = 0; // no flags
|
||||
sa.sa_handler = SIG_IGN; // handler function
|
||||
sigemptyset(&sa.sa_mask); // dont block additional signals during invocation
|
||||
// of handler
|
||||
if (sigaction(SIGINT, &sa, nullptr) == -1) {
|
||||
cprintf(RED, "Could not set handler function for SIGINT\n");
|
||||
}
|
||||
/** - Parent process ignores SIGINT and waits for all the child processes to
|
||||
* handle the signal */
|
||||
sls::setupSignalHandler(SIGINT, SIG_IGN);
|
||||
|
||||
/** - Print Ready and Instructions how to exit */
|
||||
std::cout << "Ready ... \n";
|
||||
cprintf(RESET, "\n[ Press \'Ctrl+c\' to exit ]\n");
|
||||
LOG(sls::logINFO) << "\n[ Press \'Ctrl+c\' to exit ]";
|
||||
|
||||
/** - Parent process waits for all child processes to exit */
|
||||
for (;;) {
|
||||
pid_t childPid = waitpid(-1, nullptr, 0);
|
||||
int status;
|
||||
pid_t childPid = waitpid(-1, &status, 0);
|
||||
|
||||
// no child closed
|
||||
if (childPid == -1) {
|
||||
if (errno == ECHILD) {
|
||||
cprintf(GREEN, "All Child Processes have been closed\n");
|
||||
LOG(sls::logINFOGREEN)
|
||||
<< "All Child Processes have been closed";
|
||||
break;
|
||||
} else {
|
||||
cprintf(RED, "Unexpected error from waitpid(): (%s)\n",
|
||||
strerror(errno));
|
||||
LOG(sls::logERROR)
|
||||
<< "Unexpected error from waitpid(): " << strerror(errno);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// child closed
|
||||
cprintf(BLUE, "Exiting Child Process [ Tid: %ld ]\n",
|
||||
(long int)childPid);
|
||||
if (WIFEXITED(status) && WEXITSTATUS(status) != 0) {
|
||||
std::cerr << "Child " << childPid << " failed\n";
|
||||
kill(0, SIGINT); // signal other children to exit
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "Goodbye!\n";
|
||||
return 0;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -27,106 +27,14 @@ namespace sls {
|
||||
|
||||
Receiver::~Receiver() = default;
|
||||
|
||||
Receiver::Receiver(int argc, char *argv[]) : tcpipInterface(nullptr) {
|
||||
|
||||
// options
|
||||
uint16_t tcpip_port_no = 1954;
|
||||
uid_t userid = -1;
|
||||
|
||||
// parse command line for config
|
||||
static struct option long_options[] = {
|
||||
// These options set a flag.
|
||||
//{"verbose", no_argument, &verbose_flag, 1},
|
||||
// These options don’t set a flag. We distinguish them by their indices.
|
||||
{"rx_tcpport", required_argument, nullptr,
|
||||
't'}, // TODO change or backward compatible to "port, p"?
|
||||
{"uid", required_argument, nullptr, 'u'},
|
||||
{"version", no_argument, nullptr, 'v'},
|
||||
{"help", no_argument, nullptr, 'h'},
|
||||
{nullptr, 0, nullptr, 0}};
|
||||
|
||||
// initialize global optind variable (required when instantiating multiple
|
||||
// receivers in the same process)
|
||||
optind = 1;
|
||||
// getopt_long stores the option index here.
|
||||
int option_index = 0;
|
||||
int c = 0;
|
||||
|
||||
std::string help_message =
|
||||
"\nUsage: " + std::string(argv[0]) + " [arguments]\n" +
|
||||
"Possible arguments are:\n" +
|
||||
"\t-t, --rx_tcpport <port> : TCP Communication Port with "
|
||||
"client. Non-zero and 16 bit.\n" +
|
||||
"\t-u, --uid <user id> : Set effective user id if receiver "
|
||||
"\n" +
|
||||
"\t started with privileges. \n\n";
|
||||
|
||||
while (c != -1) {
|
||||
c = getopt_long(argc, argv, "hvt:u:", long_options, &option_index);
|
||||
|
||||
// Detect the end of the options.
|
||||
if (c == -1)
|
||||
break;
|
||||
|
||||
switch (c) {
|
||||
|
||||
case 't':
|
||||
try {
|
||||
tcpip_port_no = sls::StringTo<uint16_t>(optarg);
|
||||
validatePortNumber(tcpip_port_no);
|
||||
} catch (...) {
|
||||
throw RuntimeError("Could not scan TCP port number." +
|
||||
help_message);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
if (sscanf(optarg, "%u", &userid) != 1) {
|
||||
throw RuntimeError("Could not scan uid" + help_message);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
std::cout << "slsReceiver Version: " << APIRECEIVER << std::endl;
|
||||
LOG(logINFOBLUE) << "Exiting [ Tid: " << gettid() << " ]";
|
||||
exit(EXIT_SUCCESS);
|
||||
|
||||
case 'h':
|
||||
std::cout << help_message << std::endl;
|
||||
exit(EXIT_SUCCESS);
|
||||
default:
|
||||
throw RuntimeError(help_message);
|
||||
}
|
||||
Receiver::Receiver(uint16_t port) {
|
||||
validatePortNumber(port);
|
||||
#ifdef SLS_USE_TESTS
|
||||
if (port == 65535) {
|
||||
throw sls::RuntimeError("Throwing for testing purposes. ");
|
||||
}
|
||||
|
||||
// set effective id if provided
|
||||
if (userid != static_cast<uid_t>(-1)) {
|
||||
if (geteuid() == userid) {
|
||||
LOG(logINFO) << "Process already has the same Effective UID "
|
||||
<< userid;
|
||||
} else {
|
||||
if (seteuid(userid) != 0) {
|
||||
std::ostringstream oss;
|
||||
oss << "Could not set Effective UID to " << userid;
|
||||
throw RuntimeError(oss.str());
|
||||
}
|
||||
if (geteuid() != userid) {
|
||||
std::ostringstream oss;
|
||||
oss << "Could not set Effective UID to " << userid << ". Got "
|
||||
<< geteuid();
|
||||
throw RuntimeError(oss.str());
|
||||
}
|
||||
LOG(logINFO) << "Process Effective UID changed to " << userid;
|
||||
}
|
||||
}
|
||||
|
||||
// might throw an exception
|
||||
tcpipInterface = make_unique<ClientInterface>(tcpip_port_no);
|
||||
}
|
||||
|
||||
Receiver::Receiver(uint16_t tcpip_port_no) {
|
||||
// might throw an exception
|
||||
tcpipInterface = make_unique<ClientInterface>(tcpip_port_no);
|
||||
#endif
|
||||
tcpipInterface = make_unique<ClientInterface>(port);
|
||||
}
|
||||
|
||||
std::string Receiver::getReceiverVersion() {
|
||||
@@ -134,7 +42,7 @@ std::string Receiver::getReceiverVersion() {
|
||||
}
|
||||
|
||||
void Receiver::registerCallBackStartAcquisition(
|
||||
int (*func)(const startCallbackHeader, void *), void *arg) {
|
||||
void (*func)(const startCallbackHeader, void *), void *arg) {
|
||||
tcpipInterface->registerCallBackStartAcquisition(func, arg);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-other
|
||||
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||
/* slsReceiver */
|
||||
#include "CommandLineOptions.h"
|
||||
#include "sls/Receiver.h"
|
||||
#include "sls/ToString.h"
|
||||
#include "sls/container_utils.h"
|
||||
#include "sls/logger.h"
|
||||
#include "sls/network_utils.h"
|
||||
#include "sls/sls_detector_defs.h"
|
||||
|
||||
#include <csignal> //SIGINT
|
||||
@@ -18,44 +21,49 @@
|
||||
|
||||
sem_t semaphore;
|
||||
|
||||
void sigInterruptHandler(int p) { sem_post(&semaphore); }
|
||||
/**
|
||||
* Control+C Interrupt Handler
|
||||
* to let all the other process know to exit properly
|
||||
*/
|
||||
void sigInterruptHandler(int signal) {
|
||||
(void)signal; // suppress unused warning if needed
|
||||
sem_post(&semaphore);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
CommandLineOptions cli(AppType::SingleReceiver);
|
||||
ParsedOptions opts;
|
||||
try {
|
||||
opts = cli.parse(argc, argv);
|
||||
} catch (sls::RuntimeError &e) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
auto &o = std::get<CommonOptions>(opts);
|
||||
if (o.versionRequested || o.helpRequested) {
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
LOG(sls::logINFOBLUE) << "Current Process [ Tid: " << gettid() << " ]";
|
||||
|
||||
// close files on ctrl+c
|
||||
sls::setupSignalHandler(SIGINT, sigInterruptHandler);
|
||||
// handle locally on socket crash
|
||||
sls::setupSignalHandler(SIGPIPE, SIG_IGN);
|
||||
|
||||
sem_init(&semaphore, 1, 0);
|
||||
|
||||
LOG(sls::logINFOBLUE) << "Created [ Tid: " << gettid() << " ]";
|
||||
|
||||
// Catch signal SIGINT to close files and call destructors properly
|
||||
struct sigaction sa;
|
||||
sa.sa_flags = 0; // no flags
|
||||
sa.sa_handler = sigInterruptHandler; // handler function
|
||||
sigemptyset(&sa.sa_mask); // dont block additional signals during invocation
|
||||
// of handler
|
||||
if (sigaction(SIGINT, &sa, nullptr) == -1) {
|
||||
LOG(sls::logERROR) << "Could not set handler function for SIGINT";
|
||||
}
|
||||
|
||||
// if socket crash, ignores SISPIPE, prevents global signal handler
|
||||
// subsequent read/write to socket gives error - must handle locally
|
||||
struct sigaction asa;
|
||||
asa.sa_flags = 0; // no flags
|
||||
asa.sa_handler = SIG_IGN; // handler function
|
||||
sigemptyset(&asa.sa_mask); // dont block additional signals during
|
||||
// invocation of handler
|
||||
if (sigaction(SIGPIPE, &asa, nullptr) == -1) {
|
||||
LOG(sls::logERROR) << "Could not set handler function for SIGPIPE";
|
||||
}
|
||||
|
||||
try {
|
||||
sls::Receiver r(argc, argv);
|
||||
sls::Receiver r(o.port);
|
||||
LOG(sls::logINFO) << "[ Press \'Ctrl+c\' to exit ]";
|
||||
sem_wait(&semaphore);
|
||||
sem_destroy(&semaphore);
|
||||
} catch (...) {
|
||||
// pass
|
||||
sem_destroy(&semaphore);
|
||||
LOG(sls::logINFOBLUE) << "Exiting [ Tid: " << gettid() << " ]";
|
||||
throw;
|
||||
}
|
||||
LOG(sls::logINFOBLUE) << "Exiting [ Tid: " << gettid() << " ]";
|
||||
LOG(sls::logINFO) << "Exiting Receiver";
|
||||
return 0;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -19,8 +19,8 @@ namespace sls {
|
||||
// files
|
||||
|
||||
// versions
|
||||
#define HDF5_WRITER_VERSION (6.6) // 1 decimal places
|
||||
#define BINARY_WRITER_VERSION (7.2) // 1 decimal places
|
||||
#define HDF5_WRITER_VERSION (7.0) // 1 decimal places
|
||||
#define BINARY_WRITER_VERSION (8.0) // 1 decimal places
|
||||
|
||||
#define MAX_FRAMES_PER_FILE 20000
|
||||
#define SHORT_MAX_FRAMES_PER_FILE 100000
|
||||
@@ -57,9 +57,6 @@ struct image_structure {
|
||||
// parameters to calculate fifo depth
|
||||
#define SAMPLE_TIME_IN_NS (100000000) // 100ms
|
||||
|
||||
// to differentiate between gotthard and short gotthard
|
||||
#define GOTTHARD_PACKET_SIZE (1286)
|
||||
|
||||
#define DUMMY_PACKET_VALUE (0xFFFFFFFF)
|
||||
|
||||
#define LISTENER_PRIORITY (90)
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
target_sources(tests PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test-GeneralData.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test-CircularFifo.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test-ArrangeDataBasedOnBitList.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test-Apps.cpp
|
||||
)
|
||||
|
||||
target_include_directories(tests PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../src>")
|
||||
|
||||
message(STATUS "Resolved path: ${CMAKE_CURRENT_SOURCE_DIR}/../src")
|
||||
344
slsReceiverSoftware/tests/test-Apps.cpp
Normal file
344
slsReceiverSoftware/tests/test-Apps.cpp
Normal file
@@ -0,0 +1,344 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-other
|
||||
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||
#include "CommandLineOptions.h"
|
||||
#include "catch.hpp"
|
||||
#include "sls/logger.h"
|
||||
#include "sls/versionAPI.h"
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
namespace sls {
|
||||
|
||||
template <typename T, typename U> constexpr bool is_type() {
|
||||
return std::is_same_v<std::decay_t<U>, T>;
|
||||
}
|
||||
|
||||
TEST_CASE("CommandLineOption construction", "[detector]") {
|
||||
CommandLineOptions s(AppType::SingleReceiver);
|
||||
REQUIRE(s.getTypeString() == "slsReceiver");
|
||||
REQUIRE(s.getVersion() ==
|
||||
std::string("slsReceiver Version: ") + APIRECEIVER);
|
||||
REQUIRE_NOTHROW(s.getHelpMessage());
|
||||
|
||||
CommandLineOptions m(AppType::MultiReceiver);
|
||||
REQUIRE(m.getTypeString() == "slsMultiReceiver");
|
||||
REQUIRE(m.getVersion() ==
|
||||
std::string("slsMultiReceiver Version: ") + APIRECEIVER);
|
||||
REQUIRE_NOTHROW(m.getHelpMessage());
|
||||
|
||||
CommandLineOptions f(AppType::FrameSynchronizer);
|
||||
REQUIRE(f.getTypeString() == "slsFrameSynchronizer");
|
||||
REQUIRE(f.getVersion() ==
|
||||
std::string("slsFrameSynchronizer Version: ") + APIRECEIVER);
|
||||
REQUIRE_NOTHROW(f.getHelpMessage());
|
||||
}
|
||||
|
||||
TEST_CASE("Parse Help", "[detector]") {
|
||||
for (auto app : {AppType::SingleReceiver, AppType::MultiReceiver,
|
||||
AppType::FrameSynchronizer}) {
|
||||
CommandLineOptions s(app);
|
||||
ParsedOptions opts = s.parse({"", "-h"});
|
||||
if (app == AppType::SingleReceiver) {
|
||||
REQUIRE_NOTHROW(std::get<CommonOptions>(opts).helpRequested);
|
||||
} else if (app == AppType::MultiReceiver) {
|
||||
REQUIRE_NOTHROW(std::get<MultiReceiverOptions>(opts).helpRequested);
|
||||
} else if (app == AppType::FrameSynchronizer) {
|
||||
REQUIRE_NOTHROW(std::get<FrameSyncOptions>(opts).helpRequested);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Validate common options", "[detector]") {
|
||||
std::string uidStr = std::to_string(getuid());
|
||||
|
||||
for (auto app : {AppType::SingleReceiver, AppType::MultiReceiver,
|
||||
AppType::FrameSynchronizer}) {
|
||||
CommandLineOptions s(app);
|
||||
REQUIRE_NOTHROW(s.parse({}));
|
||||
REQUIRE_NOTHROW(s.parse({"", "-v"}));
|
||||
REQUIRE_NOTHROW(s.parse({"", "-h"}));
|
||||
REQUIRE_NOTHROW(s.parse({"", "-h", "gdfg"})); // ignored extra args
|
||||
REQUIRE_NOTHROW(s.parse({"", "-p", "1955"}));
|
||||
REQUIRE_NOTHROW(s.parse({"", "-u", uidStr}));
|
||||
REQUIRE_NOTHROW(s.parse({"", "-p", "1234", "-u", uidStr}));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Validate specific options", "[detector]") {
|
||||
std::string uidStr = std::to_string(getuid());
|
||||
|
||||
CommandLineOptions s(AppType::SingleReceiver);
|
||||
REQUIRE_NOTHROW(s.parse({"", "-t", "1955"}));
|
||||
REQUIRE_THROWS(s.parse({"", "-c"}));
|
||||
REQUIRE_THROWS(s.parse({"", "-n", "2"}));
|
||||
REQUIRE_THROWS(s.parse({"", "-m", "2"}));
|
||||
|
||||
for (auto app : {AppType::MultiReceiver, AppType::FrameSynchronizer}) {
|
||||
CommandLineOptions m(app);
|
||||
REQUIRE_NOTHROW(m.parse({"", "-c"}));
|
||||
REQUIRE_NOTHROW(m.parse({"", "-n", "2"}));
|
||||
REQUIRE_NOTHROW(
|
||||
m.parse({"", "-p", "1234", "-u", uidStr, "-c", "-n", "2"}));
|
||||
REQUIRE_THROWS(m.parse({"", "-t", "1955"}));
|
||||
REQUIRE_THROWS(m.parse({"", "-m", "2"}));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Parse version and help", "[detector]") {
|
||||
for (auto app : {AppType::SingleReceiver, AppType::MultiReceiver,
|
||||
AppType::FrameSynchronizer}) {
|
||||
CommandLineOptions s(app);
|
||||
auto opts = s.parse({});
|
||||
std::visit(
|
||||
[](const auto &o) {
|
||||
REQUIRE(o.versionRequested == false); // default
|
||||
REQUIRE(o.helpRequested == false); // default
|
||||
},
|
||||
opts);
|
||||
|
||||
opts = s.parse({"", "-v"});
|
||||
std::visit(
|
||||
[](const auto &o) {
|
||||
REQUIRE(o.versionRequested == true);
|
||||
REQUIRE(o.helpRequested == false);
|
||||
},
|
||||
opts);
|
||||
|
||||
opts = s.parse({"", "-h"});
|
||||
std::visit(
|
||||
[](const auto &o) {
|
||||
REQUIRE(o.versionRequested == false);
|
||||
REQUIRE(o.helpRequested == true);
|
||||
},
|
||||
opts);
|
||||
|
||||
opts = s.parse({"", "-h", "-v"});
|
||||
std::visit(
|
||||
[](const auto &o) {
|
||||
REQUIRE(o.versionRequested == true);
|
||||
REQUIRE(o.helpRequested == true);
|
||||
},
|
||||
opts);
|
||||
|
||||
opts = s.parse({"", "-v", "-h"});
|
||||
std::visit(
|
||||
[](const auto &o) {
|
||||
REQUIRE(o.helpRequested == true);
|
||||
REQUIRE(o.versionRequested == true);
|
||||
},
|
||||
opts);
|
||||
|
||||
opts = s.parse({"", "-v", "-h", "sdfsf"}); // ignores extra args
|
||||
std::visit(
|
||||
[](const auto &o) {
|
||||
REQUIRE(o.helpRequested == true);
|
||||
REQUIRE(o.versionRequested == true);
|
||||
},
|
||||
opts);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Parse port and uid", "[detector]") {
|
||||
uid_t uid = getuid();
|
||||
std::string uidStr = std::to_string(uid);
|
||||
uid_t invalidUid = uid + 1000;
|
||||
std::string invalidUidStr = std::to_string(invalidUid);
|
||||
|
||||
for (auto app : {AppType::SingleReceiver, AppType::MultiReceiver,
|
||||
AppType::FrameSynchronizer}) {
|
||||
CommandLineOptions s(app);
|
||||
REQUIRE_THROWS(
|
||||
s.parse({"", "-p", "1234", "-u", invalidUidStr})); // invalid uid
|
||||
REQUIRE_THROWS(s.parse({"", "-p", "500"})); // invalid port
|
||||
|
||||
auto opts = s.parse({"", "-p", "1234", "-u", uidStr});
|
||||
std::visit(
|
||||
[&](const auto &o) {
|
||||
REQUIRE(o.port == 1234);
|
||||
REQUIRE(o.userid == uid);
|
||||
},
|
||||
opts);
|
||||
|
||||
opts = s.parse({"", "-p", "5678"});
|
||||
std::visit(
|
||||
[](const auto &o) {
|
||||
REQUIRE(o.port == 5678);
|
||||
REQUIRE(o.userid == static_cast<uid_t>(-1)); // default
|
||||
},
|
||||
opts);
|
||||
|
||||
opts = s.parse({});
|
||||
std::visit(
|
||||
[](const auto &o) {
|
||||
REQUIRE(o.port == 1954); // default
|
||||
REQUIRE(o.userid == static_cast<uid_t>(-1)); // default
|
||||
},
|
||||
opts);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Parse num receivers and opt arg (Specific opt)", "[detector]") {
|
||||
for (auto app : {AppType::MultiReceiver, AppType::FrameSynchronizer}) {
|
||||
CommandLineOptions s(app);
|
||||
|
||||
REQUIRE_THROWS(s.parse({"", "-n", "0"})); // invalid number of receivers
|
||||
REQUIRE_THROWS(s.parse({"", "-n", "1001"})); // exceeds max receivers
|
||||
REQUIRE_NOTHROW(s.parse({"", "-n", "10"})); // valid
|
||||
|
||||
auto opts = s.parse({""});
|
||||
std::visit(
|
||||
[](const auto &o) {
|
||||
using T = decltype(o);
|
||||
if constexpr (is_type<MultiReceiverOptions, T>()) {
|
||||
REQUIRE(o.numReceivers == 1); // default
|
||||
REQUIRE(o.callbackEnabled == false);
|
||||
|
||||
} else if constexpr (is_type<FrameSyncOptions, T>()) {
|
||||
REQUIRE(o.numReceivers == 1); // default
|
||||
REQUIRE(o.printHeaders == false);
|
||||
}
|
||||
},
|
||||
opts);
|
||||
|
||||
opts = s.parse({"", "-n", "5"});
|
||||
std::visit(
|
||||
[](const auto &o) {
|
||||
using T = decltype(o);
|
||||
if constexpr (is_type<MultiReceiverOptions, T>()) {
|
||||
REQUIRE(o.numReceivers == 5);
|
||||
REQUIRE(o.callbackEnabled == false); // default
|
||||
|
||||
} else if constexpr (is_type<FrameSyncOptions, T>()) {
|
||||
REQUIRE(o.numReceivers == 5);
|
||||
REQUIRE(o.printHeaders == false); // default
|
||||
}
|
||||
},
|
||||
opts);
|
||||
|
||||
opts = s.parse({"", "-c", "-n", "3"});
|
||||
std::visit(
|
||||
[](const auto &o) {
|
||||
using T = decltype(o);
|
||||
if constexpr (is_type<MultiReceiverOptions, T>()) {
|
||||
REQUIRE(o.numReceivers == 3);
|
||||
REQUIRE(o.callbackEnabled == true);
|
||||
|
||||
} else if constexpr (is_type<FrameSyncOptions, T>()) {
|
||||
REQUIRE(o.numReceivers == 3);
|
||||
REQUIRE(o.printHeaders == true);
|
||||
}
|
||||
},
|
||||
opts);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Parse deprecated options", "[detector]") {
|
||||
for (auto app : {AppType::SingleReceiver, AppType::MultiReceiver,
|
||||
AppType::FrameSynchronizer}) {
|
||||
CommandLineOptions s(app);
|
||||
// argc 3 or 4, invalid
|
||||
REQUIRE_THROWS(s.parse({"", "1954"}));
|
||||
REQUIRE_THROWS(s.parse({
|
||||
"",
|
||||
"1954",
|
||||
}));
|
||||
// argc 3 or 4
|
||||
if (app == AppType::SingleReceiver) {
|
||||
REQUIRE_THROWS(
|
||||
s.parse({"", "1954", "1"})); // deprecated unsupported
|
||||
} else {
|
||||
REQUIRE_THROWS(s.parse({"", "1954", "1", "1", "-p",
|
||||
"1954"})); // mix deprecated and current
|
||||
REQUIRE_THROWS(
|
||||
s.parse({"", "1954", "1", "-c"})); // mix deprecated and current
|
||||
REQUIRE_THROWS(s.parse(
|
||||
{"", "1954", "1", "-n", "34"})); // mix deprecated and current
|
||||
REQUIRE_THROWS(s.parse({"", "110", "1954"})); // mix order
|
||||
REQUIRE_THROWS(s.parse({"", "1023", "10"})); // privileged port
|
||||
REQUIRE_THROWS(s.parse({"", "2000", "0"})); // invalid num receivers
|
||||
REQUIRE_THROWS(
|
||||
s.parse({"", "2000", "1001"})); // invalid num receivers
|
||||
REQUIRE_THROWS(s.parse({"", "1954", "1", "2"})); // invalid 3rd opt
|
||||
|
||||
REQUIRE_NOTHROW(s.parse({""}));
|
||||
REQUIRE_NOTHROW(s.parse({"", "1954", "1"}));
|
||||
REQUIRE_NOTHROW(s.parse({"", "1954", "1", "0"}));
|
||||
REQUIRE_NOTHROW(s.parse({"", "1954", "1", "1"}));
|
||||
|
||||
// default
|
||||
auto opts = s.parse({""});
|
||||
std::visit(
|
||||
[](const auto &o) {
|
||||
using T = decltype(o);
|
||||
if constexpr (is_type<MultiReceiverOptions, T>()) {
|
||||
REQUIRE(o.port == 1954);
|
||||
REQUIRE(o.numReceivers == 1);
|
||||
REQUIRE(o.callbackEnabled == false);
|
||||
|
||||
} else if constexpr (is_type<FrameSyncOptions, T>()) {
|
||||
REQUIRE(o.port == 1954);
|
||||
REQUIRE(o.numReceivers == 1);
|
||||
REQUIRE(o.printHeaders == false); // default
|
||||
}
|
||||
},
|
||||
opts);
|
||||
|
||||
opts = s.parse({"", "1958", "10"});
|
||||
std::visit(
|
||||
[](const auto &o) {
|
||||
using T = decltype(o);
|
||||
if constexpr (is_type<MultiReceiverOptions, T>()) {
|
||||
REQUIRE(o.port == 1958);
|
||||
REQUIRE(o.numReceivers == 10);
|
||||
REQUIRE(o.callbackEnabled == false); // default
|
||||
|
||||
} else if constexpr (is_type<FrameSyncOptions, T>()) {
|
||||
REQUIRE(o.port == 1958);
|
||||
REQUIRE(o.numReceivers == 10);
|
||||
REQUIRE(o.printHeaders == false); // default
|
||||
}
|
||||
},
|
||||
opts);
|
||||
|
||||
opts = s.parse({"", "1958", "10", "1"});
|
||||
std::visit(
|
||||
[](const auto &o) {
|
||||
using T = decltype(o);
|
||||
if constexpr (is_type<MultiReceiverOptions, T>()) {
|
||||
REQUIRE(o.port == 1958);
|
||||
REQUIRE(o.numReceivers == 10);
|
||||
REQUIRE(o.callbackEnabled == true); // default
|
||||
|
||||
} else if constexpr (is_type<FrameSyncOptions, T>()) {
|
||||
REQUIRE(o.port == 1958);
|
||||
REQUIRE(o.numReceivers == 10);
|
||||
REQUIRE(o.printHeaders == true); // default
|
||||
}
|
||||
},
|
||||
opts);
|
||||
}
|
||||
}
|
||||
|
||||
// test function directly
|
||||
// nargs can be 1, 3 or 4
|
||||
REQUIRE_THROWS(CommandLineOptions::ParseDeprecated({"", ""}));
|
||||
REQUIRE_THROWS(CommandLineOptions::ParseDeprecated({"", "", "", "", ""}));
|
||||
|
||||
// default
|
||||
auto [p, n, o] = CommandLineOptions::ParseDeprecated({""});
|
||||
REQUIRE(p == 1954);
|
||||
REQUIRE(n == 1);
|
||||
REQUIRE(o == false);
|
||||
|
||||
std::tie(p, n, o) = CommandLineOptions::ParseDeprecated({"", "1955", "6"});
|
||||
REQUIRE(p == 1955);
|
||||
REQUIRE(n == 6);
|
||||
REQUIRE(o == false);
|
||||
|
||||
std::tie(p, n, o) =
|
||||
CommandLineOptions::ParseDeprecated({"", "1955", "6", "1"});
|
||||
REQUIRE(p == 1955);
|
||||
REQUIRE(n == 6);
|
||||
REQUIRE(o == true);
|
||||
}
|
||||
} // namespace sls
|
||||
411
slsReceiverSoftware/tests/test-ArrangeDataBasedOnBitList.cpp
Normal file
411
slsReceiverSoftware/tests/test-ArrangeDataBasedOnBitList.cpp
Normal file
@@ -0,0 +1,411 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-other
|
||||
// Copyright (C) 2025 Contributors to the SLS Detector Package
|
||||
/************************************************
|
||||
* @file test-ArrangeDataBasedOnBitList.cpp
|
||||
* @short test case for DataProcessor rearrange functions,
|
||||
***********************************************/
|
||||
|
||||
#include "DataProcessor.h"
|
||||
#include "GeneralData.h"
|
||||
#include "catch.hpp"
|
||||
#include <vector>
|
||||
|
||||
namespace sls {
|
||||
|
||||
// dummy GeneralData class for testing
|
||||
class GeneralDataTest : public GeneralData {
|
||||
|
||||
public:
|
||||
GeneralDataTest() { detType = slsDetectorDefs::CHIPTESTBOARD; }
|
||||
|
||||
int GetNumberOfAnalogDatabytes() { return nAnalogBytes; };
|
||||
|
||||
int GetNumberOfDigitalDatabytes() { return nDigitalBytes; };
|
||||
|
||||
int GetNumberOfTransceiverDatabytes() { return nTransceiverBytes; };
|
||||
|
||||
void SetNumberOfAnalogDatabytes(int value) { nAnalogBytes = value; }
|
||||
|
||||
void SetNumberOfDigitalDatabytes(int value) { nDigitalBytes = value; }
|
||||
|
||||
void SetNumberOfTransceiverDatabytes(int value) {
|
||||
nTransceiverBytes = value;
|
||||
}
|
||||
|
||||
void SetCtbDbitOffset(const int value) { ctbDbitOffset = value; }
|
||||
|
||||
void SetCtbDbitList(const std::vector<int> &value) { ctbDbitList = value; }
|
||||
|
||||
void SetCtbDbitReorder(const bool value) { ctbDbitReorder = value; }
|
||||
|
||||
private:
|
||||
int nAnalogBytes{};
|
||||
int nDigitalBytes{};
|
||||
int nTransceiverBytes{};
|
||||
};
|
||||
|
||||
// dummy DataProcessor class for testing
|
||||
class DataProcessorTest : public DataProcessor {
|
||||
public:
|
||||
DataProcessorTest() : DataProcessor(0){};
|
||||
~DataProcessorTest(){};
|
||||
void ArrangeDbitData(size_t &size, char *data) {
|
||||
DataProcessor::ArrangeDbitData(size, data);
|
||||
}
|
||||
|
||||
void RemoveTrailingBits(size_t &size, char *data) {
|
||||
DataProcessor::RemoveTrailingBits(size, data);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* test fixture for Testing,
|
||||
* num_analog_bytes = 1 byte has a value of 125
|
||||
* num_transceiver_bytes = 2 both bytes have a value of 125
|
||||
* num_digital_bytes is variable and is defined by number of samples
|
||||
* default num sample is 5
|
||||
* all bytes in digital data take a value of 255
|
||||
*/
|
||||
class DataProcessorTestFixture {
|
||||
public:
|
||||
DataProcessorTestFixture() {
|
||||
// setup Test Fixture
|
||||
dataprocessor = new DataProcessorTest;
|
||||
generaldata = new GeneralDataTest;
|
||||
|
||||
generaldata->SetNumberOfAnalogDatabytes(num_analog_bytes);
|
||||
generaldata->SetNumberOfTransceiverDatabytes(num_transceiver_bytes);
|
||||
generaldata->SetNumberOfDigitalDatabytes(num_digital_bytes +
|
||||
num_random_offset_bytes);
|
||||
|
||||
dataprocessor->SetGeneralData(generaldata);
|
||||
}
|
||||
|
||||
~DataProcessorTestFixture() {
|
||||
delete[] data;
|
||||
delete dataprocessor;
|
||||
delete generaldata;
|
||||
}
|
||||
|
||||
size_t get_size() const {
|
||||
return num_analog_bytes + num_digital_bytes + num_transceiver_bytes +
|
||||
num_random_offset_bytes;
|
||||
}
|
||||
|
||||
void set_num_samples(const size_t value) {
|
||||
num_samples = value;
|
||||
num_digital_bytes = num_samples * 8; // 64 (8 bytes) per sample
|
||||
|
||||
generaldata->SetNumberOfDigitalDatabytes(num_digital_bytes +
|
||||
num_random_offset_bytes);
|
||||
}
|
||||
|
||||
void set_random_offset_bytes(const size_t value) {
|
||||
num_random_offset_bytes = value;
|
||||
generaldata->SetNumberOfDigitalDatabytes(num_digital_bytes +
|
||||
num_random_offset_bytes);
|
||||
}
|
||||
|
||||
void set_data() {
|
||||
delete[] data;
|
||||
uint64_t max_bytes_per_bit =
|
||||
num_samples % 8 == 0 ? num_samples / 8 : num_samples / 8 + 1;
|
||||
uint64_t reserved_size =
|
||||
get_size() - num_digital_bytes + max_bytes_per_bit * 64;
|
||||
data = new char[reserved_size];
|
||||
|
||||
// set testing data
|
||||
memset(data, dummy_value, num_analog_bytes); // set to dummy value
|
||||
memset(data + num_analog_bytes, 0,
|
||||
num_random_offset_bytes); // set to zero
|
||||
memset(data + num_analog_bytes + num_random_offset_bytes, 0xFF,
|
||||
num_digital_bytes); // all digital bits are one
|
||||
memset(data + num_digital_bytes + num_analog_bytes +
|
||||
num_random_offset_bytes,
|
||||
dummy_value,
|
||||
num_transceiver_bytes); // set to dummy value
|
||||
}
|
||||
|
||||
DataProcessorTest *dataprocessor;
|
||||
GeneralDataTest *generaldata;
|
||||
const size_t num_analog_bytes = 1;
|
||||
const size_t num_transceiver_bytes = 2;
|
||||
const char dummy_value = static_cast<char>(125);
|
||||
size_t num_digital_bytes = 40; // num_samples * 8 = 5 * 8 = 40
|
||||
size_t num_random_offset_bytes = 0;
|
||||
size_t num_samples = 5;
|
||||
char *data = nullptr;
|
||||
};
|
||||
|
||||
TEST_CASE_METHOD(DataProcessorTestFixture, "Remove Trailing Bits",
|
||||
"[.dataprocessor][.bitoffset]") {
|
||||
|
||||
const size_t num_random_offset_bytes = 3;
|
||||
set_random_offset_bytes(num_random_offset_bytes);
|
||||
set_data();
|
||||
|
||||
generaldata->SetCtbDbitOffset(num_random_offset_bytes);
|
||||
|
||||
size_t expected_size = get_size() - num_random_offset_bytes;
|
||||
|
||||
char *expected_data = new char[expected_size];
|
||||
memset(expected_data, dummy_value, num_analog_bytes); // set to 125
|
||||
memset(expected_data + num_analog_bytes, 0xFF,
|
||||
num_digital_bytes); // set to 1
|
||||
memset(expected_data + num_digital_bytes + num_analog_bytes, dummy_value,
|
||||
num_transceiver_bytes); // set to 125
|
||||
|
||||
size_t size = get_size();
|
||||
dataprocessor->RemoveTrailingBits(size, data);
|
||||
|
||||
CHECK(size == expected_size);
|
||||
|
||||
CHECK(memcmp(data, expected_data, expected_size) == 0);
|
||||
|
||||
delete[] expected_data;
|
||||
}
|
||||
|
||||
// parametric test tested with num_samples = 5, num_samples = 10, num_samples =
|
||||
// 8
|
||||
TEST_CASE_METHOD(DataProcessorTestFixture, "Reorder all",
|
||||
"[.dataprocessor][.reorder]") {
|
||||
// parameters: num_samples, expected_num_digital_bytes,
|
||||
// expected_digital_part
|
||||
auto parameters = GENERATE(
|
||||
std::make_tuple(5, 64, std::vector<uint8_t>{0b00011111}),
|
||||
std::make_tuple(10, 2 * 64, std::vector<uint8_t>{0xFF, 0b00000011}),
|
||||
std::make_tuple(8, 64, std::vector<uint8_t>{0xFF}));
|
||||
|
||||
size_t num_samples, expected_num_digital_bytes;
|
||||
std::vector<uint8_t> expected_digital_part;
|
||||
std::tie(num_samples, expected_num_digital_bytes, expected_digital_part) =
|
||||
parameters;
|
||||
|
||||
// set number of samples for test fixture -> create data
|
||||
set_num_samples(num_samples);
|
||||
set_data();
|
||||
|
||||
std::vector<int> bitlist(64);
|
||||
std::iota(bitlist.begin(), bitlist.end(), 0);
|
||||
generaldata->SetCtbDbitList(bitlist);
|
||||
generaldata->SetCtbDbitReorder(true); // set reorder to true
|
||||
|
||||
const size_t expected_size =
|
||||
num_analog_bytes + num_transceiver_bytes + expected_num_digital_bytes;
|
||||
|
||||
// create expected data
|
||||
char *expected_data = new char[expected_size];
|
||||
|
||||
memset(expected_data, dummy_value, num_analog_bytes); // set to 125
|
||||
for (size_t bit = 0; bit < 64; ++bit) {
|
||||
memcpy(expected_data + num_analog_bytes +
|
||||
expected_digital_part.size() * bit,
|
||||
expected_digital_part.data(), expected_digital_part.size());
|
||||
}
|
||||
memset(expected_data + expected_num_digital_bytes + num_analog_bytes,
|
||||
dummy_value,
|
||||
num_transceiver_bytes); // set to 125
|
||||
|
||||
size_t size = get_size();
|
||||
dataprocessor->ArrangeDbitData(size, data); // call reorder
|
||||
|
||||
CHECK(size == expected_size);
|
||||
CHECK(memcmp(data, expected_data, expected_size) == 0);
|
||||
|
||||
delete[] expected_data;
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(DataProcessorTestFixture,
|
||||
"Reorder all and remove trailing bits",
|
||||
"[.dataprocessor][.reorder]") {
|
||||
|
||||
// set number of samples for test fixture -> create data
|
||||
const size_t num_random_offset_bytes = 3;
|
||||
set_random_offset_bytes(num_random_offset_bytes);
|
||||
set_data();
|
||||
|
||||
std::vector<int> bitlist(64);
|
||||
std::iota(bitlist.begin(), bitlist.end(), 0);
|
||||
generaldata->SetCtbDbitList(bitlist);
|
||||
generaldata->SetCtbDbitOffset(num_random_offset_bytes);
|
||||
generaldata->SetCtbDbitReorder(true); // set reorder to true
|
||||
|
||||
const size_t expected_num_digital_bytes = 64;
|
||||
std::vector<uint8_t> expected_digital_part{0b00011111};
|
||||
|
||||
const size_t expected_size =
|
||||
num_analog_bytes + num_transceiver_bytes + expected_num_digital_bytes;
|
||||
|
||||
// create expected data
|
||||
char *expected_data = new char[expected_size];
|
||||
|
||||
memset(expected_data, dummy_value, num_analog_bytes); // set to 125
|
||||
for (size_t bit = 0; bit < 64; ++bit) {
|
||||
memcpy(expected_data + num_analog_bytes +
|
||||
expected_digital_part.size() * bit,
|
||||
expected_digital_part.data(), expected_digital_part.size());
|
||||
}
|
||||
memset(expected_data + expected_num_digital_bytes + num_analog_bytes,
|
||||
dummy_value,
|
||||
num_transceiver_bytes); // set to 125
|
||||
|
||||
size_t size = get_size();
|
||||
dataprocessor->ArrangeDbitData(size, data); // call reorder
|
||||
|
||||
CHECK(size == expected_size);
|
||||
CHECK(memcmp(data, expected_data, expected_size) == 0);
|
||||
|
||||
delete[] expected_data;
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(DataProcessorTestFixture, "Arrange bitlist with reorder false",
|
||||
"[.dataprocessor][.retrievebitlist]") {
|
||||
// parameters: num_samples, bitlist, expected_num_digital_bytes,
|
||||
// expected_digital_part
|
||||
auto parameters = GENERATE(
|
||||
std::make_tuple(5, std::vector<int>{1, 4, 5}, 5,
|
||||
std::vector<uint8_t>{0b00000111}),
|
||||
std::make_tuple(5, std::vector<int>{1, 5, 3, 7, 8, 50, 42, 60, 39}, 10,
|
||||
std::vector<uint8_t>{0xFF, 0b00000001}),
|
||||
std::make_tuple(5, std::vector<int>{1, 5, 3, 7, 8, 50, 42, 60}, 5,
|
||||
std::vector<uint8_t>{0xFF}));
|
||||
|
||||
size_t num_samples, expected_num_digital_bytes;
|
||||
std::vector<uint8_t> expected_digital_part;
|
||||
std::vector<int> bitlist;
|
||||
std::tie(num_samples, bitlist, expected_num_digital_bytes,
|
||||
expected_digital_part) = parameters;
|
||||
|
||||
generaldata->SetCtbDbitList(bitlist);
|
||||
|
||||
generaldata->SetCtbDbitReorder(false);
|
||||
|
||||
set_num_samples(num_samples);
|
||||
set_data();
|
||||
|
||||
size_t expected_size =
|
||||
num_analog_bytes + num_transceiver_bytes + expected_num_digital_bytes;
|
||||
|
||||
// create expected data
|
||||
char *expected_data = new char[expected_size];
|
||||
|
||||
memset(expected_data, dummy_value, num_analog_bytes);
|
||||
|
||||
for (size_t sample = 0; sample < num_samples; ++sample) {
|
||||
memcpy(expected_data + num_analog_bytes +
|
||||
expected_digital_part.size() * sample,
|
||||
expected_digital_part.data(), expected_digital_part.size());
|
||||
}
|
||||
|
||||
memset(expected_data + expected_num_digital_bytes + num_analog_bytes,
|
||||
dummy_value, num_transceiver_bytes);
|
||||
|
||||
size_t size = get_size();
|
||||
dataprocessor->ArrangeDbitData(size, data);
|
||||
|
||||
CHECK(size == expected_size);
|
||||
|
||||
CHECK(memcmp(data, expected_data, expected_size) == 0);
|
||||
|
||||
delete[] expected_data;
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(DataProcessorTestFixture, "Arrange bitlist with reorder true",
|
||||
"[.dataprocessor][.retrievebitlist]") {
|
||||
// parameters: num_samples, bitlist, expected_num_digital_bytes,
|
||||
// expected_digital_part
|
||||
auto parameters = GENERATE(
|
||||
std::make_tuple(5, std::vector<int>{1, 4, 5}, 3,
|
||||
std::vector<uint8_t>{0b00011111}),
|
||||
std::make_tuple(10, std::vector<int>{1, 4, 5}, 6,
|
||||
std::vector<uint8_t>{0xFF, 0b00000011}),
|
||||
std::make_tuple(8, std::vector<int>{1, 5, 3, 7, 8, 50, 42, 60, 39}, 9,
|
||||
std::vector<uint8_t>{0xFF}));
|
||||
|
||||
size_t num_samples, expected_num_digital_bytes;
|
||||
std::vector<uint8_t> expected_digital_part;
|
||||
std::vector<int> bitlist;
|
||||
std::tie(num_samples, bitlist, expected_num_digital_bytes,
|
||||
expected_digital_part) = parameters;
|
||||
|
||||
generaldata->SetCtbDbitList(bitlist);
|
||||
|
||||
generaldata->SetCtbDbitReorder(true);
|
||||
|
||||
set_num_samples(num_samples);
|
||||
set_data();
|
||||
|
||||
size_t expected_size =
|
||||
num_analog_bytes + num_transceiver_bytes + expected_num_digital_bytes;
|
||||
|
||||
// create expected data
|
||||
char *expected_data = new char[expected_size];
|
||||
|
||||
memset(expected_data, dummy_value, num_analog_bytes);
|
||||
|
||||
for (size_t sample = 0; sample < bitlist.size(); ++sample) {
|
||||
memcpy(expected_data + num_analog_bytes +
|
||||
expected_digital_part.size() * sample,
|
||||
expected_digital_part.data(), expected_digital_part.size());
|
||||
}
|
||||
|
||||
memset(expected_data + expected_num_digital_bytes + num_analog_bytes,
|
||||
dummy_value, num_transceiver_bytes);
|
||||
|
||||
size_t size = get_size();
|
||||
dataprocessor->ArrangeDbitData(size, data);
|
||||
|
||||
CHECK(size == expected_size);
|
||||
|
||||
CHECK(memcmp(data, expected_data, expected_size) == 0);
|
||||
|
||||
delete[] expected_data;
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(DataProcessorTestFixture,
|
||||
"Arrange bitlist and remove trailing bits",
|
||||
"[.dataprocessor][.retrievebitlist]") {
|
||||
|
||||
size_t num_random_offset_bytes = 3;
|
||||
std::vector<int> bitlist{1, 4, 5};
|
||||
|
||||
set_random_offset_bytes(num_random_offset_bytes);
|
||||
set_data();
|
||||
|
||||
generaldata->SetCtbDbitList(bitlist);
|
||||
|
||||
generaldata->SetCtbDbitReorder(false);
|
||||
|
||||
generaldata->SetCtbDbitOffset(num_random_offset_bytes);
|
||||
|
||||
std::vector<uint8_t> expected_digital_part{0b00000111};
|
||||
const size_t expected_num_digital_bytes = 5;
|
||||
|
||||
size_t expected_size =
|
||||
num_analog_bytes + num_transceiver_bytes + expected_num_digital_bytes;
|
||||
|
||||
// create expected data
|
||||
char *expected_data = new char[expected_size];
|
||||
|
||||
memset(expected_data, dummy_value, num_analog_bytes);
|
||||
|
||||
for (size_t sample = 0; sample < num_samples; ++sample) {
|
||||
memcpy(expected_data + num_analog_bytes +
|
||||
expected_digital_part.size() * sample,
|
||||
expected_digital_part.data(), expected_digital_part.size());
|
||||
}
|
||||
|
||||
memset(expected_data + expected_num_digital_bytes + num_analog_bytes,
|
||||
dummy_value, num_transceiver_bytes);
|
||||
|
||||
size_t size = get_size();
|
||||
dataprocessor->ArrangeDbitData(size, data);
|
||||
|
||||
CHECK(size == expected_size);
|
||||
|
||||
CHECK(memcmp(data, expected_data, expected_size) == 0);
|
||||
|
||||
delete[] expected_data;
|
||||
}
|
||||
|
||||
} // namespace sls
|
||||
@@ -53,30 +53,3 @@
|
||||
// CHECK(bunchId == 0xf012fb20010f195b);
|
||||
// CHECK(subFrameNumber == -1);
|
||||
// }
|
||||
|
||||
// TEST_CASE("Parse header gotthard data", "[receiver]") {
|
||||
// GotthardData data;
|
||||
// struct packet {
|
||||
// uint32_t frameNumber;
|
||||
// unsigned char data[GOTTHARD_PACKET_SIZE];
|
||||
// } __attribute__((packed));
|
||||
// packet test_packet;
|
||||
// test_packet.frameNumber = 25698u;
|
||||
|
||||
// int index = 0;
|
||||
// char *packetData = reinterpret_cast<char *>(&test_packet);
|
||||
// uint32_t dynamicRange{0};
|
||||
// bool oddStartingPacket{0};
|
||||
// uint64_t frameNumber{0};
|
||||
// uint32_t packetNumber{0};
|
||||
// uint32_t subFrameNumber{0};
|
||||
// uint64_t bunchId{0};
|
||||
|
||||
// data.GetHeaderInfo(index, packetData, dynamicRange, oddStartingPacket,
|
||||
// frameNumber, packetNumber, subFrameNumber, bunchId);
|
||||
|
||||
// CHECK(frameNumber == test_packet.frameNumber/2);
|
||||
// CHECK(subFrameNumber == -1);
|
||||
// CHECK(bunchId == -1);
|
||||
|
||||
// }
|
||||
Reference in New Issue
Block a user