From 995f0924e567b7740ca095cbf3661e01449ab15e Mon Sep 17 00:00:00 2001 From: Dhanya Thattil <33750417+thattil@users.noreply.github.com> Date: Mon, 21 Oct 2019 10:29:06 +0200 Subject: [PATCH] Commandline (#66) * WIP * WIP * removed status to string from defs * WIP * WIP * WIP removed unused functions in multi * WIP * print hex in a terrible way * WIP, loadconfig error * WIP, type to string * WIP * fix to conversion * WIP, hostname doesnt work * WIP * WIP * WIP * WIP, threshold * WIP, threshold * WIP * WIP, triggers * WIP, cycles to triggers * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * rx_udsocksize fx, WIP * WIP * WIP * WIP * file index (64 bit), WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * merge * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * New python mod --- ctbGui/ctbAcquisition.cpp | 2 +- ctbGui/ctbDacs.cpp | 4 +- ctbGui/ctbPattern.cpp | 22 +- ctbGui/ctbPattern.h | 4 +- ctbGui/ctbPowers.cpp | 2 +- examples/gotthard_setup.det | 2 +- .../test-integrationDectector.cpp | 12 +- integrationTests/test-integrationMulti.cpp | 2 +- manual/manual-client/Eiger_short.tex | 22 +- manual/manual-client/commands.txt | 4 +- .../manual-client/slsDetectorClientHowTo.tex | 22 +- manual/manual-gui/slsDetectorGuiHowTo.tex | 4 +- .../manual-main/images/gated_acquisition.eps | 2 +- .../manual-main/images/gated_acquisition.fig | 2 +- .../images/gated_acquisition.fig.bak | 2 +- .../manual-main/images/normal_acquisition.eps | 2 +- .../manual-main/images/normal_acquisition.fig | 2 +- .../images/normal_acquisition.fig.bak | 2 +- .../images/trigger_acquisition.eps | 2 +- .../images/trigger_acquisition.fig | 2 +- .../images/trigger_acquisition.fig.bak | 2 +- manual/manual-main/manual.tex | 4 +- manual/manual-main/slsDetector-softFAQ.tex | 24 +- manual/manual-main/slsDetectorClientHowTo.tex | 22 +- manual/manual-main/slsDetectorGuiHowTo.tex | 4 +- python/CMakeLists.txt | 10 +- python/scripts/basic.py | 11 +- python/sls_detector/__init__.py | 13 +- python/sls_detector/detector.py | 1486 --------- python/sls_detector/experimental.py | 90 +- python/sls_detector/jungfrau.py | 259 -- python/sls_detector/jungfrau_ctb.py | 178 -- python/src/DetectorPythonInterface.h | 992 ------ python/src/enums.cpp | 18 +- python/src/experimental.cpp | 12 +- python/src/main.cpp | 306 -- slsDetectorGui/forms/form_tab_advanced.ui | 4 +- slsDetectorGui/forms/form_tab_measurement.ui | 9 +- slsDetectorGui/src/qDacWidget.cpp | 2 +- slsDetectorGui/src/qDetectorMain.cpp | 7 +- slsDetectorGui/src/qDrawPlot.cpp | 10 +- slsDetectorGui/src/qTabAdvanced.cpp | 4 +- slsDetectorGui/src/qTabDebugging.cpp | 6 +- slsDetectorGui/src/qTabMeasurement.cpp | 2 +- slsDetectorGui/src/qTabSettings.cpp | 4 +- .../ctbDetectorServer/RegisterDefs.h | 4 +- .../bin/ctbDetectorServer_developer | Bin 175020 -> 175292 bytes .../slsDetectorFunctionList.c | 14 +- .../eigerDetectorServer/Makefile | 2 +- .../bin/eigerDetectorServer_developer | Bin 321160 -> 322201 bytes .../slsDetectorFunctionList.c | 30 +- .../gotthard2DetectorServer/RegisterDefs.h | 2 +- .../bin/gotthard2DetectorServer_developer | Bin 123848 -> 124840 bytes .../slsDetectorFunctionList.c | 14 +- .../gotthardDetectorServer/RegisterDefs.h | 4 +- .../bin/gotthardDetectorServer_developer | Bin 128524 -> 128696 bytes .../slsDetectorFunctionList.c | 26 +- .../jungfrauDetectorServer/RegisterDefs.h | 4 +- .../bin/jungfrauDetectorServer_developer | Bin 139860 -> 140032 bytes .../slsDetectorFunctionList.c | 14 +- .../moenchDetectorServer/RegisterDefs.h | 4 +- .../slsDetectorFunctionList.c | 14 +- .../mythen3DetectorServer/RegisterDefs.h | 2 +- .../bin/mythen3DetectorServer_developer | Bin 114332 -> 114332 bytes .../slsDetectorFunctionList.c | 14 +- .../include/communication_funcs.h | 6 + .../src/communication_funcs.c | 36 +- .../src/slsDetectorServer_funcs.c | 287 +- slsDetectorSoftware/CMakeLists.txt | 4 +- slsDetectorSoftware/include/CmdProxy.h | 1272 +++++++- slsDetectorSoftware/include/Detector.h | 123 +- .../include/multiSlsDetector.h | 167 +- slsDetectorSoftware/include/slsDetector.h | 35 +- .../include/slsDetectorCommand.h | 36 - .../include/slsDetectorUsers.h | 8 +- slsDetectorSoftware/src/CmdProxy.cpp | 885 +++++- slsDetectorSoftware/src/Detector.cpp | 127 +- slsDetectorSoftware/src/multiSlsDetector.cpp | 497 +-- .../src/multiSlsDetectorClient.cpp | 5 +- slsDetectorSoftware/src/slsDetector.cpp | 257 +- .../src/slsDetectorCommand.cpp | 2742 +---------------- slsDetectorSoftware/src/slsDetectorUsers.cpp | 4 +- .../tests/test-multiSlsDetectorClient.cpp | 2363 +++++++++++++- slsReceiverSoftware/include/DataStreamer.h | 5 +- slsReceiverSoftware/include/GeneralData.h | 3 +- .../include/slsReceiverImplementation.h | 7 +- slsReceiverSoftware/src/DataStreamer.cpp | 6 +- slsReceiverSoftware/src/Listener.cpp | 10 +- .../src/slsReceiverImplementation.cpp | 27 +- .../src/slsReceiverTCPIPInterface.cpp | 54 +- slsSupportLib/include/ToString.h | 302 +- slsSupportLib/include/genericSocket.h | 9 +- slsSupportLib/include/sls_detector_defs.h | 396 +-- slsSupportLib/include/versionAPI.h | 10 +- tests/test.cpp | 6 +- 95 files changed, 5320 insertions(+), 8114 deletions(-) delete mode 100755 python/sls_detector/detector.py delete mode 100755 python/sls_detector/jungfrau.py delete mode 100755 python/sls_detector/jungfrau_ctb.py delete mode 100755 python/src/DetectorPythonInterface.h diff --git a/ctbGui/ctbAcquisition.cpp b/ctbGui/ctbAcquisition.cpp index 95f6c31ee..c0e95d214 100755 --- a/ctbGui/ctbAcquisition.cpp +++ b/ctbGui/ctbAcquisition.cpp @@ -1670,7 +1670,7 @@ void ctbAcquisition::toggleAcquisition() { } else { StopFlag=1; try{ - myDet->stopAcquisition(); + myDet->stopDetector(); } CATCH_DISPLAY ("Could not stop acquisition", "ctbAcquisition::toggleAcquisition") stop=1; bStatus->SetText("Start"); diff --git a/ctbGui/ctbDacs.cpp b/ctbGui/ctbDacs.cpp index 9eed1bbf4..5a8c5a600 100755 --- a/ctbGui/ctbDacs.cpp +++ b/ctbGui/ctbDacs.cpp @@ -116,7 +116,7 @@ void ctbDac::setValue() { cout << "setting dac! "<< id << " value " << dacsEntry->GetIntNumber() << " units " << dacsUnit->IsOn() << endl; try { - myDet->setDAC(dacsEntry->GetIntNumber(), static_cast(id), dacsUnit->IsOn()); + myDet->setDAC(static_cast(id), dacsEntry->GetIntNumber(), dacsUnit->IsOn()); } CATCH_DISPLAY ("Could not set dac " + to_string(id) + ".", "ctbDac::setValue") getValue(); @@ -128,7 +128,7 @@ void ctbDac::setOn(Bool_t b) { setValue(); } else { try { - myDet->setDAC(-100, static_cast(id), false); + myDet->setDAC(static_cast(id), -100, false); } CATCH_DISPLAY ("Could not power off dac " + to_string(id) + ".", "ctbDac::setOn") } getValue(); diff --git a/ctbGui/ctbPattern.cpp b/ctbGui/ctbPattern.cpp index 8f56ca16c..0819f9eaa 100755 --- a/ctbGui/ctbPattern.cpp +++ b/ctbGui/ctbPattern.cpp @@ -455,7 +455,7 @@ ctbPattern::ctbPattern(TGVerticalFrame *page, sls::Detector *det) hframe->MapWindow(); - sprintf(tit, "Number of cycles: "); + sprintf(tit, "Number of triggers: "); label= new TGLabel(hframe, tit); hframe->AddFrame(label,new TGLayoutHints(kLHintsTop | kLHintsLeft| kLHintsExpandX, 1, 1, 1, 1)); @@ -465,14 +465,14 @@ ctbPattern::ctbPattern(TGVerticalFrame *page, sls::Detector *det) - eCycles = new TGNumberEntry(hframe, 0, 9,999, TGNumberFormat::kNESInteger, + eTriggers = new TGNumberEntry(hframe, 0, 9,999, TGNumberFormat::kNESInteger, TGNumberFormat::kNEANonNegative, TGNumberFormat::kNELNoLimits); - hframe->AddFrame( eCycles,new TGLayoutHints(kLHintsTop | kLHintsExpandX, 1, 1, 1, 1)); - eCycles->MapWindow(); - eCycles->Resize(150,30); - e= eCycles->TGNumberEntry::GetNumberEntry(); - e->Connect("ReturnPressed()","ctbPattern",this,"setCycles()"); + hframe->AddFrame( eTriggers,new TGLayoutHints(kLHintsTop | kLHintsExpandX, 1, 1, 1, 1)); + eTriggers->MapWindow(); + eTriggers->Resize(150,30); + e= eTriggers->TGNumberEntry::GetNumberEntry(); + e->Connect("ReturnPressed()","ctbPattern",this,"setTriggers()"); // sprintf(tit, "Number of measurements: "); @@ -821,7 +821,7 @@ void ctbPattern::update() { try{ auto retval = myDet->getNumberOfTriggers().tsquash("Different values"); - eCycles->SetNumber(retval); + eTriggers->SetNumber(retval); } CATCH_DISPLAY ("Could not get number of triggers.", "ctbPattern::update") try{ @@ -934,10 +934,10 @@ void ctbPattern::setFrames() { } CATCH_DISPLAY ("Could not set number of frames", "ctbPattern::setFrames") } -void ctbPattern::setCycles() { +void ctbPattern::setTriggers() { try{ - myDet->setNumberOfTriggers(eCycles->GetNumber()); - } CATCH_DISPLAY ("Could not set number of triggers", "ctbPattern::setCycles") + myDet->setNumberOfTriggers(eTriggers->GetNumber()); + } CATCH_DISPLAY ("Could not set number of triggers", "ctbPattern::setTriggers") } void ctbPattern::setPeriod() { diff --git a/ctbGui/ctbPattern.h b/ctbGui/ctbPattern.h index 685fe8304..0bb565f4b 100755 --- a/ctbGui/ctbPattern.h +++ b/ctbGui/ctbPattern.h @@ -102,7 +102,7 @@ private: TGNumberEntry *eStopAddr; TGNumberEntry *eFrames; TGNumberEntry *ePeriod; - TGNumberEntry *eCycles; + TGNumberEntry *eTriggers; // TGNumberEntry *eMeasurements; TGNumberEntry *eAdcPipeline; TGNumberEntry *eDBitPipeline; @@ -141,7 +141,7 @@ public: void setAdcPipeline(); void setDBitPipeline(); void setFrames(); - void setCycles(); + void setTriggers(); // void setMeasurements(); void setPeriod(); diff --git a/ctbGui/ctbPowers.cpp b/ctbGui/ctbPowers.cpp index c98808e6a..476235f33 100644 --- a/ctbGui/ctbPowers.cpp +++ b/ctbGui/ctbPowers.cpp @@ -99,7 +99,7 @@ void ctbPower::setValue() { cout << "***************************Setting power " << dacsEntry->GetIntNumber() << " " << id << " " << 1 << endl; try { - myDet->setVoltage(dacsEntry->GetIntNumber(), static_cast(id)); + myDet->setVoltage(static_cast(id), dacsEntry->GetIntNumber()); } CATCH_DISPLAY ("Could not set power " + to_string(id) + ".", "ctbPower::setValue") getValue(); diff --git a/examples/gotthard_setup.det b/examples/gotthard_setup.det index 518c0ad6c..98b1a70c3 100755 --- a/examples/gotthard_setup.det +++ b/examples/gotthard_setup.det @@ -8,7 +8,7 @@ period 0.000024984 delay 0.999999968 gates 1 frames 300000.000000000 -cycles 1.000000000 +triggers 1.000000000 timing auto fineoff 0.000000 startscript none diff --git a/integrationTests/test-integrationDectector.cpp b/integrationTests/test-integrationDectector.cpp index 873e933e6..7eefc3cae 100755 --- a/integrationTests/test-integrationDectector.cpp +++ b/integrationTests/test-integrationDectector.cpp @@ -163,12 +163,12 @@ TEST_CASE("Set settings", "[.integration][.single]"){ TEST_CASE("Timer functions", "[.integration][cli]") { // FRAME_NUMBER, /**< number of real time frames: total number of - // acquisitions is number or frames*number of cycles */ ACQUISITION_TIME, + // acquisitions is number or frames*number of triggers */ ACQUISITION_TIME, // /**< exposure time */ FRAME_PERIOD, /**< period between exposures */ // DELAY_AFTER_TRIGGER, /**< delay between trigger and start of exposure or // readout (in triggered mode) */ GATES_NUMBER, /**< number of gates per - // frame (in gated mode) */ CYCLES_NUMBER, /**< number of cycles: total - // number of acquisitions is number or frames*number of cycles */ + // frame (in gated mode) */ TRIGGER_NUMBER, /**< number of triggers: total + // number of acquisitions is number or frames*number of triggers */ // ACTUAL_TIME, /**< Actual time of the detector's internal timer */ // MEASUREMENT_TIME, /**< Time of the measurement from the detector (fifo) // */ @@ -214,9 +214,9 @@ TEST_CASE("Timer functions", "[.integration][cli]") { CHECK(d.setTimer(slsDetectorDefs::timerIndex::GATES_NUMBER) == gates); } - auto cycles = 2; - d.setTimer(slsDetectorDefs::timerIndex::CYCLES_NUMBER, cycles); - CHECK(d.setTimer(slsDetectorDefs::timerIndex::CYCLES_NUMBER) == cycles); + auto triggers = 2; + d.setTimer(slsDetectorDefs::timerIndex::TRIGGER_NUMBER, triggers); + CHECK(d.setTimer(slsDetectorDefs::timerIndex::TRIGGER_NUMBER) == triggers); if (test::type == dt::EIGER) { auto subtime = 200; diff --git a/integrationTests/test-integrationMulti.cpp b/integrationTests/test-integrationMulti.cpp index ddeaf864f..617b84bbe 100755 --- a/integrationTests/test-integrationMulti.cpp +++ b/integrationTests/test-integrationMulti.cpp @@ -50,7 +50,7 @@ TEST_CASE("Set and read timers", "[.integration][.multi]") { // DELAY_AFTER_TRIGGER, // GATES_NUMBER, - // CYCLES_NUMBER, + // TRIGGER_NUMBER, // ACTUAL_TIME // MEASUREMENT_TIME diff --git a/manual/manual-client/Eiger_short.tex b/manual/manual-client/Eiger_short.tex index d0dab648c..48366bc1d 100755 --- a/manual/manual-client/Eiger_short.tex +++ b/manual/manual-client/Eiger_short.tex @@ -609,17 +609,17 @@ The detector can be setup such to receive external triggers. Connect a LEMO sign \begin{verbatim} sls_detector_put 0-timing [auto/trigger/burst_trigger/gating] sls_detector_put 0-frames x -sls_detector_put 0-cycles y +sls_detector_put 0-triggers y sls_detector_acquire 0- \end{verbatim} No timeout is expected between the start of the acquisition and the arrival of the first trigger. Here are the implemented options so far: \begin{itemize} -\item {\tt{auto}} is the software controlled acquisition (does not use triggers), where {\tt{exptime}} and {\tt{period}} have to be set. Set number of cycles (i.e. triggers) to 1 using {\tt{cycles}}. Set number of frames using {\tt{frames}}. -\item {\tt{trigger}} 1 frame taken for 1 trigger. Your {\tt{frames}} needs to be 1 always, {\tt{cycles}} can be changed and defines how many triggers are considered. {\tt{exptime}} needs to be set. In the GUI this is called trigger exposure series. -\item {\tt{burst\_trigger}} gets only 1 trigger, but allows to take many frames. With {\tt{frames}} one can change the number of frames. {\tt{cycles}} needs to be 1. {\tt{exptime}} and {\tt{period}} have to be set. In the gui it is called trigger readout. -\item{\tt{gating}} allows to get a frame only when the trigger pulse is gating. Note that in this case the exp time and period only depend on the gating signal. {\tt{cycles}} allows to select how many gates to consider. Set number of frames to 1 using {\tt{frames}}. IMPORTANT: Up to firmware 23, the last subframe is oblige to finish being taken, despite the gate signal going down. This will be configurable from later fw and software version. Also, in gating mode, due to timimg of the state machine, you need to leave 500~$\mu$s deadtime between the end on an acquisition and the next. This is as the state machine is unable to check for changes in the status in the first 500~$\mu$s. ATTENTION: if you are in 16 bit mode and you are applying online rate corrections, as now the exptime is generated by the trigger, you might not have correct rate corrections. If you know what the exposure time is in the gating signal, then you can set the {\tt{exptime}} once and the rate corrections will be correct. In 32 bit mode, it does not matter as the rate corrections depends on the {\tt{subexptime}} which is software set independently from the gate exptime. +\item {\tt{auto}} is the software controlled acquisition (does not use triggers), where {\tt{exptime}} and {\tt{period}} have to be set. Set number of triggers (i.e. triggers) to 1 using {\tt{triggers}}. Set number of frames using {\tt{frames}}. +\item {\tt{trigger}} 1 frame taken for 1 trigger. Your {\tt{frames}} needs to be 1 always, {\tt{triggers}} can be changed and defines how many triggers are considered. {\tt{exptime}} needs to be set. In the GUI this is called trigger exposure series. +\item {\tt{burst\_trigger}} gets only 1 trigger, but allows to take many frames. With {\tt{frames}} one can change the number of frames. {\tt{triggers}} needs to be 1. {\tt{exptime}} and {\tt{period}} have to be set. In the gui it is called trigger readout. +\item{\tt{gating}} allows to get a frame only when the trigger pulse is gating. Note that in this case the exp time and period only depend on the gating signal. {\tt{triggers}} allows to select how many gates to consider. Set number of frames to 1 using {\tt{frames}}. IMPORTANT: Up to firmware 23, the last subframe is oblige to finish being taken, despite the gate signal going down. This will be configurable from later fw and software version. Also, in gating mode, due to timimg of the state machine, you need to leave 500~$\mu$s deadtime between the end on an acquisition and the next. This is as the state machine is unable to check for changes in the status in the first 500~$\mu$s. ATTENTION: if you are in 16 bit mode and you are applying online rate corrections, as now the exptime is generated by the trigger, you might not have correct rate corrections. If you know what the exposure time is in the gating signal, then you can set the {\tt{exptime}} once and the rate corrections will be correct. In 32 bit mode, it does not matter as the rate corrections depends on the {\tt{subexptime}} which is software set independently from the gate exptime. When using 32-bit mode, by default the acquisition ends the last complete subframe that was started when still the acquisition time was valid. This has been chosen as many people wants to know the exact acquisition time for when the detector was taking data and also, if {\tt{ratecorr}} are active, the last subframe will be correctly corrected, while otherwise it will be corrected with a wrong subdeadtime. However, from 4.1.0, in gating mode, an option to immediately terminate the subframe when the gate signal goes down it is implemented to stop the acquisition at the same time. This option is {\tt{./sls\_detector\_put interruptsubframe 1}} while the default option is {\tt{./sls\_detector\_put interruptsubframe 0}}. @@ -628,13 +628,13 @@ However, from 4.1.0, in gating mode, an option to immediately terminate the subf Hardware-wise, the ENABLE OUT signal outputs when the chips are really acquiring. This means that the single subframes will be output in 32 bit mode. The TRIGGER OUT outputs the sum-up-signal at the moment (which is useless). This will be changed in the future to output the envelop of the enable signal. -We are planning to change some functionality, i.e. unify the {\tt{trigger}} and {\tt{burst\_trigger}} trigger modes and make both {\tt{frames}} and {\tt{cycles}} configurable at the same time. +We are planning to change some functionality, i.e. unify the {\tt{trigger}} and {\tt{burst\_trigger}} trigger modes and make both {\tt{frames}} and {\tt{triggers}} configurable at the same time. There is the possibility to use {\tt{timing trigger/burst\_trigger}} and send software single commands to fake the trigger. This is done with: \begin{verbatim} sls_detector_put 0-timing [trigger/burst_trigger] sls_detector_put 0-frames x -sls_detector_put 0-cycles y +sls_detector_put 0-triggers y sls_detector_status trigger \end{verbatim} Note that this functionality is very (!) useful if you need to do something between and acquisition and the next. This can be used to do a fast threshold scan for example. See section~\ref{sec:fastthresholdscan}. @@ -715,7 +715,7 @@ If \textbf{dr} is 32 and \textbf{clkdivider} is not 2, whatever the detector get Here is a list of parameters that should be reset: \begin{enumerate} \item \textbf{resetframescaught} should be reset to zero after every acquisition taken with {\tt{receiver start}},{\tt{status start}},{\tt{receiver stop}}. If the acquisition is taken with {\tt{sls\_detector\_acquire}}, there is no need to reset this. -\item After changing the {\tt{timing}} mode of the detector, one should reset to '1' the unused value, in that specific timing mode, between \textbf{frames} and \textbf{cycles}. See section~\ref{triggering} for how to use the timing. At the present moment the detector will acquire more frames than planned if the variable not used between \textbf{frames} and \textbf{cycles} is not reset. In future releases, the unused variable will be ignored. Still resetting is a good practice. +\item After changing the {\tt{timing}} mode of the detector, one should reset to '1' the unused value, in that specific timing mode, between \textbf{frames} and \textbf{triggers}. See section~\ref{triggering} for how to use the timing. At the present moment the detector will acquire more frames than planned if the variable not used between \textbf{frames} and \textbf{triggers} is not reset. In future releases, the unused variable will be ignored. Still resetting is a good practice. \end{enumerate} @@ -1257,7 +1257,7 @@ We have also been requested if we could speed up the threshold scan. At the mome ./sls_detector_put enablefwrite 0 ./sls_detector_put resetframescaught 0 ./sls_detector_put index 0 -./sls_detector_put cycles 21 +./sls_detector_put triggers 21 ./sls_detector_put receiver start ./sls_detector_put status start for i in $(seq 0 20); @@ -1515,8 +1515,8 @@ frames number where {\tt{number}} is a string to be interpreted as an integer. \item \begin{verbatim} -sls_detector_get cycles -cycles number +sls_detector_get triggers +triggers number \end{verbatim} where {\tt{number}} is a string to be interpreted as an integer. diff --git a/manual/manual-client/commands.txt b/manual/manual-client/commands.txt index ac64110a3..bde305796 100755 --- a/manual/manual-client/commands.txt +++ b/manual/manual-client/commands.txt @@ -111,7 +111,7 @@ "delay"; // sets/gets delay after trigger in s "gates"; // sets/gets number of gates per frame in gated mode "frames"; // sets/gets number of frames - "cycles"; // sets/gets number of cycles (use in trigger mode) + "triggers"; // sets/gets number of triggers (use in trigger mode) "probes"; // sets/gets number of probes (advanced!) "measurements"; // sets/gets number of non-real time measurements /* read only timers */ @@ -120,7 +120,7 @@ "delayl"; // gets delay left "gatesl"; // gets number of gates left "framesl"; // gets number of frames left - "cyclesl"; // gets number of cycles left + "triggersl"; // gets number of triggers left "now"; // gets time stamp from the dteector "timestamp"; // gets time stamp for the frames (fifo-style) "framescaught";// gets the entire frames caught by receiver diff --git a/manual/manual-client/slsDetectorClientHowTo.tex b/manual/manual-client/slsDetectorClientHowTo.tex index 414d1877b..0f9ed3190 100755 --- a/manual/manual-client/slsDetectorClientHowTo.tex +++ b/manual/manual-client/slsDetectorClientHowTo.tex @@ -94,7 +94,7 @@ where: \\ \textit{v0} is the scan0 variable with the desired precision, if scan0 is enabled;\\ \textit{v1} is the scan1 variable with the desired precision, if scan1 is enabled;\\ \textit{p} is the position index, if different positions are configured;\\ -\textit{f} is the frame index of the first frame stored in the file, if many frames and cycles are configured;\\ +\textit{f} is the frame index of the first frame stored in the file, if many frames and triggers are configured;\\ \textit{i} is the file index;\\ \textit{ext} is the file extension e.g. \textit{.raw} for MYTHEN and \E raw data, \textit{.dat} for MYTHEN processed data. \item[index i] Sets the starting index of the file i at the beginning of the acquisition (automatically incremented for each measurement). @@ -115,10 +115,10 @@ Sets the number of gates per frame in gated (stroboscopic) mode.\\ Refer to the detailed documentation to understand how the different timing modes work. \item[frames n] Sets the number of frames acquired sequentially per cycle (e.g. after each trigger), with the exposure time defined by exptime and the period defined by period (unless in gated mode). The frame index in the output file name will automatically be incremented.\\ -Note that the total number of images will be frames times cycles. Refer to detailed documentation to understand how the different timing modes work. -\item[cycles n] -Sets the number of cycles (e.g. number of triggers). The frame index in the output file name will automatically be incremented. \\ -Note that the total number of images will be by frames times cycles. Refer to the detailed documentation to understand how the different timing modes work. +Note that the total number of images will be frames times triggers. Refer to detailed documentation to understand how the different timing modes work. +\item[triggers n] +Sets the number of triggers (e.g. number of triggers). The frame index in the output file name will automatically be incremented. \\ +Note that the total number of images will be by frames times triggers. Refer to the detailed documentation to understand how the different timing modes work. \item[probes] Sets the number of probes to accumulate for stroboscopic measurements. \\ Refer to detailed documentation to understand how the different timing modes work. \item[measurements] Sets the number of repetitions of the acquisitions (non real time!). The file index in the file name will be automatically incremented.\\ @@ -231,7 +231,7 @@ It is normally recommended to use \verb=sls\_detector\_acquire [j-]=, which take %\item[delayl] %\item[gatesl] %\item[framesl] -%\item[cyclesl] +%\item[triggersl] %\item[frameindex] %\item[now] \end{description} @@ -430,11 +430,11 @@ Returns the number of gates per frame in gated (stroboscopic) mode. Refer to detailed documentation to understand how the different timing modes work. \item[frames] Returns the number of frames acquired sequentially per cycle (e.g. after each trigger), with the exposure time defined by exptime and the period defined by period (unless in gated mode). Returned as a string to be interpreted as an integer ``frames integer'' -Note that the total number of images is frames times cycles. +Note that the total number of images is frames times triggers. Refer to detailed documentation to understand how the different timing modes work. -\item[cycles n] -Returns the number of cycles (e.g. number of triggers). Returned as atring to be interpreted as an integer ``cycles integer'' -Note that the total number of images is frames times cycles. +\item[triggers n] +Returns the number of triggers (e.g. number of triggers). Returned as atring to be interpreted as an integer ``triggers integer'' +Note that the total number of images is frames times triggers. Refer to detailed documentation to understand how the different timing modes work. \item[probes] Returns the number of probes to accumulate for stroboscopic measurements. Refer to detailed documentation to understand how the different timing modes work. @@ -556,7 +556,7 @@ It is normally recommended to use \verb=sls\_detector\_acquire [j-]=, which take \item[delayl] Returns the delay after trigger left for the current frame. \item[gatesl] Returns the number of gates left for the current frame. \item[framesl] Returns the number of frames left for the current cycle. -\item[cyclesl] Returns the number of cycles left for the current acquisition. +\item[triggersl] Returns the number of triggers left for the current acquisition. \item[now] Returns the current timestamp of the detector clock. \item[timestamp] Returns the timestamp of the acquisitions in a First-In/First-Out mode i.e. every time it is called it returns the timestamp of the first acquisition start of readout. The FIFO is reset everytime the acquisition is started. \end{description} diff --git a/manual/manual-gui/slsDetectorGuiHowTo.tex b/manual/manual-gui/slsDetectorGuiHowTo.tex index c7973207a..dffac2af2 100755 --- a/manual/manual-gui/slsDetectorGuiHowTo.tex +++ b/manual/manual-gui/slsDetectorGuiHowTo.tex @@ -217,7 +217,7 @@ is used to configure the detector parameter var \item[delay t] Sets the delay after trigger (in s) \item[gates n] Sets the number of gates per frame \item[frames n] Sets the number of frames per cycle (e.g. after each trigger) -\item[cycles n] Sets the number of cycles (e.g. number of triggers) +\item[triggers n] Sets the number of triggers (e.g. number of triggers) \item[probes n] Sets the number of probes to accumulate (max 3) \item[dr n] Sets the dynamic range - can be (1,) 4, 8,16 or 24 bits \item[flags mode] Sets the readout flags - can be none or storeinram @@ -298,7 +298,7 @@ is used to retrieve the detector parameter var \item[delay] Gets the delay after trigger (in s) \item[gates] Gets the number of gates per frame \item[frames] Gets the number of frames per cycle (e.g. after each trigger) -\item[cycles] Gets the number of cycles (e.g. number of triggers) +\item[triggers] Gets the number of triggers (e.g. number of triggers) \item[probes] Gets the number of probes to accumulate (max 3) \item[timestamp] Gets the internal time stamp of the nex frame acquired (i.e. during an acquisition, all timestamps of the frames are stored in a FIFO which can be read after the acquisition - returns -1 if the FIFO is empty) \item[dr] Gets the dynamic range diff --git a/manual/manual-main/images/gated_acquisition.eps b/manual/manual-main/images/gated_acquisition.eps index 77b2a828d..67d30ccf8 100755 --- a/manual/manual-main/images/gated_acquisition.eps +++ b/manual/manual-main/images/gated_acquisition.eps @@ -372,7 +372,7 @@ gs 1 -1 sc (Number of frames) col0 sh gr gs 1 -1 sc (Number of frames) col0 sh gr /Times-Roman ff 450.00 scf sf 11325 9150 m -gs 1 -1 sc (Number of cycles) col0 sh gr +gs 1 -1 sc (Number of triggers) col0 sh gr /Times-Roman ff 240.00 scf sf 5325 4950 m gs 1 -1 sc (Readout) col0 sh gr diff --git a/manual/manual-main/images/gated_acquisition.fig b/manual/manual-main/images/gated_acquisition.fig index 432110c89..1fde889c5 100755 --- a/manual/manual-main/images/gated_acquisition.fig +++ b/manual/manual-main/images/gated_acquisition.fig @@ -118,7 +118,7 @@ Single 21900 2700 22050 2700 4 0 0 50 0 0 30 0.0000 4 300 3225 6975 7800 Number of frames\001 4 0 0 50 0 0 30 0.0000 4 300 3225 15975 7800 Number of frames\001 -4 0 0 50 0 0 30 0.0000 4 405 3090 11325 9150 Number of cycles\001 +4 0 0 50 0 0 30 0.0000 4 405 3090 11325 9150 Number of triggers\001 4 0 0 50 0 0 16 0.0000 4 165 810 5325 4950 Readout\001 4 0 0 50 0 0 30 0.0000 4 300 2565 825 4125 Detection time\001 4 0 0 50 0 0 30 0.0000 4 300 1785 825 5550 Dead time\001 diff --git a/manual/manual-main/images/gated_acquisition.fig.bak b/manual/manual-main/images/gated_acquisition.fig.bak index c615f22fa..0afc80aad 100755 --- a/manual/manual-main/images/gated_acquisition.fig.bak +++ b/manual/manual-main/images/gated_acquisition.fig.bak @@ -95,7 +95,7 @@ Single 4 0 0 50 0 0 30 0.0000 4 405 2580 9450 6600 Exposure time\001 4 0 0 50 0 0 30 0.0000 4 300 3225 6975 7800 Number of frames\001 4 0 0 50 0 0 30 0.0000 4 300 3225 15975 7800 Number of frames\001 -4 0 0 50 0 0 30 0.0000 4 405 3090 11325 9150 Number of cycles\001 +4 0 0 50 0 0 30 0.0000 4 405 3090 11325 9150 Number of triggers\001 4 0 0 50 0 0 16 0.0000 4 165 810 5325 4950 Readout\001 4 0 0 50 0 0 30 0.0000 4 300 2565 1050 4125 Detection time\001 4 0 0 50 0 0 30 0.0000 4 300 1785 1050 5550 Dead time\001 diff --git a/manual/manual-main/images/normal_acquisition.eps b/manual/manual-main/images/normal_acquisition.eps index 631061fa2..642453f67 100755 --- a/manual/manual-main/images/normal_acquisition.eps +++ b/manual/manual-main/images/normal_acquisition.eps @@ -341,7 +341,7 @@ gs 1 -1 sc (Number of frames) col0 sh gr gs 1 -1 sc (Number of frames) col0 sh gr /Times-Roman ff 450.00 scf sf 11325 9150 m -gs 1 -1 sc (Number of cycles) col0 sh gr +gs 1 -1 sc (Number of triggers) col0 sh gr /Times-Roman ff 240.00 scf sf 5325 4950 m gs 1 -1 sc (Readout) col0 sh gr diff --git a/manual/manual-main/images/normal_acquisition.fig b/manual/manual-main/images/normal_acquisition.fig index 7a1f4d907..50e0a4eda 100755 --- a/manual/manual-main/images/normal_acquisition.fig +++ b/manual/manual-main/images/normal_acquisition.fig @@ -79,7 +79,7 @@ Single 4200 5850 4650 5850 4 0 0 50 0 0 30 0.0000 4 300 3225 6975 7800 Number of frames\001 4 0 0 50 0 0 30 0.0000 4 300 3225 15975 7800 Number of frames\001 -4 0 0 50 0 0 30 0.0000 4 405 3090 11325 9150 Number of cycles\001 +4 0 0 50 0 0 30 0.0000 4 405 3090 11325 9150 Number of triggers\001 4 0 0 50 0 0 16 0.0000 4 165 810 5325 4950 Readout\001 4 0 0 50 0 0 30 0.0000 4 300 2565 825 4125 Detection time\001 4 0 0 50 0 0 30 0.0000 4 300 1785 825 5550 Dead time\001 diff --git a/manual/manual-main/images/normal_acquisition.fig.bak b/manual/manual-main/images/normal_acquisition.fig.bak index 432110c89..1fde889c5 100755 --- a/manual/manual-main/images/normal_acquisition.fig.bak +++ b/manual/manual-main/images/normal_acquisition.fig.bak @@ -118,7 +118,7 @@ Single 21900 2700 22050 2700 4 0 0 50 0 0 30 0.0000 4 300 3225 6975 7800 Number of frames\001 4 0 0 50 0 0 30 0.0000 4 300 3225 15975 7800 Number of frames\001 -4 0 0 50 0 0 30 0.0000 4 405 3090 11325 9150 Number of cycles\001 +4 0 0 50 0 0 30 0.0000 4 405 3090 11325 9150 Number of triggers\001 4 0 0 50 0 0 16 0.0000 4 165 810 5325 4950 Readout\001 4 0 0 50 0 0 30 0.0000 4 300 2565 825 4125 Detection time\001 4 0 0 50 0 0 30 0.0000 4 300 1785 825 5550 Dead time\001 diff --git a/manual/manual-main/images/trigger_acquisition.eps b/manual/manual-main/images/trigger_acquisition.eps index d5b03cec8..5027c5364 100755 --- a/manual/manual-main/images/trigger_acquisition.eps +++ b/manual/manual-main/images/trigger_acquisition.eps @@ -401,7 +401,7 @@ gs 1 -1 sc (External trigger) col0 sh gr gs 1 -1 sc (Number of frames) col0 sh gr /Times-Roman ff 450.00 scf sf 12600 9150 m -gs 1 -1 sc (Number of cycles) col0 sh gr +gs 1 -1 sc (Number of triggers) col0 sh gr /Times-Roman ff 240.00 scf sf 6600 4950 m gs 1 -1 sc (Readout) col0 sh gr diff --git a/manual/manual-main/images/trigger_acquisition.fig b/manual/manual-main/images/trigger_acquisition.fig index 90e942079..3f047048b 100755 --- a/manual/manual-main/images/trigger_acquisition.fig +++ b/manual/manual-main/images/trigger_acquisition.fig @@ -111,7 +111,7 @@ Single 4 0 0 50 0 0 30 0.0000 4 300 1785 825 5550 Dead time\001 4 0 0 50 0 0 30 0.0000 4 405 2760 825 2700 External trigger\001 4 0 0 50 0 0 30 0.0000 4 300 3225 8250 7800 Number of frames\001 -4 0 0 50 0 0 30 0.0000 4 405 3090 12600 9150 Number of cycles\001 +4 0 0 50 0 0 30 0.0000 4 405 3090 12600 9150 Number of triggers\001 4 0 0 50 0 0 16 0.0000 4 165 810 6600 4950 Readout\001 4 0 0 50 0 0 30 0.0000 4 405 2580 4575 6225 Exposure time\001 4 0 0 50 0 0 30 0.0000 4 300 1140 9525 6225 Period\001 diff --git a/manual/manual-main/images/trigger_acquisition.fig.bak b/manual/manual-main/images/trigger_acquisition.fig.bak index 7a1f4d907..50e0a4eda 100755 --- a/manual/manual-main/images/trigger_acquisition.fig.bak +++ b/manual/manual-main/images/trigger_acquisition.fig.bak @@ -79,7 +79,7 @@ Single 4200 5850 4650 5850 4 0 0 50 0 0 30 0.0000 4 300 3225 6975 7800 Number of frames\001 4 0 0 50 0 0 30 0.0000 4 300 3225 15975 7800 Number of frames\001 -4 0 0 50 0 0 30 0.0000 4 405 3090 11325 9150 Number of cycles\001 +4 0 0 50 0 0 30 0.0000 4 405 3090 11325 9150 Number of triggers\001 4 0 0 50 0 0 16 0.0000 4 165 810 5325 4950 Readout\001 4 0 0 50 0 0 30 0.0000 4 300 2565 825 4125 Detection time\001 4 0 0 50 0 0 30 0.0000 4 300 1785 825 5550 Dead time\001 diff --git a/manual/manual-main/manual.tex b/manual/manual-main/manual.tex index c7973207a..dffac2af2 100755 --- a/manual/manual-main/manual.tex +++ b/manual/manual-main/manual.tex @@ -217,7 +217,7 @@ is used to configure the detector parameter var \item[delay t] Sets the delay after trigger (in s) \item[gates n] Sets the number of gates per frame \item[frames n] Sets the number of frames per cycle (e.g. after each trigger) -\item[cycles n] Sets the number of cycles (e.g. number of triggers) +\item[triggers n] Sets the number of triggers (e.g. number of triggers) \item[probes n] Sets the number of probes to accumulate (max 3) \item[dr n] Sets the dynamic range - can be (1,) 4, 8,16 or 24 bits \item[flags mode] Sets the readout flags - can be none or storeinram @@ -298,7 +298,7 @@ is used to retrieve the detector parameter var \item[delay] Gets the delay after trigger (in s) \item[gates] Gets the number of gates per frame \item[frames] Gets the number of frames per cycle (e.g. after each trigger) -\item[cycles] Gets the number of cycles (e.g. number of triggers) +\item[triggers] Gets the number of triggers (e.g. number of triggers) \item[probes] Gets the number of probes to accumulate (max 3) \item[timestamp] Gets the internal time stamp of the nex frame acquired (i.e. during an acquisition, all timestamps of the frames are stored in a FIFO which can be read after the acquisition - returns -1 if the FIFO is empty) \item[dr] Gets the dynamic range diff --git a/manual/manual-main/slsDetector-softFAQ.tex b/manual/manual-main/slsDetector-softFAQ.tex index ecd4af5f5..dfcdf8e84 100755 --- a/manual/manual-main/slsDetector-softFAQ.tex +++ b/manual/manual-main/slsDetector-softFAQ.tex @@ -127,7 +127,7 @@ where: \\ \textit{v0} is the scan0 variable with the desired precision, if scan0 is enabled;\\ \textit{v1} is the scan1 variable with the desired precision, if scan1 is enabled;\\ \textit{p} is the position index, if different positions are configured;\\ -\textit{f} is the frame index of the first frame stored in the file, if many frames and cycles are configured;\\ +\textit{f} is the frame index of the first frame stored in the file, if many frames and triggers are configured;\\ \textit{i} is the file index;\\ \textit{ext} is the file extension e.g. \textit{.raw} for MYTHEN raw data, \textit{.dat} for MYTHEN processed data. @@ -241,7 +241,7 @@ Figure~\ref{eq:acqflow} shows in which sequence the various scripts and loops ar If you prefere to handle the acquisition from your acquisition enviroment, simply leave al scripts and scans disabled and call the acquition from your acquisition enviroment. \\ -Only the frames and cycles loops are defined in firmware and guarantee a precise timing of the acquisition which cannot replaced by any other method (you can synchronize to your beamline by hardware connection of the IO signals as described in~\ref{sec:timing}). +Only the frames and triggers loops are defined in firmware and guarantee a precise timing of the acquisition which cannot replaced by any other method (you can synchronize to your beamline by hardware connection of the IO signals as described in~\ref{sec:timing}). Hereafter a description of the meaning of the various loops: \begin{description} @@ -259,11 +259,11 @@ Hereafter a description of the meaning of the various loops: The detector is moved in the angular positions specified by the positions command.\\ The command for moving the detector should be defined as described in~\ref{sec:usersFunc}.\\ All data acquired during a position loop will be merged together, unless the number of positions is set to 0. In this case single frames will be converted to angle without merging.\\ - Avoid using the position loop together with many frames/cycles. + Avoid using the position loop together with many frames/triggers. -\item[Cycles loop] is executed in real time and defines e.g. the number of triggers that will be accepted. The total number of images will be given by frames times cycles. +\item[Triggers loop] is executed in real time and defines e.g. the number of triggers that will be accepted. The total number of images will be given by frames times triggers. -\item[Frames loop] is executed in real time and defines e.g. the images acquired per trigger. The total number of images will be given by frames times cycles. +\item[Frames loop] is executed in real time and defines e.g. the images acquired per trigger. The total number of images will be given by frames times triggers. \end{description} Executing a script simply consists in a system call with the arguments specified below. The various scripts are executed only if they are enabled and different than \textit{none}. \\ @@ -332,11 +332,11 @@ In the following is a list of the main parameters involved in the acquisition ti \item[Period] is the period of the images acquired. If it is shorter than the exposure time plus readout time, it will be ignored. \item[Delay after trigger] can be set as a delay between the trigger signal and the start of the detection time. \item[Number of gates] is used only in \textit{gating} mode and is the number of times that the gate is toggled before the detector is read out. Useful for stroboscopic measurements with gate period shorter than the minim acquisition period of the detector, otherwise can be left to 1. -\item[Number of frames] is the number of images to be acquired per cycle. Frames and cycles have the same meaning except in trigger mode, when frames means the number of images per trigger. The total number of images is frames time cycles. -\item[Number of cycles] is the number of times that the frames are acquired. Frames and cycles have the same meaning except in trigger mode, when cycles means the number of triggers that will be accepted. The total number of images is frames time cycles. +\item[Number of frames] is the number of images to be acquired per cycle. Frames and triggers have the same meaning except in trigger mode, when frames means the number of images per trigger. The total number of images is frames time triggers. +\item[Number of triggers] is the number of times that the frames are acquired. Frames and triggers have the same meaning except in trigger mode, when triggers means the number of triggers that will be accepted. The total number of images is frames time triggers. \item[Number of probes] is used in stoboscopic measurements when the period is longer than the minimum acquisition period, but shorter than the frame rate.\\ In this case the data can be summed in firmware. \\ -Currently it is implemented for Mythen only. If probes is set to 0, works normallyreturning an image for each readout, otherwise set number of cycles to 1. The maximum number of probes that can be set is 3. The detector will return a number of image equal to the number of probes, where all frames are going to be accumulated. The total number of readouts is number of frames time probes and for probes=1 the detector will return one image where all frames have been summed, for probes=2 two images where every second frame has been summed (each image accumulates the number of frames), for probes=3 three images where every third image has been summed (each image accumulates the number of frames).\\ +Currently it is implemented for Mythen only. If probes is set to 0, works normallyreturning an image for each readout, otherwise set number of triggers to 1. The maximum number of probes that can be set is 3. The detector will return a number of image equal to the number of probes, where all frames are going to be accumulated. The total number of readouts is number of frames time probes and for probes=1 the detector will return one image where all frames have been summed, for probes=2 two images where every second frame has been summed (each image accumulates the number of frames), for probes=3 three images where every third image has been summed (each image accumulates the number of frames).\\ The returned images will always have 32~bit dynamic range, while the dynamic range if the detector defines the bit depth of the counters in rder to limit the readout time, if necessary.\\ The probes counter waorks also in trigger and gating modes. \end{description} @@ -349,14 +349,14 @@ The probes counter waorks also in trigger and gating modes. \begin{center} \includegraphics[width=\textwidth]{images/normal_acquisition.eps} \end{center} -\caption{Auto timing: the detection time is defined by the exposure time and the period by period (if longer than exposure time plus readout time). The total number of images is frames (in the example 3) times cycles (in the example 2), and in this case there is no difference between the acquisition of the two.}\label{fig:autotiming} +\caption{Auto timing: the detection time is defined by the exposure time and the period by period (if longer than exposure time plus readout time). The total number of images is frames (in the example 3) times triggers (in the example 2), and in this case there is no difference between the acquisition of the two.}\label{fig:autotiming} \end{figure} \begin{figure} \begin{center} \includegraphics[width=\textwidth]{images/gated_acquisition.eps} \end{center} -\caption{Gating mode: the detector acquires for a number of gates define by the user (in this case 4) before being read out, independently on the timing of the gates. The detector remains insensitive during the readout time and then starts being active again. External gates given during the readout time are ignored. The total number of images is frames (in the example 3) times cycles (in the example 2), and in this case there is no difference between the acquisition of the two. The polarity of the external gate signal can be defined by the user through the \textit{external signal flag} (in the example active high).}\label{fig:gating} +\caption{Gating mode: the detector acquires for a number of gates define by the user (in this case 4) before being read out, independently on the timing of the gates. The detector remains insensitive during the readout time and then starts being active again. External gates given during the readout time are ignored. The total number of images is frames (in the example 3) times triggers (in the example 2), and in this case there is no difference between the acquisition of the two. The polarity of the external gate signal can be defined by the user through the \textit{external signal flag} (in the example active high).}\label{fig:gating} \end{figure} @@ -365,7 +365,7 @@ The probes counter waorks also in trigger and gating modes. \begin{center} \includegraphics[width=\textwidth]{images/trigger_acquisition.eps} \end{center} -\caption{Trigger mode: the external trigger signal defines the start of the beginning of the acquisition, which starts after the delay set by the user. For each trigger, the number of frames is acquired (in the example 3) and all trigger signals ignored. The number of trigger accepted is given by the number of cycles (in the example 2). The polarity of the external trigger signal can be defined by the user through the \textit{external signal flag} (in the example rising edge).}\label{fig:trig} +\caption{Trigger mode: the external trigger signal defines the start of the beginning of the acquisition, which starts after the delay set by the user. For each trigger, the number of frames is acquired (in the example 3) and all trigger signals ignored. The number of trigger accepted is given by the number of triggers (in the example 2). The polarity of the external trigger signal can be defined by the user through the \textit{external signal flag} (in the example rising edge).}\label{fig:trig} \end{figure} @@ -373,7 +373,7 @@ The probes counter waorks also in trigger and gating modes. \begin{center} \includegraphics[width=\textwidth]{images/ro_trigger_acquisition.eps} \end{center} -\caption{Read Out Trigger mode: the external trigger signal defines the beginning of the readout. The exposure time works as a time out for the waiting time for the trigger signal. The number of trigger accepted is given by the number of cycles (in the example 3) and it does not make sense to program more than one frame. The polarity of the external trigger signal can be defined by the user through the \textit{external signal flag} (in the example rising edge).}\label{fig:trig} +\caption{Read Out Trigger mode: the external trigger signal defines the beginning of the readout. The exposure time works as a time out for the waiting time for the trigger signal. The number of trigger accepted is given by the number of triggers (in the example 3) and it does not make sense to program more than one frame. The polarity of the external trigger signal can be defined by the user through the \textit{external signal flag} (in the example rising edge).}\label{fig:trig} \end{figure} diff --git a/manual/manual-main/slsDetectorClientHowTo.tex b/manual/manual-main/slsDetectorClientHowTo.tex index 675d0ca0d..6f411c84a 100755 --- a/manual/manual-main/slsDetectorClientHowTo.tex +++ b/manual/manual-main/slsDetectorClientHowTo.tex @@ -91,7 +91,7 @@ where: \\ \textit{v0} is the scan0 variable with the desired precision, if scan0 is enabled;\\ \textit{v1} is the scan1 variable with the desired precision, if scan1 is enabled;\\ \textit{p} is the position index, if different positions are configured;\\ -\textit{f} is the frame index of the first frame stored in the file, if many frames and cycles are configured;\\ +\textit{f} is the frame index of the first frame stored in the file, if many frames and triggers are configured;\\ \textit{i} is the file index;\\ \textit{ext} is the file extension e.g. \textit{.raw} for MYTHEN raw data, \textit{.dat} for MYTHEN processed data. \item[index i] Sets the starting index of the file i at the beginning of the acquisition (automatically incremented for each measurement). @@ -110,10 +110,10 @@ Sets the number of gates per frame in gated (stroboscopic) mode.\\ Refere to the detailed documentation to understand how the different timing modes work. \item[frames n] Sets the number of frames acquired sequentially per cycle (e.g. after each trigger), with the exposure time defined by exptime and the period defined by period (unless in gated mode). The frame index in the output file name will automatically be incremented.\\ -Note that the total number of images will be frames times cycles. Refere to detailed documentation to understand how the different timing modes work. -\item[cycles n] -Sets the number of cycles (e.g. number of triggers). The frame index in the output file name will automatically be incremented. \\ -Note that the total number of images will be by frames times cycles. Refere to the detailed documentation to understand how the different timing modes work. +Note that the total number of images will be frames times triggers. Refere to detailed documentation to understand how the different timing modes work. +\item[triggers n] +Sets the number of triggers (e.g. number of triggers). The frame index in the output file name will automatically be incremented. \\ +Note that the total number of images will be by frames times triggers. Refere to the detailed documentation to understand how the different timing modes work. \item[probes] Sets the number of probes to accumulate for stroboscopic measurements. \\ Refere to detailed documentation to understand how the different timing modes work. \item[measurements] Sets the number of repetitions of the acquisitions (non real time!). The file index in the file name will be automotically incremented.\\ @@ -234,7 +234,7 @@ It is normally reccomended to use \verb=sls\_detector\_acquire [j-]=, which take %\item[delayl] %\item[gatesl] %\item[framesl] -%\item[cyclesl] +%\item[triggersl] %\item[frameindex] %\item[now] \end{description} @@ -393,11 +393,11 @@ Returns the number of gates per frame in gated (stroboscopic) mode. Refere to detailed documentation to understand how the different timing modes work. \item[frames] Returns the number of frames acquired sequentially per cycle (e.g. after each trigger), with the exposure time defined by exptime and the period defined by period (unless in gated mode). -Note that the total number of images is frames times cycles. +Note that the total number of images is frames times triggers. Refere to detailed documentation to understand how the different timing modes work. -\item[cycles n] -Returns the number of cycles (e.g. number of triggers). -Note that the total number of images is frames times cycles. +\item[triggers n] +Returns the number of triggers (e.g. number of triggers). +Note that the total number of images is frames times triggers. Refere to detailed documentation to understand how the different timing modes work. \item[probes] Returns the number of probes to accumulate for stroboscopic measurements. Refere to detailed documentation to understand how the different timing modes work. @@ -518,7 +518,7 @@ It is normally reccomended to use \verb=sls\_detector\_acquire [j-]=, which take \item[delayl] Returns the delay after trigger left for the current frame. \item[gatesl] Returns the number of gates left for the current frame. \item[framesl] Returns the number of frames left for the current cycle. -\item[cyclesl] Returns the number of cycles left for the current acquisition. +\item[triggersl] Returns the number of triggers left for the current acquisition. \item[now] Returns the current timestamp of the detector clock. \item[timestamp] Returns the timestamp of the acquisitions in a First-In/First-Out mode i.e. every time it is called it returns the timestamp of the first acquisition start of readout. The FIFO is reset everytime the acquisition is started. \end{description} diff --git a/manual/manual-main/slsDetectorGuiHowTo.tex b/manual/manual-main/slsDetectorGuiHowTo.tex index c7973207a..dffac2af2 100755 --- a/manual/manual-main/slsDetectorGuiHowTo.tex +++ b/manual/manual-main/slsDetectorGuiHowTo.tex @@ -217,7 +217,7 @@ is used to configure the detector parameter var \item[delay t] Sets the delay after trigger (in s) \item[gates n] Sets the number of gates per frame \item[frames n] Sets the number of frames per cycle (e.g. after each trigger) -\item[cycles n] Sets the number of cycles (e.g. number of triggers) +\item[triggers n] Sets the number of triggers (e.g. number of triggers) \item[probes n] Sets the number of probes to accumulate (max 3) \item[dr n] Sets the dynamic range - can be (1,) 4, 8,16 or 24 bits \item[flags mode] Sets the readout flags - can be none or storeinram @@ -298,7 +298,7 @@ is used to retrieve the detector parameter var \item[delay] Gets the delay after trigger (in s) \item[gates] Gets the number of gates per frame \item[frames] Gets the number of frames per cycle (e.g. after each trigger) -\item[cycles] Gets the number of cycles (e.g. number of triggers) +\item[triggers] Gets the number of triggers (e.g. number of triggers) \item[probes] Gets the number of probes to accumulate (max 3) \item[timestamp] Gets the internal time stamp of the nex frame acquired (i.e. during an acquisition, all timestamps of the frames are stored in a FIFO which can be read after the acquisition - returns -1 if the FIFO is empty) \item[dr] Gets the dynamic range diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index ee5a58c7e..f37b4966b 100755 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -5,8 +5,6 @@ pybind11_add_module(_sls_detector src/experimental.cpp ) - - target_link_libraries(_sls_detector PUBLIC slsDetectorShared slsReceiverShared @@ -26,12 +24,12 @@ set( PYTHON_FILES dacs.py decorators.py detector_property.py - detector.py - eiger.py + # detector.py + # eiger.py errors.py experimental.py - jungfrau_ctb.py - jungfrau.py + # jungfrau_ctb.py + # jungfrau.py registers.py utils.py diff --git a/python/scripts/basic.py b/python/scripts/basic.py index d1da98cce..4400961f3 100755 --- a/python/scripts/basic.py +++ b/python/scripts/basic.py @@ -2,12 +2,9 @@ import os import sys import numpy as np sys.path.append(os.path.join(os.getcwd(), 'bin')) -from sls_detector import Eiger, Jungfrau, Detector, defs -from sls_detector import ExperimentalDetector - -from _sls_detector.io import read_my302_file - +# from sls_detector import Eiger, Jungfrau, Detector, defs +from sls_detector import Detector +from sls_detector import dacIndex d = Detector() -e = ExperimentalDetector() -j = Jungfrau() + diff --git a/python/sls_detector/__init__.py b/python/sls_detector/__init__.py index f250e3336..b5addeed2 100755 --- a/python/sls_detector/__init__.py +++ b/python/sls_detector/__init__.py @@ -1,9 +1,10 @@ -from .detector import Detector, DetectorError, free_shared_memory -from .eiger import Eiger -from .experimental import ExperimentalDetector -from .jungfrau import Jungfrau -from .jungfrau_ctb import JungfrauCTB -from _sls_detector import DetectorApi +# from .detector import Detector, DetectorError, free_shared_memory +# from .eiger import Eiger +from .experimental import Detector + +# from .jungfrau import Jungfrau +# from .jungfrau_ctb import JungfrauCTB +# from _sls_detector import DetectorApi import _sls_detector diff --git a/python/sls_detector/detector.py b/python/sls_detector/detector.py deleted file mode 100755 index 6b87ae2d9..000000000 --- a/python/sls_detector/detector.py +++ /dev/null @@ -1,1486 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -""" -Python - sls -============= - -""" -import os -from collections.abc import Iterable -from collections import namedtuple - -from _sls_detector import DetectorApi -from .detector_property import DetectorProperty -from .errors import DetectorError, DetectorValueError -from .registers import Register -from .utils import element_if_equal - -import numpy as np - -class Detector: - """ - Base class used as interface with the slsDetectorSoftware. To control a specific detector use the - derived classes such as Eiger and Jungfrau. Functions as an interface to the C++ API and provides a - more Pythonic interface - """ - - _speed_names = {0: 'Full Speed', 1: 'Half Speed', 2: 'Quarter Speed', 3: 'Super Slow Speed'} - _speed_int = {'Full Speed': 0, 'Half Speed': 1, 'Quarter Speed': 2, 'Super Slow Speed': 3} - _settings = [] - - def __init__(self, multi_id=0): - self._api = DetectorApi(multi_id) - self._register = Register(self) - - self._flippeddatax = DetectorProperty(self._api.getFlippedDataX, - self._api.setFlippedDataX, - self._api.getNumberOfDetectors, - 'flippeddatax') - - - def __len__(self): - return self._api.getNumberOfDetectors() - - def __repr__(self): - return '{}(id = {})'.format(self.__class__.__name__, - self._api.getMultiDetectorId()) - - - def acq(self): - """ - Blocking command to launch the programmed measurement. Number of frames specified by frames, cycles etc. - """ - self._api.acq() - - - @property - def busy(self): - """ - Checks the detector is acquiring. Can also be set but should only be used if the acquire fails and - leaves the detector with busy == True - - .. note :: - - Only works when the measurement is launched using acquire, not with status start! - - Returns - -------- - bool - :py:obj:`True` if the detector is acquiring otherwise :py:obj:`False` - - Examples - ---------- - - :: - - d.busy - >> True - - #If the detector is stuck reset by: - d.busy = False - - - """ - return self._api.getAcquiringFlag() - - @busy.setter - def busy(self, value): - self._api.setAcquiringFlag(value) - - - @property - def client_version(self): - """ - :py:obj:`str` The date of commit for the client API version - - Examples - ---------- - - :: - - d.client_version - >> '20180327' - - """ - v = hex(self._api.getClientVersion()) - return v[2:] - - @property - def detectornumber(self): - """ - Get all detector numbers as a list. For Eiger the detector numbers - correspond to the beb numbers. - - Examples - --------- - - :: - - #for beb083 and beb098 - detector.detector_number - >> [83, 98] - - """ - return self._api.getDetectorNumber() - - @property - def detector_type(self): - """ - Return either a string or list of strings with the detector type. - - * Eiger - * Jungfrau - * etc. - - Examples - ---------- - - :: - - detector.detector_type - >> 'Eiger' - - detector.detector_type - >> ['Eiger', 'Jungfrau'] - - """ - return element_if_equal(self._api.getDetectorType()) - - @property - def dynamic_range(self): - """ - :obj:`int`: Dynamic range of the detector. - - +----+-------------+------------------------------+ - | dr | max counts | comments | - +====+=============+==============================+ - | 4 | 15 | | - +----+-------------+------------------------------+ - | 8 | 255 | | - +----+-------------+------------------------------+ - |16 | 4095 | 12 bit internally | - +----+-------------+------------------------------+ - |32 | 4294967295 | Autosumming of 12 bit frames | - +----+-------------+------------------------------+ - - Raises - ------- - ValueError - If the dynamic range is not available in the detector - - - """ - return self._api.getDynamicRange() - - @dynamic_range.setter - def dynamic_range(self, dr): - if dr in self._detector_dynamic_range: - self._api.setDynamicRange(dr) - return - else: - raise DetectorValueError('Cannot set dynamic range to: {:d} availble options: '.format(dr), - self._detector_dynamic_range) - - - @property - def exposure_time(self): - """ - :obj:`double` Exposure time in [s] of a single frame. - """ - return self._api.getExposureTime() / 1e9 - - @exposure_time.setter - def exposure_time(self, t): - ns_time = int(t * 1e9) - if ns_time <= 0: - raise DetectorValueError('Exposure time must be larger than 0') - self._api.setExposureTime(ns_time) - - @property - def file_index(self): - """ - :obj:`int` Index for frames and file names - - Raises - ------- - ValueError - If the user tries to set an index less than zero - - Examples - --------- - - :: - - detector.file_index - >> 0 - - detector.file_index = 10 - detector.file_index - >> 10 - - """ - return self._api.getFileIndex() - - @file_index.setter - def file_index(self, i): - if i < 0: - raise ValueError('Index needs to be positive') - self._api.setFileIndex(i) - - @property - def file_name(self): - """ - :obj:`str`: Base file name for writing images - - Examples - --------- - - :: - - detector.file_name - >> 'run' - - detector.file_name = 'myrun' - - #For a single acquisition the detector now writes - # myrun_master_0.raw - # myrun_d0_0.raw - # myrun_d1_0.raw - # myrun_d2_0.raw - # myrun_d3_0.raw - - """ - return self._api.getFileName() - - @file_name.setter - def file_name(self, fname): - self._api.setFileName(fname) - - @property - def file_path(self): - """ - :obj:`str`: Path where images are written - - Raises - ------- - FileNotFoundError - If path does not exists - - Examples - --------- - - :: - - detector.file_path - >> '/path/to/files' - - detector.file_path = '/new/path/to/other/files' - - """ - fp = self._api.getFilePath() - if fp == '': - return [self._api.getFilePath(i) for i in range(len(self))] - else: - return fp - - @file_path.setter - def file_path(self, path): - if os.path.exists(path) is True: - self._api.setFilePath(path) - else: - raise FileNotFoundError('File path does not exists') - - @property - def file_write(self): - """ - :obj:`bool` If True write files to disk - """ - return self._api.getFileWrite() - - @file_write.setter - def file_write(self, fwrite): - self._api.setFileWrite(fwrite) - - - @property - def file_overwrite(self): - """ - :obj:`bool` If true overwrite files on disk - """ - return self._api.getFileOverWrite() - - @file_overwrite.setter - def file_overwrite(self, value): - self._api.setFileOverWrite(value) - - @property - def file_padding(self): - """ - Pad files in the receiver - :obj:`bool` If true pads partial frames - """ - return self._api.getReceiverPartialFramesPadding() - - @file_padding.setter - def file_padding(self, value): - self._api.getReceiverPartialFramesPadding(value) - - @property - def firmware_version(self): - """ - :py:obj:`int` Firmware version of the detector - """ - return self._api.getFirmwareVersion() - - # @property - # def flags(self): - # """Read and set flags. Accepts both single flag as - # string or list of flags. - - # Raises - # -------- - # RuntimeError - # If flag not recognized - - - # Examples - # ---------- - - # :: - - # #Eiger - # detector.flags - # >> ['storeinram', 'parallel'] - - # detector.flags = 'nonparallel' - # detector.flags - # >> ['storeinram', 'nonparallel'] - - # detector.flags = ['continous', 'parallel'] - - - # """ - # return self._api.getReadoutFlags() - - # @flags.setter - # def flags(self, flags): - # if isinstance(flags, str): - # self._api.setReadoutFlag(flags) - # elif isinstance(flags, Iterable): - # for f in flags: - # self._api.setReadoutFlag(f) - - @property - def frames_caught(self): - """ - Number of frames caught by the receiver. Can be used to check for - package loss. - """ - return self._api.getFramesCaughtByReceiver() - - - @property - def frame_discard_policy(self): - """ - Decides what the receiver does when packet loss occurs. - nodiscard - keep all frames - discardempty - discard only empty frames - discardpartial - discard partial and empty frames - """ - return self._api.getReceiverFrameDiscardPolicy() - - @frame_discard_policy.setter - def frame_discard_policy(self, policy): - self._api.setReceiverFramesDiscardPolicy(policy) - - - @property - def api_compatibility(self): - Compatibility = namedtuple('Compatibility', ['client_detector', 'client_receiver']) - c = Compatibility(self._api.isClientAndDetectorCompatible(), self._api.isClientAndReceiverCompatible()) - return c - - @property - def frame_padding(self): - """ - Padd partial frames in the receiver - """ - return self._api.getPartialFramesPadding() - - @frame_padding.setter - def frame_padding(self, padding): - self._api.setPartialFramesPadding(padding) - - def free_shared_memory(self): - """ - Free the shared memory that contains the detector settings - and reinitialized with 0 detectors so that you can keep - using the same object. - - """ - self._api.freeSharedMemory() - self.__init__(self._api.getMultiDetectorId()) - - @property - def flipped_data_x(self): - """Flips data on x axis. Set for eiger bottom modules""" - return self._flippeddatax - - - @property - def high_voltage(self): - """ - High voltage applied to the sensor - """ - return self._api.getDac('vhighvoltage', -1) - - @high_voltage.setter - def high_voltage(self, voltage): - voltage = int(voltage) - if voltage < 0 or voltage > 200: - raise DetectorValueError('High voltage {:d}V is out of range. Should be between 0-200V'.format(voltage)) - self._api.setDac('vhighvoltage', -1, voltage) - - - @property - def hostname(self): - """ - :obj:`list` of :obj:`str`: hostnames of all connected detectors - - Examples - --------- - - :: - - detector.hostname - >> ['beb059', 'beb058'] - - """ - _hm = self._api.getHostname() - if _hm == '': - return [] - return _hm.strip('+').split('+') - - - @hostname.setter - def hostname(self, hn): - if isinstance(hn, str): - self._api.setHostname(hn) - else: - name = ''.join([''.join((h, '+')) for h in hn]) - self._api.setHostname(name) - - @property - def image_size(self): - """ - :py:obj:`collections.namedtuple` with the image size of the detector - Also works setting using a normal tuple - - .. note :: - - Follows the normal convention in Python of (rows, cols) - - Examples - ---------- - - :: - - d.image_size = (512, 1024) - - d.image_size - >> ImageSize(rows=512, cols=1024) - - d.image_size.rows - >> 512 - - d.image_size.cols - >> 1024 - - """ - size = namedtuple('ImageSize', ['rows', 'cols']) - return size(*self._api.getImageSize()) - - @image_size.setter - def image_size(self, size): - self._api.setImageSize(*size) - - - def load_config(self, fname): - """ - Load detector configuration from a configuration file - - Raises - -------- - FileNotFoundError - If the file does not exists - - """ - if os.path.isfile(fname): - self._api.readConfigurationFile(fname) - else: - raise FileNotFoundError('Cannot find configuration file') - - - def load_parameters(self, fname): - """ - Setup detector by executing commands in a parameters file - - - .. note :: - - If you are relying mainly on the Python API it is probably - better to track the settings from Python. This function uses - parameters stored in a text file and the command line commands. - - Raises - -------- - FileNotFoundError - If the file does not exists - - """ - if os.path.isfile(fname): - self._api.readParametersFile(fname) - else: - raise FileNotFoundError('Cannot find parameters file') - - - def load_trimbits(self, fname, idet=-1): - """ - Load trimbit file or files. Either called with detector number or -1 - to try to load detector specific trimbit files - - Parameters - ----------- - fname: - :py:obj:`str` Filename (including path) to the trimbit files - - idet - :py:obj:`int` Detector to load trimbits to, -1 for all - - - :: - - #Assuming 500k consisting of beb049 and beb048 - # 0 is beb049 - # 1 is beb048 - - #Load name.sn049 to beb049 and name.sn048 to beb048 - detector.load_trimbits('/path/to/dir/name') - - #Load one file to a specific detector - detector.load_trimbits('/path/to/dir/name.sn049', 0) - - """ - self._api.loadTrimbitFile(fname, idet) - - - @property - def lock(self): - """Lock the detector to this client - - :: - - detector.lock = True - - """ - return self._api.getServerLock() - - @lock.setter - def lock(self, value): - self._api.setServerLock(value) - - @property - def lock_receiver(self): - """Lock the receivers to this client - - :: - - detector.lock_receiver = True - - """ - - return self._api.getReceiverLock() - - @lock_receiver.setter - def lock_receiver(self, value): - self._api.setReceiverLock(value) - - @property - def module_geometry(self): - """ - :obj:`namedtuple` Geometry(horizontal=nx, vertical=ny) - of the detector modules. - - Examples - --------- - - :: - - detector.module_geometry - >> Geometry(horizontal=1, vertical=2) - - detector.module_geometry.vertical - >> 2 - - detector.module_geometry[0] - >> 1 - - """ - _t = self._api.getDetectorGeometry() - Geometry = namedtuple('Geometry', ['horizontal', 'vertical']) - return Geometry(horizontal=_t[0], vertical=_t[1]) - - @property - def n_frames(self): - """ - :obj:`int` Number of frames per acquisition - """ - return self._api.getNumberOfFrames() - - @n_frames.setter - def n_frames(self, n): - if n >= 1: - self._api.setNumberOfFrames(n) - else: - raise DetectorValueError('Invalid value for n_frames: {:d}. Number of'\ - ' frames should be an integer greater than 0'.format(n)) - - @property - def frames_per_file(self): - return self._api.getFramesPerFile() - - @frames_per_file.setter - def frames_per_file(self, n): - self._api.setFramesPerFile(n) - - @property - def n_cycles(self): - """Number of cycles for the measurement (exp*n_frames)*n_cycles""" - return self._api.getCycles() - - @n_cycles.setter - def n_cycles(self, n_cycles): - if n_cycles > 0: - self._api.setCycles(n_cycles) - else: - raise DetectorValueError('Number of cycles must be positive') - - @property - def n_measurements(self): - """ - Number of times to repeat the programmed measurement. - This is the outer most part. Real time operation is not - guaranteed since this is software controlled. - - Examples - ---------- - - :: - - detector.n_frames = 1 - detector.n_cycles = 1 - detector.n_measurements = 3 - - detector.acq() # 1 frame 3 times - - detector.n_frames = 5 - detector.n_cycles = 3 - detector.n_measurements = 2 - - detector.acq() # 5x3 frames 2 times total 30 frames - - """ - return self._api.getNumberOfMeasurements() - - @n_measurements.setter - def n_measurements(self, value): - if value > 0: - self._api.setNumberOfMeasurements(value) - else: - raise DetectorValueError('Number of measurements must be positive') - - @property - def n_modules(self): - """ - :obj:`int` Number of (half)modules in the detector - - Examples - --------- - - :: - - detector.n_modules - >> 2 - - """ - return self._api.getNumberOfDetectors() - - - @property - def last_client_ip(self): - """Returns the ip address of the last client - that accessed the detector - - Returns - ------- - - :obj:`str` last client ip - - Examples - ---------- - - :: - - detector.last_client_ip - >> '129.129.202.117' - - """ - return self._api.getLastClientIP() - - @property - def receiver_last_client_ip(self): - """Returns the ip of the client last talking to the receiver""" - return self._api.getReceiverLastClientIP() - - @property - def receiver_online(self): - """ - Online flag for the receiver. Is set together with detector.online when creating the detector object - - Examples - --------- - - :: - - d.receiver_online - >> True - - d.receiver_online = False - - """ - return self._api.getReceiverOnline() - - - @property - def receiver_version(self): - """ - :py:obj:`str` Receiver version as a string. [yearmonthday] - - Examples - ---------- - - :: - - d.receiver_version - >> '20180327' - - """ - v = hex(self._api.getReceiverVersion()) - return v[2:] - - #When returning instance error hadling needs to be done in the - #class that is returned - @property - def register(self): - """Directly manipulate registers on the readout board - - Examples - --------- - - :: - - d.register[0x5d] = 0xf00 - - """ - return self._register - - def reset_frames_caught(self): - """ - Reset the number of frames caught by the receiver. - - .. note :: - - Automatically done when using d.acq() - - """ - self._api.resetFramesCaught() - - @property - def period(self): - """ - :obj:`double` Period between start of frames. Set to 0 for the detector - to choose the shortest possible - """ - _t = self._api.getPeriod() - return _t / 1e9 - - @period.setter - def period(self, t): - ns_time = int(t * 1e9) - if ns_time < 0: - raise ValueError('Period must be 0 or larger') - self._api.setPeriod(ns_time) - - @property - def rate_correction(self): - """ - :obj:`list` of :obj:`double` Rate correction for all modules. - Set to 0 for **disabled** - - .. todo :: - - Should support individual assignments - - Raises - ------- - ValueError - If the passed list is not of the same length as the number of - detectors - - Examples - --------- - - :: - - detector.rate_correction - >> [125.0, 155.0] - - detector.rate_correction = [125, 155] - - - """ - return self._api.getRateCorrection() - - @rate_correction.setter - def rate_correction(self, tau_list): - if len(tau_list) != self.n_modules: - raise ValueError('List of tau needs the same length') - self._api.setRateCorrection(tau_list) - - - @property - def readout_clock(self): - """ - Speed of the readout clock relative to the full speed - - * Full Speed - * Half Speed - * Quarter Speed - * Super Slow Speed - - Examples - --------- - - :: - - d.readout_clock - >> 'Half Speed' - - d.readout_clock = 'Full Speed' - - - """ - speed = self._api.getReadoutClockSpeed() - return self._speed_names[speed] - - @readout_clock.setter - def readout_clock(self, value): - speed = self._speed_int[value] - self._api.setReadoutClockSpeed(speed) - - @property - def receiver_frame_index(self): - return self._api.getReceiverCurrentFrameIndex() - - @property - def rx_datastream(self): - """ - Zmq datastream from receiver. :py:obj:`True` if enabled and :py:obj:`False` - otherwise - - :: - - #Enable data streaming from receiver - detector.rx_datastream = True - - #Check data streaming - detector.rx_datastream - >> True - - """ - return self._api.getRxDataStreamStatus() - - @rx_datastream.setter - def rx_datastream(self, status): - self._api.setRxDataStreamStatus(status) - - - @property - def rx_hostname(self): - """ - Receiver hostname - TODO! setting of individual hostnames, now done with API call - """ - return self._api.getReceiverHostname() - - - @rx_hostname.setter - def rx_hostname(self, name): - self._api.setReceiverHostname(name) - - - @property - def rx_udpip(self): - """ - Receiver UDP ip - """ - return self._api.getReceiverUDPIP(-1) - - - @rx_udpip.setter - def rx_udpip(self, ip): - if isinstance(ip, list): - for i, addr in enumerate(ip): - self._api.setReceiverUDPIP(addr, i) - else: - self._api.setReceiverUDPIP(ip, -1) - - - @property - def rx_udpmac(self): - return self._api.getReceiverUDPMAC(-1) - - @rx_udpmac.setter - def rx_udpmac(self, mac): - if isinstance(mac, list): - for i, m in enumerate(mac): - self._api.setReceiverUDPMAC(m, i) - else: - self._api.setReceiverUDPMAC(mac, -1) - - @property - def rx_tcpport(self): - return self._api.getReceiverPort() - - @rx_tcpport.setter - def rx_tcpport(self, ports): - if len(ports) != len(self): - raise ValueError('Number of ports: {} not equal to number of ' - 'detectors: {}'.format(len(ports), len(self))) - else: - for i, p in enumerate(ports): - self._api.setReceiverPort(i, p) - - @property - def rx_zmqip(self): - """ - ip where the receiver streams data - """ - ip = self._api.getNetworkParameter('rx_zmqip') - return element_if_equal(ip) - - @rx_zmqip.setter - def rx_zmqip(self, ip): - self._api.setNetworkParameter('rx_zmqip', ip, -1) - - - - @property - def syncclk(self): - return self._api.getSyncClkSpeed(-1) - - @property - def detectormac(self): - """ - Read detector mac address - """ - mac = self._api.getNetworkParameter('detectormac') - return element_if_equal(mac) - - @property - def detectorip(self): - """ - Read detector ip address - """ - return self._api.getDetectorIp(-1) - - - # @detectorip.setter - # def detectorip(self, ip): - - - @property - def client_zmqip(self): - """ - Ip address where the client listens to zmq stream - """ - ip = self._api.getNetworkParameter('client_zmqip') - return element_if_equal(ip) - - @client_zmqip.setter - - def client_zmqip(self, ip): - self._api.setNetworkParameter('client_zmqip', ip, -1) - - - - @property - def rx_fifodepth(self): - """ - Fifo depth of receiver in number of frames - """ - return self._api.getReceiverFifoDepth() - - @rx_fifodepth.setter - def rx_fifodepth(self, n_frames): - self._api.setReceiverFifoDepth(n_frames) - - - @property - def rx_udpsocksize(self): - """ - UDP buffer size - """ - buffer_size = [int(s) for s in self._api.getNetworkParameter('rx_udpsocksize')] - return element_if_equal(buffer_size) - - @property - def rx_jsonaddheader(self): - """ - UDP buffer size - """ - header = self._api.getNetworkParameter('rx_jsonaddheader') - return element_if_equal(header) - - @rx_jsonaddheader.setter - def rx_jsonaddheader(self, header): - self._api.setNetworkParameter('rx_jsonaddheader', header, -1) - - - - @rx_udpsocksize.setter - def rx_udpsocksize(self, buffer_size): - self._api.setNetworkParameter('rx_udpsocksize', str(buffer_size), -1) - - - @property - def rx_realudpsocksize(self): - """ - UDP buffer size - """ - buffer_size = [int(s) for s in self._api.getNetworkParameter('rx_realudpsocksize')] - return element_if_equal(buffer_size) - - - @property - def rx_zmqport(self): - """ - Return the receiver zmq ports. - - :: - - detector.rx_zmqport - >> [30001, 30002] - - """ - _s = self._api.getNetworkParameter('rx_zmqport') - if _s == '': - return [] - else: - return [int(_p) for _p in _s] - - @rx_zmqport.setter - def rx_zmqport(self, port): - if isinstance(port, Iterable): - for i, p in enumerate(port): - self._api.setNetworkParameter('rx_zmqport', str(p), i) - else: - self._api.setNetworkParameter('rx_zmqport', str(port), -1) - -# Add back when versioning is defined -# @property -# def software_version(self): -# return self._api.getSoftwareVersion(); - - - @property - def user(self): - return self._api.getUserDetails() - - @property - def server_version(self): - """ - :py:obj:`int` On-board server version of the detector - """ - return hex(self._api.getServerVersion()) - - @property - def settings(self): - """ - Detector settings used to control for example calibration or gain - switching. For EIGER almost always standard standard. - - .. warning :: - - For Eiger setting settings should be followed by setting the threshold - otherwise reading of the settings will overwrite the set value - - - """ - return self._api.getSettings() - - @settings.setter - def settings(self, s): - if s in self._settings: - self._api.setSettings(s) - else: - raise DetectorValueError('Settings: {:s}, not defined for {:s}. ' - 'Valid options are: [{:s}]'.format(s, self.detector_type, ', '.join(self._settings))) - - - @property - def settings_path(self): - """ - The path where the slsDetectorSoftware looks for settings/trimbit files - """ - return self._api.getSettingsDir() - - @settings_path.setter - def settings_path(self, path): - if os.path.isdir(path): - self._api.setSettingsDir(path) - else: - raise FileNotFoundError('Settings path does not exist') - - @property - def status(self): - """ - :py:obj:`str` Status of the detector: idle, running, - - .. todo :: - - Check possible values - - """ - return self._api.getRunStatus() - - def start_detector(self): - """ - Non blocking command to star acquisition. Needs to be used in combination - with receiver start. - """ - self._api.startAcquisition() - - def stop_detector(self): - """ - Stop acquisition early or if the detector hangs - """ - self._api.stopAcquisition() - - - def start_receiver(self): - self._api.startReceiver() - - def stop_receiver(self): - self._api.stopReceiver() - - @property - def threaded(self): - """ - Enable parallel execution of commands to the different detector modules - - Examples - ---------- - - :: - - d.threaded - >> True - - d.threaded = False - - """ - return self._api.getThreadedProcessing() - - @threaded.setter - def threaded(self, value): - self._api.setThreadedProcessing(value) - - @property - def threshold(self): - """ - Detector threshold in eV - """ - return self._api.getThresholdEnergy() - - @threshold.setter - def threshold(self, eV): - self._api.setThresholdEnergy(eV) - - @property - def timing_mode(self): - """ - :py:obj:`str` Timing mode of the detector - - * **auto** Something - * **trigger** Something else - - - """ - return self._api.getTimingMode() - - @timing_mode.setter - def timing_mode(self, mode): - self._api.setTimingMode(mode) - - - @property - def trimmed_energies(self): - """ - EIGER: the energies at which the detector was trimmed. This also sets - the range for which the calibration of the detector is valid. - - - :: - - detector.trimmed_energies = [5400, 6400, 8000] - - detector.trimmed_energies - >> [5400, 6400, 8000] - - """ - - return self._api.getTrimEnergies() - - @trimmed_energies.setter - def trimmed_energies(self, energy_list): - self._api.setTrimEnergies(energy_list) - - @property - def vthreshold(self): - """ - Threshold in DAC units for the detector. Sets the individual vcmp of - all chips in the detector. - """ - return self._api.getDac('vthreshold', -1) - - @vthreshold.setter - def vthreshold(self, th): - self._api.setDac('vthreshold', -1, th) - - @property - def trimbits(self): - """ - Set or read trimbits of the detector. - - Examples - --------- - - :: - - #Set all to 32 - d.trimbits = 32 - - d.trimbits - >> 32 - - #if undefined or different - d.trimbits - >> -1 - - """ - return self._api.getAllTrimbits() - - @trimbits.setter - def trimbits(self, value): - if self._trimbit_limits.min <= value <= self._trimbit_limits.max: - self._api.setAllTrimbits(value) - else: - raise DetectorValueError('Trimbit setting {:d} is outside of range:'\ - '{:d}-{:d}'.format(value, self._trimbit_limits.min, self._trimbit_limits.max)) - - @property - def client_zmqport(self): - """zmq port of the client""" - _s = self._api.getNetworkParameter('client_zmqport') - if _s == '': - return [] - return [int(_p)+i for _p in _s for i in range(2)] - - - def _provoke_error(self): - self._api.setErrorMask(1) - - - def config_network(self): - """ - Configures the detector source and destination MAC addresses, IP addresses - and UDP ports, and computes the IP header checksum for such parameters - """ - self._api.configureNetworkParameters() - - - #TODO! can we make this one function? - @property - def patnloop0(self): - return self._api.getPatternLoops(0, -1)[2] - - @patnloop0.setter - def patnloop0(self, n): - self._api.setPatternLoops(0, -1, -1, n, -1) - - @property - def patnloop1(self): - return self._api.getPatternLoops(1, -1)[2] - - @patnloop1.setter - def patnloop1(self, n): - self._api.setPatternLoops(1, -1, -1, n, -1) - - @property - def patnloop2(self): - return self._api.getPatternLoops(2, -1)[2] - - @patnloop2.setter - def patnloop2(self, n): - self._api.setPatternLoops(2, -1, -1, n, -1) - - @property - def patloop0(self): - return self._api.getPatternLoops(0)[0:2] - - @patloop0.setter - def patloop0(self, value): - start, stop = value - self._api.setPatternLoops(0, start, stop, -1) - - @property - def patloop1(self): - return self._api.getPatternLoops(1)[0:2] - - @patloop1.setter - def patloop1(self, value): - start, stop = value - self._api.setPatternLoops(1, start, stop, -1) - - @property - def patloop2(self): - return self._api.getPatternLoops(2)[0:2] - - @patloop2.setter - def patloop2(self, value): - start, stop = value - self._api.setPatternLoops(2, start, stop, -1) - - def setPatternWord(self, addr, word, det_id = -1): - self._api.setPatternWord(addr, word, det_id) - - def setPatternLoops(self, level, start, stop, n, det_id=-1): - self._api.setPatternLoops(level, start, stop, n, det_id) - - def getPatternLoops(self, level): - return self._api.getPatternLoops(level) - - def getPatternWaitAddr(self, level): - return self._api.getPatternWaitAddr(level) - - def setPatternWaitAddr(self, level, addr): - self._api.setPatternWaitAddr(level, addr) - - @property - def patwait0(self): - return self._api.getPatternWaitAddr(0) - - @patwait0.setter - def patwait0(self, addr): - self._api.setPatternWaitAddr(0, addr) - - @property - def patwait1(self): - return self._api.getPatternWaitAddr(1) - - @patwait1.setter - def patwait1(self, addr): - self._api.setPatternWaitAddr(1, addr) - - @property - def patwait2(self): - return self._api.getPatternWaitAddr(0) - - @patwait2.setter - def patwait2(self, addr): - self._api.setPatternWaitAddr(2, addr) - - - def setPatternWaitTime(self, level, duration): - self._api.setPatternWaitTime(level, duration) - - def getPatternWaitTime(self, level): - return self._api.getPatternWaitTime(level) - - @property - def patwaittime0(self): - return self._api.getPatternWaitTime(0) - - @patwaittime0.setter - def patwaittime0(self, duration): - self._api.setPatternWaitTime(0, duration) - - @property - def patwaittime1(self): - return self._api.getPatternWaitTime(1) - - @patwaittime1.setter - def patwaittime1(self, duration): - self._api.setPatternWaitTime(1, duration) - - @property - def patwaittime2(self): - return self._api.getPatternWaitTime(2) - - @patwaittime2.setter - def patwaittime2(self, duration): - self._api.setPatternWaitTime(2, duration) - - @property - def patioctrl(self): - return self._api.setPatternIOControl(np.uint64(-1)) - - @patioctrl.setter - def patioctrl(self, word): - self._api.setPatternIOControl(np.uint64(word)) - - @property - def patlimits(self): - return self._api.getPatternLoops(-1,-1)[0:2] - - @patlimits.setter - def patlimits(self, value): - start, stop = value - self._api.setPatternLoops(-1, start, stop, -1) - - @property - def patword(self): - print('Can\'t read') - - @patword.setter - def patword(self, value): - addr, word = value - self._api.setPatternWord(addr, word) - - @property - def patclkctrl(self): - return self._api.setPatternClockControl(np.uint64(-1)) - - @patclkctrl.setter - def patclkctrl(self, value): - self._api.setPatternClockControl(value) - - -def free_shared_memory(multi_id=0): - """ - Function to free the shared memory but do not initialize with new - 0 size detector - """ - api = DetectorApi(multi_id) - api.freeSharedMemory() diff --git a/python/sls_detector/experimental.py b/python/sls_detector/experimental.py index 6fd26352e..368067361 100755 --- a/python/sls_detector/experimental.py +++ b/python/sls_detector/experimental.py @@ -54,7 +54,7 @@ def freeze(cls): @freeze -class ExperimentalDetector(CppDetectorApi): +class Detector(CppDetectorApi): """ This class is the base for detector specific interfaces. Most functions exists in two versions @@ -425,54 +425,88 @@ class ExperimentalDetector(CppDetectorApi): def zmqip(self, ip): self.setClientZmqIp(ip) - #TODO! Change to dst + @property - def rx_udpip(self): + def udp_dstip(self): return element_if_equal(self.getDestinationUDPIP()) - @rx_udpip.setter - def rx_udpip(self, ip): + @udp_dstip.setter + def udp_dstip(self, ip): self.getDestinationUDPIP(ip) + @property - def rx_udpip2(self): + def udp_dstip2(self): return element_if_equal(self.getDestinationUDPIP2()) - @rx_udpip2.setter - def rx_udpip2(self, ip): + @udp_dstip2.setter + def udp_dstip2(self, ip): self.getDestinationUDPIP2(ip) @property - def rx_udpmac(self): + def udp_dstmac(self): return element_if_equal(self.getDestinationUDPMAC()) - @rx_udpmac.setter - def rx_udpmac(self, mac): + @udp_dstmac.setter + def udp_dstmac(self, mac): self.getDestinationUDPMAC2(mac) @property - def rx_udpmac2(self): + def udp_dstmac2(self): return element_if_equal(self.getDestinationUDPMAC2()) - @rx_udpmac2.setter - def rx_udpmac2(self, mac): + @udp_dstmac2.setter + def udp_dstmac2(self, mac): self.getDestinationUDPMAC2(mac) @property - def detectormac(self): - return element_if_equal(self.getSourceUDPMAC()) + def udp_dstport(self): + return element_if_equal(self.getDestinationUDPPort()) - @detectormac.setter - def detectormac(self, mac): - self.setSourceUDPMAC() + @udp_dstport.setter + def udp_dstport(self, port): + self.setDestinationUDPPort(port) @property - def detectormac2(self): + def udp_dstport2(self): + return element_if_equal(self.getDestinationUDPPort2()) + + @udp_dstport2.setter + def udp_dstport2(self, port): + self.setDestinationUDPPort2(port) + + @property + def src_udpmac(self): + return element_if_equal(self.getSourceUDPMAC()) + + @src_udpmac.setter + def src_udpmac(self, mac): + self.setSourceUDPMAC(mac) + + @property + def src_udpip2(self): + return element_if_equal(self.getSourceUDPIP()) + + @src_udpip2.setter + def src_udpip2(self, ip): + self.setSourceUDPIP(ip) + + @property + def src_udpip(self): + return element_if_equal(self.getSourceUDPIP()) + + @src_udpip.setter + def src_udpip(self, ip): + self.setSourceUDPIP(ip) + + + @property + def src_udpmac2(self): return element_if_equal(self.getSourceUDPMAC2()) - @detectormac2.setter - def detectormac2(self, mac): - self.setSourceUDPMAC2() + @src_udpmac2.setter + def src_udpmac2(self, mac): + self.setSourceUDPMAC2(mac) @property def vhighvoltage(self): @@ -487,12 +521,12 @@ class ExperimentalDetector(CppDetectorApi): return self.getUserDetails() @property - def settingsdir(self): - return element_if_equal(self.getSettingsDir()) + def settingspath(self): + return element_if_equal(self.getSettingsPath()) - @settingsdir.setter - def settingsdir(self, dir): - self.setSettingsDir(dir) + @settingspath.setter + def settingspath(self, path): + self.setSettingsPath(path) @property def status(self): diff --git a/python/sls_detector/jungfrau.py b/python/sls_detector/jungfrau.py deleted file mode 100755 index 0526e9270..000000000 --- a/python/sls_detector/jungfrau.py +++ /dev/null @@ -1,259 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -""" -Jungfrau detector class and support functions. -Inherits from Detector. -""" -from .adcs import Adc, DetectorAdcs -from .detector import Detector -from .dacs import DetectorDacs -from .utils import element_if_equal - - -class JungfrauDacs(DetectorDacs): - _dacs = [('vb_comp', 0, 4000, 1220), - ('vdd_prot', 0, 4000, 3000), - ('vin_com', 0, 4000, 1053), - ('vref_prech', 0, 4000, 1450), - ('vb_pixbuff', 0, 4000, 750), - ('vb_ds', 0, 4000, 1000), - ('vref_ds', 0, 4000, 480), - ('vref_comp', 0, 4000, 420), - ] - _dacnames = [_d[0] for _d in _dacs] - -class Jungfrau(Detector): - """ - Class used to control a Jungfrau detector. Inherits from the Detector class but a specialized - class is needed to provide the correct dacs and unique functions. - - """ - _detector_dynamic_range = [4, 8, 16, 32] - - _settings = ['dynamichg0', - 'dynamicgain', - 'fixgain1', - 'fixgain2', - 'forceswitchg1', - 'forceswitchg2'] - """Available settings for Jungfrau""" - - def __init__(self, multi_id=0): - #Init on base calss - super().__init__(multi_id) - self._dacs = JungfrauDacs(self) - - #Jungfrau specific temps, this can be reduced to a single value? - self._temp = DetectorAdcs() - self._temp.fpga = Adc('temp_fpga', self) - # self._register = Register(self) - - - @property - def dacs(self): - """ - - An instance of DetectorDacs used for accessing the dacs of a single - or multi detector. - - Examples - --------- - - :: - - #Jungfrau - - - """ - return self._dacs - - @property - def power_chip(self): - """Power on or off the ASICs, True for on False for off""" - return self._api.isChipPowered() - - @power_chip.setter - def power_chip(self, value): - self._api.powerChip(value) - - @property - def delay(self): - """Delay after trigger [s]""" - return self._api.getDelay()/1e9 - - @delay.setter - def delay(self, t): - ns_time = int(t * 1e9) - self._api.setDelay(ns_time) - - @property - def n_gates(self): - return self._api.getNumberOfGates() - - @n_gates.setter - def n_gates(self, n): - self._api.setNumberOfGates(n) - - @property - def n_probes(self): - return self._api.getNumberOfProbes() - - @n_probes.setter - def n_probes(self, n): - self._api.setNumberOfProbes(n) - - @property - def storagecell_start(self): - """ - First storage cell - """ - return self._api.getStoragecellStart() - - @storagecell_start.setter - def storagecell_start(self, value): - self._api.setStoragecellStart(value) - - - @property - def n_storagecells(self): - """ - number of storage cells used for the measurements - """ - return self._api.getNumberOfStorageCells() - - @n_storagecells.setter - def n_storagecells(self, value): - self._api.setNumberOfStorageCells(value) - - @property - def temp(self): - """ - An instance of DetectorAdcs used to read the temperature - of different components - - Examples - ----------- - - :: - - detector.temp - >> - temp_fpga : 36.90°C, 45.60°C - - a = detector.temp.fpga[:] - a - >> [36.568, 45.542] - - - """ - return self._temp - - @property - def temperature_threshold(self): - """Threshold for switching of chips""" - return self._api.getThresholdTemperature() - - @temperature_threshold.setter - def temperature_threshold(self, t): - self._api.setThresholdTemperature(t) - - @property - def temperature_control(self): - """ - Monitor the temperature of the detector and switch off chips if temperature_threshold is - crossed - - - Examples - --------- - - :: - - #activate - detector.temperature_control = True - - #deactivate - detector.temperature_control = False - - - """ - return self._api.getTemperatureControl() - - @temperature_control.setter - def temperature_control(self, v): - self._api.setTemperatureControl(v) - - @property - def temperature_event(self): - """Have the temperature threshold been crossed? - - Returns - --------- - - :py:obj:`True` if the threshold have been crossed and temperature_control is active - otherwise :py:obj:`False` - - """ - return self._api.getTemperatureEvent() - - def reset_temperature_event(self): - """Reset the temperature_event. After reset temperature_event is False""" - self._api.resetTemperatureEvent() - - @property - def rx_udpport(self): - """ - UDP port for the receiver. Each module have one port. - Note! Eiger has two ports - - :: - - [0:rx_udpport] - - Examples - ----------- - - :: - - d.rx_udpport - >> [50010] - - d.rx_udpport = [50010] - - """ - return self._api.getNetworkParameter('rx_udpport') - - - @rx_udpport.setter - def rx_udpport(self, ports): - """Requires iterating over elements two and two for setting ports""" - for i, p in enumerate(ports): - self._api.setNetworkParameter('rx_udpport', str(p), i) - - @property - def detector_mac(self): - s = self._api.getNetworkParameter('detectormac') - return element_if_equal(s) - - - @detector_mac.setter - def detector_mac(self, mac): - if isinstance(mac, list): - for i, m in enumerate(mac): - self._api.setNetworkParameter('detectormac', m, i) - else: - self._api.setNetworkParameter('detectormac', mac, -1) - - - @property - def detector_ip(self): - s = self._api.getNetworkParameter('detectorip') - return element_if_equal(s) - - @detector_ip.setter - def detector_ip(self, ip): - if isinstance(ip, list): - for i, addr in enumerate(ip): - self._api.setNetworkParameter('detectorip', addr, i) - else: - self._api.setNetworkParameter('detectorip', ip, -1) diff --git a/python/sls_detector/jungfrau_ctb.py b/python/sls_detector/jungfrau_ctb.py deleted file mode 100755 index fae5a51f9..000000000 --- a/python/sls_detector/jungfrau_ctb.py +++ /dev/null @@ -1,178 +0,0 @@ -from functools import partial -from collections.abc import Iterable -from collections import namedtuple -import socket - -from .detector import Detector -from .utils import element_if_equal -from .adcs import DetectorAdcs, Adc -from .dacs import DetectorDacs -from .detector_property import DetectorProperty -from .registers import Register, Adc_register - -class JungfrauCTBDacs(DetectorDacs): - _dacs = [('dac0', 0, 4000, 1400), - ('dac1', 0, 4000, 1200), - ('dac2', 0, 4000, 900), - ('dac3', 0, 4000, 1050), - ('dac4', 0, 4000, 1400), - ('dac5', 0, 4000, 655), - ('dac6', 0, 4000, 2000), - ('dac7', 0, 4000, 1400), - ('dac8', 0, 4000, 850), - ('dac9', 0, 4000, 2000), - ('dac10', 0, 4000, 2294), - ('dac11', 0, 4000, 983), - ('dac12', 0, 4000, 1475), - ('dac13', 0, 4000, 1200), - ('dac14', 0, 4000, 1600), - ('dac15', 0, 4000, 1455), - ('dac16', 0, 4000, 0), - ('dac17', 0, 4000, 1000), - ] - _dacnames = [_d[0] for _d in _dacs] - - - -class JungfrauCTB(Detector): - def __init__(self, id = 0): - super().__init__(id) - self._dacs = JungfrauCTBDacs(self) - self._register = Register(self) - self._adc_register = Adc_register(self) - - @property - def v_a(self): - return self._api.getDac_mV('v_a', -1) - - @v_a.setter - def v_a(self, value): - self._api.setDac_mV('v_a', -1, value) - - @property - def v_b(self): - return self._api.getDac_mV('v_b', -1) - - @v_b.setter - def v_b(self, value): - self._api.setDac_mV('v_b', -1, value) - - - @property - def v_c(self): - return self._api.getDac_mV('v_c', -1) - - @v_c.setter - def v_c(self, value): - self._api.setDac_mV('v_c', -1, value) - - @property - def v_d(self): - return self._api.getDac_mV('v_d', -1) - - @v_d.setter - def v_d(self, value): - self._api.setDac_mV('v_d', -1, value) - - @property - def v_io(self): - return self._api.getDac_mV('v_io', -1) - - @v_io.setter - def v_io(self, value): - self._api.setDac_mV('v_io', -1, value) - - @property - def v_limit(self): - return self._api.getDac_mV('v_limit', -1) - - @v_limit.setter - def v_limit(self, value): - self._api.setDac_mV('v_limit', -1, value) - - @property - def adc_register(self): - return self._adc_register - - # @property - # def register(self): - # return self._register - - def adcOFF(self): - """Switch off the ADC""" - self.adc_register[0x8] = 1 - - - - @property - def dacs(self): - """ - - An instance of DetectorDacs used for accessing the dacs of a single - or multi detector. - - Examples - --------- - - :: - - #JungfrauCTB - - - """ - return self._dacs - - @property - def dbitpipeline(self): - return self._api.getDbitPipeline() - - @dbitpipeline.setter - def dbitpipeline(self, value): - self._api.setDbitPipeline(value) - - - @property - def dbitphase(self): - return self._api.getDbitPhase() - - @dbitphase.setter - def dbitphase(self, value): - self._api.setDbitPhase(value) - - @property - def dbitclock(self): - return self._api.getDbitClock() - - @dbitclock.setter - def dbitclock(self, value): - self._api.setDbitClock(value) - - @property - def samples(self): - return self._api.getJCTBSamples() - - @samples.setter - def samples(self, value): - self._api.setJCTBSamples(value) - - @property - def readout_clock(self): - """ - Speed of the readout clock relative to the full speed - - - Examples - --------- - - :: - - - - - """ - return self._api.getReadoutClockSpeed() - - - @readout_clock.setter - def readout_clock(self, value): - self._api.setReadoutClockSpeed(value) diff --git a/python/src/DetectorPythonInterface.h b/python/src/DetectorPythonInterface.h deleted file mode 100755 index 2d6716d0b..000000000 --- a/python/src/DetectorPythonInterface.h +++ /dev/null @@ -1,992 +0,0 @@ -#ifndef DETECTOR_H -#define DETECTOR_H -#include -#include -#include -#include -#include -#include - -#include "multiSlsDetector.h" -#include "slsDetector.h" -#include "sls_detector_defs.h" - -class DetectorPythonInterface { - public: - DetectorPythonInterface(int i) : det(i), multi_detector_id(i) { - // Disable output from std::cout - // std::cout.setstate(std::ios_base::failbit); - } - - int getMultiDetectorId() { return multi_detector_id; } - - - - - // blocking command, acquire set number of frames - void acquire() { det.acquire(); } - - // for Eiger check status of the module - // true active false deactivated - bool getActive(int i) { return det.activate(-1, i); } - // activate or deactivate a module - void setActive(int i, bool value) { det.activate(value, i); } - - int getFramesCaughtByReceiver() { - return det.getFramesCaughtByReceiver(); - // return det.getFramesCaughtByReceiver(); - } - int getFramesCaughtByReceiver(int i) { - return det.getFramesCaughtByReceiver(i); - } - - void setReceiverFifoDepth(int n_frames) { - det.setReceiverFifoDepth(n_frames); - } - - void setNumberOfStorageCells(const int64_t num) { - det.setTimer(slsDetectorDefs::timerIndex::STORAGE_CELL_NUMBER, num); - } - int getNumberOfStorageCells() { - return det.setTimer(slsDetectorDefs::timerIndex::STORAGE_CELL_NUMBER, - -1); - } - - void setStoragecellStart(int cell) { det.setStoragecellStart(cell); } - - int getStoragecellStart() { return det.setStoragecellStart(); } - - int getReceiverFifoDepth() { return det.setReceiverFifoDepth(); } - - void resetFramesCaught() { det.resetFramesCaught(); } - - int getReceiverCurrentFrameIndex() { - return det.getReceiverCurrentFrameIndex(); - } - - std::string getReceiverHostname(int det_id = -1) const { - return det.getReceiverHostname(det_id); - } - - void setReceiverHostname(std::string hostname, int det_id = -1) { - det.setReceiverHostname(hostname, det_id); - } - - // std::string getReceiverUDPIP(int det_id = -1) const { - // return det.getReceiverUDPIP(det_id); - // } - - // void setReceiverUDPIP(std::string ip, int det_id = -1) { - // det.setReceiverUDPIP(ip, det_id); - // } - - // std::string getReceiverUDPMAC(int det_id = -1) { - // return det.getReceiverUDPMAC(det_id); - // } - - // void setReceiverUDPMAC(std::string mac, int det_id = -1) { - // det.setReceiverUDPMAC(mac, det_id); - // } - - void startReceiver() { det.startReceiver(); } - void stopReceiver() { det.stopReceiver(); } - - bool getTenGigabitEthernet() { return det.enableTenGigabitEthernet(); } - void setTenGigabitEthernet(bool value) { - det.enableTenGigabitEthernet(value); - } - - void setFileFormat(const std::string &format); - std::string getFileFormat(); - - // std::string checkOnline() { return det.checkOnline(); } - - bool isChipPowered() { return det.powerChip(); } - void powerChip(const bool value) { det.powerChip(value); } - - // read register from readout system, used for low level control - uint32_t readRegister(const uint32_t addr) { - return det.readRegister(addr); - } - - // directly write to register in readout system - void writeRegister(const uint32_t addr, const uint32_t value) { - det.writeRegister(addr, value); - } - - // directly write to the ADC register - // should this also be unsigned? Probably... - void writeAdcRegister(const int addr, const int value) { - det.writeAdcRegister(addr, value); - } - - void setBitInRegister(const uint32_t reg_addr, const int bit_number) { - det.setBit(reg_addr, bit_number); - } - void clearBitInRegister(const uint32_t reg_addr, const int bit_number) { - det.clearBit(reg_addr, bit_number); - } - - bool getAcquiringFlag() { return det.getAcquiringFlag(); } - - void setAcquiringFlag(const bool flag) { det.setAcquiringFlag(flag); } - - bool getCounterBit() { return det.setCounterBit(); } - void setCounterBit(bool b) { det.setCounterBit(b); } - - slsDetectorDefs::dacIndex dacNameToEnum(std::string dac_name); - - - - int getNumberOfDetectors() { return det.size(); } - - std::string getRunStatus() { - auto s = det.getRunStatus(); - return det.runStatusType(s); - } - - void startAcquisition() { det.startAcquisition(); } - void stopAcquisition() { det.stopAcquisition(); } - - std::string getHostname() { return det.getHostname(); } - - void setHostname(std::string hostname) { - det.setHostname(hostname.c_str()); - } - - int getDynamicRange() { return det.setDynamicRange(-1); } - void setDynamicRange(const int dr) { det.setDynamicRange(dr); } - - void pulseChip(const int n) { det.pulseChip(n); } - void pulseAllPixels(const int n); - void pulseDiagonal(const int n); - - void readConfigurationFile(std::string fname) { - det.readConfigurationFile(fname); - } - void readParametersFile(std::string fname) { - det.retrieveDetectorSetup(fname); - } - - int64_t getFirmwareVersion() { - return det.getId(slsDetectorDefs::DETECTOR_FIRMWARE_VERSION); - } - int64_t getServerVersion() { - return det.getId(slsDetectorDefs::DETECTOR_SOFTWARE_VERSION); - } - int64_t getClientVersion() { - return det.getId(slsDetectorDefs::THIS_SOFTWARE_VERSION); - } - int64_t getReceiverVersion() { - return det.getId(slsDetectorDefs::RECEIVER_VERSION); - } - - std::vector getDetectorNumber() { return det.getDetectorNumber(); } - - int getReadoutClockSpeed() { - return det.setSpeed(slsDetectorDefs::CLOCK_DIVIDER, -1); - } - void setReadoutClockSpeed(const int speed) { - det.setSpeed(slsDetectorDefs::CLOCK_DIVIDER, speed); - } - - int getSyncClkSpeed(int det_id=-1){ - return det.setSpeed(slsDetectorDefs::SYNC_CLOCK, -1, 0, det_id); - } - - void setDbitPipeline(const int value) { - det.setSpeed(slsDetectorDefs::DBIT_PIPELINE, value); - } - int getDbitPipeline() { - return det.setSpeed(slsDetectorDefs::DBIT_PIPELINE, -1); - } - void setDbitPhase(const int value) { - det.setSpeed(slsDetectorDefs::DBIT_PHASE, value); - } - int getDbitPhase() { return det.setSpeed(slsDetectorDefs::DBIT_PHASE, -1); } - void setDbitClock(const int value) { - det.setSpeed(slsDetectorDefs::DBIT_CLOCK, value); - } - int getDbitClock() { return det.setSpeed(slsDetectorDefs::DBIT_CLOCK, -1); } - - int getReceiverPort() const { return det.getReceiverPort(); } - - void setReceiverPort(int det_id, int value) { - det.setReceiverPort(value, det_id); - } - - void setRateCorrection(std::vector tau) { - for (size_t i = 0; i < det.size(); ++i) - det.setRateCorrection(tau[i], i); - } - - std::vector getRateCorrection(); - - void setPatternLoops(int level, int start, int stop, - int n, int detPos) { - det.setPatternLoops(level, start, stop, n, detPos); - } - - - std::array getPatternLoops(int level, int detPos) { - return det.getPatternLoops(level, detPos); - } - - void setPatternWord(int addr, uint64_t word, int detPos) { - det.setPatternWord(addr, word, detPos); - } - - uint64_t getPatternWord(int addr, int detPos){ - return det.setPatternWord(addr, -1, detPos); - } - - uint64_t setPatternIOControl(uint64_t word, int detPos){ - return det.setPatternIOControl(word, detPos); - } - - uint64_t setPatternClockControl(uint64_t word, int detPos){ - return det.setPatternClockControl(word, detPos); - } - - void setPatternWaitAddr(int level, int addr, int detPos){ - det.setPatternWaitAddr(level, addr, detPos); - } - - int getPatternWaitAddr(int level, int detPos){ - return det.setPatternWaitAddr(level, -1, detPos); - } - - void setPatternWaitTime(int level, uint64_t duration, int detPos){ - det.setPatternWaitTime(level, duration, detPos); - } - - uint64_t getPatternWaitTime(int level, int detPos){ - return det.setPatternWaitTime(level, -1, detPos); - } - - bool getFlippedDataX(int i) { - return det.getFlippedDataX(i); - } - - // bool getFlippedDataY(int i) { - // return det.getFlippedData(slsDetectorDefs::dimension::Y, i); - // } - - void setFlippedDataX(int i, bool value) { - det.setFlippedDataX(value, i); - } - - // void setFlippedDataY(int i, bool value) { - // det.setFlippedData(slsDetectorDefs::dimension::Y, value, i); - // } - - /*** Frame and file settings ***/ - void setFileName(std::string fname) { det.setFileName(fname); } - std::string getFileName() { return det.getFileName(); } - void setFilePath(std::string path) { det.setFilePath(path); } - void setFilePath(std::string path, int i) { det.setFilePath(path, i); } - std::string getFilePath() { return det.getFilePath(); } - std::string getFilePath(int i) { return det.getFilePath(i); } - - std::string getUserDetails() { return det.getUserDetails(); } - - void setFramesPerFile(const int n_frames) { - det.setFramesPerFile(n_frames); - } - int getFramesPerFile() { return det.setFramesPerFile(); } - - std::string getReceiverFrameDiscardPolicy() { - return det.getReceiverFrameDiscardPolicy( - det.setReceiverFramesDiscardPolicy()); - } - void setReceiverFramesDiscardPolicy(std::string f) { - auto fdp = det.getReceiverFrameDiscardPolicy(f); - if (fdp == slsDetectorDefs::GET_FRAME_DISCARD_POLICY) { - throw std::invalid_argument("Coult not decode policy: nodiscard, " - "discardempty, discardpartial"); - } - det.setReceiverFramesDiscardPolicy(fdp); - } - - void setPartialFramesPadding(bool padding) { - det.setPartialFramesPadding(padding); - } - - bool getPartialFramesPadding() { return det.getPartialFramesPadding(); } - - std::vector getMeasuredPeriod() { - std::vector mp; - for (size_t i = 0; i < det.size(); ++i) { - auto t = det.getTimeLeft(slsDetectorDefs::MEASURED_PERIOD, i); - mp.push_back(static_cast(t) * 1E-9); - } - return mp; - } - std::vector getMeasuredSubPeriod() { - std::vector mp; - for (size_t i = 0; i < det.size(); ++i) { - auto t = det.getTimeLeft(slsDetectorDefs::MEASURED_SUBPERIOD, i); - mp.push_back(static_cast(t) * 1E-9); - } - return mp; - } - - void checkDetectorVersionCompatibility() { - det.checkDetectorVersionCompatibility(); - } - void checkReceiverVersionCompatibility() { - det.checkReceiverVersionCompatibility(); - } - - /*** END Frame and file settings ***/ - - void loadTrimbitFile(std::string fname, const int idet) { - det.loadSettingsFile(fname, idet); - } - - // Eiger: set the energies where the detector is trimmed - void setTrimEnergies(std::vector energy) { det.setTrimEn(energy); } - - std::vector getTrimEnergies() { return det.getTrimEn(); } - - /*** Temperature control functions for Jungfrau ***/ - void setThresholdTemperature(float t) { - det.setThresholdTemperature(static_cast(t * 1000), -1); - } - - float getThresholdTemperature() { - return static_cast(det.setThresholdTemperature(-1, -1)) / - 1000.0; - } - - void setTemperatureControl(bool v) { det.setTemperatureControl(v); } - bool getTemperatureControl() { return det.setTemperatureControl(); } - - bool getTemperatureEvent() { return det.setTemperatureEvent(); } - void resetTemperatureEvent() { det.setTemperatureEvent(0); } - /*** END Temperature control functions for Jungfrau ***/ - - void setThresholdEnergy(const int eV) { det.setThresholdEnergy(eV); } - - std::string getSettingsDir() { return det.getSettingsDir(); } - void setSettingsDir(std::string dir) { det.setSettingsDir(dir); } - - int getThresholdEnergy() { return det.getThresholdEnergy(); } - - std::string getSettings() { - return det.getDetectorSettings(det.getSettings()); - } - - void setSettings(std::string s) { - det.setSettings(det.getDetectorSettings(s)); - } - - // name to enum translation on the c++ side - // should we instead expose the enum to Python? - int getDac(std::string dac_name, const int mod_id) { - int val = -1; - auto dac = dacNameToEnum(dac_name); - return det.setDAC(val, dac, 0, mod_id); - } - - void setDac(std::string dac_name, const int mod_id, int val) { - auto dac = dacNameToEnum(dac_name); - det.setDAC(val, dac, 0, mod_id); - } - - int getDac_mV(std::string dac_name, const int mod_id) { - int val = -1; - auto dac = dacNameToEnum(dac_name); - return det.setDAC(val, dac, 1, mod_id); - } - - void setDac_mV(std::string dac_name, const int mod_id, int value) { - auto dac = dacNameToEnum(dac_name); - det.setDAC(value, dac, 1, mod_id); - } - - // Intended for the JungfrauCTB should we name dacs instead - int getDacFromIndex(const int index, const int mod_id) { - int val = -1; - auto dac = static_cast(0); - return det.setDAC(val, dac, 0, mod_id); - } - // Intended for the JungfrauCTB should we name dacs instead - int setDacFromIndex(const int index, const int mod_id, int value) { - auto dac = static_cast(0); - return det.setDAC(value, dac, 0, mod_id); - } - - // Calling multi do we have a need to lock/unlock a single det? - bool getServerLock() { return det.lockServer(-1); } - void setServerLock(const bool value) { det.lockServer(value); } - bool getReceiverLock() { return det.lockReceiver(-1); } - void setReceiverLock(const bool value) { det.lockReceiver(value); } - - int getAdc(std::string adc_name, int mod_id) { - auto adc = dacNameToEnum(adc_name); - return det.getADC(adc, mod_id); - } - - // std::vector getReadoutFlags(); - - // // note singular - // void setReadoutFlag(const std::string flag_name); - - // name to enum transltion of dac - int getDacVthreshold() { - int val = -1; - auto dac = slsDetectorDefs::dacIndex::THRESHOLD; - return det.setDAC(val, dac, 0, -1); - } - - void setDacVthreshold(const int val) { - auto dac = slsDetectorDefs::dacIndex::THRESHOLD; - det.setDAC(val, dac, 0, -1); - } - - void setFileIndex(const int i) { det.setFileIndex(i); } - - int getFileIndex() { return det.getFileIndex(); } - - // time in ns - void setExposureTime(const int64_t t) { - det.setTimer(slsDetectorDefs::timerIndex::ACQUISITION_TIME, t); - } - - // time in ns - int64_t getExposureTime() { - return det.setTimer(slsDetectorDefs::timerIndex::ACQUISITION_TIME, -1); - } - - void setSubExposureTime(const int64_t t) { - det.setTimer(slsDetectorDefs::timerIndex::SUBFRAME_ACQUISITION_TIME, t); - } - - int64_t getSubExposureTime() { - // time in ns - return det.setTimer( - slsDetectorDefs::timerIndex::SUBFRAME_ACQUISITION_TIME, -1); - } - - void setSubExposureDeadTime(const int64_t t) { - det.setTimer(slsDetectorDefs::timerIndex::SUBFRAME_DEADTIME, t); - } - - int64_t getSubExposureDeadTime() { - // time in ns - return det.setTimer(slsDetectorDefs::timerIndex::SUBFRAME_DEADTIME, -1); - } - - int64_t getCycles() { - return det.setTimer(slsDetectorDefs::timerIndex::CYCLES_NUMBER, -1); - } - - void setCycles(const int64_t n_cycles) { - det.setTimer(slsDetectorDefs::timerIndex::CYCLES_NUMBER, n_cycles); - } - - - // int getNumberOfGates() { - // return det.setTimer(slsDetectorDefs::timerIndex::GATES_NUMBER, -1); - // } - // void setNumberOfGates(const int t) { - // det.setTimer(slsDetectorDefs::timerIndex::GATES_NUMBER, t); - // } - - // time in ns - int64_t getDelay() { - return det.setTimer(slsDetectorDefs::timerIndex::DELAY_AFTER_TRIGGER, - -1); - } - // time in ns - void setDelay(const int64_t t) { - det.setTimer(slsDetectorDefs::timerIndex::DELAY_AFTER_TRIGGER, t); - } - // time in ns - int64_t getPeriod() { - return det.setTimer(slsDetectorDefs::timerIndex::FRAME_PERIOD, -1); - } - // time in ns - void setPeriod(const int64_t t) { - det.setTimer(slsDetectorDefs::timerIndex::FRAME_PERIOD, t); - } - - int64_t getNumberOfFrames() { - return det.setTimer(slsDetectorDefs::timerIndex::FRAME_NUMBER, -1); - } - - void setNumberOfFrames(const int64_t nframes) { - det.setTimer(slsDetectorDefs::timerIndex::FRAME_NUMBER, nframes); - } - - // std::string getTimingMode() { - // return det.externalCommunicationType( - // det.setExternalCommunicationMode()); - // } - // void setTimingMode(const std::string mode) { - // det.setExternalCommunicationMode(det.externalCommunicationType(mode)); - // } - - void freeSharedMemory() { det.freeSharedMemory(); } - - std::vector getDetectorType() { - std::vector detector_type; - for (size_t i = 0; i < det.size(); ++i) { - detector_type.push_back(det.getDetectorTypeAsString(i)); - } - return detector_type; - } - - void setFileWrite(bool value) { det.setFileWrite(value); } - bool getFileWrite() { return det.getFileWrite(); } - - void setFileOverWrite(bool value) { det.setFileOverWrite(value); } - - bool getFileOverWrite() { return det.getFileOverWrite(); } - - void setAllTrimbits(int tb) { det.setAllTrimbits(tb); } - int getAllTrimbits() { return det.setAllTrimbits(-1); } - bool getRxDataStreamStatus() { - return det.enableDataStreamingFromReceiver(); - } - - void setRxDataStreamStatus(bool state) { - det.enableDataStreamingFromReceiver(state); - } - - // Get a network parameter for all detectors, looping over individual - // detectors return a vector of strings - std::vector getReceiverStreamingPort() { - std::vector vec; - vec.reserve(det.size()); - for (size_t i = 0; i < det.size(); ++i) { - vec.push_back(det.getReceiverStreamingPort(i)); - } - return vec; - } - - void setReceiverStreamingPort(int value, int det_id) { - det.setReceiverDataStreamingOutPort(value, det_id); - } - - // std::vector getReceiverUDPPort() { - // std::vector vec; - // vec.reserve(det.size()); - // for (size_t i = 0; i < det.size(); ++i) { - // vec.push_back(det.getReceiverUDPPort(i)); - // } - // return vec; - // } - - // std::vector getReceiverUDPPort2() { - // std::vector vec; - // vec.reserve(det.size()); - // for (size_t i = 0; i < det.size(); ++i) { - // vec.push_back(det.getReceiverUDPPort2(i)); - // } - // return vec; - // } - - // void setReceiverUDPPort(int port, int det_id) { - // det.setReceiverUDPPort(port, det_id); - // } - // void setReceiverUDPPort2(int port, int det_id) { - // det.setReceiverUDPPort2(port, det_id); - // } - - - std::string getLastClientIP() { return det.getLastClientIP(); } - std::string getReceiverLastClientIP() { - return det.getReceiverLastClientIP(); - } - - // get frame delay of module (det_id) in ns - int getDelayFrame(int det_id) { - auto r = det.setDetectorNetworkParameter( - slsDetectorDefs::networkParameter::DETECTOR_TXN_DELAY_FRAME, -1, - det_id); - return r; - } - // set frame delay of module (det_id) in ns - void setDelayFrame(int det_id, int delay) { - // auto delay_str = std::to_string(delay); - det.setDetectorNetworkParameter( - slsDetectorDefs::networkParameter::DETECTOR_TXN_DELAY_FRAME, delay, - det_id); - } - - // get delay left of module (det_id) in ns - int getDelayLeft(int det_id) { - auto r = det.setDetectorNetworkParameter( - slsDetectorDefs::networkParameter::DETECTOR_TXN_DELAY_LEFT, -1, - det_id); - return r; - } - // set delay left of module (det_id) in ns - void setDelayLeft(int det_id, int delay) { - // auto delay_str = std::to_string(delay); - det.setDetectorNetworkParameter( - slsDetectorDefs::networkParameter::DETECTOR_TXN_DELAY_LEFT, delay, - det_id); - } - - // get delay right of module (det_id) in ns - int getDelayRight(const int det_id) { - auto r = det.setDetectorNetworkParameter( - slsDetectorDefs::networkParameter::DETECTOR_TXN_DELAY_RIGHT, -1, - det_id); - return r; - } - - // set delay right of module (det_id) in ns - void setDelayRight(int det_id, int delay) { - // auto delay_str = std::to_string(delay); - det.setDetectorNetworkParameter( - slsDetectorDefs::networkParameter::DETECTOR_TXN_DELAY_RIGHT, delay, - det_id); - } - - // Check if detector if filling in gap pixels in module - // return true if so, currently only in developer - bool getGapPixels() { return det.enableGapPixels(-1); } - - // Set to true to have the detector filling in gap pixels - // false to disable, currently only in developer - void setGapPixels(bool val) { det.enableGapPixels(val); } - - slsDetectorDefs::networkParameter networkNameToEnum(std::string par_name); - - private: - multiSlsDetector det; - slsDetector *getSlsDetector(int i) const; - int multi_detector_id = 0; -}; - -void DetectorPythonInterface::setFileFormat(const std::string &format) { - if (format == "binary") { - det.setFileFormat(slsDetectorDefs::fileFormat::BINARY); - } else if (format == "hdf5") { - det.setFileFormat(slsDetectorDefs::fileFormat::HDF5); - } -} - -std::string DetectorPythonInterface::getFileFormat() { - auto format = - det.setFileFormat(slsDetectorDefs::fileFormat::GET_FILE_FORMAT, -1); - switch (format) { - case slsDetectorDefs::fileFormat::BINARY: - return "binary"; - case slsDetectorDefs::fileFormat::HDF5: - return "hdf5"; - default: - return "unknown"; - } -} - -slsDetectorDefs::networkParameter -DetectorPythonInterface::networkNameToEnum(std::string par_name) { - - if (par_name == "detectormac") { - return slsDetectorDefs::networkParameter::DETECTOR_MAC; - } else if (par_name == "detectorip") { - return slsDetectorDefs::networkParameter::DETECTOR_IP; - } else if (par_name == "rx_hostname") { - return slsDetectorDefs::networkParameter::RECEIVER_HOSTNAME; - } else if (par_name == "rx_udpip") { - return slsDetectorDefs::networkParameter::RECEIVER_UDP_IP; - } else if (par_name == "rx_udpport") { - return slsDetectorDefs::networkParameter::RECEIVER_UDP_PORT; - } else if (par_name == "rx_udpmac") { - return slsDetectorDefs::networkParameter::RECEIVER_UDP_MAC; - } else if (par_name == "rx_udpport2") { - return slsDetectorDefs::networkParameter::RECEIVER_UDP_PORT2; - } else if (par_name == "rx_udpsocksize") { - return slsDetectorDefs::networkParameter::RECEIVER_UDP_SCKT_BUF_SIZE; - } else if (par_name == "rx_realudpsocksize") { - return slsDetectorDefs::networkParameter:: - RECEIVER_REAL_UDP_SCKT_BUF_SIZE; - } else if (par_name == "rx_jsonaddheader") { - return slsDetectorDefs::networkParameter::ADDITIONAL_JSON_HEADER; - } else if (par_name == "delay_left") { - return slsDetectorDefs::networkParameter::DETECTOR_TXN_DELAY_LEFT; - } else if (par_name == "delay_right") { - return slsDetectorDefs::networkParameter::DETECTOR_TXN_DELAY_RIGHT; - } else if (par_name == "delay_frame") { - return slsDetectorDefs::networkParameter::DETECTOR_TXN_DELAY_FRAME; - } else if (par_name == "flow_control_10g") { - return slsDetectorDefs::networkParameter::FLOW_CONTROL_10G; - } else if (par_name == "client_zmqport") { - return slsDetectorDefs::networkParameter::CLIENT_STREAMING_PORT; - } else if (par_name == "rx_zmqport") { - return slsDetectorDefs::networkParameter::RECEIVER_STREAMING_PORT; - } else if (par_name == "rx_zmqip") { - return slsDetectorDefs::networkParameter::RECEIVER_STREAMING_SRC_IP; - } else if (par_name == "client_zmqip") { - return slsDetectorDefs::networkParameter::CLIENT_STREAMING_SRC_IP; - } - - throw std::runtime_error("Could not decode network parameter"); -}; - -// slsDetectorDefs::fileFormat DetectorPythonInterface::file/// - -slsDetectorDefs::dacIndex DetectorPythonInterface::dacNameToEnum(std::string dac_name) { - // to avoid uninitialised - slsDetectorDefs::dacIndex dac = slsDetectorDefs::dacIndex::E_SvP; - - if (dac_name == "vsvp") { - dac = slsDetectorDefs::dacIndex::E_SvP; - } else if (dac_name == "vtr") { - dac = slsDetectorDefs::dacIndex::E_Vtr; - } else if (dac_name == "vthreshold") { - dac = slsDetectorDefs::dacIndex::THRESHOLD; - } else if (dac_name == "vrf") { - dac = slsDetectorDefs::dacIndex::E_Vrf; - } else if (dac_name == "vrs") { - dac = slsDetectorDefs::dacIndex::E_Vrs; - } else if (dac_name == "vsvn") { - dac = slsDetectorDefs::dacIndex::E_SvN; - } else if (dac_name == "vtgstv") { - dac = slsDetectorDefs::dacIndex::E_Vtgstv; - } else if (dac_name == "vcmp_ll") { - dac = slsDetectorDefs::dacIndex::E_Vcmp_ll; - } else if (dac_name == "vcmp_lr") { - dac = slsDetectorDefs::dacIndex::E_Vcmp_lr; - } else if (dac_name == "vcall") { - dac = slsDetectorDefs::dacIndex::E_cal; - } else if (dac_name == "vcmp_rl") { - dac = slsDetectorDefs::dacIndex::E_Vcmp_rl; - } else if (dac_name == "rxb_rb") { - dac = slsDetectorDefs::dacIndex::E_rxb_rb; - } else if (dac_name == "rxb_lb") { - dac = slsDetectorDefs::dacIndex::E_rxb_lb; - } else if (dac_name == "vcmp_rr") { - dac = slsDetectorDefs::dacIndex::E_Vcmp_rr; - } else if (dac_name == "vcp") { - dac = slsDetectorDefs::dacIndex::E_Vcp; - } else if (dac_name == "vcn") { - dac = slsDetectorDefs::dacIndex::E_Vcn; - } else if (dac_name == "vis") { - dac = slsDetectorDefs::dacIndex::E_Vis; - } else if (dac_name == "iodelay") { - dac = slsDetectorDefs::dacIndex::IO_DELAY; - } else if (dac_name == "v_a") { - dac = slsDetectorDefs::dacIndex::V_POWER_A; - } else if (dac_name == "v_b") { - dac = slsDetectorDefs::dacIndex::V_POWER_B; - } else if (dac_name == "v_c") { - dac = slsDetectorDefs::dacIndex::V_POWER_C; - } else if (dac_name == "v_d") { - dac = slsDetectorDefs::dacIndex::V_POWER_D; - } else if (dac_name == "v_io") { - dac = slsDetectorDefs::dacIndex::V_POWER_IO; - } else if (dac_name == "v_chip") { - dac = slsDetectorDefs::dacIndex::V_POWER_CHIP; - } else if (dac_name == "v_limit") { - dac = slsDetectorDefs::dacIndex::V_LIMIT; - } else if (dac_name == "temp_fpga") { - dac = slsDetectorDefs::dacIndex::TEMPERATURE_FPGA; - } else if (dac_name == "temp_fpgaext") { - dac = slsDetectorDefs::dacIndex::TEMPERATURE_FPGAEXT; - } else if (dac_name == "temp_10ge") { - dac = slsDetectorDefs::dacIndex::TEMPERATURE_10GE; - } else if (dac_name == "temp_dcdc") { - dac = slsDetectorDefs::dacIndex::TEMPERATURE_DCDC; - } else if (dac_name == "temp_sodl") { - dac = slsDetectorDefs::dacIndex::TEMPERATURE_SODL; - } else if (dac_name == "temp_sodr") { - dac = slsDetectorDefs::dacIndex::TEMPERATURE_SODR; - } else if (dac_name == "temp_fpgafl") { - dac = slsDetectorDefs::dacIndex::TEMPERATURE_FPGA2; - } else if (dac_name == "temp_fpgafr") { - dac = slsDetectorDefs::dacIndex::TEMPERATURE_FPGA3; - } else if (dac_name == "vhighvoltage") { - dac = slsDetectorDefs::dacIndex::HIGH_VOLTAGE; - } else if (dac_name == "vb_comp") { - dac = static_cast(0); - } else if (dac_name == "vdd_prot") { - dac = static_cast(1); - } else if (dac_name == "vin_com") { - dac = static_cast(2); - } else if (dac_name == "vref_prech") { - dac = static_cast(3); - } else if (dac_name == "vb_pixbuff") { - dac = static_cast(4); - } else if (dac_name == "vb_ds") { - dac = static_cast(5); - } else if (dac_name == "vref_ds") { - dac = static_cast(6); - } else if (dac_name == "vref_comp") { - dac = static_cast(7); - } else if (dac_name == "dac0") { - dac = static_cast(0); - } else if (dac_name == "dac1") { - dac = static_cast(1); - } else if (dac_name == "dac2") { - dac = static_cast(2); - } else if (dac_name == "dac3") { - dac = static_cast(3); - } else if (dac_name == "dac4") { - dac = static_cast(4); - } else if (dac_name == "dac5") { - dac = static_cast(5); - } else if (dac_name == "dac6") { - dac = static_cast(6); - } else if (dac_name == "dac7") { - dac = static_cast(7); - } else if (dac_name == "dac8") { - dac = static_cast(8); - } else if (dac_name == "dac9") { - dac = static_cast(9); - } else if (dac_name == "dac10") { - dac = static_cast(10); - } else if (dac_name == "dac11") { - dac = static_cast(11); - } else if (dac_name == "dac12") { - dac = static_cast(12); - } else if (dac_name == "dac13") { - dac = static_cast(13); - } else if (dac_name == "dac14") { - dac = static_cast(14); - } else if (dac_name == "dac15") { - dac = static_cast(15); - } else if (dac_name == "dac16") { - dac = static_cast(16); - } else if (dac_name == "dac17") { - dac = static_cast(17); - } - - return dac; -} - - // enum readOutFlags { - // GET_READOUT_FLAGS = -1, /**< return readout flags */ - // NORMAL_READOUT = 0, /**< no flag */ - // STORE_IN_RAM = 0x1, /**< data are stored in ram and sent only after end - // of acquisition for faster frame rate */ - // READ_HITS = 0x2, /**< return only the number of the channel which - // counted ate least one */ - // ZERO_COMPRESSION = 0x4, /**< returned data are 0-compressed */ - // PUMP_PROBE_MODE = 0x8, /** DetectorPythonInterface::getReadoutFlags() { -// std::vector flags; -// auto r = det.setReadOutFlags(); -// if (r & slsDetectorDefs::readOutFlags::STORE_IN_RAM) -// flags.push_back("storeinram"); -// if (r & slsDetectorDefs::readOutFlags::READ_HITS) -// flags.push_back("readhits"); -// if (r & slsDetectorDefs::readOutFlags::ZERO_COMPRESSION) -// flags.push_back("zerocompression"); -// if (r & slsDetectorDefs::readOutFlags::PUMP_PROBE_MODE) -// flags.push_back("pumpprobe"); -// if (r & slsDetectorDefs::readOutFlags::BACKGROUND_CORRECTIONS) -// flags.push_back("backgroundcorrections"); -// if (r & slsDetectorDefs::readOutFlags::TOT_MODE) -// flags.push_back("tot"); -// if (r & slsDetectorDefs::readOutFlags::CONTINOUS_RO) -// flags.push_back("continous"); -// if (r & slsDetectorDefs::readOutFlags::PARALLEL) -// flags.push_back("parallel"); -// if (r & slsDetectorDefs::readOutFlags::NONPARALLEL) -// flags.push_back("nonparallel"); -// if (r & slsDetectorDefs::readOutFlags::DIGITAL_ONLY) -// flags.push_back("digital"); -// if (r & slsDetectorDefs::readOutFlags::ANALOG_AND_DIGITAL) -// flags.push_back("analog_digital"); -// if (r & slsDetectorDefs::readOutFlags::DUT_CLK) -// flags.push_back("dutclk"); -// if (r & slsDetectorDefs::readOutFlags::NOOVERFLOW) -// flags.push_back("nooverflow"); -// if (r & slsDetectorDefs::readOutFlags::SHOW_OVERFLOW) -// flags.push_back("overflow"); -// return flags; -// } - -// // note singular -// void DetectorPythonInterface::setReadoutFlag(const std::string flag_name) { -// if (flag_name == "none") -// det.setReadOutFlags(slsDetectorDefs::readOutFlags::NORMAL_READOUT); -// else if (flag_name == "storeinram") -// det.setReadOutFlags(slsDetectorDefs::readOutFlags::STORE_IN_RAM); -// else if (flag_name == "readhits") -// det.setReadOutFlags(slsDetectorDefs::readOutFlags::READ_HITS); -// else if (flag_name == "zerocompression") -// det.setReadOutFlags(slsDetectorDefs::readOutFlags::ZERO_COMPRESSION); -// else if (flag_name == "pumpprobe") -// det.setReadOutFlags(slsDetectorDefs::readOutFlags::PUMP_PROBE_MODE); -// else if (flag_name == "backgroundcorrections") -// det.setReadOutFlags(slsDetectorDefs::readOutFlags::BACKGROUND_CORRECTIONS); -// else if (flag_name == "tot") -// det.setReadOutFlags(slsDetectorDefs::readOutFlags::TOT_MODE); -// else if (flag_name == "continous") -// det.setReadOutFlags(slsDetectorDefs::readOutFlags::CONTINOUS_RO); -// else if (flag_name == "parallel") -// det.setReadOutFlags(slsDetectorDefs::readOutFlags::PARALLEL); -// else if (flag_name == "nonparallel") -// det.setReadOutFlags(slsDetectorDefs::readOutFlags::NONPARALLEL); -// else if (flag_name == "digital") -// det.setReadOutFlags(slsDetectorDefs::readOutFlags::DIGITAL_ONLY); -// else if (flag_name == "analog_digital") -// det.setReadOutFlags(slsDetectorDefs::readOutFlags::ANALOG_AND_DIGITAL); -// else if (flag_name == "dutclk") -// det.setReadOutFlags(slsDetectorDefs::readOutFlags::DUT_CLK); -// else if (flag_name == "nooverflow") -// det.setReadOutFlags(slsDetectorDefs::readOutFlags::NOOVERFLOW); -// else if (flag_name == "overflow") -// det.setReadOutFlags(slsDetectorDefs::readOutFlags::SHOW_OVERFLOW); -// else -// throw std::runtime_error("Flag name not recognized"); -// } - -std::vector DetectorPythonInterface::getRateCorrection() { - std::vector rate_corr; - for (size_t i = 0; i < det.size(); ++i) { - rate_corr.push_back(det.getRateCorrection(i)); - } - return rate_corr; -} - -void DetectorPythonInterface::pulseAllPixels(int n) { - // int pulsePixelNMove(int n=0,int x=0,int y=0); - // int pulsePixel(int n=0,int x=0,int y=0); - - for (int j = 0; j < 8; ++j) { - det.pulsePixel(0, -255 + j, 0); - for (int i = 0; i < 256; ++i) { - det.pulsePixelNMove(n, 0, 1); - } - } - return; -} -void DetectorPythonInterface::pulseDiagonal(int n) { - // int pulsePixelNMove(int n=0,int x=0,int y=0); - // int pulsePixel(int n=0,int x=0,int y=0); - - for (int j = 20; j < 232; j += 16) { - det.pulsePixel(0, -255, j); - for (int i = 0; i < 8; ++i) { - det.pulsePixelNMove(n, 1, 1); - } - } - return; -} - -#endif // DETECTOR_H diff --git a/python/src/enums.cpp b/python/src/enums.cpp index a6a1c9e91..0fce016cb 100644 --- a/python/src/enums.cpp +++ b/python/src/enums.cpp @@ -10,7 +10,7 @@ namespace py = pybind11; void init_enums(py::module &m) { py::class_ Defs(m, "slsDetectorDefs"); py::class_ xy(m, "xy"); - xy.def(py::init()); + xy.def(py::init()); xy.def(py::init()); xy.def_readwrite("x", &slsDetectorDefs::xy::x); xy.def_readwrite("y", &slsDetectorDefs::xy::y); @@ -32,7 +32,7 @@ py::enum_(Defs, "timerIndex") .value("ACQUISITION_TIME", slsDetectorDefs::timerIndex::ACQUISITION_TIME) .value("FRAME_PERIOD", slsDetectorDefs::timerIndex::FRAME_PERIOD) .value("DELAY_AFTER_TRIGGER", slsDetectorDefs::timerIndex::DELAY_AFTER_TRIGGER) - .value("CYCLES_NUMBER", slsDetectorDefs::timerIndex::CYCLES_NUMBER) + .value("TRIGGER_NUMBER", slsDetectorDefs::timerIndex::TRIGGER_NUMBER) .value("ACTUAL_TIME", slsDetectorDefs::timerIndex::ACTUAL_TIME) .value("MEASUREMENT_TIME", slsDetectorDefs::timerIndex::MEASUREMENT_TIME) .value("PROGRESS", slsDetectorDefs::timerIndex::PROGRESS) @@ -217,6 +217,20 @@ py::enum_(Defs, "dacIndex") .value("M_cas", slsDetectorDefs::dacIndex::M_cas) .value("M_vIcin", slsDetectorDefs::dacIndex::M_vIcin) .value("M_vIpreOut", slsDetectorDefs::dacIndex::M_vIpreOut) + .value("VREF_H_ADC", slsDetectorDefs::dacIndex::VREF_H_ADC) + .value("VB_COMP_FE", slsDetectorDefs::dacIndex::VB_COMP_FE) + .value("VB_COMP_ADC", slsDetectorDefs::dacIndex::VB_COMP_ADC) + .value("VCOM_CDS", slsDetectorDefs::dacIndex::VCOM_CDS) + .value("VREF_RESTORE", slsDetectorDefs::dacIndex::VREF_RESTORE) + .value("VB_OPA_1ST", slsDetectorDefs::dacIndex::VB_OPA_1ST) + .value("VREF_COMP_FE", slsDetectorDefs::dacIndex::VREF_COMP_FE) + .value("VCOM_ADC1", slsDetectorDefs::dacIndex::VCOM_ADC1) + .value("VREF_PRECH", slsDetectorDefs::dacIndex::VREF_PRECH) + .value("VREF_L_ADC", slsDetectorDefs::dacIndex::VREF_L_ADC) + .value("VREF_CDS", slsDetectorDefs::dacIndex::VREF_CDS) + .value("VB_CS", slsDetectorDefs::dacIndex::VB_CS) + .value("VB_OPA_FD", slsDetectorDefs::dacIndex::VB_OPA_FD) + .value("VCOM_ADC2", slsDetectorDefs::dacIndex::VCOM_ADC2) .value("V_POWER_A", slsDetectorDefs::dacIndex::V_POWER_A) .value("V_POWER_B", slsDetectorDefs::dacIndex::V_POWER_B) .value("V_POWER_C", slsDetectorDefs::dacIndex::V_POWER_C) diff --git a/python/src/experimental.cpp b/python/src/experimental.cpp index 57b2bb0d8..c759179f6 100644 --- a/python/src/experimental.cpp +++ b/python/src/experimental.cpp @@ -99,8 +99,10 @@ void init_experimental(py::module &m) { // ACQUISITION .def("acquire", &Detector::acquire) - .def("startAcquisition", &Detector::startAcquisition) - .def("stopAcquisition", &Detector::stopAcquisition) + .def("startDetector", &Detector::startDetector) + .def("stopDetector", &Detector::stopDetector) + .def("startReceiver", &Detector::startReceiver) + .def("stopReceiver", &Detector::stopReceiver) .def("clearAcquiringFlag", &Detector::clearAcquiringFlag) .def("getDetectorStatus", &Detector::getDetectorStatus, py::arg() = Positions{}) @@ -412,11 +414,11 @@ void init_experimental(py::module &m) { .def("setThresholdEnergy", &Detector::setThresholdEnergy, py::arg(), py::arg() = defs::STANDARD, py::arg() = true, py::arg() = Positions{}) - .def("getSettingsDir", &Detector::getSettingsDir, + .def("getSettingsPath", &Detector::getSettingsPath, py::arg() = Positions{}) - .def("setSettingsDir", &Detector::setSettingsDir, py::arg(), + .def("setSettingsPath", &Detector::setSettingsPath, py::arg(), py::arg() = Positions{}) - .def("loadTrimbits", &Detector::setSettingsDir, py::arg(), + .def("loadTrimbits", &Detector::loadTrimbits, py::arg(), py::arg() = Positions{}) .def("getRxAddGapPixels", &Detector::getRxAddGapPixels, py::arg() = Positions{}) diff --git a/python/src/main.cpp b/python/src/main.cpp index 02f0a9d23..bf2cace69 100755 --- a/python/src/main.cpp +++ b/python/src/main.cpp @@ -4,7 +4,6 @@ #include #include "Detector.h" -#include "DetectorPythonInterface.h" #include "Result.h" #include "mythenFileIO.h" #include @@ -12,14 +11,6 @@ #include "typecaster.h" -// // Add type_typecaster to pybind for our wrapper type -// namespace pybind11 { -// namespace detail { -// template -// struct type_caster> -// : list_caster, Type> {}; -// } // namespace detail -// } // namespace pybind11 using ds = std::chrono::duration; @@ -39,303 +30,6 @@ PYBIND11_MODULE(_sls_detector, m) { init_enums(m); init_experimental(m); - - py::class_ DetectorApi(m, "DetectorApi", R"pbdoc( - Interface to the multiSlsDetector class through Detector.h These functions - are used by the python classes Eiger and Jungfrau and normally it is better - to use them than to directly access functions here. - - However it is possible to access these functions... - - :: - - #Using the python class - from sls_detector import Eiger - d = Eiger() - d._api.getThresholdEnergy() - - from _sls_detector import DetectorApi - api = DetectorApi(0) - api.getNumberOfFrames() - - #But the Pythonic way is almost alway simpler - d = Eiger() - d.n_frames - >> 10 - - )pbdoc"); - DetectorApi.def(py::init()) - .def("freeSharedMemory", &DetectorPythonInterface::freeSharedMemory) - .def("getMultiDetectorId", &DetectorPythonInterface::getMultiDetectorId) - .def("acq", &DetectorPythonInterface::acquire) - .def("getAcquiringFlag", &DetectorPythonInterface::getAcquiringFlag) - .def("setAcquiringFlag", &DetectorPythonInterface::setAcquiringFlag) - - .def("setAllTrimbits", &DetectorPythonInterface::setAllTrimbits) - .def("getAllTrimbits", &DetectorPythonInterface::getAllTrimbits) - .def("setCounterBit", &DetectorPythonInterface::setCounterBit) - .def("getCounterBit", &DetectorPythonInterface::getCounterBit) - - .def("getAdc", &DetectorPythonInterface::getAdc) - .def("getDac", &DetectorPythonInterface::getDac) - .def("getDac_mV", &DetectorPythonInterface::getDac_mV) - .def("setDac", &DetectorPythonInterface::setDac) - .def("setDac_mV", &DetectorPythonInterface::setDac_mV) - .def("getDacFromIndex", &DetectorPythonInterface::getDacFromIndex) - .def("setDacFromIndex", &DetectorPythonInterface::setDacFromIndex) - - .def("getDbitPipeline", &DetectorPythonInterface::getDbitPipeline) - .def("setDbitPipeline", &DetectorPythonInterface::setDbitPipeline) - .def("getDbitPhase", &DetectorPythonInterface::getDbitPhase) - .def("setDbitPhase", &DetectorPythonInterface::setDbitPhase) - .def("getDbitClock", &DetectorPythonInterface::getDbitClock) - .def("setDbitClock", &DetectorPythonInterface::setDbitClock) - - .def("setThresholdEnergy", &DetectorPythonInterface::setThresholdEnergy) - .def("getThresholdEnergy", &DetectorPythonInterface::getThresholdEnergy) - - .def("getSettings", &DetectorPythonInterface::getSettings) - .def("setSettings", &DetectorPythonInterface::setSettings) - .def("getSettingsDir", &DetectorPythonInterface::getSettingsDir) - .def("setSettingsDir", &DetectorPythonInterface::setSettingsDir) - - .def("loadTrimbitFile", &DetectorPythonInterface::loadTrimbitFile) - .def("setTrimEnergies", &DetectorPythonInterface::setTrimEnergies) - .def("getTrimEnergies", &DetectorPythonInterface::getTrimEnergies) - - .def("pulseChip", &DetectorPythonInterface::pulseChip) - .def("pulseAllPixels", &DetectorPythonInterface::pulseAllPixels) - .def("pulseDiagonal", &DetectorPythonInterface::pulseDiagonal) - .def("getRunStatus", &DetectorPythonInterface::getRunStatus) - .def("readConfigurationFile", - &DetectorPythonInterface::readConfigurationFile) - .def("readParametersFile", &DetectorPythonInterface::readParametersFile) - // .def("checkOnline", &DetectorPythonInterface::checkOnline) - .def("setReadoutClockSpeed", - &DetectorPythonInterface::setReadoutClockSpeed) - .def("getReadoutClockSpeed", - &DetectorPythonInterface::getReadoutClockSpeed) - .def("getSyncClkSpeed", &DetectorPythonInterface::getSyncClkSpeed) - .def("getHostname", &DetectorPythonInterface::getHostname) - .def("setHostname", &DetectorPythonInterface::setHostname) - - .def("getReceiverPort", &DetectorPythonInterface::getReceiverPort) - .def("setReceiverPort", &DetectorPythonInterface::setReceiverPort) - - .def("isChipPowered", &DetectorPythonInterface::isChipPowered) - .def("powerChip", &DetectorPythonInterface::powerChip) - - .def("readRegister", &DetectorPythonInterface::readRegister) - .def("writeRegister", &DetectorPythonInterface::writeRegister) - .def("writeAdcRegister", &DetectorPythonInterface::writeAdcRegister) - .def("setBitInRegister", &DetectorPythonInterface::setBitInRegister) - .def("clearBitInRegister", &DetectorPythonInterface::clearBitInRegister) - - .def("setDynamicRange", &DetectorPythonInterface::setDynamicRange) - .def("getDynamicRange", &DetectorPythonInterface::getDynamicRange) - .def("getFirmwareVersion", &DetectorPythonInterface::getFirmwareVersion) - .def("getServerVersion", &DetectorPythonInterface::getServerVersion) - .def("getClientVersion", &DetectorPythonInterface::getClientVersion) - .def("getReceiverVersion", &DetectorPythonInterface::getReceiverVersion) - .def("getDetectorNumber", &DetectorPythonInterface::getDetectorNumber) - .def("getRateCorrection", &DetectorPythonInterface::getRateCorrection) - .def("setRateCorrection", &DetectorPythonInterface::setRateCorrection) - - .def("startAcquisition", &DetectorPythonInterface::startAcquisition) - .def("stopAcquisition", &DetectorPythonInterface::stopAcquisition) - .def("startReceiver", &DetectorPythonInterface::startReceiver) - .def("stopReceiver", &DetectorPythonInterface::stopReceiver) - - .def("getFilePath", - (std::string(DetectorPythonInterface::*)()) & - DetectorPythonInterface::getFilePath, - "Using multiSlsDetector") - .def("getFilePath", - (std::string(DetectorPythonInterface::*)(int)) & - DetectorPythonInterface::getFilePath, - "File path for individual detector") - .def("setFilePath", (void (DetectorPythonInterface::*)(std::string)) & - DetectorPythonInterface::setFilePath) - - .def("setFileName", &DetectorPythonInterface::setFileName) - .def("getFileName", &DetectorPythonInterface::getFileName) - .def("setFileIndex", &DetectorPythonInterface::setFileIndex) - .def("getFileIndex", &DetectorPythonInterface::getFileIndex) - .def("getNumberOfDetectors", &DetectorPythonInterface::getNumberOfDetectors) - - .def("setExposureTime", &DetectorPythonInterface::setExposureTime) - .def("getExposureTime", &DetectorPythonInterface::getExposureTime) - .def("setSubExposureTime", &DetectorPythonInterface::setSubExposureTime) - .def("getSubExposureTime", &DetectorPythonInterface::getSubExposureTime) - .def("setPeriod", &DetectorPythonInterface::setPeriod) - .def("getPeriod", &DetectorPythonInterface::getPeriod) - .def("setSubExposureDeadTime", &DetectorPythonInterface::setSubExposureDeadTime) - .def("getSubExposureDeadTime", &DetectorPythonInterface::getSubExposureDeadTime) - - .def("getCycles", &DetectorPythonInterface::getCycles) - .def("setCycles", &DetectorPythonInterface::setCycles) - // .def("getNumberOfGates", &DetectorPythonInterface::getNumberOfGates) - // .def("setNumberOfGates", &DetectorPythonInterface::setNumberOfGates) - .def("getDelay", &DetectorPythonInterface::getDelay) - .def("setDelay", &DetectorPythonInterface::setDelay) - - .def("setStoragecellStart", &DetectorPythonInterface::setStoragecellStart) - .def("getStoragecellStart", &DetectorPythonInterface::getStoragecellStart) - .def("setNumberOfStorageCells", &DetectorPythonInterface::setNumberOfStorageCells) - .def("getNumberOfStorageCells", &DetectorPythonInterface::getNumberOfStorageCells) - - // .def("getTimingMode", &DetectorPythonInterface::getTimingMode) - // .def("setTimingMode", &DetectorPythonInterface::setTimingMode) - - .def("getDetectorType", &DetectorPythonInterface::getDetectorType) - - .def("setThresholdTemperature", &DetectorPythonInterface::setThresholdTemperature) - .def("getThresholdTemperature", &DetectorPythonInterface::getThresholdTemperature) - .def("setTemperatureControl", &DetectorPythonInterface::setTemperatureControl) - .def("getTemperatureControl", &DetectorPythonInterface::getTemperatureControl) - .def("getTemperatureEvent", &DetectorPythonInterface::getTemperatureEvent) - .def("resetTemperatureEvent", &DetectorPythonInterface::resetTemperatureEvent) - - .def("getRxDataStreamStatus", &DetectorPythonInterface::getRxDataStreamStatus) - .def("setRxDataStreamStatus", &DetectorPythonInterface::setRxDataStreamStatus) - - // Network stuff - .def("getReceiverHostname", - &DetectorPythonInterface::getReceiverHostname, - py::arg("det_id") = -1) - .def("setReceiverHostname", - &DetectorPythonInterface::setReceiverHostname, py::arg("hostname"), - py::arg("det_id") = -1) - .def("getReceiverStreamingPort", - &DetectorPythonInterface::getReceiverStreamingPort) - .def("setReceiverStreamingPort", - &DetectorPythonInterface::setReceiverStreamingPort) - // .def("getReceiverUDPPort", &DetectorPythonInterface::getReceiverUDPPort) - // .def("getReceiverUDPPort2", - // &DetectorPythonInterface::getReceiverUDPPort2) - // .def("setReceiverUDPPort", &DetectorPythonInterface::setReceiverUDPPort) - // .def("setReceiverUDPPort2", - // &DetectorPythonInterface::setReceiverUDPPort2) - // .def("setReceiverUDPIP", &DetectorPythonInterface::setReceiverUDPIP) - // .def("getReceiverUDPIP", &DetectorPythonInterface::getReceiverUDPIP) - // .def("getReceiverUDPMAC", &DetectorPythonInterface::getReceiverUDPMAC) - // .def("setReceiverUDPMAC", &DetectorPythonInterface::setReceiverUDPMAC) - - .def("getReceiverPort", &DetectorPythonInterface::getReceiverPort) - .def("setReceiverPort", &DetectorPythonInterface::setReceiverPort) - - .def("getDelayFrame", &DetectorPythonInterface::getDelayFrame) - .def("setDelayFrame", &DetectorPythonInterface::setDelayFrame) - .def("getDelayLeft", &DetectorPythonInterface::getDelayLeft) - .def("setDelayLeft", &DetectorPythonInterface::setDelayLeft) - .def("getDelayRight", &DetectorPythonInterface::getDelayRight) - .def("setDelayRight", &DetectorPythonInterface::setDelayRight) - .def("getLastClientIP", &DetectorPythonInterface::getLastClientIP) - .def("getReceiverLastClientIP", - &DetectorPythonInterface::getReceiverLastClientIP) - - .def("setFramesPerFile", &DetectorPythonInterface::setFramesPerFile) - .def("getFramesPerFile", &DetectorPythonInterface::getFramesPerFile) - .def("setReceiverFifoDepth", - &DetectorPythonInterface::setReceiverFifoDepth) - .def("getReceiverFifoDepth", - &DetectorPythonInterface::getReceiverFifoDepth) - - .def("getReceiverFrameDiscardPolicy", - &DetectorPythonInterface::getReceiverFrameDiscardPolicy) - .def("setReceiverFramesDiscardPolicy", - &DetectorPythonInterface::setReceiverFramesDiscardPolicy) - .def("setPartialFramesPadding", - &DetectorPythonInterface::setPartialFramesPadding) - .def("getPartialFramesPadding", - &DetectorPythonInterface::getPartialFramesPadding) - - .def("getUserDetails", &DetectorPythonInterface::getUserDetails) - .def("checkDetectorVersionCompatibility", - &DetectorPythonInterface::checkDetectorVersionCompatibility) - .def("checkReceiverVersionCompatibility", - &DetectorPythonInterface::checkReceiverVersionCompatibility) - .def("getMeasuredPeriod", &DetectorPythonInterface::getMeasuredPeriod) - .def("getMeasuredSubPeriod", - &DetectorPythonInterface::getMeasuredSubPeriod) - - .def("setFileWrite", &DetectorPythonInterface::setFileWrite) - .def("getFileWrite", &DetectorPythonInterface::getFileWrite) - .def("setFileOverWrite", &DetectorPythonInterface::setFileOverWrite) - .def("getFileOverWrite", &DetectorPythonInterface::getFileOverWrite) - .def("getDacVthreshold", &DetectorPythonInterface::getDacVthreshold) - .def("setDacVthreshold", &DetectorPythonInterface::setDacVthreshold) - .def("setNumberOfFrames", &DetectorPythonInterface::setNumberOfFrames) - .def("getNumberOfFrames", &DetectorPythonInterface::getNumberOfFrames) - - // Overloaded calls - .def("getFramesCaughtByReceiver", - (int (DetectorPythonInterface::*)()) & - DetectorPythonInterface::getFramesCaughtByReceiver) - .def("getFramesCaughtByReceiver", - (int (DetectorPythonInterface::*)(int)) & - DetectorPythonInterface::getFramesCaughtByReceiver) - - .def("resetFramesCaught", &DetectorPythonInterface::resetFramesCaught) - .def("getReceiverCurrentFrameIndex", - &DetectorPythonInterface::getReceiverCurrentFrameIndex) - .def("getGapPixels", &DetectorPythonInterface::getGapPixels) - .def("setGapPixels", &DetectorPythonInterface::setGapPixels) - .def("getFlippedDataX", &DetectorPythonInterface::getFlippedDataX) - // .def("getFlippedDataY", &DetectorPythonInterface::getFlippedDataY) - .def("setFlippedDataX", &DetectorPythonInterface::setFlippedDataX) - // .def("setFlippedDataY", &DetectorPythonInterface::setFlippedDataY) - - .def("getServerLock", &DetectorPythonInterface::getServerLock) - .def("setServerLock", &DetectorPythonInterface::setServerLock) - .def("getReceiverLock", &DetectorPythonInterface::getReceiverLock) - .def("setReceiverLock", &DetectorPythonInterface::setReceiverLock) - - // .def("getReadoutFlags", &DetectorPythonInterface::getReadoutFlags) - // .def("setReadoutFlag", &DetectorPythonInterface::setReadoutFlag) - - .def("setFileFormat", &DetectorPythonInterface::setFileFormat) - .def("getFileFormat", &DetectorPythonInterface::getFileFormat) - - .def("getActive", &DetectorPythonInterface::getActive) - .def("setActive", &DetectorPythonInterface::setActive) - - .def("getTenGigabitEthernet", - &DetectorPythonInterface::getTenGigabitEthernet) - .def("setTenGigabitEthernet", - &DetectorPythonInterface::setTenGigabitEthernet) - - .def("getPatternLoops", &DetectorPythonInterface::getPatternLoops, - py::arg("level"), py::arg("det_id") = -1) - .def("setPatternLoops", &DetectorPythonInterface::setPatternLoops, - py::arg("level"), py::arg("start"), py::arg("stop"), py::arg("n"), - py::arg("det_id") = -1) - .def("setPatternWord", &DetectorPythonInterface::setPatternWord, - py::arg("addr"), py::arg("word"), py::arg("det_id") = -1) - .def("getPatternWord", &DetectorPythonInterface::getPatternWord, - py::arg("addr"), py::arg("det_id") = -1) - - .def("setPatternIOControl", - &DetectorPythonInterface::setPatternIOControl, py::arg("word"), - py::arg("det_id") = -1) - .def("setPatternClockControl", - &DetectorPythonInterface::setPatternClockControl, py::arg("word"), - py::arg("det_id") = -1) - - .def("setPatternWaitAddr", &DetectorPythonInterface::setPatternWaitAddr, - py::arg("level"), py::arg("addr"), py::arg("det_id") = -1) - .def("getPatternWaitAddr", &DetectorPythonInterface::getPatternWaitAddr, - py::arg("level"), py::arg("det_id") = -1) - - .def("setPatternWaitTime", &DetectorPythonInterface::setPatternWaitTime, - py::arg("level"), py::arg("duration"), py::arg("det_id") = -1) - - .def("getPatternWaitTime", &DetectorPythonInterface::getPatternWaitTime, - py::arg("level"), py::arg("det_id") = -1); - - - - py::module io = m.def_submodule("io", "Submodule for io"); diff --git a/slsDetectorGui/forms/form_tab_advanced.ui b/slsDetectorGui/forms/form_tab_advanced.ui index 315d1cc01..ed32f0c17 100755 --- a/slsDetectorGui/forms/form_tab_advanced.ui +++ b/slsDetectorGui/forms/form_tab_advanced.ui @@ -1072,7 +1072,7 @@ false - <html><head/><body><p>Number of additional storage cells. For Jungfrau only. </p><p>Default: 0. </p><p>Number of Images received: #frames * #cycles * (#storagecells+1) </p><p> #storagecells#</p><p><br/></p></body></html> + <html><head/><body><p>Number of additional storage cells. For Jungfrau only. </p><p>Default: 0. </p><p>Number of Images received: #frames * #triggers * (#storagecells+1) </p><p> #storagecells#</p><p><br/></p></body></html> Number of Storage cells: @@ -1129,7 +1129,7 @@ - <html><head/><body><p>Number of additional storage cells. For Jungfrau only. </p><p>Default: 0. </p><p>Number of Images received: #frames * #cycles * (#storagecells+1) </p><p> #storagecells#</p><p><br/></p></body></html> + <html><head/><body><p>Number of additional storage cells. For Jungfrau only. </p><p>Default: 0. </p><p>Number of Images received: #frames * #triggers * (#storagecells+1) </p><p> #storagecells#</p><p><br/></p></body></html> diff --git a/slsDetectorGui/forms/form_tab_measurement.ui b/slsDetectorGui/forms/form_tab_measurement.ui index 8454d2434..10fdfc038 100755 --- a/slsDetectorGui/forms/form_tab_measurement.ui +++ b/slsDetectorGui/forms/form_tab_measurement.ui @@ -438,8 +438,7 @@ false - Number of Triggers to be expected. - #cycles# + <html><head/><body><p>Number of Triggers to be expected.</p><p> #triggers#</p></body></html> Number of Triggers: @@ -534,7 +533,7 @@ Frame period between exposures. Number of Triggers to be expected. - #cycles# + #triggers# @@ -620,7 +619,7 @@ Frame period between exposures. Number of Triggers to be expected. - #cycles# + #triggers# Number of Samples: @@ -700,7 +699,7 @@ Frame period between exposures. Number of Triggers to be expected. - #cycles# + #triggers# diff --git a/slsDetectorGui/src/qDacWidget.cpp b/slsDetectorGui/src/qDacWidget.cpp index 03120f8ac..ff94e1d87 100755 --- a/slsDetectorGui/src/qDacWidget.cpp +++ b/slsDetectorGui/src/qDacWidget.cpp @@ -59,7 +59,7 @@ void qDacWidget::SetDac() { FILE_LOG(logINFO) << "Setting dac:" << lblDac->text().toAscii().data() << " : " << val; try { - det->setDAC(val, index, 0, {detectorIndex}); + det->setDAC(index, val, 0, {detectorIndex}); } CATCH_DISPLAY (std::string("Could not set dac ") + std::to_string(index), "qDacWidget::SetDac") // update mV anyway diff --git a/slsDetectorGui/src/qDetectorMain.cpp b/slsDetectorGui/src/qDetectorMain.cpp index dc7f2f9e5..178beabb8 100755 --- a/slsDetectorGui/src/qDetectorMain.cpp +++ b/slsDetectorGui/src/qDetectorMain.cpp @@ -11,6 +11,7 @@ #include "qTabMessages.h" #include "versionAPI.h" +#include "ToString.h" #include #include @@ -231,13 +232,13 @@ void qDetectorMain::SetUpDetector(const std::string fName, int multiID) { default: std::ostringstream os; os << det->getHostname() << " has " << - slsDetectorDefs::detectorTypeToString(det->getDetectorType().squash()) << " detector type (" << + sls::ToString(det->getDetectorType().squash()) << " detector type (" << std::to_string(detType) << "). Exiting GUI."; std::string errorMess = os.str(); throw sls::RuntimeError(errorMess.c_str()); } std::ostringstream os; - os << "SLS Detector GUI : " << slsDetectorDefs::detectorTypeToString(det->getDetectorType().squash()) + os << "SLS Detector GUI : " << sls::ToString(det->getDetectorType().squash()) << " - " << det->getHostname(); std::string title = os.str(); FILE_LOG(logINFO) << title; @@ -384,7 +385,7 @@ void qDetectorMain::ExecuteUtilities(QAction *action) { } else if (action == actionLoadTrimbits) { - QString fName = QString((det->getSettingsDir().squash("/tmp/")).c_str()); + QString fName = QString((det->getSettingsPath().squash("/tmp/")).c_str()); FILE_LOG(logDEBUG) << "Loading Trimbits"; // so that even nonexisting files can be selected QFileDialog *fileDialog = new QFileDialog( diff --git a/slsDetectorGui/src/qDrawPlot.cpp b/slsDetectorGui/src/qDrawPlot.cpp index 75f93390d..d77db24ed 100755 --- a/slsDetectorGui/src/qDrawPlot.cpp +++ b/slsDetectorGui/src/qDrawPlot.cpp @@ -6,6 +6,7 @@ #include "qCloneWidget.h" #include "detectorData.h" +#include "ToString.h" #include #include @@ -570,8 +571,11 @@ void qDrawPlot::AcquireFinished() { FILE_LOG(logERROR) << "Acquisition Finished with an exception: " << mess; qDefs::ExceptionMessage("Acquire unsuccessful.", mess, "qDrawPlot::AcquireFinished"); try{ - det->stopAcquisition(); - } CATCH_DISPLAY("Could not stop acquisition and receiver.", "qDrawPlot::AcquireFinished"); + det->stopDetector(); + } CATCH_DISPLAY("Could not stop detector acquisition.", "qDrawPlot::AcquireFinished"); + try{ + det->stopReceiver(); + } CATCH_DISPLAY("Could not stop receiver.", "qDrawPlot::AcquireFinished"); emit AbortSignal(); } FILE_LOG(logDEBUG) << "End of Acquisition Finished"; @@ -599,7 +603,7 @@ void qDrawPlot::GetDataCallBack(detectorData *data, uint64_t frameIndex, uint32_ void qDrawPlot::AcquisitionFinished(double currentProgress, int detectorStatus) { progress = currentProgress; - std::string status = slsDetectorDefs::runStatusType(static_cast(detectorStatus)); + std::string status = sls::ToString(static_cast(detectorStatus)); if (detectorStatus == slsDetectorDefs::ERROR) { qDefs::Message(qDefs::WARNING, std::string("The acquisiton has ended abruptly. Current Detector Status: ") + status + std::string("."), "qDrawPlot::AcquisitionFinished"); diff --git a/slsDetectorGui/src/qTabAdvanced.cpp b/slsDetectorGui/src/qTabAdvanced.cpp index 4504dd41c..6a4a40211 100755 --- a/slsDetectorGui/src/qTabAdvanced.cpp +++ b/slsDetectorGui/src/qTabAdvanced.cpp @@ -205,7 +205,7 @@ void qTabAdvanced::GetCltZMQIP() { try { auto retval = - det->getClientZmqIp({comboDetector->currentIndex()})[0]; + det->getClientZmqIp({comboDetector->currentIndex()})[0].str(); dispZMQIP->setText(QString(retval.c_str())); } CATCH_DISPLAY ("Could not get client zmq ip.", "qTabAdvanced::GetCltZMQIP") @@ -303,7 +303,7 @@ void qTabAdvanced::GetRxrZMQIP() { try { auto retval = - det->getRxZmqIP({comboDetector->currentIndex()})[0]; + det->getRxZmqIP({comboDetector->currentIndex()})[0].str(); dispRxrZMQIP->setText(QString(retval.c_str())); } CATCH_DISPLAY ("Could not get receiver zmq ip.", "qTabAdvanced::GetRxrZMQIP") diff --git a/slsDetectorGui/src/qTabDebugging.cpp b/slsDetectorGui/src/qTabDebugging.cpp index 9ae292cb5..0365930cb 100755 --- a/slsDetectorGui/src/qTabDebugging.cpp +++ b/slsDetectorGui/src/qTabDebugging.cpp @@ -1,6 +1,8 @@ #include "qTabDebugging.h" #include "qDefs.h" +#include "ToString.h" + #include #include #include @@ -65,7 +67,7 @@ void qTabDebugging::GetDetectorStatus() { FILE_LOG(logDEBUG) << "Getting Status"; try { - std::string status = slsDetectorDefs::runStatusType(det->getDetectorStatus({comboDetector->currentIndex()})[0]); + std::string status = sls::ToString(det->getDetectorStatus({comboDetector->currentIndex()})[0]); lblStatus->setText(QString(status.c_str()).toUpper()); } CATCH_DISPLAY ("Could not get detector status.", "qTabDebugging::GetDetectorStatus") } @@ -88,7 +90,7 @@ void qTabDebugging::GetInfo() { //to make sure the size is constant lblDetectorFirmware->setFixedWidth(100); layout->addWidget(dispFrame, 0, 1); - QString detName = QString(slsDetectorDefs::detectorTypeToString(det->getDetectorType().squash()).c_str()); + QString detName = QString(sls::ToString(det->getDetectorType().squash()).c_str()); switch (det->getDetectorType().squash()) { diff --git a/slsDetectorGui/src/qTabMeasurement.cpp b/slsDetectorGui/src/qTabMeasurement.cpp index 08a6b5484..197dea098 100755 --- a/slsDetectorGui/src/qTabMeasurement.cpp +++ b/slsDetectorGui/src/qTabMeasurement.cpp @@ -524,7 +524,7 @@ void qTabMeasurement::StopAcquisition() { FILE_LOG(logINFORED) << "Stopping Acquisition"; try{ isAcquisitionStopped = true; - det->stopAcquisition(); + det->stopDetector(); } CATCH_DISPLAY("Could not stop acquisition.", "qTabMeasurement::StopAcquisition") } diff --git a/slsDetectorGui/src/qTabSettings.cpp b/slsDetectorGui/src/qTabSettings.cpp index 6e6eb5d1f..ab289b97b 100755 --- a/slsDetectorGui/src/qTabSettings.cpp +++ b/slsDetectorGui/src/qTabSettings.cpp @@ -1,6 +1,8 @@ #include "qTabSettings.h" #include "qDefs.h" +#include "ToString.h" + #include #include @@ -129,8 +131,8 @@ void qTabSettings::GetSettings() { void qTabSettings::SetSettings(int index) { // settings auto val = static_cast(index); - FILE_LOG(logINFO) << "Setting Settings to " << slsDetectorDefs::getDetectorSettings(val); try { + FILE_LOG(logINFO) << "Setting Settings to " << sls::ToString(val); det->setSettings(val); } CATCH_HANDLE ("Could not set settings.", "qTabSettings::SetSettings", this, &qTabSettings::GetSettings) // threshold diff --git a/slsDetectorServers/ctbDetectorServer/RegisterDefs.h b/slsDetectorServers/ctbDetectorServer/RegisterDefs.h index e5b21dc28..6c30913c3 100755 --- a/slsDetectorServers/ctbDetectorServer/RegisterDefs.h +++ b/slsDetectorServers/ctbDetectorServer/RegisterDefs.h @@ -122,7 +122,7 @@ #define DELAY_LEFT_LSB_REG (0x12 << MEM_MAP_SHIFT) #define DELAY_LEFT_MSB_REG (0x13 << MEM_MAP_SHIFT) -/* Cycles Left 64 bit RO register TODO */ +/* Triggers Left 64 bit RO register TODO */ #define CYCLES_LEFT_LSB_REG (0x14 << MEM_MAP_SHIFT) #define CYCLES_LEFT_MSB_REG (0x15 << MEM_MAP_SHIFT) @@ -450,7 +450,7 @@ #define DELAY_LSB_REG (0x60 << MEM_MAP_SHIFT) #define DELAY_MSB_REG (0x61 << MEM_MAP_SHIFT) -/* Cycles 64 bit RW register */ +/* Triggers 64 bit RW register */ #define CYCLES_LSB_REG (0x62 << MEM_MAP_SHIFT) #define CYCLES_MSB_REG (0x63 << MEM_MAP_SHIFT) diff --git a/slsDetectorServers/ctbDetectorServer/bin/ctbDetectorServer_developer b/slsDetectorServers/ctbDetectorServer/bin/ctbDetectorServer_developer index d69af91f50c91584545ced6279046f9cda46d0c6..3592691d122c2c216bbb71c77ad933a9a229aec6 100755 GIT binary patch delta 83780 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 E|8~q2kN^Mx delta 83332 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 diff --git a/slsDetectorServers/ctbDetectorServer/slsDetectorFunctionList.c b/slsDetectorServers/ctbDetectorServer/slsDetectorFunctionList.c index b3ef74d0c..122f73ed5 100755 --- a/slsDetectorServers/ctbDetectorServer/slsDetectorFunctionList.c +++ b/slsDetectorServers/ctbDetectorServer/slsDetectorFunctionList.c @@ -560,7 +560,7 @@ void setupDetector() { setTimer(DIGITAL_SAMPLES, DEFAULT_NUM_SAMPLES); // update databytes and allocate ram setTimer(FRAME_NUMBER, DEFAULT_NUM_FRAMES); setTimer(ACQUISITION_TIME, DEFAULT_EXPTIME); - setTimer(CYCLES_NUMBER, DEFAULT_NUM_CYCLES); + setTimer(TRIGGER_NUMBER, DEFAULT_NUM_CYCLES); setTimer(FRAME_PERIOD, DEFAULT_PERIOD); setTimer(DELAY_AFTER_TRIGGER, DEFAULT_DELAY); setTiming(DEFAULT_TIMING_MODE); @@ -904,12 +904,12 @@ int64_t setTimer(enum timerIndex ind, int64_t val) { FILE_LOG(logINFO, ("\tGetting delay: %lldns\n", (long long int)retval)); break; - case CYCLES_NUMBER: + case TRIGGER_NUMBER: if(val >= 0) { - FILE_LOG(logINFO, ("Setting #cycles: %lld\n", (long long int)val)); + FILE_LOG(logINFO, ("Setting #triggers: %lld\n", (long long int)val)); } retval = set64BitReg(val, CYCLES_LSB_REG, CYCLES_MSB_REG); - FILE_LOG(logINFO, ("\tGetting #cycles: %lld\n", (long long int)retval)); + FILE_LOG(logINFO, ("\tGetting #triggers: %lld\n", (long long int)retval)); break; case ANALOG_SAMPLES: @@ -974,9 +974,9 @@ int64_t getTimeLeft(enum timerIndex ind){ FILE_LOG(logINFO, ("Getting delay left: %lldns\n", (long long int)retval)); break; - case CYCLES_NUMBER: + case TRIGGER_NUMBER: retval = get64BitReg(CYCLES_LEFT_LSB_REG, CYCLES_LEFT_MSB_REG); - FILE_LOG(logINFO, ("Getting number of cycles left: %lld\n", (long long int)retval)); + FILE_LOG(logINFO, ("Getting number of triggers left: %lld\n", (long long int)retval)); break; case ACTUAL_TIME: @@ -2200,7 +2200,7 @@ int startStateMachine(){ #ifdef VIRTUAL void* start_timer(void* arg) { int wait_in_s = (setTimer(FRAME_NUMBER, -1) * - setTimer(CYCLES_NUMBER, -1) * + setTimer(TRIGGER_NUMBER, -1) * (setTimer(FRAME_PERIOD, -1)/(1E9))); FILE_LOG(logDEBUG1, ("going to wait for %d s\n", wait_in_s)); while(!virtual_stop && (wait_in_s >= 0)) { diff --git a/slsDetectorServers/eigerDetectorServer/Makefile b/slsDetectorServers/eigerDetectorServer/Makefile index 989117917..8a326bfc8 100755 --- a/slsDetectorServers/eigerDetectorServer/Makefile +++ b/slsDetectorServers/eigerDetectorServer/Makefile @@ -6,7 +6,7 @@ support_lib = ../../slsSupportLib/include/ BLACKFIN_CC = bfin-uclinux-gcc CROSS = powerpc-4xx-softfloat- CC = $(CROSS)gcc -CFLAGS += -Wall -DEIGERD -DSTOP_SERVER -I$(main_inc) -I$(support_lib) -I$(current_dir)#-DVERBOSEI #-DVERBOSE +CFLAGS += -Wall -DEIGERD -DSTOP_SERVER -I$(main_inc) -I$(support_lib) -I$(current_dir) #-DDEBUG1 #-DVERBOSEI #-DVERBOSE LDLIBS += -lm PROGS = eigerDetectorServer DESTDIR = bin diff --git a/slsDetectorServers/eigerDetectorServer/bin/eigerDetectorServer_developer b/slsDetectorServers/eigerDetectorServer/bin/eigerDetectorServer_developer index 5108c440f6fe1cf14875ec6247269500f610ddb3..134c8198c5c5c1a192513a66f423cbd6891c42d7 100755 GIT binary patch delta 71056 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

gDN3G@1{y1d5*x=_6OF9+f<;P9$Lojo2NG!w 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 delta 73050 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 0) { - FILE_LOG(logDEBUG1, ("Setting number of frames: %d * %d\n", (unsigned int)val, eiger_ncycles)); + FILE_LOG(logDEBUG1, ("Setting number of frames: %d * %d\n", (unsigned int)val, eiger_ntriggers)); #ifndef VIRTUAL - if (Feb_Control_SetNExposures((unsigned int)val*eiger_ncycles)) { + if (Feb_Control_SetNExposures((unsigned int)val*eiger_ntriggers)) { eiger_nexposures = val; - //SetDestinationParameters(EigerGetNumberOfExposures()*EigerGetNumberOfCycles()); + //SetDestinationParameters(EigerGetNumberOfExposures()*EigerGetNumberOfTriggers()); on_dst = 0; int i; for(i=0;i<32;i++) dst_requested[i] = 0; //clear dst requested ndsts_in_use = 1; - nimages_per_request = eiger_nexposures * eiger_ncycles; + nimages_per_request = eiger_nexposures * eiger_ntriggers; } #else eiger_nexposures = val; - nimages_per_request = eiger_nexposures * eiger_ncycles; + nimages_per_request = eiger_nexposures * eiger_ntriggers; #endif }return eiger_nexposures; @@ -714,25 +714,25 @@ int64_t setTimer(enum timerIndex ind, int64_t val) { return eiger_virtual_period*1e9; #endif - case CYCLES_NUMBER: + case TRIGGER_NUMBER: if (val >= 0) { FILE_LOG(logDEBUG1, ("Setting number of triggers: %d * %d\n", (unsigned int)val,eiger_nexposures)); #ifndef VIRTUAL if (Feb_Control_SetNExposures((unsigned int)val*eiger_nexposures)) { - eiger_ncycles = val; - //SetDestinationParameters(EigerGetNumberOfExposures()*EigerGetNumberOfCycles()); + eiger_ntriggers = val; + //SetDestinationParameters(EigerGetNumberOfExposures()*EigerGetNumberOfTriggers()); on_dst = 0; int i; for(i=0;i<32;i++) dst_requested[i] = 0; //clear dst requested - nimages_per_request = eiger_nexposures * eiger_ncycles; + nimages_per_request = eiger_nexposures * eiger_ntriggers; } #else - eiger_ncycles = val; - nimages_per_request = eiger_nexposures * eiger_ncycles; + eiger_ntriggers = val; + nimages_per_request = eiger_nexposures * eiger_ntriggers; #endif } - return eiger_ncycles; + return eiger_ntriggers; default: FILE_LOG(logERROR, ("Timer Index not implemented for this detector: %d\n", ind)); break; @@ -1240,7 +1240,7 @@ int configureMAC() { on_dst = 0; for(i=0;i<32;i++) dst_requested[i] = 0; //clear dst requested - nimages_per_request=eiger_nexposures * eiger_ncycles; + nimages_per_request=eiger_nexposures * eiger_ntriggers; #endif return OK; } diff --git a/slsDetectorServers/gotthard2DetectorServer/RegisterDefs.h b/slsDetectorServers/gotthard2DetectorServer/RegisterDefs.h index e2aca049c..f22731f77 100644 --- a/slsDetectorServers/gotthard2DetectorServer/RegisterDefs.h +++ b/slsDetectorServers/gotthard2DetectorServer/RegisterDefs.h @@ -75,7 +75,7 @@ /* BASE_ACQUISITION FPGA registers TODO --------------------------------------------------*/ -/* Cycles left 64bit Register */ +/* Triggers left 64bit Register */ #define GET_CYCLES_LSB_REG (0x10 + BASE_ACQUISITION) #define GET_CYCLES_MSB_REG (0x14 + BASE_ACQUISITION) diff --git a/slsDetectorServers/gotthard2DetectorServer/bin/gotthard2DetectorServer_developer b/slsDetectorServers/gotthard2DetectorServer/bin/gotthard2DetectorServer_developer index 3f1281b3c766e9cf177d7fe832d105509cd33607..b46fd4380ec45145a75e08197e0aefb7f575a4f6 100755 GIT binary patch literal 124840 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 vYWL}yLeDej< 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 literal 123848 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

8NhuQ<~o6`cwEb14N2k% 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 XP=HEDzm+^mybJjVPCC&4yz~D774$K< diff --git a/slsDetectorServers/gotthard2DetectorServer/slsDetectorFunctionList.c b/slsDetectorServers/gotthard2DetectorServer/slsDetectorFunctionList.c index 4cb422a95..4d2ab470d 100644 --- a/slsDetectorServers/gotthard2DetectorServer/slsDetectorFunctionList.c +++ b/slsDetectorServers/gotthard2DetectorServer/slsDetectorFunctionList.c @@ -374,7 +374,7 @@ void setupDetector() { setHighVoltage(DEFAULT_HIGH_VOLTAGE); setDefaultDacs(); setTimer(FRAME_NUMBER, DEFAULT_NUM_FRAMES); - setTimer(CYCLES_NUMBER, DEFAULT_NUM_CYCLES); + setTimer(TRIGGER_NUMBER, DEFAULT_NUM_CYCLES); setTimer(ACQUISITION_TIME, DEFAULT_EXPTIME); setTimer(ACQUISITION_TIME, DEFAULT_PERIOD); } @@ -436,12 +436,12 @@ int64_t setTimer(enum timerIndex ind, int64_t val) { retval = set64BitReg(val, SET_PERIOD_LSB_REG, SET_PERIOD_MSB_REG )/ (1E-9 * SYSTEM_C0); //TODO FILE_LOG(logDEBUG1, ("Getting period: %lldns\n", (long long int)retval)); break; - case CYCLES_NUMBER: + case TRIGGER_NUMBER: if(val >= 0) { - FILE_LOG(logINFO, ("Setting #cycles: %lld\n", (long long int)val)); + FILE_LOG(logINFO, ("Setting #triggers: %lld\n", (long long int)val)); } retval = set64BitReg(val, SET_CYCLES_LSB_REG, SET_CYCLES_MSB_REG); - FILE_LOG(logDEBUG1, ("Getting #cycles: %lld\n", (long long int)retval)); + FILE_LOG(logDEBUG1, ("Getting #triggers: %lld\n", (long long int)retval)); break; default: @@ -488,9 +488,9 @@ int64_t getTimeLeft(enum timerIndex ind){ FILE_LOG(logINFO, ("Getting number of frames left: %lld\n",(long long int)retval)); break; - case CYCLES_NUMBER: + case TRIGGER_NUMBER: retval = get64BitReg(GET_CYCLES_LSB_REG, GET_CYCLES_MSB_REG); - FILE_LOG(logINFO, ("Getting number of cycles left: %lld\n", (long long int)retval)); + FILE_LOG(logINFO, ("Getting number of triggers left: %lld\n", (long long int)retval)); break; default: @@ -870,7 +870,7 @@ int startStateMachine(){ void* start_timer(void* arg) { int64_t periodns = setTimer(FRAME_PERIOD, -1); int numFrames = (setTimer(FRAME_NUMBER, -1) * - setTimer(CYCLES_NUMBER, -1) ); + setTimer(TRIGGER_NUMBER, -1) ); int64_t exp_ns = setTimer(ACQUISITION_TIME, -1); diff --git a/slsDetectorServers/gotthardDetectorServer/RegisterDefs.h b/slsDetectorServers/gotthardDetectorServer/RegisterDefs.h index b4ea94ad1..4f9c0f1f8 100755 --- a/slsDetectorServers/gotthardDetectorServer/RegisterDefs.h +++ b/slsDetectorServers/gotthardDetectorServer/RegisterDefs.h @@ -318,11 +318,11 @@ #define GET_DELAY_LSB_REG (0x6a << MEM_MAP_SHIFT) #define GET_DELAY_MSB_REG (0x6b << MEM_MAP_SHIFT) -/* Set Cycles 64 bit register */ +/* Set Triggers 64 bit register */ #define SET_TRAINS_LSB_REG (0x6c << MEM_MAP_SHIFT) #define SET_TRAINS_MSB_REG (0x6d << MEM_MAP_SHIFT) -/* Get Cycles 64 bit register */ +/* Get Triggers 64 bit register */ #define GET_TRAINS_LSB_REG (0x6e << MEM_MAP_SHIFT) #define GET_TRAINS_MSB_REG (0x6f << MEM_MAP_SHIFT) diff --git a/slsDetectorServers/gotthardDetectorServer/bin/gotthardDetectorServer_developer b/slsDetectorServers/gotthardDetectorServer/bin/gotthardDetectorServer_developer index 0794903492fdd67bdd98ff71b3ca82ed36233e5a..e08b7748efd3112a2d521d554233f127c9eed0dd 100755 GIT binary patch delta 61234 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 nDviwp5r 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 0) { - FILE_LOG(logINFO, ("Setting Cycles: %lld\n", (long long int)val)); + FILE_LOG(logINFO, ("Setting Triggers: %lld\n", (long long int)val)); } retval = set64BitReg(val, SET_TRAINS_LSB_REG, SET_TRAINS_MSB_REG); - FILE_LOG(logDEBUG1, ("\tGetting Cycles: %lld\n", (long long int)retval)); + FILE_LOG(logDEBUG1, ("\tGetting Triggers: %lld\n", (long long int)retval)); break; default: @@ -905,9 +905,9 @@ int64_t getTimeLeft(enum timerIndex ind){ } break; - case CYCLES_NUMBER: + case TRIGGER_NUMBER: retval = get64BitReg(GET_TRAINS_LSB_REG, GET_TRAINS_MSB_REG); - FILE_LOG(logINFO, ("Getting number of cycles left: %lld\n", (long long int)retval)); + FILE_LOG(logINFO, ("Getting number of triggers left: %lld\n", (long long int)retval)); break; default: @@ -1466,7 +1466,7 @@ int configureMAC() { // remember old parameters enum timingMode oldtiming = getTiming(); uint64_t oldframes = setTimer(FRAME_NUMBER, -1); - uint64_t oldcycles = setTimer(CYCLES_NUMBER, -1); + uint64_t oldtriggers = setTimer(TRIGGER_NUMBER, -1); uint64_t oldPeriod = setTimer(FRAME_PERIOD, -1); uint64_t oldExptime = setTimer(ACQUISITION_TIME, -1); @@ -1474,12 +1474,12 @@ int configureMAC() { FILE_LOG(logINFO, ("\tSetting basic parameters\n" "\tTiming: auto\n" "\tframes: 1\n" - "\tcycles: 1\n" + "\ttriggers: 1\n" "\tperiod: 1s\n" "\texptime: 900ms\n")); setTiming(AUTO_TIMING); setTimer(FRAME_NUMBER, 1); - setTimer(CYCLES_NUMBER, 1); + setTimer(TRIGGER_NUMBER, 1); setTimer(FRAME_PERIOD, 1e9); // important to keep this until we have to wait for acquisition to start setTimer(ACQUISITION_TIME, 900 * 1000); @@ -1507,14 +1507,14 @@ int configureMAC() { FILE_LOG(logINFO, ("\tSetting previous parameters:\n" "\tTiming: %d\n" "\tframes: %lld\n" - "\tcycles: %lld\n" + "\ttriggers: %lld\n" "\tperiod: %lld ns\n" "\texptime:%lld ns\n", - (int)oldtiming, (long long int)oldframes, (long long int)oldcycles, + (int)oldtiming, (long long int)oldframes, (long long int)oldtriggers, (long long int)oldPeriod, (long long int)oldExptime)); setTiming(oldtiming); setTimer(FRAME_NUMBER, oldframes); - setTimer(CYCLES_NUMBER, oldcycles); + setTimer(TRIGGER_NUMBER, oldtriggers); setTimer(FRAME_PERIOD, oldPeriod); setTimer(ACQUISITION_TIME, oldExptime); FILE_LOG(logINFOBLUE, ("Done sending a frame at configuration\n")); @@ -1566,7 +1566,7 @@ int startStateMachine(){ #ifdef VIRTUAL void* start_timer(void* arg) { int wait_in_s = (setTimer(FRAME_NUMBER, -1) * - setTimer(CYCLES_NUMBER, -1) * + setTimer(TRIGGER_NUMBER, -1) * (setTimer(FRAME_PERIOD, -1)/(1E9))); FILE_LOG(logDEBUG1, ("going to wait for %d s\n", wait_in_s)); while(!virtual_stop && (wait_in_s >= 0)) { diff --git a/slsDetectorServers/jungfrauDetectorServer/RegisterDefs.h b/slsDetectorServers/jungfrauDetectorServer/RegisterDefs.h index d2b7484d4..99290ced9 100755 --- a/slsDetectorServers/jungfrauDetectorServer/RegisterDefs.h +++ b/slsDetectorServers/jungfrauDetectorServer/RegisterDefs.h @@ -81,7 +81,7 @@ #define GET_DELAY_LSB_REG (0x12 << MEM_MAP_SHIFT) // different kind of delay #define GET_DELAY_MSB_REG (0x13 << MEM_MAP_SHIFT) // different kind of delay -/* Get Cycles 64 bit register */ +/* Get Triggers 64 bit register */ #define GET_CYCLES_LSB_REG (0x14 << MEM_MAP_SHIFT) #define GET_CYCLES_MSB_REG (0x15 << MEM_MAP_SHIFT) @@ -375,7 +375,7 @@ #define SET_DELAY_LSB_REG (0x60 << MEM_MAP_SHIFT) // different kind of delay #define SET_DELAY_MSB_REG (0x61 << MEM_MAP_SHIFT) // different kind of delay -/* Set Cycles 64 bit register */ +/* Set Triggers 64 bit register */ #define SET_CYCLES_LSB_REG (0x62 << MEM_MAP_SHIFT) #define SET_CYCLES_MSB_REG (0x63 << MEM_MAP_SHIFT) diff --git a/slsDetectorServers/jungfrauDetectorServer/bin/jungfrauDetectorServer_developer b/slsDetectorServers/jungfrauDetectorServer/bin/jungfrauDetectorServer_developer index 066463ef43fbb46b15d07c85994310f51e1e9d4b..29052d33871e34e965f1a0a4dec8143c46aeed14 100755 GIT binary patch delta 67399 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%0DrX@cCx$XRV}VPfBe1#>a` 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

Z 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 ZATsRCMrDXJJ9+OknV#mo({U*4e*r= 0) { - FILE_LOG(logINFO, ("Setting #cycles: %lld\n", (long long int)val)); + FILE_LOG(logINFO, ("Setting #triggers: %lld\n", (long long int)val)); } retval = set64BitReg(val, SET_CYCLES_LSB_REG, SET_CYCLES_MSB_REG); - FILE_LOG(logDEBUG1, ("Getting #cycles: %lld\n", (long long int)retval)); + FILE_LOG(logDEBUG1, ("Getting #triggers: %lld\n", (long long int)retval)); break; case STORAGE_CELL_NUMBER: @@ -690,9 +690,9 @@ int64_t getTimeLeft(enum timerIndex ind){ FILE_LOG(logINFO, ("Getting delay left: %lldns\n", (long long int)retval)); break; - case CYCLES_NUMBER: + case TRIGGER_NUMBER: retval = get64BitReg(GET_CYCLES_LSB_REG, GET_CYCLES_MSB_REG); - FILE_LOG(logINFO, ("Getting number of cycles left: %lld\n", (long long int)retval)); + FILE_LOG(logINFO, ("Getting number of triggers left: %lld\n", (long long int)retval)); break; case ACTUAL_TIME: @@ -1674,7 +1674,7 @@ int startStateMachine(){ void* start_timer(void* arg) { int64_t periodns = setTimer(FRAME_PERIOD, -1); int numFrames = (setTimer(FRAME_NUMBER, -1) * - setTimer(CYCLES_NUMBER, -1) * + setTimer(TRIGGER_NUMBER, -1) * (setTimer(STORAGE_CELL_NUMBER, -1) + 1)); int64_t exp_ns = setTimer(ACQUISITION_TIME, -1); diff --git a/slsDetectorServers/moenchDetectorServer/RegisterDefs.h b/slsDetectorServers/moenchDetectorServer/RegisterDefs.h index a946a0a47..83b9f3c0e 100755 --- a/slsDetectorServers/moenchDetectorServer/RegisterDefs.h +++ b/slsDetectorServers/moenchDetectorServer/RegisterDefs.h @@ -123,7 +123,7 @@ #define DELAY_LEFT_LSB_REG (0x12 << MEM_MAP_SHIFT) #define DELAY_LEFT_MSB_REG (0x13 << MEM_MAP_SHIFT) -/* Cycles Left 64 bit RO register TODO */ +/* Triggers Left 64 bit RO register TODO */ #define CYCLES_LEFT_LSB_REG (0x14 << MEM_MAP_SHIFT) #define CYCLES_LEFT_MSB_REG (0x15 << MEM_MAP_SHIFT) @@ -446,7 +446,7 @@ #define DELAY_LSB_REG (0x60 << MEM_MAP_SHIFT) #define DELAY_MSB_REG (0x61 << MEM_MAP_SHIFT) -/* Cycles 64 bit RW register */ +/* Triggers 64 bit RW register */ #define CYCLES_LSB_REG (0x62 << MEM_MAP_SHIFT) #define CYCLES_MSB_REG (0x63 << MEM_MAP_SHIFT) diff --git a/slsDetectorServers/moenchDetectorServer/slsDetectorFunctionList.c b/slsDetectorServers/moenchDetectorServer/slsDetectorFunctionList.c index 6f1a62fe2..ca7523934 100755 --- a/slsDetectorServers/moenchDetectorServer/slsDetectorFunctionList.c +++ b/slsDetectorServers/moenchDetectorServer/slsDetectorFunctionList.c @@ -523,7 +523,7 @@ void setupDetector() { setTimer(SAMPLES, DEFAULT_NUM_SAMPLES); // update databytes and allocate ram setTimer(FRAME_NUMBER, DEFAULT_NUM_FRAMES); setTimer(ACQUISITION_TIME, DEFAULT_EXPTIME); - setTimer(CYCLES_NUMBER, DEFAULT_NUM_CYCLES); + setTimer(TRIGGER_NUMBER, DEFAULT_NUM_CYCLES); setTimer(FRAME_PERIOD, DEFAULT_PERIOD); setTimer(DELAY_AFTER_TRIGGER, DEFAULT_DELAY); setTiming(DEFAULT_TIMING_MODE); @@ -847,12 +847,12 @@ int64_t setTimer(enum timerIndex ind, int64_t val) { FILE_LOG(logINFO, ("\tGetting delay: %lldns\n", (long long int)retval)); break; - case CYCLES_NUMBER: + case TRIGGER_NUMBER: if(val >= 0) { - FILE_LOG(logINFO, ("Setting #cycles: %lld\n", (long long int)val)); + FILE_LOG(logINFO, ("Setting #triggers: %lld\n", (long long int)val)); } retval = set64BitReg(val, CYCLES_LSB_REG, CYCLES_MSB_REG); - FILE_LOG(logINFO, ("\tGetting #cycles: %lld\n", (long long int)retval)); + FILE_LOG(logINFO, ("\tGetting #triggers: %lld\n", (long long int)retval)); break; case SAMPLES: @@ -901,9 +901,9 @@ int64_t getTimeLeft(enum timerIndex ind){ FILE_LOG(logINFO, ("Getting delay left: %lldns\n", (long long int)retval)); break; - case CYCLES_NUMBER: + case TRIGGER_NUMBER: retval = get64BitReg(CYCLES_LEFT_LSB_REG, CYCLES_LEFT_MSB_REG); - FILE_LOG(logINFO, ("Getting number of cycles left: %lld\n", (long long int)retval)); + FILE_LOG(logINFO, ("Getting number of triggers left: %lld\n", (long long int)retval)); break; case ACTUAL_TIME: @@ -1813,7 +1813,7 @@ int startStateMachine(){ #ifdef VIRTUAL void* start_timer(void* arg) { int wait_in_s = (setTimer(FRAME_NUMBER, -1) * - setTimer(CYCLES_NUMBER, -1) * + setTimer(TRIGGER_NUMBER, -1) * (setTimer(FRAME_PERIOD, -1)/(1E9))); FILE_LOG(logDEBUG1, ("going to wait for %d s\n", wait_in_s)); while(!virtual_stop && (wait_in_s >= 0)) { diff --git a/slsDetectorServers/mythen3DetectorServer/RegisterDefs.h b/slsDetectorServers/mythen3DetectorServer/RegisterDefs.h index 83a661cee..83731c5e2 100644 --- a/slsDetectorServers/mythen3DetectorServer/RegisterDefs.h +++ b/slsDetectorServers/mythen3DetectorServer/RegisterDefs.h @@ -76,7 +76,7 @@ #define GET_DELAY_LSB_REG (0x0002 * REG_OFFSET + BASE_PATTERN_CONTROL) #define GET_DELAY_MSB_REG (0x0003 * REG_OFFSET + BASE_PATTERN_CONTROL) -/* Cycles left 64bit Register */ +/* Triggers left 64bit Register */ #define GET_CYCLES_LSB_REG (0x0004 * REG_OFFSET + BASE_PATTERN_CONTROL) #define GET_CYCLES_MSB_REG (0x0005 * REG_OFFSET + BASE_PATTERN_CONTROL) diff --git a/slsDetectorServers/mythen3DetectorServer/bin/mythen3DetectorServer_developer b/slsDetectorServers/mythen3DetectorServer/bin/mythen3DetectorServer_developer index f131ab3cf61cbbde4369edf1fad4ffe5b9c14104..a5c25fa1141790043db6a7ae5f009a674e566c36 100755 GIT binary patch literal 114332 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\Ilh2y8iMnHWFNOCYZCdty(0C_P-jC#c zN9J4ByF@ps?6z@l8{ah#Z1^_6JeOx=PU?(}`?0eA>i2oSew{=6so(RI_qBUWNuA$(#@um6}hyOpINmwU3G<%?&Mw2&ch1lrBbhl`F4-IclvOxQz>bJJqu=@ z`lU~V^Hl$yzH9MSt^0HE@|^Xa-g8=a-h*Y0qSEF4*Und1-;!(IoA$~%KMtIA`Gi;I z<6X>kBz`6IPQm?syEVw#KP%#H!$Zn>PR}KCd6&<15+3iW$~h!*Hq}A(espLebLYfV zX4Q3*Gk2yF?#ub^q&d&ywp1{;$}F3LJ{|3FzFcP}J8Uf9b-p9B?6=5lh%YzZ6Egbf zmsjak)Ky9z^}-{+f}3+WIoCh;#3;wzmwyJCZ%uMWezH8biSJ5mO2+Co5n|co#&cUT zHO?;f-EQ&X^ot7O%)mfmAGWVy<|(Co4bG?S^))O#{jRo^`hcO$(J|e`JvdJ%_jjWl zbM7c(r$;}LbzzVG;Vc+Myx|be;fl=r?6a4qat^EH+l>sX=nsOgKo_ctyh|YaXR;^w z-?28jxbhRFW2<@EBX9Ky;ycmzoQwKRk#RI=@8n_dG*#`DuJSKIWYFnA3G7^fF==k3a6X6V{s8$Bqr)M}fP!M8{(roz8Fjv5$`N8=d;^Y%;Nr z&a#{{atP1i+qqv}FwOX1Kh?I<`qT%pC9My-=fwX~*AdXmq?`fG*<^ncA+ z<9_p(&Pd`jxAAU3QNDG~9`dbocEk6zMfz!ApN@9Y#p+Nf>&HV`8@@OAai)-O>JaiR zbqM&T4u)@JeH(gSl<&Y_4CJl;nc@3*i|?V>)nS%hJ*GI{1CjlX6z%Xa>L9W|YOT}x zIPw<0zm2>%__CM!*FQ!Zik_e^_2a=MK2}U;g8m)ULHoC<1MfZa9T%X;JD!nPe)a+E z0Pl8Zhe-O;=lxAJ?_XGF{r!iIUlqm1FLa#mei%Fb<(h-ngj8?BH6hg-|NESbY5%GH zLffe;sH3)%_rdf!Nh@{rI0w=6rL}$crJ}Nk*nDU>6*0#Q?3a9tQ^ur2vfG0gn+oPSo3#$A zhoLX2dKmB~wzb&1?*;OBvQQpjUMi3G)SOB7eD>A0&llDu+O~(heliFhEoi6L3i*l3 zR`_{O$+y40v#YQ^QTdkaJEKbU9q8|P--*4i&%HBY-x)Q4zB5Gg3T$OCFZpxqJBh-& zMBDZq?>plQ`FY#=&LC{BJum1p207K97g+1M)rC42%GRD2RO*<+cl1IXbe+ni%!Ne1 z7<2drUwZ10TupEt%*8zBp!hTCXkY3#mO0ox?eJ4z=cZ}>WPO|WB*M1Rz4ig0!CYD1 zq4lUwP>+H&@Z$<)73QU~a@nWiz60+=4Yn3+oYW^JstSx2*=Dx2BDvZB<*y zS5&@cOnR@$xKzJ7r?4(j8JqE_Sic%dzZy1xe#IPwb@6wvUtOa0>#twwT&d4~bw#19 zqV4`?)32^AtVguX-?e`A$wI!O@*Q-)8iWrzp!Em7w^T3>SgicZShL@XGxj$xBF<5C zUIaZl9ucSP`}=)^wQqZPz+Hv>gnhx{=RGy=iOTcah5Wx|dA?P>zEAlnG2b__82Ug#fBwh9Iz-#x zJuUx#FXa6#%m1zF^O{0_qOvr$9eo5qu24vf#`uyuc{@-JBdE4X}S^vZ~_IUYQ z%z0cj<=I5lCH}f+_|1n`Ze<<1_nWOR4q>roXv`T4)BvXebAd)+DR2j{0$2^K1!UdR z_?i3OSDkaqo%qT4(9leLqb%*ySi=fw!<06|qK#4--$V`5jZvD!UxWNoO5^<1kam>P z_$F#do2WF2Lj=zrt+c}}+H|GKw;h6Xvz1n1(N6Md^4$dEFE8=WS2g=9UMpjrDpq`L zOWvtqO`iP%TV4Hjy;oM(!#;!_*4=vCJ-iR}4BwQ)harCBpPy!8`Fu+?zlQtF4T$mN z*n42kSYsYy&XD3a!Mg!fuEfPy+j{@CvQNUv-IOrrKNPGjRp{D(gGQ(Ta8Q?M+kf3s#u3bPaydiiD(NzlQ9`_W8Kv z+M;XZ+2skx({rIhKJ{Fv_!?Oo^xrA%WL?b>d6;*!ID=Kb19>RrU(-kV)>%hJPQh76 z-_vzF-Ys=iY4m-r^XPUfEa%FL=|{`$Mg z>o?>j@Q{3CsZ#1-_~F-_p?~d)bs}>Q{q!zQuPe}x#g=|{tf2nsKa8MXCtu5Vb3We& zbk*$Z3Ex|}FjOC=!Txd6_@iC4n_a^YB%eAK~sjFFDP{?=&xnkUpHbqreZs$ zuuo?)``0G1e{CXrdE^?KVEXH3qig2-kMi!JoLMaN_>*F%SQ~%t1%D5bk?XL8n?87L zyklzCaaa7%*Nr!7yOYS5eLm(Jj_S9Y{%P#Yb2o^cNjZE&$lJ=?3YhwvSVDeB9pxnI zUgmonw5@y}rK+IsI<9*`x--tVXBZb;_o8%X@{()U2kE8%WOs`lJsiClxs3M7k}l@n zs_i4+g6j77*BIG#`}=F+D;a;J?7zL$@wTAXE4bdmbum4C?jOjzSGVMR`Q(;bTTj!y zdRmK~x~ivqyVK~YTZt~Grgl=_KFf&og)N8J7iM)jnMK+kB0NifaNo?E?@k~m`UvM% zQ-^FB?;oKHNnq4u_zQKmnA}&W-0Q|hWVFRLy3y0!)1_e%Cy zZPDYmMUaNWx2l& zSlLfH`G*bA@<}V*lbYWuO}A3hS^H;AUk~=r{;j6_k*2f0 zEn?E?w?*RjYP$P1owZ-pqzm?|-l^&SNz>^*+OQtFk2bzc)2-5Uy5}@Zr+ZH0pVxE` zXu7AVFW++u(><;A?a*}prs?EcTTfZ(_zs-eFZ@YO_n@ZZ8+geltaMLkx?o@1e`q@P z)XKM0!gBd$iOKIHn%~bg9s7`V@3HSUKC9_2)O2e!o!M(@<@b!HJ5$sBr>4{M1Hy7S zpVpLnio^GaYt8p<#J7|)`(1o7*Y}aI`TE}MF5j-n-dxws#RB`*$vBYRSLT>!K5^|I zO!|Kq?HF5E%+43{M>Zd#4erYyxwd_gR*~`;FJ(M1J_^77_?g8n^FIC6zeq`1 zcRzb`UH0advp3h?mmB!z`x)!Y80%xq69C!wh5z3@j`7^QD_l{|{G`OVR;<4GJcs0e z*<(%-AFSm3COX$F#&6r z=Q92Zekl9@`JP9rYO<4v+a%JCsr^tlg_(OL2@~w1ufPdk^oa1H6AClNe>T_$Bx>p)5SZ;;&aLTp!hTJ#5@*1weLLd8gA96NSW(JMs}U; zG=9BJ8Pr$&8&mHu`SsqjJf29>PRxO%zUgF){kdlU|L~Oe3Ud!2v+BHRzDL@VxpQcO zZUU(R~l*}W?;s*{{0skv|Wp-bx z7ysL|oV}h|^%v7U=4J9dvdpTkv1Wc3&0pr-ujiR7vBpn5N|wK#_Z#l2qFuI3%G@IyDc6>Cl07iFu##^d&FJ}?`BNkSNhAi!{xp4m_v-=nPi-CprURw z?`mv5=v|E=I{%BVgD~gwSc7KoD)Bt(!>_DKOMIyA=auALWN&qJjjfM7vRiw?Hmo z&3wN@;zi<3@4kWP3n# z0A1J{(S^N!%uQk)68lV&wrZs2C$SpQHSQT*Bk$xMy_PyizQX?##7E5g2=q~Cqu4i> z`~e4hD9 z(fU^m@cDB}JRcw6^Cy*fo*3qU>OZyk^GV*9k#;Euh#N4t{avg#C4_o zB7LuD`MYWB{_0O&1?3;B<;&P9zEaR0JGI@V{33m~X!#olP`=S$^e&M9iCVtK&cpJ9 zZ&*nAMf!fx@_#ab@&mmO%0FGpH$H_`e_anTwzG)sC|dqE2T(qF70CZwE#LSiR{6TF zWXdmMdy1C-=>e2aUIpb}s^#nW9m+o#zeWBp#SX~Y%hbd1P4wF2!92v+lzEzm+OE*&QQKwwNwaoLUIVbBMeByoRI+dJE?Zci zMaql%UtxU$|0`;b0)1p|W$JR1K5xc#OCI>##tviCirV3b|6u$M)?@AO6cZ2XPJW_$ zoh!Z#V+L|c{8gTL| zeu=rsH*AyeShPM-AMoHgNB3056ywJa;g@{OcS^;dlX4gnI>q;bF89O_k~P(WF_=8X zhm!l|e7fLUu&?|m5xid?oLx4RGP=b7+LMi$^$gwvHFGAOk5{4_1Bp+4sZiHLJq>hy zf4+yf9`hjD-QumNe5`TTt0Xp*AU1S3v7u4KhDH(_I*izmoB{h9ek9)n<2=zGZzuUP z&Pm^){hcKD>JB3&i0#ij;wJp_MbQy#G3T~b8u|w4*d}i`bbdK!!KV|CN$$vZXCAF# z{$Asmw2vM`z7;Fv%s27-Gk3)~`?Izuvwm_qv+BMHhPHmH#2J>85B@**?jD*>@{OR( zBk7vVs`O+-dt_o7*kvFn9P%*qf?HFBbU_q==qnLZxFK%`lEa= zJSa>0p_FCn^aJX|GdVd65StuNpj%>#xt4Y_Y5qpjP;bd6c>wuI9xuq*60Eh6htVy~ zBS}70FW2%70n+BzU}s44Lz5;U=TVfbO9>gtUf800fVTey?ccjTxBXb+6w{fM0n>px z;BsIAa5JzRxDR*`co-19H#YEZs}J4-bidM!9oKaKsx*5K(1S{|_W=D|Y4#qVUn$#5S98 z!HNe3>kLLOSYu!vBHS0&z?>JorN6N5+)4k%|2E^X=$yp4a_ENcZ(=-fW7-eRng!Qo z47JA=S@ETcy8?N;$a|okK8|babS|zUV^zO6n7?e5HR>tdZwz3=z!uCA_g7<*_x=_5u5M`&LAG%xYN z;SF7JOkVU?@lD0&jK5#kbIT_B<%)dw`SAqbrub=B$8L9IpNNzpCPnmw*&lxB~s zwMw(c)q16kwZ_Ktm1d8t7c0#kS1(hVJ+5Bq)84b=>c_7$K3R6gn9}2FWA=jL*9gf4y&CFOD>=m?Z zyRqdm9tY2MX!&YKBtB@$S34r}a@jX%Y`}@cx)0QLC$D3!DSSyk=f3pwuDsck0T0IB zI=Qb<2hvFY49ohgmSt>^zAq_t)%m9JU$fWw_KG^?*i$QepT(9-9N*lZ*5cp4wNP$i zTWq-*eq|r4@?f6*+I41bmy@`s%)^F>?_Hv=A8KFz$yW>d^4OEv9}k=c%mo^OrNAA) z3Sc#`7T5%A2SOPw*FJEv)qn0*n%$SbqcpoO|3GPWU;aC#*?swbrP+P?UzBF|ab<=^?V_iSJOz2BGXKG{cKw)V+;qwtSL;vdQPh1DMo{SU?< z(?8H%=^x3x_#}JQ5C^F9`|Q?<)y@~`_Zpv+erL)J;*<18vj#8YsKk&Zj?KJ$luN8k zXmTxSzal&Rw$@i@+?$UEZGoBp!^ z9hAH&N7l?ppQwvVpQ#rADV5xxH+{44p8p+S`hD8pPdzM)O<0y=ZBCx|?L#&9Ce@kxw-&?vrgiFcqZpIX-V5Avy_yfPn<_4DLBi6_8^_#ono7$4+U z%rQoiN3Rc3)Q>-eJh5Ri$8fsxXPNnn_%%iIeB;0tZ`gls^@hf_x`2mm@|c5o2iCxE zo;f+Ne+~0emCqF_<2}E?27cZ@|3_rJ=X8HP0NI;&xsY9QU!MIz*mH2!L+PXVR6#zU z(0m+hgyYYfvXYNu&6{qcneo%QOUL@~g7{0+%QlB$}>s%rUPofXfcIZg2%x}~( z_EN^)&->q<5n1i^%W%t(;l4cjn~k}X{&BYP8E-ZHDIu|Fxi57!`u#=CYae;-v)XT8 zZ(ip4+x2&yaA%YD(osjQ8S+f_?k=>pRHCKcaN>zq_pSDjgVKKXPdKC>>K`pmlFHSz7W z^cVJhy;AGA5)+JNH_suSkm;W8%yFDD_s-;*p6qSr9OBHf84vjJsl#jB%U32w9qFVq zYlp-}jdW`2c`wNH?X~|U{g6I+o0r*ky6g?g;(v&rLcAusnR(A9x7?4{__m-oZG5Nj zBKF}n@1XPxoWv+opK2%mbT6;MTgdD6@Tz={N(gVmV!{{i6V+taUJ#Rd3E$`{Jo@}0 zw?6ozEac-F8yJzxg~>BT9+F?kvyuFTpWF8}Ge zDa$jQ`(RG*sO()1N{U; zzv7HbFFya`b9?WYdvg|^fAKk&SVYnvUxYUMVA`xGNy<8LVg1=>e%LCdmo_^rrI&Vm z5!wkwXmg6tP7G;hwJm9BOt-dmq!%r2ZtX~SENDv4Yg@RerKzJS-L!ad+v4=XruO!R z>zmTet>$iP(^5@56B~An{-rPaG>^8PkiM*G@r_N3GwH@QKd%K%^KNKQ2g$-;9(8)l zUf8fG-O)x#3)>cddS<%5q4oNv#cfO4g*dORwWGOpNt2Z3I8)k(o8R7N7d5oEr>|>h zZ=RR#Xln0hPq)oapELK|Gtv#Mjp^%_w3p55nBO+~2&tKfO(6r#p z^xT%FhW4iPl0}UTsN;MUmuSM}3!2;0je*p|0zyP{OV{`nnwBPcb8Aq33))ne_rY1! zENpI_sq&a6ig=yhGlc(^ru0qC9ShKKvbEXr`3fjOod(QB_~3vGZ#Uh|?;B^?(oN4u zw=bDDkG|`-iEzsQ($gEF%3fm{U`pfkbkovB=rP(erEyweThgPX!Om%3%3T_GQ5=pwDtOZ%IdbMq_#+|IL`6o;}-fGGcS+5&ZN%8$5S(b88dgl>UCSW;Nr+ z^wG1AKY8XX{+oStm}Q3im@PZbOkm2a<4t~3`1i7ownd@Mya+RRPD67`DU+2xx2>)5 zx=%M%5BK%Vx3$u&^D#ZM!)9IB*0=-}l{z2S)G_b4#-9yeZ$2mfTImCs~R)N zVL^t6_~0NP3uU&bX>oH~V=pT~eo=Z*ug0d9hEMkQaNo0gjX-YmoULX19rLKMYVt-#>Hhus#fOBPi4{Q(oG%u%WqCMggCj=0oDfaTc;i9L-EGX>IOkxAYU*$LP~DaMC_5tn+L1{H!xB zyX-vDedO}->xPB_D@p zosY~t&rfgeoqw@p_K~?4^4z88UnI2pvrPWWE@qDma1XEoxF2{B$N_7Cb-;RH1F#8r z3V0FN4(tK~U8%=Cpf;vT)UiO;k$dSH5-$9RZ=VAlIj{Np1?d~xS~~F5OeP;0j(;VV zZV7(f^=aG>ljpF@+LkPy*Cc*Q+LShPN~8aOde|@-EV15_bC6El7DW*t^WZ;gSU8x6;m$AwFwgj=OBRX&rRKOj zw0}dZ43XDk*XR0!9J+Qz+u}y}ZN(rqHyV3y#-N$$%N7{-8PDLlrjDDMnp)GdjN9oC zOKCICiS&c4B%^eV889RX!b+RWEfV8e2jyf8M~0<DFF&?iFYc0+&KFA=X7q*36@8WstXn;gZH_7q7k91J|Ehf`7 zCZmivLXkGIQ~3>4DzVrQUxyCjTP$I(Abh6jeI>O>ST4%1WMr4$k&zMA7zEl&cr_^w zX0$h95gspWYg;ruXs~omdq>0Kj!+EK)9rXF;pMdS!X@n;;u5#ex{N3dsD9v!70J7W zya!hG8M93fDpq%4(5`l?5NIu_cvMc&w0+lRxFdQhYL8;7B^NmeRJkMU*EDpI?ttpL;GtajvjZO1- z+D<+N+iIl^%aa_%5#aet7Bv}9Od=_Z+gg;%bX%*R58lLZ;wpGj|4(~o10B~@-TOO| zY)iJ{+OZw-1(|?DoM6izn8X+pEK9PjWGpGt$Z?vqH)GAn5|KxPX5`pucr_48prHhw zfzYPdl+Z_ufs}@lt^^7+Eoom$^V&Q}`_dBH^fi>MHbDAFOG@7Fzt1`M-jU^$vfk=i zZ!Ko&>fU|MKKtym&p!Kn?RzdfanBSl?^x8xgm>PUUmnz=3Ugu8@obs5vM{4Eg}fx9 zc{2isaf$KaMJtUz($&>v3p<(lkoBG+Vz{z@dRhWu?lWW0j75{#kgdo4q#gX2?V!(= z`DUmF85moBsZWpHSYeDdG+nRTa)%4ZkIj_o6Vl1i>W$Uuo2vQo+3Hw>Wt)738G%!` zC_h%3V!jEf5IIid>(#BUxu|a4ROIrk9Ii0s7OK`A6ZF?h;T-DDKtdqP6T+u8nYImH z#d<_{zlQeF&cWfHzIb$~x4YOUc-P=y?~ZHxqT#+BgM*CtXC1$h&1zyddl6n~jODUA zO>MdwH|SOs=5XBXO|VVN;?g)v9<+0ep#3RqOiBes{v**cLh59#H zmiJFK0-`;8ME9H`9xNS>6FPByVsg9@DJ)In1IeR)q?%;z>ou;|DizFRG+Caqd~N9( zSW5=zS2QzQjmMdg)+Y>&`YToI2PbXO12o0UMn%$)_@p=+wOvErx_@b5yf&ekXK(^=-Vlp;<@+Qf$ly1J@Ih& zz^)+g;lci-jN#eJH`LeHOS-;&{VMG6UK7^NxG>mrRTfq~7P?1@aZjPYZ=e|W4|#qG z9~vCCx^Q;HV~FNJ_l`mzRW%Ur>fhDv$_GA$inSoHqrYf!6(2+0MJYtwKZy1W6o+l; z!Ivk*^%zqj+LblLT{Adr`j(|t7#xJlIe6Wav%9xfvdiLLqi_jwPWYbg5!p-AvKSg3+yxYC4@hazaxfia`3+tJ zmuY_8J;naL)@vwjAEf%4)g2mXTPgPK@%o~tw1&YE+_x8%a{AOgT9gJ5*xNrM^??p; zX}EhAMe9RxXe`n;@zk@s4<$uoM|_(b+*xGP5se$}-?dAMj2@%ix(B;~e)aYhx~<*z z3=Ul@821n_T z#qTL`go&;dU#L4(ck#gJo*l-c=$|f5>8>8_PV8}bR(QX(Z+LWw)T29$rjxDcoi0x4 z%sLIkaNU>K#<^j_8yfT`G4O9Cj7NKiXf86SG`W*_VeYi7H3@pWt~*gSRyA!(8^T&c4imPU+LXPAN?s7~I@EF=gtOn#CLYn&e> zAqM?p3`;d%vi<4=pINq_(6fS;OlnGXn+6S5*X^Ii(IB(EZJWGu!0)iMIap#(R*MB|v{gNg%uCfH`O?gRS#1R|nL5R{Vz|9Ep_;oH4e{nIRf89yM7L>(^E@^64*2wOFulRTK61 zx(zJpYOkB~*tYIkM@BP5t0(PK+D;dEr`t2~`zMyQn>j|2?U(FL_e(^qj)qQT_ED5~ zs!NL1jucZ z*NBxzB_;3H%4~l?@FxKuZZTl-fE2wJO?d-tWPym1rR`l?S%Y<8eDB+l*oH(x-Ru~YpRQ*0?RcioR-zExoS1X0#(^Q zY__VBsXf&)~E-Ze}J$0={&X%3Te3mUJ!1O$Hoo2_V+n8l#EQ<8Z!r3 z9dhcSTmx>{YniiK+O#*ROy}8WTB9`C-8<|vdo0Or)qLBuQB!_y)2wN4b1q*~Y&&Vs zhFd|~2H2N8?QN!!Y}o*2HgNJRH)`KVhDfWQ^YCpXyYfa3WyoWmGQxKzmM=l){$YX=I*F`l6zDd-|KCa`V+)Go7Rg)Gua* zJg@2{<;@aF#O=D)d2z(cT)i|JGL&-!p&-Ah>38){Uk>5^sKN+!mF64t1jflp0y_oA z@tqIhdrEa@h%f;3T}|OiFIy3CcTm-*!w+#v6UI9dpNt$U8|)=z20kE(?%4D!K2bAy zjF5BZv_YLSQbV&-^z1df9jDgjadec0KkROD-7+JY!LbH*aQaZ?bjS{uP1~AFt^8*+ zni-p(VMgH@Xq0CC2srfPSsVt@DxUF<;~_2?H{yw@E?cDteP?RxnIDjgR=yTTLyS?) z5lAegD2WcSe=&JT{4|ZysXzQ9>9tN77{R~aw+UmZM&%$|CX6<4j}F#9)zNHh*oO>Q z39SqT?5e!cLl>R!neUz@kcmYtU!JU6XPO`dI*gmN$C1|_hqpcnPLF(kRGi=`ye{#% z6;Wm?&N#)Dv~xi#sc#2zBuC_J#vkCi+eg- z6MtkJP5s;vY>%|pyS8VL`ZJExYr`CL%yMBn*6(rSSO|rAQlFNcd2r{=DVdFiIwR9W z{6*&*sfH2ie~N)qrP{0;VGh|pNRe^BTua-o%9wwPBj{({lvi_wcME&gEVTBE3Al3O^LHmo@5@?gqQkiy=k_j8BCK5t|lzYJMY@C zMLAn*peJqz*QE$~oEo3fx9M7y1qW1PZa&#K<(JO5>huLkOR6zjutk|QWjq>XkPZ-i z5ED1a%FfLdTXYC=!3n^S8S~N&`Y~*>RxmGJvtOms*8Tgpj*V?Cms8(Scp5F^8sgkg z53*dLahjZ<#^4>br$n@`izX&;I6cijXawF)DG?I6?xI8`I6eXdXI)V>!{WCBt&q(%8%oy?G@Cw+cl-%< zN|7DAx;3k8+0%56FO6>Jr|aek*|b@nQNM(-Z2CDkRxZ`WobapwZGinE`J{{@qZi4` z7(N{x??%>S%d$KvUd+zr)fNkaNWEQuu{>bbumYcR^AM9EeL5*LD>+``EhmzjeGTbT z9C4Q7iPwST9f#()M7VSKt}$KNYkF*43>o-r6UUla2 z_A^7wU@@)!n-*bi>pHU5hlUnMeFK9#Mt6=VSkHU{ti`HaHhoZ7GG0pd zR+3_$#?8|5eDQQUX2-`FqH2!O#S%wjCRv;Kk<(q6FHTQ0n5j1|%n$GiwpXsfD(_KZ zpfr7DugPx*WmxVDZ;GNvF8(6cE06FBHtV#0Z;BFNQ}ik#3wRn0^L`4LOyQ+P(RI6@>9ue3(LOH#E+DHC~A$MpKae25m~u?)`!MyC=4 zFD%SZ&sA-*%}b65PmKx5yeNbx`SDVqrj+yI`M3mED?jsPNqB-&**h;vWpBchE1Bev zFw-tjJ7)3{Pu}fan?JxfRKio#d{m`;fgg1Yb1E^JkE#B`l$14E?H^D}uHmCj)+CY> z1lSLk|7d1gLxX4yz%Xt}YhjyFt0Zhh)mdxE7kh@7O`PuCGn-hz>)iKhf6`C=`27^G zA=_4^JC0#-w4Qet)&n4B^(7ZKc;%h0Bm|qC3P7HBDA>5NFo&zN9Z0N`9q>M=l-MgB z85-QtJ<`WqOun{mWrc}|txM`o>OFQ81XCr~`FTv&`HA>X>i5U5UwYN#z0j;5gyb5= z*jYb_ungOAQF(8E4HknQ6ysrz{5MG_lDI?E<==L$H!Ho23esFH~1>F`Z=v%6f{s3n(ABv>HO7vr#6*YQ(L!jQ~hV$tJE;2 zrNHnK`bBlUp~ibHxKV^P}Q?(UKUc_-H+Yoq84 z?#FsLtDgJNg?7Y76kQxe9HkLG!}p9-fxRtJw1oRIF3!ucAIEA$Lnm?(QPD~Mt>nIl zi!;-r)t9>Gr!L`a4&ZHE9G`4?f?C_2Z;5{R!VA+65f6XU;_Dgiy}&=t@69Aq{wmim z|CcEG6|Sp)pM3+a|LAYcadG2*8`ee9X09z<+qkxK^>XdzDsT;P6}k3tUC(s`SD9;q zYl^GJ)!;hJbqm)~u3NcoS*MnRS zaXrlS2-l-rk8wTD^#s?GTu*U5&Gih|vs}+{Jz%-zL()GF>v$vo+qUX?Wye0@yiU(&cl-lzJ^XLmq35+7AJB8}CRp3hF{aY*+`|9O9W~+a z7N1)>KBnh>J#Xu{MmSf#h3D-Z8^zn65uSTHz9gK163;t3_6TS23jXivSSg&V2YBAy zah<}i{jcB@I$kdP>#ilF*zxCjzP`-!z79Sj5w-n{c(}gfvtYLU?1%Y(L&s8u$EaXb z?)aphZxBBd9d8uP{rW!@wN8=Qf<>PpVlgKSMs2TJvV(|)ZR_m6!aG$V;^qt~h2r?+ zSG42;C@yR(>hTeKjCnL%DTd)*48kW#VXCt9xUk-N2ayZgRIf{=tqb3!fThog?l0Qo zZWvm0t~l*HO4OIRekxk@Ibl65TIVTb=`LZtOjt|5tH7VT^26D|l(A9yeL8b+}l3 zxjjBjy2Y>4W2dl=09x^L(b5v|lH-$vEIk+AmYlEz9eVtTa$PzmgkLv=^A-9jLs+86 zPYYqiMS46tr{LCA(CNHXwa}_=sdN2b5wNiBZ~4FMEByN|mlZE+y@6z%m;F$p+Q7fg z`~Qr%rLR`1F9>bv<2;_R-lUcT;f#JgwysfvpDPfz=n}QkBL9{iRpxDNZ8Cms?X3p2 zw;dvfwq>pT5bN9wT8+z!{X(?p2A)?ORyNP)6u#p1ATMoc(ep~a84~5bm3uAE!T#j# zS~VNOh~+m9BW=;Y@Z?Qa8FZPfVB5rQi!(bd&Lp+8nDuFKmdRLedAW+x<}KR@BwAka zvxKxb%hsA#$ZFv%=;tx_rfwd4dvZDmHOk%fCH^lg`QQr$?DxP9fJKKvTnroSxnk@0 za>e%CD7Vq}+}<3A5iO8Ra&HvDWeLGEbB>?|k9mRy+$w^~d47T$Aov~;92UX5cjRcg z;;`-sTJXm_K?A-D&{3@%h;qe>9zpD2gEq>Iib4T!@zaoT**T7{QwEnS`Z+p~liYK6 zDPAJ5;FwerfdTgexC~ya45UOZgRP=qcA?-i_y(v*rw!>`An|O7mK^p`|7uZ1qKZCh z(VZE#D0k--V(WaFOx689V{0KpY9BZw4$GCQ2W3OfxYUvuTYEcj42yCvQ~FOOJYFF1 zF+fN!&t0^1#gf*g=Pg~HJ9DAFGvBg0TC(JdC9Mp*TF;7Fmu_A1x+VQ9P$VC|l-l?y zP{>#}MJ;+|q+9!nT(It1^p`=^2)B<8_qG77YJWP+J5#2cR*&< zf~d6}&OmLUkS|tn3OH}U5y*ms{*os8D#Aja0}@dVi{AOx9MXONj&n9jH1B#VL!qAHZKbQLfXA|f6set@- zb**=QQKWN_f>-UGT*E&D;TF-=#LK~^-b$i4sZ#XJ-qHfb#{IINL}N>^|SSvkjHw| zx&EJ)(R#f)^q-PlG^eIiZ9%L)YP~8jauvC$YfSZ9Zl{A81Q+@ZnmDUEZ@<(_{z7_{pDJ# zZ{^mq@XCdStA3$yRpF}E#oujNedZSm1G`!~u57>Jsy(eYw{L6zOzX|xZN2%*)|;+u zJ@>8cPZh2jYX1~b)%I|(+<;8uX07uWnr-~WwZ=>o>qWr21uAOf&N;V2%PouPqF%^rkJPAa)MmJ_DY=H)Qrk%lX#mB|asf@K<_ zDQ&gkKEZ1}ksb0`(^b~fi+dXt1hIV+E=B-ye$_`kB_s6kHjXls}K{A=tB!rcs+ZL2K+#W4_w5GPpVmZNyh?ss?IVv1D=C zW>Z~uJF3&lX}UJ17YdyI2*KyKpQ@X!xhA1L1kqVz*+jE|m9$N`Mso=Lo2n$jminL}zK*i-tpx<~Db5!J}@Uu*Z>yxP9F{>ZXai7%N_IT#w&(F}gj+;=d5F-?H(>G_XWpODoMFTMXaeHx{H(wsJlyfG}?IaaXsGa zqr|=#6`JmndR7jaX9@>7JjP8Z8Ib@5jmz_>{4+HOb!Xd=g<;B-Bo*m|Jp2sa*3f6sy3*K}Sfov%N=lQL?&;>FcvWE=`Y*SC$D^NtM z2Ce+GSD+tXLw67CA?VjimFO4N_W81?!CL#*uhn)9ShG%GmDlYd=-z5O2X3#z!M3Fo zZP1bqzgF9sK=>O1tdW}A)6l)ub~vKw!CqI6Ru=E{EB;b|`EVD%v;De%t4TA8@(H}$ z;={f`Yjmc;(TR|Lg~8ej(XZ8Nfc4Ce1bCH&A5Gx141P3$Ut)0h*BYH29_`*5G5^i{ zS|cq&rN7qbycFQ6)t21Tpw{T6DPZw0n*(1E{iqB_ zN5U`gbM#fs_?_!g{NZ`$Tx0{*TUq)s(|LO!EKGocNGdccs6Z_@KYCo}UE{?U%0;MxO@`?L9|(|HC=>e=!Gt z0VYNJW%{+SWBO0TYmd|YR?_3q#h}l!jLXqyzGEMqe@QOdPWYMddoJ)6^iA=CF9qJv z` zGwCwgKcodjSKd7E+HYc`J^ohUJ9^mnq^l5q4{$NV&tBkT-$=__2Y&W9;17Ds*@4zJ zM)>7k6SAlQH z@bgXJr;*QnK3+S0wePVX>)}=^cFiv$GY>BVe&8LH5xFS83xFTN$OQUpfqT#3oPJhe z6#shQ_OVpHdw`G8zQw2F_X)qp4Qd6KfTuG2HGm)Z1mFAy-{b@QG#@*=&*y(Dum)03 zdj4(){$fU7-v?a&Eo`oj{}}M$4E@gu{)ij#D*rzQUWUB4gTEYk|4-oJ71Xg$|M$Qf zFrqpNl^3;}rn_JPta6k1a^`?L5UpuZ=2IewP9dbt5AWZvobxwti|q zdx3AiH!c4(@Ew`>Uj)AU!d%3s<&55kxZhA=U)0ifM#q5W10Lm0YAAtP2UZCG-Ge}DL#Wg3taxQ)PCFsyy4Hee0%x;@D0C@ z$?*CAH{d(|Ce_z_fFH{6^A+He1IWjh=c~YvvDJR3PyaRGXEOP#U0?r8Y5vaxKc9(T z)=u5rn%aYlf%ol5>+dq)=SQL8^Xma_Ur%P1Uld&n{4mDrVS_uPGVsa2O8GeqTw@SH z7jF7~D{$D)JhP=UdJpg|rBok23S9mf>d4FIGr;#TU)s0YCM3DgPG(pG2QR{C42Nduije8`*>1 zz}x>YEkAw+(b3;Y;R)c?U8%ip0I$vP_YUBF2=4)(|NDTqWa2+2eEPp&zkUZe_|M4R zJOq5_|48%uOWN(U)}IT3aj|M}L^g^Buqwne-n5e)jQH-#-cbct&2o3;fioTy(zIp9h8C zlG^950dIdj+ZvwVZvpTA+cdxL0^fykQh%iSTC@aNGl+i53e`TP(MLGM}Qw-{4GB{@p~h% z=BJ?3Kd*{z2JZdqw7%a7ysyBR(bw<$fuErM0=<*Kx4%0bAN>LF(Tx5)20WFa{{--@ zZ=gT*^!^d}`MXkmXg!1HCsX)b;KCoL_V-o5w`b_T0eIr)kTLB>B7&j#@B8S2c(zXkZt480Ekm%oV2ynIdqKgD?GS6iE1$^u`kbzJC17LYvkcIKPWGTFV+^wOB|8s!XjHT^+GjQ<>=#=N@O5l4k`CSLB z!SchNUJdwxO#It{JAXaxzdr!{P$vE)@MeVZgirqk;72p@ng=xQ;~&3e=>KDiXHtHL zFVDAukN$6D;@cyx1koc&ebYY!KlK%ChNr&{_$Yofw|n?H+J9KDQTcZeANH0czXI?V ze~{My&jR22%cSx7PXa%&UffBZ^i{xjek<*7-UnRUL!0sV9|E3uE~WQL;QKQC-Va<( z;8oEd1K;)bv_1Yg@HXsQ(Eq;!-ggasf~Wt_z)!C?c8s6SWyp*1$KAgEUJm>e?RUHJ z+Zk;DE^I@;JbVT4bD8wV7h>x+r1bU@-*zI0q}+JA1iUO0-vCa>%V+V`U39$$kDkAG z1Fyk-FVx@rfuE**(d0}YKLPylr2J<^_W|d7((&Fyz{e`+gzsPf1i1D=WbWxd4!pTa z8eiV0mHr@Q^z?JfDc?(TNqLt8FMC~DKj#2H%6v@YTIs_pfp1CpSrx4Vz5#o|pT%zl zK7Rv%!K{-5-@BPS4epF$;Ag&>*7p&`e?9GA-UYlSlm1tMpZJrsJ^dzd;eKqY*YEp* zZ~KMRe*Gcv^Vs*iFaKk}ClY?oiv9+8bB6x2z$Y{DIh6MB5IXJUxfD3;=Su%y0=)ZP z^vlcR6~NDaIL&`E@S69)qtE|!O8@<|{~83|p2@!iyroW?^745T@LiwACiwK*$fuCO ze>3qMwzB%gEHh(E%@yu)=Re+zXlOOXEm1h?C2G*Bu^ZEY*@QDol z4+4i@o`>H8ew_X|*vl^h-;Mmj`oq_OPiE5p190PxbiVq1;QKQ1?W<_-Z%^fW9&oXi z+JjdDH@=I`k+=B04ERp;H`t$Tz$?F#j+X|3wf>H{t-Skzr(PgWpMDm2_mye?`!?XU z|Cs92dx7u0G?(i>j~f13Eh z=Td$AH{d5fL7VXL3(f-nhbg~j1K*vL=d9=zz_+)i@_!BR8ijCb?-u8NW1>id} z>GuIYb9*Y^Hv(TzdG~pIHhFO_7+W{P7punb-5Hx{)Em4B&SM9pePTmv2flGo>TW+2uej=B4W>eAA>EgBs;a zVDYX3FUA()!JRvGvU|}!IugYPYJB!bFZ%Q5ygN*-E*BOKA@YY!PF6?ECkC4E#nYZ1;$$(N2QjUrw_xJex06zqd@#Sn*+ z!rbSTaKiD~N8`?&q`$ZaNra4wdpPN#S}Dq3BfKo%D>n_5Q6C&qJDs(S)iOD97J$ikW_nWJXc{jYds7@C zfmPAbgD6QfPDb@65~kxZ$Lv#6R2O;Z)F4!kGXP9TK?@y!E(>8+(Q4T$D2`sXnUg+; zaZZmb<`E-N+u1ggRVrF2fr>uLL5XIS180a#FqQ(76#)~70!S`!yIw~dt= z%|Vrh-qQ98FXKOhVM&iE&oqi%vI>Wh-$UjD|7)ePEaC*;>ajdgeMj4t}#=cs~|GcayA^8ZuF<0`d0q_Ywnbi zp1w3SW+#f)c>%&_R&LHrhqT6a@@n9UuFJg9tU$h(j7L!Lj5n#u;VUTVKgipwQGt`8 zP338{^z5>|sCey2Qz>P^@XNE0a75$dQ?vDnrg(inkSuL9sWG*u*U;Tu_V})!UiI*0ZB(l9fk~PN6ccj;)A;!{F@?h_ z1kB2EzQx=kDXytgvqOoR2$VR=R;8}tSZ7Ds8b_fun8lEU)mIo~=tHw6-NaO=58H(6 z=yY|eiH3O7NBpu%Ls%k2b$h-Es=KV^94%KT?AI1_#U{+*< zLE-yRDq;l87dtF)p4^116SLFCF;6cX%%vQ4k+0H(Q}vuC*6hsdN>d*TmUVSD zBET3}SKq|FDkrpEorvx}{b`{Z@@1nZ)$E;;qGyfr_@*XGiKDI3l-)-tD3;YnI>1-m zI^j?SvA%L4Xs)pvs?4aPZOY!b)2XXwmz%QAa*0XAZ=a3~Ctl85n`1AM7NLNR<(V(ehEeAB^@ir3v^hrvW<+ma5K5`|nDg85O> zDPyFusT+I!=Uq9+oq=pqJ*vO2``!V1HjA>hz{yOU=d{5T%pXc`hTRUOk2EPr3NI-+ zZFa^*LvY7xYJ%Mdu5Es#zT22BF9x)3^ zrp%!1u=={qyPAqMSr2`V4UKwb*QEev_ciEhnm&e)@6vwlWH&#%YNDw8!eRPNtxg}X zNGklY&78C}gArvgRV@$O;qpUT3B2E;dp>FWO3dOQQG4aRzooJ|>3>|p)qT)+<& zPU6h;8SdlVA(oTGBiC%L*G-IyMn#Ol-K#D0aBT%_8lViYk`t5H4jM^Veo)qdsl=Lz z(`<`ZeFr7z9_r7IJ(|$cK1ibsGo6qM&FK_lW&;IlFF1Bs4fR za9gQpiq(W@&YTBtZBB!pQEtsno@5%3WAM8|h~O%u5$b+a)3Tr`l8_ z>aqb(SA)@H)WslrlDKI)&r;M?nQ(SG>avw(vd{vv<)jaL@nC3Le(kEe=Q`b4)MfuP z?_|*mEZJX{Y&FtSY6B;$5UFVAm%>7$KZ0VbT6a{GA6LTY?eW zdeO=Yxd6_|q*a`Lui#>9$nf-D2wU4x9yt88ucF^ZF19!gZwS00@J?`rc-?hf&V>t% z;psh+XJ9}+vPuiO;Vk2h3rW<o>L5A(YGraA|MC+x=g1(e4llawxCP z8&Ys6?;SsnZ&!#UTyeTC@_0PjZ_TZ_=-heo6|QtN{CeMk-k%#q7ZR|SOQcoDG;7l- dZuXPU-_K|2Lv-}Roudiwd!K_|h$JpN{$G^3F&F>< literal 114332 zcmeFa4PaeWmFRzNa&r6K-hQ0kTPWeCl#)VQ+ESrhl>`W1%0~r6RJ5c`N;9NMZBi(T z_Tr>i6`T&DqT)=QVMcWDy^gOlqK~oHF%I>KV_`a2prr}&QJ_G97W#evzqQXgC;Oh> zo1~F1-~Rg)3v-jF-uf6u#Ywxqq%JVKhKNgEQ!C#s48Aq-r&T^bN{7(Lve{YVH zb_O}s&I!&WCk|ci%}M*v1ujqlxIj5Dj>pDT`7nWN0l6o+37Ee${{kILVg}@SC*j{u zwZ@#(-}=y8MjA4Za^*gkPBr(dxi7GVYXP}0WeCiqkeO9Jq`4Ld?p^*&dxM?-4(Wegkn+z0rT`+J z8sH4z6krr^0??noL6Jm5t?R+yBlOy|75HfD{zwZK9gx3q{*U=rbYM78sk9;dCV`21 zeZ2mPe5V2;%iu2^Ap8ykrUSEqX~1~kSU`00G(i4RfCromoC?U_`+>0rEBxma1lE3T zOxtm|Gm7g5X)yjou0M%6&Qk08n_S;)U4Mz|)z-D}7yP9`J^|cm-EScMTI>1{_wTc= zU*Z1!*7d#I@3gM}j_b9JetpLv(G2M~S@*xk^;YY8IoCU^>yLB2+q(WP`2|9f`u+wO zu0oUR(WFmV*Vl7B*}DE3*E6l_cAoiwb-kGD3$5#VuCKJN%X$7<>-xi7H(S@wkbZ@A z{UX;L*7c*LUt?W=f%|t`*U}e*zeylZ0_&~&U*S4uT|Y~H4_ViP(1$J7_4~PAe@@KF z@tny2eWZWdy8m;ocUjl>lkT8(eG>NvONZu9(a&+XKCZIWv$Dg zHj&|(XU=bHTUg(+$Z2Y6Y@grK-n!IjYr3wbzF9JDZmn-$-qO(2u!vewg%+o+vAJT!)Z_;v?XA~4OP16xbrxOM*iOOi%bH2Mq;W|b{LY_Gfi11`n_Cyww>P!6 zI18Fu8hUbXliZgz);Bmew6!S5ZS4)M%iARbsp6uA&8=;X6x}WoXkE&U`et&IJfzxf zO-2~??fy?&hEN^RWY+UNpx3@O&bVJh(Ml7M6mMm`;g4W#B zyME!qMoOGNzis&fxhGVhHgR%Je@OnS=j&r~#$eZ_g9O(ifxox%50I z*D?N^2PX+(hre6?`kS~GWloxYD}QzLl@sX$@;6U#9f+?KTpSest`=O!4Cz~w#o6HR znzb=!iso~z;5zU(2rfhk(Bof~(_kv*0?QW(8LV zq(ktLe)`pdkMi-`1lNkL5nLUVI|UbG%impst0Qo?;OeBT6l97`I{-YIL!Rb5nLVPxq^!W%-;tDuQjMsEBM(y?jFuR={ebL znXYLL-L%a8uZibmR!{$l7t3v*<76GTHk-(-Ugag7Yy#a)L}{5FXC-QB5&Ecaxl+L7TU{ENePoO;BmSDbprsdpSX#F0xJImMA%96833Yn=WSN7ivbt#%b#~eKJn_$I*v4`Vmh9=uaGdilbj~^evA5#nHz&`WZ)GSMLar#G`{t~DE#OY6Q`d1t$Jx-sC(+A`9$vAy9J_x{S#OcRz`gNRs z9;e^Ou^W)_y|d-+)n9GPZ2a5Lt#@k6lit18C&w?oKC{?ayxz%`CzCrq2fo7KDGQ%q z;m26`u@*kj!jH4?N((>U!qXOBW#N-7`~(Z1Y~d$b_!J92$-=8Ge5!??Y~iO^_%sWj zZs9X5{8S5{Y2mXhe71$3X5n)z{CyUFx`m%%;d3qgObgFg`1>vV0~Y>43qQ-kYb?Ch z!q2wwb1eK^3$L^A^DO*)3%|g^FSPKBEc`Vruqcc$xRA4`_kK1SM@dyZ3;S^eb`Nz3n<(svy9tR8zKw#CqD3Tf+kcDS6$_f zyEno3I@+WY8x?aB^sj{2pJ=+w#){ED-&B#<|A(Ps)2ctaX_!1)UF=!+0QHR3Zlw>q zZvEohuyCtAH@Dp@&uyjtTdCXD%27^&GF-#U#vdfy-<;Hu+4%kJ&o@EEuqV8`8^ z`I?T*>Jt;##k)=)>Ws@BQ|{Ekdj()pcB{v>;xp}Fb+VNPLjOarG1^zRnFjY zWAj5=Txr<+kTybT*!++-Mrqjmkd{;$Hb10IR2nuvq*W;mn;+7qC~cfYJ4I>O{4m{2 zrD5|!+WVA-%@1iApO#r2b4>fU-79U3+=e7-_mnw8&#XS9%O4X(?tUA&Z_*YOw1o=| z@ba`pS#7shp6y1zy50Rw%z2^A@eXe2a?7$^9_=D+lUY3~k<4%4er+syu%_F2i8P0} z2aGSL{rFAnr!8G4(eBj7+?tO}g%>9`z1&HXR{<}oW4;bK+v$5-l2@+XWYReBrTS!i zgP2_Vd?xexE>qXre<-?{N?uXqnMbMLRO(mFGbhz<^QJi4yc6j&lj$=j)Nb`Aq2qGz ziu5M$%Je38e>Rp`Jq#J5FSk#v%8n`*KP2W}Ho7W%e!1g4O&yASj4mC&WL9>bk!b2PS0)Va(42&V?&qse7>tr+&o7#rUNh8CR0e z^Xu@tBj25TZUgNyjCMsIzM$>(D!jdF>BFnOeC)Pi?v)7J?PlzjJil3=e~sr~TiI>u zAbsOC|9RmfiJUU)I%P~q2;WKSCfAjzh>mUd+q82;u{NbF(PPowH^}1+t1aIs(Uw^9^=dPb)I|OYQxv9=jf~M{`|Aa zL5z)YXM3^&eq3kU5##J&wa1aM5nC5?9vS0g9(5BB;dgj>$^zEL=;tHR3-FGZv02zz zfA@zsgS;n-z(q~G}beYlXnQ16vLneRw?o{#bTtnj&y>T`@M$wOAX z4)xT_JHS1lXuaN`UPGwYU~K&$Y(BrHZVj66exBWL)os7lZ7+3mZ=sGGx^|aiZ`Z6z z$XF;kFCg}WUL*QNFLz1-;J?oRfZ;QIAwG;>!(FeNoU&C9}}{Mm&Jv$3C94d z?L7LK(}9NqN$xy*%~Epk0XeD-qR zH~QR|s@lESna`u6UqHt`zoEOcrWQYKNFs-Cn*4lCcka0|NA8*DzI3_xnh9ql`Q5ys zOJXIR|HgAS8@rLnzFda=W?b^qIYGK4X)E{CB+!d4NiV#abgTXRYIjnW*wuWVdx1Vy zq-pEwqBiG$AcKz}gL%jR@P0zw{ui(w_!r<`fu92R13v?P4*YN60RVZ8Ku+FzJlRTkVcynok{#X4j$7JIc08#O}u&Y*?mBVU~p zw9_Zuy_2hQ%tb%AoDsQ<=067DX)|G0@G z{Z&b4d;sPI;*)EvA>qDMgYUg6?GhjG=e1JjVT=hwQqB{uBWcZ;$gkiDmoez&nuN>) zO6!@i<7Un)G%kCok>GXIjf%RWD! zcw@{je{Q7wr}a7Y`NRIAKEK2fq}*JY^g}cLr-DA?w>fr*T}+wPqpAPc)cOb3$J~`a znl)$h?_+ge-$G1pNG&>Xp_7+*N7O#c+us*fFp){LzD4RnAM#$NE_PeKrfs5g z!>~ZQK*we?d&woXBW0- zmt|*nshuSbkvyRDyV;s{KWUlAiajzmS?94bZppZq#Fj^GMW6E^m+`)w@ePnUpLdw? zir6ncOLr1~YGj#%u2nekHeVjs;_DFiP0d)6b*g3jy5331x@z(;_8s5Lx9@&`^L>|5 zV!vw9j}o@KNdG1;f6bsDdG=Qa!aVa`tbue@5?f5->nF>>W7$-k^=%VBIkR|Oj&3|U zx;mB2`>m=Q>&B*TtR4G4P9#1Q!~*u>{}Idbh-J9|b2Z;@LGO&;f}bKfAu-RiwEY;` zp7n6|OZc3(;(tDhPeEGm0CGi7@oRkFq(=1@zeRk2u+N}x;-Aafxx0!y@QX|4agpXB zV>RPXmSXl=g{Y{zn}w>*7O(YOYj-(FGc;y9mpk#T*f08!0sn9 zXB=NE^AP;s+rOT0clvo2^MA$15StSEy)UZYi!6!Bj1FXL@>=-yM4a|Ac*ECa4P;C5 zaGtu1NYj`6IQ4Z}PvY6h7cCn?zEV%&P2yR7mFtp5^2dit!vkw|MrJ9ed#vNfnQFR? zuXZEr5ynq?5Fbh4*YM?x_G6AE<`hnX@h@;xka>&aK=0noKgzgO7) zoq=Df?H}@2Bp=aHqrb?$w{)(ln?J|RJu%i_gDJtAF9-2CNA&P`kMbz}1lt|*$UMNb zhiUu1=f&C0G7l`0E)qYM{z-dv&6`bM#7?`jSx@0wXyZ-%SY`L)!u}BU9qkWE^2vQ@ zEd2*P_~_bANuX%?o9G9p(hp|P2d1;$HjNnkDa6lC&TjRlGViHo-org3W0y7^P8{Df%X+&zt)uTGcBWw zGP*1q)TL!mhYb1o>tZ!sN!G_GXG~J)TcFGO(~HpgrA(iGM?8^42AN0GiOjn6M3eT> zNiybUSrZs-uJ6<|nxM?|LYMZy_wrta&aaWR(C{SF(w z&K>QEpD6cPtMO#6!!`07ZD@DuGn;v4H_re@_A)1sXQ-bi^J1<|owjoSoAFfg3G#kq zaN1)&mIN~E;uE|#cwX*HJH83dwP`2P!h2QniIuch?PJNU{JOQY7i|{GNA>h+m5Z)t zhy7jGvy)HKPETq(y{>6>EjUc8Yr(G5;drv{d%THFC6cVax)M)W+JWs`m6o+&cc{Ov zo_wyRTjIQhGO12w)>V7H98N}O2d!nTmGOqYMjw|rrCi@m%*^Piw98)Z@2lw=wwL;I zZ-m@KU(IvG(t>lRT&rG%X#!f1W-w{6CEgN2rb9=du zpUdw<<+;?jL@sq+NOMNB=LLEENBYWG5B;kZq|HB=8s}_E-41T@O5~jL6t8o0P6fF5 z)*mW%5+e(FI8J#` zId%p-s88PWoIjUAPt(Y-_*zI*ZsZZnBgF^Zf{s-VcFcOV!7IQ?lf6miA%6bx51|Y2 z67DauWqnB7d5ZFkj>#M#l(qVR?0+L(w=yRCex=-G-l}(y$C-t)4|OGwJvAPY|mdHk0&o%{X?R@+56_pqSrSC@a4lDX)S&2F)$% ztL?^D8-}ko6#WJ~`huBL2YNgrqQ{pN>O&}7)d$hz_(vS}nbdT7ZvuO3=xZCgOgvzS zlUgfrfe}th=7jDS|Jv+Fk#wE;FF9h*P|1k0%tnwa)yxAA(W_|g&xA03{WZ${F zN@=$$P2~I)rF~Ut>^n~e{o; zTy#$A#_*7U3Uk)FM>?$#G&!*S~X`AubrT~|=2=jkh^QZ5KUWR(BYacz&U=t)hD>i}O&?cDja@yvU za~kESK8&9U9?=EH3dZ6Qsj&Q4wER;2CU~B;g3wOUhMA?HL}fX*=ip{KS1rHydTr^9QH3LS9rnx8JlV3-&6kr*;aVI zeJsEl{mfiJle8Y9r+LdCgfEd%m`~JS?W?S4 zyhwe3IB`Yy^Q`N#mm+s^+^IZRgFcps-&tiyzcn(k>to#y`Lyp_^`%d4b=l96Jv~l7 zRf+6ue&?>rmfV|W<=s&x`w57N*?C*{#h&$gKV9U03HeB$D*CR%Yj+{1p0)YC3)$z^ z;5cbu4saoG4X_mG0PX_r19HG-K-$){_jK>bcNI=k+H5ObMrroD3N=cz-&Lqn+6mUP z7b(qtSK(5n+3zY`p|o+n&^{>1HRYZRcQXGc~>Dj zH_rHiow4Jr!Mh5U&WgVJ^FaC{i)1DHi4_}_7-;Bkqf2XKO!gQD=-)Dbld;I``?=Zh zl5kj~#&=G5|6S9S{O=9u2x}oLKkDy~`=VD>`;oZgJ&J93)E}D+?~nSn!QH|BRpLC} zBQ;&#A8NW}&rluvb#ts8$(oP%UySW5XW|H^lX zO&kA(4Jns6pF6>i*U4N};&nkgiY`ofKYZKe{HvDp82LPAmGhWij<>m{OZM?5H=vu8Tl{Bpk7F}PFL5-HUG94cNBWYH-(u+p zy6TX~gQxBW zf2k&{SD4p)KdrexT6up?dD=#P+brI<`8*kZB4dE5%M18Cw1L5QY93FL$CFmQp7iqw z{femnbF}04Q{Rz(9KLIK|Mi?%0(1epfx*qZ8xPC`>VT_(W*`gP354VKD?08;oGBR7 z_bAOCzYi+S9=~Jb{juL3zvD`?$M0cEv&Zj*((LiuQ`$I-mt&M>kKe~D%^treE6pCi zr~0(_?D#$7Du4W5-~aL3=-64~t7?CT-m8yoY^>y=KDLaN1-?KK6OQbQFR+#Lm+Y0i ztvkv!@7>gnVNWjkxch#Ta3>Jo#~#!jN6cS-kIgx&^!L~DTgiRaHQd46=hxhqU!MCl zznv4gU*`Xw$8TMV=jB@N%eCas8pL___z{hka@S^jX0JWD;TqT`18jKzkXGT+EI~u zHfmnhJlo`Tz_RhmYk%f)cHKBwLBpQ4OaE&A zW(9Ugx&8t?kn6AdDc3UOdTK;(1#?u|?mfr&shFbAjw zE(Wd!8i1w1&A@8lPGBu?A86Iy10Dc2 z0-J#@U?;E_a6e1^fr&shFbAjwE(Wd!8i1w1&A@8lPGBu?A8k;kd^G0cgTOf`(9nm2 zU#9q2@QW2sfnTKfvEb(`empqmdzxn_f!8X2BKQXtKN*~ZG)sK2h;&z$Yj^AAG#x3&F=Kz8E~A z`1Rl;6mJ3NphJ`YXTS$3z8svuk)huN9#ecJ_+gdv7r_rGek=H1#lH%^NAWe_uPOd5 z@K+T78}OZq|2_Egir)+Vtm6Lz{Ev#S2k%n+XW-iu{{{Htig$wlLGk|szFG1A1br%J9j1G z>lBZJ|5)*1;6GA)6!;Gm9}9ku;wkX&D_#lyH;PXJ|E}UEf#0S0RPb*oJ_Gy?#ZLqO zE5+x6-=_Fk;9pj}4*XWdF9QEd#V-ZVD*jRM&nx~3aQd;)lX`G$n!y)?2e$uu@Xsi{ z1-wP^<>1#Velz%D#cu&`RQy)(1&V(Ke7@pqz^_sKo8TW;{BH286#qN$D-{0$_&mk$ z1IJG`eEtOdLyF%Ieu3iu241K5zk{Ex_=DhQDgF@n`xSo}e6He;g1=AkC%|Vb-US}` zN6&x<{?QBIfq%3MJn)a+01y15gWze+r|jE3{=y*eW0XD|JgN9-@L;?h4<3xS$ASmr zZ5linZ>N9<v=>sI7opt_ZG42b16nddt9mizr6ROTpiPL-UV?T^gf?nt$~!hfy8+t7 z2yG3t<07;%FQvT72<<1(j*rluftHTYQZJ{xstD~|XpXiv&JD?)n+8vE`G>_#41 zZG?8_8!7MX2<@~tQ{Fid+GWtrjnF<1tu8|QduZoHXb(d>KSFyG+658X$$L}Yg%R4P zpj{N9eGS@&BD8;n_TdQaX=oQmXhZju?X#B(5{Zqz6|Z-5!#iM z@relSThKlkp*;-knh32dpYlExq5V(F_;iH!GPL;-+7#-0ZG?6;wE76`WXf0&p*2EV z7@>U|T0?~PAhgB^?Imc7BD7<3Det-n?Gk80INrZM0w3Z0%Mrf@O+V`L>jnIAz?K3&fxMH0eh?mQHg|7SYE4Yd2?zi@$*n2%9 zYx2fk5OWOT%H~>Q!)9GmW3^^2{rw;J&js6ea?crM;JvK}l#FxBS)KMfv&3&@Uu~41 zr0fwqtZVrf_ELU{7OMW7M zvtBt=(#f8y?3Uy~s}5Hd)tOI0apO7gdf2afW$@lFbu{n&PS-fNEeqZWHnJEcdDfV7D`fqgHZ|wpnRlf8 z_oLFhOYHC0xUR6?GEeCDv&#yf{gY(&D*8E+b(j&XzYJ#`Mt&{1A^RT zodno7U*&O5hv1pj$#iD*1n0AV7<~2qHHm98>k^apuNir@e{U@JJh^uvd*bJ1*8NAC zcN8v^eS4kg+s`+-64&%$<4-B4LLlLvO^EzoVrOA!J-#hTe(} zvS!gPx^wdczn|*fOj$26YY)NROzP&C{d(+aq5Wk~i>#^1I#>s5SY{n;l)nzvF~na7 zJ7R6?i1q2(nERI>pDOKV&Zc5trkv?5dUhD1Tk!GJ7>w zpHX@bpLN!n%lT-smnyJPf$a|TAkcf!1;amelrzvfWzCSYTg{r`zQ33%Yqn<1ko#hT z#=p5CvX(W1c{FYK34-3s;| z?av7vz3#CCLHoMHzQFs;e%s2q6V9V?b7p?_<}ps?5X$2DI@XSPHsKCCt2?*q$TeKI zg1ttRt?!Fc&Y#wfrRvxbqYR@%)}E}K_7$U-)|xAJKy*vao@4F1fH&E%*Q<_2$9t>) zl;TbH8_D}|<`*7aaQd2AcNf_mA!9N!W4YP})9)YDx?oeq7Dv~QYp)o5M1AP9u|De) zJrCgRsLwdRK2ldxmrZX|U93G1X1_x}>cUv;w~O6A$hg<`IgR?5u}$mqgw{uGa@aP3 zO(yLw#y`#kNL?FaPoL~PHP17aa89#~Daa<}p_d*uP})9uINv4mlD=tVwq46moe0ZN zpUu3xY4h~Q301jIN`K@VQ23c{S&yEJUUc-O=L3+X(QkM-Lf@eod9tU!q`s5Je|JmA zxo3N??|}9FW&E+x_+ts)BLezkKTUm*d&&B7&(yEHMEzK6OOnRCvo7_-CougRKgGQ7 z{u=umMrIS0OVJB(+27DE@#i1iBfeX>KW_8a9mlEP|^qZAnXF|7uva( z{5}|*#}fEiW-j;>^$p8q-)7cvcUfx_ugcm4Xa3`#COPlCUHtCd+8_3yJ9{kq&pbiK zGVyuMypnO+jL+Zkbtyd*dov!KxrCf!dBhlbK=Tzp`3);ydDl|%WxNvq3m*BV!*|RX z(UMng;b15JMd~a5?J<%+=bkuUOjITvKc;2P-(2U5W{gel&UYgpe|}c+iPA9uom+&y zpw2DiyFXH1<+1o8F?k=ze@AI#^2qtK+&6P(yG*Z_GWA`ruuOb=slTivQ6_US>@sJ; zne#7S_wn4zu90U!yPkwB4(H7rB(rf&muhz}v(CAQ5q0Hi*zstix+r9S%pSXdu@f6VYEZPtt4$(R%B-K=B$`Cf^!Ezs?#FGb(& z+xO_jUoYiLF-C@d6tXcslzWKwV62xpNa&{$4;kzKN#stxM z#(mG|;Rf?QuIcxutNgV+!*O5R)AaRe=+|CkApN9l?2$Uj`==&evNzu~W&DwSMedot zvKQTYQ+2Dh7u`}_2z4v)bBwJ}pXf5>yM(_oAboi!eDBG$2kj8r@Q?Lg4?iv6eaUmy z8ugcJ-*+=}D&ODzwB|uOi|<|++50&lSw!QW{nb%;H2p%xL}H4R-QBOg8h!t|ALWJb zOVelBd)$?sBkvgo?>r4jm~Y+i9<|H{Q_TrYtGZZ zcb17at?I>2i#;k5QU)2seQ!`7eNSZ_jt?s9QaWE$ zCkHCuZ}mgICp(GU@dK#;_x$>E-Vw4hv9xqi+f$#_KAa z=E4)?y(GSC@~r8H#P(SW*-gxVd+xJ&-ih7NW#$!+=ULaW&dJ@Vvfm01Tdgs9tNJhS zX6D7rQ6&$-#h)>4@&jm(>9-nKgOGQMNz-lk;d>jx1GY8gakiqzxAaV0^fBU}7LP$( z)Ye1eYprn-9r%s1PAPL>@-g|DwG!$h_k?c7-G@IR?>#2u8*9SPy)M4m=Y8J7_}zDY zSP;Kk_m8|o@Pi(Z>)Lydgssp8ByI3akWOgw&U5maJZs<1mJa+{^pUec_3Wj`Ymmpv z?(8z+Gwdl2(r(GujOM+UG_p)pRvqb61m9LDB}X|6QqJM@%QI)OQnwLlBa8p)#Ru8O zbK5LGe4F3K@?GVCx4!BTrt{B$Eok%Xy{=BPg?bOQtN?zk{Ejs2RTBgMxqniUSS(OrZK(k+7Gsq_jaovZ1?k) zvkcraf1XARE+un?cO`DGYkWt8FlxL-1r)5oq zxS^jHHsm)}KgM@7Ya$2HYZ==Q=cNy#dveyZo;&-JmV1Ev2dr{~wGoNS+I;Rl#;lD5 zZRQSSePjT>fw9-r!TjRC^tlfB0r)0;DBpd(*Hh9K#DGsgriRA5oUA>iu~Ac)U;BAt zyH5Axmwt>_<2Hx24CGa8ol&0k+dyN&<=>TeHc^-Uhp{!{?6SMcv4>meo z*VkIq0OkUH%C^#BU5qwB_n23eUW*;)*GKhEbk2|I3_sS7iwnOB{ve52PA`*4F;tInqbS(VaJ z=v$OW)*pNJg1G;wXRSrgJQ=_`xyY+e`}E<69X(C!Rbp%vn>&8C`aqlwAv!o^xXxcz zHTi38w@j^aMwdHGVX$Gfe82XS1#~keGZq>dne!!bW~>PFxkbO9{eI;|ZC_m=W5#IF zN7;*N+M-s|>9`!G({Xvd@L=&K{Zhu{?D8?bPHR16u0Nppd-Ob-e%L7HP|WYLTj-xL z_m=0+6rZcp(u1P5aG>i&wB-?f2wGsLWvn^E=c;GDS@sjXxuMJS?X&6IJTut2B~f|& zkv_0#OU?u{`Vg%7o%h|I_uwx0F3+2ONuShxdKal)6x*M@kAAh!@`Lwjo3pmw|FSGQ z^AXh%V(hYp73zqtzq;s-(Gzq}Y^0fAQeXSbCy|BNmfmbg(CCh-}SyOIORe zk?h5h^OVTT<66oU`I~t^{YJ{Q^C+qZz35wqlS8j^MaRWbHplSyVVQ##iF@?n6Nz3K zJ)w`9U+jbVr7v}AtRRr9lp|xlXZorCjVZI&Z;|L)P0aX-pUxPhPV*ijy%q{DQSrpBS_0b@&I$|(?QeM2f8sydSr{;ye2YJaD^C$5&T>FmN zJJ~N_+9qNf`_#WabfVba(5PUEi1tM4bT$^`tedSNC%Qb~{>5PnP z1Fp+J=Zf@4Q>P+*IOsbr^Ihq`MfX0ulk?hlgV$ZeR!0$A9Z75z=yzoMkS1l-k9gYUyR{)-g7mKj;`M@7bIEO?x(UCt1sOZkN4Ph4#8< z-XF$ZW>TlQrY>2n3uC98*B$m7-M8fqL=OkB-@vpbGB>}-)%?Pf`K9jWw@BN|T&_;X z#G*dew~-HNjam50>OD?*1kLL`8siTFFIl7 zfR;a}`xD|$IySXe6E6VW1-*X=KU~{jp@(Wgf~=&UsSoO9SP;C zc0}Y;psN?4H^|i3FMdnv=^Lu2`+Ct8X&=VAP*;N3F8hI{++JQ16q}ZO1HJplBKv2LpXkQ{MW2`#g)-53k@VkCU#jo+_s?P%P22-r>21zZ zR3BbJ9}?)pDD(m7w>}iHdqyvc=?Q6tXXe7OqV}*6nMi&2=Z|j8o1wCjeuhqkvJ%-6 zH;}P1T=&D?7OeZ#qD$6TSW=gQaqxq^w6*GQ*w(=~coOwuuNJo6jDzycancmbTf}Dg zeZ0sxc&XOU^c$;wIt~WDfIm)%uE`iNx?1KnvL0n@*T*JSF&~umyt&-34a%4GJYx@! zc0K4VniF)0K9sT>i;?kyzWMsIll66d*C~iI zNKC8Gap$d)bxYrT4M^4lh`SnlXOD;A#?F<}Yq9;LDew{YV;dNUj2^Z3UN`aK-)Wg2 z_5A(wz1QI#pYs+QkD!@$Dzz>o?Ibn^-z-_oA6%t%R39Q7chrYCYCAO0`TW~ax39g$ zbsNAsr0G}UU#hQzPgC4)7(+XeCX5|@TX~nUEwEX|;*teEa;dTI zdwut#ciI*h8}$!;^EDv*8$Anz7*sGXq@G3N+(u7&>jS0iaLVuB1#>pB!}!~#j`#K5 z2i~dmBgR&s&X;qS^WzeDgDdD zn9Ld>?^Rf9L`BcgC$4}GXy*Ixv>qSznD(=N==|XU%)QfrrB3zd}iJ; z{YbgL*Lh5l7`#cN`xV%?;qO;~_dec-EGX|9VreZ$2c`!AI_gN zUN6s>H7}Vf6SwPN-BivskvOvVW}f!ZYvOJmF>n({-;?heFXwY{U)EMCC+b;UyE(UO zLXmfrB`-MxkJy?QllS29|Mukl^^G~7DjnC=IbSH}AZ}cRPf58+_%VFIkHj=9kA)9e z6WI$NsUm!E&+x&shL64ChbkZQdf}r)d^zx?`Zc}`bj)6&?N`DN{IeLdmuVeDKMz{I ztnN9JIt<9iA7~s2y(&4M;hwQcrQ+wZ-YR-|5S=q?hCwXY>T@?~eN}J5KBwyvN8M(_ z4?gL={;TcYYvtQrpg*?O9rg?MRTX&`Ciy^@yZaWI<74C4lO<<~nY3o!-$Nr^r`Tpc zZ6X=nr|^6B`pH>hzh=HjT5lBjO5Xdk2`}+LS2FQHcXHIt{v2jS zMt{J}W&E?uBIR>FS#s3DZpp{2Mc)3Y@SPoVCK~rUeLtMNZ|wi#{4#G0`2%L(F6SNw z_7VTm%zdPuVjI^}zSvf?XYm`l-|-IRaV&X^y}4&E+t?l+lcSWEZ}-iM)M?IyjZWt^ zkD2r5=WP6qQ}@*;%(?UJ6Sg^>!yY#0&Cl8Pgj4s}7IV&g`?t3`9a}g1=gV*Xt<&)- zo~_6w=4||}Q}_GdnDgX!ZvmgM&733Oe#|zf?mOf;IG0$T;$7cQked7~uwcpEOqB-d$q< z^8n(7flou9D*fI?G*6>`>Av|HkUZawn9WYD%UkWMyc>0Sc0BR4 zN@8ip<+gegvs=AmYqxsGaPB;`XWndY*)ooqW!uO*m{^HScj+wA!)Icz06XW8}R= z=3CbLLg%aOc5rV8-!~6z_zu53muF-y=cM9(tgNs4UE10JNE#+s{ZA@2w%t?3f&SuB(!g;CG>mk0eBkzYkRO5`6G{GKLGf%zh z)8RbTzo+k7T%&b=9$uce-j#Y@>(2YCtWk`1c~7=KW@`oO9m5S(i_EWj@}? zTu0(pLhlgVpJP-bYyV7#M#Dp@cBj7gm)qhO_B3Liy{8MCOi3sm!_s zlQVau6Yk6TuB174V^u1cTV++QE-VrkT=$ALz ztEe3EInPKZKXb7XmfN-H*pWny{Wx#q+`wp zmDnl$MAn5p`a-sOB=LsgXT%jf$X2j zeo)?-)^`DK{B-HqYM%DUTYZA~j`aD!o|IhAj*O#0dnbp((-gHwU%EFjXW~Yu?l?d8 z(f+-yPUluX_A%$e$DPirp_dV}c;X4iow(7&K6Y;bKMvf@CE6c<%<1^9ANy#Z@R(Eg zy{#tp(NUIjMhxOPc~{~~i>Dg@>&x0!TA#Wgwxsnz_ni3GbR7Y`Ov+i!oFQiTj_|pA z;x@X{05{n^5v;O1M>${|hgJ1KQ z)A?~fM&o|_-<=V}X9!Of=UeCOA>TS@H+)}Pq@M=%=_DsztPX{;ej=2$;d_f8XA1eI z4k6!Chk$SDVE9JXtI+eJ@(%pPK;G(~8NPW}FSIX%v8zKYyLxhQzWXEl-6`7Plhi?E zf80i=;|b&~e18{tZ}DX>^{;!JHWWQUU+N}+OMI-D&IJ8CsDt)zQwQE<=6fqZk@q(v zv3%#J*n#Q1uRqK`*Vwd+p6?jo(x0Z7_b-Uk1?ORYMaQp-V&fM&&i6Tt9KXcbRlB8c z`f*G1ttHhP#;byFZusBPB;6YA7urspK^?W7ybq^0Nm{9^$9aXOFMX@`zEo5e5qr=t z`+T^j@BL;cV4JC{eL)PH+fB|V6Et| zzArE16?7Ssj>>KiU~DRw>)fYxC=qKgx?^}|{0!?~LLNUUltermKufFqOVSS?VE!lTQmgqas-|@b)N$b#8 z-x=ADzVm3IJfiLUXVrJM7uF@(w(oe~*-^+(RJH@|I|H!2_Pn6i7~~XtUSP!_cNOYf zC|i48Fk0sYeD5x_->x${DRUtiiy3qHR$h9_pj>ru9r#Kfb5Q)5bhIz^8Ot2#o_6>t zuycF0ezLyJdlF$=>As7A&tR@B@6dYGC#XlkzLUd+vI_H3S-As=iN2j}KCVQY$B%z+ z#+^qN@)eb@=~wSH8JFr;USVDO-LD4IuZHxaUoi(^UHskaSCv}7zWSBUm3r-0Qwn7j zZTCN$esyYLJ)&(M9jE%VfdjA&#`Z;R;F*PdMddr-e)V?wdYonB`_eiuI$QadvF4B! zXY6ZUM4Y4Oya;-9JR(ln`*-#R+7`?S%sli%y|+O)u9n%po!0*&h4t?UV$53q_mnRe z-6!#hLf*qZp}a@?M4#<20G%uF2No9c6ZQp*pZByp|DurpKUtoCs$RD#KPBcYCKeOU z^Hra3F04be4c^o8zqOF}KUw~Nsy=_Mke{e5jcv!DWvzuckiTz>HtG9)>jCi9uX%jb zK76B)|94%UcNg;WXD83UE9C!Om*)=)`T4Vx=l?9^|6P~oPYe0^vy;9M%F*Ejon^;r8$qQx;&exyv$$s48P3~`y%VmJ>OQHGdSj42wVd!1v-Gcfct

6^90U?W_?|0y8$a{6$5%On%boZc_|O6EVWqK#71FjSZMsFvs2ZUgisY0}UUBJ#EB) zB&KEdK=6*h2JSOAAjaeH&XqZ1jd_SULyF%7?*>%55*K4_Yv{GIPr|9aIbqI!C|Fyn z(6#@_c}c9trAM&NYy70k)^0Mss+=Xhzou(go;cLJwVNt=|0sFs+D-C}OjGY;)|&Hj z4L)&gLelAeY@d(HYm2UtJKsn+o}81!d+H&ddM;FagRBku@04~R|JvuNt2wWX^H*8p zJF4<$^isZc){&7@aMsb^>bf28mqgFb?Fjr8IWO&%GKXtt1aSwcLvEknZo`nF=s`AK z?%d8jIWO0B_1p)Z%Z)5|j=COmd#Q(>sT9gl&s2&pp&l{xMR<+z&fZ6m-KS_nVyLFQ z#@?5ZchbDq*|WmA)VwpsnRCK>@EyWcyj#ID(9ns5Il~cr=3w+}ca8ZT^GLdU=b&uj zvkzBbGxVEjo#o1By2|&`*hOmUpt=tYnANfk!x&%>92ef30?EgE5?S%H(!Mwe^l%gYvZrK z=$(%u9m#puZVu8*|H<+F zAZ!VGF=93ClQp(@p0|3uzB zx|O7k$){>;Jx%xMX$^Yns-E(VO{1soXmmL>r$%R!4Wx>O4l2`wwE#%_i|72oTsu|Lpsyvnzfy+ z_p*(>()Y6CKh^z6pV4%BwrHpiGXBVZSM$C({#2W$W8bUpb@ly}=QQ2lYkoIsI_ujW zrd<8DN1U@~4SzRjI(-K_EH^ka^{+JD=QJJrI_29XVLJVGNqm*2`@E);J+^!sBuvLQ zIZQo1r|DK|I@yo=l9lcyP4^j1cZ;Uey{Tb-x;Hg`ou=#1bh>{xOsD&Iqvt;}<=2-2Tqvo~2DE(3Yv%ZC=vZ=8ey7^*nsCark6o@yX;K z{l~+8uwP%kp~N>N(I5F0J0QRGBkwtUlvnU6*~`zjH&T_8oy3gt9G)`xd?ykABlobA zzE3_Vkt7fCgNNZ$neTku;i9K}3#FGd6P>jQ7sxzPVcy}zt`tfCAp7#&sUs*?_TYDj zO!$re+Ad$_1@Hj>!h_kvY|0;$XwPkM+}s9y`_-u)UW%lL2gzf1P1fn;ePZ#S#MdwW z3_LL>#pmoj&pU@&^(j*3W|5IyXFH8wZ&L>K6<@{F`%8Yk_pga3lC%@^8L4kN8Dp=l z*~>pP<-Ni@0?4epu!?Vhc4zJwoZx$)-N~2pT}iHcWYUq6^UP%7y01+0m}AK|z%uJP$CSX^RpdP#v6sTT z858)G{xW`)yaOI{h!;GYj57{Y)NV_<&bA}oyBMT%x#*e(^EZ$6Wa2%<=BN+9vc4>_ zp6oB=yY@x)Nk`YqddVZ#)$aT-^zI>p`S$k#jla_;+Mf2`Bu*8Jx|e}aGd&q=4+itW5y{xSA?{F zo154G@7l0FUfExs|3&jA79@MWLY{T+m*IJm#GUYei0#RDCyajYMZU;&%GloHZk)+O zKd|cZYb{S>Y?803i^kYYtOxnX9L#)+Lt;PTlYDhUN_Z)%Bhh_umX4S>0Wrvtl^Sm_ z@m+Mm=}c5IC3Bq)KPDlvJuEtaE--H`(1pW({47bkN*psu+R71{pNa3nBlnE1!K<9H zZmy*clCSXp6tNETZUKE1+DP{Pn>p*3^*e8?g6~x^kF~xbWWN1IOjG9d-Y3^?l03Xm z5=$bFqOyqgJ&mac-z*beh?(@9;lO?K4JV_set*L6aN^%YPmx1d577^v72mjD&)-_& zd33X1&)-nudDaE`_57j|&%6D6{;CqsSM>Aw^GiG*@8|QUmw28yWxwh_rTFtn-ieWR zOd?0$cUxuhL*Ka`#=8+E^g-67i|9iVdCIe5JItK-58A)!b23hJvJc1fZ?UOj1JR?R zdK*1gPW84khTfZb@rJHyv1@!k+?3O$<>(wdDRX66Q_wlMw~Mjh)f%I-QdbkFFQWT$ zPO$NL@K0oHFuH#xeRNlzZ@vhx^kJE&!h)bXhKZxB*-!0Pjik82Rw(hI`i~kiT115FZcA557|&FQxBF2(c@@Ziyq0f#7OVW=J1y3aXplOFs@7aMQm5m z@;}~>@@2h7>`oy6leK&qZ}}!nSbpFmQNGv#Sznnl3ZF%5%cAxu&`08FrY`5}^JZMPweg|u=CKh(f4`&&lWnO*hwNsI6o>)rY*Abf$yI(SvbC`Gq-{)n$V0&iunOlCSAPoX)JfXQH8Po+7b@HROZO&%JLB zPAB=sPv((yb!J_9vY|aPDUEEhoW)Qj_a3ULo$8g>KIWAE&d9JR=`Z8jl2C^1CW?%cW#3osTlLD&ozBp z$7$N#nd8>RI-EM+SL!5vIWa}i8Nle^FwN^h%}aeJC+nEPi{x92*WytRsY?M5k7&NS78dd#^1**IJRF0) zou7VKY{{I2?9W+6+xq9F8<}j;Jm@FML;iZ2;q8#0hwSAt>AE$Y&J{x0>0AN5DBhlV z+9U82;or2mZL>zP}Z1#@=_W?OzGq3|V2qaF6Ig^38z{S9|Ksc5? zujA1f)_C-a((G~d4W-%R>H($M^HnH~OpJmT|>F1sK9Q}I){l?f^C%ck7NF)6-EbDwN%h(`Y@0PN3PHFt*4=?cT z6?JlUS#fXTUgrL3&Hnw13*}~PizPS1uk77a9?Y|!SYYNu&U3^8W$rS(9DYmm^`q^} zt8Xvp%kxf;ISs%H;5J|_upZb5Yz1}!?inlq0Mmd_MxUf!Q6ITpX?9;;tTekXFHxG^ zmzOEc?#nkS&F;%LE6wi9w6Erzk#`Pt>0&VG^r|g1N~m( zb<*!lxk0>+{%F>!WgL~5s>F4f%Z_x39SKdYC5_xG%bEM*%elwic$03l;JI$|%?sw% z#!lR?W$L&mea4g-#K_9CoXe1R#HTm?XEFUp@}?YFTOxfTJ4E_SmH1DooEAjz4esgl(uWN{0ln~<+Mzwqur|xO z_)5P2f$ihB_BFAWL469J57Id7Tkk2;UoW5Y;Ll@qzg;tH{eS#E)^Y#u&J6Bn50yD1 zhnPLX&YZo!j|F-3%>(;Jkh{oSe*L+Sek-6;+e_vn%n3pr(U_{(u3r7sqqSi_`&xkw z8~6U0Qw@9om{q|$5~_D7}J zHf)E|Y#a8H(rg>{n$m0=_NLNo8+K4>whfD&;M-!`hQ)o_d)9^xTj={EKkCJXMfX_X zYj}rOnmrB1P8>@ee}!#QAK&;SCO_YgmU*aGAMr`1PxpNi@-cbHH9m>>58eXtl{H2{ ztkul(gT4EfPc3WVNBGoHUYQSg_%6wMi6@Y^%r(RpF+Rwzj_^SWY^PnI zbItrk{F}>d?u-k_x}PL_yvER zQe?dUEPtI6*_-#5kX`a%o_#dfb8yxN>7)2mK|WJ89|s%Zm^gq_EBQFqyy<4_IBhnv zf;a=e>E||>eJIApFBcn+-NBX{8)U{U9+MJM+CqANbg&u={U z+?b4$?6c#3?g{^Xk~Ah(J&tE358~-2CN}5qd)|q9-`^M3W3JXCk38~U=*F)4^~n43 zFuZ<9c_m&X?;jYx!BbM7bAsz!A_-5T57Kt%NRQ0V)-n!I#(^)GZ><nRwX<-yfd8aBA|48`<+nGVHuKFmd-Po5+@0)s zBo1`P;PmiZp4fP2VkdEId5=TRzOCb2W9IG7=@kyPq{3m%JH=YaOz^ba7ag3!TG9Bu zHH_~cCe4GX`0g6#^s?Hj%*Knzr!(={P4U!cHw~?h@2a7{us`aR8u=DIYc1JrbBHHo zx~4gE9H-3vRq`B9_5gGCZf5oLpZM{qQPu7V_a;Uj>!dRq2gOE?aO8XUu9;tK{H^pu ze34aNX2)5whbD_}B7O?-n(Q`g%T~ACkJtF~k)E{iJ;IC3QC4|Jq+jeLMw>YnJMy@Is>lz6W&?-$%Z>K8~H0vR>U8%i+x*lTAWfmQRANq_d{7Cz_|8Y`B zXMUwCrZCf zLY6v)9Q(=BW-U4Ple3nbclqU)U7ksw*mmqEXD)FZ=%*R_$Iia|(u*#=py!UcH)qL3 zm!5x_MI`;~BD7gY(q=|UQr7#H)SY+EN3BwNXtTmndT6tY&`v8tn^T1LzL0iq>+PsC)+I}u8`~Sxjmws`E=w|Iq!%o2E1g})3`m6kBN>*&Locjf)^KC}vc~jPjmz4aT3a$hhNNe%IB~_$I>fcG z9bsKGFMW1H!?Gi9Typlg_MPVD6+?%f-?VH=k?iE&6|IZfOWZpD)ElQ?aq5lfv*%qD z;X@w0yzw*3o0c^;q>s$pXZ76XrpA``>0to{*+>$}MQS^cKhri>(hN;4*M%HRZwo3T znpNN4w4kZEsr{ym(SdrDZdqe}LmI6Sk+!85Eo)t3T5v{sUUOr8TVs0p(uR7}agmBk zG~vp{O>OChKjZtNjX1O_RK-B`CicZ7R(B$gHZDG_}l7c}x{WT;TT%;lH^t zePdJmVl&!%NH)B@A_>bobtc)^!li> zSDOYnv0+-eam7;f80|T+VQOJp(xaro&Tm@5T^g~yaal_yC}Pp_=Jb;K_JxZ@UNh&e z7+RPPW6+BbPL_>2n`j)`}jGZpAcTX#_QVUg6gj zMw)Ljb^tEv{L~}e-h>5{M9YAtMc9)?P1mIx+ZWGF-<-Z~S>w|5g&(V@&vLbJd3$<# zLwXYbO<$CrHOp}_Vsq#b{Pa8Ed1T%PkeN%HOla;=pwY6cvO^sDUeLeGStu*T*OwX*a zS(mgnEJsD9&ZjoEFFduO@rLH6mh0P2U3^1B{lW-MDDctPZu)Fp6XhQ{Xln|hKvA>WZ3LHZLG-n6i}nA{@tE0GK%P)kGO3e(S*y%SC5?<8q^GHkev{g?!zwl_f%Nv)}H?@fM_ql00DsCKS z345i{$n^4-ruH^VFQI*szC0c0>{G%zzec~$J^P9)E+pMmS6*oP*HxFF?_bOBrSmSk zSngdk@AC65`{f7H&EI+;wT(4wL7QD_WN?Ti7W6N!pY) zzCFdZWxGRzlQW39^?;I{=s z*wkR`ycv6Dq_0?P+-5w21&!@DHa51TXBv0YACA&yd=u#hSxH9eYBNws5`>jDnOh{r zvv$hK7>*1}0Z(mj1y6y#l;CJu`bJpHh&24Rgg-OZ3K>7l7s*8})a*K&#bP{uOsupx z!T25nkY3mpcD;+|siOcAE!`xuec$Ma`ddtbCa!W$mFD zrls5PP{PZp=_SkC+Qk)SKw^5fxE|FHe6S*UH{lB^8g# zDVnzT+6;9>PetubqVZq&|gfxSBPkOB-Nue#-BAsh55l;i9D!`q!RgAil55 z*0>omI-2oqx^xA9!sYns8XHXaNc%(?Xs4SDdB@RAO}QTykj5*g;UvxUrHqh{)6$w2 z#P_q)*EQYH$b|E}6;0xZi`6=@!EqM)Hl?9)Ay3=MPsFxbX~Xg)M{xvr{<5Ww#uJkW z%CgpGaV+bDm`e#}^G}K_(9O|N6lI`@wnt zUwh{t9oJRe`#X|sOSa?Mi4&Y3B@=LnLv8s7CJDv_%aUv>ktIbMIZ2cDdaM~)YNVM# zGji-Sv;hJMG?cZV+Q2z`0fKuS$X7lHC4ZBv@kyf%fjD=nc-TPRtyK>A2a+Pu$q zpL6cLGnP}zdaLXG!7N?fyU*EYpMCb(XP;mDo@>i{b5w&2j4iv=s}nbr8KaF<>vdb^ zZ~^&=xng}vIyqjsp;EoElAoNfOf*=o$(NZCICYEi6U7()(0 zF3%H7OUpxY{r$)tj$$fVyLT$Ir{Zjf{v{rEff~lI4KAI zD#e-V!MI-39FEkb>4Vb^G716p`2&vK1qzbHm8e=@INIeLQ-pY;JTnuxZwj-*Ch{`= zWfLc6(1^G+eQ3Hw>EWw15nGslu1yu|5}v|q)3q}7Z?Y^Mm~I3_d-jO#IYpc;9*!-o z=*0D@>B&ZU+C{G43EZzYe)JC z8zZd$nnM5RP|sjIHn3Z_U4uQlg|E26z+UzX;=RLt{p8_j3_wlKeFM7(3g8#|$IwrQ z&rC1D>*;gPSC0-9`s305-2-D}3K0(sqdh}~QCoWOFbm1vba|(T!L%~-`g`Ldue(c@(N+u^pqtI;gVIr&4xRj zL_?*7KA+y<@gWKxgJ<#?86O<$k4FZs=~uWZ??a`WKJ|4U9>BphH_4?b%Jy`cWJji?mHV z_3r6MNzvFb-{yvQ71(S<<3%tKUJL4T{Yg5*yHf5@BwMx==cb!$9Eb{CtJ}wRh-h9bsCD{x<9dvtzp6& z8TKYI@NXrI$NNTTE;7|#j;`d*;Y!~ezU377F1!Vwrs3)+L&L&O!c+2vaDBM&`{-{{ z?i}6LuvWY+o@N$LVNH0}fLrMKuogVHISJ3gn()jRx8V7(lkhU-PIweatLgB*qy|71i`8S7!v3eLwTiKh&)qX?p1vd(8j>yupZJ}z7^gqGYJTLeZXp+hb zjV%$aXFtww_4-wolkqfFNU&@Udom7*S)-nw!ag+N_B3w$X=`# z3)X3ix{Az;l_UA$+`)Nm1u>aA$){qp+?b!Um4bv~<4CP+v%0XphSLWdzL2g@AJlDf zrpV;2x-gE!$_CB^Tjk6UjTw)ctceY1iy8S0l%!fLSh%W*2Kw9vmUOkx&3SA)cfBK{ z8KTvb_9tzp3%pb98TtJa%i7HxqsaD4_NDtJB34I3r!xB}$~)C1#cD^2sVS6fPn75G ze9z2G^+uFoW}4}QR*AGZWg9fA_a8aEva-#ui$x|1^7kBU%in0r@?_N9P9zU6Nt-1r z?bUNO2NK(J<%838YS6bt+$oBgb=#!9-bjk_N%-Awt7v(ghUevPBuai|&^{^~fDjy84Ii)g-6&RJ1 zw(DgKF0}geNi8Mvo~hQQzHUu*X*9@kO$w)FtyJB*j9+`zs*Xjf(tX%`MWJQaX8fA5 zt&2#0)TXUf4>>;puL9LPHV_JF`2$`Ma*)gBO}h{DJ9U(-OzRqRv#b(1HBqhsH|)8z z?3y<1Q7Y2~_M6rzO?DR#JI!88vTL=_c5T#@pW8fZ+T(2HYliJ7?cH!2)b;^(CQrMY zYb0AYfSHY)Jj;&SKaxSxD(C`y8_DjxkwYo+m?@2+G8@ccf9wU*C;LjqPP&jwd%S6vVqB+TqT$ISu3U!eajb-fDK?Ch1-t(pCmN>Uy zE4LIwK3PY!&KGF6R7o*x?VUpA*`zNhdbhW~MJl&Y-8IumszCi?R>%vgUQ*sHkwo0C zi(L>$ytL}2(U8Gx5rl&L=BD4>KXo~T`@;$&)K!{q&=VLZCkgB%9LIM)gzqiZogu;i z(1$gJE4^$*z}-nzp9(+3DNPvnNPIGKtZ=ZWloYh@)#lK&S`@?XQW2v zXXxQ;cstIl&*SJQOMlqiGJ|6cY_@u+d@5vz%jRv(rB?oP8r4ix=a^Y|1{%eA zKN1f8c@~Gkw2EiE<9LW`#tnF4s_RxMLLZvieC7${q7|^E(FkKza|jX(DN3S4>|;zH z5x5AU?$N>er#hOA4f~M+E1{L4fL)b0dg!VX zKJz{E1Tw*>r@k@K!@>@_B!&~>+sem!ReLnkBSpKg*PNVw<5}n#W^Qig{EHR zG)c_|<=5(6w#R}`b8k~Jqn}^ryVL=^*rstFy2)ljScAqiENO~ZqCa;3nBCQ#6K{ST z-+JeNYh(X}SHE8^wwswWCuBDzNt+yF0(p2}l<|)qyV|_PJ)LcdKQfM{ehvw?N80CI z+cQW58OQ1MVJ#xC`c#%t}L@k!d3Sg4>u=!wB_1!vLyW zY1WM}mmC#Q6=jXXh(@qFS4V1Mhup9?46ii76UZ{?bb?1zl~p4#tM*{6!a*N*CqLNtaEk zMx%IuI2fc>+{j$}X)GGBbMD{g)+bS$Ppc<|DWaE@yI`gX27bGpI#;m~>XV#VQY?MJdNc1cwZkiRIo65HM5afb0 zfFU#Hr5p5P*ksLMLAqwYip6aQ4s4s4*j6f~KBVw8UcyDhxuedqY@upPWfT%UMPWo+Y+>WaMv>7AijH?DYqDioo)j-; zTY0s`f*?|F*Iy_Pm^G}xXKNl}GNex@g=Qrui@fDTaw9-<72klK*3*g%d;>))HL5 zXT6Qq-~3e28j#y(P#qjm-D=VKK$*2c_cCng+pOO_MS9hl$2-6bF@wdpCgcGU{gm;> z+{t)T-{-hFz$}?gd0L?P@+p-)OqRHjHpO)h5%UPe_OMhRq zHCG{|>5IIuSZjpzS~sp#XnNX3nk!FIeA`ni->AXI0b9c?7Y{Npj-v8`VrdduY|>R2 zi^8Joo89YdOQSLsHmCS$z0CnUJ4yG=opFJ?R~ss!_$?2Q3=J2?#z#h$M*Ty>JI8m8 zDOk^Y`&qT-J~m27KQ1SQVfqp86KRDeJgmv8TsD1BSTbHp_E?f)pTgbJ@_gZRJLe}S z8KP>A(ajP^V=h^n_@UEXkS|oL3})($3-Uv}g6)-SxWaps7${9&*>m#SLK&9(!<(Y$ zk&C~O^~xi>g3UUu-=m@g*c82r$O4{*l~g_=u{VDGa*STz94$|jaWG`yz1Q#PXnw?! z`3xS?ERGOK#Vf7R@0L_8Qp!Xgl?lCuun?lfcr3%SfzinX!3zsB)N@6fZ3~hk!c${H zvLFiKNq)Q(s43-wcs?${)ymI8SrVS$l=m%&Qr?&FQs|^rQDnymo9`l%EBD3&T=5JPIAEOpj>2+bZlgJXU|wab1(VWx|I|r9<~mt zJE`~D(GN_GTxaJoU1ulaKd#>&y?*IMllMWh{tuFC7*l8cAHuS0*M+5h`E^(bdQ6Ok zIq=^ook;pJRX)n0olW-+x_SZ`ayo@NBbh8!+AwPJ<9htj>k)^S8pHH`dM#fjKflfb zwy`Q>z9$#2&kxTxKuJTa&N9ig&&*K2jup<^z|PimT!qUE#~QMRU0RZ(sXBUTme$UH zT!%k;9cJ4i{z-^`u+Y2Zk}aF4DOwtRHY?EXT}0hE`C=ad^sx*{k{upbi5gUeI^5)| z(CX)u{!q|BRcNZM1k(Ac`Alsov4*x`^OpM0xL2rQOiO>^cdNYmpS#X~SYsCLG zyC8y2*W7!av2?vM6z<^lJS3+$MXX!S)= z#Bm_eGkl{+N_k~l6fNVvl8ZCH?8ng{(a5n}L{#(u|5kHf!o|67(T#Ts5u+*I}-kxo+XQmFsq{JGk!Tx{K>>u6wwSaox*xAJ=iN`?*eV zJ;3!K*XOt%;(D0t5w1tM9^-nP>j|zWxt`+s2G`SE|IGCa*Rx#Dap^#s4z5nFqBQlA9FQv4n4&6S(-j7Pv?n)X}+Q6@l%?d2a8yT>o!F+uPrBhY?-09BS>8 z3VH7#LKbx_?)Y`ZrQ9bV$KT};lCz=QJ zeT5Qt_l%1r%5Rk_cDNG=R_`d0@qJO zOFkv6r$y^rg{;^utQQMw#kUlCzJdv59}nKmDh~t$2k}eO72I zp5XDcjV84m2&WC`v3;Eq{QMwsODqqE(h&W=Om(6O?80AkCx zf>z_QVm}`(+0XMChn3B9Ifb9`8jx4Cwdr{^-#&?Q-^{&==U{(w_nbK&!ieQJ2_qfR zzw+cwRta>OtYF*3ZksbZZO$aMwVCy4bC$_iZ+nS~(%~)J7$n+W`m=Rp3n1tanT1~AmD%pb^59X;CuqSR_5=<1 zGC)_Qd@#xt%6bH`i;d_`L_9Fs~SFyPYw zE`wJo11XWqV4EnIUAP@GBJed(kxmEFIbY)06fHa9qyEjJ3Pcrr)RM=1l*5dcUoN)J zlgU)wUt?@7W~$%==fq*DT=Af6$Z0RPB*xahE*#vV+>4d|V+oJv3w#_9(yMY8t~g^^ z`-*c{tje9fSl^XzTN^D~cKNb)hFK@PC%v?TRqU@r~CXwqj8v;Az^PA)fahHy{2016wyTCp`r^xCt9@)H-p z=E^g37oF`eS1q!|aKVBjkVOgoWli)|gvCAwB%&Oay!DMar2FojXK$8h-u6a@LTlc+a}9EVYq8=H zmpVjYEensLx4au^3au$8L`6QnQre&veU^%Bi;nU?m-_){Ea&*Cfc$lLZ*+e%(+3Vt zaQfd=b+){5CZ4T3--(U0_BO%B17Ym7!H>N*vQWTcf{P$ky|IDx_{;JB&juTo`6xm+ za<=Boe5w3jr!Kl1E7R5bmJKNfxVFq6-f*xozp;L#uJPc;`TAVQVcs0xf+MQ-VyQ2o{$C0-inp3?BxSmlv!r{0*GpJ>Fp1_t{Hz!;=Y zq?oP}xCpEx^_V648Qu+Y$p9)oj+cp~d%e7bD$gOSh6^jS2 ze9PdKgIBgM{chXZ(?2^nw7b3Qiq6Zg+}nOr=l0G|wBPjI_M5I~zwwIpbKcnbjlnBN zIzL8KrE`1xi{ALAf$x3#4I}oytpmnsuoOUZoAxMo^ZCoqHJG5JpI<0GPkb=!C7uO` z{-=YgW7Nf`o}%bIZ5?XsM{{?!cWmcj>DMgwEB60Uhe=mY%(9OB3&(RNyvrwaq%L*H z=V-1&lVS4FFyIC9u}N4SoY2ENIvtMRoU!5f!=SDMPq<-t@j|#dM&ZExWL&P4B2HF^b~@^&5+|`t+8_ZN4AoWyET+5lIc>^6TPS)%-Lfk*MRvXf$}C0v|(7@3apY zHz3ovN$XdJW*eAstuYtHdaD8^RafPbvTYp23!$FV&AM00Yk zTxN(N&QEI1p&d-HU(8!U6C42}ziMb@TA`XVZP1lPO-p>@l7Ew4--)%qMnI`}WQNxj z8xhS?2P3NqNAbk`91V14eik-4dF7^9&ZI`0m)(d*8m^dDCNC@tmT8D)v}K4J2(Kwc zc4$p;HfFC}uioj591|6c^Y&-C#0iSUxoG#$c)oY@W;a8}1vbB77*E*YE$%*P)|>)v za0TZ8+)9-rriv3cY=FK$E_=h|$UrYqhd7JJIbOeJY8r!9@j^P3NXhuKe+d_=&GD-S zWc5;kHC4Z>E~KE^SEa8 z)+Y2~gwr1(`1}q~b@MgXB-Do>I%_OjXcn-Nwh7m04xxWD3?4CHDryrksPFTNMa~ z0>{Uks?dNOR%?Ho?N>HhFOqaCv5F`n`pGo%#bn)N(mEoB?plel-@SAKU*!TpH!VV) z3Sm5pFrHATkwj}$P|!^Tn<=CS<5`510v}_D_*Szh=ys)hoZ_aWga&4XxXFUXb-RqK zBbtxSKB}hz*CNU`e)iEc>3BA&h_^+Xj_R)TZPDhVx{q+>qW!vwh=KzJp$8I!#3?)% zjfNo2ZSLfPN8NtI9>*T$_Eq<&ngaC)#&&<)U%j zj&Z55=O5LR%V}J<`?;*#=O0a}B;^(rv8ICPE>bF>?k?pm(dLVe>hXk+68mCQXu3=4 zSvhE)DIDbRI5(kWL;@5vF3+R#&(t80j~&nR=wcIQ72C|Kz;E>hE|Bq%J#0!~n|j)Qfg;*9XyvE<0{!?B zy4|&ppkF&xqF-3wZ@1kA*0%k6f4hd7{Ip-7U%Qn%vV8;x+ajm!S2%d7Zqa@%>F{f} z-3iu0?Nn&N8mYN`4c*&qmxG5sSB`cT@ASLn?E&TkWc=3nwSPX7WNUdmVqn4E4T2EpW+9(2l?cpv!d&OZ};*MJPmw*2LG+V4`tw6 zfgjGmt^B^5`15>yir)_chx*U4MEgnL!@aK5;^%(g2Q%;=0f(Q;|91dSkl!675&r)H zp4tk`UGS2O00aK*%>T0ZtIH|=xeMU$xuF^Vv6&SAl?&iMM5bB#BP^Q*e$4)ZX{|9vg-A+7F8e=qSte`P&C2^`vQj`sT*;LzT4wD;d{!T*aE{6&})?U(7- z#;)l<5wCqt_ghVmM|(h@Wf@nY&mBaqy*L-`ApCUrJqNgfzA0Yt%YjSXF7@f$UJYE! zz{9||6xpBg_}a9@HKN%U&K`~Sstd4k^ny!N{(d>3$u&9nPGKOX_U zIg{UKfM+7UGwJC+3cMbDyW7KG2R?oP8{pw@0^jma>{EL92f$OTqZd4UI$g$n@6!UJ zD{mgS@pam?kKYFTXfOMctW1dCUf|m^{OkjM;%jMn>%ixI1pc76id|@JV}xIxhpW|P z93zrnJ~|_MH}Ut-=mvpB{{z4yA8>uS;QN8^`geHn@m~Nw@o{+Y@Rt>z;pgkXTXVVS z0UxiOz6ZX?Vz-Cesn~~qi9XN6D}k?vm==7M-}%66sJuXbJ@6f;L65Fc@vi~iGm*-7 zFYptzZ}F-4Yk+ULMc`u@{u;nf{RZDL2jAoayykr9`}}VeJ|n27Jb!lpKakPa zcL6{Co7AC?|1j|J4E;|5ulb-G@hbl>0k1^fJHTIsy#E~duFKIGpZ*_!4`W1wyq*Pq zv^y8w=i?VKWC;DiO1uu113$4S)wgqjKLrnz>i*#i}*yI(R&~FV`b{p(l3vW0^gj-j9q{|@kpB>t@EcY&u4 zFy!#*{}A|z4E__q-^jrK1bo>DZN}sO2k_SS(`J2nR?-gk(0=khel7JTzYYCPZ#ylz znD}Qh^mYIr-bS5y`~l#*pGo!mr-2{6hC1=|Zvfr{zj=>;82G#ort*3#@Nx8Ot&e{f zaN!RqlZW3A9C`l%$y?u(X(aMEGx{{}x`~wjBft;*4(WaVe+9hfglvqH|F?i2`bYBg z@biKbdS^vzXcx;f`E3DS+moj60e&!JZ>|Aelfj<{KK`ev{kR?Y@SkBrX&=(3_W}_?+5-|hMzwGetHNVe0jbMeE7Yoef8S2Z+=M%usY~*8Vmm9^l)5KP^9g z2GPU6ox)SV`!}Tax*<5j-)+Fh9zg~^|91h;Wa2*z+*q8Z|83ylKO_Br82HJI{Qna8 zi7%x2e+&55484B`e)td5_!ab5_dS`yYk?o3ym`;hrN9qn*#7fUk1Jg{jK@aw9 zsXTuY_%QA5W*`4@;N!ED-^>3p;61OTO?5badV%|>pHN?8z|S)NKHlcyZvfW(6mAxFz-BW4&ap3jXFRIAO|9ikEGWzp4a4kdsN#KWGt1*(p z|2FVFzn1Dl`)RZn=-=(>odbN=ms0!tQ^23g(0?s(C&E}yyOI2dfbU>15Yq1le&)-m z{cHe#V-6oWPyY?Tk7Ve*2l)8surXdf$ANczf;>F@N#Okm^SDp{2=L>X^iKkZeIM2T zHwAx$I`-xL0kAwS$inztwu1ccV~pVA&jy~FNZa>T;Cnucj{E$t0DdZy-*v!y9!mAQ z2K>*N_%{P@{q?l}eh=_-nfT+tHzSNEJwKlX?%V`mu$u?m^8n28TZ#TZPW(Svz2(sc;0OJDPWac+{=<5W;GM*Wy(P(S5V-TX zwElk4(AFbdA%C=Y5Gr0g2`_fxRJ@f2>f^*8|vd<2fY1$3{{`@|OnILKzW!e1)8XpxAAzTs->&!c+TrKKucY!@0sLTw-UYzV?nv=p0sL?# zeiv|9-&)nSIvNFjl>D7Nc~Nv7@Dsq0Fnd@AzPmww%uA$S^T79gCGAh&0{mEp{(FJL zFVDko0@(b$^Uj=?Lll~upSHClzuYMo+=}dg*nUwd+VHaiRIK`#;+1Vo@=YGCap^V)}3LJD28GZ5Fk*Uwr!&}hduAye50iqgBs<_ zX7TPpUicl1hj;DLN%aN$h)NV6tnnEm9az8#0Paw@x?ET|OvxXbIb9hupBQMu8{hh= z&)dg)BKg(q*s*(XU}tZ-PW!g0ZQMDTGTzF~cY z!wed6Q$A^}#QrSuLX|iCc;g;FqM+R_nLq0p*CL#ik}o%v8wI?AaFaN~sot}#Vu-_u zXYO-RIN|v0qeXCC{~)=jz8+b3k5eQvf=cm=uo|~Kufc;U`$zeNh_oI`b@c8YvKauwuxe+ zIjG#w+vi^4W&GzbEa|c9nMSc&R^c%68*7wnsxLd61t*~~=I9pM zF`hz_=jc4v#q`+u`EcxnKZZuJPGM>~^_B0Kaq4R{sh8WE@+)bd zN_zU@%!HkcTIU4_pINCnGaWV?+X=FPE4nW8MzaF>UNRm-!86{ZDu=J2r2imquSSEM zaBV72qorq;?M20FN19403x;2weN-fxoSd1jPc_Bsdx&IdqZv1*a5Wk4<3yXuBZKnq zl>E)GWXwgO%D4Ygh2xu`WlW8!J-vqR=Ca3k3iYaoFKeS*i4RWGJfN7E8<@t=uZbxf zRv}i)?gyXsjwwiqbuiCe*m(jIjP^W z+Mb^QPaV=u9WNA3)N7lZi($;!nWf2BG%+Lh*hW!Z7X6d`SF0~G$k2y#O}dGxP#?Ah z*U@Tariq4l(?V;Q>#gnvKGYAut!oW;5$x{$czp+ zAuuup#!T6fT+?-AHtu1v;wrNq%zY5YeuD3;YnI>1-m zI^j?SvA)_NsMXkwl;_mZHf3+z>GW8$%S~Blxx^&mw@*ig6EEk+wb+ZKMQCJ5$H+S@ za9g31Z6YY?W*VurEZ<9Wm`ZamP3FGS&>TXVm6|adHyU^TP~A)?PMNKT%Zx${UFXVY z(8jDk46TpeRDQ|guelK`gh&l?HRxZ!{DuaF%eOn=SJDk#d8V*t6Kr(sb zG)9`3xuMU0u9oxY8OS!(qx$>0?;W6LvnXo|oH)ffRhvw~{Neg$*zIurNRxu3@RE}I zM2s^o8iG4kQxohy*lqK34QZIn(9GTZWE6=w`{+mA>e_VP9(K3hV8RFwl~NKod&Ddx znKFa2L-*@8?`kU6bUpMrHZ0>v1 zMq8@2R{O>1*%)foP*awsG9Upz>UT3B2E;dn>FR;`dOQcK4aRzooJ|>3>|p)qT)+<& zPU6h;8SZ1`A(j)-BiC%L*G-IyMn#Ol-K#ANaBT%_8lViZk`t5HP8vyAeo)qdsl=Lz z(`<`ZeFr7z85ziqJ(|$cK1ibsGo6qM&FLg#W&;Il9SgRvpEY-9&q5@?m>0vnJme!JaHWsc?y`iZfp~0zv z+e$@KtR_S)a~=f7ah|S|&ek*ijuiLCR#nn!mV0HUiLw~3G%r#GQ*D+nZGrTV6A{CI zQZ!TGRXdrYtah1+@ok-{PO~9bmRfFQA)kPZpiAV z9;9|A(fW^;zC)+X9de)av)qz?&E5|}lmj*2l9C0+sJnh-RxikPtG4Vu6`pK7R*Skh zvvXiW154IzFXMGHiXmZScivL!<`v~`te=hYvjC>0n`P~y5dBkarV(}9V5hsm zNHXeX06k4ym5#F*b(g1{jgGo)RhcZbxNJG;BV{}onwDO>>+ZQuR~B{KKg~H=umVfA zm*rZGvXt7u>B?j^JQoifm@6L&kQSuEvm5C8BnTsfQ%fw^|B%0P!DBlxVoNVteE}E1 z*_pJ8)9 zDn096l&8SU^PJ5WFp>zBR(N_xr32rE?LLf~#c3an?QVPC$z5k)$tO$xwMxr&R)TjU z&*GIWe)AcBmc-Zd9Dae%IRXNn-gS{r%Yzbt|4AnLy`C%J$*1DHRqSQyunzwV^xl-g zlke!GFLnNVt$1(scq*^GGqaX`&w+sD$|2~TT*^gwdY9ssS+}1CXupszZX1Rt*5z}* zrt0>Q9ac*3gBd)%OOihY-v0tmvJ*Y|=&u9sah_Fg`YB)SQ-6X>{F%s(@l?y%OHc&a zFYu>5vw){P(h=}hD!~6FXW@Q^%j2z-@6`U+;jiFvbPMzz;#v8V?@IY(+zQ?vA^2aw z`x3Cnv%N^+J<2{?_ys(+r7ho0K0+d)|Pg}8qpAUrGXZ^8RX z+EVz1xbG1Vo-OW3F8X37AUx)H2+zX%;!U|oM`ndzh&!zXZ}1n8ONazHl=mEu7s`9r zFXGn~BEeG= 0) { - FILE_LOG(logINFO, ("Setting #cycles: %lld\n", (long long int)val)); + FILE_LOG(logINFO, ("Setting #triggers: %lld\n", (long long int)val)); } retval = set64BitReg(val, SET_CYCLES_LSB_REG, SET_CYCLES_MSB_REG); - FILE_LOG(logDEBUG1, ("Getting #cycles: %lld\n", (long long int)retval)); + FILE_LOG(logDEBUG1, ("Getting #triggers: %lld\n", (long long int)retval)); break; default: @@ -498,9 +498,9 @@ int64_t getTimeLeft(enum timerIndex ind){ FILE_LOG(logINFO, ("Getting number of frames left: %lld\n",(long long int)retval)); break; - case CYCLES_NUMBER: + case TRIGGER_NUMBER: retval = get64BitReg(GET_CYCLES_LSB_REG, GET_CYCLES_MSB_REG); - FILE_LOG(logINFO, ("Getting number of cycles left: %lld\n", (long long int)retval)); + FILE_LOG(logINFO, ("Getting number of triggers left: %lld\n", (long long int)retval)); break; default: @@ -960,7 +960,7 @@ int startStateMachine(){ void* start_timer(void* arg) { int64_t periodns = setTimer(FRAME_PERIOD, -1); int numFrames = (setTimer(FRAME_NUMBER, -1) * - setTimer(CYCLES_NUMBER, -1) ); + setTimer(TRIGGER_NUMBER, -1) ); int64_t exp_ns = setTimer(ACQUISITION_TIME, -1); diff --git a/slsDetectorServers/slsDetectorServer/include/communication_funcs.h b/slsDetectorServers/slsDetectorServer/include/communication_funcs.h index ab6ebd8e2..bfe60c75a 100755 --- a/slsDetectorServers/slsDetectorServer/include/communication_funcs.h +++ b/slsDetectorServers/slsDetectorServer/include/communication_funcs.h @@ -67,5 +67,11 @@ void getMacAddressinString(char* cmac, int size, uint64_t mac); */ void getIpAddressinString(char* cip, uint32_t ip); +/** + * Convert string to ip address + * @param cip string source + * @param ip result + */ +void getIpAddressFromString(char* cip, uint32_t* ip); #endif diff --git a/slsDetectorServers/slsDetectorServer/src/communication_funcs.c b/slsDetectorServers/slsDetectorServer/src/communication_funcs.c index f8382826c..39385e266 100755 --- a/slsDetectorServers/slsDetectorServer/src/communication_funcs.c +++ b/slsDetectorServers/slsDetectorServer/src/communication_funcs.c @@ -25,8 +25,8 @@ extern int errno; // Variables that will be exported int lockStatus = 0; -char lastClientIP[INET_ADDRSTRLEN] = ""; -char thisClientIP[INET_ADDRSTRLEN] = ""; +uint32_t lastClientIP = 0u; +uint32_t thisClientIP = 0u; int differentClients = 0; int isControlServer = 1; int ret = FAIL; @@ -34,7 +34,7 @@ int fnum = 0; char mess[MAX_STR_LENGTH]; // Local variables -char dummyClientIP[INET_ADDRSTRLEN] = ""; +uint32_t dummyClientIP = 0u; int myport = -1; // socket descriptor set fd_set readset, tempset; @@ -220,9 +220,14 @@ int acceptConnection(int socketDescriptor) { } // accept success else { - inet_ntop(AF_INET, &(addressC.sin_addr), dummyClientIP, INET_ADDRSTRLEN); + char buf[INET_ADDRSTRLEN] = ""; + memset(buf, 0, INET_ADDRSTRLEN); + inet_ntop(AF_INET, &(addressC.sin_addr), buf, INET_ADDRSTRLEN); FILE_LOG(logDEBUG3, ("%s socket accepted connection, fd= %d\n", (isControlServer ? "control":"stop"), file_des)); + + getIpAddressFromString(buf, &dummyClientIP); + // add the file descriptor from accept FD_SET(file_des, &readset); maxfd = (maxfd < file_des)?file_des:maxfd; @@ -381,9 +386,9 @@ int receiveDataOnly(int file_des, void* buf,int length) { } if (total_received>0) - strcpy(thisClientIP,dummyClientIP); + thisClientIP = dummyClientIP; - if (strcmp(lastClientIP,thisClientIP)) { + if (lastClientIP == thisClientIP) { differentClients = 1; } else @@ -545,7 +550,7 @@ int receiveModule(int file_des, sls_detector_module* myMod) { } n = receiveData(file_des, myMod->chanregs, sizeof(int) * (myMod->nchan), INT32); FILE_LOG(level, ("chanregs received. %d bytes.\n", n)); - if (!n){ + if (!n && myMod->nchan != 0){ return -1; } ts += n; @@ -557,7 +562,9 @@ int receiveModule(int file_des, sls_detector_module* myMod) { void Server_LockedError() { ret = FAIL; - sprintf(mess,"Detector locked by %s\n", lastClientIP); + char buf[INET_ADDRSTRLEN] = ""; + getIpAddressinString(buf, dummyClientIP); + sprintf(mess,"Detector locked by %s\n", buf); FILE_LOG(logWARNING, (mess)); } @@ -610,3 +617,16 @@ void getIpAddressinString(char* cip, uint32_t ip) { memset(cip, 0, INET_ADDRSTRLEN); inet_ntop(AF_INET, &ip, cip, INET_ADDRSTRLEN); } + + +void getIpAddressFromString(char* cip, uint32_t* ip) { + char buf[INET_ADDRSTRLEN]=""; + memset(buf, 0, INET_ADDRSTRLEN); + char* byte = strtok (cip,"."); + while (byte != NULL) { + sprintf(cip,"%02x",atoi(byte)); + strcat(buf, cip); + byte = strtok (NULL, "."); + } + sscanf(buf, "%x", ip); +} \ No newline at end of file diff --git a/slsDetectorServers/slsDetectorServer/src/slsDetectorServer_funcs.c b/slsDetectorServers/slsDetectorServer/src/slsDetectorServer_funcs.c index 9cdbd9353..7ef514ab7 100755 --- a/slsDetectorServers/slsDetectorServer/src/slsDetectorServer_funcs.c +++ b/slsDetectorServers/slsDetectorServer/src/slsDetectorServer_funcs.c @@ -28,8 +28,8 @@ const enum detectorType myDetectorType = GENERIC; // Global variables from communication_funcs extern int lockStatus; -extern char lastClientIP[INET_ADDRSTRLEN]; -extern char thisClientIP[INET_ADDRSTRLEN]; +extern uint32_t lastClientIP; +extern uint32_t thisClientIP; extern int differentClients; extern int isControlServer; extern int ret; @@ -41,7 +41,7 @@ int sockfd = 0; int debugflag = 0; udpStruct udpDetails = {32410, 32411, 50001, 50002, 0, 0, 0, 0, 0, 0, 0, 0}; int configured = FAIL; -char configureMessage[MAX_STR_LENGTH]=""; +char configureMessage[MAX_STR_LENGTH]="udp parameters not configured yet"; int maxydet = -1; int detectorId = -1; @@ -71,8 +71,6 @@ void init_detector() { } else initStopServer(); strcpy(mess,"dummy message"); - strcpy(lastClientIP,"none"); - strcpy(thisClientIP,"none1"); lockStatus=0; } @@ -122,7 +120,7 @@ const char* getTimerName(enum timerIndex ind) { case ACQUISITION_TIME: return "acquisition_time"; case FRAME_PERIOD: return "frame_period"; case DELAY_AFTER_TRIGGER: return "delay_after_trigger"; - case CYCLES_NUMBER: return "cycles_number"; + case TRIGGER_NUMBER: return "triggers_number"; case ACTUAL_TIME: return "actual_time"; case MEASUREMENT_TIME: return "measurement_time"; case PROGRESS: return "progress"; @@ -1670,7 +1668,7 @@ int start_acquisition(int file_des) { ret = startStateMachine(); if (ret == FAIL) { #if defined(CHIPTESTBOARDD) || defined(MOENCHD) - sprintf(mess, "Could not start acquisition. Could not create udp socket in server. Check rx_udpip & rx_udpport.\n"); + sprintf(mess, "Could not start acquisition. Could not create udp socket in server. Check udp_dstip & udp_dstport.\n"); #else sprintf(mess, "Could not start acquisition\n"); #endif @@ -1778,7 +1776,7 @@ int start_and_read_all(int file_des) { ret = startStateMachine(); if (ret == FAIL) { #if defined(CHIPTESTBOARDD) || defined(MOENCHD) - sprintf(mess, "Could not start acquisition. Could not create udp socket in server. Check rx_udpip & rx_udpport.\n"); + sprintf(mess, "Could not start acquisition. Could not create udp socket in server. Check udp_dstip & udp_dstport.\n"); #else sprintf(mess, "Could not start acquisition\n"); #endif @@ -1841,7 +1839,7 @@ int set_timer(int file_des) { case FRAME_NUMBER: case ACQUISITION_TIME: case FRAME_PERIOD: - case CYCLES_NUMBER: + case TRIGGER_NUMBER: #if defined(CHIPTESTBOARDD) || defined(MOENCHD) case ANALOG_SAMPLES: case DIGITAL_SAMPLES: @@ -1911,7 +1909,7 @@ int set_timer(int file_des) { #else switch(ind) { case FRAME_NUMBER: - case CYCLES_NUMBER: + case TRIGGER_NUMBER: case STORAGE_CELL_NUMBER: validate64(tns, retval, vtimerName, DEC); // no conversion, so all good break; @@ -1983,13 +1981,13 @@ int get_time_left(int file_des) { case FRAME_NUMBER: case FRAME_PERIOD: case DELAY_AFTER_TRIGGER: - case CYCLES_NUMBER: + case TRIGGER_NUMBER: #elif GOTTHARDD case ACQUISITION_TIME: case FRAME_NUMBER: case FRAME_PERIOD: case DELAY_AFTER_TRIGGER: - case CYCLES_NUMBER: + case TRIGGER_NUMBER: #elif CHIPTESTBOARDD case FRAMES_FROM_START: case FRAMES_FROM_START_PG: @@ -1998,7 +1996,7 @@ int get_time_left(int file_des) { case FRAME_NUMBER: case FRAME_PERIOD: case DELAY_AFTER_TRIGGER: - case CYCLES_NUMBER: + case TRIGGER_NUMBER: #elif MOENCHD case FRAMES_FROM_START: case FRAMES_FROM_START_PG: @@ -2007,13 +2005,13 @@ int get_time_left(int file_des) { case FRAME_NUMBER: case FRAME_PERIOD: case DELAY_AFTER_TRIGGER: - case CYCLES_NUMBER: + case TRIGGER_NUMBER: #elif MYTHEN3D case FRAME_NUMBER: - case CYCLES_NUMBER: + case TRIGGER_NUMBER: #elif GOTTHARD2D case FRAME_NUMBER: - case CYCLES_NUMBER: + case TRIGGER_NUMBER: #endif retval = getTimeLeft(ind); FILE_LOG(logDEBUG1, ("Timer left index %d: %lld\n", ind, retval)); @@ -2270,15 +2268,17 @@ int lock_server(int file_des) { // set if (lock >= 0) { if (!lockStatus || // if it was unlocked, anyone can lock - (!strcmp(lastClientIP, thisClientIP)) || // if it was locked, need same ip - (!strcmp(lastClientIP,"none"))) { // if it was locked, must be by "none" + (lastClientIP == thisClientIP) || // if it was locked, need same ip + (lastClientIP == 0u)) { // if it was locked, must be by "none" lockStatus = lock; if (lock) { - FILE_LOG(logINFO, ("Server lock to %s\n", lastClientIP)); + char buf[INET_ADDRSTRLEN] = ""; + getIpAddressinString(buf, lastClientIP); + FILE_LOG(logINFO, ("Server lock to %s\n", buf)); } else { FILE_LOG(logINFO, ("Server unlocked\n")); } - strcpy(lastClientIP, thisClientIP); + lastClientIP = thisClientIP; } else { Server_LockedError(); } @@ -2293,7 +2293,9 @@ int lock_server(int file_des) { int get_last_client_ip(int file_des) { ret = OK; memset(mess, 0, sizeof(mess)); - return Server_SendResult(file_des, OTHER, UPDATE, lastClientIP, sizeof(lastClientIP)); + uint32_t retval = lastClientIP; + retval = __builtin_bswap32(retval); + return Server_SendResult(file_des, INT32, UPDATE, &retval, sizeof(retval)); } @@ -2303,7 +2305,7 @@ int set_port(int file_des) { ret = OK; memset(mess, 0, sizeof(mess)); int p_number = -1; - char oldLastClientIP[INET_ADDRSTRLEN] = {0}; + uint32_t oldLastClientIP = 0; if (receiveData(file_des, &p_number, sizeof(p_number), INT32) < 0) return printSocketReadError(); @@ -2320,7 +2322,7 @@ int set_port(int file_des) { } else { FILE_LOG(logINFO, ("Setting %s port to %d\n", (isControlServer ? "control":"stop"), p_number)); - strcpy(oldLastClientIP, lastClientIP); + oldLastClientIP = lastClientIP; sd = bindSocket(p_number); } } @@ -2331,7 +2333,7 @@ int set_port(int file_des) { closeConnection(file_des); exitServer(sockfd); sockfd = sd; - strcpy(lastClientIP, oldLastClientIP); + lastClientIP = oldLastClientIP; } return ret; } @@ -2355,7 +2357,9 @@ int send_update(int file_des) { int i32 = -1; int64_t i64 = -1; - n = sendData(file_des,lastClientIP,sizeof(lastClientIP),OTHER); + i32 = lastClientIP; + i32 = __builtin_bswap32(i32); + n = sendData(file_des, &i32,sizeof(i32),INT32); if (n < 0) return printSocketReadError(); // dr @@ -2421,8 +2425,8 @@ int send_update(int file_des) { if (n < 0) return printSocketReadError(); #endif - // #cycles - i64 = setTimer(CYCLES_NUMBER,GET_FLAG); + // #triggers + i64 = setTimer(TRIGGER_NUMBER,GET_FLAG); n = sendData(file_des,&i64,sizeof(i64),INT64); if (n < 0) return printSocketReadError(); @@ -2458,7 +2462,7 @@ int send_update(int file_des) { #endif if (lockStatus == 0) { - strcpy(lastClientIP, thisClientIP); + lastClientIP = thisClientIP; } return ret; @@ -2466,219 +2470,6 @@ int send_update(int file_des) { -/* -int configure_mac(int file_des) { - ret = OK; - memset(mess, 0, sizeof(mess)); - const size_t array_size = 50; - const size_t n_args = 14; - const size_t n_retvals = 2; - char args[n_args][array_size]; - char retvals[n_retvals][array_size]; - - memset(args, 0, sizeof(args)); - memset(retvals, 0, sizeof(retvals)); - - if (receiveData(file_des, args, sizeof(args), OTHER) < 0) - return printSocketReadError(); - - FILE_LOG(logDEBUG1, ("\n Configuring MAC\n")); - // dest port - uint32_t dstPort = 0; - sscanf(args[0], "%x", &dstPort); - FILE_LOG(logDEBUG1, ("Dst Port: %x\n", dstPort)); - // dest ip - uint32_t dstIp = 0; - sscanf(args[1], "%x", &dstIp); - { - char ipstring[INET_ADDRSTRLEN]; - getIpAddressinString(ipstring, dstIp); - FILE_LOG(logINFO, ("Dst Ip Addr: %s\n", ipstring)); - } - - // dest mac - uint64_t dstMac = 0; -#ifdef VIRTUAL - sscanf(args[2], "%lx", &dstMac); -#else - sscanf(args[2], "%llx", &dstMac); -#endif - { - char macstring[50]; - getMacAddressinString(macstring, 50, dstMac); - FILE_LOG(logDEBUG1, ("Dst Mac Addr: %s\n", macstring)); - } - // source ip - uint32_t srcIp = 0; - sscanf(args[3], "%x", &srcIp); - { - char ipstring[INET_ADDRSTRLEN]; - getIpAddressinString(ipstring, srcIp); - FILE_LOG(logINFO, ("Src Ip Addr: %s\n", ipstring)); - } - // source mac - uint64_t srcMac = 0; -#ifdef VIRTUAL - sscanf(args[4], "%lx", &srcMac); -#else - sscanf(args[4], "%llx", &srcMac); -#endif - { - char macstring[50]; - getMacAddressinString(macstring, 50, srcMac); - FILE_LOG(logDEBUG1, ("Src Mac Addr: %s\n", macstring)); - } - -#if defined(JUNGFRAUD) || defined(EIGERD) - // source port 2 - uint32_t dstPort2 = 0; - sscanf(args[5], "%x", &dstPort2); - FILE_LOG(logDEBUG1, ("Dst Port2: %x\n", dstPort2)); -#endif -#ifdef JUNGFRAUD - // dest ip2 - uint32_t dstIp2 = 0; - sscanf(args[6], "%x", &dstIp2); - { - char ipstring[INET_ADDRSTRLEN]; - getIpAddressinString(ipstring, dstIp2); - FILE_LOG(logDEBUG1, ("Dst Ip Addr2: %s\n", ipstring)); - } - // dest mac2 - uint64_t dstMac2 = 0; -#ifdef VIRTUAL - sscanf(args[7], "%lx", &dstMac2); -#else - sscanf(args[7], "%llx", &dstMac2); -#endif - { - char macstring[50]; - getMacAddressinString(macstring, 50, dstMac2); - FILE_LOG(logDEBUG1, ("Dst Mac Addr2: %s\n", macstring)); - } - // source ip2 - uint32_t srcIp2 = 0; - sscanf(args[8], "%x", &srcIp2); - { - char ipstring[INET_ADDRSTRLEN]; - getIpAddressinString(ipstring, srcIp2); - FILE_LOG(logDEBUG1, ("Src Ip Addr2: %s\n", ipstring)); - } - // source mac2 - uint64_t srcMac2 = 0; -#ifdef VIRTUAL - sscanf(args[9], "%lx", &srcMac2); -#else - sscanf(args[9], "%llx", &srcMac2); -#endif - { - char macstring[50]; - getMacAddressinString(macstring, 50, srcMac2); - FILE_LOG(logDEBUG1, ("Src Mac Addr2: %s\n", macstring)); - } - - // number of interfaces - int numInterfaces = 0; - sscanf(args[10], "%d", &numInterfaces); - int selInterface = 1; - sscanf(args[11], "%d", &selInterface); - -#endif -#if defined(JUNGFRAUD) || defined(EIGERD) - int pos[2] = {0, 0}; - sscanf(args[12], "%x", &pos[X]); - sscanf(args[13], "%x", &pos[Y]); - FILE_LOG(logDEBUG1, ("Position: [%d, %d]\n", pos[X], pos[Y])); -#endif - - - // set only - if ((Server_VerifyLock() == OK)) { - - // stop detector if it was running - enum runStatus status = getRunStatus(); - if (status != IDLE && status != RUN_FINISHED && status != STOPPED) { - if (status == RUNNING) - stopStateMachine(); -#if !defined(EIGERD) && !defined(MYTHEN3D) && !defined(GOTTHARD2D) - cleanFifos(); -#endif - status = getRunStatus(); - if (status != IDLE && status != RUN_FINISHED && status != STOPPED) { - ret = FAIL; - sprintf(mess, "Cannot configure mac when detector is not idle. Detector at %s state\n", getRunStateName(status)); - FILE_LOG(logERROR,(mess)); - } - } - - if (ret == OK) { -#ifdef EIGERD - // change mac to hardware mac - if (srcMac != getDetectorMAC()) { - FILE_LOG(logWARNING, ("actual detector mac address %llx does not match " - "the one from client %llx\n", - (long long unsigned int)getDetectorMAC(), - (long long unsigned int)srcMac)); - srcMac = getDetectorMAC(); - FILE_LOG(logWARNING,("matched detectormac to the hardware mac now\n")); - } - - // always remember the ip sent from the client (could be for 10g(if not dhcp)) - if (srcIp != getDetectorIP()) - custom10gIp = srcIp; - - //only for 1Gbe, change ip to hardware ip - if (!enableTenGigabitEthernet(-1)) { - FILE_LOG(logWARNING, ("Using DHCP IP for Configuring MAC\n")); - srcIp = getDetectorIP(); - } - // 10 gbe (use ip given from client) - else - srcIp = custom10gIp; - ret = configureMAC(dstIp, dstMac, srcMac, srcIp, dstPort, dstPort2); -#elif JUNGFRAUD - ret = configureMAC(numInterfaces, selInterface, dstIp, dstMac, srcMac, srcIp, dstPort, dstIp2, dstMac2, srcMac2, srcIp2, dstPort2); -#else - ret = configureMAC(dstIp, dstMac, srcMac, srcIp, dstPort); -#endif -#if defined(CHIPTESTBOARDD) || defined(MOENCHD) - if (ret != OK) { - if (ret == FAIL) - sprintf(mess,"Could not configure mac because of incorrect udp 1G destination IP and port\n"); - else if (ret == -1) - sprintf(mess, "Could not allocate RAM\n"); - FILE_LOG(logERROR,(mess)); - } -#else - if (ret == FAIL) { - sprintf(mess,"Configure Mac failed\n"); - FILE_LOG(logERROR,(mess)); - } -#endif - else { - FILE_LOG(logINFO, ("\tConfigure MAC successful\n")); - } -#if defined(EIGERD) || defined (JUNGFRAUD) - if (ret != FAIL) { - ret = setDetectorPosition(pos); - if (ret == FAIL) { - sprintf(mess, "Could not set detector position\n"); - FILE_LOG(logERROR,(mess)); - } - } -#endif - // set retval vals - if (ret != FAIL) { - sprintf(retvals[0],"%llx", (long long unsigned int)srcMac); - sprintf(retvals[1],"%x", srcIp); - } - } - } - return Server_SendResult(file_des, OTHER, UPDATE, retvals, sizeof(retvals)); -} -*/ - - int enable_ten_giga(int file_des) { ret = OK; memset(mess, 0, sizeof(mess)); @@ -3225,15 +3016,23 @@ int set_rate_correct(int file_des) { // switching on in right mode else { - if (tau_ns < 0) + if (tau_ns < 0) { tau_ns = getDefaultSettingsTau_in_nsec(); + if (tau_ns < 0) { + ret = FAIL; + strcpy(mess,"Default settings file not loaded. No default tau yet\n"); + FILE_LOG(logERROR,(mess)); + } + } else if (tau_ns > 0) { //changing tau to a user defined value changes settings to undefined setSettings(UNDEFINED); FILE_LOG(logERROR, ("Settings has been changed to undefined (tau changed)\n")); } - int64_t retval = setRateCorrection(tau_ns); - validate64(tau_ns, retval, "set rate correction", DEC); + if (ret == OK) { + int64_t retval = setRateCorrection(tau_ns); + validate64(tau_ns, retval, "set rate correction", DEC); + } } } #endif diff --git a/slsDetectorSoftware/CMakeLists.txt b/slsDetectorSoftware/CMakeLists.txt index 9a7e32b76..f51937c58 100755 --- a/slsDetectorSoftware/CMakeLists.txt +++ b/slsDetectorSoftware/CMakeLists.txt @@ -1,7 +1,7 @@ set(SOURCES src/multiSlsDetector.cpp src/multiSlsDetectorClient.cpp - src/slsDetectorUsers.cpp +# src/slsDetectorUsers.cpp src/slsDetectorCommand.cpp src/slsDetector.cpp src/Detector.cpp @@ -39,7 +39,7 @@ target_link_libraries(slsDetectorShared PUBLIC set(PUBLICHEADERS include/SharedMemory.h include/slsDetector.h - include/slsDetectorUsers.h +# include/slsDetectorUsers.h include/detectorData.h include/multiSlsDetector.h include/Detector.h diff --git a/slsDetectorSoftware/include/CmdProxy.h b/slsDetectorSoftware/include/CmdProxy.h index e9dce0948..a67665a07 100644 --- a/slsDetectorSoftware/include/CmdProxy.h +++ b/slsDetectorSoftware/include/CmdProxy.h @@ -3,11 +3,11 @@ #include "Detector.h" #include "Result.h" #include "sls_detector_exceptions.h" +#include "network_utils.h" #include #include #include #include -#include "network_utils.h" /** Macro to make an integer command. * CMDNAME name of the function that does the command @@ -17,7 +17,7 @@ * HLPSTR Help string for --help and docs */ -#define INTEGER_COMMAND(CMDNAME, GETFCN, SETFCN, CONV, HLPSTR) \ +#define TIME_COMMAND(CMDNAME, GETFCN, SETFCN, HLPSTR) \ std::string CMDNAME(const int action) { \ std::ostringstream os; \ os << cmd << ' '; \ @@ -27,46 +27,356 @@ auto t = det->GETFCN({det_id}); \ if (args.size() == 0) { \ os << OutString(t) << '\n'; \ - } else { \ - WrongNumberOfParameters(2); \ - } \ - } else if (action == slsDetectorDefs::PUT_ACTION) { \ - if (args.size() == 1) { \ - auto val = CONV(args[0]); \ - det->SETFCN(val, {det_id}); \ - os << args.front() << '\n'; \ + } else if (args.size() == 1) { \ + os << OutString(t, args[0]) << '\n'; \ } else { \ WrongNumberOfParameters(1); \ } \ - \ + } else if (action == slsDetectorDefs::PUT_ACTION) { \ + if (args.size() == 1) { \ + std::string time_str(args[0]); \ + std::string unit = RemoveUnit(time_str); \ + auto t = StringTo(time_str, unit); \ + det->SETFCN(t, {det_id}); \ + } else if (args.size() == 2) { \ + auto t = StringTo(args[0], args[1]); \ + det->SETFCN(t, {det_id}); \ + } else { \ + WrongNumberOfParameters(2); \ + } \ + /* TODO: os << args << '\n'; (doesnt work for vectors in .h)*/ \ + if (args.size() > 1) { \ + os << args[0] << args[1] << '\n'; \ + } else { \ + os << args[0] << '\n'; \ + } \ } else { \ throw sls::RuntimeError("Unknown action"); \ } \ return os.str(); \ } -#define INTEGER_COMMAND_NOID(CMDNAME, GETFCN, SETFCN, CONV, HLPSTR) \ +/** time get only */ +#define TIME_GET_COMMAND(CMDNAME, GETFCN, HLPSTR) \ std::string CMDNAME(const int action) { \ std::ostringstream os; \ os << cmd << ' '; \ if (action == slsDetectorDefs::HELP_ACTION) \ os << HLPSTR << '\n'; \ else if (action == slsDetectorDefs::GET_ACTION) { \ - auto t = det->GETFCN(); \ + auto t = det->GETFCN({det_id}); \ if (args.size() == 0) { \ os << OutString(t) << '\n'; \ - } else { \ - WrongNumberOfParameters(2); \ - } \ - } else if (action == slsDetectorDefs::PUT_ACTION) { \ - if (args.size() == 1) { \ - auto val = CONV(args[0]); \ - det->SETFCN(val); \ - os << args.front() << '\n'; \ + } else if (args.size() == 1) { \ + os << OutString(t, args[0]) << '\n'; \ } else { \ WrongNumberOfParameters(1); \ } \ - \ + } else if (action == slsDetectorDefs::PUT_ACTION) { \ + throw sls::RuntimeError("cannot put"); \ + } else { \ + throw sls::RuntimeError("Unknown action"); \ + } \ + return os.str(); \ + } + + +/** string */ +#define STRING_COMMAND(CMDNAME, GETFCN, SETFCN, HLPSTR) \ + std::string CMDNAME(const int action) { \ + std::ostringstream os; \ + os << cmd << ' '; \ + if (action == slsDetectorDefs::HELP_ACTION) \ + os << HLPSTR << '\n'; \ + else if (action == slsDetectorDefs::GET_ACTION) { \ + auto t = det->GETFCN({det_id}); \ + if (args.size() != 0) { \ + WrongNumberOfParameters(0); \ + } \ + os << OutString(t) << '\n'; \ + } else if (action == slsDetectorDefs::PUT_ACTION) { \ + if (args.size() != 1) { \ + WrongNumberOfParameters(1); \ + } \ + det->SETFCN(args[0], {det_id}); \ + os << args.front() << '\n'; \ + } else { \ + throw sls::RuntimeError("Unknown action"); \ + } \ + return os.str(); \ + } + + +/** int or enum */ +#define INTEGER_COMMAND_HEX(CMDNAME, GETFCN, SETFCN, CONV, HLPSTR) \ + std::string CMDNAME(const int action) { \ + std::ostringstream os; \ + os << cmd << ' '; \ + if (action == slsDetectorDefs::HELP_ACTION) \ + os << HLPSTR << '\n'; \ + else if (action == slsDetectorDefs::GET_ACTION) { \ + auto t = det->GETFCN({det_id}); \ + if (args.size() != 0) { \ + WrongNumberOfParameters(0); \ + } \ + os << OutStringHex(t) << '\n'; \ + } else if (action == slsDetectorDefs::PUT_ACTION) { \ + if (args.size() != 1) { \ + WrongNumberOfParameters(1); \ + } \ + auto val = CONV(args[0]); \ + det->SETFCN(val, {det_id}); \ + os << args.front() << '\n'; \ + } else { \ + throw sls::RuntimeError("Unknown action"); \ + } \ + return os.str(); \ + } + +/** int or enum hex val */ +#define INTEGER_COMMAND(CMDNAME, GETFCN, SETFCN, CONV, HLPSTR) \ + std::string CMDNAME(const int action) { \ + std::ostringstream os; \ + os << cmd << ' '; \ + if (action == slsDetectorDefs::HELP_ACTION) \ + os << HLPSTR << '\n'; \ + else if (action == slsDetectorDefs::GET_ACTION) { \ + auto t = det->GETFCN({det_id}); \ + if (args.size() != 0) { \ + WrongNumberOfParameters(0); \ + } \ + os << OutString(t) << '\n'; \ + } else if (action == slsDetectorDefs::PUT_ACTION) { \ + if (args.size() != 1) { \ + WrongNumberOfParameters(1); \ + } \ + auto val = CONV(args[0]); \ + det->SETFCN(val, {det_id}); \ + os << args.front() << '\n'; \ + } else { \ + throw sls::RuntimeError("Unknown action"); \ + } \ + return os.str(); \ + } + +/** int, no id */ +#define INTEGER_COMMAND_NOID(CMDNAME, GETFCN, SETFCN, CONV, HLPSTR) \ + std::string CMDNAME(const int action) { \ + std::ostringstream os; \ + os << cmd << ' '; \ + if (det_id != -1) { \ + throw sls::RuntimeError("Cannot execute this at module level"); \ + } \ + if (action == slsDetectorDefs::HELP_ACTION) \ + os << HLPSTR << '\n'; \ + else if (action == slsDetectorDefs::GET_ACTION) { \ + auto t = det->GETFCN(); \ + if (args.size() != 0) { \ + WrongNumberOfParameters(0); \ + } \ + os << OutString(t) << '\n'; \ + } else if (action == slsDetectorDefs::PUT_ACTION) { \ + if (args.size() != 1) { \ + WrongNumberOfParameters(1); \ + } \ + auto val = CONV(args[0]); \ + det->SETFCN(val); \ + os << args.front() << '\n'; \ + } else { \ + throw sls::RuntimeError("Unknown action"); \ + } \ + return os.str(); \ + } + +/** int with index, */ +#define INTEGER_IND_COMMAND(CMDNAME, GETFCN, SETFCN, CONV, INDEX, HLPSTR) \ + std::string CMDNAME(const int action) { \ + std::ostringstream os; \ + os << cmd << ' '; \ + if (action == slsDetectorDefs::HELP_ACTION) \ + os << HLPSTR << '\n'; \ + else if (action == slsDetectorDefs::GET_ACTION) { \ + auto t = det->GETFCN(INDEX, {det_id}); \ + if (args.size() != 0) { \ + WrongNumberOfParameters(0); \ + } \ + os << OutString(t) << '\n'; \ + } else if (action == slsDetectorDefs::PUT_ACTION) { \ + if (args.size() != 1) { \ + WrongNumberOfParameters(1); \ + } \ + auto val = CONV(args[0]); \ + det->SETFCN(INDEX, val, {det_id}); \ + os << args.front() << '\n'; \ + } else { \ + throw sls::RuntimeError("Unknown action"); \ + } \ + return os.str(); \ + } + + +/** dac */ +#define DAC_COMMAND(CMDNAME, GETFCN, SETFCN, DAC_INDEX, HLPSTR) \ + std::string CMDNAME(const int action) { \ + std::ostringstream os; \ + os << cmd << ' '; \ + if (action == slsDetectorDefs::HELP_ACTION) \ + os << HLPSTR << '\n'; \ + else if (action == slsDetectorDefs::GET_ACTION) { \ + bool mv = false; \ + if (args.size() == 1) { \ + if (args[0] != "mv") { \ + throw sls::RuntimeError("Unknown argument " + args[0] + ". Did you mean mv?"); \ + } \ + mv = true; \ + } else if (args.size() > 1) { \ + WrongNumberOfParameters(1); \ + } \ + auto t = det->GETFCN(DAC_INDEX, mv, {det_id}); \ + os << OutString(t) << (args.size() > 1 ? " mv\n" : "\n"); \ + } else if (action == slsDetectorDefs::PUT_ACTION) { \ + bool mv = false; \ + if (args.size() == 2) { \ + if (args[1] != "mv") { \ + throw sls::RuntimeError("Unknown argument " + args[1] + ". Did you mean mv?"); \ + } \ + mv = true; \ + } else if (args.size() > 2 || args.size() < 1) { \ + WrongNumberOfParameters(1); \ + } \ + det->SETFCN(DAC_INDEX, std::stoi(args[0]), mv, {det_id}); \ + os << args.front() << (args.size() > 1 ? " mv\n" : "\n"); \ + } else { \ + throw sls::RuntimeError("Unknown action"); \ + } \ + return os.str(); \ + } + +/** set only, no arguments, no id */ +#define EXECUTE_SET_COMMAND_NOID(CMDNAME, SETFCN, HLPSTR) \ + std::string CMDNAME(const int action) { \ + std::ostringstream os; \ + os << cmd << ' '; \ + if (det_id != -1) { \ + throw sls::RuntimeError("Cannot execute this at module level"); \ + } \ + if (action == slsDetectorDefs::HELP_ACTION) \ + os << HLPSTR << '\n'; \ + else if (action == slsDetectorDefs::GET_ACTION) { \ + throw sls::RuntimeError("Cannot get"); \ + } else if (action == slsDetectorDefs::PUT_ACTION) { \ + if (args.size() != 0) { \ + WrongNumberOfParameters(0); \ + } \ + det->SETFCN(); \ + os << "successful\n"; \ + } else { \ + throw sls::RuntimeError("Unknown action"); \ + } \ + return os.str(); \ + } + +/** set only, no arguments */ +#define EXECUTE_SET_COMMAND(CMDNAME, SETFCN, HLPSTR) \ + std::string CMDNAME(const int action) { \ + std::ostringstream os; \ + os << cmd << ' '; \ + if (action == slsDetectorDefs::HELP_ACTION) \ + os << HLPSTR << '\n'; \ + else if (action == slsDetectorDefs::GET_ACTION) { \ + throw sls::RuntimeError("Cannot get"); \ + } else if (action == slsDetectorDefs::PUT_ACTION) { \ + if (args.size() != 0) { \ + WrongNumberOfParameters(0); \ + } \ + det->SETFCN({det_id}); \ + os << "successful\n"; \ + } else { \ + throw sls::RuntimeError("Unknown action"); \ + } \ + return os.str(); \ + } + +/** set only, 1 argument, no id */ +#define EXECUTE_SET_COMMAND_NOID_1ARG(CMDNAME, SETFCN, HLPSTR) \ + std::string CMDNAME(const int action) { \ + std::ostringstream os; \ + os << cmd << ' '; \ + if (det_id != -1) { \ + throw sls::RuntimeError("Cannot execute this at module level"); \ + } \ + if (action == slsDetectorDefs::HELP_ACTION) \ + os << HLPSTR << '\n'; \ + else if (action == slsDetectorDefs::GET_ACTION) { \ + throw sls::RuntimeError("Cannot get"); \ + } else if (action == slsDetectorDefs::PUT_ACTION) { \ + if (args.size() != 1) { \ + WrongNumberOfParameters(1); \ + } \ + det->SETFCN(args[0]); \ + os << args.front() << '\n'; \ + } else { \ + throw sls::RuntimeError("Unknown action"); \ + } \ + return os.str(); \ + } + +/** get only */ +#define GET_COMMAND(CMDNAME, GETFCN, HLPSTR) \ + std::string CMDNAME(const int action) { \ + std::ostringstream os; \ + os << cmd << ' '; \ + if (action == slsDetectorDefs::HELP_ACTION) \ + os << HLPSTR << '\n'; \ + else if (action == slsDetectorDefs::GET_ACTION) { \ + if (args.size() != 0) { \ + WrongNumberOfParameters(0); \ + } \ + auto t = det->GETFCN({det_id}); \ + os << OutString(t) << '\n'; \ + } else if (action == slsDetectorDefs::PUT_ACTION) { \ + throw sls::RuntimeError("Cannot put"); \ + } else { \ + throw sls::RuntimeError("Unknown action"); \ + } \ + return os.str(); \ + } + +/** get only hex*/ +#define GET_COMMAND_HEX(CMDNAME, GETFCN, HLPSTR) \ + std::string CMDNAME(const int action) { \ + std::ostringstream os; \ + os << cmd << ' '; \ + if (action == slsDetectorDefs::HELP_ACTION) \ + os << HLPSTR << '\n'; \ + else if (action == slsDetectorDefs::GET_ACTION) { \ + if (args.size() != 0) { \ + WrongNumberOfParameters(0); \ + } \ + auto t = det->GETFCN({det_id}); \ + os << OutStringHex(t) << '\n'; \ + } else if (action == slsDetectorDefs::PUT_ACTION) { \ + throw sls::RuntimeError("Cannot put"); \ + } else { \ + throw sls::RuntimeError("Unknown action"); \ + } \ + return os.str(); \ + } + +#define GET_IND_COMMAND(CMDNAME, GETFCN, VAL, APPEND, HLPSTR) \ + std::string CMDNAME(const int action) { \ + std::ostringstream os; \ + os << cmd << ' '; \ + if (action == slsDetectorDefs::HELP_ACTION) \ + os << HLPSTR << '\n'; \ + else if (action == slsDetectorDefs::GET_ACTION) { \ + if (args.size() != 0) { \ + WrongNumberOfParameters(0); \ + } \ + auto t = det->GETFCN(VAL, {det_id}); \ + os << OutString(t) << APPEND << '\n'; \ + } else if (action == slsDetectorDefs::PUT_ACTION) { \ + throw sls::RuntimeError("Cannot put"); \ } else { \ throw sls::RuntimeError("Unknown action"); \ } \ @@ -95,8 +405,14 @@ class CmdProxy { std::vector args; int det_id{-1}; + template std::string OutStringHex(const V &value) { + if (value.equal()) + return ToStringHex(value.front()); + return ToStringHex(value); + } + template std::string OutString(const V &value) { - if (value.equal()) + if (value.equal()) return ToString(value.front()); return ToString(value); } @@ -107,164 +423,822 @@ class CmdProxy { return ToString(value, unit); } + inline unsigned int stoui(const std::string& s) { + unsigned long lresult = stoul(s, 0, 10); + unsigned int result = lresult; + if (result != lresult) throw std::out_of_range("cannot convert to unsigned int"); + return result; + } + using FunctionMap = std::map; using StringMap = std::map; + StringMap depreciated_functions{ + /* configuration */ + {"detectorversion", "firmwareversion"}, + {"softwareversion", "detectorserverversion"}, + {"receiverversion", "rx_version"}, + {"thisversion", "clientversion"}, + {"detsizechan", "detsize"}, + + /* acquisition parameters */ + {"cycles", "triggers"}, + {"cyclesl", "triggersl"}, + {"clkdivider", "speed"}, + + /* acquisition */ + {"busy", "clearbusy"}, + {"receiver", "rx_status"}, + {"framescaught", "rx_framescaught"}, + + /* Network Configuration (Detector<->Receiver) */ + {"detectorip", "udp_srcip"}, + {"detectorip2", "udp_srcip2"}, + {"detectormac", "udp_srcmac"}, + {"detectormac2", "udp_srcmac2"}, + {"rx_udpip", "udp_dstip"}, + {"rx_udpip2", "udp_dstip2"}, + {"rx_udpmac", "udp_dstmac"}, + {"rx_udpmac2", "udp_dstmac2"}, + {"rx_udpport", "udp_dstport"}, + {"rx_udpport2", "udp_dstport2"}, + + /* Receiver Config */ + {"r_silent", "rx_silent"}, + {"r_discardpolicy", "rx_discardpolicy"}, + {"r_padding", "rx_padding"}, + {"r_lock", "rx_lock"}, + {"r_lastclient", "rx_lastclient"}, + + /* File */ + {"fileformat", "fformat"}, + {"outdir", "fpath"}, + {"index", "findex"}, + {"enablefwrite", "fwrite"}, + {"masterfile", "fmaster"}, + {"overwrite", "foverwrite"}, + {"r_framesperfile", "rx_framesperfile"}, + + /* ZMQ Streaming Parameters (Receiver<->Client) */ + {"r_readfreq", "rx_readfreq"}, + + /* Eiger Specific */ + {"trimdir", "settingspath"}, + {"settingsdir", "settingspath"}, + {"resmat", "partialreset"}, + + /* Jungfrau Specific */ + /* Gotthard Specific */ + {"digitest", "imagetest"}, + + /* Gotthard2 Specific */ + /* CTB Specific */ + {"flags", "romode"}, + {"i_a", "im_a"}, + {"i_b", "im_b"}, + {"i_c", "im_c"}, + {"i_d", "im_d"}, + {"i_io", "im_io"} + + /* Pattern */ + + + }; + // Initialize maps for translating name and function FunctionMap functions{{"list", &CmdProxy::ListCommands}, - {"exptime", &CmdProxy::Exptime}, - {"period", &CmdProxy::Period}, - {"subexptime", &CmdProxy::SubExptime}, - {"frames", &CmdProxy::frames}, - {"parallel", &CmdProxy::parallel}, - {"overflow", &CmdProxy::overflow}, - {"storeinram", &CmdProxy::storeinram}, - {"fwrite", &CmdProxy::fwrite}, - {"fmaster", &CmdProxy::fmaster}, - {"foverwrite", &CmdProxy::foverwrite}, - {"findex", &CmdProxy::findex}, - {"rx_fifodepth", &CmdProxy::rx_fifodepth}, - {"rx_silent", &CmdProxy::rx_silent}, - {"rx_lock", &CmdProxy::rx_lock}, - {"lock", &CmdProxy::lock}, - {"rx_readfreq", &CmdProxy::rx_readfreq}, - {"rx_padding", &CmdProxy::rx_padding}, - {"rx_framesperfile", &CmdProxy::rx_framesperfile}, - {"detectormac", &CmdProxy::detectormac}, - {"detectormac2", &CmdProxy::detectormac2}, - {"rx_udpmac", &CmdProxy::rx_udpmac}, - {"rx_udpmac2", &CmdProxy::rx_udpmac2}, - {"detectorip", &CmdProxy::detectorip}, - {"detectorip2", &CmdProxy::detectorip2}, - {"rx_udpip", &CmdProxy::rx_udpip}, - {"rx_udpip2", &CmdProxy::rx_udpip2}, - {"rx_udpport", &CmdProxy::rx_udpport}, - {"rx_udpport2", &CmdProxy::rx_udpport2}, - {"numinterfaces", &CmdProxy::numinterfaces}, - {"selinterface", &CmdProxy::selinterface}, + + /* configuration */ + //{"config", &CmdProxy::config}, + {"parameters", &CmdProxy::parameters}, + {"hostname", &CmdProxy::Hostname}, + {"versions", &CmdProxy::Versions}, + {"packageversion", &CmdProxy::PackageVersion}, + {"clientversion", &CmdProxy::ClientVersion}, + {"firmwareversion", &CmdProxy::FirmwareVersion}, + {"detectorserverversion", &CmdProxy::detectorserverversion}, + {"rx_version", &CmdProxy::rx_version}, + {"detectornumber", &CmdProxy::detectornumber}, + {"type", &CmdProxy::type}, + {"detsize", &CmdProxy::DetectorSize}, + {"settings", &CmdProxy::settings}, + + /* acquisition parameters */ + {"frames", &CmdProxy::frames}, + {"triggers", &CmdProxy::triggers}, + {"exptime", &CmdProxy::exptime}, + {"period", &CmdProxy::period}, + {"delay", &CmdProxy::delay}, + {"delay", &CmdProxy::delay}, + {"framesl", &CmdProxy::framesl}, + {"triggersl", &CmdProxy::triggersl}, + {"delayl", &CmdProxy::delayl}, + {"speed", &CmdProxy::Speed}, + {"adcphase", &CmdProxy::Adcphase}, + {"maxadcphaseshift", &CmdProxy::maxadcphaseshift}, {"clkfreq", &CmdProxy::ClockFrequency}, {"clkphase", &CmdProxy::ClockPhase}, {"maxclkphaseshift", &CmdProxy::MaxClockPhaseShift}, - {"clkdiv", &CmdProxy::ClockDivider}}; + {"clkdiv", &CmdProxy::ClockDivider}, + {"vhighvoltage", &CmdProxy::vhighvoltage}, + {"temp_adc", &CmdProxy::temp_adc}, + {"temp_fpga", &CmdProxy::temp_fpga}, + {"temp_fpgaext", &CmdProxy::temp_fpgaext}, + {"temp_10ge", &CmdProxy::temp_10ge}, + {"temp_dcdc", &CmdProxy::temp_dcdc}, + {"temp_sodl", &CmdProxy::temp_sodl}, + {"temp_sodr", &CmdProxy::temp_sodr}, + {"temp_fpgafl", &CmdProxy::temp_fpgafl}, + {"temp_fpgafr", &CmdProxy::temp_fpgafr}, + // dacs + {"timing", &CmdProxy::timing}, + + /* acquisition */ + {"clearbusy", &CmdProxy::clearbusy}, + {"rx_start", &CmdProxy::rx_start}, + {"rx_stop", &CmdProxy::rx_stop}, + {"start", &CmdProxy::start}, + {"stop", &CmdProxy::stop}, + {"rx_status", &CmdProxy::rx_status}, + {"rx_framescaught", &CmdProxy::rx_framescaught}, + {"startingfnum", &CmdProxy::startingfnum}, + {"trigger", &CmdProxy::trigger}, + + /* Network Configuration (Detector<->Receiver) */ + {"numinterfaces", &CmdProxy::numinterfaces}, + {"selinterface", &CmdProxy::selinterface}, + {"udp_srcip", &CmdProxy::udp_srcip}, + {"udp_srcip2", &CmdProxy::udp_srcip2}, + {"udp_dstip", &CmdProxy::udp_dstip}, + {"udp_dstip2", &CmdProxy::udp_dstip2}, + {"udp_srcmac", &CmdProxy::udp_srcmac}, + {"udp_srcmac2", &CmdProxy::udp_srcmac2}, + {"udp_dstmac", &CmdProxy::udp_dstmac}, + {"udp_dstmac2", &CmdProxy::udp_dstmac2}, + {"udp_dstport", &CmdProxy::udp_dstport}, + {"udp_dstport2", &CmdProxy::udp_dstport2}, + {"rx_printconfig", &CmdProxy::rx_printconfig}, + {"tengiga", &CmdProxy::tengiga}, + {"flowcontrol_10g", &CmdProxy::flowcontrol_10g}, + {"txndelay_frame", &CmdProxy::txndelay_frame}, + {"txndelay_left", &CmdProxy::txndelay_left}, + {"txndelay_right", &CmdProxy::txndelay_right}, + + /* Receiver Config */ + {"rx_hostname", &CmdProxy::rx_hostname}, + {"rx_tcpport", &CmdProxy::rx_tcpport}, + {"rx_fifodepth", &CmdProxy::rx_fifodepth}, + {"rx_silent", &CmdProxy::rx_silent}, + {"rx_discardpolicy", &CmdProxy::rx_discardpolicy}, + {"rx_padding", &CmdProxy::rx_padding}, + {"rx_udpsocksize", &CmdProxy::rx_udpsocksize}, + {"rx_realudpsocksize", &CmdProxy::rx_realudpsocksize}, + {"rx_lock", &CmdProxy::rx_lock}, + {"rx_lastclient", &CmdProxy::rx_lastclient}, + + /* File */ + {"fformat", &CmdProxy::fformat}, + {"fpath", &CmdProxy::fpath}, + {"fname", &CmdProxy::fname}, + {"findex", &CmdProxy::findex}, + {"fwrite", &CmdProxy::fwrite}, + {"fmaster", &CmdProxy::fmaster}, + {"foverwrite", &CmdProxy::foverwrite}, + {"rx_framesperfile", &CmdProxy::rx_framesperfile}, + + /* ZMQ Streaming Parameters (Receiver<->Client) */ + {"rx_datastream", &CmdProxy::rx_datastream}, + {"rx_readfreq", &CmdProxy::rx_readfreq}, + {"rx_zmqport", &CmdProxy::rx_zmqport}, + {"zmqport", &CmdProxy::zmqport}, + {"rx_zmqip", &CmdProxy::rx_zmqip}, + {"zmqip", &CmdProxy::zmqip}, + + /* Eiger Specific */ + {"dr", &CmdProxy::DynamicRange}, + {"subexptime", &CmdProxy::subexptime}, + {"subdeadtime", &CmdProxy::subdeadtime}, + {"threshold", &CmdProxy::Threshold}, + {"thresholdnotb", &CmdProxy::ThresholdNoTb}, + {"settingspath", &CmdProxy::settingspath}, + {"trimbits", &CmdProxy::trimbits}, + {"gappixels", &CmdProxy::GapPixels}, + {"parallel", &CmdProxy::parallel}, + {"overflow", &CmdProxy::overflow}, + {"storeinram", &CmdProxy::storeinram}, + {"flippeddatax", &CmdProxy::flippeddatax}, + {"trimval", &CmdProxy::trimval}, + {"trimen", &CmdProxy::TrimEnergies}, + {"ratecorr", &CmdProxy::RateCorrection}, + {"readnlines", &CmdProxy::readnlines}, + {"interruptsubframe", &CmdProxy::interruptsubframe}, + {"measuredperiod", &CmdProxy::measuredperiod}, + {"measuredsubperiod", &CmdProxy::measuredsubperiod}, + {"activate", &CmdProxy::Activate}, + {"partialreset", &CmdProxy::partialreset}, + {"pulse", &CmdProxy::PulsePixel}, + {"pulsenmove", &CmdProxy::PulsePixelAndMove}, + {"pulsechip", &CmdProxy::PulseChip}, + {"quad", &CmdProxy::Quad}, + + /* Jungfrau Specific */ + {"temp_threshold", &CmdProxy::temp_threshold}, + {"temp_control", &CmdProxy::temp_control}, + {"temp_event", &CmdProxy::TemperatureEvent}, + {"powerchip", &CmdProxy::powerchip}, + {"auto_comp_disable", &CmdProxy::auto_comp_disable}, + {"storagecells", &CmdProxy::storagecells}, + {"storagecell_start", &CmdProxy::storagecell_start}, + {"storagecell_delay", &CmdProxy::storagecell_delay}, + + /* Gotthard Specific */ + {"roi", &CmdProxy::ROI}, + {"clearroi", &CmdProxy::ClearROI}, + {"exptimel", &CmdProxy::exptimel}, + {"periodl", &CmdProxy::periodl}, + {"extsig", &CmdProxy::extsig}, + {"imagetest", &CmdProxy::imagetest}, + + /* Gotthard2 Specific */ + /* CTB Specific */ + {"samples", &CmdProxy::Samples}, + {"asamples", &CmdProxy::asamples}, + {"dsamples", &CmdProxy::dsamples}, + {"romode", &CmdProxy::romode}, + {"dbitphase", &CmdProxy::Dbitphase}, + {"maxdbitphaseshift", &CmdProxy::maxdbitphaseshift}, + {"adcclk", &CmdProxy::adcclk}, + {"dbitclk", &CmdProxy::dbitclk}, + {"runclk", &CmdProxy::runclk}, + {"syncclk", &CmdProxy::syncclk}, + {"adcpipeline", &CmdProxy::adcpipeline}, + {"dbitpipeline", &CmdProxy::dbitpipeline}, + {"v_limit", &CmdProxy::v_limit}, + {"v_a", &CmdProxy::v_a}, + {"v_b", &CmdProxy::v_b}, + {"v_c", &CmdProxy::v_c}, + {"v_d", &CmdProxy::v_d}, + {"v_io", &CmdProxy::v_io}, + {"v_chip", &CmdProxy::v_chip}, + {"vm_a", &CmdProxy::vm_a}, + {"vm_b", &CmdProxy::vm_b}, + {"vm_c", &CmdProxy::vm_c}, + {"vm_d", &CmdProxy::vm_d}, + {"vm_io", &CmdProxy::vm_io}, + {"im_a", &CmdProxy::im_a}, + {"im_b", &CmdProxy::im_b}, + {"im_c", &CmdProxy::im_c}, + {"im_d", &CmdProxy::im_d}, + {"im_io", &CmdProxy::im_io}, + {"adc", &CmdProxy::SlowAdc}, + {"adcenable", &CmdProxy::adcenable}, + {"adcinvert", &CmdProxy::adcinvert}, + {"extsampling", &CmdProxy::extsampling}, + {"extsamplingsrc", &CmdProxy::extsamplingsrc}, + {"rx_dbitlist", &CmdProxy::ReceiverDbitList}, + {"rx_dbitoffset", &CmdProxy::rx_dbitoffset}, + {"diodelay", &CmdProxy::DigitalIODelay}, + {"led", &CmdProxy::led}, + + /* Pattern */ + {"pattern", &CmdProxy::Pattern}, + {"savepattern", &CmdProxy::savepattern}, + {"patioctrl", &CmdProxy::patioctrl}, + {"patclkctrl", &CmdProxy::patclkctrl}, + {"patword", &CmdProxy::PatternWord}, + + + + {"adcvpp", &CmdProxy::adcvpp}, + {"lastclient", &CmdProxy::lastclient}, + {"lock", &CmdProxy::lock} + }; - StringMap depreciated_functions{{"r_readfreq", "rx_readfreq"}, - {"r_padding", "rx_padding"}, - {"r_silent", "rx_silent"}, - {"r_lastclient", "rx_lastclient"}, - {"r_lock", "rx_lock"}, - {"r_online", "rx_online"}, - {"r_checkonline", "rx_checkonline"}, - {"r_framesperfile", "rx_framesperfile"}, - {"r_discardpolicy", "rx_discardpolicy"}, - {"receiverversion", "rx_version"}, - {"receiver", "rx_status"}, - {"index", "findex"}, - {"exitreceiver", "rx_exit"}, - {"enablefwrite", "fwrite"}, - {"checkrecversion", "rx_checkversion"}, - {"masterfile", "fmaster"}, - {"outdir", "fpath"}, - {"fileformat", "fformat"}, - {"overwrite", "foverwrite"}, - {"flags", "romode"}}; void WrongNumberOfParameters(size_t expected); /* Commands */ std::string ListCommands(int action); - std::string Period(int action); - std::string Exptime(int action); - std::string SubExptime(int action); + /* configuration */ + std::string Hostname(int action); + std::string FirmwareVersion(int action); + std::string Versions(int action); + std::string PackageVersion(int action); + std::string ClientVersion(int action); + std::string DetectorSize(int action); + /* acquisition parameters */ + std::string Speed(int action); + std::string Adcphase(int action); std::string ClockFrequency(int action); std::string ClockPhase(int action); std::string MaxClockPhaseShift(int action); std::string ClockDivider(int action); + /* acquisition */ + /* Network Configuration (Detector<->Receiver) */ + /* Receiver Config */ + /* File */ + /* ZMQ Streaming Parameters (Receiver<->Client) */ + /* Eiger Specific */ + std::string DynamicRange(int action); + std::string Threshold(int action); + std::string ThresholdNoTb(int action); + std::string GapPixels(int action); + std::string TrimEnergies(int action); + std::string RateCorrection(int action); + std::string Activate(int action); + std::string PulsePixel(int action); + std::string PulsePixelAndMove(int action); + std::string PulseChip(int action); + std::string Quad(int action); + /* Jungfrau Specific */ + std::string TemperatureEvent(int action); + std::string PowerChip(int action); + /* Gotthard Specific */ + std::string ROI(int action); + std::string ClearROI(int action); + /* Gotthard2 Specific */ + /* CTB Specific */ + std::string Samples(int action); + std::string Dbitphase(int action); + std::string SlowAdc(int action); + std::string ReceiverDbitList(int action); + std::string DigitalIODelay(int action); + /* Pattern */ + std::string Pattern(int action); + std::string PatternWord(int action); + /* configuration */ + EXECUTE_SET_COMMAND_NOID_1ARG(config, loadConfig, + "[fname]\n\tConfigures detector to configuration contained in fname. Set up once."); + + EXECUTE_SET_COMMAND_NOID_1ARG(parameters, loadParameters, + "[fname]\n\tSets detector measurement parameters to those contained in fname. Set up per measurement."); + + GET_COMMAND_HEX(detectorserverversion, getDetectorServerVersion, + "\n\tOn-board detector server software version in format [0xYYMMDD]."); + + GET_COMMAND_HEX(rx_version, getReceiverVersion, + "\n\tReceiver version in format [0xYYMMDD]."); + + GET_COMMAND_HEX(detectornumber, getSerialNumber, + "\n\tReceiver version in format [0xYYMMDD]."); + + GET_COMMAND(type, getDetectorType, + "\n\tSerial number or MAC of detector (hex)."); + + INTEGER_COMMAND(settings, getSettings, setSettings, sls::StringTo, + "[standard, fast, highgain, dynamicgain, lowgain, mediumgain, veryhighgain, dynamichg0, fixgain1, fixgain2, forceswitchg1, forceswitchg2]\n\t[Jungfrau][Gotthard] Detector Settings.\n\t[Eiger] Use threshold or thresholdnotb."); + + /* acquisition parameters */ + + INTEGER_COMMAND_NOID(frames, getNumberOfFrames, setNumberOfFrames, + std::stol, + "[n_frames]\n\tNumber of frames per aquire. In trigger mode, number of frames per trigger."); + + INTEGER_COMMAND_NOID(triggers, getNumberOfTriggers, setNumberOfTriggers, + std::stol, + "[n_triggers]\n\tNumber of triggers per aquire. Use timing command to set timing mode."); + + TIME_COMMAND(exptime, getExptime, setExptime, + "[duration] [(optional unit) ns|us|ms|s]\n\tExposure time"); + + TIME_COMMAND(period, getPeriod, setPeriod, + "[duration] [(optional unit) ns|us|ms|s]\n\tPeriod between frames"); + + TIME_COMMAND(delay, getDelayAfterTrigger, setDelayAfterTrigger, + "[duration] [(optional unit) ns|us|ms|s]\n\t[Jungfrau][Gotthard][Ctb] Delay after trigger"); + + GET_COMMAND(framesl, getNumberOfFramesLeft, + "\n\t[Gotthard][Jungfrau][CTB] Number of frames left in acquisition."); + + GET_COMMAND(triggersl, getNumberOfTriggersLeft, + "\n\t[Gotthard][Jungfrau][CTB] Number of triggers left in acquisition."); + + TIME_GET_COMMAND(delayl, getDelayAfterTriggerLeft, + "[(optional unit) ns|us|ms|s]\n\t[Gotthard][Jungfrau][CTB] DelayLeft Delay Left in Acquisition."); + + GET_COMMAND(maxadcphaseshift, getMaxADCPhaseShift, + "\n\t[Jungfrau][CTB] Absolute maximum Phase shift of ADC clock."); + + INTEGER_COMMAND(vhighvoltage, getHighVoltage, setHighVoltage, std::stoi, + "[n_value]\n\tHigh voltage to the sensor in Voltage.\n\t[Gotthard] [0|90|110|120|150|180|200]\n\t[Eiger] 0-200\n\t[Jungfrau][Ctb] [0|60-200]"); + + GET_IND_COMMAND(temp_adc, getTemperature, slsDetectorDefs::TEMPERATURE_ADC, " °C", + "[n_value]\n\t[Jungfrau][Gotthard] ADC Temperature"); + + GET_IND_COMMAND(temp_fpga, getTemperature, slsDetectorDefs::TEMPERATURE_FPGA, " °C", + "[n_value]\n\t[Eiger][Jungfrau][Gotthard] FPGA Temperature"); + + GET_IND_COMMAND(temp_fpgaext, getTemperature, slsDetectorDefs::TEMPERATURE_FPGAEXT, " °C", + "[n_value]\n\t[Eiger]Temperature close to the FPGA"); + + GET_IND_COMMAND(temp_10ge, getTemperature, slsDetectorDefs::TEMPERATURE_10GE, " °C", + "[n_value]\n\t[Eiger]Temperature close to the 10GbE"); + + GET_IND_COMMAND(temp_dcdc, getTemperature, slsDetectorDefs::TEMPERATURE_DCDC, " °C", + "[n_value]\n\t[Eiger]Temperature close to the dc dc converter"); + + GET_IND_COMMAND(temp_sodl, getTemperature, slsDetectorDefs::TEMPERATURE_SODL, " °C", + "[n_value]\n\t[Eiger]Temperature close to the left so-dimm memory"); + + GET_IND_COMMAND(temp_sodr, getTemperature, slsDetectorDefs::TEMPERATURE_SODR, " °C", + "[n_value]\n\t[Eiger]Temperature close to the right so-dimm memory"); + + GET_IND_COMMAND(temp_fpgafl, getTemperature, slsDetectorDefs::TEMPERATURE_FPGA2, " °C", + "[n_value]\n\t[Eiger]Temperature of the left front end board fpga"); + + GET_IND_COMMAND(temp_fpgafr, getTemperature, slsDetectorDefs::TEMPERATURE_FPGA3, " °C", + "[n_value]\n\t[Eiger]Temperature of the left front end board fpga"); + + //dacs + + INTEGER_COMMAND(timing, getTimingMode, setTimingMode, sls::StringTo, + "[auto|trigger|gating|burst_trigger]\n\tTiming Mode of detector.\n\t[Jungfrau][Gotthard][Ctb] [auto|trigger]\n\t[Eiger] [auto|trigger|gating|burst_trigger]"); + + /* acquisition */ + + EXECUTE_SET_COMMAND_NOID(clearbusy, clearAcquiringFlag, + "\n\tClears Acquiring Flag for unexpected acquire command terminations."); + + EXECUTE_SET_COMMAND_NOID(rx_start, startReceiver, + "\n\tStarts receiver listener for detector data packets and create a data file (if file write enabled)."); + + EXECUTE_SET_COMMAND_NOID(rx_stop, stopReceiver, + "\n\tStops receiver listener for detector data packets and closes current data file (if file write enabled)."); + + EXECUTE_SET_COMMAND_NOID(start, startDetector, + "\n\tStarts detector state machine."); + + EXECUTE_SET_COMMAND_NOID(stop, stopDetector, + "\n\tStops detector state machine."); + + GET_COMMAND(rx_status, getReceiverStatus, + "running, idle]\n\tReceiver listener status."); + + GET_COMMAND(status, getDetectorStatus, + "[running, error, transmitting, finished, waiting, idle]\n\tDetector status."); + + GET_COMMAND(rx_framescaught, getFramesCaught, + "\n\tNumber of frames caught by receiver."); + + INTEGER_COMMAND(startingfnum, getStartingFrameNumber, setStartingFrameNumber, std::stoul, + "[n_value]\n\t[Eiger[Jungfrau] Starting frame number for next acquisition."); + + EXECUTE_SET_COMMAND(trigger, sendSoftwareTrigger, + "\n\t[Eiger] Sends software trigger signal to detector."); + + + /* Network Configuration (Detector<->Receiver) */ + + INTEGER_COMMAND(numinterfaces, getNumberofUDPInterfaces, setNumberofUDPInterfaces, std::stoi, + "[1, 2]\n\t[Jungfrau] Number of udp interfaces to stream data from detector. Default: 1."); + + INTEGER_COMMAND(selinterface, getSelectedUDPInterface, selectUDPInterface, std::stoi, + "[0, 1]\n\t[Jungfrau] The udp interface to stream data from detector. Effective only when number of interfaces is 1. Default: 0 (outer)"); + + INTEGER_COMMAND(udp_srcip, getSourceUDPIP, setSourceUDPIP, IpAddr, + "[x.x.x.x]\n\tIp address of the detector (source) udp interface. Must be same subnet as destination udp ip."); + + INTEGER_COMMAND(udp_srcip2, getSourceUDPIP2, setSourceUDPIP2, IpAddr, + "[x.x.x.x]\n\t[Jungfrau] Ip address of the bottom half of detector (source) udp interface. Must be same subnet as destination udp ip2."); + + INTEGER_COMMAND(udp_dstip, getDestinationUDPIP, setDestinationUDPIP, IpAddr, + "[x.x.x.x]\n\tIp address of the receiver (destination) udp interface."); + + INTEGER_COMMAND(udp_dstip2, getDestinationUDPIP2, setDestinationUDPIP2, IpAddr, + "[x.x.x.x]\n\t[Jungfrau] Ip address of the receiver (destination) udp interface where the second half of detector data is sent to."); + + INTEGER_COMMAND(udp_srcmac, getSourceUDPMAC, setSourceUDPMAC, MacAddr, + "[x:x:x:x:x:x]\n\tMac address of the detector (source) udp interface. "); + + INTEGER_COMMAND(udp_srcmac2, getSourceUDPMAC2, setSourceUDPMAC2, MacAddr, + "[x:x:x:x:x:x]\n\t[Jungfrau] Mac address of the bottom half of detector (source) udp interface. "); + + INTEGER_COMMAND(udp_dstmac, getDestinationUDPMAC, setDestinationUDPMAC, MacAddr, + "[x:x:x:x:x:x]\n\tMac address of the receiver (destination) udp interface. Can be unused as rx_hostname/udp_dstip retrieves it."); + + INTEGER_COMMAND(udp_dstmac2, getDestinationUDPMAC2, setDestinationUDPMAC2, MacAddr, + "[x:x:x:x:x:x]\n\t[Jungfrau] Mac address of the receiver (destination) udp interface where the second half of detector data is sent to. Can be unused as rx_hostname/udp_dstip2 retrieves it."); + + INTEGER_COMMAND(udp_dstport, getDestinationUDPPort, setDestinationUDPPort, std::stoi, + "[n]\n\tPort number of the receiver (destination) udp interface. Default is 50001."); + + INTEGER_COMMAND(udp_dstport2, getDestinationUDPPort2, setDestinationUDPPort2, std::stoi, + "[n]\n\tDefault is 50002.\n\t[Jungfrau] Port number of the receiver (destination) udp interface where the second half of detector data is sent to. \n[Eiger] Port number of the reciever (desintation) udp interface where the right half of the detector data is sent to."); + + GET_COMMAND(rx_printconfig, printRxConfiguration, + "\n\tPrints the receiver configuration."); + + INTEGER_COMMAND(tengiga, getTenGiga, setTenGiga, std::stoi, + "[0, 1]\n\t[Eiger][Ctb] 10GbE Enable."); + + INTEGER_COMMAND(flowcontrol_10g, getTransmissionDelayFrame, setTenGigaFlowControl, std::stoi, + "[0, 1]\n\t[Eiger][Jungfrau] 10GbE Flow Control."); + + INTEGER_COMMAND(txndelay_frame, getTransmissionDelayFrame, setTransmissionDelayFrame, std::stoi, + "[n_delay]\n\t[Eiger][Jungfrau] Transmission delay of each image being streamed out of the module.\n\t[Jungfrau] [0-31] Each value represents 1 ms\n\t[Eiger] Additional delay to txndelay_left and txndelay_right. Each value represents 10ns. Typical value is 50000."); + + INTEGER_COMMAND(txndelay_left, getTransmissionDelayLeft, setTransmissionDelayLeft, std::stoi, + "[n_delay]\n\t[Eiger] Transmission delay of first packet in an image being streamed out of the module's left UDP port. Each value represents 10ns. Typical value is 50000."); + + INTEGER_COMMAND(txndelay_right, getTransmissionDelayRight, setTransmissionDelayRight, std::stoi, + "[n_delay]\n\t[Eiger] Transmission delay of first packet in an image being streamed out of the module's right UDP port. Each value represents 10ns. Typical value is 50000."); + + + /* Receiver Config */ + + STRING_COMMAND(rx_hostname, getRxHostname, setRxHostname, + "[hostname or ip address]\n\tReceiver hostname or IP. Used for TCP control communication between client and receiver to configure receiver."); + + INTEGER_COMMAND(rx_tcpport, getRxPort, setRxPort, std::stoi, + "[port]\n\tTCP port for client-receiver communication. Default is 1954. Must be different if multiple receivers on same pc. Must be first command to set a receiver parameter. Multi command will automatically increment for individual modules."); + INTEGER_COMMAND( rx_fifodepth, getRxFifoDepth, setRxFifoDepth, std::stoi, - "[n_frames]\n\tSet the number of frames in the receiver fifo"); + "[n_frames]\n\tSet the number of frames in the receiver fifo (buffer between listener and writer threads)."); INTEGER_COMMAND(rx_silent, getRxSilentMode, setRxSilentMode, std::stoi, - "[0, 1]\n\tSwitch on or off receiver text output"); + "[0, 1]\n\tSwitch on or off receiver text output during acquisition."); + + INTEGER_COMMAND(rx_discardpolicy, getRxFrameDiscardPolicy, setRxFrameDiscardPolicy, sls::StringTo, + "[nodiscard (default)|discardempty|discardpartial(fastest)]\n\tFrame discard policy of receiver. nodiscard does not discard frames, discardempty discards empty frames, discardpartial discards partial frames."); + + INTEGER_COMMAND(rx_padding, getPartialFramesPadding, setPartialFramesPadding, std::stoi, + "[0, 1]\n\tPartial frames padding enable in the " + "receiver. 0 does not pad partial frames(fastest), 1 " + "(default) pads partial frames"); + + INTEGER_COMMAND(rx_udpsocksize, getRxUDPSocketBufferSize, setRxUDPSocketBufferSize, std::stol, + "[n_size]\n\tUDP socket buffer size in receiver. Tune rmem_default and rmem_max accordingly. rx_hostname sets it to defaults."); + + GET_COMMAND(rx_realudpsocksize, getRxRealUDPSocketBufferSize, + "\n\tActual udp socket buffer size. Double the size of rx_udpsocksize due to kernel bookkeeping."); INTEGER_COMMAND(rx_lock, getRxLock, setRxLock, std::stoi, "[0, 1]\n\tLock receiver to one IP, 1: locks"); + GET_COMMAND(rx_lastclient, getRxLastClientIP, + "\n\tClient IP Address that last communicated with the receiver."); + + + /* File */ + + INTEGER_COMMAND(fformat, getFileFormat, setFileFormat, sls::StringTo, + "[binary|hdf5]\n\tFile format of data file. For HDF5, package must be compiled with HDF5 flags. Default is binary."); + + STRING_COMMAND(fpath, getFilePath, setFilePath, + "[path]\n\tDirectory where output data files are written in receiver."); + + STRING_COMMAND(fname, getFileNamePrefix, setFileNamePrefix, + "[path]\n\tFile name prefix for output data file. Default is run. File name: [file name prefix]_d[detector index]_f[sub file index]_[acquisition/file index].raw."); + + INTEGER_COMMAND(findex, getAcquisitionIndex, setAcquisitionIndex, std::stol, + "[0, 1]\n\tFile or Acquisition index."); + + INTEGER_COMMAND(fwrite, getFileWrite, setFileWrite, std::stoi, + "[0, 1]\n\tEnable or disable receiver file write. Default is 1."); + + INTEGER_COMMAND_NOID(fmaster, getMasterFileWrite, setMasterFileWrite, std::stoi, + "[0, 1]\n\tEnable or disable receiver master file. Default is 1."); + + INTEGER_COMMAND(foverwrite, getFileOverWrite, setFileOverWrite, std::stoi, + "[0, 1]\n\tEnable or disable file overwriting. Default is 1."); + + INTEGER_COMMAND(rx_framesperfile, getFramesPerFile, setFramesPerFile, std::stoi, + "[n_frames]\n\tNumber of frames per file in receiver. 0 is infinite or all frames in single file."); + + + /* ZMQ Streaming Parameters (Receiver<->Client) */ + + INTEGER_COMMAND(rx_datastream, getRxZmqDataStream, setRxZmqDataStream, std::stoi, + "[0, 1]\n\tData streaming from receiver enable (eg. to GUI ot another process for further processing). 1 enables zmq data stream (creates zmq streamer threads), 0 disables (destroys streamer threads). Switching to Gui automatically enables data streaming in receiver. Switching back to command line acquire will require disabling data streaming in receiver for fast applications."); + + INTEGER_COMMAND(rx_readfreq, getRxZmqFrequency, setRxZmqFrequency, + std::stoi, "[nth frame]\n\tStream out every nth frame. Default is 1. 0 means streaming every 200 ms and discarding frames in this interval."); + + INTEGER_COMMAND(rx_zmqport, getRxZmqPort, setRxZmqPort, + std::stoi, "[port]\n\tZmq port for data to be streamed out of the receiver. Also restarts receiver zmq streaming if enabled. Default is 30001. Modified only when using an intermediate process between receiver and client(gui). Must be different for every detector (and udp port). Multi command will automatically increment for individual modules."); + + INTEGER_COMMAND(zmqport, getClientZmqPort, setClientZmqPort, + std::stoi, "[port]\n\tZmq port in client(gui) or intermediate process for data to be streamed to from receiver. efault connects to receiver zmq streaming out port (30001). Modified only when using an intermediate process between receiver and client(gui). Also restarts client zmq streaming if enabled. Must be different for every detector (and udp port). Multi command will automatically increment for individual modules."); + + INTEGER_COMMAND(rx_zmqip, getRxZmqIP, setRxZmqIP, IpAddr, + "[x.x.x.x]\n\tZmq Ip Address from which data is to be streamed out of the receiver. Also restarts receiver zmq streaming if enabled. Default is from rx_hostname. Modified only when using an intermediate process between receiver and client(gui)."); + + INTEGER_COMMAND(zmqip, getClientZmqIp, setClientZmqIp, IpAddr, + "[x.x.x.x]\n\tZmq IP Address in client(gui) or intermediate process for data to be streamed to from receiver. Default connects to receiver zmq Ip Address (from rx_hostname). Modified only when using an intermediate process between receiver and client(gui). Also restarts client zmq streaming if enabled."); + + + /* Eiger Specific */ + + TIME_COMMAND(subexptime, getSubExptime, setSubExptime, + "[duration] [(optional unit) ns|us|ms|s]\n\t[Eiger] Exposure time of EIGER subframes"); + + TIME_COMMAND(subdeadtime, getSubDeadTime, setSubDeadTime, + "[duration] [(optional unit) ns|us|ms|s]\n\t[Eiger] Dead time of EIGER subframes. Subperiod = subexptime + subdeadtime."); + + STRING_COMMAND(settingspath, getSettingsPath, setSettingsPath, + "[path]\n\t[Eiger] Directory where settings files are loaded from/to."); + + EXECUTE_SET_COMMAND_NOID_1ARG(trimbits, loadTrimbits, + "[fname]\n\t[Eiger] Loads the trimbit file to detector. If no extension specified, serial number of each module is attached."); + + INTEGER_COMMAND(parallel, getParallelMode, setParallelMode, std::stoi, + "[0, 1]\n\t[Eiger] Enable or disable parallel mode."); + + INTEGER_COMMAND(overflow, getOverFlowMode, setOverFlowMode, std::stoi, + "[0, 1]\n\t[Eiger] Enable or disable show overflow flag in 32 bit mode."); + + INTEGER_COMMAND(storeinram, getStoreInRamMode, setStoreInRamMode, std::stoi, + "[0, 1]\n\t[Eiger] Enable or disable store in ram mode."); + + INTEGER_COMMAND(flippeddatax, getBottom, setBottom, std::stoi, + "[0, 1]\n\t[Eiger] Top or Bottom Half of Eiger module. 1 is bottom, 0 is top. Used to let Receiver and Gui know to flip the bottom image over the x axis."); + + INTEGER_COMMAND(trimval, getAllTrimbits, setAllTrimbits, std::stoi, + "[n_trimval]\n\t[Eiger] All trimbits set to this value. A get returns -1 if all trimbits are different values."); + + INTEGER_COMMAND(readnlines, getPartialReadout, setPartialReadout, std::stoi, + "[1 - 256]\n\t[Eiger] Number of rows to readout per half module starting from the centre. 256 is default. The permissible values depend on dynamic range and 10Gbe enabled."); + + INTEGER_COMMAND(interruptsubframe, getInterruptSubframe, setInterruptSubframe, std::stoi, + "[0, 1]\n\t[Eiger] 1 interrupts last subframe at required exposure time. 0 will wait for last sub frame to finish exposing. 0 is default."); + + TIME_GET_COMMAND(measuredperiod, getMeasuredPeriod, + "[(optional unit) ns|us|ms|s]\n\t[Eiger] Measured frame period between last frame and previous one. Useful data only for acquisitions with more than 1 frame."); + + TIME_GET_COMMAND(measuredsubperiod, getMeasuredSubFramePeriod, + "[(optional unit) ns|us|ms|s]\n\t[Eiger] Measured sub frame period between last sub frame and previous one."); + + INTEGER_COMMAND(partialreset, getPartialReset, setPartialReset, std::stoi, + "[0, 1]\n\t[Eiger] Sets up detector to do partial or complete reset at start of acquisition. 0 complete reset, 1 partial reset."); + + + /* Jungfrau Specific */ + + INTEGER_COMMAND(temp_threshold, getThresholdTemperature, setThresholdTemperature, std::stoi, + "[n_temp (in degrees)]\n\t[Jungfrau] Threshold temperature in degrees. If temperature crosses threshold temperature and temperature control is enabled, power to chip will be switched off and temperature event occurs. To power on chip again, temperature has to be less than threshold temperature and temperature event has to be cleared."); + + INTEGER_COMMAND(temp_control, getTemperatureControl, setTemperatureControl, std::stoi, + "[0, 1]\n\t[Jungfrau] Temperature control enable. Default is 0 (disabled). If temperature crosses threshold temperature and temperature control is enabled, power to chip will be switched off and temperature event occurs. To power on chip again, temperature has to be less than threshold temperature and temperature event has to be cleared."); + + INTEGER_COMMAND(powerchip, getPowerChip, setPowerChip, std::stoi, + "[0, 1]\n\t[Jungfrau] Power the chip. Default 0. Get will return power status. Can be off if temperature event occured (temperature over temp_threshold with temp_control enabled."); + + INTEGER_COMMAND(auto_comp_disable, getAutoCompDisable, setAutoCompDisable, std::stoi, + "[0, 1]\n\t[Jungfrau] Auto comparator disable mode. Default 0 or this mode disabled(comparator enabled throughout). 1 enables mode. 0 disables mode. This mode disables the on-chip gain switching comparator automatically after 93.75% of exposure time (only for longer than 100us)."); + + INTEGER_COMMAND_NOID(storagecells, getNumberOfAdditionalStorageCells, setNumberOfAdditionalStorageCells, std::stoi, + "[0-15]\n\t[Jungfrau] Number of additional storage cells. Default is 0. For advanced users only. \n\tThe #images = #frames x #triggers x (#storagecells + 1)."); + + INTEGER_COMMAND(storagecell_start, getStorageCellStart, setStoragecellStart, std::stoi, + "[0-15]\n\t[Jungfrau] Storage cell that stores the first acquisition of the series. Default is 15. For advanced users only."); + + TIME_COMMAND(storagecell_delay, getStorageCellDelay, setStorageCellDelay, + "[duration (0-1638375 ns)] [(optional unit) ns|us|ms|s]\n\t[Jungfrau] Additional time delay between 2 storage cells. For advanced users only. Resolution is 25 ns."); + + + /* Gotthard Specific */ + TIME_GET_COMMAND(exptimel, getExptimeLeft, + "[(optional unit) ns|us|ms|s]\n\t[Gotthard] Exposure time left for current frame. "); + + TIME_GET_COMMAND(periodl, getPeriodLeft, + "[(optional unit) ns|us|ms|s]\n\t[Gotthard] Period left for current frame."); + + INTEGER_COMMAND(extsig, getExternalSignalFlags, setExternalSignalFlags, sls::StringTo, + "[trigger_in_rising_edge|trigger_in_falling_edge]\n\t[Gotthard] External signal mode for trigger timing mode."); + + INTEGER_COMMAND(imagetest, getImageTestMode, setImageTestMode, std::stoi, + "[0, 1]\n\t[Gotthard] 1 adds channel intensity with precalculated values when taking an acquisition. Default is 0."); + + /* Gotthard2 Specific */ + /* CTB Specific */ + + INTEGER_COMMAND(asamples, getNumberOfAnalogSamples, setNumberOfAnalogSamples, std::stoi, + "[0, 1]\n\t[CTB] Number of analog samples expected."); + + INTEGER_COMMAND(dsamples, getNumberOfDigitalSamples, setNumberOfDigitalSamples, std::stoi, + "[0, 1]\n\t[CTB] Number of digital samples expected."); + + INTEGER_COMMAND(romode, getReadoutMode, setReadoutMode, sls::StringTo, + "[analog|digital|analog_digital]\n\t[CTB] Readout mode. Default is analog."); + + GET_COMMAND(maxdbitphaseshift, getMaxDBITPhaseShift, + "\n\t[CTB] Absolute maximum Phase shift of of the clock to latch digital bits."); + + INTEGER_COMMAND(adcclk, getADCClock, setADCClock, std::stoi, + "[n_clk in MHz]\n\t[Ctb] ADC clock frequency in MHz."); + + INTEGER_COMMAND(dbitclk, getDBITClock, setDBITClock, std::stoi, + "[n_clk in MHz]\n\t[Ctb] Clock for latching the digital bits in MHz."); + + INTEGER_COMMAND(runclk, getRUNClock, setRUNClock, std::stoi, + "[n_clk in MHz]\n\t[Ctb] Run clock in MHz."); + + GET_COMMAND(syncclk, getSYNCClock, + "[n_clk in MHz]\n\t[Ctb] Synch clock in MHz."); + + INTEGER_COMMAND(adcpipeline, getADCPipeline, setADCPipeline, std::stoi, + "[n_value]\n\t[Ctb] Pipeline for ADC clock."); + + INTEGER_COMMAND(dbitpipeline, getDBITPipeline, setDBITPipeline, std::stoi, + "[n_value]\n\t[Ctb] Pipeline of the clock for latching digital bits."); + + INTEGER_IND_COMMAND(v_limit, getVoltage, setVoltage, std::stoi, defs::V_LIMIT, + "[n_value]\n\t[Ctb] Soft limit for power supplies and DACS in mV."); + + INTEGER_IND_COMMAND(v_a, getVoltage, setVoltage, std::stoi, defs::V_POWER_A, + "[n_value]\n\t[Ctb] Voltage supply a in mV."); + + INTEGER_IND_COMMAND(v_b, getVoltage, setVoltage, std::stoi, defs::V_POWER_B, + "[n_value]\n\t[Ctb] Voltage supply b in mV."); + + INTEGER_IND_COMMAND(v_c, getVoltage, setVoltage, std::stoi, defs::V_POWER_C, + "[n_value]\n\t[Ctb] Voltage supply c in mV."); + + INTEGER_IND_COMMAND(v_d, getVoltage, setVoltage, std::stoi, defs::V_POWER_D, + "[n_value]\n\t[Ctb] Voltage supply d in mV."); + + INTEGER_IND_COMMAND(v_io, getVoltage, setVoltage, std::stoi, defs::V_POWER_IO, + "[n_value]\n\t[Ctb] Voltage supply io in mV. Minimum 1200 mV. Must be the first power regulator to be set after fpga reset (on-board detector server start up)."); + + INTEGER_IND_COMMAND(v_chip, getVoltage, setVoltage, std::stoi, defs::V_POWER_CHIP, + "[n_value]\n\t[Ctb] Voltage supply chip in mV. Do not use it unless you are completely sure you will not fry the board."); + + GET_IND_COMMAND(vm_a, getMeasuredVoltage, defs::V_POWER_A, "", + "\n\t[Ctb] Measured voltage of power supply a in mV."); + + GET_IND_COMMAND(vm_b, getMeasuredVoltage, defs::V_POWER_B, "", + "\n\t[Ctb] Measured voltage of power supply b in mV."); + + GET_IND_COMMAND(vm_c, getMeasuredVoltage, defs::V_POWER_C, "", + "\n\t[Ctb] Measured voltage of power supply c in mV."); + + GET_IND_COMMAND(vm_d, getMeasuredVoltage, defs::V_POWER_D, "", + "\n\t[Ctb] Measured voltage of power supply d in mV."); + + GET_IND_COMMAND(vm_io, getMeasuredVoltage, defs::V_POWER_IO, "", + "\n\t[Ctb] Measured voltage of power supply io in mV."); + + GET_IND_COMMAND(im_a, getMeasuredVoltage, defs::I_POWER_A, "", + "\n\t[Ctb] Measured current of power supply a in mA."); + + GET_IND_COMMAND(im_b, getMeasuredVoltage, defs::I_POWER_B, "", + "\n\t[Ctb] Measured current of power supply b in mA."); + + GET_IND_COMMAND(im_c, getMeasuredVoltage, defs::I_POWER_C, "", + "\n\t[Ctb] Measured current of power supply c in mA."); + + GET_IND_COMMAND(im_d, getMeasuredVoltage, defs::I_POWER_D, "", + "\n\t[Ctb] Measured current of power supply d in mA."); + + GET_IND_COMMAND(im_io, getMeasuredVoltage, defs::I_POWER_IO, "", + "\n\t[Ctb] Measured current of power supply io in mA."); + + INTEGER_COMMAND(adcenable, getADCEnableMask, setADCEnableMask, stoui, + "[bitmask]\n\t[Ctb] ADC Enable Mask."); + + INTEGER_COMMAND(adcinvert, getADCInvert, setADCInvert, stoui, + "[bitmask]\n\t[Ctb] ADC Inversion Mask."); + + INTEGER_COMMAND(extsampling, getExternalSampling, setExternalSampling, std::stoi, + "[0, 1]\n\t[Ctb] Enable for external sampling signal to extsamplingsrc signal for digital data. For advanced users only."); + + INTEGER_COMMAND(extsamplingsrc, getExternalSamplingSource, setExternalSamplingSource, std::stoi, + "[0-63]\n\t[Ctb] Sampling source signal for digital data. For advanced users only."); + + INTEGER_COMMAND(rx_dbitoffset, getRxDbitOffset, setRxDbitOffset, std::stoi, + "[n_bytes]\n\t[Ctb] Offset in bytes in digital data in receiver."); + + INTEGER_COMMAND(led, getLEDEnable, setLEDEnable, std::stoi, + "[0, 1]\n\t[Ctb] Switches on/off all LEDs."); + + + /* Pattern */ + + EXECUTE_SET_COMMAND_NOID_1ARG(savepattern, savePattern, + "[fname]\n\t[Ctb] Saves pattern to file (ascii). Also executes pattern."); + + INTEGER_COMMAND_HEX(patioctrl, getPatternIOControl, setPatternIOControl, std::stoul, + "[64 bit mask]\n\t[Ctb] 64 bit mask defining input (0) and output (1) signals."); + + INTEGER_COMMAND_HEX(patclkctrl, getPatternClockControl, setPatternClockControl, std::stoul, + "[64 bit mask]\n\t[Ctb] 64 bit mask defining output clock enable."); + + + + + DAC_COMMAND(adcvpp, getDAC, setDAC, defs::ADC_VPP, + "[dac or mv value][(optional unit) mv] \n\t[Ctb] Vpp of ADC.\n\t 0 -> 1V ; 1 -> 1.14V ; 2 -> 1.33V ; 3 -> 1.6V ; 4 -> 2V."); + + GET_COMMAND(lastclient, getLastClientIP, + "\n\tClient IP Address that last communicated with the detector."); + INTEGER_COMMAND(lock, getDetectorLock, setDetectorLock, std::stoi, "[0, 1]\n\tLock detector to one IP, 1: locks"); - INTEGER_COMMAND(rx_readfreq, getRxZmqFrequency, setRxZmqFrequency, - std::stoi, "[nth frame]\n\tStream out every nth frame"); - INTEGER_COMMAND(rx_padding, getPartialFramesPadding, - setPartialFramesPadding, std::stoi, - "[0, 1]\n\tgets partial frames padding enable in the " - "receiver. 0 does not pad partial frames(fastest), 1 " - "(default) pads partial frames"); - INTEGER_COMMAND(rx_framesperfile, getFramesPerFile, setFramesPerFile, - std::stoi, "[n_frames]\n\tNumber of frames per file"); - - INTEGER_COMMAND_NOID(frames, getNumberOfFrames, setNumberOfFrames, - std::stol, - "[n_frames]\n\tNumber of frames per aquire"); - - INTEGER_COMMAND(fwrite, getFileWrite, setFileWrite, std::stoi, - "[0, 1]\n\tEnable or disable receiver file write"); - - INTEGER_COMMAND(fmaster, getMasterFileWrite, setMasterFileWrite, std::stoi, - "[0, 1]\n\tEnable or disable receiver master file"); - - INTEGER_COMMAND(foverwrite, getFileOverWrite, setFileOverWrite, std::stoi, - "[0, 1]\n\tEnable or disable file overwriting"); - - INTEGER_COMMAND(findex, getAcquisitionIndex, setAcquisitionIndex, std::stoi, - "[0, 1]\n\tFile index"); - - INTEGER_COMMAND(detectormac, getSourceUDPMAC, setSourceUDPMAC, MacAddr, - "[x:x:x:x:x:x]\n\tMac address of the detector (source) udp interface. "); - - INTEGER_COMMAND(detectormac2, getSourceUDPMAC2, setSourceUDPMAC2, MacAddr, - "[x:x:x:x:x:x]\n\t[Jungfrau] Mac address of the bottom half of detector (source) udp interface. "); - - INTEGER_COMMAND(rx_udpmac, getDestinationUDPMAC, setDestinationUDPMAC, MacAddr, - "[x:x:x:x:x:x]\n\tMac address of the receiver (destination) udp interface. Can be unused as rx_hostname/rx_udpip retrieves it."); - - INTEGER_COMMAND(rx_udpmac2, getDestinationUDPMAC2, setDestinationUDPMAC2, MacAddr, - "[x:x:x:x:x:x]\n\t[Jungfrau] Mac address of the receiver (destination) udp interface where the second half of detector data is sent to. Can be unused as rx_hostname/rx_udpip2 retrieves it.") - - INTEGER_COMMAND(detectorip, getSourceUDPIP, setSourceUDPIP, IpAddr, - "[x.x.x.x]\n\tIp address of the detector (source) udp interface. Must be same subnet as destination udp ip."); - - INTEGER_COMMAND(detectorip2, getSourceUDPIP2, setSourceUDPIP2, IpAddr, - "[x.x.x.x]\n\t[Jungfrau] Ip address of the bottom half of detector (source) udp interface. Must be same subnet as destination udp ip2."); - - INTEGER_COMMAND(rx_udpip, getDestinationUDPIP, setDestinationUDPIP, IpAddr, - "[x.x.x.x]\n\tIp address of the receiver (destination) udp interface."); - - INTEGER_COMMAND(rx_udpip2, getDestinationUDPIP2, setDestinationUDPIP2, IpAddr, - "[x.x.x.x]\n\t[Jungfrau] Ip address of the receiver (destination) udp interface where the second half of detector data is sent to."); - - INTEGER_COMMAND(rx_udpport, getDestinationUDPPort, setDestinationUDPPort, std::stoi, - "[n]\n\tPort number of the receiver (destination) udp interface."); - - INTEGER_COMMAND(rx_udpport2, getDestinationUDPPort2, setDestinationUDPPort2, std::stoi, - "[n]\n\t[Jungfrau] Port number of the receiver (destination) udp interface where the second half of detector data is sent to.\n[Eiger] Port number of the reciever (desintation) udp interface where the right half of the detector data is sent to."); - - INTEGER_COMMAND(numinterfaces, getNumberofUDPInterfaces, setNumberofUDPInterfaces, std::stoi, - "[1, 2]\n\t[Jungfrau] Number of udp interfaces to stream data from detector. Default: 1."); - - INTEGER_COMMAND(selinterface, getSelectedUDPInterface, selectUDPInterface, std::stoi, - "[0, 1]\n\t[Jungfrau] The udp interface to stream data from detector. Effective only when number of interfaces is 1. Default: 0 (outer)"); - - INTEGER_COMMAND(parallel, getParallelMode, setParallelMode, std::stoi, - "[0, 1]\n\tEnable or disable parallel mode. [Eiger]"); - - INTEGER_COMMAND(overflow, getOverFlowMode, setOverFlowMode, std::stoi, - "[0, 1]\n\tEnable or disable show overflow flag in 32 bit mode. [Eiger]"); - - INTEGER_COMMAND(storeinram, getStoreInRamMode, setStoreInRamMode, std::stoi, - "[0, 1]\n\tEnable or disable store in ram mode. [Eiger]"); }; } // namespace sls diff --git a/slsDetectorSoftware/include/Detector.h b/slsDetectorSoftware/include/Detector.h index 1edd384a8..d19a22bfb 100644 --- a/slsDetectorSoftware/include/Detector.h +++ b/slsDetectorSoftware/include/Detector.h @@ -52,14 +52,17 @@ class Detector { /** Gets shared memory ID */ int getShmId() const; + /** package git branch */ + std::string getPackageVersion() const; + + int64_t getClientVersion() const; + Result getFirmwareVersion(Positions pos = {}) const; Result getDetectorServerVersion(Positions pos = {}) const; Result getSerialNumber(Positions pos = {}) const; - int64_t getClientVersion() const; - Result getReceiverVersion(Positions pos = {}) const; Result getDetectorType(Positions pos = {}) const; @@ -197,7 +200,7 @@ class Detector { Result getDAC(defs::dacIndex index, bool mV, Positions pos = {}) const; - void setDAC(int value, defs::dacIndex index, bool mV, Positions pos = {}); + void setDAC(defs::dacIndex index, int value, bool mV, Positions pos = {}); Result getTimingMode(Positions pos = {}) const; @@ -213,33 +216,33 @@ class Detector { * * * ************************************************/ /** - * Blocking call, starts the receiver and detector. - * Increments file index if file write enabled. - * Acquired the number of frames set. + * Blocking call: Acquire the number of frames set + * - sets acquiring flag + * - starts the receiver listener + * - starts detector acquisition for number of frames set + * - monitors detector status from running to idle + * - stops the receiver listener + * - increments file index if file write enabled + * - resets acquiring flag */ void acquire(); - - /** Non blocking - * Starts the reciever (if enabled) and then the detector - * You have to check detector status until it is idle before you call - * stopACquisition - * - */ - void startAcquisition(); - - /** - * Stops detector acquisition and then receiver (if enabled) - * If no receiver enabled, you can skip this for normal acquisition (no - * abort) - */ - void stopAcquisition(); - - /** TODO: initially was getting acq flag, if set, check if detctor idle, then set, else exception & abort - * Clears the acquiring flag. This has to be done manually - * after an acquisition was aborted. - */ + + /** If acquisition aborted, use this to clear before starting next acquisition */ void clearAcquiringFlag(); + /** Non Blocking: Start receiver listener*/ + void startReceiver(); + + /** Non Blocking: Stop receiver listener */ + void stopReceiver(); + + /** Non blocking: start detector acquisition + * detector status changes from RUNNING to IDLE when finished */ + void startDetector(); + + /** Non blocking: abort detector acquisition */ + void stopDetector(); + Result getDetectorStatus(Positions pos = {}) const; Result getReceiverStatus(Positions pos = {}) const; @@ -337,8 +340,6 @@ class Detector { /** module_id is -1 for all detectors, ports for each module is calculated * (increments) */ - // TODO if Parallel takes a vector, can send multiple vaues to set in - // slsdetector.cp void setDestinationUDPPort(int port, int module_id = -1); /** [Eiger right port][Jungfrau bottom half] */ @@ -397,7 +398,7 @@ class Detector { /************************************************** * * - * RECEIVER CONFIG * + * Receiver Config * * * * ************************************************/ @@ -416,8 +417,10 @@ class Detector { Result getRxPort(Positions pos = {}) const; - /** Receiver TCP port (for client communication with Receiver) */ - void setRxPort(int value, Positions pos = {}); + /** Receiver TCP port (for client communication with Receiver) + * module_id is -1 for all detectors, ports for each module is calculated + * (increments) */ + void setRxPort(int port, int module_id = -1); Result getRxFifoDepth(Positions pos = {}) const; @@ -458,11 +461,11 @@ class Detector { /** locks receiver server to client IP */ void setRxLock(bool value, Positions pos = {}); - Result getRxLastClientIP(Positions pos = {}) const; + Result getRxLastClientIP(Positions pos = {}) const; /************************************************** * * - * FILE * + * File * * * * ************************************************/ Result getFileFormat(Positions pos = {}) const; @@ -483,9 +486,9 @@ class Detector { */ void setFileNamePrefix(const std::string &fname, Positions pos = {}); - Result getAcquisitionIndex(Positions pos = {}) const; + Result getAcquisitionIndex(Positions pos = {}) const; - void setAcquisitionIndex(int i, Positions pos = {}); + void setAcquisitionIndex(int64_t i, Positions pos = {}); Result getFileWrite(Positions pos = {}) const; @@ -545,23 +548,23 @@ class Detector { */ void setRxZmqPort(int port, int module_id = -1); - Result getRxZmqIP(Positions pos = {}) const; + Result getRxZmqIP(Positions pos = {}) const; - void setRxZmqIP(const std::string &ip, Positions pos = {}); + void setRxZmqIP(const IpAddr ip, Positions pos = {}); Result getClientZmqPort(Positions pos = {}) const; /** - * Needed only when using the client call back to get reconstructed data - * from multi modules module_id is -1 for all detectors, ports for each - * module is calculated (increments) Restarts client zmq sockets oonly if it + * Modified only when using an intermediate process between receiver and gui/client. + * Module_id is -1 for all detectors, ports for each + * module is calculated (increments) Restarts client zmq sockets only if it * was already enabled */ void setClientZmqPort(int port, int module_id = -1); - Result getClientZmqIp(Positions pos = {}) const; + Result getClientZmqIp(Positions pos = {}) const; - void setClientZmqIp(const std::string &ip, Positions pos = {}); + void setClientZmqIp(const IpAddr ip, Positions pos = {}); /************************************************** * * @@ -599,10 +602,10 @@ class Detector { bool trimbits = true, Positions pos = {}); /** [Eiger] */ - Result getSettingsDir(Positions pos = {}) const; + Result getSettingsPath(Positions pos = {}) const; /** [Eiger] */ - void setSettingsDir(const std::string &value, Positions pos = {}); + void setSettingsPath(const std::string &value, Positions pos = {}); /** [Eiger] */ void loadTrimbits(const std::string &fname, Positions pos = {}); @@ -808,13 +811,15 @@ class Detector { * Can set only a single ROI at a time * @param module position index */ - void setROI(defs::ROI value, int moduleId); + void setROI(defs::ROI value, int module_id); - /** [Gotthard] TODO: check with jiaguo if he needs any of these functions // - * TODO remove */ + /** [Gotthard] Clear ROI */ + void clearROI(Positions pos = {}); + + /** [Gotthard] */ Result getExptimeLeft(Positions pos = {}) const; - /** [Gotthard] TODO remove */ + /** [Gotthard] */ Result getPeriodLeft(Positions pos = {}) const; /** [Gotthard] */ @@ -904,12 +909,6 @@ class Detector { /** [CTB] */ void setDBITPipeline(int value, Positions pos = {}); - /** [CTB] */ - Result getVrefVoltage(bool mV, Positions pos = {}) const; - - /** [CTB] */ - void setVrefVoltage(int value, bool mV, Positions pos = {}); - /** [CTB] */ Result getVoltage(defs::dacIndex index, Positions pos = {}) const; @@ -918,20 +917,17 @@ class Detector { * Options: V_LIMIT, V_POWER_A, V_POWER_B, V_POWER_C, * V_POWER_D, V_POWER_IO, V_POWER_CHIP */ - void setVoltage(int value, defs::dacIndex index, Positions pos = {}); + void setVoltage(defs::dacIndex index, int value, Positions pos = {}); /** * [CTB] mV - * Options: V_POWER_A, V_POWER_B, V_POWER_C, V_POWER_D, V_POWER_IO, - * V_POWER_CHIP - */ + * Options: V_POWER_A, V_POWER_B, V_POWER_C, V_POWER_D, V_POWER_IO */ Result getMeasuredVoltage(defs::dacIndex index, Positions pos = {}) const; /** * [CTB] mA - * Options: I_POWER_A, I_POWER_B, I_POWER_C, I_POWER_D, I_POWER_IO - */ + * Options: I_POWER_A, I_POWER_B, I_POWER_C, I_POWER_D, I_POWER_IO */ Result getMeasuredCurrent(defs::dacIndex index, Positions pos = {}) const; @@ -990,7 +986,7 @@ class Detector { /************************************************** * * - * PATTERN * + * Pattern * * * * ************************************************/ @@ -1012,6 +1008,9 @@ class Detector { /** [CTB] */ void setPatternClockControl(uint64_t word, Positions pos = {}); + /** [CTB] same as executing */ + Result getPatternWord(int addr, Positions pos = {}); + /** [CTB] Caution: If word is -1 reads the addr (same as * executing the pattern) */ void setPatternWord(int addr, uint64_t word, Positions pos = {}); @@ -1178,7 +1177,7 @@ class Detector { void setDetectorLock(bool lock, Positions pos = {}); /** Get last client IP saved on detector server */ - Result getLastClientIP(Positions pos = {}) const; + Result getLastClientIP(Positions pos = {}) const; /** Execute a command on the detector server console */ void executeCommand(const std::string &value, Positions pos = {}); diff --git a/slsDetectorSoftware/include/multiSlsDetector.h b/slsDetectorSoftware/include/multiSlsDetector.h index b200c3afc..13e61f4ce 100755 --- a/slsDetectorSoftware/include/multiSlsDetector.h +++ b/slsDetectorSoftware/include/multiSlsDetector.h @@ -261,6 +261,12 @@ class multiSlsDetector : public virtual slsDetectorDefs { int getMultiId() const { return multiId; } // part of multi also + /** + * Get package version (git branch) + * @returns package version + */ + std::string getPackageVersion() const; + /** * Get Client Software version * @returns client software version @@ -453,13 +459,6 @@ class multiSlsDetector : public virtual slsDetectorDefs { */ int lockServer(int p = -1, int detPos = -1); // - /** - * Get last client IP saved on detector server - * @param detPos -1 for all detectors in list or specific detector position - * @returns last client IP saved on detector server - */ - std::string getLastClientIP(int detPos = -1); // - /** * Exit detector server * @param detPos -1 for all detectors in list or specific detector position @@ -553,31 +552,6 @@ class multiSlsDetector : public virtual slsDetectorDefs { */ void saveSettingsFile(const std::string &fname, int detPos = -1); // - /** - * Get Detector run status - * @param detPos -1 for all detectors in list or specific detector position - * @returns status - */ - runStatus getRunStatus(int detPos = -1); // - - /** - * Start detector acquisition (Non blocking) - * @param detPos -1 for all detectors in list or specific detector position - */ - void startAcquisition(int detPos = -1); // - - /** - * Stop detector acquisition - * @param detPos -1 for all detectors in list or specific detector position - */ - void stopAcquisition(int detPos = -1); // - - /** - * Give an internal software trigger to the detector (Eiger only) - * @param detPos -1 for all detectors in list or specific detector position - */ - void sendSoftwareTrigger(int detPos = -1); // - /** * Configures in detector the destination for UDP packets * @param detPos -1 for all detectors in list or specific detector position @@ -669,12 +643,12 @@ class multiSlsDetector : public virtual slsDetectorDefs { int64_t setNumberOfFrames(int64_t t = -1, int detPos = -1); // /** - * Set/get number of cycles - * @param t number of cycles (-1 gets) + * Set/get number of triggers + * @param t number of triggers (-1 gets) * @param detPos -1 for all detectors in list or specific detector position - * @returns number of cycles + * @returns number of triggers */ - int64_t setNumberOfCycles(int64_t t = -1, int detPos = -1); // + int64_t setNumberOfTriggers(int64_t t = -1, int detPos = -1); // /** * Set/get number of additional storage cells (Jungfrau) @@ -929,45 +903,7 @@ class multiSlsDetector : public virtual slsDetectorDefs { */ int getReceiverStreamingPort(int detPos = -1); // - /** - * (advanced users) - * Set/Get client streaming in ZMQ IP and restarts client sockets - * @param i sets, empty string gets - * By default, it is the IP of receiver hostname - * @param detPos -1 for all detectors in list or specific detector position - */ - void setClientDataStreamingInIP(const std::string &ip = "", - int detPos = -1); // - - /** - * Returns the client zmq ip - * If detPos is -1(multi module), ip returns concatenation of all client - * streaming ip - * @param detPos -1 for all detectors in list or specific detector position - * @returns the client zmq ip - */ - std::string getClientStreamingIP(int detPos = -1); // - - /** - * (advanced users) - * Set/Get receiver streaming out ZMQ IP and restarts receiver sockets - * @param i sets, empty string gets - * By default, it is the IP of receiver hostname - * @param detPos -1 for all detectors in list or specific detector position - */ - void setReceiverDataStreamingOutIP(const std::string &ip = "", - int detPos = -1); // - - /** - * Returns the receiver zmq ip - * If detPos is -1(multi module), ip returns concatenation of all receiver - * streaming ip - * @param detPos -1 for all detectors in list or specific detector position - * @returns the receiver zmq ip - */ - std::string getReceiverStreamingIP(int detPos = -1); // - - /** + /** * Sets the transmission delay for left, right or entire frame * (Eiger, Jungfrau(only entire frame)) * @param index type of delay @@ -1435,13 +1371,6 @@ class multiSlsDetector : public virtual slsDetectorDefs { */ int lockReceiver(int lock = -1, int detPos = -1); // - /** - * Returns the IP of the last client connecting to the receiver - * @param detPos -1 for all detectors in list or specific detector position - * @returns IP of last client connecting to receiver - */ - std::string getReceiverLastClientIP(int detPos = -1); // - /** * Turns off the receiver server! * @param detPos -1 for all detectors in list or specific detector position @@ -1541,7 +1470,7 @@ class multiSlsDetector : public virtual slsDetectorDefs { * @param detPos -1 for all detectors in list or specific detector position * @returns file index */ - int setFileIndex(int i, int detPos = -1); // + int64_t setFileIndex(int64_t i, int detPos = -1); // /** * Get File index @@ -1549,26 +1478,7 @@ class multiSlsDetector : public virtual slsDetectorDefs { * position * @returns file index */ - int getFileIndex(int detPos = -1) const; // - - /** - * Receiver starts listening to packets - * @param detPos -1 for all detectors in list or specific detector position - */ - void startReceiver(int detPos = -1); // - - /** - * Stops the listening mode of receiver - * @param detPos -1 for all detectors in list or specific detector position - */ - void stopReceiver(int detPos = -1); // - - /** - * Gets the status of the listening mode of receiver - * @param detPos -1 for all detectors in list or specific detector position - * @returns status - */ - runStatus getReceiverStatus(int detPos = -1); // + int64_t getFileIndex(int detPos = -1) const; // /** * Gets the number of frames caught by receiver @@ -1820,21 +1730,8 @@ class multiSlsDetector : public virtual slsDetectorDefs { /** * Loads the detector setup from file * @param fname file to read from - * @param level if 2 reads also reads trimbits, angular conversion - * coefficients etc. from files with default extensions as generated by - * dumpDetectorSetup - * @returns OK or FAIL */ - int retrieveDetectorSetup(const std::string &fname, int level = 0); - - /** - * Saves the detector setup to file - * @param fname file to write to - * @param level if 2 reads also trimbits, flat field, angular correction - * etc. and writes them to files with automatically added extension - * @returns OK or FAIL - */ - int dumpDetectorSetup(const std::string &fname, int level = 0); + void loadParameters(const std::string &fname); /** * register callback for accessing acquisition final data @@ -1916,12 +1813,6 @@ class multiSlsDetector : public virtual slsDetectorDefs { */ void updateUserdetails(); - /** - * Prepares detector for acquisition (Eiger) - * @param detPos -1 for all detectors in list or specific detector position - */ - void prepareAcquisition(int detPos = -1); // - /** * Check if acquiring flag is set, set error if set * @returns FAIL if not ready, OK if ready @@ -1935,14 +1826,6 @@ class multiSlsDetector : public virtual slsDetectorDefs { */ std::string exec(const char *cmd); - /** - * Appends detectors to the end of the list in shared memory - * Connects to them - * @param name concatenated hostname of the sls detectors to be appended to - * the list - */ - void addMultipleDetectors(const char *name); // - /** * Add sls detector * @param s hostname of the single detector @@ -1960,7 +1843,7 @@ class multiSlsDetector : public virtual slsDetectorDefs { * @param detPos -1 for all detectors in list or specific detector position * @returns the file index */ - int incrementFileIndex(int detPos = -1); + int64_t incrementFileIndex(int detPos = -1); /** * add gap pixels to the image (only for Eiger in 4 bit mode) @@ -2013,26 +1896,6 @@ class multiSlsDetector : public virtual slsDetectorDefs { */ void startProcessingThread(); - /** - * Start detector acquisition and read all data (Blocking until end of - * acquisition) - * @param detPos -1 for all detectors in list or specific detector position - */ - void startAndReadAll(int detPos = -1); // - - /** - * Start readout (without exposure or interrupting exposure) (Eiger store in - * ram) - * @param detPos -1 for all detectors in list or specific detector position - */ - void startReadOut(int detPos = -1); // - - /** - * Requests and receives all data from the detector (Eiger store in ram) - * @param detPos -1 for all detectors in list or specific detector position - */ - void readAll(int detPos = -1); // - /** * Check if processing thread is ready to join main thread * @returns true if ready, else false diff --git a/slsDetectorSoftware/include/slsDetector.h b/slsDetectorSoftware/include/slsDetector.h index e3e26da9a..c7cf6b0b7 100755 --- a/slsDetectorSoftware/include/slsDetector.h +++ b/slsDetectorSoftware/include/slsDetector.h @@ -148,7 +148,7 @@ struct sharedSlsDetector { char rxFileName[MAX_STR_LENGTH]; /** file index */ - int rxFileIndex; + int64_t rxFileIndex; /** file format */ slsDetectorDefs::fileFormat rxFileFormat; @@ -350,7 +350,7 @@ class slsDetector : public virtual slsDetectorDefs { * Get last client IP saved on detector server * @returns last client IP saved on detector server */ - std::string getLastClientIP(); + sls::IpAddr getLastClientIP(); /** * Exit detector server @@ -896,29 +896,32 @@ class slsDetector : public virtual slsDetectorDefs { /** * Sets the client zmq ip\sa sharedSlsDetector - * @param sourceIP client zmq ip + * @param ip client zmq ip */ - void setClientStreamingIP(const std::string &sourceIP); + void setClientStreamingIP(const sls::IpAddr ip); /** * Returns the client zmq ip \sa sharedSlsDetector - * @returns the client zmq ip, returns "none" if default setting and no - * custom ip set + * @returns the client zmq ip */ - std::string getClientStreamingIP(); + sls::IpAddr getClientStreamingIP(); /** * Sets the receiver zmq ip\sa sharedSlsDetector - * @param sourceIP receiver zmq ip. If empty, uses rx_hostname + * @param ip receiver zmq ip */ - void setReceiverStreamingIP(std::string sourceIP); + void setReceiverStreamingIP(const sls::IpAddr ip); /** * Returns the receiver zmq ip \sa sharedSlsDetector - * @returns the receiver zmq ip, returns "none" if default setting and no - * custom ip set + * @returns the receiver zmq ip */ - std::string getReceiverStreamingIP(); + sls::IpAddr getReceiverStreamingIP(); + + /** update receiver stremaing ip from shm to receiver + * if empty, use rx_hostname ip + */ + void updateReceiverStreamingIP(); /** * Sets the transmission delay for left, right or entire frame @@ -1333,7 +1336,7 @@ class slsDetector : public virtual slsDetectorDefs { * Returns the IP of the last client connecting to the receiver * @returns the IP of the last client connecting to the receiver */ - std::string getReceiverLastClientIP() const; + sls::IpAddr getReceiverLastClientIP() const; /** * Exits the receiver TCP server @@ -1440,19 +1443,19 @@ class slsDetector : public virtual slsDetectorDefs { * @param i file index * @returns file index */ - int setFileIndex(int file_index); + int64_t setFileIndex(int64_t file_index); /** * Gets the file index * @returns file index */ - int getFileIndex() const; + int64_t getFileIndex() const; /** * increments file index * @returns the file index */ - int incrementFileIndex(); + int64_t incrementFileIndex(); /** * Receiver starts listening to packets diff --git a/slsDetectorSoftware/include/slsDetectorCommand.h b/slsDetectorSoftware/include/slsDetectorCommand.h index 3bf778a18..a4d6cc9bc 100755 --- a/slsDetectorSoftware/include/slsDetectorCommand.h +++ b/slsDetectorSoftware/include/slsDetectorCommand.h @@ -42,40 +42,22 @@ class slsDetectorCommand : public virtual slsDetectorDefs { std::string helpLine(int narg, const char * const args[], int action=HELP_ACTION, int detPos = -1); static std::string helpAcquire(int action); static std::string helpData(int action); - static std::string helpStatus(int action); - static std::string helpDataStream(int action); static std::string helpFree(int action); static std::string helpHostname(int action); static std::string helpUser(int action); static std::string helpExitServer(int action); - static std::string helpSettingsDir(int action); - static std::string helpTrimEn(int action); - static std::string helpOutDir(int action); - static std::string helpFileName(int action); - static std::string helpRateCorr(int action); static std::string helpThreaded(int action); - static std::string helpNetworkParameter(int action); static std::string helpPort(int action); - static std::string helpLastClient(int action); - static std::string helpOnline(int action); - static std::string helpDetectorSize(int action); static std::string helpSettings(int action); static std::string helpSN(int action); static std::string helpDigiTest(int action); static std::string helpRegister(int action); static std::string helpDAC(int action); - static std::string helpTimer(int action); - static std::string helpTiming(int action); static std::string helpTimeLeft(int action); - static std::string helpSpeed(int action); static std::string helpAdvanced(int action); static std::string helpConfiguration(int action); - static std::string helpCounter(int action); - static std::string helpADC(int action); - static std::string helpTempControl(int action); static std::string helpReceiver(int action); static std::string helpPattern(int action); - static std::string helpPulse(int action); static std::string helpProcessor(int action); private: @@ -85,40 +67,22 @@ class slsDetectorCommand : public virtual slsDetectorDefs { std::string cmdUnknown(int narg, const char * const args[], int action, int detPos = -1); std::string cmdAcquire(int narg, const char * const args[], int action, int detPos = -1); std::string cmdData(int narg, const char * const args[], int action, int detPos = -1); - std::string cmdStatus(int narg, const char * const args[], int action, int detPos = -1); - std::string cmdDataStream(int narg, const char * const args[], int action, int detPos = -1); std::string cmdFree(int narg, const char * const args[], int action, int detPos = -1); std::string cmdHostname(int narg, const char * const args[], int action, int detPos = -1); std::string cmdUser(int narg, const char * const args[], int action, int detPos = -1); std::string cmdHelp(int narg, const char * const args[], int action, int detPos = -1); std::string cmdExitServer(int narg, const char * const args[], int action, int detPos = -1); - std::string cmdSettingsDir(int narg, const char * const args[], int action, int detPos = -1); - std::string cmdTrimEn(int narg, const char * const args[], int action, int detPos = -1); - std::string cmdOutDir(int narg, const char * const args[], int action, int detPos = -1); - std::string cmdFileName(int narg, const char * const args[], int action, int detPos = -1); - std::string cmdRateCorr(int narg, const char * const args[], int action, int detPos = -1); - std::string cmdNetworkParameter(int narg, const char * const args[], int action, int detPos = -1); std::string cmdPort(int narg, const char * const args[], int action, int detPos = -1); - std::string cmdLastClient(int narg, const char * const args[], int action, int detPos = -1); - std::string cmdOnline(int narg, const char * const args[], int action, int detPos = -1); - std::string cmdDetectorSize(int narg, const char * const args[], int action, int detPos = -1); std::string cmdSettings(int narg, const char * const args[], int action, int detPos = -1); std::string cmdSN(int narg, const char * const args[], int action, int detPos = -1); std::string cmdDigiTest(int narg, const char * const args[], int action, int detPos = -1); std::string cmdRegister(int narg, const char * const args[], int action, int detPos = -1); std::string cmdDAC(int narg, const char * const args[], int action, int detPos = -1); - std::string cmdTiming(int narg, const char * const args[], int action, int detPos = -1); - std::string cmdTimer(int narg, const char * const args[], int action, int detPos = -1); std::string cmdTimeLeft(int narg, const char * const args[], int action, int detPos = -1); - std::string cmdSpeed(int narg, const char * const args[], int action, int detPos = -1); std::string cmdAdvanced(int narg, const char * const args[], int action, int detPos = -1); std::string cmdConfiguration(int narg, const char * const args[], int action, int detPos = -1); - std::string cmdCounter(int narg, const char * const args[], int action, int detPos = -1); - std::string cmdADC(int narg, const char * const args[], int action, int detPos = -1); - std::string cmdTempControl(int narg, const char * const args[], int action, int detPos = -1); std::string cmdReceiver(int narg, const char * const args[], int action, int detPos = -1); std::string cmdPattern(int narg, const char * const args[], int action, int detPos = -1); - std::string cmdPulse(int narg, const char * const args[], int action, int detPos = -1); std::string cmdProcessor(int narg, const char * const args[], int action, int detPos = -1); int numberOfCommands; diff --git a/slsDetectorSoftware/include/slsDetectorUsers.h b/slsDetectorSoftware/include/slsDetectorUsers.h index 3bf71f750..d0e029e6a 100755 --- a/slsDetectorSoftware/include/slsDetectorUsers.h +++ b/slsDetectorSoftware/include/slsDetectorUsers.h @@ -340,12 +340,12 @@ public: int64_t setNumberOfFrames(int64_t t = -1, int detPos = -1); /** - * Set/get number of cycles - * @param t number of cycles (-1 gets) + * Set/get number of triggers + * @param t number of triggers (-1 gets) * @param detPos -1 for all detectors in list or specific detector position - * @returns number of cycles + * @returns number of triggers */ - int64_t setNumberOfCycles(int64_t t = -1, int detPos = -1); + int64_t setNumberOfTriggers(int64_t t = -1, int detPos = -1); /** * Set/get number of additional storage cells (Jungfrau) diff --git a/slsDetectorSoftware/src/CmdProxy.cpp b/slsDetectorSoftware/src/CmdProxy.cpp index 45009e63e..b5d43eb1f 100644 --- a/slsDetectorSoftware/src/CmdProxy.cpp +++ b/slsDetectorSoftware/src/CmdProxy.cpp @@ -1,54 +1,22 @@ #include "CmdProxy.h" - - -#include "TimeHelper.h" -#include "ToString.h" #include "logger.h" #include "slsDetectorCommand.h" #include "sls_detector_defs.h" +#include "ToString.h" +#include "TimeHelper.h" +#include "container_utils.h" -#include #include #include #include - -#define TIME_COMMAND(GETFCN, SETFCN, HLPSTR) \ - std::ostringstream os; \ - os << cmd << ' '; \ - if (action == slsDetectorDefs::HELP_ACTION) \ - os << HLPSTR << '\n'; \ - else if (action == slsDetectorDefs::GET_ACTION) { \ - auto t = det->GETFCN({det_id}); \ - if (args.size() == 0) { \ - os << OutString(t) << '\n'; \ - } else if (args.size() == 1) { \ - os << OutString(t, args[0]) << '\n'; \ - } else { \ - WrongNumberOfParameters(2); \ - } \ - } else if (action == slsDetectorDefs::PUT_ACTION) { \ - if (args.size() == 1) { \ - std::string time_str(args[0]); \ - std::string unit = RemoveUnit(time_str); \ - auto t = StringTo(time_str, unit); \ - det->SETFCN(t, {det_id}); \ - } else if (args.size() == 2) { \ - auto t = StringTo(args[0], args[1]); \ - det->SETFCN(t, {det_id}); \ - } else { \ - WrongNumberOfParameters(2); \ - } \ - os << args << '\n'; \ - } else { \ - throw sls::RuntimeError("Unknown action"); \ - } \ - return os.str(); - +#include namespace sls { +using defs = slsDetectorDefs; + std::ostream &operator<<(std::ostream &os, const std::vector &vec) { if (!vec.empty()) { @@ -121,26 +89,8 @@ void CmdProxy::WrongNumberOfParameters(size_t expected) { * * ************************************************/ -std::string CmdProxy::Period(int action) { - TIME_COMMAND(getPeriod, setPeriod, - "[duration] [(optional unit) ns|us|ms|s]\n\tSet the period"); -} -std::string CmdProxy::Exptime(int action) { - TIME_COMMAND( - getExptime, setExptime, - "[duration] [(optional unit) ns|us|ms|s]\n\tSet the exposure time"); -} -std::string CmdProxy::SubExptime(int action) { - TIME_COMMAND(getSubExptime, setSubExptime, - "[duration] [(optional unit) ns|us|ms|s]\n\tSet the " - "exposure time of EIGER subframes"); -} - - - - std::string CmdProxy::ListCommands(int action) { - if (action == slsDetectorDefs::HELP_ACTION) + if (action == defs::HELP_ACTION) return "list\n\tlists all available commands, list deprecated - " "list deprecated commands\n"; @@ -181,7 +131,243 @@ std::string CmdProxy::ListCommands(int action) { } } +/* configuration */ +std::string CmdProxy::Hostname(int action) { + std::ostringstream os; + os << cmd << ' '; + if (action == defs::HELP_ACTION) { + os << "\n\tFrees shared memory and sets hostname (or IP address) of all modules concatenated by +." << '\n'; + } else if (action == defs::GET_ACTION) { + if (args.size() != 0) { + WrongNumberOfParameters(0); + } + auto t = det->getHostname({det_id}); + os << OutString(t) << '\n'; + } else if (action == defs::PUT_ACTION) { + if (args.size() < 1) { + WrongNumberOfParameters(1); + } + if (det_id != -1) { + throw sls::RuntimeError("Cannot execute this at module level"); + } + // only args[0], but many hostames concatenated with + + if (args[0].find('+') != std::string::npos) { + auto t = sls::split(args[0], '+'); + det->setHostname(t); + os << ToString(t) << '\n'; + } + // either hostnames separated by space, or single hostname + else { + det->setHostname(args); + os << ToString(args) << '\n'; + } + auto t = det->getHostname({det_id}); + } else { + throw sls::RuntimeError("Unknown action"); + } + return os.str(); +} + +std::string CmdProxy::FirmwareVersion(int action) { + std::ostringstream os; + os << cmd << ' '; + if (action == defs::HELP_ACTION) { + os << "\n\tFimware version of detector in format [0xYYMMDD] or integer for Eiger." << '\n'; + } else if (action == defs::GET_ACTION) { + if (args.size() != 0) { + WrongNumberOfParameters(0); + } + auto t = det->getFirmwareVersion({det_id}); + if (det->getDetectorType().squash() == defs::EIGER) { + os << OutString(t) << '\n'; + } else { + os << OutStringHex(t) << '\n'; + } + } else if (action == defs::PUT_ACTION) { + throw sls::RuntimeError("cannot put"); + } else { + throw sls::RuntimeError("Unknown action"); + } + return os.str(); +} + +std::string CmdProxy::Versions(int action) { + std::ostringstream os; + os << cmd << ' '; + if (action == defs::HELP_ACTION) { + os << "\n\tPrint all versions and detector type" << '\n'; + } else if (action == defs::GET_ACTION) { + if (args.size() != 0) { + WrongNumberOfParameters(0); + } + auto t = det->getFirmwareVersion(); + os << "\nDetector Type: " << OutString(det->getDetectorType()) + << "\nPackage Version: " << det->getPackageVersion() + << std::hex + << "\nClient Version: 0x" << det->getClientVersion(); + if (det->getDetectorType().squash() == defs::EIGER) { + os << "\nFirmware Version: " << OutString(t); + } else { + os << "\nFirmware Version: " << OutStringHex(t); + } + os << "\nDetector Server Version: " << OutStringHex(det->getDetectorServerVersion()); + if (det->getUseReceiverFlag().squash(true)) { + os << "\nReceiver Version: " << OutStringHex(det->getReceiverVersion()); + } + os << std::dec << '\n'; + } else if (action == defs::PUT_ACTION) { + throw sls::RuntimeError("cannot put"); + } else { + throw sls::RuntimeError("Unknown action"); + } + return os.str(); +} + +std::string CmdProxy::PackageVersion(int action) { + std::ostringstream os; + os << cmd << ' '; + if (action == defs::HELP_ACTION) { + os << "\n\tPackage version (git branch)." << '\n'; + } else if (action == defs::GET_ACTION) { + if (args.size() != 0) { + WrongNumberOfParameters(0); + } + os << det->getPackageVersion() << '\n'; + } else if (action == defs::PUT_ACTION) { + throw sls::RuntimeError("cannot put"); + } else { + throw sls::RuntimeError("Unknown action"); + } + return os.str(); +} + +std::string CmdProxy::ClientVersion(int action) { + std::ostringstream os; + os << cmd << ' '; + if (action == defs::HELP_ACTION) { + os << "\n\tClient software version in format [0xYYMMDD]." << '\n'; + } else if (action == defs::GET_ACTION) { + if (args.size() != 0) { + WrongNumberOfParameters(0); + } + os << ToStringHex(det->getClientVersion()) << '\n'; + } else if (action == defs::PUT_ACTION) { + throw sls::RuntimeError("cannot put"); + } else { + throw sls::RuntimeError("Unknown action"); + } + return os.str(); +} + +std::string CmdProxy::DetectorSize(int action) { + std::ostringstream os; + os << cmd << ' '; + if (action == defs::HELP_ACTION) { + os << "[nx] [ny]\n\tDetector size, ie. Number of channels in x and y dim. If 0, then hostname adds all modules in y dim. This is used to calculate module coordinates included in UDP data packet header." << '\n'; + } else if (action == defs::GET_ACTION) { + if (args.size() != 0) { + WrongNumberOfParameters(0); + } + auto t = det->getDetectorSize(); + os << "[" << t.x << "," << t.y << "]\n"; + } else if (action == defs::PUT_ACTION) { + if (args.size() != 2) { + WrongNumberOfParameters(2); + } + defs::xy t; + t.x = std::stoi(args[0]); + t.y = std::stoi(args[1]); + det->setDetectorSize(t); + os << ToString(args) << '\n'; + } else { + throw sls::RuntimeError("Unknown action"); + } + return os.str(); +} + + +/* acquisition parameters */ + +std::string CmdProxy::Speed(int action) { + std::ostringstream os; + os << cmd << ' '; + if (action == defs::HELP_ACTION) { + os << "[0 or full_speed|1 or half_speed|2 or quarter_speed]\n\t[Eiger][Jungfrau] Readout speed of chip.\n\tJungfrau also overwrites adcphase to recommended default. " << '\n'; + } else if (action == defs::GET_ACTION) { + if (args.size() != 0) { + WrongNumberOfParameters(0); + } + auto t = det->getSpeed({det_id}); + os << OutString(t) << '\n'; + } else if (action == defs::PUT_ACTION) { + if (args.size() != 1) { + WrongNumberOfParameters(1); + } + defs::speedLevel t; + try{ + int ival = std::stoi(args[0]); + switch (ival) { + case 0: + t = defs::FULL_SPEED; + break; + case 1: + t = defs::HALF_SPEED; + break; + case 2: + t = defs::QUARTER_SPEED; + break; + default: + throw sls::RuntimeError("Unknown speed " + args[0]); + } + } catch (...) { + t = sls::StringTo(args[0]); + } + det->setSpeed(t, {det_id}); + os << sls::ToString(t) << '\n'; // no args to convert 0,1,2 as well + } else { + throw sls::RuntimeError("Unknown action"); + } + return os.str(); +} + +std::string CmdProxy::Adcphase(int action) { + std::ostringstream os; + os << cmd << ' '; + if (action == defs::HELP_ACTION) { + os << "[n_value] [(optional)deg]\n\t[Jungfrau][Ctb][Gotthard] Phase shift of ADC clock. \n\t[Jungfrau] Absolute phase shift. If deg used, then shift in degrees. Changing Speed also resets adcphase to recommended defaults.\n\t[Ctb] Absolute phase shift. If deg used, then shift in degrees. Changing adcclk also resets adcphase and sets it to previous values.\n\t[Gotthard] Relative phase shift" << '\n'; + } else if (action == defs::GET_ACTION) { + Result t; + if (args.size() == 0) { + t = det->getADCPhase({det_id}); + os << OutString(t) << '\n'; + } else if (args.size() == 1) { + if (args[0] != "deg") { + throw sls::RuntimeError("Unknown adcphase argument " + args[0] + ". Did you mean deg?"); + } + t = det->getADCPhaseInDegrees({det_id}); + os << OutString(t) << " deg\n"; + } else { + WrongNumberOfParameters(0); + } + } else if (action == defs::PUT_ACTION) { + if (args.size() == 1) { + det->setADCPhase(std::stoi(args[0]), {det_id}); + os << args.front() << '\n'; + } else if (args.size() == 2) { + if (args[1] != "deg") { + throw sls::RuntimeError("Unknown adcphase 2nd argument " + args[1] + ". Did you mean deg?"); + } + det->setADCPhaseInDegrees(std::stoi(args[0]), {det_id}); + os << args[0] << args[1] << '\n'; + } else { + WrongNumberOfParameters(1); + } + } else { + throw sls::RuntimeError("Unknown action"); + } + return os.str(); +} std::string CmdProxy::ClockFrequency(int action) { std::ostringstream os; @@ -199,7 +385,6 @@ std::string CmdProxy::ClockFrequency(int action) { WrongNumberOfParameters(2); } det->setClockFrequency(std::stoi(args[0]), std::stoi(args[1])); - //TODO print args os << std::stoi(args[1]) << '\n'; } else { throw sls::RuntimeError("Unknown action"); @@ -280,11 +465,593 @@ std::string CmdProxy::ClockDivider(int action) { WrongNumberOfParameters(2); } det->setClockDivider(std::stoi(args[0]), std::stoi(args[1])); - //TODO print args os << std::stoi(args[1]) << '\n'; } else { throw sls::RuntimeError("Unknown action"); } return os.str(); } + + + +/* acquisition */ +/* Network Configuration (Detector<->Receiver) */ +/* Receiver Config */ +/* File */ +/* ZMQ Streaming Parameters (Receiver<->Client) */ +/* Eiger Specific */ + +std::string CmdProxy::DynamicRange(int action) { + std::ostringstream os; + os << cmd << ' '; + if (action == defs::HELP_ACTION) { + os << "[4|8|16|32]\n\t[Eiger] Dynamic Range or number of bits per pixel in detector." << '\n'; + } else if (action == defs::GET_ACTION) { + if (args.size() != 0) { + WrongNumberOfParameters(0); + } + auto t = det->getDynamicRange({det_id}); + os << OutString(t) << '\n'; + } else if (action == defs::PUT_ACTION) { + if (det_id != -1) { + throw sls::RuntimeError("Cannot execute dynamic range at module level"); + } + if (args.size() != 1) { + WrongNumberOfParameters(1); + } + det->setDynamicRange(std::stoi(args[0])); + os << args.front() << '\n'; + } else { + throw sls::RuntimeError("Unknown action"); + } + return os.str(); +} + +std::string CmdProxy::Threshold(int action) { + std::ostringstream os; + os << cmd << ' '; + if (action == defs::HELP_ACTION) { + os << "[eV] [(optinal settings) standard, fast, highgain, dynamicgain, lowgain, mediumgain, veryhighgain, dynamichg0, fixgain1, fixgain2, forceswitchg1, forceswitchg2]\n\t[Eiger] Threshold in eV" << '\n'; + } else if (action == defs::GET_ACTION) { + if (args.size() != 0) { + WrongNumberOfParameters(0); + } + auto t = det->getThresholdEnergy(); + os << OutString(t) << '\n'; + } else if (action == defs::PUT_ACTION) { + if (args.size() == 1) { + det->setThresholdEnergy(std::stoi(args[0]), slsDetectorDefs::GET_SETTINGS, true, {det_id}); + } else if (args.size() == 2) { + det->setThresholdEnergy(std::stoi(args[0]), sls::StringTo(args[1]), true, {det_id}); + } else { + WrongNumberOfParameters(1); + } + os << ToString(args) << '\n'; + } else { + throw sls::RuntimeError("Unknown action"); + } + return os.str(); +} + +std::string CmdProxy::ThresholdNoTb(int action) { + std::ostringstream os; + os << cmd << ' '; + if (action == defs::HELP_ACTION) { + os << "[eV] [(optional settings) standard, fast, highgain, dynamicgain, lowgain, mediumgain, veryhighgain, dynamichg0, fixgain1, fixgain2, forceswitchg1, forceswitchg2]\n\t[Eiger] Threshold in eV set without setting trimbits" << '\n'; + } else if (action == defs::GET_ACTION) { + throw sls::RuntimeError("cannot get"); + } else if (action == defs::PUT_ACTION) { + if (args.size() == 1) { + det->setThresholdEnergy(std::stoi(args[0]), slsDetectorDefs::GET_SETTINGS, false, {det_id}); + } else if (args.size() == 2) { + det->setThresholdEnergy(std::stoi(args[0]), sls::StringTo(args[1]), false, {det_id}); + } else { + WrongNumberOfParameters(1); + } + os << ToString(args) << '\n'; + } else { + throw sls::RuntimeError("Unknown action"); + } + return os.str(); +} + +std::string CmdProxy::GapPixels(int action) { + std::ostringstream os; + os << cmd << ' '; + if (action == defs::HELP_ACTION) { + os << "[0, 1]\n\t[Eiger] Include Gap pixels in data file or data call back. 4 bit mode gap pixels only ind ata call back." << '\n'; + } else if (action == defs::GET_ACTION) { + if (args.size() != 0) { + WrongNumberOfParameters(0); + } + auto t = det->getRxAddGapPixels({det_id}); + os << OutString(t) << '\n'; + } else if (action == defs::PUT_ACTION) { + if (det_id != -1) { + throw sls::RuntimeError("Cannot execute dynamic range at module level"); + } + if (args.size() != 1) { + WrongNumberOfParameters(1); + } + det->setRxAddGapPixels(std::stoi(args[0])); + os << args.front() << '\n'; + } else { + throw sls::RuntimeError("Unknown action"); + } + return os.str(); +} + +std::string CmdProxy::TrimEnergies(int action) { + std::ostringstream os; + os << cmd << ' '; + if (action == defs::HELP_ACTION) { + os << "[trim_ev1] [trim_Ev2 (optional)] [trim_ev3 (optional)] ...\n\t[Eiger] Number of trim energies and list of trim energies, where corresponding default trim files exist in corresponding trim folders." << '\n'; + } else if (action == defs::GET_ACTION) { + if (args.size() != 0) { + WrongNumberOfParameters(0); + } + auto t = det->getTrimEnergies({det_id}); + os << OutString(t) << '\n'; + } else if (action == defs::PUT_ACTION) { + if (args.size() < 1) { + WrongNumberOfParameters(1); + } + unsigned int ntrim = args.size(); + std::vector t(ntrim); + for (unsigned int i = 0; i < ntrim; ++i) { + t[i] = std::stoi(args[i]); + } + det->setTrimEnergies(t, {det_id}); + os << sls::ToString(args) << '\n'; + } else { + throw sls::RuntimeError("Unknown action"); + } + return os.str(); +} + +std::string CmdProxy::RateCorrection(int action) { + std::ostringstream os; + os << cmd << ' '; + if (action == defs::HELP_ACTION) { + os << "[n_rate (in ns)]\n\t[Eiger] Dead time correction constant in ns. -1 will set to default tau of settings. 0 will unset rate correction." << '\n'; + } else if (action == defs::GET_ACTION) { + if (args.size() != 0) { + WrongNumberOfParameters(0); + } + auto t = det->getRateCorrection({det_id}); + os << OutString(t) << '\n'; + } else if (action == defs::PUT_ACTION) { + if (args.size() != 1) { + WrongNumberOfParameters(1); + } + int tau = std::stoi(args[0]); + if (tau == -1) { + det->setDefaultRateCorrection({det_id}); + auto t = det->getRateCorrection({det_id}); + os << OutString(t) << '\n'; + } else { + auto t = StringTo(args[0], "ns"); + det->setRateCorrection(t, {det_id}); + os << args.front() << "ns\n"; + } + } else { + throw sls::RuntimeError("Unknown action"); + } + return os.str(); +} + +std::string CmdProxy::Activate(int action) { + std::ostringstream os; + os << cmd << ' '; + if (action == defs::HELP_ACTION) { + os << "[0, 1] [(optional) padding|nopadding]\n\t[Eiger] 1 is default. 0 deactivates readout and does not send data. \n\tPadding will pad data files for deactivates readouts." << '\n'; + } else if (action == defs::GET_ACTION) { + if (args.size() != 0) { + WrongNumberOfParameters(0); + } + auto t = det->getActive({det_id}); + auto p = det->getRxPadDeactivatedMode({det_id}); + Result pResult(p.size()); + for (unsigned int i = 0; i < p.size(); ++i) { + pResult[i] = p[i] ? "padding" : "nopadding"; + } + os << OutString(t) << ' ' << OutString(pResult) << '\n'; + } else if (action == defs::PUT_ACTION) { + if (args.size() < 1 || args.size() > 2 ) { + WrongNumberOfParameters(2); + } + int t = std::stoi(args[0]); + det->setActive(t, {det_id}); + os << args[0]; + if (args.size() == 2) { + bool p = true; + if (args[1] == "nopadding") { + p = false; + } else if (args[1] != "padding") { + throw sls::RuntimeError("Unknown argument for deactivated padding."); + } + det->setRxPadDeactivatedMode(p, {det_id}); + os << ' ' << args[1]; + } + os << '\n'; + } else { + throw sls::RuntimeError("Unknown action"); + } + return os.str(); +} + +std::string CmdProxy::PulsePixel(int action) { + std::ostringstream os; + os << cmd << ' '; + if (action == defs::HELP_ACTION) { + os << "[n_times] [x] [y]\n\t[Eiger] Pulse pixel n number of times at coordinates (x, y)." << '\n'; + } else if (action == defs::GET_ACTION) { + throw sls::RuntimeError("cannot get"); + } else if (action == defs::PUT_ACTION) { + if (args.size() != 3) { + WrongNumberOfParameters(3); + } + int n = std::stoi(args[0]); + defs::xy c; + c.x = std::stoi(args[1]); + c.y = std::stoi(args[2]); + det->pulsePixel(n, c, {det_id}); + os << sls::ToString(args) << '\n'; + } else { + throw sls::RuntimeError("Unknown action"); + } + return os.str(); +} + +std::string CmdProxy::PulsePixelAndMove(int action) { + std::ostringstream os; + os << cmd << ' '; + if (action == defs::HELP_ACTION) { + os << "[n_times] [x] [y]\n\t[Eiger] Pulse pixel n number of times and moves relatively by (x, y)." << '\n'; + } else if (action == defs::GET_ACTION) { + throw sls::RuntimeError("cannot get"); + } else if (action == defs::PUT_ACTION) { + if (args.size() != 3) { + WrongNumberOfParameters(3); + } + int n = std::stoi(args[0]); + defs::xy c; + c.x = std::stoi(args[1]); + c.y = std::stoi(args[2]); + det->pulsePixelNMove(n, c, {det_id}); + os << sls::ToString(args) << '\n'; + } else { + throw sls::RuntimeError("Unknown action"); + } + return os.str(); +} + +std::string CmdProxy::PulseChip(int action) { + std::ostringstream os; + os << cmd << ' '; + if (action == defs::HELP_ACTION) { + os << "[n_times] \n\t[Eiger] Pulse chip n times. If n is -1, resets to normal mode (reset chip completely at start of acquisition, where partialreset = 0)." << '\n'; + } else if (action == defs::GET_ACTION) { + throw sls::RuntimeError("cannot get"); + } else if (action == defs::PUT_ACTION) { + if (args.size() != 1) { + WrongNumberOfParameters(1); + } + det->pulseChip(std::stoi(args[0]), {det_id}); + os << args.front() << '\n'; + } else { + throw sls::RuntimeError("Unknown action"); + } + return os.str(); +} + +std::string CmdProxy::Quad(int action) { + std::ostringstream os; + os << cmd << ' '; + if (action == defs::HELP_ACTION) { + os << "[0, 1]\n\t[Eiger] 0 is default. 1 sets detector size to a quad (Specific hardware required)." << '\n'; + } else if (action == defs::GET_ACTION) { + if (args.size() != 0) { + WrongNumberOfParameters(0); + } + auto t = det->getQuad({det_id}); + os << OutString(t) << '\n'; + } else if (action == defs::PUT_ACTION) { + if (det_id != -1) { + throw sls::RuntimeError("Cannot execute dynamic range at module level"); + } + if (args.size() != 1) { + WrongNumberOfParameters(1); + } + det->setQuad(std::stoi(args[0])); + os << args.front() << '\n'; + } else { + throw sls::RuntimeError("Unknown action"); + } + return os.str(); +} + + +/* Jungfrau Specific */ + +std::string CmdProxy::TemperatureEvent(int action) { + std::ostringstream os; + os << cmd << ' '; + if (action == defs::HELP_ACTION) { + os << "[0]\n\t[Jungfrau] 1, if a temperature event occured. To clear this event, set it to 0.\n\tIf temperature crosses threshold temperature and temperature control is enabled, power to chip will be switched off and temperature event occurs. To power on chip again, temperature has to be less than threshold temperature and temperature event has to be cleared." << '\n'; + } else if (action == defs::GET_ACTION) { + if (args.size() != 0) { + WrongNumberOfParameters(0); + } + auto t = det->getTemperatureEvent({det_id}); + os << OutString(t) << '\n'; + } else if (action == defs::PUT_ACTION) { + if (args.size() != 1) { + WrongNumberOfParameters(1); + } + if (std::stoi(args[1]) != 0) { + throw sls::RuntimeError("Unknown argument for temp event. Did you mean 0 to reset event?"); + } + det->resetTemperatureEvent(); + os << "cleared" << '\n'; + } else { + throw sls::RuntimeError("Unknown action"); + } + return os.str(); +} + + +/* Gotthard Specific */ + +std::string CmdProxy::ROI(int action) { + std::ostringstream os; + os << cmd << ' '; + if (action == defs::HELP_ACTION) { + os << "[xmin] [xmax] \n\t[Gotthard] Region of interest in detector. Either all channels or a single adc or 2 chips (256 channels). Default is all channels enabled (-1 -1). " << '\n'; + } else if (action == defs::GET_ACTION) { + if (args.size() != 0) { + WrongNumberOfParameters(0); + } + auto t = det->getROI({det_id}); + for (auto &it : t) { + os << '[' << it.xmin << ", " << it.xmax << "] \n"; + } + } else if (action == defs::PUT_ACTION) { + if (det_id == -1) { + throw sls::RuntimeError("Cannot execute ROI at multi module level"); + } + if (args.size() != 2) { + WrongNumberOfParameters(2); + } + defs::ROI t; + t.xmin = std::stoi(args[0]); + t.xmax = std::stoi(args[1]); + det->setROI(t, det_id); + os << '[' << t.xmin << ", " << t.xmax << "] \n"; + } else { + throw sls::RuntimeError("Unknown action"); + } + return os.str(); +} + +std::string CmdProxy::ClearROI(int action) { + std::ostringstream os; + os << cmd << ' '; + if (action == defs::HELP_ACTION) { + os << "\n\t[Gotthard] Resets Region of interest in detector. All channels enabled. Default is all channels." << '\n'; + } else if (action == defs::GET_ACTION) { + throw sls::RuntimeError("Cannot get"); + } else if (action == defs::PUT_ACTION) { + if (args.size() != 0) { + WrongNumberOfParameters(0); + } + det->clearROI({det_id}); + os << "[-1, -1] \n"; + } else { + throw sls::RuntimeError("Unknown action"); + } + return os.str(); +} + +/* Gotthard2 Specific */ +/* CTB Specific */ + +std::string CmdProxy::Samples(int action) { + std::ostringstream os; + os << cmd << ' '; + if (action == defs::HELP_ACTION) { + os << "[n_samples]\n\t[CTB] Number of samples (both analog and digitial) expected." << '\n'; + } else if (action == defs::GET_ACTION) { + if (args.size() != 0) { + WrongNumberOfParameters(0); + } + auto a = det->getNumberOfAnalogSamples({det_id}); + auto d = det->getNumberOfDigitalSamples({det_id}); + int as = a.squash(-1); + int ds = d.squash(-1); + if (as == -1 || ds == -1 || as != ds) { // check if a == d? + throw sls::RuntimeError("Different samples. Use asamples or dsamples."); + } + os << OutString(a) << '\n'; + } else if (action == defs::PUT_ACTION) { + if (args.size() != 1) { + WrongNumberOfParameters(1); + } + det->setNumberOfAnalogSamples(std::stoi(args[0])); + det->setNumberOfDigitalSamples(std::stoi(args[0])); + os << args.front() << '\n'; + } else { + throw sls::RuntimeError("Unknown action"); + } + return os.str(); +} + +std::string CmdProxy::Dbitphase(int action) { + std::ostringstream os; + os << cmd << ' '; + if (action == defs::HELP_ACTION) { + os << "[n_value] [(optional)deg]\n\t[Ctb] Phase shift of clock to latch digital bits. Absolute phase shift. If deg used, then shift in degrees. Changing dbitclk also resets dbitphase and sets to previous values." << '\n'; + } else if (action == defs::GET_ACTION) { + Result t; + if (args.size() == 0) { + t = det->getDBITPhase({det_id}); + os << OutString(t) << '\n'; + } else if (args.size() == 1) { + if (args[0] != "deg") { + throw sls::RuntimeError("Unknown dbitphase argument " + args[0] + ". Did you mean deg?"); + } + t = det->getDBITPhaseInDegrees({det_id}); + os << OutString(t) << " deg\n"; + } else { + WrongNumberOfParameters(0); + } + } else if (action == defs::PUT_ACTION) { + if (args.size() == 1) { + det->setDBITPhase(std::stoi(args[0]), {det_id}); + os << args.front() << '\n'; + } else if (args.size() == 2) { + if (args[1] != "deg") { + throw sls::RuntimeError("Unknown dbitphase 2nd argument " + args[1] + ". Did you mean deg?"); + } + det->setDBITPhaseInDegrees(std::stoi(args[0]), {det_id}); + os << args[0] << args[1] << '\n'; + } else { + WrongNumberOfParameters(1); + } + } else { + throw sls::RuntimeError("Unknown action"); + } + return os.str(); +} + +std::string CmdProxy::SlowAdc(int action) { + std::ostringstream os; + os << cmd << ' '; + if (action == defs::HELP_ACTION) { + os << "[n_channel (0-7 for channel|8 for temperature)]\n\t[Ctb] Slow ADC channel." << '\n'; + } else if (action == defs::GET_ACTION) { + if (args.size() != 1) { + WrongNumberOfParameters(0); + } + int nchan = std::stoi(args[0]); + if (nchan < 0 || nchan > defs::SLOW_ADC_TEMP - defs::SLOW_ADC0) { + throw sls::RuntimeError("Unknown adc argument " + args[0]); + } + if (nchan == 8) { + auto t = det->getTemperature(defs::SLOW_ADC_TEMP, {det_id}); + os << OutString(t) << " °C\n"; + } else { + auto t = det->getSlowADC(static_cast(nchan + defs::SLOW_ADC0)); + os << OutString(t) << '\n'; + } + } else if (action == defs::PUT_ACTION) { + throw sls::RuntimeError("cannot put"); + } else { + throw sls::RuntimeError("Unknown action"); + } + return os.str(); +} + + +std::string CmdProxy::ReceiverDbitList(int action) { + std::ostringstream os; + os << cmd << ' '; + if (action == defs::HELP_ACTION) { + os << "[all] or [i0] [i1] [i2]... \n\t[Ctb] List of digital signal bits read out. If all is used instead of a list, all digital bits (64) enabled. Each element in list can be 0 - 63 and non repetitive." << '\n'; + } else if (action == defs::GET_ACTION) { + if (args.size() != 0) { + WrongNumberOfParameters(0); + } + auto t = det->getRxDbitList({det_id}); + os << OutString(t) << '\n'; + } else if (action == defs::PUT_ACTION) { + if (args.size() < 1) { + WrongNumberOfParameters(1); + } + std::vector t; + if (args[0] == "all") { + t.resize(64); + for (unsigned int i = 0; i < 64; ++i) { + t[i] = i; + } + } else { + unsigned int ntrim = args.size(); + t.resize(ntrim); + for (unsigned int i = 0; i < ntrim; ++i) { + t[i] = std::stoi(args[i]); + } + } + det->setRxDbitList(t, {det_id}); + os << sls::ToString(args) << '\n'; + } else { + throw sls::RuntimeError("Unknown action"); + } + return os.str(); +} + +std::string CmdProxy::DigitalIODelay(int action) { + std::ostringstream os; + os << cmd << ' '; + if (action == defs::HELP_ACTION) { + os << "[64 bit bitmask] [0-775]\n\t[Ctb] Delay for digital IO pins selected by the bitmask. Delay is in ps and max of 775 ps. Resolution is 25 ps." << '\n'; + } else if (action == defs::GET_ACTION) { + throw sls::RuntimeError("Cannot get"); + } else if (action == defs::PUT_ACTION) { + if (args.size() != 2) { + WrongNumberOfParameters(2); + } + det->setDigitalIODelay(std::stoul(args[0]), std::stoi(args[2])); + os << sls::ToString(args) << '\n'; + } else { + throw sls::RuntimeError("Unknown action"); + } + return os.str(); +} + + +/* Pattern */ + +std::string CmdProxy::Pattern(int action) { + std::ostringstream os; + os << cmd << ' '; + if (action == defs::HELP_ACTION) { + os << "[fname]\n\t[Ctb] Loads binary pattern file with only pattern words" << '\n'; + } else if (action == defs::GET_ACTION) { + throw sls::RuntimeError("Cannot get"); + } else if (action == defs::PUT_ACTION) { + if (args.size() != 1) { + WrongNumberOfParameters(1); + } + det->setPattern(args[0]); + os << args.front() << '\n'; + } else { + throw sls::RuntimeError("Unknown action"); + } + return os.str(); +} + +std::string CmdProxy::PatternWord(int action) { + std::ostringstream os; + os << cmd << ' '; + if (action == defs::HELP_ACTION) { + os << "[step or address] [64 bit mask]\n\t[Ctb] 64 bit pattern at address of pattern memory." << '\n'; + } else if (action == defs::GET_ACTION) { + if (args.size() != 1) { + WrongNumberOfParameters(1); + } + auto t = det->getPatternWord(std::stoi(args[0]), {det_id}); + os << OutStringHex(t) << '\n'; + } else if (action == defs::PUT_ACTION) { + if (args.size() != 2) { + WrongNumberOfParameters(2); + } + det->setPatternWord(std::stoi(args[0]), std::stoul(args[1])); + os << sls::ToString(args) << '\n'; + } else { + throw sls::RuntimeError("Unknown action"); + } + return os.str(); +} + + } // namespace sls \ No newline at end of file diff --git a/slsDetectorSoftware/src/Detector.cpp b/slsDetectorSoftware/src/Detector.cpp index a9955bda3..637ecd005 100644 --- a/slsDetectorSoftware/src/Detector.cpp +++ b/slsDetectorSoftware/src/Detector.cpp @@ -22,11 +22,7 @@ void Detector::loadConfig(const std::string &fname) { } void Detector::loadParameters(const std::string &fname) { - pimpl->retrieveDetectorSetup(fname, 0); -} - -void Detector::savePattern(const std::string &fname) { - pimpl->savePattern(fname); + pimpl->loadParameters(fname); } Result Detector::getHostname(Positions pos) const { @@ -39,6 +35,14 @@ void Detector::setHostname(const std::vector &value) { int Detector::getShmId() const { return pimpl->getMultiId(); } +std::string Detector::getPackageVersion() const { + return pimpl->getPackageVersion(); +} + +int64_t Detector::getClientVersion() const { + return pimpl->getClientSoftwareVersion(); +} + Result Detector::getFirmwareVersion(Positions pos) const { return pimpl->Parallel(&slsDetector::getId, pos, defs::DETECTOR_FIRMWARE_VERSION); @@ -54,10 +58,6 @@ Result Detector::getSerialNumber(Positions pos) const { defs::DETECTOR_SERIAL_NUMBER); } -int64_t Detector::getClientVersion() const { - return pimpl->getClientSoftwareVersion(); -} - Result Detector::getReceiverVersion(Positions pos) const { return pimpl->Parallel(&slsDetector::getReceiverSoftwareVersion, pos); } @@ -117,11 +117,11 @@ void Detector::setNumberOfFrames(int64_t value) { } Result Detector::getNumberOfTriggers() const { - return pimpl->Parallel(&slsDetector::setTimer, {}, defs::CYCLES_NUMBER, -1); + return pimpl->Parallel(&slsDetector::setTimer, {}, defs::TRIGGER_NUMBER, -1); } void Detector::setNumberOfTriggers(int64_t value) { - pimpl->Parallel(&slsDetector::setTimer, {}, defs::CYCLES_NUMBER, value); + pimpl->Parallel(&slsDetector::setTimer, {}, defs::TRIGGER_NUMBER, value); } Result Detector::getExptime(Positions pos) const { @@ -157,7 +157,7 @@ Result Detector::getNumberOfFramesLeft(Positions pos) const { } Result Detector::getNumberOfTriggersLeft(Positions pos) const { - return pimpl->Parallel(&slsDetector::getTimeLeft, pos, defs::CYCLES_NUMBER); + return pimpl->Parallel(&slsDetector::getTimeLeft, pos, defs::TRIGGER_NUMBER); } Result Detector::getDelayAfterTriggerLeft(Positions pos) const { @@ -246,7 +246,7 @@ Result Detector::getDAC(defs::dacIndex index, bool mV, return pimpl->Parallel(&slsDetector::setDAC, pos, -1, index, mV); } -void Detector::setDAC(int value, defs::dacIndex index, bool mV, Positions pos) { +void Detector::setDAC(defs::dacIndex index, int value, bool mV, Positions pos) { pimpl->Parallel(&slsDetector::setDAC, pos, value, index, mV); } @@ -263,20 +263,27 @@ void Detector::setTimingMode(defs::timingMode value, Positions pos) { void Detector::acquire() { pimpl->acquire(); } -void Detector::startAcquisition() { - if (getUseReceiverFlag().squash(true)) - pimpl->Parallel(&slsDetector::startReceiver, {}); +void Detector::clearAcquiringFlag() { pimpl->setAcquiringFlag(0); } + +void Detector::startReceiver() { + pimpl->Parallel(&slsDetector::startReceiver, {}); +} + +void Detector::stopReceiver() { + pimpl->Parallel(&slsDetector::stopReceiver, {}); +} + +void Detector::startDetector() { + if (getDetectorType({}).squash() == defs::EIGER) { + pimpl->Parallel(&slsDetector::prepareAcquisition, {}); + } pimpl->Parallel(&slsDetector::startAcquisition, {}); } -void Detector::stopAcquisition() { +void Detector::stopDetector() { pimpl->Parallel(&slsDetector::stopAcquisition, {}); - if (getUseReceiverFlag().squash(true)) - pimpl->Parallel(&slsDetector::stopReceiver, {}); } -void Detector::clearAcquiringFlag() { pimpl->setAcquiringFlag(0); } - Result Detector::getDetectorStatus(Positions pos) const { return pimpl->Parallel(&slsDetector::getRunStatus, pos); } @@ -497,8 +504,19 @@ Result Detector::getRxPort(Positions pos) const { return pimpl->Parallel(&slsDetector::getReceiverPort, pos); } -void Detector::setRxPort(int value, Positions pos) { - pimpl->Parallel(&slsDetector::setReceiverPort, pos, value); +void Detector::setRxPort(int port, int module_id) { + if (module_id == -1) { + std::vector port_list(size()); + for (auto &it: port_list) { + it = port++; + } + for (int idet = 0; idet < size(); ++idet) { + pimpl->Parallel(&slsDetector::setReceiverPort, {idet}, + port_list[idet]); + } + } else { + pimpl->Parallel(&slsDetector::setReceiverPort, {module_id}, port); + } } Result Detector::getRxFifoDepth(Positions pos) const { @@ -559,7 +577,7 @@ void Detector::setRxLock(bool value, Positions pos) { pimpl->Parallel(&slsDetector::lockReceiver, pos, static_cast(value)); } -Result Detector::getRxLastClientIP(Positions pos) const { +Result Detector::getRxLastClientIP(Positions pos) const { return pimpl->Parallel(&slsDetector::getReceiverLastClientIP, pos); } @@ -589,11 +607,11 @@ void Detector::setFileNamePrefix(const std::string &fname, Positions pos) { pimpl->Parallel(&slsDetector::setFileName, pos, fname); } -Result Detector::getAcquisitionIndex(Positions pos) const { +Result Detector::getAcquisitionIndex(Positions pos) const { return pimpl->Parallel(&slsDetector::getFileIndex, pos); } -void Detector::setAcquisitionIndex(int i, Positions pos) { +void Detector::setAcquisitionIndex(int64_t i, Positions pos) { pimpl->Parallel(&slsDetector::setFileIndex, pos, i); } @@ -675,11 +693,11 @@ void Detector::setRxZmqPort(int port, int module_id) { } } -Result Detector::getRxZmqIP(Positions pos) const { +Result Detector::getRxZmqIP(Positions pos) const { return pimpl->Parallel(&slsDetector::getReceiverStreamingIP, pos); } -void Detector::setRxZmqIP(const std::string &ip, Positions pos) { +void Detector::setRxZmqIP(const IpAddr ip, Positions pos) { bool previouslyReceiverStreaming = getRxZmqDataStream(pos).squash(false); pimpl->Parallel(&slsDetector::setReceiverStreamingIP, pos, ip); if (previouslyReceiverStreaming) { @@ -705,11 +723,11 @@ void Detector::setClientZmqPort(int port, int module_id) { } } -Result Detector::getClientZmqIp(Positions pos) const { +Result Detector::getClientZmqIp(Positions pos) const { return pimpl->Parallel(&slsDetector::getClientStreamingIP, pos); } -void Detector::setClientZmqIp(const std::string &ip, Positions pos) { +void Detector::setClientZmqIp(const IpAddr ip, Positions pos) { int previouslyClientStreaming = pimpl->enableDataStreamingToClient(-1); pimpl->Parallel(&slsDetector::setClientStreamingIP, pos, ip); if (previouslyClientStreaming != 0) { @@ -757,11 +775,11 @@ void Detector::setThresholdEnergy(int threshold_ev, settings, static_cast(trimbits)); } -Result Detector::getSettingsDir(Positions pos) const { +Result Detector::getSettingsPath(Positions pos) const { return pimpl->Parallel(&slsDetector::getSettingsDir, pos); } -void Detector::setSettingsDir(const std::string &value, Positions pos) { +void Detector::setSettingsPath(const std::string &value, Positions pos) { pimpl->Parallel(&slsDetector::setSettingsDir, pos, value); } @@ -882,7 +900,12 @@ void Detector::setRxPadDeactivatedMode(bool pad, Positions pos) { } Result Detector::getPartialReset(Positions pos) const { - return pimpl->Parallel(&slsDetector::setCounterBit, pos, -1); + auto res = pimpl->Parallel(&slsDetector::setCounterBit, pos, -1); + Result t(res.size()); + for (unsigned int i = 0; i < res.size(); ++i) { + t[i] = !res[i]; + } + return t; } void Detector::setPartialReset(bool value, Positions pos) { @@ -943,7 +966,7 @@ Result Detector::getPowerChip(Positions pos) const { } void Detector::setPowerChip(bool on, Positions pos) { - if (on && pimpl->size() > 3) { + if ((pos.empty() || pos[0] == -1) && on && pimpl->size() > 3) { for (unsigned int i = 0; i != pimpl->size(); ++i) { pimpl->powerChip(static_cast(on), i); usleep(1000 * 1000); @@ -996,11 +1019,15 @@ Result Detector::getROI(Positions pos) const { return pimpl->Parallel(&slsDetector::getROI, pos); } -void Detector::setROI(defs::ROI value, int moduleId) { - if (moduleId < 0 && size() > 1) { +void Detector::setROI(defs::ROI value, int module_id) { + if (module_id < 0 && size() > 1) { throw RuntimeError("Cannot set ROI for all modules simultaneously"); } - pimpl->Parallel(&slsDetector::setROI, {moduleId}, value); + pimpl->Parallel(&slsDetector::setROI, {module_id}, value); +} + +void Detector::clearROI(Positions pos) { + pimpl->Parallel(&slsDetector::clearROI, pos); } Result Detector::getExptimeLeft(Positions pos) const { @@ -1136,14 +1163,6 @@ void Detector::setDBITPipeline(int value, Positions pos) { pimpl->Parallel(&slsDetector::setSpeed, pos, defs::DBIT_PIPELINE, value, 0); } -Result Detector::getVrefVoltage(bool mV, Positions pos) const { - return pimpl->Parallel(&slsDetector::setDAC, pos, -1, defs::ADC_VPP, mV); -} - -void Detector::setVrefVoltage(int value, bool mV, Positions pos) { - pimpl->Parallel(&slsDetector::setDAC, pos, value, defs::ADC_VPP, mV); -} - Result Detector::getVoltage(defs::dacIndex index, Positions pos) const { switch (index) { case defs::V_LIMIT: @@ -1160,7 +1179,7 @@ Result Detector::getVoltage(defs::dacIndex index, Positions pos) const { return pimpl->Parallel(&slsDetector::setDAC, pos, -1, index, 1); } -void Detector::setVoltage(int value, defs::dacIndex index, Positions pos) { +void Detector::setVoltage(defs::dacIndex index, int value, Positions pos) { switch (index) { case defs::V_LIMIT: case defs::V_POWER_A: @@ -1276,6 +1295,10 @@ void Detector::setLEDEnable(bool enable, Positions pos) { // Pattern +void Detector::savePattern(const std::string &fname) { + pimpl->savePattern(fname); +} + void Detector::setPattern(const std::string &fname, Positions pos) { pimpl->Parallel(&slsDetector::setPattern, pos, fname); } @@ -1296,6 +1319,10 @@ void Detector::setPatternClockControl(uint64_t word, Positions pos) { pimpl->Parallel(&slsDetector::setPatternClockControl, pos, word); } +Result Detector::getPatternWord(int addr, Positions pos) { + return pimpl->Parallel(&slsDetector::setPatternWord, pos, addr, -1); +} + void Detector::setPatternWord(int addr, uint64_t word, Positions pos) { pimpl->Parallel(&slsDetector::setPatternWord, pos, addr, word); } @@ -1369,7 +1396,7 @@ Result Detector::getDetectorMinMaxEnergyThreshold(const bool isEmax, Positions pos) const { auto res = pimpl->Parallel(&slsDetector::getAdditionalJsonParameter, pos, isEmax ? "emax" : "emin"); - Result intResult; + Result intResult(res.size()); try { for (unsigned int i = 0; i < res.size(); ++i) { intResult[i] = stoi(res[i]); @@ -1391,7 +1418,7 @@ void Detector::setDetectorMinMaxEnergyThreshold(const bool isEmax, Result Detector::getFrameMode(Positions pos) const { auto res = pimpl->Parallel(&slsDetector::getAdditionalJsonParameter, pos, "frameMode"); - Result intResult; + Result intResult(res.size()); try { for (unsigned int i = 0; i < res.size(); ++i) { intResult[i] = defs::getFrameModeType(res[i]); @@ -1411,7 +1438,7 @@ void Detector::setFrameMode(defs::frameModeType value, Positions pos) { Result Detector::getDetectorMode(Positions pos) const { auto res = pimpl->Parallel(&slsDetector::getAdditionalJsonParameter, pos, "detectorMode"); - Result intResult; + Result intResult(res.size()); try { for (unsigned int i = 0; i < res.size(); ++i) { intResult[i] = defs::getDetectorModeType(res[i]); @@ -1516,7 +1543,7 @@ void Detector::setDetectorLock(bool lock, Positions pos) { pimpl->Parallel(&slsDetector::lockServer, pos, static_cast(lock)); } -Result Detector::getLastClientIP(Positions pos) const { +Result Detector::getLastClientIP(Positions pos) const { return pimpl->Parallel(&slsDetector::getLastClientIP, pos); } diff --git a/slsDetectorSoftware/src/multiSlsDetector.cpp b/slsDetectorSoftware/src/multiSlsDetector.cpp index 2536dfd83..4dbe31a56 100755 --- a/slsDetectorSoftware/src/multiSlsDetector.cpp +++ b/slsDetectorSoftware/src/multiSlsDetector.cpp @@ -13,6 +13,7 @@ #include "container_utils.h" #include "network_utils.h" #include "string_utils.h" +#include "ToString.h" #include #include @@ -164,6 +165,8 @@ int64_t multiSlsDetector::getId(idMode mode, int detPos) { return sls::minusOneIfDifferent(r); } +std::string multiSlsDetector::getPackageVersion() const { return GITBRANCH; } + int64_t multiSlsDetector::getClientSoftwareVersion() const { return APILIB; } int64_t multiSlsDetector::getReceiverSoftwareVersion(int detPos) { @@ -240,8 +243,7 @@ std::string multiSlsDetector::getUserDetails() { sstream << "\nType: "; // get type from multi shm if (multi_shm()->shmversion >= MULTI_SHMAPIVERSION) { - sstream << slsDetectorDefs::detectorTypeToString( - getDetectorTypeAsEnum()); + sstream << ToString(getDetectorTypeAsEnum()); } // get type from slsdet shm else { @@ -396,7 +398,10 @@ void multiSlsDetector::setHostname(const char *name, int detPos) { freeSharedMemory(); setupMultiDetector(); } - addMultipleDetectors(name); + for (const auto &hostname : sls::split(name, '+')) { + addSlsDetector(hostname); + } + updateDetectorSize(); } std::string multiSlsDetector::getHostname(int detPos) const { @@ -410,15 +415,9 @@ std::string multiSlsDetector::getHostname(int detPos) const { return sls::concatenateNonEmptyStrings(r); } -void multiSlsDetector::addMultipleDetectors(const char *name) { - for (const auto &hostname : sls::split(name, '+')) { - addSlsDetector(hostname); - } - updateDetectorSize(); -} void multiSlsDetector::addSlsDetector(const std::string &hostname) { - FILE_LOG(logDEBUG1) << "Adding detector " << hostname; + FILE_LOG(logINFO) << "Adding detector " << hostname; int port = DEFAULT_PORTNO; std::string host = hostname; @@ -622,13 +621,6 @@ int multiSlsDetector::lockServer(int p, int detPos) { return sls::minusOneIfDifferent(r); } -std::string multiSlsDetector::getLastClientIP(int detPos) { - if (detPos >= 0) { - return detectors[detPos]->getLastClientIP(); - } - auto r = parallelCall(&slsDetector::getLastClientIP); - return sls::concatenateIfDifferent(r); -} void multiSlsDetector::exitServer(int detPos) { if (detPos >= 0) { @@ -650,7 +642,7 @@ void multiSlsDetector::readConfigurationFile(const std::string &fname) { FILE_LOG(logINFO) << "Loading configuration file: " << fname; std::ifstream input_file; - input_file.open(fname, std::ios_base::in); + input_file.open(fname.c_str(), std::ios_base::in); if (!input_file.is_open()) { throw RuntimeError("Could not open configuration file " + fname + " for reading"); @@ -664,7 +656,7 @@ void multiSlsDetector::readConfigurationFile(const std::string &fname) { FILE_LOG(logDEBUG1) << "current_line after removing comments:\n\t" << current_line; if (current_line.length() > 1) { - multiSlsDetectorClient(current_line, PUT_ACTION, this); + multiSlsDetectorClient(current_line, PUT_ACTION, nullptr); } } input_file.close(); @@ -787,118 +779,6 @@ void multiSlsDetector::saveSettingsFile(const std::string &fname, int detPos) { parallelCall(&slsDetector::saveSettingsFile, fname); } -slsDetectorDefs::runStatus multiSlsDetector::getRunStatus(int detPos) { - // single - if (detPos >= 0) { - return detectors[detPos]->getRunStatus(); - } - - // multi - auto r = parallelCall(&slsDetector::getRunStatus); - if (sls::allEqual(r)) { - return r.front(); - } - if (sls::anyEqualTo(r, ERROR)) { - return ERROR; - } - for (const auto &value : r) { - if (value != IDLE) { - return value; - } - } - return IDLE; -} - -void multiSlsDetector::prepareAcquisition(int detPos) { - // single - if (detPos >= 0) { - detectors[detPos]->prepareAcquisition(); - } - - // multi - parallelCall(&slsDetector::prepareAcquisition); -} - -void multiSlsDetector::startAcquisition(int detPos) { - // single - if (detPos >= 0) { - if (detectors[detPos]->getDetectorTypeAsEnum() == EIGER) { - detectors[detPos]->prepareAcquisition(); - } - detectors[detPos]->startAcquisition(); - } - - // multi - if (getDetectorTypeAsEnum() == EIGER) { - prepareAcquisition(); - } - parallelCall(&slsDetector::startAcquisition); -} - -void multiSlsDetector::stopAcquisition(int detPos) { - if (detPos >= 0) { - detectors[detPos]->stopAcquisition(); - } else { - parallelCall(&slsDetector::stopAcquisition); - } -} - -void multiSlsDetector::sendSoftwareTrigger(int detPos) { - // single - if (detPos >= 0) { - detectors[detPos]->sendSoftwareTrigger(); - } - - // multi - parallelCall(&slsDetector::sendSoftwareTrigger); -} - -void multiSlsDetector::startAndReadAll(int detPos) { - // single - if (detPos >= 0) { - if (detectors[detPos]->getDetectorTypeAsEnum() == EIGER) { - detectors[detPos]->prepareAcquisition(); - } - detectors[detPos]->startAndReadAll(); - } - - // multi - if (getDetectorTypeAsEnum() == EIGER) { - prepareAcquisition(); - } - parallelCall(&slsDetector::startAndReadAll); -} - -void multiSlsDetector::startReadOut(int detPos) { - // single - if (detPos >= 0) { - detectors[detPos]->startReadOut(); - } - - // multi - parallelCall(&slsDetector::startReadOut); -} - -void multiSlsDetector::readAll(int detPos) { - // single - if (detPos >= 0) { - detectors[detPos]->readAll(); - } - - // multi - parallelCall(&slsDetector::readAll); -} -/* -void multiSlsDetector::configureMAC(int detPos) { - // single - if (detPos >= 0) { - detectors[detPos]->configureMAC(); - } - - // multi - parallelCall(&slsDetector::configureMAC); -} -*/ void multiSlsDetector::setStartingFrameNumber(const uint64_t value, int detPos) { @@ -994,8 +874,8 @@ int64_t multiSlsDetector::setNumberOfFrames(int64_t t, int detPos) { return setTimer(FRAME_NUMBER, t, detPos); } -int64_t multiSlsDetector::setNumberOfCycles(int64_t t, int detPos) { - return setTimer(CYCLES_NUMBER, t, detPos); +int64_t multiSlsDetector::setNumberOfTriggers(int64_t t, int detPos) { + return setTimer(TRIGGER_NUMBER, t, detPos); } int64_t multiSlsDetector::setNumberOfStorageCells(int64_t t, int detPos) { @@ -1436,74 +1316,6 @@ int multiSlsDetector::getReceiverStreamingPort(int detPos) { return sls::minusOneIfDifferent(r); } -void multiSlsDetector::setClientDataStreamingInIP(const std::string &ip, - int detPos) { - if (ip.length() != 0u) { - bool prev_streaming = enableDataStreamingToClient(-1); - - // single - if (detPos >= 0) { - detectors[detPos]->setClientStreamingIP(ip); - } - // multi - else { - for (auto &d : detectors) { - d->setClientStreamingIP(ip); - } - } - - if (prev_streaming) { - enableDataStreamingToClient(0); - enableDataStreamingToClient(1); - } - } -} - -std::string multiSlsDetector::getClientStreamingIP(int detPos) { - // single - if (detPos >= 0) { - return detectors[detPos]->getClientStreamingIP(); - } - - // multi - auto r = serialCall(&slsDetector::getClientStreamingIP); - return sls::concatenateIfDifferent(r); -} - -void multiSlsDetector::setReceiverDataStreamingOutIP(const std::string &ip, - int detPos) { - if (ip.length() != 0u) { - int prev_streaming = enableDataStreamingFromReceiver(-1, detPos); - - // single - if (detPos >= 0) { - detectors[detPos]->setReceiverStreamingIP(ip); - } - // multi - else { - for (auto &d : detectors) { - d->setReceiverStreamingIP(ip); - } - } - - if (prev_streaming != 0) { - enableDataStreamingFromReceiver(0, detPos); - enableDataStreamingFromReceiver(1, detPos); - } - } -} - -std::string multiSlsDetector::getReceiverStreamingIP(int detPos) { - // single - if (detPos >= 0) { - return detectors[detPos]->getReceiverStreamingIP(); - } - - // multi - auto r = serialCall(&slsDetector::getReceiverStreamingIP); - return sls::concatenateIfDifferent(r); -} - int multiSlsDetector::setDetectorNetworkParameter(networkParameter index, int value, int detPos) { // single @@ -2209,16 +2021,7 @@ int multiSlsDetector::lockReceiver(int lock, int detPos) { return sls::minusOneIfDifferent(r); } -std::string multiSlsDetector::getReceiverLastClientIP(int detPos) { - // single - if (detPos >= 0) { - return detectors[detPos]->getReceiverLastClientIP(); - } - // multi - auto r = parallelCall(&slsDetector::getReceiverLastClientIP); - return sls::concatenateIfDifferent(r); -} void multiSlsDetector::exitReceiver(int detPos) { // single @@ -2360,7 +2163,7 @@ slsDetectorDefs::fileFormat multiSlsDetector::setFileFormat(fileFormat f, return sls::minusOneIfDifferent(r); } -int multiSlsDetector::incrementFileIndex(int detPos) { +int64_t multiSlsDetector::incrementFileIndex(int detPos) { // single if (detPos >= 0) { return detectors[detPos]->incrementFileIndex(); @@ -2371,7 +2174,7 @@ int multiSlsDetector::incrementFileIndex(int detPos) { return sls::minusOneIfDifferent(r); } -int multiSlsDetector::setFileIndex(int i, int detPos) { +int64_t multiSlsDetector::setFileIndex(int64_t i, int detPos) { // single if (detPos >= 0) { return detectors[detPos]->setFileIndex(i); @@ -2382,54 +2185,13 @@ int multiSlsDetector::setFileIndex(int i, int detPos) { return sls::minusOneIfDifferent(r); } -int multiSlsDetector::getFileIndex(int detPos) const { +int64_t multiSlsDetector::getFileIndex(int detPos) const { if (detPos >= 0) return detectors[detPos]->getFileIndex(); auto r = parallelCall(&slsDetector::getFileIndex); return sls::minusOneIfDifferent(r); } -void multiSlsDetector::startReceiver(int detPos) { - // single - if (detPos >= 0) { - detectors[detPos]->startReceiver(); - } - - // multi - parallelCall(&slsDetector::startReceiver); -} - -void multiSlsDetector::stopReceiver(int detPos) { - // single - if (detPos >= 0) { - detectors[detPos]->stopReceiver(); - } - - // multi - parallelCall(&slsDetector::stopReceiver); -} - -slsDetectorDefs::runStatus multiSlsDetector::getReceiverStatus(int detPos) { - // single - if (detPos >= 0) { - return detectors[detPos]->getReceiverStatus(); - } - - // multi - auto r = parallelCall(&slsDetector::getReceiverStatus); - if (sls::allEqual(r)) { - return r.front(); - } - if (sls::anyEqualTo(r, ERROR)) { - return ERROR; - } - for (const auto &value : r) { - if (value != IDLE) { - return value; - } - } - return IDLE; -} int multiSlsDetector::getFramesCaughtByReceiver(int detPos) { // single @@ -2508,7 +2270,7 @@ int multiSlsDetector::createReceivingDataSockets(const bool destroy) { try { zmqSocket.push_back(sls::make_unique( detectors[iSocket / numSocketsPerDetector] - ->getClientStreamingIP() + ->getClientStreamingIP().str() .c_str(), portnum)); FILE_LOG(logINFO) << "Zmq Client[" << iSocket << "] at " @@ -3245,190 +3007,28 @@ void multiSlsDetector::setDigitalIODelay(uint64_t pinMask, int delay, parallelCall(&slsDetector::setDigitalIODelay, pinMask, delay); } -int multiSlsDetector::retrieveDetectorSetup(const std::string &fname1, - int level) { - - int skip = 0; - std::string fname; - std::string str; - std::ifstream infile; - int iargval; - int interrupt = 0; - char *args[10]; - - char myargs[10][1000]; - - std::string sargname, sargval; - int iline = 0; - - if (level == 2) { - FILE_LOG(logDEBUG1) << "config file read"; - fname = fname1 + std::string(".det"); - } else { - fname = fname1; +void multiSlsDetector::loadParameters(const std::string &fname) { + std::ifstream input_file; + input_file.open(fname.c_str(), std::ios_base::in); + if (!input_file.is_open()) { + throw RuntimeError("Could not open parameter file " + fname + + " for reading"); } - - infile.open(fname.c_str(), std::ios_base::in); - if (infile.is_open()) { - auto cmd = slsDetectorCommand(this); - while (infile.good() and interrupt == 0) { - sargname = "none"; - sargval = "0"; - getline(infile, str); - iline++; - FILE_LOG(logDEBUG1) << str; - if (str.find('#') != std::string::npos) { - FILE_LOG(logDEBUG1) << "Line is a comment \n" << str; - continue; - } else { - std::istringstream ssstr(str); - iargval = 0; - while (ssstr.good()) { - ssstr >> sargname; - // if (ssstr.good()) { - sls::strcpy_safe(myargs[iargval], sargname.c_str()); - args[iargval] = myargs[iargval]; - FILE_LOG(logDEBUG1) << args[iargval]; - iargval++; - // } - skip = 0; - } - if (level != 2) { - if (std::string(args[0]) == std::string("trimbits")) { - skip = 1; - } - } - if (skip == 0) { - cmd.executeLine(iargval, args, PUT_ACTION); - } - } - iline++; + std::string current_line; + while (input_file.good()) { + getline(input_file, current_line); + if (current_line.find('#') != std::string::npos) { + current_line.erase(current_line.find('#')); } - infile.close(); - - } else { - throw RuntimeError("Error opening " + fname + " for reading"); + FILE_LOG(logDEBUG1) + << "current_line after removing comments:\n\t" << current_line; + if (current_line.length() > 1) { + multiSlsDetectorClient(current_line, PUT_ACTION, this); + } } - FILE_LOG(logDEBUG1) << "Read " << iline << " lines"; - return OK; + input_file.close(); } -int multiSlsDetector::dumpDetectorSetup(const std::string &fname, int level) { - detectorType type = getDetectorTypeAsEnum(); - std::vector names; - // common config - names.emplace_back("fname"); - names.emplace_back("index"); - names.emplace_back("enablefwrite"); - names.emplace_back("overwrite"); - names.emplace_back("dr"); - names.emplace_back("settings"); - names.emplace_back("exptime"); - names.emplace_back("period"); - names.emplace_back("frames"); - names.emplace_back("cycles"); - names.emplace_back("timing"); - - switch (type) { - case EIGER: - names.emplace_back("flags"); - names.emplace_back("clkdivider"); - names.emplace_back("threshold"); - names.emplace_back("ratecorr"); - names.emplace_back("trimbits"); - break; - case GOTTHARD: - names.emplace_back("delay"); - break; - case JUNGFRAU: - names.emplace_back("delay"); - names.emplace_back("clkdivider"); - break; - case CHIPTESTBOARD: - names.emplace_back("dac:0"); - names.emplace_back("dac:1"); - names.emplace_back("dac:2"); - names.emplace_back("dac:3"); - names.emplace_back("dac:4"); - names.emplace_back("dac:5"); - names.emplace_back("dac:6"); - names.emplace_back("dac:7"); - names.emplace_back("dac:8"); - names.emplace_back("dac:9"); - names.emplace_back("dac:10"); - names.emplace_back("dac:11"); - names.emplace_back("dac:12"); - names.emplace_back("dac:13"); - names.emplace_back("dac:14"); - names.emplace_back("dac:15"); - names.emplace_back("dac:16"); - names.emplace_back("dac:17"); - names.emplace_back("dac:18"); - names.emplace_back("dac:19"); - names.emplace_back("dac:20"); - names.emplace_back("dac:21"); - names.emplace_back("dac:22"); - names.emplace_back("dac:23"); - names.emplace_back("adcvpp"); - names.emplace_back("adcclk"); - names.emplace_back("clkdivider"); - names.emplace_back("adcphase"); - names.emplace_back("adcpipeline"); - names.emplace_back("adcinvert"); // - names.emplace_back("adcdisable"); - names.emplace_back("patioctrl"); - names.emplace_back("patclkctrl"); - names.emplace_back("patlimits"); - names.emplace_back("patloop0"); - names.emplace_back("patnloop0"); - names.emplace_back("patwait0"); - names.emplace_back("patwaittime0"); - names.emplace_back("patloop1"); - names.emplace_back("patnloop1"); - names.emplace_back("patwait1"); - names.emplace_back("patwaittime1"); - names.emplace_back("patloop2"); - names.emplace_back("patnloop2"); - names.emplace_back("patwait2"); - names.emplace_back("patwaittime2"); - break; - default: - break; - } - - // Workaround to bo able to suplly ecexuteLine with char** - const int n_arguments = 1; - char buffer[1000]; // TODO! this should not be hardcoded! - char *args[n_arguments] = {buffer}; - - std::string outfname; - if (level == 2) { - writeConfigurationFile(fname + ".config"); - outfname = fname + ".det"; - } else { - outfname = fname; - } - - std::ofstream outfile; - outfile.open(outfname.c_str(), std::ios_base::out); - if (outfile.is_open()) { - auto cmd = slsDetectorCommand(this); - for (auto &name : names) { - sls::strcpy_safe(buffer, name.c_str()); // this is... - outfile << name << " " - << cmd.executeLine(n_arguments, args, GET_ACTION) - << std::endl; - } - outfile.close(); - } else { - throw RuntimeError("Error opening parameters file " + fname + - " for writing"); - } - - FILE_LOG(logDEBUG1) << "wrote " << names.size() << " lines to " - << outfname; - return OK; -} void multiSlsDetector::registerAcquisitionFinishedCallback( void (*func)(double, int, void *), void *pArg) { @@ -3455,10 +3055,10 @@ void multiSlsDetector::registerDataCallback( int multiSlsDetector::setTotalProgress() { int nf = Parallel(&slsDetector::setTimer, {}, FRAME_NUMBER, -1) .tsquash("Inconsistent number of frames"); - int nc = Parallel(&slsDetector::setTimer, {}, CYCLES_NUMBER, -1) - .tsquash("Inconsistent number of cycles"); + int nc = Parallel(&slsDetector::setTimer, {}, TRIGGER_NUMBER, -1) + .tsquash("Inconsistent number of triggers"); if (nf == 0 || nc == 0) { - throw RuntimeError("Number of frames or cycles is 0"); + throw RuntimeError("Number of frames or triggers is 0"); } int ns = 1; @@ -3520,8 +3120,8 @@ int multiSlsDetector::acquire() { // verify receiver is idle if (receiver) { - if (getReceiverStatus() != IDLE) { - stopReceiver(); + if (Parallel(&slsDetector::getReceiverStatus, {}).squash(ERROR) != IDLE) { + Parallel(&slsDetector::stopReceiver, {}); } } setTotalProgress(); @@ -3535,16 +3135,20 @@ int multiSlsDetector::acquire() { // start receiver if (receiver) { - startReceiver(); + Parallel(&slsDetector::startReceiver, {}); // let processing thread listen to these packets sem_post(&sem_newRTAcquisition); } - startAndReadAll(); + // start and read all + if (getDetectorTypeAsEnum() == EIGER) { + Parallel(&slsDetector::prepareAcquisition, {}); + } + Parallel(&slsDetector::startAndReadAll, {}); // stop receiver if (receiver) { - stopReceiver(); + Parallel(&slsDetector::stopReceiver, {}); if (dataReady != nullptr) { sem_wait(&sem_endRTAcquisition); // waits for receiver's } @@ -3560,7 +3164,12 @@ int multiSlsDetector::acquire() { dataProcessingThread.join(); if (acquisition_finished != nullptr) { - acquisition_finished(getCurrentProgress(), getRunStatus(), + // same status for all, else error + int status = static_cast(ERROR); + auto t = Parallel(&slsDetector::getRunStatus, {}); + if (t.equal()) + status = t.front(); + acquisition_finished(getCurrentProgress(), status, acqFinished_p); } @@ -3597,7 +3206,7 @@ void multiSlsDetector::processData() { if (fgetc(stdin) == 'q') { FILE_LOG(logINFO) << "Caught the command to stop acquisition"; - stopAcquisition(); + Parallel(&slsDetector::stopAcquisition, {}); } } // get progress diff --git a/slsDetectorSoftware/src/multiSlsDetectorClient.cpp b/slsDetectorSoftware/src/multiSlsDetectorClient.cpp index 9a1b7b455..e1b1e8b59 100644 --- a/slsDetectorSoftware/src/multiSlsDetectorClient.cpp +++ b/slsDetectorSoftware/src/multiSlsDetectorClient.cpp @@ -30,7 +30,7 @@ void multiSlsDetectorClient::runCommand() { action_ = slsDetectorDefs::HELP_ACTION; bool verify = true; bool update = true; - if (action_ == slsDetectorDefs::PUT_ACTION && parser.n_arguments() == 0) { + if (action_ == slsDetectorDefs::PUT_ACTION && parser.command().empty()) { os << "Wrong usage - should be: " << parser.executable() << "[id-][pos:]channel arg" << std::endl; os << std::endl; @@ -77,8 +77,9 @@ void multiSlsDetectorClient::runCommand() { return; } } + if (parser.detector_id() >= static_cast(detPtr->size())) { - os << "position is out of bounds.\n"; + os << "position " << parser.detector_id() << " is out of bounds (max " << detPtr->size() << ").\n"; return; } diff --git a/slsDetectorSoftware/src/slsDetector.cpp b/slsDetectorSoftware/src/slsDetector.cpp index 760cd34b0..11680460e 100755 --- a/slsDetectorSoftware/src/slsDetector.cpp +++ b/slsDetectorSoftware/src/slsDetector.cpp @@ -7,6 +7,8 @@ #include "sls_detector_exceptions.h" #include "string_utils.h" #include "versionAPI.h" +#include "ToString.h" + #include #include #include @@ -324,7 +326,7 @@ void slsDetector::initializeDetectorStructure(detectorType type) { shm()->timerValue[ACQUISITION_TIME] = 0; shm()->timerValue[FRAME_PERIOD] = 0; shm()->timerValue[DELAY_AFTER_TRIGGER] = 0; - shm()->timerValue[CYCLES_NUMBER] = 1; + shm()->timerValue[TRIGGER_NUMBER] = 1; shm()->timerValue[ACTUAL_TIME] = 0; shm()->timerValue[MEASUREMENT_TIME] = 0; shm()->timerValue[PROGRESS] = 0; @@ -419,34 +421,34 @@ int slsDetector::sendModule(sls_detector_module *myMod, n = client.Send(&(myMod->nchan), sizeof(myMod->nchan)); ts += n; FILE_LOG(level) << "nchan sent. " << n - << " bytes. serialno: " << myMod->nchan; + << " bytes. nchan: " << myMod->nchan; n = client.Send(&(myMod->nchip), sizeof(myMod->nchip)); ts += n; FILE_LOG(level) << "nchip sent. " << n - << " bytes. serialno: " << myMod->nchip; + << " bytes. nchip: " << myMod->nchip; n = client.Send(&(myMod->ndac), sizeof(myMod->ndac)); ts += n; FILE_LOG(level) << "ndac sent. " << n - << " bytes. serialno: " << myMod->ndac; + << " bytes. ndac: " << myMod->ndac; n = client.Send(&(myMod->reg), sizeof(myMod->reg)); ts += n; - FILE_LOG(level) << "reg sent. " << n << " bytes. serialno: " << myMod->reg; + FILE_LOG(level) << "reg sent. " << n << " bytes. reg: " << myMod->reg; n = client.Send(&(myMod->iodelay), sizeof(myMod->iodelay)); ts += n; FILE_LOG(level) << "iodelay sent. " << n - << " bytes. serialno: " << myMod->iodelay; + << " bytes. iodelay: " << myMod->iodelay; n = client.Send(&(myMod->tau), sizeof(myMod->tau)); ts += n; - FILE_LOG(level) << "tau sent. " << n << " bytes. serialno: " << myMod->tau; + FILE_LOG(level) << "tau sent. " << n << " bytes. tau: " << myMod->tau; n = client.Send(&(myMod->eV), sizeof(myMod->eV)); ts += n; - FILE_LOG(level) << "ev sent. " << n << " bytes. serialno: " << myMod->eV; + FILE_LOG(level) << "ev sent. " << n << " bytes. ev: " << myMod->eV; n = client.Send(myMod->dacs, sizeof(int) * (myMod->ndac)); ts += n; @@ -548,7 +550,7 @@ slsDetectorDefs::detectorType slsDetector::getDetectorTypeAsEnum() const { } std::string slsDetector::getDetectorTypeAsString() const { - return slsDetectorDefs::detectorTypeToString(getDetectorTypeAsEnum()); + return ToString(getDetectorTypeAsEnum()); } void slsDetector::updateNumberOfChannels() { @@ -695,8 +697,8 @@ bool slsDetector::lockServer(int lock) { return (retval == 1 ? true : false); } -std::string slsDetector::getLastClientIP() { - char retval[INET_ADDRSTRLEN]{}; +sls::IpAddr slsDetector::getLastClientIP() { + sls::IpAddr retval = 0u; FILE_LOG(logDEBUG1) << "Getting last client ip to detector server"; sendToDetector(F_GET_LAST_CLIENT_IP, nullptr, retval); FILE_LOG(logDEBUG1) << "Last client IP to detector: " << retval; @@ -728,8 +730,8 @@ void slsDetector::updateCachedDetectorVariables() { FORCE_UPDATE) { int n = 0, i32 = 0; int64_t i64 = 0; - char lastClientIP[INET_ADDRSTRLEN] = {0}; - n += client.Receive(lastClientIP, sizeof(lastClientIP)); + sls::IpAddr lastClientIP = 0u; + n += client.Receive(&lastClientIP, sizeof(lastClientIP)); FILE_LOG(logDEBUG1) << "Updating detector last modified by " << lastClientIP; @@ -787,9 +789,9 @@ void slsDetector::updateCachedDetectorVariables() { shm()->timerValue[STORAGE_CELL_DELAY] = i64; } - // cycles + // triggers n += client.Receive(&i64, sizeof(i64)); - shm()->timerValue[CYCLES_NUMBER] = i64; + shm()->timerValue[TRIGGER_NUMBER] = i64; // readout mode if (shm()->myDetectorType == CHIPTESTBOARD) { @@ -934,7 +936,7 @@ slsDetector::setSettings(detectorSettings isettings) { return shm()->currentSettings; default: std::ostringstream ss; - ss << "Unknown settings " << getDetectorSettings(isettings) + ss << "Unknown settings " << ToString(isettings) << " for this detector!"; throw RuntimeError(ss.str()); } @@ -1088,7 +1090,7 @@ std::string slsDetector::getTrimbitFilename(detectorSettings s, int e_eV) { break; default: std::ostringstream ss; - ss << "Unknown settings " << getDetectorSettings(s) + ss << "Unknown settings " << ToString(s) << " for this detector!"; throw RuntimeError(ss.str()); } @@ -1146,7 +1148,7 @@ slsDetectorDefs::runStatus slsDetector::getRunStatus() const { runStatus retval = ERROR; FILE_LOG(logDEBUG1) << "Getting status"; sendToDetectorStop(F_GET_RUN_STATUS, nullptr, retval); - FILE_LOG(logDEBUG1) << "Detector status: " << runStatusType(retval); + FILE_LOG(logDEBUG1) << "Detector status: " << ToString(retval); return retval; } @@ -1202,116 +1204,6 @@ void slsDetector::readAll() { FILE_LOG(logDEBUG1) << "Detector successfully finished reading all frames"; } -/* -void slsDetector::configureMAC() { - int fnum = F_CONFIGURE_MAC; - const size_t array_size = 50; - const size_t n_args = 14; - const size_t n_retvals = 2; - char args[n_args][array_size]{}; - char retvals[n_retvals][array_size]{}; - FILE_LOG(logDEBUG1) << "Configuring MAC"; - if (shm()->rxUDPIP == 0) { - // If hostname is valid ip use that, oterwise lookup hostname - shm()->rxUDPIP = shm()->rxHostname; - if (shm()->rxUDPIP == 0) { - shm()->rxUDPIP = HostnameToIp(shm()->rxHostname); - } - } - - if (shm()->rxUDPMAC == 0) { - throw RuntimeError( - "configureMAC: Error. Receiver UDP MAC Addresses not set"); - } - FILE_LOG(logDEBUG1) << "rx_hostname and rx_udpmac are valid "; - - // Jungfrau second interface - if (shm()->numUDPInterfaces == 2) { - if (shm()->rxUDPIP2 == 0) { - shm()->rxUDPIP2 = shm()->rxUDPIP; - } - if (shm()->rxUDPMAC2 == 0) { - throw RuntimeError( - "configureMAC: Error. Receiver UDP MAC Addresses 2 not set"); - } - FILE_LOG(logDEBUG1) << "rx_udpmac2 is valid "; - } - - // copy to args and convert to hex - snprintf(args[0], array_size, "%x", shm()->rxUDPPort); - sls::strcpy_safe(args[1], getReceiverUDPIP().hex()); - sls::strcpy_safe(args[2], getReceiverUDPMAC().hex()); - sls::strcpy_safe(args[3], getDetectorIP().hex()); - sls::strcpy_safe(args[4], getDetectorMAC().hex()); - snprintf(args[5], array_size, "%x", shm()->rxUDPPort2); - sls::strcpy_safe(args[6], getReceiverUDPIP2().hex()); - sls::strcpy_safe(args[7], getReceiverUDPMAC2().hex()); - sls::strcpy_safe(args[8], getDetectorIP2().hex()); - sls::strcpy_safe(args[9], getDetectorMAC2().hex()); - snprintf(args[10], array_size, "%x", shm()->numUDPInterfaces); - snprintf(args[11], array_size, "%x", shm()->selectedUDPInterface); - - // 2d positions to detector to put into udp header - { - int pos[2] = {0, 0}; - int max = shm()->multiSize.y * (shm()->numUDPInterfaces); - // row - pos[0] = (detId % max); - // col for horiz. udp ports - pos[1] = (detId / max) * ((shm()->myDetectorType == EIGER) ? 2 : 1); - // pos[2] (z is reserved) - FILE_LOG(logDEBUG) << "Detector [" << detId << "] - (" << pos[0] << "," - << pos[1] << ")"; - snprintf(args[12], array_size, "%x", pos[0]); - snprintf(args[13], array_size, "%x", pos[1]); - } - - FILE_LOG(logDEBUG1) << "receiver udp port:" << std::dec << args[0] << "-"; - FILE_LOG(logDEBUG1) << "receiver udp ip:" << args[1] << "-"; - FILE_LOG(logDEBUG1) << "receiver udp mac:" << args[2] << "-"; - FILE_LOG(logDEBUG1) << "detecotor udp ip:" << args[3] << "-"; - FILE_LOG(logDEBUG1) << "detector udp mac:" << args[4] << "-"; - FILE_LOG(logDEBUG1) << "receiver udp port2:" << std::dec << args[5] << "-"; - FILE_LOG(logDEBUG1) << "receiver udp ip2:" << args[6] << "-"; - FILE_LOG(logDEBUG1) << "receiver udp mac2:" << args[7] << "-"; - FILE_LOG(logDEBUG1) << "detecotor udp ip2:" << args[8] << "-"; - FILE_LOG(logDEBUG1) << "detector udp mac2:" << args[9] << "-"; - FILE_LOG(logDEBUG1) << "number of udp interfaces:" << std::dec << args[10] - << "-"; - FILE_LOG(logDEBUG1) << "selected udp interface:" << std::dec << args[11] - << "-"; - FILE_LOG(logDEBUG1) << "row:" << args[12] << "-"; - FILE_LOG(logDEBUG1) << "col:" << args[13] << "-"; - - // send to server - auto client = DetectorSocket(shm()->hostname, shm()->controlPort); - int ret = client.sendCommandThenRead(fnum, args, sizeof(args), retvals, - sizeof(retvals)); - - // TODO!(Erik) Send as int already from detector - uint64_t detector_mac = 0; - uint32_t detector_ip = 0; - sscanf(retvals[0], "%lx", &detector_mac); - sscanf(retvals[1], "%x", &detector_ip); - detector_ip = __builtin_bswap32(detector_ip); - - if (shm()->detectorMAC != detector_mac) { - shm()->detectorMAC = detector_mac; - FILE_LOG(logINFO) << detId << ": Detector MAC updated to " - << getDetectorMAC(); - } - - if (shm()->detectorIP != detector_ip) { - shm()->detectorIP = detector_ip; - FILE_LOG(logINFO) << detId << ": Detector IP updated to " - << getDetectorIP(); - } - if (ret == FORCE_UPDATE) { - updateCachedDetectorVariables(); - } -} -*/ - void slsDetector::setStartingFrameNumber(uint64_t value) { FILE_LOG(logDEBUG1) << "Setting starting frame number to " << value; sendToDetector(F_SET_STARTING_FRAME_NUMBER, value, nullptr); @@ -1361,7 +1253,7 @@ int64_t slsDetector::setTimer(timerIndex index, int64_t t) { if (shm()->useReceiverFlag) { timerIndex rt[]{FRAME_NUMBER, FRAME_PERIOD, - CYCLES_NUMBER, + TRIGGER_NUMBER, ACQUISITION_TIME, SUBFRAME_ACQUISITION_TIME, SUBFRAME_DEADTIME, @@ -1376,11 +1268,11 @@ int64_t slsDetector::setTimer(timerIndex index, int64_t t) { retval = -1; // rewrite args - if ((index == FRAME_NUMBER) || (index == CYCLES_NUMBER) || + if ((index == FRAME_NUMBER) || (index == TRIGGER_NUMBER) || (index == STORAGE_CELL_NUMBER)) { args[1] = shm()->timerValue[FRAME_NUMBER] * - ((shm()->timerValue[CYCLES_NUMBER] > 0) - ? (shm()->timerValue[CYCLES_NUMBER]) + ((shm()->timerValue[TRIGGER_NUMBER] > 0) + ? (shm()->timerValue[TRIGGER_NUMBER]) : 1) * ((shm()->timerValue[STORAGE_CELL_NUMBER] > 0) ? (shm()->timerValue[STORAGE_CELL_NUMBER]) + 1 @@ -1388,9 +1280,9 @@ int64_t slsDetector::setTimer(timerIndex index, int64_t t) { } FILE_LOG(logDEBUG1) << "Sending " - << (((index == FRAME_NUMBER) || (index == CYCLES_NUMBER) || + << (((index == FRAME_NUMBER) || (index == TRIGGER_NUMBER) || (index == STORAGE_CELL_NUMBER)) - ? "(#Frames) * (#cycles) * (#storage cells)" + ? "(#Frames) * (#triggers) * (#storage cells)" : getTimerType(index)) << " to receiver: " << args[1]; @@ -1630,7 +1522,7 @@ std::string slsDetector::setReceiverHostname(const std::string &receiverIP) { FILE_LOG(logDEBUG) << "detector type:" - << (slsDetectorDefs::detectorTypeToString(shm()->myDetectorType)) + << (ToString(shm()->myDetectorType)) << "\ndetector id:" << detId << "\ndetector hostname:" << shm()->hostname << "\nfile path:" << shm()->rxFilePath @@ -1645,7 +1537,7 @@ std::string slsDetector::setReceiverHostname(const std::string &receiverIP) { << "\noverwrite enable:" << shm()->rxFileOverWrite << "\nframe index needed:" << ((shm()->timerValue[FRAME_NUMBER] * - shm()->timerValue[CYCLES_NUMBER]) > 1) + shm()->timerValue[TRIGGER_NUMBER]) > 1) << "\nframe period:" << (shm()->timerValue[FRAME_PERIOD]) << "\nframe number:" << (shm()->timerValue[FRAME_NUMBER]) << "\nsub exp time:" << (shm()->timerValue[SUBFRAME_ACQUISITION_TIME]) @@ -1745,7 +1637,7 @@ std::string slsDetector::setReceiverHostname(const std::string &receiverIP) { // data streaming setReceiverStreamingFrequency(shm()->rxReadFreq); setReceiverStreamingPort(getReceiverStreamingPort()); - setReceiverStreamingIP(getReceiverStreamingIP()); + updateReceiverStreamingIP(); setAdditionalJsonHeader(shm()->rxAdditionalJsonHeader); enableDataStreamingFromReceiver( static_cast(enableDataStreamingFromReceiver(-1))); @@ -1826,7 +1718,7 @@ sls::IpAddr slsDetector::getSourceUDPIP2() { void slsDetector::setDestinationUDPIP(const IpAddr ip) { FILE_LOG(logDEBUG1) << "Setting destination udp ip to " << ip; - if (ip == 0) { + if (ip == 0) { throw RuntimeError("Invalid destination udp ip address"); } sendToDetector(F_SET_DEST_UDP_IP, ip, nullptr); @@ -2011,31 +1903,23 @@ void slsDetector::setReceiverStreamingPort(int port) { int slsDetector::getReceiverStreamingPort() { return shm()->rxZmqport; } -void slsDetector::setClientStreamingIP(const std::string &sourceIP) { - auto ip = HostnameToIp(sourceIP.c_str()); - if (ip != 0) { - shm()->zmqip = ip; - } else { - throw sls::RuntimeError("Could not set zmqip"); - } +void slsDetector::setClientStreamingIP(const sls::IpAddr ip) { + FILE_LOG(logDEBUG1) << "Setting client zmq ip to " << ip; + if (ip == 0) { + throw RuntimeError("Invalid client zmq ip address"); + } + shm()->zmqip = ip; } -std::string slsDetector::getClientStreamingIP() { return shm()->zmqip.str(); } +sls::IpAddr slsDetector::getClientStreamingIP() { return shm()->zmqip; } -void slsDetector::setReceiverStreamingIP(std::string sourceIP) { - // if empty, give rx_hostname - if (sourceIP.empty() || sourceIP == "0.0.0.0") { - if (strcmp(shm()->rxHostname, "none") == 0) { - throw RuntimeError("Receiver hostname not set yet. Cannot create " - "rx_zmqip from none"); - } - sourceIP = shm()->rxHostname; +void slsDetector::setReceiverStreamingIP(const sls::IpAddr ip) { + FILE_LOG(logDEBUG1) << "Setting rx zmq ip to " << ip; + if (ip == 0) { + throw RuntimeError("Invalid receiver zmq ip address"); } - - FILE_LOG(logDEBUG1) << "Sending receiver streaming IP to receiver: " - << sourceIP; - shm()->rxZmqip = HostnameToIp(sourceIP.c_str()); - + shm()->rxZmqip = ip; + // if zmqip is empty, update it if (shm()->zmqip == 0) { shm()->zmqip = shm()->rxZmqip; @@ -2043,19 +1927,27 @@ void slsDetector::setReceiverStreamingIP(std::string sourceIP) { // send to receiver if (shm()->useReceiverFlag) { - char retvals[MAX_STR_LENGTH]{}; - char args[MAX_STR_LENGTH]{}; - sls::strcpy_safe(args, shm()->rxZmqip.str()); // TODO send int FILE_LOG(logDEBUG1) - << "Sending receiver streaming IP to receiver: " << args; - sendToReceiver(F_RECEIVER_STREAMING_SRC_IP, args, retvals); - FILE_LOG(logDEBUG1) << "Receiver streaming ip: " << retvals; - shm()->rxZmqip = retvals; + << "Sending receiver streaming IP to receiver: " << ip; + sendToReceiver(F_RECEIVER_STREAMING_SRC_IP, ip, nullptr); } } -std::string slsDetector::getReceiverStreamingIP() { - return shm()->rxZmqip.str(); +sls::IpAddr slsDetector::getReceiverStreamingIP() { + return shm()->rxZmqip; +} + +void slsDetector::updateReceiverStreamingIP() { + auto ip = getReceiverStreamingIP(); + if (ip == 0) { + // Hostname could be ip try to decode otherwise look up the hostname + ip = shm()->rxHostname; + if (ip == 0) { + ip = HostnameToIp(shm()->rxHostname); + } + FILE_LOG(logINFO) << "Setting default receiver streaming zmq ip to " << ip; + } + setReceiverStreamingIP(ip); } int slsDetector::setDetectorNetworkParameter(networkParameter index, @@ -2834,8 +2726,8 @@ int slsDetector::lockReceiver(int lock) { return retval; } -std::string slsDetector::getReceiverLastClientIP() const { - char retval[INET_ADDRSTRLEN]{}; +sls::IpAddr slsDetector::getReceiverLastClientIP() const { + sls::IpAddr retval = 0u; FILE_LOG(logDEBUG1) << "Getting last client ip to receiver server"; if (shm()->useReceiverFlag) { sendToReceiver(F_GET_LAST_RECEIVER_CLIENT_IP, nullptr, retval); @@ -2871,12 +2763,13 @@ void slsDetector::updateCachedReceiverVariables() const { sls::ClientSocket("Receiver", shm()->rxHostname, shm()->rxTCPPort); receiver.sendCommandThenRead(fnum, nullptr, 0, nullptr, 0); int n = 0, i32 = 0; + int64_t i64 = 0; char cstring[MAX_STR_LENGTH]{}; - char lastClientIP[INET_ADDRSTRLEN]{}; + IpAddr ip = 0u; - n += receiver.Receive(lastClientIP, sizeof(lastClientIP)); + n += receiver.Receive(&ip, sizeof(ip)); FILE_LOG(logDEBUG1) - << "Updating receiver last modified by " << lastClientIP; + << "Updating receiver last modified by " << ip; // filepath n += receiver.Receive(cstring, sizeof(cstring)); @@ -2887,8 +2780,8 @@ void slsDetector::updateCachedReceiverVariables() const { sls::strcpy_safe(shm()->rxFileName, cstring); // index - n += receiver.Receive(&i32, sizeof(i32)); - shm()->rxFileIndex = i32; + n += receiver.Receive(&i64, sizeof(i64)); + shm()->rxFileIndex = i64; // file format n += receiver.Receive(&i32, sizeof(i32)); @@ -2931,8 +2824,8 @@ void slsDetector::updateCachedReceiverVariables() const { shm()->rxZmqport = i32; // streaming source ip - n += receiver.Receive(cstring, sizeof(cstring)); - shm()->rxZmqip = cstring; + n += receiver.Receive(&ip, sizeof(ip)); + shm()->rxZmqip = ip; // additional json header n += receiver.Receive(cstring, sizeof(cstring)); @@ -3102,9 +2995,9 @@ slsDetectorDefs::fileFormat slsDetector::getFileFormat() const { return shm()->rxFileFormat; } -int slsDetector::setFileIndex(int file_index) { +int64_t slsDetector::setFileIndex(int64_t file_index) { if (F_SET_RECEIVER_FILE_INDEX >= 0) { - int retval = -1; + int64_t retval = -1; FILE_LOG(logDEBUG1) << "Setting file index to " << file_index; if (shm()->useReceiverFlag) { sendToReceiver(F_SET_RECEIVER_FILE_INDEX, file_index, retval); @@ -3115,9 +3008,9 @@ int slsDetector::setFileIndex(int file_index) { return getFileIndex(); } -int slsDetector::getFileIndex() const { return shm()->rxFileIndex; } +int64_t slsDetector::getFileIndex() const { return shm()->rxFileIndex; } -int slsDetector::incrementFileIndex() { +int64_t slsDetector::incrementFileIndex() { if (shm()->rxFileWrite) { return setFileIndex(shm()->rxFileIndex + 1); } @@ -3143,7 +3036,7 @@ slsDetectorDefs::runStatus slsDetector::getReceiverStatus() const { FILE_LOG(logDEBUG1) << "Getting Receiver Status"; if (shm()->useReceiverFlag) { sendToReceiver(F_GET_RECEIVER_STATUS, nullptr, retval); - FILE_LOG(logDEBUG1) << "Receiver Status: " << runStatusType(retval); + FILE_LOG(logDEBUG1) << "Receiver Status: " << ToString(retval); } return retval; } diff --git a/slsDetectorSoftware/src/slsDetectorCommand.cpp b/slsDetectorSoftware/src/slsDetectorCommand.cpp index d02c54dfc..dcd161d50 100755 --- a/slsDetectorSoftware/src/slsDetectorCommand.cpp +++ b/slsDetectorSoftware/src/slsDetectorCommand.cpp @@ -124,13 +124,6 @@ slsDetectorCommand::slsDetectorCommand(multiSlsDetector *det) { /* digital test and debugging */ - /*! \page test - - imagetest [i] If 1, adds channel intensity with precalculated values. Default is 0. Gotthard only. - */ - descrToFuncMap[i].m_pFuncName = "imagetest"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdDigiTest; - ++i; - /*! \page test - bustest performs test of the bus interface between FPGA and embedded Linux system. Can last up to a few minutes. Cannot set! Jungfrau only. Only get! */ @@ -192,20 +185,6 @@ slsDetectorCommand::slsDetectorCommand(multiSlsDetector *det) { descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdAcquire; ++i; - /*! \page acquisition - - busy i sets/gets acquiring flag. \c 1 the acquisition is active, \c 0 otherwise. Acquire command will set this flag to 1 at the beginning and to 0 at the end. Use this to clear flag if acquisition terminated unexpectedly. \c Returns \c (int) - */ - descrToFuncMap[i].m_pFuncName = "busy"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdStatus; - ++i; - - /*! \page acquisition - - status [s] starts or stops acquisition in detector in non blocking mode. When using stop acquisition and if acquisition is done, it will restream the stop packet from receiver (if data streaming in receiver is on). Eiger can also provide an internal software trigger. \c s: [\c start, \c stop, \c trigger(EIGER only)]. \c Returns the detector status: [\c running, \c error, \c transmitting, \c finished, \c waiting, \c idle]. \c Returns \c (string) - */ - descrToFuncMap[i].m_pFuncName = "status"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdStatus; - ++i; - /*! \page acquisition - \b data gets all data from the detector (if any) processes them and writes them to file according to the preferences already setup (Eigerr store in ram only). Only get! */ @@ -213,13 +192,6 @@ slsDetectorCommand::slsDetectorCommand(multiSlsDetector *det) { descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdData; ++i; - /*! \page acquisition - - resmat i sets/resets counter bit in detector.gets the counter bit in Eiger - */ - descrToFuncMap[i].m_pFuncName = "resmat"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdCounter; - ++i; - /*! \page config Configuration commands Commands to configure the detector. these commands are often left to the configuration file. - \ref configstructure "Data Structure": commands to configure detector data structure @@ -247,13 +219,6 @@ slsDetectorCommand::slsDetectorCommand(multiSlsDetector *det) { descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdFree; ++i; - /*! \page config - - hostname \c put frees shared memory and sets the hostname (or IP adress). Only allowed at multi detector level. \c Returns the list of the hostnames of the multi-detector structure. \c (string) - */ - descrToFuncMap[i].m_pFuncName = "hostname"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdHostname; - ++i; - /*! \page config - virtual [n] [p] \c connects to n virtual detector servers at local host starting at port p \c Returns the list of the hostnames of the multi-detector structure. \c (string) */ @@ -274,12 +239,6 @@ slsDetectorCommand::slsDetectorCommand(multiSlsDetector *det) { commands to configure detector status */ - /*! \page config - - activate [b] [p] Activates/Deactivates the detector. \c b is 1 for activate, 0 for deactivate. Deactivated detector does not send data. \c p is optional and can be padding (default) or nonpadding for receivers for deactivated detectors. Used for EIGER only. \c Returns \c (int) (string) - */ - descrToFuncMap[i].m_pFuncName = "activate"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdOnline; - ++i; /* detector and data size */ /*! \page config @@ -287,62 +246,6 @@ slsDetectorCommand::slsDetectorCommand(multiSlsDetector *det) { commands to configure detector data size */ - /*! \page config - - dr [i] sets/gets the dynamic range of detector. Eiger [4,8,16,32]. Others cannot put! \c Returns \c (int) - */ - descrToFuncMap[i].m_pFuncName = "dr"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdDetectorSize; - ++i; - - /*! \page config - - clearroi resets region of interest of the detector. Used for GOTTHARD only. \c Returns \c (string) - */ - descrToFuncMap[i].m_pFuncName = "clearroi"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdDetectorSize; - ++i; - - /*! \page config - - roi [xmin] [xmax] sets region of interest of the detector. Used for GOTTHARD only. \c Returns \c (int) - */ - descrToFuncMap[i].m_pFuncName = "roi"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdDetectorSize; - ++i; - - /*! \page config - - detsizechan [xmax] [ymax] sets the maximum number of channels in each dimension for complete detector set; 0 is no limit. Use for multi-detector system as first command in config file. \c Returns \c ("int int") - */ - descrToFuncMap[i].m_pFuncName = "detsizechan"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdDetectorSize; - ++i; - - /*! \page config - - quad [i] if 1, sets the detector size to a quad (Specific to an EIGER quad hardware). 0 by default. \c Returns \c (int) - */ - descrToFuncMap[i].m_pFuncName="quad"; // - descrToFuncMap[i].m_pFuncPtr=&slsDetectorCommand::cmdDetectorSize; - ++i; - - - /*! \page config - - flippeddatax [i] enables/disables data being flipped across x axis. 1 enables, 0 disables. Used for EIGER only. 1 for bottom half-module, 0 for top-half module. \c Returns \c (int) - */ - descrToFuncMap[i].m_pFuncName = "flippeddatax"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdDetectorSize; - ++i; - - /*! \page config - - tengiga [i] enables/disables 10GbE in system (detector & receiver). 1 enabled 10GbE, 0 enables 1GbE. Used in EIGER, Moench and ChipTestBoard only. \c Returns \c (int) - */ - descrToFuncMap[i].m_pFuncName = "tengiga"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdReceiver; - ++i; - - /*! \page config - - gappixels [i] enables/disables gap pixels in system (detector & receiver). 1 sets, 0 unsets. Used in EIGER only and only in multi detector level command. \c Returns \c (int) - */ - descrToFuncMap[i].m_pFuncName = "gappixels"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdDetectorSize; - ++i; /* flags */ /*! \page config @@ -350,34 +253,6 @@ slsDetectorCommand::slsDetectorCommand(multiSlsDetector *det) { commands to configure detector flags */ - /*! \page config - - romode [b] sets/gets the readout flag. Options: analog, digital, analog_digital. Used for CTB only. \c Returns \c (int) - */ - descrToFuncMap[i].m_pFuncName = "romode"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdAdvanced; - ++i; - - /*! \page config - - interruptsubframe [i] sets/gets the interrupt subframe flag. Setting it to 1 will interrupt the last subframe at the required exposure time. By default, this is disabled and set to 0, ie. it will wait for the last sub frame to finish exposing. Used for EIGER in 32 bit mode only. \c Returns \c (int). - */ - descrToFuncMap[i].m_pFuncName="interruptsubframe"; - descrToFuncMap[i].m_pFuncPtr=&slsDetectorCommand::cmdAdvanced; - ++i; - - /*! \page config - - readnlines [i] sets/gets the number of rows to read out per half module. Options: 1 - 256 (Not all values as it depends on dynamic range and 10GbE enabled). Used for EIGER only. \c Returns \c (int) - */ - descrToFuncMap[i].m_pFuncName = "readnlines"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdAdvanced; - ++i; - - /*! \page config - - extsig [flag] sets/gets the mode of the external signal. Options: \c trigger_in_rising_edge, \c trigger_in_falling_edge. Used in GOTTHARDonly. \c Returns \c (string) - */ - descrToFuncMap[i].m_pFuncName = "extsig"; /* find command! */ - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdAdvanced; - ++i; - /* fpga */ /*! \page config @@ -421,55 +296,6 @@ slsDetectorCommand::slsDetectorCommand(multiSlsDetector *det) { commands to configure chip of the detector */ - /*! \page config - - powerchip [i] Powers on/off the chip. 1 powers on, 0 powers off. Can also get the power status. Used for JUNGFRAU only. \c Returns \c (int) - */ - descrToFuncMap[i].m_pFuncName = "powerchip"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdAdvanced; - ++i; - - /*! \page config - - led [i] sets/gets the led status. 1 on, 0 off. Used for MOENCH only ?? \c Returns \c (int) - */ - descrToFuncMap[i].m_pFuncName = "led"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdAdvanced; - ++i; - - /*! \page config - - diodelay [i] [v] sets the delay for the digital IO pins selected by mask i and delay set by v. mask is upto 64 bits in hex, delay is a max is 775ps, and set in steps of 25 ps. Used for MOENCH/CTB only. Cannot get. \c Returns \c ("successful", failed") - */ - descrToFuncMap[i].m_pFuncName = "diodelay"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdAdvanced; - ++i; - - /*! \page config - - auto_comp_disable i Currently not implemented. this mode disables the on-chip gain switching comparator automatically after 93.75% of exposure time (only for longer than 100us). 1 enables mode, 0 disables mode. By default, mode is disabled (comparator is enabled throughout). (JUNGFRAU only). \c Returns \c (int) - */ - descrToFuncMap[i].m_pFuncName = "auto_comp_disable"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdAdvanced; - ++i; - - /*! \page config - - pulse [n] [x] [y] pulses pixel at coordinates (x,y) n number of times. Used in EIGER only. Only put! \c Returns \c ("successful", "failed") - */ - descrToFuncMap[i].m_pFuncName = "pulse"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdPulse; - ++i; - - /*! \page config - - pulsenmove [n] [x] [y] pulses pixel n number of times and moves relatively by x value (x axis) and y value(y axis). Used in EIGER only. Only put! \c Returns \c ("successful", "failed") - */ - descrToFuncMap[i].m_pFuncName = "pulsenmove"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdPulse; - ++i; - - /*! \page config - - pulsechip [n]pulses chip n number of times, while n=-1 will reset it to normal mode. Used in EIGER only. Only put! \c Returns \c ("successful", "failed") - */ - descrToFuncMap[i].m_pFuncName = "pulsechip"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdPulse; - ++i; - /* versions/ serial numbers getId */ /*! \page config \section configversions Versions @@ -490,166 +316,13 @@ slsDetectorCommand::slsDetectorCommand(multiSlsDetector *det) { descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdSN; ++i; - /*! \page config - - detectornumber Gets the serial number or MAC of detector. Only get! \c Returns \c (long int) in hexadecimal - */ - descrToFuncMap[i].m_pFuncName = "detectornumber"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdSN; - ++i; - - /*! \page config - - detectorversion Gets the firmware version of detector. Only get! \c Returns \c (long int) in hexadecimal - */ - descrToFuncMap[i].m_pFuncName = "detectorversion"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdSN; - ++i; - - /*! \page config - - softwareversion Gets the software version of detector server. Only get! \c Returns \c (long int) in hexadecimal - */ - descrToFuncMap[i].m_pFuncName = "softwareversion"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdSN; - ++i; - - /*! \page config - - thisversion Gets the software version of this client software. Only get! \c Returns \c (long int) in hexadecimal - */ - descrToFuncMap[i].m_pFuncName = "thisversion"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdSN; - ++i; - - /*! \page config - - rx_version Gets the software version of receiver. Only get! \c Returns \c (long int) in hexadecimal - */ - descrToFuncMap[i].m_pFuncName = "rx_version"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdSN; - ++i; - + /* r/w timers */ - /*! \page timing - - timing [mode] sets/gets synchronization mode of the detector. Mode: auto, trigger, ro_trigger, gating, triggered_gating (string) - */ - descrToFuncMap[i].m_pFuncName = "timing"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdTiming; - ++i; - - /*! \page timing - - subdeadtime [i] sets/gets sub frame dead time in s. Subperiod is set in the detector = subexptime + subdeadtime. This value is normally a constant in the config file. Used in EIGER only in 32 bit mode. \c Returns \c (double with 9 decimal digits) - */ - descrToFuncMap[i].m_pFuncName = "subdeadtime"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdTimer; - ++i; - - /*! \page timing - - delay [i] sets/gets delay in s. Used in GOTTHARD only. \c Returns \c (double with 9 decimal digits) - */ - descrToFuncMap[i].m_pFuncName = "delay"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdTimer; - ++i; - - - /*! \page timing - - startingfnum [i] sets/gets starting frame number for the next acquisition. Only for Jungfrau and Eiger. \c Returns \c (long long int) - */ - descrToFuncMap[i].m_pFuncName = "startingfnum"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdTimer; - ++i; - - /*! \page timing - - cycles [i] sets/gets number of triggers. Timing mode should be set appropriately. \c Returns \c (long long int) - */ - descrToFuncMap[i].m_pFuncName = "cycles"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdTimer; - ++i; - - /*! \page timing - - samples [i] sets/gets number of samples (both analog and digital) expected from the ctb. Used in CHIP TEST BOARD and MOENCH only. \c Returns \c (long long int) - */ - descrToFuncMap[i].m_pFuncName = "samples"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdTimer; - ++i; - - /*! \page timing - - asamples [i] sets/gets number of analog samples expected from the ctb. Used in CHIP TEST BOARD and MOENCH only. \c Returns \c (long long int) - */ - descrToFuncMap[i].m_pFuncName = "asamples"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdTimer; - ++i; - - /*! \page timing - - dsamples [i] sets/gets number of digital samples expected from the ctb. Used in CHIP TEST BOARD and MOENCH only. \c Returns \c (long long int) - */ - descrToFuncMap[i].m_pFuncName = "dsamples"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdTimer; - ++i; - - /*! \page timing - - storagecells [i] sets/gets number of additional storage cells per acquisition. For very advanced users only! For JUNGFRAU only. Range: 0-15. The #images = #frames * #cycles * (#storagecells +1). \c Returns \c (long long int) - */ - descrToFuncMap[i].m_pFuncName = "storagecells"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdTimer; - ++i; - - /*! \page timing - - storagecell_start [i] sets/gets the storage cell that stores the first acquisition of the series. Default is 15(0xf).. For very advanced users only! For JUNGFRAU only. Range: 0-15. \c Returns \c (int) - */ - descrToFuncMap[i].m_pFuncName = "storagecell_start"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdTimer; - ++i; - - /*! \page timing - - storagecell_start [i] sets/gets the storage cell that stores the first acquisition of the series. Default is 15(0xf).. For very advanced users only! For JUNGFRAU only. Range: 0-15. \c Returns \c (int) - */ - descrToFuncMap[i].m_pFuncName = "storagecell_start"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdTimer; - ++i; - - /*! \page timing - - storagecell_delay [i] sets/gets additional time between 2 storage cells. For very advanced users only! For JUNGFRAU only. Range: 0-1638375 ns (resolution of 25ns). \c Returns \c (int) - */ - descrToFuncMap[i].m_pFuncName = "storagecell_delay"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdTimer; - ++i; /* read only timers */ - /*! \page timing - - exptimel gets exposure time left. Used in GOTTHARD only. Only get! \c Returns \c (double with 9 decimal digits) - */ - descrToFuncMap[i].m_pFuncName = "exptimel"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdTimeLeft; - ++i; - - /*! \page timing - - periodl gets frame period left. Used in GOTTHARD and Jungfrau only. Only get! \c Returns \c (double with 9 decimal digits) - */ - descrToFuncMap[i].m_pFuncName = "periodl"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdTimeLeft; - ++i; - - /*! \page timing - - delayl gets delay left. Used in GOTTHARD, JUNGFRAU, MOENCH and CTB only. Only get! \c Returns \c (double with 9 decimal digits) - */ - descrToFuncMap[i].m_pFuncName = "delayl"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdTimeLeft; - ++i; - - /*! \page config - - framesl gets number of frames left. Used in GOTTHARD and Jungfrau only. Only get! \c Returns \c (long long int) - */ - descrToFuncMap[i].m_pFuncName = "framesl"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdTimeLeft; - ++i; - - /*! \page timing - - cyclesl gets number of cylces left. Used in GOTTHARD and Jungfrau only. Only get! \c Returns \c (long long int) - */ - descrToFuncMap[i].m_pFuncName = "cyclesl"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdTimeLeft; - ++i; - - /*! \page timing + /*! \page timing - now Getting actual time of the detector from start. For Jungfrau only. Only get! */ descrToFuncMap[i].m_pFuncName = "now"; @@ -670,19 +343,6 @@ slsDetectorCommand::slsDetectorCommand(multiSlsDetector *det) { descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdTimeLeft; ++i; - /*! \page timing - - measuredperiod gets the measured frame period (time between last frame and the previous one) in s. For Eiger only. Makes sense only for acquisitions of more than 1 frame. \c Returns \c (double with 9 decimal digits) - */ - descrToFuncMap[i].m_pFuncName = "measuredperiod"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdTimeLeft; - ++i; - - /*! \page timing - - measuredsubperiod gets the measured subframe period (time between last subframe and the previous one) in s. For Eiger only and in 32 bit mode. \c Returns \c (double with 9 decimal digits) - */ - descrToFuncMap[i].m_pFuncName = "measuredsubperiod"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdTimeLeft; - ++i; /* speed */ /*! \page config @@ -690,75 +350,6 @@ slsDetectorCommand::slsDetectorCommand(multiSlsDetector *det) { commands to configure speed of detector */ - /*! \page config - - clkdivider [i] sets/gets the readout clock divider. EIGER, JUNGFRAU [0(fast speed), 1(half speed), 2(quarter speed)]. Jungfrau also overwrites adcphase to recommended default. For CTB, it is the run clock in MHz. Not for Gotthard. \c Returns \c (int) - */ - descrToFuncMap[i].m_pFuncName = "clkdivider"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdSpeed; - ++i; - - /*! \page config - - adcclk [i] sets/gets the ADC clock frequency in MHz. CTB & Moench only. \c Returns \c (int) - */ - descrToFuncMap[i].m_pFuncName = "adcclk"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdSpeed; - ++i; - - /*! \page config - - dbitclk [i] Sets/gets the clock frequency of the latching of the digital bits in MHz. CTB & Moench only. \c Returns \c (int) - */ - descrToFuncMap[i].m_pFuncName = "dbitclk"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdSpeed; - ++i; - - /*! \page config - - syncclk Gets the clock frequency of the sync clock in MHz. CTB & Moench only. Get only. \c Returns \c (int) - */ - descrToFuncMap[i].m_pFuncName = "syncclk"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdSpeed; - ++i; - - /*! \page config - - adcphase [i] [deg] Sets/gets phase of the ADC clock to i. i is the shift or in degrees if deg is used. deg is optional & only for CTB, Moench and Jungfrau. For CTB & Moench, adcphase is reset if adcclk is changed. For Jungfrau, adcphase changed to defaults if clkdivider changed. Jungfrau, CTB & Moench, these are absolute values with limits. Gotthard, relative phase shift. Not for Eiger. \c Returns \c (int) - */ - descrToFuncMap[i].m_pFuncName = "adcphase"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdSpeed; - ++i; - - /*! \page config - - dbitphase [i] [deg] Sets/gets phase of the clock for latching of the digital bits to i. i is the shift or in degrees if deg is used. deg is optional. dbitphase is also reset if dbitclk is changed. These are absolute values with limits. for CTB & Moench only.\c Returns \c (int) - */ - descrToFuncMap[i].m_pFuncName = "dbitphase"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdSpeed; - ++i; - - /*! \page config - - maxadcphaseshift Gets maximum phase shift of the ADC clock. CTB, Moench and Jungfrau only. \c Returns \c (int) - */ - descrToFuncMap[i].m_pFuncName = "maxadcphaseshift"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdSpeed; - ++i; - - /*! \page config - - maxdbitphaseshift Gets the maximum phase shift of the clock for latching of the digital bits.\c Returns \c (int) - */ - descrToFuncMap[i].m_pFuncName = "maxdbitphaseshift"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdSpeed; - ++i; - - /*! \page config - - adcpipeline [i] Sets/gets the pipeline of the ADC. For CTB & Moench only. \c Returns \c (int) - */ - descrToFuncMap[i].m_pFuncName = "adcpipeline"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdSpeed; - ++i; - - /*! \page config - - dbitpipeline [i] Sets/gets the pipeline of the latching of the digital bits. For CTB & Moench only. \c Returns \c (int) - */ - descrToFuncMap[i].m_pFuncName = "dbitpipeline"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdSpeed; - ++i; /* settings dump/retrieve */ /*! \page config @@ -766,32 +357,9 @@ slsDetectorCommand::slsDetectorCommand(multiSlsDetector *det) { commands to configure/retrieve configuration of detector */ - /*! \page config - - config [fname] sets/saves detector/receiver to configuration contained in fname. Same as executing sls_detector_put for every line. Normally a one time operation. \c Returns \c (string) fname - */ - descrToFuncMap[i].m_pFuncName = "config"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdConfiguration; - ++i; - /* settings dump/retrieve */ - /*! \page config - - rx_printconfig prints the receiver configuration. Only get! \c Returns \c (string) - */ - descrToFuncMap[i].m_pFuncName = "rx_printconfig"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdConfiguration; - ++i; - /*! \page config - - parameters [fname] sets/saves detector parameters contained in fname. Normally once per different measurement. \c Returns \c (string) fname - */ - descrToFuncMap[i].m_pFuncName = "parameters"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdConfiguration; - ++i; - - /*! \page config - - setup [fname] sets/saves detector complete setup contained in fname (extensions automatically generated), including trimfiles, ff coefficients etc. \c Returns \c (string) fname - */ - descrToFuncMap[i].m_pFuncName = "setup"; + descrToFuncMap[i].m_pFuncName = "config"; descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdConfiguration; ++i; @@ -801,12 +369,6 @@ slsDetectorCommand::slsDetectorCommand(multiSlsDetector *det) { Commands to setup the data processing */ - /*! \page data - - ratecorr [ns] Returns the dead time used for rate correections in ns (int). \c put sets the deadtime correction constant in ns, -1 will set it to default tau of settings (0 unset). \c Returns \c (int). For Eiger only. - */ - descrToFuncMap[i].m_pFuncName = "ratecorr"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdRateCorr; - ++i; /*! \page data // - threaded [i] Sets/gets the data processing threaded flag. 1 is threaded, 0 unthreaded. @@ -830,25 +392,7 @@ slsDetectorCommand::slsDetectorCommand(multiSlsDetector *det) { \section settingsdir Settings, trim & cal Directories commands to setup settings/trim/cal directories */ - /*! \page settings - - settingsdir [dir] Sets/gets the directory where the settings files are located. \c Returns \c (string) dir - */ - descrToFuncMap[i].m_pFuncName = "settingsdir"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdSettingsDir; - ++i; - /*! \page settings - - trimdir [dir] obsolete \c settingsdir. \c Returns \c (string) dir - */ - descrToFuncMap[i].m_pFuncName = "trimdir"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdSettingsDir; - ++i; - /*! \page settings - - trimen [n e0 e1...e(n-1)] Sets/gets the number of energies n at which the detector has default trim file and their values in eV (int). \c Returns \c (int int...) n e0 e1...e(n-1) - */ - descrToFuncMap[i].m_pFuncName = "trimen"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdTrimEn; - ++i; /* settings, threshold */ /*! \page settings @@ -856,28 +400,6 @@ slsDetectorCommand::slsDetectorCommand(multiSlsDetector *det) { commands to configure settings and threshold of detector */ - /*! \page settings - - settings [s] sets/gets the settings of the detector. Options: \c standard, \c fast, \c highgain, \c dynamicgain, \c lowgain, \c mediumgain, \c veryhighgain, - \c dynamichg0, \c fixgain1, \c fixgain2, \c forceswitchg1, \c forceswitchg2. - \n In Eiger, only sets in client shared memory. Use \c threshold or \c thresholdnotb to pass to detector. Gets from detector. \c Returns \c (string) s - */ - descrToFuncMap[i].m_pFuncName = "settings"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdSettings; - ++i; - - /*! \page settings - - threshold [eV] [sett] sets/gets the detector threshold in eV. sett is optional and if provided also sets the settings. Use this for Eiger instead of \c settings. \c Returns \c (int) - */ - descrToFuncMap[i].m_pFuncName = "threshold"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdSettings; - ++i; - - /*! \page settings - - thresholdnotb [eV] [sett] sets/gets the detector threshold in eV without loading trimbits. sett is optional and if provided also sets the settings. Use this for Eiger instead of \c settings. \c Returns \c (int) - */ - descrToFuncMap[i].m_pFuncName = "thresholdnotb"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdSettings; - ++i; /*! \page settings - trimbits [fname] loads/stores the trimbits to/from the detector. If no extension is specified, the serial number of each module will be attached. \c Returns \c (string) fname @@ -955,13 +477,6 @@ slsDetectorCommand::slsDetectorCommand(multiSlsDetector *det) { descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdDAC; ++i; - /*! \page settings - - vhighvoltage [i] Sets/gets the high voltage to the sensor in V. \c Returns \c (int ["mV"]). - */ - descrToFuncMap[i].m_pFuncName = "vhighvoltage"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdDAC; - ++i; - /*! \page settings - vapower [i] Sets/gets the analog power supply for the old chiptest board in DAC units. \c Returns \c (int ["mV"]) */ @@ -1172,62 +687,6 @@ slsDetectorCommand::slsDetectorCommand(multiSlsDetector *det) { descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdDAC; ++i; - /*! \page settings - - adcvpp [i] Sets/gets the Vpp of the ADC 0 -> 1V ; 1 -> 1.14V ; 2 -> 1.33V ; 3 -> 1.6V ; 4 -> 2V . \c Returns \c (int ["mV"]) - */ - descrToFuncMap[i].m_pFuncName = "adcvpp"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdDAC; - ++i; - - /*! \page settings - - v_a [i] mv Sets/gets value for Va on the new chiptest board. Must be in mV. \c Returns \c (int ["mV"]) - */ - descrToFuncMap[i].m_pFuncName = "v_a"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdDAC; - ++i; - - /*! \page settings - - v_b [i] mv Sets/gets value for Vb on the new chiptest board. Must be in mV. \c Returns \c (int ["mV"]) - */ - descrToFuncMap[i].m_pFuncName = "v_b"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdDAC; - ++i; - - /*! \page settings - - v_c [i] mv Sets/gets value for Vc on the new chiptest board. Must be in mV. \c Returns \c (int ["mV"]) - */ - descrToFuncMap[i].m_pFuncName = "v_c"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdDAC; - ++i; - - /*! \page settings - - v_d [i] mv Sets/gets value for Vd on the new chiptest board. Must be in mV. \c Returns \c (int ["mV"]) - */ - descrToFuncMap[i].m_pFuncName = "v_d"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdDAC; - ++i; - - /*! \page settings - - v_io [i] mv Sets/gets value for Vio on the new chiptest board. Must be in mV. It should be minimum 1200 mV and must be the first power regulator to be set after server start up (fpga reset). To change again, reset fpga first. \c Returns \c (int ["mV"]) - */ - descrToFuncMap[i].m_pFuncName = "v_io"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdDAC; - ++i; - - /*! \page settings - - v_chip [i] mv Sets/gets value for Vchip on the new chiptest board. Must be in mV. \c Returns \c (int ["mV"]). Do NOT use it, unless you are completely sure you won't fry the board! - */ - descrToFuncMap[i].m_pFuncName = "v_chip"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdDAC; - ++i; - - /*! \page settings - - v_limit [i] mv Sets/gets a soft limit for the power supplies and the DACs on the new chiptest board. Must be in mV. \c Returns \c (int ["mV"]) - */ - descrToFuncMap[i].m_pFuncName = "v_limit"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdDAC; - ++i; - /*! \page settings - vipre Sets/gets dac for the preamplifier's input transistor current for Mythen3. Normally in DAC units unless \c mv is specified at the end of the command line. \c Returns \c (int ["mV"]) */ @@ -1425,294 +884,15 @@ slsDetectorCommand::slsDetectorCommand(multiSlsDetector *det) { commands to readout ADCs of detector */ - /*! \page settings - - temp_adc Gets the ADC temperature. \c Returns \c EIGER,JUNGFRAU(double"°C") Others \c (int"°C") - */ - descrToFuncMap[i].m_pFuncName = "temp_adc"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdADC; - ++i; - - /*! \page settings - - temp_fpga Gets the FPGA temperature. \c Returns \c EIGER,JUNGFRAU(double"°C") Others \c (int"°C") - */ - descrToFuncMap[i].m_pFuncName = "temp_fpga"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdADC; - ++i; - - /*! \page settings - - temp_fpgaext Gets the external FPGA temperature. Used in EIGER only. \c Returns \c EIGER(double"°C") - */ - descrToFuncMap[i].m_pFuncName = "temp_fpgaext"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdADC; - ++i; - - /*! \page settings - - temp_10ge Gets the 10Gbe temperature. Used in EIGER only. \c Returns \c EIGER(double"°C") - */ - descrToFuncMap[i].m_pFuncName = "temp_10ge"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdADC; - ++i; - - /*! \page settings - - temp_dcdc Gets the temperature of the DC/DC converter. Used in EIGER only. \c Returns \c EIGER(double"°C") - */ - descrToFuncMap[i].m_pFuncName = "temp_dcdc"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdADC; - ++i; - - /*! \page settings - - temp_sodl Gets the temperature of the left so-dimm memory . Used in EIGER only. \c Returns \c EIGER(double"°C") - */ - descrToFuncMap[i].m_pFuncName = "temp_sodl"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdADC; - ++i; - - /*! \page settings - - temp_sodr Gets the temperature of the right so-dimm memory. Used in EIGER only. \c Returns \c EIGER(double"°C") - */ - descrToFuncMap[i].m_pFuncName = "temp_sodr"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdADC; - ++i; - - /*! \page settings - - adc:j Gets the values of the slow ADC number j for the new chiptest board. \c Returns \c (int"°C") - */ - descrToFuncMap[i].m_pFuncName = "adc"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdADC; - ++i; - - /*! \page settings - - temp_fpgal Gets the temperature of the left frontend FPGA. Used in EIGER only. \c Returns \c EIGER(double"°C") - */ - descrToFuncMap[i].m_pFuncName = "temp_fpgafl"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdADC; - ++i; - - /*! \page settings - - temp_fpgar Gets the temperature of the right frontend FPGA. Used in EIGER only. \c Returns \c EIGER(double"°C") - */ - descrToFuncMap[i].m_pFuncName = "temp_fpgafr"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdADC; - ++i; - - /*! \page settings - - i_a Gets the current of the power supply a on the new chiptest board. \c Returns \c (int"mV") - */ - descrToFuncMap[i].m_pFuncName = "i_a"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdADC; - ++i; - - /*! \page settings - - i_b Gets the current of the power supply b on the new chiptest board \c Returns \c (int"mV") - */ - descrToFuncMap[i].m_pFuncName = "i_b"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdADC; - ++i; - - /*! \page settings - - i_c Gets the current of the power supply c on the new chiptest board \c Returns \c (int"mV") - */ - descrToFuncMap[i].m_pFuncName = "i_c"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdADC; - ++i; - - /*! \page settings - - i_d Gets the current of the power supply d on the new chiptest board \c Returns \c (int"mV") - */ - descrToFuncMap[i].m_pFuncName = "i_d"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdADC; - ++i; - - /*! \page settings - - i_io Gets the current of the power supply io on the new chiptest board \c Returns \c (int"mV") - */ - descrToFuncMap[i].m_pFuncName = "i_io"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdADC; - ++i; - - /*! \page settings - - vm_a Gets the measured voltage of the power supply a on the new chiptest board \c Returns \c (int"mV") - */ - descrToFuncMap[i].m_pFuncName = "vm_a"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdADC; - ++i; - - /*! \page settings - - vm_b Gets the measured voltage of the power supply b on the new chiptest board \c Returns \c (int"mV") - */ - descrToFuncMap[i].m_pFuncName = "vm_b"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdADC; - ++i; - - /*! \page settings - - vm_c Gets the measured voltage of the power supply c on the new chiptest board \c Returns \c (int"mV") - */ - descrToFuncMap[i].m_pFuncName = "vm_c"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdADC; - ++i; - - /*! \page settings - - vm_d Gets the measured voltage of the power supply d on the new chiptest board \c Returns \c (int"mV") - */ - descrToFuncMap[i].m_pFuncName = "vm_d"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdADC; - ++i; - - /*! \page settings - - vm_io Gets the measured voltage of the power supply io on the new chiptest board \c Returns \c (int"mV") - */ - descrToFuncMap[i].m_pFuncName = "vm_io"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdADC; - ++i; - - /* temperature control */ - /*! \page settings - \section settingstmp Temp Control - commands to monitor and handle temperature overshoot (only JUNGFRAU) - */ - - /*! \page settings - - temp_threshold Sets/gets the threshold temperature. JUNGFRAU ONLY. \c Returns \c (double"°C") - */ - descrToFuncMap[i].m_pFuncName = "temp_threshold"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdTempControl; - ++i; - - /*! \page settings - - temp_control Enables/Disables the temperature control. 1 enables, 0 disables. JUNGFRAU ONLY. \c Returns \c int - */ - descrToFuncMap[i].m_pFuncName = "temp_control"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdTempControl; - ++i; - - /*! \page settings - - temp_event Resets/gets over-temperative event. Put only with option 0 to clear event. Gets 1 if temperature went over threshold and control is enabled, else 0. /Disables the temperature control. JUNGFRAU ONLY. \c Returns \c int - */ - descrToFuncMap[i].m_pFuncName = "temp_event"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdTempControl; - ++i; - /* file name */ /*! \page output Output settings Commands to setup the file destination and format */ - /*! \page output - - fpath [dir] Sets/gets the file output directory. \c Returns \c (string) - */ - descrToFuncMap[i].m_pFuncName = "fpath"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdOutDir; - ++i; - - /*! \page output - - fname [fn] Sets/gets the root of the output file name \c Returns \c (string) - */ - descrToFuncMap[i].m_pFuncName = "fname"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdFileName; - ++i; - - /*! \page output - - fformat [i] sets/gets the file format for data in receiver. Options: [binary, hdf5]. \c Returns \c (string) - */ - descrToFuncMap[i].m_pFuncName = "fformat"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdFileName; - ++i; /* communication configuration */ - /*! \page network Network - Commands to setup the network between client, detector and receiver - - rx_hostname [s] sets/gets the receiver hostname or IP address, configures detector mac with all network parameters and updates receiver with acquisition parameters. Normally used for single detectors (Can be multi-detector). \c none disables. If used, use as last network command in configuring detector MAC. \c Returns \c (string) - */ - descrToFuncMap[i].m_pFuncName = "rx_hostname"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdNetworkParameter; - ++i; - - /*! \page network - - rx_udpsocksize [size] sets/gets the UDP socket buffer size. Already trying to set by default to 100mb, 2gb for Jungfrau. Does not remember in client shared memory, so must be initialized each time after setting receiver hostname in config file.\c Returns \c (int) - */ - descrToFuncMap[i].m_pFuncName = "rx_udpsocksize"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdNetworkParameter; - ++i; - - /*! \page network - - rx_realudpsocksize [size] gets the actual UDP socket buffer size. Usually double the set udp socket buffer size due to kernel bookkeeping. Get only. \c Returns \c (int) - */ - descrToFuncMap[i].m_pFuncName = "rx_realudpsocksize"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdNetworkParameter; - ++i; - - /*! \page network - - txndelay_left [delay] sets/gets the transmission delay of first packet in an image being streamed out from the detector's left UDP port. Use single-detector command. Used for EIGER only. \c Returns \c (int) - */ - descrToFuncMap[i].m_pFuncName = "txndelay_left"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdNetworkParameter; - ++i; - - /*! \page network - - txndelay_right [delay] sets/gets the transmission delay of first packet in an image being streamed out from the detector's right UDP port. Use single-detector command. Used for EIGER only. \c Returns \c (int) - */ - descrToFuncMap[i].m_pFuncName = "txndelay_right"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdNetworkParameter; - ++i; - - /*! \page network - - txndelay_frame [delay] sets/gets the transmission frame period of entire frame being streamed out from the detector for both ports. Use single-detector command. Used for EIGER and JUNGFRAU only. \c Returns \c (int) - */ - descrToFuncMap[i].m_pFuncName = "txndelay_frame"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdNetworkParameter; - ++i; - - /*! \page network - - flowcontrol_10g [delay] Enables/disables 10 GbE flow control. 1 enables, 0 disables. Used for EIGER and JUNGFRAU only. \c Returns \c (int) - */ - descrToFuncMap[i].m_pFuncName = "flowcontrol_10g"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdNetworkParameter; - ++i; - - /*! \page network - - zmqport [port] sets/gets the 0MQ (TCP) port of the client to where final data is streamed to (eg. for GUI). The default already connects with rx_zmqport for the GUI. Use single-detector command to set individually or multi-detector command to calculate based on \c port for the rest. Must restart zmq client streaming in gui/external gui \c Returns \c (int) - */ - descrToFuncMap[i].m_pFuncName = "zmqport"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdNetworkParameter; - ++i; - - /*! \page network - - rx_zmqport [port] sets/gets the 0MQ (TCP) port of the receiver from where data is streamed from (eg. to GUI or another process for further processing). Use single-detector command to set individually or multi-detector command to calculate based on \c port for the rest. put restarts streaming in receiver with new port. \c Returns \c (int) - */ - descrToFuncMap[i].m_pFuncName = "rx_zmqport"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdNetworkParameter; - ++i; - - /*! \page network - - rx_datastream enables/disables data streaming from receiver. 1 enables 0MQ data stream from receiver (creates streamer threads), while 0 disables (destroys streamer threads). Switching to Gui enables data streaming in receiver and switching back to command line acquire will require disabling data streaming in receiver for fast applications \c Returns \c (int) - */ - descrToFuncMap[i].m_pFuncName = "rx_datastream"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdDataStream; - ++i; - - /*! \page network - - zmqip [ip] sets/gets the 0MQ (TCP) ip of the client to where final data is streamed to (eg. for GUI). For Experts only! Default is ip of rx_hostname and works for GUI. This command to change from default can be used from command line when sockets are not already open as the command line is not aware/create the 0mq sockets in the client side. This is usually used to stream in from an external process. . If no custom ip, empty until first time connect to receiver. \c Returns \c (string) - */ - descrToFuncMap[i].m_pFuncName = "zmqip"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdNetworkParameter; - i++; - - /*! \page network - - rx_zmqip [ip] sets/gets the 0MQ (TCP) ip of the receiver from where data is streamed from (eg. to GUI or another process for further processing). For Experts only! Default is ip of rx_hostname and works for GUI. This is usually used to stream out to an external process for further processing. . If no custom ip, empty until first time connect to receiver. \c Returns \c (string) - */ - descrToFuncMap[i].m_pFuncName = "rx_zmqip"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdNetworkParameter; - i++; - - /*! \page network - - rx_tcpport [port] sets/gets the port of the client-receiver TCP interface. Use single-detector command. Is different for each detector if same \c rx_hostname used. Must be first command to communicate with receiver. \c Returns \c (int) - */ - descrToFuncMap[i].m_pFuncName = "rx_tcpport"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdPort; - ++i; - /*! \page network - port [port] sets/gets the port of the client-detector control server TCP interface. Use single-detector command. Default value is 1952 for all detectors. Normally not changed. \c Returns \c (int) */ @@ -1727,12 +907,6 @@ slsDetectorCommand::slsDetectorCommand(multiSlsDetector *det) { descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdPort; ++i; - /*! \page network - - lastclient Gets the last client communicating with the detector. Cannot put!. \c Returns \c (string) - */ - descrToFuncMap[i].m_pFuncName = "lastclient"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdLastClient; - ++i; /* receiver functions */ @@ -1740,19 +914,6 @@ slsDetectorCommand::slsDetectorCommand(multiSlsDetector *det) { Commands to configure the receiver. */ - /*! \page receiver - - rx_status [s] starts/stops the receiver to listen to detector packets. Options: [ \c start, \c stop]. \c Returns \c (string) status of receiver[ \c idle, \c running]. - */ - descrToFuncMap[i].m_pFuncName = "rx_status"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdReceiver; - ++i; - - /*! \page receiver - - framescaught gets the number of frames caught by receiver. Average of all for multi-detector command. Only get! \c Returns \c (int) - */ - descrToFuncMap[i].m_pFuncName = "framescaught"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdReceiver; - ++i; /*! \page receiver - resetframescaught [i] resets the number of frames caught to 0. i can be any number. Use this if using status start, instead of acquire (this command is included). Only put! \c Returns \c (int) @@ -1768,27 +929,6 @@ slsDetectorCommand::slsDetectorCommand(multiSlsDetector *det) { descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdReceiver; ++i; - /*! \page receiver - - rx_lastclient gets the last client communicating with the receiver. Only get! \c Returns \c (int) - */ - descrToFuncMap[i].m_pFuncName = "rx_lastclient"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdLastClient; - ++i; - - /*! \page receiver - - rx_framesperfile [i] sets/gets the frames per file in receiver to i. 0 means infinite or all frames in a single file. \c Returns \c (int) - */ - descrToFuncMap[i].m_pFuncName = "rx_framesperfile"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdReceiver; - ++i; - - /*! \page receiver - - rx_discardpolicy sets/gets the frame discard policy in the receiver. nodiscard (default) - discards nothing, discardempty - discard only empty frames, discardpartial(fastest) - discards all partial frames. \c Returns \c (int) - */ - descrToFuncMap[i].m_pFuncName = "rx_discardpolicy"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdReceiver; - ++i; - /*! \page receiver - rx_jsonaddheader [t] sets/gets additional json header to be streamed out with the zmq from receiver. Default is empty. \c t must be in the format "\"label1\":\"value1\",\"label2\":\"value2\"" etc. Use only if it needs to be processed by an intermediate process. \c Returns \c (string) */ @@ -1838,88 +978,6 @@ slsDetectorCommand::slsDetectorCommand(multiSlsDetector *det) { descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdProcessor; ++i; - /*! \page prototype - - adcenable [mask] Sets/gets ADC enable mask (8 digits hex format) - */ - descrToFuncMap[i].m_pFuncName = "adcenable"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdPattern; - ++i; - - /** not documenting this, but keeping this for backwards compatibility */ - descrToFuncMap[i].m_pFuncName = "adcdisable"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdPattern; - ++i; - - /*! \page prototype - - adcinvert [mask] Sets/gets ADC inversion mask (8 digits hex format) CTB or Moench only - */ - descrToFuncMap[i].m_pFuncName = "adcinvert"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdPattern; - ++i; - - /*! \page prototype - - extsamplingsrc [i] sets/gets the sampling source signal for digital data. \ci must be between 0 and 63. Advanced! CTB only \Returns (int) - */ - descrToFuncMap[i].m_pFuncName = "extsamplingsrc"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdPattern; - ++i; - - /*! \page prototype - - extsampling [i] enables/disables the external sampling signal to the \c samplingsrc signal for digital data. Advanced! CTB only \Returns (int) - */ - descrToFuncMap[i].m_pFuncName = "extsampling"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdPattern; - ++i; - - /*! \page prototype - - rx_dbitlist [i] sets/gets the list of digital signal bits required for chip in receiver. If set to "all", then all digital bits are enabled. Advanced! CTB only \Returns (string) - */ - descrToFuncMap[i].m_pFuncName = "rx_dbitlist"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdPattern; - ++i; - - /*! \page prototype - - rx_dbitoffset [i] sets/gets the offset in bytes in receiver of digital data from chip in receiver. Advanced! CTB only \Returns (int) - */ - descrToFuncMap[i].m_pFuncName = "rx_dbitoffset"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdPattern; - ++i; - - /*! \page prototype - - pattern fn loads binary pattern file fn - */ - descrToFuncMap[i].m_pFuncName = "pattern"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdPattern; - ++i; - - /*! \page prototype - - savepattern fn save pattern to file (ascii). This also executes the pattern. - */ - descrToFuncMap[i].m_pFuncName = "savepattern"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdPattern; - ++i; - - /*! \page prototype - - patword addr [word] sets/gets 64 bit word at address addr of pattern memory. Both address and word in hex format. Advanced! - */ - descrToFuncMap[i].m_pFuncName = "patword"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdPattern; - ++i; - - /*! \page prototype - - patioctrl [word] sets/gets 64 bit mask defining input (0) and output (1) signals. hex format. - */ - descrToFuncMap[i].m_pFuncName = "patioctrl"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdPattern; - ++i; - - /*! \page prototype - - patclkctrl [word] sets/gets 64 bit mask defining if output signal is a clock and runs. hex format. Unused at the moment. - */ - descrToFuncMap[i].m_pFuncName = "patclkctrl"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdPattern; - ++i; - /*! \page prototype - patlimits [addr1 addr2] sets/gets the start and stop limits of the pattern to be executed. hex format. Advanced! */ @@ -2040,7 +1098,6 @@ slsDetectorCommand::slsDetectorCommand(multiSlsDetector *det) { //----------------------------------------------------------- std::string slsDetectorCommand::executeLine(int narg, const char * const args[], int action, int detPos) { - if (action == READOUT_ACTION) return cmdAcquire(narg, args, action, detPos); @@ -2173,87 +1230,6 @@ std::string slsDetectorCommand::helpData(int action) { return std::string("data \t gets all data from the detector (if any) processes them and writes them to file according to the preferences already setup\n"); } -std::string slsDetectorCommand::cmdStatus(int narg, const char * const args[], int action, int detPos) { - -#ifdef VERBOSE - std::cout << std::string("Executing command ") + std::string(args[0]) + std::string(" ( ") + cmd + std::string(" )\n"); -#endif - - if (action == HELP_ACTION) - return helpStatus(action); - - if (cmd == "status") { - if (action == PUT_ACTION) { - //myDet->setThreadedProcessing(0); - if (std::string(args[1]) == "start") - myDet->startAcquisition(detPos); - else if (std::string(args[1]) == "stop") { - myDet->stopAcquisition(detPos); - } else if (std::string(args[1]) == "trigger") { - myDet->sendSoftwareTrigger(detPos); - } else - return std::string("unknown action"); - } - runStatus s = myDet->getRunStatus(detPos); - return myDet->runStatusType(s); - } else if (cmd == "busy") { - if (action == PUT_ACTION) { - int i; - if (!sscanf(args[1], "%d", &i)) - return std::string("cannot parse busy mode"); - myDet->setAcquiringFlag(i); - } - char answer[100]; - sprintf(answer, "%d", myDet->getAcquiringFlag()); - return std::string(answer); - } else - return std::string("cannot scan command ") + std::string(cmd); -} - -std::string slsDetectorCommand::helpStatus(int action) { - - std::ostringstream os; - if (action == GET_ACTION || action == HELP_ACTION) { - os << std::string("status \t gets the detector status - can be: running, error, transmitting, finished, waiting or idle\n"); - os << std::string("busy \t gets the status of acquire- can be: 0 or 1. 0 for idle, 1 for running\n"); - } - if (action == PUT_ACTION || action == HELP_ACTION) { - os << std::string("status \t controls the detector acquisition - can be start or stop or trigger(EIGER only). When using stop acquisition and if acquisition is done, it will restream the stop packet from receiver (if data streaming in receiver is on). Eiger can also provide an internal software trigger\n"); - os << std::string("busy i\t sets the status of acquire- can be: 0(idle) or 1(running).Command Acquire sets it to 1 at beignning of acquire and back to 0 at the end. Clear Flag for unexpected acquire terminations. \n"); - } - return os.str(); -} - -std::string slsDetectorCommand::cmdDataStream(int narg, const char * const args[], int action, int detPos) { - -#ifdef VERBOSE - std::cout << std::string("Executing command ") + std::string(args[0]) + std::string(" ( ") + cmd + std::string(" )\n"); -#endif - int ival = -1; - char ans[100] = ""; - - if (action == HELP_ACTION) - return helpDataStream(HELP_ACTION); - - if (action == PUT_ACTION) { - if (!sscanf(args[1], "%d", &ival)) - return std::string("cannot scan rx_datastream mode"); - myDet->enableDataStreamingFromReceiver(ival, detPos); - } - - sprintf(ans, "%d", myDet->enableDataStreamingFromReceiver(-1, detPos)); - return std::string(ans); -} - -std::string slsDetectorCommand::helpDataStream(int action) { - - std::ostringstream os; - if (action == GET_ACTION || action == HELP_ACTION) - os << std::string("rx_datastream \t enables/disables data streaming from receiver. 1 is 0MQ data stream from receiver enabled, while 0 is 0MQ disabled. -1 for inconsistency between multiple receivers. \n"); - if (action == PUT_ACTION || action == HELP_ACTION) - os << std::string("rx_datastream i\t enables/disables data streaming from receiver. i is 1 enables 0MQ data stream from receiver (creates streamer threads), while 0 disables (destroys streamer threads). \n"); - return os.str(); -} std::string slsDetectorCommand::cmdFree(int narg, const char * const args[], int action, int detPos) { @@ -2286,18 +1262,7 @@ std::string slsDetectorCommand::cmdHostname(int narg, const char * const args[], "multiDetector level"); } - char hostname[1000]; - strcpy(hostname, ""); - // if each argument is a hostname - for (int id = 1; id < narg; ++id) { - strcat(hostname, args[id]); - if (narg > 2) - strcat(hostname, "+"); - } - if (cmd == "hostname") { - myDet->setHostname(hostname, detPos); - } - else if (cmd == "virtual") { + if (cmd == "virtual") { int port = -1; int numDetectors = 0; if (!sscanf(args[1], "%d", &numDetectors)) { @@ -2316,12 +1281,8 @@ std::string slsDetectorCommand::cmdHostname(int narg, const char * const args[], std::string slsDetectorCommand::helpHostname(int action) { std::ostringstream os; - if (action == GET_ACTION || action == HELP_ACTION) { - os << std::string("hostname \t returns the hostname(s) of the multi detector structure.\n"); - } + if (action == PUT_ACTION || action == HELP_ACTION) { - os << std::string("hostname name [name name]\t frees shared memory and " - "sets the hostname (or IP adress). Only allowed at multi detector level.\n"); os << std::string("virtual [n] [p]\t connects to n virtual detector servers at local host starting at port p \n"); } return os.str(); @@ -2408,145 +1369,8 @@ std::string slsDetectorCommand::helpExitServer(int action) { return os.str(); } -std::string slsDetectorCommand::cmdSettingsDir(int narg, const char * const args[], int action, int detPos) { -#ifdef VERBOSE - std::cout << std::string("Executing command ") + std::string(args[0]) + std::string(" ( ") + cmd + std::string(" )\n"); -#endif - if (action == HELP_ACTION) { - return helpSettingsDir(action); - } - if (action == PUT_ACTION) { - myDet->setSettingsDir(std::string(args[1]), detPos); - } - if (myDet->getSettingsDir(detPos) == "") - return std::string("undefined"); - return myDet->getSettingsDir(detPos); -} - -std::string slsDetectorCommand::helpSettingsDir(int action) { - std::ostringstream os; - if (action == GET_ACTION || action == HELP_ACTION) - os << std::string("settingsdir \t gets the directory where the settings files are located\n"); - if (action == PUT_ACTION || action == HELP_ACTION) - os << std::string("settingsdir dir \t sets the directory where the settings files are located\n"); - if (action == GET_ACTION || action == HELP_ACTION) - os << std::string("trimdir \t obsolete for settingsdir\n"); - if (action == PUT_ACTION || action == HELP_ACTION) - os << std::string("trimdir dir \t obsolete for settingsdir\n"); - return os.str(); -} - -std::string slsDetectorCommand::cmdTrimEn(int narg, const char * const args[], int action, int detPos) { - std::vector energies; - if (action == HELP_ACTION) - return helpTrimEn(action); - - if (action == PUT_ACTION) { - energies.reserve(narg-1); - for(int i=1; i!=narg; ++i){ - energies.push_back(std::stoi(args[i])); - } - myDet->setTrimEn(energies, detPos); - energies.clear(); - } - energies = myDet->getTrimEn(detPos); - std::ostringstream os; - for(const auto& en : energies){ - os << en << ' '; - } - return os.str(); -} - -std::string slsDetectorCommand::helpTrimEn(int action) { - - std::ostringstream os; - if (action == PUT_ACTION || action == HELP_ACTION) - os << "trimen ne [e0 e1...ene] \t sets the number of energies at which the detector has default trim files" << std::endl; - if (action == GET_ACTION || action == HELP_ACTION) - os << "trimen \t returns the number of energies at which the detector has default trim files and their values" << std::endl; - return os.str(); -} - -std::string slsDetectorCommand::cmdOutDir(int narg, const char * const args[], int action, int detPos) { - if (action == HELP_ACTION) - return helpOutDir(action); - - else if (action == PUT_ACTION) - myDet->setFilePath(std::string(args[1]), detPos); - - return std::string(myDet->getFilePath(detPos)); -} - -std::string slsDetectorCommand::helpOutDir(int action) { - std::ostringstream os; - if (action == GET_ACTION || action == HELP_ACTION) - os << std::string("fpath \t gets the directory where the output files will be written\n"); - if (action == PUT_ACTION || action == HELP_ACTION) - os << std::string("fpath dir \t sets the directory where the output files will be written\n"); - return os.str(); -} - -std::string slsDetectorCommand::cmdFileName(int narg, const char * const args[], int action, int detPos) { - if (action == HELP_ACTION) - return helpFileName(action); - if (cmd == "fname") { - if (action == PUT_ACTION) - myDet->setFileName(std::string(args[1]), detPos); - - return std::string(myDet->getFileName(detPos)); - } else if (cmd == "fformat") { - if (action == PUT_ACTION) { - if (std::string(args[1]) == "binary") - myDet->setFileFormat(BINARY, detPos); - else if (std::string(args[1]) == "hdf5") - myDet->setFileFormat(HDF5, detPos); - else - return std::string("could not scan file format mode\n"); - } - return myDet->fileFormats(myDet->getFileFormat(detPos)); - } - return std::string("unknown command") + cmd; -} - -std::string slsDetectorCommand::helpFileName(int action) { - std::ostringstream os; - if (action == GET_ACTION || action == HELP_ACTION) { - os << std::string("fname \t gets the filename for the data without index and extension\n"); - os << std::string("fformat \t gets the file format for data\n"); - } - if (action == PUT_ACTION || action == HELP_ACTION) { - os << std::string("fname s \t sets the filename for the data (index and extension will be automatically appended)\n"); - os << std::string("fformat s \t sets the file format for the data (binary, hdf5)\n"); - } - return os.str(); -} -std::string slsDetectorCommand::cmdRateCorr(int narg, const char * const args[], int action, int detPos) { - - if (action == HELP_ACTION) { - return helpRateCorr(action); - } - int64_t ival; - char answer[1000]; - - - if (action == PUT_ACTION) { - sscanf(args[1], "%ld", &ival); - myDet->setRateCorrection(ival, detPos); - } - sprintf(answer, "%ld", myDet->getRateCorrection(detPos)); - return std::string(answer); -} - -std::string slsDetectorCommand::helpRateCorr(int action) { - std::ostringstream os; - if (action == GET_ACTION || action == HELP_ACTION) - os << std::string("ratecorr \t returns the dead time used for rate correections in ns \n"); - if (action == PUT_ACTION || action == HELP_ACTION) - os << std::string("ratecorr ns \t sets the deadtime correction constant in ns, -1 in Eiger will set it to default tau of settings\n"); - return os.str(); -} // std::string slsDetectorCommand::cmdThreaded(int narg, const char * const args[], int action, int detPos){ // int ival; @@ -2574,193 +1398,7 @@ std::string slsDetectorCommand::helpThreaded(int action) { return os.str(); } -std::string slsDetectorCommand::cmdCounter(int narg, const char * const args[], int action, int detPos) { - int ival; - char answer[100]; - std::string sval; - int retval = FAIL; - if (action == HELP_ACTION) - return helpCounter(HELP_ACTION); - else if (action == PUT_ACTION) - ival = atoi(args[1]); - if (std::string(args[0]) == std::string("resmat")) { - if (action == PUT_ACTION) { - if (!sscanf(args[1], "%d", &ival)) - return std::string("Could not scan resmat input ") + std::string(args[1]); - if (ival >= 0) - sprintf(answer, "%d", myDet->setCounterBit(ival, detPos)); - } else - sprintf(answer, "%d", myDet->setCounterBit(-1, detPos)); - return std::string(answer); - } - - if (retval == OK) - return std::string("Counter set/reset succesfully"); - else - return std::string("Counter read/reset failed"); -} - -std::string slsDetectorCommand::helpCounter(int action) { - std::ostringstream os; - os << std::endl; - if (action == PUT_ACTION || action == HELP_ACTION) { - os << "resmat i \t sets/resets counter bit in detector" << std::endl; - } - if (action == GET_ACTION || action == HELP_ACTION) { - os << "resmat i \t gets the counter bit in detector" << std::endl; - } - return os.str(); -} - -std::string slsDetectorCommand::cmdNetworkParameter(int narg, const char * const args[], int action, int detPos) { - - char ans[100] = {0}; - int i; - if (action == HELP_ACTION) - return helpNetworkParameter(action); - - if (cmd == "rx_hostname") { - if (action == PUT_ACTION) { - myDet->setReceiverHostname(args[1], detPos); - } - return myDet->getReceiverHostname(detPos); - } else if (cmd == "rx_udpsocksize") { - if (action == PUT_ACTION) { - int64_t ival = -1; - if (!(sscanf(args[1], "%ld", &ival))) { - return ("cannot parse argument") + std::string(args[1]); - } - myDet->setReceiverUDPSocketBufferSize(ival, detPos); - } - sprintf(ans, "%ld", myDet->getReceiverUDPSocketBufferSize(detPos)); - return ans; - } else if (cmd == "rx_realudpsocksize") { - if (action == PUT_ACTION) { - return ("cannot put!"); - } - sprintf(ans, "%ld", myDet->getReceiverRealUDPSocketBufferSize(detPos)); - return ans; - } else if (cmd == "txndelay_left") { - networkParameter t = DETECTOR_TXN_DELAY_LEFT; - if (action == PUT_ACTION) { - if (!(sscanf(args[1], "%d", &i))) { - return ("cannot parse argument") + std::string(args[1]); - } - myDet->setDetectorNetworkParameter(t, i, detPos); - } - sprintf(ans, "%d", myDet->setDetectorNetworkParameter(t, -1, detPos)); - return ans; - } else if (cmd == "txndelay_right") { - networkParameter t = DETECTOR_TXN_DELAY_RIGHT; - if (action == PUT_ACTION) { - if (!(sscanf(args[1], "%d", &i))) { - return ("cannot parse argument") + std::string(args[1]); - } - myDet->setDetectorNetworkParameter(t, i, detPos); - } - sprintf(ans, "%d", myDet->setDetectorNetworkParameter(t, -1, detPos)); - return ans; - } else if (cmd == "txndelay_frame") { - networkParameter t = DETECTOR_TXN_DELAY_FRAME; - if (action == PUT_ACTION) { - if (!(sscanf(args[1], "%d", &i))) { - return ("cannot parse argument") + std::string(args[1]); - } - myDet->setDetectorNetworkParameter(t, i, detPos); - } - sprintf(ans, "%d", myDet->setDetectorNetworkParameter(t, -1, detPos)); - return ans; - } else if (cmd == "flowcontrol_10g") { - networkParameter t = FLOW_CONTROL_10G; - if (action == PUT_ACTION) { - if (!(sscanf(args[1], "%d", &i))) { - return ("cannot parse argument") + std::string(args[1]); - } - myDet->setDetectorNetworkParameter(t, i, detPos); - } - sprintf(ans, "%d", myDet->setDetectorNetworkParameter(t, -1, detPos)); - return ans; - } else if (cmd == "zmqport") { - if (action == PUT_ACTION) { - if (!(sscanf(args[1], "%d", &i))) { - return ("cannot parse argument") + std::string(args[1]); - } - myDet->setClientDataStreamingInPort(i, detPos); - } - sprintf(ans, "%d", myDet->getClientStreamingPort(detPos)); - return ans; - } else if (cmd == "rx_zmqport") { - if (action == PUT_ACTION) { - if (!(sscanf(args[1], "%d", &i))) { - return ("cannot parse argument") + std::string(args[1]); - } - myDet->setReceiverDataStreamingOutPort(i, detPos); - } - sprintf(ans, "%d", myDet->getReceiverStreamingPort(detPos)); - return ans; - } else if (cmd == "zmqip") { - if (action == PUT_ACTION) { - myDet->setClientDataStreamingInIP(args[1], detPos); - } - return myDet->getClientStreamingIP(detPos); - } else if (cmd == "rx_zmqip") { - if (action == PUT_ACTION) { - myDet->setReceiverDataStreamingOutIP(args[1], detPos); - } - return myDet->getReceiverStreamingIP(detPos); - } - - return ("unknown network parameter") + cmd; -} - -std::string slsDetectorCommand::helpNetworkParameter(int action) { - - std::ostringstream os; - if (action == PUT_ACTION || action == HELP_ACTION) { - - os << "rx_hostname name \n sets receiver ip/hostname to name" << std::endl; - os << "txndelay_left port \n sets detector transmission delay of the left port" << std::endl; - os << "txndelay_right port \n sets detector transmission delay of the right port" << std::endl; - os << "txndelay_frame port \n sets detector transmission delay of the entire frame" << std::endl; - os << "flowcontrol_10g port \n sets flow control for 10g for eiger and jungfrau" << std::endl; - os << "zmqport port \n sets the 0MQ (TCP) port of the client to where final data is streamed to (eg. for GUI). The default already connects with rx_zmqport for the GUI. " - "Use single-detector command to set individually or multi-detector command to calculate based on port for the rest." - "Must restart streaming in client with new port from gui/external gui" - << std::endl; - os << "rx_zmqport port \n sets the 0MQ (TCP) port of the receiver from where data is streamed from (eg. to GUI or another process for further processing). " - "Use single-detector command to set individually or multi-detector command to calculate based on port for the rest." - "Restarts streaming in receiver with new port" - << std::endl; - os << "zmqip ip \n sets the 0MQ (TCP) ip of the client to where final data is streamed to (eg. for GUI). Default is ip of rx_hostname and works for GUI. " - "This is usually used to stream in from an external process." - "Must restart streaming in client with new port from gui/external gui. " - << std::endl; - os << "rx_zmqip ip \n sets/gets the 0MQ (TCP) ip of the receiver from where data is streamed from (eg. to GUI or another process for further processing). " - "Default is ip of rx_hostname and works for GUI. This is usually used to stream out to an external process for further processing." - "restarts streaming in receiver with new port" - << std::endl; - os << "rx_udpsocksize [t]\n sets the UDP socket buffer size. Different defaults for Jungfrau. " - "Does not remember in client shared memory, " - "so must be initialized each time after setting receiver " - "hostname in config file." - << std::endl; - } - if (action == GET_ACTION || action == HELP_ACTION) { - os << "rx_hostname \n gets receiver ip " << std::endl; - os << "txndelay_left \n gets detector transmission delay of the left port" << std::endl; - os << "txndelay_right \n gets detector transmission delay of the right port" << std::endl; - os << "txndelay_frame \n gets detector transmission delay of the entire frame" << std::endl; - os << "flowcontrol_10g \n gets flow control for 10g for eiger and jungfrau" << std::endl; - os << "zmqport \n gets the 0MQ (TCP) port of the client to where final data is streamed to" << std::endl; - os << "rx_zmqport \n gets the 0MQ (TCP) port of the receiver from where data is streamed from" << std::endl; - os << "zmqip \n gets the 0MQ (TCP) ip of the client to where final data is streamed to.If no custom ip, empty until first time connect to receiver" << std::endl; - os << "rx_zmqip \n gets/gets the 0MQ (TCP) ip of the receiver from where data is streamed from. If no custom ip, empty until first time connect to receiver" << std::endl; - os << "rx_udpsocksize \n gets the UDP socket buffer size." << std::endl; - os << "rx_realudpsocksize \n gets the actual UDP socket buffer size. Usually double the set udp socket buffer size due to kernel bookkeeping." << std::endl; - } - return os.str(); -} std::string slsDetectorCommand::cmdPort(int narg, const char * const args[], int action, int detPos) { @@ -2779,10 +1417,6 @@ std::string slsDetectorCommand::cmdPort(int narg, const char * const args[], int if (action == PUT_ACTION) myDet->setControlPort(val, detPos); sprintf(ans, "%d", myDet->setControlPort(-1, detPos)); - } else if (cmd == "rx_tcpport") { - if (action == PUT_ACTION) - myDet->setReceiverPort(val, detPos); - sprintf(ans, "%d", myDet->setReceiverPort(-1, detPos)); } else if (cmd == "stopport") { if (action == PUT_ACTION) myDet->setStopPort(val, detPos); @@ -2798,209 +1432,16 @@ std::string slsDetectorCommand::helpPort(int action) { std::ostringstream os; if (action == PUT_ACTION || action == HELP_ACTION) { os << "port i \n sets the communication control port" << std::endl; - os << "rx_tcpport i \n sets the communication receiver port" << std::endl; os << "stopport i \n sets the communication stop port " << std::endl; } if (action == GET_ACTION || action == HELP_ACTION) { os << "port \n gets the communication control port" << std::endl; - os << "rx_tcpport \n gets the communication receiver port" << std::endl; os << "stopport \n gets the communication stop port " << std::endl; } return os.str(); } -std::string slsDetectorCommand::cmdLastClient(int narg, const char * const args[], int action, int detPos) { - if (action == HELP_ACTION) - return helpLastClient(action); - - if (action == PUT_ACTION) - return std::string("cannot set"); - - if (cmd == "lastclient") { - return myDet->getLastClientIP(detPos); - } - - else if (cmd == "rx_lastclient") { - return myDet->getReceiverLastClientIP(detPos); - } - - return std::string("cannot decode command"); -} - -std::string slsDetectorCommand::helpLastClient(int action) { - - std::ostringstream os; - if (action == GET_ACTION || action == HELP_ACTION) { - os << "lastclient \n returns the last client communicating with the detector" << std::endl; - os << "rx_lastclient \n returns the last client communicating with the receiver" << std::endl; - } - return os.str(); -} - -std::string slsDetectorCommand::cmdOnline(int narg, const char * const args[], int action, int detPos) { - - if (action == HELP_ACTION) { - return helpOnline(action); - } - int ival; - char ans[1000]; - - if (cmd == "activate") { - - if (action == PUT_ACTION) { - if (!sscanf(args[1], "%d", &ival)) - return std::string("Could not scan activate mode ") + std::string(args[1]); - myDet->activate(ival, detPos); - bool padding = true; - if (narg > 2) { - if (std::string(args[2]) == "padding") - padding = true; - else if (std::string(args[2]) == "nopadding") - padding = false; - else - return std::string("Could not scan activate mode's padding option " + std::string(args[2])); - myDet->setDeactivatedRxrPaddingMode(padding, detPos); - } - } - int ret = myDet->setDeactivatedRxrPaddingMode(-1, detPos); - sprintf(ans, "%d %s", myDet->activate(-1, detPos), ret == 1 ? "padding" : (ret == 0 ? "nopadding" : "unknown")); - } else { - return std::string("unknown command"); - } - - return ans; -} - -std::string slsDetectorCommand::helpOnline(int action) { - - std::ostringstream os; - if (action == PUT_ACTION || action == HELP_ACTION) { - os << "activate i [p]\n sets the detector in activated (1) or deactivated (0) mode (does not send data). p is optional and can be padding (default) or nonpadding for receivers for deactivated detectors. Only for Eiger." << std::endl; - } - if (action == GET_ACTION || action == HELP_ACTION) { - os << "activate \n gets the detector activated (1) or deactivated (0) mode. And padding or nonpadding for the deactivated receiver. Only for Eiger." << std::endl; - } - return os.str(); -} - - -std::string slsDetectorCommand::cmdDetectorSize(int narg, const char * const args[], int action, int detPos) { - - if (action == HELP_ACTION) - return helpDetectorSize(action); - int ret, val = -1; - char ans[1000]; - - - if (action == PUT_ACTION) { - if (cmd != "roi" && !sscanf(args[1], "%d", &val)) - return std::string("could not scan ") + std::string(args[0]) + std::string(" ") + std::string(args[1]); - - if (cmd == "clearroi") { - myDet->clearROI(detPos); - } - - if (cmd == "roi") { - //debug number of arguments - if (narg != 3) - return helpDetectorSize(action); - ROI roi; - if (!sscanf(args[1], "%d", &roi.xmin)) - return std::string("cannot parse arguments for roi xmin"); - if (!sscanf(args[2], "%d", &roi.xmax)) - return std::string("cannot parse arguments for roi xmax"); - myDet->setROI(roi, detPos); - } - - if (cmd == "detsizechan") { - int val2 = 0; - if ((!sscanf(args[1], "%d", &val)) || (narg <= 2) || (!sscanf(args[2], "%d", &val2))) { - return std::string("Could not scan det size chan values"); - } - slsDetectorDefs::xy res; - res.x = val; - res.y = val2; - myDet->setNumberOfChannels(res); - } - - if(cmd=="quad"){ - if (val >=0 ) { - myDet->setQuad(val); - } - } - - if (cmd == "flippeddatax") { - if ((!sscanf(args[1], "%d", &val)) || (val != 0 && val != 1)) - return std::string("cannot scan flippeddata x mode: must be 0 or 1"); - - myDet->setFlippedDataX(val, detPos); - } - - if (cmd == "gappixels") { - if ((!sscanf(args[1], "%d", &val)) || (val != 0 && val != 1)) - return std::string("cannot scan gappixels mode: must be 0 or 1"); - - if (detPos < 0) // only in multi detector level to update number of channels etc. - myDet->enableGapPixels(val, detPos); - } - } - - if (cmd == "dr") { - ret = myDet->setDynamicRange(val, detPos); - } else if (cmd == "clearroi") { - if (action == GET_ACTION) { - return std::string("Cannot get"); - } - return std::string("successful"); - } else if (cmd == "roi") { - ROI roi = myDet->getROI(detPos); - return (std::string("[") + std::to_string(roi.xmin) + std::string(",") + std::to_string(roi.xmax) + std::string("]")); - } else if (cmd == "detsizechan") { - slsDetectorDefs::xy res = myDet->getNumberOfChannels(); - sprintf(ans, "%d %d", res.x, res.y); - return std::string(ans); - } else if (cmd=="quad") { - return std::to_string(myDet->getQuad()); - } else if (cmd == "flippeddatax") { - ret = myDet->getFlippedDataX(detPos); - } else if (cmd == "gappixels") { - if (detPos >= 0) // only in multi detector level to update number of channels etc. - return std::string("Cannot execute this command from slsDetector level. Please use multiSlsDetector level.\n"); - ret = myDet->enableGapPixels(-1, detPos); - } - - - else - return std::string("unknown command ") + cmd; - - sprintf(ans, "%d", ret); - - return std::string(ans); -} - -std::string slsDetectorCommand::helpDetectorSize(int action) { - - std::ostringstream os; - if (action == PUT_ACTION || action == HELP_ACTION) { - os << "dr i \n sets the dynamic range of the detector" << std::endl; - os << "clearroi \n resets region of interest" << std::endl; - os << "roi xmin xmax \n sets region of interest " << std::endl; - os << "detsizechan x y \n sets the maximum number of channels for complete detector set in both directions; 0 is no limit" << std::endl; - os << "quad i \n if i = 1, sets the detector size to a quad (Specific to an EIGER quad hardware). 0 by default."<< std::endl; - os << "flippeddatax x \n sets if the data should be flipped on the x axis" << std::endl; - os << "gappixels i \n enables/disables gap pixels in system (detector & receiver). 1 sets, 0 unsets. Used in EIGER only and multidetector level." << std::endl; - } - if (action == GET_ACTION || action == HELP_ACTION) { - os << "dr \n gets the dynamic range of the detector" << std::endl; - os << "roi \n gets region of interest" << std::endl; - os << "detsizechan \n gets the maximum number of channels for complete detector set in both directions; 0 is no limit" << std::endl; - os << "quad \n returns 1 if the detector size is a quad (Specific to an EIGER quad hardware). 0 by default."<< std::endl; - os << "flippeddatax\n gets if the data will be flipped on the x axis" << std::endl; - os << "gappixels\n gets if gap pixels is enabled in system. Used in EIGER only and multidetector level." << std::endl; - } - return os.str(); -} std::string slsDetectorCommand::cmdSettings(int narg, const char * const args[], int action, int detPos) { @@ -3009,78 +1450,8 @@ std::string slsDetectorCommand::cmdSettings(int narg, const char * const args[], int val = -1; //ret, char ans[1000]; - // portType index; - // if (sscanf(args[1],"%d",&val)) - // ; - // else - // return std::string("could not scan port number")+std::string (args[1]); - // } - - - if (cmd == "settings") { - detectorSettings sett = GET_SETTINGS; - if (action == PUT_ACTION) { - sett = myDet->getDetectorSettings(std::string(args[1])); - if (sett == -1) - return std::string("unknown settings scanned " + std::string(args[1])); - sett = myDet->setSettings(sett, detPos); - if (myDet->getDetectorTypeAsEnum(detPos) == EIGER) { - return myDet->getDetectorSettings(sett); - } - } - return myDet->getDetectorSettings(myDet->getSettings(detPos)); - } else if (cmd == "threshold") { - if (action == PUT_ACTION) { - if (!sscanf(args[1], "%d", &val)) { - return std::string("invalid threshold value"); - } - detectorType type = myDet->getDetectorTypeAsEnum(detPos); - if (type != EIGER || (type == EIGER && narg <= 2)) { - myDet->setThresholdEnergy(val, GET_SETTINGS, 1, detPos); - } else { - detectorSettings sett = myDet->getDetectorSettings(std::string(args[2])); - if (sett == -1) - return std::string("invalid settings value"); - myDet->setThresholdEnergy(val, sett, 1, detPos); - } - } - sprintf(ans, "%d", myDet->getThresholdEnergy(detPos)); - return std::string(ans); - } else if (cmd == "thresholdnotb") { - if (action == PUT_ACTION) { - if (!sscanf(args[1], "%d", &val)) { - return std::string("invalid threshold value"); - } - detectorType type = myDet->getDetectorTypeAsEnum(detPos); - if (type != EIGER) - return std::string("not implemented for this detector"); - if (narg <= 2) { - myDet->setThresholdEnergy(val, GET_SETTINGS, 0, detPos); - } else { - detectorSettings sett = myDet->getDetectorSettings(std::string(args[2])); - if (sett == -1) - return std::string("invalid settings value"); - myDet->setThresholdEnergy(val, sett, 0, detPos); - } - } - sprintf(ans, "%d", myDet->getThresholdEnergy(detPos)); - return std::string(ans); - } else if (cmd == "trimbits") { - if (narg >= 2) { - std::string sval = std::string(args[1]); -#ifdef VERBOSE - std::cout << " trimfile " << sval << std::endl; -#endif - if (action == GET_ACTION) { - //create file names - myDet->saveSettingsFile(sval, detPos); - } else if (action == PUT_ACTION) { - myDet->loadSettingsFile(sval, detPos); - } - return sval; - } - return std::string("Specify file name for geting settings file"); - } else if (cmd == "trimval") { + + if (cmd == "trimval") { if (action == PUT_ACTION) { if (sscanf(args[1], "%d", &val)) myDet->setAllTrimbits(val, detPos); @@ -3097,79 +1468,22 @@ std::string slsDetectorCommand::helpSettings(int action) { std::ostringstream os; if (action == PUT_ACTION || action == HELP_ACTION) { - os << "settings s \n sets the settings of the detector - can be standard, fast, highgain, dynamicgain, lowgain, mediumgain, veryhighgain" - "dynamichg0,fixgain1,fixgain2,forceswitchg1, forceswitchg2" - << std::endl; - os << "threshold eV [sett]\n sets the detector threshold in eV. If sett is provided for eiger, uses settings sett" << std::endl; - os << "thresholdnotb eV [sett]\n sets the detector threshold in eV without loading trimbits. If sett is provided for eiger, uses settings sett" << std::endl; - os << "trimbits fname\n loads the trimfile fname to the detector. If no extension is specified, the serial number of each module will be attached." << std::endl; os << "trimval i \n sets all the trimbits to i" << std::endl; } if (action == GET_ACTION || action == HELP_ACTION) { - os << "settings \n gets the settings of the detector" << std::endl; - os << "threshold V\n gets the detector threshold" << std::endl; - os << "thresholdnotb V\n gets the detector threshold" << std::endl; - os << "trimbits [fname]\n returns the trimfile loaded on the detector. If fname is specified the trimbits are saved to file. If no extension is specified, the serial number of each module will be attached." << std::endl; - os << "trimval \n returns the value all trimbits are set to. If they are different, returns -1." << std::endl; + os << "trimval \n returns the value all trimbits are set to. If they are different, returns -1." << std::endl; } return os.str(); } std::string slsDetectorCommand::cmdSN(int narg, const char * const args[], int action, int detPos) { - char answer[1000]; - if (action == PUT_ACTION) return std::string("cannot set"); if (action == HELP_ACTION) return helpSN(action); - if (cmd == "thisversion") { - int64_t retval = myDet->getClientSoftwareVersion(); - if (retval < 0) - sprintf(answer, "%d", -1); - else - sprintf(answer, "0x%lx", retval); - return std::string(answer); - } - - - if (cmd == "detectornumber") { - int64_t retval = myDet->getId(DETECTOR_SERIAL_NUMBER, detPos); - if (retval < 0) - sprintf(answer, "%d", -1); - else - sprintf(answer, "0x%lx", retval); - return std::string(answer); - } - - if (cmd == "detectorversion") { - int64_t retval = myDet->getId(DETECTOR_FIRMWARE_VERSION, detPos); - if (retval < 0) - sprintf(answer, "%d", -1); - else - sprintf(answer, "0x%lx", retval); - return std::string(answer); - } - - if (cmd == "softwareversion") { - int64_t retval = myDet->getId(DETECTOR_SOFTWARE_VERSION, detPos); - if (retval < 0) - sprintf(answer, "%d", -1); - else - sprintf(answer, "0x%lx", retval); - return std::string(answer); - } - - if (cmd == "rx_version") { - int64_t retval = myDet->getReceiverSoftwareVersion(detPos); - if (retval < 0) - sprintf(answer, "%d", -1); - else - sprintf(answer, "0x%lx", retval); - return std::string(answer); - } if (cmd == "checkdetversion") { myDet->checkDetectorVersionCompatibility(detPos); @@ -3190,11 +1504,6 @@ std::string slsDetectorCommand::helpSN(int action) { if (action == GET_ACTION || action == HELP_ACTION) { os << "checkdetversion \n gets the version compatibility with detector server (if hostname is in shared memory). Only for Eiger, Jungfrau & Gotthard. Prints compatible/ incompatible." << std::endl; os << "rx_checkversion \n gets the version compatibility with receiver server (if rx_hostname is in shared memory). Only for Eiger, Jungfrau & Gotthard. Prints compatible/ incompatible." << std::endl; - os << "detectornumber \n gets the serial number of the detector (MAC)" << std::endl; - os << "detectorversion \n gets the firmware version of the detector" << std::endl; - os << "softwareversion \n gets the software version of the detector" << std::endl; - os << "thisversion \n gets the version of this software" << std::endl; - os << "rx_version \n gets the version of the receiver" << std::endl; } return os.str(); } @@ -3221,18 +1530,6 @@ std::string slsDetectorCommand::cmdDigiTest(int narg, const char * const args[], return std::string(answer); } - else if (cmd == "imagetest") { - if (action == PUT_ACTION) { - int ival = -1; - if (!sscanf(args[1], "%d", &ival)) { - return std::string("could not scan parameter for imagetest\n"); - } - ival = (ival == 0) ? 0 : 1; - myDet->digitalTest(IMAGE_TEST, ival, detPos); - } - - return std::to_string(myDet->digitalTest(IMAGE_TEST, -1, detPos)); - } return std::string("unknown test mode ") + cmd; } @@ -3241,12 +1538,10 @@ std::string slsDetectorCommand::helpDigiTest(int action) { std::ostringstream os; if (action == GET_ACTION || action == HELP_ACTION) { - os << "imagetest i \t If 1, adds channel intensity with precalculated values. Default is 0. Gotthard only." << std::endl; os << "bustest \t performs test of the bus interface between FPGA and embedded Linux system. Can last up to a few minutes. Jungfrau only." << std::endl; os << "firmwaretest \t performs the firmware test. Jungfrau only." << std::endl; } if (action == PUT_ACTION || action == HELP_ACTION) { - os << "imagetest i \t If 1, adds channel intensity with precalculated values. Default is 0. Gotthard only." << std::endl; os << "bustest \t performs test of the bus interface between FPGA and embedded Linux system. Can last up to a few minutes. Jungfrau only." << std::endl; os << "firmwaretest \t performs the firmware test. Jungfrau only." << std::endl; } @@ -3391,8 +1686,6 @@ std::string slsDetectorCommand::cmdDAC(int narg, const char * const args[], int ++iarg; --narg; } - else if (cmd == "adcvpp") - dac = ADC_VPP; else if (cmd == "vthreshold") dac = THRESHOLD; else if (cmd == "vcalibration") @@ -3405,8 +1698,6 @@ std::string slsDetectorCommand::cmdDAC(int narg, const char * const args[], int dac = SHAPER1; else if (cmd == "vshaper2" || cmd == "vshaperneg") dac = SHAPER2; - else if (cmd == "vhighvoltage") - dac = HIGH_VOLTAGE; else if (cmd == "vapower") dac = VA_POT; else if (cmd == "vddpower") @@ -3466,26 +1757,6 @@ std::string slsDetectorCommand::cmdDAC(int narg, const char * const args[], int dac = E_Vis; else if (cmd == "iodelay") dac = IO_DELAY; - else if (cmd == "v_a") { - dac = V_POWER_A; - mode = 1; - } else if (cmd == "v_b") { - dac = V_POWER_B; - mode = 1; - } else if (cmd == "v_c") { - dac = V_POWER_C; - mode = 1; - } else if (cmd == "v_d") { - dac = V_POWER_D; - mode = 1; - } else if (cmd == "v_io") { - dac = V_POWER_IO; - mode = 1; - } else if (cmd == "v_chip") { - dac = V_POWER_CHIP; - mode = 1; - } else if (cmd == "v_limit") - dac = V_LIMIT; else if (cmd == "vipre") dac = M_vIpre; else if (cmd == "viinsh") @@ -3588,9 +1859,6 @@ std::string slsDetectorCommand::helpDAC(int action) { os << "vshaper2 " << "dacu\t sets the shaper2 feedback voltage in dac units (0-1024)." << std::endl; os << std::endl; - os << "vhighvoltage " - << "dacu\t CHIPTEST BOARD ONLY - sets the detector HV in dac units (0-1024)." << std::endl; - os << std::endl; os << "vapower " << "dacu\t CHIPTEST BOARD ONLY - sets the analog power supply in dac units (0-1024)." << std::endl; os << std::endl; @@ -3676,9 +1944,6 @@ std::string slsDetectorCommand::helpDAC(int action) { os << "vshaper2 " << "dacu\t gets the shaper2 feedback voltage in dac units (0-1024)." << std::endl; os << std::endl; - os << "vhighvoltage " - << "dacu\t CHIPTEST BOARD ONLY - gets the detector HV in dac units (0-1024)." << std::endl; - os << std::endl; os << "vapower " << "dacu\t CHIPTEST BOARD ONLY - gets the analog power supply in dac units (0-1024)." << std::endl; os << std::endl; @@ -3745,357 +2010,9 @@ std::string slsDetectorCommand::helpDAC(int action) { return os.str(); } -std::string slsDetectorCommand::cmdADC(int narg, const char * const args[], int action, int detPos) { - - dacIndex adc; - char answer[1000]; - - if (action == HELP_ACTION) - return helpADC(action); - else if (action == PUT_ACTION) - return std::string("cannot set ") + cmd; - - if (cmd == "adc") { - int idac = -1; - if (sscanf(args[1], "%d", &idac) != 1) { - return std::string("Could not scan adc index") + std::string(args[1]); - } - if (idac < 0 || idac > SLOW_ADC_TEMP - SLOW_ADC0) { - return (std::string ("cannot set adc, must be between ") + std::to_string(0) + - std::string (" and ") + std::to_string(SLOW_ADC_TEMP - SLOW_ADC0)); - } - adc = (dacIndex)(idac + SLOW_ADC0); - } - else if (cmd=="temp_adc") - adc=TEMPERATURE_ADC; - else if (cmd=="temp_fpga") - adc=TEMPERATURE_FPGA; - else if (cmd=="temp_fpgaext") - adc=TEMPERATURE_FPGAEXT; - else if (cmd=="temp_10ge") - adc=TEMPERATURE_10GE; - else if (cmd=="temp_dcdc") - adc=TEMPERATURE_DCDC; - else if (cmd=="temp_sodl") - adc=TEMPERATURE_SODL; - else if (cmd=="temp_sodr") - adc=TEMPERATURE_SODR; - else if (cmd=="temp_fpgafl") - adc=TEMPERATURE_FPGA2; - else if (cmd=="temp_fpgafr") - adc=TEMPERATURE_FPGA3; - else if (cmd=="i_a") - adc=I_POWER_A; - else if (cmd=="i_b") - adc=I_POWER_B; - else if (cmd=="i_c") - adc=I_POWER_C; - else if (cmd=="i_d") - adc=I_POWER_D; - else if (cmd=="vm_a") - adc=V_POWER_A; - else if (cmd=="vm_b") - adc=V_POWER_B; - else if (cmd=="vm_c") - adc=V_POWER_C; - else if (cmd=="vm_d") - adc=V_POWER_D; - else if (cmd=="vm_io") - adc=V_POWER_IO; - else if (cmd=="i_io") - adc=I_POWER_IO; - else - return std::string("cannot decode adc ")+cmd; - - if (myDet->getDetectorTypeAsEnum(detPos) == EIGER || myDet->getDetectorTypeAsEnum(detPos) == JUNGFRAU){ - int val = myDet->getADC(adc, detPos); - if (val == -1) - sprintf(answer,"%d",val); - else - sprintf(answer,"%.2f", (double)val/1000.000); - } - else sprintf(answer,"%d",myDet->getADC(adc, detPos)); - - //if ((adc == TEMPERATURE_ADC) || (adc == TEMPERATURE_FPGA)) - if (adc < 100 || adc == SLOW_ADC_TEMP) - strcat(answer,"°C"); - else if (adc == I_POWER_A || adc == I_POWER_B || adc == I_POWER_C || adc == I_POWER_D || adc == I_POWER_IO) - strcat(answer," mA"); - else - strcat(answer," mV"); - - return std::string(answer); - -} - -std::string slsDetectorCommand::helpADC(int action) { - - std::ostringstream os; - if (action == PUT_ACTION || action == HELP_ACTION) { - os << "temp_adc " - << "Cannot be set" << std::endl; - os << "temp_fpga " - << "Cannot be set" << std::endl; - os << "temp_fpgaext " - << "Cannot be set" << std::endl; - os << "temp_10ge " - << "Cannot be set" << std::endl; - os << "temp_dcdc " - << "Cannot be set" << std::endl; - os << "temp_sodl " - << "Cannot be set" << std::endl; - os << "temp_sodr " - << "Cannot be set" << std::endl; - os << "temp_fpgafl " - << "Cannot be set" << std::endl; - os << "temp_fpgafr " - << "Cannot be set" << std::endl; - } - if (action == GET_ACTION || action == HELP_ACTION) { - os << "temp_adc " - << "\t gets the temperature of the adc" << std::endl; - os << "temp_fpga " - << "\t gets the temperature of the fpga" << std::endl; - os << "temp_fpgaext " - << "\t gets the temperature close to the fpga" << std::endl; - os << "temp_10ge " - << "\t gets the temperature close to the 10GE" << std::endl; - os << "temp_dcdc " - << "\t gets the temperature close to the dc dc converter" << std::endl; - os << "temp_sodl " - << "\t gets the temperature close to the left so-dimm memory" << std::endl; - os << "temp_sodr " - << "\t gets the temperature close to the right so-dimm memory" << std::endl; - os << "temp_fpgafl " - << "\t gets the temperature of the left front end board fpga" << std::endl; - os << "temp_fpgafr " - << "\t gets the temperature of the left front end board fpga" << std::endl; - } - return os.str(); -} - -std::string slsDetectorCommand::cmdTempControl(int narg, const char * const args[], int action, int detPos) { - char answer[1000] = ""; - int val = -1; - - if (action == HELP_ACTION) - return helpTempControl(action); - if (cmd == "temp_threshold") { - if (action == PUT_ACTION) { - double fval = 0.0; - if (!sscanf(args[1], "%lf", &fval)) - return std::string("cannot scan temp control value ") + std::string(args[1]); - val = fval * 1000; - myDet->setThresholdTemperature(val, detPos); - } - val = myDet->setThresholdTemperature(-1, detPos); - if (val == -1) - sprintf(answer, "%d", val); - else - sprintf(answer, "%.2f°C", (double)val / 1000.000); - } - else if (cmd == "temp_control") { - if (action == PUT_ACTION) { - if (!sscanf(args[1], "%d", &val)) - return std::string("cannot scan temp control value ") + std::string(args[1]); - if ((val != 0) && (val != 1)) - return std::string("temp_control option must be 0 or 1"); - myDet->setTemperatureControl(val, detPos); - } - sprintf(answer, "%d", myDet->setTemperatureControl(-1, detPos)); - } - - else if (cmd == "temp_event") { - if (action == PUT_ACTION) { - if (!sscanf(args[1], "%d", &val)) - return std::string("cannot scan temp control value ") + std::string(args[1]); - if (val != 0) - return std::string("temp_event option must be 0 to clear event"); - myDet->setTemperatureEvent(val, detPos); - } - sprintf(answer, "%d", myDet->setTemperatureEvent(-1, detPos)); - } - - else - return std::string("cannot scan command " + cmd); - - return std::string(answer); -} - -std::string slsDetectorCommand::helpTempControl(int action) { - std::ostringstream os; - if (action == PUT_ACTION || action == HELP_ACTION) { - os << "temp_threshold t \t sets the threshold temperature. Jungfrau only" << std::endl; - os << "temp_control t \t Enables/Disables the temperature control. 1 enables, 0 disables. JUNGFRAU ONLY" << std::endl; - os << "temp_event t \t Resets over-temperative event. Put only with option 0 to clear event. JUNGFRAU ONLY." << std::endl; - } - if (action == GET_ACTION || action == HELP_ACTION) { - os << "temp_threshold \t gets the threshold temperature. Jungfrau only." << std::endl; - os << "temp_control \t gets temperature control enable. 1 enabled, 0 disabled. JUNGFRAU ONLY" << std::endl; - os << "temp_event \t gets over-temperative event. Gets 1 if temperature went over threshold and control is enabled, else 0. /Disables the temperature control. JUNGFRAU ONLY." << std::endl; - } - return os.str(); -} - -std::string slsDetectorCommand::cmdTiming(int narg, const char * const args[], int action, int detPos) { -#ifdef VERBOSE - std::cout << std::string("Executing command ") + std::string(args[0]) + std::string(" ( ") + cmd + std::string(" )\n"); -#endif - - if (action == HELP_ACTION) { - return helpTiming(HELP_ACTION); - } - if (action == PUT_ACTION) { - if (myDet->timingModeType(std::string(args[1])) == GET_TIMING_MODE) - return helpTiming(action); - myDet->setTimingMode(myDet->timingModeType(std::string(args[1])), detPos); - } - return myDet->timingModeType(myDet->setTimingMode(GET_TIMING_MODE, detPos)); -} -std::string slsDetectorCommand::helpTiming(int action) { - - std::ostringstream os; - if (action == GET_ACTION || action == HELP_ACTION) - os << std::string("timing \t gets the timing mode of the detector (auto, trigger, ro_trigger, gating, triggered_gating)\n"); - if (action == PUT_ACTION || action == HELP_ACTION) - os << std::string("timing mode \t sets synchronization mode of the detector. Can be auto, trigger, ro_trigger, gating, triggered_gating \n"); - return os.str(); -} - -std::string slsDetectorCommand::cmdTimer(int narg, const char * const args[], int action, int detPos) { - timerIndex index; - int64_t t = -1, ret; - double val, rval; - - char answer[1000]; - - if (action == HELP_ACTION) - return helpTimer(action); - - if (cmd == "exptime") - index = ACQUISITION_TIME; - else if (cmd == "subexptime") - index = SUBFRAME_ACQUISITION_TIME; - else if (cmd == "period") - index = FRAME_PERIOD; - else if (cmd == "subdeadtime") - index = SUBFRAME_DEADTIME; - else if (cmd == "delay") - index = DELAY_AFTER_TRIGGER; - else if (cmd == "cycles") - index = CYCLES_NUMBER; - // also does digital sample - else if (cmd == "samples") - index = ANALOG_SAMPLES; - else if (cmd == "asamples") - index = ANALOG_SAMPLES; - else if (cmd == "dsamples") - index = DIGITAL_SAMPLES; - else if (cmd == "storagecells") - index = STORAGE_CELL_NUMBER; - else if (cmd == "storagecell_delay") - index = STORAGE_CELL_DELAY; - else if (cmd == "storagecell_start") { - if (action == PUT_ACTION) { - int ival = -1; - if (!sscanf(args[1], "%d", &ival)) - return std::string("cannot scan storage cell start value ") + std::string(args[1]); - myDet->setStoragecellStart(ival, detPos); - } - sprintf(answer, "%d", myDet->setStoragecellStart(-1, detPos)); - return std::string(answer); - } else if (cmd == "startingfnum") { - if (action == PUT_ACTION) { - uint64_t ival = -1; - if (!sscanf(args[1], "%lu", &ival)) - return std::string("cannot scan starting frame number value ") + std::string(args[1]); - myDet->setStartingFrameNumber(ival, detPos); - return std::string(args[1]); - } - return std::to_string(myDet->getStartingFrameNumber(detPos)); - } else - return std::string("could not decode timer ") + cmd; - - if (action == PUT_ACTION) { - if (sscanf(args[1], "%lf", &val)) - ; //printf("value:%0.9lf\n",val); - else - return std::string("cannot scan timer value ") + std::string(args[1]); - - // timer - if (index == ACQUISITION_TIME || index == SUBFRAME_ACQUISITION_TIME || - index == FRAME_PERIOD || index == DELAY_AFTER_TRIGGER || - index == SUBFRAME_DEADTIME || index == STORAGE_CELL_DELAY) { - t = lround(val * 1E9); - } else - t = static_cast(val); - } - - - ret = myDet->setTimer(index, t, detPos); - - // samples command does both asamples and dsamples - if (cmd == "samples" ) { - int64_t dret = myDet->setTimer(DIGITAL_SAMPLES, t, detPos); - if (dret != ret) { - throw sls::RuntimeError("Analog and digital number of samples are different. Check with asamples and dsamples command"); - } - } - - if ((ret != -1) && (index == ACQUISITION_TIME || index == SUBFRAME_ACQUISITION_TIME || - index == FRAME_PERIOD || index == DELAY_AFTER_TRIGGER || - index == SUBFRAME_DEADTIME || index == STORAGE_CELL_DELAY)) { - rval = (double)ret * 1E-9; - sprintf(answer, "%0.9f", rval); - } else - sprintf(answer, "%lld", (long long int)ret); - - return std::string(answer); -} - -std::string slsDetectorCommand::helpTimer(int action) { - - std::ostringstream os; - if (action == PUT_ACTION || action == HELP_ACTION) { - os << "exptime t \t sets the exposure time in s" << std::endl; - os << "subexptime t \t sets the exposure time of subframe in s" << std::endl; - os << "period t \t sets the frame period in s" << std::endl; - os << "delay t \t sets the delay after trigger in s" << std::endl; - os << "frames t \t sets the number of frames per cycle (e.g. after each trigger)" << std::endl; - os << "startingfnum t \t sets starting frame number for the next acquisition. Only for Jungfrau and Eiger." << std::endl; - os << "cycles t \t sets the number of cycles (e.g. number of triggers)" << std::endl; - os << "samples t \t sets the number of samples (both analog and digital) expected from the ctb" << std::endl; - os << "asamples t \t sets the number of analog samples expected from the ctb" << std::endl; - os << "dsamples t \t sets the number of digital samples expected from the ctb" << std::endl; - os << "storagecells t \t sets number of storage cells per acquisition. For very advanced users only! For JUNGFRAU only. Range: 0-15. The #images = #frames * #cycles * (#storagecells+1)." << std::endl; - os << "storagecell_start t \t sets the storage cell that stores the first acquisition of the series. Default is 15(0xf). For very advanced users only! For JUNGFRAU only. Range: 0-15." << std::endl; - os << "storagecell_delay t \t sets additional time to t between 2 storage cells. For very advanced users only! For JUNGFRAU only. Range: 0-1638375 ns (resolution of 25ns).. " << std::endl; - os << "subdeadtime t \t sets sub frame dead time in s. Subperiod is set in the detector = subexptime + subdeadtime. This value is normally a constant in the config file. Used in EIGER only in 32 bit mode. " << std::endl; - os << std::endl; - } - if (action == GET_ACTION || action == HELP_ACTION) { - - os << "exptime \t gets the exposure time in s" << std::endl; - os << "subexptime \t gets the exposure time of subframe in s" << std::endl; - os << "period \t gets the frame period in s" << std::endl; - os << "delay \t gets the delay after trigger in s" << std::endl; - os << "frames \t gets the number of frames per cycle (e.g. after each trigger)" << std::endl; - os << "startingfnum \t gets starting frame number for the next acquisition. Only for Jungfrau and Eiger." << std::endl; - os << "cycles \t gets the number of cycles (e.g. number of triggers)" << std::endl; - os << "samples \t gets the number of samples (both analog and digital) expected from the ctb" << std::endl; - os << "asamples \t gets the number of analog samples expected from the ctb" << std::endl; - os << "dsamples \t gets the number of digital samples expected from the ctb" << std::endl; - os << "storagecells \t gets number of storage cells per acquisition.For JUNGFRAU only." << std::endl; - os << "storagecell_start \t gets the storage cell that stores the first acquisition of the series." << std::endl; - os << "storagecell_delay \tgets additional time between 2 storage cells. " << std::endl; - os << "subperiod \t gets sub frame dead time in s. Used in EIGER in 32 bit only." << std::endl; - os << std::endl; - } - return os.str(); -} std::string slsDetectorCommand::cmdTimeLeft(int narg, const char * const args[], int action, int detPos) { timerIndex index; @@ -4107,26 +2024,12 @@ std::string slsDetectorCommand::cmdTimeLeft(int narg, const char * const args[], if (action == HELP_ACTION) return helpTimeLeft(action); - if (cmd == "exptimel") - index = ACQUISITION_TIME; - else if (cmd == "periodl") - index = FRAME_PERIOD; - else if (cmd == "delayl") - index = DELAY_AFTER_TRIGGER; - else if (cmd == "framesl") - index = FRAME_NUMBER; - else if (cmd == "cyclesl") - index = CYCLES_NUMBER; - else if (cmd == "now") + if (cmd == "now") index = ACTUAL_TIME; else if (cmd == "timestamp") index = MEASUREMENT_TIME; else if (cmd == "nframes") index = FRAMES_FROM_START; - else if (cmd == "measuredperiod") - index = MEASURED_PERIOD; - else if (cmd == "measuredsubperiod") - index = MEASURED_SUBPERIOD; else return std::string("could not decode timer ") + cmd; @@ -4137,8 +2040,7 @@ std::string slsDetectorCommand::cmdTimeLeft(int narg, const char * const args[], ret = myDet->getTimeLeft(index, detPos); - if ((ret != -1) && (index == ACQUISITION_TIME || index == FRAME_PERIOD || index == DELAY_AFTER_TRIGGER || index == ACTUAL_TIME || index == MEASUREMENT_TIME || - index == MEASURED_PERIOD || index == MEASURED_SUBPERIOD)) { + if ((ret != -1) && (index == ACTUAL_TIME || index == MEASUREMENT_TIME)) { rval = (double)ret * 1E-9; sprintf(answer,"%0.9f",rval); } else { @@ -4152,177 +2054,19 @@ std::string slsDetectorCommand::helpTimeLeft(int action) { std::ostringstream os; if (action == GET_ACTION || action == HELP_ACTION) { - - os << "exptimel \t gets the exposure time left" << std::endl; - os << "periodl \t gets the frame period left" << std::endl; - os << "delayl \t gets the delay left" << std::endl; - os << "framesl \t gets the number of frames left" << std::endl; - os << "cyclesl \t gets the number of cycles left" << std::endl; - os << "measuredperiod \t gets the measured frame period (time between last frame and the previous one) in s. For Eiger only. Makes sense only for acquisitions of more than 1 frame." << std::endl; - os << "measuredsubperiod \t gets the measured subframe period (time between last subframe and the previous one) in s. For Eiger only and in 32 bit mode." << std::endl; os << std::endl; } return os.str(); } -std::string slsDetectorCommand::cmdSpeed(int narg, const char * const args[], int action, int detPos) { - - speedVariable index; - int t = -1, ret = 0, mode = 0; - - char answer[1000]; - - if (action == HELP_ACTION) - return helpSpeed(action); - - if (cmd == "clkdivider") { - index = CLOCK_DIVIDER; - } - else if (cmd == "adcclk") { - index = ADC_CLOCK; - } - else if (cmd == "dbitclk") { - index = DBIT_CLOCK; - } - else if (cmd == "syncclk") { - index = SYNC_CLOCK; - if (action == PUT_ACTION) { - return std::string("cannot put"); - } - } - else if (cmd == "adcphase") { - index = ADC_PHASE; - if ((action == PUT_ACTION && narg > 2 && std::string(args[2]) == "deg") || - (action == GET_ACTION && narg > 1 && std::string(args[1]) == "deg")) { - mode = 1; - } - } - else if (cmd == "dbitphase") { - index = DBIT_PHASE; - if ((action == PUT_ACTION && narg > 2 && std::string(args[2]) == "deg") || - (action == GET_ACTION && narg > 1 && std::string(args[1]) == "deg")) { - mode = 1; - } - } - else if (cmd == "maxadcphaseshift") { - index = MAX_ADC_PHASE_SHIFT; - if (action == PUT_ACTION) { - return std::string("cannot put"); - } - } - else if (cmd == "maxdbitphaseshift") { - index = MAX_DBIT_PHASE_SHIFT; - if (action == PUT_ACTION) { - return std::string("cannot put"); - } - } - else if (cmd == "adcpipeline") { - index = ADC_PIPELINE; - } - else if (cmd == "dbitpipeline") { - index = DBIT_PIPELINE; - } - else - return std::string("could not decode speed variable ") + cmd; - - if (action == PUT_ACTION) { - if (sscanf(args[1], "%d", &t)) - ; - else { - // if parameer is a string (unknown speed will throw) - if (cmd == "clkdivider") { - speedLevel lev = getSpeedLevelType(std::string(args[1])); - t = static_cast(lev); - } - return std::string("cannot scan speed value ") + std::string(args[1]); - } - } - - - ret = myDet->setSpeed(index, t, mode, detPos); - - sprintf(answer, "%d", ret); - return std::string(answer); -} - -std::string slsDetectorCommand::helpSpeed(int action) { - - std::ostringstream os; - if (action == PUT_ACTION || action == HELP_ACTION) { - os << "clkdivider c \t sets readout clock divider. EIGER, JUNGFRAU [0(fast speed), 1(half speed), 2(quarter speed)]. Jungfrau, full speed is not implemented and overwrites adcphase to recommended default. Not for Gotthard." << std::endl; - os << "adcclk c \tSets ADC clock frequency in MHz. CTB & Moench only. " << std::endl; - os << "dbitclk c \tSets the clock frequency of the latching of the digital bits in MHz. CTB & Moench only. " << std::endl; - os << "adcphase c [deg]\t Sets phase of the ADC clock to i. i is the shift or in degrees if deg is used. deg is optional & only for CTB, Moench & Jungfrau. For CTB & Moench, adcphase is reset if adcclk is changed. For Jungfrau, adcphase changed to defaults if clkdivider changed. Jungfrau, CTB & Moench, these are absolute values with limits. Gotthard, relative phase shift. Not for Eiger." << std::endl; - os << "dbitphase c [deg]\t Sets the phase of the clock for latching of the digital bits to i. i is the shift or in degrees if deg is used. deg is optional. dbitphase is also reset if dbitclk is changed. These are absolute values with limits. for CTB & Moench only." << std::endl; - os << "adcpipeline c \t Sets the pipeline of the ADC. For CTB & Moench only." << std::endl; - os << "dbitpipeline c \t Sets the pipeline of the latching of the digital bits. For CTB & Moench only." << std::endl; - os << std::endl; - } - if (action == GET_ACTION || action == HELP_ACTION) { - os << "clkdivider \t Gets readout clock divider. EIGER, JUNGFRAU [0(fast speed), 1(half speed), 2(quarter speed)]. Jungfrau, full speed is not implemented and overwrites adcphase to recommended default. Not for Gotthard." << std::endl; - os << "adcclk \tGets ADC clock frequency in MHz. CTB & Moench only. " << std::endl; - os << "dbitclk \tGets the clock frequency of the latching of the digital bits in MHz. CTB & Moench only. " << std::endl; - os << "syncclk \t Gets the clock frequency of the sync clock in MHz. CTB & Moench only." << std::endl; - os << "adcphase [deg]\t Gets phase of the ADC clock. unit is number of shifts or in degrees if deg is used. deg is optional & only for CTB, Moench & Jungfrau. For CTB & Moench, adcphase is reset if adcclk is changed. For Jungfrau, adcphase changed to defaults if clkdivider changed. Jungfrau, CTB & Moench, these are absolute values with limits. Gotthard, relative phase shift. Not for Eiger." << std::endl; - os << "dbitphase [deg]\t Gets the phase of the clock for latching of the digital bits. unit is number of shifts or in degrees if deg is used. deg is optional. dbitphase is also reset if dbitclk is changed. These are absolute values with limits. for CTB & Moench only." << std::endl; - os << "adcpipeline \t Gets the pipeline of the ADC. For CTB & Moench only." << std::endl; - os << "dbitpipeline \t Gets the pipeline of the latching of the digital bits. For CTB & Moench only." << std::endl; - os << "maxadcphaseshift \t Gets maximum phase shift of the ADC clock. CTB,Moench and Jungfrau only." << std::endl; - os << "maxdbitphaseshift \t Gets maximum phase shift of the clock for latching of the digital bits. CTB & Moench only." << std::endl; - os << std::endl; - } - return os.str(); -} std::string slsDetectorCommand::cmdAdvanced(int narg, const char * const args[], int action, int detPos) { if (action == HELP_ACTION) return helpAdvanced(action); - - if (cmd == "romode") { - if (action == PUT_ACTION) { - myDet->setReadoutMode(getReadoutModeType(std::string(args[1])), detPos); - } - return getReadoutModeType(myDet->getReadoutMode()); - } - - else if (cmd=="interruptsubframe") { - if (action==PUT_ACTION) { - int ival = -1; - if (!sscanf(args[1],"%d",&ival)) - return std::string("could not scan interrupt sub frame parameter ") + std::string(args[1]); - myDet->setInterruptSubframe(ival > 0 ? true : false); - } - return std::to_string(myDet->getInterruptSubframe()); - - } - - else if (cmd == "readnlines") { - if (action == PUT_ACTION) { - int ival = -1; - if (!sscanf(args[1],"%d",&ival)) - return std::string("could not scan readnlines parameter ") + std::string(args[1]); - myDet->setReadNLines(ival); - } - return std::to_string(myDet->getReadNLines()); - - } - - else if (cmd == "extsig") { - externalSignalFlag flag = GET_EXTERNAL_SIGNAL_FLAG; - - if (action == PUT_ACTION) { - flag = myDet->externalSignalType(args[1]); - if (flag == GET_EXTERNAL_SIGNAL_FLAG) - return std::string("could not scan external signal mode ") + std::string(args[1]); - } - - return myDet->externalSignalType(myDet->setExternalSignalFlags(flag, detPos)); - - } - - else if (cmd == "programfpga") { + + if (cmd == "programfpga") { if (action == GET_ACTION) return std::string("cannot get"); if (strstr(args[1], ".pof") == nullptr) @@ -4372,56 +2116,8 @@ std::string slsDetectorCommand::cmdAdvanced(int narg, const char * const args[], return std::string("successful"); } - else if (cmd == "powerchip") { - char ans[100]; - if (action == PUT_ACTION) { - int ival = -1; - if (!sscanf(args[1], "%d", &ival)) - return std::string("could not scan powerchip parameter " + std::string(args[1])); - myDet->powerChip(ival, detPos); - } - sprintf(ans, "%d", myDet->powerChip(-1, detPos)); - return std::string(ans); - } - else if (cmd == "led") { - if (action == PUT_ACTION) { - int ival = -1; - if (!sscanf(args[1], "%d", &ival)) - return std::string("could not scan led parameter " + std::string(args[1])); - myDet->setLEDEnable(ival, detPos); - } - return std::to_string(myDet->setLEDEnable(-1, detPos)); - } - - else if (cmd == "diodelay") { - if (action == GET_ACTION) { - return std::string("Cannot get"); - } - - - uint64_t pinMask = -1; - if (!sscanf(args[1], "%lx", &pinMask)) - return std::string("could not scan diodelay pin mask(in hex) " + std::string(args[1])); - int delay = -1; - if (!sscanf(args[2], "%d", &delay)) - return std::string("could not scan diodelay delay " + std::string(args[2])); - - myDet->setDigitalIODelay(pinMask, delay, detPos); - return std::string("successful"); - } - - else if (cmd == "auto_comp_disable") { - char ans[100]; - if (action == PUT_ACTION) { - int ival = -1; - if (!sscanf(args[1], "%d", &ival)) - return std::string("could not scan auto_comp_control parameter " + std::string(args[1])); - myDet->setAutoComparatorDisableMode(ival, detPos); - } - sprintf(ans, "%d", myDet->setAutoComparatorDisableMode(-1, detPos)); - return std::string(ans); - } else + else return std::string("unknown command ") + cmd; } @@ -4429,30 +2125,11 @@ std::string slsDetectorCommand::helpAdvanced(int action) { std::ostringstream os; if (action == PUT_ACTION || action == HELP_ACTION) { - - os << "extsig mode \t sets the mode of the external signal. can be trigger_out_rising_edge, trigger_out_falling_edge. Gotthard only" << std::endl; - os << "romode m \t sets the readout flag to m. Options: analog, digital, analog_digital. Used for CTB only." << std::endl; - os << "interruptsubframe flag \t sets the interrupt subframe flag. Setting it to 1 will interrupt the last subframe at the required exposure time. By default, this is disabled and set to 0, ie. it will wait for the last sub frame to finish exposing. Used for EIGER in 32 bit mode only." << std::endl; - os << "readnlines f \t sets the number of rows to read out per half module. Options: 1 - 256 (Not all values as it depends on dynamic range and 10GbE enabled). Used for EIGER only. " << std::endl; os << "programfpga f \t programs the fpga with file f (with .pof extension)." << std::endl; os << "resetfpga f \t resets fpga, f can be any value" << std::endl; os << "copydetectorserver s p \t copies the detector server s via tftp from pc with hostname p and changes respawn server. Not for Eiger. " << std::endl; os << "rebootcontroller \t reboot controler blackfin of the detector. Not for Eiger." << std::endl; os << "update s p f \t updates the firmware to f and detector server to f from host p via tftp and then reboots controller (blackfin). Not for Eiger. " << std::endl; - os << "led s \t sets led status (0 off, 1 on)" << std::endl; - os << "diodelay m v \tsets the delay for the digital IO pins selected by mask m and delay set by v. mask is upto 64 bits in hex, delay max is 775ps, and set in steps of 25 ps. Used for MOENCH/CTB only." << std::endl; - os << "powerchip i \t powers on or off the chip. i = 1 for on, i = 0 for off" << std::endl; - os << "auto_comp_disable i \t this mode disables the on-chip gain switching comparator automatically after 93.75% of exposure time (only for longer than 100us). 1 enables mode, 0 disables mode. By default, mode is disabled (comparator is enabled throughout). (JUNGFRAU only). " << std::endl; - } - if (action == GET_ACTION || action == HELP_ACTION) { - - os << "extsig \t gets the mode of the external signal. can be trigger_in_rising_edge, trigger_in_falling_edge. Gotthard only" << std::endl; - os << "romode \t gets the readout flag. Options: analog, digital, analog_digital. Used for CTB only." << std::endl; - os << "interruptsubframe \t gets the interrupt subframe flag. Setting it to 1 will interrupt the last subframe at the required exposure time. By default, this is disabled and set to 0, ie. it will wait for the last sub frame to finish exposing. Used for EIGER in 32 bit mode only." << std::endl; - os << "readnlines \t gets the number of rows to read out per half module. Used for EIGER only. " << std::endl; - os << "led \t returns led status (0 off, 1 on)" << std::endl; - os << "powerchip \t gets if the chip has been powered on or off" << std::endl; - os << "auto_comp_disable \t gets if the automatic comparator diable mode is enabled/disabled" << std::endl; } return os.str(); } @@ -4462,96 +2139,28 @@ std::string slsDetectorCommand::cmdConfiguration(int narg, const char * const ar if (action == HELP_ACTION) return helpConfiguration(action); - std::string sval; - - if (narg < 2 && cmd != "rx_printconfig") - return std::string("should specify I/O file"); - - if (cmd == "config") { if (action == PUT_ACTION) { - sval = std::string(args[1]); - myDet->readConfigurationFile(sval); - } else if (action == GET_ACTION) { - sval = std::string(args[1]); - myDet->writeConfigurationFile(sval); - } - return sval; - } else if (cmd == "rx_printconfig") { - if (action == PUT_ACTION) - return std::string("cannot put"); - return myDet->printReceiverConfiguration(detPos); - } else if (cmd == "parameters") { - if (action == PUT_ACTION) { - sval = std::string(args[1]); - myDet->retrieveDetectorSetup(sval, 0); - } else if (action == GET_ACTION) { - sval = std::string(args[1]); - myDet->dumpDetectorSetup(sval, 0); - } - return sval; - } else if (cmd == "setup") { - if (action == PUT_ACTION) { - sval = std::string(args[1]); - myDet->retrieveDetectorSetup(sval, 2); - } else if (action == GET_ACTION) { - sval = std::string(args[1]); - myDet->dumpDetectorSetup(sval, 2); - } - return sval; - } + myDet->readConfigurationFile(std::string(args[1])); + } + return std::string("success"); + } return std::string("could not decode conf mode"); } std::string slsDetectorCommand::helpConfiguration(int action) { std::ostringstream os; - if (action == PUT_ACTION || action == HELP_ACTION) { - - os << "config fname \t sets the detector to the configuration contained in fname" << std::endl; - os << "parameters fname \t sets the detector parameters to those contained in fname" << std::endl; - os << "setup fname \t sets the detector complete detector setup to that contained in fname (extensions automatically generated), including trimfiles, ff coefficients etc." << std::endl; - } - if (action == GET_ACTION || action == HELP_ACTION) { - os << "rx_printconfig \t prints the receiver configuration" << std::endl; - os << "config fname \t saves the detector to the configuration to fname" << std::endl; - os << "parameters fname \t saves the detector parameters to fname" << std::endl; - os << "setup fname \t saves the detector complete detector setup to fname (extensions automatically generated), including trimfiles, ff coefficients etc." << std::endl; - } - return os.str(); } std::string slsDetectorCommand::cmdReceiver(int narg, const char * const args[], int action, int detPos) { char answer[100]; - int ival = -1; if (action == HELP_ACTION) return helpReceiver(action); - - if (cmd == "rx_status") { - if (action == PUT_ACTION) { - if (!strcasecmp(args[1], "start")) - myDet->startReceiver(detPos); - else if (!strcasecmp(args[1], "stop")) - myDet->stopReceiver(detPos); - else - return helpReceiver(action); - } - return myDet->runStatusType(myDet->getReceiverStatus(detPos)); - } - - else if (cmd == "framescaught") { - if (action == PUT_ACTION) - return std::string("cannot put"); - else { - sprintf(answer, "%d", myDet->getFramesCaughtByReceiver(detPos)); - return std::string(answer); - } - } - - else if (cmd == "resetframescaught") { + if (cmd == "resetframescaught") { if (action == GET_ACTION) return std::string("cannot get"); else { @@ -4568,39 +2177,6 @@ std::string slsDetectorCommand::cmdReceiver(int narg, const char * const args[], return std::string(answer); } } - else if (cmd == "tengiga") { - if (action == PUT_ACTION) { - if (!sscanf(args[1], "%d", &ival)) - return std::string("Could not scan tengiga input ") + std::string(args[1]); - if (ival >= 0) - sprintf(answer, "%d", myDet->enableTenGigabitEthernet(ival, detPos)); - } else - sprintf(answer, "%d", myDet->enableTenGigabitEthernet(-1, detPos)); - return std::string(answer); - - } - - else if (cmd == "rx_framesperfile") { - if (action == PUT_ACTION) { - if (sscanf(args[1], "%d", &ival)) { - myDet->setFramesPerFile(ival, detPos); - } else - return std::string("could not scan max frames per file\n"); - } - memset(answer, 0, 100); - sprintf(answer, "%d", myDet->getFramesPerFile(detPos)); - return std::string(answer); - } - - else if (cmd == "rx_discardpolicy") { - if (action == PUT_ACTION) { - frameDiscardPolicy f = myDet->getReceiverFrameDiscardPolicy(std::string(args[1])); - if (f == GET_FRAME_DISCARD_POLICY) - return std::string("could not scan frame discard policy. Options: nodiscard, discardempty, discardpartial\n"); - myDet->setReceiverFramesDiscardPolicy(f); - } - return myDet->getReceiverFrameDiscardPolicy(myDet->setReceiverFramesDiscardPolicy(GET_FRAME_DISCARD_POLICY, detPos)); - } else if (cmd == "rx_jsonaddheader") { if (action == PUT_ACTION) { @@ -4623,15 +2199,7 @@ std::string slsDetectorCommand::helpReceiver(int action) { std::ostringstream os; if (action == PUT_ACTION || action == HELP_ACTION) { - os << "receiver [status] \t starts/stops the receiver to listen to detector packets. - can be start, stop." << std::endl; os << "resetframescaught [any value] \t resets frames caught by receiver" << std::endl; - os << "rx_readfreq \t sets the gui read frequency of the receiver, 0 if gui requests frame, >0 if receiver sends every nth frame to gui. Default : 1" << std::endl; - os << "tengiga \t sets system to be configure for 10Gbe if set to 1, else 1Gbe if set to 0" << std::endl; - os << "rx_fifodepth [val]\t sets receiver fifo depth to val" << std::endl; - os << "rx_silent [i]\t sets receiver in silent mode, ie. it will not print anything during real time acquisition. 1 sets, 0 unsets." << std::endl; - os << "rx_framesperfile s\t sets the number of frames per file in receiver. 0 means infinite or all frames in a single file." << std::endl; - os << "rx_discardpolicy s\t sets the frame discard policy in the receiver. nodiscard (default) - discards nothing, discardempty - discard only empty frames, discardpartial(fastest) - discards all partial frames." << std::endl; - os << "rx_padding s\t enables/disables partial frames to be padded in the receiver. 0 does not pad partial frames(fastest), 1 (default) pads partial frames." << std::endl; os << "rx_jsonaddheader [t]\n sets additional json header to be streamed " "out with the zmq from receiver. Default is empty. t must be in the format '\"label1\":\"value1\",\"label2\":\"value2\"' etc." "Use only if it needs to be processed by an intermediate process." << std::endl; @@ -4639,16 +2207,7 @@ std::string slsDetectorCommand::helpReceiver(int action) { } if (action == GET_ACTION || action == HELP_ACTION) { - os << "receiver \t returns the status of receiver - can be running or idle" << std::endl; - os << "framescaught \t returns the number of frames caught by receiver(average for multi)" << std::endl; os << "frameindex \t returns the current frame index of receiver(average for multi)" << std::endl; - os << "rx_readfreq \t returns the gui read frequency of the receiver. DEfault: 1" << std::endl; - os << "tengiga \t returns 1 if the system is configured for 10Gbe else 0 for 1Gbe" << std::endl; - os << "rx_fifodepth \t returns receiver fifo depth" << std::endl; - os << "rx_silent \t returns receiver silent mode enable. 1 is silent, 0 not silent." << std::endl; - os << "rx_framesperfile \t gets the number of frames per file in receiver. 0 means infinite or all frames in a single file." << std::endl; - os << "rx_discardpolicy \t gets the frame discard policy in the receiver. nodiscard (default) - discards nothing, discardempty - discard only empty frames, discardpartial(fastest) - discards all partial frames." << std::endl; - os << "rx_padding \t gets partial frames padding enable in the receiver. 0 does not pad partial frames(fastest), 1 (default) pads partial frames." << std::endl; os << "rx_jsonaddheader \n gets additional json header to be streamed " "out with the zmq from receiver." << std::endl; os << "rx_jsonpara [k] \n gets value of additional json header parameter k to be streamed out with the zmq from receiver. If empty, then no parameter found." << std::endl; @@ -4661,10 +2220,6 @@ std::string slsDetectorCommand::helpPattern(int action) { std::ostringstream os; if (action == PUT_ACTION || action == HELP_ACTION) { - os << "pattern fname \t loads pattern file" << std::endl; - os << "patword addr word \t writes pattern word - only very advanced users!" << std::endl; - os << "patioctrl reg\t configures inputs/outputs of the chiptest board - only advanced users!" << std::endl; - os << "patclkctrl reg\t configures output clk enable of the chiptest board- only advanced users! " << std::endl; os << "patlimits addr1 addr2\t defines pattern limits between addr1 and addr2" << std::endl; os << "patloop0 addr1 adrr2 \t configures the limits of the 0 loop " << std::endl; os << "patloop1 addr1 adrr2 \t configures the limits of the 1 loop " << std::endl; @@ -4680,18 +2235,8 @@ std::string slsDetectorCommand::helpPattern(int action) { os << "patwaittime2 nclk \t sets wait 2 waiting time in clock number " << std::endl; os << "patmask m \t sets the 64 bit mask (hex) applied to every pattern. Only the bits from patsetbit are selected to mask for the corresponding bit value from m mask" << std::endl; os << "patsetbit m \t selects bits (hex) of the 64 bits that the patmask will be applied to every pattern. Only the bits from m mask are selected to mask for the corresponding bit value from patmask." << std::endl; - os << "adcinvert mask\t sets the adcinversion mask (hex) CTB or Moench only" << std::endl; - os << "adcenable mask\t sets the adcenable mask (hex) CTB or Moench only" << std::endl; - os << "extsamplingsrc i\t sets the external sampling source signal for digital data. i must be between 0 and 63. Advanced! CTB only " << std::endl; - os << "extsampling i\t enables/disables the external sampling signal to the samplingsrc signal for digital data. Advanced! CTB only" << std::endl; - os << "rx_dbitlist i..\t sets the list of digital signal bits required for chip in receiver. If set to 'all', then all digital bits are enabled. Advanced! CTB only " << std::endl; - os << "rx_dbitoffset i\t sets the offset in bytes in receiver of digital data from chip in receiver. Advanced! CTB only " << std::endl; } if (action == GET_ACTION || action == HELP_ACTION) { - os << "pattern \t cannot get" << std::endl; - os << "patword \t cannot get" << std::endl; - os << "patioctrl \t returns inputs/outputs of the chiptest board - only advanced users!" << std::endl; - os << "patclkctrl\t returns output clk enable of the chiptest board- only advanced users! " << std::endl; os << "patlimits \t returns pattern limits between addr1 and addr2" << std::endl; os << "patloop0 \t returns the limits of the 0 loop " << std::endl; os << "patloop1 \t returns the limits of the 1 loop " << std::endl; @@ -4707,12 +2252,6 @@ std::string slsDetectorCommand::helpPattern(int action) { os << "patwaittime2 \t returns the wait 2 waiting time in clock number " << std::endl; os << "patmask \t gets the 64 bit mask (hex) applied to every pattern." << std::endl; os << "patsetbit \t gets 64 bit mask (hex) of the selected bits that the patmask will be applied to every pattern. " << std::endl; - os << "adcinvert \t returns the adcinversion mask " << std::endl; - os << "adcenable \t returns the adcenable mask " << std::endl; - os << "extsamplingsrc \t gets the external sampling source signal for digital data. i must be between 0 and 63. Advanced! CTB only " << std::endl; - os << "extsampling \t gets the external sampling signal enable to the samplingsrc signal for digital data. Advanced! CTB only" << std::endl; - os << "rx_dbitlist \t gets the list of digital signal bits required for chip in receiver. If value is 'all', all digital bits are enabled. Advanced! CTB only " << std::endl; - os << "rx_dbitoffset \t gets the offset in bytes in receiver of digital data from chip in receiver. Advanced! CTB only " << std::endl; } return os.str(); @@ -4729,83 +2268,11 @@ std::string slsDetectorCommand::cmdPattern(int narg, const char * const args[], **********/ std::string fname; int addr, start, stop, n; - uint32_t u32; uint64_t word, t; std::ostringstream os; - if (cmd == "pattern") { - //get fname fron stdin - - if (action == PUT_ACTION) { - fname = std::string(args[1]); - myDet->setPattern(fname, detPos); - os << "successful"; - } else if (action == GET_ACTION) - os << "Cannot get"; - } else if (cmd == "savepattern") { - if (narg < 2) { - return helpPattern(action); - } - fname = std::string(args[1]); - myDet->savePattern(args[1]); - os << "Pattern executed and saved to " << fname; - } else if (cmd == "patword") { - - if (action == PUT_ACTION) { - //get addr, word from stdin - - if (narg < 3) - return std::string("wrong usage: should specify both address and value (hexadecimal fomat) "); - - if (sscanf(args[1], "%x", &addr)) - ; - else - return std::string("Could not scan address (hexadecimal fomat) ") + std::string(args[1]); - - if (sscanf(args[2], "%lx", &word)) - ; - else - return std::string("Could not scan value (hexadecimal fomat) ") + std::string(args[2]); - - os << "0x" << std::setw(4) << std::setfill('0') << std::hex << addr << " 0x" << std::setw(16) << myDet->setPatternWord(addr, word, detPos) << std::dec; - } else if (action == GET_ACTION) { - if (narg < 2) - return std::string("wrong usage: should specify address (hexadecimal fomat) "); - if (!sscanf(args[1], "%x", &addr)) - return std::string("Could not scan address (hexadecimal fomat) ") + std::string(args[1]); - os << "0x" << std::setw(4) << std::setfill('0') << std::hex << addr << " 0x" << std::setw(16) << myDet->setPatternWord(addr, -1, detPos) << std::dec; - } - } else if (cmd == "patioctrl") { - //get word from stdin - - if (action == PUT_ACTION) { - - if (sscanf(args[1], "%lx", &word)) - ; - else - return std::string("Could not scan value (hexadecimal fomat) ") + std::string(args[1]); - - myDet->setPatternIOControl(word, detPos); - } - - os << "0x" << std::setw(16) << std::setfill('0') << std::hex << myDet->setPatternIOControl(-1, detPos) << std::dec; - } else if (cmd == "patclkctrl") { - //get word from stdin - - if (action == PUT_ACTION) { - - if (sscanf(args[1], "%lx", &word)) - ; - else - return std::string("Could not scan value (hexadecimal fomat) ") + std::string(args[1]); - - myDet->setPatternClockControl(word, detPos); - } - - os << "0x" << std::setw(16) << std::setfill('0') << std::hex << myDet->setPatternClockControl(-1, detPos) << std::dec; - - } else if (cmd == "patlimits") { + if (cmd == "patlimits") { //get start, stop from stdin if (action == PUT_ACTION) { if (narg < 3) @@ -5056,123 +2523,6 @@ std::string slsDetectorCommand::cmdPattern(int narg, const char * const args[], os << "0x" << std::setw(16) << std::setfill('0') << std::hex << myDet->getPatternBitMask(detPos) << std::dec; - } else if (cmd == "adcenable") { - - if (action == PUT_ACTION) { - if (sscanf(args[1], "%x", &u32)) - ; - else - return std::string("Could not scan adcenable reg ") + std::string(args[1]); - - myDet->setADCEnableMask(u32, detPos); - } - - os << std::hex << myDet->getADCEnableMask(detPos) << std::dec; - } - // kept only for backwards compatibility, use adcenable - else if (cmd == "adcdisable") { - - if (action == PUT_ACTION) { - if (sscanf(args[1], "%x", &u32)) - ; - else - return std::string("Could not scan adcdisable reg ") + std::string(args[1]); - - // get enable mask from enable mask - u32 ^= BIT32_MASK; - myDet->setADCEnableMask(u32, detPos); - } - - u32 = myDet->getADCEnableMask(detPos); - // get disable mask - u32 ^= BIT32_MASK; - os << std::hex << u32 << std::dec; - - } else if (cmd == "adcinvert") { - if (action == PUT_ACTION) { - - if (sscanf(args[1], "%x", &u32)) - ; - else - return std::string("Could not scan adcinvert reg ") + std::string(args[1]); - - myDet->setADCInvert(u32, detPos); - } - - os << std::hex << myDet->getADCInvert(detPos) << std::dec; - - } else if (cmd == "extsamplingsrc") { - if (action == PUT_ACTION) { - - if (!sscanf(args[1], "%d", &addr)) - return std::string("Could not scan extsampling src ") + std::string(args[1]); - - if (addr < 0 || addr > 63) - return std::string("extsamplingsrc must be between 0 and 63. ") + std::string(args[1]); - - myDet->setExternalSamplingSource(addr, detPos); - } - - os << myDet->getExternalSamplingSource(detPos); - - } else if (cmd == "extsampling") { - if (action == PUT_ACTION) { - - if (!sscanf(args[1], "%d", &addr)) - return std::string("Could not scan extsampling enable ") + std::string(args[1]); - - myDet->setExternalSampling(addr, detPos); - } - - os << myDet->getExternalSampling(detPos); - - } else if (cmd == "rx_dbitlist") { - - - if (action == PUT_ACTION) { - std::vector dbitlist; - - // if not all digital bits enabled - if (std::string(args[1]) != "all") { - for (int i = 1; i < narg; ++i) { - int temp = 0; - if (!sscanf(args[i], "%d", &temp)) - return std::string("Could not scan dbitlist value ") + - std::string(args[i]); - if (temp < 0 || temp > 63) - return std::string("dbitlist value should be between 0 and 63 ") + - std::string(args[i]); - dbitlist.push_back(temp); - } - if (dbitlist.size() > 64) { - return std::string("Max number of values for dbitlist is 64 "); - } - } - - myDet->setReceiverDbitList(dbitlist, detPos); - } - - std::vector dbitlist = myDet->getReceiverDbitList(detPos); - // all digital bits enabled - if (dbitlist.empty()) - return std::string("all"); - // selective bits - for (const auto &value : dbitlist) - os << value << " "; - - } else if (cmd == "rx_dbitoffset") { - - - if (action == PUT_ACTION) { - - if (!sscanf(args[1], "%d", &addr)) - return std::string("Could not scan rx_dbitoffset enable ") + std::string(args[1]); - - myDet->setReceiverDbitOffset(addr, detPos); - } - - os << myDet->getReceiverDbitOffset(detPos); - } else @@ -5181,60 +2531,6 @@ std::string slsDetectorCommand::cmdPattern(int narg, const char * const args[], return os.str(); } -std::string slsDetectorCommand::helpPulse(int action) { - - std::ostringstream os; - if (action == PUT_ACTION || action == HELP_ACTION) { - os << "pulse [n] [x] [y] \t pulses pixel at coordinates (x,y) n number of times" << std::endl; - os << "pulsenmove [n] [x] [y]\t pulses pixel n number of times and moves relatively by x value (x axis) and y value(y axis)" << std::endl; - os << "pulsechip [n] \t pulses chip n number of times, while n=-1 will reset it to normal mode" << std::endl; - } - if (action == GET_ACTION || action == HELP_ACTION) { - os << "pulse \t cannot get" << std::endl; - os << "pulsenmove \t cannot get" << std::endl; - os << "pulsechip \t cannot get" << std::endl; - } - return os.str(); -} - -std::string slsDetectorCommand::cmdPulse(int narg, const char * const args[], int action, int detPos) { - - if (action == HELP_ACTION) - return helpPulse(action); - else if (action == GET_ACTION) - return std::string("cannot get ") + cmd; - - - int ival1 = -1; - if (!sscanf(args[1], "%d", &ival1)) - return std::string("Could not scan 1st argument ") + std::string(args[1]); - - if (std::string(args[0]) == std::string("pulsechip")) - myDet->pulseChip(ival1, detPos); - - else { - //next commands requires 3 addnl. arguments - int ival2 = -1, ival3 = -1; - if (narg < 4) - return std::string("insufficient arguments:\n" + helpPulse(action)); - if (!sscanf(args[2], "%d", &ival2)) - return std::string("Could not scan 2nd argument ") + std::string(args[2]); - if (!sscanf(args[3], "%d", &ival3)) - return std::string("Could not scan 3rd argument ") + std::string(args[3]); - - if (std::string(args[0]) == std::string("pulse")) - myDet->pulsePixel(ival1, ival2, ival3, detPos); - - else if (std::string(args[0]) == std::string("pulsenmove")) - myDet->pulsePixelNMove(ival1, ival2, ival3, detPos); - - else - std::string("could not decode command") + cmd; - } - - return std::string(" successful"); -} - std::string slsDetectorCommand::helpProcessor(int action) { diff --git a/slsDetectorSoftware/src/slsDetectorUsers.cpp b/slsDetectorSoftware/src/slsDetectorUsers.cpp index 4ce5222e2..e29ee00d0 100755 --- a/slsDetectorSoftware/src/slsDetectorUsers.cpp +++ b/slsDetectorSoftware/src/slsDetectorUsers.cpp @@ -143,8 +143,8 @@ int64_t slsDetectorUsers::setNumberOfFrames(int64_t t, int detPos){ return detector.setNumberOfFrames(t, detPos); } -int64_t slsDetectorUsers::setNumberOfCycles(int64_t t, int detPos){ - return detector.setNumberOfCycles(t, detPos); +int64_t slsDetectorUsers::setNumberOfTriggers(int64_t t, int detPos){ + return detector.setNumberOfTriggers(t, detPos); } int64_t slsDetectorUsers::setNumberOfStorageCells(int64_t t, int detPos) { diff --git a/slsDetectorSoftware/tests/test-multiSlsDetectorClient.cpp b/slsDetectorSoftware/tests/test-multiSlsDetectorClient.cpp index bc34ebe7b..45e3855e1 100644 --- a/slsDetectorSoftware/tests/test-multiSlsDetectorClient.cpp +++ b/slsDetectorSoftware/tests/test-multiSlsDetectorClient.cpp @@ -9,6 +9,2228 @@ auto GET = slsDetectorDefs::GET_ACTION; auto PUT = slsDetectorDefs::PUT_ACTION; +TEST_CASE("patword", "[.cmd][.ctb]") { + if (test::type == slsDetectorDefs::CHIPTESTBOARD) { + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("patword 0x23 0xc15004808d0a21a4", PUT, nullptr, oss)); + REQUIRE(oss.str() == "patword 0x23 0xc15004808d0a21a4\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("patword 0x23 0x0", PUT, nullptr, oss)); + REQUIRE(oss.str() == "patword 0x23 0x0\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("patword 0x23", GET, nullptr, oss)); + REQUIRE(oss.str() == "patword 0x23 0x0\n"); + } + } else { + REQUIRE_THROWS(multiSlsDetectorClient("patword 0x23", GET)); + } +} + +TEST_CASE("patclkctrl", "[.cmd][.ctb]") { + if (test::type == slsDetectorDefs::CHIPTESTBOARD) { + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("patclkctrl 0xc15004808d0a21a4", PUT, nullptr, oss)); + REQUIRE(oss.str() == "patclkctrl 0xc15004808d0a21a4\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("patclkctrl 0x0", PUT, nullptr, oss)); + REQUIRE(oss.str() == "patclkctrl 0x0\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("patclkctrl", GET, nullptr, oss)); + REQUIRE(oss.str() == "patclkctrl 0x0\n"); + } + } else { + REQUIRE_THROWS(multiSlsDetectorClient("patclkctrl", GET)); + } +} + + +TEST_CASE("patioctrl", "[.cmd][.ctb]") { + if (test::type == slsDetectorDefs::CHIPTESTBOARD) { + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("patioctrl 0xc15004808d0a21a4", PUT, nullptr, oss)); + REQUIRE(oss.str() == "patioctrl 0xc15004808d0a21a4\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("patioctrl 0x0", PUT, nullptr, oss)); + REQUIRE(oss.str() == "patioctrl 0x0\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("patioctrl", GET, nullptr, oss)); + REQUIRE(oss.str() == "patioctrl 0x0\n"); + } + } else { + REQUIRE_THROWS(multiSlsDetectorClient("patioctrl", GET)); + } +} + + +TEST_CASE("savepattern", "[.cmd][.ctb]") { + REQUIRE_THROWS(multiSlsDetectorClient("savepattern", GET)); + if (test::type == slsDetectorDefs::CHIPTESTBOARD) { + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("savepattern /tmp/pat.txt", PUT, nullptr, oss)); + REQUIRE(oss.str() == "savepattern /tmp/pat.txt\n"); + } + } else { + REQUIRE_THROWS(multiSlsDetectorClient("savepattern /tmp/pat.txt", PUT)); + } +} + +TEST_CASE("pattern", "[.cmd][.ctb]") { + REQUIRE_THROWS(multiSlsDetectorClient("pattern", GET)); + if (test::type == slsDetectorDefs::CHIPTESTBOARD) { + ;// todo test with real file? + } +} + +TEST_CASE("led", "[.cmd][.ctb]") { + if (test::type == slsDetectorDefs::CHIPTESTBOARD) { + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("led 1", PUT, nullptr, oss)); + REQUIRE(oss.str() == "led 1\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("led 0", PUT, nullptr, oss)); + REQUIRE(oss.str() == "led 0\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("led", GET, nullptr, oss)); + REQUIRE(oss.str() == "led 0\n"); + } + } else { + REQUIRE_THROWS(multiSlsDetectorClient("led", GET)); + } +} + + +TEST_CASE("diodelay", "[.cmd][.ctb]") { + if (test::type == slsDetectorDefs::CHIPTESTBOARD) { + REQUIRE_NOTHROW(multiSlsDetectorClient("diodelay 0x01010 125", PUT)); + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("diodelay 0x01010 775", PUT, nullptr, oss)); + REQUIRE(oss.str() == "diodelay 0x01010 775\n"); + } + REQUIRE_NOTHROW(multiSlsDetectorClient("diodelay 0x01010 0", PUT)); + REQUIRE_THROWS(multiSlsDetectorClient("diodelay 0x01010 776", PUT)); + } else { + REQUIRE_THROWS(multiSlsDetectorClient("diodelay", GET)); + } +} + + +TEST_CASE("rx_dbitoffset", "[.cmd][.ctb]") { + if (test::type == slsDetectorDefs::CHIPTESTBOARD) { + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("rx_dbitoffset 1", PUT, nullptr, oss)); + REQUIRE(oss.str() == "rx_dbitoffset 1\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("extsamplirx_dbitoffsetngsrc 0", PUT, nullptr, oss)); + REQUIRE(oss.str() == "rx_dbitoffset 0\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("rx_dbitoffset 15", PUT, nullptr, oss)); + REQUIRE(oss.str() == "rx_dbitoffset 15\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("rx_dbitoffset", GET, nullptr, oss)); + REQUIRE(oss.str() == "rx_dbitoffset 15\n"); + } + REQUIRE_NOTHROW(multiSlsDetectorClient("rx_dbitoffset 0", PUT)); + } else { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("rx_dbitoffset", GET, nullptr, oss)); + REQUIRE(oss.str() == "rx_dbitoffset 0\n"); + } +} + + +TEST_CASE("rx_dbitlist", "[.cmd][.ctb]") { + if (test::type == slsDetectorDefs::CHIPTESTBOARD) { + REQUIRE_NOTHROW(multiSlsDetectorClient("rx_dbitlist 0 4 5 8 9 10 52 63", PUT)); + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("0:rx_dbitlist", GET, nullptr, oss)); + REQUIRE(oss.str() == "rx_dbitlist [0, 4, 5, 8, 9, 10, 52, 63]\n"); + } + REQUIRE_NOTHROW(multiSlsDetectorClient("rx_dbitlist all", PUT)); + } else { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("rx_dbitlist", GET, nullptr, oss)); + REQUIRE(oss.str() == "rx_dbitlist []\n"); + } +} + +TEST_CASE("extsampling", "[.cmd][.ctb]") { + if (test::type == slsDetectorDefs::CHIPTESTBOARD) { + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("extsampling 1", PUT, nullptr, oss)); + REQUIRE(oss.str() == "extsampling 1\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("extsampling", GET, nullptr, oss)); + REQUIRE(oss.str() == "extsampling 1\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("extsampling 0", PUT, nullptr, oss)); + REQUIRE(oss.str() == "extsampling 0\n"); + } + } else { + REQUIRE_THROWS(multiSlsDetectorClient("extsampling", GET)); + } +} + +TEST_CASE("extsamplingsrc", "[.cmd][.ctb]") { + if (test::type == slsDetectorDefs::CHIPTESTBOARD) { + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("extsamplingsrc 1", PUT, nullptr, oss)); + REQUIRE(oss.str() == "extsamplingsrc 1\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("extsamplingsrc 0", PUT, nullptr, oss)); + REQUIRE(oss.str() == "extsamplingsrc 0\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("extsamplingsrc 15", PUT, nullptr, oss)); + REQUIRE(oss.str() == "extsamplingsrc 15\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("extsamplingsrc", GET, nullptr, oss)); + REQUIRE(oss.str() == "extsamplingsrc 15\n"); + } + REQUIRE_THROWS(multiSlsDetectorClient("extsamplingsrc 64", PUT)); + } else { + REQUIRE_THROWS(multiSlsDetectorClient("extsamplingsrc", GET)); + } +} + + +TEST_CASE("adcinvert", "[.cmd][.ctb]") { + if (test::type == slsDetectorDefs::CHIPTESTBOARD) { + std::string s; + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("adcinvert", GET, nullptr, oss)); + s = oss.str(); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("adcinvert 0x8d0a21d4", PUT, nullptr, oss)); + REQUIRE(oss.str() == "adcinvert 0x8d0a21d4\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient(s, PUT, nullptr, oss)); + REQUIRE(oss.str() == s); + } + } else { + REQUIRE_THROWS(multiSlsDetectorClient("adcinvert", GET)); + } +} + + +TEST_CASE("adcenable", "[.cmd][.ctb]") { + if (test::type == slsDetectorDefs::CHIPTESTBOARD) { + std::string s; + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("adcenable", GET, nullptr, oss)); + s = oss.str(); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("adcenable 0x8d0a21d4", PUT, nullptr, oss)); + REQUIRE(oss.str() == "adcenable 0x8d0a21d4\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient(s, PUT, nullptr, oss)); + REQUIRE(oss.str() == s); + } + } else { + REQUIRE_THROWS(multiSlsDetectorClient("adcenable", GET)); + } +} + + +TEST_CASE("vm_a", "[.cmd][.ctb]") { + if (test::type == slsDetectorDefs::CHIPTESTBOARD) { + REQUIRE_NOTHROW(multiSlsDetectorClient("vm_a", GET)); + REQUIRE_NOTHROW(multiSlsDetectorClient("vm_b", GET)); + REQUIRE_NOTHROW(multiSlsDetectorClient("vm_c", GET)); + REQUIRE_NOTHROW(multiSlsDetectorClient("vm_d", GET)); + REQUIRE_NOTHROW(multiSlsDetectorClient("vm_io", GET)); + REQUIRE_NOTHROW(multiSlsDetectorClient("im_a", GET)); + REQUIRE_NOTHROW(multiSlsDetectorClient("im_b", GET)); + REQUIRE_NOTHROW(multiSlsDetectorClient("im_c", GET)); + REQUIRE_NOTHROW(multiSlsDetectorClient("im_d", GET)); + REQUIRE_NOTHROW(multiSlsDetectorClient("im_io", GET)); + } else { + REQUIRE_THROWS(multiSlsDetectorClient("vm_a", GET)); + REQUIRE_THROWS(multiSlsDetectorClient("vm_b", GET)); + REQUIRE_THROWS(multiSlsDetectorClient("vm_c", GET)); + REQUIRE_THROWS(multiSlsDetectorClient("vm_d", GET)); + REQUIRE_THROWS(multiSlsDetectorClient("vm_io", GET)); + REQUIRE_THROWS(multiSlsDetectorClient("im_a", GET)); + REQUIRE_THROWS(multiSlsDetectorClient("im_b", GET)); + REQUIRE_THROWS(multiSlsDetectorClient("im_c", GET)); + REQUIRE_THROWS(multiSlsDetectorClient("im_d", GET)); + REQUIRE_THROWS(multiSlsDetectorClient("im_io", GET)); + } +} + +TEST_CASE("v_a", "[.cmd][.ctb]") { + if (test::type == slsDetectorDefs::CHIPTESTBOARD) { + std::string s; + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("0:v_limit", GET, nullptr, oss)); + s = oss.str(); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("v_limit 1000", PUT, nullptr, oss)); + REQUIRE(oss.str() == "vlimit 1000\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("v_limit", GET, nullptr, oss)); + REQUIRE(oss.str() == "vlimit 1000\n"); + } + REQUIRE_NOTHROW(multiSlsDetectorClient(s, PUT)); + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("0:v_a", GET, nullptr, oss)); + s = oss.str(); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient(s, PUT, nullptr, oss)); + REQUIRE(oss.str() == s); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("0:v_b", GET, nullptr, oss)); + s = oss.str(); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient(s, PUT, nullptr, oss)); + REQUIRE(oss.str() == s); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("0:v_c", GET, nullptr, oss)); + s = oss.str(); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient(s, PUT, nullptr, oss)); + REQUIRE(oss.str() == s); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("0:v_d", GET, nullptr, oss)); + s = oss.str(); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient(s, PUT, nullptr, oss)); + REQUIRE(oss.str() == s); + } + REQUIRE_NOTHROW(multiSlsDetectorClient("0:v_io", GET)); + REQUIRE_NOTHROW(multiSlsDetectorClient("0:v_chip", GET)); // do not set vchip + } else { + REQUIRE_THROWS(multiSlsDetectorClient("v_limit", GET)); + REQUIRE_THROWS(multiSlsDetectorClient("v_a", GET)); + REQUIRE_THROWS(multiSlsDetectorClient("v_b", GET)); + REQUIRE_THROWS(multiSlsDetectorClient("v_c", GET)); + REQUIRE_THROWS(multiSlsDetectorClient("v_d", GET)); + REQUIRE_THROWS(multiSlsDetectorClient("v_io", GET)); + REQUIRE_THROWS(multiSlsDetectorClient("v_chip", GET)); + } +} + +TEST_CASE("adcvpp", "[.cmd][.ctb]") { + if (test::type == slsDetectorDefs::CHIPTESTBOARD) { + int prev_val = 0; + { + std::ostringstream oss; + multiSlsDetectorClient("adcvpp", GET, nullptr, oss); + std::string s = (oss.str()).erase (0, strlen("adcvpp ")); + prev_val = std::stoi(s); + } + { + REQUIRE_NOTHROW(multiSlsDetectorClient("adcvpp 1", PUT)); + std::ostringstream oss; + multiSlsDetectorClient("adcvpp", GET, nullptr, oss); + REQUIRE(oss.str() == "adcvpp 1\n"); + } + { + REQUIRE_NOTHROW(multiSlsDetectorClient("adcvpp 1140 mv", PUT)); + std::ostringstream oss; + multiSlsDetectorClient("adcvpp", GET, nullptr, oss); + REQUIRE(oss.str() == "adcvpp 1140 mv\n"); + } + REQUIRE_NOTHROW(multiSlsDetectorClient("adcvpp " + std::to_string(prev_val), PUT)); + } else { + REQUIRE_THROWS(multiSlsDetectorClient("adcvpp", GET)); + } +} + + +TEST_CASE("dbitpipeline", "[.cmd][.ctb]") { + if (test::type == slsDetectorDefs::CHIPTESTBOARD) { + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("dbitpipeline 1", PUT, nullptr, oss)); + REQUIRE(oss.str() == "dbitpipeline 1\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("dbitpipeline 0", PUT, nullptr, oss)); + REQUIRE(oss.str() == "dbitpipeline 0\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("dbitpipeline 15", PUT, nullptr, oss)); + REQUIRE(oss.str() == "dbitpipeline 15\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("dbitpipeline", GET, nullptr, oss)); + REQUIRE(oss.str() == "dbitpipeline 15\n"); + } + REQUIRE_THROWS(multiSlsDetectorClient("dbitpipeline 16", PUT)); + } else { + REQUIRE_THROWS(multiSlsDetectorClient("dbitpipeline", GET)); + } +} + +TEST_CASE("adcpipeline", "[.cmd][.ctb]") { + if (test::type == slsDetectorDefs::CHIPTESTBOARD) { + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("adcpipeline 1", PUT, nullptr, oss)); + REQUIRE(oss.str() == "adcpipeline 1\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("adcpipeline 0", PUT, nullptr, oss)); + REQUIRE(oss.str() == "adcpipeline 0\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("adcpipeline 15", PUT, nullptr, oss)); + REQUIRE(oss.str() == "adcpipeline 15\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("adcpipeline", GET, nullptr, oss)); + REQUIRE(oss.str() == "adcpipeline 15\n"); + } + REQUIRE_THROWS(multiSlsDetectorClient("adcpipeline 16", PUT)); + } else { + REQUIRE_THROWS(multiSlsDetectorClient("adcpipeline", GET)); + } +} + +TEST_CASE("maxdbitphaseshift", "[.cmd][.ctb]") { + if (test::type == slsDetectorDefs::CHIPTESTBOARD ) { + REQUIRE_NOTHROW(multiSlsDetectorClient("maxdbitphaseshift", GET)); + } else { + REQUIRE_THROWS(multiSlsDetectorClient("maxdbitphaseshift", GET)); + + } +} + +TEST_CASE("dbitphase", "[.cmd][.ctb]") { + if (test::type != slsDetectorDefs::CHIPTESTBOARD) { + REQUIRE_THROWS(multiSlsDetectorClient("dbitphase", GET)); + } else { + int prev_val = 0; + { + std::ostringstream oss; + multiSlsDetectorClient("dbitphase", GET, nullptr, oss); + std::string s = (oss.str()).erase (0, strlen("dbitphase ")); + prev_val = std::stoi(s); + } + { + REQUIRE_NOTHROW(multiSlsDetectorClient("dbitphase 20", PUT)); + std::ostringstream oss; + multiSlsDetectorClient("dbitphase", GET, nullptr, oss); + REQUIRE(oss.str() == "dbitphase 20\n"); + } + { + REQUIRE_NOTHROW(multiSlsDetectorClient("dbitphase 0", PUT)); + std::ostringstream oss; + multiSlsDetectorClient("dbitphase", GET, nullptr, oss); + REQUIRE(oss.str() == "dbitphase 0\n"); + } + if (test::type != slsDetectorDefs::GOTTHARD) { + REQUIRE_THROWS(multiSlsDetectorClient("dbitphase deg", GET)); + } else { + REQUIRE_NOTHROW(multiSlsDetectorClient("dbitphase 20 deg", PUT)); + std::ostringstream oss; + multiSlsDetectorClient("dbitphase deg", GET, nullptr, oss); + REQUIRE(oss.str() == "dbitphase 20 deg\n"); + } + REQUIRE_NOTHROW(multiSlsDetectorClient("dbitphase " + std::to_string(prev_val), PUT)); + } +} + +TEST_CASE("romode", "[.cmd][.ctb]") { + if (test::type == slsDetectorDefs::CHIPTESTBOARD) { + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("romode digital", PUT, nullptr, oss)); + REQUIRE(oss.str() == "romode digital\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("romode analog_digital", PUT, nullptr, oss)); + REQUIRE(oss.str() == "romode analog_digital\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("romode analog", PUT, nullptr, oss)); + REQUIRE(oss.str() == "romode analog\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("romode", GET, nullptr, oss)); + REQUIRE(oss.str() == "romode analog\n"); + } + } else { + REQUIRE_THROWS(multiSlsDetectorClient("romode", GET)); + } +} + + +TEST_CASE("samples", "[.cmd][.ctb]") { + if (test::type == slsDetectorDefs::CHIPTESTBOARD) { + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("samples 1200", PUT, nullptr, oss)); + REQUIRE(oss.str() == "samples 1200n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("samples 1000", PUT, nullptr, oss)); + REQUIRE(oss.str() == "samples 1000\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("asamples 2200", PUT, nullptr, oss)); + REQUIRE(oss.str() == "asamples 2200n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("asamples 4000", PUT, nullptr, oss)); + REQUIRE(oss.str() == "asamples 4000\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("dsamples 1200", PUT, nullptr, oss)); + REQUIRE(oss.str() == "dsamples 1200n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("dsamples 1000", PUT, nullptr, oss)); + REQUIRE(oss.str() == "dsamples 1000\n"); + } + REQUIRE_THROWS(multiSlsDetectorClient("samples", GET)); // different values + } else { + REQUIRE_THROWS(multiSlsDetectorClient("samples", GET)); + REQUIRE_THROWS(multiSlsDetectorClient("asamples", GET)); + REQUIRE_THROWS(multiSlsDetectorClient("dsamples", GET)); + } +} + +TEST_CASE("imagetest", "[.cmd][.gotthard]") { + if (test::type == slsDetectorDefs::GOTTHARD) { + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("imagetest 1", PUT, nullptr, oss)); + REQUIRE(oss.str() == "imagetest 1\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("imagetest 0", PUT, nullptr, oss)); + REQUIRE(oss.str() == "imagetest 0\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("imagetest", GET, nullptr, oss)); + REQUIRE(oss.str() == "imagetest 0\n"); + } + } else { + REQUIRE_THROWS(multiSlsDetectorClient("imagetest", GET)); + } +} + +TEST_CASE("extsig", "[.cmd][.gotthard]") { + if (test::type == slsDetectorDefs::GOTTHARD) { + { + std::ostringstream oss; + multiSlsDetectorClient("extsig trigger_in_falling_edge", PUT, nullptr, oss); + REQUIRE(oss.str() == "extsig trigger_in_falling_edge\n"); + } + { + std::ostringstream oss; + multiSlsDetectorClient("extsig trigger_in_rising_edge", PUT, nullptr, oss); + REQUIRE(oss.str() == "extsig trigger_in_rising_edge\n"); + } + { + std::ostringstream oss; + multiSlsDetectorClient("extsig", GET, nullptr, oss); + REQUIRE(oss.str() == "extsig trigger_in_rising_edge\n"); + } + REQUIRE_NOTHROW(multiSlsDetectorClient("extsig gating", PUT)); + } else { + REQUIRE_THROWS(multiSlsDetectorClient("extsig", GET)); + } +} + + +TEST_CASE("exptimel", "[.cmd][.gotthard]") { + if (test::type == slsDetectorDefs::GOTTHARD) { + REQUIRE_NOTHROW(multiSlsDetectorClient("frames 1", PUT)); + REQUIRE_NOTHROW(multiSlsDetectorClient("exptime 5 s", PUT)); + REQUIRE_NOTHROW(multiSlsDetectorClient("start", PUT)); + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("0:exptimel s", GET, nullptr, oss)); + std::string st = oss.str(); + std::string s = st.erase (0, strlen("exptimel ")); + double val = std::stod(s); + REQUIRE(val >= 0); + REQUIRE(val < 1000); + } + REQUIRE_NOTHROW(multiSlsDetectorClient("stop", PUT)); + REQUIRE_NOTHROW(multiSlsDetectorClient("exptime 1 ms", PUT)); + } else { + REQUIRE_THROWS(multiSlsDetectorClient("exptimel", GET)); + } +} + + +TEST_CASE("periodl", "[.cmd][.gotthard]") { + if (test::type == slsDetectorDefs::GOTTHARD) { + REQUIRE_NOTHROW(multiSlsDetectorClient("frames 2", PUT)); + REQUIRE_NOTHROW(multiSlsDetectorClient("period 5", PUT)); + REQUIRE_NOTHROW(multiSlsDetectorClient("start", PUT)); + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("0:periodl s", GET, nullptr, oss)); + std::string st = oss.str(); + std::string s = st.erase (0, strlen("periodl ")); + double val = std::stod(s); + REQUIRE(val >= 0); + REQUIRE(val < 1000); + } + REQUIRE_NOTHROW(multiSlsDetectorClient("stop", PUT)); + REQUIRE_NOTHROW(multiSlsDetectorClient("period 1 s", PUT)); + } else { + REQUIRE_THROWS(multiSlsDetectorClient("periodl", GET)); + } +} + +TEST_CASE("roi", "[.cmd][.gotthard]") { + if (test::type == slsDetectorDefs::GOTTHARD) { + { + std::ostringstream oss; + multiSlsDetectorClient("roi 0 255", PUT, nullptr, oss); + REQUIRE(oss.str() == "roi [0, 255] \n"); + } + { + std::ostringstream oss; + multiSlsDetectorClient("roi 256 511", PUT, nullptr, oss); + REQUIRE(oss.str() == "roi [256, 511] \n"); + } + { + std::ostringstream oss; + multiSlsDetectorClient("clearroi", GET, nullptr, oss); + REQUIRE(oss.str() == "clearroi [-1, -1] \n"); + } + REQUIRE_THROWS(multiSlsDetectorClient("roi 0 256", PUT)); + } else { + REQUIRE_THROWS(multiSlsDetectorClient("roi", GET)); + } +} + +TEST_CASE("storagecell_delay", "[.cmd][.jungfrau]") { + if (test::type == slsDetectorDefs::JUNGFRAU) { + { + std::ostringstream oss; + multiSlsDetectorClient("storagecell_delay 2.25 ms", PUT, nullptr, oss); + REQUIRE(oss.str() == "storagecell_delay 2.25 ms\n"); + } + { + std::ostringstream oss; + multiSlsDetectorClient("storagecell_delay", GET, nullptr, oss); + REQUIRE(oss.str() == "storagecell_delay 2.25s\n"); + } + { + std::ostringstream oss; + multiSlsDetectorClient("storagecell_delay 0", PUT, nullptr, oss); + REQUIRE(oss.str() == "storagecell_delay 0\n"); + } + REQUIRE_THROWS(multiSlsDetectorClient("storagecell_delay 1638400 ns", PUT)); + } else { + REQUIRE_THROWS(multiSlsDetectorClient("storagecell_delay", GET)); + } +} + +TEST_CASE("storagecell_start", "[.cmd][.jungfrau]") { + if (test::type == slsDetectorDefs::JUNGFRAU) { + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("storagecell_start 1", PUT, nullptr, oss)); + REQUIRE(oss.str() == "storagecell_start 1\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("storagecell_start 0", PUT, nullptr, oss)); + REQUIRE(oss.str() == "storagecell_start 0\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("storagecell_start 15", PUT, nullptr, oss)); + REQUIRE(oss.str() == "storagecell_start 15\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("storagecell_start", GET, nullptr, oss)); + REQUIRE(oss.str() == "storagecell_start 15\n"); + } + REQUIRE_THROWS(multiSlsDetectorClient("storagecell_start 16", PUT)); + } else { + REQUIRE_THROWS(multiSlsDetectorClient("storagecell_start", GET)); + } +} + +TEST_CASE("storagecells", "[.cmd][.jungfrau]") { + if (test::type == slsDetectorDefs::JUNGFRAU) { + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("storagecells 1", PUT, nullptr, oss)); + REQUIRE(oss.str() == "storagecells 1\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("storagecells 15", PUT, nullptr, oss)); + REQUIRE(oss.str() == "storagecells 15\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("storagecells 0", PUT, nullptr, oss)); + REQUIRE(oss.str() == "storagecells 0\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("storagecells", GET, nullptr, oss)); + REQUIRE(oss.str() == "storagecells 0\n"); + } + REQUIRE_THROWS(multiSlsDetectorClient("storagecells 16", PUT)); + } else { + REQUIRE_THROWS(multiSlsDetectorClient("storagecells", GET)); + } +} + + +TEST_CASE("auto_comp_disable", "[.cmd][.jungfrau]") { + if (test::type == slsDetectorDefs::JUNGFRAU) { + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("auto_comp_disable 1", PUT, nullptr, oss)); + REQUIRE(oss.str() == "auto_comp_disable 1\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("auto_comp_disable 0", PUT, nullptr, oss)); + REQUIRE(oss.str() == "auto_comp_disable 0\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("auto_comp_disable", GET, nullptr, oss)); + REQUIRE(oss.str() == "auto_comp_disable 0\n"); + } + } else { + REQUIRE_THROWS(multiSlsDetectorClient("auto_comp_disable", GET)); + } +} + +TEST_CASE("powerchip", "[.cmd][.jungfrau]") { + if (test::type == slsDetectorDefs::JUNGFRAU) { + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("powerchip 1", PUT, nullptr, oss)); + REQUIRE(oss.str() == "powerchip 1\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("powerchip 0", PUT, nullptr, oss)); + REQUIRE(oss.str() == "powerchip 0\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("powerchip", GET, nullptr, oss)); + REQUIRE(oss.str() == "powerchip 0\n"); + } + } else { + REQUIRE_THROWS(multiSlsDetectorClient("powerchip", GET)); + } +} + +TEST_CASE("temp_", "[.cmd][.jungfrau]") { + if (test::type == slsDetectorDefs::JUNGFRAU) { + std::string s; + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("0:temp_threshold", GET, nullptr, oss)); + s = oss.str(); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient(s, PUT, nullptr, oss)); + REQUIRE(oss.str() == s); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("temp_control 1", PUT, nullptr, oss)); + REQUIRE(oss.str() == "temp_control 1\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("temp_control 0", PUT, nullptr, oss)); + REQUIRE(oss.str() == "temp_control 0\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("temp_control", GET, nullptr, oss)); + REQUIRE(oss.str() == "temp_control 0\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("temp_event", GET, nullptr, oss)); + REQUIRE(oss.str() == "temp_event 0\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("temp_event 0", PUT, nullptr, oss)); + REQUIRE(oss.str() == "temp_event 0\n"); + } + REQUIRE_THROWS(multiSlsDetectorClient("temp_event 1", PUT)); + } else { + REQUIRE_THROWS(multiSlsDetectorClient("temp_threshold", GET)); + REQUIRE_THROWS(multiSlsDetectorClient("temp_control", GET)); + REQUIRE_THROWS(multiSlsDetectorClient("temp_event", GET)); + } +} + +TEST_CASE("quad", "[.cmd][.eiger]") { + if (test::type == slsDetectorDefs::EIGER) { + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("quad", GET, nullptr, oss)); + REQUIRE(oss.str() == "quad 0\n"); + } + REQUIRE_NOTHROW(multiSlsDetectorClient("quad 0", PUT)); + } else { + REQUIRE_THROWS(multiSlsDetectorClient("quad", GET)); + } +} + + + + +TEST_CASE("pulse", "[.cmd][.eiger]") { + REQUIRE_THROWS(multiSlsDetectorClient("pulse", GET)); + REQUIRE_THROWS(multiSlsDetectorClient("pulsenmove", GET)); + REQUIRE_THROWS(multiSlsDetectorClient("pulsechip", GET)); + if (test::type == slsDetectorDefs::EIGER) { + REQUIRE_NOTHROW(multiSlsDetectorClient("pulse 1 1 5", PUT)); + REQUIRE_NOTHROW(multiSlsDetectorClient("pulsenmove 1 1 5", PUT)); + REQUIRE_NOTHROW(multiSlsDetectorClient("pulsechip 1", PUT)); + } else { + REQUIRE_THROWS(multiSlsDetectorClient("pulse 1 1 5", PUT)); + REQUIRE_THROWS(multiSlsDetectorClient("pulsenmove 1 1 5", PUT)); + REQUIRE_THROWS(multiSlsDetectorClient("pulsechip 1", PUT)); + } +} + + +TEST_CASE("partialreset", "[.cmd][.eiger]") { + if (test::type == slsDetectorDefs::EIGER) { + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("partialreset 1", PUT, nullptr, oss)); + REQUIRE(oss.str() == "partialreset 1\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("partialreset", GET, nullptr, oss)); + REQUIRE(oss.str() == "partialreset 1\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("partialreset 0", PUT, nullptr, oss)); + REQUIRE(oss.str() == "partialreset 0\n"); + } + REQUIRE_NOTHROW(multiSlsDetectorClient("partialreset 1", PUT)); + } else { + REQUIRE_THROWS(multiSlsDetectorClient("partialreset", GET)); + } +} + + +TEST_CASE("activate", "[.cmd][.eiger]") { + if (test::type == slsDetectorDefs::EIGER) { + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("0:activate 1", PUT, nullptr, oss)); + REQUIRE(oss.str() == "activate 1\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("0:activate 1 nopadding", PUT, nullptr, oss)); + REQUIRE(oss.str() == "activate 1 nopadding\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("0:activate 0 padding", PUT, nullptr, oss)); + REQUIRE(oss.str() == "activate 0 padding\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("0:activate 0 nopadding", PUT, nullptr, oss)); + REQUIRE(oss.str() == "activate 0 nopadding\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("0:activate 1 padding", PUT, nullptr, oss)); + REQUIRE(oss.str() == "activate 1 padding\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("0:activate", GET, nullptr, oss)); + REQUIRE(oss.str() == "activate 1 padding\n"); + } + } else { + REQUIRE_THROWS(multiSlsDetectorClient("activate", GET)); + } +} + +TEST_CASE("measuredsubperiod", "[.cmd][.eiger]") { + if (test::type == slsDetectorDefs::EIGER) { + REQUIRE_NOTHROW(multiSlsDetectorClient("frames 1", PUT)); + REQUIRE_NOTHROW(multiSlsDetectorClient("dr 32", PUT)); + REQUIRE_NOTHROW(multiSlsDetectorClient("start", PUT)); + sleep(3); + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("0:measuredsubperiod ms", GET, nullptr, oss)); + std::string st = oss.str(); + std::string s = st.erase (0, strlen("measuredsubperiod ")); + double val = std::stod(s); + REQUIRE(val >= 0); + REQUIRE(val < 1000); + } + REQUIRE_NOTHROW(multiSlsDetectorClient("dr 16", PUT)); + } else { + REQUIRE_THROWS(multiSlsDetectorClient("measuredsubperiod", GET)); + } +} + +TEST_CASE("measuredperiod", "[.cmd][.eiger]") { + if (test::type == slsDetectorDefs::EIGER) { + REQUIRE_NOTHROW(multiSlsDetectorClient("frames 2", PUT)); + REQUIRE_NOTHROW(multiSlsDetectorClient("period 1", PUT)); + REQUIRE_NOTHROW(multiSlsDetectorClient("start", PUT)); + sleep(3); + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("0:measuredperiod", GET, nullptr, oss)); + std::string st = oss.str(); + std::string s = st.erase (0, strlen("measuredperiod ")); + double val = std::stod(s); + REQUIRE(val >= 1.0); + REQUIRE(val < 2.0); + } + } else { + REQUIRE_THROWS(multiSlsDetectorClient("measuredperiod", GET)); + } +} + +TEST_CASE("interruptsubframe", "[.cmd][.eiger]") { + if (test::type == slsDetectorDefs::EIGER) { + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("interruptsubframe 1", PUT, nullptr, oss)); + REQUIRE(oss.str() == "interruptsubframe 1\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("interruptsubframe", GET, nullptr, oss)); + REQUIRE(oss.str() == "interruptsubframe 1\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("interruptsubframe 0", PUT, nullptr, oss)); + REQUIRE(oss.str() == "interruptsubframe 0\n"); + } + } else { + REQUIRE_THROWS(multiSlsDetectorClient("interruptsubframe", GET)); + } +} + +TEST_CASE("readnlines", "[.cmd][.eiger]") { + if (test::type == slsDetectorDefs::EIGER) { + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("readnlines 256", PUT, nullptr, oss)); + REQUIRE(oss.str() == "readnlines 256\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("readnlines", GET, nullptr, oss)); + REQUIRE(oss.str() == "readnlines 256\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("readnlines 16", PUT, nullptr, oss)); + REQUIRE(oss.str() == "readnlines 16\n"); + } + REQUIRE_THROWS(multiSlsDetectorClient("readnlines 0", PUT)); + REQUIRE_NOTHROW(multiSlsDetectorClient("readnlines 256", PUT)); + } else { + REQUIRE_THROWS(multiSlsDetectorClient("readnlines", GET)); + } +} + + +TEST_CASE("ratecorr", "[.cmd][.eiger]") { + if (test::type == slsDetectorDefs::EIGER) { + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("ratecorr 120", PUT, nullptr, oss)); + REQUIRE(oss.str() == "ratecorr 120ns\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("ratecorr", GET, nullptr, oss)); + REQUIRE(oss.str() == "ratecorr 120ns\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("ratecorr 0", PUT, nullptr, oss)); + REQUIRE(oss.str() == "ratecorr 0ns\n"); + } + REQUIRE_NOTHROW(multiSlsDetectorClient("ratecorr -1", PUT)); + REQUIRE_NOTHROW(multiSlsDetectorClient("ratecorr 0", PUT)); + } else { + REQUIRE_THROWS(multiSlsDetectorClient("ratecorr", GET)); + } +} + + +TEST_CASE("trimen", "[.cmd][.eiger]") { + if (test::type == slsDetectorDefs::EIGER) { + REQUIRE_NOTHROW(multiSlsDetectorClient("trimen 4500 5400 6400", PUT)); + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("0:trimen", GET, nullptr, oss)); + REQUIRE(oss.str() == "trimen [4500, 5400, 6400]\n"); + } + } else { + REQUIRE_THROWS(multiSlsDetectorClient("trimen", GET)); + } +} + +TEST_CASE("trimval", "[.cmd][.eiger]") { + if (test::type == slsDetectorDefs::EIGER) { + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("trimval 63", PUT, nullptr, oss)); + REQUIRE(oss.str() == "trimval 63\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("trimval", GET, nullptr, oss)); + REQUIRE(oss.str() == "trimval 63\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("trimval 31", PUT, nullptr, oss)); + REQUIRE(oss.str() == "trimval 31\n"); + } + REQUIRE_NOTHROW(multiSlsDetectorClient("trimval 0", PUT)); + } else { + REQUIRE_THROWS(multiSlsDetectorClient("trimval", GET)); + } +} + + + +TEST_CASE("flippeddatax", "[.cmd][.eiger]") { + if (test::type == slsDetectorDefs::EIGER) { + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("0:flippeddatax", GET, nullptr, oss)); + REQUIRE(oss.str() == "flippeddatax 0\n"); + } + multiSlsDetector d; + if (d.size() > 1) { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("1:flippeddatax", GET, nullptr, oss)); + REQUIRE(oss.str() == "flippeddatax 1\n"); + } + } else { + REQUIRE_THROWS(multiSlsDetectorClient("flippeddatax", GET)); + } +} + + +TEST_CASE("storeinram", "[.cmd][.eiger]") { + if (test::type == slsDetectorDefs::EIGER) { + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("storeinram 1", PUT, nullptr, oss)); + REQUIRE(oss.str() == "storeinram 1\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("storeinram", GET, nullptr, oss)); + REQUIRE(oss.str() == "storeinram 1\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("storeinram 0", PUT, nullptr, oss)); + REQUIRE(oss.str() == "storeinram 0\n"); + } + } else { + REQUIRE_THROWS(multiSlsDetectorClient("storeinram", GET)); + } +} + + +TEST_CASE("overflow", "[.cmd][.eiger]") { + if (test::type == slsDetectorDefs::EIGER) { + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("overflow 1", PUT, nullptr, oss)); + REQUIRE(oss.str() == "overflow 1\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("overflow", GET, nullptr, oss)); + REQUIRE(oss.str() == "overflow 1\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("overflow 0", PUT, nullptr, oss)); + REQUIRE(oss.str() == "overflow 0\n"); + } + } else { + REQUIRE_THROWS(multiSlsDetectorClient("overflow", GET)); + } +} + +TEST_CASE("parallel", "[.cmd][.eiger]") { + if (test::type == slsDetectorDefs::EIGER) { + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("parallel 1", PUT, nullptr, oss)); + REQUIRE(oss.str() == "parallel 1\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("parallel", GET, nullptr, oss)); + REQUIRE(oss.str() == "parallel 1\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("parallel 0", PUT, nullptr, oss)); + REQUIRE(oss.str() == "parallel 0\n"); + } + } else { + REQUIRE_THROWS(multiSlsDetectorClient("parallel", GET)); + } +} + + +TEST_CASE("gappixels", "[.cmd][.eiger]") { + if (test::type == slsDetectorDefs::EIGER) { + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("gappixels 1", PUT, nullptr, oss)); + REQUIRE(oss.str() == "gappixels 1\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("gappixels", GET, nullptr, oss)); + REQUIRE(oss.str() == "gappixels 1\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("gappixels 0", PUT, nullptr, oss)); + REQUIRE(oss.str() == "gappixels 0\n"); + } + } else { + REQUIRE_THROWS(multiSlsDetectorClient("gappixels", GET)); + } +} + +TEST_CASE("settingspath", "[.cmd][.eiger]") { + std::string s; + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("settingspath", GET, nullptr, oss)); + s = oss.str(); + REQUIRE_NOTHROW(multiSlsDetectorClient(s, PUT)); +} + + +TEST_CASE("subdeadtime", "[.cmd][.eiger]") { + if (test::type == slsDetectorDefs::EIGER) { + std::string s; + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("subdeadtime", GET, nullptr, oss)); + s = oss.str(); + REQUIRE_NOTHROW(multiSlsDetectorClient(s, PUT)); + } else { + REQUIRE_THROWS(multiSlsDetectorClient("subdeadtime", GET)); + } +} + +TEST_CASE("subexptime", "[.cmd][.eiger]") { + if (test::type == slsDetectorDefs::EIGER) { + std::string s; + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("subexptime", GET, nullptr, oss)); + s = oss.str(); + REQUIRE_NOTHROW(multiSlsDetectorClient(s, PUT)); + } else { + REQUIRE_THROWS(multiSlsDetectorClient("subexptime", GET)); + } +} + + +TEST_CASE("dr", "[.cmd][.eiger]") { + if (test::type == slsDetectorDefs::EIGER) { + int vals[4] = {4, 8, 16, 32}; + for (int i = 0; i < 4; ++i) { + REQUIRE_NOTHROW(multiSlsDetectorClient("dr " + std::to_string(vals[i]), PUT)); + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("dr", GET, nullptr, oss)); + REQUIRE(oss.str() == "dr " + std::to_string(vals[i]) + '\n'); + } + } else { + REQUIRE_THROWS(multiSlsDetectorClient("dr 4", PUT)); + REQUIRE_THROWS(multiSlsDetectorClient("dr 8", PUT)); + REQUIRE_THROWS(multiSlsDetectorClient("dr 32", PUT)); + REQUIRE_NOTHROW(multiSlsDetectorClient("dr 16", PUT)); + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("dr", GET, nullptr, oss)); + REQUIRE(oss.str() == "dr " + std::to_string(16) + '\n'); + } + } +} + + +TEST_CASE("zmqip", "[.cmd]") { + std::string s; + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("0:zmqip", GET, nullptr, oss)); + s = oss.str(); + } + { + REQUIRE_NOTHROW(multiSlsDetectorClient(s, PUT)); + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("0:zmqip", GET, nullptr, oss)); + REQUIRE(oss.str() == s); + } +} + +TEST_CASE("rx_zmqip", "[.cmd]") { + std::string s; + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("0:rx_zmqip", GET, nullptr, oss)); + s = oss.str(); + } + { + REQUIRE_NOTHROW(multiSlsDetectorClient(s, PUT)); + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("0:rx_zmqip", GET, nullptr, oss)); + REQUIRE(oss.str() == s); + } +} + + +TEST_CASE("zmqport", "[.cmd]") { + multiSlsDetector d; + int socketsperdetector = 1; + if (test::type == slsDetectorDefs::EIGER) { + socketsperdetector *= 2; + } else if (test::type == slsDetectorDefs::JUNGFRAU) { + REQUIRE_NOTHROW(multiSlsDetectorClient("numinterfaces 2", PUT)); + socketsperdetector *= 2; + } + int port = 3500; + REQUIRE_NOTHROW(multiSlsDetectorClient("zmqport " + std::to_string(port), PUT)); + for (size_t i = 0; i != d.size(); ++i) { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient(std::to_string(i) + ":zmqport", GET, nullptr, oss)); + REQUIRE(oss.str() == "zmqport " + std::to_string(port + i * socketsperdetector) + '\n'); + } + port = 1954; + REQUIRE_NOTHROW(multiSlsDetectorClient("zmqport " + std::to_string(port), PUT)); + for (size_t i = 0; i != d.size(); ++i) { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient(std::to_string(i) + ":zmqport", GET, nullptr, oss)); + REQUIRE(oss.str() == "zmqport " + std::to_string(port + i * socketsperdetector) + '\n'); + } + if (test::type == slsDetectorDefs::JUNGFRAU) { + REQUIRE_NOTHROW(multiSlsDetectorClient("numinterfaces 1", PUT)); + } +} + +TEST_CASE("rx_zmqport", "[.cmd]") { + multiSlsDetector d; + int socketsperdetector = 1; + if (test::type == slsDetectorDefs::EIGER) { + socketsperdetector *= 2; + } else if (test::type == slsDetectorDefs::JUNGFRAU) { + REQUIRE_NOTHROW(multiSlsDetectorClient("numinterfaces 2", PUT)); + socketsperdetector *= 2; + } + int port = 3500; + multiSlsDetectorClient("rx_zmqport " + std::to_string(port), PUT); + for (size_t i = 0; i != d.size(); ++i) { + std::ostringstream oss; + multiSlsDetectorClient(std::to_string(i) + ":rx_zmqport", GET, nullptr, oss); + REQUIRE(oss.str() == "rx_zmqport " + std::to_string(port + i * socketsperdetector) + '\n'); + } + port = 1954; + multiSlsDetectorClient("rx_zmqport " + std::to_string(port), PUT); + for (size_t i = 0; i != d.size(); ++i) { + std::ostringstream oss; + multiSlsDetectorClient(std::to_string(i) + ":rx_zmqport", GET, nullptr, oss); + REQUIRE(oss.str() == "rx_zmqport " + std::to_string(port + i * socketsperdetector) + '\n'); + } + if (test::type == slsDetectorDefs::JUNGFRAU) { + REQUIRE_NOTHROW(multiSlsDetectorClient("numinterfaces 1", PUT)); + } +} + +TEST_CASE("rx_datastream", "[.cmd]") { + { + std::ostringstream oss; + multiSlsDetectorClient("rx_datastream 1", PUT, nullptr, oss); + REQUIRE(oss.str() == "rx_datastream 1\n"); + } + { + std::ostringstream oss; + multiSlsDetectorClient("rx_datastream", GET, nullptr, oss); + REQUIRE(oss.str() == "rx_datastream 1\n"); + } + { + std::ostringstream oss; + multiSlsDetectorClient("rx_datastream 0", PUT, nullptr, oss); + REQUIRE(oss.str() == "rx_datastream 0\n"); + } +} + +TEST_CASE("fpath", "[.cmd]") { + std::string s; + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("0:fpath", GET, nullptr, oss)); + s = oss.str(); + } + { + REQUIRE_NOTHROW(multiSlsDetectorClient(s, PUT)); + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("fpath", GET, nullptr, oss)); + REQUIRE(oss.str() == s); + } +} + +TEST_CASE("fformat", "[.cmd]") { + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("fformat", GET, nullptr, oss)); + REQUIRE(oss.str() == "fformat binary\n"); + } +} + + +TEST_CASE("rx_hostname", "[.cmd]") { + std::string s; + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("0:rx_hostname", GET, nullptr, oss)); + s = oss.str(); + } + { + REQUIRE_NOTHROW(multiSlsDetectorClient(s, PUT)); + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("0:rx_hostname", GET, nullptr, oss)); + REQUIRE(oss.str() == s); + } + // save rx_hostame's ip somewhere (getent hosts [rx_hostname]) + { + REQUIRE_NOTHROW(multiSlsDetectorClient("rx_hostname 129.129.205.80", PUT)); + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("0:rx_hostname", GET, nullptr, oss)); + REQUIRE(oss.str() == "rx_hostname 129.129.205.80\n"); + } + { + REQUIRE_NOTHROW(multiSlsDetectorClient("rx_hostname none", PUT)); + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("0:rx_hostname", GET, nullptr, oss)); + REQUIRE(oss.str() == "rx_hostname none\n"); + } +} + +TEST_CASE("txndelay", "[.cmd][.eiger][.jungfrau]") { + if (test::type == slsDetectorDefs::EIGER) { + { + REQUIRE_NOTHROW(multiSlsDetectorClient("0:txndelay_frame 50000", PUT)); + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("0:txndelay_frame", GET, nullptr, oss)); + REQUIRE(oss.str() == "txndelay_frame 50000\n"); + } + { + REQUIRE_NOTHROW(multiSlsDetectorClient("txndelay_frame 0", PUT)); + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("0:txndelay_frame", GET, nullptr, oss)); + REQUIRE(oss.str() == "txndelay_frame 0\n"); + } + { + REQUIRE_NOTHROW(multiSlsDetectorClient("0:txndelay_left 50000", PUT)); + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("0:txndelay_left", GET, nullptr, oss)); + REQUIRE(oss.str() == "txndelay_left 50000\n"); + } + { + REQUIRE_NOTHROW(multiSlsDetectorClient("txndelay_left 0", PUT)); + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("0:txndelay_left", GET, nullptr, oss)); + REQUIRE(oss.str() == "txndelay_left 0\n"); + } + { + REQUIRE_NOTHROW(multiSlsDetectorClient("0:txndelay_right 50000", PUT)); + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("0:txndelay_right", GET, nullptr, oss)); + REQUIRE(oss.str() == "txndelay_right 50000\n"); + } + { + REQUIRE_NOTHROW(multiSlsDetectorClient("txndelay_right 0", PUT)); + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("0:txndelay_right", GET, nullptr, oss)); + REQUIRE(oss.str() == "txndelay_right 0\n"); + } + } else if (test::type == slsDetectorDefs::JUNGFRAU) { + { + REQUIRE_NOTHROW(multiSlsDetectorClient("txndelay_frame 5", PUT)); + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("0:txndelay_frame", GET, nullptr, oss)); + REQUIRE(oss.str() == "txndelay_frame 5\n"); + } + { + REQUIRE_NOTHROW(multiSlsDetectorClient("txndelay_frame 0", PUT)); + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("0:txndelay_frame", GET, nullptr, oss)); + REQUIRE(oss.str() == "txndelay_frame 0\n"); + } + REQUIRE_THROWS(multiSlsDetectorClient("txndelay_frame 32", PUT)); + REQUIRE_THROWS(multiSlsDetectorClient("txndelay_left 32", PUT)); + REQUIRE_THROWS(multiSlsDetectorClient("txndelay_right 32", PUT)); + } else { + REQUIRE_THROWS(multiSlsDetectorClient("txndelay_frame", GET)); + REQUIRE_THROWS(multiSlsDetectorClient("txndelay_left 32", PUT)); + REQUIRE_THROWS(multiSlsDetectorClient("txndelay_right 32", PUT)); + } +} + + +TEST_CASE("flowcontrol_10g", "[.cmd][.eiger][.jungfrau]") { + if (test::type == slsDetectorDefs::EIGER || test::type == slsDetectorDefs::JUNGFRAU) { + { + REQUIRE_NOTHROW(multiSlsDetectorClient("flowcontrol_10g 1", PUT)); + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("0:flowcontrol_10g", GET, nullptr, oss)); + REQUIRE(oss.str() == "flowcontrol_10g 1\n"); + } + { + REQUIRE_NOTHROW(multiSlsDetectorClient("flowcontrol_10g 0", PUT)); + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("0:flowcontrol_10g", GET, nullptr, oss)); + REQUIRE(oss.str() == "flowcontrol_10g 0\n"); + } + } else { + REQUIRE_THROWS(multiSlsDetectorClient("flowcontrol_10g", GET)); + } +} + +TEST_CASE("tengiga", "[.cmd][.eiger][.ctb]") { + if (test::type == slsDetectorDefs::EIGER || test::type == slsDetectorDefs::CHIPTESTBOARD) { + { + REQUIRE_NOTHROW(multiSlsDetectorClient("tengiga 1", PUT)); + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("0:tengiga", GET, nullptr, oss)); + REQUIRE(oss.str() == "tengiga 1\n"); + } + { + REQUIRE_NOTHROW(multiSlsDetectorClient("tengiga 0", PUT)); + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("0:tengiga", GET, nullptr, oss)); + REQUIRE(oss.str() == "tengiga 0\n"); + } + } else { + REQUIRE_THROWS(multiSlsDetectorClient("tengiga", GET)); + } +} + +TEST_CASE("rx_printconfig", "[.cmd]") { + REQUIRE_NOTHROW(multiSlsDetectorClient("rx_printconfig", GET)); +} + +TEST_CASE("network", "[.cmd]") { + { + REQUIRE_NOTHROW(multiSlsDetectorClient("0:udp_srcip 129.129.202.84", PUT)); + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("0:udp_srcip", GET, nullptr, oss)); + REQUIRE(oss.str() == "udp_srcip 129.129.202.84\n"); + } + std::string udp_dstip; + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("0:udp_dstip", GET, nullptr, oss)); + udp_dstip = oss.str(); + } + { + REQUIRE_NOTHROW(multiSlsDetectorClient(udp_dstip, PUT)); + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("0:udp_dstip", GET, nullptr, oss)); + REQUIRE(oss.str() == udp_dstip); + } + { + REQUIRE_NOTHROW(multiSlsDetectorClient("0:udp_dstmac 10:e7:c6:48:bd:3f", PUT)); + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("0:udp_dstmac", GET, nullptr, oss)); + REQUIRE(oss.str() == "udp_dstmac 10:e7:c6:48:bd:3f\n"); + } + { + REQUIRE_NOTHROW(multiSlsDetectorClient("0:udp_dstport 6200", PUT)); + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("0:udp_dstport", GET, nullptr, oss)); + REQUIRE(oss.str() == "udp_dstport 6200\n"); + } + { + multiSlsDetector d; + int socketsperdetector = 1; + if (test::type == slsDetectorDefs::EIGER) { + socketsperdetector *= 2; + } else if (test::type == slsDetectorDefs::JUNGFRAU) { + REQUIRE_NOTHROW(multiSlsDetectorClient("numinterfaces 2", PUT)); + socketsperdetector *= 2; + } + int port = 5500; + REQUIRE_NOTHROW(multiSlsDetectorClient("udp_dstport " + std::to_string(port), PUT)); + for (size_t i = 0; i != d.size(); ++i) { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient(std::to_string(i) + ":udp_dstport", GET, nullptr, oss)); + REQUIRE(oss.str() == "udp_dstport " + std::to_string(port + i * socketsperdetector) + '\n'); + } + port = 1954; + REQUIRE_NOTHROW(multiSlsDetectorClient("udp_dstport " + std::to_string(port), PUT)); + for (size_t i = 0; i != d.size(); ++i) { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient(std::to_string(i) + ":udp_dstport", GET, nullptr, oss)); + REQUIRE(oss.str() == "udp_dstport " + std::to_string(port + i * socketsperdetector) + '\n'); + } + if (test::type == slsDetectorDefs::JUNGFRAU) { + REQUIRE_NOTHROW(multiSlsDetectorClient("numinterfaces 1", PUT)); + } + } + REQUIRE_THROWS(multiSlsDetectorClient("udp_srcip 0.0.0.0", PUT)); + REQUIRE_THROWS(multiSlsDetectorClient("udp_srcip 124586954", PUT)); + REQUIRE_THROWS(multiSlsDetectorClient("udp_srcip 999.999.0.0.0.5", PUT)); + + if (test::type == slsDetectorDefs::JUNGFRAU) { + { + REQUIRE_NOTHROW(multiSlsDetectorClient("0:udp_srcip2 129.129.202.84", PUT)); + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("0:udp_srcip2", GET, nullptr, oss)); + REQUIRE(oss.str() == "udp_srcip2 129.129.202.84\n"); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("0:udp_dstip2", GET, nullptr, oss)); + udp_dstip = oss.str(); + } + { + REQUIRE_NOTHROW(multiSlsDetectorClient(udp_dstip, PUT)); + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("0:udp_dstip2", GET, nullptr, oss)); + REQUIRE(oss.str() == udp_dstip); + } + { + REQUIRE_NOTHROW(multiSlsDetectorClient("0:udp_dstmac2 10:e7:c6:48:bd:3f", PUT)); + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("0:udp_dstmac2", GET, nullptr, oss)); + REQUIRE(oss.str() == "udp_dstmac2 10:e7:c6:48:bd:3f\n"); + } + { + REQUIRE_NOTHROW(multiSlsDetectorClient("0:udp_dstport2 6400", PUT)); + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("0:udp_dstport2", GET, nullptr, oss)); + REQUIRE(oss.str() == "udp_dstport2 6400\n"); + } + } else if (test::type == slsDetectorDefs::EIGER) { + { + REQUIRE_NOTHROW(multiSlsDetectorClient("0:udp_dstport2 6400", PUT)); + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("0:udp_dstport2", GET, nullptr, oss)); + REQUIRE(oss.str() == "udp_dstport2 6400\n"); + } + } else { + REQUIRE_THROWS(multiSlsDetectorClient("udp_srcip2", GET)); + REQUIRE_THROWS(multiSlsDetectorClient("udp_dstip2", GET)); + REQUIRE_THROWS(multiSlsDetectorClient("udp_srcmac2", GET)); + REQUIRE_THROWS(multiSlsDetectorClient("udp_dstmac2", GET)); + REQUIRE_THROWS(multiSlsDetectorClient("udp_dstport2", GET)); + } +} + + +TEST_CASE("selinterface", "[.cmd][.jungfrau]") { + if (test::type == slsDetectorDefs::JUNGFRAU) { + REQUIRE_NOTHROW(multiSlsDetectorClient("numinterfaces 1", PUT)); + { + REQUIRE_NOTHROW(multiSlsDetectorClient("selinterface 0", PUT)); + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("0:selinterface", GET, nullptr, oss)); + REQUIRE(oss.str() == "selinterface 0\n"); + } + { + REQUIRE_NOTHROW(multiSlsDetectorClient("selinterface 1", PUT)); + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("0:selinterface", GET, nullptr, oss)); + REQUIRE(oss.str() == "selinterface 1\n"); + } + REQUIRE_THROWS(multiSlsDetectorClient("selinterface 2", PUT)); + } else { + REQUIRE_THROWS(multiSlsDetectorClient("selinterface", GET)); + } +} + +TEST_CASE("numinterfaces", "[.cmd][.jungfrau]") { + if (test::type == slsDetectorDefs::JUNGFRAU) { + { + REQUIRE_NOTHROW(multiSlsDetectorClient("numinterfaces 2", PUT)); + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("0:numinterfaces", GET, nullptr, oss)); + REQUIRE(oss.str() == "numinterfaces 2\n"); + } + { + REQUIRE_NOTHROW(multiSlsDetectorClient("numinterfaces 1", PUT)); + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("0:numinterfaces", GET, nullptr, oss)); + REQUIRE(oss.str() == "numinterfaces 1\n"); + } + } else { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("0:numinterfaces", GET, nullptr, oss)); + REQUIRE(oss.str() == "numinterfaces 1\n"); + } + REQUIRE_THROWS(multiSlsDetectorClient("numinterfaces 3", PUT)); + REQUIRE_THROWS(multiSlsDetectorClient("numinterfaces 0", PUT)); +} + +TEST_CASE("timing", "[.cmd]") { + { + REQUIRE_NOTHROW(multiSlsDetectorClient("timing auto", PUT)); + std::ostringstream oss; + multiSlsDetectorClient("timing", GET, nullptr, oss); + REQUIRE(oss.str() == "timing auto\n"); + } + { + REQUIRE_NOTHROW(multiSlsDetectorClient("timing trigger", PUT)); + std::ostringstream oss; + multiSlsDetectorClient("timing", GET, nullptr, oss); + REQUIRE(oss.str() == "timing trigger\n"); + } + if (test::type == slsDetectorDefs::EIGER) { + { + REQUIRE_NOTHROW(multiSlsDetectorClient("timing gating", PUT)); + std::ostringstream oss; + multiSlsDetectorClient("timing", GET, nullptr, oss); + REQUIRE(oss.str() == "timing gating\n"); + } + { + REQUIRE_NOTHROW(multiSlsDetectorClient("timing burst_trigger", PUT)); + std::ostringstream oss; + multiSlsDetectorClient("timing", GET, nullptr, oss); + REQUIRE(oss.str() == "timing burst_trigger\n"); + } + } else { + REQUIRE_THROWS(multiSlsDetectorClient("timing gating", PUT)); + REQUIRE_THROWS(multiSlsDetectorClient("timing burst_trigger", PUT)); + } +} + + +TEST_CASE("adc", "[.cmd][.ctb]") { + if (test::type != slsDetectorDefs::CHIPTESTBOARD) { + REQUIRE_THROWS(multiSlsDetectorClient("adc 8", GET)); + } else { + REQUIRE_THROWS(multiSlsDetectorClient("adc", GET)); + REQUIRE_THROWS(multiSlsDetectorClient("adc 5", PUT)); + for(int i = 0; i <= 8; ++i) { + REQUIRE_NOTHROW(multiSlsDetectorClient("adc " + std::to_string(i), GET)); + } + } +} + + + +TEST_CASE("temp_fpga", "[.cmd][.eiger][.jungfrau][.gotthard]") { + if (test::type == slsDetectorDefs::CHIPTESTBOARD) { + REQUIRE_THROWS(multiSlsDetectorClient("temp_fpga", GET)); + } else { + REQUIRE_THROWS(multiSlsDetectorClient("temp_fpga 0", PUT)); + std::ostringstream oss; + multiSlsDetectorClient("0:temp_fpga", GET, nullptr, oss); + std::string s = (oss.str()).erase (0, strlen("temp_fpga ")); + REQUIRE(std::stoi(s) != -1); + } +} + +TEST_CASE("temp_adc", "[.cmd][.jungfrau][.gotthard]") { + if (test::type != slsDetectorDefs::GOTTHARD && test::type != slsDetectorDefs::JUNGFRAU ) { + REQUIRE_THROWS(multiSlsDetectorClient("temp_adc", GET)); + } else { + REQUIRE_THROWS(multiSlsDetectorClient("temp_adc 0", PUT)); + std::ostringstream oss; + multiSlsDetectorClient("0:temp_adc", GET, nullptr, oss); + std::string s = (oss.str()).erase (0, strlen("temp_adc ")); + REQUIRE(std::stoi(s) != -1); + } +} + + +TEST_CASE("temp", "[.cmd][.eiger]") { + if (test::type != slsDetectorDefs::EIGER) { + REQUIRE_THROWS(multiSlsDetectorClient("temp_fpgaext", GET)); + REQUIRE_THROWS(multiSlsDetectorClient("temp_10ge", GET)); + REQUIRE_THROWS(multiSlsDetectorClient("temp_dcdc", GET)); + REQUIRE_THROWS(multiSlsDetectorClient("temp_sodl", GET)); + REQUIRE_THROWS(multiSlsDetectorClient("temp_sodr", GET)); + REQUIRE_THROWS(multiSlsDetectorClient("temp_fpgafl", GET)); + REQUIRE_THROWS(multiSlsDetectorClient("temp_fpgafr", GET)); + } else { + REQUIRE_THROWS(multiSlsDetectorClient("temp_fpgaext 0", PUT)); + REQUIRE_THROWS(multiSlsDetectorClient("temp_10ge 0", PUT)); + REQUIRE_THROWS(multiSlsDetectorClient("temp_dcdc 0", PUT)); + REQUIRE_THROWS(multiSlsDetectorClient("temp_sodl 0", PUT)); + REQUIRE_THROWS(multiSlsDetectorClient("temp_sodr 0", PUT)); + REQUIRE_THROWS(multiSlsDetectorClient("temp_fpgafl 0", PUT)); + REQUIRE_THROWS(multiSlsDetectorClient("temp_fpgafr 0", PUT)); + { + std::ostringstream oss; + multiSlsDetectorClient("0:temp_fpgaext", GET, nullptr, oss); + std::string s = (oss.str()).erase (0, strlen("temp_fpgaext ")); + REQUIRE(std::stoi(s) != -1); + } + { + std::ostringstream oss; + multiSlsDetectorClient("0:temp_10ge", GET, nullptr, oss); + std::string s = (oss.str()).erase (0, strlen("temp_10ge ")); + REQUIRE(std::stoi(s) != -1); + } + { + std::ostringstream oss; + multiSlsDetectorClient("0:temp_dcdc", GET, nullptr, oss); + std::string s = (oss.str()).erase (0, strlen("temp_dcdc ")); + REQUIRE(std::stoi(s) != -1); + } + { + std::ostringstream oss; + multiSlsDetectorClient("0:temp_sodl", GET, nullptr, oss); + std::string s = (oss.str()).erase (0, strlen("temp_sodl ")); + REQUIRE(std::stoi(s) != -1); + } + { + std::ostringstream oss; + multiSlsDetectorClient("0:temp_sodr", GET, nullptr, oss); + std::string s = (oss.str()).erase (0, strlen("temp_sodr ")); + REQUIRE(std::stoi(s) != -1); + } + { + std::ostringstream oss; + multiSlsDetectorClient("0:temp_fpgafl", GET, nullptr, oss); + std::string s = (oss.str()).erase (0, strlen("temp_fpgafl ")); + REQUIRE(std::stoi(s) != -1); + } + { + std::ostringstream oss; + multiSlsDetectorClient("0:temp_fpgafr", GET, nullptr, oss); + std::string s = (oss.str()).erase (0, strlen("temp_fpgafr ")); + REQUIRE(std::stoi(s) != -1); + } + } +} + + +TEST_CASE("vhighvoltage", "[.cmd]") { + int prev_val = 0; + { + std::ostringstream oss; + multiSlsDetectorClient("vhighvoltage", GET, nullptr, oss); + std::string s = (oss.str()).erase (0, strlen("vhighvoltage ")); + // std::stoi doesnt convert [0,-999] beccause of [ + if (s.find('[') != std::string::npos) { + s.erase(0, 1); + } + prev_val = std::stoi(s); + } + if (test::type == slsDetectorDefs::GOTTHARD) { + { + REQUIRE_NOTHROW(multiSlsDetectorClient("vhighvoltage 90", PUT)); + std::ostringstream oss; + multiSlsDetectorClient("vhighvoltage", GET, nullptr, oss); + REQUIRE(oss.str() == "vhighvoltage 90\n"); + } + { + REQUIRE_NOTHROW(multiSlsDetectorClient("vhighvoltage 0", PUT)); + std::ostringstream oss; + multiSlsDetectorClient("vhighvoltage", GET, nullptr, oss); + REQUIRE(oss.str() == "vhighvoltage 0\n"); + } + REQUIRE_THROWS(multiSlsDetectorClient("vhighvoltage 50", PUT)); + } else { + if (test::type != slsDetectorDefs::EIGER) { + REQUIRE_NOTHROW(multiSlsDetectorClient("vhighvoltage 50", PUT)); + } else { + REQUIRE_THROWS(multiSlsDetectorClient("vhighvoltage 50", PUT)); + } + { + REQUIRE_NOTHROW(multiSlsDetectorClient("vhighvoltage 120", PUT)); + std::ostringstream oss; + multiSlsDetectorClient("vhighvoltage", GET, nullptr, oss); + std::string s = (oss.str()).erase (0, strlen("vhighvoltage ")); + REQUIRE(s.find("120") != std::string::npos); // due to different values for highvoltage for eiger + } + { + REQUIRE_NOTHROW(multiSlsDetectorClient("vhighvoltage 0", PUT)); + std::ostringstream oss; + multiSlsDetectorClient("vhighvoltage", GET, nullptr, oss); + std::string s = (oss.str()).erase (0, strlen("vhighvoltage ")); + REQUIRE(s.find("0") != std::string::npos); // due to different values for highvoltage for eiger + } + REQUIRE_NOTHROW(multiSlsDetectorClient("vhighvoltage " + std::to_string(prev_val), PUT)); + } +} + + + +TEST_CASE("maxadcphaseshift", "[.cmd][.ctb][.jungfrau]") { + if (test::type != slsDetectorDefs::CHIPTESTBOARD && test::type != slsDetectorDefs::JUNGFRAU) { + REQUIRE_THROWS(multiSlsDetectorClient("maxadcphaseshift", GET)); + } else { + REQUIRE_NOTHROW(multiSlsDetectorClient("maxadcphaseshift", GET)); + } +} + +TEST_CASE("adcphase", "[.cmd][.ctb][.jungfrau][.gotthard]") { + if (test::type != slsDetectorDefs::CHIPTESTBOARD && test::type != slsDetectorDefs::JUNGFRAU && test::type != slsDetectorDefs::GOTTHARD) { + REQUIRE_THROWS(multiSlsDetectorClient("adcphase", GET)); + } else { + int prev_val = 0; + { + std::ostringstream oss; + multiSlsDetectorClient("adcphase", GET, nullptr, oss); + std::string s = (oss.str()).erase (0, strlen("adcphase ")); + prev_val = std::stoi(s); + } + { + REQUIRE_NOTHROW(multiSlsDetectorClient("adcphase 20", PUT)); + std::ostringstream oss; + multiSlsDetectorClient("adcphase", GET, nullptr, oss); + REQUIRE(oss.str() == "adcphase 20\n"); + } + { + REQUIRE_NOTHROW(multiSlsDetectorClient("adcphase 0", PUT)); + std::ostringstream oss; + multiSlsDetectorClient("adcphase", GET, nullptr, oss); + REQUIRE(oss.str() == "adcphase 0\n"); + } + if (test::type != slsDetectorDefs::GOTTHARD) { + REQUIRE_THROWS(multiSlsDetectorClient("adcphase deg", GET)); + } else { + REQUIRE_NOTHROW(multiSlsDetectorClient("adcphase 20 deg", PUT)); + std::ostringstream oss; + multiSlsDetectorClient("adcphase deg", GET, nullptr, oss); + REQUIRE(oss.str() == "adcphase 20 deg\n"); + } + REQUIRE_NOTHROW(multiSlsDetectorClient("adcphase " + std::to_string(prev_val), PUT)); + } +} + +TEST_CASE("syncclk", "[.cmd][.ctb]") { + if(test::type != slsDetectorDefs::CHIPTESTBOARD) { + REQUIRE_THROWS(multiSlsDetectorClient("syncclk", GET)); + } else { + REQUIRE_NOTHROW(multiSlsDetectorClient("syncclk", GET)); + } +} + +TEST_CASE("adcclk", "[.cmd][.ctb]") { + if(test::type != slsDetectorDefs::CHIPTESTBOARD) { + REQUIRE_THROWS(multiSlsDetectorClient("adcclk", GET)); + } else { + int prev_clk = 0; + { + std::ostringstream oss; + multiSlsDetectorClient("adcclk", GET, nullptr, oss); + std::string s = (oss.str()).erase (0, strlen("adcclk ")); + prev_clk = std::stoi(s); + } + { + REQUIRE_NOTHROW(multiSlsDetectorClient("adcclk 20", PUT)); + std::ostringstream oss; + multiSlsDetectorClient("adcclk", GET, nullptr, oss); + REQUIRE(oss.str() == "adcclk 20\n"); + } + { + REQUIRE_NOTHROW(multiSlsDetectorClient("adcclk 0", PUT)); + std::ostringstream oss; + multiSlsDetectorClient("adcclk", GET, nullptr, oss); + REQUIRE(oss.str() == "adcclk 0\n"); + } + REQUIRE_NOTHROW(multiSlsDetectorClient("adcclk " + std::to_string(prev_clk), PUT)); + } +} + +TEST_CASE("dbitclk", "[.cmd][.ctb]") { + if(test::type != slsDetectorDefs::CHIPTESTBOARD) { + REQUIRE_THROWS(multiSlsDetectorClient("dbitclk", GET)); + } else { + int prev_clk = 0; + { + std::ostringstream oss; + multiSlsDetectorClient("dbitclk", GET, nullptr, oss); + std::string s = (oss.str()).erase (0, strlen("dbitclk ")); + prev_clk = std::stoi(s); + } + { + REQUIRE_NOTHROW(multiSlsDetectorClient("dbitclk 20", PUT)); + std::ostringstream oss; + multiSlsDetectorClient("dbitclk", GET, nullptr, oss); + REQUIRE(oss.str() == "dbitclk 20\n"); + } + { + REQUIRE_NOTHROW(multiSlsDetectorClient("dbitclk 0", PUT)); + std::ostringstream oss; + multiSlsDetectorClient("dbitclk", GET, nullptr, oss); + REQUIRE(oss.str() == "dbitclk 0\n"); + } + REQUIRE_NOTHROW(multiSlsDetectorClient("dbitclk " + std::to_string(prev_clk), PUT)); + } +} + +TEST_CASE("runclk", "[.cmd][.ctb]") { + if(test::type != slsDetectorDefs::CHIPTESTBOARD) { + ;// REQUIRE_THROWS(multiSlsDetectorClient("runclk", GET)); Only once setspeed is split into many (runclk = speed for now) + } else { + int prev_runclk = 0; + { + std::ostringstream oss; + multiSlsDetectorClient("runclk", GET, nullptr, oss); + std::string s = (oss.str()).erase (0, strlen("runclk ")); + prev_runclk = std::stoi(s); + } + { + REQUIRE_NOTHROW(multiSlsDetectorClient("runclk 20", PUT)); + std::ostringstream oss; + multiSlsDetectorClient("runclk", GET, nullptr, oss); + REQUIRE(oss.str() == "runclk 20\n"); + } + { + REQUIRE_NOTHROW(multiSlsDetectorClient("runclk 0", PUT)); + std::ostringstream oss; + multiSlsDetectorClient("runclk", GET, nullptr, oss); + REQUIRE(oss.str() == "runclk 0\n"); + } + REQUIRE_NOTHROW(multiSlsDetectorClient("runclk " + std::to_string(prev_runclk), PUT)); + } +} + +TEST_CASE("speed", "[.cmd][.eiger][.jungfrau]") { + if(test::type != slsDetectorDefs::EIGER && test::type != slsDetectorDefs::JUNGFRAU) { + REQUIRE_THROWS(multiSlsDetectorClient("speed", GET)); + } else { + { + REQUIRE_NOTHROW(multiSlsDetectorClient("speed 0", PUT)); + std::ostringstream oss; + multiSlsDetectorClient("speed", GET, nullptr, oss); + REQUIRE(oss.str() == "speed full_speed\n"); + } + { + REQUIRE_NOTHROW(multiSlsDetectorClient("speed full_speed", PUT)); + std::ostringstream oss; + multiSlsDetectorClient("speed", GET, nullptr, oss); + REQUIRE(oss.str() == "speed full_speed\n"); + } + { + REQUIRE_NOTHROW(multiSlsDetectorClient("speed 1", PUT)); + std::ostringstream oss; + multiSlsDetectorClient("speed", GET, nullptr, oss); + REQUIRE(oss.str() == "speed half_speed\n"); + } + { + REQUIRE_NOTHROW(multiSlsDetectorClient("speed half_speed", PUT)); + std::ostringstream oss; + multiSlsDetectorClient("speed", GET, nullptr, oss); + REQUIRE(oss.str() == "speed half_speed\n"); + } + { + REQUIRE_NOTHROW(multiSlsDetectorClient("speed 2", PUT)); + std::ostringstream oss; + multiSlsDetectorClient("speed", GET, nullptr, oss); + REQUIRE(oss.str() == "speed quarter_speed\n"); + } + { + REQUIRE_NOTHROW(multiSlsDetectorClient("speed quarter_speed", PUT)); + std::ostringstream oss; + multiSlsDetectorClient("speed", GET, nullptr, oss); + REQUIRE(oss.str() == "speed quarter_speed\n"); + } + REQUIRE_THROWS(multiSlsDetectorClient("speed 3", PUT)); + } +} + +TEST_CASE("triggers", "[.cmd]") { + { + REQUIRE_NOTHROW(multiSlsDetectorClient("triggers 10", PUT)); + std::ostringstream oss; + multiSlsDetectorClient("triggers", GET, nullptr, oss); + REQUIRE(oss.str() == "triggers 10\n"); + } +} + +TEST_CASE("settings", "[.cmd]") { + switch(test::type) { + case slsDetectorDefs::EIGER: + REQUIRE_THROWS(multiSlsDetectorClient("settings mediumgain", PUT)); + REQUIRE_NOTHROW(multiSlsDetectorClient("settings standard", PUT)); + break; + case slsDetectorDefs::JUNGFRAU: + REQUIRE_THROWS(multiSlsDetectorClient("settings standard", PUT)); + REQUIRE_NOTHROW(multiSlsDetectorClient("settings dynamicgain", PUT)); + REQUIRE_NOTHROW(multiSlsDetectorClient("settings dynamichg0", PUT)); + REQUIRE_NOTHROW(multiSlsDetectorClient("settings fixgain1", PUT)); + REQUIRE_NOTHROW(multiSlsDetectorClient("settings fixgain2", PUT)); + REQUIRE_NOTHROW(multiSlsDetectorClient("settings forceswitchg1", PUT)); + REQUIRE_NOTHROW(multiSlsDetectorClient("settings forceswitchg2", PUT)); + break; + default: + break; + } + REQUIRE_NOTHROW(multiSlsDetectorClient("settings", GET)); +} + +TEST_CASE("threshold", "[.cmd]") { + REQUIRE_NOTHROW(multiSlsDetectorClient("threshold 6400 standard", PUT)); + REQUIRE_NOTHROW(multiSlsDetectorClient("thresholdnotb 6400 standard", PUT)); + REQUIRE_NOTHROW(multiSlsDetectorClient("threshold 6400", PUT)); + REQUIRE_NOTHROW(multiSlsDetectorClient("thresholdnotb 6400", PUT)); + { + std::ostringstream oss; + multiSlsDetectorClient("threshold", GET, nullptr, oss); + std::string s = (oss.str()).erase (0, strlen("threshold ")); + REQUIRE(std::stoi(s) == 6400); + REQUIRE_THROWS(multiSlsDetectorClient("thresholdnotb", GET)); + } +} + + +TEST_CASE("detsize", "[.cmd]") { + CHECK_NOTHROW(multiSlsDetectorClient("detize", GET)); +} + +TEST_CASE("type", "[.cmd]") { + CHECK_NOTHROW(multiSlsDetectorClient("type", GET)); +} + +TEST_CASE("firmwareversion", "[.cmd]") { + { + std::ostringstream oss; + CHECK_NOTHROW(multiSlsDetectorClient("firmwareversion", GET, nullptr, oss)); + } +} +TEST_CASE("status", "[.cmd]") { + + multiSlsDetectorClient("timing auto", PUT); + multiSlsDetectorClient("frames 10", PUT); + multiSlsDetectorClient("period 1", PUT); + + { + std::ostringstream oss; + multiSlsDetectorClient("start", PUT, nullptr, oss); + REQUIRE(oss.str() == "start successful\n"); + } + { + std::ostringstream oss; + multiSlsDetectorClient("status", GET, nullptr, oss); + REQUIRE(oss.str() == "status running\n"); + } + { + std::ostringstream oss; + multiSlsDetectorClient("stop", PUT, nullptr, oss); + REQUIRE(oss.str() == "stop successful\n"); + } + { + std::ostringstream oss; + multiSlsDetectorClient("status", GET, nullptr, oss); + REQUIRE(oss.str() == "status idle\n"); + } +} + +TEST_CASE("trigger", "[.cmd][.eiger]") { + // trigger + { + std::ostringstream oss; + multiSlsDetectorClient("timing trigger", PUT, nullptr, oss); + REQUIRE(oss.str() == "timing trigger\n"); + } + int startingfnum = 0; + { + std::ostringstream oss; + multiSlsDetectorClient("startingfnum", GET, nullptr, oss); + std::string s = (oss.str()).erase (0, strlen("startingfnum ")); + startingfnum = std::stoi(s); + } + { + std::ostringstream oss; + multiSlsDetectorClient("start", PUT, nullptr, oss); + REQUIRE(oss.str() == "start successful\n"); + } + { + std::ostringstream oss; + multiSlsDetectorClient("status", GET, nullptr, oss); + REQUIRE(oss.str() == "status running\n"); + } + { + std::ostringstream oss; + multiSlsDetectorClient("trigger", PUT, nullptr, oss); + REQUIRE(oss.str() == "trigger successful\n"); + } + multiSlsDetectorClient("stop", PUT); + int currentfnum = 0; + { + std::ostringstream oss; + multiSlsDetectorClient("startingfnum", GET, nullptr, oss); + std::string s = (oss.str()).erase (0, strlen("startingfnum ")); + currentfnum = std::stoi(s); + } + REQUIRE((startingfnum + 1) == currentfnum); + + + multiSlsDetectorClient("timing auto", PUT); +} + + +TEST_CASE("framesl", "[.cmd][.jungfrau][gotthard][ctb]") { + if(test::type == slsDetectorDefs::EIGER) { + REQUIRE_THROWS(multiSlsDetectorClient("framesl", GET)); + } else { + multiSlsDetectorClient("timing auto", PUT); + multiSlsDetectorClient("frames 10", PUT); + multiSlsDetectorClient("period 1", PUT); + multiSlsDetectorClient("status start", PUT); + { + std::ostringstream oss; + multiSlsDetectorClient("framesl", GET, nullptr, oss); + std::string s = (oss.str()).erase (0, strlen("framesl ")); + int framesl = std::stoi(s); + REQUIRE(framesl > 0); + } + multiSlsDetectorClient("stop", PUT); + } +} + +TEST_CASE("triggersl", "[.cmd][.jungfrau][gotthard][ctb]") { + if(test::type == slsDetectorDefs::EIGER) { + REQUIRE_THROWS(multiSlsDetectorClient("triggersl", GET)); + } else { + multiSlsDetectorClient("timing trigger", PUT); + multiSlsDetectorClient("frames 1", PUT); + multiSlsDetectorClient("triggers 10", PUT); + multiSlsDetectorClient("status start", PUT); + { + std::ostringstream oss; + multiSlsDetectorClient("triggersl", GET, nullptr, oss); + std::string s = (oss.str()).erase (0, strlen("framesl ")); + int triggersl = std::stoi(s); + REQUIRE(triggersl == 10); + } + multiSlsDetectorClient("stop", PUT); + } +} + +TEST_CASE("delayl", "[.cmd][.jungfrau][gotthard][ctb]") { + if(test::type == slsDetectorDefs::EIGER) { + REQUIRE_THROWS(multiSlsDetectorClient("delayl", GET)); + } else { + multiSlsDetectorClient("timing trigger", PUT); + multiSlsDetectorClient("frames 1", PUT); + multiSlsDetectorClient("triggers 2", PUT); + multiSlsDetectorClient("delay 1", PUT); + multiSlsDetectorClient("status start", PUT); + { + std::ostringstream oss; + multiSlsDetectorClient("delayl s", GET, nullptr, oss); + REQUIRE(oss.str() == "delayl 1s\n"); + } + multiSlsDetectorClient("stop", PUT); + } +} TEST_CASE("clk", "[.cmd]") { REQUIRE_THROWS(multiSlsDetectorClient("clkfreq 0 2", PUT)); // cannot get REQUIRE_THROWS(multiSlsDetectorClient("clkfreq", GET)); // requires clk index @@ -68,6 +2290,8 @@ TEST_CASE("rx_fifodepth", "[.cmd]") { multiSlsDetectorClient("rx_fifodepth", GET, nullptr, oss); REQUIRE(oss.str() == "rx_fifodepth 100\n"); } + REQUIRE_NOTHROW(multiSlsDetectorClient("rx_fifodepth 0", PUT)); + } TEST_CASE("frames", "[.cmd]") { @@ -93,8 +2317,8 @@ TEST_CASE("frames", "[.cmd]") { TEST_CASE("rx_status", "[.cmd]") { { std::ostringstream oss; - multiSlsDetectorClient("rx_status start", PUT, nullptr, oss); - REQUIRE(oss.str() == "rx_status running\n"); + multiSlsDetectorClient("rx_start", PUT, nullptr, oss); + REQUIRE(oss.str() == "rx_start successful\n"); } { std::ostringstream oss; @@ -103,8 +2327,8 @@ TEST_CASE("rx_status", "[.cmd]") { } { std::ostringstream oss; - multiSlsDetectorClient("rx_status stop", PUT, nullptr, oss); - REQUIRE(oss.str() == "rx_status idle\n"); + multiSlsDetectorClient("rx_stop", PUT, nullptr, oss); + REQUIRE(oss.str() == "rx_stop successful\n"); } { std::ostringstream oss; @@ -131,7 +2355,7 @@ TEST_CASE("fwrite", "[.cmd]") { } } -TEST_CASE("enablefoverwrite", "[.cmd]") { +TEST_CASE("foverwrite", "[.cmd]") { { std::ostringstream oss; multiSlsDetectorClient("foverwrite 1", PUT, nullptr, oss); @@ -149,26 +2373,6 @@ TEST_CASE("enablefoverwrite", "[.cmd]") { } } -// EIGER ONLY -// TEST_CASE("activatecmd", "[.cmd]") { - -// { -// // TODO! read padding from somewhere -// std::ostringstream oss; -// multiSlsDetectorClient("activate 0", PUT, nullptr, oss); -// REQUIRE(oss.str() == "activate 0 padding\n"); -// } -// { -// std::ostringstream oss; -// multiSlsDetectorClient("activate", GET, nullptr, oss); -// REQUIRE(oss.str() == "activate 0 padding\n"); -// } -// { -// std::ostringstream oss; -// multiSlsDetectorClient("activate 1", PUT, nullptr, oss); -// REQUIRE(oss.str() == "activate 1 padding\n"); -// } -// } TEST_CASE("fmaster", "[.cmd]") { { @@ -209,35 +2413,20 @@ TEST_CASE("findex", "[.cmd]") { TEST_CASE("rx_tcpport", "[.cmd]") { multiSlsDetector d; - int port = 1500; - int base = 1954; + int port = 3500; + multiSlsDetectorClient("rx_tcpport " + std::to_string(port), PUT); for (size_t i = 0; i != d.size(); ++i) { std::ostringstream oss; - std::string cmd = - std::to_string(i) + ":rx_tcpport " + std::to_string(port + i); - std::cout << cmd << "\n"; - multiSlsDetectorClient(cmd, PUT, nullptr, oss); - REQUIRE(oss.str() == cmd + "\n"); + multiSlsDetectorClient(std::to_string(i) + ":rx_tcpport", GET, nullptr, oss); + REQUIRE(oss.str() == "rx_tcpport " + std::to_string(port + i) + '\n'); } - { - std::ostringstream oss; - REQUIRE_THROWS( - multiSlsDetectorClient("rx_tcpport 15", PUT, nullptr, oss)); - } - + REQUIRE_THROWS(multiSlsDetectorClient("rx_tcpport 15", PUT)); + port = 1954; + multiSlsDetectorClient("rx_tcpport " + std::to_string(port), PUT); for (size_t i = 0; i != d.size(); ++i) { std::ostringstream oss; - std::string cmd = std::to_string(i) + ":rx_tcpport"; - multiSlsDetectorClient(cmd, GET, nullptr, oss); - REQUIRE(oss.str() == cmd + " " + std::to_string(port + i) + "\n"); - } - - for (size_t i = 0; i != d.size(); ++i) { - std::ostringstream oss; - std::string cmd = - std::to_string(i) + ":rx_tcpport " + std::to_string(base + i); - multiSlsDetectorClient(cmd, PUT, nullptr, oss); - REQUIRE(oss.str() == cmd + "\n"); + multiSlsDetectorClient(std::to_string(i) + ":rx_tcpport", GET, nullptr, oss); + REQUIRE(oss.str() == "rx_tcpport " + std::to_string(port + i) + '\n'); } } @@ -260,7 +2449,7 @@ TEST_CASE("fname", "[.cmd]") { } } -TEST_CASE("resetframescaught get framescaught", "[.cmd]") { +TEST_CASE("rx_framescaught", "[.cmd]") { { std::ostringstream oss; multiSlsDetectorClient("resetframescaught 0", PUT, nullptr, oss); @@ -268,9 +2457,20 @@ TEST_CASE("resetframescaught get framescaught", "[.cmd]") { } { std::ostringstream oss; - multiSlsDetectorClient("framescaught", GET, nullptr, oss); - REQUIRE(oss.str() == "framescaught 0\n"); + multiSlsDetectorClient("rx_framescaught", GET, nullptr, oss); + REQUIRE(oss.str() == "rx_framescaught 0\n"); } + REQUIRE_NOTHROW(multiSlsDetectorClient("frames 1", PUT)); + REQUIRE_NOTHROW(multiSlsDetectorClient("exptime 1", PUT)); + REQUIRE_NOTHROW(multiSlsDetectorClient("rx_start", PUT)); + REQUIRE_NOTHROW(multiSlsDetectorClient("start", PUT)); + sleep(2); + REQUIRE_NOTHROW(multiSlsDetectorClient("rx_stop", PUT)); + { + std::ostringstream oss; + multiSlsDetectorClient("rx_framescaught", GET, nullptr, oss); + REQUIRE(oss.str() == "rx_framescaught 1\n"); + } } TEST_CASE("rx_silent", "[.cmd]") { @@ -305,19 +2505,24 @@ TEST_CASE("rx_silent", "[.cmd]") { // REQUIRE(oss.str() == "rx_jsonaddheader\n"); // } -// TEST_CASE("rx_udpsocksize", "[.cmd]") { -// std::ostringstream oss; -// multiSlsDetectorClient("rx_udpsocksize 4857600", PUT, nullptr, oss); -// REQUIRE(oss.str() == "rx_udpsocksize 4857600\n"); +TEST_CASE("rx_udpsocksize", "[.cmd]") { + REQUIRE_NOTHROW(multiSlsDetectorClient("rx_udpsocksize 4857600", PUT)); + uint64_t val = 0; + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("rx_udpsocksize", GET, nullptr, oss)); + std::string s = (oss.str()).erase (0, strlen("rx_udpsocksize ")); + val = std::stol(s); + } + { + std::ostringstream oss; + REQUIRE_NOTHROW(multiSlsDetectorClient("rx_realudpsocksize", GET, nullptr, oss)); + std::string s = (oss.str()).erase (0, strlen("rx_realudpsocksize ")); + uint64_t rval = std::stol(s); + REQUIRE(rval == val * 2); + } +} -// std::ostringstream oss; -// multiSlsDetectorClient("rx_udpsocksize", GET, nullptr, oss); -// REQUIRE(oss.str() == "rx_udpsocksize 4857600\n"); - -// std::ostringstream oss; -// multiSlsDetectorClient("rx_udpsocksize 104857600", PUT, nullptr, oss); -// REQUIRE(oss.str() == "rx_udpsocksize 104857600\n"); -// } TEST_CASE("rx_framesperfile", "[.cmd]") { { @@ -435,10 +2640,13 @@ TEST_CASE("lock", "[.cmd]") { } -TEST_CASE("rx_lastclient", "[.cmd]") { +TEST_CASE("lastclient", "[.cmd]") { + REQUIRE_NOTHROW(multiSlsDetectorClient("lastclient", GET)); +} +TEST_CASE("rx_lastclient", "[.cmd]") { std::ostringstream oss; - multiSlsDetectorClient("rx_lastclient", GET, nullptr, oss); + REQUIRE_NOTHROW(multiSlsDetectorClient("rx_lastclient", GET, nullptr, oss)); REQUIRE(oss.str() == "rx_lastclient " + test::my_ip + "\n"); } @@ -486,4 +2694,27 @@ TEST_CASE("period", "[.cmd]") { multiSlsDetectorClient("period 0", PUT, nullptr, oss); REQUIRE(oss.str() == "period 0\n"); } +} + +TEST_CASE("delay", "[.cmd][.eiger]") { + if(test::type == slsDetectorDefs::EIGER) { + REQUIRE_THROWS(multiSlsDetectorClient("delay 1", PUT)); + REQUIRE_THROWS(multiSlsDetectorClient("delay", GET)); + } else { + { + std::ostringstream oss; + multiSlsDetectorClient("delay 1.25s", PUT, nullptr, oss); + REQUIRE(oss.str() == "delay 1.25s\n"); + } + { + std::ostringstream oss; + multiSlsDetectorClient("delay", GET, nullptr, oss); + REQUIRE(oss.str() == "delay 1.25s\n"); + } + { + std::ostringstream oss; + multiSlsDetectorClient("delay 0", PUT, nullptr, oss); + REQUIRE(oss.str() == "delay 0\n"); + } + } } \ No newline at end of file diff --git a/slsReceiverSoftware/include/DataStreamer.h b/slsReceiverSoftware/include/DataStreamer.h index 567cf364a..275be7c2b 100755 --- a/slsReceiverSoftware/include/DataStreamer.h +++ b/slsReceiverSoftware/include/DataStreamer.h @@ -8,6 +8,7 @@ */ #include "ThreadObject.h" +#include "network_utils.h" class GeneralData; class Fifo; @@ -107,9 +108,9 @@ class DataStreamer : private virtual slsDetectorDefs, public ThreadObject { * (throws an exception if it couldnt create zmq sockets) * @param nunits pointer to number of theads/ units per detector * @param port streaming port start index - * @param srcip streaming source ip + * @param ip streaming source ip */ - void CreateZmqSockets(int* nunits, uint32_t port, const char* srcip); + void CreateZmqSockets(int* nunits, uint32_t port, const sls::IpAddr ip); /** * Shuts down and deletes Zmq Sockets diff --git a/slsReceiverSoftware/include/GeneralData.h b/slsReceiverSoftware/include/GeneralData.h index ca7d04898..cce1832cd 100755 --- a/slsReceiverSoftware/include/GeneralData.h +++ b/slsReceiverSoftware/include/GeneralData.h @@ -12,6 +12,7 @@ #include "logger.h" #include //ceil #include +#include "ToString.h" class GeneralData { @@ -218,7 +219,7 @@ public: */ virtual void Print(TLogLevel level = logDEBUG1) const { FILE_LOG(level) << "\n\nDetector Data Variables:"; - FILE_LOG(level) << "myDetectorType: " << slsDetectorDefs::detectorTypeToString(myDetectorType); + FILE_LOG(level) << "myDetectorType: " << sls::ToString(myDetectorType); FILE_LOG(level) << "Pixels X: " << nPixelsX; FILE_LOG(level) << "Pixels Y: " << nPixelsY; FILE_LOG(level) << "Header Size in Packet: " << headerSizeinPacket; diff --git a/slsReceiverSoftware/include/slsReceiverImplementation.h b/slsReceiverSoftware/include/slsReceiverImplementation.h index cba2ecbde..eaeae6b97 100755 --- a/slsReceiverSoftware/include/slsReceiverImplementation.h +++ b/slsReceiverSoftware/include/slsReceiverImplementation.h @@ -14,6 +14,7 @@ #include "container_utils.h" #include "logger.h" #include "receiver_defs.h" +#include "network_utils.h" class GeneralData; class Listener; class DataProcessor; @@ -352,7 +353,7 @@ class slsReceiverImplementation : private virtual slsDetectorDefs { * Get streaming source ip * @return streaming source ip */ - std::string getStreamingSourceIP() const; + sls::IpAddr getStreamingSourceIP() const; /** * Get additional json header @@ -571,7 +572,7 @@ class slsReceiverImplementation : private virtual slsDetectorDefs { * Set streaming source ip * @param c streaming source ip */ - void setStreamingSourceIP(const char *c); + void setStreamingSourceIP(const sls::IpAddr ip); /** * Set additional json header @@ -974,7 +975,7 @@ class slsReceiverImplementation : private virtual slsDetectorDefs { /** streaming port */ uint32_t streamingPort; /** streaming port */ - char streamingSrcIP[MAX_STR_LENGTH]; + sls::IpAddr streamingSrcIP; /** additional json header */ char additionalJsonHeader[MAX_STR_LENGTH]; diff --git a/slsReceiverSoftware/src/DataStreamer.cpp b/slsReceiverSoftware/src/DataStreamer.cpp index 2f16b7078..82214da74 100755 --- a/slsReceiverSoftware/src/DataStreamer.cpp +++ b/slsReceiverSoftware/src/DataStreamer.cpp @@ -140,11 +140,11 @@ void DataStreamer::SetFlippedDataX(int fd) { flippedDataX = fd; } -void DataStreamer::CreateZmqSockets(int* nunits, uint32_t port, const char* srcip) { +void DataStreamer::CreateZmqSockets(int* nunits, uint32_t port, const sls::IpAddr ip) { uint32_t portnum = port + index; - + std::string sip = ip.str(); try { - zmqSocket = new ZmqSocket(portnum, (strlen(srcip)?srcip:nullptr)); + zmqSocket = new ZmqSocket(portnum, (ip != 0? sip.c_str(): nullptr)); } catch (...) { FILE_LOG(logERROR) << "Could not create Zmq socket on port " << portnum << " for Streamer " << index; throw; diff --git a/slsReceiverSoftware/src/Listener.cpp b/slsReceiverSoftware/src/Listener.cpp index 9a00c41f5..a06734d77 100755 --- a/slsReceiverSoftware/src/Listener.cpp +++ b/slsReceiverSoftware/src/Listener.cpp @@ -233,7 +233,7 @@ void Listener::ShutDownUDPSocket() { int Listener::CreateDummySocketForUDPSocketBufferSize(int64_t s) { - FILE_LOG(logINFO) << "Testing UDP Socket Buffer size with test port " << *udpPortNumber; + FILE_LOG(logINFO) << "Testing UDP Socket Buffer size " << s << " with test port " << *udpPortNumber; if (!(*activated)) { *actualUDPSocketBufferSize = (s*2); @@ -256,9 +256,11 @@ int Listener::CreateDummySocketForUDPSocketBufferSize(int64_t s) { // doubled due to kernel bookkeeping (could also be less due to permissions) *actualUDPSocketBufferSize = g.getActualUDPSocketBufferSize(); - if (*actualUDPSocketBufferSize != (s*2)) { - *udpSocketBufferSize = temp; - } + if (*actualUDPSocketBufferSize == -1) { + *udpSocketBufferSize = temp; + } else { + *udpSocketBufferSize = (*actualUDPSocketBufferSize) / 2; + } } catch (...) { FILE_LOG(logERROR) << "Could not create a test UDP socket on port " << *udpPortNumber; diff --git a/slsReceiverSoftware/src/slsReceiverImplementation.cpp b/slsReceiverSoftware/src/slsReceiverImplementation.cpp index 55d8189f1..f082c5f32 100755 --- a/slsReceiverSoftware/src/slsReceiverImplementation.cpp +++ b/slsReceiverSoftware/src/slsReceiverImplementation.cpp @@ -14,6 +14,7 @@ #include "Listener.h" #include "ZmqSocket.h" //just for the zmq port define #include "file_utils.h" +#include "ToString.h" #include //eperm #include //system @@ -111,7 +112,7 @@ void slsReceiverImplementation::InitializeMembers() { streamingTimerInMs = DEFAULT_STREAMING_TIMER_IN_MS; dataStreamEnable = false; streamingPort = 0; - memset(streamingSrcIP, 0, sizeof(streamingSrcIP)); + streamingSrcIP = 0u; memset(additionalJsonHeader, 0, sizeof(additionalJsonHeader)); //** class objects *** @@ -410,9 +411,9 @@ uint32_t slsReceiverImplementation::getStreamingPort() const { return streamingPort; } -std::string slsReceiverImplementation::getStreamingSourceIP() const { +sls::IpAddr slsReceiverImplementation::getStreamingSourceIP() const { FILE_LOG(logDEBUG3) << __SHORT_AT__ << " called"; - return std::string(streamingSrcIP); + return streamingSrcIP; } std::string slsReceiverImplementation::getAdditionalJsonHeader() const { @@ -560,7 +561,7 @@ int slsReceiverImplementation::setReadoutMode(const readoutMode f) { return FAIL; } - FILE_LOG(logINFO) << "Readout Mode: " << getReadoutModeType(f); + FILE_LOG(logINFO) << "Readout Mode: " << sls::ToString(f); FILE_LOG(logINFO) << "Packets per Frame: " << (generalData->packetsPerFrame); return OK; @@ -581,7 +582,7 @@ void slsReceiverImplementation::setFileFormat(const fileFormat f) { for (const auto &it : dataProcessor) it->SetFileFormat(f); - FILE_LOG(logINFO) << "File Format: " << getFileFormatType(fileFormatType); + FILE_LOG(logINFO) << "File Format: " << sls::ToString(fileFormatType); } void slsReceiverImplementation::setFileName(const char c[]) { @@ -624,7 +625,7 @@ void slsReceiverImplementation::setFrameDiscardPolicy( frameDiscardMode = i; FILE_LOG(logINFO) << "Frame Discard Policy: " - << getFrameDiscardPolicyType(frameDiscardMode); + << sls::ToString(frameDiscardMode); } void slsReceiverImplementation::setFramePaddingEnable(const bool i) { @@ -924,9 +925,9 @@ void slsReceiverImplementation::setStreamingPort(const uint32_t i) { FILE_LOG(logINFO) << "Streaming Port: " << streamingPort; } -void slsReceiverImplementation::setStreamingSourceIP(const char c[]) { +void slsReceiverImplementation::setStreamingSourceIP(const sls::IpAddr ip) { FILE_LOG(logDEBUG3) << __SHORT_AT__ << " called"; - strcpy(streamingSrcIP, c); + streamingSrcIP = ip; FILE_LOG(logINFO) << "Streaming Source IP: " << streamingSrcIP; } @@ -1122,7 +1123,7 @@ int slsReceiverImplementation::setDetectorType(const detectorType d) { case JUNGFRAU: case CHIPTESTBOARD: case MOENCH: - FILE_LOG(logINFO) << " ***** " << detectorTypeToString(d) + FILE_LOG(logINFO) << " ***** " << sls::ToString(d) << " Receiver *****"; break; default: @@ -1196,7 +1197,7 @@ int slsReceiverImplementation::setDetectorType(const detectorType d) { it->SetGeneralData(generalData); SetThreadPriorities(); - FILE_LOG(logDEBUG) << " Detector type set to " << detectorTypeToString(d); + FILE_LOG(logDEBUG) << " Detector type set to " << sls::ToString(d); return OK; } @@ -1275,7 +1276,7 @@ int slsReceiverImplementation::startReceiver(char *c) { StartRunning(); FILE_LOG(logINFO) << "Receiver Started"; - FILE_LOG(logINFO) << "Status: " << runStatusType(status); + FILE_LOG(logINFO) << "Status: " << sls::ToString(status); return OK; } @@ -1326,7 +1327,7 @@ void slsReceiverImplementation::stopReceiver() { } status = RUN_FINISHED; - FILE_LOG(logINFO) << "Status: " << runStatusType(status); + FILE_LOG(logINFO) << "Status: " << sls::ToString(status); { // statistics uint64_t tot = 0; @@ -1368,7 +1369,7 @@ void slsReceiverImplementation::stopReceiver() { status = IDLE; FILE_LOG(logINFO) << "Receiver Stopped"; - FILE_LOG(logINFO) << "Status: " << runStatusType(status); + FILE_LOG(logINFO) << "Status: " << sls::ToString(status); } void slsReceiverImplementation::startReadout() { diff --git a/slsReceiverSoftware/src/slsReceiverTCPIPInterface.cpp b/slsReceiverSoftware/src/slsReceiverTCPIPInterface.cpp index eec9ebaad..b9afa639e 100755 --- a/slsReceiverSoftware/src/slsReceiverTCPIPInterface.cpp +++ b/slsReceiverSoftware/src/slsReceiverTCPIPInterface.cpp @@ -14,6 +14,7 @@ #include "sls_detector_exceptions.h" #include "string_utils.h" #include "versionAPI.h" +#include "ToString.h" #include #include @@ -318,7 +319,7 @@ int slsReceiverTCPIPInterface::lock_receiver(Interface &socket) { } int slsReceiverTCPIPInterface::get_last_client_ip(Interface &socket) { - return socket.sendResult(server->getLastClient().arr()); + return socket.sendResult(server->getLastClient()); } int slsReceiverTCPIPInterface::set_port(Interface &socket) { @@ -327,7 +328,7 @@ int slsReceiverTCPIPInterface::set_port(Interface &socket) { throw RuntimeError("Port Number: " + std::to_string(p_number) + " is too low (<1024)"); - FILE_LOG(logINFO) << "set port to " << p_number << std::endl; + FILE_LOG(logINFO) << "TCP port set to " << p_number << std::endl; auto new_server = sls::make_unique(p_number); new_server->setLockedBy(server->getLockedBy()); new_server->setLastClient(server->getThisClient()); @@ -347,11 +348,12 @@ int slsReceiverTCPIPInterface::update_client(Interface &socket) { int slsReceiverTCPIPInterface::send_update(Interface &socket) { int n = 0; int i32 = -1; + int64_t i64 = -1; char cstring[MAX_STR_LENGTH]{}; - char ip[INET_ADDRSTRLEN]{}; - sls::strcpy_safe(ip, server->getLastClient().str().c_str()); - n += socket.Send(ip, sizeof(ip)); + sls::IpAddr ip = 0u; + ip = server->getLastClient(); + n += socket.Send(&ip, sizeof(ip)); // filepath sls::strcpy_safe(cstring, receiver->getFilePath().c_str()); @@ -362,8 +364,8 @@ int slsReceiverTCPIPInterface::send_update(Interface &socket) { n += socket.Send(cstring, sizeof(cstring)); // index - i32 = receiver->getFileIndex(); - n += socket.Send(&i32, sizeof(i32)); + i64 = receiver->getFileIndex(); + n += socket.Send(&i64, sizeof(i64)); // file format i32 = (int)receiver->getFileFormat(); @@ -406,8 +408,8 @@ int slsReceiverTCPIPInterface::send_update(Interface &socket) { n += socket.Send(&i32, sizeof(i32)); // streaming source ip - sls::strcpy_safe(cstring, receiver->getStreamingSourceIP().c_str()); - n += socket.Send(cstring, sizeof(cstring)); + ip = receiver->getStreamingSourceIP(); + n += socket.Send(&ip, sizeof(ip)); // additional json header sls::strcpy_safe(cstring, receiver->getAdditionalJsonHeader().c_str()); @@ -542,7 +544,7 @@ int slsReceiverTCPIPInterface::set_timer(Interface &socket) { ret = impl()->setAcquisitionPeriod(value); break; case FRAME_NUMBER: - case CYCLES_NUMBER: + case TRIGGER_NUMBER: case STORAGE_CELL_NUMBER: impl()->setNumberOfFrames(value); break; @@ -583,7 +585,7 @@ int slsReceiverTCPIPInterface::set_timer(Interface &socket) { retval = impl()->getAcquisitionPeriod(); break; case FRAME_NUMBER: - case CYCLES_NUMBER: + case TRIGGER_NUMBER: case STORAGE_CELL_NUMBER: retval = impl()->getNumberOfFrames(); break; @@ -669,16 +671,12 @@ int slsReceiverTCPIPInterface::set_streaming_frequency(Interface &socket) { int slsReceiverTCPIPInterface::get_status(Interface &socket) { auto retval = impl()->getStatus(); - FILE_LOG(logDEBUG1) << "Status:" << runStatusType(retval); + FILE_LOG(logDEBUG1) << "Status:" << sls::ToString(retval); return socket.sendResult(retval); } int slsReceiverTCPIPInterface::start_receiver(Interface &socket) { - runStatus status = impl()->getStatus(); - if (status != IDLE) { - throw RuntimeError("Cannot start Receiver as it is: " + - runStatusType(status)); - } else { + if (impl()->getStatus() == IDLE) { FILE_LOG(logDEBUG1) << "Starting Receiver"; ret = impl()->startReceiver(mess); if (ret == FAIL) { @@ -689,14 +687,14 @@ int slsReceiverTCPIPInterface::start_receiver(Interface &socket) { } int slsReceiverTCPIPInterface::stop_receiver(Interface &socket) { - if (impl()->getStatus() != IDLE) { + if (impl()->getStatus() == RUNNING) { FILE_LOG(logDEBUG1) << "Stopping Receiver"; impl()->stopReceiver(); } auto s = impl()->getStatus(); if (s != IDLE) throw RuntimeError("Could not stop receiver. It as it is: " + - runStatusType(s)); + sls::ToString(s)); return socket.Send(OK); } @@ -740,13 +738,13 @@ int slsReceiverTCPIPInterface::set_file_name(Interface &socket) { } int slsReceiverTCPIPInterface::set_file_index(Interface &socket) { - auto index = socket.Receive(); + auto index = socket.Receive(); if (index >= 0) { VerifyIdle(socket); FILE_LOG(logDEBUG1) << "Setting file index: " << index; impl()->setFileIndex(index); } - int retval = impl()->getFileIndex(); + int64_t retval = impl()->getFileIndex(); validate(index, retval, "set file index", DEC); FILE_LOG(logDEBUG1) << "file index:" << retval; return socket.sendResult(retval); @@ -956,15 +954,19 @@ int slsReceiverTCPIPInterface::set_streaming_port(Interface &socket) { } int slsReceiverTCPIPInterface::set_streaming_source_ip(Interface &socket) { - char arg[MAX_STR_LENGTH]{}; - char retval[MAX_STR_LENGTH]{}; + sls::IpAddr arg = 0u; socket.Receive(arg); VerifyIdle(socket); FILE_LOG(logDEBUG1) << "Setting streaming source ip:" << arg; impl()->setStreamingSourceIP(arg); - sls::strcpy_safe(retval, impl()->getStreamingSourceIP().c_str()); - FILE_LOG(logDEBUG1) << "streaming source ip:" << retval; - return socket.sendResult(retval); + sls::IpAddr retval = impl()->getStreamingSourceIP(); + if (retval != arg) { + std::ostringstream os; + os << "Could not set streaming ip. Set " << arg + << ", but read " << retval << '\n'; + throw RuntimeError(os.str()); + } + return socket.Send(OK); } int slsReceiverTCPIPInterface::set_silent_mode(Interface &socket) { diff --git a/slsSupportLib/include/ToString.h b/slsSupportLib/include/ToString.h index fa1ee0def..641314c76 100644 --- a/slsSupportLib/include/ToString.h +++ b/slsSupportLib/include/ToString.h @@ -18,11 +18,162 @@ #include #include + namespace sls { +using defs = slsDetectorDefs; -inline std::string ToString(const slsDetectorDefs::runStatus s){ - return slsDetectorDefs::runStatusType(s); +inline std::string ToString(const defs::runStatus s){ + switch (s) { + case defs::ERROR: + return std::string("error"); + case defs::WAITING: + return std::string("waiting"); + case defs::RUNNING: + return std::string("running"); + case defs::TRANSMITTING: + return std::string("data"); + case defs::RUN_FINISHED: + return std::string("finished"); + case defs::STOPPED: + return std::string("stopped"); + default: + return std::string("idle"); + } +} + +inline std::string ToString(const defs::detectorType s){ + switch (s) { + case defs::EIGER: + return std::string("Eiger"); + case defs::GOTTHARD: + return std::string("Gotthard"); + case defs::JUNGFRAU: + return std::string("Jungfrau"); + case defs::CHIPTESTBOARD: + return std::string("JungfrauCTB"); + case defs::MOENCH: + return std::string("Moench"); + case defs::MYTHEN3: + return std::string("Mythen3"); + case defs::GOTTHARD2: + return std::string("Gotthard2"); + default: + return std::string("Unknown"); + } +} + +inline std::string ToString(const defs::detectorSettings s){ + switch (s) { + case defs::STANDARD: + return std::string("standard"); + case defs::FAST: + return std::string("fast"); + case defs::HIGHGAIN: + return std::string("highgain"); + case defs::DYNAMICGAIN: + return std::string("dynamicgain"); + case defs::LOWGAIN: + return std::string("lowgain"); + case defs::MEDIUMGAIN: + return std::string("mediumgain"); + case defs::VERYHIGHGAIN: + return std::string("veryhighgain"); + case defs::DYNAMICHG0: + return std::string("dynamichg0"); + case defs::FIXGAIN1: + return std::string("fixgain1"); + case defs::FIXGAIN2: + return std::string("fixgain2"); + case defs::FORCESWITCHG1: + return std::string("forceswitchg1"); + case defs::FORCESWITCHG2: + return std::string("forceswitchg2"); + case defs::VERYLOWGAIN: + return std::string("verylowgain"); + case defs::UNDEFINED: + return std::string("undefined"); + case defs::UNINITIALIZED: + return std::string("uninitialized"); + default: + return std::string("Unknown"); + } +} + +inline std::string ToString(const defs::speedLevel s){ + switch (s) { + case defs::FULL_SPEED: + return std::string("full_speed"); + case defs::HALF_SPEED: + return std::string("half_speed"); + case defs::QUARTER_SPEED: + return std::string("quarter_speed"); + default: + return std::string("Unknown"); + } +} + +inline std::string ToString(const defs::timingMode s){ + switch (s) { + case defs::AUTO_TIMING: + return std::string("auto"); + case defs::TRIGGER_EXPOSURE: + return std::string("trigger"); + case defs::GATED: + return std::string("gating"); + case defs::BURST_TRIGGER: + return std::string("burst_trigger"); + default: + return std::string("Unknown"); + } +} + +inline std::string ToString(const defs::frameDiscardPolicy s){ + switch (s) { + case defs::NO_DISCARD: + return std::string("nodiscard"); + case defs::DISCARD_EMPTY_FRAMES: + return std::string("discardempty"); + case defs::DISCARD_PARTIAL_FRAMES: + return std::string("discardpartial"); + default: + return std::string("Unknown"); + } +} + +inline std::string ToString(const defs::fileFormat s){ + switch (s) { + case defs::HDF5: + return std::string("hdf5"); + case defs::BINARY: + return std::string("binary"); + default: + return std::string("Unknown"); + } +} + +inline std::string ToString(const defs::externalSignalFlag s){ + switch (s) { + case defs::TRIGGER_IN_RISING_EDGE: + return std::string("trigger_in_rising_edge"); + case defs::TRIGGER_IN_FALLING_EDGE: + return std::string("trigger_in_falling_edge"); + default: + return std::string("Unknown"); + } +} + +inline std::string ToString(const defs::readoutMode s){ + switch (s) { + case defs::ANALOG_ONLY: + return std::string("analog"); + case defs::DIGITAL_ONLY: + return std::string("digital"); + case defs::ANALOG_AND_DIGITAL: + return std::string("analog_digital"); + default: + return std::string("Unknown"); + } } // in case we already have a string @@ -84,8 +235,37 @@ ToString(const T &value) { return std::to_string(value); } +/** Conversion of integer types, do not remove trailing zeros */ +template +typename std::enable_if::value, std::string>::type +ToStringHex(const T &value) { + std::ostringstream os; + os << "0x" << std::hex << value << std::dec; + return os.str(); +} - +/** + * hex + * For a container loop over all elements and call ToString on the element + * Container is excluded + */ +template +typename std::enable_if< + is_container::value && + !std::is_same::value, + std::string>::type +ToStringHex(const T &container) { + std::ostringstream os; + os << '['; + if (!container.empty()) { + auto it = container.cbegin(); + os << ToStringHex(*it++); + while (it != container.cend()) + os << ", " << ToStringHex(*it++); + } + os << ']'; + return os.str(); +} /** * For a container loop over all elements and call ToString on the element @@ -180,10 +360,120 @@ template T StringTo(const std::string& t) { } template <> -inline slsDetectorDefs::detectorType StringTo(const std::string& s){ - return slsDetectorDefs::detectorTypeToEnum(s); +inline defs::detectorType StringTo(const std::string& s){ + if (s == "Eiger") + return defs::EIGER; + if (s == "Gotthard") + return defs::GOTTHARD; + if (s == "Jungfrau") + return defs::JUNGFRAU; + if (s == "JungfrauCTB") + return defs::CHIPTESTBOARD; + if (s == "Moench") + return defs::MOENCH; + if (s == "Mythen3") + return defs::MYTHEN3; + if (s == "Gotthard2") + return defs::GOTTHARD2; + throw sls::RuntimeError("Unknown detector type " + s); } +template <> +inline defs::detectorSettings StringTo(const std::string& s){ + if (s == "standard") + return defs::STANDARD; + if (s == "fast") + return defs::FAST; + if (s == "highgain") + return defs::HIGHGAIN; + if (s == "dynamicgain") + return defs::DYNAMICGAIN; + if (s == "lowgain") + return defs::LOWGAIN; + if (s == "mediumgain") + return defs::MEDIUMGAIN; + if (s == "veryhighgain") + return defs::VERYHIGHGAIN; + if (s == "dynamichg0") + return defs::DYNAMICHG0; + if (s == "fixgain1") + return defs::FIXGAIN1; + if (s == "fixgain2") + return defs::FIXGAIN2; + if (s == "forceswitchg1") + return defs::FORCESWITCHG1; + if (s == "forceswitchg2") + return defs::FORCESWITCHG2; + if (s == "verylowgain") + return defs::VERYLOWGAIN; + throw sls::RuntimeError("Unknown setting " + s); +} + +template <> +inline defs::speedLevel StringTo(const std::string& s) { + if (s == "full_speed") + return defs::FULL_SPEED; + if (s == "half_speed") + return defs::HALF_SPEED; + if (s == "quarter_speed") + return defs::QUARTER_SPEED; + throw sls::RuntimeError("Unknown speed " + s); +} + +template <> +inline defs::timingMode StringTo(const std::string& s) { + if (s == "auto") + return defs::AUTO_TIMING; + if (s == "trigger") + return defs::TRIGGER_EXPOSURE; + if (s == "gating") + return defs::GATED; + if (s == "burst_trigger") + return defs::BURST_TRIGGER; + throw sls::RuntimeError("Unknown timing mode " + s); +} + +template <> +inline defs::frameDiscardPolicy StringTo(const std::string& s) { + if (s == "nodiscard") + return defs::NO_DISCARD; + if (s == "discardempty") + return defs::DISCARD_EMPTY_FRAMES; + if (s == "discardpartial") + return defs::DISCARD_PARTIAL_FRAMES; + throw sls::RuntimeError("Unknown frame discard policy " + s); +} + +template <> +inline defs::fileFormat StringTo(const std::string& s) { + if (s == "hdf5") + return defs::HDF5; + if (s == "binary") + return defs::BINARY; + throw sls::RuntimeError("Unknown file format " + s); +} + +template <> +inline defs::externalSignalFlag StringTo(const std::string& s) { + if (s == "trigger_in_rising_edge") + return defs::TRIGGER_IN_RISING_EDGE; + if (s == "trigger_in_falling_edge") + return defs::TRIGGER_IN_FALLING_EDGE; + throw sls::RuntimeError("Unknown external signal flag " + s); +} + +template <> +inline defs::readoutMode StringTo(const std::string& s) { + if (s == "analog") + return defs::ANALOG_ONLY; + if (s == "digital") + return defs::DIGITAL_ONLY; + if (s == "analog_digital") + return defs::ANALOG_AND_DIGITAL; + throw sls::RuntimeError("Unknown readout mode " + s); +} + + /** For types with a .str() method use this for conversion */ template typename std::enable_if::value, std::string>::type @@ -193,6 +483,4 @@ ToString(const T &obj) { - - } // namespace sls diff --git a/slsSupportLib/include/genericSocket.h b/slsSupportLib/include/genericSocket.h index 1b7e7d00f..e9c42d58f 100755 --- a/slsSupportLib/include/genericSocket.h +++ b/slsSupportLib/include/genericSocket.h @@ -183,7 +183,7 @@ public: if (p == UDP) { uint64_t desired_size = buf_size; uint64_t real_size = desired_size * 2; // kernel doubles this value for bookkeeping overhead - uint64_t ret_size = -1; + uint64_t ret_size = 0; socklen_t optlen = sizeof(uint64_t); // confirm if sufficient @@ -192,12 +192,13 @@ public: "Could not get rx socket receive buffer size"; } else if (ret_size >= real_size) { actual_udp_socket_buffer_size = ret_size; - FILE_LOG(logDEBUG1) << "[Port " << port_number << "] " - "UDP rx socket buffer size is sufficient (" << ret_size << ")"; + FILE_LOG(logINFO) << "[Port " << port_number << "] " + "UDP rx socket real buffer size is sufficient (" << ret_size << ")"; } // not sufficient, enhance size else { + FILE_LOG(logINFO) << "[Port " << port_number << "] UDP rx socket real buffer size to be modified from " << ret_size << " to " << real_size; // set buffer size (could not set) if (setsockopt(sockfd.fd, SOL_SOCKET, SO_RCVBUF, &desired_size, optlen) == -1) { @@ -234,7 +235,7 @@ public: (ret_size/2) << " (Real size:" << ret_size << ")."; } else { FILE_LOG(logINFO) << "[Port " << port_number << "] " - "UDP rx socket buffer size modified to " << ret_size; + "UDP rx socket buffer size (force) modified to " << ret_size; } } } diff --git a/slsSupportLib/include/sls_detector_defs.h b/slsSupportLib/include/sls_detector_defs.h index ce6de7045..313347209 100755 --- a/slsSupportLib/include/sls_detector_defs.h +++ b/slsSupportLib/include/sls_detector_defs.h @@ -107,13 +107,13 @@ class slsDetectorDefs { */ enum timerIndex { FRAME_NUMBER, /**< number of real time frames: total number of - acquisitions is number or frames*number of cycles */ + acquisitions is number or frames*number of triggers */ ACQUISITION_TIME, /**< exposure time */ FRAME_PERIOD, /**< period between exposures */ DELAY_AFTER_TRIGGER, /**< delay between trigger and start of exposure or readout (in triggered mode) */ - CYCLES_NUMBER, /**< number of cycles: total number of acquisitions is - number or frames*number of cycles */ + TRIGGER_NUMBER, /**< number of triggers: total number of acquisitions is + number or frames*number of triggers (* number of storage cells [jungfrau]) */ ACTUAL_TIME, /**< Actual time of the detector's internal timer */ MEASUREMENT_TIME, /**< Time of the measurement from the detector (fifo) */ @@ -578,286 +578,17 @@ format return std::string("disabled"); }; - /** returns detector type string from detector type index - \param t string can be EIGER, GOTTHARD, JUNGFRAU, CHIPTESTBOARD, MYTHEN3, GOTTHARD2 - \returns Eiger, Gotthard, Jungfrau, JungfrauCTB, Mythen3, Gotthard2, Unknown - */ - static std::string detectorTypeToString(detectorType t) { - switch (t) { - case EIGER: - return std::string("Eiger"); - case GOTTHARD: - return std::string("Gotthard"); - case JUNGFRAU: - return std::string("Jungfrau"); - case CHIPTESTBOARD: - return std::string("JungfrauCTB"); - case MOENCH: - return std::string("Moench"); - case MYTHEN3: - return std::string("Mythen3"); - case GOTTHARD2: - return std::string("Gotthard2"); - default: - return std::string("Unknown"); - } - }; - /** returns detector type index from detector type string - \param type can be Eiger, Gotthard, Jungfrau, JungfrauCTB, Mythen3, Gotthard2 - \returns EIGER, GOTTHARD, JUNGFRAU, CHIPTESTBOARD, MYTHEN3, GOTTHARD2, GENERIC - */ - static detectorType detectorTypeToEnum(const std::string &type) { - if (type == "Eiger") - return EIGER; - if (type == "Gotthard") - return GOTTHARD; - if (type == "Jungfrau") - return JUNGFRAU; - if (type == "JungfrauCTB") - return CHIPTESTBOARD; - if (type == "Moench") - return MOENCH; - if (type == "Mythen3") - return MYTHEN3; - if (type == "Gotthard2") - return GOTTHARD2; - return GENERIC; - }; - /** returns string from run status index - \param s can be ERROR, WAITING, RUNNING, TRANSMITTING, RUN_FINISHED, - STOPPED \returns string error, waiting, running, data, finished, stopped, - idle - */ - static std::string runStatusType(runStatus s) { - switch (s) { - case ERROR: - return std::string("error"); - case WAITING: - return std::string("waiting"); - case RUNNING: - return std::string("running"); - case TRANSMITTING: - return std::string("data"); - case RUN_FINISHED: - return std::string("finished"); - case STOPPED: - return std::string("stopped"); - default: - return std::string("idle"); - } - }; - - /** returns string from file format index - \param s can be BINARY, HDF5 - \returns string binary, hdf5 - */ - static std::string getFileFormatType(fileFormat f) { - switch (f) { - case HDF5: - return std::string("hdf5"); - case BINARY: - return std::string("binary"); - default: - return std::string("unknown"); - } - }; - - /** - * Returns string of frame discard policy index - * @param f can be NO_DISCARD, DISCARD_EMPTY_FRAMES, DISCARD_PARTIAL_FRAMES - * @returns No Discard, Discard Empty Frames, Discard Partial Frames, - * unknown - */ - static std::string getFrameDiscardPolicyType(frameDiscardPolicy f) { - switch (f) { - case NO_DISCARD: - return std::string("No Discard"); - case DISCARD_EMPTY_FRAMES: - return std::string("Discard Empty Frames"); - case DISCARD_PARTIAL_FRAMES: - return std::string("Discard Partial Frames"); - default: - return std::string("unknown"); - } - }; - - /** returns std::string from external signal type index - \param f can be TRIGGER_IN_RISING_EDGE, TRIGGER_IN_FALLING_EDGE, - \returns std::string trigger_in_rising_edge, trigger_in_falling_edge, unknown - */ - static std::string externalSignalType(externalSignalFlag f) { - switch (f) { - case TRIGGER_IN_RISING_EDGE: - return std::string("trigger_in_rising_edge"); - case TRIGGER_IN_FALLING_EDGE: - return std::string("trigger_in_falling_edge"); - default: - return std::string("unknown"); - } - }; - - /** returns external signal type index from std::string - \param sval trigger_in_rising_edge, trigger_in_falling_edge, unknown - \returns can be TRIGGER_IN_RISING_EDGE, TRIGGER_IN_FALLING_EDGE, - GET_EXTERNAL_SIGNAL_FLAG (if unknown) - */ - - static externalSignalFlag externalSignalType(std::string sval) { - if (sval == "trigger_in_rising_edge") - return TRIGGER_IN_RISING_EDGE; - if (sval == "trigger_in_falling_edge") - return TRIGGER_IN_FALLING_EDGE; - return GET_EXTERNAL_SIGNAL_FLAG; - }; - - /** returns detector settings std::string from index - \param s can be STANDARD, FAST, HIGHGAIN, DYNAMICGAIN, LOWGAIN, - MEDIUMGAIN, VERYHIGHGAIN, DYNAMICHG0, FIXGAIN1, FIXGAIN2, - FORCESWITCHG1, FORCESWITCHG2, GET_SETTINGS \returns standard, fast, - highgain, dynamicgain, lowgain, mediumgain, veryhighgain, - dynamichg0, fixgain1, fixgain2, forceswitchg1, forceswitchg2, - verylowgain, undefined - */ - static std::string getDetectorSettings(detectorSettings s) { - switch (s) { - case STANDARD: - return std::string("standard"); - case FAST: - return std::string("fast"); - case HIGHGAIN: - return std::string("highgain"); - case DYNAMICGAIN: - return std::string("dynamicgain"); - case LOWGAIN: - return std::string("lowgain"); - case MEDIUMGAIN: - return std::string("mediumgain"); - case VERYHIGHGAIN: - return std::string("veryhighgain"); - case DYNAMICHG0: - return std::string("dynamichg0"); - case FIXGAIN1: - return std::string("fixgain1"); - case FIXGAIN2: - return std::string("fixgain2"); - case FORCESWITCHG1: - return std::string("forceswitchg1"); - case FORCESWITCHG2: - return std::string("forceswitchg2"); - case VERYLOWGAIN: - return std::string("verylowgain"); - case UNINITIALIZED: - return std::string("uninitialized"); - default: - return std::string("undefined"); - } - }; - - /** returns detector settings std::string from index - \param s can be standard, fast, highgain, dynamicgain, lowgain, - mediumgain, veryhighgain, dynamichg0, fixgain1, fixgain2, - forceswitchg1, forceswitchg2, undefined \returns setting index - STANDARD, FAST, HIGHGAIN, DYNAMICGAIN, LOWGAIN, MEDIUMGAIN, - VERYHIGHGAIN,DYNAMICHG0, FIXGAIN1, FIXGAIN2, FORCESWITCHG1, - FORCESWITCHG2, VERYLOWGAIN, GET_SETTINGS - */ - - static detectorSettings getDetectorSettings(std::string s) { - if (s == "standard") - return STANDARD; - if (s == "fast") - return FAST; - if (s == "highgain") - return HIGHGAIN; - if (s == "dynamicgain") - return DYNAMICGAIN; - if (s == "lowgain") - return LOWGAIN; - if (s == "mediumgain") - return MEDIUMGAIN; - if (s == "veryhighgain") - return VERYHIGHGAIN; - if (s == "dynamichg0") - return DYNAMICHG0; - if (s == "fixgain1") - return FIXGAIN1; - if (s == "fixgain2") - return FIXGAIN2; - if (s == "forceswitchg1") - return FORCESWITCHG1; - if (s == "forceswitchg2") - return FORCESWITCHG2; - if (s == "verylowgain") - return VERYLOWGAIN; - return GET_SETTINGS; - }; - - /** - returns external communication mode std::string from index - \param f can be AUTO_TIMING, TRIGGER_EXPOSURE, GATED, BURST_TRIGGER, - GET_TIMING_MODE \returns auto, trigger, gating, - burst_trigger, unknown - */ - - static std::string timingModeType(timingMode f) { - switch (f) { - case AUTO_TIMING: - return std::string("auto"); - case TRIGGER_EXPOSURE: - return std::string("trigger"); - case GATED: - return std::string("gating"); - case BURST_TRIGGER: - return std::string("burst_trigger"); - default: - return std::string("unknown"); - } - }; - - /** - returns external communication mode index from std::string - \param sval can be auto, trigger, gating, burst_trigger - \returns AUTO_TIMING, TRIGGER_EXPOSURE, GATED, BURST_TRIGGER, - GET_TIMING_MODE - */ - - static timingMode timingModeType(std::string sval) { - if (sval == "auto") - return AUTO_TIMING; - if (sval == "trigger") - return TRIGGER_EXPOSURE; - if (sval == "gating") - return GATED; - if (sval == "burst_trigger") - return BURST_TRIGGER; - return GET_TIMING_MODE; - }; - - /** returns std::string from file format index - \param s can be RAW, HDF5 - \returns std::string raw, hdf5 - */ - static std::string fileFormats(fileFormat f) { - switch (f) { - case BINARY: - return std::string("binary"); - case HDF5: - return std::string("hdf5"); - default: - return std::string("unknown"); - } - }; /** returns std::string from timer index \param s can be FRAME_NUMBER,ACQUISITION_TIME,FRAME_PERIOD, - DELAY_AFTER_TRIGGER, CYCLES_NUMBER, + DELAY_AFTER_TRIGGER, TRIGGER_NUMBER, ACTUAL_TIME,MEASUREMENT_TIME, PROGRESS,FRAMES_FROM_START,FRAMES_FROM_START_PG,ANALOG_SAMPLES,DIGITAL_SAMPLES,SUBFRAME_ACQUISITION_TIME,STORAGE_CELL_NUMBER, SUBFRAME_DEADTIME \returns std::string frame_number,acquisition_time,frame_period, - delay_after_trigger, cycles_number, + delay_after_trigger, triggers_number, actual_time,measurement_time, progress,frames_from_start,frames_from_start_pg,analog_samples, digital_samples,subframe_acquisition_time,storage_cell_number, SUBFRAME_DEADTIME @@ -872,8 +603,8 @@ format return std::string("frame_period"); case DELAY_AFTER_TRIGGER: return std::string("delay_after_trigger"); - case CYCLES_NUMBER: - return std::string("cycles_number"); + case TRIGGER_NUMBER: + return std::string("triggers_number"); case ACTUAL_TIME: return std::string("actual_time"); case MEASUREMENT_TIME: @@ -899,83 +630,6 @@ format } }; - /** returns string from readoutMode */ - static std::string getReadoutModeType(readoutMode mode) { - switch(mode) { - case ANALOG_ONLY: - return "analog"; - case DIGITAL_ONLY: - return "digital"; - case ANALOG_AND_DIGITAL: - return "analog_digital"; - default: - return "Unknown"; - } - }; - - /** returns readoutMode from string */ - static readoutMode getReadoutModeType(std::string smode) { - if (smode == "analog") - return ANALOG_ONLY; - if (smode == "digital") - return DIGITAL_ONLY; - if (smode == "analog_digital") - return ANALOG_AND_DIGITAL; - throw sls::RuntimeError("Unknown readout mode " + smode); - }; - - /** returns string from speedLevel */ - static std::string getSpeedLevelType(speedLevel mode) { - switch(mode) { - case FULL_SPEED: - return "full_speed"; - case HALF_SPEED: - return "half_speed"; - case QUARTER_SPEED: - return "quarter_speed"; - // default: - // return "Unknown"; - } - }; - - /** returns speedLevel from string */ - static speedLevel getSpeedLevelType(std::string smode) { - if (smode == "full_speed") - return FULL_SPEED; - if (smode == "half_speed") - return HALF_SPEED; - if (smode == "quarter_speed") - return QUARTER_SPEED; - throw sls::RuntimeError("Unknown speed level mode " + smode); - }; - - /** - @short returns adc index from std::string - \param s can be temp_fpga, temp_fpgaext, temp_10ge, temp_dcdc, temp_sodl, - temp_sodr, temp_fpgafl, temp_fpgafr \returns TEMPERATURE_FPGA, - TEMPERATURE_FPGAEXT, TEMPERATURE_10GE, TEMPERATURE_DCDC, - TEMPERATURE_SODL, TEMPERATURE_SODR, TEMPERATURE_FPGA2, TEMPERATURE_FPGA3, - -1 when unknown mode - */ - static int getADCIndex(std::string s) { - if (s == "temp_fpga") - return TEMPERATURE_FPGA; - if (s == "temp_fpgaext") - return TEMPERATURE_FPGAEXT; - if (s == "temp_10ge") - return TEMPERATURE_10GE; - if (s == "temp_dcdc") - return TEMPERATURE_DCDC; - if (s == "temp_sodl") - return TEMPERATURE_SODL; - if (s == "temp_sodr") - return TEMPERATURE_SODR; - if (s == "temp_fpgafl") - return TEMPERATURE_FPGA2; - if (s == "temp_fpgafr") - return TEMPERATURE_FPGA3; - return -1; - }; /** @short returns dac index from std::string @@ -1007,38 +661,6 @@ format return -1; }; - /** - @short returns receiver frame discard policy from std::string - \param s can be nodiscard, discardempty, discardpartial - \returns NO_DISCARD, DISCARD_EMPTY_FRAMES, DISCARD_PARTIAL_FRAMES, - GET_FRAME_DISCARD_POLICY when unknown mode - */ - static frameDiscardPolicy getReceiverFrameDiscardPolicy(std::string s) { - if (s == "nodiscard") - return NO_DISCARD; - if (s == "discardempty") - return DISCARD_EMPTY_FRAMES; - if (s == "discardpartial") - return DISCARD_PARTIAL_FRAMES; - return GET_FRAME_DISCARD_POLICY; - }; - - /** returns std::string from frame discard policy - \param f can be NO_DISCARD, DISCARD_EMPTY_FRAMES, DISCARD_PARTIAL_FRAMES - \returns std::string nodiscard, discardempty, discardpartial, unknown - */ - static std::string getReceiverFrameDiscardPolicy(frameDiscardPolicy f) { - switch (f) { - case NO_DISCARD: - return std::string("nodiscard"); - case DISCARD_EMPTY_FRAMES: - return std::string("discardempty"); - case DISCARD_PARTIAL_FRAMES: - return std::string("discardpartial"); - default: - return std::string("unknown"); - } - }; /** * returns frameModeType as enum @@ -1215,9 +837,7 @@ struct detParameters { nGappixelsY = 0; break; default: - throw sls::RuntimeError( - "Unknown detector type! " + - slsDetectorDefs::detectorTypeToString(type)); + throw sls::RuntimeError("Unknown detector type! " + std::to_string(type)); } } }; diff --git a/slsSupportLib/include/versionAPI.h b/slsSupportLib/include/versionAPI.h index c76e5d22b..a0fd69d0f 100644 --- a/slsSupportLib/include/versionAPI.h +++ b/slsSupportLib/include/versionAPI.h @@ -4,9 +4,9 @@ #define APIRECEIVER 0x190722 #define APIGUI 0x190723 #define APIMOENCH 0x190820 -#define APICTB 0x190930 -#define APIGOTTHARD 0x190930 -#define APIEIGER 0x190930 -#define APIMYTHEN3 0x191008 -#define APIJUNGFRAU 0x191008 +#define APICTB 0x191011 +#define APIGOTTHARD 0x191011 +#define APIJUNGFRAU 0x191011 +#define APIMYTHEN3 0x191011 +#define APIEIGER 0x191014 #define APIGOTTHARD2 0x191017 diff --git a/tests/test.cpp b/tests/test.cpp index 66ca3db98..22474913c 100755 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -5,6 +5,7 @@ #define CATCH_CONFIG_RUNNER #include "catch.hpp" #include "sls_detector_defs.h" +#include "ToString.h" #include "tests/config.h" #include @@ -38,7 +39,10 @@ int main(int argc, char *argv[]) { return ret; } - test::type = slsDetectorDefs::detectorTypeToEnum(test::detector_type); + test::type = slsDetectorDefs::GENERIC; + if (!test::detector_type.empty()) { + test::type = sls::StringTo(test::detector_type); + } return session.run(); } \ No newline at end of file