From d4d8cbe9bc279186c3d08d1585fc43bb1026adaf Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Wed, 14 Aug 2019 09:20:50 +0200 Subject: [PATCH] gotthard fixed roi only xmin and xmax.remove updateoffsets --- slsDetectorGui/forms/form_tab_advanced.ui | 282 +++++---- slsDetectorGui/include/qTabAdvanced.h | 11 - slsDetectorGui/src/qTabAdvanced.cpp | 190 +----- .../bin/eigerDetectorServer_developer | Bin 302608 -> 302632 bytes .../bin/gotthardDetectorServer_developer | Bin 117024 -> 116980 bytes .../slsDetectorFunctionList.c | 119 ++-- .../slsDetectorServer_defs.h | 1 + .../slsDetectorFunctionList.h | 3 +- .../slsDetectorServer_funcs.c | 111 ++-- .../slsDetectorServer_funcs.h | 1 + slsDetectorSoftware/include/Detector.h | 21 +- .../include/multiSlsDetector.h | 112 +--- slsDetectorSoftware/include/slsDetector.h | 75 +-- .../include/slsDetectorUsers.h | 32 +- slsDetectorSoftware/src/Detector.cpp | 48 +- slsDetectorSoftware/src/multiSlsDetector.cpp | 588 +++--------------- slsDetectorSoftware/src/slsDetector.cpp | 185 ++---- .../src/slsDetectorCommand.cpp | 52 +- slsDetectorSoftware/src/slsDetectorUsers.cpp | 17 +- slsReceiverSoftware/include/DataStreamer.h | 4 +- slsReceiverSoftware/include/GeneralData.h | 35 +- .../include/slsReceiverImplementation.h | 10 +- slsReceiverSoftware/src/DataStreamer.cpp | 6 +- .../src/slsReceiverImplementation.cpp | 51 +- .../src/slsReceiverTCPIPInterface.cpp | 20 +- slsSupportLib/include/sls_detector_defs.h | 12 +- slsSupportLib/include/sls_detector_funcs.h | 2 + slsSupportLib/include/versionAPI.h | 4 +- 28 files changed, 573 insertions(+), 1419 deletions(-) diff --git a/slsDetectorGui/forms/form_tab_advanced.ui b/slsDetectorGui/forms/form_tab_advanced.ui index b6545fd4a..858567f9f 100755 --- a/slsDetectorGui/forms/form_tab_advanced.ui +++ b/slsDetectorGui/forms/form_tab_advanced.ui @@ -54,7 +54,7 @@ QTabWidget::North - 2 + 1 Qt::ElideLeft @@ -132,102 +132,20 @@ Region of Interest - - + + - + 0 0 - - - 130 - 0 - - - Add ROI Slot - - - - :/icons/images/add.png:/icons/images/add.png + X Min: - - - - - 0 - 0 - - - - - 130 - 0 - - - - Get ROI - - - - :/icons/images/download.png:/icons/images/download.png - - - - - - - Qt::Horizontal - - - - 20 - 20 - - - - - - - - Qt::Horizontal - - - - 20 - 20 - - - - - - - - - 0 - 0 - - - - - 130 - 0 - - - - Set ROI - - - - :/icons/images/upload.png:/icons/images/upload.png - - - - + @@ -237,12 +155,12 @@ - 130 - 0 + 0 + 35 - Clear ROI + Clear ROI @@ -250,45 +168,159 @@ - + + + + + 160 + 0 + + + + -1 + + + 1279 + + + -1 + + + + Qt::Horizontal - 20 + 40 20 - - - - QFrame::NoFrame + + + + + 0 + 0 + - - true + + X Max: + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 160 + 0 + + + + -1 + + + 1279 + + + -1 + + + + + + + + 0 + 0 + + + + Readout: + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + 0 + 0 + + + + + 0 + 35 + + + + Set ROI + + + + :/icons/images/refresh.png:/icons/images/refresh.png + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + 160 + 0 + - - - - 0 - 0 - 735 - 235 - - - - - 1 - - - 15 - - - @@ -399,7 +431,7 @@ - Detector Control Port: + Readout Control Port: @@ -910,7 +942,7 @@ - Detector UDP MAC: + Readout UDP MAC: @@ -929,7 +961,7 @@ - Detector: + Readout: @@ -968,7 +1000,7 @@ - Detector UDP IP: + Readout UDP IP: @@ -981,7 +1013,7 @@ - Detector Stop Port: + Readout Stop Port: @@ -1402,11 +1434,11 @@ Exposure Time of a sub frame. Only for Eiger in 32 bit mode tabAdvancedSettings spinSetAllTrimbits - btnAddRoi + comboReadout + spinXmin + spinXmax btnSetRoi - btnGetRoi btnClearRoi - scrollArea comboDetector spinControlPort spinStopPort diff --git a/slsDetectorGui/include/qTabAdvanced.h b/slsDetectorGui/include/qTabAdvanced.h index 921232914..62986e7b9 100755 --- a/slsDetectorGui/include/qTabAdvanced.h +++ b/slsDetectorGui/include/qTabAdvanced.h @@ -29,7 +29,6 @@ private slots: void SetRxrUDPMAC(); void SetRxrZMQPort(int port); void SetRxrZMQIP(); - void AddROISlot(); void GetROI(); void ClearROI(); void SetROI(); @@ -56,22 +55,12 @@ private: void GetRxrUDPMAC(); void GetRxrZMQPort(); void GetRxrZMQIP(); - void ClearROIWidgets(); void GetAllTrimbits(); void GetNumStoragecells(); void GetSubExposureTime(); void GetSubDeadTime(); multiSlsDetector *myDet; - /** ROI */ - std::vector lblFromX; - std::vector spinFromX; - std::vector lblFromY; - std::vector spinFromY; - std::vector lblToX; - std::vector spinToX; - std::vector lblToY; - std::vector spinToY; }; diff --git a/slsDetectorGui/src/qTabAdvanced.cpp b/slsDetectorGui/src/qTabAdvanced.cpp index 72eb07e23..811fd8217 100755 --- a/slsDetectorGui/src/qTabAdvanced.cpp +++ b/slsDetectorGui/src/qTabAdvanced.cpp @@ -10,18 +10,7 @@ qTabAdvanced::qTabAdvanced(QWidget *parent, multiSlsDetector *detector) FILE_LOG(logDEBUG) << "Advanced ready"; } -qTabAdvanced::~qTabAdvanced() { - for (size_t i = 0; i < lblFromX.size(); ++i) { - delete lblFromX[i]; - delete lblFromY[i]; - delete lblToX[i]; - delete lblToY[i]; - delete spinFromX[i]; - delete spinFromY[i]; - delete spinToX[i]; - delete spinToY[i]; - } -} +qTabAdvanced::~qTabAdvanced() {} void qTabAdvanced::SetupWidgetWindow() { // enabling according to det type @@ -93,9 +82,8 @@ void qTabAdvanced::Initialization() { // roi if (tab_roi->isEnabled()) { - connect(btnAddRoi, SIGNAL(clicked()), this, SLOT(AddROISlot())); + connect(comboReadout, SIGNAL(currentIndexChanged(int)), this, SLOT(GetROI())); connect(btnSetRoi, SIGNAL(clicked()), this, SLOT(SetROI())); - connect(btnGetRoi, SIGNAL(clicked()), this, SLOT(GetROI())); connect(btnClearRoi, SIGNAL(clicked()), this, SLOT(ClearROI())); } @@ -122,14 +110,20 @@ void qTabAdvanced::PopulateDetectors() { FILE_LOG(logDEBUG) << "Populating detectors"; disconnect(comboDetector, SIGNAL(currentIndexChanged(int)), this, SLOT(SetDetector(int))); + disconnect(comboReadout, SIGNAL(currentIndexChanged(int)), this, SLOT(GetROI())); comboDetector->clear(); - for (unsigned int i = 0; i < myDet->size(); ++i) + comboReadout->clear(); + for (unsigned int i = 0; i < myDet->size(); ++i) { comboDetector->addItem(QString(myDet->getHostname(i).c_str())); + comboReadout->addItem(QString(myDet->getHostname(i).c_str())); + } comboDetector->setCurrentIndex(0); + comboReadout->setCurrentIndex(0); connect(comboDetector, SIGNAL(currentIndexChanged(int)), this, SLOT(SetDetector(int))); + connect(comboReadout, SIGNAL(currentIndexChanged(int)), this, SLOT(GetROI())); } void qTabAdvanced::GetControlPort() { @@ -462,173 +456,33 @@ void qTabAdvanced::SetRxrZMQIP() { &qTabAdvanced::GetRxrZMQIP) } -void qTabAdvanced::AddROISlot() { - FILE_LOG(logDEBUG) << "Add ROI Slot"; - - QLabel *lFromX = new QLabel("x min:"); - QLabel *lFromY = new QLabel("y min:"); - QLabel *lToX = new QLabel("x max:"); - QLabel *lToY = new QLabel("y max:"); - QSpinBox *sFromX = new QSpinBox(); - QSpinBox *sFromY = new QSpinBox(); - QSpinBox *sToX = new QSpinBox(); - QSpinBox *sToY = new QSpinBox(); - lFromX->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - lFromY->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - lToX->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - lToY->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - sFromX->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - sFromY->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - sToX->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - sToY->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - lFromX->setFixedWidth(50); - lFromY->setFixedWidth(50); - lToX->setFixedWidth(50); - lToY->setFixedWidth(50); - sFromX->setFixedWidth(80); - sFromY->setFixedWidth(80); - sToX->setFixedWidth(80); - sToY->setFixedWidth(80); - sFromX->setFixedHeight(19); - sFromY->setFixedHeight(19); - sToX->setFixedHeight(19); - sToY->setFixedHeight(19); - sFromX->setMaximum(myDet->getTotalNumberOfChannels(slsDetectorDefs::X) - 1); - sToX->setMaximum(myDet->getTotalNumberOfChannels(slsDetectorDefs::X) - 1); - sFromY->setMaximum(myDet->getTotalNumberOfChannels(slsDetectorDefs::Y) - 1); - sToY->setMaximum(myDet->getTotalNumberOfChannels(slsDetectorDefs::Y) - 1); - sFromX->setMinimum(-1); - sToX->setMinimum(-1); - sFromY->setMinimum(-1); - sToY->setMinimum(-1); - sFromX->setValue(-1); - sFromY->setValue(-1); - sToX->setValue(-1); - sToY->setValue(-1); - - lblFromX.push_back(lFromX); - lblFromY.push_back(lFromY); - lblToX.push_back(lToX); - lblToY.push_back(lToY); - spinFromX.push_back(sFromX); - spinFromY.push_back(sFromY); - spinToX.push_back(sToX); - spinToY.push_back(sToY); - - int nroi = (int)lblFromX.size(); - gridRoi->addWidget(lblFromX[nroi], nroi, 0, Qt::AlignTop); - gridRoi->addWidget(spinFromX[nroi], nroi, 1, Qt::AlignTop); - // FIXME: gridRoi->addItem(new - // QSpacerItem(40,20,QSizePolicy::Expanding,QSizePolicy::Fixed), - // nroi,2,Qt::AlignTop); - gridRoi->addWidget(lblToX[nroi], nroi, 3, Qt::AlignTop); - gridRoi->addWidget(spinToX[nroi], nroi, 4, Qt::AlignTop); - // FIXME: gridRoi->addItem(new - // QSpacerItem(40,20,QSizePolicy::Expanding,QSizePolicy::Fixed), - // nroi,5,Qt::AlignTop); - gridRoi->addWidget(lblFromY[nroi], nroi, 6, Qt::AlignTop); - gridRoi->addWidget(spinFromY[nroi], nroi, 7, Qt::AlignTop); - // FIXME: gridRoi->addItem(new - // QSpacerItem(40,20,QSizePolicy::Expanding,QSizePolicy::Fixed), - // nroi,8,Qt::AlignTop); - gridRoi->addWidget(lblToY[nroi], nroi, 9, Qt::AlignTop); - gridRoi->addWidget(spinToY[nroi], nroi, 10, Qt::AlignTop); - - lblFromX[nroi]->show(); - spinFromX[nroi]->show(); - lblToX[nroi]->show(); - spinToX[nroi]->show(); - lblFromY[nroi]->show(); - spinFromY[nroi]->show(); - lblToY[nroi]->show(); - spinToY[nroi]->show(); - - FILE_LOG(logDEBUG) << "ROI Inputs added"; -} - void qTabAdvanced::GetROI() { FILE_LOG(logDEBUG) << "Getting ROI"; - ClearROIWidgets(); - try { - int nroi = 0; - const slsDetectorDefs::ROI *roi = myDet->getROI(nroi); - if (roi != nullptr) { - for (int i = 0; i < nroi; ++i) { - AddROISlot(); - spinFromX[i]->setValue(roi[i].xmin); - spinFromY[i]->setValue(roi[i].ymin); - spinToX[i]->setValue(roi[i].xmax); - spinToY[i]->setValue(roi[i].ymax); - } - FILE_LOG(logDEBUG) << "ROIs populated: " << nroi; - } - + slsDetectorDefs::ROI roi = myDet->getROI(comboReadout->currentIndex()); + spinXmin->setValue(roi.xmin); + spinXmax->setValue(roi.xmax); } CATCH_DISPLAY ("Could not get ROI.", "qTabAdvanced::GetROI") } -void qTabAdvanced::ClearROIWidgets() { - FILE_LOG(logDEBUG) << "Clear ROI Widgets"; - - // hide widgets - QLayoutItem *item; - while ((item = gridRoi->takeAt(0))) { - if (item->widget()) { - item->widget()->hide(); - gridRoi->removeWidget(item->widget()); - } - } - - // delete widgets - for (size_t i = 0; i < lblFromX.size(); ++i) { - delete lblFromX[i]; - delete spinFromX[i]; - delete lblToX[i]; - delete spinToY[i]; - delete lblFromY[i]; - delete spinFromY[i]; - delete lblToY[i]; - delete spinToY[i]; - } - lblFromX.clear(); - spinFromX.clear(); - lblToX.clear(); - spinToY.clear(); - lblFromY.clear(); - spinFromY.clear(); - lblToY.clear(); - spinToY.clear(); -} - void qTabAdvanced::ClearROI() { FILE_LOG(logINFO) << "Clearing ROI"; - if (QMessageBox::warning( - this, "Clear ROI", - "Are you sure you want to clear all the ROI in detector?", - QMessageBox::Yes | QMessageBox::No, - QMessageBox::No) == QMessageBox::Yes) { - - ClearROIWidgets(); - SetROI(); - FILE_LOG(logDEBUG) << "ROIs cleared"; - } + spinXmin->setValue(-1); + spinXmax->setValue(-1); + SetROI(); + FILE_LOG(logDEBUG) << "ROIs cleared"; } void qTabAdvanced::SetROI() { - // get roi from widgets - int nroi = (int)lblFromX.size(); - slsDetectorDefs::ROI roi[nroi]; - for (int i = 0; i < nroi; ++i) { - roi[i].xmin = spinFromX[i]->value(); - roi[i].ymin = spinFromY[i]->value(); - roi[i].xmax = spinToX[i]->value(); - roi[i].ymax = spinToY[i]->value(); - } + + slsDetectorDefs::ROI roi; + roi.xmin = spinXmin->value(); + roi.xmax = spinXmax->value(); // set roi - FILE_LOG(logINFO) << "Setting ROI:" << nroi; + FILE_LOG(logINFO) << "Setting ROI: [" << roi.xmin << ", " << roi.xmax << "]"; try { - myDet->setROI(nroi, roi, -1); + myDet->setROI(roi, comboReadout->currentIndex()); } CATCH_DISPLAY ("Could not set these ROIs.", "qTabAdvanced::SetROI") diff --git a/slsDetectorServers/eigerDetectorServer/bin/eigerDetectorServer_developer b/slsDetectorServers/eigerDetectorServer/bin/eigerDetectorServer_developer index f79ce81f4e10757be6b2c605237aed6d07bc9d3f..58a992a6c86049b59c114161da0d46ad08fde533 100755 GIT binary patch delta 44635 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%0Aw?N63K)d%vfD&uyqC_52n_G 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 RrE=5G@@>914>;Du{y#I17b^e& delta 45927 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 PB^vcgv5RWbLVErmYT*%r delta 50976 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 diff --git a/slsDetectorServers/gotthardDetectorServer/slsDetectorFunctionList.c b/slsDetectorServers/gotthardDetectorServer/slsDetectorFunctionList.c index 6f7ce88b4..a0b0807d5 100755 --- a/slsDetectorServers/gotthardDetectorServer/slsDetectorFunctionList.c +++ b/slsDetectorServers/gotthardDetectorServer/slsDetectorFunctionList.c @@ -37,8 +37,7 @@ int digitalTestBit = 0; // roi configuration int adcConfigured = -1; -ROI rois[MAX_ROIS]; -int nROI = 0; +ROI rois; int ipPacketSize = 0; int udpPacketSize = 0; @@ -397,7 +396,9 @@ void setupDetector() { bus_w(TEMP_SPI_OUT_REG, 0x0); // roi, gbit readout - setROIADC(-1); // set adcsyncreg, daqreg, chipofinterestreg, cleanfifos, + rois.xmin = -1; + rois.xmax = -1; + setROI(rois);// set adcsyncreg, daqreg, chipofinterestreg, cleanfifos, setGbitReadout(); // master, slave (25um) @@ -726,95 +727,49 @@ int setDynamicRange(int dr){ return DYNAMIC_RANGE; } -ROI* setROI(int n, ROI arg[], int *retvalsize, int *ret) { +int setROI(ROI arg) { - // set ROI - if(n >= 0){ - // print - if (!n) { - FILE_LOG(logINFO, ("Clearing ROI\n")); - } else { - FILE_LOG(logINFO, ("Setting ROI:\n")); - int i = 0; - for (i = 0; i < n; ++i) { - FILE_LOG(logINFO, ("\t(%d, %d)\n", arg[i].xmin, arg[i].xmax)); - } + int adc = -1; + if (arg.xmin == -1) { + FILE_LOG(logINFO, ("Clearing ROI\n")); + rois.xmin = -1; + rois.xmax = -1; + } else { + FILE_LOG(logINFO, ("Setting ROI:(%d, %d)\n", arg.xmin, arg.xmax)); + // validation + // xmin divisible by 256 and less than 1280 + if (((arg.xmin % NCHAN_PER_ADC) != 0) || (arg.xmin >= (NCHAN * NCHIP))) { + FILE_LOG(logERROR, ("Could not set roi. xmin is invalid\n")); + return FAIL; } - // only one ROI allowed per module - if (n > 1) { - FILE_LOG(logERROR, ("\tCannot set more than 1 ROI per module\n")); - *ret = FAIL; - *retvalsize = nROI; - return rois; + // xmax must be 255 more than xmin + if (arg.xmax != (arg.xmin + NCHAN_PER_ADC - 1)) { + FILE_LOG(logERROR, ("Could not set roi. xmax is invalid\n")); + return FAIL; } + rois.xmin = arg.xmin; + rois.xmax = arg.xmax; + adc = arg.xmin / NCHAN_PER_ADC; + } + FILE_LOG(logINFO, ("\tAdc to be configured: %d\n", adc)); + FILE_LOG(logINFO, ("\tROI to be configured: (%d, %d)\n", + (adc == -1) ? 0 : (rois.xmin), + (adc == -1) ? (NCHIP * NCHAN - 1) : (rois.xmax))); - //clear all rois - nROI = 0; + //set adc of interest + setROIADC(adc); + return OK; +} - // find adc number and recorrect channel limits - int adc = -1; - if (n) { - // all channels - if ((arg[0].xmin <= 0) && (arg[0].xmax >= NCHIP * NCHAN)) - adc = -1; - // single adc - else { - //adc = mid value/numchans - adc = ((((arg[0].xmax) + (arg[0].xmin))/2) / (NCHAN * NCHIPS_PER_ADC)); - // incorrect adc - if((adc < 0) || (adc > 4)) { - FILE_LOG(logERROR, ("\tadc value greater than 5. deleting roi\n")); - adc = -1; - } - // recorrect roi values - else { - rois[0].xmin = adc * (NCHAN * NCHIPS_PER_ADC); - rois[0].xmax = (adc + 1) * (NCHAN * NCHIPS_PER_ADC) - 1; - rois[0].ymin = -1; - rois[0].ymax = -1; - nROI = 1; - } - } - } - - if (adc == -1) - nROI = 0; - - FILE_LOG(logINFO, ("\tAdc to be configured: %d\n", adc)); - FILE_LOG(logINFO, ("\tROI to be configured: (%d, %d)\n", - (adc == -1) ? 0 : (rois[0].xmin), - (adc == -1) ? (NCHIP * NCHAN - 1) : (rois[0].xmax))); - - // could not set roi - if((n != 0) && ((arg[0].xmin != rois[0].xmin)|| - (arg[0].xmax != rois[0].xmax)|| - (arg[0].ymin != rois[0].ymin)|| - (arg[0].ymax != rois[0].ymax))) { - *ret = FAIL; - FILE_LOG(logERROR, ("\tCould not set given ROI\n")); - } - if(n != nROI) { - *ret = FAIL; - FILE_LOG(logERROR, ("\tCould not set or clear ROIs\n")); - } - - //set adc of interest - setROIADC(adc); - } else FILE_LOG(logINFO, ("Getting ROI:\n")); +ROI getROI() { + FILE_LOG(logINFO, ("Getting ROI:\n")); // print - if (!nROI) { + if (rois.xmin == -1) { FILE_LOG(logINFO, ("\tROI: None\n")); } else { - FILE_LOG(logINFO, ("ROI:\n")); - int i = 0; - for (i = 0; i < nROI; ++i) { - FILE_LOG(logINFO, ("\t(%d, %d)\n", rois[i].xmin, rois[i].xmax)); - - } + FILE_LOG(logINFO, ("ROI: (%d,%d)\n", rois.xmin, rois.xmax)); } - - *retvalsize = nROI; return rois; } diff --git a/slsDetectorServers/gotthardDetectorServer/slsDetectorServer_defs.h b/slsDetectorServers/gotthardDetectorServer/slsDetectorServer_defs.h index 6c037e852..16e1142cb 100755 --- a/slsDetectorServers/gotthardDetectorServer/slsDetectorServer_defs.h +++ b/slsDetectorServers/gotthardDetectorServer/slsDetectorServer_defs.h @@ -24,6 +24,7 @@ enum DACINDEX {VREF_DS, VCASCN_PB, VCASCP_PB, VOUT_CM, VCASC_OUT, VIN #define NCHIP (10) #define NDAC (8) #define NCHIPS_PER_ADC (2) +#define NCHAN_PER_ADC (256) #define DYNAMIC_RANGE (16) #define NUM_BITS_PER_PIXEL (DYNAMIC_RANGE / 8) #define DATA_BYTES (NCHIP * NCHAN * NUM_BITS_PER_PIXEL) diff --git a/slsDetectorServers/slsDetectorServer/slsDetectorFunctionList.h b/slsDetectorServers/slsDetectorServer/slsDetectorFunctionList.h index fd4ca2898..7038b6135 100755 --- a/slsDetectorServers/slsDetectorServer/slsDetectorFunctionList.h +++ b/slsDetectorServers/slsDetectorServer/slsDetectorFunctionList.h @@ -114,7 +114,8 @@ void resetPeripheral(); // parameters - dr, roi int setDynamicRange(int dr); #ifdef GOTTHARDD -ROI* setROI(int n, ROI arg[], int *retvalsize, int *ret); +int setROI(ROI arg); +ROI getROI(); #endif #if defined(CHIPTESTBOARDD) || defined(MOENCHD) int setADCEnableMask(uint32_t mask); diff --git a/slsDetectorServers/slsDetectorServer/slsDetectorServer_funcs.c b/slsDetectorServers/slsDetectorServer/slsDetectorServer_funcs.c index 4b98305cc..542af9d48 100755 --- a/slsDetectorServers/slsDetectorServer/slsDetectorServer_funcs.c +++ b/slsDetectorServers/slsDetectorServer/slsDetectorServer_funcs.c @@ -189,6 +189,7 @@ const char* getFunctionName(enum detFuncs func) { case F_SET_DYNAMIC_RANGE: return "F_SET_DYNAMIC_RANGE"; case F_SET_READOUT_FLAGS: return "F_SET_READOUT_FLAGS"; case F_SET_ROI: return "F_SET_ROI"; + case F_GET_ROI: return "F_GET_ROI"; case F_SET_SPEED: return "F_SET_SPEED"; case F_EXIT_SERVER: return "F_EXIT_SERVER"; case F_LOCK_SERVER: return "F_LOCK_SERVER"; @@ -279,6 +280,7 @@ void function_table() { flist[F_SET_DYNAMIC_RANGE] = &set_dynamic_range; flist[F_SET_READOUT_FLAGS] = &set_readout_flags; flist[F_SET_ROI] = &set_roi; + flist[F_GET_ROI] = &get_roi; flist[F_SET_SPEED] = &set_speed; flist[F_EXIT_SERVER] = &exit_server; flist[F_LOCK_SERVER] = &lock_server; @@ -1896,76 +1898,49 @@ int set_readout_flags(int file_des) { int set_roi(int file_des) { ret = OK; memset(mess, 0, sizeof(mess)); - int narg = -1; - ROI arg[MAX_ROIS]; - int nretval = -1; - ROI* retval = NULL; + ROI arg; - // receive number of ROIs - if (receiveData(file_des, &narg, sizeof(narg), INT32) < 0) + // receive ROI + if (receiveData(file_des, &arg.xmin, sizeof(int), INT32) < 0) return printSocketReadError(); - // receive ROIs - { - int iloop = 0; - for (iloop = 0; iloop < narg; ++iloop) { - if (receiveData(file_des, &arg[iloop].xmin, sizeof(int), INT32) < 0) - return printSocketReadError(); - if (receiveData(file_des, &arg[iloop].xmax, sizeof(int), INT32) < 0) - return printSocketReadError(); - if (receiveData(file_des, &arg[iloop].ymin, sizeof(int), INT32) < 0) - return printSocketReadError(); - if (receiveData(file_des, &arg[iloop].ymax, sizeof(int), INT32) < 0) - return printSocketReadError(); - } - } - FILE_LOG(logDEBUG1, ("Set ROI (narg:%d)\n", narg)); - { - int iloop = 0; - for (iloop = 0; iloop < narg; ++iloop) { - FILE_LOG(logDEBUG1, ("%d: %d\t%d\t%d\t%d\n", - arg[iloop].xmin, arg[iloop].xmax, arg[iloop].ymin, arg[iloop].ymax)); - } - } + if (receiveData(file_des, &arg.xmax, sizeof(int), INT32) < 0) + return printSocketReadError(); + FILE_LOG(logDEBUG1, ("Set ROI: [%d, %d]\n", arg.xmin, arg.xmax)); #ifndef GOTTHARDD functionNotImplemented(); #else - // set & get - if ((narg == GET_READOUT_FLAGS) || (Server_VerifyLock() == OK)) { - if (myDetectorType == GOTTHARD && narg > 1) { - ret = FAIL; - strcpy(mess,"Can not set more than one ROI per module.\n"); - FILE_LOG(logERROR,(mess)); - } else { - retval = setROI(narg, arg, &nretval, &ret); - if (ret == FAIL) { - if (nretval == -1) // chip test board - sprintf(mess,"Could not set ROI. Max ROI level (100) reached!\n"); - else if (nretval == -2) - sprintf(mess, "Could not set ROI. Could not allocate RAM\n"); - else - sprintf(mess,"Could not set all roi. " - "Set %d rois, but read %d rois\n", narg, nretval); - FILE_LOG(logERROR,(mess)); - } - FILE_LOG(logDEBUG1, ("nRois: %d\n", nretval)); - } + // only set + if (Server_VerifyLock() == OK) { + ret = setROI(arg); + if (ret == FAIL) { + sprintf(mess, "Could not set ROI. Invalid xmin or xmax\n"); + FILE_LOG(logERROR,(mess)); + } } #endif - Server_SendResult(file_des, INT32, UPDATE, NULL, 0); + return Server_SendResult(file_des, INT32, UPDATE, NULL, 0); +} + +int get_roi(int file_des) { + ret = OK; + memset(mess, 0, sizeof(mess)); + ROI retval; + +#ifndef GOTTHARDD + functionNotImplemented(); +#else + // only get + retval = getROI(); + FILE_LOG(logDEBUG1, ("nRois: (%d, %d)\n", retval.xmin, retval.xmax)); +#endif + + Server_SendResult(file_des, INT32, UPDATE, NULL, 0); if (ret != FAIL) { - //retvalsize could be swapped during sendData - int nretval1 = nretval; - sendData(file_des, &nretval1, sizeof(nretval1), INT32); - int iloop = 0; - for(iloop = 0; iloop < nretval; ++iloop) { - sendData(file_des, &retval[iloop].xmin, sizeof(int), INT32); - sendData(file_des, &retval[iloop].xmax, sizeof(int), INT32); - sendData(file_des, &retval[iloop].ymin, sizeof(int), INT32); - sendData(file_des, &retval[iloop].ymax, sizeof(int), INT32); - } + sendData(file_des, &retval.xmin, sizeof(int), INT32); + sendData(file_des, &retval.xmax, sizeof(int), INT32); } return ret; } @@ -1973,7 +1948,6 @@ int set_roi(int file_des) { - int set_speed(int file_des) { ret = OK; memset(mess, 0, sizeof(mess)); @@ -2284,20 +2258,9 @@ int send_update(int file_des) { // roi #if defined(GOTTHARDD) - ROI* retval = NULL; - ROI arg[1]; - int ret = OK, nretval = 0; - retval = setROI(-1, arg, &nretval, &ret); - //retvalsize could be swapped during sendData - int nretval1 = nretval; - sendData(file_des, &nretval1, sizeof(nretval1), INT32); - int iloop = 0; - for(iloop = 0; iloop < nretval; ++iloop) { - sendData(file_des, &retval[iloop].xmin, sizeof(int), INT32); - sendData(file_des, &retval[iloop].xmax, sizeof(int), INT32); - sendData(file_des, &retval[iloop].ymin, sizeof(int), INT32); - sendData(file_des, &retval[iloop].ymax, sizeof(int), INT32); - } + ROI retval = getROI(); + sendData(file_des, &retval.xmin, sizeof(int), INT32); + sendData(file_des, &retval.xmax, sizeof(int), INT32); #endif #if defined(CHIPTESTBOARDD) || defined(MOENCHD) diff --git a/slsDetectorServers/slsDetectorServer/slsDetectorServer_funcs.h b/slsDetectorServers/slsDetectorServer/slsDetectorServer_funcs.h index 66ed015c7..26c889650 100755 --- a/slsDetectorServers/slsDetectorServer/slsDetectorServer_funcs.h +++ b/slsDetectorServers/slsDetectorServer/slsDetectorServer_funcs.h @@ -49,6 +49,7 @@ int get_time_left(int); int set_dynamic_range(int); int set_readout_flags(int); int set_roi(int); +int get_roi(int); int set_speed(int); int exit_server(int); int lock_server(int); diff --git a/slsDetectorSoftware/include/Detector.h b/slsDetectorSoftware/include/Detector.h index 824b11bb3..08eb14955 100644 --- a/slsDetectorSoftware/include/Detector.h +++ b/slsDetectorSoftware/include/Detector.h @@ -82,16 +82,10 @@ class Detector { /** * Sets the maximum number of channels of complete detector in both * dimensions. -1 means no limit in this dimension. This value is used to - * calculate row and column offsets for each module. + * calculate row and column channels for each module. */ void setMaxNumberOfChannels(const defs::coordinates value); - /** [Gotthard] */ - Result getDetectorOffsets(Positions pos = {}) const; - - /** [Gotthard] */ - void setDetectorOffsets(defs::coordinates value, Positions pos = {}); - /** [Eiger with specific quad hardware] */ Result getQuad(Positions pos = {}) const; @@ -664,15 +658,16 @@ class Detector { /** [Eiger] If it is set, it resets chips completely (else partially) before an acquisition TODO: if it makes sense */ void setCounterBit(bool value, Positions pos = {}); - /** [Gotthard, CTB]*/ - Result> getROI(Positions pos = {}) const; + /** [Gotthard]*/ + Result getROI(Positions pos = {}) const; /** - * [Gotthard Options: Only a single chip or all chips, only 1 ROI allowed] - * [CTB: multiple ROIs allowed] - * subset modules not allowed + * [Gotthard] + * Options: Only a single ROI per module + * Can set only a single ROI at a time + * @param module position index */ - void setROI(std::vector value, Positions pos = {}); + void setROI(defs::ROI value, int moduleId); /** [CTB]*/ Result getADCEnableMask(Positions pos = {}) const; diff --git a/slsDetectorSoftware/include/multiSlsDetector.h b/slsDetectorSoftware/include/multiSlsDetector.h index 611d93ae3..c24a00cd9 100755 --- a/slsDetectorSoftware/include/multiSlsDetector.h +++ b/slsDetectorSoftware/include/multiSlsDetector.h @@ -65,16 +65,6 @@ struct sharedMultiSlsDetector { /** total number of channels including gap pixels in one dimension */ int numberOfChannelInclGapPixels[2]; - /** total number of channels for all detectors */ - int maxNumberOfChannels; - - /** max number of channels for all detectors in one dimension*/ - int maxNumberOfChannel[2]; - - /** max number of channels including gap pixels for all detectors in - * one dimension*/ - int maxNumberOfChannelInclGapPixels[2]; - /** max number of channels allowed for the complete set of detectors in * one dimension */ int maxNumberOfChannelsPerDetector[2]; @@ -432,8 +422,7 @@ class multiSlsDetector : public virtual slsDetectorDefs { /** * Returns the maximum number of channels of all sls detectors in each - * dimension d from shared memory. multi detector shared memory variable to - * calculate offsets for each sls detector + * dimension d from shared memory. * @param d dimension d * @returns the maximum number of channels of all sls detectors in dimension * d @@ -442,8 +431,7 @@ class multiSlsDetector : public virtual slsDetectorDefs { /** * Sets the maximum number of channels of all sls detectors in each - * dimension d from shared memory, multi detector shared memory variable to - * calculate offsets for each sls detector + * dimension d from shared memory * @param d dimension d * @param i maximum number of channels for multi structure in dimension d * @returns the maximum number of channels of all sls detectors in dimension @@ -453,37 +441,18 @@ class multiSlsDetector : public virtual slsDetectorDefs { /** * Returns maximum number of channels of all sls detectors in each - * dimension d from shared memory, multi detector shared memory variable to - * calculate offsets for each sls detector + * dimension d from shared memory * @returns maximum number of channels of all sls detectors */ slsDetectorDefs::coordinates getMaxNumberOfChannels() const; // /** * Sets maximum number of channels of all sls detectors in each - * dimension d from shared memory, multi detector shared memory variable to - * calculate offsets for each sls detector + * dimension d from shared memory * @param c maximum number of channels of all sls detectors */ void setMaxNumberOfChannels(const slsDetectorDefs::coordinates c); // - /** - * Get Detector offset from shared memory in dimension d - * @param d dimension d - * @param detPos -1 for all detectors in list or specific detector position - * @returns offset in dimension d, -1 if pos is not an actual position in - * list - */ - int getDetectorOffset(dimension d, int detPos = -1); // - - /** - * Set Detector offset in shared memory in dimension d - * @param d dimension d - * @param off offset for detector - * @param detPos -1 for all detectors in list or specific detector position - */ - void setDetectorOffset(dimension d, int off, int detPos = -1);// - /** * Get Quad Type (Only for Eiger Quad detector hardware) * @param detPos -1 for all detectors in list or specific detector position @@ -1376,22 +1345,27 @@ class multiSlsDetector : public virtual slsDetectorDefs { int setCounterBit(int i = -1, int detPos = -1); // /** - * Set ROI (Gotthard) - * At the moment only one set allowed - * @param n number of rois - * @param roiLimits array of roi + * Clear ROI (Gotthard) * @param detPos -1 for all detectors in list or specific detector position */ - void setROI(int n = -1, ROI roiLimits[] = nullptr, int detPos = -1); + void clearROI(int detPos = -1); /** - * Get ROI from each detector and convert it to the multi detector scale - * (Gotthard) - * @param n number of rois - * @param detPos -1 for all detectors in list or specific detector position - * @returns OK or FAIL + * Set ROI (Gotthard) + * At the moment only one set allowed per module + * Only allowed to set one ROI per module + * @param arg roi + * @param detPos specific detector position */ - const ROI *getROI(int &n, int detPos = -1); + void setROI(slsDetectorDefs::ROI arg, int detPos = -1); + + /** + * Get ROI (Gotthard) + * Only allowed to set one ROI per module + * @param detPos specific detector position + * @returns roi + */ + slsDetectorDefs::ROI getROI(int detPos) const; /** * Set ADC Enable Mask (CTB, Moench) @@ -2187,14 +2161,6 @@ class multiSlsDetector : public virtual slsDetectorDefs { */ void initializeMembers(bool verify = true); - /** - * 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);// - /** * Update user details in detector structure */ @@ -2206,23 +2172,6 @@ class multiSlsDetector : public virtual slsDetectorDefs { */ bool isAcquireReady(); - /** - * Decodes which detector and the corresponding channel numbers for it - * Mainly useful in a multi detector setROI (Gotthard) - * @param offsetX channel number or total channel offset in x direction - * @param offsetY channel number or total channel offset in y direction - * @param channelX channel number from detector offset in x direction - * @param channelY channel number from detector offset in x direction - * @returns detector id or -1 if channel number out of range - */ - int decodeNChannel(int offsetX, int offsetY, int &channelX, int &channelY); - - /** - * Updates the channel offsets in X and Y dimension for all the sls - * detectors It is required for decodeNMod and setting ROI - */ - void updateOffsets(); - /** * Execute in command line and return result * @param cmd command @@ -2230,12 +2179,26 @@ 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 */ void addSlsDetector(const std::string &hostname); + /** + * Updates the channel size in X and Y dimension for all the sls + * detectors + */ + void updateDetectorSize(); + /** * increments file index * @param detPos -1 for all detectors in list or specific detector position @@ -2243,13 +2206,6 @@ class multiSlsDetector : public virtual slsDetectorDefs { */ int incrementFileIndex(int detPos = -1); - /** - * Ensures that min is less than max in both dimensions (Gotthard) - * @param n number of rois - * @param r array of rois - */ - void verifyMinMaxROI(int n, ROI r[]); - /** * add gap pixels to the image (only for Eiger in 4 bit mode) * @param image pointer to image without gap pixels diff --git a/slsDetectorSoftware/include/slsDetector.h b/slsDetectorSoftware/include/slsDetector.h index 269e8cdc7..de23d310d 100755 --- a/slsDetectorSoftware/include/slsDetector.h +++ b/slsDetectorSoftware/include/slsDetector.h @@ -13,7 +13,7 @@ class ServerInterface; #define SLS_SHMAPIVERSION 0x190726 -#define SLS_SHMVERSION 0x190726 +#define SLS_SHMVERSION 0x190813 /** * @short structure allocated in shared memory to store detector settings for @@ -35,10 +35,6 @@ struct sharedSlsDetector { /** END OF FIXED PATTERN -----------------------------------------------*/ - /** Detector offset in the X & Y direction in the multi detector structure - */ - int offset[2]; - /** Number of detectors in multi list in x dir and y dir */ int multiSize[2]; @@ -75,11 +71,8 @@ struct sharedSlsDetector { /** size of the data that are transfered from the detector */ int dataBytes; - /** number of rois defined */ - int nROI; - - /** list of rois */ - slsDetectorDefs::ROI roiLimits[MAX_ROIS]; + /** roi */ + slsDetectorDefs::ROI roi; /** adc enable mask */ uint32_t adcEnableMask; @@ -339,7 +332,7 @@ class slsDetector : public virtual slsDetectorDefs { /** * Update total number of channels (chiptestboard or moench) - * depending on the number of samples, roi, readout flags(ctb) + * depending on the number of samples, adenablemask, readout flags(ctb) */ void updateTotalNumberOfChannels(); @@ -423,32 +416,6 @@ class slsDetector : public virtual slsDetectorDefs { */ int getReadNLines(); - /** - * Get Detector offset from shared memory in dimension d - * @param d dimension d - * @returns offset in dimension d - */ - int getDetectorOffset(dimension d) const; - - /** - * Get Detector offset from shared memory in dimension d - * @returns offset - */ - slsDetectorDefs::coordinates getDetectorOffsets() const; - - /** - * Set Detector offset in shared memory in dimension d - * @param d dimension d - * @param off offset for detector - */ - void setDetectorOffset(dimension d, int off); - - /** - * Set Detector offset in shared memory - * @param value offset for detector - */ - void setDetectorOffsets(slsDetectorDefs::coordinates value); - /** * Set Detector offset in shared memory in dimension d * @param detx number of detectors in X dir in multi list @@ -1143,35 +1110,29 @@ class slsDetector : public virtual slsDetectorDefs { */ int setCounterBit(int cb = -1); + /** + * Clear ROI (Gotthard) + */ + void clearROI(); + /** * Set ROI (Gotthard) - * At the moment only one set allowed - * @param n number of rois - * @param roiLimits array of roi + * Also calls configuremac + * @param arg roi */ - void setROI(int n = -1, ROI roiLimits[] = nullptr); + void setROI(slsDetectorDefs::ROI arg); /** - * Get ROI from each detector and convert it to the multi detector scale - * (Gotthard) - * @param n number of rois - * @returns OK or FAIL + * Send ROI from shared memory to Receiver (Gotthard) */ - const slsDetectorDefs::ROI *getROI(int &n); + void sendROItoReceiver(); /** - * Returns number of rois - * @returns number of ROIs + * Get ROI (Gotthard) + * Update receiver if different from shm + * @returns roi */ - int getNRoi(); - - /** - * Send ROI to the detector after calculating - * from setROI - * @param n number of ROIs (-1 to get) - * @param roiLimits ROI - */ - void sendROI(int n = -1, ROI roiLimits[] = nullptr); + slsDetectorDefs::ROI getROI(); /** * Set ADC Enable Mask (CTB, Moench) diff --git a/slsDetectorSoftware/include/slsDetectorUsers.h b/slsDetectorSoftware/include/slsDetectorUsers.h index 734aabbc8..742d574cf 100755 --- a/slsDetectorSoftware/include/slsDetectorUsers.h +++ b/slsDetectorSoftware/include/slsDetectorUsers.h @@ -104,7 +104,7 @@ public: /** * Returns the maximum number of channels of all detectors * (provided by user in config file using detsizechan command) - * Offsets are calculated according to these dimensions + * number of channels in x and y are calculated according to these dimensions * @param nx number of channels in horizontal * @param ny number of channels in vertical * @returns the maximum number of channels of all detectors @@ -112,15 +112,13 @@ public: int getMaximumDetectorSize(int &nx, int &ny); /** - * Returns the size and offsets of detector/multi detector - * @param x horizontal position origin in channel number - * @param y vertical position origin in channel number + * Returns the size of detector/multi detector * @param nx number of channels in horiziontal * @param ny number of channels in vertical * @param detPos -1 for all detectors in list or specific detector position * @returns the total number of channels of all sls detectors */ - int getDetectorSize(int &x, int &y, int &nx, int &ny, int detPos = -1); + int getDetectorSize(int &nx, int &ny, int detPos); /** * Gets detector type @@ -496,22 +494,22 @@ public: int setFlowControl10G(int enable = -1, int detPos = -1); /** - * Set ROI (Gotthard) (>= 1 roi, but max 1 roi per module) - * At the moment only one set allowed - * @param n number of rois - * @param roiLimits array of roi - * @param detPos -1 for all detectors in list or specific detector position + * Set ROI (Gotthard) + * At the moment only one set allowed per module + * Only allowed to set one ROI per module + * @param arg roi + * @param detPos specific detector position */ - void setROI(int n=-1, slsDetectorDefs::ROI roiLimits[]=NULL, int detPos = -1); + void setROI(slsDetectorDefs::ROI arg, int detPos = -1); + /** - * Get ROI from each detector and convert it to the multi detector scale (Gotthard) - * >= 1 roi, but max 1 roi per module - * @param n number of rois - * @param detPos -1 for all detectors in list or specific detector position - * @returns pointer to array of ROI structure + * Get ROI (Gotthard) + * Only allowed to set one ROI per module + * @param detPos specific detector position + * @returns roi */ - const slsDetectorDefs::ROI* getROI(int &n, int detPos = -1); + slsDetectorDefs::ROI getROI(int detPos = -1); diff --git a/slsDetectorSoftware/src/Detector.cpp b/slsDetectorSoftware/src/Detector.cpp index 81dc9792a..b35e7223a 100644 --- a/slsDetectorSoftware/src/Detector.cpp +++ b/slsDetectorSoftware/src/Detector.cpp @@ -110,16 +110,6 @@ void Detector::setMaxNumberOfChannels(const defs::coordinates value) { pimpl->setMaxNumberOfChannels(value); } -Result Detector::getDetectorOffsets(Positions pos) const { - return pimpl->Parallel(&slsDetector::getDetectorOffsets, pos); -} - -void Detector::setDetectorOffsets(defs::coordinates value, Positions pos) { - pimpl->Parallel(&slsDetector::setDetectorOffsets, pos, value); - // pimpl->Parallel(&slsDetector::setDetectorOffset, pos, - // value); -} - Result Detector::getQuad(Positions pos) const { return pimpl->Parallel(&slsDetector::getQuad, pos); } @@ -1071,41 +1061,15 @@ void Detector::setCounterBit(bool value, Positions pos) { pimpl->Parallel(&slsDetector::setCounterBit, pos, value); } -Result> Detector::getROI(Positions pos) const { - //vector holding module_id for the modules that should be read - const std::vector id_vec = [&]() { - if (pos.empty() || (pos.size() == 1 && pos[0] == -1)){ - std::vector tmp; - for(size_t i=0; i!= pimpl->size(); ++i) - tmp.push_back(i); - return tmp; - }else{ - return pos; - } - }(); - - - //values to return - Result> res; - - //for each detector id get the ROI - for (const auto& i :id_vec){ - int n = 0; - auto ptr = pimpl->getROI(n, i); - // res.emplace_back(ptr, ptr+n); - } - return res; +Result Detector::getROI(Positions pos) const { + return pimpl->Parallel(&slsDetector::getROI, pos); } -void Detector::setROI(std::vector value, Positions pos) { - if (pos.empty() || (pos.size() == 1 && pos[0] == -1)) { - pimpl->setROI(static_cast(value.size()), value.data(), -1); - } else if (pos.size() > 1) { - throw RuntimeError("Cannot set roi to a subset of modules"); - } else { - pimpl->Parallel(&slsDetector::setROI, pos, - static_cast(value.size()), value.data()); +void Detector::setROI(defs::ROI value, int moduleId) { + if (moduleId < 0 && size() > 1) { + throw RuntimeError("Cannot set ROI for all modules simultaneously"); } + pimpl->Parallel(&slsDetector::setROI, {moduleId}, value); } Result Detector::getADCEnableMask(Positions pos) const { diff --git a/slsDetectorSoftware/src/multiSlsDetector.cpp b/slsDetectorSoftware/src/multiSlsDetector.cpp index ef1f9c1e1..1dd184d87 100755 --- a/slsDetectorSoftware/src/multiSlsDetector.cpp +++ b/slsDetectorSoftware/src/multiSlsDetector.cpp @@ -283,8 +283,8 @@ void multiSlsDetector::initializeDetectorStructure() { multi_shm()->numberOfChannel[Y] = 0; multi_shm()->numberOfChannelInclGapPixels[X] = 0; multi_shm()->numberOfChannelInclGapPixels[Y] = 0; - multi_shm()->maxNumberOfChannelsPerDetector[X] = 0; - multi_shm()->maxNumberOfChannelsPerDetector[Y] = 0; + multi_shm()->maxNumberOfChannelsPerDetector[X] = -1; + multi_shm()->maxNumberOfChannelsPerDetector[Y] = -1; multi_shm()->acquiringFlag = false; multi_shm()->receiver_upstream = false; } @@ -303,9 +303,6 @@ void multiSlsDetector::initializeMembers(bool verify) { throw; } } - - // depend on number of detectors - updateOffsets(); } void multiSlsDetector::updateUserdetails() { @@ -333,197 +330,6 @@ bool multiSlsDetector::isAcquireReady() { return OK != 0u; } -int multiSlsDetector::decodeNChannel(int offsetX, int offsetY, int &channelX, - int &channelY) { - channelX = -1; - channelY = -1; - // loop over - for (size_t i = 0; i < detectors.size(); ++i) { - int x = detectors[i]->getDetectorOffset(X); - int y = detectors[i]->getDetectorOffset(Y); - // check x offset range - if ((offsetX >= x) && - (offsetX < - (x + detectors[i]->getTotalNumberOfChannelsInclGapPixels(X)))) { - if (offsetY == -1) { - channelX = offsetX - x; - return i; - } else { - // check y offset range - if ((offsetY >= y) && - (offsetY < - (y + detectors[i]->getTotalNumberOfChannelsInclGapPixels( - Y)))) { - channelX = offsetX - x; - channelY = offsetY - y; - return i; - } - } - } - } - return -1; -} - -void multiSlsDetector::updateOffsets() { - FILE_LOG(logDEBUG1) << "Updating Multi-Detector Offsets"; - - int offsetX = 0, offsetY = 0, numX = 0, numY = 0; - int maxChanX = multi_shm()->maxNumberOfChannelsPerDetector[X]; - int maxChanY = multi_shm()->maxNumberOfChannelsPerDetector[Y]; - int prevChanX = 0; - int prevChanY = 0; - bool firstTime = true; - - multi_shm()->numberOfChannel[X] = 0; - multi_shm()->numberOfChannel[Y] = 0; - multi_shm()->numberOfDetector[X] = 0; - multi_shm()->numberOfDetector[Y] = 0; - - // gap pixels - int offsetX_gp = 0, offsetY_gp = 0, numX_gp = 0, numY_gp = 0; - int prevChanX_gp = 0, prevChanY_gp = 0; - multi_shm()->numberOfChannelInclGapPixels[X] = 0; - multi_shm()->numberOfChannelInclGapPixels[Y] = 0; - - for (size_t idet = 0; idet < detectors.size(); ++idet) { - FILE_LOG(logDEBUG1) - << "offsetX:" << offsetX << " prevChanX:" << prevChanX - << " offsetY:" << offsetY << " prevChanY:" << prevChanY - << " offsetX_gp:" << offsetX_gp << " prevChanX_gp:" << prevChanX_gp - << " offsetY_gp:" << offsetY_gp << " prevChanY_gp:" << prevChanY_gp; - - // incrementing in both direction - if (firstTime) { - // incrementing in both directions - firstTime = false; - if ((maxChanX > 0) && - ((offsetX + detectors[idet]->getTotalNumberOfChannels(X)) > - maxChanX)) { - FILE_LOG(logWARNING) - << "\nDetector[" << idet - << "] exceeds maximum channels " - "allowed for complete detector set in X dimension!"; - } - if ((maxChanY > 0) && - ((offsetY + detectors[idet]->getTotalNumberOfChannels(Y)) > - maxChanY)) { - FILE_LOG(logERROR) - << "\nDetector[" << idet - << "] exceeds maximum channels " - "allowed for complete detector set in Y dimension!"; - } - prevChanX = detectors[idet]->getTotalNumberOfChannels(X); - prevChanY = detectors[idet]->getTotalNumberOfChannels(Y); - prevChanX_gp = - detectors[idet]->getTotalNumberOfChannelsInclGapPixels(X); - prevChanY_gp = - detectors[idet]->getTotalNumberOfChannelsInclGapPixels(Y); - numX += detectors[idet]->getTotalNumberOfChannels(X); - numY += detectors[idet]->getTotalNumberOfChannels(Y); - numX_gp += - detectors[idet]->getTotalNumberOfChannelsInclGapPixels(X); - numY_gp += - detectors[idet]->getTotalNumberOfChannelsInclGapPixels(Y); - ++multi_shm()->numberOfDetector[X]; - ++multi_shm()->numberOfDetector[Y]; - FILE_LOG(logDEBUG1) << "incrementing in both direction"; - } - - // incrementing in y direction - else if ((maxChanY == -1) || - ((maxChanY > 0) && ((offsetY + prevChanY + - detectors[idet]->getTotalNumberOfChannels( - Y)) <= maxChanY))) { - offsetY += prevChanY; - offsetY_gp += prevChanY_gp; - prevChanY = detectors[idet]->getTotalNumberOfChannels(Y); - prevChanY_gp = - detectors[idet]->getTotalNumberOfChannelsInclGapPixels(Y); - numY += detectors[idet]->getTotalNumberOfChannels(Y); - numY_gp += - detectors[idet]->getTotalNumberOfChannelsInclGapPixels(Y); - // increment in y again only in the first column (else you double - // increment) - if (multi_shm()->numberOfDetector[X] == 1) - ++multi_shm()->numberOfDetector[Y]; - FILE_LOG(logDEBUG1) << "incrementing in y direction"; - } - - // incrementing in x direction - else { - if ((maxChanX > 0) && - ((offsetX + prevChanX + - detectors[idet]->getTotalNumberOfChannels(X)) > maxChanX)) { - FILE_LOG(logDEBUG1) - << "\nDetector[" << idet - << "] exceeds maximum channels " - "allowed for complete detector set in X dimension!"; - } - offsetY = 0; - offsetY_gp = 0; - prevChanY = detectors[idet]->getTotalNumberOfChannels(Y); - prevChanY_gp = - detectors[idet]->getTotalNumberOfChannelsInclGapPixels(Y); - numY = 0; // assuming symmetry with this statement. - // whats on 1st column should be on 2nd column - numY_gp = 0; - offsetX += prevChanX; - offsetX_gp += prevChanX_gp; - prevChanX = detectors[idet]->getTotalNumberOfChannels(X); - prevChanX_gp = - detectors[idet]->getTotalNumberOfChannelsInclGapPixels(X); - numX += detectors[idet]->getTotalNumberOfChannels(X); - numX_gp += - detectors[idet]->getTotalNumberOfChannelsInclGapPixels(X); - ++multi_shm()->numberOfDetector[X]; - FILE_LOG(logDEBUG1) << "incrementing in x direction"; - } - - double bytesperchannel = - (double)detectors[idet]->getDataBytes() / - (double)(detectors[idet]->getTotalNumberOfChannels(X) * - detectors[idet]->getTotalNumberOfChannels(Y)); - detectors[idet]->setDetectorOffset( - X, (bytesperchannel >= 1.0) ? offsetX_gp : offsetX); - detectors[idet]->setDetectorOffset( - Y, (bytesperchannel >= 1.0) ? offsetY_gp : offsetY); - - FILE_LOG(logDEBUG1) << "Detector[" << idet << "] has offsets (" - << detectors[idet]->getDetectorOffset(X) << ", " - << detectors[idet]->getDetectorOffset(Y) << ")"; - // offsetY has been reset sometimes and offsetX the first time, - // but remember the highest values - if (numX > multi_shm()->numberOfChannel[X]) { - multi_shm()->numberOfChannel[X] = numX; - } - if (numY > multi_shm()->numberOfChannel[Y]) { - multi_shm()->numberOfChannel[Y] = numY; - } - if (numX_gp > multi_shm()->numberOfChannelInclGapPixels[X]) { - multi_shm()->numberOfChannelInclGapPixels[X] = numX_gp; - } - if (numY_gp > multi_shm()->numberOfChannelInclGapPixels[Y]) { - multi_shm()->numberOfChannelInclGapPixels[Y] = numY_gp; - } - } - FILE_LOG(logDEBUG1) - << "\n\tNumber of Channels in X direction:" - << multi_shm()->numberOfChannel[X] - << "\n\tNumber of Channels in Y direction:" - << multi_shm()->numberOfChannel[Y] - << "\n\tNumber of Channels in X direction with Gap Pixels:" - << multi_shm()->numberOfChannelInclGapPixels[X] - << "\n\tNumber of Channels in Y direction with Gap Pixels:" - << multi_shm()->numberOfChannelInclGapPixels[Y]; - - multi_shm()->numberOfChannels = - multi_shm()->numberOfChannel[0] * multi_shm()->numberOfChannel[1]; - - for (auto &d : detectors) { - d->updateMultiSize(multi_shm()->numberOfDetector[0], - multi_shm()->numberOfDetector[1]); - } -} std::string multiSlsDetector::exec(const char *cmd) { int bufsize = 128; @@ -560,8 +366,6 @@ void multiSlsDetector::setHostname(const std::vector &name) { for (const auto &hostname : name) { addSlsDetector(hostname); } - - updateOffsets(); } void multiSlsDetector::setHostname(const char *name, int detPos) { @@ -598,8 +402,7 @@ void multiSlsDetector::addMultipleDetectors(const char *name) { for (const auto &hostname : sls::split(name, '+')) { addSlsDetector(hostname); } - - updateOffsets(); + updateDetectorSize(); } void multiSlsDetector::addSlsDetector(const std::string &hostname) { @@ -623,11 +426,63 @@ void multiSlsDetector::addSlsDetector(const std::string &hostname) { sls::make_unique(type, multiId, pos, false)); multi_shm()->numberOfDetectors = detectors.size(); multi_shm()->numberOfChannels += detectors[pos]->getTotalNumberOfChannels(); - detectors[pos]->setHostname(hostname); multi_shm()->multiDetectorType = getDetectorTypeAsEnum(-1);// -1 needed here } +void multiSlsDetector::updateDetectorSize() { + FILE_LOG(logDEBUG) << "Updating Multi-Detector Size: " << size(); + + int my = detectors[0]->getTotalNumberOfChannels(Y); + int mx = detectors[0]->getTotalNumberOfChannels(X); + int mgy = detectors[0]->getTotalNumberOfChannelsInclGapPixels(Y); + int mgx = detectors[0]->getTotalNumberOfChannelsInclGapPixels(X); + if (mgy == 0) { + mgy = my; + mgx = mx; + } + + int maxy = multi_shm()->maxNumberOfChannelsPerDetector[Y]; + if (maxy == -1) { + maxy = my * size(); + } + + int ndety = maxy / my; + int ndetx = size() / ndety; + if ((maxy % my) > 0) { + ++ndetx; + } + + multi_shm()->numberOfDetector[X] = ndetx; + multi_shm()->numberOfDetector[Y] = ndety; + multi_shm()->numberOfChannel[X] = mx * ndetx; + multi_shm()->numberOfChannel[Y] = my * ndety; + multi_shm()->numberOfChannelInclGapPixels[X] = mgx * ndetx; + multi_shm()->numberOfChannelInclGapPixels[Y] = mgy * ndety; + + FILE_LOG(logDEBUG) + << "\n\tNumber of Detectors in X direction:" + << multi_shm()->numberOfDetector[X] + << "\n\tNumber of Detectors in Y direction:" + << multi_shm()->numberOfDetector[Y] + << "\n\tNumber of Channels in X direction:" + << multi_shm()->numberOfChannel[X] + << "\n\tNumber of Channels in Y direction:" + << multi_shm()->numberOfChannel[Y] + << "\n\tNumber of Channels in X direction with Gap Pixels:" + << multi_shm()->numberOfChannelInclGapPixels[X] + << "\n\tNumber of Channels in Y direction with Gap Pixels:" + << multi_shm()->numberOfChannelInclGapPixels[Y]; + + multi_shm()->numberOfChannels = + multi_shm()->numberOfChannel[0] * multi_shm()->numberOfChannel[1]; + + for (auto &d : detectors) { + d->updateMultiSize(multi_shm()->numberOfDetector[0], + multi_shm()->numberOfDetector[1]); + } +} + slsDetectorDefs::detectorType multiSlsDetector::getDetectorTypeAsEnum() const { return multi_shm()->multiDetectorType; } @@ -732,14 +587,6 @@ void multiSlsDetector::setMaxNumberOfChannels(const slsDetectorDefs::coordinates multi_shm()->maxNumberOfChannelsPerDetector[Y] = c.y; } -int multiSlsDetector::getDetectorOffset(dimension d, int detPos) { - return detectors[detPos]->getDetectorOffset(d); -} - -void multiSlsDetector::setDetectorOffset(dimension d, int off, int detPos) { - detectors[detPos]->setDetectorOffset(d, off); -} - int multiSlsDetector::getQuad(int detPos) { int retval = detectors[0]->getQuad(); if (retval && size() > 1) { @@ -1272,8 +1119,6 @@ int multiSlsDetector::setDynamicRange(int dr, int detPos) { // change in dr if (dr != -1 && dr != prevValue) { - updateOffsets(); - // update speed, check ratecorrection if (getDetectorTypeAsEnum() == EIGER) { @@ -2172,318 +2017,40 @@ int multiSlsDetector::setCounterBit(int i, int detPos) { return sls::minusOneIfDifferent(r); } -void multiSlsDetector::verifyMinMaxROI(int n, ROI r[]) { - int temp; - for (int i = 0; i < n; ++i) { - if ((r[i].xmax) < (r[i].xmin)) { - temp = r[i].xmax; - r[i].xmax = r[i].xmin; - r[i].xmin = temp; - } - if ((r[i].ymax) < (r[i].ymin)) { - temp = r[i].ymax; - r[i].ymax = r[i].ymin; - r[i].ymin = temp; - } - } -} - -void multiSlsDetector::setROI(int n, ROI roiLimits[], int detPos) { +void multiSlsDetector::clearROI(int detPos) { // single if (detPos >= 0) { - detectors[detPos]->setROI(n, roiLimits); + detectors[detPos]->clearROI(); } // multi - int xmin = 0, xmax = 0, ymin = 0, ymax = 0, channelX = 0, channelY = 0, - idet = 0, lastChannelX = 0, lastChannelY = 0, index = 0, offsetX = 0, - offsetY = 0; - - bool invalidroi = false; - int ndet = detectors.size(); - ROI allroi[ndet][n]; - int nroi[ndet]; - for (int i = 0; i < ndet; ++i) { - nroi[i] = 0; - } - - if ((n < 0) || (roiLimits == nullptr)) { - throw RuntimeError("Cannot set ROI due to Invalid ROI"); - } - - // ensures min < max - verifyMinMaxROI(n, roiLimits); - FILE_LOG(logDEBUG1) << "Setting ROI for " << n << "rois:"; - for (int i = 0; i < n; ++i) { - FILE_LOG(logDEBUG1) - << i << ":" << roiLimits[i].xmin << "\t" << roiLimits[i].xmax - << "\t" << roiLimits[i].ymin << "\t" << roiLimits[i].ymax; - } - // for each roi - for (int i = 0; i < n; ++i) { - xmin = roiLimits[i].xmin; - xmax = roiLimits[i].xmax; - ymin = roiLimits[i].ymin; - ymax = roiLimits[i].ymax; - - if (size() > 1) { - // check roi max values - idet = decodeNChannel(xmax, ymax, channelX, channelY); - FILE_LOG(logDEBUG1) << "Decoded Channel max vals: " << std::endl - << "det:" << idet << "\t" << xmax << "\t" - << ymax << "\t" << channelX << "\t" << channelY; - if (idet == -1) { - FILE_LOG(logERROR) << "invalid roi"; - continue; - } - - // split in x dir - while (xmin <= xmax) { - invalidroi = false; - ymin = roiLimits[i].ymin; - // split in y dir - while (ymin <= ymax) { - // get offset for each detector - idet = decodeNChannel(xmin, ymin, channelX, channelY); - FILE_LOG(logDEBUG1) - << "Decoded Channel min vals: " << std::endl - << "det:" << idet << "\t" << xmin << "\t" << ymin - << "\t" << channelX << "\t" << channelY; - if (idet < 0 || idet >= (int)detectors.size()) { - FILE_LOG(logDEBUG1) << "invalid roi"; - invalidroi = true; - break; - } - // get last channel for each det in x and y dir - lastChannelX = - (detectors[idet]->getTotalNumberOfChannelsInclGapPixels( - X)) - - 1; - lastChannelY = - (detectors[idet]->getTotalNumberOfChannelsInclGapPixels( - Y)) - - 1; - - offsetX = detectors[idet]->getDetectorOffset(X); - offsetY = detectors[idet]->getDetectorOffset(Y); - // at the end in x dir - if ((offsetX + lastChannelX) >= xmax) { - lastChannelX = xmax - offsetX; - } - // at the end in y dir - if ((offsetY + lastChannelY) >= ymax) { - lastChannelY = ymax - offsetY; - } - - FILE_LOG(logDEBUG1) - << "lastChannelX:" << lastChannelX << "\t" - << "lastChannelY:" << lastChannelY; - - // creating the list of roi for corresponding detector - index = nroi[idet]; - allroi[idet][index].xmin = channelX; - allroi[idet][index].xmax = lastChannelX; - allroi[idet][index].ymin = channelY; - allroi[idet][index].ymax = lastChannelY; - nroi[idet] = nroi[idet] + 1; - - ymin = lastChannelY + offsetY + 1; - if ((lastChannelY + offsetY) == ymax) { - ymin = ymax + 1; - } - - FILE_LOG(logDEBUG1) - << "nroi[idet]:" << nroi[idet] << "\tymin:" << ymin; - } - if (invalidroi) { - break; - } - - xmin = lastChannelX + offsetX + 1; - if ((lastChannelX + offsetX) == xmax) { - xmin = xmax + 1; - } - } - } else { // FIXME: check if xmax is greater? or reduce logic above? - idet = 0; - nroi[idet] = n; - index = 0; - allroi[idet][index].xmin = xmin; - allroi[idet][index].xmax = xmax; - allroi[idet][index].ymin = ymin; - allroi[idet][index].ymax = ymax; - // nroi[idet] = nroi[idet] + 1; - } - } - - FILE_LOG(logDEBUG1) << "Setting ROI :"; - for (size_t i = 0; i < detectors.size(); ++i) { - FILE_LOG(logDEBUG1) << "detector " << i; - for (int j = 0; j < nroi[i]; ++j) { - FILE_LOG(logDEBUG1) - << allroi[i][j].xmin << "\t" << allroi[i][j].xmax << "\t" - << allroi[i][j].ymin << "\t" << allroi[i][j].ymax; - } - } - - // settings the rois for each detector - for (size_t i = 0; i != detectors.size(); ++i) { - detectors[i]->setROI(nroi[i], allroi[i]); - } + parallelCall(&slsDetector::clearROI); } -const slsDetectorDefs::ROI *multiSlsDetector::getROI(int &n, int detPos) { +void multiSlsDetector::setROI(slsDetectorDefs::ROI arg, int detPos) { // single if (detPos >= 0) { - return detectors[detPos]->getROI(n); + detectors[detPos]->setROI(arg); } // multi - n = 0; - int num = 0; - int ndet = detectors.size(); - int maxroi = ndet * MAX_ROIS; - ROI temproi; - ROI roiLimits[maxroi]; - ROI *retval = new ROI[maxroi]; - const ROI *temp = nullptr; - int index = 0; + if (detPos < 0 && size() > 1) { + throw RuntimeError("Cannot set ROI for all modules simultaneously"); + } + detectors[0]->setROI(arg); +} - // get each detector's roi array - for (size_t idet = 0; idet < detectors.size(); ++idet) { - temp = detectors[idet]->getROI(index); - if (temp != nullptr) { - if (index != 0) { - FILE_LOG(logINFO) << "detector " << idet << ":"; - } - for (int j = 0; j < index; ++j) { - FILE_LOG(logINFO) - << temp[j].xmin << "\t" << temp[j].xmax << "\t" - << temp[j].ymin << "\t" << temp[j].ymax; - int x = detectors[idet]->getDetectorOffset(X); - int y = detectors[idet]->getDetectorOffset(Y); - roiLimits[n].xmin = temp[j].xmin + x; - roiLimits[n].xmax = temp[j].xmax + x; - roiLimits[n].ymin = temp[j].ymin + y; - roiLimits[n].ymax = temp[j].ymin + y; - ++n; - } - } +slsDetectorDefs::ROI multiSlsDetector::getROI(int detPos) const { + // single + if (detPos >= 0) { + return detectors[detPos]->getROI(); } - // empty roi - if (n == 0) { - return nullptr; + // multi + if (detPos < 0 && size() > 1) { + throw RuntimeError("Cannot get ROI for all modules simultaneously"); } - - FILE_LOG(logDEBUG1) << "ROI :" << std::endl; - for (int j = 0; j < n; ++j) { - FILE_LOG(logDEBUG1) - << roiLimits[j].xmin << "\t" << roiLimits[j].xmax << "\t" - << roiLimits[j].ymin << "\t" << roiLimits[j].ymax; - } - - // combine all the adjacent rois in x direction - for (int i = 0; i < n; ++i) { - // since the ones combined are replaced by -1 - if ((roiLimits[i].xmin) == -1) { - continue; - } - for (int j = i + 1; j < n; ++j) { - // since the ones combined are replaced by -1 - if ((roiLimits[j].xmin) == -1) { - continue; - } - // if y values are same - if (((roiLimits[i].ymin) == (roiLimits[j].ymin)) && - ((roiLimits[i].ymax) == (roiLimits[j].ymax))) { - // if adjacent, increase [i] range and replace all [j] with -1 - if ((roiLimits[i].xmax) + 1 == roiLimits[j].xmin) { - roiLimits[i].xmax = roiLimits[j].xmax; - roiLimits[j].xmin = -1; - roiLimits[j].xmax = -1; - roiLimits[j].ymin = -1; - roiLimits[j].ymax = -1; - } - // if adjacent, increase [i] range and replace all [j] with -1 - else if ((roiLimits[i].xmin) - 1 == roiLimits[j].xmax) { - roiLimits[i].xmin = roiLimits[j].xmin; - roiLimits[j].xmin = -1; - roiLimits[j].xmax = -1; - roiLimits[j].ymin = -1; - roiLimits[j].ymax = -1; - } - } - } - } - - FILE_LOG(logDEBUG1) << "Combined along x axis Getting ROI :\ndetector " - << n; - for (int j = 0; j < n; ++j) { - FILE_LOG(logDEBUG1) - << roiLimits[j].xmin << "\t" << roiLimits[j].xmax << "\t" - << roiLimits[j].ymin << "\t" << roiLimits[j].ymax; - } - - // combine all the adjacent rois in y direction - for (int i = 0; i < n; ++i) { - // since the ones combined are replaced by -1 - if ((roiLimits[i].ymin) == -1) { - continue; - } - for (int j = i + 1; j < n; ++j) { - // since the ones combined are replaced by -1 - if ((roiLimits[j].ymin) == -1) { - continue; - } - // if x values are same - if (((roiLimits[i].xmin) == (roiLimits[j].xmin)) && - ((roiLimits[i].xmax) == (roiLimits[j].xmax))) { - // if adjacent, increase [i] range and replace all [j] with -1 - if ((roiLimits[i].ymax) + 1 == roiLimits[j].ymin) { - roiLimits[i].ymax = roiLimits[j].ymax; - roiLimits[j].xmin = -1; - roiLimits[j].xmax = -1; - roiLimits[j].ymin = -1; - roiLimits[j].ymax = -1; - } - // if adjacent, increase [i] range and replace all [j] with -1 - else if ((roiLimits[i].ymin) - 1 == roiLimits[j].ymax) { - roiLimits[i].ymin = roiLimits[j].ymin; - roiLimits[j].xmin = -1; - roiLimits[j].xmax = -1; - roiLimits[j].ymin = -1; - roiLimits[j].ymax = -1; - } - } - } - } - - // get rid of -1s - for (int i = 0; i < n; ++i) { - if ((roiLimits[i].xmin) != -1) { - retval[num] = roiLimits[i]; - ++num; - } - } - // sort final roi - for (int i = 0; i < num; ++i) { - for (int j = i + 1; j < num; ++j) { - if (retval[j].xmin < retval[i].xmin) { - temproi = retval[i]; - retval[i] = retval[j]; - retval[j] = temproi; - } - } - } - n = num; - - FILE_LOG(logDEBUG1) << "\nxmin\txmax\tymin\tymax"; - for (int i = 0; i < n; ++i) { - FILE_LOG(logDEBUG1) << retval[i].xmin << "\t" << retval[i].xmax << "\t" - << retval[i].ymin << "\t" << retval[i].ymax; - } - return retval; + return detectors[0]->getROI(); } void multiSlsDetector::setADCEnableMask(uint32_t mask, int detPos) { @@ -2688,15 +2255,16 @@ int multiSlsDetector::enableGapPixels(int val, int detPos) { int ret = sls::minusOneIfDifferent(r); if (val != -1) { - updateOffsets(); + multi_shm()->numberOfChannelInclGapPixels[X] = sls::sum(parallelCall(&slsDetector::getTotalNumberOfChannelsInclGapPixels, X)); + multi_shm()->numberOfChannelInclGapPixels[Y] = sls::sum(parallelCall(&slsDetector::getTotalNumberOfChannelsInclGapPixels, Y)); } return ret; } void multiSlsDetector::setGapPixelsEnable(bool enable, Positions pos){ Parallel(&slsDetector::enableGapPixels, pos, static_cast(enable)); - - updateOffsets(); + multi_shm()->numberOfChannelInclGapPixels[X] = sls::sum(parallelCall(&slsDetector::getTotalNumberOfChannelsInclGapPixels, X)); + multi_shm()->numberOfChannelInclGapPixels[Y] = sls::sum(parallelCall(&slsDetector::getTotalNumberOfChannelsInclGapPixels, Y)); } int multiSlsDetector::setTrimEn(std::vector energies, int detPos) { diff --git a/slsDetectorSoftware/src/slsDetector.cpp b/slsDetectorSoftware/src/slsDetector.cpp index a8e373ad9..c2fc2416f 100755 --- a/slsDetectorSoftware/src/slsDetector.cpp +++ b/slsDetectorSoftware/src/slsDetector.cpp @@ -308,15 +308,13 @@ void slsDetector::initializeDetectorStructure(detectorType type) { shm()->controlPort = DEFAULT_PORTNO; sls::strcpy_safe(shm()->hostname, DEFAULT_HOSTNAME); shm()->myDetectorType = type; - shm()->offset[X] = 0; - shm()->offset[Y] = 0; shm()->multiSize[X] = 0; shm()->multiSize[Y] = 0; - + shm()->controlPort = DEFAULT_PORTNO; shm()->stopPort = DEFAULT_PORTNO + 1; sls::strcpy_safe(shm()->settingsDir, getenv("HOME")); - shm()->nROI = 0; - memset(shm()->roiLimits, 0, MAX_ROIS * sizeof(ROI)); + shm()->roi.xmin = -1; + shm()->roi.xmax = -1; shm()->adcEnableMask = BIT32_MASK; shm()->roFlags = NORMAL_READOUT; shm()->currentSettings = UNINITIALIZED; @@ -688,28 +686,6 @@ int slsDetector::getReadNLines() { return retval; } -int slsDetector::getDetectorOffset(dimension d) const { - return shm()->offset[d]; -} - -slsDetectorDefs::coordinates slsDetector::getDetectorOffsets() const { - slsDetectorDefs::coordinates coord; - coord.x = shm()->offset[X]; - coord.y = shm()->offset[Y]; - return coord; -} - -void slsDetector::setDetectorOffset(dimension d, int off) { - if (off >= 0) { - shm()->offset[d] = off; - } -} - -void slsDetector::setDetectorOffsets(slsDetectorDefs::coordinates value) { - shm()->offset[X] = value.x; - shm()->offset[Y] = value.y; -} - void slsDetector::updateMultiSize(int detx, int dety) { shm()->multiSize[0] = detx; shm()->multiSize[1] = dety; @@ -878,17 +854,9 @@ void slsDetector::updateCachedDetectorVariables() { // roi if (shm()->myDetectorType == GOTTHARD) { n += client.Receive(&i32, sizeof(i32)); - shm()->nROI = i32; - for (int i = 0; i < shm()->nROI; ++i) { - n += client.Receive(&i32, sizeof(i32)); - shm()->roiLimits[i].xmin = i32; - n += client.Receive(&i32, sizeof(i32)); - shm()->roiLimits[i].xmax = i32; - n += client.Receive(&i32, sizeof(i32)); - shm()->roiLimits[i].ymin = i32; - n += client.Receive(&i32, sizeof(i32)); - shm()->roiLimits[i].xmax = i32; - } + shm()->roi.xmin = i32; + n += client.Receive(&i32, sizeof(i32)); + shm()->roi.xmax = i32; } if (shm()->myDetectorType == CHIPTESTBOARD || @@ -1849,7 +1817,7 @@ std::string slsDetector::setReceiverHostname(const std::string &receiverIP) { break; case GOTTHARD: - sendROI(-1, nullptr); + sendROItoReceiver(); break; default: @@ -2344,44 +2312,27 @@ int slsDetector::setCounterBit(int cb) { return retval; } -void slsDetector::setROI(int n, ROI roiLimits[]) { - std::sort(roiLimits, roiLimits + n, - [](ROI a, ROI b) { return a.xmin < b.xmin; }); - - sendROI(n, roiLimits); +void slsDetector::clearROI() { + FILE_LOG(logDEBUG1) << "Clearing ROI"; + slsDetectorDefs::ROI arg; + arg.xmin = -1; + arg.xmax = -1; + setROI(arg); } -const slsDetectorDefs::ROI *slsDetector::getROI(int &n) { - sendROI(-1, nullptr); - n = shm()->nROI; - return shm()->roiLimits; -} - -int slsDetector::getNRoi() { return shm()->nROI; } - -void slsDetector::sendROI(int n, ROI roiLimits[]) { +void slsDetector::setROI(slsDetectorDefs::ROI arg) { int fnum = F_SET_ROI; int ret = FAIL; - int narg = n; - // send roiLimits if given, else from shm - ROI *arg = (roiLimits != nullptr) ? roiLimits : shm()->roiLimits; - int nretval = 0; - ROI retval[MAX_ROIS]; - FILE_LOG(logDEBUG1) << "Sending ROI to detector" << narg; - + if (arg.xmin < 0 || arg.xmax >= getTotalNumberOfChannels()) { + arg.xmin = -1; + arg.xmax = -1; + } + FILE_LOG(logDEBUG) << "Sending ROI to detector [" << arg.xmin << ", " << arg.xmax << "]"; auto client = DetectorSocket(shm()->hostname, shm()->controlPort); client.Send(&fnum, sizeof(fnum)); - client.Send(&narg, sizeof(narg)); - if (narg != -1) { - for (int i = 0; i < narg; ++i) { - client.Send(&arg[i].xmin, sizeof(int)); - client.Send(&arg[i].xmax, sizeof(int)); - client.Send(&arg[i].ymin, sizeof(int)); - client.Send(&arg[i].ymax, sizeof(int)); - } - } + client.Send(&arg.xmin, sizeof(int)); + client.Send(&arg.xmax, sizeof(int)); client.Receive(&ret, sizeof(ret)); - // handle ret if (ret == FAIL) { char mess[MAX_STR_LENGTH]{}; @@ -2389,65 +2340,63 @@ void slsDetector::sendROI(int n, ROI roiLimits[]) { throw RuntimeError("Detector " + std::to_string(detId) + " returned error: " + std::string(mess)); } else { - client.Receive(&nretval, sizeof(nretval)); - int nrec = 0; - for (int i = 0; i < nretval; ++i) { - nrec += client.Receive(&retval[i].xmin, sizeof(int)); - nrec += client.Receive(&retval[i].xmax, sizeof(int)); - nrec += client.Receive(&retval[i].ymin, sizeof(int)); - nrec += client.Receive(&retval[i].ymax, sizeof(int)); - } - shm()->nROI = nretval; - FILE_LOG(logDEBUG1) << "nRoi: " << nretval; - for (int i = 0; i < nretval; ++i) { - shm()->roiLimits[i] = retval[i]; - FILE_LOG(logDEBUG1) - << "ROI [" << i << "] (" << shm()->roiLimits[i].xmin << "," - << shm()->roiLimits[i].xmax << "," << shm()->roiLimits[i].ymin - << "," << shm()->roiLimits[i].ymax << ")"; + memcpy(&shm()->roi, &arg, sizeof(ROI)); + if (ret == FORCE_UPDATE) { + updateCachedDetectorVariables(); } } - if (ret == FORCE_UPDATE) { - updateCachedDetectorVariables(); - } + // old firmware requires configuremac after setting roi - if (shm()->myDetectorType == GOTTHARD && n != -1) { + if (shm()->myDetectorType == GOTTHARD) { configureMAC(); } + sendROItoReceiver(); +} + +void slsDetector::sendROItoReceiver() { // update roi in receiver if (shm()->useReceiverFlag) { - fnum = F_RECEIVER_SET_ROI; - ret = FAIL; - narg = shm()->nROI; - arg = shm()->roiLimits; - FILE_LOG(logDEBUG1) << "Sending ROI to receiver: " << shm()->nROI; - - auto receiver = ReceiverSocket(shm()->rxHostname, shm()->rxTCPPort); - receiver.Send(&fnum, sizeof(fnum)); - receiver.Send(&narg, sizeof(narg)); - if (narg != -1) { - for (int i = 0; i < narg; ++i) { - receiver.Send(&arg[i].xmin, sizeof(int)); - receiver.Send(&arg[i].xmax, sizeof(int)); - receiver.Send(&arg[i].ymin, sizeof(int)); - receiver.Send(&arg[i].ymax, sizeof(int)); - } - } - receiver.Receive(&ret, sizeof(ret)); - - if (ret == FAIL) { - char mess[MAX_STR_LENGTH]{}; - receiver.Receive(mess, MAX_STR_LENGTH); - throw ReceiverError("Receiver " + std::to_string(detId) + - " returned error: " + std::string(mess)); - } - if (ret == FORCE_UPDATE) { - updateCachedReceiverVariables(); - } + FILE_LOG(logDEBUG1) << "Sending ROI to receiver"; + sendToReceiver(F_RECEIVER_SET_ROI, shm()->roi, nullptr); } } +slsDetectorDefs::ROI slsDetector::getROI() { + int fnum = F_GET_ROI; + int ret = FAIL; + FILE_LOG(logDEBUG1) << "Getting ROI from detector"; + auto client = DetectorSocket(shm()->hostname, shm()->controlPort); + client.Send(&fnum, sizeof(fnum)); + client.Receive(&ret, sizeof(ret)); + // handle ret + if (ret == FAIL) { + char mess[MAX_STR_LENGTH]{}; + client.Receive(mess, MAX_STR_LENGTH); + throw RuntimeError("Detector " + std::to_string(detId) + + " returned error: " + std::string(mess)); + } else { + ROI retval; + client.Receive(&retval.xmin, sizeof(int)); + client.Receive(&retval.xmax, sizeof(int)); + FILE_LOG(logDEBUG1) + << "ROI retval [" << retval.xmin << "," + << retval.xmax << "]"; + if (ret == FORCE_UPDATE) { + updateCachedDetectorVariables(); + } + // if different from shm, update and send to receiver + if (shm()->roi.xmin != retval.xmin || shm()->roi.xmax != retval.xmax) { + memcpy(&shm()->roi, &retval, sizeof(ROI)); + sendROItoReceiver(); + } + } + + return shm()->roi; +} + + + void slsDetector::setADCEnableMask(uint32_t mask) { uint32_t arg = mask; FILE_LOG(logDEBUG1) << "Setting ADC Enable mask to 0x" << std::hex << arg diff --git a/slsDetectorSoftware/src/slsDetectorCommand.cpp b/slsDetectorSoftware/src/slsDetectorCommand.cpp index 3989a1d3a..3c3a7c36a 100755 --- a/slsDetectorSoftware/src/slsDetectorCommand.cpp +++ b/slsDetectorSoftware/src/slsDetectorCommand.cpp @@ -308,7 +308,14 @@ slsDetectorCommand::slsDetectorCommand(multiSlsDetector *det) { ++i; /*! \page config - - roi [i] [xmin] [xmax] [ymin] [ymax] sets region of interest of the detector, where i is number of rois;i=0 to clear rois. Used for GOTTHARD only. \c Returns \c (int) + - 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; @@ -3252,28 +3259,28 @@ std::string slsDetectorCommand::cmdDetectorSize(int narg, const char * const arg if (action == HELP_ACTION) return helpDetectorSize(action); - int ret, val = -1, pos = -1, i; + int ret, val = -1; char ans[1000]; if (action == PUT_ACTION) { - if (!sscanf(args[1], "%d", &val)) + 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 ((val < 0) || (narg != ((val * 4) + 2))) + if (narg != 3) return helpDetectorSize(action); - ROI allroi[val]; - pos = 2; - for (i = 0; i < val; ++i) { - if ((!sscanf(args[pos++], "%d", &allroi[i].xmin)) || - (!sscanf(args[pos++], "%d", &allroi[i].xmax)) || - (!sscanf(args[pos++], "%d", &allroi[i].ymin)) || - (!sscanf(args[pos++], "%d", &allroi[i].ymax))) - return std::string("cannot parse arguments for roi"); - } - myDet->setROI(val, allroi, detPos); + 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") { @@ -3308,17 +3315,21 @@ std::string slsDetectorCommand::cmdDetectorSize(int narg, const char * const arg 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 offsets etc. + 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") { - const ROI* r = myDet->getROI(ret, detPos); - - delete [] r; + 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") { sprintf(ans, "%d %d", myDet->getMaxNumberOfChannelsPerDetector(X), myDet->getMaxNumberOfChannelsPerDetector(Y)); return std::string(ans); @@ -3330,7 +3341,7 @@ std::string slsDetectorCommand::cmdDetectorSize(int narg, const char * const arg return std::string("Not required for this detector\n"); ret = myDet->getFlippedData(Y, detPos); } else if (cmd == "gappixels") { - if (detPos >= 0) // only in multi detector level to update offsets etc. + 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); } @@ -3349,7 +3360,8 @@ 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 << "roi i xmin xmax ymin ymax \n sets region of interest where i is number of rois;i=0 to clear rois" << 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; -1 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; diff --git a/slsDetectorSoftware/src/slsDetectorUsers.cpp b/slsDetectorSoftware/src/slsDetectorUsers.cpp index f4b83b178..8e89ca408 100755 --- a/slsDetectorSoftware/src/slsDetectorUsers.cpp +++ b/slsDetectorSoftware/src/slsDetectorUsers.cpp @@ -14,14 +14,7 @@ int slsDetectorUsers::getMaximumDetectorSize(int &nx, int &ny){ return nx*ny; } -int slsDetectorUsers::getDetectorSize(int &x, int &y, int &nx, int &ny, int detPos){ - if (detPos < 0) { - x = 0; - y = 0; - } else { - x = detector.getDetectorOffset(slsDetectorDefs::X, detPos); - y = detector.getDetectorOffset(slsDetectorDefs::Y, detPos); - } +int slsDetectorUsers::getDetectorSize(int &nx, int &ny, int detPos){ nx=detector.getTotalNumberOfChannels(slsDetectorDefs::X, detPos); ny=detector.getTotalNumberOfChannels(slsDetectorDefs::Y, detPos); return nx*ny; @@ -226,12 +219,12 @@ int slsDetectorUsers::setFlowControl10G(int i, int detPos) { return detector.setFlowControl10G(i, detPos); } -void slsDetectorUsers::setROI(int n, slsDetectorDefs::ROI roiLimits[], int detPos) { - detector.setROI(n, roiLimits, detPos); +void slsDetectorUsers::setROI(slsDetectorDefs::ROI arg, int detPos) { + detector.setROI(arg, detPos); } -const slsDetectorDefs::ROI* slsDetectorUsers::getROI(int &n, int detPos) { - return detector.getROI(n, detPos); +slsDetectorDefs::ROI slsDetectorUsers::getROI(int detPos) { + return detector.getROI(detPos); } /************************************************************************ diff --git a/slsReceiverSoftware/include/DataStreamer.h b/slsReceiverSoftware/include/DataStreamer.h index b3e62d48d..152d006c0 100755 --- a/slsReceiverSoftware/include/DataStreamer.h +++ b/slsReceiverSoftware/include/DataStreamer.h @@ -32,7 +32,7 @@ class DataStreamer : private virtual slsDetectorDefs, public ThreadObject { * @param nd pointer to number of detectors in each dimension * @param gpEnable pointer to gap pixels enable */ - DataStreamer(int ind, Fifo* f, uint32_t* dr, std::vector* r, + DataStreamer(int ind, Fifo* f, uint32_t* dr, ROI* r, uint64_t* fi, int fd, char* ajh, int* nd, bool* gpEnable); /** @@ -188,7 +188,7 @@ class DataStreamer : private virtual slsDetectorDefs, public ThreadObject { uint32_t* dynamicRange; /** ROI */ - std::vector* roi; + ROI* roi; /** adc Configured */ int adcConfigured; diff --git a/slsReceiverSoftware/include/GeneralData.h b/slsReceiverSoftware/include/GeneralData.h index 87ad410d0..99beeeddd 100755 --- a/slsReceiverSoftware/include/GeneralData.h +++ b/slsReceiverSoftware/include/GeneralData.h @@ -142,17 +142,17 @@ public: * Set ROI * @param i ROI */ - virtual void SetROI(std::vector i) { + virtual void SetROI(slsDetectorDefs::ROI i) { FILE_LOG(logERROR) << "SetROI is a generic function that should be overloaded by a derived class"; }; /** * Get Adc configured * @param index thread index for debugging purposes - * @param i pointer to a vector of ROI pointers + * @param ROI * @returns adc configured */ - virtual int GetAdcConfigured(int index, std::vector* i) const{ + virtual int GetAdcConfigured(int index, slsDetectorDefs::ROI i) const{ FILE_LOG(logERROR) << "GetAdcConfigured is a generic function that should be overloaded by a derived class"; return 0; }; @@ -311,9 +311,9 @@ private: * Set ROI * @param i ROI */ - void SetROI(std::vector i) { + void SetROI(slsDetectorDefs::ROI i) { // all adcs - if(!i.size()) { + if(i.xmin == -1) { nPixelsX = 1280; dataSize = 1280; packetSize = GOTTHARD_PACKET_SIZE; @@ -352,28 +352,21 @@ private: /** * Get Adc configured * @param index thread index for debugging purposes - * @param i pointer to a vector of ROI + * @param i ROI * @returns adc configured */ - int GetAdcConfigured(int index, std::vector* i) const{ + int GetAdcConfigured(int index, slsDetectorDefs::ROI i) const{ int adc = -1; // single adc - if(i->size()) { + if(i.xmin != -1) { // gotthard can have only one adc per detector enabled (or all) - // so just looking at the first roi is enough (more not possible at the moment) - - //if its for 1 adc or general - if ((i->at(0).xmin == 0) && (i->at(0).xmax == nChip * nChan)) + //adc = mid value/numchans also for only 1 roi + adc = ((((i.xmax) + (i.xmin))/2)/ + (nChan * nChipsPerAdc)); + if((adc < 0) || (adc > 4)) { + FILE_LOG(logWARNING) << index << ": Deleting ROI. " + "Adc value should be between 0 and 4"; adc = -1; - else { - //adc = mid value/numchans also for only 1 roi - adc = ((((i->at(0).xmax) + (i->at(0).xmin))/2)/ - (nChan * nChipsPerAdc)); - if((adc < 0) || (adc > 4)) { - FILE_LOG(logWARNING) << index << ": Deleting ROI. " - "Adc value should be between 0 and 4"; - adc = -1; - } } } FILE_LOG(logINFO) << "Adc Configured: " << adc; diff --git a/slsReceiverSoftware/include/slsReceiverImplementation.h b/slsReceiverSoftware/include/slsReceiverImplementation.h index aacab85cb..f579bc94d 100755 --- a/slsReceiverSoftware/include/slsReceiverImplementation.h +++ b/slsReceiverSoftware/include/slsReceiverImplementation.h @@ -207,9 +207,9 @@ class slsReceiverImplementation : private virtual slsDetectorDefs { //***acquisition parameters*** /** * Get ROI - * @return index of adc enabled, else -1 if all enabled + * @return roi */ - std::vector getROI() const; + ROI getROI() const; /** * Get ADC Enable Mask @@ -529,10 +529,10 @@ class slsReceiverImplementation : private virtual slsDetectorDefs { //***acquisition parameters*** /** * Set ROI - * @param i ROI + * @param arg ROI * @return OK or FAIL */ - int setROI(const std::vector new_roi); + int setROI(ROI arg); /** * Set ADC Enable Mask @@ -961,7 +961,7 @@ class slsReceiverImplementation : private virtual slsDetectorDefs { //***acquisition parameters*** /* ROI */ - std::vector roi; + ROI roi; /** ADC Enable Mask */ uint32_t adcEnableMask; /** streaming frequency */ diff --git a/slsReceiverSoftware/src/DataStreamer.cpp b/slsReceiverSoftware/src/DataStreamer.cpp index c11d383df..3d5db32b9 100755 --- a/slsReceiverSoftware/src/DataStreamer.cpp +++ b/slsReceiverSoftware/src/DataStreamer.cpp @@ -16,7 +16,7 @@ const std::string DataStreamer::TypeName = "DataStreamer"; -DataStreamer::DataStreamer(int ind, Fifo* f, uint32_t* dr, std::vector* r, +DataStreamer::DataStreamer(int ind, Fifo* f, uint32_t* dr, ROI* r, uint64_t* fi, int fd, char* ajh, int* nd, bool* gpEnable) : ThreadObject(ind), runningFlag(0), @@ -93,9 +93,9 @@ void DataStreamer::ResetParametersforNewMeasurement(const std::string& fname){ delete[] completeBuffer; completeBuffer = nullptr; } - if (roi->size()) { + if (roi->xmin != -1) { if (generalData->myDetectorType == GOTTHARD) { - adcConfigured = generalData->GetAdcConfigured(index, roi); + adcConfigured = generalData->GetAdcConfigured(index, *roi); } completeBuffer = new char[generalData->imageSizeComplete]; memset(completeBuffer, 0, generalData->imageSizeComplete); diff --git a/slsReceiverSoftware/src/slsReceiverImplementation.cpp b/slsReceiverSoftware/src/slsReceiverImplementation.cpp index 1634f8c83..28b3f100e 100755 --- a/slsReceiverSoftware/src/slsReceiverImplementation.cpp +++ b/slsReceiverSoftware/src/slsReceiverImplementation.cpp @@ -104,7 +104,8 @@ void slsReceiverImplementation::InitializeMembers() { overwriteEnable = true; //***acquisition parameters*** - roi.clear(); + roi.xmin = -1; + roi.xmax = -1; adcEnableMask = BIT32_MASK; streamingFrequency = 0; streamingTimerInMs = DEFAULT_STREAMING_TIMER_IN_MS; @@ -305,7 +306,7 @@ int slsReceiverImplementation::getNumberofUDPInterfaces() const { } /***acquisition parameters***/ -std::vector slsReceiverImplementation::getROI() const { +slsDetectorDefs::ROI slsReceiverImplementation::getROI() const { FILE_LOG(logDEBUG3) << __SHORT_AT__ << " called"; return roi; } @@ -858,51 +859,21 @@ int slsReceiverImplementation::setUDPSocketBufferSize(const int64_t s) { } /***acquisition parameters***/ -int slsReceiverImplementation::setROI( - const std::vector new_roi) { - bool change = false; - if (roi.size() != new_roi.size()) - change = true; - else { - for (size_t i = 0; i != new_roi.size(); ++i) { - if ((roi[i].xmin != new_roi[i].xmin) || - (roi[i].xmax != new_roi[i].xmax) || - (roi[i].ymin != new_roi[i].ymin) || - (roi[i].xmax != new_roi[i].xmax)) { - change = true; - break; - } - } - } +int slsReceiverImplementation::setROI(slsDetectorDefs::ROI arg) { + if (roi.xmin != arg.xmin || roi.xmax != arg.xmax) { + roi.xmin = arg.xmin; + roi.xmax = arg.xmax; - if (change) { - roi = new_roi; - switch (myDetectorType) { - case GOTTHARD: - generalData->SetROI(new_roi); - framesPerFile = generalData->maxFramesPerFile; - break; - default: - break; - } + // only for gotthard + generalData->SetROI(arg); + framesPerFile = generalData->maxFramesPerFile; for (const auto &it : dataProcessor) it->SetPixelDimension(); if (SetupFifoStructure() == FAIL) return FAIL; } - std::stringstream sstm; - sstm << "ROI: "; - if (!roi.size()) - sstm << "0"; - else { - for (size_t i = 0; i < roi.size(); ++i) { - sstm << "( " << roi[i].xmin << ", " << roi[i].xmax << ", " - << roi[i].ymin << ", " << roi[i].ymax << " )"; - } - } - std::string message = sstm.str(); - FILE_LOG(logINFO) << message; + FILE_LOG(logINFO) << "ROI: [" << roi.xmin << ", " << roi.xmax << "]";; FILE_LOG(logINFO) << "Packets per Frame: " << (generalData->packetsPerFrame); return OK; diff --git a/slsReceiverSoftware/src/slsReceiverTCPIPInterface.cpp b/slsReceiverSoftware/src/slsReceiverTCPIPInterface.cpp index ba99be5ae..7aacb2eb8 100755 --- a/slsReceiverSoftware/src/slsReceiverTCPIPInterface.cpp +++ b/slsReceiverSoftware/src/slsReceiverTCPIPInterface.cpp @@ -510,22 +510,12 @@ int slsReceiverTCPIPInterface::set_detector_hostname(Interface &socket) { } int slsReceiverTCPIPInterface::set_roi(Interface &socket) { - static_assert(sizeof(ROI) == 4 * sizeof(int), "ROI not packed"); - auto narg = socket.Receive(); - std::vector arg; - for (int iloop = 0; iloop < narg; ++iloop) { - ROI temp{}; - socket.Receive(temp); - arg.push_back(temp); - } - FILE_LOG(logDEBUG1) << "Set ROI narg: " << narg; - for (int iloop = 0; iloop < narg; ++iloop) { - FILE_LOG(logDEBUG1) - << "(" << arg[iloop].xmin << ", " << arg[iloop].xmax << ", " - << arg[iloop].ymin << ", " << arg[iloop].ymax << ")"; - } + static_assert(sizeof(ROI) == 2 * sizeof(int), "ROI not packed"); + ROI arg; + socket.Receive(arg); + FILE_LOG(logDEBUG1) << "Set ROI: [" << arg.xmin << ", " << arg.xmax << "]"; - if (myDetectorType == EIGER || myDetectorType == JUNGFRAU) + if (myDetectorType != GOTTHARD) functionNotImplemented(); VerifyIdle(socket); diff --git a/slsSupportLib/include/sls_detector_defs.h b/slsSupportLib/include/sls_detector_defs.h index e224a319f..816836d9e 100755 --- a/slsSupportLib/include/sls_detector_defs.h +++ b/slsSupportLib/include/sls_detector_defs.h @@ -220,12 +220,18 @@ format @short structure for a region of interest xmin,xmax,ymin,ymax define the limits of the region */ + + #ifdef __cplusplus + struct ROI { + int xmin{-1}; /**< is the roi xmin (in channel number) */ + int xmax{-1}; /**< is the roi xmax (in channel number)*/ + }; + #else typedef struct { int xmin; /**< is the roi xmin (in channel number) */ int xmax; /**< is the roi xmax (in channel number)*/ - int ymin; /**< is the roi ymin (in channel number)*/ - int ymax; /**< is the roi ymax (in channel number)*/ - } ROI; + } ROI; + #endif /** network parameters diff --git a/slsSupportLib/include/sls_detector_funcs.h b/slsSupportLib/include/sls_detector_funcs.h index cbc2caedd..3aa838a93 100755 --- a/slsSupportLib/include/sls_detector_funcs.h +++ b/slsSupportLib/include/sls_detector_funcs.h @@ -35,6 +35,7 @@ enum detFuncs{ F_SET_DYNAMIC_RANGE, /**< set/get detector dynamic range */ F_SET_READOUT_FLAGS, /**< set/get readout flags */ F_SET_ROI, /**< set/get region of interest */ + F_GET_ROI, F_SET_SPEED, /**< set/get readout speed parameters */ F_EXIT_SERVER, /**< turn off detector server */ F_LOCK_SERVER, /**< Locks/Unlocks server communication to the given client */ @@ -185,6 +186,7 @@ static const char* getFunctionNameFromEnum(enum detFuncs func) { case F_SET_DYNAMIC_RANGE: return "F_SET_DYNAMIC_RANGE"; case F_SET_READOUT_FLAGS: return "F_SET_READOUT_FLAGS"; case F_SET_ROI: return "F_SET_ROI"; + case F_GET_ROI: return "F_GET_ROI"; case F_SET_SPEED: return "F_SET_SPEED"; case F_EXIT_SERVER: return "F_EXIT_SERVER"; case F_LOCK_SERVER: return "F_LOCK_SERVER"; diff --git a/slsSupportLib/include/versionAPI.h b/slsSupportLib/include/versionAPI.h index 1392d0ae8..85bcbd662 100644 --- a/slsSupportLib/include/versionAPI.h +++ b/slsSupportLib/include/versionAPI.h @@ -2,9 +2,9 @@ #define GITBRANCH "developer" #define APIMOENCH 0x181108 #define APICTB 0x190604 -#define APIGOTTHARD 0x190715 #define APILIB 0x190723 #define APIRECEIVER 0x190722 #define APIGUI 0x190723 #define APIJUNGFRAU 0x190730 -#define APIEIGER 0x190809 +#define APIGOTTHARD 0x190813 +#define APIEIGER 0x190814