From e14519c23663d06d0ff7ff8036e8c55948685c2b Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Fri, 3 May 2019 20:37:40 +0200 Subject: [PATCH 1/4] slsReceiver: removed special receiver config, added rx_dbitlist, rx_dbitoffset to put bits together in file, connected adcinvert, extsamplingsrc and extsampling properly to the detector, added tests --- CMakeLists.txt | 1 - cmk.sh | 13 +- .../test-integrationDectector.cpp | 72 +++++++ .../slsDetectorFunctionList.c | 32 +++ .../slsDetectorFunctionList.h | 4 + .../slsDetectorServer_funcs.c | 109 +++++++++- .../slsDetectorServer_funcs.h | 5 +- .../include/multiSlsDetector.h | 78 +++++++ slsDetectorSoftware/include/slsDetector.h | 86 +++++++- slsDetectorSoftware/src/multiSlsDetector.cpp | 94 +++++++- slsDetectorSoftware/src/slsDetector.cpp | 163 ++++++++++++++ .../src/slsDetectorCommand.cpp | 201 +++++++++++++----- .../tests/test-slsDetector.cpp | 43 ++++ slsReceiverSoftware/CMakeLists.txt | 14 +- slsReceiverSoftware/include/DataProcessor.h | 56 ++--- slsReceiverSoftware/include/slsReceiver.h | 15 -- .../include/slsReceiverImplementation.h | 65 +++--- .../include/slsReceiverTCPIPInterface.h | 40 +--- .../include/slsReceiverUsers.h | 10 - slsReceiverSoftware/src/DataProcessor.cpp | 75 ++++--- slsReceiverSoftware/src/mainCustomized.cpp | 189 ---------------- slsReceiverSoftware/src/slsReceiver.cpp | 12 +- .../src/slsReceiverImplementation.cpp | 47 ++-- .../src/slsReceiverTCPIPInterface.cpp | 127 +++++++++-- slsReceiverSoftware/src/slsReceiverUsers.cpp | 5 - slsSupportLib/include/sls_detector_funcs.h | 15 ++ slsSupportLib/include/versionAPI.h | 2 +- 27 files changed, 1088 insertions(+), 485 deletions(-) delete mode 100755 slsReceiverSoftware/src/mainCustomized.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 3865b5643..87f1c0bdb 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,7 +38,6 @@ option (SLS_USE_HDF5 "HDF5 File format" OFF) option (SLS_USE_TEXTCLIENT "Text Client" OFF) option (SLS_USE_RECEIVER "Receiver" OFF) option (SLS_USE_GUI "GUI" OFF) -option (SLS_USE_MYTHEN302_CTB_RECEIVER "Mythen302 CTB Receiver" OFF) option (SLS_USE_TESTS "TESTS" ON) option (SLS_USE_INTEGRATION_TESTS "Integration Tests" ON) option(SLS_USE_SANITIZER "Sanitizers for debugging" OFF) diff --git a/cmk.sh b/cmk.sh index 31f7fef44..661d6c526 100755 --- a/cmk.sh +++ b/cmk.sh @@ -8,7 +8,6 @@ RECEIVER=0 GUI=0 DEBUG=0 PYTHON=0 -SPECIAL_RECEIVER_TYPE=0 CLEAN=0 @@ -17,7 +16,7 @@ CMAKE_PRE="" CMAKE_POST="" usage() { echo -e " -Usage: $0 [-c] [-b] [-p] [e] [t] [r] [g] [-h] [-d ] [-j] [-s] +Usage: $0 [-c] [-b] [-p] [e] [t] [r] [g] [-h] [-d ] [-j] -[no option]: only make -c: Clean -b: Builds/Rebuilds CMake files normal mode @@ -29,7 +28,6 @@ Usage: $0 [-c] [-b] [-p] [e] [t] [r] [g] [-h] [-d ] [-j] list = m.getReceiverDbitList(); + list.clear(); + for (int i = 0; i < 10; ++i) + list.push_back(i); + m.setReceiverDbitList(list); + + CHECK(m.getReceiverDbitList().size() == 10); + + list.push_back(64); + CHECK_THROWS_AS(m.setReceiverDbitList(list), sls::RuntimeError); + CHECK_THROWS_WITH(m.setReceiverDbitList(list), + Catch::Matchers::Contains("be between 0 and 63")); + + list.clear(); + for (int i = 0; i < 65; ++i) + list.push_back(i); + CHECK(list.size() == 65); + CHECK_THROWS_WITH(m.setReceiverDbitList(list), + Catch::Matchers::Contains("be greater than 64")); + + list.clear(); + m.setReceiverDbitList(list); + CHECK(m.getReceiverDbitList().empty()); + + // adcinvert + m.setADCInvert(0); + CHECK(m.getADCInvert() == 0); + m.setADCInvert(5); + CHECK(m.getADCInvert() == 5); + m.setADCInvert(-1); + CHECK(m.getADCInvert() == -1); + + // ext sampling reg + m.setExternalSamplingSource(0); + CHECK(m.getExternalSamplingSource() == 0); + m.setExternalSamplingSource(62); + CHECK(m.getExternalSamplingSource() == 62); + CHECK_THROWS_WITH(m.setExternalSamplingSource(64), + Catch::Matchers::Contains("be 0-63")); + CHECK(m.getExternalSamplingSource() == 62); + m.setExternalSampling(1); + CHECK(m.getExternalSampling() == 1); + m.setExternalSampling(0); + CHECK(m.getExternalSampling() == 0); + m.setExternalSampling(1); + CHECK(m.getExternalSampling() == 1); + CHECK(m.readRegister(0x7b) == 0x1003E); + } \ No newline at end of file diff --git a/slsDetectorServers/ctbDetectorServer/slsDetectorFunctionList.c b/slsDetectorServers/ctbDetectorServer/slsDetectorFunctionList.c index a71a11d96..2a71dbc1e 100755 --- a/slsDetectorServers/ctbDetectorServer/slsDetectorFunctionList.c +++ b/slsDetectorServers/ctbDetectorServer/slsDetectorFunctionList.c @@ -714,6 +714,38 @@ uint32_t getADCEnableMask() { return retval; } +void setADCInvertRegister(uint32_t val) { + FILE_LOG(logINFO, ("Setting ADC Port Invert Reg to 0x%x\n", val)); + bus_w(ADC_PORT_INVERT_REG, val); +} + +uint32_t getADCInvertRegister() { + return bus_r(ADC_PORT_INVERT_REG); +} + +int setExternalSamplingSource(int val) { + uint32_t addr = DBIT_EXT_TRG_REG; + if (val >= 0) { + FILE_LOG(logINFO, ("Setting External sampling source to %d\n", val)); + bus_w(addr, bus_r(addr) &~ DBIT_EXT_TRG_SRC_MSK); + bus_w(addr, bus_r(addr) | ((val << DBIT_EXT_TRG_SRC_OFST) & DBIT_EXT_TRG_SRC_MSK)); + } + return ((bus_r(addr) & DBIT_EXT_TRG_SRC_MSK) >> DBIT_EXT_TRG_SRC_OFST); +} + +int setExternalSampling(int val) { + uint32_t addr = DBIT_EXT_TRG_REG; + if (val > 0) { + FILE_LOG(logINFO, ("Enabling External sampling\n")); + bus_w(addr, bus_r(addr) | DBIT_EXT_TRG_OPRTN_MD_MSK); + } + else if (val == 0) { + FILE_LOG(logINFO, ("Disabling External sampling\n")); + bus_w(addr, bus_r(addr) &~ DBIT_EXT_TRG_OPRTN_MD_MSK); + } + + return ((bus_r(addr) & DBIT_EXT_TRG_OPRTN_MD_MSK) >> DBIT_EXT_TRG_OPRTN_MD_OFST); +} /* parameters - speed, readout */ diff --git a/slsDetectorServers/slsDetectorServer/slsDetectorFunctionList.h b/slsDetectorServers/slsDetectorServer/slsDetectorFunctionList.h index ba4ae9da8..57aad1b21 100755 --- a/slsDetectorServers/slsDetectorServer/slsDetectorFunctionList.h +++ b/slsDetectorServers/slsDetectorServer/slsDetectorFunctionList.h @@ -115,6 +115,10 @@ ROI* setROI(int n, ROI arg[], int *retvalsize, int *ret); #if defined(CHIPTESTBOARDD) || defined(MOENCHD) int setADCEnableMask(uint32_t mask); uint32_t getADCEnableMask(); +void setADCInvertRegister(uint32_t val); +uint32_t getADCInvertRegister(); +int setExternalSamplingSource(int val); +int setExternalSampling(int val); #endif // parameters - readout diff --git a/slsDetectorServers/slsDetectorServer/slsDetectorServer_funcs.c b/slsDetectorServers/slsDetectorServer/slsDetectorServer_funcs.c index 3bdcd7f77..97b9f99bd 100755 --- a/slsDetectorServers/slsDetectorServer/slsDetectorServer_funcs.c +++ b/slsDetectorServers/slsDetectorServer/slsDetectorServer_funcs.c @@ -238,7 +238,10 @@ const char* getFunctionName(enum detFuncs func) { case F_REBOOT_CONTROLLER: return "F_REBOOT_CONTROLLER"; case F_SET_ADC_ENABLE_MASK: return "F_SET_ADC_ENABLE_MASK"; case F_GET_ADC_ENABLE_MASK: return "F_GET_ADC_ENABLE_MASK"; - + case F_SET_ADC_INVERT: return "F_SET_ADC_INVERT"; + case F_GET_ADC_INVERT: return "F_GET_ADC_INVERT"; + case F_EXTERNAL_SAMPLING_SOURCE: return "F_EXTERNAL_SAMPLING_SOURCE"; + case F_EXTERNAL_SAMPLING: return "F_EXTERNAL_SAMPLING"; default: return "Unknown Function"; } } @@ -317,6 +320,10 @@ void function_table() { flist[F_REBOOT_CONTROLLER] = &reboot_controller; flist[F_SET_ADC_ENABLE_MASK] = &set_adc_enable_mask; flist[F_GET_ADC_ENABLE_MASK] = &get_adc_enable_mask; + flist[F_SET_ADC_INVERT] = &set_adc_invert; + flist[F_GET_ADC_INVERT] = &get_adc_invert; + flist[F_EXTERNAL_SAMPLING_SOURCE] = &set_external_sampling_source; + flist[F_EXTERNAL_SAMPLING] = &set_external_sampling; // check if (NUM_DET_FUNCTIONS >= RECEIVER_ENUM_START) { @@ -3904,3 +3911,103 @@ int get_adc_enable_mask(int file_des) { #endif return Server_SendResult(file_des, INT32, UPDATE, &retval, sizeof(retval)); } + + +int set_adc_invert(int file_des) { + ret = OK; + memset(mess, 0, sizeof(mess)); + uint32_t arg = 0; + + if (receiveData(file_des, &arg, sizeof(arg), INT32) < 0) + return printSocketReadError(); + FILE_LOG(logDEBUG1, ("Seting ADC Invert to %u\n", arg)); + +#if (!defined(MOENCHD)) && (!defined(CHIPTESTBOARDD)) + functionNotImplemented(); +#else + // only set + if (Server_VerifyLock() == OK) { + setADCInvertRegister(arg); + uint32_t retval = getADCInvertRegister(); + if (arg != retval) { + ret = FAIL; + sprintf(mess, "Could not set ADC Invert register. Set 0x%x, but read 0x%x\n", arg, retval); + FILE_LOG(logERROR,(mess)); + } + } +#endif + return Server_SendResult(file_des, INT32, UPDATE, NULL, 0); +} + + +int get_adc_invert(int file_des) { + ret = OK; + memset(mess, 0, sizeof(mess)); + uint32_t retval = -1; + + FILE_LOG(logDEBUG1, ("Getting ADC Invert register \n")); + +#if (!defined(MOENCHD)) && (!defined(CHIPTESTBOARDD)) + functionNotImplemented(); +#else + // get + retval = getADCInvertRegister(); + FILE_LOG(logDEBUG1, ("ADC Invert register retval: %u\n", retval)); +#endif + return Server_SendResult(file_des, INT32, UPDATE, &retval, sizeof(retval)); +} + + + +int set_external_sampling_source(int file_des) { + ret = OK; + memset(mess, 0, sizeof(mess)); + int arg = -1; + int retval = -1; + + if (receiveData(file_des, &arg, sizeof(arg), INT32) < 0) + return printSocketReadError(); + FILE_LOG(logDEBUG1, ("Setting external sampling source to %d\n", arg)); + +#ifndef CHIPTESTBOARDD + functionNotImplemented(); +#else + // set & get + if ((arg == -1) || (Server_VerifyLock() == OK)) { + if (arg < -1 || arg > 63) { + ret = FAIL; + sprintf(mess, "Could not set external sampling source to %d. Value must be 0-63.\n", arg); + FILE_LOG(logERROR,(mess)); + } else { + retval = setExternalSamplingSource(arg); + FILE_LOG(logDEBUG1, ("External Sampling source: %d\n", retval)); + validate(arg, retval, "External sampling source", DEC); + } + } +#endif + return Server_SendResult(file_des, INT32, UPDATE, &retval, sizeof(retval)); +} + +int set_external_sampling(int file_des) { + ret = OK; + memset(mess, 0, sizeof(mess)); + int arg = -1; + int retval = -1; + + if (receiveData(file_des, &arg, sizeof(arg), INT32) < 0) + return printSocketReadError(); + FILE_LOG(logDEBUG1, ("Setting external sampling enable to %d\n", arg)); + +#ifndef CHIPTESTBOARDD + functionNotImplemented(); +#else + // set & get + if ((arg == -1) || (Server_VerifyLock() == OK)) { + arg = (arg > 0) ? 1 : arg; + retval = setExternalSampling(arg); + FILE_LOG(logDEBUG1, ("External Sampling enable: %d\n", retval)); + validate(arg, retval, "External sampling enable", DEC); + } +#endif + return Server_SendResult(file_des, INT32, UPDATE, &retval, sizeof(retval)); +} diff --git a/slsDetectorServers/slsDetectorServer/slsDetectorServer_funcs.h b/slsDetectorServers/slsDetectorServer/slsDetectorServer_funcs.h index 25f55902b..6b824b99d 100755 --- a/slsDetectorServers/slsDetectorServer/slsDetectorServer_funcs.h +++ b/slsDetectorServers/slsDetectorServer/slsDetectorServer_funcs.h @@ -99,4 +99,7 @@ int copy_detector_server(int); int reboot_controller(int); int set_adc_enable_mask(int); int get_adc_enable_mask(int); - +int set_adc_invert(int); +int get_adc_invert(int); +int set_external_sampling_source(int); +int set_external_sampling(int); diff --git a/slsDetectorSoftware/include/multiSlsDetector.h b/slsDetectorSoftware/include/multiSlsDetector.h index 812c61829..613034514 100755 --- a/slsDetectorSoftware/include/multiSlsDetector.h +++ b/slsDetectorSoftware/include/multiSlsDetector.h @@ -236,6 +236,10 @@ class multiSlsDetector : public virtual slsDetectorDefs { */ int64_t getReceiverSoftwareVersion(int detPos = -1); + /** + * Get Detector Number + * @returns vector of detector number + */ std::vector getDetectorNumber(); /** * Free shared memory from the command line @@ -438,6 +442,10 @@ class multiSlsDetector : public virtual slsDetectorDefs { */ int setReceiverPort(int port_number = -1, int detPos = -1); + /** + * Get Receiver port + * @returns vector of receiver port + */ std::vector getReceiverPort() const; /** @@ -1305,6 +1313,76 @@ class multiSlsDetector : public virtual slsDetectorDefs { */ uint32_t getADCEnableMask(int detPos = -1); + /** + * Set ADC invert register (CTB, Moench) + * @param value ADC invert value + * @param detPos -1 for all detectors in list or specific detector position + */ + void setADCInvert(uint32_t value, int detPos = -1); + + /** + * Get ADC invert register (CTB, Moench) + * @param detPos -1 for all detectors in list or specific detector position + * @returns ADC invert value + */ + uint32_t getADCInvert(int detPos = -1); + + /** + * Set external sampling source (CTB only) + * @param value external sampling source (Option: 0-63) + * @param detPos -1 for all detectors in list or specific detector position + */ + void setExternalSamplingSource(int value, int detPos = -1); + + /** + * Get external sampling source (CTB only) + * @param detPos -1 for all detectors in list or specific detector position + * @returns external sampling source + */ + int getExternalSamplingSource(int detPos = -1); + + /** + * Set external sampling enable (CTB only) + * @param value external sampling source (Option: 0-63) + * @param detPos -1 for all detectors in list or specific detector position + */ + void setExternalSampling(bool value, int detPos = -1); + + /** + * Get external sampling source (CTB only) + * @param detPos -1 for all detectors in list or specific detector position + * @returns external sampling enable + */ + int getExternalSampling(int detPos = -1); + + /** + * Set external sampling enable (CTB only) + * @param list external sampling source (Option: 0-63) + * @param detPos -1 for all detectors in list or specific detector position + */ + void setReceiverDbitList(std::vector list, int detPos = -1); + + /** + * Get external sampling source (CTB only) + * @param detPos -1 for all detectors in list or specific detector position + * @returns external sampling enable + */ + std::vector getReceiverDbitList(int detPos = -1); + + /** + * Set digital data offset in bytes (CTB only) + * @param value digital data offset in bytes + * @param detPos -1 for all detectors in list or specific detector position + */ + void setReceiverDbitOffset(int value, int detPos = -1); + + /** + * Get digital data offset in bytes (CTB only) + * @param detPos -1 for all detectors in list or specific detector position + * @returns digital data offset in bytes + */ + int getReceiverDbitOffset(int detPos = -1); + /** * Write to ADC register (Gotthard, Jungfrau, ChipTestBoard). For expert * users diff --git a/slsDetectorSoftware/include/slsDetector.h b/slsDetectorSoftware/include/slsDetector.h index c3b92c3bc..e491e25f3 100755 --- a/slsDetectorSoftware/include/slsDetector.h +++ b/slsDetectorSoftware/include/slsDetector.h @@ -16,10 +16,8 @@ class multiSlsDetector; class ServerInterface; class MySocketTCP; -#define SLS_SHMVERSION 0x190430 -#define NCHIPSMAX 10 -#define NCHANSMAX 65536 -#define NDACSMAX 16 +#define SLS_SHMVERSION 0x190503 +#define MAX_RX_DBIT 64 /** @@ -245,6 +243,15 @@ struct sharedSlsDetector { /** overwrite enable */ bool rxFileOverWrite; + + /** receiver dbit size */ + int rxDbitListSize; + + /** receiver dbit list */ + int rxDbitList[MAX_RX_DBIT]; + + /** reciever dbit offset */ + int rxDbitOffset; }; @@ -1218,6 +1225,77 @@ class slsDetector : public virtual slsDetectorDefs{ * @returns ADC Enable mask */ uint32_t getADCEnableMask(); + + /** + * Set ADC invert register (CTB, Moench) + * @param value ADC invert value + * @param detPos -1 for all detectors in list or specific detector position + */ + void setADCInvert(uint32_t value); + + /** + * Get ADC invert register (CTB, Moench) + * @param detPos -1 for all detectors in list or specific detector position + * @returns ADC invert value + */ + uint32_t getADCInvert(); + + /** + * Set external sampling source (CTB only) + * @param value external sampling source (Option: 0-63) + * @param detPos -1 for all detectors in list or specific detector position + * @returns external sampling source + */ + int setExternalSamplingSource(int value); + + /** + * Get external sampling source (CTB only) + * @param detPos -1 for all detectors in list or specific detector position + * @returns external sampling source + */ + int getExternalSamplingSource(); + + /** + * Set external sampling enable (CTB only) + * @param value external sampling source (Option: 0-63) + * @param detPos -1 for all detectors in list or specific detector position + * @returns external sampling enable + */ + int setExternalSampling(int value); + + /** + * Get external sampling source (CTB only) + * @param detPos -1 for all detectors in list or specific detector position + * @returns external sampling enable + */ + int getExternalSampling(); + + /** + * Set external sampling enable (CTB only) + * @param list external sampling source (Option: 0-63) + * @param detPos -1 for all detectors in list or specific detector position + */ + void setReceiverDbitList(std::vector list); + + /** + * Get external sampling source (CTB only) + * @param detPos -1 for all detectors in list or specific detector position + * @returns external sampling enable + */ + std::vector getReceiverDbitList(); + + /** + * Set digital data offset in bytes (CTB only) + * @param value digital data offset in bytes + * @returns digital data offset in bytes + */ + int setReceiverDbitOffset(int value); + + /** + * Get digital data offset in bytes (CTB only) + * @returns digital data offset in bytes + */ + int getReceiverDbitOffset(); /** * Write to ADC register (Gotthard, Jungfrau, ChipTestBoard). For expert users diff --git a/slsDetectorSoftware/src/multiSlsDetector.cpp b/slsDetectorSoftware/src/multiSlsDetector.cpp index 9598deb72..97839a048 100755 --- a/slsDetectorSoftware/src/multiSlsDetector.cpp +++ b/slsDetectorSoftware/src/multiSlsDetector.cpp @@ -2446,22 +2446,18 @@ const slsDetectorDefs::ROI *multiSlsDetector::getROI(int &n, int detPos) { } void multiSlsDetector::setADCEnableMask(uint32_t mask, int detPos) { - // single if (detPos >= 0) { detectors[detPos]->setADCEnableMask(mask); } - // multi parallelCall(&slsDetector::setADCEnableMask, mask); } uint32_t multiSlsDetector::getADCEnableMask(int detPos) { - // single if (detPos >= 0) { return detectors[detPos]->getADCEnableMask(); } - // multi auto r = parallelCall(&slsDetector::getADCEnableMask); if (sls::allEqual(r)) { return r.front(); @@ -2471,6 +2467,96 @@ uint32_t multiSlsDetector::getADCEnableMask(int detPos) { throw RuntimeError("Error: Different Values for function getADCEnableMask"); } +void multiSlsDetector::setADCInvert(uint32_t value, int detPos) { + if (detPos >= 0) { + detectors[detPos]->setADCInvert(value); + } + + parallelCall(&slsDetector::setADCInvert, value); +} + +uint32_t multiSlsDetector::getADCInvert(int detPos) { + if (detPos >= 0) { + return detectors[detPos]->getADCInvert(); + } + + auto r = parallelCall(&slsDetector::getADCInvert); + if (sls::allEqual(r)) { + return r.front(); + } + + // can't have different values + throw RuntimeError("Error: Different Values for function getADCInvert"); +} + +void multiSlsDetector::setExternalSamplingSource(int value, int detPos) { + if (detPos >= 0) { + detectors[detPos]->setExternalSamplingSource(value); + } + + parallelCall(&slsDetector::setExternalSamplingSource, value); +} + +int multiSlsDetector::getExternalSamplingSource(int detPos) { + if (detPos >= 0) { + return detectors[detPos]->getExternalSamplingSource(); + } + + auto r = parallelCall(&slsDetector::getExternalSamplingSource); + return sls::minusOneIfDifferent(r); +} + +void multiSlsDetector::setExternalSampling(bool value, int detPos) { + if (detPos >= 0) { + detectors[detPos]->setExternalSampling(static_cast(value)); + } + + parallelCall(&slsDetector::setExternalSampling, static_cast(value)); +} + +int multiSlsDetector::getExternalSampling(int detPos) { + if (detPos >= 0) { + return detectors[detPos]->getExternalSampling(); + } + + auto r = parallelCall(&slsDetector::getExternalSampling); + return sls::minusOneIfDifferent(r); +} + +void multiSlsDetector::setReceiverDbitList(std::vector list, int detPos) { + if (detPos >= 0) { + detectors[detPos]->setReceiverDbitList(list); + } + + parallelCall(&slsDetector::setReceiverDbitList, list); +} + +std::vector multiSlsDetector::getReceiverDbitList(int detPos) { + if (detPos >= 0) { + return detectors[detPos]->getReceiverDbitList(); + } + + auto r = parallelCall(&slsDetector::getReceiverDbitList); + return sls::minusOneIfDifferent(r); +} + +void multiSlsDetector::setReceiverDbitOffset(int value, int detPos) { + if (detPos >= 0) { + detectors[detPos]->setReceiverDbitOffset(value); + } + + parallelCall(&slsDetector::setReceiverDbitOffset, value); +} + +int multiSlsDetector::getReceiverDbitOffset(int detPos) { + if (detPos >= 0) { + return detectors[detPos]->getReceiverDbitOffset(); + } + + auto r = parallelCall(&slsDetector::getReceiverDbitOffset); + return sls::minusOneIfDifferent(r); +} + int multiSlsDetector::writeAdcRegister(uint32_t addr, uint32_t val, int detPos) { // single if (detPos >= 0) { diff --git a/slsDetectorSoftware/src/slsDetector.cpp b/slsDetectorSoftware/src/slsDetector.cpp index a1cbb2060..9d45316e2 100755 --- a/slsDetectorSoftware/src/slsDetector.cpp +++ b/slsDetectorSoftware/src/slsDetector.cpp @@ -393,6 +393,9 @@ void slsDetector::initializeDetectorStructure(detectorType type) { shm()->rxFileWrite = true; shm()->rxMasterFileWrite = true; shm()->rxFileOverWrite = true; + shm()->rxDbitListSize = 0; + memset(shm()->rxDbitList, 0, MAX_RX_DBIT * sizeof(int)); + shm()->rxDbitOffset = 0; // get the detector parameters based on type detParameters parameters{type}; @@ -1908,6 +1911,8 @@ std::string slsDetector::setReceiverHostname(const std::string &receiverIP) { << "\nrx streaming source ip:" << shm()->rxZmqip << "\nrx additional json header:" << shm()->rxAdditionalJsonHeader << "\nrx_datastream:" << enableDataStreamingFromReceiver(-1) + << "\nrx_dbitlistsize:" << shm()->rxDbitListSize + << "\nrx_DbitOffset:" << shm()->rxDbitOffset << std::endl; if (setDetectorType(shm()->myDetectorType) != GENERIC) { @@ -1954,6 +1959,7 @@ std::string slsDetector::setReceiverHostname(const std::string &receiverIP) { enableTenGigabitEthernet(shm()->tenGigaEnable); setReadOutFlags(GET_READOUT_FLAGS); setADCEnableMask(shm()->adcEnableMask); + setReceiverDbitOffset(shm()->rxDbitOffset); break; case MOENCH: @@ -1971,6 +1977,11 @@ std::string slsDetector::setReceiverHostname(const std::string &receiverIP) { break; } + if (shm()->myDetectorType == CHIPTESTBOARD) { + std::vector list(shm()->rxDbitList, shm()->rxDbitList + shm()->rxDbitListSize); + setReceiverDbitList(list); + } + setReceiverSilentMode(static_cast(shm()->rxSilentMode)); // data streaming setReceiverStreamingFrequency(shm()->rxReadFreq); @@ -2666,6 +2677,143 @@ uint32_t slsDetector::getADCEnableMask() { return shm()->adcEnableMask; } +void slsDetector::setADCInvert(uint32_t value) { + uint32_t arg = value; + FILE_LOG(logDEBUG1) << "Setting ADC Invert to 0x" << std::hex << arg << std::dec; + if (shm()->onlineFlag == ONLINE_FLAG) { + sendToDetector(F_SET_ADC_INVERT, &arg, sizeof(arg), nullptr, 0); + } +} + +uint32_t slsDetector::getADCInvert() { + uint32_t retval = -1; + FILE_LOG(logDEBUG1) << "Getting ADC Invert"; + if (shm()->onlineFlag == ONLINE_FLAG) { + sendToDetector(F_GET_ADC_INVERT, nullptr, 0, &retval, sizeof(retval)); + FILE_LOG(logDEBUG1) << "ADC Invert: 0x" << std::hex << retval << std::dec; + } + return retval; +} + +int slsDetector::setExternalSamplingSource(int value) { + int arg = value; + int retval = -1; + FILE_LOG(logDEBUG1) << "Setting External Sampling Source to " << arg; + if (shm()->onlineFlag == ONLINE_FLAG) { + sendToDetector(F_EXTERNAL_SAMPLING_SOURCE, arg, retval); + FILE_LOG(logDEBUG1) << "External Sampling source: " << retval; + } + return retval; +} + +int slsDetector::getExternalSamplingSource() { + return setExternalSamplingSource(-1); +} + +int slsDetector::setExternalSampling(int value) { + int arg = value; + int retval = -1; + FILE_LOG(logDEBUG1) << "Setting External Sampling to " << arg; + if (shm()->onlineFlag == ONLINE_FLAG) { + sendToDetector(F_EXTERNAL_SAMPLING, arg, retval); + FILE_LOG(logDEBUG1) << "External Sampling: " << retval; + } + return retval; +} + +int slsDetector::getExternalSampling() { + return setExternalSampling(-1); +} + +void slsDetector::setReceiverDbitList(std::vector list) { + FILE_LOG(logDEBUG1) << "Setting Receiver Dbit List"; + + if (list.size() > 64) { + throw sls::RuntimeError("Dbit list size cannot be greater than 64\n"); + } + for (auto &it : list) { + if (it < 0 || it > 63) { + throw sls::RuntimeError("Dbit list value must be between 0 and 63\n"); + } + } + + // copy size and vector to shm + shm()->rxDbitListSize = list.size(); + std::copy(list.begin(), list.end(), shm()->rxDbitList); + + int ret = FAIL; + if (shm()->rxOnlineFlag == ONLINE_FLAG) { + int fnum = F_SET_RECEIVER_DBIT_LIST; + int arg = list.size(); + auto receiver = + sls::ClientSocket("Receiver", shm()->rxHostname, shm()->rxTCPPort); + receiver.sendData(&fnum, sizeof(fnum)); + receiver.sendData(&arg, sizeof(arg)); + receiver.sendData(shm()->rxDbitList, arg * sizeof(int)); + receiver.receiveData(&ret, sizeof(ret)); + if (ret == FAIL) { + char mess[MAX_STR_LENGTH]{}; + receiver.receiveData(mess, MAX_STR_LENGTH); + throw ReceiverError("Receiver " + std::to_string(detId) + + " returned error: " + std::string(mess)); + } + } + if (ret == FORCE_UPDATE) { + ret = updateCachedReceiverVariables(); + } +} + +std::vector slsDetector::getReceiverDbitList() { + int fnum = F_GET_RECEIVER_DBIT_LIST; + int ret = FAIL; + std::vector retval; + int retsize = 0; + FILE_LOG(logDEBUG1) << "Getting Receiver Dbit List"; + if (shm()->rxOnlineFlag == ONLINE_FLAG) { + auto receiver = + sls::ClientSocket("Receiver", shm()->rxHostname, shm()->rxTCPPort); + receiver.sendData(&fnum, sizeof(fnum)); + receiver.receiveData(&ret, sizeof(ret)); + if (ret == FAIL) { + char mess[MAX_STR_LENGTH]{}; + receiver.receiveData(mess, MAX_STR_LENGTH); + throw ReceiverError("Receiver " + std::to_string(detId) + + " returned error: " + std::string(mess)); + } + receiver.receiveData(&retsize, sizeof(retsize)); + int list[retsize]; + receiver.receiveData(list, sizeof(list)); + + // copy after no errors + shm()->rxDbitListSize = retsize; + std::copy(list, list + retsize, shm()->rxDbitList); + } + + if (shm()->rxDbitListSize) { + retval.resize(shm()->rxDbitListSize); + std::copy(shm()->rxDbitList, shm()->rxDbitList + shm()->rxDbitListSize, std::begin(retval)); + } + + return retval; +} + +int slsDetector::setReceiverDbitOffset(int value) { + int arg = value; + int retval = -1; + if (value >= 0) + shm()->rxDbitOffset = value; + FILE_LOG(logDEBUG1) << "Setting digital bit offset in receiver to " << arg; + if (shm()->rxOnlineFlag == ONLINE_FLAG) { + sendToReceiver(F_RECEIVER_DBIT_OFFSET, arg, retval); + FILE_LOG(logDEBUG1) << "Receiver digital bit offset: " << retval; + } + return shm()->rxDbitOffset; +} + +int slsDetector::getReceiverDbitOffset() { + return shm()->rxDbitOffset; +} + int slsDetector::writeAdcRegister(uint32_t addr, uint32_t val) { uint32_t args[]{addr, val}; FILE_LOG(logDEBUG1) << "Writing to ADC register 0x" << std::hex << addr @@ -3295,6 +3443,21 @@ int slsDetector::updateCachedReceiverVariables() const { n += receiver.receiveData(&i32, sizeof(i32)); shm()->rxSilentMode = static_cast(i32); + // dbit list size + { + int listsize = 0; + n += receiver.receiveData(&listsize, sizeof(listsize)); + int list[listsize]; + n += receiver.receiveData(list, sizeof(list)); + // copy after no errors + shm()->rxDbitListSize = listsize; + std::copy(list, list + listsize, shm()->rxDbitList); + } + + // dbit offset + n += receiver.receiveData(&i32, sizeof(i32)); + shm()->rxDbitOffset = i32; + if (n == 0) { throw RuntimeError("Could not update receiver: " + std::string(shm()->rxHostname) + diff --git a/slsDetectorSoftware/src/slsDetectorCommand.cpp b/slsDetectorSoftware/src/slsDetectorCommand.cpp index 326b75f62..87533de64 100755 --- a/slsDetectorSoftware/src/slsDetectorCommand.cpp +++ b/slsDetectorSoftware/src/slsDetectorCommand.cpp @@ -1934,13 +1934,6 @@ slsDetectorCommand::slsDetectorCommand(multiSlsDetector *det) { descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdProcessor; ++i; - /*! \page prototype - - adcinvert [mask] Sets/gets ADC inversion mask (8 digits hex format) - */ - descrToFuncMap[i].m_pFuncName = "adcinvert"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdPattern; - ++i; - /*! \page prototype - adcenable [mask] Sets/gets ADC enable mask (8 digits hex format) */ @@ -1948,11 +1941,46 @@ slsDetectorCommand::slsDetectorCommand(multiSlsDetector *det) { descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdPattern; ++i; - /** not documenting this, but keeping this for backwards compatibility */ + /** 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 */ @@ -2086,13 +2114,6 @@ slsDetectorCommand::slsDetectorCommand(multiSlsDetector *det) { descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdPattern; ++i; - /*! \page prototype - - dut_clk [i] sets/gets the signal to be used as a clock for the digital data coming from the device under test. Advanced! - */ - descrToFuncMap[i].m_pFuncName = "dut_clk"; - descrToFuncMap[i].m_pFuncPtr = &slsDetectorCommand::cmdPattern; - ++i; - numberOfCommands = i; // #ifdef VERBOSE @@ -5233,8 +5254,12 @@ 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)" << std::endl; - os << "adcenable mask\t sets the adcenable mask (hex)" << 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; @@ -5257,8 +5282,12 @@ std::string slsDetectorCommand::helpPattern(int action) { 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(); } @@ -5274,6 +5303,7 @@ std::string slsDetectorCommand::cmdPattern(int narg, char *args[], int action, i **********/ std::string fname; int addr, start, stop, n; + uint32_t u32; uint64_t word, t; myDet->setOnline(ONLINE_FLAG, detPos); @@ -5589,41 +5619,15 @@ std::string slsDetectorCommand::cmdPattern(int narg, char *args[], int action, i os << "0x" << std::hex << myDet->getPatternBitMask(detPos) << std::dec; - } else if (cmd == "adcinvert") { - if (action == PUT_ACTION) { - - if (sscanf(args[1], "%x", &addr)) - ; - else - return std::string("Could not scan adcinvert reg ") + std::string(args[1]); - - myDet->writeRegister(67, addr, detPos); - } - - os << std::hex << myDet->readRegister(67, detPos) << std::dec ; - - } else if (cmd == "dut_clk") { - if (action == PUT_ACTION) { - - if (sscanf(args[1], "%x", &addr)) - ; - else - return std::string("Could not scan dut_clk reg ") + std::string(args[1]); - - myDet->writeRegister(123, addr, detPos); //0x7b - } - - os << std::hex << myDet->readRegister(123, detPos) << std::dec ; //0x7b - } else if (cmd == "adcenable") { + } else if (cmd == "adcenable") { if (action == PUT_ACTION) { - uint32_t adcEnableMask = 0; - if (sscanf(args[1], "%x", &adcEnableMask)) + if (sscanf(args[1], "%x", &u32)) ; else return std::string("Could not scan adcenable reg ") + std::string(args[1]); - myDet->setADCEnableMask(adcEnableMask, detPos); + myDet->setADCEnableMask(u32, detPos); } os << std::hex << myDet->getADCEnableMask(detPos) << std::dec; @@ -5632,22 +5636,109 @@ std::string slsDetectorCommand::cmdPattern(int narg, char *args[], int action, i else if (cmd == "adcdisable") { if (action == PUT_ACTION) { - uint32_t adcEnableMask = 0; - if (sscanf(args[1], "%x", &adcEnableMask)) + 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 - adcEnableMask ^= BIT32_MASK; - myDet->setADCEnableMask(adcEnableMask, detPos); + u32 ^= BIT32_MASK; + myDet->setADCEnableMask(u32, detPos); } - uint32_t retval = myDet->getADCEnableMask(detPos); + u32 = myDet->getADCEnableMask(detPos); // get disable mask - retval ^= BIT32_MASK; - os << std::hex << retval << std::dec; - } + 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") { + + myDet->setReceiverOnline(ONLINE_FLAG, detPos); + + 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") { + + myDet->setReceiverOnline(ONLINE_FLAG, detPos); + + 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 return helpPattern(action); diff --git a/slsDetectorSoftware/tests/test-slsDetector.cpp b/slsDetectorSoftware/tests/test-slsDetector.cpp index b6fb6ce39..d79c47f99 100755 --- a/slsDetectorSoftware/tests/test-slsDetector.cpp +++ b/slsDetectorSoftware/tests/test-slsDetector.cpp @@ -217,4 +217,47 @@ TEST_CASE("create detParamets struct", "[detector][new]"){ CHECK(par2.dynamicRange == 16); CHECK(par2.nGappixelsX == 6); CHECK(par2.nGappixelsY == 1); +} + + +TEST_CASE("ctb digital offset and list", "[detector][ctb]"){ + slsDetector::freeSharedMemory(20, 20); + slsDetector d(slsDetectorDefs::detectorType::CHIPTESTBOARD, 20, 20); + + // dbit offset + CHECK(d.getReceiverDbitOffset() == 0); + CHECK(d.setReceiverDbitOffset(-1) == 0); + CHECK(d.setReceiverDbitOffset(0) == 0); + CHECK(d.setReceiverDbitOffset(5) == 5); + CHECK(d.getReceiverDbitOffset() == 5); + + // dbit list + std::vector list = d.getReceiverDbitList(); + CHECK(list.empty()); + + + for (int i = 0; i < 10; ++i) + list.push_back(i); + d.setReceiverDbitList(list); + + CHECK(d.getReceiverDbitList().size() == 10); + + list.push_back(64); + CHECK_THROWS_AS(d.setReceiverDbitList(list), sls::RuntimeError); + CHECK_THROWS_WITH(d.setReceiverDbitList(list), + Catch::Matchers::Contains("be between 0 and 63")); + + list.clear(); + for (int i = 0; i < 65; ++i) + list.push_back(i); + CHECK(list.size() == 65); + CHECK_THROWS_WITH(d.setReceiverDbitList(list), + Catch::Matchers::Contains("be greater than 64")); + + list.clear(); + d.setReceiverDbitList(list); + CHECK(d.getReceiverDbitList().empty()); + + + } \ No newline at end of file diff --git a/slsReceiverSoftware/CMakeLists.txt b/slsReceiverSoftware/CMakeLists.txt index c5bcc311d..4d483adc7 100755 --- a/slsReceiverSoftware/CMakeLists.txt +++ b/slsReceiverSoftware/CMakeLists.txt @@ -70,19 +70,9 @@ set_target_properties(slsReceiverShared PROPERTIES PUBLIC_HEADER "${PUBLICHEADERS}" ) +add_executable(slsReceiver + src/main.cpp) -if (SLS_USE_MYTHEN302_CTB_RECEIVER) - add_executable(slsReceiver - src/mainCustomized.cpp - ) - add_definitions( - -DMYTHEN302 - ) -else() - add_executable(slsReceiver - src/main.cpp - ) -endif (SLS_USE_MYTHEN302_CTB_RECEIVER) set_target_properties(slsReceiver PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin diff --git a/slsReceiverSoftware/include/DataProcessor.h b/slsReceiverSoftware/include/DataProcessor.h index d30c60c9b..21a1348fd 100755 --- a/slsReceiverSoftware/include/DataProcessor.h +++ b/slsReceiverSoftware/include/DataProcessor.h @@ -39,15 +39,15 @@ class DataProcessor : private virtual slsDetectorDefs, public ThreadObject { * @param act pointer to activated * @param depaden pointer to deactivated padding enable * @param sm pointer to silent mode - * @param ct pointer to ctb type - * @param cdo pointer to ctb digital offset + * @param cdl pointer to vector or ctb digital bits enable + * @param cdo pointer to digital bits offset * @param cad pointer to ctb analog databytes */ DataProcessor(int ind, detectorType dtype, Fifo* f, fileFormat* ftype, bool fwenable, bool* mfwenable, bool* dsEnable, bool* gpEnable, uint32_t* dr, uint32_t* freq, uint32_t* timer, bool* fp, bool* act, bool* depaden, bool* sm, - int* ct, int* cdo, int* cad); + std::vector * cdl, int* cdo, int* cad); /** * Destructor @@ -223,20 +223,6 @@ class DataProcessor : private virtual slsDetectorDefs, public ThreadObject { void registerCallBackRawDataModifyReady(void (*func)(char* , char*, uint32_t &, void*),void *arg); - /** - * Call back for raw CTB data that will be modified - * args to raw data call back are - * args to raw data ready callback are - * sls_receiver_header frame metadata - * dataPointer is the pointer to the data - * revDatasize is the reference of data size in bytes. Can be modified to the new size to be written/streamed. (only smaller value). - * type CTB chip type - * digitalOffset digital offset - * analogdataBytes analog databytes - */ - void registerCallBackCTBReceiverReady(void (*func)(char*, - char*, uint32_t &, int, int, int, void*),void *arg); - private: @@ -307,6 +293,11 @@ class DataProcessor : private virtual slsDetectorDefs, public ThreadObject { */ void PadMissingPackets(char* buf); + /** + * Align corresponding digital bits together (CTB only if ctbDbitlist is not empty) + */ + void RearrangeDbitData(char* buf); + /** * Processing Function (inserting gap pixels) eiger specific * @param buf pointer to image @@ -380,6 +371,15 @@ class DataProcessor : private virtual slsDetectorDefs, public ThreadObject { /** frame padding */ bool* framePadding; + /** ctb digital bits enable list */ + std::vector *ctbDbitList; + + /** ctb digital bits offset */ + int* ctbDbitOffset; + + /** ctb analog databytes */ + int* ctbAnalogDataBytes; + //acquisition start /** Aquisition Started flag */ bool acquisitionStartedFlag; @@ -404,14 +404,6 @@ class DataProcessor : private virtual slsDetectorDefs, public ThreadObject { /** Frame Number of latest processed frame number of an entire Acquisition (including all scans) */ uint64_t currentFrameIndex; - // for ctb call back - /** ctb type*/ - int* ctbType; - /** ctb digital offset */ - int* ctbDigitalOffset; - /** ctb analog databytes */ - int* ctbAnalogDataBytes; - @@ -435,20 +427,6 @@ class DataProcessor : private virtual slsDetectorDefs, public ThreadObject { */ void (*rawDataModifyReadyCallBack)(char*, char*, uint32_t &, void*); - - /** - * Call back for raw CTB data that will be modified - * args to raw data call back are - * args to raw data ready callback are - * sls_receiver_header frame metadata - * dataPointer is the pointer to the data - * revDatasize is the reference of data size in bytes. Can be modified to the new size to be written/streamed. (only smaller value). - * type CTB chip type - * digitalOffset digital offset - * analogdataBytes analog databytes - */ - void (*ctbRawDataReadyCallBack)(char*, - char*, uint32_t &, int, int, int, void*); void *pRawDataReady; diff --git a/slsReceiverSoftware/include/slsReceiver.h b/slsReceiverSoftware/include/slsReceiver.h index 43e567d6e..e7f14685f 100755 --- a/slsReceiverSoftware/include/slsReceiver.h +++ b/slsReceiverSoftware/include/slsReceiver.h @@ -95,21 +95,6 @@ class slsReceiver : private virtual slsDetectorDefs { void registerCallBackRawDataModifyReady(void (*func)(char* , char*, uint32_t &,void*),void *arg); - /** - * Call back for raw CTB data that will be modified - * args to raw data call back are - * args to raw data ready callback are - * sls_receiver_header frame metadata - * dataPointer is the pointer to the data - * revDatasize is the reference of data size in bytes. Can be modified to the new size to be written/streamed. (only smaller value). - * type CTB chip type - * digitalOffset digital offset - * analogdataBytes analog databytes - */ - void registerCallBackCTBReceiverReady(void (*func)(char*, - char*, uint32_t &, int, int, int, void*),void *arg); - - private: std::unique_ptr tcpipInterface; diff --git a/slsReceiverSoftware/include/slsReceiverImplementation.h b/slsReceiverSoftware/include/slsReceiverImplementation.h index 8913ea04e..d3abff1b5 100755 --- a/slsReceiverSoftware/include/slsReceiverImplementation.h +++ b/slsReceiverSoftware/include/slsReceiverImplementation.h @@ -300,6 +300,18 @@ class slsReceiverImplementation: private virtual slsDetectorDefs { */ bool getSilentMode() const; + /** + * Get CTB digital bits enable list + * @returns digital bits enable list + */ + std::vector getDbitList() const; + + /** + * Get CTB digital bits offset + * @returns digital bits offset + */ + int getDbitOffset() const; + /** * Get activate * If deactivated, receiver will create dummy data if deactivated padding is enabled @@ -637,6 +649,18 @@ class slsReceiverImplementation: private virtual slsDetectorDefs { */ void setSilentMode(const bool i); + /** + * Set CTB digital bits enable list + * @param v digital bits enable list + */ + void setDbitList(const std::vector v); + + /** + * Set CTB digital bits offset + * @param s digital bits offset + */ + void setDbitOffset(const int s); + /************************************************************************* * Behavioral functions*************************************************** @@ -751,20 +775,6 @@ class slsReceiverImplementation: private virtual slsDetectorDefs { void registerCallBackRawDataModifyReady(void (*func)(char* , char*, uint32_t &,void*),void *arg); - /** - * Call back for raw CTB data that will be modified - * args to raw data call back are - * args to raw data ready callback are - * sls_receiver_header frame metadata - * dataPointer is the pointer to the data - * revDatasize is the reference of data size in bytes. Can be modified to the new size to be written/streamed. (only smaller value). - * type CTB chip type - * digitalOffset digital offset - * analogdataBytes analog databytes - */ - void registerCallBackCTBReceiverReady(void (*func)(char*, - char*, uint32_t &, int, int, int, void*),void *arg); - private: /** @@ -877,6 +887,12 @@ private: bool framePadding; /** silent mode */ bool silentMode; + /** ctb digital bits enabled list (empty: all enabled) */ + std::vector ctbDbitList; + /** ctb digital bit offset in bytes */ + int ctbDbitOffset; + /* analog data bytes */ + int ctbAnalogDataBytes; //***connection parameters*** /** Number of UDP Interfaces */ @@ -938,13 +954,6 @@ private: /** Fifo Structure to store addresses of memory writes */ std::vector> fifo; - /** ctb type for callback*/ - int ctbType; - /* ctb digital offset for callback */ - int ctbDigitalOffset; - /* analog data bytes */ - int ctbAnalogDataBytes; - //***callback parameters*** /** * Call back for start acquisition @@ -986,20 +995,6 @@ private: void (*rawDataModifyReadyCallBack)(char* , char*, uint32_t &, void*); - /** - * Call back for raw CTB data that will be modified - * args to raw data call back are - * args to raw data ready callback are - * sls_receiver_header frame metadata - * dataPointer is the pointer to the data - * revDatasize is the reference of data size in bytes. Can be modified to the new size to be written/streamed. (only smaller value). - * type CTB chip type - * digitalOffset digital offset - * analogdataBytes analog databytes - */ - void (*ctbRawDataReadyCallBack)(char*, - char*, uint32_t &, int, int, int, void*); - void *pRawDataReady; diff --git a/slsReceiverSoftware/include/slsReceiverTCPIPInterface.h b/slsReceiverSoftware/include/slsReceiverTCPIPInterface.h index be1d5a132..00431f8f8 100755 --- a/slsReceiverSoftware/include/slsReceiverTCPIPInterface.h +++ b/slsReceiverSoftware/include/slsReceiverTCPIPInterface.h @@ -92,20 +92,6 @@ class slsReceiverTCPIPInterface : private virtual slsDetectorDefs { void registerCallBackRawDataModifyReady(void (*func)(char* , char*, uint32_t &,void*),void *arg); - /** - * Call back for raw CTB data that will be modified - * args to raw data call back are - * args to raw data ready callback are - * sls_receiver_header frame metadata - * dataPointer is the pointer to the data - * revDatasize is the reference of data size in bytes. Can be modified to the new size to be written/streamed. (only smaller value). - * type CTB chip type - * digitalOffset digital offset - * analogdataBytes analog databytes - */ - void registerCallBackCTBReceiverReady(void (*func)(char*, - char*, uint32_t &, int, int, int, void*),void *arg); - private: @@ -295,7 +281,7 @@ class slsReceiverTCPIPInterface : private virtual slsDetectorDefs { int set_padding_enable(); /** set deactivated receiver padding enable */ - int set_deactivated_receiver_padding_enable(); + int set_deactivated_padding_enable(); /** set readout flags */ int set_readout_flags(); @@ -303,6 +289,15 @@ class slsReceiverTCPIPInterface : private virtual slsDetectorDefs { /** set adc mask */ int set_adc_mask(); + /** set receiver dbit list */ + int set_dbit_list(); + + /** get receiver dbit list */ + int get_dbit_list(); + + /** set dbit offset */ + int set_dbit_offset(); + /** detector type */ detectorType myDetectorType; @@ -382,21 +377,6 @@ class slsReceiverTCPIPInterface : private virtual slsDetectorDefs { void (*rawDataModifyReadyCallBack)(char* , char*, uint32_t &, void*); - /** - * Call back for raw CTB data that will be modified - * args to raw data call back are - * args to raw data ready callback are - * sls_receiver_header frame metadata - * dataPointer is the pointer to the data - * revDatasize is the reference of data size in bytes. Can be modified to the new size to be written/streamed. (only smaller value). - * type CTB chip type - * digitalOffset digital offset - * analogdataBytes analog databytes - */ - void (*ctbRawDataReadyCallBack)(char*, - char*, uint32_t &, int, int, int, void*); - - void *pRawDataReady; diff --git a/slsReceiverSoftware/include/slsReceiverUsers.h b/slsReceiverSoftware/include/slsReceiverUsers.h index a6d0ad513..39456bd94 100755 --- a/slsReceiverSoftware/include/slsReceiverUsers.h +++ b/slsReceiverSoftware/include/slsReceiverUsers.h @@ -87,16 +87,6 @@ public: void registerCallBackRawDataModifyReady(void (*func)(char* header, char* datapointer, uint32_t &revDatasize, void*),void *arg); - /** - @short register callback to be called when CTB data are available in receiver (to process and/or save the data). - \param func raw data ready callback. arguments are sls_receiver_header, dataPointer, revDatasize is the reference of data size in bytes, chip type, digital offset, analog databytes. revDatasize be modified to the new size to be written/streamed. (only smaller value). - \param arg argument - \returns nothing - */ - void registerCallBackCTBReceiverReady(void (*func)(char* header, - char* datapointer, uint32_t &revDatasize, int type, int digitalOffset, int analogDataBytes, void*),void *arg); - - //receiver object std::unique_ptr receiver; }; diff --git a/slsReceiverSoftware/src/DataProcessor.cpp b/slsReceiverSoftware/src/DataProcessor.cpp index c16a8bbba..21d3163d9 100755 --- a/slsReceiverSoftware/src/DataProcessor.cpp +++ b/slsReceiverSoftware/src/DataProcessor.cpp @@ -28,7 +28,7 @@ DataProcessor::DataProcessor(int ind, detectorType dtype, Fifo* f, bool* dsEnable, bool* gpEnable, uint32_t* dr, uint32_t* freq, uint32_t* timer, bool* fp, bool* act, bool* depaden, bool* sm, - int* ct, int* cdo, int* cad) : + std::vector * cdl, int* cdo, int* cad) : ThreadObject(ind), runningFlag(0), @@ -50,6 +50,9 @@ DataProcessor::DataProcessor(int ind, detectorType dtype, Fifo* f, deactivatedPaddingEnable(depaden), silentMode(sm), framePadding(fp), + ctbDbitList(cdl), + ctbDbitOffset(cdo), + ctbAnalogDataBytes(cad), acquisitionStartedFlag(false), measurementStartedFlag(false), firstAcquisitionIndex(0), @@ -57,12 +60,8 @@ DataProcessor::DataProcessor(int ind, detectorType dtype, Fifo* f, numTotalFramesCaught(0), numFramesCaught(0), currentFrameIndex(0), - ctbType(ct), - ctbDigitalOffset(cdo), - ctbAnalogDataBytes(cad), rawDataReadyCallBack(nullptr), rawDataModifyReadyCallBack(nullptr), - ctbRawDataReadyCallBack(nullptr), pRawDataReady(nullptr) { if(ThreadObject::CreateThread() == FAIL) @@ -356,6 +355,11 @@ void DataProcessor::ProcessAnImage(char* buf) { else if (!(*activated) && *deactivatedPaddingEnable) PadMissingPackets(buf); + // rearrange ctb digital bits (if ctbDbitlist is not empty) + if (!(*ctbDbitList).empty()) { + RearrangeDbitData(buf); + } + // normal call back if (rawDataReadyCallBack) { rawDataReadyCallBack( @@ -376,20 +380,6 @@ void DataProcessor::ProcessAnImage(char* buf) { (*((uint32_t*)buf)) = revsize; } - // ctb call back - else if (ctbRawDataReadyCallBack) { - uint32_t revsize = (uint32_t)(*((uint32_t*)buf)); - ctbRawDataReadyCallBack( - (char*)rheader, - buf + FIFO_HEADER_NUMBYTES + sizeof(sls_receiver_header), - revsize, - *ctbType, - *ctbDigitalOffset, - *ctbAnalogDataBytes, - pRawDataReady); - (*((uint32_t*)buf)) = revsize; - } - // write to file if (file) @@ -397,8 +387,6 @@ void DataProcessor::ProcessAnImage(char* buf) { sizeof(sls_receiver_header) + (uint32_t)(*((uint32_t*)buf)), //+ size of data (resizable from previous call back fnum-firstMeasurementIndex, nump); - - } @@ -464,12 +452,6 @@ void DataProcessor::registerCallBackRawDataModifyReady(void (*func)(char* , pRawDataReady=arg; } -void DataProcessor::registerCallBackCTBReceiverReady(void (*func)(char* , - char*, uint32_t&, int, int, int, void*),void *arg) { - ctbRawDataReadyCallBack=func; - pRawDataReady=arg; -} - void DataProcessor::PadMissingPackets(char* buf) { FILE_LOG(logDEBUG) << index << ": Padding Missing Packets"; @@ -519,6 +501,45 @@ void DataProcessor::PadMissingPackets(char* buf) { } } +/** ctb specific */ +void DataProcessor::RearrangeDbitData(char* buf) { + int totalSize = (int)(*((uint32_t*)buf)); + int ctbDigitalDataBytes = totalSize - (*ctbAnalogDataBytes) - (*ctbDbitOffset); + + // no digital data + if (!ctbDigitalDataBytes) { + FILE_LOG(logWARNING) << "No digital data for call back, yet dbitlist is not empty."; + return; + } + + const int numSamples = (ctbDigitalDataBytes / sizeof(uint64_t)); + + // ceil as numResult64Bytes could be decimal + const int numResult64Bytes = ceil((double)(numSamples * (*ctbDbitList).size()) / 64.00); + std::vector result(numResult64Bytes, 0); + + auto dest = result.data(); + const int digOffset = FIFO_HEADER_NUMBYTES + sizeof(sls_receiver_header) + (*ctbAnalogDataBytes) + (*ctbDbitOffset); + auto source = (uint64_t*)(buf + digOffset); + + // loop through digital bit enable vector + for (auto bi : (*ctbDbitList)) { + // loop through the frame digital data + for (auto ptr = source; ptr < (source + numSamples);) { + // extract destination in 64 bit batches + for (int i = 0; i != 64; ++i) { + // get selected bit from each 64 bit + int bit = (*ptr++ >> bi) & 1; + *dest |= bit << i; + } + ++dest; + } + } + + // copy back to buf and update size + memcpy(source + digOffset, result.data(), result.size() * sizeof(uint64_t)); + (*((uint32_t*)buf)) = result.size() * sizeof(uint64_t); +} /** eiger specific */ void DataProcessor::InsertGapPixels(char* buf, uint32_t dr) { diff --git a/slsReceiverSoftware/src/mainCustomized.cpp b/slsReceiverSoftware/src/mainCustomized.cpp deleted file mode 100755 index 360da811f..000000000 --- a/slsReceiverSoftware/src/mainCustomized.cpp +++ /dev/null @@ -1,189 +0,0 @@ -/* A simple server in the internet domain using TCP - The port number is passed as an argument */ - -#include "sls_detector_defs.h" -#include "slsReceiverUsers.h" -#include "logger.h" - -#include -#include -#include //SIGINT -#include //system -#include //wait -#include //wait -#include //usleep -#include -#include -#include - -bool keeprunning; -int ctbOffset = 0; -bool printData = false; - -void sigInterruptHandler(int p){ - keeprunning = false; -} - - -#ifdef MYTHEN302 -void GetData(char* metadata, char* datapointer, uint32_t& datasize, - int ctbType, int ctbDigitalOffset, int ctbAnalogDataBytes, void* p) { - - // only analog data - if (ctbAnalogDataBytes == (int)datasize) { - FILE_LOG(logWARNING) << "No digital data for call back. Remove this unnecessary call back."; - return; - } - - constexpr int dynamicRange = 24; - constexpr int numSamples = 32 * 3; // 32 channels * 3 counters = 96 - constexpr int numCounters = numSamples * 2; // 2 strips - // validate datasize - { - FILE_LOG(logDEBUG) << "Datasize:" << datasize; - int wordsCaught = ((datasize - ctbAnalogDataBytes) / sizeof(uint64_t)) - ctbOffset; - int expectedWordSize = numSamples * dynamicRange; - if (expectedWordSize != wordsCaught) { - FILE_LOG(logWARNING) << "Number of words do not match, Expected " - << expectedWordSize << ", got " << wordsCaught; - } - } - - // source - uint64_t* ptr = (uint64_t*)(datapointer + ctbAnalogDataBytes); - // remove the offset from source - ptr += ctbOffset; - // destination - auto result = new int[numCounters]; - memset((char*)result, 0, numCounters * sizeof(int)); - auto strip0 = result; - auto strip1 = strip0 + numSamples; - constexpr int bit_index0 = 17; - constexpr int bit_index1 = 6; - FILE_LOG(logINFO) << "Bits (" << bit_index0 << ", " << bit_index1 << ")"; - constexpr int mask0 = (1 << bit_index0); - constexpr int mask1 = (1 << bit_index1); - - for (int j = 0; j < numSamples; ++j) { - for (int i = 0; i < dynamicRange; ++i) { - int bit0 = (*ptr & mask0) >> bit_index0; - int bit1 = (*ptr++ & mask1) >> bit_index1; - *strip0 |= bit0 << i; - *strip1 |= bit1 << i; - } - strip0++; - strip1++; - } - - if (printData) { - slsDetectorDefs::sls_receiver_header* header = (slsDetectorDefs::sls_receiver_header*)metadata; - slsDetectorDefs::sls_detector_header detectorHeader = header->detHeader; - FILE_LOG(logINFO) << "Frame Number: " << detectorHeader.frameNumber; - for (int i = 0; i < numCounters; ++i) { - cprintf(MAGENTA, "%d:%u\t", i, result[i]); - } - std::cout << std::endl; - } - - // update the size to be written to file & overwrite data in memory - datasize = numCounters * sizeof(int); - memcpy(datapointer + ctbAnalogDataBytes, (char*)result, datasize); - delete[] result; - datasize += ctbAnalogDataBytes; - FILE_LOG(logDEBUG) << "Modified Size: " << datasize; -} -#endif - - -int main(int argc, char *argv[]) { - - // options - std::map configuration_map; - //parse command line for config - static struct option long_options[] = { - {"ctb_offset", required_argument, nullptr, 'o'}, - {"print_data", no_argument, nullptr, 'p'}, - {nullptr, 0, nullptr, 0} - }; - //initialize global optind variable (required when instantiating multiple receivers in the same process) - optind = 1; - // getopt_long stores the option index here. - int option_index = 0; - int c = 0; - while ( c != -1 ) { - c = getopt_long (argc, argv, "hvf:t:o:p", long_options, &option_index); - // Detect the end of the options. - if (c == -1) - break; - switch(c) { - case 'o': - sscanf(optarg, "%d", &ctbOffset); - break; - case 'p': - printData = true; - break; - default: - break; - } - } - -#ifdef MYTHEN302 - FILE_LOG(logINFOGREEN) << "Mythen 302 Receiver"; - FILE_LOG(logINFO) << "CTB Offset: " << ctbOffset; - FILE_LOG(logINFO) << "Print Data: " << printData; -#endif - - keeprunning = true; - FILE_LOG(logINFOBLUE) << "Created [ Tid: " << syscall(SYS_gettid) << " ]"; - - // Catch signal SIGINT to close files and call destructors properly - struct sigaction sa; - sa.sa_flags = 0; // no flags - sa.sa_handler = sigInterruptHandler; // handler function - sigemptyset(&sa.sa_mask); // dont block additional signals during invocation - // of handler - if (sigaction(SIGINT, &sa, nullptr) == -1) { - FILE_LOG(logERROR) << "Could not set handler function for SIGINT"; - } - - - // if socket crash, ignores SISPIPE, prevents global signal handler - // subsequent read/write to socket gives error - must handle locally - struct sigaction asa; - asa.sa_flags=0; // no flags - asa.sa_handler=SIG_IGN; // handler function - sigemptyset(&asa.sa_mask); // dont block additional signals during invocation of handler - if (sigaction(SIGPIPE, &asa, nullptr) == -1) { - FILE_LOG(logERROR) << "Could not set handler function for SIGPIPE"; - } - - int ret = slsDetectorDefs::OK; - slsReceiverUsers *receiver = new slsReceiverUsers(argc, argv, ret); - if(ret==slsDetectorDefs::FAIL){ - delete receiver; - FILE_LOG(logINFOBLUE) << "Exiting [ Tid: " << syscall(SYS_gettid) << " ]"; - exit(EXIT_FAILURE); - } - - - //register callbacks - receiver->registerCallBackCTBReceiverReady(GetData, NULL); - - //start tcp server thread - if (receiver->start() == slsDetectorDefs::FAIL){ - delete receiver; - FILE_LOG(logINFOBLUE) << "Exiting [ Tid: " << syscall(SYS_gettid) << " ]"; - exit(EXIT_FAILURE); - } - - FILE_LOG(logINFO) << "Ready ... "; - FILE_LOG(logINFO) << "[ Press \'Ctrl+c\' to exit ]"; - while(keeprunning) - pause(); - - delete receiver; - FILE_LOG(logINFOBLUE) << "Exiting [ Tid: " << syscall(SYS_gettid) << " ]"; - FILE_LOG(logINFO) << "Exiting Receiver"; - return 0; -} - diff --git a/slsReceiverSoftware/src/slsReceiver.cpp b/slsReceiverSoftware/src/slsReceiver.cpp index d6d9ae45b..d9b5855c1 100755 --- a/slsReceiverSoftware/src/slsReceiver.cpp +++ b/slsReceiverSoftware/src/slsReceiver.cpp @@ -44,17 +44,13 @@ slsReceiver::slsReceiver(int argc, char *argv[]): int c = 0; while ( c != -1 ){ - c = getopt_long (argc, argv, "hvf:t:o:p", long_options, &option_index); + c = getopt_long (argc, argv, "hvf:t:", long_options, &option_index); // Detect the end of the options. if (c == -1) break; switch(c){ - // reserved for ctb receiver users - case 'o': - case 'p': - break; case 't': sscanf(optarg, "%d", &tcpip_port_no); @@ -113,7 +109,6 @@ void slsReceiver::registerCallBackStartAcquisition(int (*func)( } - void slsReceiver::registerCallBackAcquisitionFinished( void (*func)(uint64_t, void*),void *arg){ tcpipInterface->registerCallBackAcquisitionFinished(func,arg); @@ -131,8 +126,3 @@ void slsReceiver::registerCallBackRawDataModifyReady(void (*func)(char*, tcpipInterface->registerCallBackRawDataModifyReady(func,arg); } - -void slsReceiver::registerCallBackCTBReceiverReady(void (*func)(char* , - char*, uint32_t &, int, int, int, void*),void *arg){ - tcpipInterface->registerCallBackCTBReceiverReady(func,arg); -} diff --git a/slsReceiverSoftware/src/slsReceiverImplementation.cpp b/slsReceiverSoftware/src/slsReceiverImplementation.cpp index 874785edb..7bb1bd238 100755 --- a/slsReceiverSoftware/src/slsReceiverImplementation.cpp +++ b/slsReceiverSoftware/src/slsReceiverImplementation.cpp @@ -46,6 +46,7 @@ void slsReceiverImplementation::DeleteMembers() { dataProcessor.clear(); dataStreamer.clear(); fifo.clear(); + ctbDbitList.clear(); } @@ -80,6 +81,8 @@ void slsReceiverImplementation::InitializeMembers() { frameDiscardMode = NO_DISCARD; framePadding = false; silentMode = false; + ctbDbitOffset = 0; + ctbAnalogDataBytes = 0; //***connection parameters*** numUDPInterfaces = 1; @@ -113,11 +116,6 @@ void slsReceiverImplementation::InitializeMembers() { //** class objects *** generalData = nullptr; - //** ctb callback parameters - ctbType = 0; - ctbDigitalOffset = 0; - ctbAnalogDataBytes = 0; - //***callback parameters*** startAcquisitionCallBack = nullptr; pStartAcquisition = nullptr; @@ -125,7 +123,6 @@ void slsReceiverImplementation::InitializeMembers() { pAcquisitionFinished = nullptr; rawDataReadyCallBack = nullptr; rawDataModifyReadyCallBack = nullptr; - ctbRawDataReadyCallBack = nullptr; pRawDataReady = nullptr; } @@ -383,6 +380,16 @@ bool slsReceiverImplementation::getSilentMode() const{ return silentMode; } +std::vector slsReceiverImplementation::getDbitList() const{ + FILE_LOG(logDEBUG3) << __SHORT_AT__ << " called"; + return ctbDbitList; +} + +int slsReceiverImplementation::getDbitOffset() const{ + FILE_LOG(logDEBUG3) << __SHORT_AT__ << " called"; + return ctbDbitOffset; +} + bool slsReceiverImplementation::getActivate() const{ FILE_LOG(logDEBUG3) << __SHORT_AT__ << " called"; return activated; @@ -703,7 +710,7 @@ int slsReceiverImplementation::setNumberofUDPInterfaces(const int n) { fileWriteEnable, &masterFileWriteEnable, &dataStreamEnable, &gapPixelsEnable, &dynamicRange, &streamingFrequency, &streamingTimerInMs, &framePadding, &activated, &deactivatedPaddingEnable, &silentMode, - &ctbType, &ctbDigitalOffset, &ctbAnalogDataBytes)); + &ctbDbitList, &ctbDbitOffset, &ctbAnalogDataBytes)); dataProcessor[i]->SetGeneralData(generalData); } catch (...) { @@ -748,10 +755,6 @@ int slsReceiverImplementation::setNumberofUDPInterfaces(const int n) { for (const auto& it : dataProcessor) it->registerCallBackRawDataModifyReady(rawDataModifyReadyCallBack,pRawDataReady); } - if(ctbRawDataReadyCallBack) { - for (const auto& it : dataProcessor) - it->registerCallBackCTBReceiverReady(ctbRawDataReadyCallBack,pRawDataReady); - } // test socket buffer size with current set up if (setUDPSocketBufferSize(0) == FAIL) { @@ -1088,6 +1091,17 @@ void slsReceiverImplementation::setSilentMode(const bool i) { FILE_LOG(logINFO) << "Silent Mode: " << i; } +void slsReceiverImplementation::setDbitList(const std::vector v) { + FILE_LOG(logDEBUG3) << __SHORT_AT__ << " called"; + ctbDbitList = v; +} + +void slsReceiverImplementation::setDbitOffset(const int s) { + FILE_LOG(logDEBUG3) << __SHORT_AT__ << " called"; + ctbDbitOffset = s; +} + + /************************************************************************* * Behavioral functions*************************************************** @@ -1148,7 +1162,7 @@ int slsReceiverImplementation::setDetectorType(const detectorType d) { fileWriteEnable, &masterFileWriteEnable, &dataStreamEnable, &gapPixelsEnable, &dynamicRange, &streamingFrequency, &streamingTimerInMs, &framePadding, &activated, &deactivatedPaddingEnable, &silentMode, - &ctbType, &ctbDigitalOffset, &ctbAnalogDataBytes)); + &ctbDbitList, &ctbDbitOffset, &ctbAnalogDataBytes)); } catch (...) { FILE_LOG(logERROR) << "Could not create listener/dataprocessor threads (index:" << i << ")"; @@ -1434,15 +1448,6 @@ void slsReceiverImplementation::registerCallBackRawDataModifyReady(void (*func)( } -void slsReceiverImplementation::registerCallBackCTBReceiverReady(void (*func)(char* , - char*, uint32_t&, int, int, int, void*),void *arg) { - ctbRawDataReadyCallBack=func; - pRawDataReady=arg; - for (const auto& it : dataProcessor) - it->registerCallBackCTBReceiverReady(ctbRawDataReadyCallBack,pRawDataReady); -} - - void slsReceiverImplementation::SetLocalNetworkParameters() { FILE_LOG(logDEBUG3) << __SHORT_AT__ << " called"; diff --git a/slsReceiverSoftware/src/slsReceiverTCPIPInterface.cpp b/slsReceiverSoftware/src/slsReceiverTCPIPInterface.cpp index 602814fa3..41a728425 100755 --- a/slsReceiverSoftware/src/slsReceiverTCPIPInterface.cpp +++ b/slsReceiverSoftware/src/slsReceiverTCPIPInterface.cpp @@ -53,7 +53,6 @@ slsReceiverTCPIPInterface::slsReceiverTCPIPInterface(int pn): pAcquisitionFinished = nullptr; rawDataReadyCallBack = nullptr; rawDataModifyReadyCallBack = nullptr; - ctbRawDataReadyCallBack = nullptr; pRawDataReady = nullptr; // create socket @@ -131,12 +130,6 @@ void slsReceiverTCPIPInterface::registerCallBackRawDataModifyReady(void (*func)( pRawDataReady=arg; } -void slsReceiverTCPIPInterface::registerCallBackCTBReceiverReady(void (*func)(char* , - char*, uint32_t &, int, int, int, void*),void *arg){ - ctbRawDataReadyCallBack=func; - pRawDataReady=arg; -} - void* slsReceiverTCPIPInterface::startTCPServerThread(void *this_pointer){ ((slsReceiverTCPIPInterface*)this_pointer)->startTCPServer(); return this_pointer; @@ -231,9 +224,12 @@ int slsReceiverTCPIPInterface::function_table(){ flist[F_RECEIVER_CHECK_VERSION] = &slsReceiverTCPIPInterface::check_version_compatibility; flist[F_RECEIVER_DISCARD_POLICY] = &slsReceiverTCPIPInterface::set_discard_policy; flist[F_RECEIVER_PADDING_ENABLE] = &slsReceiverTCPIPInterface::set_padding_enable; - flist[F_RECEIVER_DEACTIVATED_PADDING_ENABLE] = &slsReceiverTCPIPInterface::set_deactivated_receiver_padding_enable; + flist[F_RECEIVER_DEACTIVATED_PADDING_ENABLE] = &slsReceiverTCPIPInterface::set_deactivated_padding_enable; flist[F_RECEIVER_SET_READOUT_FLAGS] = &slsReceiverTCPIPInterface::set_readout_flags; flist[F_RECEIVER_SET_ADC_MASK] = &slsReceiverTCPIPInterface::set_adc_mask; + flist[F_SET_RECEIVER_DBIT_LIST] = &slsReceiverTCPIPInterface::set_dbit_list; + flist[F_GET_RECEIVER_DBIT_LIST] = &slsReceiverTCPIPInterface::get_dbit_list; + flist[F_RECEIVER_DBIT_OFFSET] = &slsReceiverTCPIPInterface::set_dbit_offset; for (int i = NUM_DET_FUNCTIONS + 1; i < NUM_REC_FUNCTIONS ; i++) { FILE_LOG(logDEBUG1) << "function fnum: " << i << " (" << @@ -556,6 +552,20 @@ int slsReceiverTCPIPInterface::send_update() { i32=(int)receiver->getSilentMode(); n += mySock->SendDataOnly(&i32, sizeof(i32)); + // dbit list + { + std::vector list = receiver->getDbitList(); + int retvalsize = list.size(); + int retval[retvalsize]; + std::copy(std::begin(list), std::end(list), retval); + mySock->SendDataOnly(&retvalsize, sizeof(retvalsize)); + mySock->SendDataOnly(retval, sizeof(retval)); + } + + // dbit offset + i32=receiver->getDbitOffset(); + n += mySock->SendDataOnly(&i32, sizeof(i32)); + if (!lockStatus) strcpy(mySock->lastClientIP, mySock->thisClientIP); @@ -621,8 +631,6 @@ int slsReceiverTCPIPInterface::set_detector_type(){ receiver->registerCallBackRawDataReady(rawDataReadyCallBack,pRawDataReady); if(rawDataModifyReadyCallBack) receiver->registerCallBackRawDataModifyReady(rawDataModifyReadyCallBack,pRawDataReady); - if(ctbRawDataReadyCallBack) - receiver->registerCallBackCTBReceiverReady(ctbRawDataReadyCallBack, pRawDataReady); // client has started updating receiver, update ip if (!lockStatus) @@ -2030,7 +2038,7 @@ int slsReceiverTCPIPInterface::set_padding_enable() { -int slsReceiverTCPIPInterface::set_deactivated_receiver_padding_enable() { +int slsReceiverTCPIPInterface::set_deactivated_padding_enable() { ret = OK; memset(mess, 0, sizeof(mess)); int enable = -1; @@ -2123,5 +2131,100 @@ int slsReceiverTCPIPInterface::set_adc_mask() { } FILE_LOG(logDEBUG1) << "ADC enable mask retval: " << retval; } - return interface->Server_SendResult(false, ret, &retval, sizeof(retval), mess); + return interface->Server_SendResult(true, ret, &retval, sizeof(retval), mess); +} + + + +int slsReceiverTCPIPInterface::set_dbit_list() { + ret = OK; + memset(mess, 0, sizeof(mess)); + + // receive arguments + int narg = -1; + if (mySock->ReceiveDataOnly(&narg,sizeof(narg)) < 0 ) + return interface->Server_SocketCrash(); + int narglist[narg]; + if (mySock->ReceiveDataOnly(narglist, narg * sizeof(int)) < 0 ) + return interface->Server_SocketCrash(); + std::vector arg(narglist, narglist + narg); + + FILE_LOG(logDEBUG1) << "Setting DBIT list"; + for (auto &it : arg) { + FILE_LOG(logDEBUG1) << it << " "; + } + FILE_LOG(logDEBUG1) << "\n"; + + // base object not null + if (receiver == nullptr) + interface->Server_NullObjectError(ret, mess); + else { + // only set + // verify if receiver is unlocked and idle + if (interface->Server_VerifyLockAndIdle(ret, mess, lockStatus, receiver->getStatus(), fnum) == OK) { + if (arg.size() > 64) { + ret = FAIL; + sprintf(mess, "Could not set dbit list as size is > 64\n"); + FILE_LOG(logERROR) << mess; + } else + receiver->setDbitList(arg); + } + } + + return interface->Server_SendResult(true, ret, nullptr, 0, mess); +} + + + +int slsReceiverTCPIPInterface::get_dbit_list() { + ret = OK; + memset(mess, 0, sizeof(mess)); + std::vector list; + + // no arg, check receiver is null + interface->Server_ReceiveArg(ret, mess, nullptr, 0, true, receiver); + + // base object not null + if (ret == OK) { + // get + list = receiver->getDbitList(); + FILE_LOG(logDEBUG1) << "Dbit list size retval:" << list.size(); + } + + interface->Server_SendResult(false, ret, nullptr, 0, mess); + int retvalsize = list.size(); + int retval[retvalsize]; + std::copy(std::begin(list), std::end(list), retval); + mySock->SendDataOnly(&retvalsize, sizeof(retvalsize)); + mySock->SendDataOnly(retval, sizeof(retval)); + return ret; +} + + +int slsReceiverTCPIPInterface::set_dbit_offset() { + ret = OK; + memset(mess, 0, sizeof(mess)); + int arg = -1; + int retval = -1; + + // get args, return if socket crashed, ret is fail if receiver is not null + if (interface->Server_ReceiveArg(ret, mess, &arg, sizeof(arg), true, receiver) == FAIL) + return FAIL; + + // base object not null + else if (ret == OK) { + // set + if (arg >= 0) { + // verify if receiver is unlocked and idle + if (interface->Server_VerifyLockAndIdle(ret, mess, lockStatus, receiver->getStatus(), fnum) == OK) { + FILE_LOG(logDEBUG1) << "Setting Dbit offset: " << arg; + receiver->setDbitOffset(arg); + } + } + // get + retval = receiver->getDbitOffset(); + validate(arg, retval, std::string("set dbit offset"), DEC); + FILE_LOG(logDEBUG1) << "Dbit offset retval: " << retval; + } + return interface->Server_SendResult(true, ret, &retval, sizeof(retval), mess); } \ No newline at end of file diff --git a/slsReceiverSoftware/src/slsReceiverUsers.cpp b/slsReceiverSoftware/src/slsReceiverUsers.cpp index 81343d093..3ce3c00f1 100755 --- a/slsReceiverSoftware/src/slsReceiverUsers.cpp +++ b/slsReceiverSoftware/src/slsReceiverUsers.cpp @@ -46,8 +46,3 @@ void slsReceiverUsers::registerCallBackRawDataModifyReady(void (*func)(char* hea receiver->registerCallBackRawDataModifyReady(func,arg); } -void slsReceiverUsers::registerCallBackCTBReceiverReady(void (*func)(char* header, - char* datapointer, uint32_t& revDatasize, - int type, int digitalOffset, int analogDataBytes, void*), void *arg){ - receiver->registerCallBackCTBReceiverReady(func,arg); -} diff --git a/slsSupportLib/include/sls_detector_funcs.h b/slsSupportLib/include/sls_detector_funcs.h index 95f7340c0..4b8ecb509 100755 --- a/slsSupportLib/include/sls_detector_funcs.h +++ b/slsSupportLib/include/sls_detector_funcs.h @@ -83,6 +83,10 @@ enum detFuncs{ F_REBOOT_CONTROLLER, /** < reboot detector controller (blackfin/ powerpc) */ F_SET_ADC_ENABLE_MASK, /** < setting ADC enable mask */ F_GET_ADC_ENABLE_MASK, /** < setting ADC enable mask */ + F_SET_ADC_INVERT, /** < set adc invert reg */ + F_GET_ADC_INVERT, /** < get adc invert reg */ + F_EXTERNAL_SAMPLING_SOURCE, /** < set/get external sampling source for ctb */ + F_EXTERNAL_SAMPLING, /**< enable/disable external sampling for ctb */ NUM_DET_FUNCTIONS, RECEIVER_ENUM_START = 128, /**< detector function should not exceed this (detector server should not compile anyway) */ @@ -137,6 +141,9 @@ enum detFuncs{ F_RECEIVER_DEACTIVATED_PADDING_ENABLE, /** < deactivated receiver padding enable */ F_RECEIVER_SET_READOUT_FLAGS, /**< set/get receiver readout flags */ F_RECEIVER_SET_ADC_MASK, /**< set adc mask */ + F_SET_RECEIVER_DBIT_LIST, /** < set receiver digital bit list */ + F_GET_RECEIVER_DBIT_LIST, /** < get receiver digital bit list */ + F_RECEIVER_DBIT_OFFSET, /** < set/get reciever digital bit offset */ NUM_REC_FUNCTIONS }; @@ -216,6 +223,10 @@ static const char* getFunctionNameFromEnum(enum detFuncs func) { case F_REBOOT_CONTROLLER: return "F_REBOOT_CONTROLLER"; case F_SET_ADC_ENABLE_MASK: return "F_SET_ADC_ENABLE_MASK"; case F_GET_ADC_ENABLE_MASK: return "F_GET_ADC_ENABLE_MASK"; + case F_SET_ADC_INVERT: return "F_SET_ADC_INVERT"; + case F_GET_ADC_INVERT: return "F_GET_ADC_INVERT"; + case F_EXTERNAL_SAMPLING_SOURCE: return "F_EXTERNAL_SAMPLING_SOURCE"; + case F_EXTERNAL_SAMPLING: return "F_EXTERNAL_SAMPLING"; case NUM_DET_FUNCTIONS: return "NUM_DET_FUNCTIONS"; case RECEIVER_ENUM_START: return "RECEIVER_ENUM_START"; @@ -271,6 +282,10 @@ static const char* getFunctionNameFromEnum(enum detFuncs func) { case F_RECEIVER_DEACTIVATED_PADDING_ENABLE: return "F_RECEIVER_DEACTIVATED_PADDING_ENABLE"; case F_RECEIVER_SET_READOUT_FLAGS: return "F_RECEIVER_SET_READOUT_FLAGS"; case F_RECEIVER_SET_ADC_MASK: return "F_RECEIVER_SET_ADC_MASK"; + case F_SET_RECEIVER_DBIT_LIST: return "F_SET_RECEIVER_DBIT_LIST"; + case F_GET_RECEIVER_DBIT_LIST: return "F_GET_RECEIVER_DBIT_LIST"; + case F_RECEIVER_DBIT_OFFSET: return "F_RECEIVER_DBIT_OFFSET"; + case NUM_REC_FUNCTIONS: return "NUM_REC_FUNCTIONS"; default: return "Unknown Function"; } diff --git a/slsSupportLib/include/versionAPI.h b/slsSupportLib/include/versionAPI.h index 1b40940b2..dcbd57bee 100644 --- a/slsSupportLib/include/versionAPI.h +++ b/slsSupportLib/include/versionAPI.h @@ -7,4 +7,4 @@ #define APIRECEIVER 0x190405 #define APIGUI 0x190405 #define APIEIGER 0x190418 -#define APICTB 0x190430 +#define APICTB 0x190503 From 0904d1db29e1624df18f53f858f8cf5c3aa06c0d Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Fri, 3 May 2019 20:46:08 +0200 Subject: [PATCH 2/4] updated ctb binary --- .../bin/ctbDetectorServer_developer | Bin 163660 -> 167808 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/slsDetectorServers/ctbDetectorServer/bin/ctbDetectorServer_developer b/slsDetectorServers/ctbDetectorServer/bin/ctbDetectorServer_developer index 0f9c25ef483c1058e1ba23fb65fdd9356cda899a..b550b0c93f5244021bf678c0ad25e4aae993769c 100755 GIT binary patch delta 80050 zcmb4s3w%?>^8aap5-{ii3IwQ_A{Q$nhEg$NffNvGK?qoRi5Q@~6tEy-MI;4LQSp*; zP!YMBB3`Q(F;�K`mH$SuuqIc-fc_qQq!j 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 delta 76384 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

IReOuXyp;_X!8~Riv7n+5>V_Z>1fuSx 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 Pv%gHiG6BoHS2p^8BByPs From 932e37776555350be508fab7571de1eca691ad65 Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Mon, 6 May 2019 19:13:31 +0200 Subject: [PATCH 3/4] review fdback: using sendtoReceiver, not using size of for specifyng arguments to sendtodetector --- slsDetectorSoftware/src/slsDetector.cpp | 24 +++++------------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/slsDetectorSoftware/src/slsDetector.cpp b/slsDetectorSoftware/src/slsDetector.cpp index 1cb18c1d3..233d1d150 100755 --- a/slsDetectorSoftware/src/slsDetector.cpp +++ b/slsDetectorSoftware/src/slsDetector.cpp @@ -2681,7 +2681,7 @@ void slsDetector::setADCInvert(uint32_t value) { uint32_t arg = value; FILE_LOG(logDEBUG1) << "Setting ADC Invert to 0x" << std::hex << arg << std::dec; if (shm()->onlineFlag == ONLINE_FLAG) { - sendToDetector(F_SET_ADC_INVERT, &arg, sizeof(arg), nullptr, 0); + sendToDetector(F_SET_ADC_INVERT, &arg, nullptr); } } @@ -2741,25 +2741,11 @@ void slsDetector::setReceiverDbitList(std::vector list) { shm()->rxDbitListSize = list.size(); std::copy(list.begin(), list.end(), shm()->rxDbitList); - int ret = FAIL; if (shm()->rxOnlineFlag == ONLINE_FLAG) { - int fnum = F_SET_RECEIVER_DBIT_LIST; - int arg = list.size(); - auto receiver = - sls::ClientSocket("Receiver", shm()->rxHostname, shm()->rxTCPPort); - receiver.sendData(&fnum, sizeof(fnum)); - receiver.sendData(&arg, sizeof(arg)); - receiver.sendData(shm()->rxDbitList, arg * sizeof(int)); - receiver.receiveData(&ret, sizeof(ret)); - if (ret == FAIL) { - char mess[MAX_STR_LENGTH]{}; - receiver.receiveData(mess, MAX_STR_LENGTH); - throw ReceiverError("Receiver " + std::to_string(detId) + - " returned error: " + std::string(mess)); - } - } - if (ret == FORCE_UPDATE) { - ret = updateCachedReceiverVariables(); + int args[list.size() + 1]; + args[0] = list.size(); + std::copy(std::begin(list), std::end(list), args + 1); + sendToReceiver(F_SET_RECEIVER_DBIT_LIST, args, sizeof(args), nullptr, 0); } } From df938c2535860052426c705defaffae3a41c126f Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Tue, 7 May 2019 09:47:53 +0200 Subject: [PATCH 4/4] review: removing size in sendtoDetector --- slsDetectorSoftware/src/slsDetector.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/slsDetectorSoftware/src/slsDetector.cpp b/slsDetectorSoftware/src/slsDetector.cpp index 233d1d150..05dd882ae 100755 --- a/slsDetectorSoftware/src/slsDetector.cpp +++ b/slsDetectorSoftware/src/slsDetector.cpp @@ -2678,10 +2678,9 @@ uint32_t slsDetector::getADCEnableMask() { } void slsDetector::setADCInvert(uint32_t value) { - uint32_t arg = value; - FILE_LOG(logDEBUG1) << "Setting ADC Invert to 0x" << std::hex << arg << std::dec; + FILE_LOG(logDEBUG1) << "Setting ADC Invert to 0x" << std::hex << value << std::dec; if (shm()->onlineFlag == ONLINE_FLAG) { - sendToDetector(F_SET_ADC_INVERT, &arg, nullptr); + sendToDetector(F_SET_ADC_INVERT, value, nullptr); } } @@ -2689,7 +2688,7 @@ uint32_t slsDetector::getADCInvert() { uint32_t retval = -1; FILE_LOG(logDEBUG1) << "Getting ADC Invert"; if (shm()->onlineFlag == ONLINE_FLAG) { - sendToDetector(F_GET_ADC_INVERT, nullptr, 0, &retval, sizeof(retval)); + sendToDetector(F_GET_ADC_INVERT, nullptr, retval); FILE_LOG(logDEBUG1) << "ADC Invert: 0x" << std::hex << retval << std::dec; } return retval; @@ -2784,13 +2783,12 @@ std::vector slsDetector::getReceiverDbitList() { } int slsDetector::setReceiverDbitOffset(int value) { - int arg = value; int retval = -1; if (value >= 0) shm()->rxDbitOffset = value; - FILE_LOG(logDEBUG1) << "Setting digital bit offset in receiver to " << arg; + FILE_LOG(logDEBUG1) << "Setting digital bit offset in receiver to " << value; if (shm()->rxOnlineFlag == ONLINE_FLAG) { - sendToReceiver(F_RECEIVER_DBIT_OFFSET, arg, retval); + sendToReceiver(F_RECEIVER_DBIT_OFFSET, value, retval); FILE_LOG(logDEBUG1) << "Receiver digital bit offset: " << retval; } return shm()->rxDbitOffset;