From 6bbcf6173dedde62ad820c9e6bb554fb091c5d31 Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Mon, 2 Mar 2020 18:34:10 +0100 Subject: [PATCH] moench: first version --- slsDetectorGui/include/qDrawPlot.h | 2 - slsDetectorGui/src/qDetectorMain.cpp | 5 +- slsDetectorGui/src/qDrawPlot.cpp | 9 - slsDetectorGui/src/qTabDeveloper.cpp | 41 +- slsDetectorGui/src/qTabPlot.cpp | 2 - .../slsDetectorFunctionList.c | 2 +- .../slsDetectorServer_defs.h | 1 - .../slsDetectorFunctionList.c | 3 +- .../moenchDetectorServer/Makefile | 1 + .../moenchDetectorServer/RegisterDefs.h | 65 +- .../bin/moenchDetectorServer_developer | Bin 0 -> 176860 bytes .../slsDetectorFunctionList.c | 1638 ++++++++--------- .../slsDetectorServer_defs.h | 85 +- .../include/slsDetectorFunctionList.h | 21 +- .../src/slsDetectorServer_funcs.c | 121 +- slsDetectorSoftware/include/Detector.h | 221 +-- slsDetectorSoftware/src/CmdProxy.cpp | 75 +- slsDetectorSoftware/src/CmdProxy.h | 152 +- slsDetectorSoftware/src/Detector.cpp | 163 +- slsDetectorSoftware/src/DetectorImpl.cpp | 3 +- slsDetectorSoftware/src/slsDetector.cpp | 37 +- slsDetectorSoftware/src/slsDetector.h | 41 +- slsReceiverSoftware/src/ClientInterface.cpp | 2 +- slsReceiverSoftware/src/DataProcessor.cpp | 1 + slsReceiverSoftware/src/GeneralData.h | 104 +- slsSupportLib/include/sls_detector_defs.h | 5 + slsSupportLib/include/versionAPI.h | 2 +- 27 files changed, 1452 insertions(+), 1350 deletions(-) create mode 100755 slsDetectorServers/moenchDetectorServer/bin/moenchDetectorServer_developer diff --git a/slsDetectorGui/include/qDrawPlot.h b/slsDetectorGui/include/qDrawPlot.h index 906617416..950154bae 100755 --- a/slsDetectorGui/include/qDrawPlot.h +++ b/slsDetectorGui/include/qDrawPlot.h @@ -161,8 +161,6 @@ class qDrawPlot : public QWidget, private Ui::PlotObject { unsigned int nPixelsX{0}; unsigned int nPixelsY{0}; - const static int npixelsx_jctb = 400; - int npixelsy_jctb{0}; uint32_t pixelMask{0}; uint32_t gainMask{0}; int gainOffset{0}; diff --git a/slsDetectorGui/src/qDetectorMain.cpp b/slsDetectorGui/src/qDetectorMain.cpp index 139b56729..40c6712e2 100755 --- a/slsDetectorGui/src/qDetectorMain.cpp +++ b/slsDetectorGui/src/qDetectorMain.cpp @@ -431,8 +431,7 @@ void qDetectorMain::ExecuteUtilities(QAction *action) { void qDetectorMain::ExecuteHelp(QAction *action) { if (action == actionAbout) { - FILE_LOG(logINFO) << "About Common GUI for Eiger, Gotthard, Jungfrau " - "and Moench detectors"; + FILE_LOG(logINFO) << "About Common GUI for Jungfrau, Eiger, Mythen3, Gotthard, Gotthard2 and Moench detectors"; std::string guiVersion = std::to_string(APIGUI); std::string clientVersion = "unknown"; @@ -449,7 +448,7 @@ void qDetectorMain::ExecuteHelp(QAction *action) { clientVersion + "

" "Common GUI to control the SLS Detectors: " - "Eiger, Jungfrau, Mythen3, Gotthard, Gotthard2 and Moench.

" + "Jungfrau, Eiger, Mythen3, Gotthard, Gotthard2 and Moench.

" "It can be operated in parallel with the command " "line interface:
" "sls_detector_put,
sls_detector_get,
sls_" diff --git a/slsDetectorGui/src/qDrawPlot.cpp b/slsDetectorGui/src/qDrawPlot.cpp index 6f4b8934d..50c38f28b 100755 --- a/slsDetectorGui/src/qDrawPlot.cpp +++ b/slsDetectorGui/src/qDrawPlot.cpp @@ -60,7 +60,6 @@ void qDrawPlot::SetupWidgetWindow() { detType = det->getDetectorType().squash(); switch (detType) { case slsDetectorDefs::JUNGFRAU: - case slsDetectorDefs::MOENCH: pixelMask = ((1 << 14) - 1); gainMask = (3 << 14); gainOffset = 14; @@ -111,13 +110,6 @@ void qDrawPlot::SetupPlots() { nPixelsX = res.x; nPixelsY = res.y; switch(detType) { - case slsDetectorDefs::MOENCH: - try{ - npixelsy_jctb = (det->getNumberOfAnalogSamples().tsquash("Inconsistent values for number of analog samples") * 2)/25;// for moench 03 - nPixelsX = npixelsx_jctb; - nPixelsY = npixelsy_jctb; - } CATCH_DISPLAY ("Could not get number of analog samples.", "qDrawPlot::SetupPlots") - break; case slsDetectorDefs::EIGER: try{ if (det->getQuad().tsquash("Inconsistent values for quad type")) { @@ -984,7 +976,6 @@ void qDrawPlot::toDoublePixelData(double *dest, char *source, int size, int data case 16: if (detType == slsDetectorDefs::JUNGFRAU || - detType == slsDetectorDefs::MOENCH || detType == slsDetectorDefs::GOTTHARD2) { // show gain plot diff --git a/slsDetectorGui/src/qTabDeveloper.cpp b/slsDetectorGui/src/qTabDeveloper.cpp index 1fe5c5332..d82312a4f 100755 --- a/slsDetectorGui/src/qTabDeveloper.cpp +++ b/slsDetectorGui/src/qTabDeveloper.cpp @@ -82,14 +82,14 @@ void qTabDeveloper::SetupWidgetWindow() { case slsDetectorDefs::MOENCH: lblSpinHV->show(); spinHV->show(); - dacWidgets.push_back(new qDacWidget(this, det, true, "v Dac 0: ", getSLSIndex(detType, tempid++))); - dacWidgets.push_back(new qDacWidget(this, det, true, "v Dac 1: ", getSLSIndex(detType, tempid++))); - dacWidgets.push_back(new qDacWidget(this, det, true, "v Dac 2: ", getSLSIndex(detType, tempid++))); - dacWidgets.push_back(new qDacWidget(this, det, true, "v Dac 3: ", getSLSIndex(detType, tempid++))); - dacWidgets.push_back(new qDacWidget(this, det, true, "v Dac 4: ", getSLSIndex(detType, tempid++))); - dacWidgets.push_back(new qDacWidget(this, det, true, "v Dac 5: ", getSLSIndex(detType, tempid++))); - dacWidgets.push_back(new qDacWidget(this, det, true, "v Dac 6: ", getSLSIndex(detType, tempid++))); - dacWidgets.push_back(new qDacWidget(this, det, true, "i Dac 7: ", getSLSIndex(detType, tempid++))); + dacWidgets.push_back(new qDacWidget(this, det, true, "vbp_colbuf: ", getSLSIndex(detType, tempid++))); + dacWidgets.push_back(new qDacWidget(this, det, true, "vipre: ", getSLSIndex(detType, tempid++))); + dacWidgets.push_back(new qDacWidget(this, det, true, "vin_cm: ", getSLSIndex(detType, tempid++))); + dacWidgets.push_back(new qDacWidget(this, det, true, "vb_sda: ", getSLSIndex(detType, tempid++))); + dacWidgets.push_back(new qDacWidget(this, det, true, "vcasc_sfp: ", getSLSIndex(detType, tempid++))); + dacWidgets.push_back(new qDacWidget(this, det, true, "vout_cm: ", getSLSIndex(detType, tempid++))); + dacWidgets.push_back(new qDacWidget(this, det, true, "vipre_cds: ", getSLSIndex(detType, tempid++))); + dacWidgets.push_back(new qDacWidget(this, det, true, "ibias_sfp: ", getSLSIndex(detType, tempid++))); break; case slsDetectorDefs::MYTHEN3: @@ -343,10 +343,27 @@ slsDetectorDefs::dacIndex qTabDeveloper::getSLSIndex(slsDetectorDefs::detectorTy break; case slsDetectorDefs::MOENCH: - if (index >= 0 && index < (int)dacWidgets.size()) { - return (slsDetectorDefs::dacIndex)index; - } - throw sls::RuntimeError(std::string("Unknown dac/adc index") + std::to_string(index)); + switch (index) { + case 0: + return slsDetectorDefs::VBP_COLBUF; + case 1: + return slsDetectorDefs::VIPRE; + case 2: + return slsDetectorDefs::VIN_CM; + case 3: + return slsDetectorDefs::VB_SDA; + case 4: + return slsDetectorDefs::VCASC_SFP; + case 5: + return slsDetectorDefs::VOUT_CM; + case 6: + return slsDetectorDefs::VIPRE_CDS; + case 7: + return slsDetectorDefs::IBIAS_SFP; + default: + throw sls::RuntimeError(std::string("Unknown dac/adc index") + std::to_string(index)); + } + break; case slsDetectorDefs::MYTHEN3: switch (index) { diff --git a/slsDetectorGui/src/qTabPlot.cpp b/slsDetectorGui/src/qTabPlot.cpp index 4fbea4210..83703e364 100755 --- a/slsDetectorGui/src/qTabPlot.cpp +++ b/slsDetectorGui/src/qTabPlot.cpp @@ -72,7 +72,6 @@ void qTabPlot::SetupWidgetWindow() { chkGapPixels->setEnabled(true); break; case slsDetectorDefs::JUNGFRAU: - case slsDetectorDefs::MOENCH: chkGainPlot->setEnabled(true); chkGainPlot->setChecked(true); plot->EnableGainPlot(true); @@ -585,7 +584,6 @@ void qTabPlot::Refresh() { GetGapPixels(); break; case slsDetectorDefs::JUNGFRAU: - case slsDetectorDefs::MOENCH: chkGainPlot->setEnabled(true); break; case slsDetectorDefs::GOTTHARD2: diff --git a/slsDetectorServers/ctbDetectorServer/slsDetectorFunctionList.c b/slsDetectorServers/ctbDetectorServer/slsDetectorFunctionList.c index 368e3f8ab..1957d7df3 100755 --- a/slsDetectorServers/ctbDetectorServer/slsDetectorFunctionList.c +++ b/slsDetectorServers/ctbDetectorServer/slsDetectorFunctionList.c @@ -515,7 +515,7 @@ void setupDetector() { // altera pll ALTERA_PLL_SetDefines(PLL_CNTRL_REG, PLL_PARAM_REG, PLL_CNTRL_RCNFG_PRMTR_RST_MSK, PLL_CNTRL_WR_PRMTR_MSK, PLL_CNTRL_PLL_RST_MSK, PLL_CNTRL_ADDR_MSK, PLL_CNTRL_ADDR_OFST); - bus_w(ADC_PORT_INVERT_REG, 0);// depends on chip + setADCInvertRegister(0);// depends on chip FILE_LOG(logINFOBLUE, ("Setting Default parameters\n")); cleanFifos(); // FIXME: why twice? diff --git a/slsDetectorServers/ctbDetectorServer/slsDetectorServer_defs.h b/slsDetectorServers/ctbDetectorServer/slsDetectorServer_defs.h index dd26567da..0db56c528 100755 --- a/slsDetectorServers/ctbDetectorServer/slsDetectorServer_defs.h +++ b/slsDetectorServers/ctbDetectorServer/slsDetectorServer_defs.h @@ -107,7 +107,6 @@ enum CLKINDEX {RUN_CLK, ADC_CLK, SYNC_CLK, DBIT_CLK, NUM_CLOCKS}; #define BIT32_MSK (0xFFFFFFFF) #define BIT16_MASK (0xFFFF) -#define ADC_PORT_INVERT_VAL (0x453b2593) #define MAXIMUM_ADC_CLK (65) #define PLL_VCO_FREQ_MHZ (800) diff --git a/slsDetectorServers/jungfrauDetectorServer/slsDetectorFunctionList.c b/slsDetectorServers/jungfrauDetectorServer/slsDetectorFunctionList.c index 6c628adfb..79d3841ba 100755 --- a/slsDetectorServers/jungfrauDetectorServer/slsDetectorFunctionList.c +++ b/slsDetectorServers/jungfrauDetectorServer/slsDetectorFunctionList.c @@ -1,7 +1,7 @@ #include "slsDetectorFunctionList.h" #include "versionAPI.h" #include "clogger.h" -#include + #include "AD9257.h" // commonServerFunctions.h, blackfin.h, ansi.h #include "LTC2620.h" // dacs #include "MAX1932.h" // hv @@ -14,6 +14,7 @@ #include #include // usleep +#include #ifdef VIRTUAL #include #include diff --git a/slsDetectorServers/moenchDetectorServer/Makefile b/slsDetectorServers/moenchDetectorServer/Makefile index 00d7f828e..5285f2ea2 100755 --- a/slsDetectorServers/moenchDetectorServer/Makefile +++ b/slsDetectorServers/moenchDetectorServer/Makefile @@ -34,6 +34,7 @@ $(PROGS): $(OBJS) mv $(PROGS) $(DESTDIR) rm *.gdb rm $(main_src)*.o + rm *.o clean: rm -rf $(DESTDIR)/$(PROGS) *.o *.gdb $(main_src)*.o diff --git a/slsDetectorServers/moenchDetectorServer/RegisterDefs.h b/slsDetectorServers/moenchDetectorServer/RegisterDefs.h index 83b9f3c0e..ca8263056 100755 --- a/slsDetectorServers/moenchDetectorServer/RegisterDefs.h +++ b/slsDetectorServers/moenchDetectorServer/RegisterDefs.h @@ -16,7 +16,7 @@ /* Fix pattern RO register */ #define FIX_PATT_REG (0x01 << MEM_MAP_SHIFT) -#define FIX_PATT_VAL (0xACDC2014) +#define FIX_PATT_VAL (0xACDC2016) /* Status RO register */ #define STATUS_REG (0x02 << MEM_MAP_SHIFT) @@ -289,7 +289,7 @@ /* Configuration RW register */ #define CONFIG_REG (0x4D << MEM_MAP_SHIFT) -#define CONFIG_LED_DSBL_OFST (0) +#define CONFIG_LED_DSBL_OFST (0) // Not used in firmware or software #define CONFIG_LED_DSBL_MSK (0x00000001 << CONFIG_LED_DSBL_OFST) #define CONFIG_DSBL_ANLG_OTPT_OFST (8) #define CONFIG_DSBL_ANLG_OTPT_MSK (0x00000001 << CONFIG_DSBL_ANLG_OTPT_OFST) @@ -365,23 +365,23 @@ #define PATTERN_CNTRL_RD_OFST (1) #define PATTERN_CNTRL_RD_MSK (0x00000001 << PATTERN_CNTRL_RD_OFST) #define PATTERN_CNTRL_ADDR_OFST (16) -#define PATTERN_CNTRL_ADDR_MSK (0x0000FFFF << PATTERN_CNTRL_ADDR_OFST) +#define PATTERN_CNTRL_ADDR_MSK (0x00001FFF << PATTERN_CNTRL_ADDR_OFST) /* Pattern Limit RW regiser */ #define PATTERN_LIMIT_REG (0x53 << MEM_MAP_SHIFT) #define PATTERN_LIMIT_STRT_OFST (0) -#define PATTERN_LIMIT_STRT_MSK (0x0000FFFF << PATTERN_LIMIT_STRT_OFST) +#define PATTERN_LIMIT_STRT_MSK (0x00001FFF << PATTERN_LIMIT_STRT_OFST) #define PATTERN_LIMIT_STP_OFST (16) -#define PATTERN_LIMIT_STP_MSK (0x0000FFFF << PATTERN_LIMIT_STP_OFST) +#define PATTERN_LIMIT_STP_MSK (0x00001FFF << PATTERN_LIMIT_STP_OFST) /* Pattern Loop 0 Address RW regiser */ #define PATTERN_LOOP_0_ADDR_REG (0x54 << MEM_MAP_SHIFT) #define PATTERN_LOOP_0_ADDR_STRT_OFST (0) -#define PATTERN_LOOP_0_ADDR_STRT_MSK (0x0000FFFF << PATTERN_LOOP_0_ADDR_STRT_OFST) +#define PATTERN_LOOP_0_ADDR_STRT_MSK (0x00001FFF << PATTERN_LOOP_0_ADDR_STRT_OFST) #define PATTERN_LOOP_0_ADDR_STP_OFST (16) -#define PATTERN_LOOP_0_ADDR_STP_MSK (0x0000FFFF << PATTERN_LOOP_0_ADDR_STP_OFST) +#define PATTERN_LOOP_0_ADDR_STP_MSK (0x00001FFF << PATTERN_LOOP_0_ADDR_STP_OFST) /* Pattern Loop 0 Iteration RW regiser */ #define PATTERN_LOOP_0_ITERATION_REG (0x55 << MEM_MAP_SHIFT) @@ -390,9 +390,9 @@ #define PATTERN_LOOP_1_ADDR_REG (0x56 << MEM_MAP_SHIFT) #define PATTERN_LOOP_1_ADDR_STRT_OFST (0) -#define PATTERN_LOOP_1_ADDR_STRT_MSK (0x0000FFFF << PATTERN_LOOP_1_ADDR_STRT_OFST) +#define PATTERN_LOOP_1_ADDR_STRT_MSK (0x00001FFF << PATTERN_LOOP_1_ADDR_STRT_OFST) #define PATTERN_LOOP_1_ADDR_STP_OFST (16) -#define PATTERN_LOOP_1_ADDR_STP_MSK (0x0000FFFF << PATTERN_LOOP_1_ADDR_STP_OFST) +#define PATTERN_LOOP_1_ADDR_STP_MSK (0x00001FFF << PATTERN_LOOP_1_ADDR_STP_OFST) /* Pattern Loop 1 Iteration RW regiser */ #define PATTERN_LOOP_1_ITERATION_REG (0x57 << MEM_MAP_SHIFT) @@ -401,9 +401,9 @@ #define PATTERN_LOOP_2_ADDR_REG (0x58 << MEM_MAP_SHIFT) #define PATTERN_LOOP_2_ADDR_STRT_OFST (0) -#define PATTERN_LOOP_2_ADDR_STRT_MSK (0x0000FFFF << PATTERN_LOOP_2_ADDR_STRT_OFST) +#define PATTERN_LOOP_2_ADDR_STRT_MSK (0x00001FFF << PATTERN_LOOP_2_ADDR_STRT_OFST) #define PATTERN_LOOP_2_ADDR_STP_OFST (16) -#define PATTERN_LOOP_2_ADDR_STP_MSK (0x0000FFFF << PATTERN_LOOP_2_ADDR_STP_OFST) +#define PATTERN_LOOP_2_ADDR_STP_MSK (0x00001FFF << PATTERN_LOOP_2_ADDR_STP_OFST) /* Pattern Loop 2 Iteration RW regiser */ #define PATTERN_LOOP_2_ITERATION_REG (0x59 << MEM_MAP_SHIFT) @@ -412,31 +412,36 @@ #define PATTERN_WAIT_0_ADDR_REG (0x5A << MEM_MAP_SHIFT) #define PATTERN_WAIT_0_ADDR_OFST (0) -#define PATTERN_WAIT_0_ADDR_MSK (0x0000FFFF << PATTERN_WAIT_0_ADDR_OFST) +#define PATTERN_WAIT_0_ADDR_MSK (0x00001FFF << PATTERN_WAIT_0_ADDR_OFST) //FIXME: is mask 3FF /* Pattern Wait 1 RW regiser */ #define PATTERN_WAIT_1_ADDR_REG (0x5B << MEM_MAP_SHIFT) #define PATTERN_WAIT_1_ADDR_OFST (0) -#define PATTERN_WAIT_1_ADDR_MSK (0x0000FFFF << PATTERN_WAIT_1_ADDR_OFST) +#define PATTERN_WAIT_1_ADDR_MSK (0x00001FFF << PATTERN_WAIT_1_ADDR_OFST) /* Pattern Wait 2 RW regiser */ #define PATTERN_WAIT_2_ADDR_REG (0x5C << MEM_MAP_SHIFT) #define PATTERN_WAIT_2_ADDR_OFST (0) -#define PATTERN_WAIT_2_ADDR_MSK (0x0000FFFF << PATTERN_WAIT_2_ADDR_OFST) +#define PATTERN_WAIT_2_ADDR_MSK (0x00001FFF << PATTERN_WAIT_2_ADDR_OFST) /* Samples RW register */ #define SAMPLES_REG (0x5D << MEM_MAP_SHIFT) +#define SAMPLES_DIGITAL_OFST (0) +#define SAMPLES_DIGITAL_MSK (0x0000FFFF << SAMPLES_DIGITAL_OFST) +#define SAMPLES_ANALOG_OFST (16) +#define SAMPLES_ANALOG_MSK (0x0000FFFF << SAMPLES_ANALOG_OFST) + /** Power RW register */ #define POWER_REG (0x5E << MEM_MAP_SHIFT) -#define POWER_ENBL_VLTG_RGLTR_OFST (16) -#define POWER_ENBL_VLTG_RGLTR_MSK (0x0000001F << POWER_ENBL_VLTG_RGLTR_OFST) -#define POWER_HV_SLCT_OFST (31) -#define POWER_HV_SLCT_MSK (0x00000001 << POWER_HV_SLCT_OFST) +#define POWER_CHIP_OFST (16) +#define POWER_CHIP_MSK (0x00000001 << POWER_CHIP_OFST) +#define POWER_HV_INTERNAL_SLCT_OFST (31) +#define POWER_HV_INTERNAL_SLCT_MSK (0x00000001 << POWER_HV_INTERNAL_SLCT_OFST) /* Number of Words RW register TODO */ #define NUMBER_OF_WORDS_REG (0x5F << MEM_MAP_SHIFT) @@ -493,17 +498,16 @@ #define PATTERN_WAIT_TIMER_2_LSB_REG (0x76 << MEM_MAP_SHIFT) #define PATTERN_WAIT_TIMER_2_MSB_REG (0x77 << MEM_MAP_SHIFT) -/* ADC Disable RW register TODO */ -#define ADC_DISABLE_REG (0x78 << MEM_MAP_SHIFT) +/* Readout enable RW register */ +#define READOUT_10G_ENABLE_REG (0x79 << MEM_MAP_SHIFT) -/* DAC Value RW register TODO */ -//#define DAC_VALUE_REG (0x79 << MEM_MAP_SHIFT) - -/* DAC Number RW register TODO */ -//#define DAC_NUMBER_REG (0x7A << MEM_MAP_SHIFT) +#define READOUT_10G_ENABLE_ANLG_OFST (0) +#define READOUT_10G_ENABLE_ANLG_MSK (0x000000FF << READOUT_10G_ENABLE_ANLG_OFST) +#define READOUT_10G_ENABLE_DGTL_OFST (8) +#define READOUT_10G_ENABLE_DGTL_MSK (0x00000001 << READOUT_10G_ENABLE_DGTL_OFST) /* Digital Bit External Trigger RW register */ -#define DBIT_EXT_TRG_REG (0x7B << MEM_MAP_SHIFT) +#define DBIT_EXT_TRG_REG (0x7B << MEM_MAP_SHIFT) // Not used in firmware or software #define DBIT_EXT_TRG_SRC_OFST (0) #define DBIT_EXT_TRG_SRC_MSK (0x0000003F << DBIT_EXT_TRG_SRC_OFST) @@ -511,7 +515,8 @@ #define DBIT_EXT_TRG_OPRTN_MD_MSK (0x00000001 << DBIT_EXT_TRG_OPRTN_MD_OFST) /* Pin Delay 0 RW register */ -#define OUTPUT_DELAY_0_REG (0x7C << MEM_MAP_SHIFT) +#define OUTPUT_DELAY_0_REG (0x7C << MEM_MAP_SHIFT) // Not used in firmware or software + #define OUTPUT_DELAY_0_OTPT_STTNG_STEPS (25) #define OUTPUT_DELAY_0_OTPT_STTNG_OFST (0) //t = OTPT_STTNG * 25 ps, max for Cyclone V = 775 ps #define OUTPUT_DELAY_0_OTPT_STTNG_MSK (0x0000001F << OUTPUT_DELAY_0_OTPT_STTNG_OFST) @@ -523,7 +528,7 @@ /* Pin Delay 1 RW register * Each bit configured as enable for dynamic output delay configuration */ -#define PIN_DELAY_1_REG (0x7D << MEM_MAP_SHIFT) +#define PIN_DELAY_1_REG (0x7D << MEM_MAP_SHIFT) // Not used in firmware or software /** Pattern Mask 64 bit RW regiser */ #define PATTERN_MASK_LSB_REG (0x80 << MEM_MAP_SHIFT) @@ -533,7 +538,7 @@ #define PATTERN_SET_LSB_REG (0x82 << MEM_MAP_SHIFT) #define PATTERN_SET_MSB_REG (0x83 << MEM_MAP_SHIFT) - - +/* Round Robin */ +#define RXR_ENDPOINT_START_REG (0x1000 << MEM_MAP_SHIFT) diff --git a/slsDetectorServers/moenchDetectorServer/bin/moenchDetectorServer_developer b/slsDetectorServers/moenchDetectorServer/bin/moenchDetectorServer_developer new file mode 100755 index 0000000000000000000000000000000000000000..5f32a8451989eba90a1abff25f0c7450ccd81171 GIT binary patch literal 176860 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 z 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 CuV>8w literal 0 HcmV?d00001 diff --git a/slsDetectorServers/moenchDetectorServer/slsDetectorFunctionList.c b/slsDetectorServers/moenchDetectorServer/slsDetectorFunctionList.c index 46613a557..77513d918 100755 --- a/slsDetectorServers/moenchDetectorServer/slsDetectorFunctionList.c +++ b/slsDetectorServers/moenchDetectorServer/slsDetectorFunctionList.c @@ -9,9 +9,7 @@ #include "MAX1932.h" // hv #include "ALTERA_PLL.h" // pll #include "blackfin.h" -#ifndef VIRTUAL -#include "programFpgaBlackfin.h" -#endif +#include "common.h" #include #include // usleep @@ -22,14 +20,15 @@ // Global variable from slsDetectorServer_funcs extern int debugflag; +extern udpStruct udpDetails; // Global variable from UDPPacketHeaderGenerator extern uint64_t udpFrameNumber; extern uint32_t udpPacketNumber; -int firmware_compatibility = OK; -int firmware_check_done = 0; -char firmware_message[MAX_STR_LENGTH]; +int initError = OK; +int initCheckDone = 0; +char initErrorMessage[MAX_STR_LENGTH]; #ifdef VIRTUAL pthread_t pthread_virtual_tid; @@ -37,70 +36,69 @@ int virtual_status = 0; int virtual_stop = 0; #endif +// 1g readout int dataBytes = 0; -char* ramValues = 0; +int analogDataBytes = 0; +int digitalDataBytes = 0; +char* analogData = 0; +char* digitalData = 0; +char volatile *analogDataPtr = 0; +char volatile *digitalDataPtr = 0; char udpPacketData[UDP_PACKET_DATA_BYTES + sizeof(sls_detector_header)]; +uint32_t adcEnableMask_1g = 0; -int32_t clkPhase[NUM_CLOCKS] = {0, 0, 0, 0}; -uint32_t clkDivider[NUM_CLOCKS] = {40, 20, 20, 200}; +// 10g readout +uint8_t adcEnableMask_10g = 0; -int dacValues[NDAC] = {0}; +int32_t clkPhase[NUM_CLOCKS] = {}; +uint32_t clkFrequency[NUM_CLOCKS] = {40, 20, 20, 200}; +int dacValues[NDAC] = {}; // software limit that depends on the current chip on the ctb int vLimit = 0; - int highvoltage = 0; -ROI rois[MAX_ROIS]; -int nROI = 0; -uint32_t adcDisableMask = 0; int nSamples = 1; -char volatile *now_ptr = 0; +int detPos[2] = {0, 0}; -// basic tests -int isFirmwareCheckDone() { - return firmware_check_done; +int isInitCheckDone() { + return initCheckDone; } -int getFirmwareCheckResult(char** mess) { - *mess = firmware_message; - return firmware_compatibility; +int getInitResult(char** mess) { + *mess = initErrorMessage; + return initError; } void basictests() { - firmware_compatibility = OK; - firmware_check_done = 0; - memset(firmware_message, 0, MAX_STR_LENGTH); + initError = OK; + initCheckDone = 0; + memset(initErrorMessage, 0, MAX_STR_LENGTH); #ifdef VIRTUAL FILE_LOG(logINFOBLUE, ("******** Moench Detector Virtual Server *****************\n")); if (mapCSP0() == FAIL) { - strcpy(firmware_message, + strcpy(initErrorMessage, "Could not map to memory. Dangerous to continue.\n"); - FILE_LOG(logERROR, (firmware_message)); - firmware_compatibility = FAIL; - firmware_check_done = 1; - return; + FILE_LOG(logERROR, (initErrorMessage)); + initError = FAIL; } - firmware_check_done = 1; return; #else defineGPIOpins(); resetFPGA(); if (mapCSP0() == FAIL) { - strcpy(firmware_message, + strcpy(initErrorMessage, "Could not map to memory. Dangerous to continue.\n"); - FILE_LOG(logERROR, ("%s\n\n", firmware_message)); - firmware_compatibility = FAIL; - firmware_check_done = 1; + FILE_LOG(logERROR, ("%s\n\n", initErrorMessage)); + initError = FAIL; return; } // does check only if flag is 0 (by default), set by command line if ((!debugflag) && ((checkType() == FAIL) || (testFpga() == FAIL) || (testBus() == FAIL))) { - strcpy(firmware_message, + strcpy(initErrorMessage, "Could not pass basic tests of FPGA and bus. Dangerous to continue.\n"); - FILE_LOG(logERROR, ("%s\n\n", firmware_message)); - firmware_compatibility = FAIL; - firmware_check_done = 1; + FILE_LOG(logERROR, ("%s\n\n", initErrorMessage)); + initError = FAIL; return; } @@ -108,14 +106,14 @@ void basictests() { uint16_t hsnumber = getHardwareSerialNumber(); uint32_t ipadd = getDetectorIP(); uint64_t macadd = getDetectorMAC(); - int64_t fwversion = getDetectorId(DETECTOR_FIRMWARE_VERSION); - int64_t swversion = getDetectorId(DETECTOR_SOFTWARE_VERSION); + int64_t fwversion = getFirmwareVersion(); + int64_t swversion = getServerVersion(); int64_t sw_fw_apiversion = 0; - int64_t client_sw_apiversion = getDetectorId(CLIENT_SOFTWARE_API_VERSION); + int64_t client_sw_apiversion = getClientServerAPIVersion(); if (fwversion >= MIN_REQRD_VRSN_T_RD_API) - sw_fw_apiversion = getDetectorId(SOFTWARE_FIRMWARE_API_VERSION); + sw_fw_apiversion = getFirmwareAPIVersion(); FILE_LOG(logINFOBLUE, ("************ Moench Detector Server *********************\n" "Hardware Version:\t\t 0x%x\n" "Hardware Serial Nr:\t\t 0x%x\n" @@ -141,7 +139,6 @@ void basictests() { // return if flag is not zero, debug mode if (debugflag) { - firmware_check_done = 1; return; } @@ -149,41 +146,37 @@ void basictests() { //cant read versions FILE_LOG(logINFO, ("Testing Firmware-software compatibility:\n")); if(!fwversion || !sw_fw_apiversion){ - strcpy(firmware_message, + strcpy(initErrorMessage, "Cant read versions from FPGA. Please update firmware.\n"); - FILE_LOG(logERROR, (firmware_message)); - firmware_compatibility = FAIL; - firmware_check_done = 1; + FILE_LOG(logERROR, (initErrorMessage)); + initError = FAIL; return; } //check for API compatibility - old server if(sw_fw_apiversion > REQRD_FRMWR_VRSN){ - sprintf(firmware_message, + sprintf(initErrorMessage, "This detector software software version (0x%llx) is incompatible.\n" "Please update detector software (min. 0x%llx) to be compatible with this firmware.\n", (long long int)sw_fw_apiversion, (long long int)REQRD_FRMWR_VRSN); - FILE_LOG(logERROR, (firmware_message)); - firmware_compatibility = FAIL; - firmware_check_done = 1; + FILE_LOG(logERROR, (initErrorMessage)); + initError = FAIL; return; } //check for firmware compatibility - old firmware if( REQRD_FRMWR_VRSN > fwversion) { - sprintf(firmware_message, + sprintf(initErrorMessage, "This firmware version (0x%llx) is incompatible.\n" "Please update firmware (min. 0x%llx) to be compatible with this server.\n", (long long int)fwversion, (long long int)REQRD_FRMWR_VRSN); - FILE_LOG(logERROR, (firmware_message)); - firmware_compatibility = FAIL; - firmware_check_done = 1; + FILE_LOG(logERROR, (initErrorMessage)); + initError = FAIL; return; } FILE_LOG(logINFO, ("\tCompatibility - success\n")); - firmware_check_done = 1; #endif } @@ -195,7 +188,7 @@ int checkType() { uint32_t expectedType = (((FPGA_VERSION_DTCTR_TYP_MOENCH_VAL) & FPGA_VERSION_DTCTR_TYP_MSK) >> FPGA_VERSION_DTCTR_TYP_OFST); if (type != expectedType) { - FILE_LOG(logERROR, ("This is not a Moench Detector Server (read %d, expected %d)\n", + FILE_LOG(logERROR, ("(Type Fail) - This is not a Moench Detector Server (read %d, expected %d)\n", type, expectedType)); return FAIL; } @@ -313,39 +306,15 @@ int testBus() { return ret; } -int detectorTest( enum digitalTestMode arg){ -#ifdef VIRTUAL - return OK; -#endif - switch(arg){ - case DETECTOR_FIRMWARE_TEST: return testFpga(); - case DETECTOR_BUS_TEST: return testBus(); - default: - FILE_LOG(logERROR, ("Test %s not implemented for this detector\n", (int)arg)); - break; - } - return OK; -} - /* Ids */ -int64_t getDetectorId(enum idMode arg){ - int64_t retval = -1; +uint64_t getServerVersion() { + return APIMOENCH; +} - switch(arg){ - case DETECTOR_SERIAL_NUMBER: - return getDetectorNumber(); - case DETECTOR_FIRMWARE_VERSION: - return getFirmwareVersion(); - case SOFTWARE_FIRMWARE_API_VERSION: - return getFirmwareAPIVersion(); - case DETECTOR_SOFTWARE_VERSION: - case CLIENT_SOFTWARE_API_VERSION: - return APIMOENCH; - default: - return retval; - } +uint64_t getClientServerAPIVersion() { + return APIMOENCH; } uint64_t getFirmwareVersion() { @@ -434,7 +403,10 @@ uint32_t getDetectorIP(){ /* initialization */ void initControlServer(){ - setupDetector(); + if (initError == OK) { + setupDetector(); + } + initCheckDone = 1; } void initStopServer() { @@ -450,139 +422,175 @@ void initStopServer() { /* set up detector */ void setupDetector() { - FILE_LOG(logINFO, ("This Server is for 1 moench board\n")); + FILE_LOG(logINFO, ("This Server is for 1 Chip Test Board module\n")); // default variables dataBytes = 0; - if (ramValues) { - free(ramValues); - ramValues = 0; + analogDataBytes = 0; + digitalDataBytes = 0; + if (analogData) { + free(analogData); + analogData = 0; } + if (digitalData) { + free(digitalData); + digitalData = 0; + } + analogDataPtr = 0; + digitalDataPtr = 0; { int i = 0; for (i = 0; i < NUM_CLOCKS; ++i) { clkPhase[i] = 0; } - clkDivider[RUN_CLK] = DEFAULT_RUN_CLK; - clkDivider[ADC_CLK] = DEFAULT_ADC_CLK; - clkDivider[SYNC_CLK] = DEFAULT_SYNC_CLK; - clkDivider[DBIT_CLK] = DEFAULT_DBIT_CLK; + clkFrequency[RUN_CLK] = DEFAULT_RUN_CLK; + clkFrequency[ADC_CLK] = DEFAULT_ADC_CLK; + clkFrequency[SYNC_CLK] = DEFAULT_SYNC_CLK; + clkFrequency[DBIT_CLK] = DEFAULT_DBIT_CLK; + // default adc phase in deg + { + int phase_shifts = 0; + ConvertToDifferentRange(0, 359, 0, getMaxPhase(ADC_CLK) - 1, DEFAULT_ADC_PHASE_DEG, &phase_shifts); + clkPhase[ADC_CLK] = phase_shifts; + } + FILE_LOG(logINFO, ("Default Run clk: %d MHz\n", clkFrequency[RUN_CLK])); + FILE_LOG(logINFO, ("Default Adc clk: %d MHz\n", clkFrequency[ADC_CLK])); + FILE_LOG(logINFO, ("Default Sync clk: %d MHz\n", clkFrequency[SYNC_CLK])); + FILE_LOG(logINFO, ("Default Dbit clk: %d MHz\n", clkFrequency[DBIT_CLK])); + FILE_LOG(logINFO, ("Default Adc Phase: %d (%d deg)\n", clkPhase[ADC_CLK], getPhase(ADC_CLK, 1))); + for (i = 0; i < NDAC; ++i) dacValues[i] = -1; } vLimit = DEFAULT_VLIMIT; highvoltage = 0; - nROI = 0; - adcDisableMask = 0; + adcEnableMask_1g = 0; + adcEnableMask_10g = 0; nSamples = 1; - now_ptr = 0; - ALTERA_PLL_ResetPLLAndReconfiguration(); - resetCore(); - resetPeripheral(); - cleanFifos(); + resetCore(); + resetPeripheral(); + cleanFifos(); // hv MAX1932_SetDefines(SPI_REG, SPI_HV_SRL_CS_OTPT_MSK, SPI_HV_SRL_CLK_OTPT_MSK, SPI_HV_SRL_DGTL_OTPT_MSK, SPI_HV_SRL_DGTL_OTPT_OFST, HIGHVOLTAGE_MIN, HIGHVOLTAGE_MAX); MAX1932_Disable(); setHighVoltage(DEFAULT_HIGH_VOLTAGE); - // adc + // power off chip + powerChip(0); + + // adcs AD9257_SetDefines(ADC_SPI_REG, ADC_SPI_SRL_CS_OTPT_MSK, ADC_SPI_SRL_CLK_OTPT_MSK, ADC_SPI_SRL_DT_OTPT_MSK, ADC_SPI_SRL_DT_OTPT_OFST); AD9257_Disable(); AD9257_Configure(); - //dac - LTC2620_SetDefines(SPI_REG, SPI_DAC_SRL_CS_OTPT_MSK, SPI_DAC_SRL_CLK_OTPT_MSK, SPI_DAC_SRL_DGTL_OTPT_MSK, SPI_DAC_SRL_DGTL_OTPT_OFST, NDAC, DAC_MIN_MV, DAC_MAX_MV); + // dacs + LTC2620_SetDefines(SPI_REG, SPI_DAC_SRL_CS_OTPT_MSK, SPI_DAC_SRL_CLK_OTPT_MSK, SPI_DAC_SRL_DGTL_OTPT_MSK, SPI_DAC_SRL_DGTL_OTPT_OFST, NDAC, DAC_MIN_MV, DAC_MAX_MV); //has to be before setvchip LTC2620_Disable(); LTC2620_Configure(); - //FIXME: - // switch off dacs (power regulators most likely only sets to minimum (if power enable on)) - FILE_LOG(logINFOBLUE, ("Powering down all dacs\n")); - { - int idac = 0; - for (idac = 0; idac < NDAC; ++idac) { - setDAC(idac, LTC2620_PWR_DOWN_VAL, 0); - } - } + setDefaultDacs(); - // altera pll - ALTERA_PLL_SetDefines(PLL_CNTRL_REG, PLL_PARAM_REG, PLL_CNTRL_RCNFG_PRMTR_RST_MSK, PLL_CNTRL_WR_PRMTR_MSK, PLL_CNTRL_PLL_RST_MSK, PLL_CNTRL_ADDR_MSK, PLL_CNTRL_ADDR_OFST); - - bus_w(ADC_PORT_INVERT_REG, ADC_PORT_INVERT_VAL);//FIXME: got from moench config file + // altera pll + ALTERA_PLL_SetDefines(PLL_CNTRL_REG, PLL_PARAM_REG, PLL_CNTRL_RCNFG_PRMTR_RST_MSK, PLL_CNTRL_WR_PRMTR_MSK, PLL_CNTRL_PLL_RST_MSK, PLL_CNTRL_ADDR_MSK, PLL_CNTRL_ADDR_OFST); + // not using setADCInvertRegister command (as it xors the default) + bus_w(ADC_PORT_INVERT_REG, ADC_PORT_INVERT_VAL); FILE_LOG(logINFOBLUE, ("Setting Default parameters\n")); cleanFifos(); // FIXME: why twice? resetCore(); - // 10 G UDP - enableTenGigabitEthernet(1); + // 1G UDP + enableTenGigabitEthernet(0); //Initialization of acquistion parameters - setTimer(SAMPLES, DEFAULT_NUM_SAMPLES); // update databytes and allocate ram - setTimer(FRAME_NUMBER, DEFAULT_NUM_FRAMES); - setTimer(ACQUISITION_TIME, DEFAULT_EXPTIME); - setTimer(TRIGGER_NUMBER, DEFAULT_NUM_CYCLES); - setTimer(FRAME_PERIOD, DEFAULT_PERIOD); - setTimer(DELAY_AFTER_TRIGGER, DEFAULT_DELAY); + setNumAnalogSamples(DEFAULT_NUM_SAMPLES); + setNumFrames(DEFAULT_NUM_FRAMES); + setExpTime(DEFAULT_EXPTIME); + setNumTriggers(DEFAULT_NUM_CYCLES); + setPeriod(DEFAULT_PERIOD); + setDelayAfterTrigger(DEFAULT_DELAY); setTiming(DEFAULT_TIMING_MODE); - - // ensuring normal readout (only option for moench) - bus_w(CONFIG_REG, bus_r(CONFIG_REG) & (~CONFIG_DSBL_ANLG_OTPT_MSK) & (~CONFIG_ENBLE_DGTL_OTPT_MSK)); - - // clear roi - { - int ret = OK, retvalsize = 0; - setROI(0, rois, &retvalsize, &ret); + setADCEnableMask(BIT32_MSK); + setADCEnableMask_10G(BIT32_MSK); + if (setAnalogOnlyReadout() == FAIL) { + strcpy(initErrorMessage, + "Could not set readout mode to analog only.\n"); + FILE_LOG(logERROR, ("%s\n\n", initErrorMessage)); + initError = FAIL; } + setPipeline(ADC_CLK, DEFAULT_PIPELINE); } -int allocateRAM() { - int oldDataBytes = dataBytes; - updateDataBytes(); +int updateDatabytesandAllocateRAM() { - // only allcoate RAM for 1 giga udp (if 10G, return) - if (enableTenGigabitEthernet(-1)) + int oldDataBytes = analogDataBytes; + updateDataBytes(); + + // update only if change in databytes + if (analogDataBytes == oldDataBytes) { + FILE_LOG(logDEBUG1, ("RAM size (Databytes:%d) already allocated. Nothing to be done.\n", dataBytes)); return OK; - - // update only if change in databytes - if (dataBytes == oldDataBytes) { - FILE_LOG(logDEBUG1, ("RAM of size %d already allocated. Nothing to be done.\n", dataBytes)); - return OK; + } + // Zero databytes + if (analogDataBytes == 0) { + FILE_LOG(logERROR, ("Can not allocate RAM for 0 bytes.\n")); + return FAIL; + } + // clear RAM + if (analogData) { + free(analogData); + analogData = 0; } - // Zero databytes - if (dataBytes <= 0) { - FILE_LOG(logERROR, ("Can not allocate RAM for 0 bytes (databytes: 0).\n")); - return FAIL; - } - // clear RAM - if (ramValues) { - free(ramValues); - ramValues = 0; - } - // allocate RAM - ramValues = malloc(dataBytes); + // allocate RAM + analogData = malloc(analogDataBytes); // cannot malloc - if (ramValues == NULL) { - FILE_LOG(logERROR, ("Can not allocate RAM for even 1 frame. " - "Probably cause: Memory Leak.\n")); + if (analogData == NULL) { + FILE_LOG(logERROR, ("Can not allocate data RAM for even 1 frame. " + "Probable cause: Memory Leak.\n")); return FAIL; } - - FILE_LOG(logINFO, ("\tRAM allocated to %d bytes\n", dataBytes)); - return OK; + FILE_LOG(logINFO, ("\tRAM allocated to %d bytes\n", analogDataBytes)); + return OK; } void updateDataBytes() { - int oldDataBytes = dataBytes; - dataBytes = NCHIP * NUM_BYTES_PER_PIXEL * nSamples; - if (dataBytes != oldDataBytes) { - FILE_LOG(logINFO, ("\tUpdating Databytes: %d\n", dataBytes)); + int nchans = 0; + analogDataBytes = 0; + + if (adcEnableMask_1g == BIT32_MSK) + nchans = 32; + else { + int ichan = 0; + for (ichan = 0; ichan < NCHAN; ++ichan) { + if (adcEnableMask_1g & (1 << ichan)) + ++nchans; + } } + analogDataBytes = nchans * (DYNAMIC_RANGE / 8) * nSamples; + FILE_LOG(logINFO, ("\t#Channels:%d, Databytes:%d\n", nchans, analogDataBytes)); + + dataBytes = analogDataBytes; } +int setDefaultDacs() { + int ret = OK; + FILE_LOG(logINFOBLUE, ("Setting Default Dac values\n")); + { + int i = 0; + const int defaultvals[NDAC] = DEFAULT_DAC_VALS; + for(i = 0; i < NDAC; ++i) { + // if not already default, set it to default + if (dacValues[i] != defaultvals[i]) { + setDAC((enum DACINDEX)i,defaultvals[i],0); + } + } + } + return ret; +} + /* firmware functions (resets) */ void cleanFifos() { @@ -613,354 +621,246 @@ void resetPeripheral() { } -/* set parameters - dr, roi */ +/* set parameters - dr, adcenablemask */ int setDynamicRange(int dr){ return DYNAMIC_RANGE; } -ROI* setROI(int n, ROI arg[], int *retvalsize, int *ret) { - uint32_t addr = ADC_DISABLE_REG; - - // set ROI - if(n >= 0) { - // clear roi - if (!n) { - FILE_LOG(logINFO, ("Clearing ROI\n")); - adcDisableMask = 0; - } - // set roi - else { - FILE_LOG(logINFO, ("Setting ROI:\n")); - adcDisableMask = 0xffffffff; - int iroi = 0; - // for every roi - for (iroi = 0; iroi < n; ++iroi) { - FILE_LOG(logINFO, ("\t%d: (%d, %d)\n", iroi, arg[iroi].xmin, arg[iroi].xmax)); - // swap if xmin > xmax - if (arg[iroi].xmin > arg[iroi].xmax) { - int temp = arg[iroi].xmin; - arg[iroi].xmin = arg[iroi].xmax; - arg[iroi].xmax = temp; - FILE_LOG(logINFORED, ("\tCorrected %d: (%d, %d)\n", iroi, arg[iroi].xmin, arg[iroi].xmax)); - } - int ich = 0; - // for the roi specified - for (ich = arg[iroi].xmin; ich <= arg[iroi].xmax; ++ich) { - // valid channel (disable) - if (ich >= 0 && ich < NCHAN) - adcDisableMask &= ~(1 << ich); - - FILE_LOG(logDEBUG1, ("%d: ich:%d adcDisableMask:0x%08x\n", - iroi, ich, adcDisableMask)); - } - } - } - FILE_LOG(logINFO, ("\tSetting adcDisableMask to 0x%08x\n", adcDisableMask)); - bus_w(addr, adcDisableMask); +int setADCEnableMask(uint32_t mask) { + if (mask == 0u) { + FILE_LOG(logERROR, ("Cannot set 1gb adc mask to 0\n")); + return FAIL; } - - // get roi - adcDisableMask = bus_r(addr); - FILE_LOG(logDEBUG1, ("Getting adcDisableMask: 0x%08x\n", adcDisableMask)); - - nROI = 0; - if (adcDisableMask) { - int ich = 0; - // loop through channels - for (ich = 0; ich < NCHAN; ++ich) { - // channel disabled - if ((~adcDisableMask) & (1 << ich)) { - // first channel - if (ich == 0) { - ++nROI; - rois[nROI - 1].xmin = ich; - rois[nROI - 1].xmax = ich; - rois[nROI - 1].ymin = -1; - rois[nROI - 1].ymax = -1; - } - // not first channel - else { - // previous channel enabled (so increase roi) - if ((adcDisableMask) & (1 << (ich - 1))) { - ++nROI; - // max roi level - if (nROI > MAX_ROIS) { - nROI = -1; - *ret = FAIL; - FILE_LOG(logERROR, ("Max ROI reached!\n")); - break; - } - rois[nROI - 1].xmin = ich; - rois[nROI - 1].ymin = -1; - rois[nROI - 1].ymax = -1; - } - // set max as current one each time - rois[nROI - 1].xmax = ich; - } - } - } + int topAdcs = __builtin_popcount(mask & 0xF0F0F0F0); + int bottomAdcs = __builtin_popcount(mask & 0x0F0F0F0F); + if (topAdcs > 0 && bottomAdcs > 0 && topAdcs != bottomAdcs) { + FILE_LOG(logERROR, ("Invalid mask. Top and bottom number of adcs do not match\n")); + return FAIL; } - - // print - if (!nROI) { - 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, %d)\n", i, rois[i].xmin, rois[i].xmax)); - + FILE_LOG(logINFO, ("Setting adcEnableMask 1G to 0x%08x\n", mask)); + adcEnableMask_1g = mask; + // 1Gb enabled + if (!enableTenGigabitEthernet(-1)) { + if (updateDatabytesandAllocateRAM() == FAIL) { + return FAIL; } } - - // validate and update databytes - if (n >= 0) { - // validate - 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")); - } - // update databytes (now that mask is up to date from fpga) and allocate ram - if (allocateRAM() == FAIL) { - *ret = FAIL; - nROI = -2; - } - } - - *retvalsize = nROI; - return rois; -} - - -/* parameters - speed, readout */ - -void setSpeed(enum speedVariable ind, int val, int mode) { - switch(ind) { - case ADC_PHASE: - FILE_LOG(logINFOBLUE, ("Configuring ADC Phase\n")); - configurePhase(ADC_CLK, val, mode); - break; - case DBIT_PHASE: - FILE_LOG(logINFOBLUE, ("Configuring Dbit Phase\n")); - configurePhase(DBIT_CLK, val, mode); - break; - case ADC_CLOCK: - FILE_LOG(logINFOBLUE, ("Configuring ADC Clock\n")); - configureFrequency(ADC_CLK, val); - configureSyncFrequency(ADC_CLK); - break; - case DBIT_CLOCK: - FILE_LOG(logINFOBLUE, ("Configuring Dbit Clock\n")); - configureFrequency(DBIT_CLK, val); - configureSyncFrequency(DBIT_CLK); - break; - case ADC_PIPELINE: - setAdcOffsetRegister(1, val); - break; - case DBIT_PIPELINE: - setAdcOffsetRegister(0, val); - break; - case CLOCK_DIVIDER: - FILE_LOG(logINFOBLUE, ("Configuring Run Clock\n")); - configureFrequency(RUN_CLK, val); - configureSyncFrequency(RUN_CLK); - break; - default: - return; - } -} - -int getSpeed(enum speedVariable ind, int mode) { - switch(ind) { - case ADC_PHASE: - return getPhase(ADC_CLK, mode); - case DBIT_PHASE: - return getPhase(DBIT_CLK, mode); - case MAX_ADC_PHASE_SHIFT: - return getMaxPhase(ADC_CLK); - case MAX_DBIT_PHASE_SHIFT: - return getMaxPhase(DBIT_CLK); - case ADC_CLOCK: - return getFrequency(ADC_CLK); - case DBIT_CLOCK: - return getFrequency(DBIT_CLK); - case CLOCK_DIVIDER: - return getFrequency(RUN_CLK); - case ADC_PIPELINE: - return getAdcOffsetRegister(1); - case DBIT_PIPELINE: - return getAdcOffsetRegister(0); - default: - return -1; - } -} - - - -/* parameters - timer */ -int64_t setTimer(enum timerIndex ind, int64_t val) { - - int64_t retval = -1; - switch(ind){ - - case FRAME_NUMBER: - if(val >= 0) { - FILE_LOG(logINFO, ("Setting #frames: %lld\n",(long long int)val)); - } - retval = set64BitReg(val, FRAMES_LSB_REG, FRAMES_MSB_REG); - FILE_LOG(logINFO, ("\tGetting #frames: %lld\n", (long long int)retval)); - break; - - case ACQUISITION_TIME: - if(val >= 0){ - FILE_LOG(logINFO, ("Setting exptime (pattern wait time level 0): %lldns\n",(long long int)val)); - val *= (1E-3 * clkDivider[RUN_CLK]); - setPatternWaitTime(0, val); - } - retval = setPatternWaitTime(0, -1) / (1E-3 * clkDivider[RUN_CLK]); - FILE_LOG(logINFO, ("\tGetting exptime (pattern wait time level 0): %lldns\n", (long long int)retval)); - break; - - case FRAME_PERIOD: - if(val >= 0){ - FILE_LOG(logINFO, ("Setting period: %lldns\n",(long long int)val)); - val *= (1E-3 * clkDivider[SYNC_CLK]); - } - retval = set64BitReg(val, PERIOD_LSB_REG, PERIOD_MSB_REG )/ (1E-3 * clkDivider[SYNC_CLK]); - FILE_LOG(logINFO, ("\tGetting period: %lldns\n", (long long int)retval)); - break; - - case DELAY_AFTER_TRIGGER: - if(val >= 0){ - FILE_LOG(logINFO, ("Setting delay: %lldns\n", (long long int)val)); - val *= (1E-3 * clkDivider[SYNC_CLK]); - } - retval = set64BitReg(val, DELAY_LSB_REG, DELAY_MSB_REG) / (1E-3 * clkDivider[SYNC_CLK]); - FILE_LOG(logINFO, ("\tGetting delay: %lldns\n", (long long int)retval)); - break; - - case TRIGGER_NUMBER: - if(val >= 0) { - FILE_LOG(logINFO, ("Setting #triggers: %lld\n", (long long int)val)); - } - retval = set64BitReg(val, CYCLES_LSB_REG, CYCLES_MSB_REG); - FILE_LOG(logINFO, ("\tGetting #triggers: %lld\n", (long long int)retval)); - break; - - case SAMPLES: - if(val >= 0) { - FILE_LOG(logINFO, ("Setting #samples: %lld\n", (long long int)val)); - nSamples = val; - bus_w(SAMPLES_REG, val); - if (allocateRAM() == FAIL) { - return -1; - } - } - retval = nSamples; - FILE_LOG(logINFO, ("\tGetting #samples: %lld\n", (long long int)retval)); - break; - - default: - FILE_LOG(logERROR, ("Timer Index not implemented for this detector: %d\n", ind)); - break; - } - - return retval; - -} - - - -int64_t getTimeLeft(enum timerIndex ind){ -#ifdef VIRTUAL - return 0; -#endif - int64_t retval = -1; - switch(ind){ - - case FRAME_NUMBER: - retval = get64BitReg(FRAMES_LEFT_LSB_REG, FRAMES_LEFT_MSB_REG); - FILE_LOG(logINFO, ("Getting number of frames left: %lld\n",(long long int)retval)); - break; - - case FRAME_PERIOD: - retval = get64BitReg(PERIOD_LEFT_LSB_REG, PERIOD_LEFT_MSB_REG) / (1E-3 * clkDivider[SYNC_CLK]); - FILE_LOG(logINFO, ("Getting period left: %lldns\n", (long long int)retval)); - break; - - case DELAY_AFTER_TRIGGER: - retval = get64BitReg(DELAY_LEFT_LSB_REG, DELAY_LEFT_MSB_REG) / (1E-3 * clkDivider[SYNC_CLK]); - FILE_LOG(logINFO, ("Getting delay left: %lldns\n", (long long int)retval)); - break; - - case TRIGGER_NUMBER: - retval = get64BitReg(CYCLES_LEFT_LSB_REG, CYCLES_LEFT_MSB_REG); - FILE_LOG(logINFO, ("Getting number of triggers left: %lld\n", (long long int)retval)); - break; - - case ACTUAL_TIME: - retval = get64BitReg(TIME_FROM_START_LSB_REG, TIME_FROM_START_MSB_REG) / (1E-3 * CLK_FREQ); - FILE_LOG(logINFO, ("Getting actual time (time from start): %lld\n", (long long int)retval)); - break; - - case MEASUREMENT_TIME: - retval = get64BitReg(START_FRAME_TIME_LSB_REG, START_FRAME_TIME_MSB_REG) / (1E-3 * CLK_FREQ); - FILE_LOG(logINFO, ("Getting measurement time (timestamp/ start frame time): %lld\n", (long long int)retval)); - break; - - case FRAMES_FROM_START: - case FRAMES_FROM_START_PG: - retval = get64BitReg(FRAMES_FROM_START_PG_LSB_REG, FRAMES_FROM_START_PG_MSB_REG); - FILE_LOG(logINFO, ("Getting frames from start run control %lld\n", (long long int)retval)); - break; - - default: - FILE_LOG(logERROR, ("Remaining Timer index not implemented for this detector: %d\n", ind)); - break; - } - - return retval; -} - - -int validateTimer(enum timerIndex ind, int64_t val, int64_t retval) { - if (val < 0) - return OK; - switch(ind) { - case FRAME_PERIOD: - case DELAY_AFTER_TRIGGER: - // convert to freq - val *= (1E-3 * clkDivider[SYNC_CLK]); - // convert back to timer - val = (val) / (1E-3 * clkDivider[SYNC_CLK]); - if (val != retval) { - return FAIL; - } - break; - - case ACQUISITION_TIME: - // convert to freq - val *= (1E-3 * clkDivider[RUN_CLK]); - // convert back to timer - val = (val) / (1E-3 * clkDivider[RUN_CLK]); - if (val != retval) { - return FAIL; - } - break; - default: - break; - } return OK; } +uint32_t getADCEnableMask() { + return adcEnableMask_1g; +} + +void setADCEnableMask_10G(uint32_t mask) { + if (mask == 0u) { + FILE_LOG(logERROR, ("Cannot set 10gb adc mask to 0\n")); + return; + } + int topAdcs = __builtin_popcount(mask & 0xF0F0F0F0); + int bottomAdcs = __builtin_popcount(mask & 0x0F0F0F0F); + if (topAdcs > 0 && bottomAdcs > 0 && topAdcs != bottomAdcs) { + FILE_LOG(logERROR, ("Invalid mask. Top and bottom number of adcs do not match\n")); + return; + } + // convert 32 bit mask to 8 bit mask + uint8_t actualMask = 0; + if (mask != 0) { + int ival = 0; + int ich = 0; + for (ich = 0; ich < NCHAN; ich = ich + 4) { + if ((1 << ich) & mask) { + actualMask |= (1 << ival); + } + ++ival; + } + } + + FILE_LOG(logINFO, ("Setting adcEnableMask 10G to 0x%x (from 0x%08x)\n", actualMask, mask)); + adcEnableMask_10g = actualMask; + uint32_t addr = READOUT_10G_ENABLE_REG; + bus_w(addr, bus_r(addr) & (~READOUT_10G_ENABLE_ANLG_MSK)); + bus_w(addr, bus_r(addr) | ((adcEnableMask_10g << READOUT_10G_ENABLE_ANLG_OFST) & READOUT_10G_ENABLE_ANLG_MSK)); +} + +uint32_t getADCEnableMask_10G() { + adcEnableMask_10g = ((bus_r(READOUT_10G_ENABLE_REG) & READOUT_10G_ENABLE_ANLG_MSK) >> READOUT_10G_ENABLE_ANLG_OFST); + + // convert 8 bit mask to 32 bit mask + uint32_t retval = 0; + if (adcEnableMask_10g) { + int ival = 0; + int iloop = 0; + for (ival = 0; ival < 8; ++ival) { + // if bit in 8 bit mask set + if ((1 << ival) & adcEnableMask_10g) { + // set it for 4 bits in 32 bit mask + for (iloop = 0; iloop < 4; ++iloop) { + retval |= (1 << (ival * 4 + iloop)); + } + } + } + } + return retval; +} + +void setADCInvertRegister(uint32_t val) { + FILE_LOG(logINFO, ("Setting ADC Port Invert Reg to 0x%x\n", val)); + uint32_t defaultValue = ADC_PORT_INVERT_VAL; + uint32_t changeValue = defaultValue ^ val; + FILE_LOG(logINFO, ("\t default: 0x%x, final:0x%x\n", defaultValue, changeValue)); + bus_w(ADC_PORT_INVERT_REG, changeValue); +} + +uint32_t getADCInvertRegister() { + uint32_t readValue = bus_r(ADC_PORT_INVERT_REG); + int32_t defaultValue = ADC_PORT_INVERT_VAL; + uint32_t val = defaultValue ^ readValue; + FILE_LOG(logDEBUG1, ("\tread:0x%x, default:0x%x returned:0x%x\n", readValue, defaultValue, val)); + return val; +} + +/* parameters - timer */ +void setNumFrames(int64_t val) { + if (val > 0) { + FILE_LOG(logINFO, ("Setting number of frames %lld\n", (long long int)val)); + set64BitReg(val, FRAMES_LSB_REG, FRAMES_MSB_REG); + } +} + +int64_t getNumFrames() { + return get64BitReg(FRAMES_LSB_REG, FRAMES_MSB_REG); +} + +void setNumTriggers(int64_t val) { + if (val > 0) { + FILE_LOG(logINFO, ("Setting number of triggers %lld\n", (long long int)val)); + set64BitReg(val, CYCLES_LSB_REG, CYCLES_MSB_REG); + } +} + +int64_t getNumTriggers() { + return get64BitReg(CYCLES_LSB_REG, CYCLES_MSB_REG); +} + +int setNumAnalogSamples(int val) { + if (val < 0) { + FILE_LOG(logERROR, ("Invalid analog samples: %d\n", val)); + return FAIL; + } + FILE_LOG(logINFO, ("Setting number of analog samples %d\n", val)); + nSamples = val; + bus_w(SAMPLES_REG, bus_r(SAMPLES_REG) &~ SAMPLES_ANALOG_MSK); + bus_w(SAMPLES_REG, bus_r(SAMPLES_REG) | ((val << SAMPLES_ANALOG_OFST) & SAMPLES_ANALOG_MSK)); + + // 1Gb + if (!enableTenGigabitEthernet(-1)) { + if (updateDatabytesandAllocateRAM() == FAIL) { + return FAIL; + } + } + return OK; +} + +int getNumAnalogSamples() { + return nSamples; +} + +int setExpTime(int64_t val) { + if (val < 0) { + FILE_LOG(logERROR, ("Invalid exptime: %lld ns\n", (long long int)val)); + return FAIL; + } + FILE_LOG(logINFO, ("Setting exptime %lld ns\n", (long long int)val)); + val *= (1E-3 * clkFrequency[RUN_CLK]); + setPatternWaitTime(0, val); + + // validate for tolerance + int64_t retval = getExpTime(); + val /= (1E-3 * clkFrequency[RUN_CLK]); + if (val != retval) { + return FAIL; + } + return OK; +} + +int64_t getExpTime() { + return setPatternWaitTime(0, -1) / (1E-3 * clkFrequency[RUN_CLK]); +} + +int setPeriod(int64_t val) { + if (val < 0) { + FILE_LOG(logERROR, ("Invalid period: %lld ns\n", (long long int)val)); + return FAIL; + } + FILE_LOG(logINFO, ("Setting period %lld ns\n", (long long int)val)); + val *= (1E-3 * clkFrequency[SYNC_CLK]); + set64BitReg(val, PERIOD_LSB_REG, PERIOD_MSB_REG); + + // validate for tolerance + int64_t retval = getPeriod(); + val /= (1E-3 * clkFrequency[SYNC_CLK]); + if (val != retval) { + return FAIL; + } + return OK; +} + +int64_t getPeriod() { + return get64BitReg(PERIOD_LSB_REG, PERIOD_MSB_REG)/ (1E-3 * clkFrequency[SYNC_CLK]); +} + +int setDelayAfterTrigger(int64_t val) { + if (val < 0) { + FILE_LOG(logERROR, ("Invalid delay after trigger: %lld ns\n", (long long int)val)); + return FAIL; + } + FILE_LOG(logINFO, ("Setting delay after trigger %lld ns\n", (long long int)val)); + val *= (1E-3 * clkFrequency[SYNC_CLK]); + set64BitReg(val, DELAY_LSB_REG, DELAY_MSB_REG); + + // validate for tolerance + int64_t retval = getDelayAfterTrigger(); + val /= (1E-3 * clkFrequency[SYNC_CLK]); + if (val != retval) { + return FAIL; + } + return OK; +} + +int64_t getDelayAfterTrigger() { + return get64BitReg(DELAY_LSB_REG, DELAY_MSB_REG) / (1E-3 * clkFrequency[SYNC_CLK]); +} + +int64_t getNumFramesLeft() { + return get64BitReg(FRAMES_LEFT_LSB_REG, FRAMES_LEFT_MSB_REG); +} + +int64_t getNumTriggersLeft() { + return get64BitReg(CYCLES_LEFT_LSB_REG, CYCLES_LEFT_MSB_REG); +} + +int64_t getDelayAfterTriggerLeft() { + return get64BitReg(DELAY_LEFT_LSB_REG, DELAY_LEFT_MSB_REG) / (1E-3 * clkFrequency[SYNC_CLK]); +} + +int64_t getPeriodLeft() { + return get64BitReg(PERIOD_LEFT_LSB_REG, PERIOD_LEFT_MSB_REG) / (1E-3 * clkFrequency[SYNC_CLK]); +} + +int64_t getFramesFromStart() { + return get64BitReg(FRAMES_FROM_START_PG_LSB_REG, FRAMES_FROM_START_PG_MSB_REG); +} + +int64_t getActualTime() { + return get64BitReg(TIME_FROM_START_LSB_REG, TIME_FROM_START_MSB_REG) / (1E-3 * CLK_FREQ); +} + +int64_t getMeasurementTime() { + return get64BitReg(START_FRAME_TIME_LSB_REG, START_FRAME_TIME_MSB_REG) / (1E-3 * CLK_FREQ); +} + /* parameters - settings */ @@ -970,8 +870,9 @@ enum detectorSettings getSettings() { /* parameters - dac, adc, hv */ + void setDAC(enum DACINDEX ind, int val, int mV) { - if (val < 0 && val != LTC2620_PWR_DOWN_VAL) + if (val < 0 && val != LTC2620_GetPowerDownValue()) return; FILE_LOG(logDEBUG1, ("Setting dac[%d]: %d %s \n", (int)ind, val, (mV ? "mV" : "dac units"))); @@ -1002,7 +903,7 @@ int getDAC(enum DACINDEX ind, int mV) { } int getMaxDacSteps() { - return LTC2620_MAX_STEPS; + return LTC2620_GetMaxNumSteps(); } int dacToVoltage(int dac) { @@ -1045,13 +946,23 @@ int setHighVoltage(int val){ highvoltage = val; return highvoltage; #endif - // setting hv - if (val >= 0) { - FILE_LOG(logINFO, ("Setting High voltage: %d V\n", val)); - MAX1932_Set(val); - highvoltage = val; - } + // setting hv + if (val >= 0) { + FILE_LOG(logINFO, ("Setting High voltage: %d V\n", val)); + uint32_t addr = POWER_REG; + + // switch to external high voltage + bus_w(addr, bus_r(addr) & (~POWER_HV_INTERNAL_SLCT_MSK)); + + MAX1932_Set(val); + + // switch on internal high voltage, if set + if (val > 0) + bus_w(addr, bus_r(addr) | POWER_HV_INTERNAL_SLCT_MSK); + + highvoltage = val; + } return highvoltage; } @@ -1064,22 +975,18 @@ int setHighVoltage(int val){ void setTiming( enum timingMode arg){ - - if(arg != GET_TIMING_MODE){ - switch((int)arg){ - case AUTO_TIMING: - FILE_LOG(logINFO, ("Set Timing: Auto\n")); - bus_w(EXT_SIGNAL_REG, bus_r(EXT_SIGNAL_REG) & ~EXT_SIGNAL_MSK); - break; - case TRIGGER_EXPOSURE: - FILE_LOG(logINFO, ("Set Timing: Trigger\n")); - bus_w(EXT_SIGNAL_REG, bus_r(EXT_SIGNAL_REG) | EXT_SIGNAL_MSK); - break; - default: - FILE_LOG(logERROR, ("Unknown timing mode %d\n", arg)); - return; - } - } + switch(arg){ + case AUTO_TIMING: + FILE_LOG(logINFO, ("Set Timing: Auto\n")); + bus_w(EXT_SIGNAL_REG, bus_r(EXT_SIGNAL_REG) & ~EXT_SIGNAL_MSK); + break; + case TRIGGER_EXPOSURE: + FILE_LOG(logINFO, ("Set Timing: Trigger\n")); + bus_w(EXT_SIGNAL_REG, bus_r(EXT_SIGNAL_REG) | EXT_SIGNAL_MSK); + break; + default: + FILE_LOG(logERROR, ("Unknown timing mode %d\n", arg)); + } } @@ -1094,57 +1001,60 @@ enum timingMode getTiming() { /* configure mac */ -long int calcChecksum(int sourceip, int destip) { - ip_header ip; - ip.ip_ver = 0x4; - ip.ip_ihl = 0x5; - ip.ip_tos = 0x0; - ip.ip_len = IP_PACKETSIZE; - ip.ip_ident = 0x0000; - ip.ip_flag = 0x2; //not nibble aligned (flag& offset - ip.ip_offset = 0x000; - ip.ip_ttl = 0x40; - ip.ip_protocol = 0x11; - ip.ip_chksum = 0x0000 ; // pseudo - ip.ip_sourceip = sourceip; - ip.ip_destip = destip; - - int count = sizeof(ip); - - unsigned short *addr; - addr = (unsigned short*) &(ip); /* warning: assignment from incompatible pointer type */ - +void calcChecksum(udp_header* udp) { + int count = IP_HEADER_SIZE; long int sum = 0; - while( count > 1 ) { + + // start at ip_tos as the memory is not continous for ip header + uint16_t *addr = (uint16_t*) (&(udp->ip_tos)); + + sum += *addr++; + count -= 2; + + // ignore ethertype (from udp header) + addr++; + + // from identification to srcip_lsb + while( count > 2 ) { sum += *addr++; count -= 2; } + + // ignore src udp port (from udp header) + addr++; + if (count > 0) sum += *addr; // Add left-over byte, if any - while (sum>>16) + while (sum >> 16) sum = (sum & 0xffff) + (sum >> 16);// Fold 32-bit sum to 16 bits - long int checksum = (~sum) & 0xffff; - FILE_LOG(logINFO, ("IP checksum is 0x%lx\n",checksum)); - return checksum; + long int checksum = sum & 0xffff; + checksum += UDP_IP_HEADER_LENGTH_BYTES; + FILE_LOG(logINFO, ("\tIP checksum is 0x%lx\n",checksum)); + udp->ip_checksum = checksum; } - -int configureMAC(uint32_t destip, uint64_t destmac, uint64_t sourcemac, uint32_t sourceip, uint32_t udpport){ +int configureMAC(){ + uint32_t sourceip = udpDetails.srcip; + uint32_t destip = udpDetails.dstip; + uint64_t sourcemac = udpDetails.srcmac; + uint64_t destmac = udpDetails.dstmac; + int sourceport = udpDetails.srcport; + int destport = udpDetails.dstport; #ifdef VIRTUAL - return OK; + return OK; #endif FILE_LOG(logINFOBLUE, ("Configuring MAC\n")); // 1 giga udp if (!enableTenGigabitEthernet(-1)) { - // if it was in 10G mode, it was not allocating RAM - if (allocateRAM() == FAIL) + FILE_LOG(logINFOBLUE, ("Configuring 1G MAC\n")); + if (updateDatabytesandAllocateRAM() == FAIL) return -1; char cDestIp[MAX_STR_LENGTH]; memset(cDestIp, 0, MAX_STR_LENGTH); sprintf(cDestIp, "%d.%d.%d.%d", (destip>>24)&0xff,(destip>>16)&0xff,(destip>>8)&0xff,(destip)&0xff); - FILE_LOG(logINFO, ("1G UDP: Destination (IP: %s, port:%d)\n", cDestIp, udpport)); - if (setUDPDestinationDetails(cDestIp, udpport) == FAIL) { + FILE_LOG(logINFO, ("1G UDP: Destination (IP: %s, port:%d)\n", cDestIp, destport)); + if (setUDPDestinationDetails(0, cDestIp, destport) == FAIL) { FILE_LOG(logERROR, ("could not set udp 1G destination IP and port\n")); return FAIL; } @@ -1152,71 +1062,84 @@ int configureMAC(uint32_t destip, uint64_t destmac, uint64_t sourcemac, uint32_t } // 10 G - else { - uint32_t sourceport = DEFAULT_TX_UDP_PORT; + FILE_LOG(logINFOBLUE, ("Configuring 10G MAC\n")); - FILE_LOG(logINFO, ("\tSource IP : %d.%d.%d.%d \t\t(0x%08x)\n", - (sourceip>>24)&0xff,(sourceip>>16)&0xff,(sourceip>>8)&0xff,(sourceip)&0xff, sourceip)); - FILE_LOG(logINFO, ("\tSource MAC : %02x:%02x:%02x:%02x:%02x:%02x \t(0x%010llx)\n", - (unsigned int)((sourcemac>>40)&0xFF), - (unsigned int)((sourcemac>>32)&0xFF), - (unsigned int)((sourcemac>>24)&0xFF), - (unsigned int)((sourcemac>>16)&0xFF), - (unsigned int)((sourcemac>>8)&0xFF), - (unsigned int)((sourcemac>>0)&0xFF), - (long long unsigned int)sourcemac)); - FILE_LOG(logINFO, ("\tSource Port : %d \t\t\t(0x%08x)\n",sourceport, sourceport)); + FILE_LOG(logINFO, ("\tSource IP : %d.%d.%d.%d \t\t(0x%08x)\n", + (sourceip>>24)&0xff,(sourceip>>16)&0xff,(sourceip>>8)&0xff,(sourceip)&0xff, sourceip)); + FILE_LOG(logINFO, ("\tSource MAC : %02x:%02x:%02x:%02x:%02x:%02x \t(0x%010llx)\n", + (unsigned int)((sourcemac>>40)&0xFF), + (unsigned int)((sourcemac>>32)&0xFF), + (unsigned int)((sourcemac>>24)&0xFF), + (unsigned int)((sourcemac>>16)&0xFF), + (unsigned int)((sourcemac>>8)&0xFF), + (unsigned int)((sourcemac>>0)&0xFF), + (long long unsigned int)sourcemac)); + FILE_LOG(logINFO, ("\tSource Port : %d \t\t\t(0x%08x)\n",sourceport, sourceport)); - FILE_LOG(logINFO, ("\tDest. IP : %d.%d.%d.%d \t\t(0x%08x)\n", - (destip>>24)&0xff,(destip>>16)&0xff,(destip>>8)&0xff,(destip)&0xff, destip)); - FILE_LOG(logINFO, ("\tDest. MAC : %02x:%02x:%02x:%02x:%02x:%02x \t(0x%010llx)\n", - (unsigned int)((destmac>>40)&0xFF), - (unsigned int)((destmac>>32)&0xFF), - (unsigned int)((destmac>>24)&0xFF), - (unsigned int)((destmac>>16)&0xFF), - (unsigned int)((destmac>>8)&0xFF), - (unsigned int)((destmac>>0)&0xFF), - (long long unsigned int)destmac)); - FILE_LOG(logINFO, ("\tDest. Port : %d \t\t\t(0x%08x)\n",udpport, udpport)); + FILE_LOG(logINFO, ("\tDest. IP : %d.%d.%d.%d \t\t(0x%08x)\n", + (destip>>24)&0xff,(destip>>16)&0xff,(destip>>8)&0xff,(destip)&0xff, destip)); + FILE_LOG(logINFO, ("\tDest. MAC : %02x:%02x:%02x:%02x:%02x:%02x \t(0x%010llx)\n", + (unsigned int)((destmac>>40)&0xFF), + (unsigned int)((destmac>>32)&0xFF), + (unsigned int)((destmac>>24)&0xFF), + (unsigned int)((destmac>>16)&0xFF), + (unsigned int)((destmac>>8)&0xFF), + (unsigned int)((destmac>>0)&0xFF), + (long long unsigned int)destmac)); + FILE_LOG(logINFO, ("\tDest. Port : %d \t\t\t(0x%08x)\n",destport, destport)); - long int checksum=calcChecksum(sourceip, destip); - bus_w(TX_IP_REG, sourceip); - bus_w(RX_IP_REG, destip); + // start addr + uint32_t addr = RXR_ENDPOINT_START_REG; + // get struct memory + udp_header *udp = (udp_header*) (Blackfin_getBaseAddress() + addr / 2); + memset(udp, 0, sizeof(udp_header)); - uint32_t val = 0; + // mac addresses + // msb (32) + lsb (16) + udp->udp_destmac_msb = ((destmac >> 16) & BIT32_MASK); + udp->udp_destmac_lsb = ((destmac >> 0) & BIT16_MASK); + // msb (16) + lsb (32) + udp->udp_srcmac_msb = ((sourcemac >> 32) & BIT16_MASK); + udp->udp_srcmac_lsb = ((sourcemac >> 0) & BIT32_MASK); - val = ((sourcemac >> LSB_OF_64_BIT_REG_OFST) & BIT_32_MSK); - bus_w(TX_MAC_LSB_REG, val); - FILE_LOG(logDEBUG1, ("Read from TX_MAC_LSB_REG: 0x%08x\n", bus_r(TX_MAC_LSB_REG))); + // ip addresses + udp->ip_srcip_msb = ((sourceip >> 16) & BIT16_MASK); + udp->ip_srcip_lsb = ((sourceip >> 0) & BIT16_MASK); + udp->ip_destip_msb = ((destip >> 16) & BIT16_MASK); + udp->ip_destip_lsb = ((destip >> 0) & BIT16_MASK); - val = ((sourcemac >> MSB_OF_64_BIT_REG_OFST) & BIT_32_MSK); - bus_w(TX_MAC_MSB_REG,val); - FILE_LOG(logDEBUG1, ("Read from TX_MAC_MSB_REG: 0x%08x\n", bus_r(TX_MAC_MSB_REG))); + // source port + udp->udp_srcport = sourceport; + udp->udp_destport = destport; - val = ((destmac >> LSB_OF_64_BIT_REG_OFST) & BIT_32_MSK); - bus_w(RX_MAC_LSB_REG, val); - FILE_LOG(logDEBUG1, ("Read from RX_MAC_LSB_REG: 0x%08x\n", bus_r(RX_MAC_LSB_REG))); + // other defines + udp->udp_ethertype = 0x800; + udp->ip_ver = 0x4; + udp->ip_ihl = 0x5; + udp->ip_flags = 0x2; //FIXME + udp->ip_ttl = 0x40; + udp->ip_protocol = 0x11; + // total length is redefined in firmware - val = ((destmac >> MSB_OF_64_BIT_REG_OFST) & BIT_32_MSK); - bus_w(RX_MAC_MSB_REG, val); - FILE_LOG(logDEBUG1, ("Read from RX_MAC_MSB_REG: 0x%08x\n", bus_r(RX_MAC_MSB_REG))); + calcChecksum(udp); - val = (((sourceport << UDP_PORT_TX_OFST) & UDP_PORT_TX_MSK) | - ((udpport << UDP_PORT_RX_OFST) & UDP_PORT_RX_MSK)); - bus_w(UDP_PORT_REG, val); - FILE_LOG(logDEBUG1, ("Read from UDP_PORT_REG: 0x%08x\n", bus_r(UDP_PORT_REG))); - - bus_w(TX_IP_CHECKSUM_REG,(checksum << TX_IP_CHECKSUM_OFST) & TX_IP_CHECKSUM_MSK); - FILE_LOG(logDEBUG1, ("Read from TX_IP_CHECKSUM_REG: 0x%08x\n", bus_r(TX_IP_CHECKSUM_REG))); - - cleanFifos();//FIXME: resetPerpheral() for ctb? - resetPeripheral(); - usleep(WAIT_TIME_CONFIGURE_MAC); /* todo maybe without */ - } + cleanFifos();//FIXME: resetPerpheral() for ctb? + resetPeripheral(); + FILE_LOG(logINFO, ("Waiting for %d s for mac to be up\n", WAIT_TIME_CONFIGURE_MAC / (1000 * 1000))); + usleep(WAIT_TIME_CONFIGURE_MAC); // todo maybe without return OK; } +int setDetectorPosition(int pos[]) { + memcpy(detPos, pos, sizeof(detPos)); + return OK; +} + +int* getDetectorPosition() { + return detPos; +} + int enableTenGigabitEthernet(int val) { uint32_t addr = CONFIG_REG; @@ -1234,43 +1157,69 @@ int enableTenGigabitEthernet(int val) { } - -/* moench specific - configure frequency, phase, pll, */ - -int powerChip(int on) { +/* moench specific - powerchip, configure frequency, phase, pll*/ +int powerChip (int on) { uint32_t addr = POWER_REG; - if (on >= 0) { - FILE_LOG(logINFO, ("Powering %s\n", (on > 0 ? "on" : "off"))); - if (on) - bus_w(addr, bus_r(addr) | POWER_ENBL_VLTG_RGLTR_MSK); - else - bus_w(addr, bus_r(addr) & (~POWER_ENBL_VLTG_RGLTR_MSK)); + if (on > 0) { + FILE_LOG(logINFOBLUE, ("Powering on chip\n")); + bus_w(addr, bus_r(addr) | POWER_CHIP_MSK); + } else if (on == 0) { + FILE_LOG(logINFOBLUE, ("Powering off chip\n")); + bus_w(addr, bus_r(addr) &~ POWER_CHIP_MSK); } - - uint32_t regval = bus_r(addr); - FILE_LOG(logDEBUG1, ("\tPower Register: 0x%08x\n", regval)); - - if (regval & POWER_ENBL_VLTG_RGLTR_MSK) - return 1; - return 0; + return ((bus_r(addr) & POWER_CHIP_MSK) >> POWER_CHIP_OFST); } -// ind can only be ADC_CLK or DBIT_CLK -void configurePhase(enum CLKINDEX ind, int val, int degrees) { - char clock_names[4][10]={"run_clk","adc_clk", "sync_clk", "dbit_clk"}; - int maxShift = getMaxPhase(ind); +/* parameters - readout */ +int setAnalogOnlyReadout() { + FILE_LOG(logINFOBLUE, ("Setting Analog Only Readout\n")); + + uint32_t addr = CONFIG_REG; + uint32_t addr_readout_10g = READOUT_10G_ENABLE_REG; + // default: analog only + bus_w(addr, bus_r(addr) & (~CONFIG_DSBL_ANLG_OTPT_MSK) & (~CONFIG_ENBLE_DGTL_OTPT_MSK)); + bus_w(addr_readout_10g, bus_r(addr_readout_10g) & (~READOUT_10G_ENABLE_ANLG_MSK) & ~(READOUT_10G_ENABLE_DGTL_MSK)); + bus_w(addr_readout_10g, bus_r(addr_readout_10g) | ((adcEnableMask_10g << READOUT_10G_ENABLE_ANLG_OFST) & READOUT_10G_ENABLE_ANLG_MSK)); + + // 1Gb + if (!enableTenGigabitEthernet(-1)) { + if (updateDatabytesandAllocateRAM() == FAIL) { + return FAIL; + } + } + + // 10Gb + else { + // validate adcenablemask for 10g + if (adcEnableMask_10g != ((bus_r(READOUT_10G_ENABLE_REG) & READOUT_10G_ENABLE_ANLG_MSK) >> READOUT_10G_ENABLE_ANLG_OFST)) { + FILE_LOG(logERROR, ("Setting readout mode failed. Could not set 10g adc enable mask to 0x%x\n.", adcEnableMask_10g)); + return FAIL; + } + } + return OK; +} + + + +int setPhase(enum CLKINDEX ind, int val, int degrees) { + if (ind != ADC_CLK && ind != DBIT_CLK) { + FILE_LOG(logERROR, ("Unknown clock index %d to set phase\n", ind)); + return FAIL; + } + char* clock_names[] = {CLK_NAMES}; + FILE_LOG(logINFO, ("Setting %s clock (%d) phase to %d %s\n", clock_names[ind], ind, val, degrees == 0 ? "" : "degrees")); + int maxShift = getMaxPhase(ind); // validation if (degrees && (val < 0 || val > 359)) { - FILE_LOG(logERROR, ("\tPhase provided for C%d(%s) outside limits (0 - 359°C)\n", ind, clock_names[ind])); - return; + FILE_LOG(logERROR, ("\tPhase outside limits (0 - 359°C)\n")); + return FAIL; } if (!degrees && (val < 0 || val > maxShift - 1)) { - FILE_LOG(logERROR, ("\tPhase provided for C%d(%s) outside limits (0 - %d phase shifts)\n", ind, clock_names[ind], maxShift - 1)); - return; + FILE_LOG(logERROR, ("\tPhase outside limits (0 - %d phase shifts)\n", maxShift - 1)); + return FAIL; } - FILE_LOG(logINFO, ("\tConfiguring Phase of C%d(%s) to %d (degree mode: %d)\n", ind, clock_names[ind], val, degrees)); int valShift = val; // convert to phase shift if (degrees) { @@ -1284,8 +1233,9 @@ void configurePhase(enum CLKINDEX ind, int val, int degrees) { // same phase if (!relativePhase) { FILE_LOG(logINFO, ("\tNothing to do in Phase Shift\n")); - return; + return OK; } + FILE_LOG(logINFOBLUE, ("Configuring Phase\n")); int phase = 0; if (relativePhase > 0) { @@ -1298,9 +1248,14 @@ void configurePhase(enum CLKINDEX ind, int val, int degrees) { ALTERA_PLL_SetPhaseShift(phase, (int)ind, 0); clkPhase[ind] = valShift; + return OK; } int getPhase(enum CLKINDEX ind, int degrees) { + if (ind != ADC_CLK && ind != DBIT_CLK) { + FILE_LOG(logERROR, ("Unknown clock index %d to get phase\n", ind)); + return -1; + } if (!degrees) return clkPhase[ind]; // convert back to degrees @@ -1310,31 +1265,29 @@ int getPhase(enum CLKINDEX ind, int degrees) { } int getMaxPhase(enum CLKINDEX ind) { - int ret = ((double)PLL_VCO_FREQ_MHZ / (double)clkDivider[ind]) * MAX_PHASE_SHIFTS_STEPS; + if (ind != ADC_CLK && ind != DBIT_CLK) { + FILE_LOG(logERROR, ("Unknown clock index %d to get max phase\n", ind)); + return -1; + } + int ret = ((double)PLL_VCO_FREQ_MHZ / (double)clkFrequency[ind]) * MAX_PHASE_SHIFTS_STEPS; - char clock_names[4][10]={"run_clk","adc_clk", "sync_clk", "dbit_clk"}; + char* clock_names[] = {CLK_NAMES}; FILE_LOG(logDEBUG1, ("Max Phase Shift (%s): %d (Clock: %d MHz, VCO:%d MHz)\n", - clock_names[ind], ret, clkDivider[ind], PLL_VCO_FREQ_MHZ)); + clock_names[ind], ret, clkFrequency[ind], PLL_VCO_FREQ_MHZ)); return ret; } -int validatePhaseinDegrees(enum speedVariable ind, int val, int retval) { - if (val == -1) - return OK; - enum CLKINDEX clkIndex; - switch(ind) { - case ADC_PHASE: - clkIndex = ADC_CLK; - break; - case DBIT_PHASE: - clkIndex = DBIT_CLK; - break; - default: - FILE_LOG(logERROR, ("Unknown speed enum %d for validating phase in degrees\n", (int)ind)); +int validatePhaseinDegrees(enum CLKINDEX ind, int val, int retval) { + if (ind != ADC_CLK && ind != DBIT_CLK) { + FILE_LOG(logERROR, ("Unknown clock index %d to validate phase in degrees\n", ind)); + return FAIL; } - FILE_LOG(logDEBUG1, ("validating phase in degrees for clk %d\n", clkIndex)); - int maxShift = getMaxPhase(clkIndex); + if (val == -1) { + return OK; + } + FILE_LOG(logDEBUG1, ("validating phase in degrees for clk %d\n", ind)); + int maxShift = getMaxPhase(ind); // convert degrees to shift int valShift = 0; ConvertToDifferentRange(0, 359, 0, maxShift - 1, val, &valShift); @@ -1346,36 +1299,62 @@ int validatePhaseinDegrees(enum speedVariable ind, int val, int retval) { return FAIL; } -void configureFrequency(enum CLKINDEX ind, int val) { - char clock_names[4][10]={"run_clk","adc_clk", "sync_clk", "dbit_clk"}; - if (val <= 0) - return; - - FILE_LOG(logINFO, ("\tConfiguring Frequency of C%d(%s) to %d MHz\n", ind, clock_names[ind], val)); +int setFrequency(enum CLKINDEX ind, int val) { + if (ind < 0 || ind >= NUM_CLOCKS) { + FILE_LOG(logERROR, ("Unknown clock index %d to set frequency\n", ind)); + return FAIL; + } + if (val <= 0) { + return FAIL; + } + char* clock_names[] = {CLK_NAMES}; + FILE_LOG(logINFO, ("\tSetting %s clock (%d) frequency to %d MHz\n", clock_names[ind], ind, val)); // check adc clk too high if (ind == ADC_CLK && val > MAXIMUM_ADC_CLK) { FILE_LOG(logERROR, ("Frequency %d MHz too high for ADC\n", val)); - return; + return FAIL; } - // reset phase - if (ind == ADC_CLK || ind == DBIT_CLK) { - FILE_LOG(logINFO, ("\tReseting phase of %s\n", clock_names[ind])); - configurePhase(ind, 0, 0); - } + // Remembering adcphase/ dbit phase in degrees + int adcPhase = getPhase(ADC_CLK, 1); + FILE_LOG(logDEBUG1, ("\tRemembering ADC phase: %d degrees\n", adcPhase)); + int dbitPhase = getPhase(DBIT_CLK, 1); + FILE_LOG(logDEBUG1, ("\tRemembering DBIT phase: %d degrees\n", dbitPhase)); // Calculate and set output frequency - clkDivider[ind] = ALTERA_PLL_SetOuputFrequency (ind, PLL_VCO_FREQ_MHZ, val); - FILE_LOG(logINFO, ("\tC%d(%s): Frequency set to %d MHz\n", ind, clock_names[ind], clkDivider[ind])); + clkFrequency[ind] = ALTERA_PLL_SetOuputFrequency (ind, PLL_VCO_FREQ_MHZ, val); + FILE_LOG(logINFO, ("\t%s clock (%d) frequency set to %d MHz\n", clock_names[ind], ind, clkFrequency[ind])); + + // phase reset by pll (when setting output frequency) + clkPhase[ADC_CLK] = 0; + clkPhase[DBIT_CLK] = 0; + + // set the phase (reset by pll) + FILE_LOG(logINFO, ("\tCorrecting ADC phase to %d degrees\n", adcPhase)); + setPhase(ADC_CLK, adcPhase, 1); + FILE_LOG(logINFO, ("\tCorrecting DBIT phase to %d degrees\n", dbitPhase)); + setPhase(DBIT_CLK, dbitPhase, 1); + + // required to reconfigure as adc clock is stopped temporarily when resetting pll (in changing output frequency) + AD9257_Configure(); + + if (ind != SYNC_CLK) { + configureSyncFrequency(ind); + } + return OK; } int getFrequency(enum CLKINDEX ind) { - return clkDivider[ind]; + if (ind < 0 || ind >= NUM_CLOCKS) { + FILE_LOG(logERROR, ("Unknown clock index %d to get frequency\n", ind)); + return -1; + } + return clkFrequency[ind]; } void configureSyncFrequency(enum CLKINDEX ind) { - char clock_names[4][10]={"run_clk","adc_clk", "sync_clk", "dbit_clk"}; + char* clock_names[] = {CLK_NAMES}; int clka = 0, clkb = 0; switch(ind) { case ADC_CLK: @@ -1391,6 +1370,7 @@ void configureSyncFrequency(enum CLKINDEX ind) { clkb = ADC_CLK; break; default: + FILE_LOG(logERROR, ("Unknown clock index %d to configure sync frequcny\n", ind)); return; } @@ -1421,67 +1401,69 @@ void configureSyncFrequency(enum CLKINDEX ind) { // configure sync to current if (configure) - configureFrequency(SYNC_CLK, min); + setFrequency(SYNC_CLK, min); } - -void setAdcOffsetRegister(int adc, int val) { - if (val < 0) +// adc pipeline only +void setPipeline(enum CLKINDEX ind, int val) { + if (ind != ADC_CLK) { + FILE_LOG(logERROR, ("Unknown clock index %d to set pipeline\n", ind)); + return; + } + if (val < 0) { return; - - FILE_LOG(logINFO, ("Setting %s Pipeline to %d\n", (adc ? "ADC" : "Dbit"), val)); + } + FILE_LOG(logINFO, ("Setting adc clock (%d) Pipeline to %d\n", ADC_CLK, val)); uint32_t offset = ADC_OFFSET_ADC_PPLN_OFST; uint32_t mask = ADC_OFFSET_ADC_PPLN_MSK; - if (!adc) { - offset = ADC_OFFSET_DBT_PPLN_OFST; - mask = ADC_OFFSET_DBT_PPLN_MSK; - } - uint32_t addr = ADC_OFFSET_REG; // reset value bus_w(addr, bus_r(addr) & ~ mask); // set value bus_w(addr, bus_r(addr) | ((val << offset) & mask)); - FILE_LOG(logDEBUG1, (" %s Offset: 0x%8x\n", (adc ? "ADC" : "Dbit"), bus_r(addr))); + FILE_LOG(logDEBUG1, (" adc clock (%d) Offset: 0x%8x\n", ADC_CLK, bus_r(addr))); } -int getAdcOffsetRegister(int adc) { - if (adc) - return ((bus_r(ADC_OFFSET_REG) & ADC_OFFSET_ADC_PPLN_MSK) >> ADC_OFFSET_ADC_PPLN_OFST); - return ((bus_r(ADC_OFFSET_REG) & ADC_OFFSET_DBT_PPLN_MSK) >> ADC_OFFSET_DBT_PPLN_OFST); +int getPipeline(enum CLKINDEX ind) { + if (ind != ADC_CLK) { + FILE_LOG(logERROR, ("Unknown clock index %d to get pipeline\n", ind)); + return -1; + } + return ((bus_r(ADC_OFFSET_REG) & ADC_OFFSET_ADC_PPLN_MSK) >> ADC_OFFSET_ADC_PPLN_OFST); } // patterns + uint64_t writePatternIOControl(uint64_t word) { if (word != -1) { - FILE_LOG(logINFO, ("Setting Pattern - I/O Control: 0x%llx\n", (long long int) word)); + FILE_LOG(logINFO, ("Setting Pattern I/O Control: 0x%llx\n", (long long int) word)); set64BitReg(word, PATTERN_IO_CNTRL_LSB_REG, PATTERN_IO_CNTRL_MSB_REG); } uint64_t retval = get64BitReg(PATTERN_IO_CNTRL_LSB_REG, PATTERN_IO_CNTRL_MSB_REG); - FILE_LOG(logDEBUG1, ("I/O Control: 0x%llx\n", (long long int) retval)); + FILE_LOG(logDEBUG1, (" I/O Control retval: 0x%llx\n", (long long int) retval)); return retval; } uint64_t writePatternClkControl(uint64_t word) { if (word != -1) { - FILE_LOG(logINFO, ("Setting Pattern - Clock Control: 0x%llx\n", (long long int) word)); + FILE_LOG(logINFO, ("Setting Pattern Clock Control: 0x%llx\n", (long long int) word)); set64BitReg(word, PATTERN_IO_CLK_CNTRL_LSB_REG, PATTERN_IO_CLK_CNTRL_MSB_REG); } uint64_t retval = get64BitReg(PATTERN_IO_CLK_CNTRL_LSB_REG, PATTERN_IO_CLK_CNTRL_MSB_REG); - FILE_LOG(logDEBUG1, ("Clock Control: 0x%llx\n", (long long int) retval)); + FILE_LOG(logDEBUG1, (" Clock Control retval: 0x%llx\n", (long long int) retval)); return retval; } uint64_t readPatternWord(int addr) { // error (handled in tcp) - if (addr < 0 || addr > MAX_PATTERN_LENGTH) { + if (addr < 0 || addr >= MAX_PATTERN_LENGTH) { FILE_LOG(logERROR, ("Cannot get Pattern - Word. Invalid addr 0x%x. " - "Should be <= 0x%x\n", addr, MAX_PATTERN_LENGTH)); + "Should be between 0 and 0x%x\n", addr, MAX_PATTERN_LENGTH)); return -1; } - FILE_LOG(logDEBUG1, (" Reading Pattern - Word (addr:0x%x)\n", addr)); + FILE_LOG(logINFORED, (" Reading (Executing) Pattern Word (addr:0x%x)\n", addr)); uint32_t reg = PATTERN_CNTRL_REG; // overwrite with only addr @@ -1496,7 +1478,7 @@ uint64_t readPatternWord(int addr) { // read value uint64_t retval = get64BitReg(PATTERN_OUT_LSB_REG, PATTERN_OUT_MSB_REG); - FILE_LOG(logDEBUG1, (" Word(addr:0x%x): 0x%llx\n", addr, (long long int) retval)); + FILE_LOG(logDEBUG1, (" Word(addr:0x%x) retval: 0x%llx\n", addr, (long long int) retval)); return retval; } @@ -1507,13 +1489,13 @@ uint64_t writePatternWord(int addr, uint64_t word) { return readPatternWord(addr); // error (handled in tcp) - if (addr < 0 || addr > MAX_PATTERN_LENGTH) { + if (addr < 0 || addr >= MAX_PATTERN_LENGTH) { FILE_LOG(logERROR, ("Cannot set Pattern - Word. Invalid addr 0x%x. " - "Should be <= 0x%x\n", addr, MAX_PATTERN_LENGTH)); + "Should be between 0 and 0x%x\n", addr, MAX_PATTERN_LENGTH)); return -1; } - FILE_LOG(logINFO, ("Setting Pattern - Word (addr:0x%x, word:0x%llx)\n", addr, (long long int) word)); + FILE_LOG(logINFO, ("Setting Pattern Word (addr:0x%x, word:0x%llx)\n", addr, (long long int) word)); uint32_t reg = PATTERN_CNTRL_REG; // write word @@ -1536,9 +1518,9 @@ uint64_t writePatternWord(int addr, uint64_t word) { int setPatternWaitAddress(int level, int addr) { // error (handled in tcp) - if (addr > MAX_PATTERN_LENGTH) { - FILE_LOG(logERROR, ("Cannot set Pattern - Wait Address. Invalid addr 0x%x. " - "Should be <= 0x%x\n", addr, MAX_PATTERN_LENGTH)); + if (addr >= MAX_PATTERN_LENGTH) { + FILE_LOG(logERROR, ("Cannot set Pattern Wait Address. Invalid addr 0x%x. " + "Should be between 0 and 0x%x\n", addr, MAX_PATTERN_LENGTH)); return -1; } @@ -1563,20 +1545,20 @@ int setPatternWaitAddress(int level, int addr) { mask = PATTERN_WAIT_2_ADDR_MSK; break; default: - FILE_LOG(logERROR, ("Cannot set Pattern - Wait Address. Invalid level 0x%x. " + FILE_LOG(logERROR, ("Cannot set Pattern Wait Address. Invalid level 0x%x. " "Should be between 0 and 2.\n", level)); return -1; } // set if (addr >= 0) { - FILE_LOG(logINFO, ("Setting Pattern - Wait Address (level:%d, addr:0x%x)\n", level, addr)); + FILE_LOG(logINFO, ("Setting Pattern Wait Address (level:%d, addr:0x%x)\n", level, addr)); bus_w(reg, ((addr << offset) & mask)); } // get - uint32_t regval = bus_r((reg & mask) >> offset); - FILE_LOG(logDEBUG1, (" Wait Address (level:%d, addr:0x%x)\n", level, regval)); + uint32_t regval = ((bus_r(reg) & mask) >> offset); + FILE_LOG(logDEBUG1, (" Wait Address retval (level:%d, addr:0x%x)\n", level, regval)); return regval; } @@ -1598,38 +1580,29 @@ uint64_t setPatternWaitTime(int level, uint64_t t) { regm = PATTERN_WAIT_TIMER_2_MSB_REG; break; default: - FILE_LOG(logERROR, ("Cannot set Pattern - Wait Time. Invalid level %d. " + FILE_LOG(logERROR, ("Cannot set Pattern Wait Time. Invalid level %d. " "Should be between 0 and 2.\n", level)); return -1; } // set if (t >= 0) { - FILE_LOG(logINFO, ("Setting Pattern - Wait Time (level:%d, t:%lld)\n", level, (long long int)t)); + FILE_LOG(logINFO, ("Setting Pattern Wait Time (level:%d, t:%lld)\n", level, (long long int)t)); set64BitReg(t, regl, regm); } // get uint64_t regval = get64BitReg(regl, regm); - FILE_LOG(logDEBUG1, (" Wait Time (level:%d, t:%lld)\n", level, (long long int)regval)); + FILE_LOG(logDEBUG1, (" Wait Time retval (level:%d, t:%lld)\n", level, (long long int)regval)); return regval; } void setPatternLoop(int level, int *startAddr, int *stopAddr, int *nLoop) { - // level 0-2, addr upto patternlength + 1 (checked at tcp) - if ((level != -1) && - (*startAddr > MAX_PATTERN_LENGTH || *stopAddr > MAX_PATTERN_LENGTH)) { - FILE_LOG(logERROR, ("Cannot set Pattern (Pattern Loop, level:%d, startaddr:0x%x, stopaddr:0x%x). " - "Addr must be <= 0x%x\n", - level, *startAddr, *stopAddr, MAX_PATTERN_LENGTH)); - } - - //level -1, addr upto patternlength (checked at tcp) - else if ((level == -1) && - (*startAddr > MAX_PATTERN_LENGTH || *stopAddr > MAX_PATTERN_LENGTH)) { - FILE_LOG(logERROR, ("Cannot set Pattern (Pattern Loop, complete pattern, startaddr:0x%x, stopaddr:0x%x). " - "Addr must be <= 0x%x\n", + // (checked at tcp) + if (*startAddr >= MAX_PATTERN_LENGTH || *stopAddr >= MAX_PATTERN_LENGTH) { + FILE_LOG(logERROR, ("Cannot set Pattern Loop, Address (startaddr:0x%x, stopaddr:0x%x) must be " + "less than 0x%x\n", *startAddr, *stopAddr, MAX_PATTERN_LENGTH)); } @@ -1676,7 +1649,7 @@ void setPatternLoop(int level, int *startAddr, int *stopAddr, int *nLoop) { break; default: // already checked at tcp interface - FILE_LOG(logERROR, ("Cannot set Pattern - Pattern loop. Invalid level %d. " + FILE_LOG(logERROR, ("Cannot set Pattern loop. Invalid level %d. " "Should be between -1 and 2.\n", level)); *startAddr = 0; *stopAddr = 0; @@ -1687,7 +1660,7 @@ void setPatternLoop(int level, int *startAddr, int *stopAddr, int *nLoop) { if (level >= 0) { // set iteration if (*nLoop >= 0) { - FILE_LOG(logINFO, ("Setting Pattern - Pattern Loop (level:%d, nLoop:%d)\n", + FILE_LOG(logINFO, ("Setting Pattern Loop (level:%d, nLoop:%d)\n", level, *nLoop)); bus_w(nLoopReg, *nLoop); } @@ -1695,9 +1668,9 @@ void setPatternLoop(int level, int *startAddr, int *stopAddr, int *nLoop) { } // set - if (*startAddr != -1 && *stopAddr != -1) { + if (*startAddr >= 0 && *stopAddr >= 0) { // writing start and stop addr - FILE_LOG(logINFO, ("Setting Pattern - Pattern Loop (level:%d, startaddr:0x%x, stopaddr:0x%x)\n", + FILE_LOG(logINFO, ("Setting Pattern Loop (level:%d, startaddr:0x%x, stopaddr:0x%x)\n", level, *startAddr, *stopAddr)); bus_w(addr, ((*startAddr << startOffset) & startMask) | ((*stopAddr << stopOffset) & stopMask)); FILE_LOG(logDEBUG1, ("Addr:0x%x, val:0x%x\n", addr, bus_r(addr))); @@ -1706,55 +1679,15 @@ void setPatternLoop(int level, int *startAddr, int *stopAddr, int *nLoop) { // get else { *startAddr = ((bus_r(addr) & startMask) >> startOffset); - FILE_LOG(logDEBUG1, ("Getting Pattern - Pattern Loop Start Address (level:%d, Read startAddr:0x%x)\n", + FILE_LOG(logDEBUG1, ("Getting Pattern Loop Start Address (level:%d, Read startAddr:0x%x)\n", level, *startAddr)); *stopAddr = ((bus_r(addr) & stopMask) >> stopOffset); - FILE_LOG(logDEBUG1, ("Getting Pattern - Pattern Loop Stop Address (level:%d, Read stopAddr:0x%x)\n", + FILE_LOG(logDEBUG1, ("Getting Pattern Loop Stop Address (level:%d, Read stopAddr:0x%x)\n", level, *stopAddr)); } } -int setLEDEnable(int enable) { - uint32_t addr = CONFIG_REG; - - // set - if (enable >= 0) { - FILE_LOG(logINFO, ("Switching LED %s\n", (enable > 0) ? "ON" : "OFF")); - // disable - if (enable == 0) { - bus_w(addr, bus_r(addr) | CONFIG_LED_DSBL_MSK); - } - // enable - else { - bus_w(addr, bus_r(addr) & (~CONFIG_LED_DSBL_MSK)); - } - } - // ~ to get the opposite - return (((~bus_r(addr)) & CONFIG_LED_DSBL_MSK) >> CONFIG_LED_DSBL_OFST); -} - -void setDigitalIODelay(uint64_t pinMask, int delay) { - FILE_LOG(logINFO, ("Setings Digital IO Delay (pinMask:0x%llx, delay: %d ps)\n", - (long long unsigned int)pinMask, delay)); - - int delayunit = delay / OUTPUT_DELAY_0_OTPT_STTNG_STEPS; - FILE_LOG(logDEBUG1, ("delay unit: 0x%x (steps of 25ps)\n", delayunit)); - - // set pin mask - bus_w(PIN_DELAY_1_REG, pinMask); - - uint32_t addr = OUTPUT_DELAY_0_REG; - // set delay - bus_w(addr, bus_r(addr) & (~OUTPUT_DELAY_0_OTPT_STTNG_MSK)); - bus_w(addr, (bus_r(addr) | ((delayunit << OUTPUT_DELAY_0_OTPT_STTNG_OFST) & OUTPUT_DELAY_0_OTPT_STTNG_MSK))); - - // load value - bus_w(addr, bus_r(addr) | OUTPUT_DELAY_0_OTPT_TRGGR_MSK); - - // trigger configuration - bus_w(addr, bus_r(addr) & (~OUTPUT_DELAY_0_OTPT_TRGGR_MSK)); -} void setPatternMask(uint64_t mask) { set64BitReg(mask, PATTERN_MASK_LSB_REG, PATTERN_MASK_MSB_REG); @@ -1772,6 +1705,7 @@ uint64_t getPatternBitMask() { return get64BitReg(PATTERN_SET_LSB_REG, PATTERN_SET_MSB_REG); } + /* aquisition */ int startStateMachine(){ @@ -1786,10 +1720,11 @@ int startStateMachine(){ FILE_LOG(logINFOGREEN, ("Virtual Acquisition started\n")); return OK; #endif + int send_to_10g = enableTenGigabitEthernet(-1); // 1 giga udp - if (!enableTenGigabitEthernet(-1)) { + if (send_to_10g == 0) { // create udp socket - if(createUDPSocket() != OK) { + if(createUDPSocket(0) != OK) { return FAIL; } // update header with modId, detType and version. Reset offset and fnum @@ -1797,9 +1732,10 @@ int startStateMachine(){ } FILE_LOG(logINFOBLUE, ("Starting State Machine\n")); - cleanFifos(); - unsetFifoReadStrobes(); // FIXME: unnecessary to write bus_w(dumm, 0) as it is 0 in the beginnig and the strobes are always unset if set + if (send_to_10g == 0) { + unsetFifoReadStrobes(); // FIXME: unnecessary to write bus_w(dumm, 0) as it is 0 in the beginnig and the strobes are always unset if set + } //start state machine bus_w(CONTROL_REG, bus_r(CONTROL_REG) | CONTROL_STRT_ACQSTN_MSK | CONTROL_STRT_EXPSR_MSK); @@ -1812,17 +1748,43 @@ int startStateMachine(){ #ifdef VIRTUAL void* start_timer(void* arg) { - int wait_in_s = (setTimer(FRAME_NUMBER, -1) * - setTimer(TRIGGER_NUMBER, -1) * - (setTimer(FRAME_PERIOD, -1)/(1E9))); - FILE_LOG(logDEBUG1, ("going to wait for %d s\n", wait_in_s)); - while(!virtual_stop && (wait_in_s >= 0)) { - usleep(1000 * 1000); - wait_in_s--; - } - FILE_LOG(logINFOGREEN, ("Virtual Timer Done\n")); + int64_t periodns = getPeriod(); + int numFrames = (getNumFrames() * + getNumTriggers() ); + int64_t exp_ns = getExpTime(); + int frameNr = 0; + // loop over number of frames + for(frameNr=0; frameNr!= numFrames; ++frameNr ) { + + //check if virtual_stop is high + if(virtual_stop == 1){ + break; + } + + // sleep for exposure time + struct timespec begin, end; + clock_gettime(CLOCK_REALTIME, &begin); + usleep(exp_ns / 1000); + clock_gettime(CLOCK_REALTIME, &end); + + // calculate time left in period + int64_t time_ns = ((end.tv_sec - begin.tv_sec) * 1E9 + + (end.tv_nsec - begin.tv_nsec)); + + // sleep for (period - exptime) + if (frameNr < numFrames) { // if there is a next frame + if (periodns > time_ns) { + usleep((periodns - time_ns)/ 1000); + } + } + + // set register frames left + } + + // set status to idle virtual_status = 0; + FILE_LOG(logINFOBLUE, ("Finished Acquiring\n")); return NULL; } #endif @@ -1839,6 +1801,7 @@ int stopStateMachine(){ bus_w(CONTROL_REG, bus_r(CONTROL_REG) & ~CONTROL_STP_ACQSTN_MSK); FILE_LOG(logINFO, ("Status Register: %08x\n",bus_r(STATUS_REG))); + return OK; } @@ -1863,7 +1826,7 @@ enum runStatus getRunStatus(){ // error //if (retval & STATUS_SM_FF_FLL_MSK) { This bit is high when a analog fifo is full Or when external stop - if (retval & STATUS_ANY_FF_FLL_MSK) { // if adc fifo is full + if (retval & STATUS_ANY_FF_FLL_MSK) { // if adc or digital fifo is full FILE_LOG(logINFORED, ("Status: Error (Any fifo full)\n")); return ERROR; } @@ -1908,9 +1871,9 @@ void readandSendUDPFrames(int *ret, char *mess) { FILE_LOG(logDEBUG1, ("Reading from 1G UDP\n")); // validate udp socket - if (getUdPSocketDescriptor() <= 0) { + if (getUdPSocketDescriptor(0) <= 0) { *ret = FAIL; - sprintf(mess,"UDP Socket not created. sockfd:%d\n", getUdPSocketDescriptor()); + sprintf(mess,"UDP Socket not created. sockfd:%d\n", getUdPSocketDescriptor(0)); FILE_LOG(logERROR, (mess)); return; } @@ -1919,24 +1882,24 @@ void readandSendUDPFrames(int *ret, char *mess) { while(readFrameFromFifo() == OK) { int bytesToSend = 0, n = 0; while((bytesToSend = fillUDPPacket(udpPacketData))) { - n += sendUDPPacket(udpPacketData, bytesToSend); + n += sendUDPPacket(0, udpPacketData, bytesToSend); } if (n >= dataBytes) { FILE_LOG(logINFO, (" Frame %lld sent (%d packets, %d databytes, n:%d bytes sent)\n", udpFrameNumber, udpPacketNumber + 1, dataBytes, n)); } } - closeUDPSocket(); + closeUDPSocket(0); } - void readFrame(int *ret, char *mess) { #ifdef VIRTUAL - while(virtual_status) { - //FILE_LOG(logERROR, ("Waiting for finished flag\n"); - usleep(5000); - } + // wait for acquisition to be done + while(runBusy()){ + usleep(500); // random + } + FILE_LOG(logINFOGREEN, ("acquisition successfully finished\n")); return; #endif // 1G @@ -1954,76 +1917,84 @@ void readFrame(int *ret, char *mess) { // ret could be fail in 1gudp for not creating udp sockets if (*ret != FAIL) { // frames left to give status - int64_t retval = getTimeLeft(FRAME_NUMBER) + 2; + int64_t retval = getNumFramesLeft() + 2; if ( retval > 1) { - *ret = (int)FAIL; sprintf(mess,"No data and run stopped: %lld frames left\n",(long long int)retval); FILE_LOG(logERROR, (mess)); } else { - *ret = (int)OK; FILE_LOG(logINFOGREEN, ("Acquisition successfully finished\n")); } } + *ret = (int)OK; } void unsetFifoReadStrobes() { - bus_w(DUMMY_REG, bus_r(DUMMY_REG) & (~DUMMY_ANLG_FIFO_RD_STRBE_MSK)); + bus_w(DUMMY_REG, bus_r(DUMMY_REG) & (~DUMMY_ANLG_FIFO_RD_STRBE_MSK) & (~DUMMY_DGTL_FIFO_RD_STRBE_MSK)); } void readSample(int ns) { - uint32_t addr = DUMMY_REG; - // read analog data - uint32_t fifoAddr = FIFO_DATA_REG; + uint32_t addr = DUMMY_REG; - // read strobe to all analog fifos - bus_w(addr, bus_r(addr) | DUMMY_ANLG_FIFO_RD_STRBE_MSK); - bus_w(addr, bus_r(addr) & (~DUMMY_ANLG_FIFO_RD_STRBE_MSK)); - // wait as it is connected directly to fifo running on a different clock - //usleep(WAIT_TIME_FIFO_RD_STROBE); - if (!(ns%1000)) { - FILE_LOG(logDEBUG1, ("Reading sample ns:%d of %d AEmtpy:0x%x AFull:0x%x Status:0x%x\n", - ns, nSamples, bus_r(FIFO_EMPTY_REG), bus_r(FIFO_FULL_REG), bus_r(STATUS_REG))); - } + // read adcs + if (ns < nSamples) { - // loop through all channels - int ich = 0; - for (ich = 0; ich < NCHAN; ++ich) { + uint32_t fifoAddr = FIFO_DATA_REG; - // if channel is in ROI - if ((1 << ich) & ~(adcDisableMask)) { + // read strobe to all analog fifos + bus_w(addr, bus_r(addr) | DUMMY_ANLG_FIFO_RD_STRBE_MSK); + bus_w(addr, bus_r(addr) & (~DUMMY_ANLG_FIFO_RD_STRBE_MSK)); - // unselect channel - bus_w(addr, bus_r(addr) & ~(DUMMY_FIFO_CHNNL_SLCT_MSK)); + // wait for 1 us to latch different clocks of read and read strobe + { + int i = 0; + for (i = 0; i < WAIT_TIME_1US_FOR_LOOP_CNT; ++i) + ; + } - // select channel - bus_w(addr, bus_r(addr) | ((ich << DUMMY_FIFO_CHNNL_SLCT_OFST) & DUMMY_FIFO_CHNNL_SLCT_MSK)); + if (!(ns%1000)) { + FILE_LOG(logDEBUG1, ("Reading sample ns:%d of %d AEmtpy:0x%x AFull:0x%x Status:0x%x\n", + ns, nSamples, bus_r(FIFO_EMPTY_REG), bus_r(FIFO_FULL_REG), bus_r(STATUS_REG))); + } - // read fifo and write it to current position of data pointer - *((uint16_t*)now_ptr) = bus_r16(fifoAddr); + // loop through all channels + int ich = 0; + for (ich = 0; ich < NCHAN; ++ich) { - // keep reading till the value is the same - /* while (*((uint16_t*)now_ptr) != bus_r16(fifoAddr)) { - FILE_LOG(logDEBUG1, ("%d ", ich)); - *((uint16_t*)now_ptr) = bus_r16(fifoAddr); - }*/ + // if channel is in enable mask + if ((1 << ich) & (adcEnableMask_1g)) { - // increment pointer to data out destination - now_ptr += 2; + // unselect channel + bus_w(addr, bus_r(addr) & ~(DUMMY_FIFO_CHNNL_SLCT_MSK)); + + // select channel + bus_w(addr, bus_r(addr) | ((ich << DUMMY_FIFO_CHNNL_SLCT_OFST) & DUMMY_FIFO_CHNNL_SLCT_MSK)); + + // read fifo and write it to current position of data pointer + *((uint16_t*)analogDataPtr) = bus_r16(fifoAddr); + + // keep reading till the value is the same + /* while (*((uint16_t*)analogDataPtr) != bus_r16(fifoAddr)) { + FILE_LOG(logDEBUG1, ("%d ", ich)); + *((uint16_t*)analogDataPtr) = bus_r16(fifoAddr); + }*/ + + // increment pointer to data out destination + analogDataPtr += 2; + } } } - } uint32_t checkDataInFifo() { uint32_t dataPresent = 0; - uint32_t analogFifoEmpty = bus_r(FIFO_EMPTY_REG); - FILE_LOG(logDEBUG2, ("Analog Fifo Empty (32 channels): 0x%x\n",analogFifoEmpty)); - dataPresent = (~analogFifoEmpty); - FILE_LOG(logDEBUG2, ("Data in Fifo :0x%x\n", dataPresent)); + uint32_t fifoEmpty = bus_r(FIFO_EMPTY_REG); + FILE_LOG(logINFO, ("Analog Fifo Empty (32 channels): 0x%08x\n", fifoEmpty)); + dataPresent = (~fifoEmpty); + FILE_LOG(logDEBUG2, ("Data in Fifo :0x%x\n", dataPresent)); return dataPresent; } -// only called for first sample +// only called for starting of a new frame int checkFifoForEndOfAcquisition() { uint32_t dataPresent = checkDataInFifo(); FILE_LOG(logDEBUG2, ("status:0x%x\n", bus_r(STATUS_REG))); @@ -2053,11 +2024,10 @@ int checkFifoForEndOfAcquisition() { return OK; } - int readFrameFromFifo() { int ns = 0; // point the data pointer to the starting position of data - now_ptr = ramValues; + analogDataPtr = analogData; // no data for this frame if (checkFifoForEndOfAcquisition() == FAIL) { @@ -2066,7 +2036,6 @@ int readFrameFromFifo() { // read Sample while(ns < nSamples) { - // chceck if no data in fifo, return ns?//FIXME: ask Anna readSample(ns); ns++; } @@ -2075,7 +2044,6 @@ int readFrameFromFifo() { return OK; } - uint32_t runBusy() { #ifdef VIRTUAL return virtual_status; @@ -2098,7 +2066,7 @@ int calculateDataBytes(){ return dataBytes; } -int getTotalNumberOfChannels(){return ((int)getNumberOfChannelsPerChip() * (int)getNumberOfChips());} +int getTotalNumberOfChannels() {return (getNumberOfChannelsPerChip() * getNumberOfChips());} int getNumberOfChips(){return NCHIP;} int getNumberOfDACs(){return NDAC;} int getNumberOfChannelsPerChip(){return NCHAN;} diff --git a/slsDetectorServers/moenchDetectorServer/slsDetectorServer_defs.h b/slsDetectorServers/moenchDetectorServer/slsDetectorServer_defs.h index c9b0247b9..2641a83d2 100755 --- a/slsDetectorServers/moenchDetectorServer/slsDetectorServer_defs.h +++ b/slsDetectorServers/moenchDetectorServer/slsDetectorServer_defs.h @@ -4,27 +4,51 @@ #define MIN_REQRD_VRSN_T_RD_API 0x180314 -#define REQRD_FRMWR_VRSN 0x180314 +#define REQRD_FRMWR_VRSN 0x200302 -#define CTRL_SRVR_INIT_TIME_US (300 * 1000) +#define CTRL_SRVR_INIT_TIME_US (2 * 1000 * 1000) /* Struct Definitions */ -typedef struct ip_header_struct { - uint16_t ip_len; - uint8_t ip_tos; - uint8_t ip_ihl:4 ,ip_ver:4; - uint16_t ip_offset:13,ip_flag:3; - uint16_t ip_ident; - uint16_t ip_chksum; - uint8_t ip_protocol; - uint8_t ip_ttl; - uint32_t ip_sourceip; - uint32_t ip_destip; -} ip_header; +typedef struct udp_header_struct { + uint32_t udp_destmac_msb; + uint16_t udp_srcmac_msb; + uint16_t udp_destmac_lsb; + uint32_t udp_srcmac_lsb; + uint8_t ip_tos; + uint8_t ip_ihl: 4, ip_ver: 4; + uint16_t udp_ethertype; + uint16_t ip_identification; + uint16_t ip_totallength; + uint8_t ip_protocol; + uint8_t ip_ttl; + uint16_t ip_fragmentoffset: 13, ip_flags: 3; + uint16_t ip_srcip_msb; + uint16_t ip_checksum; + uint16_t ip_destip_msb; + uint16_t ip_srcip_lsb; + uint16_t udp_srcport; + uint16_t ip_destip_lsb; + uint16_t udp_checksum; + uint16_t udp_destport; +} udp_header; + +#define IP_HEADER_SIZE (20) +#define UDP_IP_HEADER_LENGTH_BYTES (28) /* Enums */ +enum DACINDEX {MO_VBP_COLBUF, MO_VIPRE, MO_VIN_CM, MO_VB_SDA, MO_VCASC_SFP, MO_VOUT_CM, MO_VIPRE_CDS, MO_IBIAS_SFP}; +#define DEFAULT_DAC_VALS { 1300, /* MO_VBP_COLBUF */ \ + 1000, /* MO_VIPRE */ \ + 1400, /* MO_VIN_CM */ \ + 680, /* MO_VB_SDA */ \ + 1428, /* MO_VCASC_SFP */ \ + 1200, /* MO_VOUT_CM */ \ + 800, /* MO_VIPRE_CDS */ \ + 900 /* MO_IBIAS_SFP */ \ + }; + enum CLKINDEX {RUN_CLK, ADC_CLK, SYNC_CLK, DBIT_CLK, NUM_CLOCKS}; -enum DACINDEX {D0, D1, D2, D3, D4, D5, D6, D7}; +#define CLK_NAMES "run", "adc", "sync", "dbit" /* Hardware Definitions */ #define NCHAN (32) @@ -33,12 +57,13 @@ enum DACINDEX {D0, D1, D2, D3, D4, D5, D6, D7}; #define DYNAMIC_RANGE (16) #define NUM_BYTES_PER_PIXEL (DYNAMIC_RANGE / 8) #define CLK_FREQ (156.25) /* MHz */ +#define NSAMPLES_PER_ROW (25) /** Default Parameters */ #define DEFAULT_DATA_BYTES (NCHIP * NCHAN * NUM_BITS_PER_PIXEL) -#define DEFAULT_NUM_SAMPLES (1) +#define DEFAULT_NUM_SAMPLES (5000) #define DEFAULT_EXPTIME (0) -#define DEFAULT_NUM_FRAMES (100 * 1000 * 1000) +#define DEFAULT_NUM_FRAMES (1) #define DEFAULT_NUM_CYCLES (1) #define DEFAULT_PERIOD (1 * 1000 * 1000) //ns #define DEFAULT_DELAY (0) @@ -46,35 +71,37 @@ enum DACINDEX {D0, D1, D2, D3, D4, D5, D6, D7}; #define DEFAULT_VLIMIT (-100) #define DEFAULT_TIMING_MODE (AUTO_TIMING) #define DEFAULT_TX_UDP_PORT (0x7e9a) -#define DEFAULT_RUN_CLK (40) -#define DEFAULT_ADC_CLK (20) -#define DEFAULT_SYNC_CLK (20) -#define DEFAULT_DBIT_CLK (200) +#define DEFAULT_RUN_CLK (40) +#define DEFAULT_ADC_CLK (20) +#define DEFAULT_SYNC_CLK (20) +#define DEFAULT_DBIT_CLK (20) +#define DEFAULT_ADC_PHASE_DEG (30) +#define DEFAULT_PIPELINE (14) #define HIGHVOLTAGE_MIN (60) -#define HIGHVOLTAGE_MAX (200) +#define HIGHVOLTAGE_MAX (200) // min dac val #define DAC_MIN_MV (0) #define DAC_MAX_MV (2500) /* Defines in the Firmware */ -#define MAX_PATTERN_LENGTH (0x7FFF) +#define MAX_PATTERN_LENGTH (0x2000) #define DIGITAL_IO_DELAY_MAXIMUM_PS ((OUTPUT_DELAY_0_OTPT_STTNG_MSK >> OUTPUT_DELAY_0_OTPT_STTNG_OFST) * OUTPUT_DELAY_0_OTPT_STTNG_STEPS) #define MAX_PHASE_SHIFTS_STEPS (8) #define WAIT_TME_US_FR_ACQDONE_REG (100) // wait time in us after acquisition done to ensure there is no data in fifo #define WAIT_TIME_US_PLL (10 * 1000) #define WAIT_TIME_US_STP_ACQ (100) -#define WAIT_TIME_CONFIGURE_MAC (500 * 1000) +#define WAIT_TIME_CONFIGURE_MAC (2 * 1000 * 1000) #define WAIT_TIME_PATTERN_READ (10) -#define WAIT_TIME_FIFO_RD_STROBE (10) +#define WAIT_TIME_1US_FOR_LOOP_CNT (50) // around 30 is 1 us in blackfin /* MSB & LSB DEFINES */ #define MSB_OF_64_BIT_REG_OFST (32) #define LSB_OF_64_BIT_REG_OFST (0) -#define BIT_32_MSK (0xFFFFFFFF) +#define BIT32_MSK (0xFFFFFFFF) +#define BIT16_MASK (0xFFFF) -#define IP_PACKETSIZE (0x2032) -#define ADC_PORT_INVERT_VAL (0x453b2593) //FIXME: a default value? -#define MAXIMUM_ADC_CLK (40) +#define ADC_PORT_INVERT_VAL (0x4a342593) +#define MAXIMUM_ADC_CLK (20) #define PLL_VCO_FREQ_MHZ (800) diff --git a/slsDetectorServers/slsDetectorServer/include/slsDetectorFunctionList.h b/slsDetectorServers/slsDetectorServer/include/slsDetectorFunctionList.h index e0295aa1c..71696a9c7 100755 --- a/slsDetectorServers/slsDetectorServer/include/slsDetectorFunctionList.h +++ b/slsDetectorServers/slsDetectorServer/include/slsDetectorFunctionList.h @@ -3,6 +3,14 @@ #ifdef GOTTHARDD #include "clogger.h" // runState(enum TLogLevel) #endif +#ifndef VIRTUAL +#if defined(MYTHEN3D) || defined(GOTTHARD2D) +#include "programFpgaNios.h" +#elif defined(CHIPTESTBOARDD) || defined(JUNGFRAUD) || defined(MOENCHD) +#include "programFpgaBlackfin.h" +#endif +#endif + #include #include // FILE #include @@ -84,7 +92,7 @@ int updateDatabytesandAllocateRAM(); void updateDataBytes(); #endif -#if defined(GOTTHARDD) || defined(JUNGFRAUD) || defined(MYTHEN3D) +#if defined(GOTTHARDD) || defined(JUNGFRAUD) || defined(MYTHEN3D) || defined(MOENCHD) int setDefaultDacs(); #endif #ifdef GOTTHARD2D @@ -141,6 +149,8 @@ void setADCEnableMask_10G(uint32_t mask); uint32_t getADCEnableMask_10G(); void setADCInvertRegister(uint32_t val); uint32_t getADCInvertRegister(); +#endif +#if defined(CHIPTESTBOARDD) int setExternalSamplingSource(int val); int setExternalSampling(int val); #endif @@ -213,6 +223,8 @@ int64_t getStorageCellDelay(); #if defined(CHIPTESTBOARDD) || defined(MOENCHD) int setNumAnalogSamples(int val); int getNumAnalogSamples(); +#endif +#ifdef CHIPTESTBOARDD int setNumDigitalSamples(int val); int getNumDigitalSamples(); #endif @@ -298,11 +310,9 @@ void setPower(enum DACINDEX ind, int val); void powerOff(); #endif -#ifndef MOENCHD -#if !defined(MYTHEN3D) && !defined(GOTTHARD2D) +#if !defined(MOENCHD) && !defined(MYTHEN3D) && !defined(GOTTHARD2D) int getADC(enum ADCINDEX ind); #endif -#endif int setHighVoltage(int val); @@ -358,6 +368,7 @@ int enableTenGigabitEthernet(int val); // moench specific - powerchip #ifdef MOENCHD int powerChip (int on); +int setAnalogOnlyReadout(); #endif // chip test board or moench specific - configure frequency, phase, pll, flashing firmware @@ -383,8 +394,10 @@ uint64_t writePatternWord(int addr, uint64_t word); int setPatternWaitAddress(int level, int addr); uint64_t setPatternWaitTime(int level, uint64_t t); void setPatternLoop(int level, int *startAddr, int *stopAddr, int *nLoop); +#ifdef CHIPTESTBOARDD int setLEDEnable(int enable); void setDigitalIODelay(uint64_t pinMask, int delay); +#endif void setPatternMask(uint64_t mask); uint64_t getPatternMask(); void setPatternBitMask(uint64_t mask); diff --git a/slsDetectorServers/slsDetectorServer/src/slsDetectorServer_funcs.c b/slsDetectorServers/slsDetectorServer/src/slsDetectorServer_funcs.c index 51170c764..42137d235 100755 --- a/slsDetectorServers/slsDetectorServer/src/slsDetectorServer_funcs.c +++ b/slsDetectorServers/slsDetectorServer/src/slsDetectorServer_funcs.c @@ -2,13 +2,6 @@ #include "slsDetectorFunctionList.h" #include "communication_funcs.h" #include "clogger.h" -#ifndef VIRTUAL -#if defined(MYTHEN3D) || defined(GOTTHARD2D) -#include "programFpgaNios.h" -#elif defined(CHIPTESTBOARDD) || defined(JUNGFRAUD) || defined(MOENCHD) -#include "programFpgaBlackfin.h" -#endif -#endif #include #include @@ -928,10 +921,35 @@ int set_dac(int file_des) { case V_LIMIT: break; #elif MOENCHD + case VBP_COLBUF: + serverDacIndex = MO_VBP_COLBUF; + break; + case VIPRE: + serverDacIndex = MO_VIPRE; + break; + case VIN_CM: + serverDacIndex = MO_VIN_CM; + break; + case VB_SDA: + serverDacIndex = MO_VB_SDA; + break; + case VCASC_SFP: + serverDacIndex = MO_VCASC_SFP; + break; + case VOUT_CM: + serverDacIndex = MO_VOUT_CM; + break; + case VIPRE_CDS: + serverDacIndex = MO_VIPRE_CDS; + break; + case IBIAS_SFP: + serverDacIndex = MO_IBIAS_SFP; + break; case ADC_VPP: case HIGH_VOLTAGE: case V_LIMIT: break; + #elif MYTHEN3D case HIGH_VOLTAGE: break; @@ -1056,17 +1074,13 @@ int set_dac(int file_des) { serverDacIndex = J_VREF_COMP; break; #endif + default: #ifdef CHIPTESTBOARDD if (ind < NDAC_ONLY) { serverDacIndex = ind; break; } -#elif MOENCHD - if (ind < NDAC) { - serverDacIndex = ind; - break; - } #endif modeNotImplemented("Dac Index", (int)ind); break; @@ -1750,18 +1764,23 @@ int start_acquisition(int file_des) { FILE_LOG(logDEBUG1, ("Starting Acquisition\n")); // only set if (Server_VerifyLock() == OK) { -#if defined(CHIPTESTBOARDD) || defined(MOENCHD) - int mode = getReadoutMode(); - int asamples = getNumAnalogSamples(); - int dsamples = getNumDigitalSamples(); - if ((mode == ANALOG_AND_DIGITAL || mode == ANALOG_ONLY) && (asamples <= 0)) { +#if defined(MOENCHD) + if (getNumAnalogSamples() <= 0) { ret = FAIL; - sprintf(mess, "Could not start acquisition. Invalid number of analog samples: %d.\n", asamples); + sprintf(mess, "Could not start acquisition. Invalid number of analog samples: %d.\n", getNumAnalogSamples()); FILE_LOG(logERROR,(mess)); } - else if ((mode == ANALOG_AND_DIGITAL || mode == DIGITAL_ONLY) && (dsamples <= 0)) { + else +#endif +#if defined(CHIPTESTBOARDD) + if ((getReadoutMode() == ANALOG_AND_DIGITAL || mode == ANALOG_ONLY) && (getNumAnalogSamples() <= 0)) { ret = FAIL; - sprintf(mess, "Could not start acquisition. Invalid number of digital samples: %d.\n", dsamples); + sprintf(mess, "Could not start acquisition. Invalid number of analog samples: %d.\n", getNumAnalogSamples()); + FILE_LOG(logERROR,(mess)); + } + else if ((getReadoutMode() == ANALOG_AND_DIGITAL || mode == DIGITAL_ONLY) && (getNumDigitalSamples() <= 0)) { + ret = FAIL; + sprintf(mess, "Could not start acquisition. Invalid number of digital samples: %d.\n", getNumDigitalSamples()); FILE_LOG(logERROR,(mess)); } else @@ -1880,18 +1899,23 @@ int start_and_read_all(int file_des) { FILE_LOG(logDEBUG1, ("Starting Acquisition\n")); // only set if (Server_VerifyLock() == OK) { -#if defined(CHIPTESTBOARDD) || defined(MOENCHD) - int mode = getReadoutMode(); - int asamples = getNumAnalogSamples(); - int dsamples = getNumDigitalSamples(); - if ((mode == ANALOG_AND_DIGITAL || mode == ANALOG_ONLY) && (asamples <= 0)) { +#if defined(MOENCHD) + if (getNumAnalogSamples() <= 0) { ret = FAIL; - sprintf(mess, "Could not start acquisition. Invalid number of analog samples: %d.\n", asamples); + sprintf(mess, "Could not start acquisition. Invalid number of analog samples: %d.\n", getNumAnalogSamples()); FILE_LOG(logERROR,(mess)); } - else if ((mode == ANALOG_AND_DIGITAL || mode == DIGITAL_ONLY) && (dsamples <= 0)) { + else +#endif +#if defined(CHIPTESTBOARDD) + if ((getReadoutMode() == ANALOG_AND_DIGITAL || mode == ANALOG_ONLY) && (getNumAnalogSamples() <= 0)) { ret = FAIL; - sprintf(mess, "Could not start acquisition. Invalid number of digital samples: %d.\n", dsamples); + sprintf(mess, "Could not start acquisition. Invalid number of analog samples: %d.\n", getNumAnalogSamples()); + FILE_LOG(logERROR,(mess)); + } + else if ((getReadoutMode() == ANALOG_AND_DIGITAL || mode == DIGITAL_ONLY) && (getNumDigitalSamples() <= 0)) { + ret = FAIL; + sprintf(mess, "Could not start acquisition. Invalid number of digital samples: %d.\n", getNumDigitalSamples()); FILE_LOG(logERROR,(mess)); } else @@ -2102,14 +2126,23 @@ int set_num_analog_samples(int file_des) { #else // only set if (Server_VerifyLock() == OK) { - ret = setNumAnalogSamples(arg); - if (ret == FAIL) { - sprintf(mess, "Could not set number of analog samples to %d. Could not allocate RAM\n", arg); - FILE_LOG(logERROR,(mess)); - } else { - int retval = getNumAnalogSamples(); - FILE_LOG(logDEBUG1, ("retval num analog samples %d\n", retval)); - validate(arg, retval, "set number of analog samples", DEC); +#ifdef MOENCHD + if (arg % NSAMPLES_PER_ROW != 0) { + ret = FAIL; + sprintf(mess, "Could not set number of analog samples to %d. Must be divisible by %d\n", arg, NSAMPLES_PER_ROW); + FILE_LOG(logERROR,(mess)); + } +#endif + if (ret == OK) { + ret = setNumAnalogSamples(arg); + if (ret == FAIL) { + sprintf(mess, "Could not set number of analog samples to %d. Could not allocate RAM\n", arg); + FILE_LOG(logERROR,(mess)); + } else { + int retval = getNumAnalogSamples(); + FILE_LOG(logDEBUG1, ("retval num analog samples %d\n", retval)); + validate(arg, retval, "set number of analog samples", DEC); + } } } #endif @@ -2121,7 +2154,7 @@ int get_num_digital_samples(int file_des) { memset(mess, 0, sizeof(mess)); int retval = -1; -#if !defined(CHIPTESTBOARDD) && !defined(MOENCHD) +#if !defined(CHIPTESTBOARDD) functionNotImplemented(); #else // get only @@ -2140,7 +2173,7 @@ int set_num_digital_samples(int file_des) { return printSocketReadError(); FILE_LOG(logDEBUG1, ("Setting number of digital samples %d\n", arg)); -#if !defined(CHIPTESTBOARDD) && !defined(MOENCHD) +#if !defined(CHIPTESTBOARDD) functionNotImplemented(); #else // only set @@ -2856,10 +2889,16 @@ int send_update(int file_des) { #endif #if defined(CHIPTESTBOARDD) || defined(MOENCHD) + // analog samples + i32 = getNumAnalogSamples(); + n = sendData(file_des,&i32,sizeof(i32),INT32); + if (n < 0) return printSocketReadError(); + // 1g adcmask i32 = getADCEnableMask(); n = sendData(file_des,&i32,sizeof(i32),INT32); if (n < 0) return printSocketReadError(); + // 10g adc mask i32 = getADCEnableMask_10G(); n = sendData(file_des,&i32,sizeof(i32),INT32); @@ -4237,7 +4276,7 @@ int led(int file_des) { return printSocketReadError(); FILE_LOG(logDEBUG1, ("Setting led enable to %d\n", arg)); -#if (!defined(MOENCHD)) && (!defined(CHIPTESTBOARDD)) +#if (!defined(CHIPTESTBOARDD)) functionNotImplemented(); #else // set & get @@ -4262,7 +4301,7 @@ int digital_io_delay(int file_des) { return printSocketReadError(); FILE_LOG(logDEBUG1, ("Digital IO Delay, pinMask: 0x%llx, delay:%d ps\n", args[0], (int)args[1])); -#if (!defined(MOENCHD)) && (!defined(CHIPTESTBOARDD)) +#if (!defined(CHIPTESTBOARDD)) functionNotImplemented(); #else // only set @@ -6169,9 +6208,11 @@ int set_pipeline(int file_des) { case ADC_CLOCK: c = ADC_CLK; break; +#ifdef CHIPTESTBOARDD case DBIT_CLOCK: c = DBIT_CLK; break; +#endif default: modeNotImplemented("clock index (pipeline set)", ind); break; diff --git a/slsDetectorSoftware/include/Detector.h b/slsDetectorSoftware/include/Detector.h index eab4b6f9c..ce8128602 100644 --- a/slsDetectorSoftware/include/Detector.h +++ b/slsDetectorSoftware/include/Detector.h @@ -155,32 +155,32 @@ class Detector { void setPeriod(ns t, Positions pos = {}); - /** [Gotthard][Jungfrau][CTB][Mythen3][Gotthard2] */ + /** [Gotthard][Jungfrau][CTB][Moench][Mythen3][Gotthard2] */ Result getDelayAfterTrigger(Positions pos = {}) const; - /** [Gotthard][Jungfrau][CTB][Mythen3][Gotthard2] */ + /** [Gotthard][Jungfrau][CTB][Moench][Mythen3][Gotthard2] */ void setDelayAfterTrigger(ns value, Positions pos = {}); - /** [Gotthard][Jungfrau][CTB][Mythen3] + /** [Gotthard][Jungfrau][CTB][Moench][Mythen3] * [Gotthard2] only in continuous mode */ Result getNumberOfFramesLeft(Positions pos = {}) const; - /** [Gotthard][Jungfrau][CTB][Mythen3] + /** [Gotthard][Jungfrau][CTB][Moench][Mythen3] * [Gotthard2] only in continuous mode */ Result getNumberOfTriggersLeft(Positions pos = {}) const; - /** [Gotthard][Jungfrau][CTB][Mythen3] + /** [Gotthard][Jungfrau][CTB][Moench][Mythen3] * [Gotthard2] only in continuous mode */ Result getPeriodLeft(Positions pos = {}) const; - /** [Gotthard][Jungfrau][CTB][Mythen3] + /** [Gotthard][Jungfrau][CTB][Moench][Mythen3] * [Gotthard2] only in continuous mode */ Result getDelayAfterTriggerLeft(Positions pos = {}) const; Result getTimingMode(Positions pos = {}) const; /** - * [Gotthard][Jungfrau][CTB] Options: AUTO_TIMING, TRIGGER_EXPOSURE + * [Gotthard][Jungfrau][CTB][Moench] Options: AUTO_TIMING, TRIGGER_EXPOSURE * [Eiger] Options: AUTO_TIMING, TRIGGER_EXPOSURE, GATED, BURST_TRIGGER */ void setTimingMode(defs::timingMode value, Positions pos = {}); @@ -192,19 +192,19 @@ class Detector { * Options: FULL_SPEED, HALF_SPEED, QUARTER_SPEED */ void setSpeed(defs::speedLevel value, Positions pos = {}); - /** [Gotthard][Jungfrau][CTB] */ + /** [Gotthard][Jungfrau][CTB][Moench] */ Result getADCPhase(Positions pos = {}) const; - /** [Gotthard][Jungfrau][CTB] */ + /** [Gotthard][Jungfrau][CTB][Moench] */ void setADCPhase(int value, Positions pos = {}); - /** [Jungfrau][CTB] */ + /** [Jungfrau][CTB][Moench] */ Result getMaxADCPhaseShift(Positions pos = {}) const; - /** [Gotthard][Jungfrau][CTB] */ + /** [Gotthard][Jungfrau][CTB][Moench] */ Result getADCPhaseInDegrees(Positions pos = {}) const; - /** [Gotthard][Jungfrau][CTB] */ + /** [Gotthard][Jungfrau][CTB][Moench] */ void setADCPhaseInDegrees(int value, Positions pos = {}); /** [Mythen3][Gotthard2] Hz */ @@ -244,7 +244,7 @@ class Detector { /** * [Gotthard] Options: 0, 90, 110, 120, 150, 180, 200 - * [Jungfrau], CTB Options: 0, 60 - 200 + * [Jungfrau][CTB][Moench] Options: 0, 60 - 200 * [Eiger][Mythen3][Gotthard2] Options: 0 - 200 */ void setHighVoltage(int value, Positions pos = {}); @@ -415,10 +415,10 @@ class Detector { Result printRxConfiguration(Positions pos = {}) const; - /** [Eiger][CTB] */ + /** [Eiger][CTB][Moench] */ Result getTenGiga(Positions pos = {}) const; - /** [Eiger][CTB] */ + /** [Eiger][CTB][Moench] */ void setTenGiga(bool value, Positions pos = {}); /** [Eiger, Jungfrau] */ @@ -954,18 +954,67 @@ class Detector { /** [Mythen3] countermask bit set for each counter enabled */ void setCounterMask(uint32_t countermask, Positions pos = {}); + /************************************************** + * * + * CTB / Moench Specific * + * * + * ************************************************/ + /** [CTB][Moench] */ + Result getNumberOfAnalogSamples(Positions pos = {}) const; + + /** [CTB][Moench] */ + void setNumberOfAnalogSamples(int value, Positions pos = {}); + + /** [CTB][Moench] */ + Result getADCClock(Positions pos = {}) const; + + /** [CTB][Moench] */ + void setADCClock(int value_in_MHz, Positions pos = {}); + + /** [CTB][Moench] */ + Result getRUNClock(Positions pos = {}) const; + + /** [CTB][Moench] */ + void setRUNClock(int value_in_MHz, Positions pos = {}); + + /** [CTB][Moench] */ + Result getSYNCClock(Positions pos = {}) const; + + /** [CTB][Moench] */ + Result getADCPipeline(Positions pos = {}) const; + + /** [CTB][Moench] */ + void setADCPipeline(int value, Positions pos = {}); + + /** [CTB][Moench] */ + Result getVoltage(defs::dacIndex index, Positions pos = {}) const; + + /** + * [CTB][Moench] mV + * [Ctb] Options: V_LIMIT, V_POWER_A, V_POWER_B, V_POWER_C, + * V_POWER_D, V_POWER_IO, V_POWER_CHIP + * [Moench] Options: V_LIMIT + */ + void setVoltage(defs::dacIndex index, int value, Positions pos = {}); + + /** [CTB][Moench] */ + Result getADCEnableMask(Positions pos = {}) const; + + /** [CTB][Moench] */ + void setADCEnableMask(uint32_t mask, Positions pos = {}); + + /** [CTB][Moench] */ + Result getTenGigaADCEnableMask(Positions pos = {}) const; + + /** [CTB][Moench] */ + void setTenGigaADCEnableMask(uint32_t mask, Positions pos = {}); + /************************************************** * * * CTB Specific * * * * ************************************************/ - /** [CTB] */ - Result getNumberOfAnalogSamples(Positions pos = {}) const; - - /** [CTB] */ - void setNumberOfAnalogSamples(int value, Positions pos = {}); - /** [CTB] */ Result getNumberOfDigitalSamples(Positions pos = {}) const; @@ -978,6 +1027,12 @@ class Detector { /** [CTB] Options: ANALOG_ONLY = 0, DIGITAL_ONLY = 1, ANALOG_AND_DIGITAL */ void setReadoutMode(defs::readoutMode value, Positions pos = {}); + /** [CTB] */ + Result getDBITClock(Positions pos = {}) const; + + /** [CTB] */ + void setDBITClock(int value_in_MHz, Positions pos = {}); + /** [CTB] */ Result getDBITPhase(Positions pos = {}) const; @@ -993,49 +1048,12 @@ class Detector { /** [CTB] */ void setDBITPhaseInDegrees(int value, Positions pos = {}); - /** [CTB] */ - Result getADCClock(Positions pos = {}) const; - - /** [CTB] */ - void setADCClock(int value_in_MHz, Positions pos = {}); - - /** [CTB] */ - Result getDBITClock(Positions pos = {}) const; - - /** [CTB] */ - void setDBITClock(int value_in_MHz, Positions pos = {}); - - /** [CTB] */ - Result getRUNClock(Positions pos = {}) const; - - /** [CTB] */ - void setRUNClock(int value_in_MHz, Positions pos = {}); - - /** [CTB] */ - Result getSYNCClock(Positions pos = {}) const; - - /** [CTB] */ - Result getADCPipeline(Positions pos = {}) const; - - /** [CTB] */ - void setADCPipeline(int value, Positions pos = {}); - /** [CTB] */ Result getDBITPipeline(Positions pos = {}) const; /** [CTB] */ void setDBITPipeline(int value, Positions pos = {}); - /** [CTB] */ - Result getVoltage(defs::dacIndex index, Positions pos = {}) const; - - /** - * [CTB] mV - * Options: V_LIMIT, V_POWER_A, V_POWER_B, V_POWER_C, - * V_POWER_D, V_POWER_IO, V_POWER_CHIP - */ - void setVoltage(defs::dacIndex index, int value, Positions pos = {}); - /** * [CTB] mV * Options: V_POWER_A, V_POWER_B, V_POWER_C, V_POWER_D, V_POWER_IO */ @@ -1051,24 +1069,6 @@ class Detector { /** [CTB] Options: SLOW_ADC0 - SLOW_ADC7 in uV */ Result getSlowADC(defs::dacIndex index, Positions pos = {}) const; - /** [CTB]*/ - Result getADCEnableMask(Positions pos = {}) const; - - /** [CTB]*/ - void setADCEnableMask(uint32_t mask, Positions pos = {}); - - /** [CTB]*/ - Result getTenGigaADCEnableMask(Positions pos = {}) const; - - /** [CTB]*/ - void setTenGigaADCEnableMask(uint32_t mask, Positions pos = {}); - - /** [CTB] */ - Result getADCInvert(Positions pos = {}) const; - - /** [CTB]*/ - void setADCInvert(uint32_t value, Positions pos = {}); - /** [CTB] */ Result getExternalSamplingSource(Positions pos = {}) const; @@ -1113,72 +1113,71 @@ class Detector { * * * ************************************************/ - /** [CTB] */ + /** [CTB][Moench][Mythen3] */ void setPattern(const std::string &fname, Positions pos = {}); - /** [CTB] */ + /** [CTB][Moench][Mythen3] */ void savePattern(const std::string &fname); - /** [CTB] */ + /** [CTB][Moench][Mythen3] */ Result getPatternIOControl(Positions pos = {}) const; - /** [CTB] */ + /** [CTB][Moench][Mythen3] */ void setPatternIOControl(uint64_t word, Positions pos = {}); - /** [CTB] */ + /** [CTB][Moench][Mythen3] */ Result getPatternClockControl(Positions pos = {}) const; - /** [CTB] */ + /** [CTB][Moench][Mythen3] */ void setPatternClockControl(uint64_t word, Positions pos = {}); - /** [CTB] same as executing - * [Mythen3] */ + /** [CTB][Moench][Mythen3] same as executing for ctb and moench */ Result getPatternWord(int addr, Positions pos = {}); /** [CTB] Caution: If word is -1 reads the addr (same as * executing the pattern) - * [Mythen3] */ + * [Mythen3][Moench] */ void setPatternWord(int addr, uint64_t word, Positions pos = {}); - /**[CTB][Mythen3] Options: level: -1 (complete pattern) and 0-2 levels + /**[CTB][Moench][Mythen3] Options: level: -1 (complete pattern) and 0-2 levels * @returns array of start address and stop address */ Result> getPatternLoopAddresses(int level, Positions pos = {}) const; - /** [CTB][Mythen3] Options: level: -1 (complete pattern) and 0-2 levels */ + /** [CTB][Moench][Mythen3] Options: level: -1 (complete pattern) and 0-2 levels */ void setPatternLoopAddresses(int level, int start, int stop, Positions pos = {}); - /**[CTB][Mythen3] Options: level: -1 (complete pattern) and 0-2 levels + /**[CTB][Moench][Mythen3] Options: level: -1 (complete pattern) and 0-2 levels * @returns number of loops */ Result getPatternLoopCycles(int level, Positions pos = {}) const; - /** [CTB][Mythen3] n: 0-2, level: -1 (complete pattern) and 0-2 levels */ + /** [CTB][Moench][Mythen3] n: 0-2, level: -1 (complete pattern) and 0-2 levels */ void setPatternLoopCycles(int level, int n, Positions pos = {}); - /* [CTB][Mythen3] */ + /* [CTB][Moench][Mythen3] */ Result getPatternWaitAddr(int level, Positions pos = {}) const; - /** [CTB][Mythen3] Options: level 0-2 */ + /** [CTB][Moench][Mythen3] Options: level 0-2 */ void setPatternWaitAddr(int level, int addr, Positions pos = {}); - /** [CTB][Mythen3] */ + /** [CTB][Moench][Mythen3] */ Result getPatternWaitTime(int level, Positions pos = {}) const; - /** [CTB][Mythen3] Options: level 0-2 */ + /** [CTB][Moench][Mythen3] Options: level 0-2 */ void setPatternWaitTime(int level, uint64_t t, Positions pos = {}); - /** [CTB][Mythen3] */ + /** [CTB][Moench][Mythen3] */ Result getPatternMask(Positions pos = {}); - /** [CTB][Mythen3] Sets the mask applied to every pattern to the selected bit mask */ + /** [CTB][Moench][Mythen3] Sets the mask applied to every pattern to the selected bit mask */ void setPatternMask(uint64_t mask, Positions pos = {}); - /** [CTB][Mythen3] */ + /** [CTB][Moench][Mythen3] */ Result getPatternBitMask(Positions pos = {}) const; - /** [CTB][Mythen3] Sets the bitmask that the mask will be applied to for every + /** [CTB][Moench][Mythen3] Sets the bitmask that the mask will be applied to for every * pattern */ void setPatternBitMask(uint64_t mask, Positions pos = {}); @@ -1238,26 +1237,26 @@ class Detector { * * * ************************************************/ - /** [Jungfrau][CTB] fname is a pof file + /** [Jungfrau][CTB][Moench] fname is a pof file * [Mythen3][Gotthard2] fname is an rbf file */ void programFPGA(const std::string &fname, Positions pos = {}); - /** [Jungfrau][CTB] */ + /** [Jungfrau][CTB][Moench] */ void resetFPGA(Positions pos = {}); - /** [Jungfrau][Gotthard][CTB] + /** [Jungfrau][Gotthard][CTB][Moench] * Copy detector server fname from tftp folder of hostname to detector * Also changes respawn server, which is effective after a reboot. */ void copyDetectorServer(const std::string &fname, const std::string &hostname, Positions pos = {}); - /** [Jungfrau][Gotthard][CTB][Mythen3][Gotthard2] */ + /** [Jungfrau][Gotthard][CTB][Moench][Mythen3][Gotthard2] */ void rebootController(Positions pos = {}); /** - * [Jungfrau][Gotthard][CTB] + * [Jungfrau][Gotthard][CTB][Moench] * Updates the firmware, detector server and then reboots detector * controller blackfin. * @param sname name of detector server binary found on tftp folder of host @@ -1278,13 +1277,13 @@ class Detector { void clearBit(uint32_t addr, int bitnr, Positions pos = {}); - /** [Gotthard][Jungfrau][Mythen3][Gotthard2][CTB] */ + /** [Gotthard][Jungfrau][Mythen3][Gotthard2][CTB][Moench] */ void executeFirmwareTest(Positions pos = {}); - /** [Gotthard][Jungfrau][Mythen3][Gotthard2][CTB] */ + /** [Gotthard][Jungfrau][Mythen3][Gotthard2][CTB][Moench] */ void executeBusTest(Positions pos = {}); - /** [Gotthard][Jungfrau][CTB] not possible to read back*/ + /** [Gotthard][Jungfrau][CTB][Moench] not possible to read back*/ void writeAdcRegister(uint32_t addr, uint32_t value, Positions pos = {}); bool getInitialChecks() const; @@ -1293,6 +1292,12 @@ class Detector { * default enabled */ void setInitialChecks(const bool value); + /** [CTB][Moench][Jungfrau] */ + Result getADCInvert(Positions pos = {}) const; + + /** [CTB][Moench][Jungfrau] */ + void setADCInvert(uint32_t value, Positions pos = {}); + /************************************************** * * * Insignificant * @@ -1321,15 +1326,15 @@ class Detector { /** Execute a command on the detector server console */ void executeCommand(const std::string &value, Positions pos = {}); - /** [Jungfrau][Mythen3][CTB] + /** [Jungfrau][Mythen3][CTB][Moench] * [Gotthard2] only in continuous mode */ Result getNumberOfFramesFromStart(Positions pos = {}) const; - /** [Jungfrau][Mythen3][CTB] Get time from detector start + /** [Jungfrau][Mythen3][CTB][Moench] Get time from detector start * [Gotthard2] only in continuous mode */ Result getActualTime(Positions pos = {}) const; - /** [Jungfrau][Mythen3][CTB] Get timestamp at a frame start + /** [Jungfrau][Mythen3][CTB][Moench] Get timestamp at a frame start * [Gotthard2] only in continuous mode */ Result getMeasurementTime(Positions pos = {}) const; diff --git a/slsDetectorSoftware/src/CmdProxy.cpp b/slsDetectorSoftware/src/CmdProxy.cpp index 0d72860f4..add741892 100644 --- a/slsDetectorSoftware/src/CmdProxy.cpp +++ b/slsDetectorSoftware/src/CmdProxy.cpp @@ -395,10 +395,10 @@ std::string CmdProxy::Adcphase(int action) { std::ostringstream os; os << cmd << ' '; if (action == defs::HELP_ACTION) { - os << "[n_value] [(optional)deg]\n\t[Jungfrau][Ctb][Gotthard] Phase " + os << "[n_value] [(optional)deg]\n\t[Jungfrau][Ctb][Moench][Moench][Gotthard] Phase " "shift of ADC clock. \n\t[Jungfrau] Absolute phase shift. If deg " "used, then shift in degrees. Changing Speed also resets " - "adcphase to recommended defaults.\n\t[Ctb] Absolute phase " + "adcphase to recommended defaults.\n\t[Ctb][Moench] Absolute phase " "shift. If deg used, then shift in degrees. Changing adcclk also " "resets adcphase and sets it to previous values.\n\t[Gotthard] " "Relative phase shift" @@ -588,8 +588,10 @@ std::string CmdProxy::Dac(int action) { os << cmd << ' '; if (action == defs::HELP_ACTION) { os << "[dac index] [dac or mv value] [(optional unit) mv] " - "\n\t[Ctb][Jungfrau] Dac." + "\n\t[Ctb] Dac." << '\n'; + } else if (det->getDetectorType().squash(defs::GENERIC) != defs::CHIPTESTBOARD) { + throw sls::RuntimeError("Dac command can only be used for chip test board. Use daclist to get list of dac commands for current detector."); } else if (action == defs::GET_ACTION) { bool mv = false; if (args.size() == 2) { @@ -707,6 +709,11 @@ std::vector CmdProxy::DacCommands() { "vth1", "vicin", "vcas", "vpreamp", "vpl", "vipre", "viinsh", "vph", "vtrim", "vdcsh"}; break; + case defs::MOENCH: + return std::vector{"vbp_colbuf", "vipre", "vin_cm", + "vb_sda", "vcasc_sfp", "vout_cm", + "vipre_cds", "ibias_sfp"}; + break; case defs::CHIPTESTBOARD: return std::vector{ "dac 0", "dac 1", "dac 2", "dac 3", "dac 4", "dac 5", @@ -1316,26 +1323,29 @@ std::string CmdProxy::Counters(int action) { return os.str(); } -/* CTB Specific */ +/* CTB / Moench Specific */ std::string CmdProxy::Samples(int action) { std::ostringstream os; os << cmd << ' '; if (action == defs::HELP_ACTION) { os << "[n_samples]\n\t[CTB] Number of samples (both analog and " - "digitial) expected." + "digitial) expected.\n\t[Moench] Number of samples (analog only)" << '\n'; } else if (action == defs::GET_ACTION) { if (!args.empty()) { WrongNumberOfParameters(0); } auto a = det->getNumberOfAnalogSamples({det_id}); - auto d = det->getNumberOfDigitalSamples({det_id}); - int as = a.squash(-1); - int ds = d.squash(-1); - if (as == -1 || ds == -1 || as != ds) { // check if a == d? - throw sls::RuntimeError( + // get also digital samples for ctb and compare with analog + if (det->getDetectorType().squash() == defs::CHIPTESTBOARD) { + auto d = det->getNumberOfDigitalSamples({det_id}); + int as = a.squash(-1); + int ds = d.squash(-1); + if (as == -1 || ds == -1 || as != ds) { // check if a == d? + throw sls::RuntimeError( "Different samples. Use asamples or dsamples."); + } } os << OutString(a) << '\n'; } else if (action == defs::PUT_ACTION) { @@ -1343,7 +1353,10 @@ std::string CmdProxy::Samples(int action) { WrongNumberOfParameters(1); } det->setNumberOfAnalogSamples(std::stoi(args[0]), {det_id}); - det->setNumberOfDigitalSamples(std::stoi(args[0]), {det_id}); + // set also digital samples for ctb + if (det->getDetectorType().squash() == defs::CHIPTESTBOARD) { + det->setNumberOfDigitalSamples(std::stoi(args[0]), {det_id}); + } os << args.front() << '\n'; } else { throw sls::RuntimeError("Unknown action"); @@ -1351,6 +1364,8 @@ std::string CmdProxy::Samples(int action) { return os.str(); } +/* CTB Specific */ + std::string CmdProxy::Dbitphase(int action) { std::ostringstream os; os << cmd << ' '; @@ -1499,7 +1514,7 @@ std::string CmdProxy::Pattern(int action) { std::ostringstream os; os << cmd << ' '; if (action == defs::HELP_ACTION) { - os << "[fname]\n\t[Mythen3][Ctb] Loads binary pattern file with only pattern " + os << "[fname]\n\t[Mythen3][Moench][Ctb][Moench] Loads binary pattern file with only pattern " "words" << '\n'; } else if (action == defs::GET_ACTION) { @@ -1520,7 +1535,7 @@ std::string CmdProxy::PatternWord(int action) { std::ostringstream os; os << cmd << ' '; if (action == defs::HELP_ACTION) { - os << "[step or address] [64 bit mask]\n\t[Ctb][Mythen3] 64 bit pattern at " + os << "[step or address] [64 bit mask]\n\t[Ctb][Moench][Mythen3] 64 bit pattern at " "address of pattern memory." << '\n'; } else if (action == defs::GET_ACTION) { @@ -1546,17 +1561,17 @@ std::string CmdProxy::PatternLoopAddresses(int action) { os << cmd << ' '; if (action == defs::HELP_ACTION) { if (cmd == "patlimits") { - os << "[start addr] [stop addr] \n\t[Ctb][Mythen3] Limits of complete " + os << "[start addr] [stop addr] \n\t[Ctb][Moench][Mythen3] Limits of complete " "pattern." << '\n'; } else if (cmd == "patloop0") { - os << "[start addr] [stop addr] \n\t[Ctb][Mythen3] Limits of loop 0." + os << "[start addr] [stop addr] \n\t[Ctb][Moench][Mythen3] Limits of loop 0." << '\n'; } else if (cmd == "patloop1") { - os << "[start addr] [stop addr] \n\t[Ctb][Mythen3] Limits of loop 1." + os << "[start addr] [stop addr] \n\t[Ctb][Moench][Mythen3] Limits of loop 1." << '\n'; } else if (cmd == "patloop2") { - os << "[start addr] [stop addr] \n\t[Ctb][Mythen3] Limits of loop 2." + os << "[start addr] [stop addr] \n\t[Ctb][Moench][Mythen3] Limits of loop 2." << '\n'; } else { throw sls::RuntimeError( @@ -1601,11 +1616,11 @@ std::string CmdProxy::PatternLoopCycles(int action) { os << cmd << ' '; if (action == defs::HELP_ACTION) { if (cmd == "patnloop0") { - os << "[n_cycles] \n\t[Ctb][Mythen3] Number of cycles of loop 0." << '\n'; + os << "[n_cycles] \n\t[Ctb][Moench][Mythen3] Number of cycles of loop 0." << '\n'; } else if (cmd == "patnloop1") { - os << "[n_cycles] \n\t[Ctb][Mythen3] Number of cycles of loop 1." << '\n'; + os << "[n_cycles] \n\t[Ctb][Moench][Mythen3] Number of cycles of loop 1." << '\n'; } else if (cmd == "patnloop2") { - os << "[n_cycles] \n\t[Ctb][Mythen3] Number of cycles of loop 2." << '\n'; + os << "[n_cycles] \n\t[Ctb][Moench][Mythen3] Number of cycles of loop 2." << '\n'; } else { throw sls::RuntimeError( "Unknown command, use list to list all commands"); @@ -1646,11 +1661,11 @@ std::string CmdProxy::PatternWaitAddress(int action) { os << cmd << ' '; if (action == defs::HELP_ACTION) { if (cmd == "patwait0") { - os << "[addr] \n\t[Ctb][Mythen3] Wait 0 address." << '\n'; + os << "[addr] \n\t[Ctb][Moench][Mythen3] Wait 0 address." << '\n'; } else if (cmd == "patwait1") { - os << "[addr] \n\t[Ctb][Mythen3] Wait 1 address." << '\n'; + os << "[addr] \n\t[Ctb][Moench][Mythen3] Wait 1 address." << '\n'; } else if (cmd == "patwait2") { - os << "[addr] \n\t[Ctb][Mythen3] Wait 2 address." << '\n'; + os << "[addr] \n\t[Ctb][Moench][Mythen3] Wait 2 address." << '\n'; } else { throw sls::RuntimeError( "Unknown command, use list to list all commands"); @@ -1691,11 +1706,11 @@ std::string CmdProxy::PatternWaitTime(int action) { os << cmd << ' '; if (action == defs::HELP_ACTION) { if (cmd == "patwaittime0") { - os << "[n_clk] \n\t[Ctb][Mythen3] Wait 0 time in clock cycles." << '\n'; + os << "[n_clk] \n\t[Ctb][Moench][Mythen3] Wait 0 time in clock cycles." << '\n'; } else if (cmd == "patwaittime1") { - os << "[n_clk] \n\t[Ctb][Mythen3] Wait 1 time in clock cycles." << '\n'; + os << "[n_clk] \n\t[Ctb][Moench][Mythen3] Wait 1 time in clock cycles." << '\n'; } else if (cmd == "patwaittime2") { - os << "[n_clk] \n\t[Ctb][Mythen3] Wait 2 time in clock cycles." << '\n'; + os << "[n_clk] \n\t[Ctb][Moench][Mythen3] Wait 2 time in clock cycles." << '\n'; } else { throw sls::RuntimeError( "Unknown command, use list to list all commands"); @@ -1811,7 +1826,7 @@ std::string CmdProxy::ProgramFpga(int action) { std::ostringstream os; os << cmd << ' '; if (action == defs::HELP_ACTION) { - os << "[fname.pof | fname.rbf]\n\t[Jungfrau][Ctb] Programs FPGA from pof file." + os << "[fname.pof | fname.rbf]\n\t[Jungfrau][Ctb][Moench] Programs FPGA from pof file." << "\n\t[Mythen3][Gotthard2] Programs FPGA from rbf file." << '\n'; } else if (action == defs::GET_ACTION) { @@ -1832,7 +1847,7 @@ std::string CmdProxy::CopyDetectorServer(int action) { std::ostringstream os; os << cmd << ' '; if (action == defs::HELP_ACTION) { - os << "[server_name] [pc_host_name]\n\t[Jungfrau][Ctb] Copies detector " + os << "[server_name] [pc_host_name]\n\t[Jungfrau][Ctb][Moench] Copies detector " "server via tftp from pc and changes respawn server name in " "/etc/inittab of detector." << '\n'; @@ -1854,7 +1869,7 @@ std::string CmdProxy::UpdateFirmwareAndDetectorServer(int action) { std::ostringstream os; os << cmd << ' '; if (action == defs::HELP_ACTION) { - os << "[server_name] [pc_host_name] [fname.pof]\n\t[Jungfrau][Ctb] " + os << "[server_name] [pc_host_name] [fname.pof]\n\t[Jungfrau][Ctb][Moench] " "Updates detector server via tftp from pc, updates firmware to " "pof file and then reboots controller (blackfin)." << '\n'; @@ -1904,7 +1919,7 @@ std::string CmdProxy::AdcRegister(int action) { std::ostringstream os; os << cmd << ' '; if (action == defs::HELP_ACTION) { - os << "[address] [value]\n\t[Jungfrau][Ctb][Gotthard] Writes to an adc " + os << "[address] [value]\n\t[Jungfrau][Ctb][Moench][Gotthard] Writes to an adc " "register in hex." << '\n'; } else if (action == defs::GET_ACTION) { diff --git a/slsDetectorSoftware/src/CmdProxy.h b/slsDetectorSoftware/src/CmdProxy.h index 1a5adeca4..d5d072df0 100644 --- a/slsDetectorSoftware/src/CmdProxy.h +++ b/slsDetectorSoftware/src/CmdProxy.h @@ -666,6 +666,12 @@ class CmdProxy { {"vb_pixbuf", &CmdProxy::vb_pixbuf}, {"vin_com", &CmdProxy::vin_com}, {"vdd_prot", &CmdProxy::vdd_prot}, + {"vbp_colbuf", &CmdProxy::vbp_colbuf}, + {"vb_sda", &CmdProxy::vb_sda}, + {"vcasc_sfp", &CmdProxy::vcasc_sfp}, + {"vipre_cds", &CmdProxy::vipre_cds}, + {"ibias_sfp", &CmdProxy::ibias_sfp}, + {"dac", &CmdProxy::Dac}, {"daclist", &CmdProxy::DacList}, @@ -796,20 +802,24 @@ class CmdProxy { /* Mythen3 Specific */ {"counters", &CmdProxy::Counters}, - /* CTB Specific */ + /* CTB/ Moench Specific */ {"samples", &CmdProxy::Samples}, {"asamples", &CmdProxy::asamples}, - {"dsamples", &CmdProxy::dsamples}, - {"romode", &CmdProxy::romode}, - {"dbitphase", &CmdProxy::Dbitphase}, - {"maxdbitphaseshift", &CmdProxy::maxdbitphaseshift}, {"adcclk", &CmdProxy::adcclk}, - {"dbitclk", &CmdProxy::dbitclk}, {"runclk", &CmdProxy::runclk}, {"syncclk", &CmdProxy::syncclk}, {"adcpipeline", &CmdProxy::adcpipeline}, - {"dbitpipeline", &CmdProxy::dbitpipeline}, {"v_limit", &CmdProxy::v_limit}, + {"adcenable", &CmdProxy::adcenable}, + {"adcenable10g", &CmdProxy::adcenable10g}, + + /* CTB Specific */ + {"dsamples", &CmdProxy::dsamples}, + {"romode", &CmdProxy::romode}, + {"dbitclk", &CmdProxy::dbitclk}, + {"dbitphase", &CmdProxy::Dbitphase}, + {"maxdbitphaseshift", &CmdProxy::maxdbitphaseshift}, + {"dbitpipeline", &CmdProxy::dbitpipeline}, {"v_a", &CmdProxy::v_a}, {"v_b", &CmdProxy::v_b}, {"v_c", &CmdProxy::v_c}, @@ -827,9 +837,6 @@ class CmdProxy { {"im_d", &CmdProxy::im_d}, {"im_io", &CmdProxy::im_io}, {"adc", &CmdProxy::SlowAdc}, - {"adcenable", &CmdProxy::adcenable}, - {"adcenable10g", &CmdProxy::adcenable10g}, - {"adcinvert", &CmdProxy::adcinvert}, {"extsampling", &CmdProxy::extsampling}, {"extsamplingsrc", &CmdProxy::extsamplingsrc}, {"rx_dbitlist", &CmdProxy::ReceiverDbitList}, @@ -881,6 +888,7 @@ class CmdProxy { {"firmwaretest", &CmdProxy::firmwaretest}, {"bustest", &CmdProxy::bustest}, {"initialchecks", &CmdProxy::InitialChecks}, + {"adcinvert", &CmdProxy::adcinvert}, /* Insignificant */ {"port", &CmdProxy::port}, @@ -955,8 +963,9 @@ class CmdProxy { std::string BurstMode(int action); /* Mythen3 Specific */ std::string Counters(int action); - /* CTB Specific */ + /* CTB/ Moench Specific */ std::string Samples(int action); + /* CTB Specific */ std::string Dbitphase(int action); std::string SlowAdc(int action); std::string ReceiverDbitList(int action); @@ -1034,38 +1043,38 @@ class CmdProxy { "\n\t[Gotthard2] Uploaded to detector just before acquisition starts"); TIME_COMMAND(delay, getDelayAfterTrigger, setDelayAfterTrigger, - "[duration] [(optional unit) ns|us|ms|s]\n\t[Jungfrau][Gotthard][Mythen3][Gotthard2][Ctb] Delay after trigger"); + "[duration] [(optional unit) ns|us|ms|s]\n\t[Jungfrau][Gotthard][Mythen3][Gotthard2][Ctb][Moench] Delay after trigger"); TIME_COMMAND(burstperiod, getBurstPeriod, setBurstPeriod, "[duration] [(optional unit) ns|us|ms|s]\n\t[Gotthard2] Burst period. Only in burst mode and auto timing mode."); GET_COMMAND(framesl, getNumberOfFramesLeft, - "\n\t[Gotthard][Jungfrau][Mythen3][Gotthard2][CTB] Number of frames left in acquisition." + "\n\t[Gotthard][Jungfrau][Mythen3][Gotthard2][CTB][Moench] Number of frames left in acquisition." "\n\t[Gotthard2] only in continuous mode."); GET_COMMAND(triggersl, getNumberOfTriggersLeft, - "\n\t[Gotthard][Jungfrau][Mythen3][Gotthard2][CTB] Number of triggers left in acquisition." + "\n\t[Gotthard][Jungfrau][Mythen3][Gotthard2][CTB][Moench] Number of triggers left in acquisition." "\n\t[Gotthard2] only in continuous mode."); TIME_GET_COMMAND(delayl, getDelayAfterTriggerLeft, - "\n\t[Gotthard][Jungfrau][Mythen3][Gotthard2][CTB] DelayLeft Delay Left in Acquisition." + "\n\t[Gotthard][Jungfrau][Mythen3][Gotthard2][CTB][Moench] DelayLeft Delay Left in Acquisition." "\n\t[Gotthard2] only in continuous mode."); TIME_GET_COMMAND(periodl, getPeriodLeft, - "\n\t[Gotthard][Jungfrau][Mythen3][Gotthard2][CTB] Period left for current frame." + "\n\t[Gotthard][Jungfrau][Mythen3][Gotthard2][CTB][Moench] Period left for current frame." "\n\t[Gotthard2] only in continuous mode."); INTEGER_COMMAND(timing, getTimingMode, setTimingMode, sls::StringTo, - "[auto|trigger|gating|burst_trigger]\n\tTiming Mode of detector.\n\t[Jungfrau][Gotthard][Mythen3][Gotthard2][Ctb] [auto|trigger]\n\t[Eiger] [auto|trigger|gating|burst_trigger]"); + "[auto|trigger|gating|burst_trigger]\n\tTiming Mode of detector.\n\t[Jungfrau][Gotthard][Mythen3][Gotthard2][Ctb][Moench] [auto|trigger]\n\t[Eiger] [auto|trigger|gating|burst_trigger]"); GET_COMMAND(maxadcphaseshift, getMaxADCPhaseShift, - "\n\t[Jungfrau][CTB] Absolute maximum Phase shift of ADC clock."); + "\n\t[Jungfrau][CTB][Moench] Absolute maximum Phase shift of ADC clock."); INTEGER_COMMAND(vhighvoltage, getHighVoltage, setHighVoltage, std::stoi, "[n_value]\n\tHigh voltage to the sensor in Voltage." "\n\t[Gotthard] [0|90|110|120|150|180|200]" "\n\t[Eiger][Mythen3][Gotthard2] 0-200" - "\n\t[Jungfrau][Ctb] [0|60-200]"); + "\n\t[Jungfrau][Ctb][Moench] [0|60-200]"); INTEGER_COMMAND(powerchip, getPowerChip, setPowerChip, std::stoi, "[0, 1]\n\t[Jungfrau][Mythen3][Gotthard2] Power the chip. Default 0." @@ -1169,13 +1178,13 @@ class CmdProxy { "[dac or mv value][(optional unit) mv] \n\t[Gotthard] Dac for ?? "); //TODO DAC_COMMAND(vout_cm, getDAC, setDAC, defs::VOUT_CM, - "[dac or mv value][(optional unit) mv] \n\t[Gotthard] Dac for ?? "); //TODO + "[dac or mv value][(optional unit) mv] \n\t[Gotthard] Dac for ?? \n\t[Moench] Dac for 5"); //TODO DAC_COMMAND(vcasc_out, getDAC, setDAC, defs::VCASC_OUT, "[dac or mv value][(optional unit) mv] \n\t[Gotthard] Dac for ?? "); //TODO DAC_COMMAND(vin_cm, getDAC, setDAC, defs::VIN_CM, - "[dac or mv value][(optional unit) mv] \n\t[Gotthard] Dac for ?? "); //TODO + "[dac or mv value][(optional unit) mv] \n\t[Gotthard] Dac for ?? \n\t[Moench] Dac for 2"); //TODO DAC_COMMAND(vref_comp, getDAC, setDAC, defs::VREF_COMP, "[dac or mv value][(optional unit) mv] \n\t[Gotthard][Jungfrau] Dac for ?? "); //TODO @@ -1193,7 +1202,7 @@ class CmdProxy { "[dac or mv value][(optional unit) mv] \n\t[Mythen3] voltage to define feedback resistance of the second shaper."); DAC_COMMAND(vipre, getDAC, setDAC, defs::VIPRE, - "[dac or mv value][(optional unit) mv] \n\t[Mythen3] Dac for the preamplifier's input transistor current."); + "[dac or mv value][(optional unit) mv] \n\t[Mythen3] Dac for the preamplifier's input transistor current.\n\t[Moench] Dac for 1"); DAC_COMMAND(viinsh, getDAC, setDAC, defs::VIINSH, "[dac or mv value][(optional unit) mv] \n\t[Mythen3] Dac for the bias current for the shaper."); @@ -1274,7 +1283,7 @@ class CmdProxy { "[dac or mv value][(optional unit) mv] \n\t[Gotthard2] Dac for common mode voltage of ADC DAC bank 2."); DAC_COMMAND(adcvpp, getDAC, setDAC, defs::ADC_VPP, - "[dac or mv value][(optional unit) mv] \n\t[Ctb] Vpp of ADC.\n\t 0 -> 1V ; 1 -> 1.14V ; 2 -> 1.33V ; 3 -> 1.6V ; 4 -> 2V."); + "[dac or mv value][(optional unit) mv] \n\t[Ctb][Moench] Vpp of ADC.\n\t 0 -> 1V ; 1 -> 1.14V ; 2 -> 1.33V ; 3 -> 1.6V ; 4 -> 2V."); DAC_COMMAND(vb_ds, getDAC, setDAC, defs::VB_DS, "[dac or mv value][(optional unit) mv] \n\t[Jungfrau] Dac for ??"); //TODO @@ -1291,6 +1300,21 @@ class CmdProxy { DAC_COMMAND(vdd_prot, getDAC, setDAC, defs::VDD_PROT, "[dac or mv value][(optional unit) mv] \n\t[Jungfrau] Dac for ??"); //TODO + DAC_COMMAND(vbp_colbuf, getDAC, setDAC, defs::VBP_COLBUF, + "[dac or mv value][(optional unit) mv] \n\t[Moench] Dac for 0"); + + DAC_COMMAND(vb_sda, getDAC, setDAC, defs::VB_SDA, + "[dac or mv value][(optional unit) mv] \n\t[Moench] Dac for 3"); + + DAC_COMMAND(vcasc_sfp, getDAC, setDAC, defs::VCASC_SFP, + "[dac or mv value][(optional unit) mv] \n\t[Moench] Dac for 4"); + + DAC_COMMAND(vipre_cds, getDAC, setDAC, defs::VIPRE_CDS, + "[dac or mv value][(optional unit) mv] \n\t[Moench] Dac for 6"); + + DAC_COMMAND(ibias_sfp, getDAC, setDAC, defs::IBIAS_SFP, + "[dac or mv value][(optional unit) mv] \n\t[Moench] Dac for 7"); + /* on chip dacs */ INTEGER_USER_IND_COMMAND(vchip_comp_fe, getOnChipDAC, setOnChipDAC, stoiHex, defs::VB_COMP_FE, @@ -1391,7 +1415,7 @@ class CmdProxy { "\n\tPrints the receiver configuration."); INTEGER_COMMAND(tengiga, getTenGiga, setTenGiga, std::stoi, - "[0, 1]\n\t[Eiger][Ctb] 10GbE Enable."); + "[0, 1]\n\t[Eiger][Ctb][Moench] 10GbE Enable."); INTEGER_COMMAND(flowcontrol10g, getTenGigaFlowControl, setTenGigaFlowControl, std::stoi, "[0, 1]\n\t[Eiger][Jungfrau] 10GbE Flow Control."); @@ -1574,10 +1598,34 @@ class CmdProxy { /* Mythen3 Specific */ - /* CTB Specific */ + /* CTB/ Moench Specific */ INTEGER_COMMAND(asamples, getNumberOfAnalogSamples, setNumberOfAnalogSamples, std::stoi, - "[0, 1]\n\t[CTB] Number of analog samples expected."); + "[0, 1]\n\t[CTB][Moench] Number of analog samples expected."); + + INTEGER_COMMAND(adcclk, getADCClock, setADCClock, std::stoi, + "[n_clk in MHz]\n\t[Ctb][Moench] ADC clock frequency in MHz."); + + INTEGER_COMMAND(runclk, getRUNClock, setRUNClock, std::stoi, + "[n_clk in MHz]\n\t[Ctb][Moench] Run clock in MHz."); + + GET_COMMAND(syncclk, getSYNCClock, + "[n_clk in MHz]\n\t[Ctb][Moench] Sync clock in MHz."); + + INTEGER_COMMAND(adcpipeline, getADCPipeline, setADCPipeline, std::stoi, + "[n_value]\n\t[Ctb][Moench] Pipeline for ADC clock."); + + INTEGER_IND_COMMAND(v_limit, getVoltage, setVoltage, std::stoi, defs::V_LIMIT, + "[n_value]\n\t[Ctb][Moench] Soft limit for power supplies(ctb only) and DACS in mV."); + + INTEGER_COMMAND_HEX(adcenable, getADCEnableMask, setADCEnableMask, stoiHex, + "[bitmask]\n\t[Ctb][Moench] ADC Enable Mask for 1Gb Mode for each 32 ADC channel."); + + INTEGER_COMMAND_HEX(adcenable10g, getTenGigaADCEnableMask, setTenGigaADCEnableMask, stoiHex, + "[bitmask]\n\t[Ctb][Moench] ADC Enable Mask for 10Gb mode for each 32 ADC channel. However, if any of consecutive 4 bits are enabled, the complete 4 bits are enabled."); + + /* CTB Specific */ + INTEGER_COMMAND(dsamples, getNumberOfDigitalSamples, setNumberOfDigitalSamples, std::stoi, "[0, 1]\n\t[CTB] Number of digital samples expected."); @@ -1585,30 +1633,15 @@ class CmdProxy { INTEGER_COMMAND(romode, getReadoutMode, setReadoutMode, sls::StringTo, "[analog|digital|analog_digital]\n\t[CTB] Readout mode. Default is analog."); - GET_COMMAND(maxdbitphaseshift, getMaxDBITPhaseShift, - "\n\t[CTB] Absolute maximum Phase shift of of the clock to latch digital bits."); - - INTEGER_COMMAND(adcclk, getADCClock, setADCClock, std::stoi, - "[n_clk in MHz]\n\t[Ctb] ADC clock frequency in MHz."); - INTEGER_COMMAND(dbitclk, getDBITClock, setDBITClock, std::stoi, "[n_clk in MHz]\n\t[Ctb] Clock for latching the digital bits in MHz."); - INTEGER_COMMAND(runclk, getRUNClock, setRUNClock, std::stoi, - "[n_clk in MHz]\n\t[Ctb] Run clock in MHz."); - - GET_COMMAND(syncclk, getSYNCClock, - "[n_clk in MHz]\n\t[Ctb] Synch clock in MHz."); - - INTEGER_COMMAND(adcpipeline, getADCPipeline, setADCPipeline, std::stoi, - "[n_value]\n\t[Ctb] Pipeline for ADC clock."); + GET_COMMAND(maxdbitphaseshift, getMaxDBITPhaseShift, + "\n\t[CTB] Absolute maximum Phase shift of of the clock to latch digital bits."); INTEGER_COMMAND(dbitpipeline, getDBITPipeline, setDBITPipeline, std::stoi, "[n_value]\n\t[Ctb] Pipeline of the clock for latching digital bits."); - INTEGER_IND_COMMAND(v_limit, getVoltage, setVoltage, std::stoi, defs::V_LIMIT, - "[n_value]\n\t[Ctb] Soft limit for power supplies and DACS in mV."); - INTEGER_IND_COMMAND(v_a, getVoltage, setVoltage, std::stoi, defs::V_POWER_A, "[n_value]\n\t[Ctb] Voltage supply a in mV."); @@ -1655,16 +1688,7 @@ class CmdProxy { "\n\t[Ctb] Measured current of power supply d in mA."); GET_IND_COMMAND(im_io, getMeasuredCurrent, defs::I_POWER_IO, "", - "\n\t[Ctb] Measured current of power supply io in mA."); - - INTEGER_COMMAND_HEX(adcenable, getADCEnableMask, setADCEnableMask, stoiHex, - "[bitmask]\n\t[Ctb] ADC Enable Mask for 1Gb Mode for each 32 ADC channel."); - - INTEGER_COMMAND_HEX(adcenable10g, getTenGigaADCEnableMask, setTenGigaADCEnableMask, stoiHex, - "[bitmask]\n\t[Ctb] ADC Enable Mask for 10Gb mode for each 32 ADC channel. However, if any of consecutive 4 bits are enabled, the complete 4 bits are enabled."); - - INTEGER_COMMAND_HEX(adcinvert, getADCInvert, setADCInvert, stoiHex, - "[bitmask]\n\t[Ctb][Jungfrau] ADC Inversion Mask.\n\t[Jungfrau] Inversions on top of the default mask."); + "\n\t[Ctb] Measured current of power supply io in mA."); INTEGER_COMMAND(extsampling, getExternalSampling, setExternalSampling, std::stoi, "[0, 1]\n\t[Ctb] Enable for external sampling signal to extsamplingsrc signal for digital data. For advanced users only."); @@ -1682,19 +1706,19 @@ class CmdProxy { /* Pattern */ EXECUTE_SET_COMMAND_NOID_1ARG(savepattern, savePattern, - "[fname]\n\t[Ctb] Saves pattern to file (ascii). Also executes pattern."); + "[fname]\n\t[Ctb][Moench][Mythen3] Saves pattern to file (ascii). Also executes pattern."); INTEGER_COMMAND_HEX(patioctrl, getPatternIOControl, setPatternIOControl, stoulHex, - "[64 bit mask]\n\t[Ctb] 64 bit mask defining input (0) and output (1) signals."); + "[64 bit mask]\n\t[Ctb][Moench][Mythen3] 64 bit mask defining input (0) and output (1) signals."); INTEGER_COMMAND_HEX(patclkctrl, getPatternClockControl, setPatternClockControl, stoulHex, - "[64 bit mask]\n\t[Ctb] 64 bit mask defining output clock enable."); + "[64 bit mask]\n\t[Ctb][Moench][Mythen3] 64 bit mask defining output clock enable."); INTEGER_COMMAND_HEX(patmask, getPatternMask, setPatternMask, stoulHex, - "[64 bit mask]\n\t[Ctb][Mythen3] 64 bit mask applied to every pattern. Only these bits for each pattern will be masked against."); + "[64 bit mask]\n\t[Ctb][Moench][Mythen3] 64 bit mask applied to every pattern. Only these bits for each pattern will be masked against."); INTEGER_COMMAND_HEX(patsetbit, getPatternBitMask, setPatternBitMask, stoulHex, - "[64 bit mask]\n\t[Ctb][Mythen3] 64 bit values applied to the selected patmask for every pattern."); + "[64 bit mask]\n\t[Ctb][Moench][Mythen3] 64 bit values applied to the selected patmask for every pattern."); /* Moench */ @@ -1711,17 +1735,19 @@ class CmdProxy { /* Advanced */ EXECUTE_SET_COMMAND(resetfpga, resetFPGA, - "\n\t[Jungfrau][Ctb] Reset FPGA."); + "\n\t[Jungfrau][Ctb][Moench] Reset FPGA."); EXECUTE_SET_COMMAND(rebootcontroller, rebootController, - "\n\t[Jungfrau][Ctb][Gotthard][Mythen3][Gotthard2] Reboot controler (blackfin) of detector."); + "\n\t[Jungfrau][Ctb][Moench][Gotthard][Mythen3][Gotthard2] Reboot controler (blackfin) of detector."); EXECUTE_SET_COMMAND(firmwaretest, executeFirmwareTest, - "\n\t[Jungfrau][Gotthard][Mythen3][Gotthard2][Ctb] Firmware test, ie. reads a read fixed pattern from a register."); + "\n\t[Jungfrau][Gotthard][Mythen3][Gotthard2][Ctb][Moench] Firmware test, ie. reads a read fixed pattern from a register."); EXECUTE_SET_COMMAND(bustest, executeBusTest, - "\n\t[Jungfrau][Gotthard][Mythen3][Gotthard2][Ctb] Bus test, ie. keeps writing and reading back different values in R/W register."); + "\n\t[Jungfrau][Gotthard][Mythen3][Gotthard2][Ctb][Moench] Bus test, ie. keeps writing and reading back different values in R/W register."); + INTEGER_COMMAND_HEX(adcinvert, getADCInvert, setADCInvert, stoiHex, + "[bitmask]\n\t[Ctb][Moench][Jungfrau][Moench] ADC Inversion Mask.\n\t[Jungfrau][Moench] Inversions on top of the default mask."); /* Insignificant */ @@ -1738,7 +1764,7 @@ class CmdProxy { "\n\tClient IP Address that last communicated with the detector."); GET_COMMAND(nframes, getNumberOfFramesFromStart, - "\n\t[Jungfrau][Mythen3][Gotthard2][Moench][CTB] Number of frames from start run control." + "\n\t[Jungfrau][Mythen3][Gotthard2][Moench][CTB][Moench] Number of frames from start run control." "\n\t[Gotthard2] only in continuous mode."); TIME_GET_COMMAND(now, getActualTime, diff --git a/slsDetectorSoftware/src/Detector.cpp b/slsDetectorSoftware/src/Detector.cpp index 51520f027..aa2e8be8b 100644 --- a/slsDetectorSoftware/src/Detector.cpp +++ b/slsDetectorSoftware/src/Detector.cpp @@ -1230,7 +1230,7 @@ void Detector::setCounterMask(uint32_t countermask, Positions pos) { pimpl->Parallel(&slsDetector::setCounterMask, pos, countermask); } -// CTB Specific +// CTB/ Moench Specific Result Detector::getNumberOfAnalogSamples(Positions pos) const { return pimpl->Parallel(&slsDetector::getNumberOfAnalogSamples, pos); @@ -1240,46 +1240,6 @@ void Detector::setNumberOfAnalogSamples(int value, Positions pos) { pimpl->Parallel(&slsDetector::setNumberOfAnalogSamples, pos, value); } -Result Detector::getNumberOfDigitalSamples(Positions pos) const { - return pimpl->Parallel(&slsDetector::getNumberOfDigitalSamples, pos); -} - -void Detector::setNumberOfDigitalSamples(int value, Positions pos) { - pimpl->Parallel(&slsDetector::setNumberOfDigitalSamples, pos, value); -} - -Result Detector::getReadoutMode(Positions pos) const { - return pimpl->Parallel(&slsDetector::getReadoutMode, pos); -} - -void Detector::setReadoutMode(defs::readoutMode value, Positions pos) { - pimpl->Parallel(&slsDetector::setReadoutMode, pos, value); -} - -Result Detector::getDBITPhase(Positions pos) const { - return pimpl->Parallel(&slsDetector::getClockPhase, pos, defs::DBIT_CLOCK, - false); -} - -void Detector::setDBITPhase(int value, Positions pos) { - pimpl->Parallel(&slsDetector::setClockPhase, pos, defs::DBIT_CLOCK, value, - false); -} - -Result Detector::getMaxDBITPhaseShift(Positions pos) const { - return pimpl->Parallel(&slsDetector::getMaxClockPhaseShift, pos, - defs::DBIT_CLOCK); -} - -Result Detector::getDBITPhaseInDegrees(Positions pos) const { - return pimpl->Parallel(&slsDetector::getClockPhase, pos, defs::DBIT_CLOCK, - true); -} - -void Detector::setDBITPhaseInDegrees(int value, Positions pos) { - pimpl->Parallel(&slsDetector::setClockPhase, pos, defs::DBIT_CLOCK, value, - true); -} Result Detector::getADCClock(Positions pos) const { return pimpl->Parallel(&slsDetector::getClockFrequency, pos, @@ -1291,16 +1251,6 @@ void Detector::setADCClock(int value_in_MHz, Positions pos) { value_in_MHz); } -Result Detector::getDBITClock(Positions pos) const { - return pimpl->Parallel(&slsDetector::getClockFrequency, pos, - defs::DBIT_CLOCK); -} - -void Detector::setDBITClock(int value_in_MHz, Positions pos) { - pimpl->Parallel(&slsDetector::setClockFrequency, pos, defs::DBIT_CLOCK, - value_in_MHz); -} - Result Detector::getRUNClock(Positions pos) const { return pimpl->Parallel(&slsDetector::getClockFrequency, pos, defs::RUN_CLOCK); @@ -1328,10 +1278,6 @@ Result Detector::getDBITPipeline(Positions pos) const { return pimpl->Parallel(&slsDetector::getPipeline, pos, defs::DBIT_CLOCK); } -void Detector::setDBITPipeline(int value, Positions pos) { - pimpl->Parallel(&slsDetector::setPipeline, pos, defs::DBIT_CLOCK, value); -} - Result Detector::getVoltage(defs::dacIndex index, Positions pos) const { switch (index) { case defs::V_LIMIT: @@ -1364,6 +1310,81 @@ void Detector::setVoltage(defs::dacIndex index, int value, Positions pos) { pimpl->Parallel(&slsDetector::setDAC, pos, value, index, 1); } +Result Detector::getADCEnableMask(Positions pos) const { + return pimpl->Parallel(&slsDetector::getADCEnableMask, pos); +} + +void Detector::setADCEnableMask(uint32_t mask, Positions pos) { + pimpl->Parallel(&slsDetector::setADCEnableMask, pos, mask); +} + +Result Detector::getTenGigaADCEnableMask(Positions pos) const { + return pimpl->Parallel(&slsDetector::getTenGigaADCEnableMask, pos); +} + +void Detector::setTenGigaADCEnableMask(uint32_t mask, Positions pos) { + pimpl->Parallel(&slsDetector::setTenGigaADCEnableMask, pos, mask); +} + +// CTB Specific + + +Result Detector::getNumberOfDigitalSamples(Positions pos) const { + return pimpl->Parallel(&slsDetector::getNumberOfDigitalSamples, pos); +} + +void Detector::setNumberOfDigitalSamples(int value, Positions pos) { + pimpl->Parallel(&slsDetector::setNumberOfDigitalSamples, pos, value); +} + +Result Detector::getReadoutMode(Positions pos) const { + return pimpl->Parallel(&slsDetector::getReadoutMode, pos); +} + +void Detector::setReadoutMode(defs::readoutMode value, Positions pos) { + pimpl->Parallel(&slsDetector::setReadoutMode, pos, value); +} + +Result Detector::getDBITClock(Positions pos) const { + return pimpl->Parallel(&slsDetector::getClockFrequency, pos, + defs::DBIT_CLOCK); +} + +void Detector::setDBITClock(int value_in_MHz, Positions pos) { + pimpl->Parallel(&slsDetector::setClockFrequency, pos, defs::DBIT_CLOCK, + value_in_MHz); +} + +Result Detector::getDBITPhase(Positions pos) const { + return pimpl->Parallel(&slsDetector::getClockPhase, pos, defs::DBIT_CLOCK, + false); +} + +void Detector::setDBITPhase(int value, Positions pos) { + pimpl->Parallel(&slsDetector::setClockPhase, pos, defs::DBIT_CLOCK, value, + false); +} + +Result Detector::getMaxDBITPhaseShift(Positions pos) const { + return pimpl->Parallel(&slsDetector::getMaxClockPhaseShift, pos, + defs::DBIT_CLOCK); +} + +Result Detector::getDBITPhaseInDegrees(Positions pos) const { + return pimpl->Parallel(&slsDetector::getClockPhase, pos, defs::DBIT_CLOCK, + true); +} + +void Detector::setDBITPhaseInDegrees(int value, Positions pos) { + pimpl->Parallel(&slsDetector::setClockPhase, pos, defs::DBIT_CLOCK, value, + true); +} + + +void Detector::setDBITPipeline(int value, Positions pos) { + pimpl->Parallel(&slsDetector::setPipeline, pos, defs::DBIT_CLOCK, value); +} + Result Detector::getMeasuredVoltage(defs::dacIndex index, Positions pos) const { switch (index) { @@ -1402,30 +1423,6 @@ Result Detector::getSlowADC(defs::dacIndex index, Positions pos) const { return pimpl->Parallel(&slsDetector::getADC, pos, index); } -Result Detector::getADCEnableMask(Positions pos) const { - return pimpl->Parallel(&slsDetector::getADCEnableMask, pos); -} - -void Detector::setADCEnableMask(uint32_t mask, Positions pos) { - pimpl->Parallel(&slsDetector::setADCEnableMask, pos, mask); -} - -Result Detector::getTenGigaADCEnableMask(Positions pos) const { - return pimpl->Parallel(&slsDetector::getTenGigaADCEnableMask, pos); -} - -void Detector::setTenGigaADCEnableMask(uint32_t mask, Positions pos) { - pimpl->Parallel(&slsDetector::setTenGigaADCEnableMask, pos, mask); -} - -Result Detector::getADCInvert(Positions pos) const { - return pimpl->Parallel(&slsDetector::getADCInvert, pos); -} - -void Detector::setADCInvert(uint32_t value, Positions pos) { - pimpl->Parallel(&slsDetector::setADCInvert, pos, value); -} - Result Detector::getExternalSamplingSource(Positions pos) const { return pimpl->Parallel(&slsDetector::getExternalSamplingSource, pos); } @@ -1747,6 +1744,14 @@ void Detector::setInitialChecks(const bool value) { pimpl->setInitialChecks(value); } +Result Detector::getADCInvert(Positions pos) const { + return pimpl->Parallel(&slsDetector::getADCInvert, pos); +} + +void Detector::setADCInvert(uint32_t value, Positions pos) { + pimpl->Parallel(&slsDetector::setADCInvert, pos, value); +} + // Insignificant Result Detector::getControlPort(Positions pos) const { diff --git a/slsDetectorSoftware/src/DetectorImpl.cpp b/slsDetectorSoftware/src/DetectorImpl.cpp index 22a211fe6..95eb7387d 100755 --- a/slsDetectorSoftware/src/DetectorImpl.cpp +++ b/slsDetectorSoftware/src/DetectorImpl.cpp @@ -557,7 +557,7 @@ void DetectorImpl::readFrameFromReceiver() { uint32_t yoffset = coordY * nPixelsY; uint32_t singledetrowoffset = nPixelsX * bytesPerPixel; uint32_t rowoffset = nX * singledetrowoffset; - if (multi_shm()->multiDetectorType == CHIPTESTBOARD) { + if (multi_shm()->multiDetectorType == MOENCH) { singledetrowoffset = size; nPixelsY = 1; // TODO: nDetPixelsY is not updated. } @@ -1070,6 +1070,7 @@ std::vector DetectorImpl::readProgrammingFile(const std::string &fname) { switch (multi_shm()->multiDetectorType) { case JUNGFRAU: case CHIPTESTBOARD: + case MOENCH: if (fname.find(".pof") == std::string::npos) { throw RuntimeError("Programming file must be a pof file."); } diff --git a/slsDetectorSoftware/src/slsDetector.cpp b/slsDetectorSoftware/src/slsDetector.cpp index 3519f582a..1a9c36e21 100755 --- a/slsDetectorSoftware/src/slsDetector.cpp +++ b/slsDetectorSoftware/src/slsDetector.cpp @@ -336,6 +336,7 @@ void slsDetector::initializeDetectorStructure(detectorType type) { shm()->roMode = ANALOG_ONLY; shm()->currentSettings = UNINITIALIZED; shm()->currentThresholdEV = -1; + shm()->nASamples = 1; shm()->nFrames = 1; shm()->nTriggers = 1; shm()->nBursts = 1; @@ -557,8 +558,8 @@ slsDetectorDefs::detectorType slsDetector::getDetectorType() const { } void slsDetector::updateNumberOfChannels() { - if (shm()->myDetectorType == CHIPTESTBOARD || - shm()->myDetectorType == MOENCH) { + + if (shm()->myDetectorType == CHIPTESTBOARD) { int nachans = 0, ndchans = 0; // analog channels (normal, analog/digital readout) @@ -577,15 +578,29 @@ void slsDetector::updateNumberOfChannels() { } // digital channels (ctb only, digital, analog/digital readout) - if (shm()->myDetectorType == CHIPTESTBOARD && - (shm()->roMode == DIGITAL_ONLY || - shm()->roMode == ANALOG_AND_DIGITAL)) { + if (shm()->roMode == DIGITAL_ONLY || + shm()->roMode == ANALOG_AND_DIGITAL) { ndchans = 64; FILE_LOG(logDEBUG1) << "#Digital Channels:" << ndchans; } shm()->nChan.x = nachans + ndchans; FILE_LOG(logDEBUG1) << "# Total #Channels:" << shm()->nChan.x; } + + + else if (shm()->myDetectorType == MOENCH) { + uint32_t mask = shm()->tenGigaEnable ? shm()->adcEnableMaskTenGiga : shm()->adcEnableMaskOneGiga; + // count number of channels in x, each adc has 25 channels each + int nchanTop = __builtin_popcount(mask & 0xF0F0F0F0) * 25; + int nchanBot = __builtin_popcount(mask & 0x0F0F0F0F) * 25; + shm()->nChan.x = nchanTop > 0 ? nchanTop : nchanBot; + // if both top and bottom adcs enabled, rows = 2 + int nrows = 1; + if (nchanTop > 0 && nchanBot > 0) { + nrows = 2; + } + shm()->nChan.y = shm()->nASamples / 25 * nrows; + } } slsDetectorDefs::xy slsDetector::getNumberOfChannels() const { @@ -807,11 +822,18 @@ void slsDetector::updateCachedDetectorVariables() { shm()->tenGigaEnable = static_cast(i32); } + // analog samples and adc enable masks if (shm()->myDetectorType == CHIPTESTBOARD || shm()->myDetectorType == MOENCH) { - // 1gb adcmask + + // analog samples uint32_t u32 = 0; n += client.Receive(&u32, sizeof(u32)); + shm()->nASamples = u32; + + // 1gb adcmask + u32 = 0; + n += client.Receive(&u32, sizeof(u32)); shm()->adcEnableMaskOneGiga = u32; // 10gb adcmask @@ -1321,6 +1343,7 @@ int slsDetector::getNumberOfAnalogSamples() { void slsDetector::setNumberOfAnalogSamples(int value) { FILE_LOG(logDEBUG1) << "Setting number of analog samples to " << value; sendToDetector(F_SET_NUM_ANALOG_SAMPLES, value, nullptr); + shm()->nASamples = value; // update #nchan, as it depends on #samples, adcmask updateNumberOfChannels(); if (shm()->useReceiverFlag) { @@ -1836,7 +1859,6 @@ std::string slsDetector::setReceiverHostname(const std::string &receiverIP) { case MOENCH: setNumberOfAnalogSamples(getNumberOfAnalogSamples()); - setNumberOfDigitalSamples(getNumberOfDigitalSamples()); enableTenGigabitEthernet(static_cast(shm()->tenGigaEnable)); setADCEnableMask(shm()->adcEnableMaskOneGiga); setTenGigaADCEnableMask(shm()->adcEnableMaskTenGiga); @@ -2974,6 +2996,7 @@ void slsDetector::programFPGA(std::vector buffer) { switch (shm()->myDetectorType) { case JUNGFRAU: case CHIPTESTBOARD: + case MOENCH: programFPGAviaBlackfin(buffer); break; case MYTHEN3: diff --git a/slsDetectorSoftware/src/slsDetector.h b/slsDetectorSoftware/src/slsDetector.h index d5f318053..ff7cb8953 100755 --- a/slsDetectorSoftware/src/slsDetector.h +++ b/slsDetectorSoftware/src/slsDetector.h @@ -13,7 +13,7 @@ class ServerInterface; #define SLS_SHMAPIVERSION 0x190726 -#define SLS_SHMVERSION 0x200225 +#define SLS_SHMVERSION 0x200302 /** * @short structure allocated in shared memory to store detector settings for @@ -80,6 +80,9 @@ struct sharedSlsDetector { /** detector threshold (eV) */ int currentThresholdEV; + /** number of analog samples */ + int nASamples; + /** number of frames */ int64_t nFrames; @@ -295,7 +298,7 @@ class slsDetector : public virtual slsDetectorDefs { /** * Update total number of channels (chiptestboard or moench) - * depending on the number of samples, adenablemask, readout flags(ctb) + * depending on the number of samples, adcenablemask, readout flags(ctb) */ void updateNumberOfChannels(); @@ -554,10 +557,10 @@ class slsDetector : public virtual slsDetectorDefs { /** [Jungfrau] Advanced */ void setNumberOfAdditionalStorageCells(int value); - /** [CTB] */ + /** [CTB][Moench] */ int getNumberOfAnalogSamples(); - /** [CTB] */ + /** [CTB][Moench] */ void setNumberOfAnalogSamples(int value); /** [CTB] */ @@ -574,10 +577,10 @@ class slsDetector : public virtual slsDetectorDefs { void setPeriod(int64_t value); - /** [Gotthard][Jungfrau][CTB][Mythen3][Gotthard2] */ + /** [Gotthard][Jungfrau][CTB][Moench][Mythen3][Gotthard2] */ int64_t getDelayAfterTrigger(); - /** [Gotthard][Jungfrau][CTB][Mythen3][Gotthard2] */ + /** [Gotthard][Jungfrau][CTB][Moench][Mythen3][Gotthard2] */ void setDelayAfterTrigger(int64_t value); /** [Gotthard2] only in burst mode and in auto timing mode */ @@ -605,22 +608,22 @@ class slsDetector : public virtual slsDetectorDefs { * Options: (0-1638375 ns (resolution of 25ns) */ void setStorageCellDelay(int64_t value); - /** [Gotthard][Jungfrau][CTB][Mythen3] + /** [Gotthard][Jungfrau][CTB][Moench][Mythen3] * [Gotthard2] only in continuous mode */ int64_t getNumberOfFramesLeft() const; - /** [Gotthard][Jungfrau][CTB][Mythen3] + /** [Gotthard][Jungfrau][CTB][Moench][Mythen3] * [Gotthard2] only in continuous mode */ int64_t getNumberOfTriggersLeft() const; - /** [Gotthard][Jungfrau][CTB] + /** [Gotthard][Jungfrau][CTB][Moench] * [Gotthard2] only in continuous mode */ int64_t getDelayAfterTriggerLeft() const; /** [Gotthard] */ int64_t getExptimeLeft() const; - /** [Gotthard][Jungfrau][CTB][Mythen3][Gotthard2] */ + /** [Gotthard][Jungfrau][CTB][Moench][Mythen3][Gotthard2] */ int64_t getPeriodLeft() const; /** [Eiger] minimum two frames */ @@ -629,15 +632,15 @@ class slsDetector : public virtual slsDetectorDefs { /** [Eiger] */ int64_t getMeasuredSubFramePeriod() const; - /** [Jungfrau][CTB][Mythen3] + /** [Jungfrau][CTB][Moench][Mythen3] * [Gotthard2] only in continuous mode */ int64_t getNumberOfFramesFromStart() const; - /** [Jungfrau][CTB][Mythen3] Get time from detector start + /** [Jungfrau][CTB][Moench][Mythen3] Get time from detector start * [Gotthard2] only in continuous mode */ int64_t getActualTime() const; - /** [Jungfrau][CTB][Mythen3] Get timestamp at a frame start + /** [Jungfrau][CTB][Moench][Mythen3] Get timestamp at a frame start * [Gotthard2] only in continuous mode */ int64_t getMeasurementTime() const; @@ -727,13 +730,13 @@ class slsDetector : public virtual slsDetectorDefs { bool getStoreInRamMode(); /** - * Set readout mode (Only for CTB and Moench) + * [Ctb] * @param mode readout mode Options: ANALOG_ONLY, DIGITAL_ONLY, ANALOG_AND_DIGITAL */ void setReadoutMode(const readoutMode mode); /** - * Get readout mode(Only for CTB and Moench) + * [Ctb] * @returns readout mode */ readoutMode getReadoutMode(); @@ -1117,10 +1120,10 @@ class slsDetector : public virtual slsDetectorDefs { */ int64_t getReceiverRealUDPSocketBufferSize() const; - /** [Gotthard][Jungfrau][CTB] */ + /** [Gotthard][Jungfrau][CTB][Moench] */ void executeFirmwareTest(); - /** [Gotthard][Jungfrau][CTB] */ + /** [Gotthard][Jungfrau][CTB][Moench] */ void executeBusTest(); /** [Gotthard] */ @@ -1222,14 +1225,14 @@ class slsDetector : public virtual slsDetectorDefs { uint32_t getTenGigaADCEnableMask(); /** - * Set ADC invert register (CTB, Moench) + * Set ADC invert register (CTB, Moench, Jungfrau) * @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) + * Get ADC invert register (CTB, Moench, Jungfrau) * @param detPos -1 for all detectors in list or specific detector position * @returns ADC invert value */ diff --git a/slsReceiverSoftware/src/ClientInterface.cpp b/slsReceiverSoftware/src/ClientInterface.cpp index 2bd2be3c6..aadeb5ffe 100755 --- a/slsReceiverSoftware/src/ClientInterface.cpp +++ b/slsReceiverSoftware/src/ClientInterface.cpp @@ -529,7 +529,7 @@ int ClientInterface::set_num_analog_samples(Interface &socket) { int ClientInterface::set_num_digital_samples(Interface &socket) { auto value = socket.Receive(); FILE_LOG(logDEBUG1) << "Setting num digital samples to " << value; - if (myDetectorType != CHIPTESTBOARD && myDetectorType != MOENCH) { + if (myDetectorType != CHIPTESTBOARD) { functionNotImplemented(); } try { diff --git a/slsReceiverSoftware/src/DataProcessor.cpp b/slsReceiverSoftware/src/DataProcessor.cpp index f81673b55..0a1905514 100755 --- a/slsReceiverSoftware/src/DataProcessor.cpp +++ b/slsReceiverSoftware/src/DataProcessor.cpp @@ -447,6 +447,7 @@ void DataProcessor::PadMissingPackets(char* buf) { memset(buf + fifohsize + (pnum * dsize), 0xFF, dsize+2); break; case CHIPTESTBOARD: + case MOENCH: if (pnum == (pperFrame-1)) memset(buf + fifohsize + (pnum * dsize), 0xFF, corrected_dsize); else diff --git a/slsReceiverSoftware/src/GeneralData.h b/slsReceiverSoftware/src/GeneralData.h index 067505731..7e62c8353 100755 --- a/slsReceiverSoftware/src/GeneralData.h +++ b/slsReceiverSoftware/src/GeneralData.h @@ -629,13 +629,6 @@ private: /** Number of bytes per analog channel */ const int NUM_BYTES_PER_ANALOG_CHANNEL = 2; - struct ctb_10g_packet_header { - unsigned char emptyHeader[6]; - unsigned char reserved[4]; - uint32_t packetFrameNumber; - uint64_t bunchid; - } __attribute__((packed)); - public: @@ -660,7 +653,7 @@ public: }; /** - * Set databytes (ctb, moench) + * Set databytes * @param a adc enable mask * @param as analog number of samples * @param ds digital number of samples @@ -700,50 +693,21 @@ public: nPixelsX = nachans + ndchans; nPixelsY = 1; + // 10G if (t) { - headerSizeinPacket = sizeof(slsDetectorDefs::sls_detector_header); dataSize = 8144; - packetSize = headerSizeinPacket + dataSize; - imageSize = adatabytes + ddatabytes; - packetsPerFrame = ceil((double)imageSize / (double)dataSize); - standardheader = true; - - /* - headerSizeinPacket = 22; - dataSize = 8192; - packetSize = headerSizeinPacket + dataSize; - imageSize = adatabytes + ddatabytes; - packetsPerFrame = ceil((double)imageSize / (double)dataSize); - standardheader = false; - */ } // 1g udp (via fifo readout) else { - headerSizeinPacket = sizeof(slsDetectorDefs::sls_detector_header); dataSize = UDP_PACKET_DATA_BYTES; - packetSize = headerSizeinPacket + dataSize; - imageSize = adatabytes + ddatabytes; - packetsPerFrame = ceil((double)imageSize / (double)dataSize); - standardheader = true; } - return adatabytes; - } - /** - * Get Header Infomation (frame number, packet number) - * @param index thread index for debugging purposes - * @param packetData pointer to data - * @param oddStartingPacket odd starting packet (gotthard) - * @param frameNumber frame number - * @param packetNumber packet number - */ - void GetHeaderInfo(int index, char* packetData, bool oddStartingPacket, - uint64_t& frameNumber, uint32_t& packetNumber) const - { - auto header = reinterpret_cast(packetData); - frameNumber = (header->packetFrameNumber >> frameIndexOffset) & frameIndexMask; - packetNumber = header->packetFrameNumber & packetIndexMask; + packetSize = headerSizeinPacket + dataSize; + imageSize = adatabytes + ddatabytes; + packetsPerFrame = ceil((double)imageSize / (double)dataSize); + + return adatabytes; } }; @@ -769,14 +733,14 @@ public: imageSize = nPixelsX * nPixelsY * 2; packetsPerFrame = ceil((double)imageSize / (double)UDP_PACKET_DATA_BYTES); frameIndexMask = 0xFFFFFF; - maxFramesPerFile = CTB_MAX_FRAMES_PER_FILE; + maxFramesPerFile = MOENCH_MAX_FRAMES_PER_FILE; fifoBufferHeaderSize = FIFO_HEADER_NUMBYTES + sizeof(slsDetectorDefs::sls_receiver_header); defaultFifoDepth = 2500; standardheader = true; }; /** - * Set databytes (ctb, moench) + * Set databytes * @param a adc enable mask * @param as analog number of samples * @param ds digital number of samples @@ -785,41 +749,37 @@ public: * @returns analog data bytes */ int setImageSize(uint32_t a, uint32_t as, uint32_t ds, bool t, slsDetectorDefs::readoutMode) { - int nachans = 0; - int adatabytes = 0; + + // count number of channels in x, each adc has 25 channels each + int nchanTop = __builtin_popcount(a & 0xF0F0F0F0) * 25; + int nchanBot = __builtin_popcount(a & 0x0F0F0F0F) * 25; + nPixelsX = nchanTop > 0 ? nchanTop : nchanBot; + + // if both top and bottom adcs enabled, rows = 2 + int nrows = 1; + if (nchanTop > 0 && nchanBot > 0) { + nrows = 2; + } + nPixelsY = as / 25 * nrows; + FILE_LOG(logINFO) << "Number of Pixels: [" << nPixelsX << ", " << nPixelsY << "]"; - // analog channels (normal, analog/digital readout) - if (a == BIT32_MASK) { - nachans = 32; - } else { - for (int ich = 0; ich < 32; ++ich) { - if (a & (1 << ich)) - ++nachans; - } - } - adatabytes = nachans * NUM_BYTES_PER_ANALOG_CHANNEL * as; - FILE_LOG(logDEBUG1) << "Total Number of Channels:" << nachans - << " Databytes: " << adatabytes; - nPixelsX = nachans; - nPixelsY = 1; // 10G if (t) { - headerSizeinPacket = sizeof(slsDetectorDefs::sls_detector_header); - dataSize = UDP_PACKET_DATA_BYTES; - packetSize = headerSizeinPacket + dataSize; - imageSize = adatabytes; - packetsPerFrame = ceil((double)imageSize / (double)dataSize); + dataSize = 8144; } // 1g udp (via fifo readout) else { - headerSizeinPacket = sizeof(slsDetectorDefs::sls_detector_header); - dataSize = UDP_PACKET_DATA_BYTES; - packetSize = headerSizeinPacket + dataSize; - imageSize = adatabytes; - packetsPerFrame = ceil((double)imageSize / (double)dataSize); + dataSize = UDP_PACKET_DATA_BYTES; } - return adatabytes; + + imageSize = nPixelsX * nPixelsY * NUM_BYTES_PER_ANALOG_CHANNEL; + packetSize = headerSizeinPacket + dataSize; + packetsPerFrame = ceil((double)imageSize / (double)dataSize); + + FILE_LOG(logDEBUG) << "Databytes: " << imageSize; + + return imageSize; } }; diff --git a/slsSupportLib/include/sls_detector_defs.h b/slsSupportLib/include/sls_detector_defs.h index 6c1056f84..07e30f8f9 100755 --- a/slsSupportLib/include/sls_detector_defs.h +++ b/slsSupportLib/include/sls_detector_defs.h @@ -332,6 +332,11 @@ class slsDetectorDefs { VB_PIXBUF, VIN_COM, VDD_PROT, + VBP_COLBUF, + VB_SDA, + VCASC_SFP, + VIPRE_CDS, + IBIAS_SFP, V_POWER_A = 100, V_POWER_B = 101, V_POWER_C = 102, diff --git a/slsSupportLib/include/versionAPI.h b/slsSupportLib/include/versionAPI.h index b5d4b63ac..0c81f31b6 100644 --- a/slsSupportLib/include/versionAPI.h +++ b/slsSupportLib/include/versionAPI.h @@ -1,6 +1,5 @@ /** API versions */ #define GITBRANCH "developer" -#define APIMOENCH 0x200131 #define APIMYTHEN3 0x200226 #define APIJUNGFRAU 0x200226 #define APIEIGER 0x200226 @@ -10,3 +9,4 @@ #define APIGUI 0x200227 #define APICTB 0x200227 #define APIGOTTHARD2 0x200228 +#define APIMOENCH 0x200302